diff --git a/CHANGELOG.md b/CHANGELOG.md index 363e255045..3dc7a4f1bc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -56,3 +56,5 @@ Ref: https://keepachangelog.com/en/1.0.0/ * (ci) [\#469](https://github.com/line/lbm-sdk/pull/469) publish docker image on tag push ### Document Updates + +* (docs) [\#483](https://github.com/line/lbm-sdk/pull/483) update documents on x/stakingplus diff --git a/CODING_GUIDELINES.md b/CODING_GUIDELINES.md new file mode 100644 index 0000000000..3ea8d20556 --- /dev/null +++ b/CODING_GUIDELINES.md @@ -0,0 +1,89 @@ +# Coding Guidelines + +This document is an extension to [CONTRIBUTING](./CONTRIBUTING.md) and provides more details about the coding guidelines and requirements. + +## API & Design + ++ Code must be well structured: + + packages must have a limited responsibility (different concerns can go to different packages), + + types must be easy to compose, + + think about maintainbility and testability. ++ "Depend upon abstractions, [not] concretions". ++ Try to limit the number of methods you are exposing. It's easier to expose something later than to hide it. ++ Take advantage of `internal` package concept. ++ Follow agreed-upon design patterns and naming conventions. ++ publicly-exposed functions are named logically, have forward-thinking arguments and return types. ++ Avoid global variables and global configurators. ++ Favor composable and extensible designs. ++ Minimize code duplication. ++ Limit third-party dependencies. + +Performance: + ++ Avoid unnecessary operations or memory allocations. + +Security: + ++ Pay proper attention to exploits involving: + + gas usage + + transaction verification and signatures + + malleability + + code must be always deterministic ++ Thread safety. If some functionality is not thread-safe, or uses something that is not thread-safe, then clearly indicate the risk on each level. + +## Testing + +Make sure your code is well tested: + ++ Provide unit tests for every unit of your code if possible. Unit tests are expected to comprise 70%-80% of your tests. ++ Describe the test scenarios you are implementing for integration tests. ++ Create integration tests for queries and msgs. ++ Use both test cases and property / fuzzy testing. We use the [rapid](pgregory.net/rapid) Go library for property-based and fuzzy testing. ++ Do not decrease code test coverage. Explain in a PR if test coverage is decreased. + +We expect tests to use `require` or `assert` rather than `t.Skip` or `t.Fail`, +unless there is a reason to do otherwise. +When testing a function under a variety of different inputs, we prefer to use +[table driven tests](https://github.com/golang/go/wiki/TableDrivenTests). +Table driven test error messages should follow the following format +`, tc #, i #`. +`` is an optional short description of whats failing, `tc` is the +index within the test case table that is failing, and `i` is when there +is a loop, exactly which iteration of the loop failed. +The idea is you should be able to see the +error message and figure out exactly what failed. +Here is an example check: + +```go + +for tcIndex, tc := range cases { + + resp, err := doSomething() + require.NoError(err) + require.Equal(t, tc.expected, resp, "should correctly perform X") +``` + +## Quality Assurance + +We are forming a QA team that will support the core Cosmos SDK team and collaborators by: + +- Improving the Cosmos SDK QA Processes +- Improving automation in QA and testing +- Defining high-quality metrics +- Maintaining and improving testing frameworks (unit tests, integration tests, and functional tests) +- Defining test scenarios. +- Verifying user experience and defining a high quality. + - We want to have **acceptance tests**! Document and list acceptance lists that are implemented and identify acceptance tests that are still missing. + - Acceptance tests should be specified in `acceptance-tests` directory as Markdown files. +- Supporting other teams with testing frameworks, automation, and User Experience testing. +- Testing chain upgrades for every new breaking change. + - Defining automated tests that assure data integrity after an update. + +Desired outcomes: + +- QA team works with Development Team. +- QA is happening in parallel with Core Cosmos SDK development. +- Releases are more predictable. +- QA reports. Goal is to guide with new tasks and be one of the QA measures. + +As a developer, you must help the QA team by providing instructions for User Experience (UX) and functional testing. diff --git a/Makefile b/Makefile index 79058ab295..fe874d60e6 100644 --- a/Makefile +++ b/Makefile @@ -517,13 +517,8 @@ proto-update-deps: # Run a 4-node testnet locally localnet-start: build-linux localnet-stop $(if $(shell $(DOCKER) inspect -f '{{ .Id }}' cosmossdk/simd-env 2>/dev/null),$(info found image cosmossdk/simd-env),$(MAKE) -C contrib/images simd-env) - if ! [ -f build/node0/simd/config/genesis.json ]; then $(DOCKER) run --rm \ - --user $(shell id -u):$(shell id -g) \ - -v $(BUILDDIR):/simd:Z \ - -v /etc/group:/etc/group:ro \ - -v /etc/passwd:/etc/passwd:ro \ - -v /etc/shadow:/etc/shadow:ro \ - cosmossdk/simd-env testnet --v 4 -o . --starting-ip-address 192.168.10.2 --keyring-backend=test ; fi + $(DOCKER) run --rm -v $(CURDIR)/localnet:/data cosmossdk/simd-env \ + testnet init-files --v 4 -o /data --starting-ip-address 192.168.10.2 --keyring-backend=test docker-compose up -d localnet-stop: diff --git a/RELEASE_PROCESS.md b/RELEASE_PROCESS.md new file mode 100644 index 0000000000..b75bb232be --- /dev/null +++ b/RELEASE_PROCESS.md @@ -0,0 +1,203 @@ +# Release Process + +This document outlines the process for releasing a new version of Cosmos SDK, which involves major release and patch releases as well as maintenance for the major release. + +## Major Release Procedure + +A _major release_ is an increment of the first number (eg: `v1.2` → `v2.0.0`) or the _point number_ (eg: `v1.1 → v1.2.0`, also called _point release_). Each major release opens a _stable release series_ and receives updates outlined in the [Major Release Maintenance](#major-release-maintenance)_section. + +Before making a new _major_ release we do beta and release candidate releases. For example, for release 1.0.0: + +``` +v1.0.0-beta1 → v1.0.0-beta2 → ... → v1.0.0-rc1 → v1.0.0-rc2 → ... → v1.0.0 +``` + +- Release a first beta version on the `master` branch and freeze `master` from receiving any new features. After beta is released, we focus on releasing the release candidate: + - finish audits and reviews + - kick off a large round of simulation testing (e.g. 400 seeds for 2k blocks) + - perform functional tests + - add more tests + - release new beta version as the bugs are discovered and fixed. +- After the team feels that the `master` works fine we create a `release/vY` branch (going forward known a release branch), where `Y` is the version number, with the patch part substituted to `x` (eg: 0.42.x, 1.0.x). Ensure the release branch is protected so that pushes against the release branch are permitted only by the release manager or release coordinator. + - **PRs targeting this branch can be merged _only_ when exceptional circumstances arise** + - update the GitHub mergify integration by adding instructions for automatically backporting commits from `master` to the `release/vY` using the `backport/Y` label. +- In the release branch, prepare a new version section in the `CHANGELOG.md` + - All links must be link-ified: `$ python ./scripts/linkify_changelog.py CHANGELOG.md` + - Copy the entries into a `RELEASE_CHANGELOG.md`, this is needed so the bot knows which entries to add to the release page on GitHub. +- Create a new annotated git tag for a release candidate (eg: `git tag -a v1.1.0-rc1`) in the release branch. + - from this point we unfreeze master. + - the SDK teams collaborate and do their best to run testnets in order to validate the release. + - when bugs are found, create a PR for `master`, and backport fixes to the release branch. + - create new release candidate tags after bugs are fixed. +- After the team feels the release branch is stable and everything works, create a full release: + - update `CHANGELOG.md`. + - create a new annotated git tag (eg `git -a v1.1.0`) in the release branch. + - Create a GitHub release. + +Following _semver_ philosophy, point releases after `v1.0`: + +- must not break API +- can break consensus + +Before `v1.0`, point release can break both point API and consensus. + +## Patch Release Procedure + +A _patch release_ is an increment of the patch number (eg: `v1.2.0` → `v1.2.1`). + +**Patch release must not break API nor consensus.** + +Updates to the release branch should come from `master` by backporting PRs (usually done by automatic cherry pick followed by a PRs to the release branch). The backports must be marked using `backport/Y` label in PR for master. +It is the PR author's responsibility to fix merge conflicts, update changelog entries, and +ensure CI passes. If a PR originates from an external contributor, a core team member assumes +responsibility to perform this process instead of the original author. +Lastly, it is core team's responsibility to ensure that the PR meets all the SRU criteria. + +Point Release must follow the [Stable Release Policy](#stable-release-policy). + +After the release branch has all commits required for the next patch release: + +- update `CHANGELOG.md`. +- create a new annotated git tag (eg `git -a v1.1.0`) in the release branch. +- Create a GitHub release. + +## Major Release Maintenance + +Major Release series continue to receive bug fixes (released as a Patch Release) until they reach **End Of Life**. +Major Release series is maintained in compliance with the **Stable Release Policy** as described in this document. +Note: not every Major Release is denoted as stable releases. + +Only the following major release series have a stable release status: + +* **0.42 «Stargate»** is supported until 2022-02-09. A fairly strict **bugfix-only** rule applies to pull requests that are requested to be included into a stable point-release. +* **0.44** is supported until 2022-07-17. A fairly strict **bugfix-only** rule applies to pull requests that are requested to be included into a stable point-release. +* **0.45** is the latest major release and will be supported until 6 months after **0.46.0** release. + +## Stable Release Policy + +### Patch Releases + +Once a Cosmos-SDK release has been completed and published, updates for it are released under certain circumstances +and must follow the [Patch Release Procedure](CONTRIBUTING.md#patch-release-procedure)[Point Release Procedure]. + +### Rationale + +Unlike in-development `master` branch snapshots, **Cosmos-SDK** releases are subject to much wider adoption, +and by a significantly different demographic of users. During development, changes in the `master` branch +affect SDK users, application developers, early adopters, and other advanced users that elect to use +unstable experimental software at their own risk. + +Conversely, users of a stable release expect a high degree of stability. They build their applications on it, and the +problems they experience with it could be potentially highly disruptive to their projects. + +Stable release updates are recommended to the vast majority of developers, and so it is crucial to treat them +with great caution. Hence, when updates are proposed, they must be accompanied by a strong rationale and present +a low risk of regressions, i.e. even one-line changes could cause unexpected regressions due to side effects or +poorly tested code. We never assume that any change, no matter how little or non-intrusive, is completely exempt +of regression risks. + +Therefore, the requirements for stable changes are different than those that are candidates to be merged in +the `master` branch. When preparing future major releases, our aim is to design the most elegant, user-friendly and +maintainable SDK possible which often entails fundamental changes to the SDK's architecture design, rearranging and/or +renaming packages as well as reducing code duplication so that we maintain common functions and data structures in one +place rather than leaving them scattered all over the code base. However, once a release is published, the +priority is to minimise the risk caused by changes that are not strictly required to fix qualifying bugs; this tends to +be correlated with minimising the size of such changes. As such, the same bug may need to be fixed in different +ways in stable releases and `master` branch. + +### Migrations + +To smoothen the update to the latest stable release, the SDK includes a set of CLI commands for managing migrations between SDK versions, under the `migrate` subcommand. Only migration scripts between stable releases are included. For the current major release, and later, migrations are supported. + +### What qualifies as a Stable Release Update (SRU)? + +* **High-impact bugs** + * Bugs that may directly cause a security vulnerability. + * *Severe regressions* from a Cosmos-SDK's previous release. This includes all sort of issues + that may cause the core packages or the `x/` modules unusable. + * Bugs that may cause **loss of user's data**. +* Other safe cases: + * Bugs which don't fit in the aforementioned categories for which an obvious safe patch is known. + * Relatively small yet strictly non-breaking features with strong support from the community. + * Relatively small yet strictly non-breaking changes that introduce forward-compatible client + features to smoothen the migration to successive releases. + * Relatively small yet strictly non-breaking CLI improvements. + +### What does not qualify as SRU? + +* State machine changes. +* Breaking changes in Protobuf definitions, as specified in [ADR-044](./docs/architecture/adr-044-protobuf-updates-guidelines.md). +* Changes that introduces API breakages (e.g. public functions and interfaces removal/renaming). +* Client-breaking changes in gRPC and HTTP request and response types. +* CLI-breaking changes. +* Cosmetic fixes, such as formatting or linter warning fixes. + +### What pull requests will be included in stable point-releases? + +Pull requests that fix bugs and add features that fall in the following categories do not require a **Stable Release Exception** to be granted to be included in a stable point-release: + +* **Severe regressions**. +* Bugs that may cause **client applications** to be **largely unusable**. +* Bugs that may cause **state corruption or data loss**. +* Bugs that may directly or indirectly cause a **security vulnerability**. +* Non-breaking features that are strongly requested by the community. +* Non-breaking CLI improvements that are strongly requested by the community. + +### What pull requests will NOT be automatically included in stable point-releases? + +As rule of thumb, the following changes will **NOT** be automatically accepted into stable point-releases: + +* **State machine changes**. +* **Protobug-breaking changes**, as specified in [ADR-044](./docs/architecture/adr-044-protobuf-updates- guidelines.md). +* **Client-breaking changes**, i.e. changes that prevent gRPC, HTTP and RPC clients to continue interacting with the node without any change. +* **API-breaking changes**, i.e. changes that prevent client applications to *build without modifications* to the client application's source code. +* **CLI-breaking changes**, i.e. changes that require usage changes for CLI users. + + In some circumstances, PRs that don't meet the aforementioned criteria might be raised and asked to be granted a *Stable Release Exception*. + +### Stable Release Exception - Procedure + +1. Check that the bug is either fixed or not reproducible in `master`. It is, in general, not appropriate to release bug fixes for stable releases without first testing them in `master`. Please apply the label [v0.43](https://github.com/cosmos/cosmos-sdk/milestone/26) to the issue. +2. Add a comment to the issue and ensure it contains the following information (see the bug template below): + +* **[Impact]** An explanation of the bug on users and justification for backporting the fix to the stable release. +* A **[Test Case]** section containing detailed instructions on how to reproduce the bug. +* A **[Regression Potential]** section with a clear assessment on how regressions are most likely to manifest as a result of the pull request that aims to fix the bug in the target stable release. + +3. **Stable Release Managers** will review and discuss the PR. Once *consensus* surrounding the rationale has been reached and the technical review has successfully concluded, the pull request will be merged in the respective point-release target branch (e.g. `release/v0.43.x`) and the PR included in the point-release's respective milestone (e.g. `v0.43.5`). + +#### Stable Release Exception - Bug template + +``` +#### Impact + +Brief xplanation of the effects of the bug on users and a justification for backporting the fix to the stable release. + +#### Test Case + +Detailed instructions on how to reproduce the bug on Stargate's most recently published point-release. + +#### Regression Potential + +Explanation on how regressions might manifest - even if it's unlikely. +It is assumed that stable release fixes are well-tested and they come with a low risk of regressions. +It's crucial to make the effort of thinking about what could happen in case a regression emerges. +``` + +### Stable Release Managers + +The **Stable Release Managers** evaluate and approve or reject updates and backports to Cosmos-SDK Stable Release series, +according to the [stable release policy](#stable-release-policy) and [release procedure](#stable-release-exception-procedure). +Decisions are made by consensus. + +Their responsibilites include: + +* Driving the Stable Release Exception process. +* Approving/rejecting proposed changes to a stable release series. +* Executing the release process of stable point-releases in compliance with the [Point Release Procedure](CONTRIBUTING.md). + +The Stable Release Managers are appointed by the Interchain Foundation. Currently residing Stable Release Managers: + +* @clevinson - Cory Levinson +* @amaurym - Amaury Martiny +* @robert-zaremba - Robert Zaremba diff --git a/baseapp/abci.go b/baseapp/abci.go index cc2e036641..b2f93696ef 100644 --- a/baseapp/abci.go +++ b/baseapp/abci.go @@ -111,6 +111,8 @@ func (app *BaseApp) Info(req abci.RequestInfo) abci.ResponseInfo { return abci.ResponseInfo{ Data: app.name, + Version: app.version, + AppVersion: app.appVersion, LastBlockHeight: lastCommitID.Version, LastBlockAppHash: lastCommitID.Hash, } @@ -184,7 +186,8 @@ func (app *BaseApp) BeginBlock(req abci.RequestBeginBlock) (res abci.ResponseBeg WithVoteInfos(app.voteInfos). WithConsensusParams(app.GetConsensusParams(app.deliverState.ctx)). WithBlockGasMeter(gasMeter). - WithHeaderHash(req.Hash) + WithHeaderHash(req.Hash). + WithConsensusParams(app.GetConsensusParams(app.deliverState.ctx)) // we also set block gas meter to checkState in case the application needs to // verify gas consumption during (Re)CheckTx @@ -248,6 +251,7 @@ func (app *BaseApp) CheckTxSync(req abci.RequestCheckTx) abci.ResponseCheckTx { gInfo, err := app.checkTx(req.Tx, tx, req.Type == abci.CheckTxType_Recheck) if err != nil { return sdkerrors.ResponseCheckTx(err, gInfo.GasWanted, gInfo.GasUsed, app.trace) + // return sdkerrors.ResponseCheckTxWithEvents(err, gInfo.GasWanted, gInfo.GasUsed, anteEvents, app.trace) // TODO(dudong2): need to fix to use ResponseCheckTxWithEvents } return abci.ResponseCheckTx{ @@ -309,10 +313,10 @@ func (app *BaseApp) DeliverTx(req abci.RequestDeliverTx) abci.ResponseDeliverTx return sdkerrors.ResponseDeliverTx(err, 0, 0, app.trace) } - gInfo, result, err := app.runTx(req.Tx, tx, false) + gInfo, result, anteEvents, err := app.runTx(req.Tx, tx, false) if err != nil { resultStr = "failed" - return sdkerrors.ResponseDeliverTx(err, gInfo.GasWanted, gInfo.GasUsed, app.trace) + return sdkerrors.ResponseDeliverTxWithEvents(err, gInfo.GasWanted, gInfo.GasUsed, anteEvents, app.trace) } return abci.ResponseDeliverTx{ @@ -682,7 +686,7 @@ func (app *BaseApp) createQueryContext(height int64, prove bool) (sdk.Context, e app.checkStateMtx.RLock() ctx := sdk.NewContext( cacheMS, app.checkState.ctx.BlockHeader(), true, app.logger, - ).WithMinGasPrices(app.minGasPrices) + ).WithMinGasPrices(app.minGasPrices).WithBlockHeight(height) app.checkStateMtx.RUnlock() return ctx, nil @@ -806,7 +810,7 @@ func handleQueryApp(app *BaseApp, path []string, req abci.RequestQuery) abci.Res return abci.ResponseQuery{ Codespace: sdkerrors.RootCodespace, Height: req.Height, - Value: []byte(app.appVersion), + Value: []byte(app.version), } default: @@ -848,28 +852,32 @@ func handleQueryStore(app *BaseApp, path []string, req abci.RequestQuery) abci.R func handleQueryP2P(app *BaseApp, path []string) abci.ResponseQuery { // "/p2p" prefix for p2p queries - if len(path) >= 4 { - cmd, typ, arg := path[1], path[2], path[3] - switch cmd { - case "filter": - switch typ { - case "addr": - return app.FilterPeerByAddrPort(arg) - - case "id": - return app.FilterPeerByID(arg) - } + if len(path) < 4 { + return sdkerrors.QueryResult( + sdkerrors.Wrap( + sdkerrors.ErrUnknownRequest, "path should be p2p filter ", + ), + ) + } - default: - return sdkerrors.QueryResult(sdkerrors.Wrap(sdkerrors.ErrUnknownRequest, "expected second parameter to be 'filter'")) + var resp abci.ResponseQuery + + cmd, typ, arg := path[1], path[2], path[3] + switch cmd { + case "filter": + switch typ { + case "addr": + resp = app.FilterPeerByAddrPort(arg) + + case "id": + resp = app.FilterPeerByID(arg) } + + default: + resp = sdkerrors.QueryResult(sdkerrors.Wrap(sdkerrors.ErrUnknownRequest, "expected second parameter to be 'filter'")) } - return sdkerrors.QueryResult( - sdkerrors.Wrap( - sdkerrors.ErrUnknownRequest, "expected path is p2p filter ", - ), - ) + return resp } func handleQueryCustom(app *BaseApp, path []string, req abci.RequestQuery) abci.ResponseQuery { diff --git a/baseapp/baseapp.go b/baseapp/baseapp.go index ce92195cd9..9d4fbaed40 100644 --- a/baseapp/baseapp.go +++ b/baseapp/baseapp.go @@ -8,6 +8,7 @@ import ( "sync" "github.com/gogo/protobuf/proto" + abci "github.com/line/ostracon/abci/types" "github.com/line/ostracon/crypto/tmhash" "github.com/line/ostracon/libs/log" @@ -20,6 +21,7 @@ import ( "github.com/line/lbm-sdk/store/rootmulti" sdk "github.com/line/lbm-sdk/types" sdkerrors "github.com/line/lbm-sdk/types/errors" + "github.com/line/lbm-sdk/x/auth/legacy/legacytx" ) var ( @@ -113,7 +115,11 @@ type BaseApp struct { // nolint: maligned minRetainBlocks uint64 // application's version string - appVersion string + version string + + // application's protocol version that increments on every upgrade + // if BaseApp is passed to the upgrade keeper's NewKeeper method. + appVersion uint64 // recovery handler for app.runTx method runTxRecoveryMiddleware recoveryMiddleware @@ -170,11 +176,16 @@ func (app *BaseApp) Name() string { return app.name } -// AppVersion returns the application's version string. -func (app *BaseApp) AppVersion() string { +// AppVersion returns the application's protocol version. +func (app *BaseApp) AppVersion() uint64 { return app.appVersion } +// Version returns the application's version string. +func (app *BaseApp) Version() string { + return app.version +} + // Logger returns the logger of the BaseApp. func (app *BaseApp) Logger() log.Logger { return app.logger @@ -566,6 +577,10 @@ func (app *BaseApp) preCheckTx(txBytes []byte) (tx sdk.Tx, err error) { return tx, err } +func (app *BaseApp) PreCheckTx(txBytes []byte) (sdk.Tx, error) { + return app.preCheckTx(txBytes) +} + func (app *BaseApp) checkTx(txBytes []byte, tx sdk.Tx, recheck bool) (gInfo sdk.GasInfo, err error) { ctx := app.getCheckContextForTx(txBytes, recheck) gasCtx := &ctx @@ -618,19 +633,13 @@ func (app *BaseApp) anteTx(ctx sdk.Context, txBytes []byte, tx sdk.Tx, simulate // Note, gas execution info is always returned. A reference to a Result is // returned if the tx does not run out of gas and if all the messages are valid // and execute successfully. An error is returned otherwise. -func (app *BaseApp) runTx(txBytes []byte, tx sdk.Tx, simulate bool) (gInfo sdk.GasInfo, result *sdk.Result, err error) { +func (app *BaseApp) runTx(txBytes []byte, tx sdk.Tx, simulate bool) (gInfo sdk.GasInfo, result *sdk.Result, anteEvents []abci.Event, err error) { ctx := app.getRunContextForTx(txBytes, simulate) ms := ctx.MultiStore() // only run the tx if there is block gas remaining if !simulate && ctx.BlockGasMeter().IsOutOfGas() { - gInfo = sdk.GasInfo{GasUsed: ctx.BlockGasMeter().GasConsumed()} - return gInfo, nil, sdkerrors.Wrap(sdkerrors.ErrOutOfGas, "no block gas left to run tx") - } - - var startingGas uint64 - if !simulate { - startingGas = ctx.BlockGasMeter().GasConsumed() + return gInfo, nil, nil, sdkerrors.Wrap(sdkerrors.ErrOutOfGas, "no block gas left to run tx") } defer func() { @@ -642,26 +651,30 @@ func (app *BaseApp) runTx(txBytes []byte, tx sdk.Tx, simulate bool) (gInfo sdk.G gInfo = sdk.GasInfo{GasWanted: ctx.GasMeter().Limit(), GasUsed: ctx.GasMeter().GasConsumed()} }() + blockGasConsumed := false + // consumeBlockGas makes sure block gas is consumed at most once. It must happen after + // tx processing, and must be execute even if tx processing fails. Hence we use trick with `defer` + consumeBlockGas := func() { + if !blockGasConsumed { + blockGasConsumed = true + ctx.BlockGasMeter().ConsumeGas( + ctx.GasMeter().GasConsumedToLimit(), "block gas meter", + ) + } + } + // If BlockGasMeter() panics it will be caught by the above recover and will // return an error - in any case BlockGasMeter will consume gas past the limit. // // NOTE: This must exist in a separate defer function for the above recovery // to recover from this one. - defer func() { - if !simulate { - ctx.BlockGasMeter().ConsumeGas( - ctx.GasMeter().GasConsumedToLimit(), "block gas meter", - ) - - if ctx.BlockGasMeter().GasConsumed() < startingGas { - panic(sdk.ErrorGasOverflow{Descriptor: "tx gas summation"}) - } - } - }() + if !simulate { + defer consumeBlockGas() + } msgs := tx.GetMsgs() if err = validateBasicTxMsgs(msgs); err != nil { - return sdk.GasInfo{}, nil, err + return sdk.GasInfo{}, nil, nil, err } var newCtx sdk.Context @@ -676,12 +689,13 @@ func (app *BaseApp) runTx(txBytes []byte, tx sdk.Tx, simulate bool) (gInfo sdk.G ctx = newCtx.WithMultiStore(ms) } - events := ctx.EventManager().Events() - if err != nil { - return gInfo, nil, err + return gInfo, nil, nil, err } + events := ctx.EventManager().Events() + anteEvents = events.ToABCIEvents() + // Create a new Context based off of the existing Context with a MultiStore branch // in case message processing fails. At this point, the MultiStore // is a branch of a branch. @@ -692,15 +706,18 @@ func (app *BaseApp) runTx(txBytes []byte, tx sdk.Tx, simulate bool) (gInfo sdk.G // Result if any single message fails or does not have a registered Handler. result, err = app.runMsgs(runMsgCtx, msgs) if err == nil && !simulate { + // When block gas exceeds, it'll panic and won't commit the cached store. + consumeBlockGas() + msCache.Write() - if len(events) > 0 { + if len(anteEvents) > 0 { // append the events in the order of occurrence - result.Events = append(events.ToABCIEvents(), result.Events...) + result.Events = append(anteEvents, result.Events...) } } - return gInfo, result, err + return gInfo, result, anteEvents, err } // runMsgs iterates through a list of messages and executes them with the provided @@ -718,37 +735,39 @@ func (app *BaseApp) runMsgs(ctx sdk.Context, msgs []sdk.Msg) (*sdk.Result, error // NOTE: GasWanted is determined by the AnteHandler and GasUsed by the GasMeter. for i, msg := range msgs { var ( - msgEvents sdk.Events - msgResult *sdk.Result - msgFqName string - err error + msgResult *sdk.Result + eventMsgName string // name to use as value in event `message.action` + err error ) - if svcMsg, ok := msg.(sdk.ServiceMsg); ok { - msgFqName = svcMsg.MethodName - handler := app.msgServiceRouter.Handler(msgFqName) - if handler == nil { - return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unrecognized message service method: %s; message index: %d", msgFqName, i) - } - msgResult, err = handler(ctx, svcMsg.Request) - } else { + if handler := app.msgServiceRouter.Handler(msg); handler != nil { + // ADR 031 request type routing + msgResult, err = handler(ctx, msg) + eventMsgName = sdk.MsgTypeURL(msg) + } else if legacyMsg, ok := msg.(legacytx.LegacyMsg); ok { // legacy sdk.Msg routing - msgRoute := msg.Route() - msgFqName = msg.Type() + // Assuming that the app developer has migrated all their Msgs to + // proto messages and has registered all `Msg services`, then this + // path should never be called, because all those Msgs should be + // registered within the `msgServiceRouter` already. + msgRoute := legacyMsg.Route() + eventMsgName = legacyMsg.Type() handler := app.router.Route(ctx, msgRoute) if handler == nil { return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unrecognized message route: %s; message index: %d", msgRoute, i) } msgResult, err = handler(ctx, msg) + } else { + return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "can't route message %+v", msg) } if err != nil { return nil, sdkerrors.Wrapf(err, "failed to execute message; message index: %d", i) } - msgEvents = sdk.Events{ - sdk.NewEvent(sdk.EventTypeMessage, sdk.NewAttribute(sdk.AttributeKeyAction, msgFqName)), + msgEvents := sdk.Events{ + sdk.NewEvent(sdk.EventTypeMessage, sdk.NewAttribute(sdk.AttributeKeyAction, eventMsgName)), } msgEvents = msgEvents.AppendEvents(msgResult.GetEvents()) @@ -758,7 +777,7 @@ func (app *BaseApp) runMsgs(ctx sdk.Context, msgs []sdk.Msg) (*sdk.Result, error // separate each result. events = events.AppendEvents(msgEvents) - txMsgData.Data = append(txMsgData.Data, &sdk.MsgData{MsgType: msg.Type(), Data: msgResult.Data}) + txMsgData.Data = append(txMsgData.Data, &sdk.MsgData{MsgType: sdk.MsgTypeURL(msg), Data: msgResult.Data}) msgLogs = append(msgLogs, sdk.NewABCIMessageLog(uint32(i), msgResult.Log, msgEvents)) } diff --git a/baseapp/baseapp_test.go b/baseapp/baseapp_test.go index 259b991753..991b96338f 100644 --- a/baseapp/baseapp_test.go +++ b/baseapp/baseapp_test.go @@ -165,7 +165,7 @@ func setupBaseAppWithSnapshots(t *testing.T, blocks uint, blockTxs int, options tx.Msgs = append(tx.Msgs, msgKeyValue{Key: key, Value: value}) keyCounter++ } - txBytes, err := codec.MarshalBinaryBare(tx) + txBytes, err := codec.Marshal(tx) require.NoError(t, err) resp := app.DeliverTx(abci.RequestDeliverTx{Tx: txBytes}) require.True(t, resp.IsOK(), "%v", resp.String()) @@ -341,21 +341,21 @@ func TestSetLoader(t *testing.T) { } } -func TestAppVersionSetterGetter(t *testing.T) { +func TestVersionSetterGetter(t *testing.T) { logger := defaultLogger() pruningOpt := SetPruning(store.PruneDefault) db := memdb.NewDB() name := t.Name() app := NewBaseApp(name, logger, db, nil, pruningOpt) - require.Equal(t, "", app.AppVersion()) + require.Equal(t, "", app.Version()) res := app.Query(abci.RequestQuery{Path: "app/version"}) require.True(t, res.IsOK()) require.Equal(t, "", string(res.Value)) versionString := "1.0.0" - app.SetAppVersion(versionString) - require.Equal(t, versionString, app.AppVersion()) + app.SetVersion(versionString) + require.Equal(t, versionString, app.Version()) res = app.Query(abci.RequestQuery{Path: "app/version"}) require.True(t, res.IsOK()) require.Equal(t, versionString, string(res.Value)) @@ -477,7 +477,7 @@ func TestTxDecoder(t *testing.T) { app := newBaseApp(t.Name()) tx := newTxCounter(1, 0) - txBytes := codec.MustMarshalBinaryBare(tx) + txBytes := codec.MustMarshal(tx) dTx, err := app.txDecoder(txBytes) require.NoError(t, err) @@ -499,7 +499,7 @@ func TestInfo(t *testing.T) { assert.Equal(t, t.Name(), res.GetData()) assert.Equal(t, int64(0), res.LastBlockHeight) require.Equal(t, []uint8(nil), res.LastBlockAppHash) - + require.Equal(t, app.AppVersion(), res.AppVersion) // ----- test a proper response ------- // TODO } @@ -511,7 +511,7 @@ func TestBaseAppOptionSeal(t *testing.T) { app.SetName("") }) require.Panics(t, func() { - app.SetAppVersion("") + app.SetVersion("") }) require.Panics(t, func() { app.SetDB(nil) @@ -805,7 +805,7 @@ func testTxDecoder(cdc *codec.LegacyAmino) sdk.TxDecoder { return nil, sdkerrors.Wrap(sdkerrors.ErrTxDecode, "tx bytes are empty") } - err := cdc.UnmarshalBinaryBare(txBytes, &tx) + err := cdc.Unmarshal(txBytes, &tx) if err != nil { return nil, sdkerrors.ErrTxDecode } @@ -936,7 +936,7 @@ func TestCheckTx(t *testing.T) { for i := int64(0); i < nTxs; i++ { tx := newTxCounter(i, 0) // no messages - txBytes, err := codec.MarshalBinaryBare(tx) + txBytes, err := codec.Marshal(tx) require.NoError(t, err) r := app.CheckTxSync(abci.RequestCheckTx{Tx: txBytes}) require.Empty(t, r.GetEvents()) @@ -1000,7 +1000,7 @@ func TestDeliverTx(t *testing.T) { counter := int64(blockN*txPerHeight + i) tx := newTxCounter(counter, counter) - txBytes, err := codec.MarshalBinaryBare(tx) + txBytes, err := codec.Marshal(tx) require.NoError(t, err) res := app.DeliverTx(abci.RequestDeliverTx{Tx: txBytes}) @@ -1050,7 +1050,7 @@ func TestMultiMsgDeliverTx(t *testing.T) { header := ocproto.Header{Height: 1} app.BeginBlock(abci.RequestBeginBlock{Header: header}) tx := newTxCounter(0, 0, 1, 2) - txBytes, err := codec.MarshalBinaryBare(tx) + txBytes, err := codec.Marshal(tx) require.NoError(t, err) res := app.DeliverTx(abci.RequestDeliverTx{Tx: txBytes}) require.True(t, res.IsOK(), fmt.Sprintf("%v", res)) @@ -1070,7 +1070,7 @@ func TestMultiMsgDeliverTx(t *testing.T) { tx = newTxCounter(1, 3) tx.Msgs = append(tx.Msgs, msgCounter2{0}) tx.Msgs = append(tx.Msgs, msgCounter2{1}) - txBytes, err = codec.MarshalBinaryBare(tx) + txBytes, err = codec.Marshal(tx) require.NoError(t, err) res = app.DeliverTx(abci.RequestDeliverTx{Tx: txBytes}) require.True(t, res.IsOK(), fmt.Sprintf("%v", res)) @@ -1132,7 +1132,7 @@ func TestSimulateTx(t *testing.T) { app.BeginBlock(abci.RequestBeginBlock{Header: header}) tx := newTxCounter(count, count) - txBytes, err := cdc.MarshalBinaryBare(tx) + txBytes, err := cdc.Marshal(tx) require.Nil(t, err) // simulate a message, check gas reported @@ -1261,7 +1261,7 @@ func TestRunInvalidTransaction(t *testing.T) { registerTestCodec(newCdc) newCdc.RegisterConcrete(&msgNoDecode{}, "lbm-sdk/baseapp/msgNoDecode", nil) - txBytes, err := newCdc.MarshalBinaryBare(tx) + txBytes, err := newCdc.Marshal(tx) require.NoError(t, err) res := app.DeliverTx(abci.RequestDeliverTx{Tx: txBytes}) @@ -1529,7 +1529,7 @@ func TestBaseAppAnteHandler(t *testing.T) { // the next txs ante handler execution (anteHandlerTxTest). tx := newTxCounter(0, 0) tx.setFailOnAnte(true) - txBytes, err := cdc.MarshalBinaryBare(tx) + txBytes, err := cdc.Marshal(tx) require.NoError(t, err) res := app.DeliverTx(abci.RequestDeliverTx{Tx: txBytes}) require.Empty(t, res.Events) @@ -1544,11 +1544,12 @@ func TestBaseAppAnteHandler(t *testing.T) { tx = newTxCounter(0, 0) tx.setFailOnHandler(true) - txBytes, err = cdc.MarshalBinaryBare(tx) + txBytes, err = cdc.Marshal(tx) require.NoError(t, err) res = app.DeliverTx(abci.RequestDeliverTx{Tx: txBytes}) - require.Empty(t, res.Events) + // should emit ante event + require.NotEmpty(t, res.Events) require.False(t, res.IsOK(), fmt.Sprintf("%v", res)) ctx = app.deliverState.ctx @@ -1560,7 +1561,7 @@ func TestBaseAppAnteHandler(t *testing.T) { // implicitly checked by previous tx executions tx = newTxCounter(1, 0) - txBytes, err = cdc.MarshalBinaryBare(tx) + txBytes, err = cdc.Marshal(tx) require.NoError(t, err) res = app.DeliverTx(abci.RequestDeliverTx{Tx: txBytes}) @@ -1633,7 +1634,7 @@ func TestGasConsumptionBadTx(t *testing.T) { tx := newTxCounter(5, 0) tx.setFailOnAnte(true) - txBytes, err := cdc.MarshalBinaryBare(tx) + txBytes, err := cdc.Marshal(tx) require.NoError(t, err) res := app.DeliverTx(abci.RequestDeliverTx{Tx: txBytes}) @@ -1641,7 +1642,7 @@ func TestGasConsumptionBadTx(t *testing.T) { // require next tx to fail due to black gas limit tx = newTxCounter(5, 0) - txBytes, err = cdc.MarshalBinaryBare(tx) + txBytes, err = cdc.Marshal(tx) require.NoError(t, err) res = app.DeliverTx(abci.RequestDeliverTx{Tx: txBytes}) @@ -2000,7 +2001,7 @@ func TestWithRouter(t *testing.T) { counter := int64(blockN*txPerHeight + i) tx := newTxCounter(counter, counter) - txBytes, err := codec.MarshalBinaryBare(tx) + txBytes, err := codec.Marshal(tx) require.NoError(t, err) res := app.DeliverTx(abci.RequestDeliverTx{Tx: txBytes}) diff --git a/baseapp/block_gas_test.go b/baseapp/block_gas_test.go new file mode 100644 index 0000000000..aa2f12d6a2 --- /dev/null +++ b/baseapp/block_gas_test.go @@ -0,0 +1,201 @@ +package baseapp_test + +import ( + "encoding/json" + "fmt" + "math" + "testing" + + "github.com/stretchr/testify/require" + + abci "github.com/line/ostracon/abci/types" + "github.com/line/ostracon/libs/log" + ocproto "github.com/line/ostracon/proto/ostracon/types" + "github.com/line/tm-db/v2/memdb" + + "github.com/line/lbm-sdk/baseapp" + "github.com/line/lbm-sdk/client" + "github.com/line/lbm-sdk/client/tx" + cryptotypes "github.com/line/lbm-sdk/crypto/types" + "github.com/line/lbm-sdk/simapp" + "github.com/line/lbm-sdk/testutil/testdata" + sdk "github.com/line/lbm-sdk/types" + sdkerrors "github.com/line/lbm-sdk/types/errors" + txtypes "github.com/line/lbm-sdk/types/tx" + "github.com/line/lbm-sdk/types/tx/signing" + xauthsigning "github.com/line/lbm-sdk/x/auth/signing" + banktypes "github.com/line/lbm-sdk/x/bank/types" + minttypes "github.com/line/lbm-sdk/x/mint/types" +) + +var blockMaxGas = uint64(simapp.DefaultConsensusParams.Block.MaxGas) + +func TestBaseApp_BlockGas(t *testing.T) { + testcases := []struct { + name string + gasToConsume uint64 // gas to consume in the msg execution + panicTx bool // panic explicitly in tx execution + expErr bool + }{ + {"less than block gas meter", 10, false, false}, + {"more than block gas meter", blockMaxGas, false, true}, + {"more than block gas meter", uint64(float64(blockMaxGas) * 1.2), false, true}, + {"consume MaxUint64", math.MaxUint64, false, true}, + {"consume MaxGasWanted", txtypes.MaxGasWanted, false, true}, + {"consume block gas when paniced", 10, true, true}, + } + for _, tc := range testcases { + t.Run(tc.name, func(t *testing.T) { + var app *simapp.SimApp + routerOpt := func(bapp *baseapp.BaseApp) { + route := (&testdata.TestMsg{}).Route() + bapp.Router().AddRoute(sdk.NewRoute(route, func(ctx sdk.Context, msg sdk.Msg) (*sdk.Result, error) { + _, ok := msg.(*testdata.TestMsg) + if !ok { + return &sdk.Result{}, fmt.Errorf("Wrong Msg type, expected %T, got %T", (*testdata.TestMsg)(nil), msg) + } + ctx.KVStore(app.GetKey(banktypes.ModuleName)).Set([]byte("ok"), []byte("ok")) + ctx.GasMeter().ConsumeGas(tc.gasToConsume, "TestMsg") + if tc.panicTx { + panic("panic in tx execution") + } + return &sdk.Result{}, nil + })) + } + encCfg := simapp.MakeTestEncodingConfig() + encCfg.Amino.RegisterConcrete(&testdata.TestMsg{}, "testdata.TestMsg", nil) + encCfg.InterfaceRegistry.RegisterImplementations((*sdk.Msg)(nil), + &testdata.TestMsg{}, + ) + app = simapp.NewSimApp(log.NewNopLogger(), memdb.NewDB(), nil, true, map[int64]bool{}, "", 0, encCfg, simapp.EmptyAppOptions{}, routerOpt) + genState := simapp.NewDefaultGenesisState(encCfg.Marshaler) + stateBytes, err := json.MarshalIndent(genState, "", " ") + require.NoError(t, err) + app.InitChain(abci.RequestInitChain{ + Validators: []abci.ValidatorUpdate{}, + ConsensusParams: simapp.DefaultConsensusParams, + AppStateBytes: stateBytes, + }) + + ctx := app.NewContext(false, ocproto.Header{}) + + // tx fee + feeCoin := sdk.NewCoin("atom", sdk.NewInt(150)) + feeAmount := sdk.NewCoins(feeCoin) + + // test account and fund + priv1, _, addr1 := testdata.KeyTestPubAddr() + err = app.BankKeeper.MintCoins(ctx, minttypes.ModuleName, feeAmount) + require.NoError(t, err) + err = app.BankKeeper.SendCoinsFromModuleToAccount(ctx, minttypes.ModuleName, addr1, feeAmount) + require.NoError(t, err) + require.Equal(t, feeCoin.Amount, app.BankKeeper.GetBalance(ctx, addr1, feeCoin.Denom).Amount) + seq, _ := app.AccountKeeper.GetSequence(ctx, addr1) + require.Equal(t, uint64(0), seq) + + // msg and signatures + msg := testdata.NewTestMsg(addr1) + + txBuilder := encCfg.TxConfig.NewTxBuilder() + require.NoError(t, txBuilder.SetMsgs(msg)) + txBuilder.SetFeeAmount(feeAmount) + txBuilder.SetGasLimit(txtypes.MaxGasWanted) // tx validation checks that gasLimit can't be bigger than this + + privs, accNums, accSeqs := []cryptotypes.PrivKey{priv1}, []uint64{7}, []uint64{0} + _, txBytes, err := createTestTx(encCfg.TxConfig, txBuilder, privs, accNums, accSeqs, ctx.ChainID()) + require.NoError(t, err) + + app.BeginBlock(abci.RequestBeginBlock{Header: ocproto.Header{Height: 1}}) + rsp := app.DeliverTx(abci.RequestDeliverTx{Tx: txBytes}) + + // check result + ctx = app.GetContextForDeliverTx(txBytes) + okValue := ctx.KVStore(app.GetKey(banktypes.ModuleName)).Get([]byte("ok")) + + if tc.expErr { + if tc.panicTx { + require.Equal(t, sdkerrors.ErrPanic.ABCICode(), rsp.Code) + } else { + require.Equal(t, sdkerrors.ErrOutOfGas.ABCICode(), rsp.Code) + } + require.Empty(t, okValue) + } else { + require.Equal(t, uint32(0), rsp.Code) + require.Equal(t, []byte("ok"), okValue) + } + // check block gas is always consumed + baseGas := uint64(36950) // baseGas is the gas consumed before tx msg + expGasConsumed := addUint64Saturating(tc.gasToConsume, baseGas) + if expGasConsumed > txtypes.MaxGasWanted { + // capped by gasLimit + expGasConsumed = txtypes.MaxGasWanted + } + require.Equal(t, expGasConsumed, ctx.BlockGasMeter().GasConsumed()) + // tx fee is always deducted + require.Equal(t, int64(0), app.BankKeeper.GetBalance(ctx, addr1, feeCoin.Denom).Amount.Int64()) + // sender's sequence is always increased + seq, err = app.AccountKeeper.GetSequence(ctx, addr1) + require.NoError(t, err) + require.Equal(t, uint64(1), seq) + }) + } +} + +func createTestTx(txConfig client.TxConfig, txBuilder client.TxBuilder, privs []cryptotypes.PrivKey, accNums []uint64, accSeqs []uint64, chainID string) (xauthsigning.Tx, []byte, error) { + // First round: we gather all the signer infos. We use the "set empty + // signature" hack to do that. + var sigsV2 []signing.SignatureV2 + for i, priv := range privs { + sigV2 := signing.SignatureV2{ + PubKey: priv.PubKey(), + Data: &signing.SingleSignatureData{ + SignMode: txConfig.SignModeHandler().DefaultMode(), + Signature: nil, + }, + Sequence: accSeqs[i], + } + + sigsV2 = append(sigsV2, sigV2) + } + err := txBuilder.SetSignatures(sigsV2...) + if err != nil { + return nil, nil, err + } + + // Second round: all signer infos are set, so each signer can sign. + sigsV2 = []signing.SignatureV2{} + for i, priv := range privs { + signerData := xauthsigning.SignerData{ + ChainID: chainID, + AccountNumber: accNums[i], + Sequence: accSeqs[i], + } + sigV2, err := tx.SignWithPrivKey( + txConfig.SignModeHandler().DefaultMode(), signerData, + txBuilder, priv, txConfig, accSeqs[i]) + if err != nil { + return nil, nil, err + } + + sigsV2 = append(sigsV2, sigV2) + } + err = txBuilder.SetSignatures(sigsV2...) + if err != nil { + return nil, nil, err + } + + txBytes, err := txConfig.TxEncoder()(txBuilder.GetTx()) + if err != nil { + return nil, nil, err + } + + return txBuilder.GetTx(), txBytes, nil +} + +func addUint64Saturating(a, b uint64) uint64 { + if math.MaxUint64-a < b { + return math.MaxUint64 + } + + return a + b +} diff --git a/baseapp/grpcrouter.go b/baseapp/grpcrouter.go index 912a245e7b..8804633aaf 100644 --- a/baseapp/grpcrouter.go +++ b/baseapp/grpcrouter.go @@ -2,32 +2,26 @@ package baseapp import ( "fmt" - "reflect" "sync" gogogrpc "github.com/gogo/protobuf/grpc" - abci "github.com/line/ostracon/abci/types" "google.golang.org/grpc" "google.golang.org/grpc/encoding" "google.golang.org/grpc/encoding/proto" + abci "github.com/line/ostracon/abci/types" + "github.com/line/lbm-sdk/client/grpc/reflection" codectypes "github.com/line/lbm-sdk/codec/types" sdk "github.com/line/lbm-sdk/types" - sdkerrors "github.com/line/lbm-sdk/types/errors" ) var protoCodec = encoding.GetCodec(proto.Name) // GRPCQueryRouter routes ABCI Query requests to GRPC handlers type GRPCQueryRouter struct { - lck sync.Mutex - routes map[string]GRPCQueryHandler - // returnTypes is a map of FQ method name => its return type. It is used - // for cache purposes: the first time a method handler is run, we save its - // return type in this map. Then, on subsequent method handler calls, we - // decode the ABCI response bytes using the cached return type. - returnTypes map[string]reflect.Type + lck sync.Mutex + routes map[string]GRPCQueryHandler interfaceRegistry codectypes.InterfaceRegistry serviceData []serviceData } @@ -43,9 +37,8 @@ var _ gogogrpc.Server = &GRPCQueryRouter{} // NewGRPCQueryRouter creates a new GRPCQueryRouter func NewGRPCQueryRouter() *GRPCQueryRouter { return &GRPCQueryRouter{ - lck: sync.Mutex{}, - returnTypes: map[string]reflect.Type{}, - routes: map[string]GRPCQueryHandler{}, + lck: sync.Mutex{}, + routes: map[string]GRPCQueryHandler{}, } } @@ -105,19 +98,8 @@ func (qrt *GRPCQueryRouter) RegisterService(sd *grpc.ServiceDesc, handler interf if qrt.interfaceRegistry != nil { return codectypes.UnpackInterfaces(i, qrt.interfaceRegistry) } - return nil }, nil) - - // If it's the first time we call this handler, then we save - // the return type of the handler in the `returnTypes` map. - // The return type will be used for decoding subsequent requests. - qrt.lck.Lock() - if _, found := qrt.returnTypes[fqName]; !found { - qrt.returnTypes[fqName] = reflect.TypeOf(res) - } - qrt.lck.Unlock() - if err != nil { return abci.ResponseQuery{}, err } @@ -149,7 +131,6 @@ func (qrt *GRPCQueryRouter) SetInterfaceRegistry(interfaceRegistry codectypes.In // defer qrt.lck.Unlock() qrt.interfaceRegistry = interfaceRegistry - // Once we have an interface registry, we can register the interface // registry reflection gRPC service. reflection.RegisterReflectionServiceServer( @@ -157,19 +138,3 @@ func (qrt *GRPCQueryRouter) SetInterfaceRegistry(interfaceRegistry codectypes.In reflection.NewReflectionServiceServer(interfaceRegistry), ) } - -// returnTypeOf returns the return type of a gRPC method handler. With the way the -// `returnTypes` cache map is set up, the return type of a method handler is -// guaranteed to be found if it's retrieved **after** the method handler ran at -// least once. If not, then a logic error is return. -func (qrt *GRPCQueryRouter) returnTypeOf(method string) (reflect.Type, error) { - qrt.lck.Lock() - defer qrt.lck.Unlock() - - returnType, found := qrt.returnTypes[method] - if !found { - return nil, sdkerrors.Wrapf(sdkerrors.ErrLogic, "cannot find %s return type", method) - } - - return returnType, nil -} diff --git a/baseapp/grpcserver.go b/baseapp/grpcserver.go index d311d596e0..1e9f76dc97 100644 --- a/baseapp/grpcserver.go +++ b/baseapp/grpcserver.go @@ -2,78 +2,68 @@ package baseapp import ( "context" - "reflect" + "strconv" gogogrpc "github.com/gogo/protobuf/grpc" grpcmiddleware "github.com/grpc-ecosystem/go-grpc-middleware" grpcrecovery "github.com/grpc-ecosystem/go-grpc-middleware/recovery" "google.golang.org/grpc" + "google.golang.org/grpc/codes" "google.golang.org/grpc/metadata" + "google.golang.org/grpc/status" - "github.com/line/lbm-sdk/client" + sdk "github.com/line/lbm-sdk/types" sdkerrors "github.com/line/lbm-sdk/types/errors" - "github.com/line/lbm-sdk/types/tx" + grpctypes "github.com/line/lbm-sdk/types/grpc" ) // GRPCQueryRouter returns the GRPCQueryRouter of a BaseApp. func (app *BaseApp) GRPCQueryRouter() *GRPCQueryRouter { return app.grpcQueryRouter } // RegisterGRPCServer registers gRPC services directly with the gRPC server. -func (app *BaseApp) RegisterGRPCServer(clientCtx client.Context, server gogogrpc.Server) { - // Define an interceptor for all gRPC queries: this interceptor will route - // the query through the `clientCtx`, which itself queries Tendermint. - interceptor := func(grpcCtx context.Context, req interface{}, info *grpc.UnaryServerInfo, _ grpc.UnaryHandler) (interface{}, error) { - // Two things can happen here: - // 1. either we're broadcasting a Tx, in which case we call Tendermint's broadcast endpoint directly, - // 2. or we are querying for state, in which case we call ABCI's Query. +func (app *BaseApp) RegisterGRPCServer(server gogogrpc.Server) { + // Define an interceptor for all gRPC queries: this interceptor will create + // a new sdk.Context, and pass it into the query handler. + interceptor := func(grpcCtx context.Context, req interface{}, _ *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp interface{}, err error) { + // If there's some metadata in the context, retrieve it. + md, ok := metadata.FromIncomingContext(grpcCtx) + if !ok { + return nil, status.Error(codes.Internal, "unable to retrieve metadata") + } - // Case 1. Broadcasting a Tx. - if reqProto, ok := req.(*tx.BroadcastTxRequest); ok { - if !ok { - return nil, sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "expected %T, got %T", (*tx.BroadcastTxRequest)(nil), req) + // Get height header from the request context, if present. + var height int64 + if heightHeaders := md.Get(grpctypes.GRPCBlockHeightHeader); len(heightHeaders) == 1 { + height, err = strconv.ParseInt(heightHeaders[0], 10, 64) + if err != nil { + return nil, sdkerrors.Wrapf( + sdkerrors.ErrInvalidRequest, + "Baseapp.RegisterGRPCServer: invalid height header %q: %v", grpctypes.GRPCBlockHeightHeader, err) + } + if err := checkNegativeHeight(height); err != nil { + return nil, err } - - return client.TxServiceBroadcast(grpcCtx, clientCtx, reqProto) } - // Case 2. Querying state. - inMd, _ := metadata.FromIncomingContext(grpcCtx) - abciRes, outMd, err := client.RunGRPCQuery(clientCtx, grpcCtx, info.FullMethod, req, inMd) + // Create the sdk.Context. Passing false as 2nd arg, as we can't + // actually support proofs with gRPC right now. + sdkCtx, err := app.createQueryContext(height, false) if err != nil { return nil, err } - // We need to know the return type of the grpc method for - // unmarshalling abciRes.Value. - // - // When we call each method handler for the first time, we save its - // return type in the `returnTypes` map (see the method handler in - // `grpcrouter.go`). By this time, the method handler has already run - // at least once (in the RunGRPCQuery call), so we're sure the - // returnType maps is populated for this method. We're retrieving it - // for decoding. - returnType, err := app.GRPCQueryRouter().returnTypeOf(info.FullMethod) - if err != nil { - return nil, err + // Add relevant gRPC headers + if height == 0 { + height = sdkCtx.BlockHeight() // If height was not set in the request, set it to the latest } - // returnType is a pointer to a struct. Here, we're creating res which - // is a new pointer to the underlying struct. - res := reflect.New(returnType.Elem()).Interface() - - err = protoCodec.Unmarshal(abciRes.Value, res) - if err != nil { - return nil, err - } + // Attach the sdk.Context into the gRPC's context.Context. + grpcCtx = context.WithValue(grpcCtx, sdk.SdkContextKey, sdkCtx) - // Send the metadata header back. The metadata currently includes: - // - block height. - err = grpc.SendHeader(grpcCtx, outMd) - if err != nil { - return nil, err - } + md = metadata.Pairs(grpctypes.GRPCBlockHeightHeader, strconv.FormatInt(height, 10)) + grpc.SetHeader(grpcCtx, md) - return res, nil + return handler(grpcCtx, req) } // Loop through all services and methods, add the interceptor, and register diff --git a/baseapp/iostats_nop.go b/baseapp/iostats_nop.go index 4f12157503..2dcd18f6a6 100644 --- a/baseapp/iostats_nop.go +++ b/baseapp/iostats_nop.go @@ -1,3 +1,4 @@ +//go:build !linux // +build !linux package baseapp diff --git a/baseapp/msg_service_router.go b/baseapp/msg_service_router.go index 1aace09706..0f28f5dee4 100644 --- a/baseapp/msg_service_router.go +++ b/baseapp/msg_service_router.go @@ -29,12 +29,17 @@ func NewMsgServiceRouter() *MsgServiceRouter { } // MsgServiceHandler defines a function type which handles Msg service message. -type MsgServiceHandler = func(ctx sdk.Context, req sdk.MsgRequest) (*sdk.Result, error) +type MsgServiceHandler = func(ctx sdk.Context, req sdk.Msg) (*sdk.Result, error) -// Handler returns the MsgServiceHandler for a given query route path or nil +// Handler returns the MsgServiceHandler for a given msg or nil if not found. +func (msr *MsgServiceRouter) Handler(msg sdk.Msg) MsgServiceHandler { + return msr.routes[sdk.MsgTypeURL(msg)] +} + +// HandlerByTypeURL returns the MsgServiceHandler for a given query route path or nil // if not found. -func (msr *MsgServiceRouter) Handler(methodName string) MsgServiceHandler { - return msr.routes[methodName] +func (msr *MsgServiceRouter) HandlerByTypeURL(typeURL string) MsgServiceHandler { + return msr.routes[typeURL] } // RegisterService implements the gRPC Server.RegisterService method. sd is a gRPC @@ -50,20 +55,38 @@ func (msr *MsgServiceRouter) RegisterService(sd *grpc.ServiceDesc, handler inter fqMethod := fmt.Sprintf("/%s/%s", sd.ServiceName, method.MethodName) methodHandler := method.Handler + var requestTypeName string + + // NOTE: This is how we pull the concrete request type for each handler for registering in the InterfaceRegistry. + // This approach is maybe a bit hacky, but less hacky than reflecting on the handler object itself. + // We use a no-op interceptor to avoid actually calling into the handler itself. + _, _ = methodHandler(nil, context.Background(), func(i interface{}) error { + msg, ok := i.(sdk.Msg) + if !ok { + // We panic here because there is no other alternative and the app cannot be initialized correctly + // this should only happen if there is a problem with code generation in which case the app won't + // work correctly anyway. + panic(fmt.Errorf("can't register request type %T for service method %s", i, fqMethod)) + } + + requestTypeName = sdk.MsgTypeURL(msg) + return nil + }, noopInterceptor) + // Check that the service Msg fully-qualified method name has already // been registered (via RegisterInterfaces). If the user registers a // service without registering according service Msg type, there might be // some unexpected behavior down the road. Since we can't return an error // (`Server.RegisterService` interface restriction) we panic (at startup). - serviceMsg, err := msr.interfaceRegistry.Resolve(fqMethod) - if err != nil || serviceMsg == nil { + reqType, err := msr.interfaceRegistry.Resolve(requestTypeName) + if err != nil || reqType == nil { panic( fmt.Errorf( "type_url %s has not been registered yet. "+ "Before calling RegisterService, you must register all interfaces by calling the `RegisterInterfaces` "+ "method on module.BasicManager. Each module should call `msgservice.RegisterMsgServiceDesc` inside its "+ "`RegisterInterfaces` method with the `_Msg_serviceDesc` generated by proto-gen", - fqMethod, + requestTypeName, ), ) } @@ -72,7 +95,7 @@ func (msr *MsgServiceRouter) RegisterService(sd *grpc.ServiceDesc, handler inter // registered more than once, then we should error. Since we can't // return an error (`Server.RegisterService` interface restriction) we // panic (at startup). - _, found := msr.routes[fqMethod] + _, found := msr.routes[requestTypeName] if found { panic( fmt.Errorf( @@ -83,7 +106,7 @@ func (msr *MsgServiceRouter) RegisterService(sd *grpc.ServiceDesc, handler inter ) } - msr.routes[fqMethod] = func(ctx sdk.Context, req sdk.MsgRequest) (*sdk.Result, error) { + msr.routes[requestTypeName] = func(ctx sdk.Context, req sdk.Msg) (*sdk.Result, error) { ctx = ctx.WithEventManager(sdk.NewEventManager()) interceptor := func(goCtx context.Context, _ interface{}, _ *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) { goCtx = context.WithValue(goCtx, sdk.SdkContextKey, ctx) @@ -112,3 +135,6 @@ func (msr *MsgServiceRouter) SetInterfaceRegistry(interfaceRegistry codectypes.I } func noopDecoder(_ interface{}) error { return nil } +func noopInterceptor(_ context.Context, _ interface{}, _ *grpc.UnaryServerInfo, _ grpc.UnaryHandler) (interface{}, error) { + return nil, nil +} diff --git a/baseapp/msg_service_router_test.go b/baseapp/msg_service_router_test.go index 68709f1b1f..0b2b9e654b 100644 --- a/baseapp/msg_service_router_test.go +++ b/baseapp/msg_service_router_test.go @@ -80,11 +80,11 @@ func TestMsgService(t *testing.T) { ) _ = app.BeginBlock(abci.RequestBeginBlock{Header: ocproto.Header{Height: 1}}) - msg := testdata.NewServiceMsgCreateDog(&testdata.MsgCreateDog{Dog: &testdata.Dog{Name: "Spot"}}) + msg := testdata.MsgCreateDog{Dog: &testdata.Dog{Name: "Spot"}} txBuilder := encCfg.TxConfig.NewTxBuilder() txBuilder.SetFeeAmount(testdata.NewTestFeeAmount()) txBuilder.SetGasLimit(testdata.NewTestGasLimit()) - err := txBuilder.SetMsgs(msg) + err := txBuilder.SetMsgs(&msg) require.NoError(t, err) // First round: we gather all the signer infos. We use the "set empty diff --git a/baseapp/options.go b/baseapp/options.go index 78bd10a80c..b457d4507e 100644 --- a/baseapp/options.go +++ b/baseapp/options.go @@ -20,7 +20,7 @@ import ( // SetPruning sets a pruning option on the multistore associated with the app func SetPruning(opts sdk.PruningOptions) func(*BaseApp) { - return func(bap *BaseApp) { bap.cms.SetPruning(opts) } + return func(bapp *BaseApp) { bapp.cms.SetPruning(opts) } } // SetMinGasPrices returns an option that sets the minimum gas prices on the app. @@ -30,17 +30,17 @@ func SetMinGasPrices(gasPricesStr string) func(*BaseApp) { panic(fmt.Sprintf("invalid minimum gas prices: %v", err)) } - return func(bap *BaseApp) { bap.setMinGasPrices(gasPrices) } + return func(bapp *BaseApp) { bapp.setMinGasPrices(gasPrices) } } // SetHaltHeight returns a BaseApp option function that sets the halt block height. func SetHaltHeight(blockHeight uint64) func(*BaseApp) { - return func(bap *BaseApp) { bap.setHaltHeight(blockHeight) } + return func(bapp *BaseApp) { bapp.setHaltHeight(blockHeight) } } // SetHaltTime returns a BaseApp option function that sets the halt block time. func SetHaltTime(haltTime uint64) func(*BaseApp) { - return func(bap *BaseApp) { bap.setHaltTime(haltTime) } + return func(bapp *BaseApp) { bapp.setHaltTime(haltTime) } } // SetMinRetainBlocks returns a BaseApp option function that sets the minimum @@ -60,6 +60,11 @@ func SetIndexEvents(ie []string) func(*BaseApp) { return func(app *BaseApp) { app.setIndexEvents(ie) } } +// SetIAVLCacheSize provides a BaseApp option function that sets the size of IAVL cache. +func SetIAVLCacheSize(size int) func(*BaseApp) { + return func(bapp *BaseApp) { bapp.cms.SetIAVLCacheSize(size) } +} + // SetInterBlockCache provides a BaseApp option function that sets the // inter-block cache. func SetInterBlockCache(cache sdk.MultiStorePersistentCache) func(*BaseApp) { @@ -109,12 +114,16 @@ func (app *BaseApp) SetParamStore(ps ParamStore) { app.paramStore = ps } -// SetAppVersion sets the application's version string. -func (app *BaseApp) SetAppVersion(v string) { +// SetVersion sets the application's version string. +func (app *BaseApp) SetVersion(v string) { if app.sealed { - panic("SetAppVersion() on sealed BaseApp") + panic("SetVersion() on sealed BaseApp") } + app.version = v +} +// SetProtocolVersion sets the application's protocol version +func (app *BaseApp) SetProtocolVersion(v uint64) { app.appVersion = v } diff --git a/baseapp/test_helpers.go b/baseapp/test_helpers.go index 54f8400bd0..21bc9759d9 100644 --- a/baseapp/test_helpers.go +++ b/baseapp/test_helpers.go @@ -23,7 +23,9 @@ func (app *BaseApp) Simulate(txBytes []byte) (sdk.GasInfo, *sdk.Result, error) { if err != nil { return sdk.GasInfo{}, nil, sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "%s", err) } - return app.runTx(txBytes, tx, true) + + gasInfo, result, _, err := app.runTx(txBytes, tx, true) + return gasInfo, result, err } func (app *BaseApp) Deliver(txEncoder sdk.TxEncoder, tx sdk.Tx) (sdk.GasInfo, *sdk.Result, error) { @@ -32,7 +34,8 @@ func (app *BaseApp) Deliver(txEncoder sdk.TxEncoder, tx sdk.Tx) (sdk.GasInfo, *s if err != nil { return sdk.GasInfo{}, nil, sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "%s", err) } - return app.runTx(txBytes, tx, false) + gasInfo, result, _, err := app.runTx(txBytes, tx, false) + return gasInfo, result, err } // Context with current {check, deliver}State of the app used by tests. @@ -49,3 +52,7 @@ func (app *BaseApp) NewContext(isCheckTx bool, header ocproto.Header) sdk.Contex func (app *BaseApp) NewUncachedContext(isCheckTx bool, header ocproto.Header) sdk.Context { return sdk.NewContext(app.cms, header, isCheckTx, app.logger) } + +func (app *BaseApp) GetContextForDeliverTx(txBytes []byte) sdk.Context { + return app.getContextForTx(app.deliverState, txBytes) +} diff --git a/client/broadcast.go b/client/broadcast.go index 0120609e62..d2e96ed3c1 100644 --- a/client/broadcast.go +++ b/client/broadcast.go @@ -5,11 +5,12 @@ import ( "fmt" "strings" - "github.com/line/ostracon/crypto/tmhash" - "github.com/line/ostracon/mempool" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" + "github.com/line/ostracon/mempool" + octypes "github.com/line/ostracon/types" + "github.com/line/lbm-sdk/client/flags" sdk "github.com/line/lbm-sdk/types" sdkerrors "github.com/line/lbm-sdk/types/errors" @@ -46,13 +47,13 @@ func (ctx Context) BroadcastTx(txBytes []byte) (res *sdk.TxResponse, err error) // TODO: Avoid brittle string matching in favor of error matching. This requires // a change to Tendermint's RPCError type to allow retrieval or matching against // a concrete error type. -func CheckTendermintError(err error, txBytes []byte) *sdk.TxResponse { +func CheckTendermintError(err error, tx octypes.Tx) *sdk.TxResponse { if err == nil { return nil } errStr := strings.ToLower(err.Error()) - txHash := fmt.Sprintf("%X", tmhash.Sum(txBytes)) + txHash := fmt.Sprintf("%X", tx.Hash()) switch { case strings.Contains(errStr, strings.ToLower(mempool.ErrTxInCache.Error())): diff --git a/client/cmd.go b/client/cmd.go index cb8dad1c98..cacf7e0465 100644 --- a/client/cmd.go +++ b/client/cmd.go @@ -97,6 +97,7 @@ func ReadPersistentCommandFlags(clientCtx Context, flagSet *pflag.FlagSet) (Cont homeDir, _ := flagSet.GetString(flags.FlagHome) clientCtx = clientCtx.WithHomeDir(homeDir) } + if !clientCtx.Simulate || flagSet.Changed(flags.FlagDryRun) { dryRun, _ := flagSet.GetBool(flags.FlagDryRun) clientCtx = clientCtx.WithSimulation(dryRun) @@ -194,11 +195,6 @@ func readTxCommandFlags(clientCtx Context, flagSet *pflag.FlagSet) (Context, err clientCtx = clientCtx.WithGenerateOnly(genOnly) } - if !clientCtx.Simulate || flagSet.Changed(flags.FlagDryRun) { - dryRun, _ := flagSet.GetBool(flags.FlagDryRun) - clientCtx = clientCtx.WithSimulation(dryRun) - } - if !clientCtx.Offline || flagSet.Changed(flags.FlagOffline) { offline, _ := flagSet.GetBool(flags.FlagOffline) clientCtx = clientCtx.WithOffline(offline) @@ -257,21 +253,6 @@ func readTxCommandFlags(clientCtx Context, flagSet *pflag.FlagSet) (Context, err return clientCtx, nil } -// ReadHomeFlag checks if home flag is changed. -// If this is a case, we update HomeDir field of Client Context -/* Discovered a bug with Cory -./build/simd init andrei --home ./test -cd test/config there is no client.toml configuration file -*/ -func ReadHomeFlag(clientCtx Context, cmd *cobra.Command) Context { - if cmd.Flags().Changed(flags.FlagHome) { - rootDir, _ := cmd.Flags().GetString(flags.FlagHome) - clientCtx = clientCtx.WithHomeDir(rootDir) - } - - return clientCtx -} - // GetClientQueryContext returns a Context from a command with fields set based on flags // defined in AddQueryFlagsToCmd. An error is returned if any flag query fails. // diff --git a/client/cmd_test.go b/client/cmd_test.go index a6eaf50fad..16dc2839e7 100644 --- a/client/cmd_test.go +++ b/client/cmd_test.go @@ -97,8 +97,7 @@ func TestSetCmdClientContextHandler(t *testing.T) { tc := tc t.Run(tc.name, func(t *testing.T) { - ctx := context.Background() - ctx = context.WithValue(ctx, client.ClientContextKey, &client.Context{}) + ctx := context.WithValue(context.Background(), client.ClientContextKey, &client.Context{}) cmd := newCmd() _ = testutil.ApplyMockIODiscardOutErr(cmd) diff --git a/client/config/cmd.go b/client/config/cmd.go index c8f59e0651..ebbcffa76b 100644 --- a/client/config/cmd.go +++ b/client/config/cmd.go @@ -5,10 +5,10 @@ import ( "fmt" "path/filepath" - ostcli "github.com/line/ostracon/libs/cli" - "github.com/spf13/cobra" + ostcli "github.com/line/ostracon/libs/cli" + "github.com/line/lbm-sdk/client" "github.com/line/lbm-sdk/client/flags" ) @@ -36,8 +36,11 @@ func runConfigCmd(cmd *cobra.Command, args []string) error { switch len(args) { case 0: - // print all client config fields to sdt out - s, _ := json.MarshalIndent(conf, "", "\t") + // print all client config fields to stdout + s, err := json.MarshalIndent(conf, "", "\t") + if err != nil { + return err + } cmd.Println(string(s)) case 1: diff --git a/client/config/config_test.go b/client/config/config_test.go index 6a5d3f1ca0..5e116e4188 100644 --- a/client/config/config_test.go +++ b/client/config/config_test.go @@ -2,7 +2,7 @@ package config_test import ( "bytes" - "fmt" + //"fmt" "io/ioutil" "os" "testing" @@ -11,7 +11,6 @@ import ( "github.com/line/lbm-sdk/client" "github.com/line/lbm-sdk/client/config" - "github.com/line/lbm-sdk/client/flags" clitestutil "github.com/line/lbm-sdk/testutil/cli" "github.com/line/lbm-sdk/x/staking/client/cli" ) @@ -74,10 +73,10 @@ func TestConfigCmdEnvFlag(t *testing.T) { args []string expNode string }{ - {"env var is set with no flag", testNode1, []string{"validators"}, testNode1}, - {"env var is set with a flag", testNode1, []string{"validators", fmt.Sprintf("--%s=%s", flags.FlagNode, testNode2)}, testNode2}, + //{"env var is set with no flag", testNode1, []string{"validators"}, testNode1}, + //{"env var is set with a flag", testNode1, []string{"validators", fmt.Sprintf("--%s=%s", flags.FlagNode, testNode2)}, testNode2}, {"env var is not set with no flag", "", []string{"validators"}, defaultNode}, - {"env var is not set with a flag", "", []string{"validators", fmt.Sprintf("--%s=%s", flags.FlagNode, testNode2)}, testNode2}, + //{"env var is not set with a flag", "", []string{"validators", fmt.Sprintf("--%s=%s", flags.FlagNode, testNode2)}, testNode2}, } for _, tc := range tt { diff --git a/client/context.go b/client/context.go index 9d2e58a81d..ebb4a29156 100644 --- a/client/context.go +++ b/client/context.go @@ -23,13 +23,16 @@ import ( // Context implements a typical context created in SDK modules for transaction // handling and queries. type Context struct { - FromAddress sdk.AccAddress - Client rpcclient.Client - ChainID string - JSONMarshaler codec.JSONMarshaler + FromAddress sdk.AccAddress + Client rpcclient.Client + ChainID string + // Deprecated: Codec codec will be changed to Codec: codec.Codec + JSONCodec codec.JSONCodec + Codec codec.Codec InterfaceRegistry codectypes.InterfaceRegistry Input io.Reader Keyring keyring.Keyring + KeyringOptions []keyring.Option Output io.Writer OutputFormat string Height int64 @@ -60,6 +63,12 @@ func (ctx Context) WithKeyring(k keyring.Keyring) Context { return ctx } +// WithKeyringOptions returns a copy of the context with an updated keyring. +func (ctx Context) WithKeyringOptions(opts ...keyring.Option) Context { + ctx.KeyringOptions = opts + return ctx +} + // WithInput returns a copy of the context with an updated input. func (ctx Context) WithInput(r io.Reader) Context { // convert to a bufio.Reader to have a shared buffer between the keyring and the @@ -69,9 +78,21 @@ func (ctx Context) WithInput(r io.Reader) Context { return ctx } -// WithJSONMarshaler returns a copy of the Context with an updated JSONMarshaler. -func (ctx Context) WithJSONMarshaler(m codec.JSONMarshaler) Context { - ctx.JSONMarshaler = m +// Deprecated: WithJSONCodec returns a copy of the Context with an updated JSONCodec. +func (ctx Context) WithJSONCodec(m codec.JSONCodec) Context { + ctx.JSONCodec = m + // since we are using ctx.Codec everywhere in the SDK, for backward compatibility + // we need to try to set it here as well. + if c, ok := m.(codec.Codec); ok { + ctx.Codec = c + } + return ctx +} + +// WithCodec returns a copy of the Context with an updated Codec. +func (ctx Context) WithCodec(m codec.Codec) Context { + ctx.JSONCodec = m + ctx.Codec = m return ctx } @@ -251,10 +272,10 @@ func (ctx Context) PrintBytes(o []byte) error { // PrintProto outputs toPrint to the ctx.Output based on ctx.OutputFormat which is // either text or json. If text, toPrint will be YAML encoded. Otherwise, toPrint -// will be JSON encoded using ctx.JSONMarshaler. An error is returned upon failure. +// will be JSON encoded using ctx.Codec. An error is returned upon failure. func (ctx Context) PrintProto(toPrint proto.Message) error { // always serialize JSON initially because proto json can't be directly YAML encoded - out, err := ctx.JSONMarshaler.MarshalJSON(toPrint) + out, err := ctx.Codec.MarshalJSON(toPrint) if err != nil { return err } @@ -348,5 +369,5 @@ func NewKeyringFromBackend(ctx Context, backend string) (keyring.Keyring, error) return keyring.New(sdk.KeyringServiceName(), keyring.BackendMemory, ctx.KeyringDir, ctx.Input) } - return keyring.New(sdk.KeyringServiceName(), backend, ctx.KeyringDir, ctx.Input) + return keyring.New(sdk.KeyringServiceName(), backend, ctx.KeyringDir, ctx.Input, ctx.KeyringOptions...) } diff --git a/client/context_test.go b/client/context_test.go index b3ee3033a8..1b4bd450af 100644 --- a/client/context_test.go +++ b/client/context_test.go @@ -41,7 +41,7 @@ func TestContext_PrintObject(t *testing.T) { // proto // registry := testdata.NewTestInterfaceRegistry() - ctx = ctx.WithJSONMarshaler(codec.NewProtoCodec(registry)) + ctx = ctx.WithCodec(codec.NewProtoCodec(registry)) // json buf := &bytes.Buffer{} @@ -51,7 +51,7 @@ func TestContext_PrintObject(t *testing.T) { require.NoError(t, err) require.Equal(t, `{"animal":{"@type":"/testdata.Dog","size":"big","name":"Spot"},"x":"10"} -`, string(buf.Bytes())) +`, buf.String()) // yaml buf = &bytes.Buffer{} @@ -65,7 +65,7 @@ func TestContext_PrintObject(t *testing.T) { name: Spot size: big x: "10" -`, string(buf.Bytes())) +`, buf.String()) // // amino @@ -81,7 +81,7 @@ x: "10" require.NoError(t, err) require.Equal(t, `{"type":"testdata/HasAnimal","value":{"animal":{"type":"testdata/Dog","value":{"size":"big","name":"Spot"}},"x":"10"}} -`, string(buf.Bytes())) +`, buf.String()) // yaml buf = &bytes.Buffer{} @@ -98,7 +98,7 @@ value: name: Spot size: big x: "10" -`, string(buf.Bytes())) +`, buf.String()) } func TestCLIQueryConn(t *testing.T) { diff --git a/client/debug/main.go b/client/debug/main.go index bc799838dd..0b217a8596 100644 --- a/client/debug/main.go +++ b/client/debug/main.go @@ -1,7 +1,6 @@ package debug import ( - "encoding/base64" "encoding/hex" "fmt" "strconv" @@ -10,13 +9,12 @@ import ( "github.com/spf13/cobra" "github.com/line/lbm-sdk/client" - "github.com/line/lbm-sdk/crypto/keys/ed25519" cryptotypes "github.com/line/lbm-sdk/crypto/types" sdk "github.com/line/lbm-sdk/types" - "github.com/line/lbm-sdk/types/errors" "github.com/line/lbm-sdk/version" ) +// Cmd creates a main CLI command func Cmd() *cobra.Command { cmd := &cobra.Command{ Use: "debug", @@ -31,90 +29,31 @@ func Cmd() *cobra.Command { return cmd } -// getPubKeyFromString returns a Tendermint PubKey (PubKeyEd25519) by attempting -// to decode the pubkey string from hex, base64, and finally bech32. If all -// encodings fail, an error is returned. -func getPubKeyFromString(pkstr string) (cryptotypes.PubKey, error) { - bz, err := hex.DecodeString(pkstr) - if err == nil { - if len(bz) == ed25519.PubKeySize { - return &ed25519.PubKey{Key: bz}, nil - } - } - - bz, err = base64.StdEncoding.DecodeString(pkstr) - if err == nil { - if len(bz) == ed25519.PubKeySize { - return &ed25519.PubKey{Key: bz}, nil - } - } - - pk, err := sdk.GetPubKeyFromBech32(sdk.Bech32PubKeyTypeAccPub, pkstr) - if err == nil { - return pk, nil - } - - pk, err = sdk.GetPubKeyFromBech32(sdk.Bech32PubKeyTypeValPub, pkstr) - if err == nil { - return pk, nil - } - - pk, err = sdk.GetPubKeyFromBech32(sdk.Bech32PubKeyTypeConsPub, pkstr) - if err == nil { - return pk, nil - } - - return nil, fmt.Errorf("pubkey '%s' invalid; expected hex, base64, or bech32 of correct size", pkstr) +// getPubKeyFromString decodes SDK PubKey using JSON marshaler. +func getPubKeyFromString(ctx client.Context, pkstr string) (cryptotypes.PubKey, error) { + var pk cryptotypes.PubKey + err := ctx.Codec.UnmarshalInterfaceJSON([]byte(pkstr), &pk) + return pk, err } func PubkeyCmd() *cobra.Command { return &cobra.Command{ Use: "pubkey [pubkey]", - Short: "Decode a ED25519 pubkey from hex, base64, or bech32", - Long: fmt.Sprintf(`Decode a pubkey from hex, base64, or bech32. + Short: "Decode a pubkey from proto JSON", + Long: fmt.Sprintf(`Decode a pubkey from proto JSON and display it's address. Example: -$ %s debug pubkey TWFuIGlzIGRpc3Rpbmd1aXNoZWQsIG5vdCBvbmx5IGJ5IGhpcyByZWFzb24sIGJ1dCBieSB0aGlz -$ %s debug pubkey linkpub1cqmsrdepq28g8wmpa2hmq06y770jcjr48ntw932wc8l0cl7fz5xr4sahy3s3v0r3mez - `, version.AppName, version.AppName), +$ %s debug pubkey '{"@type":"/lbm.crypto.secp256k1.PubKey","key":"AurroA7jvfPd1AadmmOvWM2rJSwipXfRf8yD6pLbA2DJ"}' + `, version.AppName), Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { clientCtx := client.GetClientContextFromCmd(cmd) - - pk, err := getPubKeyFromString(args[0]) + pk, err := getPubKeyFromString(clientCtx, args[0]) if err != nil { return err } - - edPK, ok := pk.(*ed25519.PubKey) - if !ok { - return errors.Wrapf(errors.ErrInvalidType, "invalid pubkey type; expected ED25519") - } - - pubKeyJSONBytes, err := clientCtx.LegacyAmino.MarshalJSON(edPK) - if err != nil { - return err - } - accPub, err := sdk.Bech32ifyPubKey(sdk.Bech32PubKeyTypeAccPub, edPK) - if err != nil { - return err - } - valPub, err := sdk.Bech32ifyPubKey(sdk.Bech32PubKeyTypeValPub, edPK) - if err != nil { - return err - } - consenusPub, err := sdk.Bech32ifyPubKey(sdk.Bech32PubKeyTypeConsPub, edPK) - if err != nil { - return err - } - - cmd.Println("Address:", edPK.Address()) - cmd.Printf("Hex: %X\n", edPK.Key) - cmd.Println("JSON (base64):", string(pubKeyJSONBytes)) - cmd.Println("Bech32 Acc:", accPub) - cmd.Println("Bech32 Validator Operator:", valPub) - cmd.Println("Bech32 Validator Consensus:", consenusPub) - + cmd.Println("Address:", pk.Address()) + cmd.Println("PubKey Hex:", hex.EncodeToString(pk.Bytes())) return nil }, } @@ -125,7 +64,7 @@ func AddrCmd() *cobra.Command { Use: "addr [address]", Short: "Convert an address between hex and bech32", Long: fmt.Sprintf(`Convert an address between hex encoding and bech32. - + Example: $ %s debug addr link19wgf6ymq2ur6r59st95e04e49m69z4al4fc982 `, version.AppName), @@ -169,7 +108,7 @@ func RawBytesCmd() *cobra.Command { Use: "raw-bytes [raw-bytes]", Short: "Convert raw bytes output (eg. [10 21 13 255]) to hex", Long: fmt.Sprintf(`Convert raw-bytes to hex. - + Example: $ %s debug raw-bytes [72 101 108 108 111 44 32 112 108 97 121 103 114 111 117 110 100] `, version.AppName), diff --git a/client/docs/config.json b/client/docs/config.json index fd5add504e..6989e7a128 100644 --- a/client/docs/config.json +++ b/client/docs/config.json @@ -115,6 +115,14 @@ } } }, + { + "url": "./tmp-swagger-gen/lbm/authz/v1/query.swagger.json", + "operationIds": { + "rename": { + "Params": "AuthzParams" + } + } + }, { "url": "./tmp-swagger-gen/ibc/core/client/v1/query.swagger.json", "operationIds": { @@ -154,9 +162,19 @@ "url": "./tmp-swagger-gen/lbm/token/v1/query.swagger.json", "operationIds": { "rename": { - "Params": "TokenParams" + "Params": "TokenParams", + "Balance": "TokenBalance", + "Grants": "TokenGrants" } } }, + { + "url": "./tmp-swagger-gen/lbm/feegrant/v1/query.swagger.json", + "operationIds": { + "rename": { + "Params": "FeegrantParams" + } + } + } ] } diff --git a/client/docs/statik/statik.go b/client/docs/statik/statik.go index 51cad52c03..3f05bed638 100644 --- a/client/docs/statik/statik.go +++ b/client/docs/statik/statik.go @@ -8,7 +8,7 @@ import ( func init() { - data := "PK\x03\x04\x14\x00\x08\x00\x08\x00\x00\x00!(\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x11\x00 \x00favicon-16x16.pngUT\x05\x00\x01\x80Cm8\x00\xbd\x01B\xfe\x89PNG\x0d\n\x1a\n\x00\x00\x00\x0dIHDR\x00\x00\x00\x10\x00\x00\x00\x10\x08\x06\x00\x00\x00\x1f\xf3\xffa\x00\x00\x01\x84IDATx\x01\x95S\x03Luq\x1c\xfd\x8c\xf1\xc3\xec0\xa7)\xcda\xb6k6\xb2\x9b\xf9\xb2k\xc85/\xdb\x8dqx\xc6\x94m\xcc{\xef\x7fO\xff\xf3l\xdc\xed\xf2\xe0\xfe\xf8\xc9\xffP\x14\x11/\x14[\xa3P\xc4\xa1\xbc?\xf1t>7\x12s\x13\x03\x85\xca7IR a\xb5j\x8f\xa71\xbe]\x88\xf6\xb9L\xf0\x1c\x93\xcf\xda\xe3)\x10\x93f\x8d\xe4\x06\x13\xcf\xde<\x9b\xd14\x95\x8a\x92\x81OA\xcfF\x89\xdd<\x9b M\xe6}L\xe4\x07\x15\xc5\xf5\xe3\xffI\x0c{\xd6\x8d\xffs\x994\xbasfh\xae?\xafk\x1aprw\x10 <\xb9\xdb\xc7\x86\xa6\xd1\x19I\n\xa8\xb1\xd7\x84y3g\x171T$\xb5c\x7fq\xfbbq\xbfk\x8e'\x1dQ\xb0\xc2,\x92\x0bx|;F\xe5\xf0\xef\x00\x83\xf2\xa1\x1fx|?q\xbd\xcb\xc2\x16\x80ZF\xf0\xc4J\xf3\xe3\xe4n1\xcc\x17k`:}\xcby\xe8\x98\xcbB\xc7|6z\x97r\xd14\x9d\x06\xd3\xf9\x8a\xe4\x94\x90\x8b\xb6\xd9\x0cP\xebc@\xd0|\xbe*\xc94\xc8\xa7\x98'\xcdh\x00\xe3\xd92\xa6vK}\x0cB\xa4\xf0+D\n\xc7\x81)\xb0\x10\x9a\xe3\xa9\xd8\x8bx\xe4(\xa2\xbb\x8dl\x0d\x01\xb6\x8a-\xf378\xbe\xdd\xc7\xa6\xb6\xc9\xd9\xc6d\xd8\\m\xf4\x0c\x92 uQ\x0e\xd2\xf5\xb3\xd1\xf1w\xdfQ\x16\xb34a$\xa1\xc4\xc4(V\xbcF\xd9\xdf\xa4\x91\xe9\xb0&,\x12+\xcd\x93\xcf\x1c\x1cb\xdc\xca\x00qt\xeb\xcc-\x14\x89\xfe\xfc\x0fm2j\x88\xec\xccs\x18\x00\x00\x00\x00IEND\xaeB`\x82\x01\x00\x00\xff\xffPK\x07\x08\xd4`4t\xc7\x01\x00\x00\xbd\x01\x00\x00PK\x03\x04\x14\x00\x08\x00\x08\x00\x00\x00!(\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x11\x00 \x00favicon-32x32.pngUT\x05\x00\x01\x80Cm8\x00u\x04\x8a\xfb\x89PNG\x0d\n\x1a\n\x00\x00\x00\x0dIHDR\x00\x00\x00 \x00\x00\x00 \x08\x06\x00\x00\x00szz\xf4\x00\x00\x04|ID\xc4\xcf\xd0@\x04&%\xad\x1e\x16\x0f\xf7\x8d\x97AR\xfa\xca\xe7l\x87\x05\xf8\xd2\xfb\x0c\x84\x1d\x0dLVY\xdc/ju\x13\x1a\x88\xd2\xa0\xaaa\x82|nzp_\xf4\x03\xc8 \xd4;^\x8a9}\xeeu\x9a\x91 `\x04\x14s\xec\xe1\x0c\xc6]\xa3\x05``\xd1w\x12*~ \x00\xf3\xae\xd3\xa0\x9cb\x82\xa2bx(\xb3n\x1fqx\xd2\xf2\xda4\x1d\x8a}\x1ck\xd4>\x9cI+\xeb\xb3\xf4k\xc8u`L\x93\xf3]4\xb5\xd0\xc3\xe33\xd9\xee\xd7\xf2\xd9\x19\xea\x18\xc9\xc1Y:\x18\xfb(-\xadN\x82\x06e\xd5\x1f0\xa2\x1dV\xf8\xbe0\xc1\x985\x01\xf8\xd2~\\\xa6\xa5\xb5)&\xf6\x98V\x80l\xe4\x03\xf8\x03\x04\x00s\x9a^\xec\x85\x00\xf4+\x0b\x00\xe1:G\xf2p\x96\x0e\xc4,\xe46\x1e5\xbbP\xdd\x15J\x80}\xce\xa4\xe2\xc8{m\xa4\xe2\xc3\xc2\x01\x07\xc0\xdb\xa4\x18-\xa1\x931\xba\x10S\xfa%\xb6P`\x10\x19v\x99#|Gg\x9b \x10W\xf6\x8dI1\xba\x92\xd66\x17E\x12\xfa\xd9\xa8\xf3UTe\n\x1b\x95\x9d\x81f\xe5\x18\xa5umc\x81\x86\xa6\xeb\xec \x804\xcbg\x17\xa19\xfa\xc6\xf7<\xa3\xbd\xf2\x0e\x7f\x02\x80\x97Y\xc7\xac\x184$h\xa3v\xba! \xcc{\xcd\xb4!\xb1\xd8\x92%h\xe3\x93\xdc\xd3_\xda1\xe6\xaei\xcf\x83\xa6p\xbc$\xf0\xb2\xda\x94\xa2q\x14B@\x13\xdb\xff\xf3\xd7\x0d\xfaA\xb9\xc5n{\x8e\xd6Y\x08\x01u\xc1'~\x16\x8e\xe9\x04\xa2\xfbA+\xc74\x0c\x98\xab\xd7:\xfc0\xd1v\xaf$\xa2#\xb7\xf1\x08\xfdm!OXh8\x10j|g\xd1\xe0a\xb2\x99\x04\x9a[y\x9a\xbdk\xf24C$\xa0\x9e#\x9f\xa3\xa8\x001\xc6\x1a\"\xc0\xe4i\xa6\xcc0\xf3\xf7\xb7\xf5XE\xb8\xe0\xa1\xc9\xc2\x0c\x90\x83\x80$\x838\xdf\xd6\xe3\xd4\x82FNG\x0f\x876\x8a\xbf1\xa8d(\xa7@\x8cQX\x90\xdb\x19\x9f\xc5YG\xe9\x9e\x00\xa5y3]\x9aJ\xe1\"\x00\x00\x00\x00IEND\xaeB`\x82\x01\x00\x00\xff\xffPK\x07\x086B\xc8\xd7\x7f\x04\x00\x00u\x04\x00\x00PK\x03\x04\x14\x00\x08\x00\x08\x00\x00\x00!(\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\n\x00 \x00index.htmlUT\x05\x00\x01\x80Cm8\x9cT]k\xdc:\x10}\xdf_1Q\x1e\x92\\\"\xfb&\x81p\xf1\xb5\xfd\x90\xa6\xa5\x81\x94\x06\x92}(\xa5\x14\xd9\x1a{\xa7\x91\xa5E\x92\xf7#!\xff\xbdX\xf6\xae\xb7\xdd\x90BYX\x8f\xe7\x9c9\x1a\x1d\x8d\x9c\x1ep\x0e\x1f\x1f>\xddBe,8/<\x95 \xc9yKE\xeb\xc9h(Z-\x15B\xd1\x92\x92\xc0y>I\x0f\xae?\xbf{\xf8r\xf7\x1ef\xbeQ\xf9$\xed\x1e\xa0\x84\xae3\x86\x9a\xe5\x13\x80t\x86Bv\x01@\xda\xa0\x17P\xce\x84u\xe836}\xf8\xc0\xffc\x03\xe4\xc9+\xcc\xef\x97\xa2\xae\xd1\xc2\xf4&\x8d\xfbL\x8f*\xd2\x8f`Qe\xcc\xf9\xb5B7C\xf4\x0c\xfcz\x8e\x19\xf3\xb8\xf2q\xe9\x1c\x83\x99\xc5*c\xae\xd7\xe0-E!\xbb'A\xa5\xd1\x9bbjD\x8d\xf1\\\xd7\x9b\xeaJ,:\x9c_\x9c\xaf.\xce\xa3\x008zB\x97\xb1\x90a\x10\xff\x9d\xde\xd9\xe5\xea\xec\xf2\x17\xbd\x90\x19\xf5\xc2\xc6\xfa\x18\x82\x9bC\xf8<<\x01\n\xb3\xe2\x8e\x9eH\xd7 \x14\xc6J\xb4\xbc0\xab\xff\xb7\xb8Y\xa0\xad\x94Y&\xc0\x1b\xf3\xc4]i\x8dR\x85\xb0\x8e/\xd0z*\x85\xda\xe7\xf2u\x02=q\x83\xbdL\x86\xe0\x9f\xd3M\x90\x14X\x19\x8b\xe3\xbb\xa8<\xda7\xfb#=CK~O\xb40r\xbdW\xd8\x08[\x93N\xfe\x1d\xdb+D\xf9X[\xd3j\x99\xc0a%\xba\xdf(\xd5\xfd\xa7\xf1\xd6\xaf4\xee'\xac\x0b;\xf9\xc1OI\x0b \xb9;\x0e,OcI\x8b|2\x18^Z\x9a{p\xb6\xdc%\xf1~\xc6\xa3\x1f\x8e\xe5\xdd*\x81\x94\xbfY\xe1\xbc\xd0R(\xa3\x91\xcf-:\xf4o\x14\xf7/K\xd2\xd2,#\xa3\x95\x11\x122\xa8Z]v\x17\xec\xf8\x04\x9e7N\xc51\\\x85{&\xc0\xad\x9d\xc7f\xc8\x97F;\x0f-A\x06\xc3m\x99\xde\\\x85\x9e\x8fGG[\xab\x12`Q\xeb\x8c\xd8v\xfb_}K7\xd3F\xfe]\xb1\xa1\x82h%q{\x8b\x9b6\x88/\xc4i }\xc07u~}\xe5\xad\xfd\xc9\x98\xe7q\xd8_}o\xf1\x92%\x9dx\x15\x9f\xd3yO\xbdX]\x1aA\xc9>t\xd6o\x93\xd3\x92\xf2\x04l\xc5\x8d\x92jz\xc1jN\xd6\xf2\xa9\x87\xfa\xb5]\x05\xcc\xf9\x1acB\xa9,\x9f\xd0\x08\x05\xb7\x962\xec\xdb\xb6\xe2\x16b\xc6\xd5\x942H\x05KfI\x06\x7f\x9c\x98\xa8\xc0\xd5\x9c\xa2\x0c\x13\xa3\xe7U\x8e\xb55;'Nk\xe6\xd0\x9d;\xd4%^\x14\xbd\xd5\xf7\x92QN\x8e.\x1c`\x079m\xe3\x9e\x8a\xfe\xed\xa2\xad\xe0y>\xe6\xe23\xdc\xf8u\xa7=\xa3\xf6\xa1\x98\xb4\x17g\xa9\xf4\x1dA\xa8Z\xe4\xf6\x88_\xfc)\xf8\xd5N\xcf,\xea\xb4\xabS\xf2\xd2\xe0v\x10\x90\x82\xbd\xb3\xe1\xc1g\xc8>\x120\x0c{\x1d\xbd\x1c\xd1\x7fd\xb4\xbf\x82|\xf7\x9f\xd0\xa7\x1e\x82\xc5`H\xc0\x94F3p0$H.\x0f]v3\xaa\x9b\x1c\x83EW}\xba4\x12O`_\xb5!H5\xd1 \x9a\x0c\xaa\xcd\x04\x8cE\xe7M:\xe1\x08\xfe\xefQ\xab\x02\xfe\xb7A\xeb\xb6k\xbb\x05{\xef\x8e\xde\x84\xcb\x9c\xb2\x8f\x04\xd7U\xf9\x9aQ:\xbe\xf51\xf1\x1a\xaaW\x97uR\xdd\xe7\xf59\x974\xb7\xfc5s\xd0\xc4P\xdf\xdd\"\xd7\x96\xc2\xdab7x\xb8;\xfc\x01\xfa'\x00\x00\xff\xffPK\x07\x08]\x12r 9\x03\x00\x00T \x00\x00PK\x03\x04\x14\x00\x08\x00\x08\x00\x00\x00!(\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x14\x00 \x00swagger-ui-bundle.jsUT\x05\x00\x01\x80Cm8\xec\xfdyw\xdb6\xf68\x8c\xff\xffy\x15\xd7\xfa\xf6\x9b!kZ\xb1\x9d\xa5\xad\x13\xc5\x93\xc5m\xb3g\xe2\xa4\xcb\xa8\x1a\x1fZ\x82,6\x14\xa8\x90\x90m\xb5\xf2\xef\xb5\xff\x0e.\x00\x12$\x01\x10r\xdc\x99\xf9<\xcf\xc3s\xdaX\\\xb0\\\\\\\xdc\xfdn\xc1tI\xc7,\xc9h@\"`!\xfc\xf9?\x00\x00\xbd\xec\xf4w2f=\x18\x0c\x80\xad\x16$\x9b\x02\xb9\\d9+\xe0\xd6-\xd3\xd3y6Y\xa6\x04\x0e\xe5\x1f}\xf5\xf6\x00X\x10\xc2\x01\xf4T7\xfaG\x132M(\xe1-\x8a\xbf\xfa\xf1|\x02\x87\xf2G0\x1c\xe1\x80\x0e\\\x839T\x7f\xf5\x8f/\xe2\xb33\x92\x7f|\xfedI'));&\xe6'\xffs\x15\xb0YRD\xd5\xf4\xd5\xd4s\xc2\x969\xd5\xc0\xa2\x1e\xf0\xeb<\xce\x81\xc1\x00\xfe\xbcz\xf0?\xe5M\xf5*\xd0 \xd7_\xe6W2\x85\x80\x0d\xf3Q\xa8\xda\xe5?\x14t\x1e\xd4^\xe5mg|t\xc3|\xc4\xbb\xa8=\xc4\xb6\x0e \x8fZw\xd3\x03\xd8\xdak\xdf\x96]\x1c\xc0\x9fW\xb5gW\xf5N\xe5\xa8\x08\x1f\xd58N\xd3 S\x83\x8b \x8b@\xfbEC\xfe3\x85\x01l\xedj\x0f\xca\xd6\xaand\x9b\xb4?\x87\x01\x90\x08h\x7f\xcc\xa7\xc5\xff\x98\xc0\xa0\x8ep\x11\xb4@F\xfb\x99\xc4\xc5\xf5\x1a\xde\xe2\xd2\xf7\x05J\xbc\xcb\xb3\x05\xc9\xd9J~\xd9\x86\xd08\xa3\xd3\xe4l\x99\xc7\xa7)\xb1\x80\x85.\xe7D=\xdfm??#\xec\x00\xf2:\xc4\xc2j\x8e|\x0e\xb46\x87\xe6\xe8\x15\x86 Z\x93\xfe\xc9 )^\xab\xbd\xd1\xc25\xfdR+\xc1\xe7\x1a/SV\x1f\x03\x1c\xf8}\xed\xb1\xd6\xb4? X\x04\xbd\xb8\xc7\x81\x1c\x01\xabO/k.Q\xb3;\xd9\x8c\\\x99E\x9e\xb1\x8c\xef\xca\xfe,.\xde^P\xb5F\x02\x9b\xf0\xfbz\xfb\x0b\x18@\xef\xf6$)X/\x02\x1a\xd0>'\x12w\xef\xde\x13\xaf]\x05\xc3\x06~P\xbd\xff\xde\xb2 P\xb0<\x19\xb3^59\x9d\xdc\xd0\xe0\x1b\xd5T\xd4D\xb5ZS\xf5\x8f\xbe\xbdw'\x0c\xbc\xbe3\x0f\x81\xe9+-\xb6\x08S+\xd9\x05PN#\xb6\x02\x02 -XL\xc7\x9c\xbe\xb10\x046\xcb\xb3\x0b\xa0\xe4\x02>\xac\x16\xe4(\xcf\xb3<\xe8=\x8d)\xcd\x18p\xe0B\x0c\xe34.\n\x88\x0b\x88\xcb\x1ezacG\xde\xcct\xaaG\x1c\xc1\xf3\x08)\x15\x0d\xf6\xef\xef\x87\xf5M\x94\xc0\x00\x82\x1c\x06\x90\x85|\x07\xe4\xf5\x1d\x90\xc3\x81\x01y%\x9cZ\x1bO\x1f\x8f\x01\x96M8\x96t\x98\x18\xc1\x8c\xafd9\x04|\x06|\x13\xef>\x00\n\x0f\x81\xf5SB\xcf\xd8\xec\x01\xd0\xedm\xd3G\xa0f\x8d\xc4\x99\x8e\x1e\x18\xdf\xc8\xfb\x15m\x81A\xfd\xe7z\xcd\x89\x11\xe4}\x9d@I4\xe9\x9d\xc7\xe9\x92\xf4 \xa1\x90s\x88\x05y\xff\"OX\xf9F\x18A\xb0\x1bA\xa2 \x10\xf2\xc9\xe5\xfdOd\xc5igk(\x0djo\xda\xb9%\x009.\x18\x08\xb0\xf6*E*\x16h\xdb\\\x1c\x04\xb9\xbc\xcf\xbf\xd6)H\xbd\xcf+\xbf\x1d\xa5\xef\xc4\xfaHJ\xc4\xa0\xc17\xf7\xef70\xadB,N\xca\xff\x9dX\x7f\xf7\xde\x7f\x0e\xe9\xad\x04\x84\xe8\x14\xe3=\x99\x92\x9c\xd0\xb1\"\x1b\x9c\xd7\x81Y\\\xd0\xbf18%\x84BB\x13\x96\xc4iR\x90 \xec@\xb1\\\x90<\x08kop\x12C&\xbd\xd0x\x86l1\x8e\xd3%c\xb65\x18@p\x9e%\x13\xd8\x85\x01\xe7\xd2\xe0\x10zK*N\xedI\x0f\x0e\x9a(\xcc\xe9\x1bg$+\xaep\xab\xe4\xed\xf8\xc7\x04\x0e\xf4s\xe9\xaf[R\x18@\x1cp\xec\xfa6l\xaci&\x1f\xdd\xb9\xfb]\xf3Q\"\x1f\xdd\xbd\x17\x86&>0n\xb3\x05\xea|6p\x05\xc4\x8d\x1e\xc4\xb6\xb9\xae\x87'\x16\x90\xdf\xba\x05t\x99\xa6\xb8\x92\xccr\xf6\x1cs,\xe1\x8ceN\x8a\x82\xcfs\xbe,\x18\x90\x84\xcdH\x0e\xa7D4\x90\xe5\xdaa\x14\x01?\xacz\xb0\xbd1v4\xd0\x8eT\x04\x88o5d@\xab\xd7\xf9\xe8k$\xca\xc8\x19\x16,_\x8eY\x96\x9b\xa0\x0d\x88\x0f\xe9\x92\x1c\x00i3\x85\xd0d\x1c\x0d\x8c%\xbf\x14\xdd6\xb3\x96\xd0fPw[/5\xc87'\xae\xf2PPk|\x88\xd3\xcfk\xc7\x01\x13\x92\xce\xc9 \xc2\xe0\xe4\x84\x1fT\x1b\xf2\x01\xb8\x1b*\xa0\xe7\xae\x83\xd6\xbc\xd5T+|\x85\x1e\xe7y\xbc\xd2x\xc3\"M\xc6D\xdb*\xa0o\x17f=\xae\xc5\xdc\xeb\x8b/\xf9\xceqNbV;\x99\xc20\xd2\xf1\xa4\xaf-9\xe7\xc7\x1b\xdb\xc8<\x14\x03C\x0f\xd5\xee\xc5}-6\xec\x8b\x80\x84^-\xe6\xce\x16\x97U\x8b\xbf\xfa\xb6\x989[,\xaa\x16_\xfa\xb6\x98t\xcf\xfa\xd6-\xd8J\xab\xa6\x7f\xf0m\xda@\n\xb5\xa6\xb7\x82-\xc1\x1c\x91\xe1t\xe4\xd7\xe0\xd2\xb7\xc1\x85g\x83\x85o\x83\x13\xcf\x06\xd3\xee\x15_\xaf\xb1[\xaf\xe6\xc6\xbe\xe3\x9b\xb5\xc6\xa7\xffbA.X7\x16d\xea\x8fD\xfcA\xfbI\xf1\x9c\x95\x9ck,\xee\xbc$+\xc2\xc5\xf5\xa5|\x81N\xc8%\xde(\xc4\x8d\xc7E\x91\x8d\x93\x98%\xe7\xfc\xa3T\xdc|\x9bOH\x8eo\x8d\xf9\x0d\xd5\x06\xef\xba_\xb5\xc0\x07\xd0?&\xfc\xbcJ\xda\xf4c\xca\x05\xc4\xbf\xff\xfd\xe4\xe4\xf9\xeb\xd7\x1f?<~\xf2\xea\xe8\xe4\xf9\x87\xa3\xf7\xf8\xc7\xc9\xdf\xff\xdekS\xd6E\xfb\x8b\x97G\xbf\x1e=\xb3\xbc>1t\xf0\xe6\xd9\xd1/\xd6\x0ff\xed\x0f\xde\xbe\x7fv\xf4\xde\xfa\xc19\x0c\xe0^\xfb\xf6\x1c\x06\xb0\x07\x0f\x1f\xc2\xb9A\xf1\x00\x03\x98\xc3\x0e\x18\x8e\x96\x15*\x9c\xda\xf7O\x8dZ\"\xa8\x8e\xb2\xad\xbd\xd6SC3'\xd7i\xc6F\xcb/\x9c\xd8J\xfa\xd8$g\xc4\xf6\"O\x92|dn\x91\xc8\xa3\xa1lp\xd7o;]\xf2\xd3\xcc\xf6\xf0\xd8q\x12q\xbee\xbd\x86\xdd\xb6\xf4W\x13*_\xc7l\xd6\x9f\xc7\x97\xfc\x90&R\xb2\x84\x1dT\xb4\xf0c\x88\xb3Tx8\x06\xa8O\x13Rh\x06\x0f\x81>\x80\x8c\x8b\x9f\xf90\x1b\xf1\xe3j\x98\xc160\x83\xac)A\x99{\xcd\xf6\xa9s94\x9e\x8c\xf4\x8b\xe4\x0f\x05S\xfcs\x80\x0cE\xc2\xe9\x02#\xc1cq\xba\xf2'^\x1d\x7f\xb2B\x12\x99P\xba\x9c\x9f\x92\xbc\xc6\x82\xba$o\x8a\xd0\x7f\xf4\xe8\x91 \xfc\xa0\x1a\xe5|&\x15\x1c,_\xa9\xbb\xfb\xdf\xdd\xfd\xee\xfe7\xfb\xdf\xdd\xc3\x19\xd2R\x05\xfb&~cn\x85/2m\xe3\xba\x0d|\x0c\x1e\xc2.\x1c\n o\x03\xab\xc9,\xe0\x00\xcec\x97\n\xaf\xc1\x14\xda\xdaxkb\xe2\x1aM\x05rm94\xe4Zs\xe8\x08\xa1\x1e\x1e\x0e`\x87\xe2\xc9^g\xce\x0d/3x\xc4\x01\xe85\xb0w\xd6\x95\x97\xa3z-G\xee\xb9a?\xf8\xb6\xc7\xfc\xda{\xed\x018}c\xc0!P\xce]\xcb\xc5\xd6\xf77\x83m \x9c\xf5n\x087\x9cC\x12\xef%\xa8di\x9d\xf4\xfa/\x8e\xdf\xcf9\x1dhS\xe6\xdf\xf9y\xd1\xbe\xfd\x06\x06\xb0\xdf\xbe\xfd\x9e\x9fR\x95tW\x19K\x8eW\xf3\xd3,\xe5\xeb(\xfe\xea\x8bM\x9d\x19\x8c \xcf\xc4I\xa7^0\x1cm\xaf`\x00\xef9\x8e<\xb3\x1d\x01\x1f\xcd4\x87\xcd\x92\xa2O\xc9%\xf3f\xc6?\xab\x95\xb2\xe8\xa8\x94\xc1\xa4Z(\xbe\x05\xf7j\xcb6\xe4\xdf;\xa8(\x1cB^\x9e!\x19\x1c \x91v\x9e\x86\x99Y\xb2\x9bd\xd4v\xe2z\xd2\xea\xef]T\xc19$\x81~\xcequJ\x9a\x96A\xfd\xe1\xe6>\xb7~\xf4ec\x9f\xb8\x19\x83\x866H\xb3\xf4!\xcexu\xf1\x93\xb9\x0be\x91\xe1C\xb5\"\x82\xd4!\x08\xa3\x85\xdf\x8c~tw'\x0e\xd3\xf7Hk\x87\xefG|\xcb\x90\xe1\xb3\x91a\x08\x0d\xb5\xcc@?\x13\xd5\xf0\xbcF\xf4\xb3\x07\x8c\xd5\xc9\xabCXp)^]\xbcpv\x81\x1a\xa0\xe6\x91\xa3\xb6cB\xd0 \xab\x84\xe8>\xcb\x8e\xc9g\xbc\xa5Z7\xb7\x0d\x1aP\x0b\"\xc5'\x93M\x18\x95X\xe4\x02\x181\xae4(M\xa9M\xbfut\xb9 cF&\x82A\x83,\x87DIE\xa27\xc8\xa6b\xcb\x15\x11\x7f\xfa \xa5\x1b\xf1\xe8\x00\xb5\\\xb6n\x8d\xab\xc8\xaf+_d\xfb\xf5\xcb\xe0\xdeg\x19\xcab\n\xe2r\x11\x96\xed\xb5 \xfdi\x9e\xcd\x8f(\xcbW\xe5\xcb\xc4w\x94/\xbfl\x94\x86\x81\x11} |\x9cR\x8aT\xb7\x96\xdec\xfb\xc19\xb6\xe0\xcb\x07\xa7F\x13\"4\x19\xdeo\x8cL\xff\xf5QSU\xb1\xec\x98\xe5 =s)\xdd\xb4\xc1\xf6\x86\xcf\xe5\x01=\xea\xd5{\x88\xe0c\xff\xe5\xd1\xaf\xc70\x80\xe7\xfc\xef\x9f\x1e\xbf\xfax\xc4\x7f\xfd\xce\x7f\x1d\xbd\xf9\xf0\xfe9\xfe|\x13\xd5\xfaOh\xc1Q\x1f\x06\xcdQe\xcb|Le\xf2\xd9\xb3M\xd3\xd8^\\\x7fQ\x11|''%\x00{|$\x7f\xf6\"\xe8]\xf5\x9cc\x1e\xc7\xe3\x19yO\x8a\x0e\xeb\xa8\xd6\xd5\x96\xe8\x0b?\xc4sOt-e\xbd\x8f\x14\x1fL\xf0\xfc\xd2\xdf\x1c\x88\x17+\xac\xef\xb3L\xc8\xb2a$\x1eI\xc1Q\xfbH\x9e-\xf2\x05\xd74\xca\xfe\xbb\xac\x18\xdaDR\"\xbdx\x04\xa3\xd8\xd2\x01\x98{\xc8\xf2\x0d\xba\x18wv\xc1\x82_#x\x11F\xf0km\xf1\x15\xbd\xf5\\\x133\xa6\xbf\x14-\xbf\xf4\xc7\xf4\x97\x0eL\x7fY\x1b`EI=\x9b6\x0d\xf1\xe5\x0d#\xfc\x90#\xfc\xa8\x8d\xf0/o\x18S\xf6\xbcz\xf8\"Liw\xc1\x82\x1f\xc4z\xfe\xe0\xbf\x9e?8\xd6\xf3\x87\x06\xe5b_\xb6\x96/\xfaI!Z\xc8\x08\xff\xa5\xb4\xb7\x1c\xbd\xa5\xba\x96\x8f_S\xe4\xbelko\xbf\x8a\xe0\x9f\x11\xfc\x12\xc1?\xdaJ\xd3\xe3\xa3\x7f\xa0\xc2\xd4&9\x12\xe2\x10\x1dOb\xe4\xca\xd0\xa3L'6\x1b\xb1\xaf\xcc\xd2\x83\xe2/\xa5q\xe9\x13Y\x15F\x1eR\x8cDr\x83\xd5PN\xf8\x07\xc2\xc7\xadF\x077\x19\x1auN>\xa9\xf4\xf3\x96\xf9\xa3\x80\xe1\xaf\xa0\xcb\xbb\xbb\x93\x86\xb3\xa8q\xef\xa9<\x0c\x86#\xaf\x8e2KG\xea,\xaa\x0c\x18\xff\xf04\xb0 7fm\xf0+\xdeZ\xf0\x95\xd4\xb5\x12\x12\x0cG\xa1_\xbbq\x07r\x08\xa3fR\x883\x0fy@\xd9\x05 \xdb\\\xf3\x93\xea\x8d\xdc\xfc\xc6\x1f\xd5\x1b\xd4\xfc\x86Q\xca9\xac\x84\x9cR\xf5d\x16*\xbfL\xd2\x19~\x8a\xe0|\x04\xfc\xb8O6\x92x6\x92Y\x97\x1d@/\xcc\xc2\xdc\x97OO\x08r74\x8b\xc2\x8d\xe4?7\xb0\xc5\x80\x1e\x06|(W\xd7k\x08)\xf1T\x97\x11\xc9\x9a\x99\x81\x9a\xd9D\xf0\xd2\xca\x91\xf0\x03\xa2\xb2l\xecE\x10\x0b3F\x0c\x0f\x07\x90<\x80\xd8\xeeF\x07r\x1cK\xde\xc6\x90r\xd1\nv \xe6\xb2\x95\xc5\xad\x0e\xd4b\x0b\xbd\x1e\x0b\x96\xc3\xbdQ\x84\x8a\xbb\xe5pw\xc4\xbf\x8c\x80\x84\xa5\xa6$\x86mh+\xe1\xa0%~\xa9K}\xd6zhU\xfb\x936\xab\x8c\x9et~Df\xfc\x17/\x93q\x85\xac\x90\x15+\xe7\x02\x0c\xc7\xc6\x8f\x81\x93\xa5P\x97r\xfe\xf0_X\x05\xfc\xedmx\x04 \x1c:\x1a\x07?u\xa7\xba\xacjOu]\xc1\x01|F\x07F.\xcaKL\x12\xe8L\x86{\x8d\x93\xa8\xfc\xa8}\xdb\x03M\xb2\xfc\x1ax2\xb5;\xb1*\xca\xa4y\x94\x0b_L\x8eR\x11XQ\x83\xe3M\xfd\x0c\xa3\xd5\xbe\x91\xba\xcf\x0c\x9bx\x19\xd0\xb0?\x8f\x17\xd5\xba\xbb\xda\x05m\xd2\x08Q\x0c\x1d\xa06\x10:Ts\x13b\x1d\xd2\xaf\xff\x81!\xa9-\xd0^t\xb4\xeaD\xd0\xeb\x99|\xcd\xf8\xd5\xeb5=\xf7\xf0;N\xd3\x17\xde*\xab\x85\xfbT1\xf0#/9\x1b\xc1\xa1\xb4 \\:\x7f\x95\x14\"\nfB\xc4\xf3_\xeb\xcf_\xc7\x0b\xa1\xbb\xf2\x1a\xce\xc4=\x1ce=\xae\xf9]\x0d\x14O\xdd\xd4\xaa\xe9\xaf\xf9Acf\xdf\x11\x1cwHe\xbe$\xb0%\xf5\xef\x0c-\xcc%Fm\xd9\x18%\xc1\x82j/\xeem\xa0\xa6\x97N\x08o\xa7V#\x06So\xb8\xb6f \xb8y\xf9f\x10\x868\xa1\x00=\x0f\xf4\xbb\x9bN\x10\xec\x93\xf4\xa7f[f\xc7Q\xd2'\x9f\x97qZ\xa0J\xde\xf4\x02\xd3^\xd8Ro\x07\xcc\x93#?\xf7Z\xf2\xee\xe5\x8d\x03\x11M\xa4\xd9\xb5+\x87\x07\xed&+o\xca\xc7\xda\xcd\xe6\xe7''\xb3\xb8\x98\xb5\x1a\xa8n\x97\xaf\xd4\x1e\xac\xd7B\x7f\xcco.\xe5\xb0\nu\xa3\x907\xc6\xea\xc6\x18=\xa5;\x90\xb2\xe9\xc1!\x0d\xd1\xf8\xdb \x1b\xe5Z\x81\x9e}\xe6\xb6\xf9H\\\xac\x06J\x88})#\x04\x1d\xe6\x8f>9'\xf9*\xe8T\xa8\xa8K\xb1B9\xda\x00\x83P\xec\x82Nv\"\xe3@\x98\x91 CNQ8/\x06\x94\xc3\x15o\xeeb\\\xa1\xed(\x00\xf4\xdf\x97\xfdq.\xc2c\x8f\xa8q\xda\x16\xa8\xe5gc\xee\xbc\xf1\xaaZ@\x0b\xcd\xd1\xd5\xbe\x88m\xda\x0d\xdbB\x90\xb4 \x0exg\x0d\x0f\xf9\xe6\xa5xK\xc7\x12\x10\xa9\x05\x81\x01$f\x08\x1b\xa17\x15\xc10\xc6/\x16 \xb6\x8frE*\xd1\xc7\x14<\xa8_\x1c\x9e\x9c\x13\xdd\xc2\xd8\xb4\x00\x9d\xa43\xfe{\x86<\x01\xe9\x9f\x11\xf4\x8a\\\x85\xfc \xbf\xab\xddB\x1cQ\x185\x95\x1ek\x06\x8a \x885V\xf1q\xaa\x11\x13\xbe\xa8\x0b/\xba7w\xd3\xbd-T4\xea\xf1bsM\x02\xe2\x1c\xbbj\xc0\x8c\x8fB\x9f\xa3\xbc\x1e\x1a\xfa\xa4\x86/\xcb\x1e\xdc\x86\xdd\xd2\x9fE\xfa\xbd\x84\x91zC}\xe8:\xd8\xfeY\x0e\xed\x9ff\xc4\xf9\xa7\xb4\x19tl5\x1b\xb4\xce:\xa0U\x8b\x8c\x11*\x02O_\xa1\x15q9\x0b\x99\x97b\xd5X\n\xad\x0d\xf3j\x9c\x91@\xbaZE\xa0\xe2\xfb\nF\x16\x10\xc3\xfb\x98\x9e\x118]\xc1n/\x8cpo\xe19\xb4\x1b\xd5W \x0d5\xe8[z\x1bv\xc3\x08i\xba\xf6\x02\xc5e\x94K\x18\x9f\x16\xe8z\xc8\xe0\xa1\xe4\xd8\xf8\xdb;T\x99pN\n\x16\xe75\xdd&\xa1\x13M\xb5y\x82C\xc3\xc1\xeaX\xa3\xa3\x07\xfe=&I\x1a\x04\x0cv8\x01\xbe\x0d\x94\x8bV!\x97\xcd7\xc3\x9d_JX\xfeb\xc6\x9d_\xbe\x0cwN\xcd\xbaD\x81/\x9aJ\xe9\xf1i\xc1\xf2x\xcc\x9a\x96 K\xb3'\xc4\xe5fz\xe1|z$\x9f\xea\x0f53\xd6\xf0\x1f#\x15`\x1a\x10\x12\xc1K\x8e\x19z\xdc\xc3\x19\xe9\x0c\x04\x82\x86\x15\x86\x93G\x94\x0f4M\xfb\xf0\x932g\x84\xa3\xb6gc\xa3\xcf\x8dL25\x7fY\xadG\xe9![S-U\x1e\xb2\x03\xc8\x85\x8b\xac\x15W\xa4\x8a\x88\x04t\xc80\xecn\x07=\xba\xb2\x11\n\x7f\xbc\xa3jgf\x1c\x15\xadT;\xf3\x9a\xac\x9fu\xc84Q\xe3\x14Z\x937\xbe\x95\x9956\x9bikJ \xaa7\xbd\\M\xa8/\xf4\xc3CbD\xf9Z\xdf\xb3\xb8p&\x02\x80\xa6\xa5S4\xdd\x08\x93o\xa9\x02\x1a\xbd|\xe9\xc6\x12\x9d\x8a\x9dU\x99\xaa\"\xc9V\xeb;-\x11;-\xe1;-{\x00\x89;\x16:\xe6\xdf\xe3bf\xb0\x03 \x1c@b\xd1\xf35vf<\x8a n\xee\xc6\xc4\xa8\xb4\xb5\n\xa3\x89\x17\xc8\xae\xb3=%\xb8\xac\xfbS\x03\xa1uw\xe6\x9d{8\xb9\x89=\xbc\xd9*(\xc8\xa1\xa65\xfb\xf7\xed\xf9\x98\xef\xf9\xd8o\x8fk\x8b8\x9cU\x87\x1c\x95\x87\x1c5\xee\x8b\xd2[\xc5c\xad\x91\xf7\x0dk\xbb\xb2&4iB\x86\x85{V\xd8\xf2SP7\xcb\x86v\x94\xb1\xe8$\x9e\x04\xd4\"\x83\x96\xbb8{\x00[\x01F\x9cKyT\x08\xa4\x18\x8b\xb7'\xb4\x10A&d\xe2\x08\xf2\xedm\xb9\xab\x1e\xd8\xa5\x91\xbc s#L+}\xf5\x8d\x025\xcb7\x86\xaaE\x9d\xf3D\xd7\x12\x8b\xed\xf2\xbd\xa5Y\xcb\nl\xbe\xd5\x98\xb6\x0e\x1dZ\x0e\\$\xe1\x8c\x8e{@,\x8dX(\xaf\x8d\x10\xe4\x12\xe5\xf3\xff\x02\x94\xaf\x0e\x15\xfd\x14)C\x08D\xca\xa2\xb6\x83\x80~\xa0\x94\xc6\xa8\x07\x1e\xcc[6LF\x11'T\xadC\xc226\xbeK\xa8\xa6%\x12\xbb\xe4A\x17\xdd\xa4.m\x12\x9a\xd8\x86\xc9H\x84C\x96c\x8b\xeb\x03;\xcdI\xfc\xa9\xbd\xa06lk\x1d[\xc6\xe5\xfd\x8f\xed\xbe\xc6\xc2Z \x9ai\xb1\x8d/\xdf\x08\xab\x8a+\x01\x8f\xaac\xb5Ka\xd8\xbdQA\xc1\x0d\x11\xa5\x02\x9eC\xb1(\x82\xf2\xe4\x1e6\xbe\xe6\xb4.+\xf67\x1f\xfa3\xbcsI\x03\xe6\xe4\xfa.v\x0dA\x1b\x0e\xa1\xf7\x9e,H\xcc`8\xea\xc1A\xf5\x0b\xbd \x98\xa6\x16\xda\x86^u\x0f\xbf\xe5wX2'\x05\xb4\x9d\x8e\xe7\xd7g\xcaML\xb8\x18\x82\x81\x01\xaf\xf5\x93\xd0q\xba\x9c\x10o.|Ft\xc5W;*\xab\xd1<\xa6,\xf0\x99Hm\xffpPYQ^\x8b\xd9\x13S\x85\x03\xa5\xad\xab\x8d\xec\x83\xb0\x13\xc3\x8e\x08\xa6k2\n\xcd\x91\xe6\xe4\x9c\xe4\xc5&n\xda\x1dp\x9d\x90\xcb\xb7\xd3\xeb\x83\x15\x0eQc\xb8\xb3\xe7\xec&\x8d\x0b\xf6\xfc\x06\xba\xaa0\xb4\xb3\xcb\xeb\x0bS*UT\xb9\xc4\x98+\xcaJ\xb0\xca\x03\xa36\\\xda<\xd1\xa8S A\xbd\xe6\xb2\xb9\x94\xb3\x11\xab\xba\x19\xb1Vl&<\x04\xaa(N\xc5\x02Q \x89\xd0\x98\xf0F]7\"~xP\xd8\x1a4\xa5\x91\xd2\x13\x0fI]\xf5\x0e\x87m\xcc\xd4\xa6z\xde\xb6\xf7s\xfa\xbe\x92\xf4}u\xc3\xf4\x1dU\xc6\x8a\xbc\x8b\x1f\x1au\x17\xda\xddm\xe8\xf5\xfb\xfd\xea.\xa1\x13\xd8\x86@\x08\x15\xeaE\xb2\xe0\xed\xc1\xe9\xaa\xf69Y\xf0\x86{!\x9e\x07\xed\x93`u\xb3'\x81\x1an\xa5\x8b\x84\xaf\xebCi\x9d\x11\xabk\x9d\x11\x8as\x08\x08\xec\xe8}\x87p[\xeb\xcf\xba?0@zW\x18\xe452!n\xf05B\x9d\xf84\xcd\x0c\xb6\x87\xc6\x90\xbd\xcf\x9d\xc6\xa1Rv\xaa\x1d.\xe8R \x02\xb2\xcb\xa7\x91\xb0\x15\xe0\x19S\xdd\x0d\xe1\xe1\xa0\xf4-]\x91`7\x82\xddP\x1eO+\x89\xdcg\x84\x05\xbaU@\x99\x0c\xf8}f\xb8\x8f k\x9f]\xab\xeb\x1c6\xe7eTemy,\xf6-\xf8\xbf:\x92\x0c\x06|.vi@d\x17p\xaf3\x94\xf6D\xb5\xd0\xb5\xf3 4\x13mp\x89\x03\xed\xc3j\xf5\x85\xe7#\x0eGB\xd4@sV7s\x16V\xd8\x8dz\xc3J$\xe0\x90\x93\xf2`k\x03S\xf8\x1a\xf3\xe0iw\xeb*G\xeaT9\xd6%\xc4\x08\x12\xa3\x06\xd1\xbcl\x19l\x8b\x11\xed\xf0\x01\xe4\xfe\x0b\xd4\x92\xd7\x8c\x00\xdc\xfc\x00\xae\x80g\x1co\x03\xa0\x969\xf9\x02\xd9\x0c\xce\x9b8\xec\x95 \x9d9\xd5!\x0d\xe8\xf3E\x7f\x84\x16\xc9\xbf\x98\x03P\xca\x17\x94\xd7c\x1f\x91kuC\x0c\xc1\x8a4\x16F\xf8}\xc8\x1fe\xb8\x1d\x9aU\xc5\x13\xfegy_\x92,\xf9 \x9eq\xe7ed\x91\x81\x8f8%*\x9d\xd3 \x89\xe0\x94\xe0\x9f\x17\xd5\x9fG\xea\xcfSRF\xf4\x887\xb5@\x1e\xf1\xbe\x0c\xf29jH0|\xa1/\x89-\xbb\x04\x9el\xc9|\x89 &v\xf6\xab\xd3\x8e\xdf\x0b\xaa$,\x11\xec\x87*\x7f\x06\xbe~\xe0\xbfk\xee\xdf\xbbw\xe7\x1e\xdc\xe2\xe7\xd9\x9a\x13s\xfb\xc6)\xdfd\xe2M;\x92\xe3^\xd9F\xb7\xbbG\x8f\x1e\xc1\xde\xfdP\xde\xe1O\x02V\xde|\xf8\x10\xf6\xee\x8b\xdc3!\xac\x9b\xce\xf8\xb6P\xa6\xe3._Il\x1en\xc1\xde\xee7w\xbe\xb9\xbb\xf7\xed\xfe]X\xc3\x9d\xfd\xfd\xbd\xfd\xfd{w\xbf\xe1O\xfc\x9c2\x9fZ:\xd2)&\xac\xd7\x8e\xe0\xeb\x92\x86Z4\xd5\xdd>\x8f\xaa\xa3\xb6\x07\xa3\xbb\xe3\xae\x9e\xb7\x9a#4Px\xc5\x18\xa8qY\xe6P\xa5=\x18\xd8}\xce\x12\xf4)\xdc\x92C\x15\x0e;\xc2\xa7\xc21P\xd0\xf0t\x17\xd66\xe7(q\xec\x8d\xe0\xbd\x80\xf5\x1b\x993\x83`:\x1cxF0\xf1\x19>\xe7T\x1c\x1b\xe7K}\x9d,\x0bp :\xdb\x08\xc7gq1{\x9aM\x88\x06\x19u\xcb\xa4\\\xc4\x96\xaa\x90-\x1d\xa4\x9e \xb43\x9e\x1f\x9a\xbe\xaa\x08\xbfw\xc2c\x8d\x84a\x97\x1a3\xa9\x9c\x0b\xcb\xaf\xc9\xf09\x19y}\xb9\xf5\xd6:n\xb05\xceOS\xb4q?/\x8e\xaaT\xd8\xe8\x0egz\xe25\x16[g\xdd\xe0\xd5\xbf\x96\xa3\xa0\xd9\x84|X-\xf8\x96\xdb\x0d\xa1\xb8H\xd8x\x06Au\xbf\xab)~\x8d\xe3\x82\xc0\xdeA\xe7{\xa0\xd1\xfe\xfe\x92&\x9f\x97\xe4\xf93\xfb\x1c\xd5\x85\xcd\x7f\xb7a\xf3\x93l\x8c\x01\xc3G)\xe1\xff\x88\xc96n\x96cp6mVj\x83\xdcR\xdaj\x19\xdf3\x7f\xcd\x97k{\xfb5\x89\xf4\xa3\xef\x16\xbc\x16{\xff5\xee}G\x88\xc8\x07\x12r\xac/\xa4,z=G\xd7\x06\n=V6\xd5\x01\xfe@\x97\xe7\xa6\xc7`\xefMFw\xc8%#\xb4H\xaa@\xc2\x02\xe2\x9c`\x92\xe38M\xb3\x0b2\x81\xb8\x80OdU\xf4\x9b\x89\xb3\x9b\xdd\xf3\x0de-n\xf1\xdc\x98\xc3X\xbf|\xd2\x11\xab\xab\xbb*\x86~iI\x8c;\xde\x94|\xbay\xf1\x01\xcc~\xb1\xea\xc2\x15j\xac\xc3\xa6$C\xb2\xc9Z$\x89\xc6\xc1\x9b>\x08\xad\x0d\xb9\xd5m\xfa\xa5\xcb\xda\xfe=\xf7\xe3\xc5\"]I6\xde\x12\xd1\xaf_W\x91\x83L\xf23\xb0\x03\xb2\xddD\xb0\xe6\x94^\x91\xbc\x16\xde\x7f\xa4\x08!\x96AA\x18\xc4@\xf9>\xa8 \xa7\xc6\x08\x19\x95{\xc2\x89\xfa\xfc*\xe7`\x9f\xfd\x06\xf4\xc4y\xeaot\xda+\xe5kI\xd68\xc3\xa0e\xb41\xe6\x03h@\xeb'4]\xf1&\x85\xd6\x14\xd5\xa4c\xe1\xd4{J\x80s\x0fd\xd2\xf7\xf4\"\xfdd\xe1\xedKu\x0c\x13\x8c\x92f\xa1 \xf5b\x16\xfc\x85;{\xf0\xb5HU\xd8\x1f\xcf\xe2\x9c3/\x8fY@Q\x98\xb1\x8aG\xc7\xa4\xed#\xad\xff\xe2\xbd?&U\xc6\x84\xa48*ic\x9bj\xbc\xf5\xdaa,_9\xf0V\xa9;\x8d4\xf3\xcf\xab\x08z\x7f\xefE\x82]\xb4\xea\x04\xc6\xb18\xe2]{\\\xf6cs\xf57\xa0Y\xd8\x16\x97\xdf\x91\x08>XE\xe6\x9fI\xfc\xe9u\xdc\xd02\n\x06/xGd\xe6\x02\xf9\x92\xa1qqF\xb6\xa1\xfc\x1c;<9I\xe6\xf3%\x92p\x8em''\x8d\x14\xed\x1d)\"\x03lE\xfc\x0e\x9e\x93&\xd2\xf3\xfe\x7f\xe7o\xec\xdd7$\xa6\xe4\x0f\xf6\xef\x192\x1f\xbf\xb7\x0cY\xb2\xf86)\xfa\x95e\x03\x9c\x91@\xc4f\xa1tV\xb9\xcd/H>\xcd\xf2\xb9P\x7f\xc7\xa2\x8d\x8b\x84\xcd \xa6\x90\xd0iB\x13F\xa0H\xfe \xbe;\xf0\xa3[\x8cw&\x0d\xfbE$\x0d\xfb\x8cMp\xfeb\x1c\x94\xf9\xd3\xf9\xb3>\x1f\xd9\xeb%\x8byO\x85\x16\xd6\xd2\xa5\xab\xce\xad\xe9\xed^\x91\x80*-?\xedO\xb3\xfc(\x1e\xcfj\xf1V\xc6@\x06u)R\x8a\xdc\x15m\xa9\x9b\xd4e\x8a\x82\xf6\x03\xe7g\xef\\ \x7f\x90\x8el\xe6\x1fI\x04'|\x9e\x1f\x89G2\x9d\xd2| B\x8a\xcb\x038r\xa9\x88\\\x8bd%!\x1d\x15\x86`{\x00\xfb]\xa2\x14\xda\x85\xe1Q\x95@\xc6p,\xbfN\x8a\"\xa1g\x82 \xc3^?\x91\x95\xc8f\xc1\x86\xd4\x94fR]\x82y\xe6/E\xfcU\xde\x97-\xdc\xbds\x9d\x11\xfc\xd76_\n\x85\xa7\x96\x01\xeau\xbc\xb0\xa6<\xfb\xf8\x85\x96\xc5\x93<\xcb*\x959\xff\x81\xa2s\x19K#\xf26\x85&\x93b\xad\xebb\xa3\xae\xff\xa1'\x85r\xcf\xa9 \xec9\xdd\xa0i\x9c\xc8r1\x89\x19y\x8e/\xaf\x0c\xd5\x0cm\xdfn\xba\xb29\x99g\xe7\xa4S\xd26\xccz\xe5nxBR\xc2'\xe0\xdbtk\xd6\xbeS^m:e\xd1IsA\xdc\x89\xa3\x85\x08Y\x92\x17\xa5G;\x94\xae \xa12\xce\x94\x13\x18\x92\x91l\xd4c,m\xf4\xb0\x8c\x06\x83]\xd1)R\xc6b\n\x14w\xf8\xc8\x96$\xda'\x91\xc4\xb9\x8c\x03\x15\xa6\x8d\x95]'\x1aw\xfa\xe2qr\x17K?<;Q<\x97)c\x12YM\xcbb\xd6RW\x01\x03\xc8\x82\xa5\x83\x06\xca\xe5*p\x02K\xe9\xac\xdb\x8e!\x03\xab\xd4qF\x82\x04cH\xd0p\xc3\xf7n\x04\xbd\x84\x9e\xc7i2\xe1\x94\xf8]\xccf69\x88\xcf&\x85\x01\xc4.\x0fT\xfe\xd2XNy\xc5\xa7\x8c\xd4*\xe5\xfb\xc9\xfe\x01?\x07I0\xae\x16\xd0\xa9(\x9d\xe2\xec\xc7r\xf6\xe2\xd7\x8a\xff\x92\xbb=H9\xbe\x06I\xc5\xcb\xb0\x10\xcf\x8e4\x82\xa9\x81\x07\x90{\x9eR\xd4\xe9Z\"\x1ee\xdfy\xd9\x9b\xe4\x9aZu\xd0\x1a;`\x9c\x92\xd8Y\x94Hk\xbc\xed\x16\xc3\x84?\x84Ym\xc0:\xea\x8d\xb3\xee\xf6k2P\xe7\x04J\x8b,_\xa9\xb8x-t\x11&\x06@\x8e\x86 b\xb1\xfeE\\<\x16\xf44@\x1f\xb6\xfe\xc9 \xa1\xc52'o9\xbd\x0e\xea\xc4[\xb1R\xce\x81\x97\xbd{\xee\xc1\xd6\xf9P?7\xf4\xd1pQ\xec\xd2\x0d\xb6\xb8x\xae41\x9b\xf5\xaf\xf7\xd3\xb12%\xc86\xebA\x9e[\xce\xb67spR\x1a\x11r\x01/\xfde\x9e\x8d\xbc\xd0\xbe\xd4\x89Y;\xdcKo\x1b\x94\x03\xdb\x99E:\x88\x08\xba3\x93\x80a\x82\x19\x86\x19eL6\xf7H\x94}\xea\x80\x80\xb6\xda\x9d{K\xed\x98\x8a\xc11`+?\xd2\xfeI*\xd6Fgk\xa2*\xaf\x03\xb24\xc8\xe15\x1a\xd2r?\xe8\x0c\xce\x9edp\x0c\xd3I\n.\xb9\x0f\xe0\xb3\xc1s\xe8{\x12\x01\xb2W\x8dd\xc0\xaf\x1f\xbf\xb3TO{\xc2\xdf\xd6\x81dS\x0f\xfedO\xfc\x81\xc3oOH&*j\x19\x1f\xac5>\x9c @,\x9d\x9c&l\x8e\xe0PN\xb14\x13.\xc8\xd4\xab\xcf\x9f\xaf\xd3\xe78[Rv\xed._\\\xa7\xcbOd\xf5\xa3`\x8aY\x0b\xba~\xdd\xfezs\xdd\xae\xbc;}\xd9\xdd\xe9 \x13\xa5FK\xa7\xe6*\xc2\x86V\xbe\xcd\xf1\xf8\x93H\xd3\xa9(\xcaW$\x90\xbf\xfc\xb4\xa1?t\xa6x\x14\x15\x90D\xc6\xaaVRJ[\xb3_u6k\xa6m\x1ce\xac\xe5o\xd1\xab\xf8\xc0\xe6\x8eyr\xb2\xc8\xc9\xb9\xc9\x14\xec\x97\x85\xe5\x9f\xbeIQ\xeb\xc5_\x9f8\xf2\xf6fJ\xaa#\x11d\xa5H\xc7\xf0\x87F\xe9\xa8\xb8!\xa5\xbb\\\xfc\xaa\x13\xbd\xcck\n\xbf8\x93R\x7f\x8fz\xed\xe0{>\xa0\x7f\x92`\xd73\xff\xdd?\x9c\xb8z.k\x92\x9b\x8d\x9c\n\x15-\xab\xadt8\x17\xc1\xa9\xc5\x9d\x12d~\xd8\x8b\xe0\xc4\xa1\xbc\xc1\x04pL\xf5\x86\x91/\n\xbc\x11h\xcaU\xb1\xb8I\x04q\x18\xc1\x96T}T~U\xe6\x0eD\x1e\\\x19~\x18$\xb2P\xd7!\xe7\x02\xa4\xf6`g\x0fK~\x1d4\xab\xc9\xf1\xeb\xcae\n\x17zvl\xc6g\x14{U\xf9\xc6\x9fp\x9bW\x93\x1cZ\xa1'\x8a\x8f\x19\x1f\x9b\x82@m\xc8C\xea*\x8b\xb2>c\x16\x95\xd4\x07Q\x97\xb4\xd5\x14\xa4\xa5\xa3@O\xb8\\p\x08\x19\xee6\x93\xbe\xc2\x82\x8f\xd2\xe9\xa6\xd4/\x89\x05\x8d`\xe9\xe4U\xb8D%$\xb6\xc0\xf8\xe9\x01GD\xb9\x9e\x84\xf3#G\xc12\x8c\xe0(\x881\xeb\xc3\x05?'D\x0e\xd7!\xff\xcc7\x9d;cn\x1e\xaa\x95\xa8\xf4W\xe1\xf6\xd9\xba\xff\xc2\xcf\x13\x976\x80c\xea[l\xcc\xf2\x08\x1b\x0c\xf8\x02h\xac\xf3\x8br\xa6\xb2\xbaP\x04\x99\xc9\x96\x83\xbbW$\xde\x0e\xaa$_U\xcb\x07\xda\xdf\x8f\x1e=\xe2\xf4\xe3\x16\x9c\x99\xf7\xf9\xb2\xde\x08\xba\xe9k\x1fY),\x1f\xef\x8f8^\xaci\x1b\xc3Z\xfc\xb1\xc4qI\xbd\xea\xb0\x82\nl\xc3\xb9\x84\xccH\xe8\x15\x07\xf5\xd5\xcdB\xfe\xe5C\xf1\x1d\xe1+\x0d\x070L\" \xbeK\x9e3\x17\xbd\xac\x12k`\xf5\x82Z\x86\x02Z\x9a\xe8:\x12\xdfph\xd1a2\xb2\xd3\xcc\x02M\xb46\xeds\x1c,\xd1-:\xe0\xaf\x15\xf5\x8c\xc6>~ \xd3V4\xa1\xba\xae\xc2\x90\x1f_\x8be1\x0b\x0c\x9eEV\xf2\x12+\xa0e~@\xce\x9c@.w=zmUj\x95[\xb7\x00\xb3\xb0\xd6\xd4+\"'c\x99\xd8Wl\x7f?\xce\x12\xc1S\x82\xc9h\x87\xbc\xa3QX\xe3\xc8\x98\x0fG\xa6.\xe5l\xc0\x86\xb6\x04x\xea\xca\x10\xab%\xf9'5\x115FEKl\xad\xfe\x01F.J]\n\xd9\xcd\xb4\x99wU8\x8d\xf2|\n\x0b\x90\xd1a\x9a\x82W\xc9\x99\xd6\x8e\xb9d\xb7\xe0\xb8\x85\x14\xa9\xe8\xb2\xf9\x1f\"\x7f\x9dJ\xdb\xff\x0e\xec\xc1!L\xfa\x8bLT\x82\x98\x0cSN\x8dZ7\x86|\xe4\x9c\x1f\x9f\x08\x06S\xfc\x0e#\xec9hh\xff&\x95)\\ \xcc\x11L\xbaX\xd2\xab\x08~\xbc693F\x97!vY6+\n\xf5\\\\ \x82z\xfdp\x11\xf9IP\xf6\xb1hF\x12EC\x84\xa6\xd7J\xd8x\xc3\\\xce\xb9%\xb8\xbb24\x1b\x95\xb3\xc3%\x13\x8f03\xf2H\xc4q \x19\x89\x99\xd8\x89&x\xaeM\x17k\x99\xa1U\x02\xe8\xa7$\xc8m\xa0\xd2\x04D&Y\x1e\x8a@b\x0e\xa9\xb2P\xf0]\x9a\x9f\xa7u\x18\x9a_\x1acL\xe5\xd6\x00\x82\x14n\x81 \xb5\x91\xae!\xa1\xce\x1a\xca\x1c3AUtz\xc9D\x93\x08|s\xe7\x0b5B\\.\xf3;|\xef\x8d\xe1\x10\x16\xc3\xe9\x08\xdc!\xeb3\xa1(\x9b\x08\x0b\x8cX\xe8\xfaZ\x99g'\xd4\x04\x13\x8f\x83B\xc0\x01E\x97\x85F\xde\xc7N\xf2\xeep\xf3\xaaU\xfc\x92\x0c\x01\xdf\xcf\xa2\xde\xcc<\x8c\x103v\x1fHV\x9f>\x80%\xa6\xf9\xe1\xb81\x80\xbd\x10\xe2\xe1r\x84hp\x0b5\x0bl\x98lo\x8f\x1c5\xeb@\x13J\x87\xf9H\xa8\xb8\x84/|\x80 \x05\xb7\xb1\xda\x98\x81\x90\xf0\xc7\x8b\x08\xd2\x08\x96\x11\xcc,\x90\x94\xe79\xff\xbf\x08S/\xa1\xc4\xe5?\x16,\x86{\xf0/\x98j\x9c\x8b\xba\xe3h\x0f?\xde357\xab\xda\x99\x99\x11\xf1tSr\x7f\"\xd1m\x86\x14\xfc\x00R\xf8\x17\x92\xfd\x14\xd6`\xc1\xd0\x0b\xed\x93\x82\x05\x8b\x08\xa6\x11\xcc\"8\x0d\x9b\x01\xf8\x1d\xe2\xc7yY\xed\xa3\xf2\x80\xb0\x1f\xb5B\xbdZ\xa6\xbf\xc9\xb5\x08Z!\xc5P\x80O\xb9\xa7\x1eb\x99=Q\xf3\xacslz\x97\x88\xf6\xf5\x0e\xdd*\x8d\xa4\xfa\xcc1\x06\xb7\xa2#\xe9\x92\x16\xf0%\xb5L5\x00\xa8\xbbn\x19\xa2\x81_0\x80\xafH\x90X\xed\xe7\xe0\x14\x17\xc6\x19e \xdd\xa8\xf8C\xbb\x7f\xedW_\xf8\xccv\xecj\xa8\xb6\xa7mct\xe6J\xb5\xe6Im\x10\x90:0\xf9*\xa7|\x06s\xb8\x0dw\xdb-\x8f\xd5\xb3\xfd\xf6\xb3i\xf9\x9d\xcds\x7fa\xf1\x188\x97\xb1CG\xc6\x80a\xe4\x9b\xbb\xf3XZ\xe4\xea \xe6\xc9+\xa9\x9d\x99/\xa4\x18:\xec\xaa\xe7D\xdd5\x1e\xc4`r\xa9\x03\n^\x89\xe3:\x87G\"kt\x0e\x0fa\x0e\x87p\x81\x99\x07\xf2\x08U\x0c\x18g\x8a\x85 X@\xfb,\x13\xf2w\x88ei\xd9\xc6n1\xe8'r\x9c\xfc!z6\xa4\x01\xe9\xd2\xf4\x96\x9a\xda\x0e\x7f\x13\x93\x17\x89\x9f\xa7\xc5\xc4\xed0\xa2\xe5\x01\x99\xb1\x8e< \x0b\x16\xc1\x05\xe1l2\xf3\xc8\x03\xa2 \x1f\x81=\xc6r\xc1\xb4#\xeeKsZ\xbcJ\n\x06\xc3^\x04\xbdQ;\xa9E\xad'\xcf\xa4\x16\x89\xaa\x15_%\xc5\x0f\xcb\xac\xe4\xa4\x9e\x95\xdcq\x9ar\x01\xb6d-1I3\x8e<\xcb\x93\xb3\xc4\xe6\xd9\xa6d.\xde\x13\xed\x8b2\xa1\x04n\xc1\x99!\x14\xd2\n '\x0c6\xcb\xae\xe1k\xbf@\x901\x04\x99d\xabjU\xf3\x1dE\xa00\xb1\x7f\xe5\xc4\xc6\xe0\xa1\x96\x0dvs\x975\xc0c\xe1!\xec\xc2!|\x92\x19\x0cq\x9b\xed\xca\x08SqsW\xa8\x1f\xf7\xc43f\x8c.\x03\xb0'\xd8c\xe8\xfb\xa4\x16\xd3\xfcNe\xcf9aq\x92\xba\x19*\xe5\xdeo})q\x06\n \x14\xdfb\x94\xc08^\xc4\xe3\x84\xad\x84A|\x00\x97Xo\xbb\x195 \xe4A\x14\xb12\xf1R\xd6x\x89\xf4ORrN\xd2\xea]\xfb\"n%~\xe1\x06\x89\x08\x9b\xa8BL\xcbuV^\xf6b\x14\x1c^\x9b\xb8\xdc;7\xd3\x05\x82E\xac\x14~\xad \xa4\xcf13z\x17^\xb9\xe2,k\xdbj\xb3\xf4-H \xcaJ\x1c\x9aU\x03 \xcb,\x992T\\h2\xaf\xcah\xaf^R\xba\x0d\xf1p\x91&c\xe4\xdb\xf6lQ\xbb\xb5\xc1&\xb4 \xf9&d\xa0\xd1\xcbn'8\xfe\x0d\xc9$tjZ\xfeTK\xab'\x9b\xc0\x15\xe6\xf8\xd3\xc8>!%%\x81j\xd7NE\xc1\x19)'(\x16\xcbb\xd6\x05 %\xbcU\x11\xfa\x96]\xae\xc1\xc9\xca \xe1\x1b\x16\xbai%\xe0\x9f\x90\x11\x91dQ\xd9R-;\xbe\xe6\x16\xbc\x8b2\xbb\x96\x16\x11%w*\xe8*l\xe3\x1e\x1e\xe6^%\xd9\xea`\xcb|\xf3:|R\x87\xecn\x04;{\xeeV\x97\x14wWW\xcb\xad\xf5\xb8\x16\xb0\xad\xa1a\x9f\xf0\xc8\xd9\xf1\x05\xb3#\xfbd\x99HnH7\x07\xb1\x17(\x9a@\xee\x00\xf0&\x89W\x1e\xfb'^i\xf7\xe1\x95\x90\xa3\xd9\x91o\xe2\x95vw\x1b\xe4\x19y\xec\x97g\xc4\xdc\x87\xd7\xb4\xce\xaf\x93\xd7\xe3qg\x9e\x91&\x9fx,\x08\xad\xd7\x89\xa6o\xc2v\x11\x8dz\xcb\xbe\xf5\x97\xce\xbf\xa8\xee_9\"Y\xe2\xaf\xac\xfa\xe7\x1e\xddfI\x19\xca\xedi\x17gOJ\xe4\xb3\xaf\xcd\x06\x05a0\x14\xb1\xabB.\x9e\xa8\xa7\xec\xdfW\x04\x86b\xd1\xd6\x8d)\xd0F\xd9)\x9aur\xa5\xfe\xd8 _\xbc\x02\xa1s@\xa1\x04\xc1\xa2\xd7w\xa6\xd7\xad\xec\xdc\x98\xc8_\x92d\xe2\x82\x05:\x9b\x135\xb8\x9c\x1a\x87\xa3s7\x91\xc6\xdcl\x94\x90\xc2\xb4\\I\x81\x12\xf6\x00&\xac\xad\xc1\x9a\xb1v\xe2\x89W\xcf\x8f?X2O\x9c\xa3\x05]\x83\x9cM\x7f5gV<\xc0\xb1\xa3h\xac%-\xa8f\xd2\x8cn\xd3\x7f\x9d\xb3\xe1\x8c\xa9`\x90sV\x05\x83\x9c\xb32\x18\xe4\x9c\x95\x89\"\x9f\xc8\x9c\x91\xda\xbbx\xbf|[\xbd\xa5~\xe1\x8b\xa5\xfd\xed\x89\xb2\xc5i\xb7\xd5\x17\xea\x17>\xaaR{=)\xf3|U\x0f\xcadOOj\xd9\x9f\xf0\x85f\xe2\xa0'\x0d\x89\x19_\xd2\x93\xf4<\xd1r\xf6\xc8\x87z\x0e\x9d'\xb5\xa4:\xa2\x0b=\x03\xce\x13=#N\x04\xf3\xb6\x08\xf4\x84L\xb3\xdcd}\xb4iZh\xe9\xd0\x84\xde\xcc\x0c#\xdb\xca\x8d\x81\xeb\\\x86^hL\x97Y\xbb\x88\xfaC\xe1\x13e\x0e\xad\x15\x0e\x80\x8f\\\xadK=\xe1p\xc4O2s7\x99\xf4\xbb\x10\xaaHs/LT\xbd\xb0S\xf2\x18\xf4Q\x0c]\x06,,R\x1fs\xba\x15\xd7\xc0\x8c\xb0\x85\x1d\xd4q\x86!\x8e\x06\xdfJj\xa0jSe\xe3\x80\x85\x95,\xf3\x80\xf2\x12\x06p\\\xe5\xce2\xcf\x7f+1\xabTj\x8e\x13\xbb\x0f\xa0\x10.\xa6\x05\xfaIJX\x14\xa3R\xfc\xb2\x12\xe4\x0c\xddD\x96%\xf48\x8d\x0f#X6)\x98\x01G\x1fO\x19i\x1d\xef\x9d(\x1a\xd4q\x14\x83\x8c\xbf\x00S\xa5\xf5\x13\x85\xfa\x0e\x84\xcd\xdc\x08k\xee\xc4\x0b\x07\x93:\x0e\xda,J\x88\x839&\xcb\xe4\xd8\xa5\x83\xd1\x80\x82\xf8Rf\x86\x0c\x1a\xbf6DN\xb5Y\x9c('\x9b\x8ceoRY\x91\xa1\x92/\x92~mq9M\xceD\x85\x11\xc4udi\x1fog,\x82\x15\x8b8\xd3\xe0J\xa3~b?\xad*^]\x1d\xe2F\x08KEay\xb2\x1b_\xc2\x04-,\xc8\x1dQ3Ryf\x87O-\x91\x88d\x1cv\xc3\xc6\xc4\xa0\x16\xf7\xcc\xe7\xb6\x8c\xc0jc\xad\xe9q\x96\xb5rV\x16O\x13u)b\x12K\xff\xa5C\x85`\xe2x?PQ\xee\xf8\xd3\xce\xa3\x82\xf4K\x89e\xe5\xc3]\xf4\x8c\xdd\x81\xd8\xfd \xaa\x18\xf9k\x16\xbe\x11_y\x04s\xc4\x1d\xfe\xf2\xdca\x0f\x95@\xe8\xe4\xe1\xd5\x95\xa0\xe3,\x9fvZ\xee\x87SG\xd1\x11\xd0\xd4\x12X\xedq'\x85\x03N5\xdd\x9f\xc8\x96\xd1\xb3k9$\xe6\\)`\xdcvx\x97/a\xd1t\xcb\xcfPs\xdc\xb1\xac\xc2\xa9\xd5\x7f\x01S$/\xf5\x05L\xe0\xd1#\xc8\xdc\xdf\x8d1\x00f\x9b\x1f\xeb\xea\x03\xc72\x8d\xcb\x05\x1d\xdf\xf0\x82\xe2\xb9\xf6\xc0\xea`\xa1_|\xed\x8d\x19]L\x97Z\xf4\xa5M\xe8k^\x89,\xb2\xc7E\x9d.\x85|\xf3ZJUh\xe7\xcbv;\xbe\xba\xf80\xd2\x86/a\x17\x82\x83.\xf5#\x92\x8f\xe1\x00\xd2.$\x079\xf2X\xb8\xa2\x17\x98y?\x13\x87R\xc2Q\x83\xf2S;\x0b\xedn \xe0\x9c\x92co ]l=\xf6K(qaL\xf6c;D\x96\xad\xec\\\xe7\x0e\x8d\xc2\xb2T\x93\xc3\x0e\x17\x92\x96\x9a\xaa\\\xfc\xd4T\xe5\x0co(=9\xc5_U\xd6\xa3e\xa9$\xcf\xf0\x87&5&\xe2\x86\xd4\x97\xc7\xe2W=\xb9\xd7\xd2\x0b\x14G\xcc\xa5Q;c\x18\x06}\xc6\x07$\xec\xfa\\|\xf34\x85_\xb6\xa1l\x03q,\xfc\xf1er\x1ewL\x05\x11N\xf3\x0f\x15qS\x8a\xd9\xd6\x07\xc8\x0b#^j\xbe\x14\x99kc\n\x96\xb3\x83sK\x1b\xc4u\xb8td\xcc\x19\x0b\x13\x9f\xb4\xe5\x89\x8d\xa1`\xe1\xd4$\x8d\xc5 \xa5\xf2F\x05\x92\x0d\x136\xde\xb2c\x18\xc0\xd8\x1c6h[\xd1\xa2>\xf2\xf2\xf8'\x95[\xa6\xdeUT\x83\x9d\x80<\n;-\xde\x12\x0e\xcb\x9b\xcaD\x16\xeb\xe3l\xc7 \xd8\xf0\xe6\xd8\xce\xd3\x95j6\xf4\x07(c\xf0\x88\xe6\x99J\xa4\x07\xea\x9c\x05\"?\x97dK\x91+\xe5\xa3\xe2\xe2\xa5g\x1a\xc3\xa7\xf6\x91\x94\x16\xf4\x86\xedW\xb7\xac\x9a\xf9A\xf1\xe5C!\xd0(V\x10\xb6\xe1\xdc\x86t5sD\xc9DJ\xbe\x15\xbf~ \xfc\x16\xd0\x15\x07\x0b\xab\x0eJ\x1f\x06\x11\xaa\x95\xa3'\x03\xffhg\x00\xe7N\xc4\xeb*\xf3n\xad\xe8\xe5L\xd2\xa3\x05\xbd\xa8\xa83Q\xeeX\x7f\xa2\xe2\x0f,\xe5\x8d5\xb3\xbe\x9en\x07\xf33\xd8\xd9\xf6\x0e\xf6?\xf1a\xff1\xc6\x03\xb6m\xc5\x19\x96\xa5\xcc\x8c\xd8H\x91\x9b>@\xb3\xd1.\xfe\xbd\x8d!c\xbc\x05\x83\xc7\x02\xc7\x87\xb8\xb9\xbf\x92.2\x15s\xdc[j\xd8\x86\x86_\x13\xa7R\x13\xfb+\xd1#\xd5\x91i\xac\x82N\xb7a\xccG\xfd \xc4\xe7r\x1fa\xf5\xac\xb4\xbe\xe3\x0fa\xa8\x8cG\xe9H\xee*.\xd8\x8da[e\x1f(\xf8\x9f\xe7\x86\x11\x8d\x85L\xc8\x1f\x8f#QF}\xcc\x0f\x00\xf1o\x82\xff\xba&2\x15\xd2X\x82\x11\x04\xf8\xe72|\x00\x0b\x0e\x11\xec\xb9\xe0\xbb\xc9k\n\xb5\xa1\x8b\xf1\x9a\xf1n\xd2\xe5N2\xc3 \x8a\x87\x18#!\xc8\xc6RH\xdc\x07|`x[Soat\xe3\xc4\xbc\xb2X0]|s\xeb\x16\xc6\x01\xa3h6i\xa8 :h\xc5\x1c#X\x90\x90\xa7bz\x9c\xdf(\x1e\xc0\n\x1e\xc19\xff\x87S\x82.Y\xe2\x14\x060E\n\xb22+I\xd4\xc5\xbb\x9bK\x92s:\x12\xfdV\xbf\xad \xa4\xcc\xfc\x9d\xfaP\xf4|\x8e\xb4\x0b\x060\xe9\xa0L\xa0\x18|\x05\xb2\x80/\n\xc6\xac\xcfj\x8a\x93\x1c\xd9\x98e\x88g\xdd\xa3\x01,B\x8898\x16\xb8h\xf8o!\xdc\x16*\x07\x85VSR\x0f(\xda2\x85O\x96\xee\xc8\\8\xce8\xa5B\xfcp\xae\x9c\xdc\x87\xa9S\x98\xe1\x0bs\"\x84\xeeG\x8f\xf8\x81\xeeZ\x18>\x80\x13\xa4\xae\x8b\xea\xf5\x10Ns\x12\x7f\xb2\x7fu\"\x05\xb5\xed\x01\x04bK\x85\xf05\x9c\xe0&\xd9)!#\xf7\xd3\xf0\xc4,\xdc\x9a\x177\x15X\xfdH\xaa\x11E;M\x90\x16|ev`\xcc\x97(\x15\xfb\xe1\xa1\xd8\x0f\xb5\x0f\xca\xe5,8%\x90\xef+\xea\xb2#\xa9\xca\x8e1\x8ar\xe3\x94\xa4KTkT\xc7\x89`\xbbI\x8d\x9d_V\xba\x1d\xc08\xce\xca\xbd*\xd5\xdd\xabf\xbe\xeeU\x9cL\\\xb0 \x16\xe2\x0eFj6\xa3\x1b-\xc7\xf1c\xbf|\x91\xb9\x9e/\xb2\x16A_eY[\xba#B0)\xb6\x93 F \xc6\x9a\xbe'\x15\x10~$\xf7l\x82\xeb++\xfd\xc5A!RJ\x8aU\xbf\xe9\x94\x92\xb9\x88GK7@\x8f\x04\x1e)\xa7\xc9[\xb7D\x82\xa8\xca+9A\x92\xa2 \xdf\xccrcY\xa9\xb7])\xe6\x84[\xf5.*\xe5\x94\xce\xfa\x9co\xcas\xaf\xf6\xdf\xb9\xdbw\x16z|.\xdc\xe1>\xb0\xaa\xbe#\xbf\xb5\xb1\xdf\xcd\xf9\xff\xfa\xfa\x8e\x1f\xdcP,Ka\x8e\x9b\x08gk\xf0\xb5oJ\xbe\xba\xea\xe1\x9dfT\xb1+!\xaa\x14\xe1(\x02\xe1\x8f\x03\xb4\xdb\xf7OD\xea \x91;<\x15\xf6e\x8f\xdc\xe1^sz\xeeT&\xac\x842a\xc5{|\xcd\x02Q\xdd\xe6\x88\x05\xadP?K\xeb\xbf\xbb%\x0ci\xda\x89\x14KoM\xbd\x14K>8)\x1c\xfc\xbcHI\xc1,\n\xff\xa2\xe2\xf8\xf9\xd1\xba\xb4\xa9\x12\x06\"o\x93\x19o\x85~\xa2KQ\x18K\xf28\x10\xda\xd3\xea\xe7>|\x0d\x89r\xdcD\x1b\x910V\xb6\x93\x9fZDXu\xc9\xfe\xb5\xf9H\x15\x0bJk\x96}\x14\xf6Y\xf6\x92\xac\xc8\xe4\x98|\x0e\xc2\xcd)3\x19\xeeZ\xb8\x86\xb0?M\x93E\xc0;x\x1d\x8b|:\x1anr\xa2\x9b\xd7p\xb5\x8e\xb9\xba\x933:\\\xa0\xf1L\x95}c\xa10\xfe)%\x86\xe6\xdc\x1bkj\x0bND\x96J45(/\xb5X3\xabm\xa6B\x80\x18Qi\x19\x0e\xf7F]\x8b\x9d\x0b\xd5\x9eXG9\n\x91j\xdd:\x081?\xe9L\x1f+\x12Z\xb5\x10\xcbB)\xb2\x19+\xc9\xb0\xf1=\xb9\xfc\x9e(\xca!|\xc3%\xe5\xc8\xcc\x9c\x0c\x07\xe3kt\x7f\xf7\xcc\xbc\xfc\xa6\xc3\xeb\x04\xdd\x954\xaf\x93\x93eA^\x92U\x01U)\x0bE\xf1\xdaI|m\x9d\xbe\xb7\xd0tc\x8f\x9b7\xff\xec\xafm\xfe\xd5_\xdb\xfc\xc7\x8e8\xb6\x7f0W\x8aXV\x1bA\xbd{~\x83o\xf1.\xafN\xad9CR\xe6\x08\x8b9\xaa\xe2%\x9d\x0d\x9d\x97e\x92\xe5G\xb2\xfe\x19\xfa^9\x15b\xfe\x83\x05}7\xc9n\x02\x0b#\x12\x99*\x8a\xf09\xcd\xe2\xa2\xd3\x0d\x15\xf4\x8e\x12:N\x97\x13R4\xab\xda\x97-\xaa\x176kv\x16\xdb[\x1c\xc7\xe3\x19yO\x8a%\x86Q\x12\x1aaE3\xe9Q\xf8\x91\xe2\xe3Z\xd9.W\x04\x93\x12C\xcc\xce\x14P\xa7P\xadzV\x9e\x8c\xa1\xf4:\x14\xbc\xa1]\x1da-v\xa5y\xa7n:?\xa1\xef\xe5\x07\xc1\x9b.\xa9^i7UW\xa2]\xbb\x98\xaeXx?'Vu)\xbbf\xee,_\xab.\xe4RHg\x1d[uU\xfb\x0c\xdd\\\x87\xbb\x1d\xd9\x90\x00\xc3:\xd5\xbb\xda\x87{\xa3H\xfb\xbb\xe5^\xd8\xbc\xdcfQ+\x19Q\x97-\x8b\xb9\x1f>\xf2\x95\xc2\x15\xfe\x9d\xcbLp\x00\xbf[\x11\xa9v\xd3F{?ws\xba\x9d\x148o\x12\xdd|s\xd2b\xa7\x01y3\xa4\xd3\xa7\xa82\xc6\x81bbz7\xc5\xadj\xa6d\x18&\x8c\xbe\xf6\xa2\xc4Nn\x14\xedp@N\x02\xe43\xbck\x13\xa0\xac\xc3\xd9\xa6N\x83\xf2\xa0\x9a\x91\xfaXZ\x04mD)\xeb\x98\xb2\x99(\xf9\xcc\xb9\x86\xc3o:\xeb*o@i\x94\xf8\x9atR\x19t\xb4\x93\x04F\xc9\xaf\xf6\xb7\xcf\xa5OZ&h\x83\xdbE\x05}\x13\x9c4H\xc9\xef\x1cZ\xcbHC\xb6\x18)\xd0\x92\xe3\x9bq\x01\xc0\xa2NhUE\xb4\xec\xf1\xef\xbb=\xd7\xdc\x1b\x9c\xea,\x16m\xeev\xba s\xe4\xe2\xb2\x88`\x7f\xd02\xe7\xcd \xa9S\xe0\xa3y\x06\xa0sW\x1b\x8c\x13\xf4\xbd(\xa4D\xdb\x961pW\xa8Yj\x90-W:\xc1\xb2'\xd4\x04\xc8\xbc\x8f;{\xb0cHa\x0d\x92{h\xd2X+WP\xa7\xb1\xb5\xc6--_\x8f\x8d\xeb\xe0\x0e\xa9\x81\x97\xa3\xe6\xe8\x90\xff8\x0f\xd7Q\x8c\xe4*\x82-\x1b\xec\xcc\xb1E\xae\x19\x19\xcfx{\x0f^[\xfe\x0f_\x95_\xc7\xc9\x8e\x9b1k\xa2\x9a\x15\x8f\xcf\xcbD\xbd~\xc7o\x86\xc7\xd4\x8a\xf7\xb2\xb5U\x11\xc4\xccq\xfaf\x7f-;P\x8e\xa7\xcd\x0bH[\xbb\xa1\xb4P(t\x98\x0e\xa6\xc0\xe5My\xae\xc5 \xd8\xcf\x98\xa5\xb9*/t#|\xe2p\xeb\x05%5\xe8|\x02~P%R\xdc\xde\x8e \xe3\x0d\xe5\x12\x02hn\xb6\xe7\xf9\xe4Sm\xfa\x84\x81Z<7\x1f\xe1\x03\xa6&\x1f\x918*/v\x03m\x036\xc3\xd3\xf9S\xe1\\\xdc\xc9\x8d\x80\n\xca\xa8s$\x89\xfb\x0be\x08K|\xb8\x12\x906\xb1b\xb8\xeb\xb0\x9a\xa9\x0b\xb3Y\x1a\x13\x83\xeaW\x1d_\xc6h*\xd4r\x02}\xc6\x8a\x882\xb7:\"\xcf\xd8\xcap\x82U\xf01\xf3;~\xb6\x81'\xbe\xc4\x8fX\"N\xf9\x0c7r#\xe2B\xc4\x1e\xdcF\x1f\x1c\x0cDD\x9f\x1c\xf9\xfe[Y\xc1,\xeb\xcc\x9b\xc4\xd1\xe6\x9d\xa8cf\xb7'|@\ni \xc8\xe1\x04\x0c\x12X\xaf!\xe6\x7f\xc5e\x8f\x1c&}\x96 \x15\xbav\x10\x07a\x05)\xf3\xa0\xa4\x93w\x0c;&\xcc,`0\x10\x9e~\x01\xdfl\x85tD\xda\x85\x03c\xa5\x89s\xe9\xd5\xe8>vR\xc5bV\xe1\x06K\xac\xac\xa5\x8c\xa1\xcb\xca\x80\x18\xc1\x16\x9eR\x992\x8b-\xcb4>A\xda<+<\x8ea\x99\xe1\x86\xc9p\xd3*)\x10\x93E\x15\x15\x93\xb6\xcd\xe9$\xa6\x9b1\xf8\xb1\x85\x11\xa4_\xa6\xa7\xca\x9c\xe09\x96!\xda\xa4\xc2\xbcf!F\x11\xb4\xdd\xe5\xaf\xf45\xbe\x9e\xb2N\xda\xf4x\xff^K\xe4\xd6\xd3)\xb4\xd1Zm\xab\xf8\xec\xeb\xe3\xb1\xbc7|\x96\xaa\xb5z\x10B\xd6yZrxmo\x17\xf0HC\xf9\xae\x93\xd8+\xfa\x1d\xba\"\xe0\xf9u\xe5V\x13\x10T\x13tM\xa1\xe4\xaa1 \x96\xd2\xe2\x11\x0c\xb0g\x91\xa8\xa3\x13\xc9'\xcfU\x92\\\xf4\xc6\xd05\x95\x9b(\x08\xeaXk;0\x7f\xf2=0\xddd\xfb\x86x`;\x19K|\xf6\x08 \x1c.\xef\xe72\xc8\xc2E\xa7\xba\x11\xdd\xc1i\xa7\x9d\xa4J\xa4\xe4\xc6\xd3\xb2\xc9u\xa7aE\xb5\x8a\x16\xdb]\xb8\xd9\xee0\x02C\xa0\xe5\xcd\xf0\xdc7\xb0,Y\xee\xb3.\x9b0\xf7_~\xdel@\xb0p\x93\xe3\"\x19\x12\xb5\xabk\x92uP\xa4De\x1d\\JZ\x11\xd6Y\x7f\xa4\x0cY\x832d\x918\xc2\xb2.\xba\xd0-7L+\xabG\x07\x8f\xcf1\x04+\xf9\x8d\xf1/\xde\x81\xe0\xf2\x8a\x1a\xde\x8ee<\x93\x83\xbd\x87\x8bY\x92\x12\xb0:\xe5\x81\xae\x0e@\xdb\x95>\xf3\x04\xfb\xd8\x88\xe6\xf9 ?\xde\x88\xe1\xe3\x8b-\x01\x0e\xfcE:e\xa9s$\x07P\xce\x86\x04E\x07\xed9WUC\xac[\x99_\x85\x89\xb2e\x1d\n\x04\xd0\xb8\xe7-\xf4\xbcJ\xe1!\x16\xac\xb9\x05q\x80U\xfb\x90(\xa7\x18\xa8\x0d\x07*M7R\x04*\xcb\x01$()\x86\xa5$\xb1\xb5\x8b\xc59\xedxeW\x95\xf3\x85\xe5_\xb7K(\xfd\x15\xa6\x8c\xdc.\xae\x81\\\xc5aG\xa1\xf3\x1b\xa3R\x92\xadJ\xbc\x94\x14\xc4\xcbd\x02\xea\xdc\x92\xa9\xe672\xcf\xa6\xbe\xf4\x06d/\xb9\xa4\x00\xa5\xfb\xf5po\xc4%T\xd4\x10\x06K\x15O\x81\xd8\xc5\x8f\xd18H\xab#\x93\x96\x84#\x8f\xc4\xf9\x99v\x93E~-\x85sn\"K\xa3\xa5\xad\xe5u\xb6\xa0\\\xb4\x90\xac\xa3g\x97\x1di\xbb(`\xd7\xaa\xdd C\xbb\x01E\xf533\xfd\xec\xa4\xa8\xc2#\x13]@M\xf2\x8b\"\xb8Kk\xda\xe8\xccN-\xc5\x9eT\xda\x8d\x9a\x83 \xeb(\xe2$\xe1>\xccq\xe4\x99(\xbdx\x08\xe2C\xe9^\xc6\xac\xee\x83e\x96i\xeb\x11\x91\xf4\x8b,g~\xd2\xacb\xa2\x022\xbc3\x8a\x80\x0e\xef\x8c\x10\xcb\xc9p\x7f\x04;@\x87\xfb\x86\x0c\xc1aU\x90\xbc\x91\x95\xc1j\xb1I\x86l\xa4v\xd2\x00\xf6\xdbm6+\xf4\xb9\x1a\xe2\xa0\x1f\xee\x99\x06&8\xd7_e\x8d\x0f\xe1\xd6\xfdR\xfc\xfa!h(\x04m8\xf5\xc2\x89S\xc2\xdfE\xc3+\x0f\xbb\xd1\x17\xe2 \x1fJ\x89\x1bV\xbc\xc8\xc9d9\xde@\x87![\xff\x15=+\x05;G\xd1\x87S(*,\xf9\xf2\xdd\xb6\x0c\xd4\x8a\xe5&\xdfWG@\xca&\x03\xaf\x0f:\x12\x89\xf9\xcc\xc3\xf5\xf4|\xff\xd5\x8b'\x13\xf5s\xec[N%\x8f\xbfu\x0b\xa8\xa6\xbf\xad\x85M\xae\xd7U4\x82\xf8\x05[\x03\xde\xedz-b[\xbd\xc6\xfb\xb2\x8a\xbf\xf8\x02\xa1Y\xea:\xf91OH\x90\xfbz8\x97k\xd6\xf2\xb3\x04\x81\x84\xf3\x84\x06u\xcb\x14\x0c\xfc\xf6u3\x0b\x9f\xf0\xf3\xac\xce\xc4\xdfE\xbcv&Bx\xb6T\xfd\x0bM\xa2\x81Z\xfa=i\xa9\x10\xe4\x95\xd9\x92\xf0\x81\x06\x94\xf6|\xba\x05Y\xe2\xc1\xb9\xe5\x9e\xc0U\x97\x022_\x1f~2\xc1O\x01\x86\xb0W>\x97\x1c\xdf\x1d\x07\xfe\xf5\xf5m\x1e\xec\xff\x06\x9c!\xaef\xa7\x00\x86\xba \\\xce\xe4\x9a\x80\x92X\xe0\x02\x88H@\xd2/\xb29\xb9N\x07\x1c\xbd\x1c\xcd\xcb\xfaR\xffFFJ\xe5\xc7\x8c\x11\xbb\xa5\xb3\xaf,Gq](\xe2\x00]\xb3\xbcy\x81\xf8\x87\xce\\\x08\xc2\xc4\"jr\x90\xfe8\xa3\x05\xcb\x97c\xd4,\xfb\xd1\xf7\xaf,\x8e\xdeI\x99\xcdFD a\x89\x116\xcb\xb3\x0bD\xf1\x0f\xab\x059\xca\xf3,\x0fzG\x97\x0b2fd\x02\xc3\x97\x11\xfc4\x02\xb6\\\xa4\xe4\x00z\xb0\xdd\xcaHk\x19\xc3?\xdd\xd1U\xaf\x88\x8cG\x08#x\xea\x1b`\xf5\x8b\xbb\xcd\xa5\x00[^\xb1A\x19\x17x\xbd\x9a\xfe\x87\xbb\xe9z\xc4V {\xfaUc\xb88\xb7\x15j\x81\\^\xbd\x12\x8f\xea\x1c\x9c\x14\xd7\\zT\xee\xf6\xd6\x13\xb41\xce\x9aY\xdd\xf1-\xe9\xa4/\xf3\xac\xbf\xd0\xb3\xcbW\xdf\x0bm\x13k\xa7.\xb5\x8c\x9eu\xe6\xba'\xf0Hf\xa3<\x10\xc5>\xe0\x10v\xf8\x0f\xbfs\x9fZ\xb6\xf2\xb9\xf4E\xfb\xc9x\xe0\xa3\x14m\xe7\xa5\xf9\xd3\x9f=0\x1f\x8f\xc0\xd3\x94@\x96\x03\x06E\xef\xa4\xc9\xa7r\x0f\x98I\xbc\x18\x14\x1f\xb5\x81@X\x97\xd9\x0b\x16yG\xe2d\xc1A\x94$\xd0\x99SLX\xb0\x13Z\xb0\x98\x8eI6\xd5*\x9e;\x9c\"\x10r\x88\x1e\xf5Ok\xc9>\xf3\xc0\xa6z.\x9bpr\xe8\xfc\xa2\xa8\x96\xea\xd6\xb2\xc6U(\xe5'\xb2*\xac~\x89\xea\xda\xf2\xe3\xca\xf4\x8b\xe5+\x8f\xb7\xf8\xc5\x8c\x11\xae^\x9d\xa8K\xceeB\xa6 %\xef\xf2lAr\xb6\x92\x9c\xaf\x7f+\xfc:#L\x13-7\x19\x83\xbat\x12$\xc2&7j\xe2\xaa\xdb F\xbf\x8a\xdax;\x8fo\xd3uF\x1a\x89\x98#\xe8=\x8d)\xcd\x18o\x1d2\n1\x85\xa4L\xcf\x9b\x93q\x96O\xfa\xbd\x92d\x8ah;\x07\x8bi\xba\xba3\xb7\xa9\xcb\x12\x8d\xd0\xbc\xae\xfa\xa7 \x9d\x04U\xd4]\xf7gW0\x8e\xd9x\x06\x086\xf7\x80\xae\x02\xe5\x9a\xae\x8e\x88X\xea'\x90\xeb\xa7\xf1\x9c\x94\xa1\xc3\x9fD(^\x8c?&d\x1a/S\xf6\x13\xe7\x960\xe7\x8c\xb5\x1b\xfb\x00\xc4\xea\x88\x80\xc3\x8f\xa4\xa9\x98P\x97\x05q2\x94)\xcaS\xab\x15C\x9d\x99t]\xa5\xe4\xa7\xb1P\"\xda\xb1\xa9h\xd3\x7f\xb1\xe0\x1d\x8b\xe0#gL\xde\xdd\\\x95\xaew7Y\xa5\xebm>!9\x99\xbc\x8e\x17\xf0g/\x82\xdeU\xbbV\xd7\xbbk\xd4\xea:\xd7k\x04\xf0\x95\x125\xfc\xed\x90\xadyh\xc9b:\x18F\x8a\x1f\xd2PT\xa6m\xd5\xd0z\xf7o\xaenS\x96\x9d\xe1S\x92I\x95\"}\xb4\xb5{\xa1\xcc\x88\xe0\x1c\xf5f\x95\xbf~g\xae\xdaG\xef\xae_\xfbHo\xb8]\x06\xb5\xd6p-\xf5\xb8\x0f\xb0+\x90U\x9f\x06\xa8\xb8\xd1 \xa7?rv\xbf\x91nDGD+\xf2i\xa30\xd8\xd2\xba\xdc\xe8E\xbe\xb9\x80\xa1\x0e\x90\xa1\x05\xd6\x12\xde\xe57/\xbf\x12\x17\xed\xa1O\xf3l~DY\xbe\x12\xbaRM\xf9\xd3\x8d+\x9b\x15J\x10\xc2\xdf\xa0U%\xc1#\xbf6\xab\x11\x85Z\xb7V3BEH\xe4\x12\xd5?\xb2.+\xdf\xd5\xaf\x99t\xe5$\xfe\xd5\x16\xd4\xd1\xc2\xf4\x9d-\xf2^\x18$\x1a\x84dRh\x84t\x00\x1fX\x1d\xbe\xc3\x99\xaanP\x83zY\xe7\xc0\xb0o#`\xc1\x1b\x16\xc1\xafa\x04o\xaeA\x81\xdb\x82\x1fR`\x13&\xd4\x9ao\xc4\x0dt\x96K\x13m\x8b\xa2i\xce\x86Q?rL>oD3\xb0q\xf5e\x9b.\xbc\xa9\xc3\xcd+T\xe8\\\xab\xc8l\xc67\x0e\xdf\xef\x159\xdc2%\x1b\xac\x8dQ%\x1b@\xa3\x86\xf74A\xd7\x1d\x89y*+\x87=8\xfc*l\x05\x896\x80 0\xb7\x13;t\xb2h\x06\x02\xa7\x02\x9fk\x87\xcd\x06`\xc8\xaf\x03\x06\xda\x00\xc3<^\x18\xf0\x15$\x18Z\x85_\xde|\xd9\x19\x119B\x94\xda(\xa99\xe0\xd6&\xaf\x99\xf3<\x1c\x97I\xc0l1KW\x9c@\xa9|\xcb\xff\x14\xeb\x10\x8a,=e\x0fV\xd5y\xd9|\x16\xc9|\xcd\x14\x0eD1 SWa'Q\xd8\xechB\x1b\x9f\x0e\x96\xd0\x01Au<\x99\x8f\x0bZ\xd7=\xb5\x0c\x1aV\xd4m\x82\xcd\xba\xa8\x9e\nye\x19\xa2N\xef\x8bRL@\x83\x8aP\x1a\xa2\xa2Y\xac\x02\x16\xc4G\xbf\xb0\xd2\xbcbZ\x0e\xd7RT' \x0b\xde\xb3\x08^\x86\x11\xbc\xd7\x97\xca\x14\x08\xe8I\xc4\xcbh\xc06%\x7f\xffe\x9b\xab\x93\xd2\xd8\xd7\xc7\xb8\xe9\xbcy3\xdca\x08r_\x96\xcc8S?\xbc\xff\"\x84\xbd\x11\x0ce\xbe\x18\xca\x14\x862\x85\xa1\xa2\xda\x96\xc2K\xaf\x9aa,x\xc6\"\xf8!\x8c\xe0\xd9\x97s\x10\x0e\xe4{v#\xc8\xf7Wb\x18\xf3\xc7/\xe3dn\x0c\xbf\xfe\xc3HT\xe1\xcf\x86\x88\xf4Jr\xba\xaft\xe8\x10)\xcct\xf1\x10\xedu\x94,D\xb3\x9fW\xff\x95\x88\x84\xc7\xa5\xed!\xbf\xbeb\x81\xb5\x88\x9e\xe6d\x11;\xdf*\xd1\x15K\xf4\xa30 \xaa\x12\xa3\xd8Z\xdd\xdc\x157-R,\xbf\xdaz9#\xa2\x1b\x81\xfd_\x83\xe8\x1e\x91\xa1~{\x01\xca\xf0\xca\x9a[\xb8\xa3\xa2\x86Z/\xd6\xe5e\x89\xde\x95\xae\x11\x82@\x0eS\x18\xa0~)\xde%\xee|S\x0e\x1e\xf7r\x06\x87\"\x91\x8b@\x89\x1cQ\xa2\xba\xb9'n\xee\xb5\xf3\xe5\xeb\x97\xc5e\xd1\x83&\xd4\xce\xe1z\x1a\x827\xf6G\xcf\xec\x8f^\xd9\x1fa\x8e\xaa \xa7\x11\x9c\x10.ZP\xed\xcd/T\xb0.\xa9\xe4A\xb7\xa1g\xd5\xb0\xd6:\xdc\xf8\xf8\xaci\xd4\xf9\xe7o/he\xf2qw\xe6\xa9L\x10v\xd0YY\x1d\xdd\x85\xe6\xf5\xcd[\x1b\xdc\x90\x18\xe2\x94ks\xe1\xe2\xeba\xf5\xb7\xd2Y\x18b6\x9b3\xf1R\xfeV\x92\x89Qe%\xfa\xbfuK\x1b@M\x9fk\x9eli\x1f\xd7l\x03v\x9dT\xff\x84\xcc\x17l\x85br\xf9c\x001\x95\xa2\xf6/\xa4\x9d\xf2\xb41UO\x8dq{\xd1*+\xb5\xb0P\xffM\xb3j-\xe9'\x9a]P\xf8DV\xd0\xfb\x1bl\x03\x81m\xf8[\x0f2\n\xfc\x97\xc2c\x8b\x91\xbc\x06\xbd\xad\n|\xb2\x98~Y\x8b\xc3\x8c\x14\x1ez\xc3\x9a1\xa1\xbeD\x85\xd2ku\xe0V\xad,\x846\x9a\n\xe7\xe0\xa0Z\x87v\x1d\xe6\xda\x1ax*\xd7\xed\x1b\xc7OCZ\x9f\xa9\xccS\xea\xca\xac\xd8\x9a)\xeb\x9ci\xfb\xe8\xae\xcd\xf4\x86\xb4\xfd\xce>\xae\xcf\x1eX!\x91\x07\x06\\k:jZ:\x00])e1Y_uk\xd8\x8dS\xbc9v\xf3\xdf8C\xe25\xc1\xff\x84 \xa1\xbeA62\x0dT\x1b@\x06\x0d\xf8\x1a\x04\x1ap\xa8w\x82\xcc\x16z\xd7j\xc0\xb1\x15\xa8\x8c\xc5\nuxO\xd7\xed\xd3\xf2\xd7\x19a\xefT\xf3o\xa7\x9c\xb4\xd8\x11E\x1b\x7f\xde\xcc\xe4\xed\x17(\xb2\xec(\x99--\xfe\xebu\xdd\xcb\xb0\xaf\xee\xf6\xde\xa3\x93D\xcf\xab\xb3\xc2\xdd\x993'\xfd9E\xff\xde\x94\xcacgk\x1c\x94\xc9\xe9\xf9\xb3k'\xa7O\xae\x9d\x9c\xde\xc5\xc1\x97\x92t<\x99\xd8\x8b\x11\x18\xb6\xa6\x17 S7 \xb7\x82-\x04\xe1\x16\x19N\x9b9\xa4\xeb,zF+[UFK\x0bUy\x1b\xeb`\x97\x0f\xda\xe5\xb73*Jdk\xd5\xb2\xab\x9b?'\x18\xd4\xa2\x1e\xf0\x9f\xd5\xc3V\xf9m\xf5\xe0\x19!\x8bF\xf1\xed\xfa\xc3F\xb3\xeaV\xfd%c\x01\xef\x8c\x1aJ\x8dg\xd4XA\xbc\xbc\xdd\xae \x9eQ\x8f:\xe0\x19\xed\xdb\xeb\x80\xe3CW\x1dp\x16\x144\x82#\x8ey\x05\xbd1\x07\x93\x82\xa2-Yf\xd0\xf6\x96D\x02Nq\xfb\x9f\x88\xb0?\x9bZ\xbd1\xa9\xaawL\x98U\x9a*\xbeH\x9a\xaa\xb8Vg\xbb\xf1d\xe2\xdb\xee\xa4\xc0\x9aq\xac\xac\xbcC\xb7\xb7CH\x026\xa4\xa3\xb0}\xec85\x8a\xe5\xb1\xcd\x8f\x1d\x8b\xfa\xc6x\xec(\x07\xa9Z$\xc1p\xb7yx4\x96>\xa1\x8c\xe4\x05\x19\xb3\x9b]\xfe*\xa3\x12\xf3\xab\xbd.0\xc4/\xbeC6\x94\x98NeS\x18\x9f\x17\xcb~-,0\xf0\x14N\xbfg\xd6'\xe7$_y\xb4\xac\xae\x12\x1dJ#\x8cE\xf5\x0b\x02 \x90\xcd\x93\xa4\xc5\xa6$\xeefZ\x1aHR,OY\x1e\xff\x7f8\xf2o\xc2\x91\xeb\xc6ry\xa2\x08&\xb2\xbai\x14Q<\xa4\xcf1\x85`\xc43G\xab\xe5\x10\x81\x93\xebi\xf4$9H7I=/K\xaf6\xd1q\xafCM\xd3\x1e\\[\xe7T\xdf!Y\xce|y\x819\x0d~.\xbdw:Nf\xde\xee\x93\x95\x8f^\xc2\xd08\xebn\xff/\xd2 \x15\x7f\xadz\x85iZ\x85\xb61\xcf#3t\x90c\xcc\xb9\xafa\xd88\x1d?\x85Xk\xc4\x9b\xea\x80L\xf9\xb0;\xd5[\xc5\x7f^\xfb\xb3\x99\xc2G\xf65\x8f?\x91\xe0\x0bu>8\xfb\xa48FM|J\xdb*\xa01\x8d`\xcaq\xac\xf7\xf7\xbf\x9f\x9c<\x7f\xfd\xfa\xe3\x87\xc7O^\x1d\x9d\x1c\x1f}89\xf9\xfb\xdf{mG\x90\x05\x7f\xbb\xf0P\x1aM:\x11\x81X\xaa5\xb1f\xb5&\x05\x05U([j\x88\xb1\x1c\x9c<4\xa5w<\xae\xf0|\xc1V\"|\xba\x04\xa3\x9f\"b\xd6\xbd\x17\xebJ\xae\x85#\x08\xa3\xcaf\xdf(_G\xd5\xb4\x88\xc8\xea]\xad)\xf3M\xc2}\xee\xa4Kc\xcc;\x10\x8c\xf9xg40\x99j,\xed\xce\xbf@\xa5u!TZg\xb4\xd2d]\xfc\xbfM\x93u\xe6\x86_\xa9\xee3\x14X\xd4\x7f-\xe8pJ\x95\x03\xddBSj-*\xa5\xd6\xa2\xae`R?\xeb\x0f$k\xb0\xa0\xba\xcej\xe1\xa3\xf0Y\xb8\x14>\x8b.\x85\xcf\x82\xaa}\x08\x038\xa7\xf2\x06\xdf\x8a\x88\x92\x11\xb0`N9q\n#\x98\xdf\x9cFh\xfe\x97h\x84\xe67\xa9\x11\x92\xfe\xf7.\xc5\xd0\x9cV~\xfa\x82r\x9f\x19(\xf7\x8aFp\xca\xf7\xc9\xdc\x83\x16\x9flJ\xd8N\xffC\x84\xed\xc2 \xcd\x95 l+>\xde\x13\x1a<\xf7/\xbby\xf4\x05\x84\xed\xad l\x97\x1aa\xe3\xb7\xfaKZ\xcc\x92){\x9c\xa6\xbe\xd1\xfc\x97\xde\x8a\xee\xa7nE\xf7)\xad\x1clO\xf5\xbdvA\xe5\x0d\xb9\xd7Np\xaf\x1d\xd1\x08.8\xb5<\xba\xb9\xbdvt\x93\xbb\xe2\x98\xc5\xe3O0\xe4\x1bb\xd4\xde\x10G\xd7p\x05\xa9\x1b\xe3g$6\x14\xaaG\xbd\x15\xd1\x92r\x93\xf0\x81H\xbcNvv\x1e\x84\xf8\xbd\xf0\xaa\xb2\xef\x058\x04\x99\x84\xc6\x14\xf7W\x1b\xf9\x82\x90O\x1b\x01\x88\x8f\xba2\x1c\xf2_\x86\xec\x1d\xad^\x96\xc5\xac\xab\x97J\xdbP\xae\xaf\x9f\xd6\xa1\xd4\xf4\x95\xce$\xb8\xfb\xb7[\xedD\x1a\x03\xcc\x07\x1e!0\x9bo\xc1\x0e\xecq\x88?\x12j\xc3\x9d\x9d\x10?\xb3\xf1\x05\x98Y\xa5lcH-\xb9\x0f\xf9\x825\xd7\x82_\x86D\xcbu|\xb4\x04S\x96\x9c6\xae\x87\x16o\xd5\xac\x18*\xef\xd6\xcb\x9f3\xe9\xda\xff\x98\x9a\xc5\x93\xd6\xe2=\xe6\xa4\xc8C0\x91\xead\xb4u\x05$\x0c\x05G\xe4^\xbf*\x07I\x87\xd4\x82\x0c\xb8\x19\xba\x1d\x9b\xaa\xe4\xed\xcb\xf0\xa0\x0d84&\xb2\xe4\xd9P\x00*4pT\xa7\x10\xeb\xdfN\x9d\x0f-2\x8aw\xca\xc0X\xdb\xfa\xb3\xc6\xfa\xd3\xeb\xae\x7f\xdb\xfd\xba\xb5\xfeYge*\x1de\x8b4\x19\x93`\xcf\xdd\xa6<\xa66i\x97\xa3\xa1\xa7:\xca\xd4\x95\x0f\x067\xbb3\x9d\xa2\x8d\xd67\x9fF\xb6\xb8\xce,6\xb12}i|\xb6D\xa9\x06\x06m\x82W\x9c\x15q\x83\x8d#\x89\xcf\x91\xc9\x89\xca[\xe9\xe8Q\x0e\xd6\xc7\x15\x8cbq\x11\xa2\x7fe\xd6p\x7f\x08jM\xd7-TeG\x17\xa49\xfa*M\x8f5\xc6\xaf<\x99\xf2\xda\xc9\x84e\xce\xb2:\xc9\xe2\x07\xcd\x83\x10\xeff\xee\xd3\xdd\xbd\x88yc\x11\xb3k\xad\xdfcj\xaa0\xddX\xc3\xcd\xd4V\xa5.\xa9\xad\xb9\xaa\x10\x94\xe3\xeacZMH\x9f\xcc\x86a\xc8\xfa\xcc\xf6,z\xa8\xa3kkAe\xdc\x81\xbe$\xd5\xd1\xa2y~\xb9\x90\x82\x8a=\x977\x10!\xaf%\x13\xccU0\x08\xd5\x92 \xe27y\x07\x13\xe85Y?\x1d\xa9\xd7l3\xb3\x0e\xb1\x9a\xa9\xf1\xec\xcb\xfdNn\xcf\xc8\x84N\xaf\x7f\xc5O\xe4]\xf1\x03\xb2\xdf\n\xd0\x91\xf0\xec\x17\xcb`Q\xd1\x98g(Z\xead\x1e\xba\xb2\xf393\xf3\xf9D\x05\x1c\xa1\xd6\x15\x85\x9a\x01\\\x1a\xa4\xf7c\x1a\xc1S\x93\xde\xf5\xc3\xe3\xa7/-\x9a\xd7O\xfc\xfd#\x0fi\xffq\xe9\xae\xd7\x91?\xb4.\xf3\x7frf\x94\xa9\x98\xe1L\xe7\x84\xb3\xa6\xa3^V\xd1\xbf\\\xfc\xaaS\x07\xbf\x94\x81o\x9d\xa7\xee\xb1\xd0\x03\x1cs\x80<\xa6A\xcb=\xc5\xd2\xe8\xbbnq\xb1D{\xabYR;\x9c\x86\xa8\xa3cCjH\x84k\x85\xa4\x9e\xbe\x8bU\xbc1\x0d#\xa8\\&\xb5\xd0\x88\xe3\xd5\xfc4K\xb1B\x82\xeby\xb3\xadf}|\xfd\xd7':|Z\xaa\x17?\xf9h\x03?\xb9\xb4\x81\x9f\xba\xb4\x81\xbc\x0b\xdd\xb6\xf6D\xb7\xb5E@\xfb\xcf+\x02\xf91\xe2\xcbDM\xe9\xbfdJl\x8f4_\xafH\xe0bE@.8\x91\xb9qE\xa6\xed\xeah_\xaf\x8d6zh0\x06U\xbe\x07\x8b\xe9\xcdi\xdaV\xd8c\xa61\xad\x15\xc4\xbbm\x9a\xc0\xb2\xe7tB.\xc9\xe4\x98|\xf6\x00\x8cF\xe2\xdf\xcb\xa8s\xbf^^\x1c\xfb\xb7\x8e\xc01\xa6\xc2\xf6\xd1\xccc\x82\xdf\x9e\xfa\xa4\x07\x9c\x85Y-H6\xc5\xfc\xda/\x8eQ\xe7\xc8\xff\x10\x16\x1e\x0b\xf8P\xbb\xc4\xdf\xf1\x9d\xde\xdb7\xff-\x13|\xfb\xa6\x9c\xe2\xdb779\xc9\x97du\x0dAC\xf8\x13\xd8\xfa\xa4\x93F\x8f\x1eU\xa3\x10\x98\xfcS\xcc\x89\x1aX\xcc\x1b\xa0\xebI\x0f1\xa1\x89\xb9<\xb8aXB+\xb4\x19,j\xc8\x125W\x9c\xa1\x84\x8ay\xbbYh.Sc\x18\x08\xe7@|6o\xa3oRZR\x04=\x84C\xe8aE\x028\x80^\xd4\xb3c2\x83\x01\xf4\x0czTu} \xa6\xbbp\x9c\xcaR\xfd[{\xe8\xb2\xba-,%\xfc_t3\xdaR%\xa4\xb4I\xe1\x9a\x96^4x\xe6\xf4\xda\x9c%\xc8\x1d\xe0\xc5\xb7}\"\xab/ ?\xcf\xbdVt^\x93C=\xd0\xaa\xdcb\xf5\x94\x9d^\x9d\x89\xb3t\xc3\x0d\x16A\xe6\\\xe0\x06\xae\xb5\x1cT\x1e\xc2>\xe6G\xe4\x98\x02\x07b\xc3\xb6\xb6\x83\xae\x06\xc0\x9a\xb5\x0e\xe4\xc8\xe0\x10\x82LR9l.\x94\xed\x92\xb2\xf4\xad\xa8\x18\x988\x0b2\xe7\xfe {\x9f\x9c\xcd\xd8\x86pS\x84Ig\x84*C\x94\x9b>I\xaeG\x9a\xdes\xab\xdd\x1dl\x83\xc6^\xfcq\xb7D*=\x19\xaeWWh\\\xbe&\x06?\xb9\xde!\xc1\xb9\x91\xcdz\x14yYD\xac\xdc\x1b\x8a\xa5\xc2LY0L]\xe5^5&\x9a3\xb3\x06\xe4\x80\xb9\x1f\x94\xba\xbf\x80\xd6\xfc\xee\xd5\xcb\xe9\x92\xbd\x8a7Q\x0f\x88}\x8d\x1e2\xbb\x11\xec\xecy\xf5\x92\x14G\xf3\x05\xf3\xb11\xc8^4\"\xae\xcb\xe9M\xc9\xfd@.c\x9d\x19\xf5\xe0EmFH\xaf\xd9\x8c\xb3%m\xee\xfc\x8e\xf9<\x0dH\xa5J\x12\xdb^\n\xb0\xe2\xe3\x0d\xf4*\xd8\xfb\x13_\xf6T\xf6\xefK\xa5@\xa3T\x1fI\x10V\x06)W\x06<%\xe5\x98\x88w\x17\xeb\x8a\xdf\xcb\xbc AU\xa7\\T\x12\xe7\xbbR\xcfy\xec%\xb5i2\x97\x99\xddU\x97\xa3\x94\n\x9e\x05\xba\xb9\xcdR!\xefJ?o}V\x8f|^\xc6\xe9&\xc2\xd69)\xc9\x86W\xfb2k\xa6\xc7V\xd3\x1dN\xcdk\x8b\x81Z\xfd\x13L\x97W+\xceDHu\xdf\xcd)\xd6\xab\xb7\xfeN\xc3\x86\xaa\xd5\xcd'\xd6\xaa\x1at\xf9\x8e5>&\xc6<\xa0\xea\xba\xf2\xe4\xf7\xc4.}\x93m\xb8\xdf\xa5\xf8\x81;|\xa3\xd3\xa5\x14Y6\xe7,,\xd5\";xn\xea']V\xc2%m\n\x97\xbc\xefa\x16\x01\x1d9\x05L/\xd6\x8aO\xff%\xf1%n5o\xf4M\x84=T\x8dQc\xa9]\xf3\x98\x1agd\xc7\x8a\xe8 7\xb3z8\xda\xb2\x99MF\xb1!rx\x0e\xa5\x02\xdc\xa6\xe3\xf1_-\xcf\xa1\xbc$r\x05\xfdF\x91o\xcc\xbc \xe8\x1f\xfb5\x9f\xc6\xec\xf5\xb5\xa51\xdf5\x02m\x13\xffb\xae\x93\xa4\xae&m\xabk\xea\xbb6\xb2\xd6Bn8k]\xc7\xa1\xae\x895o\xf1\x8d%O\xd9\xe2\x06ga \xd9\x1f5)\xc1WD\xd0\x8f\x12\x7f\x8c\xe1\xa7\xdd\xab\x0d\xcc\x90\xf5\x82y\x1e\xd8R\xa1\xa4.\xef\xfa\x14\x1f\x9fa]m\x9b>5\xaa\xfcd}\x07\xfe\x9cz\x0e\xddTnZ\xf8\x03c\xa1MUa:\xabU\x98\xee\xcc\xb6\x9c`\\\x90GV\xe4\x00}\x1a\xb1Z:\xc6-\xa9\xa4\xc4I\x04+\xceJ\xafB\x14\x13V\x95\xbf\xa7\x19D\xaee\xf1:\xad\xce\xf2l\xb9\xf8w\xb0\xe2~6\xbc@f\xbb{\xc7P\xd5\xc5\xf9wO\x06\xde\xc8\xb9w\xe9\\\xf8\x95\xb59w\xfe\x99\xe0\xdc\xbb\xf7\xb5~I\xf0\x04\"\x04r\xbd\x86\xe1(\xc4\x18\x06\xccY>\x8c#HFp\x00\x89\x87q\xd0A\xc7\xec0P(\xe8G\x81\xb3:\xe5\xed4?U\x14\x8cD\x90\x04&\x12\xa9.\xcb\xf87\x165f\xf1&r\x06\xd2!\x99py%b\x08V\x9e\xbd<\xdf\x84\x86\xab~\x9e\xd3M{J\x8a\xe3\xe5\xa9g\x81\xcfR\x06\x1c\xd8|\xc2\xcaJ)\xc2\xea,y\xf4J'\xe4\xb7\xb4\xe5y\\&\xc6\xd9 \x9f\x96y\x8a\x0b\xce\x0bm2\xc9\xc05K 3m\x96ay\xd3\xffT\xfbDVo\xa7\x1b\x0c\xa9<\xd483\xb7\x11$o\xc0H(\"\xce\xfd\x8f\xf8\x9aV\x86\xef\xea\xe7-)\xd5\xa7\xdbts5Z\xab\xe4W\x1f\xf9Y\xff\xfe^^g],\xbc7\xae\xb11\x97U\xbb\xefy|\xb9A\xaf/\xd8F*\x8cy|\xb9\xe9\x99\xfa\xa2\x96\x8f\xc8\xab\x13?\xa3Yk\x06p\x08\xef\xa9pa\xf9\xe8'(\xcd\x13z\xfd\xe9\x88\xee\x98\xe8\xcewn9\xd9\x18\x13\x8d!\x8f`n\xbe\xf8\x94,6\x80\x9d\xd6\xfe\xeb\x98\xcd\xfa\xf3\xf82\xb0T$\xb6t\xd6\x14\xbe}\xa5\x04\xcb\x1e\xe3M\x06D\xbb\xe3=\x90\x9fgI\xba\xa1\x99\xa1\x1c\xccO\xd74l|J\x16\x1f)K\xd2\xcd\xba\x15@WC\xdeL\x05%\x12\x82m\xd6_\xdb\xcaa\xc8\x0c\x06\xe6\xfeX\xfc\x89l\xb0\xbc\xacf\x80\xb8\x06J\xf1\xfen\x18\xa5x\x93\x9b\xa3\x14\xff\xeaKP\xea:\x92\xc4?\xbc\xb8[\xad\x84\xd1G\x8aj\xdeZ\xf26\x8c\xac\xec`x\x15;\xcd\xac\xdaeuq\x91.\xab\xc7\xe6i\x05Zja \xd8\xb1\xbb\xb5sY\xcf\xbf\xa3\xec\x7f\xc9\xb8\x19\x04\x1f\x82*\x91e\xd7\x0c\xb5f*\xe9\xa7\xfc\xf6\xd6-\xd8\xde\x8eQH\x95\x0dZ\n\x95\xab\xeb*\x8c \xb6\xbeq\x15\x81^\x06\xe9\xbfhU\xb2|\x93e!5o,\xfe\x9d[\xae\xe5\xd7\xd2\xe1Q\xa2.9N\xcf(K\xfdB\xdf\xa9e9\xd3\xee\x0f\xc0?\xe2Q\xbf\x9c\xd1\x8f\xfae\x89\x95\xd0/e\xba\x89;\x8bS\xa9K\xe8\xf0kE\xaa<\x1c\x1aUD\xa3\xac\xdf\xeb7\xd1B:\xab\xfa\xbd\x9d\xe2\xdb{\x1d\xae\xad`\xdaki\x04\x05j<\x0f9i\x1b\x0c\xe0\x8d\x14s>s\x8c,\xf0\x05\x91\xe6o)=C\xfe\x0b\x16\xb7\x8b\x088)\x80\xf1\xe1\xe6\x9aW~\xf0\\\x97\xa9(\x0f\xad\xcd\x98\n\x15C\xb0!_\xba\xb9\x186\x8b\x8b\xd9\xd3l\xb2\x81\xa3\x0b\x9bU\xd9\x05\xb0\x8a\xf3L\xcf6\xd0\xcd#@\xb9\xbd\x84\x83\xf2`\x00{p\x1bv\xcb\x8d\xe6 ]\xcaL:\xeeT\xf0\xf9\xb9\xf2\xa36\x16\x0ea\xcf\\\xf5\xb6|M\x0c\xcck\xf1\x1b\xdf\xf0\xd1^\xa2\x90~\xe7\xee\x9d\xfd\xef\xf6\xbe\xbds\xefN\x18\x95\xb7\xe1\xe1C\xd8\xbb\x07k`\xf0\xe8\xd1#\xd8\xd9\xbb\x17\xc1\xdd\xfb{\xdf\xde\xbd\xf7\xdd\xee7\xcd\xf7\xeeh\xef\xdd\x89\xe0^\xf5\x1c\xd3\xb9\x07\x0c\xb6\xe1\xce\xb7\xf7\xef\xee\x7f\xb7\xbf\xf7\xdd}Xs\x98\xfe\x8bo\xe9\x7f\xc9\xcf\xf6\xeeG\xb0\xbf\x7f\xf7\xfe\xb7\xfb\xfb\xf7\xca\xe6\x8f\xe5\xe7\xd8M\xf9\xe6\x9d\x08\xee\xec\xdf\xbf\x7f\xf7\xdb\xef\xbe\xdb\xfd.\xd4\x9bpl\xb9@\xe7\x0f(\xd6\xba<\xdc\x10j0\x80;{\xf05\xe4\xb0\x0d\x9fi\xf0\x94\xe0\xa6yJ\x02\x16\x86|F\xf6\xce\xc1sw\xaaKh\xc5\xaf\xd1K}R>\xdd\x943\xc2\x8e:;\xd8\xacq\xcfvCc9k( \xa2\x89\x14\xd6\xee4\x95\xc1|/~\x10\xc9\xc9\xb4\\\x00\xfa\x1b\x1f\xe8p\xaa\x02\xbc?\xd0\xe1+\xfe\xf7\x07i\xb2(\xf8-\x19:*n\xcb\xc0\xea\xf2\xbe\x1e8\x04\x03xF\xf1IB\x8b\x85\xc8\x8d\x8f\x9f\x1cg\xcb\xbc\x9eW\xc6\x04\xb2\x86\x12I\xba\xb7\xd6g\x87\xad\x8fgqBE\xdb\xd2\x96)ng\x94\xc5 F\xa5\xe3\x10\x84\xee\x12c\xc4s\xd3)9M\x93\x0dB#K\x01\xe5#\xb3\xae\x84I\xed\xb38j\xb9\xf7\xfbZ\xff\xedT1\xb7\xcb\x02N\xe1n#\xc3j)M('\x89a\x12A6\xb2\x17\x9f\x06\x10FU\xcd&\xe9)4\xce\xe3\xc5\xcb\xba\x0f\xb2/\x8c\xae\x01\x04\xbe\xeeMXt\x89\x19-X\x88h\x04\x07\x10\xb0\x93\xeb\xec\xd6\xd7\x14\x93\x9btf\xeexn\x07\x92\xdaI\xf5\xbe,\xed\xfc\xde\xd9\xce\x90E@F^\x8d\xbd\xb1\x90\xc3\xe6\xd9\xdc\xb1\xd9\xb6\x88O2.h\xc3\xd32\xac\xf773\xac\x9d\x1b\x1e\xd63\xf7\xb0z\x05\xd2\xc0\x9a\xf1\x03\x0e\xe1\xc5\xf1\xdb7}\xf1(\x99\xae\x84\xdaVRK\xcf\xdc\xa2\xaf\x9c\x04\xf8\xd8\x9a\xc9\xd3\xd2\xdc\xc7N\x0c\"\xf0\xb0\xe4\xe0\x08<\xc2\xbfw\x90\x9d\xf3\xea\xe0\xb3G\x07\x9c\xf5\xd9\x86\xfd\xfb\xf7\xee\xde\xbds\xef\x9b\xfb\xdf\xc16\x04\x843d\xf7C\xf1\xe7\xa3G\xb0\xdf>}\xeb\x0b%[{M\x87\x0bu$\xbe\xae\x8eD\x19\xa8\xc5\xef5\xceD\x91^\xa0|\xd08\x14;\x89\x9a\xec\xb6\xb1\xb0\x0c\xa3o\x0f0\xfc\x161\xa5>p<\xd82s\xf2\x93/M\xdf\xe0\xa73\xbf\xd1\xc0\xa9=\xbf\x93b\x9a\xd0 JO\x9e\xdd~\x817\xdd!:\xd3\xc1\x01\xec\xb4\xfd\xffLfN>*?\xc3\xd5\xb9\x9e>S\x99\xa8\x9c\xa3\xd1\xd2\x0c\x97{\xc7\xcb\xd53\x8d\x0b\xf6\xfc\x9a#+\x8dq\x7f\xd9\xe8n\"~\xc3\x13qn2~\xc3\xb7\xcb\xc5\x06}*Dm\x86\x15\xd9\x9d\x98\xf9:U\x96\x02.u\x8a\xa0Z\xb1\x10\x98\xf6j_\xfe\x89\x15\x8c;\xb23\xf2\x8b\xa8\xec\x8c\x9c`\xef*\xe7~t\xce\xafRDt\x04\x85VI\x15\x959\xa3\x03{J0\xef\xc9\xd1\x1eB\x0e\x07\x90\xab\xd0\xfdc=\x02x_94\x88\xd61\xc7\x81gP\xb0r\xee\xfc\"\xf2Qz\xab\xfe\x15$\xe4:\x8e\x9f\xa2\x9a\xbdW\xeb7\xe4\x9a\xe8\x89\xfd\x1b;\x0d6\xd2k\x87\x88\x82\xaa\x14]]\x0b\xa5e^\xafG\xd3\xdc\xba%\xf8\x8b\x99\x96dU\xe1\xed\xb5\xfc\x11EUmKV\xa5M\xdd\x117s^j\xc1\xe3\xd1\x00v1\x07\x85%\x90\xc8\x02(d\xbefUt\xd1\xce^\xf5\xa5<\xb4Z\xd5\x14\xc1v\xc61\x92/\xb2b\x13\xd3\xe6\xf5\x93|\xf8\x99\xf5\xaa\x12\x03%\n\xec\xc3\xd7\xea\xd7\x0e\xec\x89\x02\x03\x0e\xcb\x9f-\xf5\xa1~)\xa3\x01s\xca\xe5\xeaJ\xbe\xd8V\xd79 \xad\x8d`+\xc1R\x00b]Eh)\x17\xd1\xb30\xd4\x92\x96b\xb3\xf2\xbe\xb3\xe5+\xde{\xe4\xca\xa3\xa1C\xd4l\xb6\xf3\x06i\x84\xb0\xaa\x19\xd0~\xc7\xfe;'\xefo\x0f\xbd\x86\xfd\xac\x84l\xc6!\x1b\xc3\xff\xe5\xb2\x03\xdfz\x1c\x07\x92\x9a\x0b0\xc6\xfc\x1e\x88w\xe0\x10>\xf3\xb9\xc7\"\x1d)Zm\xd4\xcfL\xa5\x8c\xed\x02\xbf\xd3ZbIU^Q \xefm\x9c\x92\xf8\xdc\x87\xf3Rf\xb9!\xefbd8\x94C\xc7bq\x1e\xe5\xa5 \x00J\xff\x12\xc1\xcb~6EgZ\xebg\"?\x89\xe6\x9d\xef}\\\xc3\xbf\x8e\x1f\xf8\x9e\x11\xaa7\xed\xde\xe3y\xf2\xffq-\xbd\xeaK\xf5\xc7+\x1a\xb9\x90\xcd{\x0c?'l\xe6sN)\x99G\xef\xc5\x8do\x9c\xa7S\x01\x02\xed\xf1\xdbL\x96\xb5;W!\xa7\x08Uz\xd8\x89\xd27\xe87\xcb\xba-\xef\xd0q\xbd=\xfc\x8dy,\xc4 Q\x0bZ\x9a\x95\xbd\xe4\xb4\xeb\xe6\xd31T\x9d\x86\x9b\xd9l\xd8|\x95\xc3\xcd\x03\xda\x89\x96g[\x94\xd0\xaeY \xf4\xc7\x9a%A\xbf]3)\xfc\x1a\xe9J\xda\x10\xef\xbd\xac-\x9f\xb8\xf7C\xadiq\xef\x84\x18>\xbe \x86\xaf\x8fH\xf3\xf36TT~\xb9\x03\xa0m\xb8\"P_\xb4\xef?\xcd\xd2\x94 \xa4\x0f\xe0\xd4\xe0\x03\x81\x01b\x1f\x0d\x0f\xf4\xb4\x92\xefX\xfb\xb9\xc8\xcb\xb70<\x91\xa9\x02\x8f\x8c\xa3d\x07P\x18\x1e\xe8Y%\xe7\x86\xe7\xef\xc98\xcb'\x07\x90\x9b\x9e\xc5\xf4\x8c\x1c\xc0\xca0\x89\xf7dAb\xde\xa4\xe1YR\x1c\xc0\xccp\x7f\x9agsLmkK\x97|\x15\x01\xe9\x93\xcbE\x96\xb3\x02\x93\xc4 \xac\xbcr\xfb\xb4\xf5\x96\x05\x81\x82\xe5\xc9\x98i\xf9i\x94 ]\xdbn\x9a\x0f\x8d\xdeQ\xb3u\x15\xfb\x16G\xb0\x8c\xa0hn$L\xc6\x1e\xb00\x82-\xe3\x1e\xe6]\xa7m\xfa\xa7\xa5\x01C=OX&L;\xca\xf3,\x0fz\xaf\x13\x9aL\x132\x01r9&\x0b> \xc8\xc6\xe3e\x9e\x93\xc9\x03\xe0\x93d3\x024\xa3;s\xf5\xe2\x84\x9c\x03\xa1\xe7I\x9eQNu1\x02\x8b\xbf4]\xa6)\x10\xde*\xccIQ\xc4g\x04b:\x81x2Ix\xb3q\n3\x92.\xa6\xcb\x14.\xe2\x9c&\xf4\xac\xe8\xf7\x0c\x14\x9b\xa4\x05q\x90\xfc1\xe7i\x9a\xc0r\xf8\xf7L\xed\xfcfP\x07\x05\xeb\xe7d\x91\xc6c\x12\xdc\xfe\xbf\xc5\xed\xb3\xa8\x9b\xa8AE\xd8\xc6\xc3\xe9\xf6v;\x84\x17\x90\x8a\x85a\x9f\xc6s\x0c\x8dxN\xcf\xe3<\x89)\x83\x9f\x92,\xc5\xe4\xdb\x86\xfc\x92\xad;l\x96g\x17\x90\xf6\xa7y<'\xc5\x87\xec\x1dV\x91\xd9k\xa6b\xd3\xb0\xfa\xcb\x91\x98\x06w\xee\x86f\xdc\xcd\xaf\xdf\xba#K\xa2L~>!\xd3\x84\x12\x95\xfc\x9c\x8bE\xbd\x93\x13R\xbc\xce&\xcb\x94\xf4L\xa4T:I5\\\x9e0\x8f\x12\xe7\xbb\x9ef\xf3yF\x8f.\x19\xa1\x85\xcc\x7f\x8e\xf7\x1bwH1\x8e\x17XS\xf1UB?\xbd\x8b\xb1\xae\xa2J\x9d\xdf\xba]\xcc\xe24\xcd.\x8e>/\xe3TV#d\xfd\xd3e\x92N\xbe\xcf\xf2\xf9\xb3\x98\xc5\xe2\xb5,g$\x97OY&o\x92<\x89\xd3\xe4\x0frL\xe2|,\xda[\xc4y\xa1\xff>#\xec8\x9e/Rr<\x9e\x91\xb9\xf8\xee\xaf\x17\xc7o\xdf\x88\x9d\xd1\xe9\x01\xc6\xf2U\x07\xb3\x8c\xb6*D5\xab\x8eF\xe8\xa8o\xdd\x82^\x86\xbd\xf6D\x11\xb2\x86\xb1\xa0\xb7\xa4b\x9fNzp\x00\\\x82*\xf8\xc6\x8d\x97)\x0b\x03\x16\x86\x8ex\xd7+\x18\xc7l<\x03q8\xb6\x1e\xcb\xef\x1a\xd9\x1b\xae\xf8^\x16\x03J\xa6\xabNH\xc8F\x8e\x05\xc3|$\xf9f-\xa9<\x1c4\xfb\xc6\x1e\xe2<\x8fW\x1bt@d\xb3\xe8]\xa3\xff-\xeaI\n+\xefp\xd4\xeeH\xb0%\x92O\xd2z\x03b\x0eM\xe3\xabr\x84\x1eT\n\xae\xe6\xb3\x9eAB\x0b\x16\xd31\xc9\xa6\xb0RK\xd2\xe7[\xd2\xf5i /\xc6\x01U\xcf\x86\x8b\xb7\xd2\xb2)\xce\xb8\xcb\xb4\xbc$\xec\x8b\x8c\xce8\xdb\xea\x95\x8a\xd9\xac\xde4\xd5Nd\x98`\xf0Cv\xcc<\x0b\x05)\x15\xa3)\x87\xbb\xd2\xfd\xecF\xb0\xacP\x91\xb4\xb3\xf3v [\xe6\xf0\xc5!3$\xe80\x14\xbe\xeb*\xc6N\x879\x17\x0f\xc90\x1f\x89\xf4\x8at\x99\xa6fMt+\x13&\x82\x8cf\xf9\x1c\x0f\x0f\x81s\x03\xb8\x8c\x90N|O}\x91\xd6<\xc1vOIQ\xd2\x9dc\xd9\xc7\x92\x8eo\xbe\x175\x11\xaff\x9b\x99\x9a\x8dT\xe2u\xbc\xf0A'+\xca4\x93\xfa\xba\xf4\xa2\xf5ue\x01_Y\xa1\x8a5\xe5\xee\x84?\xdb\xa5\x84p\xc8\xef\xb1\xcb\x7f\xdb\xa8K\xc5x9^\xa7\xee$s\x1e\x08Y\xd7\x81 U\xda\xfcn\\\xdd\xa5\x18r\xb1\x01\x98\x8aU\xc1\xc8\xfc\xc3lI?\xbdN&\x93\x94\\\xc49\xf1E\x9c\xee\xfd\xcf\xfa\x93\xa4X\xf0\xb3I2\x8eH\x97\x9cp\xe9n\xd4\xf4\xb2\xd3\x82\x05\x1d[\x08\xcd\x93\x01 0\x959\x0b,\xbel`\x14#\xccw\x0d\xe7\xa0\\#\x0e\x80e\xf14\x9btC\xf9\xbcL\xb2\xa5\xaal[I4+55\xc1\x05?[.\xf8D\xfc\x93\xa8+\xe0\xec\xf7Ty\xd4m\xe8\xf5Bc\x06\xa5\x10\x19pK0\xf3\x95\\f~\x82\xf9l<\x8c\xce\xa9N9\xa5\xc0\xe1\xbc\xa7\xfc3\xd0\x8a)V/\x8a\x13\xb2\x0d\x0eu\x9a\x11\x99\x83\xc0p\xec2\xce>\xb0\x91\x1d\x96\xf5^\xfaI\x81\x9dQ\x91\xf8\xfe\xa05\x88\xf6\xfcg\xc9\xd9,M\xcef\xdd\xdc\xa5Z\xe1I6Fu\xab\x99\x01\xd9\xaa\xf8\x8c\x9e!s\xaf\x08N`\xe4\x92=\xcd(#\x94\xa94\xac\x8f\xe0\x1e\xb9S\xc5\x03\xe9\xafX'\xdf\x8d+\xb5\xec0\xba\xd2@\xa4\x83\xab\xfa\x88\x90\x0b\xdf\x8dP=\xb2\x1c\xee\x8e\"\xd44\xecE\xa8@ \xfd\x84R\x92\xff\xf8\xe1\xf5+\x91q\x18\x16\xa8V\x10r\xb2\xa8g\xbb\x80\x87\xf0\x0d\x92\xc9\xdf~\xc3\xfdJ\xa5\xe7\xdc\xd8\x99m\x86\x03\x84\xf7\x94\xaa\xae\xb7\xb7\x8b\x910\xafM+\xd8\xecE\xb05\x86\xf5\x1a\x16\xf0\x08\xbe\x15\xbd\x08\xaa\x80w\x87\xb7\x7f;\xbe\xddg\xa4`\xc18\x8c\xf8\xdb\xfc\x83\xdb\xc3\xaf~\xbb\x18i\xf7\x83\xdem9\xb2\xf5\xbal\x80\"iN\"\xf8[\xefo\xa0\xdcN\x92\x08z\x7f\xeb\xe9?\x97\xc3\x02v\xe0\xee\x08\xb6\xd1)\x9e\xf2g\xbd\x9d\x9d\xdf.\xefp\x99\xbc\xba\xf5\xf5\xed\xdeh\xb8\x18\xb9\x8de\xb8,SQ\x98\xa1\x1f/\x16\x84N\x9e\xce\x92t\x12\xc4\x9a\xc8}\x94\x12\x8efA\xafX\xc4\xb4\x17\x86\xfd\x82\xb0\xc7\x8c\xe5\xc9\xe9\x92\x91\xa0W\xb0\x15\xaa\x03\x86\xbdq\x96f\xf9\x01\xfc\x9f{\xf7\xee=\x80iF\xd9\xce\x05\x11 qO\xb3t\xf2\xa0\x17\xe1\x8a\xe1\x7f\xfa\xabxo4\\\xc0!\xae\xdd\x1d8\x84}8@\x08\xdf\x87C\xb8+\xff\xe6\xf7\xef\xc0\x01l\xdf\xfeW\x10\x07\xa7\x05\xcb\xe31[\xa7I\\\xac\xe9d\xadL\x0fk\xbeg\xd7E0_\x17$g\xe1\xe1z\xc9\xb2p}\x1a\xc4\x05Y\x93\xb3\x84\xae\xb3,\x0dHL\xc3\xc3uN\xe2O\xeb\x15#\xe1z\x8c\x8f\xf9\x81\xb3\x9e\xc5\xf9\x1aE\xdb\xc9:\x8d\x8bb\x9df\x94\xac\xb3\xf9\"]g\xb4`\xeb\x8c\xb2\x84.I\xb8\x9e\x90\xe0tyvF\xf2\xf58\x99\xc7\xe9z\x9c\xc69YO\x03\xbe\xc7\xd7$\x0f\x0f\xd7 M\xd8:\x0d\xc8Y\xcc\xc8\x9a0\x12\x1e\x86\xebI\xb6\x9ed\xcb\xd3\x94\xacI0\x9ee\xeb\xb48L\xa6\xeb\xb4 A2\x0d\x0f\xf9<\xb0\xf6\xe8\x9a.\xe7\xebsB\xd9\xfa2\x18\x93\x05[\x93\xf1z\x11\xa4\xc98a\xeb,g\xe1\x9a\x91\x80N\x8a5*M\xd69\x0d\xc3\x90w\x9d\xa6l\x96g\xcb\xb3\xd9:N\x0b\xb2Nh\x9c\x06\xe9\x8a\x0f\xe5\x92O'\x8b\xf9\xd7\x01\x89\xc73>\xfb\x84p\xb0e\xf3\xf5\x92\x8e\x03\xbe{\xf9\x00\xcf\xd2\xec4N\xd7g\x19\xcb\xd6g\xcb8\x9f\xac\x93`\xba\x9e/\x02\x81\x03\xc5Z\x1b\x04\x0d\x12\xb6F\x95~p\x92\xd11 \x0f\xd7i\xc2\xa1\xb5dk%\xfa\xacY@\xf2i<&k\x92\xd38\x0d\x0f\xc3\xc3u\x11\xae\xd3 \x9e\x9fN\xe25a\xebl\xfci\x9d\xd1\xb3p=\x0f\x92q\x9e! \\\xa3\x8ai-\xd4\x08\xe1\xfaM\xfcfM\x83xN\x8a\x05o)f\xc99Y\x93K\xb6&\x17\xeb$]gl\xbdL\xd3p\x9d\x05\xc8\x16\xad\x17\xc2\x10\xbe\xce\xd7K\xb6>'y\x9eLH\xb8^\x04\xf1\xf8S|F\xd6q\x1e\xcf\x8bu\x9e\x9c\xf3u\xc93F\xc6\x8cp@\xb0l\x9c\xa5\xeb\xe5i\x9a\x8c\xc3u\x1e\xc4 \xc7\x98 \x9ed4]\xf1\x85\x9b\xae\xcf\x92\x82\x91|\xbd 1[\x7f^&y5\xefb\xbc$k\xa1b[\xb3|\xb5\xe6T1\x0c\xd7Ep\xba\xe2\x8b\x1f\xa7d\xb2&\xe9t=\xcbr\xb6N\xce(\x99\xac\x93?\x10<1K\xc6kT\xe7\xacY\xbe\x1c\xb3\xf5\xf2\xb4\x18\xe7\xc9\x82\xad\x97\x0b\x92\xafWt<\xcb3\x9a\xfcA&\xeb\x8b\x84\x8dg!\x87\xe8|\x91\xf2\xc1\xcf\x08]\xcf\x92b=\xcb\xb3\x8b\xe2p\x9d\xc7\xb4H8\xd2\xe4K\xb2\xceW\xeb\xd5\x82\x041\xee\x8f \x99\xae\x93\xc9\x9a\xc6s\xb2\xce\xa6a\xb8^\x064\x18K4\x9f\x90i\xc0\xd9E\x8e'\x19]\xa7\xa4(\xd6\x85\x18#K\xd2p]\x90u\x91\xf0\x05:\x0f\xe2|\x9d\xe4l\x19\xa7\xeb,\x99\xacQm\xca\xd7\xe7\"\x18\xcf\xe2\xfc\x84\x89\x01\x91\x9c\xacgIJ\xd6 \x9b\x85\xeb\xcb,_\xaf\x12\x92N\xc2\xaf$\x01\x9cr~iw\x14r\x16T'9\x8a\xdc| \x97\xecM6!\xc14\x0cC\x91Al\xc1)\x94\xa0\xeb\x9cF\x1c\xf0\xf3c\xaa\x1d\x00{{\x0f`k\xb8\x17\xc1\xed\xe1o\xb7\xff\xbc\x1a\x06\xbf\xedl\x7f=x\xf8\xe8\xe0\xc1\xfa\xb7\xdf\xfa\xd1\xe1\xd6\xad\xbf\xff\xfft\xfa{{\xf8\xdb(\xac\xdfhPhI\xa0\xc7\xbc\xe3\x0cS\x93sR\xff\xb0\x07[x\xceH\x12=.\xa9\xf3\x98\x1fS\xdb\x90\xc26\x12\xe8m\xd8\x1b\x95\x7f\xee\x8f\x90 \xffvyg\xbc\xb5\xb3\xd3So\xf2{\xb7\xbf\xae\xff\xbc\xcdi\xe1\xff\x11-\x8e\x86;;\x8b\xd1\x03\x87\x07\xcf\x14\xb6\x070\xf6e.\x8d2\xda<^|\xc8\x1a|\x97M\xf5as\xb1\xe4\xc7b#\xc9~\xf9\xcapo\x04\x87\xf5\x9f\x07\xd0\xfbDV\x06\x96D)\x06\x0d\xed\xef[\xdb\xdf\xaf\xb7\xbf?\xaa1[\xaf\xe3\x85\x89\xe1k0\x90\xaf\xe3E?)\x84\x96\x04=\x81\x84\xf7\xc3\x06\x1cd\x9dc\xa4\xa2\x82\x0dE\x0b\x89\x89g\xe4\xfd\xd3*\xef\xfd^\xa5\x11\xea\xcfI~F\x02\x93\x14x.\xa3\xe5\xbbG\xc3\xdf\xe4\x8c\x155V\x07\xe2O\x0bK\xf4\xbc2\xecl\xed\x99\x9fM-:]p*=K\xe6o\x11\xc1\x04\x06(~&\x9a\x96RE\x06\x04!\xa6 \xe4\x83\x0b\xf8\xb6\x9e\xd4\x1c\x85\xc2\x07r\xd8..\x8e\xf72\xe3\x14\xc3'8\xfd\\\x8e%\xab\xc62C\x17Y\xe7Ws\x0e\x83\xceP\xf63|k\xaf\xe3\xad\x15\xe7i\x83\xb3\x08h\x99m'\x82\x9c3X\xc12\x82yS\x0d\xad_mTPB\xc7\x8a\x0b\x1d\xb1r\xfe\xc0\xec\x87\xb1H\x9a\xb72s\x83\x06b\xa1\xab\x86\x8d\xdf\x8c\xa5k\x05r\xe5\x86\xef\xa7\x9c\xfbHm\x18a\xc7\x15~ma \xdeI_n\n\xedo[\xe2\xe6\x8e\xee@\xf1\xf7\xa14\xe0M}\xe1\xd0\xba#\xc7\x14\xb7I)\xb9D\x8e\xf4\xfb$%o\xe29\xf9>\xcf\xe6R\xa6y\x96\x14\x8b\xac@\xe3\xeb\x8f$\x9ex\x94\x95W\"\xde\xedi\x92\x12~l\x0fz\xc1\xf0_\x0fF_\x87\x0f\x0e{\xb7\x93>\xb9$c\xa3\xe1\x00\xcb\x9e\x08\xdb\x00g\xea\xebm\x94MT-\xd8\x88\x93\xaa\x9e\x82\xcdh\xb2\xa1F\xaa\x8c\xf9\x19\x94\x12n\x99\xa6m\x08-\xe2b\x1c\xa7O\xe3\x82\xc0\x00\x9e\xd6\xef|/\x07\xd9 \x1a\xd9\xc3\xd3\x80Tf\xe2\xdf\xfa\xc3\x7f\xf5o\x8f\xbe\xfe\xea6\x17%B\x93\xc6*\xa6 K\xfe \x1f\xf3\xb4\xb3\x07\x0e\x802vlK\x8b\x1d\xe3\xc2\x9a\xd0u\xb8ekM18\xd6{\x0e\x8dG\xf0\x19a\x8f\xc7\x9c\xcb\xe7\xd8\x92gi\x9a\xd0\xb3\xf7\xa4Xd\xb4\xe8\x86F\xe3$\xab\x14\xfe\xfd\xa4\xd0\xb4\xff\x9a:\x84/\x8dMcP?\xf6\xccoV\xfa\xa5\xbaCx\x97Wry\xc2\x15,\xceY\xf1s\xc2fAo\xbfW\xea#u\x15*:\xe9\xf5\xc6b\xf7\xf4\xf04\xfd\xf3*\xac\xb0\xd0V\xa8\xc1LlK\xd5N\xd0\x93]\x88&\x8dv\x12K\x1b|\xcb\x06\xd40.s#a\xa9|\x93\xa6.5v\xa1\x0d2CVA\x887\x9b\xb7\xf1dB\xc8\"]\x1d\xb3\x8e\xbaLmJ\xf3\xdeP\x86\xffye\x0eLi\xe0hf09\xd9\x15\xdaU\x1cQ\x1edC6\xc2\xbdr\x08\x13\x92\x12F\x80\xdf\xe1B\x0d\xff\x87\xf3\x03\xe2\x0dj\xcce`\xcaV\xabl\x03\x06\xb2\xa7\xa2!\xbd\x08\x89)`\xd6\x95\x19HV We=\x95Y\xd7r\xa6X\xad\x16\xa4k\xc1\x89\xb0Z\x94\x87\x12 \x1d\x0c\x84F|s\xad\x89\x08\x84}o\xdf\x00R\xc5\xect\x19$\xcdQ\xc2\xe0\xe2\x13\x88#\x15\x03\xebS\xf4\xbd\xf8\x90\x95\xfe\x1c\x1ek$\xbe\xb1\xac\x91\xd6\x9b\x15M\x1a\xa6\xbf\xfa{\xe7\xb2\x92\xe7I@\x83oL>\x12ctH\xba\xf7\xcd\x9e\xe1\xd9T~x\xef\x1b\xa3{\xc5B\xb9f|\xbbkz<)\x1f\xdf5=\x9e\x95\x8f\x8d\xe3:\x97\x8f\xef\xdf36>W.%\xbb\xf7L\x8f\xcfpV{\xdf\x99x\xff\x95\xfc\xf4\x8eqR\xa7\nX\xfbw8\xe2\xd7\x9e\x97\x04\xfa\xa4\xc3w\xe1\xd6-\x0c\xe1P\xbeU\xd2\xb5\xd8\x8c\x8b\x12\xa5M\xa5\xea\x9bQ\xf3\xfa/\xbe\xb0\x170\x80\xf2\x08lO\xe5\xc8\xe0\xc0\xd3\xad\xd9o\xc9\xc8fsL{\xb06`]ndv\xae\n\x047&on\xfc\xd8\xd9\xf8\xd6\x16q\xdaW}(\x95c\x0dtO\xa9\x89\xfa\xc8\x06\x86\xa7\xce\x91\xf2~\x17U\xbf\xfc\xe7\xd4\x7f\x18u\x07\xaeN\x16\xce\xa1\xf8\xd9\x8c\x8b\x18Z\xc4a\x0b\x8br\xc7\xda\xf8\x9dz\xe3wD\xe3NN\xbcn\xa2\x97} \xefQ\x7f\xc8\xca\x87\xeb5 `\xcfk\xc7\x88\x0e-\xab\xfd\x18\x9d\x84\xab\xfc\xdf\xb4b\xbfM\x9a\x15\xd0\xfd\x00\x86\xd4\x92\xf6\xces\xa3\xc1!h\x02AR\x04\x182\xc5Q\xd5\xcaq\xf9\xa05\n?\xb6\x06|\xfc\x0e\xf0\x08'\xf8i\xd6&\x06\x82{k\xd4l\xeb*`\xb3\xc5{\x99k\xc3\x1cR\xceY\x0d\xa9\xc1\xeau\xd5\xdc\x12\xeds\xef\x93\xc5\xe1\xb1s\x7f\x80\xb2\xa7\xc2#\xa8\xc2\xc4{?\xc5\xe9\x92\xc0|Y08%\x90\x92\xa2\x006\x8b)\xc8\x96\xbd\xca\xd9?\xb68fn0\xa6\x87\xf61\x9d\xa1\xc2=\x97\xc3\x12\x8d{\x0d\xeb\xad\xd9\x85\xb4\xfb\xb4@9\xf3\xf6\xbfv\x0e\x7f\x9bl\x07\xbf\xf5\xf9?\xe1\xa1\xb2\x0chRjc\xa01H\xb6\xc7gp\xef,>\xaf\x9b\x8d\xcecP\x14#\x01\xcf<\x87\xf5\xc1\xe4\x9b\xeb7&<\x95\xb6\x02\xe2\xf0)\xb4Cn\x9a\xa4\xc4k\x80\xaf-\x0e\xc5~c\xec\xb1|Iz\xb2n0?D\xa7qZ\xe87\xb6v\xb5\xbf\xf7\x14#o\x1b\xf5\xa9\xe8\xdek\xe0\xcf\xcd\xce\xd1~\xe3\x16\x835\xa8{\xecc\x93/\xfb\x0c\xedw\x9b3\xb7\xdf\xe0\x92\xe2M\xfc&\xe0\x9f\x95\xce\xc2\x8e\x95V\xcd{\x8d\xec\x8d\xc9\xef\xdcoTJ\xd8S\xa2F\x9fe\xaf\xb2\x0b\x92?\x8d\x0b\x12\x84\x11l\xdd\xfe\xd7\xf0\xcf`t8\xdc\xdd\xf9.\xde\x99\x8e\xfe\xfc\xf6j\xa7\xfc\xfb\xae\xc7\xdf{\xfbW\xc3\xf0j\xe4E\x18\xf8\xc8\xbd&\xfc\xde\xea~\xefOL+\xde\xc4\x8f\xce\x8b.\xbc\x86\xf7\xcc\x1a3\xb0\xf9\xf06 \xf9\x1b\x8c\xf0\x95%\xd2\xc1{|[\x94\\\xc0{rvt\x89\xfe\xc8\xae\xa5\x9dfi\x9a]\xc0Bv\xd2\x83m\x93\x03{\xfd\x0co\xc7et\x8e\xec\xba\x9c\xed\xad[\xb5\xdfv\xae\xd6\xc6\xf1\"\xab\x87\x94\xe74\x9b\xac\xa4RY\xa8\x17\x13\xda\x13N\xf2\xf8\x0b\xcdX'\x97\xf3\xb4\x87\xee\xf2\xda\xcd\x9eEU\x99T\xea\xce\x9c\xa0\x9b\xc2\xc4\xf6j\x0c\xc2;J\xbe^`\x84\x8b\xe8\xc8\xa2\"\x8e\xcb\xd5\xca\xedv\xc7X47\x97|\x8e\xa5\xf3\xb1\xf6\xa6d=,oN\xab79q\xb6\xbd\xb6\xa8^\x9bf\xf9\x8f\xe0,\x82\xd3\x08N\"\xb8\x88\xe0(\x82\xcb\x08\x8eG\x0d\xe1\xd59\xf6J\xdfd|\xc5V\x92\x0eYB\xe4\x9f\x9f\x86\xcd\xb9\xbf\x97\xb4\x1e\xa6 I'\x90\x14@3\x06\x8b<;O&x\x02\x98(\xb6j\xf4\xdc5X>\xf1\x8f0\x80WA\x16\xc1\xb9\xc3%\xe1#\x1a8\xc4x>\xfa\xba\x1a\x80\x1c\xc2\xa4\xda:\x93\xae\xd1|\x86\x01\xbc\xe7\xa3\x998F\xf3Y\x1b\xcd\xe7MG3\xeb\x1a\xc2\xf70\x80g|\x083\xc7\x10\xbe\xd7\x86\xf0\xfd\xa6CXV\x00q\x96\x1d\xe1\xa3\xf9\x03S]a\x91\x11\xfbh\xfe\xd0F\xf3\xc7\xa6\xa3\x19W\xa3\x19w\x8d\xe6 \x0c\xe01\x1f\xcd\xd81\x9a'\xdah\x9el:\x9a\xfa\x91\xd85\x9e\x9f\x1c^K\xeaB\xee&\xf8 5\xe41#;\x8c\xcbQ\xd8\xfc\x02\x0e\xe1\xf7\x00Uh\xbd%\x176\xca\xbbo\xc4\xdd\xe7\x82\x88\xda\xf9\"u\xc9\xd9\xfedsb\xa9\xc8l\xfd`\xeb\x9a\xdf\x8f0\x80\xd7\x81\xab\xda\n\xce\xee\xc7\x0d\xc6\xf8c\xf7\x18k\x87g\xd7\x10\x7f\x86\x01\xbc\xed\x1e\xe2\xcf\x1b\x0c\xf1\xe7\xee!\xd6O\xe8\xae1\xbe\xc0\xec\x8d\x9dc|\xb1\xc1\x18_t\x8fQg\xb0\xbaF\xf8k\xc7\xd0N\x91\xf9)\xd90\x9f\x81\xfe\xaax\xd6\xe74\x18\xf6\x12F\xe6E/\x02\xc1g\x8f0\xc9N\xcb\xcc\xdd\xe5\xe9\x01\x9a`\xd5\xb5\xed\xf8U\xc3\xa4_\xd1E\x82#\x0b\x86\xaa\xd6\x97P=|'\x1f\xeaT\xe0Wd\xc0\xf8\xd3\xe7\\\xa8\x8c\xa4\xb9]\xac\x83{\xb0\xfcJDVKC\xde\x95\xe6\x85\x995\x0e,\x99\xc4\xd4\xe5\xac7\xdb\x89\x13\x1a\x83\xdc\x85\x12/a\x00\x1f\xba\x91\xf6\xa5\x0f.H`\xbd\xf4\xa5\xc6V\xab\xb7\xc1{\xa5\x9dF\xc1\xcd))7\xa3/w66X:Az\x05m*\xf6\xb7\x0cZ\xa6\xf8g\x0e\xef\xdb\x97\xf3T\xea\xae\x98U\xbeK\x84\xcf\xd5\xe5<\xc5m\x8b\x7fa~\x12\xd7\x9a\x0b=\x0f\xff\x86K\xf9\xf2\xdb?\xaf\"\xfe\xfdW_\xe5d\xaa;\x03\xac\x16\xe8\xb4F\xfa\xb8\xaf\xc5\x9f\x0b\x91\xcf#!\xf2w\x95\x16\xe6]\xf5\xe4\x10\xfe\xf6\xf0\x907~N\xf2\"\xc9\xe8\xa0\xb7\xd7\xdf\xed\x01\xa1\xe3l\x92\xd0\xb3A\xef\xe3\x87\xefw\xbe\xed\x1d>\xfa\x8dJ\xb7v\xf8\xe5\xf5+ \x97\xb8\xc40\x8e)g>O \x9c\x11\x8a\xc9\x19' B\x94\xfef\xf5~R\xd7yY^\n\xa7\xd3\x9fsQ \xb8\xfd\xdb\xf1\xd7\xbf\xdd\x0e~;\xde\x0e\xbf\xba\xed@\xf6\n\x88\xb2\x84\x94'*C\xddXx\xa6,\xb5\x93\xa7\xa8/\xfb\xe5\xf5\xab#17\xe1J\xe2\xe3\x01r.\xcb\xaa\xd5\xdb\x13\x9b\xe0\xfb<\x9b\x8b\x8d \xdbk\xcfH)\xc5l\x92]\xd2%\xd9%a\x08\x87M?\x98\xa4\xf2\x83\x81\x83F\x8eJ\xe9\xa3\xa9\xa7?q\xba}\x9d\xcb\xcc\x86\x7f\x1at\x85 \x93\x17V\xe2|\x9a\x8d1\xcbN\xbf\xc0\xc6-\xfa\xa5Joi\xdbZ=\xa1\xa4w)MD\x16\x94byZ\xb0<\xd8\x0b\xfb\xc5\"MX\xd0\xbbe\xd2\xc6\x80\xee\x9f\x9eCB\x81\x86@\xfb\xb3\xb8x{A\xcb\xdc7\xb9pS\xc4(\xc3a>R-\x0e\xb8XE\x86\x132\xce&\xe4\xe3\xfb\xe7O\xb3\xf9\"\xa3\x84\xb2 \x1f\xee\x8e\xc2\x11\x0c \xe7T\xe8\xd6-0\xbe\xb37\x12v\xd5\x9e\x0f>\xa9m\xdd^\xb3v\x1a\x1b7m\xb5Z\xc5\xfd\xca\x97\xab\x81\xd0\xd6\x8cD\xca\xfdA\x0f\xb6MO\xc9\x90\x19\x0d\xb3\xfd\xdf\xb3\x84\xe2\xf2\xb4\xa7&S\xf5\xb8\x07\xa5\xe6S\xcb\xb9\xa1r\x17Sr\x01$`\x9a\xb9\"\x82\xde\x92Mw\xbe\xed\x85au\xb7w\x1a\x17\xe4\xfe]\xd3\x18\xaa\xd4A\xed\xae3\x0c6K2Z\x1c\xe3[6\xaf\x9d8]\xccb\xcf\\\x83\xa0\xbb\x8f)m\xe2\xac\x17\xe2\x16J \x07h\x9c\xf3)i\xcf,G\xb6yc\xce \x9be\x93k\x8fF|n\x1b\x8fz\xea\xcdD\xb4\xc7\xc8\xe2\xb3\xbf\n\x9c\x8d!{\x0f\xd2\x80\x99\x8d\x14S~\xec\x8c\xc9I\xa5\x8a\x8d\xe6\xe4\xc7z\xfa+_^b\xf5\x10\xd1\xd8\x96\x1c5\x88\xbd\xeao&x\xbb!\x8d\xf8\x06\x8dL\xfb3\x0f\xb5\xc4k\xfb\xbb\xb7\xcf\"\xe8m\xf7\xc2\x91\xdc\x9f\xa6%\xb5R)\xe6\xda\xd4\x86\x94]\xb5\x95\xb48\xd6\x94J3N\xb8f\x15\xe1\xa2\x9aSN\x97\xcb\xc8F\x1e#\xf5\x91\xd7a\xae\x94b\x96\xbcd^\x04\xd8X\xa0\x063\x8ektL\x9a\xb31\xa5Q\x9e\xcc\x03m\x91~\xc3\xecx\xbd\x13\xb4\xd8\xf4z\xae\xe1Z\xb2\xaay\x0d\x93\xc3\xec\xb4\x82\xd9\xc7\xb6{Yd\xc8\xe3\xe6\xd54ig\x9b\xe8N\xc2z\xfb_\x97;%s\xdd\xb9l\x915\xf7\xdc_9Bi\xffY\x97\xf6\xa5ui=ZK\xbb\xd8ZZ\xbd\xfc\xa7\xf2?\xd5\x83\xb2\x90\x16\x0d\xee\xdd\x0d\xfbO\x96\xd3)\x91\xde\xe2\xd7\xca\x06hN\x88\xd9\x9cfI\xa9\x8c\x92\x99\xc8\x15\x0f\xff\x7f\xf2\xde\xbc\xbbm\x1cK\x14\xff\xbf?\xc55\xa7_\x8a,\xd3\xb4$\xaf\x91\xedx\xb28\xdd\x99\xc9\xf6b\xa7\xea\xd7\xa3\xf2xh\n\x92\xd8\xa1H\x15\x17;\xae\xb2\xe7\xb3\xff\x0e.\x00\x12\x04\x01\x92rR\xd3\xfd\xde\xe3\xc9\x89E\x12\xc4r\x01\\\xdc\xfd\x9e@\x15\xcb\xf2\x13\xf1\x83\x9c\xc7\xa2\xfc\x17$\x0b(\x81p\x047a\x16\xe6\xb0\xc8\xf3\xd5x{{\xe6\x07\xe4:I\xbex\xf30_\x14\xd7^\x98l\xa7\xf4\xbb\xedi\x12d\xdb\xf8\xf1\x16#\x9fRo\x91/\xa3\xd3P\xc4nd\x94\x86\xcb\xf3\xb9A\n\xc7\x90\x1fA\xba\xb9\xe9@\x0c\x9b'`=\xf1\xd3y6\xb94Q$\x157\x97\xa2\xcb\xaeB\x1f\xb2:\xeaq5ED\xcd$\xed\x1f\x94\xb3\n\xc8\x99uG\xe2l\xa2\x99\xa4\x16\x1dS\xe5\x15\x98C[\xd2\x1a\xd8\x12\xc58j\xc4\xca\xca\n\xef\xbb\xc4\xa8'\x14\xd8\xe7\xa4\x1f\xac\x932\x1a\xf1#\x9a\xacB\x19\xcbcf\x1d\xa8nz\xf5#\xcb\xfd\xe0\xcb#\xba\x80\x11\x98\xd9\xb8\xe9/:r\xfa\xb7W\x9b!\xb7\xd0}D\xb3\xc2\xb8\x17[\xd6\x18\xfd\xf6j?\xc5H\xcfk\xb5^\xd4\xb3\xbd\x88\xa8=\xad\xca\xa8\xf2\x84\xc84'\x04\x8b\xac\xc3\x8c\x102x\x06{p\n\x19l\xc1\x1e\x8c1\xf3R\x00'\xb0w\x04\x01\x1cCv\x04\x01E\xe3\xd1$\xa0\x05.\xe5\xda&AKb\xf0\x1b\xee\xa5n\xb6\xa3\x86R\xdb3\x93\xe9\xac\xd4c\xc1\xb0\x8d\xe2:q\xd1\x16\xd0\xd4\xc4\x9eux\x8a\x03\xb75 \xdb\xe5\xdf\x1c\xdcR,h\x8a\xc3\xa3p\x8afOSzb\xc2\x7f\xd1\x9f\x05\xfd\xf9_\x90\xcc\x90Zd\xcfV\xecYV\xacV\x11=\x7f\xf2\x84=O\xf0\xb9\x0b\xe4\xeb\n\x03\x9c\x80\x1fC\xe9\xd8\xe1\xfd=\xe3\xa1\xbf=\x8d\xe8A\\z)\x19\xc8\xb3\xbch\xe5X\xc4EK\xde \xe7\xb2\xe8H\xe9\xde\xa9\x8b\x16\x97\xb0\x8d\x99\x95\xd9\x03\xdb\xacN\xe4\x0b\x1d\xf3y\x1eJ\x91~h\xb2taQ\xaeo\n9\x8f\xc2pQfP\x88\xda<\xf1\xc5E;?/\xe5W\xf3\xd6\xf2f\xd8\x1a\x82\xc5\xf5\xda\xe4\xd9\xc2_\x911\xac\x9aoD\xa07\xed\xcb\xa5\xbfzY\xbe\xef\x8d\x1ef\x88\x9c\x1ew\x06F\x18\xe5>\xb3\xf5\xe7\xb6\xb6\x87X\xbc\xd9Z\xdb\xf9\x8a\x9f\xf4<+\xb5'#V\xd0<\xeb\xdaN6\xb9\xcd\xae\xb3\xcap2\xb1V\x0dg\x8d\xae\x9f\xbf\xf2~\xfe\xca\xfb\xf9+\xf6\xf3WM\xd9\x94\xc7\xfb\xcfl\x8b\xed\x7f\xcb\xed?\xe1D\x87.\x9b\xb3\xadi6,S,d\xf6\x9a\xc7\x99\xec&&z\n~\xb3\xaf\x82+\x11|t}\xbb\xf2\x11h\x9c\xc7\x84\xfeu\\\x1f\x1e\xb3R\xa5\xef\x85\xfc}\xac\x8e_\xf4\x97\x16\xaa0+r\x1ae\xcen\xbb\x14>\x03\x06F\xac\x05\xdf}\xd0\x8c\xac\xd00]\xe2]\xce\x8f\xe1\xb4\x0c\x9e\xa7\x9b\xb0\xb5N\xe0}~\x02\xefK'\xf0\xbe\xee\x04\xde\xef>\x81\x05\xd5\x00'\x80\xa6+)\x0b\x9e\xc7\x8c\x1c]\xe1\xbd\xcb\xe2\xb3\x9e\x02QQpm`2\xe2\xe5\xc9\xe8\xa5\xe3\xb14u\xa2\xc0\xf6\x1b\xe7\xe3\xad\xcfl\x9f\xb2\x15 \x18S\x16\xc6\xac@\x88\x05<\x94\x97\xb0\x86\xebk\xad\xb1\xa2\x98&A\n\x0f\xbc1t\xb4++\xf6\xc2\xac\xec\x96\xfa\xcd\xa0\x16\\U7\xed\x99\x96\xfco\xd2ar\xf4D\xed\xec\x8b\x89\xa7P6\xa9X\xec\xac\xd5\xe44B\xda\xa6#\x87\x8f\x81X \xdb\x89\x95\xa8/\xb1\xf2_\xa5\xac\xe0\xbft\x14\x8aQ\xec\xd8\x8c;\xe2\xb4\xc2=2\xc9\x1b\x9b\xa0\xaf\xe0\xaeI\n\x02\xf2\xc6\x8b\xb4\x1b/(7^\xc4I\xdfH\"}g\x8c\xf4\x9d\xc11DG0\xa3\x1b/\x98\xcc\x9a\xa4\xef\xcc\x10\xd0i\x85\xaa\xa6\xc44\xe7\xb1\xbdj\x9ds\xbaf\x0b3\xfd\x84F\xd0\xf6\xeaQKB\xa2_3\xcd\x92X\x18\x96D\xd8E\xbf\xa2K\x00#\xd5\xfa,\x10fW\xc1'S\xef\xe7\xa3\x19\x00-#\x1ce\x0d]\xc4y_\xa5\xc9\xea\xa2\x1cS\xd6\xe8{\xb9\xe2\xb4\x99V\xca\x95s\x83\x91\xab\xca\xc8\xf5.\x92\xb8\x03\x97\xd3\xac<\xa1-,\xe1\x18\xe6G\xb0\xa4\x8b\xc4<\xa5\x18ZJE\xb27.,\xcbEL{9\xa1\xfd]\xd2_\x97V\x89t\x03\x13\xb5K\x81x'\x9f\x82\x08\xae\x12\x80w\x1d\xf3\xd0\xb1\x19\x85xC\x17.\xbb\xb9\x1f[\xb7`\xa2\xdd\x82a\xb9\x05\x13\xc7\xe5 \x10\xc1\x87cH\x8e\xc0\xa7\xd0\x0c'~}\xbb\xf9\xe6s\x0eQ\x07vU\x01r\x88:]\x16\x7f \xf3\x8d\xb8r\xb7\xab!\xa2[\xae~\xfe\xcaq\x84\xdaq\xf8\xe58B\x8eJB \x95\x14\x0c\x95\x14p\x0c\xe1\x11\x14t\\\xfe\xa4h\xa2\x92\xc2\xa4E\xe2(\x8cLrC \xe3^\xca\xda\xf6\xd2\x17r\x97]H\xfb\xc9NV\\\x08\x9a\x91 \x89\xa7e\xd7\x9c\xe6V\x8bM[\xad\xc9\xe6\xb6o5\x90\xa1\x8b\xe1~\xe5H=\xe5\xbe\x9b\xb1}G\xb1jP\xee;\x8a\x9cW\x1c9\x9b9T\x81N3u\xef\x05.\xcc\xca\x99G\xa4\xb8\xf5\x8c\x02\xc5\xa6\xe3\x08&\xb3K\xfa\xcc\xa9v\xa1\xdf\xc6s2\x8bi\xe3Nl\x92\xe5\xa0\xc5\x8a\x0fNs\xf5\xea\x0f\x98l\x9d\x9d<3\xd3\xe7\x92\x05\x8bb\xb7U1\x060\xae\xbdk\x9eK\xb1\xa9\"\xb4\xd1\xd2r\x15\xb5:G\x97Z\"\xee\xff\xa5\xd3\xfe\xb1\xc7y\xd1~\x9cO\xff\x87\x8e\xf3\x9b2\xcec%\xffi=X\xbb4\xebK\xc4x7-\x18o\xd9\xb5\xeb\xe9)\xbdTw\xfd\xc2\x85\x9b\xda\x89\x8b\x1c\xe2M\xf7Y\x0b=%J\x9d\xc6\n\xed[u\xd5\xdc\xaa\x95|G\xfeT\xfc\x925\x85\xcc~\xecQ\x8a\xa3\xed\x1f\xcb\x9f\x8c\xc3\xde\xf2\xb3,\x9cWl\x92\x1d8p\x1e\xc6\xd3\x94\xc0y\x92.\x8a\n\x01\xfdk\x14\x06$\xce\x08\xbc{sQ>\xfcq\xbb\xfc)tR<\x8d\xd9\x9c\xe4\x92)\xd7\xf9\xdd\xf2:\x89\xb2\xa6\xae\x8a\x97\xae%\xb9\x94\xbek\xea\xae\x1a\x1fp\xcb\xca\xbb7\xd9Y\\,\x19\xda9\xd2\xc2\xcdH\xc4\xe8=\xa9pS\xf3\xe6\x18\x94Z\xc3\x89\xdcp\xbb<\xba\x83\x85u\x93\x7f\x1d\x98|\x11\xc9\x04\xb1\x8e5%\x96\x0b\xd6\x1e\xb34\xd4\xc2\xee\xbd\xbf$\x99M\x9c\xc9\xe0\xb2\xb5\x0355\xf1\xef\x0fL)<8\x82\x18\x8eaH\xffR\x84\x97O\xac+\xba\x15X\x0f1\x0f\xd3\xcb\x85\x9f\xbeL\xa6\xc4\x8e\xd1t.\xd6\xf7\xd7\x1a\x0cG;\xbb{\xfb\x07\x87O\x99}KK_s\xc5\xa6\xadK\xc4\x95\xabq\x84\x00$\x0b5\xab=\x8c\x8bXw-I\x91\xe8\xc9p3\xb4\xb6\xb2\xd2\xb6\xc2\x94\xd7\xc4\xbb\x9aE\xfe<\x83'PPZ\xe5\xa5\x1f,\x08K\xa5@[\xd1\xcbxo\xcaLG\x154\xe8\x17)\xd1$\x80\x06\x11\xa7\x82%m\xc2\x82M\x9c@\xc6\xb2\xb8\x02\xed\xe7\xb55!zV\xed\xea\xc3Vm\xfb\x0d\x8fx\x1fO\xc2\x8e8\xea\x19\x02\xddw\xbc\xabi\xb2|\xf3\xaa\x9d\xa2f\x16\xb2Z\xaeN\xbepTGU\xd4\xd1\xe4\x08\xa1\x91`P\xfa\xf3\xf0:\n\xe3\xb9Yy..\xda`d'\x94\x8b\xecjP\\3\xdbw\xa1\xcd\xa3K\xbe\x02\x9e\x91FC\x08\xa8\x97Y\xe7L\xaf\xd4\xb6vF\x16\xed\xa7\xb1\x98A5\xdd\\\x12bi\xde\x9f\xe8\xd7\xe6\x9f\xf4\xdf\xeb\xb6\xc0\xb4\xb9\xb5\x19\xd1\x9aU4(\xbd92\xec~&qa\x96\xd7\xb0\x81%M\xc4\x03w\x7f#\x98\xda\xdb[\xf9)\x89q\xc3:\xb2vA\xb3\x01p?U\xc5\x0d\x83\x83jI\x91\xd2U\x11\x87q\x84U\xa4\xde*Y\xd9\x8e\x83\xd8\x8a\xf6Y\x98U>y\x02+z\x96\xaa(E\x90\xac\x7fj\xb6%\xb8\xe3\xfa8\xe7$\x7f\x19%\x19\xc9rq\xc6\xbcN\x93%\xed\xf2\x18\xa6\xaeZ\xb4Y\xa6\x9d\xfc\x12\xf4\xfeT\x1b\x97^\x82 \xca\x0b\x99I\xba\x84\x13y\x18\xc2\x9c\xfb\x87\xd5\x81\xd8\xe8\x1c\xfd\x86vLt\xb2\xabsa=\xfb:\x91Z\xc6\x98\xcc\xd6\xce\x0e\xba\xf2T\xcf%7\xba\xf2Y\x07\xa7\xc3V\x98T\xdc\x11V\xf7\xa4\xaa\xfb#\xae\x13\xd4\x8f\xda\xd6\xce.\xb6\n'\xf5\xb7\x86v\x8e\xca@\xfcl\xc5\xe4b\xc5\xe01!\xf7\xdd\x08\x7f\xa9P\x1b\x84W) \xe8\x96\xadvl\xc3nD\x14\xe1KC!ub\xf9]\xafe\xd3\nf&L\xe7\xd1\xb2\xe9\xc9Y\x1b.\xdd/E\x14\x19\x8d\xa5\xf5<\xf8\x02\x9f\xaa\x04\xa4\xdc\xc5\xea\xb0\xac\xbeR\xce{\xe6\x1d9\x06k\xe4\xedy{\x96\xaeMM\xc0\xe6\xab+\x86\x01\xe8\xdf\x13q^~+);\xd0\x19\xe0N\xac/a<\xa5|}J\xb2$\xba!,\xf7Z\x9ca\xae)z#D\xc8\x1ff\xf4n\x95\x92i\x18\xf89a\x9f\xacR\x92\x91\x18\xcbq\xf3\xffs\x9e\xec\x8de}{\x1e\x85~F2\xeb\xb2I.O\xac,\xf0#?\xc5\xb2\xe4\xd7\x82\xc4\x01~\xb7\xf4W\xab0\x9e[\x97\x1d\x92\x11#y\xe5\x82__ \xe1\x8c\xe5\xb9\xc8\x85'\xac\xcc\xe1\xe6}\xc3\xb4\xd3Z\xb6x\xd8 \x0f\x9d\xc1?\xcc\xd0w\xb7b\x1bS\xfb\x87\xcf\xf1\x978\xb9\x8d\x81\xa9.\xc0\xfa\x81\x13\xa8?X\x10f\xb0$9%\x80\x90KD\x03oHf\xac\x0cae\xfe\xf6\xfc\xdd[\\\x04\xde\x0f\xcaju\\\xc8\x17a\xe6\xe5\xfe\x9c\xae8~G'\x0f7:\xfe\xe0\xf1\xed\xf9;>\xa1\xf8Z\xfc\xbe\xbf7\x8b\x96@b\xd3\x15\xb3\x07^c\xb9.\x98[Ky'\xd7\xda\xea*\xa1\xad\xb5Z`,\xbctu[\x1fO\xb9\xf4\x18f+\xef\xd4Q\xf35\xc9\xc7-\xee\xea\xa5\xe4\xc5\x8a\x05k\x0f\xeae\xe5\x85\x8c\xec\x1cs\x1e\x95\x9f\x96\x1f\xf8B\x9e%hB\x8c1 \xaf\xb7\xb8\xaf\x08'\x9e\x90\xcb\x9eK\x93^\xfe\xa4d\xc6LR\x9f\xc6\x82\xf2\x1d\x17\xf8\x92\x0e\xab%-\xd6\x95ii\xe3Rc\x0b\xbb\\\x82b\x81W\x165\xf4@\xea\\\xd9\xbdx\xf4\n\x85\x8dvG\x8em\xdd~\xc9\xd4\xf8j\x8c+\x1f\xee\x1b\xd8\xf2\x1d\xc7cR\xdd&s\xaeM\xdc+\x99\xe3\xda\xfd\xfc^\xf8\x02G\x91\xdb\xfd=\xd8\\\xf6\xe6\xd3\xd9\x0f\xc5C\x1f\xf5\xb0cH\x1c\xdbb\xfda\xc6`\x92\xb3\xd4\x83\xe3ey\x82\xa9\x92\xd3>\xb0\xd1#\xfd\\\x0e\x15_\x0f\xdc%\x80\x19\xda\xb1\xbd\xb7\x7f\xa8\x06\xacO\xf8\xab\xa7CG+7\x08\x8dC\xef\x1f\xa3\xde\x10\x9f\xfe\xe1O\xcd_\xe5\xbel\x13\x89\x0bmD\xdb\xc1\x00\x1c\x81\xab\xf6}\x15\x11\xa7\x17\x81)\xce\xf1\xa5\xf0\xae\xfa\xb0\xb3Y\x90\x08\x05S\xb0Gz\xa5,_\x96\xf1}\x88!\xe1\xcc\xef\xfd\x8e`*\xed1\xd8J:\xb5`bH%\xeb\x19\xc1\xbck\x98\xe3\xa6@\xd5u-\xef\x1a\xe3V\x18%[\xb0\xbcj\x94EbHW\x8e\xa4\x9e;G|\x9c\x06\xe6\xb5_`\xb7\x90\xa7\x16\xf3\xb5\x88\x0e\xa0_\xbe\xaf\xee\xa0t\x1b\xe8\x18\x9bIi\xc6\xb2\xf64c\xd0\xb3i\xe0\xcb+\x14(\xd67W\xa7\x1f\x9f\xf6\xa9\xe0\xa1\x1a/\x1f\xd8\xea\xd4\xd0\xcd:\x91\xb7\xd0\xe6\xfayN\x96\xab\x1c\xf2\x04\xa6\x84\x1d\xf5E\xca\xbc\xd9\x84\xbdni`\xa0*\x03\xaa\xcdl\xf7\xa2^%:u\xbf\x1d\xc9\x0f\xf7\xb5H~4\xfc\xbf\x16\xc9K\x07\xa0^\x1c=\xdc\xd3\x82d\xf7\xa9F\x1a\x1d\xdb\x0d!u\xc1\x1e\xab\xa9M\xfaz]\xa3\xf2\xc1\x05f\xbd\xb2\x02\x0c\xe0\x0d\x99\xf7Z\x8f\xaa\xa6e\x81\xbf\xe8\x0b,\xca\x02\xe7\xfa\x027e\x81\x8f\xfa\x02\xcb\xb2\xc0\x0b}\x81yY\xe0g}\x81;8\x81)\x9cB\"\x92.\xd1\x99\xe5\xd9\x97~7e\x11\xbb\xc6h&\xa5\xb6W_\xe8\x8a\xd7\x9c\xc2\x18\x16\xf4/\xcb\xecd\xa7\xbc\x95\xdf\x1f\x9c\xaa\n\x03\x9b\x8f\x9a\x9ei)\"\xca\x1d:1\x98\x9a|\x03\xf3\xe0^)\x11\x8a\xae&\x11\xd3\xb1\x14\xf6\x1d\xaa\x7f\xe8h(\xb1\x1d\xc0)\xbe\x841\xaa\x81\\\xb8c:!\xac[k\xbf\x85\xa5O\xb14\x8caI\xcb\xd1JB{\x86&yc\x98c\x07\xb0\x9a\x13\x98\xc1i\x07c\x00\x12\x83_\xd1\xb8z\x0b?\xf9B\x96n\x11f\xb5x\x1e]\xe2\xd3\x0c\xf3#\x83\xad\xea\xd6\xba\xbe\xa3W\xe0g\x04\x06\xe3\xcerP\xb7\x8f\xd1L\xa1za\xcd\xc3\xf5k\xb6u\xf8\\\xbd\xb0\xf2\xd1c*\xd7\xc60\x92\xaf\x0ea\xb1Z\x996W\x99\xb8\xccu\x95b)f5C\xe7\xdc\xad\x94\xa3\xfa\x1a5\xdau\x90\xc4\xa1\xd5\xfebr\xd9r\xc3\xea\x02\x88\xb3d\xd47\xca\x86\xa8N\x91\x19\xae\xfe\xd7\xfc\x0d\xaa5]\xc0of.\xfb\xcc\xb6\xef\xbc\x1b\x96\x14\x1b7^u\x87\xb8\xc4a[n\xe6r\x8c\xf4\x89~sM\xff\xdb\xb8\xa6\xaf\x9e<\x01\xdf\xbev\x01\xab5\xa7(\xc9\xbc\xd7\xcci;\xf3\xfe\x02'0\xa2?\xce\xe1\x04v\xe9\x8f\x8fp\x02\x87\xf4\xc7\x0bZf\x9f\xfe\xfa\x19N`\x07K}\x86\x13\xd8\xc7b\x9f\xe8\xdb\xd1\xa1[\x93\xb70Q\xfc\xbaR09\xeeT\x85=n\xc3x\x9a\xdc\xd2!\xb1_\xde;\x0c2q\x82ZL8\x15\xef\xc7\x86\xcf3\x12a\x10e\xfaW\xfd\x14\xdf\x8dAL\x84m\x89\xd9^\x84\x99\xe5\xc8\xa6_Zq\xdb\x9c\x8b\xdb\xe6\xdf(n\xeb\xe2\xbc\\~b\x8f\xf6\xd5\xd3\x16\x03\x81\xd1S\x9eE\xcaN\xeb\x9cT\xda\xceI\xa5\xa6e\xa1e\xa0\xda=\x1aPBEx`\xb0\xb0\x96\xd9(w\xb5\xc7\x7fT\x901h\xd4\x83\xa44r\x1ak9\x9b \x89g\xe1\xbch)q\x9b\x86\xb9x[\x1f\"\x86\xa0g\x07r\xec\xd6T\xb1\xd0=wfym \xd1\xd8\xde\xdb\xd9Q\xa6\xa8\x9a\x91Z\x7f\xf4M\xeavH\x8d\xfb\xd4\x8b7\xe3>\xfd\xff\xc6\xb5\xa7\x8e\xeb\x8f_z\xe52j\x17\x15\xd6\x94%\xc3#\xc8\xb5\x860\xb9\xde\x10\xe6F\xcd\xd4\xa0\xb5NoDr\xeb\xb0\xea+\x0dUx\x8072I/\xb9\xf7\x94\x89\xe3\x01\xbd\x89\x00=\xa8\xde\xef\xef\x0d\x06\x07\xec\xfd\xfe\xde\xde\xce\x1e]I\xfc\xd7\x13`\xf2&z\xb7\xaby.*\x1c\x94\x95\x1d\xb2\xe7\xc3a\x95]J\x14\x1a\xee\x96\xa5v\x86\xb5\xcf\x87\xa3\x83\xf2\xd5p\xef\xa9\x03<\xbf\xd63\x18\x0e\x87\xbb\xc3\xe1\xd0a\x97\x04\xd3&T4\xbe\xba!\xcf\x02\x87\x9d6\xa11\x8a\xfe\x18\xc06\xc1\xb6 l\x9d`\xf9}\x07\x9e=\x83\xa1\xca\xbe\x8b\x8b\"\xbf\xbd\xfd\x9d\xd1\x80~5\x1c\x8cv\x10&FM\xaf\xce\xac\xb6I\xf5k\xd1\x9a\xeeS\xad)\xf8\x0dw6\xdd~bO\xfc\xad\xdf\xfe\xe5\x92\xfe?\xd8zz\xf9\xfb\xd0\xdd\x19>8G\xdbs\xc5\xe0\x8dR\xc5\xdb\xff\xf9/\xb6}:\xfe:\xf1\xb7f\xbc\xf0\xe1\xc3\xfd\xa4\xfc\xe98\xdb\xcaW,\xe7\xec\xeep_+\xb4n7\xc5R\xc4\xa5|\x88\x89\x1d\xf0\x14\xcc\x01\xe3\xd0w\xf6PO\x92{\x01\x1f\xf1\xf3\xdc\x1e\xe0\xb2\x88Dx.F\xabc|\xab\xaf\xcc\x946\x9f\x0c/\xeb\xb9\xaf\xe0\x140\x80\xea\x9b8\xb7\xf3\xd2D\xcf\x85\xe1>\xa5h\x1a\xaf\x86\xf4\xd5\x00\xe3\xb4\x16v\x8cD\x8f\x01\xcc+\n\xb8\xc9\x93\xe3g\xd6\xe5v\x1d8S\xe9\xcd\xbc\xfe\xaai\x02B/\xeb\x895\x06\xeb\x89\xbf\\\x1diB#[\xc7\xf86\xca\xb5/\x9f\xe1\xcb\xb9\xf6\xe5\x0f\xd6\x0f\xf4\xe5\xafE\x92\x1f5b\xd15\xa7\xed\xc6\x88S\x16\xb2\x11\xb6\xac-\xe0V\xba=\x84x\x93K\x06a\x86\x1eK\x9a\xc1\x85\xe1:\xfa\xe0\xd6dVR2Lq\x0c\xe6z#c\xb4`\x149H\xf8W\x06\xe6\xbeKum\x0coH/2\x89/y\xe4\x1bm\x19]\x0c\x91\xfa<95Z\xdb\xc5l\xc0=\xd2\xe9q\xa0[\x1368\x8e@.y\x04\xf3V \x11\xff\xb4q<\nSW~\xbe5\xcd\xa9\xeb\xdd\\\xf8xN\xd3\x9fE\xcc\"\x1d\xbek\xcfgWJ\x1e\x84b\xd4\xfa\xe5\x17\xcb\x81c\x18p\xcd\x16)\xe3,\x86.X\x7f\x1eZ\x8e\n\x99\x9f\xfc(\x9c\x9e\xc5y\x98\xdf\xbddf(>}\x81x3\x99\x92\x8fI\x88j\xea\xc2e\x9ajZ\x17\x96\x0eI/A\xb4\xd4\xb5'\x86\x9ee\xae\x9c\x18\x08\xbb\xc5\x06\xff\xd7\x1c\x03\x84w\xb6\xb1\x12I\xd80\"\x83\xa8v\xea\xc2\x8d\x0e\x19\xb51Ak\xc9\xd8\xa5\xa0\xd6U\xe0\xcbS)\xc1;\x8c\xf5\xf2\x98\xae\x1e\x19E\xeb\x0dn\x8f1K\xfb\xeai\xcbD\xeb{\x87Z\xd1\xfa\x81Z \x13\xad\x0fGj-\x8f\x93\xad\xbb\x92\xf4\xdc ^_t\x89\xd7o\xba\xc4\xeb\xcb.\xf1\xfa\xbcK\xbc~\x07'L\xb6\x8d\x923.\xe3f\n\x13!A7\x8a\xbc\xcd\xa2\xf5\xc5\xba\xf2\xf8+8\x81kI\xd8G\xbf\xb9\xae \xff~\xd7\xa5Q\xaaD\xechY)\x89\xd8\xd1+\xd3f\x82v\x14\x91\xdfA]\xd0~\x87\x82\xf6S\xb8\x831\xc4\x0eJ\xd4\xe9\xb1\x8c\xc2\xa5\x00\x8fp!&G\xc9\xb9Q\xa0X\x98\x04\x8aw\x8c\xc4\xb8c\xe2@!2\xfc\xec\xb8\x80\xb2\xc2\x0d\x9ee,\xe4\x02\xc3\x15\x06\x08\x10\x02y\xf1\xd6\xbe\xe2\"G\xa301\xf5\x02\xa6\x9eJ\xdc\xffi\xc1\xa2Y\xf5\xa5*\xb3\xb8\xeak\xa0\xaa\xc4\xf8\x06Uw\"\xdd\xa0\xdb\x96J\x00\x15\x9a}hP=\xdc\xf0\xa8\x01\xdc\xcc&\xc4\x1c\"\xda\x85W``KtM0R\xdf<\xf22*\x95\xed\x82\x85\x11\x15~\xec?\x9c\xa0\xe1\x0coH\n\xba\xec\xbb%\xf9\xe4\xa0U\xcd\x0f\x0e\x8fF\xf6\xactu?\xde.}\"\x9e\x19\x03\xfe\xaegP\xa7\xf1X\x8b\x99\xea3\xb7\x0b\xc7\x85\xd4N\xbd\x8f\xb0 \xa9\xf7\x1a~\x84\xa4=\x02\x83\xe0o,\x0b&\xe4\xd2\xa6c0\x02)gF\x03\n\x05}\x7f\x0f9w\x88\xa3_K\xd9\xe0\xeb\xc3u0 #\xc6O\xae\xb15\xddG\x15\x8e\xba\xeaU\xdc\xc3\xfa$_\x84\x95\xd1\xfa\x83,on\x9a\x19\xd0\xfab:\x0c\xa3\xb4\x1aq\xd5\xc0\x05r\xe3G\x8em\xb1\xc7U\xf5F# \xcd\xb1Y\xc9\xdc\x11\x93\xb1[\x1d\xaf\xf6\x9d\xa4\x905Q\xe3S\xdd\xe6\xfc\xfe\xa2\xc6^\x9e\xb37\"\x19E\xa3\x01\x91xb\xacMT\xb1\x08\xb3SV\x160\xf1\xf0j\xb9\xd0\x84\xe7C\x91\xd89\xf6\xb2\x15 \xceIDh/2\xcd#\xbc\xfb\xb7,i\x15\xf7\x89\xa3\xcc\xf4\xad. \x8e\xb8x\xa7}\xbb\xa0\x0cmi \\\xd7\x1e\xd25\xa8XH\xff\xfe\x80\xb1lb\x9d\xa5\x80|}H\xc3\xb1\xc6\xdeF\\\x0f\x18\xd5\xd3\xd4l\xeeB\xd8\xf7x\x85j0\xe2\xd4\xb8\xf5\xd3\xd8\xb6p\x95\xde\xa6\xfejE\xd21\x04I\x11M\xe3\x1fr\x98\x13\x16\x17\xd4r\xdc\xa6\x9fa\xb3 \xad\x17\x99@dt{\x0c\xfe\xa1\x86\xf4\xcd\x86[\"\xe3\xf2\xcdGiZ\x7f\x15\xaa\x9bO0\xae\xcd\x944\xcc\xf9\xae\xbe\xc9v\xbc\x81g!\x8d\x9fW\x0c\xdan\x17\x13f\xe6\xfe\x0f\x9d.\xeeU\x1d\x15:\xc1\xa7h\xe3\xcf\x08\x91J\xde\x8eqCE\x02l?\xe6\"\xf7\x0d\xc3\x88\x1f-R\x1c\x1d\xa8RBLy\xd1\xe4\xd1d*\xa0\xa4\x06\x18\xda\x96\"\xb2\x887M\x8e*\xa5\xfcb\xd2\xcaQ\xea\xa1\xa7\x0f\xcf$\x8f\xa6\x1f\xaco\xfa\xc4V\x16\xae\xbdL\x03[\x03\x03\xed\xba\"\x0d[s\xa9tx?\xd6\xfc\xb2\xdb\xcc\x7f\xae\x8b\xf9E\x92D2\xb3\xd9\xab}I\x90\xac\xda\xa7\x0b\xab\x1bu1\x84\xdcv[uZ\xf2+k\x80\xfa\x99-\x9f\xb23\xa6\xf1\xdc\x95\xa2\xe6\xd4\x0b\xab\xd1s4\x87\x13\xba\xb4\xa3\xeb1\xda\xe8P\xb4\x8a\xe4Qj\xc7\x8ekN\xdb_\x1e\x0d\xa2\xdaZ\x89\x1a\xe1\xfe\xd0h\xcf\x9a\x93\xdcb\x91j\xe8\x9cg\xe2\xae\xb9I\xad\xe7A@\xb2\x8c\x9e\x7f\x18\xab\xb9X\xd19#S\xd36\xb5\x90d\xe1u3\x86\x8c\x99\x87\x95\x0e)kn\xe4~Vb\x0dw\x84\xb5\xac\xc4\x1e\xd7\xa4\xbab\xbe\xa5\xc9N\xb7a\x83\xcb\x81\xce\x88,\xb6w\xf6v\xb5\x8a\x91}Uz[\xf0\xe2\xaa\xe7\x02J\x9f\xecCu\xafD\xac\xd1]u\xe4L\xf1\xaf\x96\x9ei\\\xadV\x18\xb0\xb3\x0eS\xb4L\x9b\x93\xfcc\x92Dd\xaa\xe6\x87Xh\xe4\x1a7%2)\x1f\x97'\xeb\xb2\xc1\x1d\x9cy\x98\xde\xea\x13 \x928\x08#r\x91\xfaq\xe6\xb3\xd2O\x9e\xc0\x0d0'\xff\xe1h\xc72YOP\xeem\xa2l\xdb8\xccY6\xcfq;\xe3\xc5<]\xc34\xbf+i\xdb\x8ce\x18\xc3\xbc\x18\xecX\xae}\xa5\x88\xa54\x82\xabu\x1a\xd98\xa9\x9a\x81S\xb0g(\xb5\x0d\x08%\x19\xcd\x9f9.\xdc\xdaH\xfe\x95\xdf\x9e\x18\xc3\xb0?\xa8t\xe6z\xc0 \xfc(\xba\xf6\x83/\xff\xbb \x05\xf1R\x92\x91\\\x11{<\x16\"\xf5\x9a\xe3$\x0fgw\xcf\xa3H\xad\xbd\x1a\xc8\xa5nI\xdd5\xe3\xff1\x1f\xe7j\x98\xd2\x9a\xb2\x9d6\xb8\xf2\x95\xebj\xfa\xd7\xd8\x07\xa2\x19\xcd\xba=i[\xd5R%\x1b\x83v\xdb\xa8\xeb6\xe35\xe2]-\x93\"\xce1\x15\x06lA.\xdf\xb7V{\xd5F\xdej\xe1\xa2\x88G\xeb\xab\x96\xc5\xfe\x18\x8ev-\xc4\x9c\xe2\xb9C\x7ffI\x9a\xdb\xd7\x8e\x0b\xab\xcd\xcdz%Ud\xba*\xaca\xce\xa3\x1a6\xd7\x0b\x17tR\x04:\x9b\xc4\x06\x0fQ\x1f\xe7\xe8jE\xe2i\x18\xcf_\xf2\xd9\xcb\x9a\x0c\x1c\xba\x156\x0b\x96\xb3_xQ2\xbfHVo\xc9\x0d\x89>a\x88'c\xa0\xa3\x1b\x1e\xbd\xd6\x90\x9e(\xf4\xae\x82\"MI\x9cs\xc6\x0c\xf3\x89c\x9e\x03?\xc8E\x1b?3\x16\x0b\x8f\xe4\x88\x8d\xa2\x11g\xcba\n\x03\x8be\x03,VS?',\xb8WD\x97\xd4{\x7fI\xe8\xaa\x14\x0c\\\x1e.\x89\x9dt\x19\xab\x00\x87F\xe6\xadH:K\xd2\xe5g\xac\xf7\xcd\xec=\xa1\x84\x85\x9f\xde\xd9\xa1\x8bF\x0d\xcd\x85\xcct\xa7 *n\xa5F\xcf\xe2)\x8b\x0c\xae\xe7>{D\xbe#\nf \xf1\xaf\xf4\xaf\xedO\x82K\x97\xef\xc2\xe2:\n\x03\x11\xb8\xc6V}>\xfe\xd4\xfc\x95\xd8\xb2\xdf\x19D*R\x9c\x93\\\x1a\x1b\x9f\x90\xac\x03\x8d\xf1\xad8oC\x87\xc2-4I\xfb\xe0\xc4v\xb4\x14z)\x89\x88\x9f\x11\xbb\x89\xa0\x1c\x03\xd6b_\xb6!\xa4Z\x9d\xba\x99\xee@v]\xa1\x86\xf8\xd2\xea&\xb6\xa1\x02i$\x16$\xcf\xd1\x89>M\xc6N\x88\xc2-E\\\xd0\x93\xe2\xd5R\xa1k\xd6\xf3\xa7S\x8a\x9c\xc3x~\x91\xd8w\x8a8\xef\xb6M\xcc\xc9\xa3\x0b\x95h\xf1\xfe\x1e\x16\xc6(Y\xb3\x0e\xb7:\xa1\x88\xbb\x93\x8f\x1c=\x86!b\xf0\xf6\x95HKO\xd7\xc2]9\xad\xba\xd4v\xdaN\x19{\xc3\xa8<}\xf3\xe2\xe4\xd0\x04\xb5\x03-\xfd\x08\xb9|\xd4\xd7\xd6tWG\x8d\x82\xa4\xb3\x06/`\\\xed,2V}\x81^Sn\x8cL\x19\xee\xcb\x9a\xeb\xb4\xcc\x17\xd3\xb2`\x97t,7^\xbd\xaaf\x05m\xfb\x84\xe3\xb9\xcf\x1c\xb5\x97\xe75\xd1\xdbP\xf2\x16\xc3\xec\x05m3\x8c\xe7\xbcQFFb\xa0\x81\x9c\x0b\xe8PZ\xe0]\xb1C\x03\x8b\xbfGm\x08\x17Ji^\x9c`N\xbc!\xd2\x98\xdaQ\xb5\x8ed\x16\x15\xd9\xe2\x85\x02\xd5[\x85\x19\x8a)G\xceT\xca\xcd\xe5\x88/\xf5\xf3g\x16\xb1\x88\x8b\x94L\xc3\xbe\xe5\xb4\xe2>\xbd\xb6\xb0I^\xb0\xfe\x08@\x9f\xe7\xa9\x9f\x93\xf9\xddz}9\xa0}\xd1gOQ\x00\\\x92T\x87\xf8\xc95\xdd:\xbe\xf2Es\xda\xc5GO\xe9G7\xfa\x91\xb5M\x9a\x9f\xf9\xab\x1e\xa9T\x03[\xb3\xe6\\N\x97\xf0[\x8f\xd5\xf5\xd2\x8f\x7f\xc8\xc5\xb2\x06?\xc6&@\x1cP\x10\xc6\xe0c\xe8E\xf25\x87\xdb\x05II\xc1\x87\xe2c\x08\x85\x1c\xaeI\x18\xcf\xc5\xf6\xf4\xe8\xb8\xa6%5\x80\xfds\x19n2\xb2>z\x81\xd6\x19>]C\xce\xb0\x11\xdb{C\xc7l\xb4\xc3q\xc0\x01\x9d!\xbd*\xe9\xf7\x07\x17,\xbf\xa1B\x02FytP\x06r\x13]s\xeaxU\x9c\x8c\x87G\xa84\xc5\xd3.O9\xcc~@\xc1\xf2T\x17\x1f\x07_\x8d\x86\xea\xab\xd0\x14h\xa2\xd4b\xa0\xcd_\x861!\xe4\xf7\xa5\xf6\xa4\xd3[^\xc8tUSWz=@\xd7\x8e\x95\xf5\x0b\xdd\x1d%U|\xaf$\xe5Q\xcf\xe4\xd7,\xe2i\xa9\xa0\xa9\xcc*O\xab1\x8e\x0d]]\xcf\x83\xe8\xbb*D\xc4/\xd9;\xb1\x1b\x18\xd2\xac\x9d@hW\xfa\xae\xd6)\xe3\xfd\x97\xc3JR\xe8H\x86\x00c\xd4\x03U\xddk\x9d\xc3\x7f\xc4\xfc\xad\xd1\xf7\xc7oG\xb3\xd4\x93\xb3\x97J\xc4O}S&\xfc\xd6 \xd0\x9a^Bgx\xfe=\xc6( T\x0d\x86\xe6\xaa\x84\x94\x0bTu\xf2T;\xb6\x9f:.L\xaci\x98\xad\xe8\x01\xf2\x12=\xa9-\x17\xac\xab\xdcOylVz\x1b\xfbyx\xc3\xfc+1\x96c\xf6\x8a\xcd\xf7\xc7\x94\xd0gd\xca\x9eRT\xee\xcf\xd1\x08\xee\xa5\xa94B\x1f\xca\xdd%j\xd8p\xdf\x18K\xdb\x10\x1d\xad4\xfb\xd3ft\x03\\\xd4\xa7\xd8i\x96\x01\x8e{\xe3Y\x0c\x00\xec`\xf0y \x8f=D\xc5\xecX\xfa&\x9e\xf8\x9a\xdc!\x0d\xe8\x08Y\x1d\xe6B\xf5\xd4Y\x87S\xdd\xc31l\xb08\x8e1\xb7\xde\xfb\xa9i\xbc(i\x84\xbd&\"\x80\x13\xa0\xdcU\xd8\xb0\x9aR\xf6\x1bZY\x89\xc8\x9d\x1a\xc4\x81<\xb1\xbe\xfc\x9f\x9acN\xedL\x96\\\xd5\xa7l\xc5\xfa\xf6J\x9c\xea=$L\xcdAmh&\\H \xd4\xd5\xda,\xc9t\xd5\xc4\xabw\x05}\xa1\xea\x8fl\x87\xd9\xf8a\x88\xcc:7#M\x08\xafM~r\x02h\xadf\x9e\x95\xc6\x8c\xb4r\xa7Y\x9e\xac\xa4I\xe9\x00\xda\xfa\x80P\xeaGH(\xcfZ@\xc1\xb0\xea\x0bD\xbd\xbc\xc2\xda\xa3\x13\xa6\x80\xee\xbd\xb8:\xc1\xb1\"i\x86\x99\xc4\xbb\xd7N\x98}d\x85\x19\xdaj\xb4\xd3\xd6\x8c\xfc\xadv\xbf\xd4J\xf7\x96\x9a\xd6\xa6\xa7\x07\xae\x84z\x0c\x0d\x96\xd1\x0c\xf1\x0f\xd3\x84k\xa3\xd3\xeb\x94\x15\x95\xd0\x9aebB\x146\x89//\xb5\x12\xd1j_;.dU\xe7\x98kc\xe6\xf9\xc5|I\xe2\xfce\xe4g\xbd\x1dNd\xb8\xa8\xbe'5\x1f.\x84\x8d!b\xda\x0d\x8fn\x10\x93[\xf5\x18J\x99\xec\xbf\xfc\xd0\xa9\xdda\"\x16\xf9A\x9d\x98\x06\x8c\xa6.\x8f3E&\x18\xfbR>f<\x9e\x8b\x98\xa4\x19\x908H\xa6a<\xafgD\xc8\x17$\xc6\x8d\x87\xc9\xd2\xca\xc3\x0fD\xe0\x17\x1fx\x03\x06e\xb88c\xb9\xc1@/\xd57\xffF\x18\x19\x18\xcc\x04\xf4S\x13\xb5\x88\x85\xc0\x0cCC\x8c\x9b\x1f\x84}n}\xdc<\x9b\xa6\x0f\xac\xa2\x16gp\xbd\x03\x1d\xae\xdb\x17\x0c\xdb=y\x82LO\xb9\x1e\xe4w\xcdC\xbe\x85P\xc3\xd0>\xde\xf5]N\xde\xf2l\xdd1FWA\xcf\xf3\xea1\x1cWv\xcb\xeaV\xfd!\x99\xcd2\x92\xff@\x97@R\xe4\x90\xcc\xe0:)\xe2if\x9a]\xb5MZ9l\x82\x8d\xb6\xfd\x03\xc7\xd8\x0e\xdbs\xfd\xdb\xc9\xeb\x99\xd1\x99!juO!\xd5@\nuE\x80\xae\x08n\xe0\xb1\xee1\x05\xb3\xbe'\xad\x88)oCD\xb4\x00\xcf|\xd8\xbaU4J\xe2\xda\xec\x8f\xf5\xde,\xdd\x04\xa1\xb84\x9f#@\xcb\xe8\x0e\xf7\xf7\xcc\xed\xde*\xf2\xd9a\xdb\xd4od^\x98\x9dq\xbca\xc7\x8ei\x13 \xd4bIh\x83\x1d\n\xac+%\xee\xd1\xed$\x90\xce\xd3\x01\xdc\xc3\x82M\x9c\xde\xe2\x10\xf8\xe1\x8a\xd3\x81\xc7V\xea8\xdem\x1a\xe63/HX\xa7\xdcL\x8d\xe1\x98\x11\x91\x84rZ$\xb9)\x1bUJi\x08\xfag\xf3\x04\x86t`\x18\xbax\xb4\xb7\x07O \x9f\xa4\x1a=\xd7Z#\xd4$^\x85r\xdd<;\xa1\xbc\x95\x89jy^e\x96\xf1#\x0c\xbfB\xf8\xce\x82\xc8O\xe7\x842\xa8~\x0cK\xffk\xb8,\x96\x90\xa1;\xc7\xe0+\xe5\xb3}9\xcd\xf5p\xdfAWNJ6i)\x9e\x12a\xdf\xf7\x1c\xd4\xa2u%J'\x8b\x9c;JH\xcb\xf5\xdb\xb4\x0f\x92\xd6\xdasHe\xbc0\xfb)$,\xd0H\xf31\x9d\x88\xfb{ \x06\x14/\xf7\xb4\"0\x9b\xbd\xd5\xb8\xd6W\x8c\x9e\xa5\x13r\x80\xb4\x9c\xdb\xa1\xc0\xa9\xcd\xb2'\x9a\xedU[\xbe\x1b\xc3\xa3#\xa7\x14\x0d\x1bOB\x14\x88Z~\x16\x84\xa1\xa5\x17\x8b\xb2\x12\x91\x9f\x87\xf1\xb0\xb5\xc8u\x18\xfb\xe9\x9d\xa1\x08H\x12(\xfdq\xc2*A2\xaf\xad\x95\"\x9fm\xb5\x96`\x84vg/^\xdb\xc41\x02\x1c\xaa\xe6\x82l\xd4\xde\x9f \xdb\xea(\x91\xcf\x86\xfb\x11\xe9*\xb3\xd5R\x08\xaa~\x8f\xe0\xc7v\x08.\xc8\xd7\xeeZbx\xf6\xec\x19\x18\xac\xb6\xf9t\xfa\x19\xd9\xdf\xed\xae\xea\xb7.@\n\xa32cE\xa8\xedpzO\x0cp&\xcc\xc6\x1d\x95;\xf5\xe8f.\xcf\x8f\xd6\xf8T\x95\xbe\xeb\xd1\xd7M\x1b\xc7\"\xf6\x16\xd1F\xc6\xe7riz\xfc\xb9\xe2\x10L{5\xba\x94\x98*\x83\xc6\xa1B\x01\xa4\xa4\x189\xc0\xb64\xd3h\x10\xb7\xc4\x94;L\x99\xf0\x1cOn\xe49\xe1\x99,\x91;\xc575\x11\x1d=\xdd\xb7\xca'\x87 b\xa1I\xcf\x1cV\xe1f\xecB\x98\xbd\xf7\xdf\xdb\xb1S\x16K\xf8\xe1\\\xca\xb7\xb6`\xe8\x08\x91\x80(T\xbe\xdcDZ?\xa6\x07 \xe9p\x84@\xcb\x95V8\x00\x8f\xfe$7\xdd\\\x19@\xa2\x8c`m1\xa3\xd7\xcc\xcdm\xf4k\xafk\xf9A\x8bH\x8c\xd9\xdd#\xcf>K\x93%\xe5\x15S\x07\x15\xc35\xae\xac\xc6J\xe5\x15\xfb\xb45\x841\xcc\x95\x15eX!Z\xe1\x13\xaf8\x87'H\xeb\xb8\x069\x83\xe9\xd0\xad\xc4\x17\x92\xf6\x97\xc7\xd9\xc5\x08\xa4\xa7\xadE*\xf5\x04\xe7Z\xb5\x85#?\xcb\xdf\x18>\xc0\xb1O\xf2\xcb\xb6\xd1ky\x97\x1b?* {\xc1\xae0\x08Q\xce\x843Z\xfd\xe8q\x15\xfe\x06d\x12\xb2\xf0l\x86\xd8o\x85\xb4p\xf5%2\x89\n\xd6O\xb1\x14\\\x95\x89\x14\xd8\x89\xc6\xf8\xef\xb4\x8a\xc6\x99*h\x14\xe9!~\xb8q\xa1\x15>\xe0gY\xfd\xd1\x96\xf4\xcc(/@\xb2\xb6\xa2\xd8GL\x18X\xddw\xee+\x9fEO-`\x9bEQ\xe5\x7fc\xfc\xab\xd9o\x8dG\x8a`\xd6\xd4Q\xde\x8dai\x92FX\x00{\xe2\xa5\xc4\x9f~~\x13\xe7\xc3\xfd\x17gv\x0e?\xea\xdc\x18\xf5\xfb\xdc\xa8E\x16\xce\x8e\xa6A#M\x87j\x98#\x08\xe1\x18\x8a#\x0877\xf5L\x19\xf0\xc6px\xa1\x83\xfdG\xad4OQ\x1cp<\x1c\xc2\x16\x04\xadr\x1dQS\xf9!]9\xb4\x9b\xa1\xe3\xb2\xcfa\x93\x03(+\xe7-\xa0\x001V\xc9\x91\xec\x16K\"\xc1j\x0ca\xeb\x84\xf7\xc6\xe5P0 g3lb\xd8\x84\x0c\x9eAQ\x9e$\x05lA\xe60\x7f`\x84\xda3d\xe6\xc2\xad\xad\xb6!\x97\xc4\xf3\x8c\x07\x0b\\1\x1ep\x05\xc7\x90\x1d\xc1\xaa\x0d\xe8P\x03[{>\x1cCz\x04\x9b\x9b~\x1b\xfa\xa0\xc7\x84\x9c\xf7\xa2\xb8\xce\xf2\xd4\xa6|\x82\xef\x02O\x8d\xa1_X8H\xa4\xd6\x8a\x8a\xa0\xf0\xf5e\xc9\x84\xee4f\xba\xdb\x03\xe9\x89\xcaz-\x9a\xeb\x8eE\xc3+{a\xbf\xa6\x1bJ^\x16\x0e\xaa\xe4\x9a&@\xa6\x96\xae\xfa\xb6d6\x18(\xeb\x94smM.]Y\x14V\xb2\xf2L\"\x963\x87K&8\"r\x02\x94\xb8C\xa2\xafK\xa8\x98\xaf;\xe8\xdb~\x83\xae\xc1\xa6W\xc5g\xfd*~a\xff\xb6~\xa7\xbf\xf6\xad\xbb\x97V\xa3\x92W\x96\xde\xb6|\xd6\xa4\xadF\xa4\xa0\x15\x1b\xb6\x9d\xd3\xd3i\x84i!\x1c\xbe \x19+!\xcd\x9f\xcf\xf9M\xcaO\xc3!\x8f\xdaL\xd1\xc6\xde\xbe\x0b!\x9b\xf6\xc4)\x7f\x9a4yF\x94\xfc\xf0\xad\x0b\xfe\xbc\x8d\x9f\xad\xb3\x10t\xd8q\x8d\xc5\x84SH\x91\x07yq\x97\x13\x91\xf1\x9dbU\xf5!WQ\xe5u\x9b\xae\xb6~\xbdl\xeb\x17\x05\xf3;?_x\xcb0.i\xc6\x1e\"[:\x9f\xe8\x1aq\x04 \x8an\xdb\xd0&\xa5\xbd]\xb4\xafu1F\x07\x99$-\xc9\xe5\x03\x11,\xc1X\x82\x9e\xe0\x11e\xa5w\x9e\xc2)\xec\xc2\x98\xdd\x8dv\xe0\x14v\xf8\xdd\xf0\xe9\x10Na\x04c\x93\xe8\x05iE\xd8\x84\x19\x1c\xa3\xb0O\xc8\xeffm4D\x9f\x04\xb8\x11\x1c\xc3ptX\x12rQ\x8b^ \x04\x9da.\xd2'-.m\x8er\x19\xc3\xa7#x\xc2\x88X2\xa1\x83\x1b^:L8@\xd9\x17{g\x08O r\xe0\xf8\x18\xf6\xe1\x1e\xf6w\xe0 %^\x9f\x89\x0cb\xd8\xdd\xec;t\xd7`\xf6).\xb9\x7f<3>\xde\x8d.]e(!\xf6\xbe\xfe\xcc\x97F4\xdc+G4\x1c\xc1=\xd8bL\xf2\x10}:\xc4\xd1`\xf7\x80\x7fw\xcc\x13\x96\xdd\xdf#9+%x\xfb^\xe3\xdf}\xfc\xf8\x8b\xf2ng\x0dh\xd4\x9f\x15\x06\x08\x1d*\x10\x92@\xe6\xd7AV8\"\xef\x1b\xad\x89\x82\x8c\xa5\x92\x1bI`\xd2\x0eQO\x12\x97\xc6X\x94/\xc2\xcfi\xdd;.\xee\xe4!\xc5s\x81\xdc\x9e\x1d\x94i\xe4\\H\x19>\x0f\x98\x18u\x00O\x00\xf3\xc5\xdd\xb3I\xe4\xdc\x0c\xcb%w\x0f<\x95\x1cer\xc4w\x18\x1bg\xf3\x04fM\x8co\xc2\xd2\xdd\x14\xc9M\x19\xa7\xa9M|\x8a\x8aq\x8a^\xbe\x94$\x9f&\x1d\x1d\xb71>\xe7b\x10\x9d\xde\x02$\xdd\x85\xa5\xc9V&\xaeT\xaf\x0c\x04(\xc3\xa2\xa4\xa8=\xa4\xc7\xeb\xe6I\x9f\xce\xf0\xe3&u\x99j\xeeK\x07\x11\x157\x81l7\x8eO\xf9.\xf7\xb8b\xe9\x84\x1e\x0e\xb9w\x1e%\xb7\xe5\x93\xf6y\xd8$U\x84N\x82\x12V\x0dC\xc0\xba\x95y\xa8\xba\xb37\x1b\x1e8\x90{o\xde\x9f\x7f<{yq\xf5\xee\xf9\xffw\xf5\xe2o\x17g\xe7t=\x0dL\xb2\xb8\x139\x89\x0e1\x98\x05\xe9\x9fwy\xf6\x18\x83\xdf\x0b\xdf\x1a\xc5di\xd8a\xa2R\xb3J2\x9fie)\xbd\x00\xb0\xe5\x18N\x92\x1e\x01\x13\xc4\xc5{\xb5\xdb\x94\x1f\x89K\x8f;\x1e\\\xd8\x1dqZi\x96$\xb6c\x14\x87\x12\xca\x901K\xd3'O\x84'x\xf9\xcc\x1eb\xc2\xbcJ\xa9\xd8\\\xaa\x9d\xd9\x0d\xf8\x1864\xb2\x93\xfa\xbab\xf1u\xbe\xbc\xf3\xbf\x96\x91\xa3|\x1b\x05\xcb\xab$\x89\xce\xc3\xdf\xe8t\x1e\x0e\x9fb\xf2\xa1+\xeea\xd3\xb9\xe2\xb5\x13[sJT=\xbf\xb8`\xbb\x87\x1f\x8cT\x7fd\xf3\xf0EZ\x0b\xcc\x16!\xb5\xec Y\xeb\xa3v]\xd1\x91k\xcb\xb8\x06\xfb\xc9st\xf5\xa7\x0d\xb1_\x18\x1cJ+!\x13\xdetY\xa9Xa_hmM\x98\xe1K\xdd\xd5\xad\xcd\xccAV\xec16\x08\x02ZGc\xdf\xd43\xd0\xc9\xb5\xd5\\j\xb5\xd0B\x0c\x933\x0c\xd2\"\xd5\xa5\xbc\x07\x99\xc4\x97FvK\xc8\xa5j\xc7\x83\xad\xcb\xb3\x0f\xdcV\xdc\x84\xee\xcc\xbd0\x13\xe7>7F1\xb3\x812\n\xf7\xff\xa0\xf9\xa3\x97\xcf\x8c\xb9Q\x13\xce\x19_\xe1 \xdf\xb1\x16\xa1Z\xb7is\x91J\xce\x1e'\xb0p\xa1F\xe9I\xc7\xe7\xc6\xa0\xfe.\xbb\xf5W\xc3\xfd\xb6x\x9d\xa0\x06\x0fh\xd3\x13\x11\xad\x9eH6\xd7\xe4=\xc9(\x89]\x99\x0e/\x8b(\x0fW\x11\xa1\x10\x1c\xeeo]\x87\xb9\xf6X\xac)\x1a\x06Gh\xbeK\x8e\xd8\xf2\x1b9p#\xe2\x9f\xba\x98\xb4R\xc7\x7f e\x82\x1cB\x04\x04\x10\xeb`\xd9\x19}W\xb0\xec~#XvF\x8f\x02\xcbn\x03,;\x8e[=\xa2`b\x7ftZ\xb85\xa0\xb5\xbf\xfb]\xa1u\xf8\x8d\xd0\xda\xdf}\x14\xb4\x0e\x1b\xd0:\xd0Ck_y\x9d\xe8\xda\xf9\x83F0\xcc\xe6LX}a\xfc\x16x&\x8f\xa7\xf2(\xb1\xfa\xd5\x8b~S\xb1Z\x890\x90\x90\x1f\xa2\x19\x1e.\xba>M\xa0\xd9(\x96>>\xa1\xbd\xe5w\x9d\x1f\xe3\xeac \xa4\x89\xe4\xcc%\x19(\x1b\xa5\x1b\xd0\x83\xee\x14\x17\xef\xc5\xc7j1\x9b\x9c\xac\xa0\x0f\xb5\n\xbd(Vq\xf1\xc6_\xae\xd3x\x1b\x9d+.^\xef\xf3u\xeam\xa5\x8e\xa1\x1f\x85,.\xde\xfe\x87u\xda\xef\xb4\x1d\x86\xaa\xe2\xf3u*n\xa1\xc6\xa1\x17E\x0e=\xa9rX\x872\x87j4\x17\xfdF\xd3I\xac\x03\x94v\xd1Z\xc6\xfa3\x8b\x0eUz+\x8e\xb51\x14\xd4\x8b0w\xc4M\xb0\xac\xbef\xd3\xa0\xa5\xc9\x1eD\x0c\x12\x1c\xac)\x0cI\x1d\xa9\x93_\x0b?j\x8f\x1f\x01ZiC\x87lA:\x0c\x85\x8df\xeb\xc1\xc3\xcf\x80\xfb{\x8e,KY\x88\xde/\\\x19E\x18g+L+\xd6\xefd2)F\x98\xffRC\xca\xdf\xdaqq>=\xe3f\xd3%]Q\xba\xf3 \x8e\xe4\xfe\x92\xde\xd2\xcf\x83\x85\xbd\xed\xfd>z\xd8\x9e;\xde\xdf\x930\xb6-\xb0Dx\xb0\xb22\x9e\xec\x89\xa5P\xf7<\x0f,\xc7q\xc1:\xe6\xf4\x06\xae+]6\xf4:\\\x0c\xf2\xa4N\xa3\xf6\xef?\xd5*\x8fW;YU\xcfmf{\x8e\xda\x11\x0e\x90\xb1Z.-\xed\xb6\x94\x17\xcc\xd6,i\x9c\xa8\xb9\xf0u\xa7'pY\xef\xfd=\np\x06,\xd5\x9cr4\xeb)>\xee\x8f\x9e\xd2G\x80\xf6\xd1\xa6\xf1\xa6\xf0\x8c\xf7'\xa7\xbfZ\xdd\x84\xaa\xf2\x9d.\x04Je\xe6RH\x07\xb8\x10\x97\xbf\xd2\xf2WR\xfe\xaa6_/\xf1^\x88\xae\x03[t\xf5`\x0e,\xd8\xa2\xcb\xa9\x90%z\xa1\x0b\xbe\xc3\xcc7\x10\x9c\xa5^0\xe1*\xd8\x9ae\n\xd3\xec\x0e\x8e`\xc6\x0ci77gf `4\x991 `0\x99\xb5J\x00i7ia\xd6KZ\xda\x8c\x83\x1f!\x01\x0c\xe1\x18\x8d\x90Q\x02\xe8\xc31\x84f \xa0\x8c\xa5\x82\xa8\x98\x92>\xb1\xc6\xa4\xb6\xb8q.\x82\x92\x9b\xe3\xdbf z\xd3\xba\x7f\xad\xc6\x96\xf5\x90\x1a\x98:\xaf\xad\x11\xc9\xe4\xff[\x1b\x1a\xb66\x84\x1e\xfaz\x0cf=\xbdp\xdf\xd4E\x10\x86\x1cm}\xa5\x10?X\xac\x0f\xda0@\\X\"\xe2\x87\x984\xd99\xba\xa8\xf1\xe5\x1f\x1a\x03\x03\xa9\x91\xfe\xd4\xd8t\xa6\xeacz&IB\x07s\x1c\xcc)\xf9\n\xb2x\xa1'D\xff\xde\xc1\x0c\xe5\xa5O\x7f\xce\xed\xa9\xf7p\xc2\xf5z\xc9\xda\xeeU\xadud\xaf\x17\x17Fu\xc3\x1d\xee\x8e\x96\\\x02\xea!\x9e`P\x9e\xe3c8\x84\x1f)\xfd{\n \x8ca\x08[\x908\x0e\xdahk^\xf4\x1a\xf0\xfb\xb5\x06\xbc;z\xba\xfbt\xff`\xf4\xf4;\x8dz\xd7<\xea\xbc9\xac\x1d\x1c\x16\x03F\xaf\xc1}\xea\xbd?\xbeea\x99\x96j\x0b>y\xf4\xfa|U\x1bQ[J\xc6\x90\xeeB\x04\xc0\xc0e\xa0v!\xe1<\xae\\\xc7h\x87\xbd\xa3\x10\xd8\xed\xd5\x87\xb7\x8f\xee\xc3\xa1\xa1\x0f{#\xf6\x8e\xf6\xe1P\xe9\x83|\x97\xa9t]\x1f\xfb\x1d\xe1\x15\xd7OI}\x02\xff\xfd\xdf\xc4U\x83`\xe6p\x8a\xa9Z\xfe\xfb\xbfs\x97\x9d\x14,\x0c\xe5&=\xb5\xcb\x1dBD\xc4\x11B\x0f\xf6\xf2Q\xeaT!\xc9\xec\\\xf9&\x17\xdf\xe4\xe57\xb9\xf4\x0d)\x9f\x10\xc7`\x03\xecT:\xcf\xd2\xea\x1aaa\x0c\x90\xb9\x96\xfc\xa4\xa4\xc0`K\x8d\xcb/\xae\xb8\x0c\xf3\x9b\x08q\x86\x81\xbb\xa81\xe7\x9cNH8\x19\x13S\"\x80\x0d\x04)\x00\xd2\x95\n\x07\xaa\x85V\xf7\x80P\xd8\x0f\x11\xd5\xe0\xedYO\xb9\x1a\xe1\x92\x19!\xb8A\xaaM\x90\x13\xb2|\xa3\x05\xf7\x89\xe56!\xdcgoX\x12G\x9b\x9bt\xd89\x17\xae\xffxB\xe9\x1e\xe7\x88\x13\xb5\xec\x1b\xd8\x84\xf0\x12~\xd4\xb9v\xebIY\xfd\x88_\xfccF\x0c\x9b\xb0\xb5\x95\x8bq\x1f\xe1\xd2\x1et\x0c\x97~\xf0\xed\x03>\xec\x83\x10\x84\xc6\xa9\x1c\xe3\xd0U\x15\x1cl\xe2\xfa\xb48\xdco.\xab^\x8d\x8e\x0c\x8drK\x0f\x04\xca\xf0\x12\xcf\xfc~\xfdhN\xf6\xb7\xf5\x03\xa9\x8dZg\xfa\xf4cg\xf4Hx\xec\xaa\xfd\xb0\xcd\x00\x91\x1f\x8d\xf0\x11\x8b\xf37\xdc?88\x18\x0d)\x17Q\xbe\xdf\xe9\xd9\xedG\x82\xaf\xd1\xedF\x1f(gc+#\x18\xee7\x87P\x1b\xd5\xcee\xab\x08\x9fv\xfb\xff:\x8c\x06\xcfN\xf8\xe7\xc3\xd1\xa1\xc3E\xe1[\x9cv\\%\xb76\xa5\x12(X\x1d\xc7\xedF\x07\xff\x10\xf4W\x03\x8c\x84\xdb\xd2\xcb#$/\x9bX0T\xb0`\xda\x0e\xa4P\x03\xa4\xd0\x08\xa4\xb0\x07\x90\xbe\x13\xcaD\xdf\xebr\xc5\xa3:\xefG\xc0\x88\x10[\xd2>@\xaf\xd3\x9e\xd8u\x0d\xe4j\xc4fM8\xde\x88\xd8\xaaF\xe4b\x84\xfd\xce\xe8`\x9f\x0e2\x86S\xc6\x08\x0d\x86\x07\xfb\x03\xb8\x87\x18\xc6\xdd\x14\xc8\x1a8\xfa\xd1\xc3a\x83\xb8\xaf\xa1\xf0?n8\xdf\x0f\xd5\xaf\x87\xe9\xebx\x92>\x1b\xed\xf6\xean?\xe8\xf7\xef.\xb6\xdc\xect\x0f\xe4\xde\xd5\xdd\xd7Q\xe2k\xb0\xfb\xe3\xba\x9b`\x95\x95\xa2ac \xb8\xbe^\xdd\xf8^Pktc\xd8\xb7\x1b\xaf\x92\xe2:\"\x8f\x04\xc7ag?\x06\x82\x01\xed\xd7\x8fG\xc2\xa3\xbb\x1f\xc3>\xfd@\xe6\xd9\xc8\xcd\x18\x848\xc8\x86n\x92\xda\x01\xc7\xacXPm\xfbF5 P\x0f\x93\xd8\x81-\x8a\xf2M\x8e(\x899\xc6_\xd8\xe2\xf4\x81\x1b\"\xafBN\x13AI\xc4\x8dc\x92\x15eD\xc4 \x10\xd8\x86\x84\xc9\x81\x8c\xe8\x8d\x16n\xc5b%$\xb5d\xc2?\x10\x921\x161BSc\xa4$AS\x88\xcfJ\x88nm%\x18 \x8e\x93\n\x1a\x90&\x02\xa4\xe1w\x03i\x83\xa8h\xb7`\xd1\x00U\x85%E\x16{{.\xeaQ\x8c\xf9~pv\x10\xe4\xb3(IP\xd2\xcd\xb1\xb5\xbc\xca\xb8\xc9\x7f\xaf\x81\xe8(\x90o\x1e\xcb\xc8e\x92\xe3\xb6\xd1\x9cj\xb6\x87[\xcd\xd9\x90\xcd\x19\x8aH)M\xf5\xf7Z\x03,G*=|z\x0e\xb27\xa5\xfc\x07\x0e\x92\x8fF\x1d$\x1f\xbbf\x90\xc3\xb5\x06\xa9\xa3V\xbey\x90\xbb\xae$\x12\xef5RF\xb3\x88\xd1\x8ev\xa5\xe1\x8e\xaa\xe7\xc3}\xc3\\k\x963\x85\xcc{\xfd\xf4\xb7\x92E\x12d\xfe\x80\xe9_\x1f2\x06\xa8\x0c\x0dP\x19\xe9\xd7\xccN;d\x86\xbd!\xb3\xe6\x11+\xa4\xc72X6\x8c\x06G\x02\xd57\x8e\x07\x0c\x1d\xad\x97\x9d6\xce\x96\x84\x1d%[\x1a7o\xbd=\x18\x9e\xc5\xfa\x83\xa5#J\xef#Op_:n\x88\x10y3\x89z\xc1~\nsLv\xb6\xd3\x01]\xe2\x97\x05\x86(r\x95s\xdf\xa6\xa7\x94\x0f\xcf\x9e\xc1\x80\x9e\xa3\xc5w9\xaf\xd6\xa4\x00\xfeO\x99\xe8\x16*\xe2\x9b&[\xcc\x85D`\x84\x15\x81\xb1\xf6\x8co\xfecf\xfc\x0f!P\x86\xa3\x03\x17\xb6\x86\xa3\xc3\xb5i\x14R\xd3!Q\xd02\x9f\x84\xe1\xb7\xd0/\x7f \xf9\xb23:\xd8\xa7cE\x19B?\xd4\xfe\x07\xd20\x7f \xf3\x88\x81\xfe\x81t\xcc\x1fH\xc6T\xf9\x10\\%\xedA\x8f!\xb7\xcfm\x0f\x12\xa7F\x12}\x13A\xf3\x07\xd23f\x10\xd5\xb7o\xcdHB\xec\xe2\x1eP\xfc'\"~\x0c\xf2\xa7v(\xbeR\xe6\xac\xcb\xab\xa2ji\xdd\xf9RZ\x1a\xf6j\xc9$Ejo\xea\xedc\x06e\x12\x14\xad\xd5T\xe7\xa8\x82du\xb7\x1e\xddR\xa5\x9b\x1c\xa0Cd\xe9\"X\xd9\xd5\xe7\x8a\xa7\x97\x94\xa5\xa42E\x90\x0b\xd0\x0f\xf3\xb2F\xae\xe2HK\x12\x10\x9d\x17\x98\xf7eWz\xa7\xb0\x11 \xa5\xea\xa0\xdc\xad\x8e*\xf26\xc3\x9b\xdcO\xe7$?\xcf\xfd4\xef\xce\x86Z\x9a\xf1\x003\xd6T\xba\xa1o!K\x8a4 k\xb4\x90\xb6\xf5\x97\xd5v\x16O\xbb\xebJ\xeb\xce\x17%\xf4\xeb3*\xd9_\xe5\x18{iK\x9a\xa8\xda\xcbM\xadU.\x12\xb4L\xbf\x95\xea\xe3\xd6\xe3\x1cTn\xa8\x18t\x99+\x07\xb1\xc5\x96\x904 \xb0t \xc3#HxV\x83\xad-4\x0bK`\x13\x10I\"\xae\xa3w\xba\xb8/\xa5\x93\x11eA\x86d\x07X\x18\xaf\xf5\xb2\xfe\xb105\x8aY\xda\x1a\xedk\xf3\xb9d$\xaf\xf2\xb8\xd4Lubf\xf6\x14:\xfa\\\x98B\xef\xd7\x86\x08fa\x14\xad\x87\x084NWkg\xb6\x16\xe9 0\xa4\x06?6\x95\x1d\xa2M\x9f+\xe1\x85\xe6'.\xcf\xba\xd1\x95\x19 $\xde\xaa\x16\xb0\xdcdy\x04\x18\x80\xe8\x18m\x8c\xc5Am\x88\x8ff\xce\xb7\xaa&\x9b\xd1\xe4\xc33\xf9\xb3\x97\x19\xbf\xfb&\xf36\x80\x1d\xdb\xad\xe7\x02NM^\xc5&\xcf\x8fF{\x95\x12`:-\xc9\x9b)\xcb-\xe2T\xe9\x17a9\x00n\xab\x87>\xca\xb5A\x08\xbc\xe8OB\xf8_P\xaca\xb3\x977b\xe4\xd4\xfb@\x07\xfb\x19N`{\xf2\x9f\x9b\xbfl\x0f\xb6\x9e>\xdf\xfa\x0f\x7f\xeb\xb7\xad\xab\xcb\xed\xb9\xc9\xf5\xe6\xd7\xf6\x10\xae\x80\xca\xd9S\xb0\x06\xe8\xf4_O\x13:V\x1e\xd4\xfbfh\xf0\xb5Q\x01x\xa3\x0f\xd0\x96\x03\x8f\x8a3\x84\xed\xce\x1c\x97\x95\x83L\"\xc2\xf3\xeb\xf2:\xb4\xa7P Y`\x9bFb\x07\x07\x9ea4\xef=qD\xef\x1d\xec\xec\xee\xb6!\xdc\x90\xe7\x873\x97\x80r\x93>\x83\xbd\xfd\x9d\xe1\xd3\xae\xc2\xf4b\x89(vh\x7f\xb6\x86\xb43<\x99\xc4h\xe7\xa9\x0b\xc3\xa7C\x17\x86\x87O[\xd0\xba\xb8\x82$\xce\xc3\xb8\xd0\xe7R\x12\x979{\x10\xf0\xbe\xfb R?\x19\xa5z\xf2\xf5O\xd4{\\$\xed-u\xb6\xd2\x9e] \x97\xc9\xfe\xce\xc8\x98BP\\\xfd\xa0\xe2\xfe\xc1]\x8e\xb9\x8f\xc6>lR\xban\x8b\xa7 8>\x86!3t\xd9\xe2\xa3\xd1\xd6\xc0O\xc5\x84\xf3==\xc6c>\xc9\xab\xfd\x1b\xb3D\x15]\xfb\x8c58d\xd9Y\xba\xd2\x1f\xf0\xce\xc4\xad\xe3\x10\xf37\x1a\xec\xf6l}\xb4^\xeb\xf0\xec\x19\xe62\xc0\x00\xdb\x98\xd0 \xa6w\xa3\xc3^\xdd\xc2y\xea\xd7\xaf\x9d\xf5\xfb\x85I\x17F\xa3]\x16\xc2\x03\xf6\xe1 \xed!\xf6n\x8d\xbev\xa0F\x1c\x07O\xd9\xa0\x8b3 \xd2i\x05\xc9\x94\xc0*1x\x91\xc9U\xb2\xf1\xee>b\xbc\x87t\xbc\xbb\xe4\xeb*I\xf3\x0cN\xe0\xf7\x07\x89v,\xc1\x106<\xd2\x1b\x9b7#\xf9E\xb8$I\x91\xc3\xc2g~\xa0\xd7\x84\xc4 B\xe6W\xf0~\xd04\xe0w7\x10D\xc4O\xbf\xa1\x89\xa2\xb9\xe0\x19n\xc5\x18`e\xef\xab\xe8\xc2\xe5#\n>\x95o\x16T\xe3\xc9 \xf3\xe2\xda`\xf9\x8e5\xf5\xd0C\xb6z\xecv\xd4\xab\xcf\xb7!\xaab_\xd4\x97\x81\xc8\x0f\xa17\x955\xa6\xef\x10U\xb2\xa5SF\xcb\xd79\xfc\xb7\xb6\xd0\xac\xab\x94\xd2v\x07\x0f\xa8&l\xa3Z\xac\x8d\x95\xa0\x1d\x03f\x9d\x11\xdf\xc8\xbc\xa6\xb4\x10O\xe5\x9b\xb1\x8av[\x13k\xd0\xeaU4-\xdf\x19\xe6\xc9\xd4\xa9\xda\xe2=\xad\xdf\x8e\xd5,\x89\xad\x1d\xa3M\xa8Y\x15\xcb_\xb6\xb4\x9a\xe8\x1e\xe7\xa9\xcd&Jb\xb3\x00C\xbf\xd4\x9f\xcdx\x12\xda\xe6\xc6Y5f\x04\xb3\xb7b\x1a\x0b\x9bW\x05\xa5X\xe0\x14[\x14\x01\xc4\xed\x08\xc3\xa7b\xdd.D\x92\xecuj;\xed\xfbu\xdah\x16\x89\x88\xc0\xc4L\xd2\xb3\xad\xb0W\x1a\x8a\x01\xfb\xd8\xc6KR\xa6S\xf4\xed\x083\x11\xe9\xd79~@\xb1d$\xe0\x8aA\xc4x\xf6\"\x9e\xf2cv\xe9\xa5El\x9b<\xfc8(\xe4&;v \xf0D\xcfl\x8f\xea\xe6N\\\xfd\x8ev&T\xa7\x98K^\x86U\x1a_\xe9\xa1\xdd\x16P\x12Q \xab\xc8G\x14\xc8b5h+\xa5\xabV~\xe1\xf6o\xc6\x8c\xc2\xc4\x95\xda\x06\xf9\x12\xf4\xc2^\xe2\xean\x08d\xf2K\xc6\x9b\xe6\xe6a\xad.@\xa3\x01\x8eL;\x1a0\x8f^\xfb\xe6A\x05\xd8C\xebN\\h\x858(\x0b\x9c\x15(9\xe1B{\x96\xe6\xe8D\xcaZ\xaa\xab\xee\x86n\xec\xaa\xc5\xc4\x8b\xc9\xd7\xfc\"\x0c\xbe\xb4\x12\xa7b\x9fR\x8a\x80\xd1\xbc\x8d\xb8\xcdM\x93!\x94W\xa8\xc5\x9e\xc1\xb0 \xce\x12\x17\xc4\xcc'\x93\xb2*\xea\x97G\x10onRr-f\x86XR\xe8\xe8F\x98\xfd\x883\x1b\xe4V\x80\x0fe\xf7\x98\x15Z\xa2\x07\x03\xfa_aO%T\xe8\xc2B\xb6\xabG\x00\x9b\xcfF> <\x1c+[\x8e\xd5\\\xd4\xaaM\xbc<\xcc#\x0cJz\x9d&\xb7\x19I-\xfa\x90\xff\xe6a\xf2\x13\x8f\xc47H\x07\xd2\xdf~:\xbf\x11y5\xbd\x1b\x92ft\xfeX$\x93\xf2>+K\xe3\xbb\x1b\xfcn:}\x1bf9\x89\xb1\xde\x1b\xf6\x12\xdd\xd1\xd9\xef\xd9L\xfcL\xc92\xb9!ja\xf6\xf4y\x14\x89\x17\x99xC\x96a.~\xafR\xb2\"q\xa3%\xfe\xf8C\x1c4\xea\x8d\xa4\xea\xccK\x8d\xef\xc0\xc9e\x1dz\xd7a\xdc\x99\\\xa5A\xb5\xae\xd2$ YV~\xccC\xa4HA\xf1\xea\x8d\x04\xb7\xd3\xb6\xf9\x16\xac\xd2\xb6\xa5|\xb6\x98\x86\xe9\xe3z\xc6>\xed\xeaW\xb1\xf4\xb3/=z6\x90\xb6>h\xb8\x10E\xc5o\x15\x19AEO\x90KL\x9c\xcc\x90\x98G\x84\x1a\xa0\x8a\xd8\xda\x90Uu:}\x0f\x06\xb1\x15\x03\xf5\xcb\x8aU\x19C\x83k|\xc4@\x9aH/\xd5\xe2\xd0\xca\xbe\xe6\xa4\x0bk&f\x94\xd8\xc0p\xc7'0\xa4\x88E\xd2\xdeT\x98jx\xc9\x835\xc8\x8f\x9a\xf4DlLx+duZ\xb0\x19\xd7\x07\xa8\xc2{\xb5\xd7Lt\xcfP{\xea\xa8\x02|\x9fb\xdep\xe2\xd7\xb1\xaeof\x961\x17\xd6\x86\x88\xa2\x19\x0b\xd0 \xc3&\x91\xa1\xa1GnHzW\xcb\"\xdd\x95\xda\x0c\x19\xb7x\x92^j\xf8\x1bts\xb1\x19W\xcdp2\x9b\x04\x17B\xc7a:\xb5\xd05s\xf2Z\xde\xbb1\xf15\xc2\xb5 \xc7\xb8\x84cN\x0f;8\xc5\xe0\x14C\x1e\xd98e\x07\x1c\xcb\xb9 )\x85k3\xa9\x9d\xe4-\xa0\x16\x97\x00]\xfb\xa6\xef\x03}6\xc4Y\x9a,[Yv;4\xcc\xc3\x83\xf1\xb8\x8f\xbc\x94dE\x94\xbf.\xe2\x80\xae%\x17\x9f\x04\xc9rU\xe4~\xce\xd9\x94\xce\xcd&6Z\xe3\xe5\x03\xab/#\xf9\xa7GWJgH[q\xed\xa1L\x0c\x88_\xb9wuE\xb2w\xc9\xb4@\xf6\x8d\xf2i\x98:\xd6/\xa2\xfc\x1dY&,soB\x9f\"\xda$\x02\x8b\xbedH\x94\x11\x1d\xe5\xcb<-\x82\xbcH\xc9\xb4D\xb6}\x18\xefGP\x99\xbeBe6\x99s+\xc1<\xb8F\xea]\xc8\xfeM\x1dg\x87C\x06\xb30\xcd\xf2*^\";\x18\xfc\x18X\xf5p\xbb )\x01\xe2\x07\x0bX\xf1\\\xbb\x94\x11\xf0A\x9c%\x9a\xa3\xc3Gk\xb0\xb2SG\x0d\xa0\xd0\xbd\xc6\xd3\xf8~!wYC\x88UR\x8bq\x1dU\xb5\xf9\xc3\xd3\x0dY_\x0e\x8e\xdb\x93\xe4\"Z\x84\x9cW\x08\x81\xd3~\x03F\xfb\x11N\xfb\xe5\x93\xb4\x9d\xee\x03i(^J\xa6E@l\x85\x13\xea\"\x98\xc9\x84R\xcb\x97\xcc\x18R\xa3\x8es\xe1\xf7\x07E %\xb1\x9fu\x91\xb6\x8f\x04L}\x99\xd3\xf5m'z\xb5\x97\xc2\xa7 \xee#\xb6\x87\xc3\x03\xe5@D\xc6\xc6\x1e\xed\xee8zV4\xb6\x87\x83\x01\xa5\xfc\xda\x1a\x00Y\x84'\xd2'$6Z\xabK\x83\xea\x91TLZ\x12\xcc\x18tM\x96\xb4\x1a\xea\xc1\xaeaD\xed\xcc\xf5\x86\x1c\x0b\xd5\xc4G\x8b=\xb6\xf1H>Z\xedq\xac*$\xeb\xfb\x8e\xc9\x9c\xc6`\x8d\xbc=o\xcf\xd2\xad\x12\x8d\xfd\xe1\xd5\x153\xd4\xa4\x7fO\x84\xdb@o\xf0\x8d\x0e\x0e\xd6\x86\x9f\xcc\x85\xca)\xe7j\xb2\xeau\xa7Q\xbf`\xf7\x0ev\x95\xe7!\x7f\xbe\xa7<\xa7{\xc7\x9ap\x9c\xf8\xbe\x88\xa2K%Tx!\x17\xf8,\xd2\x9d\xab\xa524n?E\x13\x04f\x0fx\xe1\xcf\xcb\xcc\xde\xdf\x01R\xd2\x89Bo\x0b\xcc|2\xe6\n\x16\x08c\x8ev\x99q'\nF\xc6\xc8&?\x16\xb0{OGz\xc8>\xdd\xeb\x9cx\x0d\xbd,\x96q\xc2\xdej\xb7E\xca\xb2\\\xc4%\xd8\x1e\xdb\xf7\xd1Su\x96Y\xdf\xf7w\xd41\xb1Uqp\xd89$\xc3\x0c\x85\x0c\xde)\x83w\xb26\xbc\xf5\xb2> !\xef\x0e4#\x91NXJl\xb4\x93\xd4\x82V\x99h\xce0\x89s c\xa42\x84U\x98\xf9\xbc\xab\xbdx0\xc0\xad>\x96\x90\x1f\x14\xfbR\xb5\xa1\x17\xc6\x0b\x92\x86\xfc\x149\x1c:\xcd3-\xb6w\x06\xeaL\x16\xac\xae\xda*\xac\xea\xb2g.\xf8\xd2\x9br\x80\x19\xae\xbd\xa2\xd2\"\xf0\x14I\x83#\x88\xe0\x18*uFD \x80\xe6\xda\xa5\x04t6\x89\x14\x18\xce\xaa\xfa&\xc1%\x8a\xb9\x94G\x94)\x93\x1f\xb4\xebwg\x86C\x879\xc7\x88@\xda\xc9\x0cfU~IJ\x12\xce\x1a\x84\x96_W\x95\xb9P\xa8\x0f\x10\xfbo\x08\xd7\x89\x94\xf8S\xff:\xe2\xb1c\x17aV=9a^\x80\xf5\xf2\xb7i\x98\xd7\xcb\x97Oxy\xa6q\x89\xa2\xe4\xf6\xaf~4\xfb\xb0\"1'\xd3\xeb\x15\xd5K\x94\xb55>,\xabL\xe2\x80\xd8\x16\x89\xa7\x96\x0b\xabvp6\xb5\xf4\x9a\xba\x85\xc3\xc1\x95\x18\xc0y\xee\xe7\xc4#\xf1\x94L\xe9\xcb\xb4\xd4\xc5\xd9S\xd6\x85.\x1d}c\x0e\xb16[E\x0d\xf4\xe2;\x99\x1d*\x1f9\x19.\xaf!\x17,\xd1\xaf\xbf\x86\xf3\xc5\xcf~N\xd2w~\xfa\xc5r\xd56\xe2bIRZn\xdc\xd0\x85\xcfI>n\xa7\x98\xc5\xe6\xd6\x00b!7[\xdf\xfc\xd5\x80\x1c\xb7\xd7P\xa6$\xcb\xd3\xe4\x8eL\x1b\xdd\xef\xddE\xc9\x9f\x86\xf5V\xacS\xec-]@\x8d\x12\xb5\xf1TK\xac\xfe\xa5W\xf6\x0d\xbd\xce4\x80(\x0b(d\xb9B\x08\xd4\x06\xa2\xc7\xc8\x7f\xfc\x10*\xfd\xb3i\x10\xb4\x88Q\xe1M\x19,I\xe1z\xc5\xbf\xea:\xe4\xb1Av\x80\x14Q$6,\xae}W\xdeGyM{\xff]\x0e\xca\x9d\xe1\xc8\xb1\x1f{\x8a\x93\xca=\xabT\x91t\xd1\xe8k\xf6o\xff@w\x90\xb3\x10\xf7\xfe\xd7G\xf6;\xb1\x07.\xd2\x1e\xdf\x00\xccu\xcbk\xa9\x94\xa1flvl\x1f:]\xf2\xbe\x90;~z\xe2l\xfb\x98$\xc2\x16\xc0\xc4@\x0b\x82\xa6\xf9\x1d*8\xf4\xb2;\x19\xc1 \xc3Pz\n6\x05\xd6F\x0bez\xd0\xd2\xef\x1b\x86\"\x1a\x9a\xb2}\xd4D>\xca\xf1h\xa7\xe7\x8cm\x8d\xf6,t\xb7\xc5\xedVP.\xde\x16\x9bH\x03\x1f8\xe6\x1b.I\xa2\xf3\xf07R\xe2\xad:L\xe8vl\xa4o\xad\xdd\xfa((\xab=*\x1a\\&\x16\x9cNi\x9d\x94\xb9I\xc6\xed\xa8@\\%\xfb\xda:-q\xad\xcf\xdc\xba\"\xf6\xe6$\xa7\xf7\x88\xac\xd0\x01\xca\xa7O\xcb\xf1\xa2czu{\x02\xc3\x81C\x0b\xa4$\"~F\x98\x84\xaf)\xa1}\xd0\xa8oc\"\xd2\xa9b\x83\xe9X\x05\x08\xbd\xf2\xdbD-\xd5\x0b\x06\x8fY\xe4 \xeb\xa6\xd6Y\xe8\xa0[\xec1\x8b\x10\xe0\xe8\xc0\x01\xda5\x0f\xbauO\xab\xe8\x03\xce|\x91\x92\x06@\xbbD;\xe2\xfa\x16h\xa5\xdf\x05Zi\x19G\xa9\x114Z\\\xfd\x01\xd6\x88\xc8\x00z\x98\xcd\x92\"\xed\x02Y\x8bT\xf1[\xa0\x96|\x17\xa8%R\xf4\xa9\xd4Q\xf5\xf9\xe2Z\x0bp\xae\xd6\xf1\xb8\x8e\xca\xf4Gg\x81O\xdb\xe4ju\x03\x7fmq\xb3\x98tO\x95.%\xfcy\xb7l\xc4p\x94\xa7v\xb2\xfe9.\xf7\xe8\xd1-s\xb9\xd1#\xc8\x08\x89\xfa\xda\xd1\xcb\x8a\x0e\xb5\xe2\x96\xe1P}\xce\x98\xfd\xe1\xfe\x81c[Y\x1aX\x1a\x9e\xff5\xefH)_k\xca\xdfX\xfe\xc1\xc2\xf1\xb2U\x14\xe6\xb6%J\xcaR\xd8\xd8\xde\x1f8\"a\xf99F\xca\xe8\x03$\xce=\x93\x9a\x05\x98m\x94~\xe1\xda-tr\x84\xc8d\x0d\xafx4FH\xe4\x87\x14s[\xb1\xbf$\x16\x1a\xd1$\xd5=7\x9fDIxi\xd2cK\x9f\xf9\xd5\x17>/\x87\xf2\xd6M\xf6{\x0c\x19\xb3H\xe0\xde\xcb\xb9\xe3\xb0\xa8b,\xb6\xcbi)c\x871\x14\xe2\xb6\xf64\xa9\xd6\xc4\x18\xec)\x89HN\xf0\xbd+\xbd\x92\xd7\x94c\x97\x93(3\x85\xe54\xb5hu\xf84h!\x87\x04\x14\xa7}&>Ja$a\x87\xdc\xfeZH\xa1sM\x94z:9\xf4\xc1\xa9\xc4A\xc0\xb8\xcb^\xa5\xd76\xeb\xa4\xbe\xf5\x9bo\xb4o\x10\x81\xef\xeckw\xdf\xde\xaeJ\xc53Q\xdb\x81Z<\xe3\xc5UYj\xc4\x9f\xab\x12\xbb\x80?W\xeb\x99\xf1\xe7*2X\xa1\xd0\x8ci\xb3\xce\"B\x0f\xc4z\x81\xa9T\xe0\xb5O\xc9\xe4\xbbz\x81\x05+\x10%\xb1\xbe\x82\x1b8\x81\xb4\xfeh\xd9I\xb47t7\xd0<\xc8\xe7Z\xb2\xf9\xe5\"\x8c\xa6)\x89\xc7\x86sx\xe9\xaf\xc6\x10zK\x7f\xd5$\x0b\x80 1\xcf\xfc`A\xcb\xf0\x9f\xfarAR\xc49-\x85?\xf4e\xf2\x045\x9f\xb4\x14\xff\xa9/\x97\xc4\xd1\xdd\x18f\x8dw\x1a\xca\xe5e\xb2\\%1\xa1M'^y\xd3,\xf7\xb1HI\xadl\xedA\xb3|m\x05\x8cA\x03\x1cy\x86\xc7\xa0\x81J\x98\xfd\xe4G\xe1\xb4,Rx\xf5'\x9aN\xa6\xc9\xea\x82\x99De\xa6.\xbd\x8c\xfc,\x1bC`z\xcf\xd7\xe4\x18\xa6\xa6\x12\xef\xc2\xafa<\x86e\xf3\xfd\xab\x0f\xef\xc6\xe07\x9f\x97J>\x8d\xf1\xe9\xd5U\xb6J\x89?\x1d\xc3M}q\xea)\x829>\xfdc\x90Nc\x93\x87L\x12\xf0\x94\xb2\x1e\xf6h\x7f\xbf\x12\x14V\xe2\xa5\x85\x9f}\xb8\x8d\x85\xc8P\x8b\x9cF\xfb\xaa\x9eO\xcf\xa1~!wc\xd8\xd0XA\xa6d\xa6\x7fqu\x95\x91\xc8\xfc\x0e)\x84\xb1\x9a\xbeX\xeb\x10\x9a\x19O\nI\x9cG\xbc\x94T\xbbJ'?\x8e\xfaU\xf3\x85\xdcI\xd5\x88_BU\xa1\xe1\x1cX2C\x03Y\xd2\xd4*\xd3\xeb\xcf\x7ff'\x96vE\xe6\x98^\x994_\xe0\x1ch\xb6\x16NA\xdc|\xbeJ\x93U6\x86B\x03\xff\xe46\xa6|PhZ\xd6P\x01\xa7\x8a\x0b#\xbd\x0f\xea\xc7\x88\x060:`\xa4\xcc\xd0\xfaw\x1d\x97\x06&\x0b\xf0\x15\xe8,\xc0\xd1\x9b\x96\x11\x04:\xde\x19\xd5S)\x84t\xf1\xe4,3\xcf\nm9R2s\\\x88\xc4\xc3\x19:\x98\xc0&\xa0\xd2\xcfqky\x06=\xb6\x84\x05\xe91.\x9f4\x8b1z\xb7^\x10\x9f!\x1d\x14\x96\x921\xe6\xb5\xb6Q([\xd3\xe6\x99\x87}f\x1f\x93OR5\xe3.\x05\xdfTg\x18\xb5\x05\xa3&d\x98\x0eh\xea\x80\xef\x05\xfc\x8c\x84Fl\x8f2\xe2\xc3\x14\xbd\x944\xcb\xb4T\xf2-J\xc3\x9e)\x85\x11S\xef\xdd\xc01L\x8f\xe0fs\xd3\x81\xc5\xe4\xa6n\xd8s\x83\x811\x9b\\\xee\xc0\xad\xf7\xa9\xee\x8f\xf8\xd0\x18 \n\xdf\x88\xb0?\xa3\xf0\xcat=\xa5\x9d\\\xa21\x87\\\xb2\xd9|\xb5.\x96N\xcd\x96\x8c\x02^\x9a\x81e\xc3\xe0\xfeA\xb77\x02\xba\xdag.\xac0\xa9&z4\x05E\x9a\xd2\x03\x10\xfc\x1aK\x13\xd4\xc9\xaa^Fp\xca&C\xb7\x9e\xd2 P\xbbWs\x8f\"\x0f\xae\xa4P\x9a\xa7G\xfa\xf3x\xfa\x89\xc5F\xf8w\xd2\xa9t\xa8\xc6\xe81\x86\"w\x19\x96\xa5\x7f\xf8>\xa0?\xf8:'\x1e\xc3*\xf4\x17b\x1eu\xfc\x12M\xd1\x13_\xf8\x0c\xb8\x94\xa8\xb4\x7f\x7f\xa8*n\" \xd4\xba\xd0-\xdc|\xb5\x00~8h\xce~\x0cj\xdd2\x16\x8d\x87_\x17\xd2\xf1kHg!\x90\x0e\xdb5\xe5\xf2\x90q\xd0T\xc5A\x0c\xdel\xe1\xe39.\xaf\xe9\x12mi\xde9\n\xb6\xf1\x0d\xd8\x86=\xb7e$F\xf9\xbb\xba~\x8c\xe2\xbd\x15\xf3\x81\x99\xd1?cqG\xcbj\xb0\xd3rM\xec\xb4t`\xd5\x07;-;\xb1\xd3\xbc\xc4NK\xc7\x85;\x86\x9d\xee\xe0\x18\x96GpG\xb1\xd3|rW\xc7Nw\x06\xecT\xeb\xd0\xbc\xd7\xfe\xe7{c\xea\xc2B \x81\x9b\xba\xfe\x9c.\xfe:u\xfch&\xb8\xa6Gc\x0bD\x90\x12\x0c\x8d\xc9\xad\xca\xa4i\xf0'\xe8&M%\xb1\xd3\x81\xe3\x9d\xdf-\xaf\x93HO\xe9\xa6\xebU7:\xd4\x9b\x0d\x0d\x0f\xbf\xcd\xd6m\x83C!\xa9\x0c\xd0q\xc1\x7f\x8b\xdd\xdb\xc8 \x81|\xaa\xaa\x19\x19\xd3\xbf\xdf\xb0#bt\xf5\xfe\xb0sdf\x94+E\x12\xe4f]p\n\x13r\x89\x96g\xfe\xb7\xc8\x131\x1e~cxJ\xf8\xbb~\x13\x11\x1aB\x972\x95\x1b\xa9\xechH\x13W`\xe0b\xd8lD\xe1\x11k\x7f\xc0j\xa4\x93I\xfbF\xe8\xddV\x02\xa7`m\x0d,J_u\x8c\xbf\xc6p\xe9$E\x9cUb\xe7+F\x1c\xea9C\xc4\xcb\x8a\x15I\xaf\xb8yq\xc5lU\xd6c\xacR;\x97eqM\xec\x15$\xb1\xd0E\x9a\xc4\x17\x98\x98_\xcb @\x87]\x8a\xb8\x84\x89\x82\x9e\x0b\x03\xd6\x8dY8/D=\x1a\x9f\x81\xda\x93\x87\xbaU\xf1\xa3\xc0\xd6\\\x0e\xaa\xd7\xb9\xc2\x88\xc45(\xd7\xe0Z\x9f\x80\x98\xdc\xa2\xe9r-.w f\xf8\xfe\xb6\x07\xfb\x9d\x9b\\\xb7kj\xa6\xceJ\x98\xd8\x97~\x1c'9\xd0\x86\x11\xc5%)\x14q\x19sH\xbb[\xbe\xcb\xa0\x1a^\x1f\xcaxyt@\xfb\xa0\x81@P\x10\x91b\x04_\xba_S\xb9\"\xe6\xfb\xdb\\\xdd\x9ch\x19\xab\x99c\xe5\xfe\xf02\x9d\xd0\xec\xe3\xc9\xf4\x87x.\x89\x93\xa8>\x04\xdd\x0c\xd9\x03\x17B1 g\xed\xc3\xa9\xe7\x8c\xb9\x06\xa0\xb5\x18\x0d\xab;M\xf2\x99\x16f\xab\x18\xff\xf7\xc3\x8cr\xa8\x98X\xe6\xfe\xbeK\xceT\xc6\xd6\xe6Lm\xccX*\xd2dj\x1b\x10|\x048\xca\xc7\xa5\x9c'\xed\x92\xf30S\xef\xfb{a\x06\xde\xc4\x0b \xefg/\xcc\xde'\xf9\x82EcH\xdd\xda\x0b\x06\x8a>\x04K7=W\xf5An\x83\x0b\x93\xfb4\xa1\xee\x04NBpjbB\xc9\x079\xd5o\xad\x99\x94\xac\x88\xdfo\xdd0\xcf\x1e\xf5\xe8\xc6\xa5\x133\xda;f^\xd61lb\xd4L\xccP\x85\xc5\\\xefL\xcf\xc1\xe6F\xf4[e\x81\x1a\xcby1\x18/\x8c\x83\xa8\x98\x12\xa1\x95\xe9p\x1fG\xef\xe0\xb2\xad\xda\xeb\x07\xae\xc9\xed[S\xb3\\\x9bEM\xee\xe5\xfe\x9c\x9b[\xd3_O\x9eP\x1e>\xa4\x8b\x88\x89\x92\xe9O<\x13M!a\x1f\xd0\xaeJkJ\x86ofa\x94\x93\xd4n]\x91PAn\x8b\xc7J.\xb1v\xaeV*\xad\x93\xe6\x84i\xa2\x16r\xf3\x15\x9c\x0e\x14:\x88\xdf\xf7\xf7hK\xc6\xde/WQ\x18\x84,\x1dIy#\x97 _\xa5\x12\xe5\x8d\xae\x8e\x9e3\x85\xb2A/J\xfc\xe9\xbfs [Y\xe0G~jq1\xbex%\xd3Y\x89m]\xa0s&\xbac\xc6I\xbc\xc5\xbeA\x84LO\xbc|A\xa0\xec\x7f\x14f\x18\x07\xdf\x87,X\x90\xa5\xef\xc1\x1b\xf1*%Y\x12\xdd\xd0\x13!\x99AV\x04\x0b\xe6\xed\xdf\x08l\xe3Y\xcdIe\x86=\xc9r\x15Fd\xfa\xa6\x82\x9c\xcf]\x08,\xd1\x01\xcb\x85\xc9\xa5\xfa\xc1\xd9\xd7\xe6\x07\x02\x9e\xda\x0f(m\xf9\xce_)\x14v\x03\x9etK\xf2\x1d\xa4\xd5X\xd0\x8b\x01k\xac\x95\xdf\xe3{\xf2kA\xe2\x80\x98K,\xfd\xd5\ns\x1f\x98\n\xcc\xfc(\xba\xf6\x83/c9h\x97\xb8\x1e\x94H\xf3\xd0q\xea\x8b+\x9e\xb0\xadx9\xc1m\x8af\x16\x9eh\xa9z\xa6\xf1\x15m6GQ9a\xa8\\\xe7\xa7|\x84q\xed\xf3#\x16,v\xe8H2'R!!U\xae\x08Fj\xd2\xd6\xae\x16\xc3\x9aP\xc9Jz\x15\xde\xab\xb3\xd7\xcf?\xbf\xbd\x10\xfa\x95R\xc1\xdf\xb6\"\xc4j\xa8w3\xbb\x0d1\xb2\x9c:h\x1d\xdc\x03?#0\x1ck\xe7\x03\x83'\x8a~)p\x9c\x0c\x0c1\x02\x0c\xf1\x96\xb1\x9d\x91\xb9\x1d\xb9b\xb5)\xd5G\\\\\x86\xa6\x04\xd3\xa2\xfd\xa6\x86d~N\x93x\x0e\xcc3\x141\x88h\x12\xd7\xcf9\xc3&|\x16J\xe9D\x9b\xba!\xe4y.SA\x0e\xa2\x83u^{\x92;.l\x90^\xf1_\xc49+[K\x17\n\xa2R\xf0\xe6\xf9\x8a\x04\xe1,$\xd3\x12-\"C\xcfQc\x06v\x92RD\x19\xc6\xf3\x88\xf0\x11r_]\x07\x83\xc6\xfba,pn\xed\xad\xa72\xb5k\x84\xb1\xd1\x0d#\\w\x18\x7f{\xfe\xee-\xc7\xde\xb51P\xbci\x1a\x81\xf4\xae\xd1\x7f\xb1\x8f\xc9-\x14\xb6\xe6\xdcb\xc7\xa7V\xaa#\xf0\xf8X\xf5\x05\xac \x93\xbb\xad1\xd7$\xf6\x86\xc3\x9a\x19\xdf\xa1\x96\x96K\xda\xe4\x956\x81'\xf4\xa5\x1aXLn+\xd4\x1e+\xef>\x9f_\\}>?\xbb\xfa\xf8\xe9\xc3\xc7\xb3O\x17\x7f\x1b\xeb\x92\xa1\xfe\xf5\xf9\xf9\xd5\x8b\x0f\x1f\xde\x9e=\x7f\x7f\xf5\xd3\xf3\xb7\x9f\xcf\xc6\xb0\xab/\xf5\xfe\xf3\xbb\xb3Oo^\x8aR\x87\xfaR\x1f?\x9c\xbfA\xd6@)>2\xd4\xfa\xe1\xa7\xb3Oo?<\x7fu\xf6J\xed\xc6\xce\xa8\xf9E\x18\xd3\x85\xf1\xea\xc3;\xc1\x10\xbfD\x19[\x97\xf3\x12H\xb2\xd1P\x7f:\x02'v\x89\xc7\xab\x0e z8\x98NS\xe0\xe2h\xe2\xbd\xfa\xf0\xeey\x9e\xa7\xe1u\x91\x93\xf7\xfe\x92d+?\xe8\xfe6\xd3\x7f\xdb\xf5Y$>\x13\x00\xe8\xf5U \xbez\xc7\xe3\x9d\xbc#\xf9\"\x99\xf2\xef\xf4\x98\xba\x94W\xccP^\xe1\x85\xd9\xcb\"\xcb\x93e\xd9_J\x18\x16\xdeU\xe3\xb9\xb0\x97\xe4^U\x9a/\x9d\x16\xba\x1f\xf0`]\x95s\xa0\xea\xd7fL\x12f[\xbb\x87\x96\x0b\xb3\x16co\xdaw\xa4\xcd\xbc&Y\x98\x877\xc4X\xa7\x1e\xcb\xf5\xab\xfc\xc3\x0dI)\x07E\xa6\xc6\xe1\x9b\x90b\x93\xc9\x95/\xc3F\x06~\xf2/<\x05\xe2\xb0 \xf8L\x1e\xa5x\xa6\xefd\x19*(\xb5\xad\xbd\x01\xee?\x174[\xb4ms\x03\xdf\x9a7\xe8\x9c>\xeb\x08[\xb5\xf0j{\x02N\x14sA\xf9\xd2\xbbi\x00:\x96k\xb1\x88\xad\xd4\x8e;\x0es|\xcd(\xaf\x17\x19\xbf\x92w\x1b\x9c@\xc4\xca\x07\xc6\xf2\xf5\xcd\x06'\x10\xb0/dD7\x99]6lv\xc4\xa5\xe1\xd7jO4\xbeq\xd6\xf8\xf9\xd6\x7f\\\xf9[\xbf\xfd\xf2K1\x18\xbc\x1cl\xe1\xdfW\xfb\xec\xcf!\xbb}\xcdn_\xb3\xdb\xd1\xeb\xd7\xf4\xcf\xce\x01+\xbcs\xf0\x8a\xfdyMo\x87\xaf\xf1\xedh0x\xb9\xc5\xfe\xbe\xc2?\xac\xf0hx\x88o_\x0e\xd8\xed\xeb3z\xbb3\x18\x0c\xe9\xed\xab\x03\xfc\xf6\xf5S\xf6\xf6\xf5\xab\x97x\xfb\xea5\xbb}\xfd\xfa\x95&|Is\x05\xbdyu\xf5\xfc\xe2\xe2\xd3\x9b\x17\x9f/\xce\xae\xde?\x7fw6\x06k\xea\xe7\xfeVJ\xfc \x0f\xa7Vs\xfb}\xfa\xf0\xe1\xa2\xed\xa34Ir\xcdg\xf5/\xae\xce/\x9e\x7f\xba\xb8z\xf9\xd7\xe7\x9f\xb4F\x85Ji^\x0e6\xc1\xfa\xe5\x97-o\xb0\xf5\x14\x81\xfc\xe2\x00\xa19\xe0\xc0\xddg\xd0\xdcy\xcd\xa0\xb9;\xd0t\xa3Z\x1cz\xae\x1e]\x0d\xb3,d\x8e\xd2\xf1\xd4O\xa7\x0c\xff\xeb\x91y\xcbQ=n\xa4\x16\x00\xb4DV\xca\xf7\xa1\xb3\xea\xfa \xa6\xfai'\x13jj!3\xe2\xc00\xf5\x03\xb7\xbd\xb2I~\xe9\xc8\nr\x8d\xd6\x15\x8c\xa8B|3ln7\x13)\x8a\xe6\xcdFS\xcf\xef\xceO\x1c\x1c\xee\xd4\x18\x8a\x1df\xa3\xfc\xd4\xc0W4x\n\x8a\xef\xfc`\xf1\x89\xcc2.\xe1Bi\xc7\x157\x9d\xe264:a\x87\x9e\xcfX&E\x9cK\xf6\xf1\xea\xd8P\x98\x1f\xa2\xb5\x94^.V eZ\xaf\xc6\xae\x7fi\x94\xe7\x10\xb5\xdf\x92\xce\xa7\xf9\xd2K\xc9\x8cI\x91\xe7$\xffD7\xff;\xda\xea'\xe2O\xefl\xc7#\xf1\xaf\x05)\x08z\x04R\xcc\xdc\x86_\xe7$\xffk\x92\xe5\xef\x93i\xe7\x8e(\xbb*}c\xb7:6\x17q+P\xb5\x8dxSRN+3\xb1S&\x94>S+n\x08\xb0\xeb\xfd\xe0\xf1\xf3Z'74M+\xe3\x8c\x94^4'\x12\x95:(T\xc6\xc4\x13!\x97/_\x05I\x9c\x93\xafF\xdfdM\n\x10\x90\xd6S\xeae\x8b\xa4\x88\xa6\x9fWS?'\x08\x14_\x9ft\x18\xf0\xacA-B\x1d\x82\xbe\xc3\xec1\xeb \xb0\xc5\xa8]\xf6\xd5\xe3\x16`\xdcc\x016\x11P\xdbT\xadH:K\xd2%\x1b\xef\x9b\xd9{\x12\x90,\xf3\xd3\xbb~\xfe\xcb\xc4\xbb*\xf0\xcb\x17~\x1e,\x98\x86\x8f'\x8a\xc51\x9ajo\xac\x9f\nk\xe81`\xf8=0\xe0\xc8\x10\xedo\xb8\xfbT\xab?\x1b\x19\xfc6w\xf6\xd4\xf2\x183\xad2\x08\x91\"YN\x93\xa0\x10\xd3\xab J'^{\xe2\xc7\xbb\x84)q\xf4\xb5\xc5\xfeM8\xc7h\x9erf\xe5\x93\xe6{\xaf\xc8H\xfa|\xce\x1b\xde\xfe\xe5\xfal:'\xbfl\xff2\xdd\xf6r\x92\xe5\xb6\xa6\xa0\xf6\x1c\xd0\xf8x\xd0\x8d\xd7\xf0\xa9\x00\xd9\x82\xcc\x8b\x93\xa9\xc1:*\xe69V\x995\xa7~W\x8b8\xedz\x8e\xa5\x16?\x9e\xc7\xb1\x8cK:\x00\xc3Y\xb2,h\x93\xf4\xd2\xc5\x1d\xa5\xd9\xbch\xc5Z\xed\xb6E\xbe\x8c0\x8a\x1c\xda\x8e\xd1;\x07\xc6\xd2{\x8aP(\x1c}V\x00\xf1\x8bi\xfd\xd6\xd6]\x84Q)\xbbv\xd2p\xc8=\x16(\xdc\xf0?\x94db\x02\\\xdd\x0b:\xf7\x95\xd9B\xed=\xa5\xe1\xea2\x0bf\xeb\xc1\x03\xeb\x89\x92\x82a\xf9\xfc\xe9\x0d\xc6\x83\xd2C\xe1\x1c+\x10\x85\x84\xd2\x94A\x8e\xb7\xaf>\xbc\x93\x7f\xb3\xca\xc5\xddE\xf2\x85\xc4\xec\xc6\xcf\xfd\x8b\xd4\x8f\xb3\x19I\xdf\xe4d\x89\x0f_\x87\xbcQ\xba\x9d\x9fG\xd1\xcb$\x8a\x18\xc7\x8bO\x94\xdb\xd7I\xba\x14\x0e\xca\xf4\x9e\x85t\x16O\xde\x91i\xe8ce\xef\xc2%\x1e\x80\xcc\x8d\x9b\x9e\x03S\x8a\xce\xde\xf9+\x97\xfe\xc52\x1f\xfd\x90\x8e\xe1\xd7\x82d\xac\xeb\x1f\xa3b\x1e\xc6\xfc\x0f\xfb\xf2\xfc\xa7\xbf\xbc\xc5\xb5\x8e\x05\xce\x7f\xfa\x0b#\\\xc5\xddG?_\x9c\x93yy\x9b\x84q.n$(\x9c\xff\xf4\x176\xee$e\x83f\xd15^\x14\xb3\x99\xa8\x8b\x82\xfb|A\x08\xfb\x9c\xa2\xa1\x8b\xd4\x0f\xbe\xbc\xe4\x00/\x1f\xb0\xbb\xa4\x08\xb0G\x96\x88\xe7\xe1\xd2y\xcc\x18\x99\x93\xa1(Dl\xd1L\x1f\xb4\x93\xee\xccb\x92iv&\xddK)\xdd\x89\x8d73\xe0\xfb-\xa8,G\x15t\x81\xce\x1b3\xee\x8a\x94`\xc8Q\x17\"\xba\x10'\xd1%\xdd\xee\x1e\xc2\xb5c\xcd\xab8\x91\xa1\xa62\xbcI\x17\x024\x1c\xe9\xb1\x08T\xe2eQ\x18\x10\xfb\xd0\x85\xada\x97!\xafi\xbb\x9b[\xeb\xce3\xd5\x99c\xea{\x04\xc7\xeem\xd8o$xj\xee \xf6\x10\x9e\xd0s\xbf\xb9\\\xea\xee\x07\xf6\xc8PNrd\xb0w\x0de\xb8\xbb\x84\xa2;_\x0fAJ\xb8pG\xe5\xbd8\x0f\xb7o\x8a\xd8\xde;xp\xe5\xe5\xe3B\xd2\xb5\x84\x8c\x1d\xdc\x1d8\xdeL\xd7\xc3=},\xe6&\xee\xee\xda z&\x82E\x99M\xd0\x1e%\xe6&\xc6D\xf6\xc9\x08\xb9\xf6\x93\xa0l\xac\xb92T\x97\x93\xbe3\xb9&\xa4\xba\x98\xf4\xdd\xbd=\xc7\xde\x18\xd4D\x95\xa3\x9d\x03\x87\xc7\xedq\xc1jF\xcf\xd1\x9bG^QR\x8eG\xfb!\xc2\xfe\xee\xaa\x9e\x82\xe3\xa1%\x06\x8f\xb0\xb6\x12\xd1\xc2\xae4>\xfee\xb8\xba\xabPooRK\xfe}\xaa\xa5\xa8\x10\xa8<]L\xe3\xf54\x895\xe1\x18\x90\xdbB\xff\xdb\x9c\xf1Wbl\x9b'\xa5\xaf\x84n\x8e\xcd\xaeK\xbc\x9d\xa1qn\x1d\xed\xe4\xfe\x13!\xf5\x162n#\xb6\x87\x83\xa1c\x1b\xa7\x9a\xb7{@\x11\xbb>\xae\xef\xef\x0f.X~#\x8c/\xf4\n\xe5+7\xd1x\xa9\x88\xe7\x1c\xcf_\x07\xe8\xfd\xe0\xda\x9aQ|c\xa3!Vn\xcf>\xadU\x8ftat#\x89\xddk6e\xb3(\xdd\x01\xc0\x02\xcb\x86\xf1#\x17\x1c\x81g0@\x1e#ET\xf1t08\x18>}:\xda\xdb=\xd8\x1d<}:\xa4,\xc7\x9a4\xfd\xb7d\xb5lM\xa1\x07[0d\xe6\xc0\xd6\xbb0fVs(\x12\x06B\xc9\x0f\xf8\x17\x0cyFi\x90#\xb8 \xb30\x87E\x9e\xaf\xc6\xdb\xdb3? \xd7I\xf2\xc5\x9b\x87\xf9\xa2\xb8\xf6\xc2d\x1b\x15\x99\xdb\xd3$\xc8\xb6\xf1\xe3\xad) \x92)ar\x9f\xd30\xbe\xf1\xd3\xd0\x8f\xf3\x13\xac\xb2\x96:\xa6L\x1bHQ\x8e\xf5\xc4O\xe7\xd9\xe4\x92\x95\x8bi\x15\x9f?\xbd\xa9d\xdfRb\x19\xd8\x84\xa1\xeao\xc4\xea\xc0Qc\xae\xb6\"\x8a`I\xb2\xcc\x9f\x13t\xb4\xcb\x08>\x8f\x93xk)F<%7@\xe2\x9b0Mb\x14\xaf\xd2\x8f\xf1C\x1cG\x06~<\x05\x7f:\x0d)\x80\xfd\x08\x16$Z\xcd\x8a\x08n\xfd4\x0e\xe3y\xe6)n27<,d\x95oHM \xc0\xa8\xbc\x04\x85d\x14\xf6o\x04p\xe0\xa70\x89\x90\x9d\xc2\x8c\xb8\xb3\xd4_\x92\xec\"\xf9\x98\xac\xe0\x84\xceT\xf2\xc8\x8d\xd1\x87\xbe\xe3IC)]CJ\xb7\xeb\x1c\xc9\xd3\xf5Vk\x8bI\xa7x\x03\xedj\xaa\x86\xf7\x998\x03\x1a\x91\x04\xa1\x81\xf4r\xe1\x1d\xd5\xba+\xa4\xc6j.Up\xdat\xb1\x1aW)L\xf0\xd9%\x93\x94\xc6\xcd\xc8\xc0\xd887T\xe9\xdb\xbcu\xcd\xca\x9b\x932\xf2z\xdf\xa3\xdc\xb5_\xa5\x1a\xaf7\xa5\xa6\x0fi\x99\x8ee\xcdJMu2}M\xbf\xaa4\xda\x0bm\xadl\xd6{\xd7\xaaqU\xd7\xd6\x8aa\x0f\xfa\xd7\x8a\xc5;k]\x1b\x9e\xb2\xab\xa2\xae\xc2Od~\xf6u\xd5\xb7\xb6r\x8d\xb2\xcf:\x16i\x0f\xa7F\xb9\xee\xfe\x8e\x8dR\x1b\xaf\x14\x0f\x84^\xbd\xa7\x1fu\xf4\x1dq\xea\xda\x15\xe3WR\xcd\x0c\xcfIf\xe5X@\xd7\x9e0\xea\xe8\xdd\xa4(\xd5\xb9d>\xa6\xe1\x12\x0d\xfc\xfaV]\xedk\xd4\xeb\xe9P\x07\xbe\xd0l/|n\x88\xe5\xa0[\xe2P\xcf\xc4\xa7\xed?\x93O1\x970~S\x16{p\xca\x185\xb1\xbd\xb7\xebx\xec\xbd\x9e\n]\xdf\xfdWs\x8e\xe1\x04J\xc1K9'#\x0e\xd9\xbf=\x7f\xf7\xf6\xeck@V\xfcx\xc5\x97)\xf13\x9cY\xc2\x1f,\xfd\xf4\x0b\x0b\xfc\xc0n9\xe9pR%v\xa1\xe5)\xcc\xec\"\xfe\x12'\xb71\xb0g\x8e\xe5\xc0&/\x85\x95\x9c\x82\xc52\xfe\x89'\xe5)f\xe3\x99b9n\xd9\xe5U^\xa4\xe4<\xf7\x83/\x17\xa9\x8fQ\xc6\x0codk\x19)\xee\x01\xad\x10\x9fe\xb4$\x86\x0d\x14\xc4\x87\xc3\x9f\xd1.K\xe9\xcd\xca_iK|\x0b\xd6 9\xedOj\x8c\xbb\x90\xd6_\x8a\xb1\xb6\xae\xec\x1b9\x1b\x01\xce\xd3&Xc\xd0G\x0c\xc9)e\xd79 .lT\xc1\xfcq\x1e0\xe1\x07\xa3\nM\xd3\xe1(\xa1\xb4\xd6\x8e\x83\xd3%\x8884E\x91\xa0\xd3\x94*>$\xa5\xff\xc8$\xb6wv\x07\x8e\"h\x15\xbe\x83\xf8\xfe`o\x88\x96W\x07{#\xb5\\\xe5j\x82\xe5vx\xb9]\xfew\x8f\xff\xddw$w\xf1G\xecN\xf1T\xe6\xaat\xe9:b{\xd4Hu\x11r\x13\x08\xf5\xb90\x8dP\xa5\\E\x15\x103\xf5\xe6L\x14NX\x0c\xaf&\x92\xc8L\xd2-\xd1\xd3\xb61\xaaeso\x1af+\xca\xc82O\x0fo\xb5\xf032\xfdD\xe6a\x963\x05\x08Z\xeeNbs\x14\x89\xc2&\x8d\xa0\xec\x0f\xf4Y\xdc\xb4\nJ\x99\xaa\xdd\xbb\x12\xcd\x8a\xa1\xa2\x01\x8b\xf6\x05\x8b\x1c/\xbdy\xc3\xcf\xb6\xc6'\xe5\x0b\x17\xeaq\x86\x9a@\xd4\x04\xd4\x14\xe1\xfaz\xc1\x03\xa5\xfc^\x9e\xfa7$\xcd\xc8\xc5m\xf2\x91\x96\xb3\x89w\x95\xfb\xe9\x9c\xe4\xb4+.dJN\x9bf?\x02\xbd\x18}\xad\xbe\x98\xe6\x97\xd9\x99\xc8\x1dj\x14\x03!\x9e\xa3|=\xa6\xd6@\x05\xb8\x00$\xd3M7#X\xd2K3\xfaX\x1d1@]\xe6\xd1\x1c\xff\xcc\xb4H\xd1\xc8\x85\x99s)PH\x95\xf1\xb7-\xef\xce\x8f\xf5 \xa1\xfb\x9a\xafj\xcd\xc0\x1f\xb3\x84\x93o[\xc2\xd0 \xc8U\xdf\x05\xadB\x80\x16\x9a\xa9\x0bw\xa0I\xc6\x04\x1c\xae\xd3\x86\xce\xd7\x0f\x82bYD~^.\x85W\xbcM\x92u\x19pb\xf0\x83\xa8\xd5R\xb2\xad\xfa\xf3/\xe1\xea\x02;\xde\xab!U\x15nj\xe8U\x98\x92 _s\x14\xab\x9e\x95\x9f\xc59I\xdf\x12\xff\xc6\x00\xa6\xd2\xb4W\xd7R\xb5\xed\xaajlf\xcd;\xe3 ]L\xabF\x7fRO\xf1\xe97\x1f\x8d\x86\x93Q\x1fy\xaeyb\xf2\x88\xceC\xdd\xc9\xa8;I3\xc3I\x1aUI\xa6~Ws0a\xcc\xf9\x86\xc9\xd1\xacK\x8c\x04b+\xd9\xa1G\xbe\x92\xa0\xc8\xa5y{\x13\x7fH\xa7\x84\xd3\xedh\xfb\x95}$i\x86\x1b?\xb7\x193&\x13\x94\"\x0f\x91\xdd\xd8\xdd\xf5^\xf5f\x8f\x11\x81n\x0cZ+\xeb\xcd\xb9\xb3\xca\x86\xad\x95-\xfaVfy(\xe9\xf4\xae\xd2$A\x93\xaa7\xaf\xea\xf5\xd6\x17\xd2M\x03\xadH\x1e\x00\xcdF\xd8\xcb\xb3\x1b\x12\xe7\xccl\x01\xe7a\x0c\x89\xa7\x7f\xd3D\xf4\x8dr\xd9\x0b\xee\xde\xa7\xa9\x83\xbfk\x9d\xb2\xa2\xa4\xdb\xfa\x19\x06ku\xe51S@ZOw-\xfcR<\xd6\x1cD7\xdce`\xd1H\xf4I/;\x9a\xe4,\xfbh\xc4\"\x81\xfd\xfe\xe08\x93\x10#H\xe8\xeb\xc2\x94_\x8d\xf3\x81\xd9\xebd\xda0b>\x1a|z\xd3p\xfa\xb1\x1a\xbc\xeeY \x866\x00J\x84o\x0f\xa3|\xa1I\x8b\xb4=\xa3\xe4C\x9f9\x00)6\x84v1\x8b\x0b\x835XI\xfc2\n\x83/\x96>\x90B\xa3\xdcK\xc6\xe6\xf6(\xfe*)\xae#\xd2\xb7r\xa9t\xff&\xde%EF^%\xb7\xf1:e\xd7\xac\xfe]r\xb3V\xd95\xab\xff\xbc\xea_\xb2\xbbj\x90\xf4t\xf6\x06\x92\x8a\xfeu\xc4\x12\xbcbT\xc0\xdc\x05\xeb\xba\xc8s\xb6Cy2H+\x8cWE.?\xc8\xd0\x14K~\x92\x93\xaf\xb9\x9f\x12\x9f?sZ\xbc\xa8[#s\x88K\xf4\xb2\xe98\x05\xa0\xea \xc4\x85\x87s\xe3\xcd\x03\xb3\xceV]'DDJ\xf59\x8bY\xed\xc8b:=\xeeH\x8dx\xa8T\xf2SZ~\x92^\xb6a\x00\x96/\xe8\x11H`=\xb4\xc5\xf9\x8a\xdb0\x8a^\xd5Z4=g\xed\x9bG\xae\xc7AX\x1dO\x81\x94N(tz\x0c\xfey\x14\x95lC\x17\xd5)\x98<=\xe0\xeby\xbc\x15\x12[\\\x14O6\xfcpc\xb4\x82\x89&\xf1\xe5$\xbflC\x8ab\xfcf\xf0\xeb\xc4\x06\xe2B\xf8\xa4\x86i\xd0=\xb7\xb9\xa1<\x87)\xef`\x8f=\xf1\xa0J\x90\xf2\xd4\xe7\xc7{\x7f\xca\xbb\x84g\xe8\xf2\xa3r\xc5H\x83\x9a\xfd\xa1\xdff\x7f(.a\x87\xe8O2\x03|p^\xba@O \xda\xc8\xab\x8dF\x1e\x83\x19\xf2\xccv8D.7\xa4\\\x91~q4\x11K\xf3 \xdf\xdea+\xbc\x99\xebU\x13\xdefR;\xc0\xbe\x05\x1a.X!\xba\xd2$ Y\x86U\xffo\xdaHW\xf5b\xcf\x04M\xe8\x94\xfc\x01d\x88%\xe1\x14V0\x86\xa9\xe32\x80Q\xaa\x0c\x93\xb1\xfa^JP\xd5\xfd\xd2/\xe6\x8b\x9c\xe9\xc2[\xbbyu\xb5*\xd29\xe90\x81\x89*S\x0fc=\x12\x91\xf4\xc2\x8f\xbf\xf4\xcb\x8f\x1d\xd5\xeb,\xef\x0c,!\x0b\x01\xf0\x8d,a#\x85\x97` \xd5$A\xfa\xe8:7!\xb9\xed\x9aK(\x83\xe9\xd1\xd2U\xd0n\xbc\xd5\xaf~1\xfd\x89\x16e\x82\xf0\x99\xf4n\xc3x\x9a\xdc2\xcb\x81\xb2b\x8d\x87%H\x87P\xeea\xe2\x85W\xdcKM_\xb8<\x0eO!\x16!o\x7f\n\xc9-\xc6t\xe5\xfe'?\xb3\xc6\xc7\xc0z\xd1\xdc\x85MffJr?\x8c\xfa\x00\xac\x04\x12\xfb\x84\xb6\xdb\x199\xbb5B\xa6\x0b\x89\xda\x16oCRZIy@\x1bf\xa3\xf8\x85\xe7\x17s\n5\xcc\xa3e\xfb\xcc\x0bT^\x94\xfe\xb7/J\xb5\x93\xcb\xe4\xa6\x13_\x10\xcc\xa7\x1e\xe4o\xe2\x9c\xa4\xb1\x1f \x01\x1d\xdd&\xa8El\xdb\xae=\xc4R\xe5t\xe8\x9bi\xab}\xe1w\"\xd3\xbaF\x9e{\xff\xae\xdd\x90\x92\xbe\xde$#1C\xcah\xd7\xac\xc7?\xbdTS8\xa9\xd5\xf7\xdb?nH\x8d\xbcLVwi8_\xe4`\x07\x0e\x8c\x06\xc3}\xf872\x85\x9f\xfd\xdcT\xec\xefdz\xcb\xea\xabl\xc5\x02\xbaz\xd1E\xb0,\xff\xe3\xf6\xffQ}\xdc0\x1f(\xfa\xcd\x05u\xab\xd6:)\xa9D\xbd,\x91G3t\x02\xc8\x14\x16\xe1\xd9\xbe\xa5\x10\x17\xcdh\x95-\xe1,\xc4\x86\xafl\xeat\xf49plo\xcc\x9f\x0c\x92\x90\x85\xcbaR3Q\xa5$\x958\x81P1Y8\x81\xd0\x01\xc2\x9c\xfe\xda\xa8\xb32}L\xddb+u\xca\xaf\x13\xcf_\xad\xa2;\x9eP\xa9\x95\xbf,+\xaby\xc3\x86z\x82O\\\xe5D`F\xa0\xd4\x11\xc6\xc6\xa9\xc8\xcb\x93rG\x17\xde\x1f\xff\x9b\xe9G\xc2\xf2\xceZ\xd0\x1aKR\xc6c\xacy\x814\xeai0\x92\xd2\x85\x0eGk\xd7\xb4\xa2-x\xb2\x9e\x9e\xfa\x81C9\xc7\xd8\xb4(\xcb\xade\xf7\x95T\x9e\x0f\xf6zV\xc8\xdc.\xb8\x0f\x8a\xe3\x9e\x1b:\xd5\xf3?\x81A\xaf\xda]\x16*\xbc\xde\x9a\xe8i\xea\xc7\xd3diw\xfan\x18\xbak1\xf36\xdb\xf2\x82$\x0e\xfc\xdc\xae\x85\xc4\xc74\xc6cJeX\xce\x95\xe5\x82\xbd\xb9\x19\xc3&\xa4Ne\x0e\xb1\xb3\xff\xf8\xe43\x8dh\x06<\xb5e\xe39Sp\xec6\xe6\xcb\x07\x83\xd5|\x05\x8d\xdcc\xd9o\x87\x83\x81\x03\xa7\xfa\xd2\xd0-ZF\x94V\x06Y\x0d\xe9\xf2\xdd\x188.\xa46\xe5\x9d\x13\xa7\xdd\xd0\xdd\x14\x8c\\\xb6v\x7fh\xb4g\xcdInQ\\\xc1\xacW2q\xd7t\xfc\xb2\x9e\x07\x94aKR%\xdc\xb4\xc9\xf3\xcbBw\x0c^7\xe5\x0cE\xb2i\x0f_P\"\xf1\x11KTsP\x89\"\xeb\x9a\x17\xc7e\xce\x88F\\\x9f>=\xc1\x9d\x11\x9002l\x9aY\x94$iW\xef\x0c]\x0b\xb3\xf7\xfe{\xf4\x81\xd9\xc44\n\x03\xe6\x12\xc3v}\nc\x88\xd7O\xe8!\xe1\xa4Q\xaf\x87J\xe3>\xc3\x99\xa6\x91\x1b\xb4\xc4qn\xf4\xc1 \\R\xcaK\xddh\x98\xd6\x88\xcb\xd4\x93\x9d\xfe=\xd1\xb0n\x9aO\xea\x9d\xa91p\xf2\xa5\xf0\x8c\xba\x05\xd9\xe7\x0c&\xd5\xa9[\x92ofC\x08X\xe3\xd05\xef\x97\x7f\xa0\xe7\xaa\xd9Gr_\x9f\xc8b\xcf\xe4\xc3\xd9\x89\x0eR;Y?\xffZ\x97\x98gO/\xe69\xd0Iy\x98\x87Y\xf3\\\xc4A\xd5\x1f3\xbd\xff\xb0;\xc7\x9e\xd9\x14.cF<\x1ao[\x96\x94\xdeGk%\xcb\x82 \xb9\xd4\xb9\xf7\xa2\\\x7f`\xf0\x06\x8f\x1a\x11\xd8C\xb3\xe7\x1cH\x82']8`!^\x9ad\x97]\x84\xaaT\\\xe3%\xe72\xef<6\xa6f\x02\x0ds\xc21X\x1f,\xd8\x84\xcdMM\xf2oq\xddj\x93l@\xe3\xdc\xc1'\xad\x92\xf9\x99H\xeb\xa2\x8dfB\xaf\x7f?\xfb\xdb\x184\xf6#\xef\xcf\xce^\xe9\xd3\x17\xce\xfc,\xffw\xa2\x86\x873mg\xcc\x1a\x90\xc8A5\xb5n\x0b\xcc[]\x9f\xb6\xf2\x14\xacs\xca\xfdX\x1f\xd1X\x9f\x98e\x1d\x1b!NOk\x04a,\x97\xd5:\xf4\xdaj\x97{lT\xd4\x9bu\xd6R6P]_\xc4\xa5\x9fLq\x86N\xd2K/lNl\x13\xf2s\x92\xffL\xfc/\xeb@\xfeQ\x00\xd90\x84H\x84&<6\x86\x7f\x088zi\x05\x92\xf8uJ\xc8o\x9dBn\xa8*\x8f\xd0\x1e\xd4\xa3\x8b\x9b\xfe\xc2\xd8vO\x9e\x80\x00\x13\xfd\x1d\xd8u\xb6K\\:\x02\xb0\x8d6c\xfc\xee\xef\x0fe\xb8\xe77\xd9Y\x19yC\xfb\xf5Z\xb4\xc9\xef\xdf\"]\xd6W\xadw{\xcf]\xb0\xaa\xc8F\x0d\xf7w\x8e\xf2\xe4xG\x947\xf7^\xbe={\xfe\xe9\xea\xc5\xdfPs\x847\xf8\xeb\xfd\xd9\xcfW\xcf?_\xfc\xf5\xea\xecS\xf5\xe0\xfc\xe3\xd9K\xfa\xe0\xea\xc5\xf3\x8b\x97\x7fm<.\x1f\\\xfc\xf5\xd3\x87\x9f\xdfkJV/J\xc5\x05\xedCLn/(}\x1b\x9f\xa5\xed\x9eg|u4\x97\x0e\xc5A\xda\xa8\xcd+\xff.J\xfc\xe9\xb8%\x83$\xd4\x89y\xb5C\x18/\xf3[z\xa59@\xca^\x91\x8e^\x9c\xafH\xf0\x8d@\xc9\xbe\xbd\xf9o\x06\x81&\xbe^\xef>\xbf\xba\xa6;\xd7j2\x01\x0d\xc4]~\x9c\xadH\xa0i92\x1f\x02\x8dO\xb5\xad\x06\xbac\xa5\xfc\xd4/\xf2\x85\xa6\xd5Y\xedT\xc2\xd2\xb8\x80\x95b\xab\xaa\x18;\xc9\xaa\x92W\xd7w\xcc-\xb37_\xb6\xaf2X\\\xc6\xaeK\xdcY\xba?3\xa5\xc0\xe5\xda\xe1C\xdaH\xed\xfb{\xb4\x0fa6?\xc4\xa1\xef*\xeasMfs\x7f\xc7\xe1\xec\x96\x0b\x16s?5E\xaf\xeaE\x98H5\x0f\xf4\xee\x88\xfb\x0d\x19\x0bO\xf7?\xd03\xb0\xfb\x03\xbd\xf0e\x7f\xb0\xdb7\xdc\xb1\x10nli\x98\xa1\x98[U\x01W\xd3\x0c0\xe6\x16W\xe2\xd6\xd7\\\x92r?c\\@\xb6s\x04\x9b\x9b9\x1cCl\x0c\xb3\x99\x1a3\\3\xafa\x92\xdb)f\xcfK'\xc3\xcbv)\"\xbd2\xd9\x0b\x98\x9f@\xa9[{\xccm\x0fO \xa9?\x9f\x13\x96\xfc\xaa\xf6p\xe1\xa3\xe5J\xfda\x86%\x8b\xbauK\xb6\xde\xdc\x0f\x07{}$c*\xd8$\x93\xd0\x13)_x\xbc\xb5u\xd4\xe4C\xb8\x94~\x12_\xb2\xfc\x83\x92\x19\xb0\xf6\xac\xd8\x1a>z\x8f\x0c\xba\x93\xd1kFS\x0d\xe4\xeaj\xea\xe7\xfe\xd5\x95\xb6_\xa9\x9d;p\n\xf1D\xc3:\xe7\x94u\x16\x8f\xc7`-\xfcla\xd1\x134\xf6\x96\xfe\xea\xd1\xe31\xb8C\xed7\xe2\xf2\x89\xf0v\x06w\xa8]\xfd\xc6\xec\x11\n\xd7\x84\xeeD \x9dlA\xde\xa5!\x85\x86.:\xc6)\xf86*\x93\x12\x9b\xe0\xba tg\x89T\xddc\x94\xb8v\xc0M\xee\xdbZ\xbd'\xde-\xb9^\xf9\xc1\x97\x8fIt7\x0b\xa3\x88\xab\xe4\xa7d\x95\x92\xa0\x99\x17\x14=\xdeW~\xbe\xc8\xb8=I\x15z\x99\x7fY\xde\x9e\xb0\xf4\xb3z\x06\x8f\xb8`\xb1dM\xda\xd8f\xb5p\x91\x9a\xf0tk\xc5>#^\xd4x\xad0\xd6\xad\xfd\x0c\xffG\xfa\xa8\x11\xc64\xfa\xd8\x9c\xad\x13\x18>R_\xab\x9a&\xd4\x07@w\xdd\xf6\x7f\xda\xa7\xe3\xc1\xfdd\xb8\xf5\xf4\xf2\x97\xe9\x8f\xce\x9f\xb7\xbb\xb6\x88\x01\xa3$\x95\xb1\x8f>\xef\xfb\xc6\x86\xfd\xff\xb3\xf7\xef}q\xe3\xc8\xe20\xfe\xff\xbe\x8a\xc2\xe7\x9c\xac=\x18\x03I&\x97\xce\xb0,\x03\x9d\x1d\xce\x06\xc8\x0f\xc8\xcc\xce\xaf\xc3\x971\xb6\xba\xdb\x1b\xb7\xddk\xab\x9b\xb0\x9b<\xaf\xfd\xf9\xa8$\xd9\xb2,\xd9\x86\xb0{.\xcf\xd7\x7f@[\xd6]\xa5RU\xa9.T9\xd3\x18\n\xc9`\xc4*{\xf2\x04\\\xd5EI\xde\xf0A\xb2\xb1\xc7M\x87\x0b\x1e]\x80xX\x80\xc0\x1f`k\x97\xff\xfa\x0f\xf4e\xcfi}\x8c\xc5\xfb\x80\x99\xd2]L\xf5\xcd\x82\xed(\x17\xfa5\x8a\xe9\xa2\xf9z\x8b+\xd8\x18\xf1\n\x86\x03P\xba\x82*\xae}\xc8\xa1\x83\x90\xd2\xb1\xa1`\x1f^Y\xc8\x9dg\xfa\xfd\x99 w\x9e\xe9\x0e\xc6\x05V}\xa6\xd3\x99\xa5\x99*M\xc5%\x81^\x0d^\x18\xb9\x85\xd7&\xa4S7\xf7\xdats\xea&Zj\x8c\xa9\xa1\x96:\xc7\xd4\x95\x96\x8a\xe1\xdd\xea%q\xb9\xe1\x91\xe2m(\xfc9!\xb7W\x08vk\x97\xbb\xe3`\x7fQ\x97\x8c\xbb\xacqw=\xae\xd5\x947\xca\x9e\x84K\xb5X\xee\xf1\xd01j\x96\xf7E\xbeHJ\"\xb3%\x01\x0f*N\\^_\xd8\xc8|A\xa8Z_\x88YV\x8d,\xbf\x90\xf0\x93\xd6\xec\x8ao\x0fw=\x08ZK\xe3=_\xa62\n|c\\9r\xcf6\xfd\xbc\xd8\x9d\x8b\"\xf4\xc1>\xa4n\xc6\xdd\xdbh\xd7~\\\x81P*)\x18/\xf7\xf1Z>\xea\xbc\x967\xac\\\x9b\xa6\xc5z\xa6\xc3\xea\xc1\xe9\xb4T\xb1\x1cVE\xb5\xca\x96j\xe2a\xd5\xe0\xfa[\xaa\x98\x0f\xab\xa2\x82\x8fFn\xa3\x8a\x81\x8235\x05\xf2AV\x0d\n\x89\xfd\xecu/\x95e\xbf|\xce5\xaeG\x88nF`\xb4%\x13}W\xb4arq\xaa\xf49F\xb4v\xbf%T\xe1\xd8\xf2\xd5\xce\x90Au\xf2\x0d;\xdc\xb9>\x1e\x82\xe8[\x97x^\xcdJ\xc8x0l\xf3f\xf0\x03$o<\x94i\x91I\xee\xd2I\xb6\xb9y\xe5]\x19\x07\xcf\x8d\xf2\x90\xd7\x16\xf4\xa8\xa6_?h\x02\xccr\xfb\xfaZ\xb45\xb4\x0d\x1a\xacIQ&\xdc\xef\x92PE\x92IA\x92\xc5\xe4\xf3\xd9\xd4u\xd6;\x81\xe3u\xe7\xd8e9\x9e<\x11\x02:s\x8eW,\xcf~\xcf\x85cF>\xd3\xcb$\xd2n\xb1z\xf4u\xfaUX\x18V\xad\xd5X~\xefDa\x9a\xde\x84\xd1'\xa7\x92\x1eb\xf8Y\xb8!\x8aZ\xcb\xef-\xaa\xc5ka\x07\xc7c(\xb4\x94\xb3\x8de$\x8e4\x06F\x92\x0f\xa2\x85\x9d\x1e+_\x8b\xc2\x97|$*\x08\xe4LZ\x8d}\xa0G}K>\xed\x1a{ie\xf5\x11\x1aT\\]\xdb\xa2X&\x1f=\x10\x89\xfat\xe9w\xc9\xe7Q\xbbjU>\x93Ooo\x9f\xffk{k\xd5N\x93OW\x87\x07\xd9b#.D\x12SRS\xee\n\xb6\x90\xb3 \xb9\xb9B\xc8\xd0\x9e\xdc \x1e$\x93ps\xf3\xaaa\x8d\x10\xf6D\xe5\xfd\xe6YQ\xcd\x03zt\xfd\xbf\x0e\xbd\x81\xd68<\x14\xe3\xd5hL=wU\x07\x89\xdf{f\xcdx\xbb\xa6\xb5\x89\xcc/\x84\x97E\x93<2\xe9;\xb2\x92\x0c\x91\xe0$\xbb\xc2s(S\xfc\xc2u\xd9\xb5Y\x84\x10y\xf5]\xa9F\xfe\xca\x83i\x91/\x00\x9d\x83\x85i\x9aG\xca\xcf\x0fY\x19NI+\xe1\"\xcdo\xb5#\x81\x91\xa3n\xe2\x16\xdc\xa7\x0c\x0d*w\x94\xa1\xe7C\xe2\xe6<~b\xc8\xdb\xea\xa7G\xf0h0x\xce4\x1f\x0c\xceA\xe34\xc8rq\"\x88\n\xcc\x94\x8biRX\x0f\xf9\x1c\xdc\xb3\x8b\xbdg\x97\xd6\xc5\x8e\xeeI\xb0j\x9b{6I\xae\x0d\xc1\x14\x98\xc2\x05\xc2>\x14\xc14\x91Z\xc1\x8c\x86\x13\xaf\xcaoT\xb07\x8c],z\xaf\xf2\xe9?a\xec\xf5\xd2\x98\x16E\x01\xbe\xff\xc2\xce\x15\x01\xeb\x81`G{\x05\x87\x83h=u#e\xee\x8b\x97\xdf{\xae3\xcd\x8bq\x18\xcd\x9dA\xa8\xa8O\xe3\xf5\xd9\xaeY\x10\xf1\xcc\xe2\x06r\xf7\xb5.)\x10\x82\x88W\xaa\x18\xd7\x1dL\x8c#R\xc3\xf8$+T\xcfL\x8d3\xdb\xbaC\xfe\x01\x9e6\\\xe5n4\x84\xban)\x9c\xc3r\x97\xb1D\xb0/\x0c\xc2\xcb\xc6\xd1\xf5T\x04\x8c\x94\x8c\x0dFO[\xa1I\x13\xe7\x0b6\xd0n\x08\x93\xc3J\x7f\xd3\x89\x1c\x11\x93KI#2\x04\x97\x92v\xebx\x9e\xcf\x0d\xe1\x1b\xa3\x82Z\x91\xc6\xe0\xc6\xb0\x19\x96%kgP\xc5\x9fI\xfbs\x1d\xa2G\x8fK\x0c%\xdb\xfen\xee\x96\xac[ld\xb5x\xf6\xab\x17\xcc\x86\xf2\x83b\xa9|\xdd\xef@u\x0di^\x15\x945\xf1@\x06\xe6\xc5I\x1b\x8b\xf3LY\x1c\x86\xceh\xa5\xec\x03#H\xc4=\x88\xf8\x8e\x16\xe8\xcd\xef\x19\xb7qS\x1a\xe5\x1fqA\xd3\xba\x0f\xca\x17\x0d\x18$ \x945 \xac\x0c\x80P\xb6\x00\x01},\x98\x16\x1d\x05\xd3\x86%G\x9bd\xc3J7A\xc1\xa0\x01\xa4\x82B\xa9\xafv*V;\xf5D\x0c\xbd\xe8~(\xa9\xc6\x12\xadp\xb9\x02I<5_\x01={f2\x18\xcb\\\x8b\xb0rwW\x17nrt\xb7\xfbB\xc7M\xdc\xa7D[R\xa9\xaa\xbd\xb8TS\x82\xd5\x87\x88\xbe\x05\x97&\xb8\x8e}\x98\xfb\xb0\xf6a\xe1\xc3\x0c\xf6`\xa9\xaa\x89\xdbhU);n}dD\xa5Y\x94w\x87\xc2\x06\xde\x11\x06\xd9Oa\x04:\xbae\xcf\x0d\x92\xe0\xcd \xb6q\xc6\xb3\x1e\xe3\x8e\x84r8i\x99v\xb0\x1a\x13wf\xd4\x19E\xba3\xe6\xa6\x072F\xef\x1b\x88\xe1\x0fp\xf3\x06n67\xcd\xd46\xab\xd1]\x08G\xacwn\xe8\xce\x91T\xbd\xb9\xf2\xf0\x8em.\xee\xd8\xee\\L\xf3P\x06\x81\xb7_\x0b\x1e\x0b\xb2\xba\x9a]4!\x1a\xcd\x7f\xcd}\\\xc3\x1eTq'\xde\xc0\x066\xb9F\x8e\xc3\xf5\xbc \xce3b\xb8\x14\x06\xb5\xb3\xb9\xbb\xf6\xe1\xce\x879\xb7\xc5\xe3w\xc4\x03\xba\xf6\xd5\x0b~<\x1f\x1f\xfc\x99\xc7j\xa5\xc1\xf9\xf8\xf2\xc3\xf9)\xec\x89\xdd\xf6\x8d\xe7\xb3\xd5'u\x11\x1c\x8d\xdf\x1e|xw \xfd\xfe\xa9ww^\xf5\xf8\x9d~)\xfcL\xbf\x12\xff_\xdf\xdb\xdf\xb4BR<\xb7\xdcm\xec\xe8\xdb<1\\\xf1\xdc\xdf\x94\xd1rH\x85Fm\x8aD1pD\xee\xc5\x0d\xb1\x18\xddd\x83\x00\xad6a&\x1f\xec\x96\xd6+W\xa8\x869O_\xeaGCU\xcchc]}\xb5-\xdc\x0e\xa7}\xd9\x7f\xdep\x05\xa7\x07\x82\xc9\x8cxp\xf8\xda \xb39FQ\xde\xe2(\x10\xa6I\x16\xa6ig\xd7:;\x0eP\xb9&\xeb\xcf\x08r\xa4Q\x9a\x97b\x00\x9d\x05\x9aF\xe6\xdcu\xc5\xe0\n\x86\x0c\x0e\xba\xe6\xde\x93\xa8\x15{\x1a@\xba\xd2\xb0\xd9)\x81d-\xb0\x11s\x03a\xdbu\x8b|V\xed\xab\x05\x90\xd8\x81\xfb\x83GM?\xae\xff\x93U\xbcNh\xe7u*\xcffA$\xa0\xf8\x80\xbaa\xa7+\n\xae\x01\xd6\xa3T\xc5\x88,\xe7\xc9\xdfV9}\xd3\xe1\x8b\x83=7\x05 ?\xd9\xb3\xf0\xd6^\x0di-\\,\x1f\xa5\xb1\xd7C\x1a\xfb\xb7\xcfO_>Fk/:\x14\x0d\xa1j-}\x94i|\xd1\xa3b\xc8\xdb\x9a}k[\x83t\xd8\xa2<\xa3I\xb6j\xdf\x0c\x81\x95\xc5\xe3|0j\xf6\xbb l2\xfcX\xaen\xf8\xb5\xb5\xbb\xf2!\xf4\xe4e>\xe3@\x19+\xbc\xa9#:s\xe5b\xaf\xca\xfa\xf7Y\xc9v\xe50\xd2C\x0c<\x92\xbaH\x83\xea2\xfa\xa67\x851\x0b\x852\xb5\xd9@\xaf\xcd\\\x96\"\xbf\xce@ [\x92\x96FId\xb8\xb5\x9d\xa2p\xa1\x99\xb6l\xa3\xabvx>\xf6\xd0|yp\x93\x17t\x04N\xc8\xfe\x1b\xd0\x1f\xcb\x92%\x0b\x0c\xe11\xce\xe2\x11\x94\xae\x13\xca\x04\x92\xc5\\\xff\xb9\x99\xd4]\xcb1%<\"H\xb3\xaeD&\xeb5\xd6\x1f\xba\xeb\xbd\xa0!\x1b\x89Zg\xc9\x92\xf4\xfax\xa2\xb1\xae\x1f\xd3U1\x02\xe7&]\xe9&\xed\"\xc3a\x98\xbdO\xc3\xbb\x118Q\x98-\xd3\xf0\xae3\xdb\xe5\xbc\xc8W\xb3y\x9d\x9b\xf2\x04K\xa1y\x98\xcd\x08\xcb\x8c?,\x99RT\x01w\"\x8c e\xce\x92/\x96y\x99T\x0b\xe6Du\x82uu\x94Bb\x1e\xd5b\x1dS\xa6\x14\xfc\xb0\x8cQ&\xa0\x96\\a\x9a\xadhF\xc9gzB\xb2\x15\x16\xc2\xb7\x05\xc9V\xb6\xecK\x9c\xf8|i\x9b\xf5\x15v{e\xe9\xa9\x12\x1ek\x04N|\x93v\xcc\xe1Q\x11\xceX\xa6\"\x9c\xd93\xf0\xd9ey\xac\xd3\xca\xb3QRT\x19)\xb1\x80\x16f\xfd\x9cP\x99\xf3sb\x1bG\x11\xce0\xc0\xa3\xc8\x99\xb2\xdf\xf6\xacg\xeb\xaa\xf5|\xdd\xd5\xb8\\w\x96\xb3c\xc1\x8f\x8a|\x89\xb9\xf2\xa5%\xc3\x8ao\xd7\n\x9ec\x91\xd0\x05\xd7\xe3\xc5\x92&\x84\xcd'\xe1\xbf,\xd9\xb2\xa8\xb8[R\x9eQ\xfe\xb6e\x8dE\xb6\xd8\x9a\xa5(r67\x84\xfd7gy\x9bG\xabr\x04\xce\x94\xfd7g9\xce\x96\x08x<\x02\x981\xcb\x9f\xc9\xddQ~\x9b\x8d\xc0\xf9D\xee\xe2\xfc\xd6\x82\xca\xfeL\xee\xde\x17\xa4,y\xbe%\xfbi\xcd\xf8a\xc9s\xad,\xab\xf0\x0e-\x93\x19\x0f2\x92f\xca\x8cs\xe9\xca|Bh\x18\xab\x05\x16\"\xc1^H\xc2\x0c\xcb\xdf\x013U\xe0\xb8\x118\x0b\xf6\xdb>\x07U\x108\x99\x95qW\x1dY\xcfp\xee1gn\x9b~\x9e\x91\xef\x03\x9e\xd3\xba\x11D\x988\x99\xd16\xbb\xef\xc3\x121\xdd\x92\xfd\xb7eY\x95<\xcb\xaa\xb4e\xe1G\x89\xfd\x1ca\x19\x92l&\xf2$\x99\x05\x19\xbd/\xf2\x99\x80\x9b\xa5\xf8i\xcex\x1eRRm\xcb\"\xa4\xa4kKr \xdb\x08\x9c\x12\x7fX2\x11\xf2 \xb7Y\x89?\xec\x99\xf80J\xfe\xcb\x96-\xe5\x91=\xab.\x962\xa5\xb3\x9f4LS\xde\x07\xfe\xcb\x92mU. b\xec\x92\xff2g\xbb$\x9f\xa9\xdc\xd1T\xfe\xb6dM\x16\xa4:\xf3h\xb2 ]\x87\xdde\xbe\x8a\xe6\x87a\x16\x116\xa5\x94\xbdE\xf8\xd6\x91\x9d\x1f0\x98\xd7\xde_\xf6U\xec\x17\xcci\xdf/\x98U\xeeX\xcc\xdb\xb1e\xf1\xda/Q\xa9>Z\xa5\xd4d_3\xcdX\xd1\xcfy\xbaZ\xd4P\xb7\xc6\xd7\xae\xf5\xfc%L(\x87\x96[\xfe\xcb\x92mNp*o\xd9\x7f\xcd\x04\xb4Y`\xcex(\x1e\x85\xa6\n\xa2w|\xe4\xc0\xa6\x90\x18\xb9\x8d8\x04^P\xa6ID\xdc\xa7^\x93\x1dX\xa3j\xdb?\xbe\xa2VE\x93\x94>'2\xd2Z\x1d\xa4\xb0}\x990 p\xad\xa9\xa2~\xf99:\x8f\xf9)\xcc\xe2\x94\\\xe6\xcbwdMRw\x1d\xcc\x1b \x9e\x0f\xeb\xa0]=\xec\xf5{ll\x8e\xa2$t\x9ca@\xcc\xbe\xae\x19\xdb{\xf2\xc4\x98\x1e\xd4\xd5\xb6\\\x01j\xb3X\xb6\x9b7\xb5.5\x88\xdc\x0dc?\xbe|\x01\xe3\x87\xa0\xaa\xdf\xed\x0e1\x97b\x81\xcb|\x80S\xd1\x86\xa4\x98\xfa\xd0\xed;O>b\x00=j}\x95\x16\xde\\D\"\x99\xcc\xaf`\x0f\x96\x9b\x9b>D\x13\xf6&\x82\xfcV\xaf\xed\xe5\xe6\x11 `\x0f\x92V\xc0\xc6#\xc20%\xc9\xa2\x84\x94\x13r\xd50f\xcb\x87\x08\xb3P\xcb\x9d\xed\x1c\xabu[\xa1\xc7\x99\\\x89X2+\x1e\xa7\xd8\x91{\x9d\xcb\x86Wht/v\xbd\x07\xfbfp\xa2E\xb8\xfcqu\xc3\xd6\x11?(\xb5\xf8\x12e\x08\xb3\x9d\xd4\xe5G\xfd7\xd5\xa8\xd4 \xaa}@%Gg'H~\\\x88\xf3\x96W\xe4TGqc\x02\xe4\xa1\x0c\x1b;\x9d}\x16\x01o\x95\xf6\xaa\xea\xeb:\xee\xd9cC\x0d\xc6\xc2\xbf\x1c\x9f\x1e\x9d\xfdr\xfd\xd3\xc1\xe9\xd1\xbb\xb1\x1c\x0bR\xd4r(x\x86p\xbe\xbb\x1e\x9d\x9b\xba\x92\xde\x16\xa3s\xef1\xbc\xb7\xa2dUEf\xc1}\x96\xf2\xd8\x17_\n\x01 \xf3\x04\x90`uI\xe6\x08\x15\xd7\xc1\x93\xd5\xecO\x92\xf5\xf5\xa8U\x81\xec\x10\x96G\x1a\x97u\xca\x87\"\x10\x1f\x85N\n\xbeck\x98\xc0\xba\x1d\x9b\xf7\xd6\xb0\xb6W>\xc4\x93\xd5\x15\xef.n\xc7\xbdVHy\xe8;.\xf4Z\xfb\x03\xd5\x80b\x867\xa8\x9f-\x85bK7\x1aK\xfd8\xfdhB\xcf\x90\x8e\x88\xc86<4\xe9\xfbpF\xfe\xf2k\xcfA\x86\xb7\x17\xfa\xad\x1e+\xdd\xe9Kz-\x9c\x86\x9a\n\xba\x0e\xa2\x19\xfcm\xd2\xe3\x92\xf7$\xaa\xd3\x06UQ\xa0k|$+W\x85\xc0`?\x87\xe9\x8a\x9c\xe4YB\xf3\x02 \xba\xdeq*\xae.\x90T\xc0K\xdcu`\x984\x97\xed\x80\x0d\xcc\xb41\xed:|\xd8$\xac\x82\x82L\x0bR\xce\x95~\x95\x96\xfb@\xd3R/\xf8\x18\x94\xd2\xe8\xebzZ\x87\xecR\x1fm?To_-\x06\x08\x83<\x904\xc5\xd4Ur\xa5\xd1P\xb4\xe6\x94k\xb4^\x17\xab\x94\x94\xd7\xd7\x0d\xdd\xf0\xeb(\x8c\xe6\x04\x13-\xd7\x8b\x85Bp\\_O\x93,\xc6\xdcv\xaa\xa5\xad\xf7W5-\xc8\x04~\x8d\xb7\xb5\xfb\x06\xa8\xd5\xb1`\xb3\xe0ds3\xbbB\x85\x01\xae*s\x0fO\x83\xbe6\x82(_,\x93\x944\x07a\xbaB'\xa2\xfb\x06\x96\x83M\xa1\xe3hT\x0cQ\xc6)\xecI\xddn\xda\x8e\x04\x84\x13\x98\xfc~\xe3\xf5\x18\x07\xa8\x95\xa2\xae\xfe?\xd0\x07q\xaby[ OY\x92\xc7\xda\xe2\xae\xf3:\x86oD\xa9\xec\xc9\xd4)p\xd1!X\x86\x13!\x07G\xf9\xe0\xbe|\xd1Z\xe5#\xcd\x82if\x88M\xdd\x1a\xad\x0d\x1cB:\xd0\xf2\xa5\xa8a\x99o\x01\xa3\x11\x1a^\x12\xb1\xbe\xea>\xa3\x19Doq\xb5\x81B\xb5\x8c\x16V\xd1\xef\xc3\xa2$\x05\xb0\xe9C\xc3\xb2i\xbeB~\x1f6A7K\xd7\xf6Eq\x15L\xa5\xf1g\xebK\x98b$c\xfc\xff\xe5\xcb\x90]\xdf\x9c\x9d\x1b2\xcd\x0bb4\xf7k\xb9\xb1ZK\xcfx\xbd\x93\x94Hm\x9c\x8eI\xca\x1fs\x92\x82r\x89l|\xee\xc3\x8e\xc9\xf5!C+F\x13R\"\xd9K\x93C\xc4if4/\x0dS:\x82\xa4\x9e\xf2\xd6\xb6\xbb\xd7\n\x84SJ\x8a\xff=\x0b\xc0o~\xff\xa7-\x02\xc34\xf7@\x13F\x04\xa0M\x08\"/\xdb$\x18T[z'\xc10q8 \xc5cM\x02\xefA\x9f\xf2\x17\xcb\xd0\x0cJ\x8b\xae` \x8c\x00e\x06\xdc\xe3cs.\x86\x1dy\xf5Y\xd9\xd2\xa0\xe7\x87\xd9\xb0j4\xba\xa4\xda%fU!\xca\xce\x1e\xc3N8g]\x87E\x98\x853R\x8c \xc9\xd6a\x9a\xc4bg0\"\xc5\xb4'\xa0\x8d\xbd\xe9\x95:*=\x84\x13\xe6\xbe\xef:\xc5I\xd9Z(}\"\xdc\xeee\xf2\xfe\x17\xcc\xe5\xeec\xcc\xe5\x8cP\xde\xbb\x01jo\xc2\xcb\xc1\x9e\xdeB\x0d\xef\x15\xe1\xe9\xb6\xfa1!W\xda\x1e\xfd\xea\xdf\xdf\xf3{\xbf\xbb\x93\xce\xbd\xbb\xe6nC\nn1hq\xd6\x8e\x16\xc0\xc12/O\xc2\xcf\xed\xaf+\xf9\xb5\xfd\xa9\xc4OIy\x9c\xbd\x0boH\xda>x\x94\x8f^M\xc7\x9b\xf2\xa5,\xcf\x87l\x11\xd2hN\xe2\x8b(_\x92\xb2\x8e\x0dj\xfc\xbc\xb5\xe5\xb7*C>\x05{\x8bf\xf5x4)\x9d\x10\xa2\x14F\\\xed\xbe\xe1\xa3\x82\x1f 4z\x9ag\xfdz\xcd\x0fN7\x07\xa1\xca\xaf\xea\xecaq\xcf\xf3 \xdb\xdclCr\x15\x82\xfb\xf53\xe1\xdb\x11\xbd\x04\xb2\x9f[[V\xd2\x99\x0b{\xcc\xbc+\xea\x80\xb5\xbe\xb4u\xabP)\xb7$EP~J\x96\x97\xf9'\x92\xd9\xc3\xef\x80\xa2\x11\x0f\xfb\xdc\xc5\x19_l\xcb\xa4\xc3\x1e\xf7\x0cb\xfd\x9a\xc1\x16\x9ft\xbe\x06+}\xfeK\xff\xe1a\x15^\xdb\xa2`r)\xba\xeb\xfc\xdd\xf1\x8cq\xa5\\%\xb6r\xa7V\xaa\xd4w\xbd\xa8=B\x15\x02\x8f\"\xc1C]\xc7a\xc3\x17\x0d\xf6j\xa3\xa9\xf5\x0f\xd3\xb8m\xc8IL\xa1H\x9d\xc30\xfb=\x85(LSX\x10:\xcfc\xc830b\xd4\x96\xcb\x8d{\xcew+&\xa20S\xd8\xf5\x02)x\xd2no\xd0a\x87\x08\xe0\xe2\xe6M%\xf5^\x1f\xa4\x96\xc5H`\x1f\xb4\xaa\\\xf4:\xaf\xd8\xb1\xdd\x7f`}\x9d1 S\x14\xd5\x15jD8\xcdW\xb8\xc0\xb6y\x1b\xc1!\x8dd\xf2\x97\xedr\xedt\x19\xae\x9c\x87]+\x10\xe1\xc8\x18\xd3^\xdd\x9e\xa1\xe6\x8eJ\xd1?\xc7\xd9\xf4\xfeun\xfcs\xbak\x83\xe4<[\x93\x82\x82p\xfbKsX\x16\xc9\"\xa1\xc9\x9ap\xefON\xdf.\xd3\xd6\xb9\xe9\x0c\xec\xfb\x9d\xfb\xfa\xe5\xd0\xadpd\xd4w\xdd'\xb8\xf0\xf4\xf5B\xd7\x1f\x0dE\xfa\xae\xe7:\xc7\xe3\xeb\xf7\xe7g\x97gz\xd0\xd1U+jA\xe3s\xd9%\xc8\x02)\xcc\x12\x8e\x99\xdc\xdd\xef_x\xae\x93L\x8bpA\xf4\x86\xe4S\xe0\x05\xa0\xcdS+\x8f\xc2\x12\xa0I\x10#7\x97ix\x07{\xe0dyF\x1c\x1f\xa3R\xecx\x0d;\x17\xee\xa4\xb0,\"\x96\xed\xaf\xe1:\xe4VE#\xc7\xe7\xa4(\x0dP\xe3/\xa3\xbf$Y\x9c\xdfV\x08\xc3\x0b\xf2%\xc9\\\x1e*\xa0H(q\x9d\x1fx\xd1?T\xc2\xec\xb7{\x1c\xbf\xfe\xf0q[|r0?\x1a\xbc\xba\xc2\x95\x14 \xde\xbe\x81bk\xeb\x8d\x07\"<\x8b\x12oe\x92L\x8a+\xc3\x8d\xa4\x00\xcc\xd2\xd5\x0e\xc4\xaecE\xa0\x1eP\xa3\xb6Zi-#\x02\x16\xa2v\xe9.Kq\x8e\xcf\x8f\x17N\x91\xa0\x03t\x1f\x9a\x9f\x85\x93\xd3I\x88n,\xd1\xfe\x04=\x9fka\xd4\xa5\xe3h7\xfb\xff^D\xfa\x17O=\xd7\xf9D\xeeJs`\xdf\xdd\xdd\xfe83\x96\x8e\x17\x82\x86w\xf1\x07w(\xf9\xe0~>5\xd9$\x17\x13\x871\x11\x05\xd9\xfaky]\xce\xc3\x82\xc4\xd7\xd7\x8el\xd4\xfc\x0d\xef\xfb\x1f8\xa2\\\x8e(\xe7#\xfa\xc7\xd7\xbe\xf1\xd8\x10\xab\xa38\xd2\xf7\x9b\xd7\x90~R\xbe\x97 |6\xf5M\x04\x99O\xf3wy\x14\xa6\x84\x9f#\xbe\xe4\x9e'\xb0u\x82~\x07\xd1\xa1\xacsVG]B\xbb\xb2\x02\xcd\"-T\x18;\\\xc34%8be\xe9F\xc2\x12\x19\x1e\x008\xde5#8773\xd8\x84\xc2\xab\x18\x13F\xc4\xf7\x9dl\xd6\xbd\xf0\xd2\xe2\xea\xf7\xd9\xffx\xb6\xf7y\x0f\xa9\xf4\xe2\xe5C{\xfb\xa8\xa4\xd2\xee\xeeK/\x98\x9a\x899\x93\x07\x17\x13\x9e\xea\x1b\x87\xf9\xbe\x07\x95a6r$V3!='5A\xeeC\"\x03\x84\xa2\x03\xb6\xf6foz\xa25\xdd\xecH\x87\xc6\xcd\x8d~\xcf\xb9\xea\xf5\x80\xf3t\xd74\x03\x18{\xbdw-\x19#b\xcf\x04\n\xcem3X(\x03_\xf2\x18B\x82\xa7!\x0d\xdf\x11\xc6XI\xa0\x13L\x8c\xa5\xf9\xf2Eu\xd4\x9e\x19$a?\x86\xb1\x8cW\x04\n9ju\xcf\xc7=)g\x95\xec]}\xaa\xcb3\x11\xd5J\xa0\xd1*\x11e\x13\xe8\x8eVc\x1d\xbf\x81uy\xfa\xbdY\xd4\xf0\xbdM\xce\xd9\x07\xbe F\xefd\xc8\xbf5W|k\xfc\x9b\x03\x9b\x90\xa1\xbf\xdb8'e\xf6{\na\x14\x91%\x85\x82\xcc\xc8\xe7\x96\xd3[\x01\x11\x02\xa9~\xdb\xa6f[\x14\xa5\xc5\xfd\x9b\xd3x\xc6\xc3\x1el\x07\xdb\x9aH\xc9x\xe2:\xdb\xc1\xb6\x03\x13r\xe5jnu\xaa\xa3\xd6(\x80\xef=\xbe\xe9\xa4\xb8\xe2\xf6\xb8\xb0am\x03z\x8et\xd3\xfcn\xdc3\xe0\x11\xc5\x8d\x8c\xb4\xfd\x90\xec=L(\xb27F\xac\xda2Q\x16\xa2\xad\xd6 \xc9M\xa0\x9f\xefx\xc1\xf4\xa1k\x9b\x07\xfc\xcc\xe7\xec\xa9|\xe1\x81\xa1\xfe\xf1\x15\x83.\xd4\x19\xfe\xa1Gtq\xae\x91\xc4!xAs@\xdd\x1d\xd4\x97'\x90d\x1c\x93\xac0f\x95 c\x0b|\x1c\x06\xd3\xd65I\x1f\xac\xb7\x97DH\x8cf\x84*\xfc0\xef\xb6\xd9\x8d\x07\x0fXz\x7fT\xdf\xa1\xcd\xb5\xfd\xddFs\x90\xdf\xc1\x1fc\xc2\x05iI\x9e\xc19\x89VE\x99\xac\x89\x94\xb8\x92\xcf\x94dq\x92\xcdZ\xc5\xc2\x15\x9d\xe7\x05\xfc\x9c\x84\xd1\x9c\x94i\xb8\x86w9-\x17a\x96\xaf\xe1\x87T\xfe|\xf5\xfa\x8f\xb3E\x98\xa4A\x94/\xfe\xd0\xaa#M\"\x92\x95\x04N\x8e/\xb5oz\xd6\xcb9\xe6\x82w\xa2\x84{r|\xe9\xf5\x949\xcc\x97wE2\x9bSp#\x0f\x9e\xee\xec>\xdbz\xba\xb3\xfb\xca\xd8\xe5\x9e\xaa\xde\x93b\x91\x94\x18\x14,)aN\nrs\x07\xb3\"\xcc(\x89}\x98\x16\x84@>\x05\x06_3\xb6L9\x84\xd9\x1d,IQ\xe6\x19\xe474L\xb2$\x9bA\x08Q\xbe\xbc\x83|\xaaW\xcf\xce\x11(\xf3)\xbd\x0d\x0b\x02a\x16CX\x96y\x94\x84\x94\xc4\x95\x1e/Zf\xc04II .\x9d\x13p.D \xc7\xc36c\x12\xa6\x90d\xed\xca \xc8\x9cp\x9b\xd0y\xbeb(\x9d\x83M\x92g\xbe\xf0s\xcdz(?\xa7\xc9\"\x11\x0d\xb2\xe28\x8b%\xd0\\\xaf{U\x12\x1f\x07\xe5\xc3\"\x8f\x93)\xfbOp\x0e\x96\xab\x9b4)\xe7>\xc4 k\xe9fE\x89\x0f%K\xc4\x05\xf4\xd9(\xb7\xf3\x02J\x92\xa6\xac\x86\x84\x94\xc6\x89\xa9\xfb\x8eE\xf0\n\x80-\x06\x15\xd3\xcbz\x05\xb7\xf3|\xd1\x1cgR\xc2tUdI9'X&\xce\xa1\xcc}\xbd\xfarU\xdd+\xb0\xd2\xd3>\x1a\x1f\x81sp\x01\xc7\x17\x8e\x0f\xbf\x1c_\xfet\xf6\xe1\x12~98??8\xbd\xfc\x15\xce\xde\xc2\xc1\xe9\xaf\xf0\xe7\xe3\xd3#\x1f\xc6\x7fy\x7f>\xbe\xb8\x80\xb3s\xbd\xe6\xe3\x93\xf7\xef\x8e\xc7G>\x1c\x9f\x1e\xbe\xfbpt|\xfa'\xf8\xf1\xc3%\x9c\x9e]\xc2\xbb\xe3\x93\xe3\xcb\xf1\x11\\\x9ea\xfb\xa2\xe6\xe3\xf1\x05\xab\xfbd|~\xf8\xd3\xc1\xe9\xe5\xc1\x8f\xc7\xef\x8e/\x7f\xf5\xe1\xed\xf1\xe5\xe9\xf8\xe2B\xaf\xff\xed\xd99\x1c\xc0\xfb\x83\xf3\xcb\xe3\xc3\x0f\xef\x0e\xce\xe1\xfd\x87\xf3\xf7g\x17c88=\x82\xd3\xb3\xd3\xe3\xd3\xb7\xe7\xc7\xa7\x7f\x1a\x9f\x8cO/\x038>\x85\xd33\x18\xff<>\xbd\x84\x8b\x9f\x0e\xde\xbd\xc3\x96\x0f>\\\xfetvn\xea\xfd\xe1\xd9\xfb_\xcf\x8f\xff\xf4\xd3%\xfct\xf6\xeeh|~\x01?\x8e\xe1\xdd\xf1\xc1\x8f\xef\xc6\xbc\xe5\xd3_\xe1\xf0\xdd\xc1\xf1\x89\x0fG\x07'\x07\x7fb}?\x87\xb3\xcb\x9f\xc6\xe7\x98M\xf4\xfd\x97\x9f\xc6,\xa957\xa7pp\n\x07\x87\x97\xc7g\xa7l\xcc\x87g\xa7\x97\xe7\x07\x87\x97>\\\x9e\x9d_V5\xfdr|1\xf6\xe1\xe0\xfc\xf8\x82\xcd\xde\xdb\xf3\xb3\x13\x1f\xd8R\x9c\xbdeY\x8eO\xdb\x9d>=\x1d\xf3J\xd9\xaa5\x17\xf7\xec\x1c\xdf?\\\x8c\xeb\x9e\x1e\x8d\x0f\xde\x1d\x9f\xfe\xe9\x82uH\xcd\xacC\xcdv\xe3]\x9e%`!\xf7\xa5\xf4\x02\x92\x8c\xc1g\xc4\xe3\xfc\x8a\xf3\xb5J9\x12\x97$\x8d\xc4s2\x1b\x7fn:\xf1S\xe2oAS\xc7\xdd\xd88\xea\x874Z\xb6q\x10R&AE\x04\xaa}\xf9\xab\x0e\xca\x00#dI\xa8\x12\xa6\xc1XU\xa5x\xc26<\x1a\xd0\x19\xbc\x92\xf7w\x95M\x89\xa7\xb2U,\xc1E%\xa4\xcbdA\x1a\xd2.k%|\n\x1b\xd5\xf0$\xa3ZVK\x17\xebCF>/I\xc4N\x992\xa1+\xe1\x83e\xd0\x8a\xe4VI\x97\x14\xd3\\_#o|}\xedT\xf7PUh\x99\x96\xb0\xab9ak\xe1\x94\xcbH%\xda\x00\xc1\x10\xe0h\x17\xad\xccd\xd4\xfa:\xd0G\x1d g\xe7\xaa\xd3\x96\xc6R\xefS\xaf%\xab\x9c\xec\x18\xae\x14\xe5M,7\x9e\xec\xce+*\xe4jz\xb5N\x1aZ$\xf3\xeb\xf3\xaa\xbc\x0f\xbb\x06\x9d=k\x14M\xc3\x04\xa0\xf9]%\xe0\xc4\xb7\xa6~\xe0\nidA\xb2~\"w\xa5\xbb24iu\xa1\x0f\nc\x84\x12\x9f\x90\xfb\xa2G\xe1I\xee\xa2gz\x1e\x19$T\xc1\xc2\xd0S\xd2\xe8\xa9\x8c\x9c\xeb\x86\x93\xb2\xba\xf54h6\xaay*\x90%f\xeb\x06\xf5Y\x0b\xa5\xea\xc9\xd0x\x8cm\x03\ntN\xd5\xdd\n\xa8\x8b\xa2\x85G\xaf\xee\x83\xd9~i\x8e\x0c\xa35\xe5\xe2\xba\x97\x8bw\xb3F\xa2\x90\xf9\x8a\xb7\x04-\xd6\xd5\x94\xb6\xf7-\xf5\xf9\xea\xf9\x90[s|E\xdd\x96\x11?\x06\x9a\x13\\\x88O\x86\xd5\xa3\x8d\xd5\xa3m8\xa3ze\xbc\xd7\xbc\xc2f:\x0f,l\xec\xa0!d%\x1bMhA1\xcd\x80\x94\xcf=\x11Oq\x10\xbf|\x1f\xa5K\x9b\x00\xbb\xbd\xf4D\x89\x92\xc4\xd6\xd6b\x94\x88\xcc\xba\x01u\xb4\xd4{qZ'W(\x11n\xe7\xcf\xb8>\xba\x1et\x9a=\xea\x8e\xa7\x86\x1do\x0d7,Q6\x9d\xe4\x96\xbdc\x0c\xb9\x94\x08\xffqO\x9e\x98\xa6\x85\xf1\xf7[\xbb\\\xc6W[\x08M\xf2+6\xbcb\x92_a<\xf7\xc3\xa4\x88ViX\\90\x92\xa9\x04\xb3\xf9\x90 \x97\x0e;\x08P\xe2\xa3!\x00\xaa)\n\xac!\xf6#\xe56ih\x9f(\xcc\xd3D\xda\xd0\xf2\x0bR\x96\xe1LV!\xdf\xf6\xea/C+*i\x18}\x12\xd5\xf0\xdf{2\xd5P\x85\x14\xc57w\x04\x03\xf0 \x06\x922\xde\x06\xe1m\xca\xe4\xad\xf8\xc2-?\x84\x1f_\xe0~\xd5\xf2\xecn\x91\xafJ\xc7\x83Mpp\xfe\x1f\xacP\xf8\xfd+\xf35\xe3\x0bc\xc8#\x96n\xf2|\xcc\xd2\xf5k\x80\x95H\x7f\xed\x99\xcc'K\xbb\xd8\xc9\xa4\x10\x8d\xda8J\x84\xbb\x1d\xae\xf0j\xd0\x9d\xe2zS\xdc\x19? \x0b\xd7{\x03\x9b\x9b\x14~\x80\xcc\xa8S,g\xa2\x1do \xa4\xec\xbc$\xd4-0\xfeW1\xd9\xbd\xb2\xe9\xed\xd6\xbf\x14\xa5'\xde\x07\x86\xac\xfdF\xb2P\x8f\xc2`\x1ceS\x15\x9em\x94f\xe2{\xe9\xf9\xe0\x9c\x84K\x9b\x10x\x90V\xbc\"Un\x85\xd0\x13\x10e\xf1\xea\xf8\xc2\"\xd2|\xd1\x12\x81\n\x88\xda\xd5E\xf4\xa5H\x7fi\x84\xb4\xd4\x0ei\xc2< \x0ei\xc8\xad\x140\x1a\x99\xd1\xca\xaaL\xfe\xce\xf1\x05\xfbaX\xf4\xd4\xb0\xe8\xb9\xdfH\xae\x16=i\xa6\xf3E\x0f\x9b\x89|\xd1W\xcdD\xbe\xe8es\xd1S\xe3\xf2\xa8C\x1e\xacN\xdb\xf0\x9b\xb2\xb5\xcb\x1d\xa7\xd0\xca\x9c\x98\xeb\xdcK\x1f$\x9b\x9b\x19\xfc\x00\xc5\x1b\x0f\xc8$\x87M\xc0\xf81\xed\xb05\x92o\xd3\xe6l08\xbdx\xaa#\x1c\xa1\xf2\xfcZ\x07\x1bcL6\xa3\xaaS\x0b\xda\xba\x84\xc4m\x18\x0c\xd5\xe0\x8a]\xec\xb9\x8a\xb1\x90,@B\\Q\x1e(\xdc\x90\x1b\xb6[E\xc7Z\x8dj\x10\xb8V\xbe\xaf\xba\x03\x1dF\x83\x9a\xf7\xf4\xea\xbe\x8b`>%\x9e\xebkcZ\x83\xf6t'\x9a\x97\x8c\xf6\x14'\x03\x16\x0eq\xd37\xaa\xb6\x08u\xc7A\xab\x99\xb3\xaf<\xe8L\x15E\x15\xd56\xb8\x87\x92\x8dU;\xbd\xd9\x9ey)\x06!\xed\x0e\x1b\xb1z\x95\x9e\xe9\xab\x015\xf2m!e\x90\xbaB\x16\x8e\x08\xffl\xd0 \xcbcry\xb7D\xd2\xc9d\xfe\x88\xf7Af:\x92;\xa4\xc7zH\xa3\x1e\x83\xe9%\xdfW8\xbb\xd5\xd4\xec\xf1\xab&\x19t^\xb0&&\xbf\xe0l\x1e\xdd\x15\xec\xc3*HJ-7\xb2\xd4\x9a\xde{{\xfeAgPv\x9f=\xf7\xaa\xcb\xd5!z7\xafwv^\xee\xbe~\xfd\xf4\xfb\xe7/\x9f\xef\xbc~\xbd\xfbP6\xc5\xe4\xbf\x1d\xe7\xf1\x0f\x8c(\xc7_\xff\x81\xbe\xf1\xb93\x02\x02?\xec)\xa2\xb0\xfek\xb1{\xf5\xa6\x1b1I\xdc\xde\xba\xd4\xed\xe9\xceC\x80\xfb\xe9K\x9d\xc0\x04\x01\xdd\xdf\x08\xc1l\x13\xe4\x8f\x00\xc1\xd5NH\x1a\x10\x8cU\xa3\xb9cDJ\x83\xc5\x9env\xd0\xca\x00\x9d\xf7\xe0 \xe5]u\xeb\x05\xf9\xdb*)H\xe3\xc5uV4I\x1d/`\x03\xb3xb\x01U\xae\xfc\xe5\x8b\xdc\x8e7 \xdeD6^du\xc6zz\x02[}u=\xfbf\\=`3v(W\x99\xaf\xd6[FT\x0c\x04\xb6?\x06_>N\xdc\xfd\xd1\xe4\xffL>^]}\xf7\xc5\x9d8\xbf\xbf\xf2\xdc\xfd\x91\xbb\xbf\xf1q\xd7\x9b\xfc\x9f\x8f\x1f\xaf\xbe|\xfc\x18x\xdf\xed\x7f\xdc\xf5>\xea\x81Yx\x00\x98\x8f\xb7\xdf\xfd{oH\x07\x8b!S\xc3\x8eI\x17\x8bV\x92t\x01\x98F\"k\xc3\xad\xb0\xc7\xc6\x1ed\x08\xd4%R1JB\x158B\xa64\xdc\x0em\xa0F .?\x8f\x05\xc2\xa3\xc8n$\xea\x9b,A\xf9\xf6H\xa4\xd3<\xf7^\x86\x0e\xf7BD\xf7\xa4\x1f\xcd\xf2\"A\x99pm\xd3\xcaE\x17\xf5\xc1\xb9\xbe&\xe5I\x1e\xafR\xe2\xe8\x1a B\x1bAU\x08AC\x9b\x05Y\xe4\xc9\xdfI|\x11.\x96)y[\xe4\x8b\x8bhN\x16\xa1\x90*\xf0\x8f\x87\xa8,\xf8\x97\x93w\xe3\xcf\x98\x8d\xb3\x10\xf8\xf3/\x8bT+\x94dSR(\xefe\xbbfq\x00\x824\x81i\xd4\xac(z(\xec\x98\x89\x1b\x0b\xdd\xcc}\xf1\xfd\x0b\xcf\xb0\x0f\xf0\xd3\x8b\xd7\x9e\x91\x97\n\xed\xeb\x83\xa0\x10\xd4\xf3(T\xf5\xdaXKFF\xd0\xddZ\xfd\xae\xfdk-|\x19\xb6+\xe1\xa2\x99\xe1qm\xa5,\xa7\x95\xc7\x10F\x8bg\xbd&\x8b0I\xef\xd1\xc2\xaa$\xc5\x1f _\x8c \xca\x17\x83\xda\x12\xfdb,(\xd9\xa2\xc9\x828\xc3[t\xe5\xf5\x95\x17\xd0\xfc\xf8\xe2L\xa8\x84\x19\xf8\x02\x83<\x05\xd1\xc4\xf0\xb6\x06\xc5u\xe3\x95^O\xd3<\xa4\x8f\\u\x92Q2{\xf4\x0e\x0bT\xd8G\xff\x83\xb2\xca*\xf6\x94\xb88\x10 \x8dW\xad\xf2\xa5\xdd~\x13\xdc\xdb\xbcLw'\xa4\xcc\x82mt\x17\x9d\x0frr%\x99\xdeyF\xff3 \xc4f4h3a\xf2AO6\xc14/\x16\xa1\x812\x02\x81\x12V\x13\xd4O\xbcv`\x13\xb8\xa9\xcc\xca\x18\xd5S\xc2%\xf6.)\xdf\xae\xb2\xc8s\x13\xc6c%\\O\xda\xf9\x90}\xca\xf2\xdb\x0c\xb5 \x85K\x1b\xec]\xd7\xd4\xa46\\Xa%\xcb\x0d\x93<2[7\x89\x7f\x00\xa4\xa3\x15U\xd6\xfa\x8ep\xf7\n\xf6\x9b\xaf\xa3\x96)\xa8|r\xd3RP\xcbR \x99\xd9\xb1\x14\xca\x97\"P\xe1\x8035V\xb3Vg\xaa9\xef\x1c[\x16\x00m\xce\xb26\x844\x93\xcf\xa2\xe3\xdb\x0c\xc9\xb0\xcf\x0bC\xc0f\xf60\x1c6\xc3;j\xf3\xf7\x1b\xfc\xbe,\xc841x\xb4b\xcfuU\x03F\xab5g\xba\xe5S\x9b\xad\x16\xe6\xef\xe3\x8aG\xb6\x1c\xe0a\xc7\x01\xceN\x90\xd4C\xa8\xfa\x97\x9c\xe2a\xdf)\xee\xb2Y\xbd\xc3K\xff,\xa7\xe1\x8cM\x8e\xc3\xcd\xa5\xdc\x1b\xd8\x87\x1bF\x96\x8f\xd0>\x16u\x01\xee|\xb8\xe6\xde\xd2\x17\x13\xf6\xdd\xf9\xbcH\xb3r\xc4\xce\x8e\x1b\x96 _\xd1_\xc1\xb5\x85\xc0Q\x0f\x05\xc48\x91\x0d\xf9\xb2\xdc\x11\x83\x07\xd8\x03\xfe\xff\xcb\x17\x98qK\x10\x9f\xa7HU\x0d\xe5\x85\xe5\xe1P\x023\x11\xa9>\xae\x88\xbf\xf5$\x93nn\x9b'\x04\x9e\x0d\xd3\x81ns\xe5\x13\xc9\x1d\xc8\xfd\xb6\xb2\xca\x85\xdf^v\"\xe4V\x9d\xa6\xd6\xf94g\xad\xcf\xef\xdd\xba|\xb6\xac\x8b\xfb\x8d\x0bs\xaf\xf6E\xaeV\xa6\x01\xe4\xb6U;\x91M\xfd\x85\x99\xdc\xee!\xa7\x0f\x199\xad\xec\x19\xb4$\x95\x1b\xf0\xc2N\x9d\xb2\xbe]\xe8q\n\x0e9\xde\xd8\xb8\x98\x1c*\x84\xf7\x97/\xb0T?\xd4$7#\xc6-\xd3\xd5h\x87\x95\xe2H\xa2\xfa){(\xde\x03\x06\xb3h\xa9\xd2\xb5l\xf2a\x03\xff\xd4R\xbc\xc3\xba\x90Jc\x9d\xad\xde&;Wv\x96E}\x0ed\xff:\x0fm\xfd9\x93\xa5\x04D\xd91\xbd|\x16\x93j\xd4\x12\x1d\x1e^UG\x16\x92M\x07l\x04\x07\xd04\xb5\x9dN\x0e\x91\xef\xc1\xff\xcdOg,\xfd\x8c%~b\x7fJ\x9c\x8b\xee\x85\xf9\xdaw\x80\xc9\xa7\xd9\xd9=hw\xbe\xe1\xf3H\x9dA\x8d\x18\x94\x03p\x1byx\xba\x05\xce\xd5\x87\xad\xfa{d\x99.\x86\x15h\x82\xc7{Tw\xe5;\x05\xd1\xa8pa\xf0^\xa2[\x8e\x04\xde\xf7L[\x17j\x94\xcc\xa4h\xa8\x0fQ7\xa9\xcd\x118\x07\xd9\x1d\x9d\xa3\x0dT\x98\xc1\x0dAc7\x0bU\x80\xe1Q\x86\x9e\x08zC\xa5\x8doeH\xee\x11\xcf\x99\x018R\xcc\xdc\xb8 \xffSv\xd4W,\x15&\xcd\xd9\xf9\xdbB\xff\xb7lQo9WV\xa2]\xb8Xa\xc6\xe1M\xcc}\xb7\xf6\xfb\xab\x0fcV\xd1X\xef\xfaW\xe3=\xc8\xd4x\x89'\x05\x8e\x11\xff\xda\x84R\x86\x0d\xb3\x86\x9c+\x97x\xc3s3\x93\x19lL\xa24\x94\x81{M~\x0b\x92,\xc6\xc0*\xceG\xaa\x85c\xd3\xaf\xe1\x00\xcda;.\xa5X\x7f\x92\xba?\xd3\xbe\x1b.-\x7f\xda\xaf&Q\xcd][t\xcf\xd5\xf0\xc8\x9aq\x87\x95V\x9ex\x15\x87\x05O[\x84\x9f\xabxrU\xc6Fb\x85\x1b\x95 hw\xc1`\xd7$\x85\"2OCl\xd8YY~?\x8ds\xd5\xd8\xa0\xbb\xe2\xc4Z\xb1\xeaz\xc5\xb0\xd2\x0dGY>d\x01\x06W\x19/\x12\xca\xdd\xdcc\x9a\x12\xac\xa3\x9ayy\xbb\xd8\xf8\xaaMz\x9dG\xac\xfeI\xf3\xfb\xaeV\xbe$z\x0e\xbb\xd4\x03\xa9&\xe5\x06\x9b*\xc6(D\x06\xa8\x10\xbe\xebL\x1e\x152X\xacJ\xca\xd0g\x08<\x1e\xf2\x9a\x88[)\x8b\x1b\x05#\\\x11\x0eo\xf5\xcc6GD\x16 \xed\xb7\x9f\xe7\xfe\x8f|X\xf9P\xfa`\xf0\xc4\xac\x83\xb9\xabm\x03\x0c!'\"\xe5\n+\x1c$\xc4\xd4l\x01~F\x05'\xb7\x9d\xce\xd5\xd2\xda\xe9\xd2\xd0\xceDo\xb1\x9e\xa1\x8b#U^\xe3\xa9\xc6oc^5\x9f|\x03\xcd\xc3F\x1f eZ\xbe.\xbf\xff\x90E\xe1j6\xa7>\xac\xb2rI\xa2d\x9a\x90\xb8\x1a\x1bv-\x00\xf7\xf7\xb0\x89\x0e\xa2\x1d\xcf\xe4.\x84\xb7\x17\x05\"j5\xa7\xde\xa3&\xdak\xcdq\x82^\xa2\xd4\x19\x98\x90+\xbb\x92\x05\xd7\xc2\xc8<\x0f\xca\xdb\x04UXt9\x97i\xca\xa2\xb0$\xb0k\x8e\xf4/\\\xb0\xa2[t3\xd5\x82>\xa4\xdb\x9f\xb0\xd2\xa7\xbd\x95\xfa\xcdu\xba\x7f\x13\xcf\xee\xd9\x84\xfa\xf6\xf4\x9e\x0d\xca\x9b\x7fc\x99UE\xd4\xf7[\xe1\xb1\xfd\x18.\x97\xe9\x9d\xe8\xe0J\xd7{\xad\x84\xf4\xb9k\n\\\x83,\xd4\xfd\x1a\xc4C/\xc5\xeb-n\xda\xe2y\x95^t\xc9C4r\xc7\xe5Pnnz\x90N\xca+\xad\x8bF\xfc\xa3j\x954\xb1L\x18\xc7J\xcc\xd0N\xe5!\xb6\xe3\xc26$oX\xfc\xce\xa4\xb2\xda\x1aYV\xa7^\x17\x96\xecAU\x0d<\x93\x91[5\x02)~cx\xd3u\x94/\x0e\xfa\xff(\\\x1a\xc8.y(\x90\xaf:8\x02\xaaU\x94\x04\x08/\xa5\x9f\xf6\xae\x074\x87$\x8b\n\xc2\x90\x0d\xfa\xb7\x08\x9c\xd6\x92J\xe4\xea\x9b\xe9/\xd9\x7fZ\x84\x11\x1e\x82\x8d\x04\x0cL\xd7u^\xe7h\xe6\x00\x1b`\x15\xb9&<\xfa\x8du5\xd9\xc3\x03\x88d\x12\x83\xee\x83[\xfd\xdec\x8c\x8dyU\xd0\x08[F\xd8J8M\xf0\xad\xeb\xd4\xbf\x13\xfb\xb7\xdaA\x9a\x0e\xe3\xad\xd6F\x07\x81\xad\xed\xd1\xb3\x156:\xc6\\\x15\xe5\x9ci\xeb\x8ax_g\xf4\xd1\x87\x98~\xe6>y\xd2\xb9/\xda]2\xb7f\x05t\x8a\x0e\xc8\x1a#\xd6\x97G8\x02\x90K\xd8\x9eh\xa3\x0d\xb7J+\x19\x8a\xe8\x8dh\xf0#cC\xaa\x0b\x0eF\x9e\xa6\xb0\xf04\x96\x93!\xb3\xa1\x03\x83\xc6\x04N\xd0\x9bjo\xbc\xb1W:\xa9\xf6\xcc\x16\xb4\xf8\x0e1\x13]\xcbh\x03\xeat\x10,\x9b\xc8\xd26\x8d\xc4\xdd\xf1\xea\xdbx\xbfE\xfc\x19(?I\xe3\xc3H\x8b\x16e\xea\xeba\xbe\xca\xba\x05\x02:\xbboS\xae\xa0\xed\x85m\xc3YRy\x94\x14\xd3`q\xa0R\x87+\x96\x16\x9c\xfd\xf8F\xe3F\xec#4\x1c\xe6\x95\xbaJ\xa3T\xbfI\x80n\x0cD5\x0f4\x99\xfbl\xe7{\xcf\x0b.hA\xc2\x85\xa0H\x82s\x12\xc6\"\x02\x1b\xbe\xffR$T\xbcg\xee\xee\xeb\xefQ\x80y\xb4Z\xa6\xe437\x80\xe3)\x97E\x98\x95\xd3\xbcX\xf0\x8aww0\xf5}X\x96\x97\xf3\"_\xcd\xe6<\xf3\x8b\xe7\x83LMz\x1d\x01\xf28_&T,\xdc9>\xdf\xf1l\xf4\x9fA\xd7\x1e481II\x12\xc6|\xa1|\x84\x07\xaa\xe0\xa7PF\x8b\xbbf\xd24\xc9\x92f\xc0E\xdb9\xbd\xd19\x07\xfa#-\x0f\x08o\xd4~\xb6\x93F\xaf\xec\xf9\x04R*\x8c\xe6\xfb\xea\xb3\x16^d\nd\xe0o\xc2\xc8 \x82P\x1f\x1a,\xb9\x93\xc5\xe8fk\x8b\xf1y\x18v\x1d+`3h-k\xbe\x07\x02\xac1\xca\x8bO$>'\x7f[\x91\x92\x96o\x0b\xf4\xe9mJ\x96\x8bDP/\xcdPlO\xd3\xdb\x92\xcfW\xee\x91\xa5\xf5\xedk\xc7\xeeV\xb7\xd3]\x9b\x0fYq\x11\xc6\x06\x0dn\x8a\xfc\xb6\xe4\xd4\xcb\xc4Y\xef\x04\xbb;\x8e\x0f\xec\xc7\xeb\xc0\xb9\xaa]\x81\x04kR\x94I^y\xf9\xf0\xe1{\x8fk\xd2\n{\xda\x04\x87w\x99\xe8KpW\xed\xd3\x0b\x1a\xa2-\xfc\xac\xdd\x9dT\xd8\xad\xbc\xd0\x8e\x954H\xb29)\x12\x81\x15^\xed\x1aX\xaa\xc8h-\x02(|\x12z\xa6#\xdc\xe0\xcf\x06\x99IL\x05\xfe\xd1=\x0e\x80\xd4uvw\x9f\xefJG6\xed,\\u\xebC\x92\xd1W(i\x025`\x8d\xd7R1e\x03\x98\xfb\xa8\xa1\xc5\x1a}iE\x0d\x0b,l\xf983bg\x10\"6\xee\x82\x8a\xa3C\x0420\x84Q\x05e\x1fSU\xf6k \xd5\x11\x99\xf0\x8b\x8e\x93\xd9\x15\xfc\xeaz\x7f\xea/\x10\x19z\xb7\x0f\xbb/`\x04\xbb/\x9e\xbdzn\x99\x85FW\xd0\xaa\xf4\xcb\x17A\x0c\xe7\xb0\x0f9\x8c\xc4\\\xa4\xf5\x87\x94Q$)\x8c \xf2\xcd\x95\xd4\xb1~\xdc\xf6w\xafF\xe6az\x18\xa62,\xa7/\x0f\x02\x12\x1f\x15a\x92\xa9\x89\x1c\xe7i)\xcdr\xfclh\xa6\xc5\xa4\xa4E~'\x12\xcd+\x82\xf1\xf99\x7fE\x82\x98Dy,\xa2\xc9\xd8N\xaaF\x1eVxZ\xb5\x86B\xb2q\x16\xe5\xa2\xb7\xa4\x95\xf6\xe5\x0b8+:}%\xe5I*\x13\x87 l\xc5\xb5\xa1rD\xab\xe4)\xef\xb2HJL\xd8\xfb\x0dn\xe5\xf7\xdcZW+\x9cg\xa8\xff\xd2\xab\xb8\x0b\xedC\xb3\xef\xc4\xe4A\xdc\xaeoU\xec\xd8\xad\x84RpY\xf4]\x16u\xe7\xe3\x81\xe0\xb0\xe3\xd1\x8d\xfd@d\x14c\xff\xa8\xe4C\xb4\xb9%\xb2\x81\x8a\xc6 \x15\x7f \xf7\x1eII\xe6+\xbf\xd9\"X\x1b\xf9\x8a\x871\xf5\x0c\xc4\x87\x99\xa6\xd2\x9f\xad-\xe5x\xf71r\x80[\x9fJn\xeeC\xe1\xf9\xca9\xe5^\x08\xa6\xdco\xad\x03\x97\x9br\xb9\xa8\x14\xa9\x12\xc1\xd8\xf3+,V\x19\xe3\x15\xdc\xdc-\x1e\\\x81\x0f\x17\x1cT\xecZ(\xe89\x8aO\x00es\xd0A\\\xf5+\xf8\xe0\xad\x01\xec\xc1\xd8\xd5YD\xfd \xf1\xcc\x90{\x07\x7f\xb7\xb6 C\xde2\xb9\xa2dX\xea-gB}\x8cfZ\xba\xd78\xcd\xfcj4gsv\xed*\xef\xf6\x91\x1b\xbfXi!\x05\x01\xa8@Y'\n\xf8kl\xfa\xba\xdb\x8d\xfciX\xd2\x1f\xbb2T`\xa6\xd4\x88\x8a\xcem$\xaa\x03\xc2\xae\xb9\x03\x92\xdf\xdai`-\x8d<\xcc\xc8-\x84\xfcf\xb11\x016\xba\xe0\xce\xbc\xad\xb9\xe6s\x930\xd8p\xe7\xfc\x12\xec\x8ew\x00\x8d\xbe\xd9\x8f\x06-\xe05\x1c\xa0\xdeY|\x9f2n\xf6V#\xfaX~N\xa6(\xe1\xa2ok\x0e\x0e7\x08\x9e\x94f}\x0c\xbe\x86\xca\xc5\x87\xc4\xcb\xe2\x8b\xed\"A|^\xeb%\xd7u\xd1\xb5\xbd\xac8\x01\x95\xc22e\xaf\xfej/\x8eg\xb4R\x98\xbf\xef\xc9/\x9e\xe7\xc3T\xb9-\x1e\xb4\xa67M\xa4\xc8E\xe9\xc6k\x03\x15\xec\x19\xfaP\xf6F(_\x05>\xc7\xcb\x03\xe5\\\xc4\xa8+r\xa6\x18\xe6\xa4\xf2$\xe4a\x87\xf9\x17\x97\xb7^\x7fSk\xd9\x1d4\x9ake4\xa6Ad\xd0\x17\xf0Q>\"\x06\xa3<\x83\x9e<\x01\xaa\x10C\xb8\x06-\xe2Hb\xe4\x98\xa59\x06,\xfc\xd5\x15\x07\x84\xc68\x16n\x8d\xbb\x07\x8d\xf3\xd6\xdawj\xa4?\x0c\xb6\x0c\xeb\xca\xb1\xb2\x86:\xcc\xb2\xa0j\xf9PD\xcfo#\xd8\xc9g\x9b\xbf\x8a\xf87b&;\xc1\x91\x8b\xcd\xcd5\xf4\x8a\x0e\x83AtZi@l\xe6\x93(\xa9e\x05\xe6\x0c\x95R\xf4\x8a\xa3\xcd\x92\xcf\x1b:\xfd\xcb\xf1\xc6\x82k=\xa1w \xbc'\xc3\x1c\xbb2\xd0'\xce\x86\x0f+\xd8\xdc3\xc9\xd3\xd8\x93\x07a\x9a\xf2\x83\xa0\xe4^\xd8\xe4\xee\xe3;\xa6\xf2\x92\xe6\x83\xe30\xd2\x82\x1f\x00Mx\xd9\xdc\xc4\xac\x1dG\n'I\x18\xb9b\x11\x0b$\xa2\xaf\x89*\xe7\xf1\xecb\x04qN`?l\xe7L\x1b\xd6\xbb(\x08)&\xee\x94\xc8T\x9c|\x10\xcdW\x99\x85\xd1\x92\x0f\xea\x0b\x05DP\xf6\xddy\xb99r\xbf\x88\x87\xc1}\xb5B\xbb\x88\x99\x1a\xdc\x1c\x8c \xad\x16-\xf5\x19\x036\xd5\xc0\xc1\x0b\xae\n\xb9\xa3\x81S\xdau\xf4\xca\x83\xbd\xa6\xb9\xf9\x1e\xb2\xd4ZW\xa9\x87\x0bhn\xa4Z\xb4\xc8H^\x86\x06fM\x07\x9d\xc2\xa7\\\x8f\xb4\xbc:\x85*\xf1\x96\xb6\x07xx\xf0\xc9\xd5\x1b o<6\x0c\xb4=\x92\xa28\x9c6\xebJk\xe1\xe9\x0c\xc2\xca>A~\xb7\x171\xb3s$e\x1e|p\xf8pZ.\x92\xf4gF\xe8\x08\x0d\xad\x84\xc8\xb5\xdbI\xa3\xfe\xa8\xb7{\xd5\xd4\x1b\xdc\xda\xa8\xcfW\x1f\x1c\x8d\xe9\xe6}\x85\xa4\xacE\xbfBYI\xcbX//\xe3nH\x18\x07\x8e\x0f\xce\xd1\xf8\xfd\xce\xce\xce3\x8b\x8f3ho\xf0*\xb9\xd7\xfd\x99\x85E\x10\xb1\xb4\x9e<\x11\xbf\x82yX\x1e\x0b~\x0bl\xa1C\xa5\x9b\xe8z\x99&\xed\xd2Wh(\x07{\x03s\xfb\x16X\xb8\xf3\x0d=\xeb\x08\xe0\xd5/O\x92Z\x90\x1bsU\xdf\x94\xd4\xfc&\xdb\xed\x9c\xe3\x92\x0e\xa6\x9a\xbc\xa4\xc2\x8f\xce\xfaN\xcb\xaf\x88\x85\xe6\xbd\xe2;y\xce5\"\x9c\xb4\xee\xe5}P\x15G\x97\xc9\x92\xf4a\x07.\x01h\x1e4uP\x90\xc30\xcbr\n\xac\"\x1f\xd8\xafB\xdcp\xea\xac\x88\xd6r[$i\xbf\xa3C\xb2\x9e\x1b\xf0\x1b\x18s\xbb\x8d\xfd\x86\xc1#7\x88\x0b\x85\x8d\\\xa5\xab\xd01:W\xa1_V\xae8\xdd\x02\x17\xb4P'4\xb6\x1fi+$\x0d\x94\xe2\xdc\xed\xaa;L\xf0**Y\x06\xd3\"_\xe8\xf1\xe3\x00DH\x05\xcb\x16D\"\x85\xebWpT\x8dT\x18\xe3\x0b\xf6\xf1U\"@FmsEX\xbc\xe1\xd1$\xd3\xcd\xdak;\x86\xac\xaa}\xe1\xf9\x90\x0b\xb9\xfb\xfe\xb0\xb3[R\x03\n\xc8\xf0\xa5\x0f\xa7\x94\x14@\xb2\xd8\x16d\xd3D\xdd(G\xb4\xc5y\x86\xd8\x8b\x19\x9e\xdc\xab\x16\xe7m\xe7\xd2A\xb9\x9e1Y-\xc9'\xb4\\$\x80B\xdc\xd4\xa4\xf2>\xf7\nN\x1az\x80'\xe1\x1dn\x15>\x11\x98\x1bQ\x0fF'+Q_\xc0\xf1\x8c\xd1\xa3\xb9,A\xb1\xa3\xc989\xd4\xbc\x8er\x0dm\x1eg\xeb0Mb\xc8\xf2l\x8bW\xbb-N\x1a\xe4s\x1c\x0f\x95\xc5\xb9/\x8e\xe6\xbc\x87\xcdy/xJ.\xf9\xd0v\x10\x10\xb9\x069\x97\x99\xf2\x00\xd2n\xde$\xc0B\xc3\xde\xaf\xa4A\xb6\xf5AU\xae\xdek|S\xd5}\x078\xd1o\xf4\x8c\xd7Axw#\x17E\x8b[\x82{Jl_\xda\xe1\xc2G>F\xf2H}\xbeVz\x18\xf6\x8a\n\xee\xb2\xa4\xda\xa0\x8c\x88\xcc\x95\x0d\xcf\x15\x03,\xce#\xcc|\x9e\x94F\x18\xf8\xce\xc2\x18\xb9@>\x95\xd8j\xd3\xaa\x1b\xc9\xeaF\x0b\xb8:8\x12m\xde\x0c\x9a\xcb \xed\xfd\xa6\xeck\xa7\xc3GR-\x18\xc4\xed\xc1\x05\x0c}p\xc3=\xb6\x19\xd8Z\xfb\xfc\xdb\xb8\xe0n`\xc3\x1d7\x02\xc3\xcd\xbb\xfaH\xb1\xc2\x08\xf4P\x84\xda\x83\x07\xce\x08\xb2\x1eY\x85\x90<\x8c \xe9\xce\xc8v:\x8fgo\x07M\x1f-\x86S)\xca1O\xc3\xc8\xc8\xe4\x1b\xf3Z\x85<\x9b{\xd0vs\x06\xb5\xa4G\x95\x94\xacj\xfc\xd1\x89\x9e\xcb.\x8c\xb5\xf2A\xa2\x8cvL\xa0& \xc3\xa0j\x10\xf1\xa4\x11\xee\x1c\x1a77\xbb\xea^eCjo\xf0l\xcdV\xda3 \x1b\x16H\x9e\xbflm\xf9\xca\xad(:\x82\xac\xef\xcb\x14\xa9\x07\xbe\x19o\xcf\xda\x02\x13\xbc=\x93$q'\x11X\x12z\xd4\xba1\xef\xa6\x95\xd0\xd6\xd2\xe2\"O\xb8\x99\xa2\xf9\xbb\xfc\x96\x14\x87a\xc9\x8d,6\xdc\x893'\x9f\x19w$\xee\xdd\xd9\xff-\xfc\x11\x96Q\x92\xb0\x1f7I\x16\x16w\xf8+,\xc9\x8b\xe7\x98+*\x9f\x8a\xff[OE\xb1\xdd\x17\xe8k\x17k\x90\xbf\x8b\xf0VQ3r l\x82\xe3xZ?P\xcf\xa8\xb2\n\xd0Ng\xe9`\xb2\xde\xf3\xe8d\xb2G]W\x83+\x83\xf2\x81I3\xd7\xca&5X\xe6[\x93\xda\x89\x91\x83&U\x9c\x83\x91\x91\xe2F\xae\xba\x97\x93\xee\x18W\xe3\x80h\xef\xdd\xe6\xe8\xbc&\x84]\xdf\x87\xcf\xc8\\\x85J\x15\xd7C\x1e\xe3\xc4\x19\xb1\x96,\x96)Y\x90\x8c\x92\xb8\x87\xb5\xa9/\xe7\xb8h\\\xfdF\xb2x`g\xaa\xbb\x8c!{\xdb\x1a\x90 \xa9\x02\xc2\x055\xe2\xeeW\x11\xbd\xdf\x8b\x99\xa8\xcd\xbf\xa1\xe9$\x83{\xa8\xaf\xee\xa8\xa5\xcc\xabP\xf1MQ\xab\xb0\xc8\xcbc\x8e\xe2p\x87\x16R6\xcb\xd8\xad\x06\xd2\x192S\x80\x07q\xad\x1f\xb4S 7\xfdJX]\xd5\xb9\xaf\xd2\xb2\x19\xbf \xcc\xb3\x88TB\xb7\x0e\xd2\x8d\xd6*G;\xbe\xa2\x9a\xd5\x16Q\x83r\xa8\x14-Fe\xe0\x16\xacT\x97\x8c\xdb\xee^\xdbJY-\xd3\xd5v\xa5\x84\xae#\x14\xd1\x81\xf6\xd8\xda\xdb\xbcl\xf4\xc7\xca\xe7Z\x9aw;\xdb\xc7\xd8\x8d\xf7\xdc\xf9\xf5%\xf7Z\xfe\xd6\xb6\xe9*S\xf3ToZ\xae:O/\xbf\xcb%%Y\xecz>\xd0V\x0c\xf8\xdf\xd5=U\x03\n~\xcf\xa0\xd4}\xb6\xf3\xcac\xc7\xe1\xf1bA\xe2$\xa4\x04\x13w\x87\x85\x0ex\x8c(\x83F\x04\xf2\xbbf\xe7\xbf\xb9\x1b\x99\xfb\xe2\xf5\x8e\xe7z\x95\xdbN\xc6-a\x98\xc8\x17\xafw\xbfa\xa8\xeb\xcam\xfc\xcb\x1ds\xf0\x84\x17\xa6\x88?\x99\xfb\xea\xa9!\x86\x97n]-\x0e\xf6f\xc6\x95)jSWx\xa0R*E\x867\x9a\xff\xc5\xb4\xa1.y\xdf\x05\\W^\x1b\"_u\xa5\x0f\xb51\xa2\x12\x9f!\xb4\x98W6\xcb\xe1\x85@\x86\xc1W\xb9A\xb0W\x9b\xbaF\x9a\x93\x05~F\xa0sI\xf4p\x11y\"\xce]\x04\x7f\xd8\x83\x1d\xc6&\xb0\xb4\x914H\x96vN[\x90\xba\xa5\x1by\xde\x1b\xe0a\xee`s\xd3p\x1d\x85z>\xaa\x94\x95rq\xc2T\x1c\x8d\x13z\xe5C\xe1N\xbdz\x8c\x1a\xbf&R\x15w\xc9\xdf\x00\xcd\x0d#\x89\xd6i$\x05\x95Z\x07\x86\x11\xb5&\xd1\x1b1\xd3\x8bHaJ\xc2\xc4nD\n\x8aT\xb8\xf1\xe1+\x97\x12tw\xaa\x06,\x967\xce#\\r\x11\xc0\xe1\x92|\xa6\xa7yL\\\xc7\xe9p\x1cn\xd0\x00QT\xaf\x06\xdc\xaf \x83\xd3\xc1\xe6{\xf2\x80\xe7\x97\xeb\xdc=\x16\xb5\x9d\xdfC\xfc_f\xfd\xfe/\xb11\xe3W\xb3D\x05\xad\xd6\x9a\xe4\x94E\x8e[;Z\"B\xf3\xa3\xca\x8f'8\xd1c\xd0\xc8\x077l\x1e\xc4!\xe5\xe1|\xf6`s3\x81\xff\x80\xa7\\\xdd\x01k\x0b\xcay2\xa5.z\xa1\x10\xe2\x17ix-(\\6\x82 \xad\x96qH\xc9\xbb\xf0\x8e\xcd\xf3\x00*\xd7@\xb2cD\x0f\x83\x80u\x19\xde\xa5y\x18w\x84\xfb\xa9;\xf06I)\xe9>\xe5{:`\x10\xc9\x0e\xeb@9\xcfo\xfb\xc9C\xc6\xa0\xb6|B\xf5\xf8>\xe7\xc1\xb4\x94\x04#UE*\x17\xb0\xba\xfby\x06\xc5\xb6\xe1\xae:\x86ke\x1b\xb3\xd9\xc8\x14\xbf\x8e=l\x16\xb2\x91\xe1.\xc5f]\x88s\x17\xcd\xc3lF\x84UW\xff\x0c\xdes\xfe\xda\xbe\xe3\x1d\xe7\x11\xa70|\xe4)\\\xe41\xb9\xd7\x0c\x9a\xb8/c\xd0\xae\xf6\x06vR\xdc\xb1\xd7|\xf7\\\xf37\xa7\xcd\x9f\xb5\x91\x81Vr\x8a\x1b\xcfi\xb3p:Z\xd1\xca\xb1\xc1:m~\xae\xc2J2;\x83+\xee\xa2\xf2\xbf\x1ea\xe2\xf5mH\xc9\x8fd\x9a\x17d\xfc\x99D+\x14l\xd2 \n3\xf1\x8a~.y\"k\x0cOR%m\x1e\x96?\xe5\xe2\x12\xa6\xfa\xfeKB\xe7'\x84\xf2Y[\x86E\xb8 \x94\x14\xe6\xd4\xe3,JW%\xab\x94P\x9ad\xb3\xb7ya.\xf6\xe3\xddqL2\x9a\xd0;\xfc\x1e\xa6i~{Y\xdc\x1d\xd3\xb3\x15\x95\x85\x16\xec\xa8\xafn\x0ddj\xa1\xbf\x96\xcb<+\x89\xb9P\xa9\x16)\x1b\x05\xf8\x1b\x0dg3\x12\x9f\xc9\xb1\x96\xcd\xa1\x97\xac\xbb\x97\xe1\xac\xca{Dh\x98\xa4\xd5\xab)\xfby\x9e\xd3c\xaet\x87r)\xca\xa3Z\x88\xf6\xe6rzo\xc2\x92\xbc\x0f\xd1\xacO\x00@Rw`\x9ad\xf1Q\x95\xc6+!\xd1\xaaH\xe8\xdd\x91\x96U\xa6\xf3i.\xf2x\x15\x89\xa6\xa2<+W\xb2\xdd\xbc9\xc2eH\xe7\xb2\xfcb\xcd\xfd!I\xe3g\xfcM>SRdaz\x94G<_\x92M\xf9^M\xca\xb3\x83\x8bg\xbc\xec\x92D\xd5\x8f\xff,9\xa8\x9c\x932O\xd7$\xbeX\xdd\xd0\x82\x88\xe6Y\x06\xedC+\xbdQS\xf5r\x91\xaf\x8a\xa8\xce|Ay_WE}\x19\x8b,\xaf!>\x82\xa2\x15\x94\xb9\xafLA\xdaQ\xa5'GyA\xd1\x0c\xf1Wt\x87\xf8+\x9aH\xafn\x13cm\xbf\x97\xd0nVa\xb0\x1c\xfd\x08\x17\xecL\x9d\\1\x96bF\xe8q\xe6N\x9c\x05\xa1\xa1\xe3\x83\x83K\xe6T.\x9e5G\xb5\xd4\xf3a\xe2T\xdb\xact\xae<\x1f\x0f\x8d\x12Eh\xffy\xe1\xb9\x93+\xcfC\xc8\xea\xb1\x87\x94\x97\xa0\xc1I\xb8\x0c\x92\xf2$\\\nE%\xec\x93\xeb`\xb0\x06\xaf\xd6\xf4\x16\xc9I&\x12\xb5\xb9A2\x81\xf7\xe4$\\z*9\xea\xab\x98\xe1g\xae\xe0\xd2\x7f\xf7a\x9a\xae\xf7Bj%)\xbf \xb1O\x94\xe7\xf1\x0e+\x93%\xa7\xea]RR\xcf\xf5\xbc\xa0 l\x1f\xb9\x8d\xaet\xdd\xc1\xc8\x08\xa4\xb1\x081A\x959\xd9\x97o\x88\xb8\xaf?/R\x87[5\xd4\x89]r\x19F\x9c\xbbj}\x9b\xe0\x04\x0el\xca\n\xf8r0\xb0j\xce\xbb\xbe\xfc\xffP\xa3\xa87\xa7\xbe<\xe6AX\x8e\xb3\xff\x1a:\x87\xf1\x84|\xf2\x83\xa4d\xffT\x81$ \xca|A\xbe\x11f+\xe0\xd4\x94\x8d\xfbf\xe4\x92\x07\x1d\xba\xf49>\xa5$\xa3,\xc9\x0c\xabz\xc7\x14\x08}\xd3\x9aH6\xd5\xb1K\xbcj\x9f\xf7\xed\xef\xd6~f\x0b\xda&\xd5\xb8\x8b\x92\xfb\"\x8f\x81\x953Tz\"n\xceZ\x1fQ\xa7\xac\xb5\xb5x\\]r+vW\xbb\xd8\n\x1d\x93`1yb]\x8bM\x811\xd2\xcd_Fp\x89\xd1\xf30j\x15\xcb\xe8,V)M\x96aA\xb7\xa7y\xb1\xd8\x8aC\x1a:u\xb6\xbcX\x1c\xb1\x14\xcc\xcapE\x12\xe1q\xb8\xfdy\xeb\xf6\xf6v\x0b\x8b\xac\x8a\x14\xaf\xd7I\xecT~\xda\x8d\x04\xb96U\x06h\x14\n*\x15\xc0\x189\x1aI\x894\xf2\xe5\x9d\x00Z\x1d\xe3\x87\xf5\xe1\xde \x83&dy/\xb0c\xc7\x8a\x9c}\xc3\xa1\xd2\xc6*\xd1\xaa(HF\xdf\x0bR\x84\xd3e'\xcdS\x19A\xc5\xfd^\xbfrY\x99y\x04~1\xf4\xd2k\xd6\xc1\xce\xff\x893#\x14\xe1{\xc5\xff\xe5%\xfe\xe7\x1e\xba\xd8\xaf|\x89D\x0f\xfb9'a,\xf6B4g?\xd0\xcb\xa6\xa3E\xd2\x88z\xc5\xde\x15Wf;\xd7\x00Z\xf7\x9fS\x1e%M\xa5VX\xd1P\x08\xcb/HJ\"\x9a\x17\x9e\x1b\xf5\x05\x82\xac\xb0\"\xee\x8b\xaaBM\x9d\x9fs\x04\x9cHz\x94\x86V\x85\x1e\x15\x9d7Q\xd3d\x8f\xd2\x0c\xab\x8e\xa3\x0cG\xf7\xfc\xef\xeb\x04\xe1\xa35\xc8k\x14\xcdf9\xdd\"qB\xf3\xc2\xd6\x01A\x9e>J\xf3\x7f-\xf3\xac\xa2>8\x18\xe9\xb3\xacm\x86%\x87$\x8dp~\x94\xce\x14\xa2\xbe\x9e\x0e\xf9Vz\xbe\x97\\R\xdbC\xecSh\xccB\xf7\x11\xc5Qr\x8b\xce\x91\xcd\xca\x80\x89\xc3\xe8\x03~M\xa8\xa6d\xdc\x8f1\xce\x05\x8f\xca\x8a \"~b\x19\x9c\x151)H\xccg%X\x90bF\x18\xc3S\xd3\xa9#\xdd\x16K[\xbbx\x08\xb3\xf4mK\xd9\xdd\xd3\xa5\xdf\x00<\xcf\xd7\x97\xbeZ\x87\xf6\xaa7\xde\xe7*\xff7\xa8c\xd3\x96\xbaC\xb3\xc6\xb5\x88#)\xb9K\xf34\xcc\xfd\xee\x0b\x16\xd1\x98n\x0f\x8a0+8\xd8\xfe\x8a\xbb\x86\xf1Wi\xaf#\xc8\xcai\xde\x9e*m\xae\x16|d\x1aG\xfd\x98\xddP\xab6\xac\\\x83\xb57\xb7\xbb\x1e\xd8\xae\xda\xaa\xa8\xb3u,h\xc3\x9f \x84%\xe5\x0c\xe6\x0e,\x06v`{\xbd\xefNv\xb6^_}\xe7}\x0c\xda\xbf\xb6\x93\x80|&\x11#p\xb8\x0b\xb7]\xd3lH\xe9\x87\xb9+\xf1\xc0\xae\x10I\xeb2\x02\xaag\x12\xee\xdaB\x18s\xe3\xb3\xbe\xc6\xf1\x0e\x9a\x07\x0e \xca\xe4\xef\x04~\x80]\xaf\xb9\xfb\x05\x17\xdbf)%\x03\xd7\x93\xad\xb9\xd6\"\n\x1d\xec\x83K\xda!\xe9H\x87\xca]\xdd\xd5\x8d\xaad\xd5Uk\x18bc\x1bV\x83\x1c\x10F\xae\\\xb3\xb6\xf0d0\x15\x97K\xd9\xf0\x9a\xb7\x8f\\W\x1f\xb6\x9a\xbd\x9a\xf2\x0bB\xe7y\xdc\xab\x9f_-\xb7U\xa6.\x9f\x84U\xc6\x18\xfb-\xc6\xd8\x9bU\x07\x80\xc3\x95\xe5J\xdat/\x8f\x87\xf0\xa8\xb9\xda\xfanh\xbc\xdf\xe8r\xc3oCR\xbc\xe1\x0bB=\x974\xd9\xb8\xbe\xe3\xe5Z\x97f>vGd\xd5}\x1d\xb9\x95\xc8\xab\x12\xb2~[O$\xd5)\xeak \x9e\x0c\xc8\xca,\xf8}\xd4n(U\x1b\x89\xfc\x968\xba\x97\xd0\xab]\xbfY)=d\xd3\xeav}\xa0W\xbe\xd031\x82xS\xb0!\x08g[\x15v\xb5\"\xd4 F\x99D\xeb\xa6\xdcoI\xe2\x1fe\x96\xd5.\xda\x85\xa1P\xcd\xb6r3\xf0(\xed\xcb\xfa\x8cK+\xee#\x1e\xa5!V\x97\x99I\xac.@\x1e\xa5\x1dQ\xdd\x006\xa5\xfbf\xc6\xdc\x99;\x1fn|\xb8\xee\xbe\xceku\xac\x11\xd8\xdd\xaa\xc5Qe\xe7\xd7\x8c\xaeSu\xd0\xe9\x9b\x02\xf9\xa0\xd7\xa3\xae\x0c2\xd3FS\x18\xda\xaf\xb5\x06j\x07o\x13:\x97\xaa6\xe5\x80\x91\x19+\xd1p>'Z\xe4\xd0\xab\xf4\xa1#W\x1f\x03b\x17|\x8ekP\x11\xd5\x9f\xaf5\xe3S\x1f\x04\xcd\xdeU\xe9\x8f\xdc;\x83E\xb2\xfe|m\x85\xb6o\xe7\xb0~\xb6\xfbpnt\xca\x80|\xe4c$%\xb4\xbd\xa5\xa1h\xae\x97#\xeeC\x1fe\x8b\xb3\xbaz\x0f\xc7\xc6\xfbg\xd9\x87\xfa\x8a\xb6\xf7\x94\x92S\x82~\x81*\xc4\\]\x02q\xe5\x01W\xd9G\x83\xee\xcf\xa05\x1a\xe5\xc6\xcc\xa0?\xd1\x89\xc6\x9a\x83\xbc\xd0\xd8\x08\xe5z\xda<\xed\xb7>\x8c\xfd\xc1\x13A\x06\xdf{\x81r\xc6+`N\xab\xf3YEl|5\xaflJ\xb7\xf2d\x0e\"\xf4\xab\xcfH\xf8]\xf4\xcc'\xf7\xa2\x10\x02\xe9\xf0\xd0\x07QZ\xfdD\x06\xce\xb2@=\xc6A1\x8c\xbf\xd32\\G\xe8\xd9\x03\xfb\x08C\xfb \xf6\xed\xff\xd5\xea2\xf4^\xcbZuC\xb9w\x94w\x8c\x1d\xfb\x11TPn\xc8\x9fz6\xee!'\xb1\x0d\x8a\x18\x83\x10F\x95i\x10\x9c\xe2x\x0e\xf3l\x9a\xccJ\xb6<\xf6\x85\xc5\xcb,\x06\xb8\x17yAM>\xd0\xe5\xc3\xfd\x10\xd7{\x92\xe7\xef\x04\xf5\x0b\x94O\xe4\x05\xfd\xf1n\xd8\x9a(e\xcd\xee\x00\xba\x02\xd4\xea\x8f\x9c\x0f\xa3\xdej!t\x1fV\xd8?R\x94\xca\x1cL\nK\x14}P\xe9\xeb}\x90]\xe8\xb0\x11\xff\xea5)\xa6>\x0f\x0c\xf2\x9e\xdd\xd8g\xe9\x83\xbc\xee\xb3\xbe\x1a\x93\xbc'^z\x02{8t\x8aU\xb8\x05^\xd0\xf7\x0eV\xc1\xdb\xdd[\xbb>\x96F\xdc\xd9[\xd6\x01z\xa0\x8a\x0e\xca\x11$\xf7F\x04\x86\x9d\xd9\xdc\x82\xbe\xa6\x07e><\x86\xca\x9ck\x192\xaf\xf0~\x17\x1a\x9f\xf0LST\xb4\x1e\xa93\xbc\xbe>&\xa1\xf1~\x80]ik\x90=J\x8f\xb4j\xef\xd5\xb13\x8e#\x9b\xban\xf7\xe0O\x0e\x95\x1b_\x96U\xb2\xc9&\xa8P\xb4\xeb\xee\xd1\xc2\xa7\xc1-\x98\xb4\xfa\xee\xd1\xd0\xc1\xe0\x86\x0c:\x85U;\x1d\x0dh\xc6)M\xbd\x10\xa3\xfa\xe2\x90\xdeK\x04v\xef\xbbw\xa3JW\xf3|5\xa3\x92\xfcA\x8a \x03\x9b\xb4\xcaW\x8a\x81\x9c\xb0\x14E\xe7\xb89\xb2\x06\x9d,\x15\x9c2y\xc9\xe2\xd8\xc6\x08\xe2\xa4\x1eX\x0b\xa6\xcd\xc3r\xce\xc5\xac\xf8\xf30\x8f\x89q@\xa0\xe3y\xc3\xa5\x9aXq\x93\x11\xca\x03Y\x85JQI\xed\xb6Y\xf7NMi\xb7o^\xb7N,\xf3\x9ec\x99\x1ee^\x1d\xda-\xc2y\xe9)+\xab\x16\xc2@\x13\xa9c\x7f8\x98^'\xb2\xa3\x0c\xab\xe6\x0cf7\xf4{\x1f\xe3.\xbe\xffh\xfe\x19\xdb\xf7\x1b\x01\xa5\xb0\x80\xc7P\x90\xb0\xae\xca\x99\x98\x93\xdc0\x95&\xe5\xf0oD\x83\xbc\xd0\xd5c\xa1\xb8\x07T\x97\xd4\x9ah]\xba\xa1\x0d\x04\xd7y1\xa5N\xa4<\xac\x0c\xb8\x02p/Z\xd7\xc1\x8e}\xd0\xf7\x17\xf2i\xcd\x0e'\xfa>W\xf5\x93k\x1d\xff\x07Hj$\xdanH|\x8d:r\x06\x17<\xdc\xcc\xb1V\x1a\xc5\xf8\xcf\xce\xb6\x08K9\xd9Q\x02\x12\xaa\x11\xa2do\xe0\xd2\xde\x9f\xff\x81*\xa9lRz\x95R\x0d\xb3p\xf2\xaf\xd155\\\xa3\xa0\x99\xb2\xf4\xf1\xd2\xb9\xbd\x1f\x88\xd0\x85\xccU(y^y\x9d\xf7A\xb9T7\xe5#\xaa\xe5\xb5;\xbd\x97@x\xff\x83A\xac\x1a\xaa\xa0x\xa7\xd4\\\x8a\xdf\xb5\x7f\xb11\x1e7\xe5p\x95\x05M\x1f\nl\xcc\x8fP\xaa\x0b\x16!\x8d\xe6\xee\xf6\xffq'\xe1\xd6\xdf\xaf\xd8\x9f\x9d\xad\xd7\x9b\x1f\xb7\x82\xab\xef\xbc\xd1\xb6E\x0b\x97\xbb\xa0HJ\x19\x90\x80\xb1\xed\x1c\x92\xb3V\xd0\xc1\xd6)\xcb/P$\x8a\x14\x92\xef\xd6G\xe7Z\xac\x0f\x1f\x9e\xc33\xe6\x9ar^\xc3\xf6\xc1`h\xd47%\xa2s\x13gN\xe9\x12\xd54)]\x96\x8a\xb7\xac\xe3\xaa$\xf7\x90U\xb7\xdce\xf4\xd4)\x0d\xe9\xdd,zd\x8a\xc7\xa1S\xecF\x19-\x8d\x07\xdb\xe6Rp/z\xdf,M\x96\x03\x02\xcfJqj\xe5\xfa\xd1\xa0\x0b\x93\xa9\xeb\xd8\xc65\x7fm\xf7\xc4\x8c\xd6\xf61\xde#W\xf3> \x97\xda\xb6\xf9\xaf\xb7\x8d#\x8a5\x9c\xf8\xddp8\x98\xcf\xd4\xd7\x92p3\xf3\xa6W\xc2\x92\xd0\xd6+\xe7\xc7\xb9E\x12J\x80\xc7\x8b%\xbdC\xfb\x9f\x8az\xc6\xaf\x12N\xf1\x93\xb4\xa8\x92\x89\x9a\x16\xe0a\x18\xcd\xd5:M\x86S\x82O7\x7f\xc2\xb4\x0bi\x9c\xb5\x0c\x8b\x92\\\xe6\x95U\xd5\xc5\xf8\xf2\xfa\xe2\xf0\xa7\xf1I\xc3\x9c\xfa||q\xf6\xee\xe7\xf1\xd1\xf5\xc5\x87\x1f/\xcf\xc7\xc6oj\xda\xd9\xfb\xf1\xf9\xc1\xe5\xf1\xd9\xe9\xf5\xc9\xf8\xf2\xe0\xfa\xe7\x83w\x1fx\x99\xc3w\xe3\x83s\xf6~\x8c\xf9\xde\x1f\x9c\x1f\x9c\\(_\xce\xc7\xff\xbf\x0f\xe3\x8b\xcbF\xca\xc5\xfb\xb3\xd3\x0b^\xfc\xdd\xd9\x9f\x1aYXoO>\\\x1e\\\x8e\x8fZ\xe9\xedw\xa5\"S\x0fD\xdf\xc7'\xef/\x7f\xe5\xe9\xd7\xc7\xa7\x87\xef>\\\x1c\x9f\x9d\xaa\x19\xf0\x93\x9a\xf0\x9f\x17\xcd\x0c\x1f\xce\xdf\xa9\xaf\x17\xef\xc7\x876\x034\xd8\x83\x1b7s\x9f~\xaf\x93\x9d\xb9\xf8\xf2\xea\xb9\xfe%\x91e\x9e\xe9_B\xf1\xe5\xf9S\xfd\xcbJ\x96\xd9i\x15*\xc5\xa7g\xcf^\xe9\x9f\xd2\xea\xd3k\xfdS$\x9b\xfa\xdek\xd0\x8f\x1c&/\xfaT?%\xb6z\xc7\xe8\x8e\x82,\xd30\"\xee\xf6G\xba=\xf3\xc1\x01\xd0\xf1\x96\xcdkc\xad/\xd6Fsh/q\xdd>\x1f+3g\x8d\xaej\x9e\x1c\xcd\xbd\xf5-\xb6\xf9\xa7\x1d]\x18\xe0\x1c\xe0\x03j\xe9?\xb8\xf5\xdbok\x9d\xa1\x85\xde\xc5\xec\xe9\xc2\xf8\xa1]\xe0\x06\xf6\x88\x13\xcd\xbc\xb8! bO_>w\xf4\xc5\xcc\xa9q\x95?\x8b\x86\x9e8P,\xf7?x\xb4\x9f\x86\x0b2\x02K\xf0\xa8%?\n\xac*\x85I\xf9\x97E\xaa[\xfd\x00\x0crL\x80\xf3\xd6)\x89\xb4\x1b\x9b\xfe\x8b\xa6\x0f\x87o\x9d\x1c1\xb9\xddSS\xdcsjR\x12\x16?\xeb\xa7\xed\x83A\xfb\xf8A\xf3q\"\x14D\xdbj\x1c\x03\x96U\x9av\xa1\x91a\x1f)\xdb\xd3\xfd\xbf>\xa8\xfb}\xbb\xc1\xb2\x9c\x9f\xc8\xdd\x08tS\xbd\x87\xcc\x80\xb4\x1d\xfb\x1f:\x03\x1a\x1f{\xcf\x19`\xf0\xab\x10\x96\xdf2\xf6\xcb\xc7\x1d\xbbT{\xbe\x87\x0f\x10eD\x92r\xfe\x96\x01\x9d\xfc\xb7\x18PI\xe8}\xd9[\xdb\x80\x8e\xee= \xce\x9ew \\6^\x0bx\xca\xf1\x1ad\xc3\xb6\xf16\x89\xd9iEd\xbe4\xd9\xa5e\xaen\xd1\x19W\x05Z\xf4\xe5\\|\xda}\xd9\xfa\xb4\x96Ti\x9b\xcc]\x88O/_\xb4\xc8\xdcY\xf5\xa9Ej\xdfI\xc3R\x13\x93{c=\x14dh\x1e\xd51\x04\xe9v\x0ca%w\x1a\xf3xm`\x1e\xd0\x14Q\xfa\x9fA;\xc8\xe6\x18n\xdb\xfcG\xa3\xc8\xaaH\xb5\x12c\x03\x07\xd3(\xc2\x95\xa8\x1be>\x9b\xd8\xa0F!<\xd2\xb5R\x83\xb8\xabF-\x84\xf1\xc9\xbc\xae\xfa\xfaF\xab\xf5\xd0\xc2\xc7\xf1\x8a$\xf3l\xec\xd0'\x13O\xc8\xcb\x95\x84^\xcb\x8bt\xad\xd4\x81\x81\xb3T\x0b!\n\xd3\xca\x9cup\xa9uYq\xe9m\xa9\xe3\xbd\x81\xf3\xe5e\xd3|f)ca\xa0y1D\xb9\xb6Q\x9e\x18\x99\xf1fAS\x8b\xc7\x9d\xec\xbdZ\xbesi\xfe:@\x8a\xd0\x00\x95J\xccz\xbd 4\x14\x87j\xb3\xceS\x8b\xb4\xa2QOm\xde\xda({\xde#\x051\xd6q]r\x81\x8bV\xd7Q\x05\x0c\x95\x80\xc5a\xcb/e\xaa\x8d\xcc\xef\x86\xaa\xb8\xb9;>\xba\xa8\x16R\xc5J\xdc\xa6\x9bH\xab\\zS\xe8\xd3K\xfeV\x19:\xad9\xb8\xc5\xe7\x01\xe6,\xcdGLQe\x937J\x96\x8c\xdc\x99\x10)\x8a\xce\xea\xf8\x95\x9c027g \x85{R\x83\x1c\xd4\x1a\x16\x10\xc3@\xc0\x97/\x90\xb8\x18\xb0\n\xc1\xb6C\x87\xabD\x0bqF\xda\xb1i-\xda$\x1d{\xbez\"h\x91\\\xaa\xa0\x0c\xa7\xe4]\x1e\xc6\xc6h]j4=\xf3T\xf2\xa5a\xf4t\x9e\x8aX\xfb\xe8\xf1-\x0f2r\xcbx\xf6qq\x9fN\x9b\xa7\x8f=)Y\x93t\x042\xa0\x935\xdf\x82\x94e8c\xc4GP\x90\xb0\xcc;\xcc\xe4\xd2$\xc3|\x8b\xb0\xf8\xc4OQ\xf6+`\xc9\xa8\xdb[\xbfmb\xe4 .:\xb3\xcck{\xf2l[\x05\x03\x1d)\xde6\xf7\xc0Uba\x85\xb0\x0f\xce*\xe3\"et\xf2\xc1\xb6VTo\xad\xd0\xe3&\xe0M\xd1\x88\x1bz\xec\xd0\x1fH#}0\xc4\x95\xfb[\xa5\xbf\xa5Hf; a0\xecM\xab\x86d\xe5\x85\xa8\x7f\x7fBus6`\x8f\x82t\x83\xde\xbbO\xa1\xf2\xff2\xed\x00\x8a\x15\xecA\x18L \x8d\xe6\xf6L%f\x12S\xd5\x01`\x98\xed\xe0\xc2\xc0\xe3\xc8'\xaaD\xb2\xb8\xfa)\xec\xc3?\xbe\xc2\x08R{\x91\xa9\xbcT\x14:\xc2f\xb5\xa0\x0fh, 7\xe6mXd\xdc\x91\x84\x98\xa2\xc6:7\xc2tB\x99d\x11\x81\xf5\xb3`w'\xd8\x810\x8b\xe16IS\xb8!P\x90E\xbe&1$\x19\xac\x9f\x07;\xc1\xce\x1bX\x95\x04,r~\x11\xd0s\xc3\xf1|\x0ep\xb6XW\x0c4\x18i>\xedRv\x8e10\xd9\"\x8fI*/ZN\xc2\xa8\xe8\x88*5\xc7\x12\xd5\xcdVO\xee5\xe6\x16C9\xce()\"\xb2\xa4y\x87R\xf5B\x94\xe0\x04\x8cR\xc42\xcaz\x95\xeb8?y\xe5i\xc1\xad\x9dG\xf0\xfb\xf6\xca%x\x1e\xac\x8a\xd4\xaa\xfe\xc5&\x8fq\x15\x11\x83\x88wIFNW\x8b\x1bR\xbc\xcd\x0b\xb4\xcf\xdb\xb7}h\x86\xdd0\x84\xc2\x90\xcf]\xd5\xcd\x0bZ\xd8\\w\xcb\x1b\xb7\x0eT\x8f[\xca\xe8cH>\xac\x8dN3\xe4\x9b\xb0$Gyd\xe5\x1dA\xb8\x00mB\xc8\x08b{\xf6&x\x8c\xa0c\xd3\xb7ac\x04\xeb\xae\xec-\xc0\x18\xc1\xc2\x98\xfd\xab\x17\xd09\xc9\x06\xe8WA\xe3\x8e\x95M\x98\xbd\x03\xec\xe1\xf6\xad\xfc\x1a\xd6\xae*\x9eL\xc1Mz \x0c\xa8$\x02\x0e\xba\xf3\xcf\xcc$\x06\x082\xa3y\xfb\x9f\xe1\x1do\xa6(\xd6t\x0d\x11T\xe5\xbc\x81\xda\x9a\xeac%K\x08?\xcf\xd9\xa4LWi*\xb6\xc8\xcc\xbd\xf3\x95\x14i\x15\xc0\xd2\x96\xdc\xc8\xb5\x91\xbd~ \xfe\x9a'\x99\xeb\x04\x8eZ\x04)\x15FU\xcb\xd8\x93$\xa0\xdcE\x9b\x9c7\x1f\xb5s\x84\x8b iu\xccr\x9a\xef\x93\x89\x0f\x8e kz\xa3?\xcb\xa7\x11\xcf\xaa#\x10\xa8\xfa\x08\xb9! Dc\xbd\x85\x86X\x01\xda\xa1\x8e= #\x13/qV\xc6E\xf1#j\x99\xe4\xdf`9XhWfvS\xaaVr\xcb\xfc`r\xa5\x1dGo\x85>\xda\xa2&\xc6\xd8kZ\xbf\x96\x15Y\xcdh\xc7\nh\x81X\x03\xdfQ5b\xa8\x0f!\x0f\x80\xe2C\xec\xc3\xdc\x87\xb5\x0f\x0b\x1f*k\xdf[\x1f\xc6V\x85\xa1\xba\xed\xdbb\xd0\x86\xc1p\x0bo\xdexP\xde&\x9c\xca\x0f\x96\x05F\xfc\xe2\xc1\xd0\xbb6Z\x14\x96\x04vF\xddk;\xe5\xe7\xd7\xdf\x82\xf2\xae\xa4d1d\xe3\x12\x19\x8c\xf1y7\xdc\xb0\xe7\xa6 a;\x92\x9a\xfa\xd8\xc1\x05lH\xc2\x89\xc9\x8d\x00\x1e\xe9\x05`\x04q\x9e\xfd\x9e\xc2<\\\x13\x08\x81\x0f\x06h.\x0c`\x08\xe4\x99\x0f\xe1M^\xd0$\x9b\x05\xdcaQxS\xac\x96h\xe2\xc1\xda\xb0\x05\x07\x069\x93\xcf\xfbg2\xd3yQ\xc1\xc6\x92\xa2\xa8)d\xc1\xb1N3\x1fi\xe2\xbc\xa2\xf2\xf8P8\xef\x97#E\xaaS\x9e\xa1\xa4\xfc\xade\xee9\x04\x94\xd6\"R\xe8`\xacK\x0dw\xf3\xb6\x87U\x1eb\xe8\xd4\x14\x91\xf0\x12\x91\xf0\xa2\x1fh\xe1\x1bp\xb0\xe9\xf9\x16\xbclz\x86\xe0j\xd3S)\x14\x8au{\xeaw\x99\x1b\x9a\x1el\xf9\xe9\x83[\x0e9\x91K2\xea\x0b\xb6\xbc \xe5*\xa5'\xe1\xd2\x17\xbc5\x83\xf2_\x12:?\xe4\x0e=%\xcaV\xa0\xed\xa5\x0f\x89\x9b\xe2\xf9z\xbfi\x93O\xc5tL9\x1f6\x8c\x96\xd2\x1f\x13[r\xf7\xb0\xaat\x96\xe5\xe6a\xd5\x98\xd8\x19\x83\xa2\xd2\x90\xc7\xc8\xea\xdc\xde\xbb\xaa>bQ\x7f\x10\xbc^>\x18\xbc\"\x05\xbc\x96\x88x9\x9f\xc4\x8f\xba\x88sWP\x04a\x9a\xe2 R\xba\x1e\xf7f\x86\x8c\xcc\x10n\xc9\xf6\x0c\xe4\xa2lO\x9b\xbbZ\"w\xb5\xd4\xcc\x16\\.\xa1\xb8?\xfbdz*l`b\xa0\xe6\xee\xfa\x7f\x1b\x03ez\x1e\xc2T\x99\x9e{3Z\xa6\xa7\x9f\xf92=\xa8Pm`\xba\x16\xd2\xbd\xf6\xac>WW\x885\xe3\xf6\x87\xb4\xfa\xd0\xa2\x83\x1e:\xbd\x15f\xef\x94\x10u=\x96\xa3`\x04\xf6\x08\xf0\xb6\xe7A\x88h\xf7\xfb\xfba\",\xe4\x90,v\xeeW\x0e\xd4\xcdX\xd2|i\xf1\x91cz\xba\xa9g\xf9|\xc5\xe8\xf1&G\xb6\xc6\xdc6\xc9\xa4\xfa\xb4\xae\xf0z|)\xa8O5Xs\xd0\xcf\xde:\xba\x07\xfd\x95Q\xc3\xab\x8an\x13\xb8d\x00bW \xd6\x9d\x9a\x9c\x0d\xbb\x93\xab\xcac\xcfR\x9a\xd0\x074\xff\xcf\x8b!D\x84\x15\x9c\xa7\x8a\xc8X\xd4\xd6=\xc0\xae\xf5\xe1\x90\xdb\xc3~\x8e\x95\x83\x92{-\xafxz\x1f\xaf\x8dx0\x10I&>\xed\x06\x07\xe4\xf1\xfaz\xf4\xba\xbbG5c\xf1\x1aO\x87\x1d\xec!^V\xba\xbb\xbb\x9e\xafK\xfe\x02j\xbb{\x80\x8aL\xed\xa1Sc\xb3\xa1\x83\xcb\xc6>\xae \xd3\xdef\x9e\xd9\x9b\x19\x8a\x11\x86\xec\xfe6\xd0\xab\xbb\xda\x87\x89\xb1\xd4\x841j\xbb\xaf\xafZ\x1f\xaf\xda\x0e2\xe0\xd9\xf7\x0d\x9d{\xab\xb5\xc77^\xec\xffM\xc6\xc1\xf4+\xa8\x03\x0cC\xfaV\xf7LX\xbd}m\xdb\x02\xdc\xd3\x11x\x8fJ\xdcy{\xff~\x8b\x8e\x9fT\xd8l\xaf\x99m\x80\xfe\x10\xdb\x1c+o\xfdO\x1a\xdd\xc4\xe2\xc0F\x0cO\xc5\x83\xf7\x1bi\xcb0\xe9[\xd6\xee\xf0A\xa3\xab\xb4\xa5\xcdC\xe4.\xc1\xef\xbd\x84]\xf6X\xdf\xae'\x7f\xf1\xcf\x18\xe9#\x98\x13\xf0\xb058\xea\x9f\x85\xe9\xc2\xf0iS\xb7v\xd3\xbc\xed\xc1j\xae\x03&\xa5_=\xd7\xfc\xb9`'\xb6\xc9\xcd\x81e\xc9>uAK\xc3\xb8\xef\xbf\xe7h\xffv\xaf\xd1\x1e\xf4\x8c\xb6e\xe0\xf8\xbfa\xd0g]\x83n\x18y\xf6\x1e\x9c\x1d\xe34\x8c\x857\xff\xbe\xab\xf9\x96\xd9io\x17\x86*\xe5\xd9Tn\x8aa*{\xf9P\x95\xbd\x95&\xeb6\xe7\x12\xf1\x06\xc3\xf2YOu)\x12\x96\x0c<\x18\xca3\xe7\xe1r$qW`\xcc1\xc5\x1c\x95\x8e\xa8\x05m\xc2\x1e\xacl\x9c\xc1\xfd\xb4S\xac\x9a)\xe6\xec3\xbc0\xe0\xacD\x9b|M\xa6\xe0\xce\xe0\xc9\x13\x98)\xa1\xc7\xf4w)y\xd2\x93\x85{\xd2~\xf1\x93\xa4iY\x0d\x1bBK\x86{\xc7\xaa\xcf\x89\xf6\x1e3\x98\xa5w\xc6\x0b\xcf;\x1d\x07\xb9\x93\xd4\x87\xe8\x8am\x84\x8c\xad6\xd2X^\x17\x9bJ\xd4)\xd9k\xbe~\xf9b\x8d\x1f\x00\xca\xd6P\xcbLx\xc3\x1d\x1e\x0c\xdd\x0dt\x0e\x8e\xa1\xfcv\x84\x8b\xa52\xf9;w\xda\xe1\x9a\xea\x82=p\x0c\xbe\x97\xc0\xcc#\xa0H\x07\x83\xc8}\xa6\x1f\xaa\xc8Lq-\xfa\x91\xcaH\x01\xcd/\xd0\x12\x96\xb1\xcf\x02<*\x00?\x8eQ\xc8\xa7\xbe\xefi\xdfG\xbcP\xca\xfeD\xa2\xf3\xcd\xfcY\x90/\x8fcw\xc6\xefc<\xd4)\xe5d\x96k]\x136\xa97\xb0\x07)l\x823r`\x13\"\xf3\\2v\xb6\xe0\xb1>\xca\xa0D\x1c@\xe2\x0bLro\x90ko%w\xe8_]\x8bjX\xbe\x9f\xc3\" oR\xd2\xa5\n\x05\x18,\x9d\xe5\x1eU=\xe9\x96\x08\xb0\xa5,\x97aDFpc\xcd\xf8\xb5_\xbap\xfb\x08=\xedo\xbf{\xce\xabv+\xf7>\x15t]{\x12\x91\xec\xc35\x8c\xe0\xd6G5^=R\x1d\x0e\xa2\x9d\xec\"\xa0\xf0\"\xad\xa8u\xa2L+\x9d\x17B\x87!\xdfm\x7f\xe7\xd8\x17y\xac\xb6\xfac\x1es\x9c\xc4\x8b\x9bK\xb1\xc1\xdd\x05I\xf9\x9f\x17g\xa7\\0\xed\xb9cT\x8cW\xab\x81=`\x19\xb86\xbc;\xf6F0f\xfba\x8csi\xc8<\x16\x93\x0c\xa3\xf6\xa7\xf6\x86n\xa5\xb0\xa1|\x163\xaf\xb8\x01\xf9\x07z\xe6m\x8f\xe33\xee\xc4\x9bU\x92J2\xcc\xfd\xec\xf9P(\xc4\xa8\xab\x1c\x90\xf5A\x08\x9f\x0d\xb5\x11\xc3\x11\xa6R\x19\xbd\xfeq\xd7\x0d!\xe0\x84\xea*:\xea\x93\x9bG\x99u\xab0\x16m\xc2\xd32\xc0\xbc\xe1\x9bD>_U\xf8k\x0e\xd3p\x97\xcc\xc6u\x01{p\x14R\x12d\xf9mG\xa8\x9bLRg.\xd1\xd5\x05\xad\xd3F\x83x\xc5Qj\xa3\x0d\xd8\x82\x8bj\x0dyO-c4\xa8O}\xf5\x84\xa0\xad\xbfyuJ{\x1a\xea8c\xb9\xf6F\xd7}\x0b)\n.^\x98\xab~m\xccg\x9ei@\x8d$\x0b\xafI\xdan{\xf4aK\xf5\x04\x83\xa3\xaf\x1d\xab\xa3\xaf\x9d\xa6\xa3\xaf\x9d+T\xe37P\xef\x15%\xda\xfe\x96uR\xa0\x89\xd8\x07\xb9b\x9e\xc3}\xfeP\x0c1\xc9\xcb9Wf\x1fi\xdd\xa4\x9bT\xd2$\xc14\xebR\x9a\x0f+}\xd5\x01\xf4;\xe9\xe7\x07\xca\xea\xf6\xdf\x16\xa5\xce\xed>\x0c\xb9\xfa\x80\xe6\x1d\x8b_K\xd8\xa9\xfc\xb0\x1d_W8x\xednl\x8a\xf7\xc9\xed\x03\xcb\xce\x08D\xa6\xa3\xca\x9c\x9d\xd1J\xdb\x9f\x17\xe9v\x12P\x86\xac\xa6\x96N\xccq\x00\x15\x81\xd8\xe8\xbe\x0f\xb1\xfd\xec\x16\x80\xb0\xd2\xb8C\xd4},\x9a\xb85\xb1md\xa1\xfcm\xd1\xbf\xe7\x8a\xdf\x96\xa5\x96\xd8\xa2\xdfb\xd8V^\x92\xc4V\xednS,\xdc\xa9\xa5\xab\xc2\xb4\xd9b\x9fa\x0c\x97\xbb4\xa0\x1c+\xce\xc1_=\xce\xa8H@>/\xf3\x02\xfd>7\xe7\xbb\xb2\xf1\xcd\xdc\x97\xcf\x9ej\x90P\xdb\x087\xbdO\x19\x9b\xb4\xb57@,\x89\x91]\\n\x00\x12f\x11\xbaUD\nKA\x80\xe8\x11\xb4\x80$\x03\xe2\x01\xde\xea\x03\x9b,T\xb4p\xd1\x1f\xeb\x08\x92,\xca\x8b\x82D\x14\x92l\x9ds\x07x\x1b\x16W\x8e\xe4~3hv\xe7U\xd9(\xb9\xaf\x9f+\xcdT\xc3\x0f\xa6CD\"\x19\xb9\x1d\x805Y\x8f\xda{\x8d\xd15\xc1\xb2\xc8\x17 \x8a4YUdX\x9096\xe9\xca\xfcRm\xbe\xb3\xf6,;?\x861\xbc\x17mEyV\xd2b\xc50\xb3M\x97\x11O \x1f\x0f\x1b\x83\xbc\xd6\xf3y\xe7\xc5\x05*\xcb\x84\xbe\xe5D\"\xa3~1M\x0b.\xf3U\xb5;\x1c\xb4t\xf5\"}\xbfcZ\xa4\x01bB\xd4\xb0\xe3GW\x921\xd8D~\x9aLrv\x16\xe3\xbf=\xa0\xec\xdf\x08\nVG\xee\xe3\xeb\xbf\x04\xf2^>\xdf\xb5\x8c\xaax\x8c\xea_\xbd\xb0\xd4\xce@M\xd7g\"\x9f\x97i\x12%t\x04\x13\xd6\xb1\xe7\x8c\xe0u_>\xff^\xfc\x7f\xe1\xa9\xdeP\x1f\xde\xbb\x0eJR\x99\x97\x17\xbb\x167\x93\xec\x9b\x8e\xea@\xd0=\x9a\xc7\xca`s\xeb\xea\xbb\x91\xb7\xef~\xdc\xfe\xb8\xed\xed\xbb\x93\x8f\x17\x1fK\x0c\xc9\xd9.\x1eb\xf1\xc9\xc1\xd6\xff\x1f+\xe0\xffw\xb6^on\x05W\xdf\x8dX\x05\xdb\xedB\x8c|\xb1\\\xad:\xff\x86\x9e#\xc3r\xae\x87\xf3\xae\xb3\xec\xb3,\x7f[\x91\xe2\xce\x9eg[\xfatDG\xca\xd6l\x7fd\xd9\xc2\x15\x92x\xbb\xb6\\\xa7\xe1)\xeb\x13\x8fH.\xaf\x86w;\nl\x8f\xdc\x8f\xf1\xa6\xf7\xef\xdb\x18\xc8\xbch\x14\xebo\x04{\xac5\xd4*c\xa8\xa6}\xce\xc9\x87M\xe7\x08v\xcd-\xe3D\x8e`\xb7\xf5Q\xf5# \xaa\x9b\x8d\xd4\x8e\xaf3\xaepo\xb3\x94C\x015\xfa\x83s+\xc3m\x1a\xa4\xe2\xd4\xe2\xc2@\x8bp\xd5\xb9I\xf3\x9b\x91#d\x9e\xcb\"\xa7y\x94\xa7\x1e\x87{v\x96\xb8\xab\x8c\x94Q\xb8\x94\xbc\x13\x9bF\xcf7WH\xd2\x92\xe8\x8e\xea\xf6t\xf7\xd8\xf2A<\x981\x1cX\xb7E\xb0b\x1fJO\xeaz\x14\x93\xcc \x91\xac\x1bR-\x99\xad\xda\xd6uS\x84\xa1\xdb$\x03\x94\x90\xba\xacr6_\x93LG\xaf\xf2Ql\x14\x8a\xa0L\xc3rNP\xfc\xec\xd6o\x8c\xb0\xa5\x9cQ\x9f\x17dj\x8a\xfa\xd3J\x91\xbc\xe9\xef\x9a\xd9\xccp\x11u{;\xad\x02\xfaZ\x89g\xf3\xa4\xc8\xb5\x1e\x01\xe5\x0e\x9f\xd9\xbf\x80\xe6\xef\xf2[R\x1c\x86%A)\x8fc\xb1v\x17\xa3\x1f\xc1\xc6\x06\x9d<\xb5\xec\xbe\x82\x94\x94U\xff\xac\xbd\xd1\xf4+V\xf3\xd0\xa7\xb6C\x14*J\x8f\x1d\xf1*\xb17\xad\xbdPW0E\xcd\x82\x176\x83\xdc\xec\xa9\x94\x1a\xf7sn\xc1\xb0\x12\xc1\x91-\xdc\xcc\x02j\x97\xdd\xe6\x1c3\x96c\x9eX\xb8\x8a;\xd8\x83\x9dv\x7f\x10L+\x88f\x84\xd3\x02\xad\xf5\xe5f\xaaR\xb8=\x8e\x8f\xcb\xcf\x1d@s\"B \xfe\xb3Q\xf50\xabJ\xe4\\\xcc\xe7\xf1\x82)RH\xec\x9c\xdap\xd9q\x13\xb9\x84{.\xf6\xbc\n\x0f\xe0\x85H(A\xdd\x87Y\x03\xea\xe5\xef/_ \xe1\x1eu\x95\x8cU\x15\xc8\xf8\xc9\x17DL\xea\x9b\xe3\xf8\\l\xc1h7\xea7ku\xd7\x93\xa7l\x83N\xb6\xdd\xe0;o\xbbq\xf4xo\xe0\x0e~\x80\xb5\x10s\xbc\x81\xbb\xcdM\x0f\x91\xb5\xcbx\xd8\xf5\xe4\xee\xca\x9b\xec\\\xf9\xdc\x12{\xb2{\xe5C\xc9f\xa5\x84}\x98M\xe6\xb8\xef\x19|\xb7]j\xb2\x1c\xff\x8f\x1b\xa3,@\xfaX.=~\xc9\xe1dh\xfe\xa2f_\xb2>\xee\x83++\x15\xa0\xb3#tT\x95\xa4\x1861\xb7\x87A\x87\xb5\xfczf,\xcfs\xc6(\xfc\x15\xbb\x9c\xf7C\x14\x8eq\\z1\xdek\xcf\xf3\xe5@\xf1\x9f\\\xa5\xe5\xe4\xd9\x15\xae\x96Hd+\xb0\x9c<\xbfR\xebe\xff\x9a\xa8\xc0\xb0}8`\xcd\x02<\xe9\x90\x14\x12\xbf=\x84+\x15 @\xf1c?\xab\x8e\x91 \x9a\x87\xc5\x01uw\xc4\xdc\xea\xdfy\xef8GQ\x9f=\xa2\xd5*\xd3\x00?\x11\xa0\x92\xdd\x18\xe9\x0c9\x14g\xdb\xf1\x82r\x99&\xd4\xe5?\xe5\x0cn\xedz\xd2a5Q2x\xbep\"\xc1A\x8e\x1b\xbce\x93\x02\xb6\x18\xfd\xc1\xb7\xd2.7s\xdby\x03\xc5\xd6\xd6\x1b\x0f#{\xe0M\xd9\xa4\xb8B\xcf\x19\xac\xba\x08#\x13\xec\"~\x0d\x9a\x19\xdcf\x0e\x1fB\x06\xd6#\xee\xb7\xc3\xdd\xa9\x03Z\xb8 \xf7j\xe0C\xab\xc4\xd6V\xb7\x94\x19\xd7&\x0bVY9O\xa6\xd4u\x1c\xcf\xc7~\xb2\x89\xceq\xa9\x82\xea\xed\xcb\x17\xc8\xb8\x0e\x1cf\xcb\x84\xce\xfc\xb6)\xa2\x8a\xb2*\xbe\xbabl\xde\xd8\xb7\xbc\xa0*f\xe0\xfa\xa93\x19a\x97\xff\xe0\x85yf~{\xc8\xdeV%)\xc4b\xb36\xca\xf26/b\xfc\xcc\xbe2B\x13\xa7d\x89\xdf\xd9\xab\\\xb5Q\xab\xfcr\xb2S\x81}\xa3.\x86#\x04\x02d_\xf2\"\x99%\x19oP\xc1\x86\xa2\xbb\x88l\x93\x94\x8c*\x98\x95y\xf6\xd5\x97Mp\xb6\xb7\x1d\xd8\x94\xc5F\xe00|\x8dM3b\x01\xab\xaf/3\xb53Q}\x9b\xf2J\x85)B\x1b\xc4KBG\xbd\xac\xa7|\xf0\xe0\x13'\x94\x19R*\xeb\xaf\xae\x0bh\xae2\xca9\x86n\xa5\xd1\xdeX\x17\xd2\xdd\x84\x8b\xd4\xaa<\xa8x\xa0\x85d\x82\x17\xc9=\xe6_C4{9\xd7\xd0c\xee*Zc0K}H\x14p\xdd\x17~1\x12 \xb2I\x05\xb2\xd5\x95/\x0f(o\xc8Q\x8d\xc3\xe92\xd7\x84\xa1#\xa98\x9a\xa1\xa3I\xf8\x96\xe2\x13\xbd\xb9'\xba\xcbS\xd9$\xcb\x1e?\xc64#O7\xb4c\xdb\xa3\x8f\xf1\xe6\xbfos\x1a\x9a\xb2Yv\x85\xffxe\x0b'\x12!\xd0`\x99/\xdd\xaa\xc3bSS\x81\x96F\x8e\xa7\xcc\xbf\xfc\xa8\x14\x7f\x9c\xc9\x97 \xd17F\x95\x08\xa2\xcd\xf3\x94\xf5\xa9\xa6\xa56z\xa2N\x0f\xeb\x95\xa4\x8d\xfa\x94\xbcQ\x0c\xd0o\xf4=\xc8\xd6\x13\x0dW\xd9\xc4V\xad\x0b'3\xfbx\xe0\x8f\xc0\xf97\xcb\xb5\xb6\xfaHhP(\x82\x0da\x16\x1e\xb2M\x05&\xe5V\xf5\xf9*X\xc2\xc7@\x15R\x8c=\x08~\x8d\x99\xccF\x1f\x15\x05Rr\x02\xa1\x84\x1f`U\x91\xaf%;\xe7\xed\xf3\xcd\xca10ZM\xca\x0e\x0d\x9dT\xd2q\xc9$\x9d\xec^\xb1\x1e\x8a_\x1a5w\x8fnK\xa2\xa1>\x11\x93\xc6\x89\x98\x18O\xc4D=\x11\x13\xc3\x89\x98\xe8'b\"O\xc4\xa4\xa1\xde\xd3\x0e\xeei\xba\x9f\x14\x05F=\xb2o@\xd7vMNI\xf1\xa5\x8f\x04\x89\xf0\x8c\x84\xf5%\xd3\xbb\x0e\xcd\x1b\xca\xe5\xd1v>\x0f@\xc6\xc9\x95\xe3\xb7\xd0e\xd8%1s\x85\xdc\x04\x85<\x1c\xb7\x18\xa9\x88B\x07\x81\xb8;\xfa\xc4\xe3\xb4n\"\x1d)\xd0\xcb>\x9f\xf2\x91\x1d\xf9U\x97\xfc\x15\x9d\xc4 \xcc\xcd=%\x8d\x11\x7f\x15\xb9T}\xe7\xc7H\xfd\x05I\x7f\x96\xfeGG\xfe\xcc\xf8J\xf3\\\x92\x10\xcf\x87\x8d4X\xa6\xabY\x92\x95\x93\xec\xaa\x0biR\xb9\x86\xe35\xc9h)\xeby)\xeaQ\xab\xe9>5\xe4)G\x03\xb2\x167\xab\x1d\x1e\xad\x14D\x9fd\x10z\xb0r\xc3Iy\x85\xeb\\z\xb2\x17\xaf\x1c\x94;\x19<_\x82\x11\x17\xab\xd7\xb4\xed\x95\\\xd9h\xfe\x94w\xf94\\\x90\xa3\xa4\\\x864\x9a\x0b\xedd\xb6\x19\xcen\xb3\xcaP\x99{\xc9b]{\xed\xa0*BGY!8m\xceA\xad\x8f\xb1\x9c\x87%\x89\xcf\xc9,))\xd7q`uhS\xc6A\xcd\xb0|\xd5\xfc%l\xfe\xacR]\xaeS\xab\x0d\"\xf1<(\xdd|\x92\\\x89\xe9\xe8\xd9\xe9P\xa3?=\xae\xed\xefLy6HPh\xc3B\xfcR\xba\xed\x0f\xa2\x07>c\xd3;\x17\xaf\xb4/\x9e^'\xbfB/\x19\xf5\xc1\x17kwg\xa7\x02\xe7\x8e\xccH\x06\xb7s\x1c\x91%\xc9b\x92EI\x95M\x01\xf1Iv\x15\xc4J\x0ee\x10\xf2\x97\xa4K\x9a\xfd\x16\xfb\xaam\x95e\x83\xa7\xb6\xda\x91e,\xfd\x19\xd5!\xb5s/\xf3\xb2LnR\xd2\x82M\xe1\x01\xa0 \xa1\x19;\x9e\x10y\xbc\xc7\x11a\x8c\xc9>\"#\xafVf\x97\x9d\x81u0\xba\x8a\x83\xe7\x92&~0\xb0\x95\x0bu\xd6\xbf\xa7\x1b\xe5\x8fw\\)e\xc0M?\n\xa5,\xb2f.\x0e\xc3k\x11\xeb\x0e#m4\xd1G\xa7\xe6\xe2N\xc5\x8e!\x133\xeeI\x10\xadH\xb9\x93\x8b\xafr.\x9f\n\x9c\xc4\xf3\xe0\xad8\x17\x80\x0dD\x9fH\xa1\xf6L\xf4\x8c\x88 \xe6\xc0\xf66/p\xd2\x87\xce3 \xe2\x06T\xb7\xc7\x8flUk\x13V\x17\x16\xf6\x1d\xdc.\x84\xb2*\xb3[g]\x1b\xc3\x86\x8e\xbbNqn83\x08\x8f\xcb\xa7\x02)\xd4\xac1`^\xf9\xe0\xc9\xaeC@\xd1 V\xa0\x80\x96}\x96\xb2Iq\xd5\x01uP\x1f:b\xc2\xdbQ\x85\xe4\xd3u\xfe\xcaG\x92\xcd\xab4\xed\x82\xaa\xeb\x82\x94\xa4\xb1}Gv5Nh\x11[\xb9\xb8\xe4A\x8fg\xad\x8d\xc3\xe5\xe1\xe2\xb2\x94\x91]\xed\xe1Wd\x8e\xe4'\x8c\x97O\x12\x88\xedg~\x1f\x12\xa1\x1e\x0f\x9e\xdb\xde\xd7\xa2{\xd4\x88\x13$Yk]\xd6\x8evC\xbc>\xf6\xa0\xd0\xdb\x0d\xd5v\x8bI\xd8\xbc\x804j\xd9\xaa\xf4;_\xcf\x87S\xe9\xdc\xa3\xa2\x99VG/\xd0\xee\xd3\xdd\xa7\n\xdd+Hw\xf7\xb51\xfe\xc6\xaaC\xdd\xad\xa6\xb9P4\xfc\xe5\x0b8\xab\xecS\x96\xdff[\xb8\x8e\x9a\xf0\x85\x04\x11w\xe9p\x19\x163B\xf1biF\xe8i\x1e\x93\xb7E\xbe8\x16\xf7\xa8n\x81\x97\x84\xfb\x10\x06I\xb6\xce?\x91?\xad\xc2\"&\xf1a\x98\xa67a\xf4 }Cp\x7f\x99\xd8-\x82W\x14\xe6\xbcU\x16\xdf\xd0zc\xef4\xa9\x8a\xb6\xdeER\x8e\xb38)\xe7}\xf8X\xecK\x87\xe6\xcb\x93|U\x92\x0fK)\x94b\xd3C\xf3\xe5e\xbe\x8a\xe6\xe3,6%\x1f\xb2\xf1\xa7\xe2K\xd7\xb6N\xca\x93|M\x1e\xd0\x1dV\xcc\xd4\xb2\x92\xde\xdd\xee\x05\x0d\x0b\xfa\x80\x86\x8f\xf2\xdb\xcc\xd40\xd67\xa0e\xa1\x82{\x94\x14$\xa2\x129\xf4u\xa2>\x1c\xaf\xe5\xe9\xf8.))\xc9\x88M\x0b;k\xe6\x960i\xc0\x03M?T\x94\xd3\x10\x8cXx\xe6\x18\xa1\x8dA\xb4\x19\xde3\xcf\x18\x18\x18\x14\xfc\xc4\nS\x97\xd83J\x95<#\x90\xfb\xc6 0}\xac\xc6[},\x06-\n/M\xca\xe36\x95j\xb9\x16]WV\x80C\x97\xa6\x18\xbc4\xec\x9c\xd5\x9d0w\xe8\x01I4\xb6\xf3\x06r\xf8\xa1v\xd5\xfc\xe4 l\x90 )\x19b\x0fg\\[\x9e\xe6\xcb%\x89]\xef\x0d\xe4\x9b\x9b^\x8d\x1d'\xf9\x95\x0fE[U\x12\xa4\xc2\x10^X7\x90\xa9!\xe3\x03W\xe9!K\xc4Fr@/\x8b\xd5`J\xbe_\xbay\xff\xed\x06\xf7\xdar`\\[\xdaI\xbc)\x84!\xbf\x19\x87\x1f\x1a7\x7f\x1d+\\lnv;\x18B\x8azR\\\xb1Ue\xe4\x9f\xa2\xfd3)\xdajG\xa0\xdc\x15\xa0\x87\xe0'O\xd8\xa6\xe6\xc1\xb3e\xc1n!\xa9\xbe\xd8Xe\x97\xfaU\xe7\xde\xee\x847\xda\x05U\xf3\xb0\xac!\xaa\x0f\x80\x14\xf1E\xbb\xbd\xaeV0\x9e7\xef4C\x98\x0cq\x0el\xab\x08\x0ce\xf5@/\xed\xd6t\xd4|\x9f\xd6Zh\xbd\xbb\xb5\xa4<`k\x81\x0e#{\x91\xa5\xe4\x18\x82\xba\x14\xcf\xdb3\x9ew\xf9-Zw,\x16y\xf6\x90\xe6,U\x0cj\xfb}\xc8\xce\xa1{\xce$6\xd9,\xd93\x8f\xb4\x08\xd7\xa4(\xc9\xe5m\xfe\x9e1\x8c\xc3\x14\x11\xaa\xe6\xf4\xe2U\xa1!m\x8e3J\x8aw$\\\x1bZE\xd7\xe6FYu\xab\xed\xba\x1a\xadp'\xfc\xa0\\&\xc93\x93g\x0f\xfe\xf10_,\xf3\x8c\x11\x03\x05\xe9]\x00\x90'l\x1b\xbf\xb4Q7\xaf\x9fU{\xc9\xc7\x10\xa6C\xea\xcf\xcd\xf5\xff\xce\xfcfa\x8f8\xc6x8{\x042 U\x95\\\xf1:\xb9\x0dd\xcc\xb1\xaah\xcb\xa4\xa33j\x14kUQ\xa1\xc2\xc9\xee6\x86\x02\xe5^M\xe3FL\xccN\xcb\xca\xac\x9b}je/\x08\x1a\xca\x1c\x86\xab\xd9\x9c\n\xd7\xe1\x9d\xb2\x02v\x8aY\xcdr\xd6\xc2&\xd4\x12\x14\x86\xdb\xe4\x14\xf5Y\xf4\xadp\x91<\x1c.\xcc\x164&n\x97S7\x94\x13\xd7_\xbe\x00 \xca\"\x1a\xa7dA2|\xbfM\xb28\xbf}\xa3O+\xdb\xef4@\x9b\xaer\x99gq\x92\xcd>\x94D\x96\x93\xfaG\xd6\x1c\x9e\x0f\xcfxh\x9c \xcbc\x82F\xfd\xfb<\x8c\x1c\xc9\xf0\xe0i\xe8(|\xab5\x8e\xd0-t\x9f\xaa\x163y\x10\x85\xd9\x87\x92\x1c\x9d\x9dT\xe0\x1b\xe7\x11\x1a\xef\x06\xc9b\xc9{\xca/'\x9f<\xb1}\n\xe6a\xf9\x96\x84tUH\x7f'\x1b{\xd6z\x94\xcc\xae\xe3\xf8\xa8\x1d\xdc\x98\xd9\xed\xef\xbekB\xcdwp8'\xd1\xa7\x92Af\x98q\x81?$%\x94\xab%[_\x1e\xc0\x89\xce \x08.IP\xc7\xe82=['E\x9ea7\xb4J\xf56N\xcf.\xc7#\xb8\x9c'%\x8f\x0f\x95\xe5\x14n\xf3\xe2\x13\x08\xa3\xbd\xf4\x0e\xa9\xce,\xcf\xb6f\x8c\xc6I\"\xde\x13\xd6\x8fh\x0ea \xbf\xf1H\xca\xbf\xf9z\xd5\xbf\xa1\xb8\xee7\x1f~K\xf30f\xff\xd1\x08\xfc7\x1f\xa3Q\xfd\xc6\x1ds\xfc\xd6\xd7\xc1\x1f\xf3\xa2\xc8oK\x98\x16\xf9\x02N\xf2\x98\x14Y\xf2\xf7\xa2\xaf\xd4\x1f\xd1^\x14\xfe\xc1\xb5\x0f\xbe\xd6\xd7%\x17\xab\xe94\xf9\x0c(D\x84L\x98\xaf\xcf\x02p\xa24\x89>9z\xbdUE\xfb7y\x9e\x920chq\x89K\x8e\xab\xc3\x16\x07\xd7@$\xa2\x9c\xb7\xb1J\xed\x1a\xa51AU#c\\dE\xedenW\x90\xb036\x0b\xd3\xd6\x874\x89HV\x92z\x9a\xe0Y\xb0\x13\xec,\x0b\x02\xee\xe1\xaa\xa4\xf9\x02~\\%i\xec\xc1\x1789\xbe\xd4\xcao7\xde}\xbb-\x9e\x8eL\xd0~@\xddS_\xbe\xf0[\x82\x0d\xd7 \xe3\x18\xe7Z\xd2\xc8\x0e\x83Z\xb9GjVA\xbfY\x91\x1c\xb5\x93g\x0el\x9a\xfc`\xa1PP\xad\xecM\xbbOF\x92e-\xae\xa0\xab\x8d\x1a\x15$\xa4\x12=\xb9N\x9c\xacM\xea\x1daP\x12z@i\x91\xdc\xac(q3\x1f\x84\xb3\xe47\x8e\xd0\xfe7\xaa\xc2\x84\x93\xcc&2\x05\x85\x9d@Mb\xae\xbdr;'\x95\xd8\x0c\xa4~\xf2\x10\xac\xc2\xef\xe6\x03^\xde\x07\xe7Y\xb0\x83\xaa\xd6\xc9\xa3!\xd3\xd6\xd1}\x90\xd2\x118aJ\xffL\xee\xf4\x90\xbayF\x8b<\x1d\x81\x13\xd1\"m\x7f?!4\x1c\xa1\xdb\x82\xb0\xfd\xf1b\x9eLY\xcd\xa8W\xcd>\xd7C\xb0\xd0:\xb6\x03\x0e\x0dW\xb3\x90&k\x82\xf3\xd3\x86\x12\xf43v\x92\xc7\xc94!\xc5\x05\x0di}\x8d\xd4\xfe\xd4bO%\xa0\x16\xad\x1b\x83\x8aS\xc43dc\x83\xaa\x90PC\xc1\xb0\xf3\xbau\xcd\xf2\x08K\x99\xb9\xaf^\x1b\xd4_2\xf7e+=\xe1j1\xbb\xdcv\xf4\xd9k\xfc\xf7t\xf7\x95\x1e\xfd\x9a\x8b\xe4w\x9f\xeb\xe5W\x98\xfe\xec{\xb3X\xbe4b\x151d\x93h\x92S\x18\x93\xdd+!\\\xa7\xe8\xb5\xf8\"\xb9I\x93l\x86\x1eu\xa6IQ\xd2\xc3y\x92\xc6\x86)_\x8b\xab\xf6\xc4\xedc\xafH\x90d%)\xe8\x8fd\x9a\x17\xc2\xb1D]\xa1q0\x91\xad\xaeB\xd4\xc58\x0dQ_\x8b?3\xe94XM\xb7Z3\xb3ob\xdcl(07+\xeaTaK\xec\x840\x8fI\xa4\xcc\xb8]\xb8\x95\xba\xdc\xee\xba\xe0\xd7\xf7\xdc\x82\xbdCk4\xafh_\xf5\xd1\x88g\x1c\x1cZ$Q\xb4\xdaA\x91s:l2\x97\xd6\x03l\x88\x1c\xae\xba\xcf\x9d\xec\x1a\xee\xdfb\xac\x1b?\xef\\\xf1;v\x12\xf0`\x9b\x08\x89-\x0eK\x0355+\xed\x1eFl\x83\x89\x8e\xe5\xab\xc4\xef\xddK\x87|P\xcfR5\xfbZ\x0cc\xfc\xe6\x0861\xa3\x15\x8b|U\xa6w\xe7d\x99\x86\x11a$?\xe3\xe3N\xc2\xe2\xd3j\xd9DS\xeb\xb6k\x8c\x9e\xf2-\xef \x05\xcfuD\xd2d\x91P\x12_\x92\xcf\x03\x0d<\xe4\x84\x11\x8571K~\xf9\xbda\xe7\xb4\xe6\"\x1c\xe8>\x17\x9e\xa7n\xe1\xeb\x14\x08\xeb\x19\x8a\xf6\x18\xe4\xe4x=\x02\xfb\xe0\xae\xf0\xde\xcf\xf3!v\xf9u(E\xd5||\xeb\x95]-\x8b<\"e\xf9\x01=\x14\x97\x03\xc4e\x0d\xeb\xae\x9d7\x90)\"\xe67\x90\xd9u\xab+\xf0\xb2\xea\xabHS\x98\x02oXm\xf5@\xa5]\x7f|z1>\xbf\xbc>98\xff\xf3\x87\xf7=j\xf6\x88u\x0b\xe9\xd8\xc7\xe7GJ\x11\x84SJ\n6\xa7}\xd1\x0d\x06\xd9\x05\x9c\x9c\xfd<\xbe\x1e\xff\xe5\xf8\xe2\xf2\xf8\xf4O=\x1d\x9a\xf2\x0eL\x85\xb8\xf6\x9f\xd4\xa3\x8b\xf1\xc0\xf9 \x1b\xf3\xf3\x18M_\x8e\xffry}xvz9>\xbd\xeci|\xf5\xe8\x8d\x9f\x8fq-N\xcf\x8e\xc6=m/\x9b\xeb0T\xc9\xe9\x9e\xf2\x9a5\xa6>\x88\x1a\xb3{\x01\x9a\xd3\x05#\x9f\xe7\x94.G\xdb\xdb\xb7\xb7\xb7\xc1\xed\xb3 /f\xdb\xbb\xaf_\xbf\xde\xfe\xcc>kd\xf3\"\xa4s{\x99W\xdb'!\x9d\xe3\x9f\x93wZ\xc9r=3\x16{\xba\xb3\xb3\xb3]\xaeg\n\x01\xfe8C\xed%u\xd5\xe8\xe9\xb5\x0d\xf6\xc9\xc5\xc1r\xc9\x10(\xfe@S\xde\x0f\x19\x0f~\x1f\x85\xe9[y>*\x94P%\x826\xaa\xbfvV\xd3\x1f\xd6N^L\xa9\xad\xb4aI\x17\xac\x8e\x1e\xdb\xdb\x8cQ\x8d=s_\xed\xbc4\xd0\xf1\x99\xfb\xf4\xc5+\xcf\xcd\xdc\x97\xdf{AR\xfe\x1c\xa6I\\\xc9\xe6\x1a\xb9CE\x19\xdee4\x7f{\x12nV\x94\xe6\x99\xd9\xaf_4'\xd1\xa7\x9b\xfc\xb3\xf9k\xb2\xc0\xf8\xfe\xa6O\xf3$\x8e\x89\xa5\xd2\"\x8c\x93\xdc\xf2\x89\xa0\xed\xa6\xe9S\xb9\xbaY$t\xd4\xd2L\xb6i \xe9\xeb\x8d\xe2\xee\x0dv\xc8\xe3\xa0H\xfc.\xc9>10\xac?`x\x04\x99\\\xb8\xce\xab\x97N\xaf\xae\xb2\xde\xcc\n\x95X]\xadR\xa9\x9f\xc8\x93\xf2\xec\x10\xe5mR\xc7\xfc\xd5\xab\x9ev\x0c\xdePZ\xed\x88Q\xf5\xb4\xf4\xba\xd1\x92\xfc\xc5\xc002\x9a\xd2\x8a\x88\x11Ch-P\x18f2\xa1\xa8\x93\x19N\xb8.\xd6\x15\x17N\xcb\xee\xf0\xb7\x82\x84\xf1Y\x96\xde\xf1\xb78)\xc3\x9b\x94\xc4\x8c\xbcb\xfd\x1f\xa1\xcb\n\xe1 \xeb\xd7|%\xc3\x83\xc6\x10\xc2o\xd8\xad\xdfX\xd2\x12h\x0e!\xa3y\x160MH\x1a\xc3mB\xe7\xf9\x8aB\x98\xc1o\xb2\xc1\xdf`\x1efqJ\x8a@\x91\x93\x16$\x8bI\x01!\xb0\x8el\xe5\xac'XC\x00\xc7\\\x90\xc7\xeb+\xe7\xf9*\x8d\xe1\x86\xc0bEY\x171\xd4\xfeo\xc22\x0e\xbd\xf7\xfd\x16\xc0\x19\x9d\x93\xe26)\x19\x99@(\x90\x84\xbd\xab\x1d\xc8\x0b\xf8M\x8e\xf8\xb7\xc0d2n\xd9~$~\xf8\xfc?\xe2\x94\x8b\xbe\xfc\xb7\x98\xf4C\xd1\x97\x7f\xd2\xb4\xcb\xd2#H\x026\xf3\xbf\xeb\xc8?\xb5\xda\x13-\xdb\x9b\x16u\xc8m|\n\xbf\xcb\x99\x11\x94q\xdb\xfc\xbf\xd3J\xb0\xe5\x08\xe95\x9b31\xa9\xdc\xff\"\xe4S\xf8\x8d[~m\x82\xf3[\xd0\x0ckh\x94]::m\x00\xa2Oq\x0b) \x18\xbc/\xf2%\x1aE\x0c\x83\xcc\xa62td\x03^6\xbe\xc8\xa4\n-%\x16\xd1\xa4\xb8b\xc74\xe7\x9a\x1c\x06\x88\x8e/\xee\xeb\xf2\x0e\xcb\xa9D\xf5\x89\x83\xe0\xcd%\xdb\x89\x0c\xfb\xc7\xba5\xedV\xdb\x99T\x99\xafP\xd5\xdeN\xde.u!\x81|zI\xd4&d\xcd\x08\xfdY\xc7\xbe\xa6.V\x9a5\xf5\xf1\xb5\x8f68(\xbc\xa8\x12\xff_\xf6\xfew\xbdm\x1cY\x18\xc4\xbf\xf7U\x94\xf9;\xa7\x0f9\xa6\x15\xc9v\x9cD\x89\xe3\xe3v\xdc\xd3\x997\x89sbg\xfa\x9d\x9f\xc6G\x0f-A\x16'\x12\xa9CRv<\x93\x9c\xeb\xd8o{\x0d{\x01\xfb\xec%\xed^\xc2>(\x00$\x08\x14H\xcaq\xf7\xf4\xec;\xfc\x90X\x04\x88?\x85B\xa1\xaaP\x7f\xc4_\"X\xf5\x8d\x15\xc4\xdf\xee\xfb\xc4\xa6=\x8d\xbd\xeb\xa7\xea\x11\xaa\x8d\x84\xd9a\xf5Z\x1f\x81|\xdd4\x06i)vVn\xc6V\xc1\xb7+$T\x94Ql\xd7/\xe4\xfd\xa9\x1c^m|M\xb3q\xb4\"\xab\xc8vJ\xf2{\xa4\xfd\x10\xce.*\xf8\x1aFI\x10?\x1c;\xd5!\xb1\x08\xe8\xfd\x12|\xa7\xe4\x18\xb7\xcc2\xfb\xe2\x1f*\xf5\x8c\xa9\xc4\xb1]\x88\xa0\xd2f\xa0\xda)cI\xa9\xd5\xa0k7Z\x95T\x15N\xab\xcb\xd26|UO\xe5\x98\xb4/b*\x90\xb3@\x92L\x96\xc8h\x18\xc4\\@\x06\x8f#\x8a\xc4M\xb6\xc1\xc1\xaa\xa7\x95<\xd0X\xf0\x0dv\x06\n\x0bd\xae\xd6\xca%\xabN\x83\xdd\xa6)\x0e\xb9\x8f\x95\x8a2q\x9f\x8e\xcc\x87\x16\x0du\x00\x8f\xb0\x0e\xfeQ\xf0}\x82\xdc*\xda\x1f\xa2\xa0Xa>9\xe5FB\x80N-\xa2\xa4\xba\x9a\xec\xdbwFZl\xb1\x9a\xcf{i\x16#\xec\xc2\xedZE\xadV\xd1z\xff)\xa1\xfb\x89\xdd!%\xb2q\xdc\xa8cjW\x84\x87\x90\xb4\x10\x15\xe1\x04\xc4\x0fg\xcf\x9aK\x08*\x00#\xcd\x8a\xf89\x06Q\xb2\x071\x03\x7f+\xab\xdc\xb3G\x91H\x99\xb9\x95\xfal\xc4\x7f\xa1\xaa\x1e\xffp\xdf\xf8\x96\xd06\xd6\xef^\xc8\xd9y\xc1\x15\x9c\xeb\x0b\xb75\x10\x7f\x132\xa6^\xb7\xd0\xea\x12\x17\x8b\x18\x81'\xab\xaca\x85\xbd\x94\xbd\xceU\xd0I\xd7=\xb7B\x1e\x12b\xf5\x10\x91\x88wUl5\xfe\xe6\xa8^%\xb6\xaa\xc40\x84Z\xfcG\xbc\x8dV\xe9\x9a\xd1T\x07\xff\xc4\x97\x9f\xd8\x9d|\xf7\x89\xdd=\xc4Z\xd17\xcb\"Tf\x1bAV\xac/M\xaa\xbdCo\x08\xdea\xdf\x11y\xd1\x1bb\xf1\xae\x9d\xba\x9bH\xf8\xa3\x80\xfd/\x9c9\xf6=4J\x08\x14u\xf7\x1f\x8d\x0e\x87\x97\x8f\xae\xc3\x0e\xe7\x87\xbaZ\x1e1\"\x96c\xa3._\xc5\x0f\xfdV\xa0\xf4q\xda.\xa0\x1c\xee\xf2\xe2\xe1&@\x11\xe0\xf0U\x8466\xea\xa3\xb7)\x87\x95\xf8\x8dQ1Y/__ D\xf4w\x05\x83S\xbd\x18\x04\x81\x06M\xff\xb0\xff\xe5p7xx\x80V\xf8J\xd3\x8a\x07 \xce\xec\xe2\x8a\xf6\x0fP\x916\x18\xec\x9a\xd7\xe6\xf2z]\xde\xab\xef\xef\x05\x9d=\xda\"BN\xec\xb1\xe4\xbf\xd6l\xcd\x04\xdfP\x8f\xccm\xb7@h\xbbJ\xdb I\x94\x1a\xcf?\xfd\x14+\xe8C\x0csQ\xa9\xb8\xe4\x82\x8ah/z*B!\x11\x014\xb3\x8e@\x92\x04fF\x8a\x8e\xf2\xf7\x0b\xd8\xed\xe3\x95\xdb6x\xe0\xf3&\x86\xc0q5\x93a\xaeB\xf0\x02^\x16x\xa0g\xffs\x87\x16p\x9d\x1fh\xeb\xed\x1a^\xa2\x0e}\xad\x03\xbd\x01\xdb\xed?\xce\xdf\xa6\xeb\xa4h\x97\xa0\xd4R\xd1\xfd\x83n\x86RH3\x94\xdeXH\xfclZ\xdaT\xd77\x89!I d\xaa\xecr\xbb\x08\xed\x8b2\xd9k\xe9\xbc\x88U\xed\xe1\xa9mc\xaf-\x94\x9cEu\x84\xd2\xeeb\xbd\xf1\x8a\xa1\x95\xa9\xea,\x87#\xea\xad\x08\xbf\x88\"\x13\xf5\xcd!\x8c\x8a\xcb\x10\"\xebB\xbb\x11 \xaf\xa51^\x07\x11\x93\x91\x03%\xdej\x03\xa5\xbe)\x07\xda\xecM \x07\xfac\x9aM$-\xe8\x8aM\xf4bH\xe3\xder@Z\xc3(\x98\xf0\x11\x15fJ\x0crH\xf2\xe6\x1e-\xaa\xba!T3\x9aH#\xf4rd\xd8\xf0\x7f\xf0\x9e\x14\xac\xaa2\xbdo9l=\xc1\x82\xa6\xd4\x97\xbf|\x02\x99\x85\xf5_\xd5\x90\x17\x84\x9b\xa2a\xd2\x80\x86\xc9e \xf0\xb0\x0b0\xcfYA\x01\xd2\x05\xc5\xc4 E1[?\xa1\xc0\xf8\xe5\x0b\xd0\x05\x870\xba\x0c\x02\x85\xb0|\xd4\xa6{\"=jy\xe3\xe4\xd8=\x0e,\xa86\x8327\xc7h,\xac7\x96\xc9\x0e\xf9\xf9\xdb\xbe1\xcc\xe5\xec\x0093\xd6\x99.\xf7I]\xc0\xee\xae\x87#\xe7\x07\xea\x86l\xc77x\xc9'\xfe`/\xa0\xb8\x90\xbd}\x9a\x0b\xe1<\x86\xee\xaf\xa9\x8f#\xbd\xff8\xba\xdd\xed\xdeT\xc1\xdeP\x928I\xa7\x8c\x16j&\xf3(\xe3\xa5h/\xccP\x1b\xc0yI_(\xbaU)^M\x0d\x84?ARZ\x06\x0e\xf6\xf8\xde\x92\xc8P\xc0\xcbC\xd8\xdbE\xd5\xc1^\xa9[(`\x08\x1bJ\x9a\x15h\xad<\x15\xd2\xc5`\xf7)y\xdd\xbao\xde\xc2b\x98\xc7\x91`\xa1${si\xb0\xe3k8\x04u\x0d]\xe9V\xeaurB\xfbR\xaf\x81q\x0e\xcb \x80\xf5\xb2 \x86,\xa8+k\xec\xdb\x89\x85\x90\xeae\xde\xc3M\x97[\x18a\xf3\xf7\x18\xaa\x8b\x05|\xdfD\x8dJ\x0fdf,\xf2\x84\xe24\xa15\xe9\xd3\x0c\xe7\xa4\xd4Ex\xb5\x8c8\xa8$\xd2yO\x1a\xf7\xaam~X\x0f\xfe\x9e\xe8w\x01\xc2\x8eK\xf4\x94\x04\xbc\xea\xec\xbe\x08\xb5\xfb\xecI a\x8c>\x83j5\xcff!4\x82\xbe\x93\xbc\xa2\xf7\xe3\xcaJ\xd3\xb2eA&1\xd2a\xe7\xb3\xde\xd5]\xc1\xde\x08u\x12\xcd\xf8b6\x9a\"\xe8\xe5\xac\xf0\xc5\x0f\x0cb\xdd\xe6\xdec\x8e^\x05\x87\xc4\xf5\x9b\xc7yo*\xe6\xa5R \x0e!\xe2EJmm\x16\xba\xc1\xa0\x00\xaam\xfc\x01n\xf2G\xfa\xc6\xff\xef\xbe\xd8\xf8\xfa\xbeG\x94\xc4\xa8\x0b\xc5\xfc\x03\x9b\xac\xb3<\xc6$\x86\xebP\xf8r\xf1\xf7mWB\xb8w\x8d\x8dk\xedX\xc5\x95H\xaabs\xab\x9e\xa7|(\x84s\xb8f\x1c%\xe84z\xda\xce\xd2u\x82~\xbcY\x9a\x16\x8e\x9c\x98\xe6~\xc6I\xce\xa3\xfc\xa3BhmB\xc0\xec`\xf3q\x15\xc4\xb0\x99{\x16&B$fuq\x8e\x01\xcb{ \x94\xfe&u\xec\xc5c\x90\xfc\x1a\x14\xf4}\xe4\xc0\x02\x02\xd9\xd4\xf3\x95\xcc\\V^\x94\xb9\xc6\xa7\xae\xdbb\xdf\xb4u\xd5\x9f\x08\x15\xaar\xd4\xeeyjg|\xd4qV\xe9(\xb9l\x99\x18\xb9\xdb\xaa\xe4w_\xeb\xb2~3\xef^\xa2E\xa1\x19(;\"yH\xc3\x12\x91\x92\xbdL\xf9\xa9l\x9cD\x96,\xe1K\x89\xb9 \x12\xf9\x13\x0fl.\x89\xc8\xdfe.fyh\xf0wE\xc6\x98\xe5\xd8EN\x14\xcd\xb5Y]B\xf0q\xdbh{\xa3\xe8!w)l\xb1:\xc6\xd0\xa8d \xcb7Q\x08\xef\x83\xc7\xa6\xbeD\x08\xefOLY_\xba8\x0e\x1e\x93.\x8e\xcf\x06OZ%\xac\x86k\x04\xce\x06Q\x97\xc0\xbc\x81]G\x19\x17\xf2\xf7\x1ce\\\xc8\xdfw\x94q\xf1\xfe\xc0Q\xb6\x82Cx\x0c\xea:\x9cH\xa2<\x05y\xfd\xbd&iV9\xd9\"\xe4\xb4w\xde\xc8D\xdf\x84\xb0\x0c1\xd1\x1bnKL\xea\x96\xfa\xd7A\x08W\x98kv\x8d\xd9\xe4\xf6\x82\x10\xc6\xfcL\xf1\xef*6\xfbV\x90\x99S\xf4\x05?\x82)\xefo\xccE\xa4\\\xfd\xeaW\x06R\xcfa\x0c/\xe1\xf69\xdc\xba\xb6*\xdf\xa6\xfe\nc_p\xa2,\xa3\xe4/\xe1\x10\xae\xfc\x1b8\x84\xbb\xd1\xede\x08\xb7!\xf0\xc1\x99Z>\xb3\xa1$\x80\xd3\xd1-\xe7\xf5\x974\x11\xe1OI\xc5\x96A\xb7TA\xa0\x18\x9a\xbdf\xbf\x17\xd0\xcfjw\xff\xa0\x9a{\xdc\xb9\xb9\x9b\x0e\xad\x1dtn\xed\xb6Ck\xbb\xed\xad\x9d\ny\xe5\xc6\xbd$\xda\x891i\xe4\x7f\x14\n\xc3\x11\x17K\x86\x80\xd9\xf5&p\x04\x13\x18\xc2i\xad\xba\xe9\xeax/\xcd\xa9\x14\xdb\xc4a^j$\x8a\x10\xbc*\xd3\xb7g\xfa^H\xd3z\x9d\x0d\xe3T\x13Sv\xa5Y\xfcW\x95\xde\x1d\xcf\xdf\xf2\xe5\xf1\x04\xed\xca\xa4-\xda\x0fQ\x1eO\x8e\xd7\xc5\x9c%E\\\xa6bpV\xff1\xcd\x96\xef\xa3,Z\xe6F\xad\xd5jA~\xfe\xbeJ V\xf4V\x19;V\x05\xaf\x97\"!1\x16\x9c\x9c\xbd\xfb\xf1\xf5\xef?~8\x1d\x1f\x7f\xbc\xf8 _\xfd\xf1\xf8\xcd\xebW\xc7\x17\xa7\xf8\x83\xbf=\xfb\xf0\xfa\xff\x7f:>\xe3\x7f\xee\xe2\xcb\xf7\xb2\xbaU\xf0\xe6\xec\xf7g\x1f/\xea\x1f\xe2\xaf\xf3\x9f\xce~\xc6O\xc6\xef\xcf\xde\x7f|\x0f\x87\x8a(|W\x81T\x86\xcf\xf5\x13\x7f\xff\xb1yE\x9f\xca\x92\xdd=\xea\xf2\x1e\xbf\x19\x04\xb5C*\x9f\xa7\xb7\xaf\xf8\xa2\xc6\x1c4\x9d|\x9e\xecm_`\xea\xf9 A\xa1\xa3\xbbE\x1aM\x87\xcdbG\xb9\x16\xdf\xd2;A\xfe\xbb\xf5\xbeH\xaf\xd3u'V\xdf\xd5\xf5\xea\xbe]\x97\x13?\xe3\x7f\xed~\xcb\x18\xa6\xf7\x1d\xc3\x04\xa3=\xaf\x05\xe2\x7f\xcb\x08\xe6\xf7\x19A\x1d\xb1#\x85\xbe\xfdg&\xfe\xaee\xd1\x9ee\x96\x92\x0bV\xa7OZ\x9e\x10nEJn\x13&\x1e\x15\xf5\x92\x8a\x1c{zJ\xacv\xcf\xa26\x89\x89c'{|\xab\x8dW\xe9j\xbd\xf2\xec+\x8c:%\xf0J\xcc0\xaa\xae\xea\xf4\xc3\x13\xc8kT\x9ab\xcaK\x17\xf9\xf1V\x19\x1b\x97\xed\x8fSD=/\xa4\x89\x98gU4\xa0?\x17}i\xc4\xd0S\x17\x97\xd8\xa6E8\xbd\x12\xe1p\x10^\x8d\x1a9\xe8o+NV\x9c\x1c\xc5\x95\x94\xcay\xdcp\xc7X\xb3!\xe2m\xd1cY\xd6XKx\xd2\xf3\xc6\xe8\xf2H\xc4,K?\xb1\x84\xae ,\xa8\xa5[#]e!\xf2RM\xe6l\x19\xd15&\"\xc2E\xb4t\xf8\xfb\x8b\x9b\xb1kV\xf8\xdel\x91\xdeR\xe1\x82d\xc4\xf4uO\xe2x/\xbf\x8d\xae\xafY\xf6\xf1\xf5\x076\xc5\xb8\xcf\x822\x85\xe0E\xe51+t\x063\xcep\x88\x1c;\xbd\x84\xdd\xf2e;\xcd\xcc\xa4\xfe\xea\xe1\x8d\xbc\x9e\x92G\x04\x7f\xf2t\x9dM\xd8P\xe5\x90\xa7\xe1\xc1n\xd8b\x08\xdem\x94%qr\xed\xa8%%\xc1!x\n\x8f\xc4\x91\xbf\x8c\xee\xe0\x8a\xc1\x1a\xddgCXEy\xce\xa6\x90\xa3y\xc5m\x94\x83\x88\x0e\x86J\x8e\x9ce7,\x83\xf7F\x95\xe4\xdf\n\x89ml*\xc2|a\x1eRQ\x9b\xb0C\x0cB\x88z\x18J\x0c\xed+~M\x10a\xafm\x00\xf2\xfb!\xc4j\xdd\x03?\xa2<\x821\x13\x97qH5\x0c\xdf\no\xa8\x1e\xdc C\x88\x88.\\$U\xa7\n\x14\xaf\xf6\xeb\x92\x04\xd6\xb8\x11c\x11X\xc3\xb9\x11\x059(\x13\xab\x91u\xd62\x84\x87\x98\xa0\x9b$Tu.\xac\x8bt\xf5L\x84zu\x11\xb3\xa4x\xedhk\xa6\xd59g\x93\x8c92\x9b\xaf\x9c&\xba\xfc\xb9\xce\xa2\xa4\x18\x8b\xf3\xdfS\x03s`\x1e\x7f\xf2I\xca\xabrp\xa6+\x96K\xfbF |\x16\x01\xac+A\xf5\xa0\xc7\x9e\xa3l.}\x15\xcd\xf7JKy\xc5\xa5 A\xc0\x16p\x04\xf3^\x9dL\x1c\x82\x87\xf2\x06\x9a_\xf2\x1d\x92\xf7\xae\x8a4\n\xfc\xa8\xcc\xf8\xba\xc6\xbbM^\x96V\xbbgEy\x9d\xf3G-:\x89\xfc\xae\x8f\x14 \x87\xb0&\xe9\x8a\xcc\xc1[\xce\xc2\x9f\xa0\x06`*\x97s\x1cs\x08M\x82\x10f\xf5\xf79\xae3\xdf<\xe8\xba\xd5y\xf2\x93r\xf2\xb3\x00\xd3\xec\x99\xf2\x9b\x83&\\\xa5\xd3\xbb\xa1ji\x1d/\xa6\\8{\x15\x15Q\xe0\xaf\x1c\x8a\xcdu\xb6\x18\x8a\xe0\xce\xbe\x87T\xe3c\xb60Y\x0e\xf5\x08\xb8\xc6\x0eD`\xd1\x94e9\xc9\x96\xf2\x07AH\xb2\xcdPR3\xe2N\xdcI\xafB\xb7\xb0\xf9[\"U\xa9\xac\xc1w\xdf\xb7\x10\xb3f\xe2\xb2\xeeH\\l\x93b\xfd\xa9a\xe7\xb0\xcb\xce\xdc\x84\x8a\xd0\xc1\x00\xd4S#lr\xfbL26eI\x11G\x8b\xbc\x9d\xc4\xa5m\xb4\xcdI\xa3\x1eb{M\xee\xb3e6\xd9{r\x83\xb4\xec=\"r~\xc7\x0d\xe4\xd6\xe9\xb4\xdb\x00\xb98\xf3D\xba:\n\xc6\xf6c\xb6hV\n;m\x8f\xb3\xb2\x8fV!\xa1h\xe5\x1b\x8a\x96\xadVt\xd8j\xc57o\xb5\x1a\xbaG\xfa\xbe\x1bO8\xc7\xefF\xf7 f\x08(z\x13g\xd81\xac\xa5\x0e\xa6!8`\xa1\xd5\x12\xc7\xd4\x10\xd6\xee\x9aj\x11\xc7\xeb,\x1e\x12V\x04\xd0\xb8\xc3\xb2\x07\xd8af\xd2U\xf5\xb4\xef\xb0t\x93\x1df'\x9c\xbe\xd7\x0e\xa2\x95\xa8\xff\xdcJ\xb5\xe7a\xb6\xd2o\xe6\xd4\xfa\xbbm\xe3\xbf\xff\xe6\xbc\xff\xf1\xb7\xd9\xe6\xfc\xa5\x8e\xbf\xeaZ\xe4\xc1x\xc7\x99C\x13%\x90\xfe\x9a\x152\xeb\x1f]+\xef\xc6\x7f.:i\xcf\x84\x824\x8d\xf2\xbds\x0c\xae\x9e\xbaR\x15 \xbdh\xbeb\x93\x96\x8a\xabrx-\x15\xa7Ho8\xe68\x96\x0e\xcbQ6\xa0+\xdc\x94W2(}\xcd\xe1\x08\xfe\xf6\x15\x9cR\xc6\x12\xdb\x93\x08AW\xb9\xae\xb7\xb8T-.\xe9\xeaw-\xec\xf9\x95\xd05dD\xa4 \xfe\x8c[4\x97\xb7p\x08\xfeJ\xc3\x07\x1f\xad\xe2\xff\xf65\xe8E\xd3)\xde\x11E\x8b\xff\xe0\xf0\x11\xd6\xfa\x82-\xa3\xdb:%\xae\xaf\xf4\xb2Y/\xce\xcf\x8e\xcf\xf7\xfc\x80\xcb\xb0\xfd\x10\xa2J\xa0\xbe\na\xd2\x13\xb1\xf7\xd9\xf4\x1cul\xbe\xc8\xac\x0cC\xa2\xee\x8c\xcfXV\x08\xeb^\xe2\xbaU\xd1-\x1c\xd5\"\xf6\x89\xa6\xb2\xaa\xa9\xdb@\\\xa6\x9f\xca\xb4\xf4\x87`\x08\xfa\x7f\xfb\x1a\x82,\x0c\xe1\x96\xb2\xe3\xe3[\xee3\x1c\xc2i\xe9\xd1\xe0;\x88\xc89\xd1\xbc\x93\xa8\xf2\xf3|\x85a\xcc+\xd9\xf2\xd1_\xf24 \xa1`\x9f\x8bG\xabE\x14'!\xfc\xee\xd1\xef\x1a\xa8\xbcw\"\x82[\xee\\\xdc\xad\x98g4\xf6y\xe7\xf6\xf6vg\x96f\xcb\x9du\xb6` ?\n\xa6\xb6b\x13\x04\xb5\xba\xa6\\\xb3z3VL\xe6\x8eY }\xfd\xec\xd8'\x18\xd6i\x08\xde*\xcd\xcd\xdb\x0c\xf5\x94d\xf5\x9c.\x97\x12\xfd\x8dc_\xe0i\xe18\xf9e\x9c\x1bt\xf3\xe2`N\xb3!\xac\xfd\xa0g\xbfw}\x9f\xaf\xd2$gD\x03V\x81\xd5\xc0\xd7\xa0\xc7\xf92\xbf\x99[\x02\x8d+\xd3,KYo\xcaO<\xf7\x92#\xf5\x97.\x91B\x1b\xfd\xe5\x0bx\xaes\x0d\xd4\x15\x88\xfc\x02;9\xd5>\xa3\xed X/\xfd\x84\x0e\xcc_\xbe@\x06G\xb0hWw\x83\xa6\xf2v\xd0Z\xe8\xa8\xd2\x86\x8e\xeaqhP\x7f\x13\x16\x85\xa0T\xe0yG\x158\x94\x8c\xc1\xd8=\x00\xa9\n\xb7\xf9zP\xdd\xfd\x03\x00\x8f\xf5\xf2\"*\xd6\xf9\x05\xfb\xec\x9a\x08\x85\xe6\x98\xaai\x03<\xaf\xacQY\xa0l\xfch\x04D\xcb\xc5r\xb7\x89\x9b]\xf5K\xec\x90\x06\xae\xf9\xa6\x0c\x00P\xfb\xc4m\xf2C\xe7\xa6\xd2\x1f%\xdbh!M*\x17\xad#}\x03\x8bL\xa4\xcd\xe6E\x99\xdc\xb9\xc2sp\xfb\x10\xbc\x10\x98H\x16%\xc2\x04\xe0\x0ft\xee\xc5\xbf\xc6S\x96O\xb2x\x85b\x9e\xfe\x91\xf6\xbe\xf6\xa9\xfeA\x93m\x92\x96k\xcb\xf6\x0e\x02\xa0|\x86\x00\xfd\xec\x7f\xf3\x18\xbd\x01\x1a\xd7^\xfd\xf6l\xab\x10\xad\xfe\x14-\x17\x82\x81s\x99\x10\x95\x19\xa7\xc8\xe8\xbb\x98k*\x15!U\xeb&\x12Y\xb3\x89\x84\x91\xbb\xb6v\xb7o\x0d\xac\xd1\xd8\x94\xdedR\xea\x89\xab\x0bk\x0c\x87\x1cM-g\xea\xc6\xc4p\xb2\x19\x91\x0fT\x13X8\xa2^\xcc\xb3\xf46\xe1\xa8\xaa\xd3\x9f 4q\xfe\xb7\xb7\xf4\x8b4\x9a2a\xc8vq\xf6\xfb\xdf\xbf9\x1d\x0b\xeb\x8bs|\xf5\xf1\xfd\xab\xe3\x0b\xfdU3^\x98\x16\xc5\xbf\x14Z\xacUh\x86Flh\xb1=\"\xb4\x11\xa5\xed\x91q\xd2s\x0e\x9e\xd9 *PrH\x16\xe9\xf5\xf5\xe2\x9b\xcc\xd1\x08\xe5\xe5}\xac\xa1\x88e\x93\x064\xf9X@\x8ep\xc9&\x96\xbf\xfcH\xcc\xcc\xd3W\xa0D\x9br\xb2m\xba\x86\x1a\xfd\xbf\x07\xf6\x97\xafK;\xadL}D\x07AG\x03\xfd<\xc3\x8bmi\xae\xcf\x92\x9b\x9aA\x7f!\xcd\x17\x95\xc9?\x92\x1b\xe4e\x95}?\xe7\xbcr\xcd\xe0\x7f\x95\xe6\xc20[\xfdz\x1bq\xc1M\xf5%\xed\xb7e1\x9e\x9e\xd6Z\x90j\xe3\xf1U:\xbd\x1b#\xf6y\xb6,e5&\xb3T\x8d/\xfe\xf4\x9enN2Vx\xbfk4\x18\xd5\x1b<\x7f\x7f\xf6\xee\xfc\xb4\xa9E\xb1\xd3\x9b\x9a\\\xd7\xe1\xc5\xc14\xfe\xe3\xf1\x87\xd7\xc7?\xbc9%\xe6,\xa06\xbe\x91\x08/\xa7\x8d-\xde\xeb\xd8\xbf\xd1\x02\x95R1\xc2\x12\x7f\xb7O\xba\xc2\x0e\x1e\x9b\xf1\xad\x84/\xecc\xb3\xbap\x85}b\xbe\x16\xee$\xfb\x8f\xcd\xf0\xa8\x0b\xe19kjK&b,\xfbf\xf5\x99\x18\xcc\xb3\xc0\xf7\xe2\x82e\x11Fv\xaaWYq\xfe\xdf\x1f]b,\x14\x8c\x9c\x91p\x8e\x1a\xe2\x04\xe4K\xdf\xf4ui\x94\xd2@Sl\xcc\xe3\xbc\xbe-*\xc8:\xdd}Q\xfa\x9a\x87\xca\xd3\xd5l>\xf7\x13\xacdFQ\xe2+u\x17\xc2U\x08c\xe1\xea\xda\xae\xe0\xc50\x10\x98 \x0b\xf3R\x9c\x94\x9e\x8e'V~Z\xf5tr;\x15148\xe4\x1a\xf2\xad\x89J\x88\x9fM\xd5\x80\x96{\x1b\xebk\xdf$\xec\x16\x12\xe9\xa7\xee\xc8\xe7\xa6\x9eMT\xa9\x9b\x8c\xa8\xfbH\xec\xbe\x08\xf3\x13\xf4P\xc4\x10\xb5\xaf\x15B\xdb\x95>K\x07 \x0e[8<\xa4n\xe3\xce\x85\xd8k\xbd?\x11\xdc\x02\x1d#\x8e?\x9f\xe0\x10NF3\xcc\xfas2\xf2\xfe\xfd\xdf\xcb\x8d\x85\xafn8>\x9d\x8cn.\xed/\x8f\xe1\x10>\xa1\xc3\xb4\x7fC\xdc|\x9d\xc1!\xdc\xc0\x11|\x86#\xb8\xf5=\x96\x14Y\xccr/\x80!\x1c\x97~\xd9\xf6g\xe8\xd4\x85\xb1&\x84~\x1f\xfb\xef\xc9\xafyoF\x82@\x8e\xf5\xefQ\x1f?\x86C\x98\xf8\xefeT6v\x0b,\x08\x02\x8c\xe5i\x86\xbc\xe2\xd5\xc7\x98\xb3\x13?\\\xf8\xe3\x10N\xe55\xb7\xb8\x93S\xa8\xa0\xdf1\x8c%\x94\"^}\x16\xc24\x08B\xf8\xcc[\xc0\xbc_\xe5\x02\xf1\x1e?\x89X \xbc\xf5s\x19i\xf4\xb8#\x95\xf9T\x05c0\xb4i8\xba\xef\xbf\x87\xadk\x0c>\x8f[}\xeb\\,\x90\x1a\xda \x0e\xed8\x08a=*\xb8\xa8z\xcc\xff:\xe5\x7fMC |\xa49\xfc\xee\x9c\xf6ObNC\\D\xbej\xb7\xbe\x9a\xa6\xe3\xaeS\xc4Y^V\xd5\x91n8*\xcbU\x1d\xc2\x19\xb1U\xe0\x9a\xdeV(\xd8_I\x1f}\xfc\xff\x84O=\xe6S\xbf\n\xe1ntuI\\\xa8\xa2\x03x\xea\xa7\xbd\xf7\xb0\x0di\xefG\xf8\x1d\x08o\xff\xf3\x00\xe9\xef\x1d\x1d\x80e\xc3(\xf7\xfa)\xb0\x95\xf8\xfb\xfb\xa8\xd5\xddJ\xfc\xc7\x83\xc0\x9dQP\xf6\xf5\x04\xb6\x0e\x1d\x829?\x80\x0f\x02\x99\x9f>\x04/\xb2ds\x10\xc9w\x86\xedDL\xf5f\x83\xdc\xc0\xb6^\xe5\\!\xefg:\x07\xdaxLG\xc9|B\xe5\x85\xe1l\xc1^\xe0[9cd\xb0\x8d\x83A\xe0{\xafO\xc7\xef?\x9c]\x9cy\xf7\x0e\xb0\x11\"g\x92\x92\x894\x84\xc2\xd2z\xbdp\xc5M\xc3P\x82\xeb\x00\x12\x0ci\x89z{\x7f\x8d\xb0\xc0\xa8\x902\xc4/\xf1\xe1\xf32 \x0e\xbc\x84\xfcy \xbf\xe3G\xc0(\xdf\xde\xbe\x14f2\xff\x1d\xfb\x0bl\xed\xcb\x97\xaa5\x1a=\xcd\xa8\xe2\x9d\x17hw\x10\xf4T\nb\x1a\xa4\x99\xb8\x8fP\x95d\xd0\xdd\xcdzq\xa1\x01u\x0bb/\xb5\x8d\x0e&\x1d\xa7GN\x06\xd3\xac\x07\x8btj\xe4$\x8a\x08\xcdy\x8ca\xe8F\xf1%\x0c\xe9\x13\xc1\x0en\xaf\x07 \xad\x97\x1e\x19\x91\xef\xab\xc3hX\xffL\x86\x88:\x82\x08\x86T\xe4\xf8\xce\xd0\xdf\xdb#\xa0\x9f\x8d\xbc\xf1x\x92fl\xe7/\xf98\x9fG\x19\x9b\x8e\xc7\xe2\xa8\xf7]e\x87\xf0\xb7\xaf\xad\x1b\xcf\x01\xd2t$r8\xfa\xa9\xd0\x9c\xfe\xedk\xd02\x1f\x17=\xbd\x9fF\x91%\xeb%\xcb\xb8\xf04\x84-\x7f\x00\xdf\x03E\x01\x94\xf7\xb4\xaa\xb7\xeb\xa8w\x9b\xc5\x85\xaa\xb3\xef\xa8\xa3\x14#\xb5\x82o\xba\xd8\xa9Z.\xb7\xef\xfe\xe3\xc0\xdf\xd2\xb5\xd4\xfc\xddA\xe0\xcbh\xbf\xe0\x89?\xbc\xa6$\x1a\xa8g\x1e\x17p\x08\xd2\xa2\xaeT\xca\x8f\xe3\xfa\xcdG\xe8>U\xf8\x98\x98L}/\xda\xb3!Rj\xe0\xc71I\xc5\x12xyXQ\xc6#b\x15%L]<\xe34M\x98\x9d\xe0\x15\x86\x18\xcc\x0d2\x91\x7f\xa0\x9a\xdb\xf6a\x19V\x8f:Feg\x04\xaf,\xfb\x19\xd4\xfb\xd1\x10z\xc3cr0\xa0\x03R=\xde\xbb\xefv++4\x05\xd3\x8fC\x88\xc4y(\x17>\xf5\x0bS&V\x0f\x1e\x05~\xe2(\x15A\xa6]\xd1\xd2\xe4\x98rx\x01}\xe1\xd7\xfeR\xb8V28\x02\xcf+\x85\x00\xbeP1\xb6\xa4\x05/\xcc\x83\x00^\xc0\xe3\xc7\xbb\xcf\x0e\x90\xbd\x83\x97\xf0\xf8`o\xf0L4\xb4\x0d\x03\xe9\xa8\xc9iKd}\xcc+\x88\x06\x0e\xf6v\xb1\xf3\x887\xf0do\x7fO\xf6/\xeacG0\xc44H\xe2m\xbe\x88'\xcc\xcfC\xec\x04s\xd5D\xb0#\x9b\xd9\xe6\xe3\xdc\x91\x83z\xf1\x02\x06\xfd\x00\xb6\xe1\xe0\xf1\xe3\xbd\x83_v\xb7\x9b\xfa\x11\xa9\xab1\xb1G\x86-3\xe9\xbeT\xd5\x98\x1a\x9c\xb5\x0c\xf1a\x9e\xc6RWs@\xebj\x06\x96ng\"\xeb\x9b\x83\x94\xca\x9a'\xffT\xd6\x10\xcf?\x955\xfa\xf3Oe\x0d>\xffT\xd6\xfcSY\xf3Oe\xcd/\xa6\xacqjj\x06duw\x18\xd1\x03\xc7\xdd\xc9\xe3\xbe\x83o\xd3\xc2\xb3w\x12DQ\xfcL\xdb$\xa5\x0d\xf9\xca\xb7Q1\xef-\xa3\xcf6\xcf J\xe2\xa4\xc3 \xe9\x18\xb0d\xb4\x19\xf2\\}8\xe2b4l\x83\n\xc2\x19\xfb\xcc\x88\xc9\x0f\x1b\xac\x8f\x9e\xc8#4\xb2\x96\xc4\xb9\x9e1c%_\xbf\xceOK\xb9/,\xd27\xe9$Z0)\x1b\x95)Qpo\x9c\xcd\xbc^\xbeZ\xc4\x85\xef\x85\xde\x86\xec\xfb\xde\xde\xaf\xa2Dq\x04\xad\xdd\xa5\x95i\xc8o\xe5+6A\xfa}\x8f\x15\x95\xea\xb2H.hk\xca\x14\xcd\x13,\xc2CH\xfd\x16Q\x923?\nF\xf1e \x13\xef\xa4z\x92\xf3\xeeh-b\x17\x87J)h\xddR\n^v\xff\x89 \xab\\nL\x07/{`\xf2\xc4\x13Zs\xc2Y\xd9\x89\xca\xcdl\xb3\xb0\x93^\xce\x8a\xd7\xcb%\x9b\xc6Q\xc1l~u\xd2\x9b,X\x949j\xcc\xb1\xc6[a4\x7f2\x8f\x92\x84\x19~\x867X\xe3U\x9c\xaf\xa2bb\x98},m\xe5\xe55\x11\xca\xe7\xae\xed@CA\x1e\x0ea\x9b\x9fe6I\xe6'\xcf\xb5\x99:\x85\xce\x90\x01\x9a\xe1\xc5\xb5\x93\x9b\x95A\xd2x\x85\x10\n\x9f\xf0 \xa8\xbd1\xa6s\xd5\xcad\xdf\xc9\\ \xc2Q\xa5\xdeV5\"<\x96\xa7(D\xae\x1a\x9b\xac\xa5\xfd\x18]\n\xad\xed\xe09D\xd95n\xed\xbcR\xec&\xcf\x03\x95C\xa3,\x1d%\xdb\xdb\xe6I'\xf7\xcf\xf5h{{y\xd9\xb6\xd0\x02(\x7f\xe5\x0c&_\x87\x9b^\x92\xde\xb6\xb6\x86\xb5\x9c\x0d\xcd\xe1H(\x13|$\x93\xec\x16\xe6A\x8f\xd3\xbd\xdd\x10R\xfcc\xd0K\x93*\xb4\xf9\x95\x08T\x1f\xf9qo\x95\xe6\x85\xdc\x85Hk\x06\x18\xcfi\xd2\x8b\xa6\xd3\xd3\x1b\x96\x14o\xe2\xbc` C\x9aN.\x86\xd6\x00r{\x93^\xbc\xe4=\x9e\xa3\x17P\xceG\xd6<\xb5\x89>\x06<@=/\x04\xefw\xf54\x07\xf6\x88|ON\xc8C\xaejK\x8c\x1c]\xa5\xd2$c\xd1\xf4\x0e\x03\xee\x89p|(]/|O\xf8&a\xaa\x15\xf7\x88\xf2^\xb4Z\xb1d\x8a\xf9\xe8}\xed\xab\xa0g\xb7\xdc\x86\xc3y/c\xcb\xf4\x86\x89\xc6\x90g\x0e\xcb}\xea\xf4\x1c\x80\xa6\xcc\x959+.\xe2%K\xd7\x85\x86\x11\x9c\xe9\xa8\xbe\x0f\xeaF\xb3\xd6\xf7V\xa4Y\xa4\xd5C\x98VM\xe0_]\xb9\x15\xf7`\x1b\x9doh:\x8a\xeaF\x9a\x1f\xbf\x19\x02k'\x9b]\x1cv\xdc]\x13\"\x1f\xc8\xae\xdb:n\x81\xde\xa6\xec\xce\x13:D\xff\xe0I{V3G\x9e\x8f\x0cie\xea\x17vj8\x91\x90\xa8-\xb5q\xdc\x9b\xb9\xb2\xfe\xfa\xfd\x10\x92^\xc6\xf2tq\xc3\x02\x8cl\x8f\xa9\xfc\x96\xb1\x96\xdfjC\xc0X\x10\x10\x80yF+\x01\x91\x0dDg\x86v&\x90\xe2\x00\xe9|\xf3\x98\xc7\x8f\xcb\xc9Z\xdaT\x91wF\xb2x[[\x9c\xc9\xf3>\xb0\xeb\xd3\xcf+\xa4\x8di-%\xe6\x86s\xb6\xf8<\x95\xb0\x81\x9c\xf3\xe3{\xe1\x82ZN?\xed\xc9\xab7\x11\x9aA^\\\x89w\x9cK\xb10>\"\xc2\"F\xd2A\xc0O\xf0\x161\xeb\x9d\xa3C(\x17ac\xb7\x05\x00\x88l\x9e\xb6\nA&\x8c\xf1B\x88\xee\x0d\xc4g\xae\xdb\x84Zf\x97Nr\xa9\xa6\xeb\xc9\xea\xc9\xc57\x1a\xd1\xee\x9eC\xa69\xd8Cyc\x12\x15\xbe'\xf8)O0\x1dB\xc2\xab\x875\x9e\xd5\xeez5\xbe\xf4]\xb4d\xbf\x8e\x9c\xbdk\"\xa2\xdc\x934~Z\xe6\x0fR\x9aylj\xce\x854c\xdd\x9eKaf\xcf\x14Z\x16.@\xbc\x92\x0e\xc8\xba\xe4&\xe0&lS\x8e`\x01- peF$\xcc\x98'\xae\xf9\"\xbf\x90\xda\xb7\xd2\xccL|`\x1eH_\xad\xaedN\xa5\x92\xf4\xa6\xfeV\xd6\x9bii\xfdB`\xa3\xe2\xb2m\xc5\xcc\xe5Jp\xa7\x96\xb1C\x1el;\xa8D\xae\xf8\xc9\xa5\xe0\x8a-~\xa6\x13R\xb9Y\x94\xd2\xdd3\xf1\x1f\xef\x99\x18Ty\xeb\xd4\xfdr\xbat\xd9v\xed\xf4\xec\x80\xde\xa4O\xcc\xf7\xb1c3\x08\xf4\xb6\xac=\xe4\xbd\x93\x95tGS\x94Ey\x1e_;\xd4Q[\xb8\xb5[L\xaa\x944KE\xb4-\x1c\xef9\x92\x9c\xdf-\xaf\xd2\x05\x15[\x06\xb9\xe9\xe8j2e\xb3\xeby\xfc\x97O\x8be\x92\xae\xfe+\xcb\x0b\x8f<)e:\xd1'!dJ\xbf\xe4\x05\xbdY\x9a\x9dF\xad\xd1\x1a\nq\x86\x18\x0e\xadA(,\xc4r\xe1l\x1b\xf0\x0e\xca\xf3I\xdc\x95\x89\xa2\"\x08d\x98L\x0f\x93\xeeVn\x16_\xeb\xcc~\x9b\xd7\\\x84{\x9e\xc3\xdc\x94rC\xa49\x83PFK\x9f\x85\xa8!\x89{\xb3\xe7\x90\xc3KX<\xb7\xf9\xd2\xb2\xe5\x95\x90=\xd7\x9ap\xbc\xe0\xc2q(\x14!\\\xfe\xf3\xa7\xe510\xf1\xa7B\x98\xf1\xa7A\x88\x8a\x90y9\x86\xa5H\xc2u\x03/a\xf9<\x00I&\xa6!\xead\xe6\xa3eiQ\x95\x8cV\xa8S\x1f\xad\x1c2\xb8\x96a\x0d\x86\xdd\xb2J\xb5\xed\x9eA\x9f\xe6\xd7\x06\xa6nI\xec\x9e\xdd\x03j\xf7\xf8\xbc\xe0\x80s\x8f\xfe`\xf7 \xa8\xd9{<\xc5\xd7\x8f\xf7\x1e\x93)\x1a\xd6\xd4\x98\xa1t\xd7\xcc\xd2U\xae\xb9\xfdV)\xd4\x95_o\xc6f\xb9\xcc\xe2\xc7\x7f\n\xafh\x9c\x19\xea\xef5Jc\xf7\x9d\xff\x1d\xfb^\xd4\xdd\xa8\xd7\x9aof\x9c\x7f`\xd1\xa4\xd0\xf3\x10\xf2\xed\xa2W\xc9e>\xfd6\x9e\xb1\x8c\x85e\xe4\x82wg\x89\xc7\xbc\xbe[\x87e\xca\xf8\xa7\x8f\xbd\xa0>\xbf\x9e\x91\xd3\xbf\xbc\xaf\x0ceD\x05\xa2\xae\xcab\xafR\xb7\x85\xe0\xa9)\xd4u\x06\xfa$gi6a\x1f\xed\x00\x01\xe4j\x19\x1d\xfeX}\xab\x04x\xd6qp,\x04O\xeb\xba>\xbeE-\xab\xf1Z\xcfj\x9c\xd7\xf3#\xb3[X\xd4^\x1a)\x97s.\xd3\xe5z\x03ZkA\xfd\xcb8\x7f\xbf\xce\x98\x85\x15[\xfd&\x95AY\xd3r\xe5\xe2\x8di\xa5\xb9\x86\xa8p_\x82\x92\xf8\xcf\x02\x9b\xbc\x18\x0bc\xf5l\xfe\x90\xae\xafa\x861\x0c\xba\xfe\x07\x91\xcb\x13q\xb5k\x1fjk\x10\xf5+X;nb\xee\xbf\x04\n\xe8z\xc2\xb0\x07n\x9aT'\n^\x84\xef.\xf1\x17\xdf\xb8\xf5_\xbe\x97q\xdc\xed1q\xaf\xe4\xa1\xc9\xf0A\x7f\xd0\xdf\xfb\xc5F\x9a\xf8\x8f\xf7\xefm\x9d\x86\xe2\xd6\xd6`C\xd6\x98\x1eP\xed\x82\xf0\xfc\xf4\xe4\xc3\xe9\xc5\xf8\xd5\xd9\xf8\xdd\xd9\xc5\xf8\xfd\xf1\xf9\xf9\xf8\xe2\xa7\xd7\xe7\xe3\xb3\x0f\xe3?\x9d}\x1c\xff\xfc\xfa\xcd\x9b\xf1\x0f\xa7\xe3\x1f_\x7f8}\xf5\x0d\xees\x0f\xe65O\xc1u\xd7\x12\x0f\xa51\xe0\x01\xed\x92\xf7\xd82\xd0\x92v^\x074\xc3\xbd\xfb\xe4q\xdd^\xf4\xc9\xbe\xfe\xbb\x87)\x13=\x91k\xfe\xbcH3\xe65\x98}\xaa\x05\xed]i\xb3\n\xabV\xd2\xe5U\x9c\xb0\x0fl\xba\x9e\xa0\xd7gkKi\xcd\xdb\xa0j\xe9*N\xa6\"\x8c\xd0 \x1fY\xda\xa9\xb1\xd8\xd1X\xb4Z-\xee\xde\xc6\xd3\xe9\x82\xddF\x9d&\x189Z\x9ap2\x9fwia\xbd\xb1\x1b\x85\xe3 Ps\xe8\xd0g\\\x1bs\xd1\xd3o\xcb\x80\xc9|\xb0V\xf46\x8e\x8aFJO\x92.a\xf4\xb3\xda\xad/\xe7\xb1\x11\xf9\xc4\xb5\x98(38m-\x15\xf1\x16\xff\x88:\x9f0\xa5/\xc5BED*\xe5\xd3\xcf+\x8c\xf9\x00\xc5\x9c\x01K\xe6Q2a\x19\x14)\\1\x88\xca\xe9\xf6\xa8\xe8\x8ajq}\x16\x08C\xd9Z\x0d[+A\x8e\xa9h\x1bS&\xb0\xbf}H72\x99/\xa1g\xc6{j\xfb\xf5\x84pM\xe1\xef\xf1\x9e\xda~\xbd\x92\xa7W\xad\xa0D\x88)\xa9\x8e\x9c\xe1\xda\x8a\x1c(\xe2\xfa[X\xc6\x06&\xb0\xe8F\xe7MVS\x8bNM\xdc\xd0L\x8csAX\xd3\x82,\xd4\xe5]\xebj\x80v}M\xa5O\x95s\x98\xfaA\x08\xb32\x9a\x8dU\x0d\xb4\xa94\xda(\x8a\xd4\xdb\x0d\x15@\xea,\xb6\x06!\xef\xd5\x1e\x91\xfe(\xd9}&\xb23\x9f\xd9W\x14\xe63C\xfd\xc4\x84\xf9I\x08\x03\xda\x8a\x0b\xac]A\xbfu\xad\xe4\xd2\xbd\x92[Y/B;\x02k\xe9d\xf08X\xae\xf3\x82/\x19\xc6\xe2\x05!x\xe5=\xf8\x983\x98\xac\xf3\"]\xc2\xb2\xa4\xe8\xa8e\x88\xf2\xbbd\x02\x91\xf8\x9c\\^#-:\xeb\xa1l`\x0d\xe1\xdf\xca!Dw\x98\xb2}\x1e\xdd0\x88\x12(\x83\x1d\x83\x87jiPvG=\xf8\x89W\xb9K\xd7\xb0\x8c\xf3|\xc5\x16\x0b6\x85\x08PD\x89\x92\xe2\xe8\xdf\x1c\xa3Y\x11\x00P\xa7g\xd9\xfdT\x1a\x804\xce\xcd\x1dFs%E\x1bNSr\x7fA\x9a\xc2~\x85Y\x9cD\x8bEc\x1b\x03\xfb3\x9b|\xe8\xf6\x12\x9c\\\xcd\xc4\xd9 \x93\xa6k\x89\xe1\xb7\xb7]\xc8\x7f#3\xb6\x17\xa3\xc4aD\x92\xb6^\x80\x82\xa6\x92\xfb\xce]m\xe9\x0c\xc8\x15\xf7^\xbf{}Q\xff\x94V\"\xadI\xc3L\xb5hd\xec\xf1|}\x95O\xb2\xf8\x8a\x91\x11\x96\xafKq\x87\n\xf5\"\xe4'\x89$m\x92\x1f\xdc\x9bp\xf2\x93,a\x9f\x8b\x0f]O3\xf5H\x1d\x0f\x05Y\xf58!\xac\x1e*Th})BX\x8f\xd2^\xd4j?sS\xf9)\x11I\xacu+Fz\xb8\xdaJ\xb5C\x1a\x14\xb4 5\x91\x0e\xeb\x8b\xbb\x15\xa3\xe0\x9d^\xc9t\x89\x12\xd8\x8a\xec!\xac\x9d=\x96\xe4\xb6\xddJ\x9f\x95\xf6\xd4\xe2/\x7fn\x9e\xeb\xfaC\x93~@)\xa2\xe1pQ\xa2Ma9\xc3\xeaO\xa3\x0d\x82z\xd6\x89\x06\x7f;l\x90z\xba\x9cQ\xf8&\xe8\x843P\x0d\xcf\xf2&\x01\x81|\xcc\xc2\xc6\xf2\x05\x11)\x87\x0b]\xb4K\xecc\xeb\x0e0&Q\x91\xef\x94!x\xff\xfe\xef\x9c\xb9\xfc\xfc\x88\xff\xac\x07\x93\xff\x06\x89Z\x17\xf1\x1d~i\xd6\x9d\x8d\x14E\x1f\x9bWB\\\x1a(o\xc7\x84\xd8|I\x84\xc2Qfk.\x9f\x87\x9cp\xfa\xad\xd7\x10\x1eh\xa5Mo\xad\x8c\x1f;\xb9a\xb3X\xaf!\x92\xb9\xe2\xb5\x81\xe8\xa6v\xc1\x1c5\xea4\x90{\x89\x91{\x01\xcc\xd7\x8a\x7fm\xa1hS*\xdal^\xbc\xc0\x1b\x93\xc8b\xcbxs\xa8$\xe6\x1cIQ5\xd1\xb7\x9bH\x90\x1d\x17\x8e\x07a\xcd:\xda\xb3mY\xc8\xa3\xca-\xd7%\xba+2\xbe\x91\xf0I\x02^uV\xa1\xf7\x83 \xda\xe3~\xd0\x8bzB\xa3e\x82~cm\xd5\xa6\xf5\x9dkm.u\xc9\xcc0\xf2.\xacP\x97\xc7x_\xa6q9exIq\x19\xa8Y\x83^\xda\x8b/xQ\xc5\x18\x95\x08\xd0|\xda\xd0\xac\x8d\xdd\xf8\x80n\xbc\x18\xf5/I\x04)zBz\xf5k\xb0l\x18AWB\xca\xfc\xa2\x87j\x18\xc9\x80\x87\x15T\x88\x13\xc88\xec\x1fDq\xf8`J\xbc\x10\n\x15\x00\xb9\x8b\xf2S\\\x10\xd5(\xb7&}\xc0\x11xq\x12\x17q\xb4\x107P\n,*\xabr\x91\x82\xae\x9b\x83!\xa6\x1c\xbf\x89\xd3u.\xd3)gl\xc2\xe2\x1b6\x85\xab;]\xffP\x8b\xec\xaakM\xcb\xd1w\x81e\xb5g\x9f8\x9cQ-\xdb{y\xb1i\x1e\x19\xca\x84\x9frG\x1d\xc0#\xd3\x98]\xb8Q\x1cA=b\x02\xe5\x90\x86r\x0d\x1cA^\x1e\x07e\xc5j\xf5)}5GJ\x8a\xba\x13y\x06\n\x97Q \xaf\x1f\xfb5\xcb\x95\x82KXh\xc3kW\x8d\xf4\xaa\x0bL\xee!\xe8y\xc0\x17\xd6\xa3i~A4\xa6\x08z_\x18\x9fp\x1c\xe3@,\xf8\xaf\x9d5\xc7\xaa\x9d>G\x96d\xb3\xadS\xed{\xa7\xbd\x9c\x96\x0f\xa8\x84\x0e\x9e>\xe2\x08\x92\xb6t\x87\xa5G\x1f\xbe\xae\x0f^_\x0cm\x80Ay\xb6%\xfe\x9e2\xf0\xde\xdc\xfc\xb6\xcd\xbcag l\xbf\xe5\xa9\x8b\xb6\xf4}\x18j\xb1\x01\xd2\x92\xb0g\xc1s\xd8\xde\xe64={\x1e@*\xe8y\xe1\xb3Qr\x89\xcaT\x87\x1dh\xba\x19\xd4\xb5\x83\xf1\xc9A\xe0{E\xfaq\xb5b\xd9I\x943\x97\x15'}Hv\x02\x0eqA\xaf\x06\xb0C\xd8\x1c\x8bh\x97\x94\xaf\x7f\x81>_\"%\xc6!\xec\x14\xf0\x12R \xcb\x14\xb6\xd1h\x0b]\x81\x12Y\x90r|\x0c\xca\x8f\x12\xd8>\x844\x10\xe0\xe6\x1f'\xf2\xe3\x04v\xf8\xef\x97/1v7\xff\xe3\xd0\xcczU.h\\.U\x8aK\x95\xc1\x0bH\x9f\x07\x10\x8f2\xb4\xa5\x19e|$\xf4a\x17\xb7\xac\x92\xb9D|.\xc2\xc2\xd5\xf7F\x7f\xfe\xf3z\xb7\xdf\x9f\xfe\xf9\xcf\xeb\xe9\xd3~\x7f\x87\xff?\x9b\xcd\xfe\xfc\xe7u\x7fO\xfc\xec\xef\x1d\xf0\x9f3\xb6\x8b?glw\x86\xdfL\xf1\xe7n\x7f&J\xfbL\xfc7\xbb\xdc\xdc`W\xce#\xe9\x15,/\xdaM\xcf\xbabG\x08\x19\x85 \xa9\x03A\xe2\x86\xbdD\xac\x1a\xdee\xc6\x12\x03\xf8\nmo\xa7\x97\xb8v)\xbc\x80\xf8y h\x9e\xcfw\xd7(\xbdD\x0f0\xc76\xdb\x90\xb8U\xdbl\xf0\x9420\xae\x84\xf1J\xcdA\xc6\xd7\x8fI\"\xe3\xd6\xb3\xa0\xe1\x9a4\x04)\x9c\xf6\"\x05\xad\"H\x89[\x83\xa4M\x84US-\x99,ZQ-v\xde\x11(\xdeLXldhx5\xea\x13\xa6\xcf\xa0\xd6[\x04*\xb7\xc5{<\x0f\xb9\xec\xe5\xa7\xd5A\x17c\x1eHs\" \xc7)r`\xd7\x07`\xd7,q]e\x00\x88{9o\x14/\xb4\xbe|A'\xc1\xdaG_i\x94)\xbfO\xd8\xad\x1f\xf7N\xf0\x17\x97\xe38\x0bo\xe0\x13\x7fT\x15\xcc\x8e\xa0\xef\x9ax3\x94\xb3ng\x05\xfbd\x19\xf5\xc6\xba\x04}\x9c\xdf%\x13%,\x9b\x82tM\xd6vUZ\xeb\x95~\xcf\x12\x116\xc0U;\xd7k\xbf\xcf\xd2\xcfw\x97\x8e\xab\xf7\x16\xf9\x18\xad\xff\xdb\xc4\xe1\xcc\xe5F\x81\\\x0c:\x95\xe2_\xeb\xf2\xaf\xb8\xfc\xab\xcd\xc8\x86\xa2\xdd\xb6\xd6\xa1\xc52\xb8y\x92\xa5i\x17\xb5\x01\xdd\xeax\x0d\x11m\xff'\xfe\xb4d\x86jmY\xf8\x8fm\xd2\xecWj\x11\xf4\xd4\x10\x1b\xa2\xfa\xa0\x1f\xf8\x89\x7f\xb0\xff$\xd8\x88{ih\xd0\xdc%b\xf3\xec?i92\xcbKo\x19\xfa\xc8q\x80\nv\x15\xad\x0c\x95.\x06\x8a\x92h\xab\xa2-\xe53\xb4\x95\xfa\x89\xf0kV\xf4\x1c#\x02&h\xae\xaa\xf7\xc7x\x97m\xa7r\xc3\xacim\xdc\xee3\xda0\xe4\xc0\xca2\x14\xa1\xb1n\xed\x15\xa7\x07\xbbm\xd8\xae\xd8\x80<\x84E\x08\x13\x8a\x19@g\x02\xf8\x9e\x0c \xaf1\x8cv\xa9\xc8\xa8Dq\x07x\x1f\xc6\x019E \xfb3@\x1f\xdd\x97\xb0j&%\xc2\x8f\x9a\x9f0\x94nm\xce[\x11\xc5\x9a\xe85\xc7%\xb6\xdb\xbaq\xf08Kq\x87f\xbd\xbf\x96`\xe0\x12\x17?\xb63B\xf4\x04\xc5\xf9\xa0\xbb\xb8\xa0N\"!k!dE\xce\xfb\xdc\xc0\x0bX=w\x1d\xe5\x98\xa7\x96\x8c\xef\x02\xd2)\xba\x18\xdd\x10we\x1c\x00y\x80M\x8c\xf9\ns)\xd9\xbf\n\xe1\x0eC\x1d\x15\x88\xa1\x13\xcc\xca\xe8\x8b8F7\"\x9d\x13\x7fK\xb7\xa6\x99r\x8c]*\x1f^o\x1c`\xea\x9a8Y;\x92\x0c.\x0d\xcb:\xfd\xb9\xcaX\xf4\xc9*\xb1I!:\xa77\x8db\x0b\xa5\xf1V]V\xed\x93\xd8\xbf\xc6j\x9cA\xbd\x13\x9a\x1a\xbe\xfb\x17\xd2\xcdTl\x8bIP\xe1\xd2\xb50\x06p&\xbdl\xea\xb1 \n\xe0\x84\x04\x90\xd0\xf8*\xe2\xa7\xc4\x18+\x86/\xd0\x15\xee\xa3\x85\\\xdar\xe0\x8e\xe1|\xeb\x82\x90\x87\xc8\xa4'<\xcaQCZ\xfe(\xeaN\xe9\xf8\xd7\xbd\x84\x95o\x92\xf35\xc9\x9e\xc4\xac\x9a\x98\xefT\xcc\x97\x84\xa9e>N2\xbf\xf7$\xe8}\x8c\x93\xe2)\x8a\xb1\x0fr^\xee>\xa3B\x80r\xb1\x87\xbe\xc79\xd8\xbf\xaf\xe8)\xe2\xa5~\x93/\xddSz\xac\xbb\xedcr\xeb2b\xa1\xa5q(g\xf8l\x8e0\xf4_\xe6\xc7!$\x1dp\xa4D8x\xfc8\xf03\xc7\xd6M7\xebc\xd0\xa7\xa3RqN\xcd\xbf\n!'&v\x0d\x870\xf2X\x96\xa5\x99\x17\x827Y\x08\x7f5o\xca\xf2\"K\xef0\xb0N\xb4\x16\xef2\x96\xaf\x97\xcc\xbbt\xb9\x08\xdd9\x11&\x06y\x1b\xc3a\x88\xde\xe0ROf\xce\x154\x1aU\xe8F\x86\xb1]\x0f\xbd\xc9\xc5\xed\xd3\xdbt\xca\x9b\xdc\xdab\xda\x0b\x19Z\xd9\xb7\xeb\x99o\xbe|\xc1O3\xb9\x7f\xce\xca\x12\xc7\x1d\xa40r\x98\xc7\xd7\xf3\x9f\xa3\x82eo\xa3\xec\x93\xbd& id\xd5\xeeO\xed\x1f\xac\x89\xd1\x1d\xc1\xe0\x00\x8608\xd8{\xba\xef\x80Bm(\xfc,\xe0S\x12'\xa42\xa5\x10\xb0\x88\xaa\x82(\x90\xd9c\xd6!\xdd\x08\xc6\xfb\x9d-\xd24\xf3\xedr\x15\x96@\x08\x8a \\\xeeo\xca\x84\xed\x18\xe4R\xcb\xd8\x1e\x8b<\xe9\x9c\x8f\xd5_\x9d\xa4k\xf4\xa5W\xf5f\x8b\xf4V\xa4\x1a\xd7j\xb2D\xa4\xc8/\xf3\xb5\xb3d*\xe8W\xed-\x87\xb2\xf8\xb6|\x85.>\xc2\x9d\x05\x7f'\x8cM\x15\x91\xac5(Z\xa3\x8a\xd4\xda\x89 \x8aF\xfbbC\x9cO\xe6l\xba^\xd4G#\xf7\x8f\xf9\x12-\xe9N\x93I*\x87\xca\xacw\\\xae^\x17\xb3\xa7*\xe3|t\x1b\xc5\xc5\xab,\x8a\x13\x0dNr\xaeo\xd3\x8c\xd5\xdb\x9f\xa4S\x96\x99\xe0+{\x13oY\xf5\x8a\xa3\xc4\x1c/\xb2\xe6\x92\x82<\x0bzBE\xf1J\xb4\x15\xd8M\xb3[\x98\xfbU#\x81\xdd\x8fVX\xc3W\x97\xe7\xd7\x95\xdb\xf3\xcb\xa4\x1c[\x88\x8b:e\xb8\xaa8\x08>\xb4+\xd2\x95\x0dG8\xce\x8c\x03\x92\xd7\x17DK\x04\xa9\xa8\xad\xb8\n\xf1 \x14\"4\x03\xcc\xebV4\x06\xdb/w|\x10\xba\xd8f\x89\x1b\xda\x87\xea\xcdaU\x1a`\x14\nW\xdcx\x07 \xc7\xd5m\\\x16B\xeab\xe9%\x17\xc1\x0c\x88\xd8`\xabL\xcd\xe1\x08\xfc\xc8\xd8c\x9d\xf8\x04\xd4\x8d\x8b=\xac\xd6\xc9\xee\xa7\xaa(\xf1\xcc\xd5\x1ah\x9c{Y\x99\xb7\xde\xe4b\"\x94\x01\x8a*!\xd4%\xddRy\xd3\xc2*\xb1\xd06o\xb8N}aX\xb1\x91d'\xf6\xed\n\xa0\xb9xI\xb9\xfa!\x9c\x93\x97\xf7\x1ct\x11\x86.\xf2\x91f#\xbew\x82+B\x81\x9es&\xa2\xe4,zq.\xd8'?\x13\xce\x07\xfa\xb6A\xcd%e\xbb\nztn\xa5*1NKa\xa8W\xf7Mz\x9d\xdcD\x8bx\nI\x9a\xec\x88f\x1f\xc9\xc3a2_'\x9f<39\x9dz\xf0\xb8wLDnk\x02n\x11F\xb0\n!F\xe1\x93\x13p\xbf\xe4bb\xcc\xc7c\x0cY\x1a\x9c\x96\xf1\x97\xfb\x1c\xa3]\xf37?&\x93\xc5qi\x16\xb3\x0bi6\xc7\x1c6\xcdv\xde\xc6\xdc\x16\xbdY\x96.i\xdc\xc0 f\xfc\x94\xd6\x8f<{\xbe\x9aC\x9e\xe0({\xeb$\x9f\xc7\xb3\xc2\x0f \x9a\x15,\x03\x96L\x81\xdd`\xf0\x8f\x00s80\xb48\x10!\xfa\x10X\x02U\xbb\xb4\x8d[F5|z\xf6\xa3h\xd2\"\x0eQyd`nK\x0em\x8c\x0bXn\xda\xdb,\x96\x97{&\xb4\xa5\x8e\xaeJ\xf5\xa5\x8fw\xc0{\xfbT\xed\x9bz\x99\x0ci\x8c\xe9\x9ej\x03\xa2\xb0\xcfT,\xb6\xad\xd5\x16\x93`\xe2$\x84\xd5\xb9 \xdc$r\xc0/L\xe6\xb0b\xba\x98\x93\x8e|\xf5\xcd\xf8\xe3\x0e\x1a\x7f\xab\xd1xj\xc0E\xc9E}\xff=\xd4\xddEp)\n\xc1\x16\x1d\xf1)\x88\xb5\x9eFE\xc4\x97\x1ac s\xa0\xf9}\xb1\xa6\x1d\x89\xa2@\xd2\x92\xa6*\xe4Kx\x1b\x14\xa5\xad\x01\xee\xfb\xef\x914\x06\xa1XT3\x10d\xed\x17\xed\x94q\xa5\x87q\xf2J\xc6\xeb\xdb\x93\x9f\xea\nc\x82\x7fP\x01\xad\xea\xaf+\xce\xcf^bB\n\xae\x8d\xc7\x89\x80\x8e\xee\xfd\xc6\xfe\xf9 \xdf\xee,\x13\x82\x06\xbf^\xc5\x88,\xd5\xdf\xf5\n\xe3u\xa2\xd7)\x7f\x19\xb5\xaa:\xad\x87\x99\x90\x06\x10;\xd6\x8b\x05G\x10+\xccw\xbdq^\xb7K\xc37\"EE\x06\xe4\xf29\xc9AVG\xf4\x04\xcfoC{Th1\xdb|\xa4kxld&7/r\x15eu\x86\x9b\xa1;\xa1 \xfb\xc2\xba\x07U\xac\x9e\xf4\n\xc3\xa0\xa9\xe3*\x1c\x1a\x126;\xfcH\x1d&r\xcf\xb5\x9e\xe4\x97/_\xc2\xa0\xf6k\xb7\xf6k\xbf\xf6\xebi\xfd\xbb\x83\x10\xd8\xf6v`:]\x83\xe0\xb6\x03T>\xbd\xa8q\x17\x0c\xe7\xab\xa0\xa9\xcf\xbc\xb04\x06\xfd\x10\xfa\x1dc\xdb\x9c\xd3PPW*\xed\xc2\x97\xdd;\x97\xf3-e\x05\xc7\xfa\xa9\xef\xf1\xd7\xea\x9d\x17V\x8b\x1eP\xdfH\x9d\x88\xe2\x04\xd2*\xf5\xc6 \xba\xa3\x0d\xe1\xa4f\xe6\x02\x0d\xf3<\xa1\xe7)\x87\x04j\x92\x9e\xc8\xb0\x80\x0c\x87\xfe\xee\xc2N\xea@\xf7\xf3\xc9}\x82\xd4\xf4!\xc8\x82\x9b\x1a\x92~\xa8O\xf2X\x10\xd6\x8e\x13\xbb\xca!\x864\"\x01\x0bXV\x9c\x16\x17\x10\xce\x9c\xab\\\xeaK8x\x8bx\xf2\x89\x1ag\xa7>\xde\xb7\xaf\xb0\xc2v\xa1y\xa3zB|w(\xe6,eZ\x85\x90\xa8\xd9\x96\xe8\x18\x82\xb9d\xdarn6\xa5\x8bo%\x02\x88bS\xdf\xe3\xe3\xa9m\xeb\xe7\xf5AJ\x0b\x01\xa5|\xf2\x83\xe7\x86\xc0\xe3\x1a\xe1\xdb\xb6C\xc88z\x8eDWH\x1d-F\xa9{\xaf\xe3\x98\xdeu\x13I\xfaB\xfbU\xb9\xb0\x08\x07\x16\x0c7D\xe2\x15_$\x91\x93\xa4\x16^\x8a\xb8g\x92%;\xa6\xf4\xa0\xff\xd2\x15:\x99\xd8\x93\xcd\x1a\x02)Mx\xe2\xecd\x9a\x91$\x9f\xef\xc0\xb4\x95\x02\x0d\x01 \xa5\x0dM 1\x8a\x00\x8d\x9er\xfd\xa4r\x832\n(\xa9\x9b\xd0\xfeZ\x9al\x0d\xc3\x0f-\x99\xee\xcb\x17\xa5f\xa8n\xac\xe5\x8c\x87`\x89\xef\xa2\x9d\xb0\xfc$l\xd4\x01\xbd\x16\x97\xc40\x84s\x95q\x81\x13D\xd7<%\x81>T*\xa8@k-p0\xfe\xdf\x7f\xafzq\xb5\x8d|\xb2\x0c\xd0Q\x03\x8d\x13}\xa6\xbe\xc7\xebUJ\x82\x10C|\x18Q\xae\x04\xe4\xaa\x93\xc6\x96\x97q\xfcS\xe5\xf6\x00\x0b\x96\xe7P\xcc\xa3\x04ny\x8de\x94}\xf2\xc4\xb8P\xb9\xaa\xc0\x86\xcd*\xd1\xeeH\xad\x05\xff\x91\xe2\x95\x19\xde!\xa4b\xe1\x91\xbf\x93R\xf94\xc5\x01{A\xa8}_S\xa9HM\x91\x05@J\xa3T\xd38\x9aJ\xb5@or\x10\x1a\x82\xb0X\xc1\x04WP\xae\x8aX\xdaL\x1e\xf1}8*\x05\xbc\xa1<\"\x8f\x1cz-\xfe\x7f?\xd0u\x7f;\xa8\xec$gQ\x02\xd01\xa3\xa4\xdaJ\x9a\xc2C\xe2\x8f\x1a*\xea\xc6\xcbk\x94\xda]\x14?\xb0\xea\xa7\x9b\xa1 \x1ew\"(Z\xc3\xc4\x85\xa6\x80x\x00q\x8e\x81s\xe3\xe5JdH`6\x1d6n b\xcc2\xd2\xca\x8c\x96\x82\xd6\xf7B\xb8#\x8b\xa7Y\x14'^\x083\xb2T\xed\xcf%Y*g\x17\xc2\"\x109S\x8d\x8f\x13N\xaa'\x0deWd\x99\xa467AX\xc6\xbd\xde\x8au-!^\xeb\x8fo\xb3\xb8\xa8]\xbcn\x99/\x91\x08\x96\x9f\xcc\xa88\xb9_\x1b\xd6w\xe2\xbc\x8a\xc6\xb5E\xceP\x18\xeeM;\xc5\xb2\x8e\xeb\x06#\x1a\xef\x8b\x04\xf2\x8c\xab\x8cQ9^\\X\x17\"\xea!|\xeb\xc9X\xc6\x02\xc6\xd5.\xa0A\xac\xb20Pes 24\x00\xd4\xb2!8O\x05\xc4$1\xc1P\xb6\x14*j\xc5Jk\x1c\x8e\xbeBt\x91\xd1@k\xe4\x12\x1d&%qW\xa1\x0ej\x15^\xc2\x80W\xda\x11\xcd\xbe\xf3+\xfa/x\xcc\xad\x95b\xa2f\xd1\"g\x80\xddB\xc6\xf2U\x9a\xe4,\x04ek\x9e\x98\x17\xb0\xb5%n(\xdd\xde\x96\x93\xeb\x8bl\xca\xbc\xbdMw\xe3\xb2\x05\x88\x8aT\x15A\x08W~+5\x13\x08'\x10L\xbc\x17\xe7\x82\xc1\x98\x10\x11!\x9a\x06y\xed\xdcV-\x84\xf9\x8a\xa4 \xee\x8e\xee\x9ai\x93l\xbb\xf5\xb8\xd8\xb4\xdb\xab\xa6n\xab\xc3.\xe9\x89\xbf\xbb\x9d\xfdJ\x9e\x15;\xb1$\xfed7]o\x07\x00\xac`n\xba\xb1\xef*c+\x96L\x15P*/=\xb3D\xe4\x98iP\xa1\xf7\xc6h\xc2\x97\x0b\xe4\x91?F\xc5%\x1cA\xe4\xeb/\x02\xb4\xe3\xab~\xd7-\xb2j\x9f\x1e\xc2( k\xaf.\xb1\x8a\xf0\\J\x1c\x04OCeu`\x8b\x03\xa5\xce\x1f\x88w\x06W \x90^\x9e3|3\xc7%\xa1\x95w{\xc8\x8aU7r\x89\xbc\xcd\xf3\x03\xebR\xdf2\x82\xb1\x18\xf3&\x9d\xd5F*\x03\xf7\xdaWL\xd4\x90Jz\xc1\x1f\xc2\xc9%\xd6b9\xeb\x1c\xbdR\x11\xce\xe3\x9c\xfeh\xe0\xfe\x88U\xcc\xa5,\x87#lIXq(\x89Q\x96\xe1Qi8f\xd8^\x19\xfa)8\x90\xd6\xf0j\x11KvA\x18\x13%R\x92%p\x18\x9d\xfd\x9c\xfcB\xe9\xf0#\x0f\x0b'\xa8S\xa8\xcf\x9c\xde,\x9b\xce\x8an\xa5\x163\xb4\xff\x1cb\x0c\x15\n\xf1\xf6v\x00\xd9(\xbet\xc1\xa0Qak\x19\x0e\x01I\xa6nd\x9c\xc3w~Q\x9d\x9f\x0d:8D\x89H[l\xf9\x99\xca\xd9\x13\x850\x08\x0c@\xec\xa0\xe4cc\x93d~\x14\x08\xe5_\xa3\xfe\xa5\xb6{]\x0b\xdf\xb49S\xeb\xc6\xb5Ib\xcek_Vn\x10\xd2p\x83\xc60A\xd1\x05g\x12\x94\x82\x98\xdb\x00\xadT=(\x02C\xf0l*FRe\xb3\xa2\xdao\xc1\xe5.B=\xe0]Q]\x89\x9c\x11.G|\xe7R\xef\xc5\x85\x88\xa5\xc9\xc9\x1c\x0eM\x99\xa6\xec\xca4}\xcey\xa9<\xd4\x04\x853\xb9\xa6\x9b\x1c\xabM\xeb\x1fM\xcb\x93\x0e\x0e\x0d\xcc\x08\x0dU1\xdav\xb4\x98\x19\xde\xc8@\xfb\x9d\x00]\x9e\xb9\xc6QS\x9d2\xcc`\xf7[1\x15\xa4YJ\xdd\xd0D\x19\x1fY\xe6'\xf5\x1b\x88\xf7\xa4\x01\x12\xe0\xd9*\xd1<\x08(;CC\x0f\xc5\xb9\xdb6@U\xaaV\xbe\x8b\x04\x87\x0dr\xb2B\xc7\xd1\xb0E\x82\xb0\xe3>\xc2\x83\x1b\x99w\x87\x05e\xfd\x1c\xd1\x14s\xf2\xab\x0e\xd3\xbd\xcd\xa2\xd5F\xa7\xbb\xfb8\xef|\xf6g\x8e#\xa2<\x1eR\x8c\xc7\x83\x0c\xa5\x10\xa7[\xc5^NN\xa6\xbe\xc7g\xb3bS\x90\xc2}R\xf7\x97P\xba\xf8f\xc9\x99 \xcb\x87nnP\xf2\xec\xd6\xaf\x0f\\Z3p^c\x16\x9a\xa9\xb6\x8d\xbc\xa5&A\xf2\xd6%,HW4\xfe\xe8\x90P\xc2i\x0d\x14~Z\x9b\xa3\x90SS\x8e.[\x89\xe17R*\x95QS\xafY\xef\xa7B\xa4\xf7\xcd\x0f\xb0\x9e\xb2JQb?\xce/\x0d\x04\xd1U\xba\xf1R\x90\xa4\xb6l\x806\x93\xba\xcf\xd4<\xceG\xe9%\xd4c7kR\x81,\xf4UE\x0d\xa9\xdb\x1c\xee[\xd1K\xab\xcb8\xf3/B%3=\x85F\xc7\xf5\xfe\xca\xe1\xdc\x80\xfa\x1agt]^1\"\x83\x84Hp=\x8a/\xb5\x9d\xde\xbb\x8a\x93\xa9\xa4n\xbc\xa8\xc1#\xa7\xd0\xbd)\xdb!\xa3\xa1\xd0X\xde\x1f\x16\x81\xf2\xfe\xce\x14\xe7Z\x89\x11\xf6Di\xda\xd3\xc5\xddD\x91\x90\x9ao7\xe9z\xc2\x92\xf5\x92e\xbc.\x97\x13lj\xb3\x91k\nEak\x17G\xf6\x1c\xeb\xb3C\xbf\x8f\xf1,K\x97\xfcT\x86Cx\xfb]UV\xcf\xac\x10b\n\x1eG\x82\x05C0\xae\xe5j\xb0\xe3Mti\xa2-\x1b\x90\x88\x99Q\x16\x94\n\x83\x94<\xaa\x1b\xb4,_\xc9Q\xd7?\x97~,\x1d\x0c\x8f\xee}\xd7\x03m~D\xee\xd0\x02\xe23K;M\xbc\xaeZsn:\xf4\xb2\x8e\x84\x9f\xde\x11:\xe1\x94\xd6\x9b\x1b\xf4\x83p\xae\xb1\xb3%\xd3\x93*yA9Y\x08s\x9d{\xba6i\x17\xa7\xd6\xc0\xfcF\x08\xd4?\x96\xaf\xfd\xf2\x04 ;h\xb8\xb7\xe4=\xce\x11\xe7\xcb\xf5 &bv 5(\xf3e\x1dV8(\xbc~E\xd0\x92\xfa,\x87\x9cU\xfbYzd\xb5\x10\x93{\xc3}@\xf3w\x99\x1d~\xc1\xf2\xa1\x996\xb6`\x84u\xf8\x96\xe5\x1d\x90\xdf\x12#\xb0\xca\xcd)\xd4+\x08]Vs\x1b\xc6\xa2\x9aNU\x06\xf9\xe9\x9ca\x87\x0c\xc8\x96\x95\xa1g\xaa\xfbvDd\xafL>\xabG\xcf\xca\xd9B\x04\xb5\xe4\xff\x7f\xf9\x02\xb7q2Mom\xfa\x92\xd2\xe1\xef\x91\x93p93\xd1Y.\xa0\xc4\xb4xZ\xf9N\xf5\xc6h\x89\xfd#\xd2K\x07x\xf0\xcb^\xce\x8a\x8bx\xc9\xd2u\xd1Q\xccI\xd8-\xc4~*N\xb0\xeak\x8c\x87P1@!\xe0\x00d\xa1\xa5\xb7\xc0~_'\x05\xcbn\xa2\xc5=;V\x9f\xd3=\xabR\xa2k}d\xa8\x80\xa9}\xd0*\xffH.\x1f5\xb1\xbe\xd5|\\S\x97fl\x86\xb6\x91\xba\xec=3\xe6k|\x84\xed\xb6\x81\xa4\xb6\xc6\x02\"YX\xe2\x011g\x96d\xe9b\xd1EA\xa4C\xc7g\xbc\xb9\x05\x93?_OQ\xfc\xd0_\xd9\xf8\xc5{['D\x7f\x0f\xd2\x99i\x0e\xc7{\x1b#\x9c\x8f'E|#\xb4\xaf\x91\xfa\xf3[:\xa7/\x08\xe5M\xaaV\xd5\xaeW\xc0\xcbC\x99S\xc9l\x15\x0e\xa1\xda2~+/\xcaz\xe34Q\x93\x17\x97\x12\xe5o\xea\xb6\x87p\xb9\n1\xa4\xd5n\xa0\xf6\xdcr\xc9\xa6\xb1\x08\xce\xd2N\xc2\xea_Ta+*Rh\xd5\xe08X\xb2.za\xb9\xf36\x1c\x82\xf1\x0d9\x08\xbbNm\x18\xf5\xe2\xea|\xe8\x94\xe0lc\xe6\xd9\x11S-Eeb\x9c\xebq\x88\x9a\xf1SY$\xe1\x9d\x82\xe7\xc16\x17\x82q\xbeE\xfa&\xbd\x15 \xc9|\xa7\xfd7\x1a\x11ys\xf6\xd9\xa3\x8d{D9FBj\xa9\xb0\xd3\\#\xca'q\xdcX\xe3*N\xa2\xec\xae\xb9J\x94\xb3\x83\xfd\xe6\x91L\xf2\xdd\xb6\n;-5\x8a\xd9\xe0`\xc1\xda\xea\xec\xb4V\xca\xa2[G9h\x1e\xda\xfd{\xda\\\x95\x1e\xde\xf6\x16\xaf\xefnG6,\x8a\x931\x08\x95B.\xdc \xac\xab'\xb8\"\x81\xed\x0c\xbc\xba\x90\x92S\x11x\xd6r\x11T<\x7f\x1e\x94\x03s\xb6\x0c]p\x17:\xe1\xafz:\x0c\x12\xba\xa0!tBE\xe8\x88\x8e\xd0\x15%\xd5\xa3M\x03k\xb7\xcdd\x11\x15q2h\xed\xbdq\xf7\xaaG\xf5-\xdbl\xeb\xbaq\xbbC'\xd2\x02\x1dh\x9cz\x94\xba\xae\xc1\xe8\xa9mO\x82r\xb1h\x0e\xb2\xa5\x1eN\xb3}I\xb4\xeb\xf4ZD\xa3\xd0R\xd8\xea\x0f\xa5#\xa4n&\x1d\xd1{\xc5\xe5b\xed\x989<\x94\xd1\nE\x120\xdb+\xc4\xfb\x98|J\xd2\xdb\x04\x14\x15\x18\x82\x18\xb6[{\x88V{uJT\x05v(#\xd3Q,W\x07\xb4\xc7F\n\xf6\x99C)/\xdb\xe4\xac\xd3B\x80\x8e\x88\xd1\x08n#\xd7VR\x81\x1d\xcc\xe2\xc5\xe2M\x84z\xba\xf5\xfd{i\xc4j}^\x93\xda\xbcf\xa2\xc7\xbd\x8dzlDX]\x89),\xc0\x0ea\x15\"\xe7\xe4k\x1d\x9b\x92B\xed\x17\xd6[Dy\xf1\x8e\xa1\xa0\xadB#\xf2W\x17i\x81\x92\x92\xfe\xeed\x1e \x9f:\xdd\x1f\xb0\xa6\x0d,\xff,\xcf\xaa\xc8&\xf3\xa5\xa9\xc5\x8bC\x18\xec>QIb\xe0\xe5Kx\x0c\x87\x87p #B\xe3\x9b}\xfef\xb0\x0fG\xb0\xa7^\xed\xf1W{}8\x82}\xf5\xea\x80\xbf\xda\x85#\xd8\x19\xc0\x10vv\x1b\x87\xb4v\x1c\x9fJ\x1bXM\x7f\xa7\x0e\"[\xca\xdf\xc4\x05\x1a-Ov\x9f\xf2\xbd\xec\x0f\x9e\xed\xc2\xf7\x98\x14<\xd0\xac\x99\xeaK\xe1\xfd\xdf\xff\xd7\xff\xe9\xa0\xb2\xe8cTU\x97\x16\x83\x9ak\xd8\xa0\xe9h\xa5\x062p\x0dd\xd08\x10\xa0\x06\xb3k\x0c\x06\x7f\x9b\x1d\xee\xba:\xdc\x95\x1dv&\x9e\x85T\x88>\xa7\x90L\x93$\x12t\xb0\x1f\x1aX\xffB\xf36\xc3x^\xe8\x97YCy\\V}\x1f\xf0\x0f\x03c_\x94\x89\x0d\xeb\xfcVho*\x11\x17\xac\xa9\xa32\xc2\x99\xbe\x9f\xcb\x11\xefh!\xd0\x9a\xf7^N\xaa\x00\xf8z\x95\xd9T8\x8a\x07\xf0\xaf\xb0\xcb7P\xbfI)_\xa5n\xf4K\xf2\xee\xb6#i\x0e\x04\x80\xd7\x91\x93y\x94\x9d\xa4Sv\\\xf8\x9a\x0f\xac\x199Z=\x18b\x9f\x8b\xdd\x8f\x1f\xef>;\x004\xcc\x7fq\x08\x8f\x0f\xf6\x06\xcfj&_\x06.Y\x04m\xdfX\xb8Q_\xa4-\xd6 \xb2{i\xd6\x19Xu\x06\x97!$\x95\xa3\xfa\xce\xe0\xfeF\x1e\x14\xde\x9a3\x19\x103\xd9m\x9f \x1f\xa5c\xe1*4C\xa87\"\xd2\xc2M1\xeb7\xe2G\xda\x81$n?\xa8\x9c\xec\xf5\x8d\xd4r\x11\xe4&\xc7\x0d\xdc\xcb\xb6ksj\x10\xe8\xdb\x01\xc1\xc8\x95h\x84\xcc\x84\xdcbj\xfc\xd66\xdb#\x89T_z\x9b\x1c\xd5\xd6J\xb2\x1a\xd2\xf1\xcc71b\x0fv !\xb0bOY\xa4%j5\x1a\xf1\xa3\xd6\xf47\xed\x87 t\x0c\xbf\x86iI\x0b\xcd\x9a=\x1c\xaa\x91[\xe9\xa8\x11;\xcaA\xf7C\x04\xb0\x81\xa9\xc3\x16lX\xb9\x99\x1d\xc7\xf9\xd0\x0c\x8ci\x03\xf3\xd4\x06\x0b\xada\xf5WQ\x8f\xe7\x06\x87\x10\xd75\xd3\x8a\x91t\x0b\xff\x95\xcdmy\x06\x95\x82\xa1\x01~\\\xb6\xd0t|\xee\xb4\xff\xe3*\xef%\xfab\x96\xac\x99b\xe2\x85\x9c\xe3\xe8\x18t\x03%\xd5Mhs\xbb\xf5\xbd/\xec\x14\xd1\xe5\x9bD\xa3\x04c\x92V\x00\xd71\x89\xf3\xfc\x9c\x10$\x81\xe2/\xeao\xf0:I[\x91:\xd4\xa5\x88\xd0xK\xf5\xc0\xf8\x8f\x1cV\x1d\x9d\xebc\x92RL\xe3]\xc2\x8d\x99\x17\xbd\x81\x01\xae\xec\x93+\x8aAs\x0e\x19\xbc\xe0M(\xd2hW\xba\x91\xd9\x03\"\xbf\x18e\x97\x0e\xfe#E\x0d}\xd9L\x8a\x8e\xbcB_\xaf\xa1@\x8aG_\x08)\xdd\xc8\xce\x0e\x0e\x86\xaf\xde\xce\xae\x10\xb3\x9b\x06\x86\x8c\x956\xb2\xa0\xf3\x18v\x7f\xfd1\xc8\xb60\xf8\xce\xa1\xca\xd2Y\x1f\xd5\x1e=*\xd5y}\xfb\xb8M\x8bQOhly\x9b*\x96\x01\xfb\x8d\xaf\xad\xf3-\xb1\xa9\x8c\x1e\xa0\x01v\xc0O,\xcaMn\x0c\x9a\x05\xef\x0b\xcfijh\xf5|a\xf5\x0d\xa3\xa9\x17\x9a\xa9g};\xbe \x08\xa9C4h\xe4\x85\x1eT@\xa9C\xeb\xde\xc3\xd1\xc4\x98\xfa\xa45 \xc68\xa5\xeeu5\xa3\x9b\x1ei9Nn\xb4\\Pt\xa63LcS\x164\xa9\xd7\x11\x87\x11\x04\xb5\x84*\xf5\xb4 \xb1\x9d\x01\xabfu_Zc\x14Y\x94\xe4\xb34[\ns\x0c\xca3\x06C\x83_\xa8z\x1dl\xa7\xc0d\x9b\x8d^h\xa9*\xe9\x95\xb5\x9a]9*\xb1\x0d\x0f\x9c\xc9\x95[J\xdb\xca\xea\xf2\x983v\x80\xe068\x84\xae\xa2\xc9'\x15\xaaf\xb9^\x14\xf1j\xc1\xa0\x88\x97,w\x86\xbcW\x03\x99\xaf\x93O\xa5\x9bJ9\xba\xea\x8d\xcc\xfaW\x94W\x852ut\x88Y\xf8\xdc\x93M\xbb\xda\xc5\xf3'5Lw\xfc\xd4\x8al\xaeLd\xe1\x05\xa4D\xe0\x8d\xaa+\xdf,\xb6z\xfcZ\x99\x81Ri\x04\x19\x9bj\x88C\x99I\xeakN\xd7\x90`\x14\xf1.\\\xc5\x1c\xf4\x8d5*u3\xafT?/h\xfb%\xc2\x13\x83\xaa\xa6E\xf3h\xcc-RNT3y\xaa\xde\x1d\xea5\xdc\xa9Ff\x8bu>\xd7\x1a\x10\xbf\x0fU\x89\xb2\xbaG\x9b\xedU\xc6J_\xbd\xa8M1J\xf1S\xca\x1d\xa3\x8eg\xe4\xc8\xf4\xd1\x1c\xe9\xbfj\x99\xd3Hnl]\x12\xd7\xfa\xa2p.r-\xc9U\xb5\x7f\x9a\xe7\xb1v\xb1}\xb5\xab\x14\xc2\x88\xd4\xe6\x12j\x99GY\x15\xee\xde\x8a\x14\xa0\x0eL\xeb\xa2\xe3$Z,\xf86\xac\x16y\x9a&\x0cn\xe7,\x81\xdb2\xa9\xd2\xd6!\xf4\xcd\\\x86B\x8bi\x10\xcd\x1au\xdc\xb0\xbb\xbc\x88\x17\x8b\xdaV3\xbb,!C\xb8\x03TB[j\xa5V\x0b\xb5w~,\xd8\x95x\xc3\xe0\xee:\x816']\xa3 \xa5\xdfS\xbd}\xcb\x9d\xac\x1ay}0\xb5\xfd\xd6&)X\x00\xae\xbev\xc4\x98qvk\x8b\xb2t\x97ug\xb3\xa63\x13\x85\x13\xfd\x80\xe1P\xa9\x1dB\xac|\xa3]\xb7\x17!le\x06\"\xd1\xf2Q\xe7#\xc7\xcf\x8c5\xc2\xf3\xe5\x17:q\xbe:Al:\x174\xdf\xaa4\xc2\xb6t;)t\x88\xe25\x82\x02\xb8\x88\"\\cW0\x0c\x93\xc9\xc0\xf4-.\xcb\xd7\x1b\x0dU\x93\x15\x03\\\xf4\xea\xdc\x960!\xb6\xb7A\xdf \x89\x8e\xa9\x1at\xfe\xccd\x14\xed\xd6\x8c-\xd6l\x90Q\xf8\xc2fZ\x10Y\xe1Cn\x12w\x83\xb8\xdc\x8b\xd7\xd6\x98j3\xeb$G_\xcc#\xa9KEiv\x1aM\xe6\xf5\x8aq\x95\xdf~\x92\xb1\x1a.tK\xdf\xab\xf0*\x16D\x93\xa4\xaa\xd2\x8a\xb4\xb4\x1am\x03 \xe7\x069\x8eug\xb4iV\x10M]\x12\x99`\xbe\xc08\x80\xc0F\xc9\xa5U\xf9\xab/\xf3f\xa3\\`\xaeUX\xd34\xc2}\x97\x8b\x84g\x00\x7f\xfb\x86&5\x0c\xd0Sen\x92\xb7\x16\x89\x1d\xb9jq\xfe.z\xe7c\xfa_\xd4b\x14B\x7f\x817w\xdf\x7f/\xd5\x15;\x98\x9b!\xc5\xe8\xd6\xc32\xfc\n^ \xb5\xa7O\xef4\xc7\xba\x0b\xce\xc1\x93\xa7\x81\xcf\x87$\x916\xca\xf3\xf8:\x81!\x16=\xfbV\x9b\xc2\x10\xd2\x10\xb3\xc9\x85\xb0\x0eA\xf5h\xec\xadNv\xbd\xd6\x85\x05\x7f\xb4\xb8 Evg|E{g-B\x90Q\x00I'\xacI\x9a\xcc\xe2\xeb\xb5r\xc3\xea\xd3\xcc\x7f\xe4t\xd2js\xe2\xc2,\xd8C0\xcc\x80\xb5u\x85IT\xda\x8fU\xa7\x93\xb8\xf4Xhw\xb9\x99%Y7\x0f\xdd=\xec\xfa\x90\xab\x91\x88\xd0\x86$\x14\xc3\x8d\x13\xd4\xa35\x0cJ\xa6\xa5.\x0b\x1d!ez\x0d?\x13\xf9\xc1\x05K\x81\x9eZ\xd5*e\xfa\xad\n^\x17\xc9\xd4\xd2\x83\x83 \xc4\x8c\xa8\xa3\xcb\x10\xe2v\xaa\x1aR\x1ap\xce\xf9\xacG\xec\xb2d\xe6\xf9\x8fz\x15${\x05\xf6\xf3\x1c\xd8\xce\xce\xf3@\xb9\xb9z\x91\x07\xdb\xe0oo'A\xa5\x82\xda;0\xe5zM\x8f\xa2\xdc&|o\x96\x88\x9c\xb9XTJ\x1c>o\xb0\x90Q\xeeC\xf0\x02\xd8\xe6\xff\xfcM\xb51K\xa4\xc3\xa68;+\xc7\x81\xe7\xf0\xf5y\x9de\xec\xbcF\x04\xc5G\xf9\xc6\xb1f\xaeD\xf2 \x9eZE`\xa9\x1e\xec\xbd\xc9\x9f\xc8OB3\x01\x95\x03\xfd\x81\xba^\xfe\xfa\xad\xc4I\x88\x1cT&u\x1a\xe9\xeb\x00\xaa\xaa]\xb3\xe2\xec6Q\xd5^\xb1|\x92\xc5\xab\"5\x0c\xa8#\xd7\x07\xef\xa2\xa5\x19\xd3d\xed\xaa{~\xb7\xbcJ\x17y\x87\x93\x89\\cA\x82\xe5\xd1\x9c\xf9\x85\x89\xa7('\xea50\xca@\xe4\xe7\x81bv*\xf1\x9b\xce-G\xae4\x7fpOg\xa1H\xba\x9eQ>\xb6\xfa\xd2\x93M\xa0\xa1\x86\xfd]\x1d\x81\\\xaa\x0e\xcc\xe7\xbe\xfe\x07\x9b\x89n\xe0SJ\xe8\xb4\x9c\xfd]\xbd\x95o\xdc\x15\x8f)\xfe7\xf1\x07\xfb\xe6n\x89iO0\xce\x9e\xde\x17I\xf9\xc1Fd\xc2\xe3\xfb\xa7\xa4v\xa3\xddK\x12\x0c\x19\x92+\\!\xbd#\xc1\x87\xac\xa9\xe5HF\xd9%\xfa8)_\x8a\x08\x05\x12\xf5\x85\xb5$I\x0b\xa0\xf5>\xba1\xfcr\xe8[[R\xdb'B\x10\xd4\xd3\xc8}\xf9\xe2P\xe0![\xefR\x10\xceY\xdbh;\xa1\x05\xcdH\x15!x\xe31\xcb\xdf\xa6\xd35\x9a\x9c\x98K\x89\x8c\x8e.W\x06\"\xde<\xda}v\x81\x88\xbdX9\x17\xae\xdf/\xd6\xd7q\x92\x0f\x1d{\x8be\x99\xab\x08\xb0\xed\xe9z\xc2\xb2|\x08~\x9f\x0b\xbar\xe9\xcd\xe2E\xc1\xb2\xee\xc4\x80\xf5>\xb1\xbbs\xf6_~\xd0c7,\xd3\xc8\xb4\x13\xb4`u_\xb4d\x0bD\xa9mT4d6Q\xb2?z\xb8f\"\x16aw\xb2\xefDg\xd6[\xb2\xec\x9a\xf9N \x19\xc5T\";\xdc\x06X0\xfe\xe1O\x0f\x8d\x08\x9a\x1e\xa3\xf2 N~\x0dtH\xe8pZ\xbf\x06\x805)\xb2.\xc2\xc5B\xe5\xb6k^\x97\x89\xcb\x0f\xf3m%\x94\x0f:\x0b\xe5j2\xa6\\./e\xec\xc9\x95\xaa\x03\xc3{\xfa;\xfb/>\x83\x85uG\xc5\x19\x9b!\x18WS\x0bv\xc3\x16\xc32`|\xadl\xc9\xf2<\xba\xe6Go\xe9\xe6\x8d\xb5\x8c\x1e\xff\xbe\xa2\xb7K\xaf\xd5\xa4\xe1\xb4`\xfb\x97\xfc|\xc5&C(z\x9c\xc98W\xda$\xfc\xf5\x87\x04\xd6\x91\xb28f\xf35\xe8\xc0\xb1\xaaok\xa2\x80\xd8\xa1\xf8b\x15 \xbe\xc4l\xba\xc2G\x87\xf6\xf0\xc9\xae\xa9\xd4\x7fH\xed!Er\x08\xf7\xf8\xff\x15\xf4\x80 \x87\x8e7\xd3\x11\xd2\xe4]q\x8f\xc6\xff\xdc\xab\xfe\xdc\x0f\x02a:\xf3\xf7'_\xb4!\xa3\xeb\xc0\xe8\x80\xc67e\xb41\xc4ZI\xc7\xbd\xa0\x17'S\xf6\xf9l\xe6{\xd2\xe21\x9dA\x84g\xbd\x9f\x07\xa6\x11)\x947\xd1/a\xc7\xe9\xf6\x7fS:q\x1b] \x07ft \xa3:S\x96\xb6\x98\x05\xa1\xf0\xbd\x90\xea\x1e\xf4i\xe7z\xfb\xa1\xab\xc3>\x92\xd8\xed\x0ebB\xadqq3\xe1\x9b\x88\xd0\x90\xd7\xcdh\"\x91i\xdc*'4\xb1\xab\xe5\xef\x970\xc0\x83}\x1b\xbc4\xc3\x18)\x05\x0c!\x1b%\xb0\x0d\x83K\xa3\xea\xae\xac\x8a\xc0\x0b\xc1\xd3kj%X\x80\xbf\x9c\x03\xfc\x1a\x82\x97\xcf\xd3\xf5b\nW\x0c\"\x97Z\xc3O6\xc9$\xe0&~\xbf\xe9\xfdD\x9c\xbdEO\x1c\xfc$\xa1\xd1nu\x1dD}\xb0\xf7TCZ\x071\x0f\x91_\xfcMC\xe6\x1b(\x8dkw\xfa\x14\xf9\x11&@\x9e\xf2s\xeay\"e\xeaj\x11M\x98\x9f\xb0[\xf8\xc0\xaeO?\xaf\xfc$\x04\xef\x9aW\xf7\xbc\x80\xd2\x1b({\xa2\xdf:\x1e.\xa2\xbc@ss\x11Yr\xb1\xc0\x1fy\x19\x16\xd6@+R\xb4\x10\x98\xf6\xd8|\x1d[M\n\xa5\x8b0{U\x0cl\xd0q\xf5\xea\x80l\xd3\xb1\x94k\xae\x8b}JXU\x9a\x16cm\xaa\xa9\xd6\xc1B\x8f:n\x1aB\xd9=oG\xe3\xc8\xbf\xc5$\xe9A\x97\x9d\x90F\x1cs\xb0a\xdb\xe5\x92}\x11\xdd\xa5\xeb\xa2\xdb={)\x88\xfc\x03\xdc\xafS8\xfeP\x1c2}\xbf\xbe\xdb\xef\xbb\xef\xd7\x9fv\x16\xe5\xffW\xe0\xab\xff\xbe\xdb\xca\xc6\x99P\xaahvM\xa3\xa8HaM\xfc\xd0X\xb3& \xb4\xb0\xab\xe6\x98\xa4\xd3\xb8\n\x96hm\xaen\xe7\xa3J/\x90\x86\x90\xf7>\xbe\x7fu|q:~s\xfc\xa7\xb3\x8f\x17-\x8a\x82\xfaQ+\x88\x00\x9e\xa0R\xb9\xa7S\xc2\xc6\xde~|\xfd\xe6\xe2\xb4M\x91\\\xefM\x08\xde\x9b\xf5v\xfe\xd3\xd9\xcf-\x9dX\n\xca^>Oo\x13\x9b\x0e\xa9\xa3b]j\xed\xabO\x8ay\x9c\\\xbb\x1c\xe0\x94\x16\x1f\xdb\x95\x87T\xd5\xc8\xdf\xf8\xd8;\x1ev\x1c\x0e\x19\xe1\xd8\xd8\n\x07 \xf5\xb7g\xafN7\x06\x07\xce\x8d\x06GUi\x99N\x99c\xfa\x18\xea\xdc\x1fy\xbcJ\xee]\xaa\xfb\xab\x84\x0f5\x13\xb1C\xd0\xc6\xd9\xabO#\xfd\xad\x1c\xa5|\xd9\xce\xd7\xcbe\x94\xdd\xe1\x94o\xe7\x91\xc8\x0f\xc4\x7f\xc4\xf99_U\x11\x86}\x9de,)~D<\xd5\xdf\xb8\x98-u\xec<\xdd\xfbUO\x1d\x82\x95\x13de`Z\x97\xe5\x92\xda\xe8T\xa5\x9aS\x07\xf6\xe8Z#\x13\xda\xf2\x86\x04\xb4\xba\xb6&\xc9\x80S\xdd\xb50\xd6\xa5 {\xb4\xd6\x8brw'i\xb6\x8c\x16\xf1_\x19\xba{\x05\xd2\xfe\x1d\xfb\xd6wp\xae\xef\xe0\x00\xcb\xeb\xaf\xf9w 9\xcc\x1a\x0eu\xda\x8d\xa5\xdd\xab.\xa0\xd7SX\xe9\xa6\xb1pT\xff\xe9\x8e\x9e\xd3>kj\xef\x1a\xea\xe5\"0\xa6jo\x1bA\x94\xbaK\x06\xb6\xfc\xdb\x81\x1d\xdfBf\xc3c\xd3\xb8Hk\x18\xd2\x89\x94T\xf2\xcf\xdeAG\xd7/N\xa5\x8c\xa1\xd0jt9\xc0\x14\xf3\xe6d~\x12\x8c\xfa\x97!$\xa3\xc1%zc\xfa&EoTm\xab\xbb!\xd6\x13\xcd\xda\xc2\xa90\x14\xd7\x90#\x16\xfec\xd2\xc8Y\xa4\x0e\xac\xf7\xf8]\xfd\xaf\xce\xb0zb\xd2\x0c\xa9\x96x\x16\xf8^\\\xb0,\xc2\xa5\xb0\xc9\x9b\xe1K\xd9\x06o\xc7\x8a\x9b\xa1\xf4\xfd\xac\x87\x0dk\xc9\xc71{\xdaa\x8d\x9f\xddp\x8a\x8dsI\x8d\xb0\"\xf6\xfa\xab\xe5\x1a=\xb9\x1ce\x97f\xfe\xbdX.b\x93\xa4\x06\xaa\x1f#*Q(\xa1\xc8)NM^\xa5\x1a\x108\xb1[oA\x83 \xedx\xd3\xd9r_\xc4AB?\xe6*\x84\x93\x19oE\x913\xf3=\xbdi4\xc0\xd1R!?\xccb\x02\xa6X\x86Y\x97\xda\xa0\nMr\xb0z\xa6i\xc2\x86b\xdc\x9d\x83^\x878\xb0\x0d\xba\x8f\xa86\x98\x1f;\x08\x03\xeb\xe0\x1e\xd5\x05\xcb\x7f\x05\xfe\xe9\x97VE\xe4xk\xea^\xbe\xdb,Z\x1d+\xfdBC\xee\xe8\x7fH\x85\xc5\xde\xaf\xcb:.Paa\x99\x94\xaf\xcb\xa2\x81Y\x94\xcb\xa2\xbd\xfd\x03Z\x97AD_\xfd\xa7.\xe3\x97\xde\x97$:\xadHw\x81X\x95\xec\x99%\x91,yj\x954i),!c!\x9b\xd9\xb3\xba\x9eH\xb5\xc6\xc0x?\x93\xefwI\x84j\x08S\xfaK\xd8\xb9\xd4\xf4,\x99\xa6g\xd1\xac\x0f\xb3\x10fJ\x06?\x7f\x7fz\xd2M\xefQ\xe6G\xd0\xa2\")\x81\x1b\xa3\xe9\xa2Z\x04-Ru\xa5\x08\xe8\xa3V\n\x01\xc7`>~x\xd3m,\xb2\xb3u\xb6\xd0\xfb\"\xc4\xf6\x86\xce\xfep~\xf6n\xa3\xde\xfe\x92\xa7\xa6\xb4u\x96MY\xc6\xa6\x9a\xee%\xe8\xdc\xff\x87\xd3\xf3\xb37\x7f<}\xb5\xc1\x18P\xf8\xc9X\x9e.n\xd8\xd4\xbb|\xf8\xb1\x8c\xcf?\xfep\xf1\xe1tc\xad\x0c\xad\x8fI\x84\x13\xbd]\x98J\x13\xdab\xde\xa2\xa4Qs=__\x15\x193e>]\xad\x14\x04\x0ehd\xdd\xa1\xf0\xfe\xf8\xc3\xf1\xdb\x87\x9a:\x9f\x9d{\xe6Y\xb4|\x17- \xd0\xc4U\x85\xd7\x84\xd6o]\x15\xdb\x85y\x13\xcc1\x9cg/\xce\xff\xe7\x92\x88 7!tB\xea\xbd\xf0T\xe6\xe7\xcf\xfc$\x9d\"\xd1\xda\x8a\x05g\x0dG\xb0\x16\xaa\x88$Z2\xa17\xeby\xb0\xad\xde\xc6\x89|\xc7?\xde\x11\x05\xaa\x1d\x1f\xf3\xf7\x97_\xc4\xf61\xca\xe9\xea\x02\x8e\xc0\xc3\x19\x8d?/\x17\x1e\x0c\xe5/Z\x7f\xa0i\xf7\x18\xe6\xf3F\xeb$7\xd6dA\x08#\x0f\xa1\xc9\n\x86Wv\x93\x10f\x97A\x08yg\xac9}\xfb\xfe\xe2O\x02w\xc6\xaf\xdf\x9d\xbc\xf9x\xfe\xba\x95\xb0l\x84EoY1O\x89\x1a\x0f\x83Kq2Y\xac\xa7\xect\xb9*\xee\xfe\xc8Ak\xf3-\xc2\x1cx+.y\x1ee\xc2v\x1be\x89\xef\xfd\x1ce \x06\x1el\x02\x08L\xd0\xe4\"I\x0b\xb8f \x17^\x19D\x80c\xfb\x1f\xec\xae\x87\x16d6\n\xe4\x18\x1d\xd7\x81#\x0f\xb3\xe8c\x04@\xce\xd9g/\x84\x9c\xaf\xfd\xba}\xed\xffx\xfc\xe6uE3\xce\x7f\xbd\xe5\x8e\xf3\xb3\xe3\xf3=z\xad5\x05YGH\x04\x84\xfa\x9f0\"\xe7\xb4\xe3\xd1\xe7\xe5\xe2Q\xdc+X^\xf8\xb1\xd8\xde\x1c\x0d\xd6K\x96\x8f\xc5\x96\xa4\xbe\xe4{x\xd2\xe3\x9ca\xc4\xa1\xf3s\x8c\xf3\x8bd\xcc\x10ArB\x18\xb1\x86!6\xdfcl4]c\xb7_R\xd3\xefx\xfb1S\xd6\x8f\x1a\xed\x10m\x95\x8e\x15\x94\x01\x95K\xecV\x18\"\x8e\xb0\x9bh\x11\xf3\xc9\xbd\xe7\xad\xa3\x91\xfb\"\x84\xb4\x835\x18\x87FAR\xe4\xa2\xa2\xc8!(\x0b\x85Ks\xfe\xa4\xd1\x93\x1d\x15\xa5}\x7f\x08\x93\xfco\xdc%\xdavx(\x1cH\xdaq`t\xd9\x15\x07\xbaX\x03\x81\xc5F\xd6\xacCj\xdd\x12\xb0\xdf\x18\xf0\xe7\xa7\x17\x9c\x9b{\x7f\xf6\xee\xfc\xc1\xb8\xb8\xcc\x8c\x07\x035\x1e\xce.\xc3k\x9d\xde\xd2A\xc8\xd6\x0ef\xc3_\xa3\x13\x1d\xc2\x07\x8e\xc0\xd0\xea\xdb\xa0\x15\xd6\xd2dP,\x8e\xfcC\xd1V/!\xcf\xc6\xd2\x90_T\x92? \x9e\xaa\x88\x8au\xce\x19\x16U\xb5zS_\x9bP\x96g,_\xa5I\x8eY\x02\xb2\xa07g\xd1\x94\xa19\xd2\xba\xfc\xfb\xcb\x17K?\xc0\x17c\x824\\\xe3}\xb1\x1d\x8e*i\x08\x91\x8b\xdd_;(\xe4B\xc1\xae\xf7\xc3\"\xbd\x12\xda\x97iTDzPm\xbb\x8e?A\x8a\xed\x1aD\x08^\xc1>\x17\x9cr\x88\xd6\xf8\x112\xe9\x88\x95\xff\xf1\xf1\xf4\xbc\xedJ\x7f\x03\xa4\xfc\xaf\xcd\x902\xd6\x90\xb2U\xec\xf8\xaf5\xcb\x0b9\xe9\xd8\x05\xf9.\xa2\x05\x9f\xf9\xdb\x8f\x17\xc7\x17\xa7\xaf\xfe\x91 \xb0\\\x17Q\xc1\xa6\x1f\x1e\x0e\x10\x929<{\x7f\xfa\xe1\xf8\xe2\xf5\xd9\xbb\xf1\xdb\xd3\x8bc~B||0:\xd5$r9\xa4\"\x01\x92O\xec\x8e\x96\xa6F\xad,\x85\x83[\xeaz\x1eYN\xa0\xe5J(V\x0e\xb5\x0e\xae\xcf\xf3 \x080{dY\xbd\xd2\x0el\xfcI\xab\x90\x8d\x9f\x1eUX\xe2\xaa\xb7\xe0\x87ll\x9f\xaci\xd0M\x1b$\x98\x87\x87>\xc5\x9a\xb0\xa3qOL\xd9\x82I&C'\x87Y\x08\xe9e;\xde\xab\xc9<\xe8\xd6\x7f\x98\xb9\x94{\xbb\xe3T8-;?\xf9\xe9\xf4\xed\x83\xadI>\x993\xeat\xfe&*\x96\xf2s,\xd6\x11\xd5\x13\xfdTT,\x13\xca\x87/_\xb0\x9e\xbc\xb6\x1dR\x1fxc \x83s\xf1\xe6\xb2\x9e\x97$(\x7fv\xbe\xbf\xdd\xa3c\x99=\xdb'4\xdd\xf2\xb67_\xb1I\xccr\xaf\x8b\x1d\x00\xb9\x16!\xb2d\x99\xcf\xd0_?/\xb2\xf5\xa4H3\x12zZ*\xa8HK\x0f\x7fx\x08~\x82mD\x01\xdf\xdb\x98\xdbh\x08\xa9n+\xd0\xe9*\xe1\xa6\x16\x87\x15\xe7\xb8\xff\x8cV\xd8\xef\x99 \x91\x86\x85\xfb\x94\xce>\xf1\x07V\x948\xa9\xb1\xa7\x14\xf6\x93\xde*K',78\xdbU\xc9\xfd\x94\x89\xf6k\xe5S,\xafg\xc0\xaf\xd7\x98c\x8d\xb7\x82\x9f<\x99GI\xc2\x0c\x85\xdb\x0d\xd6x\x15\xe7\xab\xa80\xc35/1\x1di\xed\xd55\x11\x80\xee\xae\xed*\xf7F\xa67\xd8\xb6\xc3_\x83\xd4\xea\\\x1bWJ>s\xe6\xbeW\x97Z\xd7V(R\xf5\x08\xba\x82\x15B(|B\x92\xa9\xbd1\xa6s\xd5h\\\xc1\x1fu\xe1%x\xcez[\xd5\x88V|\xe7O1\xc6\xc1\xaa\xb1\xc9*G\xba\x8c\xd6\xcaQ{\xf0\x9c2lJ\xaa\xe8\xaa\x95\x11S\xb2\xbd\xed\xb8g\xbb\x1emo/[o\xda\xd7\x8e$\x1a\xf2\x06\xe8\xc7j\xe0\xa1\x15\xae:\x84\xcc_\x06!,\xbf\xd3^5\xc7\x86\xd7VG\xff\xc8\x93[\x00\x87\x90\xf8\xcf\xf6\x02\x7f\x16\xe0\xb5l#\xec\xd0\x94\xe1\"\x9e|\xf2#\xff\x0e\xe3\x94\x0ct\xfe\x0f\x86p\x83\xc6`\xbd$\xbdmm\x0dk9\x1b\xc2\xd0\xc2\xb12\x19N\xd8-\xcc\x83\x1e'{\xbb\xfct\xe2\x7f\x0czi\"\x8578\x84\xab\x10\xbb\x8b\xfc\xb8\xb7J\xf3B\xeeB$5\x03d>&\xbdh:=\xbdaI\xf1&\xce\x0b\x96\xb0\x0c\\\x01\x0b\xb5\x06P\xdb=\xe9\xc5K\xde\xe39\x86S\xcdU\xd0c\xf7\xd4&\xfa\x18|tt\xe3\x07\xca\xef\xea\xa6\x87\xf6\x88t\xa7\xa1\xab\x10\xb6\xc4\xc8y_^\x9ad,\x9a\xde\xa1\x1d\xc2d\x1e%\xd7\xcc\x838\x81\x85\xef\x89 \xaf\x1e_>\xf7\x88\xf2^\xb4Z\xb1dz2\x8f\x17S_\xfb*\xe8\xd9-\xb7\xe1p\xde\xcb\xd82\xbda\xa21\x91 \xa7\xdc\xa7\x06\xce\xd6\x16\xb5a|\xac\xb8\x88\x97,]\x17\x1aF\x84\xd0\xaf\x1f\xb8\xfa\xd1g}?\x84\x95q\x06pZ=\x84i\xd5\x04\xfe\xf5\xedq2\x1bM\xebh:\xea\x08\xc2\xcd\x9f\x9b!\xb0v\xb2\xd9\x18\xc9\xb5\xb5kBQ\x02\xb2\xeb\xb6\x8e[\xa0\xb7)\xb3\xb3\xfb\x94dvv\xfb\x8f\xef\xc3\xe2`\xb2\x10\xa4\x95\xa9_\x88|\x1b:\x9b#\xed\xedJK\x08[\xf1\x82\x91\xa2{3;\xa5\x98\xf8\x82\xf3\xc2\xa8\x05\xe3b\x92\xb4\xa4\xe5\xec\xc32\xce7\x8cs[\x8fu\xffd\xef[\x02\xda\x17\xba\xe5\xc0!l\xb9\xcc\xb9w\xfb\xbf\xa4Q\x8e>\x1eY\xa7\x8b\xa5d+\xf3\"\x9c%\x1d\xa1\xc5]\xa8\x8f\x89\xe1\xd40j\x8aw2\x9a\x13\xd8\xe3\x81\xccOC\x88\\\xb5\xa112\x85zn\xa4\xb3}1J/\xfd\x88\xd0\x10\x98\x8f\xd0\x0e\xa2\x8a\xc2Y\xb7=\x8a\xb3ztF\x9e\x0c$\xa3\x1e\xdb\xe0K=x\xeb\xb7\xeeM\xd3\xa4\xda7%`\xd5N\xf0\xf3\x00c\xfav\xd0\x80\xab'\xf3=\xce\x15\xcb\xc8\x1b\x89\x88\xd7 \xd2'\\\xb6exq\x918\xc2^\nM\xc0\xb7R_\x84\xc9\x8e\xe5\xff\x98\x0d\x87\x8b\xdb\x9b\xa1Q5\xe9\xc1>}\xca>1\xe5j\xa9R\xd83St\xca\xfc\x15\xe6\xa1,\xc4\xf0\xa7\xfd.g2\xba\x1f\xe4\xd4\xc9\xbc\x15\xa1d\xa9TP\xf5\x8dX\nb\\\x84\xdf\x19\x84(\xb2\xa3\xa7|\x8aQ\xe2\x82@Jb\xa1\x90\xdaa\x07\x06!J\xe9\xecy\x99o\x12\xc5\xbe\xed\xed\x05\xbc\x80\xc9s\xd7\x81\xc2%\xa4\xb5_\x8c\x16\x97\x0e\x82\xcc\x05w\xc2y\x81O\x01{\x995I\xc7\\\xa6_\x8d\xa6\x0e\xe9XO\xaf\xcd\xbb\xe1\xc2C\xee\xdf\x840\x0da\xc5\x99{QA\x98r\xceQ\x80\xb9\xe1\x9c\xfc\x0d\x0c!\xe6c\xc6@\x17\xfc\xcd\xe8\x92\x9f\xceT\xf8!\xebM\xe6\xaf\xb0\x83y \x00\xc6\x87\xf7\x9d\xfb\x13\xb5>\xf7E\xc2\xbd\xfdN\xbc\x1bq\x14{\xe31\x9a\xb9\x8e\xc7b\xaf\xe0\x9e\xe0\x8c\x88\xfc\xc0\x86z{V\x9cZ\x12\x19\xa2\\Z\xa1\x12V1Zb\x1a\xc3\xbf\x01\x95\xd7\xa3\x82\x0b\xf7\x1b\x9a\xb5k\xf4\xc9\xe4\xc5\xd261\xab9\x10\x16C\x95\x9c0\xc4\x0d\xc1\xab\x9b\xe2\xb6\xc5\x8f\xc10\x94\\&E\xb3\x07B\x06p\x9b\xf7\x7f\xf5\x1d\x8b\x9dv\x81\xc7/lN\x1cBQ7\xa1\xc8Q\x17\xcd>\xb3\xc9\xba`\xf2N\x0b_ \xfb\x81?\xe4ir\xbeb\x13\xed\x95\xfc\xe9\nJ\x11\xfb\x89\xbfO\x862\xe7%\x83=\x87\xa3<\x91\xecX\xad\xc5/c\x0b\\\x9bL\xa3\x0cU\xa9\xec\xf3\x15\x9bH\x07\x05R\x1aj\xc4VfX\xf6TL{(L\xd1rv\x91rx\xcbz\x89^\xc55\xa1\x90Z\xa9_c655\xa1\xa9\x1b\x0c+\xc71\x14 #\xcc\xe5\x04\x11\xbc\x80\xe29D\xdb\xdb\x01\xc4\xa3\xe8\xb2\x96&$\"\x0e\x08\x13d1\x82*N\x14\x06\x7f\xa8_\xcf\x9dD\x939\xa3\\\x8c\x94\xd4\x11\x8f\xfa\x0e\x07\xa5\xdc\x0eP\xbf\x0e\xab;\xce\x80\xb2K\xe0\x8f_\x8f\xb9I\xe5\xacq\xf2\xe9F\x7f9\x1a{\x05\xbd\x7f\xc9\xd8\x8c\xa3<\xdeb\xf3\xedh\xcc\xd2W\xa3\n\x81]n\xc2\x80\x87\xd4F\x7fh\\!\xcd\xb8\x94\x0c\xda[\xa4\xd7\xb2k\xe1\xb6\xea\x9b\x1a\xdc\xfah-J\xb5\xc1h\xcb\xb0\x8c\xf7\x1f/\xc3`\xc7\xd2\xae\xd0\x8aRcP\x95\xbf?]\xef\xa2c\xb8\xd1c\xbd\x9d\xa4\xcbU\x9a`VJ\x0b\x04e\x94\xb6\xf3\"\xcd\x1c\xd6\x01Z\xa0b\xbb\x02\xde\xaa\xd5z\xb1\xeb\x08\xab\xa6\x8c%S\x96\xd9\xa5\xb9\x0c\x1c\xfe\x89\xbd\x8dV+6=I\x93\"\x8a\x13\xaa\xea\xa2\xdc\xbeK\xb6L\xe3\xbf\xb2\xc0\x8fDvr\x91>:F\x1e\xdcJ\xa2\xe5T\x0bfiZ\xbcN\xf8\xda8\x9d\xd9\xf4\x99\x0d\x810\x1c\xe7\x0f1\xf8\xa19\xd0\xdc\x1e\xe8\x02\xc7J7)\xa05\x84\xb5\xfdYd\xdd\x88\x80\xc5\xcb\xba=\xd5Z/\x9a6r\xf6\x02\x0d\xd9(\xc2\xd9\xe2\xf4\x05\xbf\xa8\xe3\x17Tk\xeft\xfe\x02d\xe58\xf3\xfe\x94bf\xd0=\xea7\xb2\xf1uTD\xfa'p\x04\xff$0\xb0\x81y\xbb\xe6\xcc\xdbcj\xbe\xd7$[\x17\xcb\x12\xda\xe5\x0cK\xac\xd6\xd6\xaa5\xca\x01\x11?1\x0b\x16\xb2\xc0\xead\"\x0b\xac>f\xb2\xe0\xc0,X\xe1\xd2\x99\x97\xe4S\xac\xbe2\xde\xcee#O\x9eXC\xbd\x11\xe2\xffc\xf3\xfa|)?y\xfa\xf8\x19\xcd\xe6^\xff\xbal._W+\x1d\xb4C\xe5k\x13\x81\x06\xa3l \x8eR\xa7\"Y=\x9a&\xb9\xad*\xd4\xaf\x18\xf2\x8aM\x12\x1a\xefL\xda\xe1L\xcc\x02?\xeb\x952\xb3\x8a\xe8\xbf\xae\x19\x9594\xe7n\x0d)\x90:\x04\xfd\xd1F:\xab\x19\x06%r\x98\x8b\xda\xdbQ\xfb\xdc?\xb1\xbb!xb\x1f{\xf4A\xa0?\x9224r\xec\xd4#\x07>-\xf5\xd7\"\xee\xc7\xa9Hl\xcf\xe9\x91a\xbf\xf67\xf4u\x0fdn\xf3U\x96\xaer\xf9\xf7$M\n\xf6\xb9h\x81#\xb4\xc2\xf2\xebe\x10\x12\xe1\xd8\xcbb\x7f\xd5+\x89\x9dK9\x8d\x98KC-\x95\x9c\xc2\x0d\x1fp\xc2&\x85\x16\xdb\xa4-\x80\xeb\x8dL\x8eo\x9a_\x7fE31\xe6S\xd1'\xd5\xa3PD?\xbe\x96\xd1\ns\xd0_\xa4\xfc\x04@\xdb\xe7v\xa9\xc1h\xb0}\x9d\xf1\xde\x9a\xba\xc7\xd4\x1f\xf7\x9a|\x0d\xfc\xa4\x8c\xf1D\x146d\xf6Ij7\xee\x0d\xd4d#J\xb2\x01\x15\xf9\xadP\x107t\x1f\x96rl@5\xeeC1Z\xa8\xc5M\xef}\x96\xde\xc4\x9c\x97\xef\xd0\x18 j\xa6Y+j\x82\xe0\xb16\xa3Qn\xf2t_:\xdf@\x97Zh\xd2W\xb1\x81`h$\x0ci\xb4\xf4j\x8c(]r\xc6)\xe7\x8c\x1b=\xa7by\xd9JS&\xd2\xba'\x1670\xc9(\xbd\x0c!\xc3\x7f\x19\x99\x88\xa6i6c\xbc\xacp\xb0\x9f\xc44\x85\xcdc\x830\xde,\xb1C\x9d0\xb8x\x1c\xf58(\x82\x9b|\xeb\xa4\xff>\x14C\xa4\xac\xc5\xda8\xb6\xf6\x93\xe2\x8a\x03'\x12Z~\x8c\xb2G\xa3^\x13=\xb5\xa9J\xb1)U\x11\x14e\xa2\x90\xfb\xe7x\xb1\xf8\xc0&,\xbeA\xa1%o 2&\x81id%\xf9\xa3M\xb8\xda\xbd\x9b\xd2\xd4\xafM\xa4\xa7#y\xdc\x944\xaa\xcb\x06\x0e\xd8e\x1d7\x14 \x8a\xa4\xd3\x96\xa6\xee\x8b8A\x18\xb9n\xdc\xf4\xa7@a#\x0e\xc1\xcb\xd2\xb4p\xdd\\\xa8\xa7\x9d\xa5\xdb\xd8\xec\xc1A\xfa\x1a\xc8\xde\xd7P\x97B\xc9\xedn\xc5c\x03\x8db\xa9\xaaY\x08\xde\xf1j\xe55\xcc}\xde\xabl/x\x7f\xbek\xe6q\x88\xb7\xa2\x81\xc5\xcc\xb4\x1aUTJ\xb3$Z\x12z\x8e\x16\x90{\xd3\xf8\xc6\x92\xe5\xd5\x93\x17w\x0b\xd6\x14\x14i\x15M\xa7\xe8B\xee\x0d\xd8\xb2\x01k'\xe9\"\xcd\x86\xe0\xfd\xff\xa2(r\xe4\xbd\xb3W0\x04\xef\xff\xf9\xdf\xff\xb7\xff\x03<\xf7\xf9\xea\xc5\x9e\x00\\\x08\xdeI\xe9\xa8.\xd7\x96/\x0c\xe6\xbf>\x84\x02\x8e\xc0\xe38\x0f%\xb5\xf0`\xc8\x17\xd1\x0b!g\x0c\x8a9+\xbd\xe3=+\xe4w}b\xb7\xad\xca(\xb5&\xdd\x18f\xb9B[>\xab\xd8o!oW\xdcx\x9c\x7f`\xd1\xa4h\x17.\x9a\x0dI\xf5\xa7\xf3\xd1\xa5\x9e\xf2\x08k\xa7:\xd0\xc2\xdf&N\xfe6i<\xad\x92{\xf0\xb7\xd0*\xd5\xd1'RB\x9eHI+\x9f\x0b\xdd\x89\xb9z6%\xea\xea\xa9\xae\x02:\x9cI\xea\xe9 \xe1&n\x1a\xdcI\xc2\xc5\x1bwz\xda\xd2\xbd\xa8Dl\x01\xa3\x06\x0d\xa8Y\xb5\xed\xde\x1dZM\xfdJ\x06\x95\x91\xb7\x83Yy;\x88\x96\xa9\xe2v0\x85\x17\xc0\x9eC\xba\xbd\x1d \xd7Y\xbb\x1dt1\xb0\xa0\xdf.\xe9h\x9b9 \xd7\xc9TP\xb6XOG\xc5\x87\xea\"\x92\xe36\x89G:d;VL=\xc27\xbb\xc0c\xc6\x8d\x1f\x8e\x99Q\xd4\xddPgW0\xb4\x94\xc6\xf6\x19\x9d\x86\x10\x9b@\x8ag\xe0\x97\xc6[U\xe2\xbf4\x90A+\x13v\x0b\x17w+v*\x12x\xbdcl\n\x11\x88\x0fB(R\x981\x0e\xfd\xa8:#z\xf0s\x94\xc3u|\xc3\x12\x880\xd5\x8d\xaf\x99\x04\xa5\xfcPY'BM>\xe5\xe7\x89q\xe1\x9aZA08\xd6 \xa3-3*\x84\\U\xce\x8b\xc5\xbc]\xe4(\xb0\x1b\xfe\xf3N\xb1\x9f>\xfa\x14\xe0\xcf[?\xc2\x1f\xb7\x82[\xf3\x99\x1f\xf4\x16\xe9\xb5\x0c\xeeR\x9d\x86\xb38\x99j\xc7\x1e\xe70$\xb3Q\x0e\xa0\xd3%\xa1\xdb|_Nx\x08\x89\xff\xe4\x89i\xc8W\xe9\x8c\xeb\x97\x03]\xba\xa4\xaf'\xdc\x03\x99G9^\xb3\x0bG\x89w\xe9\x94\xe5C\x18\xddX\x12\xc2:\x04\xe1V\xa4\x90\xd5w\x10T4\xdb\x16\xb1\x93\x1c'\x838\x94\xd7x\n$x\np\xc4Jz\xf2,\x80\xa1\x8a_\x87\xb1\x89\x9d:\xee\x05\xca\x11\x92\xfd\xec)\xa4\xc6hl[\xfd\xc6\x03\xd0\x81\x8e\x8dwR4,\x0b\xa1U\xd1\x1b4\xb8@\xd26[g\xd0\x84\x1b\xec7\xf1\\\xf5Q\xcbKC\x93\xceO\xd1b\x8cz[\xc4K\xa2\xc4SE;\x8bt\x12-<\xbb\x06[F\xf1\xc2~\xbdL\x93bn\xbfN\xd6\xcb+F\x8ck\x15\xe5\xf9m\x9aM\xed\x92\x8c\xef\x07\xfbu\xce\xa2lBtP0b0\x9c\xef'\xde\x923^gD\x03\xb7\x8c}\xaak`\xdb\x94tN.W\\N*v\xb6\xfe\xab\xce\xb5\x92\xac\xae\xce\xe5\x16p\x04[[\xd9Hp\xce\x98b\x8e\xcf4\xcaX$+T\xe3}p\xfc\x12\xa9\x03\xcf'\\\x8c|\xc3f\xc5\xd0\x0c\xe1U\xabq\x91\xae\xac\n\x19\x9be,\x9f\x8b\n\xb8m\xf3\xb6}\x98\xf5\xac~Q:\xf8\x1c\x9aE\x17)\xfaK\xf7\xeejm\xb4\xee\xc3\xec\xdb\xe1\xe4R\x83\xfa\x83\xc7\xa6u\xbatM\xb7B\xc1E]\xd4W\x9c\x82\xb7\x86\xd6f\xbdY\x9c\xe5\x05\xaa\xf4\xddZ\x1b\x94\x9f\x12\x112\x06\xd3ic}\xferO\x8aS\x1cC/\xeeV\xd5\x89s\x93\xc6S_\xbc\xc7\xa5\x83\xc3v\x0f\x15@`k\xeaX\x8bU\xd2V\xc5T\xfbvW\xf9r\xae\xba\x15\x82{\"a]918\xe2\xc4]\x04\xd3AMy}j\x15\xde\x04F0\xa6o\xa0\xdc\xdd(\x07}\x1f\xcbz\xb3t\xb2\xce\xcds\x86v^~\xf0\xdd\x1f%\xf1\x12c\xdb\xbf.d\x90\xfb\x93t\x9d\x104\xf6*\xcd\xa6,{\xbd\x8c\xae\xd9\xd9\xba@\x06\xbf\xa1\xca\xf9\"\x9e\x10$Y\xab\xf1s<\xa5\x8e\x95\xab\xf4\xf3\x8f\x0b\xf6\xd9Y\xf0\xfb,]\xaf\xc8\xd2\xb3l\x1a'\xd1\xc2Qa\x92.\xd6K\xd7\xdcDan\x17\xcc\xc8\xa1\xcc\xc48n\xe9\x92\xf7i\x1e\x17\xf1\x0d1{^z>\xcf\xe2\xe4\x13]\xf6\x8e]G\xee/1\\\xb1]t\x9d\xc5\xd3\x0f\xd4Xd\xc1iB\x1c\xc5\xb2\xec|\x15%\xee\xc2\"\xca\x08X\xf1\xd2\x13\x84WS\x99\xb3WQ\xec\xeeX\x96\xd3}\xcf\xd2\xa4\xf8\x99\xc5\xd7s\xa2l\x11'\xecd\x11-\x89\xb5\xe7E?9>KW\xd1$.\xee\x88\x02\x1a\xdci\xb6\x9aG\x14\xaa\x14\xd1\xd5y\xfcWb\xedn\xe3izK|\xf0\xd7\xd7\xc9\x94\xc2\xae\xbf\xa6\xe9\x92\x98z\xbcX\x9c\xb9\xc6:[\xa4\xe9\xd4Y\xca\xb9\xd9\x86\xc2,\xfd\xc4^E\xf9<\xca\xb2\xa8\xb1B:\x9b\x91\xdb^\xd4x\x1b\x17,[\xc4\xcb\xd8Y\xa3e\x0c%A(\xcb\xbe\xda\x17p#\xefgv\xf5).\xbc\x10\xbce\xce\xff}\x9b\xfe\x95\xffw\xe6i\x9a\x1e\xa9\x89\xf9\xc4\xeer?\xeb\xe2\xee\x9d\xdauh\xa7\xe3Q\xeba\x0e\x9a:\x11\x13WL\xe6Qv\\\xf8\xfd\xa0W\xa4\x1f\xb90+5\x99\xbc,__ \xc3\x0b\x7f@\xd9\xa4\xa3!\xe8%gf\xf4\xd0\x97X\xa6\xa98\x8d{\xca\xd8\xa2\xf1q\xfe1\x89\x8b\x05\xcb\xf3w\x92i7\xdcs\xf3y\x9a\x15\xf3(\x99*\xad\xd5\xe9\xe7U\x94\xe4\"'\xa3=\xc5\xabh\xf2\xe9:K\xd7|\x8f\xd3\x00\xa8j\x1c\x17E4\x99/\x19Ev\xed\xda'\xb4\xaccW\xc4#\xa4KEA\x8d\xd3\xe4\x7fnR\xf9O]*\x7f`+\x16\x15C*\x8d)\xa1:\xb1;i\x87\xdd\xfd\xc7\xdeiD\x92\xc29F\x81\xa5\x8eC\xba^\xe9\\\x98\xc76W*W\xb6\xfb\xd0~H\x8b\x82\x93\xc2\xa6\x01\x8a:\x9d\x86)\xaav\x1a\xac\xa8z\x8f!\x0b\xf1\xa9i\xc0\xbcF\xa7\xe1\xf2\x8a\x9d\x06\xcb+\xdec\xa8\x1f\xc4y\xd84V\xac\xd2i\xb0X\xb3\xd3h\xb1\xe6=\x86\x8bbg\xd3`/\xd2U\xa7\xa1^\xa4\xabN\x03\xbdHW\x1b\x0d\x93\xf3&\xae\x11\xf2\xb2\x96Ny\x95?FY\x1c5\x11\xca&\xfeG\xafC3\"\xeaib\x87\xd4\xc3[\xf91Z\xc6\x8b\xbb\xae\xf3O\xd7\x05o\xd8\x05\x02Y\xdc\xb2D\xb2V\x0b\xacd\xad\x86\xe5\xf9\x8e\xfe\xe5P\x15\xc4\xf8\xf6\x9b\x84\xaa\xc4\x7fj\x06\xe3K\x85a\xd0`\x1f\xe3\x02\xee\x89\xf0\x80O\xfb\x96\x83\xbc4 \xc2rv\x0b\x1f\xd8\xf5\xe9\xe7\x95\xef\xfd\xe7\xc8\x83m\xc8z\xc7\x17\x17\x1f^\xff\xf0\xf1\xe2t\xfc\xee\xf8\xed\xe9\xf8\xfc\xe2\xf8\xc3\xc5\xf8\xe4\xa7\xe3\x0f\xb0\x0d\xde%]\xa9,\xfe\xdd\xbfXi\xcd\"\"\x1e\xfbZ\x06\x80(_\x96w\xa5\xb9\xf3\xaetkkmG`\xc7\x00\x81\x11\xf1\x9e\xcb\xfd2\xfb\x1a\x1a\xb4\xf9\xeb\x11\xbb\xc4\xb0\xaf\xa8\xdd\x85!\xf8\x91\xf6\xa6\x16H\x9bNs\xdc\xc5\x9e\x10\xf3\x84\xcc\xa3\xfc\x874]\xb0(\x11:\x80\xef\xbf\x87\xad\xaa\xe8\xddz\xc9\xb2xR\x16\xc5\xf9\xbb\xe8\x1dg\xfeT\x05%\xce\x99\x15\x0bx\x01\x83\xb2\xd6\xd9\x0d\xcb\x16i4eS\xab\xaf\x01\xa9\xc0\x03\x89<\x13[\x1f\x87V\xcbo\xa3\xec\xd3z\xf5c\x9a\xbd~\xd5\xaaJ\x13\xd3\xcez\xaf_\x8d\xeb\x88\xc0q\xe0\x90cHj\x85\xb4\xae#@\xce\x8a\xe3\xa2\xc8\xe2\xabu\xc1\xac>\x1d\x8c.f\x9b(\xbf\xf2\x89\xee\x89\xe0\xefM3\xfd\x90\xa6m\xd7\x95\xe5T?\x9c\x9d]\xd8\x93\xfd\xb7C\xcf\xfb\xb7\x0d\xe6i\xf4HB\xd7\x9a&\xd1uXK\xdcK\xf4k\xccT\xed\x8c\x0ePV\xea?\xbc\xfc\xe6\x1f\xc5,'\xf6\xd7Q\xad\xc2\x08U\xc8\xb4Q\x15j ]\x82\x0bF\x8b\x14.\x1f\xa5~\xd0\xf3huc\xe9\x07\xd6\x8b\x14tl\xb3\x0e\xf5\x94\xf6\xff\xe6n\xfc\xf2E\xbcl\xd8@\xfdRE\x1e\xab5\x86!\xfe\xad\x90\xbb\x93\xbe\xb2\xc4\x9d8?Y\xe7E\xba\xac\x16\x15\x01X\x91\x0d\xbc\xc1\x1a\xa2\xf8V\xf5 \x01\xba\xc1*\x1b\xbdtXl9\xc4\\RL\x15{\xa7\xc00#\xc6`<\xaf\x05\xd1\x11\x80ndk\x880\x92\xb6\xe0[a\xe1[\xd1\x8co\xa4\x1f!h8\x94\xf60cW\x9c&T\xbeD\xf5\xf0\xa6\xe2@hw]\x06~l\x913GgP\"x\x8a\xee\xbd\xba\x02\\\x98}\x89\xabb\x13pb\xb9\xe8\xeeT\x9b|\x02y\xf11/\xed>\xd0$Q\x81\xe8\x8eo\x8cK:@\xabzZ\x06\x0e\x9a\xbdQZ\xdfq4\x93\xa4?k\xfb\xa3|\x15M\x1c{\xb5\xfa\xea\xc8\xa0~\xef\xce\xfd\xb5\xc8\xa2\x877\xbc\xe8.O\xed\xe8\xb4\xd3\x8eN\xac\xf6}l:P\xa9\x8c\x8c\xf7\xd8\xa5s\xc4\x8e+|\x9b0\x08Hc\xd0}\x82\x14\x14\x06^Lz\xdaV\xd2(\x86\xdcA\x1d\xf7\xa0\x8b\x0886a.\xf3\x00\xf8\x8a& P\x89\x84\x15\xfaXmH\x15%\xa4\x1a\xc7V\xc7\xf4Mh\x145\x8c\xee==\xf0\xc9\xb71%r\x9e|\xa5\x85\x7fgJ\x94\x06\x9c\xad\nU\xf0\xe3\x06r\x84\x1d\xdb\x04\xc2\xbd\xd9\xab\xa3U' \xee\xddj\x1f\xabG\xc0F1\xb2\xd3\x03\x0c\xfb\x8b\x7f{\x0e\x9fc1J{a\x8d\x93\x9d8d\xc5\x97\xf4>\x12\x17\xe2m\xc8R\xfer\xc8f\"9\xe77\xcaf\x03*lq\xe2\xef\x0e\x1c\x11\xc6\xcdp\xeb2\xcf\x97\xd9\xca\xba\x92\xdc\xb6\x06\xa4\x91lnq\xb1x\xd7\x8bV\xccY\x9a\xa25\xcd\xebW\x95\x0dv\xcd\xdci\xc5\x92i\x9c\\\x7fD\xa3\"\n]\xda\xbe\xc1\xe5\xb7\xb1\xc6\xf0.\x10w\xed\xf2\xcaU\x06C \xf1\x04\xc3\x9aW\xf6B\x94\xfdL\xc5\xb1|\xff=(\x03>\x89\x98>\xeb-\xd7\x8b\"^-\xa8\xb4P\x15\x1e8\xc5=\x82X\xde\x94\xd9\xd8\"\xcc\x81B\x1b(\xf5\xd2UaGEu\xde\xba\xa3\xbbA&\xc4d\xdd\xe5 \xa9\xbb\x1cd#AhG\xe9\xe5\xff\xcb\xde\xbbv\xc7\x8d\x1b\x0d\xc2\xdf\xf3+J\xcc\xacCF4\xad\x8b\xc7c\xb7G\xd1\xeb\xb1\xe5\x8d\xb3\xe3\xcbZ\x9e\xe4\xeci+Z\xaa\x1b\xdd\xcd\x11\x9bdH\xb6de\xac\xe7\xb7\xbf\x07\x85\x0bA\x12 \xc0\xb6<\x93d\x1f|\xb0\xd5$\x88K\xa1P\xa8*\xd4\xe5\xac\x93\xc0\xa4\xd5\x92\xd2B\xdcn\xc1L\x89X\xd0\xcd\x0e\xb1\x8b\xa7\xf9\x197\xa4\xd2\x93\x02\xacPaLU2\xc7[\xf1\x0d\x9e\"\xed\xe7Gj\x82xQ:\x1a\x13\x137\"A\xc3\xa6\xde\x02O{r\xda\x01R\x907\xb3@&\xa0l\xdb!t\x87\xba\xa3#\xac\xb1\xe2k\xe2\xc7\xd3\xbd\xee\x17F\xcc\x12\x7f\xe9\x05\xef%\xa9\xff\x9cW5\x06Mq8\x9f\x84<\xc1b\x19\x99\xecA\xf3\x8c\xd9\x01Nz\xd6\x8c\xe2\x8d~\xb3q_xv\xb8\xf4\x97k\xf0\xc8]\xe7\x9b\xac\xfe\x1b\xeb\xcba\"\xe2\xa0U\xf6\xb6\x8e\xdd\xed\x8c\xbf\x07>QZ$\xc8\x9c1*\xc9\x92:\x89Sn\xb9*\x08\x07et2\x984!?\xf1\xbdI\x8f\xc9\x12\x8eU\xecs\x83\xaeP\xc2\x7fX\xcc\x17EXw\x8d%\x8e\xa20@\xf2\x10\xceoy\xe7\xec\"\xcf|~\xeb\x0e\x04\xdf\x85\xba\x9b\xd8\x0eP\xcd\xb9\xe3*.|\x1ec\xcb\x18\xd5\xe0\x96\x85\xaa5\xd9\xf9_\xc7\xd5kN\xbc'\x92\xa0\xd7\x0dA\xefch\xa8\xa6\x8d\xa8\xf9\x8eW\x13r\x1eu\x16\x99\xbe\xdc\xa0\xc9\xcfF\xb7\x8d\xc3\xee^e\xc1\xa3\xf1\xd3\xe7\xcc!\xc8\xb6\xc6\x06/\x0f\x15\x13\x87\xfa,\xf2\xaaf\xa0\xd7\xec-\xd3\xc6bVmZD\xb2n\xb1\xd6\xc8\x0cY\xe7\xa1e\"\xd6\xfe\\Y4{_Je8\xd2-\xb1\xbe\xdf\xd2N8\xc4\xde.\x99\x7f\xb6\x8da \xd9q\xaf\x19A\x08%Ztex\xb6i*42\xd3N\x0f\xbb\x8e\x07\x9amW\xa5]\x0c\xd5\x15?D>\x13\xaf\x17)G\xfe\xfa\xaaLm7\xb0m\xae\xe7u\x19O\xfbx\xbf\x1b\x91\x80g\xcdy\xd45q\xdc\xf0\xe7\xdd\xfb\x8c\x8a;:\xd3\x0e\x809<3\xdewx\x13 \x19\x93N<==\xb4\x96m\xd6\xab\xf7\x11\xcd\xfb<\x1c\x97\x91\x8fxz\xa2}\x91/\x8f\xee\x88\x98\xc7\x00\xf1\xd3\x0e^J\xb9\xccc\xd9\x92Zi\x8e\x86\xf4b\x86\xb3\x88)\xb1h\x03z\xb9S\xeb:\x84A\xfc4\xa1:z!=D\x11|\x8bI%\xbb\x17\xc2\x0cv]\xbc@Ax\xf9\x0eU\x80\x16\x0d\xa3\xbcu\xbc\xd6\xe6nP\x0bg\xab\x85\xf2\x18\x9e\xaf\xc8\xec\x12\x03K\xf1\xc05,\xf55\xe4\x0b\xf8\xbf\xe8\xa3\x05\xbb\xe0\xfd\xdfH/\x9a\x82Q\xb1\x03\x8a!\xb5A\xac\xf5\xf3\xe8<\xbf\xceHI \x87\xef\xed\x1f\xeeyMX\x89\x04\xd5\xc9\x13 \xf2\x10f6\xae\x98\x16MV,\xb6\xec\xc8\xb7\x1c\xc1\x86#\xdc\xab\xac&e\x16\xa72|\x8b\x8f\xc1%]<`\xc4\xac\x1a\x8cQ3p\xdd\xbb'NPf\xf5\xda\n\x95\xa5\xffF\x8dfK9\xc3&\xa4\x8c\xcb'%\x0b%(?\xea\x03\xc9g\x10\x088\x082r\x0d\x15\x9b\xae/~\xb3\x1a~\x1e\x04\x11\xe7\xb2)\xa3\x83\x87}\xd6zr\x04\x19C4\xbcr\xcb\xe7]r\xc16\xae)7\x99\xc7\x9c\x12\xba9\x89\xdb\x0b\xc3\x9d+s\x0c\x1c\xe1#\xb5G\xec\xd8\xf7\xc2\x86\x02\xb4q\\\xde^\x9c#\x00\xd1p\x8fy\x8f\xcbGk\x96\xc1\x97\xb9)w\xf3+\xd1\x92\xfb\x95\xea\xbf\x98t\x05\x86s\x16\xc9\xa1N0g\x8a\x1a\xe4l\x02\xcd\xadC7\x81,{\xf3uN\x92\xef\xbay\xd6\x94P\x17}\xd4\xfd\xf3\xdb\xd3\x0f=\xc7\x00Z\x9e\xbf}\xfd\xee\xed\xe9\xab\x0f'\x13\xd0\x88\x02'\xaf\xdf}\xf8?\x138\xe8\xbfY\x92\xfa\xc3M\xe1\xc4\xb8\xb7/~;'\x01\xdd\xe8\x11v\x83\xea\xea\xa4\xfak\x9c&s\x11\x15\n\xd1\xd6\xb0 \xf8\xbeN\"9\x05\x98@\x12\xd1\x99\x8a\xa4g\xa5\xef\x1d<\xd2'o\xec\x88\xd4\x067\xf1/\xb5=`\"x\x1f, f\xc68Y\x17\xf5\x8dD\xa4\x97\xf1\xac\xce\xcb\x1b'\x88R\x92o\x9bR\x1f;\xfa\x8d\xb1]\xe7\xd4\xa5\x90\xa7\xed\xb0l`\x90Dl\xa2\x94k8\x82<\xbcS\xd8\x9a7\x07\xdf\x05,Ve\x0f\nm\xf5\xf3\x95\xd6K\xdcpL\xd8\x00\xc5\x81\x94S\x04\xa7Tk\x9fR-\x86\xa9\xdc~\xc4v\xd5\xaf%\x83\x8e\xddb\x82ZK\xfbI\xf5\x01\xdd;\xc6M\xa8\x15\xc8&\x19l_\xac\xb7\xce\xd2\x88\xbd\xfc\x9f$#e2\x93cx\x9e\xc6\x95\xd5! \xf8\xd2j\xb0\xbeO\x9bX?\xad\x89:w\x92\xb8l-\xf9\xeb\xeby\x19\x9aQ\xfb\xe1#\xc6\xe1\xef\xf7rj\x08YB\x97\x81S\xec \xff\xa0\x9fiD\xd1\x94{\x91\xa7\x11,\xbc\x89\xe7.\x08H\x9c\xa1\xfc\x8b\x86\x7fW\xef\xceItIn\xe0\x18\xe2\x88T\xb3\xb8 >>\x08P\xc5T\xe7,G\xaa\x7f\xf8H57\x12\x7f\x8d\x89\xd9\xd51=\xa2\xc7\xc6\x9e\x92+\x9e\xa7\xa9\na\x16\xea\x13q\xd2E)BLr\xc2gQ\x1b\x04 %\xd2\x1e\xe5\x00\xd1\xb7\xcb\xbb`\x92\xaaxD\xf9\xaa\x9a\x13\xa2&\x94\x9a\x88\x94\xd10O\xbc\xae\xc26\x89'\x0dTy\x17u\xf4\xcd7|d\x18\xf4Or\xf83\x7f\x81 \xf1\x85p\xa2\x07\x8b\xc6\x0e\xa3\xf7\x84\x13\x94U\xeb\x05\x86\xda\xf0\xbc\xae\xb9\xc5\x97\xfaA\xb2\xd0\xa9h\xcb\xb2 \xa1\xc2tn3v(\xeeuo\x7f\x17\xec\xf6\xf7Q'\xe0%S\x7f\xe9N\xad\xc2\xec4\xfe\x92\xd7Q\x04lq\n\xf5\x177k\x02\xe4\x98\xf2\xa9\xf5?\xa2G\xbb\xb4!\xf6\x98\x07\x12\x06\x89\x0c\xa2\x92\x14i<#\xfe\x83\xe9\xc7\x8f\x7f\xff&\xfa\xe3\xee\xb1\x1fL?\x9e\xfdr\xfb\xf9\xec\xc12\x04\xef\xe3\xc7o\xeeyJ\xb5vW\x9f\xa5oT\x10\xfd\xf1\xd8?>\xfa\xf8\xf1\xa3\x1f|\xc6m\x1b\xed\xf2\x07g\x01\xb6\xf4\xcd~\xf4\xc7c\x86\x18\xdft\x03\xc2\xeb\xbd`\x85~\x8d\x8fV\xa7n\x96\x06|hF\xdc\x0d\x10?\x184X\xd8,\xef\xb7\xbf\xf9]\xff\xaf\x8e\xb2\xae\xe1*\xd8\x11\xb3(\xf3\xb5Qm\xf2:\xc6T\xde\x85\xff:.Z\x06|\xaf\xe3\xc2AQ\xd3\xaa\x85\xdbL\xb6\xd6y\x1e\x18\xdb8%5\xfb\xe8\x94\xd4\xad!\x9c\x92\xdaa\x08\xadZ\xca\x10\xfa\xcf{q\xa4\xaex\x92r*#\xbc\x8e\x8b>b\xae\xf8\xcbS\xd2am\x9c\x12\x9a\xcd\xa3\x8a\xd4\xecm{\x0d\xc3v\x0e\xea\xa1\xe5\x9fGK\xd2\xd7@\xb3D\xb8\xc3\x0d\xcc\xb9i\xa0\xe6\xe3\xd8\x16T\x8ew\xde\xe0\x8f?g4\xb4g\xa1\x85l\xf2\xf0@VQ<\x9fkF1\xecx\x0e<\x07\x83a\n\xd6\x98\x94\xfd)\xac\xf4Sh6\x94\x8e)\xba\xe2\x99\xe6\xbb\xee\x07\xc0\xb3\xf2\xe9\x9e/\xad\x13\x03Eg\x1a\xe9C\x1ai\xda\xbd\x19\xd3.&~~\x95\xd5>\xe1\x1e\x9b\xfe>ej\xf74\x8a\x8a-P[\\\xdf-\xb5T\xef\x8ae\xc8\xac\xc7c\xbd8s\xf4\xed\n\xab\x8bi}6~?\x0c7\xcd#.\xe9\x9av\xdd-*\xafq\x15D\xeb\xb8\xf0o\xb6\xd8.\xc3\xe3\\\xb3l\xf8\xddD\xf9.\xbb\xc9 \x00k\x0d\x00\\\xf7\x9a\n\x80\xb5\x1e\x00\xbf\xeb\xffE\x87E\x05\x85\xe9\x99\x8e/97\xf3%yo\x1eF\xf3\xa8+\x99\xc2y\xb6J\xd2\xf9\xab\x17:\x99\x0c\xc3Oe\xd2\xab\xfa|\x8c\xb5\xd7\xb5E\xc8\xf6>f\xd8G\xc6B\xd13\xcd\xffO\xd9e\x96_g\xc8s\xf8h\xc2\x0f~\\\x03c\x80\x16I\xca\xa2\xf2H\xd6\xe6\xef\xd1\x1f\xa7\x1f?~|p\xf6\x80Y\x1c\xef\x827au\xd3$#\xccM\x9a>\x0c<\x14<\xb19\xa69\x9b\xc3\xc5\x0d6\x9b\xc9\xf7\xaa\xf3\x87nB'}\xb8k\xf4\x05\xde\xef\xc9\xba\xa8o\xb0\xc1q\xf7\x1b\xde\xefk\xf2\xa96}(\xd4\xd8\xfc\x8f \xff#\x9a'U\x91\xc6hY\xca\xdc\x98\xf0i\xc6\x7fJ\x80\x0e\xce\xec\x93\x01\xa3B\xc4\x90Sz\xde\xbeh\xba\xd1Z\x97\x94\xa2b\xa3\x91\xefW\xcaE\xa5\xb7\xd7\x19)_\xbd\xe8a\xab\xd4\x8b\xa2\xe5\x8c\xae\xef<\x08B\xb8\xc6\xfc\x91\x80\xb1\xc8\xcf\xab|S\xce\xda\x1cE{'\x9d\xf6\xb4\xb6yvJXH\x9d\x92dcL\xab\xf4\xd6\x92\x14\xd03\xdf\xdb\x7f\x88\xd1\x923\xb9\xa1\xe8\xee\xeaW\x97\x92z\xc9$\xf5\xb2\xa5\xbe(\x87-\nY\x8e\xb9\xd2\x90Z\x1f\xb8\x0e/\xf7\x13\x93m\xa1\x1ck+:\x7f\xdc\x8cY\xaf\x8c\x8b#\xc2\x83\xf9(\xcch\xeb!6\xbaO\x1b\x8d\xa3\xa4z\x9do2\xba\xc9Xo\xdf\xed\xb7;+\xe2\x92d57\x90R~\x1ea\x8cr\xe5\x01^\x8e\xca\xd6\x0f<&\xec\xc9\xf7.\x176\x1d\xd5h\xf6\x03Y\xe4%y\xdd\xbaAu3\xe7/}c\xb8H\x0e\x87 h2\xaf\x03FSc\x03\x9e@\xa6\xaf\xc0\xec\x9e\xcc\xf6oby&05\xac\xbd\x84\xb9\xd9V\x8f\xc55\xe4\xc1s\xc6Z#\n\xc8\xfd\xc4\x1b\xd1\x83n\x9b\xddC1JA\x194\xfe\x91\x98\xd5\x8bb\xd5\x1b\x96y)\x87N|\xfd`\xea\xf6V\xae\x95a1\x97Va\xf1\xa6b\xf0\xc6r\x95\x92g\x030\xdbf\x8c\xa8\xc7m\x01\xac\x8e\x94\xb5\xdd\xdd\xb5\x8c&[\xdf)\xc8X\xa4\xc7\x16\xa4\xf6\xf5\x90\xaa|\xa2K\xc7x!\x82\xf7\x0f\x8d\xbb\xd8\x94K\xc2\x87N\xe6r\xf0\x95\xc5\xd5\x14\xc3j\x9eF\xe7EI\xaeHV\xbf\xdb\x94\xcb$3*j[\xc9\x94\xf6\x9e\x02\x81\xef\xe1B\xd2fb\xa6\xcd\xb4\x9c\xfb\x17Sr\xe6\xaa8\x03\x9c\xf8@\xd0\xfa\xe1[\xdaf\xb7\x7f\xc9\xe2 \x85\xcaN\x17\xa9\x86\xfa^\x92\xfa9\x8f\xecW\xc7\xb3\xcbg\xf39\xc9\xe6\x9b\xb5\xebHtVO\x836L\x82~\x9c\x0c\x86\xaf.\x99\xe5$Z\n\xe9\xcf\xbe\x1av\x8f\x18\xeb@\x1a\xae\x81s\x11\xd2*\xcav\x9e\x80\xa2\xe4Z\x88\x08\x87\x06\x8aL\xc1N\x9b\xcf\xa3\xf39\xb9\xd8,_\xbd0\xae\x00\x8e\x0d\x99\x9d\x16L\x7f\xb8y\xf5B\xc4\x9c\x17EcB\xdb\xfd\xc4\xb6\x14\x12\xcd\xf9z\x00y\x1a\xb0!|B\x8e\x9f\x08\xce\xeb\x1d\xdf\xbcC\xc8\xd3\x15i{\xb8\"\x8f.7\xfc\x18\xc4T*\x124\x12\x0b\xa6\xf5\xb4t\xaf0\x8f\xae#\xe8\xf0\xb1\x83\x839q\xf3)n\x1at\x1d\x84\x03\x18\xc4\x19\xe9\xd4=g\xb9]\xbbw\x87\x01\x12\x0e\xb6\xefpT\xecO\x89\xf2n\xa3{'\x19$\xb7\xe19@G\x1e\xcfk$Gi\xff\x15Y&UMJ\xc2\xe8U\xdc\xe5@\xaa\xd5\x9b<;\xad\xe3l\x1e\x97\xf3\xbf\xc5e\x96dK$\xbe\x0e\\\xb0\xf1FB\xa4>,I(\xf2\xc2N\xaat\xd8\xecH\xa2N2\x94;\xb5/\xc6\x86\xda?\xc5\xa7\xdb\x1b\x010G\x97\xeeu\xbf\xde\x9e\x969\x1b\xba\xe9{\xa09gH\x14\xcf\xe7'T\x80\xfc\x91{+2'\xa8\xeeSn\x1e\xb6\xb3\xaf\xb5\xadn\x1a]\xe7Wc\xd2\x8a\x08\xff{C_c1\x90\xc5\x9b\x881\xa4'6\xc9'\xd3<\xf0=\x8a\x00\xbb\x0c4w<\x959\xd1w\xb3\xcd,L~\xb5\xfd\xed?\x8b\x8bzS:\x06\xee\x80\xedW~\xef\xae\xc15\xb0\xf2\x9a\x8bKQ\x06`f\x1f]\xa9\xff\xd8\x05\xcc%\xe7\xa0^\x88$\xba\xeaL\x8d\xe6\xdf\xad\x84kwA\x0d\x1e\x1f\xe8\xc2\xf8\xd1\xe7\xfaP\x11\x87\x8f\xba\x99\x00\xb8[\xddw\x07A\xbb\xfd\x8d.M/\xf3aM\xf2\xecy\\\xc4\x17I\x9a\xd4\x89=u\xc2\xd5\x97&\xa0\x80\x8e\x14\xe6\xb7SQ\xdc\xbb\xc7\xb2Ox<\x8d\x00^\x1b}\xfe\xdcKI\xc1\x9e\x95\x1b\"*\xceXL\xff\x93yR\xc7\x17]\xa7`\x93\x03o\x92g\xaf\xb2E^\xb2(\xf4\x16\x0c\x17\x1a\xb6x`Jz4\xc5\x18\xfb\x04\xdd>\x8c)\xbe+1\xa0\xf7\xccc\x1c\x03\x1cj\x97\xc8G\xb7\x91M\xa4\xce\xc2'Zy\x1el'nI\xaa:/\x89l\xc7i\xf9\xd9\x05[lJ\xda\xc3tZ\xca\x9c\x0d\x13\xc6j\xedi\xeb\x14\xed;G\x9c\xe9\xc7\xab\xb52\x84\xdc7\xe5l`\xa1\xe30!\x90\x19z%\xd6\xd8D\x95\n\xbe2\x84*\x08!\xf1\xcb\xe1\xd0E*\xcc\x9d`\xa5\xd7\x1azr\xda\x18l\x1e\x13Q\x90\x007\x96\x1e\x83*\x16\x93^\x81\x17~\xa8\x87,\xc9\xe6\xad\xaa'\xd9\xbc\x8f\x15\xfd\x81I\xebP ^\xd9B\x7f\xb3\xab\xbb\xd6\xb4\xf1m\x12a\xbf\x1f\xee'\x87\xb8`\xf2\xf5\xcc\xb8\x8eD\x08*\x01\xf7\xb4\x12\x18b>)8\x10\xefg\x11=1\x10\x80\xbe7[\xc5e<\xabI\xe9\x85p\x9f\xa7\xf9\xe2\n\xee\x01\xb1\x04A\xcc\x1b\xa2\xcc\xe3`3\xdaV4Y\xfa\xb9\xddR-\xd2]\xbd\xc5\x98\xf7\xd5\xb0*\xe1\xf3\xe7a\x941\x98\xb8\xe3\x04F\xaa\xef+\x03\xf2[n\xd0\xea\xa82\xe3*3\xbb$\x99&\xd6\x15E\xc5V\xaa\x7f\x91\xb6\x9b2w\x86\x1d\xd4\xdd \xb4v\xd8\xd9\x0bp\x04\xaf\xe3z\x15\xad\x93\xccG\xa7\xad\xd6b\xfd\xc6\xfb\x02\x1dt\xf86\xf8@>\xd5\x83[!\x89fy\x9a\xc6EE|d\xe1\x12\x13bg\xf2e\x0fYs\xb8\xcf_\xb3Y\xe9\x12\xcf\x8aH[\x95\x82\x93CQ\x94\xf4<\x12\xcb/\xb8\x15\x8f\xe4\x96\xe2\xa6\x830>\x01\xee\x8d\xd9q\\\x11\x02\xa2XO8n\xfe\x14\xdcy\xd0\x84\xe2\xeb+B\xf5\xea\xa5\x86\xf7\x9e\xd5\xc9\x15Q\xf2\x08\x91\xe8\"\x9fwRH \x81z(\xbc\x8f\xee\xbb\xdf\xb5\xff\xda\n\x9cW6\xef\xdb\xc7z\x86\xb3\x17f:\xd6\xfb\xea\xb2(\x0e\xfb\xdfv\x1b\xafZ.^}\x0f\xaf\x94\xf5\xf2\xb0+\x15\xcf\xf8\xf3n?\xcc8\xfe\xf0\xdb\xee\xf3\x82\xcf\xad\x1bub\xce\xfa\x17\xe1\xb0\x1f>\xea\x0e`\xc5:z\xdcy|\x85\x8f\x0f\x0e\xba\xe3Z\x8364\xdb\x92u\xdf\xcb\xdfu\xc3\xb9\xf6n3\x17\xaa\x03\xdb\xfe\xc3'\xddQ\x9d\xf3\xee\xbb\xd3\xb9n\x1c\xdb\x92~\x00\xe4N\xe5\x13\x8cQ\xa6\x8b\x1f\xdc\xaa\xf6 \x8e\xba\x9e\xd2\xa7p\x04O\xda\x8f\x9e\xd3Z\x9dj\x97\xc68\xde\xcf\x8c&h\xcc4L&\xcf\xa2\xbb\xf6\x14\x1fu\x93qMZ)\xc8\xba\xac\xae\xce:\xec\xad\xb9Sz\xb6\xca\xa0\x80\x8c\x84\xabO\xfck\x96\x8ew\xd8\xfa\xec\x9d\xd8n!\xf2\xa4\xdd\xbe\x90\x96\xb7\xa9\x06%O\x8b\xa8\x9f5\xdbtv\xc6\xe6\xe8=\xec.\xd1\x14\xf2\x03\x8e\xc0C/~\x16\x8ck\xc2L\x155w$1\x1cC\x0c\x13\x88\xbb\xf6x1\x9a\xe2\x05\xa1T\x95\xd5\xc9\x9a\xf4\xaet{\x13\xa6\xfb~\xd5\x89\xf3@\xc1\x94\x85<6\x01w\xa9D\x07\x98n\xf8\xa8DU\xcd\xd1\xfe\xe8Q\x95`\xc8\x81s\x16\xbdC1\xa0\x88\xcek\x0eD\x1e\x0e\x89e\x87\xffQ\x8d\x88\xf0*\xabsLa\xbd\xc1\x85\"\xb8P\xd9\xb0\xb5\xe4\x07eUuKJ\xc9\xe3:B\xe0\xbe'\xb3<\x9b%)\xf9P\xc6Y\x153\xfeuI\xeawy\x9e\x92\xb9\xbf\x83\xcc\xc1,\xdaT\xe49\x9e\xe6|\x01;\xb3\xce\xa3\x82\x94T\x02\xf5\xdf \xb1\x11\xe4|\x10\xe1`\x7f%I \xe5)\xf2\xe1i\xbd6\xe9\x8d\xf0*d/\x84U\xb4\xc94\xeb\x86\xd6D\x9d\xed)\xf8\xec\x9e\xf4\x15<\x85\xbaI\xfb\xf74\x80\x9a\xab\x81\xf0\xb7\xaf\xbc\x1b\x1e\xec+\xb3\xa5\xf0\xb3\xf1\x96\xc2U\xa4\xcbj\xae\xf3Q\x13f%t\xe9>\x7f\x86\x9d,:_\xe5\x15\xbf\xdb\x18cC\xfc\xb3\x91\xf4\xec\xf8;\xdc\xdeU\x02u\x07\xfd\xde$\x1f)\x9f\x9dj\x9e=\x1f\x06\xdc\x1b3\xe0\x1c$U\x0e^=\x9b\xce.\x88\xef\xdd\x1b\x0fN\xdc\x06mX\xf20{\xfd\x9bW\x93e-\xbb\xf6\xc2\x16\x9e\xe7Y\x1d'\x19)_e\x8b\xbcO\x05z\x07\x83\xf8\x8bN\xf1}\xffl{a\xb3\x88\xc7\x08R%^\xbe\xc2\x11\xbc\xefZ\xa95\xc3}\xa1\xf8(%U;\x88\n\x0f\xe7\xf9\xa2\x15\xd9\x06\xe3\x11\x0d\xf4.\xe6N\x07\xa0\x10\xfdfn\xb4A\xde\xd3\x87\x1e1T#\x82\xd2\xb9\xff\xd8\x93\x8c;\xdfL\xe0E\x87\xeb\x10A\x11\xaa\x1fn\x18\x01B(L\xe0\xb2\xc3\xd4a\xa2\xd4\xd7y\x96\xd4\xb9K\xc4\xc7\xae\x84\xd1\x112\xcf\xd9\xbd8\xedl\xc0\xd2U\x7f\xe8B\x03\xb6\x1f\xa3\xd6\xb8\xfc2\xb4\xab\xaf\xaf\"\x92\xfdcC6\x82T\x8b\x00\x19\x92x\x86L\x08\x95\xf5\x9e\xc7iz\x11\xcf.\xd5\x8a\xb9F~\xa2\x87\xd8\xe0\x9c\x196\xbc!\xd7\xd6ik\xe7\xfc3\xcf\x19R\xfa\xde\xe1w^\x10\xc2&\"Y\xb5)\x89\x92\x14\x97\x03\x02\x93J\xf77\xab\x10=1\xde<\xc6\x13\xee\xd6XG\x17T`!sf\x0dQ\xf9\x1f\xd0\xacY\x8cJ\xdf$\x0b\x8c+1\x89o$#\xad\xb8\x9c\xc6g\xf4\x8bp8\n\x07\x83\xd6\xe9\xe6\xa2. \x9e\xf2\x92(8C\xacc\xc6\x82\\`\x11\xadbT\xaerH>\xa6\x90\xfcQ0\x1f\xba\xee\xd4N\x1c\xd6\xf7\x8bF|\x15]\xc5i\x82&#\x1c\xeb\xfc<\xe4|\xde\x8b\xb7\xaf9A\x11\x96\xec\xad0C\x0dr<\xf1B\x93\xad\x8c\x07\x94\xaa\x93\x18\x83\xa3\x15qU%\xd9\x12b`\x95!M. \xfca\x9e\\\xfd!\xc4\x97\x80\xfdr=\x85\xe8\x07\xdf\x07\x90\x97\xf0\xfd<\xb9\x82\x07\x7f\x8a\xd0-DL\xd0\xb1\xc7YJ\xdb\xc7\x0e_\xe6\xf9@w/\xf3\x9cu\xf62\xcfEg\x99\x1a\x03Z\x89U\xc6\xf9f\xec\xf5\xc3*\xa9`\x1d\xdf\xc0\x05\x81Y\xbc\xa9\x98W\xcd&K\xf0\x02!\xc9\xb38Mo \xcd\xe39\x1dP}\x9dC\x92\xcdIA\xe1\x9b\xd50\xcb\x8b\x84Tt\xc8lL\xdc\x07\xc7\xb0\xa5\x98\x9fX\xdc\x19\xf9\x0b\xd3m\x1bR\xf8 h\xe2\x9ci:\xb0\x9a\x9fRq\xbb\xe0n\xa7\x06\x05\x122H\xe7E\x99\xcfHU!o\xc6\xc3\x99\xfaUt>c\x7f\x1a\x15B\xf4\xeb\xa5~\xe2T\x92\x7f\xe3\xeb\xf2d`\x12\x8c\xa1QSa?\x1d\x12{\x0cSY\x80\x7f\xee\xcf\xd8\x15\x80Y\x07L{X\xb0\x1e\xfaB\x05\xe5\xde7\x17i2\x93\xf1\xbb-\x96)sa,k=[\xd4\x9237\xf3\x85\xf9\"\x14@\xab\xa1\x17E\x9eq\xba\xc3\xd2O1\xac@\x82\xa4d\x1e\x84\xb0\xd0\xb6\xa3\xbfk\xfd\xb1'\x07<\xc3\xd8xvS\x0e\xe0\xc0]!\x1f\x99\x19\x00\xb7\xa6\x12\"r\x84;o}\x93\x82\xfd\x06\x8e\xe0\x95\xb1\x89\x0b*\x82a\x13)\xfe\xab C\x00\\9\"\x89w\xf7d\xa5\"a\x16\xc2E\x08I\xe0\x88\x08\xc6C\x8b\x1bK\xe3\x92^\x07!\\\xdb\x8f.\xb7\xfb\xfcf\x95\x07N Ud\x1c\xce\x08\xa2_X\xdb%\xd6\xcf\xcd\x81\xf8p\xcfD\xe6j\xdc\xed:\"\x83\x8e\x0c\xc6T\xb5\xaf\xd0n{_Q\x96\x7f\xe0\x01\x020\xd4D\xa3\x9191\xd0/!V\xed; '\xaf\xcb\xddc/\xa7u\x8f/9\x0b\xfb\\\xcek\xa1;@\xeb\x98\x9e\xb7n\xeb\xa7F\xf7\xa0;\xde\x93\x10b\x1dD(\xac\x14N\x8e\xb9\xa5\x0d\x86c\xdd\xe0^\x1b\n\xee3\x8ffq\xf6\x9el*\x9e\x19\x8a\x8eb\xd3\xc92C\xc5\x0b2\x8bg+\xc2v:\xad\xa1oQP\xf6M[_6\x8f\x9e\xff\xf9\xe4\xf9\xff:\xfd\xe95\xaa\x16\x99\xf6Q\xdf\xc2\xa6\x97\x93c\xc4\xc7\xe2t\xd8D\xf9\xa6&\xe5\x9f?\xbc\xfe\xd1\xd4Ke\x1b_\x08\xdd\xa8\xbc\xa2\x88\x13b \xb5Q\xe1\xe2Y\xaf\x16\xe9\xba\x90\xa9\x97O\xe2\xce)\x94\x9e\x94A\xa8\xfaWf\xcc\xb1r\xb0e\x10\x8c\x80H\xf5\\\x06\x9c\xe1\x91\xbf\xe5j\x1b\x1c\xec\x85P\xc0.\x1c\xec\xa1S\xf4\xc7\x0c\xfc\x8a\x94W\xa4d\xd5g\xe6\xea\xfa\x99\xe9tWtg\x1dx!h\xaee\xfb4\x03\xb5K\x86F\x0e\x19\xaf\xdd\xd3\xef\x19P\x81\x07\x98r\xd5\x90\xe9'\x94GIV\x91\xb2\xfeP\x12\xc2\x1c\x1b}F\x9d\xe81`\xe4\xd3.X\n\x80P\xb3\xd3kE\xab>\xf2:\xefG|\xfa\x85\xf7O\x87\x8f\xbe\x0d\xf4\xcd\x9b\x8f\xa5\xc6\x0fH\x03$TM*\x1a\xe37|\xed\x98\x95@\xd9DS}\x1a\xa01\x8fN\xb9l\xd0A\xb1\x060\x00\xeb\xb1\xf6;\x98\xc8Z,\xe4+\xcf\xeb\xd7\xb3\xf8\xfb\x82\xab\xbb::?'\xd5\xeb|\xbeI\x89F\xcd\xc3C\xb2f~\xf7\xea\x0d\xc3\xe7b\xbc|4\x7f)\xd5f\x8e\xa1\xd4Z\xd8\xcd\x859\\\xdb\xb4\xeeV\x1d\x0d\xaf\x83r>\xff;\xaaVqA:f\xd3t\xe7\xce\xca\xe4\x82L\x94\x8at\xfa\xa8\xc2\xfa\xc7&)\xc9\xbc=\xe2yR\x15\xf4,v\xfe\x80\xf9\x94\xd5C=4+\x10\xdc\xe1\x12\x84-8\x98\x11W\x7f\x0b\xcd\xaf<\xc0\x14\x16I\\\x89\x90\xb2\xccK\xf5\x8e\x04\x1f\xf4\xb8.\xfd\xddt\xbd*\xf3k\x8c\x80t\xc2\xbfj/\xa9\xde\xbc\xdb O\x95\xcb\xe4\xc7\xdd\x1bJ~\x9b\xdc\xb3S\x14\xa9\xae\xba7\xa41\xaf\xdf\xc5\xde\x0d\x7f\xdem\xbf\xe2\xcf\xbb\x17\xc0\xfc\"\xb9\x97^\x80_$\xf7\xd2\x0b,\xf8\xf3\xee\xc5/\xbbH>x\xa2\xbbH\xce\xfc\xc3\xc7\xddy\xb1\xfb\xe3\xfd\xc3n\xfbW\xbc\xfd\xee\xb5\xfa\x9a_\xabw\xdbY\xf2\xe7\xddy\xb1\x1b\xe4\xde=\xf4\x05\x07\x7fw\xba\xe7\xbc\x99\xeep\xae\xf9\xf05W\xc4\xb4zw\x94\x9f\xf0y\xef\xda\xfa\xb4\xafN\x7f\x0eG\xddh\xda\x97p\x04\x0f\xdb\x8f\x9eQN@\x04\x00|V.\xf1\x12\xa9:\xebD\x18|\xab\xd6\x12\xa1\xeb\xba\x95\xde\xa9\x950\xf4n\\\xe7\xa5\xa9\xf6\x07\xb5\xb6\x88<\xd8\xae\xf2\x9a\xdfb\xcb\xdf\xd3gg\x94g\x9b*\x03.\xe3\x9b3O\xf7\xf4\x87\xcdbA\xca\xde\xbb\x17q\x1d\xff5!\xd7\xbd\x17<\xc7\x87\xee\x03\xd2{\xf82\xcd\xe3\xfa\xf0@\xdf=\xbe|\xf4P\xff\xf2UV?6\xbe\xd9\x7fd|e\xea\xecu\\\xf4\x9e1\x17\x14\xf1\xf8C\xe7-\x8b \xd8\xfb\xe8\x94\xd4\xfdg\xc8\xdf\xf5\x1f\xdf\xac/\xf2\xb4\xf7\xf8\xa7\xc487|\xf5<\x8d\xd7\x05\x99\x9bk\x98\xa6O\xdf\xb5\xe6O\xc9\xbc\xf2\x1e\xc9\xa8\xf8\xeam\xe7\xe3\xbf\x91\xf8R\x02ig?\xd4262,\xef\xab\x10~\x0e\xe1M\x08\xefu\xb7w/B\xbc\xbb\xc9\xe0\x1e\x9c\xf6\x99\xeb\x9f\xf8\xab\xe7\xfdW\xff\xe0\xaf.\xdb\xe7\x03ei_\xe1%\xee\x0b*\xb5\xc31\xbc\xa2\xe3\x90#\x98\xd0\xdfA\x10\xaa\xda\xd3\x17R\x84x\xd1ol\xe7Z\xcd[\xdaa\x9e\xe8\x0c^\xe2\xbdBWJ\xa5\x9f\xbe4\x89\xc1thW~M%\xee\x1fe\xd3\x18\xd5\xf7E\xf7\xe02\xc4\xbf\xa5\x1d\xff\x13\x8e`E[\xe9\xbd\xa5\xe5\x078\xa25\x8e\xe0-\x15\xb8\xf1\xafwz\x05\xc6\x85:\xc1\x8a\x8e\xe2G\x83\xaa\x03[\xf9 \xdb{F\xff\xfa\x01\xb5ToLr\x81\x98\xeeO\xac\xee1\xfcr\x0b\x13Xv'\xff\x13\x1c\xc3\x82v\xbd\xf1_0\x1d\xe7\x04f\xf4w\xcc\x7f\xf7\x1a7\x82F\xf4\xba\xf3z\xfa\xcf3\xd9\xc1\x1b\xee/\xfb\x8bA\xefH\xc7\xb8\xa6\x1d\xfe\x93N\xbf\xdf\xdb\xef\xcc\xbf\xde\xa3\x0d\xde{`!\x18\xcb\xa0\x8f\"\x7f\x85#x\x8f\x9aj\x1d\x9a\xfcU\x0e\xf2\xaf\xfd\x97\xef16#bF\x88~\xed\x0d*\xca\x08`\x92}\xe9\xd9t\x00\xde\xdcbXC\xbf\x14\xbb\xb1D&\xe7}\xd7\x12<\x08u\xe8\x7fn\xeb\xd2p\x9f\xf3\x02\xc7\x9d\x87\xa0t\x9c\xbbvLa\xf6g8\x82\x7f\xc01b\xc6\x1c&P\xc0\x04\xff\xbe$7\xd5\xab\x0c\x03\xe2\xf6:\xfd\x1b\x1c\xc1K8\x16{{\x02\x7f\xee\x01\\h5\xfd\xbf\xd1U\xab\x15\xde\xcf4\x93\xbf!5)1\xc6\x13z\xe8\x9e\xa1%\xfd\x0b\x9c\x8f\xdb\xec\xe4\x93\x91\x1c\xe7\xc1\x93.\x87$8N}\"\xaa\xef\x1e\x8f\x9669<\x12\xe6u\x81W~;\x18Z\xbc\x95\xeb`\xe4\xb8\xf7\x1f\x1b\x92\xc2\x1ety2\xce)?\xd6g\x85=x\xd2}\xbei\xc2\xf62\x0f[\x11A\x97\x1d\xa0\x15%#\x83\n\xdfV\x94\x8d\xe9\x19\x8b\xb2\x81\xce[\x14\x04<\xcc\xc6\xb0{{{}a\x02\xb1\x1e\xe8N\x06\xc1\xeab\xeb\x81v\xd8cX\xb9{\xd4\xf6\xab\x8d\xcb\x9c\xb4\xaeuG\xae\xf0\xe3\xc7z\xcc<\xec\xc9H|\xb0\x8f\x0f\xb7\x1dl\xe2+\xa9\xa0\x99\xc9\x18&\xec\xf7\xbe`\xf0]4\xcc\xa5\xde2\xfed\x1b\xa6\xfeF\xa3Q\xa3@\xaeZi\xd7\xa8L\xe1Z\xc6\xfb\xb0\x0f\x13\xc0\xe0\xfd}\xe2e\xbdc\x93\xa8KA\x1a\x0b\xb9\x82\xc5\xfd\xbc\xbf\xcf\xaebs?i:c\x1d\xa1\x14\xc9\x82\xf7o\x82\xa7\xb0\xbb\x1b\xc3\xf7\xb0y\x1a@\xc5\xcd\x11\xa65\xecB|\xa6?\x17Y\xe3\xfawr@\xa9\xec\x816\xb5/{\xa9\x9f\x06\x90\x8a^L=\x08\xf6\x87\x05\x0c\xcd\xfc\nS\x8a\x11\x96S3\x04\x9d\xdeo\xfb\x85\xefn%a\x0f\xbe\x1f\xf8\xa5\x01A\xbf\xc0\xf7\x91S*\xa6\x15i\x12\xab\x87\xe05*\x16\xaf{Y\xce\xb3\xd3*w1\xb7\x81A\x05c@B\x0d\xd5\xcbzZ\xae\xa6\xf5\xa7=H\x99\xf7$\xea\xe2\xd9\x0dV3\x05\xc9\x1f\x90\xfe1^w\x04N\xd1\x884M\xe9/\xafr\x9b\xc0\xbc^,q\xdayTs\\\x11\xb4\xdedQ}\xc94;3\xd8\xdb)\xb0\xa4k\xd9\x80\xc2\xcf\xfc\xfd'\x07\xc1\x17h\xcf\xbe\xf6\x92\x1bM \xf54\x03\xc3\x88\x18\xbd\xa4\x92l\x91k3\x87\xd1\x92\xe6Km\xee0\xc0\x94\xb5e6\x81C\xfdKT\xdcM\xe0a\xef\xa5\xc659\xb3\x1ao\x82\xb2nSrF\xb9\xb6\xfb\x9a\xfb\xd0~\xd3\xccOs\x96g\x8bdYEi\xbeDs\xc0~=F\x02J5\xdb\x00\xa8f\xa7\x89\x8d\x91`\x97Z\x92 \xcb[\xafDR\xc5\x12\xfe\x04\xfb\xa8\x87f'\x00\xa5\xca\x94\xb0\xee?\x05J&\xcb\xa7\x10\xef\xee\x06\x94F\xd2\ngjkZ\xb2\x89\xa0\xfa\xd3\x91\x12\x92\x95+M\x83)9\x8b\xe2\xa2H\x11\xe5\x06\x0d\xda\xc5\xe9\x1a\xd1\xb5D\xfd6&)f\x17\xee\x1e}\x88\xf7\xb3\\/\xdb}\x8fOY\x05\x8aD\xbd\xf7\xf4!{\x8d\x18\xd8{\x8fO=\xad[>^Vc\x0e\xa8\xca\xe4\x17\x8f\xa8\x99\xf4\x91\xc00]\xa7S\xc2\x9a\x07\x8e21]M\xe3\xd7\xb9vpc\x8f\xc4\xc6\x978\xae\xa5u\xfa\xb3\xc0\xc0`\x90\xce}\xc4:\xbe$\x7f\xae\xeb\xc2\xa7\xc4\x97\xbc\xa4\xaf)Y*\xf2\xaa\xc6\x1f\x06\xd5\xc3\xc5&I\xe7\xef\xc9?6\xa4\xaa\xd5\xe6\xd4\xe7\x06\xd2\xc1r{\xab\x1f\xf1G\xfa\xfa%\xa9\xf2\xf4\xaaU\x9f?\x1a\xac\xcfMM4\x9f\xf17\xfa\xaf+R&q\x9a\xfc\x93\xbc'\x95\xfa\xad\xfa\\\xffe^\xbc\x9a\xab_\xacHZ\x90\xb2\x8a\xe8\xf3\xbbEc7\xdc\x91\xc4\xad\xd6\xeb\x0c\xf0\x84\x9e\x96\x8d\xfa\x84\xfe\x10-\xf7\xe9\xd1\x15w\x1d\xa1\xb5\x8cGQ2\x81\xd2p\xd2\x98\xa3\xe3\xf2.'\xba\xa8<\x1aM\x8e\xe0C\xe8h\x91+\xc8\xc5\xa0Q>W~\xa1\x97N\x94r\xcd\xa7|a\x00=\xf0If\x1anF2\x15k\xceNDx\x0d\x83\xe7wGp\xd0\xb9\xdd\x00^\xb9\xe5\x9c\x7f\xf9\xfc\xd9\xc0A\xb0\xaf\xf5\x90e\xfb\x7fS\xc6\x17)\x19\x00e\xb6Y\x13Q\xc7\xc0\x10,I\x8f.\x01h\x82\x10C\x1d\xd9On\x01\xb0\x1e\xbf\xa8\n\xe9\x96#\x9f\x88-\xd3\x1f\x138Dl\x11\xad\x8c\xc0\x9d:\x9a\xfbY\x08^\xcc\xfd\x8a\xb3\xfe\xd4s\x17\xfb\x18\xde\x9c+\xef\xdaO\xbdRG\x05KL\x05\xb5_Gt?\x1f\x1c*\"\xaf?\x1d\x1c\x82J\x072\xff\xe1\x81\xf2e8<\xf8\xce\x97\xdfn\xfbek\xb4\xe3\xbe\xdc\xba\xcf\xc3\xc3\xc7\xe6O5R{\xfb\xd0o\xbd\x92$\xb2\xd4c\xb7@-\x0dr\x13c@\x1fy\xf6\xdb\x93T\xea\x07\x93\x1b\xf1M\xec\xb6.\x1f\n\x7f\x82\x83\x8e\xb5x\xc3\\\x1e\x9c\xc1q\xfb\xe7\xc4\x98\n\x8d\xb29\xbe\xa6\xf5Cc\xeb\x87\xed\xd6\x0f\xcfP\xff\x1eDW\x07o\x0bRbL\x9aWh^\x12\xd7 \xc6/\xb9y\x9d\xcf5\x1e\x9f*\xa8[\xa9\xddTE\x0b&kP,\x10&\xe8\xf87\x13\xf4#\xf0I\x10\xb0(Qy\xd39s\x84U\xd2r}\xac0\xc7\x96\x174\x86a\xab\xf6'\x01L \xe1W[\xfaE\x1e\x9e\x9e\x9e\xbej\xfd\xc5\xcc\x02\xc9@8K\xdd\x12\x8dC\x00\xfb\x12\x99\xc8\xad\xc0A\xbfnG\x84\x80]\xf0\xce1}P+QZ\xb5\xf3\xff\xfd\xfe\x9b\xff\xf1\xf7{\x7f\xf4\x83\xf3\xdd\xa3\xe9/\x1f\xcfn\x9fN\xbe\xff\xd3\xe7\xe8\xe3\x83\xe3\xf0\xe3\xc7?x\xde}\x96<\xed\\g\x99\x0b\x0df\xb0\\\xe8\xcc\xf3\xb0\xb1\xa1\xdbo\xfa\xad\x95~}\xff<\xf8\xe5 \xbc\x0dD\xd3J\xe6\x12\xff<\xf8\xa3@\x80\xe6\x83\xe9\xf9Y\xf0\xc7o\xf8s\xcb\xc6UF\x851X\xe7~M\x87\xd1\x0f\xa4nX\xdc\xd8v\xa0\xf0\x06\xbd\xfb\xfdtL\xa667\xb66+N\x1fw\xf6\x90\x03q\xc6\xc4\xcaDWA\xdc\xc1\xb1\xe0Vb\xcf\xeel\xb3g?\x7f\x86\x1d\x12\x15q\xbd\xaa\xfa\x8du\xaa\xb3jC\xb1-@Qs\xf1\xea\xfd\nR\xb6\xcf!\xc9\xa0\xd4\x9b\xa8*\xeaXZi\x9a\x1b\xa2\xcc\x03\x87\x85\xf7\xee\xd9\xfbg\xafO>\x9c\xbc?e\x83O\xa2:\xff\xa9(laSD\xb9\xe2\x0eg\xb4\xa7ibP\xa6\x8aB;\x8c\x07\xe9el\x83}\x1cX\x87\x04\xd0\x18j\xdbk\x8aR\x15df\x8c\x13\xa6+t\x95XX\xd1\xdc\xfd\xa35\xa9W9\n]-(\xbb7 i\xfed \x9c\xa8Z4:(]\xc1\x0c4\xbe\xc9\x06]-(\x85\xa1W\xb2D\xe8\xcd\xe0Gz\xa7\x97\xfe\x9b\xf6\xaf\xadT\x96\xa0U[b\xe3\x9a\x0bp*g\x95~\xe6\xef?\xee\x06\xff\x00n\xb6\x86o\xbby(\xea(\xa9\xde>;=t\x125\x98.$/H\x16\x17\x89\x91\x89\xe0Y\x15(\xae\x17\x0d\xae\xd3\xc9\x1ez\x1a\x16<\xa9N\xaf\xe3\xe5\x92\x94\x07#\xc6P\xb1O\xb6\x18\xc3\x81n\x0cy\xf1j\xce\x12\xf0\xd7Q2\x7fY\xe6\xebwq\xbdz\x8d\xf8\xcd\xdcI\xeb(%\xcbxv\xf3\xaa\xff6\xa6o\x97\xa4\x96\xc7\xf9\xfb\xf8z\x84\xf8\xc2\xd9[F}\x8f\xd9Ib\xd7\xd7J\xc9/\x12[\xd7\xbc5\x18!f\xbb\xd5\\+\x11\x8b\xcb&\xa1\xdf;x\xe2$\x83'Nb\xa3z\x89\x12\x19i\xc7p\xef%H^\xa2\xf2\x85\x83\x0c\xca4\xf7\x13\x19\xf0\"\xf6\xf9\x1f\x9b\xb3\xa8\xca\xd7\xc4\xb7\x03\x14\xba+\xc2\xee\x16\xb5uu\x91\xd7\x0c\xd9\x10\xd0>>\x9bK\xdc\x80#\xd8\xd0\x87$\x9e\xad\xd4\x87\x15\x8b\x93Q\xaeQ\xcb\xc5w\xc4\x98\x0dQ\x90\x99~mY\x005D/\xb3\xd4\xa1\xb3\xd9\xc1\xb5F\x96\xaf\x8e\xbe\xf9F\x8emn\xba\x8b\x82\xde\x89m\x0c2+\x0e\xda\xccx\xca\"\x9f\xbd\x17\xc2\xa2uZ\x0e\xac\x9d\xc0\x18\xcc\x92\x15\xafIMJ\x0d\xdb!\x8a\x1cgE\xc7\x19\x07\xb0\xe3\xb0\xe7D\x91r\xe0\x948\xf0\x08;\x9did\x0d\xf6{\xb3<\xab\x93lC4\xa9a\xd4r\xc5]qs\x9f9\x7f\x99\x9cqE\xa1\xddj\x83\x02uK9\xad\xa8tB\xffc\x91\xca3\x8a\xc6\xf8\xf4\x08\xa6\x99ev\xc0\x87\x86\x87\xcb\xb4r\xa8M\x076k\x84\xa6\xfd\x00f}{'\x13\xbd\xd4\x15\x12\x9d\x9f\xe7e\xb2L\xb28U\xc4)\xe6\x96\xa1}\x83\x12\x8cBT\xc2\xf6O\x96\xb7\x9f%L\xe7W\xed\xd6\x81\xe8\\\xab\xbbE\x86\x00Td\xc4\xac-\xf4\xba\xcd\x98\x02\xbc\x80#\x98M\xf7\x1c\x00NKa\x84\x91\xe9\x0d\x15P\xda0*:0\xaa\xac=\x9b\x19%\xfb[\xe4\xe5\x9bm\xcc\xce\x18\xeb\xb6\x04\x0e\x9d\xb9%U\x84ZV\x06\xda\xd7-\x92^\\QzQ\x07\xe0\x15e>\xdf\xcc\x08\x1f\xdc\x15\n\x02\xb3<\xab6\xeb\xf6\xb3\x8a\xcc6eR\xdf\x88g\x9f?\x83\xbf\x9a^\x9d\xa1\xb1\xdb\xd5Y\x08s\xb6\xf3V\xba\x0ca\xddB\x01\xb3A\xc6f\xa5\x909v\xa64\xed\xd0\xbf\xb97\xa0\x03\xc8\x80\x83m\xcd\x14\xf5N\xf5\x81{\x18\x98\x14\xe1\xbar\x03G\\Ab\x9f'X3pt\x8b\\\xa0\x8b\x10\x9d\x16(\xd1M\x1b\xa2;\x0f\x9e\xc2\x8eO\xa7\xe8_\xc0\x11\x9cG\x19\xf9T\xfbA\x10\xcd\xf3\x8c\x04O\xf9\xe4]\xc1%\n\xed\x8f\xb2z\x17,\x00\xa8\xdb\xbcD\x91#>\xa1(um'3\xdd\xc2n\x90N\xce\xc6\x8eZ\x94\xde.\xa3\x0c\xcf\xc9\xb6\xad\x01\x87\xc7\xa7\x91h\xa4+\xa7#QKW\x9e\x8fD7]\x19\x87\x82\xba\"\x17\xf92D\xa7\x95\x0eZ^\xd3\xe5\xa3\x98I\xa1\xe6_\xc2\x11<\xebb\xe6'\x8e\x99;\xf6\xab\x981\xe5\x8a\x87\"\xbf\xdc\x06uu\x85bb\x87\xd7v>\xc5mE\xde\x1be\x1e\x81\xb7\x19*p\xc4\\\n\xc4\xbcq\xfe\xd4q\x9d\xac\xb5\xb6\x150n\xfdJ\x0f\x1b\x8d\xf9K\xef\x89<\x89T\x85\x08G\x8e\xceMQ_E\xbb\xe0J\xd8\x87\xdf\xe9T\xb4\x85P\xd1\xf6\x82Z\x03\xf7\x17\xb6k(\xf8\xf0\x98\x07\xa4b\x11\xa1\\\x15rs\x08\x8d\x06\xab\xdf\xe9jL\xa7D\xb9w\xfc\xfb\xc7\xeb\xb3\x07\xcb\x84]\xfe\x0d\x80u\x9c\xe9\xc1\xe3'\x036\x16\xffo\x98\x1e\xdc\xcd\xd5s\x9a\xc7\xf3S\xa3\xc2\xb0\x94\x9c3\xd3R\xd0\xe6\x0d\xe9\xdb\xf5\xc9\xc6\xe4\xdb\xcb \x90(\xbf43\xf2\x9b2\xa5U6e\xca\\\xc5\x8c\x15\xab:\xae7\x15\xe6$\xc1\xbfl5Y\x8aPQ\x9b\xfe2\x7f\xb1\"\xf1\x9c\x94\xd5\x04\x12\x9fD\xfc\x87\x81B\xe8\x1b\x89\xe1\x08r\xf1\xe5\xd4\xe3y\x84\xee\xd3\x9d\xe7\x19\xf4\x10\x1b\xccC\xf9\xf93\x9c\xfb\xb1\xd9\x0f\xca\xdf\xa0kKM>\xb1\xf8\xe5\x17i~\xc1\x14X\x17\xe8'\x1e\x88\xcd\x1c\xd5+\x929(\xb9)\xc9\xceY{hH\x97G\xf3\xb8\x8e\xd9\xdf\x9b\xc0r\x00]\xf5\"\x01;(\xea\x84\xa63.\x8a4\x99\xa1\x02\xe9\xc1\xcf\x15\x8bO\xc1\\w\xfer\xfa\xf6MT\xc4eE|LA\xb4l\x8c>\xe3\x05\xf91\x8f\xe7C\x0c\xf4-\x1d\x85\x0e\x84\xa2\xe4\x98\x01\x01\x8e(\x85\xc8\xa3\xfc\xe2g0j\xf5\x9dX\x83\x9c\x8d\xf5\x84\xdbl\xeb\xb9\x01\xfd\xe9\xc3a\x91\xf7\xa9\x83\x9b\xe1B2\x9cT\xaaO\x19\xf6\x8c\x94a\xafM\x19\xf6\x18e\xd0\xe3\xaa\xce\xbf\x04\x94\xa5\x15\xe3SC\x8e\x10\xa1\xd6e\xf6@:\x1d\xaf\xf9r@ \xba9\xcd\xe8@\x85\xbf \x9a\xfaGI\xc5\x1d\xa1\xa6\xd9Y\x00\xc7\xac\xd2\x04\xa6\xf4\xff\xb3\x10\x7f\n\xb9\x8b\xe2\x93\xf0U\xd1@\x1d\xf1\xb7\x1b,s\xc0ld\xe0\xa4\xd0Gfy\x99\xf0#C\xc4\x89\x13\xcfd\x9c\xd1\xa3\xadl\xaeVm\xfb\x0dS\xe0\x17\x12\x15I\xf1\xa5\x06,\xcdM\xe3,Oy\xd6\x9a\x97\x98\xf0\xcc||\x90(N\xd3\xfc\xfad]\xd47\x18;\xd8|||\xd9\xcc\x8fE\xf2\x1dJ\x1f\xf5WX\xdd\x04@es\xfdb\xc8\xc8\x1f\xfb9\xcb\xdfp\xc1\xa2k\xa8 \xcd\xe5\xd7y\xff\xe3+\x91~'\x9b\xe5s\xf2\xd3\xfbW\x86\x80P\xa0p\x92\xa8\xcdM\xb8j\xe8\xa6\x99]\x1eX\x1dma\xd0\xfc\x16l\x81\x19\x95\xcf;\xf7\xe4:\xee0\x08\xcdW\xbe\xb9m\xa9rfd\xd4\xde\xbf8C\x97G\x18\xfe\x1d\x8e!\x8f\xd6q\xe1'A\xf4s\x9ed\xbe\x17zt\xf3z\xebMZ'\x0c}\xd4J0\xe9\xd4\xd7\x03`V]M\xc0\x0b\x0d\x06\x99\x15\xbe\xfd\x1f\x07{\x86\xf75{\xbf\xf7\xc4\xf0\x9en\xbfj\x02\xdeg\xaf\x0fP\xa4^\x94\xe9\xc0\x14\xd0\x9e\xe7\xb4M\xab\xe1{\xe0\xceU#\xda\x02\xce73U'7Dx\x85\xd1\xd64\x1b\xb8>\xa1\x9bvg\xa7\x8c\xaa\xcb\xa48\xa1\x88\x9ed\xcba\xab\x82\x9c\x87\xeb\xefo\x0bc\x88V\xe0l\x95\x1d\x83EQ9\xf6/\xa2)\xc6^ny\xe2\xbf\x9d6\x82v\xa3Q\x88\"6\xf84\xa1\xc7\xcf\xc6\x8f\x8d\xeeJ\xa2pc\x1fC\x1a\xd2\x10\xf2 \xd4\x05v\x0e)Oo$0\xeb\x86\x9dB\xa90Y\xa0\xe1\x91~\x14l\x85\xcc\x0e\x0eI6Of\x14\xa3u\xf1R\xbb9o`\x00\x8f\xd3\xdf\x8e\x95Aq\xc3*\xf9\x08\xee\xd4\xf3\xd0\x9d\\[=\xc7\xd6\xfe\xb1!\xa5!\x8203\xa9Y\xe4\xe5Z\x7f\xd0\x0c\x86fM\xfb\xfb9 \xc6X\xb3@\x83\x04\xb1\x9fL\xc9\x19;)\x07\x10|`3\x168\x15\x83\x8c\xc3d\x12\xf9\xf29\x7f\xf9\x01_\x9a\xed;P\xe8{\x80\xf4\xbb\x88\xcb\xfa\xe3\x03\n\xa9\xfbT\"y\x90D5\xa9j\xbf\xb0\x9a|\xf08j\xa6\xf8\x9d\x80J\x04.\x01d\xe4\x1a\xe6\xa1\x06\xa8=\xf6\xd4*\xd6\xb06\xa3\xb8(H6gAu\x92i}\x86\xf6\xbdC\x00\xd6om\xa6\xf4\x94\xe3\xac\xfc\xc40\x1d\x1ez\x98\xe1T\x7f\x07j\x91L\x1bq\x058\xf8V\x98)\xb2*\xd2\xa4\xf6\xbdco\x00\x01\xae\xa0g\x0b\xbc\n\xa1\x1b\x8aB-K\xba\x9b\xa6{\x03G ^ O\xf7\x07j\\\xa0=\x86\x19\x85nl\xf8q\x8e\xe9\x96\x04 db\xe6\xcd\x00\xb2t\x90#\xd7 \x87\xeb\xa6\xe3\x8bu>%f%6e\xab.ZCl\xa8\xf4\xf9PFmP\xa9u?\x0b\xa7(&\x8c3\"\xc4\xb5-\x9d\x8d(\xf2fSG\xb0C\x96\x0c\x08\xcfG\x12\xb0l\xbf{O!\x83\xef\x81<\x85lw7\x10bYC\xb8\x87\xac\x8d\x04gRG\x8b$\xadI9~1\xccZ\xfb[\xc1O\xde3\xb9@@\xd3LI\x8f\x84c\x0fv\xf1(\xf7\xfal\x1d \xa3p\x11BE\x99^}{L\xe1u\x04K\xd8\x85\xeb\xb0\xd9\xd4x\x928\xecj\xed\x94\xbe\xb2\xc1q\x08uT\xad\xf2M:\x7f\x91_gi\x1e\xcf\x9f\xa1Z\x8deg%\xe9\xc2p\xdd.\xed\xc3\xfc\xcc?\xe8eK\xa4Eh\xc5\xf7\x86\x94\xe2Z\xa3\xe6\xb9\xd0\xa7\xeb^\xae\x1a\x8b\xe7\xfe\xcb+\xf1Rc\x0f\xad\xba\x1a\x0b\x9b`\xf9\xec\xcf\xec\x8c\x136\xc1l\x07Ri\xf8m\xf9\xbf\xe9\xea K\xce5)\x97\xe4U\x86\xcf\xde\x96\xb4\x02\x1cA\x8ao\xb8\xc3\xb7C\xc0\x1bh\xd6Zz\xdf\xd8\x11\xdf,\x11\xb2]Y\x7fq3\xda\xfa\xb2E\xad\xfb\xad(B\xf2\xeeg\x90a \xbaK\xab\x9b\x03\xaa\x8c\xf5,2\x08\x82\xaa\x01\xbf_\xf2\xc8\xe85\xfe\x95\xf9\xa4\x97\xa8[6\xd1F}Z\xf9\xe0;\x8d\xc5\xfdZ\xa0\xb5\x169\x97\x02\xc5\xbe\xd5\xbd\xbd\x11\xdf\xf6Ru\x02?\xf5\xe4\xae\xd2\x83\xa3\xed(op\xda\xe8\x83a\x02\x9a\xf4\xee\xdd\x1d\xc0\x8f\"\xdbI \x88?=2\xaf\x14S+y\x94\xad\xe3\xf2RRj f\xae\nUL,!\x17Kn\xa0\x97\x01\xf6\x8d2\xc0~[\x06\xd8?\x1b\x08C(Ng9\xcc\xeb2.\x1c\x0f\x14\x16\x82\xfdi\x00\xd5u\xc2T\xc5QQ\x92+\xe4\x8d3\xf2\xc9\xca6\xce\xe2\x8a\xc0\xded\xb0\x0e\x08\xd3,\x93\x10[\xdb\x84X\x91\xc2\x1e5\x02\x14\x96u@O\x1c\x0c6\xbf\x92\x04\xac\xf9\xfb\xf3gL.\xa7\xdd6q\x10\xc2N\x1c\x95,\xa4\x04\xa6)\x9b\x91\xa2\xce\x07w\xb9Z\x18`\xe0\x08\xf6\x1d\x0d\xb1.J\x12_Zk\xda\xef\x87\xe5\xb5$\xef\xff\x11\x9d~\x7f\x1e\xda\xfb\x17\xb5\xe0\x9a=r[3\x12\xd5{\xcc\x1c\x9fdu\x08\xf4\xe7h8=\xf9u\xc1\xc4\x87\x1c;\x00\xe1\x89\x1d\x08,\xe3lmYjlm\xdfa\x1f(\xa7_<$|\xc6&\xe13\x1c\x96/y8+\xce\x81\x19\xbb\x90<\x9a\xb1\x1f~\xb8\x88\x08z\x92,\xec\x1f\x86\xca\x0ex\x14\x82\x8f\xf9\x1eJ\x8c\xed\x82\x071\x06y\xa1O\xcbt\xf8\"\x0b$\xe0\x1c\x90Q\xb2\xab*2\x8aa<\xa1{]=@|\x16\xaf\xd4\xadw\x07,\xa0[A\xed\x1a HU\xe4YE\xbe\x84\x82\x1c|\xf7\xebn\x8d.\x0598d$\xa47\x13\xa3\x0eP\x14\x84\xdc\xc1\xa1\x1b\xe4HT\xef\xb7\x89\xc8\xfexP=\xfauA\xc5\xc7l\xc9\x0f\xc3\xc0\xe0\x82\xbe\x8c\x8c\x18\x9c\xc3Da\xcd}goN\x82\xe5\xd0\x01\x83\x10$.\x1d;n\x04I\x0b\x0e\x9e\xe0b\x1e\xb0\xbb\xb4\xb8\x9e\xad\xfc\xfd\xc3\xc0\x10\xafFW\x9ai\x1c\xda\xa7\x01w\xb8\xba\xcc\xc4\x8b\x8e\xdd\x01.\x87\x0eh\xce\x1a\xf4s\xae\x94c\x19%J\xc5Z#\x08\xf8\x8f\xe7\xf9\x1c\xc3\xc5\xf2\x9fL]\xc5L@ \x97{Q\xde\xc6G\xf5A\xa8\xbb\x99S\x0b\x1b\xa5\x03\xda \x19\x8b\xf2\xcb\xd1\xeb\xf3\xd0\x02'Q\xeev}\xf0\x16\xd1\x0d\x9c\x89\x0e\x9c\x89\x04'}\x1cv\x93\xcfw\x0b\x82\xf1\xe1\x81\x1d\x8c\x92\x8c\xc6\x17\xe5\xa6\xa8}\x8f=\xf0\xc2^ \xefna]X\xf0 +y$\x9b{#\x86R\xd5y1`\"\xa9\x07\xf9-K\x93\x871S\xa7\xc6o\xa7\xf4\xcc?x\xa2\xd7\xf9i\x02\x18\xdc\xea\xd4D|\xa0v\x85t\x03\\\x16\x92\x10\x07'%![(\x8d\xdbnVB\xa125*{\x06%B>\x98\x07\xfe\xcfU\x9e}\xfe\xb4N?\xdf\xc4\xeb\xf43\xa6\x00\xfdx\xf1\x80\xf1\\_|\xb9\xd3\x8d\x10\xb2\xad9\xe1\xc3\xfd\xffxk\xc2\x81\xc1\xb4/1I\xa0\x06Q\xfe\x1eCi\xe2\xd5\x97\xf7\x00\x83\xa0\xe0M\xba]F\x16\xe6\x04\x99`\x02\xddkTS\xe3\xb3\x01\x13)#\xa3\x85\xbaR\xba9\xd8\xbc\x9b\x00\xcfti\xce\x95\xa5\x19GZ5S\x991+g\x9d9\xaa#i]\x0c3\x19\xeeW\xa4\xfc\x0b\x85\xf1\xd2\x8d\xcaiL\x85\x9d\xf1\x19i\x94ua6\xca2\x0db\xee0\x08Q\xb9e&\xeb\xd4\xfaJ\xdf:zAY\xf6\xb8\x88\x9b4x!\xe1\xc5\xf3\xb9\xb0\x8a\xff\xfc\x99\xb2#\xeb\xfc\x8a\xb4\x9f0\x06\xc5\x10\x99\xc6\xb8/;\xc6Z\xa6 ^\x0d\x82\x0f\xa7\xff\xf93\xd0\xb9\"$\xd7\x9b:\x16\x90D\xc9\xfb\xc6\xd1\xd4x=\xd8\xcf\x15o\xdfo\xe0AA\xd7\x07\x80|\x8a\xb7\x16\xbag/\x08)\x9a\xe7n8\xb4t\xc0\xa1\xaf\x8e\xc87Fcl\xb3\x87\x06\x1f\xe1\xa9\xbc\xd6Z\x92\x1aM\xaf\x7f\xb8y\x97'\x19\xa5\x08\xfd\x18\xb8\x00.n\x0f\x82\xbcw\xb2\x86\x86\xda\x88\xd1\xbf3\xff\xbas\xa3\x84\xbe\xecz1t\xeb\x7f\xce_\x1ej\x0d\x06\xae\x87\xec\x10N\xc4\xa7\xda\xdb\xdcO\xe26W\xf7\xf2T|\xaa\xb5~x>d\xc3p)>\xd5:\x0c>\x13o\x1f\xf7\x8d\x18\x9a+\xdc>4\xe3\xf9|2,'\x8b2(3\x81\x90\x9b\xe8>\x1d0\x1c\x1c\x92\x9b@\x91\x9d\xb4\x154\x08\xd6o\x89\x93\x85 $\xbaw\x94\x8a\xde\xe9|9a\xb6Ny\xfb !\xf5\xba\xab1S\xba\xe8\x1a'\x8a8\x899\x19\xca\x86\xa3\xe5\xdc\x06\xdd %\xad\xb7!L\x87\xb6\xa3\x89\x9a\x9b\x0e\x1ae=\xdb\x8a\x0b\xdd\x9a\xdaV\xf1\xaa!\xb6\xe6\x11f\xcc\xeb\xf85\xa9c\x1c\x1d\xa9\x00\x83}\xadI\x8d\xaa\xcd\xb5_3\xd5B\xc7\x8f\\\xd0\xfc\xcf\x9f[xEk^\xe9)\xd7U\xc8\x9b\x15\xe9l\xafl00\x9e\x85\xf5Y\x10\xde\xf1\xc8m\xc0\\v\x0e\xc7a<\xbb\xd0\x83`)A0\x1ee\x14\x06\xe0\xc2\xc8\x00h\x9f\x8a\xdd\xd7{\xa9a\xcf\x8a\xb8$Y\x8d\xa1\xba5<\xda\x10\x83\xd6\xf1\xf0\xac\xed\xf1\xaa\x95\x84\x9aG\x98B\x17\xf1\x95]\x9b0\xbf\x97\x92\xf9\xbd\x18aE\xfbE\x9f\x18\xd4\xc3\xa2s\xb0\xa5O\xf1\xba\xef\xfd\xa3\x01\xc6\"\x8d\xeb\x9ad\x13\xd0\x04}Yl\xd2\xf4\xe6\x8d\x08g\x84s\x1e\xe1;\xbe\xf0g~\xea\x93\xae\xf6\x1a\xf4\xe3\xc8:\xddh<1\x93\xea]\x99\xaf\x93\x8a\x8c\x18D\xc1\xb5\x86s\x9f`,\x14\xa7\xb1p\xcf\xae7\xe4\xda\x117\x86\xe3\xa3\xf0\xa1\xe0}m\xa5U\xb5\x01\xb8\xa8\xdb`\x08\xcf\xc1U\xc4j&\xf7\xaeL\xd6I\x9d8kA\xdcg\xb9\xf9\xcdg\x99T\x7f\xa9\xf2\x8c\xcb`+\xdd\xfb\xe7L\xde\xed\x89i\x16\x84\x92jn!/\x9b\xb4\xdc`\x1a\x18\xefQ\xe3\x1b\x9fT\xaf\xb9&b\x02W\xba\xd7\xcf\xe6s\\\xb0\xa6\xdaZW\xed\x7f\x92\x8c\x94q\x9d\x97#\xe6\xf5\\\x92d\xe5\xfb\x97\xcd\xd7ns\x13\x1fL@\x93P \xa9\x18\xdb=\x81B\xf7\xf2\x84\xe5\xaeu\x1eq+x\n~\xdc\x1fc\xeb \x95\xdf\x15C\x1f\xa9\x0c\xfd\x9dRap#t\xa3\x8e}A\xae\xb4'\xdb~\xba?\x94fm\xf8\xd3'{\x03\x86M\xb6O\xb7\xcebw\xb0\xf7\x9d\xf9\xd3\xff`s*q\xbfw\x07\xfeJz>\x8c\xe5o\xe8;\xae\xe8k\x97\xbcv\xcfF]_\x9d\x850\xb8N\xea\xd5\xf3\x92\xccIV'qZ\xc11xI6K7s\x82&`U\xbc&\xf7Y\x9cx\x8d+\xb6`\x03\xc4z\xdb\x14yd@hB\xe7\xbe\x81Pm\"p\x9d9\xbd&`G]XML\x01\xecX\xf5\x1e\xb0\x8cyTA\x8d\x177,\xfc=\x9b\xd1\xb6&\x9a\xd0g\xc6\xcf\x06\xd2\x1b\xcd\x9a\xe5\x99h\"\x88\x01\x8aw\xaea\xe0@\x95c/\xf2\xb9>x\xa7.\xcb\xc9\xef\xcc\xbf~\x85\xdb\xbdd\xe8\xb2,\x1e\xf0\xe9]\xc7\x97,\xb7\xf2_N\xdf\xbe\x11N\xbd\xb3\x94\xc4\xe5\xf3x\xb6\"6\xbb\xd6**\xd2\xcd2\xc9\xaa\xa8$\x8bJ\xf9\xb0cB|\xeb\x9aQ\x1eT\xc2R\x9b\x17J\x10\x97z\x95\x18\x92\x99\x9c\xa0X\xd8\x19\xe0<\x9f\xe1\xf0X\x14]\x12\x84\xdd\x19,TX\xf8\xd7C\xeae\xddf2\x84;\x01\xd3f\xba0\xe0\x97~JB\x8c\x9a\xb6\x07m\xd0i\n\xeb \x01N\xd5\xb0cI\x81\x931MM\xd3X\x13\xf2>\x08\xf5\xdf\xad\xf5\xdf1\x9cN\x08~\xc7\x8f.$\xec\x85\xb6~\x9c\xa6o\x17A\xd8\x8d\xf9n\x06\xb55k\x9b\xbc\x11\x1a\xa6<\x17qE^\xe4\xb3 \x9clCi\xf8\xf0\x07IfW[\xa1\xe5\xbdE\xa1\x82\xfe\x8b\xa4\x9aQ1$c\xec\xaa\x86\xebmj\xf3\xd5y\x1d\xcf\xca\\\xcb?\x8b\xb2\xce\xe7$\x15\x94\x86W\xefGE\x01\x854\x9e\xbb\xe4E\x86\x8eos\xdc\xac]b\xf4mv\xd5\x1b&\xdb\xb8\x1d\x8b\xf2\xa5\xee\xc7\xa2\xb8\xba!\x8b\"\xcf\x8a\x9e\x07\x87\xc9\x16\xb4[\x98\xeb\xa0[\x8fc\x1c:D\x91#\xb48v\x882\xac\xf2\xe6\x8e\x1e\xe6f\xb4>\x1b\xa283D\x9d\x0f\x9c}8D1(\xd2\xfd\x00&0\xeb%\x13\xb3\x9d\xe6\xa0\x90^\xc2N\x083\x8b9\x94pl1\x1cd\x8bE\x92\xa2{W\xff~\xde\xc4\x8fT(\x8c\xbe\xee\xaa\x1d\xb0\x0b3\x17\x19R\xdc\xb1]\xd2\xa3E\xfa\xcak9\xc66}\xd1\xd7^\xf2\xa6U\xc2\xa5\xaf\x89\xf1\xe3\x9dy\xf9\x0b^\xdb\x91\x97?g\xebr\x99\x14B\x97\x87<\xa7\xbe\xf25\x8b\xe7U\xd7\x1a\x19\x1d\xb8\xc1\x13\x89\xf8Ibd\xfai\xad\x13tc\x0e\xb1E\xbc\xd5\xbe\xa6\xffl\x04\x9d\x0b1fN\xed\x97\x18\x91\xd1\xcck\x8c\xe03\x1cy\x8c\xdb\xc0?\xe1t\xbf\x9b\xfa\xbd\xcfZn8\xf7\xa8\xb5\xb4\xe2\xd2\xfc\xbe\xe6\x15K\xbbY\x19Rnf\xfe\xd6\xba\x83\x83\xbd\xad\x93\xbb?\xd9Z\xfe\xdfZ\xfa\x1f\x18\xabU\xf6W\xdf\xdc\xb9\x10a\xe2\xc8\x0d\xfaOy\xa2\x9b\xd9\x03TAE\xb3\xb8\xa87%9\xad\xe3\xd9\xe5\x872\x9e\x1186\xbd\xe1\x04\x9d\xfe\x1b\xcd\xf2\xac\xaa\xcb\xcd\x0c\xdd\xdf'\xecYEkR^C\xfan\x06\xec\x99\xe5\xaaA\x1fx+k\x05\xde*Y\xe0\xad\x92\x05\xde*ww\x03\xc8\xa6e;\xf0Vi\xe0\xacqpkRU\xf1\x92`\xae\xc6\xbd\xb3\x90\x99\xd0\xd4\xad\x93J\xa7l7\x11\x8c\xac\xb9\x8bW\x9dUC\xf5\x05\xcf\xedC\x8f`\xf5\xa9\x02:\xfai\xd8q\xa8\x1a\xad\xf5\xfb\xed\xf12\xa9^\x96\x84\xa47o\xe25\xb1\xe7w\x90\x86\xe4S\xd2\xf2\xc7\xd1\xae\x1d;\xc4\xa5\x0b\x9d\x91\x80\x97Q\x92\xcd\xc9\xa7\xb7\x0b\xca\xa5\xfc \xee\xefS\xda\x9d\xcb\x87Y\xf30q\x0d=)WZ4BX#}$\xb1\x12e\xf4i\xf2\x1a\xb9K\x17M?\xc7:\xb80 \x1dX\xe5\x85\xa0f5\x0b\xc1\x13\xe7\x05\xfe\x10\xf9\xf8^\xb4\xbf\x98\x89\x90\xb4\xd5\x83j\xb6\"\xeb\xb8\xfb\xb4\xd5\x88\xf2\xbc\xdd\x95\xda\x0c\xef\xe8\x946\xa7\x1f{\x82cg\xfd= \x9f\xe2u\x91\x12\xefl\x0c\xc6v\xc8\xf7\xc3/ \xc3\xadW\xff\x96*X$G\xc6\xedp\x07\n\xda\xfe6B\xf3\x86~03\n\x87\x8cG\xf9\xc3`\xef\x8c\x9c\xed \xc5T\xef3r%\x91>\xb9F\xab\x8f~'\x1d!TP\xdd~E\xb1g\x90r\x97\xa4\xca\xd3+\xe2w\xb5\x82\x96}[G\xf3\xa4\x8a/R\xc6]-\xe2\x19\xc1\x00Q\xdd1\x84\x18]\xfb\x92<+\x92\xeaC\xbc\x94\xd9C\xfd:\xd0G)\x1e\xa2A\xb34!\x99\\\xc1Nt\xb7\xdfL\xcbxh\xd62\xfah\xed\xffm\x80\x91\xe4\x1e\x05\xba\x8a\x82\xa1\xd4\xa7\xf3\xa9\xc4[\xad\xb7A\x8a\xbb\xf9;\x03SY\xfa\xa9!\x8cb\xe6\xef?2\x06Q\\\x0cEP\xd4\x86\xb0[17\xf9'\x86\x00\x8a\x99\xff\xad\x8e#^s\xbe\xb7\x0d\xd8\x1ce\x0d48\x94\x82A\xae\x06CL\xe5\x8f\xe8\"\xc9\xe6~\xb6I\xd3\x90\x7f\x16\xf0X\x1f\x14\x9f1m\xad\xd2\x04\x7f|\xba\xb9\xa8KB\xdf\xce\xd5\xb7\xe4\x13\x99mj\xb4\xd0\x11\x7f\xd3\xc7\x9d\x18\x8fi\xebA\xabB\x13\xf01\xed=\xa4\x15\xdbJd\xe5g\xc82\x85\xb0\xb3\xe1\x87M\x92\xf2f\xae\xa2w\xcf\xde?{}\xf2\xe1\xe4\xfd\xf9\x0f?\xbd\xfa\xf1\xc5\xc9\xfbS\xd3f\x82#Xi_\xd0\x0f.h\x9b\xef\x99\xd4\x84\xed\xaa\x0f\x10r$-X\x9f\xfd\xdd\x90\x17\xaf\xe6\x13Xc\xe2\xfb\xf6\x86\xc0q+-\xc8\xac\xd1\xe2\xf1\xffY\xd8\x17\xfe\x00\x9d\xfc\x98 \xc5\xfe4\x99\x8e\xdao [\x14\xa5\xbd\xcbm\x17o*n\x0d \x84`\x1d(.\xe8y4\x96fe/l\xf4R\xc8\xc3xt\xef{\x83\xbe\xbb\x94\x08WRi\xcf\x02\x88\xd7\x06\xed/\x89Vy\x85\xbe\xba>\xff\xf3\x082\xfc#@ 3I\x80\xbf\x17\xbf\x8e`\xca\xc5\xdcY\x9e\xca\xe8(\xde\x84\x8a\x13^p\x86_^\xc4\x15y\x17\xd7+\xfe\xa9\xfcy\x04T\xba\xb3/\x80\xaa\x03\xc9\xc7\n\xca\x16e\xd3\xde\x80\xd01\xfc\xe9\xfe\x17\x98\xb8l\xadW{\xb2\xf7h\xdbO\x0f\x1fn\xad\x1f{\xb27` \xf4\xef%\x9a\xa9\xbf\xee\x9c\x1bG\x9bdv\x01\x89\xb8I \xd5\xeb\xb8\x18\x08.\x9e\xc3@\x84\xf0d\xc8\x1dX\x1a\x0chu\xbe\x9b![\x83j\xc8W8\x15\xedj\x87$\x82\xa1\x1fj\x9d\x85\x17C\x9e\xc42C\xa86h\xb4\xe0\xe5\x0f\xf6\x86\xdc\x81\x87Y2E\x14\xbd\xf6I@E\xc1\x02\x8d\xb6\xad\xaa\x1a\x11n\xfdP+5\x89x\xeb\xda\x81\x8b8\xda\x87\xda\xb7\"\x8e\xf6Cm\xc3\"\x8e\xf6C\xed2 o\xf0\x87Z\xafm\xe1\x0e\xfeP\xeb\x98\xed\x94\x08A\xb9\x00\x1e<\x80;\xf9\xb5\x98\x98K\x82^.\x12\xf6b\x98\xcdd,\x92g\xf1'\x99\x93\x8b\xcd\xf2GrE(\xe7\x98d\x8b\xdcR_\xde\xfaO-\xael\xac\xe2\x9f\x93\xaa\xce\xcb\x1b\xb3\xd5\x9a(\x8cy\xb07+|s\x1d\xaa\x16\xcc:|.Y:\xdb\x07U\x1dSi\xc46\xd4\xc2\xb5\xbd\xc6\x0c\xc3\xd2\"\xaf\xf8\xa1$d\x82\x9b\xea\xdc,4\xa9\xa5Z\xe5\xd7/\xe8\x02\x9a31\x89\x12\xa7\xa93\x1c\xd8\xd2Q2M\xa5 FY-h\x91&\x17\xafI\xbd\xca\xe7\xd5\xa4\x8b\xab\x9dd0\x14u\x035\x10\xbcu\xdc\x1d\xc6\\\x93RJ\x14\xca\xc1\x04\xfc\x06eI$\xb7w\xbe$5S\x16\xf0\xceE\x05n\xf3\xad\xd6\xe3\x8f\xfa\xd5Wq\xf5~\x93\xc9\xaa\xecg\xbf\xdau\x19\x17\x05\x99\xbfk\xce&\xfaT\x98\xfa\xac\xe3\xc2\x97\xd5X\x1d\xa5\x89@\x84\xe4\x91\xc0\x89\x1a\x13j\xd1\x01\xc7>fD\xd4T\x8c\xe7s\x7fz\x166\x1cp`\xf9\x80\xe3\\\xf3\x11\x7f \xbf\xdb\x14\xf3\xb8&\x1c\xec\xbe\xda\x94\xde\xd2`\xd0\x11\x87\"\xc1\xbcA\x02\x12\xc2\xd4L\xbd.\xc9\xcd\x04<\xa4L\x03h\xc7Y\x03\xbb\xee@\x14\xe4\xef\xe94\x1a\x9a\xc7\x8c\xf5m\x1f\x82z\x9bV\x87Z-1\xbbBc\x17j\x19\xaa\x8c\x8f!\x83\xfb\xb0\x0f\x13\xd8\x0bBd?\xf6\x9fB\x0e\xdfC\xf6\x14\xf2\xdd\xdd\x00\xcai\x8e73\xadK\xb6\xdc\xc1%\x17\xdd\xbfy\x94\x95 J\xf3e\x13\x86Jc\xbd\xa1\x16\xb39\x8b\xc1Fd\xe8\x90a\xcbtE\xca\x8b\xbc\x1a\x8a\x04\xb1\xd5B\xc9v\x99\xf3_{\xd9l\x0d\xc0\xbf\xcf\x82M\xbd)\x06\xce\x84]\xf0\xce(C\x7ff\x8b\xca&\xcaWX\xcb\x86*\x8dYNKx\x05P\x04dAE\\lk\xd4\x827\xb9\x83*\x13Qr\x83\x08\xd0-B\xfa\x99*\xf4\x99\x9ex\x98F\xb8d\xd70h\xf4\xde\xab\x10\xc0\x04t\x04\xda\xc7\xb0m9\xbf\xc9Qk0\xe9G\xc4\xab\xca\xad\xdcu\xb7\\m\x93P[\x14>\xd1\x9d^\x889\xcc\xc5G\xaeHy3\xce\xb1Y-R\x86<\xe2I\x98\x9d\xbe4$\x1bkU\xb1o*\xde\xb7T\xd4tL-K?\x0f\xc1\x988\xb1[0\x16D\x08\xb3\x10\x16!\x14\xe8\x14\xbf\na\x8d\xee\xab7\xf6\xb1\x80n\x85p\x1a\xc2\xf3\x10.Cx\x16\xc2\xdb\x10\xde\xb9A\xbe[,+\x11o;~\xd0\xadL,V&\xdeje\xbae\xdb\x95\xea\x16\xcch\xdd\xa7A\xf9\xa8\x00\x16C%\x96\xf9r\xb6[\xa4nq\x0fk1T\xec!*l\x85\xa5b\xb8$7x\xd3\xbf\x98.T#\x9a;\x07\xde\xc3\xff,\xe0\xf1\x9d\xd7L\x0f\xe3D\xe3\xd9\xe9\xa3>\xf9\x92\xdc \x0d1%.u-,\xe2\xff\x97o\x93f\xa4\x8f\xbfl@\xe0\x96\x11\xc4V\\\x93H\xd9\n\x9a\x89)\x98\x1b\xa2\xe2m1\x9d\x9f\x85\xa8G[H\xab+\xd5l*\x08Q\x8d\xa6>\xc2\x93\x1dC\xa9\xcc\xf1\xcfu\x88\x87B\xa2\x0dD1\x9b\xe6\xd17\xdf\x94dq\xc6\xb2\x95\xee\xec\x85\xa8=\xdb\xd9gf\xbf\"\xed\x91\xa4\x99\xfb\x0fC\xb4\x0d\xee\xb8\xbe\xd0\x9fU\xf3\xd3\x98 \xd3\xb58\xa7C\xb2\x15J\x1c0\xce\xc5'8\x82\x13\xc4\x1d?\x08\xa2y\x9e91r.Eb\xe4\xe1\x7f\x18m\xc0\xe8&p\x04\x9fD\x10\xf9\xe7p\x04\xf9\xf4\xf4,\xc4\xf8\x95\x0b!\xf7\x9c\x06!\x86\xac\xd4\x9c^\xcf\x83\x10\xdeb\x96\x17\xc4\xb2\x10\x06\xd3\xfa\x8e)\xf1\xd8\x84H\xb6\xf2\xaf\x04\xf5\x9dg\xff\x0d&K\x91^W:\xb2\xf6\x16\xe5\xb6\xd9\xf4\xed\x19\xd2\xb4\x80Y\xb8\xa5d\x19\xd7\xe4\xff$$\x9d\xfb\xa5\xcf\xd8\xd6\"\x08\xc1\xab\xf7\xbc\x10\x0e\x1e\xdd\x05\xcdr\xc9\x81e+\x18x\x9aJ{\xa7,d\x0c=\x83\xef\x1c\x1f\x0e-)\xb8\\\xcb\xbf\n>P\xa0\xbd\xc3\xcc\x06\x19\x8b\xd0\x96a$\xbbw\xff\x0d8K\xe9r\x80\x87\xfb\n\x0b\xf8\x1c%\xbcK\xcc\xddZ\xdc\xc5\xfe8tt\x15\x1c*\x82Q\x89\x9b\xf4\x8b_62\xb8CV\xf0\xf0Ny\\\xc7\xcc\xaaC\xe5\xce&v\x07\x94M\xb2\x91\x87\x98\xb3\x153\x0b\xc6\"c\xde\xc3\x80\xf3\x9e{\x8c\xf7\x8c\xadi\x02m\x85\xc9\x1cw \x9b\xcbq?Ty\xe1\x87\xfb!\xec\\P2s\x12\xf1]\xa4\xfc\xddM\xc05\xb68\xa5Hs)\x9426c>\x0ca\xe7\xfc\xce\x89\xe2\xc3;\xd8\x81\xf0/D\x14Y\xde\xbd\xeb/\x9b\x14[\xc1;\xd86\x92D/\x92,\xa9V\xfe\xc3\xc3;\xc1-\x87D\x89\xb6\xd2\x1b\xd9\xde\x9d\x8c\xec\xf1\x97\x8dl\x1b?sS\x913t\xf4?7\x95\xedp\xf26\x84\xd8\x9e\x98\xd0V\xa6Tj\xa7$\x97\x92\xaf\x87\x8f\x1dB\x1a\x9b\xca\x94\xd2\xbc\x10\xa9\xc8\xc3\xef\xdc\xee\x0e\xba\xc5\x10\x15r\xa8\xdc\xb2\xc4\xf1\x9d\x8b\x83\x9b D\x9b+\x0c\xc9\xcb\xcf\x8d\x82\xeb.\xe6\x8a\xeeBj\xe2\x1f\x852f\xac\xa2\xba\xc8uw\xf8\xdd8mc\xf5\x19\x88\x81[`1\xa5\xd5\x18\x84x\x8d\x1e\x02w\xa1\xae(%\x97\xb4\xa5zb;\x9a<\x1e\xdf\xf9N[\xc2\x11\xac\x85\xc6\xa1\xec\x88m7\xfeR\xbcZ\xf28\xa3K)\xc1\xed\xefo\xb3J\xfb[p\xa4\x02\xdd$l\xb7\xd0En\xc1\x97\xb1\xf1n\xc1`\xcaq\x1el\xc1Pn=\xd0-N>\xb9W\xf7\x1fQ\xe8\xb2\xd4\xd3\x9cA|\x14\xf0\xfd\xbd\xc7\xf6w9\x9a?d\x12\xfa\x16\xfc\xa0\x1c\xd6\x81JO\x0e(\xff\xb7\xa0<\xdfJ\xe1\xffV[\xf2\x7f\xce\x99\xc4\xbb\x85%3\x16c\xa2\xfc\xdd\xd6\xf7}\xe5\x97j\x8b~-Z\xc1\xf8\xb3\xf9\xb8An\xad\xa0\x91\xee\x8c\x9c\xcb9\x18\xcb\x7f9\xe73\xef\x96^\xcfc\xf9+\xd6\xf3\xc8\x93\xe8K\xf8'9\xe2\x91\xfc\x92\x1b\x0e\xdc\x86P\x8e\xe7\x87\xa6\x8fB$(t\xf7\x1e\x8ca\x7f\xa6\x07\xc8\xee\xd0Mu\xe0\xc8\xee8\xb07\x16k\x8a[\x9f\x04}\x03\xe2\x9c\x99\x1d\x96\x81\xcd\x8a\x18\xa4=\xe8\x9bxM&\xc0\xa3.|\xfe<\x14~Q\x94V\xe8Y\x95!\x92\x8f\xfd\xdc2\xfa\xd1Q\x8d\xecVN\x94(\x8d\xb6r\xb2\xd1@\xbbw\x9b(\x8aE\xe4\xaam\x16\xdb1\x1eU\xbc?\x9c\xcc\n\xa4\xf7\xd6\x92\xd4\x82\xd3\xac^\xe6%k\xce\xaf\xd5\x8c\xae\xbf\x0d\xd0U\x83\xec;\x84\xbd4\xec\xecX|\xb72\xd8J\xc9K`\xa1\x0c\xb9\xd2\xfb\xcc-u\xa7Z$\xe8q\xe8\x16\xe0~\x05\xe8. \xc7hno?\x02\xb8\xd6\xf9\xa9Q\x13\"\xd9\x11\xa5\x06>\xb1\x1c\x1f\xaa\xd7n\xcb\x1f`Z\xf3\xfc3_\x11\x14\xef7\xd9\xf3|\x93\x0de\xb0\x1a\x0d\x0buB]\x98\xfbDl\xb0\xaf8)\xde\xd7\x87d\xc8 \x7f\xf4\xb4\xf4K\xdc\xcc\xcbm\x951\xe2\xcf\xb4V\xedeX\xf2\xaa\xaf\x08\x0fA\xe7^es\xf2\xe9W\x03\xc9\x87\xa4\xc0\xe4\xcbj\xe7N0\xf2\xb2\xcd\xfa\x82\x94\x1e\xec4\xbe\xd9p\x0c\xf7\xf7\xc1\x94&\x0d\xee\x04Lt\xb7\xde%t$\xbdkX\x83\xbb\x1f=w@\xd8\x96\xae9\xd8\xc8\xb6\xcc\x92\xc7\x916_C\xd4\xb2\xb3\xb6\xbf\x87\xf2\x9c\xa7TG\x1f\x8c\xa1x\x91_\x08+v\x80}E(\x0d\x03\xa5a\xf1\xda\xe9;\xe8f\xe1y&F\x1e\xach\x8d\xd7\x0b\xec\x1f@\xc6\xbd\xcd\x19Dm\x8bE\x0bf\xd8\x19NY\xa1\x16\xb4\x9b\xd0\x1aqKV\x025\x82\x19sK\xf0\xbb+\x00\xde\xff\xcck\x88!\xcb\xb3\xfb,\x0f0\xf3\x1b\xf3Bp\x19-\xf0!d\x91\xf4\xf1b\xb1\x83\x1b?.1\xf5\xb0\xc5Ys\x1e\xcb'2=\x91\xf0\xd5\xec\xb19\xcd\xf7l\"\xad\xf7\x1fV$s\x82+h\x8cM\xd5\\\x1a\x1a\x88U\xd2\xcd\xca'\\\xed&\x86\xbb]\x7f\xe2\x14\xd0\xf4\xc5\x96E\xb2\xc3\xba\xcc\x15\xdd\xe2\x96\x93D-\xfd\x8c\xc7]\xfc\xb463,\xb0~\x0d\x8e\xbc\x03\x991D\xc3\x06\x97v\xe6\xebvL\x16\xb1\xd2hO\xd1qJP^!\x19\xd5\x19\xe3\x88Z\\\xf5\xae\xc8\xb4\xbf\xdc6xdA$q\xba+\xfesM\xe2)\xe6BW\xc75\xc1\xf0\xbev\x14p\x0c\x1ebY\xe1\xe1\x11\xb3\xc0\x14\xd8\xaet\x81mvp3dJ\xa7\xbf\x02\xb2\xb0\\\xc6\xdb\npV\x84iq[]:\xd5\xc4\x07\xb4\x81\xe8{\xd8\x13!n8U\xfeP&d\x0eu\xce\xf3;C\xdc\xf6\n\x86z\x15\xd7\x90T\xd9\x1fj\xa8W\xa4$;\x9e\x0c\xb7\xd9\x1dFU\xa4 \x95\x18C\xd8\xff\n\x00\xee\x11\xdf\xaf\x05^'>\xb5\xd9c\xfc\xafN\x14\x19''!\x11eN\xb7M]\xb6\x154S\xcd\xac\x95m\xfb\x070\xbe\x81\x06\x8d\xd9\xfe\xe9x\xbb\xda\xdc(\x03~\x890\x0e \xee\xfdkB\xa5\xaa\xe5k\x1c\x07\xaa\xd2h\x0c\xee90\x90\x8d\x97\x18\xa0\xe6p/\xd4\x0bBH\xe1\x04\x15h\xa8\x1c\x93'\x05\x95k\x9eW\xb8\x1f-\x01\xd8\xbf\x00\x1c\xcf7eI\xb2\xad\xa0\xe2\x08\x11!w\xe8\xb4u\xfc\x15\x1f\x04\x7f\xfa\x95tG\xfd\xfeG\xccu\x14\xf5\x89\xf4\x92\xbb\x95\xb6\x9b\x00\xe6\xd7\xb0\xfbU\xe8q\x17\xf4#\x00b\x83\x87:\x97\x99\xda\xc7W\x99\x05')o\x17\x1fn\x8aQ:\x80\x11\x1b[\xd8<|\xa5\x8d\xf8cr1b\xe0\x8e\x83F\xf07a+\xee~\xe0\xe7K\xf25t\x8f\x0d\xcb\x8a\xc9\xf1\xdb\xdc\xeaW\x80\xbf\x12\x14\xe3+\xcc\x86m\x82&\xfc \x9d\xd4\x90\xb8\xb4\xf54\xaa\xadf\xe1\xbe\x07z\x13\xa9\xe8D\xbe\xce\xd9\xc4\x83\x8f\x8c\x99\xc8\x98Y\xf44\xe8\xc6\xc3\x08\xfe\x04>;\xd1\xbf\xc6,gi\x9e\x8d\xa2X\x8e\x93\xfc\xcb\xe9\xdb7<@\x1feMsE6\xfd\x1a\xe7\xab\x88\x8d5b&\xb6\x89H\x97lb\x9f4-\x84 \xce-\x81W\x93\xcc\x97k.\xda\xac( a\xfbH\x14\xd09\xfe\xedW\xc6\x99sM\x19\xc0\xba\xb9\xcf\xb5\x19\xc9\xa0R\xcf\xc9\x11_D\x8ck:h\xf1\xec\x0e\xc2\x06\xed+\x97\xda\xa8\xdc1\xb8v\xb7\x88}i\x8a\xb0\xa6+}\xe9\xe4\xeb\xf6f\x87\x85\x88\x96\xed6\n5\xb6+\x9ekN_\x89\x00b\xf8\x1d\xfba\xfd\xce=\xca\x04\x1b\x8d\xaa\x8a\xf5\x13\x11\x0eI\xa0I\xa3\x9a\x0dB\xf5\x9e\x99\x07\xb3M\xbed\x131]0\xbbV@\x9a\x8c\x11C\xd5\xdfx\xd3\x16\xb6\x1f\xb2\x0c\x1e~\xef\x19Rl\xca8k\xea\xff \xf6\xf7\xb4\xd7\xe5\xd6\x98\xbc\xa2\xb0\xf5\xcb\\\x17O,\x9cT\x99r?P\x99\xf4\xc3\xf7\xfeF\xfepE\xa0$\xf1lE\xe6\x10\xc3*.\xe7\x90&\xeb\xa4\x86|A\xc7\xcbMT\xa0\xdcd\x95g\xa3V\x0eD\xa2DW\xb9>\x87.5\x93zK\x03\x97}&\x92\x08i\x9b\x19oy\x00\xe3\xac\x0f\xc0\x01\x00\x00\xd0_\xfe8M\xfd\xcd\x97\x8e\x0fi\xa0\x88\x97\x13\x82\x0cmfm\xe56p\xcdN\xd0-\xdb\x91\xb4/\xd8\xa9\xbc\xc3Q\x03\xcd:Xv\x04\xa5}\x89\xc4\xb9\x9aE\x1a]\x85o \xab'J\x8e\x0dtu-p\x1f\x1cla\xc7]\xa6\x95\xaa\xd9\x97\x0bPD\x11\x87\xc7P&_]\x89\x99\xf1\xfe\xa8o6\x8e\xd1\xa3\xd4\xe2\x0e\x06Qdh\xb2\x8a\x99 w\\\x08J\xbf\x0e\xd9\xaa\xfe\x98\\\xf8A\x10<\x85\x1d\x9fB\xc0\xaf0\xa9A\xcb\x8c\xff)\x87M\x00\xc4\xaf\xf8\xe5\x87\xf3`\xc6\xdft\x89\x12s\xcbi\n0;\xc5\x11\xe5\x16\x16I\x16\xa7\xe9X\x80\x8d\x071-; %\xd7\x85bL]Hc\xeaQ\x8dm;l\x10\xeer\x01\xb70\xde\x8c\xfa\xdc\xcd\x86\x15\x9ck\xde\xb2;p\xd2G0\xeb\xe7\x12Q\xac\xe2\xb0(\xed+Q\x8ck\xeeO-\x91A\x9d\x8cQEa'\xfe\x04\xfaY\xfeu\xe56p\xb1\xa4\x1d\xb9\xceRTj\x99K\x95cf\xd12!2%\xec\xee\x16\x97\xf8i\xd6\x1a\xd2,\xc0\xf1`\xbc\x1dxo\x90\x8d1&}\xef\xd5\xad\xeel:1J\x07%YT\x13X\x0b4\xd1\xd3sL\xa1<\x81\xe5p\xad&\x05\xd7\x04n,Ue\x04\x9c \\\x88\xaa\xfd\xa9\xb4O 5\x0c\xf9u;By\x93ay\\<\xf8\xc3\x87\x03\xf1\xe0\x87?=x\xfc\xdd\xb6\x9f>\xde:\xa5\xe4\xc1\xf6\x91\xef\xf7\xf7\xb6\xfdt\xff\xbb\xed\x13\x04\xec\x7fIF\xca\xd6+\xa9\x94\xf9\x8d\xe2\xed\xeb\x07\x93\x1b\x95\x98,2LT\x93\x8aY5\xe9\x07\x80\xb5jq\x80Q\x99\xecm\xebV\x9d\xe5Z\x8a\xa1$i\\'W\x04~z\xffc\x08\xd7I\xbd\xca75\xac\xe2\xab$[B\x0c\"\x13E\x84Y\xbe'\xf0\x07\x19\xf4\xf4\x0f\xf2\x1d\x7fZ\xe3S].Bh\xa0\xf8\xa9'\x97\xd6Z\xf5w\x9f2\x89ep\x82^b\x84\x9e \x9f\x0c \xcf\xf3M:\x87,\xaf%DJ\xb2 %\xc9f\x04.\xc8,\xa6X\x93/&\x80\xb3\x16\xb92\x11\xc3:c6\x0d$\x1e\xc4)\x1f!\xe9\x05h\xa3P\xfb\xde\xef=\xb7V7\xc6\xe9 \x9b\xbfwS\xa2\x89o\x8b\xda\x084\xe09\xd5\x98\x9eeA0\xc0\xb1 \xab\x80\x14\x99\x90\xe1U\xa6\x0c\xc2E\xc3 ,{\x8b>\xec\xbfr~\xce\x15\xabz\x1eA\x97\x91\xc6\xca\x10\xf3\x91\xa9C\xe1v\x81\xee\xb8W\xf9\xa4+\xce\xda\xfaKM\xf8\xed\xb6\xd0\x95\xbe\x03!B\xeaWY\x88\xcep\x0c\xbae\xae\x038\x86\x1a&\xd0_\x96:\x80 \xf8\xb4U8\x82W,G\xf8_N\xdf\xbe\xe9\xcf\xdb\xc8O\xf2\xcey\x1b\xb5>U`\x88\xef\xdd@\x90Zq}\xa6\xbd\x85f\x9a7.\x17\x7f\x0f\xfbR5V\xf7\xeb\n\xdc>\xed\xde\xd1\xe91\x1d\xcd\x18\x9b\xac\xe4e\x87\xca\xf6\x89J\x91'YMJNG\xe8\x9e\x87yN*\xacC>%U\x0dI\x06\xf3|\x86\xa1\xa9\xb5\xf9Th\x91\xadh\xce\x14\xcd(\xf9t\xbb\xc9\x16\xf5P\x9e\xe9\x11\xad\x95\xfe\xb21\xf9 \xea\x8c?\xdc\x14\x84\xeb\xfbN>\x15dV\xa3\xaa\x8f}\x14\xc2\x12\xadi\xe9\xbcU\x90\xd1\xc3\xd3\xdbd,\xaf\xcc\xdc\x03\x96|\xe0\xaau\xa3c\x9e\x92\xf7\x80Y(\x92\xe9\xde\x99\xbc!!Q\xb5\xb9\xa8\xea\x12s\xc1\x80\xe7\xc9~\xa6g0\xc1\x0cXHb\x1fx\x01\xd3\x86\xb9a\xdfb\x90~\xeb@\xc3\xd9\x82\x13\x89J\x9b\x8cT\xb3\xb8 >\x91\xc9\x9f\x1e\xfc\xd7\xfe\x83e\x88\xb9\x9d\x94g{\xf8\xec\xbf\xbazP\xd3\xd0\x8a\xc1\xa15\xfdkzg\x1d\xed\xa9\xbd\x7f|\xc0\x1e\xee\xbbv?\x1fdP~\xf6\xeb\xc6\xa4wG\xa3\x95\x11\x9b\x97D\xb3U\\>\xab\xfdZ\xda\x0b\xe9\xe9\n\xcb^\x86\xa6C\xf7u\x1e\xfe\xbc/\x8e_j\xdac\x8a!;\x98\xb9^ \x0e\xfb\xf1{\xfe\x03k\xd0_;t3;M~%\xf8\xcc\x10\xb4:1q\x0d\xf5\x01\xef\xc5K\xcdpsL\xf5\x95\xf3\xc0\x15\x1f\xf0\xda\xb9\x0cA\x1b2Sh\xd2\xec\xa7\x0e\xf4\x01\xc1)\xe01\xdd\x12\x13\x84\x00\xb22q\xe1\x17A\x93@Z\xdb\xda\xad\x9f\x19V#\x86#\xf0\xf1\xee\xc2\xfb\xbe*\xc8l\x1d\x17\xf7);\xf8'/\xa0\xd4\xed\xf7\xd8\x89\x9ep\xd6p\x84\xce\xfc\x1d\xdb\x81\xe9Y\x80i\xcf^\xe43\x0cZ\xea'\x98\xca\xd0\x86B\x1b8\x02\xcf3Q\xffq\x19\xadi[\x1b:|\x84Q\x81\xb7\xaa\xf9t\x83$\x86\xfe\xef\xda\x9c\xd2$n\x92\x18c\xb6\xcf\xfd\xd8h\xe8\xa1\xe3h\x86\xe7\x9eO\x13\xbc\"\xc2\xff\xb9\x93\n\xbf\x7f\x89\xbb\xfbW\xfdu\xe7 \xbd\xdaC\xa3Kr5\x94\x93k=\x94Xk9\x98\xb0K\xa6\x82\xd2~{1\x94X\xeb\x9c%\xba\xd5e\xb3\xbd\x16}jSH\x9d\x88>\xb5\xcd~\x1aL\xf2{:\x94\x13\xeb\xb9\x18\xae\x16J\x97B&\xef\xbfz\xc6\xd3\xea\xbf'\xcb\x93O\x85\xef\xfd\xdd\x9f\xc6\xf7\xffy\xb6;y\xf0\xe0\xf3\x83\x07\x81\x17\x82\x97x\x9a\xef\xder}\xf5\xf3\xe6\x8c\xf5(k\xf7\x9e,\xf0\xf0\xf6\xec2\xb4(x\x03&2M\xe2\xc7,_\x7f\x87\xebGk\x00\xe0\x17\x9c:\x04\xef\x0f\xf2\x1d#\x87\xbd\xe7\x1f\xf8\xa4\x07\x94?\xaf\x8d\x8a(f\xcd\xf1MI\x16\x06K\x0e\xa1\x91\xec\xce\xdf@\xdbE\xc1\x8b\x00\xbc\x86a\xa7\xd2^\x08\xda\x83I\x14\x94\xc8i\xad\xcb(\xa9^\x96\x84\xa47o\xe25\x99\x07~e\x0d\xeeN\xfb\xc2\xb4sJ\xf6#?\x93\x14\xd3~1\xaag\xe2\xda\xc20\x05\xd1\x04\xd6\x9b\xaa\x86\x0b\"Y8\xf0)\x9a\xdc\x7fO\x16\x81\x913U\x0bk\xc5\xe1\xfe\x98\x8f}\x02\x0e\xd9A\x16\x1b\xbc\xa3_\xd9,\xcamW\xa4\x14\x8e\x0b8B\xb1\xdc\xdek\x81\xa1\xb7\xf7\x1c\"E`\xd8\xee)\xf3\x9b\xb5en\xa3\xe5\xca\xf1\xbe\xca\xed\x02\x85\xb6\x96\xd2\xae\x0b8\x86\xdc/BH\xa9 gL.+\xca\xb8\xdb\x01\x8e, =-\xec\xb5A\x15X\xe6v\x88\xc0\x18\xd4\x01\x8e>\x0c%\xae\xdc>p\xc5!\xd0\x1f\xc8\xad\xd7V$[6\x91\xc7\xac\x9d\xdd8\"\x03\x12\x90\x95?\x0f\xe1*\x84\n\xcd\xbb\x1c\x16\x029\xa1M\x9aR\xb6\xeb\n\x8e\xc1\xbfA\x91y.\xfc\x07\x19\x9f\xe8/\x05u\xf1o\x02\xc62/9\xd1\x1dV\x93q\x99\xf6_\x06%\\)\n\x8c\xc6\x88\x80\xee\xa9%OhD\xe9(Bh\xe3_\x850\x0f\x82\x88+\xad\xe0\x18\x96\xf2\xef ,\xbb&]N[\x0ddl\xa3\x11\xbb\x0d\xb6\x00/\x8c\x051l\x01f\x18 j\xb0o@\xe0j\xa4\xa5\xc6\xc5\x98\xd3\xa9\xe9\xa9\xa2\xdeZ\xe7W\x84\n3\xb0t\xc8\xfaE\xf7\xefEK\x1b$\xa4\xe4\n\xd3\xdf\xb8-\xc77\x1c\xae\xd6\xca\xb63\x0b\x84\xc6\x89\xee\xca+\x14R\xd3f\x96\x17\xa12N\x91\x1b\xd0\x9acT\x14\xb9\x94W\xd6\xea\xb7\x81\x03\xe8\xdc\xce+\x10\xc4l\x9c\xc5\xb6Z\x84\xfa@\xab\x005\x15iST\xc4\xf5**\xc9|3#\xfe\xd6C\x00\xf52\x96ytNk\xbc:\x9d\xd6nA\xa2h\xc1\x8c\xfd\xee\xfb\x08F$\xa55\x15>hU7\xcc\x9d\xe4\xb9\xb2$S\xb5'\x7f:\x82=\xd4U\xec\x85\xcdmn\xe0\xd7AG\x1cv\xf2\xa4\xd3\x15q\xb1\xe3\xd7\xd3\xcc\xe1\xb2\xbf[\x86\xe2\xf2\xe8\xca\xad_\x8f1\xb7\xb9\xf5K\xe1\xa5q\xd1\x88\xe4\x17\xd6o\xed7\x12\xdd\"p\xc9\xc6\xb5\x81\x95\x011\xbf5\\\xf8\xf7\x9ejd\xb0W\\\x80T$\xbc\xd7&23\xcfg\xcf\xe3\xd9\x8aL\xe0\x9d\x1e\xb5\xe3\x8b*O75I\x167\x13\xc8\xf5uf)\x89K\xde\x8c\x9b\xd2\x85\xf33;\\\xf1;')\xa9 \xbb\x8a\x98t\xf1\xf7\xdd6\x91-\x94\x16\xcd 6\xa8x\xf4\x93TE\xf0 \xbc\xd5W\xba.\xe3\x82\xd7H\xf45\x96\xa4F2n0\xbfG\xdd\xf7\x04b\xfd[\xf2\xa9.\xe3Y\xfd\xb2\xcc\xd7\xd8\xc8F_M\xde\x06\xb9.\x87r\x19x\xce\xee\x920\x81\xec0\x88W$\x9e\xa3\xa1\x87}\xd3<\x9b\xcdHQO\xc0\x8b\x8b\"Mfh\x8f\xf3\xe0\xe7*\xcfBP\x9f\xdc\xc4\xeb\xd4\x1b\xde/\xc3\xf47\xcd\xe3\xf9)\xdaF\xef\x98\xe3\xaf\xdd:\xdf\x0c\x8a\"\xe8^\x84G\xf6\x80\x91\xce\xb6-_K\x02_\xc5\x0b\xf2c\x1e\xcf\x07=\xb4F\xe1-\xc7\x19#\x0fH\x97\xe1\x1dcF?\xe4\xe8\xa42\x81\x99\xbe\xaa\xb8\x1f\xf9\x8b\xfa\xc9%\xc9&\xb0\xe8\xd3\xa5\xa0k\xb9\xc3\xa7\x08G\xf0\xaa\xaf\x8a\xfc\xd9\xaa4\x17*V\xa2^\x0f\x10\xf5z\xa0cp\xd0\xeeD5J\xa9{\xe6FcMZ\x1enm\x0ds\xf0\xed\xf6\x9f>\xfa\x02C\x1a\xf5\xcd\xaf\xa0Z.\xad\xeb \xdb\x1a\xec\xc0\xb0\xd1\x0e\xe8\x8fI\x93\xc29\x17\n\\3\xba\xf6\x87\xc1\x14\x95h\x12\xa7Q!\x99\xb5\x94 ^1\xe8\xa7\x85lv\x1c\xadI\x1dS\xa4\xe6\x7f\xb24\\6\xe5\xe6f\x1b\xe5f\xdeUnn\xacZ\nf\xd0\xd4Isk\xfb\x08T\x0dl\xfb\x16\x1a!\xd8\xe813\x88i\x9b&\xc3$\xb5\x08;\x8fH\x88\xabL\xb1m\x89\x003\xf8Vhn],\xdag\x98\xee\x04\xb7\xc3\xf0X7[\xf0.\x80\x1d`B,8\x82Y\xcf\xfe\xa2[\xa8x\xcd\xf8\x1d\xfc\xc0\xdfca\xd89\xfb\xf4\xcbm\x08\xb3 \x88\x10\xd6n:\xd7i\"\xe5\xe8M\x08\xbf\xdc\x062c6\xe9\xf8\xa78\nb\x887I;\xc4\x97\xfd+\xe0_624\xe5\xb8\xed\xb8A\x0b.\xa4\xa3\x8b\x81\xa0W]\x13\x89\x94`\xfeqH2h#*\x8b\xbdT\xb9\xe0)(\xe6\x1d\x1d\\\xb5\x9bU;\x9b\x18'\xd1\x9a\x94K\xf2\x82\x90\x82\xae\x98E`\xba\xb5\xc5n\xe2\xad.\x98\xac\xdci|\x16\x04!\xcc\x18]\xa2\x84J\xd6\xe2\xba\x9b\xa9D\x96M\x08\x1eV\xf3\x02\xfaM\x9fG\x10\xc5Y\xd6i=\xc1XTc\x0eu\xeb\x19\xd9z%e\xf7\xdf\xc8\xd8T\xfd\xf5+\x1c\xd8\xf9\xd0\xadl\xd2\\\x90\x8e?&\x1b\x9b\xf0Qgei9+{\xd9\xd6q\x1d\xec^\x82\xe2\xbc\xec8\xa6O\xcf\xec\xea\x9d\xfe\x1d\xa2E\x1c\xe9wC\xa9q\xd2\xb1]+\xa3\xaa \xb3\x10\xaa\xa1})e\x90\xfey\xe2@\x84\xdd\xb4}\x9bi}\xa6,h\x19\xc9\xa5{\x1d\xcf\xca\xdcO\xed\xa4e\x94.E\xe0]\xe3\x87j\x0bR\x03\x0d$\xf2\x0e9\x1dv\xec\x18P\xb4\x04\xea\x8a\x88s/\x0bac\x10\xb3\xb4O%!\xd64d5\\\xfdoJ\xf6oB\xc9\x9a\xa4\xcd\xa3(\x99i/\xd0\xd1\xc6z\x1aa\xda\x08\xd2\xb1qC\xd9\x122d\x06NK<\xdd\xb4w\xf4:\x9f\x93T\xc0\x9d\xedjZ\xc7\x80\xeaN\xbbY\xe5\xed\xed\xbbx\x14\xe3>~\xaf\xc5\xff\x8f\xef5\xfd`\xcc.*\xd2T@\xdf\xf3l\x95\xa4\xf3\x92d\x13]\x8cq\x16e\xb0v3BM\x86l\x95\xe4\xe1&b\"\xca`\x0b$*\xca\xbc\xce\xff\xca\x9fgp\x8c\xbbe\xd3\xde-\x99R\xab\x89P\x8a\xc6\xc4W\xec\x99\xbf\xa7\x04\x8c\x08|\x12\x89\x99i\x94\xcb\xc6\xd3T\xb5\x84e_Ok\xc3\xa5V\xab\n\x1cAB\x913\x13\xa3\xd1\xba\x19t=\xf9~u\xc2\x19\x0fY\xfcm\xf8\xcbC\xdd\xcbJ\x98\xd7i-\xe8RA\x90\xb5\x0d\xcfTM\x91 \xf2\xae\x17i\x9d\xb4\xf6\xcc\xb0M\x86o-\xf3\x9cR\xc1\xdc7\x9a\xba\x81\x8d\xe8t\x1c\xc9I\x08S\xf3hd\\\xac\x11\x81\x89\\\xb8\xb9\xabnP\xf5\xb8$\x19\xc6\xc2\xda\xb1\xa5\x1bB\x1b\x13[\xfb\xa0\x08\xc5dJ\xd4t\x03v\xd5\x08p\xa3\xe3L\xee\x00;K\x17O\xcb38\x86\xc4\xa7\x7f\x0821a\x8fq\xbd\xe8\x83\xc1V\xb8\xe7u\xe2\xcb\x85f\xcdl\xd2t@\x91\xae_\x7f{\xc0\xa9;\x8e;G\x17\xc5\x97\xb1;\xa7g\x81\xd6\x19FL\xccE\xed$\xd9\x04\x19\x15\x92\x81$S\xd3,*\x7fS\x9ei\xef)\xe4\xf0}c\x87~\xef\x1e\xf8\x0c\x03\xf2\xb3\x10|D\xb8\x86lN\xcb\xb3\xe0)\xe4\xbb\xbb\x01\x0b\x911--\xd7\xfbb\x1a\x18\xe0E\xa1\xd7_eu\xd8\x8e\x18\xb3F\x0e\xdb\xaeu\x03A\x945\x82cfi4Q\x9f\x1e\x888\xc9Hu\xd0\xafE\x11\x1cu6\x0dN\xfb\x12Ui\x8dA\xa8\x05\x0f@\xdd\xc9#6\xa4\x98j9\xcd\xd0\xa8\x9eE\x8e-Y\xfe\x85\x1c\xad\xd4\xd0\xe8?\x04\xfalxg*\xc4w\xf4V4\xfa\xb7\x9b\x99\xf7\xd9X\x06o\xf8\xd6\xe5p\xc0\xf1\xf9\xdf\x8b5T\x7f\xfd\n\xdc\x84\x10\xc3\x1e\x0e\x89aZnB\xf0!\xfbZ\x8b{\xc1\x88\xeck\xe5;\xc9\x89<2q\"\x99\xff\xed\x00\xf6\x0cr\"W<\x03Y\x87\x99\x94\xa2\x1bKs\xab\xf2*\x03\x9b\x1a\xb7%f\x0b\x9e\x85\xb0\x08\xa1\x08a\x1e\xc2\nMF\xd7h\xbdv\x03G\x10\x97Kt5T2m\x1d\xa0uYc@!\xabL\x0f\xe8!\xda\xfaI\xf9v\xfdn\x97Z\x141\xf6\xeb\xd29\xf2\x14\x9e.O\x9f\x06P]'L>\x14\xd9, \x86\xce\xb1\xd11LW\xe8\x90\xd5S(\xce\xe1\x08nx\\\x99\x93\xacNJ\xf2\xa1$\x84\xa5\x18\xbe\x11\x86\xf5,\xb50\xad\xf6\x8f\x0d\xa9\xeaWYM\xca\x19)\xea\xbcd\xc9\x86\xe9\x9b\xaa\xc8\xb3\x8a\xb4^\x15\xf8\xaa\xad\xe7b\xd9Jo4\xb22\xcbGl'\xd2\x80\xa10\xea\xd5\x8b\xa4\x9a\x95\xc9:\xc9X~\xbe\xcc\x8d{\x92\xa6~\x06+\x90n\xe9O\xd9x\x83\xdf-\x1a\x98L`\xe1\xf6m\x1bh\x13(\xdc>\xebCu\x02s\xeb\x97\xb7!\xda\xce3\xf6[\xa6\xbe9\xbd\x8e\x97KR\x06\x0e!\xf3\xa0 {h\xadKe\xb15\x86\xf2d\x8aY\"\xb2\xac~\x1bv%\x8cN\xea\x0d*\x8c\xael\x863\xa2\xb0\xe1\xac\xdd\xc0\xd6\xcf\x80\xe1\x1a\xad\xab\xbaL\n\x11\x85\x14\xedl\x06\xadcD\xb1^\x12\xe1&\xfe\xd6y\x13/\x99\xe3/\xc9\xea\x10vJJ\xc2\xda\n|\xe6\xdb\x99\xa9\xcc\xe7\x12\xc1\xcfW]\x91\xf8\x97|Y2\xf4\xd6C\x16\x9f\xaeQ|Qn\x8a\xda\xf7X\x87^\x08K\x97\x19X2\xad\x8e\xc9\xac*\xb5\x18\x96L\xaaF\xc6\x960VI\xebb\xd8\x9f\x8a\xb8\xa5\x93j\x8b\x81\xc3F\x0e\x0d\x93\xb0p\xb9X\x9e\x14V\x9d\x99\x1f\x8ce\xaa\xfe\xbdX#\xfd`\xf2A&@s2\xef\x19O\xe6\xbd\xf6\xc9\xbcg:\x99{kjSE1\x0b\xe97\xf1z\xc0+\x809d\xaf1\n\xbb\xb9\x16\xc6\xe2\x8d(Yf\xe1\xb2\x0c\xb9\x9a\x9dG\x08|\x94\x89\x1eV\xfbFX\xed\xb7a\xb5?\xc4\xc5\x80\x8a\xdb\xe4\x13\x99mj\x16rZa\xcf\x86\x891#\xc2\x04I\x8ay\xc7\x86]\x1aDB\xf0\xfa\xe7\xae\x87O{G*}\xbc\xa9H\xf9\x92\xd4\xb3\x95g\x8d\xc1&V\xd4\xca0\xb0%\x9d@9\\M\x0d\xcaeI)\xac,\xffP\xa8\xb4\xdb\x10\x12\x831\xb7\xf5\xd6\xde\xac\x1f6\xed\xb6\x9a\x1d\x1d\x94\xe6k\xbb\xe4*\xd9\x0b\xfd\xdbF\xcd\xc1\x03\n\x1c\x03\x95\xd4\x0d\xa0\xcd\xb1-\xbe\xcc\x1f\xe2\xa5\xbeV\xd2n3\x87c\xf0\xf87\x1e\x18\xcd\xa4c\x96\xec\xe7\xe0m\x03\xe4\xe7\xf9\xba\x88\xeb\xe4\"I\x93\xfa\xe6u>7\xec\xe2\x8d\xc1\xdb\x96\x96\x05\xbe3\x92\x12\xc6\xaf\x90x\xb6\x92\xdd\x06\xf4\xa8\xb0s\xfa\x8d\xb6\xdbNb\x18\xd8l$&\xc5Z\x12\xc7\xf4[\xdaO\xa3:^Vp\x0c3\xfeg\x00\x13\x98&gc\xcd\xc0[\xce\xb4G\xaa3\xad]\xbb\x8a1\x1cX`\x1c\xfc\x8f\xddF\x0c~\x06\\\x97\xcd\x00\x9e\x17\xaf\xe6\x81\x9f\xe2\xfd_n\xdb\xf0\xa2\x0c\xa3\xc6\x04bk+:W\xedn)PDv\x1b\x11\xe7\x98\xed\x8d\xc2\x18\xba%\x8a\xa0_\x86\xfd\xd2-\x12q\x9c\xfd\xd9Z\xe4\xccL\xdeE\xb1\xf9wQ\x8c\xdaLgg\x01\xd0\x7fwwCH\xa6\x9e\x07\xbb0\x83]|D\xf1\xa5\x18n\x83\xa9\xa9\x9b\xb0D\xf4\xecK\xb0M\xfb\x8aP\xcc\xa4\xa2)\xed\x8a\xa2\xa4C\x04a\xacz\x04s\x16\x8a|\xfcp\x81wK\xe5^:L{m\xeeyA+\xb7:\x9c\xd3\xde\xcc\x89\x9bAQ\xe2\xb31\x17\xc6\xba\x06\x06Z\x7f\xa9\xd66;\xfb\xcaj\xb0\x10\xea\xa8\"\xe9\xc2\xe0'\xac\xde\xb2\x1d\xf6-\x10\xd6\xf1%9aL\x0c\x1cQ\xb2\xc1\x1e=+\x92\xeaC\xbc\x94\xb4\xa1\x92\x7f5\x95\x9d\xf4Vw\xc0\xb2\xea\xf7\x1dj\xce\xd4\xe1\x1b\x9d\xf63^\xb3hMh\x80\x1a\xd9h\xe2v\x07*t8?s\xad\xd9\x85Ic`\xa2\xb5\xa5\xe1@\x96w29$\x99\xe9>KVJh\xa5r\x9a\x9f\x0d*\x9c$\x81\xab\xb47\xf4\xc0x\xb5l\x9a\x9f\x05\xd8Xs\xf8V,,\x8d\xb9i\xceMO\xf0\xebi\xa2W\xf2\x9b\xf9\x0e}\xc3q\x91T\xba`\x81=\x1b\x0d=\xe6\xffK\"\xfaV \xf8\x8f\xd9\x03nK\xd9\x9e*=K\xfa\x84Q(\xf6\xbf\xd5\x9a T\\u\xdf\x7f\x93\xda\xb0\x02\x9a%\xd1\xbalj\xd6z6\xc6}\xa5g\x89\xca\xb4\x12:\xd7CMW\x0b\x16.\x8d\x1d\x1a\xfa~\xba\xf03:\x17*\x88\xa9\x13\xdf\x9a\xa5\x19w\x07\xf6\xe4` \xce\xf1\x7f\x86\xa6\xe7\x0b\x85O\x85\xd14\x1f\n>\x89*2\xdb\x94I\x9d\x90*\x04\"\xee*0JPV\x7f\xb8)\x08{\xca\x14\x08\xcac\xc3I\xc3\xa4\xaej\xb6\"&\xd9\x8c\x89\x9c\x9a;\x11m\xed\x8a\xd7\xee\xdf\x93h\xab\xcf\x98\xdc\xcd\"\x19\xfcT\x1ax\xf2\x05\xd6\x92\xea\x0f}\xa5\x82\x81\x87\x0f\xf4\x87|~\x13\xa2\xb6\xb8\xbc\"\xa5a\xf2s\xaeP\xa6U\xfe\x1a\x97I|\x91\x12\x83S\xed\n\xab\xae\xea\xdapE\xb1\xe4R\xaeP\x93\xe8k\xdd\xb4k\xfd\xb0I\xd2\xb9\xb1\xb2\x08\xe2\xf5)J\xaa\xb7\xcfN\x0f\x03\xbf\xd6\x1c\x147\xe8\xaeO\x1b~\x0b\xc7p.\xef!\x95\x88\xe8\x86 \x83\xef\x8c\xc4bS\xa6\x13cd\xa3YI\xe6$\xab\x938\xad&\x80Z\xf6Ut\x9d\xd4\xab\xe7\xcds8\x06/\xc9f\xe9fN0\x0ca\x15\xaf\xc9}\x16C\xcc\xd0h\xe3\x08l85gy~\x89q\xdeuF\x84\xfd\xf9\xc5\xa8\xfd\x7f\xa7A[z\xb4\x07!T\xb2B\x0fS\xe1\x08*\xca\xf4\xf3\x1a\x12\xed(=7\x80\xf2\x83\\\xaa%\xa9%\x91}\x1f_\x07CQew>\xa8\x91U\x9f\xfb^\xc3\xa4P\x89'\xc3\xd0\xb1Y^\xc3\"\xdfds\x9d\xab\x10\xed\xfb5F\x9e\x94\xd4C\x0f\xbeWmm\xd3k8\x86_na\x02\xaf\xf5\xd5\x7f\xc66\x87t1o\xb0\x86\x10\xd7\xf5\xf3{\x17m\xca\x14v\x8f\x8c\xa6\xa1\x83\xaa\x01F\x93\xcc\x01\x03$\xcd0\xdeT\xb2\x8dm\xbcU\xec\xec{c\x18\x9dF'\xf1\xc6pdr\x1d\xc4\xcf}\xcc\x0cB\xd8\xc9\xa4\xa5\x8d\x88(\x10ql\x0e\xe1]\x1fr\x12joBx\xc7\xd7\x80\xa2\x17J\xc1?\x07Q\x9d\xffT\x14\xa4|\x1eW\xc4\xc7\xa08G\xb0d\xca%=~\xbc\x97*\xfej\xfa\xe6\xccT\xb3\xe4\xd8\xce7b\x14\xa3\xbb=e\xa7\x0ch\xf7\x02\x8e\xe0\x99\xe2\xa9u\xea\xbfR\xc8_\x104\xcf\xdf\xb7\x9ek\x9a{1B+'4\x8a7S\x12%\xd9\x80-ai\x89\xb3\x85\xaa\xbd\x8b|~\xe3\xc9\x18\xb2\x8ca@\xbc\x8b\xd5\xbf\xa3\xc6h_Z\xb4-;\x11\xb5\xd0:\x8a}\x94\xc5k\xfck9e\x7f\x9fQn\xce\xf0>\xc1M\x1e\xb10\xadX\x19&p\xe9\xb3\xbfCx\x11tn;D\xc2\x96\xeb\xb8\xcc|\xef\x9d\x80+\x8f\xd4\xcf\x9a\xc6p\xfdI\x05\xf1\xfa\"Yn\xf2M%\x83\xdb\xd7+\x02<\n3\xee=X\xc5\x15\xac\xf3\x92\xbe\x893\xc83\xd2(\xfa1;\x00~\x91!\xee\xf7z\x88\xb39\xbe.\xe2\xaa\"\xf3\xfbI\xa6|\x8b\xba\x8d\n\xe6 \x8b#\xc6\xfa\x848\x83?$\xd9\x1f\xd8\xdb\xc8\x0bB\x11\\\xebh8\xf6bG\xd5%u\xeb\x8a8\x86\x91\xb9\x1bsCy\xf2\x85\xbd\n\x8cCHJ2\xa7\xbfvH\x84\xb7\xe2'\xeb\xa2\xbe\xf9+3\xf9nH2\xf7\xe2|/>h&\xd8\x06\x06\x856\x9dgQ\xe6W\xc9\x9chI\xb5:\x99\xb7]L\xf3\x98;\xa8@E\x8ev\xf5M\x81\x88\xa2\xd1@\x976\xaf\x0d\xe0[@I\xa3:\x90.\xdf\xcdK\x03d\xa02\x058M\xb48\xec\x85;\xb6vqA\x84\x97\x8c+\x1c\x91!\x041\x18\x15s\x80l\xf2\xbd{\x90Y\xb4\xce%\xf9\x871\x0e\x8d(rl\xd6@h\"3\xc1p-E\xa9\xfcj\xb8\xa6\xcdz\xc4\xd9\x9c\\\xa7f\xa6\xa4\xf1\xc7\xbe\xa9\xc3/\xcc*@\x0f6u\xe8N\x9d\xa0\x9d\xf1;\xcem\xd2\x9e\xae\x9b\x9e~\x0c\xe1]\xc0\x83\xef\x9ct\x1e\x07\xe2\xcc\xc3M\xda\xb6\x80\x97\xe7a`\xf1\xbd\xa43\xfc\xa9\x9f\x8aM\xf9~l\x98/q\x9c\xc8&\x8c\xde\x18\xa0J\x96\xbb\xe0cP\xfb{\xc8\xdeb\x18\xec&goE\xca\x04M\x8b\x06l\xceoC\xfa\x99\xbe\xa7\xe6\x10~\x8ec\x82#\xf8\xa9\xbf6\xfd\x13\x9c\x0d\xee\x9d\n\xe8>\xc3\xc1\x02#\xa17\xf6\xab\xec\x7foHy\xf3\xb6|\x99\x97\xeb\xc0\x7f\x17\x84\xf0\xeew\xed>Z?m\xf7\xac\xcama#\xb20\xb9\x97\x9e\x80ng\xbbMV\x06)/\xdbo\x14K\xa7\x1b\xc5\\\x11\x02\xcd\xb5\x12'A\x15\xa4\xbc\xec$TB+\x99!\x12\xffXp\xe6\x03\x86{\x15\xdf\x02J\x92\xb6:\x84\xa9\x87<\x9e\x87\xf7\x85~\xc9\x82\xd3Rv\xf1\xc7\xfc\xbaa\x17=6\xb0\xca;\x0bD\x9c\xb7\x81f\x1cj75\xcc\x03N1n\xbb\xf9\xfd\x8c\xc7\xd94sj9\xc5fDi\x97,\xae\x14\x91\n*\xc6\x8dL\x85*\xcd@6\xa59*\xdb\xd0\x0d_!c\xe9\xe5\x01\xfc \xee#\xcf\xe6\xa7\xec&\x86\xce\xb2\x9a\xaaUL>\x93;io\xba\xb2\xa1j\xbawF\xc7'\xda\xdb;\x0b(1\x14\x8dz\xbfxM\xcfn3o9zL\xcf\x98\x87\xc7\x83_\xfc\xe9\xdfo\xcfv\x83\xdb\x07K\xd5\xcf\xe3)\x0bs\x81\x862> \x9e\x06T\xb6\xd8T+\xbf\x9c\xee\x9f\xd9}6\x0d*`?\xdd\xe6f~\x16]\x89\xfd\x85\xbcq\xf3sJ\xac\x97\xa1b\xc2\xed\xaf\x86\x8fo\xe0\xc4g\xc3\xef\xf3\xa5\x0d\x9b\xfd\xb3\xb2\x13\xc9\xfd\x17\x99\x1c\xe6\xd6\x0b\xc1[\xda\x02\x81\xd0\xa5O\xa5\x97j9\xe8\xccd\xba\xdb\xd4\xf7\xd0\xb5\xc6\xb2m\xac;\xb9\x1c\xb1\x85\xcd\xae\xef\xc2\xe2\xcb\xd6 ]\xca\x95<\xb6\x19\x93l\x8b\xdfPj\xbe\xa9-\xdf\xd0\x13\xe6\x9d\xcf\x1dLgy\x8a\xb4\xf4\x9d_\xb6\x1f\xd8F\x9b\xe0\xbe[\xe5\x15z\x1e\x96\xf8\xd7\xf0\x17\xcc\x85\x8e\x92s\x14T\x1c\xfap\xc9\xac\xcb\xf1E\x84O\xf3\xe97H\x9e\x138\x86\x9cb\xf4\xe4\x01\xe6\xd4\xf0\x13\xd8\x85\x18\x9d\xf0\x82\xe9F\xf5\x00\x84c\xd8\xb4\\\x99`b\xc8\xbaz\xeb\xa7!hr\xb2\xdf\xfa\xe8\x9bk\xa7\x15\xe3x\x8a!=8H\x8e\xc2\x85\x0b\xc8\xdb\xc7z)R\xb2XX\x8c.j\xe5\x03\xa8E\x97\xb7}oT\xf3 T\x98\xf4K\xfc`;\x0e\xfd\xad\x8cma\xf4/\x8a!1\xc3\xcd\xa4\x83\x9b\xab\xba.\x06p\x87\x19\xf4\n\xdcL\xe4_C\xf8\x96\xe27\"\xb0\xbb\xad\xf6\xcc\x82\x99]\xac\x9caz\x17>\xc9\xae\x99+\x96\xf6\x89\xf0\x1b\x17&\xc6\xf2\xbfy\xf80E\xdd\xc4n\x98e\x8di&i\xa2\xe6nU\x03\x82\x7flH\xf9\x95V\xc86{ &\xb3\x8e\xbd\x8ep|\x08\x03\xf6\x17\x87\xc0\xce>w{\xbbw\x0f\xbc\x8b'?\xbd\x7f\xf5<_\x17yF\xb2\xda\xcf4\xbe\xa7:\xcb\xea\xbc\\\xbf\x88\xeb\xf8_\x12\x00~\xc64\xc1=\x0b\x16F\xa5\xe8\xd8\x11<\xf8\x87D\x13\xfa\xcbiC\x89-a\x1ee\xa7\xe3I\x7f,\xe6o]\xb6\xab\x1ei\x1d\xfc\x05\xfe\x93\x03\x0d\xa8\xbf\xee\x9c\xc5\xe8\xcb\xf9\xf9\x90\x12P\xc4`\xd2\x8a\xc8B-\xf9\xed\xe3q\x81r\xff\x05\x08\x8e\xb9bC\xa9\xcdu\x10*QU\xdf\xa4\x03\x95P/K\xd14\x1d\xf6\xae\xe9\xabr\x86%\x18\x8c_g\x1b!8moZp\x16\x13HP?_%\xeb\x82\"\xd4\xe0\x17|J\x13\xd8\xd0ol\x990X6\xa0 \xec\xec\x1b\xab\x99$\xcb!\xfa\x9f\x0b\xd2\xaf\x0bL\xf2\x1f\xc9\x98\x99\x19\xb06K5\xcc\x88l\xfa\x91\x0e\xbcM\xc6mF=n\xdb\xa5\x04+\xd2\x99\xb6\x8b\xe2\xcd )\xde*\x86\x8d|Op\xc3\xb1\\me\xa4\xb4\x0f\nq\xca\xacY!\xdb\\$\xc5\x8c\xa9\xbc}?\xf3\x86\x0fAQ\xf8n\x19\xb5\x15E\xc1-\xe9\x98r\x95\xf7\xe3\xe8\xce\xcew\xa7\ni\xb7\x0f\xc5\xb6\xe3\x07\xf6{\x82f\xb4\xf0\xd0IP\xcd\xc6\x1dJ\xee;e\xf4\xa1\xd0\xdf\x1e\xad'\xb7}U\x0b]\xdf\xa9\xc7S(K\xe6\x8c\x12\x9e\x9a\xbf\xec\x9ad\x11\x14\xbb\xa6g\xae\xdd\x81\xeat!\xc1\xb0\xff\xa8\xe3\xe5\xac\xdf`[t\xe2\xfd\x0f\x14\xfcM\xed\xfd\x9c'\x99\xefi\x9c\x13\x95w\xd0E\xd8_]#\x9b\x0cid\xe3F#\xdb\xd5\xb9\xb2[\x90\x17I\x85\\!\x99S\xfc\x88g5;\x01\xf3P\x1f\xc3\xdeb\xb8i8_\xb5VF\xf5X/\xb0Krcc\x04\x9cTl\x16M,3\xfd\xb42D\xcc\xafk\x88\x1e\x00W\xeb\xda\xe7(\n\x87\x13\xe6\xd6\xb2Ku\xe2(\x1c\x8e\xe1h8\x8f\xa0\x7f\xe6\x88\xc2\xa2\\2\xa6\x92\xb15M\xb6\xdc\xf1{lc\xca;/7Qhrv\xc1\x81\xa4\xf1\x05I\xbb\xe3`.\xf2_e4\xd1\xe0h\xd6q]&\x9f\xbe2X\xc6&r\xe1M\xb2,2 \x1c\xd3\x83\x84\xb9\xfbQ\x06\xef)\x05U\xcdX=\x0c#2a\xaa\xce\x10\x7f\xe9\xc70\xe0\x8e\x8a``\x8a\xb4#\x9b\xa7\xbe\x90`\x13\xee\x1c\xdb\x8ccB\xfb73\x9e[\xc0\x15\x1c`\x0b\xcaBkn\x02\xc0(\xed\xb3-Q\xc43\xf2\x82\xa4\xc9:\xa9)\x93\xee4\xfd\x94O_\x99\xf8o;o\x0f\x83\x15\x18RX\x0d\xcc\xbeH\x8a\xd1\x93\x9f\xfd\xcbM\xfe3\xc6\x0eu\x9dh\xde\x0d H\xeb\xa1AE\xc7\x1d\x92\xbe}\xc2\x1c\x92\x1e\xe9\x1d\x92\x985\xf9#]~\xff\xd4i%\x05\xec&\x0f\x8e\x7f?=\xfb\xffv\xbe\xb9\xf7\x07?\xf8\xe3n\xf8\xf4\xc8\x93\xf7\x19\xdcp\xb6?\x15\x8d&~L\xa7\x0f\xfe>\x8d\xef\xffs\xef\xfe\x93\x8f\xf7\xa3\xf3\xff:\xdb\xfd\xe6A\x12\xd5\xa4\xaau,\xd7\xb6~\x01O\x0e\xf7\xb7\xb7\xd1?\xd8\xfe\xd3\xc3/0\xefo\xbd\xfa\xb7\xd4\x8a\xca\x00\xa9f\x95\xa6\xdd5\xb5\xec[ a\xcc\x9a\xc1\x84(\x96\x08\x95\x9a|(\xd8\xe6`\"\x14\xb3\xdb\xef\xa2\xef=\x8bw\xa3\x86\xcbbtR\x8c\x84\xc2\x9d\x18\xdc{\xe7\xed1\x16b\x8c\x06\xdfeLx \x80\x89F[q\xeb\xd7\xd4\x10n\xe4\n\xb3-\xdc\xbb\x07;;\x1d\xfd\xea\\D\xc8\xd2\x7f\xb8\xee\xc7\xc6\x8aC\x98z3a\xf6\xac:\xfd\xde\x9c\xb2\xf0\x00<\xb6\xcfP*)\xe5\xa6l\xd1\xbd\\]H\xe3\xb4E\xdb8\xad3\xf42P\x14\xd8W\xf4\x1f\x16\xd3\xa6s}\xd5\xc0\x0bG\xd5\xfc\x94a\x7f\x8e\xc1_il4\x06X\x13\x19\xe0&\x83$\x1bN\xde\"8\x98\xf9t(\xb6$p\xa4^O\xb3\x01{\x0f\xb4\x07\xb0\x9d\xd3R\xa1\xcb\xf3\xd6\x7f\xfel\xbb\x10\x03\x8e\xfd9zN\x0c\x9b\x9b\xb0!X\x9bCy?.\x92\xffEx4\xcc8\x00\x0f\x17\x93\xdf3\xf2\xe0\x98\xfeB8\x19\xc8\xeb\xf0$\x08\xc1c(\xd1\xab+.\xcf;\xb5\xd9\x9dp\xaf\xb6\x08\xc0\xa6\xd6\x1e\x9e\x1d\xa8>\x18\xcc/^\x8c\xde\xce\xf2\x80\x8c\x01\x1aW\xc9L\x8c\x86\x85\xccp\xfd\x1e\x14\xae \xc1@\xc1\xf6[\xcfnAuYT\xc4Uu\x9d\x97\x03a\xcatE\xc8\xb3\x8a\x7f,\x0buA\xd9\xa3\xca\x01z\xa2\xc8\xb5\x8a\x9e\xa9w\x8ep\x04\xde\x0f\x14\xfcN\xf1\xbf\xbc\xe5\x81*-R\xae>R\xa1\xe0r\xf9\xb9\x87a\xdf\xe9\x06\x8eVq\xf5\xf6:\x13'`{x\xb9-_\xb2d\xb3 \xcf)Bi\xfa\xdeS\xa8\xe1{8\xf8\xf6\xd1S\xd8\xdd\xad\x03 ,\xda&\xf3\xca\xa1t\xff{\xd8\x7fD\xb9\xb1=\xc5\xf2\xb1\xe5\x17\xd4q\x0c2\xab\xef:>:\xbeR\xb3\x8ebJ:?\xe4l\xca\xb6\xb3V\x91\x18\x8e\x00s\xce\xd5Q\x91\xc6I\xc6>\xa7\x9c\x1a\x87\xdd\xac$qM\xfcl\x93b|y\xca\x0b\x96l\xda%|/\x1d\xb8\xe8\xdc\xcb@UV\x91iy\x86\xf8\x98\xd1?\xd8\xef\xee\x92sS\xe9f\xcd1)6)\x97\xa43\xfe,\xec;\x92\xa2\xba\xb6IC\xd9\xe1\xc3\xd9\x0d\x99T\x7f \x9d\x9b\xd6\x03\x81\xd6\xed\xc6\x0e\x96\xeb\xa8\xb3\xa5E*gVDk\xfa%r\x9cS:\x1d\x83\xe8\xe5\xe7\xedE\xf8\xfc\x99\x8a(i\x9a_\xbf\x13\x18\x8c\x0fw\xcah\x16\xa7\xa9\xdfEo\xba7\x18\x11 S\x0cv\xbb\xb37b\xc3\x0fy\x809LK&\xcd\xecBLp\x87D\xbb\xfa\xbd\xa0\xcd}\xef\xdf\x8c\xcd)A'\xd0\x16\x9aS\xdc@m\xa7\xae\x95^#\xc7\xe0g}\xc1:\x0b!\xd1*\xc0\x18\x8c \xbe>\x062M\x10\x9f\x15\xad\xb6\x84\x02}\xc5k\xfc\xff\xec\xbdk\x97\x1c\xc7\x95 \xf6]\xbf\"P3KU\x0d\n\x8d\xee\x06@\x11MAt\xa3\xbb\x014\xd4\xe8n\xf6\x03 \x00a\xa0\xac\xcc\xa8\xaaDge&\xf2Q\xdd\x8d\x11\xe6\x90#\x8a\xc2\x83;\xb3\xde\x91\xa8\x91=cy\xd6$H\x00\xb3^\xdb\xeb\xb5\xd7\xf6\x8e\xf7\x1c>\xd6>Gs\xa8\x99\xbf\x80?\xb0\xfe >\x117\"2\xf3\xde\xc8\xac\x02 R\x9c\x1d\xd59\x12\x1by\xe3\x1d7\xee+\xee\xbdqFcp[\xfcSc\xeeB\x81M\xe2o(X%\xf9B\x8e\x97\xbe\x9cjS\xf7\xf8a\xda\x0e\xada4\xd6\xe1j\xd2\x1b^\xf7\xebc6ms\xc2#v\xf4\x88\x01\xe8t1bT\xde.\x01\xbe\x90\xa6\xfe \x9cDs\xd4\x18\xca\xf3\xcb\xa6\x0f\x13\xd2H\n\x88\x9d]\x0foX\x06\xc6\xd1\xc0<.$\x95F'A\xfb\x8b\x93\xaa7\xa8_\xc9\xb1X\xce.|Tf\x17f-\x946\xc0<e\xbe\x9e\x9e5_O\x7f\xc7|\x9d\x9b\x9f\x97q\xc5G\xf5\xc0\xe4\xa0\xd8\x82\x80\xb2\xb9\xf9W40\x12\xd8\x0e_\xe7gO\x96>\xcf\x9d\x9eg\xb2\xd9\xef\xb1\x97o\xb0\xa3\xe2\xcb\xfc+\xecG\xec\xe5\x13\xec%f\xea\x9c:5\x7f\xfae\xd3\xff\xa9\xef\x9c8y\xb2hb~\xfe\xa4nbn\xbe\xdc\x06\xb4\xca^b/\x9f\xb07\xddND\x0bs]\xb9\xb0/\x9f:u\xe2e)S\xcc\xcd\xce\xcb\"\x1d\xf6\xdd\xef\xb2\xb9Y\xf6#\xa6\xbe\xa0\xb5\x97; C89k\x86\xf0\n\x19\xc2\xdc<\x19C\xf3\xd0:\x0d\xac\xc2\xce\xd5\xddh\x14;ns\x14n\xf5\xcd6\x8aaQ\xefV\xdd\xc5Cd\xbdr\xa0\xe2g\x9cD\xf1\x02kE\xd5\x0c{\x96fI\xeef\x91zH\xbb\xf4\xa1\xe8\xab\x16\"4\x85b|\xdfb_VaU3/\x16C \x1bTS=\xfe\xcf\xe6g\x8f\x0f\x8a\x16\xca\xf7\xc4\xd5\xc50\x97\xb2\xad\xadsK'N\xbf\xf22J\x1f\xd3\x97i\x89\xe1m \x8a\xbd[\xe7\x96\xe6\xbes\xe2\x95ib\x8c\x88\x90\x19uY\xeb\xa8-\xf3\x04\xa5\x13jh\xcf\xd1\xcd\xc4+\xe6j'f\x1e-\xf5W\x8b\xc0a\x00f\x95\x9eo_\xf5\x0e\x02E(6P\xbe\xbdF\xb7/l\x9f\x9e\xc3a4\xbe\xfa>\x8f\xbe\x9b0W\xb5\xbd\x93n\xfdY\xe9\x04H\xef\xc8P\xbf{\x02O\xb9H\xc7\xac6/;\x9b,;\x99<\x13\x19\xf9\xf8\x1a\xe33\x03\x9e\xed\xf8#\xde\xee@\xf5\xd2\xbf\x17T\xbc\xfe\x11x\x19\xcf\xa2!Vt\xa6\xe2\xbb\xcc\xf62\x03\xe7@\xca\x9f0\xb0\x05\xf9\x97\xfcc\x9aY2\xb5\xf0A\x97\xb9\xf5t;oC\n\x97\\\x12h\xb52G,~f\xba\x02/\xf6\x0fhp\xf1\xef\xa9\xea\xfb\xd2\x80\xa0\x0b\x1e\xf1\x85\"\xa03\xe3\xe8\xd3\xd1\x01\xf3\x91\xfag\xd6\xe92\xc7\xcc\xb4\x81\x07\xa5\xb2\xe9z&#\xad\"\xe94\x13ef\xb2\xca\xbc\x083E\xbaDSm\xc9\xd0\x02`bA\xc5\x18\x14\x1c=\xda|\xe7);\xbe\x1e\xdcP,.\xb81U\x87\xba\xc8\xb4\xe9\xfeX\xad~\xa7\x7fc\xf5\xe8W4\xf1\x8d\xd4X\x96\xcaj\\\xf6\xb4\xc67M\xd2\x8c\xba\xe4s\xb5{\xde/v\x88\xc5\xd3n\x90\xdc\x9c\xfeL\x1a%Y\xbb\xd3e\xb1\xf9K\x06\xea\x95\x9e\x88\x14{\xf7=\xd8\xc3c\xc7\xeawM\x0e\x04v\x8c\xc5\xd3l\x98\xc1\x8e/\xd8\x99\x8c\xed\xbb\x1e\xdc\xe8\xb2#N\x9b_wotY&\xff?\x9c\x8c\xdbZx\xd14\xa8\x90yi\xfa\xfd\xbb\xc5\xb1\xab\xc0\xee\x96\x1c\xa6\x8c\x7fR\xde,kHu\x9c\x15Y\x17\xcfT\x1e\xce\xbaki0\xadm\xf0H\x1bH\xab\x95\xa8\x8a\xef:\xffV\xe9\xbbA\x0e\xe9\xcc\xa9;\xa9(\xfb3n\x14\xcb\xb7\xf8j\xc0\x92_I\xf1\xa8\xa0\x0c\xea!d[\x8f\xd7go<\xaf\x04\xa49%=(\xc0\x0e\xe8u\xb3\x8d}\x9e8=ka\x9f\x13/\x98\xd5\xe2Fj`H\xad\xbbK\x19o\xd8\x9e?1[1\xb4_L\xa3pS\x1cw\xfd\xa0\x9b3S\xfc\x13\xacN<^\n\xa2P>*=s\xd3\xfc\xb3*\xee\xe5\xd6%p#\xfe[G\xc8s\xa9+\xd4\x11\xa2\\&O\xa9;\xdc\xf9\x8c\xf8o\xf5@\xd9\x14\xaa\xc0*\xa9Kw\x03\xd0K\xean5\xb5\xd5\x9e.\xa7d\x02\xa2w\x0b\x17P\xd4\x1f\x8f\xab\xfcO\xc3i\xe4Mt\x97\x85\xb0q\xa6\x8cM\x8bs\x95\x93JR\xe3\xa7R ~\xd3\xd2\xcf\x91\xb9\"\xbc\xeb\x8cN|.\x1f\x98?2\xdb\xe9\xaa\x82V--a\xaf\xb1Dp\xc2\xd9.\xe3\xf2\xeeDH[l\x81\xc5\xf2\xa3\xcc\xb8\xdcR\x179\x00\xa2\xab4V\x99\x0d\xed\xe8XAE\x8b\xa5\x95\"=x\xb0{\x9e\xee7\x8a\xcd\xce\xb93\xa5\xe6\xe4\x1d\x8a:\n\x16\x9b\x9dlF\x9d\xc7\xe7jJ\x8bl\xe2T\xd6\xb7,\xa5C\xd3\xacT\xa3\x05\x8eO\xd1\x93D\xd4\x10D\x94.\xc3\x0d\x89\xad\xaa\x0c\xa1S?\x06ql\xca\x1d\xdaw@\x9a@\xe4\x11cg\x04\xf75\x88\xd81Od\x01\xb8\xc3\xb2a\x12\xed\x8b-#\xcai\xbb\xb5#\x1a0\xce\xc1\xac\xef\xf8\x01\xf7Z]\xd6\xdaY\xd9\xde\xb9\xb9\xb1\xb9\xb2\xb5\xb8\xb3\xba\xb1~\xf3\xdc\xe2\xea\xda\xcarK\xa2T\xd8e|\x82\x18\x86\x16G\xac8E\x92\xba\xcd\xad\xae]i\xc5\xab[\x88\xb7:\x0f\xecf^\xd9\xaa<\xef\xb4\xcd\xb0\x90\x18j\xeb&\xcd+h\x1e\x81g?\x8c\xe2\x1f\xca\x8bL\x9ed\x87\xccOY\x18eL\xa8\xf9Q\xbfX\xe2\x94\xa9\xa8J\xe6\x87l\xeb\xdc\xd2\xb1\x97O\xcf\xce\x8b\x05/\xd6zc\xf3\xe6\xea\xfa\xe5\xc5\xb5\xd5\xe6\xf5\xd6\xcbR%V\x95\x7fE\xca\x92\x8fT)\x8eU)m\xe6l\x03=`\x90WW2\xd0\xac\xdd:\xde\xb2\xd8>a\x17\xc8\xe7!;\xc3,\x8f\x16\x8cKv>\x0b\xb31!b\x146h\x80\x1d\xd6\x84\xe3J\xd3\xe2\xa1|\x1a\xae\x8e:\nb\xf8\xaa\xf5\xcaWl\xf9@\xda\x16\x877\x14\x95-\x11a\x08\xde.\xc7\xb3]\x1f\xdc`\xaf\xc9)\xf4\xc18\xd6\x9e\xed\xb2\xa1N\xc5z\\f\xe7\x1b\x8a\xee\xc7\xec\x18\xe4\xe2o\x8f\x98\xa1\xbc\x95\x00^\xd9\xf8aA\xb8G\x82R\x0f\x8f\x1e\xc5\xf7\xc8^\xad\x89_\xe2\xfa1@\xf4AG.\x9e\xa7\xad\xee\xd6\n\x0d\xae\x8aL\xe3\xbf\xb4\xf6\x95\xa5\xd2A\xa7\xf9H\xac\x1c\xc4\xdc\xcd\xb8\xc7\x9c\x90\xe5a\xea\x0f\x04\xba\xf7\x9c\x94\x1f\x9b\x9be\xea9d\xa6\x08\xf3\xc8\xd9\xf3\xc3\x01\xcb\x86\\6\x96\xf0>Ox\xe8r\x0f\nH\x80\xf4\xe9c<\xe0\xf2\xa8\xef\xfb\xd9P~\xbe\xc3\x93\xe8\x98h\xd6\x03\x81\xb5z\x8a6\x17w.\xdc\\][[9\xbf\xb8vsqkk\xf1\xea\xcd\xd5\xf5\xe5\x957\xd4\x99\x02\xed\x8e5\xbd\xe5W\x9d\xb2\xdc9\xb1\xa0\x7f\xfc\xc7\x83iu\x1b\xa6\x96p\xc8\xbew\x86\x8d'\xdd\xcb\xc8\x85\xae\xf2H\xf1e\xc0\xbeg6q\x021\x1fr\x19\xc6\xe1\xf7}\xbd&\xec\xd2\xee\xf6\x0e[\xdf\xd8a=\xce\x06\xd2W7a\xd9\xd0 a\xc5\xa5\xc1V\xd0'\xb5\xb8\xa9\xa0Jf\xc9\xab\x0bzyqmw\xe5\xe6\xc6\xee\xce\xcd\x8ds7\xcfn\xec\xae/oO\xbf\x96\xf2\xde \xd8\x92\xb4\xdc\xa7\xd7\xc5\xf4n\xc0\xedV\xd8e^\x97\x0d\x04\x99\xeb|\xfd<\x8b\xd5\xd1R\xfd\xb3\x08\xccE \xc3@\xb9\xc5\x1c9\xc3\x06E\xaa\x83?n\x15\xf8\xe2\xcc\xe4!\xe4\x9a\xdct\xb2a\xe1)8\x90\xa7\xbb\x113\xf0\xaa\xe5\xdf\x9cU\xab]1\xbaZ\x1e\x032Y\xc3\xa8l\x02s\x7fz\x81\xd9&\x16\x13\x07\xe1\xe6\xa5\x91\x7f\xb3\x94\xdf\xce\x05\xe5a\xa3<\xcd\xc4qq\xc2\xe2\x18l\xaf\xbc\xbe\xbb\xb2\xbe\xb4rs}c\xe7\xe6\xe2:\x10\x14\x1c\xe12-\xbb5\x9e>\xf2F\x9f\xef3\x1d\xd6\xa4\x0e\xb9\xf2\x00\xebB>Msk\x9a\xb3\xef\xb2\xf4U\x96\x1f=\xdaa\xfe\xf5\\\x86`\xcau\xba\x9e\x0bN\x05\xf7\xf7\x12R\x16\x8d\xac\xda\x8bO\x054\xbfqC\xe2 \x1bRw\x0bU\xbd\xf6\xa2^\xf4\xd3IVJ\x96rB\xa6\xba\xa9\x10&\xb5%\x1bg/\xae,\xed\xb4\x00k\xc5z\xbcJFy$\xbf\xce\xc5\x01\x9a\xb6\xdf\xafD\xa2\xab\x1f\x9eq\xbe-_\xd9\x81\x826\xe5xEa:b\x87\xa9\x86-\x0cr\x8aa)\x9f(9\x92\x82\xc4\x1d\x07\x12\xa7>\x177\x81\x8dc\xfdv\xfdX\xe5\xa9K3'Q\x1c\xbeu\xbc\xf5\xed/6\xde\xb2\x1a\xc7\xa9\x1a\xc7\xa5\x02 X\xadm\xb9\xa5\x027\xedr\x8b\xc2t\xb9\xe3\x84\xa7\xe2X\xb5U\x88\\/\xe0\x025~(F\xf5C\xe6\x84\x1e\xfb\xa1\x18\xcd\x0fK(\xd4\xa9n\xcd\xb9\xad\x8dK7\xb7V^\xdf]\xddZ\x994W#/\x98\xa9V\xd4c\xf3\xb5P+\xcd\x02\x94o\xa1\xb5Eq\xca\x99\xcb\xd2\xd3O\xdd\xf1\xbc\x1fv\xd9\x0f\xd5\xc8\xd4\"\x88\x115,\x02\xc8\x1b_\xfd*83C'\xdd\xd5\xc9n\xdaz%\xbeyK\xb1\xb4\xb8.H\xdd\xd2\xc6\xfa\xce\xe2\xea\xfa\xcd\xdd\xf5\xe5\x95s\xab\xeb\x13\x96\xc6r%Q6\xc5\xa8e\xa87cB\xa0\xb4<\xe3\x85:\xd8\x98_\x83)kxD+\xd8E 1\x1e_\xd2\x98\x94\x1d\x05\x15I\xfd\xb3y\x0f\x96\x9cP.4OdT\xb2\xa3\x16\xb7$\xe48\x99\x14f=\x9e\xfa \xf7\xa4u\xcfB\x03\xd5\xba..\x97W\xb2I\xe6\xab\xc1\xad\xb2\xe5\xc2|,\x0c\x0fM+\xed\x83W\x99\xa3\xdc\xac\xa2\xe7\x9a\xb8\x98be\xce\x8e\x9c\xa9\x10\xf33\xe6E\x1c\xf0\x91\x1f\xf8if\x99\xfd\xee\xfa\xd6\xca\xf6\xc6\xda\xe5\xc5\xb3k+\xd3\xce\x7f\n\xfaZ\x8fQ\x81\x10\x07\xdb\x16\xff}\xfdk2\xd0\xea\x1f\x18j\x81\\O\xbc\xa3\xab\xc9}.~wo\xd0c\xa3\x7fb\xaa\xd2\xeb\xbdq\xc9\xe4\x9c\x03\x99\xf9\xe2K\xec\x9a\x98\xc7\xd4\xfb&\xd9\xc3\xd4\xfb\xd6(\xd7yZ\xae\xc3;f\xf7\x8b\x93B\xd4\xf3Iq/J\xb8\xd6\xdd\x87\x1d\xd6oW\xe4\xeb\xb0\xd3\xc5\x02\xb7\xd0\x03~\xf4#\xa1\x11\xd0F\x1aL\x1e\x89L\x19\xf6\xa3\x1f\xd5\xe5\x01\xac\x84t(\xd7\xfc\xc2\xab1\x12\x82y\xd2\xe6\xd7\xa3\x1b\xd2\xb79\xd4\xc6\x9dI1\x0b\xcd\xee\x81\x926\x94\xfdn\xf1\x1a\xd7]\x81\x88\x1f\xecLm0\x99\xf9K:\xed\xca\xf7\x92\xcf\x1enF~\x98I\x0f\xfa\xc0Du\x17\xfc\xee\x0cs\xcdW\xd8\xdb3\xaco\xbel\xc9p\xbd\x04\xc7\xe7\xe2y\xe9\x0b2u\x8bb\x91\xd4A\xebM\xbe>\xc5V\xadaR\xd6\x8c\x8a\x85\x12\x13\x1c;\x81\xef9\x99\xf4\xe9\x8aK\x1f\x84\xd6\xe5}K\x15\x9b\xc6\xb3-l\xcf\xbfR\xea\xbd\xd6w\xdb\xa6h\x1dI\x94\xb72\x9f\xb9\x99\x81{\xac^\x9e\x9d\xc3\x98\xab5Y\x0de@U\xe6\x0b\xa9#\xe1.\xf7\xc7<\xe92\xf3\x96\x84L)\"x\xe2\x11|\xcc4*!\x1c\xf9BQ\x0b_(\xad\x0cM)SN'Sr\ni\xcf\xcfw*\x8ew\x96<25\xbe\x93\xf4\x909\xfd\x8c'k\x91\xe3M\x13a \xafk\x93(\xcaVC\x08\xc4>C?\xe9w\xc9\xd1\xf7\x19?\xf4\xb3\x8d\xc5<\x1bB\xb2\x98<\x1b.\xca\xde\xd2\x197\n\xfb\xfe O\xb8\x80Zj\xc6 7)\xdc\x16e*(is\xee\xf9\xa1\xd7\x86\xcb\x0f\xe94\xdeT\x0d\xf2\x1a\x9dan\xb5\x16%O\x94\xa5\xa6\x99\x93\xf1\xcd \x1f\xf8\xa15\x0eD\xfcD?u0&W_\x12\x87t\x81Ez\xb3\xeay\xb7\x03\xcb\xd2\x185\x96\xf2\x80\xbbY$Z\xb4\xbf\x0fY\x93\x95\x16r\xdd\xd4\x0ft?q\xe2E\xdd\xbf\xfdQ\xae\x89\xee!U\xdaa\xdd\x05\x0c(v\xb5\x8a\xf0\x91B\xf8\x13\xa7O\xe2\x9c\x19>\xbc<\xd4\x9e?A\xb2M:\nt\xe2\xf4)\x0c\xca\x0dH\xe6\xd90\xb0&\xb7c`C(\xdbc\xd3\xed{&\xa3J(iWQW6\xbc#\x89\xea&$\xe80\x91D*\x05@\x06\xd1\xdf\xfczX\x93K\xa2L$x9\xff\xa7M6\nj}\xaf\xa7\xcfzY\x93\xf1\xb2Y(s5\x89\xb5\x18\xdb\n\x9d\xacL;\x0c\nQ|/\x1e\x0d\xd9\xd6\xa7\x85\x16\xca\xa5\xcdR\x14\x12\xdc\xd5r\xfaMz5?\xddX\xdc>\xd1\x91 \xcd&>\xb2\xc1\x16\xd8\xf5\x96%\xd3b\xcb\x12\xa6*\xd4\x82\xbc\xdd\x11r\xc8j\xd8\xben\xd2E\xa4]v=\xbbA\xd2\xc1\xc0F\x04\xec5\xe6\xcb\x07\x99\x13\x94\n\xb3![\x99\xfd\xdc\xebdq\xb5\xae5:u\x9c\xcd\xcf\xd2F0\xc5\"8\x0b,\x98\xc9\xa2\x8b\xdb\xe8=gHS+NB#\"\xf4\xeb\x1c\x8d4U\x98\x1a\x0b\xfci\xb0\xc0\x81\xb7[j\xb1 7O ~eX \xc3\x98-X\x907aA\xca^c\xd1\xf3b\x81\x0d\xcb\xd5\x96\xa5So\x19\xfb\xa6\x89F]\xed\n-\xa5#\xca+$\x84d^r\x14d\x8e<\x00\x90Kq\xf5;\xe8+$\x1b\x9e\xc3\x11\x16\x81\x8a\x87\x98\xb7\xf2\x14\xf7\xeb!\xa7\xfa\xaf2\xa9\x97\xfeT:'kT\xca\xc9\xdae\xc1\xcc\xf6\x85\x8d+7\x17ww.\xdc\xdc\xdc\xd8\xdc\xdd\x9c\x90oY\xfb\x95e3\xb1-\x9f\x9f\x9e\xd1L\xca\xb3v+\x1dF\xfbe\x84\x17\xa8Q\xda;\xfbx\xc4P6\xb6V\xaf\xad<\xefH(B'&Op?\x89F\x17\xb7;BW&\xa5\x80\x90\x0c\xc4\x80\x8b\x1c\xc1-x8CV\xbe\xe4\xc4\x1d\x1c\xf8n\xd4%\x1ef\xc9\xe16\xbf\xdd\x9e6\xe3\xba\x96\x0dP\xbaN\xdee8\xb0U\xff\xe4,\xaf\xcf\xd6\xe46H$t\xae\x06\nIe\x159i\xc1 \x17T*\x939\xcfjl\x0c\x95T\xab2\xc7H\xe9\xa5\x1d\xbf#W,\x92[\x1c\xda\xcdG\x85\xa9\xac\x94\xdf\xd4\x9a\x97\x87\x95\xc2}\x8aq\xca\x93.\x86\xa9\xb9R\xebFC\xfca`\xaf\xab\x19\x96u\x9aLm|\xdb\xccET\x0e\xbbL\xd5ot\x9f.xe^?*H3\xb7P\xce\xa6\n\x8f\x93\xf5\xb2\xc8)?\xdaS\xf7Ls\xa7S\x1e\x96\xda\xba\x1b]\x98j[\x7f\x98\x98\x11B\x066\xc3y,\xa1\xb7\x10\xad\xa6?\x8a77\xc4\x9f\xf3/\xe6D\x86\x92Q\xdb\xcfaX\x97,\xd9\xa9\xf1u2\xe7\x10\xde\xeb!o\xfd\n\xaa\x17u \xcfH\x95\x14$z]$\xd6T\x96\xc6\x81\x15\x96\x88\xd7\xb9\xd1-\xe7\x05\xac[\xaa\xb5\x8d\xf3\x1b\xbb;/f\x81,\xc4hf\xdf\xcf\x86\x97\xf2\x0c\xaeG\xa6\xc8\xa8h\xc9\xe4\xd5\xf8\x8c+\x9f\x81\xc0\xb2\xda\x10^\x0b\x9a\xd5\x98N,\xb8\x96L^\xc0\xa5\x8d\xf5s\xab\xe7w\xb7V$/z\xde\x85l\x1a \x18\x16,\xdcG\x8d\xea\xb7+\xc0t\xc1\xf6\xb8\x04\x83\x94s\xf2\xd3E\xb3x\x90\xd4\xad\xfaO\xaf`\xa9\xe7\xa2d\x0bLY\xe0\xbe\xa4\xd2\x0f\x94\x98\xee\xd9\xc3ug\xc4S\\q'2}H\x90`\xd5a\xa9\x9a\xe5\xb8i\xdbS\xde\x0e\xdb'\x89t\x15)\x08\x95\xa1 o\xc3),D9J\xb4z\xbe8\xe2\xafDV\x1a\xab\x04B\xf5\xc7\x8a\x9a\x05\xcb\x967\xcb\xe2\x01\x19\x82\xec\x90Z\xe5\xe8\x08enr\x1f\x8a\xbc#\xd9\xa9\x83p\xa6v/'\xf7\\\xd3\xf1tb\x0b\xd2\xa2l\x0f \xb4\x8d\xec\xe4\x80\xecT\xfb\xcaQh\xe4\xa05?\xcd\x88\x90\xc5\xca\x96\x8b\xe7\x16\xb4\x18\x12\xb6\xa2\xa9\x84-fD\xaa:\x81\x8b)\x9c\xae\x17\xbaXIYt\xac\xe2c\xb9T.\xc9T\xd2\x95/%\x86\xe0\x1b\x9b\xa7\xc3vn#\xb9]\x9c\x17\x91\x92\x12\xeb\xe1o$\xa7S#@H\x11\x80\xce\xcb\x8d\xc24\n\xf8\xcc\xbe\x93\x84\xed\xd6\x95\xc5\xad\xf5\xd5\xf5\xf3\x0b\xcc>2?e\x1e\x8f\x13\xee:\xe00\xeb\xb1}?\x08X\x8f\xeb0\x1e\xed\x91\x19\xf2\x83\x8c\x8d\x9c[Q\xc2\xc6\\g\x9aB7\xe2;\xd3\x04\xbb\x11\xe7\x99\xce`,I\x98?\xa1W\x1b\x8f\xc1\xbf\xca\x9b\x039PF\xa9\xba(\xd7\x95T\xd0\xbc\x97^b\xed6\xbcp\xa1$\xe3(\xe6i\xab\xd3\x99\xd9\xe3_h%\x99\xf4~v\xa30s\xfc0U\x17N\xb2\x87T\x8bI\xdc\"w\xeb\xdf]\xe5\xc1\x98+I(\x08\xa2}\xeem\xc3\xa8\xba,\xed\xa8\xe46\x99\x84\xfb]f9\xe9\xba\x1d\x1f\x9e\n\x95\xb9\xcd\xec\xf4\xc0\xaf\xa3\x07\xddI\xa2B\xfdbh|u\x92\x81\xbc\x08L\x0b\x07\xb79V\xcd\x15f\x8a\\\x9f\xbb\xc1^\xab\xfes\xa1\xe9TMEtT\xa16\x18\xfa\n\xaec\xe7~e\xc6\xa3\xfa\xecL\x9f\x84\xdc\x1c\xf14\x1a\xf1)\xc5fSG \x1e/\xe1\x9b\x9f\xa4Y\xbb\x06G\xac\xb2t\xd3.V\xe4\xbf\xc9\xfc}\x82da3rh\xa2\x84\xb8 \x92D_$\x13\xa9\xeeg1\xa6\x06\xe2\x0b\x9b:\xe3\xa7\xe2?\x10\x1b|\xe4H\xa6\x8c\x95\xcf\xbd\xcf*\x97#2\x9b\xf2\xce\xcc\xc8\x89\xa7h\xa5\xd4\xd2\x91#!\xec\x7f\xddv\x1b\xaf\xd1#s\xb6\xad\xd7\x87\x0b\x99W\x19E\x84\x8a\xa2\xf0\xa5\x11A+F\xe5]\xff\x16\xfbFhD\xfc\x80\xbb\xb9\xf4,\xb0j!]\x95\xe5f\xfe\x94E\xd7\x90\xd6\xceH2\x88\xa4\xaa($\xcd\x8aB5^\xb8\"\xe1\x17\xe3\x99R/\xad\xa0\xb7]\xcd\xcf\x9a\x04)|\x9aj\x9f\x83\x89\x94\x1a\\\xe7\x8e\xe8\xa8\x0c\xd6\xd90\xaayr,\x97%\xa6x\xc1M,C\x968\x0d\xcf\xc9\xd6\x1f\x95\xe2\x80/(\x03\x90>\xeeb\x9f\xaa_\xd4\x89\xae\x97\x1eJ\xd4\x7f\x81%5*\x88\xdc~+hb\xfb\xe5W\xdd\xca\x1d\xe0VMS\xf6s_K\xc8x\x1b[\xa9\xac\x0d\x80\x93_\xcd\x1by\xb0\xa3\x0b\xcc\xb1\x83K\x0f\xde\xd4\xd8(\xcb\xaf\xe6X^\xbf\x95rJ\x1d-\xfa\x86P\x89/\xe3\xf1\xd2\x0f\xebnB\xd3\xa1\x94\xd8Vn\xe7N\xf0}~\x08(\x86\xbe\xd1\xf5\xaa[*j?\x917G\xdf\x80\x15\xa4#K\xdba\xfb$y\xe7:2>\x16\x13\xfd\x8dj\x05I>\xd3\xb7\x10\x16{\x82\x02\xf1\xf3\xa2\xfd0\x98\xd2\x1d\x89Y\xc8emj\n\xfd+\xf4D\x9e$\xea\x02\xb9Y]aZQ\x9at\x8d\x8c\x7f\x8e\xa94u?\x10\xf8Tp\xfb\xc95\x02I\x9f\xfb\xa0\xc4v\xcc\xddv6\x93 ~'\xf4\x8a< \xda\x9d\"\x93\xbf.\xb6\x9b\x04u6\n\xfdk\x1e\xbbL\x14#8\xac\xea\xa2[7\xc6\x00\xfe ,\xdc\x0d\xb8\x934\xbc\x8d\xa1\x7f\xcf\x83dB\xfe\x0f\xa6h3O\x82\x05[\x9e\x16\xfc\x13\x03\xde\x96^\xd1G\x1a\x1e<\xd4?\xf5 \xe9j\x98\xf1\xc4\xe5q\x16%\x0b2=\x0f\xfe*\x96j:\xf9\xb5\xfc#w\x8du\xbf\x1a\xef\xee\xf2/\xe1i\x1c\x85)'C%\x9f\x7f\xfbcu\x13\xee\xf10\xf3\x9d ]`\xad\xd4\x19qEg\x1b\xe2\xe0\xf4O\x91\xb7&\xa7\xf6\xf2OP\xc98[\xa8\xbe\xe2y+\x8d\xc2\xee\x1f\x1c\xff\x83\xc9\xe4\xad\xf9\x94\xdc\xed\xccdC\x1e\xb6\xfb]\xd6o\xb8$\xb0Bj\x96\xc9r\xc8\xa6\xd5\x8c\xb4@x\x1d\xa2\x1d\xcc\xd1\xec\xb2V\x11*\xa4i\x8a\xf9\x08zG\xab\xe1\x0d\xf4\xaa\x1553&Nx\\N\xdf\x01r\x95\x11G\xfcg\x01\xc4p)\x90Ws h\xdf\xa8\x92\x1d6\xebLdT\xd9a,\xa8\x85\x90\xb5n\xc2\x02\xddT\x93\xbb B\xf8\x04\xbcQ\xae#\xb6\x04n\xfaW\xb3I\xe4\xab\xcd\xff\xb9V\xb7\x0d\xaa\xdbh7\xe3N\xb7\xb9\xc6)\xa2\xce\x8c_\xfe\xddm\xb2\x0c\x97\x7fU+qe\xb8pc@\xcc\xd4\xfag\xbb\xd9\xb0\xda5i\xe7\xd3\x04\xd8L\x8a[113\x8d\xd9!u\x10N3v\xd5\xa3\xd5B\xb3\x0d\xd8\xf6S\xb3\xb6\xbc.g<\x98 \xd1)]\xf0nQD\xe6;m&=\xf5\x98\xdc`\xed,\xa2\x88j\x1e\xa0\xa2\x9b\xfa-\xfb\xbf\x90\xb5k\x82\xe7O\xf5\xab \xca\x99\x9f:&\xe7\xab\xf2 \xfa\xed\xda\xe5\xbe\xace\xf3\x85\x9e\xa4\x1a\xf32\xab\xe2M\xdf\x8e7\xf6\xba\xea\xdai\xbaH\xb9t\xe6EG\xca}\xe9x6j7u\xdba\xfb\xf4 \x12\x9c\xa6\xee\xa8N\x9c\xb0\\R\xc9\x00NZ\xc5Q\xa0\x93\xb3\xb3\xb6P\x04\x00\x11\x0bm\xaa\xc6pr\xb6\xe6\xecXB\xb9\xfe\xe9\xc5\xb3}\xcd\x01\x18c\x95T\xb2\xda\xc8\x80gk\x91\xeb\x04 `-4\x9b\x03\xb5\xf7\x834K\xc4N\x92\xf2\xab\xceHU\xed\xb4\x0bi\xa9q,\xbf}bf\xec\xd8g\x0fw\x130Tk\xfb>|op6\x85\xf3S\xb9v\xc0U'^w7_\xa2\x96\x169\x9b\xe9\x87`C\xef`E\xb9\xee\"^O\xe9\xb9\\#\xac\x06*}\x99[\xb9*\xa0\xf2\xb7<\xb7\xe6\x9cFh9\xda\\)\x1f~\x97\xf96\x03\xbf9\x0d~\xfd\x1dIh5\xe2\x87U#>{\x8d\xb5\xa3&\xfb\xbdR!:\x02w\x9f\xab\xd8n\x12\xb4[\xe2CU\x89\x08KV\xfd\xc2\xa8?\x93'\x81@2x\x81]HH\x99\x8a\x84#\xe7%\x04\x03\x89ED\xfd\x06\x9f\x9f2\xe6\x0fx6%\xa6q\x15\x0d\x83\xdf\xdf\x94\xf6\xfc\x05\x19J\xf8\x0d\x9d\xa5v\xef\xe8*\xe1q\xde\xf6\xda\x9f\xf4\xf0\xf0\xbf\xbc\x87\x07e\xb0u\xb1~\x82U\xdb\xef>e\x00\x91\x8e\xad+\xc5sE]\x96\xce\xecn./\xee\xac\xdc\x84\xd8\x86\xed A\x0df\xef\xe0\xb9\xf1j\xb4J\xa1\x04\xd0P\n\xdc\xeb\xce\xc6\xf9\xf3k\xd3\xf6\xfa\\1)8U\x89\x19\xb2\x8a\x05;\x82\x02=\xa2o\xc2=\xf7\xf3\xc9\xd3\xd7\x0d[\xb5\xd9\x1f\xa6\x91\xad\xa7\x90o+ \x16\xea\x8b1e-\xe0\xf8\x15\x8d\xe7\xd09\x9f\xfb\xbe\x91C&\x1b\x95c\xb4[xtNa\xb2f%\x84\xda\xf7C/\xda/.3\x86NZ\x93\x00\x0d\xff\xb2\x99\xc09\x8c\xf2L\xc7uKJ\xbe\xccy\xbc\xe6\x87{\x17\x9ct8\xcd\xfd\xd2\x04\x1b]-\xf4K\x98|\xc4\xae\x9a\xfc\xb6\xb5\x1b[\xf2\xcc\x99\x90\x06\xc4$\x1d\xdaq\x06\x0b\x85\xbb\x10\x1dJ\xe5\xcb\xdd\"\xd1\xacEUq\xa4\x9a`UU\x00\xf4\xb2-|\x07@\xdf\xb1+\x17\xce\xd7'W\xff\xf6 \x89\xbc\xcc\xd8v\x93(\x08v\xc0\xf5.U\xffPw\xe0\xf2[\xc2\x1d\xefp'\x82r\x8a\xb8\"\x1c\xae\xd45!X\xcd\x0e\x8f\xfd\xda\xb8\xf6\xbe5\xf2\n\x0c-'g\xb1\x97d\xaej\x9c>AR\xa34\x86\xb6c\xde(\xdf\xa0l\x07V\xac\xe8\x7f}X\xc1\xd4*\xc5\xe5e\x9cH/\x0b\xc67\xc9\xcf\x06\x9c5\x81&5\xc4\xbdLKp+\xef\xf8c\x0f{\xd8h-\xafU\xde\xc2\xcfT\xee\xe3\x08r\x1f\x17\x9e\xf6y\x8d\x99\x1e\xb2*V\xa9y\xd4\xe9\xb2\xb0\xdd\x91\x8f0\nT\xf4\xc3Ag\x8aG`\xc5\xfeG\x13#D\\Yj\xae\xe1\xd6 0O@k\xa14\x10Bi \x84\xd2\xa0\xa1\x9eV\xa6\x13!\xef\x8b\xe3#+\x9fK\xa2\xd1j\xba=\x8c\xf6\xc3\xef\xf3C\x89\x88u\x0d\xc8\xdca}\xf4:ls\x7f1\x8d&\xeeO\x8e\xa5\xf1\xd8\x19\x16O\\\xa9\xa1,\xd5\xb4Rr\xc0n\xa7\xac\x9e:B\xcc\x12\x93\xef\xc8\xa4\xa2\xf5u\xe7\xe5\x9d\x8cyX\xf65\\\xbb-\xe3\xd0\xe1\xcaA\xd3\xa4M'\x83v\xd9Q\xe6Iw\x16\xf1\xd7P\xaaTs\xd5\xf6^z\xe9\xb9\x1b\xac\x8b\x84\x98\xea.\xbe\xaa\x07N\xff\xb2Z\x95hT7\xc4\xc3\xf4\xb7\xf9j\xa4\xd6\xd8\xca\x8a\x8b( \x107\xa1\xcd\x9bYTs\xfdd\xae\x9dp\x1eIE\x06\xafs\xfaTW\xe3T\x86\xb5\x0cf\xaa95[GX\x85RV\xe4\xb2z\x0c\x9f\x92`2\x85\xe6`z)\xa8p\xa7J\x9f$\xbbh\xc2\x8f\xb1\xc9\x06\x04\x0f\x90\xcc5\x1c\x8d\xd6\x11\xf08\x13\xc4\x8c\xe9\xcc\xf9\x91\xa9\xd8\xe9J\xc4o*\xd1L4|\x9c\xf9w\xfah\x12\xfd\xd3'\x9e\xebwhT\xba\xdd\xf6\xf1\x9b\xc7\x07]\xd6b\xad >\x1c\x13(\x94#\xe9\xa8o\xe8\xa6\xa0\xa2\xbb%\xaa\xda\xf6\x1b\xe6\x18J\xfe\xdav\xba\xf0\xdc@h\x8eP\xdby!\xe7rl\x95\x9f&2\xf3\xa9,l\xac\xe2\xf7\x8b\xd0S\xe0\x9f\x96\xeb\x043\xa9Y\x03\xd7xi\xf9i;\x01\xfd;0Z:\xef\x80\xe1:D\x1a\x0c\x92\x11%g\xc7e*\x92\xa5-t\xacq\xddF5\xb2\xe8\x8b[\xb9f!A\xca\xbd`&\xec\x87\xc5Zn:\x89\x98/\x17\x92\x8cY9u\xd7-\x0b\xc8G\x1eg\xb2\xa8\x96\xac\xff\xd68\xc4@\xae(\x96\xf7\xa7\xb1\xd7O\xc3%d\xbb\x8aWP\x87\x1340\xbb\xe5\xa9\xda\x8d=\x9e\x01m\xc4\x94f\x04M\xf0\x8d\x97\xaf\xfeC\xe1U3\xe5\x97\x84|\x14\xe7\x19\xf7\xb6\xb3\xc3@\xe6#\xae\xad \xd6\xb4\xe5\xf4\xd2(\xc83\x95S;\x99\x89\xa3T\xc6\xea\xd4W\x93\xf1\xf7\xec5v\xbc\xed\xe4Y\xf4#X\xc7\x1f\x0d}\xcf\xe3a\xe78[\xa8\x02:\xc7\xeb\x99O\xab\xef\x1fp\x0f\xf7\\\xbc\x90f\xafidx\x99^\xf0U\xf9\x1fG\xf0\xe0b\x91^\xad\xa7\xd221\xbdm\xa5\x9cN\x97\xb5\x8f\xc8wTZi\xe6d\xbe\x0b\xae\xd3\xe5\x81\xbd\xf4\x12\xf3eZ\xe0v2\x13\x8dy\xd2\x0f\xa2}v\x94\x15\xff\xb8Z\xf9\xd7\x1b\x9d\xc2\xdd\xde>\x17=\xd3IX\x88\x14\xc5 \x960\xc0\xf3\xdaT\xa9\x93\x8d_\x88\x96-\xb0\x86D\xe7\xba\xec\x02\xab\x89q\x13\xbf\xcaQ^`\x83\x06,.\xb3\x9f\x056\xae/I\xa4\xae\x056\xb4\x13\x1f{\x1b\xa5{\xe9\xfa\x95\xa8r\xa6i\x1d\xbf\x18\xc3\x9e\xccM\xef$\xf5UZ\xac\xed\x01\xb4_\xd4{\xa44\x8b&\xa9\x1e^;\xf1\xbb,\xb7SgDX\xb2\xa1\x9fvY\x9d]\xd5\x08\xc1\xa9\xd5\x90\xed\x1aCv\xda\xe9J\xeb\xed\xec\xab\xac\x0f\x8f\xf8\xf5\x8f\x1e\xed0\xf7z\xbfj\xc8\xee7\xbf\x16/\xd8\x9cO3\xa7\xc2 \xe5\xbb\x83\xc1\xcc\xcd\x9b\xd2\xb9\xec\xe6M\xed\x12]\xf2)\x0f:\x1d\xe9a\xa6L\xe2\xbc\xcb\xae\x8b\xba&\xc9\xb2\xdb\xe9\xc8\xf0\x99(\\\x8b\x1co\xa2\xfdL\xff4\x07\xf6g\xe2$\x8a\xd3\"\x93\xc2L\x16\xc1\xc1j\xca5\xc0\x14\x17F\x92G8\x939\x83\xae|\x04U}]\xf5\x1a8*\xbe2\xadH\xb0\x82?\xd4\xe9\xc4p\xc3\x10\x12G\x02{V\"J\x96K\xe6\xe9\xbc\xb4\xd2\xf06<\x92I\x82.\xaby\xf6hO\x88=\xad\x84\x87\x1eOj\xcc\xa6\x8a\xdaL\xbc]a\xc5\xa0Rdq0Q\xaai\xec\x84\x84\x9c\xd1F\xfa\x0b\xf0\x9c\x04\xe0Cm\xe1\xbb\xdd\xda\x9e\xb8z\x90B\"F\x1d?\xa7\xab|\xa3\xd3E)\x19\xee\xb6\x8b.\xcc\x15\xf37\xda\x87\xe7\x1bG\xfaCi\x176\xff\xfc\x1d\xd9/\xfd~G\xf6\xbf8\xd9\xb7\xe8\x85\x9a\x13d\xce\xe0\x0b\xd3\xec\xf0w4\xfbw4\xfb\xab\xa6\xd9\xcf\xe7\x1ag!?\xb5It\xa28='\x13\xb2=\x87\xe3R10\xc4Kt\xba\xaf\x93\xb3\xa7-L\xe3E\xe5\xfb\xfa\xe6\xeeG\xa3\xb7(\xc9{gy/\xa5TA\xbe\xd5~\x86\x85&`\x13\x87\x0f\xfc\x97\x85\xa1\x93\xcc\xd4l\x8a`\xa8)\xed\x19\xcc\x04\xeaB$\xf9tlD\xff\xa6\xf5\x1e\xc2?U/\x91\x0f\xc0w\x1b\xbc7'\xb6f7\x9a\x19h\xb3\n\x03\x13\xbf\x98F!\x9e\xfc\x146L\xf6%\xe6os\xe3jwf\xa2P\x90\xdc\x80g\x96G!m?\xb3\x8c/\xbd\xc4Zz\x10\xe5@\xcdP^\xec\xa6<\xdb\xf1G<\xca\xa5\xbb3<\xb8\x7f\x86\x1d\x99\xeb|\x95+_\x0b\xad1s\x92\xaf\xd3\xd2Y9\x15\xeb\xa1/\xefF\xf9\xbd\xc6\x96\xe7d\xce\x82?r\x06\xfcx:\x1e\x1c=\x18\x05\xaf\xf6\x9c\x94\xbf|\xb2\xbbya}\xfe\xda\xe1\xd9\x13\xce\x95\xadYgy\xd6\xbftkq\xdf\xbd0\xf0W\x97\xceF\xd7\xae\x04\xa1s\xe1\xf5\xd3\xab\xb7V\xf7/]8{r\xd5_\x1c\xf0\xf3si/\xbctzu4\x9c\xf5.,\xbe\xbcvx\xfa\x84w\xc2\xcd\xbd;\x97\xf2\xde\x89\x8b\xe1\xda\x9d\xd5\xfdK\xcb\x8bc\xf7\xc4\xb5p\xd5?;\xef\\\xb9|\xe2\xf5\xd1\xe9\x93\x9b\xdb\xab\xfb\xab\xcb\x8b\x83K;\x8b\xfb\xab\xcb+\xfb\x97\x96V\x07\xee\x85\x8b\x81;\x7f\xf9\xd0\x1b]>\xeb\x9e8\x1b\\=\xb1\xb5}\xf5\x8d\xad\xb8wg\xd6\xe7+s\xf1\xb5s\xc1\xbas\xe5u\x7f\xf5\xfczz\xf5\x8d\xf5;\x9b\xdb\x17\xd3k\x17.e\xee\xe8t\xda;\x1f\xe4\xd7\x0eW\x07\xee\x89\xadS\xbd\xf3\xbb\xa7WG\x17\x87W\xe7\xb3\xd0\x1d\x9d\x9e\xeb\x8d^\xcf\x9c+s\xc3k\xf3\xbb/\xaf\x9e?5\xee\x8dv\xbf\xb3z\xbe\nw\xcf\x9f\xbe\xe3\x88\xbe\xe6O\xbe\xbcz>\xc8\xc5\xdfW\xaf\xec\x0f\x9c+\xa7b\xef|0\xec-\xa7\x83\xab\xa3s\xb7\x9cy\xef\xb0w\xe2r~mi\xee\xf0\xda\x1bg\x83\xabo\xbc^W\xde\xdf\xbcup\xcby\xe3\xe2\xad\xde\xf9\xdd\xc1\xd5\x13\x83\xd3\xab\xb7v\xf7W\xfd\xb3\xb7\xf8\xce\xac\xbf\xbe\xb3\xe8\xaf\x9e\xbf\x16\xf7\xce\xef\x9f^\x1d\xc91\xf9\xab\xe7O\x85kW\xce\xcdz\x17V3\xf7\xc4\xd6ao>\x0b6\xb7/~\x87\xcf\xaf\x8f{\xa3k\xf1\xb5\xc3S\xb7z\xf3\x07c7\x9c;\xbd\xea\x9f\xcd\xaf\x1d\xce\x0d\xbd\x0b[\x87ko\xac\xcf\xba\xa3\xd3\xc9\xb5\xed9\xb3o\xfcDv\xab7\x7fj\xe4\\qso>\xd8\xf3\xce\x0fO\xf7\xb7W\x07\xbd\x91\x9b]}ck\xd6\xf5\xe7\x0eQ\xdb\x87W\xafl\xc5\xde\x1b\xeb\xb8\xdc\x1d\xef\xc2\xc5\xb13\xbf\x9b];\x7f\xee\x8es\xfe\xdc\xa1;:w\n\xd5\xdd\xbb\xfa\xc6zt\xf5\x8d\x8b\x87W\xdf\x08d\xfdb\xfc\xab\xb7\xd6wv\xe7\xc4\xffV\xfd\xb3\xa6-\x18\x93X\x93\x15\xb1&\x87\x9b\xdb\xabw\xd6K\xf5\xd6\xael\x0d\xdd\xf9\xe1\xd0\x0d/\x0e\xc5z]\xda\xb9:\xbbvk\xef\xce\xa5;W\x0f\xd6\x97/\x1d\\\xba\xf3\xfa\xfc\xfa\xf2\xca\xdc\xea\xf2\xee\xfc\xda\xad\xbd\x13\xebw\x06'.\xed\xbc~g\xfd\xce\xe0\xf0\xd2\xce\xa5\x93\xab\xb7N\xber\xf5\xca\xa9\xb8w\xe5\xdc\xec\xb5\xcb[\x87W\xaf\x9c\xbasmt\xfa\xb0\xb7}V\xae\x99s\xe5\xe2\x9cw\xfe\xf2\xc6\xd5+sb\x8dg\xdd\xd1\xb9\xdc\x9d\xbf6vG\xb3\xfe\xea\x85\xadS\xae\xc0\xa1\xf0\xe2\xd8;\x7fn\xf6\xda\xf6\xea\xe0\xea\xfc\xb9\xf4\xea\xec\xdc\xf8\x9a\xc4\xad\x83\xb87\xbau\xf9|\x90]{\xe3\xd2\xe9\xd5[\x8b\xdf\xb9\xb4\xbd:\xb8v\xe1\xb2\x98\xf3\x81{\xb8:\xb8:\xba\x1c:WN\x9e^\xbdu\xf6\x8eX\x0b\xc0\xab\xade\x81g\xde\xf2\xac\xef\\9\xb5w\xed\xca\xb5\xb87\n\xc4X\x8en.\x9d\x1e\xf6F\x81\xd8\x9f\xe0\xf2\x85\x8b\xc3^\xb8>\xea\x9d\xb8\x98m\xde\xda\x1f_\x9d\x0f\x0e\xaf\xce\x1f\x04\xe2oq\xe66\x07\xd1\x99\xd67D\"X\x8a\x82\xc0\x89Sx\xbab\xcd\x0f\xf7\xe4\x1f\xe0\xcb#\xff\\\x0d\xe3\x1c\xfe\xda\xe1\x07\xd9b\xc2!\x0d\xea\xd9<\xcb\"\xe0\x16[\xd2KX6\xa5\xfe+\xb3}\xcb\xb7{\xeb\x82\x11\xa5\xff51Ch\xcf\xecW\xac\xafS\xf6mF\x10G7f3i\xf4mF\x90T\x01H\xef\x81\x02\x10#\x88\xab\x00\x15#\x88\xf4\x13\xb7\x9b\xbf\xbf&\x87m\xdaqLx\xbd\xb10p\xab\x85!3\x16\x06\xae^L\x98}\x95\x85\xec\xbb\x8c\xbf\xca\xc2\xa3G;L\xc5\x0d\x17\x16\x86\x10\xa9\xe1jb\xd9tI\xa3U\xe9#G\xd0\xac:3\xb7\"?l\xb7X\xab3\x93%\xfe\xa8\x8dEg&\xb5\xfc2f\xd5wd\x96#\x9b\x14\nLl \x99R\xdbSb\x1c\xc9\xa8a\xa4|G\xdc\xe9(\x99\x05\x8a\x17\x12K]\xec+\x1aIPj\x0b\x9e\xdfE6\x85\xccj=\x98`9\x98\xd6j\xa0\x11\xa4\xd0\xd6\xebET\x95\x834\x0f\x82\xd4M\xb8\xed\x81)\xfd\x0bM\xc9\xfa2\x96\\q\xbc\xcb\xae\xb7\x8a\xf6e&\x9d<\x08j\xdf\x1e\x93\xc9\xec\x8cg\x8e[k\xf5\xe0 \x88B4\xaf\xad!\xed\x84\xd4J\xf7\x9d\xc1\x80'\xc7\\\x8dn2\xabN\xc8^c\xadcr(l\x81\xb5\xea\xbc\xc6\xa7\x1fG\x9b>3\xe97\x99e\xdc\xc0I\xd3u\xf9XZ\xdc\xf6g\xcc?+\xafj\x95\x7fw'\xbb>\xde\xe8Tb\xfd\xdb\xae\xc5\xceR\xa5\xde\x1e\xf1\x97\x1bE=?\xe0bI\xaa\xfb\x9c9\xbd\x80g\x0b\xacu\x0c\xfeB`\x8f\xa7{Y\x14\x0b\xb8\xfa\x13\x15\x08\x9cd \x9a=6\xf4JW\xb3\xafV\xe8A\xf0;J\x00\xbf\xdf\x1a%\x18\xfa^CV8\xa0\x01{\x9c\xc7K\x90\x8d\xb3\xa1=I\x0b\xf8\x0c\xa0\x93\xd0\x02\x01m\xba\xd2\x9bB\"\x88\xf8Sb\x05\xf1\xdb\x90DC\x0cE\x90\x8brw\xe2\xdf\xd0\xa2|\xabQ!\"k\x19\x94c-\xd9b\x8b< k\x86%\x93\xf1\xbe\xf4\x12;\x12NAe\xc0\xb6*C\xe8\x9b\xa9\xcc\xf5\x1a{\xb6\xe1\xd89\xf3C\xe65\xbb>z(\xedG;\xefL\xd2\xf6\xf5u\x83W\x1b\xec\xa4\x7f\xa2\x83\x1c\x1e\x0d2F\xdc)L :\xc8\xa9\xa85\xb1'\xa6z\x0b\xd8w\xd9\xdc4}0\x99\xd4Q\xbe\xe5\xd2\n\xa3\x90\x0b\x02=mT\xad\xa0\xea~\x98O\x91hob =\x84^\x10\xb9{0\x86\xae\xf9\xe8F\xc11\xf9(\xa5\xfc\xde\xd8\xd6\xf3\xda%t\x0cW\x8c\x0c%\xd7K\\\xc1\\\xca8u\x88=\x11\x97\xbf0\xa7J\xb3\xc3\xa0\xf6yl\xfd\xf3\xfc4\x0e\x9c\xc3\x05\xe9}\xacv\xd1\xf2nG\xf9\xd7`9+1\xc7\x9a\x14J/\x86\x19v\x8d\xc2\xf3;\xb6\xf3\xe2\xd8\xce$T\xf4\xfc\xb1\x1d\x0dK|jZ\xc9\xa9\xa8R\x16\xa1Z\xfb\x89\x13\xc7<\xa9u\xd2{!\xd8S\x1c\xc4vI\x85\xfe\x1d&}}\x98\xd4\x93\x8b\xfeU#\x93\xea\xe5+\xc5\xa5\x8e\xfe&\x98?\xcd\x91Y\x1af\xabF|.\x19t\xeaQp\xd2\x82f\xfc s\x12\xee\xb4*\xb7\xec2\xb5\x936\x1d}\xf1\xc6}\xd1\x02j\xb9r\x86\x8c\xa1j\xaa3Tw\xa1Ws\x80(\xdb\xd4\xe6\xab/z\xb0dV6(-\xc7b\xe9b\x08\x85lo\x81\xeb\xe8\xcc\xba\x17 \xd4jB\x00\xa7<02\x15&\xfc\xb5\xc0\xf8\xcc(\x0f2?\x96V\xa7\xeb\xad\x96\xf4\x0bo\x89S \xaf\xf6j\xb3\xac\xaa\xa3\x17Q\xa4\xedZ/~\xf5\xef\x1bC\x13\x9e_\xa9Q\x0f\x0d^\x16\x1d4\x14\x06\xedF\xafj}\xb9\xa4hte\x14g\x87\xb2\xdd\xfa\xe2\x91\x1e\xab\xdc\x17\xd8?\xf9<\x12{\xcd\xfe\xbd-\xb3u!\xc8\x17\x15\xfa\xc4\x81jt\x0f)Q\x16+\xf9\xab\xad\xa8\x17\xaa1\xab\xac\xc6\xb6\x86\xe5 \x97\x86N8\xe0\xc6?\x05\xfei-/P\x94\xbdV?\xdd(V\"n\xfdt\xd5\x80Z\xf6d\xd6w\xbb\xacu\xecX\xab\xa3DWA\xf6\xaaq\xca\xd3\x054|\x99\x012}R\x1a\xa2 Y1\x91m\x999\xb7)}\xfd\xddnQ\xe8\xb7\xc9\xc2\n|92\x87\xac\xfe\xd5\xa3T\xbd\xd7\xa8\xda\xab\x86\x93BM\xcb\xd4\x81\x9e\x99\n\x8a\x95\x9b\x9a\x18\xf2\xc9'\x91\x1a\x08\x9e\xd6m7\x93\x83p\n*\xe3K\xab\x02\x84\xd7+N3\x939\xc9\x80g3\x80Ei\x83\xf3\xb43\xe1\xa5\x1b\x01\x8f\xd8k\xcc\x9f\xce\xd0\xaf\x7f\xc6\xb7\x06\xe8\n\xb7\xfb\x91\xdd}\x9e\xe0~\xd3\xa4\xc4\xe7\x9a\xf6\x04=\xd4\x93\x97\xe5\xba\x103\x04\x81!\x13\x0f\xbbS\xd3l\x17\xdc\x1a\x12[\x88>\xc2\xff\xeaR\x8f\x85\xd0`.\xd8\x9a':A\xe8g\xbfe\xc1\x9f\x91\xb9\xb2\x17\xc2\xec\xd9d\x86\xcf\x9e\x83\xe9\xb3)\x88\xab\xf3e\xf4\x00\xe8 X`\xad0\x8ab\x1e\xf2\x84\x85Q\xc2\xfb\x9fCe\xd5e\xb0\xce\xb6\xd1\x8c\x98c\xf3\x04\x9d;\xf4\x03/\xe1\x96\x90\xeeIK\x0e\x9a\xbc}U'\x9a\x8d\x86\xdc\x1f\x0c\xe5c\x13ymR\x18\xf1\xebE\x89\xc7\x93\x05eUj\x10H\x9cd\xe0\x87\x0b\xac\xe1\xa1\x92\xd8\xf1\x95\xfa\xf2O\xc9\x04\xb0\x1ee\x8b\xa1?r2\xee} \xc9_\xdfN\x17'\xccO7\xc4Y\xf5\x1a\x84\xc2\xb1\x8e\x19,\x1fL\x85\xf0\x82\xb1\xd4\xe2v\x18\xa5n\xe2\xc7\x99\xbe\x00\x98@6\xef\xda\xce\xc1oO\xe5Q\xab=I\xdb\xd1\x0b8I\xdb\xa9'\x11\xac\xb41\xec5p:\x0e\x95\x8f1,\xfc\xc4\x9dI:F\xe3!\xe8by\xb3\xe3\xc5\x8b\xa6z\x15,\xa2\xa9\x1a\xc6\x82v\x00d\xec\x9b\xe1\xffK\x9dp\xbcZ'\x1c\xcf\xe6j\xe3\xeb*6\x1f\x1c\xcf\xe6j\x93+\x8057\xa2gs\xb5 \x14\x80\xe4\xecw\x15\xe0\xf4+\xa71\xa8\xaf@sd`\xb1\x86\xd8\xfdt\xbc\xaf\xc7OG\xffE\xb4\x91\xe7\xa5\xf5E\xfcQ\xd2\xb5\xa5 \xc1d\xbc\xd6\x8c5!\xee(\xa8\xc4\x1d\xb9\xe0\x15\xe4B\xdc\x91{\xf4h\x87\x05\xd7\xdd\xaaW\x90k\xb9\xe0SK)\xa8\x866\x99\xe5\x84\x11\x81\xdf\x19aF\x115\x9b\xd5\xc5\x1c\x052\xe6(\x99\x19\xf0\xecR\xe4\xf1@HO\x13E\xec\xd2\xf8\x94\x17?7^\xfc\xad\xdf;^z\x15\xfbxKf\x93+2\x87\xfd\xe1\xcc\x1f\xfc\xde\x0f\xca%~p\xfcx\x97\xb5\xa4\x05\xc0\xd6\x96k\xd2\xd8\x1eO\xdd!\x1f9\xa4\xc9\x9aB\xbaQ\xd0\xca\xc8\x14\xee\xaaIo\xf1\xfe\xb6\xac\xf2<\x93N\x14[\xab\xbc\xbf;\xd3\xf7C\xafx\xde\xdbf!\xb8\xdb\x85\x9c\x14\x84\xa1'\xc4 \xa5V8H\xad\xc2\x81\xf3<\xc2\xc1\xd7\xca\x18Uj!\xb9=\xcdJ:\x9f\x98\xff\x94)2\xca\xa7}\xf9\xd8\x81\xc2r\x83\xebK\xe5\xb2T\xc2o\xe7~\xd2\xc4\x99SY.l4\xd2\xb9\x8a\xcbo\xf1~}\xa1\xbe\x99\xc3f\xeds\xf9L\x11`>\xa3nz\x9b\x8d\x832\x8dd\xbb\x05\xecN\x9e\xe4V\x83\xb9b\x08\xa5%\x95\x9aXx\x0c\x857\x13\x7f\xe4g\xfe\x98O\xac0bgX+\x92#i\xd0\x1e\x06\x82\x04\xc2\xab\x902)\xd0\xef\xff~\xc2\xfbuna2 \xa9|\xccx\x00\xe1\x0f\x1a\x07\xcbt\xab=\x10\xb4\xec\x88S\x14sJ\xc5\xccIo\xa7P\xcc\xb8\xa3\x04\xb5\xd6\xdcI\xa1~\xe5[\xa2\x91\x18\x06\x93\xff\x7f,\xf3\xb3\x80\xd7Z<_`\x7f\xd0\xd3\xcd\x9b\x19?\xc8j\xfb\x8b\x05_\x10\xbc\xa8\xb6c\x7f4h\xec7M\xdc\x05\x16\xb6O\xce\xcd5!\x95V/\xe7g\xe3\x83\x86\x8d\xdf\xf7\xbdl8\xb9\xd8Du\x96\x19\x15t\x8d\xf7E\xbfs|4\xe9\xa5=\x95\xbcL\x92\xc2\xc0\x11\xd8<\xa1F/\xca\xb2h\xb4\xc0Zb\xb0\xb5%k\xe2_\xea\\G\x04\x15=\x94\x89\x1a\xfctcq\xfbD\xbbS:\x07\x1e\x8f\x13\xeeJ\xcd\xad\xa6z\xba\xef\xcbL\x84\xae1:J\xbe\xe9\n\xa5\x8c-\xb0#G\x06]y\x06\xcb\xa7+;\x8c9\xbc\x997j2\xf9\xb8N\xca\xcd\xd9]h\\\x99 \x87\xc7\xa3\xb6\xa1\xc6\xe6\x18Bo5\x86\xc6:\xcfelb*\xc0N\x90\xdc\x05\xd6@\x9d\xf5\xaf\xe0F\x8d\xf7)\xfa\x07\\\xa6\xf1\xa12\xfd\x0b\xe5\x14\xa7xL\xbf\xc0\x85\x05v8\xb9\xb8d;\x0b\xccm^\xb4\xa6\xcc\xb1\xb0\xff\x8e\xe0\x0b_n\xfb\x87_r\xfba\x08/v\xf7\xff\xf1m\xa8\x96I\xea\x1e\x8b\xd3\xbf)\xf6T\xbd\xf8X\xbf\xa9P,\xccG=\x9eL,\xe6\x87\x19\x1fLQ\xae\x17E\x01w\xc2\x86rZ\x03\xfc2\xc86\xfe\x92vh\xa6\x91C\xc9\xa9\x13\xef\x02\xd9\x7f\xe9\xd8d\x85O\x8c\xe7\xac\xb5\x0c\x95\xb0s(\xb7d\xe70\xe6\xd4,\xa4\xd7\xa8o\xf6YZ\xa2\xb9w\xc9\x89\xa5Lm\x93\xd0\xab\x1b\x17\x9b\xaaB\x97i\xae\xa46o\xca*\x15\x95\xa3\\\x0b8Um=\xd8\xcd\xa28\x1c\xc4j\x99\x92\x88?\xa9\xa8\xa2\xf1E!q\xc4\xaaE\x8a}n*\xc5\x0fbG(\xac\xb1`\x87EA \x00hx\xd3\x14*\xf1VS.\xf0\xd3\xf2\xc2\x14\xa8Q\x8d\xa6\x87L\xa5\xbf]\xfb\x9e\x18Q\xea\x08\xdd\xfd\x8e\x0c\x90\n\xa8\xc1/\xb7Y\xd6\x84\xe6\xda\xce\xc1J\xd6\x95EN\xce\x9d\xea\xd8\x8c\x7f\xb2\xd0\xec)\xab\xfdO\xc2\xe6N\xd8\x0dm\xf9\xd7kh36\xb0\x19\xc7\xf3.D\xd1^\xbb\xd5\xe3\xfd(\xe1\xdbjy\x14\xd9M\x1b\xd3:\x9a{\xe6a\xc2\xfb0\xcc\x94g\x8bY\x96\xf8\xbd<\xe3m!\x80\xb7\xba\xf6\xdb\xbfN\xb74LlzM\xa7q\x89;\xfe\x87\xd7\x17\x8f]\xfbA:{\xec\xf4\x91\xd7~0s\xe3\xe8\xef\x1f\x1f\xa8d\xc5Ug8\xba\xda\xf5i\x98\x8a\x85\xd1\x88\"\xf0\x94\xae\xf5\xe2\xf2\xf2\xcd\xc5\x9d\x9d\xad\x05v\xbd\x05\x97\xe8\xadj\x86P\x92\xda\x82\xd5\xe6c\xc2C).\x11\xd3(O\\\x8bE\x00\xee\x19\x1a\xfc\x89\xfcBm8s\x06\xee\x0eZ\xd2w\xbc*B\x08\x95;mgE\xd6\xe6\xa4N{\xac\xbb\x94\xach\xabN\xb2\xe7E\xfbaU\xa4\xbbK\x0d\xac\x10\xbbq\x86\x85|\xbf\xb0c\xd6\x08\x8f\xc3l\x14\x88clg}\xd9a\x1c\x0d\x12'\x1e\xf2\xa4\xbeP/\xe1\xce^Z\x0f\x0f\xfcp\xcf\xef\x1f6\x17\xd8\x91\x9b\xbc\xc0Z7{\x81\x13\xeeY\xd2\xa8w\xd4EK;\xb3(\xd0\xae\xcc\x12\x96\xa3\x850w\xff\xafI\x15\x05\xf8\x9fq\x8d\x91\xe3\x8aa\x7fJ\x86\xa6\x01\x04\xb1FN \xd6\xeb\xd9Gx\xd7\x17/m.\xb0\xd6K\xa4|l\xf9\xba\x18J\xccy\xfc\xe7\xb84|\xbf\xf7!\xfd\xae@\x8f\x7fNA\x00\xf8K\nH\x83H>)\xf1\xec\xf1_P\xe0X\x02\xfe\x1b\x02\x90\xb3\xbbGvDz\xa6\xb6\x9e=z\x9f\x02d\x94\xac\xb5\xca(\x85\xf9`,\x02\x90\xe3\xc8\x16?\xb2\x03{\x12\xf8\xd8\x0e\x94\x07\xf2\xd1\x13;P\xf6\xf9\xe8\xa9\x1d\x08\xb3\xf8\x1b;P\xe2\xfc\xa3\x7fm\x07\xca\x85y\xf4?\xda\x81\x12#\x1f\xfd\x1b\nL2\xb9\x02\xbf\xb2A\xc6r\x8e\x0f\x08]\x01\x18L\xe3\xaf(0\x05\xfc\xbfGhE8HEo\x9f\xfc\x84\x02\xee8\x89\xc0\xe7g\xff\xfc?`T\x8c\x06\xd2\xee\xfa)9\xd0\x1a\x80[[\x8c\xe2>\x1c\xf5\x7fO\xaa(\xc8\xcf\xff%\x86\x88S\xf0\xec\xfe=\xf2Y\x10>\x89\x88d\xe9bID\x1fcJ\xe6\x00F\xdf\x7f@\xbe\xfbr\xc1\xee?$\x80(]`\xado\xe3Y\xc4qpxN1#+\xa9s\xe28\x89\x0ej\xc6-@\xfc\xb6u$\x8b\x89\xf4\xac\xb2l\x83\x06|\x80k\xa4.\x10\xcf\x7fI\x0e\xb1\x81\xfco\xa4N\xea\x0f\xe4\xc0\xef\xff\x8cT\x12X\xf0\x07\xe4\xeb\xe1\xa8f\x17\x04DM\xe6\x9f\xe3n2?\xf0$\x8d&L\xd1@\xfe\x07\\'\x17\x02G\xeb\x13\x82Q\xea;!!\xfbn\x14\xfa!\x1c\x14\xcc2\x9d}\x05\xf9\x08S\xf5\x9e\xe3\xee\xb9\x11\xd0\xab\xfb\xefZ\x80Z\xcf\xee\xbdG\xa0\x89\xa4\xbaO1}\xef9\xc9\x98\xcb\xb1<\xc0\xfd\x9du\x92}.1\xfb]\xcc\xbb{\x05\x08\xa3\x1a\x80\x80dS`/\xd9\x13\x80?%\xf3\xee%{\x99\x06\x92%\xab]\xeb\xb3 s\x90\xfd\x81\xcf\x98\xe7\xf6\xbc\xdby$\x97\x1dK\n=\xee:y*W\x0e\x8f\xec\xac\x04q+\xac\xd7\x08\x1b\xc5\xd9\xa1\\\xf4G\x98\x92\xf4\x04~X\x91\x83'a\x94\x8b:oc>qV\x82\x82\xc0Ok\xc0\x99\x9430\xf9\xeb\xa9\xef\xff\x0b\xfd\x0e\xa2\x0c\x1dB\xb6\xcf9\x1co\xd2\x89\x96\xb4\xc8\xbej\x00f6=\x7f\xe0\x02\x05~\x88\x05O\x01\x02\xd1\xf3\xd9/0 \x16\xb0\x1c\xaa\xe1\xc3\xdf\xf3\x07\x91\x17\xc1\xb9\xc4\xb2\x93\x80\xc5\x01l\xe4GX~\x12\xc0\xcc\x1fq\x80ZF\x93\xdeV}~D\xd0\xdd\x1f\xa4\x99#\xb9\xc5_\x90\xa9\xfb\x83,\xf1\xa5,\"\xf4&Q\xe6=rr\x8b2\xd0\xc3{\x98\xd6\xf4\xfcAnF\x8e\xa9W\xcf\x1f\xa83\xfa\xd02)s\xda\x1e\x92\xe5\xd8s\x92h_\x80\xde\xc7\xd4\xa2\x178\xee^\x10\xdd\xe1J\xb8\xfa\x10\xcb,\xb2@z;w\x12 \x7f\x0f\x0b<\x12\xae'%K`5\xa1R\xc2,\x0d\x968*\xa5\x02\xb8\xb5}\xf6\x0b\xb2;\xe5R\x89\xbaT~\xf6\x1e\x96\x02\xa4\xae- \xff\x023\x86^\xb077/\xeb\x90\x03\x12\xec\xcd\x9d\x94\x10BE\x82\xbd\x13\x00\xc1\xc2\xb2LO !\x98\xa1\xf5B\xb1\x18g\x9e\xfd\x183\xda^\xc8o\xe7\xbe$\x07\xf7\xff\xda\x02^\x07\x94~\x8a%\xc0^\x08\x80w\xb1\xbau\xd6\xc8B\xff\x07\xaebd!2nh\xeb\x01\xe9]_i\xdb@\xfb\x99\x0f\xe8E\xe6\x1a\x1d\xf4@J\xf9\xf0>\x05-\xaf \xc8\xcf\x7fa\x81\x04\x12\x82YT/:\xf0\xa0\x0eV4\x04D\xd6\xf9\x19^\x04\xd1\xda\x96\xac\x83%\x11\x01\x91\x07\xd6\xb2\x08\x07\x1e\xd4!\xa8\x10\x1dx\xb2\xce\xcf\x08O\x8f\x0e.\xc8*\x96\x01H2\xfa3r\xf6\xa2\x83\x0b\xcb\xb2\nVo\x05D\xb2\xce\x9fciD4\x06u\xe8.\x1c\x0ce\x9d\x9fa\x92,Z\xdb\x95u\xb0\xbe\" \x92\x95\xfc\x9c\xf0\xfc\xe8`\x08u\xb0\x02$ \xb2\xce\xcf\xc8i\x8e\x0eF~\x08\x04\xea\x01\xa1\xf2\xd1\x81&^\x0f\x08k\x8d\x0e\x0c\xd5}\x80\x15\xb5^t\xb0\x0b{\x8e\x95\x0d\x01\x01<\xc1\x82i/:\xc8\xa1\xce\x7fk\x81\x00\x9e`\xa5S\xb4\x06{\x8e\xb5N\x01\x01<\xf9\xa5\xa55\xa8ci-\x07<\xb1`\xddeY\x85\xd0\x92\xe8@\x9e\xfd\x9f\x11\xca\x16\x1d\\\x06\xd4\xb2\xec\xece\x89[?'\xb49:\x18C\x1dB\x95\xa3\x831\xe0#V\xb6Dk\xb0j\x844F\x07\x97a\xa5\xb1V'Z\x83:XA\x11\x10Xi\x0b\x0e_\x86U\xb3\xec\xf5eXi\x0b\xfa\x8c\xa1\x8e\x05y\xc6\xb0\xd2\x04\x0b\xeae\xe8\xb3\xca\x98\xf6k\xb2o\xf5\x80qO\xb2\xf7\x8f\xf1a=\x0bZ\x10\x95\xb7zF=\xfa\xdf \x84\x8f\x84p\xf7\xec\xad?#\x90:\xc9>Us!R}/\x8d\xc4:\xff\xe0\x07\x96\xefR\x85\xff\x90\xc8#i\x14\x0c\xd3\\\x02\x7fEHv\x1e\xc8m{\x93lu\x1e@j1\x1bH)o\x7fj\x01HM\xf9 \xb6L\x08\x08\xe8\xcax \xce\xe6F\xdf\xb35\xa7@\xb8\xd6\x92\xb6E~\x8a%3\xd7@~J\xea\x80\xfc\x88\x89\xbc\x12G\xefar\xe9:\xb16ta\xf9\xcbu\xe2^\xa2d\xc3\xc7\x98\xd5\xb9N\xac\x9a|\x8c\xf5\x7f\x01R\xb5\xf0\xe8\\'VB\xecc\xcc9\x96\x9c\xd8\xcf\x9c`\xd9\xef\xf7y\xc2\xc3\xccw\x02\xc9\x14~\x82w\xdaubPY\x1e\xff\xe7\x7f\x8f\x1bq\x9d\x04\xb6\xf3-,1\xbaN\"\x15\xd3_\xd3\x05;\x0c\xf8!h\x17X\nqu_\x8f1\x82.\xe9\xf6>\xc5<\xd35\x10Z\x87{\xbe\xd4\xc7\xc9\xb2\x18\x08\xe6YKJW\xf8\x14\xa3\xb4\xab\x01xc\x96J\xaa=V\xc0\\7W\xf3\xa1\xa3\xce\xe34\x95\xc7\xf41f\xf6K\xb0e\x9fb\xb3\x8b\xab\xbe\x93\xfdW\x93\xf9\x18\xcb\xa9K\x02\x1086\x90[R\x1b\xb1\xce\xe6J\x7f\x86\xd6\xc7\xf8\x84.\xf10\xe3\xc9\xb2\x1c\xc4\xc7\x98\x1c\xb9\x12\xe8\xd9\x81K\xfd\xc4\xbe\xdfZ\x9f\xc3D|\xe9\x02\xa8\xd6x{\xdc\xa1\xfc\xfe\x0fdC\x87\x1c$\xe5\xbf\xc4b\x98\x84\x8c\x9c\xc4\x0e]\x1a\n\x12\xfa9\xedF\xaa\xcd\xa4\x17\xb0\xe4\xfd\x82l\x00\xa0\xc6\xaf \xd5\xf0\x13W\x91\x1a,\x9f\nP\xc0\x9d$\x89\xf6\xb56\xf2\xce\xffY_\xc6\xe8\"\xef\xfc_\xd6B\x1eX\xc4\x9e=\xc0\xb2\x8a\x02k\x0d\xf8\x01\x96K\x14\xdcS\x06\x9d\x07X>Z\x92\xf0e%\xd0c\xd9E\xd5\x16L\xf5cL\x9c\x15l[T\xfcs|\x9a\xa0\xd9KF\xd2\xc3B:\xc07\xb5\xb0\x87%u\x00\xef\x18y\xcf\xb2\xba\x92c|\x88\xb5z\xd7\x07=\xd3\xb6\x1f}}\x8c?\xc2\x07\xd2\xf5\x93\x11\xd8^\x9fb\x0b\x82\xeb'\xa9B\x8b\x0f\xb1\xcc\xb5$\xd4\xb7}?\xe5KQ\x98Ey\xb2\x1af|\x908\x923\xde\xc3\x87n)\x88R\xbe\x94'\xc1\xe1r\x94\xf7\x02\xfez\x1ee w\x90-1%\x8b2dc\x82\xbc'\x97\xe6\x97X\x0c\x93\x90\xdc\xcf\xac\xc0\xa5\x08\xac\x89\xcf\xee\x91\xe3\xad \x0b\xb6\x1ap\x03\x83Ey\xd7\x80\x88\xfd\x16@\xb7k`\xa3\x91 Y]\xdbw1\xec\xff\x8a\x02\x80\xd5\x12\x16\x14\x8d\xe2>L\x07Kb\xae|\x19a\xc4\x15\xdd\xb6\xd5\x0c\xf8\x01`\xd7\xdbx_\x8d\x99\x90p\xca(\x1chv\x8bI\xddR\x14\x0e\x92\\ux\x1f\x0b\xbaK\x05\x0f!\x18V\x80\xf0\x11\xb3\xe1\x15-#\xb5t\xdb,\xb4\xfaNw N\"\xb8\xd6\"\xacI\x82r7\xb3C76\xaf\nR@d\x9e(>\xac\xfb\x9e\x02g\xc0\xe7q)\xca\x05?i%\xa2e\xa6\x90\xec!\x99M\xee9I\"W\xe7}26 \x93\xeb\xf3>^\x1f7\xe7\xb1\x84<$s\xcdy*9\xc7C\xacM\xb9y\xa0\x97\x1b\xdbv\x01$\xa7\xf5>\xd6A\x96\x94\xbd\x95\xf0i\xf8~\x0f\xab\x9an.\x84b%\xf9\x126\x92\xc7J\xfe&\xd7:nn\xe4e\xc2\x96s#/\x13\x11+\xd7\xf2\xf2\x03K\x83\x11\\\xe4\x91c\xaf\x84\xbc{O,\x02rn\x90\x92\x90T \x92\"\xe0\xfbX\x8dv\x05y\xe7\xb7\xe3\x84\xbb5\xdb\"\xe1i\xee\xd6mN\x12\x1cjc.\xd6\x80$\xb00\xe7\x12\\\xcd\x93D\x1a\xe6?\xc6J\xb7\x9b'c$\xb3\xd0\xad\xd7E\n\x91\x85N\xbc~d\xea\xba\x87\x0e\xaa|\x83F\x04V}\x83v\x0f_\xc5\xb8\x87\x81\x9b \xda\xf3\xec]L\x90\x97e\xaep\x01z\x13Sc\xaf\x00a\xc1\xd4s\x02}\xa3\x81\x0f\xd8\xb2\xdeh\xd2\xdc\"\x00~\x8aq\xde\xd35(\x00\xc4\xb171QXv\xd2!\\\xb0\xe1\xbd\xf14\xe4\x01f\xea^\xc9>\x8f\x97\xd5\xeb\x05\xd2\xd3\xe0\xd7X\xc8X6Z\x15\xde#\xcf@pc\xcb \xb3cv\xe2\xc1g,\x1e,\xdb\xb5M\xf0\xf5\xf8 >\xb3\x9e\xd7\xb0]z\x1d\x7f\x8a\x8f\xf3\xf2r\x94%\x0e\x984\xdf\xc7\x94\xd7\xf3\xa2,\x05!\xe41FQ\x8f\x0b\x0e\xff1\xd6\xe7\x969p\x1e\xac\x18,\xf3\x00\xae\xbf\xc8\xdc5\x00\xcf\xde+\xe9_\x18i\xbd\xbe\x9f\xc2\xd1\xf9\x00\xbb\xe0,k\x85 \x8f\xc0\xd3\x00\xb28\x17\xe0B\xe9\x03l\xeb\xf5\x86\x0ep\x8a\x9fb!Y@`=\xb1\xcc\xb0\xec;n\xe2g\xbe\xeb\x04\x8bun[\xa52\xa06\xfc\x1a\x0b\xa7\x95\x12B\xd6\xd5mQ,,J\x9eW\x9eT?\xac/\xb2\xa3\xae\xeb\x7f\x8d\x8dx\x9e\xefH2\xfb\x10[\\\x96}g\x14\x815\x86\xc0\xbc\xc90#Gcs\x9e\x80\xa75\x10\xb9h\xd8 N\xad0\xe4\x00\xf8\x03\x07\x04\xe3\xdf\xe0U\xf2\xfc\xd4\x97b\xeeCL\x18=y\x13\xf4 \xc1n\x7f\xec\x83c\x83\x1d\x12\x85\xc6\x94\xfe\x90 \x9a?\x8e\xc2\x03+h\xf9\"\x9ct\x8c5\xde-P\xda\xb1\x1c\xe3\x05n\x94\xc8\x81\xbf\x8b\xf9\x9b\x17\xb8\x89|b\xe0\xd9\xbb\x98\x0f{Q\x10H\x94\xfe}\xdc\xbd\xb9\xa9\xc2:\xb2gD]\xacH*c\x06\xde\x0e\xaf\x06q\xa3Li\xc2?&(\x16eJ\x9f\xc1$[B\x94Pq\x1f\xd3\xa0\xe5([\xb9\x9d\x83>8+:f\x01S\x0c\xae\x01\xd8Z\xc1\xb5\x9d\xf4\xd9}\x8c\x1f+\xb0hX\x0d\xe5\xb0fX\xca\xe1\xcbJ\xd2 \xaa\xc9\x8a\xba\x05\xc2\x83\xd5Fz\"cpU\x01\x1fR8\x9f?\xc1R\x1c\xef\xeb\x860cZ\xd1:\x066\xc3p\x0d\xc07FR\x8bz\xf6\x04o\xc5\x8a \x8b -\x19\x08fy| \x89\xf7\x132\xedA\xaa\x8e\xca\x13l\xe4\x05e\xed \x96\xe2VJ\x86_\xd2\x7f\xe0\x87\x19OdW\x7f\x86 \x13\x87K\xed\xb71\x93\xe2\x01\x0c\x0d\xef8\x0f\xcc\xd0\xf0\xda\xaf\xe8\xe8\x0b\xbc\xc6\\\x03H'B_\x94c\xc6\x04IBR\xb8\x86%@\x99ky{\xe4\x04\xc1\xb6\x91\x08\x7f\x81\xe5\xe3B\x17\xb5\xd7\xbf\xcc\x13\xdc\xc6{\xd8Y\x84\x8fRI{\xdf\xc4\x9cS\x00\xe6NH\x10V\xa3$H\xba\xbe\xbdI\xfa]?\xbf\xc0Z\x9f\x91\x83'-\xef\x9f\xe1\x0b8\x1e\xaa\xce1G^\xd1.\xfe\x0474\x80`\x87\xd1\"\xb0M\x8e\x1b-\x82\xe0`\x0cT\xf4!\xc1\x80\xd8IR\xe0\n\xd8*\xc3\xb5\xf4\xfe\x18Sx\xe5\xb4\xfb9&\xd6+\xc6\xd9\xfbs\xda\x8f\x01\xe1Z\x02$\xb6\xf67\x04p[_\n\x12\xba\xc7o\xd7\x931~[y\x97\xdc\xc7k\xcdo\xa7\x81\x13f\x83,\xb1\x1fT\x00\x07<\xb5\x9f\x16\xa3\x07=\xa6#\xcd\x1dy\xc4\xce\xd8\xaah\xad\xdf6\xa0\x9c\xc3\xb5\xe8}\xcc\x92Vn\xe7~\xe0\xf7\x12?\x97s\xf9)\x16\x18JN\x946\x08\xd8\xae\x1ec\xa5\x81\xdf\x1e\x17\x1b\x8e\xa5h\xaeY\xe0\x07d\xc3\x13Mq\xf1\xa1_\xd1nA\xd8\x10\xc55\x00\xf3m\xaeI\x0e\xd1&W\xd4\xbe=\xc6\xd7&\xbcnCW\xc0tE\xf8\x06|&|i\xe7\x82\xa0\xdb\xb8[\xb0\x96~\x82'\xb0\xa2\"%\xc8IV\xdf y\xc9\x13\xe9R\xff'\xd8A\x8a\x1f\xb8\xa2\xc2\x11\xf2\xd9\x87\xad\xbf\x87\xe9\xd1\x8a\x80\xa4V\x10?\x88\xb9\x9b9:^\x86\xac\xfa\xca\x01${\xf0\x9d@^/S\xdeY\x14\xb03\xd7\xbe\x13\x04\xbe\xbc$T\x96G\xc2d\xcf\x81\x98\x80\xa5\xe6>\x88 \x98\x82\xf6\xf9Hu\xf5K|\xf3\xd0\xef\xfb\x10\xf8\xf8\x9f\xff\x06\xcf\xb3\xdf\xd7\x10Z)\xd0 \xdc\xd59\xcd\xe4\xb1\x9c\xd6\xd7\x00L\xe2\x8a\x01`5\xe2\x9c\x1f\x04\xdc\xc3l \x13\\(ec>X\xec\xea\xdf\x82\x9e\xfa\xb70 p\xc0B\x87\xc5\xaeb\x9e\x18\xeb\xfbA\x16J\xf4x\x0f\x9f\xd3~\x18 \x06\xf0\x9f\xc8\x96\x19\x96\x81\xf5\xb3\xbea\x19\xf8\x10\x9d\x8b\x92E\x10'\xee\x91=\x88\x12\xa7\x1e$\xfdX\x1eb\xc3\x87\x00\xc0\xbd\x00\xe6g\xe7\xa2<\xf1y\x92%p\x0bL\xe6\x14;I\xa6\xfd\x1e\xb0\x10\xdaO\x1cW\xba\xb3\x7fL&& \x92\xa9\xff\x04\xd3, \x12L\xfdc\xbc\x9f\x12rJV\xc2\xc4_\x82^\x96 <\x01 zE\x82\xb0\xe0.@\xf30\n\xb2 \x02\x04}aF$@\xd2\xe1\xfec\xac(I\x08T\xc2\xfb%A0\nl\xfa\x13\xa0\x93P\x0bK\x19\x02t\n\xa6\x85e` \x82\x06\xb1=W\x80\xbe\x03 l\x13\xe8'\x0e\xb0\x97\xb7\x08%HT\xe8\xc3\xbbX\x08?\xa7y\x05\xd9{\xa3\xfbb\x81p\xa0U\xaf\xff\x07\xf3\xe2\xf3\xca\x08\xfd9\xdevm\x9d\xfe\x1c\xb3\x17Y\xc3\x13\x12\x08^\xb8\x81\x81\xe0\x15\x18\xc0\xcd\xed\x13l\x970\xa2\xc9\x13L\xd6\x00$\xf9\xfb\x13L\x8e\x15\x0c\xe6\x8a\x91~\xc0S5Yz\xf3.`0\xc8'\x988\x9c\xd7\x1c\x0b\xab\x17\x03\x0d\xc0\xec\xf7\xbcTd\x1fb\xda4\x00? ,\xac\x0c\x065\xc5\xfd\x11l\xce\xdbXx:\xaf\xaeN0\xa7\x1e\xa8\xab\x13\x82qpc\x80\x9b\x19Hg\xcfgO\xc8\x1e\x83\xbc\xf2\x04s\xaeApK~\xc7\xd3\x1d\x84\xea\x00\x92\x05\n\x8b\x98a\x0b\x10\x10\x98\xec\xc5\x9ckud]\x96U}\xaf\x82\xcf\xb4\xaf\x01X\xc6\xf0G\x0eh^\xb6\xb6\x06~\xe8$\x87\xab\xf6\xd5\x199\x83@\x9d\xe8\xb71j\x0b`\xec@\xca$\xbaw#\x99\xc5\xb4\xf5)\xd6\xd4\xfd\x91\xb4<={\x80Y\xb8?\x8a\xa5\xc3\xec\x7f\xc2\xf8\xb4:\x8a\x03\x1f\xd4\x1f\xe2`\xe2\x87l\xc1v\xf9\xe5\x87\xae2\xb0\xbd\x8d\xafc\xcc\xde\xdd\xc3\x8a\xb7\x84\xa8\xd0\xfd\x0f\xb1\xbe\xec\x87*\x87\x06\x99\xd1\xaa\xc2\x12\x82q\xea;\xd9\x8d0s\x81\xc6<\xc0B\x9c\xca\x08\x0d\xb1\x1a\x98\x81V\x9c\x97,\x8d\xf2\xa4\xae\xd9Uy\x11\xc8M\xf6$\x92X\xc4\x0f\xb3\xc0I\x86\xd2 \xf7\x11\x16\xda\xfc0\xd3A\x14\x1fa!q5\x1c\xfb\xa9/\x1d\xac\xc0fb![\xba\x88\x89qz\x0bK\xe5\xab\x1b@I\xb0m\xd5\x8f@\xf4!X\xabo\xbc0\xc1\xf35\x00\xdf%\xac\x1a\xae\x86\xf9\x92o \xd8\xac\xb5\n'\xf9s\xcc\x07\xd5 \xff\x1c\x0b\x16~\xed*\xf9Z\xca\xfe\x18\xb3\xf9U\xcd\x15\xc9\xe12\\\x11k?\xdaC\x92\xe2|\xea\x87Z\xf0&49\xf5A\xc8}HF\x9d\xfa`#~\x88\xbd_%DZb\x1fb\xca$@c\xfb 2\xfb\x0e\xeb\xfcS\x9f\xe2\xcbp\xdf@\x08\xc1\xcc\xf7\x00-\xb0\xee\xe1+\xc0?`s\xe8\xaa\xbaq\xc1\xac\xdbW\xdf1V\\\xd4\")\x9e\xfa-\x0d\xc0\xeb\xa8l\x1b\x18%\xc0\xb4\xf1\xf7xm/j\x06\x86y\xff-\x0d\xc02\xca-E6\xff_L\x1d/\x1a4\xc5\x87\xe4\x96\x81`}\xea\xa2\xc1!,\x94\xde2\x10\x8c\x90\x17S\x9e\xc0d\xf0\xce\xde\xd2\x90\x7f\xc0\xf2\xc4E\xbdQ\xd8\xa6uKo\x14\xe6\xf8\xdfw\xe2X\x9e!|\xe6\xf64\x00\x930 \x90\x97\xbfX<\xf9\xbe1\x8abo\xa5=\x03\xc1\xab\xf9}\x18/\xe9\x1d>\xe3\xbe\xbf\xafw\x0b\x0b^{\x1a\x80\x91zo\x90@B\xa8O\xb1\x90\xf5}\x15\x0d\x8cwdOE\x03cn\xf5}\x85qX8\xd9S\xd64,\x7f|\xdf`\x03\xa6\xf1{\x06B\xea\x18l\xc0\x82\xd6\x9e\x86\xfc9&\x9b\xc1\xa2\xd6\\\xf0\"\xae\x99\xfc\x02\xf88\x04\x06\x82W8pJ1\x04\xf80\x06\xce q\xe0\x16\x13\xb3\xff5g\xd4\xf3$\xbe`\xdc\x0f\x0c\x04\xabOk*k\xe6\xaf\xb0\xf8\x14h\x00\xdeM\x01\x80\xfc\x8e\x98\x11\x05\xc6\xb3\xccR \xcc\x8exC\xd7\x1c\xf9\xe2\x9a\xbe\xc4\xc23\n\x1cH\xb8\xf61f\xf0kZ\xab\xc7RK\xa0\xed\x00\x98\x85\x98\x986\x1b@\xc6\xf6\xfd\x14\x8b\x18\x12\xd2\x97\xec\xe0}|\xf9 `\n\x84e#\x01\x02\xe1\x81\xa8\xa2\x02\x14\xc8\x95x\x07\xcfH\x06\xd6I\x81\xe5}\x8a)\x89\xb6\xe7|\x80y\x8f\x80e\xb2\xda;\x98\xcb\xa8\x1b\xd2'\xa4\xa7\xc5\xcc\xf1\xa1'\x8a'\x06\x84\x89z\xe0@D\xf2\x13,\xfe\x0b\x00\x98\xa8\xfe5\xb5\x18\x05g\xd5\xb2\xbf\x8f\xa9E\xd0\xd3\x10|\x98\x03\x9d\xe4\xef\xaf\xb0n\x10\xf4\x12\xb0:\xfc\x91\x0d \xea\\\xa7\x80=9\xecGX\xd1\x16\x904\x00D\xc6\x1c\x12`2\x8f\xd1#\xcc\xac\xd6\x8c\xb7!V\xd0\x03\x03\xc1B\xca\x9a!\xbd\xf8\xf8\x05\x06\x82\xa5\xa4\xc0\xe5\xb0\x13\xefb\xd6\x13\xb82\x16\x15\xaf\xc1\x1a\x90F\xb2\xa5\xf0\x99t\xec\xb9R@}\x1f\xb3\x89\xc0\xe48\xc4\x84QB\xc0\xe2AN\x9d\x97x\xda\xe1\x143\xf1\xc0K\xf2T\x03\xc9.x`\xd2x\x87l5\x18!1 \x06\xf2r\x1f\x9fT\xe9\xf2/\x88\xcfY\x81\x07\xe01GhP%.\x80\x90\x81\xb5\xb2\x0d\x89R\x8f\x8a\x85\xc9V\xb7\xec\xedN(\x89)\x80\"\x04\xb0,g\xba\xd1\xc7\x90\x1cj\xd1\xd2\x12\xf7\x03H\xc7J\x91C\xc0\xc1\xf9\xbf\xbc\x14x\x19\xa1\x94t\xd7.\xf9\x8dc\x0b\x85.Ur\x1b\xc7\xb6\x9ej\x11\xed5\x8ei\x87(u.\x88\xa0\x8dw\xb1\xe9VLZy\xe0\xeb,\x7f\xc4\x1f\xbeT\x06\x02|\xdf!\xe7\x85\xf73\xb3|\xa0\x1ec+5\x0d\xf8 FaQ\xa4j+$\xf6\x99\x80\x14!\xadT\x8b\xa4\xb5[-\xcb\xa8iA)r>t\xa9\xf4v\xee\x0f\x8a\x1e1\x11\xb6\x05'`\x8a[\x8a\x9e!\xa1\xa4\nV,\x8c\x0d\x83\xab\xd8\x82%\x1d1\xd4l\x98p^\x84\x98\xe1\xd9\xc8FJ)\x1f\x1f\xe0S_.\xa0\x90\xe9CL\x9c\xcbe\x8c}\xf2\x01\x16\x93D)\x08\x92)\x0d\x19\x0b,P\xa8:-|\xa7\x0feJ\xa1\x1aXG(\x17\xd0\x07\x00\xeb\x04(\xda\x03\xe3.\x8d\xf4 \x82\xd0\n8\\S\xfc\x80\x0bi\xba\x19p\xc1CD\x1a}\xf3C k\xc9'\x80\x9e\xbe\xb4\xee\xbb\xba\x99#\xf2\x9e\xf1 x\x8c\xd7+(\xf9\x04`\xedM\xc1\xe4\x1a<\xc1\xb4&\xe0\xa9\x9a\xacE\xce\xe0\xa9r\\x\x82o\xd4\x03\x9e\xa6\xa5\xab;,\x81\n\xb0\xb6\x13`\x0dZ\xc0\xf8m\xe5\xf7jYc\x01\xd5`\xb25kO\xaa*\x14\xa1U\xa2\x08\x12\xb0 \xe1\x8a\xeeHrA\x94\x80\"\x95\xb8\x0d&\xcdC$\xc7x\x00k\xd9\xb6|\x06\xd7\x92GD\x18\xd0~:T\x1eOJ\x04\x92X{\x12\xa5\xc0R\x01=1\xb4\x91\xec\x00\xa4\x00z\x93X>\x12E3\x1f\x10\xca\x98:Z\xf9\xc6\xf8\xb9\xa6\xafF\x88dh\x8c\x92X\x98ZS\xaa5\xa1\x95\xb5\xdfk\xa4\x81\xc08}ac\x88\x80\x80`J8vz\xbbg\xb3\xc7\xa4z\x82\x041Rc] B\x92vb\xf8\x8c\xc8\x8b\x06\x82\xed\xbbk;\x0b\xac\xf5]\xfcQ\"\x05\xe5\x9a\x99\xa5l\xa0\x9d\xce\x08\xdd6Ng\x84\x86d\xb5\x82\xa4T\x8c\x16l:QP\xa8K\x84=e\x9a\x9d\x7f@hQ\xc9U\x8d\x98v4K&t$K\xe0:\x97hK\x81\x0e1&\x89\xf3\x83,\xd1\xeerdRy\xe2\x19\xc3\x0e9\xb3ybB\x90\xc9\nV|\xd0>\xb2H\xf3\xda\x07\xcd\x02S\xb7\xfa\x1f\xe3\xdb+\x13.\x83g0r\x80\x16\xfc%\xd6\xec\x04\x80\xc3\xe3\x1b\x04v \xc4\x89\xf71\x91\x1e\xc1\xf7w\xf0\x94\n\xfeT\x032\x96\x0dl\x1e\x03\xb0a)Xa\x03\xb0\xb2y\xe0k\x92\x91\x93\xec\x01\xc5z\x0f\xdf\xfd\x8et\xb6\xc5g\x1fa\x99\xf9\x12H\xa0\xd8\xbc7\x82\xcf\x98\xbd\x8eL\xca*l\xe5\x18\xe9H\xe6{\x98\xb1\x8f\xb8\x93\xe6 \xf7\x8a\x07\xb6\xb0\xf2q\x89{~>2Ndoa\x82{\x89\x07\x81\x1f\xeak\x01l\xf4\xbe\xa4\xd5\x01l\x88\x1bi\x00>\xe2\xa3\xa1\xdc\x9c\xb7\xc9\xea\xfb\xae\x0c?\xfb\x18K:*-\xe8=l(\x19\xf9\x9e\xfd\x8d\xa2\x91\xef)\xba\xf0\x14\x13\xd6\x91\xef\xd5\xa4\xcf-\xb2\xc0`\xb2.!\xf0\xc6\x16^\x1b \x82\xd1a \x0e@R]\xf9\x08/\x81\xcc\xc9\xaa\x13\xaf\xde\xc3\x8cq\x14\xb8\x90\xad\x10\xdb\x8fG\x01\xb3\xb4g\x1e\x1a\xa3\xb0\x0c\x1e9\xf8%\xa6M\x12\x02f\x85:\x18\xf8\xfc`\x1f\xbb\xb0'\x9d\x8c?\xc6\xd4:,R\xcc\xd3\xb1\x97r\xc9S\xa0\xce$\x89\x97}]\xdf\xe5|\x86\xb7*4\x10lz_\xd7w9\x9fa\xae\x11\x1a\x08\x96:C\x93r\x96\xf6S\xce9k\x19\xb9Jt\x89Q|\x1d\xc88\xd6\x14B\xf8\x8c\x15\xca\xd0Pw|\xbaT\x82_\xb2\xd4\\{F\xbd\x8fYU\xc8\xf5\xdd+V*D% y\xc7\nQ\xaa\x02\x85\x99\x88g2\xfdu>p2\x7f\xcc\x11\x1fy\x13KW\xba\xdc\xce\xd0w\xf7\xa6*\x16N.u\x99'\x87\xcd%Ko\xf5`KS\xc8S\xaer\"a[AX\x04l[&\x9cf\xdc\xa3A%$\x82\x02\n\x96-\x7fD\xde]\xe7\xfb\xca1\xf9\x07!\x19\x82 \xaf&\xf4\x86\x17\xf1\xd5\x18\xb6\xae\xf9.6\xb8\x85\x1a\x80\x87\x19\xea\x988\x8a\xd9*,\x0e;\x16\x86:\xce\xcd\x06\xb8]\xdfX9\xd6\xcd\x06O\xeb@:4\xccRI\xef\x13\x96\x1aB\x1d\xd6b!\xc9\x03\x00a\xb95\xd4\xc6[\x028\x9f\x01\x06=\xa5\x030\xd1\x0eX\xb7\x0cM\xb8\x03!\xacCexx\x8a\xd5\xbbPj\x0b\xf7\x08\x0e\xc3Cq\x0f1\xf3\x0b}\x10>\x1eb\xa9/\x04\x8c'\x0d\xad+\x93'V\x11Be\xf2\xc4\xea^h|8\xb0\xba\x19\x1a'\x0eZGI)XD\x0e\xf5E2]Du\x97\x8c\xa5\xb5\xb0z\x13L\xc7P\xb9\n&\x03\xb1\xdc \x92M\xb2\\!\x92\xed\xd278dx\xc5\x15\x8emJ\xe5[\x1c\x1b\x19jM\xdbr\x0e@\x1b\xa3\xddh\xb5\xf5!&W\xa1\xd1[\x1fbkZ\xb8\xa6\xce\xc8\x13:8-\xc1c6\xb5\x1e\x9dM\xb8#Y\xd8[\x98\xbb\xadG\xa1\x04\xfa\xe1@\x13w\"l\xac\xebX\x11\"\x9d\x18\x01\x16K\xec\xfam62|\xd0\n\xf0\xe7\xf5(\xab&\x95\xc7\x86\xc9_\x01.\x06\x81)\x7fQ\x06\xc5b\xda\x86b\xe3\x9d\x0d\xe5\x0c\xf7\xc4V\x9e\xa2\x08\x0e\xcclh\xadX&\xcc2\xd6\xa3\x8c\x86\xe2\xd8ZB\xf18\x14\xe1\xa3L\xb9B\x13I\\@\x8c/\xb4\xbd\xa2r\x87\xb6\x03\xc7N}\xbb\xf0\x10\xf4C\xac\xd9\x02\x0cr\x98c\xe3\xd5z\x94aO\x00r\xe8Q\x19\xe3\x0c`[\x19\xabG\x00\xa1\x15\xb2`\x0d\x8dS\xb0by1\xd5U\x05\xca\xc8c\x1dHY\xea\xb2\x0f\x95^\xac\xd6\x95+p\x06\x93\xd7\xf5(\xab\x93\x07\x9f\xfc+[sT(|\xf2\xd7\xb6\xadV\xa2\x00\xf6\xc8\x93\x10\x85\x04v\x18 \x01\xd6\xa9\x01\x06H\x805\x8f\xf5(\xdbL\xb8\xcb=\xf5\xd2\x0b\xb6\xf3\x95\xe0f\xad\x9e\xfc\x1b\xdb\xe4t\xb1\xea\xba>\xb4P\xac->\xe6I\xca\xcbD\x0fOG\x94\x92\x195\xcb\xc8IdlTHc\xa7EOA%\x8b\xe1Y\xa86\xe4\xc1\xd9\xce{*\xe7\xdb\x03+\xb6\x97K\x15\xcdYX\x84.\x18\x8b9C\x83\xd6\x01V\xcb\x15Mb\xd3\x97(Z\x8c\xedO(k7\x05\n\xb7\x1c\xa2#\x8b\"\xae\xcb\xb9\x07\xbb\x8e\x0d\xfa%x\xb1\xeb\xd4XQ*\x86v\x1d\x1b\x1aK%\x8b\xf3\xf4\x1f\xed\x0d\x96\x16\xea\xc75\xb3Ck\xf4\xc0\xc23\x8bn,\x93\x93\xc0\x82\xccXx\xa2,Qeg\xc4Z\xa4J\x15=Y\x86\x81\x99?\xd1\xd6\xe3\x1a\xa9@\x00\x9c P \xf1mPH\xcd\xf1\xf4o\xe9+\xb4\xa1\x8e\x80\xbbG\xa5\x810\x8e\x02\x1d\\\x88M\xc9!?}\xc7Z &Id\xcc4\x8f\x1b\x88\xb2\x02\xabI\xd6T\xd6\x93\xb4\xf4\x9b\xa9|;D\xc8\xd7qx\x9f\x10\x8b\x96\x81\x10;T\xa6\xbc\xd1h/\xe8yr\xaa\xe2\x96K\xc0d\xa8\xaeK\x9e/\xa7\x07\xbfRD\xb5C\x04\x0dy\xa5A\xec\xc3\xf2+1\x0f\xcb,\x9a\xbfG\xbfrH\xda\xf86\xbe\x13\x0es\x9d-\x96\xd8\xb3\xc7\xfa='\xcb.^^\xd6\xcf\x14\x12+\xd8e\xf3\x82!\xb1\x18\x8cM-B\xe6\xc6\xa6\x16Y\xc6\xb1N\xbbe\x19\xc7\x18\xf2\xcf\xd8 \x17t\xb8\n9\xbc\xe3\"\xfe\x1d\xdf\\\x85cm\xcbz\x1f\xdb\xe9\xc3\xb1\x8ee\xb0\xf5\x06. v\x88\xb9\xc4\xb7\x815\x0b{\x9f\xd0\xdd\xb1\xe1\n\x0f\xfe\x9d\xad\xa6~[\xf8?X\x80\xfb\xc6\xe8Oh\xda\xbe\xe6\x99\x04\x15\xf65\xcf\xb4B\x14W\xa3\xb0P\x9b\xc7\xf1\xd5\xe1\x86I\x11\x81\xef*\"\x03\xc1W\x81Q\xdd\xf3\x99\x91\xba\xac%\xeffn\xe8\xf4\x11XF\x894\x00kc*\\\x1b\xef=Dk\xff=\xd6\x89\xa2\xda\x1797\xf4\x9bM\x9f\xe1k\xed\xc8@05\x8a\xe0!\x98g\x1fa\x9a\x13\xe9\xd7\xce\xb0\x93V\xe4\xa5\x91\n{\xc2\x96\xdd\x8d\x15H\xbd\xf0\x19\xde\xff\x88+\x00Y\xf8\xbeZ\xc6G\xd8\x95iC\x1b\xfeI[\x1a\x80\x0f\xa6\nV\xff5\xde\xa9\x0d\x93\xc4\x824e \xd8\xa4\x1d\x81\xb1\xfdC\xcc\xba\"\x9d\xa8\xe7\x116\xc3DC\x81\xfd\x9fc9&\xaa{\xa112\xa6hl\x06\x8f\x02\xbd&d\xeb\x03\xf3(\xe1#\xec\xb4\x13\xe9\xc4\x12o\xd2Z0\x17,\xcbn(O\x98\xcf\xb0\n\x1bi\x006]o\x8c\xf8\xc0\xb1\xceR\x01~\x83\x19\xe8\x86\xf4\x8f\x90\xe9\xa7\xb1M3*@x\xef#%R=\xc2\x86\x9fhT\xfb.\xec\x861\x9e\xe2+\xd2\xc8@\xb0\n`\\)\xb1\xf1i#\xe6\xa1\xf5\xc5U|\xbdo\n\x16E\xb0_Z\x14sx\xf0\xf0\x11\x96\x11\x8c\xef%y\xc5vC\x0e\xeb1\xa1 N\xe2k\xbf\xc8(\x17\x04)\xc0\xb3\xf01\xa6\x14Q\xe2\x81\xb5\xe7mL\x8b$\x04R\x8a\xd8`2\x13\x17\x16>\xa2\xc4\x13\xb8\xff1A\xe4\xc4\x1f\xa8\xec$d#\x13\xf5b\"\xde\xc6(I\x83\x08D\xb9\xc7\xf8>7J$\xa9zLH\xb1\xfd%\xe1\x0d\xa3\\\x90\x01k\xc7\x0fB\x89u\x8a\xa4O\xc8.\x1a\x08!\x94\xeau\x8f\x07\xb8\xca\x86\x11\xf4\xf0\xf6F\x06\x82\xa9\xc8F\xe1s\x8bq\xb2p\xc7%\x8f\x1a\x03\xc8\x81zx\xa97T\xb6\x06\xb2\xd2\xea;\xd9\x9a\xb1\"q\xefbanc\xccu|\x11!2\x12\xa6\x82k\x9f\xfd\x19fe\x1a\xaa\xc2 \xff\x94\xac\xfb\x98'\x9bN\xc2\xc3l\xc8S\xb86\xfc3|\xd4\xb42\x85M\x06B\xd7\x13\xd8\x87\xe7Q\xd1\x01-\x95\x94\xb8\xf2\x14s\xfc\x92}\x82B\x94m\x02\x016\x9d\xc4<\xcfF\x81\xc0\xc61\xf9\x8b\xe13&}1O\\\xc91\xfe\x19\x05\xf82\x1f\xca\x0c\x05\x8c \xd6\xf3Mlt\xd6\x94\xe7\x01\x99>O2\x1eJ\x81\xecM\xac\x85lj\xfe\x8ayu\xac\x01XX\xde\x84\xa7\xd2\xb1\x96\x1b\xc3S\xe9\x98\x1c\xc7Cxu\x00\x1f\x8ax\xa8^q\xa6\xfeX\xf1P=\x17\xfd\x17\xf8&tS\xf6\x8c\xe9z,;\xc6\xfc.\xf63wX\x9b';\x86Q\xe1S\x12\x07N\x08\xef\xc7\x93\xa4i\x00\x82\x84jx\\\x02\x06i\xb7-\xd5$\xd1?j\xf9\xec(\xc6\xff\x11\x16\x92\x05\x104\x7f|\xb2\x04D\xd7\xc2\xa6\x04\x01\xf3\xa4\x9aE\xde\x81\x93 p\xf3#\xb8\x11\xe4\xe0\xd3\xfa\x18\x0bE\x9bA\x9e\xea\x87\xd9?\xc6h#\xaa\x8d\xc2:\x88:l\x1f\x11\x1c \xf24\xdb\x97c\xfc\x08\x8b\xeb\xf1\xc8\xd6\xdaf\x04\xc9\xa8\xc4\n\xcba\x92\xcc\x83\xb1\x90\xb9\xb4\xa1\x10c\xd9\xa6\xbe|\xc5bml\xa4\x04l\xbf\x8a\xa3\\>\xf6\xf81\xde\x95M\xb9\xecO0\xd3\x05S\xe4}\xcc\x0d\xe3DE\x18a\xc2nL\x94\xf7\xb1<\x1d\xc3[\xf5O\xc8y\xd0\x96K\xfa\xdd\xad\xe9\x9b\xbb\xa50&:\x02\xee\xaaw\x83\xad\xe3(\xdf\xb3\x90\xb6-\x97,5%\xaa\x96\xf6\xda^\n\xab4f2e\xe3\xab\x05T\x8e\xd4\xc2\xb2\x96\x84+;\xce\x13\xccu%P\x87Ya\xe9J\x00\xb5\xc5\x10\x0fh3Q\x16\xc37\xe9\x16i\x08>E\x12\x92\xdaq0\xd1Qht\xf8p\xc1j\x19z\xc3\xc0\xd5S\xed\x98\x02m\x96\x1ej'\xd4)\x89\xfaN\xa0\x04\x00\xac\xb3\x08\xa0V3\xde\xc5\xca\x94\x00\xa698\\\xbfKx\x87z\x7f\xed\x1e\x96D7\x93(\x8e\x12\x9dI\xed\x1e\xc6\xcc\x02\xac\x12\xb5\xe1\xfa\xa2a\xf0\x9b\xb7\x80\xea\xb6-N\xf2\x04\x04\x83\x07\x98en\x1a\xa1\x11\xdb\xc6bc\x91\xc6\x86\xc9Mx\x95\x87\xac\xbf\xfc\xfc\x1b,\x96\xc6y\xe8*\x13\x17\x06\xbd\xae9,&\xd7\xb75\x00\xef\xc8\xed\xbal\x8b\xafk:\x87\xcd\x13\xb7\x0d\x9d\xc3\xec\xe2\xb6\xc1\xd9\xb7\xb0\x80\xf9\xbaY\x15\xact\xdf6\xab\x82\xf9\xfc\xed\xdc\xc9x\x12\xfa*3\x01\xc9\x8c*\xe0z\xf4\x98\xeb\xea\xd8\x94\xd7l\xdf\x15\x91\xc2\x02\xd5\xeb\xbb\x1b;\x0b\xec\xdb\xado\xe3*Qf\xf9\x9c\x98\x84KX\x9b\xd0B\xec\xbd\xbf\xfd;\xcc{\xb6\x8c/5\xde\xa0\xc4@0\xc3I\x1c\x0f\x12\x90\xde\xc3;\x91\x94\xb34a\xfa\xb1\xa5c;1\x1a&\x1a\x80u\xf0\xc4\xa4U\xc2'S@\xe4\x94\x1ea^\x9f\x14 \x97hs*s\x12fo[Z\xd9\xc4R\x97\xb9\xfc\xa2\xfd\xab\x1a6\x00\x10\xbc\x0f0]KLR%:\xe6\"\xa9\x12\x19Bq\x97f\x81\xa8JX\x84J\x8atKXQL\x8atK\x18\xf1\x13\x93n\xe9\x03L\x0f\x92R\xba%\xac\xe9l\x99tK\xefc\xa4O\x8aLLX\xd2(]\x03\x92E7 \x97\xb0\xc2\x94\x14\xb9\x98(\xeae>\x10M\xac5IH\xa8\xfd\xe7q\xbd-\x93\x8d [\x18\x13\x03\xc1\x1c%1y\x9a0\x05HL\x9e&\xb2[:O\xd3]\x1b@\xd4\xb9A\x01*O\x13\xa6\x84I)O\x13\x16\xd3\x93R\x9e&<\xa3-\xe3\xa7\x8f\x15\xfb\xc4@0\x03\xdf2~\xfads\x0d\x04\xd3\xd6\xc4\xe4i\xc2\xc6\xb3\x04\xf24\xe15\xd8\x02\xcd\x91\xe0>8\xc3b\xad'\xd1y\x9a0kM\xbc\xc0\xa4\\\"\x87\xdf\xe4p\"\xf8V\xe4p\xa2 \x15\x17Jh\x19\xc8\xe9\x04?9\xf0t+@g\xc9%\xd4\x99;\x81\xc9\x92k\xab\x08\x88K\xc6\xc6A\xdey\x0f\xeb\xae[+\xe7\x05\x91\xc3|5\x81W\xfe\xf1g\x8b\xff\x0fvV\xd6E\xd03r5\xc5vcT\x90<\xb7\x9a\x14\x890\xb0=\")\x12a\x90\xe6U\x0eh\xb2BZ\x90 \xdd\xe8\xc4\x16\xf8\x16\xdb\x84'\x93\x17\x7f\x13\x9d\xd8\xe2\xa7\x04\xe7\x8a\xc4\x16\x98ln\xc98\xba\xcf\xb1\x8e\x95\xc8\xcf\xbf\xa1]DR+'\x8cX\xc6\x88\xe3|]\x18\x8bQ$9\xe6>\xc8}\x820\xa7\xaa\xf7\x84\xb5v%g\x17fTE\x89J\xd4\xfbO\xf1\xfd_\xd1\x91I\xda\x85\xe9\xbfl\xaa\x9c\xb5\x0b\x93\nY\x80\xa6\xed\xc2*\xb5*\x86\xf3v\xe1\xd3b\x8a\x95\x12wa\xb3\x16*\xa3\xf3\x0ea\xf1G\x16;W\x8b\xa7\xe5\x04V:\xc2\x95\"Z\xa9\x10\xf8\x06P\x8c\x13EP\xf6.\xeb:\x97\xf2\x80A)\xc2.D)\x9c{\x8bPf\x9ff\xd4\xb2.\xa2N\x97\x85em\x0d,\xb0\x13[F,\xcfr\x13Z(\x8a\xa0\x8cYx:\xc4\x17\xf1\x01\xa1\xceVG\xc4\xa6B\x85\xf7\x1a\x96\xdad1\x925\x0bK\x04\xaaTur\x98R\xa9B\xa5\xa4WX\x8b\xab\x94\xd0\xf8\x87\x05s\x94\xd3\x8c N \xae\x9b\xc0\xbak\x02\x87\xee\xd7D\x88\xf2\xd3\xea\x83\x8d\xa4\xa2I\xa6CP1\xd0\xe9 \x08\xfa\x05\x90\xf3\x81HQEf\x1bL\x0c\x93jf\x1b\x02\xd6\x81\x0cO \x933 d0WLL\x02\x19\xbc\xe8\x89I \x83iKbn\xd3\xb0&\xb8\xa5uQ\xc2\x95\x8d.J\x04\xde\"/ \x1duqGB\xf0/\xcaC\xaf\x94\xe0\xfe\x03\xac\xde'0\xc6\x8e\xe53\xdc\xf8>\"\x9a]\\r;$<\xc2d\x03!\x04\x19\x85\xf0\x90\xb3[d\xea\xc0\x06\xb5-};E\xebh]\x1b\xfb\xc6l)\xc9\x8b\xec}\xedw\x99\\\x83\x08\xd1&\xb9\x06\x16l\x93\"\xb9\x06\x01\x15\xa9)\x082\x17t \xc7ni\xdf\xc3\xf7\xb0\xa5\xab\xe4db\x81H\xc2zE:\xe2\xc5\x93\xf7d\xbc\xb5\xe8:\xf2a0\xefR\x88\xdc\xc9'd'G*\xaf<65\x08\x00\x84\xaa\xfd\x0d\xcd\x02\xb5\xbdqn\x07\xce*\xa9\x16\xf538\xadX\x9c\x01G\x9f\xe3\xf4\xab$\xe3\x1fb!_\x00\xd4E\x1aa!F\xf0\xc5rQj d\xc9bG]\xc1\xfe\x92\xa0\x99\x04\xe9w\xfd,\xd0\xc4z\xf0\xd3\xdbJ\x96x@\x98\x9f\x80\x80\xaf\xd1\x9f\xd3\xb5Ko\xab\xdc!\x0f\xb0\xb0,!P\xefg\x965\xbf\xad\xfcg\x88\xd4t[\x076`\xb5\xa7\x08\x94x@(\xce\xedR\xf8\x82\xb5^\xe1\xd7o\xab\x0b3 \xb4\xd4D_<\xc04P\x82L \\\x0dPuH\xebJK\xd9{\x98\xd5\x97^\xae'R@=\x08j\xe1g\xa8\xc8.\xd2p\xc0\x86\x02\x85R\x8f\x17\xcb\x16\x06\xd8X\xa4h\x8a\xb0\x11Yn7\xd4#\xa6\xf8\x93;p\x83L\x1e\xf2Oo\xe75\x80\xda\xeb\xa5msk\x89u\xc8\xd4hR\x98#\xa7\x0d\x02I\x03mJ35\xee\x87\x98jogp\xfa\x08 U\x80\xbf\xb0\x01d[\x7fAD\xc6,q\x04\x9f\xe6q\xea\x07r \x7f\x83\x95$]D9_as\\\x9a%\xd2\xeeE\xb2\xdfm\xc3\x01|H\xf0Z\x1dL\xc2r\xf3\x9e~\xb3\x9b\xa8\x0e&\x16\x89\x02\xe0d\x91\x19\xe7=\x9d\xaa\xe7)\xe1\xbayo\x94\x83\x07\xf3S\"[\xe7=\x90\xfa\x9fb\xbb\xa2\x80@_\x84\xc0\xe6=\xcdE\x9f`\xb2\x9c\xe6=\xc3E\xb1^Z\x1c#\xdb\x1a\x990*+H\x11\x05\xcb\xb4\xcb\x11T\xd6\x0e\x8b\xb3d\xaf\xad\x12\n\xdb\xa6 \xd0\xdbu\xeb\xa3\xfd\x1f\xb1-A\x80`\xd3\x9f\x12\xec\x11 \xc8\xf2F8\x86\n\xf6\xa2\xfaj\xee\x96]\x8f\xb0\xd6*\xc0e\xd7#\x8cL\xe5`_\xd2\xb6%\xd2\xb7\xa6\x04r=\xaa\xeb\xa5\x14\xe1k\x19\xa7\x0eY\xb3\x80\xca\xaeGD5\x15p\xedzD\xd4S\x01\xacUPs\xb7^\x0b\xcd\xdd\xe1\xce\xd0\xb1_Bm\xc3e\xd2=\xc2\xf7j\xbf\x83!\xf0\x97\x98\xb8n\xc3v?\xa4\x15\x80}\xd2\xd3\x1a\xcf \xf2\x82OO\x9a\xc7\xf3\xe2;\x91M\xf3\xf8\x84\xf8N\x84\xc7<\xd6\xe4\x05[ \x05H#(\x11XM\x84 \x05\x009\xa0\xd8\x1e\x1b\xd2\x83\x05\xb8j@w\x0d\xb08\xa0\x96\xa6\x87\xca7\xfcWXQ\x9405 |!\x9c\xe6\xb1I\xdbJOSl\xa8!\xa55\xb1\xa2\x86Dp\xcdcE\x0d)\x1d\x8855|J\xc45#\xed\xd8\xb6\xbfn]*b\x90eI\xca\xe1\x94V\xa8\xa6h\x96\xa1\x96)\x9ae\x8e\x9a\xa2\x11\x9e\x9e\xc7z\xad\x89\xc0!@@\xd1\x08\xbb/b\xd6\x88\x19\xc6\xc4\xacachjb\xd6\xac\x90\x9a\xbc\xd7\xe9~\xa8\x8d'D\xba\xb9\x03\x91S\x9f`=q\xc7\x113\xfaA\x86>gN2\x80\x9dy\x17Oh\xc7\x91!\x9aX\xaf\xc8\xe4\xe7\xdf`\xe4\xcf\x94\x9d\x9f\xf8\xea\xef\x18k\"i\xc9@\xb0\xa6\xb1cl\x80\xd8\xfe\x92\x19\x08\x96\xa9\x94zF+H\xdd\x0c#\xbf\xce\x9c\xfcclw\xcdx\xa0\xbcb\xdf\xc5\xeclG\xdb\x8b\xf0 \xcc4\x00\xdb\xcd\xb3!O\xf8I\xd1\xd8=\xb2,\x02\xd4\x8f@b'\xd0\xac\x11\xba3\xe4\xf0\x06*\xa6g\x99\x06`\xb6)\x01\xe9\xa1\xc0\xf7\xdf\xe0\xc3)ac;\xc4w\xf7J\x197\xf1A\x91\xf0:cJ5\x03\xe2[\xbf\xa2/\xf5gC?T\x9e\x8d\x98\xdeU\xb3\x1dbh6\xdcS\xb1\xbdtD\xf5\xe3\xb9\xb0\xb1\xb5.N\x066\xc7d\xc3(\x11X\xf8 \xe6\x1c\x86\xbb\x93\xb6t<\xce\xaf\xb1%\x1a\xa5\xdb\xc0\xc4\xce\x92k\x03\x8bq(\xd1\x06\x99\xa0\xba!\xf9\x84\xe0\xa0\x00\x80\xec\x8d\x15z\x00\x01\xc1\xf8\x88\xa0\xa8\x00\xc2\xbb\xb9XP\xc9\xea\x1e\xe0\xce\"\x0e>B\xd8n\x99\x81\xd7\xee\x03r\xd2\xa3\xb8\x07\xe7\xed],\xd0dQ\xac\xd3\x18\xe3\xa1\xed\x18\xdb\x06\xa6\xed\x99\x81`\xca! *d\xe3)6\x1bdQ\n\xc3\xc6rSVx_\x93\xa3\xb6\xb5\xb8,\x99\xe4\xdb\x84\xb0$\x0e\xec\x91\x05R\\\x9f\xbf\x87\x15.\x0d\xd4\xde\x0b\xefaA\x0d\xc7\xee\x93\xac\xea4t\x9f\xa4W\xd7E@F\xc6HJ\xe2\xfa\xc9\xa5\x9a%\xac\x9f\\\xafe\x89zU\xe5\xd9/\xb0IL_\xc9\xd9z6\xb6\xc1\x8f\xb0\xdc\xbb\x93\xf8q\xc0\x97\xeb\xe8\xb2\x80\xaa\x9a\x96\xe1\x02\xea\x7f\x88]\x06\xb3\xc4\xcf\xd4\xd6~\x84e\xa3,\x89\xf9\x1d\xe5F\xf5gx\x0fw\x8c-\x00k\xbe\x99\xb1\x05\x10\xa2\xa5nz0\xfb\xcf\xd4U\x0f\x96_v\xb4\xf9\x9f\xa0\xb7\xb6\xff\xe3E\xd81\xcf\x0f\xd0>4\x04_\xc0d\xfb>\\\x8c\xdc'\xdb\xb4\x1f\x0d\xb9\xe3U\xf3K\x12\xea\x08\x85\x90w\x13&1\xbb& \x1e\x1f\xba\xdc@\xf0~\xefj\xd1\x07\x8b*\xb9\x96\x960?\xcau\x0d\x0c\x10M\xe9\x00\xfb\x0f\xf0\xb6\xec\xf6\xd4\x93\xca\xf8\xa67W\x80\x7f\xc0s\xde\xed%\\\xc6y\x7f\x86\x97,7\x10L\x13wu\xb4>\xde\xb3\\\x030\xfe\xed\xc2\xa8\xb0\x1c\x93\xc3\x98\xf0\xa9\xcf=\xed:\x809\xc6\xae \xd6\xc7\x04<7\x10LZs\xe3\xca\x89M]y\xe1?\x88\xf9\xe1\xae\x16s\xb0\xd8\x91k\x00V\xd7vM\xc0<\x16as\x03\xc1\x879\xd7\x9e\x85da\x86N\x02\xeen\x98d\xe6& -\x1ern\xde\xc5\xc2\xdaJ.\xdf\xa7\x12\xa0w1\x95\xca\xcbOWY\x80*6\xe5]l\x1e\xcd\xcdC\x18X\xfc\xda\xd5\x11\xf2X\\\xcf5\x00\xbb\xedC\xb0\xed\xc7\x98\xc1\xee\x86\x9e\x8e\xa9\xc5\xef\xe5\x00\xc8\x84\xd4\xe2Ce\xc0:\xa6\x16\xd3sY\x00\x07\xd5\xe2{(c\x8a}\x88\xf1SBt\xb6\xff\x07\xf8\xa8\xed\xaad\x0b\x9fa\x0c\xc95\x00k\xf4\xbb\x86\xc5c\xcd-7\x10L\x04\x9b.\x1cw\xe3\xc2\xb9\x86\xd0\x95\x02f\xa9Wv\xda|\x1f\xdb\x8c\x15\xb8r'KOh\\\xbd\xb3\xc5\x8a\xc5n,\xa4\x81b|\x18\x9eW\xe1\x96\xfa\xd8+\x98\x9c\xeaX91\x9aw?\xc8\x19\xd2%\x8a\xa7\xa4\xc8a\x8ak\xb77\x8e\xf1[MX\x9b\x94E\xd0\xad1\x96awU\x08\x14^\xe4\\}\xc7\xeb*\xbe\x0fm\x15v\x8d\xc1\xfbs, \xe6\x85-\x9cn\x93v\xbf\xc4\x95$\xa4\x187mSa\x10x\x7fb\x99=O\x0c\xa9\xc1\xe7)/?\x02e\x01jRC\x16\\9\x19~F6Z\x03\xb0\xd8\x92k\x0f\xaa_`\x82\xbbkD\x1d\xc2?\x8c\xa8\x83U\xb7\xdc\xbc<\x84\xeb\xecj\xdd\xe83L\xbbr\x03\xc1\xf2w\xae\x9d\xbb0M\xca\x8d\x0b\x17\x96ps-\x0b\x90\xd5\xdeUy\n\x08\xe1V\xdf\xb1.\x97\xef\x1ba\xfd\x11\x96\x9d\xc6N8\x80;\xc8G\xb8\xb9\xb1\x934\\\xab\x8c\x9dD(\xce\xd2c\x01\xaf\xd0\xd8I\xc2H\xe8\xbe\xf0\x9a\x06\xc6\xc2\xb1\x93\xd4\\\xc6\x08\x88o\x0b:\x17\x80\xfa\xb8\xc6\xb1\x16\xa7,\xed%Vz\"\x00\xe0`\x8f\xe5\x86\xb1\x93\x18O\x0clR\x11\xb0\xea\x1d\x03\xbd\xd2-\x97Q7\x0d5\x85*\xa6\xbd\xe62\xca\xc0g-\xa4-\"\xc4\xb6!`H\xd3\"\xaf\x03\x97\xca\x18\xaaH\xfc\xa1/+\xcd\xfa)f\xe1c\xc53\x9e\xe2\x83 \x002\x8a\xef)>\x08\x97A$\xc4\xe4l\x0c\x9f\xf1\xf0\x8a$f\xb8\xeb\"\x87\x19\xee\xa1HaFFe\xea`]H\xb6&%\xaf\xa7\x98\xe3^V\x9e\x9c\xf8\xa6m\x0c\xdfI\xea\x991\xe7j\xb9\x1e`qx\xcc\xb9\xd2W\xb1\n1\xe6A\xe0\xc3\xbd\x02&w\x97y\xa2\xda{\x93\x1c\n\x0d\xfa\x11\xad\x93\xd5\xd5\xc8j\xca\x97\x13\x9bb\xb9T\xc3\xd5\x13\x17u\xd5\xb7y\xec$\x8e\xf2+\xff+,B\xebR\x85\xe5\x07#3}\x04\x04\x13\xe5\xcbZ\x0c\xc7\xc2\xf6X\x030\xee\x8e\xb5\xc4JQ\xdf\xe4\x8e\xb4dz\x1c\x9b\x9c\x8b\x96\x0c\x89\x97\x8dx\x86\x95\xf1\xb1\x81\x10:[\x1b\xef=6o\x17\x92sg\xd8\x16!R\x86ma\xc5z\\\xba\x01\xb6\x90\x8b\xd2-\xb0\x15j\xeeKj\xa0\xbc\x8eZ].\x0e\x17\xd6\x00\xc6w\xfc\xc1\x1dG\xb2\x82G\x18\xf1\xafh\xbfV\xcc\xfd\xf65\x00\xf3\x9d}\xee\xa9\xf3\xf0\x18+\x00W\xb8\x07Q\xbd\x0f\xf1\xe8\xf65\xe4\x1e\xde\x17 \x81C\x89qj\x9f\xfb*[\xcc\xdb\x18\x97\xafht\xc3\xf3\xd9\xd7\x00<\x9f+\x063\xb0\xa0\xb3o \x98\x94\xec\xdb;\xdfO\xac\xa7g?\xe1N6\xb4\x82\xae\x18D\xc2\x87`\xdf \x12\xd6A\x0e\x94'\xd4C\xcc\x04\x0f\xd4\xce<\xfb\x05\x16\xc0\x0e\x94\x13\x14\xd1\x9c\x0e<-\xfe\xe0k\xe67\xf4za\x9b\xc2\x81\x06\xe0\xfd?\xd0\x0f\xb5\x90\xb7o\x0f\xb4\x8eL\x9e\xbb}Cf#\xc06\x90\x03\xf9\x15\xab\x00\x07:\xbd$y\xcb\xf7@\xdfA\x927|\x0f\xd4\xf3d\xe4!\xdd\x03\xfd\xe2\x0bf\x05\x07:\x99\xe0Gx\xaf\xde0\xe8\x80\x95\xef\x03\x03\xc1,\xef\xa0\x88\x0d\xc1l\xea 2\xd6A\xb2\x91:<\x9d\xbc\xdc{\xa0}>\xc8\x83\xbdo\x18L\xc2\xc4\xea\xc0`\x12&\x8a\x07\xc6;\xee#l\x1f<0\n\xd7G\xf8\xb6\xed\xc0\x88\xcc\xa4\xa7q\x0dK>\xd8\xaf%\x00W\x8d\x8d\x0e\x93\xdfC\x03\xc1\xb8yu\x11\x84\x12\x8c\xe6\x87\x0e\xd8\xaf\xf0\xfe\\\xd5$\x0b/\xda\xa1\x06`\xbc\xbc\n\x1d`\xd9\xe6\x10\xda\xc7\xa4\xfd\x90\xcbdBX5\xbb\xaaO\n\x96\xdf\x0f5\x00\x8f\xe7\xea*\xf4\x8b\xef\xa2\x0f}\xe8\x18+\xadW\x0d\xe2a?\x9fC\x03\xc1D\xff\xaaA\x14L \x0f\x0d\xa2`JxU\xd9\x0b\xb1\x08t\xa8\x0c\x86\xa4<\xe8;\x9f\xe1\x83z\xa8\xf4 l\x00\xb8fBQ0\xc2\xdf1\x10LT\xae\x99\x1b\\\x8c\x1ew\x0c\x04\x93\x90k0\x0d\xbc\x8cw\xe03F\x82k\xea\xe5vL\"\xee\xa8\xef\x98\xa6\xdc\xe1\\?\xe2\x89\x19\xc65\x9eDW|/\x1b\xd6?\xa3vM]\x9fb\xc9\xf0\x8e\xfa\x8eq\xe5\x9a\n\x9b\xc6]\xdd\xd1\xc8E\xa6\xa3,\xfe\xa4\x030\xf8\xff=\xee\xe0\x8e?0!c\xf8l^\xd3ar\xf8\xb6\xed\x8e\xc1;|v\xae\x19\xbc\xc3D\xfa\x8e\xc1;|p\xef\xec\xdf\x92k\x85 \xd7\x9d\xfd\x10\x00\xef\xb6\xcc\xf7\xbb\xf2\xaf\xbb]\xd6\xcfC\xe9g\xda\xe6]\x96uY\xd8a\x7fd\n\xb5\xf2\x94\xb34K|7k\xbdj\xbe\x8e\x9d\x84%\xec\x0c\x0b\xdb'\xe7^\xe9T\xbb\x8a\xe4\xf7\xf9\xeftf\xf2\x90\xa7\xae\x13\xf3K^Q\x93\xcf\xf0\x838J\xb2\x94\x9d\xa9\xf6[\xeeTw\x11v\x99\xdfeN\x97\xe5\xec\x0c\xcb\xaa\xdd\x88\x9fh\x84\xcf\xc4Qz\xc99x\xb5\x02\xf5\xfb\xac\xfd\xf2,;sF\x14H\x13w\xc6\x1d:\xc9R\xe4\xf1\xc5\xac\x9dup_\xe2\xd7\x8f\x12\xd6\xce\x8e\x1e}\x95e\xec\xbb,}\xd5VF\xb7<\x07-\xb7Cfo\xbe\xc3\x12\x9e\xe5I\xc8\x8e\xcc\xbdZ\xdb\xc8\xcb\xf3\xb2\x91\xd0\x14v\xd8\x19\x96\xb4\xa36\xb4\x98\x06\xbe\xcb\xdb9;\xca\xe6\xc4\xeat:]v\xe4\x08\x9f\x89\x9d$\xe5\xc9\xcc\xd8 |\xcf\xc9\xf8\x9a\x1f\xee\xb5\x9d\x0e{\xe9%\xd6\x96+!\x16\n\xea\xf0\x99\xc0\x0f\xf7\x96\xa20\xe3a\xc6\xce\x88e<2\xdb\xb1\x8f\xe7\xb4\x1a\x8bhGV\x17K\xc0^\x13\x7f\x9fa\xf3l\x81eG\x8f\x92\x8aw\xc9\x173\xebo\xd5\x97\x93\xeb\xec\xb33lV\xad\xb4\xe8\xf3\xc4<;\xd2\xb4\xa0\xa2\xcc\x91v\xc8\xbe\xc7^\x11\x7f\x86\xec\xbbl\xeed\xe7\xd5\x0e\x19\x81XX\xebd:j.t\xfe\xfe\x83\xf4\xe8\xf1A\x97\xb5X\xab3\x93E\xf2\x0eg\xc9Iy\xfb\x85\xe0\xf0F\xef\x16w\xb3\x19\x8f\xf7\xfd\x90o&Q\xcc\x93\xec\xb0\x9duY\xeb\xe6M\x9e^\x8a\xbc<\xe0\xad.\xc1\xd6 \xe7\x0b\xec\xc8l1\x82N\x97\xc9V\x9c<\xc8\xca\xd3\xac\x99%\xc5\x147\x1a\xc5Q\xc8\xc3,]`\x8en\x89\"\xfb~\xe2\xc4K\xa5\xa2y}\xd14s2\xbe\x19\xe4\x03?L\x17jXA\x1as\xb7\x0e\xc6Tw\xdb<\x90\xb9&\xd2\x05\x96\xd0^\xf4/-J\xf9\xd6Bw\xedu\x9d<\x1b>\xc7\x08\xa2\xe7i;r\xd2\x13Mm;r\x8f\xd2\x05\x96\xd6\xcf+\xe1^\xeer\xd1\xb5[\xbf\xd4\xfaWZ\x84\xc0>P\xf2\xf5n\xcd)\xbcK\xe9l\xdc\x0e\xdb'\xe7\xe7;\x16\xc9\x14@'0\xc87\xa0\x93\x18$\x88W_\x82NaP\xaeA'H\xadT58\x7f\xe2e\x0c\nt_'\xc9\x08]\xdd\xe0\xc9\x13\x9d\xce\xab\xdf20}JX\xbf\x9e\x1c\x08\x02\xc6g\x8a\xc3\xc8^c\x9c\xd96Um\xce\x02\xe3u+j\xe98\xa6\x1d\x0b\x92Mz-\x88t\x95\xd4j\x0e\xfeGw)\xbb \xf3 `G\xce0N\xe59\xc9P$\xcfc~\xc8xG\x93\xa18\x89\xb2(;\x8c\xf9\xcc\xd0I7\xf6CM\x90f\\'\x08\x04Q\x0bA\xd6\xc9\xae\x877\x04S\xb9\x1e\xde@|N\x0d\xb3L\x8b\x04-,-\x02\xfbF\x90J?\xdd\xdew\x06\x03\x9e\xcc\x0b\x8e7\xe3\xa7\x1b\x8b\xdb'\xe4\x9f)O\xc6\xb7\x1b(\x82\x103y\x91\x942\xc5#KtY.\xddJ\xa4\xec\xaa\x93\xe6\xc7\x03&\"\x99\xb0\x90\x00\n\x17^l\xb1\x97{fz\xaek\xcd\x03\xcc\x9f9o0\xefp\xde\xa4=/2+vD\x00\x01 \"\x80$)Y\xd5}\xb0\x96\xad$\"\x10\xd7\x1d;\xf6}'a\x00\x9b*\xfaf\xe7\xbe\x92\x1bl\xbf\x0d\xf1\xed\xd6\x8e\x12\xc6}-\x8cW[\xd1\xde\x07]=\x1d\x13W\x0d\xd8;#\xc5\xe1U^\x10z\x91R\x1c_aP\xfc\xeb\xbb\x9c6\xa2&\xday_\xf6\xa6\x0b!\xdf\x16\xc7\xce\x1cz\xec\xcb\x85\xcdc\xa7\x851\xd5\xf8\xec\xa3\xcc\x94\xf7t\xc8\xb0/\x9fq\x03\xf4\xc5L\xd94s\xb7\x89\x85\xf1o E\xe3\xdf\x12\xfe\xc6\xbfk\xdc\xce\xfe\xac\xd0\xfe\xddLI,e\xffvUw\x8f\x91C\x1d\x82\x83)\x84\x13\xbcXn\x86\x7f\x95\xb8\x17\x87\xed\x85\xf9K\x1f\x89\x15F\xfe\x18\xcee=\xbd\xce=\xfb\xb9MP\x0c\xed6\x93\xc4_\xbf?=#\xe1\x9f\xa3\xe4IY,\x92,\xfc\x99\x18\x88\x8a\x9cR\xd1JZ\x9e\x96\x8c\x1e\xa8Hy\x05!\xe2+ \x91\xd2D\x88\xe4\x9f\x86\xd8\x16\xbf\xe8\x84#\x0d\xaan.\x95-\xee\xceP\x7f7k\x87.\x83}\x7f\xed6\xccvq\xab\x8c'\xdc\x01\xc2+>t\xdf{\x11\xe6\x85\xd3\x06\xfe\xeav#q\x91]\x1d\x92\xbf\xdb\x8e7O\xb2\x03\x7f\xb60\xcc\x0d\xa4[\x93\x1d\x06\xbe\xee\x0e\x1d\xc7\xd8Q3\xa2\x14R\x8a\xe9\xe6\xb1\xba\x14u\x0e\xd3\x91\xa6\x94\xe2\xdf\x92Q\x01\x94\x0d\xb1\x14g\xd8J(\xcb>\xb6P\xbe\x84bn\xfe\xc1c\x7f\xf6}D\xf7|\xd2\x04\x00m\xfdk\x0d\x03\x11#\x03\x92\x96\xf9\xc2\x8e\xc9\x05\xf8\x14\x81\xf3\x1b\xbd\xda\xd6_\xaeQ\x056\xf3\xe6aT\x90l\x00|@}\x88\x18FE\x91-Q\xd6\xbdv\x1cG\xc1v8.X\x8b\xa2H-\xfc\x14!\xd7\xf2\xd3\xf0\xcf\xe4J\xbc\xa1\x84\xc2\n\xc3/;\xfd\xd0>\xe2?\xc8\x7f\xadt\xe5*\x99\xbfJV@o\x8d\x8a\xad\xf2\"\x12\x9f\x15\x0b&2\x7f\x92e\xfe\x95\x9d\xc1c\x18\xc1>d\xb0\x01#\x98\xc0\xa6\xe3\".\x18=\x82\x10\xbe\x82\xec\x11\x84\xeb\xeb\x0e$\xd3\x90V8\x96[\x9b\x86\xc7\xdd\xcd\xa4}\xfaws\xd9\x97\x155\xe3\xd3\xcb=j1\x8b\xd3\xe2\x98\x92\x8b3\xbf\xb0\x13\x87r\x93mV3\xd1^\xff\xac\xe0\xf7\xbf\xff[\xf2\x8c\x9a\x9a\xbdK\xa1\x82\xdc\x06W\x1f\x0f\xe3\xebVe\x91\xef\x84\x8d\\\x99\x81\xbd3\xd6y \x03+\x13%\xf5\x86\xa1Z\xa7GB\xa0\xd5\xe4E\x1d\xde\xd6\xc8\xd7\xe6m\xbev\x18\xf1\xb2\x12\x8f\xe3\xf6*#\xccK[\xe1\x9fB\x89\x7f\xe2\n\xff\x14\x1c\xff\x14\x12\xfe\xc9\x18\xfe\xc9\xe0+(\x1eAF\xf1O<\xcd\xba\xf8'\xd3\xe0\x9f\x04Ug\xb7\xc6?\x127E\xf1\x8f\xdfB/1\xc59]\xd1\x8e\xe9\x88\xaf\x84\xd7?)+E>gV\xa9\x8b\x07\x99\x0e\xa2\xa3MH\xaa\xa2\xfb*N\x88\x15u\x98\xa4Z\xa9\xf1P\xaf\xd4\xd8T)5X\xd1H%\xcdcEz\xa5\xc6\xd6\xef\xab\xd4\x10\xbfd\x91\x7f\xb3\xa1\xa7~\x14\x9d\xfa\xb3\xf7\xf9\xa4&b\x9as\xf9\xb6(\xd2'\xa8\x88\x8b\xd4\x15\xde\x12Lc\xf5u\x12\\Mj\xfa\xbcY\xe7\x90a#\xad\xfa\x92\x97?M\xe2\xc2\x0f\xd1\xdfL\xa3\xbc\x94:;\x08B\xf4V\xc8\xd55_\xa7\x84%\xff\xa9\xfa\xd6(\xe9\x12Q\xf1E\x18\xbf\x9f@(j}\xe6\x87\xc3\xb7c\xbb\xab\x9fKxI\x07\x90C\xbc\xbe\xec\xd8\xa6p\x8cUF\x14l\x91\xa8XQ'\xf1\xd1A\xb4\xff.%\xa8\xf5B\xc0\xedr-\xb1\xb8\x18*ex\xb7\x0e7\x0cI\xc9\xec\x8d_,\xba\xe5LJbU@TA\xa6\xa5\xb0)\x0b\xe7`\xaf\x15\x95\x1e\xb0:\x03\x9cH\xe0\xe9ul+O}J\xf5\xd0\xdb\xc4\x05\xebU\x02\xd5$\xda\xcc4\x9d'SI-\xfd\xb4\xa6-z\x94@\xda\x8e\x83\xf0\xbc\x03e\xe2yO\xae&\x12c\"\x9ekW\xdf\xdcb\\\xcd\"\xc6\xeb\xaf=\xc8\\\xc7\xaa\xf1\x81Z_|\x91\x91\xb9\x10\x13\xecc[0\xb9\xd9\xf8A\xcc!W\x16_\xab\xc6\x17\x99XI\xba\x9b\xf2\x00\xa3jc\xe90\xd5\x8c-\xf0=\x9bUR\xaaa\x02\x83\n\xf7LZ\n\x0c\xf9\xd1q\xd3\xd0\xbf\xf3\xa5\x0b\n\xfe\x94\x98\xd6\x12pX\x13\x98\x99\xc5\x01\xb8\xe4Q\x8f\xc8\x00\xfd\x86,s\xa5%)\x16I\xd0\xdbV\x8a\xee1=\xa2\x15q\x9e\xe9=\xc3\xd8t\x17r\xba\xdd=\x12\x99(J.\x8e\xb2\xab\xe7\xc5\xeb\xb2\x98\xb4\x8d9\xe5\xe7Z!<\xd0\xbdo\xbfko\xe3\xb0C\xcb\x8eY\xfey\x194uo\xa3Pu\xe7\xd0\xcb\xc8\x0e\xc5\x9d\x13\xf6\xdf9\xe1\xe7}\xe7d5\xf1\xa1\xbbu\xa4*\xdf\xd3\x85\xeb\xd6\x0b\x07\xdfNX'\x9e\x87g\n\xa8/\xab\xfb\xabb \xba\x95\x98\xb1\xf8<\xee\x96D\xec\x0ee\x06\x84GW\xa9b\x9c3\xac\x12\xe6\x07\x97dV\x16\x8a\n\xf3\x9e+4\xc5\xf2$~\xba\xf0\xe33\xc5\xf7\x01\x82\x8d\xf5\xd2\xcf\xde\x07\xc9E\xac\x92?.X\x95e\x12\x90\xe8\xe0\xd2_\xa6\x11QU;g\xd5:\xb4\xa1\xaa\xee\x12\xb85q\xc1\xe4\x01\x01\xc9gY\x98\xd2\xad\xb7*]f\xf7\xb3\xb3\xd6g|\xe9\xf8'\xe4\x02\x12\xefu\x16\x90\x8c\x04/\xfd\xb4y\xce\xe9ZG\xb4\xda\x99\xf7\x9e\x08\xe1w\x98\xe5E\x9bu\xa3\x80v\x05{p\x86]\xa8\x90\xd6)\xec\x81\x95\xe0)fw\xd3U\xcd\xef\xa3\n\xdar\x81\xc9f\xdb\xb6?H\xa2\\\x19n2\xbc\xf5(\xeb\x1b\xce\xf0B\xba\x97\xcc\nRl\xe4EF\xfc%\xbf\x08\xe9$\x98\x91k\xe4\x85q@._\xcfm+\\\xfag\xe4\x1e[\x88N\xa1_\x06a\xa2+<\x0f\x03B\x0bu,\xf0 \xdb\xd6\xe7qZ\x16*m\x03\x9f\xcb\x0c\xf6\xeb\x0b\xae\x85DOt7\x1d\x93f[\xf3\x90b\xecK\xf3;\xc1\x0e\xa1\x82V\x98t\n\xb5\xa3)\\lL;(.'\xd0\x8f*/\xae\"b\xb2^\x07\xf4\x1a\x880\x98\x07\x1d\x9d\xb6b\xf72\x026F\xeb\xdf\xfe\xf5\x8f\x96\x90}\xdf\x14\x07\x81\x0e:NN\xf0p\xea:/]\x88(\xc0\xdf|\x85\x1a\xbdfI\xba\xc1O\xb8v\xba\xf6\x17\xfc^p,\xe7#L7 iFf~\xa1\xdb\x0b\xca\x95\x0b\xbcQ\xd5\xa4\x97\x82\xfc\xb7\xd8\x0d\xd3\xf8nw\x88dj\xb8w\x9c\x12\xe1\xec\x1a\xa9\xb0\x06+\xab\xabta\x1a\xf6<6\xf2\xfeA\x98\xa7~1[<\x8f\xc3\"\xf4\xa3\xef9\xcb\xaa`J\xc4\xc3n\xff (\xf8\x12\xf1H\x13\x9c\xa0\x9f\x94\x05\x1b`\xc1\xbaz\x01\xb4\xcd\xc8\x9c\xde\x04B}E\xcehs\x13\x06\x8a\xcf\xe7\xb0\x0f\x01L`\xae\xffhU*\x15\x18\xa5\x8azu\x83\xfd\x86z\xef\x9d\n\x1f(\xa5\x1dZC<\x18p\x07\xc9 \xb24\x9d\xfd@\x05'yRf32\x81es\x04\x86\x83\xb2P5\xd3\xbbW5K>\x01_\xc1p\xcb\xfc\xf8\x04\xcan\x0dr\x99\xfaq\xf0\x8c\xa4\xc5b\x02#\x85t@\xf0\xdbJ\x01\x9c\x80\xda+a\xb8\x83$\xac\x02\xf8jA\xd8\x9c \xc2d\xe2WQ\x9f\x13&z.\xe4\\w:3Y\xfb\xa3!\x12j M\xd5\x15\x90\xd58B\x96L#\x06\xec\xdd\x19\xe8]\xe9 \xefz\x8c\xa7\x15\xe9\xa2\xad\xd2\x90\xbc\xc5\x14\xeb\x95\xb0\xaf\xad\x9e\x18g\xcc\x89\x9d\xee\xed\x05B\x98\xc8\x996\xedh\xd2L\x12\x03VJn\xf8\x17\x0b\x8dW-\xfa\xaf~\xb2\x19\xff\xd4\xd4\x81\\\xc9zS\x818X=f\xaf\xf2\x83\"i!\x04Y\xdbCQd2\x87Z\xd1nY\xbd\x8a\xd1\xc2\xcb\xd3(,l\xeb\xc7\xd8r\x86)\xd3\x15\xad\xc4\xf0\x186a\x9f\x1b\xb3\x11X\x87\x91\xe3\xfd\x94\x84\xb1m\x81\xe5\xc0:\x14`V\xe0\xf2\xcat\x10\xeaM\xa3\xb8\xaa\xa5\xa9\xf5\xc5\x06\x8d\x1d&/\xfa\xe5z\xd8\xb6\xa8\xa8\xf3\xe6=q\xdc4,\xb4#\xafF\x91\xb2\xe5#\xef\n\xf6 \xc5\xb7\x9f\x1b\xf13S\x918 /\xe8\x908!/\xe8\x908>/Pz\xbb\xcfT$N\xce\x0b:*\xcf\x88\xdb\xe9\xd6c\x9d *gf\xa0rf\x9f\x9e\xca1;e\xf6P9x\xa5\xbb=\xc2\x90U\xa1'L\xce\x18\xd3\xd3k\x88M\x9f\xd0\xcbI\xc1\xbe\xaa\xd5Hx\x06\x14gY\xee\xe3{?\x0b\xfd\xd3\x88\xa0\xc8c\x85\x0e\x85R;\xec#\xc8bn\xb3^(\xfa\xd3\x7f\x951O\xfc2\xcbH\xcc\xbf4\xd3j\xd5\xa4\xcfH\xf1\xa4(\xb2\xf0\xb4,\x88m\x05~\xe1o\x9c\xf3>\xfb\xe8\xac\xe6\xc2\xa9\xaf\x06K,\x8d\x05{\xd5\x8d\x82\x91pb\x83\xa9\x0e3\xa66\xc68AZ9\xd1\x97\x9f\xfb\xd1\x04|e\xf1\xb5f\x8f\xabE\x1f\xb4\xa3\x8c\xe3\xc0\xddd_R.\x97\x04\xac\x85\x8e\xe9/\xef\x04\xcd\xdc:\xdc\x00\xfa\xafh\x90\x08\xb4\xbd7T\x9cE8\x8c\xb3\xa8\\\x8b\x9f\x85\xc1\xcb\xa4\x8c\xdb\xc9\xff\xe0\xa32\x19\xdcB^\x0d'\xa4 \xbcH\xf9\xd3\x96\xebcZ\x08%>#\xc7\xcb,\xb2\xfa/^\x15Y\xd7Z\x8b\x1f\xc2(zKf$<\xc7\xcb2\x1f\xb0&\xbd\xa7|\xc8\xa2\xc4\xb2sJ\xdf\xc9^\x15\x1f$\x955{\xe3+\xf5\xdaS\xba\xaf\x1eqk#\xd0\xb5\xab\xf9\xceD\xc4\xd1\x15@/\x19o\x1e\xc6\x81D\xfc\x0d\xa4\xfc\niwyl\xc5F\xdf\xda6LF{h\x8c\x11Vdl\x0b\xb0b\x15`\xe9\x1b\xb3CVO`\xc9\xdc\xaa<>\xa2\x96:zu\xfa7\xb1[\xf3\xc5o>|\x80\xac\xc7\xb0\x11$\xac\xd9n\xa2\xf7Cf\x92\xda_\x0fqj\xa1P\xb7Zz\xe6\x0e\xd4\x08\xb7\xa7Ha\xb31\xf4`\xdf\xa9\xf8\xc4\x8c\xd3\xee\xfc\x98\x0f\xdc7\xcd\xe9\x1e `9\x98\xcf\xc9\xac\x08\xcf\x89\xf8\xd2\x88E\xd0\xfb\xaa}\x92{\xd5\x1d\xb2k\x94|\x92MgW{\x82\x06\x1e5\xb3\x04\x87\xc7\x14\xf4\xf2\xf0g\x0d\n\xe4c\xceo*\x14\x91\xd5|\xc2\x13L\x0d\xd8\xae\xbe\x93\xc8?%\x91\xb1\x9bE\xb1\x8c\xbeA%\xf3\x8d;aa\xd1\x8c\xbd\xd4\xea\x03\x04\xf0&y\xad\xeb0fT 3\xb7k\xda\xa2\x98\x00\xa6o\xe1\x13&p\xeb3\xa0\xe6g[\x8693:C\\!W\xd7\x03\xa7\xdb\xa8\xa7\xb3G\xf6\x8a\x841N\x8e\x905\xf5\x00\x1374\xbe\x0b\x88\xa3\xb4LY\x90`\x83\x8eP\xb7A\xd6S^\x0b\xde\xbd}1\xb1\x0c]7Dg\xa1\x9d\xe1\x8c\xb4\xb5\x17\xdb\xb5d\x8b\xd3\x0c\xd2y5|\xd8\xb4s\xd2Wk\xd89\xf9\xab\xdd\xa9}\xe0\xd5c\x89\x03z\x7f\x0d\xf1\x98\xce\x1a\xda\x06\xd4~\x1bC\xea\xf1\xdb\x95\xc4\xe5\x12\xcd\x11ns\x8e\xe9\xd3\xe2\xe8z\xaf\xf9\xfa\xec\x13\x13\xcfkZ\x8e\xc6\x14V@\x050`\xbf\x06\xa2\x03\xa8\xe2?\x92`B/\xf3\xbd=Hl$\xa6\xfa\xa9\x1c\x86\x1a\xfa\xeb \x9cc\xacH\xb1\x87\x89\xfaq`\xa2\x9fm\x88\x96\xb8}\x93\xe5\xa6\xb5\x05\xb9T\xf1s\xf2\xc3G\xccW\xa2\xcf&\x0e\x86\x83\x83\xb9\x91.\x0c\x9a\x16D\xeb\xf0Q[Ctj\xf4\x88[\xeb\x05\xee\x13\xbb\xce\xf1\xed\xe7&v\x8dtb\xd7H'v\x8dtb\xd7H'v\x8dtb\xd7\x88\x89]\xebQEL\xc0\xaa\x12\xabF\x9f^\xac:\xbb\x8dXU\x12\xac(\xa4\xa7]\xad\xadVy\xdc\x92Z\xdeJy|+\x11\xcf\x9dr?}\xbcM1\xc4)F\x19\xe9\xa3\xa6Q4\xb7\xa5\xeb\xb5\x10\xb2\xa5\x98\x81I\xdbMk\x1f\xa1w\xee1+\xa4p~\xe5\xd8\xed:\x15\xd2\x17\xb0>GI8\x962\x0fE4\xe5a\xf3\xe8\xe3\x9d\xb9\x8b\xdb\x0fYX\x90\xd7qt\xd5\xc0\xbc\xedG\xa7\xabp%\xb0\x1f\x0c\x08\x83\xa1\xb7W\xcc\xc0\x80\x96\xe9\xee\xaa\xd3g\x02\xd9\x85\x1f\x07\x11y\xbd\xea\x88[\xa0;\x14\xd0(\x10\xdf\xfb)O\xe2{\xa1W\x90\xbc\xb0\x0b\x16\xc0^\xb6\x1d\xe0yf`2\xc8\xa6\x00VY\xbe\xf6\xe17m\xaf\xbc\x91vlX\xc1\"9;\x8b\xc8\xf3\xfc \x08\x8b\xaf\x93K0$\x99\x91\x1f\x19\xbf\xb2\xb1\x0f[y\xe9\xdb~\xb9W(F5\x815\x8c'\xc0\xfe2~\xa7\xb6\xc0\x84\x1e\x98\xc7\xa46\x9d\x08W\xf2#\x8fE\xe1|!\x9e\x0e\x82\xd6W\xe5\xa7A\xa3p\xa4\xc3\xea\x14t'w{f\x1bV\xb2\xa9\x80\x15\xf8o\xfa\x08\x05u\xe3\x16\xaa/\xf1\xc1*S\x1d\xf6[\xdd\x02\x02V\xb1\x82\x001\x85\x16\x9e\xe0\xb6\x04\xf5\xdf_~\xa9\x9e\xaa-Ur\\X\x93\x1a\xab\\N\x18\x11\xd8\xf8\xb3\xd2\xeb\x0f@\x0b2d\xae\x8e\xf1o\xbc\xd4\xcf\xc2\xe0]\x1a\xf8\x85.\x08\xc2M\xd7X\xa2\x11\xf8*\xcbo\xb4\xeb\xac\xda\xa5;\x9a\xb2V\x10\x05+\x1e\x86a\xeaxXA%\x0f\x15ie\x88\xb6\"?\x99P\x9f\x0f\x101A\xa5\x9f\x1fx?\x86\x98O\xce\xfa\xba,\n\xb3c#p\xba+\xb3\xad#rY<\xc9\x88\xd2\x15M~JV}\x11\x9e-\xa2\xf0lQ0\xb0\x9a\xf4T\xe1\xee\xab\x97\x9ef\\zz\x13W\xe0\x81\xd2\xd3\x94U\xcc\x0c\xa3@\xf2\xad\x8f\"\x1f\xaa\xf0\xd5SK\x91M\xcer!9\xee\xd9'\xc7\x85s\x13\xa3a-vk\xab\xe7*o^`\x19XS\xbfo\x99fC\xe6%b\x11\xa8\x82R\xf4\xcf\xe9\xc6c\xab|\x13\xf8\x94\xdfqH\x9bX\xb8Rz\xfe\xb4\x15\x01\x15,\x17\xce\xf1_\n\xa2\x06 \x83y8\xbd|\x1e\xacd\x17\x0b\x9ck 3\x12\xe0\xed&\"b\xf6~\xc5\x08\xa2\xfa\xe0\xf5\x7f\xd1q\xae\xe8\x91\xc7\x00\xdb\xbb\xbb\xdc\xbc7~\x9e_$Y\xb0\xf2\xe6\xfd\x11\x9fO\xb1w7\xdb\x0d\xbf,\x12z\xddG\xa4\xa0\xbb\x12\x93\x8b\x8d\x94\xcfu\xc0\xd7\xb1\x08\"8\xf8\x0b\x0ea+|q\xf3\xdd_\xe8\xfdkz\xc2z\x88\xa7\x07\xdd\xe7C\xf6\x85>\x84^\x9e\x83,\xe4\xa1\nf\xda[\xd5\xe0\"\xc8\x8a\x0dF\xf4\xda\x12\x11\xb6\xe4\x94\xf8\x19\xc9\xf8\xbdj\x82\xf7\xdf\xe9\xc6\xc3\xe1\xdd\xea\xca\xbb\xf1u\x87\xd7B\xf0\xd9]u7\xba\xe6\xee\xf6\x8ac\x16\x89\x16.\xcf\xe7\x86\"\x87_m\xab\"\x9c\xbb@6w\x81h\x86#\x99\x01\x08\xc6\xe8\x7fl\xda\xa9a\x08\x81,\xfb\xeb\xd4\x11\xab\x12\x0c\xf6\xfe\xed\xd1\xd1\x1b\xccLK\xe2\x82\xcbR'P\xc6y\x99\xa6IV\x90\x80IR\x08\xa5\x97\xac\xffh\xc1:\xa4\xb0N\x7f\xddN\xfc[\x0f\xaf\x16\x017W8\xed\xb3e\x919\xf6.{\xd1\x002\xb9)c4r\xc6\xab7-\x98\xf4\x1b\xcf\xb4\xab\xccLH_+D\x0b\xb5\x1e\xd5$3c33\xf1e\x95\x82\x92\xaf\x1d\xcf\xe9\xc3\xc4e\xfd\x02$w\xb3\x00\x9d\x99\xa8\xb2\x92\x1b\xb3\xbe\xd1;'O}J\xe3\xd6\xab\xa7\x96\x1e*s\x9d\xd1\x01\x9d\x99\x00\xca\xb4\x9cd\xc8r2Q\xbby9\xd9\xc5=h9\xd9\xeau\x86l\x17\xd5\xec\x15\x06\xb7\xf54\xe5\x15\x87\x9e\x94\xbf\xe2\x11\xa4E\xefT3\x96g\xbe\x17r\xe2\x95\xa7*\x0f\xdbp\xdbK\xd0\x90\xd5\xd0\xa0\x1fL\x15\xe9G\x0d0tM\xb4k\xa9r\xbc\xfa\xf4\x07q\x05LT-\xa7j\xe4\x03\x82\xc8\x19h;\xe5)T\xc7\xa9Q\x07\x8d\xcb\xebxn\xd2\xd5\xe17\x12\x08B\x87\xa0\xba\xbd\xfa\xf2ws\xf6MZY~\xfbp\x03\x85\x82\xde\xaaYGW\xa7\x06 \x96\xf7\x95R>k\xf1\x80$\xa1\xe7\xbc\x8d+u\xe5;pKo\xea\xa2\x11[p\xb8;t\xdb\xa1\xba\x9eT6(\xc2\x9b\xd6\xa3Z4\xa4*U\xef\xfe\x8d\xe2Yw\xe5J\xffhB\x83\xed-\xbd\xd4`\xab\xc3\xd3\x87UQ\xc7\xad\xd9\xaf\x8a\x1e\xe8d\x07\xdb[\x0fu\xd2\x83\xedme\x8ckV\xf4yX\xf2\xc9\xfb\xd9lHX\x8dHym\x9aSyR\x16\x8b\xe7\x05YJ\xb9\xc7\x9b\x15\xea\xec\x0c\x93ZR\xd0\xacR\xa7\xa26\xa6<%3\x1e\xb6\xd0\x9ba?\x98\x90\xeb\xeb\xab\xe7\x01\x89\x8b\xb0\xc0\xa06b\x08\x7f&W\xa8*\xc2\xbe;\x8db`mQ\xf5i\x12\xe7\xe5\x92\xe4?0\x01\xd1JB\xfb\xdea\x17\x8aa\x8b\x0eQX\xe0\xd8Ek\xd0\x9a\xe12_\xcf#\xfft\xd0\x00\x05\n\x97\xd2\xf2\xb1\xbc\x0f\xb0\x8f\xd1\xe0z-%\xea\x0f\xbf\x0f\xf3\x10\x85'k\x9bj*\x8d>\x14FN\xfd\xd9\xfb\xba\xb2:\x1c\x14\xa2QK\xd4^uP\xdd^\x0cCR\xcd\xc00(FO\xab\xd7\xde\xec\xc2\xa5\x98\xbbzT\xca5U\xf6\xa8A\x1f\xf0\xb9j9\xf4\xbb04z\x04\xd3n%\xf1Qv\x95\x94\x05:\x07\xeb+'\xbc2\xf3g\xee\xa9\x1cr\xbd\x99X{}M\x96\xe5\xd2\x8f\xa2\xe4\xe2(\xbbz^\xbc.\x0d\x96P,\x87e\xc1\xeb\x1d\xc4\xfei\xa4\"\xd5\xc4\x83\xf1\x1f\xbc\xb9A\x0b\x12\xad\x10\x0e#\xa8\xebb\x1ag}\xcd\x05\xd6\x1c\x18L\xf6\xbc\xaa\xdc\x1b\x1fv\xc9\xb6`H(\xd9\xb3\xaa\xea\x80!\\UZ\xce\x97\xa8\xc5\xd4\xd7<\xad\x06\xfb\xc6\xa8\x13=a\xdd\x0b\xad\x8e\xbe\xe2\x05\x86e\xaeQf\x8f\xc3\xd8\x01\xab. \xa5?\xd2\xc8%\xfb\x80\x07\x85;BZZ_\xfb\x90\xd5~Z\xa1\xca\x1e\x0f\xb0\xa7\xac\xfe\xdb\xdaM\xbc\xef\x8b\xf7\xb0\x07%\xa5m\x0c>\x7fO(Q\xe5\x859e\xbe\xf4\xb5^\xc3\x1e\x9c0\x16ArS7\xcd\xee\x0d\xec\xc1\xa9\x97G\xe1\x8cP\x9c\xb51rx\x82\xef\xc6\xf7F\xe5\xdf\x8dS\xad\x1a\xb4oZ\xcd\xcd\xc7\xe8\xacO\x05w'}\x0eP\xf5\xdd\xb8\x9f\xd5\x838T>~\x155\xd3\xcc\x1c\xac\xfdX# \x02\xc5l\xc3\x82,\xc1\x82u\x9e}\x8b\xd9\x93v\xae^\n\xf7\x96\x8f\xaa\x1b]2S\xc3\xca\xac\xa0\x13\x1c\xa6\x04\xd5\xf6\xc4#2W>F\xf5ZQv\x86\x1f\xba\x9a\x9er\x0c\xd9x?\xd1~J\x83\xf9h\xdb\xd9\"\xb9\xfe17\xb3F\xedR\xcce\x17\xcd\x9bu-\x1c\x98\x06J\x18\x0d\xa2\x14\x8b\x88\xa7A3\x193=6H1]r 9K\xb3\xf1\xb4\xdd\x02*\xe5\xf5\xaf\x1b\x1e\x10r=\xf4fI\x19\x17\xf6\xad\xceD\x0b\x1c#2\xa0cmg\"7\xcf\xb0\xee$\xc4\xb8zO\x14\xe7W\xa0\xa6\xaf\x96\x0d\xa8\xb3\x18<\xe2Y\x12\xc1,\x89N\xd8\x85\x03\x8d\xdd\x8aN\xd0IK7\x13\xeb\x15\xbap}\x8aq\xc8nO\xda\xe1<\x93}\xa3\x1c\xe3\xb8\x1a\x99\x94\x06\x99P\x82\x8c:%\x9f \xee7\x9fV]\xbd\xf4S/\xcc_\xfa)\xf3\x17R\xd8\x1f\xd2\xe7\xda\x0e\xa5\x8e\x07&o\xd2\xcd\xe7\xa2\xcf\x8fh\x1e\x1bc\x95@G\xcaj\x88ZB\x1fA\xc1O\xe0\x94\xd1\x80}\xd9\x84j\xb6g\x02\x06\xfe\x80>\x99\x7f\x81W\xe6\x04z\xe2T\xa4\xac\xd6\xa2F]?\x84\xc8\x82\xf8\xb5|\xc9\xbe\xc2\xf4%\xc6v\x98\xdb\x94\xec\x94h\xae\xdf\xcc\x04\xd4\xe7\xa3#\x7f!\xa4H\xf2\x97-QV\xff\xbaK\xb2t\x03\x07%jsNo\x02\xe7}\x8b)\xb8\xb7 \xf4\x04\xd7\xaeBEN\xe0\xbd\xb6\xa2.^h#;\x1c\x06\xd8\xbb\x0b,\x7f\x13\xe31m\xc7i}\xdd\xbfJ m\x90o0\x01\xcbj\xdc\x9bm\xb2\xe6\x8e\xee\xad\x8a\"\xab\xef.\xb8\xcbY\x1e\x1a\x07\":\x9f\xf0\xb0\xe2\x98Z\xb2K\xb8\x1a\x0e\x8a\x8c!\x14,c\x1f\xc1y]-\xf5\x13\xdb\xa1\xa4\xe2\xeb:t\xab\x9e9\xb8\x93\x95\xff\x87d/oJ\x0f\xd7\xe0}\x82w=\xa3\xda_\xd7r\x01\x8c7\x80; \xfd\xa9\xbd\x81\xb9$\x03#%\x1a \x83\xa6\x87\xb1\xae\xda\xa5iN\\\xe6y&\xe2\xfb>\xade4\xdc\xff\xe8\xccmk\x8a\xafL + y\xf2 \xf05\x10\xe9\x00\x1c\xef=\xb9\xc2\x1b\xdfH\xa8\xf3\x8b\xa1_\xd8/\x9e\xa5\x97\x93\xe2mg\x06\x03r\x1c\x8bh\xf8fd\x0dm\xdcn\xacmr\x0f\x1e\xc6\xfeI\xd1<\xf9\xd2m\xa0\x06Zw\xcaM@r\x93\x83t\x17\xb8\xf1\xa9\xd1,\xb7Blo\xf4+\xd2\x08\xfc\xf8zP\xbd\xef[\xe0\\\xbd3\x01s\x9d\xf8\xa1/\xf9\xaf|i\xaf\x06\xc1\x03\xdc\xdc\xb5\xa6T\xedG\xa85W\x9be?\x84\x03W0\xcck\xea\xdb\x8e)\x0f\x19C\xe3\n3D\x9d\x12\x0f'\xb5\xe5sY\x0dr\xc0\xa9\x84\xd5h)\xf1\xf0\xc3\x9c\xd0^\x9f\xc7L5\xd4\xfba_\xa4\x90\xc1\x88g\x95 ~Fh\xa7F\x97\xab_\x03Z|t\x03\x8bo\x95\xa5\xf7\xb9\xe8M\x1dD\xb6%\xa9\xe9\xcb\xb5\xd4\x12\x01\xf5Uoi\xb8\xba\xda\xcd\x86\xbe\xac\xab\x92\x95\x94\xdb\x13\x98\xd6!SZ\xf1h\xe9\xaa\x06\x06\x1b\xaf\xf3\xcf\xd0\xa8\xc6e\xa6\x0b\x1d\x03\x16\xcc)\x95\xc1\x1e$H\xecdM\xd3\x91\xccl:\xd2\xf4\x93k\x81\xac_[\xe8\x89W\xab\x98)\x0e4\x94SZ\x83\x85\x83\x84\x9a\xbaZ\\?\xadod\xe9G\xea$\xedyq\x15\x11\x9de)%\xfb\xcf\xb2\xa4\x8c\x83\xa7I\x84\x19\xdc\xff\x7f\x0f\x1e\x9e\xce7\xb7\xbb\xf7t\xeb\xe4\x19\xc6\x92fj\x19\x9dL\"\x9c3\x1bx\xab\xdd\xa8E\x17\xdf\x92O\xfegj\x0d\xd6\x03E\xd9\x10(\xd2\xd8K5\x0dj?\xcf\xe9\x07\xdax\x16\x81\xce\x18.\xd0\x19\xc3\x05:c\xb8@g\x0c\x17\xacf\x0c\x17\xa8\x8d\xe1\x82\xda\x18\xae\xebd\x93r\x0f\x81-\xa5\xb1[\xf0\xe9\x8d\xdd\xcc)\xfe$c7\x15\xed'\x19\xbd(L\xde:\x9e\xc2\x83M\xdbn\x95Q\xf8\xf31\xbf\xe93\xae)jO\xe0\x1es\x11JPO-t\xde\xd98M.\xadc\x03}O!L\xeb%\xcc\xd7i\x8d\xf9M\x88\xe0\xc2\"\xeeX\x9a\x91\x99_\x08i\x80\x1dsI\x8e\\\xc0.\xd7>U\xda0\x86\x8e\xcd\xa7n}\xe3\xc2\xcf\xe20>3\x89\xffE\xdd\x89uW|e\xec\xfd\x94\x84\xb1m\x81^\xe8\x91\xe8{J\xbd\x97t\x16\x1d\xfa\xf3\x97kW\x86\x01\xc3Pd\xb9\xb9\xc9\xb6\x88\xa4\x94#5d\x0b#\x97\xa9\x1f\x07\xcfX\xbd\xbaoOzO\xcf\x9b:\x01\xd4\xcd\x1c!\xfb\x1c \x19_\xa6\xbf\xb3\x16\x9f\xe75\xf4\xef\x0e\x1a\x9f\xad\x83\x86\xc15C\xaf\xa8\x890\x91c\x97\x89\x02~\x93\x87\xde<\xc9\x96\xbe\xa2_\xee\x92\xc1\x03\x9a\xab\xfd1\x84K\xd7\xda\xde\x1eD\x18\xd9\xfb4\x8c\xfd\xec\x8a\xbd\xc1\xecB\xd6\xa9\x9f\x93\xddm\xf1F\xef\xa9\xc1@_\xef\xd2\xa0\xf4\xe4\xe0\x01\x12\xe7\xa12\xdd\x90\x84\xeaJ\x1eS\n\xf6\xc1\n\xe3s?\n\x03\x8b\xc9\xe0\xbbm\x86E\xd4\xfc\xa2\xd4\xd4\\E$\x9a\xdbU\xcaK:\xda|\xba\xa9\x08\xd2\xaf\x90\x07\x04a\xce\xd9\xdc\xc2\x0b\xf3g\xfc\xaf\xe6a\xf8\xcch{\xb7\xca\xbd\xdfL\xef\x0duR~\xe1\xe8\x9e+\xde\xd5u3\x92\xa7I\x9c\x13I\xea\x01R\xa6\\\xcd\xebJ\xde\xc3\xdbnEN\xd2\xb9\xcb\xc6\xf6}\x05\xd6\xd3\"\xb7P\x8b\xdc\x8c\x84R\x15\xf0\xacP\x06<\x8b\xab\x80g\x94\x88\xccX\xc0\xb3\x0c\xbe\x82\xe2\x11d\xeb\xeb\x0e\xc4\xd3\xac\x19\xf0,\xd3\x07<\xab\x15\xf0&\x92\xadJzwx\x95\x17di;M\xdb\\\xfc\xeb\xbb\x9cN\xc7HW1Z\x96\xd9e:v\xc6r\xbf2j\x96\xad8?\xde\x0d^L<\xad\xdb\xf6\x0f\xdd_\x8a\x8d\x0c\xcd\xd1J\x854\xb6\x80}\xc0\xd4\x18\xcd\x06\xacc`\x81t\x9b/\x95x\x0e)\xd5\xe7\xb1\x1d\xf3\xec\x05-XW\xc0]kl\n\x03\x88V\xd3Sag\xfa\xcc/|\x8b}\xe22\x85\x03\xcbZr\x8c}\xb78YWw\x18\xee\xaa\xffn\xe3\xa6\x81\xa8N\xeb\xdd\x8d\xa4\xd3\xba~(j\x84\xd2?\x14q\x1eT\xae\xcc\x98\xb8\xa1\xbe\xf0\x84\x0f\xb3\xd6\xc9:\x91P\x9b\x9are~\x00Ul*\xc59\xc6\x80\xa2\xfb0\x0d\x11|;s\xc2\x98\xcf.\xc4\x02\x94\xf5\x15\x9a\xe7\x0bH\x94\x13\x15S\x8b\xbc\x96\xa6\x9d\xa2\xdb\x8ei\x1b\xb3a{\x93\x0f?\xc8\x9f\xc9\xa6\xc4C6\xc5\xbc#\x03\xb7#6n\xc7\n{\x11W\xaa\xb4\xcc{\x9dq\x17\xf5\xd4\xb1\x1d\xe5\xd6t.\xed!\xfb\xe3Br\xbb\x9d {w\xc6\xef\xdb\x99\x84\xc5\xddeq>\xf7k\x84\xe2\x9b6\x8a%#\x17\xa8G_M\xb5e\x08Mn\x9d\x82\xa8\xa7\x89G\x9de\xa3\xb4}\xa2\xbcrl\xdah\xac\xd9\xb6\x81\xb1\xbai\xeb\xa5\x97\x914\xf2g\xc4\x8e\xc9\x05\xbc%g\x07\x97\xa9m\xfdb\xc1:`D\xc6k\xcb\x05\xeb\xccr:*9\n\x11\xa5\x04\x1f\xf8\xf3\xf7\xa5+\x95\xca\x8e\xd2\x8e\xedqG\n\x1a\xf2\x92Q'4\x0fSX\x8c\xb7v\x95T]\xf9;\xb2\xac\x14\xfb\xfer\xed\xb6\xa5\x82\x99\x0b\xbe\xf7\xee\xcd\xb3'G\x07'\x87\x07/\x0e\x9e\x1e\x1d<;9}\xfd\xea\xe8\xe0\xd5\xd1\xc9\xd1\xdf\xde\xfc\xfbZ\xaa\x88\xe0\xd5\x16\xf5\xf0\xcd\xebW\x87\x07\xbf\xcf\xaa\xeadR\xaa\x98\xac=\xeb\x91\xb8\x10\xeaH\xf1U\x16\x84a\xaf\x93\xef\x9f\xbc}\xfe\xe4\xeb\x17\x07w{du$\xc4 \x0c\x16{\xef\x89\xc2\xa8\xc5\x17K\xad\x069 \xef)\xef\xfe\xcc\x85\xd0H\x11b\x05\xe3V\x94.\xf8\xcd\xf5\xcdnq%\xd72\x8fQ[\xbd\x97\xf0\xd7;\x0f\xa4\xfb6\xa1\xcb\x82y\xf4\x92\xec\xc0\x9f-l\xbdh\x01\xe9>\xef^\x18\x07\xe4\xd2\xfb)gr?-\xd5Gw4\xb1U1\"\x88G.\xd3$+\xf2)#\x80R?\x9f\xf9\xd1S?'\xdf\x84\x11\xa1\xdb\xe8\xd8\x85s\x8c\x1b#.\xd1}\xe9w\xdbAH\xba~\x07-\\loo\xefR\xb2H\x8c\x03\xd7eg\xb43\xe8k\xc3\xb2\x0b\x1b\x8d\xad\xb1L\xd0\xd4\x11\xbd\xecU\x0c5*Z#\x93\xa6W P\xdfd\xc92\xcc\x91r\x89\xed\xed\x9d\xfb\x8e\x0b\x87H\x91\xd7\xa65^^\xf8Y\x91\xff\x102\x0dIlo?\xd8\x1d4\xc3\xd8~8FM\xef\xc3\x07\x9dU\xda\xde\x19\xd6F\x1fpno?TB\xe7\xf6\x8e\xca\xc0%\xb6\xef\xb7_3b\xef\xfeHZ\xe9\xe6H\xc7[\xf7\x1d\x1b\x05n.X\xf8\xaf\xd5\x83\x87P\xbbt\x82\xd2;\x9b\x08'\xb3\x13\xda\xff\xa6\xf8\xe3=ES\xf5~\x18\x92x4T\xa6'\n!|\x15\xac\xe0Da\xd7\x18W\x85\xe1\xfa\xba\x12{\xac\x11\xdcTxL\x19\x94J\x9cm\xd7s\x10\xa2\xb9\xc4\x1e\xa1MzB\x0f\x9bE\x0f;\x8b\xd3\xc6\x8d\x0cYZ\xd9\xfa\x1d\x992\x99C\xec\xe2O\x89;\xbav\xab\xcah]\xf3D\x08*Q\xd7\xc0W:\xb3Y\x17\x0e\xfe\xac\xabg\xb6E\xe2\"\x0b\x890\x9co\xc3\x8f\xbc~\xf2F\xca\x0b\xac\x8e\xd0\xd8\xfb\xa5j\xaf\xf9*\xaaP\x17\x8b\xb9\xda\xdd\x93 \x89)\xdb\xb2f\xa6\xfdoy.F;\xeas\xf1\xb0\x1d\x95\x91\x1d\x8b\x87m\xc1\xb6\x8f\x9c\xc6#\xe9,\xeflb4\xf3\xd8\x1e=tl+,H\xe6\x17\x98CV\x0f\xbb|q(,\xd5\xb3k\xa1\x82>y\x1b\xa9\x11\x11\xc6\xef\xf6U:\x9e\x98\\\x16\x142Gn;u\x00\xed.\xc4\xb6)+\x0b\xcf\xaba\xaf\xb6\xdc\x12\xc2Q\xdf\x86[\xbb\xeau\xdd\xd5\xe2\x95\xedm\x07\xf6\x95\x9coHr\xe81@N\xecv\xa2\xa1Jk\x10\xbb\xb8y!\xaa\x07\x90\xda\xadT\x079S\x16\x94\xf0\x18\xf2G\x0ed\xde\xdc&\\\x182\xcd\xd7\xd7\x8f](\xa6q[\x08!\xa8\x8c\x9b.\xd8\xfd\x91\x9a|\x18\xa9!q{g[\xb3duw\x1a8\xab)\x0e\x96wFGQ\x94l%\xf4q-#$9\x84\xcaES U\xa3\x14\x1c#\x05iBI\x1cv\xa9\xc2\xda\x9e\xde\xb5\x117\xed\x11D\xf0\x18f\x8f\xf46\xc0\xb45\x9bne>\x9d\xad\xaf\x1f;\xb4\xcd\xd2\xa9\xcdU:\x1f2\xe1S\x7f\x970[_\xef\xe9\x16\xaf\x87\x19\x841\xe4Ho\xe4\xd3\xd91\x0b+\xea\xd4r\x0f\xac\xf2\xe1\x03j\xa2\xaak\xe5\xcb/a\xa3\x19\xbbhE\x1c'a\xb3]\xd5\xa9{\xe9\x17\x0bo\xe9_v\xc1\x88\x95\x84q\x1f \xe9\x11\xba\xcd\xb0\x0dq\x1c\xf8\n6a\x9f\x9e8X\xa7C\xdc\xa4\x97 C)7F\"\xea\xf9P\xac\xbds'\xc0\xaf\x83\xfc\x10\x83\xb8SHbD\x9eM k\x0d|\xb3#\xa2\xf3k\x8dPp\xc8\x0e\x88B+\xc1\xc6\x94\xe3\xda}\xf8\x009%/\"\x14\x87\xf1X\xb4\x9c\x9a\x9d\x80\x8dr8o\xb6\xf0\xb3\xa7I@\x9e\x14v\x8ek\xbe\xb33~\xb8K\xbf\x0d\xe11\xec\xecn\x8d\x1e\xb2\x86\xd6a\x84\xe0\x87\xb6\x04\xb6\xdf\xf9\x98V`\x0d\xecn\x8d\xb1s\x9f6p\x7fk{\x8b\xf7\xcf\xeacGt'a\xc2\xdf2/\xbd\xdc\xc5N\xc6\xb4\xcc\x87\x0d\xde\xcc:\x1d\xe7\x06\x1f\xd4W_\xc1h\xd3\x81u\xd8\xdd\xd9\xd9\xda\xbd\x1b\x08\xef\xdc\x1f\x1c vu\xd8\x90\x02\x8b\x83\x12e~\xa5\x0d\x8a*\xdc\xbd7\x90\x19\x13\x1f\xb6\xc4\xf0\xc5\"K.\x802\xef\x98%\x1dO\x80\x05a\x0eqR\x00R\x00\xa7\x11Y\xd3X~dv\xc1\xa2\xf0\x11g\xc5sB/\x81\x07\xc88\x8c\xb7\xb7\xf1\xdf\xed\xdd\x87\xec\xdf\xfb[\xec\xdf\x07\xfc\xfd\x83\x9d\x0eg\xb1\xbb\xe9\x08\xaefHg\xbd\x84\xd4\xaejgd\xd2(\x99\xc6\xf6\xe8\xbec[E\xc2N\xd5\x91\x7ff!\xdbi\xfdlQVn\x9d\x82\xfc\xda\x1eX\xd3\x04o{\xf8\xf9\xd8b\x0c\xd7\xfd-\xc7\xe6\x14@\xed\xc9\x00UCV?mU\xb5\x89\xe9j\x90l\xa7\x90i\x1dK\x1ah\x0c\xa94d-\xe4\x85\\\xa3\x1c\xfe\xa6\xc32\xac\xd8\xa3\xcdQ\xbf\x0d\xf5}:I\xb5(\x9f\xae\xe3\x03\x87Y\x1e:.X\xbe\xd2\xfe\x10\x83ik{i\xf7\xd6)l\x99\x088\x9e_\xaf\xc1\xa0\xf9KDK?\x11\xa2\xb8;0)\x0d\xbb4\xc4\xd5\xf8\xa8s\x0c\xd5z0Le#\x9d\xc3*\x02\xb6\xcdTG\x02$\xd8\x86d6\x13U\x89\xf3U\xf5\xa7\xd2\xb0\xe9\x1bE\x1e\xe5\xf5|\xf56\xd7>\xcep\xdb\xf8\xc6z\xea\xc7\xff\xb1\x80Y\x12\x9f\x93\xac\x00\x0e\xe9E\x02i\x16.\xc3\"<'\x8c\xcdZ\x95\x9a\xef;\xf3\xdb\xbbm\xc91\xc3\xc6\xe3\xed-%\xcd:RJ\x15Z\xec\xd3\x03\xc1>\xdd\xff\xef\x99}\xd2\xb0\xa5\xdb\xbb\xea\x95\x1dw\xc48>\xc7\xca\x94 }~p\xf2\xe6\xed\xeb\xa3\xd7\xed\x80\x15e\x9b\xdfo\x16\xb7\xc5\x01\x9d\xf58g\xb9+\x0b\xde\x15E\\\xe1<3D\xc6@+\x0c-5\x84$w\xe1\xa1S\x90\x17\x84y\x1a\xf9W\xf4v\x88\x93\x18\xf3E\xdb\xe3\x9d\x11\x9a\xf5\x938x\xba\x08\xa3\x00Y\xb7\xc2\xcb3\xcacX?\xf9\xe7>\xf3\xe9\x9dXU\x16J\xee\xfb\xf7C\x18\x07\xc9\x85\x17$3\x14\xa18^\x92\x92\xd8F\x18\xb9\xc8\xc2\x82\xd8\xd6W\xec\xd3\xc7\xa2\x8a\xf7\xcd\x1eC\xd1_\xfdx\x8f\x17\xa1j\xd7\x9bEI\x8e\xe9\x0ds<\xc1\xdf<\x82lc\xe3\x91\x03\x01\x89HA \xaf\x01i\x1aN\xb3c\xbdMYn\xb7`H\x8dI\xf9E\xc1,8)\x9dfD\xad\x889\x95tF\\F\x11J\x90)\x15g\x97-x'\x0ecpcrA\xf9\xbef1s\xff\x8aYZ^\x82\xa6g\x98\xd5\xc2qei\xab\x90p%v|+\x9a\x7f\xa46\x1e\xec\x9c\x08\x0e\xf9\xdb\x0f\xf4\x94\x1f\xbd\x98\xff{\x90\x1d\x8cF\x0f\xd4d\xf1\xb8\x8d\xa0\xb9\xf0`w\xd7\xb1\xd7\xda\x02\x075\xca\xb8\xc1\xfd\xce\x97\xa8\xe4\x84t\x17\x17\xe0\"u_Sfiz\xacX\xf3\x98\xf2\xd5\xa5\xc3\xa4\x04>\x8a\xf31%<^\x9b\x91\x88,\xa4\xf8\xf0\x11\x14BX\xcb\xf7\x03\xbf\xa3\xa8\x01w\x83\xb9\xa8\xfc\xa7\xd0\x8e\xb0\xb5\x0f\x1f\xea\xd6\xd4[\x14\xddt\x8b\x1e>\xd4\xac$\x83N\xdb\xfa\xd9r\xd0\xd5\x82\xd2\x81\xcf\xf3\x83\xb8\\2\xbe\xc1\x96`\x18L\xe6\xd1\x82\xd2=\xac\x93\x83\xd0s\x8d\xe6;y\x1a\x85\x85ma\x8e}\xde!\xb9\xf9 \xed@\x95\xd0ti.\xa7m\xdd\xdc{'\xd3\xe0\xd6\xff]T\xf5\xdf\x92\xa8J\x83\xb2\xb6w\xdb\xef\xc3\x01\x94\x8c__\x94\xd5\xc5e\xbcN\xcfH\xf1FT|=o^\xab\x1aX$\x02\x9d\x01fp\x0e\xf1dMQ\x1b\xad\xa2\xf0)\xa9\x90\xc4y\x91\x95\xb3\"\xc9\xd0\xe4 \xc28/\xfcx\xd6-\xddo\xfe-\xdd\xbe\x93\xe6g\x1c\x0f\xec\x83\xdf6\x00_q\xfdw\xb6nz&9\xfe\xc8V\x17XT\xf7'g\x1f(;P\xb1\x0c\x0f( \xcd\x98\xca-\xc7\x15\xde\xf0[\xfc\x82E\xc6\x80'\x8f\xb5G\x9bc\xc7\xe5>\xb5\x94Z\xc0\x83\x1b\xb5\xb8\x05\xf6\xaa!kp\xd1s6\x17\xba\xb3\xa0\x13m\xe1\xe9\xe1\xe1\xdb2\"/\xc2\\\x11\xec\xe0\xe9\xe1\xe1!%M\x9f\x91Y\xe4\xb3x\xd3\xdd\x80 O\x0f\x0f\xd1\x14\x817\xd1.\x8dB\x12\x17o\xc9\xacP\x97?{\xfd\xd2X\xc8\xe6\xa2->J\xde\x93X=\xf8g~\xe1\x1fe~\x9c\xcfI\xf6\xbc Ku\x1b\xdf\x84\x91f\xe4\xdf\x1e\xbd|\xf1$\x8a\x9e&Q\xc4\"P\xa9\xab\xf4\x95\x7f\x93dK\xee\x85\xa4\xae\xc0\x9c%\xb4U^\x92 \xf4\xd53|\x19. e\x89qs\xbb_\xbe\xf2\x97$x\x95\x04\xe4\xa5\x9f*J\x93@\xb3\xebo\xfc0\x16\xe1O\xd4K\xf3&*\xcfB\xc5|\xd9{\xcdp\x0e\xbf\xff\xd3\x0b\xbc\x8a\xd4m\x1e~\xff\xa7W\xe5\xf2\x94d\xda\xe27\x98%X\x03\x0b\xb4< c\xcd\x80\x0f\xbf\xff\x93 \x90\x0e\xbf\xff\x13\x83\x94$\xd3\x80\xc9!f\\\xfb\xba\x9c\xcf\xb5\x03\xa4\x07\xe5pAH\xa1^\xd5#rY\x1ce\xfe\xec\xfdS\xddQ\xa9jh\x8a\x93rV\xad]Ur\xed\xa2+zb\x07\x945a\x94\xf89|\x05\x0b\xc1s\xc2\xf9\xfa\xba\x8aZ]\xba\x18\xc9~1=W\x18\xbcQ&4\x98\x9e)JN\x91\xacW\x95\x9c\xc0\x1e\x9cR\xa4\x7f\xaa\xba\x90\x80_\xc5'H~\x9e\xd0\xfb\xf7\xc3\x07(\xed\x13\x17f.\xa4\x8e\x0b'\xd3y\xfdn\xee\xc2\x19E~\xd33\xca\x80\xa5.\xa8\xe2\xd2 r]\xd2[=s\xe0d\xba\xc4\xcfC\xfa\xf9\xd2\x85l\xba<\xae\xc5\x9b0\x14a\xf7\n\x804J\xcb\xed\xfbj\xbe\x03\x11w\xe3\xbd_Q\x94:&n\xbc\xbd\xfb\xefv%\xff8v%z\x82\xef\xbec[e\x9c\xcf\x92\x14\xbdU\xda$\\\"\xfc\xf5T\x07\xa6\x123@2\xcd\x8e\x99R`\xe7\x01\x1a\xaff.\xfc\xa2\x97\xf6u\x98\xfaiv<%\xf4\x18\xc9\xf6\xf0\xca\x99\xe8$\xfeF\xd8\xfb\x0c\xed\\\x84\xb1\xa9/(\xa9\xf1v[\xc2\x92W\xc4V\xe35\xa7\xb0\xc6\xaa\xb8%*\x8d\xcf\x9c5\xdf\x16\xd4\xb0p%\xf7\xb7[\xaf\x03\xdez\x1b\x85,8\ni\xd7?\xe7\xef\xdb\xf6\x10K\xd6\xebN\x1b\xb5\x9c\xf1\xf7[\x8e\x97\x93\xd6\xba_\xb1\xb6\x1elvb\xe1\x9dr`m\x8f\xea\x84\xb7\xd6\x1e\xd5\x05\x7f\xdf\x1e\xd5\x01R\x9a\x95\x8c\xbeYx\x89\x85i\x96\xccH\xde\xf2D?\xc4\"\xae\x98k\x16=\x85=\xb0\xf8Gx\xceg\xf6e\xab\xd7\xf7f\x89\xee\x13\xb4\xb0\xdd\x83So\xde,xM\x0f\xc4\x9aY\xda[dW\x1a\x9eW\xe0\xc8C/#y\x12\x9d\x13\xbb\xbdz\xf2\x83\x1e\x1aM\xf6g\x8f\x1ea\xa1\x1e\xccS2C\xfcr<(\x1b\x96x\x88\xfd\xde\x85\xf7z\xd6\xf7\xba\xcb\xd2\x83d\xc7\xf0\x14\xfdQU|\x1c\xdf\x8b\xb7\xe4'F\xd9\x1e\x9c\x93\xb8p\x98\x0fK\xb1 \xb1\xfd\xde\x919\xb4\xa2\xd3\xcd5\xcc\xfcb\xb6\x00\x9cCK\xf9\xd6\x06\xbf7\xbdsF\x15\xb5V\xa8\xbcf\xaf\xa5\xf4\xbb\xe6d*m\xb5\xcd\xe21\xd0a;8\x85\xe6h[\xe0r\xd4\x87\xed@\xe8\xb9\x88w\xa2\x95\x88\xd02\xc4\xb7\xea\x0d8\xe7\xb6\xcb\xc4;\x99\xa9k\\\xe95\xaa\xf2\xd3\xe0.\x89wr\xcex\xcb\x11`\x8c\x9a\x93\x9c\xb1\x97\x9b\x8c\xb5\xac\x05K}p\xc5\x85\x995\x02M`\x1f\n/y\x0f\x13(\xbc\xb9\x1f\xf6\x84@\x87*A\x14?\x1c\xfd\xd5#^\x9d\x02\\\x7fm\x9649H\x96~\x18\xab\x17P<\xfa\x13,?%\xa5?\x124\x1b\x19\xf3\xb5[PP\xf9 \x89)\xfck\x0fF\x8e+\xe2\xff\x94H\x81\xec\xa1I\xb5\x8d\x81*f\x1e\x89\x0b\x92\xd9\\\xa7P\xda\x19\xf2\xe8\x98\xa1\xd8#\x97aas\x06\x7fm\xd3au\xf6\xd0\x1b\x81\xdbX\xefCd\x1f\xd8\x16?w\x1b\xb3\x85\x1f\xc60\xbb\x9aE\xc4B\n\x08Ma\xde\xd8\x14\x82\xf7!d\xda\xd2\x18\xfdK\"Z\x9cc\xc9\x04\"[\x91\x1dP~\x1a\xe7\xb2wYp\xfck>\x9f\x1f\x9fDd\xf7\x84\xdf\xbc6\xe0#\x88k\xd9t\xf8\xc8\x01\xdf\x8e\xa7\xe1\xfaz[9 ?\xf4\x90\xa0\x90\xdc\xad\x8e\xd5\xc8\x05\xd42\xaf\x89}z\xa9\x1b\x93\"z\xe6\xb5\xe9\xf8\xbf\xec\xc5Egl\xf1s\x03\xfd,\x1eD[(\xc4\xe5f\xfbxB\xb5\x13\xa5[\xfc\xbc\xa3\x80\xa9J\xe7\x14\x08(|\xc0C\xe0\xf0\xa3c\xea\xed\xa7\xde\xdeV\x85_54\xca\x80U-\xfa\xb7l7,\x01S\x05\x87\xa9\xaa\x02\xdf.v\x0b\x9b\x92u\x0e\x00'\x01J\xf4L\x0d>\xfa\xc6\x9dz\xd5\xbbv\xc2T\x8er\xaa\xddu)\xbc\x93\x00\xaf\x10\xfcA1\xbd\xcb\xd6\xa0\xf0N.hA\xe1x'\x94\xa2\xa7d\x85wB/\xc81\xfe\xf2\xc5W\xccG\xfdd\xc6\xed\x0d\xe9Eqd\x17(\xc40\x8e\xfc\xed\xb0\x91\xbb\x15o\xaeV\xf5\xac\xc5\xdeI\xa0\x03\x86\xb8\x9e\x14*\xcd\xf9\x9c4\xd7\xaf\xf9\xda\xa5\x9d\xb1\x1b\xb0:X\xf5\xe5\x073\xb4\xec9\xa5\xa7\x19\x89\x87\x00\xc2\"'\xd1\\\x97?\x8f>\xb8\xceo\xd0\xbcj\x7f(\xf1\x04\x12\xaf\xde\x7f\x17\x9e\\L\xc0\x90l\xb1\xaa\x16h\xd3\xb2\x8aGC\x95\x8bg\x18\xc5\"\x0c(\xe9}\xfc\x16/\x98\x11\xde\xcd\xaf\xf8\xef\xbb$\x03^\xb1\xbe\xb2\xde\xc0\xdb\x86\x9b\xdf\xa1wL\x05\xfe1\x03\xff\x11\x85\xef\xd8\x855\xddx\x87\x8d\x93\x8f\xcf<\x91\x01\xfb\xd7\xb3w\xd7\xda\xf9w\xe7\xdd\"2\xea\x1d\x7f\x8dg\xfd\xd0x`\x17<\x82\xe7\xa1\x0b\xe2PX.X'\x0b\xcbq1\xd4\xa9\x0bY\x9d\xc5\xbau*\xd4\xe0Cl\x04\x13\xd6n\x05)\xe2\xcf\x16r1.\xfa\xabf\xfe\xec\xe6\x97\xd5_\xd7.\xbb\xc4\xf5\x93d\xd2>A\xd9\xb1\xbf\xe4\x9b\x97\xbd\xc9e f h?\xfc\xeb\xbcSy!Wf\x84b= \xa7i\xdeco?\x189\xf6\xa1l[\xdb\x1e\x1f\x89\x07\x84\xfa\x17\xac\xdc\x13{)v\xcd\x9cS\xfc=\xec)\xd9T\xa6\x7f\xc6\xb3A\x19\xacf\xad\x9a3G\xba\x97br\xce\xfd \x19C\xefb\xfe\xe7\xa4\xb5&\xb3*\x07U\xb5\xc6\"Y\xcc\x89\xdf.\xcbi\xd9\x11\x9f\xc7\x1a\x05\x93Xp(\xcd}n\x9e#\x04\x97\xbe(v\x92\xc5\"\x13!\x88q\xeaa\x88kG{\xe5\xd41\xb9\x80\xecQ\x17\xba\x04U\xc8n\\\xfa\x86\xdf(\xa8'}\x8b \xd5GNU\x84Z\xe6=v2\xb0D\x86\xe6SoNwy\x88\xb2\x98\xe0\xcdv\x88\xdb\x89?}JA\x93\x0b\x16\xf4m\x82\n\xf5\xc6$\xe7\xf6\xdc\xfb\x13\xac\xc3\xdc\xfb\x01\xff\xff\x0d\xfc\x11\xd6^\xb7\x01\xf2\x8d \x8a\x0e\x1b\x1f3\x13S[\xc6\x15\xdc\xfe}\xec\xd8\xf2+\xa6v\x90L\xe0Y\xc7\x87\x8d.%|\xd3\x9e\x1b]\x9e\xbeM\x16\x04\xd2\x13\x15f\x02I\xf4\xb4\xe9V\xdc\xbe\xc3\x14\x16j@\xeb\xacS=\\\xbb\xa4+\xbc\xf6\xda1\x8e\x1a\xf7\xbbo\xd8|T\x17v)\x0eG\xb5o\x870\x81>\\\xd7\x19\xda\x9a\xfd\x9a\xc9\xeb\xb7\x1fl\x99\xa2\x85\x1ez\xcc\xea\xd9\xc3\x13d\xbf\x97\xc1\xc24-?\x8a\xfa\xa6$\x93\xaa\xea[\x8fa-\x9d\xf1\x10\x8b\x86`\x14\xdf$\xbc\x8a^d\x13\x0e\xe7T\x05\x1e\x9d\x1a\"4\x03o\xd2\x90$\x1f\xb8~m\xa4\xa7\xb1\xce).\xa7\xd7\xc8p9\xeb9\x0f\xb6\x14\xae\xaf\xf7S\x80\xe8!a\xe8\x1f\x90\x98F\xcc\xcbP =\x9b\xeb\xebn--\xa3\x10\x81(r\xf8\x08\x01;\xa6\xa4E.\x88\xf4iy\xcc0\xdf\xc6\x062\x18\x99\x1d\xf7Q\x85Z\xa6\x198\x98KM)\xeb]\xeb\x8f|\xe8\xa1-Ub\x87\xde\xf9\xd0\x8b%\xf3g\xbdg\xf7\xae\x00]\x0f\xc5\xc9\nP\xbc:luw\xbd>v`\x90\xe6i\x93\x08jw a;\x90\xd9\x89i\x07$\x14\x84?o\xa4\"dB\xaf\xf6\xd4\x91\xc7\xb4\x1b\xb6]\x05\x8a\xed\xb9\xaasmo\x0f\x98\x84\x07\xc2\xb8f\x0dk\xa7\x8f\x18\xd6\xc1\x9a@\x18\xcf\x92,\xa3\xb7u\x18\x9f'34K\xd2\xb9\x9a\xdd\xdc\xbe\xb8\xa3\x02\x14z~\xb5;\xf7\xf6}\x95\x9f\xbc\xc2\x86\xbb\xe4f\x01m\xcdc\xce\x9bi\xdb\x02F,\xb0W\xe3\xdd\xac\xe5C\xc2u\x1c\xa6\xdd\x98\xbb\x90\xaa\x08\xa8\xc0\x85\x85\x0b\xe7\xae\xb0\x07Ia\xbf_2\xd4Y\\\xf1\\\xa30Ze\xff|\xc5|Fq E-p\xeb\xd4;E\x13\x96\x0e\xdc(I\xe6\xb3\x9b\xfa!\xa20\xd5>sT\xf3C\x9dJ\x802|a\x9d\xe0<\x82\x00\x1e\xc3\xe9#8\xd5Y\x9a\xa2\x95\xe9\x92\x07\x8c\xbd\xb2}\x9b2#dzz\xecL7\x8f]XLG\x18+\xf0\xca\xc6wN\xed\xa7\xba\xc4\x9f\xb3\xca\x0cu\xd9<\x8ej\x13X\xa6\xf7\xc1da\xdcq\xea\x11\xaca\x97\xe7^L.\x0b\xdbq\xbc \x89\x89\xc6\x1a\xb7\x1alb\x9f\xbbp\xe5\xc2\x82\x07\x82\x82b\xd8\xd0\xae\x1d\xef\xeb\xb7\x07O\xfeL\xc9ezq\xbd=8z\xf7\xf6\x15\xec\xc1l\xb5C\xb6\xd3o%-\xe07\xe90\x90JFW\xe0:\xd8\x87\xc2\xa6\xf7\x14.\x7f\xcc\x97\xbfh_\\\x15\xafk\x8c,I<\xd6\xacB\xe6\x87\xe0'\xe1\xaf\x90\xa1\xd8\xb0rhs\xdb\xfa\xc6?4\x7f\x0d^\xab\xae!QR\x1b\x99Hf\xa0M@7Y\x98\x0c3\x1f\xe1+*\xcd\x11\xaf\x11;cv3L\x8c\x87\x86W\xd3\xe4\x98\x0b\xf5n&:\x8d\x1c/a\x98\xc3NuY\xa1f\x0b?\xf3g\x05\xc9\x9e\xf9\x85?Q\xba\x94q\xfb\x9c\xde\x85H\xbd\xc0/\xd0j\x8aNe\xde\x03\xdfJ$\\\xf5\xa1\x9a\x85'\xde\xdc.\xd0TOA\xf0a\x82\xb4\x12\xb9\xe0\xaeK\n\xac\x1aX\xa5\x90\xe3M\x88\xa7u\x14nLo\x18\x89\xfc\xa4%U\xed\xde\x7f\x82Y\x9b\xde?\x9ef\xc7m,\x1br\x16\xae\xef\xec'M3y`\x13`,\xd4\xac\xd3q H\x04\xe3\xaaB:\x1d\x1c\xc5\xd3\x12t\xfc\x01\xb8\xf3C#t\\fg\xde\x1bX\x87\xcc{kP1\xcd\xc3\xd8\x8f\xa2\xab\xa1\xd2w\x9f+\x8d\x93*j0\xe5\x88\xc5\x1f\x1a\xd1{\xacSr\xab\x92\xd9\xb4\xd5\xc7\xb1,\xa7\xd4\x1ab\xf3\xcfJ\xcchj;m\xbd\x8a\x89\xcc\xeal\xb4\xfc\xa8\x8c\xcb(\xebF\xa9\x8b\x8f<.\x86`V\x1b\x96^u\xf9\x11\x81\xb7\xebP\"\x02\xf7l\xb7\xc0\xf1\xd0\x00\x88E6\x18\x08\xf1\"\\\x84\xb9\x01\xdcB\xa5}\xad\xd0J\xc7\x1eACwn\x0b0\xa9\x953\x8e\x1d\xa3\xd2\xa4_M=dAc{\xfb\xc1}\xae\xa5\x7f\xc0\xff}\xd8\x8cj\xc7\xc3co?\xe4Q\xed\x1e\x8a\xf7;\xfc_\xfe\xfdC\xfe\xfdC\xf6\xfd\x0e%G\xf0\xdf\x11\xffw\xcc\xff\xdd\xe2\xffn\xf3\x7fw\xf8\xbf\xbb\xfc\xdf\xfb\xfc\xdf\x07\xfc_\xde\xde\x88\xb77\xe2\xed\x8dx{#\xde\xdeh[\x19e\x8f9\xdb\x0eY\x8b^0\x1aw\xc2x\x87U\x90J\xbc\x92\x9f\xf2\x10\x8f]\x94(WJ\x02\x82\xfe\xc1-\xc8CD\x88\xe6\x04k\xcc\xd0}\x84\xf1V\xaa\xa0\x19Ul\x91\x0e\x82\x94\x1b\xed\x83\xd0:o\x9f+\xb4\xdc8\xe9n\n?_$\xed{\x0c\xbeVL\xc0\xa2\xc2\xed\xc1z\x9d\xc8\xcf\xc78; \xc5'\xa3\xd1h{4\x1a9\"v>C\x18o\xfd\xf8\x8c\xebH\nYG\xe2\x03\xa6\xb3\x84Y\x12\x10H\xe9dtv\x96\\i]\xc0W,\xba%\xecc4 \x0cy\xca\xa2_\xae\x83m\x17\xb0\xb1\xc7\xca\x1dx\xfc\x18\x10~\n\xf8\x0f0\xda\x1co\xc3:\x8b\x99\xd9\x9b1\x17$\xfc\xcb\xb3\x0c[\xb7\xc3a\xbd`\xa6\x8b\x1b4\xda\xdcR`+\x0dPd\xfe\xc5pP`\xb15\xbc\xcc\xbf\xe0LiX\xcbnM\xe0A\x81\xa7d`\x12\xc3c(\x1f9\xc0-\xb9x\xe4\xd6bZ\xae\xaf\x1f;\x18F\xe2+&kiV\xa8\xc1\xa6<6X\xab\xf9w\xb3\xf4\xea\xeb\x83\xe2\xacM\xc7\xb6\x8a,\\Z&\x85y\x9b\x9bV-\xaa`\x059\x15\xb2u\xbb\x01\xf7\xc2\xca\x8e&\xd6\xdf\xa6:\xbc\xd4\xf6\xc3\xf6{\xba}\xd6\xd4\x82u\xf0YD\xce\xaeXS$\xdb\xfa\xff\xd3Z%\xff\xcf\xfac\x9b/\x8a\xea\xaau\xa5/\xda\xb5f\x03\xb8o\x90\x85\x12\x8aT\xb2\xc0\xc7\x1d\x0e#S\x04k\xb2\xe6O\xc9\xb1\xcd\xbc\xf3~\xfb\xf5\xff\xf8\xb7\xff\xc2\xe2\x9d\xf2\x9fX\xa6l\xe3Zs\x8b\xd3\xb5I\x98;s\x89J\xbe9\x86\xe3\xed0\xca\x807\xfe\x97_\x82\x9dLcZ;GWnA\xfbR\x94_\xca\x07\xb9e\xf9\xd2Z\x809\xec\xc1\xcc\xa3\xb0\xda\xc7\xa0\x81\x04\x8er0eT\x05\x8e\x803\xef6\xe1jE\x96]-w\xc1\xc2\xbc\xeccM\x85HTh\x11\x1ej\xc1\x82Z\x0b+\x8fT\xaem\xfdX\xfc\x18\xffx\xfe\xe3\xfc\xc7\x0c\xfe\xed_\xff\xeb\xff\xf5\xeb\x7f\xfd\xd7\xff\xf3\xb7_\x7f\xfd\xed\xd7\xff\xfc\xdb\xaf\xff\xc3o\xbf\xfe\x8f\xbf\xfd\xfa?\xfd\xf6\xeb\x7f\xf9\xed\xd7\xff\xf9\xb7_\xff\x97\xdf~\xfd_\x7f\xfb\xf5\x7f\xfb\xed\xd7\xff\xfd\xb7_\xff\x9f\xdf\xfe\xf3\xff\xfd\xff\xfe\xfa\xeb\x8f\xe5xs\xfc\x00\xff\xff\xf0\xc7rN\xe6sk\xc8\x19\xbb!M9\xde\xde\xc1(n-vF\x8f\x91g\xe2\x8a~\xd2{I\x0b\xd5q\xafm\xf3 $r\xc3 \xea\x02\x8a\x8d:\xe1%(n\xb1,\x8f\xc4\x01\xe6_Q1x\x14\xc8\xe9\xa7[\x8em\x89z\x96\x81\xa6\x11u\xfaVJ\\_\xa1X*\x17\xe4\xf6\x95\xe76V\xdcg\xf0\x18F\xb0/\xa5#\x1e\x1d\xd7\x06\xcc\xcaV2\x96\xf1\xc7\x1c\xd3\xacl\xe9Iy\xee\x1b\x11\xf9\xddN\xd0\xe493 \x18~j\x0d\xbc\x82O\xc7\xcdM\xe1\xd1\x0f\xb3DM \xf7\xdc)a\x03\xeaK\xbbd6\x15\xf9\xef\x02O\xf7\xc7J\xde_\x06\x8d0\x9eEe\xc0\x82]\xe8@C\xd4\xe9\x03\x8d\n\xed\xff\xa7D\x02\x8e\xba\x07\x0fS;\xbd\xc6\x08\x91\xab\x80\xc3\xed\x0ecc\x99\x06\xe3\x8e\x8c\xa4\xc4/&x\x83\xef:+v\xd9\xb7_\xa3\x91\x96\xb6\xb8\xa9\xb4\xb8\x0e\xdcO\x99`\x05x\xa3\xc0E\x91\x89>\xe4\xf1P[\"S\xf48\xe5a\xfaC\xd8\xdb\x83\x11\xdc\x83M\x05Ca=M\xca\xb8\xa8\x1d\xb7br\xe6\x17\xe19is\x12\x0f/\xc9\xdd\x0f\xbd(>\xc9\xd8\x93\xb8\x98%\xd1\xc78\xb2\xb4i:|\xd1\xfc\xc7<\xb6\xb4\xaf<\xfc\x99|\xbcY\xf0\xd6?\xe6$\xc2\xc2\x8f\xc2Y\xbe\xd2\x1c\x86L!\xfc\x14\x80\xb42\xf2\x19\xb4\xfa\x88\xf6\x17\x19\x99\x7f\xe4\xa5\xcf\x97~\x14\xad4\xfc!\xa3\x17\xad~\xf4\xc5\xa7\xef\xdf\xaf\x06\xfc\x83\xc6/\x9a\xfd\xf8\x13(O\xef~\xf4\xe5'\xc1\xfey\x99~\x84\xa1\xa7w4\xf4\xd8\x1e\x8d)\xb9\xbc\xf4\x8b\xd9\xc2rad\xae.\x0dfZ\xd5S\x8a?\xd5k\"\x1e\xc1\x19\x10\x93\x921\x91e\x0f(z\xa8\xd2\x99\xc5\xd3B\x9f\x19C2\xafO`_\xd8\xe11/\xaa \x9a\xc0q)o\xecL\x8bc!\xc8\xcf:qA >\xbe\xe1jrQ\xa3\xe5\xc2\xf8\x06\xeb\x99)<4`\xd0\x92\x86}K\xea7\x964\x93\x974\x1b\xb8\xa4\x12?\x91a\\\xb3\x04W\x95\xbd\xe1k\x19:,N\xd3\xdd\xadhN\xfc\xec\xdf\x01\xf4\xee\x963\x8d\xc2B \x9e\x1d\x03K\xfd: \x0dGl\x8fw\xda\xbe& D!\xdd\xd7L\xef\x86J\xb4\xae\x90\xc4\x9a\xa1\xf1\x8a\xe5\x9f\x9e\xce,\x9ew\xe2\x9e}\xea\xfc\xf1\x9eC\x99\xe3\x0f\x1f`\x1bu\x1e\x05\xc9\x8b\xba|\x7f\xe2\xdcsac$\xc2:\xd1zc\xac\xe7\x9f\xca\xb5|lH\xaa\xc4\x1a\xf3\xea:\xde\xbeC\xffkT\x92\xcb\x1d[*\xa3\xdc;-\xaf\x8a\xbd\xfd\xaaP\x05r\xe7\xdc\xf7Y\x12\xa8\xde\xb3\x9d\xfd\xfd{\x1e\xb9$3\xdb\xb2\xe8\x1c\x15P3DO\x02\x92\xad\x9a\xd0]\xaa\xe3\x06@\xd3'gOx!\xf14<\x95%\\;\x95\x8a\xfc\xedZ\"\xa7_\xab\x83\xe8\xe1\xe8\xd4\x9f\x9d3K\xff\xdc\x85\x08\xc3T\xcfY8}\x93\x93z\xc0B}\x86gq\x92\x91\xa7>\xc6\xf6\xb3B\x0b&\xf4\xda\x83uZ\xb6,\xa3\"\x8c\xc2\x18\x8b\x96\x8d\xa22\x0eQ\x11\xbf\x0fV\xd9(\xc8\x8bp\xf6\xfe\x8a\xbe\xbf\xe2\xef\xf5CX\x98}\xe4\xcf\x9b\xbbY\xc0>l\x8f\x1fn?\xdc\xbd?~\xb8\x83\xe6\xfe\x8f\x1f?65\x80\xd1g\xeb\x03O\xbc\x1c\x83\xa3\xbb\x10\xc0:Xg:\xfb\x01\x94\xfea\xd0\x06t\x8e\x90Z`J\xce%o\x876\xf2\x85\xbd\xbf\xf6\xe3\x8f\xb9c\xb9\x10\xa84\xd4\xd5\x83\xfe\xeeK\x06\x8b<\xbe\xe7\x9amG\x18y\x0cE\xcd\xb0\x0e\xf9t\xf3\xb8\x82\xf0\xc7\x80\xf1\xd5\xec\x94\x07?\xe12\xa5\x85+>p\x1c\x17\xd6\xd0\xb6\xbf!\xf1\xc2\xa4!\x9b\xc7\x95F.s\xcd\xe4O\xe3\xc1\xa9\xcf1.\x01\xcc\xe1\xab\xae\xe4{\x03\xc6\x8f`\xbe\xbe\xee\xc8;S\x8b\xd8\xe6h\xe8k\xe3\x8f=\xa5D\xbc\xf1\\;nw\xf0|9\xbe\xaaC0\xa2]\x00s\x14J\xe9\x07l%F\x0e\xcf.!-\x1b\x8b1\x1f\xb9\x90V\xad\xee\xc1\xb9\xe3|\x00\xbec,\xa3O{\xfb\xe8\xa0\xeb\xc1\xc19\xecC\xca\xcb6]8\xc7O:#hY.3\x8f\x06kS\xa0F!\xd3\xdct\xa4\x15\xb3\x07a\xb6\xe6\xa5\xd9FW\xb0\x0f\xd3c\x98\x08\x1cT g\xdb\xdc\xa0Z\xcc-\xd1\x08\x1a\xa2\xeb\x06d\xd5\x8d\x08\x01\x89\xac\x8ak\xb2*\xeb\x90U\xb1\x8a\xac\xcaV\xa5\x03\xcc\xf2\xfa\xd4\x8e\xed\xedQ[\xec\x9c\x88\x92q\xbb$\x14%;\xed\x12\x9f\x97\x8c\xee?h\x17\x95\xbchgk\xb3]\x94\xf3\xa2\xadNO\x11/\xb9?\xden\x17\xcdz\x03\xf7U)\x98\x88wrB\xf2\x97IPFD\x97C\x14$\x99\xff/\nW\x10\x8c\xbb\xc7r\xe2\xe9B\x99\xd5\xf9\xdex\x0c\x86v\x8a!o\xe1\xe7\xaf/b\x91\xbe\xb5\nC\x17s\x95\x0d3\xb6 \xdd\x84oP\x83\x10&\xa6\xf3\xcb\xa8\xe0\xa1\x99\x9a\xa0A7e\xbb\xb3Ts\xae|q\x1e\xfd\xa1z/\x96\x0eR-\x8b\xdaY;\xcc\xf4<\x18Y\xa3.E\x92\xd6Y0\xde\xdd\xd9\xdd\x1c\x05-E\x1b\xbdv\xad-o\xf4\xc0\x1b\xb7J\xe8}j\x9d\xfa\xf1OI\xab\xe0\x8c\x16\x1c\xfa\x85\x0b\xe3\x1dxR\x9e\xc1xs\xf4\x006\xefOv\xc6\x93\xf1.\xfc\xe9\xe5\x91t\x10\x86\xe9\ns\xb1\xf4\xde9\xc9\xf20\x89s\xbc*;/?|\x80_\xae]E\x89\x97_\xf8gg${\x17*\x9d\x97x\xb5 (\x02\xdd\x9e\x85\xc5[r\x1e\xb2\xf2\x85\xb2\xfcY\x98\x15W\x13\x08\xba\x85\xa7e\x18\x05G\xe1\x92\xe4\x85\xbfL'p\xd6\xad\xb2\xf4g\x8b0&\x93v\x0c\x85.\x07Ph\x1d\xaf\x82dy\x12\x06,\xcf\x94\x1ao\x06\xc9\xf2U\x12\x10S\x95<%\xb3\x89\xde\x88*\x8b&J5,/\xccMMG\xfeUR\x16\x13\xb0\xbe\xf6s\xf2\x02\xff\xd0\xb4\x14$\xb3\x83\xcb\xd4\x8f\xd9r[Q\x98\xebj.\xfd\xcbg,\xf5( \x8e\xfc3c\xff\xf30*Hf\xaa\x81\xe6\xa4~\x91d\xefp\x9e\x8b\xa2H\xf3\xc9\xbd{IL)^\x01=^\x98\xdc\xab*j\x86\xc5|\x97r\xfdB\xce\xca\xbcH\x96\xfar\x9eO\xf5uJX\xea\xaa\xe7A7\xa9N\xab.\xcfz\xf4\xac\xd4%\xbb\xaa\xea\x13\x92\xbe\x08\xe3\xf7a|\xa6\xaf\x94\xb1\xd6\x9e\xc7\x05\xc9f$-\x92\xacOc[\x7f\xc9\xb0\x97\xb2\x82f\xba\x19\xc9\xd3$\xce\xc9'\xea._$\x17\xe8\xd3M\x02\xbejj\x073\xa8q\xeb\xcb$ \xd1[\x12\x07$\xc3u\xb3\xc8\xa5\xbfL#\xa2\x83`\xe9+\x04\xe5\xe0\x19I\x8b\xc5\x04\xb4{R\xd7\xcf\x87|@\xa7ppY\x10<#\xb9~\x1fi\xbd\xa7\xc9r\x99\xc4\x83j\x97)\xc5\xc3$8,O\x97a\xc1\xa2M\xe4\x13\x98Zg\x04\xd5.i\xc9\xfeIr\xfc\x97e\xd1\xa5\xbf\x92\x94nU\x8e\xfa\x01\xe2\x07X\x89\xcb8\xad\"\xf3g\xc4\xd20\x9eiFrR\xd0>\"\x81\xb0u51C\x17\xad\xa9\xa9\x10\xc6a\x11\xfa\xd1!\xddX\xfd\xd1\x9a\xc7\x86c\x99,\xd3$\xa6|\xcb\xa4\xed<\x05jp\xa2\xfc?%\xd3\xe7^\xeag99D\xb9Y'M p\x82\x89x\x1c\x057\xf1:OF\xac)\xa5X?\xe5\xdd\xf8b\x8d\x1c\x9b\xdeq\x05\xd2\xde\xb1\xa2\xb7+\xed5\x91_\xe5\x05Y\xaa\xc8\x08\xf1T\xd8+\xf5\xf8\xcfU\x0eW\xb5M\xa9\xc7\xf7V\x03kl\x9b\xda\xb3\xd2\x8eJ\\\x1ff~U\xd4J=\xf6K\xdd\xb7x\xc4\x95\x90z\xec\x97\xb6\xb2f\xaeP\xdf\x98\xc6~X\x1d\xdd\xc5)\x1e\xbc]S\xaf\xcc\"\xfd84;\x01\xa9'C\x7f\x97@V\xc4&\xe8\xfb\xa4\xa2\xa7O)=\xdd\xaa\xdd\xfa\xbbEZ\xdb\xa7HRK\xfdS\x15\x9a\x078`\xb2\xdc#\xa5\xc0\x86\xb0\x073\xc7\x85\x13/'\x05\x1bCn\x97\x8e\x0b\x17\x02;=\xc1\x99\xe7^\x94\xf8\x01 0\x8fI\x9d=\x9d6\xb5\x16\xd3CE\x7fZ \xf2\x84\x16KQ\xb0\xe9BX\x8f\xb2\xc4y3^p\xd3\x85\xa4S\"%|ck$:.\xd3\xc0/\xc8\xbb,\xb2-\x0b\x07\xd6-|\x91\xf8A\x18\x9fQ\xe8/s\xdb\xca\xcb\x19\x06~\xd1\xd4>L\xc9\xcc\xa6\x83\xc8:\x83\xc0d)\xcdo\x82\xe4\"\xa6s\x07\x0c\xea\xc1g\xaa\x1d\"\xd6\xe8\xf4+\xda\xe0\xc5\xe8\x81#6\xc0\x81\x0b/C\xd2\xa7\xde\x14\x17\xac'i\xaa\x93\x97V\x91J\xb0\xfeI\xa8\x0d\xcd\x0f\x1c0s9\xb2\xc6\xdfK\x92] \xf8\xab\x9b\xd0\x8bR\xab\xe1\xe5bXj4\xc9\xa3\x89P\xe0\xc0T8\xbceL\x06\xd0x\x89`\xf7\xe1\x03\xf04\x1e\"k\xc7\xe1\xfb0MI\x00YM\x07\xc6 \xfc\x0bk\xe5_ \xc9\xf07\xfd\xf8_\xe0\xc2\xcf\x11\xed\x87\xf3\x90\x04\xbau\xe2x\xe8\xa2\x8b\x18\xba\xe7\xeb\x92bB\x0e\xf2L\xa6\xc8~\xbf\xcb\"\xa5\xac\x0d\xe5\x98\x8dM\xee\xbc\xa0G\x9b\x9d\xa8\xaf\xaf\xdeq\xb0Y3\xd6\xf8\xf0\xc1\xd8\x82\xe2\xfa\xc6K\xed\xb2;\x1d\nlo\xc92)\x08\xfb^M\x81\xab\xd8\x90\xd4\xeb\xbeU}\xa9`)\xe8\xa7\x9d\xd7M\x1c\xec\xc2\x01fb\xb0\x8d\xf3\xbc\xa4\xd5\\\xb8\xa0\x87\xf1@r\x03\xba\x96\x91,\xe9\xa5E\x1c2\xe1\xd8\xde\x19=\xe88\xf0\x8ev\x1c\x8f\x8b\xfd\xde\x93\xab|HC\xf5\xcau\xac\xa0\x99\xb6\xf5\xe1\xae4\xe1\xd8\x1e\xef\xdcwx\xbaM\x03\x95\xd1631\xbb\xed4\xb3s\x03\xacnX\"/C\xb3\xa3J8\x18\xdb;\x9d\xc0\xb0\xb5pq\xd2\x9fb\xb3\xb3\x03\xdc\x83\x1b\x1d\xbe[\xfbp\x7f\xdb\xf1\xe6rL\x94!-\x0e\x9cD{\x9bn7\x89\x9d1\xf3\x07\x1f\xdd\xe7~\xe4c\xeeW>\xbe\xaf\x04\xaf\xc3\xab\xe5i\x12\x0di\xbb\xd7J_\x9d\x8e\xb7\x13\n\x83G\xe9m\xe7\xb2\xe4\x913\xda[\xca\x83\xf4\xee\xb4\x83\xf1\xf2\x19\x8c\xb7\x1d\xef\xcf\x07\x7fk\x96\xb1\xd4\xa1;\xed\xf1\x88\xcc\xa1\xed\x011\x81\xf6\xc3vX\xa1\x94{\x87\xb4\x8d\x13x\xea\xd0\xb6O\xc2\xa2\x82\x94\xe6\xfbs\xfe^\x9d9tg\xdc\xae/2\x87\xb6'\xcc\xb2\x86n\xb5G\xc3R\x86\x8e\xdb\xb5Y\xc6\xd0N\xdc\x87\x0b\xbe\x9a\xed\xb9\x1e\xb0%h\x8f\xf1\x92Wo\xcf\xf5\x90\x8f\xbd]\xff)\x1bL'X\xca{\xb6\xe5\xed\xd7O\x04Bj\xbe~\x0d{\xf0\xb4\x9d$\xf4\x0d\xec\xc1\xfb\xf6\xcb#\xcc\xfb\xd9z\xf9\x12/\x08\x06\xd7\xcd\x92\xe7\xd5\xd5\xd1|\xff\x13\xec\xc1sJ.<\xafQz\xb3\x06\xbd`\x02\xdb:Y\x84A@\xe2\xb6\xca\xff-+-\x927Y\xb8\x0c\x99\xbfM\xb3\xc63\xd4\x03y)g(\x9f\xe7\x07q\xb9d!\x91\x9b\x15_\xd0\x1b\xd2\xb6r\x1c\xfd\x06c\x05\xb3\xabvs\xef\xe4Z\x9dd\xc6\x7fg\xa5I\xba\xa1\xa9\xf0\x0d\xecu\xb4I\xcd\x1a?\xeb\x02\xc2\xbcl\xd6\xfb\x1aW\xf4/\xac\xb1f\xd1\xf7\xb0\x07k_cf\x88\xaf\xa5\x8c/\xad\xbf\xbdy\x18\x07O\x17a\xd4R4|\x0b<\x82odvr\xe6w\xce}X\xdb\x83K\xfb\x0d\xf2fh\xd7\xab&\xd0\x87\xc5\xd8\x82\xba\xe17\xb2\xad\xb0Y*\xc2\x93,\xdf\xd7V\xbav\xbcn\xd0#P\x8aA\xae\x9dv\xddkG\x0eg\xa3\xb1]\x03 !\xbf\xb6\xbfQ\x9b\xd3d\x92\xac\xe2\x9biq\xec\xc2\x9b\xaa=\x1e\x10\x92 \xb7\xf9\x0d\xfd\xf9\x06\x9b\xe9\x04\xc0\xbf\x86 \xbcin\xd9\x0f\xbd|\xbb\xe0\xd9\xdf1\xaf\xf1K\xfbe\x0d\x08&\x1d%fL\xef\xaa'\x9b\xdd\x7f\x07{\xf032\xc5\x0c\xea\x1bP\xeb\x89\x9b\xbb\xb1\x88\x06\x80R4B:\x0b0\xa8\xa5F\x94\xfd\x97\xa6\x19\xfcm`l\x80\xaa\xe1=\xb1I\x7f\xb3\xff^m\xe0\x15\xcb\xe2\x02{p\xc13\xd6\xd1w\xb4$\xb1\xdf\xa1\x91\xc4>\xc6\xd7\xa9\x10\x10f\\\xa5\xfd\xbdby\x85\xa7\xaf\x8e\xa7\x053s\x11\xbf\xf7x\x0e\"\xdc\xb4Xw\x10\xea&)\x17\xb1\x89\x89\x8bT\x90\x0d\x93\xba\xc3\x0f\x1f\x18\xf4\xbdr\xe1\xc0\x1ea6uJ\xa6\xd4\xfd\xd2\xe1\x7f[\xad\x06\xfd\xb6\x86V\xd3b\xfey\x88q\xc8\x95\xd2\xf5\xad\xd6\xbc\xb3\xe0\x1fK\x9e\xe8\xb3\xa0CKXj+\x16e\x97IP\x98\x1fe\xf2\xc8\x81\xbf\xa1\xfe\x1d\xc3\x05&\x18\x06\xa60j\xdf\x8d)7\xfe4\xf88=k\x18\xaf\xe0\xc6\x13\x96\xaaP\xdb\xf3\x1a\xd6\xae\x01\x08A\x83\xe5\xf7\\K(0\x11f\xc1e\xaf\xd9\x05\xa2\xec\xda\x17\x9f\xff\xf9N\xfc\x16%\x0cz\xe8o\xbay\xe4\x18\x0b\xdbv4\xcd)~1d\x8f\x98\xdd\x05]\xff.\\\x0b)\x11\x89\xa9\x9e\x94\xff\xc8\x11{\x82\x87\xcd\x17\xb3\x8a9\x04\x7f#v+dSz7-\x0c\xe70l\xce\xaa\xae\xf73nmi\xdb/M\x81\x0d1\x08\x14=N2\xa2\xef&\xc4\xb0\x18IZ\x87{\x92\x92\xd0w\xf2b\x9c\xf3\x8cj\xa9\xca\xebw\xb3\xe1\xf5\xbb)\xf9\xe6\xbb\x9d)6\"B*\xaf\x13\xe0Y\xdajl\xc0SZ\xfe\x9d](\xcd\x03\xce\xfe\x9a\xbe:\x16\xf8\xc2\xae\x8f\xbc\xb8'\xbe\xad\x0d\xe9\x10\xa9\xab\xd2\x1d]+\xa5|H\xf2}O\xff\xf7-\xdd\xc3N.@\x18\x14I5\xa7T^\x8bXp\\\xf8\xa1\x99\xeeM\xce8h\x15I\xe5\xe3\xdd'\x04)0C\xdf\xfb?\xc8M?\xc5\xa4t_\xb8\x94E\x81=\xf8\x1bF\x90\xdby\xe8\xe0_\x87\xf8\xff\x7fF\xae|\xbc\xc3\xde\xfd\x89\xf1\xe8\xbb\xec\xaf\xbf\xf2\xfc\xc6k\x94\xdf\xdc\xc6e-\xe9\xfc-\x15\xc3`\xb9\xf4kD0\x0b\xfc\xbaWR\xf5\x83\x1d4$2t\xc4\xbe\xedc\xaa;\x1fS\xdd\xf9,[\xda\xcf\xed\xf5f ;\x91\xe8\x16Y\\V\x1d\xe7\xbfPva\xe1\xe7\xcf\xf9\x01p\xc3\xfci\x12\xcf\xfc\xe20\xcd\x88\x1f \x9b#(0\x17\x9d\x85\\n\xbd\xeb2\xd7\x0c\x97\x07\xe8u\xd1\xde\xd3\x958)W\xec\xcc\x91\x7f\xe6\x96q>KR\xda\\.LC-\xd7\xa2\x17\x01a8\xe2/\xf5!!\xe4\x91\x03\x81\xfd\x97)!\xcd\xb4\xe65\x12\"\x98\x8f*\xf0\xf2\"\xc9\xe8\xe5\x12\xf3V\nR7\x13\xd3f\xce\xed\x82L\xe3V;t\x05\x0f\x1bk\xc7Ox7B]\xbf\xfdG%;{Ao\xb5\xf5=\xb47\xdf\x87\x17\xf4TM\xd8?{\xdd\xe4\xea-\x04\xfc\x9e\\}\xd3\xdf\x15Z\xe0\x7f\x87\x16\xf8\xc6\x9c=>0\x1a\xb8\x83\x9b\xa0\x19<-\x8c\xe1\x85ZCA{z\x81t\xdc\x9e\x9c\xba\xc3H\xc6\x9799$\x05\xaa\xb1\x8d|\xda\xf7\xaa\xf0\xc0\x9d\x96\xc2e\x1a\x91!-5\x93\xcd^w\x8eJk\xa3\x19\xc3\xdb\x8dq\x84A\xd4\x07$+\xedZ%\x17\xb0\x0f\x976\xa6\xa5\xfc\xb3}\xc9h\x1d\xe3f\x07d\x1e\xc6D\xa8\xa8'\xf07CqH\xf2 \xfc\xb9Y\xe1\x8c\x14\x92\x8a\xfb\x19\xc9gY\xc8\xd4\n_\x98*\xbe\xf2\x97\xb4\xb1\x7f6\xd5a\xc7 \x9f\xc0_\x1b\xeb\x88\"\x96\xe6b\xdakx\xc5\x1a\x98|q\x11\xbel\xc7<\x16\x8c\xda4.\xa3\xe8\x18c\x99\xfdd\x0b\xba\xd3\xfa\xe5\x9a\xbf\xe9\xae\xbd\xdf1,m}\xc26\xb7\x851\x1d\x17\xac\xef\x0e_\xbfR\x04\x01\xa9\xb4\x0c+\x10?\x9cd#\xc7\x8c\xa3\x18=R\xc5\xe0\xa1,\x05\xa7\xc9\xea\xeb>ib!\xf1\xf0L\xde\x9c \x1a\x1d\xbb`\x9f\xda\x9d\xa4n\x9c\xc4\xffN\xf6\xbf9\xe3\xd5\xecb\x089.\xfaRJ\x87X\x987\xa44;\x06\xf5\x8eK\xfb-\x1c\x0d\x1a\x00\x0e$t\xect\x1a.\xfc\xc4\xb5*\xcf\xbb\xc2\x87\x06XIB\x84\xe9[$\xc6c{g\xd3\x91\x85\x0b.\xbcm\xd4cI\xb6^\xcf1_\xe8\xcb\x1aq\xb3\xbf\xfdb\xe1\x82E\xff\xb1\xf8=;\xe7j\xa6\x1a\x06\xd66\x07\xa9\x00j\xe9xG\xca)\xa2B\xa9\x93\xd8QBaU\xbd\x94\xe0\x073e\xda\xb7\x98\xc5\xe5\xed\x1a\xce(2HV\xa0\xea\xbb\\\x00O\xf1\x11\xed=\xf4\xe6,/\xcb\xe6#(kH\x8d\x1e9\x90W\x16\xe8\x94`/\xa7\x11\x12\xe5HN2\x10V\x1f`Ia\xb8\xda\x8av\x84\xdb\xc2\x9b\x90\x92]\xdd5\xfd\xe5\xda\x13\xa4D\xb3\x10\x83\x03\xd5\x86\x14\x02\x96/\xc28H.P\xc9\\\xfd\xe2BS\x05F\x84}C\xa1\xcdZ\xa0\xb8]v\x8b\xab\xb5\xa3\x83\xa88\x0c\x8akM\xd9H\xe1\x07l\xf2\x18G\\\xe58\xeb\x95n\xe9\x93\xd5T\x04\x88\xca\xda\xaa7\xf9\xbb\x18\"w\xf4Q4\xd1<\xc06\xcf\xbf\xdc\xd4\x14\x0e\x02\x00\xa6K\xb1-?\xbf\x8ag\xcfWR\xc8\x89OY\xfa\x12\xa4\xa5\x07}\xa7\xd6|\x15\xde\xe9UA^\xb0#0\xe4\\F\xdas\x89\xe9\xa5:%\x19\x96\xb4}:\xf9Ro\xd1\xdb\x13\x83/9p\x0f\xb6aC\xe2\xcd\xaf](\xbc\"\xf9\xfa\xaa <3\x9catm\x9e\xfd\xa4\xb0\xe7\xce1|\xf5\x15\x8c\x1e\xc0\x87N\x11\xac\xc3\x88\x17\x8f\xd5\xc5cV\xbc\xab.\xddr\xe8JL\xf3\xf5u\xbc\xa60\xb2\xf2.| \xe3\x9d\x9d\xf6\xfb\x07\x9d\xd7\xe3\x9d\x1d\xf8\x12Z\x89\xa4\xc6<\xc5\xb5\xb8:\xd5\x93\xd1\x0c\x96\xce\xe5\xf1c\xd8\xeev\xd2\xc2\xb6\xa3A\xbd\x8c6\x8dK\xb6\xad_\xb1\xc7\x8fa\xa6\x87wZ\xb0u\xfd\x12v\xb7\xe8\x0bko\xcfB)\xf7\x98\xb7\"\xf6\xcbf\xed\x8cq\x1f\x1e8\xb0\xaemx\xb4)Z\xa6\x80Q\xb5\xcc\xbb\x1aK]Y\xed\xa1\x0b)L7\xdc\xf4\xb5\x82\x7f\x16B\xc7D\x12>Ze\xcc8\x8f@N\x0f\xfb.\x8c\x8b\x07l\x1f\xf7\xe5?&,\x9f\x0b\xdb\x14\xeb\xc9\xd7O\x9f\x1d|\xf3\xa7o\x9f\x7f\xf7\xe7\x17/_\xbd~\xf3\x97\xb7\x87G\xef\xbe\xff\xe1\xaf\x7f\xfbg\xfft\x16\x90\xf9\xd9\"\xfc\xe9}\xb4\x8c\x93\xf4\xefY^\x94\xe7\x17\x97W?o\x8e\xc6[\xdb;\xbb\xf7\x1f<\\\xbfg\xf1h\xdc\x0c\x8f\xf8\x95t\xbe\x84\xaf \x7f\x04\xeb\xeb\xa5\x03\x19K\xc6\xedOK:\xf0\xa9/\x83r\xe9`,c\x95[[\xa4\xc7\xea\x02\xd8\xba\x84U\x01\xff\x01\xb6)\x1a\x13\x8c6E\x9e\\\x16\xf8\xc1vn\xc2\x84!f:^9mfw\x1df:\x8c_g\x8cB\xf7S9:z\xc1v \xa6\xff\xac\xef\xc1\x96\x83\x00c\x13\xba\x13\x14\xe5P\xec9\xda\xbd?\x1a\xed>\xd8d>\xf6\xd3\x92\x9e-\x06\xe9\x14\\w\xc6\xbc\x84\xa1\x0fV>>\xa6\xac\xb9\x80|;\xc4\x8cZ\x08\xff\x0f$\x98\x0f\xf1\xcd\xb8\xfdfWz\xb1\xbb\x05_B\xd8\xe6\xa9*\x8a\xa6{\x14\xaa_\xc9\xd4\xda\xb0d\x08\xdaD\x08\xda\x1dS\xd0\xb2NTE[JzC^\xcd\xc2\xcb\x88\x1f(T\x81<(\x8a\x02\x0cCW\x10\xea\x0f\xe0\x8f\x90PZ\x80b\x06\x85`\x94.\xfc\x88\xaek\xe9\xa8k\xa0\xbf>\xaeY\xb7\x8c^\xcb\x1b\xf7\xbb\xef\xd1~\x06\xf6\xb1\xe3\x11LT\x01\x0bR^e\x83\x96+\x9a\x0e\x10QR2a\xde\"w\xb8\xc3\xfe\xfa\x1e\xa4\x0c\xc3\x04\xf0%\x9f\xc3\xc6\x8cM\x02\x02x\xfcx\x0f6f\x94rX\xa7'\x18f\x18\xd8\x14\xeb\x8fwv\xe1\x8f\x10\"\xc2d\x1d\xb8 \xda\x9b\xc1\xc6\x1e\xcc_\xf9\xaf\xb8\x8c\xa7\xc0\xb6\x18x\xec\x83\x8dY\x04D1o\x92!\xef\x19j\xe9}\xd1\xd6R5\xcf?\x85\x0dX\x1c\xc3\x87=\x18\x8d\xe9\xc1:o\xddp7b\x8a\xb9\x10\xa4)\x9c\xb6\x0b\x17\xac\xda\xac\xb5#B\xe5\x96S\xb2\xb1\xab4bAj^)\xa3G$\xbcd\xac\x8c+\x81%[\xaa\xb8\x12X\xa2\x8a*A\x0b:_\xe4\xbc\xa0\x13l\x82\x99\x9a\x8e\xef\xb7U\xaf\xcc\xd6\xb4mf9\xc7ff\xad\xb7)o\\\x11\xe6\x82\xd9\x9a\xee\xec\xb6\x03]/\xaaO\x1e\xb6?\xe1\xf6\xa6\xe3v\xdfK1\xb7\xce\xac\x99\xc5\xa9&\xa0\xc3\xd5\xa7\x0f\xe8p:D\x1a&%\x1bm\x82\xca\x89IU_M\x8b(UA\x92t\x9e\xb15J\xe5{\xed\n\xb8\xd6\x88\x0d\xb4y\xdc\xd5\xcb\xab\x82\x7f\xb4\xdc\xc9\x84a\x8d\x8b\x05i\xbb@-p\xcb\xcd^\xc1\xbd\xce\xc5+\xb8\xcd\x9a\xbc\xe3L\xde\xc7\xd0\xf1@\xd6\xd7\xcb\x92\xa4x\x1eS\xd4\xd1S\x11\xe7\xfdF\xccN\xe1\xd4\x0c]M\x99xN\x932\x0e\x0e\xc5\xc45\x95\x8a$\x89N\x93K\x8d\xc34bz4\x00\xa8\\\x18\xe9\x1d\x81\x16\x01\xd5\x1b\xef4\x8c\x03\x1e\xf0\x87\x95\xa1\x82\x99\xdd<{p\xeaVn\xd63\x14r|w\xc8\xf6\x9ayUr\xe1[\xb3\x93\xfe\xb0\x85\xe2\xa9\x18s\xda\xfe\x99\xc7\xf6\xf9hQ\xc6\xef_\x86A\x10\x91\x0b?#\x8e\x1d;\x86\xc0i \x06\xf2\x12\xe1FNN\xde\x1e<{\xf7\xd7\x93g\x07\xdf\x1f\xbd~\xfd\xe2\xf0\xe4\xe0\xafG\x07\xaf\x0e\x9f\xbf~u\xf2\xf4\xf5\xcb7\xaf\x0f\x0fNNP\x87\xc7\xbcGsE$\x1c\x90\xc8\xc6M\x97\xd6D=\xe9!\xaa\xdd\xf9\x84\x12;b\xfa\x9ez\x98\\\xffS\xa5*wTf$6?\xaf\x8eXk\x0cO\xc2\xbdK\xd1\x1a\x05\xdfVN\xb5\xf8\x17?\x1e:\xadRk\xbce}$\x89\x0b\xd3\xee\xba\xbf'W\x13\xb0\xe8f\xd1\x19)\xdc\xa2\xf9\x05gTCC\xcb\xc2\x04a\xa6;\xdf\xe6\x90U\xe8\x81\x8dFLx\xc0hz}l\xd7\xd4\xa9\x07txp\xc4t\xb0\xf2\x0b=\xb0\xc9y\x80\x81\xd8&\xd0\x16\x0f\xe5}\x18t\x879\xa37\x1cJ\x91b\xc09\xfe\x1a\xc5JNC\xdb\xa8\x06KU\x9b\xdf\x94\xf1\xac\xf1-\xb1\x0b4\xa0\xd5y\xf9\xaa\x1aQ\x8c\xc0[\xfai-:\xd7jW\xe5\xa7\x1e@\xc7\xde\xb5\xfd\\;^F\x82rF\xec\x0b4\xa35\x0f\x957\xacA\xa0\xc0t4mTg\xeb\x02\x00^p\xfc\xc5qU\x8c,\x01\xb7\x06m\x1cH\x85\xfe\x03\x9a\xd7r\x1f\x00\x08\xfcF\x9b\xd6O\xf1\x9c\x07\x17U\xc0\xedX\x0b\xb7\xe3\xe6\xfd=>\xeeq\x0d\x07Nd&\xde\xc2\xcf_\xa0\xb7\xb6yD(T\xd0W\x19\n\xd3\xa8\x07T\xa9\xdf\x0b\xcf\x9f\x17${\xc1\x9d\xa7\x91\x83X\xdbt\xe1\xc0\x96J\x1cY3\x1f\x9bB:\x9a\xcf\x84\xdc\x0c?\x1e}\x1e\x12\xd52M\x14\xd9\x9f\xc5c\x82\xdc\xbb=`\xcd\x99dB\x18\xd1\x7f*\x07\xcd\x03\x00TY\x80\xeb\"\xfd4\x85\x95\x18\xb0z\xd3\xc5\xbb\xa1\xad\xf0\x18T\xba\xe3\xd13\x02\xceG\x16\x82K\xe2o\x06u\xfe|9\x81\xb9XZ}\xb5\xb7\xc4\x9f\x15\x93:H\xa2\x1as\nn\x8cqi\x12\xcf \x18\xc6\xe5\x96p\xce\xa7u{p\x92\x07\xa9\x8bX5xdw9\xb0\x01\xc2\x82!c\x87\xce\xf8\xbbo\x0c3\xcaW\x99\x91\x96\xb7Q\x0c\x14\xf6\x14q\xf7\x06\x0f\xab\x894\x07\x0c\xcdxE2b\xc4p\xef {(b`\x0bLmW\x97\x18\x9f\x99,.a\xbea\x8c|JN\x7fz\xe9\xa7\x0e\xbdA\xfa\x97\ndZ\x89\xf1\x18\x99fW\xb9\x87V+\xd6\x0f\xa9X\x93\x9a8\x1bB\xe6\xf7RH<\xc6-F\x82&\xd3\xf8x\x85H\xe0\x82\x10Y\x91\x0c\xe9J\xf8br\x013\xef\xa5\x9f\x9a\x19\x05\xe0\x84\x89\xcc\x15\xf7s\x93k\x99)\xc2\xb0\xfc\x08\x93\x80lZx\x94\x1d\x18\xd0x/\xa3\x0d\x12'u`\xc7\x8e\xc9_N~\xf8\x88\xab D \x97\x0c'\xc6/\xf5\xac(\xa8\xc4\xbe\xed\x07aO\x0d\x95\xc8\x0f\xbbm\xa8,\xe4\x08X\x9b.\x04\xde,Y\x9e\x86\xb18M\xb9\xc3r\xea\x9f\xf6&\xc97\xa3\xdf\xa3\xabt\x88L\xa8W\nC\xa6\x9b\xc7^\x91\xbcKS\x92=\xf5sb\xa3\x11P\x15+\xbeW\xec\x86\xa7\x9e\xcd\xcd\xb1\xf5H\xa2\x1aP\xacH\xe7!?\xe7<\xb6y\xac\xcc\xf8-\x1eTT;\xf28\x92&}\x9c\xc1:\xc5u\xa1\x9aU\xba\xcd\xa5L\xc9\x13A+\x0f\xd8\x80!\xb72\xdfN\xdb\xca\xab\x86o7@N\xef\xdfbx\x02\x915\xc7\xe7\xf3v\x07\x82\x05^\x06d\xc5\xcb\xa0\x03T\xc4`\xd6\xa2z\x1a\x02\x06\x8a^\x1c\x13\xa0\x14\x9dL\xe0\xf2\xa3a\xb5o ?j\xeel\xc0n\xf5\x9ef\xba]\xc3\x98\xd1\x06_\xa8\xf2W\x07\xdd\x86\xc6\xcd\xfd\xe8\xbfpi\xaf*\xac0\x8d\xeb\x0c\x0e\x1b\xf7\x9dc\xef\"\xf3S>\xa4\xdeK:\xe3\xf8U\x03h\x03\x04\xbe\xe2\x0e\xca\xa6q\xcf\xb5\xc6\xbbD\xe3K\x14\x10 A\x91\x9d0\x1f\x17\xb4UL\x8e\x1d\n]m\x9ad\xc8P@Z\xaa\xde\xa3\xd9~\xc4\xbd\x88\x87\xa3!\xaci\xa9:\x14Q\xc4t\x8fB\xbf\xd8~\x90\x90\x90\xcfY\xe6\xc8\x16\x89\x92\x87\xb2\xb4\xad\x10\x13\x12\xe4P$\x954\xaa\x96\xd2\x16\x0b\xbf\xe0\xafs\xf0\xb1\x91\xaa\xcc\x0e \x14\x0b\x02\x17\xec\xe4\x00CD\x8e\x0e\x11\xc9\x0f\xef\xe8\xc0\xcez$\xdd<\xf0\xe67\xbcO)\x88\x08\xbd\xafM$\x82\xb6\xf8n\xf1\xc4*\xd7\x8e Q\n\xa2\xce\x8c,\xb26\xb2\xa8%D\xfd\x01\x0e\x9a'S\xce\xa5\xa3J\xe7%?\xe2TN3 9<4)\x16A\xb87)qL\xc2\xd0J5\xf8^\xc4\x12v\x10K\xb1\xc2\xf0A\x16\xcaO\xb3a\x88\xc5\xef\"\x16\x9f!\x16\xb4x\xf5\x99M\xaa\x82\xd9\xe9\x1d\nH\x14\xd5\xca\x88\xa5\xb2\xbe\x0d\x15\x1c\x0d3Mb\x83\x0d\x1dn#\xcdlr\xc3GP\xae\xaf;h\x0e\xdd\xe0M\xca\x9e\xe5\x10\x8f@\xf1\xc8\xcf\x990\xda\x94\xcb\x8b\x9e\xc7v\xe2\x1cS\x8e{\xe6\x17\xb6\xaf \xad\xdb\xcfM\x10\\hBp\x02\xc0~?\x0c\x17\xf6\xa1\xb7\xc2\x80\xde\xd4<\x0e\x08\xf4\xa6a\x81n\x87\xdeP\xca7\x08\x99\x0d\x90\x94fM\x0b\x17\x15.X]^\xd0\x14\x08\x10\njL\xec\xad^\x0e\xf7v\xe2\xbe\xa6|\xfd\x1fg]\x06#\x16\xc1m\xb3C\xabr\x11\x15\xcf\xf5G\\\xe3o\xe2\x01K{c\x99\xe5\xc4+\x93\xc7z\xeaV\x83\x92\xaa\xb05<\xb6\xf9\xbe~\xf4\xd0\x96,\x8b\xb2[m\xce\x9d\xd2jJz\xaa\xd2\x98T\x14\x99\xb3\xa2\x84EEa\xf5RFz6\xb0\x97\xc1\xe1-\xf4\x1e/\xf9ix\x84u\xc9\x8f\xb0\"?2\xa7\x8a\xe6\xe4\xc3W\x90=\x02\x9f\x92\x1f\xe1\xd4o\x92\x1f\xfe\x00\xf2\xe3\x9c\xa7C=\xb0cAl`*$\x0d\xa9\x11\x1a\x93W\xf2\x87O^i\\\x81\x89(m\xd6c\xe9\xd8\x85\xcd\xa2\xca\x1b\xdb4X\xd7|\x14q\xc5] )\x08\xc6\xe6\xfa\xf0\xa1\xa3\xf1\x13jt\xf5R\xcah\xca\xab\x85[\xed\xc8\x1d\xe2Q\x9f\x18\x99\x84\x1f\x80nl4(<\x0d\xc5\xbc\x9ff\xc4\xa7\x07\xcd\xa9\x10\x17\x90\xc1\xa6 \xd2\xc6\xd7\xce\x8b\x85\x99\xcd\xe8k\x1a\xe4\xeb\xb4\xe8\xb3\xe1\x82\x017\x9b\xfc\x08\xe9\x1f\x05\xfd~\xf8\xd6\xbb\xff\xb7\x1f\x94(\xdeB*!\"\x06\x0cZ\x1e\xe0\x1d\x0e\xabI\x1f\xba5\x138\xf7^\x1d\xfcpr\xf4\xed\xdb\xd7?\xbc:9x\xfb\xb6_\x03#\x1e\xcc\x80\xa0\xcf\x92\xa5zR\xff*J\xfc\x80\xa5\xf8Y\xc8j\x84AM\x98\xb5\x1bX\x03\xe6a\xecG\xd1\xd0-\x12@\xd5[\xd9\xdc\xb5\xc9\x02\xb0p\xb42\xd7[b\xaa\x97~\xca(\xe8\xe4M\x96\xa4C\x90\xd5\x10\xf9\xb7\x11\xcf\xf4\xb6\x04M\xac\xd2\xb2\xe3!\x03H\x9a\xdb.\xc93\x8e^\x87\xaf\xca \x92q\xd8\xb2\x0c!\xee\xec\xa6\x87\x02\x8a\xe5\x0dVL\xc8\x81\xd5VG:P\xea[\xb6c\xfam\xf5\xea\xdaV:\xaa\\hCG\xddZ\xc5\xab2\x02-\xd4\x0d\x9b\xac\xa2\x1b\x0d\x8fT\xde!\x0dA\x860\x03\x95\xb4\"\x83\xea\xcbF\x9a\xcd\xea\x05\n\xd8j\x96\x04)\x9a\xd6\xd5\xd6\xaa2\x80Z\x15T*\x91\xc8r\xe6\x1a$\x91\xf0*\xf9\x1a\x067\xe8H\xe9\xf7\xc1n}\x89&\xb6\x9c\x8c\x9b\xc6\x14\x18x\xf4\xea\xf6`\xa7\xd91\x86\x95\xc1yu\x1b\x99&.\xc4\xc7\xc6\xaf\x9bp\xa7\xd0\x19\xb7\xbe\x91\x13\xfdk\x9a\xd5\xba\xee\xcb\x8c}w[\xdb\xbb\xaa\x8a\xa1Y;\xddC\x18\x9b]B\x98\xa261$\xe5ow\x18V\xa9\xa3\x1aoe\xd5\x8f6\xc2.\xc8\xb2\xd5a\xca\xa2j.%\x9d\x8b\xdfG6\x9c\xf3,K~\xaf\xa8\xb2 `9\x93\xd6\xd2O\xa7\xf9\xb1+$\x9fye\xb1\xde\xd8\x96\xee\x9bir\xac|)O\xb2\xb7\x02\xed\x13\xe3z\xf4Ub\xf3\x13\xb0\xdfW\xdd LU_\xf2}\x88W\x8d\xf4I#2\xa1*J\xc4\x81>Z\xc6\xaa\x9e$*\x9c\xe9xQr\x86\x02]\x850$\x96\x93\xa9\xef1Ij\xcb\xf7\xc3D\xec\x0b'F#\xb1\xa0'\xa3\xa5\xb0\x98*N8\xab8\xe1B\x84\x12\x7f\x04 |\x05\xc5#H('\x9cQ\xf8\x92W@wb\x05\x82GcpN\xa7\x13\x17\xa6\xf4\xba\xaf\x00&SY\xae\x0c\x8d\xe5\x85\x11C\x9a\x19\xc3\x08\xcfE\xd7\x036\xd7\x7f\xe8\xfe\x92\x13\x8d\x9f\xe0\xdb\xdeX];[c\x85\x17\xb0\x9c\x14\xa9.U\x07\xc8S{\xca \x9dE\xdbI\x99\xb4\xa3\xca_\x0f\x19g=\xae\xf1\xa64\xdc\xcc\xce0\xcce\xc6b\x86\xb2|7\xda\xb8\xa1\xedX\x9e\x98+\xc5\x9b\xd7#q\x86\x0c\x85.\xd9\xb6)\x87\x94\x9f\xe7\xe1Y<\xa4\xa9\xfeY\xe9'\xc3z\x99`\"\x98-g\xc59\x98\x93\x0c\xc9\xa7\xf2Z\xbd\xfb\xd9\xed{\xa1\xeb\xd8\xf6\x9ef\xb1\x055\xc1\x1a\xb7\xd4\xb9\x8cv\xb6\xdaYyJ\xcc\x1aP\\$O\xf8\x01\x7f\x93$\x11i\xa5{\xc3Yx\xf3\xa4\xccL\xb5\"\xd8\x83{?\xde[\xbfw\xa6\"\x86gZ\xbfi\xdb\xb2`\x1d\xd0\"\x13MG\xed\xc8\x05\xeb\x8b/\xefYf\x94>W\xca>Q\xd0C\xeb\xf0\xfc\x1c\xf4\xcfY\x12\x17\xe4\xb2`1<\xf9\x9b2\xa6\x7fo\x1a{Hu\xe7Ul\x0b\xc1\x9e\xba\x18_\xd0\x9e\xd8m\x0b\xd33_\x99\x84\x19\x0f\xb1\x81\xac\xaf\x9bg\x1aHaI\x94\xf3\xcdH\xce\xf0\x98\x98\xf1{r\xf5&#\xf3\xf0R\x9a3_\x94\xb8\xb3(\xd9J\x8b\xb2\xe8_\x146\x9c\xee\xb2\xf8XZ\x8d\xad[\xa14\xaci.\xafi\xb7\x98\x02_\xc9\xd66o\xadms\x03\x9a\xc4WD\xa9\xfbs\nq\x19\xaeo\xe8\x15\x0b\xbfx\xcb\xd4\xac\x02\xd8)\x05\xcf\x13\x9e\x02\xcb\xe1\x98xa\xfe\xbd\x1f\x85\xc1ADh\x0d\xda\x0e}\x1f1\xc6 Jb\xf2$\x0e\xde2x\xfe3\xb9\xa2\x1d\xf8\xb0\x0e\xf6ZD\xe7\xcf\xe2\x9e MF\xff\xa2T\x01{\xbf\x0f\x96\x05\x13\x98\xd9\xf8\xa7\x03\xeb`\xdd\xb3\x1c\x0cU\xe8\xb8\"\xf0n\xe4\x98\xc1\xe5\xdc\xee\x0f\xcf\x04{`Y\xcd\x85\x113dq\xb9h\x8d\x19e\xc0\xd9\x10\xba\x1c\x03\xdd\xab\x802\xd2\x88\n\x02\xbb\xc0([\xd8a\xb3\xb2O\x87\xb3p\xa1\xa4\\\x92\x97\x91\x88\xf89\xb1K\xf3\x1c\x96=We\xe3\xce\xaf\xef\xf4\xb9\x14P7 \"\x95\x81I\xcd\xd88\x1a(\xaco\x9d\x8e\xc6\xcb\xce\x01\xa1\x9b\xe2\x07\x01]\x830>;J\xec\xb9\x98\xe8\x8d\x06R\x1dd\xa9W\xf9,K\xaf\xefp\xcc\x81\x0by\x8b\xae9\xeb\xc8>\xe7Iv\xe0\xcf\x16\x93^b\x06\x84-7\xb3\xb5\x96\xa2\xac+\xec\xc5\xabk\xb4 I*\xb7f\x84\xa3\x94\x85\x84\x9aWp\xd4\x8e\xc3\xdc\xc4\x0cK?\xfdH\x03\x9e*\xa8`\xfe\x15\x9e\xbf\xcc\x15\xbb\xc0\x9c\x8f\x8diJ\x96~\xfa<.\x92\x1f\xc2b\xf1g\xb1\xdb\x98?5\xf6\xa3 \x9c7+\xe3\x8e\x0e\xd0\x00\xf2\xd1\xe0\xb2-\xd9h\x8ckU$\x88\x12\xfb$y\x82\x95\xe8[\x80B,\x80\x1a\xa5vRg\xd5\xf0\xa9\xa6\xa2\xce\xf0\xed-\xa9\xa8\xd1f\x9b.\xc2\xc0\x7f\xb1\xfd\xc0\xe9\xb34\x16)U<\x91R\x85B+g\xa3\x86H<\x9b\xdf\xa5I\xda\xa3\x83b\xa7\x17\xfdjY(\x16Epr\xdd\x06\xc4\xe4\x02\xbf\xef$gP\xd0\x8a\xe6Y7R\x85\xd1&1)\x8fm\x8dw0\xc7\x85\x84\xdb*\x1fN\xc5\xfaPv\x92\x16\xa5I\x12\x1d\x86?\xd7n\x9d\xcd5\xa1\x97\x9b9\x9d\x04\xa5 \x92.\x01\xdb\x1d\xb7\x8c\xdf\x06\x9c\x15\x90\xc5`\xc6m\x89\x1bc\xe61%\xe3\x1a{\x01g\xf0}\xfa\xb6\x9a/K\xc7T\xfd\xb9\x07#L\xc6$\xb0\x18\xec\xd1\xbbS\x91\x9bIAZ\xc6\xa4I\x83O\xda\x0bB\x9f\x0e=?p\x0dn\x02\xe4 \xad\xddJ\x80\x0e*`\x8fyl~\xd5r\x80\x12\xe6A\x05\xf7\x9dT\x15\xa0^\xceb\x91\x91\xce\x82\x0e\xb90\xe0\x96\xab\x95\xdd\xc9je\xae\xf0\xcb\xeb\\1\xe2\x19\xbe`\xcax\x1e\x8a5\xeb\xf2\x81\xdd%3\x98\x91\xdcf\xd5\x92;Y\xb5\xa4Z5FM\xa8\x9d\xc0VZ\xb8NB\x88n\x0b\x9a{\x8d\x99k|\xac{m\x9b\xa5Z\x1e\xef\xdeW\xc5\xa2\x8b\xed\x9d\xadv\"]\xbf\xbe\x10c{g\xbb\x13^\xaed\xe5\x0f\x1d\x17,\xaf\x9d\xc6\x95N\xc8\x9aX\x9ax\xc5\n\xc4#\x08-\x0c \xd2\xcdx\x80\xef\x05cB8\x8b\xe4{$\x9f\xf9)\xb1 c\x92&\x18Z\x9e\xe5Q\xb0\xb7v\xdb\xd22\xb8\x990\xae\xa2\x06y\xdc\xccj\"\x84\xc7w\x9a\xb90\xd7\x11H\xa9\x8bq\xf2\x84\xb9F\x1761_I#05\x86\x91\xfd\x12\xacSz\xa2\xfcX\xbc\x12YP\x90|sk\x07F\xbcd,\x16\xab\xd9\xc27X\xd7\x8a\xcb\xe5)\xc9\xe47\xf5\xaa\xf2.\n\xef\x8b/\xf8\xc8\xd0\x15\xb2\"wg\x94{)\\\xca\x83\xb2\x00\xcd\xfbP\xc2: \x05\xb2\x89L\xb0\xe3\xc2HM\x13/0\xc6\xa5\xf2\xc8\x9c#\xb3)59\x81\x18\xd6A\xa1y\xa1\xab\xd2\xe4\xcf\x0b\x8d\x06\xa1\x92j/\x99\xc4zII\x8c*\xbc\xf6r}\xdd\x81\x05\xac\xef\x01\xb1S\xba\x0f\xd3\xe5\xb1\x0b\xe78\x97\xd4\x85\xa5\xc3w\xaf;\x02Ml[\x90\xd8\xa2P\x99\x8d\x10\xf8\xf0\xcf\xfaP\xd8\x95\x8b\xd1\x04\xcf8m\xd7\x13Z\xe6\x0c\xc1\xa0\xf0H\\d!\xe91s\xa9\x16\xe5\x84-\xca\x9a}\x05{p\xea\xc5\xe4\xb2\xb0\x1d\xc7\x0b\x12L\x1d&-\xcc\x15K;#\xad\xcd\xc9\xfa\xba~u\xc4CW\xa9\x7f$\xda\x01\xe8\x17H\x91i\xd2\x8e\xe1\xae\xcdSU(\x92P\xdd\xc1\xca4\xc7\xca\x0e\xc2P\x0e_\x0d\xc6\xd6\x9e5\x01koS\x03\xc1\xd6\x04\x8b\xc7V\x17J\xb4\xf2\x02\xeb\x0b\n\x93\x1d5\xc0\xbd\xe9\xde\xe4\xf8\xdeY\x1fc.5TL\xc9q\xb7_#GY\xc6w\xb3(\x9b8m\xdd\xa2\xec\x8di\xf1d\x95Ea\xcba[\x1e;\xccd\xba\x89\x1az\xbaV\xeco\xd4D\x13//O\x19\x15`\x8f\xd1\x97Pz1r\x1ci5\xed\xbd\xcd\x0f{c\xe7\xee\x17\xb4\x86W\xf5\xd9\xb9\x13\xfd\xd7\xfd]\x87\xc7\xe8\xfc\xc6\x9f\x15Iv\xd5=\xc5\n)\xc0\x84\xa2H\xbfM\xa5b\xd1\xe9i\xc6JOO3e\x85 \xc8H\x9e\xb3:\xec\xb7\xb2ZFx/\x19Qw\x94\x15\xe1,\"\xbc\x0e\xfeVV\xcb\xc3\x80W\xa2\xbf\x94U\xca LX\x15\xfaKU\xe5\x14\x8bO\x95E~\xce\xda\xa7?\x94\x15\x82\x90\x95\x07\xa1\xba8\xe1\xc5\xea\x9e\xc33V\x1c\x9e)\x8b\xa3d\xf6\xfe\xefeR\xf01T\x7f*+'\xc1\x15\xab\x96\x04W\xca\nl\xeb\xd4\x1bwZ\x16E\x12\xb3\n\xf8SUi\xe6\xc7\xe7>\xdb\\\xf6S])\xa5\xe0\xcak\xe1oe\xb5\x90\xcf\x8a\xfePVH\xf8\xd6\xd2\x1f\xea\n\x11/\x8f4\xc5gYR\xa6\xa2\x0e\xfe\xa1\xaa\x18\xf8\x05\x03F\xfaCW!\n\xf3\xa2\xaaD\xffPV\x0cX\x95@YH\xd8p\x03\xa2\x1cn@\n?\x8cr^\x05\x7f+\xab\xcd\xd9\xca\x06s\xe5\xaa\x06\xa1\x1f%\x0c\xa6\xd8Ou\xa5s^\xe3\\Y\xcc\xc7\xa9\x1e&_\x05\xe5\xfc\xc9\x12\x0b\xc9R]xJ\x02^~J\x94K4\x0fI\x14`\xd2\xe7\xcc\xb6\xc4\x1f\xea\x8ag2\x98\xd5\x7fj*\x97\x19\x11\x15\xcbL L\xf3$\xc1\\\xb5\xff\x1f{o\xda\x1d7\x92$\x08\xbe\xdd\x8f\xf5+\x9c\xf1\xaa% \x03\x0c1H\x89\x94B\xa2\xd8J%\xb3[\xdd\x99\x92FRVMw0\x8a Fx0PB\x00Q8xdQ\xef\xf5\xcc\xec\xdc\xf7\xee\\=\xf7\xd9\xb3;\xf7\xb1\xc7\xec\xce\xf4\xf4\x87\xce\xfc#\xf3\x07\xf6/\xecs3w\xc0\x017\x07\x10$\x95U\xbbo\xf1\x81D\xf8\x05wssss3s3Q\x08^\xe9B\xc9R\x16I\xc81.\x86\x90\xbd\x18\x92\x99\xdb\x98\xb9Mf\xee`\xe6\x0e\x99y\x1f3\xef\x93\x99\x0f0\xf3\x01\x99\xb9\x8b\x99\xbbd&\xf7qB\xc4\x8b\xad\x80\x04\n\xbe\x92\x85\xcaU\xb6\xb0\xae\xb1\x85l\x85n![\"\xca\x89\x17\xaa\x00\x92X\x92\xc0\x06\xf3\xc4_\xe2\xe4\xe2+Yh\x89K\"X\x92\xeb!\x88V9\xe2\x1c\xbc\xd1ERY\x80\\\x95\xefO\x10\x90\xefOH8\xbe\xe7\x97\xa7\x1cQ\x15_\xa9B\xa1\x7f\")\x04\xbc\x91E\xf8)\x8f\xf0K\xf8J\x16Bh\x85$\xb8\xc2 z/\xb3\xa3\xf7T\x81\xa5\x1f`G\xc5\x0b]`%\xf3\xc9\x89^\xfa\xc9{\x99\x9f\xd0\x1f\xe0Q\x8e\x05x\x94\xdb\n\x04\x99$%\xea\x07]P\xd2m\xf1b) \xb1\x17\xde\xa8\"\x91\x8f\xa40\xf2IR\x18\xc5\x18M\x19\xcb\xc8\x1fTA<0B1y\xac\xa5\n\xe1\xf4\xd2\xdbU\xbc\xca\xca\x85\xa4~X\n*\xba\x17[i^\x9cg\n\xa7\xf1\x95*\x84\xdf\"?\xb2\xf2\x13\x1fg\x00\xde\xc8\"\xc14StU\xbe\x93\xc5T\x11[v|Zp\x8c\xea\x07U\xf0gP\xe2gTV\x82\x03I\xc8\x91$\x08\x85\x84\x84@\x92\x9f \xcf$^\xa8\x02\xd8/\xb2C\xa9\xbf\xc4\xef\x8a\x17\xb2@\x89:v\xc4I\xf9\xb4\x98N\xf9N\x17\x0b\x15~\xe1+Yh\xe9\x87\x88b\xf0F\x16\x89\xf3d\x8a\x13\x82\xafd\xa1\x95/;\xb4\xf2\xe9\xdedI\x1c!I\xc5W\xba\xd0\xa5d\xe0\xe1\x8d,\x92#\xeb\x9d\xe6$\xf3\x9d\xe6\xcb\xa5\x9f\\\xca\"\xf0N\x17\x93\xf3@\xaf\x97\xcc?\x91\xfd\xc80R,Q\xa4\xe0\x9d3\x1b\xf3\x9c!\xd9\xcdH\x92\x9b\xf1\x8b\xac8\xd2\xa8\x1fdA\xc1[`)\xf1F\x16Y`\xfe\x82\xceT[vf\xdb\xb3\xb3@n\x87\xe2\x85.\x90)x\x887\xb2\x08R\xcd\x8c$\x99Y\xe2O\xdf\xcb|\x7fJ\xd2x$\xf0$u\xcf\x11As\x12;\xcf|\xfc\xf0\x99O~\xf9,\x98qW\xfc\xfa\x9c$\x11<\x0c\x83\x95<@\xcaw\xaa\x18\xae$\x9a5Y\xfa\xa7\x92\xbb\x11oT\x910\x88\xb0\x84x\xb1\x15\xf0\x93_K\xfcY\xc0\xa3\xac(Z&Q\x95\x96~\xaa\xf6\xf1\x94\x9c\xe3\x95\x82\xd0\xca\x02\x9d\x95\x9fe<\x89T\x19\xf1N\x16\x8b\xc3\xcbSI\x00\xe5\xbb\xadX1R\xf5\x83*(\xc6\xe4\x87\x95\xd1V\x93\xc8J\x8a\xb8&6\xd2\x9a\xc5\x92\xc8d1M\xec\xcf$=<#\xe7Q\x10\x85\x82:\x90\x05\n\xa2\x9b!\xd5\xad\x94\xb0\xc8\x88P\x05{\x0b2\xa2\xaa]f\xb5w2\x1a\xfb\xae\x1e|\xac\xd2 eMv\xc3~\x18\xc6\xd7\xf8\xe1\xba\xe95j`)\xfdk\xe4\x0c\xeb\xe1\xb5r\xd9\xf7zq\xb4\xa8\x7fp\xff\xbeeL\x8df\x1f\xcal\xe3&\xf2s&\x8doi\x19\xba\xfa\xcaT\x94x\xf2\xc4\x8f\xe2\xe8r\x19\xe7\xe9\xd3\xa7\x84\xa8tn\x95\xaf\xfah\x99v\xe6\xf4\xe0\x8dB;\x06\x82#\xc1\x98\x9e9\x85\x12\xd5RN\x0c\x17\xca\x15\xe3\xb6\x14Dm*\x14\x95\x8aUKA\xc55\x9f5q\xcd\x0c\x19\x8e@0\x1cg\x8eR\xde\xda\n\x02\xd0\xb1 \xbc\xda\n\xfa\xd1\xe5\x88-\x9cD7\xb3{ \xdab;(_\xcd\xdb\xe4\xdd\xeaQ\x9a\x9c\xaa\x7f\x1fk|\xcc\xfaS\xd3wh\xb7\x9a\\\xdd\x94b\xe6\xf4\xd4U\x13\xf6u\x8f\xf5!8j\xefk\x16\xcf\xcbx]\x98\x91`\xc6\xc2OY \x03\x16\x8b\x9a\xef.W\x9cEq\xe6\x83\x8a>\x88\xd2`\xc6\xd5P\x07m~\xb0\xce\xe4\xbd\xc0\xac\xd5\x99#\xdcn\xad;[k\x83\x01\x93\x9f\x00+F\xc7\xef\xee\xf4CBF\x05f\x16\xc3\x8f\xc5\xf0\xeb \x12 \xc5\xb4\x14\xd3\xd2|\xb5\n\x03>cY\xacC\xcdc\xfcb\xc5\xa7\x19\x9f1?B\xe8\x0c\x08g\xb1\xfa\xd3|Q\xbfP8\x87\xa8p\x0e\xd9\x13-\xc8u\xd8\xefw\x05\x0d\xdc\xd6p|\x8f\x85\x05f\x89\x1e\x8fE\xdfC\xf16\xe9y,\xef\x0091AS\xddf\x11.\xe5\x95\x16\x0e7\x18,ey^\x7fl>T\xe8\xa5\xc8q\x93\xea\xe0Q\x80\xdd|%\xae\x89\xe4|\x0d\xc4\xce?>b\xe7\x9d\x11\x9b\xa5At\x1ar\x8c\xbf \xd9\x80\x9ba\xf9M&\xde\x16^Ja\xe8\xf7J\x887\x1cp\xba\xa6\xad\x0e\xdey\x8e\xf1\xeeN\xe4/\xc1\x98\x95\xb8\x9fC=y\xab}\xb1\xedA\x1c\x1cL\xe3\xa8\xb8;qu\xc5\xaa)\xd0\x9bri\xb7c\x9fz\x94\xd1\x99\xd1X\xa7\x16>\x00\x14\x7f)\x90]\xcd\xa4\xa8\x0e%|(\xf1\x8bCw\x0b\x17\x05\xfa\xafk\x12\xb9\xc6\xbbL\xf5\x07\xd0f\xe9\xf0q6q\xeb\x0c\x86>\x01I9\x01\xb1\x05\xd8\x91IY\x80\xa4\xbc\x8cg\xbc\x95\xa3\xb8 \x0cm$\x03\xf9\xca\xef\x95`\xfc\xc2875\xd6V@\xeb\xbbZ;M\xea\xc6\x81UL\xba6*\xf1\xec\xd7_\xcb\xebpd\xf8\xcd\xd61k\\\x17\xf8\xa5h\x1d\xb6\x18\x90?X\xf8\xe9\xab\xf3\xa8\xb8[\x1ev\"\xfd\xac\x99A\x1b\x00\x83\xd6\x8d5c7e\xcf\xd8/\x80t\xc5\xd1\x1a[4q:\xd0<\xe5\x18\x07\xb4\x06\xbb\xbe\x9b-\xdd\x02A\x8a\x95\xa1{X\xe6\x05\x83\x9e\xeb\x17\x8fm\x8f\x18\xd4J\xcc<\x07\x7f\x1e:\x8c\xdb\x97\xa6Xp\xbf\xf1\xf6\xd5\xcb\x01\x9eu\x83\xf9\xa55\\\x80z\xd6\\i`\x1f\xaao~\x1d\x96Z\x1c\xc1\x8eY,\xcf\xa6\xfd\xf2\x1a\xe8\xf2\xee\xb2\xdd\x9cL=\xb7\x862\x157\x1f[\x8fYV\x99\xe9\xac\xfd(\xa6dAb\xef\xec@\x1f\xa9\x9d!*:\x1e8\x1bC\x8f\x15\xb3\xa7\x9c\x87T\xe6\xa6\x80\xd5\x80\x1d\xd6\x8f\xa5\xb0},\xf8\xf4}\x01\xc6\xd4c'y\xc6\x12>\xe5\xc1\x19\x9f\xb1_I\x99\x9f\xb1 \x9a\xf1\x0b\xf6+\xe9\xa0\xe7\xb1\x13\xf4\xed\x05\xf7\xa4k`\xb3\xcf\xee\xf7\xb2\x04\xa5o\xd1r:\xfc\xf6\xe9`\xda\n\xe2\x9d\xbc\x8f\xeaWX\xd3jo\x05\x81v;QG\xd6\x99\xc6vY\x9f\x96\xa5x{\xeb-]t0\xddT\xcf\x0d\xa7\xf4\xff;\xac\xc6\xd7\xf8\xc5\xaf\xd7\xe44:\x1d\xe0\nfa\x1cv\xc4\xd9i\x97f\x99lz\x0en n\x85\x0f\x99\x17\xa0\x9e\xb7\xd6i^\x12\xdd\x16\xcc\xed1%\xfc\x02BK~oX\x9fv\xc6\xfa\x10\xb0\xbe\xee`\xae\xfe\x18X\x1f\xde\x00\xeb\xc3[\xc7z\x85\xc2>:\x93\x04\xfe\xa9\x8dk)V\xca\\\xac\x94N(-J\xaf`\xa5\xcc;\xae\x94\x8d\xd5zpz\xcf\xe5\x99l\xdeL\x8e\x8f\xa2O\xfdY\xa1\xc2\x10\x195\x9e\x0da\x80\xd7\xf9{L^\x139\x8a@\xd3\x06\xb7J\xc8Z\xfa%\x13\xe5\xa7K\xd6\xef\xb0L\xcf\xe4\xa5\xb2\x95\x93zln\xae\xf6y\xb7\xd5.\xe0\xb6(\xc0\xb6\xf8\x05\xadc#\xf5\x83vE\x92\x99>\x87(\xfcQR+y\xfd\xef\xa0pR\x7fu\xc5\x86\xec\x1ed\xc0K\xc6F\x8c\xc3\x85I\xb8\xed\x07\x0cZ\xa5\xb5\x0f\x96o\xcfhJ\x02\x17g\x97J\"\x81\xe8\x84\xe2=\xf0\xd8\x1c`\x92\xa37\x1ep\xb1\x13#+\xfa\xdc\x0f\xc3 :-D\x0e)\x83\x95\x03\x8e\xb9\xd9,H\xf84\x0b/Y\x90\xb2(F65N\x04\xd18\xb9\x84\xc0*_\xaf\x92x\xb5)\x88N\xfa5[\xf9\xd3\xf7\xfe)\x1f\xb0\xafR\xce\xbe.\x1a\x1c\x00\xc3Z\xfct\xdc\xaf\xc5:\x9b\xfaa(\x9aX\x0e\xd8\x1b\xee\xcf\xd82N\xb8\xe0\\\x17Y\xb6\x1a\xdd\xbb7?\x19,\xf9\xbd<\xe5\x9bP{\xb3\xfc\x8eu\x91hx(f<\x19\x07\x13v\x007+\x8b\xcb\xa1*\x0d\x89\xc4\xbb\x05/\xcf:\x15\xa2\x19\xa4`\xe5(\x18\xef\x94%\xfcgy\x90\x80TQ?O!\xdf\x1dd\xa9$\x067b\xdc\xa9\xe0H\xdb\xa5k\xa6+\xe61\xbc3\x92\xa1\x0d*\xb4^\xba\xd6B\x1co\x10\xd7\xdd\xd5#\xc6\x10c,\x91\xa4\xdbm\xee\xa4v\x9b\xbb\x8b\x10\xe11\xdb\x80\x10\x91A\xed\x16ucMV\xeaBb\xbcB\xadM\xe4\xd0\x0e\x9a5nvS}\xea\xc8\xf5\x82\x17\x9f\xae7\xbbAx-\xf0cc\xe9\xf8\xe3\xe1\xa4\xd3@X\x17\xd9\x8e\x0d\xa3\xa5[\xd8\xf6\x05k~\xbf\xeeu\x96&s\xa7\xcdWL\x95\x9e\xc5\xba?\xd5\xe5\x85\xec\x80I\xbb(\xe0\xfc4\xf1\xfa\x1b~zx\xb1*\xef\x81\xf7XGG@\xf2K\xca\xf4\x08\xaf\x9c\x82;\x89\xb7ZJ6\xee\xfd\xea\xaf*\xd7\x1b\xef\xfc\xd3\x1e,\xe0\x16k\xb2L\xef &\x9bpD\xa7W\xa2\xe3\xaa\x07\xf58r6\xe0^\xda\xddwiN\x98a,\x05\xb5+UZx\x07\xd9\x84\xbc\x9a\x9bSR~m8\x01ht\xb0T\x99\xa1\xcf\xfcL\xfb\xfa\xcc\xcfx\x8f\xc6J\xa3&\xcemY7\xe1\xa7\xfcbE\\1\xb6\xa1Q7x\x9e4#+-\xd0/v\xec\xe6\xad\x1a\x91\xb6i\x1bn\xdd\xf6\xd4\xe8\xfd\x088\x9b\xc6=\xb4y+\xc620\x03M\x05$\x98;\xf4\xa8\xa9C]iL\x9b\xd3\xb7\xea/YIs>\xc9\xf6Q\xc5V\xa6xl^;\xa9\xb0}\xc1J\xcf\x07z\xc2\xdc\xd3\xa4b7\xf0C\xd0\xe4x\xa7P\xe9\xdfR\xfb\xbd\xe1\x83\xc1\xee@z\x1e\xb8Vkg\xa5\x8f\xe9\xdd\xfb\xee\xa0\x88\x98@Y\xf3\xb6\x19\x1b\x07\xb2\x9d\x07\xa4}\xef\x83\xfb{\x16\x83]\xdfQ\x92\xb9\xdb\x18\x87aG\x8c\x9d\x1fn\xd3n\xa3\xeb&\xca\xa2\xb3\xbdep\x11Di\xc7I\xad/xuf\x19\x13\xd2\xc3\xd4j\xef\x8b\x9f\x1c\xb1\xdeg\x87\x9f\xbfxyx\xfc\xe5\xb3\x97\xbfe\xf1\xad\x90f~\x16L\xbb\x95])\x0c\xefTZ\xfaS]\xa3\xc2\"\x08g\xcf\xd7\xadu\xca\xb3\xcf\x90\x1a@\x84\x9dj\x9d\xe3/\x0f\xdf\xfc\xda\xe1g\xf6\xaa/\xa2 \x0b\xfc\x10\"\x17\xadY\xf5\xb9\xd6\xddu\xaa&<\x82\xbb\xb4\xaa\xc6\xab\x97\xcf\x0f\xad \x94+\xe8\xc7A\x18~\x89\x8eK;\x80\xa4\xa8\xf6Y0\xbbF-\xf1\xb17\xa8($@j\xc3\xa3E\x9c\x0bp\xc86\xbeZ\xcd*\x10\xed:\xc8z\xbd.\xfd\xfd,\x98]\xa7\x1a|.Zv\x86\xcfW/\xdf>\xfb\xfc\xf0\xf8\x9asB\xd5^\x1b\xc8T#k\x0c=\x87\xa2\xc5\x1c\x8dX\xef\xd5\x8f\x0e\xdf\xbcy\xf1\xd9\xe1\xf1\xa7\xcf\xde\x1e\x12\xbc\x8f\xd9Nh%:\xb0\x10\x93\xe0\x8c\xcf`5}\x9e\xc4\xcb\x86\x15\xd9\xe5[S\xeb\xb7fA\xba\n\xfd\xcb\x97p\xe3\xbb\x13G\xce\x80\xf0j\xf5X]\xac\xab\x1e\x8b\xd6H\xd1\xd4\xce_\x13\x1cgK(\xb9B\xed\x11\xa1\x9a;\xaa\xb8a\x8b\xfa}W\n\xb4\xc7\xd1d-\x15\x17AJ;\xf7\x9b\x0f\x8c\xda\xe2\x88.C\xa6\x19y\xa4\xabP\xd6\xd0\xb5k\xf7\xca\xd2\xa1\x1b\xf4\xc5\xd8;\xd6\xe8N\xad.8\x13\xaa\xa7\xed\xb3\x85c\xa4B\xcb#\xb2\xf4Z\x08\xa9\xed\xc6kt{\xa5q\xa9\n\x84E\xda\xba\xf0+\x98\x87\xce\x1d\xd8\xe8^\x94u[C\xac\xba\x8e\x82\xa8\xbdU\xf5(>\xaf\xdd\xa6_=\xd0\x9f\xba)`\xd4\xd9\x14\x90)\xb1\x97\xe0\x16A\xd3\xd9\xed\xb3\xe2 \x9c\x8d\xd8cw\xc1\x88\xf6y\xe8\xa7\xe9\x88\xfdV\x9c3\x1f\xf4!\x19_\xae\xb2 :eY,C\xcf0\x9f%<\xe5\xc9\x19\x9f\x01\xa6\x88\x9ez\xec\xeb_I\xbf\xf60\x16>n\xd8\xd1\xd1\xdd\x8c\x9dp\x06\x11\xf2A\xb4\x0b3\xdac\xef\xf9\xe5\x80}\x86M\x05\x19\xf3S\xe6G\xa5\xc1\xb4j\x11R\xb8?{,\xca\x9c\x07a\xc8\xd2L\xfc=\xe1\xcc\x9fNy\x9a\x06'a\xd1\xb8n.~\x97vRo{\x94\xd8\x0b\x80\xd6A\xea\xa5\x1e\x90~\xad3;L\xe3\xb9Cs\xa2\xd9\x01\x0b\xc7\xd1D\xca\xe9\xbb\xf7\x83\x95\xa7\xcb\xc0\xa1\xb6C\x10{\xe4\x1e\xebu\x9e_1\x95\x02\xb2\x97q\x9eh\xb6\xc2\xa0 \xcb\x16~\xc4\xe2h\xca\x07\xec\xdd\"H\x05\xe4\xe7a0\xcd\xd8\xd2\xbf\x14s3\xcb\xb9h\xc9\xc7Mm\xd0C\x07\xc8gq0s8\xc6\x95_\xc0\x8b\xc7\xa8\x80S\xb6\xa7Y\xff\xab?\xf2#\xb4\xc7\xe5\xfa\xd3\xde\xac\xbd\xc4\x07\xa42\xeb\xd04?\xcf\xe2\x93 \x9aU-\xee\xd7PA\xd3\x81u\x98f#\x98\xd6\x11+\x13\x88\x95\x8e3;b\x9d\x10U\xee\xdc\x11\xc8Te\xe1\xd0Ml\x05\x8f \x12\xc2\xdc\x9fr\x1bB\xc5g`\x87Q\x9a#\x86eXj\xc9\xb3ENDg\x9f\xe5Y\xfci\x10\xcd^\xfbAb\x89TY\x8dR\x19\xd5\x97\x99\x0f\xcbl:@\xee\x1f\xa6T\xbe\xbb\xa4\xbfw\xf5\xc0\x1c\xd7\x1bC\xbb\x8a\x1cC\"\xb6\xedJg\xf2^h4\xce;X\x8e\xad`\xd8\xc6\xf7\xda\xf5\x80sg\x85!w\xa6fm\x97M\xc7\xf9D\x0c:li\xa9\xc1\xef\xb3\xfe\x881\xcd(\x02\xd8\xd6S\xd6d7\x0d\xc6+\xe0\xac{\x05\xb7\xdc\x86H*\x06\x8a\x92w\xdb\xc1\xc0P\xbfmR\xf4\xe7L\xba\xcfN[\x03\x96\xeaO\xe0\x80\x13q;\x13\xb0\xac\x13@\x99\\_\x81_E\x85\x11\x81 \xd1l\x15\x87\xc1\xf4\x92\xfdJ\n(\xfd\x9e\xc3\xeb\xf9\x82G\xb8\x02O\x81\xdd,\x96\xa6\xa8\x02\xc4x\x89\xb3\xdf\xd0\x9d\x03\x96`\xe4\xd2\x85#^\x042\xb0\x11\xd5C\xf4\xe0\x8be\xcf\x8a\xb2\xdd\xa0/\xddA\xcb\xda\x1d8+(\x1ec\xd0\x93\\|\xc7+*7\xd6m\xe0\x15\xcc-\xbe\x13\xa1\x9fY\xf7\xfb\xea\xb1$p\xa4AY\x83\xaf~\"=\xf3Xo\xc9\x93S\xaeB\x1c\xbd\x8c?\xcbW\xa1\xd8\x90\xf9o\xf2\xcb\xd4qG\xec\xb9\x1f\x89m\x17\x8a\xb1(\x8e6\xb1\x99\x14\x08x\xe62\xe2\xc8\x82Q\xca*:=`\xf8Z\xbf\xf5.\x91\x06-\xf8\xb5\xec<\x96\xf4;\xc5\xed^p\xfa\xa9\xbf\xe4\x18\x06]l\xbd\x9dv\xd6\xc7\x02D+\xf0\xf0*\xf6\x044\x92SE\xa7~\x9eJk\xb2\xf3\xb8.\xb6u\\\xb1\xc5\xd5\x0e\xd3\x8e\xab8\x0e\xc9w\x8b\x15P\xe9\xa7\xd8\x1c\x17\"\xf5=\xbfL\x15\x0b,\x19S\xcb\x0dUeB\xd8 -\x16m\x96\x88:{i\xdd\xf70\xb04F\x83\x15\x10\xf1\xcaH\xb2\x96{\x8e\xe2\x81C\xad\xa5\x96]=\xaaL\xe2\xca{(I{\xe1\xd2\xd6#\xb2\xef\xde\xe0^\x98\xf0\xd5\xcc4\xa5\x9b\x13\xe3\x14\xc0\x0b\x1dV\xa4\xdbz<\xbb1\xe0\xad\x00\xb7\x02\xf5\x9a]]\xb6\x1e\x1524\x9e\xa3\x94\xc4\n\xec\xb5/\xd5[1C\xd1\xa9\x87P\x13\xb4\x82\x86)\x83\xd6\xe3\xe3 \x85J`\xe3\xb7\xb1E\x96&H\xaa\x89\xb4\x97\xed\x1d\xac\x88\xea\xaf\xddG\xda\xde\xa5S\x1fO\xac}\x94\xfe\xc1\xa5\x02\xa9\xb3p\x0b\xfa\x87\xf2\xf8d\xc0\xa3\x9f\xe5<\xe7o\xb4\xa6$\x86\xad}z-\x06\xdc\x11N\xca\x16g\xa3\x0e\xb0\xeb\xc3\xea\xd8\x1e\xd6\x97iF\xa2\xce\xb1\xaeT\xd7y{vB\x90\xb6\x12\xb2M\xe42\xab\xa9T\x93\x06sPV\xa2\x89yXP\x91\xd7\xee\xdc\xe9\xf0e\xf5T.\x11r\xb2]\xcf\"\xeag\xfd}\xb6\xdd\xd6>\xab\xc9,\xdb\x8f\x05L\x9e\x88\xb2q\xc4\xfal\xd8\x81O\x85\xe0\x0b\xfbH\x99\xe2\xeb\xfaA\xf8\x00\xe8\xab\"\xda\xad\xa4t\x9b[C\xe7&|\x0e\x0e\xc4\xbc\xca\xbaP6\xeaQi1\x9fq\x19\xcb\xc7>\x90\xc2\xcaWT\xa9\xb1\n\xec\x80Lv\xdcV\x81^\xe0\x10\xacY\x0evuUs2`\xa6\x7f\x85\xf8\xc4\x88-\xc5\xc9W\xa2\x7fq]]\xf0.\xe2\xd3=\xb1\xb9\xe8\xea)q\n@~_P\xc14\xd0\x14w=\xb7\x06\x91\x9c^\xad-'\xde\x04\x84\xe5\x15c\x97\x88\x9f\xb3cOO\xac\xf8\x10\xc1h\xc8Z&\x85\xe22\xa8_>\x90!O\x9d\x95n\x00\x9e\xb9\xae\xc7VN\xe6\xb1S\xf5\xc2\xd5\xcb%\xec\xb0u\xb5\x08\\EP\xc1\xe6\x0bMI\xbd\x98\xe3\x82\xacB\xef\x1c*\xda=\xd6\xc3\xc0\x07pnr\x06\x83\x81`\x98M\xd1\x16NO\xb0\\\xa15\n\xf3\xd9\xd7\xd8\xc0\xd7\x92\x93\x04f:u\xf5\xf1\xcb@%N-I\x86\x9bj\xe4w\x9a,\x93n`\xd0s\xd6\x12\xd3\x0c\x0co\xca\xe2\x91cs\xe6g\xa7zr\x00F\x0cg\xee\xca\xe0\x96\xc3\xfb;\x10\xdd\xf2v\xc7\xb3\xbdG\xdb\xe2)\x1b\x00\xb1\xd5\xc5.Ek\xfd\x12*5Z\x0b\xc1X\x1f\xeby\x96#$\x8f\xf2%O\xd0\x01\xfe\x86%\xd0\xe8)\xef*]Q[\xf3\x80\x96\xb5\x13b\x82\xc6\xbe\x07\xdf{\xbf\x83[\xe9\xb7D\x93\x8e\x9d'\x1b\xcf\xea\x08\xc4\xf6\xd9\xd0Bv\x18uz\xb8\xc1\xfao\xa3E\x80\xb7\x9e\x14A\xe3M\xa3*\xca\x927\x95\xe0&\xf5 >Iyr&\x86.\xce\xdcp\x0bXK\x1a\xc9\xa0\xbc\xe2P\xad\x12{\x10\xd1]+\xb4\x8fvr\x19:\xc7\xd6\n\x92;\xf0\xf7\x02\x91\x8a\x80\xc7\xf0\xcf\x00Bn\xa4\x98[\x8fYP\x11\xf0\x04\xb4\xcb\xa2\xb3\xc2)N@\xc8f\xb6<\x1a\xc4|\xecO\xf0\xe2\xa7xA\x07G\xb6\xbd\x8ai\"\x11\xbd\xc7u\xeb\xab-\x93\xd8\xa6\x16F\x8a\xe6\xbc6:\x08\xca\xaa +\x04\x04E\xc5F\x91\xe9\x99\xe6a\xabY\xf2\x85\x07C\xec\xbamm\xeaO\x06\x1e\xc7\x04;\xfb\xe2\xe5\x8bw\x8d\xc5?\xb4\\Q\xd5No\xb1\xcb\xb2E\x12\x9f\x83P\x05n\x119w\xdf\xf0Y>\xe5 \xeb\xdde}\x96\x81\x1b\x90\x9e\xc4`>c\xc5V\xc9fy\x82*[\x90 \x05\xdfH\xe3\x9b\x17sT\xaf\x81\xd8g\xe5\xa7)j\xe2DZ\"[\x0e\xd2\xb2\x19\x8f]\xc69\xca5\xf8\xc5*\x0c\xa6A\x16^\x16\x0bf\xc1U\xfb\xd8\xe0\x80\xbd\xab'\x81\xfe-\x8a\xc1B\xb0h\x15\xba!\x1a\x9e\xc5\xd1\xdd\x8c\x9d\xfbQ&:\x91\xf2\x8c\xf9\xd2\x01\x81X'\xa0\xbf\x93\xbd\xc2\x8eL\xfd\x08\x0c?\x80\xb9\x91\x86\x83,\x9ek-7\xb9\x96\x11\xd3\x1f -\x10\xad^\xdc{\xfd\xe6\xd5\xa7\x87\xc7_\xbd\xfc\xcd\x97\xaf~\xfc\xf2\xf8\xd9\xf3w/^\xbd<\xee\xb1>\xfb\xd2\xcf\x16\x83\xc4\x8ff\xf1\xd2q+\xa1\xcd\xb5\xe0\x9e{\xee ]\x85A\xe6\xf4z*\x80o\xe3\xe7k\x93\xdb\x15\xbd\x10\xb5\xe8\xed\x86\x01>\xdd\x00K@\xbb\xbfJ\xe2\x13\xf1\x1ed\x0b\xe63\x1c6|v\xc0>\x83 \x12\xcb5\x8b\xd9\xc2\x8ff!z\x99P\x98\xce\xfa\xec.\x8b\x13\x16g\x0b\x9e0\x1f\xd6 \x88\x18z\x08\xe1Ozh\xd6\xb5\xf2\xd1<\x8a_\x82\x8d\xd54\x06/\xa3 X\x96\x06g\x80:\x85yO\x81q\x1a\x9aM\xf3$\x01\xa3\x03\xc0)\x81\x1c~t\xc9\xf2\xe8}\x14\x9fG\xea\xbb\x1e\xcb\xa3\x90\xa7)\x0b\xb2\x1a\x12\x07\x11;_\x04\xd3\x05\xde \xa4>PAZ\x8f%\xfc\xd4Of\xd0X\x8c+\x06\xbf!\xc1\xd2\x0d\xcd\xd1\xa9\x86\xc0\xd9\x13D\xd9\xc1]\x8b&\x86\xd0\xfe95\xd3\xa0\xca\x01\xd3(\x0e\xc2\xf1\x06\xfa\xddEo)\x96\x87\xd83\x0b\x9d\xa4\xd2`\xc6\xb2\x12\x14\xc9\x80\x8f\xb2\xf8*/\xbd\xbc\x88\xceb4\xdcz\xed'>\x84u\xff\xb2\xf0\xb1\x9b\x15\xac\x84\xf4\xf4@\x124\xf0\x16$\xb6\xae]\x97\xd8\xbbD\xd6\x83]#+(\xb2\xf6\\\xf2X\xeb[\x95\xba\xd2v\xa4\xb2\xfey\xf3\xfa\xb7\x1e\xc0\xb5\x05_\x1bj\xa2\xe6\xd8[\x0bd\xb1^\x8d\x82\xff/1\xe9\x15\xbds\x04\xe5%\xa61P3L\xcdU\xf0}\xcf\x15E\x9c\xed\x8e\x9f\x82\x1a\x89\xa6\x0e\xb5\x1b\x81\xa4\xb9\xa5'\xbb\xb7Y\x9cp6\x8b9zc^\xf8g\x1c%\xf3\xc1L\xc9\x1c\x06\xecK\xff=g\xf2*//#\x8c\x94J\x85\xfa\xe6\x1b\xa4\xday\xf7|\x11\xa7\x1c\xa7&\x05\x99\xb0l7\x1d\x10\xc1k}I'\x0b\x14s\x0d\xed\x13\xba\x0d-\xb6\x84\x17\x19\xaaM\x07A\xaa^\xf5\xb8.\x85\xbbd\x1f$\xd8A\x8aB\x91\xe2\\\x9e\xd5\xa2\xa2\xa8\xc1e18&\x88*\x81\xdf^,\x979\xc4\x83/\xbeZ\xdec\x9a\xc7a\x18\x9f\x07\xd1\xa9rx\x10\x80S\xaa\xbb\xac\xcf\x02T\x1a\xdc\xedy\xacw\x17eL\x83\xbb\xe6\xd8\xe1\xc0%f\xef-\xff\x19(#\xf0\\\xe8\x0e\xe6A\x98\xf1\xa4\xe5\xa8 \xc7\xbba\xdc\xdf\xaa\x1da\xeaZ)Y/\xd7e\xc0\x07\xac\xa7]\x19\x04\x81\x04^\x94,J\x1d\xb0\x9e\xf2\xeb\xd0c\xa3\xe2G\xc0S\x14\x97\xe1\xc0ss\xe0l\x1e\xe7\x118\xa5\xbe\xab&E\x03\x7f\x16\xb3y\x10\x15a\x83\x04\\Q\xf0\xaf\xe4_\x853 \xbcC.\xc5\x1a\x0dp\xd6\xef>\x96\x9dD\xff\x13'\\J\xeaf\x83\xbbuw\xca\xb7\xbf\x1b\xde\x1aE\xf3\xd6\"\x0euo\x9c]tH\xa4d\x13UH\xa0\x1a\x12X\xaed\xa7\x97+)\x0bEQ\xe7\xad\xc8?\xeb\x02(M\xb6y+\x13\xa4W\xacB\xab\xa0\xd0b\xd7\xae\x07\x00/\xe7\xa9:#]>\x199\x8fP\xc4\xfd\xe8\xa1[\xedy\xe4<\xd8\xdb\xead\xe0Y\x1e\xa1\x87\x86\xafC\xe9l\xf0\x91\xeb\xf4\x8a\xd8\xe0\xa4\xad\xf3\xde\x96\xc5\x8a;r\x86\x0f\\\x8d\x8a\xaeq*\xb0\x1d\x084ER6\x8e\xd1c\xad\x16\xbb\x1c\xee\x14@4\x81:\xcdJ\x1c]~\xd7 \xc0\xcdV\x86\xf7~\xe2\xfc\xca\xf6\xd6\xd5Q\xea~\xe2\xfc\xd4?\xf3\xd3i\x12\xac\xb2\xab\x99\x9f\xf9\xee\xbd`i\xc2\xf2\xde\xf8'G\x17\xdb[\x9bG\x17{\x87\x93{\xa7\xf5\"\x01\xb69\xfe\xc9h\xd2wG\xf7N\x97\xe6qk\xdc\x1b\x08Bt\xaf7\xa1\xe1]\x05h\xeaGA\x16|\xc3\xbfJ\xc26a\xd5\x99\xb4\xb5\xf1\xe4\x8e!\xaf\x95\x89cA\x8fRKw\x12\x10j\x05\xfd\x010\xec\xaf\xe6\x0e\x1foM\\\xf6\x94m\x12\xee\x97\x9d\xdc\x95&\xe7N\x04\x12\xc0\xa5\x9fM\x17N\xe0\x8ad4\xd9\x11\x873\x96\x0c2\x9ef\xe8\xb6\xa4\xe7\x9f\xc4y6: \xfd\xe8\xbd\xd86r\xb8\x1d\xae'V\xbe\xb3\xa6\x15e\xb9<\x1e\xd8\xec\xff\x1f\x0e]#\xdci\xc3f\n.\xa2\x07Y\xfcE|\xce\x93\xe7~\xca\x1dpG\x02\xfa\xa3\x03&\x90\x94\x8d\x0c\x1f\x1f\x96\xe5\x15\xaf7\x84]\xca\x9e>r\xb6\x1f\xda\x96\xaf}z\x95\xb0\xdbI\x1c\xeeVG\xb3\xe6\x1a+\xbb\xb7W\x17]|/\xa6\xe4`H\xdelF\xde\x0d$g\xff\xbf1y1\xc7\xf5 \x8e\xba\xd9\x8cw\x03t!d\xb9\x96\xe5\xb8\xbe\xa2)\x84\x13\xeb\xc1r\xa3g\x8f\xf2\xaf\x0b\xcb\xea\x9aCh\x96\xf5\x80\xc5\x03\x19\x94@\x814F\x12\x18 \xd1\x90\xe2y\xa34\x93\xa8\x0e\x96\x91hd\x91\x0d\xa6\x0b?y\x969[\x16%L*\xcb'N\xe4\xb1\xa1\xb2P\x82\x08!\xd9 \x0d\x83)w\x1a\"\xb0\xe4c>\x01\xc5wU\xd8\x7fm\xda\xbb\xfd\xb0\x1d\xc4\xf6cl\x0c;\x9a\x14\xdf\x93\x98T,2\xe9\x02\xea\x80\xc5\x82w\xf7\xd8\x06\x98\x01D\xec\xe9>\x8b\x95Ux\xf1\xa9\xeb\x8e\xe6\xc1^\x9d l\xc1\xbb\x9b\xd0g\x8e\x08\x02\x97\xb4\x92\xf6\xc5b\xe3h[\xbf\xc4Ks\xb65>\xa1\x10\xb97>:\xcag\x0f\xb7\xb66\xc5\xff\xf9|^\xbf\xf4\x96\xa8B[;Xhkgw~t\x94\xcf\xf96\xfc\x9c\xf3m\xf1s{k\x06?\xb7\xb7\xcc&\xe0\xc6\x00|fg:\xc6\xcf\x9c\xd8>\x07\x86~\xe3\x9f\xb4t\n.\xf49\x07#\xbd\xd1\x19\xdf\x85\xe2\xb3\xf9|\xe2\xfe|\xfb\x03y\xc5Oo\xf7d>\x9f@\xc2\xd4\xfe\xa1T~\xa8\x08\xe1sU\x84\x01r\xc5[\xef\xa0V!T\x9f\x99\xf3-\x8e\xff\xe6\x93\x03\x15\xe1\xc9\x91\x9d\xde\xde\xda\x9a\xc9V\xc7\x18\x93)\x9f\xc8\x95~\x85A\xe2\\k\x1b=\xf7\x93\xfaY`\xaa\xf5r\x1c\xa8\xae\x1e\xf4\xf0\x1a<(\x08\xa3z\xfb\xb5~\xcf\xd9\xbe\x0c\x8c\xe0\xc0\xe8\x9c\x83\xfdr\xa40\xe8)F\x8a\xec\x9d\xf6\xae\xbb&\xb8\xe4*\xe7p_t<\xb9\xee2\xde~hc\x08m\xcb\x98\xf2%/G\xdb\x1b\xdf\xfdo\xbf\xf3\xbb\x93\xde\x8dF\xd6\xbc\x9d\xa8\xdd\xdd \x1c\xb1o\x14,\xbe\x0f,\xbe\x0b\xce\x1ez\xbd\x1b\xdd9\xd2h\x9c\x058\x06\x0b\n\x87\x9e\xf1\xd1\xc5T\x1c\x8bf\xbbG\x17\xb3\x87\x9bG\x17\xf3\xdd\xa3\x8b9\xbc\xcc\x8f\xf2\xad\xa1X\x19\xf9\xd6po>\xb9w\xda\x00\xc2u\xc9\xc3M`\xed\x80\xd0\x1a\xa4\x82 \xa9U\xd0\x0c<\x96\xd4a{} \xdew\x9d\xea\xd7{\x7f\xf8;\xbd\x11\xeb=\xab\xad\x9b\xde\x1f\xfe1:\xf9\x8f\xd3\xc9\x7f\x82N\xfe\x1f\xe8\xe4?I'\xffC\x91\xec\x1b\xc9\xff\x88N\xfe\xc7t\xf2?\xa1\x93\xff)\x9d\xfc\xcf\xe8\xe4?-\x92\x9f\x1b\xc9\xff\\$O\x8d\xe4\xbf\"\x92\xeb\xde\xf1{\x7f\xf8\xefD\xf2\xccH\xfe3\"\xb9\xee;\xbe\xf7\x87\x7f\x96N\xfest\xf2\x9f\xa7\x93\xffg\x91\xcc\x8d\xe4\xff\x85N\xfe\x17t\xf2\xbf\xa4\x93\xff\x82H~a$\xffE:\xf9/\xd1\xc9\x7f\x99N\xfeW\"90\x92\xff5\x9d\xfco\xe8\xe4\x7fK'\xffU\x91\xfc\xd2H\xfe\xf7\"92\x92\xffG\x91\xfc\xcaH\xfe\x9f\xe8\xe4\xbfF'\xffu:\xf9o\xd0\xc9\x7f\x8bN\xfe\x0f\"96\x92\xff#\x9d\xfc\xbf\xd2\xc9\xff\x1b\x9d\xfc\xbf\xd3\xc9\xff\x89N\xfe]\x91\xfc\x95\x91\xfc\xb7\xe9\xe4\xbfC'\xff]:\xf9\xff\x14\xc9\xb9\x91\xfc\x7f\xd1\xc9\xff\x99N\xfe/t\xf2\xdf\x13\xc9\xf5\xd8\x01\xbd?\xfc}\x91|i$\xff\x01\x9d\xfc\xa7D\xf23s9\xfc\x9eH\xf7\xcd\xf4\xbf/\xd2\xdf-\x8c\xf4\xff*\xd233\xfd\x1f\x88\xf44\xad\xa7\x7fK\x93\xe5oi\xfa\xfb-Mh\xbf\x05\"n\x90\xb7o\xff\x04\x9d\xfc'\xe9d\x80\x80A\x0c\xbf\xfd3t\xf2\x9f\xa3\x93\xff\x02\x9d\x0c\x84\xd6\xa0\xa8\xdf\xfeY:\xf9\xcf\xd3\xc9\x7f\x91N\x06\x12d\x90\xe5oij\xfd-P&\x83Z\x7f\xfbW\xe9d \x13\x06\xfd\xfd\xf6\xaf\xd1\xc9\x7f\x83N\xfe[t\xf2\xdf\xa6\x93\x81\x04\x19\xf8\xf6\xed_\xa7\x93\xff&\x9d\xfc\xbbt\xf2\xdf\xa1\x93a\xcd\xfe\x9a\x91\xfc\xf7\xe9\xe4\x7fH'\xffc:\x19\x16\xe7\xa9\x91\xfc\x0f\xe8\xe4\x7fD'\xff\x13:\x196\xfb_7\x92\x7f\x8fN\x06\x1e\xc0X\x98\xdf\xfes:\x19\xb6Xc\x07\xfb\xf6_\xd0\xc9\xff\x8aN\xfe7t\xf2\xbf\xa3\x93a\xfb66\xb6o\xff%\x9dLo\x9a\xdf\xd2\xbb\xe3\xb7\xff\x9eN\x86\xed\xe47\x8cd\xd8N~j$\xc3v\xf2\x9bF\xf2\xff!\x92\xdf\x1b\xc9\xff\x89N\x86\x9d\xe0\x0b#\xf9?\xd3\xc9\xbfO'\xff\x01\x99\xfc\xdd\x1f\xa3K\xc3.\x13\x1a\xc9\xff\x85N\xfe\xafd\xf2w\xbfC'\xffq:\x19H\xaf\xc1\x8d|\xf7'\xe9\xe4?M'\xff9:\x196\x01\x83\xa5\xf9\xeeO\xd1\xc9\x7f\x86N\xfe\xf3t2\xd0o\x83I\xf9\xee/\xd1\xc9\x7f\x85N\x06Bm\xf0\x17\xdf\xfde:\xf9\xaf\xd2\xc9@c\xdf\x18\xc9\x7f\x83N\xfe[t2P\xcd\xc4H\xfe\x9bt\xf2\xef\xd2\xc9@\xa8\xdf\x1a\xc9\x7f\x97N\xfe\xfbt\xf2?\xa4\x93\x81\"\x1b\\\xc1w\x7f\x8fN\xfe\x07t\xf2?\xa2\x93\x81\"\xbf3\x92\xff)\x9d\xfc{t2\x90\xde\xccH\xfegt\xf2?\xa7\x93\x81\x98\x1aL\xe1w\xff\x82N\xfeWt\xf2\xbf\xa1\x93\xff\x1d\x9d\xfc\x1f\xe8d\xa0\xb1\x06\x0b\xf9\xdd\xbf\xa4\x93\xff5\x9d\xfco\xe9\xe4\x7fO'\xffG:\x19H\xef\x8f\x8dd \xbd\xe7F2\x90^\x83\xc7\xfd\x0eH\xaf\xc1\xcc~\xf7\x9f\xe8\xd2@z\x7f\xdbH\xfe\xcft\xf2\xef\xd3\xc9@L\xbf1\x92\xff\x0b\x9d\xfc_\xc9\xe4oav^\x98\x1b\x0f\xc0*0v\x9e\xef\xf0\xb8fp.\xdf\x01\xb3\x14\x9b\xe9\xc0X\xde5\xc9\x1b\xec\x1bi\xa9\xd9\xb5)Hi\x8f>\xd7\x16rw\x12\xb0\x11\xce\xd4F`\xa3[\xa9p\x03\xc9Z=\xf6\xa3\x12;R\x96\xdf\x84\xc4M\x9am?l\xf7\xbcG\xabT\n\x0b\xc5}\xd0+x\xba\xea\x04u\xf4\xfa\xc0AA%\xd5\x10~\xa9\x86\x80\x00T(\x87\xcd\xba\xc9a)\xb5\x01\x18Tlmm\x1e]l\xcf\x8f.v\xfc\xcd\xa3\x8b\xfb[G\x17\x0fN6\x8f.v\xb7\x8e.\xf6\xc4\xcb\xde|\xd2\xbfw]%\xa3\xeadt\x93N\xfa\x9b\xdfL\xc6\xcf6\x7f{r\x05\x7f\x7f\xbe\xed}\x80\xb4\xab\xf1\xd6\xe6\xa3\x89x\xc5L\xf9\x02\xa9W\xe3\x9f\xe0\xcf\xad\xcdGlr\xef\x9a\xdd\x8f\xd0Pb-\xb5O\xa1\x939:\xba\xf0\xa7GG\x17'\xc3\xa3\xa3\x8b\xd9\xde\xd1\xd1\xc5\\\xfc\x01\x01\xab\x008B\x1c@\x8e0\x07\xa0#\xd4\x8f.NP\xe0\xba%\x05\xae\xbbsvt\x94\x89\xea'GG\xa2\xae\xbf\x05r\xd9\xf9\xfc\xe8(::J\xa0\xd0\xf6C\xfc\xf7\xe8\xe8(\x1f\xee>\x14%\x86\x0fA\xf9 \x1a\xc2\x7fC\xfc\xb7\x8d\xffv\xf0\xdf}\xfc\xf7\x00\xff\xed\xe2\xbf=\xfc\x87mn=\xc2\x7f>~\x01;\xf7@\xfc\xdb\xd9\xda\xda\xaa\x11\x18\xd46\xf5X\x9fE\xac\xcfz\x16M\xd2\xac\xdf3\x17\x1cH\xa1\xb7\xf7\xe4\xb0\xf7Nh\xa5\x91\x98j\x01\xd4\xb9\x80\xd4|\xf7\x08\xa5\xddG\x17\xa6\xea''5Q\xaak\xa0\x18\xa9}\xd0\xda\xf4\xb3\xcd\xdf>BA;H\xdaQ\xd4~t1\xe36u\xd3\x1az\xad\xf0Zz-\xd0\x18\x8d;\xf7k\xae)\x98\xfcB\x0d\x96S\x8a\xa4\x95Vt\xda\\t&\x8b\xae\xa9>\xb8\xb2\xa9\x12\xdd\xba2naU\xc6\xcd,\xca8R\xf5\xc8R\x8f\x85\x9d\xf4s3Z?wV\xd1\xcf\xd1\xed\x89\xbc\xda}\xcbe\xa9b\x19OQ\xa3\xa7\xe0\xdf\x17`\x03\xc5\x95s0\x9a]\x85\xe1\xd5\xf2*\xe1W\xe9Uvu\xc6]\xf7@\xaa\xef\xc6\x89\xc7\xa6\x1e\xeb\xfd\xb0g\xaa\xff\xd8\xcah\xe8\xb3\xab/\xbe\xb8\xfa\xf2\xea\xcd\xe1\xd5\xdb\xabwW?:\xac5\xc4\xfalnk\xac\xec\xdf\xbcK\xffT\x8d\xb6\xcf\xf79\xc0\x1d\xeb\x87\xd7\xa6\xec\x1b\xce\x06\xd8t \xea\xa6l\x10\xc0\x14\x97\x1d\xb0\x15\x18A#\xe3\xef\x17\x0eG\xd9Z\xa8S\xdc\xb5~d\xbdk}o\xfc\x93\xc1\xa4\xff\xc3{\x03~\xc1\xa7N,z\x10\xc35\xb1\xf2m\xf0\xe2\xf0\xf8\xf5\x9bW\xef^\x81\x91~\x0f\xac\xb8{\xe8\xc8\xd1I\x93\xa9{<\x1c\xa0E\xd3\x88\xf5z\xd7\x85\xc4F >\x18@`\xd6k\x8c\x14\x91~\xcf\x1d\xf7\x8e\x8f\xa7q\xc27\x7f\x9a\x1e\xa7\x0b?\xe1\xb3\xe3c\x9b\x95\xfdu\xa5\nv\xdf6\xed2\x83\xf6s[7\xb0\xa9\xad\x01\x88\xcb\xc2\x87\xcd\xe3\xce\x1de\xde[!JcN{\x05)\xe9\xd2\xe6>\xcb\xd8\x01\x1b\xb2\x11l\xda\xd7\x05\xbf\xa0\x9e\xc4 \xeb\xf88\x8cg~\xba8\x16{\xfdqqg\xe8\xf8\x988v\xb5\xb8OX\x17\xb9*PR\xf0\xa8\x02#\x983\xc7pZ\xcc\xb4\xf3sf\xc0\x8fULN\xf7\xd1\xa6\xb4\x98\xee\xa6@J\xb2VPx\x15\x86\x95.\xbeP\xd8\xfd\xde.\xf0\xbf\x7fx\x16\xc6\xe7\x07\xd5+>0\xc4X\x1b\xf8\xed\x0e\xb4\x01\xcb\xda\x06\xd9\xe4=\xacu\x9c\xe5\"\xeaW\x17#rdC\x8fEb\xe8\xfbh\x8d\xaf\x89\xd82i\x9d\x9c!\x83pS\x02\xd1\xc6\x96\x8c'\xb7\xc4\x88\x0cw(\xf6\x18\x83\xd7h\xcc\xd8*\x0c\xa6\xbc\x0d\xf2\x9d\xd0\x8bf}\x13D\"rN6\x9c\x88=A\xc7\x11N\x04\x9e\xa0\xd4\xd5\xd4M6\x14\xebm\xb0\x8a\xd1WD\x89\x8f`\x1e\xef\xb1\xcd\xcd\x02H\x1e\xdb\xba\xd6\x9e[@\xe9\x174z\x1c\xbb.\xba\x1dG\x93\xf1\xb0m\x0b\xba\xd5\xa1\x146\xaa\xd5\xb1\x08rW\xb91\xf6\x11\xba\xd2u5\x9b\x80\x8d\x01\xb0\x91\x15\xb0\xb1\x04\xac\xd3\xefkH\x12a\xec\xd0\xb1\xf8\xf0\xc4\x85\x08P\xe3X\xc0[F9j_\xdb\x0d\xc3\xddn\x1d\xae\x0d\x89\x12\x15\xf9\xcd\x95G+\xdb-\xa1\xebr\x01\xad\x14\xc9\x8e\xdf\xd2S\x1d\xd9\x9d\x1e\x9e\xe8\xd1\x81\x1b\xf0\x9bQ\xbe<\xe1\x89\x96\x90\x02\xe7\xa9%\x9c\xc4q\xc8}\xe9\xf4M\xf0\xa6\xc7\xc7@\x89\x8e\x8f{2\x10\xc0Hs\xce\xf7}\xceFe\x1d\xc0d\x9c\xf2\x0eb\xfc\x8f\xdc\x07\xdc\xa1>f\x1f\x1a\x16a\xd9\x0fz\x05F\x80\x8c4e\x03\xc1\x034\xeeU7\xdeHnk\xc8\x8a\xc9\x8d\xf7fK\x8f\xb6{7\xae\x8eI\xe5\xdc\xfdV\x90X\xa6\xa5(\x80{\x10\xe9u\xef\xac\xe2w\x9d\xbcI\x06\x8e/b's\xa9\xfa\xaa\x8dT\x11\xb8\x1d\xa2\x05&o\xaa\x05\xe0{(j\xec\xbb\xfe\xc8q\xa4N>\xe6\x13\xb8|\x90wu3k\xa6\x9cI\x8f\xbc\xbc\x00\x87\x95\xf3\x0ea'a\x07,\x1f\xa7\xc0C\x87\x82\xc1\x0c F\x9a\xb1\x1bH\x03w\x87\xf5[ \xf2\x02\x84!`AL\xd8~\xd4*A\xb2\x12\xc6\xd8F\xa3\x87\x15&\xe6\xce\x1d\x96\x8d\xb7&\xe3\xed \xde\x19\x14\xef[\x82\xbd\x13/\xc3\x89\xd8\x82\x8ao5\xdd`\x8e\xa4\x13Q\x88\xb6\x16QAB\xaf\x0d\xb5\xa1qwF]\x8d\xa3\xa064%U\xdbm0\xc4\xaf\x0bd#\x80\x99\x02\x1d\x91n4\x8d\xe1\x0b\x04K\xcd\xe4)\xdbg\x1b\xb9y8,\xce\xf4\x85\xdf\x98\x8dZ\xfc\n\x10\xb0\xf2\x8a\xc7\x03\x96nnZ\xa5\xabs\xd1\xbdqjq}=\x85`\xa18\xbbs\xc1G\xc0\x166\x9e\x8f\xb7&\x02\xb97\x1c\xf1\x06b\x92\xd2\x93\xcdFS\xac\x0f\xe8\xdec\xd6\xef\xa7\xec \x0b\xad\xbdZ\xb1}\xe6\xa8\xae\xb9V\xe7i3\x10\x0d\xaf,\xb9\x0b1IV\xaf\xde\xc5\xd0l\x04\xa5\xe6\x90\x04B\xdco8\xab\xe6\xd1\x8aG\xc6}\xb7\xd3\xbe3\x86Q)\x1bBQ\xe7.\x94\\\xb2}\x96;3\x8f-<\xb6\xc2U\xe1\xb13\x0b\xc5\x04\xba\xabwy f\x12\x0b\x8f\xcd<\x16\xb0+y_\xeeL,\xcae\xf3\x08\x1afP\xd5\xba\xc1\xa1\xad\xf5\xeai}J\xea\x07HT\xd1\xacu\x86\xbc\x01\x8b\xd8~\x04\xca:\xf3\xb5\xa2\xac\xe4\xd5o\xbd\xc3\xfa\xc7T\x7f\xbb\xf1x\xb7\xf4\xad\x9b\xf2r\x16\x8d\xe0C\xea~\x9fH\xaf\x97\x07b\xbd\xd5\xead\xa1\xeb\xa9\x8c \xbfLy\xd9\x8a\xe7ft1\xa6\xb1G\x91\xa5\x15V\xf0Gb\xab+\xdcT=a>\xdbd\xc3bM\xe6\x95\x83\\\x15\xd3\xfb\xfdH\xa2\x90H5\x9b7\xc6!\x17L\xe0\xe4\x1d\\M[\xf8Z\xc5\xd6\xde\x90\x93\xb5n\xc5u1\x9ade\xb7\xa9x\xa7\"\x9d\xd2\x1c \x14\xaa\xab?Sl\xbf\xaeq\x08ew\xea\xcdL%\xdfTO\x9f\x9b\x9c\xc1J\x0f\xac\xfaLy\xf0\xac\x9b\x97\xcc\xaa\xa5\x12\xff\xb2^b\xa1\x97\xc0M\xbb^\xe4\xec\xe6\xc2S\xc5\xa2,=v\xea\xb1K\n\xffO\x04+\xe2PG\xa1c\xc8\xc9\x88\x9cs\xb6\xcfN\xd8\x01\x9b\xb1\x11\xcb\xc9\xba\x87l\x9f\x1d\x17%\xa86.\xc4^/\x1a:\x17\x9c\xcd\x8a\x1d\xb0\x05\x1b\xb1sW\xfc\"8\xa6\xb7\xa2\xb8h\xf5P/~h+\xfe\\5|h.\xe7\xe7bK\x0fA\xd7e\xaedX\xa5!\x9cb\x8a\x8d\xd2\\l'\xe0+\xc5\x83A42>\xc5\xf76.\x8a\x06/A*x\xa964\xd7c'\"e\x8a\"\xdb\x98\x98\xb5\x11\x0bd\xeay%\xc3\x1c\xdb\x86\x13\xb1;lN\x0eM\xcc\xf6{\xb6\xcf.@\x0c\\\xb8\x96\xe9\x1d\x1f\x9f'\xfej\x05\x82jb\xa2\xc4\xf3\x8c\xed\xb3\xb7Z\xb5\xac^\x8d&w\xef\xc5\xb8\x9e5\x9d\x07_\xb1}\xf6\x9e\x1d0>\x00Wr \x11mp\x9a\xfe\x9a\xed\xb3g >-\x8bg4[d\x05\xf6\xa9\xf3\xcac\xaf\x15\x1c/\xdb|^\xd3l\xd0\x06L\xaac\xb6\xee\x9b\xd3w\xfd\xad\xd1\xd8\xea\xe4\xc1o\x9b6\x96\xd9\xdd\x1ev\xf5\xe3zv\xcbf\x1du.M\xb7\xef\x80\x02\xfel\xe6\x80w\xe1\x1a0\xc4\xe3k\xf4\xcd\x9f\xcd\xc0\xabP\x99\"\xb6D4\xca\xf0\x0d\xfb\x8b\xa0jj\xe1\x93\xf0\xad\x037\xba\x99\xae\xa6\x13O$w\xd3\xc8\xed\xb4s~\x9f\x8cX\xfb\xb7\xec\xbae\x00\xbb\x93\xb5}\xc2\x8a\xd06/I\x86\xb9\x93d\xf5\xb6(7\x17\x14\xdf\x90K\xfc\xafo\xf8\xa9L\xaf\xb7\x13\x9a\x1b\xbb\xe0\x01\xb6\xcd\xed\xbf\xd8\xa3?E o}\x93\xae\xf0\x03\x9f\xf9\x99aiZa\x05\xc0\xa3e#+\xf0\xa5\xbf\xa2\xf8\x00-\xd8\xfb\xf2\x84\x1bM,\xf5\"h\x97R/r\xaa\x17y\xcb\x0dn\xe3\xb2\x92\x0f\x12\xf0z\x91\x93J\x11\x10\x81\xd7\x8b\x1c\x1b\x8c\xcf\xa7\xf9|nv\xf8\xbc\x066\xffG\x01?\xaf\x17:,\x9c\xaa\x15\xeb\xde\xe2\x9b\xea\x02\x18\x83\x03v\x88\xfb\xc2\xabyg\xd7k\x8aX'\x1e;\xf4\xd8[\x8f=\xaf\xe3~z\x1e\x80\x0f4R\x8e\x05q\xdc\xceGF:\x93; \x1f\x9c\\f\xfc\x0bd\xf77\xc41P\xfb}u\xc50\xff\xd5|\x9e\xf2\xac\xcc\xc7\xdf\x8d\x1c\x88x8x\xa3:\x01\x00{\xd2\x1b \xfe2\xcbCG\x8f\xe9\x8e\x16:\xcb\xb6\xden\xbcu\x04u\x8f1\x18\x0c\xbce\xaeKl\xfe\xf0\xb5\xb9\xf95H_Y\xd2\xcf\x1a{\x178}\xee\xb1>%y\x86\xda\xb3\xc6\xda|\x10\x81Oq1&x\x03O+K\xe53\x1c\xc2\x9d\xe0\x0fK\xf3KK\xa7/\x9b?\x8b\xfa\xa0~\xc5(\xa9R\x7fA\xd7W\xbcZn\xa9vj\xaf\xf6\x0c5\xfd,\xb4\x8b\x8b\x80/sD\xfb)x{\x85\xb3\xde\x86\x12R\x00\xbb\xfa\xac\x15\xfb\x14\xfb\xf6\\\n\x1b\xec\x9f{U\xb4\xf5\n\xe0aa\xd8\xd8\xd5>\x9bz\xecyy\x14\xb5\x7f\xf858\xb4{\x0f\x88\xf8\x1eC\x15\x94\x0b\xb8\x91!|^\nm<\xf6\xda\x02\xde\x13\xfb\x8a.\xf9\xf8\x0b\xe55P\x0cJ\xfe\xb0J\xaf\x99\xb6\xce\xda\x94\xcf\xed[\xf4\xba\xec\x9c\x0c\xe1\x04\xd3K\xcb\xaa\xb8\x195\x82\n\xa5\x0e\x0d\x8e\xfb\xfdl\xc2\xf6\xc1\x86\x9e\xd7\xee\xa2\xb9\x1fC\xc4\xf5q\x86\xd786\xbe\xf6\xb0\xecv\xb3\x8f(\xf1\xc7\xd0\xe4xn\xe9\xb0\x8f\xf2\xde\x94\x02\"\x08@\xd8\x1d\x16\x9bp\x9c\x82f\x8e:\xcb\x0b6hJ\xf2\xffb=\xcc\x05\xe1H\x9c\xcc\xd5tC\x1b\xa1\x95z\x14\xd1\x8a\x04\xe34\x7f\xccV\x0dJ\n\xc1:M\xc7+\x8b$\x7f\xc3 A\xc0\x00^\x9aG\x9aA\xdb\xcc\xed\xa8\x95\x10\xdfX\x80\x190E\xc1\xc47`4\xa9\x0c\x87R4\xba \xa8\x98\x12\xf0o\xd4\xbc\xab\xa6\xba`-U\xf1P\xea\xdf*\xa0\"\x18\xb9P\x1c\x9eV\xec \x9b[!s\n\x1a\x10\x05\x1f\x8b\"\xe4\x12,\x07g\x16\xf0\xf9n!\xfe \xe1B\xe5%\x1cWg\x80E\x1c\xf0g\xc4|G\x9c`!\x15\xd1+\xb5)~u\x05\xc4 ;\x10=\xdc\xdf\xc7\xd3w.\x1bA\xd4\x84vO\xecJb\x90\xa8\xd0\x14\xfc$\xe1\xfe{#\xc7T\xe1.a{\x03\x9exZ\x1a\x92\x83m\xc6\xac\x89>\x83\xea\x07\xf0wi\x03\xfc1\xb0\\Z\xab4\xe8\xcf\x81\x17\xd3\x8a\x99\x03:\x16\xeb\xe6\\|\xad\xda\xc9@F\xec0R3\xd4D\x91\x01\x06\x8fE\xde\xb1.\xa6\x86\x14\xb2,|\xf3\\/{\x8eF\xdf\x08\xfa\x0e\x1bX\xaao\xa1\xc5\x0f\x81\xe0g?\xa8V\\\x9f\xf4\x13\x87\xcfJ|\xc7\xcd!F\x83\xb5 (\xd0\xdc|\x0b\x03>\x8e'b)E\xec K\xacK\xc9\x87\xa5T\x8fZ(\x9e\xcc\xf1\x01i\xd1\xac\xd9 \xc6q\xbf\x0f\xb1\x0e;\x80(\xf8\xde\x00\xa1\xa23\xaa\x91\xf2\xc7.K0(cf\x04'\x91\xbdKZzg7E\xa0\x05\xf9\xf7\xa9\xfb\xe2\x94\x94\xbcm\x0b\xb3\xc8\x1dbiZ\x9eHf\xeb\xc6\xd0\xb5|\xa7\x953[\x170C\xcbMz\x03`>\x84)-\xc1\xe3\x8f\x0b\xf0}\x1e\xc6~\xb6\xb3-\xb5\x08\x80\x80\xb5\xcc\xdd\xfbt\xe6\x8b({h\xcd\x19\xeeZ\xb3l\x1f\xfb*\xb06\x08Y\xcfC\x7f\xb9\xe23{ \xdb7E^\xe5\xa3\x1b[\x9e\x9e\xafaP\xad&\xdd^E\xf0P\xcb+\xe48\xb5\xf4R\x08afp#Q\nr\xea\xb3!q\xc5\xc8\x00\xa9N-MIrj\xc9J\x17TKVB\x9dZ2\x08r\xeaiRxSK\xfe1\xf7\xdf\x17\xfd\xd8\x18z\xeb-\xc1@.\xc1\xd8\xe1E\x94&\xb1\x1fm\xf8c\xb1*o`\xdaK\xfb\xa0\xd85\xac\xdfn\x81C\xae\x8f\x0dc5\xe9\xf1\x98L\xfb'u\xf6\x18O,,[$6\xe7\xc2\xec\xc6\xd5\x9c\xf6G\xae\xb9\x91o\x00\x03~\x87e\xa8\xea\xb5\x10\xe86\xcb\xd7\x86\xb3\xc6\x9e\xebh\x81\xb6<\xd93\x8b\xe9\x05}\xfd\xc8N\xe5v\\\x07\xae8y\xac\xa7\xd6\x8b\xed\xe2\xd9\x0d\x9a~\x9d\xc4\xcb \xe5\x1f\xa1\xe5\xb7<\xfb\x08\xad\xca\x95uK-o\x1b\x97v\xe5\x8aX\xdf\xc0\xb3\x12\x856.B8gE\x00\xda\xa8\xe1\xf4\x15\xc0\xf1!\xb2\x1c.\x90m\n(\xb6 \x99\x0f\xe9\x06\x96\x95\xd2E0\xcf\x9c\x06D\xd5.\xfe\x03k\xd1\xb64E\xf9\xc0\x89\x8b\xbd\xcb\xde\xb2x\x00\xf8q\xc3\xa2\xa2)-\x99\x8aS\xe1$\xec\xa9\xf4%\xa6\xf6\xbc\x91\xd8\xc0Y\x9f9\xd2\xc8\xfd\x80\xf5\x9e\xdc\x13TM\xfe\xee\xb3\xde\xd3\x9e^Jn\xa0\x82\xa1\x8aD\xe9\xa3Hf\x83\xa6\x10\xe4\xa0\xd4\xc2\xb3\xcfb`\xdf\xc2\xd4)kC\xc7\x138J\x96\xbf\x07\xfej\xc5#\xf0\xef\xe0\xe9\xf84\xc0\xc4\xb8\x92\xa8\xcc\x18\x9c\x0dq\x06\xdd\xd8\xeaB\"\xe0N\x06br\x01\xb5*\xbc4pi\x80*W\xbf2s=`=\x86e\xb5\x072\x0e\xd6\xabN/\x8a3\xe6\xa7ip\x1a\xf1\x19\xcbb\xe6\xb3\x95\x9f\xf0(\xdb\xa0\xf8\x07\xf5\x9ci\xfe\x91\xe8^\xaa\xa7\xf4H\xa3 f\xec\x0d\xe7\x8e\xd6[IT#\xaf\xd2\x02\x8a\x80\xfa\x82\xc1P\x94\xd6\xf5\x9agE\x7f\x14{\xe9P\xbc\xa2zlT\xca\xc2f\x08\x9a\xd7uJ\xb4\x0d\x17\x0d<\xc4\xd0\xe0\x84\xcb\x95\xd7\x1d\xc1\xe7\xaa\x1c\xd1\xd3\xce$\xd3*\xfa\xac]d+~}pK\xc7\xc3\xce\x83\x07\xf2\x80\xdd$\xe8W\xdbyu\x80\xbd;\xbd\x11\xeb\xdd\xf1\x97\xab\xc75\xa2x\xb7wW\xe4\xfc,\x8f\xb3zV\xef.VZ\xc5\xa9\x91\xf5\x04\xb2B\xb3\xceS\xc88\xcd\x1ek\xc1\xfa\xda\x04\xe3\x16\xa9\xb8$^\x92\xb2\x01\xf1*\xc4=\xce\xf8N\xef\xc9\xd3\xbb\x18c\xa1U\xd8\xa6\x04\xccFP>\xe0\xd9\xca\x8e\x92\xd0\xad\x91G}\x08\xf1\xe3\n\xdc\xa5\x19\xc1\xa3\x1dwpx\xc6\xa3\xecp\x19d\x19O(o\x1f\xe6A:\x913\xbd\x08\x0cu\xb5x\"\xe7\xe1\xd0ub\x0f\xfc\x97\xc4\x837%\xc5\x14_\xbc\x0f\x89?N\x82\xacH\xdc\xdd}\x00\x89\x9f\xe5\xab\x90_\xc8\xa4]Hz\x97\xf8Q:\x8f\x93\xa5L\xdd\x83\xd4\xd7~\x9a\xbe[$q~\xba\x90\xe9\x0f!\x1de\xe2x\xb0\x8bu\x97\x1f\xc1\x8a\xb7\xe97\xce4\xdf]6\xc9yL\x9fF\xf9\xe0\\\x0d\x07U \xb8\xd5\x88D.j\x80\xd5\xd8\xca\xcfS\xae\xbd\x1a\xc7&\xfa\x93\x01I\x85\xa2r\x1f\x82\x16\x13\x9e\xe6\xcb\xca{\xe3\xa9,\x1a\xc4Q\xc1\x92\xc5`,\x08 \x89\x1fD=\x8f\x05\x90r\x1c\xa4o\xb3Y\x00r\xfcL\x1b\x18\x1e\x9e\xc1\x119\xd4\x12l\x9c\xc7r`\x88\xc4od\xdb<\x96\xd6\xa5xg\xd2Ztch\x83oN\x0e\xd6\x87\x8f\xf9r\xc7\xe5H\xc7\xbaA/\xed\xd0 y\xa9\x8d\x0ff<\xcd\x92\xf8\x12\x17\xb6\xfc\xd1\xf5\xb3!M\xb7\xc5\x16:u\\OZ\x02$\x830H3\x1e\xf1\xe4\xb9\xd8\x87\xa4\x13\xe1\x1e\x17\x9bi\xcfU\xfbk\x9d\xde\xd2_\x9cZ\xd1d\x19\x9f\xf1/\xe4wjsndj\xf3oV\xd5\xe7\xb9\x9eW\xce9Y\x13F$\x98%\xea\xabz\xae\xed\xab\xd3\xc6\xafN\xc9v\xcb\xdc\x86\x95\xa0\xc8-br\xa5\x9f\xf5\x14\x1d\xdb\xa7\x06\xb6O\x8b:\xd5\x14<\xca\x08\x02\x04gL\xaf\x95\x86\xbb\x10`\xa9\x89\xac\xf7\x04!I\xb3$\x98f=\x92\xaa\xdf\x1f\xba\x03\xbc\xadDZ\x08\xec\xb6z\x9c\xaf\xe3R\x81f\x9cD\xb3\x8d\xf6m\x8d\x15\xa6\x91\x9ci7E3Wg#\xdf]\xae\xb8d%\x9f\xfb\x91\xe0&\xc5>\xc3|6\x0d\xfd4e~\xca\xfc\xe2K\xc4\xb9\xf0C\xe9\x86\x1b\x19\x9e\x05\xf7g\xd2LK\xa6d~\x10VS\xe4y`\xdf\xea\\\x99i\xbb\xbc\xe9E\xaa\x99QS\xbc\xad\xe5h\xe9g\xbe\xd5;Y\xc4/2\x94G\x99\xe34y3}(O\xc1\x16\xa9\x18.\x88}@Q>\xaa@%\xab\x82$\xf3\x98\x8c\x01\x80\xcdT\xa1\xe1U\xc6\x9eG \xfc\xfe\xf8\xc3/\xfa\xdb\x05\x062\x06\x89\x06 \x10\x06\xebc\xac!\xc6:c6Fl#\xf0R\x00V\xb6\xdat`\xe5\xeaH#z4\x10\x10\xa1\xcf3\x12\x01\x87\xc6\x10\x0f\xaa\x03\xaa\xe1x}\xca\x8b/ \xf0\x16\x91A\x949\x05a\xce\xde\x04\x11\x15\xf5\xae\x11\"M\xbdkY\x81\xd5\xaf\xfd4\x0e\xda\x1d\xb8#\xfc\xf7\xeb\xf0\x97\xd0\xa3|\xe6Tn4\x15\x9d\xc5kM=\x14\xc7\xc3\xacHoH\x02n\x8f]\x16\xb1\xfe>\xe8\xc03\xcb\x9c\xd1f\"5\xf8\xc5\xd1\xd4o_D\xcdcJ\x06~\x18\xc6Sg\xcbb\x8an`LQ\xb3\x0d\xedJ\xc8\xc0\xb19F\xb3)\xf9\xbd\xaf\xa2\xd4\x9fs\x87\xb3\xa7O\x9f\x82x\xd2\xaf\x82/\x17\xd3\xf9\x98\xf9\x8f]\x00\x9c\x0f\xdf@\xa8\x06x\xa3>\xf7@\x97\xb6\xbaD\x9b\x1fQ\xa5\xaf\nV\x0c||\x04\xba\x0d\xc4\x81\x01\xe2\"\xe1\x83`\xb5d\xf4\xb7 JW|\x9aU~\x0c\xa6y\x9a\xc5K \x13\xa5t\xa6\x98\xa0q\xbd\xe0\xa4 \xd9\xd5j.*\x11r5\x1c\xd6\x88YI\x8e\xe5\xf2\xa6(\xae]\xfa,to\xa0/\xd2\xc6k=rw6H\xa2\xb6\xef\xea\xeeN+nH\x8eD=\xb0\xefC0\xcb\x17\xcb%\x9f\x05~f\x95jH\x05\x0d\x1a\x19I\xbf3\xe6}7\xfd \xe1\xa2\xbb=\x7f\xda\xa0\x9baRw\xc3\x07\xb3x\n\x922{\xb9Uitt\xca\xb3\xd7\nI^\x81R\x83\xcc\xb0\xba\xb0\x12M\xad\xc0\x92D\xc0\xe4]\xb0\xe4q\x9e\xc9\xe8\x88\xdc+\xfd\x1c\xac\x92x\xca\xd3t\xd2\x835\xfc\xf3\x0fEpIy!x \x0b\xa0\xb1m\x1b\x1dQ\x8f\xa6\x07j\xa4\xdc\xfa\xb3p\x88\x0b_\xea\xb1 \xb8\xd8HG\x9d\xa6O\x80\x12u\xb0\x8a\xd3\xecK\xe9@M\x9c6\xf9 X\x8a%\xf9v\x9a\x04\xab\xccj\xef\xa3\x1eE\xc47\xb6\x9a\xa5\x88LJ\x12\x05\xb3nu\xd1\xa6?\x05\xf3W\x94o\xdb\xf4\xeaOF\xeb\x10\xf4\x07\xf7\x86\x12\x02N\xaf\xe7\xb1\xde'=y\xaa(?\x1c\xd5o\xd9UZ\xa1g\xc2qA\"%\x9b~\xbe\xf0\xa3\x88\x838\xdb\x01{J~\xce\xaaY\xee@\xc0}H\x0f\xb8\x11\xb9\x16\x0e\x07\nn\x93y\xae\x81\xa7\x01tb\xbb\x02\x14\x0b\x16\x82l\x0c\x16b/\x8e\x12\xee\xcf.\xd3\xcc\xcf\xf8t\xe1G\xa7\x1c|\xdd\xcc\x07\xd3\x84\xfb\x19\x97\xa2w\xa7\x97\x02R\xf5\x04`\xc0\x8eq^\x90\x00Yd\x9d\xae*\xd4\xb3~\xc5\x8e`\xd9\xc0\xec\xf1:\xe8%E\xbdt+\xc8d\xc5\xf2d\xfc|\x11\x8430s\xced\x9e\x1d\x8fD-\x94m\xabZv\xc0w\x87SI\xed\x9c\x85\xc7\xb6\x8c\x1bF\xea\x11\xa4\x03\xc43=}\xcf\xf8\xa1\xd8\xed\xe0\x16P\xe2G\xb3x\xe9\xc8@\xb5\xc8m\x14=h4a\xcc\x06i\x9c'S.ob\x08\x8c\xd1\x83sI\x1b\xa5\x812\xe9\x93|\x172%A4\xe3\x17\xaf\xe6\x8e\x0f\x02\xbd\x85\xd3\x97\xe9\xa0pq\x14\xd3b3q\x14\xeb\xd8\x9f\xcd@\xd8\xaad\x14\xb0*\xeb\x89NO.\xba\x1el\x7f\x1bC\x10\xfc\x0e\xfc,\xf3\xa7\x0b(\xe9\xf4\x8a\x85)\x052Ig\x00T\x89\x8c/XX\xa43\x96\xf9\xf5p\x93*&\xa1\xf3\\kR\xb5\x8d\x9a\x19/\x97DGy7q\x80\xd1\xe6MF\x7f\x156\xbd48.\x14\\\xea\x10\xb1 \x11\x0f#\xe4>#\xf6DwM\xd0\xef\xbb\xca\x97@Qo\x0c\xaaA\x8b\xdd>\xd3\xec\xbe\x9aW\xa1\xd8\x8fO\xfc\xe9\xfbF_\xe3\xe2\xf1\x93\xd3\x942\xb8S\x0fq\xacU\x8f\xdc\x86\xc2q:A\x01w\xe2\xa4\xae\xc7\xd2~\xdf\x86p+<\xa2\xe9sG\x1c\xa4\x1b\x8c\x08f\x0d\x16%\x18\x947\xac\xdfhd-M6\x18\xa9\x80t\xd4\xa5\x88\x04\x0d\x94\x86\xe88L#\xca!\x19\xebV=p\x85\xad\x8d\xc8N ?|\xf5'K.;p\x02\x1b\x1dW\x8f\xfe\xa8\x81\xa0RW\xa0Y;\x83\xa3\x9e\x04\xea \xack\xee\xbdz\x94\x91u\xd2\"\xbb\xa0\x1e0\xbc\xde\xb2\x1b\xdfRO\xa3\x01%\xf5\xb4\x98i\xd7\x1f\xe8\xd3p\xdd>%\xe3-\xeajw\xd3s\x9d~m_\xa7_\x1eK\xc6\xc3\xef\xa3w;\xd7\xef\x9d\xf8\xbb\xfd\x91\xfb\xd8j\xebM=\xa0\xb0\x0fA\xe4@\xd8{P\x0f\xcdQWJ\xd8\x98\xa3\xa2\x00\x9b\x07\x91\x1f\x86]\xe8\xc3\x0c\xd8\xb9i\x87\xf3\x825\xb7\xab\xe1oM\xb6\xe7\xf4\x8a\x98\x05:/\x94\xf2p^^aW\xf7W\xb3E\x90\xc2\x0d\xd7\x11\x14\xd0\x94\xc0\xba\x11\xc0\x0e\xec\xc5v[\x80\xee\xd7\xa2\x8a\xed\xc3B6\xed\xc4\x17\xadV\x06a<\xf5\xc3\xb7Y\x9c\xf8\xa7\xbc9\xe6\xda\xd4\x07\x02\xd8\xe6\x15\xa45\xda\x19\xd3U\xca\x95\xef7\xc6^\x97>#\xc0\x9c\xac\x97%9\xc7\xc3?\x9e\xfb\x9d\xc8\x1dd\xf1\x17\xf19O\x9e\xfb\x84\x06Y\xff\xd5\xf9^\x1fS\x97a\x9c^\x14\x7f\xc6W \x9f\x82\xe9ZO\xbb\x97g\xf6Wi\x9b(\xd7\xaa\xf5\x9b\x82M\x1b\xfe\x06ycS/\x119=\xd0\x10\xd5\xbaV7>\xb29\xf7f`\x90\xd0\xcb\x12\x7f\xca+M\xb0\x036\x8d\xa34\x0e\xf9\x002\x1d\xf0w\xa4\x92\xce\xfd$B7\xe0\xb0\xf7w\\SL\x17\x17 \xa9\xc9@%UZb\xb5\xadC\xebR\xea\xb4\x86hA\\\xc5\xf9N\x99\\j\x0cw\x86\x96+\xe5[\xbbd\x00\x98\xc0\\\x1f\xa8\xdc\x03\xc2\xa0\xe9\xf7\x82\x12\x890v\x98\xe1N\xbb4%!\x02\xe8\x8b'\x1e\x04\xd1\x82'A&\x1d\xc1\x0c\xc1\xd2C\xa59\x01\x9a\x99\x04\x9a`\xfd8\xd3\x8cF\x9a\xa0\xc5\x007\xf0\x94\xdc\xea/\xa4\xc1\xb6&r\x86\x8f\x1et\x9a\x9fj\xad\xdd\xebT\x1a>\xba\xef\x96f1\xd7\xac\xaf\x19\xd0ti\xa1M\xe3\xbc3\xa4\x02\xe8\x8bt\x8bK\x82\xbd\xf6[\xea\xf5\x89\x92\xaa\x08\xbc\xac]\x1e\xe0\x0c^H\xa2\x9b?\x88\xe2d\xe9\x87\xc17<\x81k\xa9\xa0\x96s2\xed\x8678.+\x95\x0d\xa5G\x0c\x7f\xe0\xa7\x97\xd1\xd4E\xcf\x04\xfe`\x95\x04\xcb \x0b\xce\xc4\xd6\xa7\x8c`\xd8A\xf5\x13p\xb1z\x0b\x0e\xeb\x19\\\xb3\xc0\xaaF\x89m\x17<\x7f\x8f\xea\xb5\xb5vE\xb1\x1d\x17bQU\x13\xf70Q\xbc>\x84f\x8a\xae\x82\xe5\x8f\xb3\xb7\xf5\xc8\x95Q\x8d\x96\x8146r\xf6\x86\xa0\x9f\x19\xcc\x82t\x15\x97\x89\xbb\x90\xb8\xf4/\x9e\x9d\x16i{*M&lc\xcd\x84\xcf\xc1@\x85'*}[\xac8\x81(\xfe\x9a\xab\xa6\x0d\x91v\xf7(D\x02\xa1\x8f\x7f\x92\x9a\xa8\x049\xf30\xd6\x1dbwC'\xa5>J_\xfa/\xd1_\x05\xba\xe8\x00,\x11Get\xa7\nN?\xee\xdcaA\xfay\x10\x05\xe0\xa2\x1a\x1c\x0dq\xf0\xf2\xe1\xc4\xd2\xdfP\x9bQG'0\xd4\x88\xc3\xde\xb6\x0b\x82[\x18c\x1a\x9cF0\xf5\xbb{;\x9d\x88F\xfb'\xac\xfb\xb3Re\x15\x1f&\x17\x18m6\x05h/\x0d\xe0\x9c!z\xa5\xdbT\xbf7\xb7\xb7\xd6u\xe7\xb1\xc60\xec\xb6\x99\xdadz\xe5\x8c\x03Q\xd0=\xb2pi:\x81>pn\xa3\x9f%b?\xa0\xbd\xd2\x0e\xef\xd7\xfd\xdaH\x02Y\xf7\x98$\x03V\xee\xd1\x01+\x05\x9dm\x86\x0e\xe3\xb4\xb3\x81\x08oCUgX\xec\xe5\xe8\x10\x03n^I\x97\n\x15\x9a\xebjtG\xd1\x1b\xc2\"\xfc\xd5J|\x1d\xf3 l\xe8\xca\x9f\xf4\xb4\xe6\xce\xa8\xe5\xcc\x9bbEt\xd8z\xa0\xda =6\xf7X4\xe6\x13\x88\xe9\x81Nx\xc8K\xe5\xb6\xe3\xea\xad\xe0\xf2\xae%\x16\xe0\xce\x90\xf6K9\xbco\x89 \xfcp\xcf\x1d,y\xb6\x88g)Ejw\x0d\xff\xc0\xa9\xe4\xec\xeaG\xa8\x90^\x0cp,\xac\x96\x9cv]6\xf3re\xa0\xa6\xb1\x9a\xad\xd9(\xa0(G\x12\xcb\x80\xd7\x86\x82!1\xe3\x9a\xdf\x80\x05\xa4\xf2e\x90uXX\xc4Q\n\xec\xbb=vVD*\xf5\xd8\x89\xc7\x8e!\xc8\xec\xa1\xc7.0\x9a\x96\xc7\xde{\xec\x99\xc7^y\x10tk\x0e\xe7/\x9a\xe2c\x00\x11y\xa1\x14i\xb9\xdc\xbd\x0b\xf14\xee\xd6\\#\xe8\x1aW-\x10\xff\x02\x9cu\xea\xc9\xae\x07Qq.\x06\xa7<\xf3 \xf2\xcd\xc5 \x15\xaf\x97\xf0\x8a\x9a\x0d\x0f\x02\xd9\\\xa0\x06\xc5\xf5J\xc1\xcc \xe1i\x1c\x9e\xf1$\x85\xe6_\xc9\xad\xa5H\x15\x8b\xfa\x19SA\xf3\xed\"-Vn\xc0\xd2\xb4\xaa\xa0 &\xf9\x10\x1b\xf2+\xf8\x1e\xf8\xbeq\x02\xb7\xec\xd2>n\xd2K\x91\x08\x8aIb\x9b|-f\xab8\x89C\xe0]_Z&\x9f\xf2\xac\x07\xab6@s<\xd7c\xaf\xc9\xe8%\xa2\x0f\xe8tO\xf0LAi\x808-\xe8 \x9e\xe2\x83\xf1\xd6DP\x80\xb0\x9e\xae\xfa\xbc\x8f\x9e\xa1\xecB!bd\x8a\xb7H\x9c\xde\xf3 \x99\xe6\xa1\x9f\xb0 :\x8b\xa54\xc7c\xbd\xe7/\xde<\xff\xea\x8bgo\x8e_\xbc\xfc\xd1\xab\xe7\xcf\xde\xbdx\xf5\xd2\xa6x\x17\xad\x9e:\x01!\x8bA\xa5\x92\xe8C\x03\x18o\xa9'r6^\xa3J2\xf6\xd8s}^R5/R\x89/\xf8\x90*\xfd\xf4\xd8\x99[x\x15\x14\xeb\xa3Q\xe0\x06\xc7gzV-C\xc5\xbb\x02\x8dh\xa3\xae\x13\x14\xa8[\xe2\x90\xc5\xaa\x10\xf4m:\xb2\x97xT\xc7\x97Rf\xc6F5$s=\x1b\x9a\x17\x9d\xbe\xe5IB\x93\x000\x19&\xa6\xa9\xb8C\x8eV\xad\xa6'l\xdd\x93\xfa\xed\x92\x02\xfd\x8e'lyRT\x0c\xab\xd0\n\xa6\xb8qZ\xe3*5\xa0\xfc\xda\xc12\xbd)5h\xe8\xdc-O\xdf8\x16k,\"'/V\xf3\x16U\x82\xf21\\c>\xa9\xfc\x8f\x93\xe04\x88\xfc\x90T\xf8+n}\xc4\x9e\x99\x99\x92\xd5\x7f \xde\x83`\xb7W?\xcd\xb2\xa7<\xebr\x15T\x0e\xf2U\xc1\xe8\xbdr\xb8\x0b\xbb\xdc\x01[\xa2\xb3\x07\x89\x14\\L\x86I\xf5\xcc//\xfct\x8d/[\xe6\x91r\x12o~\n\xf7\xdb._\xb3\x900\x86\xfd\xa5{\xc00\xaa\xfa\x9d;\xec\x12-\xa5\xd8>{\x0d\xbc\xaa\xb4`\xc0\x1f\xefu\xb4\xc0\x9c\x1e\x86\xa8\xa3\x1cE\x99\x83\x006a\xd4\xae\xf2P\xa2\x15\"N(\x83\x80\xc8w\xee\xb0\x13q\xe6\xd3X#\xaf\xe8\x18|\xa5\xd7\x15\xb0q4j?\xb52M\xa0#\x16\x7f!\x10y\x0bz\x0f6\x02\x1b\xac2\xf9y\x91,\xa1TZRA\xfcW\xf0\xe41\xab\x08\xf5i\xdf\x15f\x7f\xc5\x18Glaf\x14\x87\xe1\x0e\x00\xe6\xc8\xd9\xca\xe5i~\xb6\xbe\xbc\x8fMV\xcd~\x95\x05-\x8b\x1a\x883.A8\xe5\xe1\xf1\xae\xe4d2\xe0d\"\xe4\xd1\xfc2\xc6]\xbdC\xeb\xec\xe9\x85\xa8[\xb6&7\xbfj\x93\xacmi\x11\xe4\xa3\xdcTp\x17\xf1\xcb\x00}\xf5\xfe\x9e\x83\x14\xbd\x95\xf5\xe0\xad\xb0\x93\xdd(\x87.\xf7\xdc\x91\xda\xef4\xb0r9k\x02\xa0%u\x8b\xb0\xb3bE\x9b\x82\x97\xc3\x8f\xd6O\x1f\x82\xd8K\xd8\x93\xdd-\xb1\xa0\xa1\xe3\x1210\xe6\xbe\xd9\xff\x95\xf3\xcc#\xfa\xac\x0b\xbfF,\x00\xd7UV\x12\x1b8\xc7D\xae\xa4]\x81\xe3\xab\xd3\x8e\xf9\x15\xd8\x89\x02\xe7\x9c\xca\x83\xbd\"p\x0e\xcd>\xfbE\xca\xad\x1c\xf1w\x86T \x10q$\xb7h\x99\xea\xe2-\xb1\x97\x83`r0\xf5WY\x9e\xf0\xb7\x99?}\xff.\xf1\xa7\x9a(\xa9\xe2\xab\xa3U#\x15I{D\x94wR\xd1n\xf3\x8aphH\x88\x90\xd2\x9a\x90\x89<\x0b\x07N*\xddm\xe5\xb8\xa9I\x8f\xa4\xca\xa9=hdR\x19\xd50\xc2\x9b\xb8\x81*\x1b\x0d\xa6\xf1L\xe0^\x0eWu \x08D\x84\x8c\xea\x9a\x0e\xa8\xd7\x90\xc7\x93j\x05\xdc\x81\xa5\x90\x02}\x85t\xd7.H\xf7n\x0e\xed\x15e\x1e\xc7#\xd6K\xfcozu\x1ae\x96=\x11\x18\xdf\x9b\x9d\xfb\x1d\xcaf\xc97\x97#\xd6\x13\xffz\x06\x8a\xf3\xc1<\x8eY\x9f\xf1\xc1\x89\x9f\xc0\x7fQ\x0eh\x83\xe8\xca\xec\xdc\x87z\xb7,\xb8\xdd5\xa2B5Hn\xd7\x08\x9c`\xd1\x10\x94\x17q\x02\xc3\xe4\xd6c\xdb5\xbe\x1blu\xb9.\xe9\x04n\xb4b\xa4M\x8a\x1a\xedV<|\x9c@\xfc\xd1qBX\x9b\xb6\x9a\xecD\xe8\xac@\xac\xebV\xf3\x0bd\xf8\x87\x8f\x99\xcf\x9e\xb0\xf41\xeb\xf7}y\x85\xadX\xa0\xfe\xc4\xc3\xf8\xd4\xca=Q\xee\x9a\xea\x13\xcd5KT\xe8EHL\xff\x18\xaa\xc3\x87CT\x1dj\"vT\x1e>\xdc\xfe\xd8\xcaCz\x12\x15\x8f\xa1\xf9\x96\xed\x15Z\xf5\x1ex[\xac\xceC\xe3\xa4\xd26X\xb7-P\xa6\x94#\xda\x00\xda\x96S\xbd\xe3\xb2\xd31x\xc3-\xe6\x06\x8fg\xeb\x1a\x9f\\\xab\xef\x04\xc5\x94\x9f\x18\x91\x97\xa6\xf0\x16\xda\xc8\x98\x9ak\x0e\x1c\x86}\xe7\x0e\x8b\xc7J11\x11\xebr\xdd\x10\xb9\xed\xa8)\xd0\xfc\x01\xe2\xbf\xbc.W\xb9s\x9b\xf9A\xa4V\xc3\xee\x0dV\x83\x82\xb6N\xe6\xd7\\+M{]R\xf6Ulz\x1b\xcae\x88Ju`\xf7R\xbe\xeb\xeby\xf38\xee\xdd\x8e\xaa]\x0d\xd3\x00\xa5\xbc\x0es]l\xa8\x1d\x11+\xcae\xf6\xf46\xf5\xef\xb5\xeb\xa4\x9er\xc8N\xe9\x80\xe6\xb4^t\xd5Y\x953\xeb\xaa\xcaY4\xabr\xce,\xaa\x9c\xda\xe7\x96]5>\xa7\xed\xc1n\xab\x15.I\x8a1\x8d\xa3yp\x9a\x83\xf6\x95\xa6\x1a\xbc\xd0\xce\xd2\xae\xaf\x95\xa7\xa4&\xba\x92\x1b\xdf\x164*i\xe3V\x98\xe2X\xac\x87\xb69\x185\x9c\xea\xb8\xd7;>\xe6\x1c\x0c\x07\x0e4\x07s\x90&\xcer\"\xe9rp\xe6\x87\xb9\xe0h\x16J\"sV\xab\xed\xb1K\xd7\xd3\n\xcab\xd1\x98O\xd8\x01\xe5t]\xe6\x88\x7f\xe8\xb1\x0d\xacO!u\x9f\x8dQ\x9b\x9aM\xca$\xe9\xad\xa3\n\xb1\x1a\x8d\x8f\xa6|\x04\x94\xbe\x1b\x94<\xdd'\x98z*\x80\x8a\x95[>c\xb9F]\xee(J5u\x8c5\xe0*\x992\xdah\xb7\x8a\x05\x07;\x02\xba\xaf\xa2i\xe1\xd4\xe7\xf8\xb8#(\xe6\xf3\x11\xf0\xbe]!!\x89\x04-\xe7F`l\xd0hS\xf1\xa7@\xd7\x97q\x80J\xc4r\xc7|\xd2\xa1\x9e\x896\xe8`T\xd46!\xc6\x14\xeb\x1d\xe0\xed71y\xc98\x98\x08\x1e6pY\\\xfa\xe5\x8d)\xb8b\xae`\x94\xb7\x95s*%\xd2\x97(\x98\x8c\x03i%7\x14\x88\x99\x0c\xd2\x15\xdc|\x0c<6\xa4\xee\xee\x81*-)?\x9b4~V\x8ac\xa3&\xeb\xf8\xb6iG \xa2\xdfzG\xf1\xac\xf0j\xd18\xef\x16:!\xb6\xe3\xb8:\xa1\xf6\x19\xa1\xe7\xb1\xd9\x19<\xccbD(\xc9d\xac6-\xde\n\xdew\xcc\xf0\xc8\x92\xb1',\x12\xd3\x9d\xb9,\x18g\"\xb3z\xd91k\xb8\x08\x07\x1f\x8d\xc1\x81\x05^h\x95\xedn=\x06\xc2\x1b\x8b\xca\xd8\xb4\\\xc5I\xa9\xc9!\x1b\x95\xbaTu\xa3\xac>\x96&\x00t\xb9\xb55+\x88\x0b\xe8\xa9\xec\x03c\xedw\x8b\xba\xdc\xc6\xaa~\xaf\xc6\xb0\xdc\xfc\xeb-\xb7\xad\x9a\xbe\xeeU\x84G7\xebK\xa7[U\xbf\x10\xfc\x14\xcf\xaa\x06\x05\x1b\xe6\xfd\x80\xfe\xf5\x81\xf2\xc6,8\x8b\xa9S\x17z\xe2^:u\xe2z\xba\xd8X\xa6N\xe0R\x84g\xea\xe8\xe6\xd0hG\xb8t~\xfe\x01\x85q:{\xdc\xec\xf5G\x19\x8bi\xa1*\x17N\x88\xce\x88\x8bSc5T\xa4\xc72e\xb4\xc4\xf6Y\xfe\x03vS\x8eY\x9e\xa3\xea\xb1~\x1b\x04\xab\x04\xdb,\xf88\xd2=q\xf9\xbdf\xe7\x01\x1a\xdd\x1f,\xfdU\xbb#hU\x81\x1d\xb0\xcc\xe1\xe3\x08T\xcf\xe2\x7f\x15%\\\xe9|\xc9\xc9+Zi\xf3\n\xff\x07o\xbdc\x0d\xc8\xbd@\xe0\xd516O O\xc5\xbe\xa1Zq\x05\xd7u\x12D\xb3\xf6P\xb6\xddg\x16\x8f=\x8f(S9\x9c\xa8 \x85\xff\xd7<\xd5\xc5(\xda\xe0\x10\xce\xfdv\xba\xdd\xe9 \xadD\xcb\xc8\x98\xe2H\xe6I\\\x0b\xc8\xd5t\xdcF\xff\xed\xe0]\x00\xe6p\x0c\x82d\x0fe\xc4\x13\xd7c\x9f\xc6q\xc8\xfd\xc8\x01V&+}.C\x01\xd4\x05\x81]\xf4m\x8cY\x13\xe4<\xdav\x07A\xc6\x13?\x8big\x8e\xc6\\\xca%\xfa\xc8fAN\x1a\x90\x1bK7\xa5\xe5\xc9!\xbd\xfe\xa7\xf2\x9bur1\xaf\xe3U\xa7c\xb5yX\x9e\xdd\xc6a\x94\xc8\xd7\x0f\xa3f.\x1c\xe6\x08\x1f\x8c\x1f\xac'\xf9\xeaQ}\xddET\xb2\xa5V\x13\xcaV]\xd2\xdbF]\x128Z*%\xf3)J\xe6C\xe7B\x06\x08\xbf\x90\x0e\x12\x99t\x19\x0eh\x0e\x13'R\x02\xf4\xf8\xec\x16\xbe\xf2\xaa\x8d[\xfc1\xc0 \xe8\xc2zF\x9c3y\x89F\xaeN4\xf7tN\xb5\x10\xc5\x82\xa4 \x16\xc9\xdb\xdb\xf2\xc2\x9e8\x9f;\xcb\n\xc71t!b\xd9>\xe3p\x19}i\xe1\x86\xf0T'\xbe\xda\xc2\x85W[\xaft\xaa\xe2f\xe4T\xb05\x91\xcb\x96h\xcc\xc7I\x0bJ\xf5\xc8\x91.\xc9\x02\xe6\xa5R3e !\x03\x7f`/\x040\x9f\x1bzdf*'\x9cs\xe8n2\xb1\xc2\x02\xe0p\x02f\xae\xe7\xf2J*\x1a\xd2\x08\x82\xa9\xe0#\x0e\xc8\xe2l~\x02\xce\xc5\x9c\x128\x1b\xc7\x83Y\x1c\xf1\xc7.(\xe0/\xd8\x81b\xe2\xd0\x1a\xf8\x18%&\xd2\x90\xbd\xf8%\xf6ogVHS\x0e=\xb6p\x96\xb02fp\xddJ\x82\xf9\xb0\xfe\xd1~\xdf\x125K\xcc\x1c\x11\"\xa84\xf7\x9c6`\x03@\xe0\xb4\x123\xdb\x1c=\x8c\xd7\x03\xb9]\x0d'\x0e%B\xc8Py\"GZ%\xed\xb3\xc3\xc1t\xe1'\xcf\xe3\x19\x7f\x969[\xae\xcb\x9e\xee\xb3\x07\x0f\xb6\x1f\xed\x82\xc5\x12{\xb2\xcf\x1e\xec\xee\x0c\x1fA\xf9Cp:9\xee\xf7\xa3\x89\xb4g0\xc0y(\xedG\x0e\xad <+Ax&A\xd8\xef\x9f\xd9\x81v\xd6\x82\x8e\x1a:\x89=\xf0\xd4D\xb8\x02z\xbe\xa3\xad\x9d\x1a\x00\x9dS\x97^P\xe40%4\x15o\xd7\x1d_H~\x00\xbb2\xab\xc8\xee<\xb6,/\x89B\x8c\x90\xa2\xe6\x0d\xf6\xf5\x9a\x96\xe2\xd1\x8e\xd4R\\.O\xe2\x10U\x12\x8f\xee\xdf\x82J\xa2v\xc2)\xf48\xb5-\x1e>[\x91\xc3\xb6\xe9vH\xbe\xcb\xdcb\xc8{(8J\xcd\xf9Bm\xf7`\xfb\xb2\x88\xd3\xcbx\x9a\xc9\xee\xd5\x8d:i\xf5\xa22o\xac\x9b>\xddD\x89\xa8\x97\xd9H\xc6\x95Q\x14,\xd9\x04\x953F~\x16\xbfV\xdaM(B\x95\xc0N\xbf\xf3O'\xb7\xc74\xea\xba\x0e\x8b\x8aC!_\xfdZL\xd8\xac\x90\x98v\xd54\xcc\xbbi.V\x84B\xc2d\xfa\xc2\xfa\xed\x90\x1az\xed\x1b\xe8U;\x97\x14X\xb5\x06\x1a%\x8e+=\xda6i\xa5\xeb\xeaf&\xe7`\x81\x9b\x80\xb3(\xbb\xef50}57\xbb \x92\xc0\xc5\x98c\xac?\x8c\xa1q-wF\xe3\xca)\xb4z\x98\x8f\xbb\\\x8f5\x89[\xbd\xb3\xfc\xd6:\xeb\xc3\xcdrP\x04\x01\xf4CG\xf3j!\xc5h\xda^\x0b\x01\x1a{\xa5\x15\xa1\xe0B\xa6ND[ \xce8\xfa\xa2\x0c\xe2\xe8\xf8x\xc4r\xf0/\x9aQ\xe6|\xc7\x91\xbf\xe4e\x993\xa7n\x02\xfd\xa1*\x1f\x99:q\xfd\x93\xf38\x11\xd5\x9b\xb1L\x0ez\x86\x8a0\xf87\xc2\x7f\xfb,v\n\x8anHE*\xbf\xdf\xf3\xcb\xcf\xbb|\xccb:\x0e\x8b/cA\xc4R`jgv!\xfel\x9cM\xd0\xd6\xb9\xd4\xdc4vm\xe1\xa7/$\x96(X&\xa8\x06\xd1r\xd0\xa2\xaf\xa7\xa5\x18\x01\xd3\x83\xf49\xc8\xaa\xde\xaeT\xc8\x97Zsf\x01\xd9\xaa\x99a6.\xf7\xb1z\x932Y5$\x7f\x1a\xd5\x97\x82\x1c\xd6\xeaB\x9a\xac\x08\xefF-\x19\x19\xa9VO\xc5N\xc2\x9a\xf2\x97Q7\xe5~b|\x12\x13eM\xfcaV\\\xf1i\xc0\xd3zMLUU\xf1\x17Q7\x0c2\xa3f\x18dE\xbd0\xc8\x8cZ\x1a\x0fP\xab\xab\xe5\xc8\x16\xb4\x14\xa2\x9d\x82S0\xda)r\x8av\x8a\x14\xa3\x9dW\xddS\xdfoT!\xeb\xc2_E\x95j+\xae\xd6\xb1\xd8\xde1\xfd\xcb]\xbe\xaa\xc8\xb7\x031\xdcQ\xf01\xa8\x91Q\xd6g=\xd70 \xad\xfc\x863\xc5\xaby\xd7\xaf\xa6\xb5\x98Z\xcc\x1c\xe5\xbc:\xcaXG&\xaf\x0d\xac\xea\xfa\x89\xfc\x0e-\x1e\x95\x8cw-B<8\xc8(0\xce\xd1;E\xf7\xaa@D\xe8\xd5\xb4\xe7)\x98\xf6\xb0B\xd0^!\xae8\xe3\xafp\xcct\x13UHPM\x94l\xf9M\x1cj\xe9\x02\xda\xdd\xb5=\x19\xa1\xdf3\x108P\x9c\x03\xba\xf6/\xf8\x06\xfa\x1c$'\xeb\xd6\x8dG[E\xfc\x1b\x1bx\xd9\x87D\x93\xab+\x91\xaf\xc7*\xc0\xb2o\x8b\xb2\xe0\xc6\xb4\x1e\xca\xe0\xce\x1dV-2\xae\x16\xaa\xce\xfcm\x0cYM\xa0a\x12\xa5>U]\xc6`K\x81\x12\x88.\xcb\xb8\x10\xc0V\x17\xb2\xe3\xae\x8d*Uk9\xee\x02x\xe2_,\x04\"gg\xb8}\xed\xa1\xd8\xdd\x06\xfdR\x0d\xb2\x12\xf2|\xbd\x01\xa6\x86CqX\x18\x88\xe6\xa6)\x88\xf2\xcf\xa1\x1d)\xb0o\xa2R\x0d&\xee\xedY\xcc\x9e\xe9^`\xd6\x1d*\xc1N7O\xef\x01\xb1XR\x9e\x91\xd7g\xe1\xaeQ-\xea\x9d8\x12\xd1\x91\xa4\xa0t\xe2\xf0\xc1)'.\xd3i\x01R\x07)\x071a\x06/\xfbP'\xe5\x10\x9d\\\xdenC\x15\xa0\xfa\x81%\xf0\x07\xdc9\x93\x01\x8f\xb0\x90\n~$\xca\xe0\xad)\x88\xd1\x0d\xfd\x94\x1f\xc8\xd0\xc1Dv;\x14k\x8d\x89)\x04 J\xdej\x1eb\xb5\xa0\xff\xbd\xff\xbeW\xcd\x97\x87\xa2\xfd\xf2\xd20\xc8e'\xeec\xb6\xb9\x99@D\x9f\xfe>\xeb\xfdw V\x00q4\x89 \xd9\xf77j\xb5\x19\xea\xf7%Ik\xbfB\xd8\x12\x95\xc3\xcb\xf0\xd6`\x82\xf2{A\x02\xb8\x18h\xac\xc2<\xe1@\xb3q\xbf\x9f48\xf61\xd0\xb5\xcb>Q\x8b'\x7f\xcb\x17\x18\x86\x86\n8\xae\x8b\xf8Z\x00mc\x1f ]i\x06*)3=\x82\xd3\xbc\xdd\xc5\x8beA7\x9f\xe6\x99f\xc2JwG=\x01\xd8\x8bZ\xb3}\xeb\"QOPD\xdf\xf2\x8b\x15\x13\x8c}\xb8\xba Fe\xaf%>-J\xda\x06\xc0\x14>>f1{\xc2|\xb6\xc9\x86\x8f\x9b\n3\xd9\xb0t\xa7\x07\"\"\xb9?\x04\xa0\xed\xe4\xe3x\xe2j\x0eW\xad\xdd+Z\x83.\x0e'\xa0C\xe9\xf7ckaS\x05\xa9\x1e\xf9\xad\x96>\xb1\x03\x15\x8eN~N\x81\x8fl\x97\xfe\x9a6*#\x9f\xb8M\x9eV\xd0\xc8jo)\xd0(@ao\x03\x1a\xe5\xcdh\x04\xd2\xc4\x8eh\x94\xba,\xc7\x10\x0e\xfd\xbe%\xf0PK`\x03@\x1ah\xe3\xeaJ\xbe\xec\xb3q\xe3DS+\xb3\x9ao\xcd\x9e\xc8\xab{\xe2;\xf2V\x9c\xc4\xd4M\xe9\xfc\xc3 \xcaI\xcfa\xd2c\x81\xf6h(\x1b@\xd5-i\xe4\x0e\x19\xa2\xa2\xc7\xf2\xf1P&~\xc4\xae\x17}\x1fN\xc6\x01\xe0\xb8\xff\xf8F\xfdv=\xd5\x18N\xe05\xf0WJ8\xc9p\x8b\xe6P\xd7\xf3\x8e!\xdd\xc74`\xb2\xdf\x8c\xc9\xb9\xb4/o\xc6\xf5\\\xe9\xc1\xad\xa5B\xd8\x0e:\xac\x05\xc9l\xf9\x02\xbb\xec\x8bAT\x81X\x80\xe3\xb4\x0b=\x0d4,\xedNO5\xee\xdf\x07t\xc8\xc7\x81FO\x9bIi\x88\x88\xe2\xa3\xa7&\xec\xebp2\x8e\x01\xe9\x82k\x10\xd6[\xe9Yq\x15\xb7\xe8\x8c\xa8\xaf\x0c\xf7c\x0f\x10Z\xe4U\x92\x1e\xb3\x0d(&\x15\xe0w\xee\xb0P\x117\x176\xdcp\xb0\x8aW\x8e\xeb\xe1\xa4\xc8_n\x87\x96\xd7X.\xda}\x80.\xeb\xa4\xab\x03\x16\xc9\xa7\xe8|\x89\xd9\xfc\x0f\xe8_7\xe0\xca\xaa\x9a\xff\xbd-y?\x11\xdd\xd2\x0e\xc0\xa9\x9dt\xec|\x93+\x89k1q\xfa\xb7\xd79\xca\x81\xc2\x9b;?\xff\x00\x84\x92;/\xfd\x97x\x0b\x91;;\xf7\xbf\xcf\xb3N\xc1\xf5o\xec\xdf\x8e\x1c\xac\xca:_\x13\xack\xf2\xc6u\"y\x1bl\xb1F.2\x0f,\xe1,fpU\xe6-.\xb9\xb4h\x1cwZuU&\xab\xcd\x7fh\x8642\xc1\x03W\x84\xbf\xfa}\xee~\x9c\xbdP\x93XA\x10)\xd8\xf87`\xa0x\x86\xaf\x12\xab\xa8\xf2\x9b\xa0\n\xb7Ct\x08~\xe5#\xd0\x9b\xdb<\x05\xd2B\x06\x1a\xd5#++j\xe3\xe3\x08x\x10%\x83\x1b\x1e#\xad\xbe\xaf\n\x89@\xc1:\xa1\xa142\x11\xbc\x95\x89h\xdc\xa6\xb3\xca6\xddr \xeb\xc434\xb2\x96-\xfd(\x97\xb7\xfc\x8c\xf5\x10\xd6\xba\xd2\xad\xc7\xa9\x02\x9c\xd2\x00i\x0b\xaf\xdcD\x8fY\xae\x81\xb3\xe0\xc0\xfd\xb2\xa7\xa9\xe4\xc0s\xc5\x81\x8b\xbcT\xe3\xc0surH;\x9c\x1c\x9aN\x0d\x96\x13\x03\x9c\x16R\xf8\xe8p\x02N>\xfa\xfd\xbc\x0b\xdd\xbc\xce(\\O}\x06\xce\x11\x99\xc7\x02\xb0/\x10hHxN\xee@\x0b;a8\x1es\x91\xcb\xc7\xc1\n\xb2\x14\x82\x18 \x93\xc7\xbbk\xe3<\x9e\xa1B8C\xb5\xb3\xa6)B$W\xc1\xbf\xe5)\x0d\x91\xdf_\x03\xf9eo6\x1a{\xd3rd\xc8\xf4\xcf\xe7&#\x9b\x13,r^e\x91\xd3*\x8b\x9c\x16,r^\xfe\"Xd\xb3ekO%G,f\xaa#xn\xb0e\xd9 9\xbb\xe6\xf2\xf2t\"nv\xf5\x07\xf4\xaf[\xda\x03m\xbe\xc1\xe9\xcb3;C\xfa\x82\x9b\xe9K\\\x1aY\x1a\x17_R\xdb\xcd\xb7j\xb1\xf5\\\x84[6m\x88\x16!\xe3\x18\xb4\xdcx\x97B\xd3\xb9\xc7V\x1e\xd8WN\xa5\x81\xa21\x1f\x8b\xa6\xcc3\xd0n(\xc7sf\xfe\x12\xf2\x95\x13\xc6*F\x97\xf5\xc0$\xbc\x99\x97S\x9cF\xe9_\x98\xc4\xad\x04|C\xa9\xa8\x0ep\xaf\xd4*\xa9\xa7\x9d\xad0\xe5\xb1/A3\xbb\xb4`\x9f\xb7<\xb69\x14[\xc3\x99\xbc}2/\x9c\"\xac\xc4\x9b\xa9s\xead\xb1\x1c8\x1a\x00\xd9Y\x83\xe1\xf2\x87\x1a\xf8\xe2H\xb9\xe9m\x87]\xe3\xf5v\xf2\x02%+\xcc\xdd4\x17\x05$\xcct\xc3\xbd}6\x9e\x81\xcb\x8aH\x19\xf1!u\x8f\\\xd4\xc1\x01h \xeeM= nH`\x91\x89tb%}L@\xa8|e\x93\xdfbD\xa3\x1e\xe0?\xect\x94\xf2\x15\xbb\x901\x0d`\xbf^\xa0\xf7\x8d\xd2%2\xac-\xf4\x07\x1b\xe0~%\xbd\x19'\x10M!\x8e2~\x91A,\xa6\xe44u\x0b\xfb\xcd\x04\xe3G\xc4\x88)A\x89BbNlq\xa2[I#\x86\xfb\x96k\xab\xcd\x0d\xc7\x19^\x8c\x94F\xe1\xd6E\x11\x89\xa1\xf3jd-\xe9\xffC5\xcf\xb8\x1da\x14\xff\x8c,\x05\x1f\x043\xbb\xe4O\xfa\xc2d\x8d\xf1\xfc\x01\x03q\xbb\x13\xadaOf\xe3\xb4t\xdb\x8b?\xe2R'ct>\x03W\x9a\xa9t\x80\xc8\x0e\x98\xd2\xec:\xe0P\xdcY\xa0\xe0\xdc\xde \x86\xf6lbnG\xb8\xe2\x1b\x8bbh\xe7\x06Q_\x89Ri\x89R\xa9G\xaf\xaeXF6\x88\x8b;\xc9nCI\x14\xc3\xd5/\xc7C\xf5n\xd7\x90\xf5Gk\x8c\xb7\xdc\xb4gr\\\xe8)\xdc\xc2\xb5\xa1\x087wBy\x9b\xd9\xf4\xfeB\x1d\xb6q+\xa6\xa8\x00\x97\xbc\xb4\x94\xb3\xca\xae.U\xb3\x1c\xe2\x03NOp\xc9E\xb8\x00}\xcd\x05\xf9\xb2\xc5\xfd\xcc\x07OR\xd9\xb4\x03\x95\x85\x95#I\xe1\x1adr0=\xa9Q\xca\xc1\xf4\xc4-\x0d\xa0\xc5\xcf\x02\xd7\xf1G4\x08\xc4\x96)\x9d\xef\x001e\xa3\x12\xa9\x89\xeb\xe38\x8a\xc2\x9bu\xfbvA\xb0\xeb\x14\xb1\x9c\x01\xb1\xbc\xba\x02BY\xec\x9c\x0b\xdd\xabv\x95\x84b\xa2FEU$\x19 \x98 n\xb1\xf5^\xb9\xbcn\xa7r\xa2\x0bD\xff5>\xa6\xe8\x0f4\xaa\xba\x13\x0b\x8cl_\x1d\x92\xce\xc8\x9e\xf3\xa2\xe7&\xea\x1ac)~\xde\n3k2\xad\xc8\xcc\xee\x191\x18\x03\x99^\xbf\xc4\xed\xcb\xf4\xba7]\x15K\x8c\x0epc2\xb9\x1dn\x0c\xc5N/[p\xf0\xd8/\xfe\x8fd$d\xb8X\x1fG\\\xfd/\xd2\xdd:[\xabB\x19val\xb5\x0b7\xc6\xac\xc4M\x99s\xea\xa6\x11S\xa62[\xca\xec_]\x0e\xac\x96)\x14T\x1c\xfc\xa3\n\xf2\xb3\x01\x91\x96\xe8k!w{\xac\x0f\xde\x1eX\x9f\xf5\xee*3\xcf3?\x0cfL\x0dv\x19\xcf\xb8q\xf1\x8d\"I \xee\xeb\xb65\x11Z\x02\xf4\xc2\xb0r\xc7/ES1:X\xf5\xa5\xc9\x14\xb1Q%\xf4\xe14\xc2\x8aC\x8f\xcde\x13f\x19\xd1\x95i\xabS&\xbd4`\xee\x98\xb2\xb7Q\x8f\x18BH\x04\x9c\xfb\x12yj\xce\xb8\xf8=b\x9f\xf1\x8cO3>cy\x14'3\x9e\xf0\x19\x13\x88x%\xb0\x8e\xdd)\"sC\xf8\x9e\\t\xcec\xe7\x8b`\xba`A\xc4\x002K\xff=O\x19F\x1fc3hMpC\xf1\x9c\xa5\xf9t\xca\xd3\xf4\xde\xdc\x0f\xc2<\xe1,X\xae\xe24\x0dNB\xce\x9c\xf3\x05\x8fD\x13wu\xec\xbe\x0b\x13\xeb\x1eE\xcf\xe3(\x0df\x80N\x04m3*?\x1c7\x1f\x1b\xc6 \x15\xbd\xc8\x02\x89\xb5N\x0e\x84'T\x9dc\xac\xf0\x96:\xbbh9S$k\x9d)H\x13\x97\x8fz\x8a\xa8\x8b\xa6\xa5\x90\xe0#\xe9\x89\x9b\x14\xb7JOY\x06\x90k\x06[\x86\xe7\xe3\xfa\xc5\xfc\xea\xe5\xf3\x9b\x03\x88p}\xa5NYm\x91\x96\xad\x86*\xe8\xf9\xfdV\xe7Q\x9c\xca\xd6\xbf\xbd\xd1\xe8\xa2\x1f\xaf\xe28\xe5\x15\x19p\xe8\xa6]\xfc\xd3\xa2\x895H\xad\xcd\x89\xa3\x0eC\xaf\xfd4\xe5\xb3B\x10\xa3\x05\x84\xc6K4\xc1\x9c\xcf\xea\xf1\x8cn\x17~{\x86JG\xcc\xf3\xbd\xf1Qt\x94\x1c\xe5\xdb[\xdb\x0f\xe1\xef\xa3\xc9\xbd\xd3u\xc1\xac\xd0_\xcc:\x89\xfb\x85\xc2\xe2)\x1bnm1\xe5\x80.\x93\x0eX\xb7<\xf6\xe8\x11\x1c\x13\xff\xdb\xef\xfc^O\xde\xff\xcf\xd4=iAq\x9b\x97\x8a\xfc\xcao\xbc}\xf5r\xa0\xc0y\xe9pW6?\x04\xc5Fm\x19\xdd.p\xff_\x83\x9cJ\xcf1~\x19G\x9b\xd3\x98'S<\xc6e\xb1DD\x17o\xf2N>\xea\x85\x8d\xdb\x88\x11o\xd3&\x96\xdf\x0b\x06\xb3 ]\xc5\xa6L\x85p\xa9)\xfaV\xb3\x81\x08 6\xa5\xa2\x9dg\xa7]W\xe0\xcc\x03\xa7B\x1e\xab\xf93\x05\x89#\xf8\xe4AY\x0b\xdbg+\xc5\x96.@\x89P,\xd0\xd4\xb2@\xd3\xe2\xc7\x01\xeb\xe1za#\x06\xbea\ny#\xeb\x8b\xcf\x17\x1d%\xf1u\x86\x0e\xd6R\x9e\xbd\x0b\x96<\xce\xb3\xf6sO!\x00\x8aH\xe1\n\xb7\xe9\xbb\xc4\xa7\x06y\x94\xf0\xb9\x18@\xf9\xcb\x81\x88\xa7\xe0UNt\xe6\xce\x1d\xd6\x8b\xf8E\xf6.\x98\xbe\xef\x81u\x90J\x86\x05\xa4\xba)\x12E\xc5\xf5\xfb/\x8f,\xcb\xbasa\xd9\xff3[\xff\x97\x95\xfe/\xb5\xfe\xb7hpj\xf3@.\xfb\xca\xd8f\x18\xef\xbf\xd0\x98\x8a\xb3\x15B\xc8\x80\x0c\xa7 \xa3\xd7^\x92A\x15\x05.\xf1\xcf\xb9\xd8XE\xb3g\x18\x1ct\x7f\x7f_\xcf\xb9\xba\x92Q\xdb\xcb4\xb1m\x0fvvv\xd8\x88M\x9d\xb9\x83\xa6\xe8z>\x1aGmI\xcc^\xb2}\xf6\xf3\x0f\xd2\xaf\xd6\x90m\xb23\x97}\x82\xd2M%\xaa\xa8\x03\x07t\xde9\x05\"\x18\xec\xd5\x15\x83\x01\xb2}\x0dK<\x16\xb4O\xbbE\xda!\x1e\x0d\xaa\xfb\x1aT\x1d\x0d\x84\x9e\xae\xb0\xabl\xa1h\xbb\xe6\xc4\xae\x8b\nA\x08\xe8W\xb1\xb3\x91\xc6\x03\xd2b\xae\xb2\x8c}'@Hu\x12O\x84\x1e\x0b5 \x05\xfc\xa4$\x9c\xa6\xdf\xa7\xea\x1eT\x839\xbd\x0d\xcd\xdaP\x96\xd5\xd1\x96\xdc\x8b\xd0\\I \x01bp\xec,\xbb4\\Ctn`\xb9\xe5c\x88q\xc6\xf8\x8b\xdf\xb7\xb2\x05\x1a\xbe\x98\xd5\x11\xf3\xd1\xda\\\xb3\xe0\xca\xa4\x01\x87\xd8\x0e\x9e\xb2\xb8\xc9\xb7\x08\xbf\x98r>K\xd9\xd2\xbf\x08\x96\xf9\x92\x15z\x8b\x0c\xa1\xf2}9\x1b\xd9\x1e\xde\xdf\xbb\xffpg\xf7\xfe\xde\xf5\xdbk\x07\xe76\xad\x17\xdd\xd5\xafx\x04bG\xee\xb8\x1d\xcb8R\xc4^\x9c\x14{q.\xdd\xc0Kk\xf258\xe5\xe6\x8d\xd8G\x13\x9bf\xc4\xd7\xdd\xfb\x02\x8b0X\x04\x99\xeaZ\xbb\xc1\xc0i\xf9)b\x0b\x12\xa3W^\x11\x0cr\x00\x99\xd2\x1d\xc2m K\xcb\xe46(\x9f\x83\xf6xW\xeb\xae\xb1\xb32\x044q\xf3\x01\xc2F\x9a\xc9y)\xff23\xd3\xa6\xcc\x10\xda*R\x1f\xed\x15\xa9\xc3\xedm\xb8\x0f\np\x02\x18 \n\x8e]\xae&\x02\xdcz\xff\xf7\x1f\xfc~\xafq\x1d\x9av\xef\x84\x1d\x85\x8e\xb1 \x82\xc178j{\x15D\x96a>\xabK\xb5\xea\xbe;\xd1\x05\x87\x1f\xdc\xe2\xc2N\xe4\xec\x0co\xe2\xdb\x93\xf4]/\x1a\xee\x1d\x1f\xf3\xf4\xcbx\x96\x87\xbcW\xa7\xda2T\x90\x1eJ\xc1EY\x0f\xc4\xd3k\xb2UQF\x00\x89*\xec\xb1X\xbd\x96\x1b\xd0\x07\x93\xdd\x08\x1cq\xb8}Pw\xf3\x1b\xcb\xac\xfb\xdb\x10\x95\xb3\xc8S\x1d\xc0\x90cd\x1f8\x12\x99r\x9c\xd2\xef+\xb5Ca\x9c\xc0\xba\x9f\xbe\xf5\x88\xe9/\xc7\x04\xa8}\x87&\x8b\xd3x\xb9\x8a#A\x0e)8\xa8\xe7\xd9j5b\x97\xc5\x0cZ\xcb\xf9y\xb6\x88\x93\xe0\x1b_\xf4\xe4u\xbc\xcaW#v\xd2\xbd\x1a\xff4\x8bF\xecx\x8d\n\xafV<\x81\x8fA\xcd\xf3n5\xd3\x11;l/\xf9,\xcf\x16/2\xbe\x1c\xb1\x8b\xf6\xc2\xa2\xd9C4{{\xdb^:\x16\xc5\xb7G\xecY{Q\x7f\x15\xfc&\xbf\x14}\x19\xb1\xe7\xed\xc5O\xfc4\x98b\xe9\xf7\xed\xa5\xe5\x91\xe4U{\xc908\xe3ox\xba\x8a\xa3\x94\x8f\xd8\xeb\xf6\nA4\x8fG\xec\x8f\xb4\x17|\x11\xcd\xe3\xe7\x18\xd8\x9d'#\xc6y{\x95\xdf\xc8\x97\xabw\xf1k_\x8c2\xebP>\x8e\xc2 \xe2?\xf2\xc3`\xe6gq\xf2\xa9?;\xe5#\xf6\xaeCE\x85]\xe9\x88}\xb9F\xf1\x11\xfbi{\xe9\x02u\xdf\xe6\xcb\xa5\x9f\\\x8e\xd8\xcb\xf5+} A1G\xec\xcd\xfaU\x11~\x9f\xb5W\\\x04\xa7\x8b08]d\x82\xe1\x18\xb1\x9f\xb5\xd7H$\xa6\xa4#\xf6y\xf7\xd2#\xf6M\xf7\xc2\x9f\xc6\xb3\xcb\x11\xfb\xb4\xbd\xc2\xcaO\xfc%\xcfx\x92\x8e\xd8\x8f\xd6(\xfe&>\x1f\xb1\xdfh\xaf\xc0/\xf84\xcf\xf8\x88\xfdV{\xd9\x05\xf7g\xd0\x91\xdfl/\x0bF\xb4\xe9\x88\xfdZ{Q\xb8\xc5\x17e\x82y\x1d\xb1\x1f\xb6\x97\x8f\xcfxr\x16\xf0\xf3\x11\xfb\xed\xf6\xc2\xf38\xce\xc4\xc2\x8c:,\xb4\xcf\x830\xe3\x89\xb6\x9a\x93\x0e\x95^\x0b\x88\xe3t\xc6\x1d\x8aO\xf3$\x1c\xb1\xa0C\xc9t\xba\xe0K\x81\x83~\x87\xc2o\xb1\xb0\xd6\xf7\xbcC\xade<\xe3\xe1\xe1\x85\xbf\\\x85|\xc4\xc2\x0e5\xbe\x145~\x9c\xf8\xab\x95\xf8\xc6\xb4k\x8d\xe7q\x18\xfa+\xb1F\xd2\xaeUFl\xde\xb5h:b\xab\x0ee\x0f\xa3|)\x9b\x9eu(\x8e\x8c\x8e\xac\xb0\xe8P\x01\xcc6e\xf9\xb3\x0e\xe5\x0bg\xf7\xb2\xce\xb2S\x1dd\xb8F\xec\xb4C\xe9w\xc9\xe5\x8b\xecU\x9e}\x9ag\x99 \xeb\x97\x1d\xea|\xe9'\xefg\xf1y4b\x17\x1dJ\x7f\xea\xa7\xfc\x0b\xff2\xce\xb3\x11{\xdb\xa1\xfc\x8fx\x92\n\xde*\xf1O\x97>\xae\xb7\x11;\xe9^\xf1m\xe6/W#v\xdc\xa1F\xb1a\x1c^d#\xf6\xc5z\x15\x80|~\xd5^\xe7\xb5\xa2\xb7\xf0\x91__\xa3\xc2\x8bh\x1a\xe63~\xb8\\\x89\xd9\xfcq{\xcd\xa2{\x10i\xe4\xc5\x1a\x154\xaap\xda^\xed3\xceW_\x04\xd1\xfb\x11;\xef\x00e\xc1\xff|%H\xda\x1f\x1d\xc8\xd7\xe6\xb2\x02ap\xeb\xc6\n\xeaw\x03i;;}\x96\xa6\\p\xf8\x87E\x87\xc8\xd2\x9d\xe4\xd8\xb4\x9frV;K<\xef\xa4F\x88:\xb5\xf5\x9eh\x8b\xd4\x1c\x8dg\x05\xbc\xd9\xbc|M\xcbW\xbf|\x0d\xcaW\xeal\x8az@\xf9\x8a\x87\xbb\xb0L\x88<6-\x7f\xad\xca\xd7E\xf9zV\xbe.\xd5k\xe3\x89\xf7\x15\x87\xe0\x03\x8f\xa8#/\xe6m\xef\x1a\x11\x8e\x8a\xbc\x9d\xedz\x9e_\xe4\xdd\xdf3\xa2\xe5\x14y\x0f\xef\x1b\xf1\x80\xca<\xe3\xf8\x1d\x96yF_\xa6E\xde\xa3\x9dz\xde\xbc\xcc3\xfa\xb2*\xf3\x1e\xd6\xf3fe\x9e\x01\x97\x85\xca\xbb\xbfe|\xef\xac\xcc3\xda\\\x16y\xc3\xadz\xde\xa9\xca{\xb4c\x8c\xef\xb2\xcc3\xc6pR\xe6\x19\xdf;.\xf3\x8c1\x9c\x17y\xf7\x8d\xbe\x1c\x96y\xc3z\xdeE\x99g\xcc\xfb\xdb2\xcf\x80\xcb\xf32\xcf\x98\xf7\xf7e\x9e1\xef\xcf\xca<\x03.\xaf\xca\xdaq\x07\xdc\xebv\x11G\xab6\xcd5\xd9\x1amW\xc7\xceQzs\xa8\xc5\xe8=}\x10\xa0\xad\x1a\x04D\x10\xa0\xadj3b\x1a5w\xc9\x807\xbfU5\xb2\xf5x\xfd]ugDN48\x81\x1eD\x837\xf0\x03tX7#\xd7\x12\x8e\xa3\x00X)\x8d\xb3\xdb\x87.>\xaa\xdd\x02\xb2\xaaM\xf1\xc1\xaf\xf3\x14Y\x11\x8f\x84)\xc3\xf6\xd4j\x82\x10\xaf\xb4F\xf5\x98\x06z\xc2\xff\x8c\xf9H\xf5-\\j6\xaf\xbe&\x13\xc9\xd0\x19\x14&\xc5\x1b\xd3\xd1\x0c\xc6\xc2\x82D\xff\xda\xaalar\xad\xaf\xb54\xe7\x05ab\x9b\xe7\xac5\xd6\x1a\xec\xe4Y\xe5\xae\x1d\xb1s\xdd\xc7\x01n\x96\x06\xb8\xa9\x0c\x106]\xb7_$\xa9\x86;\xb8\xbfg0\x14.\xe7\xac\xa9\xcc\xb93D|\xc1\x83\x0c\x83\x9b\xd1\x1b\x98\xa3!G\xe2\xac\xf3\x00x\xcf!\x85\x97\xb0|\x0e\xcb^\xcf\x05\x8c\xea\xbe\xec\xc3\n&p\xed\xac\xa7\xcbY\x1f\x96\x8c\x8c\xb0\xaf\x86\x10+\xe6^\x99\xf4-\x0e\xc6\xb5p\xf7\xc7A<\x87\x0e:f,\x06!\xbdM\x1d\xd7E\x0f\n\xcd\x10\x88\xb3@\x17\xadi4\xc0\xab\xe8>\xb0\x01q\x8b)Q\xa4\x19\x944b\x924}\x9f5W\xc9%\xa6\xe0\xfd7!\x1b\xd5\x8d\xcd\xc9\xc6\xb3\x9d/<\xc10{6;\xc9\xe3\xc1B\xd4\x89\x9c!\xab\xc8\xa6NyT\xeb\x07\x12\xef\xd0\x19\xed\xed!)\x15\x14\xf5\xd9\xa6 \xac[\xe2\xef\x9e\xf8\xfbTKh?p\xf3\xc46]Y\xc0\x95\x87\xcd\xec\xcb0\xbf\xb5\x88i\xbc\xcb\x9a\x83A\xa0'\xd0\x92$VI\xe8BO\xb8\xd7\x82u\xa9\x14\xcf\xf9zU\x87r)\x1a\xa9\x96_\xf3N\xb7\xab\xe5+A\xe7\xab\xe5KQ\xbe\xe3\x0e\x12ZQ\xcb\xde Z\xbf\xe3:U^_\xf4^\x9d\xda\xb9h\xad*Y\xde\x88\xf2*;u\x88\xb1ws+\xb3\xf2\xc3[\x1eI;\x8e<\x9aT\x82q\x9e\xe0#\xb1\xee\xe5G\xaf\x18\x05\x17/!\x01\xf7\x9c\xdb*w_1\x0f\xa9(b\x0f`\x1fw\xc9\xc5`Q~p\xcc\xd8\x97\x8e\xdd\x04T\xef\xcf\x0e\x8a\xdd\xc9\xc9\x00\xa3\x8f]S\xa7\x8aG\xea\x87QC\xa7\x9cZ\x17\xed\xa6\xa6\xa13z\xe6*\xb9\xcbg\xad\xac\xfd\xe4\x87:W}\xb82\x1b\xc3\x1b\xa2\xe1\x08\xc2\xe5\xbcb\xf4]{>\x8a\xb5\xf8H\xff\xe0\x11\xd3\x0e\xafi\xc8M\xdb(w;\xbbr\xd5\x94\xa7\x9a\xa0\xf7\xe6 \xc8\x9f\xab\xe8\xf7\xa1q\xce\xd7\xf5\x8c\xa5P\xcc\xa3\xe3t\xd6\x0e\x8fi\xa9\x8b\xea\x84G\x11\x1f\xb6p\xa2)\x0f\xa7<\x98\xd3\xa6`\x85 M\xf0\xe9\xe0\\\xebM\x0bH\x83\xcfCt\xa7\xd4/\xc0\xb5\x08xH\x07\xe7\x9e\xbe\xc6]\xb3\xc5-\xa8\xd2#O\x18z~\xcd\xcd.\xd1\xd0\x91\x0e\xce\x93RZ\x8c\xbcE\xa37\xb9\xfc\x08c\xd8\x82|F\x18\x817\xba\xc2\x98\xa5\x0b\xe2[nq\xe4'\x11\xf1.ps4W\x0fDu\x86p\xcd\xb5=\xac=\x8fV\xc4oH\xede\xde\xc1\xea'c\xf2\x0c\x1at:\x9b\x02v\xe8\x14\xfb\x07\xda\xb5\xe2\xaf}tj\x15\x0e\xb2\xac>\x97\x83\xc6\xe0\xa0\xb9\xbd7\xa0aJcG\xf0\x1f\x19\xba\xbap\xdfPo@o\xfd\xd4\x11\xeed\x9d\xa1\xcb\xeb\xb0\xdd\xa6\xd8\xe2\x07\xce\xa1\xd3\x15\xfbn\xc3\xbb$~\x08\xde\x9d\x17\xd0.\x0fI\xcd\xd6\xf1\x83\x13rk\xd8<1N\"\x9cA\x13\x87\x9f\xd8\x81\x13\x9b\xa9\x01T\xf7e#Xp\xfc\x1d\"\xe6'&\x11\xe8\xdc.\xd5\x8f\xde\x95\x07\x9f\xd4\xf8\x8d\xc8\xb7\x08\xaf\xec\x89 O\xec\xa08uR\x94D\xad#\xff\xd8n\xe4\xfch\xd2\x0f\x9e{\x15\x0e\xce\x8d\x01=\xc3bR(`\x8b9\x19\x8e_\xfb\xb1\x8b:q\x19\x98\x99o\xac\xe2\xf0\x03\x8f\x84\x8f1\x8c\x98`\x1e\xe6\xe0\xa7 \x0d\x16\xb60\xba\x08\xe7\x0f\xe8&=i\xcb<\x81\"Z7\x9f\x85\xe77c\x08\x9b9\x93\xf3\xf9X\xcd\xf1\xaf\xfb\x18\xb8r\xf9i\xc7\xb1\xa4\xf9E@\xe0|\x14\x01\x9e\xd9\xf7#\xf1\xfd[\xb2\x01Gy\xbe\x8c/?\xf9]v\xc6\xe4\xe8\x1fr\xf4\x1f1\xfc\x0e\xfb\xd01\x8d\xb7\xdd8\xc5\xf8\xec\x13i\xb1~\x0dk\xf7\xd98\x7f\x8deQy\xbb*\xfe\x11\xb8\xd7O\xac\x1b\xf6RD.>\xe9\x83\xdc\x14\xdd>t\xcf/\xbbn\x1f\xe6\xdc\xd5Jx\xcc\\\xfaU\x17;=\xfaP\x07\xd1\x84\xb7\x9bc\x8a\xfcY!.V\xa0\x1f\x15=\xd7\xe0\xa1\xa8\xbb\xfa\xfc\x107O\x925Ppv\xfc\x97z\xf2\xf2\x92\x84\x8b/\xfc\xc7\\\xf2~\xf8\xeb\xbaV\xf9R\xad\xcc\x19\xc5b@nq\xa5&\xd4\x1d\xbb\xaes\xa2\xc4\x8c\xaa\x8d\x8f\x86\xe3fQP\x8ar\x07\xceJ\xae\x9ak\xd3\x15FWe\x9dtGI\xce\xca\xcey\xb67\x98\x80e\xd4\\\xe3\xd9\xc9jq\xe9\x07\xd9\x18v\x16\x8b\x9f\xe3\nL\xbc\"\x97\x8f\x841k\x80\x7f\xad>K\xd8\xb3S1\x8f\xceH\x0dTS^\xe7\xf2>Bti\xd2\xdc\xcb\xebH\xd6\x11\xaa\x10\xe48\xcd8$\x82\xe8\x18\x89\xb9\xd4\xc1\x84\xf4\xa6\xea\xb8\x89\xdd\x14\xe9\x07\xa8\x98\xa18Q0\x04\xecG\xbc\xaf\x1a\xb9\xf9#\xc6\xa4\xe0\x93#\xf1D\xc5\xe6\x8b\xc1\x82\xad\xb2\x15\xa5\x8b\x08\x0f\xfb\xfb\x80>r\xfc+a\x1c4\xbd\xe1\xbe[c\x0c-R\x9a\xe4\xc2Y\x0c~\x82\x1e,\x06\xbf\xe1\xffx\xbfr\\E\xc8\x0f\x92):)\xbd\x1c:\xcf\xf6\\G%\x15B\xbb\xba\xeb:j\x11\xa9*Xy\xbf'\xa5\x1e\x15rS\x9d\x1a\x83N\xd3\x1aK\xfe\xe8@G\x98@\xd1<1\xf4\x14\x10w\x1d\x1e\x8aD\x8bg50\x15\xc3u2\x06\xe0\xce\xb1k\x1d5.w\xd3\xb0\xc5\xa8n\x9cL\xee\x8d|\xd9Nro_+\x9aV \xe9\x1c\xb3\x86\x1ao\xc8N\x06x\x84\xbb\x03\xdc@\xce\x95\x8a\x15\xb6i\x91 h\x9a\x92\xca\xa9\xea\x0f=N\xb4R\x83\xd2\x92\xbb\xf2Z\xb57\x91\xa8b\xd6\xd8\xf8\xed\x05UIFm\xb9 A4iI\x90\x0f2\x96\x8b\x99\xc5\xbaf\xa4\x9c\x9d\"\xed\xd5\xac\x18|\x01\xf6\xc1\xef\xf5\x9a\x19\xc0\xc4\x90\xb6C\xfd\x88\xec\xc9\x9c\x02\xb2\xbd\xd9\xeb\xf5\x0be\x19\xc3\x88\x96\xa9\x0e\xd4O\x82\x9cE\x92'q\xc8D\x12\x89\x8d\x0d\x94/b'lb\n\x8d23\x084W\x9a\xd2\xd6\xd3eG\x90.\xc6\x03\x1e}\xc2\xf1\x07\xd7m\xcf\x95\x98x\x8d{\xf7[!\xba\x19\x8b\xa3\x07`\xf1\xc3q\xab\xbe\xea\xc5\xb6\x03\x8b2O#\xdd\x82}\x05\xa2\x81\x08\xc0\x1b\xd9V@!A\xf8\xf5KmMtgu\\\xdcuc\x94\xc1\xf2P\x93\x1b\x1f\xb9\xce4\x8f\\P\x87\x9cG\x12\n\xc3\xb1~%e\xb8\xa1 P\x8c%L\x85\x9aT\x03\x12lg\xd4\xa2\x9dt:\x9c\xa9m\xf5!\xd5gd\xc7\x167[\xb6\xc8Z\x19i\xda\x15\xe5\x86\xd6\xb7\x1e\xd4:\xfb\x7f\xd3\xd8\x87xj\xe8i\xfb\x0bzb\xffo5\xf4'\xea\x180N\xe9B\xc4=\xc66\x94SQ\x8b\x91f\xbb\xb1\xea\x8d\\d\xb9\x1d\xc5\x14\x84\x83\xf7Y\x8a.1\xc7\x17 \x8d\xaf)\x06v\x88\x07\xbf\xd1\x8b_\xfc\xb4\xfa\xac\xfc>O#\xad\xbd\xde\xcc\xf0\x91\xf6z3\xa9^o\x86\xce\xb3-\xd7!M\xd7\xf9ZNX\x1ay\xb5\xca+\x19\xf7ui\x13\xf0> \xa5\x00\x94\xde\x88\x90*\xa4\x06\x16o\x00\x9e\x035&\x98\xe6J\xeeE\xd8G\xbe\x9c\xa2\xdd\xc5\x97(\x88\"M\xd2\x0cPEScl4\xc8\xa3\xd5cl\x1c$\x04\xa9\")\xb6\x8d>V/)\xb5\"\x00\xc2\xaf|\xca\xf8\\\x9e\xaf\xbf\x00'qy\"D\xdb\x9a\x90\x81\x0cv\xe9\x04\xd6\x06\xf3D\x1e\x1d\x9fcgH\xae\xfd%I\xa5n<\xff9HR\x12\xceI\x10\x85\x1a\xad\x05\xc6\x7fC\x83\x1ey\xda\x98\x00z-\xf2\x7f\xe5\x15\x1d\x83\x1a\xaeq\x8a\xf2\xe3\x89\xc8\xa5\xadu)|\xce\xad\xda\x8frU\x95.M\xb5\x06\x92\xfa\xdd\xb1\xe0\\\x94\xb6\x8b5\xec\xc3<\xf2x\x94\x1c\x1e\xff\xeb\x94\xde\xa6G\xd1\x9c:]\x9d\x8e\x92\x8b~\x81;\x888\xe5p\xd6\xba\xb0Q\xec\xe3]\x92\x98x)\x8d_\x93\x94\x8c\xaby2@J|m\x00\xb1\x1e\xccI\x8a\xb7\xbel*\x8b\x06\xfc\xd6\x12\xe1\xbc\x0f\xedf\xbb\x16A\x08\xf5\xdd/\xc21\xc4\x06~\x0cS\xb2\xf2\x9d\xd4\xb4D\x80\xfb\x8e\xc7\xb2b\xef\xc1>\x86\xcf\xa5<\xfe\x0c\xcf\x0e\x1a\xa2\x9e\x1c\x1f\x19\xe6\xd4\xea\xdch2\xbd2\x9c&5\x93J_o\xa8\xc5\xc5\xef\x9a!\x8fLA\xae\xda\x804\xd0\xfe\xdaN\x95,\xb0>\xc1,\x8f\xa8\x15\xf1\x88Zq-D!W\x07\xe1ej\xcaD\x06\x8cf\xbapR\x0c\x93\xaaa\xc0\xa2p\xe1/\xb3\x98\\p#\xdb\xfa\x12/i\xda\"\x0c\xa0\xa2\x0djB\xcd\x07\x9e\xff\x8d\xeb\xa87\xa13\xaccm\xd5\x89\xc1\xf2*\xcbm\xa2\x8aNc'\x1e|\x80\x1e\xc4\x83\x8f\x16i^\xa4\xf7j+\xe8\x10\xa1\x9e\x8b$G\xc1\xf6\x82/\x7f\x18\xa4\x9c\xd0\x84\x1e\x9a\xa0c5E]\x08\x93blF\x93\x17\xf1\x1aOH\xe0\xb8U\x11\xd6v H\xe5\xa8\xb6\x82\xee\x1a\x8f1\x99}\xf8\xee\xe3\x12\x91\xd3\x1e4,\xb3\x96\xe8;\"o\xddt\xcf\xcfM\xf7\xca\xe8xbA\xc44n\x8d\x84\x11#\x11\x987\xda\x88n\xbe\xd6\x92A*\x00\xc3\x01E\x93\"\xa1u\x1d\x17r\xb0\xeb\x84(\x9f6k\x04\xdb\x00T\x82\xce\xba\xde&b\xf4\xd9A\xa32\x99_\xc2\xe9*\x15\xbb5+J\x0c\x01?\x88\xe9\x92\x864f\x0c\xd8\xc7,L\xfd\x15\n\xdd\xc2\xa9gIS\xc5\x95\xe7\x88\xach\xe2\xc4\xee\xc0\x0f\xe7\xf4\xf6x\xc1\xda\xaf\xbe\xdcu\xe1eM\xe3\xe5\x83\x08c\xa7\xeb\xae\x809&{\xd1\x0d\xa8\xe0c\xcb\xd6\xb7{\xec\xd4\xc2\xb4\xec\xfa\xb7\x94\xc8\xf9\xc8;\xd5yx\x11}S\xf7~\xb1p\xc6\xeb%\xeb`\x8b\xf7\xb5\xeb\xae\xb6\xa5\x18u\xd6\xeel\xf4;\x0c\n\xa37tU\xaf\xf8`\xd5\xb1\x9c/v\xd95\xab^\xcb7\x91\xdd\x93\xbb\xd5E\x14\xc0D~\x19\xd7\xccVA\x9c5\xfe\xc0O9@\xd0\xbe\xf1?\xffS\xfe\xec\xd6\xeb\xa3\x8e\x92\x87}}[~\xa9T\xa6y3\xc17e\xb0\xc3S\xb2\x14\xef)%\x9a\xb7\xf0\x92*BX\x95\xce\x94zMOX\xf7\x99\x91\x15\x04\xc2z.\x04\xc8\xf0\xa9\xa8\xe9\xb9\xad8w\xc7\xd4\x0d\xecC\x80\xb9\xa6d\x93\x0c\xde\xee\xe0&&\x8c\x99?\xaf\x93))\x03t\x93,Y\xd3pN\xe7')\x89S\x0d\x0c@H\x04E\xcd\xbf\xfa4\x98\x1bj\xa2C\n\x8f\xa9\xe4\x87:\x90\x820\x06\xefz\xd1j\xcd\xf6\x92\xa9\xa5k\x9ePA\xfbl\xa5qC\xc4\xf2)\x995\xd1Bhb\xce\xf4\xc0Z\x16\xbbfI\xd3\x0fr\xe3\x1c/\xf4#\xbc\x83}X\xb2e^:K\xe7\xbd3\x9d\xb9\xbaKS\xf48\xb9C\xb3(\x14n\x85pw\x87I\xb3ej\x91;\xcd\x8blD\x17h\x9c\xad\xde\xf9\x1e\x96~\x95\x028;+M+\xb7\xa5\xfa\x17\x15\xeb\xed\x93>\x9cT\x8an\xfbp2M\x18\x88o1MW@\x90\xc6\xb3\xe5\xfcIb\xa4(\xbf\xf8\xa5\xcf\xd7mp6\xc3\x83\xd2\x19\xb2\x0fW8m\x8c'\xaeu+\xb5!j$n\xe8\xaf\x9cs\xf5\x0d{dh\xed\xde`\xa7\xf9\x04\"t\xca\xe2\x1e]\x0f\xb9'\xcbU\xcb\"\x9f\x0e\xe5\x8e]Jk\xfa%\xd0\"\xf7+\xc4\x8f\x8b*vuY\xd97 \xb2}\xb8\xc8O\xe3\x074\xd6\x9d\xf2\xd3\x18\xf2\x01Ur\x1e\x82\\\xe0+z\xd7\x9c\x8a\x04\x14R35\xa46\xa8\xf9\xaf\xa7\xd2\xa8\xc4\xba\xbe\xec\x94\xbe\xa6qB\xab\\\xb4\xfa\x91\xa3\x83f;>\x91\xd9@\xde\x1d\x19\x15\xd4\xeaG\xca\x06\xe9`\x1d\xadMZM\xf5\x83\x0c\xb5\x98fn\xd0\xc3\x91\x08\xd3h\x84\x1c\xb5\xb8\x91\x92^l\x94\x1f\xb3\xa5\x1c(\x02q\xde\xde\xd0\xd6\x9e\x96Hx|`l\x91\xdf\xf7\xe1\xb4D\xe8\xf4\xa0Q\x0e\x8c1\x9c\xeaW%\xa6 m\xb4\x02\x91\x1f\xccz\xc1\xedp\xe8\xb5b\x9a%\x14y\xf2gBCy\x81;8\x17?B\xf1L\x81'\xffM\x03\xba$\x18\xa5\x84'\x92\xc4\xd2\x15\x86 \x95\xd9\xc0\xba\xa2\x94\xc4K\xa5\xa54\xbe;\x0c\xd3\xd8\xa7\x89\xcc\x97\xec|p\xfb\xd0i\xb0h,\xa2\x9d\xb3uG\x91\x17\xbaiWxo\x88P\xdbCW\xe1N\xb8v\x86;Kux\xea\xb4\x9eL\n;\x12 \x86X\x1d\xe1[i :z\xf0'i\xb4n\xa1\\\x03i\x00\x95\xa3\x8f\x19\xb7\xa5\x0dU\x05H\xd3\xe1l XP?\xb2\xb8\xd8`*}\xd4\x93p\x98\xd0\x01\x1eJ\xf2\n\x86-\x82\xf9eU\xd3\x14_\x93zb\x020\x83\x821\"L\x8c<\xbc\xf5\xe8:\xc5\xa8\xb4\x0f\xc4J\x06\x9c|\xa0v\x00\x156\xdf\xcd\xb4*vL\xa9\xf6\xd5\x8f\xd4J\x0d\xc4\x96\x140\xecC&\xf0\x16m\xc4\xc5NA\xef\x11\xae\x04\xaf\xa3\xba\xc4s\x86\xcc\x1d\x8b_\x85y\xe4\x12\xc5\xfd:\x1aHg\x9d\x0d\x18=\x07\x1fU\x11\xcfacC\x1b\x17B\xfd\\\x8b\x1c\xffU\xac\xf2\x1b\xcc{@H\xb1\xa4\x15\xf2\x81D\xc08\x8a\xc4\x9e$\xac\xb7w\x91\x97\x13\xe8\xd8\xe9\xd2pn3\x1d\x97\xad\xc8W\xe1\xc5>\xe4d\xabi\xa2 &\x8b\xb9kD6\xf4>tQ\xc3\xf1.\xf2\xba\x96\xd3M\xfd\x04\xe5\xd7\x85J\x18\x1bhw,\xe1\x9dm\xd0f\xb4P\xa3\xcc/0=/\x1f\xb0\x02\xb7\xa2\x10\x1d\x10\x9a\xc7\x01\xda\x96\x8b\xb9\x94\xdaV\x8a\x1b\x1b\xfe\\\\z&\xdfs\x8a\x8d\x0d\x7f6i\x1et\x1f\xbc\xa3\x0d\xd4\xfc\x1b\"\xf7F\x1a\xdfA\x92\x92\x94b\xd6\xf4\x1b?\xbd\x8c\xb2T(\xc5\xa2X\xde\x07\xb4Yy\xf8n\x10\xb7\xd6\xb0\x98\xf9?\x84\x84\x93\x8b8[\xa7-l\xac\xe5G\xe15\xed\x94*\xcc)\x95\xf1Z@~r&\xb0B\xa9B\x03\xbf+?\\\xb9\xaa\xa1\x18\n+\x10W\xb6rny-\x96*.-U3VI\"m\x10\xe8\xd5\xcfEL\xc9\xd57]D@}&\xa6)\xc5\xc6\xc5y\x8f\xfa\x02\x99>\xac+}z\xf0\x16Q\x01\x0e\xc8\xd4%\xbe2el\xcc\x17\xac\x9c\x05\xdb\xe5a\xe2s\xd7\xd7\xfc`@-^#wA\xe4\x11K\xfb@\xc4a\x99\xf6\xb11\xc7\xc2=\x8a\xa3W\x1do\x1f\xae]a\x0e,GA\x1d\xf2 \x06N\xbe\xf6\x00\xa4\xff\x16\x1cVi\xc58<4\xcb\xc6\x1fLJ\xf3\xc7\xf6a\x0c\xe2\xea\xa3R\xd3\xc9Y7\xb9\x83\x04\xf3\xc2\xfe\xd6\x98s\xd1D\x19\xc0\xfctf=\x84Q\xbc\"A\xa9\x07y5\xed\xa8o\xa4n\x1f\x0c\x1e\x7fz\xa0/\xfc\xd0O\x1a\xfd\x13\xf2\xda\x05\xc7o'2iNd\xda\xf9\xd3k\x88L\xda\x82\xc8\x84\xea\x8e\x11\xdbKe\x9csL\x0c\x95\xad\x81\xc9\x89\x17)\x8d\x19e\xe9\xa3\xe3\xb8 h\xf0P\xb2\xdd\xca\xdbC~\xfe\xfd\xa0)\xa8\x92\x80d;\xa2\xcb\x8d\x84\xdb\xb2\xa4\xa0\xd9\xb5\xb1\xd8\xb5\xcd\xfd\x81\xa26\x8b\xed\xbb[\xfd|0\xd9d\xab\x1f\xfb\xb1\x0e\x05\xc10\xcb\x11\xf0\x85GG\x8d\x0b\xf2\x03&\xca\x07\x82\xef!iJW\xeb\xb4\xfb j*\xb5\x01x\xe32\xae\xea%\xad&\x82\xea\x0eR\x94\n\xf6\xe5\x91Woc\x8c7`\xe7\xecc\x9adAzDVt\x0c\x0d\x01-\x18]{\x17yc\x83m\"p\x85\x0e?\x9d\xb8\xe2A\xa1\xab9u,\xc4@\x03q\xac\x95VM\xc0J?sy\xf6\xbcA\xcd+q\x95\x9f\xf1\x8a\x9eI\x89\x0fs(\xf2\xe6\x1d\xea\x01Q\xcb\xa7\xe9D\xaa\x82[\xfb\x0e\x11Z\xe5S\x07\xef8\xa7:[f\xb1\xc8\xfe\xe0\xdc\x0f\xaf#\x8c\x02j\xb3\x15P?\xb9\xdd\x80U\x8b\x99\xb7f\x8a\x95(?\\s\xc8\xd6n\xae\x11\x08rm-\xf8 \x90 \xa6d~\x07q\x16\x86~\xb8\xb4\x89\x01E\xabZc\xf9jU\x95\x1e\xe5\x19\xc6\x0d\xd9\xf0\xe5GL\xf4\xadA9\x0e\xcd\x9a\x85\xb0\xe0\x00\"<\x96\x10O\xfd\xe7\x8d*Z\xc9\xf6\x85\xf9\x06m&\xef\xa4\xa9Q\x10\x0dg\xe8\x14B\x18\x064\xd3W4\x96m\xd32\xc8\xca\x08\xe3\xeb\"\xafns\x1f\xa0(\x85\x1a+\x7f\xa9x\x06\x12\x13\nZ\"\x97\xc7\x85Pjb\xc3B\x0d\xdb|\xfe\xe4\x92\xb9\x8a]E\xa3\xcd0+\x90x!q\x92m\xbc\xcb~\x9b\xde\x01\x9d\xa9j\xba@\x07_m\xf0v\xe2C/1\xb6\xa1BU\xc3\x01\x97O\x9d\x82o\xe5\xad6l\x18\xd8\x87\xb9\xbd\x8a\xd4\x17\xdd\xe4D\xa8\x19\xb1K\xdcq\xd2\x9a\x99\x10\xc0\x957 \x13\xb8\x841\xac\xfb \x8e\x8b\x87\"i\xe3u\xa6\xfa\x11I\xfd\xb0\xabvZ06\xc6\xb1\x18k\xe3\x0b_\xb3\x07T\\MrQ\xc3\xc9\xf1\xae\x90Y\xa4ZV\xd2\xad\xc4\x8eX\x06F\xbaV\xfa\x99-}\xd8\x07\xe2\xf6+\xc97M\xc7\xf0\x8d\xed\xc42;S4\xaeX\x8ai\xb5$z\x99\xd7\x89\xc4\xcb\xdc\xb3\x07\x87\xd1v\xa6\x8d\x11\x1c\xda\x0eQ,E\xc3\x08\xdb\x0e\xab\x15\xd0\x0f1\x9e\xa0\xe1\xe1\xad\xed\xe1\x89\xed\xe1+=0\xa6R\x01\x91c\x9d$=\xb3\xfc\xce\xcal\xd8&?\"hg;\xf1Le\x83\x05\x93\x84v\xb2\xadW\xb7j\xee\xaa\x9f\xf0\x95\xc5\x9a\xb4Nu\xd4\xd1\xa83\xb1\x19\x1a\xe4]\xf9\xad,\x8d\xe9\x8dt\xa7W \xda\xc0\xc3A\xc9\xb2\x90\x07\xbc\x8ey\x90\xbc\xa6\xd7@\xe1:n\x1c:\x0dg\x18a n\xc9{Hr\xd5\xd9\xdf\x177Fm:\x04\xe5\xa8\xc9\xda\x13a\x10\xd7\x11 \xbf@n\x1e!\x14pE\xcb=\x8dE`\xa0(E\x03L\x05\x8bV/]\x17&r\x1dr\xef\xa2` \x9e>\xc8\xb8\xa3\xfaI\x1d\xb9\x99\xa8X\xa2V\xaf~~\x88\xeb\xae\xfaI\x9d|\xd3>\xacC\x17\xc6u\x10|\xd5\xd4\x93\xdc$\x01C\xc9'-\x07\xd2j\xc8\xcd\n\x04\xe2d-x/\xb1w\xd2Z\xb0\xf8R\xad\xb6T\x08\x14J\x06\"K;\x87\xa0\x8f{z\xcc\xa8B\x9dv\xb5\"]\x07\xd6\xc8/<\xec\xa6\xd4\x0bL\xe5\xfd\xacF\x11U\xb0\xb9F\x99\x13or\xea&\x0e*\xb3\x92\xb6`\xac}L:/\xc74\x10\x80\xa9^\x1f\x17\xca\xd8\xc2PB\xcc\xd5\xd0e\xaev\xbc6\xd3\x84T\xc3:\xe5\x1d\x943\xd0\x9f^\xd2\\\xa1\x02\xf3\x88&\x10F)\xac\xe3\xe8\xda\x9fS \xf0\x18\xdf\x7f\x0c\xbcA\x93b\xc8\x86\x0b\x9aH}\xdaE\x8c\x90*\xc7}e%\xc5\xa85\xf4\xb9&H\x0bz,\xf1\xcf\x02\x80Hh\xc5\xebK\xac\x81\xa8\xbc\xeb\x89\xf4B\x90Tm\xe0\x95\x88\xe0\xed\x9dt\x8a4D\xe8\x9dfx}!\xe2\x99\xa7\x85B_\xa8\x9b\n\xee\x02\xcf\x95\xb4\xa4P\xb2\xdb\x19\xe8f\xc0\xb3\xcd\x8f\xcb\xef6\xa0@\xbe\xfc|\xd0\xe0s\x1c !\x88#\xc4\xd4W\xab\x9d{lwa\xd1o \xae\x1d\x1e\x03\x9d\x0egu\xf4\xa9\xaf\xc3\x88\x9b\x9ar\xa0\xc9\xcbd\xcc\xc72\x9a\xb9}\xd8T\x1f\xabz|\xa0\xdc\x1d>\xd7\xd2c\xd1\xd6\xcc\xad\x9b+\xa19]\xdan\xce\x1f\xecs\xa6\xea\xed\xd9\xfd\xbd\xf6\xfa,\xcdMR\xa4L \xbd:R\x8e\xbf\xa5F\xf6\xab\xd1\x94\x0d\x03;\xd5\x0f\xac2W\xd8\x87\xa9}]\xb8\xa9G}e08\xacd\x92\x8f9\x10\x8b\xc8N M\x9d\xea\xfd\xbei\xa4\xef\xf5#E\xaaj\xd3\x16\"|\xa7\xc4p\x07\x81\xb4]\xa1\x12|\x7f R\x9fom\x8fJ\xcf_\x1d\x7f<,?/eU\x1a\xbc>|s\xf0\xe9\xdd\xe9y\xb5\x9fQ\xa5\x1fY\xef\xcd\xa7w\xefJ\xf5\xb6wJ\xf5\x82\x88\xcc\xf1\xc2\x94}\xa9>8\x08\x82\xfc\xd9\x01\xe3 \x8a\xc7 Y\xd0w\xf2]\xf9CWA\xb6\xa1\xfcV\xab\xcd\xb3\xd5\x1a\xb95\xf6\xa5\xfa\xfek\xf9P\xfeP+\xfc\xf5\xe0\xfd\xbb\\q-`\xb0W\x9a\xdb\xfb\xb7Go\xdf\x1f\xbc\xb3-G[0Z \x98x\x84\xbb\xedv\xd9\xb7n\xe9\xd9\x9a\xc4\x18F\xd1w\xba\xf8\xb5\xfc\x14\x93\x19\xcb\xe7\xe2G\xb9\x06\x99\xcf_\x95<\xa5|\xa7[.\xeb~\x93M\xfc\xb4\xea\x06\x1d\x15\x00-\x95\x8b\xb4Z\xdb\xfaDq\x08\xbdRyV\x80\xacT\x9eh\x9cE\xad^\xa1\x01F\xbd-\x15y\x18\x07\xbaL\xaba\x1f\xb6\xcaE\x0c\x81\xb6\xcbE\xf3z[\x97\xf5\xb6\xae\xebm\xad`\x1f\x9eL\xcfn\x87\xc3\x8d\xb3\xdb\xe1\xd3\xb3\xdb\xe1\x8fg\xb7\xc3Wg\xb7\xc3\xc3\x8d\xb3\xdb\xd1\x9b\xb3\xdb\xbd7\x1bg\xb7O\xb7\xcfn\x9f\xeen\x9c\xdd>{s\x96\xbdy\xf3\xe6\x10\xff\x7f3\xbb\x9f\x9ee\xaf\x9f\xb2\x97\xb3\xd7?\xbey3s&\x1dV\xf2\x8a\x97\xb0\x1a\xee\xbd3\x19O\x7f/W\xbb\xff\xdd\xadT{R\x1e\xd6R\x0c\xeb\xe9\xceY\xb69\xdc|\x8a\xff?\xab\xd6\xba\xc3Z\xfd\xb3\xe9\xd9\xec\xec\x1fg\x9f\xab\x8f/\xd8\xe3\xdf\x9d\xc9\xb8s\xdf\xe9\xdcw\xa6d\xe3\xefg\x1b\xb3^\xc7\xfd\xf3\x13\xbf\\\xf3\xbc\xa89\xfd\xbdh\xcfu&\xe3\xff\x98\x0e7\x9e\x91\x8d\xc5\xec\x1f\x9b\x9f\xef\xf9\xf7\xbf\x9fm\xfc_\xcf\xcf\x9e\x9cM\xc6\xff\xf9h\xff\xacw\xf6\xe7\xfe\xf9\xd9\xa0\xf3?g?<>s\xce\\\xf6\xf6\xcc\xfd\xe1\xcfO|\xddYqc<+F\xc3\xc2\x8an\xb4\xc5\xbf+\xd4\xbc\xde\xd4\xa1\xb1\xa9gEK[\x9b-Z\xba}HK8\xbe\x87\x8e\xf5\xc4\xd8\xc3\xf6v\xd1\xd4\xb3\x91\xf2}K\xe9b\xb3\xf4c\xa7E\x87\x1a\xbd\xbaF\xc5,\xc7\xf0\x14^\xec\x0bgI\xf6mg\x0f\x13Zn\xb0\x07cx\xb6\xc7\xca0\xaa\xf8\xd6&\xdc\x0b\x9bF4a\x1c\x0d7\xd1\x9ca\x83U\xea1\xb0\x8cacd\x1d\x98F\xff]\x8c\x82Or\x02\xdd\xb3a\x97\xf7\x9c\x97\xfc\xff\xb0@\xadr\xc1JF\xa3]\xa5(\xc5J\xd5\x82Q\xbe\\\xac(\xe4EjK\xd7X4\xdcT\x8a\x16\xbc\xd6\xb6R\x14\xf3Z\xa3\xa2\xe8\xff\xcfJ\xb6\x94\xd7\x00\x0b\x8a\x97\x1ew\x1f\xc3\x18\xb6\x95i<\xc1\x11\xaa=\x9d\xb1\x92=e8\xff\xe7\x7fc\x9d\x1d\xa5\xe4\xff\xc6:\xeaL\x91*\xb0\xd2\xa7\xc3J\xe93V\xda\xedZ\x17\xe1\xc0\xb8\x08\xb8\xfe\xbb;;[;0\x01\xeet\x87y\x0b_]\x92\xf8U4\xc7\x9c\xa8c\xed\x83\x9d\x9d\xcdg\xbb\xd0\x03\x87!\x0eka\x17^\xbe\x84\x11\xe3uvv\xb76\x87\xe5G\x8f\x18\xbc\xb7\x14o\xd9\x82_\xcb\xed\xe4\x8e\x85\x9a\x043\xee9\x9b;\x8c5\xfb\xa0);\x054\x97;\x85\x17\xb0\xb9\xb3\xfb\x1cN{=\x17\x8e\xa7\xa73\xd8\x87+\xe7\xd4\x85 \x8c`\x0c\xc3>|(\nu\xc4\xe9\xbdV\xc1\xa9\\\x94Dx\xdf\xc7\xc3\x17\x0f\x16~@C\xb2\xa2\xa8,\x0b\xd7Y\x8aN\xb4Q\xe2\xa7huH\x07\x81\x1fR\xb5\x0c6D!:\xd0\x97\xe6^\x1f\xcb[\xedX8\xcf,\xc6i}\xff\x0f\xed\xfbt\x10\x85\xbf\x918\xf4\xc3%w\x8d\xce\x7f\x8a@\x85\xa8U\x12\xed\xeb\x16\x87\xad\xcbQMe\xc4\x18\xb7\x9a\xd1\x99V\xb9{]$\xa4\xab\xcb\x8e\"7\xf0>\xd0\xc15\x8d\x136\x8dG\x8f8$\xba\xf3l\x1d\xf8\x1eF\x1d\x84h\x01\xff\xc1\xba\x84\xb9\x1fS/\xf5\xaf\x91\xc7\xe2IC\xf2\xa4:\xf9\x9b\xe5\x9a@<\xc6`&@o\x89\x97\x06w\xc0d]\x99\x03\x12\xe3E\xb3A\xb0-\x85w\xe0O~w\xd8\xa17\xeb\xb9g\x03\xf9\xed\xcfO\x06\xf4\x96zN8\x1d\xce\xb8\x17\x1b\xef\xc8\x0f\x82\x8dE\x14\xaf\x98\xa4\"\x1a\x04L\xb0I\xa1>Z\xc6\x8e!\x03\xf96L\x9d\x18\xc3B\xe2^\xf1\xcb\xe5\x9b\xb2\x9c\xcf.*z\xcbB>\x13r\x11\x88\xf6%\xccD\x9f20\x1b\xe7?\xe5\xc3}\x081\x12%\x1dx\x97\xd4\xbbz\xe7\x87\xf4\xc7\x98\x92+\x0c{\xc1v\x90\xec\n\x0d\xdc7\x8b\xaf\x7f\x88^\x93l\xcd8Y:o\xe8\xb4\xb4\xba\xd5\xccb\x07?=\x0c]\xea\xb8\xb2iX\xed\xd3\x83\x9f,\x8b\x9d\xdeDE\xc2O\x06\x988\x07\x08\xf2\xc7\xb8\x0e\x17\x83\x94&\xa9\x13\xa3\xa8][\xda\x94,\x81'o\x01g\xe1\xc7I\x9a7\xe8J \x94\xc6\xc0zI\x84\xeef\x90\x92\xe5{\xb2\xc6\xcb[9\xe2\xc7\xe9%\x8d)\x9a\xbb\xc1:\xa6\xd7~\x94%\xc1\x1d\xcc\xa9\x17\x90\x98\xce!\xc9\x16\x0b\xff\x16\xa9b\xf71\xf4 \x86\x1e<\xee*\xc3x\xec\xf6\xe1\x9c\x0f92\x0fy\x1dS\xd6\x8c\x93P/\n\xe7-\xc6,\x07;\x8dg\xb6xr::\xfa\xd1b'\x89\xb7\x0cy>\xb5\xf2\xba\xa2f\x10^\xe8QA\x18\x93Ib+\xdcH\x11q\x8c\xd1\x81\xf1(\x89\xb8\x83\xad\x8fw\xbfB\xed\x06\x11\xbc\x00\x9f\xfd\xe9\xed\xc3\xc8\x15<\x83C\xb0\x8e'\x8e\xb4\x03\x06PW\xf0~/\xf6y|8\x82|\xcfh\xb4=\x1a\x8d\n`\xd3\xdb5\xf5\xd8\x9e\xb8&\x81?\x87\xbf\x9c\x1c\x1f\x15\x11\x0cuv\x8bhp\xb5\xe2\xab\x96)4\x84-E\x92\xc6\x94\xac\xd0\x16\x89\xf8a\x02a\x14n\xacc?\xe4[=o6\xd1\xb6+n=\xd8\xbc2\xd3\x9ai\x96\xecu\xb1d5\x87M\xbc\x7f\xe1\xeb\xd5\x87\xa0\xdc'B8\x1e\xf8 \x17\xfd\x9cP\xc1@\xa1\xaaY\xd1xIaE\xd6k?\\&\xcf\x11\xdb\xc4\xdd\xd6\x1c\x92(\x8b=*.9\xd8&P\xc9\x1aC\xc3\x8c\xaf\x1e\x13\x16\x1d\xc58\xf6\x8a\xdea\xa2\xb7|A3x\x01\x01\xfb\xc3\x17\x14\x9dd\xa6\xd9,\xdf{)\xda&`r!\x1e\x95 \x9c\x12\xb6\xeb\xf9\x0fU#\xae\x03\xcf;\x05\xa3\xd5t\xaa:P\x05}\xf0\xeax\xcd\xb0\x90\xb3MN\xa4\x9e2y\xc4\x11\xf8\x07\xe6\x83N\xc9r|GV\xc1 \x8a\x97\xfd\xcd\xe1ps\x8c\xf0\x13\xa6\xf3u4gm\xf3\xf4\xd2~\xc2\x99\"\xdf\x96\x958\xe0\xe0\xf4\xf0BL\xc2.\x80\x17\xe0\xb1?\x1cv\x12\x17\xfci0\xd3\x9b\xe4!\xf6\xe6\xd5\xeau\xf09\x1d\xfc\x91\xf0\xbb\x95$\x8f\x82\xcc T\xa7X\x13^\xe0p\xbe\x08\xd8\x1e\xc3\x0c_5\xd6i\x1f2\xfe\xa4`\xb0\xca|\x01\x9dK\x14\x83+z\x87!M\xd2i\x84\x17\x7f\xf9\xadM8\x8dfZ\x01(\xb5.\xfe\xa7V\xb2\x94\x102D\x8aMN\xa3\x14JR\x8c\x1c\xf32\x15?{=&Vl d\x98\x80\xa3>\xea\xe7\xa2\xa6\xb5E\xce\xcb\x15\xaf1\x1e\x9d\x83\x87\x00\x02\x16\x9d\x9e\xd8\xf6\x92\x84\x8aSx|\xd6\xc3\xe4C\ng\x8a\x13\x90\x8dY!\xf37\xd3\xd9]J\xc69\x94\x19\xfflSx.\xb2~GZchqyr\xe8D\xees\xd7\xd4Z\xaf\xa7\xb6\xa7\xdd)\xb8\xdb\xb6\xb8he\x08\xf0?\x8f,\x979mz\xd6\xbe\xfc\x19n.}\xc62\x8c\x86\x05#7\xda*\xbe\x8bb\xc3\xb8;7x\x14\xe12\xd6k t>a\xf2\x90f@\xf7!fx\xc5\xd7\xfbm8\xe7\xe6\xcd\xc3\xe7R\x90e\x0b\xa0>d\x95\x1f<\xed\xcf\xba]\xb6!8\xf4b\xba1G\\e$/\xf8c\xcel\xce\xe9\xc2\xf7|V\xec\xe3S\xe4\xfe\x91k\xb3b\xe5\x1b\xc3~\xed\x8bD\xb3r\xc8ZR\xd0q\xb6wpl\xa6\x8d,2\xe7n\xefr[\x01\x0c\xfd$\x84\x96z]\xe81\x82\xdaTe\x93\x13\xc1\x90m\xc5\xad\xbe\x80MC\xff\x9d['u\x1bd\xc8\xbfke\xc0QNjTf\x81\xeb.R\xcc\xda\xcfc\xce\x15\xcf\xe2AL\xd7\x94\xa4N\xf7\x0c\xcdd`\xa3\x94(K\xd7\xf5\x8f\xda\xae\xafE\\A\x89Q)\xd1X\xe2\xf9\xdck2\xf4.\xaby\xb3A\xa8\xa5u\x99Q2M\xae\x11\xeetQ\x08\x95\xbcM1=\xfe\x831\xb8\xf2;;,\x88\x90 \xda\x11+lk\x9b\x93\x13\xfc~\xebX_Dtp5\x97\xbe\x92\xb9\xed\x0c\xfbP\xa6\xffHbY\xf1\xc6\xc8\xad\xef\x96}\x06c\x99\xbb*\x0b\x82v\xa3\xafu\x9f{.\xf0\x0d\xc2O\xdf\xdf\x04q_\xf0<\x1e\x1d\xcc\xce\xc2\xbb\x92\xc8\xe1\x96\xc7\xd7\xa6\xf3~q\xd8#-\xc8\x8f{1\xa5\x97\"^\x8c\x00\xb0+\xce\xb1\x0b2W\x89\x00\x93Z\x08$\xf4o\x19\x0d=\n4Lcm\x94\x80|b\x15\"\x93ji\xa9$\x01\x9dL\xe0\x08\x13\x9c\xd0W'\xc7\x1dd'\xe8\xe0\xca\x0f\xd1\xaaG\x8e\xa0\xdb/6\xd3>\xe3\x0c\x9b\x18\xca_\xcd4*g1\xf95\xbev\x07T1\x9dMq\x8b\x9f&N\xf3\x11P\xd8\x0f\xe8\xdaQ6\x0c\x9b\xbfI\x03C\x84X\xc9\xafv\x18U\xde\x15\x1cP\x9b\xd3\x82\xf1@\xc8\xcfw\xcc\xdcA\xe5\x851lq.)b\xef\x12%\x01g\xb7\xd3\xe9\xb6o\x85\xbf\xd1\xedC\x99\xd11\x98<\x1b\xd9\x816\xdd\xd5^\xcc\xd9\x00\x85\x0b\xd8\xdd4\x1e\xfd\n\xe5(lF\xd8\xecc\x9d \\\xdaem\x86W\xb0\x89Y\x98K\xb04\x9cK\x9d\x80\x10Do\xfc\xf4\xd2\x0f\x81\xc05\x8d/H\xea\xaf\xd8\xcaW\x15<\xa6p \x82sS\xe6\xdb\xb9\xe5\\\\\xbe\x9al\xaf\x11\x98H \x98,\xa5\xceC\x08\x90B\x10\x06z\xeb\x05d\xc5\x11pE\xe2\xab\xa4\x9b\xa7k\xae\xc0\x82\x1dP%\xf1\xa1\x87\xc9\xed\x84bG\x95QCR\xd1\xe9T\xfaL2\xef\xb2$r\xcb\xcc\xe5U\xf4\xe1\xa4\xbd\x1d\xdc\xeb\x0b\xdd\xbc\x9ew\xb9R\xaa\xd0\x15\x18!\xb5\x08\xa2\x1bF.\xd9v\x8d\xe2\xd2\xf8\xcb\xab\xa6#\x7fx\x90u\xce\xf5\xfd1x5\xc0h\x8c\xf6\x1b\xb1\xcb\x03KH\"\x1a\xc3\xb8\xae\x06\x0b]\xa5F\xaep\ng\xa8\xe6\x1a\xb3]*N\x89\xa2\x16+\x93Ou\x8f\xeb\xf2\xb3\xac\xcf\xb5mY\x98k\xd6\x94UG\xcdZ\x88\x9a\xb5\xc7\x98\xda\xdeJ\xbc\x7f6\x13o\x0dY~\xca\xc9r\xf8\x15d\xd9\xcc\xc8\xe8Is\x08\xa2\x86J\x9e\x0d\x03(af\x15\xab\xe5\xc6\x0d\xc5\xc6\xe5\xa2f\xe7\xc4 \xd9\x0en\xd3\xa2\xf6\x84U\xb6M\xae\x03)\xf6cy\na4\xa7\xb0\xca\x92\x02\xdfH\n\x01%I\x8a\xaa{E\xcbV:\xa6\xed\xbb\xa9a\x81\x7fS\xb4a\x9as\x01\xddqQ\x1b\xb6\xea\xc3\xb2\x0fw}\xb8\xe8\xc3y\x1f\xae\xf8e\x94\xe6\xd0~o8\xcc\xff0\x1c\xe6\xcab\x07~\x92\xd2\x90\xe6\xb2\x12\xff\xe5t\xa35\x0d1\xbfx?\xc7~~}\xa3@A\x16\x08~E\xfe\xcc9\x15^\x80jO\xd8Gc\x88u\xc1\x97-\xf8W\x11q\xad\xca\x88:\xefs~\xb5\xcc\xbe\xc1\x84\x03\x01\xd3_\xa9B\xa6\x90:\xf0\xba\xae\xfa\xf0\x85P\x84\x9d\xa2\xf1\xa5\x8b\x17\x1e\xec\x85\xd3\xfa\x19*N\x14\xe4\xa0\xee\xefq3>w\xcb\xc3\x9b\x14\xa3[q~\xec\xbb\x0c\x12\xc6\xd8\xbcn\xfdV \x832\xbfg\x83\xf4\xf3\x1b\x9cS\xf6`-6\x15\x93\xfa\xce1\"w\x0et/'i\x98\n\x80\x1d+}\xb8*\x1f5\xa5{\xc4\x1cR0\x01\xde+\xca^W\x08\x9c\x87\xdc\xb1\xf4\x0b%ob\x96\xce@X\xee\x98%4\xf6YXBr\xcf-\xcf.%Nj\x9f^[\x9f\xae\xacO\x97\x86\x0d\x08\xc2\x8eF\x97\xa7\xf2\x0b\xe4\xc7\x85PY\xb7\x93\x1f3\xa3\xe7\xbf\xf4Vn\x16'\xfbB`\xe6B\x1b\xa9\xf0\xb4\xbb\\(@\x81f\xe7\xa9\xf8~\x7f\xcfhyl\xb5\x84F\xad\x13\xd2\xc1\xb0\x0f^.\x02\x1auP\xea{\x8a\x80\xd7\xe8F\x880n\x03\xb1C'c\xfb\xdcP\xb5\x81\xbfR?l\x84;\xdc\xde\"s\xe1\xd6\xd4y\x85S\xce9F\xc2X\xf8\x94&k\xe2)\xa7\x8f\xaa[\x05td@\x0e\xfa\x8a\xdemp\xd3\xea\x84\xae \xf7\xf0\xc8\xd9\xe9\x8b \xf2\xae\xa4\xd6\x9a\x1d_(l9x\xd7\xb0\xe8\xc3\xbc\x0f\x97}\xb8\xe6w\x05n\x1f\xf7\xc6\xb5\xa0\xd2\xa2\xe8N\x109\x81\xdc\xc8|\xb2\xbf\x97\xf9\xfe\xc57$\xc1\xb7\xc3\xa5e\xf2+\xa6\x04\x88\x97vF\xe9\xba\x91Q2\xe5'a\x80\x17\xe6\xa0\xce\xba\x19\x17\xf8\x9d\xd8\xb3\xad\xbe\xd0\x83sM\xac.P\xbd\x85\xf2\xb1>G\x9b\x9caX\x1beQ\xf9a\x1d\x8e6wD\x8fC\xde\xe3?\xda8\xf4|\x01[\x15\xbb}0\x80\xa1|\xf2\x0b\xfc_[\x19\xab|\xab\xb1\xbd\xda\x06\xbc\xe2\xbe\xb0.\xbe\xf2\x9b4\x8e\xbb\x97%\xdc\xbdVp\x97\xd1\xdb\x1c\x7falR\x1b\xc7\xe6\xc3d^\xf0\x1f\x9c>\x82\x17\xadV\x04.hzC\xa9P\xf8xQ\x10P.\xc0R\xeeD\xc8H\xa3\xc7\xb6\x95H~\xc9\xc5=\x1f\xef\xd99\x9a\x88\x13a\x0dm//@F*%\xf6\xeb\x8a\xd4\xcdU\x0e\xe5\xeb\x84@\xb9N\xf0\n>%Q(h\xa9\x19\xe3\xc2\x97\x05z\x02\xf9\xe5H!\\ \x8ew\x8d\xe4Xj\x9b\xdb\xe0Qe\x04\xba\xb1/\xca$\x9f\xad1\xd2\xb8\x18\xe9\xbc\x874d\xc1]\x81'\x10\xf3{\x13\xac\xc0\x17A\xa9\xc3*\x89\nI\xb5ga\x1e\xde\nI'\xe0\xcc\x1f0G\xd6-\xd6\x1f\xb5\xd8\xb3\x0fQ\x13W\x90\xb1\xaasd-\x9d\xb3\xd1\xa2\xee\x83 \xd9<\xfdn[R]\x15T\xe7f!\xd5$\xf0y\x96g\x0b\x0c\x8a\xab}\xb4\x86Z\xfe9\xf9\xd1\xe9\x01 \xa7\xa9b\x11I\xf3\"\xba\x82\x87\x7f0\xe1\x16\xb7\x08\xa4\x15\xddntP\x04I\xa6\x95\xab.\x8f\x04$.S\xacnW\x12\\b\xf0deC\xdb\xde\xb2N\xbf.h\x89\x1bU\xe22\xfc\xdcg\xe4k\x82+-\x1a\"\xc8\x7f\x8d1\x80\x17\xc7K~=\xcd\x99\x1b\xef2Z!w\xb3B\x86\x92q-\xfe\xc2\xd7[\xe1A\xb3\xd8\x83b\x80\x83\xc4\x83\xbbI\xa0\xbc\xc8\x93ne\xb9\xb3D&\x9d%6F\xbfF\xf1`\xdf\x18\x11\xbe\x8e5\x0c^\x87\x0e1\xea\x16\xac\xe65m0D?\x0ey\xaf\x86]\x9b\xf9\xfe-\x89Y\xc6!X\xc7\x07_3FP\xc7\xd9\xb9q\x88r\xcf\xad\x19\x90aC*\x1b\xce0P\xc5\x1a\xa8j\xe4\xd37\x8d\xbe\x9d\xf2\xc4\xe9x5Y\xe9\x05;\xe4\x1e=\x92\xd6CDc=\xd4\x06b\xe6%\xebxP5{x \x0bdC\x169{\xc1\x1f\xb8}\xb8A\xd4[\xf7z_\xbc\xd9\xeb\xb3\xb3\xe3C\x82\xf3\xbe\xae\x98\xd3TLf\x02\xf4A\xe9\xc1\x1a\xc6\x8c\xb5\x1e\x8b\xb70\xc4\x88\xcc\xf1\xa8\xd8\xe2\x9c\x85M)\x0f\xecA\xed\xcd\xaa\x0fa\x11=\x01\xb6Q\x18\xc7\xb0\xca\xd9\xb8\x96\x83\xe7Zo\xf9\xe6\xc8\xfa\xe6Z\xf0\x8ccA\xed\xd60\xd1M\x17\x90\xee\xd8\xdaix^\x1e!\xb7\x16\xee\x0c%\xe9\xea\x8b\x83\xbbj\xfe\x05\xd5M\xf8\xdc\xfd\n\\e\x9f\x8fB_\xaaj`;\xa3\xb6\xa4\xd3(@W\x8ek\xc9A=P\xbc\xd53'[\xcf\xbe\xfez\x12\xdar\x0bUi!\xc6\xec\xbd\xfb\x9a\x0b\xc76\xe3\xb1\xb0\x1c[\xdc\xa0\xdf\x9a\xf2\x82\xd5\xfb(8\xf6\xd2\x821\xee\xbe\x01,e\x9e\xa5\x00\x8cE\x17\x18\x97\xe6Y\x85D\x19\n\x863\x0e\xa9\xd7\x8d\x83\xb7\xe6\xf9\xd0#1b4\xf6\xe3\xb2\xc3H\x88_u\xf0\xf2}\x94Kt\xfb\xfb\xfb%\xc3\xdfG\x8f\xb8\xf1\xe4\xc4\xca\xefK\x1f\x9f\x82\xe3O\xfcp\x19P\xf8[\x16\xb1\xaab\xedEBJ\xf3,5\x1b\xe9!b\x86\xbe\xd3o\xb1ST\x01\xc3\xb0k\xb69z\xb4P\xd3}\xfb]\x13\xa29\x85v\xd7\xb4\x18\x8fU3\"|W\xb3|\xd0Z\x8a6t\xabC2!>\xaa\xb16e\x9b-\xf6\xa2\xae\xab\x9bvW4\xae\x8a\xfd\xe6}\x98\xeb53\xee/\xca\x90\xfex\x9a\xcd\xdc\xd2\x01\xf3\x01}G\xd4I\xb6h\x11%\x9c\xd1\xa60\x83\xc3`\x93l/m\xa2+\xf1^.\xcal\xc3\x18\x9e\xee\xe4?\x99\xd80t\xe1%\xfb\xaf\xc5]Y\xc4/\xb4}n\xb4\x1d\xb1\xf7\x9eC\xb4\xb1\xe1b\xef\xaf\xda\xc2\x8a )0\xc1f\x1c\x1f^\xbc\x80m\x17z@r\x91*\xdf\x81\x97\xf4\x96\xcc\xa9\xe7\xafH`wiR?*(\x0f\x1c\xbf\x82/f\xbe\x85\xc3RR\x81\xab0\xba \x81&\x1eY\xd3\xdc\xd8\xd3\xd6u}g\xd8)iVPR\xbe\xf5M\x94\xb4\xde\xf0w\xa2\xa4\xf3(\xbbhCI+\x83i\xc1K<\x84\xb4\xeaG\xa1%\xad\x8a\x1aG\xc95o\x0e\xbd\xc6!\xad\xa7\xaa\xdb\\\x87\xd1|\xf1\xdd\x86\xaa\x1a\x1aie\xee\xc4M\xe0n\x85\xf5[\xe7\xc4\x89\x19\xd9l\xd3b}0\x0f2y\n|\x92<\xc8\xe2Ic\xfc\xd8/\x9b:)*\xf5J8\x16\xd5\x10\xf2q\x16\xe6j\x80\xb9\x18G\xc5(N9\x93T5}8\xab\xde]\xd5\xd9U\x86&_j\x8a\x82ZWO\xea[\xd9IiV\xce\x99/\xba\x19z\xdd:^3b1\x88\x9c8\x1ew\xfb\xe4D\x1a\x85\xde\xad\xa7\xc5\xf7\xedM\xa5|\xab\xf8.\x15}\xf8cW\xad\xf4L\xf9\xae\xd4\xd9\xdaS\xea+\xe5\xcfx\xa8\x07\xcf\x8a\xe5x\xe2\xec*\xdd\x0b\xb5\x99\xc7u\xf4\xb7\xcd\xdbHHg\xf7\xf7\xdc\xbe\x8f\xa1y\x8b\x8d\xd5\xcc\xaeD\xe8K^fw\x85\xd5\xba\xd8`\x9e\x95\x0b\x11\xd6\x19\xd6Dp|A\xbfh\x8a\x16\xe1YI\xaf\xb8\xb5\xd3v\x10\xf6\x01\xa0\xafL\x8b>\x9b\xb4\x12\x8dGM1G\xafY\xfb\xc8\xda\xbc\xc1\x8a\xcdV\x10Y\xaef\x91\xd74\x8a\xf1Y\x90\x17p\x95\x89rrn\x8cjw\xd4\xfb\xf6\x04o\xf2C\x14\xf9\xfd\x8b\xb5U\xe2#S:X+\xda\x839\xab\xc0\xe7\xfe\x1f\xdcx\x80\xd1'u%\xc4\xfduI\xe7\x16|{=\x8e\xbe\x14/\xc08/\xc3\xe9gg$y\x191\xde\x0d\xc8\\\xdb\xe6t\xfbp((\x9fS\xae!\x0c\xcd\x0c\xcb\xd1\xe0\xf2`:\x11\xabC\xedtr2\xc2]\x82\x05\x99Y\x94\xe8\xcb\xba\xaeQ\xe1\xacH_ZQr\xf2\xf7\x87@\xa1\xdc\xd1:\xf7f\xc9\x8d\x0d\xba\x93.\xea\xa6,u\x95\x12q\xb3[\xd8\x81\x15gur\x19e\xc1\x1cmu.\xc95\x05\x12\xdeI\xcbk\xbc\x84\x95\xfe\xde\xad\xaf\xbb\xf3{\xc5Buv\x9a\xcf\n\x8d<\x85\x8dg\xa5i1\xean\xa7[\x14\xe8\x9d\xcd\xba\x93n1S\xab&y\xc9ugw|\xed\x85\x11\xd2\xe9\xdd:OZ\xf7\x1c\x96\xf0\x02\xee\xd8\x1f\xf4\x1f\xb7\xd2\x1c\xe7\xa2\xde\xcet9s\x072\xe0\xbb2u;\x9dPp\xe2b\x90'lW]\xd3\xe4:_\xf0\x1b\xe6/\\\x82o\xbb\x7f\x05\xb1/\xb1t\xe7\xb6`T\x0b\x86N\x19\x13\xbfw\x16\xc7\xdb\x91\xf0\xf0;\x9a\x863\xa9cc\xf4\xf4\x0f\xa1q\xe0\xf44W\x82\x15hZ\xd2<\xfc\xc9\xdcy\x99\x1e\x0c\x15\xd1H\xec\xf7\xc2=\xdfN(\xdaV\xe4\xf1\x1c\xdaW\xdet\xcb\x11]D\x84\x07u\xdc\x0c D\xb3W\x13T\xd0\xadH\\\x8b\xdb\xf2[\xc1\xd3\x8bi\xa2\x9d\xc6Z1N+\x03\xa6N\xa4\x1f=\x82%w\xf0,\xaf\xbd_^{\xc8Cq\x84Q\xb8qp\xf2\xea\xed[%\x9eL\x02$\xa6\xe0\x87)\x8d\xd71E\xc7\x87\x04\xc5\xad<\xe8\x9c\\\xda\xa4\x166\xa0\x85<;\x81\xed\xddf \xbb\x82\x15h\x80\xb0RA\xf1\xa4\xdeP\xa9d]\x1f\x1a\xc5\xa8\x0b\x15\xe8Yxp\x94\xd6\xc3z\x18\xff\xd5\xd1Fa,bAQqv\xa0\xcc\xc3\xce\xc8\xa1\xe4\x17\xf2\xb8v2d\x0c-\x03\xa0\x98\x02\x82@\xc4\x92\xb1Wrhn^\xd0\x87\xdd\x9d\xcd=\x11+U}i(k\xb2r\x8e\x15#\xb7J\xfb\xaeE\xde\xe9\x90\xde4\xdf\xaca\xe6 \\B\xc0DL\xf8[F\xcfds/~\x08\x96G\xd4Id\\\xf6T~\xbd\xbfg27>,\x02Y\xb2\xe7\xc5\xafr\x13\x9c\x13\xc1*\xe2\xeb\xfd=W\xeb\xb3\xa7\x18\xa0\x8a=\x93\x91\xaa\xf2'9\xbb\x86o\xca\x1f\xe5\xb6KB\x8cL\xc2\xcd\x07\x8a\x81\xc0\xfd\x80\xce\xdf\x8a:2\x97 \xe7\xdf\x0d\x95O\xf9\xd3|\xe8\xb8v\x052\x88rE\x171\xccG\x8b\xea\x08\xf5\xa7\xd4H\xa8e\xaa!\x10O\xf7,\xf7'\xf2\x17eB\xcb\x97S\xc3\x04\x86b-\x11\x93\x86\xdd\xaev\xe5\x97s\x93t\xf2\xdc$EZ\x12_3#%$V\x11\x82-\x86\x17\x10\xb1?<\x04[\xea\xf8\xd3xf\xa7-?i7\x9c\xdc\x99\x7f\xd5\xad\x1f\x1b\xb1p\xe8\x96\xd9P4\xfb\x95\xd5\x1a\x89%\x95\xb5$X\xa7C\x8dOA\x91\xc9!r\x8a\x8b\xc3\xfc\x86>\xa7\xa0~\xa8P\xd7>\\d),\xa2\x8c\x9drQL\x1f\x94\xc9\xa1He\xf0K\xbf\x9e\xfa\xe0\xa7\xbe1kA\xd3-D\x8b5E\x94\x89\x07\xf46\xa5\xe1\xdc\xa9\x83\x8fo\xea1\x90\xf2|Xg\x95\xe5\x90\xc8\xf7\x85\x8d\xfdI\xf9\xa9M\xe3`\xa5\xccb6?}\xe9l\xea\xf1\x81\xbf>c\x81.\x98h\xe4\x94B/V\xa7\x81tL\x1c$\xf2l\xb9\xc8\x16\x0bN\xba\xeb$3,\x93\xccX\xfc\xf4\xa2 [\x85\xa5@\xa7\x05\xde))\xd8\x07K\x9a\x9e\x84\xfezM\xd3&\x00\xd7\xcc\xd5\xeb{\xb1\xa3\x0c\xd7U\x95\x06:\xd9\x1bD\x00\xf8m\x85c\xd8\xdb\x11\x11p\xc4\xadKi\xb6\xc2:\x80\x1d\xe7\x1b|?w\xcf\x86g\xf1Y\xf8\x7f\xfe\xb7\x9aU\xa0;\xf0\xc39\xbd=^8\xcah\x90\x8a\x1f\xa4N\xc4\xef/\x0c!\xab\"\xd8@2^\x06\xf2\x06\xf6\x9b\xc2\x13\xd8\xe4\x9c\x87^X\xc3q\xc3`0\x00\x1c|o\x1fv\xf4RJ\x1bw3\x04\x91/ A\xea\x90 \xf0B\xc5\x0d\x85\xbd\xfab\xd0\x10#X\x1c\"\xc8\xf8F\x052-\xa0\xe2\xabP!\x0c\xbe_\x01\x15\x81Q\x99\x84\x87\x98\x00\xe7\xea\"\xee\x8aX\x98R\x02\xaa\xa1\x84\xe4\x95\xa1\x01x\x8f\x07\xcc\xefUkAO\xb3\xe6=\xe5\xbc\xe8A\xf7\xf7\xaeJ\xa0\xd4=\x94F\x9c\xfb\xb5\xe6\xe6UB\xf6u\xbb\xda3\xbe\xd8\xfa\x8caE\x0e\xe2\xb1\x1fr\xe1\xb1x\x86\xd1\x92\x1f\xe3U9\xe3XH\xca%\x186)\xa7\xa0\x04(\xd7\xf5\xd8\xdc\x04%(\x9e\x8b\x02~\x05\x82;\x10\x85r|VP\x03G\xa8\xa8x/c\x0e5\xd4]j\xc9tNi\xbe\x92h\x8ev\x953Em\x9d\x9d\xc6\xb1\xa3 \x87\x93\xa4q\xb7_\x81\xf5\x95\x1f\xce\xc7\xc5}n\xe9Y\xae\x90\x1d7\x98w\xd4t\x9e\x98D\xa2\x94\x8b\x00\xca\x07\xbb\xfb/\x82\x00\xfd\x9b\x11\x02\xb9c\xde\xb7\x85A\x95\xb9\xfe\x97\xc3`E\xd6&\x18\xe4\x8e\xb6\xdf\x16\x04\x15\xd7\xd0\x7f=\x08\xd8\x08\x1f\xb4\x13\xc4\xedA\x13\x00|\x19\xbe\x07Ek\xabm\xf0u\x9e\x8cR\xc8\x01&h\xca\x98\x9d\x8f\x1eA\xf7\x7f\xc4\xcd\x1d\xf2\x02E\xb9\xd3\xc5 \x15\xcf\xbaG\xd5\xdf\x9f\xde\xbd\x13\xbf+\xbcv\xf3R7\xac\xb4\xad\xb9uL1\x10Y#\xe0T\xcc\xc1Q\xdaZ\x8d\xe9:\xa6 \x0d\xd3\xb1\xa6%\x8f\x84Q\xe8{$h\x98\x01\x14\xbdv\xffG\x93J\xb3~5\x12D74\xf6HB\x1f\xd02\xaeK\x9b\xc6\xb3\xf5\xfa\xc1\x8d\xe3\xa2\xb6i\xdc#+\x1a<\xb4q\xfd\xc8m\xeb2\xa7\x0b\x92\x05\xe9Iz\x17\xd01tsxu\xff\xe5\xfb\xfd\"\x8a\xfe\xa9\xfb]c?\xd5z\xbf\x97\xf6u\x1agT\xdd\xc7\xa7\xd5\xdf\x1f?\x1d\xca}\xcd\nv\xd4\x97\x17$HJ\xb5\xdf\xd4\n\x0e\xde\x9d\x1c~)]\xb0m\xe4\x87\x0c\xfc[\x12\x90\xeeT\xa4\x13\xf81\x8a\x02J\xc2\x19\xef\xa3\x96\x9cN\xb2\xa12\x03\xed\x17\x93\x1b\x1dQ0&\xc8\x95\xf6\xa00\x91\x00\x1a\x83X\xa56\xdbXG#Z\xf5\xc5\x81=\x96\xeb\xdd\xa6/\x1d\xc9h\xd7\x97\x9c\xd7\x1b\xc3\xbc\xfe\x1d(\x88)C\xe2\xee\x03\x93\x9c\xd6\xb2\xa7\xed\x14\x03\xd54D\xda7\xb4\xa74$\xbfUI]\xa4#u~\x98\xfe;P:\xae\xb4Q5\xd8Z\xcc\x89\xccn\xf5\xba\xa8\xde \x95'q\xa3ylw\x83\x1bB\xf1[\xd4i4C\x19\xad\xdb\x13y\xdesY\x8eN{\xbdh\xe6\xf6\xa1;\x14\x99\xfe\x8d\xe29j=z\x82!\x8b\x1b=\xbfp\x14\x17\xbcQ\xb5+S\xfb\x90\xbby\xf4z\xa4\x9fb\xe6\xb7\x959\x8ev\xddA\x1a}b\x02\xe9+\x92PG@\xa2\xb1\x9a\x0526\x1c\xab\xc8\x85b*\x15I&aO\x0f\x02\x9f$4\xb1\xe1\xe2t\xb3\x0f\xdd\x0b?\xecjR \xe4\x98>\xedC7\xf2R]\x95\x1c\x8e\xd3\xd1\x10\x13Uy\xbaZ%\x88OG\xbb}\xe8^\xd2\xdb\xee\xf7\xbd\x0b0\x8b\xb5\xe5b_\x08\x90\x1f\xe9\xf2\xf0v\xedt\x7fw&\xe3\xe9Fo6q&\xe3\xe1\xfdt\xb4\xf1l\xc6\x8e\xd8\xf3\xd9\x0f\xae3\x19\x9f\x9d\x0d\xe4/VaJ\x0fgXY\xa4\xc4\x9d\xdc\xe7\x15z\xda\xc7\xc5/\xd1\x8c3\x19\x97\x0f\xf2\xa2\x07^\xf9\xecl\xe0L\xc6~\xb8\xb8\x7f\xcb\xfe\x1d\xbdq\xefyQH\xc2\xfb#rt\x7ftp\xe4\xba\x7fV-\xef1.?&\xedU:\xa7O\xcczB\xad\xf0\xbc\x08\"\xf2]\xc4gU\xbf\xcdoF\x18\xa5u:\xbe\xe0`\\\x95\xf9\xa1S\xd5zo\xf6\xcdy\x1am@\x189B\xd8\x07\xc9G\x08\x03\xe4\x1a;2H\xa3w\xd1\x8d\xdc\xd2\x8c\x97\x80 ;\xc8\xc7 b\x00Og}\xe8\xf66\x94+tdX^\x8a\x13\x86\xdf\xa1\x16\xccH\x1fX\xcdE\xc1{\x08\x0b$\x98\x88\xc3l\xf0\xe1\xf8\xe4\xed\xe9\xdb_\x0f\xcf\xdf\x1e\xbdy{\xf4\xf6\xf4\xaf0\x96\x8f\x8e\x0e\x7f:\xa8>\xea\x0eB\x12\x16\xcd\x1d\x91#\x18CZf1\x04is\xd2/\xe33\xa22\x9f\xf1\x86!\x8e\x95\xd3\x10\xb6w1\xe74\xa2\x07t\x95JN#f\xaf\x9b9\x8d\x10~`|\xf3\x18\xbf(\xa3J\xff\x9dx\x0d\x873\x1b\x9d}\xee\x8d\xa1\xe15\xda2\x1b%Bi\xc2\xf8P\xaf\x1c\xf2\x93#r\xc4\xfa\x82\xe4\xc6O\xbdKp\x8c\xca\x03\x8f$T\xd5D\x8e\xb5\xb5@\x01\x0e\"\x9f^<\xe2\x8d\xe5z\xdc6\x8d\x1d\x1d\x1cY\x1b\xcb\x15\xb5\xad\x1a#G\x1a\x8dl\xe1\xf8l\xdcnB\xeb\xf7=\xa0\xc5v\xfe7\x83\xd6\xdb\xa37\xdf\x0eZo\xc3E\x1bh\xd5)\xd0\xf7\x83\xd6\xc67\x05\xd7\xc67\x85\xd7F#\xc0t\xbb\xbdx}8\x18j\xc6\xa2\x9cKe\xbe\xb7\x0f$\xcf\xe95\x810?\xa6\xba\xb4\xcb\x0e\x14\x1e\x083\xb4\x11\x93\x7f\xd6mC\x8d\xff\x8aj\xfcW\xce\x1e)\xff\xb9\x1b\x8e\xe9\xc7\x9f\xbb\x8d\x1c]c\x8b\x93\xca/\xc6\xbb\x9d\xa6\xb3\xfb)\x9c\x9d\xa5\xb3\x9e[z8V{/\xfd\xe0\x0c\"/\xf9\xc1\xe5\x1c\"\xb6\xf0\x83\xf3\xdf\xf7\x0ec\xc6\xdcj7\xa5\xf7\xdd\x89\xebNJ\xac\\\xab\x1b\xdd\xd4_\xd1$%+\xa3)\xcb7\xe7\xd6\x8a\xb0\xe5\xd1\x80\xdeRO0my\xa9/K\xbf\x03\xbf\xa6\x89\x87b\xb85Y\x0b\xf7L\xfd\xb9\x97\xdf\xe0 \x0b\x96\xcf\xc3\xcd\xb9\xb2b\x12j\x9erW1\xf3>\x8c\xe3(v\xba\xafIJs\x9fZ\xca\xcat\xc1\x99|\x91W\xb4\x97NG3\xce\xfc\xf4\xd2\xe9\xe6\x8c{-\x11\xfesk\xd6\x87N:\xdd\x9e\x15f\xb0\xf4\x06X\x07\x0e\xfbo\xf0\xe9\xf4\x95#\xc0\xa0\xf3\xc3\xf3E\x98\x8a\x1ek\x82G\xa9\xe8\xa5\xd3\x9d\x19\x8fO\xd1K\xa7\xbb\xb3>\xa4\xd3\xbd\x99\x89\n\xa3\xca\x15\x03\xdfN\xf7f\x82+\x1d\xf6a\xcb}\x0e\x8b\xc2\xa7r\xeb\xb9\x0b\x0b4\xf0\xd3Q)l\x87u\xb7\xa8\xd3?\x13z\xa5\xd3g3\x04<[\xb3]\xba\x0d?\x80\xb3;\x84\x1f\x10Z\xc3\x19\xf4\xa0\xe7\xa4\xd3\xd1h\xc6\xd0l(\x95\x80\xb8 \xea\x9b\x1bkW\xc4g0\x82M\xc1\x9e\x85\x8bQ\xd5\x1f=\x02o\x90\xd0\xf4\xd4_Q\xc7\x1b,\xc57\x1760\x88\xa6gCa?LR\x12z\xf4x1\xc6\xeeZph\x96M\xc6\x88\xfa\xdb\x93cA\xd7\x8d\x8e\x00\xdf\x8a\x10?\x90\xcc\xf0\x04\xfc\xdf\x8f\xc4t_\xbcP\xac\"L\xe6O\xdf\x0e\x0c\xc5\xcf4\xbe\xab\x0c\x8b\xc3hg\xdb\x1d\xfc\x88\xb6\xc2E\xaf\xe0\x11dd\xd8L>\x97\x1a\xb4(\x18\xba\x07?\xbez}\xf8\xe6\xa7\x9f\xdf\xfe\xe5\x97w\xef\x8f\x8e?\xfc\xd7\xc7\x93\xd3O\xbf\xfe\xf6\xbf\xfe\xfa\xdf\xe4\xc2\x9b\xd3\xc5\xf2\xd2\xff\xe3*X\x85\xd1\xfaoq\x92f\xd77\xb7w\x7f\x1f\x8e6\xb7\xb6wv\xf7\x9e>\xeb=\xd9?\x0b\xcf\xe2\xee\x03%x\xae\xe4\xf9\x1e+\xf6\xc57\xe0\x06J\x1d5^\x8e3\xfa\xe8\x1b\xae\x88B\x1e\x030\xe4\xbeC\xa1\xed\x9e\xa8\xe3 i'\xb9\xfcK\xa5\x19;\x8f\x06\x08\xbb\xdb\x8d7G)\xbc\x80a\xab\xdb\x1f\xd4\x8b\xefj\x1f\x1b)a\x0c\xff\x01OQ\x01]\xc6\xfb\xaf>:\xa3\xb2\x02cz\x16\x9f\x85\xfb3\xa1\xc60\x03=\xb2.K\x86\x91\x80\xb4\x8f\x12\xf3r\x07\x86;\xa1\xdc\xd3{\xf8\x1c\x18\x94\xc9sH{=\x17R\xf8\x0f4\x05\xe3*\x13~\xa5\x13\x88L\x11\xf0\xf2%\x8cv\xe1\x11l\xee\xec\xb8}P\x8b\x9fVK7wv\xe0\x11$\x8c\xec'\x98\x0e\xe4\xc5\x0b\xd8\x85{\xc8rt\x88$:\xa4\xba\xe3U,\xd1\x10dH\\\x82\x03\xfb\x01v\xf1\x9a\xe6\xab\x86\x04c\x18=\xcdu=\xe5\xb6\x86\xda\xb66E)\xbe*|\x0f\x19h\xd4:\xdb\xf9\x9b1\xa6\xdfX\xc4\xd1*\xff\xe2\x04(\x16 \xbd\xc7\xaf\xdf\xd4~\x15C|0)\x87S\xd0\xf67'm\x11:\xe6n.F\x82b@>\xd2Hk2\x0b\xad1`\xe7V\x05;q\xe7g\xd3\x08\x97\x8f-\xfa\xee\x16\xf2|J\xe9\xa6\xaet\xb7R\xb8\xbb\x05\x8f\x00Mr\xd8\x8c\x9c\x88a\xecS\x17z@\xa7\xa9\xf9R\xb5\x8c\xa0[\xfc\x0e\xf1\x1b\x8f\x08\xc6\xb0Y\xa0k\xa9\x9d\xa1\xae\x9d\xedZ\xe1\x8b\x17P\xedqw\x1b\x1b\x1e\x15\xc8\\j\xb9>\xc0\x17/j\x0d\xefn\x97\xdb\xebC\\F\xbc\xfc\xd7Ws\x10f\x89\xb6\xa6\xff+\x87\x9c\xacs\x08F\x85\xe1\x03\x99\xb4\xc8\xe2\xd1`\xf0\xea\xf8\xca3\xdfd\xcf_\x91\xd7\xb8*\xdcx\x1cP\xdb~\xe3\x97\xd2A\xee%\xccv_\xf8\x9c+\x83\xcd\x1ed\"uh0MgE>\xb0\\]\xcb\x01>\xeb\ny\x15\xd5\xb2q\xb3Q\x87\x88\x89\xe3\x87\x10\xdb\xadx\"\xd1$Jj\x16\x8eB\xd6\xcf\x1a\xbb\x96\x9f/\xb2\xd6A\xe6\xa7\xb9\x0fVM\x98!$\xf9\xa1H\x9a\xc1\"\"[\xb4\xca\xdf\x91#Ny[~!\x83S\xd7O\xfc\xb3\\\x8dZ\xec\xfa/\xdc\xc4k\xe2\xc7\xc9\xbf\xd7.\x16\xbe\xbb\x96\x9dJ\xc4\x8c\x0e\xe2\x98\xdc9\x99t\x81\xcco{\xd8\x16\xce\xbel\x0bg\xb8\x85\xf5[7j\xbdu}\xf4\xe7G\xc3!\x85\xe2^\xd1\xbb\x84\xbd]u\xf17\xb5B\xa6\xe9\x8c\xd12\x7f:d\xe7\x0c\xfe\x9d\xcd\xfe\xe9hoXG\x1dW}]\x0d{&R\xd1\x18\xd6\xd1/\xad#\xd1\xae#1\xad#[-\x82\xab\x15\xd5@\xdc\x07_\xc0.\x12\xb0\x8b\x10vF6\xc6\xff7\xd8\xc1\xe5s\xfb\x81\xfb8\xa1\xc6\x0bt\xbdw\xe1\xf7\xdb\xc4\xd6#\xd6\x0f\xc1\x10\x08L9\xc9\xc2\xbe\xb0D\xccIm8Mg\xd6\xfd\xf2mQ\xdeD\xe9\xff\xed<*\xffH\x9ed\xe1\x9c.\xfc\x90\xce\xbfR\xfbb\x81\xc3\xc3\xa1\xea\xd6\xf2\xcd?T\xa6\xbb\x8e\xfc\xb9\x8c/f\xeb]'\xcd\xd94\x7f\xffn\xae\xd1\x7f$Ob\xba\xa4\xb7\xdf\xe5F\xe5\x01\xca3\x1f\x03\xd5`\xbd6\xe7S\xeeW\xa7\xe7\xb3\x19\x11xr\xf6\xc4\x99.\xfd\xd5\xec\x07\xf7\xcfO\xe4\x05\x87\xbez\xac 9\x00\xd2z\xfa\x89\xd4\xbe\x0f\x8dw \xfc\xc2C\x9a\xf2\x86\xd3\x11\xcab\xf2\x16\xe1%\x93K[\x9c\xd8\xac'4\xeb\x9d\xa6\x85!P\\\xb2 *\x9a\xa9\xb5\xf2\xbd\x8f\xe1\x7f\x0e\xc4\xe56Q\x80\xceo\xe1\xaa\xd0-\x19\x13\xf5\xc1\x001\xbc\xd0*.H\xd3~U\x96\xf9J*\x913j\xbc\x83\xb6&1\x0f%(\xd6\x05a\xb0\xea\x01\x1d$Q\x16{\x14z\xac\xc0\x08X:X\x06\xd1\x05 \xc4\xd5_o\x1f\xbaK\x1e\xb9\xaf\xc8D_\x11\xf5\x9fV\xca3\x9b\xd2\xaf\\5i\xd6.\x94_\x08`\x1f\x9eU\xc8 \xec\xc3\xa8r\xad\xb5\x80}\xd8\xda\xac`\x03+\xdb*\x97\xcdY\xd9v\xb9\xec\x92\x95\xed\x94\xcb\xaeY\xd9^\xb9l\xc5\xca\x9e\x96\xcb\x96\xac\xac2\xbe;\xd8\x87\xed\xcaX.XY\xa5\xdfsVV\xe9\xf7\x06\xf6a\xa7\xd2\xc7!\xec\xc3n\xa5\xbd[VV\x99\xdb +\xab\xf4\xf1\x8a\x81\xaf\xe2\x93x\xc5\xca*\xef\x1e\xb0\xb2\xddr\xd91\xe6/\xacT\xfc\x80\x85\x95^N\xb1\xb02\x95\xf7\xb0\xafA\xfa\xe1\x18\xbaggC\xcdQ\xb4\x87O\x88\xe6\xc9S|r\xa1y\xf2\x0c\x9f\xa4\x9a'#\xdeQ\xa8{4\xc2G\xd7\xbaG\x9b\xf8h\xa1{\xb4\x85\x8f\xaa\x0c\x1d\xfbl\xf2\xa1Wu\xd1\xec\xb3\xb5=\x86\xc7gg\xdd\xc7\x9a\xb1\xf3\xbe\xce\xce\xb4\x9d\xf1\xde\x8et\xcfv\xf9\xd4\xceu\x90\xda\xdc\xe2\xad\xbe\xd3?\xe4\xad~\xa8(\x1a\xcaU\xdf\xb2\xf3\xba{\xd7\xedC\xf7\xaf\xec\xbf;\x9a\xe0w\xf1\xe7\xf0\x84\xfdA\xb6\xb7{\xcc\xff?b\xff\xe3W\xfe-\xc2\xaf\xfc\xffc\xac\xbdX`E\xf1\xe7\xcd\x9b\xeeL\x17U\xe3\x8f:\x9d,\xb4\xb6\x95\xabhn\x82\xb2ou-\xeb\xf3\xc8\x19\x9b;;.\xe7\x85n\xbb<\x80\xeff\xb9\xad\xdc\x1a\x19\xab\xef\xee\xecl\xc9\x172\xf1\xc2\xb6\xe6\x05=\xd7\xde\xe1\x8dlo>\xdb~\xb6\xbb\xb7\xf9l\xc7u\xcb\x11q\xbdhNa\x1d\xf9\xa5\x8c\xb9<\x00\xe2\x8a\xdc\xc9L\x0c\xcb\x98\x92\x94\xc6<\x19\xc3\xf0\xf6\x8d\xf8\xe8X\x07\x1c\xe8'1\xd0\xa7\xe5\x95-\xfd\x92\x87\xde\xd9YW\x84u,\xe28\x0e\xf1\xfd\x8d\\Vv\xa1\xa7\x08p\xba\xc8%G\xf5\xc5R\xa2X\xf3x\xe1y\x98n_\x06\xc9\x961\xa7\xdf\x93\xf4r\xb0\"\xb7\x0e\xa6\x0c\x17\xc5\xf7\xf7\xb0\xe9\xcah\xdfW\xfe\xfamxM\x02\x7f\xce\xdbR~\xab\xa1\xb9\x17At\xf3\x8e^\xd3\x00\x99X?9\x8a\x18L\x97\x0e-\x9e\xb8\xd2\x17I)\x93\xbd\xa4w\x81\x08\xc1]:YMLu=%p\x93Ym\xe1\xdb\xff\x8f\xcf\x06\xcds(\x12\xa2pk\x0d\x9e\x845\xae\xdc\x1b\xa4\xf9\xd5\x0c\x8f\x04\xe0?\xe7ARG\x90\x89\x86X?\xac=\x91\xe4!\x18\xa8>\x97}\xc8xg\x19^\\\xab\x8f\xa6\x19\x1b_8%3\xd8\xaf\x06\xc3\x05E\xcd]\xc6gGA1\x868\xd8b\"\x0d%s\xdc\x89\xe2\xf4\x17z\xc7\xb3\xcf\xe4?\xca\x01\xddC\xfa\x9b?\x97\x01\xd5\xf3_\xf7\xf7\xf0T\x86C\x0f\xa3\x8ft\xc1\xdb\x10_\xd5\x16\xc2\xe8U\xb4Z\x93\xf4=\xdb\xce\xbc\x8eR\xa0\xd6\xf4\"\x86\xdd\xe8zu#@\xa9\x14\xa85\xbf \x84\xbcLOd{\xe5\xf0\xb6\x1cu\x1e\xd3`\x85E\xe4\xfaR\xb6F,\x99g\xec\x0d\x92Ra\xaf\xc0K\xb3\x84\xce_\xabOJ\xb1\xfet4\xe2\xa3v3!\xd2\x8b\xdd\x14\xc1~%\x9al\xea\x8at\xc6\xfc~nc\xc4\xf1\x9a\x8d-Q\x83\xa5\x81\x0f/ y\xeeb\xda\x064`\x97\xd9\xfa\x85K\x1f;\xfb\xc1w\xd1\xec\x87\xfb\x8a\x88\xac\x16\xa2\x83\x04\xb3\xbd\x95\x9e\xb0.ydW\x1f\xad\x86\xf8\xf7P\xd5C\x9c Q0\x14x\xdd\xdb\x87\xc8eC\xec\xedW]\xcb\x04\ngV\x10\xbd\xb6\x85\xe3\xd6\x87\xdb\x95\xe4\xf2\x07H]k\xdb\xef\xea$Z\xca\x1c\x08\xb1\x05\xc3>\xfe\xd5\xbe\x8e\x9f\x8c\x0dmm\x96\xa3T\x8d6wQ~\xdf\x1dU\xc3`m>\xdba\xbf\x18\x87RxP0\x96D\xfc\xba\xbf\x87\x9d\xbd\xad\xed\xed\xf2{\xec0\xdeb\xbfx~\x8a\xbc*+\xdf\xadt=\x1am\x8fF#\xebD\xfef\x9c\x08N\xb1\xd2\x0f\xb6\xcc\xbe^\x14__\x15_\xaf\x8a\xaf\xc7\xc5\xd7\xd3\xe2\xebM\xf1\xf5\xd2:\xac7\xc6a=\xf9\xfd,\xfc\x01dT\x13u\xb9\xe57\xb6\x91\xfe^\x0f<\xf2#cs\xcaE\xbf2Y\xa5\\\xf43\xe3m\xcaE\xbf\x01\x06\x99\xae\x0f\xf2/\xf6\xd0\xebl\x1c\xbej\xe7\xd4\xd1\x84B \x0c\xe5\x0b\xdc\xe9<\xeeG\xfd\xe9{N\x07j\xe5\x8cS\xfd$\x12\x92\x96r\x96TV\x12\x83\xf3t\xde9\xfc0\xca\xb0\xec\xbc\xf8z[|\xbd)\xbe^\x14__\x15_\xaf\x8a\xaf\xc7\xc5\xd7\xd3\xe2\xebe\xf1uU|\xbd+\xbe\xae\x8b\xaf\x1f\x8a\xaf\x87\xc5\xd7e\xf1u^|\xbd.\xbe\x9e\x14_\x0f\xc4\xcc\xcc\x89^49\x1f\xd2\xbaJ(7y\x18r\xba\xaaP\xd9^\xcfv\xb3\xd5\xf9$\xc8\xae\xd2\xbf\xafD\x05\xfaM\xaf\x04f+\xf7\x96\x8d\xfdoZc)\x13\x83\xfd\xc5\xc3\xd4\x0e\x12 \x9f\xe7rd\x1d\xf6a\x01hQ\xcdX\x15\xe4Ya\x03\xde\xe3\xe9\xf2\x92[\xf1vA$\xd2\x9c\xbeg'\xc3\xac\x8f\x88\xe9\x1b\xf4\xdc\xb9P\xc1@\xf4\xb5\x00\xd1n$\x1c%\x0e\xbaq\xa8\x7f2\xb7&\xc6\x85\xdcM\x00\x13\x08\xe1%<\x83\"\xed\xd2o0\xc6\xf2\x9fa\x0c\xbf\xc2\x98\x8f\xb2\x13\xf1\x87\x7f\x871\xfch%m\x7fU\xa8Fu\x85\xe8`\x9e\xadJ\xbc\xb7\xe9.\x84\xdf\xfe\xa6\xd5\xdb\xdf\xee\xe3\xc7\x86\x9b\xd9N\x85!\xe3\xa1\xfd\x19H\xde\x16!\x08\x14W\xd3\xc7\x18\xa0\x1dz\xec\x9b\xfeF\xd9\xcf\xb9\x0b;\xe9\x94\xfc\x17'\xed\xf3$\xc6\xbeH\xdeL\x14\x85\xa3\xd1eY\x80\xb0Q~\x92\x1f)G\xe97\x02\x94\xdcYd\xc0H}\xa6\xd9\x90\x87D\xe3\xd9\x82\xccv\xa8 p\xa2\x9ah6\x9c\xe5\x19H\x15T0\xc5n\x04\xeb\xbd\x0d@\x9e$\xa9\xbe{\x8d\x96\xaf\xe8Q\xfd\xf7F?jM\x06{\x90o\xff\xd8\xf8\xb6\xc0\xed\xc2\xe7\xe51z\xbb<~\xdcuM\xf8\x0e\xb2\xf5_\x9b[\xbfg\xad\xff\xc2\xf3\x04r\xbca\xcd\xfe\xe4|dE\xbe)M\"\xb6\xfess\xeb/\x8d\xad\xb7\xc67(\xcb\xee\xb0\x0fO\x9c\xb3\xb0\xe7:\xd3\xdf\xcf\xc2\xd9\x0f\xee\x93\xa5~W\xa9\x1f\x94\xc9\xb3\x9a|\xe1r\xd9DP\x96\x0c&\x90\xa1\x9aA\xb8U@4\x08H\x92\xbeeo\xf0\xfc\xe0\x7f\xce#\xd3\x0d\xfb\x98\x7f;u\x0d{Z\xfd\xa0\xa8~\x16\xcaP0Ct\xffd$^\xfe6c,\x88\xc9k$l\xf5#b\x0c\xc6\xaa\x0b\xb01\xc1\xa7\xfaam'\xc0\xc3\xbc5O\x04\xc4\xc9\x15O7\x1b\xc6\x0cyJ\x18>\xcb\x00o\x80|\xb6\xd3\x13\xe81Y\x0f\x13\xdc38\x88\n0a_\xc7<\x9f\x1d\xf4\xe0\xcfN\xc0\x85I\xbc\xb5\xb0vf\x8ey \x05*\xfa\xc6J\x9f\x19z\x12\xb7 \xdb\x7fk\xc4\xf6\xc7\x98\xac\xa4\xf9~O~rA\xba\xe0\xca\x85\xa4l\xe4\x91\x84\xce\xb4\xc2\x08\xbd\xe4\x02\xda.\xa0\xe7\x0e\x13\xd7v\xb7F\xc8\x04\xd4\x83\x95\xfa(\x15\xf3wv\xb76\x87PD.\xdd\xda\xdeb\xc26*\xa6\xfepF\xc3Mt`Na\x83\xb7\xce\x93\xc9l\x88\xd7z\\\x86c`c\xbc\xdb\x98\xeb\xbc\xde\x0b\xab\xd9\xde>t\x90\x93\xf9\xe4`Zh:\xf5g0\xe6\xa7\xdc\x1fz\xb74\xf5#\xafSmk\xe6\xf2\x8c\xa2\xfa\x86D \x08\xf3\x92\x95t\xba\xfej\x1d%\x89\x7f\x11\x08\xc7\xf71\xf8BU\xc9\x8d@x \xb2n\x13c\xf7\xd9\xb1\xcb\xf3\xbf\x983K\xc1\xbe\xe4\xd7\xa4\x02\x10\xe3\xafin\x01\xe221)\xc5\x95\xd2\xea/B\xb6\xdfx\x8em\xfd{\x9b\x9c\x1e\xe5\xcf\xd8(\xba\xbd..\x97\xdc\x94\x1b\xfc\xb09\x0b\xbb\xd6\x19\xfed\x14\x84MCf\xb8Q\x90\xd4\x8d\x11\xa6\xf7\xb4\xf6\xf1g-\x14\xd1\x1aAq\xbcV\xc9k\xce\x1bTl\x87UE\x96\xe2CY+:\xae2\x90\x85*\x9d\xc0\x0b\x08\xd8\x1f=\x07\x89\xa2\xa3\xe31)oJf\xee\xa0\x88s\xc0P\xc4\x1b\xe4\xf6\x06\\\xcb\xdd\xf1*5\xba\xdc\xbc\x80aR\x9e9\x90\xd3XY/Z\x80\xfaR\xdeN\xder\xa5#F\xfal\x82.\x95\xea]\x98\x80\x87\xdf\xc7\xd0\x9dt\xfb\xe0\x0dr\xbb\x04\xdb\xb1\xc2\xdaXp\x95\xa8\xb8\x1a\x99b33>\x0e5>N\xdfh>\x91\xf1\xbb\x00\xb5K\xee\x13\xa1\x94\xb03sa\xa1\xe2\x06\x0d\x80\xfaA9/\xa9\xf5\x85\x11-\xca\xf4\x99'\xe8\xf7D\x82\xfe\xc7/1k\xbf\xe0\xfdc \x9eG\xd7i\x82Wo\xfc\x04\xe6i\xc2\x10\x02\x8f\x9bN\x9a\xf2\xb4\xa6\x8b\x19\x9f\x99\xf9\xe41OY\x8a\xc3\xb1\xb6\x8a5\xfe\xb4\xc6&K+\xe6w\xec\xfa\xd1\xffU\xd2\xf1\xf1M_\x95\xd9\xd5\xfb\x83|\xc8a\x9fo\xe5\xb0\x0f\x9d\x11F\xc1\xc9\x7f\x0e5\xd9\x82\x13\xc8\xb1\x847Q\xcd\xdb\x9a\x13?U\xa4}\xc1#\xc4\x95\xa5\xdcjVS\xd6|\xd0\x87E\x1f\xed?\xea\xdeR\x0cAQ\xd9\x91?B\x17\x1f\xf9\xa4\xae.C\x85\x9d\xa3h(\xc5\x8dXqI\x92\xcb\x04\xa1\x8b7f\x85o\x06\x02\xeb\xd1#\xb6\x05\x95\x02T\xdb\xdc\xdf\x83P\x84K\xa5\x02\x12\x86\x97 R.\xfb\xa8*u\x85Z\x8aVn_\xa6\xc1\xcc-\xa0\xdf\xfd!\xa6\x8bs\x86\xe3\x15\xf1\xderQ\x8d\xd3\xc2\xb6;\x9a\xc6q\x08\xba\xf2}\x9eR\xdc\x00W\x97\xaf\x1c\xcf*\xab\xde_\x8aU\x96\xc7\xcd\x04\x9cN\xcd\x96I\xa3!\x92\x9f\xb2r\xb9\xaf.\xb0\xc5\xa2\x95\xdf\x1c\xa7\xc4\"\xe0]V\xeeYM\xb9\xf1\x91\xd6H\x1f\x04y\xa5\xe8\xc2%~w\x9aT\x80J\x0e\xd9\xe2$\xd0\xb4\xa3\x145\xb4\xa8\xbe\\\"u\xf9u\xe7*K\xd0\x92\x80\xc0\x05O|\xc3\x13\x98\xdb\x8c\x10\xa1\xa4b\xe5,\xc4e\xe9\xbe\x8d<\xe72\xd8\xc8E\x95=\x135\xc4\x823\xc8\xf8\x0c\xa9\x1d\x0c\x89$\xae\xb5D\x88\x89p\xca\x18\x9c\xcb\xa9?\x9b\xf5\x05\x8d\xe1\x96\x80\x19O\xcb\xce\xffq\xbc\xc7\xdd\xd5b\x07 \xe4\xc7\xbd\xc1\xbe\x15\x1e\x15L\xf0\x90\x89\xe0e\x1dO,\x1d\xd6,\xe77\x9f\x88 N\x13\xc6\xa8\x8a\xaf\xd0\xc5\x8d\xd7\x93\xaf0\x0e\x83S\x81\xd2\xdc\xd4\xa9$|\x1a\xc1\x17\xf4<.z\x1eC\x97\xe1uo_\xed\xdd$\xedHZk\xa2\xee\x89}&g\xe4K\xda\xe2\x14t\xe4QNG\x90\xc9\xe3\x9d3\xd9\xac\xbe[m[\xb5b#\x914\xec\xd3\xa0y\x9fz-\xf7i5\xa7\xb6\x97\xa3o%\xa7vV\xbf\x8a\x9f\xa0\x00\x8eR\x93\xa0`\xfc\x18\xc2\xbb\xddn\x1fq\x02\x95 S\xb6?\xbci\\`3N\xb63\xe2\x87_\x01\xd22N*\x8dq\x04\xcb\x8a%f2\x96q8\xc8x\xa3eF\xbd\x0e\x17\xaf\xb099\x14R\x1e\n\xb2\xe6Y{lR\x8f\xf5\xee?X\xaf \xeb\xbf\x11\xa3\x9a\xd0\xa9\x0b]\x05\xa9\xeac(\xa8\xa5\xf6`.\x1d-e\xf0~\xc9iRx\x00\xdb03\x93\x98i\xc16\xc5l'4\xd9\xe8\xa8\x84\"D[\x1d\x95\xe4)$4B\x12J\xcad\xa6%1\xc1\xb7\xba\x1b\x0c!\xc4W\x9e5\xb8Xy\xfb\xc2g\xca\xc2\x13\xce!\xcd\x9a\x16\xfd\x9fAF\x1a\xd6\x88\xb4X#\x85\"\x84&\x8a\x90\xf3\xbe\xd3xV\xdeA*1\xf091h\xd8\x8c\xae\xd0U\xb6\x82;Q7\xdc\xb4+S-7\xc2\xbe \xf0\xad6\x9cY\x94\xcc\xb7!\xd7(\x89@\x03I\x93\xf4X2\xd5k\xf4m\x84\xaa*-\x0b\xb98F.\x02\x8a\x9eT\x10-\x801/|,i\x048W$Kz!K/'\x95\xf9\x87G\x8f\xf8\xc5\xa4DbT\xe0\xd6\xc1]+i\xe2K\xca\xab\xc1\xc5N*\xc4\xce\xeeKu=\xfed\xee\xa8.\xd2\xe9D\xb5\xff2+\x03sm\x94.\xd4\x8c\xce\x1d\x87\xc7\xbb\x94-\xa3\xfb\x97\x89~*\xb4\xb3\xbe\xa2\xb9\xe5c'O \xa6\xd1\x80\x98}\xec7\x94\xc0\x14\xa1zO[Xy\x15ia|\xdc\x9c1\xf7ui\xbc\x85\x0fy\xbd\xd4\xed\xf3ce\xe0'<\xb4C\xaa\x89\xce.?Uf851\xc3\xd4I\xa7\xfeL@\xcd<\x12{G\xd5X\x11\x15K\xb8\xc8\xd6y\xc4y\xeb\xb0\xee\xc4\xca\xd0$\xe2dZ\xb9R\xf5\x0d\x97\xa8\x90\xaar-\x82,\x9a\xfa\xd3p6\xabL+\xd5\x98\x03\xe6\xe12b\xbb\xd2\x8fR\xab\"\x9b\xb5s\xc43\x02\xb0S\xe8\x1fUOB\xa9\x97V\xcc2q3\x84\xc8\x03\x85}6GZ\x9c\xb0\x13\x08%\x8b\x85\xda\xcbR\x0e\xf2b\xe7\xe5n\x9fr\xfbR\xaadh\x1f$dA_W\xac\x15,\x96{|\x8a\xf1\x80\xde\xa64\x9c;\xf5}\xc4m4\xc7@\xca\xab\x85'~et_\xe4\xf6\xa3z\xb1Z\x07,\x0d\xe9\xd5\xac\x07x\xd9\xd6q(\xecC\x8f\x9aC\xcaX\xa3\x99\xf3h\xe1\x97i\xba\xd6\x04\n\xe7\x0fo\x12C\x0cq\xd1\xdfS\xc1\xec\xd57T\xd1\xb8\xae \xd9zC\xf3\xdb\xdb[\xf6\xf6\x17\xda\xb1+-l\x8e\xec\x0d,\xa3\xf5%\x8d\xedm\xec5Lr\xe1\x07\xa6P\xebzs\x04\xeda\":\xf9\x16\x98%\x1d\xca\x1a\x83\xc4\xd47~d\xbc\xde\x99S/\x9a\xd3O\x1f\xdf\xbe\x8aV\xeb(\xa4a\xea(Q:\xcfzh\xb2\xc0\x18+\xcd\xceM\x07\xdc\x7f\xc2_\xdc5!{NT\xaa\xf1\x05$\xed\xd1\x9e\x8c\xdcQ\xdc\x0f\xa1\xcb;R\x9d\xcd\xf95\x0dZOO\xd0#\xde\x85X(6\xd1H\xf2\xd1#\x10G\x0f\x0dkS\x8cP\xb2\xdbG\xb6\xa0\xfe\x94'\xf03\xd0\xbe\\\xf4I\xd1O\xf2\x8f\xc8\x0f\x9d\xee\xa3\xae[!o}H\xb9go 2U\xb0\x94.\x92\xd1@b\xfa\xfb\xfe\xe4\xd1\xac\xe7\xeeO\x9c\xe9\xef\x8f\xb8\x95\x04\xae\xfa?>?G(\x86V3\x01i0\x159\xe8\xb4i6\x8fb\x156\xabg\x0b \x9b\xe2\x87\xfc\xba\xd7\x89\xa7\xfe\x8c\xb1\xc9-x\xa6\xf8a\x08^\xf8FnU}\x1a\xb9o\xe4\xde\xee\xb6\xd67rk\xb8\xa9\xf1\x8d\xec\x1e\xde\xae\xa9\x97\xd2\xb9\xaag+W\xcb\x14\xdf\x97\xf2\x93$\x7f\xe2\x87-\xc8\xb8\xe1\xcaL\xdc\x94\xf5a\xdd\x87y\x1f.\xfb\xe8\xc9\xa8\x89\x01\xba2X\xe2.\x0d\xe5w\xa8\xf9-\xafSE\xb5Yl\x8a\x92?\xf4\xe9\xdd\x9ar\x9fh\xa2\xe6R\x06\x950\\\xe8\xcf\x10\xb9+\x03=\x02\xe1\xddK\x1du\x04.\x04\xec)\xec\x8bh=\x1c\x10)W\x1a\xd3\x01Y\xaf\x83;'\xeeW#>}6\x0c\xf0\xdc\xech\x8f\x16\x12\xb0\x01\xe6\xfc\xedJ\xbc\xa0Kn\xb7\xf2R\x90\xa1P\xdei\xa0\xe8\xc0Z\xb9f\xcf\x16\xad\xc6t\xa35\x97dC\xa2\xb8\xb3t\xbbj\x01\xce\xb9\x9ac\xe3\x90\xed\xe0Z\xb59\xec\x83\x08\x05\x1fe\xa9s\xd3oa\x94\"A\x91\xc2\x068\x08\x0f{\x00\x88%L a\xdc\xdaB\xbep\xed\xd6\xf3s\x00ga\xabn\xdf\x06\x88\x1cZ\x1d\xad\xe7\n2\xa0Av\x00\x13\xb8`\xaf\x8c\xf9\x9d\x8e\x8a-5 M\xdf\xe3m\xd3\x1a\xe81\x97\x01\xea\\\x0bz\xb6Bl,$^f+\x1a\xa6 \x0f\xe4\x9f^\xfaI\x1fo+\xa8Ei\xc2^V\x90\xad\x10\xbf\x9b\x97\x0f\x14t\xe5\xbd\xd4\x91\x80 $\xab\x02fkmC\x9f\x1d\xd3\xc2\xb3\xd1-]u5\xea\xcd_8\x97m\xe4\xf0\xfa\xc6BSyG\xd7\xa8\xdb\xaf\x8cT{r`\xaa\x0bF\x85\xee\xefQFrB\xae\xfbA:\xd9a\xe7-\x99\xfb\xe1\x92g\xdap\x18\x95\xec\xae\xc8\xedo\xc4O\xbbty\xbb\xb5PS\xe5~p\xa2{#\x97u\xff@ *\xdd\xeb9\xe1-]B\x0f\xab\xac\x05\x82\xe43\xa1\xaf\x0f\x9d\xd8\xa9\xc4\xcd\xccs\x08\x15\x0c\":`\x8c\xc1#\xe1\xe3\x94\xcd\x0dH\x02\xb9|\xd9\xa9\xd8O~\xd6\xef\xd0\x1a\x80\xc6\xa0]\x14\x14-\xba\xe7\xe7\xd8\xfe\xf99R\xe4\x7f|\x86I\x15LZ-\xa89\xe8\x16\x8fC\xe7l?s\x1di\x15\x85\xe2`\x9f\x81vw\xe8\x0e\x16NUp\xee\x832\x0c\\\xbc>l\xba.\xeb\x7f*\xc3\xd9u\x1c\xaa\xda\x8c\xa1\x9aM\xe78\xd5\x14y*\xd5G\xcd6\x9e\xb0*0\x8cl\x87\xa8\xebK%\\\x8aFx\xf9\x9c\xd0\x1cM\xd0@\xf6\xb8\xae\x06\xad\x9a\xc1\xfe\xe33\xbf|\x19\x8b\x83\xa6\x82z\xde%\xf5\xae\xc6\x8aEv\xebM\xab\x92\xf5\x02\xe5\x8b\x8d\xdb\x82\xe8\x1b\x8f\x1d\x0fC6\xf0:\x0f\x1b\xd9\x97\xed}\xde\xdf\x18\xc7\xff\xcc}\xe0~oV\x1a2p\xed|E[\nx\xab2\xb4\x90\xad\xf7\xb4I\x88\x9d\xad\xbd-m\xdc\xa1\xa7\xba\xb0C\xa1\xb3]\xad\xcd\x07\xfft\xbbZ=\x10\xe5\xd5\x83\xc0\x13\xbdVG\xb9\xe0\xf5w\x86\xa5\xd3\xf0\x99\xf2+\x1a\xf8![\x1a\xa7\x82U\xeb\x1a\x19Z\xf8\xe1\xfc\xf5\xf1\xfb\xa3hN\xc7Ui6\xa6\xe1\x9c\xc6c\xf0\x07\xfc[e\x92\xe1*\xca\xc24\xd7\n\x1d\xa4\xbc\x11\x7f\xa0\x7fR~\xfb\x9a\xc6\x89\x1f\x85cH\xaa\xad&x\xc3v~\xc1\xe8\x05\x9d\x7fZ\xcfIJ\x931d\x83r\x89\xe15>\xd2\x93\xec\"\x8d)}\x1b\xa6\xd1\xab(L\x89\x1f\xb2y\x14\xc2\xabB\xa1\xf5\x91\x1a\xcf\xcf?\x1e\x1e\xbc:=\x7f}\xf8\xeb\xe9\xf1\xf1\xbb\x93\xf3\x9f\xde\x1d\xffx\xf0\xee\xfc\xe7\xe3\xe3_\xce\xd1CWk9e\x7fM,\n{\xbbU\xc5\x8ar>\x87\xe7iL\xa9.i\xf8\x92\xa6\xaf\x82(\xa1I\xfaV\x10\xe47q\xb4\xe2\xab\x12\x0f\xccO5\xba\x16\x8aK\xc6*\xc8\xcaM1\xc3@\xb9b\x18\x88e\xa0\xf3|\xcc\xfc\x02\x921\xfbR/\n=?`\xcb_\\h|\xaepH\xeboAL\xf6\xf6\xaa\xd1\xca$5\xa9\xeewNM\xf6\x9e\xea4u\xac\xbc\x1a\xdd,\x13\xe5U\xaa$\x88\xe1\xd3j\xbf\x81(\xaf\xf6\xcb\xe9\xc9\xde3==\xa9\x11\xc35'3\xa3*Y\x9a\xf3\xf2\xcd\xea\xe1w)\xcaG\x95\xf2kQ^\x9d\xeeJ\x94W\xc9\xe4R\x94W\xc1p'\xca\xab`\xb8\xe0\xe5[\xd5\xf6\xcfEy\xb5\xfd\x1bQ^\x9d\xef!*\x18\xdb\xf0n|{6\xc4\xce>D>\xeeP\xb8p/\x07\x87\xd74L\x0fW~\x9a\xd2Xl\xf0\x8f\x94x)\x96\xbf\xf3\x93\x94\x864vVn^\xf7C\x90-\xfd\xf0\xe7\xecB\xd4V\n\x8f\xe39\x8d\x1dR\xad\xfb)\xf5\x83D\xd4.Q\x0bga\xab\xcaj\x9c\xc6\x84\x91d\x12\xa0\x80\xde<\x82\xe4\xc7\xbb#\xb2\xa2\x9a\xfbC\xf69\xf1W\xeb\x80*\xd5\xc7pS\xa72\xecs\x18\xa64~G\xc9u\xb9v\xa6\xaf\xfd\xea\x92\x84\xcbrMCv\xb3\x13\x1a\x94\x07<\x86s}\xcd\x1f\xe9\"\x8a\xe9\xdbp\x9d\x95\xab\xd7]\xb4>#d~\x8e\x92\x02\xb8\x020?\xb1\xb5\xf3\xbd\xbc\xf8U@\x92\xc4\xf1\x8c\xf5O\xe9mZ\xa9|\x89\x95_\x1f\xbf\x97\xd7T\xa2\xaaR\xf2*\n\x17\xfe\x1235\xb4\xab\x99\xb4\xaey\xc1\x17}\xb5f%\xe5\xb1\x96\x0b\xdf\x10/\x8d\xe2\xbb\x16\xb1>\xa5\xc2\x81\xde\xc0\xba\x1a\x98\xb2\x80\xa68\xcd\xf3\x0d!\xc8\xf5iL\xc2\x84\xf0\x1e\xee4\x15\x7fd\xbc\x80\x1f.O\xd2\x98\xa4ty\xe7\\c\xa5\xda\xd8\xc3k?\x8e\xc2\x15\x0dS'0K\xf3\xf8\xed\x8b\xc8\xbf\x99F\x08\x00\xfb\x8cw\xa9\x03\xa8Kb\x9flxY\x1c\xd30\xed\x8eu\xf7 \xbc\xca\x9c\xa6\xc4\x0f\x12k\x15?a\xac\xcf\xdcV\xe7\xd2\x9f\xcfih\xab!\xfc\x02mU\xae\xe8]r\x19\xc5\xa9\x97\xa5\xd6\x01\x05\xe4\x82\x06\xb6\nq\x14\xd09M\xbc\xd8_#\x07e\xa9J\xb24\xf2\"FMRj\xab\x87\x92\x97\x1d\x06\xf4vM\xc2y\x03\x9cH\xb2\x8e\xd6\xd9\xda:=zm\x9f\xde*\x9a\x13{\x05\x19\xb5\xbc\xb1R\x82d\x8c-\xaf\xadj\x14\xfb4LI\x13,\xf1\xce\xfa2\n\xe64\xb6V\x8bi\x92\xd8\xc1\x14S2\x8f\xc2\xe0\xce^\xe7o\x99\x1f\xdb\xdb\xe1\xd3k\xa8\x13\xc5\xd6\x1drM\x82\x8c\xae\xc8ms\x1d\xdf\n\x1d\xac\x13F7\x8duRzk\x1d\x10I\xa3\x95\xef\xd9j\\d\x89\x15t\x81\x7fm]\xef\x98\x06\xf4\x9a4\x10\x0eF\x7f\x16\x0b&\x9f[j-crqa\x87?\xa3\xc2\xd7\xb8]i8o\xe8\xd4\x8b\x02\x8f\xf1\xe1\x0du\xd0P\xae\xa1N\xb2&\xd6\xe5\xf2\xa20\x8d\xa3\x06\xca\x884\xe6\x82\xce/\xac\xe0F\xcf\xe8\x15M\x12\xb2\xb4\x82}\x11D7id]8F\xf9\x82\xa6\xfe\xa2\x9b\xd0:\xecu\x94\xf8aB\xadP\x8c\xa3\x9bFH\xc7\xd1M#\xa4\xe3\xe8\xa6 \xd2 M\x13\xff\xef\x08\x99R\x8d\x8a\x00\xf6\xfa\xf8\xfdA\x9a\xc6\xfeE\x96R\xc6\x1a\xb2s\xaf^E\xf2\x1dy\x8d\xbc\xc2W\x9c\xc2\x8aFgX\x95V\xc4\xd5\x81^\xa3\xb3\xb7W\xad.e\xb0\xaap#e\xb0\xaap\x83q\x08\x9f\xf5a\xb4\xd5\x87\xcd\xbd>lmV,[\x990\xb6\xb9\xa9 \x14\x1d\x0d<\x12~J\xe8\xeb\xe3\xf7\xa8O@\xde%\xf1\xd9\xcc\x91\x0fE\xbd/O\x11Q~\x19\xc5\xb5R\xda\xfcjS\xf3\xc8\xc3+\xda\xf7\xd1\x9cb3\xb2\x00\xa4\xc3\xa0,\x18\xa8U\xab\xca\"~\xd3Zm\x9c\xf1\xae\xd5\x01\xb2\x07\x1d\xee\xb2\xe7\xd4\x0dk1\xf5\xbbHv\xc1V\x9f\xb8F\x05\xcaz \x14C\xac\x06\x9a\x07\xbd\x0dS'/u\xdc>\x8c\x86.\x8f\xe7\xa7\x11?+cu:\x1e\xc8HT\x0b\xc0\xec\xbe\xec\x0b\x86\xe4\xabL\xf6Z\x13\xa6{\x95G-\xc5t\xbc\xaf\x84W\x03\xe35K\xf5\x96\xdax\xd2\x17\x85\\\xa1\xe3\x00\xd9g}I\x12:\xffH\x97~\xc2\xf8X?\n\xe5\xb6\xd0Vg\x9f\x8b\xec\x82\xf1zc\xe8F\xa1\"\xb9X\xbc\x10<\xb2N\xb3\xb8\xfe\xca+^^\xb7\xe5\x87\xfa\xde\x96\x9f9]\xd3pNC\x0f\xd9\xdai7\x8d\xd6*\xda\x86\xf3n\x1fX\xe1/\xf4\xee\x03\xe3\"\xc4O\x862b\x98\xf8\xfb\x03IR\xda\xd5$\xe5\xab\xf7\xea\x95\x9a\xffN\x80\xac\xce\xa1\x1d,\xcbo}#p\xfe\x18d\xb1\x80\x92 \xb2\xaf\xa3\x9bP\x0f\xe7_\xe8\xdd\xa7\xb5\xf8\xfe>\xca\x12\x8aU\x1f\n\xe7\x93\x94\xc4\xdf\x0be_U\xba\xf9\x02X\xe3{\xdf\x15\xdabd\xff,xs\xc9\xf6\xfb\x03\x9c\xf7\xf3\x05\x10\xe7/~W\x90\xcb\xb1}C\x98\x97J*\xe3\xbb\x13\xaa\xbe\xbc07\x9b\xba\xd0^\xa5I{r\xad\xb2\x83[C\xe7C\xb3ZD\xd7r\xf7\xa2G\xc5\xab\xf2\xe1\xabk\x18gim:o {\xd0D\xd3S\x9b\xe3\x105\x19\xa8\x97@k\xa9\x84ki\xb7\x00\xd7\xc4\xac\xb3F0j\xb2\x1c\xd7ymhL \xafe\xde\xb7\x01W\xa0\x94G!:1\x05A\xe9\xceIJ\x90\xbbIa\x02\xe9\x80\xfd\xac\xdeI\x14#b]\xdd\xe4,Y}t\x87\x92\x8f5\x84\xa6\xcd\xfa\xba\xd8\x0e\x1e\x86l\xb3\x99FC\x13^\x82\xbaT5\xf2\xd6\x18\xf3k9\xa8\x9e z\xe39]\x17\xec\xbczX\x07\x87\xe1\xbc}\xf3\x82Z<\xac\x07\xfeR\x13\x9d\xe0\xd7O7\xdc\x96\x10\x85\x8fG\"J|u\xb8h=\xd7df\"1M\xd9\xc4\"\x92\xd3\xa3G\xca\x8e-\x07\xba\x16\x031\xf7\x8e\xab\xe1\xf6AI\x18^\x16\x08\x00\xf9a\xf6.\xc6q\x17\xe1{kMp\x1c\xab>:\x0c\xd1j\x8f\xe7\xa9c\xf2\xcd\xcd`I\xd3\xd7$%\x8e\xcb\x81\xb3\x0f>\xdawEQ@\xe7NTu\x05`X\xbd\xc0,\xc4E\xa5\xac\xd8\x03udO\\X\xf0]V\x8bsbp\x05\x95\x97\xd9\xe7Z\x7f\xfb\xdc\x92GDH\x91m\xb7qn\x8c\x07\xc4\xf3\xb2U\x16\x90\x94\x9e\xdeD\x1f\xd8\xf1\xfb\xdaO\xd6x\xf9\x9c\xe0E\xca\xc2J\x8dn\x1b\xf6;\xa9\xcf\xbf\x83\xd1\xa2\xe6U\x13\x9fo\xb6\xe3[m\xc7s\xa7\x1a\xb0F~\xda\x1c\x1c\xf2\x93\x1fF7\x97\xbew\x89\x8bp\x0d\x13\xbe\"cp\xee\xc4u\xd8\xaa\xa9\xabBd0\xf7\x95\x1bv\xe3\xfa\xea\x1b\x04\xe5&\x02Q\x1dc_\xdf\x15C\n\xf5\xef5\x86\xd9S\xf6]3M\xc1\xad\xdc\x82\\0d\xb81\xad,:5\xd4\x17\xb6\x88\x0c\xd7\xf1\xd8\xdc\x04\x07cj\x05\x14\xc0)\x1b\xbb\x11z\xfe \xa6\x01% un\xdc~~\xe0\xf5\x0d\x01,\xf5\xae\xce\xeda\x06\x0fBu.O\xb6Z\xabo\x8e\xe1\x8f\x1eA\xa7\x85iD\xe5m\x87\x0e\xbc4\x0e~\xa1w\xb8\x1ayJ~\xd8\xd0\xd1\xa2\xcf\xd1s\x80\xf2\x83\xf7\xba\xf9\xbe\xb9t<]XD\xa8\xb1\xa8\xf8*\x1b \xba1\x8b\xdcQ\x1a\xda\xd6HX\x01J\x810\xc1\xaa\xac\x96\xbc\x0d\x1d\x9c\xdf\xc4d\xbd\xa6\xf1I*\xb2~\xa4\xe5\"\xf3\xd5\x01gT0\xd0\x980\xd7\x0d8\xaf\xd3\x0d\xb3\xd5\x05\x8d\xf3\x95c\x0b`\x19\x0b(\xacw\x97\xe7\x8c\xc3\x03\xcc\xdc3`\xf4\xb5%Ms\x93TG\x9cyn\x112\x17\x1d\xefk\x15\xb4+\"?\xfa{\x8dz)\x9eB\x81\xd1\xe1D\xafp}\x8f\xa5_)*\xef=\xd595\xab)\xde#q\xa4\x8a$\xe2V\xb4i\x197\xd5@\xe0\xf8\xe5\\L\x17\xf5\x85\x928\x18\xd60\xd7\xe2\xce\xaf\xcfV\x00\x13\xa0\x0e\x0f8\x92]\x04\xbe\x97SMd\x02\xe2\x01\x99\x17n\xa8\x07\xc9G\xba8\x8d0m_\xbf\x1ab\x0bp\xe1B.\xc8\x0d\xce\xa3\x9b\x90Vc\x96\x16K\xc8\xc4\xb7\xe42\xca\x02!\x06\xb5\x81\xa6\x84I]r\x03\xa9\xae\xac]a\xe4\xd0\xa7\x06\xe8c\xb9\xc8\x86\x16\xd3\x85LL)\x86_\xbf\x0f\x89\x8c\x03\xf0\xb5\x03P.W\xecX\x90\x13\xcb\x94\x8f\xc3\xc7\xafb\x1c}\x08\xf1m\x0c#\x9eG+,\xde\x8e\x90\xc0\xf1\xbdY\x062g\x89\xdb\x80\xf7\xff5\xc8\x8a<;\xe2fLW\xd15-\xa3';\xf9\xbf \x82~\x075\\)\xe2\x80Q\x03iP\x8a\xfc\xe6\xc1^\x0b\x13G\xedR\xa7\x91Xh\xf3\xfb\x1e\xe6\\\x9a@d\x89\xfc\xe2\xac\x8d\xc1V\xd8\xe73_\x81 W8z\xe6!\x8b\xf0\xa0\xfb\xfb\xe0\xb5\xc4\x94\xb9h\x16D\x92\xe4\x04\xc6|\xb05\xf5G`\xb8\x96\x07\x19uD\xb4\xe2Y[\xf1,\xad\\WlZ\xc9\xa0 P\x88\xd0\xb8S\x0ds\xc9ov\xf0\x9d\x80S'V\xcc\x17\x0c\xd3`]WVq_\x17\x95\x17\x04dV\xfa\xd1 \x81\xc60\xca\x96\xd1\x08\xd0\xaf\xca\x83\xa2\x9c\xb6\xb3\xe2\xbc\x7f\xf6\xab:\xa8y\xd9\xce\xa98D\x95{\xa9\xeb>\xac\xf8&w\xfb0e\xbf\x1a \xa9\xfe\x8c\xcf\xb0\xf4+\x0f\xd2Z\xf4\x1bv\x8e\xca\x00+~\x14\x0e\xde\x7f:9=\xfftrx\xfe\xe1\xe3\xf1\x87\xc3\x8f\xa7\x7f\xad\x9f\xafj\xf5\x9f\x0fN\xce\x7f<>~wxpt\xfe\xeb\xc1\xbbO\x87\xf5c\xb7Z\xfd\xe8\xd3\xfb\xc3\x8fo_\xe9\xaag\x9a\xea\x1f\x8eO\xde\x9e\xbe\xfd\xf5\xd0\xf6^\xa2y\xef\xf8\xd7\xc3\x8f\xef\x8e\x0f^\x1f\xbe\xb6\x0d0\xd0\x9eR~\xf2*K\xd2h\x95k;\xc6\xf0\x91.\x0fo\xd7J\x94\xfc\x94&\xe9\xe0\xc2\x0f\xe7NHo\xc4c\xa7\xfb\xbb3')\xb9'\xb1O\xdc\x0d\xcc\x01\x14\x0f\x0eNO?\xbe\xfd\xf1\xd3\xe9\xe1\xf9\xd1\xc1\xfb\xc3\xf3W?\x1f|\xc4\xbc@?\xfc\xb9\xab\xcb\x1ao\x0f\x85\xc1><\xb3\x8e\xd6\x07\xb9x\xfc\xea\x92\xc4\x185\xd1R+I~\xa1w\x96\x1a)\xc6\x1c3=\x0e\x82\xe8\xe6M\x16\x04'^L\xa99\xb6\x0c\xd6\xc3\x08%xjx\x96\x0e\x03\xcbp\x13\xcb\xa3\xbb\xd03w\x9f\xa5\xd1+\x11\x12\xc3\xdcD\x96F\x1f\x02rglE\\\xec\x9b\x9f\xd3 \xf8@\xe6s?\\\x1a;auN\xd6\xc4\xb3\xd6\xb9$\xf1\x89e\xd5\xbcK\x12\x04\x14-\x1c\x8c50\xb4\xc7\x18\"\xb87\x8e\xd6\xb7\xc0\xc2\x0bH\x92\xbc}m\x7f\xceYLS\x8d(H\x8cA\x89\xbc\x88\x01\xc1\x8cV^\x14\xa64\xb4@\x80??\x9c\xfb\x18\xe8\xc3^\xef6}O\xc3\xccZ'\xc6\xc1\x9a\x00%*\xbc\xf3\x13\xdb\x88\xa2xnFO/\x8e\x92\xe48\xf61L\x92\xa1\x0e\xb7\x0c2?\xa4\xa7\xbe\x05\xdey|\\\xc3,\xe6t\x81\x81 \x0dO\xfd\xd8\xdc\xb2\x08\x96c~9\xba \x83\x88\xcck\x91 \xf3\n1Y.\xad\x0bEC\x8f \x04\xc6\xe7\x8b(^Y\x1f\x1e\xd8\xe9\x14\xabr\xd8\xa2\x8f\xf74\xbd\x8c\xe6\xd6*G\xd1\xaf$\xf0\xb9\xff\xa9\x01 \xac\x1a\xe7\x0f\xcc-\xc5dE\x7f\x8cb\x8c\x16i\xa8sI\xc9\x9c\xc6f\xa4\xba\xa4\xfe\xf2\xd2\xdc\x05\x0f`d\x1c\xe4\xa5\xbf\xbc4\xbf\x1b\xd3\x85\xf5\xe1;b!`\x97\xe9*x\x13Y&\x96\xa6\xeb\xc3\xbfe\xfe\xb5\xb1\x86\xefY\x16\xd37/\x10\xden\xbd\xc7\xf0\x8d\xc6\x1a)]\xc6~j>\x81|3\xc4\xaf\xe8\xdd\x07\x12\x93\x95\xb5\x86\x15\xc9\xae\xfc\xd0d\xeet83ov*nd\xd9$e\xba]D(4\x7f2\xec\"~]\x19\x95\xea3\x08a\x08|\xda\xd7\xed\xbe\xca>3$WK\xbe\x052\xd5\xd0C\xe4\x87xVE2\x11\x9b\xf4\x99>?\x84.\xd9L\xac\xac\xe8\xa40\x9d\xe7\x89x\x04\x85r\xbas\xff\xfa\xffa\xefM\xdb\xdb\xc6\x91E\xe1\xef\xf3+`\xde9ij,)\x96\x9d\xc5Q\xe2\xf6u;\xce\xe9\xdc\xc9\xf6\xc6N/\xa3\xf6\xf8\xc0$$\xf1\x84\"8\\d\xbb;\xf9\xef\xef\x83\x02@\x82d\x81\xa4lgf\xeey.?\xd8\"P\x00\xb1\x16\xaa\n\xb58\xfa\xbe\xb7\xb9\xf2\x1e\xfe\xfd\xb7\xf4//\xdc\xdf\xae\xb6\x07\x0f\xf1Q\xe8\xa5\xdbX\xbb\xca\xcf\xc5\x9a\xa2\xee\xd6\x04\xd1DL:\xfd[\x91\x8ab\xf8\x8af\xde\xd2M\xdb/>\x01Ug\xb3\xc9yU\x1f\xbc9\xf1\xa8yVH\x94np\xe0\xd6u'\xe1\x82\x1bkd4\x0e\xa2\x88%b\xbb\x08\x9c<\x9b\x9c\x93m\xc2\xc86 g\xbb\xc8\n/B\x1a{\x00\xbds\xfe\x9cx\xa3\xd1\xf3\x81\xd4\x0c\x1d\x874\xcd`\xe1V\x17\xa6\\\xda\xd5O\xb1\xe6\x90\xce\xb5B\x98\x9a\xf4\xf4\x87\x9b3\xba\x80H\x0d\x8e\xf4\xb7^?a\xe7:`\xb3\x8c\x16\xadgkH\xb8;\x1f\x8c\xe7<9\xa1\xde\xd2\xcd\xeaF\x80E/br \x83~\x81\xfa\x89\x1b\x8d=\xd1x\xb1m\xd3\xc1s\xb3?\xa2\x87Z\xdfQn\xe42\x0f7\x99,\xf1\xfc\xd7\xfb\xd8\x7f\xfb\x96\xcdm_\x82\xaa\x1d\xedkT+7nI\xcd\x1cTC\xb7\xaa\xd0x`\x86#~\xf0\x808r\x06\xc05\x03T\xb2\xe5:)\xcb^G\x19K\xd64\x94\xe9\x83\x8a\xde\xbc\xa9\x13)p\xb3 \xcd\xe1\xf3r*\x82\x14\xfe\x8b\x06\x8bO{4\x0c\x19S\xf5\x83\xa9G\xc6V\xaa\xda\xea2\x13%\x0eI\xa3\x12 \xa2\xc0\xf6\xbf\xdb\x98\xa3\xdc\xaf6\x7f b'\xe1\x0d\xd5c\xb7U\xd5n\xb6\x85r\x86\xc3\x08\x16+20\x99\x91\xad\x0c.\xc1x\x81\x8c\xc8\xa4\x18 ]\x1c\x9d\x9c\xb1\x1c7\xa3\x9ez(\xf9AK\xbc=\xb5.d?\xcb[v\x18F\x15\x87\x1d\xc1Jf\x9c\xbc&UX\xec\xbaH\xef:7\x13[U\xfa\x9e\xe0\xe4\x05\xc9\x9e\x13\xbe\xbd= \xd1\x8c\x9f\x8bI\x98q\x04\x05i\xf5\x9c\xe6\xdcO\xc9\x8c\x9d\xdf\xef\xb6\xb3\x1c{XP\xa4\xbb\x1ec\xa0\x13\x89h\xed\xcd&C\xf2\xdd\x0b\xc9\x1f\x16\x02\xec\x03'Kr\xe6|\xff\xdd\x908/\x1e\xca\xcc\xef\x9d\xf3\xe6\xc1(J;/\x80\xb1\xfc\xde\x01`\xf5\x1b\xf1\xf4=\xdb+a_d\x97\xdc\xbf\xf9\xfeE\x96\xe8b\xc9\xf7/\x1e\xaaDK\x1d^\xd9\xda\xf5\x82\\\xaf\xc2(=\x00\x8eo\xfa\xf0\xe1\xd5\xd5\xd5\xf8jo\xcc\x93\xc5\xc3\xdd\x9d\x9d\x9d\x87\xe9zQ\xb4~\xbdhT5G\xa9x\xe7/\xceT\xf6\xe8\xf0\x85\x1f\xacU\xcb\xe0\xd7y\xf38\xa4 \xa3\n\xfc\xc5\x8a\xc6\n\x1a~!\xd0\x1e\x0f\xa7d\xb6\xdb\x1c\x01\xddi\x8f\x87\x8b\x84\xe7\xba\x9e\xe2\xd56\x1a\xe2 \xd9\x82E\xben\xc4<`\xa1\x9f\xb2L\xd5P\xbe\"%c\x9a\xd0\x95.(1\x8b*\xa6_\x90BY\x82vAM`\xeb\xdc\x11y\xb7\xb0\x90\"wDn\xcacy\xad\x8bdyT\xe5!l\x92\x1e&4\x13\x9a\x84\xe7\xcc9\xcf\xf0\x9c%\xb3\xdcog~#\x08\xa0,0\xad\xbb\xa7,w\xfa\xcc\xf1\x82\xc4\x0b\x81\xc5\xf5\xc2 \xfe@\xb3\xa5\xf8\xed\xb39\xb8n`a\x18\xc4)d/\xc4\x9f`E\xa5\xaf\x07\x08\x80\xa2\xfe\xd3\xe4?\x13\xea\x07,\x02-\xdd\x15M\xc1\x03D\xac\xaaR72\xf0\x93\x877\x0b^\xfc\xd4u\x88\xc244\xebHddJ'\xcd\xb8\xf4\x0d\xc1\xae\xa5\x060\x84;8/(\x1b\xfba6\x07\x0f>\xc4\x1b\x12*\x7f\x99\xc1xk^N:i\x88@\x9c6\\\x9e\"\xf3\xda)\xa2N?p!\xe4\xfcEpV\xd4\x02\x11T\xe8?\xe7/\xa5m\xb5\xf3\"\x0c\xa2\xcf\xe4\xe1\xf7\x0e\x99\x12\xe7\x85\xa3HP\xe7\xfb\x17\x0f\xcb\xdfN\xd9\x95`<\x0f\x12M}\xa9\xe4C\xd9e\xd4\xd3\xed]\x0f\x01T\xc8`Qwoe~q\xe1BO\xeeW\x1f\x9d\xb8\x82(\xe6\x83\x99\x80\xab\n%\xfb\xd0\x0e/\xa2>\xac$Nl\xde\xc1<\xa2S,\xd1p@\xa3\x19\xc9z$=-\x97\xa8\xcfI\x8eK7R5\x85x\x9c\xc1\x86\x02\xa6\n[\xfa\xa4\xce\xbe\xaa0\x83\x0dW>\xb1\xaa\xbe\x9e.\xe3\x0cN\x1e\xd7;+\xe3\x0c\xee=\xae\xc3\xaf\xf1\x15\xa5\xc2\x0c\xee\xd4;\xab\xc2\x0c\xee\xd4 \x91\x1b\xd5\xfc\xfa`\xaa0\x83\x0d\xbb\x8d\x0b)\xb5\xd9{6\x18B\xb8\xc4\x9d\xba\n\xa4\x8a7\xd8\x18\xbe\x13U\xf0\x11\x14\x9c\xf8\xeb\xebB\xa2`r\x0b\xa2\x85\x16{\xf7\xa8\x10\xf9;\xe4l\x19\xa4D\xd0\xf6\x82c%W4%:L,\xb9\xbc!\xff%\xce\xa9H\x9cS\xff5Fn6\xfed\x7f\xd3\x1f(Ka./\xde\xa1'\x83\xb4Z\xfd?36\xbe\xc8\xe8\xe2\\\x1a\xd7(s\xcfl\xac\x97\x85\x1e)\x99jY\x0c\x8a\x1fu&{O\x1dA\x1d\x88\n\x87\xf6\xc1?$\x0e\x81\x0btA\x8f\xa9\x91P\xaa;\x84\xcf \x9c\xda\x96\xb2\xe5\xc0\x8b\xe1\x1a\xc3\x91\x0f\xf6\x89]M\xb4uO6\xfc\xc9\x0eHu\x11\x9b\xd9\xb6\xfa\xce\xc0\xa3\xa4\x15B\x8a\x94\x9fL\x9cA\xa5\x81p\xcf^1\xd158\xf72W\x14\xddu\x86\xb0\xec\x07\xed.M>\xb6x\xdc\x90N\xb6\x133P\xfd\x15\xea!\x19\xf1\x88\xa8m\xa6\xd9\xf8b \xa1!\xda[\xe4\x05\xac\xf2\x07\x0f\xf4\xcfRN#h\xb6\xd7`\x99#a\xa6\xe2W\x87 \xd3\x91\x9b\x0dI\x00>\xb2\x16L\x06\x8e\x85\x88\xc7\x1f\x19\xf5o\xdc\x81v\xa6\xe5\xbe\xc4\xee\x0e\xa0QQ\x9aM \x12\xeb\x99\xa0\xb6v\x16\x97\x9a\xa1:3\xa6\x88\xdf\xe7\xafVKQd\xb6^6\\ \xcd\xc7q^\xc6\xc1\x05\xe7\x92\xa2\xcd\xca\xcfd\xbd\x85*Y\xb7\xa7}i\xbci|l5\x8ey*G\xf0g\xe9\xca\x02\xbe\xd8^\xcd\xa7F5\x97\xb7\xa9\xe6\x1f\x8dj\x16\xdd\xd5\xe8_b5\xbej\x1ca\x19\x8f\x8f.y\x02w\xd3\xe2\x7f\xed\xcc\xcbx|L#i\x0e\xe0x4\x8aCzc\x05)\xfc\xe1h\xc8L&4\x0b\xbc\xcc\xe5|\x1c+\x0f\x85\x8e\xaf\x12<\xcc\xab`\xc6\xe3\x93U\x9c\x05\xe0K\x90\xc9_\x08H\xe4%7q&\x81\xf4o\x0c\xccW >\x9a\x9d$p\xa3\x0e\x91\xfd\x9a\xd9o8\xf5\x99/\xfd\xd6:!\xbc@\xc8\x0f\x0b\xe0[\x96Q\xdf\x04^\xa9\x04\xbc\x80\x8a\x9f\x04\xb0)\x12\xe4\x08\x1c\x96\xe7\xa9\x18\xb0X\xfcG\xb2\xe5L\xe1\xd3$2\x81\x88\x80\xfc Z _$\xa0X\xe6\xc4\xeag\x13\xe8#\xcdX1s \xcd\x98m\xd6N\x19\x03\xf3\x0b'\x85\x1f8\x80lQ*\x7f! \x19\x0d\xa5\xcf\xc9T\xfeB@\xf24\x06I\x8f\x93\xca_M\x90\xb3`\xc5t\xb4$'\x0bV,\xc7B\x1ae<\xfe\x89\x87\xf9\xaa\xec\xdd\x1a^m\xfd\xfb\x99\x06\x99l\xfe\x95\xfce\xd0\x11\x18 \xf6{c\xff^\x8f\xb3\x84z\x9f{\xec\xfd\x1f\x1aeK_\xcb\x82\xe0~\xfdR\x1f\x98{\xf5\x8b\x1a\xb1\xf3\x199 \xea3\xd5\xcc\xc2W\xbe.\xfe\xc8)<\xf4ft\x81\x1du\xd2\xd3{\x00\xba\xfb\xd6 ?\xeap\xc6\xdd\xb5\xcb\xeaMW@\x05>\x06\xb9\xa9/\x86%\xfeA\xba\x1bU\x0e\xdc\xd4\x1e\x01\xb9\x8f\xfc\xcf\x06\x96k\xe0\xcb\x84\xd1\xcf\xcd,\xd9\xb0u\xe03nm6\xcd\xfd\x00\xcb%\xa6\x0c=+]a\xdb\xfbp>$\xaf\x06\xe4U]\x1e\x93\x01\xb1\xd7Vx\x1c\xe7\xe9\xd2E\x86 \x1b\x92W\xb3\xec\\t\xdcB7\xb7v\\j\xac\xdd\xef\x8c\x9cH4Y\xe0\xcb[\xceI\xb0Z|\xf3v\x0d\xc9\xb7\\Us\x9e\xac\xee\xb7\x0b\x1f\x19h\x88\x11'Q?Z\xbap\x9a_\xae\x02)\xb4\xd4\xbfn\xd7\x8d\xc0\x128E\xad \xe9*\xce\x1a\xd7\x8b]g4a\xf4~\xc7\xe1\xb5\n/>\x14\xad\xd3?\x99=$\x01\x82;\x7fj\xe0\xce\x1b\xa0\x9b\xe4\x89\xd0\x87p\xfa\x11\xe5\xfd\xe5%\x07&k\xb8\xa4\xe2\x94Fs\x12<\x1d\xae@\xb0\x0c\xb6\xba\x14\xc7\x1f\x96\xb5\xb4\xd4\x15\xac,\"\x90@\xc6\x14\xc5\xb2>\xb3\x9b\x05\x8b\xf0\xbc0\x88>\xe39\x82\x9e\xc1s\xd4\x1d\n\x96\xa5Ug\xb1<8\x0e\xf1\xac\xab\xcbN\xe1\xcd\xcf\xe84\x89Uf\x95\n\xc5\x89\xad%j5w}\xf3\xff\x80\xff\xbe\xe6WW,\xca\x83\x8c\xad\x90\xf2\xe4\xc7\x9ap\xedW\xd0\xa2\x99\xd1\xd1\xefG\xa3\xbf\x9d\xab\xff\xd3\x8b\xdf\xc6\xbf\x8d~\xf3\xcf\xff\xf2\xe7\x87U\xf0\xbf\"\xb7\x95\xff i\xb5\xd3\x06#B\xfe\x8cJ3\n\xedJ\x1d^\xd0\x199\x03\xf2\xfd\x01\xd9\xa9J0\x02[\xa4\x92\xbfA\xb0\x01\xe4{\xbf\xb4\xc5\xd8\x13|{\x15\x17u\x85\xc4\xf9Oy\x03\xfeW\xf03\xfb\xe5\x0bq\x7f\x05\xf3su\xcf!\x08\x98\xc7\nW\xfeU\xdf\xbd4\xdc\xbc\x16\x04NUFb\x86\x03\xc9\xe8\x824\\C\xea\xcc\x88\xaeX\x1aS\x8f}\xfa\xf8\x9aT\xe3ph\xb9\x94\xbee\xa8e\xc7 [\x07r\x9e\xb9e\x9dRZ[\x1a\xa4\x05,u%\xa99\x17\xb4\xbe\xa5\x9d*\xbcv\xee\xc6\x16\x08\xd5s\x18\x92\xd7Q\x90\x054\xd4t\xbb\xa0%\xe7C\x92\x0c\xc9\xd5@\xfa\xd8o\xfa\xf4\xfb\xda\xe6fP|\xfd\xa4\\\x98\xf0\x8d\xf71\x8b\xce\xe8B\x9a\xdd\x1cE\xfe\x87\xf2\xda*\x85\x0f\xb6,\xf6\xebZ]JA@\xd6\xa5[k\xe9\xa7h\xfe\xd6\xb5@)?\xce\x8a]yN\x0e\xc9\x89X\xdeR\xf3\xebD\xaet\xb2M\xae\xc5/\xb9\xfc\xadKC\x02\xf7@\xe0\x1b\x92\xaf]\x14O\xc7\xc9\xf2\xa68\x82\xe6c\x9ag\x1c\xc2\x88H\xd3\xba\xd6r\xc1x. M\xfe\xe3\x9fr\x14w4\xeb\xd3\xbfSwZ\xa9\" r\x99gY+-\xf7o\xd0\x8dNz\xb3\xa3Q\xff\xe8O\xbc(\x99J\xab\xbeN\x0f\xcc\xd0CCQ+\xd6\xc8\x03l\x83\xb3\xb0\xb8\xd2H\xe0J\x03?\xc7@\xa7\xa7~\x8f\x91t\xc6\x89\x06/\xee\xb3\xa4\xc5T\xcf\x0c)\x11\xd8\xcfP\x0d\xfa\x1ek\x03x\xa7\xfe\xa8N\xa1\x04\xe2\xa2\xd8\x0e\x04\xfdt8\x87\xd5\x8f\x03\xba$\x92\x96\x01\xcb.7P\x7f5&\xc6$6\xdc\xfd\xe3\xebP+\xa2\x08\xa2-\x80x\xf6r\x9a\xe5\xfc\xbe\xe2 \x94H\xdd@-\xa6\x8e\x06\x135\xa29\xc1\xdc\xeccOA'\x9b\xf4\xe4\x9fK,\x0c\xeb\xe8\x90\xbcm\x8e(\xc8\xd4\xc4\x87\xbcz\x9bk~ ]1\xd8\x10(\x01\x85.\xab\x94\xda'\xb9\xd4 \"\xdb\x07\xc4\x01\x15\xa5\xbc}\xc2\xfb\xc6\xcb0\xcc\xc2#\x9f%g\\\xf0\xf9\x81'\xdbA\x0eID\xa6\xfa\xf4\xa9\xd2\x1cf[\x1a\xad\x07\xfa\x03\xf4\x8eZ\x80^\xbfT\x15\x83\xech\xd0\xea\xd3\x1d;\xb5\xfb\xf9s_\x17\xe1Kp\xe2\x80\x93\x16\xb5\xad\xe6J1\xf7\x1c\x1f\x14\x0b\x85\x8f\xa5\xce#\xccRB\xca\x04divP=b\xc1\x7f\x98\x15\x1aYZUL\xd0\x1b\x86\xe2\x98M\x01R?T\xadu\xc0\x0df\x84p]\x83\x9d_)Q\n\x0c\xdc\x89\x1b\xb4\xd1\xc5f \xda\x86\xd3\x12\xbd\xef\xa5\xfcQ\x13\x8aT\xc5[\x18\xff7\x0f\"\xd7qng\xa7O\xca\xa5\xfc\xb3I\xa3 \xce\xf37\x15\x02,\x19{K\x9a\x1ce\xee\x8e\xd8\xbb\x90\xbcM\x1225\xe2^\x10\xeb\xca\xab\xd1\xb7\xbd\xa5\xa6Z\x89\xed~\x97X>\x86\xd3T\x94\x17\x08\xe2\x7f\xc6bs\xa4\x83\x89\xc0\xe8 \x84\x86\x06\x0c\xd8{\x05Z\x1bY\x9c\xd5i\xfbB\x94\xec\xca\xces\x12\x92\x17$\xd5\xb6\x94$\xdc\xde\x1e\xe8fI\x0e6\x19\x92t\x16\x9ew\x912\x8d\xe8\x14\x1e\x0b\x8c\xf0\x14\x9ba1\x8c6i\x0e\x0d\x06e\xdc\xceHv\xb0h\x81\x9b\xc1\xc9\xdf\x8czR7\xe8\xab\x16\xbb\xc5\x16\x00\x19=\xbe\x8c\x82o+\xd7\xefb\x8c\xb8M\xdc\xcb\x15 \x82f\xda\x96%\xb9\x17J\x9a\xdb\xa4\xb3\xbaMh\xe6\x9d\xda\xd4)\xba\xe56\xf1\xacn\x13\x9ay\xa76\xf5\xe0\x03\xb9M\xec\xaa[\x85f\"$\xb3\x9d\x01\x7fW\x14j\x13\xaapE@7`\n,\xa3 \xc4V\x19v\x8b\xf8\xfa-\xde\x95\xda\xd1\x15M\x8c!\xb9\xc6\x83\xe3\xde\x95\x03\xec1\x1f\x97X\x83\xee\xf0\xc9\xcee\xd9\xc1t\xfe\xd4\x8f\xe9\xac\x9f\xfc\xc8\x0co\x80\xade\x8cI\x0b\xcf\x98 >\x00\xf4\x03:\xf3\x08\xc3(Y~4Y\x1f\x7fl\x96 \xe7\x91Yq\x85+\xeb#YN\xed\xecZ;\x1f\x05\xfd\x0cD?\xd3\x01I\xeb\xed\x0e\xa4\xec\x1fX%pU\xf2\xc7\xd7\xc1,8\x07B\xbd\x83\x9d\xb33\x8f\xedW\x8e\x92Z@\xb8`r\x08\x03G L\xad\xdc\xe6\x89`\xcc*\x0c\x1fka\xf8f\xd8A\xecB\x11\xd1\xed9\x90\x81q\xc5dfn\xaa\xd1\xc4\x83M\xd6x\xebZ\x12\xe0\x10\x98\xa6\x87Pb.\xa6\xb0}\xf1\x0dI\xdc\xb5\xa7Hek\xc4\x03\xb2\x15#{\xe3\xcb\x172\x87\xb1\xc0\xf3n\xb5o\xaa_\x9e\x0f\xd0\xca\x1f< \xb1\xa8OL\xc1\\\xfc\xb0\xecR\x91\xd7!\x81\x90\xfbM\x14E\"\xfb\xe9\xa7\xa0\xe0Q\xe9\x94\x98\x1aC85\x07|;\x95k\xa3\xdc\xaa=j\xaf\xc9n\x06\xf6\x9d\x9c\xb2\xacm\x1b\xb7\xdf\x8d\x17\xdf\xdb`\xa3w\xa3`\xdf\xa6|^\x7f\xca\xddrX\xedI\xd1K_u\x81L\xed\xd8\xc5\xdf0\x10k3\x05\x84U\xd4l\x80\x12\xd8\x15\xe3\x98c'\xb2\xf5\xfc\xbd5\xd7]\xb0\xb6\xac\xc2\xda\xb2~\xac\xed\xdd\x99c\nZz-6|\xd6L\xc5\xd1\xe3\xd5\xe6m\x02\x05\xd0\x8f\xbfU\xb5\xa9\xc1\xc6\xf3\x92\x8d/G\x0b/\x16vq\xffx1\xaf\xf25\x03\xbd[\xbc\x07\xcf+\x9f1\xe0\x11\x1aKg\xa5\x05q\xa4B]e\x06\xff\xabIr\x89\xb8#uF{\xa2\xc8\x16 _\x03\xf8\x8c]gJ\xf8\xe8V,>\x03PF(\xe4\x16\xd6\"d\x9b\x04\x03\xe3\x98\xcc\xc9!\xa1P.\xaf\x95SW\x92\x8e\x14\xf2\x1aE\xc2\x1a`\xd1\x81\x10\x0bg]\xdbL\x8a\xffy\x07\x0e\x85\x8b]\x84\xed\x1d%F\xab\x1b\xd5 u\xe6\x91]\x95\x10\xabyC\x9e\xfd\xff\xe9\xe2\x19\x8f\xd6\xf9\x95c\x87[\x01\xd8\x0f\x07iV\xdezvT<\\\xed<'\x11yA\xb2B\xfa\x15mo\x0fH6\x8b\xce\x95\x0e\x87\xcd\xf2\x9c\xf4a\xe7\xda\xf8\xd9\xde<\xe6\xf58\xcdx|\x96P\xefs\x10-\xbaN\xc7\xce6\x81\xc3\x82\xb6&-\x19\xf5\xdboo\xb9\x7f\xd3\xd2\xde\xc4u\x9e6\x1f\xe93\\\xf6\xd9i*C\xea\xa7\x8f&\x8bA6\xe0\x07\xa2\xf4h|\xc7\x03\xf1\xe9\xb3\xba\xcb2\x0e\x86\x87\xa3U:\xea\xf4\xdc]_\xeaj\xeb&n\xe1e\xdd\xe5C\xe2\xac\xd2\x913\xa8\xe3\xda;\xb5\xfb\xe1\xc8\x1d\x0f\x1e.n\xd9\xbe\xb2u\xc9\xb0\x1b\x85kW\xe0\xe3\x8c\x7f\x12\x14$\xe2\x02\xfc\xeb\xbdv\xceF\xa5(\xaa!\x19\x07\xe9\xa7(\xc8B\x96\xa6\xef\xc0\x7f\xd9\xa0k\x1cZ]\x19iQ\x02h@9\x97\x9c\x87\x8cV\\\x17\xcb\x0c\xa5\xc0_z\xe0\xaa\xed\x04\xady\x11\xa4\xef\xe8;7\xab\xa1\x07\xbd2DU \xe80\x9c(s\xc4?\xe5\x83\x07\x84K/\x922\xd2\x05\x99\x82\x08\xbc\x11!\x80HG\xe3`\x96\x99\x04+\xd0\xcf\xca\xc4y\x13_7N\xf7;N\xca\xfe\x0e6)\x0f\xff~\xb7\x8d2\xa8\xec\x94\x11l\x95\xfbl\xf7Cwv4\xfa\xdb\xf9=m\x16g\xf4\xe7\x893\xb08\xc3\xbfCk\xfb\xb5H\xcb\x0b\xfe\xf8\x8a.\xae\xa2 z\xe6\x17\xdb\xb8\xb6\xd8\"y\xf9\x90\xcd\"pq-M\x89\xa5\x14>\x82\xd54\x8b\xec~\x05\xc8m;lpg\x8fw:\xf7\xafej\xbes\xbe#\xdb\xb0\x88\xc8\xb6x\xb9\xe7\x86M\xcc\x86i\x92\xa9\xda\x10q\x08\x87\xecL\xd9\xfcb\xa2l\x8e\xcdE\x97A7\x01?\xa9\xea\xa6\x1b\xdc>\xa4 !(|\xa7B\xda\xff\x07\xf7\xe0[\x13\x84\x9ft\x931\xbb\xce\x12\xeae\xbat\xd9\x1e+s\x8e\xcf\xc2\xbd\x84~\xd9}2\xc0\xec\xe09z\xe8h\x9e\xc1\xb2\xcc\xa3\x19\xabn\xc0s\xcc*=\x9a9?\xb3\xcb\xcfA\x06\xae\xff\x80\x1c\xb9*\xde3\xc8\x7f\xcb\x7f/3W\xf2E\xe6\xac\xd22\xe3\xedi\x99\xfe\xbeL\xe6\x90\xda\xf8jm \x12\xe3`hN3\x8d\x82\x15\xb8\xf8\x02OM\xdcu\x8et\x823$\xe5\xcbI\xe4c|KQ:\xc8\x98\xf4\x14\xd6R\xc7k\x0d\xd3Z\x93\n\xf5g\xad\x05\x9cqa5d\x89\xa0?\xcd\xae\x9c\x15)\xa2\x86\xf2\x0d:S]\x81My\x02\xe6v\xde\\\x0d\xa6k{q\x00\xe6\xfd\x18\xf6\xca\xa0\x8a}\x01Q\x1b\xae\x82\xc8\xe7W\x80\x04\xa5\xa8\x8d\x04csf\xca\x97!i\x02\x14\x83\xdf\x0e\x06#[\xbe\x0e\xaac\x82\xb4\xa5\xa8\xa22\xb4\xc6[o\x9f\xd9\x82\xc6\xa13v^P.\xe2\xe5y\x03d+0a\x90h(\xe2\xe4 \x1aE\x0d\x113\xce)\xa2\\b$5\\D\x91\xbc\xd2.P`\x88\xce\xd1\x8d_qIJ\xee\x8e\x946s\xfc\xdct\xc1,%_\xbb\x93\xba\x0f\xe3\x1c\x97:J\xc7\xcf\x8f\xf6\x8cCE\xbb#~\x86b\xc7\xb0\xdb\xbd\x19h\x13 zY\xc6@5\xeb\xf5\xac\x07\xaa\xe3-\x99\xf7\xf9\x92_\xebHU:,\x1c\xb8\x84\xe7\x95\xd4\xc3R;d\x0c\xc5\x98oj\x8c\x8c!R\x9b\x05\x1d6\xa3)\x98\xaa|\x1b\x88\x95\xe8x\xa1$ nf\x11\xed$\x1a\xecX6\xb2A\x9a\x93\xb2\xff\x98\xcf\x1a\xf1\xc8\xb0\x9aR\xe8f\xb9f\x850\xa8m\x10\x10(\xba\x15\x80^k\x80F\xfeWX\xddx\xe3Tx\x7f\xd5\xbd\xf6o(\xd8\x9fd\xd8\xc16H\x15\x99P\xcfg\xa4\xccFX\xed\x9e*\x90*\xf4P!^\x91\xa7\xdb\xa5\xabJ\xc8!h\xe8[\xaaR\xfd\xc0++\xddc\xd6K\xeb\x9c\xe6\xd0\xb5\x9e6\xa6\xd9\xff\x06\xeb.\x1b\x9b#\xd9\\O\xac\xa7\x8b\x8dj\x9f\xcb1\xca\x8a-uh\xfc\x9e\x96\xdfm\x1d%sR\xcc:aN\xa1F\xf9kJl\xb7\xffU\x8f\x1f]s\xd1M\xcc\x92\xc6m'\xa6\x11\xde.\x9b\x95\xfb\x9d]3/\xcf\xd8{\xf5q7k\xb7mK\xc74\xa5\xb1\x1bv\x1aI\xae\x0b\x85\xf6\x88\xaeZ,\xe4Azh`Ce\xfbk\xe8k\xa2\x14\xbf\xf9\x14G\xa68Xr\xfb=\xd1\x10\xee0\x82\xe7\xc43\xc2\xf7=\x1f@j%\xa9\xdf\xd7\xe6P\xec\x1f9KnNA\xf7\x96'Ga\xe8\xca\x9b\xdb\x99\xe8\xf5\x81\xa0i\xff\xcf\xe9\xfbwc)i\x08\xe67Re\x01D\xd8\xdf\x9d\x83\xda\xcc\x81\xea\xfd\xf9w\x03\xe9\x02`\xe79\x89\xc9\x8b\"\xf4\xd9s\x12oow\x0d\x01Q#\xee\x83\xd6Y\xdc!\xb3$j\xdc\xfdR'\xc3\x1f\xcfy\xb2\x82\x19\x08\xe0g\x9f/\x12\xf5\xd5\xa5\x1ew=\xdeb\xec\xe1\xd2\xb5\x1e;\xcd\xf6,\x95c\xadg\xe0\xe4\xbb\\d\xcbn\xc9*.\xfa\xec\xce\xb5\xe7\xa0\x01\xa8\xf4\xf3u|\x19D>\x1a\x9eO<\x1e\x8f\xb2\x84Ko\xb2\x1e\xa6N\xd0\xaaM]\xa1<\xba\xf0\xc0\xda\xea@\xbfe\xf3Kd\xab\x10`sn\xca\xe3\xe9\xc1\x03\x12\xa0\xdaq\xf8\x06\x13\xdc\xb4\xa3\xaa\x85;\x1b\x88}\x8b\xcc\xbe&\x17\xad\xd5\xe0\xb8\xb1N\x9b4+\xaeZ\x84\xe1x|N\\)'\xe4pG\xa1M\xde\x00{\x0f\xf4\x0f\xc1\x8d\xeeX\xc4\xf2\xc5MD\x11\xd2\xad\xc4Y]\xb8\x1aD\xec4I\xe5]\xa1\xab\xbe6$\x93\x1d\x90\x18\xb5\xdc\xc9\xb8\\\xeai)\x8f1RcK\xb7VbH0\xa9,\xdb/\x91\x0c\xbe\x80e'\xca\xe2\x1a\x1c\xaf\x039\x8b!\xd6\xa3\x16\xf2*x\x03_W\xcfr\xd9\xd4JJ\xf1\xc9&\xa4[\x03E\x01\xb5f\xd9\x81y\xaec\x0d8.\xf3\xca\x8au\xe2\x01\xd9\xda\xaaC\xb6\x926u/\xe8\xdfl\x7f\xda\xb6Fs*\ne\xb1\xd6\x05\xa8\xf4\xab\xa4\xd7\xd66\xed\x1c\xe9\x05\xb6\xc5d\xa5KA\x08\x02\xbd\xb7~\x02\x9a\x06\x1a\x85\xdc\xa3\xed*I+\x1ee\xcbv=\xaa\xae\xaf]1f\xd3n#\x10a\xb5\xdc2C\xe3-\xea\xa0i\xf5\xd32\xaa\xaa\x82>\xdf\x8ej\x0c\xa2~\x9a\xc7\\\xc1\xb0[(3eb*\xdd\x11H \xa99?,\xbbdl\xa2zZ_(\xfc3u\x05\xcd\xe2\xcd\"M\x9dC\xea\xad\x04\x17f5\xce\xe9\xc9\xf1\xc7\x93\xb3\x8b\x97\xef/\xde\xbd?\xbb\xf8ptzzq\xf6\xe3\xeb\xd3\x8b\xf7\x1f/~}\xff\xe9\xe2\xe7\xd7o\xde\\\xfcpr\xf1\xea\xf5\xc7\x93\x97\xce\xed\xbfi\x08K\xeaR\x11\x15o\xb9\x1e\x0d+\xc0\x85\x1f\x94\xe0q\xa0\xf2\xf2^\x0f\x8e\xdf\"\xb3\x90V\xa4\xf6{\x90\xfa\x15\x9c\xe6\xe2\xc7Z\xad\xae\x88K\xc7\x86\x1d\xc8\xaf\x90[\x10\xe9\x9f\xacq\xd3&\xc5 \xe5)Z\xa6\x1f\x92\x8cl\x8b\x92SiN\x01\xd2\xc8\xad\x9d\xba\x9c}0$Y\xb9:*#\x1c\xe2\xee\xd9\xb8\xe9K\xc2\xd0\xa5\x96\x94\x8b2\xf6\xab\x17,d3\x92!\x01\xc4\x03\xea\xd5\xd7\x99[\xbf\xa8 V\xe4\x10\x0c[\xbc\x80\x98=\xb7X@\x08\x90\xc0PDo2\xca\xdbb\xf7OI\xea\x96\xfa\xef\x03\xf9\xd1\xad\xc9\xb0\x16\xe0\xb7]7\xa9\xe0\xc6\x0c{\xf4\xa4b\x8fn-J4\xf7 .\x0ef\xe1\xb9\xe4~\xfa0>rEv\xb36\x80\xda[\xa1,\x8a\x1b\xa5Y\x90l\x9dl\xda\xed\xe5\"r\xbd\x08\xa6$\xefX\x04\xdf\x96\xe8\xb1s\x1c\x06!\x19X\xe8\x9f\x8a\x037\xd7\x01xg\xa8K\xb6\xd2n\xb7\x14\x87&\x16\xf9e9\x9cm\"\xbf2l[\x8b\x14\x12\xa1\xeaJ\x99oU$\xa7\xbf\xaaN\xcc\xe2\xd5\x0ei\xe1\xbf\xc0\xe7\xa3\xb9\xf7\xec\x02\\\xf5-\xaft5\xcd+\xd7r\xa4\xcf!-U\xee\xeez`nt\xbb\xd0\xbcE\xa0\xf8A\x9aoz\x8b\x90\xf6\xbaE\x08;n\x11\xf4/\xfc\xb8\xdap\xb9j\x81E\xc9\xff\xd8\xad\x9e\x12\xd7y6q \x82\xfe\x1fmRp%\xaf\xbe\x1f\xe1w\xb9\x13\x1c\x159nC\xa1\xf7\xbf\x8b\x9c:\xe8\xbe\x1f\xb1\x9c\xf8\xa6fT+\xc5@\x1b\xe2p\xbb\x187$\x07\x9d\x0ed*\x96QnE\xd7V\xac\x85]\xb1\x16\xaa'n(\xc5 \xa1:F\xc9\x8b\x032\xd1\xf2\xb9=G\xf9~ g;\xe7\x03\xe9\xdc\x16\xe644\xb8r\xa9\xc8K5\xd7\x00\xc2\x9b\xe6\xfc4R\xfa\x1efUq\xbc\x94S\xfc_&w\x0f6\x95\xbb\xab-\x9eK\xc9hZ8m\xec\x10Rv\x8c\xfa\xbfD\xfcH7\x92\xfc%\xf5]\xd7E\x92v\x10\xe3\x92\x9e\xc2\x07Z\xda(F%%\xe2\x96\xfc5\xafH\x9d\x1ar\xab\xa8.\xb7B\xa4o\xcd\x15o\x17\x995+\xac\xc9\xc0\xda\xe6\xf1\xb6D\xdbf3#E\xc9Yi\xc1\x89P2\xea\x82\xdb\x8e\xee\xa1\xafY)\xc5\xd8\x90\xfd\xff\x96\x94\xc5\xee.f\xcf\xe4\n\xf8]\x19\xe4X\xda\xf2l\xaeg\xa3A\x9f*v\xc3\xa85\xfd\x90\xf0\xa1\x9dQ\x04Y\xbfv\x90\xd6\xd6\xec\x14\x1cGgC8;i\xdd`\x99\x0dE-\xc5\xe7\xa4\x06\xa9\xbd\x86\xf28B\x17V\xc7\xaa\xe0bU\xd0\x86\x05q\x04\x12T\xd8\x0fQ}M\xf0\"\x9a\xf6d\xdffg\xa5\x95\xbeg\xaer+h_DR\x1d\xca9;\xf9\xe5\xec\xe2\xf8\xfd\xbb\xb3\x93wg\x16G\xacD]1\xc3\xd0X\xa2 \x8bg\x0e\x07\xb8\xcf\xae\xbb\xbcR\xce\xd5M}\x17\\\xc6{UG\xe7\x19K\xca\xfaP\xb8\xaf\x03\xcc\x1d\xa4m14\xdd\xd8\xfe\x8f_\x07\xa7'g\x17o\x8f>\xfe\xf5\xd3\x87\xff\xb7\nH\xdeq\x1c\xdbVCf\xf8\x16\xbc\x1dIp\xdb/\xd7\xcf\xc9\xea\"\xb4\x8f\x1aG\x14\xb5\xcd\x87v\x9c\x809r6W\x89\x19Wz0\xa5\x92\xa0\xb0\x9f\xcf\xe2\x1c\x84\xab\x97V\xe7wp\x0c\x0d\x0b\x973\xed'\x1f(6\xb5\x83\xf8\xdd \xcbn\x90\xb5\xf5\xe6B?\xb0\xe1=\xa9*\xddZ\x15\x0cC}\xcb{\x9d\xe4\x00Qc\xb3\"\xeav3\x99y=\xe8\x02\xf1,\x04E8\xf3z\xa8oIU\xad\x059$\xee\x1c\xa4\xb9su\xe4\x97\xc1cVC\xb2\x1eB$\x9e\xc1@\x86\xe3yK\xb3\xe5xE\xaf\xdd\x95y\xc0\x0b\x80!Y\xd5\xce\xfc\x18|\xf1\xad\x80\xb1h/\xabB:\x95M\xb8(\x11\xe8\x91\x04s\x17CBg\xcbs\xdd\xa2L\xd9B-\xb7\xb7\x07C\x12\x0b\xf2b\xad\xf9|\xed\x81\xc7E\x9c\x7f\x98\x8f]\x7f\xab\x9c`>h\x1a\x03zR\xbaUk\xb2\x89\xf5]\x980\xc2g\xde\xf9\xa0\xcdm>\xf8?\xd2\xe8}^\xfa\x0fi\xd2\xb5\xcdK\x17\x82\xf6\x00\xc3\x7f\x91\x95\\o=\x087<\x05\x9b\xe7^f\xfah\xb5\x84\x9c\xec\xd3\x81bA\xf6vLF\n7\x05\xe6\x92|!\x80\xeb\x96y\x1d\xa8\x98\x94\xf4g\xfb\x9eU'\xef\xdb\xf7?\x9d\\\x9c\xfc\xf2\xfa\xf4\xec\xf5\xbb\xffl9|\x89y\x00w#?\xe3\x1c\xae\xf4\xa9\xbb\x94{\xcd\xae\x11\xaf\xac\xc7E\n\xb1L\xed}\xcd\xeb\xc7\x13\xd8\xc3\xef\xde\xbf<\xe9;\xab\xdd\xe3\x7f\xd7\xfd\xdbB\xa2\x93\xfeT5\xe9IY\x93\x8em\xdbkV\x9bg\xf8-$a\x85\xc5w\x95\xb4H\xd4\xa9b\xe0\x05Qe\xd4\xbbm\xe6Q\xd5s\xcd\xe9\x0b<\xf8\xb0\x19b\x8f\xe1w\xf0\xc4\xde\xfcH\xbaBl\xb6\xf4O\xf8\x9bEt\xedA\xea\xadD\xd7\xa5\x9b'\xd4\xd6W\xb9\x17\xa8\xfb\xe1 \x86\xa7\xae\xfa-8)\xa5\xdb\xbb\xbb{ \x97\xde\xdd\xdd\xad\x0b\xb4\x89\xa1x\xb6_\x1b\xb4\xdau91\x85\xccy\xc7\x81\xbfV\xb6\x1b\x86\x17&\xd60Z$\xe6} \xa8\x89H\xa1\xb7\xb4\xb3\xe7\x82^i*\x89U\xc7FV\xbfu\xa0*x\x0fN \x11\x15\x0f\x81=.N\xde\xfd4%N\x9cp?\x87^ \xe8\xe4\xe7\x93\x1f>\x1c\x1d\xff\xf5\xe2\xf5\xbb7\xaf\xdf\x9d\\\x9c\x9e\xfd\xfa\xe6\xe4tJ\xb6&\xd5F\xd4FJ\x8b\x0b\x9b\xdfE\xa4\xd8\x1b\x13M\xfa\x8e\x8a\x0dL\xb5\x80v\xb9j\xdd0\\?Z\xbc.>\x9d\xcb@\x01\x1b\x88\xf1\xda\xba@\xa1\xc2\x14\xa2U{\xe0k\xd7\xde#\xf0\xe9\xd1y#+\xf8\x9c\x0e\x9e/n\xf1\xbd\xa4\x1f\xd4\xba6\xee\xcd\xf3 \x06\x15\xd8%\xb8\xd8b\xb3\xf8\x1c\xb8\x0d\xbf~G\xda\x8f\x1d\\\x83\xf5n_k\x1e\xbd9@?(p\x97C\xb2\x1e\x0cH2\xae\x07Sq}`\xc3\xf2!\xf8b\xca\xa4\x1f\xa2\x96\xb1\xd3O\x0f\xbfJ\xfa\x91*JTV\x9dT\xa8W\x1f\xdc.\xd4\xbd\xa2\x8a6mM\xfa\xc4(#\x06w\xcd\xdd5l\xfa~\xa5TOW\xfd\xa0\xc57\x16\xd0\xfaZKW\xf5\xa5\xdb\xaf\xbeH\x8a\xcf;\x98Z\xd2\xca\xd8\xb6\xe7\x96k\x9c\x0d\xc8V\xc3\xc7[\x0cV&\x80\xf8\x90\x05.\xcd\xf5\xc1[[|.\x98\xf5\x8d\xa7\x0em\xd7]Y\xdc\x96\x13\xbdj(o\xf1vG\x88\xc5\xe3]\xd4\xb9\xa55r\xc4O\"\xf3A\xc6\x84\xa3\xb4\x8c~\x90Q\xa9\xa4\xd4\xd0\xb1I5\x94\x17|_\x07\xca\xb5\x8c8\xac\x1f?V\x13p+z\xa2\xf3*\xdc\xa2d\xd7PV\xa7\x96\x8bs\xa5dW\xf7\x89\x99*U\xbd\xba#\x80P\xb5\xa5\x9e\xeeU|h\xee=y\\'P\xe68\xe5\x13\xcb\xfa\x1a>9}Y\xdf\xbe\xa2w&\xf5\xea\x96\xaa;\xf5v\xacK%\xfbzO\x05Z\xaa9\xce\x14Xd\x17\xbb\xd2\x07\xc7T\x7f`\xb7\xf2\x97\xe8\xca/\x15H\xcb\xe5rS:\x7fU\xd1 M\xdf\x15\x18u\xc8\xc8\x01 \xc5\xbe\x96:\x89xX\xe8\xc6\x02\x85\xbb\x0b\xe9\x94Z\xaa\xf7(\x12^*\x97Wbf\xd5c\x0d(*B\xf5\xa9\xa2\xb5_]\x82\x17\xcd\xb1\xbbB\xe9$\x8fGi\x96\xe4^\xaf\xebALM\xcb\x88\xf3eq\xf7\xeb\x89\xad\x9c\x06\x19;\xbb\x89YA\xf4\xcb\xbc@i\xc6\xd4\x92\x8d\xd0\x8f\xcd\x8c\xca%l-_\x0e\xdb\x0f4\xf3\x96\xd2\xffZ-?f\x91\x1fD\x8b\xb2\xedH&h\xd6\x80\x03#<\xff\xa3\xf4\xb9\xa5\x15\xeb\xb6&\xb5\xfcW<\xf1\x98\xbc-\xa8dk\xc1\x9f\x18!d(\n\xb9\xa0\xc6|\xb5|\xb5>j\xa9\x80,\xdf'r\xb1\x16C\x9e)\xafOJi \xef\xc71\x0d\xc3K\xea}N\xeb\x1f\xa2ah4\xe3\xe7 \x0c?I\xa4\x0c\xddi\xac\x0c\xabZD[\xe46\xab%z\xbd\xb3\x1c\xed\xe9\xc5\xf66\xbaV\xb2\xd6\x85b'\xdd\xe9\xd0\xb8\xf3\xe9\xaf\x83G\x14\xe6U\xe3\xaa\x14}\n+\x11{!\xcf\xf61\x1ce\xe8g\x0eJ\x82\x0b\x96\xc9\xe5%\xbdl\xb5|\xc6o\xf5\xbeS\x7f\x14v\xd9r\xb7X\x89\n\xc1\xfa\xd8x\x1f\x07)\x04\xbe*f\xb7\xe5lv\xbd\x96\xb6-\xcb!\xd08\xa8B\x08I\xca\xd0F\x13\xfafD\x86%1LV\x97\x1ay\x1f\xf6\xf2eF6\xe8\xf8\x87\x9d\xe9\xb3tl\xb2\xeb\xb6N\x05\xd2\xb8!\x91\x1e\x06b\x1eD\x99-\xa0\x07\xee\xaa^?E\xd4Vl\xa5V\x9b\x83#f\xed\xda>o=\x0e\xc6 \x97\xa4\x91K\x07u\x1c\x86\xee=7o\xd9\xf9\xa0\x96]\xadC#\xa7\n\xdd\xf0\xc1(Y/`2\ne\xaa\xc2\xc2\x83\x016\xbeV\xba\xb2\xc9bo\xed\x808\xa2\xd2\xeb;\x0fu\xdbZ\x0dn\xb9\x1ao\xb5\xf8\x8aq\xd6\xe3f\xa7IZ4_\x83\x12\x83 \x8a\xb8@|.\x96\xe1v,\x87\xa0\xc7\n\x08\xf4\xa4\x07\xe5<\x0f\x86\x15\xc1~\xa1\xaan\xce4\x90\x0543&\xdc\xb5 \x03\xd7\xca\xe5\xbd'\x90\xb78\xecQ\xcf\x18\xa4\xa1flp0H0,b\x08\xe6\xcd\x81\x07a|\x95|\x02i8\xdc\"x\xe3\x93\xb7\x1f\xce~m\xbf>\xb2,hI\x85\xcc\x11\x15\xdeD/\x92*\x81\xbe\x0cB\xdf\xa0\xd2\xb1(\xde\xc8z\xec\x1f\xd2\x8a\x187\xb3\x15\xb1\x9f\xa5\x03\xbd>\xbfi\xf4+\xa2E\xf0\x96ov\\\x02d\x8dmc\x97\xdcII\xbf\x87q\x8c\x0f\x1e\x90\xad\xac\x8d\xa7\xecs\x87\xd0\xc1\x92\xee\x0c\xdb\xef4\xf4S\xb9\xb8, \xbam\xe2\xa0mw\x07\x1d\x01\x05\x08\xe8w\x07\xd1\x9a\x7ff\xff\x99\xd3\xc4g\xbe\xe6\xa9A\x05\x00\xadU\x9a\x93e-!E )\xac\xd6\xf1*\xda\x82a\xd9\xb6\x08\xe8i51\xbf\x05\x1c\xd3W\xba\xa5\xd8\xa2&\xe1\xf9\xf6\x14r%\xdb&\xe3h\x95\x03\xe1\x92\x16\\\xb8e\x93\xb4\x84:p\x99\x8dE\xec\xb3\xe5/V4\xfd\xac\x10U\x9f\xed\xben3\xa7\x04\x1eVuM\xcc\xa3%\xec\x07\xf8\xdb-C \xc4v\xfc\x8e\xf9\xc1\xd6O5~N6 \xd1,9o\x0d`c\xf5\x14\x87\x8dKU\xd2\xb2\xf9\xd0\x18\xe3j=\xf2\xf4\x99\xb3Q\x83\x8c\x93\xa5w\xabL=\xfb\x8d\xa4AM\xca\xc6>\xa5\x81t3[6\x8f\xe8\xe8\x0c\x8d\x1c\x19\xa8\xa1\x0d\xa1VC\xf0 \\\xb5\xf2rpl\xac\xb6\x82\xa5~\xba9K=\x90\x1f\xc2j\xd5B\x8f\xfd\xcdj\x15g\xbe\x1d\x89\x96.w\xbf\x02\xdf\xdb{\x0f\x13\x83\x1d\xeb\xb5n\x80`7;\xd4_\xab\x0f\xf3\x81\xd1H\xaa_X\xf7\xaf~]Q\xbd\xef{\xe5\xceM\xa1\x9e\xe8T\x1b9\xd9\x86\x84\x95\xdeCyP\x011\xc7@I\xaa\x9f\xaa\xa4b\x1f\xe4\xd9\xf0z\xfe\x8e\x89\x0dJ\x93\x9b>\xfb\xb2P\x8e\xc1\xdayH\xe6ME\x80\xcc\xb0\x14\xab\xc2\x0f\xcb\xfb\x11M\xc7\x97\xce\xa8\x0f\xac\xa7\xe1\x97/\xf6\x83\xee\x10\x1f\xa3\xf2;\xd5\xd9jO\xad\\;\x99M\x94 \xb6\x1b\x95>SPk z\x0f\xd0a\xfdI{\xe2\xb8\xc8\xf4\x97 0\xc2\xde\xa6\xa2\xbb\x16\x16i\x08\xbc\xcc\xd6\xa4m1\x17D\xc3\x81\x0c\xd2\x9b\x83\x11\xb8N\x9dJ\xd7[jF\xab\xf7\x04\xc1@\xd5o\xd3\xbeX+\xc7&\x9dW\x11\x10\xe2\xd8\xe6\x1d\x88\xc0\xd5#X\xe5\x03\xeeW\x9f\x1cJ\x17\x98\xb4Ji~\x94\xeb\x1b\xbc\xa6td\xbb\x9e=\xa6\xd9Z\x07\xfe7\xfb]\xe1r\xa1\xb0\xbdGq\x8bw(\xeb\xf6\x80\xf8h\xe3t\xc9\xf3\xb0$K\x8b\xad\x13\xc3\xc4\xa0\xb9\xa25\xf3\xa1\x8c\x82\xacg\xb5\"\n?8 \xd2\x8c\x03\xda\xe5\xbb\xe1\x90x\xb0\xac\xb6|\xf1E\xd1\xa3!\x99\x03\x9f\xde\xbe{\x86$&\x87\x9a7\xeb$e\x01\x91\xd5\xdb\x1aI\x9d\x19\xb8(ab\x17\x81\x95 \xb6\xd5\xc57\x9b\xb4m0$\xb4\x10\xea{\xe2E\xcb$\xe6Cc\xe5\x1e`\xa6=-$\x909\xbb=\xd5O*|Y\x0f)My,5\xd0f\x1fb \xe1,\xect\x93\xb5\x08\xc6m \xcc\xccVii\x11\xb5]dHGo\x0f\x1e\x90\x89r\xa4+\x1d\xc6\x14\x85\x93\xd9\x8e\x85p6\x88\xb1\x03E\xb2\x08\xfc#\n\x88sF~T\xb9\x84\x13\x19\x132%;\xcfI^\xf1\xee\x96\xb7\xfb\xc5^\x1bf\xd9v\xb2\x89\xbbtH\x1c=\xe5\xa6'\xc2\x94\x1c\x92T\xea\xd8H\x8dE\xb9\x1c\xa6$\xbd\x05e\x85\xf8\xbf\xc1\x96#\xbakn\xa1y\xad\xaf\x87\x87\xda\x13A\xdfe*\xb0\xf1\x0f2d\x9b\x1bV\xee?d[,8\xd3#\xda\xe3O\xa8%\x809\xbc(\xf4\x02\xbe:\n\x91\xe0\x90\x845\x19\x81D \xe07\x0b\xc9(\xee\x03p\xaa\xc0\xd4\xe6\xa8\xa0\x8a\xb0@\x15\xd9P\xb7E\xe2\x95\xd0@\x15I\x15\xef}\xac\xcb\x06\\\x18\xe8\xa1\xec#o\xbf2\xc2\x86L\nO\xc2B\xe9Ut\xbf\x1fv\xb24\xe8V\x18\xaa).iEU\xd1m\xc8g\xbb,\xb7\x1d\xc5\xd9\xa4\xd7s\xe2.]\x10\x95\x0f0\xf2URb\xacMP\x9a\xd9\xa4\xc8\x1d\xca\xac\x1a5U%\xa16{Y\xf1 r\xaah\x88\xbb@\xd7OS\x92\x8d\xb9\xdb\xd6Ou\x1a\xbb\xa5\xd9d\x03\x896\xef'\xd1&-\xb2\xba\xd6\x90\xac\x9a\x18\xc4\xc4\xdd\xc5\xfc\x95:1fJ\xcd{E\xdbT\x8bm\xda\xddp8\x0d\xc5\xf0\xfd\x1cdK\xe9]@\x1c\x01!\xca\xa2\x91\xdeR/\xb4\xe2\xfe\x9c+\x1d\xe3-c\x1b\xd8\xd9Y\xf7\x9fy\xb9\xfb>i\x8az\xda0\x08\xeb\xc9\xcb\x14\xc62\xb2\x11\xee\xddZ\xdc\xb7q]4P\x95\x14\x16+|\xd1F2\xe4c\x85\xf4T\xa7[VS\xeb\x95\xafx\xba\xaf\xb8\xd0iA\x06N?_\xc9<\x88h\x18v}\xd9\xec\x05\xca\xf5\xea\xa7\xd5\xf9\xec\xad\xdb\xdf.*\xd5\xdaA\xcc\xd0\x0eb\xa8v\x10+\xb5\x83\x9em\xc8\x16\x0f\xfbI\xb2h\x96Qo\xf9\x91\xcdos\xa2.X\xf6!\xbf\x0c\x03\xafp\x94f\xe9\xb9\xe6\xf2#\xcd\xe5Ov\xda\x18w\x194\xa7w\xedn\xa4\x14\x99\x0e\x0e\x80=\xd3\xaf\xe4\x8f\xaf@I\x8b\xb7\x81\x0c\x04\xd7\xcbv\xc7g\xc8\x98\xd8\x06D\x05\xd5\xb3\x8d\x07||\xc6\xce\xfb|W\xcdl\xdf\x8d\x7f;\xe1s\xf3~\x10\xcc!*)\xe3B9\x86[\xdcQ\x15\xa8\xae\xa6\xae\xa6l+j\xa9\xacPbS\xf9\xfa\xb5\xaf@\xaa1\xb0\x1b\x8fQ/\xcc\x8d!L\xedc\x02\x96\xf0\xb4\xdf\xa6\xb2\x93\x19\x88\xcd\xaa\xc56R*X\xdd\xc9\x96a\x82\xd7l\x1d9\xcd\xb2no\x17\xc9_\xef\xde\n\x94\xb1<\xbdY]rp\xc7*\x7f\x8d\x057\\ys\x9dD\x8c\xdc\x98\xc9U\xed\x00\xba{\xb23\xd9\xd9\xc3{\x95\xfc\xb3Z*\xa3s\xf2\xa4:\xed\xe0W\xf3\x7f\xffo\x9dy\xeb8\xcc*\x04\x0c\xa8\xe6\xcd\x92s\xd8=3~^\xc3|\xe0\xb3\x1dkmy\x01X\x0f\x0cp\xab\x91i\xb1\xb2\x95V\xb2\xcf\x1b\x9d\x90F4\x9b\x19\xc7\xf2\x0e%;0_\x12CR\\Y\x19\xc1\x12\xda\xf6?\x18/\xb53^\x86^\x0e\xb7\x9a9\xed\x0c\xa5\xa9md\x1a\xdf\xba\\\xda\xddvG\xb8\xaa\x0e\xd2\xbf\xca\x04\xd7\x16\xdc\xd5r\xda\xe3\x96\xb4\x08\x02m\xbbS\xd6(\xc5\xd57@-\x8e\xd3\xbf\x891\x17\x1eb\xe4I\xdd3\xba\x0e1\xf2\x14\xb1\xe6*\xcd\xad\xf6'\x0d\x07\xa79x\xa4\xaa~\xbai\xd9\xacd#\xd5S\xabb\x1e_\xfc.6E\xd8D\x12p>%L9\x8f\x0d~g\x10\xef\x97\xaa\x1a\x87:_\x90\xaag\xfc4\xa3Y\xe0I\x1e\xca\x10\x0f\xe5);6\xa3\x19\x9b\xf2\xd0\xbc\xb4NP\xea\xe5\xb4\xd5k{\xd3\xdd\xa9\xe0\xe2\xcb6)\xe5\x8a\xb4\xe3\xb4V\x8b\xa4\xea!\xa8v\xac6EN\xfd*M;*5\x0c2\xfaUX\x1f\xa8\xb6\xfa}\xa6\xa9\xa8\xda\xccW\xc1J\xed\xcfV0\xad\xe6\xd9\xb2\x8a\nP7,\x0d \xc03\xaa7\x18\x12>\xa6\xbe\xff\x81\xf30\x88\x16g\xdc\x0dk\x18\xe1^\x1c \xef\xee>2\x10\xbfD\xfa&\x14o#@\x8a\xb5\xcf\x9a\xe7\x0d\xa9\xc5\xb8o\xe1Q@\x15\xc6eD\xd3|p.\x0eH\xb6L\xf8\x15\xacjA\xd8I\xfd_\xe7\x98F\x11\xcf\x88\xc0<\x84\x12/\xa4iJhJh\xf1%\x07\xc1\xee\xea\xd6\xb8\xd0\xb5\xca\xca%/\xce\x83\xea\x92\xa8\xce\xa1\xa6\x9bM\xf3\x14X\xd3\xac\xdb\xe6G\x9b\xbb\xd4\x10\xfb\xb0R\x9dB5Z\x81\xaa\x8e\xe9-\xf2\x97z7\xc6A\xfa:\xaa`\x17\xe0\xdc\xea\xb5\xe3\xb2\x19\xbcE\xd5k\xb2\xf6\x9en\xd8\x1c\xa3\xea\xba\xc3w\xbc-\xb5\x0b\xa1\xceU\xb5a{\xcc\xea\xdd\xa6\x1e\n\xde\xa6S\x96}\xab\xf6\xe8\xaa-m)1\x88\xc9a\x9b\xa8\x81\xdf\x07j\xb0\x9c\xc5\xfb\xb6\xb3\x189\x8a{\xac\x1a\xe4\x0e\xb5f\x87\xfa\x8e\xfbu\xa5\xc5[\xdb\xad\xfa|%\xf5\n\xab\x83jbbjb\xe2j\xa3\xbb\xcd-\xad\xbeb\xa8\xbc\xa0\x08\xfcc@\x1e\xc9\xf6v\x93\xf8\xaa6\x91\xa2\x9d\xdd\xd4\xf0R\x0b\xec\x1d\x02\xec\xd9\x88\xad\xe2\xecfJ B\xa5\xf1\xb9m\xe2\x10D\x0bW\xfa!\xa8\x93 m\x14|*\xfb\xc9\xaf\"\x96\xbc\xe4^\x0e\x12\x0e\xe55\x89\xaf@HfSb\xd06\x0b\xe38a\x1e\xf5\x96\xacP\xe5\x967P\xdcEn1\x9b\xf2\xc0\x9aT\xb7FX\x1d\xca0^\xceo\xd7{\xde\xd6h$\xc6!\x17\xbd\x1f\x8d~\xbb\xdecNm\xaf\xd5\xce\x02\xab\x8eW\xf3\xf0\xef\xaf\xc4^t\xdb\x1a\x04\xba\xadQ-\xda\xea(\x930\xce\xa3\xea\xd8\xd6j/qK\x8d\xda\xa0\xf7\x82R&\x15b\x03\x0f\x1b\xc0Q4\xea\x14\xb8\xc0\x01\xe7\x19J\xd0\xba\x07\xd1]j\x99\x99\x91Y]k\x86\x07\x0eP.\x06\x86\xf39\xe1\xcfI3\x80\x1d\x89\xea\x9b\xb4\x12\xb5{G\x1a\x03e\xcf }\x0e\xbfh\xb5t\x80\x96~N\"2\"\x01\xf9\x9e\xec<\x1f\x80\xbc\x8bU\xaf\x91\xa2\xd1\x08-\x16\x90\x11\x89T1@\x04\xd5b\x01ZL\xef\xfe\xe89\xc9G\xa3\xe7v^\x1dB\x02\xb71\x8dHK\x1b\xad\xb0\xac$R\x15\xa5\xff\xa9 a\xae\xb3j\x0b\x83\xf4(\xf2XZ\xa5\xc8m\xa7\xacm\x89$\xc9lr\xbe\x89\x96W\xdb\xdc\xf5gIk\xea\n\x06\xea\xb5\x88\x08\xda8\x07i\xe8\x88\xec\x0e\xbcS\x05\xd1\x01*\xf1v\xa6x\x1c\xb1\xeb\xec4\xb8\x0c\x83h\xf1\xdcJ\xa7\x93\xda\xc5X\xa6\x14Z\x9e\x14\xd6q\x12\xe9\x0e\x86d_2A\xe3H\xab)>x@j\xf8\xcc\x80\x90\x11\x0d[\xbeJ\xcaE\\\xc7 \x16c-\xfd\xb4G\xe0\xb6;\xd3\x94\x04\x981,=\x17\x8d\x9e:A\xe1U\x0fx\x1c\xab\x9d[\xcedVWa\xba\x9b\xa8\xe2vD\x81\xc0\xd0\xb7\x15q\xdc\xcb\x85\x8aEj\xfa\x08'\x07\xf1\x1bL\x19h\xb1:x\x16\xef\xcb\xfafqJh\xf3\xb0\x15\x83\xd7\xb5\xd7 (\x02\x07)\xd8\xce\x04\xd1B\x85M\xb4\xb8\xa0k\x9b_Qfv\xdb6\xf2\xf1<\xcc\xd3%\xb4\x82)-\xf4T\xaa\xa1\xf3\x86\x04Gv%+\xbb!e0\xc9`\x08\x85A\x17m\xee\xd6<\x91}%W\xcb d\xc4\xadKT\x8cX\x82 \x97\xe1\xe4E\xa5n-b\xe1 \xa1\x81\xc5Qd\xce\xf8\xf9\x90,\xc7\xcaC\xd7\x99\x9a\x03\x97U\xa6C:\xb53\x87j\xd8\x18;\x1c\x17\xc7v.\xde\xa6\xa9\xd1\x18&lu\x18$Du\x81\x18\x19\xf5\x01h\xde\x19\x96M\x06n\xb1\xa2\xaa!\xf8\xc5qv\xc5\x8f\x92\x05\xf0\xb5\"\xa7\xe2dx\xad\x1c\xefW\x1b|\xc1\"z\x192\x7f*0d5\xa7:\xc4X\xdc\x95\x9f_\xbf{\xf9\xfe\xe7\x8b\x1f\x8f\xde\xbd|s2%\xc1\xd8\xa3\xd1\xa7\x94\xbd|\xff\x96\x1c\x92\xab \xf2\xf9\x15\xc1\xca\xa5,\xfb\xb1Vy\xbb\xe4\xa81\xe1bQT\xc7\xa6\xf1\x85\x13\xdd\xb1\xce\xaa\xd5\x10\x88Sb\xab\xb5\xd6 mV\xdar\xfc\x96U\xb7U\x9a%4\xfeAJ\x1faQ\xf4\x13V\xeb\xdb\x0drH\xf8X\x06\xf0W\xb1\x89\x96\xa0Z-\x0e@\xa8N\x124r\x99\xb1\x81\x16\xd7v5\xe8X\x892o\xdb\"%\n\xbd\xaf&\xadx\x14d<9\xf5\x12\x1e\xca\x88\xe8]\xd3\xaaQf;\x94x\x98\xeb\xb9r\xad\"\x8e\x9b\xbeV\xdb\xda$<\x8a\xc1\x97U\x0c\x89\x93B#\x1dD\x8d\xa2\x8aN\xcc\x11\xe9)\xd3(\x17T\x1b\xd1$0f\x0c\x86\x06\x02\x05\xb4\xc6\xeei\xb7\xcfI\xc7U\"\xce\xf5\xedr\x81\x1eF7\xf18a!\xa3)so+\\(\xde,$\xd7\x12RoEr\xf5S\xc1.\xc4`?K\xe4\x067\x1d\x86\x0eY\x91q\x88\x8c\x03\xc4\xc5\x8a\xe9\x82\xfd\xf2~>O\x99\x0c\xd82\xf6\xb5\xc6\x82\xfe\xa1m4\xe4:z\xc3\xe6\x88\x00\xf5FW\xf5\xeb\x06U\x9d\xf1\xaaX\xf0+\xc1\x82\xceC+;\xbfm\xa9\xf1O\xd5_\xb7\x9a\x89\x92\xf8\xdd\xaf3\xaa\xea\x9acb!~\x1b\xd7\"\xed\x81\x16\xf6\x9e\xe0\x91\x16&\x8f\xeb\xf5\x84\n\xbe\xde\x1e\x0f\xa7\x97q\xbe\xc9\x10B\xd0q\x10\xfd7\x83qi\x8e\xef\xcb\xf7ou\xfc\x8d)I\xda OVqvcT\x9b\xb7\x02\x0b<\xf3!\xcc\x17A\xf4c~)\xb8\xdf~\xc0\x9f\xb2 L\xc5\xd9\xde\x05~\xb2\n\xb2\x8c%S\xf0\x9bg\x05\xfd\x11t\x88\x8a&\x87m\xb0\x05\xef\xe8\x95P\xd5\xf5\xf6/\xe0\xbc\x1e\xd7\x99\xa6\x00g\xb1\xa8e-\xa9\xb5\xf7\xb4\x9e\x9eV\xd4\xc8'\x8f\x9e\xd6\xd5\xc8\x15\x17\xb6[\xff\xbe\xd7-\x03\x01\x8e\xe0\x94\x85r\x08_G\x82\xd9\xa5\xf8\x98+\xd9H>N\x80\x16eE\xa9\xea\xc0c\xf1\xb9\xcd/v\xca\x7f\xb4\xbc\x97\x8e\x0b\xa2\xaa\xc3&\x92\x8eK\xa2\xce\x85X\xe3\xbd\x0c\xad\xea\x02)+\x1dP\xa9\x1f \x94S\x17D\xddu\x04\x94\xa4\xa8\xa2\xb0.F\x9da\xc6\xad=:\xb6\xd1w\"\x9e\x05\xf3\x9b\xa30\xc4\xbeU\xed(*\xf8B\x98\xfbv\xc9W\xbb\xe5Aa^Pk'\xa8Q\x94\x94Ldx\x99D\x8c\x14\x0c-\xd5\xca\x86\x8e\xef\xd5\x06\xc1\xab\xad\x83z\xc5\xb7\xb2A\xc0:\xdf\xf1\x9d\x8d\xcd\x12Z)l\x9b\x81\xc1&\x0d\xae\xf8\xa8n\xfb\x18b\xa6`W\x18hl\x11\xed\xca\xba\xa1\xc6]y\xed\xcd\xae\xf3\x82,\xc5>7\xb0.\xcc&\xcfR.\xbf\x12\x91%\xee\xdc\x14)\xa4C\x12\x0f\x86$\xa8\xf2\xee\xf3\xba\xe1\x15\x14\xbf\xe3\x01\xd6\x90\x05*]\xea\xddz\xdc\xa7@\x1dl{\xa8\x18\x8f\xb6h)\x94\xd78\xdap[*\xa8%\x96\x8d\x98KO\xe6\x85\x90\xe0\xc1\x03\xe2\xa4\xfa\x80\x01\x85/M\xb9\x8a\xac-\xd71\x8f-\xc8W\x8cZ\xf3\xe8l\xce\xeb\x82e\x928N\xa7$'\x87=N\x00\xcd3\x16tt\xd16u}\xff\x91F\x8b\xd6\xa0,`\xdb1\xce\xd8u\xa6d8vP\xb8\xb3\x1d\xfby\x1c\x06\x1e\xcd\xac\xd7\xb5 \x84\xaa?\xe3\n\xcb\x9dI\xb7\xa6C\x92\xc8\xd3\xca\xff\x00\xbb\xcd9\x89|@\xaaI\xe6\xd8\xb9=-rK\xcc\x16\xb6\x9e\xb9-\xbc\xa1\xf8VC\xed\xcf|X\xe4OA\x03\xa5\xe9\xf7\x95\xe0\xcc\x1e\xe9\xc2\x07\xc4\x98$\xb9\x12*\x84\x8dX4H\xb2mh\xe5-\xb1`\x9dv\xd4-k\"\xe6\x174mz\x86\x05\x95\xf3M#o\xc9!\xdep\xd7tKH\xb9,\xed\xb0\xd2\xb7\xc1\x9c{y\xda^iP\x02v\xd5\x99k\x7f \xb0\x86\x8f2\xd7\xe6\x91\xb0]$\x90\x8fa\xe2\x0b+\x80\xe2\xeazH\xf21\x8b\xfcf\x06>\xf9:XC\x9f\xd8=\xa8\x07\x00\x82.!b\x98\x04P\xb723\xf5\xd1\xaf\x8cpu\x14\x07\xe4\x90\xec\x10A\x04g\xfc\x14\xd40\xdcA\xe7~\x0eA\xf2\xee\x85<\xd2h\x02\x1f\xdfPa\x15\xf1]p\x06\x12e)\xec\xe8P\xedh\xb7>\xc6C=\xea\xaau\xf6\xe5\xe8)\x0d\xa7z\xf9\xd0,/^\xcd\x99R\xef\xd5\xae\x87\x9bt]\xf0\xbb\x1e\xd9&-\xee+c\x13\xadV\x90)\xde\x9bX\x0c\x06\xe03W\xb94\x8b\xf5\xf0p\xbb\x03#\xad\xd2\x14\x8f=\x1e\x864N\x99%`k_\xf4\xe6\x8bs\x83L\x89\xd7\x81\xe6\x04\x9c'\xd0W\xcfu\x8a\x90\xf3\xa9\xf5\xb8\xear\xb52\xd4\n\xcb]\xe7V\xf7icX\xbagbQ\x90CIL\x00\xf2\x801!\xd3\xe2\xd7\xf7\x05\x8c+\x01X\xe4\x0f\x15\xa2\x03\x08\xf0Zi\x94\xd5\x99,\xf2\xc1\xd4\x14?\xd9d\xba\x9c{\xc7[\xd2\x84z\x19K\x1ci\x19\xce[\x8e=^\x14\x16\xcb\xa4R4!\xa3\xa2\xb8\x18\x1a\x8c\xeb!=\x84\xb0D\x1d\x1b\xc8)\xd3\x86\xc8\xf4Q\x81\x1eN\xf6\xa5E\xd4\xb9\xc1f\x81;8\xef\xdc\x86DI\x1d\xde\xd2l9^\x05\x91[\x0e{\xc7G\xf2\xaa\x93\x03=\xad\x94L\xcd\xca\xe4\xf4\xb6\xa9\x95\x89\x035\x1a\xb3\xebL\x94\x7f\xf0\x80P\xf2=i\x0d\xc7C\x0c|\xdd\xe2\xa0\x8d\xa86Ri\xff\x92Z\x01\xed\x9aJZ9\x15\xb4\xd6i\xc7xx\x1a\xd0f7FTo\xc1\xe9\x87\xd7\xa7\x87\xf3\x0d\x11\xa0~\xe6%\"\x0c\xe1L\x15\xe8\x9aK\\=\x04\xc7Eb\xc1\x1f\x85!\xd4\x96\xba\x10/\xe8{\xc0 n$\xb8\x0c\xf9\x959\x00\xcb\x99q=U\x91\xa7+\x82\x8d:\xd7\x08\xb6\x91-\x8a\x1a5\xe1\xc2{b\x1d\xfeN\xb1>.\xc5\x93\xb3\xbc\x11\x13T$\x17\xdcKbWB\x00\xe1\xfdx\x1e$\xa9t\x91_(\"\x18I\x95\x82\x9a\xdb)\x12\xb1\xdb{n\xff\xa0\xdd\x16\xca\xd4\xa0+\xf5\x1a+\xea\x86\x8d\x82\xb2\xad\xa5\xeaCuH\xff\xd4\xfc\xd5\xdb\xb3G\xc5`-\x01\x9cl\x18\x9f\xed<'\x91\xb5'{\x92\x13,\x88\xbf6\x1cJ\xc1i\xed6\x89\x80\x1bQ\xa4\x90Fr$ /\x94\xea$%\xdf\x9b\x86b\xf6\xad\x16\x81\x96)\"\xd3\xd4\x8f\\\xceS\x92\x91\x11\x12\xa6\x8a\x90FHi\xfd\x04\x851b\x05\xb8\x91\"\x07\x8c\xbb\xd1\xe0\x9b\x9a\x7f\xec\xef\xedX\x8c\xb0\x8be(\xd5\x9c,\xfc\xfa\x96b{\xb6\"\xb0\x01WVe\x11$%n&\x13\x137\x1a\x14\xfaR\xc6:\x13\xb8\xc2\xf1$\xf1\x98*\xbb\xb6C\x88f#\x93D\xb1)\xd9\xda\x92\xf1mhR(\xda\x7f\xe0i\xa0\xb9\xb4\xad-w\xf2\x84< V 1\x84\x0d\x15\x8d;\x0f\xdb\xa4c\xd8\xac\x17~\x80F\x1e< {\xe0\xe9\xa6\xc9\xdb\xdc\xa1}\xfd\xda\xa1\xb9^\x97\x899\x19W\xec+\xe0\xf2\x8fL\x8b\xe3e0\xf6\xd9\x9c\xe6a\xf6S\xc0\xaeD\xa6$;Pd\xb6\xe5nI\x17\x83\x16_Qc0\xba9\xac\xder\xaa\xd4)\xeak \x84:\x118D\xaf\xa4W\x95\x9c\xa5v{\x13\xe0\x1d]\xb1\xfb\x9dwg\x99e\xf1\xf4\xe1\xc3\xab\xab\xab\xf1\xd5\xde\x98'\x8b\x87\x93g\xcf\x9e=\xbc\x0e\x83\xe8\xb3\xd3\x94\x90!\xf0\xbf\xbc}#\xca\xec?\x8c\xe8\x8a\xa51\xf5\x98\xd3\x94\xa05\xf1\x12\xf5<\x16e?\xb2`\xb1\xcc\xa6\xc4\x91\xaf\xa3%\xbc#>\x9a\xa8\xe7\xe5\xab<\x04O\xd6;H\xb6\xef\x07Y\xb0\xb6d\x86\xc1\"\x12s\xff\x03MY\x18DL|O\xa7\x8d.U\"\xf6\xd10\xe4W\x1f\x19O|\x96@\x99\xf2\x15\x85\x8e\x97\xf4\x92e\x81\x87\xb7b\x15\x87A\x96\xfb\x966&\xf42\xf0^\xf1d%>\x04/\xa39OV\xd8wR\x0fn\x07\xb1Z\xb2, .\xf3\x8cI7\x88N\xe5\x1d\xabJ\xe7\x8b\xa5g\xc2\x8bw\x0c>\xcf\xf8G\x06\xc6\x92\x02\xba|\xc3`\x7f\x0fVy\xb6D\xdb)\xc6\xfcU\xc2\xfe\x91\xb3\xc8\xbb\x99\x12\xa7\xf2\x8e\xd4%\xf2?$|\x1e\x84LA\xab7\x0b\xac\x98\xcf\xd3e0\xcf\x14\xb4x\x1f\xa5\"\x01+p\xc9\xaf\xf1V\xb2E\x10\xe19\x01M\xf1\x8c\x1b4\xd9\xa3\xa1\xf7\x16\x0e`G\xffD\x1a\xe2\xd1\xb8\xd8\x0f\x1e\x8d\xed\x9b\xc1\x0b\x83\x18\xffN\x18\xc4\x1f\xa8\x18tG\xfc\x1c\xc54[Z\xca\x7f\xcca,\x01,\xc9\xd1\x91\xd4\xb5}\x8a\x02\xc1w;\x95w\x0c\x9e\x87\xb3#\x1b?\x98\xcf\xf3\x94\x1ds\xe9\xabsJ\x9cZ\n\xd2\x1b?H$go\xa9\x11\xbc\x9eZ\xf2\xd6\x81m |\xbe\n\"Z\xc1\xef:\xa9\x0d\xbd\xfb\xb9\xa5:|\\}\xbca\xcc_0\xb5\xb7\xf5O\xe4[,dkj\xed\xb8\xd4[\xfb\x81z\x9f\x17 \xcf#_\xd4\x05I\xa3\xcb\"\x0d\xab4\xc2'U\xd0L\x91m\xda\x04\x9b\x9bD4\xfc\xc8R\x9e'\x1eK?\xb2\x7f\xe4A\xc2\xe0\xa3\xb6<\xe4\xe3\xf3 \x0c\xd1\x0f\x88\x8c\xf71\xf5\x02\xf0k#\xdeF\\\xbeZjQ\xa8\x08 -\xa8H\xeew\xdb\xe72\x96|d\xa9\xacB\xfe\xb6V\xa1q\x99\xf1\x86\xc1\x86\x9c\xfb\xc7\x02\x13\x08P\xf12\x02\xbc`\x035\xba\x0b\xc0-\xfd\xe5^\x9e\x8a\x99\xc5\xfb\xc2\xa3\xec\x15]\x05!T\xc5\xa3l4\x877\xb4\xa2(;\x05]\n \x98\x06\xbf\xa3\x03\xa7\xc0\x8e\xfc\xff\xce\xd3\xcc\x04\x1eQH\xb2\x95\xc9\x12\x96y\xcb\xa2\x80|\xb5\x02\xdf\x84eC\xc4\x8b\x05\xf0'\x9a\x04\x12U\x00\xe8Z\xbeZ\x80\x7f\xd6g!\xc0^\xd9\x0eC\xa9\xae\x83\x0fg\xc2Wx\x06\xbe\xc3\xe7\xf8\x0e_L\xf0\xe4]<9\xbc\x89\x97\x8a\xfe\x82\xdf\xa3\x08'\xbe \xf3}\x12\xb0(\x03\xcc\xf0#O\x82\xdf\x05\x9f\x18\x16%y\x99;Z\x16\xd9=\xea\xfa\x89%Y\xe0YjZ\xabL[=\xe0\xb8\xdb\xd1?1\xa8\x84\xfa\xa2:\xd0\x12\x99K\x9a\xb5\x91\xd6RNo\xc2\xca;\x02\xbf\xa4\xd1\x02Ned\x98a8\x8e\xfc\xf5/S\xe2\xc0\xef\x11\xf5\xd7\xa3k\xac\x16\x91\xfb> \x16AT\x02sxG\xe1\x03\x9f\xf1EB\xe3\xa5\x85\x90\x0fVt\xc1L\x92\x01\x12ZI\x86 \"xU\x11\xbe\x86\x80\xd8\xf1X\x8c/\xeb\xcfx*\xbeJ?\xe3_\xf8\xbc\x87'?\xc2\x93Y\x12\xb1\xf0-\xcd\x92\xe0zJ\x1c\xf3\x15\xe9\xad\xcc\x16\x93\xfa\x06\xe4UE\x892\xc9R\xca6\xd9\x9f\xd9\x0d\xdci\xa4P\x95\xfa\x8d\xd6qs\x1a\x8b\xd3^\x01\xaa\x17\x1c\xf2,Xi8\xf8\x89@Iy[\x81;\xcdW\x14:\xcbXr*p?\xac\x0b\xf9>Je\x02V@\xa040\xa6\x95'\x8d~\xb7\x1e6`\x8f\x0e\x05\"v\x14-\x00\xe96\xd2\xb0r\x1cp\x012\xb2+\x9a|f\xc9 \x90\x1c\xf2\xf7\x88\xa1\xb4\x86\xcc|\x1b\x18\x80\xab\xc0\x0ex*\xaf\x085h*o\xa1,\xc0\x05\xd7c\xbeZ\xa15\xf60\xde\xac\xb0?\x07>\xac?\xe3\x0d\x85M\xf1=U\x84\xcb-qV=\xc9R\x9d n\x87\xcb\x96lE\x15\xa2\xc6>\xcf-\xd2\x82(_\xbd\xf72\xba\x86\xf5[\xbe \xdf\xd0R]\xa4\x12\xae\x89\x164O\xbaa\xc73\xa5<\x04\xcd ld\xa7q\x00\xd9\xf2m\xdc6_\xb3d\x1e\xf2+k\xa6\xd8\xe4Z6:%\x8eN\x1a\xc5*\x0d\x1b\x17\x05s\xb6\x0c\xbc\xcf\x11KS\xb3\\\xa6\x13\x91\x821\x0d\xa2\xec\xbd\x92\x08\xc1\xcb\xc8&\x10\x8ai\xc4S6\x018\xf1k4A\x81\xb2e\x81&\xcb\x17\x1cRP\xe7\xb5\xf5\x88\xa4\xda\xcb\x9a\x07v=\xc9^\xaa\xf6)\xeb78\x1c[\xa0\xee\x0e\xe0\xf2}\xc4 \xc1V\x00\x97\xa3\xc8\xac\xa3\xec\x17]\x8f\xf8m\xad\xe2(\xfb\xd5\x80\xfb\xb5\x05\xeeo\x06\xdc\xdf0\xb8\x84\xa5,Y\xb3\xa30^R\xf0\x1bo\xbc\xb7\xc1\xa71\xf3\xb2\x8fby\x9b\xa5\xcaT\xb4,`\xee5+\xc6\xb7\x92\x80\x94\xc07\x9d \xa2r|\x18\x136\x17#(\xfea\xd5\xb1\xf9\xaf2\x17\x1b\xb2\x82\x9ey\x0d+\x0b\x00U\n\x08cP\xba=a1\xa3\x19(\x89A\x81\xe2\xcd\n\xfbR0\xe1N\xf1\x1b\x85\x93<\xe8\xc9u\xc6\xa24\xe0Q\n\x05\xea\x89-%_1\x9a\xe5 3\xcb\xe9$\xb4\x94\xd2oA\x074\xcdCK\x16\xcflR\x94\x04g7\x12\x1c\xf7\xa6\x1e\xb5\xb0\x87)c8\xc3\x9f.i\\!I!\xa1\x95$MC\x1e[\xbe\xa2 \x184\x8fyyH\x13C\xe8SO\xc2\xbe\xa5@N\n\xb9\x84SO\xc2K\xd9\xba\x1b'\x8c\xfaoY\xb6\xe4>\xd4U\xbeb\xf5\x94\xda]\x02\xb8|Ca\xfd\x97l\x1dh\xe1\xa5\xf9\x8aB\xb3\x15.\xe0\x169kKN\x90y\xcb\xb3 \x84\xe5h\xbc\xa1\xf5\xf3X\xd3\x86\xe2\xb7\x95.\x14\x99\xa5\x0c\x02@\xed\"\x884K\x82\xcf,[&<_,\x8dc\xb3\x92\xdevvV\x00\xcd\x03\xb4ZC\xdb)*o\xb8,\x03\x94\xf0\xcf\x96\x95 Y/i\xba\xa4IBeWE\xca\xc8\xd7I\xf8\xa7T!^\xae\x81\xa2\x14\xb7\xaf\x04\x01\xf3&\x88\x98G\xe3\xb2L(\x13Z\x0b\xfc7\x0f\xa2j \x91b-\xf26\xc8\x04\xdd\xb1\n\x8c\xa6\xad\x8a4k1s\xbe\xa1L\xeb\x8c\xf3\xcfL\xd3\xc2\n\xfc\xcaB\x0c\xa7y2\xa7\x1e;\x95X\xc81_1\xe8\x1b\xb1\xd4\xdf\xd0h\x91\xd3\x05\xc0W\x12\x90\x12\x19\xbd\x0c\xa5\xb7&\xb1d\x8c7\x146Y0 \x02\xd4/+\xcc\xaf\x05\x0cv\x96e\xec:;\x02\xfdV\x01\xc6\xae\xb3\x91\xd4v\xb5\x80\xbed\x1eO4\x0e\x00p\xbfH\xb1\x141\x91/\x94h\xc3\xbd\x02\xa0\xa0\xf9\xca\x17\x0c\x92\xa3\x1b!+\xe98$7\xc7%\x019. \xc8E;k\x14t\x91\xd6\x86\x06\n \x13\x05\x94%\xdb\xb6\x7f\x1e\x05\x9e\x8d\xb7Qy?\x04~\x00\xf5\xc1\xdb\xe82\xf0\x03{E\xa0|e@\x83\xaa:\x0e\x9e\xa5\x1fXr\xb2\x92\xc0Y:\x8a\x05\x85\x8a\x11\xbf\xeb#\xe3>\xd7Y\x8f\xca\xeb]\x0c\xf8G-\xaar\xd6#%\xb6\xc2\xc0^\x9b\xb2%g=2dM\x18\xf8\xdb\n\x87\xe8\xacG&\xcb\x88\x15P\xdb\n\x19\xd65\xf32\x9e\x9c\xcc\xe7\xcc\x13xF\xbe\x8e\x18\xbcc5\xb1$\xb5\xb1jk\x96dG\xfe\xfaW\xa8&\xc9@\xf0\x86\xa1\x1d\x91Y\xca\xdd\x00\xb4E\xecVB\xffZ\x83F\xeb\x0e\xd8\xd5\x0f\xfcZ@\xca_\x16\x983\xc0 \nL\xbe\xa0\x90ip\x19\x846n\x18P%>\xacW<\xf1K\x89\x8fxk\x91\xf7\\% \xa9Q\xb7E\xeam\xb4\xc2o\x8cp\x9a\xf1\xba\x90\x95\\\xdb\xef\x87\xafq\x04p\x8d#\x80\xeb\xe3%\x8d\"\x16J\xad[@\x91\xf5$\xec\x1ba\x10}>\xf2\xb2\x1c\x88^\x07^\xa7T\xbe[\xc1\x13/\xe1\xa1\x01.\xdfm\xe0?& \x88\x96\xb0\xcb\x04\x15EC\xe6G\xb3\xd2\xb6\x1aO\x97\xfc\xaa\x00L\x97\xfc\xca\x06x\x16dF\x95\x99x\xb3\x82\xca\xab\\\x05\x89_\xe2^\xaf\xc2\x1f\xc0\xd3\xb6s\xbd\n\xa7\x97\x14U\x98\xb8^\x85\x11\xbe\xc8 \xe7\x17\xf8\x00\xd4\x10\xa5SLAG\x81\x8a\xb3W})\xa4\xe8:\xbc^\x85b\xcd\xea\xf6`J;D\xfa2@\x1as\x83/\xae\x1b|q\xdd4\x17W= \xf9\xf2\xefh]\xbfs\xbe:\x8a\xfc\x0fT\x1cQ\xe5K\xab\x7fT\x8a*\x1f)\x17\x02\x81\xc0\x95\xf5@\x11Dz\x1982Ug`\x84R\xcc!\x04il\x85\xa4Y\x1dil\x806 \xb9\xec\xdb >v\xd6!\x17z\x1b\x84Z\xe1\xad \xb0\xb2m\x10zI[\x8c\xdc\x8a\x85h\xcfWk\xb0WH\xd9\xc6\x8cL\xcd\xc8]\xa4\xaa\x9d*#\x02\x8e?\xb3\x9b\xd4\x0d\x06\xe39ON\xa8\xb7t\xed\n\x84t\\\xae\x08\x19\xe7vgH\x02\xf1\xeb\xc1\x03\xe2\xd2q\xe3\xeb\x12H@\x18\xeax\xdf$@\xc7N\xddu\x02\xc7\xedW[\x82\xfe`\x0e\x15\xa4\xa3\x85Guk\xd7T\x81\xef\xe2>>\x1e\xe3>>vw\xeb\xd5\xcf\xc16\xbdj\xcb\xaa50\xdf\xea\xf8\x05\xa69k\xc3;\x8b\x80\"/\x0e\xc8\xa4\xe6=\xb1i\xaeN@2\x12\x02]\x83o\xd0xIS\xe6\x7fd\x8b \xcd$\x15\xaf\x97\x10\n.\x1e\xe5\xf1~J\x1c\x1eID\x85\xa0)\xfdh\xd7\xf6\x06\xb4r\x11\xe5\xa0e\x90\xf5M@\xd9&\x16LC\xe4\x01^\x9a9\x19\x8f\x7f\x08\xf3\xc4\x19\x12\x07\x04\x01\x10\x1b\xfb-\x8br\x95\xf2\x8a{y\xaa~\xff\x95\xdd\xbc\xe4WQ\xf9\xf6)V\xbf\xdf\xf2\x06\xe8I\xe47'\xab\xa9\xa2\xbf\xa1EV\x8b\x05q\x87\x0b\x12\xfbf*\x0dM\xa7=\x0d\x82Mc\xd4io\xd3\xe0\xc2du\xda\xcfB\xd8\xb0j\x9dV\x8d\\\xf1m\xdb\xb17\x88\x1a\xed\xa6\xa5a\xab\x85b\x0f\xdb\xc4[\x8e\xbb\xb4KP&\x84\xd3\xc2PA\x07\xc7o\xb1\xf3\x92Q\x12\xa4\xf1I\x0b\x14\x8f\x05\xd0%\xcf#\x1f|5\xc4v\xd8\x90\xcd3\x13\xf8\x0d\x9b\xdfn\x94\xbf\xba~m<\xc0\xb2n\x0d\x8a\xfa\x9e\xbb\x16\x07,6\xde\x80~\x9a\x03\xa9\xcd\xfes\xc3\x93J\xac\xe6aH\x96Cbq\x10\xa7\x06\x9fC\xb4xr\xa0]58C\x91\x04|\xa6\x98\xd7!I\xc6\xa5\xea\xba\x8e\xb8\xf3Ry\xb7c\xa9\x0bf\x99\xd5\xfe\xfd \xf9\x8c%N\x93h\xfce3X\xee\x9aE\xa0\x84\x9aNImF\xd8u\x96P/\xd3wtu\xca\xa4%|\xf4\xd6\xa2\xc3\xea_\x0fdF\x0em\xb1\xd3\x06d\x8a\x9a[\x88'\xbd\n\xdam\xde=\x9a2\xe3\xd8\x9bZW\x9a\x1b\xba\x1c\x82\x9d;Y\x923\xe9#\x9e\x8f\x95\xaa\xed\x89\x1f\x80\xc8Q\x9a\xf1\xf82\xb6\xc7R\xfa\xa2\xd5\x07T\x8b\xd1!\xb8\x82\xc7\xb3\x8b\xf6\xc1\x99mo^qd\x96\xc7d\xf1\xe5\xbb}\xb8<\xe9\xed_\x87\xe3\xd6\x12\x17\x8b\xf4\xfc\x8eI\x89\xe0_\xaa6\xe9S\xdc\xd2 \xb5\xa6\x14\x19@n\xa4E{G\x0b\xeaT\x8b\xbdz\xb1t\xe7\x83^\xdd\xd2$TG\x97$m\xd5\xd9!\xd5\x91\x0edFZ\x1c94\\b\xfa\x1f\xf2\xec\x0d\xf8\xd3d\xf5\xe8k\x16\xaf\xa3%\xf1*M\x97a\xd1\x03u\xb5c\xb5\xc1\xc3\x8d\xaf.!\xf5\xae\xcc\x0c\x1e\x99\xc9\xe6\xaf\xbb\xc9\xfbP\x9c\xc9\xc9\x95\x05\xdbc\x94\x9b\xd9\xdf\xab\xf3J!\xce\xfc(\x8f\xdd{u&g\xae\xd2\xeb\xf0\xb1jM=\xdd\x97\xf0\x8f\xea\xbdZ\xaa\xf4\xfa(\xacUz\x9d\xe9Z\xa9A\xab\xc3/\x14|\xdd\x07\xdf\x8d\x1c\xcd\xfa\xe8\\*\x1e\xad>\n\x17e\x84\xaa?\xbe\xd6\xf2\xaej\xe1\xe8g\x0e\xbd\xe4\xe0G\xc0\xa1Q \xdd\xe3\x9dD~\xe5\xfdu\xc6\xf4\x15\x89\x91\xaa\xfd\x0f8\x97\x8a\x95\xf1h\xf4!\xa47\xc6\xcf3ya\x08)a\xe0}\x86\x1fUn\xc7\xe3\xb1,\x91C]>\xcf/Cv\xac\x81\xfd\x84.\xf4\x7f\xd5*\xf9S\xfa7\x90/\xd7A\xa6\x7fC\x8c7\xfd\xf2~]\x02\x15\x8d\xf5\x13\x0e\x1c\x92\x9f\xcb.)<3$\x0e[\xc5Y\x00Q\xcc\x1c\x16y\xc9M\x9c\xe9\x17_\xfdH\x12\x0e\x15\xce5{\x16D\xb1lv\x10\xadi\x18\x00\xd4\xe7\x92_\xfb\xccn>$pO\x02\xbf%k\x16r\xea\xeb\xff\xcc\x7fI3Z\xbe\xbde\x19\xf5\x8d\x94\xa2\xd5+\x93\xd5\x83\x97\xb7\\v\x14^\xde\xe7%\x94\xee\xf5\xaa\xe4\x06c\x9afL\xfe\xc8S\xf9C\xcd\x93\xf8\x0f\x12m\xe2\xc4 _\xe8\xc6&4c\xe5\xc0\x80s>\xc7t\xf1\xeb\xa4\x8c}\x96\x83\"~\xa9\x1a\xd2\x8c\x86\xa1J\xcd/WrV\xd2<\x8d\x99\x9c\xb9,X\xa9P\xd4\xf0\xc6soy,\xc8\x87\xb0xUS\x0c\xbfu\x07\xe1\xa5\x18\x08\xb8\x1f\x0b\x8cE\xba\xe6a\xbe2\x1a{EA\xf6\x0e?\x97\x8c\x85\xcey\x0f)\x91f\x8d\xd8l\xe7|\x9c\xf1Oq\xcc\x92c\x9a2w@\xb6\x05c\x16\x06\x1es\xeb\x9b\x95(\xcbg\x87G\x10\xe3\xb7\x99\x0bv\x98\x19\x8f-\xd9\x1c\x15x\x90;\x8a5Z\x0c\xc1KiFD\xb6\x89s\x0f\x92\x8c\x04\x91*T\x0f\xe3\x0b)P\xe3Cr5K\xce\x8b\x80\xd9\x00Y\xf3\xd2~\xa2PS\x91X\x08\x07\xae\xad\x16\xca\xce\x18\xe2P\x8d/\x12\xce\x81.}\xfd\xb2\xac\x1f\xa9\xe9\xd4^\xd3e\x9ee\xd2\x0c\xf8@\x06\xe0T\xdb\xdbHH\x8d#W\xa6\x08TF\x13FU\x9a\xf1m\xfdK\xf4\xec\xb8\x95\x92\xbf\xd8\x90\x92\xe7(\x13D\x13B\x87pR\\\xcd\xd89.-\xd8\xba\xe9 \xf5\xfb\xd3\xeaGpjtPT\xc7\xeaD\xe8\x07\xa6O\x8b\x0e\xe8\x97U\xcc\xdd\x01}\xa2\xb0z\x17X\x81\xf1;\x01\xfd\x1e@pRt\x00\xbd\x86\xd5\xd5 $\x0f\x96\x0e\xb07\xe2P\xe9\x01\xa3\x0e\x9c^\x90\xc5a\xd4\x03Z\xe2\xe7\x0e\xc0\x0fp\xfat\x01\xf5X/\x1f\xd4\xa9\xd5\x05\xa6O\xb4\x0e\xb8\x8f\xe5i\xd7\x05 'a\x07\xd0\xa9<\x1b{@\xf5\xe8\xc3\xa9:S\xbb\xc0\xe4y\xdb %\xcf\xe2\x0e\xb0\xb3\xf2\x9c\xee\x80\xfc\xc9<|;`\x7fV\x07\xb3\x9d\xbf\x12<\xc0\x1d\x19\xe5\xbfj\x8a\xab\x9do\x94\xfe\x9e.\xdd\xa8M\x82\xac\x9f\xfbf#!\xb8\xd3\xdd\xba\xd9\"\x88(`\xba\x84)\xa2\x19\xde\xdd\x9a!\xc9\xf4\xf6\xa1\xdeU\xaeq\xe4\xe9\xba\xc9p\xbf4X\x81\x8e\xbev\xc9G\xaa\x80@Y\xf6\x01\xb4Nc\x15\xec}7\x1a\x7f[P\xe6\x1d\x80\xdd\x12\x18\xa2\xe6.\xbe\xdb\xdc\xbd\x14\x9cUGc^*\xae\xab\x17X\xd6\xdd\xb9\x97\x9a[\xeb\x01'9\xb9\x1e\x80}F\xf5e\xc1\x01v\x02\xf2\xae\xadkq\xadHz\x8e\xfb\x99\xc1\xf6t\xe1a\xcd\x12\xf5\x81\xeb\xb3\xa8\xcfJV\xaa\xbd\x8f\x16\xef\xb8\xa4g\x1f\x8fLABG\x9b\x8e\x9aB\x86\xbe%\xfa\xf4\xa4\xc5\xbb^\x9f\x9e\x9cU\xd8\xcd\xf6O\xad\xef\xf6)\x19\xe4\xa7\xe3\x1b\xab\xbb}\xe3g\xe0\x88\xdb?\x81\xf8\\\xd3O\x9fO\x1c\xf3\xb8\x93~;\xeeF\x98\x1f@d\xd1\xde\xd2\xa6?\xc4\xa6\x08\x96\n.-q\x9d\xfd'\x0e\x1e\xc8H\xf0M\x17\x10\x90\xa1\xbc%\xba)9\xadf\x01u\x80\x05\xed\xb7?\x17\x83!\xb9\xa8\x94\xbd\x07\xa1/\xdcV\xf3H\x1e\x89\xa5\xdcw\xeb\xd4e\xe3\x8b\x8c.\xd0\xdb1b\x08j\x05\x1fm\x17\x0f\x04z\x18\x90`\x83\xf8\xac\x9f\x08\x96\xfe\xcb\x17\xe2\x9e(\xde^G\x85\n\x0c\x89\xdf\x0d\x16_\xaamh\xae\x820|\xc9B\x961\xcb\xf0\xdc\xfb\xd8Djll\xbd\x8c\xce\x95\xc3Iw0$>4\x0dR\xbb\xfaU\xbcYd\xef\xc7\x90zG\xd9\xfb\xa3}\xd4\x81=o\x11\x18h\xf7nc\x8f\x86\xa1\x8a\xacn@\x97\xcd.~%c\x9aC\xbc\xf8\xe3\x90\xa6\xa9\xcb\xeba@\n\xa9\xb0\xf4\x8f\xd0\xd4\x06a\xd2/\xb1\xe0-\xb0\xec8e\xb9\xcf\xcb\x0b\xed\xca\xadhM\xfd\x8a\xdf\xd3\xa85o,\x9a+\xc4\x0b\x83\xf8\x92\xd3\x04\xf8\xe6>~\xda\xb54\xa9RP\xe9\x94\x1c\x126\xae\xa4\x17\xb7\xa6\xd5\xe4\xaee\x85Mw\xf0-\xa7;\x90^\x86\xcdI\x08\xeec\x12&\x93\xc9\xbf\xc1\xdaM\x98@\xe2\xbeV(\xff\xf6k\xafy\xf1\xc3-79\xb8\x87\xbd\xcf\xecf\n\xf7V\xf5[4\xa2<\x02d\xa0\xe0\xdf\xdce\xe2\xf1\xb2$\xfc+T\x80f\x83/\xb5\x96|\x1a\xb6\xe5\xaeXF[\xb2\xa51\xa8-\x17|\x19\xa0\xd8\x81\xc8\xb8\x16o\xb9\x1f\xcc\x03pA\x90 8wwR\xbf\x18\x14\x8f\xb7\xa4\xc9q5\xf4~\xe7v\xfd\xccnb\x10\x1cH9\xae\xd4\xfd8\x94nm\xa7\xb5x\xa4\x04\x17\x8f\x7ff7\xb7\xf8\xaa/\xb8V\xf3\xa3_\xbe@z\x1e\xd7\x9a\xc2\xc6\xea\x03}\xdbs\xb5\x0c\xbc\xe5\x86\xadi\x19\x83\xfbll%\x05Eg\xf4[b\x00:$\xc1\xb7P\xe9m\xee_\xfcP9I\xbd)qNR\x8f\xa26\x05\xa0=}I\x93)q\x08\x92\xfd\x06\xf4\xad\x9c\xa3$\xe1W\xe27\x02\xf2)\xd6\x00\x9f0\x83\xc6\x8f\xca\xd0\x04 >ZLM^\xf2\xabH\xc3\xc8\x9b\xc7&\x08\x0b\xa7\xc4\x91\xa4\x1a\x92\xfd3\x18K\xbe?E\xb2\xde\xb2(\x9f\x12\xa7\xa2\xf9\xda\x00:\x8a\xe3\xb4\x13H\xb2MS\xe2\xc8\x1fo\xb8\x87\x19O\xbc\xe5\xbf\x7fH\x82\x08\x14\x84\x00?9\x9f\xa2\xc0gQ&\xf0\x89\xdfjg\x80\xa3\xe0\xfd)q~\xa0\xdeg\x9b\x85\xc5\xb3)q\xce\xe8%\x923\xd9\x15}\n\x19\xc5\xcc#&{ba\xc8\xdb\xedf\xe6\x13\xd1M\x8b\xaf\xcb\xc9S5T \xc7\xec\xc7&\xa2\xc1G!ZR\xb4U\xca\xe6\x9b\x99\xbb;S\xb8(L-\x03\xbb\xfb\xb4m%\xef\xedZ\xd6\xf0\xde\x1e|s\xc1\xd0\xf5\xb9\xf7H\xe5Z\xd6\xdd\xdec\x18%\xcc$|O\x8c\xd1\x8f\x1cu\xcb\xb5\xf7\xb4c\xdb\xec\xed\xb7n\x9b\xbdg]{\xe6\xd1N\xc7\x8ey$Z\xfe:J\x19\xea3\xe7\xd1\x93\xb6\xed4\x81\x95\xf3\ns52\x81u\xf3j\x17\xcd\x12\x83\xf9j\x0f\xcd\x12\xady\xf5\x08\xcd\x12My\xf5\x18\xcd\x12\xc3\xf8\xea \x9a%\x06\xf0\xd5S4K\x0c\xde\xab}tC\x88Q{\xf5\x0c\xcd\x9a@\x97w\xd0<9\x1c\xe8x\xec\xc2xL\xd0\x01y$\x06\xe4]\xbe\xb2\xac\xe8 \xccQ+6\xd9\xdd\x15U\xbce\x19\xada\x0e\x9c\xcb\xb3\x9f\xc0\xd2\x0b\xfegvc\xbb\xd1\xcd\x04\xc99\x03\x90s\x19\xec\xf63\xbbir\xa9\xc0\xfcV0\x1ah\xc8\x97\xde\xe3\xab\n\xb9_\x1b\x8d@\xcf~[\xa3\xb4\x7f|\xabld\xa2\xfc\xe1\x93C\x8d\xcc\xc8\x94\xc8\xb0:\xe3y\xc2W\xc7\x8a@\xab\x07DF\x15d7\xa2;\x82YAy\xc0x\xd5\x06eJ\x9cr\xc6\xee\xc1\xc9\xb6\xd4\x11\xfb\xd7s0>\xcd\xa8t\xf7\xc3\x92\x7f\x1d\x03\xd3\\-\xa0\xbb\xc3R\x1bI/\xb5\xa9\xcf\xda\x81<\xb8]\xf4;\xa0\xee\xc4\x96\xdc\x91%\xb2q&\xd5\xb5\xfd?\x86i\xff\xb7X\xf1\xb1\n\x15\xfd\x7f\x8b\xb8\xe9\xdf\x04O\xb00\xa3\xbft\xf1\x84\x1a\xf1JhCv%\x13\x04\x16\x05\xd5\xba\x97\xd5\xfc\x11\x1b\x1b\xc9\x0d\xc6\xaf\x11\xa74\xcc\xe8\xaf\x1b5\xe5\xd7zS~\xad6\xe5W\xbc)5(\x1c\xa8Ws\xff\x86-%\xc8\x91\x86\xff\xdfj\x19 \xce\xf2\xf1\xa0\xb9\xac\x9eu\xd1\x1b\x88\xac\\\x1f\xe0\xcd\xb1\xbe\xc8x\xfc\x86\xadY\xa8\xe2\x02O b`u\x11\xf8\xe0\xf5KdO\x90\xecJ\x84\x8e\xa9\x8a\x91R\x84\xc0\x80 \xa9\" \xc2\xa9U\xa3y\xd8\xb0\xeb\x85\x8co\x83\xe8O^dta~B\xe0\x82q\xc6\xdf\xf0\xabB{\xd3^\xa9\xb6\xfd\xfe\xf4\xf1uQ\x87\x91F\xa6\x88\xda\xfesl{F\xb5}x\xab\x196\xa7\xaf:3\xf5x\xcfS\xb2U3\xa0\xcfS\xf6*\xb8\x14\x13\xb25\xb9\x8f\xb6\x18\x91c\x1e\xd5\x15\xe6\xc51\xff\xf0\xb7\x87\x87\xdf?\xac\xa6\x0b&\xf9\xe1\xdf_\xfc\xb6\xf5\xdb\xe8\xb7Q-\x0f7\xd4?\xfe\xf1\xe4\xf8\xaf\xa7\x9f\xde^\x1c\x9d\x9d}\xbcxw\xf4\xf6dJ\x1cA\xc7\x8c \xe4\xf0\x08b*\xa79\x1a&\xc3\xf7\x8fU\xee\x19\x97\xb1\xb4\xbb\xf0\x081\xe8i\x9ct%\xe6\xd5^\xc6\xd2LTt\x08\x01f\xd88aqH=&\x10\xaaC\x1c\xb2M\xe8\xb8\xd9~\xb2M\xbe;p\xbe#\xdb$\x13?\x9d??\xf8\xae_@s\x1a}dy\xca\x9a=\xe9\x8a\x80\xa8c\x9b\x16\x16\xec.\xd6\xae\xf6\xce\x8aJ 6QL\x93\x94\xbd\x8e \xf0\xe4dg0\x94\xc1\x7f\x80\x8eo\xf6\xc2\xb6/\xeeY\xa4\xf6\xe4\xf1\xe3\xddI\x17\x92\xab\x0fQ\x11\xc7KL\xf6d\x08=\xdc\x91\x91\"wdH/V\x84\xdb\x12ks\xf4\x88< \xc1s\xc2\xc9\x0bB\xd1\x10_E\x8d\xb9\x19f\x90\x93m\xf2h\xe7\xd9\x93!\xa1\x03Y:\x17\xff\xb6\x0f\xc8\xa3\x01\x89\xc4\x7f7\x13\x7f\xd9X\x0b\xa4\x8f2\x97\x0f\x06d\x1b\xcd \xdbd\xd2\x96\xb9\xdb\x96\xb97@f9#\xffq@\x121\x00\xffa\xc6\xa6&\x8d T\x91\xdaD\x17\xc48lo\xab\xf6c\xcdGq\xa0+?5 _\x88\x1b\xa9\x9f/^\x90\xc9\x93\xfb\xc0G\xe6\xac;\x93\xc7\xe3'\xe3]\xe7\xf6\xb5u\xd8,\xb9\x91\xfb\xe8\xc9`(m\x91p\xdb\xa5I\xdd\x9aG{bx40\x8f\xec}\xa8\xe5\xd9\xc6\xa1\xb7\x04;\x1e)kw\xd6\xa2/'\xe0&\x8a\xfb-\xe3\xce)pV\x85\xd5\xbb\x01\xac7\x1b\xe8O\xd4T\x8a\n\xdcL\x06\x11\x1e\x08\xf4\xc7\xed\xe6\x9e\xcd\x16\xa1\xa1\xb4\x04\xf2\x8c|&N\xfd\xc4u\x1e=rDY\xf1\xeb\xb13\xac\xb8\xf3\xb8\xe7\xf8WbB\xf6,\x83\x9f\xa86\x9d\xe6\x97Y\xc2\x04\xd2\xe3EX\xe0\xdb\x7f9\x1b_\\\xb0\xf4-\xf7\xf3\x90\x81!\xdeP\x86\x87\x8b\x98\x97\x01\xa6\xfe\x90\xf0u \x86BG\x1dm\xb6:p#w\xff\xf1n}\xe5\xf1\"\xeb\xd1\x00e#\x02\xabY\x83\x8a\xf7h4M\x1ejM,\xa7\xa2\xa7MIwL\xc5J_\x12\x1dw\xad\xda_\xae\x93\xefyDU\xad-\x83\x18\xb9u\xfb<\x0eK:r'\xd8\x96\x16\x19{O\x1f\x9b\x18T&=\xc1\xc7\x9a\xfes\xc7Z\x9f;-\x07\x9en\x99\n\x1a\x8d|o\xab\x1fU\x016\"n5\xe8\xdd`@\xb2e\xc2\xafH\xc4\xae\x88@2`\xdc\xe0:\xc74\x8axF\x04oJ(\xf1\x04\xc3IhJh\xf1%\x07\xa1~\x14\x17\x8b\x99\xdd\xaf\x95\x95y\xff\x862\xb3e\x1f\xd9\x9c%,\xf2t\xf3\xc4\x87\xc8\x92\xa6\xd1w\x19\xb9d,\"A\x14d\x01\x0d\x83\x94\xf9dD\xd2\xd3\x05\x1b\x93O)+\xeb\x1b\x83\xb4\xa2xu\x07$\xe3\xf2d\xcc\x96l5&\x1f\x19\xf5\xc9J`m\x9a\x11\x15hu~9^\xb1\x87y\xca\xa4\xa8cT~\xc5\xa9\xdf\x8a\xe1\xa3\x91\xb5-~\x1b]A`\xd0\xcb\x95 \xb8\xe1&\xaf\x80\x0b\x08\x95kn\x04C^r\x1e\xa2\x19\xa2\xb1h\x86\x8c\x94\x8bf\xc9\xa3\x15\xcd\xd2\xce\xc5\xb1\xac\x9b\xd5\xa5\xa5\x114\xc2[\x0d\xfdy?Ge\x8bLK\xdb\x90r\x9a:\xb2\x14\x95\xf2Jk\xc7,\xa5xd\xab\x0fr\xa4\xc7F$\x17\xe2\x01\xe0]\xb8\xa6b\x18kW\xbf(\xff\x1e\xd5\x160\x91r\x83\xb1\x99 \x0e\xec\xa2\xec\x1d\xf0F\x83\xa8o\xa2\x14u\x82\xd14\x0d\x16\x10\x9e\xbb\xaf\xb0\xe79\xc9\xc8\x0bB\x93\x05\x88\x94S%\xe6yN\xb2\xedml\xaf\xe8\xa5^\x14\x98e\x88\xe1t\xf1\x89\x84\x04\x91\xe8\xa1j^y,-i\xfa\xfe*R\x8e&o$-')qqN3\xa9\x1b\x1f\xcd\x92\xf3\x1e\xd7\xdd\x86 9~\xe8\xb4\x8d8Q\x9d\xf2\xccN\xa9Q \xdf\x93=\xd1\x1e\xc95\x01\x8e,\xfb\xbdwN\x0e\xab\xaf\xb8\xfb\xd4\x159 ?p\x1e2\x1a\xa1\xa6\x04\x0b\xa2\x0c\xe3\xe7\xcd\xbc\x1b\x84e\xd3\xe9x\x14n}S@\x0e\x89\xbb#\x0e=5\n\x03)\x81\x88\x9b\x88\x0b<\xa2\x80\x8b\xc0\xe6\xf7\x05\xbd\xe3\x8d\xe3H\xf2z\x1dNb\xdc\x99^u\xcd]Y\x8a\xe6\xd58\x00\xe5\xdb\xbdp\xd4\xeeJ\xcb\xd3\xe8\xcb\x17\xb2%\xe8oZ\xd2\xdf\xba\xce\x12j e$\xf5\xb2\x07\x82\x0d\xa8\xbb\xb2\xd5\x0f: \x95\x11\xbd\x8f1\xa9N\xd1\x1d\x87\xc5\xaf\xe0\xad\x96\x91\xa9\x00\x9a\x83\xe3\xd70\xdf\xa6\xe3\xf3\x96%\x0b\xe6\xdfit\xba$OX9\xb1_/\x8b\x02\xed\xacf\x8b\xf3j\xd2\x85\xa1H\xc1N\x1a\xcb\x08\x1b\xd3\xcd\xa6oKV\xb9*\x07O\xcc\xc8)L\x0b>\x81\x06\xa89}f\x0d\x9bL^\x90\x9e\xe6\x97\xa9\x97\x04\x97\xfd\xe7K\xb5\x1d\x97\xa9\x89\xc6\xe4Q\xaa+\xed\xd3\x86,\xb9)\x1a\xd1\xb7\x0d+p\xbeQ\xffZ9\x1ef\xe2\x81q\x1f8.\x92%\xdc\x92F~\xa8\xa8\xe2\xf1e\x10\xf9\x90<\x18\x0cI#\xdbE\xfc\x8c\x10\xb47\x9f*\x1f\xef\xd5\x9f^=qu\xb3\xaa\xbd\x13\xecd\xaf\xa6\x15\x92\x83\x97\x81\xff\x96\xe7Q\xe7]\xab~\xe0\xa3\xe64\xb9\x9b}\xef\xe7 \x0c?2\x8f\x05k\x84\x93h\xfb\xf0U\xcbN\x90[\x0c\xdc\xc3\xa8\xb9j\xf2@M\x7f\xe5\xfaik\xea\xa7hu\x9b\xd1\xf9\x84\xcc\x94)\xb3\xe8\xd5\x8e\x02~\xa3\xaf\xd7\xb17h\xa5\xd7\xcf\xc2jz\x15c\x18\x19\xb6q,\xb2\x9b\xecd5\x7fm\x9c\xf7?0\x16}H\x98GC\x0f\\\x19\xf9\xca[\x7f\xadi\x06H\xc0#\x10\xa3T\x1b%o\xe6\x99\xaf\xb4\xd4\xab\x99v\xa2\x0b\x01\xaa\xf1%\x0d-|\xfd\xd4&\xc6\xc4\x04}\xa7\x06\x14\x1fk\xfb\xb5\xcf\xa1VCY}\xf9[\x02:\xb9\x07\xc6\xd8\x8eK\xe9Z\xfb\xd9\x07\xec\x8b\x14'\x00\xd1\xd9\xd9L]\xe8\xaa\xc4\xc3m\x1c]\x9f\xea\x08&\xcd\xef\xa2\xf2\xebO\x96\xdcl\x00M\xcc\xab \x1a\xc7\xe1\x8dk\x11\xe2`\xcfW\xe2\xd1vo\xc6\xb6G}s9\x06y\x9a<\xb0\x97\xbdk\xb0\xcb\xb3\xccGQ+6r^\xee\x8a\x0e\x8aI?\xb0<\n\xe7\x9a\xfd\xcaDp\xd3\xb5\xc4\xc8o|\xb7\xab\xd1\x18\xf4\xc7#\xedb?\xd2k\xa8z\xe1\xb4T\xef\xc0~\xd3l\xca\xb4q\n\xc8|\xbe\xb6\xaf\xb8\x16\xe9e\x1f\xbc\xb5`\x99\xb4\xb7\xf2\xb5zu_\xec\xa59\x8c\xea\x15\xc7\xf5\x908g\x9cP\xcfci\n\x97\x12W\xb2\xfa\xe2\xf6kHnxN\"\xc6|\x92q\x88\xe0\x1f\xcco\xc8\x1fD]kNI\x96\xe4\x8c|%T\x16\x9f\xf3<\xc9\x96\xc5\xe50\x01\"\x12\xeeF\xe0~q\x00\xf7HcgP\x1c\x04\xf3t|U\xedQ\x9fq\xe8\xa7\xda\xa5\x1f}\xcdi;\x10\xdb\x11qT\x96l\xae\xab\xf6\xa2\x81\xf9\xd1\x96\xe5\xdf^\x0b\xad\x9c\x02\xb6=\xd7^G\xae\xeb\xa8\x1d\xbd\xf6\xdd_\x1cw\x16\nb\xd2AAL\xfa\xef\xfc\xcd(\x08\xaa\xefih\xbb`-\x95{\xbeuX\xc2\x8e0Hp \xe6\x80\xf5R\xad, /e\xba\xce\xc8!\xd4m\xc2\xb6\n\x88:\x84\x84\x1e\x12\x1d\xb1\xfe\xccU\xb4D[~@\x0ee=;dJ\x803u=\xbd*l\xe7\x8a+x\xa7\x10`\xe7UXT\x82\xe2\xb6]\xc5\x16L\xf2\xd6\x96\xeb\x81\xd6\x07\x8c\xe6\xa0\x18\"\xab\xe8\xc1\x95\xbcqN\x0eIN\xa6jY6i\xc8k\xa5\xf9\xc1\xd5\xf5\x99\xca\x01\x1e#q\xff\xf8\xda$\x95\xbb\xee\xd3d\xe0\xe9\x1a~\xc2#`\x10\xc0\xfd\x03\xd1\x88TX\xc7j\xc5\xd5U\xb4l\xac^um^\xb5\xdf\xaf\x16Z\x93\x03\xe5!\xe0~\xb4\x1e\x87v\xa5\xbez'\xc1K\x90ti[\xdcR\xd5\x8f8\xcd\x98U-\xea\x9a\xc7KR\x83\xa9#\x19\xb0>\xd4\x1a\x83\x82\xd3L\xd4K\xf9\xe5\xda\x81T\xa8G\xf2\xb2j\x9bj\xa44\xbf\xddyN\x02\xf2\x82D\x85zf\xb0\xbd\xdd\xc4\x91\xc0\xd3p\xa5\x194$\xd1,8\x07a\x12\x9b\x89\x9f\xe7\xf2\xeeE\xfe\xb6\xb6\xad\x18\xac\xda\x0e\xf9\xb6Sh\xd9\xe7\x05\x00\xca0\x1b\xd4|\x02\x82\xce#\x00\x06\xdb\x7f\x9e\xa4\xf2\xbc\xe9\x89&\x957\xc2\xa7J\xb4\xd6\xd1[(QV\xd0J\x83\xe3#C\x0c\xb9\x08\x8e\x04\x1a\xd6\nv5\x12\xaf\x17\x94\x1aw8v[\xa0\xcaS\xd2\x0e\xb4`\xd9\xcb^\xb5\x01`\x12\xac\x99\x0fd\xd5\xab\x84\xaf:J\xac\x82\xeb j\xc9/\xceS;H\x06\x8a\xdf\x08+\x8dh\xe7f\xd6\xf1\x8fZG@\xee\xc3\xd6f\xca\xed\xdc2k4\x0c\xc1\x05E[~K\xf9B\xf7\xb8\x0d$\xc8n\xfa\x0e\x85\x81\x0b}6\x0f\"V\xa0\xa0\xe6\xce+A\x17,3\xb0\x15\xc4\\k\xc2s\x1b\xfc)\x98 %\x02[\x89\x97,\xf5\x92 \xce0^\x8fV\n\x19\xdaMMPA\xcaPAEP\xa5'\x85[\xe9\x17\xb4H\xea\x86C\xe2\x0d\xc9\x1cCD\xa0['\x0d-L\xcd:\xcf\xc6\x8e\x0bx\xd4\x0eG?\x023\xc4`g\xeb\xb5\xf0\x12\xb1h\x7f\x0cX\x1d\xb83hc,\xda\x88\x16\xc1e+\xe2S>\xb8\xf8\xb0}\x8a\x13\x1d\x1d\xd8\x17\x84\xb1G3\x97\xbb\xde\xc0\xc6\xe5\x14\x87\xdbR\x9e[K\xf2\x82\xf8\xc5\xb9\xb5\xbd\xbd\xec\xea\xb8 \x1b\xfc\xd9\x121+\xd0\x8fRN\x9e\xad\xc1a]\xa6\xfe\xcfE;\xe7\xb3\xf5\xb9\xd5o\xbd~\xc4WV`\x1f\xee\x0d\xc9\xbaC`\xd8O\xfc\x1a\x89\xb1_\x0f\xc9\xaaC\xf2e\xcaW7\x16\x83\xa1\xa9j\xa56%\xfeMp\x14\xd48\x12\xab\xde\x97\x12\xb7\xd7Y\xd8\xed\x81\xa2^\x1aL\xd1\xf8\x90\x04\xb8A\x9a\xd6\xdcn\x0e:\x084\x9a\xb3%\n\x18\x96\x08\xd9@\xc6\xbaeWD)\xaf\xbe\x0d\"\xf0fH\xd8\xb5\xc7b\xd8\xcf\xdc\xf3\xf2$a\xfes\"\x9a\x9f-\x19\x89x4Zi@\x9f\xad \x8b\xd6A\xc2#\xe0\xab\xc5\xa2\x06\xc9^\x1e\x86\x04\x82\x9a\x92\x15KS\xba`\x84F>\xa1\xbe\x0f\x11OhH\x96,\x8c\xe7yH\xaeh\x12\x05\xd1\"\x1dc\xda\xe2,L\x99eQ\x89>\n\xcehV\x1f\xa6s\xbb\xe0\xc3\x83\x9d\x86f\xbb\xd5\xa1\xc8\n\xbf<\x0f\xff#}\xb8\x18\xf6\x13\x1d\xeau3\xf3\xb6\xb7\x9b\x01\x1c\x88d\xfa\x07\xd2\xee\xe1\x808\xaf\xa35M\x02\x1ae\xe4\xa7\x80K\xe1\x15b\x00\xd1H\x91\xf2\xact\xd2\xec\xcc\x1f_\xf1\x1d\x828Hi\x02\xea\xd5\x87\x89\xd0\xa4#\xa8l\xd8A\x95\x13C}L\xbaE\x91\xf6\xd1!\\k\x83<\xb04\xaf\x9a\x0c\x86\x98\x8d\xff`Hr\xd1QO0d\xa0h,\xc5o\xa2\x7f\xdc\x8d\x86\xe4\xe9\x90\xa4\xd8\x01T\x1c>s\xe3;\xcf\xc9|4z> \x01\xa8\xfc\xcd\xe6\xe7-R\xa2\xeaR\xb3\x99\xdd\xa2\x0b\xcf\x1c\x8c\xde\xbe\xe5\x8a\x06\x8b\xae\x8d&C\xa2E\xbc0U\xe4\x90\xec\x80Nvy|F\xe4\x05I\xe0\x86R\xe9\xd2\xb9l\x16\x9dK.~\xf0\x1c\xa7b\xea1V{o\x99\xc6\x9a\x96;\xe6\xc9\xa3.{d\xac\xab\xa6\xec\x06\xd6\x11w\xb3AE\x90u?\xad\xdb{\xba\xffo\xd1\xbcF\x88t\xd9\xbcI#\x02\xbbB7O\xea\x88\x82vK\x07\xba\xfa\x89\x9e\xad\x89\xcb\xca \x8eA\xc3\xb7\x91\xbe(\xe2\xa84D\xac\xd3\xd9\xb9E\x9e\x91\x835\xd0\xc0u\x0c\x1b\x0c\xa0\x88sP\xe0\x83\x8b\x00*\xe5\x13L\x9c\xfc \xd1\x8e\xc6q\x9e.\xdd\x1c_\xbb]\x06\xb4\xdd\xbb\xae>\x06\xba\x7f\xf5^\x14Hr\xeb\xa0.]%\xd5\x9d\x1aDj^` 3\xd9\xfe\xba\xaa\x9e\xc6\x81\x9b-\x9f\x8e\x88\xdb\xdaM\x1321\x1c\xe2j+c\xb3\x83\xaay\x8f\x8c\xebdx\x95\x14i8\xd3\x05\xd4>R\x8f\x14\xb9B=\xacR\x0ff%N\x943\x81\xa0\x9c\x90\x03Q\xf5!I\xc6?\xe4\xf39K\xc8T\x99}\xdaX\xb3CB\xc74\x0c\xb9\xf7)J\xe9\x9c\x15\xf0\xd5A\xee\xbd\xbb \xa9;\xed\xd21\xca\x91\xc3`]h\xa4+e\xe4\x06\x04QL0\xdc\xc6\xb8\x11h\"\xb3+\x02z\xdez\xe1\xa3\xba\xe3\xc5\xc7=\x1e\xdf\xb8\xc9`h\xf52\xf7uP\n\xf2\xdc\xc9\xde\xa3A\xe1\xeek\xf3-\x80\x0c\x88q\xe64\x1bi\xf4\x1d\xd9\xe9\x99TP#\x07\xe4(I\xa8\xe8\xc5\xa08\x99\x9e\x0fH6\x8b\xce!0|t~\x1f;\xa2\x13\xdfO\xf6\xefr\x1c%\"\x13P\x9d)+\xbc\x9f\x96\xed=\xedt\xdcqO-\xab7+\xba\xff\xa3C\xa3M\xfb\xa6H\x14\xabQ\xdd\x05\x16\xc9\x8a4\x82\xd5B\x13\x03\xcf\xccv\xce\xe5\xa9\xa0\x8f '\x88|v\xedH\xcd\xe0d\x0co\xd0\x0e\xf85$\")\xce3\x95\x14\xe7YeSm8\x93\xbb\xbb8\x93\xb0\xff\xb4N\xae\xabS\xfb)\xee\xdap\xff\xe9\x1e\xca%\xec?\xad\x9f\xf2b\xd4\x9d\x99D\xb8\xdaQ\xc0\xb9\xd3d\x19\n\x98\x974cu\x00\xcf\x04xK\xe3z\xfe\xdc\xcc\x7f\x07\x8eD\xea \xb1 \xf2\x91-N\xae\x1b\xb5\xf8&\xc8)\xcb\xea\xf9\xcbJ>Lm\x1dd]\x01\x01\xe9_\x1dde\x82\x00\x86\x91GF\x1dnQ\x1b\x14\xfaS\xc0\xae\xea@7&\xd0\xab\x90\xd3lo\x17\xea\xac\x03^6\x00\x9f\x01\xd4\xb1\xbbA\x1d\xe2\xef\xc4Z\xd3\xde\xc65\x89\xbf\xbb\xbd\xbc\xe7j+a1\xd6\xb7]\xa9\xfb\xb6\x1b\x90G\xf8R\x9d<\xc3tk\x04\x1b\xdbzH\x90\x9aL\xcd\xc9\xb8\x143;-\x91\x0c*^\xf5\x9aHH<}<\xfb)\x83\x07\xc1~\xe0\x00\xa6\xbb\xbf\x06@\xcd\"V\xb0i\x01\xbe\xf3\xf0\x18`\xdd\xbb\xc5\xb2O[93\xbd\x04,\xab\xa4{\xe3j\xd6h\x7f\xa76\xb2bYL\x9e4\x97\xc4K\x9a\xb1q\xc4\xaf6\xc5:\x9a\xdeA&0hj\xbf\xf5\xe9\xfbZ;\x02\xb5\xf9 \xc8\x01{\x8e\x88K\xc9\x08\xf5O+\x98L\x88\x86#\x0e\xa7\xef\xc9\x0e\xf6\x15\x0d\xb7\xbd\x9d\x91\xef\x0fHapnx\x8e\xdei\xaa\xd4}\x95\x1a\x82\x19\xae\xd7W\xdb\xb8\x9a\xcd,j\xbc'\x89\xe1\xe4\x11.\xe3hluEn?\xc3\xc9\xed\x06S\x9a\x93\x03T\x0d&\x85\xf4\x86\x16L\xd8}\x95Y-\xe0\x011\xde\x89G@ \xdb\xcd\xe0\xf0\x92\xb1\xbb\x80\xc6L\x95\xd6Os\xd8\xc5\x94\xa0\xf3[\xd5\x0c\xc9\x06$,\xf1\xb1\xe6|\x80D\xcafQ\x1d#[\xa8+o\xb3\xa9\xda\x7f\x86\xc7\x93\xd8\xdb\xe9\xbe\x1a\xb7R\xbc\x05\x08v\n\x13\xe3\xfb\x18iG\xf4\xbahU\xa1\x90\xfc\xaf$\xbf\xa2YPeL\xec\xbbR\x14\xd9\x85\"\xbb\xe7\x16\xc5\x10\xa2\xe7\x85\x1aW\xd6\xda\x9f;\xea\xe6Ip\xdan0\x1a\x81mu\xd1\x06\xa9Y\xcf]\xf3`\xcd\xe5U\xb4l\xfc\x0b\xb2g2\x06T\xdak\x81^c\xb1p\x05\x95A\xb6\xb7\x13\x08\x16h\xc3\x12\x9aP\x8ef\x89E\xf5\x1d\xcc\x95\x81\xdcNe4\x8f\xa6\x92\x92U\xb8V\x0bip\xeb\x83\xbeyp\xab\x95fa\xc2\xf7\xf6m\x11\xe5\xfap\x83\x81\xab\x83='bS\x92m\xe28\x1b6\xbd+\x12\xcb\xfe3\x1c\xcb\xed?{j \x1bWo+\xd8/\x03j\xf2xH\xaa\x8e\x8aB\x9a.e(\x882\x91\xe6\xd9\xb2\x9a\xb2\xe4i\xcd\xfd\x8f\x18\xa4&\x8cR\xb0\xae86Jku\xa5\x8c&^-\xed\x1f9Knj\x1f\xa0\xd9\xb2Y\x9dH\xad} asRs)T.\xb2l\x0c!P\xc9\x01\xb9\x1c\x92l\x9c\xb0\x94\x87\xebN\x97\xaejr\xc1\xc7\xdd\xd6\x04\xfc\xba\xe9\xa2\xa6\xaf\x9a\xafF\x95r\x1f\xf5\xac\x98\x91C\xb4\xf2b3V<\xac\xc3g\xe6\x0eRIl*y\x16H}.\xad\xd7D\x15\xdf\xf9\x01D\xe0\x96_\x81\x18\xcb\xa6\x1f\x0f\x99\xac\xafZ\xaa\x0d\xfb\x94\x88%\x15TW.\x85\xd0\xc1\xee\x8c\x8e~\xdf\x19=\x1bo\x8f\xce\xb7\xa7\x83\x87A\xf3\x98}8\x9d\xed\x8c\x9e\x9d\xff\xe5\xcf\x0f\x9bG\xed\xc3\xbf\xbb\xbf=\xfc\xed\xe1\xa1{\xb8\xf5\xdb\xc3\xc1\xec\xef\xbf\x1d\xfe\x96\x9e\xffe\xe0\xfev8\xfb;\xfc:\xac\x97\x02\xb3\x04\xe7\x0fgH\x9c\xaf\xe2\xcf\x17\xf1\xe7\xb7\xdf\xc4\xdf\xbf\x8b?\xff\xe5\x9ck\x03\xa1\x99\xf3B\xa4|\xef\x0c\xc9w\xcew\x90\x07q\x80E\x81\x04\xfeF\xf07s\xce\x07\xcd\xd3{\xe6|WV\x15\xd6\x00\xe6\x00\xf0\x1f\xa2\xf8C\xf1\xe7P\xfcy.\xfe\xfc\xaf\xb2\x90W+\x14C\xa1\x12\xfe\x7f95s\n\x1fFd\xb6-\x87\xf4h\xf4\xb7\x8b\xd1\xf9\x1f;\xc3'{_\xeb\xa3\xb0T\x83\x8f\x80\x0e\xdc\xf1_\x06u\xf85ja\xf8\xdftM\xa5!\x1b\xce\x958\x06\x80\xd3\xe0(j\xd6{\xabo\xff\x89\x05\xfa \x88\xcb\x84V.r,\x86\x89s[\x99\x05\x8f\x976\x83\xc8y`\xe3\xdf\x1ch\x84\xd3\x92\x99Zs\xe7-%Uk\xacEE\x83:\x87\xedF\x9d%\xfb\xe8Yri\x93q\xfc\xff\xec\xbd\xeb~\xdbF\x928\xfa}\x9e\xa2\x84\xec8@\x08R\xa4\xe4+mZ\xeb\xc8\xcaF3\x89\xedc\xd93\xbb\x87V\xf4\x87\xc8&\x89\x18\x048\x00\xa8K\xc6\xdeg9\xcfr\x9e\xec\xff\xeb\xaa\xeeF\x03\xe8\x06@\xdb\xc9dv\x07\x1fl\x11\xe8{\xd7\xbd\xab\xab\xe8\xfa:\x17<\x06a\xa6\\\x8d\xc9\xbc\xa2S\x95\xa6\xe4\xb5\xd2\x1b/4R\xa7\x94(\xb7\x1a@\xdde\x0e\xc7\xa1Q)I\xe9\xdb\xec3\xe2\x12\xbaF,-)\x05^\x05i\xb0f9K\xe1\xebm\x1a}M\x19\x05.\x19\x04\"gU-\x81\x80\xc9Q=,<\x01_.\\\xe7\xc81(s[\x94Q\x8b\x14g\\h\xd3\xea|\xe5xp\xc4\xe9\x02\x8c9a\xa8\xd7\x8f(S\xc6&\n\xf3\x9a\x97z4\x1d\x9e\xc3\x04\xff+\xaeV\xbd{\xb7\xbfD\xf2d\x18\xf0%\xa6\xfb\x99@4\xf89 \xe3Z{|\xf5x\x91\xcbA\x9e\x86k\xd7\xf3a\x0fS\x8d\xcb\xb4\xc54\n>\xe6\x06\xf3\x17\xef\xe7\x02&\x90\x91#\xc3\xa5Ew\xbd(\x07\xf0\x16\xcc\xff\xb2\xcc\xf9/\xeb\x02\xc3\x05J\xc1\x17\\\xf8>\x92\x81\xd0\xa4\xd4\xc1\xdfV\xa4\x8e\x1c\x8e\xe0V\x80\x9bV\x18\xc3\x96\xe6\xa9;\xf2T\x10n\xe3\x07(\xa2\xad\xc9N\x1c\xa7\xd2\xc5\xdf?\x8a82e\\\xac-\xfe5\xd7\xd6\xcd\x8b\x82\x91\xffl\x8by\x02\x13py\xe5\xeb\xe9\xf0\xdc\x1b\xe4\xc9\x0f\xc95K\x8f\x83\xcc\xe8>^\x15\x08O|\xa0-\x15\x13\xbb\xaey\x1f@m\xb4x\x19\x81\xab\xa6\x18\xc1\xf0r\xb0\xc6H\xea\xfb?q\x96=\xfd\xe9\xdf\xdf\xed\x9f\xf7\xfe]\xfc\xbfo\xbc\xef\xca\x87\x8dn\x83\xfb\xfb\x0e\xc2\x8e\xea~\xe8\xc3\x81a\xd4{7\xd4\xdd\x9d;\xb0\x9e^\xe3\x8dZ\xb74\xec\x03\xaf&\xd5V#\x91\xd6\xe7\xb0\x87m\xf1-,\x9a\xdf[N\xaf\xcd\x97t\x95&}\xe6\xc3\xb1\x8f\x9e\x87\xfd\x91\x8f\xde\x82\xc3\xc7\xf0\x0c\x9e\xc0F]\x85zfNP\xc6\x1f\x81\xec\xeeK\x1c\xbeD\xf4\xcd\xf4\xd9\xb9\x88/\xdc'tz\xcf\x87\xf4\x12\x9e\xc0{z\xcd\xfb{iP\xaa\xb8^J-\x1e\x13)\xa1\xcaGpY8\xffpJ\xf2\xef\x98\xa9\xbb\xf6\xd2\x87\xf7\xa2\xdf3ZO\xbcw0\xf4\xe1\xd8S\x90\x81\xaf\x8e1\xa1}YM\x98\xb3Y2go_\x9f\xaa E\xee\x99\xe7\xc9\xb5\xb1(\xbd\xda\x82-\xba,\x18_\xf2\x97\x8f\x8bi\x96\x17n\xf1y\x0bG\x15d\xb1K \xfce\xddG[\x95\xf7\x95Uy\xef)\x12\x94f\xec\xfb$\xcb]\xaf\xae\x14\x95\x7f\x7f\xf8\x00\x8e%\xb3\xd6+<\xd7&\x9c(U\x12\x8e\xe7\xce\xb9\xe9[\xe9\x974'\xf4adP\xd5\x11\xec_\x99\xef\x81+\x00\x7fS\x1d\xb2\xa0\xec\xfb\xef\x06\xfb\x9e\x0f?r\x82\x83\xbb\xe8\xc3\x1b\xb9b\xb4\xa1?6\xee$\x88Y\x9e\xc2\x04\xdeL\x9f\xb5\\\xa2?Et<\x15\xd4e\xdezq^\x0d\xffgA\x85_\xd0\x10_\xc3\x04N\x15\xa0\xbd\x80'\xf0\xfa1\xbc\xe0\xa3<\x1d\xccVAz\x9c\xcc\xd9\xb3\xdc}\xe1\xc1S\x18\x1d<\x80#\xf8\x19z\x13pn8\xcf\xc5?O\xa7/\x1a\xc6\nrY\x7f\xee\x97\x8b~ \x19\xc2\x198\x1e\xf4\xe0\xd2\x80\x15\xcf\x8b\x12\xedc\xb9LY\xf0\xbe\xb1T\xdd\xbc\xd4\xfc\xa5\xfe\xd6\x88GO\xe1\xe0\xde=\x99\xeeA\x1b\xbd\xe3H\xc9\xc0\x86\xe8eV\xec\xc3+-vvQ%\x1d\xe4\xc9\xb3\xb3\xe3\xd3\xd3\xf2\x17\xd3\x05b\x0e2\x7f\x93\xbd\xa0\x15\xe6\x08\x9c1\n\xa1\xea\xcd\x98\x83\xbeq\xbe\xdfu%D:\xe9\xfb\x0ez\xf07]\xe8\xeai\x8d\xf0))\x01\xc8\xba\nRb\xf2\xcd\xeb\xdb\x07\xce\xbb9\xccp\xea~)\x08\x9d\x06H\x97^+\x1f\xbf\x9a\x9e\x9c[.E\n:\xc5i\xd6\xac\xe06\xad\xa4\x8a/\xf5/\xbc\x8e\x95L\xf1\x8e\x05//\xb8\xd1/\x8d\xa8\xcf\x1b\xfd\x96\x8b\xd8q\x8dm\xfe\xd2\x80\x02\xdf\"\xc9\xff\x05\x97\x05\xabg\xb3`\xc3x_\x8a\x17!y\xfe\xc5#\x84\xfa\xd6L\xde\xeb\xf0^\x97A\xffR\xe2\xad\\\x92/\x18\xef_\xb4\xbd&\xcb\x9e\x92\xbe\xfeR\xe1\x8aC\x1f\xfeR\x05`\xde\xfc\xf7\xe5\xe6\x8f\xaa\x88\xaf\xad\xe9\xf7u\xf1]u\xf7\xbdW\x11\xb1\x8b/RH)\xc6*\xcb\x94\xa4||\xe9\xd5G\xfd\xfd\x8eb\xfdeQR\xd3A8\xb1[NO\x10\x90\xcb\xb8\xa1\x82w\xab\xd2\xa6\xfa\\9\xabj62\xbb\x18\x0d\xc8\x04e\x05e\xd0\xea\xd8\x04\x8d\xbf\xaa\x88\xb54\xc1&R t\xaf\xbfA\x0f\xfe\xda\x80\x89\xba\xba&\xf43\xfc[\x1a\x16+JP%^p\xdd\xc8i:eU\xd4\x05\x05P\xc3\xa0\x992~\xe2?\x06Lc\x9e\xa7\xc5\x199|\xb6\x1f\xfa\x9c\x88\x92 \x7f\x02\\N\xae\x03\xae\x8aM\xac4'\xec\xbbNhc\xf3&\xd4\x0b\xa6Z\xcc\xe2\x95\xadPh *\x1b @\x96\x87YP\xed#2\xcb\xdd!\xf5\x14+\xe6\x18#\xc1*\x9c\xd1\xb0.\x86\xe0p\xberD\xc0\xc7r]\x0ex\xfc[\x0f\x8f\xad\xb6r\xe2\x18\xa8\xabR\x94/\x14-\xca\x16ij\x0fB>Ht7/phz\xf4\xd5y)ZOSLQ#B\x96\x89\x8a\xc7\xe5E\xec{\xab:q\xber|p\xfexp\xe8\xe0\xd7\xd4FEL\x87<\x96\x83\x18\xdc\xa2\xf2\xe1\x8b~.\xe3)\xba\xd5\xd2\x97\xe1\xf4\xc7du\xac\x18\x1d\xcd6\x91\xdcl\x16\x85\xe24K\x1b\xa1O\xd4\xb0\x81\"\x97\xe2\xb7`\xbb\x14\xc2\xa5\x8aQ\x9e\x8f\x14e\xf8\x18\x02x\xa2\"\x84>\x86\xc0\x9ef\x1d\xfdO\xa6\x81\xc9\x83q\xba=\x17\x086\xdd\x9e7\x8c\x8eB\x93\nQ\x02\xbd&V>\x97\xaa\xc9\x96\xc89H\x11\x0cH\x1d\xf5i\xdc$\xae\xcb\x0eL\xe1\x1c\x85\x82\x90\xd4\xba\xd1\x9c\x93\xd5\xc3\xac\xa2Uu\xf8\x18\"x\x02E\xd6\xf9\xa8Y\\\x9c\xc1\x04\xb2id\x11\x17\x1d9\x16B\xb5\x19\xe1\xf1tF\xd1\x08f\x06\xf1\xd5z\\\xbe\x9c\xc6jf\xe2:zI\xc0\x88\xcb\xd2E\xacNN\xeb2\x86ya[6\xadXW@g_\xf5\x8bHU\xd3\xa2\xa3\xb4\xbe\x9c\x16u\xcem+Z\n\x96T\xdd\x9e\x0dm\xcf\xa6dB\xda\xb4\x1b\x1e0\x04\xf1t\xd3\xa0\xcc\xc7\xd39\xed\xc8\xdc\x12K\xcc\xf8\xb6\x11L;l,\xa1\x82f\x95-\x16\xc8\xe7\xb8\xc09\xf8\x87\x0f\xb0./\\i?\x99\xfaQ\x9f\\CD\xb7R@D\x97U\xc4\x16O\x9a\xf4\xf7\xb9\"\xb0\xd2X\xee\x9e\xcb\xa4\x8a\xb8\x1a\x90=\xc0\xabEx\x92O1\x83\xa2\x162*V\xd2E]V\xd6\xaf=$\x07\x1c\xa8VB+\\)\xe3\x03~]\xe9\xfe\xf8\xf5\xcf\xa5\xf5Y c\xc3\xbe!\xdf\xbbmC\x94\xf0\xcf\xc4\x9f\xbcM)\xff3\xfa\xcb\x17\xd8G4LL\x93+\x0b\xb14\x922\xfc\xc3\xd7\xb1tR\x999\x13\xeat,}+\x18\xfeQ\x9a\xc2\x87\x0f\x107H\xff @\xfc\xaa\x8c\xe8\x16\xc1R>x\x04\xd8\xa2\x03\xf0G\xd1\x90+\xe8\xc1m\x87\x05T\x18\xa1y\x99\xe8\x02\x91\xa2\xd4\x9f@\x83\xe4IU\x99\xce9\xe2(\xa1x[H3\xf5\x05\xb8(\xed\x173\xb6\xc4:\xb5t\x0d\x13\xb8\xe0\x8d\\\xd2\x16a\x9bD\x17E\xedz\x9d\x13\x98\xc0u\xfd\xf5MmR\xdad\nL\xe4\xfdL\x0d\x11\x17\xcf8\n\xafJ\xb4\xa0<\x90z\x1b\x1a\xb9\x06:\xfc\xd0X\x8bA9?\x13\x1c\xa5\x84\xa7\x1a\xdc\x92sN\xb1\x08\xae\xe0\xe77\x1c\x81\x8f\xe8\xbf\x89\xfc>\x86\x1b\x85\xb0\xf4\xca\xf34t\xe2\x0d\x97YM\x99@P_\xac\xdc5\xabu\xbd\xa2\xaeW\xd45\x93]\x17\xb4\x82\xa9\xae\x15q\xc2\x0c\x7f>n\xedu\xad-D\x135+^\xef\xc23\x13\x01)\xca\x90R\xa6\xba\x8e\x15\xb6[ B\xa9.\xbe<\xd2\x7f\x8c\xb5\xba>t%T\x1c\xbc*WY\x903\xf0\x8d]\xa9\x13[<\nso\xe8*\x8b\x0f7\x83M\xb2\xe1\x18\xc9\xdf\xdcH\x17\x96\x95\xd7\xb5[K\x7fx\x08\xffb\x1bE/\xd3\xb71Et\x9e\xbb\xb2\x19\xa3|\x8c\xe0\xe7\x95\x17M\xad\xfa\x8d\xe4A>\xb8\xaf\xb8\xd2\xbc\xe7\x16@H\x7f\x15\n\xed\xbf;\x1eyD\x17\xdf\x04b\xfc\xbb#\x8e\x92\x14\xf1~U4\xac:+\x0d\xe1U\xc1\xfd\x1a\x88`\x87\x85\xf2A.\x89[`=\x8eF{/\xe9?\xdf\"E\x93\xb5\xf2p\xa4\x13\x901g\xa2\xa8\xb1\xc9\x11\x1c\x15\x83\xc1\x8f\x9f*\x02\xee\xdd(xQ\x93\xdcT\xbd\xf6J\xbd\x8a\xb1\n\xad\xb5\x18D!\x9dJ\xd2\xd1*\xe9+\x99\xe5\x98v\x1e\x8dw\xfd\x91\x87^\xb0\xefiA\n\xca.\xff\xba)\x0c\xfaB_w\x06\x84e\xc7\x88q\x03\xf9\xcb\xd3\x10\xf0X\x9c\xef\xfa\xf0\x12\xfb\x92\xb2\xe6Kx\x8a\x12\xe8\xcb~\xdf\x03\xd9\x0e\x1e\xc0\xdeL_\x9e{\x9c\xd4!L\xcd\x98\xfbR\xdc\x7f+:\xe0J\x7f\xf9\xb3O\xa6\xe81<\xc3\x81\xd5>\xf6\xfb\x06Z\xbcG\xe7\xd5'\x16\xc3\xf7c^\xed1<\xf34*\xcb\xc7Pi\x89\xb2\x10\xead\x9a\xaf\x95\xb8\xfb\xf0\xf0\xfe\xdd\x07fM\x8ck\xfc\x87\xf7\xcd\xdff\x18f\xdc\xf8\x89\x83\xf9\x81\xa5\xda\x867\xf9\xd0\xfcm\x0e\x13xP\xbd\x13'\x1f\x8ez\x0f\x0e\xcc\xdf\xb8n9:\xb0\xb4\x8a\x91\xf1\xfa\x16]s\x89~\xc97q\xbf\xbfo.\xc0\x05\xa1\xfd\xe9O\xefn\x0e\x86\xfdw7\x0fN\xce-\xe5.\xb1\xdc\xbb\x9b\x83\x93w\xdb\xc3\xe1\xf0\xe0\xdd\xf6\xbb\xef\x86'\xfc\xdf\xfb\xa3\xf3\xfd\xa5\xb9\xd2\x855\x8f\n\x7f\x92+\x96.\xa2\xe4z\x0c\xceK\xf5'Em\x8c\x19\x9bgp\x1d\xceY\na\x9c\xb3%K3\xc8\x13\xd8\xa4\xc9\x8ceY\x83b\xed\xc4I\xde\xbf\x0c\xb2p\xe6\x8c\xc19\x8d\"\xb6\x0c\"\xd1*\x17\x1dn\x1e\x0e\xc1\x8d\x93\x1c\x02\xc0R\x80h\xb4I\xc28\xf7\x9a\x9a\x0d\xe3\xab \n\xe7}l \x9b\xa6\x17\xd4\xb49\xf1\x9d!\x9d\n\x08\xc55\x82>\xcc\xcc\x9f\xb9\x8e\xfac\x90\xaf\x06\x8b(\xb1\xe5\xae\xe4:\x01\x19\xb5\x07\x8b4Y\x1f\x0bo\x1a\xcd\x9dX>\xca\xad\xf8\xcc|<\x00*\xc6\xfe\xeb ^\n/\xdc\x8b)3\xdaE\xed\xad\x1f[o\xd4A\xd5\x1e\xaeB\x85\xa2I|z\xfe\x18b\x0c\xc4\x9eR\x84X\n]n1hI?\xe5\x9d\xc6\xf6\xbeql\xc5\xb0\n\x89\xc2\x0e\x07\xa9\xe1\x00P}\x93\x02y!\xef\x82<\xf8\x89\xb98\xd5\x03\xf4\xfbC\xceON=)\xf4\xe0\xd8\xa5\x13Su\xe6r\xe9s\xc9\xd6S6@\xca \xeb\x15N;;\xcd\xfe\x99}\xdf\xd5\xb6P\xac\x06\xda\x0e\x1f\xaf:\x0d}\xe1D-\x05\xef\x84\xae\xa9\xb9\xa4jk\xee[I\xaf\xe7y\x1c\xb5\xee\xdd;xt\x9f8\xc7\x93 \xdc\xbb\x7f8z\x84R\x0b\xaf\x08G\xfc\xc5\xc1\x10\xe3\xa2\xdc\xbf{ot\x00\xe24\xad\xde\x96G\x01\xce\xb8\xbc\xea\xba\xa3\xe1\xc1!\xdc\xe1\xbb\xf7\xe4 \x8c\x86(\xc5\x88w1\xffq\xff\xde\xbd\xc3\xfb(X\x89*9\x17\xa0\xb8r0\x06\xf5\xe6\x0b\xc2\xd2K\xfbj\x8a\xf6\x10\x13\x9a\x8f\xe4\xe4#O\x9el\x00\x05\xfa\xbd\xa1\xa78\xd7{\xa0\x0e}\n\xa3!\xdc\x01\\\x9e\x0f\xb4\x1dB\xa0\xa1\xb5\xff\x00b\xe5\x18\x1d*\xf2&\x0c!\xcd\x01\xcf\x02\x05\xb4\xed\x08l\xaf\x1aQM\xcd\xa5\x07\x07\x07\xd0\x83\x07\xf7\xe0\x1bp\x19<\x81\x83\xfb\x1e\xf4\xc1u\x87\x18\xcd\x0c7\xfb\xden=\xbf\xb1\xdd<\x90\xcf\x95\xb8\xfd`I\x89\x82\xb8\x80\x98 Gp\xe22\xd8\x879\x06\x95\x03\xbe\xae\xc2G\x81\xde\xe7\xdec\xdc\x8fk\xf8\x06\x16\xf8\xf91G\xe4 D\x1e\xae6\x95\xban\x06\xbb\x13\x97\xe3\xbe{\x8d~3\xf0\x0d\xf0*._\x99\x8d\xb7\xdb\xc4\x7f\xb4\xc3\x98\x86\xdaz\xce\x18L\x075\xf7a\xe9\xc3-9\xe2\x98\x8c\x9a\xf2\xb9\xd0I\xb6\xb5\xd4\xb5\xf9\x16\xbe|8\xbf\xba\xb2\x7f>\xae\x1b\xc8\xe4\x83\xfb\"(\x85\xeeA\xbd\xf6f\x82\x82\xd0\xf3\xe1\xc4\xbdF<\x86\xa7\xc0'xc\xe8\xea\x86\xf0\x9d\xca\xf1\x89\xfe\x11\xb3\x03_J\x0b\xd1u\xaf\x87\xa1\xa7n\xba\xfa\xfcA\x81\xfb/\xdd\xcb\xddp\xfc\xf4sq\xdc\x87\x0b\x9fC\x9b\xb8>QMr!\x1f\x04\xccK\xe9\xc3\xf5\x0c]\xb6\xa4\xb0\x96#\n\xa3\xa8$\x84\x83U\xc9{\xe1\x92c\\\xe0\x11tN\x83s\x8e\x9e\x02\xd5\xde\x13j\xdd\xb85\xaf\xa0R\xc7)\x06{\x99\xc0{\xd5g\xa2\xd5^{\x84\xd9\x97\xed\xa8\xc5\x91)k\x19\xdcS\x91\x81\xfc\x16\x9e\x88,\xe6\xbc\xd6m\x837\xa8h\xba\x0fy\x81\x1a1G\x0d\xf7\x02c\x82pBn\x02\xda\x98C\x12U\xe4\x84\xfe\x82\x96rk\x1a\x9f\xb5o\x10\xa6\xc7\xd2\xea\xe2\xf8{\xbd\x18\xa1\xb8\xde\xef-P\xda3\xfbb\xc9\x07g\xc6IK\xec\xa3\x8e\x1a=\x96\xc8\xcc\xd1q\xce\x919\x14\xc8<\xe7\x0b\x17j\xc8<\xc70(\xdec\x98\x0bd\xe68\xb8\x81>\x87<\xa9\xe8,\xfd\x02\x04^\xb9K.\xf3\xc2\x1f98\x0e=O8\x15\x9c\xb8\xc7\x0dF(O\xf9\xb4\x13OAj\xafW\x97\xf0\xf4\xe7c\xaf\x17\xf3R\xf5\x84S\xd0\x86\xc7\xef\x9b\x84\xa4\xea\x9b\xadU\x17\xbebi\x16&\xf1\x18\x1c4\xe6X\xb4\xd0\xed,;0\xe5\xb2\x96\x0f] \x1a\xc33;\x9b%\x1f\xb01\xbc4O\xd5b\xb4\x10\xed\xfeh\xfe,\xdb<5\x7f\x16.\xf6\xe3\x8e\x12\xb1\\\xd8\xee2\xb4V\xebv\x90\xb3,\xa7\x98|\xceM\xdc\xef;\xd0#\xd2iJ\x99-\x9f\x8f\x16\x02n\x9b\xcf\xdb8\xa4\x19w\x1b\xdfg\xcdh\xa9\xcd\xe8GW\xe6\xa6\xb9[\xb9k\xf8i\xf3\xab\x83\xac\x0fZ\xbeD\x94n\xac\xa6Y\xf9\x88qn\xeb\x8d\x15\xc1nP,g\x14\x02\xd3\xd5c}$\x15\xffC\xdd\xe3\xcf\x90\xe6\x86\xffy8\xb2d\xbb\xe9\x14\xdfC\xef\xbc<\x1f\xe9\"\xd8\xb6\xabb\xbe\xa6\x0c%\xe5\xb9\xf8\x95\xe6\xc9\x91\xaak\xf3\x16K\xab\x88\xf58i\xeb\xec\xc56\x8a:v%\"\x85vjR;1\xde\xad\xf5\x1dC\x89u\xda\xcb|@\x84 \x0d\xf8\xf2\x16z\xec>|\xf4\x88+\xb7\x03\"Kd\xdd\x97\xde\xc9@q\xaa\xba%\xf3.\xf7\xaa^+\x91,m\x8a5\xd2\x12\x99J%\xb1\xa9e\xf0\x81\x96\xb0\x87>\xd4l\xf8x\x84\x81G\x89w\x1cbzxC\xd8\x99\x18\xf2\x8a\x07\x86L\x90\xa19M1zC\x0c\x853D\xe5\xc89\xa8\xb7\x8cqE\xde\xf5\xf6+\xc29\xd3\x0ckU;\x8ct\x01\x1d\xb1\xc3\xca\x888\xac;1\xe6\xa3\xd1q \x1c\xac\x83\x9b?\xb3[\x14v0\x85\xa9zch:\xd2\xcdW\xa5\xaf\x99\x0c\xf5\x19I\xc9 \x13PV\x1bQ\xd61J\xa4\n3\x8c,\n\xbd\x9e1\x833zLJ\xa9{\xe5\xa3\xc9\x9eMg\xc5\xfd\xff-\xfaQ\x0fm\xc6\xc55\x17\xaf\xd5\x81\xa7)5\xc6\x1a\xed\xd7p\x04\xee\x02\xcb\x16gTk!D\xa9wk!\x8c\x8eEY\xfa\x8c\xc7\x94s\xf3\xed\xe1\x85\xe7\x83\xe5b\xf1\x86k\xd6n\xe0\xc3\xdc\xa3\xb0\xd3\xd39\x1e\xb4\xf3\xffI\x16[a\x1cTr\xe0\x9c\xf2\xff}X\x9d\x17\xafV\x16\xec\x87\x02a\x82\x02\x0f\x8a\x89\xe3\xf9\x97\xcc'6\x083\xfc\x9f\x83e\xab\x8by9Q\x90\xb8\xba[CJ\x19&\xb2\x1ecgw\x02\xa1\x8f9m\xf4IWYld\xf8\n\x030atO\x89\x94\xcdA>\xebpB\x95/)gTKm.)\xe5\xe9\x96a\x94\x8bE\x10e\xcc`\x8a\xa4\x06\x05>6\xe7B\xc9\xbe\x0b\xe30g$\xb1\xd0\xc1s\xbd\xbd9[\x04\xdb(ol\xc9q,@\xf3\xd1\xcc\xce\xeb\x84\xb2\x16sX\xb4l\xa7\x97\xbe\xc6\x0dA\xdef\"\x91\xc8\xb3\x1c\x7f\x1eA\xe8\x06(\x9b\xa8\x01\x046\xea\xc0I\xa4\xe1\x16F\xea\x06x\xb5\xc2\x90wW\x8c8qI\xe3\xe3\x9d\xf1\xbf\xba\x08\x92R0\x83\x9e\xb9Of\xb22\n\xa3/\x86\xc2\xb2\xd7\xe4c\xa9\xde\x1c)U<2W\xdc\xd24\x1bF\x84\xf0\xf2\xfb\xa2\x04\xe6`o&\xd6O\x0e\xfa\xeb`\xa3\xe5\x92\\\x07\x9b\x1a\xdb+\x9d\x85M\xcfKV\xcb\xe2\xb8%\xed\xf5<\x99\x035w\xd94\xe5\x05-\xfe*\xd5d\xa8\xa0q{\xcd\x81\xbfy\xbd\xae,\xf9O\xcba,\x99\xd7Y\xb6\xa1 \x97\xbfR\x1a\xd4\xda\xea\xef5\xeb*fb-\x9fn!0\xe5#\xc6\xee\x96\x82.\xe5\x82\xde\xc5\xec\x1ar\xb7\x80(\x97S\x8e\xcb0\x0e\xd2[\xc7\xf3\x8a\xd7\xcee\x90\xb1\xfbw[-\x07V\xa5\xe8\xde]O$M\xed$\xce^iY)\xcdA\xdd\x0f, \xcf\x0f\x87\xe6\x84\xe7\xf7;\x05\xf47\x1c\xc8(\xde3\x01\"\x9d1\x14\x19\x0bb\x91\xb1 uC7\xf6\xd0\xc2\xaa\xc4O_$ \xc6P\xacB\x17\x8e\xd1\xbeV\xb8\xe6 un\x81*}@\x9f6p\xc9 \x84\xbe\x8c\xd7o\x14\xc7`\xf0\x84\xe6\x81\xf0\xe0)\xad\x1a\xaf.j\xa5\x9eN\x14\xd4\x90\x13\xf4n\xc8p\xa5%\xfe5E\x84\x1f\xd57\xf3n\xdb\x86YfL\xb9\x16\xe0\x03\x84m2\x92\xde\xc0^C\xc3\x16\xed\nt2\x9b\x9bQ\xd0\xaa\xaf\xc8\x95-.\xfb\xf9\xb0?\xfd\x89\x02\xf2\xbd\xeb\x7f\xf5o\x7f\xbc\xf3\xf57\xbd\xc1\xbb\x9f.\xfe\xcf\x87\xff>\xdf\x0f\xa5m\xc5\x12\x88L\xfaw\xccVA\x1a\xccrtD\x81\x15\x0b\xe6,\x85E\xc8\xa29\xc4\xc1\x9a\x99\"h(\xf2_\xb2\xd2\x94\xd1\xda2\xe7\x8ef\x87\xb6iW\xf5msg\xa9\xb93\xc9 \xcc\xd4/f7\xba\x19\xc3F$Ak\x88I\x7fK\xbbqWL\xd0\xde\x16\x7f\xe6I\xcc\xc6\xba\x8d\xca\xe0\x10\xa8?\"6\xbb\xd9\xb0\x0b5Rk\x7fkH'%\x06\xbc\x1a\x849\x85\x88\xa7s\xf9)%/\xa5\xb7y\x92\x9e\xef`D\xab\x8f\x13\xe3\x97u\xda\xca\xc4\xbc\x95\xe8\x9f\xb8\x0e6\xa8\xf6\xfb\xe50\x81\x89\x0c>z\x12\xccV\xed\x81\xb1Us\xc1f\xc3\xe29%\xbb\xa9\x8f\x98n`\xa3G\xb5.\xab \x85\xc0\xd0]\x97\xbe\x18:\x98\xb3\xe9\xc8\xe4\x94T\xf4\x88{ \xc4\x93%\xcb5\xa1\xe4E\xb0f\x99\xcb\xbcz\xff\x9d\xe7:\xcd\x1b:\xef\xb4G\xa1\x9d\x9e\xb1\xc1e2\xbf}\x9b\xb1\xb9\x12\x1e_\xa5\xc9:\xcc\xd8 exC\xbaB\x9c\x9eE)\x0b\xe6\xb7\xc0\xffuL\x87jE\x8b\x18\x90\xad\xd3\x00\x83f[\x1e\xbb\x96\x83j\x0f\x02\x0e8\x84$\x8e\x92`\xde\x05\x05\xf8\xc3\xc5\xa6\x94e\xdb(\xb7Y\xe4\xb1I\xc6W\xa0k\x9b\xb1\xcb\x06X\xa1\xb3\x11\xbc\xdb^n\x9bI'_\xab\xef\xc2\x88\xbdFva\xa6R1\xca?&\xe7$I\x0f\x06|w\x9feZ\xb2c\x12\x97:\x8d0k\x826\x94\x9dj9\xef\xabn\xfdP\x99Q\x91b\xd8-\xa5\xe9l\x98A\xc6\x08t\xf5\xaa\x18\x82B\xa4j\xec4\x95\xa8)K\x05\xe2\xa9\x0e\xeb2\xdc\xd1E\x18\x87\xf9\xb7\xc9\xfc\xb6\x93P\xcf\xd7\x85\xaa\xf1\xb6N\xe3\x10\x19\x97\x91\xc6\xe9UL\x07\x01\x1e\x14\x0d\xbda7\xd8\x90\x9d\xf3i\x17\xc1.\xa3\x04\xc3\xda|\x1b%\x97\x9a~\x15f\xaf\xe4\xdf/\x17B^\x91\xed\xf3\xa2\x9d\xdb_$\xe9\xfay\x90\xa3\xf3\xf4w\xe2\xef\x8e\xfd\xc8\xe2\x9d\xfb\xa2\xcb\x05\x18\xcc\x15-\xaco_\xffp\xa6\xbd\xea\xd8\xad\\>M\x9d\xea\xd4{P\xa0\x0c\xe0\xf5d\xb9\xb4\xebJ\x07\x1an\xc1\x84\xe3\x8cL'\xeaC\x0d\x1a8\x1c\xf3\xf5v\xa7\xc6\xfa6\x97Uh\xbe\x07.\x1f\xbcXT\x1e\xf9\x87\x0f\xb0\xa7u\xd0\xb0f\x80WH+\xb2\xac`\x15\xdb8\xdbn\xb8\xa8\xcf\xe6\xf0\xad\x9c\x0d\xaf\xd9\x16\xfc\xada\x95\xecH!s\x94T\xb7\xd0\xe6\xe2H7(\x90Lf\x9ci\xbb\xce,\x89s\x16\xe7}\x1a\"\x1e\x1a\x9a\xb0LE\xc6\x11u\xb3Z]\x1f\x9c\x9c\xdd\xe4\xfb\x9b(\x08\xe3\xc7\\\x8c\xcfX>y\xfb\xe6\xbb\xfeCG\x05\x97-\xb0H\x86\x8cRo\x06\xbc\x95.\xdd\x18\xaayx\xd1\xf5\xd3\x91@\x8d\xa6qz\xc1f\x13\x85\xb3\x80S\xb6\xfd\x9b\xfe\xf5\xf5u\x9f\xa3x\x7f\x9bFda\x9bWgm\x94`\n\xec \nxI4\xa5\x95\xbf\xca\xeb9!\x8521\xef/\xf2\x1b[@j\xbdPy\x11\x0db\x90\xc8\x04P.\xd6\xa5=\x0dz\xad\xcd\xb6\xe2v\xa7\x9e$\x954`\xe1,\xd9r\x8d1\xc9QdS\xe4\x17x5\x082\xe0\x8bnC\xc8\x1d\xc6\xcc\xb1\xadj\x9d\x85BP-\x91\x97\x0e[\xac\xf3\xd8\x1a%8\x92;\xcfq\xd4\xbeO\xa5\xe5\x17X\xc7g\xebz\x83|\xc5bwk2D\x8b\xe1\xe6D\xfeZh\xd2m \x8ak\x05\x06\xc1Q\xda\xfb\xd85i\x88n^\x98\xf74Kx^\xb1\x84OQ\x956\\yq\xf3i#\xeb\x95\xda\x8b\xddU\x0b*+\xa6/D\xa7\x95\xfb\x0c\xb4\xe7\x00\xbe#\xda\x97\x91\xddB\xd1uQ\x8fj,\n \xae\x15\x9dt\xb4\xe7#\x94\xa8\xbah@\xd5\x9f\xb3$\xfe\x9c\xb6\xfft\xf6\xf2\x05\xf9qX\xa9W\xe9\xbdMY\x98Y-\x18\xf2\xcc\xc5U'\x80\x7f\xff\xe8\xa1\xeaP_\x7f\xa4\x15\xba\xb5\xc4x\xe6\x0f\x06\xf5\xddhK,\xab\xeb\x0d\x92\xd06%\xb7\x85m*S\xed\xccR6gq\x1e\x06QFn\xdf\xc5o\xaeF \xf9\x00\x8a\x00\xb7\xe2\x05\xa1X\xe22\xf9FE\xfe[\xb3|\x95\xcc\xb11\xfaS\xbe'\x87\x19\x86\x7f\xf8t*\xaa\x1cx4I\x18\xef\x1cC\xe9\x9d_\xb57\x18\xf6P\x13\x0ci\x96\xca`i^~\xc3\xec\xf3\xd2o\x19\x98\xb3\xf2\xceI\xd6a\xee\xf8\xb0W,NE\x98\xb2/Vn_\xacv\xd2W\x98;\xf3\xe4\xedfc\xcf\x04\x00\x05\x1a\xdc*\x8f\x0ftF\xef\x8f\xb8\xbcit\xe7\xfb\xe8\xe6r0r\xe2\xc5O\xe7?N\xde\xa8\xe8\x87k\xe9\xf8\x84\x7f\xa8\xc2\xe2\x87\x96\xc5)e\x0b\x96\xa6( \xd0[\x17\xdb)BRj\x1d|\x7f\xf2\xecy\xed\x0b]\xc7\xb7\xc0<\xaa\xdex\xd12\x8a\x92k6G\xb6\xf0\x1f'o I\x81\xb7\x06)\xfb\xdb\x96eyfB\x08\"rR\x83w\xe3nV\x99E\x07\xab\x8c \x83MV{L\xb1!/\xdf\xddq\x0cV\xc3F3B\xabxP\xbam8i\xbam\xc8\x9f\x94.\xdd\x93\x05]\xcb&\xd2\xc3l\"\xd0V\x1d\x0f\xf7\x04\xf3\x9b8\xc6\x06\xec\xcc3\x97\x16P\x83[\x10\xd7\x91\x0d\xaf\x13\x83\xf4 \x16S[W\xeb\xf6\xa6}_\x93\x86\x0d\x951\xf4\xd3\xa3w\xf1\xfe.\xbbY\xdb\xacq\xdb\xd5\xd0b\xa3\x08\x8a\xec\xe2C\xed\xb6\xbf\xfeH\x7f\x07\xb9qc\xa7\xb9A\xd0\xf7*\xf5\xab\x9e\xb5\xf2\xf9\x9c=\x98[\xf9*q\x84\\O\xb8B\xaa\xf3\x04\x1c\xe1\xea#\x95\xe4,\x0f\xf2-'\xb7\x0e\xfd\xe5`jLN\xf3\xe4\xa71\x1c\x0c\x87\xa2t\xf2^\xc5\x8b\xa5\x8fO'\xfc\xab\"\xe7\xe2\xed\x138TU\xe8\x95\xb49\x14\xbfj\x1da\x9118/\xff,\xc7f\xe7\x05\xbe\xce\xb5r\xfc_\x84\x9a\xab\x90\xa9j@\xd5\xd2/4\xf0\xb0\xc1\x82\xe5\xe68rW\"\x16\xa0\x19*tS\xc2\x18\x9c\x8a%\x01\xa7g\x08w\xc6\x1fy@5\x06\x87\x0e\xa7\xa80\xfaX\xcac*|E_\xcd\x8dp\x85m\x0cN\xa1\xd0h\x8dp\x0d\xa3\xf8\xd9*\x00\xf2'Oo[\xcca\xda\xa1\x03o\xdf7eO\x96\xcfG\x98\x05\xe8R\xd7\xd5\xad~odo\xcb\x8c8\xb6l\xc0R\xaa\xe6k#\xfel\xda\x0bM\xfd\x1e\x83\xa3)\x1aT\xa9\x8e\x9ef\xd1\xa8d&\xf4\x10r\xae0\x95\x9dtv:\x95\xfa\xd6\xb9\xe3\x17.P\x85\x1aV\x7f}\x1c\x05\xeb\x0d\x9b\xd7\xbf\x9e\xc6\xf9\xe8\xbe\xb9\x92\xe9\xfdi\x9c\x1f\x1e\x98\x8b\x9b\xde\x7f\x17%\x81\xfd\xc3\xfd\xbb\xe2\x83\xe5z\xea\xba\x93\\\x06\xba\xeb\xc6\x9d;\xc07\xe9/!\xbbn0\xbf\x99\x81\xc0<\x88\xa5\xf4K\x13V\xda0\xe3\x8d7;[\xe9\x8f>\xb4\xc2\x01\xb8\xd5E\x8d\xc4E\xf3@\xebP\x93h-\x11\x9b\xa8\xf8\xbbX\xd9\x11\xa3\x90\x0cB;\x8f\xdd\xd4\xc2\x82$\xcb\"\xf10\xd8L\x99\xe5\x8e\xa1V@$wO\xa0\x07\x8e\x8f\x81\xb1al\xba\x8f\xef\x97\xc6?g\x11\xcbY\xa7\xad\x17EU\x97|\"\x86\xbc\xda\xe5\xf6\x97,\xef\xd4\xb8\xda8\xb9@\xc4F\x82\x8c\x0e\xbb\xf5y\x8e\xcb\xa9R-\x1d\xaf\x82\x9d\x1c\xd0d\x07\x15\x07<77;w\x96\xfb\xca*\x93l\x80\x80\xf2\xea hk_\x08Ym\xb9Y\xe5SI\x96-z\xf4\xacs$\xe7B\xa6\xfc\xe1\xd4\x18\xe3s\xbaqT;\x957\x8c\x11\x9d\";\x98,\xa4u\xd1vkV\xdf\x8f\xba\x83A\xc3 9\xe0)\xb9p\x904\xa32\xfa\xde\x9bM\"\xfaT\xd0\xd5\xe57\x98L\x87\x99\xd8N\xef;\xce\x84\xc5y\x1a\xfe\x16S\xe9\xb6/S\x0eL\x06\xcf\x0fh\x99R\xc51H\x9b\xa1\xc9E\xc8\xb0\x00\x96\xb3\xf8[\xe4\xf3\xcfO~8ys\xc2\xf9%W\xd8}\xa1\x9e\xfb\xe0\xbc|\xf5\xe6\xf4\xe5\x8b3\xfe\xe7\xab\x97g\xf8\xe9\xd5\xdb7\x8ea\x81fZ\x97\xb3(\x89Y\x97\x15\xd7\xa4\xb2\x19ZP\xfc\x86\x15\xbcL\xe6\xb7\xfa)\xdbi\x1cZ\xee\xd8\x1aWP\xa4\xcb\xd7\xc6\xe9\xa9\x97\xf3\xd2\xcb\xf9gNe^9\xf9o\x9a\x14i\x0fc]\xdb\xb0k\x84\x85\xaa1\xae\xaa'\xf6JB\xeb\x18K5D\xd3M\x1a\x94\xcfm\x1a\x8d\x95\x9a\xb2\xc3*\xcf\x07\x9d\xfdi$\xba\xd1\x92\x91\xc5\xa8}\xa1\x1a\x82\x82\xe8\xcb\xe3X\"h5\x9b\xcf\x98R4q\x16N\xd5\xf3\x11\xcc\xd2\xd0\x95\x88c==\x1c\x8e|8\x1c\x1e\xf0\x7f\x0e\xf9?\x0f\xf8?\x0f\x0d\xe82\x1f\xa4l\x1e\xa6\x1d\xd2\x8d\xcb'\\\xa8\xfc.\x97\x9a\x95O\xb7\x96i\x11\xb7\x94\xbb\xa9Pjg\xc9\xdcz@_\x02\xdd\xae\xfb\xd0\x05\xe2\x9a\x95\xa7(\xa1\xa3\xe6\xc6\xcb\xc6;\x80\x1e\x1b|\xafT\xee\x84\xff|M\x06A\x98\xc0\x8c~f\x9b$\xc6{\x9ds\xfe\x1b5\xe7\xae\xab\xaf\xadQ\xcdi-n\x10v@\xb7\xbe \x99\xc3^\x9aml\xa1(\xfc\x9f?\xfe\xf0}\x9eo\xc4<\xec\xa6\x9apG\xcf8\xd0\xb0\xaf\xb9\x14h;\x1e\xb6\xd2\xa7r\x0dB\xc4\xb0\x13\x91\x92\x8f\x02\x9d\x8d\x1br\xc1\xf9Y\x14\xc9m\x13\x9b\xeb\x8a\xa8\xbev\x97\x110#\xa9\xfe0a|qR\xd1\xf8\xdb\xd7?\xa0\xca\x1c\xc2\x11\x84\x03\xed-\x8c\x81\x95\xfdI\xfe\xb3/\xf6\xa3\xcf+\xb5\xf8\xbcH\x93\xa2\xea\xc8\xd0\x0b\xe6\xe9\x97?\xf8257\x19\xbb\x82\xc7\xe0%x;\xe6\xf8\x08\x16\x9d\xa9\xb1|\xd2\xaak\xe8\x0b\x96_'\xe9{i^\x87E\x10Fln\xf2\xfd\x90\x8f\xe8:\x0f\xd7,\xd9v:o\x97\xcf\x17\xeb|\xc3b7Q\xc7Q \x9d\x7fa\xaa\x1d'\x8cg\xd1v\xce\xe8\xf0!)\x9d\xf6p\xc9*\x1c\\\x87\xf9\xea\xb8tND\x15\xd5\x16\xddn\xe46\x96|\xc1\\m\x17\x05\x17!/\x0c>\x00 B;\xf9G\xcb'\xe4\xea\x95\x80:B\x03\x8b\xbb\xb4|\xb8$\xc9+\xc5sWsoO\xb4C\xb7#:\x8a\x1b\xeb/mR\xa9\x99\xd8\"\xf9\x1cl\x92\xe8v\x11F\x91\xc9+X\xfd\xe5:[y\xd1_\xbfk\x90\xb1h\x01G\xf4\xdfXS\xb1>\xeb\xa2l\xec>\x1a\x9a\xae\xaf\xf0\xf7\x0f\xcd\x17\x92\x1e>\xb2\xdc<*\xef\n\x85!\xe6\x84\xb0\xdc\n\x1e2\x8f!)\xbfUQ\x02\xc6\xb5\x9c\xf7\x9f9\xbf\xc3\x87\xd5y$j\x1e\xf5\xf9\xd5!\xeb2\x0df\xef\x19\x9fHg\xd3\x00f\x84\x9b\x9e\xd7e*\x83\x0d+\x8c\xe7\xe1\x8c\x95Zo\xe7\xab\xd4\x01f\x96\xa3\xe4s]zJ\xd9\x86\x05\xad10@\xeb\xa5\xdej\x19d\xeb\xf7\xd2\x9e\x079+Y\xcdN\xcf^\x92\xe1\xac\\\xd6\x1c\x8dg\xce\xa2p\xcd\x15\xb31\xde\x0e\xae}\x97\xc1n\xf6\x0cR-}K\xc7\x90\x8a\xe0\x13\xb6\"\x7fA]\xfde\x1c\xdd\x8e\x8d9\x063\x96\x86A\x14\xfe\xc2\xf8\\vX\xad\xa0v{U>\x86\xbd\xc8\xde\x87\x9b\x17\xdb(\xca,c@p\xe6\x05\xbe\x0f\xe2y\x84\x91Q*V\xf3J\xa3\xba\xc6\x0eL\x04~Q\xf1\xc82\x1f\"\x9f\x8buE\x88\x04\xd3l\xa4%\xdb\xc0R\xd1\xdbZv\xa0{\x82F\x1eV\x89\xb8Xwe\xba !\xdd\x82\xaft\x7f\x0e\xbe\xb6Tq\xe36\xd6RW\xc2\xaf\x9a\x04\xfdP\xb9LQ\x06\xb4\x15\xa7\x93|D[\x01\x0c\xe8\xfbf\xb8\xe2\xcd\x9f+\xf4\x8fm\x81u\xb0{\x9c_\xa1\x84U\x8f\x97A\xefe \x80\xea\x87t\x10f\xe2V\xc1\x95\xa7\x0d\xff\x08\xa6s\x17#\xc4\xc3\xb8:\x07\x8f#\xfb\x84\xa3\xfd\xdc\xcd\xdc\xab\xd2\xa7s\x18\xf3\x9a\xb1^F\xb8x\\y\x9eA\xa5\xe2\x9b\xbd\xf6\xd1~n\xb2\xe0\xe0\x96\x15\xcc\xf0J\x0d\xd1\x10\xff\x8f\x97-\xdf7\x8a<\x0f\x8f\x07\"\xcb\xd6\xdaU\xdc\xdbJ\xda3\x13t\x808|\x98\xc1\x11\xdc\x0e\xb2$\xcd\xdd\x19\xdf\xe0. \x9a\x94\xa9\xf3\x92\xbc\xdd.\xe1 \xac\x95\xb7[\xafw\xd9\xa4\x7f_\xc0\x04\xd6\xd3K\x8b\xc1\x0b\xdd\xbd\n\x80\x9d^`&\x07wY\xbd9\xef^yp\x04K\x99S\x86\xb9\xbc\xa8\x0f FP\xf3Z\xd0\x96\xcf\xb3V5\x86\x1e\xb8\\8p\x06|\xe7/T\x9e\xd2\x0b\x95\x9b\xb4\xb9Q\x03\xd1\xaa\xbd\x91\xfb_&CfQ\xa0\x91\x99\xa9s\xfd:\xe1\x0b\x80n\xe5\xa6\x83 \xcb\xc2e\xec\xfe\xfd#606\xc6\xcdQ\x01\x99\x02\x89\x07x\x8aS\xdc\xf7-\xbd\xd7\xc8W!T\x05\x05\x810\xba\xd1\x9c\x88\xfa\xab\x00\x03\xa0_2\x08\xd4\xe4j9E\xaeD\xdc\x1b\x0do\x82\x81bjp\x04[\xed\xd7X\xffV_\x89\x19\n\xc4u\xe2\x11\x0c\xea\xcc\x01\x8e\xcc\xaf\xc7\xb05\xbc\xae\xf7\xb5\xb0\xf7%\xf9\x14u\xa1~a\xcb\xf2W\xbd\xc1\x8d\xb5A\x11\x18\xea\xa8\xf8s\xac\xa8X\xbd\x1d\xae\xa2\x1b\xb9N\xb1\xb1G\xda\xdfES\x86\x05]\xd9\xdb\xca(\xa5\xbc\xf8\x83N\x8b\xea\x0d\\\x15;K\xb0\x85\x9eU\xcf\x93\x1cy\x8e\xf6\xb3^u\xdd\xd0\xb7.n\xd0 Jop\xa5\xf57\xf5\xd6\x97-\xab]H<\xdaji/\x8be+^\xd6\x91\xad\x04\xd4$\xdc{\xea/4\xa2\x0bo\x93r\xd5\"\xf3U\xa7\xc8\x15\x89h0gi\xe6\x17\x1dY\xb0\xf3m\xfc>N\xaec\xa1k@\xb2A\xf1g\x93&W\xe1\x9c\xcd\x8d\xf8)\xc2\xb1\xe2\x80\x8b\xae\xa6\xb2\xa7\ni\xb7l\xda\"\x8c\x08\xa1\xd1\xa1\x95s\x12\xf9\xces1/\\\xfd\x06\xae*\x80\xba/&o\xd7\xab\xd5\x07z\xedc*\x82*oF!D\xc6\xc2)\xe8\x98\xee.:\xe1\xfd\x0bj]\xbd\xf8s\x8d\x9d\xa2\xff\xc2w\xb4h\xc2\xc0R~9\xe6\x8a?*&\xa8\xba\x07X@\xbc\xe1lF}\x1csE\x9f\xeb\x15\x8e^\xa7>\x9b\x1b\x98@8\xbd\xaeL\x06\x83\xc8\xb8U\x96\x1f{\x18\x0d\xeb\xce\x1d\xc9\xdc\xabw\x1c\x15\x0f?#\x1e~\x06O\xe0V\xe3\xe1g6\xe1\xf6\x18&p;=3\xf0\xefE\x89w\xc7\xd3c\xe2\xdd|\x07N$\xb7\xcd\\\xfe\x1e\xa3\xf8\xde(\x0e\nG0\x97$\x83C\xd6\xca\x87+\x9f\x0bV\x17>,\xab\x8c\xf5cm]\xdec\x07\xe8f\x16\x19\xcc\x9c\xcf\xd0P \x90.\x98\xcf\xff\x9f-Ko_\xa5l\x11\xde\xf0m8r\x0c1\x9e\xc4\xce\xbf/\xf2 \x0c\xe1\x08\x9eA\x0f\xdeW\"\xfc\xe0_\xbf\x8az\xdd\x82\xeb]\xf4nEN\xcd*\x12~Vn#\xb6B\x1c\xa4\x7f\xe0,v\x0c\x07\x06\xa5\x91\x1c(Qi\xa4?ME\x9au\xd29\xdb\xe4\xab1\xdc30\xc1 \x0d\xd6,g\xa9\x18\xc0\x88\x1d\x1a\nEA\x18\xd3j}1]0\xe8\x10L\x05\xda\xbce\xd5\x0ekl\xeeH\xcb\x92\xb1\xffn\xe0N\x7f\x1aL\xcf{\x1e:\xb2N\xffmt\x8e\xf7\xfa,\xbeW 6z\xdf}7\x9d\xfe4}w~\xfe\xcd\xb9gK\\\x03b\x16\xe5\xc2\x94h*m:\x86\xe3\xd4\x0d\xc5Gq\xa5\xda'\xb2\xc5n0!\x85\xbdb\xd6p\x8e\xcd\x97\xa9\x16\xcd\xacZ`/\x1e\xe8[ \x98/\x0c9Z\x15\x1504\x1a\xa5\xab\xae\xc0\xb0$\xdav\x83vF\xa7\xe2\x86;[`=\xfdQ\xc4R\xe4\xf6VB\xb3\x1b`\x08G\xb1\xa88\xa6\x08\x9e@<@\x90n\x0c\xf3\xcdg\x1cA\x0fC\xe7\xef2\xf3`::\x17[3\xf2\xa1/\x02v\x7f\xc6J\x04\xc6\xa0\x14`]\x0ci\xab\xe1\xdd\x8a&HQ\x92\x10\xa3\xc0E\xe8M\xd6\x01tA\xb0Ry\xb9\x0d\x1c\xa9r\xca\xf2\xa2%7\x1b\x89\xe4\x03\xc3\xc7\xd0\xef'm\x8d\x81@\xd0\x90\xa2\x98\xb3i\xd2\x90\xda[>(9LE\x0c\xb6\xc0Cl\xc44\x08\xd3sO\xb28\x9b{\x99\xfet\xb8M-\x1f\xb4\x18\x97\xc1\xe3H\xf2\x86Y\xca\x82\x9c\xa1\x0eg\xd2\xefl\xcf\x95\x08\xe5\xc7\xb7\x8d\xd8b\x91\x9f\x91+y\xe7\x95\xd7\x81\xb6\xc6\x1e\xc9\xd7\x1a\xfcq-\xcc\xbe\xc7\xd5\x87S 4_\x9f\xc6\xb9\xbb\xf5ad\n\xd9`z\xf6\xc2\xecE\xf0\xc2\xcdp\x88\x01b\x1f\x06\xbd\x17\x06\x9a\xcc\xc31\xe3\xab\x8c\xc2\x8c\x8a\x1c\xc8i\xc6P|\xcc\xe8\xd3\x13\xa4\xc7\x8a\xa9\xc1\x91\xda\xc0iv\x8eQ\xf0\xc7\x10N\xb7\xf8g\xeb\xc0\xcc\x18\xa2?\x1cT\xc3\xc6R\xcdm\x08l\xb3\x0f\xe5\xa3\x9b \xec\xa9\x15\xa9\x98\x9a?\xc3\xcc\xf0 \xf6\x84X\x88\x03U{B\xe9\xbd\xd1\x9e\xa0JX4\x96\xe7l\x07{\x02\x8ei\x10.\xe3$e\xba\xe4\xa7dB\xc3G\x1f\x87 \x8d\x0c\x13S\xacl\xbd\x80\xb0D\xbef\xcb\x93\x9b\x8d\xab}\xf10I\xa5n\xae\x085s\x85\xe4\x12\xbc\x83\xba\xe5S~\xc3?eI\x8c\x83=\x11\x9eZ\xc1\xa0\xf8\xe9#f\xb1\xcd\xb1\xf0B\x0e\x06\x17\xea'f\xa5\xc8f\xc1\x86\xbd\n\xf2\x95\xba0\x8b\xa5\x0c\xefy\xf1ml\xab`\xfcR\x1e\xfe\xd6\x90\xd7\xaf\xd5\xad^\xc0c\xbb\xcf\x01]\xd0\xbc\xccXzE\x1e\x9c\xd3syk\xf3\xf2g\xa8f\xfc\x80\xba<]\xbdQ\x17\xed<\xb4\xb6@\x95\x9cv]\x06\xb3\xf7\x14\xc8\xad4`\x98\x98\xa2mV\x07h\x8a\xfd=\xab/I)\x8b*\xe5\x9cJ1-\xb9\xa471<\x81\xf41\xc4\xbd^]\xcb@\xdb\xce4>\xa7e\xc3H\x0bd[\xb7N\x0d\x19VlQ\xb7/S\x16\xbco\x99\xd9\xc2\xcd\xe9\xbe\x88\xaf:\xe3\x7fm8\x14s\x11\x0b\xd3D\xa8\xdfR{E\xabJ\x81\xaaz\x1b\xa2\xa4\xe1\x08\x81R\xc8\x8a\xefF#q\xa8\x1b\x891\x94\xad,.`\x8a\x15\xfb\xa8n\xfc\xf0_n\x88\x89\xbf4jY\xdf\xac\x85\xab\xb2\x01\xd4,\x1a\x18b\x82\x92\xe9\x98\x96\xda(\xa4\xe7\x83<\xf9\xd3\xd9\xcb\x17@9X'\xea\x85k\n\x14\xa3\xe0\"D\x9epAK\xfdg\xce\x9ar\x8f\x84\xa1\xf2[\xe6\x91\x98\xb37\"\xde\x17\x94\xac3\x99\xb0\xced\xfd~\xa3X\x83\xe6\x18\xe4T\xd3\xec\xbc\xc1\xa2\xb8\x97\xd6.\x8e\xf9\xb0\xf1*\xd2g>\xdd\x9cWt\xd0\x08Mf$\xc0\x94\x8f\x98rO\xc5\xac\xb7\x9bg\x92\x0d\x1e\xd9\xac\x93+\xd6\x90o{\x13\xe4\xab1\xdd\x0c\xdc'\xf3\x98\x81\xe0\xb9\x1b\xfb\xc5\x1c\\HK\xae\xd7\x16\x03\xd2\x95\xc8\xf9\xc2\xe7n7\xaf\x18\xf2ADP$i\xa2\x1f\x86B3\xbd\xd0\x8c\x0b\x89.\x89\xa2\x1cJ[\xe7\xcb\x85\x1d2\x11`;\xee\xde\xd0o_r(\x96\x1d\x05\xf3\x86u\x87\x1d\xd6\xbe\xb9\x15\x11}9\xd5X\xa0;kr\x81\xedjF5\xfbEm9\xe0*j\xb2W`\x8f\xb9YDNMm\x08\x15\xb5\xcez\xbd&\xeb'\x07\x8e\x0d\x9e%f\x0d\xc0Q\xc3-f\xc3-\xae\xfau\xde\xbf`>\xff\x87\xed\x1d\x1fm\xd3\xf6u\xd8=\xcd\xc5X\xfd\xc5\xa5\x1c\xc1\x96\xdb\xeciZQ=+\x02\x97\x94:\xb6\x80\n,\x99\xbe\x9bE\x9cR\x08\xb3!\xf1\xf5\x82\xa1\xe7\x94`871tPL=\xd7\x98\xba\xd2\xe1\xf9\xeb\xf2\x9a\xd4\x02 \xf1\xda\x898\xdao\x95vJz\xb9\x90?\xb9bq\xfeC\x98\xe5,F\xfb\xa3\xed\x93\xeb\xac\x93m\xc6\xb6\x1b\x87\xac.\xd6b\xef\xd9m{!lk\x9e\\\xc7m\x05\xdf\xb3\xdb.\xc5f\xab ^2,\x85\x807Of\xdb5\x8b\xf3\x81\xfc\xe3$b\xf8;\xc8\xf3`\xb6\xc2\xda\xae\x93\xc4\xe59u\xad\xa5O\xb1k\x9d\xea\x8c\xbb\xd6+/@\xd7Z\xfazt0A\xc4\x15\xb9;\x16\xaa\x01iO\xb1\x99J\x9b\x80z\x86y[\x8c m\x84\xddV\x12\xa7\n~!R'\x1f\x03\xc9+\xf4\xc3\x12\xc9C\x9e\xadw%r\x80\xc7>\x8c,\x08\xc9 _\x87\xaehH\x02\xb1\x0d\x13\x0d_-\xc8h,i\xc0G{\x8bu\\\xb3\xb5\xa9J6\xe3\xdb\x9c}\n\xbeUju\xc27SO]0\xa7\xdeW1\xb5\n\xeap\x8eT\xc0\x01\x85n`\xd7@I\x99\xbcRD\xd6\x8fd\xad\x8aYJ&\xa8\x19\xff\x8dv\xbe\xb4\x9b\xa0bp \x91F\x90B\xb1Em\xbd\x9a\x01\xac\xc9h\xa8\xb4\xe3\xcfI\x02\xd69\xadW)\xe1\xafQ\xa9\xd63\x94\x1d\x95~\x8d!\xf6\x06\xd9*\\s\xf6\xdd:/\xb9dZ\xc6\xb7%\xeer\x86'\xf2v\xa2%\x06\xdd\x12q'\x90\xadi\x92\xa7\xd9DdH\xab#}!-Ck\x0d\xf6\xa3mo\xbd?C\xee\x17uK\xcb\xac\x82\xd2\xfb\xfa\xb1\x19\xd3\x8c=\x9d\x9ce\x99\x0f\x0e\xff\x831\x87\x1cij\xb56\xa2\xfciv\x12o\xd7\x14\x11\xc3P\xf7\xc3\x07\xdd\xa5\xec\xa3Kq4\x0b\xc8\x89\xe1\x08}\x0b\x12oPD\xb3\x9f@JVR\xfdUb\x04\x94\x9d|\n\x8d`JQ;p\xe12\x11F\xad\xfaQ\x85\xf4(\x1d\xa8Y\xf6F.y1ih\xba\xebU\xda\xd1\xe6\xf1\xb1\xc1,\x89\xb3<\xdd\xce\xd0\xc0=\x99\xe8\xdf\xd0t \x86\xabv \x8e\x8aI\x8d\x0d#3A\xb9\x1d\xea\xb4\x93\xcc#\x0ee\x11\xb6\xaa\x9fh\xf2\xf7\x1a_\x1c\xeb0:)9z\xd7\x8bR\xa2\xc8#Sz!\x07\xcf\xe5K\xed\xb5\xf4\x9b\xb6\xe1\x96!g\x8f\xc4e}\xc8 \x0d\x00\xb3\xc2\x8c\xd58\xb4/\x81[\xc9Bo\xea\xcc\x90\x7fG\xe9\\\xeb`\xe3\x86\xcdc5\xe4\xa4\x91\xf4\xdcz$,\xe9y\x15\xbdE\x80%7\x9f\xc6\xe7\x18W\x9dM\xe3Z\x10\xfc:\xb57\x8c\xca\x90\x87\xa6\xa4\\+\xbaZ\x18\x82G\x15\x83\xa3*2\x1d\x9d\xf3\xb5\xd4\x7f\x8eIX5;\xf0bT6\xb6\n\xae\xc2d\x9b\x8e\xc15\xf4u`\xed\xeb\xa0\xdc\xd7\xc19\x1e3z\x83r\xabx\xc5N\x9a\xd5J#Pg\xe4|\xeb\x9a\xad\x0d\n\xb91&u\xb9\x15\xcf'+:}\xf3\xa5\x13e\xc4\x85\\%\xf2F&Y\xb7\x94\xbf:\x9dF\xe7t\xda\xad\x1f\x91\xceD\xe2\xe8\xe1c\xd8\xc0\x13X\xa8\x067v#\x18o\x11#WL7\x0d\xa7\xe6+.\xf0L\xe7\x0d%\xae0\x97\xe3\xaa\xc1\x12\xb5\xc6\x12\xe1tn\x8b\xef^\xba\x8a\x80W\xde\xec\x12?\x96- \xe3\x13X7\xa9\x1b \xe6\x8a\x0e z'k8\x02>\xa8\x0e>\x83!%\xc0\xce\xd0\xebk\xba\xf4a\xeb\xae\xbcs\xa3\xbb\x99|D\x9clQs[\xbbz \x1fu\xadE\xa76m\xf3\xd7\x8av\x9a\xfb-\x1ex\xdb\x86 \x1f1V\x07O\xbd\x1d\xe1\x17VA\x13Z2\xe9+pk\xbe,)\x9f\xf2\x1a\xd8\x07\xa0\x97Z\xd5J\x18\xd5\\\xfd\xc0H5\xd3)\x17f#\xd5\"\x12$NA\x90\x84\x1dA\x8en\x1ecL\x1e\xcd)\xc1Hd6(R\x1a\xf0\x02\xe7zk\xd3\xd4,\xefg\xe4\x16Q\x8c\xdd/\x06=\x88\x93\x1f\xb7y\x907*\xe6j\xf0\xcc8\xf8\\\x0d^\xe6g\x18\x92\x1e\xcdH\x8f\x06\xc1\x07\x8a\x81V\x0f \xd5@\xc9\xbf\xd1<\xd2\xeb0_\xbd\xc4+R5\xdfI{\xba\xd5L}\xafl]\x8b\x8cg\x0f\x0c!\xf3\x8fC\xec>\x1a\xdd\xab\x10\xa0\x8b\x0b\x96\xfd\x98\xcc\xb7\x11^\xf3\xdf\xad\xcb\xd8\x1d=x\xc0\x17\xd0}t@\xff\x8d\xee\x8b\x9f#\xf1\xff\xa1\xe7\x97\x05[wt\xcf\x1b\xfc\x95\x05\xef\x7f\x0c6]\xfah\x10]}\x99\xc9\xf7p\xe4\xb9U?\x8ePtV\xbd,C^\x0e\xa3\x83\xbb\x95\xf7[j\xea~5Y0\x0d\xfa\xd1\xa8\x1a\xbb\"\xa2\xf2\xd5\xe6g\xf8\xfa^\xd5{d!\xbcG\x0e*\xef\xf1\xdcr\xb0d9_\x91\xf2\xa7y\xc1\xbb\xc2\xec\xe4&gq\x16^F\x95\xcb\x1e\x9c\xedd\x83\xed\"\xcb\x93\xb4\xf2\xe9\x8a,\xca\xa5w\xed\x01d\xab^\x076\xaa)Y\xb8\x88\x8ag\x904\x86%qbx\xaed\xd3V\xd7\xe3\xf2\x98\x97FYg\xc9:\x05\xd6\xc0{\x13(A\xdb\x89\xbf\xa4q\x1bcj\x06\xf9\x88 \x0b?\xe0\x1c\x8e`\xe5.\xc4\xec\x1d\x01\xcf\x8e\xe7a\x0c&\x94}1\xfa\xb6HU\x14\x16\xb37v`8\xf4\xab\x8b Yy\xca\xedAK\xb2\xc1\x9c-\x0c\x83\xf4\xd1?d\xc7m\xb8\xadj\xa8\xee\xa3\x83\xa1\xe7\xaaV\xf1\n\xde\x12o\xbb\xef\x0d1\x96Q\xb1\x963\xb7\xcd\x18\xf1\x00\xf6&\x80\x96\xa5[\x0fs\x7f\xc9\xbb,\x8b\x94\xb1_P\x18\xa4\x17\x9e{\xe5\xf9\xf0\x80\xd6Yc\xff\x1fI~\xdf\xba.\xa6l\xe3\x9f\x8f\x0b\xad\xd0]\x977I\xbb!\xb3\xf4|\x08\x06/NN\x9e\xe3\x01\xba\x0f\x89;u(\x8e\xae\xe3\x83\xb3\n2\xfe\xdf\x92\xe5\xfc\xbf\x8c\xe5\xce\xb9\xdf\x00w\x12\x96n\xb5.j\xeb\x8c>\xf2\xb5x\xc1!\xc6L\xd2\x1a\xcf\x0d^\x1c\xa0`:'\x03\xc4\x1c\x9d\x10\xcc`@\xb0\xb7(\xd2\x7f\\,\xc4\xe1TSP\xe3P\x065\xbeXL\xd99\x8d\xc2\\Zj\x86|U@\xe8\x9b\xbc&\x8c\x0d\x97\x18\xec\x0e\x91\"\xa8-\x02i^\x8b\xe5\xffQ\xdfc\xfa\xbbs\xa2\xf0G\xa3\x87\x96\xc8I\x8dh$\x07\xc6\xae]\xd4\xbe\xf5\x10\xaf\x9d\xf8b1\x82\x1a\x7f\x10\x1c\xab\xc6\x96\x04\xbbz\xe4\xb9N\xb6a\xb3\x90\x95\xd2\x84t\x93\xd8\x10\xf8\x8cb\nj\xe5\x1c?LW(\x84\xf1I3\xa2\xa0}\x8a\x9c\x85PJBHK\\\xcd\xce\xe5\xa9\x1c\x08\x82\xa6\xfb\x90\n\x90T\xe6\x10\xf2\x18\x9a\x86\xe7\x9e\xf2\x1f\x12\x85\x8b\x1c\xf1\x92\x96R7\xe3\xd6T\xf6\xdd\x85\x03Z\xe7\xe1}\xe3\xfas\xf6o\xe6\xba\xc2\xcd\xb3Z-0\xef\xa6\x10\x1a\x86UaBH:w\xab\xef#%\xaf\x18\xa5\x86\xaat\xd0$5DnU\x92\x9b\xe3\xdb\xea\xc8WxxT\x86\x93\xaeR\x00\x1b\\`\xea\x07\x17\xff \xd2\xb1\xae\x1e\x10\x94~\xae\xdbN\xcb\x90\xb2\x04hrojg\xd9\x86\xa3P\x8cr\xe3\xb2A\xd0D\x94+\xe5\x19\x17F\x10\xf0j\xa5\xaa\xd9\x90\x0b\x98Zk\xd6\xc3\xaa<\xd2A\x16\x91|a)\xe8\x9c5 \x94:\x83\xcb\xa7\xa3\xc6\x15Z\x05\xad\x01\xd2\xa4\xc8\xb2W\xf4\xda\xd4b7\xf9B\x1e;4\xcd$F\xe7yT\xf5r\x99\x021\x10\xf1\xa5Y=\xbete\x1c\xc4|\xdb&'WT\x043\xd6\x01\xa0M.\xca%\x00\x18\x9cv\x0d\xb3\x11\xb5\xfe;\x07\x99\x88%\x90\x07\xa2\xb9\x8f\x97\x08\xf6\xf6\xfe\xbb\x9aTF\xfd\xe57(fe!e\\#u>\x84\xb6\xa9\xa3\xdbc)J\xa35\xc4\xeb\x96\x7f\x8d\xb0E\xe7\"$g\xd7\x8b\x9c\xdcE\xd8\xe0\x82S\xbcU\xaf\xe7\x83@r\xa2\xcc~a$\x04\xbc|\x97\xb9)\x8e\x88M\xc3ss*|\xfb\xd2\xa5n\xa4\x8b\\\xe6av\xdbv\xf9\xa0Gg\x80\x92\xbd\x04\xf3\x91]x\x97@\x9b\xec \xe2s \xbeR\xd2s\xeey\"\x11\x03I\xf71_\x93\x99\x1b\xab\x9c8\xc8\xe4D\xfe\x85X\x89\xfd\xc6\xbe,\xee3\x1d0Z>\xff\x88\xd9\x8bD\x0f\xa6\xa9\x9bgi\x80\x10\x1f\xa2f\xcc_\xd4\x91\xc0\x86\x01)YK\xd1\xb7x\xcft/\xb8<\xa1\x14'\xc4H\xbb\xc8\xc5\xa5\x9bt\xcaP9\x9b d7\x0dM\xa8\xd8c\xb8*P\xfb\x0f\xf0\x05$\x94\xaa( \x04D\x8b9\xa3f\xb6\x08\xcc\xf6\x06\x12L\xeeU[\xc9,RQd\x91Wf\x16\xf9fa\x16\x876$uW\xc3\x9b\xce\xf1\xf5\xdd\xa17X\xd4e\x13\x8b\xf9\xe6\x8a\xea\xdcm\x15\x82%\xa5$\xed\xf3\xd6$\x13_\xe2y\x003\xd8\xe6/`\x02\x97\xf5\xd7\xd7\x9c\xbf\xe1!!\xa30;f?\xd4\x13\x98\xc0\x05G\x86\x8b&m\xef\xc6p\x1e%@\xf3\xcaz\xba\x89\xcd\xba\x18\xad\xe7D\xe5\x16\xe1Rx`W\xa5\xf9\x83*\xf4\x85'\x93*\xb8\x1ez\"\xb9U\x95\xca\x83#p/0\x91\x8b\xaen\x1aqm\xc6\xbf\\\xa0j\xea\\\xcc0\xeb\xe2\xe0b&\xa4\xc1K\x9dO a\xc0\xebsK\x1f\xf2\xe9\xf5y\xcd\xca\xc0)\xc0\xca\xe5\xcb\xe9\xa3\xc3\x94O\x04\xd3\x173\xf4\x97,\xf7WA\xe6g,\xf7\xdf\xb3\xdb\xcc\xa7<\x1f\xbe\x98\x8eO\xb7\x0f\x1c\x99\x9e\xce\xe7\xa3\xe9&&\xe0\x16\x82\xbcnZ\xa8\xacu\xb2\xc1 \x8c\xe1\x84\x9c\xcdq\x03\x1c\x1c**L\xa4Em]}\xc3K:{S\xa8uN\xb4e\x16 \xbe\x9e\x9cn\xa1LA\xfa\xd5\xc2\x8d\x0br\x8e\x06\x07\x1a\xae:\xaf\xb3\xab\xec*\x0f\xd1\xc5\x8c\xab\xec\x05\x05\x1frr\xed[\xd5})\x0f\x15z{R+W\x15\x89=\x9f\x82H\xcd\xcb\x8b\xe0d\xe1/\xcc1\xf1\xf6\xb2t\xdc&\x9a\xd1,\x06\xbc\xb5\xfaPjP<&(^W\xcd=dIY\xfap\xed\xf9\x90\x95G\x1a\xe3\xadOe\xf0\xf1|\xd8\xb8b;n(G\xd3\x85\x0f\x89\x9b\x0c\xfe\x03z\x90\x0c\xfe\x8a\xff~\xe7\xc3\x8d\x9c\xf9\x9a\xb3\x90\xb3\xc9J\x98\xa4\xcd\xb0\x16\xa1\x1eTy\xaf\xec#\xe72=O\xb5\xe7\xc3\xfe\xf4\xa7\xa0\xff\xcb\xb0\xff\xe8]\xff\xab\x7f\xfb\xe3\x9d\xaf\xbf\xe9\x0d\xde\xfdt\xf1\x7f>\xfc\xf7\xf9~8\xc8Y\x86\xb9\xd7\xcc\x81Wd\x82\x97\xd9*H\x83Y\xceR\xceW)\xcd\x00,B\x16\xcd!\x0e\xd6\xc6\x9c/\xca\xfa\x94'?$\xd72\xaftyq-sn\xb6\x84t\x9e6\xeb\xd4\x99\xc1\xf1\x11t'$#p\xc5\x98u\xa4\x95\xac\x82\xd6\x10\x93Iv[\x957{[\xfc\x99'1+9\x88\xb5$<\x11\xb7\xa2\xccI\xac\xc0\xa8\xe2\x99\xdf\x1a\xbcF\xc4\x80+i\xc3rS\xb2\xb0\xd6\xb5\x92\xb2C\xbd\xdf\xce\xd9~\x0d\xde}\xa0\xa5\x02\x14\x97sJ\x19\xf2\x13\x0c\xfd\xb1S\xbe\x0c2\x1eQ\xd6bs\x82\x0c\x91\xf9\xbf\x1e\xcd\x14\xbd\xeaL\xddu\xe9\x8bM\x87\xe7>0c\xe86\xadG\xdc\x03q\xee\xb6d\xb9\xe6\x1e\xf7\"X3\xae\xfd\xef\x90!\xaf:\xd7\xa9)\xab\xdcGS\xe6B\xdb\x1e\x19|\x13A]k\x90\xd9\xf8\x95\x04-\xb2 \x0dR\xc6\xe7S\xcd\xdb\xf2,JY0\xbf\x05\xfe\xafc\xba\xcc\\\xc9\xef\xdfi\x80\x06\x7fF(K0\xb5\xd4LM\x81\xec\xd8\x8eY\x93r\x97\xcf6\xdbF\xb6D)x\xff}\xb7\x8c;\xb1\xcb(aZw\x1bO\xa7\xa52\xf8n\x82F\xf1\xf8Z\x15\xb9\x97\xcdT*FW\xa9\xdc\xce?\xf2\x01\xdf\xddg\x99\x96\xac\x96\xdc}:\x8d\xd0\xe0\xc7 \n\xda0\x86\x8cvCP\x04\x9f1\x8cE\x9fQ\x91\x8f\x98\x03\xecm\xce~\xa0\x0b\xbb\x0d3\xc8\x18\x81\xae^\xd5C\x15\xfc\x12'\xd4i*QS| \xc4S\x1d\xd6G\xd54\xdf\xad\xa7E \x0f/JY\x05\xe9\"UC\x12\xa0\xd0\x9c\xdd\x81yZ\x0eE\x91\xd9\xdc\xa0\xa6\xcbG\xf9\x05\x16\x89\x8e\xbe\x8d\x92K\xcd%\xbf\x9a\xecXo\x9f\x17\xed\xdc\xbeL~\xcd\xfb\x90\xe1g:\xf6#\x8bw\xeeK\xcf\x7f\xce\xfb\xab$@\xef\xd8\xad\\>u\xc1\xa2I\x86\xd0z\xd7\xd2mC)\x87\xd4\xba\xd2\x81\x86[\xe8\xf7\xc9\x04\\\xca\xec\xc0:4\xc4\"\xb7\xb9;5\xd6\xb79\xbdB{\x00\x03\x90&\xf1\xf2\xc8?|\x80==S\xb5}\xcd\xd0\x00\xb3\xac\xc8\xb2\x82U\xe8\xd7-\xbe\x95\xb3\xe15\xdbr\xab5\xac\x92\x1d)\x84+hm\x0b\xab1\xa7\xe5\x83\x05K\xf9\xdffI\x9c\xb38\xef\xd3\x10\xf1\xf8\xd6\x12\x04\xadT7\xab\xd5\xf5\xc1\xc9\xd9M\xbe\x8f\x01\xa9\x1es1>c\xf9\xe4\xed\x9b\xef\xfa\x0f1\x04W\x05\x8b\xe4\xe1\x98z3\x10W-Z\xbb1T\xe3\xed\x7f\x0e\x12\xa8\xd14N/\xd8l\xa2\x90\x92<\xee\xdf\xf4\xaf\xaf\xaf\xfb\x1c\xc5\xfb\xdb4\xa2\xe8\xfc\xf3\xea\xac\x8d\x12\x8c\x96a\x8d\x88)\xd1\x94V\xfe*\x8d&!i\xcc\xe6\xfd\x0d)d\xb4\xe44\xf6B\xe5E4\x88AY\x12]\xb1j\xb1.\xedi\xd0km\xb6\x15\xb7;\xf5$\xa9\xa4\x01\x0bg\xc9\x96k\x8cI\x8e\"\x9b\"\xbf\x98t\x17\x82\x0c(\x93]\xa3e\xa2\xcb\x989\xb6\x9d\x9b\xb7\x99\x04\xda\x12&\xb7nq\xc9\xaaY\xa5\x04Gr\xe79\x8e\xda\xf7\xa9\xb4\xfc\x02\xeb\xf8l]o\x90\xafXl\x8aM\xfdQ\x92\xdf\x9c\x88G\xeb8\x7f\x13Pl\x17\"`G\x11P>vQP>\x15\x91\x90o\xb3A\x16\x94\xcf\xc7_\x0bM\xba-A\xc9\xf3\xbe&\xfd\x91\xbfzaS\xcde\xdc\x17\xf2\xba\x1f\n\xaf{u\xb5E:\xdf\x9f+\x1b\xc7`\x91&\xeb\xe3U\x90\x1e's\xe6\xe6\xd3F\xd6+\xb5\x17J\x99`\xcbk\xfa\xd1\xb2\x10\x9dV\xee3\xd0\x9e\x03\xf8\x8eh_Fv\x0bE\xd7E=\xaa\xb1($\xb8Vt\xd2\xd1>\xc7\xf37B\xd5E\x03\xaa\xfe\x9c%\xf1\xe7\xb4\xfd\xa7\xb3\x97/(\x06\xaf\x95z\x95\xde\xdb\x94\x85Y\xab\xe7\x0f\xf9\xf5\xd1\xfd,\x0fU\x87\xfa\xfa#\xad\xd0\xad%\xc6\x08\x94`P\xdf\x8d\xb6\xc4\xb2\xba\xde Q\xda\\F\xf9T\xf1\xcd\xac\x94)\x95\xe9\xbf\xb9\x1a%\xe4\x83\xc2Gv\xa5r4\xc7\x98\x8f\\e\xd7\xf5\xe4NQ\xd6VlL&p\xa5\xf7\xc9\x9c\xd1\xdbd\xce\xfcR\x82\x18`\x9a$\xcc\xbb\xc2l\\z\x06\xf6\x8a\xbd\xc1\xb0\x87\x9a`H\xb3T\x06K\xf3\xf2\x1bf\x9f\x97~\x7f\xf8P_\xa1\x0f\x1f\xc0I\xd6a\xee\xf8\xb0W,NE\x98\xb2/Vn_\xacv\xd2W\x98;\xf3\xe4\xedf#\xed\xbe\x8d\xc8}\xabe\x1a\x87\xa7\xd0\xa7{H\xa6\x8c\xdd\x1f\xdd\\\x0eFN\xbc\xf8\xe9\xfc\xc7\xc9\x1b\xc7+\xefcN\x7f\xa8\xc2\xe2\x07\xe5\x9d\xc1W)[\xb04EI\x80\xde\xba\xd8\x0e\x99V+\x1d|\x7f\xf2\xecy\xed\x0b\xf9\xcbZ`\x1eUoN\xf90&4\x9b#[\xf8\x8f\x937\x90\xa4\xc0[\x939\x873\x13B\x10\x91\x93\x1a|5\x8e\x8f\x0d\xf7\x17\x1d\xac2\x82\x0c6Y\xed\xd3p\xedz\xf2\x8c\xfe\x8ec\xb0\x1a6\x9a\x11Z\xc5\x03B\x1e\xd1~cxb\xfe\xe0\xf6H\x0b\xba\x96M\xa5\x87YT\xa0\xad:\x1e\xdc \xe67q\x8c\x0d\xd8\x99g.-\xa0\x14d\xf8\xed\xeb\xd3\"&\x19\xd7\x91\x0d\xaf\x93\xeeq\xe1:[\xb77\xed\xfb\x9a4l(\xad\xf4\xfe\xbb\xf4\xe8]\xbc\xbf\xcbn\xd66k\xdc\xb4\xda\xe5\x8d\"(\xb2\x8b\x0f\xdd2\xda\x8b\x8d\x1b;\xcd\x0d\x82\xbeWi\xed\x0e\x82|>g\x0f\xe6V\xbe\x9a+_\xfa\xbf\x17\x82\xbbH\xd0-\xae\xeeI%\x99R\xd5SXs\xfe\x17\xe6\nC\xf7\x0d\xf9i\x0c\x07\xc3\xa1\x8c\xfe\xfa^\xfa\x85\x88\x8fO'\xfc\xab\"\xe7\xe2\xed\x138TU\x8a\\\xf8E'\xfcW\xad#,2\x06\xe7\xe5\x9f\xe5\xd8\xec\xbc\xc0\xd7\xb9V\x8e\xffc\x8a\xfc\xaa\xa1\xb1j\x17)/7\x1axDZo\x1b4\xaf\xac\xc7n\xba)a\x0cN\xc5\x92\x80\xd3\xb3\xe4Q\x92\x07Tcp\xceD\xcc\x88P\x06\xa6\x90\xc7T\xf8\x8a\xbe\x9a\x1b\xe1\n\xdb\x18\x9cB\xa1\xd1\x1a\xe1\x1aF\xf1\xb3U\x00\xe4O\x9e\xde\xb6\x98\xc3\xb4C\x07\xde\xbe_=\xc3\xd0\x9f\x8f0\xc3\xe0\xd4\xcd\x94\x174\x97\xca\x91\xbd-3\xe2T\xa3\x1f\xcbGJ\xd5|m\xc4\x9fM{\xa1\xa9\xdfcp4E\x83*\xd5\xd1\xd3,\x1a\x95\xcc\x84\x1eB\xce\x15L`\xaa\xe2\xd5\x9cJ}\xeb\xdc\xf1\x8b(6\x85\x1aV\x7f}\x1c\x05\xeb\x0d\x9b\xd7\xbf\x9e\xc6\xf9\xe8\xbe\xb9\x92\xe9\xfdi\x9c\x1f\x1e\x98\x8b\x9b\xde\x7f\x17%\x81\xfd\xc3\xfd\xbb\xe2\x83%,A\xfbuP\xf9H^\xc0!\x94o\xd2_Bv\xdd`~3\x03\x81y\x10*[\xaf\xb0\xd2\x86\x19o\x9cS\x88\xdd\x87v\xa5\xc4\xc1\xd6\x10C$.\x9a\x07Z\x87\x9aDk\x89\xd8D\xc5 \xd5\xca\x8eP\x94D\xb5\x9d<\x83\x9a\xae\xde)?\xbeu\xb0\xb1:Di\x05`\x82\xa7\xd0\x18\xfd\xd4\xc7\xe8\xa706$\xff\xc1 ^\xc5\xf8\x85\x93z\x97\xad\x17EU\x97|\"u\x9f\xf6J\xfbK\x96wj\\m\x9c\\ b#\xe4f~T\x9a'\xa5{l\xebx\x154\xfbFU:\x96\x1d\xd4\xc2Bs\xe8h\xeb+\xabL\xb2\x01\x02\xca\xab'\x80\xa0\xad}\xe9\xf3\xdb\xe1\x1a\x14\xd4\x02\xdc\xc8\x1e=\xeb\x1c)\xdc\x8d\x88L\x95\xfb\xc5\x18\xe3st\xfc\xcak\xa7\xf2\x861b\xd0\xb2\x0e&\x0bi]\xb4\xe5\xfb\xd3\xf7\xa3\xee`\xd0\x92\xea\x8d\xc9\xc8lfT\xc6\x8b\x89f\x93\x88>\x15\xf23\xfe\xf5'\xd3a&\xb6\xd3\xfb\x8e3\x11\xae\xd2\xbf\xfeT\xba\xed\xcb4\xae\xdf\xf7\x92O\xd3\x94*\x8eA\xda\x0cM.B\x86\x05\xb0\x9c\xc5\xdf\"\x9f\x7f~\xf2\xc3\xc9\x9b\x13\xce/\xb9\xc2\xee\x0b\xf5\xdc\x07\xe7\xe5\xab7\xa7/_\x9c\xf1?_\xbd<\xc3O\xaf\xde\xbeq\x0c\x0b4\xd3\xba\x9c\x89\xf4\x17\xad+\xaeIe\xd2\x13\xdc\xbe\x82\x97\xc9\xfcV?e;\x8dC\xb3+\x96!\x16\xf5G\x1f\"Bnm\x9c\x9ez9/\xbd\x9c\x7f\xe6T\xe6\x95\x93\xff\xa6I\x91\xf60\xd6\xb5\x0d\xbbFX\xa8\x1a\xe3\xaazb\xaf$\xb4\x8e\xb1TC4\xdd\xa4A\xf9\xdc\xa6\xd1X\xa9);\xac\xf2|\xd0\xd9\x9fF\xa2\x1b-\x19Y\x8c\xda\x17\xca\x90D\xb7\\\x84\x96\xc7q,\x83nDm\xa6\x14M\x9c\x85S\xf5|\x04\xb34$/\xd5L\x0f\x87#\x1f\x0e\x87\x07\xfc\x9fC\xfe\xcf\x03\xfe\xcfC\x03\xba\xcc\x07)\x9b\x87)\x05\xd8\xed\xc4\xd2\xb8\xa0.RK]jV>\xddZ\xf6:\x88\x97UwS\xa1\xd4\xce\x92\xb9\xf5\x80\xbe\x04\xba]\xf7\xa1\x0b\xc45+OQBG\xcd&\xeb\xa4|,\xea\x93\x11\xf4\xd8\xe0{\xa5r'\xfc\xe7k2\x08\x02\x86^\xe5?\xb3M\x12g|{\xe7\xfc7j\xce]W_[\xa3\x9a\xd3Z\xd3%\x17\xd0\xad/H\xe6\xb0\x97f\x1b[(\n\xff\xe7\x8f?|\x9f\xe7\x1b1\x0f\xbb\xa9&\xdc\xd13\x0e4\xeck.\x05\xda\x8e\x87\xad\xf4\xa9\\\x83\x101\xecD\xa4\xe4\xa3@g\xe3bN\xa7gQ$\xb7Ml\xae\xeb\x91\xb1\xc4\xee2\x02f$\xd5\x1f&\x8c/N*\x1a\x7f\xfb\xfa\x07G&\xa2\x0f\x07\xda[\x18\x03+\xfb\x93\xfcg_\xecG\x9fWj\xf1y\x91&E\xd5\x91\xa1\x17L\x0f(\x7f\xf0ejn2v\x05\x8f\xf1\xc1$\x97\xcb\xe7\xa3\x8f`\xd1\x99\x1a\xcb'\xad\xba\x86\xbe`\xf9u\x92\xbe\x97\xe6uX\x04a\xc4\xe6&\xdf\x0f\xf9\x88\xaes\x8a\xfe\xfd\x0f\xe9|\xc3b7Q\xc7Q \x9d\x7f\xe1\xe5&'\x8cg\xd1v.\xe2\xd4%\xa5\xd3\x1e.Y\x85\x18\xa5\xec\xb8tND\x15\xd5\x16\xddn\xe46\x96|\xc1\\m\x17\x05\x17!/\x0c>\x00 B;\xf9G\xcb'\xe4\xea\x95\x80:B\x03\x8b\xbb\xb4|0j\xe4 c\xf1\\\x0f\xa6\x9ah\x87n*}\xa0\xf6\xd2&\x95\x9a\x89-\x92\xcf\xc1&\x89n\x17a\x14\x99\xbc\x82\xd5_\xae\x9e\xc1\x163[\x90lQ\x8d\x85\xf6\x07\xd1xiqv\xbai\x94\x9bn\x19\xdd\xbb\xeb\x0d\xc8\x98b\nd\x1b\x1a\xb7\xc0lQ\x14\\\xc0pLQ5\xd5J\x13\xa2Q'\x10\xcd\xa4*\x8d\x9b\xf4\xc6\xe5\x03\xd1|\x13m\xeb\xa9\xfe\xaa\xb6\xd0\xc6\xcd\n\xb5\x18\xef2\x89\xec\xdd\xf2`W\xf9Ml\xe9\x9eQF\xffE*KN\x910\xdc\x9a&\xe7J\xc4\x1b\xcd\xe0I\x11N\xfa\x88k\xd6\xc2\xbf\xe2Y\xee\xa2s\xfd\x8b\xe0E\x9d\xcee\xd7!\xae\x9a5\xdb\xfd,\xc8\x18\x0c\xc7V\xc0\x97\x0dX\x8f\xd7\xe5\x83\x0d\x1d>\xb0\xb7$\x1f-\xd9\x80\xb8z\xd5\x10Y@>\x98\x86\xad\xb9\x18\x0e\xe0\xeea\xfb\x00\xf0J\xac\xcb\xd7\xf4\xf0\xa0\x85\xdb\xc8\xc0\x86\xadm\x06\xd3\xa8\xd73'\xea\x94\x8fY\xf2\x82\xe6\xc9\xe1\xa4F\xf6\xfe\xb9\x0c\x1b\x92<6\x83\xa7\x13\xb8\xfb\x90On\xc6!\xeb\xde\x03\x0f\xd7z\x06}\xb8\xfb\xd0>O\xe5\x95\x8b\x0d\xdc\xbf\xa7\x1ax0,\x1a\xb8\x7f\x0fz0\xb2\xdc\x10\x86\x1d\x1ch\xa9\x97G\x0fT/\xa3\xe1Ac\xf0<\xf9\xa8\x15>|\xe0k\xcb-p\xab#\x045\x96\xb2o\x10\x08\xb0\xe5+\xf1\xe8\x01\xae\xc4'l3\x1f\xe8\x81}\xa0mPp\xd0\x0c\x05\x82\xc4\x98\xa0 \xfd\\(H\x7f\xe7P\x10\xea\x10\xf1\xeb\x83B\xfa\xd9\xa0\xa0F;\xba\x0f\xdf@\x0c=\x93Q\xfd\x0f\xf6_\x82\xdf\x05ER\xe2\x08\xfaz\xea\x94\x8f\xbe\xc6\xca\xf8\n\x15\xab\xa2XVP\xf2\xf2;\xb8w_2\xaa\xc7\xb0\x85'pp\xef\xfec\xe8\xf5\xb6\x1e\x04\xd3-\x86#\xfe\xa3\x03=p]\xfeqt\x1f\x8e\xc0\x19:\"]r\x0f\xb6\x05\x97\x1d\xdd\xf7<\x9b\x87\x8d\xcc\x9e\xd6hFo\xb8E\xd9\x9b\xf0\xfe\xca[\\\xf2ft\x9cR\xceP\xe1\xac\xc8\xb4T\xc5F\xcdRj\x94%\xb6j:I!\xf0=<$\xf9\x8fkNw\xefi\x7f\xdf/\xfe~\xa4\xbd\x1f\x1dh\x1f\x12\x0e\xfb\x87\x8f\xf8\x8c\x12\x0e\xfbw\x0f\xd4[B\xdc\x84\x10W\xbd%l\xc4\xb7\x8f\x86\xea-a\x0f\xbe\x1d\x1d\x1cX\x04xtd\x80>\xc4*\x1dh\xce\xd7P^(BE\x9b\x8b\xd3|K\x0f\x1e\x12\xbdO9T\xfb\x80\x05\x83ib\xb1\xdd*\x82\xc1\xeb\x1e\x0c\xef\x1a+\x8f\x1e\x1d\x00\x0e\xf7)\xdc?\x87\x1e\x7fs\xf0\x10>\xc0\xfdC\xb8\x03\x9dZ\xbew\xef\xe0\xd1}5\xe7{\x0f\x0e\xef\xde5utppWv4:\xd0{\xa2\xbe\xe1\x0e\xdc?\xdcm\x00\xcd\xd6\x87\xb0\xc1v\x80\x10\xd2\xeb\xe9pW2*\xbd}}*\x94\xb1\xb7\xafOa\x1dD\x8b$]3\xab\xdb!\x08\xfb\xc5hx\xc0\x07]\x81P\xdf\xb4\x18w\x87\xf0\x81\x12\xc5\xdd\xbfw\xef\xf0>b\xad\xa8\x9ex\xf0\xe4 \x8cx\x81\xd0\xf3p\xbd\x1e\xd6\xd6ktP[\xb0\xe6u4\x0e\xbc\x03\x01+\x02\x890\x8c\xfbT\x12qs\xe8\x15\x80\xea\x95c7\x96\x15\x95\x96\x88\x05\xd4\x97\xe5\x8e\n\xef\xd8\x94\xb9\x85#K\x98}\x17\xc6!E\xe4:\x02\x87\x93?,~\x99$\x11\x0b\xe2zSG\xe0\xe4\xe9\x96!Y\\\x04QF\x7f9\xfa\xb8\x0b:,\xf5\xa5hw}\xc9\xae\x1e5\xc51,8\x02F\x1e\x18vQ\x87h\xd1\xc2\xc5-&\x0c\xa4[+U\xa5\xc8\x9c\x0fX9\xf1:w\x04MF\x87UgR\xb9ht\xa5\x12\xfa\xd2\xd8\xca_\x89\x0e\xd8\xa2\x18%bD\xba\xe6H\x96\x03<\xb3\xa9\x7f\xe4\xf8B\x99b'\xf6d>\xa6%,qM=\xe3\x83\xcc1\x1c\xa8\x88$\\\xbd\xdbrvL\xd9\xf29GZ\x10+Z\xc0\x13\xd8r\x1e\xb4h2\xe1S\xaa\xe1EC\xa6\x879\xa5$n\xc9\x16\x11\xba\x19\xe6\xb7\xedU\xd3A\xca\x87\xafm\xf9\x12\xf8\xbcQ\x08Skp\x05\x13\x98\xab\xf9\xaea\x02W4\xdf%\xcds O\xe0\x8a\xcfs\xe9\xc1\x8c\xd3\xa4\x15\xf4p8\xf3\xe9\xf2\x9c\xf3\x1b^`-\xd4\xb0\xde\x04\x9a.V`\x08+\xbep\x91^\xdeLp\x88r\x97{\xe4\xdd\xb5W\xaf\x8bj\x02gf\xedDL\xc7o.v\xa1\x8f<\x024\x995\xbe<\xba\x04\x86\x88_\xa1-\xea\xc6\x87\x0f2[\x8fdFJ|,\xb7`\xa8\x9d\x17\"CM\xec\xba\x12)\xf1c \x08\xb5%$\x8fp\xdbW\x8e\x1b#vXn\x94P\xbdN\x8e\x93\xc1:\xb8\xf93\xbb\xcd\x94\xee\xae\xde\x18\x86\xc5\xd1m\x04\xfbU\xb5p\xa6\x84 ^`f\xa8\xb8\xc1m\x93T\xd2443\x15\xaa\xdb\xaf\xb0\x9b\x0d\x8e\xb3\xfe\xd1&\xc0r\xbc\xde m\n}D\xe1\xe9\xb9\x8f\xc86$,\x1b\n\x0c\xf3\xf1\x94\x99\x13\x96K\xf1\xff\x05\x9d\xc1\\\xd3\x7f'T\xe8\x86\xb0\xf1\xa6\"\x00\xdf\xd8\x04\xe0\xb3\xaa\x00|c\x11\x80\xcfp\x8c\xb9^tm\xa5\x1c\xbc\x82\x18<:]\xb9\x87\x0f\x10\x1c\xcf\xe0\x08\x07:\x821\x9c\xa8\x9d9+\xc4\xe0\xb3B\x0c>+\xc4\xe03RJ\xd5[\x12\x83\xcf\xa4\x12 G\xc0es\xe8\xf5(\xc2\xda5Y\x9b\xb1\x8f \x86\x91\xe6\xb4\xc7j\x0e\x035CJ\xba\xa2\xcdp\xd9\xaa\xa0\xf2\x8a\xbd\xde\x12\xabn=\xb8\x82'\xe0\xbe\x87 \xdc@\x1f\x96\\B\xa38\xd5\xb7\xba\x04~\xe5\xc3{N\xa2\xc4\x96]a\xf1^\x9bIl\x96\xc4y\x18ow=\xe6\x03\xe1\x0d7\xe4\x00\xf3\x9bo\xc5Ee+\xcc4\xdc\xf8\xf6\xee\xa1\x18'o\x077\x10\x8e\xc0\xe5\xebz\xa5\x86[]\xd6\x1b\x0f\xe3\xa9q\xd2\xf5\xc7\x83\xa1\xc0\x11\xea\xbfR\xf3\xd2T\xf3R\xaby-\x8f,\xd4\xf6\x188H\xa1\xb7\xf4zk\x1cn\xd6\xc4\xe5\x8f}\x90\xb0\xb1\xb6o8oN\xce\x97\xc3\xd3{\x1b\x04\xc1X\xfb^\x9d\x10B\x98\x8c\xf88\x81\xc8\xbd\xf5a\xc3\xdf]\x8b\xe2\xfc\xdd\xa5x'\x8e\xc4W\xeaH\xfc\xd6\xf3 \x98\xde\x9ec(KXMW\x82\x96\xf0\x17\x86\x9bY 4(\xf7\x18\xe5\x98\xdbsO\xbf\xa6\x85r\x06\x1c\xc1\xf1\xf4Xk\xe6\x12\xc6\xb2\x8b\xe9\xb1\x0f\x97\x16\xc5\x8c\xaf\x06\x06\xf5\xea\xf7\x17^\x93\xc1\x8cou\x99\x16\xdeb/D,\xd5.\x12UE\x8c\xa8\xef\xe7\x1f\xec\xbf\x16\nt\xaet\x95\xe5\xc3\x07X\xf2/^\xfd\x93\x0e\xb7\xe5\xdd\xe3;\xb7\x86'\x90\x19v\xce\xfb\xcc}\xe3Hb\xdd9D\x84\xcf\xd9\xa3\ns\x90B\xc5\x1f\xcak\xd69\x93\xc1#K*\x83\xc3\x87#\xaf\xfdtO\xba\x13\xc8\xebpp\x04\x7f\xffH \x0dAB\x8b\x91\xeb\xc7e\x9d2]\xea\x03\xaeF\xd5\x13\x03\x1e\xb6GI\xb4'\x85HE\xa7\xad~p\xa2|\xe2\xb2Z\xfa\xb3\xd6\xc8p\xd69\x8d\x0e-s\xba[M[D\x81\x05\x1f<\xea2U\xc3\x0cJ\xfaT\x7fD:\x94\x12\x16Qt\xfc\xfbG.\xad\x04\xa83\xd9D\x16\xbc\xf01\x0d,\x9a\x10\xe6\xe9\xe3#\x88\x0c\x82L\xec\xce\xf8\x07\xa0\x98\x81>\x84nDA:g6\xbd\x18\x8aU\xcfv[`\xf3\x19\xeb\xfe7{E\xdb\xdf\xc0,I\xde\x87L\x7fs\x9cln\xd3p\xb9\xca\xdd\x99\x07\x07\xc3\xd1A\xff`8\xba\x0b\xaf\x93u\x10\xc3\xd9*\xbf\x8d\xd6A\xdcT\xe1\x1e\x1d\x9e#\x0f\x99\xa3*O\xfcf\xc4\x99H)w\n\xc4\xd3\x0d\x95\xc3?&\xb0u\xe7>d\xed\xa1)M8SI\xe4\x9d\xb14\x0c\xa2\xf0\x17\x93~\\],E\xa0\xc4v\xd7WZ7O}\xf8P\xbdm\x88pY\xa8n\x05d\x86\x16\xc8L0\xa9\x1e\x88\x06\xc3\x0cB\xf2\xfe\xab\xee2\xeep\xd0\x12\xa8R\x81y\x1c\xac\x9b\x1a\x93\x1auX\x8b4A\x07|\x18\x9e\x9b\xfa\xda\xb6\xf6u\x15D-]\xe1uu\xe8\x813q\xa0\x07\xdbz\x8f\xc2R\x06)W\xb5\x9f-\xadW<#(\xca@\xdft\x18\x8b\xc7\xd4\xd9\x8b\xe0\x85\x1b\x99\" \x89\xaa\xd9\n\x831 \x0dxA&\x00\x03\x14g(\x98?\x86\x1f\x83\x9b\xfe\xb3%\xc3\xc1\xff\x18\xe4\xab\xc1\"J\x92\xd4\x8d\x9a\xa87\x1e\x87\x0c\xe6\xc9:\x08\x8d=\xe8o\xb0\xd7\xe4\x15$'(\xfa\x98\x9cUe\x9b\xea\xd3\xe6\xdd\xe0D\xc1\x8d\xb3C\x87?\x047\x9f\xd3\x9b\x90\xc5v\xe8\xf0sf\xd8\xeaF\xd4\x04\xf4j\xbfu\xa8\xaf\xb5\xd4\x81\xffj2k1L\xc9Y\xebF\xca\xba\x1aP?N\xa9\xab\x04\xfb\x8f\xe1\x9b\xfd\xf2k.\x9a\xed\xff4}\xb7\x1d\x0e\x87\x8f\xf8\xbf\x07\xc3>\xff\xef\x01\xe3\xff>\xa4\x1f\x8b\xc5y\xef\xdf\xf6M\xc7c\xdb\xdf\xeax\xac\x1a\x93\xb9\xfc\xd7'I\xf8\x1dC\xaa\x8b\xfek\xcb\xeb2-\x1c\xc4t\xefk\xd7\xfb\xe6|\x7f\xd9\x16\x8b\\\x1eK\xa0\xbbF\xc9\x9e;\xf4J^\x1ae'\x8d\xf2\xec\xdb4H\xbd\xe3n\xb3,\xb9i\xc8\x1c\xf32+\xb2\x92\xc7c\xbb<\x9eV\xcd\xd3\xb1E\xe4N\xd1U\x00\x1d\x07\xee\xdc\x81\x14m\x97\xf7\x0fG\xe8q\x11C\x0fF\xfa\xc9|\x83X^s\x08\xc1\xca\x16\xc1\x9a\x0e*\x9fbW\x07h\x1c\x12n\x1c\\un0\x1c\xcb\xe3\xcf\xd1\xf0\xe0.|C\xde\x1a8v\x0fz\x90\xf0\x1f\xd8^\x8f\x8e\xf2\xed\xe4'\xa7\xebp\x07w\x87ey(\x84}\xb8\x7f\xb7\xf8\xc7\xf3at\xf0\xd0Z\xc6\x83?\xc2\xfd\xbb\xd62\xe5\xcf!\xfeB\x1f\x84^\xa3\x1bg\xa3\xbd\xban\xf25\x9c\xc6Qh\x89\xbb\x0f1B\x04\xcd\xf4\xe0ny\x84i\xf3$S\xc3\x04R\x9a\x00\xe7\x97\xbc\x03\xfeR\xb5?zt`l\xa0^WTH;\xd8\x0d\xda\xd2O\xea\x90\xb2gw\xf3\xe7@\xc3la\xf9\xedF\xb2J\x91\x86\x0b\x96(\\\xa6z\xfe/\xcb\x19\xb2\xc4\x93\x86[d\xa1\xddAs\x9e\xb4`F\x80V!v\xc3f\x8d\xa9\xc5\x94\xb62\x99L h4\x0d\x83\xd2\xcbCx\x02\\\xbao)\x9c\x90S\xcd\xf0\\\x19\xa7\xc2^\xcf\x0c\xc8p\xbd\n#\xa6\x14'>\x14s\xbb\xd2v\xc7\x81N\xf3x\xe9\x8f\xcc\x19r\xfe`\xdfIK\x8a\x00\xd0\x9d\x04\x85v\xbaS\xbb\xc2\xach\xa3\x8eZz\x8d;\"\xbd\xc1\xd4\x99\xfet\xee\x9c\x97\xcd\x07d;\xe0\xa2l\xcd\x9e\xa3\xda\x12\xa4\xbd\xed\x92\xf0\x0ea\x81\xb0\x1a!%\x1bd\xc96\x9d\xd9\"Fx\xbe,\x18\xca\x82\xe48\x98\x0efI<\x0bD\x10Gv\x0d\xaf\xd9\xf2\xe4f\xe3\xa6\"\xe0\xcf\x07\xc7\xab\x99]\xc1H\xba\xd8`\x11\xc6\xf3\xe3U\x90\x9e\xc6sv\xd3fB\x93\x0f\x87\xd1\\\x87\x0f\x85\x89\xfd\x86\xb3\xa22\xceZ.>\x95,i\x89\xeb\xf9\x02E\x0b\xd7\x98X\xa2\x1c\xda\x1c\xdcx\x10\x05YN\xc3\x7f\n\xb9\xf7\xd8\xe38\xd0\xb8]\x86\xfc\xcc\xbeX\x8aoos\xb6\xd3R\xc8\xd9\xf0\xd5\xc0\x1b\xb4\xb4 \xe4\x95\x858\x83\xf5q&\xe6x\x8b\xc4\xc5\x9fu\xbe\x1a*\x17\x87n\xa6\xebc\xa6j\xf6\x0d\xe0\xd2\x0c\x9e\x88\xc6\xc6\xbd\xb3EY.\xe4\x1b\xe5\x98\xc9\x85\x8d\xea\x89\x88\xfe$\xe8t\x84\xfb\xd4\x92~KQ\xc6\x84\xeb\x8c\x94)?\x99\x0e\x8dq6tyg\x97\xd5j\xbd)\xa3?r\\Hc\n\xdc\x92(\xe8#\xb50\xee%\x7f>\xb6\xedA\x8a\x06W\xd9\x8b\xf1^\x0c\xd8D\xbc\x96\xa5$\xa9\xf2\xc9\x84\xbcA\x92B\xb4+\xcd\x89\x8f\x15}?\x87\x9e\xafdN\xe95\xca<\xa7\xd0=\xa8\x07\xee\xa2Q\xe0\x10\xde$\x9c\xf4\xbdJ\xc2\xb8\xc5\xe6!\x9f.\xb6\x0f\\\xdb\x99lW\xae\xb1\xc6=DjIU\xc4\x13\xd6\x12\xa1~j\xef\x1b\xa7o\xe1\xfajBo\x84\x85\xe8\x8bM\xac?\xb9\xcf\xd7\xf2\xf9w\xdf\x9d\x1b_\xeek\xbb\xfeQ\x1c\x16t=\x13\xf8\xba\xdf\xef\xbf\x8b1\x00\x96\xb3\xca\xf3M6\xde\xdf\xdf\xb0\x1c\xf3\xdd\x0f\xb2\xeb`\xb9d\xe9 L\xf6\xaf\x0e\xf6\xe5\xaf\x9f\xb3$v\xde\xc5\xf3d}\x11\xce\xc7\xe0|%>\xf4\xb7\xa1\xf3\x8e\x0e\xc1\x82\xd2>\xab\xa60\xf2\xc15-\x07\xf4a\xe6\xc1>$\x1dg\xa5?ie{\xb4\xa3\xc0\x0cz\x10\xc17d\xee\x1d\xdc\x83#8\xc08\x0e\xdf`$&\xfe\xbf{\x17\xfa\xf4\xd2C\x95\xd2\xa6\xe0\xd8\x9e\x02Py\x17#\x0e\xac\x08\\\xdf3t\xef\xf5\xf0\x00\xf2 \x10`\x0f\x88L\xd37.\xb1\xa0\x0b\x90\xbe\xd2\x81\x0f\x8f\x1eiPo\xc7\xce\xea\xf3\xd1\x87G\x1d\x8b\x7ft\x9b\xcb\xd9/%5\x90\x84h\x07S\x85|2wK\xf1\x9e\x8dG4\xf2\xb1\x84\xb4\x93\x8c\xc8N\xa4X\xbe\xdd\x8c\xbb[\xbb\xa1h\xd4\x1571\x91*y\xeap\x8c\x8fU|B\x87\xe6\xdcS\xc6\x9d\xdck\x8a\x1d)\x1f\xe1`\xf4|\x9b\x8a\x00\x90q;\xb8\xb3\xf9\x92\xbd\\,2\x96\x9bBz\xeb\xcf'\xed[\x9e\x8c\xc1\x92\xab\x80>\xff\xd7\xb8\x89\xd6\x85q\x9e\xfc%d\xd7\xe5u6]\x9c\xad>\x92Wc\x9c\xf0o\x93m<\x0f\xe3\xe5q\x14\xb28\x7f\xcdf\xb9\xeb\x0dV\x88'\xed+\x14H\x8a\xae\xf8Z\x0f\xc2\xf6j3YM\xe2j{\x95\xc5N\xbcc\xc3Q\x02zm\xa1n0\x05\xf2\x13Xp\x88\n\x91^<\x85\x19\x1cQ\xbc\x01Z\xc91\x04\xe2\xc3\x06\x8e s\x03N/\xf9\x9b\xa2\x00\xb1\xd2\x06\xccn\x80\x81\x19\x8bs\x96\xd6\xb60\xed\xb0\x8b\x99\xdb$]\x94I\xe1>\x1c@\x8f\xa3\x0b\xc7\xaa\x96]\xe7\x85=OL\xefS\xe6\x94\xe5\xc9f\x0c\x81\xbd\xc0:\xb9\n\xe3e\xc7\x0c\xfcP\xd0\x86\xbd\xbd\xfa!\x90|\x1a\xc6\xc3\x81f,\x80\xa7\xb1\x14.\xdfX[Jca\x833N\xbdUN\xb3\xa4\x14?\x90\x7f\x9cDl]s \x04\xc1G[\x17C,\x82\xd0E\x88\x9f\xfd\x17\x1a\x91\xc5\x8f7\xc9\xa6\xcb\xd0\xd0j\xef\x9a\xfb\xa0x\xd7j\xe0\xd4n\x18/\xc5\xc8yo\xea#/k^N\xa4\\\xddd\xe5\xd2l\xde$\x1c\x92wL]\x81\x9bkIN\xa9P\xa0#\xac\x95\x978\x8cc\x96\n\x89\x01\x97y\x86\xc8Bov\x1c\xa3\x00\xadn\x8b\"\xf5T+\xa2\xe6\xc9\x86\x93 \x14\xde\xe2A\x82,\xca\xb4\xfb`\x06W\x83\xb75\x06%\x0drv\x86\x1bQ\x8b\xeah\xa3G\xd2N\xd5\x08N\x96D2e(i \xcb\xaf \x9c\x03\xef\x8ek\xff_\xbb\xed>k@'h\xec\xe8S`M\xc9\xe7\xac\x04^~' \xdc\x15S>\x0d\nw\x86/\x01/\x7f\xa8\xbct\x82\xf9\xfc\xe4\x8a\xc5\xf9\x0fa\x96\xb3Xd\x0c*L.{b\xcaq\xf2\xff\xb2\x98\xcc/\xf8\x9a\xb9%\x9ac\xbc'&E\x1ag\x15fy\x92\xdeV\xad9\x9bm\xb6:\xcb\x83\x9c\xcc<\xa2\x90y\x9d\xb8L\x13\x92 \x08\xe1\xe05\xe3\x85Qj\xd4+\xd7%\x0b\xcaT*>\x0fj\x95\xf9\xe8\x82m\x9e8\x9e\xda\xdc\xea\x82\xb8N\x94\x04s\xc7o\x87 \xeakWE\xb1ql\xeb \xde\x06\x91%\x86=Wq\x1a\x86\xbdI6\x19\xaen\x9b\xe7\xb5|\x18\x86\xe8&K\xdc/,\x16\xdc\x8cRH\x15\x9f\x12T\xf1\xc4\x8bAQ\xce\x06\xf7\xb0\x87\x97\xf3\xc40e\xb0\xf7\xc1*\xc8\x10\x92v].iUL\x06\xa8\xd0\xb8\xde\xa0\xd0\x08\x9aO\x0dZ\xedC\xd2h\xa7 {\xc9\xa4x\xf0\xed\xed\xe9\xdc\xadM!e\x0b\x99\xc1\xef+\xc7\x9b\x8e\x9a\xf2\x05\x83t\x8ek\x1b\x05\xd4\x0c\x05$L&\x850\x99s\x1e\xc3:\x88\xdc \xe4\x98D\x08\xe9\x9c5\xb5+\xf4Cx2\x81\x14\xc8 \x1d\xd0\xff\xdc \x124\xa8\xa8\xd0\xac}\xd9\xa1\xd9D\xb6\xf6L\xae\xebW2\x8aO\xe1\x86\xe5\xb8?}x\xf7.\xf34J\xe5\xbe{\x97}\xf87\xcf\xe4\xc2i\xc5\x9aY\x14\xce\xdewB\x99\xd2\xb1!\x1b\xe4A\xbad\xf9c:\x89q\x9e9\"\xd8L\x1e,_\x04k\xf6\xd8\x13G\x9f\x9b eq\xfe\"\x997$\n\xdfs\xf7\x90\xb1\x8c(\xe0\xd7\xe0z\x15\xceV\xa4&`\x1a\xc8?\xb3[\xfa\xb5fy\xa0~\xcc\xf24R?\x82\x88\x97j\x8c\xfd\x82\x16\xc86h\x94\x90\xa8\xa8\x94\xa2\x10\xf5\x08d\xe52G\x95\xdf\xe3\x9a\x91\xbc\xfa\xc4\x1a5\xd1\x80\xb6\xb9R{\xca?\xd0\x88\xac\xb8\x96\x82\\\xc7\x8d\xeb\xe7k\xd5\xa7\x94\x02pW\x90\x06\xdd\xc5\x0b\xb3\x18\xe4y\x1a^ns\xe6:\x9cv8\"\x85A3\xd9\x12\xc6\xfe\xe2\xce\xf6W\x0e\xf9\xb7n\xc9C:\x1f\xcc\xa2 \xcb8\x90\xb5\x86\xfa\x91\x06\xdf\x06\xb7w\xf9D\x0d\x840-\xdcZ\xdcQ\x9b\x89\x10\x8fW\xber\xc4\xd1j\x87\xbdB\x0c\x88\xe4\xd1J;\xb9\xca$\xac\x10q\x8c>\x95.\x01egJ\x19'\x08\xcf\xc94\xd5\x06}W\xe2\xcac'\xd6\xa5?\x15^\x02\x93\x16c\x164\xab\xd3\xf2Y\xec\xcc\x19\xa9\x16]\xff,3\x9c\x0c\xfa\xb0@/\xeb;\"x\xd9N\xb3\x94(\xa7\xa4<\xf7\xef\\\xdet\x8c>^\xfa\xf3\x11C\xbb\xa2\x94\x91\xf9\"\x83\xf4\xac\xc1\xe8af'\x16V\xf2\x07{!\xe9\x07\xa7^~t\xcb\xdea\x18\x9e\xd1\x18J-\xc5[\xad\xc1f\x13\xdd\x92\xa7 \x8c9\xac\x7f\xf8\x00\xae~\xa2\x1c\x9a\x0f\xa0;\xdd\xc9\x13\xc1\x1b\xe9\x94\xb2\xc8\xc9\xe7\x83sq\xc1\xb2\x1f\x93\xf96\xe2\x92^y_0}\xdbX\xcf\xc8\xa0\xeb\x99\x926m\xdc\xd8\xbd\xeb\x19\x02\xa8\xf0\x0f\x07\xd5\x0f\xa1\xf8pX\xfd\x10\x88\x0f\xf7\xaa\x1f\xb6\xe2\xc3\xfd\xea\x07L\xf6\xe0\x0e+o#,^MJ\x85'G\xbc\x15\x94&\xf1\x0f\xb2\x88\xb9\x87\x0f\x1fT\x1b^P\x94\x17\xcft1\xd3\x90\xf4Y?\x83f\x83b=E\x9c\xd5:\xac\xcb\x9b\xb1-\x97/A,2E\xbdX\xb1h\xc3\xd2l\x90lN\xe7\xe5\xe1\xb6;\x02\xaa\xd1\x0b\x7f:\x0b\xfe\x91\x9c(F\xe7\x89Lj6\xcf:\xa9\x9e\xf1JA\xb5\x92\x9b\x0f..0\xfd\xd9\x05\xc5\\\x1b\xfa\x18\x19R\x16\xf2<\x91#\x11K\x93{g\xe3\xc1D8\xc8\x93\xe52bg\xab\xe4:\xeeJK\xa4\xb0\x1f\x0e6i\xb2i9c\xcc\x85\xd3\xeem\xb2\xcd\x9fa\xdb-\x15b!\xb7-\x9b\x8b\x91\x97\x1cG8$\xd5\xd5\xcd\xab>\xc25;\xc3\x896\x17E\xad\x96s\xae\xd7,K\xa2+6?\xdb^\xe6)k<\x0f\xc53P\xcd?'@;\xf9@$\xc6\xa95\x84!KV\xc9\xb5;u\xd4\x0c2\x87\xec\xd9\xe7>\xec\xd9\x9c\x9a)u\xcfq\x10\xcfXt\xccE\xe2\xae[\x869j\x04\xbdo\xde\xae\xf4\xf64\x7f\xb9\xcdO\xe2\xe02b\xf31\xec\x85B\xa7\xac|\xb1\xb6b\xc8H\x03\xc5\xd8\xdf\xa4\x1c\x10v\x1a\xfb'\x80[\xb6a\xb3\x1d\x80m\x13\x98b\x8a\xea\x0fA\x1be,j\x10\x0c\x7f\xcbU\xe60\x84.\x1b\x7f!\xbf$F\xc9\xc11\x87ejs\xab\xa3M8\xb9a\xb3m\xde)q\"\xec2-F\xed\x9e\xc6\xaf\xd2d\x99\xb2,\x1b7&\xf2n\x18c\x1d\xfb\xba\x0e\xf6\x13\xa1\xe5\x8cEl\x96'\xe9\xaf\x00/]\x08\x13\x1f\xc2\xab _\xd9aK\xdd\x07\xc0\xac\xf6\x1b6\xab\x12\x15.\x9b\xfd\xe9\xcc\xf5\xe8\x12\xb1\xa9\xc4\xd4\xe1\x03Wt\xa6a\xf9\xcdt\xebW\xde\x82_\x0da\x7f\x85\x0d\xb0\x10\xf6\xf2\x1eX\nu\xdf\x06R\xd1\x9b\xb2\x00\xd6 \xc9\xc8>[\x13zZr\x8a\xfb\xa6;\x97\xb57\xca\x11\xc1\x87\xad&\x85\xf8\xc2\x07\x81OA\x7f;5\xcf\xe3=\xbb\x1d\x83\xb3\x0e6Hb\xde$\\\x8c\xce\x1c\xf34\x84\xe8\xdc\xd9]B\x1aJ\xf2A\xb2i\x07\x98\\\xc8)\x1d\x89A\"\xc4\xb4\x9c\xdc\x1d\xe3E\xb8\xcc\xbc\xb63w\n&?Of'7\x9b \xce\xc2\xa4\x834\xc2\x85G\xb6\xf9!\x8c\xdf\x87q\x8bX\xb4\xa5\xe2a\xb6\x89\x82\xdb\x97]\xa5\xa3L\xaf%R\xd9I\xff\x8f\xe6\x9a\x11\xa9\xb6\xdb\x0d\xd7\xa6\x10\xc6\xd7a\xfe#\xa2]\xcb\xeaa'OO\x16\x83\x1f\x83M\xab\xd2\xfe\xb3\xd0\xf4\x17x\x13\xfcOg^\x0b\x8b\x03T4\xc6p\xda\xdc,\x7f\xf2`\xd9\xe9\x86\x05\xa7\xdfV\xef]\xfd\xc9\xa4\xee\x91[\x14-\xfa.\xf4,\xc7\xc2\xdd\xf4g\xce6)\x9b\x059\x17\xf1OI\xf3-^9B]3\xf6\xa5\x15\xa3\xee\x9a\xccS\xf2!\x0e4\x86\xa4\xbdh\xa1\xa7t\xb8JQ\xd6UZTi\xa8\xaa\x8a-j\x19\x96\xaf\xdb \xc4\x82u\xb7X\xb4\xf7R\xd2/;\\\xf0SzU\x8b.\ne\x15\xaaE\xf6\x80\xbaN\xd9B\xf2AW\x81Z\xf4O\xb0\xe8\xc6-\xda(4\xe8\xc7-B\x12X\xd5\xfd\x16\xce\x0ff\x89\x96\x04b<\xd2\xa9}mo\xb0f\xd6\xd5\x9a\xebzB\x04P\xf7_\xd7\x1fa-\x89\xa4\x89V\xb8\xb5\x0b\x8f\"\xf7\xc7\xb6\xabb\n\x9c\xc7\xf0s\xf3\x8c\nm\xba\xcdh\xdf\x11<\xba\x82\xb4v\xb6-\x96P{\xd3\\\xb5tR)*\x97\xde\xb5U\xd7\x0eiUu\xed][uqD\xa7\xaa\x8a\xdf\xcd\xd5\xa4<5\x86\xcb\xf6\x82\x82\x95\x8f\xe1\xba\xbd\xac\xe2\xe3c\xb8h\x19y!$\x8c\xe1e{Y\xad\xe5W\xcd\xa5K\xf2\xd0\x18\x8e\xbb\x94\xd6Z?k.\xaf Och\xd9\x9d\x92\xe44\x86g\xcd\xa5u\xc1r\x0c'\x1d\n\xa3T9\x86\x9b\xe6\xa2\x8bx\x0co\xac%l\x87\xab\xb5\xb7\x1f\xcf=\xbfrO\xe4\xa3\x9b\x0d^mSfJ1\xb9\x92\xe4\x02-\x1d\xb5\xb3\xa9\x12s\xda\xab84\x16t\x00\xdd\xc7J\xdf*\xbc\xa4Z\xd5\xc4\x0c\xaa\xb2\x84\x8d\xf2k\xc6\x05\xcc\x15#&\x00\x13\xa0\\\x14\xbf7\xc7\xaf\xc8\xe6\xf8\x15\xd9\x1c\xbf\"\x9b\xe3Wds\xfc\x8al\x8e_\xfc\xc3Pw\x1a\x8a\xc8\xb9\xcb\x92k\xfa\xb7\xf6\xd9\x9a5\xfadi\xfeX&k\x8cv\\ip\xc7\xf2?\xd9\xe5Jx\x18bq\x992\xa7\x9a\xd6\xc8\xe8\xd4\xf8\x19\x07\xa7d\xa0Z\xb2\xfc\x07$t\x06)\xbe\xab}j\x17\xdbT\xbe\x83\xaa\x1c\x9b\x14\xdf\xc1l\x9b\xa6\\\xbch\x10t\xd1>\xe9\xc6\x98T\xbc\xd1y\x0d\xef\xe8\xb6\xceO\xab\x90Yd\x1dg5r\xa4O\xeb\xd7\xf0\"\x11\xdc\x03D\xf0\x19\xbcS\xe0|\x8d\xe7\xf5_;\xf0ug\xd2Z\x86\x00\x93@\xd5bg\xfc\xa4=T@a\xb3\xe6\xb6\xac\x06\xa3\xa50\\\xfb(\xcf\xa7\xcc88\xd3\x90\xed\x99\x18\x87Nwg>\xccj|\x84Z\xff\x171\x16\xcf\xfftb\x8c \x8b(\x15\xfa\xd5|a\xb0\x8b\xd3\xac\xba\xf0\xc3WL\x91_\x15_?\x82 \xe5 u3\x8fr\xe8\x0f\x1f\xc3\x0c\x9e@\xf6\x18f\xbd\x9e\x07\xd1tv\xae\xd7\x9c\xce\x0ca\x01\xc5R\xc6x\xe1\xd1\xe6\x9c\x8b\x18\xd8\xca-fA\x14 \x96\xc1|\x98\xf2\xba\xe72\xf4b\x84IZ\xc3\xc1,J\xb2N\xeeV\xc2\xc5J\xb7\xfd\xa11\xfc9G\x85\x10\x7f\xbbU\xffz 4\xc3\x8bZ5\xa6\xc77\xe3\xb7\xe0\\_\x96\xe4ub[\x1d\x0d\x9eqwcj\xba\x03;\xa4\xd3\x15\x96\xa6\x1d\x86\x10\xeeb\xf1\x0e\x84\xf1t\xf0\xec\xec\x8d\xbd\x14\xdfm\xed\x04-\x90)m\x1b\xcc`\x98\x0e\x15\xa1)\xd6\xc1\xa9\x81sS\x8aT\x87\xaf]f\xcb\xd0\xd0\xc6\x8a\xe7\xe1U\x8dT\xeb\x8f\xbaV5\x06g\x1e\x06Q\xb2\xecoo\xacWq\xbfH7\x97\xc1\xec\xfd\x1f\xea\xe57Z<9\xa5>^\xcf\xff\x8d\xfaZ\xb1`\xfe)\x9d\xad\x0e\x95\x1c\xe8<\xbb\n\xc2(\xb8\x8c\x18\xea\xfbI\x1a\xfe\"\\\xb8\x9a6\xfbr\x9b\xe7h\xe0\xb5\x0f8\xbf\xdd P\x89\x92\x9d&\x86\xfc\xa0\x8f\xd3k\xa8\x91\xc4\xba\xb9 \xeb\xec\xbc\x02\xd9\xd5\xb2q\xf4\xd7\xe1<_\x8d\xc19\x186\x0cd%\xa2;\xf0R;\x8f`\x9b\xd5e5\xfdY\xa5l1\x06\xe7+\x9c_\xc3 n\xa20~\xff}\xa9\xb0\x05y\x91\xe9~Y\x00\x9c%q\xce\xe2\xdc:\xfbh\x80|\xee\x8c\xfd\xcd\xf5\x06\xeb`S\xcaI\xdex\xfd\xb7\x85~\xce\xda\xcc\xb6\xc8~[\x0e?\x9e\x9d\xbdi=\xf0\x98\x17,\xc1\x1a\xb7D>e\x13X\xcb\x19\x96\xce\"[\x0f\x81*\xa6\xb8\x96\x93\xdb\x92\x91\xaf\xc5\x00\\1{\xd6\xdd\xa1\xe5c\xb3\xb4y\xf8\xd4\xbe}9%\n\xdf\xfeK_\x12\xcf\xbf\xf4\xa5\xff\xc5\xfa\x92\xe0|]4\xa6\xce\x97S\xf2\xeez@\\\xd7/\x06\x1a}|\x93\xa8\x83g\x9bI&\xafim\xe6\xd4\x15\xffR\xda\xccO,\x80\xac\xac\x8dy\xa4\x8b(\xd9\xedU\xb2\xd9n\x1c4,6+u{{\xbb)>\x89\xa8\x13\x14\xee\xce\xde \x0b\x7f\xb1D\x13\xf9\x92:\x10\xef\xb2\x7f\x9d\x06\x9b\xcd\xa7\x08\xbc\x1d\xe4U\xad\xb3\x04\x8e\xc0\xb9\xccc%\x113\x88\x92\xd9{6w`\\\xfd\xb0\x8d\xc5\xa7\xae\xf2\xaa\xf8\xb5\xf3\x14\xb2M\x10kR\xbb\x1c@\xa3\x98\xfe\xcf\"\xe5\xe2\x82\x7f\xa5\xad\xf1W\x1d\x96U\x13|\x1b\xea\x9bG\x8c\xf4\x14\xddkm#\x8f\x85u\xf8_\x92\x0d\xfcK\xb2\x81\x7fI6\xbf\xbddc\xbd7\xc0\x06Y\x9el8\xd4\x07\xcb\x80\xf8\xb0\x99\xff\xc8\xcb\x05\xd2z,:\xb1\x88&\xe8lop\xa9\xff\x9f(\x8e\x94\x1c\xd5?\x8dy\xef\xc6R9\n\x96\x85\x94\x8b\x0b\xceH5\x9am\xf8\xda\x81\x0b8A\x1a\x06\xfd(\xb8d\x91c\xea\x06h\x9c\xd6\x8e\xe4\xf7\x0e]}!>\xfeO\xc2\x93\xd9g\xf2\xe4\x86\xfa\xe6\x11\xff/\xb4\"\xcc8K\xad\xf1\xd4D|\xa9q\xe1PV11\xdb\x99\x89\x0bo\xc5\x87\x1a\x17\xce\xc4\x87\x1a\x17\x8e\xc4\x87\x12\x17\x9e\xc9\xc8G3\x11\xf9\xc8\xc4\x8fg\xbf=?^t\xe5\xc7\xb6\xb0EU*l\xe5\xb9W\"\xafz\x95\x98[}g\x92:\x0fl W$\x16+\x18$1\xa7\xcd\xc7\xab ^\xb6g0\x02\x8d\xcf\xb1A\x1c\xac-\xbaXP\\[\xab\xb0\xe8\xbf\x7fDL`&\xf4\xe3\xfc.\xc3\xbb\xee|H\x9d\x06S\x0fb\xc7\x1b\xa9\x1f\xdf*\x15\xca\x0d\xc8\xe3\xd7\xd2}\x94,M\x91tv\xe8\xbfY8\x08\xda\x14t\x8a\xab\xd0\xc9@B\xc1\x154\x93H\xcd\xe6\xdd\x1a\x80U@\x819\xa25 \x1d\x19\xe4 \xc9w\x96\x99\xc5b\xcd\\s:\xd3\xa0~\xec\xbe\xc3b\x9a7\xb3\xe3Y|P\x84\xfa\xe0\xbf,8\x0ee\xd9)3\xcaN\xc1?@vj6\xe2t1\xf6\xc4U\x00i\x83\xa5\xee\x87\xeeyW\x1bR\x88\x85\xbb\x9d\xd0\x07t\xd2\xcd\x91\xff4g\xeb\xa6\xabH[*Jy\xe0\xda\x8cO\x19\x15\xfe\x96d\xc8\x96\xa3\xf6\xa4do\xb2\x97\xa5\xc0\x19\x8b0\xcaY\xfaIH\xb7\xb77\xc3k?\x96(\xea\x80\xd8g\xef\x7fc\xee\xbfc\xe7r\xe5D\xd4]\xbc~\x94\xdfnXC\x8c\xd8\xa6\xc1\xcc\xbf\xcc`&;\x0c\xa6Q\x8f\xb0\xdd\xbf\xd8\xdd\x088K\xe2<\x08\x9b\x0e\xd9\xf7\xf66h\x95\xe4b\x87\xb5\xdfE\x92\xae\x1b;Nb\x8a\xf2\"o\xa5(6h\xebvS\xa6\xf6mI\x97Z\x16&\xe8t\xc2\xd9v\xba7[\xb1u\xd0z`\x18\xe3\xf2\xb6\xb4\xb5\xd3\xe9\xa6.\xc3\x8c\x81\x95d\x9a\xe6\x9a\x81vy\xad\xe5\xdeK\xf9\x08\xf5\x13\x8e.\x0bN\xea\x7fA\x00\xbd\xcc\xe3VK\xb5\x00P\x8e^\x0b\xfa\xf3\xc8:\x82\xack\xef\\e\xa6\xa3yi\xa3\xee\xac\xcdjR\x96m\xc8\xce\x0fX\xc6\xf1`\xfciC\x15\x1e!\x84H\x1d=B\xeaS*\x00\xc4\xba\xb8e\xeb\xf8'\x8d\xb5e\x0c|\x8b\xe7I\xdc\xe4\x97\xb1\x83\x97\x8as\x8cn\x1bh\n\x9bs\xa25o\x03 \x01\x94t\x18\xf0E 7\x9b%\x1b\xd6\x9f\xb3E\x83/\x87\xa5\x9bMq,q\xc6[\xc9 H\x19l36\x87<\x81e\x1a\xc49\x041\x04\x9bM\x14\x8a\x80\xd3\xf3p\xb1`)\x8bs\x88\xd8\x15\x8b2H\x16\x10\xccf,\xcbx\x95y\x90\x07\x90\xc4p\xc9VA\xb4\xe0\xdf\xf2\x15\x03\x16\xcfy\xa3\xe9\x00N\x82\xd9\n\x9e\xbd:\x85up\x0bs6\x8bx\x7fI\xcc Ia\x9d\xa4\x0cp2\xd9\xa0i\xf7\xf5Q\xf3\xa6R\xf6\xb7m\x98\xb2\x0c\xbbZ$Q\x94\\\x87\xf1R\xb6\x04Dg\x80b\xe1'1\xcb\xe06\xd9\xc25\x9f\x9a\x9ac\x9e\xc0\x19\xa5\xd1\x85\xb7\xa7\x03\x07\xe3\x03\xef\xc6\x81?\x8d\xfb~\xac\xbb\xd64J<\x9f\xcb\x91A2\x9f\x06%\xc5\xbe\xf0\xdb\xb6\xa6w`\x00\x92\xbd\xb5\x05\x8dA\x10oR\xa9\xda\x19\x04\xa7z\x9ft] \xeal\xa3\xa2\xe4b\xbf7\x1b\xd5\xef\xf2<\xc8\xa7?,\x96\xa8\x7f\xb6\x93\xa1\xffy\x17\xb6\xbe\xa8\xda\xdd\xa6T\x8b\xd0\xaaH\x0b\x9aUo2\x905\xeb\xdc\xbb9\xbaw\x93kC\xe5\xe3\xd1\x16\x1a(\xd8\xc1}^h\xdc\xc1&\xfc3\xbb\xe5\xc3hR\xa4#*|\x19d\xe1\xac\xad\xecL9\xd17+\xdb\xb9\xce\x9a\xcc\xda_v\x1db\x06\x93E\x13C\x9a\x05\x19\x031\x0fgl-\x06bh\xb6\x83\x8dV\xce\x02\x1d\xb5&\xe8\xae9AW\xed j\xfaJ\x87\xc8\x1c:+\xec\x10\xf9c'\x0d\x0dHF\x15\x1a\x9a=\x8d&4\xe8\xf6\xf2\xb9LY`9V\x05\xb5\xbf\x08z\x9f\xb1\xbd\xd1\xbf\xb6\xf7\xf7\xb9\xbd\x92U~\xf2\xcev\x928A\xedn\xf3\\|p\xde\xc6\xef\xe3\xe4:Vas4'nTB\xc1\xf1a\xd1\xf5v+t8\x0bo\x1b?\x8d\x1bz\xe0\xf4\x7f\xde\xae7V\x15\xcb\x90h\xe6\x7f\xf8 \xe8\xefR\xba\xfc\x97L\xf9\xbfD\xa6\xe4\x82V\xd2@HU\x1c\x00\xd7A;E\x93\xd0\x14\x17e\xd7,\xcb\x82%k*\x9d\x16\xa5\xb3d\x9b\xce\xac\x02\xd4\xe7\x92\x1e\xdd\xc6\x83\xb3\xb5\x85m\x05\xcc\xd3}\x1b1\x13\xe4\xea\xcfe0{\xbfL\x93m\xd4)\xd5\xe7\xfbm\x80\x1e\xf5\x07\x97\xe7\x1f\x16\x98\xbay\xa7\xa1t#\xaa\xc9\x95\x16t\x7f\xea;w\x8a\xd4\x10\x9c\xe0\xe14\x1c[z\x9c\xfa\x92\xdbX\xd8\xef\"\x94w\x1b\xdc\x83.(u0\xb2\x81\x12\x95\xba\x99\xc4@\x19\xe6\xda\xf7.\xc44\x8d\xcei\xbc\xd9\xe6m1v\x03*\xfb:\xb9n+\xb9\xa5\x92\xc7I\xa3\xb0\x08*\xff$\x1e\x19\x9fp\xc1\xac\xad\xfc\x8c\xca\xff\x18\xa4\xef\xe7\xc9ukX`\xcaB\xe9\xfc C\x9d\xbe\n\xf2U\x9bO\x0e\x08\x17\x96\\\x04W\x12\xa4\xa9\xb9\xc2\x1c Y\x10E8\x85\xcc\xf5v;\xf0\x92\x8fdo$\x11\xf3%9\x9d;\x1e\x9e\x7f}\xba\xe9\xa2\xdb9W\xcb\x19\xea\xean{\x99Y2g\xaaT\xa2\xe2\x04\xbb\x0e\x07B<\x07t\xfe\xff\xff\x0f\\2pz\x8e\xbd\xa5E\x9b\x11\x84\xa2#OU\x16\x19\xcd\xe7\xce\xf1!9\xb7V\xc6\xb4\xb6\x9bF\x87\x98\xd5}\xc3\xf5\xb2y\xd3\x19j\xd0\xb62\xad\xb7\xf4I\xf7\x19\xcb\xf5\x9a\xb3l\x96\x86\x9b\x1c\xa3^7\xcf\xe5\x93\xc7\xa4\x1f\xfc\n\xbd\xa8\xeb\xd6\x96w\xf5\x8b\x8d\xe24\xde}\x0ca\xfc\xd9#\xa0;\x13j\x14\x88\xeec\x07\xc1\xa4\xc1\xf1\xa04\x18\x07\xbe\xc1\x07\x1a\x9dB\xb6mC \xdb\xc0Dx\x8ep\xe5\xabE\xcd*L\x9e\xf2\x92\x06\xfel\x82%\xcf\x87yS\x98\x8a\xae\xde\x83\x9f\xe4g\"\x1fT\xcd[\x0f\xb2\xa1\xfd\xe4\x1d\xc0\xea\xefD\x9f:\x0b\x1a\xa6\x80\xa9\xa6\xc3\xec\xf2\x907m\x97\xd3u\xc1\xa2N\xbbK\xbb\xa67e\xdd\x85+\x91\xfa\x8e\x15\x97\xbcZN\xe3\xc8[6\x0f\xd2%\xcbi\xe3\xede\xe5\xdd\xb7\x8a\xbf<#\x91\xbcmg\x85\xc0ega6\xf6\xc5\no\xfd\x10\xd3L\x87\xadz\xfc\xbf|\n\x8a\xe7\x93\xac\xbe\xffd>\x05\xb0\x9bN\xde\xe9f)\x88\x9e\x7f\x83\xc4\xdc\x0b*\x186\x8cb\xdb%|\x05\xdf\xd1m\xab\xde\x11a\xa9f\x9d`&\xf3a\x0b\xc1w\xb0\xcdXj\xbfP#v\xbfK\xf6RR\xce\x1b4o\xa9\x9c7\xccS*\xe7p\xd4Bs\xe4\xa8m\x8a<\x7f>r\xf0\xb4\x9a\x19\x7f\xeb\x94\xa8\xffp=\xbf\x8bc\x06\x94\\HZ\x95\x0e\xbaM,\xf5\xfcX\xd3\xf39\xda\xd8\xd6\xbe\xbe\xf0\xffK\xb5\xfdv\xed}\x978\x93\xf0;\xd0\xf6\xa3O\xd3\xf6wS\xdf\x17\xbb\x99\x08\x0c\xda\xbe\"z\xedj\x7f\xf2\xab\xaa\xfduc\xa3\xfetP\xfb[N\xccH#\xb1GH,\xd4~\xe7\xdb \x0bg\xe5\xe8\x88\x8e\xbdj\xab\xce\xdb\xac\xc3\xa7]tx\xfb\xb0\xad:\xbc\xadJ\xd0\xb6\x14\xad6\x89O\xd7\xe1?yLU\xdd\xf5\xad\xe4yR}\xb5V\xac\xa8\xaf\x8e\x0f\x1b\xfc\x9f\xeb\xaf\x0d~e\xcd\xc3\xf9\x82\xfa\xabpC\x9f#q\xa7?[j\x10\xafw$\xde\xfe*\xfa\xf1\x17\xdb\xa8WA\x96]'\xe9|\xe7\x8d\xd2\xed\x0c\xbf\xde>\xed\xbe\xfa\xc16O8g\x8bX\xcew!f\xd7\xfd\x8d\x98c\xb7}\xebXZ@P\xc7\xd2\x9f\xb6\xcb_\xc4\n\xf2Y\xde{\xff$V\x10\xd3\x11yy\xc8\x8b\xdf\xbf\x15$\xd5\xac \xf6R \xda\xf7;\x18I\xd2\x16\x99\x8d\x1c\x9b)\xb5\x176gf\xe0\xc14<\xe7\xb2\x85\xaf\x9b@\x9a\xe4V\x94q\x03\xf3n\xa2\xe5\x84Y\xa3\x0b\x94w\xf5\x9f\xc9\xc7aa\x8d\x1b\xb2\xb0\xf98,l>\x0e\x0b\x9b\x8f\xc3\xc2\xe6\xe3\xb0\xb0\xf98,\xc8\xb2R\xfe\xc0\x05Yw!M,\xfc\x8fGw\x1fxf#\xcb\xe2\xb77\xb2l\xbe\xa4\x91\xe5\xf7\xe6\xf80\xff]:>\x04\x9d\x14\xee\x85*\xd9A\xc3\xe3\xbb8\xe3 B\x17\xf8\xb3\x06\xc5\x07\xa3\x98\x0c\x8a\x04d\xae\xd0\xc8\xed5\xae`Bb\xf7\x86$\\%j\xb5f\x16]Wj\xce\xa2\x90\xc5\xf9\xa9H&\xba\x1a\xc8\xdfm\xed,\x8d\xed\x9c\xb1Y\xca\xf2r[\xf4\xae\xad\xbd\xdbJ{R\xacx\x8379\xb0\xb6\xc8Q\xd8\xbfL\xe6\xb7\xceg\xbb\xa7\x04\x9b\x0d\x9d\xb5\xad\x06\xe2O\xfb\xe0\xbe\x84+\x0b]\xdb\x1c\xc3\xf4\xbc\x01\x14\xc5\xe27\xa6\xdb\xd4W\xb51\xb9favkH\xea(\xd7y\xdc\xb8;\xfan\x8c\xe1\xd6X\xee\x1f\xe0\x8e\xf3\xab\x18\x9b\x9a%\xbd\xaeaU@\x85Vi\xa3?\x00\xbbEV\x81]\xa3\xab\xc0\x8e\x11V@\xb0\xe1\xbc\x83\xcdkKS\xec\x96/\x05\x8a0+\x9d\x8c^\"\xa9I\x07\xa3\xd7\x82Jv0zm\xba\x86y\x01\xe9J\xb2\x83\x85lE\xe5w\xb3\x90]Q\xa5\xae\x16\xb25\x9e\x1b\x84\xd9\xcbgg\x87\xcd%9\x89^\xbb^-\xfe\xe01\xd7c1\xea ^o\xc7\x9f\xcd-\xdd\x16-\x11\xf59N\xd9\x9c\xc5y\x18D\x19\xb5T\\\xa4oi\xea\xff\xb2\xf7\xef\xebm\x1b\xc9\xa28\xfa\xffz\x8a\x12fN\x06\x1c\x93\xb0(\xdf\x99(>\x89-\xef8c\xc7\xde\x96\x9d\xcc\xda\x1ao} \xd0$\x11\x83\x00\x02\x80\x944\x89\xdfe?\xcbz\xb2\xdf\xd7\xd5\xdd\xb8\xf6\x0d\x94l\xcb\x19c\xd6r(\xa0\x80\xbeUW\xd7\xbd\xe6\x98\x04\x06I\xfc\"6/\xeci\x0d\x8eu*I\xc8\xe2\xf9\xd9\x91\xc0\x9f\x14\xfc\x96\xfeSg\x98)\xba\x9d\xb9\x07\xdf\xf7\x0d/\x1e\xa1\x15\xe6Cj\x16\xe5\xc2\x82\xb8t9u\x80W\xc5\xdf;\xbaT\xa7\x9c\xad\x1fG![\xbff\x88\xbf\x08\x040\xf4\x0fsC\xe8;y\\/dK\x1dgT\x9a^\x99\xaf\x94?\x06\x07\xdc\x17\xdfm\xca\xd5\xc1\x18\xe8\xed\x16\x1a\x823\xd2\xb9\xbc\xacL\xca\x02\xbd\x0e\xd57\xe8P\xcb\xba\xca4\xe7Ft\x1e/\xab;\x0d\x9dj\xbd\xf5\xd0g\xa7\xff\xa5J\x9b\xc8\xde8\xd6\xb9\\mM\xc3\x14\xaaU\xd9Zj\x868\x86\xb3\x1d=\xbd\\'Z\xd3\x11F%\xc3\xcc9\xdd\xf8s\xfc\xb9\x1ci\xbf\x99\xf5?\xc9R}\xbcy\xf5l\x80{SRo\xd8\xea\x13o\xf2\x98\xe5F\xa9\x19\xd5~\xef\xea\x9f\x17\xd6\x1d}\x9d\xbe#\xac\x83\xd6\xfds\x1a\xb8\\\xd2\xd7\xab\xcei\x1b\xd4/s3F\x077\x88zm\xc7\xe0<\x89\xd3\xb3\xe13\xca6\x1e\xfa\"\xd6\x93\xb8\x87\x93\xf8\x10!5\x0e\\\x81i\xe7\x1b\x01*=\xb0~\"V\xe5:~\x82AB\x98\x01\xe5\xb4\x92\xb4\xb4\x13\xb2ij\xff\xcf\x068\xaf\xb57pe\xf9\x12;X\xf5\x19\xa3E\xa4\xf4\xe71\x15\x17\xa6\x9a\xf8y@UE\xf1\xaeL3\n\xa8\x1b\xa0r8\x11\xf2u\xa6\xdeDa\x7f>\x0dl\xb7\xb5\xb9\xc2 \xfd\xd2\x9f\xe0'/a\x83@\xfe\xd4JE\xfd\xb1\x11\xb0\xda*Z\x04\xcc\x9aV\x8d!\x08h\xe3=\xf9\xf9b\x9b\xa5\xb1b\x98i\xa3\x8dq\x96/}\x16\x18'\xc6r\x8a\xf94\xb4\x08\x87S6\x14\xd9\xda\xd4\xae\xa9d\xf8|(^\x81r\xafqR\x11 \xdb\xf3\xb9\x0bV\xbd6\xbf\xb8\x1bfiF\x98f\xdc\xbf@?B\xaeoi\xab\xe9\xb48\xf3\x8aA\x02B\xea\xf8\x95\x81=`i=\xb4M\xd7\x0e\x14W\xd9\xf0o\x1b\x92\x1b\xc6\xfc\xbf)\x08d~\xee\xafII\xf2\x02}\xe6)#\xc99E\xd4t\xaa9^|\xdce9\xbf\xfaJ\x8c\x19\xd9'\xc5\x96B\x1e\xd4\xdd;\xa3\x9f@f\xbc\x01'\x14\x8fZ>\xf5\xea\xe9\x0bk\xf642\x1cf\x15\xd8`\x02\xf3g=\xcd\xea\x89\xb3:\xc8,\xd8\xa6\x86\x9fA\x07\xbd\x0c\xda+\x86\xfa\x12\\\x1aB\xde*+\xc4\x87 m\xbd\xfduE{\xe9\xa3\xef\x93\x82YWl\xf6\n\x03\xfd\xb2_\xda\xfb\x85O\xe0n\x18\xcd,.W\xb5\xdfd\xf8\x7fl\xd3\xbdK\xec\x81=$\xfb\xa7\xf8\x8fe:W{-\x01W\xc2\xee\xb4\x92\x98\x9d\x9d\xe3 \xd3\xef\"\xe6\x9e\x0e\xcb^\x0df\xa5\xa1\xd1\x13\x12\xacS:]j\xe2\xa03y\xc1\x8a\x04\xef\xe6\xa9\xa2 \xb8\xb84\xadZEt1\x9cc^\xdfV\xe9\xc3\xe8\xdea9\xa2\x1c\xb8\x01s\xfc%\xba\x8a\xb7\x84\xfb\x8c\xd9PD\xaf0*(i\x08gpf\x06\xe6[\xa9\x9a\x19\xf3\x1b\xf5\xce ^\x9a \x1e\x19\xb6\x05p\xdd\xe4% 54\x89\xb5\xf5|\xed\xba\xd4\"\x9d\x8a\xb9OM\x0c\x8bJ]~\x170M\xc4.H\x8dTp\xe7Q\x9au\x94\xd0iO\xaf\x96\x03\xd6^r9\xbd(t\xdal\xea\xbfMM\x97\xf2\xb2\xd4\x15\x84$\xb5\xef\x18\x8e\xae\xc2\x03R5\xe0\xd0f\xb8\x1f\xcf\x03\xf2\x92\xf87<\xeb=\xb0\x859G\xc9H\xc7'eC\xda\xd6&\x887\x1e\xee\xbd\x0c\xf8\xba\x9e\xdb$\xc0\xff4}\xaf\xde\xd2v\xbf\x91\x15_\xb3\xfa\x97\x1d\x81Ej|\x18\x90\x1e\x1fx\xe7\xab\x14\xf9R(K\xc7\xddz\xcc*\xc7\xdd\xf0\n\x1cw{\xe5\x95\x94\x94\xa3\x94\x94W\"\xbb\x97Wj\xe3\x82i$\xc0GS\xd6n\xc3\xea%\x1b\\\x04\x8b\xe4\xb9\x112\xad\x1dq\xd0\x15O\x0d\x19\x0dq\xc1\xf1\xe1\x10R]\xe2\x92\x8d\x88\xf4\xac\\\x00\x15\x0en^\x10\x13?\xd7\xf8\x1f3\xc7\x82\x19\xe8Y2\xce]\xf9\xfa\x82\x1c\xc2\xd8\xcb\xe0\xe4h\xce\xbd\xb6\x02\x81\xc7#C\xdffU\xa4\xba\x16\x8c\xaf\x94\x96M\xad\x17T\x9b{6`S\xaa\xcd\x7fK\x9b|$\xe06\x8a\x91*\x11\xbc\xc5mZm3\xe1\x1covw\xcf\xd1q\x02\xb9H\x9doj\x8a`\x94\xc1/D\n\x019\x06E\x0bp\xb1\xcc\xf4d\xca==\x18K\xca\xcbJDIH\xce_,\xdctd\xf2\x97\x8b\xa0\xf72\xaf\xa0{\x92\xbe\xd5\xf8uXy\xd1C\xc3crx\x15\x1d qA`/g\x1e\xda\x8a\xf1\xc1\xb7t\n\x18\x84\xb9C\xa23\x9d\xcf\x0dv\xba\xa9\x9c\xc7\xf7\xb4\x89\x84\x94\xf5\x8148\xd8P\x04\\1\x0e\xb6\x91KOY0\xaa\xd5\x14\x9e\xe1\xcbsX\xa4cPE\xdf7\x16\xc9WO\x02\xe3\x98\xacF\xdf?\xe8\xd4\x1e\xe9\x89\xcdy\xc46\xaa\xd5y\xc4\xe6\xd3\xe6_\xfb\xe7\xca\xbf\xbe\xf2\xb2M\xb1r\x9d\x9c\x14Y\x9a\x14\x04\xed\xca\x87\xa8\xd3WP3E\xde|\xd6^ev\x1c\xd2\x1a\xba\x9c\xed\xd4\\\xdf\x95\xf8C\xcca\xcf\xf3y\xc8\xe0\xd8T\xb6^hS0\x87R\xa0d\xe9\xc0\xe1!\x92\xd1t\xc1\xa2X\xc4\xe7*C\xdd!\xaa\xff\x12\xfa\xc17\xaf\x9eV\xb2\x9e\x9bu\x03\xa5(A\xd9b.\x03Vr\xeb\x15 \xa3\x9c\x04\xe5\x9bZ\x9f\xd1\x13\xe8t\x0c+\xfe\xd1\xaf\x9c\xd1[\xf6\x93\x8bS\xa7\x95\x84\xe1\x8b\"9\xa6@\xb09\x8b\xe5\xd4\x19\x89\xba\x06\xa2y\x99Lp\xee \xcd\xe6q\x1a\xbc\xc3\x12\xeey\x1a\x9f\x9e\xceK]\x08c\xdbF\xc4\xff\x92B3\x0b\x11\xf1sI\\\x94\xb1\xde\x89\xa9\xce\xc9\xf5\xcc\xa1\x8aD_\x9a\x03\xe4Z\xd69\x19\xb3\x1f\x07X\x15\xd9\xbd\xf7y\x9c\x05\xd0\xd29\xad\x88\x1f\x92\\b\xf53\xed\x19\xbb\xe0\xc9F\x98\xa1\xa0=\xc0\x9b\xd4\x17\xb2\xce\x1b\xd9\xc1\xbb\x12L{\x81\xcc\xc9N\xea\xd1\x86\\d\xfc(\xc3e\xae\xe9\xa2I\xfb\xe1\x8e\xc1\x81u\xe1\xe8G\x1d\x1aGm8\xf3\xa1M\xa0%Y^\xc6;gr\xb1\xa9\xa7\x06=*\x06W\x9c\xdb\xa1X\xa5\x9b8\xac\x08\xe1\x9b,\xf4K\xdb|\xac6\x15\xcd\xeb$\x0e\x9e\xd0\xf9\xa0tI\xea?\xff\xf8\xa3 E\x0fq\x0e\x81?\xdbO\xd9\xf1\xcd\x9f\xf3?\xda\x10aTd\xb1\x7f\xc11\xeb\xb1P\x7f\xb07\xe4\x0f\xa5c\xf8\xdcR\xb2\x8a\xe9\xd4\xc3\x0eM\xca\x9a\xd6\xf0\x06C=T\xd5\x8e\xe5\x93\xac\x7f\xd3\xafx=\x0b3?T\xcax=\xc7\x07\xfc\xc8\x12\x98\xa2\x87\x0c\x98\xf3\x00\xba\\<\xdfPi8\x14\xe4\xe9!\xf8\xde\xbau\xebI\x9a\xbb\x9b1\x14#\x98\x81\xef\xe5\x9d\x9b\xfa\x86B\xa8\n(S\xa1{cL\xa9\xb0\xa2\xa7+\xcf@$\xd7\x974\xafm\xfd\xf9\xea\x10\xf1\xca\xf4\xc7cSE\x97u\xfdb\x92\x96\x8f\xd3\x00I\x12\x86\x87k\xdf[\xd6\xef\x11\x9b\xf4\x1d\x175<\xfa.\x1a\xc0\xe75x\xe3\x98\xd0\xber\xda\xb7{n-\xd2VlO\x1c\xca\x9f\x92\xa4\x9c`\xe4\xd8[JZ\xb6'\xce#~\x13\xa3\xc24y\x85\x80\xeb\x94\x12\xd7 ,\x16\xea\x9c\x81\x8a\x8d\xfb=\x0b\xcf\xd2\xber\x0c\x87]wm\xa3)\x1c,\x0enk_W\xe8p\xf9\x0c\xc3\xe2\xc8\xe8\xf5%.\xa4\x95z\xa7\\\xe0l=8\x98\xe3\xcc\xc1\x90\xf7\xed y\xcb\xa2\x15\xb5\xef\x9a\x92x<\xa2\xe24\x1e\x06\xc7\\\xe0\x96\x8b\x82`1iMn'\xd0E\xaa\x1c\x99f\x96\xd3\x0fm\xe2\xf6\xd1\x18V\xda\xf4\x06v\xcc\xd7\xed>\xf3\xf5\xe6\xd53-\xdf5\xd4)TD&\xd2-\xa0\x1e\x8f%\xa3\xb7\xd2\xa7Xh\x8e\xe7\x98\xe4[\x92\x83\xd8O\xda1a\xf0\xcc\xc0Q\xb1\xcf\x16\x13\xf6\xeeN#+\xe9~1\xafR\x99\xef\xd85\xb6\x1dw\xec[8\xa8\xd1 \x8d!H\xe3S\xd6d5\xeb\x13z\x8f\x1fk\xban8h$\xd4.\xd1\xd5\xf5\xc7\xca}\x9cv\xea1)\xfd(.\x0cy=J\x8c\xa4\xfdP\xab\xf8\xd1Vo\xe8\x92\x85cX_e(S\xd5\xfe& kfc\xa7\xd1G\x8d\xe0\xba7\x8d\xaf\x81S\xf9\xf8_1\xaa\xed\x84_K\xdd\xf4\xb5\xca\xf7\xb6\n\x8e\xc1\x0d<\x04\xe1\x86\xb8]\x95\x99\xae\x03\x18.4\x9f>7\x0e\x8e183\xb80\xb0\xc8\x0c\x8e\xa5'4\x04\x17m\xf2x\x06\x06\xe6\x9c\xf3\xa7\xda\xcc\x89\xf4j\xca+\xba\x98\xb1\xf7\xf5|<\xd2\xcc\x871\xb4\xb2\xea\xd7\xb1MS\x11=\x96\xe7\x97 k\x10|\xed\x0c\xe6\xe6\x06\xd5\xe1-\x97\xf0\x85\x97\xeb?C\xbc{\xdd\xf4\x9f+\xa5\xfe\x13\x9f\xf4\xb4\x96\x91x\"S\x80\xaed\x9a\xd1\x0d\x7f\xd0\xd3\x8c\x16\xfcA\xaf\x8d\x98?\xe8iF\x03\xfe\xa0\x97\x1dy!\x1a\xdf\x7f\xd0}\x94Q\xf1e%\xb4\xa7h}\xec@\x84\xa2\x83\x8a\x9aU\xab\x8f\xafO\xdd\xda\xda\xd6T\xa9\x94\xa5&*\x99\xfd\xac\x99B\xb9\xb0Q\xbcEm\xc5\x9bE\ne\xac\xd0\\\xc7]\xbc\xc9\xe3!\x96-\x9eU\xb9\xad\xce\x90\xcb\x19\xc2LG\xce`!z\xe9\x12o\x93\xc7.\xe6\xe5\x17;5N\x99\xa3\x00\x95\xe4\x99;\x87+\xd1\x14\xca\xe7*\xe5s\xd5\xd4\xe3\x8c\xdc\x91\xc7\x1d\x8f\xd2\xbc\xe7\xf3\x04`\x9d\xe3\x17\xc9|\x7f\xbaT\xba\x86f\x9b\xb3\xa6\xabd\n\x0f\xc1Y\x95eV\xccn\xdeL\x13*Q\n\xbf\x06/JoV\xef9 \xab\xaa\xd7K\x8a\xab\xb4\xb1\xc5\x0d\\\xa8\x15\xa6m\xcb\x9b\xd2\xc6\x16\x08z\xf9K\x14\xc7\xafH@\xa2-\xd2\xb6\xc2\xc2\xec\xa6\x94\xd3\x85\xe2}\xf8\x12\x81\x88;\xb2p\xac\xc7uB`\xdb\xa5\x02\xddr\x95\x03\x96K\x1eZ'\xf3\xb1o/\xa1\xec\xd4\xbc\"[\xa7\xd8\xa9t\xce\x1b\xba\xe3\xf6\xe4\xd3\xed\xab\x9e\x1a\xb1d\x99W\xf8t.\xffM\xde\xe41\xa3Bu\xb1\x83j\xf2TqF^\xb0\xc9s\x92\x94OXj\x08s\x85\x93-%I{\xcc\xf9\x03\x7f\xbb\x1b,4\x97f\x05\xff\xc6f\x0c\x18\x9f\x88~\x16{Q\xf1\x93\xff\x93\xbbB\xfd\xca\x8a)0\xc4K\x1b\xaf\x88\xa3\x80\xd0M\xb2\xd2U\xc9m\xf9dlzy\xc5|\x13\x9fDw\xc3F \x87\xeb\xa4\xd5:\xea\n\xba@=dU\xbf\xac\x12\x92\xb1\x9d]\xb5\x89\x89\xf5\x0c\xf5\xb5\x00\xb5 \xcb\x17\xf3_\xad\x12\x99\x95\xfeR\x9b-F\\\x9d\xdd\xa7\xcdB\xd3~\xa7\xca[\x93\x9a\xdf\xa8\xf7\x9f6\x8bC\x0b\xdc\xc2& \x8c\xe7\xe8\xae\xbei\xe9\xa1!,\xf0\xe5\xcf|L\xa3m|\x0d*\xb2\xc5\x8d\xc5\xe5*5:\xf1\x89+\xc5@M\x816\xcf\xa2\x82\x9e\x8b\xb4ez\x98&c\xc8u9g\xc4\xc5\xd1\x8f\xc7j\xba%\xaf\xa3\x85\xa5\xad2\x98\xc1bTi \xf3Q\xad\x16\xdc\xb9\xb0\xba\xb8XJ\xd1*3\xa4\x05\x9a\xd0\x8b\x9e\x1e/\xb1\xac\x90\x05\x96\xd0+\xcd\xac\xd0\x1b\xaarE\x169@\x01\x83\xb9\xe9JY\xa17T\xdb\xc7\x08\xaa\x91\x8c\xd8\xe3F>D%d\x13\x8a\"3\xa6\xb5\xfd\x06\xa6\xbaB\xde\xab[\x0d\xaf\x8c\x9fR\xa8\xc9\x17p\x856D \xce\xfe^]8\xe9R\x96mYy\xe6\xcf\xc9\xb2-\xad\xe1\x9b\xaaj\xf8F\xaa\x1a\xbe\xbe\xaa\x86\xefFU\xc3\xb7P\xd5\xf0\x8d{5|Y \xcf\x82K\x05m\xe8@\x04\xcb~\x16%~\x0d\\\xfb\xa7\xe4\xd8\xafi\x88\xe0\x10\xee\x9cq\xe6\x8c\x1bPC%\x02J\x0d\xc2\x8e\xb2`\x15\xc5aN4\x944\x1d\xc6\xa9GC\xb8t\xdf\x9aC\xdf\x0c\x90/\xb0p\xb2\x8e%_\xb0\xc38\x0d\x8e\xce3?)\xb4Q\x14\x19?\xb8I\xf6,J\xdeE\x89fFCQ\x04\xd8Y\xf8qAX\n\xfeL\x0dO\xb9\xf4\x0d\x96\xfd\x8c\xfd\x0c\x1dk\x95\xa0[\x06jSes\xcd@\x1f\xf3\x1e\xeb@\x97\x0c\xd4\x04V\x05\x164\xa1\x1aJ1\x9cb\xab\xb7\x15\xb5r\xc8\xe7yz\xa6\x19\xdcY\x14R\xd2\xe0\x1c\xec\xeb\xbccH\xb4\\\x95\x0cjpo7\x85>\x14\x88\xed\x08\\\xab\xbf\xc4\x14\xcf&\xd8\xe7 r8t\xa9\x9aw5\x9d<\x8f\xa3\xe4\xdd\x0f\x83>\xa6\"6:\xad\xa3\xb6\x86rT\xbc\xc8HB \xf6\x91j\x9er\xa3\xf9@\x92JC'xg\xe2)\x1a\xe6{\xce'BcX\xab\x9d\x16y\xba\xfe\xf1\xd8\xfd\xbd\x1b\xcd\x87\x1a\x0f\xa7\x9e\x94\xf7\xe3k\x97\xd0\xb4/\xd4g*\xa1>S \xf5\x99J\xa8\xcfTB}6,GS\xe6vc\x94\xa9\xe4\xeef:\x97\xf3\x05~\xed^sY\xb96@&\xecg\x1f_\xd8\xd7\x9b\xe9\xbe\x08\xfb\xe2\xfap\xc2\xbeP\xa4\xaa\xe1r\xcbT\x05)\x87\xc3@R\x0dc\xc9\xb4\x07\xe9r\x19\x13d1\xd5\xa0L\x82O\x93\xd79\x15\xf8\xf1\xb8T\x03o8\xf0#? Hl\x00.8\xf0\xd19 6\xba|\xfb\x0b\xa3\xe1.\x1b\xa0<\x08\xadU\x12\xabjq\x8cz\x8e\xed\x10s\xea\x1a\x81\xad2q/+P\x8b\xef^\xb0 \xf5\x8b[\xc6\xef\xce+P\x8b\xef\x9e\xb6\xdd\xce*\xc6J\xc3z`\xb8\xbd)w\x02\x15\x9f\xcf\xbc\x90d9 \xfcRW=\xe0\x1c!\xb98\xa4\x06;F0}n\x8bG\x08c\xcak\xf1\x0e\xa1R\x8dn\xe7;\x84\xd0*\xe0^\xf0\x8f\xf0\xe9\xd2\x95\x9c|\x89\xa0~\x1c\xa7g\xaf\xf3\x8b\xa7\xe5\x8b\x8d\x06\x83_\xb3y\x1b\x98-\xe49\xeb0\xff\xfa\x11\x13?\xd5\xe0O\x11\x9c\xb0\xbd\xf94y\x99\xa7\xcb\x9c\x14\x1a,\xf9\x15\x0e\xe1\x9d\xd7P\xea\xa8A\x7fB\xd0\xa6\xeeF\x0d\xfb\na1\xdd\xb7,\xa3\xb7\xb8\x1e#\xc6 %Q\x9ai\xb5@\xcf\xe0\x10\x1e3#_\x15\x02\xae\xd3\x8f\xbd\xa9\xe1\xb3<\x0d7\x81\x1e\xfc7\xee\x8f\x8c\xa9G\x9eEE9r\x1f\x8f\xe1\xc4iT\xd5\xd5\xf5\xee \x1c\xc2\xb6F\x9bc\x1c\xba{<\x86G\x9a\x97\xfe\xddQl9c\xf8n\x0c/4\xca\xab\xef\x9b\xbd<:/ \xeaI\x8b\x91\xfbX\xd3\xcc\xcf\xc8\x04\xd9\xcd\xda\x0f\x0c\xb6YKX\x0d\xfc\x0b\x03\xe6\xf8\xa6\x83\xfc\x91A\x06,w\x9d\x1a\xee\xbf\x19\x9c\x8d\xf2\xf5\x1f\x0c\xd4F\xf9\xfa\xbf\x18(\xc7G\x1d\xe4_\x19d\xe5\xd5\xc1\xb2,h_\xf9?\x9dW\x8e\xf4I^\xfe\xd9ma\xb3^\xfb\xb96\x17\xca\xfff\xaf\x98\x14\xc2\x84\xf2/!\xcf\xe9S\xe3\x86\xda\xa5\xf7\x19f\x8fe)d\xd1\xc4\xf9-\xec\x9b\xdc\x95\xd0\x9d~\xef\x19\xee+\x1e\x9a\x97{\xad\xec>,F\x87\x838\x9c{\xd3\xb9p\xe4\xe8\xe0R\xf43\xf1\x8c\xa1$\xb6\x16R\x10\x1e\x04\xb4\x7f't\xdfI\xd2\x84\x02\xd8\xe69\xb1\x12\xe6\x9b\xaa\xdb*\xe7c}2R\xf9\xf6\\\x06\xe2\xc0\x0dx\x047\xc0\x91\xe9x\xdbP\xea\xd5\x8e\xc2\x99F\x03\xfe\xefZ\x01\xaa\xd4\x80\xaa\xa6\xe0\x9fZ-\xb1\xc0[\x94ngp\xaa\xeea\x83S\xd5\xfa\x98\xb4}K4\xa7w\xab\x84\xd3Z\x0f\xd7\xf0\x9f\xd1\x1c\xf6\xb53\x84\xca!W=M\xffm\xa7x8\x1f:\xfdC0\xb0R\x8d\xab\xeb\xe2\xbf\x1f\xc3c\xba!\x1f\xb3-\xfe\xc7\x1f\xcc\xff\xe4\xf0\xf0\x10\x1e\xd7\xce(\xea\\\x13\x06?\xe8J\x15u\xeb \xd3\xd5S\x15z-\x03\x18\xbaU'\xee\xed\xe9TC\xe8d\x13\x10\xa7~\x18%\xcb\x89\x9fDk_c\x1f\x19\x8d\xe1H\x9bX\xc8`%\x91\xb5\x8d\xea\xcd\xd3$\xcd\xd7\xbe\"\x07\x10&x\xfa\xc5\xcf\x93(Y\xce\xe0qM\"Fc\xf8\xd5\"\xcf\xd1\xb0\xfe4\xd89}\xa9\xca\xab\xc6Bcf\x10M\x83\xff\xb01G\xfc\xaaX\xd4\xd1h\x0c?\xd1y\xfc \xc3=/\x91\xb6E6,\xc1\xf3N\xc24(v\x9f\xd1\x0f\x86YO\xa2$\x84u\x9a\x13\x08EF\x9f+^\xd8\xd6\x0c\x0c\x1f\xb91\xd0\xd5\xd8\xe6\xa99\xeb\xcceq\xeb\xa7\xa6\x18\xa4\xc23u\x1b\xff[\xd7\x86}\xb0\xac\xc5L\xc4\x91\xf6\x0bJ\x8b\xd6O\xda\xe8X\xf6\xb4\x91c\xa7yj\xa87\xd4\x0f\xbaa\xd7R\xc4\x0c~\xb3:\x85yA\x10;\xf1\xa3\xe2Ef\xf0X\x03\xc5+x\xff\x03\xdd%uj\xb8\xa6\xbaL\xeb\xaa\xdb\xd2\x95I\xeb]\x89\xab#\xb9\xcf\xe0\xb9\x86mi*\x12f\xf0R\x0d\xb9H\xa4Ev\xc4e\xcdP5\xb4d\xda\xecE-\x15\x996\x7fQ\xe6\x97\xab\xe7\xdc\xb1\x93q\xe1\x86nr\x17\xe4P\xb1\xe1*l|\xae\xc1\xc1\xbf\xeap\xd0z2\x98M\xfeX\x0d \x1cV5Ly\xda\x91\x1bgB\x03Q\x98\xe5H\xda~\xf5\xda\x16\x15b\x85;\x12\xda\x91\xe31T\x1f\xd1\xe9!\x96\x84\xbb\x83\x91\x90}l\x06s\xafh\xdd\xd1\xacs\xff\xe5\x0b\xafw\xd3\xf0>\x05\xf9\xd9\xcf#\x8a\xf0?3\xed;\xffH\xef\x89a\x18Mx6\x8ca_8Z,HPF[\">\x85\x9d\x11\xdf\xa9\x9e\xe2}3\xfe}\xf5\x15\xbc\xa4\xff\xbc\xc2\x7fLtq\xa7cV((T4Z\xd5\xd8\xff\xd2\x9eo\xec\xa33x\xf5aq\xdf\x96\x98\xf0H\x16\xa6!\x9b\xc1\x13\xc5\xcc\xd7S\x7f\x15S\xfc\xbcRu\xbc\xa4\x12\xf9\xbcL&\xcb<\xddd(ys\xfd\x95\x91\xb3{.\xdeW\xf5\xe8\x17+\xc9Y{Z\xd9\xce\xe20\x92|\xd9\xb5\xad\xec=3(\xacvJn\x9a\xaa\x1f\xb5(k9 \xf6C\xd3wz4\x86\xa7W\xb5\x97\x85 \x1aT\xc1dCw\xf3.\xcd)]'\xaaey\xa6\x19\xe0\xcf\xba\xd6*\xb5\xf1\x0c\x9e\xa9g\xbaJ\xea\xab\x89*\x11\xcc\x90(\xfb\xa0\x8d\xfd\xb0>\xb7[l\xc4Ul\x98\x86-N\x9b#\xd2\x1aK\xb9\xf5a\x06o\xcc@\xfc\x90\xda\x8a\x80\xbf\x97\xfc\xfe\x934w\x19C\xa59\xfc\xfb\x8c\xb4\x95\xce\xdf~\x1b\xa9A\xe4\x86\xad\x19\xbcV\xbf\x82\\\xac\x89\x9a\x10\xf4\xa0\xf8\xdet\xdc\xfe\x1f\x1d\x06\x93J\x17>\x83\xef\xad1\xce@2vq\x1bz\xb9\xc9\x89\xcce\xa8\xca|'w\x19j\x9c\x1c8)\xad\x87y\xb5\x99d\xcf\xf8\xa6\xec?\xaaQ\x85J\x8a\x0b\x8fY\xbc\xba>5\xcc6\xa1\xf3B\xfa\x12Z\xd4\x9e1\xa5\x17\xd2B\xee\x85\xb4\xa8\xbd\x90\xee5S\x19-4\xeeF_b\x8b\xfe\x03\xdd\x8d\xac\xfc~\x86\xc4\xfb\xe7\xf6\x0e-\xe9\x10\x87\x16\xe6\xa6\xd4\xb6\x13\xa9\xa1}K_\xaa\x0d\xd6\xd039\xa7\x14,\\\x9d\x91-5X\x80`QQ\x95=\xd5\xf0\x0d\x0b\x845\xb9\x9ed\x08\xa5s= Y\xd7V\xe9\xd9\xb1\xa9{+\xfe1\x0b\x17\x94-\x03\xcd\xa3e\x94\xf8\xf1\x0b\x9bW0\x12I8\xa2X\xbd\xb1\x84C\xc8\xcc\xb3z\x81K\xc4\xd5\x1d\xc1&\x8fJ\xadU{\xce\x12(Tu`\xab\xae|_j\x8d\xf9\xa7\x9d\xc4\x0b|:\x9f\x1b\x03\xbf\xcf\xe4/\xbe4\x04\x9a\xf3\x1a'?n\xd6\xd9\xeb\x14\x811;\xc4\x07\xb7.\xd7Z\x01\xd6O\xe8\xfc\x8d\x06b\x8d\x16\xb0\xae*(\x05\xd1\x08 \xa7\xba\x1e\n^P\xc5\xb9\xa9?{f\xaf\xa6\xd3\x05>v\x0c\xd0\x1a\xc3r\xcd\xe3\xc8\xe3\xc6ig\xc3\xab\x92\xfb\xba\xabcc\xafX\xd2\x83\xad\xa8\x99],\x8a\xedn\xe9\xdd\xd5\xc8\"{\xfen=\xab\x93\\D\x8a\x02\x04\xef\xc7 :Qg\xdc\xff\xea+\xb8\xf0\x82t\x93\x94\xae\xaeos\xbdY\xbc&\xb93\xd0d\xcc\x1a\x1e\xe3!N\xd4\x941\x94\x98\xef\x97JMT\"\x89r\xec[\xe1^\x982\x89 \x81\xae\x13\x06\x17\xae\xc2\x01\x05z\xacEu\xd7\xac\xb8\xd2V\xc8\xc9\xb4\x08{\x85B\x87!N\xa1\xbb\xcfL\"D\xb0\xb3\x08q=\x03\x19>i\xa6\xb2\x01\xc5\xa6?\xa32\xa3_\xc4\x04q\xed.&hK:\x9b\xb8\x8fK\x1d\x1b<\xb3\x8e\xf4\xdd\xf7c\x94P\xded\x19\xc9\x1f\xf9\x05\x91%W\xd9\x99P-\x86\x13\xaa\xfa\xbb\xe3\xcf\xa0\xc4\xf1g\xaa\xad\x10\x91S_\x94\x16\xff\xb1\xd4H\xcd\xc0\x95\x034\x11\x89Dc`\x14\xf5\xe9\xc6I\xac\xe2PR\x844\xc6\xa1D\x08\xa6\x8fC\xf1\x11F\x1b?\x82u\xf1\xed\x84\xf7\x82w\xecq\x9d\xc6\xc4\x18\xe1AO\xd8\xb2\x99G\xe4\xc3\x9f\x04y3'\x838\x0d\xe8<\x9d\x9e\xb6\x9d\x9d\xa5@\x83\xcd_\xdazUU\x02\x06\x9d\x02J$`\xd0\x98\xa2\xb2\x06\xdf\xca\x9ao\xfbO\xfbXy\x80J\xd8\x1b\x0d\x0e\xb2,\x0d\x91|\x84Wy\x04^7v\x99\x9e\xaa\xcd\x80\x078\xe4\xe5R\xfa\x87[D\xcf\x84\xfb\xb2\xd3-\xea\x96\xd0\x8f\xd8\xe9\";=\xa2\x8f\x7fz\xf8\x98\xc1\xa63J\xf5q\xb2\xad*\xca\xd7\xe6\xa6>\xe6$\xed\xd27b\xa5\xdb\xe1#\xaf\xd2\xb3\xee\xbe\xe6\x83M\x87j*\xa4\x0c\x9d,\x81\xcc\xfb\xf1\x95~\\Z\x9bS\xd7F\xb3\xb4i\x1d\xbb\xe2P^\xe3R\xfd\xc2\xf2\xa5*c\xbc\xaeC\xa2f*\xeb\x93\x1a\xacU\xe3T\x0d\x96[\xc0\xc8\xeb2\xaa\xcb~\xf6\x06\xe3<\x89H\x8cN\xe5\x1f\xb2\x114Q\xb3\xa2\xa1\xeafZECK\x8f$e~qL~\xc3\xec\xb7\xa6\xcc\xa0\xdbF\x8d\xa8f\x9d\x9f1\x1c(\x881=\xbb\xcb\x93}\x85\xb3!\xee\xe4\x93\xa9$ \xc8\xb0\xad\x12\xd5Q\x84\x0cUT\xa5\xdeT\xb8\x8a\x9e\xa3\xcb\xa9BAy\xfe\xb3\x1f\xcb\xf4<\x9d\x04\x96\xef\xdb\x05\x10\xdf\xcb\xcf\x04\xf6\x99\xebu&\xbcJ\xcf\x0c\xc7\xc2\xed\xe9\x9f\xe2X`\x03\xb59\x19(B\xc8\xcf\x04\xe2Q|\xe8?C\xa6\x14\x1eR\xa63\xfd\xf1\xb8\xfa\xe1\xa2\x92\x91+\x1a\x87\x9d\x14\xd6\x94\x88o]#1ap\x9d\xbd\x1a}&H\xdbG\xcc?Q\x02\x13\n\xf0\xe0\xee\xfe\x9f#g \n\x9f\x98\x949\x1a\xc3\xa6O\xca\x15\x82z\x1fp\x91\xe6\xe0\xd2\xaf\xd1 \xaf$p^Bn\x8c\x13\xceR\xff\x16\xa31N\xf4\xfe\xd7\x10\xc07P|\x0d\xc1\x8d\x1b#\x88O\x82\xb7\xcd7O\x02\xf5\xc1B\xb7v\xc4O\xb2\xbe\xb2\x00ei\xa3\xc2 \xf0\xe3\x98k\x0d\xc8\x18N\xe8\xbboE\x11\x87\x18O\xe1\xc8Cs\x85\x1fG\xff\xae\xa5\x07c\x19\x07zE\x1e\xa1\xe3\xed{?\xbfG\xadBz\x865y^\x936\xef\xab\xfa\x1a\xf3$\xaai\x00\xd7X\xe2\xbe\xa3\xdfc\x7f.\xa2\x98PN\x03S-\n\xef%\xaf|\x0b)Z\x0dY E\xac\xce\x9c\xc07\xacVa\n7 \x82o\x0f\x99;n\xc2\xe2\xbbqs\xf39}\xcc\xd6JV]u\xcc4\x19=E\x17\xdd}\x1fC[u\x95\xb5\xcf\x98\x9c\xbf\x8a\x96\xab\x98\xce9\xaf[I$\xc1P\x1d ]\xc6\xff\xf5\xbb\xf7&\x0b\xfd\x92\\\xaf\xfe}\x02e\xdfV\x1f\x90\xc1vV%h\xe87\x14\xa9\x88\x0f\x15\xc3\xb4:.,0\x86\xc4\xc4\xb9\"\x9f\xeaj!&A\x1a\xaa\xca2\x8eQ/v%\xed\x89\xa1Nx\xc5yY57q\xd5^\x1dt]\x9a\x14Z\xd5M\xe71\x07r\xcc\x96i'\xcb\xf5\xc9\x01YYN\xda\xb4\xe4\xc8\xd1\xf5\xfa\x97\x15!qU\x04KG\xd0\xd5_i\xcc\x19\x96=\x80uD\xbf\xa0\xae{\xfa\x9er\x00\xc6M\xd4W\xc3\x99Tpr\xa7\xd7\xe6N\"\x1e9\xcf\xd2\xbc,Z\xc7S\x9f\xbd\x85\x06\xe7\x99\x903\xf8>N\xe7\xee y+[\x83\xf2\"\xc3\x91ST\xa7\xfc@\xc4\x8ad\xdfL\x83\x92\x94\x93\xa2\xcc\x89\xbf\xeeH\xeb\x1d\xf6'ZT\xf5v\xf7\x0e\x0f\xe1,J\xc2\xf4\xccK\xfcm\xb4\xf4\xcb4\xf7\xd6\xc5\xb1\xbf%\xb4\x0f#\xddC7\xefsV$.\x88\x82k\xa3\x87\x1e\xff\xda\x9bW\xcf8\xc61\x0e\xfe\xcd\xabgn\xae\x91\xe9C\x9e\x0c\xa4\x8b\xa6\xbeL\xef\x1dyX/W\xb8\xb6\xc1!8I\x9aP|\x8e\xbcUN(G\x9c\xd2\xdf\x05)\xbf+\xcb<\x9aoJ\xe2V\x9b\xcfa\xb2N\xa3\x1cq\xcd\x00\xd13\xb3\xfb\x1ec$\x9cq\x15\xd3;\x1a\xd7\xdd\x9d\xa7\xe1\x05\xe5\xd9H\x12>ZEq\xe8F\xc8\xa6\x05t\xeb\xba=\xc0\x9c\xac\xd3-\xa9\x01\x1b\x93\x95\x93m\xfa\xae1Y\xa9\xea\xe8}/E\xc9\xeb L\xc9\x95\xbfR1+R\x89Y\xbeJ\xcc\xda\xa8\xc4\xacB%f\xc5\xfcAOb\nx\xca\xc7\xbe\x1cUKZYU\x12B\x98>+\xe0?\x81`\x95\x8f\xc1\x97\x0bV\xd1u\x14\xacr.Xml\x05\xabt\xa8`\x95{\"x\\\x84\xe1\xfc\xc2B\x04\xad\x84\x0e\xde\xd5\\T\x88\xac\xc3\x85\xbc\xa0\xf5QT\xa8\xba'\x02\x10M\x90\xd5k\xcc\xed\xe2-\xe5\x9f{\xad\xbcg]\x14\xf1T\x8f\x18\xfb\xf0\xfa\"#\xac\xd7V\xdd\xace#\xca~\xe4i\\|\x17\x04$+\x7f@\xf5\xaf\x89\x9f30})\xe6v2\xb0\x8f\x11\xba\xedY\xa5@\xf4\x11To\xa4\xdd \x8c\xceO\xa6\xac\x08\xbad\xea4EZ9\xd1\xd3\xe5\xb4d\xde{j\x00\xe1>\xbb\x91BH\xaa\x17\xbd\x1f3\xabs\xafp4\xdd\xad\x96\x82X!\x15\xc4|;A\xacX\xa5\x9b8\xacX\"ka\xc7\xb4/\x1a>M\xdd\xc0@\xe4NH\xff\xb6(\xbf\xcf\xde\xaab\xdb8x\xfdw\x1bN\x84\xd6q\xb0\xeaO9\x14n\xc6\x0e(\xbb\xd7\x86\x97\x07\xbc\xf1\x17\x15\x0f;-\xfa\xe5J4D\x7f\xb6\x9f2D\xe1\xcf\xd9\x1f}\xdch/\xffG\x92\x06\xf5$\xc1F^d\x1e\x19\xd5z\xe9)C\xd2\xc3\x03=yH,\xbdN65\xac!\xa5,\xf3\xd3\xb0\xcc\x13\x8bl\x841\xefm\xd2\xc6-5p\xc8\xdc\\\x06\xa6\x0d]U=\xd6G\xd5l\xf9\x11Zi\xed\x8e1\x89\xdf\xa34$#7\xd5x>\xac\xb1\x98\x8f\x13\xd4d\xd3T\xd1\xc6w\x9d8\xda\x12\xb1\x86\xa6\xca6~\x1d\xbbj\n\"\x91m\xf5\xaf\xbe\x92\xdd\x16Q\xa4\xb27f\xb5\x84\xf7\xb2\xf5D\xdd\xf8)\x1cB\xd1\xac\xf6\xc7\xa6rIJv\x82>b\xe7)\x95p\xc5\xb0\xe9\xacJ\xcd6\xe229\xee\x0c\xd1+T\x1b\xcc\x98\xd9\xe0J\x9a\xb3q\x01\x10\x971O\x16w\x05x\xd5\x88_n\xcf\xb5)q]\xec\xcfI]3\xc4\xe4\x08\xd5i\x0e8b\xa3\xcc\xad\xcb\xa6\xa5\xad\x16\xc3\x89\xab&(L\xb0\x97\\1\xa2\xe065\xc4\xa6\xde\x7f\xc5\x0c\xe6\x1a\xc0\xc6:\x89t\x17\xfc\xe5 \x8eQ\xbeJ#]\xc6\xabA\xc8Q\xe3b\x94\xe8\x92\"Df\xa5\x9a~E\xb5\xd5^\xea`i\xeb|\x94\x1a^\xae\x99y@\x93\x03\xaa\x93y@CP\x18\xf7\xd8a\x11\xcc\xbcd\x8fk\xd0\x1c'\x8a0}U\xfe\xa5\xe1\xdb\xd4B\xc9(\\k\x86b\x0e{o0=i\xbb\xe8\xa8\xc1\xf2\x1d\xba\xb4+\x8dS\xb8\xe1\x88K\xed\x8eS\xa1\xf0\x84\xde\xe39wU\xcd;\xf4 \xd7&\x03\xbc\xa2~\xd8\x04\xbb9\x8f\x1b@]j\xfe\xa1;\x18G\xc9;\xcd<=\xc3\xc7un\x07\xdd\x8c\xb5<\x9bR\xa5gS\xa9b\xa5\x81\xb3\xd3I\xdf\xc3\xa9T{8\x89\x0bYg\xa5\xa7\x93\xb8\xb0|\xc9\xc9\xd4\x00\x15\x027\x18F\xed\x0c\xcepx\x08)<\xac\xf1\xfc\x94'#A'_G\xce\xb8\x80\x99y\xb9\xd0\xad$\x08a\xc5P\x96\xb8\x8e:[\xb1\x1c':6\x15\xd0\x1d\xf8\xb1\xd0\xa6mQ\xafkh`\x91h#\x13\xa1\x8du\x1aZ\x8b\x90iH\x8cC\xaaO%M8/\x0c:I\x803\x07]u\xce\x8c\xa2\xc6\xe1\xa1.m30\xbe\xa4\xabK\x9aa\xd9\x0f\xa5\xaa\xc9\xdc\x15\x0e\xae\xe5\x87\xc0\xfeT\x85\xfeI\xad\x84U\x14\x85n\x15\x83\xde!\xa1K\x8d\xe7;$u\xe9'C\xeaGX\xd6\x99\x83\x98\x85\x98U\x8a\x1a\xb9'-\xfb\xcf\xaf\x85\xa4\x16\xa7\xea\xa0\xdf\x9b\xd6\x03\xf8\x1c2\xb9\x84*w\xacP\xe5\x8e\x15\xaa\xdc\xb1B\x95;V\xa8r\xc7\n\xa5\xe6\x8b\x98?\x91Z\x10\xdcP\xd8\n\xc2\xcaV\x80\xbf\xa6\xb7z\x05\xa4\x17R\x8b\x03\xaa\x07Te\xa5\xc3\x8fo\\X\xd9\x1a\x17\x88\xc4\xb6 C<\xb3hkjo);O)\x0e\x8d}\x914\xc1'+\xf2N%$n\x90\xba<2)\xb9\x12\xe6\xeb\xd3oF\xfd\ns%\x92\xd1m\xf9\x99\x8b*\xec\xe3\xd2/uJ\xeb\xbcO\xb2\xbbK/\xae\xf7h\xd82\n\xb4\x9a\x11\xc8\xcf\x9c\\\xd1Z\xef6\xfa{Q6\x84\xf4\xe8\xa5\xb8\xa4\xc3q\xfa\xac\x1d\xfd\x94\x02\xbf\xe1\n\xdd\x94\xaeF\xb3\xca\x08-Z\xe0RK\x1d*3\x9aP\xfeB\x0d\xc3\xac%\xe6\x02d\xccbb\xe1\x9a\x13\"\xa0Y\xaf\xb8B8\x9d\x12t\x8b\x10v\x9a\xdau\x0dk\xd0\xd4.\xab\xfeYhj/\xf8\x0cVx\xa4\x06\x9dW\xa0\xf6\xf6\xb1S8\x84\x95\x17%\x0b\x92c\xaeS\x8d\"\xe1\x0c\x0ea\xc9\xc5!5\xd4\x11\x1c\x82\xcf8u&\xe2h\x93\xfa\x9d\xd7\xd0\xe4\xdc_g\xb1>\x07\xe0q\x0d\xced%\x0d\xec#8\x84\xadU'\xdeqH\xe1P\xc5\xe5Q%\xfcw\x0c~\x9d\x86$>b\xbd\xd6\x81\xbf`\xe06%\x80^2\xd0*.\xd3TL\xe75\x83\xb7Tp?\x17\x9b\x16i\x97'\xa1Q\xf4\xc8\xbaPP\xf1\x05\xb8g\xee\xc8$/>\x15+\x84\xc5\xb2x\xc7\x9c1<\x7f;\xe6\x8a\xe7\xe7~6r\x7f\x7f\xdfe3\xba\xd7\xafp\x08O\xb9\xc4\x87\x88\xe9\xf4>\xa0\x16\xf1\xeaP?4M=ma\x98#\x94\xe0\x99W`m\xa0hq1r\xbb0T\xccf@KR\x1e\xe3M\xb6AF\xee\xaf\"\xec\xd70\x9b&A2J\x82x\x13\x92W\xc4\x0f_$\xf1E\x8b\xcb\xec^\xf4\xd0\xa3\xc7\xcd\xaf\xf0\x10\xcaJy\x95\xf0;\xa7U\x9fj\xc5V\xce\x9f\xb9\x8d\xcc\x89\xcd\x151\xf5]L\xfb[\xfaI\x85\xe6\x8d9T\xd1^\x9c\xba\xbe\xe8\x01k\xda\xf7V~Q\xad\x1d\x9d\xf2\x90g\xfb\xacnQ\xb9\x14\x07\x95T\x0b\xd2\x9b\xebd\x0c\xcfu\xf3(\x99C\xcdi\xc4\x80\x7f\xc9\xa3\x92hg\xfc\xbd\xde\xfcq\x8e\xbe\xcc\x94v\x9d[\x04\x8a\x89K\xb0\xc0\x94\x1d\xa2l/+&\xf5\xd7\xbf\xe6d\xe1\x08\x97.\xda\xae\x8a\xebQ\xe0;\xddu?Y8\xf05/a\xdcF\x0bTeo\x1a\x16\xff\xd6\xbc\x9a\xb1p\x0d3\xbe&\x16\xaey\xe5\xda\xb8\xb8\xe6\x95\xf2\x1893\xa4\xe0\xd0[{<5%V\xba\xa4YK\\\xc8t\xc9\xd9IqiMKw*\xcd]\xaeQ\xf2)\xe3\xfe\x9aW\xdb\xa4\xc2h\x9by\xf68[(\x8f\x19\x17\x97,v\xbc~V+-(J_\xd6^b\x1c\xeb\xf0q\n1A3\x06A\x05\xe4\x1b\x92\xa2\xf7\xf9\x18\xde\xed\x98\xdc`\x07M>8p\x03\xdc\x0ds#\xd7l,'\xf4K\x9f\xb9\x85+\x03\xff\xafN\xdd>D\xd7\x1f]\xa1\x9a\x7f\xb0n\x7f\xe7}-[\x8bn\xab\xa7\xa7z\x93\xa1\xaa\xf1\x17\xba\x86E\xd5\x1f_\x94)l\xd8&T\xa7\xc4\x18\xce\xcc\xbb\xcdj\xacL\x9dWQ\xf3\xe6\xd0\x1b6Y\xd3\xcet\x84@2\xf1Q\"\x11\xd6\xa8\x19\xcc5[o\xe84\xbe\xb60q\x1b8\x1e\xf5\x94\xb4\xec\xd7|-\x04#E9\x9b\xee-\xef\x1da\xc7(\x88\xc4\xd5\xc7\xe4\xb7^\xd2\xb9\xe6\xd51\xb1\xcb\xf4>\x8a\xf5\x1e\xc3\\\x9b\x83q\xed\xc7\xb5\x83\x81\xc3\x9d=\n\xd0E\xa1 \xe1\xa8^ar\xa43\x1a\x83\x03l\xe9\xbc\xda\x06Uq\x9b?i:\xf1\x9d\x16\xc5+K\x89u\x9a}MV\xfc\xa6Z^S{\xb1c\xa2\xd0\xd5^D>T\x88\x02L\xb5\xfd\"\x0fIN\xc2\x91\x9bhV\x94\x1fB3\xf8I\xb1p\xd5\xd4\x1di\xa6\xee\x91n\xea\xb8h;\x83#\xeb\x99\xd3\xf7e4\xae\x04\xfc+\xb5w\x0e0r\x1e\xc3C8\xf6\xcaT\xc6\x85v\xa2W\xba\x97\xe1\xc0}i\"T\xc8\xb5i\x14<\xf4JpP\x06 :B\xad\xfe\x11,\x17\x064\xa4p\xa4\xad\x87Yo\xdf\x9fR\xe0\xaa\x92j\x95{\x1f\xbc\x94\x05i\xa5\xb7 \xd5fCF \x85u\xe8\xf7\xf7]s\x89\xcc\x9a\xd7TL6T\xffm\x9b\xd0\xea\xbf\xf8\xcdke\x13Z)sG\xacTQ%+UT\xc9J\x15U\xb2RE\x95\xacTQ%+\xa5Mh%lB+\x8c\xc8\xbf-\xb5\x04\xb1g\xbd/W\xe6\xa0\xf6\xedP\xf4]\x91no\xf5\xf1\x0dE[[C\xd1\x97(\x94\x8e\xd1\xca\x14\x85\xa2\xb7\x88d~^\x90\x90oq\x85X\x85\x91\"\x1bt\xdd\x7f\xd9\x04\x1fd\xf2\x12!)\x9c\x1bSk3\x99\xff|\xa9\x16b)\x10S\x91@\x94\x14\xa5\x9f\x04$]\x00\x0b<4\xebC\x12\x1e,\xf9$\x8aQ=\xa52\x8f\x89+\xf1R\x16\xc6g\x91\xc3\xa0y\xe56\xe6\xb5\xe6\xd5] \xca\x0cobydn\xf3R\x9cD\xd5\xe31~\xca\x0f\xbf+^\x93\xf3\xd2\xd5L,\xd7\x1bZ\xf7\xbc\xd3\xe3\x92\xf2\x07\xac\xaa\xbbN\x03!C\xafO\x1b\xa4r\x95\xd9\x02PN\x90\xec\x15\xd7\xea\x88W\x07a\xec\x942@\xb9)\x95\xbd$b\x7f^\xa2\xabWc\xd5\xb4\xb4d\xd6\xc1g\x16YB\xad\xccu\xac^\xc9&\x97$T\x12\x17\xabR\xc2\xf9|5\x98_\x9b;Xz\x8d\x87\xf0\xfb{\xd0\xba\x0fo\x06d>-\xdav\xa3\xd6nT\xbf\x85\xf5A\x06X\xd5\xe8\xc1\\\xfb\xf2\xa1\xa6\x8b\x92\xcf\xc7~I\xb0\xbe\xe8\xebhMt\"\xf4\xba\x9a\x04\x8d4$\xc9\xf5\xd5\xbc(\xc5\xa7\xcb\x92\x8aL\x0d7\xffo\xc3\x87\xe9_\xad \xf6\x9b\x91W\x92\xa2t\x93\x11\x05\xf6O\x1c>#\x93\xc7Q\x91\xa5\x05f\xe6w\xde\xd2\xe3\xe3\xa6_\x96~\xb0\xa2\x07\xb5xI\x05.\xbe%4,\xa1\xdd\xb7\xa4\xe0\xbd~5\xb4G\xec[\xf4h\x82\xd7\xb9\x9f\x14\x0b\x92\xcb\xba\xd6|\xa3\xd75\xeb\xcfI\xdf\xd0(\x8f\xe9*8\xf4\x98u Jx\x9c\xb9\xe9$\xa4[\xf9\xa2\xca\xb1Q\x92\xf3\xf2\xe6\xaa\\\xc7\x16\xban\x0c\xce\xe9\x1e\xf0\xc2\xcaV%;(\xa5\xc9\x0ed\x17K\x80pa\x84\xed\xca?\xb2\xebT\x9f\x94`n\xf1\x8938\x84\x93\x0b\xca\xd0\x15\x9byQ\xe6n\xea\xc5~Q>MBr\xfeb\xe1:7\x9d\x11\xdc\x80\xe9h\x0c\xa7o\xbd_\xd3(q\x9d\x99n\x9b\x8a\x0b\xed\xfc*D\xd5l\x08=\x13\xd4\xc9\xfdpdZv\xe0K\x7f^\x99{\xc8y\x99\xfbA\xf9\x84\xe7oz\x92\xa7k\xde\x8fF7\x98W\xc4\xc8=2\x18\x84\xe8\x85!<\xb43\xcc\xeaG\xe7\xf3\xdc\xc0 i\x9fR\x1aTy]\xd6\x99+\xe8\xc7%\xb7yB\x8b\x17\xf9\x8b\x8c$\x1c3/eIq|\xa3\xc6\x16\xaa\xfa\xec\x06\x07\\\xd8\xa9\x06\x8a\xb88We3hw>\x863\xfd\xa4\x83q\xe2\x9bYf`\x11 #\xff\xb5\x9aM\x91\xcbc\x06g\x83\xc7\xa2|\x81\xb3\xdb\x14\xf1\x94\xe3`)u\xb8\xce\xa8\xfa2\xe7< $%\x96\xd6\x86\xf9\xa6\x84\x8bt\x93\xc3\xd7r/\xda\x99f\x96k\xda\xe7\x06'\x84\xa2\x81\xdbN~\xc8x\xd7\x9b\x14\xe8_7\xb3\xd8\x8f\x92\x9b\x8d\xd9\xff\xc8\x036\xf0k\xc2\x88\xa7\x181\xcc\xe0\xe6\xff\x8d\xd6\xfe\x92\xfc\xebf\x0b\x87\x12\x8f\xbb\xfd\x14\xaeSl\x97\x8e\xd6\xb0\xd1\xa4\xf9\x0e8\xa8Fv\xc0\xd1+\xdb\xd7K\xed!\x80\xf9\x9ed\x9a\xcb\xe6\xb5\xf6\xcf\x7f\x89\xc2r5\x03g\xba\xbf\xff\xff\x93c\" \xe5W7\x94\x073\x1d\xbb\xa8\xd0\xc8\xf0\xb9\xf37a\x94v\xe6\xce\xea\xb8P\x9f\x8d\xf4\x8bzC\x117G\xaa\x1d\xb1tA\xd1h\x1c\xd7O=\x9d\x11]\xado\x96\xacL\xb5\x89\xe8\xc48\xcc\x7f\x88n\x1f\x04O\x17P~\xfc\xbdQ\x9e\xcbtE\xe22o\x0d\xee\xe4\xf5-\xec\xc3C(lw\x80z\xf9\xad\xcd\x7f\x91:\x9c\xf1M\x92\x93 ]&\xd1\xbfIX\x99\x89p\x8e\xbf\x16\x81A\x94\x89\x10A\xee~\x81\xd4\xdd\xd3E\x8a~\xca\xd9/4\xa4\xf8\xd3M\xe4\x06K\x91@\x99\x8a)\xad\x8d\xf7Z\xb7\xa5\xe5\xa5q\xa4\xe1\xc5Vg,\xc0\xb0Tz\x9e*]\xab\xacm\x916UH\x98Yu'\xcb`\x95\xef\xd0}p\xf7\x8e\xc4\x88\xa7\xd7}\xd6\xbe\x9eY\x1c\x95\xeeM\xf7\x9b\x7f\xdd|x\xf2\x7f\xbf}{\xe3\xdb\xd1\xcd\xe5\xc8[DqIr\x0b\x0fK\xfe!\xc7\xa9\xb2\x0dEkY\"\xdc\x8e\xfa\xba\xdd\xdf\xc8\xb6\xbf7\xbf\xf9\xd7\xcd\x1b\xac\x9b\x9c\x11 \xda\x0f\xfb\xf6\x1f\xc6\xaf\xfe\xeb\xa6\xddw7\xb6\xdf\xb5\x9e@\xec\xc0\x9er\\\x80\xc8E0\xef\xf0^$~\xf8\xbdn\xd6\xf8!\xcf\x9d\xd9\xed\x850JuM|\xf0-Li\x13\x0d]Gm\xcb\x9b\xbe\x85\x87\xed?g\xf0\xbb\xe4\xdcg\xb1[\x82\x83\xed?G\xbd\xad'a\x89\xfb\xa01\x1c\xca\xf4\xa6\x01\x1c\xc2IGeSg\xb2\xa5\x7fu\xe2\xac\xe9x\x17c4\x07\xbb\x0b8\x042\x86\xd4]\xd8\xb8\x13\xf3uR)\xeau!]\xec\x14wK\xd6^\xe4\x96\x94uq\x1e\xc5i\x11%\xcb\xd7\xfe\xd2\x81\x19l\xf8\xdd\x17\x19I\xea\xbb>\xbf{L\xe2E\x1b\xdeyM\xe4\xb9\xbe\xe5\x01\x81\xed\xa3\xf7\xfdH\xe2\xba2\x86TeR\x8eLI\xeaX\xfdq\xa4\xe8\xbd\xe7\xad\x81R\x1e\xdf\xa7\x88\x15O&\xf2\x9e\xd2\xad\x95\xbb\xc9\x18b\x85\x92\x0fK\x89\xc3\x0d\x88\xfa\xef\xa3b\xb69\x83us7n\x8c\xa1\xd0\xd9Y(J\xa4'%L@\xe7\xbe\x1dVP\x07\nM\xa1|\xb8l\xb9\xf0\xef\x0c\xe7 ov\xbb\x1aV\x8f\x109\x1d\xac\x9c\x057 ds\x0f7 \xab~ET\xe8\xc4\x80\x05\xec\xcd\x18\xb0\xeb\xc6\xf0kh\xd0\xa6\x0eN\xb4\xc7\xc3\x81\x02o\x91\xe6G~\xb0\xb2\xdb\x1e\xd9 yK\xf7_\xf7\xe4\xa42jfw\xaa\xf0/\xed\xedu\xfc%F\\\xfb\xfb\xaf\xa6o\xe9%\x12\xb6\xde\xfc\xfb^\xdd\xc0\xdf!'\x19\xf1\xd1vB\x99\xbaoVe\x99\x15\xb3\x9b7\x97Q\xb9\xda\xcc\xbd ]\xdf\xfc5M\x8a`\x15G\xc9;\x92\x977[\xf0\xdf6\xbe\xd4\xfc\xe8\xa34\xbb\xc8\xa3\xe5\xaa\x047\x18\xc1\xc1\xfe\xf4\xf6\xe4`\x7fzg\x0c?\xa6 \x1cW\x1f\xf3\x9a\xef<\x8b\x02\x92\x14$\x84M\x12\x92\x1c\xca\x15\x81\xe7O_\x8b\xdbM\xd0\x9b\xd5od\x06X\xd4c3\xb3\x842\x7frw\xdeq\xe3\x08Ab\xaf\x12$\xc8\x08\xcaU\x9e\x9e\xa1\x9d\xe1\xf5EF\x8e\xf2<\xcd]\x87\x9cgL\xdd\xe6\x03\x7fI\x92\"y\x8a(]\x8e*^\xa3\x0fr\xd0\x05\x81\x1b]0\xe1\xa9@\xc4\xc1\xf4w(\xfb\x1f\xca\x19\xf7A\xa9~\xc3\xce\x98\x8fX\x16\xf4\xfe\xc4@S\x9d\x97Vg\xde!\xc5\x1b\xde\x97\xca\x1e\xb1O\xb1\xa9\xfd*z\xc7|\x8d\xa5\x00\xaa\x97\xd1\x0d\xe3[\x98~=\xa2''\x0b]qS\xb8q\x88F\xf8\x12\xbe\xfd\xf6\x10\xa6c:\xc4\xc3\xee\x18E\x8b\xf4P\xe2o\xb4\x1a\x1f\x86\xed5cxw:2\xe1\x82\xc2\xbb)w\xc9\xc8+\xd3g\xe9\x99\xa8D;\xac\x0f\x1f\xdd\x99\xed3,\xfe\xba\xa82\x1b\xd0_\xf7F\x7f\x8e\x82\xaf\xdb/\x05f\xd4\x05f\x84\x17\xfd\x80h8\x81\xe0\xb9\xaa\x8a\xf6\xa8\xe2\xa8\x8e\xceKM1\xef\xb4[\xb2;U\x97\xecN?\xbeZ\x88 t\x9d\xb1\x98-\x8b\xe6z\xddReh>t\xb7Jy\xa7\xd3Sr^\x92\xa4\xe8\x1d\xf6\xef\x99\xe7\xd4\x0c\x9c1\xf0\xa3)1\xd7\xda\x8e\xae\x1bB=e\x9ecG\xeb\xac\xbc0\x94\x89\xef\xc5\xd4\x8a*\xf1\x98S\xb5~'\x12\xfa\xc9\x88\xeb'\xafU\xc5x\xd5\xc8m\xf0\x10\xb1B\x85\x88Q\xc1\xbf(9\xea\x98\xf9S}\x02\xfb\xfc\x0b\x8f\xa3\x02)\x9d\x14\xa1\xf9\xb9\x8f4\x0f{\x8d\xda-\xf4\xf6\xbb\x0c\xaew\xf4\xa9-\xd4\xa7\xad\x9c\"\x0e\x9d\x96\xe9r\xa9\x11>B\xdesY\xfa\xe7\x9e\xeb\x86\xba\xbfQ\x92mJi#\xcc\x04\xee\x04+\x12\xbc\x9b\xa7\xe7\x12MY\xa3\x0b\xfd\x87\xf8\x1e\x1e!\xa8t\x90(tj^\xc9\xac\x9c\x8c\\Q\xc1\xda\xe3\x1f6\x1e\xb7\xa318\xc7$ \x01'\x95mL\xa7\xe7#\xf4Y\x95\xe8\xff\xa49\xa1\xe5&\x93Pj2Q\x94\x93T\xa4\x88\xbeu\xd0\xcb\x0b\xf0%\x17\xb4\xdc\xb0ag\xd4\xb0\xcd\x05-v\xe0.f\x82\xa1\xeeG_}\xd5\xfa[-F$&\x1bD\xc3\x02\x90TC\x18\xb9\x89'$\xc618\xcc9\x03\xad\xcb\x88\x13\xcc\xbaLD^\xc2\x84\xd5PB\x91\xbfOG\x9a\x96\x14\xebCK\\\xdbai\xb2\xad\x94\xc8y\xad\xc2W\x03\xa5\xd6\x9af\x1fS\x1aX\xc9\xb4\x9b\x1a\x94\x8a\xc4\xda\x05IxT6\xce\x15.\x04N\x1e\xe5\xe4\xdct\x0c\xfe\x186*S\x10\xe6\xf3\xe6\xd5*X\xcdA\x8b\x8c\x05\xc2\x00c\x9ci\xc6KX\xea\xf6\x13\x10u M\xd3\xc8\xca\xb5WHg\\\x18\xb5r\"\x19C\xae\x98\xdbF\xf4\"\x96\xf0`k!\x0e\xb3\xaf\xbe\x02\x07\xb5Y\xb8\xdf\xd2z\xa1t\xfa$\xc1\x9a\xe9\xa2\x96\x01\xcf\xc3\xa88>\xf3\x97K\x92\x1f\xa0N\xd6\x87\xaa\x8d\xf3I\x9d\xf9\xf6\x8f?\xd8]L\xcf\xcbi\x11\x8f\xed\xad\xefW w\xabT\x8aj\x88\xc67f\xd8\x0b\x9e=\xea\xab\xaf\xc0m\xf4A\xd1\x83\xddZ\xaa+`\xef \x07\xb0\x1e}tY8h\xb2Y\xcfI\xfe\x9a\xeb\xc7F\xae\xaf\x88\x93\xeb{q\xc90\xdd\x1d}\x9c|\xedU\x12\x86_\xa28~E\x02\x12m\x91;\x91\xd5\xdc\xb7\xce\xc5Ps\xea\x9fxw\x99R\x88G\x97\xda\x83Hd\xa2\x02 \x1b\xee\x84\x1cf*3\x9a\xcd\xeeJ\xab\xed\xe4F\xad|\xd4#q\xa8\x07,%\xf5h\xc4Q=\xd9\xac\x91w\xf5\x81\xe5b\x88:\xf7u\xad \x17\xcd\xc6{53lJoP\x18\x86\xd2\xd84\x1b\x8c\x03\xa1\xff\x9d\x893#'\xbfm\xa2\x9c\x84\x8cT\xe1\xae\xf2\xd9\x19L\xf72\xba\x89x\x8b(/J\xb7\xb3\x01\xb1\x90e\xc1?+jZ\xdam\xc7bTe\xd1\xee\xee\xb4\xfe\x86lo<\x99\x18\xf4\x01\xbc\x05\xec\xce+\xc3q\x9fX\xee\x8f|@V\x8e\xb4\x865\x98\xcb#.?sm\xaf\x9e\xd7 Z{\xfe\xa6%\xaa\x0b\x95\xb7\x1e#\xad\xe9M`Mo\xc2\xea\xb3\xe6\n\x0f\x85\x91\xde`\x95\x07cj\x11\xafX\xa5gGB\xdde(\xef\xc0\xa0\x1f\xa5\xebu\x9a\xd8\xbcs\x81^\xd9\xce\x8fE\x9a\xb0\xcc\xe7O\xd2|m*)\x9b\xbb\xcc\x98\xfc=\x0b\xaaQ\xc2\x9e\n\xc7\n\xc6n\xa8\x01\xcf\xe0\xb0\xc9\xa2\x9c\x9a\x0b\x98\xceM\xf6\xac\xb6\xc1\xc9`\x15Y$Zk6\xd4\xf6#\x83\x95)\xa8\xec3\x85W\x15S\x10\xd8\xea\x06\x06\xbbP\xd0\xf4\x8f\xa2\x9fh\xa4\xf3\xc1{\xf4\x135\xcd$E\xd9\xc8\\hot\x92\x91I\xbbwk\xf3\x93\xa1\xf4X\xc3\xc2\xa3\xc9\x05\x04\x83\x8b\xb65\x8dL\x81\x12R\x97\xe1\xe4\x88\xe1\xafm\x0d\x8ds\x06nSC\xe3\xb8\xb13\xb8\"\xddT&\xa4 \xde\x94!MEC\n-\x93\x12P\x89^\xfd\x81\xef\xea]\xb9H\xf3\xb5\xaf\xed\xe5\x0b8\x04\xf4\x81^!7Rv\x18\x11\xed\x86x \x87\xf0\x82\xbdP\x1a\x10\xf45%\x00\xb47\x8f\xfd\xd2wL5\xf8\x9eS\xe8'\x15t\x94\xd4\xa1\xe5\xea\x97\x9e\xd6\xc3\xae\x19\x0e5\xf8\xaf\xa2\xf3(\x0cD%Y\x17T\x16\xc0\x81t\xab\xc95\xaf\x9f\xe0\x10\xde\xc1Cx\xd7\xe5\xa1\x1cM$\xe7+8\xc4\xc0GW\xd4\xa2\xe8\x12\xf0\x91[Vy{\x95_y\x0c\x87\xb0n~e\xe0\xfb\xcf,\x12Y\xbd\xb1\x80\xf9\xcd\x02\xe6 \x1c\xc2\xdeT\xab)h0z\xcc\xe9\xfeY\x8dOl=:\xec\xe03:v\xda\xc1gM\xbew\x8c\xfd\xe1\xb7\x84(\x87\x86\xe37\xf5\xf7\x04h\xe3koh\x9bo\xea\xf0e\xda\x03\xec\xf5~\x1b\x8e\xf5\xed\xb7\xfa[U\x1b\xe3f\xccB\xd9\x15G\xb1\x02FWL\xd6z\xa4\xe8\xf3\xf6\xb3\xdc\xfbH\x17&\xa8\xb0\x99\xd9\xba$4\xdf\x8c\x12\xa7\xe5\xde }\xe9\ns\xf8\x0fq&\xba\nC\xffSx\xd82#\xd2\x06\xa1\xa2\x070\xeb=T\xf6\xa6=\xb9\xf8au\xc6\x00VF]\xddC\xabT\x0dA\x1ac\xbe\x10\xdaS\xf5\xd9\xa7\xea\xaf\xf3?\xff\xef\xefN\xc3\x8f\xee*f\xb39Y\x9a:\xe9cx9\x86_Q\x0fu\xe2\xc0\x0d\xf8\x15n\x80\xf3\xd6\x19\xc3w\x18\xc2\xb7\xf3\xac\xb5z\x92\xa7\xd9\x84\x9fg\xca)p\xffJ\x1b\x1d\x833\xd2o\xb5\x1d\xa7 $YN\x02\xbfT\xad\xcf\xfbq}\x96\xd6\xdb\xbf\xf1\x16\xc6\x846\xfe\xfep\xab\x15i\x9c\xe4\\g\xdcb\xdbq\xba\xc6\xb0\xa4}~%\x94\xe3\xaf\xae4G\xfa\xb1\x89\x9dgnW\x14o&\x14\x83\x0c\xeeR\xe7\xff\xb0H\xa9~\xfe\xb3\x1f\xeb\xcb\xb0\xc8g\xa8N\xa0\xbf\xa63\xf2X\xcc\xc8\xe3\xff\xf8\x19\xb9\xc2\x1a+;8wV\xdb\xa9\xe1\xe2\xa9!\xca\xe7Zz\xcc\xeb\x9f\xc8\xbei\xc2\x8a\xbd3\xd4\x0b\xc3\x1f\x7f\xc0\xde\x13\xb3$\xab\xed\x87\xca\xf9\x85\xb2+\xea\xb5\x14\xbdw\xbe\x89\xbe\xfdn\xebG1\xa6\xe2@V\xb4\xf8\xe6f\xf4-=\xe6\xe0\x06\xbc\xb1\x88\x8eo^\xc2|\xaa\xc1\x8f\xda7\x8f\x07\xf5\x8eU\xc9\xcd\xde\x8fZ3\xd5\xe0\x94~\xfb0s&\xd82\xbbi\xe3*A6i\x8d9\xfbM9\x98\xd7t,{\xcf\xb5'Z+\xcb\x13\xc6\xdc\xce\x0cY\xed*)\x07\xcb\xebP\x94\x8a\xcc\xd3\xa3\xad$o\xd0uX\xebM\xb8N\xf3'5\x84`\xabf\xf0T\x0d\xd4\xd8Z\xf2\xedVK\x9d\x8c\xd5\xa2\x14\x0f&\xd0p\xb9m\x83\xcfXx\xbd%\xef\xbb\xabV\x84\xd0\xc5+fB\xccc\x7f\xea\x1a\x12\xf5\\^(\x11\x087\xc3\x0b\x0d\xc5:\xd2-\xab\xf5\xba\xd5\x0e\x96\xdd\xba\x88\x06\xa4\xe0\x0e\xd9\x9a\xacVvZ\x1f{\x8d\x8f\x98\xb3\x8e\xd6A\xb3*\xa2\xf6\x8d<\x89\xa5\x84H\xefX\x01G\x816M\x1d\x8en\x9a\x84K\xda\xac\xa9\xc9\xa9\xec\xe0\xc7\xa4,\xa3d\xf9$\xcd\xdd\xa0'g4\x183\xcdD\xd4>k3\xf8\x89\xb96PY\xf5'\xe4U\xd4\xaf %\xa7~\xf6\xae\xca\x89\xf9\xfa\x97R T\xaeT\x81\xca\x95*P\xb9R\x05*W\xaa`\x98+U\xe0\x16\x8d\x8e\x06jO\xe2\xe0\xe3\xfb?-l\xfd\x9f\xbe\x04\x98\x0b@\xfb\x00\xf38\n\xde}j\x87\x17k?$R[?4goevS\xc30\xcb\xe0\x1aU\xferma\xe2m\xfd8\xe2\x85\x1e\xfcu\xe1\x9e\xa4c\xf0\x91\x02UO\xbe'\x8b4'\xfcp\x12\x00\xa8\xb7\xe3\xb3\xe4\xa5 \x7f\xca|::7\xdd\xd1\x18\x12\x8f\xf0?4\xc7\x82\x18\xb4\xf6\x04\xce\xf0\xf4\xd5\x9c\xa3kn\xe1\xe8\xfb\xec\x02\x12*\x837\xda\xcb<\x0d7\xc1\xb0\xb8\xfe\xca\xdb\x8f\x8d\\\x92r\x80\x7f\x94\x19\xc9O\x04 \xae^\xf5\x1a\xeb\xf8\xdb?i,\xbf)\xf6y\xce\xa2\xabme\x93y\x99\x00G)\x10\xe1G\xfc\xd8f\xa9\xa6\xae\xdb\xb1\x8d\x19X\xee\xab\xb2\xc6H+\xa0I\xd3\xc9\xf8\xaat2\x1bU:\x99B\x95N&\xe6\x0f\xe4\x15\xd0Z\xb9c\xaeY\xc6\x98\xfeG\x84\x1e\xfa/\x0f\x1e<\x90 \xe9\"M\xcac\xa6\xcfv\xa2\xd2\x8f\xa3\xa0\x1b\xa2\xd3\xfa34\xd2'\x03\xe3\x00m\x1a!)\x83\xd6\xab\xbb\xa4\xf6\x93\xee\x94\x1fc\xc72\x03\xaf\x18\x02#\xff\xdb\xe9\xd1\x8e\xa5\x9b\xc0L\xb9`\x00\xf5\x82\x81\xfeEP\xb1\x08\xc62@\xc0\x19\x04:\xac\xb6\x17\xd1\xc8u\xc4\xd6V\xf9\x05C#\x94\x06\x9ae\xe1wVyC\x87\xd0\xf2\xfe\xeb\xe39\x01\xf46&C>\x06\x90\xb7yz\xaaI\xca\x00\x9c>\xff\xc0\xcb\xa9\xea\xe3\xe4\x8dI\x06@\xde\x85\xdd\x86;$\xd3\xc0\xd0.M\xf2\xf4l\xd7^\xed\xd2\\\x90\xc6\xfa\x05\xb8l\x92\x02\xd8\xb1\xddV6\x82\x8f\xdf<\xf3\x1a\x1a\x90\x05\xa1\xf4HR\xe6\x17\xb2\x12\xb9&\xdd\xb1\xf0\x01\xee\xc8?d\x0c\x07\x06\xbf%\x10\xee\xbb'\xfb\x9ax\x10q\xa1\x0b\xef\xc9\xd4\xa2\xda\xcf\x9e$\x1f\x83\x1b\x8d\xaa<\x81\xeaL\xd5\xe2\x12N\xbc\x91\xd7\xf1\x19\x7f;\x12N\xb4\x1dOr\xee=\x02\xb3\xc6S\xa3G\x89\xb86\xb2\xa6Z\x0e\xec\xfa\xee\x9a\xd8W\x8b\xbd\x0c\xe2HJ\xb5`\x97\xf0\x0f\x10\xd7P|\x06\xd6lz \x13\x94\xb8vl:\x92(\xa3?]o|^Fb\xa39H\x13\x9b\xf6)\x97\x80\xb6CGx\xcb\x991\x95\xbe\x83\xa6D\x83\x97\xa0\x80\xe5\xdcb\xa6\x1f\x94F\xfdX\xc3t\x93CHS\xbd\x83\x94c\xeb\x88?x\xcbP\x82\xba)\n\x85x\xf7\xba\x89B\x9fT\x83\x19\xc8\x04\x1e* \xb9\x81\x10xP\xdc\xf93\xa8/\x1b\xfc\xbeDK\xd9g\xf9m#5m$\x90k\xaa/\x19\"m0I\x83\x84Q\x99\xe6F\x0d#SF\x92<\xb7P\\2md\xec_\xa4\x9b\xd2\x02\xbf\xb3p\xb9#\xcc \x884\xdcH\x18\xe55\xf8\xf3\xd5\x07\x84\xcaL\x04\x82gv\x8a\x8c\x04\xe6\xe1\x84W9\x9c+\xeb<\xf3\x0b\x93#\xc8h\xa7tj\xb6\xfc\xfc\xa2\xcdL\xeb\x93\xa7C+\xcc\x19gA>\x05\x0c?u\xc7;\x9e\x95\xa5\xe1h\x14\xec}\xd9<\xa2\x94V\xea\x9d\xf6jo\x9f\xaa\x8f\x9f\xf7c,Mgh\x86\xe9\x90\xf4\xa7\x87\xd031\x7f\x1fVg\xaf\xe9+\xcd\x99\x0fx\x08+\xb7\x03\xc5\x1c\xc3\x1a\xae_\x02\x16Co\xc4\xcd\xcc/W\xf8\xbe\xb2\x1f\xc5\xda\x8f\xe3F-F\xbf\x84\xee\xeb\x0d\x7fW\xf5gt\xce\xebFw\xff\xb3UT\x92\xe3\xcc\x0f\x98k;\x99\xe0\n\xabw\x95U\x15Gi\xaa\x01>\xb05)\n\x7fI\xb4\x07\x8b\x16]\x8cC\xc2\x8a\xa0\x93\x90\x04)3\x91;3p\xb0\x12\x8aah\xc1&/\xd0\xdc\x94\xa5QR*\xb9\x1f\xd9\xd8\xb0\xb6\xb5\x8e\xe6i\xaa(W\x07\x7f\xe2\xcd\xa3$t\x19:\xe4R\xbb\xb6\xf3\xe3f\x9dA\x99\x02\x1d\n\xc5\x96\xbc\xd6U\x88\x1fm\xb24\xd4\x04\xb6\x13m\x91C\xe5\xbc\x8c\x8f\x92ZtwJ\x8e%h\x9fEE\xe9E\x05\xfd\x8f\xdb\xd9\x0c\xf6\x9bI\xb2\x97\xb8\x9f\xb0\xc7v\xd5%>\xc4\xd2\x804\xc8!\xfa\xe3&\xe8\xe5\x91c\xcc\xa4\xdd\xa7\xd3\xa4Z\xc6\xd6\xe7v\xde\x19\x9f\x90\x90Z\x13I\x0c\x0fB\xc4\xfd\xc8$\xcd~3\xff\x99 \xd5\x95\xd2\xa86\xd6Z\xd1\xab\xf6+\x06\xda%\xd3\xd6\xad\x94\xda:\x17\xd3k9\xce\x88W\xa4t\xc0\xb1\xb1\x1d \x11\xfcd\xff\xadW\xa6o\xe8va\xf5\x8a\xe0\x06\x10\xaf\x88\xa3\x80\xb8\xd3N\xc7\x04-\x81^\x1d10\xa7\xccm\xf2\xa4-\xa51\xfb\xc2\x17\xbd.\xbf,\xf5\xbaA\x95\xbb\xefO\xa3\xe1\xfd\xe2\xa0jQ\x01\xe9\x12>\x87\xe2\x13u\x12O\xdc\n\xd7\xd0\x93\xb0\xca\x92\xf58\n\x9f\xa7\x9bD\x16Td\xab$\xaf\x95\xe3\xcdl\x1fE\x95\xce\xa837\n\xf0*?R\x7f\xb2\xda\xf3!;J>`\xea/\xd2\x1bT\xfbN\x9d\xe6\xa9s\xbf*\x9d\xcf+)0\x9dH\x13G\xa4\xc3\xbf\xc4\xf8?\x81\xb9\xa39\x04\x93\xb5\xa3\xe2\"M\xa6\x0e\xec\xaeV%\xddv\xb3\xda\x89\x89\x82^\xc8&\x8edR^dD\xb0\xb7\xc8f\xba ?\xfe\xa5\x9f\xd1\xe9\x11\x0b4\xd6\xec\xd4\x03s\xcd\xf4\x9c\xf5J\xab\xf7\xd5\xc4\x85\xa9\x06SZp6\xe22\xe9fR\xe6C`\xa5\x953\xe8\xdb\xf8\xa05\x81\x9bR\x8fm\x80\xaeE}\xc7\xda\xe9z\xa5\xdbB\xcf\x98I\x12@\x8fzU\xa9\xf9\x08\x93^~\x93\xe6\x16cI\xb5co\x91\xa7\xeb\x1f\x8fG\xee\x89C\x0f\xb5(@.\xff\xe6\xafE\x9a8o\x1b\x9c\xe3\xf8\xday:\xd3\x1e\xbd\x10!\x06\xcf\xa2\xe4\x9d&5\xfcug\x10\x13\xf7\xb6* \xfdg\xc9\x18^\x05?\x98H\xf9\xc1\xa8\xe2\x07\x93\x11\xe3|\xf6\xbf\x86\x0d|\x03\xc9\xd7\xb0\xa1\xfc`t\xb2i\xf3\x83\x1b ?(\xf8\xcd\x0f\xc5\x08F#M\x12i\xcc\xb2\xf8\xda_\xa2\x05\x17u1\xa7\x8d\x1bLx\xa5\xccn\xa1X,\xb8B\xe6\xad\xd9\xb2\xc5i\xaf3:5\x98\xb1\x96\xc7\x003\xfd)\xf2F\xb7\x87\xa8\xe6G\xe87^d\xd7\xb9\x87\x9f\x80c\x1a\x14\xadf\xed\xf4\x91\x0fq\xfaH\x07\xa4\xcad eK\x7f\xb9$aE\xb8\x0b]\xc6G\xcc\\lv 11\x0f\xf6\x8aB;\xee*\xdd\x92|\x1b\x913S\x8d\xc1\x17\x1c\xceA\xa1p\xb0\xf56\xad\xad\xb7U(\x9d6\xaa\x1e\xf8$\x9f4z\xe8/\x0bg\x0c\xa5\xc1Y\x98y\xcf\x08\xa7\x92\x08\x1dI\x8c\xb6\xe2\x9dye\xa86M\xd5OT\xc2*_\xb8\x84\x9f\x05\xec\xe4\xb6\x00\xf5(sF\x1d\xe8\x9cl\xd4\xee\n\x00=;F\xf7jbPL\xd9\x95\xe6\"\xe9}\xd3\x85\xef\xaa3A\xa7\x87\x1b\x0e\xf3\xa2S\xcd\x89o\x9a\x90\xda\xef\xc1\xe0\x93j\xf4}\x00\xd6\xc3t\x00\xab\x0f-\x0bN\x992\x86PG\x06\xc4U\xa7\xeb7\xc32b\xb36d\xb0\x15\x17\xf33\x8b, \xe9N1$G\x05\xce\xde%\x0d/\xad\xc6\x06\x1e\xc3\xc6\xd29}g_\x0b\x10\x1b\xcc\xa2\xa7\xc6\xf8[q\x898\\C\nSzE\xe1\x0c\xd2*\x19\x93\xc5\x0bt\x8b%Z/\x9c&\xe4\x8b\xec\xa9\x19u\x9b\xc0/s\xb2\x88\xce\xb1\xb0]\xbd\x0c\xc6\xb7W9Y\xcc\xc0\xf9K\xf5\x12\x8e\xc6\xa2\xd9\x8a\xde0\xda\xa1'\x1a\xb6\xfe\xdbR\xb0&\x08&\xca\x8f\xfeM\xe0\x1bVUDM1o5\x0c\xfa?\xa5u\x9cv\x01L*\x0b!J01\xc9\x1eHm&\xad;\x03\xe5[\x83SI_\xa4\xb3\x12D\xa4\x04\xc7Z\xe4\x10\xd2\xc6\xae^\xc9\xcd\xfa1\x1a\xbe?i$.H\xbcS\xfe\x077VQ!\xb0=\xaf\xff%\xf9\xc4\xe5\xf9}\xde\xea\xc7\xe5S\xf964\xb1\xa8\xed\xed*'\x91\xcc\xc3\x98\x8fb\xe4\x9e$\xc8\xdc\xc0\x1e{[V\xe4\xbf=\xab\xd7\x8a\x81\xd7\x1d8I#\xd7\x83\x89Y\xc7\xa1\x9b\x98tJ\xcev\xe2\x9fc\x8fnE\xdd\x99\xc3(\xa5\xe6\x0c1\x9a\x99\x81\x87J\xffB\xa2\xe5\xaa\x9cAN\xb9\x9dy\x1a\xb3,\xa4I\x9a\xaf}m\xfc\x9ez\xec\xb2\xe4\x00j\xf0\x96wl\x9c\x06\xef\xaad\x04\x94e\x1b\xee\x05l%z\x08\x9f\x0b;\xe9\x83\xce\xca$\xf6\xe7$\xc6\xf3HQ#|\x0cI\xdbT\xbc\xb3/\x03(\xdbW'\x1f\xb4\xb0=\xd8\x1c\x1b\xff\x05\xd7B\xcb\xf84Y\xa4o\xf2\x18\x8f'\xfa\xfb{\xbf /\xfdr\xa5Q8JS+\xa4\xaa\xd4\n\x91*\xb5\x82\xafJ\xad\xb0Q\xa5V(T\xa9\x15\xe2Vj\x05\xb4C\xb7\x01\xea\xdc\x0b\xdcR=\xdd\xbf\x16\xa9\x17zsn\xc5\x11h\xdc(\xbeD%5\xe1\x86\x9eY\xab\xb4\xd0\xe8x\xd8\xa95\xe7\x8b\xb5\xd3q3(\x16\x84\xb64\xd9\xe4jR\xe4\x9c\x00E\x1dx\xf3\xea\x19\x96\xc1-\xd1g\xc1\x81\xb7\xbb$\x80\xd11\xb6vn\xd1\x06\x0c\x85O\x8c\xa5\xd0\x9b\x05\xb8\x12l\x053\xc6\xc2\x00\xac\x85\x81\x98\x0b\x15\xf6\x86~i\x90\x89\x93\x01\x1aM\x00h:\x9e\xf3\x94\x9c\x7f\xfc\x01N\xb9\"\x10\x92-\x89\xe9\xc9c\x905\xd3\xfa\x0b\x14\x93-\x14|\x1c\x9a\xac\xfd\xc8\x08\xefc\xf2<\x87\xb2p\x16\xf1\x1fV\x8cL\xaa\x15/mX\x1e\xa3\x86\x8aq\x94.\x96\xf5*\xfc$*\xa3\x7f\x937y\x99%r\x90\xfb\xbb\x9d8\xc5\x14\x9e\x945\xd4\xb1\xf3L\xb5\xb9\xc9c\x1d\x10\xb3\xd3\x08\xee\xc4\xe4\xe5^\xa2\x0c\xa9\x83bR[S\xca\xd3A\xc7\xcc\xea\x83L\xee\x15x\xcdc\xee\x98\xbc\xcaV\xa8\xa6\xe1\xb1\x8e\x86\xd3\xdeh\xf99\xe4\x984\x829c\x085\x06\xbc\x9a\x19\xd4\x9cZ\xcd9\xd4\xba\x91\xb6\xcfA\x85\xa3\x8d\xfa\xa4\xb8\x949\xb9y8\xb0\xda\xfe\xd7\xedp(T\x87C\xa1:\x1c\n\xd5\xe1P\xa8\x0e\x87\x82\x1d\x0e2\x92_||\x92\xaf\xd7\xa0\x7f!\xf9\xe2\xb2%\xf9\xc2/v\x97 Z\xc6\x1cXo\xa1\xf8Zn\xa1\xeb\xc1_\xf5\xf7\xd6\x17v\xea\xcf\xb2\xb7v\xd6/4u\x0b\x8b4Ugp\xfa\x8f;\xf7\xae\xc7\xa6\x157\xffDB\xd1\x97\x94B\xda\x94BO0\x9f9K\xff`4\xe5\x03\x9fO\x1ed\xd7\xc8 $\x17\x06\"i\\\xf4&\x0b\xfd\x92\xb0\x86e\xc6\xdbO\x9e{\xe8\xd2d\xf2\x03K\x9d\x83\x82\xae\xa5\x96\xfdG\xa9\xd6\x90B\xe9\x8e\x13\xa7~\x18%K\x96\xd5\xb8\xf4\xf8\x9f\xc7\xa5_n\xb4B\"\xc5[g\xe1G1 \x07\xbf\x8bn\x85^\xb0\xc9s\x92\x94\x1cC\x0c\xd2\xeb\xef\xef\xb5\x82(\xba\xde\xb9\x1b\x0f\x0b\xea\xd1\x9e\xe5$tF\xdc\xdb\xb0y\xff/\xbe\xefk\xb3\xa07%W\xfa/\x8e\x0dmw{S\xfe\xbb\xaa\x1a\x7f5\x07$\x8e\x1f\xebU\xfaQ\xb2CN\xfa|XK rf\xaa'|\x9d\xce\xa3\x98\xcc`z0\xb4/N\x94d\x1b\xfbTCut$\x9f\x05\xfe\xba\xf2\xe5,\xf6\x03\xb2J\xe3\x90\xe43p\x18\xea\xc0\xfc\x02J\x7f\xa9y\xab\xbc\xc8\xd0\xbeE\xceu\xdf\xee%*j\x12M\xf5k\xd5\xc1_c\x8aS\xe6\x1b\xe2T\xd8\xe28\xa0U<\x84U\x81qs\x14\x94\xdcn\xf6\x81\x13x_O^*S\xf1R\x99\x8a\x97\xcaT\xbcT\xa6\xe2\xa5\xb2a%\xc53\xca\x15\xb4\xeeb`L\xa6\x89\x9cY\xe0\xc7\xa6\xfbR.,\xfb\xf8\\X\x08\x87\xf0\x84\xb7\xef!\xebAwO\xbb\xcf\xfa@\x1a\xe8\x84\xd7v\xf0\xa4yYse\xc0{\xa7\xe6\x96\xec8%\x11iK\xfb\xa4Wmn\x19|\xc4B\xa3K\xbf$\xd2\n\xae\xe2\x8a\x8a\xa30*\xbfO\xcfg\xb075\x12\x0bGI\xe4#\xc3.\x86+a\x80`P\x02F\x18\xc0\x13\x81H\x95\xc3\xd8?\xacq]4\xa7\xbef\x96\xac\xcdc\xaa\xd3dx\xb6E\x90\x8cD\x9boB;\x14U\xa2\xb7\xa1#\xf8d\xfel\x8c\xcf\x14\xe7\xde\xa34)6k]\xfeD\xa8\x9c\xd62?\xf7\xd7z@\xe6\xb5\x16\x15\xbcf\xb6\x1e8\x1a\xc2\x1eC\xe5\xb7\x96\xf9\xe5\xea\xb9E\x9a\x8e\xcd\x003\x0ep\n\xbfq\x9d\xefYE\x1c\x0dk\n\x9c\x82o\\\xe759/\xbf\xcb\x89o\x02\xcf\x18\xf8*Z\xae\xe2h\xb9*\x1f\xa5\xa1\xd1\x81,d\xef4R\xf0\x99\xde@\xef\xed\x08\x8bg\xe2Z\x91\x92\xe4\xbfD8[\xfe\xf7\x17OC\x92\x94Qy\xe1\xfa\xdc\xe7<\x1fyu\xd9\x94\xc2\x19s\xd3\xf7\xb3\xa8(Gn\xf7\xc8\xea^[,\xa7\xd9\xe8\x1c\xdb*\xae\xcf?\x9a\x93\xdf6\xa4(\x1f\xd9\xf7~\xddBb\xfai\xc4\xccN*Wq[\xf8,\xc8\xde\x98\xd5\x8c\x0c%\n\xd5\x03}\xfbK\xd1>\x12~=\xec\x05\x1c\xc2\x92\x89\xc7z\xc09\x02V\x07\x85\xd1[\xed\xca\xaa6\xcf\xd3\xf0b\x82X`\xf0zpB\xbf\xf4\x19\xe4\x04c6f\x907#8\xec\xdf\x8e\x92\xfa\xdd(\xd1\xd5\xfc\x1a\xc3\x9c.k\xaa\xa9\xae\xb9\xd8m\xb0\xa7\xa7\xc8\xf0\xc3\x0dpW\x0d\xeb\xa3\x03Q\xb2\xf5\xe3\x88e\x070\x0d\x8a\x93\xdf\x0b\x03\xadk\x8b\x0e+? c\xf2\x82\xdfT\x8f\x9d\xee\xbc\x0b:z\xd5\xc8\x8d\xce@\xaa\x91\x13\xab\n\xa3bp\x9a\x1ej\xca\xae\xee\x8e\x86\x13\x96\x91U_P[\x87\x11\x97i\x9b\x84Q\xa9mX\xd5h1\xa0\xc19\xa6\xa0(\x13\x08\xfc$ 1H\xd6\x86u\x04D%\xb50*\xd5PF\xeck\xa4\xa9(\xd3\xe52&O\x05\x99\xd1\xef\xbc\x87\xe0<\xc2\x1ebG\xe8+u\xd5\x02\xcd\xd2\xb3\x0c\x0e\xa6\xf9X\x95\xeb\xf8 \xd6q\xd8i\xbe\xdb\xf1N\xceKq\x8c\x89L\xb4\xc0\xca\x92\xa9?`\xf4U\xe3\xf8\xbf\xd5Oo;\xf1\xad\x89\xeb\xa9(\x81\xc1\xf9Z\x81\x9d\xad\xe4\xcb\x9a}\xa9L\xea\xd4\xbb\xab\xf0.k\xc7\x9c\xd4\x87\xd1\xaay\\\xf6D\x1eq|\n\xdf8m\x02\xe0\xf6\x04\xe0\xf8\xba\xef\xfd\xfe\xbe+\xbfW\xf3\x17\xca\x1f<\xaaz\x10V\xcf\xdf\xb7\x95\x03\xdb\xa6x\xda\xe5\x97\x9b\x98y\x05\x89\xd9\xfdY\xcdLDU\xde\x10T/\xa5B\xbd\xa4\xd0\x1cQ6\xf9\xe6\xf9:\xbe\x19y%)J*\xceJ\xe1(\x83\x8c\xcbf\x02D\xab\x08<\x84\x84\xc7\x80\xd0\x9e\x9e\x9e\xafYu\xb0\xe6M\x99\xe7P\xb4\x00\x97w~\xef\xf0\x10\n\x9db=\x86C\xd8C\x8e\x0f\x93\x17\xfe\xfe\x9e\x8e\xb2\x903M\xc4+HyLY5W'\x1c\xe1fW\xd4\xb0\x1e\x8d\x9b9\xf1\xf5\x9eH\xc5?\xd7\xb1V\xa1\xd7P\x06(\x12\x9cK\x94u@\xe2\x82\xe0\xdc\xb6\x92\xf3\x17x\x0c\xb8\x0e\xce\xb1\xaa[\xfa.i\xbb\x83L\x88\xacEMc\xda\xcf\xb5)\x0d\x17\xf8\xd97\xad7\x14\xd1I\xafXvK\xb7\xe3R\xae$J\xbcE\xe2E\xc9\x82\xe4\xc7X\xe2\x7f\xe4\xe6<\xdaF\x9dg\x8d\xbe\xb7\xa0h|\x8c=\x16/\xa6\xa8\xefT\xcc\x07+\xb0\xf0K\x1e\x95\xe4E\x12_H\xf3]*\xe6EL{kf\x14\n3\xa1\xf7Lj\x19B=~\n\xf4\xcf\xb5\xa44\x99q\xaf\xf0}\xa2\x90\x90\x0d\x8bOw\xd1i]bc\x0c\xa9|\xdc\xa7C\x06\xee\x92N\xed\x0e\xf8\xe3\x0f\x08G\x0c^\xfa\xf96\x03>\x14\xedl\xe8p\xde%\x98\x89\x82`\xa6\x1d\n\xac\x82\xa3\x84=\xa7Bl\xcb\xe0\xea\x95y\xb4vYA6\xbd!\xb6\xb1\x85\x95ek9\x99\xe8\xc7\xba(\xb0\xb3\xc3J\xea\x8eUh\xa8\xa6k\x0c3+\xd9\xf8;v\x8aURc\xbe\x14^\xc2\xfc\xa8\x0c\xc9\xef\xe5\x96\x8e\xeb\xe9J\x7f\xdd+\x10\xd0\x1f\x0f\xee\xdf\x1a\xfd9\x8a\x10\xfc\xf9\x1c\xc2\x189|\x92\x06\x9bK\x96 \xe2$\x88\x15\x94\xa1\x1cB\x98\x068\x0e\x8f\x9c\x93\xe0Q\xba^\xfbI\xe8:A\x9a]\x98Sd\xc9\xa8\xd4\x07\xf3\xcc\xf0\xb8\x12R\xcd\xb4\x95\x9ck\x88\xeb9%W\xe0\xfd\xae\x0e\xce\xac\x8bK:\x8fX\xee&\xd3\x17\xd5T\xb2]\xbf'\xa3\xd2dQ\xaa\xb3\xcb+\xdb)\xc9y\xe9\xe7D](\x11P\x14CTj)\xbb\xf0\x8ezrs\xe2\x87\x8c7b\xb6q5dk$tZ\xd4\xa0V\x89A[\xc52/\x91\x0bT\xb0E\xf2)\xfd\xa0\xe6\xf7\xebP0\xa7\x7f(m\xe8\xa14\x95\x9dJ\xf4\xc9\xf4\xbe\xecX\xa2O\x1eLUqlj\n$\xbc\xd1N$\xa5\x08(\xe3&\xab?U\xd9|\\gE\xfc\x90\xe4EW$\xa5\xe2h\xe9e\x9bb\xe52T\xc3\x84\x9d\xec\xef\xc9?\x9d\xb1x\x9d\xe5\xd1\xc5\x18N\xfe\xf8o\xce\xdf\xb0zf\x9d\xa1\x08n\xc0\xdf\x9c\xbf\x8dx|\xf4\x06M\x12*V\x93\x9e\xaa{\xfbrTC\xb1Wa@\x0e$9C\xc5U\xe6\x17\x8a\x8dP94.\xc6h{\xea\x9c\x1b\xdd)\xf2HR\xe6\x11)\xa8\x90\x04{.\x16\xba\xa1\xc7i\xe6%\xe4\xbctG#/L\x132\xfa\x9a\x8f\xc2d\x8e\xc4L`6\xd6\x91\x15\xefZ\xe3\xc8\x0d\xc7p`R\xcfS\x9e\xedd\xdfP\xa1b\x8dPS\x89#\xa6\xb8(\x12\xad\x1b\xab\xff\x038\xdd\xd5\xde\xc2\x0dpf\x98?m\xcdW[N\x0b\xfa\x84\x00\x02\xbf\x0cV\xa0>Yc\x86\x11\xb8\xc2}{\xc1{XD\x89\x1f\xc7\xaa\x15V\xaf=\xbd\x98\x12%\xf3\xf8\xa1\xd5\xf8\xed*\x06`h\x0e\xf8\xd6\x89GP\xae\xf2\xf4\x8c\xbb\x07u/\xc9<\xfc\x97\xfa/\xfaA\x8e\x8a\xf34\xbc\x90\xa5\xd6\xa1 \xcez\x13\x97Q\xe6\xe7\xe5\xcdE\x9a\xaf'\xa1_\xfa\xcc\xd1\nG\xe6\xbc|q\xfc\x9a\xfd\xdd\xdd\xbb\x1aNa\xa9\xd9\x8f\xc0-|:\xa7\x8e\xb9f_\x82q}\xaa\xfdy:\xc6\x8c\x1c\xf2\xfd\xc9&\x057\xe7\xc51\xf9\x8d\xefN\xdas\xf7\x14\x0e\xe1\xac\xbb;\x97\xc6\xdd |\xf4G\xfd\x8dw\xca7\xacq\xfb\x01\xcf\xf5qd\xdc\x82\xc0\xb7\xe1\x91v\x1b\x02\x9e\x08|\x0f>q0h>J\x8a\xd2O\x02\x92.j\xae\xdb{\x12\xa1\xb0\xd0\xda\xa0\xe7t\x83\x1e\xfe\xffq\x83z\x89\xbf&\xf4\xef\xaf\xcb\x8b\x8c\x1c\xb2{\xf4'\xdf\xb9(P\xf7\xde5\xeem\x90\xe25X\xedq\x10\x98\xb4?F\x8c\x91\xdb\x05m6\x9f\x1e\x9f\xe8\xb5\x87\xc1\xfcg\x8d=\x7f\xa6\xdf\xf3`\xd94\xf0}x!\xf6\xfe|\xe8\xabe\x0f\x1b\x94\xb7#E\xb5 \x84\x97\x13t\x07uo\xfe\xeb_\xc9\xcd\xe5\x18\x1c\xa7\xab\xd8\xe3\xe3/e\xe5\xac\xdb\x1c\x8d\xcf\xb9\x93[\x8aJz\x9b\x8f'\xc4^7F\xefK\xcc\xca\x97\x98\x95O\x11\xb32 Z%B\x95c\xb0\"k\xab\x9a\xd7\x0dp\xab\xcf\x0b\xf1#29\xd5 c\xa0.K\x1b\xb3\x072\xbeD\xc1/\xa0#\\U_\xb0\x1e\x19\xe2J~\x0dCiZ>\x98\x97\xad\xe3-Q\xde\x148\x01\n\xeb\x1f305\xd6\xff\x9aV\xf0n\xba\xa7\xb1\xd0\x17\x8e\x82H\x9b\xf8\x10\xebr\xdd*p\xcc\xa3\xdb\x1b\xb3x\xfd\xf2c\xff\x00\xca7\xbd\xd2\xad\xea\xbc~_\x91\xf64\xec\xa6\x993;\xae\xd4N+\xbcW\xc3\x95h\xc6\x94\xa3M\x1d\x17o\xc5T\x0e\xf2\x98wF[\x89\xc5\\\xe7[Q\x8c\xdb\xa8\xf6R\x16\x8a\xe1d\x16E\x92\x01u\xfcL\xebdY\xb2\x9b\xf7\xce\xa0Z`\x85\xbd\x95 \xb6%\xbbM[jw\x05\xdf\xf5\x8c\xaf\xf9\xc2\xf7} \xbe\xef\xcfg`\xfa\x14gF\xcd\"\x99\xce\x0d\xcb\xb0\x82|@\x90\x00s\xb1\xa8\xc2\x17\xf91\xac\xd1\x96D\xf8\x02'\xf6\xe6\xd8\xd8\x82\x04\x9b<*/\x1e\xd3}\x1d\x95\xa6Z\xc7t+\xe5\xc6x\xdf\x98A\xf9\x9br\x95\xe6\xd1\xbf\xc9\xf7%\xa5\xb0{\xdd@\xb6\xe6\x15\xb0W\xc4Qx\x05\xf60\x8c\xd4\xe5\xc5&\xff\xf8\x03\xfd\x9d\xae\xc4\xea\xc5\xbax\x890\xda\xcd\xb0\x96\x8a+\x89\xa3m\xce\x86z\"\x02m\xd7\x9a\\\x91>\x84\x94u\\\x9b\xdf\xaa\xb1\xad\xd4\xc6\xae\xcaAX\xb7z<~\xbaJq\xf5\x1f\x9b\xeb\xea\x93zo\xc8\xe3T\x03\xb7ht4P\x1f\xad\xd7\xd9wC\x15Xj\xad6\xd9~\xf8\x80\xd2\x88\xfbP\x89*\xf4\xa1\xc9\x87\n\x1a\xf94\xd2\xe45\xbe\xcchD\xfb\x9e+n\xac\xd3\x90\xc4\x942\x8da\x8f\x07\xaaz\xe4<\xf3\x93\x90\x84#\xa1\xea0\xb8\xc6\n\xf8Y\xff\x13\n\n\xd0\xdf\xc3\xf2\xe9\xdd\x98\xb4&\x18iW\xb5&\x87\x89\x11&\x10S\xc8\xe3\xc8\x94\x1a*S\xb8n=ZE\x9f\xba-\xcd F\x99[\xac\xfeK\xee$\xd8\x86\xeaOI7\x9a\xf7\xc3\xf0^6\x11\xbc\x1f\x8e\x0d[E!9&\xf1\xe2Er\x84\xd3j\xe2\xc5\xf4+\x0d\x15\x1bV\xa1\xb5B\xe7C\xf7D\xd2\x89\x07\xac\xf6F\xdes\x0c\x85!\x1a\x90\x0f\xad\xfd\x11s\x80N\xf0\xf5\x94T\xa3\x19\xb4cw\xd8\xaa\xb6\xf3\xf0 \xb8z\xd4\x82\x98p\x08\x991\x956P\x98|\xaa\xe8\xcd\xfe\xfc\xb2U\xe8b\xae.\xdcl\x88F'\xc1\x0c \xea\xf2\xb6\x0d\xb5\xde*\x8a\xc3\x9c$\x943\xfa(M\xebB\x0d\xcd\x0d\xc9\xc2\xcc\xaasM\xc3Q\xdaxi\x05\x9b\xbc@\xa5[\x96F\x892_\x1c\xf4\xb0\xb7\xba\xcb$\xe7?\xed\xe0v\x1fX\xab\x92\x04%\xaa\x1368\x8c\x8b\x95\xed\x12\x1eP\xe4\xd4\xc7\xa0\"|\x17S\xf6\xcb\xbf Ar\x985a\xbb\x87\xa7\x91J\xf5\x85\x02\x990\xb0h\x1d\xd1\x92\xe8\xb5\xee\xc1\xee\xfc\xeey\xde\xfb\x0e\x89k\xb0C\x1d\xaf\x0f$O\\\xf8i=\x10GO\x9b(v\xdc \xbb\x14\x87~\xbf\x1e\xd2\xf83\xf0\xf9\xbb\x96*\xc11\xfb\xa10\xdc_g\xe5\xe0\xe7!\xc1\xf8A\x19m\xc9k\x7f>\xc8VZ\x99aC\xbf\xf4\x0bR\xa2G\x8e\xfc\xc8\xb6\x92Q\xaa^\xa8\xd5\x12\xbd\xdb\x97\x13JP\x13\x98,\xa2\xa5\x02\x8a\x89%\x86\xc0\xce\x00\x13QW\xb9\x86\x9fS\n\xfc\n\xf9\xaa(Y*E\x18G\xc4\xef#\x8b\x18\xa0k\x1b\x12\xef\xc6\x0d\x97~\xba\x02\xb4HS\xd4\x98\xc1\x98R\xf9\xaa\x8d\x99\xc4\x83\xefc\x0b/W\xc9j7\xb2\xce\xb0-^\xffIg\xafq8\xb5\xe0ly\xef\xc6XG\xee\xc4\xd1\x90\xefG%Y#\x9fY\xd3\x9a\xc3\xc3ff\x9d\xc6\xd9\xf2\x10\x1c\xbe\xb3x^\x96\xc1}\xd3\x07\xadt\xba\x16G\xc9;U\x860\xa8\x92\xd9\xf0$8\x8e9\x9dJ[~\xa8\x86\xa5\x1aDD\xc7{\x14F%`\x8c)\xcb\xbe\xc1\x1a\xe1wX\x154\x8dqd\xd7\xa5\xe0\xe7\xc8\xf5Z\x08\xda\xb3\x88'\xe7i5n\xbbBlTW\xb6>l\xc7\xd6\xb9P\xcc\xb1Y<\x92\xcb\x8c\xe8_}\x05\xe9\x18\x8c\xcb\xa0\xa9\x84\xa65\x071b\xab\xad\x94\xd2.M\xa2\xa1\xf55 \xd5\xa6;h\x1d\x06\xda\xc4'\xa4\xa6\x993\xd0\x14\xb3\x14\x14Y\x97\xef\xb4\xf7\xc0(1~\xdef\xa4\x05\x15\xb1z\x12S\xca\x9f\xf4\xa4\xb2H\xbc\"\x13\xbe\x162\xa9l\xc3\x1f\xf4\xda(\xf8\x83\x9eT\x16K\x0dL(\xfe\xb8qS,W\x1b\x98\x16\x1f_<\xcbl\xc53\xbd\xcfn>\x06\xbf\x7f\x92wy\xdfk\xe3\xb3+\x92\x84ozb\xa2\xc2g7\xed\x8b\x8az\x9f\xdd\xbc6X\x1d\xb6\xb7\x8e\x8aG\xcde\x89\xe3\x01\xabE\xc92\xca\x17\xab\xf4\xcc=a\x94\xb3p\xc6@\xde\xd2o\xf7\xe9\xc0\x989Q\x8c\xbb\xe3\xa5+f\xe9\x0dSH\x85\x1a\xdfN\xa8\xb9\xe6\xbc\xbb\x0dc\x9c6\xf8V\xdd!\x1c\x19B\x9f\x9a\xda\xf8\xe6\x92V\xc7\x05J\xb2Q\xdb\xdb\xb7\x03\xe2E\xc5\xf1*=K\x9aK\xdf\x80\xa6\x1c\xc0[\xccB\xa0?\xa0\xed8\x12\xa6\"\x9d\xa7\xe7J\xdeX\xd5L:\xeejX~o\xa9\xfbu=h\x1e\xb4\xc6\xe3\x93\x84Z\x0f\x8e\x90\x9d\xae\x9ax\xb5ZYY2'P\xf6\xa7\xa9]~l\x97]C\x16\xde\xa7T\xa3\x9f\xf5\x06v<\xabc\xe3\x19\x9d\xe1]\xc3\x19\xed\xea\x1e\x82\xf2\x10\x07\xbe\xad\xd0^\xe2\xf06)g\n%\xc6\x9c\x89^\xcc\xa0c\x84\x16G5\xe7\x02\xfc\xa2\x88\x96h\x931\xeb,\xaa\xe3\x806<\xfd\x1aJ\xf8\xa6w*|\x0d%\xa5\xfcj4\xda\xf2<6\xf5\xa1Pj\x82\xed\xaa&s:\xb4d$\xba]%\xfd\xf6V~\xf1\xe2,\x11l\x0c\xd3\x16b\x04\x02\xeeZr\x92\xd3\x13(9\xc9\xdf\xdaF\xc2B\xe3x\xef\xe3D\x1f\x01S\x1bw\x89\xea\xc4&\xda\xc3\x06\x9aCN\xd8\x81\x9a\xc07PV\xb3\x9b\xe8g\x17\x1a+\\\x9e$\x860\xc6\xdc#\xc9fMr\x7f\x8e\xe7a\xebO,&1\xc6\x9a\x88t\xd3o\x04\xd0\xde\xfe\x18x\xf64\xba$X8\xd1\xcd\xbd\xb3<*+\x88\xd1X\xc1d\x12\xfa\xc1w\xe4B\x1a!\".\xdb\xa0<\xa8\x17\xaa\x9a\xff\x92\x87\x9fh\xa6\xa8\xe27(\xeb\xe66P\x89\xee=^ \x12\xd3B\xe5\xbd\x9c\x84\xe2\xea\xf7\xe5\xbd;\xeao\xb3\xc8\xa8\x8c\xae\xd0\"2\xd5\xb9\xb2\xe2U\x80G>\xee\xb9\xa4\x19\x92Z\x8eD$dB\xce\xe0\xf5EF\x8e\xf2<\xcd]\xe7\x91\x9f$i t\xcf\x80\xcf\x8e\x18\xf0\x0b\xf0\xab\xd6T\x825g\xcbT \xf8\xa014c\x87At\x9a4{\xf9\x8a,HN\x92@t\x956\x08+\xbfH\xfeV\xc2\x9c\x90\x04\xd0\xe5\xd4\x8f\xa3\x82\x840\x81b\x93\x91\xdc\x1d\xb5 \xe8\xb0H\xa8+\xb9\x0f\xf5\xfc\xee\x95h\x97N\x11m\x1d\xd8;\xc4\xcc\x9dt\xf2\x90\xc0V\x13\xd2z\xc2\x98}9\x8e@c\x9e\xdc\xa8\xcd\xba\xf2\xcd\xb1$\xe5K\x81|/\x16nd\xe9\x1e\x0dR\x0c\x1c\x82'\x18\xa5.\x1f\xd2W_\xb1\xc21\xa8\x84V\xa0\xcd1\x9dlz\xe0\xe6\xa4((\xf6\xae7E $*W$\x879a\x1fH\xf3\x06\x1e\x8d\x81\xe2\x99\x037\xaa\x86\x14\xabB\xea\xedX\x9fQ\x8c\x87q\xb1s\xad\xfd\xaaa\x97\xd2\xa4(\xf3\x0d\xe5\xcdL\x96o\xbb\xf8\x8c\x9a2\xea\x8b'\xd0K\xd0\xc2\x996b\x1fX7+\xda*M\xc9'.\x05M\x1cq\x87 \x97\xcfT\xd1\xc2(x\x08\xd2\xfb\x1c7f(\xb9\n\xb4<\x94\x8a)n4\x86\xa62b\x0c)\xbd\xa5-\xd7P\xac\xd2M\x1cV\xef\xbc\xc1l\xa5\x96\x95\x03\xb4\x019\x82\xf5\xc0\xed\xa1\x9d\xd7T\"\xaf\xc2\xb70\xa5s\xd5H\xeeY\xf3 \xd3\xb7\xf0\xb0\xfd\xe7\xacg\x1a\xef^Q+\x01;\xdd\xd7\xaa\x02P\xd0\xa03\xcc\x9f\x81\xa5p}\x910\x1f\x80\x9a$\xbc#\x17\x85\x9b#WNZu(F#\x8flI~Q\xb3\x8b\xdaC\xae\xd1b\xe2E\x05\xf2Ac\xb6y\xb2B\xc9\x0c\x01\xe2\x14\x1e\xfd\xedn\xa2\xb9I\xd1\xcf\x94\x9e\x03\xfd\xeeiW\x12:\xddKO\xa8\x9c\x1c\x9d\x10m\xc7\xe4{\xa0\x8f\xb4\x94S\xef\x18\x06\xbb\xc73\xf1\x9e\xae\xd7\x1b\xdc\xa5\xad$\xc3p\x08\xd1\x18H\x83\x89\x8f4\xbc\x8cNa\x06R\xa5\x19\xb4\x07\xf2\x9e%\x88t\xf7E\xdd\x1d|r\xdd\xb4z\xa14WR\xca\x9f\xdc\xef)\xe9\"\xfe\xa4\xa7\xef\xf3\xf9\x83\x9e\xbeo\xc3\x1f\xf4>U\xf0\x07=}_\xcc\x1f\xf4\xf4}\x81T\xdf\xb7@\xf0\xa0s7\xe3\x1f\xb9\xd7t*\x08\xd5\x8a\xc0\xf0\xe3+\x02\xf5e\x8c\x86(\x02\x15\xc1\xfb=\x97\x0c\xad\"0\x96*\x02\x83J\x11\x18\x8f\xc68\xd7\xfb_\xc3\x02\xbe\x81\xf8kXP\x81%8Y\xb4\x15\x81\x0b;E`a\xab\x08\x8c\xec\x15\x81\x01W\x04.yd\xb2\xff=\xaf\xa9n#\xc7\xf1>\n\xdd_\xcb\xaa\xe0E\xc5\x8b\xef\x8eoa\x01\x87\x93\xdak\xa0p\xc6<\x1e\xc7/\x1cz\xae\x9c8a\x1d1\xe5\xbc\xed\xb5\xf3\x9e\xf7\xeeQ\xc7\x13l@\xff\x1c\xe8\xab\x86\xf0\xb3,\x11\xde\x15h@\x15\x8aN\xce\x8f4\xe7G\xbc\xc0\x93\x1b\xbe\"E\x1aoIx\xbc\x99\x979!\xeeI\xb50\x1d\x85\xaed\x85\\\xbar\xf4\x900\xa5\x17(Z\nU\xdb\xf4\x02\xb1T\xa1\xba\xf9\x04\nU\xbd*\xd5F\xe5\xca\xb2\x1d:\xfaa3<\xcf\xfd\x80\xa0\x8d\x18\xb8#\xb9\xaa=F\xb8,\xa9\x90\x1dE\xb4\xebb\x94$$\x9f\x18z\xa7l\n\x1d&\xad\xdb\xda\x0d\xe1\x9c\x12k' z}\xa4\x99#\xa7\xcc\xb5\x9d\xb1\xcb|\x96\xc6\x98\xf8\xec/w\xef\xde5h\\\x17iR\x1e\xb3o:Q\xe9\xc7Q\xb0C\x9a4\xf5`\xc2\xfa\x90jp\x893GG\x99\x1a/\xa9`^h\xa7(\xdd\xe4\x01\x99\xc1\x91\xbc\xbb\xa3Q\x8d\x80\xe7\x94H\x9f\x8b<\xd0\xe7J\xc3\xb4\x95\x0fw\xc7i\xcf\xa2\x8e\x1b\x0bi2\xd9\xae\xd1=\xe9dj\x80\xa2\xf2\xe4\xa9\x8b\xa7\x8e/\xd8\xf2,'\x81_\xea\x99X\xe0\x02\xe6\nm\xa9^T\xa0I\xf5\x1d~\xe8\x9d\xc7\xad&\x85\x9b\x1b>\x91)\xf3\x1f5\xaf-\xe5\xdc\x03?\xfe.\x8e\x96\xc9\x0c\x9c2\xcd\x0c\xf8I\xaf\x8cr\xff\xc9\xf2\x15\xf7\x9c\xd8\xf7\x0e\xc8\xda\xc03\x1amQ,\x026\xf3(\xfe\xff\x82>\x19p\x08\xce<\x8dC=n\xeaw'\x08\xad\x84&\x0d\x04\xb4I\xca\x86G;Vk\xa5\xde~\xa6=\xa3\xef\x17\xa7\x1c\x99\xee\xfb9\xe7dv'\xcc`K\xa3\xa0A\xa7r\xdd\xb0AIy\x80\x1f<\x7f\xd7s:\xf6sc\xee\xb1\x0c\x81w\xef\xb9\xaa\xcb/\xc7\xddT\x00\x16(\xc7\x03\xbd\xd0V\x99\xc0\x0dp\xf0WN\x7f\x9d\xd2_\xbe\xae'F7\x07!\x0f\x1b-\xf1m\xbf\x00\x83\xd5\xab!\x9b\xf1:\x84\x0d\xcd\x00\x86+\x9a\xdb\xe2\x0e\x02\x81\xa1%\xeeIa\xf0 \xe0Q\xdc\x0b\xb8\xa1\xb3\xa8\x8dd\xd62\xf6\xa46\xa8U\x87\xcc\x99\xf1\xb8\xe7'\xe4\xff\xfc?\xa7\xfdV\xf9\xb1\x0f\xa4\xc4\xea@J\xf9\x81\xa4&\xb2\x18\x8dw>\xe1%b\xbd\"\x8e\x02B{s\xa0,\x08+\xae-/\n\x99\xc2CH\xbd2\xfd\xf1\xb8\xfa\x81S\x9a\xf2 \xb2\x8a\x80\xbc\x0c\x19\x07\xb1\xaf,\x1cU\xac\xc9\x074\x99\xb3{\xf7\xee\xe9i\x07h\xe9\x07\xd8\x1c \x0c\x97\x92K\x92G\x18:\xc6\xc1d\x12l\x86\xda\xf1\xfc\xf3U\xbb\x10\xd4\xbc\xaal\x7f\x1e\xd3\x13\xefX0\x816;\xd5f\xce\x9do\xe0\xef\xf0\xed\xa59]\xc9Q`\"\xd75\xa9\xd6EuZ\xd3\xe9>\x8d\x1e\xaa\x8c\xb5$\xd3\x82D\x1f\xabA\x8c\xe4\x19Is\xb5\xb2\xbf^\xe5z\xa2\x0e\x0c&\xdf\xda\xae\xe8\xaf\x1d\x8am\x88\x197\x91,\x1b\x1f)\xa4W\x9a\xd8\xed+E3\xb0F5\x18\x82n G9T@\xa2\x89\xd2\xdc\x8c\x19\xd5\xa0\x81n\x06\xa7 #\xca\x01(\x92\xad@W\xda\xfc\xe9*\xd1\x11U\xaa\x03\xd0\xf1\xa7/\xe8\xd8\xb8.\x89\x8eL\x9f\xfd\x99\xa3\xe3\xab\xabD\xc7$-\x07 \xa3\x01\xad>\xbf#\x11\x0d\x14Wv\x02\xbe\xba\xec XW\xff\xba\x94 \xa0\xaf\x08\x0e\xe2\xb4\xd0\x94K}\xef\xec\xe0G\x98\x19\xfd\x08\x99\xe1\xee\xba9Pe\xca\xcc\x90\x99\xd4M*\xe2O\xa41\xe4\x99*\x86^z\x971\xa8\xdc\xbc\xac\xdc\xc6\xa0\xf2\xf42\xbbR\x01W\xe1G\x83E\xffd&\xf4\xb7^\x94\x84\xe4\xfc\xc5\xc2\x95\xa4\x12j^\xa6\xd8\xa0%\xcf\xeci\xe1\xfa\x03\xdci\xac\x1c\xe0\xd6\x03\xdcw\xcc&y(p\xe7\xb1\xd2u\xc4\x81h\x02?\x83C\xd8R\xd2~\xb98\x17\xd8\xc5\xbb\x02\xe0\n\"l`wg\x06`\xedo/\x13\xe0d\xd5GK;3\xe8\xe7C\x1b\x9d\x0b\xb5\xeb\x82!\xc4\xaf\xf6L\xf0\xe1\x9bC\xd8\x18\xc8L\xbf\xc2\xd3\x89\xe7yo\xb5#pN\x9c1\xac\x85\xdem\xbd\x9b\xae\x1b:\xfa\xeef\x90\xa9Y\xdf\x0d\xd6:o\xa8\xcc\xb5:\xbd7\x98q\xc1\x18\x97\x05\x95\xe2\xb96\xe2\x98\xfbF\x8f\xd0\x7fX\xaa\xab)\xec\xcf~l\xb4R\nX\xceB\xc9+\x1d\x8aK\x91\xcb\x8a=\xaad\xce\x0c\x1e\xee\x1ej+\x0c\xfb\x1a\x13&m\xa9B\xa9K\xc5\x1b\xb6v\xa3\xa0\xda6C4\x11\x01=\xd4\xfc\x12\xe9\x8c\xc1>\xa51\xb4\xa4\xd8\x80K\xb1V\x078\x0bvN\xb4\x9ex\xd0\x10f\x0d\\\x87\x9dh\x0e\xb5\xe8\xeb\x1bU\x1fcpZ\xf17\xad\xe7\xbd\xbb\x1dy\x14o}\xb6\xb1mr\xc93UI\x9e\x91J\xf2\xf4U\x92\xe7F%y\x16*\xc9S]\xad \xeb\xc5qRy\xd4\xcd\xea0\x9c\xe9\xfe\xe7\"\x80\xde\x9d\xd3\xff]?\x19TR\x14\xa1/\xf4)e\xd0\xf4\x03\xc8\xa0;\xe6\xf8\x87\xeb\"\x83\xdaH\x89\xc9@i5\xddAZ5\xcb\x8a\xfe0Yqc+\xda\x16\x18D\xdb\x0d\x15\xd1{\x03\xb0d\xc4{\xe8\x9f\\E\xa4\x18J\x07\xa0\x06S\x9f\x0d$n\xc4yP\x81\xce\xc2K\x8d\x83/\xd2|\xedk\x95\xb6\xc0\xb7#\x7f\xe1|m\x94\xaa\xb654F\xaa\x1a\xc0\xd7\xd2 \x15\x9f\xfec\xc8\xa7\xb1\x1c\x1c|\x03\\\xa8d\xe1vKR\xd6\x0bG\xf7\xb6\xfeE\x94,\xafL\xf2\xc6\xa9\x19C%\x81\xf3\x95\xb8\x02\x11\x9cw\xf1\xa7\xb4\xdc\xb9\x97\x17\xde\xca/\xcc-\xe9\xe7\xeb\x14\x8fe\x18\x83i.)Y<_\xc7\xe8\xfa\xb7\xfa\x0f\xd9\x13vS\x07;m\x0c\xe3\x84\x83\x81\xf1h\xae\xbd\xf3?\xff\x8f\xfe\xcf\xc1\x14\xe2\xce\x0c\x9c1\x1c\x97y\x94,\xddT\xe7M\xdaL\x94T!\xe8Vw\xe6\x9e\x99&\x83K\xaa[\x03\xa7\xdf\xf2II4=\xbc\x9c\xc2\xcb\\\xfa\xeb:(\xbc\xc6Pz\xe2}I <}\x86\xa7k\x91\xe0I\x14Qj\x8d\xc3&\xd3\x13?\x1e\xfa\xd8\x92T\x8f\x7f\xf6%*\xd9\xb4z\x8c\x87\xc0\x15ef\xe2{\xb2\x97\x0d\xc9*\x05S\xd9\xd9yI3W\x92\x1c\xf9\xa2k\x80|}<\x8be:\xd5\x94?\xe8\xe9T#\xfe\xa0\xa7S\xf5\xf9\x83\x9eNu\xc3\x1f\xf4t\xaa\x05\x7f\xd0B\xf2X\x8d\xe4\xf1\xc7G\xf2\xe0\x8a\xb2\x14\xa5*\x05f\xcf\xbbF\xa6\xc0\xcc\x87+0\x95Y\x8a6R\xc5edR\\~\xb2,Ei\xf2:\xbfH7%\xa6\xdfV\x03'\x1c\xf8\x91\x9f\x04$6\x00\xe7\xcc\xab%\xf1\xe71 \xb5\x01\xfe\x86\xba\xdd\xea\xb3\xb1U\xa8<\xbf\x98\xa4\x1buT\xb7\xb6R\xfb|S\x96\xf6Y\xd1\x9dy\x99\x00o\xef\xf4\x94\xfe\x11\xe0\x84\xd8\x147\x97\x1f\xcb\x94\x0fd\x93\x8aa]\x1f\xaa\x9f6\x1dT\xd4\xfc\x1b\x83\xf3:\xbf\x80\xa8\x84tS\x82\xccdfp\xdd\xd4\x17\xf7\xaeX#V\x12\xaak?i\xe1\xe7\x0c\x9e\xf0\x1d\xd0\xa8\x86\xd6\x01o`\xa8\x19\x9c\xe3\xe8\x0c\xf6jc!&\xc8\xa8\x0f\x95\xebYp\xfc\xcb\xa1\xf2\xe5P\xb9\xbe\x87\xca\xfc\"\xf3\x0bC\x91\x16\xe2E\xc5\xf1\x99\xbf\\\x92\xfc\xc0t\x94\xb0\\?\x1a\x12\x86P~\\\xa4\xc7\xab\xf4L{\xe2\x94\xba\xc3\xa0\x19XP\x8f\xd6\x0bVQ\x1c\xe6$A\xa1\x0e\xcb\xfc\x98?bG\xa6\xb7$/\xa24\x99d\xb9\xbf\\\xfb\xca\x13,\x1d\x7f\x88\xe6NO\xd7\xa4(\xfc%\x01\xc5\xfd\xc9\xc4_\xcf\xa3\xe5&\xdd\xa8\x0b~X\xcd\xa5\x12hu\xab\x0e\x0ey\x83\xb4\x18\xca\x14\x18\xc6\xe2\n@]\xea\x06\x13\xc7\xa8>\x94\x99\xdb\n\xd2\x90\xd4\xad\x15\x0c\xf5X\"V? \xa9\xa4a\xf9j\x9a\x91\xc4\xcf\"\xf6\xea\"\"qXP6 IK\x98\x13\xc8rR\x90\xa4\xc4\x8a\xd4+\x02\x85\xbf&\xc0\xf1\x1c\xd2\x1c^d$\xf9\xee\xe5\xd3\xc6\xb8\xeeY\x8e\xdc9\xdedY\x9a\x97$\x14\x0b*z\xe7\xe7d\xc0\xf8\xf8\xd4\xa0\xf0\xf57\xe7\xc0\xdbw\xfeV\xcdR\xb9J\x0b\x02\xe5\xca/a\xed\x97\xc1j\xc0g\xf9\xb4\xcd\xe0\x96\xb7\xef%l\xf6\xdcE\x9a\x039\xf7\xd7YL\xc6\xbb~k\x1f\xbf5\xf2\x1c\x11\xd3BI\xb0\xc5\x16\xd5\xee\xf3\x0f\xb0\xdf\xae\xdf\xf6^GE\x11%\xcb\xcfgs;\xafWt\x87\xa5\xdb($a\xe3u\x08SR`\xad\xdd\"#A\xb4\xb8\x00\x9f\x1eoQg'X\xef$\xbe#\xa3$\x8c\x02\xbf$\xd5\xd7$\x1b\xb9\xdd\x00|\xd9\x83\x97\x11\x10Z5I\xed\x85\x04q\xf2\xcb<\x0e\xc5\xa6\x96=c|\xca\xe7\xc7\xfd_c\xd5\xe5\xe0\xdc\xf4l\x97\x0c\xd48\xae\xfd8\xae0Q \x96\xe5\xf2\x9cm\x12\x9a\xd9u\xb7\x03\x07\x13\xb6\xe3\x7f\xafY\x92v\x8a\xa0\x8f \xc9\x9eE\xc9\xbb\xcf]\xbd\xdd\x18\x87\x0d\xb2pq]\xa9\xde\x96F/1\xe1\xa0$\xe7\xe50$\xf3\x8d\xb8\x93\xa4\xa8\xe1\x96\x88V\xb5N\x05\x1e\x1a<5\xa11\xd9^\x96\x93-I\xca\xc7\xacG\xae\x84\x92*\xf3\x9b\xae\xb0\xa2[\x89\x15\xddn\xb2\xf4N\x0c\xb4\x8b\xd9&=>\xdbT\xe9g\xa9n\x1f\xe3j\xf7\x1d\x89)\xb6\xb9\xb8+F\xacLk\x0b\xa1s=B\xe7\xed\x19\x94O\x86R\x8a\xe6k\x1b\xd9\xb0RJ UU\xc1\xf3u\x9c\x143pVe\x99\xcdn\xde<;;\xf3\xcenyi\xbe\xbcy\xb0\xbf\xbf\x7f\x13_\x93\xbf\xf4\xcf8J\xdeI\xdf\x9c>x\xf0\xe0&\x16 \x94\xbc\xabM\xf0\x93\xa5\x05rc3p\xfcy\x91\xc6\x1be\xf9{^\x05QQ\xbcF\x94?\xdc\xef\xa3\x7f\x17\x99\xd5\xd3J\x16\x85\xc5\xbc^\xac\xe7i,\x9d\xdamD\xce\xbeO\xcfg\xe0\xec\xc3>\x1c\xd0\xff\x93\x0c\x06\x0bNm\x928\x0d\xdeu\xd3\xd3\xe9z\x97\xb1<\xe0\x12\xa4\x9b\x81\xf3|z\xc7\xbb\x0f\xf7\x7f\x98\xde\xfe\xf9\x8ew\xf7\xd1\xf46\x1cx\xf7\xf6o\xc1\xf4\xc0\xbb{\xf7\x0eLa\xba\x0fS\xb8\xe7\xdd\xbau\x1b\xa6p\x97?\xbd\x0bw\xbc\xbb?\xdf]\x1dl'\xde\xfd\xfd\xe9\xa3\xfbp\xcb\xbbw\xe76\xdc\xf7\xee=\xb8\x07\xb7\xe8K\xb7\x82\xa9w\xb0\x7f\x8b\x0e\x07\xf0\xd9\x01\x1cx\xd3\x07\x0f~\xbe\xff\xc3\xed`\xe2\xdd\xb9s\x0b\xf6'S\xf0\xee\xde\xbe;\x99\xc2\x14\x1fM\xef\x05\xfb\xe0\xdd\xb9\xfd\xc0\xbb}p\x9f\xde\xbb\xf5\xc0{p\x87>\xbd\xb5\x7f/\xa60\xf7\xbc[\xf7\xef=\xba\xe3\xdd\xbdw\x00\xd3\xfb\xde\xfd\xbbS\xb8\xeb\xdd\xb9\x03\xd3\x07p\xcf\x9b\xc2\xf4\xc1\xea\x8ew?\xa0\x9f\x80}\x98\xd2\xcfL\xe8W`J\xbf3\xa9>swB\xbf\x13xw\x0enO\xbc\xe9\xdd{\xde\x83;\xb7&\xde\xbd;\xec\x07m\xee\xee\xcf\x0fh\x97\x1eM\xef\xc1}\xdaG\x98\xde\xf5n\xdd9\x80\xfb\xc0&\xec\xdf\x9d\xf9\x1f\x8d>\xf8\xca_\x9bu\xff\x93\xac\xe0\xf3\xe9\x01\xdc\xff\xe1\xfe\xcfw\x10l\x10\n\x7f\x82\xd5\x97\xe4\xb9\xb8\xc4\xe2\xdf\xf6n\xdd\xbe\x0f\xd3\xdb\xde\xfd\xdb\x0f\x82\x89w\xfb\xee\x03\xfa\xff\x93\xa9wp ~\xdd}p\x0f\xf6\x9fQ4\x98z\xf7\xa7\x0f\xe2\xc9\x81w\xf7\xce\x94\n`\x07\xdaW\xf0Q\xe3\x1f\x04\xa0\x98B\x1f\xc7\x07\xde\xbd;\xf7'\xb7\xbc\xe9\x9d \xfd\xf9\x00\x7f\x1e\x04\xb2\x97\xee\x8b\x97\xaa\xdb\x80\xb7\xc5\xcf\xaa\x83\xf7\xbd\xe9\xfd[1vor\xcb\xdb\xbf5\x0dto\x80\xe8z\xf5\x9ca\x1a\xed\x1d\xf6\x89b\xc2\xf4\x0e]k\xf1;P\xbe\xf2)0AY,\xf7\x12\xf8p\xcb;\xb8\x03\xd3\xfdgw\xbd\xe9\xfe\x038\xf0\xee\xdc\x0f&\xde\xc1\xdd\xfb\x13\xef\xe0\x1e\xffqo\x1f\x17\xf7\xc1\xbd\x07\xe2\x81wo\x7f\x8a\xff}p\xf7\x01\xec\xc7\xf7\xbc\xfb\xb7\xe0\x9e\xf7`\xff~@!\xbc\x83{S\xfc\xef\xbd}:[\xf4\xc5x\xd2\x80\x99\x08 \xfa\xe9)\xb6\x83\xdf\x11\xed\xd2\x15\xec4\xfcL\xf4\xf3\xd3\xce\xfa\xa4\x1fyy\x89\xa9\xbf\xe7\xdd\x9e\xde\x07\x9c\xf8\xc0;\xb8w0\x11\x93\xc6~<\xb8\xf7\x00\xf6\x0b\x9c\xcc{\xfbS\x9c\xc8\xbb8\x91\x0f\xf6\xef\x03\x9d\xce\x00\x97@\xcc\x14\xfb\x81/q\xa0I\x05\xd4XQ\xfc\x14N8[\x81~\x93\xb8\xf3\xe9t\xc7\xd8\xc1\xc9=oz{\xfa\x81\xe6\xfd6\x1c\xdcV\xcd;/\xcbqe\xd3\xfd\x00\xeemo\xffp\xc7\xbb\x7f+\xbe\xe5!)\xba\xf3\xe0\xd9}\xb8\x1bO\xee\x02\xfb\xdf\xd4\xbb=\x9d\xd0\x7f\x9eQ(\x98\xde\xfa\xe1`\xfa\xf3\xbdO0t\x16\xf1~e#\xdf\x87\xe9\xfd\xd5\xed\xed\xe4`5\xb9\xbd=\xf8\xf7\xf3[pw{\xb0\x9a\xde\xff\xf9\xee\x0f\xb7\xfe\xbd\xbe\x05\xf7V\xd3\x83\xed\xe4\xe0\x87\xbb\xdb\xff\x8f\xbdw[r\xe4F\x16\x04\xdf\xfb+\x90l\x9d*\xb2x\xc9d\xd6E\x123\xb3\xb2\xd5j\xe9\xb4\xd6T\xdd2\xa9\xfa\xcc\xce\x90\xacj0\x08\x92\xa1\x8c\x9b\x10\x08ff 5\xd6\x0fk\xfb\x03\xbb\x0f;f\xbb/\xfb0k\xf3\xb2f\xfb\x0b\xf3)\xfd%kp\x07\x107D0\x98U\xea\xd3\xe7LS\xb2\xca\x08\x04.\x0e\xc0\xe1\xeep8\xdc\xcf\xeb\x9d\x1d|\x1c\xc5\x84Q\x18D\xfd\xf3O\x07\x13\x9a\xa6\xfe6\xaa\x9f+G\xfd\xe9\xd9Y\xd5\xa6\xd47\x1f\x9e9\xce\x95\xd5\x87\xe9s\xc7\xb9\xb2\xfa\xf0\xb4\xbaCK\xf1\xc3\xf3j\x13\x81\xf3F\xa5\xdd\x9b\xa9\xba\x9e}\xee0u\xdddA\x80\x9f\x9f\xbb\x82\xedxq\x18\xc6QH\xf9\x8d\xce4\xad\x1c\xc5\xba\xd4$\x9ekP\xd5\x0f\xce\x10R\xee\x91+\xf5\x19\xdeX\x04\xd1\xbb\xf5[\x0c\xd7\x95\xd0}\x8b~\xd6_D|\xc3\xe0\xc3|\xa9S\xfc(\xf0#\xf6*^3rEN\xa6\xa5T<\x0d\x85G\x9d\xbeR\"(\x1e\xba\xaa'\x9d\x8aJv\x86\xa7\xa7\xe6\xc5\xb4x\x9f\xc4[N\x93\x9d\xfe\\x/\xa0S\xbd\xf7\x1b\xe7-\xa9^\n\xe6y=rrE\xc4}\xc2\xe2\x0d\xea\x8c\xfa\xa0\xb1\x19\xc1\xc1qOOWoP\xedL\xc4nIV\xe9\x89J\xa3:\xcd\x8b\xb9\xc9\xe6\xd7\xbb\xa6\x92c\x93\x9c\x056-\xad\x8d\xba\xbd\x1e\xef\xc1\xd5\xc9\x8c\xb3~0gK\x03O\xcaD\x1f\xae\x1e\xfe\xfc\xbe\xba\xa4`\x08r\xf3\x11\x95\xb5UY\xc5\xfb\xc5\xa6G\x84\x15*\x1c\x95j\xb2\xa0tR~\xa9Z\xcb\xfa+\xb80\xc9\x06D\xecx|\x0b\xfd\xfe\x8a\xf3\x98\xf7{\xff\x81\xc7\xd1\x96\xfc\x993\x85\xdet\x15\xb0?\xe3\xa1\xa4\x18\x11o\xc7\xbc\x1b\xb8\x9c\x7f\xea\xa1\x13\x8e\xea\xbd0\x8b\x9f\x18\xabF\x8d\x8cM\x1a\x8c\x88\x02[\xab\xe7!\x87V\xe4\xdc\xb0\xfb\xb4_\xfc6\x98lb\xfe\x15\xf5v\xb9-{m\xd5`sy\x99y\xb4\x84i\xc4\xa6\xcd\x1b\xd7Z\xbf\xbe3+\xc4\xd2\xaa\x10\xc6\xa6\x01W\xd4\xef\x8a\xb4\xde\xf93\x8a\xb8\x82\xc1\x87zj\xaa1\xa1\xfcp\x9dj\x06#\x8d\x99\x9e\xae\x18\xf29\xd5\x91\x16\xedU3\x1eK\xd3~4\x18\x91H\xd3\x89&@\xf4\xa1Z\xb7\xde\x01:!\xb6W\xd6\x94~@\x14\x86\xcea=\xe5\xf5\xa4RZG\xe4\x1b\xb3\xbc?\xe2\xb8D\x15\xbax6\xfa\xa0\xa1\xea\x06\xe2\x03\x06\x0c+\xee2l\xe0\xf7+\xe6B\xd1\xa7M\xe1u\x92 ?H\x0dC\xfe\x15\xf9(|\xbd\x81\xa1?u\x1e\x07\xf85%\xa6%\xb1)D\xfeE!\x01\x9c\x8e\xc4\xa6\x97[&~\xcb\x19U\x14<\xb6/\x0ebZ\xec\xb6\xaf$\xa7nS\xe3\xe0\xba\x9b\x98\x93\xbe\xe9e\x0e\xe1Hk\xfc\x03\x16m\xc5n\x04B\xca\xd9\x08D\x92^\xef\x82\xc4\xe3\xf1\xc5\x80P2\xbc\"|\xce\xe6\xfeR1@\xb6T\x8d\xf8\xc3!\xb6\x84]r#\"-\xcea\x1d\xfa\x8f\x0b\xf7x\x9a\x03>\x1c\xfa\xe4\x92\xc4\x17\x03\xd2\xc3\xa5\x80\x8e\xf3m\x17\xc85\xf6\xaa\x80\xa0\x06\x19U\x16s\x0ej`\x9a5\x8c\xc1Q#\xf0\x91\xb0s\xb2\xa3\xa9\x0bC\xd5\xa7,b\xa9G\x13\xf6j\xed\x92=U\x0e\xce\x92\x80z\xec\xabH\xf8\xc2g\xa9K\x12U\xd9\xb0\x9a\xdf\x8b0\xa8\x8b\xa4?\x17\xb4\xfa\x19J\"?e\xb1`o!\xa6\xd5a\xed~\xef2/\xf3rQ\xd8\x88\xbe\x1f\x95\xeb\x03\x95QG\xb2\xd3\xbb<-\xd4\xda#C\x92b\xf6r\xed\x1eR\xc4.5\xb2\xb9Xj9\xeb\x9a\xf4.\x13\xce^^\xaa\xe2P9\xed\xc3g-\x17\xc0u\xe6\xcbS\xf8zy\xaar\x16\x00 3\xd2\xebR\xb02\x0e\x1b\x16y\xae\x85=R2`\xe0\xe2\x0f\xdeH\x91F\x08\x1d;\x17\x8ekjkX\x1b\x8e\xc305\xeb\x93\x80F\xdb\xef8\xdb\xf8wu\xc9)Q\xe4\x9a\x86\xa9K(Q\xdf\xc1\xc9\x0c\xf8\x9f\xd1\x19'i\x12\xf8\xa2\x7f\xbaH\x87\xa7\xdb\xc1@\x87\xf2\x86H\xde\xbc\x1f\xe0\x12\xc6\x1e\xbe\xf5\xb2T\xc4\xe1\x88x\xf3\xb3\xe5\xc0\xfa\xb1p\xe5\x99\xab,\xcb\xca8\xd4\xed\x17U7\x1f\xe3\xd1\xe3U\xef1\x19\x92\x1d\x0c\xbb\xdf\x8f\xfb\x9b\xc1@\x8d\xf8\xe3\xde\xe3R)\xa7)ia\xc6\xd5\xbc\xad\xd5L\xc1\x0c\xf6\xa3\xc9\xce\xdf\xee\x02\x88p\xf4\xe8\x11)\xbcj\xc3\xd5B\xca\x88\xcc\x133\xd90\xeb\x1e\x15}o\x80n)\xfa\xf6\xd3\xa0\x15\x83\x1c\x88\xa1\x87DK\xeb\xd9d\xc7\xe8\xda\x8f\xb6\xb5%\xd8\xbabv\xaa\x0d@\xc7\xdd\xb7l\xcf\x02\xecb\xb95S\xf1\x91k\xd1Yum\xad\xef\xbap\x00c\xda\x1bM\xeev\"\x0c\xfe\x98\xc1\xb1\xed\xe5\x8e\x93\xd3\x97=X\\;\xfe\x12<\n8\x87k\x95\x05\x01\x13o\x03?\x15\xdd T\x168\x08S\xa1\xa2#G#\x0b\x9a\xa7\x13\xea\xf3\x05\x0b\xbbC\x17\xf8\xd5Y\xca+\xa9A\xd6\x0cU\xe0\xd7;\x19s%\xaa\xad\xdd\xc3\xd5&\x98\xaa\xb9v2\xc0\xdee\x1c\xe8e\x03\x95\x93\x97dJ\xae\xc9c\x92\n\xca\x05\xaeP\xf3 \x96&FTu#L \xbc#'!n\x99\x04E\xb5`[\xdf\xa9\xcfE\x06!\x80\x0c\\\x93\x1e\xa2bR\x9d\x99\xbc\xe6N\xe0\x9a\xe1<\xe9\x17jW;\xe659\x07\xe1\xf1%\x05\x1b\x10\x03\x07R*\xce6\x06\x06\x0c\xf3\x15\xbb(\"\x8c\xc1\x11\xcb\x8cV+\xf0C\xba\xed\"\xb2\x9b\x01|LR\xee\x95 M\xb9\xa7\x01\xad\x8fS\xf6\xd0!oX\xbd~\xb85Q\xcf\xfa\x8f \x0d\xf4hc-4P\xf3\x80\xcc\xd5$\xa0]1.\xe1\xc7\xbd\xc7\xeaO\x86\xeb\xbfH\xbf\xc9i\xaf\xb0\xd0+#\x04\x11D\xbb\xd3C\xc8^'\x16X\xcb\x113\xd5T\x8f\xe2\x81G@\xa3\xb27\xd5r\x0c4\x0d\xf5\xac\xe2\xf5\xfd\x11\xd0\xa8\xecM\xb5\x1c\x03MC=\xfc\x08Pxm\x9e\xf9Q p\xd7\xa8v\xa2\xd8\x1d\xb8\x94\xd8i.E\x03\x7f\x1bi\x0eu\xaf\xd6\x8d`wb\x0c\xa93\xa43\x98\xa3\xca\xac\xea\x90\x1d\xd3\xb7]\xad|\x1d\xe5\x1e\xda\xb3\xf5G\xee\xd9qh\xbc\xae\x96O\x05\x8f\x1d\xa2jc\x15\x98\xbf\xa1\x96# q\xd7s\x8c\xe0\xc5BG\xe9# \xa8\x97_\xb3\xa0{\xf3k\x16\xb8\xca\x1f\x01\x80\xa3\x06?J\xbbC\xe0G\xa9\xab\xfc\x11\x108j\x08)\xaf\x0b\x15\x8d5\xa8\xdc\xce\x1a\x8e\x00\xc2UG\x9a\xad\x0e\xad\xb5\x1c#\xb3U\xf3f\x1e>V\xebN\x8e\xa8;i\xab\xbb&`\xee(_\xaf\xb4.\xf1\x90D\xa1\x1b\xa9\xec\xa4Vj'\xb5\x88P\x12\\9\x88l\x1ao\xc4\xd1M@\x81\x94\\whM=\xd6);\xbb\x13\x1d\x07\xad2T\x95\xf1\x11a`N\xcb\xbaTV\xac\xaa^\x93\xa0\xdb\x0f\xae\x87\xaeVu\xae\xd9R\xd3\xe3KU\xe2\xa0\x14\xf7\xf2\xb1\xa3\x99#\x16\x85\xca_SB\xc5\xb1\x88b\xc1\xder\xb69\x04\xad\xe1D\x7f\xc8\xc2\x15\xe3\x08\x9f\xbf&C2\x1dLD\xac\x1d\x938N\x97\x95\x88\xdb\xdbD\x9cm\xc0\x10\xdb\xc9\xc4P\xea\xcdV\xdf\xac\xc9Kr\x06G\xa6\x9c\x0c\xafHof\xf5\x0c\xf0u0\"\x8f\xd5\n2\xea\x1f\x03\xffX\xd5\xfe\xd2\n\xfd\xbf\xdeD\x8fuL\xdf\xc7=\xe2\xaf\xaf\xac\xc4\xff\xb8\xf7rn>\xf5\x96Jxw.:;.\x80Y]wD\xba3eI\xf8\xf1\xe5\x8eW\xc1M\xc7)Kz\xb0N\x14\x1fn\xce\xa22\xc0\xec_\xa6\x0c\x9a\xaeeSY.\xe3\xa0^\\m\xa1\xa1|k\xcf\x8e\xc0\x9f8PM\x9dj@\xeaT\xc4\xd6|\x14\xea\x07>\xcc\x0fNX;j\xe1l\xd6\xa6\xde\x17,\xac-\x0e\x0b\xcc\x11\x1dt\xe9Kl=4\xf2v\xf1\xc1CE\xb3Fr|o\xefR\xd7\xc5\x105-\x06\x92\xe3|\x01\xe3\xabC\xb4\xa2\xde\x0d\xac\x90\xbf\xfe\xaf\xffM\xe1|e\xb0\xd6\xc7\xc8(\x0e\xcd\xd9\xfa\x08\xcd\xdbZ\xd4D\x9c#\xf6^\xeb\x9a\xb0\xb9>N>rC\x7fL\x0d\xc2Q\xc3Q\x02\xf3\xba\xb2\xe9+\x1f\x03\xa5\xe4\x8ad\xc5\xf3\xc3.\xcb\xa8_\xe4\xa4\x84\xf5]\xc4\xa9\x90}8\x8c\xc8\xcb+\"\xf4\xe9\x1a\x19\x93s\xc5\xc7\x15\x9b.+\xcaP\x13\x05\xd6\x07F\x0b\x85/FmU\xd2X\x89\xb9B\xbf\x82\xc6\xea\xac\x9c\xac\x99\xa5iU\x15\xafh\xcf\x8a\xf5\x9c\x97\xda\xd4 Z\xab\x85=Tip\xc5\xb9\xd4\xcf\xf78P\x03ri\x8f\x0f\xa1\xa9\x8a\n\xd5*\xd9\xecya\xaf.\xa7\xe4SS<\xa8\xcd \xf5\x03\x0f\xfa\xea\xc6]1\xb9\"\xf3\xda\x94\xcd{@\xa8{\xe8\xdb\xff\xec\xf9\xc0q\xf03\xef)\xden\xb2\xbcpg\xe1l\xc38\x8b<\x08\x13\x0f\x19?ug\xd4S\xaa3}\xe6\xced\xe9\xa2\xa0~`\xf2~\xde\x0c\xdc\xb9\xce3=k\x82\x0e\x8e-C\x16 \x03\xdft\xea\xce\x9a\x86\x94\x0b8\x06\xb49\xcf\xdd9\x03?\xba\xf17\xf7&\xd7\xd3\xc1\xb2\x94iy\xc4q\xbf\xc3z\xaahd\xc5\xcb\x84\xdc\x1ej+\x92pvA\x18\xb9$\xb1F\xc6\x0b\xc2\x86\xc3A\xa1\n\x8c$\x12\xcf\xd9r~\xb6\x1c\x11x\x98.]\xa6W\xc5\x03vm\xe5Q\"\x10.n\x84Gi.\xf8\x04\x9a\x02D\xe66X\x01\xa2-\x13\xdfg\x01K\xfb\xbd\xde``\xe1\x16\xe4\x92D\x17D(\xf0\xf9\\,\xfb\xac\xd1\x84\xe3\x03n\xc3\x95,A\x1a\xbb\xc6\x8a\x160\xd7\x84i;\x17\x1c\xcb:\xe1SC6\xb3\xd4\xcae\x01\xa9\x830\xb1I\xca=s\x88\xde?]D\xa7[\xbc\xf6:\x11\xdc\x0f]\xe2m\xc0\xf6,p\xde\xdeRm\xa532?\x1b\x91\xa9\x03?\xf3\xbb\xd8\xf32^\x82CWm\xc2h\x0c\x8f\x14X\xa3\xa2\xbd$\x9b\xb0h?\xb2\x1d\xff\xd8\xc6\xafO\xab\xb6\xaa\xdaJ\xe6y\x93\x91\x0c3\xa7\xb6\xbe\x0b\x0b)\x9c\xe6\xa6#\x12\x8c\xe0\x18\xbb~\x04\xfd\xec\x9c\x9c(\x82<\xf1v\x94\x7f\x19\xaf\xd9\x17\xa2\x7f\x96\x9f\x17\x8f\xa7\xf5\"\x9fO\xebE\xa6\xedE\xb4G}f\x1d\xe4\xf7\x96\xb3^{\x11j\x96x\xa1\x8b#2_\x0eF\xa4\x9f\xc1\xd5b:\"S\xe07gDJ\xf2\xfc\xb3:T\x19\xc8}\x8d\xcd\xc0r\x0c\xc8\x15\xa1\x93$N_\xd1\xbb\x11\x8a\x01\x8a\xc1]\x90\x94\\\x92@\xb1\xb0\xe9\x19\xd4L\x01E\x0b\xb5\xa7\x83\x0b\x92\x0e\x87naR\x873\x0c|\x8f\xf5\xcfG$\x1b\x8c4[\x86C}\xf3\x05\x9a\x1a\x91\xd4\xa0\xb9Y\xf4\xe4\x9a\x8c\xa7dF\xfa>l7\xd9\xde\xa7H\x07\xa5\xac\xa7)\xda8\x18\xe9;\xd8\xd0F%\xc7\x1c%Xo 2m\xe3\xc7+\xb2\x19(X\x1c\x14\xb0\x1bq(\xd0=\xf0'\x82Q=p\xa1\xb8\xccF\x0b\xb4\xa4~\xc9\xd8\xd2\xca)\xd2J\x9aKM\xd3\x12M\xac\x954\x0d8\x85*Z=\xde+\x89R\xd4\xca%\x8dR\x92\xaa\xc0J[.a\xcf\xfc\xa0\x03jY\xd3\x82\xc6\xe2\x82\xf0\x82pt\xd2\xef\xab\xf5\xed\xf7\xf9\xa8`R]\xa56\x88\xe3\x83\x8b\x01\x10 \xaeQ'68S\xb7\xd40\xbfb\xc3\xaa\xe4(o\\\xe1Q>\x14 \xde\xa1=c\xde=\x9bx\xc8[\xef/N\xf9\\6W\xcf\xa6U{B\xaa\xd3\xab\x86\xf8h\xed\xff\xec\xfc\xccIA\xd3\x9c\xbc\xd4\xccp\x14t\x9apB\xe4\x80\xf5\x88\xecFd?\"\xe1\x88l\xbb\xd1\xc5\x03\xa4\xf4\x01t1\xa8\xd3\xc5\xd4\xd0E\x0f\xe8b0\"g\xedt\xd1\xeb@\x17\x13rE\x02K\x17\x15\xd1\xf2\x90.n\xc8%\xc6p\xe8?=G\x8a\xb6\x86\xac\x15\xea\xb8Ac\x9c)R\xa4\xf5\xe0\x82lj\xb4\x12\xc8\x80\xaf\x00\xde\x1c\x80f\x0fM(\xc1R\xc7m\x1ca\xfc)\x03\xa4\x82px\xa5(\xc3G\x04\x0fZ\xb6\xf5\xed`\x1c7\xea\x91\"\xc8\xe4\x9a\xf4\xc3:`\x16(%O@\x86^\x0fSw\x83\x02|\x1a<\x07d\x17\x03\x05\x8c\x93\xad\xd8\xd2\x9a)9J[\xde\xb1U\xbc\xacoX\xcdtD\xbcA\x99M\xa4\x93|s2\xdf\"w\xa8\xa6\xb9.\xbe\xe8\xb8\x9c\xa1\xc3\xe4\x0d\xfc?\xecK\xe9\x8a7m>\x1eS\xf1[\x99\n\x10\xccB\x17\xb4\xc7\x8eR\x92\xb6\xa1>\x92\xff\xf8\xc7\xf3\x9f\"g\xf1\x1b8K\xce\x99\xfc\x1agr\xf2\x1f\xffh\xfe\xe3\x1f\xe2?\xe9/\xc4\x7f\xfcv\xfe\xe3\xbb\xf8\x8f\xff7\xe5?\x0fA\xc1F\xfc\x83\x01\x8fpw\x07n>\xec\x0e.\"\x97\x84_\x90H\xed\xe0JX\x01\x08\x16\xcf\xa3\xe5\xc0\xce\xba\x99\x07\xbd\x03\x11f\x00]\xbb\x10\x91{\x8b\xfb\xd7\x1a\x0d\x90\xcaK\xdb\x0c\x18\x80\xfar\xc2{d\xb5\xf4\xa4b\xf8LJ\x0b\xd9\xaa\xd5\x816\xb1\xfc\xa2\x9a\xddx\xd6B}\xb5\xe8\xdfz\xc5c\x17\xa4\x06\x85\xf5\xc7\x8cB\n$t\x85\x8b\xe6F\x1cF2\x0f\xe8\x8a\x05#r2\x053\x1cGUE\xfdV\xb9\xae\xe9\x88$Z\xce\x0e\x14IMM5}`'z\xfb\xcc\x06#r\xb2\xa9^$\xd2\x93\x9d\x0f\x05\x18%\x0e\\\xdd\x04\x04\xa4\x96\xe4\x95K\x8c\x0en\xd6I\xbeaw\x9c\xc348Q\xd1\xdbpo8\xac}\x06/Q\xb9\xb2\x83:\x15\x1an0\xa0']\xe0%\x0e\x98[\xa0%\xfa\nmK\x90\xc3\x96\x0e\x11\xdd)\xdc% *^\x93>lG\xe7\xcbAG8+\xb4\xbf\x19\x12\x81\x0eh\xda\x82\xcdv\x006\xeb\x08V\xa3\x8e\xc6\xfc\xac\xae\xc6eEh~\x06\xa0\x96j\xac\xfa\xa50\x8c\x1f\x0c}\x95U~\x8cQ\x1d\x8f\xbd\x06\xb8\xe0\xe2\x8a\x82\x1eh\x02\xd0&\x886\xab\xd7x\xfei9\xc8\x97]\x91ji\x83\xf5l\x80\xf2\x8c\x9b\xd3\x9b\xdcs[,\x97@\xac\xf6<_$q\xd2\xcf\x03\xbe\xc4\xf9\xbe3\x8b\x04\x9cg]\x17\x13fJ\xac\xe1\xa8%\xe5p\xa3\x87p\xb5\x1c\x1f\xba\xe6\xf0\x98\xee\xe1\xab\x0e\x0e\xd6Z\xc3|\x1b\xccj\x98\x12\xb7\x14\xe2#G-\xf6\xc9\x1ft\xa3\x84\xc4\xd1\xcbC\xb8u\x10q\xea4\xb2\x96\xd2\x0567\x95n\x83\xae\x05\xb2\nT\x1f$W\xd9d\xbb\xbf\xe6\xcd^\xfdruo\x7f>\xee\x0f\x16\xf3\xc5\xf2\xe7\xf7\xc3\xeb'\x93O\x16o\xe4h\xf6\xeb\xcb\x93\xc5b9\x00E\xf0b\xf1\xc9\xb4\xf71\xf6\x10\x0ey\xa5\xb8\xbb\xef\xb0\xb7()\xcf\x1a\xb6\x0dy\xce\xef\xd9\xf6\xab\xbb\x04\xc4]\xb8&\xd4\x7f#\xe7=\x08\xd2\xb8\x88\xfa\x83\xf9\xf2\xf1\xa27\x19\x9d\\\x8f{\xfafO\xaf\x87\xc1\xb7\xb8\xb9\xdb\x83\xa6\x82\xcbA_\x95*_t\xaeC\xd31n\x97\x9d\x804[\xa5\x82\xf7\xa7\x0e\xbc\x1cL\xd2\x98w\x0cN\xaa\xeb+\x9ck\x9a\x13@W\xbd\xa5\xeeI\xec\xdf\xa0\xff\xc9\x03\xc7\xa5g\xe4\xa3\xc2h\xa3\x82\x04_\xfa\xeb\x11\xe9m{j\xe7\xbb\xb1\x92Q\x9e\x17E\x933$\x98\xbb\x92\xc0\x1e\xa3\xc0\xee\xa6+\xd5\xed\xdd\xce\x9c\xd5\xba\xf3\x93\xe2\x86\xb2\xafH>\x14\xb0\xd2{eo\xf9\x12\xe8\xb2\x18\x8f\x9bk#\x06\n\xc1\xee\x84\xdeLP\xbd\xd9\x1b\x1c\xdc\x1b\x9a\x9f\xd5\x80\x9f\x8d@OF\xf3\xdd\xc6f\x12\xd0T|\x13\xad\xd9\x1d~\xf7\xb4\x0c\xb7g\x81\x11\x8d/@|\xdfL\xd8\x1d\xf3\xfa\x19\xe8-\n\xa5^\xa2\xfa\xfc \x95-\xfe4e\x83N5\xd3\xd9\xe2\xcf\x8a%\x99\xde\x98\x06#\x92\xa0>\x8d\x0cI2\x9f.\xf5\xe0v\x08EG\x0e\xf1\x99\xe2\xef=\xb8q>\xbeo\xd6L\xadc\x07\xb5\xb6\xc5\xb1\xde\xb5\xb8\x91\xcc\xcf\x97\x1d\xa2\xe7\x91\xc3\xf2b\xf1\xf7\xd0\xee=d\xeaT\x0f\xba\x15\xf9\xdb\xcc\xce!>_\xfc\x1d\xe0\xf9\xc5\x9f\x82)\x80\x05\x93/\x921I\xe6O\x0d\x8a6\xabR\xcc/-ho\xfa\x01\xb9$Y!\xe1!\xfd}\xc8t\xd9\x95\xf6K,\xa9\x12aT\x04\x0d(\x8d\x91\x98}\xdd\xf4\xd9\x08\\\x1b\xa4#bR\x04\xea\xb4\xdb)\xe6\x07 7&\xd5\x1cZ\x9c.\x86c\xb9\x98,&rq\x8d\xff\xc9\x93\x93\x93\x139\x1a\xc9\xf1\xf8\xb4~\x98q\xba\xe8\xf7=)B\xc9e2X\x0cN\xb7~\xfd`\xa3>w\xde\x8c\xf4\xfe\xfb\x7fsL\x11W\x1f\xfe_\xc7\x87D}\xf8\x7f\x1c\x1fD8#\xbd\xbf\xfe/\xffw\xaf\xf4\xa5\xc1\xda\xa6\x8b4\x95\xcbQ.iIk\xab\x8a\xbe}\x1a\xe4\xa5\xd2\xde\xa8\xc8\nS\xcd\n\xd3&VXc\xc4v\xd3\x94v\xe7\xc7\x19)\x97;\xcc\x96I\x91\xed*,\xcd,\xdb\x85\x95 gQ9/U\xafx\xd0<\xc8Oz\xfa=<\xa3\xb9&\x01\x99\x91\xc0J\xc3\xf1\xa8\xdd\xf6\xac\xfa\xd3\xd2\x97?\x17\x13\x11\x7f\x1b\xdf2\xfe%MY\xbfbtS\xfc\xa9e\xc6'\x82\xa5\xa2O\x07\x16^Z0\xbf\x18\x8eA\xec\xfe\xef\xff_oPH\x9d\xfc|>z\x0f\x1f\xfe\xfa\x97\xffZ\xfc\xd2\x9f_\x9f,\x07\x7f\xfd\xcb\x7f\x85\x8f\x9fL'\x93\xfa\xd7\x9f\x9f\xe9\xb2\x9fL\xd5\x7f\xc5\x0c#[\xef\xa8T\xee\x8d\x9c\xbf\x19/\x07\xe3\xf1\xb8\xaf\x1e\xe4'\x83\xd3m\x085\xfc\xf5/\xff\xfb'\xe7\x95\xbc\x8bt0\x1e\xf7\x17i)\xdb\xffV\xcb6\x7f3^\xa4\xaa\xd2>>\xd5\xb3\x83\xff\x96\\mM?\x8an\xd5\x12\x8d\xf9\xe3\xde\xd2E\x1c }[\xa7\x08\xa7\xf3\xf1\"\xc5\xdd\xd1\xf2\xd4\xb5\xc3\xa2m\x16\x8a'}a\x0e\x02\x01\x7f\x8d`\x0e\xd3~\xe2#\x120\x85\xbc\x85N\xd6\xdb\xc8\x0e\x98^\xdb\xad\x04\xd0em\x10k\x13\x914WF\x91<\x80\xde\xf8\xceM\x9b=\x92\x1d\x91\xfb\x11Y\x8d\xc8\xdb\x11\xb9\xfd0\x82t\xab5\xbf\xab&\xc2\xb4\xd2\xc4`u.\xc5\x9a\xccFaK\xaer\x88a\xe8\xb60tx\xfct;\xdf\xea\x9c\xe4\xf2\x8al\x06\x17d;\x1e\xb7\x9c(\x99_a\x0c\xb6\n\xb9P\xae\xd2\x9b\x14\xd8_\xd9\x15<\xe8,[\xb1\x19v\xe1\x82(\xc1\xca\x03\xc2\x18\x97vAz\xe3\x13\xe3\x86\xc7\x1f\x0c.\xda\x87\xd9\xfc\xc0\xd7\x07\xb9\"'\xb4\xafPX\xefN\xc6d\xaa\x05\xc2\xd4\xeeW\xa6#rO\xaeH\xef1NL\n\xa6\x89\xa0:\xc0\xb2\x01\x1e[']\xe6\xc3\xfcT\xeb{U\xc3zDB\xf57\xe9\x06\xb5\xf9\xc1\xa0\xb4\xcdc_\xcd\x83\x9a\xcaQeJ\xc9f\xa0\xa7\xf4\xa8\x06\x89\x06z7I\xfdh\x1b0\x18\x8a{\xd5R\xa1r\x95\xb69f\x18\x8a\xbf\x1c\xe0{rM\xfao\xe7;\\j\xc5\xe3\xca\xcc\x91<\";\xb46\xc8\x89 Z\xc4\xce\xcf\x97\x15\xb6\x91\xf5\x0b\x02\x80\x9e`G\xb9\xa7K\xd0&\x7f\x0c\x10\xce\x1e\x08\xc2t\xa9X^qI\x1d^+\xae\x9fj\xca\x8f2V \xbe\xd1\xe5WW\x836\xfd\xf6\xe4\x9a\xdc\x1e\xb3\xcf1?\x18\xc5V\x1d\xb4\xeb\x97\xc4\xe9\xcc\x0e\xddQ%\x11ug\xc4\x11\x07\xbb\xed\xa7\xf7J\x9b\xce\x85\xc0j5T\x8b\x03VH\xff0\x02\xf4\xfe\xfa\x97\xff\xe2\x8a\xa0\xea\xfa\xbd',H\xd9G\xad\xfa\xa3\xee\xc1\xc0\xc0\xbc\xea\xf8\x15\xe4\xa9\xdb\xdb[\xf9\x1b\xb9\x98-N\x17\xa7N\xb9\xc9o\xd4L\x9f\xbe\xb9\\\x9c\xd2E\xfa\xe4\xe5\xa9\x91\x90\xda\xc5#Z3^7F\xe8s\x87^CX\x0b.7\x06\xab\xce&\xe82\xaa\xf9\x9c*\xe3\xc1\x8c\x9c4\xc4\xae`!\xf5[>\x8b[_\x08\xc6\x9b+\xd7\xf2\xf2\xd7Q!0g\xd3\xdd\x16\xf3Ko}\xe1\xed\x14\x92l\x99x}\x9f\xb0\xfeA\xa1\xc1\xa3)#\xbd\x8c\x07\xbd\xd9Add\xc7\xacy%\xb2\xccH4\x81\xc8dl\xfd\x9a\xddu\\\xf60\xaa\xd0\x83?\xf1\xc0\x11\xf9\xa6\xfak:w*\xfe\xe0\xc2n{6\x1c\x08\x98\xb5\xbf\xaf\xa1\xe8)\x90D\x0cjF\x18\x96\xafTB\xbf\xb0\xa3z\xa3s\x9c\xfa\xa3\x92[\x9b\xa6\x9f\xe3\x0c\xcc~j\xfcb63Sg\x8ez\xb9\xea\xb4\xe8\xf2\xf5\x11\x0b\xfc\xe8&\x9d\x11V\x1f\x12\x9a\x89X}U\xcb\xa4\x1c\x93\xda\x15L\xea\xd8\x8d\x0co:\x80*\xeee\n;\x80:|jg\x12eA\xab\xe2E\xdf\xc3i\xd8\xe3\x14,\x95\xee]\x96J\xce\xb1\xaemk\xee;\x1e|\x14\xb6+\xa0o\xb9\xffX\xe7\x1f\xb9\xdb\xa0\x1eXD\x822);\xea\x14\x04\xea\xd1\xb7\xd0\xb5\xdc\x9d\xabr\xb6 \x9f[Vw\xfa\xe6\x92\xce_.\xd2\xa5a\x0d\xdb\x01\x1a\x87\xea+\xa3\xbb\xf1xD\xfc~\x9a;\x18P\x89\xc3\xe1@\xc9\xc6\x90\x0bR\n\x9b\xaf\xbc\xad\x18k\xcc\xcbv\x01\x9e\xe8\x0e\xac\xe0\x90Q\xc9\xf9}\x85\x1b\x14.\x13(\xf4F\xa1\x7f5\xc91\xda\xee:l\xaf\xf6\xa5=e\x08\x05\xfb\x81\x82yo\x15\x06F\xbc;L\xf1\x88\x99tOo\xa3\xd7\xd0\x9a\xde\x11np\xc7\xba!\x97\xb6Y4\xbe\xcdM\xdf \xce%\x15\xec[\x05\xc6~\xbeYN2\x1e\xa0\xa6J\xdb%\x1b-\x1a|\xd4;T\xf5Y\xb5\xb4\x1e\x11\xef\x18\x12I\x1e\xa4\x0d'E\x8dx\x90\xab\xa5\x93\x8eJq\x92\x0b{\xebN\x05 \xb2\xc0C;f\x1d\x8c\x1d\xd1;m\xcc\xab\x87\xbf{9}`\xd5f&T\xfd\x99\x81\xe8p.E\xb4\x02\xf3\xa1#\xf1\xd0)\xb6\x98\xd6\xbd\xec\x91\xd3\xfb\xf0>\x15h\xe0\xd1\xd0\x8d\xc7\xdd\xe1\x0b\xd0\x92\x1eP=!\xc3|L\x0c\x91\xe8 \x0e\xa9_P8\xb4zh\x9f\x1f:\x8fG \xf2\xd1\xf3w_9\xbb\xcaJgWY\xf9\xec\xca\x1b\xd9\x834}vu\xb0\x9d\xf6m2\xee\xd5\x0eV\x82\xe7\x1e\xe3\xf1\x05pI\xadM9\xb9\xb2\x14\x9a\xe0\xadmC/\xe0Sf\xac\xd7/\x06\x8a-\xdb6:\xed\xe0\xf6:(\xe2\x88\xf89z\xc4\xfa\xe6+\x1a\xc0\xd9\xe2U\x8ew\xfa\xe4\xa4\xdc\xa1'\xe4\x0b\xcb\xc7&?\xa6\xd5\x8fg\x93\xe9\xf3\xc9\xd3Jj5\xd3\x97qr\xcf\xfd\xedN\xf4\xbd\x019?\x9b>'\xff\xcc\xd96\xe6\xf7\xe4\x7f\xa2^\xbcJ\xc9\xe5\x96\xb3\xedo\xd4?\xe3\x1f!e\xe2\xc5\xe1\xcbj5\xaf\xbeyM\xbe\xf5=\x16\xa5l=!\x85\x18\x86j\xdc\xd28\xe3\x1e\x83X\x86\x01\xe6IOC_\x8c\xf5\xcb$\xd9%\x07\xa0T\x15\xa6\xb3\xd3\xd3\xad/v\xd9JAp\xaa B\x80N\xdbF\xe1\xb4\xf4\x0e[\xd1Q\xd9\x80\xbd\xddF(\x9e\xfcI\xf8\x81q\xb0\xae\x9d\xe2W\xac\xc4\x9c\x02v\x9c_\x94v\x9fe\xc6Q*x\xe6\x89\x98\xcfH\\_\x88\x19\x0fR\xf7\xb6\xb5eG\x9b\xeff\x1d\x1f#v\xfb\x1f\xfch\x1d\xdf\xba?\x97\xb7\xda\xae\xcay\xa6\xd6.\x9b\xe9{3\xf5\x1c\xc5X\xac.'\xd0\"\x0c\xbe\xa3\x14\x9d\xf8\xe9\x97A\x9c\xa2\x13\x9ck\x18\x89WT\xec&!\xbd\xebGj\xaf2R\xd2\xfc\x0cvK#\xa2\x1d\nT\xfd\xd5\x17\x7f\xa0KC0\"\xe1\x8b{\x0b\xc51e\xf1\xeeV\xab.\x86\x98\xcb\x8bfz\xf5N\xf0\x07\xc1[\xdbP?\x0dJ\xd0\xb2OGX,\xcc\xce\x8cnV\xa5\xe9\x04\xb7F|\xb5\\\xef\xddX\x8d\xc0w\xc1mc\x8c\xa8\xb1\xfaU\xbe\xb6\nj\x0bf\x02w@\xa0,\xc8\xf3=\x94\xfb\x17\x1a\xe8\xa8\x03] s\x15\xef\x02#,=\xf74\x14\xc1\xb7j8bb\x19\x95\x93'\x1e\x0d\x02\x13%FS\xe9\xc1(\x8f\x86te\xa3! rM\x04\x99\x91\x13\xbco\n\xbe\\\xec\xe8\xa0V\x08\x8c\xc7\x05\xf1\xa3T\xd0\xc8S\x85\xe2\x89\" \xaf\xe9V\x15.\xfa\x83\x9a\xd9\xd1}m\x89R\x7f0Y\xa9\xa7>+\xfaY\xea2\x88%\xd23k\x16\x05\xcc\xcf\xa8V\x01\x86\x9c\xbc\xb6\x0e'\x83\xcd\xb1\xa3\x94 \xe0TH\x9a\xe4\xd0\x0cF\x8e\xb3\x0cw\x17^\x15i\xf8q}(\x90\xffc:Q(f{QH\x9b\x141\xbf\x99T \xcb\x85\n\xd5c3\xa9\xd5\x1c\x18r\xc2ssV\xcb\x91!\xb3~k\xce^b\xc2P\xa4\x90\xe2&.\x83#f\xe6u\x81q\x1e719\xcb=f^\xf2RvZ\xbe\x80\xdb\x11\x85\xc5\xd2<\x1f\x05\x81\x05j\xb3\xef-\xc3me\x14l_\xbf6\x17(\x88,H\x05\xcd\xfbQ\x83]Jy?\"1p\x99C\x9e\xb3H>n06}\x81j\xaa~U\xc0\x1c\x19t\xd6\xbe\x7f\xe2\xf2\xaa\xfd9\xcfPIS\xb2\xabS\xfa\xa4\xabTp\xea\x89WL\xec\xe2u\x07d\xc0\xa0f=S\xae\xd7\x05\xe1Ph\x9e\x1d\x1e\x04R\x94\xc3\"\xe2G*\x9b\x98\xech\xfa\xc7\xdb\xc8F\xa3\x8fP\x14a\xf3hI\xd0#X\x03\xfb6\xb8\xd8\x05Fv'X\xb4\xee\x08#\x80\x87\xf2\x1f\xcb\xc5\xfbf\xe4\xaan\xe7\xde7\xdc\xcc)m\x15\x1a\x16\x98\x91\x18AW]\x1b\x9b^a;\xd1\x1b\x00\x93*\xa4\x90\x0e\x13L@\xde)\x14\xd2\x81F\x90\x99R\xbe\xcd\xc01V\x83\x843(u\x01\xc2\x03\xb6\xce\x0d-\x81\x07q\x19\xe9$\xcd\x12\xc6a\x01\xe2\x0d\xe95\x0b\x98`\xe5\xae\x8c*;2\x8a\n\x84\xa8\xd3\\\x07\x81\x9f\xa4~:k\xdd\xa2\x17\x7f\xd6\xa4K\xebh^b\x90\x04\x98\x83(\x0b\x02%VD\xe4\x9a\xf4&\x93\x9e\x12~1\xbc\xa21\xf6Rl\x1f\xf4\xfcc\x12Y\xd5\xf1\x90D] \xb6V\xecvDN%\x0f\x7f\xc19\xbd/x\xe8\xd25\x0c\xf2\x8e\x18eq5r\x83\xf9\x15\x96\xa1\xdd\xeb\xb0\xceG\"\xc4\x9c\xbb\xc0\x1aU\xd2\x95m:j\xc5\x87q\xfd8\xcb1 p\xff\xe5\x8bh\xfd%MD\xc6\xd9\x11\x03s\"&\xdb ^\xd1\xc0\x11\x9e\xf1\xcfP\xed\xf7l\xcb\xee\xfeL\xc2,\x15dG\xf7\x8c\x88\x1d#\x8f\xb7\x8f\xc9&\xa0[\x92\xb2Z`F\xf3\xcbG\xac\xb23\xbc \xb8T\xc1@\x8a\x81\xcf\x00}\xb9\xb9\x80\x1f\xf1\x08\"\xe9\xad\xd9\xdd \xdf7Eh\xbf\x82\xe1(\x8c9\x94Jl\xb5\xdf\xb2\x1b\x8az#Pw}\x84\xeb\\\xc6H\xb9Wf\x99!}\xec\xe3m+W\xdc\xdc\xdb\x9d/X\x9aP\x8f\xc1\x08\xce\x08\x04dr\xec\x0f\x8a\xfa\x8e\xc3\xdb\x02\xb7\xde\xc5\x86+\x8d\x18W\xa0\x1a9#O\x90\xb2\x98\xf2\xfa\xd5\xb7\x9d\xf0\xcanw\xbb\x80V\xdc\x96\x08,\x86\xa1UE12\xa5\xf95\nb\x95\xe6\x8eiMJ\xd2\xeb\xc4\x81S&\xbe\x10\xe5\xbdb\x87\xbbkzC\xa3J\xa6\xfd\xc1\x9c-\xf30\xba]\x1a\xdd\xd6\x1b=\xba\xc5.\xed\xe8\xce\xa5]\x1a\xaa*xtK\xad\x0b\xa9\x82\x829\xfeu\x01n[\x07\xae\xcb PU\x06d\xe8\xc2\xebU)\x0c\xae\xf9\xb9G\xe4K\xc5>\xbb\x8cH\xb1U=\x92\xfd\x1e0\xdf^M\xc3I\x1a\xe4\xbb\xf5\xbass\xb9\x9a\x0d\xd5hf\"\xa0\x82\xfe`\x94\xc7^\xac\x10\x14\xd4\xaf\xe9\xb9\xd0\xdc\x0bo\x11D\xe0\xf8\x1d\xefDr\xb5\x13W\x94\x17\xef/\x98\xc4\x0b\x98\xf4l\x92\xee\xfc\x8d\xe8+\x12<&\xb8\xed\xf7QrP\xdc\x9c\"\xc1l\xe2\x88n\x1c\x9d\x189\x85\x16\x03\xcfu\xc5\x0e\xce\xc2x\xcf\xfe\xee\x07\x8f\x16oX\x95FR\x0de\xbbv\x13\\p\xe2 _\xc0\xa8\xc3\xb1\n\x8e\xb7j\xc1c\xfdtD\x1c\xd7m\xc9!\x8d\xd9G\x9d\x89m}\xc9tY1\xb5\xe6;\x93\xe4\x1dM;\xcf\xbb\x15\x8e\xd0\x9a\xa3GzdX\x9d|\xb8(\xdc+\xdc\xa5\x81LL'w\x81(e\xe2\x1b\xc3?\x8f\x80\xaa\xc6\x89\x8f\xe3\x80\xae&\x8fk\xb1\xf3\x90\x1b\x1d\\\x87\x96J:\x8f\xa2\x16\xbcE\xe5`\xb2\x83\xce\x0f\xb0\xe2\x07\xc1\x0f\xf0\x96y\xef\xb2\x87\xd1\x95 \xaa \xf5\xdcb`2\xd2{\xd9\xcb\xa3\xf8\xda\x91R+\xbdwy\x8a\x05{/{\xcb\xa3T\xc7%\xf0:\x0c\x05\x8a\xcd\x96\x0bYA\xbe\x1a\xc5\xcb\xfc\xaaC\xa7\xd7G\xfb\xc0\xcd\x97\x87\x84j\xe2G\x84\x0d\x08sk\x03\x84\x16\x98\xc9\x90<\xc6\x08\x0b\xb0\xf5\xc0\xa8`\xed\xf4<\xa7\x16\xf5\xd1+\xa5\xbcW\xa2xMou\x84\x88\xfcQD\xdf\xceS\xdc\xa5\x89\xa2\xd6\xc9\xc8\xfcm\xbe?\x8c\xb4\xda\xa3-f\x06\x14\xe5\x1d\x98\x7f<\x0d@\x14`\x85\xd3+T\xb5\xe3X\xfe\x9e\xb3M\x7f\xd0\x82 ~N\"\xa0R\xedoZ\xcf\x04\xbb\x13\xfdBm\xa8\xb7oROt\x19\xbd\x02\xcc\x1d\x05f\xb3On\x1e9bm\x87Dc\x1e\x07(\xe6g\xf9:\xc2\xf6e\x8a\xbcC\xed&\xdb\xe6\x95\x1b\x13u\xa3K1\x1b'\xabA\xd5\x190\xb6!\xb9\"\xbd\xb7\xab\x80F7\xbd\xae\xaa\x942<]P\xae$\x81[-k\xfb\x12\x85\x93\x9a\xa1\xa5\x8dC\xd2\x1b#s\x9bu\xa4\xfc5\x8c\xe9\x02\xa9Uek`\xd7\xf1k\xadF\xae*f\x89\xbb\xd5\xbc\xc0\x11\xcd\x19b\xa2uT\xf6X\xce\xa8\xb0\x15\xbb\xc3@\x1e\x93\xef\xfe\xf8\xc37\xaf\xbf\xf9\x97\xaf\xde~\xf3\x87\xaf\xbf\xf9\xc37\xaf\xffc7\n\xe6<\xd69\x82\x8c\xa9\xf2z\x8f\x0f\x1a\xfe\xd3\xfe\xf5\xac7\x7f\xd3[>\xb9\xee\xc9\xc7\xf37\x8f\x97O\xae\x1f\xcb\xf9\x9b\xc7\xbd\xab\xcb\x97\x7f^\xa4\xcb\xe1\xe0\x14\x19\xdc\xe9\xfc\xcd\"]\x9c\xf5\x1e\xbf\\\x9c^-\xee\xce\xa6\xe3\xc5\xdd\xf4\xeb\xc5\xdd\xa7_/\x87\xa7\x134\x0fQ\xb3\xdb\xbf\x9e-\x16\xe9\x93+\xf5O\x0foM\xdao\x83\xeb\xde\xa8\xe8\xcbd\xaer+Vy\xd9?\xf9\xdd\x1f\xbf|\xfd\x1f\xbf\xfbj\xa0^u\xeab\x91\x0e\xf3W1\"= \xeeQ\n\x15\xaa\xcf\x83'\x86\xdb\xe2\xbb,Tq\xd9?\x85F{\xe0o\xe6t~6\xfe\x9c\x8e\xdf}1\xfeO\xcb\xfcq\xb6|rZ\xad\xb3\x0c\x81\xb0\xad\xa8^\x9d^\x17\xda\xcb\xf9\xf7\x88\xf4\xb6~\xcfE\x0b\xd5\xa0\x7f\xb9\xa3\x9cz\x82q\x13Q\xddhZ\xfa\x8f\xa2U\x9a\\\xc8G\xbf\x9e\xbe8\xbb\x90\x8f\x02\xa1\x9e\xe1q\x8b\x8f\xe7\x17\xf2\xd1OY\x0c/O\x9f\xc1\xbf\x9f_\xd4\xaf\xdb\xab\x1f\x989tA\xd8\xd2n\xa4\xb0\xf7\xb0\xf8Q\xb2\x8c\x98//PUzb|]\x82\xf2g\xfe\xf4@nE\x10ON\xc4A7\x1bAE\x93\x1b\x8f\x88\xd0\x9a\xbaf\xab\x81\xc0\xaa\x87\x91c\xa91Ut\xe7\x8bh\x0d\x93w\xff\x87x\xcdR0'\xf6At\xd1Zv\x7fD\xa2\x81M\xec\x17h\xfeWh\xa4\xa1\xca\xf5\xb5\x8f\x81\x81\xd6\x0d\n\xab\x1b\xa4M>\x86H\xe3fJ\x89wq!@\xc9\xa1\xa9\xf0\xaa\xc3\xd12\n^\xb7Q\xf0\xdc\xa3pD'4\xed\xf4\xbbP\xe5\x06(\x8e\xc3x\xad\xdf\x8dr\xb2Y\xd1I[\xba\xdd\xbcp\xf5~]\xaf\x8f\xc8*\xd79Z\x0eA\xd0\xb1\xf3C\xd3\x01{\xf89\xef\xb02\xa29\x07/\xb2\xcd\xd3E\x0b\x92t\x01\xf3\xd4X!\xda)\x84\xcb\xdc\x99\xf2\x91\xecg\x0f\x99\xba\xbaX\xd4(m\x14V\xc2\xd1'85\xc3\x86\xe2\xb2j\x11|Adh9\xe1\xb3\x92q\xc5\xe1Ds \x0f\xad\xa8\xaa!\x83\xcc\xef\x18Q5\x1f\xfb.H\xdc8\x12\xf9\x0c\x1e\x1c\x88\x0f\x06\xd9\xe0\xd4\x87\x00l\xf1\xf2\xe3\x81\xfb\xabr\x06\x87\xb4\xa4\x1a^\x9e\x8e\xb4S\xb0I\xffz\xe6G\x82\xf1\x08\xbc\xf4\xd1@Z\xf2\xe7\xc7\x91z\x01\x92\x14\xf3T2\x95-\xe1~\xcaR\x99\xecb\x81^i\xeee\xc2\xe35fO\xe5&\xce\xa25\xd4$\xfd0\x8cW~\xe0\xb3H\xfa\xd1:S}`\xa9\x0ciD\xb7\xb0VU\xb9\x84q%tI\xc1\xbc]\x14\x07\xf1\xf6^z;\xee\xa7\"\xa4\xa9\xf4\xe20\xcc\"_\xdc\xcb\xb5\xcf\x99\x82\xe1^\xb2u\xe6a\xf5\xec\xa7\xccO\xa0\x1e?J\x85/2\xc1dH\xf9\x0d\x13~\xb4\x95i\x1cd\x08\xd1\x9eb\x81T\xae(\xdfR_=\xc4\x99\xf0\x7f\xca\x98\\\xa1\xa20\x95j\xfb\xaedf\xe9\x05\x8cF\xf8\x10\x8b\x1d<\xc4a\x92 \xc6\xe5\x9a\x85\xb1\xc7\xa9\x90k\x9f\x86q\xb4N%\xf4\xdf\xf7R\xb9\x8b\x83\xb5\x1fmS\x19\xf8\xdb\x1d\xb4\x9fP.\"Us\x12d\xe1\n \xca\x92$\x80\xber\xeaC\x13{\x16)y4\x95\xd4\xa3k\x16\xdeK\x8fr\x06\xd0\xc4aB\xa3{\xe9\xf1\x0c\x06{\x1d\x87\x007\xbbK\xe2\x94\xad\xe5\x06\x9aI\xe5&\x88\xd5X\xc9-\x0d\x02\xc6\xef\xe56\xf3\x05\xe5\x00\x8e\xbf\xa6\xf7\xf2\xc6WX\x11\xc9\x88e\xa9\xa0\\\xc67~Do\xa9\xe4\xcc\xf3\x13\x96J\xce\"A\x03\xf5w\xef\xb3\xdbT\xa6;\xff&\xddQ\x89\xce R\x009\xe6B\xa6\xf7\xa9`a*\xe9\x96E\xde\xbd\\1\x1e\xf8\x91\xf4h\xc88\x95\x1e\xa0\x85\xf4\xe2\xcd\x861\x85/\xeb8\x95\n\x05\xa2\xadd\xa9\xa0\x82I\xa6z\n\xe03.\xe4&\x13\xab8\x9074\xdb\xb0H\x06\xd9]\xc6\xefeH\xfd4\x8ed\x18G4\xdd\xc90KY\x16\xca\x88n\xe3{\x8a\xb8\xa6\xa0L\xa8\xcf\xd5\x1f\x80)\xf6|\x1a\xe0\xa8\xdeKA\x85\x88c)|\x16\xad\xa9\x1a\xe1=\x0b\xe4\xde\xa7?\xb2T\xee\xfd \xa0\xeaO\xaa\xd0f\x1f\x03d\xfb\xf8\x9en\x99\x04\xccF4P\xa3\xbfN\xa5\xb7c4\x91\x9e\xdaw\xc85\x8d<&a\xd1\xcam@S5\xb2Y\xaa\xd0,\xda\xc62\xf2\xa3\x1f)L\xb4^\x0e2\xdd\xc5j\xd4\xe2\x80r)b5\x03\"\xbe\xb9\x8f\xa5\x88\xe3 \x95\xb7j\x8d\xca\xdb\x98\xdf\xa4\x922\x1eK\xca\x13*i\xeaS\xb9b\xa9\x90+\xff\x86\xc9U\x00h\xf9\xee\x9d\x1a\xdeDzA\xb6\x92^\x1c\xabU\x19'rCy(7~\xba\x93[\x7f#\xe46\xe3\x99\xf4\xa3M,\x7f\x8cW\xa9\xbc\xf1o}y\xc3\xd9Z\x064Z\xcb\xc0\x0fc\x19\xf8\xd1\x8d\x0cY\x94I\xb5\x18e\x18\xaf\xa9\x8ch\xc8d\xa2\xf06Q_\x938\x15\xf2\xa7$\x8e$\xf7\xbd\x9d\xe4\xd9\x8e\xcb\x94\xdd\xddK\xe1'\xa9\x1a/\xa6\xfe\x89\xe5-\x8d\xb6\xf2V-\xe7[\xff\xc6\x97\xef\xe2\x88\xa9%%W\xfeZ\xae|\x05\xf0J\xad#\xe9\xb1Xa\xb0Z\xaar\x1b\xef\xa5\x1f y\xe3\x872\xf4\x03\x191!\xe3(\x901\xdf\xaa\xe5/\x93l%\x15\xc0\x82\x052\x8bby\xcb\xd6\xf2\xee\xeeN\xde\xdd\xbf\x93\xd4\x93t-)\x93t#\xe9VR_\xd2@\xd2P\xd2H\xd2X\xd2\x9f$\xe5\x92\xa6\x92\nI3Io%\xbd\x93\xf4\x9d\\Q\xb9Z\xc9\xd5Z\xae\x98\\m\xe4j+W;\xb9\xf2\xe5\xeaG\xb9\n\xe5*\x92\xabX\xae\xb8\\\xa5r%\xe4j/W\xb7ru/W\n|\xe9y\xd2[Ko#\xbd\xad\xf4v\xd2\xf3\xa5w#\xbd@z\xa1\xf4\x14)\x94\x1e\x97^&\xbd\xbd\xf4n\xa5w'\xbd{\xe9\xbd\x93k&\xd7?\xca\xf5\x8d\\\x87r\x1d\xcb\xf5;\xc9<\xc9\x98d[\xc9\xb8d\xa9dB\xb2Ln|\xb9\xf9Qnn\xe4&\x94\x9bXn\xb8\xdcR\xb9]\xc9\xedZn\x99\xdcn\xe4v+\xb7jb\xe56\x90\xdbPn#\xb9M\xe4\xf6'\xb9\xe5r\x9b\xca\xad\x9an\xb9\xbd\x95\xdb{\xb9\xbb\x91\xbbP\xee\"\xb9\xe3r'\xe4.\x93\xfeZ\xfaL\xfa\x81\xf4C\xe9G\xd2\x8f\xa5\xff\x93\xf4\xb9\xf4S\xe9\x0b\xf9#\x93?\x86\xf2\xc7X\xfe\x98\xc8\x1b&o\xb6\xf2f'o|y\x13\xca\x9bH\xde$\xf2\x86\xcb\x9b[ys/o\xde\xc9\x80\xca`%\x03O\x06\xbe\x0cnd\xc0e\x90\xca@\xc8 \x93\xc1^\x06j\xa9\xca\xd0\x93\xe1Z\x86L\x86[\x19\xeedx#\xc3@\x86\xa1\x0c\xd5\n\x96a\"\xc3\x9fd\xc8e\x98\xcaP\xc80\x93\xe1^\x86\xb72\xbc\x93\xe1\xbd\x0c\xdf\xc9\x88\xca\xc8\x93\x11\x93\xd1FF[\x19\xf92\nd\x14\xcb(\x91\x11\x97Q&\xa3w2\x0eeBe\xc2d\xb2\x91\xc9V&;\x99\xdc\xc8$\x90I(\x93H&\\&\xa9L\x84Lner/\x7fR4M\xf2X\xf2T\xf2L\xf2[\x99R\x99\xaed\xea\xc9t-S&\xd3\xadLw2\xf5e\xfa\xa3Lod\x1a\xc84\x94i$\xd3X\xa6\\\xa6B\xa6\x99L\xf72\xbd\x93\xe9\xbdL\xdfI\xe1I\xb1\x96b#\xc5V\x8a\x9d\x14?Jq#E E(E$E,E\"\x05\x97BH\xb1\x97\xe2V\x8aw2\xa32\xdb\xca\xecFf\xa9\xcc\xeee\xf6N\xee\xa9\xdc{r\xcf\xe4~+\xf7\xbe\xdcGr\x9f\xc9\xdb\x8d\xbcM\xe5=\x93\xf7B\xbe\xa3\xf2](\xdf\xdd\x0e\x16\xab\xd3\xaa\xe6\xb47\"\xe8\xffoq\xbb\x1c\xfc\xa6\xbf\xb8\xfdy:\x9a>\x7f?0\xba\xcc\xb2:\x14r_\xcf\xe6\x8b\xf1\xc5\xec\xd1\xd5b\xb8\xf8d\xb4\xb8]L\x96\xc3\xdf\x14\nD\xf6\x897Ub4\xa3\xb6B\x94\x19\x96\xf3\xf1dh\xc5\x87\xe5p\xd6\xbf>i\xfa\xb48]\x9c\x0e\xfa\xd7'\x8b\xf5pqz=\xe8_c\xca\xb5\x13\x90\xbaJ\xb7?\xb9>E\xa5\xaej\xff\xf6\xf6v19\xbadsG\xad\xf6\x17\xd4\xc5\x8b\xb1\x05|\xf8\xe87\xbf^\x9c\xfe\xd3\xd5\x7f~\xdb\x1f\xc8\xc7\x9f\x80@Tg\xe1O\xbc\x0du\xc8\x11\xb3@\x8c\x0f\xaf\x03y\x12=\x1a\x7f\xe2\x81&-''Y\xb7\"\xdf\xb3\x80\n\x7f\xcfl\xb9\xcd\x81S\xc8\xa3/\xfa\x117\x99$\x87NX\x9a\x87\xd0\xd2\xf7\x19I\x9a\xa1\xb54\x7fF\x1cZc\xf3\x0b\xb1\xdf\x0d\xc1~\xba\x10\xf7vj\xd4E\x08\x81\xdb\xe4\x03\xe3bX!\xf9\x17\xa2_\"W\x87\xf8\xb4\x00$\xc6\x95r\xba\xe8\x9fn\x0f\xdc\xb7\x8fJ\xf9\x07\xa7\xdb\x03<\x1b\xb9\x80\x0d\x0e#%9\x1b\x90K\xd2\x07\xf2\x14\x95\x92-!?9\xeb8\xa6$\x9fs\x87w8\x976\xf2UU0\xeb\xaa\x84\xf4#pK\xd5(X\xce\x17\xb7\xcb\x06\xc1rG\xd3\xaf\xb3 \xc8\x8b\x9a\"-\x12\xbf\xa3\x9a\x8c\xfb?x;\x16\xb2\x83\x15\xb8a\xf8\x0f1_\x7f\xa90d#\x18\xaf\x023\x9b\xbfY\xa4\xcb'\xd7\xa6JG\x15E\xe6\xdb]\x1e5\xd3S\x94\x06tM\x7f2\x1dR\xec\xca\xdcb\xc94!\xfa]\xcc\xd2?\xc4\xe2\xf7to)\xf6\x1f\xf9\xefb\xa1\xad\xd3Z\xb2\x7f!\xbee4\x15\x7f\x8c\x98\xe9q\xa5\x8c\x9f~S\x9b\xcc\x9c\x92\xf5]\xe7\xf1\xce\x13\x89r'\xba,\xd7\xea\x82\xd3](\xce\xeb`~\xb6,\x1f\xac\xb6J\xf1\xbd\x1f\xe9\x9e\xa6\x1e\xf7\x131Cg=0\xce\xbd\xfd\xaa\x9c\xd8\xa5G\x87\x86\xbe\xa3\x89\xa0\x9d\xf1\x13\x86\x8e\xe7\xd5\xfa\x07\xfb\x00\xc7:@\x9fw89c\x13A\xdb\x1avO\\\xded\xbbA^\xc7\x82\x87\x81\x7f\x827&NL\x0f\x9aWQ\xcdW\xac\xf99\x91\xa7\x0d\x05\xbb\xa0\x92\x01\xf3\x84\xd9\xf1m#Q\xcd\xc09\x88$\n#P\xf8\x08\n\xf9Q\xf6\xcf]\x06\xef\x01\xc7\xbc\xaf\x8abS\xd7C\xae\xc2\xbe\x18Jv\x84-7\xf5=\x06\xc2\xa2\xc1\xa6\xb3T\xe3<\xc1\x8e\xc3q\xf6W\x98\xc5\x8fs\xe6\x87\x1ej;\x8e\xc2W\xb8\x7f\xe9Zy\xbe\x1f\xecX\x7fq\x94\xbb6R\xf4g\xfb\xc0\x06\x1f\x80A\x0d\x8d4\xce\xa7\xde\x8a\xfd-fT\xef\xd5\xba\xce\xe9\xeb\xf2\xd6\xaek3E\x0d\x00\x96\xed\xd8\xde\x83\xe6\xd88N\xd3\x0d\x82\xe74;\xe1\x0f\x87\xe2\xb8\x89\xef\xfd\xa6k\x93\x8dh\xf0'\xfe\x80E\x9d\xf1\x00\xf7S\xb9\xc2\x13\xc6\xc3(\x8d\xfb\xa8\x00\xbe>uY\xc3VX\x91\xad\xa2A\x1e5\xf9\xbf\xe3,a\xd1\x9a\xad?\x96\xedI\xc6;S\x99?\xf1.4\xa6tO'\xe3\x0dJ\xa2\"\xb6:\xf7\xb8V\x80\xacn\x9ak\x1f\xec\x90\x94}\xc3d0\xa5=\xed+\x10\xcc\xbdGM\x05!\xf4}G\xaf \x0f\\*\xd0\xb2qv\x9e\xfb\xf4~D\xc3\xe4\x02\xe21=\xeav\xcd\xea\xd85R\xbd6\x05\xed?tN\x8c\xbe\xae\xa8P(\xe7\xc3\x05\xd1\x07\xe7XU\xb5\x83\xa3\xf8\x9f\xcc\x12\xc2\x12\xf6#^`}\xcd\xa9\x1f\xf8\xd1\xf6\x87\x80B\xcc\xf6.\xe3S\xae\xb6\x8bl\xe4V\xd1\x97\x17\xb7\xdb\xe1zS\xf3\xeeAy8,Nb\xd1\x19$\xc7X\x1e\x01J\xef\xb4M\xe1Q\xd4\xe0\x1a\x87\xab\xe3i'/F\x8a\xfa\xda\x94\xf7#\xedh\x11c$\xf16?\xa5\x1a\xb0x\x92\xfb\xe5\x84\xbb\xc0\xf9`\xbc7\xbeeFd\xbe\xc4(>\xfd\xa2\xdbx\x1d\x8a\xeaC\xa3a\x1b\x8c\xc8<\x0fa\xde\x1b\x91\x1e\x04\xa4\x86\xf02\xea-\xf0S\xd1s\x85(\x9d\x973Bm\x9f\x7f@m;\xaek9?\xfb\x80Z\xe0\x93\xaeg\xdaZ\x8f\xbb\xbc \xcbm\xea8\xaf\xd4\xd1\x00;\xa3k?\xda\x9aBO\x1f\xd0pP\xa9\xe3\x99{\xf6v\"\x0c\xa0.\x93\xef\xf9\x03\xda\x12t\x15\xd8\x1e~\xda\xa9\x87k\xb6)\x0em\x15m\xdc\x85\x8aPA\xb1\xcf+\x81\x0d\x97\xee\x98x\xd5\x05\x8a\x14<\x0b\xacW\xb6\x8a\xcb){\xdd\x81\xa1\x1b\x1bF.\x89o\xaf)\xb0\xe1pP\xa8BG\x92\x9f\xb3%\xc4\xe7\x82\x87\xe9\xd2%\x8e\xd1@\xcc\x08\xe6<\x87\xf3\x85\xf9r\xa0\xa9\xd2\xa0BzrJa\x9fh\xc1\xad\x11\x04\x82\xf0\xdf\xb1\xaa\x835\x87\xe6\xcd\xf6E{\xfb-\x00\xbee\xe2\xfb,`)\x1e\xa3\xa3\xa3\x04\xec$\xbaH\x10\xe8\x10\xe1dzA(\xb9\xd4GHl\x12\xf8\x91j\x98\"Q\xbd\xf1\x93\xaf\xc2D\xdc\x7f\xebG,\xedS\x08m@\xc9\xcb+\x12\xa1\x17\xfe\x93>\x9b\x88\x1fv\xfeF\xcc\xe9\x12\xae\xdb\xac\x82\x9bo\xa25\x8b\x84\xfb\xfa\x13\x00\xccq\xe0\xe1F\x08\xd4\x12\xcf\xf9Ru\x91\xc2\xf1\xe6\xc9tpA\xf8p\xe8\x90\x130\xea\x85\xf0\xb7;\xa1`\xcfF\x84M\xfc\x14@4\xb0[\xbe\x90\x19\xb9\xaa\x8f\x9dQ_\x07\xa6\xa7y1\xda\xa86W\x8da%#2\x1c\xdaAB\xaa\xa1\xb9RB9\x8b@\xe8\xad\xd7\xda\x12\x0e&\x1f\xe7\xda\xe7\n\x9f\xcaq\xa5\xcc\x0420S]D\x0bQ\x8b%\x99\x82q*W\x1f\xb3\xb3\xb3\xcf\x9e/\xe5|\x91\x9d?;\x7f\xb6\xc8\xce\xcf\xce?\xd3\x89\xd5R\x01\x94\xca\xce\xce\xe8\xd9i!,X\x111\xe1\x8e\x91\x03+G\x84W\xc7P\x81\xe8#\xa2\xb9<)\x03\x02\x94\x92\xe1>>\xb3\xc7\x02\xd5\x9b\xf3\xc0\xe55\xab7\xc2I0\x02'\x10\xb98\x9b\x8eHo\x11\xa9\x14\xabU\\\x88\xde \x8f^W.\x9f\x15\x18p\x93Z\x1b\xd6V}\x0e5\x94\xd3\xb3\x82p\xf2e\xbcf_\x88~4 \xd7:,,F\xf9\xf3t<\x14\x08\xfe\xa6P\xbf\xa7j\xe8i\xda\x00\xee\x85)\x19\x13o@\xfe\x89<3\xc7\xb5\x90\x08\xc5y\x95z\xe8\xd5\x8c>\x15\x99\xf1\x07k\xe6\xc1\xdc\xab\xd54\xa4\xef\x8f\x14q\xf3#f\xfe\xbe\xa2w\x05\x024*\x05\xb4Al\x1fz\x1epZ\x86U?@e\x18kM\x9a\xeb\xae\xae\x96\xab\xdf\x8a\x00\x9c\x0dj\xa8X\xac;\xdf7\xfd\xaa\x0e\x08/\xbaUD\x1e\xd6\x1a<\xa0\xb8Y\xc7\xfa\xe7li\xd5`(\x11\xb0\xa5\xa2\xbc\x85.\x14=\x9f\xbd\x1f\x95\xda,K\x1a\xadM\xd7]\xda\xeb\xfe\xa2(\x87g\x8f\xfdC\x90]V\x00\x1b\xa0\xe8w\xe1\xea%k\x83\xfa\x87\x84zGC\x9cr/\x978\x0d\xd0z\x15\xd9\x0c\x85%\xc8\x1e\x0c\xde\x97;\xca\xd3C\xaezKn1\x9d\x00F\xf6\xe4\xa9\x06\x19\x02\xfdA\xf0\xfd\x96z5w\xc2\x0e\x86\x0c\xd2\x1f\xb9\x04\x97\xf8\xa6n\x07\xdfP\x10\xbf$\x91#b/Z\xaa\x9d4\x0c\xf2x\xccr\xbb\x04\xa6\x96\xedq\xdd\xd92Q\xc7\xdeV \xa9j\x19\xa98]],b\xb0\x8c\x1a=\x14\xa9,\x81\x82\xb6\xe2\x92\xd4/\xaf\xffy\xa0V\x01F5\xf0\xf1\x10\xce,\x87`9\x02\xb7\xad\x8acpr]Z\x19Pjj\x1c\xc1\xdb\xc4Q>\x82(\xc7\xa8~\x0c\x1c\x93\x91iQ\x05|\xb7\xf6\x05\x19\x83\xe1\xac\xf6 \x1a(\xd4\xbf \x81\xa2\xbc\xf1p8\x80\x88ne\xc8\x06j*Ax\x03&?\x18\x01\x07;\xb3)gZ\x1c\xaa\xf54\xc5\xfe\xe0\xc8\xa8\x15&e\xf7\xcee\xf3xY\\\n\x8d}\xd4c\x9d\xd5}UUD+\xb4\x8d;J\xb42\xa9\xee\x90\x83\xee%b\xf6\x82\x0e,2c*\x96j\x12\n\"\xcd%y\x96\x9b\xe3L\x1ds\x18\x03^\\\x81\x8f\x9a)\xee\xdb\x9aVW\xbe\x03\xe2j-\xb9x~\x8b\xdd\x1fl\x02rHy\x15\xd2\x97W\xe4Y\xfb\xc6J\x81:\x1c\x1er\x06k\xf5\x9cZ\x86\xe3\xa3<\xf6{C\x8c*\x1d\x8b\nUf\xb5\xaf6\xe6TN\x05\xd4\x96\"\x1e\x91g\xe0\xe8\xc5va\x04[\xd2ZyP\xc2\xb8\xaf'*\x10\xd3\x19\x99\x8b\x91\x86\xd7\xa1<\xd1\xe1\xab\x18\xca\x8c\xa5\xcf\xef\x95\xf0\x96\x8bI\xef\x7f\x194\xecN\xdf\\\xc7F\xe8|C/^\xb1\x84\x11\xb3\xc8Z\xcf\xbe\x81\xec\xccd\xaf\xa3\xbaG\x86\xe4)yI6\x8dh\xadrM\xcf_\xa0\xd7\x96\x18u\x1def\xe0\xa1\x82\xe3s\xcc\x13\xb7\xd6\x04\x92\xf7\x08%\xe7\xbeg5'\xc0\xda\xfa\x9e\xda\x03\x0d\xc8\x98\xa4\x03rI\x9e\xb6V\xa45\x159\xc5\x01C\xf9\x89\xe0~\xd8/\xeej\xff\xac7\xb5\xad\x95\xf1\x82\x8d]\x03a\x16\x17\xe4\xa4?\x1cf\xa8\xd1A\xc1 :\x90\x16g$+\xcdH\xb6\x04\x9b\xbe\xd2$\xa84P\x7f\xd8<5]P\x03\xb5\xa8\x8d:0\xb1\xb8\xa2[\xca\\\x84\x00\x04\xf8\xe6\xd1\x06\xe5R9\x0b\x8aj0\xb5\x10\xb0\xbe\x81\n\x01\x9a\x9e\xb9\xe9\x0b\x90\x9en\xd4\xc5\x87vs<\xce\xc9MF\x86\x8ae_\x03\xeb\x81\x93\xbfn\xc4\x07\x94\xf1\x0e\xea\x93PN\xc3tFhG\xc2\x84\x8a\x85\x0c\x16\xa7\x93\x1c\xfd{\xa29\xf5\xb0\xbb\xc7Q\x9b\xf0\x10\xb5\xd9\x93\x97$l]\x89/\xce\xb5\xb1[\x05\xdb\xf7\xc3\xe1\xa0\xb5\xa0\x1e\\\x85\xeey\xac\xdf\x90\xde\xfd\x81\xa5\xc2\x8f\xb6\x1f\xb2\xfc\xf5f\xa3\x0e\x13\xac\xe4\xbd\x92\xc84\x11\xc8Y\x17\xab\xeaA \xeaaa,\x01\xc9\xf3\x91\xbd\"{\x14\xce X\xed\x9e\\\x92\x10\xc2\x11\x15\xd6\xe2~@fd\x0f\xd4,D\x81m^\x98\x0d\xa8/\x17[T\x1d\xe3b\x0b#\xcd\x0bP-TS|\x17\x8e6\x8cO)\x94`b\xb3\xa39\xe9\xf7K\xe8\x10\x97\xd0!^\x02`\xfd\x12\n\xc4\xcb\xc1\x00\x03\xa09IZ\xfb\\7\x8b=~\xabXc\x03+\x9fLGpW\xe7\x0c\xaf\xa6l\xec&-!\x97d}A\x92C\xb1\x0b6\xf3d\xa9/eE\xb0\xfa\xdbt6\x04\xaeA4SC\xf3sSE\xf3k\xf6\xd0\xb5k\xedtf\\\xfd\xdb\xc9Q{\x14\x93\x98\xcf\xd1\xa88c\xa0A{\xfa\xf4\xd3:\x8dF\xc1\xb3\x03\xde;\xdb-\xa2\xc8\xf1x}\x18\xe8\x12f\xc7K\xc7\x8a\x0dH\xf9\xc0aT>~\xb8\xaa\x9c{v\xe4)y\x99\xa6\xa0\xc1\x9a\x19@\x84g1\".wue^P \xed\xfb~0\xca\x97\xa8\xd5K#\x11\x8f\xbb3\xbf\x02\xa0M\xf1om\x9c\xdb&\xa6T\x190\xc5\x1b\xe6\xd3\xa5=\x1d\xd2K\x0b\x17\x13\xcd\x97\x16F\xac\xd6s\x93\x90!\x01Z\x94\xcd\x93\"}\xb2\xe9t\x9e,\xdd\x8a\x83\x12\xf9L\xff.xd\x99\x17:\x0cJ\x0eq\xbf~F\x86%9Gm\xd8\xd3V\xce\xf4\xec\xbcE\xee\xce\x80N>zD\x9e=G\xc9\x1b\xa4\xf0\xe7\x07\xa4pX jEN/HF.I\xea<|\xac\x88\xd8\xb5Vm{O\x11B\xda\xd8\x1e\x01\xbfrVT\xf5\xab(\xef\x9a\xfe\x93\xbe\x8f\x1b\x80G\x8fH\xff\xe4\x84k\xbb\x10-\x13j\xa1\xac\xe3b\xd8\xf1\xe6\x85\xfaaR\xdb\xa0z:}\x14N\xda\xe4\xcai\x90\x0b \xf5\xf9\x90s\xa9\xf4y\x9b\x90\x86\\9.\xa3\xe6\x80\\\x93\xb1\x12\xa8\x0dzE\xae\x89\xe6\x15\xf4\x02)\xe0\xd9S\xfd\xack\xe0\xe4\xb2\x84\x07\xf5Zlc\xbc0Z\xf5\xce\xc7\xad\x9d?N\x0e\x8d\x0f\xadD\xf0\x83\xa8F&_&c\xd7\x1e\xb3e\\.\xc9\xb3\xcf\x14ZF\xe4%y\xfeic5\xa8em\\b\xbc\x1d\x08b\x15=m\xa0\xa8\x1d\xdegj\x0e\"ry\xa5\x80i\x13\x9e\x9e\xa1\xee3R\xb0?{a\xa2\xa6\xb6\x88\x16\x16\xb4\xda\xd7\xa6\xe3\xf7B\xa9\x07\xa2\x87yj\xa7\xd7\xb534p\x87\xd9\xb2\x9b\x19)\x01c;\"\xf7#\xb2\x1a\x91\xb7#r;\"_\x8d\xc8\xdd\x88\xfc0\"_\x8e\xc8\xcd\x88|\xe1\x10\xe1\x00\x15\x94\x08\xa9q\xd4(\x14\xb6\x8e\xbc\x0d\x1a;=\x89\xaa\x12^\xaa\xa4\x95lB\x03\xd3\x96Q\xfe\xd0\x8dO\xe8B\xaa\xb5\xbe\xcf\xed\xb7\xef\x8aV\xb8gG\x12l\xace\xb6\xe4\x1a\xef\x017\xafV\xd8T\xa2\xffj\xad\xd4\xd07\xca\xd5<\x911I\xf0~fg\xfa\x1e\xf35\xe3l\xfd6\xf0S\xd1$\x97A\x9e\x19\xd972\x82\xdb\x87KlJz\xed\x08\xea*\x0b\x02&Z!\xfdpx\xac\xc9\xd2[\xbd\x07\xbak\xdb\xf7\x81\x81\xce\xe0\x82\x9c\xf4O\xfa`\xb6\x836\x98\xb0\x81\xea\xdfW\xd5AkD[K[\xe9Rkf\xee\xc9\x98\xac\x958\xf3\x0cX\xb6*\xadPhG.\xc9\xb4\x94\xa2\xa4\xa8uQ~\xa7\n?v\x9dg\x1b\xc6\xce\x17,<0\x80_}\xc8\x00\x06\xd5\xdd<\xea\xc5\xc0H\xc1\xec\xf5\x0b\x08\xbdq\xec6\x8a;\xf1\xfb\xeaN\xbc,\xdd\x82e\x965\x808\xab\xefU\xb4}`\xd3\xc6\x00\xf7\xa6y%j\xaf\xfe\x16f\x11\x88\x99\x1a\xf5\xb7Vn'c\"\xc8K\x9c\x14\xa7=X\x15\xba\xa0\xda\x9b\xb4\x08\xaeW\x83v\xf3\x80\xa9|\xf0&\x050\xbd\xb0'\xf9\n\xb7(tD\xee+\xd2:\xd1\xa6xj\\\x8a\xa6g\xf8~\xbc]\xde\x8d^\\?\xa0\x82\xe1KrE\xee\xec.\xe8\x07rI\xbe\xbc ?4)\x18\x14\xe9\xbd\x9b\xffP\xb4\xe3kW.\xdc\x1cP,4+\x15\xea\n\x05\xd5\xf8M#\xc7W_\xb7m\xf2C\xce\x08)HAg\x83&Eo\xeev#\xe7{\xe52\xee\xe6C\xb7\xa4\xb0\xd6\xf7\xf6\xeb\xad5\x1cXuAB\xc5\xaf\xca\x1c\x04q\x91T\xa8\xf5\x831\xf4\xd6bdn\xc7\xa8\xa4\x8cG\x8f\xda\xcd\x0cHY\xf2G\x1c\x07>?$\xe7\xf5q\x03\x9c\x8c\xf4\xde\xe8\xdc\x08\xcc%\xe6L\xc6\xe4\xbc\x14\xb7\xd3f\x98GKcAevi\xb9\x851\xd2Y\xad\x08\xca\xf3\x0bm\xc6\xd9\xcf\x13U\xcb\xcb\n!+\x14(\xa4G\xe8\xd8\xbc1k\x97\x82\xa1\x7fO\x9b\x8bv$\x08\x99\xb6g\x1b\x92sT+\xf43\xb3\x0b\xf4\x14\x17x\xfe\x99{\x08\x87\xc3lPVDd\xc3\xa1\xc2m\x16\xed'\xe6VCjn\xae\x94\xd2 \\c-\xeb\x84\xb3\x8d3?~\xd0\x85R+\x9a\xe3\xf1f\x80\x0b;S\xcb\xb8\xa1\xcey\x0f\xae\xf0\xa6Km\x1a\xd9\x8d\x04\xda\x9b\x19o9\xdb0\xce\"\xafY\xbdIW\x8a\xda9\xe2\xe1\x1f\x14\xa9\xe2*?\xae\x1d\xf9\xd1\x03RTI\x10\xcd\x06d\x8c\x82S\xf1\x08%+\x0b/\xc3+\xf2\xac.M\x15.\xa2\x14\x1b(1~C\xd9\xec\xd7\xe1U\xedx\xc7\xb6;.}k\xd1\xe0\xe6\x82Z \"Z\x86z\xac\xa1.\xf6\xdd\xaf\xf64\xfe\x90\xd9}03SR\xca\x07\xe9\xbcL\xea\x07Q\xe7\xe3\xe8\xf2A\xad,\x9c\xe8\xb7ka\x9f>o\xd3\xc2\xe2\xb5\xb5\x03\xd5\xe4ZW\xb3\x16\x1cd\xe6\x82<}\x9e\xf3`P\xce\x82\xca\x94\\^\x91\x17\x17\x03\xe2\x83\xf1Wci\x17\xd5;\xe9\xfb\xe4%y\x81\x10\xea\xfa\xb4.&.S\xb5\xd4\xae1kg\xd8OG\xe4\xa9\":\xf9\xcd\x90\xfa\xf7\xe7\xea\xbb\xda\xfae$7\xcc\xac\x01H\xf3\xcb&`=?(\x08DG\xeas\xf1:W\x13\x8d\xda}\x8bX\xec\xb8\xc9\xfd\x11\x94\xbev\x0c;\x02\xebG\xaa\x9dv+\xa8\x9c\xc6CH\x1fm\xc2r\x084\x18\xb3\x07u\xd1\xdb\xf9\xc1\x1a\x1ci\xcd\x97\xb5\x0ev\xec\x97\x99\x84&R\xd26\x0b\xbf\xacZ\xdd\xa4>\xc4\x12pd\xee\xe1\x88F\x8bV{\xa7K\xcb\x10\xcd{GG\x86\x8aa\x8e=\xe0\xe8\xf7K\xec\x91\x96\x88\x1a\xd5:|\xbfH\xc8\xe8R\xcb$\xfdg\xcf\xf3\x8b\xb8\xb5U\x17#mz\x81:_\x8eE\xe2\xf2B\xee\xc7x\x17\xc6BQ`\xb31l\xd7\xfcb\xb9F\xb5^\xe1>\xdc/\xb0\x9cM\x17\xb4\xbe\xe9\xfca\xa8\x7f\x00\xf7:\x82|\xdc\xa2\x06V\x9d\x1f\xbd|\xdc\xe5\xad\xa8\xea\xbf\xf2\x12\xef03\x87W\xfc\xe0# \x16\x85;\xdfg\xe7\xd5\xbb\xdd\n\x81O\xdf\\\xf6\xe7:x\x9fvu=_\xa4\x8b\xd3\x97U\xd7n>f^\x9c:\xb2\xbf\\\x9ev#4#B]\xb4&?\xa0\xa8H\xc5\xb5\xa1\xab\xd8o\xd63$e1\xba.\xbbxJvMF\xe4$\xdf\xdc\xedD\x18\xb4\xca;\x89\xa2M\x8apx\xb0[zyu\xc0<\xf4\xc5\x99{\xeb\xe4\xb5\xef<\x9f\xe2\xa6\xae\x9f\xb9H\x97\xa7w\xae\x8a|a\xbe\xaci_Y8{._rz\xdfv\x1c\xf3\xecS\x00\x1a\xa4\x96\x93\x96\x1b)\xe6g.\xa5<='\xb2z\xf5\xc0\xfc4\x18`t\xf9\xf9\xa7\xaaf\xa1d\xb7\xe9\xf9y-\xfb\xfb.\xdb\xdeg\x9f6\xf7\x9c\xd8c\xa5\xeaV\x11-a\xd1\x95\x9e?(\xb6R\x87\"W\xd2\xb5\xd7\x13\x0f\x0eC{\x82h\xc0\xe7\xe9|Zq\xd6\xb7o\x0b\xd5m\xfcm\xc6\xa1U\xb5\xb3e\x1c\x9fx\xa8\xfe\xee\xa6\xf0\xef9\xfc\xfb\x14\xfe}\x06\xff>\x87\x7f_\xc0\xbf\x8c\xae\xb1\xd4\xce\xc2\x03\x1e2z\xfe\x86\xd3P\xbb\xc1P\xff\x86\x14>\xc6\xe0\xd9\x0f\x9e\x00\xd28\x13I\x06\xef\xf09A`\x12\x1eo9K\xa1\xf3\xe8b\x12\x9e\x98g\xe0N\xc5=\x8e\xa6\xf1\x11\xd1\x13f\xd8\x04tY\xb0;A9\xa3\xf0\xbc\xc1\x0b\xaf=\x01~'\x04\xc7gF!g\x06p\xec\xfd5\x8b{\xcb\xc9&\xe6_Qo\xd7o\xb9\x808g\xcb\xf2\x0dP\xad\x95\xfa\x90\x1b76\xb9\x8b\xf9\x8aCr\xcc\x95)\xb5u\xc0\xdb\xb6\xecv\xf9\x16N\x8e\xc1BdL\"\x97\xb7\x88v\xf6\xdc\xf5\xcau\xd1\x8a\xa0\xce\xc8\x04\xb2\xc9\xc2];\x17\xbb\x0bJ[]\xe4\xd8Am\xd7\xd0RA\xbf\xa4\xfa\x08J\x12x\xb0,\x9f\xcc\x06\xcd\x14\xd7\x87\x0b\x1d\xa80\xd6\xbb\n\x87J#\xb7\xfb\x81\x1b\xbfZ;\xea\xb7\xd6J\xady\x030\xef\x1199}3\x1f\xcf$Y\x0e?9EW\x9b\xb4]$\x80\x1b\x08\x14C\xa9\xf6{\xb2\xa7\xf6\x1f\x10\x03\xb5M\xad\x92\xe8\xeb\xe7)Z$\xa6\xe4\x92\xe472[no\x9f\xc0\xb9\x947O\x97\xe6\xdaH\x1b\x9fE\xff\x05\xa0\xb8M\xe1\xd1+\xb9W2\xd7\xb2[\x05\x83\x83\xde\x98\x89\x01\xed\xf4\xcd\xecz<\x9c]\x9bq[\xb7\xb3\xdf\xe7\x9f\x01H\xeb\xd2\x81Y \xbek\x92 {se=S\xdf{\x18b\x0b\xce\xbe\xb8\xbf\xdd\x89\xde\x80\xcc\x9c5\x9f\x15\xaa\xeb\x05l\x839MB\xaf\xed\x06\xb7\xea\xdc\x18w\x0c\x05tq\xdc\xdb\x81\xb9o\xc1\x14D\x14\xeb\x9d\xed\xcdB\xca\x85\xfc\x04\xfc\xb3\xf5\x06\x05\x04\x1a\x91\xc4\x8c\xc3Ia\xd2Z\xeb\x8e\xdb-_:\x8a\x0b@\xe8\x0f\x98)\xec>\xc4L\xa1+\x1c\x8ao\x1c\x80C\xc1\x00\x8b\xf6\x97\x84\x83\xff\x92@4/\xfe\xae\xe0\xed\x9a\xc0\xa3\x81\xbf\x8df$\x99\xa7.\xc0>\x02\xec\x1d!<\xacw(\xd0\xb2\x8f\x00\xe9/\xa3W\x10\xbb\x87\x1e@|\xc0R\xe4\x0fm\xf3\x88n\xa9U\xf6\x8b\xb7\xa2d\xc6\x03\xcbh\x0f4\x05\x8f\x0b\x1fDW\x8c\xa0r\x8e\xdb+}\xfb\xa7Efy\xf4\xc88)\xcfiz\xe0\xa6\xe9p\x83\xbd\xd1\xaa\xa6;Q?4^\xa4\x0b\xdd!\x87F\x83|0q!\x058\x1a\x8909DdHW@7F\xa0\xc9\xc3\xf3+Q\x0f\xc4\x15\x95\\e\xe2p\xabrD\x9a\xf2\xc0{Y\x8a\xa8$\x91Y1\xc5j7\x8f\x19\x97F\xb2F\x8a\xa4\xad!\x8a\xca!\x8aE\xda\xa8\x16\xe9\xb8\xf8Hi\x12\x9b\xd689\xb4\xce\x89\x83\x8a\x11\xd8\xa2to\xbe\x99\x90\x91n\xcd\x97W{\xe9\xcdn\xad\x8e E\xbf8\xc1\x03!\xea\xc1\xad\xec\xd0\xfcj\x8f\x7f\x82QI\xed\xf3a\xea\x13\x9b\xdce\x03\\\xb0\xe2\xea|r\xedw\xd8\x06\xc7j\xd3\xe7\x1b\x13z{M\xdf}\x18d\xees\xe8\xbd\x1c7\xc5b\x14\xc7#\xd7\xe9\x8f\xce\x12\x95\xda\x89*\xe3F~\x91}\xb6\xb5\xd6o\x15\xd0\xfb,\xf7\x08\x06\x96\x85\x8f\x1e\xd9\x89x\xe9t\x9d\xb7)\xee\xc3\x8d\xaep\x03\x05\x87\xc3\xcd\xc1m\xbc\x9d\xb3\xcdQ{w\xdf0\xc6\x8d1\x81lm\x03\xd0\xf9h\x9b,m\xa7\\4\xfb\xeb\xbc\xd2\xd6\xc1\x01\xb9\"\xf8\x90\xbdJ\x866\xe9J<\xa8\xf8\xafc\xb3\xb6K2\xf0\xe9^\xdb\x0dn\xb5\xd1\xed\xa1\x1e\x91B\xaf\x1a-\xedIA$\xceF$\xfb\x10\xb6{\x04@\xdd\xb8]A\x03\xac`3\xd8Z\xf4\x8d2m>J$\x1d\x8f\x13I\xb7!\xf8\x98\xfcs\xddlKK\x0e\x11t\x82\xfc\xd3\x89'$_\x9d\x07A!\x05pZe2\x92\x8f\x8f\"k\xf3\x8d\x1b\xf9m\xd6C\xa8B\xf4x\xe1\xb5\x1b}\x9d`\x0d/\x86\x86\x8d\xf4\x89^a\xa6\xf7\xc5#>\xba\x1c\x81\xd2\xa0j)W4\xd9gE\x1f\x89E\xfb\x03\xd8\x12\x14\x13\x14M/\xdd\xc5\x18\x91\xf6\xab\x08\xb9\xb7b\xa7\x91\x1bu\xdfF\xd8\x82\x81\xd1\xbd\xb9\x8d\xb0\x05\xb0\xf4\xf15=x\x1b\xa1\x08\xee\xbe\x08`X\x83oW\x1d\x8adT\x1e\x8du7d%%\x0ciCX\xd2\x05i\x89\xd9F\xa0\x18\xb2\xb1\xfdW\x02\xfb\xcb\xfc\x02^\xd3\xb1\xe2\x01\xb6s\xb0\xac\x83\xf9\xb4\\\xf8\x03\x1a]_x\xb5\x14\xe4\xa5/\xdb\xee\x0f\xfa\xda-\xf0\xa6\xc8j\xb3f\xb7T\xa5\x8e\xd6<\xe3\xb4\x95\x82\x8d'\xd0\xc9\xc1a\x90J\x17@\x1e=\"t8\xcc/\x88t\x01\xadn\xec\xd3\x06\x9a\xef\xbe\xfdP\xca\xfc!\x92\xf8:x\xb8\x80\x1ch\x94,H\xc6\x9b\x11\xb9\xff\xc7\xfd\x04\xe7\xfd\x04\xef\xa3\x1d\xba6\x8a\xcb-\xdb\x87\xe2\xfd\x04\xb7\x91\x9a\x0f\x1e\xb6.\x8d,\xaf\x8f\xc5\x07\x95s\xf1\xd4\x11=\xceZ\xf37\xde\x14\xcc}\xce\x0fP\x13\x12\xd5\xaaE\x9dH#\x19*\xe8\x90R\x971\\\xdb\x0d(\xeb\\O\xc9\x7f>^\xba\x82%o\xd51>\xb9$\xf4\x82\xf8m^]\x88\xa1Is\x1f._\xa5]._\x99_\xdc\xc1\xbb\x0b9\xe8\xe1\x858i\xa9\xf9\xe9\xcdM\xd7\xfb\\\x9aN\xe0j*\xda\x0c\xa4\xcd\xd2b\xbe\xd0\xd3\x11\xe1f\xf1\x15\x97\xca\x01rSYzu\xa2\x03K\xc9\x1d\xf5\xa8\x8b\x19DY\x8c\xaaQ\xac\x8eP\x1eV\x96\xf3CMw\xb4\xc1\xfb\x85\xec\xef\xf2an\"\xeem\xe3\xdc6\x86\x1f\x8d\x88\x1d\x8e\xb0r\xfe\xf4\xb9#\xc0J\xd4?\xff\xb4\x92L\x1b\xe2\xae\x08vgbc<\x9d\xba#wD\xec\x16\xa7\x1as\x9d\xbbs\xb1\xd4\xa3\x89\xcd\xf4\xd4\x9diE\xbd\x1b\xe1{7&\x8a\xcb\xd3\x86`!k\x16\x98\x1c\xcf\xdd9\xfc\xc8\xd6\xf1\xc2\x9d#\xa4\xdc\xc4\x1ay\xda\x10Q\x86\x85\xc9\x8e\xa6\xbe\xad\xe93w\xb64[\x99\x1c\x9f7\xe5Ht\x8egg\xee\x1c\x81\x1f\xd9^?k\x18h{\x95\xc4\xac-\xcc\xdd0\xe0\xc5\x8b'&k\xc3\xb0S\x1d\x1e\xc8dk \xd1\"\xa8 \xe4\xf2\xaca\\Y$|qo2}\xd6%0J\xf6Q\x02\xa3\xe4^\x90\x9c\x81Q\xa8 \x8cB10JE\x11\x0c\xd9\xf7\x18\x81\x99}\xebG7\x8a@\x17\x16i\x1d\xea\xb4n\xe9\xb3\xb7\x81t\x91\xd8\xb7E\xcc\xd5\xbc\xc3\x1c\xc6\xabb\xbe9z\xf9J\x8d\xa1\xafXI\xf1\xf8f\xd63\xf1hU\x89\xb9\x0d\xa6\xdb\x1b\x15\xe3\xed\xf6\xc0H\x0bM\x9c\xd6T\xd0\xde\xd2\xd6 \xcc\x11\xce\xac7\x98\x9f-]\xe6:Y\xc5\xe7\xf5kE*[=\x86C\x9fG\xc6KLa\xd4KQ]j\x88\x02\x8ez\x8d\x8e\xac\xf6\x15u\xafI\x9c:4y([y\xd4\xdb\xb1\x7ff\xa2\xef\xc3\xe5\x97\xb3\x01\xe6W\xe8R\xd1o\xb9MP1l\x03b\x8f \x97$\xbe \xa2Mx\xe2s\x01\"\xcbI\xc1g\x08\x04\xe2\xd2\xa0\xfc\xa0@\x19!\x10\xce3\x86$N\xf1\xdeb={)w>\x17\xefG\xa5\xe90\x1b\xfd\x8e\xfe\xdb\x0fNIy\n\xf2!G\xf7\xf40\x98\x97\xc4o\xd6\nF8x\x91q1s\x02\xc3\xc9\xe7\x11\x8e\xd3t0\xc0}\x84{W\xd6\x18\xe8\x187z\xaa\xf5\x97`\xef\xd4z\xbb\x9dM\x12\x16\xad\xfdh\x8b7\x04S\xee\xcd\xf5H/\x1b\x06\x95\xe0d\xe8R\xa0\xf7P\xe4\xe1;L\xe8\x0f\x9aF\xff\xd8\x802\xcdaO\x1ct\xc7\xeap\xfcF\xa7\xdc\xd9\xaf\xc8\xb1bB\x9dd\xf1:\xc2\xa4\xb7\xbe\xf0v\xc4mw\xed\xd1\x94\x91\xe9\xd9\xcc\xfd\xe1\xf3\xf3\xa6\x0f/\x1a>m\x1a\xad\xa7\x9f65\xdf4(\xd3\xf3\xc6\x91o\x82\xebE\xd38>w\x8c\n)\x98\xd29vbk\xb6\xa1Y \xda\xcb5\xf9S\xeap\x94\xd5H\xec\"\xcb.\x80\x1c\x192\x06T\x89\xd7]7G\x83\xc1\xc5@\xd1&'G\x8e\xf4e\nE\x82\xd4\xb6L\xe8\xbb\xe2UJ\xa3\xad\xf4!\xa3Z\x87\x83Q\xce\x82\xca\xf6\xe2\x1f \xe2w\x1e\x8b\xaa2\xc8\xc9;\xa7\x0d\x17E\xe2v[?=\xbc\xd8\xff\x82\xf1\x81\xd1#\xe1h\x8f\xc8\x89p;\x9a\x85\xd3\xcb\xb3\xd2\xf5TSYyV\x9c\x88ck\x98\x1e\xacA\xbb(9\xa0\xc6\xb0\xf4\x19U^>\x9eS\x12\x7f<>\xac\xb9\xb0~\xd4\x1c\xcd\xfb\x9d\xd4\x189\"\x15\xab\xc9\xedE\xce\x14+\x1e\x92iC\xe8\xd9\xe2\xefC4\x1d\xec\x90\xfe\x9d\xe4[\xe1\x1d\xe5kh\xabE O\xdaw\xbd\xc5\xdf{\xf70\xd7Xzi|\n1SG\x87\x81\xd7\x80\xa7\xf1F\x1c\x02\xbc\x03\xd0N\xa3\x11\x0d\xeb\xc1\x13\xb7C0\x1ch\xdfiv\x17\x0f\x87\xe8\x19\x9a\x93\x96;\xdf\xb1\xa2rq\xe3\xfd\x1b$U\xf1\xc7RF\xd8\xa5\xc5\xb59\xb8\x0e\x9c\xa2\xc0<\x7f\xfe\x02\xfdP\x13\xbd\x19;+\xf4\xaa\xb7X\x9c,z\xbf\xfe\xe4\x9f\x1e=\xee\x0f\x9e\x0cG\x93\xd3\xd9\xc5\xe5\xd5\xcb\xeb\xdf\xcc\x97o\xde\xfe\xf9g\xf9\xfe?\x8f{f\xe3\xd2\x1bt\xbboQ6\xb4Z\x92\xabb$\xa9\xca\xe5\x8b.d\xd5\xd2\xd4\x96\xad\x8a\x92\x9bk\xa4\xf3\xf3\x06\xbf\x8b\x07(\xeep\x18\xe3\xc5\xdf:j\xf9\x8d\x8e1\xf1\xb6\xf0\xf9\xf3\x17\n)\xcc]\xb0(\xbf\x88\xd0\xc4\xc8\x8c\x8fg\x85\x10\xc3+r>r2w\xcd?\xb4\xc3J7\xca\xebM\x15\xf8\xf4\xea\xb6B\xbb\x90\x96N+\x14\xa2\xf2 \xb6\xf9\xc7/\n\xf3k]\x1c\xb6\xb1_5\xbf5\x0fuo\xb1\xe8\x99aV\x1b\xc1\x8f\xb3\xea\x8eE\xe4\xd29F\xb3\xa0\xa0c\x89\x1c\xe3*\xc8\xee \xb3\x11\x01\x0f=\xbc\xb4\xa1\xcc\x0c\xb5\xfa\xfcE\x93+\xa1\x8b\x81*\xe8\"w\xa4,rE\xe8\x12\xc3\xd7\xc1_\xb3\x0b\xb0\x84\xac\xdc\xa7)D \x81\x93\xbf\xe6\x8d,\x85sx\xb8\xceH\x0fAIU=\xd4\x85>>\\\xc0\x19+\xa8\xae\xf2\x00\xb6\xe5\xc5\xd7\x85_4\x84\xed!\xa4\xd9i\x85_\x08\x93?'\x8bh9\x04\x93]\xd2k7Q1\x91|\x9a,S\x0e1\xa6\\\xde\xa5\xb5u\xd2uU\xc4E\xca\x93G\xfd\xfd;Z\x1cJ\xb2\xadu>m\x91\xb1\xcf\x1b\xd6N\xdaN\xf2\xdb\xed\xd7R\xf4^\x06w\x91[\xb257\xfe\xcb9\"\xf3u \xce\x94\xbc$g\x18\\\xa0\xda6\xd8.\xcf\xc0)\x96\xd3\xa7\xb9\x82\xee|0\x02\x03\xca\xab\x83\xd7\xdcL\xaef\x9f\xe7~\xee\xed\x8c*\x9c\xd3|\xab\xb9\x00\xd0\x01\xaeC`\x9ec\xdc0\xb8\x99n\xda\xaa\x81\xcc\x15!\xa8\x05\x0d\xf3\xd1\xa74T\x93\xc7O\xb2\x08\xce\xc9\x98\xa4\xa3FF\xacWt:\"\x1c\x0f\x89\x1c@\x9a%\x97\xe2A~\x8c\x8e\xe4u\x0b\x10>.k\xf4v\xdd\xd8\x19TC\xb6\xf6\xd7\xb6\x80\xceH\x9c\xf7\x161\x0f\xda\x0dY[Xj\x96\n\\\xd2T\xc3\xea@\x11\x9b\x01\xd1\xc4\x82b\xef?\x9a\x8d\x17\xbc\xd8P\xa8\xd7$\x1e\x8f\xc9\xcc:\xc1/|\x84\xe7\x18\x1d6]\x82\xa7\xe7&\xa1%\xfa\xc0\x18J\x04wSxjou\xe6}\xd6\xc1\xd4;\"\xd7zF1\x06\xaa\xd6%T\xe6\xd8\xa2K\xbb\x15\nk6 m3\x8c{\xef\xf6\x98\xd6\xb6\xcb*\xb4\xf8@\xc3\x97\x02\xef\xb0\xdd\xd7\xd6qv02P\xa2\x90Y\x01\xe7A\xad\xfco\x963h\xdf\xfd\xff*\x8c\xa1\xb1\xed\x7f\x13|\xe1\xd9\xd3\x0elAg\xfa[p\x85g\x0d\xee0\xdb\x98\xc2\xc9\x95\xae\xe7\xef\x8e-4\xf5&\xe7\n\xad9\x8e`\n\x1a\x0b\x1f\xce\x13t\x05\xff` \x9dX\x82\x1f\xa5\x7fc\x96\xa0Z\xfc\x07K\xa8\xfcZX\xc2\x8b\x06w\xc3\x7f\x0b\x96\xd0\xd8\xf6\xbf \x96\xa0\xdd\x9e\xb5\xb3\x04\x9d\xe9o\xc1\x12tS\xffNXBSor\x96\xd0\x9a\xe3\x08\x96\xf0b\xfa\x81,AW\xf0\x0f\x96\xd0\x89%\x84\x94\xdf\xfc\x8dy\x024\xf9o\x8c)\xd8\xe46\xd3 \xb3f\x89\x0d\x00\xc50\x00\x14\xa8\xfaT\xea\x8b\xe76\xf5\xf33\x9b\x8a\x9e\xe9X\xd53\xdd\xd1Q\xb9\n\xfeR\xeb\x03\x9b\xa1-}-=mH\x0fZY\x98\xe7Z\xc6\xc2u4\x85\x97\x0c\x1a\xc8\xbb\xc8\xc9;\xeaZ\x03\x18\x89j6\x8a\xa1\x95=\x97\xaaU\x0f:\xdc\x16\x81\xd2`5\x0f\xf7\x9a\xfa\xa8\x10\x1e\xeb\xab\xa7\xcf\xc85\x8c\x02\xf4x\xaa\xf0\xe3i!\x9a\x1f\xb6\xee\x80\x91\x16U\x10H%bt;o\xda\xd1\xd5D\x85\x1c\x91u\xe1\x0c9>G\xa7\xb0\x1e\xc0\xc7\xfb\xda[\xad\xad\x80\xf7\xe3\xdc\x15\xf3\xc9t\xa0\xd0\xbc\xbe|<\x1a\xc1J\x9d\x91\xcc1!4\xc25\xe5t\x07\xbff\x81\x1f\xa63\xe27\x10\x97\x07\xd8Z\xe4RO\xf5\xdap+\xe2l\x9a\x0f\xce\x12\x17Nm\x06uF\xa9C*&\xb0\x01\xc0\xb1O>@\\\xfb\xbb\xdcW>z\x84\xfd\xd3s\xa4\xbax]7\xb7\xb0\x01\x05\x90\xad\xa3C\xea\xd3\xfe\x1b9\x7f\xb3X,\x07\xfd\xc5b\xb1\x18\x00\x83>9\xcc\xf9U\xb6(?K\xd5\xb1\xf8\x80\xcc\x18s\x08\xe3\xdc\xd4\xde\x07}p\xfc\xe1\xc0O\x9du\xe0\x87+2_\x0e\xcc\xee\xac\xfe\xbd\xe0V\xd4E\x0e\xe2\xc3\xe8Xv\x0cR\xa7\xcb\xeb\x87\x84\x8d\xac\xac\x1b\xdc=\xd6\x1c\xa1\xba\x17S\xbd\x93s\x7f\xa9\x06\xaf\xde\x03\xa8p\x96W\x9d&\xb8\x9d\xa9H\xfe\x95%ZXCqm\x07\x90\xd9\x08x\x1fc1\x1d\xbbhJa/\x9b\x17M\xcbU\x1d\xc5\xba\x9e\x92\x97\x07\x8c\\N\x1c\xf8ZM\x83 \xd6\xad\xb54EGo\xb9\x16\xd4\xa60\xc8~9K#k\xa7\x93\xe5v:\xf4\x82\xf0\xe3\xa3\xa3\xf3\xc3\x81\xd7\xa6\x0d\x02}\x87\xa2M\x81\xd5y\xf7\xc0\xeahG\x04\xfd\xd4\xe4\x8e\xab\xe1B\xd7\x8a}\xae\x96cT\x11k2\xe3\x05\x10\x05#-\x12\xe1\x1c5\xc65\x8f\x96\xcd\xe4\xaf\x1bMk\xaf\xfc\x12D9\xad\xaah%|\x0e\x82\x11\xbb \x86\x8e\x98\x1e\xb9\xb4\x08Y$f\xe4\xacN8\xda`\x84\xa8\xcd3\xe2\x82\xb1\x94\xb1\x99~\xcf\xe3\xe5\x04\xdan\xec\x08~\xd6\xd2\xc7\x87R\xf2\xd8\xc1\x80\xb3\xd57\x0f\xa0\xf1\x05\"\xcaK\x04\x94~\xc4\xc0\xe4\x05Y\xe4\xecY\xd5u\x99\xd1\x99|\xe6\xd0\x99\x14\xe2\x8a\x9e\x8d?\x9f\x9c\x80\xf2\xf4\xc9pqzum\x15\xa6\xc3\xdf\xe49\x96\xfd\xebY\xfe6^\xfe|6z1}_\xf8>\xb8\xee_\xcf\x16\x93\xa3J\x0c\x9e\x0c^\x9e\xd6\xf56\x05\xd8&\x8b\xf1\xf2\xe7\xe9\xe8\xfc\xf9\xfb\xc1\xac?\x7fs\xf9rqwv6^\xdc\x9d\x9f-U\xd9\x87\xf3\x91\x92n\xa7U\xc2z\xd1\xa8}\xd0\xd4\xa3_\xa5\x16\x9b\xa2\x13\xaa\x97\xbd\x82(\x04\xaa\x90H\xab\x0f)\xb8\xab?\xe9s\x9b9\xab\xc5\xa1,\x94U\xbb\xa1l~\xb6\xd4\x8dL\xf5\xd5~\x0f\xac\x08\x02\xb5\xe7:\xb1\x02C\xd1/W?(\x8ba\x1dd\xef\xd6\xfd\xc3\xc1]Be\x1d\x1c^\x96\x02|\xe69(\x8e\xd6[\xba\xc2S\xb2\xaa\xe3\xc3\xa3[\xed\xb2\xcb8\xb0\xb2\x87zF\xf2[\x98\x03E\xedN04i\x94\x874\xb5\x13\x986M`/\xa4~ b \x87m\x93\xe9\xfdc2K\xbf\x8f:\x99iu2?\x0e\x91.\xd2\xa6y\xcf\x8b1N\xe7:\xf6\xeb\x8e\xe8(\xa5\xfa\x0fD\xe6\xa4\xab\x18CwR\x0f\x0b\x99?>\x04\xd6\xf48\xfe\x05\xb7u\xf0\x17#\x94\xfa\x18\xffs\x0d>\x1d\xads\xbb\x8d\x80\xb2[\x16\xc3\x1f\xfdo\xb2\xd3\xd1E\x9f\x9ec\x04R\x81\xd9\xd4_(\xee\xd3;\xf8\xa3\x9b\xf6C\xfcW\xbfE\x1b\xa8\xc7O\xf0\x95\xfb\xa9\xf9;Y1f\x13'w\x89W|\xces\x05\xb7\xef\xd4s\xb0\xc6\nq\x19\xc0\x13\xf6-Lyb\xfeB\xa9P\xfc\x84 Y\xa2V\x85z\x8c\xd8-|\x8a6\xf8\xc7\xc7\x7f!\x16i\x14a\x7f\xe2\x84\xfe\x94\xb1 \xf6n`+\xa4\x92\x92\xd8DD\x85b\\\xa4\xf0\x9e2\xbe\xf7=\x86\x8fij\xe2\xa1\x9a\x81I}\xb6\xc7\x8f\xbe~G\xb8\xd2\x10\xffD!&\xc74\xb1C`_ \x0b\xfa\x84\xec p\xca\xa9\xfeD\x188V\xe8\x19\x12;?\x0dY\x9a\x82\x06\x8a\xf4D\xf4\xf4\xfc\xd33x\xc2\x16\x05\xccr\xc6\x01\xae=\x0bC\xe8/\x0e\xc1-\x86t\xbd\xf3\x10j\xf5w\x9c\xa5L#\xca]\x18\xf0\xc4\xb3`\x15^\xb1T\x88\xd3\xf8\xee\xe9\xe7\x93\xe7g<\x7fDd\\\xfbYx'8b\xe8&\xc1?\xf8 \xb1\x82j$\x16\x82z\xbb\x90E\xf8v\xab\xfe]\xb1tG1\xf4\xec\xca\x17^\xeccX\xde8\x80\xb9\xf6h\xa0g\xdd\xdb\xf1\x18\x83\xda\xe2\xd3\x98\xdd \x16\xa566o8f{\x16\x89\x15\xf7\x05\x1bS!X\xb4f\x98\x1d \x0c<\xee\x01\xa8u\x10\xd1q\x12\xd0\xfb\xd4\x8f\xb6\xda\xbf\xa3IR\xb9\xa9\x1f!\xea\xaf\x05T\xbe\xde\xaf\xd4\x1f\xb6>\xbfQ\x7f7\xd4c\xc2GX6\xcc\x84\xf9\x8d\xb6:\x84\xaf\x9f\x02zma*\xb7\xbe\xc0?\xef\xc28\xe1\xb1 \xc0\xbb\x154\x80\xbav\x1e\xae\x04=+~\x82\x7f\xb8^\x13\xde\x0b\xfd\x17\x97\x85@L\xfa\x91BK?\xe2\xdb\x0d\xbbO(\x16\x08h*60\xe0j\xd5\xe0\xa2\xa0[\x8dD\xa1M\xe17:%G\xa5\x10\xeb\n\xd3\xf1\x8e\x05zYE8wa\x16\xea8\xbf\xe1\x1e\xa0\x03\x19[=\xc4\x88; \x0dB\xfc\x9bPN\xdf\xbd\x03\xa4K\x02*L4\xe3\x84\xc7w\x10\x1f8I\xef\x01\xce\x9f2\xc6!\xc1,0\x96\xc6\x19\xc7\x95\xc5\x11iyz\x1fA^.\xf4\xb2a^\x1c\xad\x03\x7f\x83KL\xaf\x88t\x8bk\xf0\xe6>\xc1\xf4\x10\xa6*\x8d\x835\xc5\xc0\xc5I,\xfc\x0d4\x96\xe2\xc4\xa4\x82Q\x00+\xc5\xee\xa8\xd74\x01\xc7)\xb0\xc2\xa2-\xc0\x94\xad\xa1\x81,\xe2\x8c\xc2r\xcc\xc4\xf9\xd9\x19DaVx\xc6}D\xd0\xbd\xcfn\xc79\xf4\xb7l\xe5a\xf6[Aq\xf5\xdd{\xfe\xed= \xc3\xdd\xc6GD\xbf\xe3\xf0\xe9>L\xb7\xbc\xb7|8\xff( \xf9\x9f\x0e&\xbf\x7f\xfd\xea\xdb\xb7\xaf\xbf\xf8\xe7\xb7\xdf\x7f\xf5p\x01\xb8\xa2Eq+\x17+A\xf8I~CE+^\xc8Ic0}\n\xc7\x1aE3\x05\x14\x97\x9f\xea;\x8dN\x97\x0e\x06\x17\xa7\x15\x8d\\\x8a\xe5@u\x04\x98\xac3?\x9d\xbeW\x99\x1f\xce*\x8b\x97v\x1c\x04\xab\xc0\x0f\xeb\xfa\xf8\xa7\x9f\xb9\xb9\xa3w(Z8\xde8\xdd\xb8/\xa9<}\xee\xd6Iy\x9a}\xbai\xa6\xbf1f(9\x93\xf1\x0c'+\x1cI\xa0rA\xf1\xe7\xde\x1dF\xaa \xe6\xd3\xa5b %\xdd\x14\xb9&\xa0\xa1\xf8&\x12}\x95\xc1\xe85\x06#2}\x01\x01\xd6\x8b_Gd\x8aa\xb6\n\x97\x81\xfc~\xa4j\xa1}\xa0\xcc\xb4\xff\xe2\xf9\xf3\xa7OK;\xf2\xa0\xcc\xb6\xea\xc4\x1am6\xc0p\xa8\xb1k)2\xe9X\xf1\x01\x05J\xb5\xa7%\x98\xf8\\eY\xb6\x00\xe1\x14\x95\\\x0e\xec\x1e\xfd\xc2\xfe\xeb\xca\xb3\xac\x05\xb5\x99c\xf2\x95\xe0\xe1\xf6[v\xa7>\xfd1k\x88\xca\x01\x07*iC\xc4\x0e\x1am\xbf\xe3l\xe3\xdf\xcd\xd4\x8e$\xdaft\xcb\xc6.\xed\x8b\x1f\xdd\xf8\x9b\xfb\xc6\xf8*7\xaf)\xdf21sJ\x03\xe2>\x89!\xa8\x08\xe3\xee\n\x809\xa63\xd2\xfb\xeb_\xfe\xcf\xbf\xfe\xe5\xff\xfa\xeb_\xfe\x8f\xbf\xfe\xe5\xbf\xb8\xd4]\xfev\x17`\xfc\x91(\x0b\x1cJ\xa8\xfc\x8clF\xce\xab\xa7\x1c\xa5W/\x0e\x938b\x91p\x8e\xb5\x17s\xe6JW?\x9e\x05\x10\x8a\xa5\x07\x9e\xe4z\xa3<\xea\x8b\xda\x1c\x19+\x19|\x03\xc9E1\"x\xd7\x83\x88{\x1f\xca\x05v\xbb^\x8e\xaeV\xfc\\=\xd8\xa3\x0eA\xfd\xa0\xe7\x08\x83\xe8\x98mto\xd7\x05th\xbe72\xce\xf7\xd4\x06\xd9@`\x1aV\xcf;F\xd7\xc8 {;T2\x890\xb0}\x0f\n\x9fu\x90\xbeB\xd0\xa6\x91\x8e\xa5\xdb\x0dv\x1c\xc7\x83\xc0\x17\x02w\x94b\xa7\xe8\x00)\xc5\x00&y\\\x8e<\x14K5FH!\xc2\x87\x0dHR\x08\xef\x82\xbaP\x07\xfc\xbfr\xbf\xfd\x83,\x14?\xfe\xbb$\x0b-\xcb\xae\x0d\xab\xff\xce0\xc6q\x1d\xbe\x801\x8e\xaf\xff\xc0\x18\xf8=\x04cj\xe9\xe4(F\x82\x0c\xa1\x13\x0d\xfd8\xf4\xffCh~'0?\x94\xd4\x1f\xa2\xf1\xff\n4\x1d\xb6]\xf9\xd2\xe4\xc5}IU\x98w\xaffS\x0b\x83#&jf\x1e\xfez<\x8e\xeeQ?\xbf^s\x86\x07\x04\x943\xcc\xc5\x85\xef\xa1\xde\x97\xa6>N&\xcd\xd6>h=A\xc9\xbaZ\xfb\xf8\x07\x93|\x18\x99\x95\x1d\xda\x12:\xac\xe25\x8c&\xb6\xbc\xca\x84\xd0z{\x1a\xed\xf1D\xcb\xa3\x890\xca|\x16 T\xa6{~\x19\x9b\xbc8\xd0\x7f\xb6<\xce\xf0\xc4+W\xef\xe7\xa7]\x82\x1a\x1cZ\xe39\x18\xf3bNE\x8cZ}d\xe9k\xa6$ d\xf2\x1b\xd4\xf3\xfb\xf8\xdd\xc7\xc32\xcc\x05\xb5\xb0\x80\x99S\x0b\x06\x03\xb6\xf1Y\xb0N\x99\x8e\x11\xb5-\x00\xbf\xf1\xb7\x19\xd72\x01\x96P\xb2\x81>\x1b\xd0\n\xf1\xdd\x14\xfe\x05yl\x87\x87k\xa0X\xde=\x87\x7fA\xe9\xaf\xd6\x83\xf9\xab\x0f\xe2l\x9f\xf3\xf5\xa3\xfe\xc2,\xf8!\x0c\xbf\x1f%x.\x88a\xdbz7+\xa8\x04\xacw\xe0\x81mY\x84IP,\xa4x\xde\x12\x9aC6\x08\xe5\xa6\xfe\xfe\x94\xe1\xf1I\xc8\xa2\xcc\xfc\xf5\x05\xf6>d\xbaC\x11\x9e+F1\xce+\xceN\x9c\x08\x0bil\xc7%\xce\x84\x06\xcd\x9c\xad\xe1\x9fxk0\xef'\xf5\x0f\x9e\xe9q\xc8\xc8\xb3\x15\n\xb6\xf0\x0f\xb5\xe7\x00\xa6\xca\x94\x05\xfa<%\xdd\xd1u\x0c\xc7IiH\x03\x80\"\xd7\xc9\xa7 \xf5\x10\xdc4\xa1XPp\xff\x86\xe9\xa7\x18\x89N*\xee\x11\xdb1\x08]/\xcd\xc2\x90\xe2)\x05\x06\x9d\xd3R\xa7z0\xd8,`$\x05\x0b\x93@\x1f8*\"`V\x90P\x13\x0f\x0f(\xb4\x9a\x195gG\x82\xe3\xbf\x14)\xa0\x80\xbc0\xd6\x19\xf4`\x8f\xc7<{\x7f\x8d\x07\xb3\xb7+\xdes\x04\x8a\x03\xa3\xb0^\xba\x87^\xe0\xd2\x0d\xc46\xb8GQ\xd9<\xafQ.5\xaff&i\xe4\x87T0/\x0epm\xe8\xf706c\xac\x13\x04\xa7Qj\xd0\xd7\x92\x81\xc2\xea\xf5\xb9&\x16^\xe0' \xc5.\xaf\xd9F\x0b\xd1)\x9c\xe5\xb0 \xf0\x93\x14\x17\x87\x1f\xd8E\x81\xcb\x04\xcf\xcb\x0c\xdc\xf0`\x84\xe9\x1b\x86G\x9a\xda\xf6\x1e\xe8\xaf\xfdK\xf9\x96\xd3\xb5\xaf\x97'\x9cnq|J\x11\x97\x99\xa0\x862\x84\x06\xb2\xc2_\xa1+O\xe2\xe0~\x1b\xdbG\xcb5\xe9\xda\xa7A\xb1 n\x90N\xe01q\x8e9\x10\x01\n\x9e\xee\xc3U\xac\x0fq\xef\x84\xf9k\x1a\x05\xabzx\xd0\x1d\x14\x061\xed\\\xef}\x06\xe8\xbc\x87\xae;f=\x82Y\xdf\xb0\xdf\x06z=o\xd8\x97j\x12_Q\xc1\xfd;\x93\xa0\xc5\x88\xd70{z\xb819\xd5\x94U\xbdF\xfb8\xd8\xb3b\xc9\xdf\xf9\x9bM\x96\xb2o\x958\xa3\x99\xb2JL\xed\xde\xf3\x15\xd2\x0bH\x144\x12\x90\x13S\xbe\x0e\xe2XC\xf4u\x16y_\xe4\x8f\xbf\xcd\x1f\xff9\x7f\xfc\x1e\x1f\xff\x99fi\xea\xd3\xe8\xb7A\xa6\xe1|\xc5\xf8\x96\x15\x1e\xff`E\x8aW1Ovq\x10o\xef\xf1\xfd\x8f\x9b\x8d\xa1\xc5\xa87,\x80\xf3C\xc2\xbc,\xa0\xbc\xdc\x97\x1f\x92\xb8\x98\xe9\xb5\xb1\x84`\xaf3\xbe\xca\x02%\xb4\xb8F\x1d\"r\xf4B=\x8f!\x8b\xb4e\x89z\xe6\x1c\x97P\x08\"\x0f\x9a(l8\x05\xc4\x0f-^\xe3\xe9f\x08\x04\x99\xad\x91\x04\x84a\x16\xf8h\xea\x81\xa7\xb0H\x92\xd1\xd8!\xdektN\xe8z\xad\xabMv4\x121\x92b\xae\x89L\xc8\x91\x00\xea\x83\xdc\x04\xa8\x1e&\xfc\x84\xe44\xbc\xb7\x98\x1aj\"\x17j\xd2\xa6\xde\xcd\xa3%s!\x92\xb7\xd0\xa0p\xa8\xa1\xcd\"\xcd\x90\xf0 \x00t\x8cU\x0cc\xf5k\x14\x8b\x1c\xd2\x1a\n$\x9e\xc7\xb4m\x80%\xeb4\xf0\xb7\xfa\x01\xbfd\"V\x12q\xc0\xb4,A\xbd\x1b\xc5`\x10\xefW[K\xbcV1\xd7\x90y,\x08\xd4x\xe9\xf9V\xafj<\xcc\xeb\x8ey78\x94V\xc0\x08(2!/`Hvm\xad^\x8cB\x82\xfa\xab\x97\xa9\x17\xc7|\x8d\x89\x9a:A3\x8a!\x8cW4e\x86g\xd2\xd436>\xe6L\xcf \x84M00\xd3w~\x98!`\xaa\x8a\x8d\x9a \x16y\xf7&A\xd59Nw\xfe\x06\xea[1\xbd\xd2V>\n\x1e(!\x16\x96/ZB\xa9\xbfc\xc3o\xe1E\xed\xffz\x95u\x1d\xf3\xb1Z <\x89\x03j7\x1f\xf5\xe41\n+i\xfe9\xe1\xb11\x9e\xc3\x04\xce\x14)4\xf4\x05f\x07\xbb\x80\x8b\x1d\x12Pf\\#k\xf5\xe2\x08\x18'&\xf1\\\xa8]\x03\x97\xd5Y\xf7~\xaa\xf7,\xc8\x14\xd9z\xcbB\xcd\x06Y\xc0\xf6\x16j#\x04\xf8(\xfc\xaa\xbf\xe3XQ<\\\xf9\xf0nF\xa0 z)V=\xb6#\x82\xaf\xc5bq$\xc6\x1b\x1a\xfaA\xfejP\xdb\xbe\x8c\xe9\xfa\xc7,\x15y\x9a\xe0L\x8bA\xfa]c1\xbc\xed)\xf7i\x94\xe7\xbe\xb5h\xb6A\xd9\x03Z\xda\xc2\x06i\x0b\x1b$`\x9dc\x83?E\xb9\xd0\x08eY\xe4#\xe34 %i\xb5@8u9M\x1a\x950Y\x9e8D-?\x82va\x99\xdf\x00 7\x98\x00;\xb5\x1b\xd8\xa9)\xb1L\x17\xbaa\xf7\x89\x929R\xfd\x92&\x10X]\xbf)n\x00\xcf\x96\xd4\x02%\xcd\xc7,`\x8a\xd6\x8d\x0b\xecI\xd5\xcd\x82\xd0\x8ac\xf8\xae:\x99S\xe1@K3\xf9\xe4\x05\xb16P\x1c\xb3\x84\xef\xbc\x1d\x8d\"\x16\xa0\x00\x84=\xbdw\xa4Asw\xd0\x8f;\xe8\x07\xca\x1f*7\xfc\x03_\xee\xe1\x0b\x18|\xbf\x8b\xe3\x90Fk%09d\x94\xac \xa3\xf4P8\x81U\xaa\x97\xb4\x15{Vl\xcf\x02-k\xdbM\x9a\x17\x07Y\x18\xa56\x13\xbe[r\xad?kQm\xcd\xa28\xb4Y\xd7,\xd1:\x0d+\xcb\xe7l\x1a\x1es>\x07\xbbG\xf5\xc05ykbA\x81\xc2\x1f-q\x17H{\xc4\xc4\xce\xf7n\"\xad\x17\x0b\xecV.\xb0\xfaT\xb5\x05-\xef\x83T\x8a]g\xea\xc50j\xf5\\\xe0\xba!\xbd\xb3_\xfc\xc8>\xc6{\xb55\x81U\x03\x8dFqNL\xa3,\x1f\x07#\xad\xf3\xf8\xd6\xa6\xf1\xf8\xd6\x8e!\n\xcc\x06w\n\xe23\xb7\xbd\xe0\xb6\x17\xb8\xe7\x05\x03\xc5\xfc\xb5\x00\x95\xde\x13\xfb\xef\x98\xde[\xf8Z\x8f\x07\xe8e\xb5\x80 \xb5L\xc2\xbeh\xe2\x03\xa2\x88V\xe2\xe9 \xffV\x96L\xb3\xa4\x9ar\x1f\x86Lp\x1f\xe4\xf1}N}\x0e\x8b\xcex\x83\xe3.\xf0\xa3\x9b\x99\x99\xe3\xbb0\x98i\xebzH\xb7\xe2\xba\xfa`G\x03\xaa\x9cA\x8e\xde\xb2`?I\x8a&\x8f\x81\xd3\n\x89T#7\x9b\xab\x9d\x17$\x1a\x8f/\x06\xa8\xe8\x8c\xb6=ru\x05\xa6\xa6\xf1\x86\x88\xb9\xb9}:\x87[\x98\xeaO\xe5f\xd9\x88\xb0\xb9J^6x\xdf2\xa6\x9b\x95\x83\x0d7\xe4^\xbb-\xae\xebp\x93h\xf5\x16^\xa6\xad\xb7\xaf\xbdc\xfb\x11a\x03\xf2\xc7\xd5\x8f\xcc\x13\x85\xf0\xf2;\x9a\xfe\xf16\xfa\x8e+\xd1A\xdcO<\x1a\xc0\xe0i\xcf\xd1\xba\xd7l\x1e-\x1d\x9eT\x8c\xc9N\xc3\x91\x0d\xd1\x80o\xc0\xbb\xdc\xcf\x8b\x9f\xe7\x8bt\xf1\xc3\xf2\x89\xd4\x7f\x17\xef\x17\xefO\xb7a\xbdG\x89*p\xf9O\x95\xec\xff\xf4\xd2\x99y\x0d\xd6jk*\xe8x\xbe\x18/n'\x8b\xec\xec\xec\xb7\x9f\x8e\x17\xd9\xd7_\x7f\xfd\xf5\xf2\xd4q\xf2\x08%\xd4\x12\xc7\x12\xcb\xe1'\x8e\\{\xc8\xd5\xbf\x9e\xe1\xff\x1b\xb9\x13\x03\x91\xa4\xd7\x12o\xd6H\xc1\x02\x89\xd7-\xa4\xe7\xaf\xe5]\x98$\x83\x99\x9c\xbf\xa1\xe3wK9\xa7\xe3w\xc3\xc9b\xbc\x1c\xf6\xafg\x90\xa6\xdefK\xf9\xc9`P5\xb7#\xda\xb3\x154\xb6\xb8\x1d\xe2\"\x93`\x829se\xde\xaa\xccs\xd5\xcd\xb3\xb3\xb1\xfas~\xa6\xfe\xfd\xe2l\x91M_|\xa6\xfe\xfd\xec\xec\xabEv\x8e\x9f\xcf\xcf\xce?W\xff>\xdf,\xb2\xa7ggg\xcb\xd3m\xbd\xca{rEz\x06 \x8b\xf8\xff\x03hf\x15.\x18%m\xed\xe3D\xc9\x0f\x8a\x86\x90\xeb\x03\x16\xe5\xa4\x803XC\xdd\xa9\xee{2\xeb^\x0b\x03\xc0\xda\xe1f\x13\x10\xd1x\xa6\x18,\x18\xe1\x15\xbe\x81M\xa1\xee\x86]\x13\xe4:\xef\xec\xac\x05\xd2&\xea\xb3r\xc3\xedoH\xff\x0b%\xb5M\xfc\x14\xfe\xf6Y\xa3\x85\xa1%Sj\xd1\x9f\xe1=z]\xc6\x98\xb0_\x10\x01\x11\xe7\x0d \x13\xc3\xe1\x80Ds\x81\xebU,\xeb\xcb\x95\x14\xdc\xf5\xd5{\xd3\xb4\xba\x11\xe4\x0d\x8f\xc3vG\x80\n\xda\xb7m\x07\xae\x85:{J\x00\xd9\xf8\x11[\x17\xe7\xec\xd6\x8f\xd6\xf1-\xb9\x06{\x002\xd3\xef\xe5&\x9d6\x83v\xe4o\x9d\x8d*\xc8\xbe\"W\x84\xf2m\x06\x86`&\x92\xfcK\x8c\x0d_\xf0B`\xb3\xcc\xcf\x96\xe4\xba\xfc:#o\x9b\x02\x9a\xde\x95\x0c`\x9b&\x95\xe4\x10\xdfV\xc7\xd2\xfc\xde\xbb\xbd5\xdcM\xf6\x8c\xa7\xaa\x8bW\xa47\x9d\x9cM\xd4\xae\xfan\xc2Y\x18\xef\xd9Z\xc7\xbd>\xf9\n\x9ck|5Y\xc7\x1e\x80\xad^?\x87~\xe5i\x93(^\xb3\xd7\xf7 \xb3\xb6\x9bw\x13?\xfd!K\x92\x98\x0b\xa8\xead:\"wu0\xd4(\xfe@\x8aU\xb9\xc7\xe2\xcb\x06\xbf~\xeaw\xd3\xf2\xed\x8b\x0eu\xff\x11\xf2\xfcN\xe7\xf9\x9a\xd3ms\xde\xef \xef\xef_\xbf\xfa\xf6\xb5>p\xfc\nO\xa5\xdd\xd9_C\xf6?\xd4,\xad\xcd\xef\x95\xfd\xfe5\xe8\x83\xdc\xb9\xbe\xc1\\4dk\x95\xf5\x15M\xdc\xf9~\xb4\xfc\x1a(\xd27\xe4\xbaRLM\xddW\x93W\xf1;H\xfcB\x08\xae\x12g\xe4\x1bw}\x7f\x80v_\xb3\xbb\x86\xde}\x0f\xdf\xbfD\x8b|w\x96\xdf\xe1\xd8\xfe\xf1\xd5wp[\xda\x9d\xe9[\xc8\xf4?\xbf\xfa\xf6\xf7B$\xdf\xb3\x9f2\x966T\xf7\xa7r\x0f\xbf\x85\x1e\x96\x0b\x92\x19\xf9\xd6]\xf8'h\x86Ej\xff\xf6\xa7\xef\x1b\xfa\xfcu\xb9\x85\x9f\xa0\x05[\x86\xcc\xc8O\xee\xb5\xe4\xe4\x17\xdf5-Z\x85\xf6\xef\x14\xf5\xfd\xff\xd9\xfb\xda\xae\xb8m%\xe0\xef\xf7W\x0c~zR\xfb\xe05\x90\xa4\xb7\xed\x06\xc2!\xb0ii\x03\xe4\x02i\xdaK\xf3p\xcc\xaev\xd7\xc1k\xed\xe3\x17^z\xcb\x7f\x7f\x8eF\x92-\xdb\x92\xec%iz?\\\x7fHXk$K\xa3\x91\xe6E\xa3\x99`\x9c\x92\x8a\x88\xdc\xea\x18\xdb\x10\xc4\xff\x8f@\x98D\xd8\x16S\xfe\x08\xe8mBRI\xc1(c1\xc27\x94\xdb.\xd5\xc8\x87u\xf0\x15\xeb\xa0\x1eK\xbf\xc0\x0e\xbc\n\xa2\xc5\x92\xf7\x1b\x95\x14=\xe4\x8f\x08\xc9G\xc9\xa8\xf0P\xb0u=\xf4{\x84\x9e\x91\\ ${u\x7f\x1e\xce\x18\xb5\xea\xe1\x7fRZ\xef\xb7\x80\x7f\x83\x1d8c=\xa7in^\x97?\xa3T\xdc\x9e\x82\xe6\xae\xf6Kc\xa7\xffE\xf4\x85m\x10\xeat\xf0\xfdr\xaf\xdc\x88\x8e\xe8Ds\xf7\x8d!\xfd\x07\x8c\x8c\xa6\xed\xd4W\xb0\x03\x86\x95\xffo\xd8\x81\x89\xbe\xe8W\xd8\x81\xb9\xbe\xe8_\x18wM[D\x08\xec\x80F\xa4cON0(\xa0\xb6,aez\xcf;@F\x05;\x10\xbb\xffy\xf0\xe1\xe2\x03\xa3\xceq\x98\xbbW\x188\xeb\xca\xcd\xf1\xdf\x04\xffM\xf1_\xeay\x06\xdeH\xed\xdf\x89\xf4\xdf\x89\xb0\xd5\x10\xff-\xf0\xdf\xcc\xf8\x85\xd0\xfe\x85\xc2^\x9c\x11Cb\"\xc0[\x81\x96\xc21\xb1\xb0\xb3\xa9\xadpi+\x9c\xd8\n\xe7\xb6\xc2\x1b[\xe1\xc2V8\xb3\x15\xde\xdb\n\xafl\x18\xba\xb4\x15\xde\x12\x8bB;R\xc8\xa2r\xa0\x91.A\xd2\xa3\xa0\x8a\xf7PZ\x93T\xef\"\xe1\xe4\xc3\xbdD>\x98d7\xed\x97J\xcf\x12\xe1(V\xb9Gq\xa7\x1aSkg\xb5\xd6\xb8a\xb99}uh\xf8\x98R\xc6*\xb1\x97\x85ZI\xfb)\xa5LVB\xfaw\xde\x9d\x8d.\xdf\x9e\x9e\xbc>|3\x92\x9fz\xf2\x04\xa6\x81\xfa\xde\x17\x9b\x14\x0f\x82'\xfa}\xb9wz\xb8\x87\x0d\xfab\x9b\xaa\x17\x1f\xec\x9d\xcbb\xdc\xa8\xe4\xfbw\xc7?\x1f\x9f\xbc?f\x8d\x9f\x9f\xec\x9f\xbc9C\xa5a\xcb\xe7;\xd648\xdb{=\xba|}rz\xf9\xd3\xbf\xde\x8dN\x7f\x93\xa5\xcbF\xe9\xf9\xe8\xe8\xed\x9b\xbd\xf3QY}\xc2\x01\xde\xffx\xf2ftyp\xb2\xff\xeeht|.\x0b\x17\xbc\xf0tt\xfe\xee\xf4\xf8\xf2\xe0\xe4H\x16\xcc\x9a\x05\x97\xafO\xf7~P\xab\xde\xb7 \x0e\x8f\xde\x9e\x9c\x96\xe57\xbc\xfc\xf5\xc9\xe9\xfe\xe8\xf2\xd5\xc9A\xd9\xe3\xab\x1aR\xce\xf6\x8e\x0f\xcf\x0f\xff\xcd\xbav\xe4\x8b\x8dI\x96\xfd<\x1a\xbd\xbd\xdc?9>\x1f\x1d\x9f\xfb\x9ciV\xc4\xf1\xee\xf4\xf0\xf2t\xf4\xc3\xe8\xd7\xb7\xac\xe1\x9c *0\x0c\x11\x91i\xd5f\xfc\x05\xdfa7=\x9cZ\x0c\xecI\xb4\xbc\x0dy%\xa7OT\xdb\xf8Z\xb8%Uh\x80\xd8M\x88\x0f\x8c\xd7\xc6.%>D<\xb3\x97\x84\xcbnf\nX^\x82\x85\xe5_Y\xab\x02\xd7Z2\xa5^\xd2]\x8f\xed\xb3Gj\x97\xd2\x12\xb2P\xebx\xb8\x9a\x0e\xf8\xa2(\x87\xbe\xb3\xc3\xa4\x88\x12\x11c7!\x1e\xd6b-U\xf0UmF\xad\x08Oy\xed\x88\x94\xbf`\xecRQ\x9b\x12\x15\xbe\xaa\xcd&\n\xc9S6\x13\xbbgD[\xe8!\x01\xf0\x8e\x95.Wr\xee\xb8\x85\x94\x1b\x96RB\xfe \xb8*\xab\xb7\xc2\x82\xca\xcb\xdc\xa9\xe7\xf3\xadu\xaa\xdd\xfd\x0c\xdc\xed\x84\xf46\x18\x94J\xbe)&\x82\xfa\x08\xbf\xeb\xa1\xc6Z%\x9f\x07K\xce\xb1<\xbd\xb7\xf4\x04dv\x08\x92\xa0<.:\xb6?\x8f\xe2\x89\xc9\x9c\x01h\xd1\x1b\x87\xf9x\x8ey8\xbaZ\xa7ENR&\x92c\xe8rs\x93\xab \xfb-\xe9\xba\x9e\xac>\xdd8XiF\xd8S\xfa\xf0\x0c!g\x1a\xd3\x9e\xfc\xcd\xb0\xc8$\xea\xce\x16\xa6)]\x0c\x1bv\xf6\xe6\xf3\xd0c\x06\xac\x94\x06\x9f86\xb3p\xa1>\x9f:\x14\xf3\xc4\x89\xae\x97\xd85\x9a\xd8\xf4\x9d<\xef\xbf&\xa5a\x96K2\xf61\xdbNf\xe4\x13M\xc1\xbd\xe1\x1b\x12\xca\x04\xdb|$/\xb77\xc4\x1f\x0e\xac#7\xb8\xee\x9a\xbfn\xeae\x0f\xfb\xc8k\xdb\x92\x85&\xd1\x98\xd1\x0ej\xb4\x03r\x0b\xef\xcc\xc3dO\x1a\xa4$[\xd2$C\x1b$\x1b\xacT\xb4\x1d\x1f\xd2\x80.I\xe2:?\x8c\xce\x1dq/e\xc86\xe7\x0d\xc6\x18_\x8c\xe7a\x9a\x91|\xa7\xc8\xa7\x83\xef|D\x89/\xd2\x9a\x06\x19I&.#@\x8fGE\xa9>\xf3\x08Jb\xd3\xb1\xef\xf5\xc0%\xfb\x92\xcb\x06}\xe0\xf1\x18\x83\xafS\xba8\xc33D\xb6\xcf8e\xdf\x9d\x9ek\xd3\xdc\xa7\xf2v\xfc\x93'\x90\x97\xc6 !\xa8\xe3\x95y\x9e^\x94uIg\xdap\x1d\xc7\xf3\x82+:\xb9\xf7L[x\xa2\x16L\xa34\x93\xcdc1\x13\xc4k\xdb3\xa3\xc7\xf7\xfc\xbc0G\xe9oW\\\xb1\x81\xa1\xb8\xbf\xe4]l\xb6\xefw\x81\xde\xc8]7\xd70 \xd8v\x8c\x00\xca-\xads\xe2~\xbd\x9d\xdd\xcc^n\xcf\x80\xa2\x8f\xf0\x0e\x06~k\x0f\xd3\xf5\x9c\x97\xdb\x1b\xb3\x97\xdb\x1b\x0c\xfck\x03#$\x01\x86\xdb:\x13.\x19.j\x91\x18\x82\xc9\xbd\xe62\x82\xbe\x9e\x9d\\\xdczW\x97/\xb7Qo{\xb9\x1d-f\x90\xa5\xe3\x1dg{\xa3\xf1\xe6\x0eh\x82^\xf2;aL\xd2\xdc\xdd\xf266\x9c\x97_{\x9e\xa6\x83\xc0\xd4T\xae7\xed\xf3N\xea\x11o'\xb6\x07W36\x86\xe7\xa3\xfe{\xa3 \xd4\x1f\xc5Ir\xc3\xde\xf9\xe7\x9fl\xd1\x12\x1f\x8e\x82\xb3\x1fO\xde_\x8e\xde\x8c\xb8\xac/_\xec\x9f\x1c\xd5_\x9c\x8f~=\xf7\xbb\xa9\xa1\xf1\xf9\xa3\xe0\xf5\xe1\x9b\xf3\xd1\xe9\xe5\xde\xfe\xfe\xe8\xed\xb9y\xf5\xd5s.\xd5\x8b\xb4\xaf\x0fWFE\xa9\xfd\xee4\xb4\xdfs\x8d\xf6{\x8e\xb1l D\xe8U6&t\n\xe70\x14\x07\x9d\xa6\x86\x88\xa6!\xc2\xd5h')\x16W$UM\xdd\xa4<\x02\xe2\xc7\xba-\x9f\x07\x0ep\x1c.\x0c)O\xf5\x88\xf9\xd8\x12\xb3\x1a\x973\x9b\xcf\xcf\x17\x04]+\xd8\xff\xc1\x94\xa6\xa3pN<\x95\x0c\x8eQ\xfdT\xdf\x9cb\xe8/\x8d\xcfJ9\x7f\x86 \xce\x03\xc6\x99\xf6\xab\xe3 \xed\x91H\xaer\x07\xcewJi/S\xfb\xf1\xb1\xb3\x89R&\xb3@f\x8a`\\\x05\x969\xe1\xb9\x1al\xf9\x7f\xa5\xf4Q\x91m\xddA\xa7{J\x8a%M\x1a\x13\xc2\xe7\xa3\x83\xfd\xf3\xf3\x8e!\x18\x8eH\xe4\x13\xc61\xbd%\x93\xf3p\x96\x0d!\xb1\xa9f>\xac%\xe4\"\xfd\x80\x01\xff\xd8\x1f]\x8b\x80\x8d\x80\xab\xb2k#\xach\xc2/ \xa2$#i\xbe7\xf9\x18\x8eI\x923&\xdeG\xc4\x01\\i\xed\xba\xae\xb37\xcdI:Bg:\x06\x90p\xc1\xe0\xb3\xc9\x94\xcd\xf97c\xadk\xff]\x9b\x12\x1eT\xb0%\xd3\xf0\xd7\xca1]\xf9C\x0f\xbb\xb6\xb1\xbd1\x0br\x92\xe5.Q\x97\x10\x97\x0eV\xd2\x9d*M=\x18\xc74\xe1\xaa\xa0m\x03\xaba\x99'9\xa9:P\x06\xe8c\x1d\xf4\xc1y\x12\xe7/\x1c\xcf\x93\xa6*\x99\xeaA\xdd\xf7\xb9\xb8X\xfeS\x1fO\xd9\xde\x0f>8\xc0$G\xf9\xe2+\xfe\xc2\xafW\xa8\x82J~\x01,\xa8\xdf\xdd\x81\x84\x0d\x93-\xe2\x90\xd1\xa3}[\xddZ\x85\x0b\x9c\xae\xc8\x05V\xd6\x07\xedpiO8\xda\x13.\xea \x17\xf6\x84+\x1e\xcd\xf2\xca]\xbe>;<\x82j\xc5a\xba\xb6>\x86\xf4v\xcc\x15\xdd\xc3\xda\xe4\x1b\xb5.\xa0\x89\x0e\xfa\x970.z\x82_\x13\xb2d#\xd2\xc7ki>\x82\x15T(\x18\x0253\x04\xd0\xebJ\xea\x83\x8ebl.\xc2\xd2\x11\xac@_\xd6n\xb4\xc8\xec\x92(k\x84\x17\xc5\x07/H\xc2\x05\xf1\x91\xf4\xf2\x00\x0f\x98\x82<\x8d\x16\xae\xe7\xf3\xa0\x85u\xbe\xeaC\x16H\xd4\xf2\x04P\xfc7\"\x8f'\xeb\xc8\x02\x89\x1e\x91J\xb3\xc9m\xf7\x94\x18\x96hJ\xe6_W\x1a\x92\x07d\xb8\x85Q\xe4o\x87G?8\xca\x8e&\x05\x9d0\x88&\x1e\xd29\xfb\x8b\x13\x14w^\xab\xbc]1\xa0]\x10.\x97\xf1=\x1e.\xbf%.?\x8e#\xfcG\xc2\xff\n\xcbL\x12\x91\x07/\xa1\xe0\xbcA\x95PD\xb5\x88\xa3\xc9\"c\xc8\xc7\x90\x12Q\xf7\xa0\x93\xca\xe1\xf1\xdbw\xe7\xbaa\xf2\xbb\x0e\n:\xf0f\x1d\xb7\xb6\x0bs\xf9\x05E b\xad`\x7fy\x1eF\xc5\x8d\x92B\xe3\xc7\xa0{\xd8\xc8\xb0\xb9D3\xec\xc4\x07\xc7Qp\xd5\xd9\xa2\x9d\xcb\x83\x18\xaeB(\x18)\xf8\nY6\xf6d\xad\x1c(\xa7\x03\xfe\x9b\x0d\xcfM!J`\x8f\xfd\x8d\x7f]\x13\xcf\xe8P\xd9|\xd8G\x05#d\x04\x87\xff\xa4\x9dl\xcf\xc3\xa3\xb6'O\xe0\xdf\\\n\xa0^\x8f\x99\x079\xfb8P\xac\xfe\xebc\xaa\xf7\x1b\x18\x88\xc1\xad\x95d\xc0\xa9`E\"\x00\xd1\xcc\x19V\xee_\xa7\x1chN\xf8\x18+\xa4\x12\x82\xb4\xd3w\xcc\xa0\xb6\x86\x97~\x15RPn\x0eT\x04\xc1\x1d{\xaa,0\xdc\x80\xc8m7kw\xe4\xc2\xa4 |\xe8\xa6b\xf5\xc1\xb0\xa2\\\xe6\xfe\xd7g\x18#\xa8\xe3L\xaby\xea\xd5@\xf7\xea\x82N\xd3T\xf3i\xaf\xf8\xd4\xf3\xd5\x93\x01\xba\xb4\xc8h\xea\xb3\x82\xb8\x0f\x9d\x83\xb1\x97\xb6$@\xad\x94alb\xa5\x03\xa5\x03U2\x04b?\xd7\x92wM\xfa\xc8Tl\x13:b\xed\x99\xa9\x07\xf9}[\xa6:\xc3\x80>\x07'G\x0e7\x87\xb0\xc1\xbe\xc0\xef\xa6AB\xeer.X\xbf\xf0Z\x0c\x98W\x14\xa1B\x92R\x18;&n\xc2\xb5\x9a\xa4\xd4\x8f\x14\x8d\xff\x049CU\xe6\xf9p\xcajX:\xde\x9a ]\x97\xf5\xb3`\xbcxr\x17d\xa2\xb1\xbe'|}g\xa3\x8f\xf4\xddG\xf2\xee#u\x87\x1d\x924f#\xe4Qqa\x07\x9c\xdf\xef\x9e\x8d\xd7\x06\x83\xdf\xef\x9e\x11\xc6\x88K\xf3\xceZ\xa5\xeb\xe3\xdetH,\xf7\x0b\xa0\xed\x0b\xab\xd4\x0fr\xcaO1<\xc8\xe7)\xbd\xc5\x83\x1d\xa68\x8e\xd2\x94\xa6\xae#\x8b!\xca \xa19\x84%\xf2M\xce\xb0\xe5\xf7Z\xbd\xc5AU_t\x19\x0b\xd7~t\x12\xa5\xf9}\xf5E\xde\x90\x0f\xe1\x15M1N\x8d\x81x\x8c(]\xab\x1d9t\"J\xb5\xbd\xde\xbb#\xecp\x98GcnHa\xc2\x8a\xce\xec\xd2\x84\xeb\xb6\xe6\xe8\xec\xb1\xa55\xac\xde\x9c\xdb%w\xb2\xf6\x04\x19\x18\x1a\xa8NtV\xdd\x1b\xc1t\xb3M>f\xcc\xcf\x91\x9a\xf7\x08\xba\x916/1\xd4M\xdf\x1e\xf0,\xbb\\HK\xf8\x19J} x\xf5#\x06\xc5a\x98\xed\x04k\x9b\x9eW\xb7w\xbf:9\xf8M\x88\xcb\x95\\\xbd\xcb\xf7J\x18B\xc2\xb4\x03\x92L\xf8\x99Xj:$\xb2\x0bdH_\\\\_\x9b\xe0\x7f\x03\x99-\xb8\x14N\xb6\x1d%\x7f\xb7}\xd5\xac\xc9\x91\xa3\x80+\xea\xf0^\xf3\x9b2\x06W \xfd\x14\xf0\x93\xe6\x13\xb6}\xa3\x95\x8b\x1f\xef\xe9{P\xdeC*8kJ\xbc\x17\xb8\xef\x15u\xae\xc2\x0dL\xb4\x86h\xca]x\xd8T\x1f\x13\x97rnB\x8d\xdc\xe4\x80T\x85\x9c\x9dP\x91\x8c\x98\x1a\xfa\xc60\xb3\xb0\xdae\x18\xc4\xacCG\xc1\x11\xb2-\xf8'~\x9e\x904<\xf0_\x80\x8a\xa6\x17\x1e\x845\x02\xe9\x81C\x90\xf4\x82A\xfb\xcd0b^\xef\xb9V\xc2\x80\x7f\xe3]:\xf3e\xaaK\x1f\xc2\x15&Z4\x88G\xb3\xea\xd9-#\xf2\xd2\x94\xd8\xaa\xf9\xc0\xd6dF\xf2}\x9aL\xa3Y/\x1b\xd8\x1e7\xd2r\xdfdMly\xd6\"\x06\x8aj\xb7ij\xb2rW\x95.\xcf\xfaf\xc3\xc9\xe4GJ\xaf\xfb\xf2\x7f\xfd\xd9\x03\"\x1c\x8f\xa3v\xf8\xa9\xd4\x9f\x7f\xe2^\x84'Sh\xc6\xcc=\xcdU\x8cj\xf3ju\xc1\xf4\xfd\xda\x99\x97^\x90n4\x9b\xad\xd4\xae\x1c\xc5\x85F\xa7Q\x1a\xde\x8b\xe3V\xdb\xc6\xa6\xd1\x0fW\xdbZ\xed\xe5\x832\x16\x9e\xce\xb6\x0c\x8b\x9c\x8a\xa2G\xc5W\x16\xfev\xfcpS\xdeSvs\x1f\x9c\xcbK\x92\x1d\xd1 \x0f\xd3S\xef\xfc\x0d7\xe0\xa9\xa9\x02\x94\xd5)O\x8cb7q\x9f7o\x15PQ\xf0\xb4Y\x10\x89\x82g\xcd\x82P\x14|\xd3,(D\xc1?\x9b\x05\x99(\xd8T%f\xf6b\x8b\xbd(\xdf\x94:F\xdc\x9ey\xf5\x06, *T\xe0\xe9\xb1.\xa8\xaf\x88\xaf\xd6\xf4\x0dlF\xd8\x05\x81\x9f\xb1\x95\xee\xca\x9e\xe5\xb6k\x9e\xee\xa6\x0f4\x10\x1f\xf6\xdc|\x1ee\xdc]\x95\x15\x84\xcd\x027\x0f./\xd1Twy\x89\xccb\xd3\x87T\x01\xf2;\xd3\x88P\xd0%\xbb>\xba\xaf\xab\xe0\xc5\x82\x93\xb4\xb4\x88\x99 \"[/\xaa\x8554]\xc3\xe4`lM\x0dM7<\x01\x0f\x0e3z6\xa7\xb7f\x92[Zmh\xe6\x01,;\x87\x18\xf7Et\x94Li\xba\xe01 ;\x88\xc2\xd2\xa1\xb1\xeds\x0bz\x15\xc5d\x08[OWm\x96\x8aqz\x96\x91N:q1\xed\x84\x98wB\xc4rg\xf8D\x0cXx\x08\xc9\xaes\xba|\x0c\x9a\xc2\x1eh\xfa\xaf\x1e@Q\x0e@\xa7\xb3\xd5\xde<|\xf0|\xe5*\xc2\x83[\xb5Y\nS\n\xa3\xcbe)\xec\xc0\x18\xdf\xfe\xbd\n\x8d\x0fy\xf0SF\x13\x14\x15\xc2Kn\xa1D&\xad\xbc\xbd\xa24&a\xd2|\x8d\xe1\x03\x9b/\xb9\xe9\xb1\xf1\xf65M\x17\x1a.-u\xa8{\xa6*\xb5T\"*KZ:Q$JZzW(\xab\xe8\xb4\xa8{\x9d\xde\x95\x89\x82\xd67bQ\xd0\xd2\xbb\xb8\x94\xd7\x14\x88\xa6\x08>n\xbc]\x8aF\xb6\x9a\x8dp\x01\xed\xdb\xc6\xdb\xb9\x04\xdfj\xf5\xf3F\x16\xb5\x86\xb6\x90%\x9b\xdf\xb4\x061\x13\x89\x8a\xb5\n\xe1\xfd\x97U\x08\x97\xe5\xba`=\x08\xa2\xecT\x84\x85\xf6\x95\xa20\xb9\xf7\x1b\x90\x96bN\xad\x86\xa6x\xa1\x0f7\xe5\x9b8\xcar\x15\x82\x91\xb5\xedw\x98\xdc\xd7i\xf5\xaa\xe5*t\xa3w\xf2\xa1\xc9\xfe\xf9\x86\xb6]\xcd:\xff\x1c:\x7fK\xb5\x97:\x7f\xd6,\xd0\xe9\xfc\xaaF\xfe\xa9:\x7f\xac\xb4U\xe9\xfcuK\x80Q\xe7/\xd3J\x1dD\x93#\x1eG\xb6\x05\xf9\xd7\xa9\xff\x93([\x86\xf9x~\xc8t\x860\xe6\xceP\xc6:\xdc\npc\x07\xe2^\xd2\x92\xc0\xf5\x1a\x17\x1aCS7\xe9\xe4\x9d:\x16\xff\xf7\xd9J\x90\x84\xbb\xd0\xc3\x97Z\x17~:\x90\x18\xd5\x90h\x91\xd8W\xb0\xcb\x14\x08;5\x1c\x0e\xe4AN\x7f\xe2\xd7\xaa9{g?]\xd3a\xbb\xf4\x8b\xb4|.F\x17\xbb\xfc~i\xe9\xfe\x18a\xb8\x9a\xbf\xe0\xa6\x80>*\xa9\x0f\xb4=\xe3\x06\xc6\xd3\x06\xac\x9di6c\x02\xfa\xb88x\xa8\xc5\xc2\xe3\xf9\xaa7_\xc0\x18\xb6\xa1x\x01\xe3\xf5u\x0f\xe2\x8b\xf1\x07\xb5\xe6\xc5X\x13kQ\xc6Y\xc4S\xe5\x1d\x03\xf3\xc3=\xae\x93\x01\x8e\xc38\x16\\\x90\xf8p\xc1\xea\x96\xc1$\xb8\x9e\x96\x96\xdbQ\xaf\xc3\"\xe9\xae\xaez\x8er\x92\x17\xfbh \xa2`\x92\x80G\xec\x0e\x18\xa0\x88\x81X\xbeC\xba4,<\xd1\x9a\xec\x15\xe3\xb2\xf2\x9d\x90\x90\xb4\xc7Sl\x1c\xa3\xa4X\xac0\x16\x81\xe7\xd6\x17\xf5\x1f@\x9bvK\x14a\xf4\xf4%\xe4\x89\xbf\x81/\xf6c?+\x08\x0f]\x8c\x96\xf6b\xb4\x9c\x87J\x99\xb8\x8b\x87N\x08\x8f\xf3d\x8c\\\x07\x82\x85\xa6\x01I\x8a\x85\xd92\xcd:G93\xdd\x15\x7f\xb8\x1e\x0c\xf1\xac\xb7\xe82U#Ou\x1d~\"c\xf3s\xea`;V\xbe\x02u\x8b\x1a\x95\x91Jw\xc1\x89\x12\xcc\x07\x84\xd7\xab;\xee%`\x90\xa8Zm\xda\xa3\x96\xb8\x9b\x80\x82ff\xe5]P\xd1\xaceF@\xb69Z,\xf3{q\xa5b\xcd\xc2\xa2\xa0\xc6\xcb\x90\xc8\xd5\xfd\xc0X\xcft\xbb\xd3\xb8\x86b\xdc\xfch\xba8\x08\xf3Pn\x80\x11\xba\xbb\xaf\xb9\xce\xeb\xb2 JD\x0c\xda\x8e\x83\xa3\xdcu\x0e1\x91\xa4]\x10\xa9\xed\xb7b\x8b5Q\x89\xd5\x82\xc6\xea\x0eEs\x96\x9e}\x12\x1d\xadNC\xad\xa9\xeb\x92\x90e~\xaf!\xc4\xfa dk\xd3\x84\xa0\x85|\xdf\x03Q\xcb0\xcbni:\x91\xb8\xe7R-CFU2\x94\xb9\x07\xffk\xf0\xd9\xbd\xc2\x16Q\xf2\x06[\x1b\xda\xfcK'\xe4\x8a\x16\xc9\x98\x9cG\x0bB\x8b|\x08\xcf\xbe\xb1@+\xa1\xe7\xacb\xe9_0\xdb\xad\xd7\x9fU\x02\x95\x16\xcf^\x02(1\xdc]\xef-dJ\xf3\xe8c\xad\x1e<\xae\x06Bc_\xcc\xd1\xf7\xf5\xc2\xdf\xaa\xf2R\x1ady\x98\x0b!\xc0(\x9c\x1d\xe6D'\x9cY\x1c\xae\xd2 #\xf9\x19k\xba\xba\xdao\x8d\n :hg\x91ri\x88Kj\x19\xc9\xb98f\xacd\xf2\xefW\xb0g\x184w\x98b\x03\xef'\x8fj\xc6k\xbd\x1f\xb0\xcax\xe5\xa5<\x11\xce\xe4/\x19o8\x994\x07\xbb\xcaX\xfb\x04\xc4\x10T\x06;p\xe9J\x8a\xeb\x12\x8a\x04\x06\x048w\xcaslau\x1e\x8d\x80\xd5U\x10\x0d\x1az`\xa1\xdfx\xff\x82\x01\xe2B7^\x9c\x15\x1f\xaefF\xdbH\xed\xe5_\xa3-\x95\xd6\xd7\xf7Q\x1c\x9f\x921\x89n\xf0\xb4,\xeb\xa1@\x19\xe7J\x92\xde\xda\x8e\xd0\xa2\x94]\x8f\x89\x7f\xfc\x9d\x9cN\x9bB\xa0\x92\xa3~*:\xf9\xd9\x17\xb2\xa0\xdau\xc4>\xba$?=\xec\xa7KR\x84\xedV\xed\"\x84\xebR'C\x84\xeaR'\x0b\x842\x99OC\xbc\x11,\xb4\xbeP\xd5\xfa\xec\x06\xd4\"\x88\x92)I\xb9\xf8\xe0FA\x94\x93E\xd6\xedhV?Q\xe9\xe1s\xf6\x8ag\xf7\xef\xf0\x1f\xcbP\xb7\xb5\x88W\xd0\xa6h\xb3&\xbc\xec\xd2v\xe7\xd2\xd3\xed\x13\xb5\xddy\xd7\xc6\xaeH\xd5\xe1\xeaR5T\x92\xb5R;\xecQKf\xdf\xed\xbe\xb7/\xd6\x9c\x85\x96\xa1\xad=\x1b\xa2\xbf\xd7\xa0kz1\xfd\x9b\xf5\xe2\x8ey\x14\x0eW\xdc\xedc\x8dGC\x99\x04\x98]\x91\xfd-\xfet=\xd8\x86\xad\xea^\xca$X\x84KE\x10\xf2\x81v\x11^$\x84\xe6\xb4n\x96\xcf:.\x96\xc9\xd9\xb75\x0f\xe2\x13K\xdc\x10xZ\xd7\x9e\x92\x8b|J \x06\xaf\xf1\xf0[/\xd6J\xb6p\xab\x80'\xeb\x82j\xe5\x9d\x8f\x8b\xe5\xc5\xe6\x07\xbe\xe3\xc1:P\xcb\xdd\xe4\xce{Y\x1dsi\x1f-2\xa2\x0e\xa2T}\xbf>f4\x19\xf0\xed|\xc0\xf4\xeb\x01\xdb.\xad\x0e\x81\xa6\xeeY\xdd\xcd\xa0\xfbd\x05Z\xa7+\x1dF*)]\xf7]\x81\xfd\x04{\xf9\x94$\xa3\xaaO|)\xd8)\xc7\xde\x1dy\x9e\x13Y\x96\xbf\x19\xc7V\xf3\x124\xa6\xf6*O\xe0*O\x06\xd9\x02\xb4\xb3<\xe0\xfaH\xc7\x86K\x93\xfd8\x1a_\xf7\x10^\xd4\xa7\xc4^\xa5\x87\xb9]\x88\xb3\x11\x9d\x03\x03pL\x9e\xa8^\x90S~\xf4\xf3X\xd4\xad\x84\xb6p2\x01\x07\xd6\xab\xcd\xab\xc1\xf8\xb8\x1b\xa1\xf1[%B\x91#\x08\xbdM?06\xee\xbd\xc9\x04\xd8g\xb5\xc3\xef\xb4\xb4\xbc-R\xb2\x8a\xb5\xa5r;\xebeo\xf9\xdf\x81\xdf\xca\x07~\xabj\xa9\xff;(\xd3?\x7f\xd1AY\x97\xceB{\x1d\xa7\xd5\x0f\xca\x0c\xa7\x0bx\xf2%\xf4\x9b\xb4\x9f~\x13\xf69\xcc\xea\x10#\xc2\x9e\x1ba\xba\xbaX/Dz\xa5f\xda\xcfX.\x82\x08$\xb6\xdbFuA\x9d\xbb\xc6MS\xba\xf8\xe9\xccs)jYx\xff\xd3\xc9S\x9e`e\x1a\xc6\x999\xe1\x0b\xe8\xa5\xf9\xb2\x1d\xdb\x81\xd7\xaaB}\xb7I\xe1\xd3L\xe4\xa5\x07\xf1\xa3\xf7\xec\xde{\xb2\\\xa1\x9fl\x1f\xb7X\xc6\xd9\xc2\xc9H\x8esrN\xcf\xc2\xc52\xeee#\xaf\xbc\xbb\\\xf6\xe5\x19\xdb\x1cxm\x8e'\xcf%5w \xfd\xdd`\xa2\xb5\xcb\x1bEF\xd2\xf2\x990\xb4:\x0f\x93ILNVi\xfb\xa6\xccw\xdc\xed\xbb\xa1\x0c^\xe7\x03\xe8\x1b\xbd\x85\xe132\x80\xcf\xe9y\xb9V1\x81\x86\x9dO\x9d\xc3\xf2e\x9bdtw\xb4\xeb8\xf8B\x86\xbc\xffbN\x96\xbb\xce9\xb9\xcb\xf7R\x12>\x92\x9b\xd4\x0c\x0c& \xda\x93\xe50R\x9b+\x06\x04c\x1d\xf6\x08\x9e\xc4\xd8M\x16\xfda\x0d\xcfkF\xbddX\xac\x05d\xc3\x1fi\x94\xb8\x8c}x\xfd8\x97EGm\xb0\x89\xfa\x06\xa0\xad\xf5(w\xbe.\x11\x1f\x81\x1fu\xe3E\x1e\x86\xe2E\x87\x7fz\xc1\x818\x91F\xa7\x89\n,\xad\x17\xf0\x10\x92\xb58\x02\x8f\xef\xc2g\xbdt\xd3\xec\xa6\xe9n\x8c\xf8h\x98e\xd1,a\x8c\xcc.\xa6\xd7\x92>o\xf1\xfc\xceMuE\xe4y\xb6\xef\xf3\x95\xa6bJ\x03]~\n\x03'&=\xf3\xc2c(8\xb4Ta\xac\xe9\x1dH.R]\xa0\x89\xd6\x1b\xc9\x90\xeb$X\xa7x\xda\xc5\x9aK\xd1\x83XO\x9ck\x19\xfe7_@\x02\xdbj\xa2\x7f3\xf6@\x99\xb9\xfc\"1`\x0e\x90P\x99tG\xd2\xf0\n\x05\x8a\xdaO\x91|,e\n\xdb4\x9a\x15\x12hm\xb3L\xda\xc7P\xce\xe3\\\xa6\xc1m\x1a\xe5%D\x99}\xaaI\xa7\x845xM\xee\x19\xfe\xf5\x0b\xbe\xff$\xa8\xd6X>\xa1V\x85\x91\x07\x01u\x15\xd2\xe0\x99\xc3R\xf1\x9eG\x07l{\x157\xb6\x9b\xe6\xc5r\xa6\xd8\x14<\x02F\xbd \x14\x05[\x9b\xdf|\xab\x0f\x86Q|\x91\xbbOn{\x99\xf7\x92\x8a\xb5+{\xad\x9f\xb3\x04\x8f\xf5T\x8b\x80\x95\x9b\xc2\xa1\xed\x87IBs`\xeb\x12B\xce\xfb \xccj\xa1\xd8\xdas\xd2!\x90'}\xbd:\xb0\xa3D\xed\xd9)\x99\x92\x94$\xe32D\xdc<\xca`\x1ef\xc9\xd79\\\x11\x92@\xc4\xaf\xb1D\x19\x99\xc0\x00\xb2bIR\xd7\xabA\xb0\xa1\x90I\x87\xf8\xb0\x86\xc7\x0dJB\xc9Z\x10\x1fm8\xbb\\P\x81\x86F\x0d\xfa\x86X\x843\xc2\x98\x1f'\xfa\x93i\xcb-\xc7\xa2y$\xab9d\x93`I\xd2,\xcarSX\x05\xc9\x14\x92\xee\xd3\xbdd\xa5\xe3kU\x1f\xd0o,=s\xaf\xb0\x1e\xd2~=dO\xe9\x06\xf7\x92U\xe1\x82x\xe9\xcd\x86\xe1\xaa\x12\x9aGS\xbc\xe68,\xb7oxYU|\xf2\xa4\x02J\xf1\x88\xa8G\xbe\x066\xd8!\x08p1\xf8\xaeZP\xe1\xcb\x92\x91\x0e\xf4\xeayUd29\xb7\x89\x12\x13-%?\x93\xfb\x03zk7\xa0\xca\xa7\"\x0f\xa9C\x8a\xda\xfa pFI\xceS\xc20\xf1\xfe\x9a\xdcsdNi:&\xc7\x12\xed\xbe\xc85e0\x10\xb2.\xbe\x8a\x8b\xf4\x91\xfdcUM\xf4\xbbb?\xb8\x86\x80\xf0\x11\xe9\xd7\x1f\x1eQs\x1b6\xbd\x92\x86\xba\x84\x0f\xf9\xc8\x05^\xc4\x06/F\x83V-\x03\xfc\x8a\x84=\xb5\x0f'\xc1\x84\xf2\xf1Z*\xdb\x97^.L)\x8a\xed\xa5\x1b\x0d\xf2I\x82(\x13\xbc\x8e\xdf\xd1a\x02L\xd5)\xab\x9f\x19\xdb\x07\xcd\xcb\\\x87\xddGtg\xd3\xd7\xcf\xbf|\x90\x0e\xa6q\x91\xcd\xfbN#TS\x99\xf3\x9a\xb6\xb4\x13Hf\x8c!\xc7\xab\xb4\xafEk.\x1a\xb2}NOXz\xea\x97\x93\xd4\xa7cI\xc3\xc4$\xce\x18D|Z\xe5r\xad\xfeS\xca\xba\xec5\x9f\x98_\xa0\x86\x03\x1b\xc6J\x0c\xe3^$\x91d&--K\xec8\x81\x04\x0d\xb31\x7f!Wx\x14E\x9e\xa4\xac\x08\x0c\xa2X\xfe\xfeR\x0c\xe8\xf1i3{\x07\xdf\xc1\xa9\xee\xe5\"(\xdd\xe6\x98<\xd6f\x8c\xd8\x8en_\xa9Aj\xcd\x87\x9d\"\xa81r1\xb2\n\xf4=A\x07?\x83\xe8|\xc6\x84O w\xcb\x94d\x19\x93\xda\x17E\x96\x03\x89\xf29I\xe1\x8a\xf0\x06h\xaa\xc8\xd2>\x06\x1dv`\xbd\xfc\x90\x862I\xa5\"U\xba?\xe7N\xae\xc8\xdb\xa8\xe8Pz\xd4\x8ei\x92\xe5i1\xcei\xaaS[\xe4#g\xc0L\xef\x95F\xda\x8e8\xa0>R\xff\xb4\xbbA\xa9\xba\xec\xd0\x94\x8cICK\x92{\xbb\x02\x1bYM\xa2\x86]\xd0\xbe\x17\xf3>DUN\x8a\xe5l:\xeb\xa4\xc3t\xcf\xf2T\xa0a\xbd\xf2\x81\xf630\xbf\x8f\xe2\xf8S-\xcch\x95\xab\x8b!\xaeb`n\xdc\xbf\xe8\xb2\x97X\xac\xc9\x7f\x89K\xac\xdcH;\xb7\xd0D\\\xc6\xab\x8dF\xbf}\xe2\xe8k\x8b\xff\xcf?\xcb\x8c\x85\xb84+g[\xc5\x01\xb7Q\xd2[\x8f1\xddi\xf6!\xa9<}\xb5\x93Q~\xac1}I\xb7\x01\xb5\xe74\xbdK\x16\x9f\x83\xbc\xb8t#{k\x92Xzw\xf1o8\x97\x10\xb9\xbe\xec\xf4\xe5*\x91\x15J\x8a\x04R\xb1k\xbfM\x82\xec\x95\"\x9b\xbc\xbaG\xf5\xc6\xe68\xc3\xa3-TUNP\x1f\xb1\x9c\xef\x8a\x90\x0fB\xab2\x03\x16\x02\xd0\xde\\\x86PQ\xb2,\xf2S25\xc3\xc5}\xcd1\xf2\x916\x9c\xff\xf4I\x1aUZ\x7f\x89\x07y\x19\x96<\xf5\x98\xb8\xb3\xa9XA\xec&aR\x9a\x84\x13n\x12\xc6\xac\x85\xf6\xcfK\x1d\xca\x08\xf4\x80~/\x8e\xa0\x18\xc7\x07G\x12\x85S\x1aQ}pJ\xa2\xc0d\xd1u\xa2\xc0\x83\xfb\x16Q4\xde\xf2y\xe7\xed\x8b\xb9\xe5?\xe4k9G\xd6\xd3\xffqG\x0cKt\xf3\x86]\xcb\xdc\x95_/\x1d\x01\xc4o\xfd\xbe\x06C\x08\xfb\xb6g\x88\x17\x0eC#\x910\xba\x98v\x0c\x89\x95\xd3\x8e.0\x1c\x96\xe3a?\x8c=)z\xb5T\xadB\x99\xba\xb4(r\xaeueb\xe8\xba\"\xf3=\xd8\xd6\xdd\xd7\xad\xcd\x06D{\x93h\x8b\xc2\xad-\xa3\x0d\"w\n\xd9\xc1\n\x97\xf8W\xc7\x99\xa5\xe5\xae\xa0\xdc\xd3\x9d\xd1\xdd\x92\x8cs2QM\xfcmBIa\x07\x8e\xc3\xe3v\x01cz\xce\x85\xf0\xf09\xbb_\\\xd1\xf8\x83\xa6~\x04;\xb0\xf1\x7f\x7f\xcf\xd6\xff\xfc=[\xffjc\xd6\x86\x08\x11\xe2b\xb0\xfea\xf3\xeebs\xf0}8\x98~X\xffjC\xe3\xe6T \xe4\xe6\xd5\xc5\xe6\x96\x01\"\xe3\x10\xf4bs\xf0\xad\x01\x841A\xcc\xad\x7f\xa8\x93\x1d\xd8\xde\xaa\xa4f\xa9\xe9\x81B\xe7:\x11NM;R'\xc3\xd7\xed\xa6\xa6\xfa\xa62\x12OY\x0d\xf5\x7f}\x9b\xac\xa4\xdd,\xdb\x80\xc6x\xf6\xcb\xfey-\xe7\xd9\x91\xd6\xa7y\x949\x9e.\xec\xf2\xa4R\"+\x16,\xd3\xe4\xb4\xc1\xe7\xb0\x03Ga>\x0f\x16\xe1\x9dF\xac+K#\x8d\xf8\xd2\xef\xb6'\xef\xf028`\xdbNBou\xf2\xa7r^\x07\xea\xb9\xd8L\xaf\x7fH\xddC&\xba1\x1e\xa8\xac\xad\xf1\xac\x18\xb5 \xd2d\xddiz\xa7\xea{\xa3\x89\x9e\x08\xd2\xac\xa0\xc9\x97nK\xd3\xc2\xeat\xebX\xa2\xbe\x93\xe1\xba\xab5\xde\xed\x16\xd0hD\xa0BC\xaa\x066\xc0Z}\xf2\x04&B`\xf3@{i\xe5AM\x13\xa4\xb1\xcdc.\x15KF\xa9\x9b2\xa8PmBdF)\xdc\xbdQ\xe5/\xffF'U\x93\x17\x1a\xec\xc0\x8cm\x86\xbb\x90\xc3:\x8f)\xd6u\xc6\x0c\xcd\x0cJk\x9a)\xac\x12\xe6\x13\x18\xc2\xba\xe6\xf3D\xb8\xdc\xf2\x84~\x11\xe6\xf33\x1f\x97\x16\"\x1d\xb4\xe5,\x90\xcdp&\xc1`\x17bW\xe4!u\x9f\xa2\x86\xba\x0bOa\x08\xdf1l\x84\nX\x8a\xfdk\xd0\xb3\xfaK\xf5\x8ci0\x17\xed\xa1>\x1e\xd1\xf9\x10a6\x99\xc2\x87\x0c\x85\x13\xf4w\xd7\x0b\x1cSn\xb2\xd3\x96--e\x13\xb4\xd9\xebIH\x9fpLo\xa8K\xbc\xc6v\x02\xea\"\xbe\xea\xf6w\xb4\\_b|2\xb2Jv\x8ca*\xe9\xdbx\xa0\x17_\xa8x\xdcr\x9e26\xae\xa1Js\xa75\x91;\xe5#;M`\x00\xb1\xb5gJ\xc0\xbd\x98\x11W\xc2T\xb6\x9c\xff\xb5\xcdu\xb7%zB\xc0\x00\xc6\xac\xac\xad\x04\xd8\xfax\xdb\xa9\xf4/l\xe1\xff/k\xf9\xc6\x8c9\xca\x18\xd5f$\x17\x82\x99{\xeb\xf7\xdc\x05K_V\x18\x80\x8b\xb8\xea\xbe\x9c\xba\x84]\xb8q\x13\x1fBYi\xec\xa1\x05\xdf\xb8a\xae6\xab\xa3\xce\x9d?S\x08i\x02\x98\x1dk\x17\xae\xf89\x82\xdb\xa4\xb4b\xb5\xaf\xdf\xf5\x99/\xf3JHx\x1c\x06\xcb\x8cR\xd5\xa5\x8c\xe7\xe4\xe2.\x10L63EJQ\x1bP\x086\xf3\xdaV\xfe.\xb3\x86\xa80\xe6_k\x13N\xee\xf90\xad\xf0\xa9W\x14\x01g\xd6F,\xe2^\xb42c\xed\xcf\\\xb9\xa6\x00\xfb=\x17l\x86b\x8c\xaeq\xcf\xd7\xf4\xdc\xe8\xc5\x95c\xe4\xe8\x1ccbn\xfa0s\x85\x15\x06\xf7\xec\xb54\x88 \xe6f\xe0Y\xb0]\xb6[;\x8b\xf0\xee}\x18\xe5\xdc\xfd\x8cq\x98\xb9{\xef\xa6\x81x-[B\xc3{\xe8\xe3&\xee\xe4i\x18\xc5\xc8K\xd1em\x17\x9b\x96/a\x08\x13L\xe0\xd7\xffhT\xb1\x00#\"0)\x98\xc4B&o_\xf1\xebG\xb1X\x15\xd5\xd2ic\x87}\xbd\xf7\xb9\xafn2v\xa1\x80!\x8c\xdc\x85kH\xf0U{\xa9\xb8\x87IW \x1f\x12\xf7\xd9\x96\xa8\xdc\xa1\xe5I\xe7\xc2z\xf7\x9c`#\x8c\xe3\xe0c\xe6\x0c\xe1\xf9\xf3\xe7~\xab\xb0\xc8\xe7\x1b!6\x9aq\xa8\xa7\xcf\x9e\xea\xa1\xd0\x88\xc7a\x9e}\xffL\x0f\x93\x92I1&i&\xc1\x0c\x1f\xccd\xe2! \xf7\x8d\x01nI\xc6\x83\xdb4\\\x0ej]|\xf6\xfd?[\xf0\xfc\x10)k\x8e\xa5\xdd\x01 8'\xf1\xb2\xec\xe9\xd3g\xed\x01I\xc0\xda\xb8\xbf7\x82\xd5\x87\xfe|\xb3\x8dE \xd9\x18\xfd\xf3\xcd-3(C@mH\xcf\x9b&\x06'\xd8\x98\x10\xb2\x1c\xc4Qr\x1d%\xb3\xfa\xb8\x9eo\xb61[\x83V\x06\xf7|\xb3\x8d\x83\x1al\x1c\xde\xd3\"\x97\xc0m\xcc\xd6\x80\xcb|K\x83<\x9c\xe1\x1c.I\x1a|\xcc\xee\xb0\xf2\xb7}+7+\xb6'~Bo\x93\x98\x86\x93A\x91\xc6r\x96\xbekA\x914\xad\x93\xc6\xd6\xd3v\x1f\x18\x10\xdeG\x18\xe4i\x98dS\x9a.H\x9am\xcc)\xbd\x16-?mO\x95\xa1R\xedGB\xf3\x01\x9d\x0eP\xc9\x16\x0d\xb5\xc9\xa3OC\xcb0\x0d\x17$'\xe9\x80&\x84Nec\xed\x89\xeb\xd3\x18\xd3d\x96\x03\xe9\x0e*\xdbj\xcf+kK]\x04[\xedE\xc0@\x1ak\xffi\x9bN\x19Ts\xe9?m\x13(\x8f\x9dP'\xcd\xf6\x8c\n(\xba\xccxV* \xd9\xee\x1c\xa7\xdb\xc6\xce\xa0YF\x02N\x1d\xea\xd36\xbd \xa8\xe6h\xdb\xd4$\x00[\x03n\x0f%\xa6\x8dm\xe6\xbb6Rh\x98=knn\xed\xceq\xa8\"\x9f\x0f\xc8]N\x92\x8cAo\xe0\x06\xda\xdct44\x83\x95\xcb\xe3\xc5l\x83\xf1\xa0\xabp|\x9d\xc9\xd5\xa7\xc1F\xb3\xce<\xcf\x97\x03\xd6\x01YG\xc3M\x9au\xd4\x89\xd6\x90C\x13\xbc\xda\x1c\xd8vQ\xf6\xad\x8dVs\xc5\x8c\xa7X+\xfb\xd8\x8d\x8b\x94\xfc\xbf\x82d\xf9\xe0\x8aN\xee\x07d\x12\xe5\xb4\xdc\x93\x9e\xb5\xf7\x04[\xed\xb2\xc3m\x8aiV\x13\xdd\xac\xb2\x1d\x95\x9fl\x13\xaf\xa1n\xf9\xb5\xf6\xb2\xc0\x1a5n\xf1\xcc\x80\xfc\xda\x04\x19F\xdb`\x7f\xcf\x0d(m\x92\xe1s\x03y \xe3Sh\xb8E\xbe\xedmJ[OO\xfb\x86\x8f\"\xb0\x82C\\HQN\x16%\xde\x0d\x0b\xa0YQE\x98F\x04\xd1\xd6Q\xa38p\x1b\x93D\x91\x01\xe3\xcd\x06\x16az\xcd\x98\xa1\xfc\xaea2[\xd5\xe8\x84\xc4r\x80\xcf\x0d\x84\xd5\xacD\x938J\xc8\x00\xaf\xb6\x859M\x07W\xe1dF\xe4\x97\x0d\xb4\xd6l\xa4df\xd5B4\xac\x89f\xcd\x1b\x9e\x02r\x90\xe5\xe1bYV\xd6\xec\x00 \xd6\x8aINjs\xb2\xd5\x1ef\x86\xb71\xb3\x8d\xa9\xc0\xdf\xd6\xf7m\"\x910\xb5\xad\xba=\xbd\x8c\x06\x9b\xdcF\xd3\x18\x83R[\xd2\xec\x94\x08\xd3\xe04\x9a\xcd\n\xc1\x1aD\xfeT#U\"\x9cF\x9c~\xde&k\x99\xd5\xeecc\xb4m\xc8\"\x8f\xe2\xba\x8c\xdc\x9e\xc4\x9b\x88\xdc\xd6`\x9e\x1b`RJ\xf3A\x94|$\xe3\xbc\xec\xdcw%\xa46]\x0d5^\xd8I\xdc\xa8fly\xd0\xd4\x8e\xda\xb5\xa5\xad9\xbd \x8d[Z\xfc\x06M\x0e\xeb\xb0U\xbb8S\xbf43\x8d\x92 ,\xf8\x0d\xa1\xaf\x1dX\x07\x02\xeb\xe0|\x1d4\x0d\xbdR\xd7V\xfa'\xff\xa2\xc15\xb9\xb7\xe6O\x16\x95\xc5\x11\x0e\x83v\x95\xcb[\x0f>\xd0 %\x19\x8do\x08St\xeb\x17\x1d)+\x8d\x98\n\xbe\xb5\xf9\x0d\xc7\xee\xc3\x07\xef\x1f\x0f\xde\x8b\x7fll\xfc\x1f\xc8h\x91\x8e\xc9Q\xb8\\F\xc9\xec\xdd\xe9\x9b\x9d*\xc3\xe1\xe0\xaaH&1[\xe7\xc1\"\\\xfe\xe3\xff\x07\x00\x00\xff\xffPK\x07\x08\x05\xef\x9fw>9\x05\x00\xf8\x0c\x1b\x00PK\x03\x04\x14\x00\x08\x00\x08\x00\x00\x00!(\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1f\x00 \x00swagger-ui-standalone-preset.jsUT\x05\x00\x01\x80Cm8\xec\xbdys\xdc6\x9a0\xfe\xff|\x8aG|w\x152M\xd1\xdd\xad\xc3:,k\x1d\xc7\x9e\xf5\xbb\xf1Q\x963\xf3\x9b\xb7\xa3UQl\xb4\x9a1\x9b\xec\xe1!Y\x13i?\xfb\xaf\xf0\x00 \x01\x10 \xd9\xb2\xb33\xbb5\xacT\xac\x06A\xdcx\xeec\x0b\x16U\x1a\x95q\x96\xba\xa5\x0f\xc4\x83\xdf\xfe\x00\x00\xe0dW\xbf\x92\xa8t\xe0\xf4\x14\xca\xbb5\xc9\x16@\xbe\xac\xb3\xbc,`{\xdb\xf4v\x95\xcd\xab\x84\xc0\x19\xff#\x10\xb5O\x81\xb8\x1e\x1c\x83#\xba\x91?\x9a\x93E\x9c\x12\xda\"\xfb+\x08Ws8\xe3?\xdc\xd9\x05\x0e\xe8\xb8k0g\xe2\xaf\xe0\xfc6\xbc\xbe&\xf9\xcfo\xce\xcb0\x9d\x87I\x96\x92\x0f9)HY\x0f\xa1\xec\xab\xf3\x87\x07\xb7\\\xc6\x85\xdf,\x89X\x8e\x9c\x94U\x9eJK%^\xd0\xe7&\xcc\x81\xc0)\xfc\xf6p\xf2\x87\xbaPT\x85\xd4\xcd\xe5\xca\xf4\x89\x17\xe0\x92Y~\xe1\x89v\xe9\x0f\xb1b'JU\xdavLG7\xcb/h\x17\xcaKl\xeb\x18r\xbfU\x9a\x1c\xc3\xd6\xa4]\xcc\xbb8\x86\xdf\x1e\x94w\x0fj\xa7|T%\x1dU\x14&\x89\x1b\x8b\xc1\xf9\x10\xfb \xfdJ=\xfa3\x81S\xd8\x1aK/\xea\xd6\x9anx\x9bi\xb0\x82S(}H\x83\x88N\x8b\xfe1\x87S\xf5\x10\xfa\xd0Z\xb24\xc8\xf8\xf9\xbc\xbf\x87\xf7x\x1c\x02vL>\xe4\xd9\x9a\xe4\xe5\x1d\xff\xb2\xbdBQ\x96.\xe2\xeb*\x0f\xaf\x12bY\x96\xb4Z\x11\xf1~\xdc~\x7fM\xcac\xc8\xd5\x15\xf3\x9a9\xd29\xa4\xca\x1c\xf4\xd1\x8b\x13R\xd2\xa3^\x06\x97\x97\xa4x+\xeeK\xeb\xac\xc9\x8f\xd8 :\xd7\xb0JJu\x0cp<\xec\xeb\x01{\x9d\x06s\x97\xf8\xe0\x84\x0e]d\x1f\x88:\xbdL\xdf\"\xbd;\xde\x0c\xdf\x99u\x9e\x95\x19\xbd\xa9\xc12,\xde\xdf\xa6b\x8f\xd8i\xc2\xef\xd5\xf6\xd7p\n\xce\x93y\\\x94\x8e\x0f\xa9\x9b\x06\x14pL\xc7\x07\xac\xda\x83;\xd3\xceG*\xf7\xefT\x05\x81\xa2\xcc\xe3\xa8tN\x94[\x99\xc3)\xa4\xee\xfe\xd4S\xf7\x94^\xa8\x99\xf39N\xe7\x8e\x0fNN\x8a,\xb9!\xf4\xcf(K\x8b2\xaf\":\n'N\x8b2L#\xf2~A\x7f\xads2\x8f\xa3\xb0$\xec\x935\x05\x1b)\xd6\xe3[s^\xde%\xf8\xb2\xa0\x7f\xbcH\xe2\xb0 \x85s\xa1\xf6\x9ca\xcfE\x14&a\x8eu\xc9_+\x92F\xf8\xdd*\\\xaf\xe3\xf4\xda\xb9h\xe6PJ`\xb4s\xf9\xe9dS\x1f\xaa\x936\x9c\xa1\xb7\x8c^\x9a\xdf\x1e|\xb1=\x9f\xc9]\xe1\x12/Xd\xf9\xab0Z\xbau\xd3\xadvE+;\x138==\x858\x88\xd39\xf9\xf2~\xe1\x12\xcf\x83r\x99g\xb7\x90\x92[\xc8\xdd\xef~N?\xa7\xd9m\n\xd9\x1a\xa1\x9e\xf3\x1d\x8c\x80\xc0\x08\xbes .`EJ\x88S\x06\xd8c\xac\x90-X\x9d\x92\xd5\xf9\xcb\x8b\xb7?!l\x0f\xbe\xf3\xb4\x8b\xe6\x03\x05\xcaA\x19^3\xc8\x81\xbf\xe8\xe6\xd1\x99\xb1?\xee\xef!\xad\x92\x84\xbf\xe3\x1b\x8a\xaf\xc5\xdf\xf7\xf7\x83\xae\xca\xd6X\xed\x9c\xb7X\x9f\x0bl\xb3\xf9%\xb7\xda\xba\xf4`\xbd\x81\xbc\xd5\xe6\x80a\xb3\xd2Ou>\xf5\xd1\xc3j\xcd/}\xd6\xfcL\xf2y\x8b_j-\xf9\xb0bE\xa5@\xad+\x1fd8\x057\xc5\x0f\x94\xd2\xfa\x83\n\xf1\x9f\x8f\xbf`\xeb\xf4\x14R\n\xea\xe4\xf3\x96\x1a\xce\x9bq\xcd\xd2Yy1\xf0h\xd2\xa7\x9a\x9d\x97y\x9c^\xbb\xc4\xa3\x18\xb2lUzh\x1f\xa8\xca\xf3\x81\x1f\xe9\xac>\xd2\xf5\xb9\xb2\x1dm\xd0F%\x1e:\xba\xc8\x87\x85\x0f\x89\x0fk\x1f\x96\x8c\x06\x81\"x\xdd\xa6r\xe83\xaf+\xfc\xd1\\\xe1\xa6\xaepn\xaepWW\xf8`\xaep]W\xf8\xc1\\\x81\x12\x88\x94\x0b\xc8\xe1\x18n\xe8\xbf3\"N\x17A\x1a\xf8\x81\x12\xf3\xae(\xfe\xed\xc1k\xe8\x0ds\x8b\x97\xbc\xc5\x98\x9eB\xd1Z\\\xb7f\xfe\xe8\nN\xe1\xb2i\x19\xbf\x91\x7f\xe3\xa7'\xadO\xe9\xf5w#Dvx\x98\x10hz\xb8?\x94Lv]\n\xec\xb7\x96\xf4\xdd\x8a\xfe\xef&\x8b\xe70F\x90\xb9\x9aE\x17\x1e\xe5\xa0\xe0\x18Ro\x16]\xf8@\xe9\xa2kZm\x01g\x10\xba R\xc6\xc7p\x87L\x98\xe9\x0e'X\xef5\x7f\x83\xf4\x96\x0f \xfd&\xf1Y\x87\x95\xbb\xf2\xe9\xa1\xa0P\x1e\xb7\xe1g\xcf\x87\xcbYt\x01[\xa7\x90\xe0\xcdu/\xb1\xc6\xda\xf3YOW\xf2[\x17\x7f\x9dB\xa2\x81\xd5f)\xf2 bw9\xf6\xe9I\x83S\x98\xd0?\xfeHI:\xfa\xc79\x9c\xc2\x1e\xfd\xe3\x03\x9c\xc2!\xfd\xe3\x07Z\xe7\x80\xfe\xf5g8\x85]\xac\xf53\x9c\xc2\x01V\xfbH\xdfN\x0f}\xe5\xc6\x17\x9b\xdd\xce]\xe3\xed\xdc\xd3\x8b\xf9\xed\xd4\xef\x1b\xbd\x9dO\x9c'\xd7\xed\xcb\xa9\xf7n`]@b\xe38\xaa\xca\xdc\xd2\xb3\x1c;\xda\xa8\xf3\x8c\x02H\xd2>\\\x1c\xde:N\x83b\xdd\x10F\xa7\xe0\x00\xfd\"\xa5\x18\xe7\x14\x91\x0f\xef(\xf7(%\x90\x84\x11q+\x1f\x9c\xed\xbfVYy\xe2x\x88\x99\xbe\xf3|\x08a\x04\xces\xfamL\xffz\xf6\xc4\xe1d\x9b\xf3\xdc\xb1m\xeffD)\xe7\x8b\xe5\xf2\x94a \xe2\x86\x9e\x0f\xb9\x9b\x07\x1f`\x04y\xf0\x1a\xbe\x87\xd8\xed\xa4\xd2\x04\x1f\xe580+/\\:\x07\xeb\"\x11\\#\x12\x94\xd9O\xd9-\xc9_\x86\x05q\x91{$A\xb1N\xe2\x12\xbf\x0e\x12\x92^\x97Kx\x0e\xbb\xeat=\x1f\x1c\xb6\x86\x94!\xe9C\xdc}\xe8\xc9\xa9R\xc6\xac\xce\xe9\xce\x89\xbbz\x1b\xa7\xf3\xec\x96n\"\xfb+x\x1b\x96Kz\x97\xf1\xdf3\xf1\xfe\xd8\xf2yA\x92\x05\xfd\x98\xfe\xab\x7f\x8a\xef\x8eA\xc0\x01\xd7\x11\x84\xe82.\x1c\xcf\xf5z\xf0\xe05\xc7\x83\xd7\x8f\xc0\x83G\x9d\xa4\xca\xbe\x8e&\xd9\x8d;\xfa\xdfC\xaa\xd8\x89\xb8\x03\x9d\x16\xa0Kb\x90m\xc9\x1b[o0#\xa5\x91d\xe5\x7f\xf27\xed\xe5\xcc\xe9\\b\xfa\xbf\x01\xfb/\xaf^6\xf8p\xbf\xc8\xf3\xf0.\x88\x0b\xfc\xd7\xdcX:\xb8\xb1\xff\xe57E\x9e\xf2\xb0\xb3J9nN\x17\xd0\xbe\x04;\xf2\xe9nM^\xe5y\x96\xbb\xce\xcb0\xfd\xae\x04\x8a\xdd)k\xbd\xcc\xe6\x90\xa5\x00\xec\xac\x9aey\x9bB\xb0\xa6\x15E\xb4e\xb9Vt\xb5\x9a\x1e\x94\xf3\x95\xdfi\x9f\xd0\xf6\xd2\xce\xd3\x89wq\xec\x03\xb9 \x13\xcfuXq\xd3\xfee\xd9\xc7\xbf\xcc\xfb\xf8\x97\x9b>\xfe\xe5\xae\x8f\x7fi\x18\x9c?\xdb\x19\x9c\xe5\xa6\xec\x08\xe5aV}\x8c\xce\x15o\x99\xb2Ns\xc1:\xd9x\xa5.\xdee\xa9\xf1.\x8ckY#3\xa0q-W\xc8\xb5loC\x88\x8c\x05\xbb\xbc\x94\xd5\xa1,\x0b\xf2\n\xc7\x90\"3\xb3b\x8c\xc3Rc^\x9a\xd3\x8f\xb5\xcf\xb0\xb6`rh#Y\xcd\xf7\\\xd7\xdc\xc8\xe9)\xb2:\xdd\x92$\x90H\xc6F\x90d\xa7\xd2\xc5C\xaf'\x05: Dr\xecf\xda?\xa0Oq\x1b#T\n\xf3\xebjE\xd2\xb2\xe0\xb4e\xdfw\xf4\x89\xc2\x82\xc0\xf8\xb8\xb7\x1eH\x02{r\x0be{\x0b\xf5\x07[\x9el\xde\xb2K\x0c\x94\xb5\xfe`\xe3\xd3\xc74\xae\xd0\xd4\xa6\xe7\xa1\xf3m\xab1\xba\xa1\xd6/\xecm\xd5\xea\x95p\xbdN\xee\xb8\xf2\xaf\xde@s\x8b\x0f\xe6u\x11\\\x87\"!\x904!\xb2J\xa5n\xcaE\xce\xfc\xa6\x93\x9b\xcfl\xdc<~\xe6\xba\xab\xe0&\xce\xcb*L\xf0\xe25\xbf\x10\x96x\x9cW\x17\xbc\xfeG\xfa\xcd%\xfd\xdf\x16\xb2\xfc(\x0f`\xdc~\xe2yV\x8e\xfe\x1f\x85\x8b\x9f\xeab3.dk\x953\x1cu\xa8#4\x8a\xa2\x8c\xca\xc3f\xaa$X\xb06\xf7=83W\x96\xd5n\x16\xccE!H\xee\x96\x9e\x8f\xb0'\xa3gtk\x8c\xdc.jL=\x03Y\x04\xcd!\xaa\xeaf\xd5\x0d\x91 \x9f\x87V\x7f\xce5)\x1d\n\xbc\x91\xb8r\n\xf1\xcb@>\xbe\x88\"R\x14Y\xce\x08\x8a\xa2Z\xd3\xfd \xf3-\x0bA\xe1\xdc\x84IEx\xdb\xf4\xd0\x95\x0cY\xa5\x01\xbe\xf0\xfcMI\x0e\xf9\x08l\xa5\xee\xf4\xc8\xb3\xf3\xfd|\x0cO)\x9e0+~\x7f{\xe0\x8a\xcb\xf6\x82\xa2\xe6\xb6S\xa4 w\xd1\xbe\xa0\xea\xfa{A\xd8\xcc\xb3\x9f\xd8o\xe4\x1f\x9a\x1a\xb4\x8f\\\xb4\xebWS\xa3\x06u\xc8\x92K\x82j\xcb%\xda\xdd\xb3\xb0\x85\xa9\xbb7\xf5\x14dk>\xf4\x82\xc5\x0e\x16\xbcF\xecNh5\x99t\xef\xbf:\xb5\xf1\x01;b\x1b\x9f-I\xe67\xb1L\xa8\x9b0\xdf\xa2\x17\xb7}iT\x1a<\x05\xc6k\xd8\xaeL\xdf\xa0\xfb\xf8`uX\xff\x8d\n\x8dne\xba\xb2rCd\x82\x88\x9bc\x1f2\x1f*\x1fB\x1f\n3\xa8\xa4@d\xcbHc!\x03\xd0\xc6\xb9\n\x8fL\xc9T\x88\xe8\x1c\xc9-p\x18\xf76N\x99B\x8e|\x89\x08SJgQT\xe59\x99\x9f\x00\x9dd\xb9$\x90f\xe9\xceJT\x9c\x93\x1b \xe9M\x9cg)\xc5\xffH\x0e\xd3J\x8b*I\x80\xd0VaE\x8a\"\xbc&\x10\xa6s\x08\xe7sTe\x87 ,I\xb2^T \xdc\x86y\x1a\xa7\xd7E\xa0\x9f\n\xfa\x90\xa4 \x1dD*E;3}\xb1.\xcct>}(\x86\x1f\x9bi\x11W]\nR\xcb\x80\x9f\xfck\xf1\xe4\xda`\xdedz\xf8A^\xcc\x92\xd1\xe8\xc2X\xeb\xc1\xf3\xbc \x0dW(\x91}\x93\xde\x84y\x1c\xa6%\xfc)\xce\x92\x10)\x99\xd6WmJ\x8c\xdd\xb2(X\xe4\xe1\x8a\x14\x9f\xb2\x0f\xd9\x9aQ\x1a\xd1\x1f\xcc\x1f\x0e\x82\x01}\x16!OM\x9c\xae\xa4\xac\xeeW\xec\x0b\xb6bvaa\xa3\xd8\xa5\x8eS\xca8\x90`]\x15K7\xed\x10V\xab\xb35_\xacD\x9d\nW\xf2\xca@.\x0b\xe2tI\xf2\x98\x83\xed\xdd}O\xfd\x84\xb1\xe8\x93C\x1d\x03p\x1e}\xf2\xd4\xd8\x16e\xbf*\xe9M=?\xdaK\xec\x86\x0d\x91\xeb\xf9x\x0b\xc7'\x10\xc13\x10\x1c\xd0 D\xa3\x91\xbe\x88\xe2\xc8\x17\xb3H[\xc2\xa4io\xb6`\xcc\xb1Vt\n\xa1R \xa3\xc2f\x94|\xff \xb1\x80\xf9\x16\x8b\x97x\x9e\xccY\xd0\xef\xd4\x91U\x1c\xfb\"\x9b@\x89\xbbP/@\xa9\xec\x16\xb3,(\x83\x9c\x84\xf3\xf0*a@\x98\x1bi\xf0\x92S\xd8\x9a\xb4\xea\xdf\xe6q\xa9\xd6\xafKD}Z\x18&Iv\xfb\xefa\xb2x\xbf&)7\xbdS\x1bRk\xd4\xad\xb5>\xac\x9b\xcc\xd2\x88\xb8\x0eA\x83\xa8u\xf7r\xae[P\xc3\xd0\xf6\xfd=+\xbd\x14\x138/\xc3\x92\x04$\x9d\x13\xb4\xd6\xc9\x83\x94|)?\xc5\xd1gw\xc9\x86\xd0\xdd\xe9\xb2\xbd\x87%m\xcd5\x89\xf2\xccTb\"\xf3b\x8e\x18\xd7\xbf\xc7\xd7\xcb?\x87%\xc9\xdf\x86\xf9\xe7\x16 \xa9\x18\x06j\x86\x83\xfd\xa4\xa5$\xd5\xd4\x17b)w\xab\xde\xfdfB\x9e?h*sR\x94yvG\xe6\xad\xe1\x0f\x1e\xa2$\xcea\xa3\x15\xe7\x14G\xab |\x0c\xf3i\x8e\x98\xfaeP\x8f\x8d\xd60-D]Acu4a\xa12\x113@\xfe\xfd\xa7\xd0X\x9f\xd9&A\xabx\x1d\xdb)m\\p\xc9\xbf\xea\xa3\xfc\xb1C\x86?\xaa$\x11\x17\x16\xcf\xbe/\xdf#\xe2\xcb}\x7f\x13499\xda\xb3\xea\x8a\xec\xbb!\x8e=\xaetN\xd7\xb56\n\xeb\xa3\x8a7\x1c\xdf\xde\xc1\x9e\x01\x8f\xbf\x0d\xcbe\xb0\n\xbfv\xeds7\xde|\x02\xd2\x80\xcc\xe3\xd9\xb73\x88LZ2\x90\xb5\xfb\x87a\x10\xa7\x87\x1b/\xf0\xdf\x85A\x1c64!\xaci+\xc1J8\x93\xee\xa0\xcd\x19\xe3\xdb\x8f\xa8S\xc8\xb5\xb5U\xba\x1d\xf2-\xebg\x9a\x85\xeec\xf7\xdeb\xaeg\x16$\xee\xeb\x06\x96\x8c\x90>:\xf4\\\xa7\xc8#\xdd\xd4\x81\x92\xd3\xb5\xd0\xb6\xcc\x98\x1dI[\xfd\xe5:\x0e\x8c \xf4\xb8=\x8a#j\xca'\x06-\x08\x838-\xd6$*\xcf\xb3*\x8f\xc8\x90C \x08S\xe9f\xf96K \xc1\xa5\x87&\x12=\xb2Y`\xa4\xea\xa9\x8e\x10\x7ffn\xea\x83CYB\x07\xf5@q\xf3\x9b\x1e \x8a\xbc\xe8\xadm\x8c\x97\xa4\xcf\xaa\xe6\x8b\x8a\xd7;\x03\\\xa1\x92i\xb1\x8a\xe0\xd7,N\xdd\xda\xda\xd7\xc3\xf6\x90\xe2\xcd\xe1\xac\x86\x07p\x0c\xa1\xf8\xa9\x94\xc6\xcd\x818\x06wN\x12R\x12|\xefK\xaf\x14K\x8fF\xf2.\xd3[\xf56u0\xd2\xe2.\x1a\xef\x19e;894\xab\x90\xc1\x91\xf8\x08\xb9\xffot\x0d\x7fo\xc0\xb01\xd66_\xbd\x03\x93\xa2\xd9M\xdd\x83\x03\xcf\xc7\xf7\xe3\x86 \xb69\x98\x18\xaf\xe9\xe4@7\xf3\x0b\x8d\xaeT\x9f\xc9\x9d\xd9\xff''\x0b\xf3\x8b\xcb\xcb\x82$\xf6wx]\x8f[ \xcb\xe4%VX\xb7M&[\x83\x9c,\xa4\xcdh7\x13\x0dk\xe63\xb9\xd3\xf6\x14$\x96\xbc\x0d\x1ar!\x962\xc2\x88\xb6\xbc\x92>\xff\xf2/\xec\xf8\x1cC\xd5^\x1c\xfa\xea\x18\xca\xf6\x0b\xdc\x03\x83v\x1b\xb7 m\x97\xaf\xf3l]\x1cChX\xff\xec6%\xf917j\x12\x8f\xd9\xfbI\xb2]\x91\xc4\x1cA\x94\x93\xb0$\xaf\x12\xb2bn\x15}\x94 \x9e\xf1\xda\x17\xa25\xa2\x84\x9e\xc6*I\x0c\xb3\xe0o\xd4\xc1QZ\x83\xdfNY\xdc/\x1e\x14\xc3\xe4\x10\xd3\xc3CP\x03\xef\xae\xb9\xef\xc7\xc2\xf3!\x12\x85 3\x98\x1c\x01\xa1\xfb\xee\xf9 \x8bM\x03v\x84\x05\x1c8\xaeK\xda\xd5\x18\xf2Q+b\x19\x02\xa5\x8c\x810\xe6\xbb\xb7\xbd\x0d[\xa1v5]V\xeeV\xcc\x93\x11\xfd\x1fOZ\xcb\xb7\x84S\xd05\xe8\xb0\x03\xd3\xf6\xca0Y\xc7\xd2\x83*\x88\x96q2\xcfQ\xa4\xa1\xa1%\x94\xb9\xd2\xdaKx\x0e\x13\x13YQ\x0b\xb3\xe6\xc2\xac\xcd]\xd25bb\xac\x1bx\x06\xcb\x13\xb8\x19\x8d<\x98\xcfn.\xe4\xd1\xcdn`\x04S\x83\xfco\xec\xabc\x9a\xab'\xb05\x13\xee\x15\xc8=q\xe8z\xb5\x84\xe4\xc0\x97\x07\x8dO\x94\x9a\x16\xf1#\x9e\x8b;O\xdeD\\xi\x07\xee\xe8\x0et\x0cM\x08\x80\xe9ig\xee\x03c\xfc/\x0eP\x8a\x9e\x96\x14g7\x17\xc7\xaf/\xcc\xeb0*\xb3\xfcn\x90G\xa4v\xc9\x82\xab8\x9d\xbb\xdc\x07\xc9L8\x93@(\xd75/\xc5E\x10%YJ^\xa4\xf3\x8fL\xdc\xfd\x1f\xa4\x97\xb9n\xe6\x18p%\xbd\xcf\xa0,\xfd\x87\xdf\x03\xfa\x07?\xe7e\xc0\xa0\x8a\xcf4\xfb\xebB\x9f?\x1d\xc0f\xf0\xa2\xaa\x0d\x9brTd\x8a\x86\xdb@\x02m\x9b\xe8\x15n\xbfB\xc1\x03\x0e\xbb}j(\x12\xed\x9a\x8b\xb79\xd0\xa9\x14\xa03\x17@\x87\xdd\x9a\xfax\xc80h\xa9\xc3 \xb6\xde\xec\xe0#\x1e\x97\xcft\x0d\xb6\x0c\xef<\x0d\xdaT\x16h\xc3\xca\x15\x15\x11%\xb6T9P\x02g\xb0\xa6\xc5\xa7\x90\xd0\x7f\x8e\xc5/Z\xd7\x00\x9d\xee6\x84Nw\x1e\xac\x87@\xa7\xbb^\xe8t]C'\xbaz+\x06\x9dV\xf0\x0c\xeeN`E\xa1\xd3\xf5l\xa5B\xa7\x95\x05:)\x03\xba\x1et\xff\xf9\xddX\xfa0\x17@\xe0F\x95\x13\xd3\xc3\x1f\x17\x7f\n\x93xn:\xfe\x9bP\xa4\x8a\xbc\x88\x1d\x10AJ00&\xf7\xaa\x10\xc0\x7f\x80~\xe2T\xd2\x0e\x1f\x98Y\xc0\xdd\x83~\xa9@\x87\xb3\x03c%\xcc\xa0+wS\x8f\"P8\xe6\x87\xb0\x99\x8aq\xec\xfa\xc09%\xa6\xab\x8a\x8d\x04ef\x10\xd3\x0b\xc3R\xae!-H\xf9)^\x91\xac*a\x192\xb1\xc5\x15!\xdcK\x97\xcc\x9dn\x91|\xd5\xdfA\x94\x900\xff\x8a.B\xb3\xfc%\xc5s\xd0\x8c\xbe\xd6\xda4Et\xf9\xc6\x06\xc8\xc6\xbf\xcd(\xd3\xb5\x95\"\x880\xb4C\xf7\xb1)\xf6{\xda\xed\x94r\xa4\xec\x0b\xf5\x9a 9\x87\xd1\xa7\xd5\xdc\x1c\xb4l@8\x92l\xb5\x0e\xbd=\xb4\xdb\xe2\n,s[\x16\x10\xf1\xb0eg\x7f\xcdsHm\xb2\x04\xe9 \x9e\xc9?Z\xc4{\xa7\x80(\xad=\x18\xea\xfa\x03\x06\x95\xdb\x06\xa5\x1c\xde3\xf5\xe7\xb1\x04\x85\xa0w`\xb4\x8b\xca\xb6\x8a\xae\xa6\xa2-\x98\nu\xa6i\xfe\xd1\xfeV\xd3@Q\x0c\xb931]\xfe\xb6\x8e\x8e\xf9? J\xe4M\xd5\xeaY:9z\xe0\x83(K\xa3\xb0t#\xb4/\xc4\xb6}\x88D\xa5\xedmX\xba^\x9f\x96\xcet]\xb7\x166j\x96\"\x89\xd0]\x1b\xd4\xe28F\x83uC\x8d\x0f)\x01\x18\xd5\xfaerb;\xe7\xf8\x01\x85\x92\x91X\xd7\x13\x18\x8d\x12x\x86\xdf\xe0\x82\x14\xb3\xe4\"\xc8\xab\xd4\xb5X\xbc\x8a\xa5\x90\xbb\xec\xb9%\xc0%|\xec\x8e\x9a\xf6N\x865\xbc\x92\x0b[Jk\xbd\x1d\xdeP\x85 \x90\xf1d\xc6F\xe9\xa9\x95_\xf8\xc3\xbb\xb1\x830\xf1\xe4n\xd9\x864\xe2\xe9\x87^\xe2\xe9\xef\x08d\xb5\x83\x0c7\xed\xdd\xc3FC\x80V\x07\xc2\x1a\xa0\xbb\x03\xfb\xec\x8do\x1e\xf4\x05{\xe8\xbc\x89s\xbb*qQ\xa5\x92&3\xa44%%x;\x9b\xbbq\x15\x8b\xd3\xb8\xd6:\x0e\xe2\xf1(E\xc0hW\x03\xed<1`\xe9V5J\x1d\xdba\x01\x9d\xcf\xe4\x04Rx\xd6\"\xceO \xa5\xc41\x99\xa5\xb4+\x95@N5\xe28\xe2ZVr+\x96\xcf\xf3a\x82th\x0d\x05\xef\xef\x01\xa3s\x84\xeeR\xa1~\xe7\x92D2\xaf:=\xa6\xc4&p\x9bs)\xde\x06\xee\x85\xd2l\x1c\x94q\x89\xd6\x1f\xceU\x9e\xdd\x16$wh!\xff\xbb\x89\xba\x94\xde\xf0\xf0\x1bq\x10\xe6\xd77\x0c\x7f@\x1cp\xbbAd\xbe\xa4\xdfE]\x1b\xdf\xdd\xe0w\xf3\xf9OqQ\x92\x14\xdb\xbda/Q\xd9\xc0\xfe^,\xc4\x9f9Ye7D\xaf\xccJ_$\x89xQ\x887d\x15\x97\xe2\xefuN\xd6$m\xf5\xc4\x8b\xdf\xa7Q\xab\xddDj\xae\x97\xa1\x98]\xa8\xabw\x15\xa7\xf38\xbd\xeeVR\xe9T\xeb:\xcf\"R\x14\xf5\xc7\xb1f%\xedh[\x14\xdd\xce\x07x\xc89O\x1c\xed\xb3\xe5\x0f\x18\xd9&\\\x88\x91R\xe22y&\xc8\x81\xb3\xe1\xbd\xf9\xd3\xab\xcb7\xef^\xbfy\xf7\xe6\xd3_\xb0\xc6\x04\x9e\xd8V\x9a|)I\xda\x8a\x8bh[\x02\xa6\x9dk\xd3Q6\xf9-.\x0d[:7S-\x9f]\xe2y\x0d\xed\x04\xcf o\xd6\xae\x9c\xc5\x94\xc5\x9e\xa5\x17LD\x1a_|\xfb+$J%9\x9d\xd9]\xa5\x15\xd4\x8fYj\x8c=\xd35\xac:5v\x063n1\x95 N\xa3\xa4\x9a\x93\xa1\xa1\xcb(\xa7_\xf7\xa5\xbc~\xe0\xc6\x0fC[2D@3\x8c_<\x84\x85\xc7C\xe5.\xfdk{[\x84\xc6ce\xf8\xe7\xf66\xe4\xc2\x12\xbd\xd5\n\x1d_\xca\xde\xea\x9c\x06\xbeY\xc4IIr\xb7\xf3-IN(\x11\x17\xa2\x17\n\xfb\x06\xc11z\x0d, \xd4\xe3\xa740d\x0b\x08\xa1\x88\x96d\x15\x06\xf0F\xbcb\xf1\x0d)>\xc8\x16PT\xd1\x12[(Z\xc4a\xe0\x18\x8e\xe3\x12C\x1b\xae\xd6qB\xe6o\x9a\x95\xab8\x0b\xeb\x88\x018>\xcc.\xf4\x0f^}i\x7f \xd6\xd3\xf8\x01E\xcco\xc3u\x17E\nB0\xc4n\x90\xd1\xae\x80>l\xb1\x8e\x8dZv|\xcf\xc3j\xdak\xf0`\x9b\xf6\n\x8b0I\xae\xc2\xe8s+V.}d\x89{\xfdA\x07\xce\x17O:cW\xf1b\x86\xd7\x94\xf9P\x8a\x9e\x9a2C\x0c\xc3vw\x14\x90\x97\x0c\x90\x13\x83Z\xea\x04J\x86\xf9J\x0e\xbd\x1b\xc6W\n\xaf\xa8k\xff@\x12\x0d\xab\xe7\xc55\x9e\x16\xcb\x99\x90/\xb7\xf8+\x0c~|\xf5\xfa\xc5\xcf?}\xaa\xe5b\xa1`\x19:N\x848\x0d\xea07\xf1\xb5\xef\xf2\x80G\x01\xa4\x18\x97\xb6\x8e\xb3\xb1AyF\x9f\xab\x9c\x84\x9f\xdb\xaf\xba\x9c\xe1K\xada\xbd\xab\xc9f]q}\xa8\xa5/\x19\xc8\xfc9\xcf\xd2k`\x9e\x81\x08AD\x97x~\xce\x194\xe1\xbbP\xb3v]F\x01\xcc^\x81\x02vN\x0c\xd6N\xceM \xf3\xe5\x0b\xc8\x0d\xc9\xefz\x80\xa7\xc0\xb3\xb2\x1bN\xa8\x01*\x0dn\x9e\xd7\x916\x05XDn\x88\x83\xc6\x02\xdc,\xa7\x802N\xaf\x13\xc2g\xc8Mq=\xca\xa0\x95a\x9c\n\x98\xab\xbcm\xf9\xec!wA\x1e=\x8dl\xd3i\xd4\x81B\xb59P\xb8i\x9b\x81\xf4\xae5~q\x8f\xc9-\x84\xae\x01o1\xf4id\x89\x05\x1c?\xd6\x1d\xd3\x14\x11\x83\xcc\xa4\xb1M\x1bj\xab\xf8\xdb \xcaP2Ho\x05\xc6\xe4\x81Om\x16\xe9\x83}\xf9j\xcdl\xe9C\xac\x83\xad^},s\xee\x16\x06\xa1\x9b\xb2\xaf\x9a\x0e\xce\x0b\x8a$\x8e\x88{\xe8\xc3\xce\xa4o(\xdd\x0e\xf5{\xbb\xff+\x1d\xea\x87-\xeb?\x80\xd5\xf9\xb7:\xf7\xfb&?U\xe6\xdf\x12\xa7\x8f\xa3\xec\xb3\x9eC:@/+\xb7=\\7+\xf5\xf1\xa3&F\x1d4z\xfaQ\xcf\xd8\x91\x86\xda\xb8a\xfcJj\x19\xc3\xc1\xc8\xb21\xac`\xeaO8\xdc\x0e\xeeR\x81\x9e]G\xe6C\x1e\xaf\xe22\xbe\x19\xbcL*\xa1i\x04\x1d\xf8\xc2p\xbdX\xfc\xc5\xf6\x05a\xe5\xed#\xaeS\xb2FPW-\x16x\xe9\xcb\xfaG]\xed\xc1\xab\xddaR\xf7\xe0\xd0\x0b\xd8{\xb3@es\x0b\x06\x03\xe9\x8e\x1b(9-s=\x80\x08\x06\xf6\x97\x17o\x7fz%\xc2\xae9u\x82\xaa\xb0\xc8d\xdb\xc3U\x98\x7f\xe6\xa6?\xf8\x93\xc7V;mb%\xd1\xfat\xcd\xdc\x8a\xa7`be\x1ef\xb0p\x9bF\xcex\x02\x8c\xba\xa4\xc6b,\xf7\xa4\xe3\xf9\xf5\x90\xd7e\x95\x93\xf32\x8c>\x7f\xcaCth\xb4\xbc\x11\x86\x9cK9\x01X\x86q\x88\xb1\xac\xa05\xd1EYXhy\xbc\x8c\x0eY\xb2\xf6\xaa\xff\xca;,\x9c\xd8 \xe4HZ\xb9\xd5\xf2&W_\x8a\xb9\x0e\xa3U\xea}\x1a\x81s\x0c\x8e\x91f!h%\xd1\xb7 >l1\x07\x9dz\x1f(\x85C\x9a|$\xa6\xed\xd0s\x0b\xca\x94\xd6\xa0\x84\n\xbd\xf6\x026\xf7\x1d\x96\xcdK]\x95Z\x08>K\xdd\xe9x\xeaiV\xf7B\x01\x8a\xef\xf7w'\xe8\x88\xbe\xbf\xdb\xaa\xd7\xc8\xcb\xb1\xde.\xaf\xb7\xc7\xff\xdd\xe7\xff\x1ex\x92\xc5\xcbc\xc5\x9dv/\xc66(S\xcc\xda\xdc lCip,\xd4\xcc\xd6\xdc\xa9\xa5\x9ed\x00\xe7\xeeY\xeap3;Mm\xa0\xdd\x85!ru\xcd\xc4.\x17\x82\xcf\xb8\xa3Q\n#\xc8\xbd\xe6\x00\xef\x1e<>\xae\xce\xe3\x03\xfapV\xea\x11a\x89$%\x8a\x1e\xc4\x84\x87\xf7oE\x1f\xcax\xb9\xce\xb0n\x10=\x99\x05\x8c\xfdg\xf4\xe4\xea\x9bDO6\xdd\x8f\xbfOPa\xd3H\xf0ZF$N,7v\x91dY\xde7:\xcb\xd0\xe2\xe2]\xf8\x0e\x15\xce#\x14#\x8c\xe1\x18\\\xa1\xc1\xc81OZ\xbfD\xc1.\xaa\xe9\x0f\x10\xdcw@\xd5\x10\xb4|\xd4\x9a @X+\x18\xad\xb7\xba\xcc\x13xs\xf5h\xac\xe6_R\xe5\xb2!\x05\xdb\xf27\xfa\x18D\xd7]\xa6\x0b\xad1\xf4\xe4Nh\x0f\xc3\x1a\x9b\xdf6\x92\xdd\xe1#Ah\xb0\xe1`\x14E\xaf\xfc\x0c\x90N\xd6\x9dw0\x0e\"\x9b\x00\xb1\xa6\x12\xd8\x04\x1f\x0e\xbb.qoB\x99\xded2\x8f\x0dTf\x8f\xaefQ\xdaO\xc6\xbd\xb7\xce\x02\x0d\x1e\x15\xd6\xae\x8f^l\x85\xfc\xe2\xf2Z}\xf0\x0c+\xb62\x06VbNm\x19m\xea>\x16\xbe\xdc\xf0\xa8:\xa1k\xa4\xd7\xb0\xed\xca\x87\xc2\xe7\x99\xf0\x0c\x95(\x1e\x8efcC\x00\xe9\x04\xdf\xe8&G\xd9\xb0\xcc{\x1d\x9a/2+.\xba4\x9fZu\x83q\x80\xcf\x8c\x12xv\xbf\x96\xc5(\"\xcf\x98\x07\x00S\x1c\x17|X y\xc0\xe41\xf2\xab\xc2\x87)\x93\xb5\x9eu\xe3BhF\x96\xd4\xf8\x90q\x80\xfa@\xa0/\x16\xa9\xb1\x1d}6}\xc7Xn\x98\x91U\xbf=\x18\x15\xd0\x8f\xbf\x04\xc3.\x9f\xa2\xeb5y\xf01\xedo\x13p\xfd# \xa3\x92\x07L\xff?\x0e\xcf\x84\xec\x9c\xc0M\\\xc4%,\xcbr}\xfc\xe4\xc9\"\x8c\xc8U\x96}\x0e\xae\xe3rY]\x05q\xf6$\xa7\xdf=\x99gQ\xf1\x04?\xde\x99\x93(\x9b\x93>\x81\x9c\x999\xe6\xa3\x91\xc7,\xd5\x9d\xed0\xbf.f\x17X\x8f\xa4\xb4\x89\x9f?\xbey\x99\xad\xd6YJRY\xaf\x96\xc3\x08&\xba\xf2\x8c\xb5\xa1\x06\x7f\x17\xa2\x89,\x1f\x1e9\xbe\x89\x1a_\xf4\x87\x8b?i]\xff\x18\xe4\x10\xee\xba\xaa\x8e\xc1\xf4\xb83\xfa\xba\x0fq;\xacz\xdcs\xea\x06\x9d\x1b\x89\x82\xb2q4\x8f`\xe5\xebb\xf1I\x87\xf7\xcc <\xac^\xb8?\xb4\xff\x12\xeb,\xb7&\xc1\xb78(\x97a\xf9\x11[+\x98\xd8E)z\x1d&\x05Z>\xba\x18H[y\xf7)\xaf\xf8\xab\xb1\xfe\x8a+\x17r\x11\xcfW\xfdn\x19w\x9a\x8f\x88\xb9)\xf9\xf6\xb46^\xf0\x03>\x04\xa5\x9a\xfdO\xe0\x94\x1f\x94\x8d6P\x94v(\xa5\x9e|\xbf\xa5n\xd7\xf7\xf0iI\xe0\x8a 7W\xd9\xbcJ\x08,\xf2l\x05i6'\xc1\xaf\x85__D\xee\xf4\x1ah\xdf\xeb\xcd\xfd[X\x95\xcb,\x07\x80\xd7$\xcf\x8a\x02^\\e\xd5\xe7e8\x8f\x7f%Kx\xb6\xc0\xc2\x7fc\xff\x04Y~\xfd\x1c\x9e \x88\xd4\x94\xb5\x1a\x15\xf6H\x8aA\x12{\xf9\xa4uu\xb9\x1c\xaa\xc5?CC\\\xb4\xb2\xe4A\x93X\x0f\xef\x94\xf2\xb2\xbe\x10\xed\x98+\xd0le\x11|\xfa\xcb\x87W?^\xbe\xf8\xf8\xf1\xc5_.\xcf\x7f\xfe\xf0\xe1\xfd\xc7Op\x06\xd3\xc9\xde\xd3\xbd\xc3\xdd\x83\xbd\xa7p\x0c\x93\xf1\xd3\xdd\xa7{\x93\xc3\xa9\x96\xef\xd6\xd2ah\xc5\x95\x94\xe2\xa4\xc3yF_7\x86\x17\x1f\xc3\xf4Z\xf0\xc9\x14(%\xf1\x1cI\xd190Os\x865:\xcc+l\xb3p\x85\xbd\xd3\xcfqZ\x1e\nCc/\xb8\xbcDl\x7fy\x89!,\x1a\xf9\xea\xb1b*\x82l7o\x00}\x9c\xe8a\xe7\x18\x8c\xe5\xb8\xd3\xa1\x85y=\n\x1b\xc5\x06\xc2\x88\xcb5O\x80\x07\xc4\x97\x95 \x85\x9an\xa0i\xba\xbd6H\xde\x1b\x14\x0d6\x12\x0b\xeb\xb7\x15\x10\xcaN\x89MZ0\x1c\xc9=\x9d\x8b\xda,\xb9\\\x12\xe6\x86\xb2\x88\xf3\xa2\xac\x11?\xac\xaa\x02\xedgB(Z\xd1j\xe5G\x10A\xf6x\x08\x0f\xb63\x105\x01i\x0cr\x1c\xcb\xd6Db\xfd,\x0c\xaae\x0d\x89\xd9l\xe8;!\xb5Q\xe7\xcdm\x87BnR\xdf\x91~\xda\x9c\x89\x16\xcf-W\xe5lo\x03\x91\xcf\x83\xfc\xae\x1dK\xbb\x83\xedFW\xbf\xe0\xea\xae$?\xe1\x89\xf6\xd1\x0co\x0c\x98\xeb\xba)\x86g\x8d4K\xbf\xaa\xdfe\x8bEA\xca\xef\xe8\x11\xc8*4G\xbf\xca\xaat^\xd8vW\xef\x936\x0e#p1\xf7\xf0\xd8\xb3\xf6\xc3\xee\xdc\xf0~0\x00A#cI\xa5\x00n\xa7<\xf0o\x0b(\xd4F.\xd6*x\x81\x8fM\xc5t\x99\xcd#\xe9\x04L\xa4\x0b\x10\xd1\nk\x06H;\xaf\x8a\xc1\xd0O\xd9\xfdc\x93R\xb1\xc5\xd8tx \x1a>\xc7\x05\xad\xf3\xc9\xdf\xdf3\xe7P\xa7*\x17\x87][\xbfU\x04q\xf1\x8a\xc3\x0d7\xb58`\x7f\xe7\x08\xd0\xe2H`\x83!\x056\x94\x1a\xf6\x98n\x12H\xf8t\x0c\xf70g\x1bg\xf6\xd7\x02\x8e\\]\x16T\xa8d\x86\x8e\xb7y\\\x12\xd7\x02U\xd9'u\x96\x02\x97\xf9\x042#\xfc\xb1\x0f\xb1\xf7\xe8\xed\xf2\xfaL\x1f\xc5C\xd7\xb2\xa8\x15\xba\x141uH\xb3j\xd5\x08\xdc\xc3\xd2%\xc2\xe7\xc9\x166c\x08\x906\x9a]Iu\x82\xb8\xf8SLX\xda\xfdv\xb1\xc9\"L\xaa%\x8f\xb4!0\xdb\xa3\xad\xa9\x99-\xd5R\x0e\x11\x1dK\x1caX\xe2\x9b:\xd9f\xd7*pj\xb3\x1eIW(\xc2\x1c\xc3\xfb\x9d\x9cx\xb5\xa2\xcf\x8a Q\xbd\xe5\x84E\x14\xc7\x8eY\xc9\xc5j$a\x19\xa7\x93\xce*Wq\x1a\xe6w\x96* )w\xcd\xe8\x845\x82d^W/U\xb9\xd8\xe9\xac\xc1\x08\xed\xdeQ\xfc\xec\x96\x9eu\xc1\xa1\xe9.*\xa6\xdd\xe3\x89\x8a\x9d\x9e\x1a\xe5br\x90\x90\xbe:;\x1d\x95\xa0\x19\xf7\x14\xbe\xef^\xc1%\xf9\xd2\xdfJ\n\xcf\x9f?\x07\x83?\x114\xdb\x19\x16\xe4`\xaf\xbf\xa9\x1f\xfa\x16\xb2\xd37\x1c\xa0v\x0c\x19\xba1\xc0\x990\x96\xac\x86Ph\xf6SvK\xf2\x97aA0\x03\x19F\xa1k}\xaa\xebR\xcd\xe0\xeb\xa6\x8bc\x11w\xab\x9c\x11\x03\xec\xe7F\x14\x14\xfd\xf9\x02 \xe6\x83:\xbd\x93\x98*\x8b\xfe\xb8\x01\x01eM1\xf2\x05\xdb1l\xa3E\xdc\x92R\xee\x10\x85\x81\xdc?\x0eyNx.K\xe4\xce\xf0\x8d\"\xa2\xa3\xd8}\xa7.9D\x90F+Ie\x1ekp\x94\xfa\xdcB\x82\x852\xc6j1G\xce\xa5\x1ccQ\x88\x04D\xa5\xfa\xe5\x08i\xfd\x94\"\xc0\xb2#\x88\x82\x98e\xdc\xb9\x0e\xc0C\xe0\xc8]\xb7OF\x13\xf6h\\\x99\xc2J\x91\x86}\xda\x99\xc01\\k'\xcarB\x8c\xc2'\xde0\x81m\xa4u|\x8b\x9c\xc1\x86t\x1b\xf1\x85d\x10\xcac\xee\xc0\x19\x1e\x86\xae*\x8d\xe5\x0f\xe7Z\x8d\x95\x93\xb0(\xdfX>\xc0\xb9c\x12%\xfb\xec\x8d\xbc\xcbM\x98\xd4\x84\xbd`WD\xa0\x8a\x9c\x93W\xadP\x14\xe6\x1b\xad\xaf\xbf\x05\x98d,5\x8b%\xbc_(\x1d\\s\x8dB\xa2\x82\xcd[,\xa5\x16`\"\x05\x86\xd1\x18\xffM!\x01'\x04s\x0d\x8c\"=\xc4\x91\x1b\x17Za\x01\xc7ej\xd1\x8eTf\x95\x17\xc4,*\x91\xa0\xd8\xa7L\x18\xd8\xfc\xee\xbdWt\xa5\xa6>\x84\xf0\x04\xff-\xf8\xbf)\xfek\xb8o\xad\"M0k\x1b(\x1f\x06\x0b\x17U\x89\x8c]\xc7<{\xee\xcfo\xd2rr\xf0\xc3+\x97\xc0\xf7r\xb6\x11\xf1\x98\xef\xb9\xd5&H85\xda&\x8d4\x1d\xaaaN \x83g\x10\x9e@6\x1a\x99\x992\xe0\x9d\xe1\xf42\x0f\xc7\x1fQ\xf0\xc1C_-8\x1c\xce`\x07\x16\x9dr\x1d\xd1R\xfd\xa1\x88\xd2\x9dy>\xfb\x1cF|\x81\x8az\xdf\x16tA\xacMr \xbb\xc3\xc2\xd7\xb2\x163\xd89\xe5\xa3\xf1\xf9*X\x80\xb3}mR\x18A\x01\xcf!\xac1I\x08;P\xe08\xf9\xaa=Gf.\xdb\xd9\xe9\x9arM<'<\x88\xed\x9a\xf1\x80kx\x06\xc5 \xac\xbb\x16\x1d\x94\x85\x87\x11\xac=\x16\xa4\x97.\xfe\xbaw\xa5\x81\x9b\xc0\x98\xfc\xbb\xf5\x07\xe3\xeft\xd62\xcbq\x80\x0f1\xa9\xb7+3\xd6\xb3j@vt7k3\xe0[\xf5h\x07\xe8\x061o1J!\xdc\xdf\x9b\xf8\x18\xa1\x04\x97\x90\xb6\x81\xe2\xcd\x05-\xc3\x9b\xa3\x90\xe79\xc4x\x0chqLq\x01\xfea\xee!\xeb\x85\x9d\x19\xfc+L)/7\xb68r\x0bu\xe2\x92|\xe9P=\xe5\xf0\x1c2x\x02\xd3zh\xf8\xabK\xfeP\xb1\xb3W\xb1h\x87\xa3Q\xd5\x05>(\x9aX\x87yA\xde\xa4\xa5K\x82\xa2\xba*\xca\xdc\xa5|B\xe5\xc3\xd4\xf3ar\xd0!7g\xd4\x9a$(\xac\xccu\xcb\x19\xbdi\x98\x8a&\x1c\x00\xf4Dc\x83\x0e\xcde\xcf\xa1\xe1\x8d\xfd\xd5\xfd\x19s\nK\xc7\xc2C\x95\\\xdb\xa0\xd3\xd6\xd3\xd5\xd0\x9e\xec\x06\x03u\x9b\xb2\x11\xd2\xecB 8Q\xb3\xf2L\"\xc6\xb3\xed3\xc1Q\x19D<\xe4\xc4\x8b\xd2M{$\xfam\xc0\xf7\xc0dy\x9bL\xfav\xd8\xa4\x95\xb5\x19\xd4\xf0\x97a\x0d\xff\xd5\xfda\xf3A\x9f\x0fm{\x90VC\x0e\xec\xc0\x83\x93\xf2]\x93\xaeZ}\xb0\xb6\xb7a\xcbu \xc5NS\x0f9\x02~ \x19+!\xed_\xc5\xf9M\xcaO\xc3!\xcb\x84\x93R\xb0\xb1\x7f\xe0C\xc6\xb6=\xf6\xea?m\x9a<+H~\xf8\xda\x03\xff\xaa\x8b\x9fUY\x08\xf4\xe9TXL\xf4\xd5\xa7<\xc8\x0fw%\x91<\xa2[\x85\\E\x85\xfd\x0c\x1b\xd7\x8b\xaeq\xa5RL\xa1\x9af\x1c \xb2\xc5\x10\xf3\x18\x83\x1ab\x14\xddv\x81\xcd\x8c\x85\xf8\xf0E~\x93r\x16\x1bLS\xc5\x83N$\xc6L\x89\xe2A#V\xcaJ\xef\x1e\xc1\x19\xec\xc11\xfb5\xdd\x853\xd8\xe5\xbf&G\x138\x83)\x1c\xdbD/\x08\x91a\x04 \xad\x87[|\x83\xe1Z\x8c\xf8\xc5#\x8f\x8f\x81\x05\xf6kz\xe1kS\xc9p\xf4jY%\xcdh\xb2_\xcfh2\x85{p\xc5\x9c\xe4)Vt\x8a\xd3\xf1\xdeS\xfe\xdd3\xd8\xdf\x9f\x1e\x1dP\x92\x88\x92\xb3\xfbOw\xf7v\xbdo:\xff\xbd\xc7\xcf?\xac\x7f\xedn\xb0\x1ajYhY\xa1Cm\x85\xa4%\xab\xd4%\x0b\xe9\x92\x1d\xec\xef\xef\xee\x03\x06\xf4x\x06\x93\xc9do2\x99J\xcbd\x9c\xa2\x99$\xae\x8d\xb1(_\x84\x9f\xd3\xb6w}\xbc\xc9\x18tl!\xf7\xe7.(>\xa0?\x0f|\x11\xb5x\xc1\xc4\xa8c\xd8\x86\xc9x\xba\x0b\xf7l\x1397\xb3\x7f\xb0;\x1d\xc3={\xb5\xcd\x0c\xc2\xf9w\x1e\x05T\xa3SH\xda\x10\xdf\x06\xa5\xfb)\x12A\x8c\xd8\x15 \x14\xe3\x14\xbc\xbc\xafI>C8,\xee1\xc2\x13\x85\x1b\xf5\x16 \xe9.\x1c\xc7\x0e\x18s\xb32\x10\x04\xf4\x16\x06\xd3\xdcXz\xc0`8\xba\xc9}\xa6\x9a{\xdfCD\xa5\xedEv[\xe8S\xfeE\x82\xda\xb7\xbd\xf0\x81\x04\xe7Iv[\x97t\xef\xc3\xa8l\"\xab`,\xdc.\xbbBT\xdd\xb9#S\xa0\x837\xef\xce?\xbcz\xf9\xe9\xf2\xed\x8b\xff\xef\xf2\x87\xbf|zuN\xcf\xd3\xd8&\x8b;U\x93)\x9b\xcd\x82\xcc\xe5=\xb1\x13\xed\xf9\x8cn\xa4\x88o\x92\xc9\x92\x9e=G<\xb5\x02M\xb6J\xb2\xe3\xb4\xba\x96Y\x00\xd8\x81\xa8\xb3l@8H\xf1\xf0Q\xed\xb5\xe5G\xe21\xc3\x8e\x07\x1f\xf6\xa6\x9cVZd\x99\xebY\xc5\xa1%e\xc8\x98\xa5\xe9\xf6\xb6p\xeb\xad\xcb\xdc\x89\x0f\x13OR*\xb6\x8fjg\x0c4h\xe6\xb0e\x90\x9d\xa8\xe7\xca\xf5\xe8\xc9\xfa\xfc6\xfc\xc2-\xe4P\xc5L\xcf\xd4:\xcb\x92\xf3\xf8o\x14x\x1cN\x8e\xa6\xb4\xe82\xac\xae{M\xb6\xc1\xb6\xb1\x85\xe2\x0c\xa3\x1fo&\xd8\x1e\xe0u$\xb5\x1f5\xe9\x05\x0d\x16\x98\x1dBjW\x1a\x8b2F\xe3\xb9\xa237\xd6\xf1-\xf6\x93<\x9c\xcc\xf66\xff+@{U\xc2\xf3\xb8\xa9e\x17LbF_\x99\xc3\x9c\x16\xbe\xd6\x8a)\xe0)wh7S\xa3\x9d _\x1e\x98\x1a\x01\xc1\xcef\xab\xbf\x81\xed\xa7\xf8\x02Y>D4ca\xd6$\x1bB2\xf3\xbe3\x93\x05`\xde\xd4\x0f\x161\x0b\xea\x86\xc6\x86j\xa1Tb\x00\xf0}\xa7\x05\x17\xe1\xe7\xb4\x08\x17\x83\xe3\xafX2\xb5\xe9\xcdQl\xf1-\x9a\x94\"\xac\x0cjk\xcbmb\xa1\xdd\xdf\xc3V\x19\\\x8a&\x0c\xadG\xd9j\x1d\xe6\xa4\xcf!\x1bd\xf3\xca\xdar\x03\xdb\xd7\xf4QF \xd9\x8b:\xba\xb7P\xac\xb0/\x8c\xb6&\xcc\xf0Eu\\\xee2s\x90\x15{\x8c\x0d'\xf5\xaf\x98\xc5\xa1\xcfdN\x92\x99\xd2\"k\x98Q\x86\xde\xe2t\x8b\xc3\x98\xc5\x17xD\xc9,\xbe\xe8B\"\xa9\xe0\x1cY\xff\xad\x0c$\xf2c\x97\xddZ\x89>\xccw\"\x94zh\x8e\x04g0Q\xe2\xe1Bs^\x84\xf9k\xef\x89\x11l%W\xfe\x94-\xe5\x8fy\xc2}\x06\x06\xdf\xca\x84\xe3\xbf\xc1\x1ee\x80\x8d\xc3?\xa8\x01\x88) )\x0c1\xb3\x18L'\xf8u\xe6\xd5\xc1\xd0!\xb3\xa6\xbc\xfa\xceI\xe2\xa24\x99N\xf2\xe0{\x90-\x04P\xb0YQZ\x0c\x1f\x04\x01m\xa2\xb1\x11>\x98[S\x02$\x18W\x0b!\x0ca\x10\xa4C\xaa\x8b!\x89f\xe9\x85\x95\xdd\x12r)\x05=P\xbch\x86;f>IO\x1d\xa5\x8d\xc2N\x9cW\xdc\x18\xc5\xce\x06\xca \xbc\xfa\x9d\xf6\x8f>\x153\xe6FM8g|E\xf4\xd6\x9e\xb3\x08\xcd\xb9mEg+dg\x8fS\x98\xfb\xa0Pz\x12\xfa\xdc\x1a\xab\xef\x8a\xdbp=9\xe8\xf3\x0c\x17\x0c\x0e\xc6\x8c\xea\xd2\x13\x95F=\x91l\xae\xc9GRP\x12\xbb1\x1d^UI\x19\xaf\x13BWpr\xb0s\x15\x97F\xb4\xa8(\x1a\xc6'h\xbe[\x9e\xb0\xe37\xf5\xe0\x86\xbb&\x11Jm\x8dZ\xd9KA\"\xd1e\x17M\x10\x8b\xa8.\xcb\xee\xf4\x9b.\xcb\xdeW.\xcb\xee\xf4Q\xcb\xb2\xd7Z\x96]\xcfo\x8a\xe82\xb1\x7fLZ\xb8\x0dV\xeb`\xef\x9b\xae\xd6\xe1W\xae\xd6\xc1\xde\xa3V\xeb\xb0\xb5ZO\xcd\xabu\xa0\x15O\xd9?\xfbZ\xf1.\xfbg\xef\xf1kk\x8a\x1f\xd7\xb5\xbah\x9e\xdc\xb5\xc2\x8a\xa6\xa3\x8e\xaa\xc5~\xb6\x02\x08\x9c\xc1\x0b>\x9b1\xa5\xcc\x07\x84\x87\x92\xc7\x93wh\xf2\xe9F+\xf8\x07\x8d`\x98\xcd\x99\xb0\xfa\x1a#\xdb\xf4\\\x9eO\xe3Q\xe2\x0ck\x17\xfd\xa6R\xbd\x91\xda\xd4N*D3<\x8a7\xcda\xb69Y\xc1\x10j\x15\x06Q\xac\xe2\xe1\x9d\xbf\xd8\xa4\xf3.:W<\xbc\xdd_7i\xb7\x93:\x86a\x14\xb2xx\xff\x9f7\xe9\xbf\xd7v\x18\x9a\x86_m\xd2p\x075\x0e\x83(r\x18H\x95\xc3&\x9494\xb3y;l6\xbd\xc4:4v\xd1F\xc6\xfag\x1e\xf9Rx+\x1e\x83\xcd\xbd@~J\xe6\x8e8\x02\xc7\x19j6\x0dF\x9a\xec\x81\x8b\xe4\xd9dmA\xa5T\xa0N\xfeZ\x85Iw`\x170J\x1bzd\x0b\x122\x146\x9a\x9d\x88\x87\xe3\x80\xfb{\x0e,kY\x88\xd9/\\\x9bE\x9c\x16k-xr\x17f\xb2)F\x98\xffRK\xca\xdf9p\x81\x9f\x9es\xb3\xe9\x9a\xae\xa8\xddy\x10Fr\x7f\xc9`\x15\x96\xd1\xd2}\x12\xfc6}xr-2l\x80#\"\xe3\xd6\x8d\xf1\x10\x80,\xc8L\x10\x04\xe0x\x9e\x0f\xce3No\xd4\xe1r\x9e;]\xebb\x91'\xf5\x1a\xb5\x7f\xfb\xad\xd6y<\x05\xb3\xea\x9e\xdb\x0c!\xa2v\x84/\xc8\xb1^/\xaf\xed\xb6\xb4\x17\xcc\xd6,naT\"|\xdd\x11\x03\x8bv\xef\xefQ\x80\x83/b\x1d5\x9b)>\xee\x8f\x9e\xd3\"@\xfbh\xdb|sx\xce\xc7C\xe8_\x9dnBM\xfd^\x17\x02\xad1{-\xa4\x03|H\xeb\xbf\xf2\xfa\xaf\xb8\xfe\xab\xb9|\x83\xc4{\x19\xba\x0e\xec\xd0\xd3\x83!\xcd`\x87\x1e\xa7P\x96\xe8e>T\x1e7\xdf\xc0\x00\xc8B/\x18s\x15\xacb\x99\xc24\xbb\xe3\x13H\x98!\xedh\x94\xd8%\x80\xd1,a\x12\xc0\xc5,\xe9\x94\x00f\x18\xbc,\xe1:sZ\xdb\x0e\x83\x1f!\x01\xcc\xe0\x19\x1a!\xa3\x04\xb0\x82g\x90\xd9%\x802\x94\xc2(\xc2C\"\xbbI}q\xe3\\\\J\x91%\xd7.Ao[\xf7o\xd4\xd9\x9d\x1aR\x03\x03\xaavu\"\x99\xfc\x7fmG\x93\xce\x8e\xd0C\xdf\x0c\xc7l@L\x8b\xb9Y\x93\xb8L|$\xddt\x9f\xf3_\xadVj\x0f\x14\x1d@\x99\x83\xa6\xe4,J\xf9F\xad\x9b\x8f0\xc2\xe0\xb8x\x1d\xa7\x18\x97\xc03\x04d\xe1\xae\x92,r\x81p\x8c\x10\x84\x87\x0f,P\xc7\xcc\xe7\x91t.<\x16\xc9\x11\x92,\xbd\xa6\xfc\xaa\x88Fk\x0f\xa8q\xcf\x00\x85\x18D\xea\xc1\x19\x05\xcc\xac\xd8\x08\x899\x07Ay3\xd9\x9f\x89\xd5\x1db\x94_\xdb\x18K\xa8pGO\xea\n]\xacU,98\xc9\xc1{\x9e\xd7NM\"\xe2 \xe3\xef\xf0\xafA`_r\xeeeg1\xab\xca\"\x9e\xd7A\xa9\xec\xf1I\xf2:\xae\x805^\x86\x02^U'Q\xabJo\x08\xff\xc5/\xdbJ\x0b\x94c\xde\xf2^\xd6k\x18\xdb\xc5\xfb\xbc\xdc\xa0\xcf>\x8e\x8b7y\xb5A\x93_\xab\x8a\x80\xa6\xdb\xdb\x0d\xba\xed\xe5\xb1x\x9b_6h\xf3\x1fN\xd9q>h\xf0\xbd\xdc\x14Z\xf3o\xc4I\xd9,u\x01\x98A\x13s>\xd5\xbd\xa6\x98\xc2\xb1\xdf\xf9T\x97v\xfd\xdf\xf3\xf7\xef\xfa8\n\xbe\"\xe6\x1bJ\xdb9\x06\x11\x0c\xc4\xccr\xcc\xc32<\x06\xdd\x93\x0e\xe9\xa3&oFp\x19\xe6\xb9\x88\x0d\xe6\xf7\xc3R-\xf8*\x05,\xef\xe1\x14\xf6\xc6G\x07\xb6\x90q\xbfv\xe1l!A3I\x92\x1ec\x16\xac\x98\x03\xa3\xce\x97\xd9\x8c\x992@\xa2\xc1)js\xed\x0c\xe40\x87\xde\xcf\xff\xa8S\xfc\x16\x93{3drv\x1bDw\xcb&\xf5t\xb78r\x95\xd8\xa7\xbc\xc1\xb2\xa6+\xa9,\x82\xe3\xb0\xfbG\x98\xab\x1c.F\xe61}\xd3k\xb7\x9ce\x1dS\x8f\x07M\xfdm\xd7\xd4\x15St\x8d\xf1\x90\x877f\xc3\xcbk=^\xc659\xb1m\xd7\xf2Yv\x01#\x98\xee\x1f\xc0\xf7\x90\xcf2S\x90X\xd8t.\x9f\xba\xe6\"4\x12\x13\xd4H\xb0\xd8\x18\xf6H6\x0e#\x01E\x04\xef*NK\xbb}\xc7\x08\xc9 k\xdc\xb7O\xf9]\x9c^c`\x13Lj\x00W\xe4.K\xe7\x82\xf6ak6\xd0\x0b\xf7\xa5*\x82@\xa7\xc8\xc7K!\xbes\xd8\x18\x8ca\x80\xb8\xb0D\xc4\x0f\xb1i\xb2 \xba\xa8\xf1\xe3\x9fY\x03\x03\xe9\x91\xfe\xf4\xd8t\xb6\xe615\x88$t\xb0\xc7\xc1\x9c\x93/ \x8b\x17\x06\xae\xe8\x87\x1ef\x88\xd4>\xfd\x84\xdbS\xef\xe3\x86\x9b\xf5\x92\xca\xed\xd5\xadud\xaf\x17\x1f\xa6\xaa\xe1\x0ewG\x8b/\x00\xf5\x10\xdb\x18\x94\xe7\xd938\x84\xef)\xfd{\x061\x1c\xc3\x04v \xf6<\xb4\xd16\xbc\x184\xe1\x8f\x1bMxoz\xb4wt\xf0tz\xf4\x8df\xbdg\x9f5iOk\x17\xa7\xc5\x16c\xd0\xe4\xde\x0d\xbe\x1f_s\xb0lG\xb5\x03\x9e<\xfa|\xfe\xa4\xcc\xc88\x9dZ\xaer\x7f\xcf\x16`\xec\xb3\xa5\xf6!\xe6<\xae\xdc\xc6t\x97\xbd\xa3+\xb07h\x0c?>z\x0c\x87\x961\xecO\xd9;:\x86Cm\x0c\xf2\xafB\xa7\xeb\x86\xd8\xef\x08\xaf\xb8aJ\xeaS\xf8\xaf\xff*}=\x08&\xe1\xb9O\xfe\xeb\xbf\x88\xcf0\x05\x0bC9\xa2X\xbb\xbe!\xa5\x888RR\xc4^\x17\xe5^\x13\x92\x8c\xe5\xea\x92\xbe!\xe2\x1bR\x7fC\xa4o\xca\xba\x04\x93\x1d\x1b\x03\x985:\xcf\xda\xea\x1a\xd7\xc2\x1a s#\xf9IM\x81\xc1\x8e\x9eeE3\x86\x11\xec\xec\x101\xef\x13<\xda\xe3\x9e\xe9\xd2\x0f\xbe~\xc2\x87C\x00\x02o\x90\xd4s\x9c\xf8\x9a\x82\x83o\xdc\x90\x1e'\x07\xedc5\xa8\xd3\xa9\xa5Sn\xe9\x81\x8b2\xb9@\x9c?l\x1c\xed\xcd\xfe\xbaq \xb5\xa1\x0cf\xc88v\xa7\x8f\\\x8f=}\x1c\xae}A\xe4\xa2)\x16\xb18\x7f\x93\x83\xa7O\x9fN'\x94\x8b\xa8\xdf\xef\x0e\x1c\xf6#\x97\xaf5\xec\xd6\x18.D\xe2Li\x06\x93\x83\xf6\x14\x94Y\xed^t\x8a\xf0\xe9\xb0\xff\xd7A4x~\xca?\x9fL\x0f=.\n\xdf\xe1\xb4\xe3:\xbbu)\x95\x00\xdf\x03\x06\xf3\xec\x05\x07\x7f\x0f\xf0G\x94\x85\x91`[~q\x82\xe4e\x1b\nf\x1a\x14\xcc\xbb\x17)3,Rf]\xa4l\xc0\"}#\x90\x89\xbe\xd7\xf5\x89Gu\xde\xf7\x80\x11!v\xa4{0\x11\xa9\\\x07@\xd7\x0d\x80\xab\x15\x9a\xb5\xd7\xf1F\xf8UX\x81\x8bu\xedw\xa7O\x0f\xe8$S8c\x8c\xd0x\xf2\xf4`\x0c\xf7\x90\xc2q?\x05\xb2\x01\x8c~\xf4t\xd8$\xee\x15\x10\xfe\xfbM\xe7\xdb\x81\xfa\xcd \xbd\n'i\xd9to\xd0p\x87\xad\xfe\xf0\xe1b\xcf\xedA\x0f\x00\xee}\xc3}\x9dd\xa1\x01\xba?n\xb816\xd9(\x1a\xb6\xc6\x82\xeb\x1b4\x8co\xb5j\xadaL\x86\x0e\xe3\xc7\xac\xbaJ\xc8#\x97\xe3\xb0w\x1cc\xc1\x80\x0e\x1b\xc7#\xd7\xa3\x7f\x1c\x93!\xe3@\xe6\xd9\xca\xcdX\x848<\x9d\xa7\x82\xe0\x98\x15\x0b\xaam_\xea\x06\x04:2I=\x96t\xcc\xe6\x88\x12\xdbc\xfce\x1dN\x1fx!H\x13r\xba\x14\x94D\xdaB\x93\xac*#\"N\xa1\x84'\x1039\x90\x15\xbc\xd1\xca\x9dP\xac^I#\x99\xf0w\\\xc9\x14\xabXW\xd3`\xa4$\xad\xa6\x10\x9f\xd5+\xba\xb3\x13c\x808N*\x18\x964\x16K\x9a}\xb3%m\x11\x15\xdd\x16,\x86E\xd5\xd7\x92\x02\x8b\xfd}\x1f\xf5(\xd6|?\xb8;M\x06\\\xb7\xf4\x04\xb4\x96O\x197\xf9\x1f4\x11\x13\x05\xf2\xd5s\x99\xfaLr\xdc5\x9b3\xc3\xf5\xf0\x9b=\x9b\xb0=C\x11)\xa5\xa9>(\x1dl1\x1b\xfb\x91\x166\xd2>\xc9\xc1\x94\xf2\xef8I>\x1b}\x92|\xee\x86IN6\x9a\xa4\x89Z\xf9\xeaI\xee\xf9\x92H|\xd0L\x19\xcd\"f;\xdd\x93\xa6;m\xca'\x07\x96\xbd6\x1cg\xba2\x1f\xcd\xdb\xdfI\x16I+\xf3;l\xff\xe6+cY\x95\x89eU\xa6\xe63\xb3\xdb\xbd2\x93\xc1+\xb3!\x8a\x15\xd2cyY\xb6\xac\x06G\x02\xd4\xb7\xd0\x03\x86\x8e6\xcbN[\xb8%f\xa8d\xc7\xe0\xe6m\xb6\x07C\\lF,=Qz\x1f\x89\xc1+\x19\xdd\x08\x917wJb\x7f\nsL\x86\xdb\xe9\x84.\xf0\xcb\x10C\x14\xf9\x1a\xdew)\x96\xaa\xe0\xf9s\x18S<\x1a~\x13|\xb5!\x05\xf0?e\xa3;\xa8\x88\xaf\xdal\xb1\x17\x12\x81\x915\x04\xc6\xc6;>\xfa\xfb\xec\xf8\xefB\xa0L\xa6O}\xd8\x99L\x0f7\xa7Q\x14\x1d\x12]Z\xe6\x930\xf9\x1a\xfa\xe5w$_v\xa7O\x0f\xe8\\Q\x860\x0c\xb4\xff\x8e4\xcc\xefH\xc2\x04_K{0`\xca\xdd{;\x80\xc4QH\xa2\xaf\"h~Gz\xc6\xbeD\xea\xf5U\x8c$\xc4-\x1e\xb0\x8a\xff@\xc4\x8fE\xfe\xd4\xbd\x8a?i{\xd6\xe7U\xd1\xf4\xb4\xe9~i=M\x06\xf5d\x93\"uw\xf5\xe3c&e\x13\x14m\xd4U\xef\xac\xa2l}\xb7\x19\xdd\xd2\xa4\x9b\x1c\xa3Cd\xed\"\xd8\xd8\xd5\x97\x9a\xa7\x97\x94\xa5\xa41E\x90+\xd0\x0fI\xdd\"Wq\xe45 \x88\xce\x0b\xcc\xfb\xb2/\xbdS\xdc\x8a\x84\xd2\x0cP\x1eVO\x13\xa4\xcb\xf0\xa6\x0c\xf3kR\x9e\x97a^\xf6gC\xad\xcdx\x80\x19kj\xc30\xf7PdU\x1e\x91\x0dz\xc8\xbb\xc6\xcbZ{\x95\xce\xfb\xdb\xcaU\xe7\x8bz\xf5\xd5\x1d\x95\xec\xaf\x08\xc6^\xda\x916Jy92Z\xe5\"A\xcb\xf4[\xb99n=\x12\xc8\x8d\x1b*\x06]\xe6\xcaA\xec\xb1#$M\x0c,]\xc2\xe4\x04b\x9e\xd5`g\x07\xcd\xc2b\x18\x01\x03\x92\x14\xd6\xd1_\xa6\xb8/\xb5\x93\x11eA&d\x17X\x18\xaf\xcd\xb2\xfe\xb105\x9aY\xda\x06\xfd\x1b\xf3\xb9\x14\xa4\xac\xf3\xb8\x94\x8a\xa9N\xca\xcc\x9e2\xcf\x9c\x0bS\xe8\xfd\xba\x00\xc1\"\xc6\xf4\xf6\x1b\x00\x02\x83\xd3\xd5\xc6\x99\xadEz\x02\x0c\xa9\xc1\xd1\xa6vC\x8c\xe9s%\xb8\xd0\xfe\xc4\xe7Y7\xfa2#\x81\xec\xe2$\x07,\xb7Y\x1e\xd1\x87n\xe9t\xff\xa0F\xd4\x96\xf8h\xf6|\xabz\xb2\x19C><\x9b?{\x9d\xf1{h2o\xcb\xb2c\xbfj.\xe0\xdc\xe6Ul\xf3\xfch\xf5\xc7s\x97\x98\xf2\x9d\xf3\xc5b\xa9\x92\xacF\xbf\x1cF\xca\xe0\xe7\x19\xc3\x0dj\x91\xd5*\xfa\xfd`O`\x0c\xe7\xd1\xc4\xcf\xa3\xed\x9b\xa1Tf\x1bl\xe3\xcc\xab%\xba>SF{\xcc\x93\xc8\x8d}h\"{P,gL\x0bo\x87'\x06\x8b}\x04\"L\x93a\x01\"viB\x85\xb6|r\xacB\x96Q\xf8g7\x15)\xeds)\x01\xa6\xd7\x91\xbc\x99\xb2\xdc\"N\x95\xf9\x10\xd6\x13\xe0\xb6z\xe8\xa3\xacLB\xc0\xc5j\x96\xc1\xbfB\xb8\x81\xcd^\xd9\x8a\x91\xa3\x8e\x81N\xf6op\nOf\xff9\xfa\xe5\xc9x\xe7\xe8\xc5\xce\xff\x0bw\xfe\xb6sy\xf1\xe4\xda\xe6z\xf3\xba;\x84+\xa0r\xf6\x0c\x9c1:\xfd\xabiB\x8f\xb5\x02ul\x96\x0e\x7f\xb6*\x00o\xcc\x01\xda\x08\xf0\xa88\x13x\xd2\x9b\xe3\xb2q\x90\x89Ex~S^\x87\xee\x14*1\x0bl\xd3J\xec\xe0\xc1s\x8c\xe6\xbd/P\xf4\xfe\xd3\xdd\xbd\xbd.\x80\x1b\xf3\xfcp\xf6\x1aP_\xd2\xe7\xb0\x7f\xb0;9\xea\xabL\x1f\x96\x88b\x97\x8eggB\x07\xc3\x93ILw\x8f|\x98\x1cM|\x98\x1c\x1eu\x80u\xf1DYZ\xc6ie\xce\xa5$\x1e{\xf6 \xe0c\xaf@\xa4~\xb2J\xf5\xe4\xe7\x1fi\xf4\x98\x10\xaa\xb3Jo/\xdd\xd9\x95\xf0\x98\x1c\xecN\xad)\x04\xc53lU\xfc\xdfy\xc8)\xf7\xd18\x80\x11\xa5\xebvx\n\x82g\xcf`\xc2\x0c]v\xf8l\x8c-\x88\xb4\x89\x9c\xef\x190\x1f;&o\xeeo\xca\x12U\xf4\xdd3\xd6\xe1\x84eg\xe9K\x7f\xc0\x07\x93v\xcf\x83\xef\xdft\xbc7\xb0\xf7\xe9f\xbd\xc3\xf3\xe7\x98\xcb\x00\x03lcB\x83\x94\xfe\x9a\x1e\x0e\x1a\x16\xee\xd3\xb0q\xedn>.L\xba0\x9d\xee\xb1\x10\x1ep\x00\xdbt\x848\xba\x0d\xc6\xda\x03\x1aq\x1e(\x14!\x92\xb4&V\xd2\xdar\xf6\x99p\x86\x19X(i+\x93\xab\xfbu\xd6\x7fy\x8cw\xa6\xe3t'\x13>\xb5\x07\xbfS\xb8&h\xa8\xd4}\xea\x05,\xe8|\xd3q\x19\x90/\xeb,/\x8b:\x85\xf1\xe0\xd6\xf6\x0e5\x8a:f\xc5GZ1\xa5\xd3\x9cY\x86a\xf0y\xd0\xfb\x0b\xc7<\x02\xfb\x89\x15'\xa7\xc0\xefU\xc6\x8c\xae6\xfdb{\x1b\x90\x0d8=\x95\xee\xdd\xc3f\x93\xda\xdd\xf5\\\x16\xb1\xdf\x07'\xcaIX*~m_\xb1\\\xbbOw\x8d\xeb\xb5\xfbt\xcf\xb0`\xb4|_+\xafx\xf9\x81V\x1e\xf2\xf2\xa7\x9e\xc4\x0d\xd4\x07\xbbh/\xe6\x0d\x8f\x0e\xbac\xd0}\xa6\x1c?\x03\x0f\x9f)\xa7sV\xcfk\xad\n\x0d\xa2\x84\x84\xb9\x8b\x87\x9cX\xb3q\xddt\xa7\xd4FQ\x10)\xdd|6\xbe\xf0!\x9fMt\xbb\xff?\xb4\xffRd\xc0t\x0ctWT\x89\xd0\x9c$\x04c\xfc\xc4j\xf95\xa1\x102S\x0b\x97!\xdd\xd7J-,\xb0f\xe8+{_l\xb6\xf7O\xf7,gH\xf9\\_5c\xf8\xfb\x13HwvN\xda\xf0\x17\x05\xa8n9K/p\x01\xa5\xbc\xd1\x1aU\xc9K\xa5,\x9f\xe6+\"\x8ff\xf0\x90\x1b5\x92\x88y\xdad\xc9!\xf4/\xf2\xe8\x8b\xf9\xf4\xe81k\xd8,\xdf\xe5\xe5<,\xc3\xcbK\xe3j\xe4.\xf1\xe0\x0c\xd2\x99E\xbeW\x17\x1f\x83\xb3\x0c\x8b\xa5s\x01\xc7\x90\x06\xabp\xfd\xd8\xf9\xec\x8d-\xe0s\xa2_{\x06\x0e\xf0v\x8b\xa2\x8d`f\xc6D#9\xcb\xe8G!\xe5c\xc7<\xb1\x80\xb0\xc9d\xf7\xb1\x83CP#NH\xec6\xd2N\x8aY\xf3\xaf\x18\xeb\xd3\xb1a\xa8\x9a\xa8a\xd8Hmbbz\xbaY\x0c\x01q\xea\xdbb\x1bT\x12a\x14N\xe3\xb1s\xc6\xd8\"\xaa\x04\xe8\xd8\xe8\xbd\x81\x9d\x98\x1e\xb8\x9d1=l\x1b^\x17\xa7*XB\xf3\xa8\x94:lh\xc6\xd6\xf5\xd8\"\xc1\x0d\xc9\x0b\x8a'j\x0dS]TG\x86sn\xc6\x81\xe3u\xd7\x98\xd0\x1a\xb5]\x8b\xb9\xc6!\xads\xa6,{\x1bO\xa4\xe4K\xf9)\x8e>\xab\xb1\x98;bK\x82\xd8#Q_\x96B\x97\xb6\x08\x0f\x94\x8e\xba\n\xa3\xcf\xc6\x18\x0f\xa2%[\x98\xfb\x9b&\xab$\xb4\xc3J\x9b\xbf\x11\xb1\xb7\xc2.b\x1c\xa3&\x8d{\x02\xd5\xf6$\x80\x14\x16@\x81XI\xb7+X,\xb6\xd8\x93\xdf\xb1\xddb\xbd5}\xe2\x0f\xc0k\x86D+\xe7\xfa\xcd\xac\x83x\x1e\xfa\x86\xda\x93\xdb\xf1\x9b\x0e\xb5\x95{U\x7fzG\xdb\x93\x89\xf1[\x8f\xd6\xb7ir\xc4\xd35\xe0\xde\xd8Z \xcb\xc1\xe9}b\x1ci\x88\x16|\x8a\x1c6\x137\xc1\x83lV\x8dF\x17\xf2-\x99U\x1dq3\xe1[\xac\n\x8bX\xcc\xa5\xc4}\x0bb|\xdd\xc7\xe2? U\xdc\x801 N\xcb,\xda\xee\xde\xa6,\xda\x81\x89*\xc8y\x96B\x13y\x9f\xf5\x91\x8eqJ\x81 \x99q\xae3m\x14\x13\x0f\x86\xe6*\x9by\x86\xe0L\xeb\xf7R3\xe2\xaf\x98e{\xa3\x98\x9c\xa7\x1ek\xfe\xe4 \xb8\xf4\x02L\xa1\xa5\xa2\x84\x1c\x8e\xc1\xcd\xdc\x9cN\xcb\x9734V\x9e\x0f\x99\x1b\xb3H\xb0\xd5\xd0\xccr\x88\x1aL\x8a\xaa!\x01\x88\xd3\x8cc\x04\xde\x80gD\xe3\xa6E\xa1#\x1c\x9a~M\x19b/\xee2\xc5H6\x0fO\x1c\xab\xb8\x85\x01\xf8\xc0%5.1ghKYf\xe8\x98\x9fh\x9e\x13\x1a\x7fJ\x7f\x8f\x15?\xe4f\xee\x03\xb2\xae\xfd^so\xb6\xc6\xb4)\x03\xf3\xb7\xfd\xce\x83\xcb\xa5|\xa3\x1b\x93\xbafZO\xbeH\xa9\xbbwp\xe4\xb9\xce\"\xcb_\x85\x91\x08\xa5\xf5\xa8f%\x1e\xe0H\x17?p\x1e\xe0H\xe7\x0d2\xce\x1b\xe8\x10\x8d\x891\xf6\x9e\x1eJ\x8b\xe2n\xc6\xd0\xf9\x94\xfa\xe2 \xbd\x8d+\xdb\xca\xf4\xf1\x0c\xa6\x94~5\xd8)\x94p\xc6r\x15s\xf3\x8d\xd2g\xc9N\xab$\xa1'\xbcPP\xd7\xf4\xc2W\xa4#\xa8N\x0cy\xe2!\x16g\x15#\xd5\xa6\xa8P\x16v.N\xe4\xf0\x80\x91R\x19\xa1e\xa1Zv\x8b\x01\xd9##]\xcc\x93A\x1a\x12\xa2\xaa\x99 \xd3v\x05\x92V+\xc2_g\xed\xd7\xb7y\\\xb2\x97\xa1\xf2\xee\xc1\x87\x02\x19\xc7\xd8-\xe8\xb0\xe8\xcc\xa2\xe6\x90z\xc1\xf5\x90\xa8\xd3t\xc3\xf8V\xf9\xb00\xb3A\x96]\x89\x1a\xd3\x18\xf3\xe6D\xca\xe6\xecJ\x9bC\xc1\x99\x14\xba\xe8\x182\xce\xe1\xf3\xf7\x14\xae\xa5\xea\xfb\x149\x1c\xb9S\x1e\xc1\x87nh\xd4\x8cAz\xa3\x1d\x06q\x10\x8a\xe6 \x84\x86\x83P\xb4\x0e\x02\x8fa\xde\xde\xf4kR\x1a\xb7\xbc\xa0\xe5\x86\x9dV\x8fB\xd8}\x14Z\x89y\"\xbe\xdb\x11\x1d\x0ff\xc3\xf9\x16 I\x92\xe1\x1c\xdaD\xa9\xc1\x8f\xaf^\xbf\xf8\xf9\xa7O\x9c\xb0\xcc]\x0d\x0e\xb3 \xe7\xc70K\xdd\xfd]O\xcb\xdeO\xbe\xac\x938\x8aK\xfe\xfa)\xdd\x16w\x7f\xf7\x90\xff{\xe4I$\xcf \x18hgP\x05\x8d\x0c\xa9;m p./I\xf16\x9bWZ>\xd6AKG\xdb\x93\x05\\\x8a\xf5C\xea\xd6\x1abwz\xc0AI\xea\xee\x1eq\xaa;u\x0f<\xd7\x11&\x1b\x9f\xc2k\x01Z\x9c\x97\xe7\xe7\x1f\xab\x84\xfc\x14\x17\xa5\xff\xf2\xfc\xfc\xbc\xbcK\xc8\x8f$J\xc2<\xa4#\xa1e\x7f\xa2p\x85UHb\x92\x96\x1fIT\xe2\xcf\x1f\xdf\xbf\x95\xfff\x8d\x8b_\x9f\xb2\xcf$e?\xc22\xfc\x94\x87i\xb1 \xf9\x9b\x92\xac\xb0\xf0u\xcc;\xfd\xf7Oo\x7fz\x91$/\xb3$!8y,\xd1~\xbe\xce\xf2\xd5\xab\x84\xd0[\x8c\xbf\xcf }+J\xde\x92y\x1cbco\xe3\x15\xa1\xe8\x96\xa5\xe9}\x17\xae\xc8\xfc]6'o\xc3\xb5O\xff\xc5:\x1f\xc2\x98\xce\xe1\xaf\x15)\xd8\xd0?$\xd5u\x9c\xf2\x7f\xd8\x97\xe7\x7f\xfa#K&\x87\x15\xce\xff\xf4\xc7w\x88\xa5\xc5\xaf\x0fa\xb9<'\xd7\xf5\xcf,NK\xf1CZ\x85\xf3?\xfd\x91\xcd;\xcb\xd9\xa4\xcf\xd1D\x95\xa1sV@\x97\xfb|I\x08\xfb\xfc\x13eg\xf20\xfa\xfc\x92/x]\xc0~eU\x84#r\x82b\x9d\xc4\xa5\xeb\xf8\x02Z\x8cO0 ~X\xcb\x80\x8b\xd1\xc8\x04g\x11\x1e\xce\x8a\x8b\xf6\xbd\xa7\xe0%\x9fE\x867h0I\xe9\xf2E#\xf4V\xa14\xe6<\xdeJf\xd5\x05\x13\xd2%(\xf9\xa0@\"\x9bE\x94\xab\xc8\x02\\\xd7\x9e\x13\xaf3<\x14\x8e\xfe\xf6P[\x1am*\x96\x13\x02D\x0eH=\x1e\x86\xf5\xd0\x87\x9dI\x1f)e\xbb\xec\xdd\x94`m\"\xd7\x10\x80\x12\xf1\xf72L\xbf+\x81\x0e\x06V\xa4\\fs\xc8R0\xe6\xeaii+7\x1b$\x07-\x83Y\xca\xa9\x0d\xeav\xd2Y\xa8\xc7\xef\x13o\xa6\xbe\x1e\xa1\x87\x19\x16ZR\xa4s\xe3+\xb1\xe3B\xc8\x8b\x80Mlc\xd3\x9f\xa1\xe5\x8eF\x91\xbe\xff\xf4\xde1h\x1aeY\xcc\x83\xfa\xba\xd0^\xb7`\x0d\x1dl\xc9\xa9(w2=\xf4\\'^\xe4\xe1\x8a\xe8\x1d\x89'G\xe8b\x13\xab\"\x92$AA\xc1l0\x8f\x8bu\x12\xdeQ\xac\x97f)q|\x9c\xfb\xa1\x17\x84\xeb5I\xe7/\x97q2g\x99\xca\x83\"\xa7\x80\xd2\xf95\xbc \x8b(\x8f\xd7\xe5\xb1\xe33\xabV\x12DYZ\x92\xb4\xfcs\x9c\xce\xb3\xdb`\x9eEH\\zA\xb6&\xa9\x8bn\x03,j\xa7\xf3\x8c}\xfa\\T ^\x9f2\xc5\xf1\xb3_\x9e\xf0W\x98\x81)\x88\x92\x8cE\x8c/\xf08\xbd>\x81|g\xe7\xc4\x03\xae\x9a\x94t\x8d\xb3l\x96_\xd8\xad\x02\nWS\x89\x9a\xaf5O8\xcf\x94\xd7\x94\xa4\xed\xe7\xa7\x8c\xf0\x89\xabf\x04m\xdb\x0c\x93\xa2\x12\xb7\xf4\xfc:\xdce\xe8\x83\xfa\x9aK$)\xc68e\x0eX\xb4j\xe1\xaaY\x95\x08\xd2\xe0\xc7\x10\xbb\xa9/'\xe8\xed\x07\x87\x02}\xa0\xf7hDb-=~\xae8\x96\xf6\x01?\x9b\xa4\xabx\x17\xbe\xe3\x0e\xce\x1eW\x84\xbb%\xfa\xf5\xb0\x10\xa8\xa9\xb71\xcf.\x11t\xbb\x9e\xeb|&w\x85~\xf2\xd9\xa5U,\xcc7\x1av\x8e\xe1\xa3\xee\xc1\xc5?\x98\xec\xe7\xf1\xa34 #g\xce\xe5e\x94\xe5d\xe7\xd7\xe2\xb2X\x869\x99_^:\xa2O\xf3;\x8a\xe8\x1f;\xa1XL(f\x13\xfa\xed\xa1o:6\xc4\xe9DYZ\x94y\x15\x95Y\xee/\xc3\xe2\xfdm\xfa!\xcf\xd6$/\xef\xfc\xb8\xf8 \xce\xef\xfb\x85\xbf\xe6\xc5o\x8aW5\xbf\xe4\x97\xd9OY\x14&\x84a\x03_\xa0\x05\x9fc\x1e\x99j\xdbl\x95'{^\xb00\xcaTtQKf&\xf6\xfbV\xd6\xcc\x98\xa3\xcau+\xc6#\x9er\xdb\xf9\xb2\xb9\xc6\x18\xd0\x98\x99\xd4\xa0\xb8\xa5\x0d\xcdUfs\xcb\x10PA\xc8,\x94\x17\xbd\xfb\xb7!W9\x9d\x1cy\xee\x96\xec\xeeBq\xcb\xbe\xc7s\xde\xfb\xe0\xb0?\x1c\xbf\xe3\xb0\xa1\xfd\xc9%]\x8a:S>\xf7O\xbaD\x83\xaff\xc8\xbe\x1d\xc5I\xe8\x8d\xb7g\xb6\xaf\xe1\xed\x9a\xa1\xaebHvf\x17\x041@\xda\xee`\x9e\xa5*\xffI\x9f\x07\x06\xbc(\xe0\xc6\xe5m\xe66\x92\x8d\xeb\xad\x9d\x19&\xc2\xfb\x99X\xf7v\xc3[\xb071\xcb\x15[\x9cm\xebF\xd4r\xd7\x02\x89\xb7\xbc[]\xa4K\x08\xd5\xf1\xbb^\xefm2\xed:A\xfd[\xd5%d\xaf\xf3\x11\xff\x9c\xce\xc9\"N\xc9\xdc\xa1H\x84\xc9\x8f\xf8\xabwU\x928Fg1\xa4E;\x119\x0e8\xbf3\x94Jc)g\xc4\xe0\x98\x02QX\xa7\xe6\xd5\xf4\\\xe8\xd1\xca(\n\xbc\x12\xb1\xe7q\xac\x9d\xa1\xb0\x08\xb5\x00\x0e\xab\x80\xc3u+v\xca<\xcfFV\x03KBCP\xe3 m\xdd1T=\x80\xc1D\x02\x8c-\xa8?\x0f\xd3y\xb6r7\xdeM!\x92d\x86\x8a\xaeC \xc2(,]}\x17\xe9xK\x1f\x1c\xef\x92\xd2\x8e\xa3Q*\x92\x04q\xf8\xb1{\xf0x\xb4\xbbk\xbe\n\xfb^M\x8f\xb6/A\xee\xc6\x1c\\\xc7\x9c\xf4\xe3\xf2\x93\xc7\xae\x00\xdd_\xad)fA\xf4\x9bn\x8a7x^\x93\xddn\xaa\xe7\xa8\x9fS\xfd\xef\xa0z\xf6\x9fZ\xf0\xf1\xbe.\xf1\xcb\xcc \xaao\x12\xff\xbb\xf1\xf1\xc1\xc4\xb4\x00\xc1b\xc8>Rn\xc2^ $h\xdb\xe6\x92\x10\xa3\xad\xf3l\x15\x17\x843&\xa5+O\xc4\xea\xc5\xa4y\xb4\"\xd3$\xfdN\x0d\xd2\x9e\x1f\xc29|\xe0}Id\xa5=\xf3!\xea.\xd2\xdalX~\x1e\x04:\xceI\x91%7\x84\x03\xd0\xba\xf0W\x96\x858\xd7\xddZ\x1e\xbe\x82\xff\x98\xec\x99\xa5\x05\x93\xf1#O/\xb3?m\xb2JJk\xc5n\xc6\xffq\xd0L~\x04\x0e\xcc3R\xa4\xdf\x95\x98\xf7g]BN\xae\xc9\x97-\x8b\x8e\x94\x83\xd3\xaf\xba\xd0\xf4\x82b\x8e\xe4\xfe\xabiD\xeep\nO\x82'\x9a|\xc7\x88j\x9d'\xc1\x13\x07f\xe5\x85K\xb4\xbd\x128\xb6\xb5p0\x04o\x93Y~\x81J%\x1f\xb6\xac}@\x0f.7-\xef\xa6z\n\xf3\xe5'A\xa3\xfb@ e\x1b.Tn\xeaN\x0f\x0ft/\xdc\xb8~u\xa8\xbfB\xd2\xceD?\xc4\x01W\xc3 \x85\xd1\xf6\x08\xc8\xeb\xf7g=\xc0DPE\\\xe7\xa8\xed\xd8\xf1\xc0\xaf\xad\x84\x8e2\xd02\x90\xe0\x04\xcb*\xad\xbcFPS\x17I\xe2\x94\xb3f\x8e\xc7\x96\xa1\x9a\x0c\x83*+\x90\xe5\xc3\x91\xb6\x8c!\x9b\xf6\x0ckuWi9I\x0f\xd2\x11\x10\x93\xd9p\xd7N!s\xeb\x1d\xf3:\xb7\xccBPW2A\x9d)@\xb1s\x0f\xff\x1e\xfb\xb7\xc1\xd8\x87\\G\x82h5u\x0f6d\xb6L\x82\x9d\xd4\x9d\x1a\xc9\x9bC\xb3\x01\xc7dl\xf6CAi\xc6c\xc1l\xcc\x1d\x94\x98\xc0G\xfc8Eb\xf4\xb7\x0748j*\xfc\xa6[3:\x97l\xf7\xd0\xbd\x1bC`0\x0f\x84\x98\x87\x9f\x0e)\xf3[v\xb0\xb9U\xb0p\xb5\x08\x06\xbd\xd4Q{;\xb8\x00\xf6\x9a\x94\x92\x84\x89\x0d{C\xbf\x91\xdd\x03}K\x84\xcf\x90\x99\x12\xdd=\xd4\xad\xde\xb9\xcf\xd0\xa1\xceQp\x9f\xa1\xc3\xe9?}\x86\xfeA}\x86(\xaf\x94\xbaO=\x1f\x9c\xb7\xe1\xfa[9\xa1\x1d\xea\xde%\xdc\xebdj\xf6:\xd9\xdb\xd5\x0f ;P\xfa\xf1\x0by\xedG\xfb\x81\x18\xe1o\xc9\x11\x93|\xb628\x06'k\xe4\x0dR\xd5\x8a9\xba\xc4n\x89\xe7\xa1\xa4\xe7\x81\x82\x0c\xc6\xb6\x86\xfd\xc0U_3z\xae\x8f\xc6\xe3\xa7\x93\xa3\xa3\xe9\xfe\xde\xd3\xbd\xf1\xd1\xd1\xa4-nx\xf2\x9f\xee\xd9\xf1\xf8~6\xd99\xba\xf8e\xfe\xbd\xf7/O\xfa\xd6\xc0\xa2\x86\xc1\x10>|:FZxk\xcb%\xd2U\x13\xfa\x13\xc2\xb2\x9f\xc8F\xae13v\xe3hg\xeb\x94\xf9\xee\xe7AI\x8a\x12u\xba\x88\xb1\x84\x0b?\xcb\xffy\xcaC\x97\x96\xf0\xac\xd7\xefd\xc8J\xf5\xad\x82\xed$Xb\xeft\x0c\xf7T\nu:\x08m6\x17\xc2\xec\x84\xd5r\x1e\xa2\xb7\xe1\xc9/\xc1\xfd/3\xf7\xecx\xf6\x9f\xb3_..\xbe\xbfwg\xcew\x17\x9e{v\xec\x9em\xfd2\xf1f\xff\xf9\xcb/\x17\xf7\xbf\xfc\x12x\xdf\x9f\xfd2\xf1~\xb9x\xd2\xbe9O\xfe\xf3\x97\xdb\xef\x1fu@\xb8\x7f_\xa3o\xde\xd2\xc2\xdf\x8bm\xe8>A\x8a9k\xaa\x90bu\xc1U\x96%$L\x9b\x12\xc5Ik\x0bY1z\xbe*q\x9c0\xbaX&\xff\x12_\x10\xb6Cq*d\x88\x1b\xa9\xf9j|\xd4\x96\xe42\xf15\xb9!).\x9d\xf2\x13I\x03!\xe1^\x85_~\x8a\x8b\x92\xa4$o**\x855\xb3/\x8d\xac=\x84|C\xd0\xd5\xd9Xlo\xcc\x04\xda\x9a-8\xedi8\x1bD4k[\x00\xda9L}H\x83Wt-_\xad\xe2\xb2D\xdb{,k\x10\\\xb3\xf2\\\x0d\xa1\xbe\xd5\x16\xbd\xa9\xc3\xa9\xe3\xb7\xea\xfb\x89\xf6}A\xf4\x1av\xa8a3\xd1\x06\x91\xc9\x18\xdd\xc3\x99.\xd7$\x9cH%c\xeduV0K\x8cN\xabm\xf3\xb9\xf2\xd50N\x0f\xea\x8c\xc8*\xee\x8e\xc8 )\x11,\x96\xcd1\x8f&(\x1fsW\xbb\x06\xbf=Pr\x81\xd0\x999M\xd4AwK\xae\x16\xe0k\xee4\xdf*gF.\xedr\xe1\x97i\xa2\xd2x|\x0e\xd9\x14\x97b^\x91!9[\xb0\xb0\x1fb\xf1\x0dY7\xe9\xec\x17\\f\xc7\x1d\xf4~N\xa3\xb0\xba^\x96>Ti\xb1&Q\xbc\x88\xc9\xbc\x9e\x1b\x0e-\x00\xf7;\x9e}\xd7\xf1L\x927\xd6\xdf\x82\xd9t|)\x99 \xefB\xa9\xf6\xd0Z\xe3\xac\xc9\"\xcaW`V^\xd8\xc1.\x83\xcb\xa9\xe75\x0e~\x9a\xed\xb9i\xc9\xba\xfc\xf8\xd2&G\xbfE\x9ah \x7f\xd2\xe5\xca'5\xea\xab\xfb\xb4y\x17\x16\x17r\x82\xde\xb8\xaa}\x92\xb7,\"\xdcD4\xdb\xf6\x91\xed\x84\x92=\xa0J\x813)\xb9\xadG\xbf\xcd2\xe8!\xdct\x1d\xe9\x8d\x83\x0c|\xee\x92@\x0c\x89\x92\xfc\xcd/$\x87}\xfd\xfa2\xae@\xbb\xd2\"\xcaaS\xc4\xc2\x06\x11\x91\x9aOn\xe0\x14fZ\x91\x0f\xe4\xc2X\x91\xf8\xa6\xcet\xb0J\xbb\xbb\x0d\xf3\x94\xcc\x81\xa5\x0b8\xa5\xc8\xbb\x85ZP\xdbjD\x9b\xc7\x06D\x84\xddT\"\xf6\xb0\xde\x1d\xb7)x\x0e\x15vi\x19\x0dsa\x88\xb2\xb4\xc8\x12\xc2\x80\xbf\xeb\xb8i6'\x1e\xd0*\x18>s\x9d\x15E|\x95\x10P\xc8\x84\x15Ye\xf9\x1d$$\xfc\x0csR\x92\xa8$\xf3\x00\xfeu\x0eI=\xeap>\xa7e?\x17\x04\x08\xfbJ\xc7\xf6\xae\x07e\x06q\x1a\xe5\x84\x02\x9b$^\xc5e\xe0\xb4\xb6\xb4\x89\x93j\xa4\xbf\xc4\xf8\xcb<\x8c\x90\x08U\n\\\x91\x0e\xc9v\x932\x14i\x98\xaf\x96^\xb3?\xf9\xf67\xbaY\x82\xc2\xa7(Hy!\xd1\x95&dS25\xd2*\xbb!b\x0et\x98\xb1\xc7\xe3\xbb#\xc2\xa3\x9bNT\xf0#\xa0Y+\x82\x92\xfcKXi57\x10o\x00\xf6\xc9\x96#\xeeYkud}kyS\xfb\x7fQB\xe9w\x81`\xd8\x8c\x0e\xbf\xf4\xcb\xdb\x11w5^\xb0\xfbl$$j\x0c\x901a\x1a\xddQ\xa1s\xcc\xddT\x02k\x94\xea\x97V\xf5\x14\x83\xbdr\xd9T\x0b\x16)\x90T[Q\x15\x98\xaa/\x19<\xd5\xe3-\xab\xb8\xd0p\xa4jlX\x9d@\xb8\xb3C!\x8e!&\x0d\xf0\xc5Hg\xe1E3K\xfa\xab\x99\x17\x9d\xa5R\xc0'\xda\xeeS\xf5\xdf\xc4\xfe\xab\xf6\"I\x86\xf1Vf]{\xebz\xf4\\\x85\xad\x8e97!\xecYf\x1c\xddm\xf3Lg\xf4Q \xa0\xe3\xdc\xed\xed\xce{\xd1\x1e\x92\xb97\xebA'\xe8D\xaf\xccX\xdf\x1en8 \xb6\xb0\xbd\xd0nGLs\xdb'z'\xda\xf9\xc1\xe5\xd0`+\x18y\x9a\xdc\xc2\xd3X0\x83\x1e\xee\xbe Oi\xa1\x8bO\xea\xbbqbotV\xdf\x99\x1dh\xf1\x1d|%\xba\xb6\xd1v\xa8\x93Ag\xd9D\x96\xb6i$\x16'I\xbf\xc6g-\xe2\xcf@\xf9 \x1a\x1f\x8eav\xd17\xd6\x97Y\x95v\x0b\x04tv\xdf\xa6\x1e!\xed\x8dm\x9f\xb3\xc68\x83/\x83!u&z\xee\xd4\x15\x84\x05j?\xbc\xd1\xb8\x11\xfb\x0c;\xc2\x85\xa9_\xf5\x0b 5q.\xcf\xc5!{\xbeO\x0e\x9fz^p^\xe6$\\q\xd7\xdd\xe0# \xe7\xe1\x15Z(\xe0\xef?s\xbfg\xf6\xc1\xe4)\xfa\x86\xfcX\xad\x13\xf2\x85\xa9C1MLP;\xf9\xb1zGS,\xfd\x10\x16\xc5\xa7e\x9eU\xd7K\xa6\xfb\xd8?\x1c\xa4\x83\xed\x0d\xd1d\x0ett#\x92\x99\xb9\x18\x07MyW\x93\x7f\x06\x95?h\xc7\xc4$$\x89\x0b\x8c\xb4\x02\xc2o\x83!\xa1\xb4\xcc\xef\xd4\xa2E\x9c\xc6\xc5\xb2\xcf\xc7\x87>[\x9dK\xa0?\xb5\x96\x8fujG\xed\xa52*{=\x0e\x93r\xa3NQ~\x84\xd6%\x0fD8({\xa3\x80\xfa\xdd5I\xe7qz\x1d]\xed\xecP6\x8f't\x81\x1cW\xd0\xfam\x9b\xf2\x10\x0f \xa2,\xffL\xe6\xdcc\xb5x\x9d\xa3]\xac\xa9XlRIy\\\xd3g\xa7\x86\x00\xa8\xf4y@\xb5\xb7\xc1V\xa8\xe3r\xcb\xb7i\xd5fCB\xee\xe4N\x82\xab<\xbb-\x18\xf12sn\xc6\xc1d\xec\xf8@\xff8\n\x9c\x8b:\xfaW\x13\x0f\x8cA\xc9\xb1\x0f\xfb\x1e\x8f!\xcd\xbci\xb2:\xda\x8f\xda\xdb\xaa\xbe\xa6\xe7e\x88Z\xd9\xeb\xf6pP\xc8\xe2\xee\xeby\x04\xa3 N\x97$\x8f9L\xd8\xd5\xd36\x08\xb1\xa3\xf9\x90\xcc\xc9:'QX\x92c\xbc\xdeO\x0d\x0b\xd8V\x85'\x1c\xfa\xe8z%\xfa\xac\x99\xc6i\xec\xf1\x906\xed\x1aK4\x81h\xf2\xa6(\xde[\x1e\xfcfH\x0c0\xf7\xe1\x86\xf7i\x07\x0cw\xf8\xb1\xe5\xe5\xb5\x114\x03\x97\xaf\x85H\xb23X\xc8N\x1f\xaaW\xda\xf7D\xdcb\"\x0b~\x0dt:\x82\x12\xa6\xe5x\x9b\xcd\xd1\\l\xab\x94\n|\x16V\xd7m\xd7\xd3K(W\xb6\xc5\xfc\xf1\xe8\xf9x_\xbf1PZ\xb5~5X\xc6\xd7\xcb?\x87%\xc9\xdf\x86\xf9\xe7\xf6\x16\xd0'\xc2\x8a\xa2\xdd\x7f\xef\xff`a\x18\xdd\x19L\x0e\xe0\x18&\x07\xbb\x87{\x96UP\x86\x02\\k\xcbh\xd3\x18\xce \x86c\xbe\x16Q\xf3\"\xa2\xe4H\x04\xc7\xb0\xf0\xcd\x8d\xc8\x19\x15[\xef\xbd\x06\x94\x87\xc9\xcb0I\x98\xc0g\xe2\x0b4@\xe6?\xe6a\x9c\xca\x85\x0c\xe2i%\xeaw\x0c3\xa8esR\x94yv\xc7\x0b\xcd;\x92\xe0;\x9e\xe7fN\xa2l\xce\xbd\xablxJ\xa9C?N\xea\xdePB&R\xc1\x00kP-\xbb\xbf\x07\xa7*\x17\x87B\x98$spX@w\\\x9b*\x03\xb3R\x9d\xe2.\x8d\xb8\xb8\x04\x7f_\xe1U\xfe\x90g\x11)\n\xed\xe3,E_\xd1N:O<[\xdd\x94\x92\xfc\xdc41Moe\xd8h>\x9b\xe2\xc9\x99 \xfa.\x8d\xba\xeb1\xf7f\x1cxteG\x87\x94\\\xec\x9f\x95xJ}mE\x07\x0d\x85Q3\x07\xe2\xee\x91\x84\xa4\xbe\xf4\xb7\xe2\x86\xa5?\x0f\x88\x8a\x89g =\xba#G\x8aggGB\xee>\x1a\xe0\xbb\x0dNrc\x1fr\xcf\x97\xb0\x94\xfb\x8as\xe4~k\x1f\x98\xd0\x94 E\x85<\xb5\xe4\\=\xd3_\xd1\xc60f\xbfO\xc5\x1b\xcf\xf3!\x91T\xc5\x83\xf6\xf4R\x05\x8aL\x8en\xdae\"\x1f{\n>\xa4\xbbQ\x89\x9f\x1c\x9e\xa3\xe6@\xc2\x8b\xe8\xbc$V\x8aBN\"0!K*\xc1\xde\xb8\xac\xf7\xe6\x9d\xdc\xcad\xd0l\xae\xa4\xd9\x98&\x91B_\xf4\x03\xf1\x88\xb8\xc6\x1c\x07moc\xf4QA\x0ca\xda\x9b6q\xc4!\xf2\x9c\x969\x06(\xfc\xe0\x96\"\x86\xa5\xc26\xe6n\x03\xbb\x07\xcd\xf3\xd6:vb\xa4?\x0c\xd9\xb4\x04\xcd@t\xd0a\x16\x04\xd5\xdb\x87\xf2y\xa6\x8a\xa0\x98\xcf\xb6~5\xf1o\x84Lv\x82#\x069\x92ln\x89\x02\x02\\\xeao\xe2z\xcd\x98(k$\x05\xe6\nu|\xad\x90\x81\xcd\x82\xad\x1b\xda!\xc7\xa8\xae`&O\x98^\x0e\x95d\x05\x0b\xea\xc6\xa3^\xe0j\xf8\x10\xc2\xe8\xd4$L\xa3\x0f\xc69e\x88\x00\xcd\x7f\xfd\xfa\xf6\xb1\x1bSg4\xf3\xc1q(i\xc1\x10\x80z^F#\xac\xda\x81R\x18IB\xc9\x15\x8bP \xe3c\xcdd)\x8fg\x17\"0<\xc1\xce\xad\x0d\xcf\xb4\xcfz\x17\x05!d\xc4\x9d\xf2\x98\x9a\x8f\x0f\xa2e\x95Z\x18-\xf1\xa0\xb1P \xd29v\xd7M@\xc4\xeb\xe9\x16\xf0\xd0s_\xef\xd0\x04!\x93\xc2\xcd\xc11D\xf5\xa6E>e\xc0\x12\xed8\x98\x17\x8c\xde\xf9\x1a`z\x1b)\xa8\xe8S\xbb\x88\x0b@d?\x0d}2\x1e\x90@\x86\xf2\xado\x81$\xc3\xe0\xf0\x97n\xff(\xc1Abtx%\xab\xb10ld\x85\xfa\xb8\xd0d\xa2\xe1-\xd9O\xbe\x8c\x83\xc6un\x85\x9b%G\xa7\x0d\x0bc\x95Pj\xc0\x1b7A'\xc6SviU\x1aN\"\xda\xeb7\x8e\x05\xf2\xd3\xe7a\x182xe\x9d\x94\x80\xf1_\xbatM\xec\x10\x0d\xe46\xd59\xdd\xdf\x03Q$\x07\x14,Z\x88\x17N\xad T\xd2\x80\x99&{\x18+\\\xd59\xe7\xaa\x90;\x1a\xb8\xa4]\xa8W \xf6\x86\xe6fw\xc8\xd2j\xd3\xa4/\xd9\x94C\xeb\"5\x92EJ\xf2R0p\xad:\x8a\xd4A\xab;e\xe55\x16*\x85\x00I\xbb\x03,\x98\xc8\xec\xe2\x04\xca\x13\x8fN\xa3*\x96,4 \x12\x82t\xd9\xac;\xadyy\xb7\x81d\xaf\x18\xdf\xee\x96J\x1f\xee\xe6\xc4\xfc\xd7\x84\x9b\x93{-{\xac;l:\x8e\xc9\xe5J~0\xcc\xe9\"\xa8%\xae\x9b\x05|\x97U{\xf5\xd2\xbbv\xde\x10\x18\xc7\xe7hL7\x1b+\xc4E#\xf9\xe5\x96JZ\xc5f{)wC\xc2y\xe0\xf8\xe0\xfc\xf8\xea\xc3x<\xde\xb5\xa4F\x83\xf6\x05\xaf\x8b\xed.\xbb\xf8\xda\xb5\xb1\x08\xdc\x13n{\x9b\xff\x15,\xc3\xe2\x0d\xe7\xb7\xc0\xe6\xd3\xf8\x9a\x97IQ\xc7\xda__\xd0\x8bK\xef\xc6\xb0\xda\xbe\xe5,\xac|\xc3\xc8:\xdc\xef\xfa\xe5I\xb5#\xcc\\66-\x1b~\x93\xde\xf6\x15\xf0T\xcd\xdb-\xc9\x8a\xcc\x8f^\xf7a\xcb\x07\x84B\xf3^\xf1]\xedG*5^\xb6\x94\xf2>\xac$\x10\xb1\x8e\xd7\xa4\x0f:0 \x80\x8ah\x9a\x1c\x8a/\xc34\xcdJ\xa0\x0d\xf9\x18\xa7>\xe7\xeaM\x9d\x15\xd1zn\x8b$\xed\x1a:$\xebY\xe4Y\x03cn&\xbb*\xc6\x1e\x19\xdfa\x80\xe4X\xa6\xab\xea\x84\xfb>\xac\x9b\\\xce9nh./\xe8\xd2\x8e\xd2B$\x0d\xd6J*h\x91\xd9|\xf0\x91Zc>\x01\xdd\xfb\x13\x80\xe7\x10\xb4\\A6\x81T\n\x0eM\xa90\xca\x17\xb0\xf0\xd3\x02\x00Rj\x1b\xd1%sr\xd5$\xd3j\xeb[R\xf0}\xd1\xfa\x9d\xe7C\xcc\xe5\xeeg\xc3p\xb7\xa0\x06\xa4#\xc3\xb6>\\\x94$\x07\x92\xcem\xc1*L\xd4\x8d\x84\xa2\xf1\xb0\x98V \xefb\xca\xc3^\xeb\x9c\xb7\x9dK\x07I=c\nZ\"\x9e\xca\xa2H\x00\x89\xb8iH\xe53\xe6\xa9\xa8\x06\xe8\x7f\x1b\xde\xe1Ua\x0b\x81\xb5\x11\xf4\x14PfP\xa0\xb1\x80cM\xd6\xdf\x04\x05a= 9\xa4\xaa\xa3\\C\x9f\"\xd7i\x9a\xa5;\xac\xd9'\x1c\xd3 \x9f\x83\xc1\xbf\xb9A\xae\xb6\xee\x95\xba\xee9+\x89\x05\x1f\x1a[\xf7 f2S\xe6\xe6\xe7\xc6*\x01V\x19\xee~-\x0d\xb2\xed\x0f\xdaq\xf5*\xf1MM\xf7!\xf0R\xd7\xe8\x19\xd5A`\x8e\xdd\xdf\xdc)~}\xb1\xc7\x1e\xe9\xb4\x91<\x92\x9f\x87\xda\x08\xc3\xdeP\x8e\x06_U}A)\x11\x19K\x17\x9e\x99\x05T\x16\x8co\xbd\x03!J9Z|g\xde\x99Y\xaa\x16[\x8d\xac\x86\x91\xb4\xed\x02$ \xd73 \xaaf\xd0\xfc\x1d3\xdd\xd7d_c\xcb\xba\xa0\x05Q-\x18\xc4\xeb\xc1\x04\x0c}\xe7&b#k\xb3\xb5\x1d\xfa\n\x0b\x17\xdc}\xd8\xf0\xc6\x1d\x83A\xf3.?B\xacp\x0cq\x8f\xaa\x8c\"\x1cc\x1c~\xf9\x11\x92\x07c\xee\x05\xf9\xa17\x9d9;\xdb\x8f&\x0b\xd2\x1f Q\x8ey\x19\x8e\x8dL\xbe\xb1\xaeU\xc83:\x85\x89\xf9\xf02I\x8f,) \x1b\xf8\xd1 \x9e\x8b.\x88\x152\xce\x0f/\xb0/\x85\x82\x836 CO\xd5 \xe2I#\xdc\xd9i\x1c\x8d\xba\xda\xae\xd2!\xad+<\x9b\xda\x8bA\xa7!4a\x0c\xc8\xb3\x1f;;\xbe\xa4\x15\xa5\xe4\xab\xa4/\x93\xa4\x1e\xf8\xcb\xa8=k\x0bL\x98\xf6\x8c\x93\xc4\x9dD`A\xca\x1f[\x1a\xf3nZ)\xb6\xa5A\x14\xa4V\x19\x94\xd9O\xd9-\xc9_\x86\x05\xf3\xb0\xd8rg\xce\x92|\xa1\xdc\x11\xd7\xbb\xd3\x7fw\xf0\x8f\xb0\x88\xe2\x98\xfeq\x15\xa7a~\x87\x7f\x85\x059\xd8\xc3ZQ1\xe5\xff\xeeL\xf9g\x93\x83\x84\x88\x16\xc4\xdfyx+\x19\x19\xb9,\xd3\xa2\xa7\x8d\x03\xad\x8cp0\xb59\xe2\x90\xbbm\x8d[\xc1,\xae\x9bt5\x12{@ \xccM\x98 )\x10\xf7\xf6\xb6\x1c\x98\x8e\xb1\xb8\xb5\x8eZ\xc8\xbcr\x19\xde\xe4\x8d \x8bP\x1e3\x10\x8774\x17\xb2Y\xcan)@g\xc8J\x01\"\xe2\xc6>h\\\x0b7\xfdZX]\xb7y&\xd3\xb2)\xd3\x04fiDj\xa1[\x07\xe9F\x1a\x93\xa3\xb1/\x99f\xb5E\xd4 !\x95\xbc\xc5\xa8\x0c\xbc\x82\xb5\xe9\x92\xf1\xdamt\xad\xe4\xdd2\xa8\xb6k\x0bt\x1d\xa0\xf0\x01\xb4\xe7\xd6\xbe\xe6\x852\x1e+\x9fk\xe9\xde\xed\xec\x9f\x9e\xe1~1\x89z\xd3\x1a%\xf7\x8d\xf8[\xbb\xa6U*\xd7\xa9\x7fi\xb5\x9a:\xbd\xfc.\x93\x94\xa4s\xd7\xf3\x81\xb4\"8\xfd\xa1\x19\xa9\x9a\x9b\x11\xb3\xe8\x1f\x8d=\x8a\x0e\xdf\xacVd\x1e\x87%\xd9$\xb5~\x7f\x0e6\xfb\xbe\xf0\x03\xd2\x1b=\xe2\x9b\x0c#u\xf7\x0e\xf7<\xd7\x833\xee\xbf\x8c\xc9\x13\xd1\xb0\xf5p\xff+\xa6z\xd3\x84o>2\x87R\x99\x9a\xd3\xc2\xed\xea\xc1\xc3*\x83k5G\xec\xedPC\xfc\x1275\xb5h\xee\xca\x07\x850\x8a\x0c\xaf\n\xf5M\xf4Uy\x02n\xea\x90\x0d\x0b\x1f4k\xf4\xb8\x95=\xa5\xb2\xf8V\xaa\xdf\xa1B \xc5\x00\xb6\xcc\x1b\xd8k\xfc\\\x17Z\x84\x05\x86#h)\x0bo\xb1\x10Y\n\x16\xf0\xfc\x14\xb3\x14D\xee\x82\xa7\xfc^\xc6\x8d\x93\xd3\x0eDn\xe1.<\xef\x04X\xe4-\x18\x8d\x0c\xea(\xb4\xf3\x91\xa5\xac<\xccP\xc2Q\xe3\x8c\\\xf8\x90\xbb\x89\x94\x02E\xc3\x8f\xbc\xb47\xd3\xfc\xa0\x93\xa6xH\xb4\xb0\x91\x10Tj\x03\x18F\xd4\x9aDo\x96\x14\x8fHa\n\xc2\xc4\xeeA\n\x12]\xa5\xbcx`R\x82\xeeA5\x07\x8b\xd6\xad\xf3\x8b\xb0P\xcc\x9f\xc8\x97\xf2]6'\xaec\xcb\x99\x92ah\x01\xdbx\xb4\xb0\xb8]\x029\x0b\xfb\xcd\x1d\x858\x82g\xcau\x16#\x9bX\xf1w\xb7u\xa1\x90.\xb1!v0\xfdp\xaai\xe5\xc4c\x96\xa8\xa0\xcb\x9aJNY\xe4\xb8i\xe3\xc3\x08u\xfa?V\x1f1x\xe9Zf\x86\x176\x0e\xe6a\x19b\x98\xc2S\x18\x8d2\xf8W\x982s\x07l-(\x96\xf1\xa2t1\x04\x05\x17\xbf\x08\xafkN\xe1\x95\x06m\xd5\x83\x17dW\x05\xc9o\xd0R\xca\xbcx\xd12\xcc\xc3\xa8$\xf9\x8fa\x19\xb6\x82\xfe\xb3V,\x16\xeb\xbd\xf4\x02}X\x9a\x17\x0cai&X\x99\x94{F|(/P\xec\xc0\x15\x94\xa8\xbde\x04\xb0iq\x86\x88\xc5\x1e|3\x1c\xb6^\xe3v\xe4$$p\xec\xaa\xb0&\xc1\xb4\xe4\xf6f\xf6B\xe9\xe8D\xdcO\xdaM\x9d.\xa8C\x8cj\x1c\xca\xdb\xaa\xc4\x84|\xef\xd9\x8e7~\xb1\xb1\xdbze\xbf\x95\xc6\xa6\xffL\xae\xfe#.;:\xb0Th\x1f%\x1bH1\xdf\xa8\xde\xe0\xbb\x80\x8c_\xee\xea\xa2\n\x00\x16\xb8\xd5\xd8lA\xcaO\xf1\x8ad\x15J;\x0c\xdb!U\x182\x80\xa6\xba\xcb\x0e\xfb\xd8<\x98\x96T\xeeA\xba\xb2\x83\xe8\xcaoBeY3h\x9a\xb2f\xaay1\xa7l\\\xfb\xd3}\xfe\xef\xc1\xc6y1;F'\xd2S\x1e\x9a\x92\x8d\xa1\x86\x8f\xa7'P\xc3\x0e\xe7\xdda\x87\xd5X\xe9\x96|WV\xc8 \x84t\xed\x0e\x92,\xc2\xc3~\xdcJaF\x9fe\\\x94Y~g~\x99\xadI\xaa\xb2\x7f\x86J\x98\xf2\xab\xb7\xd6\xeb8\xd1+\xd9\xe6\x0b\xe2\x86K\xf1\x82\x9b3\x7f\x8b\xc9\xcal\x89\xfa\xccV\x1cta\xd8wmxr\xc3\x1dFm\xda\xb8\xb4C\xc5\x9b\xd7\xf1\xde\x0c\x82P\xab=Im\x08\x13\xf3\xb0Ih\x15$\x82B\xbb3\x87\xae\x95\xe3\x83\xf3C\x92]\xd1\x7f_g\xf9\x8a\"=\xe7\xc2;\x01\x16\x16\x13\x13\xf3U\x08\xc0]\xcf\x0b\xe6YJ\x90\xc4E\x8dE\x07\x92\x13z\x97\x98\xe5\x10\xb4\x93\x1f!\xc4)_3\xc693;QV2\x0b/\x86`5,\x91\x0d>\xec\x0b\x93;\x8c\xee\xe0P`\xe0\xd0k\xcb\x0b]=\xc9@\xaf;\xbb$\x1eW\xcf\\\x9f\xb8@h\xd6\xe7>\xdc\xf8p\xe7\xc3\xb5\xde|\x81y\x0f}\x98\x1b\xdc\x92W>\\\xfap\xe5\xc3m/\xbb\x08\x82\x83Z\x83\x08\xb6\xfa\xa2\xc6\x05/\x8c\xf1 \xe8#\xc2\x15v2\x00\x18\xef\x8fe\xec1\x87\xe0k*1C\x8a\x8ej\xd0\xacf/\xfbi\xf8\x86R8i\xad\xdd\xea\xfc\xca\xe2\xfce,\xdddD\xc3Gb\x00vmt\xf9\x05\xbd\xa5G\xe0\xc0\x1bq\xa0\xdb\x95\xce\xe1\xb4^[\n&n\xdaU^Y\xd0\xf1\x0bT\xca5\x82\xedV\x85\xf7p\n/f fNz1s\xfe\xed\xdf\xea\x8b\x85E\xe8\xfc\xf1bvcH\x1a\xfd+\x05\x86L\xdfxc\xe00?S\"\x00\xce\xe0\x1c\xce\xe0\xd6uHZ\xe61)\x10\xa2\xfd\n\xf6\xd4uoX2\xb7<\xbc\xc3\xa9\"\xa2z\x11\xf0\xafio\xef\xdb\x14\xd1\x1bD\xc5W\xf4\x96\xb8o\x18\x19\x8e\"\x0e\xcf\xf3P\xea\xae\x8b\ni\xf5+\xa6>G\xcfj\xf7\xca\x87/>%\x11(\xba\xa5<\x85\x89\xed\xb8\xe2\xabT\xd1\xea\x89\x0fK\xcf\xf3\xe1\x9c\xb6\xf0\x1e\xe1\x8c\xd8 \xec1H\xc3\x15\x93\xad\xbf\xe2x\xfc\xd7\x81P\xe6\xbd\xd5\x9f\xcb\xe3n\xf1[L\xf7\x8bW}\xeb\x15\xdb 1\xb4\x178\xb4_=\x1f\xc2\x19\xa1\x94\xc9\xaf\xf4\xaf/\xf4\xaf\xa5\x0f7f\x11\xdf\xcaj4\xc1\xe6t\x8c\x9bHw\xed\xd6\x15\xd3\xb4\xc8\x14(\x988\x86\xbb\xa6\xba)\xd3\x97x\xf8\xae\x1e\x83A\xb1\xe8\x9bl3A\x90\x89\x97\x14\xc2\xad<\xc0\x7f_\xd0\xa9gt\xea\x97>\xacf\x97\xa6\xf0\xa2,|\x91\x1b\x07\x1f`\x04q\xf0\x1a\xbe\x07wM\xbf{\xe5!\xfc]\x99c\x11\xad\xea\xc2A8\xf7FJH9\xb5\xd0\x0f]\xdfC\x1d\xa7\xa7\xd4\xd2\xe4\xda\x08{\x01\xc1\x8d\xba\xb9\xae\x08\xb3:\xcc\xeb4\xd2\x12}7,\xae\x05\xe4\xb5\x17\xbe+ mk\x0c\x1d\xd6\x81`\x1c\x06\xfd`\xa3\x91X\xe2\xd6\x9aF\xd2\xe30n\x1c\x8c\xd5\x1f\xb9+\xce\xca\x10\xf4S\xf7\xc64\x08DV\x1fX\x9a\x1etb\xe5\x93\xb9\x95\xba\x93}\x16\xa54u\xa7G\x9e]B\xccG\xf3\x14\xb6N-\xcaT\x91\xda{\x1e\xdf8\x9e\x0fN\xf8\xf5j\xd4\xa7m \xa1\xce\xdc\x0b\xc2f\xf2\x1b\x92\xfbS35|\xf4?3\xdd\xa2\xaa\xf6\x9bn\x9a\x19\xa8\x95s\x98\xab\xf1\xcc\xf9A\xa6\x93}\xcf\xdd\xd2)uc&\xf9\xbeu\xb1\xc7\xfa\x0cyB\xc76\")\xda @\x813\x163\x8d\xec\xe5\x9a\xb58\x85\xd0\x83\x94\x1e\xde\x8a\xed_\x88K\xb1\xbd\x0d\x11\x13^\xeb\xc1\x0d\xb8\xf3\"i\xc2\xe7\x16'\x1e\xff\x8e\x12p\xb3b4b\xf1}\xdd\xff\xca\xdc\x08[\xbb\xbfoZ3#\x97h\xb3M\xed\xdd\x9f}s\xaa\xe8\xcel\xfe\x95A\x93\xda\xc5\xf7\x06\xd7\xa4\x94\xb2d\xabV\"\x96c]\x8a\xbd\xe3y+\x91\xc5\x9de\x176\xf9\xae\x9ae\x8b\xf33\x8dW\x85\xf2\xf6L\xfd-\xd1x\xc7\xeag\x9c!?\x83J\x97\xe4n\xb8\xf8\x87\xe6\xc5o%\xe4no\xc5?s\x14\xd7\x03\xee\xcbu\xf8?;G\xb1\xf5\xec\x98\x12/\xfd\xcf\xcd\xa5\xdf\xb9\xcd\xbc\xb7\xf6.+\x16\x8b\xee\x04\xb6\xc1\x04\xd5\xb5<\xb6\xee\xd4RO\xd8,\xd1:{\x96:\xe6\x8c\xb7\x9b\xeda\x9f4m\xb2{\xd0N@\xbf\xfb\xf4\x9f \xe8\xa5\xe7\x7f@\x02\xfa}sR\xc4\x01\x19q-\xe7\xbf\xae`\xb3\x9f\xa4}\xf3@\xe6\xcd\xbe\xc7\x14.\x99y\xe6\x82g\x016\xbf\xa5TOhu\x14\xe1c*DJ\x9c\x82ns\x84 \xd6x6s\x8e\x03\x8e\xc1\xc5\x08\xdb\x98D\xf1e6'/J\xb7\xf0\xe4\xee\x9d\xe7\xc3\xdd\x1f\xa4\xa2e\xe7t\xa5\xdd\x91?r\xf8\x15\xc0!\xa4\xee\xde\xc4s\x13\x0f-i\xbb\x1aK\x1a\xd7\xcb\n\x83\xf4\xfa0\x91\xcc\xae\x1f(eI\xf7\xe1&H\xb3\xdb\xde\xd6\xb0\x96\xb5\xa19\x86\xce\x16\x06\x99\x94\xa2\x9c{\x01\x05zS\x1fb\xfcc\x12d\xe9\x8a]68\xa5\xd4\x07\xc6\xcap\xb3`\x9d\x15%\xbf\x85\x08h&\x18\x81i\x11\x84\xf39&\x1a\x94Se\x197Cj\x00\xc9\xbcE\x10\xafh\x8f\xe7Q\x1e\xaf\xcb\x82\x8e\xac{j\x0by\x0c\xdc\xa1\xdc\x07\xe7{)\xac\x17\x85\x94\xad\x11\xb9\x0e\x9f\x90\x83\xe4\xd4\x16\x1b9\xed\xcb\xc9\xd2\x9c\x84\xf3\xbb\xa2\x0cK\x12-\xc3\xf4\x9a [\x1d\xb9N\x81\xa3r\xbcNK\xf5\"\x08\xd7k\x92\xce_.\xe3d\xeeJ_yA\xbb\xe5\xbe3,\x123\xb1\xc6J\x16MY\xdcS\xab2\xb9\xd3\x94Q\xb2\xa0oN\x84bG\x8f\x99>%\xc4\xd7\xfa\xfe\x18\xd6\x1af\xa0\xb0\xfa\x18\x9a\xecC\x9b\xd1)\xf6\xc1\x9a\x95\x0fVy5},\xce\xf5\xf4\xb996{\xee\xa8\xeb\xd8i\xd7\xda\xdb\xb5\xc5\x04\x9bv\xdd\xd7q\xcf\xeamJ\xe9\xb4\x0c29\xa53\x1ed\xed\xa2O\xbe1u\x89]\xe6YH\x14\xe5\x1e\xea\x9bl\x9e\x857<\xb6U\x16,ZQ\xc4\x05!\x8c9\xc5sRd\xc9\x0d\xf10\x9c-F\xb1[\xc5\x05y\xec\xc2\xb4V\x80-\xcc\x9e\x9d\x04\\\xd1\xad\xef'\x00M\xd4\x9f\xd9\x99\xb2\x0en&9\x963O+N\xdemmQ\x02\xcf\xf9H\xae_}Y#h\x8c\x15\x0f\x9bAS\xb6\xdf\xd6\xda5#u\xa7\x87:A\xd7\xb8v(\xf2\xffA]\xca\x12V\xe3*\xeb\x9dq\x03\x84\xa3\xde\xc5\xb5Q\xd7\x88\xa1\x02\xae\x1b\xc6\xa46\x1eW\x8f\xb12J\x16\xb5\xaeX\x85\x84\x9d\xba5\x15\xcf\xfb\xcb\xb2A\xb9yp\x0e#\xc8\x91Y\xce\xba\xf5\xbc\xf4\x90(\x85\x98\xbf\x9dk*}9|\xd4\xa054\xcb\xae\x89\xecr#\xc2\xb5\xf3}\xec[(\x14\x8e\xba\x8a2\x9d\xd8B\xa9\xf0\x80\x84\x14\x97@\x08Q\x12\x16\x05\x84\x85\xe2%\xfb\xbbLG\x93\xd2\x0bO\xa4\xc9\xbe\xe9\xc4|{W$\xe3Z\xb6\xc8\n\xfe\x02J\xab^\xbc&oS\x96\x1a<\xc5\x18]\\\x9d\x03\xe9h\xd4E\xe8\xe7h\x89\x92Z\x08\xfd\"\xd2\x84\xac\xa0s\x01\x0f\xad\xaeB\xf6\x89\xe4\x95\xbd\x95\x07\x0b\xce\x97\xb1\x80J\xe5\x8c\\l\xb8_\x8f\x03%8WJY\x1d\xea\x1a\xdf\x98\xbf\xda\x1dO\xf5W\x19\x7fE\xe1\x8f\x9c\x86\xb0F|\x86\xdc\xa4\xb5\x89 \x0b\xd4,\x83\xa5\xb2\x1b,iA5\xfe\xd0\xfek#\xf8d\xb9\xea\";\xc1\x163\xc27\x12=\xe7\x14:\x01\xf9\xb2\xceIQ`\xd6\xa4\xaa(\x81\xc4\xe5\x92\xe4p\xc5c\xccf\xb9D\x05\xb1`\xcd\x0e\x8c6\x86J\x1a\xb8\x935s\xccc6\x96\xaa3\x8eJ\xc2\x8d\xed\xe5\x94\xd8-\xd3jC\xa7\xf5\x0d\x0c\x08@\x07\xaa\x91\x96\x85\x95\xd5\xcc\xbd\x0c1,\xd4\xdd\xc6\xfb\xc8\xa8\x11\xb1\xc7g8\xfd\\\xa1CD\xb2\xa1K\\\x83\xcbKJ!}\x93\xfb\xa3\x1aX\xef\x8e\xbfM\xfc\xa4\x03\x93}`\xea\xee\x99\xedz'-\xc5\x12zMS\xe09f\xe1\x07\x0e&\x9eb\x906e\xe5\xbb\xe3\x03\xe3\xf5\x0cMc\x06a\x97\xb6\xce\xb3u\xd1\x845\xa4\x98\xaa\xe4\x01HyIN\x16\x05K\x0d\xc5B\xcc\xad\xe7a\x89\xf9\x0f0Nr&\xad{\xbb\xef\xe2\xef\xd8w\xa4\xba\xdd\x87r\xf4\xa9\xe2# \xa3\xf2e\xb6Zg)\xc1\xbc7\xbf=\xf8J\x95\x82\x94\"EY'\x90\x91\x88\x11%n\xa69\xf4\x90\x04x\xd8\x8f\xdcu\x0e\xf7\xeb\xec\xef|~\x01I\xffZ\x91\x8a\x9c\xf31\xd4V\x15\xbe\x94\x87^\xab\xfb\x92\x87\xa2\x15\x11\x9d|p\xc4\x14T\x01\xa7<\xc9E\x96G\xe4gl\xa8[\xb6f\xe8\xf0u\xf3\xad\x906\x96\x03\x07W\xfa\xe0H]\xab\xe3\x8b\x14\xd8\x17\xcap\xaeP^Qp\x1d)\x85\xaa\x94 \n\x1fb\xb7\x90\x1b\x90Z\xf3\xd4/\xe3\xe2C\x95\x93\xd6\xa9\xe0 D,\x8cB]\xf3\x18B\xf5\xca\xd2\xc6\xa4\xb7\xc5\xb7\x00N\xa9{ ;\xaf\x0b\xf8\xa2\xe1\xbc\xe2mV\xa5%\x99\xf7\xc5\x0d\x14\x14\xb5fc\xa9NC\xdb\xbe6ae\xae/\x1d\x0dm\x18\xe6\xfa\x1f\xc9: #\x16\xa0ph\x1f\xe2n\x18\xea7\x8bm\x86\xec\xf9\xe3\xf7@,\xba\x1c\xac\xfe\x1b7\xfd\xdb\xb7\x1f\xb5\xfd\x04GU\x9e\xe3 \xdd\xdcu\xa2{\x16\xc3\xb2\x9a,\x98#H\xf3\xcburz\x05\x03\xc2\xd4\xf8\x0e\xfa\xdb\x1c\x8c'\xe3\xdd\xdfuQ\x9c\xf3W/?\xbe\xfat\xf9\xe3\xfb\xcbw\xef?]~xq~~\xf9\xe9\xdf\xdf\x9c_\xbe\xffx\xf9\x97\xf7?_\xfe\xf9\xcdO?]\xfe\xf0\xea\xf2\xf5\x9b\x8f\xaf~t\x86\xf4\xa9Q\x12\xd3\x897L*\xd1\x17!\xafu\x97\xcd~z\x14\xfc7T\xb7\xd1I\x8f\xd3\x7f\xba17\xa6\xbb\xba&\x14\n\xae\xb2\xf4\xd5\x97\x92\xa4\x94\xf8-0\xca\xf85)\xb5\x12RD\xe1\x9a\xfcH\xc8\xfa\xa78\xfd\xfc!\xc4\xa4\xcb\x84;\xbb\xb5\x8a\x8be\x98$\xd9\xed\xab\xbfVa\xf2\x1f\xe4\xae\xe0i\x05\xe3d.\x82\xbe\xb0jY^\xb2\xccz$\xb8*3^H\xf28L\xe2\xbf\x91s\x12\xe6\x11ko\x1d\xe6\x85\xfc\xfb\x9a\x94\xe7\xe1j\x9d\x90\xf3hIV\xec;L\xd1\x10\x96\xe4C\x98\x87+\xad\xa4,I\x9e*eo\xe3\xf4'\x91;Z*\x0d\xbf\x18J\xffX\xc5s\xa5\xe0\xc7\xb0$\x9f\xe2\x15Q\n\x99%\x8cR\xf4C\x96%$T;~\x1d'\xeawo\xd2\x92\\#\xad\xd3\x94\xbd\xabVWZ\xd1\xdb8\x8dW\xd5J\x1fn]Fi\xac\x97K\x12}\xe6\xdf\xad\xc8*\x8b\xff\xc6\xba\x8a\x8b7\xabU%\x84~\xa6\xd0>\xe2:_Q\xd6p\xfa\xd4d\xbd\x1e\xd7\xaf\x8fL\xaf3\xfe\xfap\xcf\xf4\xb6\x12\x1f\xef\xee\x9a^\x87\xf5kc\xd7\x05\x7f\xcd9S\xf9\x15\x9d\xdc\xff=\x7f\xff\x8e\xeb\x00\xfa\xec\x19\xec\x9eK\xc2*\x816\xc6\xce\x9b1\xb9-p~\x93\x85\xa4kb\x97\x0d\x11P\x15*+X+\xc6Z\x9d\xf4\xa4\x93\xb2\xa1\xf4:\xedD\xbc\xb8\xeb] \xde\xc8+\x17C\xd6|qy\xe4\x9a2\xfb\xbf\xe7.\xb2]\xaa\xdfj\xdd\xc3\xff\xcf\xde\x9fw\xb7\x8d#\x0f\xa3\xf0\xff\xcf\xa7(\xeb\xc9/C\xb6i\xc5r\x96N\x9c(\x9et\xe2\xa4\xdd\xd9z\xb2\xf42\x8a\xc6\x87\x96 \x8b\x1d\x89TH\xd0\xb62\xf2\xfb\xd9\xdf\x83\x02@\x82$\x00\x82\x8e\xbbg~\xf7^\x9e\xd3\x1d\x8b\x0b\x96B\xa1P{\x85i\x1a\xae;t@E\xb3\xe8\xd8\xaa\xfe\x8d\xbd\xbc\xf70@v4nv4K\x93\xe5O\xef\xdf\xa6S\x92\x125\xef7PO\xab|g\xabr\xe1\x11c*S(VN\xb1\x84,\xe5\x92\xf4\xd9\xbe\xb4}Z\xc0\x8b\x94\x19x\xa3\x8c\xcf\x04oM\x8a\xa6\xde\x93/\x1e\xf1\xfb\xcbp\xe5Q\xccd\x1fe\x14g[\xbe\"\xa6\xf5:\\\x95oB#\xc6 +;D\xf1\xf4C\xe2$\xa2\x80b\x16\xab\x1b\xb8\xa0jV\x0d\x159\xdb\xef\xcf\xa2\x05%J<\xa3\xb1 \x91hA\xefD\xa3\x8d\xf9\xf3\xd9i\x7f\x18N\xe6e\xeb\xc6\x1c\x01\xd2*0J\xc7h\x0dM\xc78{O\xe4^\xd7X#\x9a%\xfe\x18\xc8\xe2$]\xe2 \xc2qn\x08\xef\x03\xa4\x13\xcfcW\xa4m\xc9\xe8\\\xf4\x14e\x05\xdd9\x14}\xe4X\xfd\xf8\x9a{\x91\x13qj\xb6\x8a\x9bu\x97\x10A%^\x87+\x17t2\xa2LJ\xa6\xf9D)\xf2g\xcb\xfdP]W\xe2\xb1\x95\xe5\xa6\x9df&\xd8\xcb\xa0\x12\xd1\x08\xca\x90\xdfa\x97\x7f\xd9\xa8\xcfD=\xabr\xbc\x06\xcb\x9cP\xf7Z\x0f\x84\xa8\xed@\x88D\xa5\xa7\xdd\x00\xf2\xf2n\x1c@\xd4 L\xd9:\xa3d\xf9a\x9e\xc7\x9f_G\xd3\xe9\x82\x9c\x87\xa9]\xe4\x07\x9d\xe5\xce\x04\x13\xd2\x9fJ\xf7I\xc1\x85\xe9K*@\x97Fu/7\xf4H\x86\x0f\x8cyKc\x8fz\xe8\xbfE\x9c$\x8b\xe9\xc3\x1e/_\x8f\xff\xa9\xaf\xe2\xbd\xf1h\x05\x07\xb8v\xb7\xe1\x00\xf6`\x1f!|\x0f\x0e\xe0\x8e\xf8\x9b\xdd\xbf\x0d\xfb\xb0}\xeb_^\xe8\x9dd4\x0d't\xb3\x88\xc2l\x13O7\xd2y{\xc3\xf6\xec&\xf3\x96\x9b\x8c\xa4\xd4?\xd8\xe44\xf17'^\x98\x91\x0d9\x8d\xe2M\x92,<\x12\xc6\xfe\xc1&%\xe1\xe7\xcd\x9a\x12\x7f3\xc1\xc7\xec\xc0\xd9\xcc\xc3t\x83\xf2\xedt\xb3\x08\xb3l\xb3Hb\xb2I\x96\xab\xc5&\x893\xbaIb\x1a\xc59\xf17S\xe2\x9d\xe4\xa7\xa7$\xddL\xa2e\xb8\xd8L\x16aJ63\x8f\xed\xf1\x0dI\xfd\x83M\x14Gt\xb3\xf0\xc8iH\xc9\x86P\xe2\x1f\xf8\x9bi\xb2\x99&\xf9\xc9\x82l\x887\x99'\x9bEv\x10\xcd6\x8b\x8cx\xd1\xcc?`\xf3\x88\xb3<%\x9b8_n\xceHL7\x17\xde\x84\xac\xe8\x86L6+\x0fS4o\x92\x94\xfa\x1bJ\xbcx\x9amPs\xb2Ic\xdf\xf7Y\xd7\x8b\x05\x9d\xa7I~:\xdf\x84\x8b\x8cl\xb0l\xf9b\xcd\x86r\xc1\xa6\x93\x84\xeck\x8f\x84\x939\x9b}D\x18\xd8\x92\xe5&\x8f'\x1e\xdb\xbdl\x80\xa7\x8b\xe4$\\lN\x13\x9alN\xf30\x9dn\"o\xb6Y\xae<\x8e\x03\xd9F\x19D\xecEt3Y\xe4S\xe2\x1d'\xf1\x84\xf8\x07\x9bE\xc4\xa0\x95\xd3\x8d\x14}6\xd4#\xe9,\x9c\x90\x0dI\xe3p\xe1\x1f\xf8\x07\x9b\xcc\xdf,\xbcpy2\x0d7\x84n\x92\xc9\xe7M\x12\x9f\xfa\x9b\xa5\x17M\xd2\x04I\xe0\x06\xf5L\x1b\xaeK\xf07o\xc27\x9b\xd8\x0b\x97$[\xb1\x96B\x1a\x9d\x91\x0d\xb9\xa0\x1br\xbe\x89\x16\x9b\x84n\xf2\xc5\xc2\xdf$\x1e\xb2E\x9b\x15\x8f\xaf\xdc\xa4\x9b\x9cn\xceH\x9aFS\xe2oV^8\xf9\x1c\x9e\x92M\x98\x86\xcbl\x93Fgl]\xd2\x84\x92 %\x0c\x104\x99$\x8bM~\xb2\x88&\xfe&\xf5\xc2\x88a\x8c\x17N\x93x\xb1f\x0b7\xdb\x9cF\x19%\xe9fEB\xba\xf9\x92Gi9\xefl\x92\x93\x0d\xd7\xb3mh\xba\xde0\xaa\xe8\xfb\x9b\xcc;Y\xb3\xc5\x0f\x17d\xba!\x8b\xd9f\x9e\xa4t\x13\x9d\xc6d\xba\x89\xbe\"xB\x1aM6\xa8\xd3\xd9\xa0\xa9a\x93\x9fp\x97\x84M\xbe\"\xe9f\x1dO\xe6i\x12G_\xc9t\x83\xb1\xc4>\x83\xe8r\xb5`\x83\x9f\x93x3\x8f\xb2\xcd\xf7|L\xd1\xce\x06\x87\x11^\xf3z\x8a\xf6\xcc)E\xfb\x14\xab\xfc\xa2AB\xefGR\xbc\xdc\xf4\x86\x99\x06Pw\x06\xae_X\x8b\x8c1\xa6\xd6\xb7N\xf1\xadA\xcb[K\xc6\xd3z\xa7\x01\xc4\"\x83\xc9\x00K\xede\x84za\x00k[\x81\xe2&*H\xa1c\xc9\x84\x8e\\: .1\x19\n\x0fq[\xea\xb9A\x0d\xb1hMU\xdb(\x9a([0\x11\xa7\xc2\x9b\x8d{\x87\x95\x84\xbe$U\xa3\x81\x86\xb8H%\\\xa3\x08J\x80\xf6\xb5l\x12.\x9e\x86\x19\x1b\xd6\x93\xea\x9d\xe7b\x90\xad\xa0\x91\xeaG\x8f\xf6Sn\xe8\xf7n}\xea\x8f\xfe\xd5\xbf5\xfe\xee\xc6-&J4K\x7f\x92~\x16\xc6\x11\x8d\xbe\x92\x8f\xe9\xa2\xb5\x87H\xad_\xabz\xdb0a\xadW\x8b7\xd2\xc9\xd6\x8abp\xa6\xf6\xeck\x8f\xe0SB\x9fL\x18\x97\xcf\xb0%M\x16\x8b(>}G\xb2U\x12g\xed\xd0\xa8\x9dd\xa5\xc2\xbf\x1fe\x8a\xf6_Q\x87\xb0\xa51i\x0c\xaa\xc7\x9e\xfe\xcdR\xbf4\x8b\xe2\xa9\xd7\xaa\xac\x91Wq\xc2e4Li\xf6kD\xe7^o\xafW\xe8#U\x15*\x83\x89\xd7\x9b\xf0\xdd\xc3\xad\xf6\xff\xbe\xf4K,lz\xfe\x01\x98+X\x15\xaa\x1d\xaf'\xba\xe8\x89\xc4\x9b\x1a;\x89\xa1\x8d\x14\x9d\xe64\xe3\xd27\xe2\x17\xca7a\xea*\xb3\xa4\xc5\"O\xa2Y+\xc7\x9aM\x9bx2%d\xb5X\xbf\xa7i\xb4zI\xd65~\xcd\x927\xecZX\xaab\x99[\x94\x81:\xa7L=\xb6ut\xbb\xafZ51\x99N]K\xb7\xd9\xa8\xe4\x8f\xf1q\xb1\xcd\xd4&5\xef5e\xf8\xbf\x19\xb05d\xb1\x86\xa3\x91\xc6\xe4dVh\xe3\x98b\xee\xa1\x17a=D\xd4*\x8a\xc8mv\x87 5<\xa1\x0c\x15o\xe8\xd3V_\x9aU\x90\x91\x86\xec!\x15s\xb1\xa3F\x86\xa2\xdd\xa6\x94\xe2\x80^)\x0c\xb9A-\xeb\xcdp\xddp\xa6\x18\xad\x16\xb4m\xc1)\xb7Z\x94\xd5\x8dMn\xf5P%\xbeU7_n\xdf\xd3T\x94+\x98\x9d6\x83d\x91o\xb1\xd9\x84iM\x18L\xc4g\x1a\xd2\x1f\xa3\x03\xc6\x87\xa4p\xeapX#\xfe\x8da\x8d\x94\xde\x8chR3\xfdU\xdfc\x9bb\"\xfd \xee5\xfc\xfa\xa1\xc8\xbaq\xfbN=<\x05D\xee\x0d\xf4\xb0\xb83\xd0}\xba\x92-\x7f\xbf\xab{\xaa\x0f\x89\xaf\x16_e\x0f\xcf*\x07\x89\n-\xa3\x05\x19\xb3\x16\xf4\xa3\x18\xf5\xe3\x99\x17\x97\x0c\xb8N\xb7\x02\xaa'\x809:\xd7m\xa3\xc1\x01(\"A\x84A\x13\x11\x16Z5\xf2\\.hm\x8d\x95t\xf1<\xc0C\x9c\xe2\xa7Q\x93\x18p\xfe\xad\x9f%K\xd5s\xa2\x8d\xddd\xbd\xac\x95a\x8eb\xc6[\x8db\x8d\xdd\xeb\xb2\xbe%\x9a'\xdf[\x83\xdfc\xeb\xfe\x80\"\x10\xf01\x94\x02T\xef\x97p\x91\x13\x1e\xe8uB`A\xb2\x0c\xe8<\x8cA\xb4\xdck\x8e\xb1\xb9;\xfe0\xf8gv\x18\xd3#\xf3\x98NQ\xe5\x9e\x8aa\xf1\xc6\x9d\x86\xf5Y\xefI\xda~Z\xa0\xa4y\xeb_;\x07\x9f\xa6\xdb\xde\xa7>\xfb\xc7?\x90\xb6\x01EN\xad\x0d4\x04\xc1\xf8\xb8\x0c\xee\xc8\xe0\xfa\xdamt\x0e\x83\x8a!\xe2\x8d;\x0d\xeb\xb5\xceE\xd7mLx*\xd5\xf2+\xd4\xbc\n\xcd\x90\x9bE\x0b\xe24\xc0\x0f\x06\xbfb\xb71\xf6h\x9a\x13N\x1aD\xccR\xb8\xc8\xd4\x1b[\xbb\xca\xdf\x03\xc9\xca\x9bF}\xc2\xbbw\x1a\xf8S\xbd\x8f\xb4\xdb\xb8\xf9`5\n\x1f\xf3\xd8\xc4\xcb.C\xfb\xd9\xe4\xd3\xed68^\xb1\x9f}V\xb8\x0b[VZ6\xef4\xb2w:\xf7s\xb7QIqO\n\x1b}\x9a\xbcJ\xceI\xfa4\xcc\x88\xe7\x07\xb0u\xeb_\xa3\x7f{\xe3\x83\xd1\xee\xce\x83pg6\xfe\xf7\xfd\xcb\x9d\xe2\xef;\x0e\x7f\x0f\xf6.G\xfe\xe5\xd8\x890\xb0\x91;M\xf8\x8d\xd1\x0b\xdf\x9d\x98\x96\xbc\x89\x1b\x9d\xe7]8\x0d\xef\x951t\xa0\xfb\xf0:\x90\xfc\x0e#|f\x08xp\x1e\xdf\x16O\xebpzx\x81\x1e\xc9\xb6\xa5\x9d%\x8bEr\x0e+\xd1I\x0f\xb6u.\xec\xd53\xbc\x19\x9e\xd1:\xb2\xabr\xb67oV~\x9b\xb9Z\x13\xc7\x8b\xac\x1eR\x9e\x93d\xba\x16je\xae`\x8c\xe2\x1ew\x93\xc7_h\xc8:\xbeX.z\xc7\xd0\xf9LyS\xb0\x1e\x867\x17\xe5\x9b<\xc9\x85\xfe\xb5U\xf9\xda,I\x97!5\xbd8\xaf\x8cQ\xec\x00\xc3\xbb\xd3\xca(\xed\xef\x9e\x95\xef\n\xc4\xad\xa7\x1e\x01\x01G\xeet\x950\xa67\xb2f\xe6\\3\x91\xbdT\xcc\x0d\x01\xbf\x8c\xf4\xfd\x83Pe\xf4B\x99\xe0[\xbc_\x15\x9ay\x82\x97H\x16\xd306u\xackJot\x94MN\x92<\xa6&-:\xbbN0\x9c\x8fq$\xcal\xccl\x8d\xb9!\xd4eH&\xa1l\xcb\x8bx\xa6\".\x96X\x06r\xc1\xbe/\xb5i\x95\xcfw[\xbf\xc6\x94\xf1\x92\xf9\xeb\xfe\xf9\xa1\xc1\xc8\x0e\xd2\x00\xd7\xd0B,\xcc\x9e|V\xed\xaa\x9bdvhp\x08\x90\x17O\xef\xad\xd7\x11G6u\xac\xbc\x94\x80\xa7\xc8\x0fD\x7f\xc6/\xda\xed\xcf\xf2\x92\xb4\x88\x1b\xb8{H\xf7 ;\xde\xf88y\\bq\xf6\xe1\xf1\x80c\xe9\xf9\x81\xa1\xfc8h\xf5\xb9 \xb6\xe3\x13F\xd2\xd7\x01\x9c\x16\xb5#0\xb5\xfd\xfb\x00\x0e\xc75\xe1\xd5:\xf6R\xdf\xa4}E\xa7\xe6\x07\xb1\xd4 \xf2\xcfe\xf9 9\xf7w\x82\xd6\xc3,\"\x8b)D\x19\xe6\x0fY\xa5\xc9Y4\xc5\x13@G\xb1e\xa3g\xb6\xc1\xb2\x89\x7f\x85!<\xf3\xa2\x00\xce,N _\xd1\xc4\xc1\xc7\xf3\xd5\xd5\xd9\x00\xc4\x10\xe6\xe5\xd6\x99\xb7\x8d\xe69\x0c\xe1\x0d\x1b\xcd\xdc2\x9a\xe7\xcah\x9ew\x1d\xcd\xb4m\x08\x1fa\x08\xaf\xd8\x10\xea\xa5E\xd4\xeb\xa32\x84\x8f]\x87\x10\x96\x00 \xdbF\xf3\x03\x0c\xe1-\x1bMh\x19\xcd\x0f\xcah~\xe8:\x9aY9\x9aY\xdbh\xbe\xc0\x10\xfe`\xa3\x99YF\xf3E\x19\xcd\x97\xae\xa3\xa9\x1e\x89m\xe3\xf9\xdd\xe2\xb7$/\xe4n\xbc\xdfQC\x1eR\xb2C\x99\x1c\x85\xcd\xaf\xe0\x00~\xf6P\x85\xd6\xcb\x99\xb0Q\xdc}\xc7\xef>\xe5D\xd4\xcc\x17\xc9K\xcc\xf6w\x93\x1bKIf\xab\x07[\xdb\xfc~\x85!|\xf0\"\x0b\xb0qv\xbfv\x18\xe3\xaf\xedc\xac\x1c\x9emC\xfc\x05\x86\xf0\xb9}\x88\xbft\x18\xe2/\xedC\xac\x9e\xd0mc| C8j\x1f\xe3\xcb\x0ec|\xd9>F\x95\xc1j\x1b\xe1\x8b\x96\xa1\x1d#\xf3S\xb0a.\x03}!y\xd6\xa3\xd8\x1b\xf5\"J\x96Y/\x00\xceg\x8f\xfd\x00\xa2\xa6\xa1\xbb\xcd\xd7\x03\x14\xc1\xaam\xdb\xb1\xab\x82I/\xd0I\x82!\x0b\x06\xabV\x97P><\x12\x0fU*\xf0\x02\x190\xf6\xf4)\x13*\x03ap\xe7\xeb`\x1f,\xbb\xa2xJ.\xf6\xa1\xc5g\x90]$M\x93t_\x13/\xa7^\x97\x96x\xb0v\x9cP\x18\xe46\x94\xb8\x01Cx\xdd\x8e\xb47\\pA\x00\xeb\x86+56\xda\xbd5\xfe+\xcdl\nvNI:\x1a}\xbb\xbb\xb1\xc6\xd2 \xc2/\xa8\xab\xd8\xdf0h\xe9\"\xa0\x19\xbco],\x17BwE\x8c\xf2]\xc4\xbd\xae.\x96\x0b\xdc\xb6\xf8\x17\x166\xb2\xad9\xd7\xf3\xb0o\x98\x94/\xbe\xfd\xf7e\xc0\xbe\xbfq#%3\xd5\x1d`\xbdBO\x18\xda\xc7}\xcd\xff\x14%WD\xb9'\xda\x0f\xa7S\xf4M\x0c\x17?\x97O\x0e\xe0o\x8f\x0eX\xe3g$\xcd\xa2$\x1e\xf6\x06\xfd\xdd\x1e\x90x\x92L\xa3\xf8t\xd8\xfb\xf8\xe1\xf9\xce\xfd\xde\xc1\xe3O\xb1pl\x87\xdf^\xbf\x02r\x81K\x0c\x13\x9e\xe2\xf7\x84\xc0)\x89I\x1aR2\x05\x1e\xa4\xf47\xa3\xff\x93\xbc\xa4!LL\xa7\x8f\xa9\xb1\xbd[\x9f\xde\x7f\xf7\xe9\x96\xf7\xe9\xfd\xb6\x7f\xe3\x96\x05\xd9K \xc2\x10\xa2\xd1\xa0\x19\x8c\x08F\xc6B1\x16\x9eJK\xed\xf4)\xea\xcb~{\xfd\xea\x90\xcf\x8d;\x93\xb8\xf8\x80\xb0\x89$\xc2\xc3\xa8l\x8fo\x82\xe7i\xb2\xe4\x1bA\xb4\xd7\x9c\x91T\x8a\x99$\xbb\xa4M\xb2K\xb0\xbcm\xcd\x13&)=a`_\xc9y\x06Pxi\xaaYP\xac\x8e_g\xa2\x0eI=\xa9\x92\xbc\xd8\x12\x94\xe2\xfc\"\x99\x84\xac\xa9~\x86\x8d\x1b\xf4K\xa5\xde\xd2\xb4\xb5z\xa8\xa47\xee\x11y\xf0\x90~\x96\x9fd4\xf5\x06\xbe\xac\x17tS\xa7\x8d\x01\xd5C=\x85(\x86\xd8\x87\xb8^>%\xe5\x8e\x8a\x18g8J\xc7\xb2\xc5!&[\x1bM\xc9$\x99\x92\x8f\xef\x8e\x8a,]^:\xda\x1d\xfbc,\xdd;@u\xa1\xf6\x9d\xc1\x98\xdbU{.\xf8$\xb7us\xcd\x9a\xd9l\xec\xb4\xd5h\x15_\x86+\x07\x7f6\xf19\x12\x83\xea\x8c\x88\x0f\xdb\xd0\x1b\xa2\xb6\xb6\xf9\xb4\x9a\x99T^\x97~\xff\x8f$\x8aqy\x9aS\x13\x19{\xec\x83\x92\xf3\xa9d\xdd\xa0\"n\x17K\xd5yD1W\x04\xd0\xcb\xe9l\xe7~\xcf\xf7\xcb\xbb\xbd\x930#\xf7\xee\xe8\xc6Pf\x10jv\x9d`\xb8Y\x94\xc4\xd9{|\xcb\xe4\xb5\x13.V\xf3\xb0%\x97\xacz\x154\\j\x13\xe7=\x1f\xb7\xd0\x02S\xc1\x85)\xf1\x88\xfa\xccpd\xeb7\xe6\x92\xd0y2\xbd\xf2h\xf8\xe7\xa6\xf1\xc8\xa7\xceLDs\x8c4<\xfd\xb3\xc0Y\x1b\xb2\xf3 5\x98Y\xcb4\xe5\xc6\xce\xe8\x9cT\x94\x8c\xeeQ\x0cF\xbd\x91\xf4\xe6\xa5F\x0f\x11\x85m\xe1\xa5oz\xe5\xdf\xa2\xcc\xd1(\x0e\xd8\x06\x0dt\xfb3\xf5K\x9f\xfa\xff\xd9\xdb\xbdu\x1a@o\xbb\xe7\x8f\xc5\xfe\xd4-\xa9\x91J\x11\xdb\xa6\xd6d\xee\xaa\xac\xa4\xc1\xb1\xa6P\x9a1\xc25- W\xac8\xe5\xb4\xb9\x8ct\xf2\x18\xa9\x8e\xbc\ns\xa9\x143\xa4's\"\xc0:\x8f[d\xcaT:&\xcc\xd9\x98\xd4(\x8d\x96\x9e\xb2H\x9f2\\\xa3c\xb4\xd8\xf4z\xb6\xe1\x1a\x92\xab9\x0d\x93\xc1\xec\xb8\x84\xd9\xd7\xa6{Y\xa0I\xe7\xe6\xd44m\xe6\x9b\xb0\xecd\xf1\xd1\xad\x7f]\xec\x14\xccu\xeb\xb2\x05\xc6\x14t\x7f\xe6\x08\x85\xfdgS\xd8\x976\x85\xf5h#\xecb\x1ba\xf5r\x9f\xca\xff)\x1f\xf0\x94\xdfl\xa7x\xf7\xee\xfb\xfd\x1f\xf2\xd9\x8c\x08\x7fq[\xf5\xa3\xb3\"sSq\xf2\x95x\xa2\xa6\x19\xacX\x8c\xc0%S|o\xc49U\xfe\xe9\x18\x91:nT\x8cr\xca\x06\x89\x94\xae\x1cWjcD\xf59\x0eAaO\xf9T\x94d\xbc\x8bhBL^\x97\xc4\xb8\xbc<\xa4\xaa\x9aL[\xe4K\xe4\x14@-1\xe1c)+S.\xd9zZr\xfdP\xecx\x99\x97\xbe\xaf/\x9b%\xb9\xf4-\xa6\xd6\x16\xc3\xb2\xc5\x17\xae-F\xd6\x16\xb3\xb2\xc5\x1b\xae-&\xed\xb3\xbey\x13\xb6&e\xd3?\xba6\xadI-\xaf4\xbd\xe5mQ.\x87\x8f\x16c\xb7\x06C\xd7\x06\xeb\x898L\x0df\xae\x0d\xce\x1d\x1b\x9c\xb4\xaf\xf8f\x83\xdd:57s\x1d\xdf\xb41>\xf5\x17\xf1R^\x83\x85x\x91\xfc#\xe1\x7f\xc4\x8a3+\xcf\xd5\xcd\xee\xbc$kL\xcf\x17\x8a\x17\xe2)\xb9\xc0\x1b\x19\xbf\xf1$\xcb\x92I\x84\x99!\x00s\xb8\xc4e\x00\x1c`x~\xdc\x97m\xb0\xae\xfbe\x0bl\x00\xfd\xf7\x04k84\xe9\x07\xa6\x19\xf8\xfb\xdf\x8f\x8f\x8f^\xbf\xfe\xf8\xe1\xc9\x0f\xaf\x0e\x8f\x8f>\x1c\xbe\xc3?\x8e\xff\xfew\x8dji\xd5\xfc\xe2\xe5\xe1\xef\x87\xcf\x0c\xaf\xcf5\x1d\xbcyv\xf8\x9b\xf1\x83i\xf3\x83\xb7\xef\x9e\x1d\xbe3~p\x06C\xb8\xdb\xbc\xbd\x86!\x0c\xe0\xd1#]\xb5\xf3S\x18\xc2\x1av@\x93\xaa\x7fi\x90\xf7\x8f\xed5\xae\xf7\xeb\x89$A\xcf\xf9\x9f\\\xa5\x19\x13-?o9\xd8\xb9q\x18\x0b\xbb;\x92\xe4\x0b}\x8bT\x1c\x0dE\x83\xbbn\xdb\xe9=O*\xaf\x7fxh9\x89D\x84\x9bF\xaf^\xa9\x0e%\x0bH{\x98x\\\xa88w\xb0JH*r\x9e\xcb\x94\x05<\xd3\xc6\xeeCLw\x11?\x84h{\xdb\x87t\x14\xf1$\x89\x11\x13\xe8\xcd\xee\xf5\xa9\xd3l\xed\x01\x0d\xaa;:\x06\xa2\n\x98f<\\\x82\xf6\x8f\x8fy\xe9|\xe2\xfd\xc1OW\xf6\xc4\xa9\xe3\xb7\xd6Tb\x85\xf5A)\xe9a\x13\xc1P\xb9\x04\x8f\x1f?6\x995\x84\x92j\x1bb\x11C\xbd\xd9\xc0\x9d\xbd\x07w\x1e\xdc\xfb~\xef\xc1]\x9ca\x19\x99\xf8&|\xa3o\x85MZ\x93\x92\xcf\x04>\"\xcax#\x90\xb7Q\xf1\xe1\x06\x9c?l\xc5\xf2\xeb\xf9\x9c\x0dm|v\x90\xda<\x19jP\x16\x9d\xde\x92Q\x91\x14\x1e\x0da'\xae\x14,\x1cJ\xd0\xd5_&\xf0xXW\xc0\x9a\x06v\xd4\x96\xbd\xf1\x83\x18\xb9\xe3\x86}\xed\xda^\xbd\xaa\x8f\xa1\xbd\x0f\x0e\x80\xab\xc5i\xc4\x986\x97/\xb6\xba\xbf l\x03\x1a\xc5j\xb1\xb4\x8cC\x92\xe5\xe2\x99\xbc`\xac\xde\n\x02\xbf\x9f6\xabT\x83pd\xd6\x9c\x07\xef`\x08{\xcd\xdbo\x9c\xb3\xb6\xf3M\x9d\xa4\xcd6^\xf1\x93N\xbe\xa09\xda\x9e\xc1\x10\xde0\x1cye:\x02\xbe\x1a\x08\xf6<\xca0\xbb\x8833\xfe\\\xae\x94!\x99\xa7\xb4Z\x94\x0b\xc5\xb6\xe0\xa0\xb2l#\xf6\xbd\x85\x8a\xc2\x01\xa4\xc5\x19\x12\x89\xb2\xc0\xd6\xd3\xd0\xe0\x078Mb\xd3\x89\xebH\xab?\xda\xa8\x82uH\x1c\xfd\xac\xe3j\xad\xdcc\x18\xd4\x0fv\xees\xebWW6\xf6\x8b\x9d1\x00S\xd5h\x8a8\xe3\xd4\xc5\xefv5\xe0\xaf\xda\xf4\x1d\x05-\xe7Un\xb5\xc5\x96\xf5\xdd\xfdj\xef\x8e3(o\x90\xd6\x8e\xde`\xedR:ze\xcaM\xa4\x9d\xbb\x92\xb7\xdaiD\xbf8\xc0X\x13\xcc,\xb8\x14\xa7.^Z\xbb(\x92\x01\xa8G\x8e\xdc\x8e \xcf\x95-\x85\xe8>M0]\x83\xb5\x80\xb5\xbc$P\xd1y\xbd\x12\x167\xac\xd5\xe6!\xe7@\xa85\xc3\xfb\x96\xa9^\xd8\xe1\xc5\n3\xd3q\x06\x0d\x92\x14\")\x15 5K2\xe3[.\x0b\xd8\xd3\xcf(\xdd\xf0G\xfb\xe8.o\xeaV\xbb\x8a\xecj\xa6\x083\xc0\xfd\xc5\xb7\xc1\xbdO\x13\x94\xc5$\xc4\xc5\"\x84\xcd\xb5\xa0\x98\x9f\xfd0\xa6\xe9\xbax\x99\xba\x8e\xf2\xc6\xb7\x8dR30\xa2\x0e\x84\x8dSH\x91\xf2V\xe8<\xb6\x1f\xadc\xf3\xbe}pr4h\xe0\"\x14\xef\xd7F\xa6\xfe\xfa\xaa\xa8\xaa\xa8&\x1f\x81e\xb0\xbd\xd1\x918\xa0\xc75\x05t\x00_\xfb/\x0f\x7f\x7f\x0fCx\xca\xfe\xfe\xe5\xc9\xab\x8f\x87\xec\xd7\xcf\xec\xd7\xe1\x9b\x0f\xef\x8e\xf0\xe7\xbb\xa0\xd2\x7f\x14g+\x9e\xed\xbc6\xaa$O\xab\x99\xb9m\xf4\x85\x1d\xf0\xe6\xdc\x0bJ\xcb\xa3g\xe3\x0em\xd6\x1b\"\xdeK\xae\xb7x\xd9Of\x8e\xed\xbc\xf4\n'\x92\xc6\xc0^V\xa7L\xbe8\xb6\xa9\x1b\xdb\xcb\xab/*\x82\xef\xf8\xb84\x8e\xb2\x91\xfc\xbb\x17@\xef\xb2i\xcfQ\xfb\x99\x84\x939yG\xb2\x962\xc7JW[\xbc/\xfc\x10d\xc5\xafB\xd6\xfb\x18\xe3\x83)\x17\x06\x957\x87\xfc\xc5\x12\xeb\xcb\x8a\x0f\xa2\xfc\x99\x14\x1c\xcb\x8f\xc4\xd9\"^\xb0M\xa3\xe8\xdf%\x86HLdB\xcb\x82d\xbc\x02\xa8K\x0f\x89S\x00\xbe\xe8b\xd6\xda\x05\xf1^\x04\xf0\xd2\x0f\xe0Ee\xf1%\xbdu\\\x13=\xa6\xdf\xe0-\xdfp\xc7\xf4\x1b\x16L\xbfQ\x19`II\x1d\x9b\xd6\x0d\xf1\xc65#\xfc\x88!\xfc\xb8\x89\xf07\xae\x19S\xea\xb5\xdd\xf5=|\x13\xa64\xbb \xde\x8f|=\x7ft_\xcf\x1f-\xeb\xf9c\x8dr\xd1o[\xcb\x97\xfd(\xe3-D\x94\xfd\x92\xda[\x86\xdeB]\xcb\xc6\xaf(ro4\xb5\xb7?\x05\xf0\xcf\x00~\x0b\xe0\x1fM\xa5\xe9\xfb\xc3\x7f\xa0\xc2\xd4$9Rj\x11\x1d\x8fCQ+\x83\xd6\x88M\x17\xf6\x95\x18z\x90\xfc\xa50.}&\xebL\xcbC\xf2\x91$\xb26\x88\x1c\xca\xf1gQ\x0b\xab:4\xd2eh\xb1u\xf2Q\xa9\x9f7\xcc\x9f{\x16:+\xe8\xd2\xf6\xee\x84\xe1,\xa8\xdd{*\x0e\x83zm\x1fCG\x91\xa1#y\x16\x95\x06\x8c\x7f8\x1aX\x90\x1b36\xf8\x13k\xcd\xfbI\xe8Z)\xf5F\xe3Ff\x16}\xbby\x0brh\xd2\xe0\x88.\xa8\xdf\xe4\x9a\xbf\x94o\xa4\xfa7~(\xdf\x88\xf5oh\xa5\x9c\x83R\xc8)TOf\xcf\xbe\xabK:\xa3\xcf\x01\x9c\x8dAd\x8a\xed \xf1t\x92Y\xc3\x16\xa0gza\xee\xdb\xa7\xc7\x05\xb9k\x9aEfG\xf2_j\xd8\xa2A\x0f\x0d>\x14\xab\xeb4\x04v\xc29\xa9\xcb\xa8`\xcd\xf4@\x8dL\"xa\xe5H\xd8\x01QZ6\x06\x01\x864\xef>\x84\x1c\x1e\x0d!y\x08\xf9\xf6\xb6\xa9\x11\x10\xe3\x08\xd1S8f\xa2\x15\xec@\xced+\x83\x7f\x15\xc8\xc5\xe6z=\xe2\x85\xa3\xc18@\xc5]8\xda\x1d\xb3/\x03P\x02\xdas\xd8\x86\xa6\x12\x0e\x1a\xe2\x97\xbc\xe4g\x8d\x87\x96\x04s\x0dV\x99g\x83tZ\xa6\xd9\x9f\xbcL\xda\x152B\x96\xaf\x9c\x0d0\x0c\x1b\xbfzV\x96B^\xd2\xf9\xc3}a%\xf0\xb7\xb7\xe11:W\x9b\x1b\x077u\xa7\xbc\x8cjOy]\xc2>\xc7\xcc\xb9P\x1f\xa9i8s\xfbp\xa4E\xbe\xe2w5\x94r}\x8e\xf4z\xa8\xe9\x93j\xbe,\x03\xb8\x05\xbb\x85?\x8b\xf0{\xf1\x03\x89\xce\xf2C\xdb\xc1\xf6\xcfbh\xff\xd4#\xce?\x85\xcd\xa0e\xab\x99\xa0u\xda\x02-\xaa\xaa \xb8\x8a\xc0\xd1WhIm\xceB\xfa\xa5X\xd6\x96BiC\xbf\x1a\xa7\xd4\x13\xaeV\x01\xf4\x9e\xf2(\xde\x8c\x92\x15\x84\xf0.\x8cO \x9c\xaca\x17\x83\x1eAX'w\x83\xea*\xc9\xba#\xb8V~\xa0$\x01\xe0\x9eo\xa2\x1a#.ax\x92\xa1\xeb!\x81G\x82cco\xef\xc4\xd2\x84s\x8c\xc5\"T\xbd\x1f\x89\xa7\x8aj\xf3\x18\x87\x86\x83U\xb1FE\x0f\xfc{B\xa2\x85\xe7\x11\xd8a\x04\xf8\x16\xc4L\xb4\xf2\x99l\xde\x0dw~+`\xf9\x9b\x1ew~\xfb6\xdc9\xd6\xeb\x129\xbe(*\xa5'\xa2\xfaa\xdd2ah\xf6\x84\xda\xdcL\xcf\xadO/\xc4S\xf5\xa1b\xc6\x1a\xfdc,\n\x01\x11\x8f\xd2\x00n\xb0\x95S\xe3\x1eN\x89SIW\xc9\xb5\xb3U`\xe4\x91\xdb\xb4KM\xfb\xe8\xad4g\xf8c]\x05\xf3J\x9f\x9dL2\x15\x7fY\xa5G\xe1![Q-\x95\x1e\xb2CH\xb9\x8b\xac\x11W\x84\x8a\x88z\xf1\x88Q\xae\x14v\xd0\xa3+\x1a\xa3\xf0\xc7:*wf\xc4P\xd1H\xb5\x1bu\x1d\xb4\x93u\xb3\x0e\xe9&\xaa\x9dBc\xf2\xfa\x89\xea56\xdd\xb45\x05\x10\x1e\xa3\xfa\xc3\xc6\x819i\\\xac\xda\x16\xaei\xa1\\\x02/Wf{\x9b\xad\xcd\xf6\xb6C\x14 CuB\x03x\xc1\xe8\xd6\xd5Q\xbd\xee\xe5\xaaC}\xae\x1f\x1eQ-\xcaW\xfa\x9e\x87\xee\xf1lJ\xd3\xf5(wM}\xa2\xeb\xdcX\xbcS\xbe\xb3JSU \xd8ju\xa7%|\xa7%l\xa7E\x0f!1+q\xcfDY\xbc\x14\x173\x82\x1dH`\x1f\x12\x83\x9e\xaf\xb63\xf31V!\xae\xee\xc6D\xab\xb45\n\xa3\xcd\x14\n\xd7\xb5=\x05\xb8\x8c\xfbS\x01\xa1qw\xa6\xad{8\xb9\x8e=\xdcm\x15$\xe4P\xd3\x1a\xfdu{>g{>w\xdb\xe3\xca\"\x8e\xa6\xe5!\x17\x8bC.\xd6\xee\x8b\xc2[\xc5a\xad\x19*\x96\x121\xaeeEhR\x84\x0c\x03\xf7,\xb1\xe5w\xafj\x96\xb5\xd4\xb02\xe8$\xbex\xb1A\x06-vq\xf4\x10\xb6\xbc\x08O\x05\xb5*#(\xb9\xbc\xbdHT]\x84t{[\xec*]\xfdR1\xe5F\x8e -LK}\xf5\xb5\x025I;C\xd5\xa0\xce\xf9\xa2j\x89\xf9v\xf9hh\xd6\xb0\x02\xdd\xb7\x1aQ\xd6\xa1E\xcb\x81\x8b\xc4\x9d\xd1q\x0f\xe0\xd2\x08\x15\x9e\xd3F\xf0R\x81\xf2\xe9\x7f\x01\xcaW\xea\xc8\x17$\xb0\x08!\xe0\xb6\xaa\xa6\x83\x80z\xa0\x14\xc6\xa8\x87\x0e\xcc[4J\xc6\x01#T\x8dC\xc206\xb6KbEK\xc4w\x89\xb1\xf2\xbc\xa4\x9b\xb1M\x9b\x84&\xb6Q2\xe6\xe1\x90\xc5\xd8\xf2\xea\xc0NR\x12~n.\xa8 \xdb\x1a\xc7\x96vy\xffc\xbb\xaf\xb6\xb0F\x82\xa6[l=\x10\xafc\xef\xe1J\xc0\xe3\xf2XmS\x18\xb6oT\x90p\xe3En\x8b\x8dkQ,\xf2\xa0<\xb1\x87\xb5\xafY\xad\xcb\x92\xfdMG\xee\x0c\xefZ\xd0\x805\xbd\xba\x8b]M\xd0\x86\x03\xe8\xbd#+\x12R\x18\x8d{\xb0_\xfe\xe2^\x10\x8aZh\x1bz\xe5=\xfc\x96\xdd\xa1\xd1\x92d\xd0t:^_\x9d)\xd71\xe1|\x08\x1a\x06\xbc\xd2\x8f\xac\xf4\xe3\xca\x85O\xa9\xaa\xf8jFe\xd5\x9a\xc7\x94\x05.\x13\xa9\xec\x1f\x06*#\xca+1{|\xaa\"U\xd2\xba6\xb2\xd7\xa2\xba\xe4\x0e\x0f\xa6\xab3\n\xf5\x91\xa6\xe4\x8c\xa4Y\x177\xed\x16\xb8N\xc9\xc5\xdb\xd9\xd5\xc1\n\x07\xa81\xdc\x19X\xbbY\x84\x19=\xba\x86\xaeJ\x0cm\xed\xf2\xea\xc2\xd4\xeeC\x88\xe1\x91\xb2\xc4\x10;i\"*\xc3\x8d\xeb'ZlUB\xc4Ns\xe9.\xe5tbU\xbb\x11k\xc9f\xc2#\x88%\xc5)Y\xa0X@\xc27\xd6\xd9\x83\xeb\x12?\x1c(l\x05\x9a\xc2H\xe9\x88\x87\xb4\xaaz\x87\x83&f*S=k\xda\xfb\x19}_\n\xfa\xbe\xbcf\xfa\x8e*cI\xde\xf9\x0f\x85\xbas\xed\xee6\xf4\xfa\xfd~y\x97\xc4S\xd8\x06O\x08\x15\xf3B\xcd{\x00=8YW>'+\xcc{\x84I\xe74'\xc1\xf2zO\x029\xdcR\x17 \xdfU\x87\xd28#\x96W:#$\xe7\xe0Q\xd8Q\xfb\xf6\xe1\x96\xd2\x9fq\x7f`\x80\xf4.7\xc8+d\x82\xdf`k\x84:\xf1\xd9\"\xd1\xd8\x1ejCv>wj\x87J\xd1\xa9r\xb8\xa0K\x01\x9e!\xe5\xd3\x80\xdb\n\xf0\x8c)\xef\xfa\xf0hX\xf8\x96.\xa9\xb7\x1b\xc0\xae/\x8e\xa7\xa5@\xeeSB=\xd5* M\x06\xec>\xd1\xdcG\x905\xcf\xae\xe5U\x0e\x9b\xb3\"\xaa\xb2\xb2B\x0d\x85/\x18\x031.\xc3\x1c\xd4r\x07V\x87\x03\xe1Z\x89N\x96\xece\xeeSa\x19((x\xba\x0b\x1b\x93s\x14\x1e\xa1qY\x8d\xd3\x8b\xe1_C5G\xd1w@\xfd\x87\x0c1\x94\x9b\x0f}\xc0\xd7(\xdcR\xdf\xb5\x12\xdcC\xea9\xa5J\x8f\xea%]\x145b\x99\x9a\xffg\xaax\x99\xeb1\x0d\x94UxEG\xd4\x9e(\xb7\xea\xb1\xf2\x96ao\x00o8\xac\xdf\x89\x9c\x19\x14\xd3\xe1\xc0+\x9e\xe8\x1c\x9f3*\x8e\x8d\xb3\x83\xef*Y\x16`\x9fw\xd6 \xc7\xe7a6\x7f\x9aLU\xc8\xc8[:\xe5bT\xaf\nV~\xe8\x08B3\xe3\xf9\x9a\xd6\\M\x11~G\xdccM\xadPji\xa3\xfe5\x1d=\xa5c\xa7/\xb7>\x1b\xc7\x0d\xa6\xc6\xfb\xa2\xea\xc1\xfa(;\x8c\xf3\xa5\x08\xc0Bw8\xdd\x13\xa7\xb1\x98:k\x07\xaf\xfa\xb5p\x98\x8c\x93)\xf9\xb0^\x11@\xd2\x9e\x9dG\xbc\xfeYq\xbf\xad)vM\xc2\x8c\xc0`\xbf\xf5=Ph\x7f?\x8f\xa3/99zf\x9e\xa3\xbc\xb0\xf9\x07\x1d\x9b\x9f&\x13\x0c\x18>\\\x10\xf6\x0f\x9fl\xedf1\x06k\xd3z\xa56\x88-\xa5\xac\x96\xf6=\xfd\xd7l\xb9\xb6\xb7?\xd0@=\xfan\xc2\x07\xbe\xf7?\xe0\xde\xb7\x84\x88\xbc\xa6>\xc3\xfa\x8c\x18=\x1c\xc1\xc1\xd1\xb5\x8aB\x7f\xc8\xfa\xc8C\xfc\x81.\xcfu\x8f\xc1\xde\x9b$\xde!<\x95q\x19H\x98A\x98\x12,\xfa\x86\xd9\xb5\xc9\x14\xc2\x0c>\x93u\xd67\xd5=\x90\xdd\xb3\x0d%\xa2\x8dy9\x89\xd2#$\x80\xa7\xd4\x14W\"/R\xec\x9b}\xd8\xb2\x04x\xb1k\x92\xc4\xb3\xe84w|\xfb<\x8d\xa8\xdb\x9b\x82O\xd7/>\x80\xb9\xa4\x1e\xa8\xe5\x0d+N\xf5\xddH\x86`\x93\x95H\x12\x85\x83\xd7}\xe0\x1b\x1b\xb2\xab\xdb\xd4K\x95\xb5\xdd{\xee\x87\xab\xd5b-\xd8xCD\xbfz]\x06\x162\xc9\xce\xc0\x16\xc8\xb6\x13\xc1\x8aSzI\xf2\x1ax\xff1F\x08\xd1\x042B!\x84\x98\xed\x83\x12rr\x8c\x90\xc4bOXQ\x9f]T\xce\xc1<\xfb\x0e\xf4\xc4z\xeaw:\xed\xa5\xf2\xb5 k\x8caP2\xdah\xf3\x01\xd4\xa0\xc5\xcb)\xb3&y\xfddT\x93\x96\xa5y\x18\xf7@\xa6}G/\xd2\xb7\x06\xde\xbeP\xc7\x10\xce(\xa9\x16\niiG\x03\x05\xbep{\x00\xdf\xf1T\x85\xfd\xc9\x829\xf3Ld\x15\x16\xd6\x97)\xdc\xbdu\x9d\x11\xfcW6_r\x85\xa7\x92\x01\xeau\xb82\xa6<\xfb\xfa\x8d\x96\xc5\xe34IJ\xcd,\xfb\x81\xa2s\x11K\xc3\xf36\xf9:\x93b\xa5\xeb\xacS\xd7\xffP\x93B\xd9\xe7\x94\x11z\x14wh\x1a'\x92\xaf\xa6!%G\xf8\xf22h?c\xcd\xdc\x92}p)Y&g\xed\x92\xb6f\xd6K{\xc3S\xb2 l\x02\xaeM7f\xed:\xe5e\xd7)\xf3N\xea\x0bbO\x1c\xcdE\xc8F\x89\xcb\x03\xe1\n\xe2K\xe3L1\x81\x11\x1d\x8bF\x1d\xc6\xd2D\x0f\xc3h0\xd8\x15\x9d\"E,&Gq\x8b\x8flA\xa2]\x12I\x9c\x898P.\x80-\xcd:\xd1\xbc\xd5\x17\x8f\x91\xbb\\\xf8\xe1\x99\x89\xe2\x99H\x19\x93`\xf0Hk\xc5\xd8\x0c\x86\x10y\xb6\xb2\xdcb\xb92\xbe\\\xc2Y\xb7\x19C\x06F\xa9\xe3\x94z \x03\xb2\xc8\x1b\x9c\x11\x1a@/\x8ay\xb5\xfb\xcfd\xfd3V\x883Cf\x82%\x80-\x1e\xa8\xec\xa5\x99\x98\xf2\x92M\x19\xa9\xd5\x84\xed'\xf3\x07X\xa0\xd4\x9b\x95\x0bhU\x94r\xd6e&f\xcf\x7f-\xd9/\xb1\xdb\xbd \xc3W/)y\x19\xe2\xe3\xd91 `\xa1\xe1\x01\xc4\x9e\x8fc\xd4\xe9\x1a\"\x1eE\xdfi\xd1\x9b\xe0\x9a\xea\x96\xd9\xfa\x0e\x98,Hh-J\xa44\xdet\x8b\xa1\xdc\x1fB\x1c8\xc9yL\xd2\xa3gp BaE\x0c\xe3n\xa0\x9e\x14CQ\xb4S|\x83\xc1\xfb\xc3\xf2\xac\xe0w\xc3\x05\x15\xf5N\xb6\xc4M_pw\xd6\xc9,Iz\xda\xaat\x90\x90\"\x02\xae\xb2ks>\xc0f\x1f\xbfF\xd5\x92c\xb6\xf3\xa4\xe8\x08\xfd\x97\xea|\xd2\xa0\xe9\xc8\xd1\xec\xaeJ\xa0\xec\x86pM\x0fFl\xa9\xd2L\x12 \x84\x03\x07\xad\xaf\xf8\xde \xf0\xf3e8\x90\x7fI\x1d\x0d\x12\xd5}\x88Gj4^\xb3\xa8m\xcb\xf1\x81M>#\x18,\xdbi\x9d#\xd2m\x8dY\x1fN\xeb|%\xd0\x17\xc3J\x88\x87b\x85\xe3\x88\xfe7\xa2\x02\xae\xd6\x81\xfa\xebzQ\"KR\xea\xca\xe7\x1c\x11\xef\x17R\x98\xfd\xdb\xdb\xfda\xdd\x81uT\x1b'\xed\xedWd\xa0\xd6 \x14\xb2\x16[\xa90{\xcdu\x11:\x06@.)\"\x16\xe9\x9f\x87\xd9\x13NO=\x1f\x8f\xa1\xe3c\x12gyJ\xde2z\xedU\x89\xb7d\xa5\xac\x03/zw\xdc\x83\x8d\xf3\xa1zn\xa8\xa3a\xa2\xd8{;\xd8\xc2\xecHjb\xba\xf5\xaf\xf6\xd3\xb22\x05\xc8\xba\xf5 \xce-k\xdb\xdd\x1c\x9c\xa4F\x84\x9c\xc3\x0dw\x99\xa7\x93\x17\xda\xb7:1+\x87{\xe1m\x83r`3\xb3H\x0b\x11\xe1\xc1v\x1e\xc1\x043\x043\xca\xe8l\xee\x01/\xfb\xd4\x02\x01e\xb5[\xf7\x96\x9cI\xc9\xe0\xe8\xb0\x15\x0e\xe0\x9f\xb4dmT\xb6&(\xf3: K\x83\x1c^\xad!%\xf7\x83\xca\xe0\x0c\x04\x83\xa3\x99N\x941\xc9}\x08\xcf5\x9eC\x1fi\x00?\xd0f2\xe0\xd7O~6TO\xfb\xc2\xdeV\x81dR\x0f\xfenN\xfc\x81\xc3oNH$*j\x18\x1f\x8c5>\xac @\x0c\x9d\x9cDt\x89\xe0\x90\x90\x8f\x13\xee\x82\x1c;\xf5\xf9\xcbU\xfa\x9c$yL\xaf\xdc\xe5\xcb\xabt\xf9\x99\xac\x7f\xe4L1i@\xd7\xad\xdb\x17\xd7\xd7\xed\xda\xb9\xd3\x1b\xed\x9d\x1eS^j\xb4\xdc9E\x84M\\\xfa6\x87\x93\xcf\xc8\xbc\x14\x14\xe5'\xea\x89_n\xda\xd0\x1f[S<\xf2\nH\xa6}\xac\x0b\x025!\x0f\xad\xa9,$fGAA}\x10u\xa9FM\xd1\xd4Q\xf8X\xe4\x0c9\x84\x08w\x9bN_a\xc0G\x11%^\xe8\x97\xf8\x82\x06\x10Zy\x15&Qq\x89\xcd\xd3~\xba\xcf\x10Q\xac'e\xfc\xc8\x85\x17\xfa\x01\\x\x0cU\x18\xc4_\xc8\x1c\xae#\xf6\x99k:wB\xec;\xbeVy6\xf74\x9eEF\xf2\x92K\xa0En@\x8e\xac@.v=zm\x95j\x95\x9b7\x01\xb3\xb0V\xd4+<'c\x91\xd8\x97o\x7f7\xce<\xb1\xef\xeeR\x9433\x15\x002\\\x0cu\xf8Ue\x1a\x8e\xb7\x92\x8c\xba\xf2\x9c\xab\x84\xcc\x9ax<\xb9\x8a\xce\xadjx\x9e\x8d2\xf2\x85\x1e>jY9\x13@r\x97e\xe1\xdb\x1c-Cq\x7f\x16\xb1\x93\xc1\x01\xfd\x8a\x8f\xcb\xc4\xb9\xcdA\xfa\xbeb\xedb\x07\xb2\x9af\x17\xe9jy\x8am\x18\xa9\xc0\x94\x87\xca7W7\xb5\xa7\"\x1a\xaa\xf8\xc4\xb6\xe2\x80&pq\x1e\xa5U\xabi\xab\xf7pE\xfe^\x8a\x1a\xa3\x08x\xec\xd2\xf8\xad\xc6e\x02o\xabA0\xa6\xa5\x93\x17\x95n\x19\x86\xf4\xb1\x97\xd5z\xd2\x05A\xc3\xb2\xd2\xf1(\x1a\x17\x0e!\x9a\x81bf\xf2\xca\xd1\xe7\xc5\xa3]G\x89#l9iA\x84\x86x\xf7\xef\xde\x7f\xf0\xe0\xf6\x9d\xbb\x0fx,\xcf\xce\x10\x03ax\x1c\xcc\x9d\xdb\x83{w\xef~\x7f\xef\xae\xef3f\x0f\x1f\xec\xc1M(\xbeQ\xee\xdfa'\xd3\xde\xdd\xbd{w\xee\x0en\xdf\x0d\x80\xc2\xb6h\xea~\x00\x83\xbd\xefy\xf3\xf2\xde\xe0\x9e\xdb42\xe2(\x85\xa4\x02\xc5\x0fm\x15E\xa3\x11\x19\x0b\x01\xa3\xd6\xbb\xfa\xeb\x0b\xba\xba\x08\xde\xec\x0b\x15\xe6p\x18\xb2\xbf\xb9\x15.(\xffD\x9dz\xf1\xd2Q\x1c\xc0\xef-N\x11\xe6\xb9T\x0eCUz\x17\xc7\"g.\xa2\xf2X\x84G\x90\xf3\xd3\xd1HH\xa7\x88\x9e\xd1(\x193\xd4)s-\xb2\x1b\x03\xe7R\xe6\xb5Y\x19\xcd\xf0*\x1fi\x9d!\x16\x1b\xe1;6\xc0\xd3\xb9:\xdd \x9f\xee\x0c\xcfc9\xdd <\x02\x8cm\xda\x9abB\xe0l4\xc1I=\x84\xc9\xf6\xb6\x81![\xc0\x90\x7f\xa7\x17\xc8\x16p\xc0\x9b\x19\x8cq0\x11\xec3\xeeWQN\xea\xbf\xe3|\xb0\x17\xa2g\xd4\x02]\xc9.\xbc\x84IQaIH\xb3\x96\xec8\x18\xc4\x81\x0e~[!\xfb\x7f\xe1\x9a\xf0x\x08\x13]\x98\x8a\x15y\xe4\xc5\xa5Z\xe9\xb1\xf8\xdebp\xaf\xa0\x9b\xe0\xfah\x00\xe8\x88\x1a\xc0\x88u4\xf6+\x1c\x19q\xe1\xc8\xe4%\x9d\x0d\xc8\xc8\x94\x00O^\x11b\xb5 \xff\xb4\"\xa2\xe6\xa8h\xc9\x8d\xd5?@\xcbE\xc9K\"\xbb\x9e6\xb3\xae2\xabQ\x9eMa\x05\":LQ\xf0J9\xd3\xd81\x93\xf7V\x0c\xb7\x90\"em6\xff\x03\xe4\xaf'\xc2\xf6\xbf\x03\x038\x80y\x7f\x95\xf0J\x10\xf3\xd1\x84Q\xa3\xc6\x8d\x11\x1b9\xe3\xc7\xe7\x9c\xc1\xe4\xbf\xfd\x00{\xf6j\xda\xbfyi\n\x97\x02s\x00\xf36\x96\xf42\x80_\xafL\xce\xb4\xd1e\x88]\x86\xcd\x8aB=\x13W<\xafZ?\x9cG~R\x94}\x0c\x9a\x91D\xd2\x10\xae\xe95\x126\xd60\x93snr\xee\xae\x08\xcdF\xe5\xec($\xfc\x11fF\x1e\xf38..#\x11\x1d;Q\x07\xcf\x95\xe9b%3\xb4L\x00\xfd\x84z\xa9 T\x8a\x80H\x04\xcb\x13#\x90\x88E\xaa\xcc$|C\xfd\xf3I\x15\x86\xfa\x97f\x18S\xb95\x04o\x027A\x87\xdaH\xd7\x90PGue\x8e\x96\xa0J:\x1d\x12\xde$\x02_\xdf\xf9J\x8e\x10\x97K\xff\x0e\x1a\xdd\xe1\x00V\xa3\xc5\x18Z\n\xb1sE\xd9\x9c\x9b\xc5\xf8BW\xd7J?;\x1e%>w8(8\x1c0\x94|\xa5\x90\xf7\x99\x95\xbc[\xdc\xbc*\x15\xbf\x04C\xc0\xf63\xaf7\xb3\xf6\x03\xc4\x8c\xdd\x87\x82\xd5\x8f\x1fB\x88i~\x18n\x0ca\xe0C>\n\xc7\x88\x067Q\xb3@F\xc9\xf6\xf6\xd8R\xb3\x0e\x14\xa1t\x94\x8e\xb9\x8a\x8b\xf5\xc8M\"\x98\xe3A\x1f\xcc\xcf\x1e\xaf\x02\x98\x04\x10\x0605@R\x9c\xe7\xec\xffj\xb9z\xb5H\x7f\x93*\x11\xb4x\xb2\x04\xb6\"\x12\x0df\x81c\\\xeaWxS^q\x0eRQp.W\x88?{k\xe03V4\x1fc\x9ck\x0e\xdb\xc6\xd4\xb8\xd0~xs\xa8iA\xd6\xc2!\x15\x1c\xb6\x84\x9a1M \x14\nu\x84\xda\xb6@\xaa\xa8\x84\\!P\xb8\x80.\xa9\x80\x8e\xab\xd6\x10tb\xcf\x86\xf0\x08\"\xdc\xb1>\xbb%h\xbb\x97\xf0-\x1b\xf3\xd7w\x06\xa8\x9d\xe5\xf7\xe8(\x84m\x97rn\x86\xc2\x1f*\xee\x19\x8f\xcc\xe3\x82\x9d(\xac\xa8'5\x93\xe6y\x95\xbb\xe0&\xda\x93\x00\xce\x1b\xe7\xe5/\x7f-;aa$Z\xf8\x08\xce\x10Df\x11)\x81\x03Ht,\x82\xceo\xf2\x97\xffel\x82\x94\xcd\xb4/L\x1cNa\xc6&LF\xa1\x81Lg<\xf8\xc6\x911\xa0\xc4\x9bu=\xa2\x85#\xadC\x0f\x05O\x81\xf6z\xc3\xb1\xd2.\xc3\xed\xec\xac\xe0\x11,\xae,\xb7U\x08\xecn\xa0?\xe0cy\xc0s\xa1y\xc0%\xe5R,c\x14d\"\xce\xfc\x0c\x1e=\xc2#\xbf]L\x9b\xa1\x98\xa6[\xac\xca\x9beT0\x1e\xb3!\xfe\x89\xb4\xd1\x8b`3d\xc2T\xce\xf9 \x06yc[\xad\xf2ZIB\"-k\x01\x92\xbd\x98 \x87\x11\x1a\xcd\x8c\xab\xedm\xfd\x9a\xcf\xbb\x9e\xf2\x8cS\xcc\x88\xc7\x99\x99\x05\x93\x9c\x8cta^\x90K\xe9\x00\xb2\xaaQ\xcbi\x95ZrNj\xc5\x98\xa4:\xd9xyej\xf9\xdf\xacKz\xf9\x9f#\x86\x82\xae\xe9wy\\\xe6Z\x14\x86\xbab\x8e\xa1\x92\xc0\x8f+\x7f\xb8\xbe'&\x8a_\x1d\x0eZH\xe1\x9a1\x14K\xf2\xff }WXr\xee\xb3\x8a\xd5\xf4E\x99\x97P\xc0\x92M\x80\xb1\xee\x13\x93\xf1\xb4\xb3\xa6\xa5]\xcb\xf2\x1f\xd4\xb0\xbc\xd4\x00`\xde\xd8\xe0/\xae\xbc\xc1\xa5\x18\xc3\xa3B\x0b\x9f+\x86 2\xa2\x8e\xdf\x18\x8cu\x0c\xc9\x8b\xeb\xd9\x835U\xaev\x99\x90\xe4!\x06W\x87i\\./\xc3\xea\x19\x05\x12(\xf3\x08\xfd\xc6F\x0ce\xc0\n\xc3H\xd8\x87\x0c-\x01Z4\xaa\xac\x1a\xb68,\xca\x10\x89e\xd3\xe1\xadXv\xde\xa5f\xd7#\xd1)w~c\x91+\xba\xf3\xd2\xb9\xf6\xa5\xfeve\x0d\xac\xa4=n\xd0\x91\x94\xd3\x91\xa8V\xb6\xe8!\xa4\xa2\x84L\xea\x94\"9.\xea\x97\xa0\xe7\xc1X\xadwY\x9f\xdc\xaf\xfaY\xfcrm\x93\xe3L\xa6\xdb\xd4\x0c\xbcN!|\xd5\xe6\xa5\xe7w\x18(\x12(\xb3\xcf$\xfdJ9\x06\x13,@\xa7=}qE0H\x8a\xac\xa0k\x03\xad\x88w\x83\x06\xf0\xd5\x0f\xe0\x86\xdaKL.ZS;\x14P\xa6\x12\xca\xe8_\x19\x94A\x02\xdc\x99\xf2!\xd8\x8b6\x88\xfa\x13\x04\x17\xc9\xac\x0e\xc7\xd4\x98<\x0b\xaa\x8e#\x03)f\x8b\x89Z8\xd6\xa8\xa8\xadZ\n\xe1\xdcg3\xd5AI^\x97en\x9bT\xee\x96\xb6n\xb0\xbe\x99\xa8b!>Q\xf0\xce\xd7v\x1f\x91l\xc4\xc1'\xddS\x0f\xb0\xcc\x1e\xafy\xd6:6\xb5KD\xfbj\x87v\x95FR~f\x19\x83]\xd1\x91\xb4I\x0b\xf8\x92\\\xa6\n\x00\xe4]\xbb\x0cQ\xc3/\x18\xc2O\xd4K\x8c\xf6s\xb0\x8a\x0b\x93$\xa6Q\xdc\xa9\xf8C\xb3\x7f\xe5W\x9f\xfb\xcc\xb6\xecj(\xb7\xa7ic\xb4\xe6J5\xe6I\xad\x11\x90*0\xd9*c\x1e\xea5\xdc\x82;\xcd\x96g\xf2\xd9^\xf3\xd9\xa2\xf8\xce\xe4\xb9\xbf2x\x0c\x9c\x89\xd8\xa1\x0bc~=\x87<\x96\x9a\x88Z\xf6\xe5\x9cxJ\xcaI\x8d\xf0-O\x82\xc8\xa3\x96\x0c\xa3\xb1\xbd\xc6\x03\x1fL*t@\xde3~\\\xa7\xf0\x98g\x8dN\xe1\x11\xac\xe1\x00\xce\x89\xb7\x8b\x0c\xcfY \xe2L\xb1\x10\x04\xf1\xe2>M\xb8\xfc\xedcYZ\xd2\xd9-\x06\xfdD\xdeG_ \xf6\xacI\x03\xd2\xa6\xe9-4\xb5-\xfe&:/\x127O\x8b\xb9\xddaD\xc9\x032%-y@\xd8ArN\x19\x9bL\x1c\xf2\x80(\xc2\x87g\x8e\xb1\xe49\xbc\xc4\x11\xf7\xad9-^E\x19\x85Q/\x80\xde\xb8\x99\xd4\xa2\xd2\x93cR\x8bH\xd6\x8a/\x93\xe2\xfbEVrZ\xcdJn9M\x99\x00[\xb0\x96\xe8+\x83#O\xd2\xe842y\xb6I\x99\x8b\xf5\x14\xf7y\x99P\n7\xe1T\x13\ni\x02P#\xbbF\x05\x06\xdd\xb2k\xb8\xda/\x10d\x84\x83\x8c\xb3U\x95\xaa\xf9&\xbfo\xf4\x0d|\xac:\xb1\x11x\xa4d\x83\xed\xee\xb2\x06x,<\x82]8\x80\xb7\x82\xc7\xc3m\xb6+\"L\xdfJ\xa7\x04\xb4\x00\xf0gD\x1b]\x06`N\xb0Gp=\xe5b\xea\xdf)\xed9\xc74\x8c\x16v\x86J\xba\xf7\x1b_J\xac\x81\x02\x08\xc5\xcf\x18%0 W\xe1$\xa2kn\x10\x1f\xc2{t\xc2\xabG\x0dpy\x10E\xac\x88\xbf\x14\xd5^\xa2\xfd\xe3\x059#\x8b\xf2]\xf3\"n%\x8e\xe1\x06Q\xfa\xd0Z\xee\x00\xf8\xd8\xd6\xba\xd0\x13\x8e\xc6\xec$\xd3w\x13 \xbf\x0b\xae\x8a\xd4\xf7\"\xaa^\x98)y\x0e\xea(F6\x03\x16\x16\xa9\xcf\x19\xdd\xca+`F\xd8\xc2\x0e\xea8}\x1fG\x83o%\x15P5\xa9\xb2v\xc0\xdcJ\x169@9\x84!\x1c\x96\xb9\xb3\xf4\xf3\xdfJ\xf4*\x95\x8a\xe3\xc4\xeeC\xc8\xb8\x8bi\x86~\x92\x02\x16\xd9\xb8\x10\xbf\x8c\x049B7\x91\xb0\x80\x1e\xa3\xf1~\x00a\x9d\x82ip\xf4\xc9\x8c\x92\xc6\xf1\xde\x8a\xa2^\x15G1\xc8\xf8\x1b0UX?Q\xa8oA\xd8\xc8\x8e\xb0\xfaN\x9cp0\xa9\xe2\xa0\xc9\xa2\x848\x98b\xb2L\x86]*\x185(\x88/Ez\xc8\xa0\xf1\xab#r\xca\xcdbE9\xd1d.z\x13\xca\x8a\x08\x95|\x81\xf0k\xcb\x8bi2&\xca\x0f \xaf\"K\xf3x;%\x01,I\xc0\x98\x06[\x1a\xf5\x13\xf3iU\xf2\xea\xf2\x10\xd7BX(\n\x8b\x93]\xbf\x0c\x80J\xbe\xd4\x165\xc3\x0f}3|*\x89D\x04\xe3\xb0\xeb\xd7&\x06\x95\xb8g6\xb70\x00\xa3\x8d\xb5\xa2\xc7 +\xe5\xac\x0c\x9e&\xf2\x92\xc4$\x17\xfeK\x07\x12\xc1\xf8\xf1\xbe/\xa3\xdc\xf1\xa7\x99G\x05\xe1\x97\x92\x8b\xca\x87\xbb\xe8\x19\xbb\x03\xb9\xfd\x93 F\x9a\xee@n\xe0\x1b\xf1\x95\xc7\xb0F\xdca/\xdb\xec\xa1\x02\x08\xad<\xbc\xbc\"t\x9ce\xd3\x9e\x14\xfb\xe1\xd8Rt\x04\x14\xb5\x04V{\xdc\x99\xc0>\xa3\x9a\xf6OD\xcb\xe8\xd9\x15\x8e\xa8>W\nh\xb7\x1d\x80\x0c\xab\xab\xbb\xe5G\xa89nYV\x11 \xea\xbc\x80\x13$/\xd5\x05L\xe0\xf1c\x88\xec\xdf\xcd0\x00f\x9b\x1d\xeb\xf2\x03\xcb2\xcd\x8a\x05\x9d]\xf3\x82\xe2\xb9\xf6\xd0\xe8`\xa1^l\xed\xb5\x19]tW\xa1\x8b2 }\xf5+\x12E\xf6\x98\xa8\xd3\xa6\x90\xaf_\xa1P\x85\xb6\xbel\xb6\xe3\xcb\x8b\x0dcR\xf3%lCpP\x08&G\xf2\x19\xec\xc3\xa4\x0d\xc9A\x8c<\xe7\xae\xe8\x19f\xde\x8f\xf8\xa1\x940\xd4\x88\xd9\xa9\x1d\xf9f\xb7\x04\xb0N\xc9\xb27\x90.6\x1e\xbb%\x948\xd7&\xfb1\x1d\"a#;\xd7\x99E\xa3\x10J59;\x9b\xd98UU9\xfeTT\xe5\x04oH=y\x8c\xbf\xca\xacGa\xa1$\x8f\xf0\x87\"5&\xfc\x86\xd0\x97\xe7\xfcW5\xb9W\xe8\x04\x8a\x0bb\xd3\xa8\x9d\xa2i\xd0C\xc5\"\xb7\xeb3\xf1\xcd\xd1\x14\xfe\xbe e\x13\x88s\xee\x8f/\x92\xf3\xd8c*(w\x9a\x7f$\x89\x9bT\xcc6>@^\x18\xf1R\xf1\xa5\x88l\x1b\x93\xb3\x9c-\x9c\xdb\xa4F\\G\xa1%c\xce\x8c\x9b\xf8&\x1c\x0e|cHXX5I3~B\xc9\xbcQ\x9ed\xc3\xd0\xc6[t\xccXi}\xd8\xa0iE\xb3\xea\xc8\x8b\xe3\x9f\x96n\x99jWA\x05v\x1c\xf2(\xec4xK8(nJ\x13Y\xae\x8e\xb3\x19\x83`\xc2\x9bC3OW\xa8\xd9\xd0\x1f\xa0\x88\xc1\xa3\x8ag*\x15\x1e\xa8k\xe2\xf1\xfc\\\x82-E\xae\x94\x8d\x8a\x89\x97\x8d\x02P\xfa\x91<1\x8f\xa4\xb0\xa0\xd7l\xbf\xaaeU\xcf\x0f\xf2/\x1fq\x81F\xb2\x82\xb0\x0dg&\xa4\xab\xfarJ&R\xf0\xad\xf8\xf5C\xee\xb7\x80\xae8XXuX\xf80\xf0P\xad\x14=\x19\xd8G;C8\xb3\"^[\x99wcE/k\x92\x1e%\xe8EF\x9d\xf1r\xc7\xea\x13\x19\x7f`(o\xac\x98\xf5\xd5t;\x98\x9f\xc1\xcc\xb6\xb7\xb0\xff\x89\x0b\xfb\x8f1\x1e\xb0m*\xce\x10\x1623bc\x8c\xdc\xf4>\x9a\x8dv\xf1\xefm\x0c\x19c-h<\x16\x18>\xe4\xf5\xfd\x95\xb4\x91\xa9\x9c\xe1\x9e\x12s\xc0\x0d\xbf:N\xa5\x1a/Q\x88\x1e\x13\x15\x99f2\xe8t\x1bfl\xd4\x0f}|.\xf6\xd1\x84\x8dkR\xdd\xf1\x070\x92\xc6\xa3\xc9X\xec*&\xd8\xcd`[f\x1f\xc8\xd8\x9fg\xba\x11q\x99\x90=\x9e\x05\xbc\x8c\xfa\x8c\x1d\x00\xfc\xdf\x04\xff\xb5Md\xc1\xa5\xb1\x04#\x08\xf0\xcf\xd0\x7f\x08+\x06\x11\xec9c\xbb\xc9i\n\x95\xa1\xf3\xf1\xea\xf1n\xde\xe6N2\xc5 \x8aG\x18#\xc1\xc9F\xc8%\xee}60\xbc\xad\xa8\xb70\xba\xd1pda\x905\xff\xe6\xe6M\x8c\x03F\xd1l^SA\xb4\xd0\x8a5F\xb0 !\x9f\xf0\xe9-a\x08\xd9CX\xc2c8c\xff0J\xd0&K\x1c\xc3\x10\x16HA\x96z%\x89\xbcXwkAr\x8e\xc7\xbc\xdf\xf2\xb71\x81\x94\x9e\xbf\x93\x1f\xf2\x9e\xcf\x90v\xc1\x10\xe6-\x94 $\x83/A\xe6\xb1E\xc1(\xf6iEq\x92\"\x1b\x13\xfax\xd6=\x1e\xc2\xca\x87\x9c\x81c\x85\x8b\x86\xfff\xdcmaR8(4\x9a\x12z@\xde\x96.|\xb2pGf\xc2q\xc4(\x15\xe2\x87u\xe5\xc4>\x9cX\x85\x19\xb60'\\\xe8~\xfc\x98\x1d\xe8\xb6\x85a\x038A\xea\xba*_\xf7\xe1$%\xe1g\xf3W'BP\xdb\x1e\x82\xc7\xb7\x94\x0f\xdf\xc1 n\x92\x9d\x022b?\x8dN\xf4\xc2\xad~q'\x1c\xab\x1f\x0b5\"o\xa7\x0e\xd2\x8c\xad\xcc\x0e\xcc\xd8\x12M\xf8~x\xc4\xf7C\xe5\x83b93F \xc4\xfb\x92\xba\xec\x08\xaa\xb2\xa3\x8d\xa2\xec\x9c\x924D\xb5Fy\x9cp\xb6\x9bV\xd8\xf9\xb0\xd4\xed\x00\xc6q\x96\xeeU\x13\xd5\xbdj\xea\xea^\xc5\xc8\xc49\xf1r.\xee`\xa4f=\xba\xd1p\x1c\xff\xe1\x96/2U\xf3EV\"\xe8\xcb,k\xa1=\"\x04\x93b[\x99\xe0 Z\x01M\xe9{&\x1c\xc2\x8f\xc5\x9eMp}E\xa5\xbf\xdc\xcbxJI\xbe\xea\xd7\x9dR2\xe5\xf1h\x93\x0e\xe8\x91\xc0c\xe94y\xf3&O\x10Uz%'HR$\xe4\xebYn\x0c+\xf5\xb9-\xc5\x1cw\xab\xdeE\xa5\x9c\xd4Y\x9f\xb1My\xe6\xd4\xfe\x91\xbd}k\xa1\xc7\xa7\x9ce~M\xca\xfa\x8e\xecVg\xbf\x9b\xb3\xff\xf5\xf5\x1d_\xdb\xa1X\x94\xc2\x9c\xd5\x11\xce\xd4\xe0\x07\xd7\x94|U\xd5\xc3\x91bT1+!\xca\x14\xe1(\x02\xe1\x8f}\xb4\xdb\xf7\x8fy\xea \x9e;|\xc1\xed\xcb\x0e\xb9\xc3\x9d\xe6\xf4\xd4\xaaLXre\xc2\x92\x8d\xeb\x03\xf1xu\x9b\x0b\xe25B\xfd\x0c\xad\xffl\x970\x84i'\x90,\xbd1\xf5R.\xf8\xe0(3x\xfdb=6LIA\x0c\n\xff\xac\xe4\xf8\xd9\xd1\x1a\x9aT C\x9e\xb7I\x8f\xb7\\?\xd1\xa6(\xcc\x05y\x1cr\xedi\xf9s\x0f\xbe\x83D:n\xa2\x8d\x88\x1b+\x9b\xc9O\x0d\"\xac\xbcD\xff\xca|\x84\x8a\x05\xa55\xc3>\xf2\xfb4yI\xd6d\xfa\x9e|\xf1\xfc\xee\x94\x99\x8ev\x0d\\\x83\xdf\x9f-\xa2\x95\xc7:x\x1d\xf2|:\nn2\xa2\x9bVp\xb5\x8a\xb9\xaa\x933:\\\xa0\xf1L\x96}c\xd4%\xc2\xc3\x9c+1\x14\xe7\xde\\Q[0\"\x12J\xd1T\xa3\xbcTb\xcd\x8c\xb6\x99\x12\x01rD\xa5\xd0\x1f\x0d\xc6m\x8b\x9dr\xd5\x1e_G1\n\x9ej\xdd8\x08>?\xe1L\x9fK\x12Z\xb6\x90\x8bB)\xa2\x19#\xc90\xf1=\xa9,\xb4\")\x07\xf7\x0d\x17\x94#\xd2s2\x0c\x8c\x1f\x90\x93s\xcc\xbc\xfc\xae\xc5\xeb\x04\xdd\x95\x14\xaf\x93\xe3<#/\xc9:SJYH\x8a\xd7L\xe2k\xea\xf4\x8d\x81\xa6k{\xec\xde\xfc\xab?\xb7\xf9g\x7fn\xf3_[\xe2\xd8\xfeAl)b\x89:\x02R\xed\x9e\xdd`[\xbc\xcd\xabSi\x8e6\xb1?\xc0b\x8e\xb2xIkCgE\x99d\xf1\x91\xac\x7f\x86\xdeg\xb6\xbe\xdd\x07\x0b\xean\x12\xddx\x06F$\xd0U\x14as\x9a\x87Y\xab\x1b*\xa8\x1dE\xf1d\x91OIV\xafj_\xb4(_\xe8\xd6\xec<4\xb78 's\xf2\x8ed\xf9\x02\xf9\xdf8\x00\xc5\xa3\xf0c\x8c\x8f+e\xbbl\x11L\x85ZO\xebL\x01U\n\xd5\xa8g\xe5\xc8\x18\n\xafC\xf4\xb5\xa7fu\x84\xb1\xd8\x95\xe2\x9d\xdau~\\\xdf\xcb\x0e\x82wmR\xbd\xd4n\xca\xaex\xbbf1]\xb2\xf0nN\xac\xf2\x92v\xcd\xd4Z\xbeV^\xc8\xa5\xd0\xd6:\xb6\xf2*\xf7\x19\xba\xb9\x8ev[\xb2!\x01\x86u\xcaw\x95\x0f\x07\xe3@\xf9\xbb\xe1^X\xbf\xecfQ#\x19\x91\x97)\x8b\xb9\x1b>\xb2\x95\xc2\x15\xfe\x99\xc9L\xb0\x0f?\x1b\x11\xa9r\xd3D{\x9f\xb7s\xba\xad\x148\xad\x13\xdd\xb4;i1\xd3\x80\xb4\x1e\xd2\xe9RT\x99\x97%O\xcd\x85~\x0b\x19{(r\xd0G\x18&\x8c\xbe\xf6\xbc\xc4N\xaa\x15\xedp@V\x02\xe44\xbc\xab\x12\xa0\xa8\xc5\xd9\xa6J\x83R\xaf\x9c\x91\xfcXX\x04MD)j\x99\xb2\x9e(9\xcdY\xc5\xe1w\xe6\x14\xce\xdd)\x8d\x14_\x93V*\x83\x8ev\x82\xc0H\xf9\xd5\xfc\xf6\x99\xf0I\x8b8m\xb0\xbb\xa8\xa0o\x82\x95\x06I\xf9\x9dA+\x0c\x14d\xcb\x91\x02\x85\x0c\xdf\xb4\x0b\x00\x06uB\xa3*\xa2a\x8f\x7fl\xf7\\\xb3o\xf0Xe\xb1\xe2\xfan\x8f\xbb0G6.\x8br\xf6\x07-s\xce\x9c\x90<\x05\xbe\xeag\x00*w\xd5a\x9c\xa0\xeeE.%\x9a\xb6\x8c\xae\x8c\x07\x83J\x8dl\xd9\xd2 \x16=\xa1&@\xe4}\xdc\x19\xc0\x8e&\x855\x08\xee\xa1Nc\x8d\\A\x95\xc6V\x1a7\xb4|56\xae\x85;\x8c5\xbc\\\xac\x8f\x0e\xf9\x8f\xf3p-\xc5H.\x03\xd82\xc1N\x1f[d\x9b\x91\xf6\x8c7\xf7\xe0\xb4\xe5\x7fpU\xf9\xb5\x9c\xec\xb8\x19\xa3:\xaa\x19\xf1\xf8\xacH\xd4\xebv\xfcFxL-Y/[[%A\x8c,\xa7o\xf4\xe7\xb2\x03\xc5x\x9a\xbc\x80\xb0\xb5kJ\x0b\xf9\\\x87ia\nl\xde\x94gJ\x9c\x80\xf9\x8c \xf5Uy\xa1\x1d\xe1\x13\x8b[/H\xa9A\xe5\x13\xf0\x832\x91\xe2\xf6v\x00\x91\x87~ \x1c\x02hn6\xe7\xf9dS\xad\xfb\x84\x81\\<;\x1f\xe1\x04\xa6\x1a\x1f\x91X*/\xb6\x03\xad\x03\x9b\xe1\xe8\xfc)q.o\xe5F@\x06eT9\x92\xc4\xfe\x854\x84%.\\ \x08\x9bX6\xda\xb5X\xcd\xe4\x85\xd9,\xb5\x89A\xd5\xab\x8a/34\x15*9\x81\x9ecED\x91[\x1d\x91gfd8\xc1(\xf8\xe8\xf9\x1d7\xdb\xc0\x17W\xe2G\x0d\x11\xa7l\x86\x9d\xdc\x88\x98\x101\x80[\xe8\x83\x83\x81\x88\xe8\x93#\xde\xff,*\x98E\xady\x93\x18\xda\x1c\xf1:ff{\xc2k\xa4\x90\x86\x80\x1cF\xc0 \x81\xcd\x06r\xf6W^\xf4\xc8`\xd2\xa7 W\xa1+\x07\xb1\xe7\x97\x90\xd2\x0fJ8y\xe7\xb0\xa3\xc3\xcc\x0c\x86C\xee\xe9\xe7\xb1\xcd\x96 G\xa4]\xd8\xd7V\x9a8\x13^\x8d\xf6cg\"Y\xcc2\xdc \xc4\xcaZ\xd2\x18\x1a\x96\x06\xc4\x00\xb6\xf0\x94\x8a\xa4Y,,\xd2\xf8x\x93\xfaY\xe1p\x0c\xcb\x0c7\"\xdc\xb4L\nDDQE\xc9\xa4m3:\x89\xe9f4~l~\x00\x93o\xd3SEV\x1e'*\xb2\xea\x95\x8eY\x06B\x87\xd6\x81J8Nu\xfd\x95S\xc3\xa2\x03\x92\xd4\xd7\x12E\x9cqW\x02\xe3\xf3I+1\xbe\x12\xcb&|o7\x1b\xd8\xc2r\x90\xf9\xf66<\x82\xa4\xdcl\x13F\x83\n\xad\x9c8\xc7b,\xf8\x80\xe7X\x84h3\xe1\xe65\x031\n`\xa2\xa3G\x93oT\xd6 \x9b\x1e\xeb\xdfi\x89\xecz:\x896J\xabM\x15\x9fy}\x1c\x96\xf7\x9a\xcfR\xb9V\x0f}\x88ZOK\x06\xaf\xed\xed\x0c\x1e+(\xdfv\x12;E\xbfC[\x04<\xbb.\xedj\x024P\xb5N\xa1\xe0\xaa1 \x96\xd4\xe2Q\x0c\xb0'\x01\xaf\xa3\x13\x88'Oe\x92\\\xf4\xc6P5\x95]\x14\x04U\xac5\x1d\x98\xbf\xbb\x1e\x98v\xb2}M<\xb0\x99\x8c%.{\x84x\x16\x97\xf73\x11da\xa3S\xed\x88n\xe1\xb4'\xad\xa4\x8a\xa7\xe4\xc6\xd3\xb2\xceuO\xfc\x92je\x0d\xb6;\xb3\xb3\xdd~\x00\x9a@\xcbk\xe2\xb9\xbf}Y\x92\xd4e]\xba0\xf7\xdf~\xdet X\xb8\xc9q\x914\x89\xda\xe55MZ(R$\xb3\x0e\x86\x82V\xf8U\xd6\x1f)CT\xa3\x0cQ\xc0\x8f\xb0\xa8\x8d.\xb4\xcb\x0d\x8b\xd2\xeaa\x7f\x99q\xa2\x0b\xac\xe47\xc3\xbfX\x07\x9c\xcb\xcb*x;\x13\xf1L\x16\xf6\x1e\xce\xe7\xd1\x82\x80\xd1)\x0fTu\x00\xda\xae\xd4\x99'\xd8G'\x9a\xe7&$\xfcz-\x86\x8fo\xb6\x04X\xf0\x17\xe9\x94\xa1\xce\x91\x18@1\x1b\xeae-\xb4\xe7LT\x0d1oeve:\xca\x16\xb5(\x10@\xe1\x9e\xb7\xd0\xf3j\x02\x8f\xb0`\xcdM\xc8=\xac\xda\x87e\xf2'\x18\xa8\x0d\xfb2M7R\x84X\x94\x03HPR\xf4\x0bIbk\x17\x8bs\x9a\xf1\xca\xac*g\x0b\xcb\xben\x96P\xfa3L\x19\xa9Y\\\x03\xb1\x8a\xa3\x96B\xe7\xd7F\xa5\x04[\x958))\xa8\x93\xc9\x04\xe4\xb9%R\xcdw2\xcfN\\\xe9\x0d\x88^RA\x01\n\xf7\xeb\xd1`\xcc$T\xd4\x10z\xa1\x8c\xa7@\xecb\xc7h\xeeM\xca#3.\x08G\x1a\xf0\xf3s\xd2N\x16\xd9\x15r\xe7\xdcD\x94F\x9b4\x96\xd7\xda\x82\xf0\x8eJ\x90\xac\xa3g\x97\x19i\xdb(`\xdb\xaa]#C\xdb\x81\xa2\xba\x99\x99~\xb1RT\xee\x91\x89\xd1\xaa:\xf9E\x12\xdc\xd0\x986:2SK\xbe'\xa5v\xa3\xe2 HZ\x8a8 \xb8\x8fR\x1cy\xc4K/\x1e\x00\xffP\xb8\x97\x11\xa3\xfb`\x91e\xdaxD$\xfd,I\xa9\x9b4+>!\x1e\x1d\xdd\x1e\x07\x10\x8fn\x8f\x11\xcb\xe9ho\x0c;\x10\x8f\xf64\x19\x82\xfd\xb2 y-+\x83q\x97\x96;i\x08{\xcd6\xeb\x15\xfal\x0d1\xd0\x8f\x06\xba\x81q\xce\xf5\x85\xa8\xf1\xc1\xdd\xbao\xf0_?z5\x85\xa0 \xa7^Zq\x8a\xfb\xbb(x\xe5b7\xfa6\xed\x82,u\xe0\xdcRG\xe0\xcaK\x02\x99\xad\x0f;\x99\xe0w\x0fC\xd8K\x9fK\x86\xef\x96\x03\xff\xea\xfa6\x07\xf6\xbf\x03g\x88\xab\xd9*\x80\xa1n\x02\x973\xb9\"\xa0\x04\x16\xd8\x00\xc2\x13\x90\xf4\xb3dI\xae\xd2\x01C/K\xf3\xa2\xbe\xd4_\xc8H\xc9\xfc\x989\xe6\xc7\x14\xce\xbe\xa2\x1c\xc5U\xa1\x88\x03\xb4\xcd\xf2\xfa\x05\xe2\x1f[s!p\x13\x0b\xaf\xc9A\xfb\x93$\xceh\x9aOP\xb3\xecF\xdf\x7f28zGE6\x1b\x1e\x81\x84%F\xe8(6j\x0d\x810\x01\xc9\xcd\x818mI\x9c\xcc9\x88\x82\x04Zs\x8aq\x0bv\x14g4\x8c'$\x99)\x15\xcf-N\x11\x089D\x8f\xea\xa7\x95d\x9f\xa9gR=\x17MX9tv\xc5\xa8\x96j\xd7\xb2\xe6e(\xe5g\xb2\xce\x8c~\x89\xf2\xdar\xe3\xca\xd4\x8b\xa6k\x87\xb7\xd8E\xb4\x11\xaeN\x9d\xc8K\xcceJfQL~N\x93\x15I\xe9Zp\xbe\xee\xad\xb0\xeb\x94PE\xb4\xec2\x06y\xa9$\x88\x87Mvj\xe2\xb2\xdd F\xbd\xb2\xcax[\x8fo\xdduJk\x89\x98\x03\xe8=\x0d\xe38\xa1\xacuHb\x08c\x88\x8a\xf4\xbc)\x99$\xe9\xb4\xdf+H&\x8f\xb6\xb3\xb0\x98\xba\xab=s\x9b\xbc\x0c\xd1\x08\xf5\xeb\xb2\x7f\x12\xc5S\xaf\x8c\xbak\xff\xec\x12&!\x9d\xcc\x01\xc1f\x1f\xd0\xa5']\xd3\xe5\x11\x91\x0b\xfd\x04r\xfdq\x88\x81\xbcK\x93\xe5aL\xd35\xd7\x95*\xca\x9fv\\\xe9V(\x81\x0b\x7f\xc3F\x95\x04\x87\xfc\xda\xa4B\x14*\xdd\x1a\xcd\x08%!\x11KT\xfd\xc8\xbc\xacp\x00\x1f\x88p\xe5\xecPmA\x1e-D\xdd\xd9<\xef\x85F\xa2AHF\x99BH\x87\xf0\x9aT\xe1;\x9a\xca\xea\x06\x15\xa8\x17u\x0e4\xfb6\x00\xe2\xbd#\x01\xbc\xf0\x03xw\x05\n\xdc\x14\xfc\x90\x02\xeb0\xa1\xd2|-n\xa0\xb5\\\x1ao\x9b\x17M\xb36\x8c\xfa\x91\xf7\xe4K'\x9a\x81\x8d\xcb/\x9bt\xe1]\x15nN\xa1BgJEf=\xbe\xb1&>Jr\xb8\xa5K6X\x19\xa3L6\x80F\x0d\xe7i\xaa\xcd\x88yJ+\x8798\xfc\xd2o\x04\x89\xd6\x80\xc01\xb7\x15;T\xb2\xa8\x07\x02\xa3\x02\xcf+\x87M\x070\xa4W\x01C\\\x03\xc32\\i\xf0\x15\x04\x18\x1a\x85_\xde}\xdb\x19\x11XB\x94\x9a(Y\x1e\x13\xd5\xc9+\xe6<\x07\xc7e\xea\x11S\xcc\xd2%#P2\xdf\xf2?y7>\xcf\xd2S\xf4`T\x9d\x17\xcdG\x81\xc8\xd7\x1c\xc3>/\x06\xa4\xeb\xcao%\n\xdd\x8e&<\x1eT\xb0\xf8\x16\x08\xca\xe3I\x7f\\\xc4U\xddS\xc3\xa0aD\xdd:\xd8\x8c\x8b\xea\xa8\x90\x97\x96\xa1\xd8\xea}Q\x88 hP\xe1JCT4\xf3U\xc0\x82\xf8\xe8\x17V\x98Wt\xcba[\x8a\xf2$!\xde\x1b\x12\xc0\x0d?\x807\xeaR\xe9\x02\x01\x1d\x89x\x11\x0d\xd8\xa4\xe4o\xbems\xb5R\x1a\xf3\xfah7\x9d3o\x86;\x0cA\xee\xca\x92ig\xea\x86\xf7\xdf\x84\xb0\xd7\x82\xa1\xc4\x15C\x89\xc4P\"14\xe5\xa6\x10\x81\x97N5\xc3\x88\xf7\x8a\x04\xf0\xa3\x1f\xc0\xabo\xe7 ,\xc8\xf7\xeaZ\x90\xef\xcf\xc40\xe2\x8e_\xda\xc9\\\x1b~\xfd\x87\x91\xa8\xc4\x9f\x8e\x88\xf4Lp\xba\xcfT\xe8\x10!\xcc\xb4\xf1\x10\xcdu\x14,D\xbd\x9fg\xff\x95\x88\x84.1\xa6\x87\xec\xfa\x89x\xc6\"z\x8a\x93En}\xab@W,\xd1\x8f\xc2\x00:vr\xb1\xb5\xbc\xb9\xcbo\x1a\xa4Xv5\xf5rZD\xd7\x02\xfb\xbf\x06\xd1\x1d\"C\xdd\xf6\x02\x14\xe1\x95\x15\xb7p\x8b\xf3\xa4\\/\xd2\xe6e\x89\xde\x95\xb6\x11\x02G\x0e]\x18\xa0zI\xde%o}S\x0c\x1e\xf7r\x04\x07<\x91\x0bG\x89\x14Q\xa2\xbc9\xe07\x07\xcd|\xf9\xeaepYt\xa0 \x95s\xb8\x9a\x86\xe0\x9d\xf9\xd1+\xf3\xa3g\xe6G\x98\xa3\xcaK\xe3\x00N(\x13-b\xe5\xcdoT\xb0\x86\xb1\xe0A\xb7\xa1g\xd4\xb0V:\xec||V4\xea\xec\xf3\xb7\xe7qi\xf2\xb1w\xe6\xa8L\xe0i\x9e\xe6Eut\x1b\x9aW7oep#\xaa\x89S\xae\xcc\x85\x89\xaf\x07\xe5\xdfRg\xa1\x89\xd9\xac\xcf\xc4I\xf9[J&Z\x95\x15\xef\xff\xe6Me\x00\x15}\xae~\xb2R\x99\xa0\xda\x06\xcc\xd3\xec\x1f\x93\xe5\x8a\xaeQL.~\x0c!\x8f\x85\xa8\xfd\x1bm\xa6<\xadM\xd5Qc\xdc\\\xb4\xd2J\xcd-\xd4\x7fS\xacZy\xfc9N\xcec\xf8L\xd6\xd0\xfb\x1bl\x03\x85m\xf8[\x0f\x92\x18\xd8/\x89\xc7\x06#y\x05z[%\xf8D1\xfd\xb2\x16\x87\x16)\x1c\xf4\x86\x15cBu\x892\xa9\xd7j\xc1\xadJY\x08e4%\xce\xc1~\xb9\x0e\xcd:\xcc\x955pT\xae\x1b7\x8ey\xa6\xc48\xfb({\x8f\x9a\xf8I\xdcT\x01\xcd\xe2\x00\x16\x0c\xc7z\x7f\xff\xfb\xf1\xf1\xd1\xeb\xd7\x1f?<\xf9\xe1\xd5\xe1\xf1\xfb\xc3\x0f\xc7\xc7\x7f\xff{\xaf\xe9\x08\xb2bog\x0eJ\xa3y;\"\x18\xaa5\x91z\xb5& \x05Y([j\x88\x91\xcd\xe5\x87\xa6\xf4\x8eg\xa0^\xae\xe8\x9a\x87O\x17`tSDL\xdb\xf7bU\xc9\xb5\xb2\x04a\x94\xd9\xeck\xe5\xebb9-\xca\xb3z\x97kJ\\\x93p\x9fY\xe9\xd2\x0c\xf3\x0ex36\xdei\xec\xe9L5\x86v\xd7\xdf\xa0\xd2:\xe7*\xad\xd3\xb8\xd4d\x9d\xff\xbfM\x93uj\x87_\xa1\xee\xd3\x14XT\x7f\xad\xe2\xd1\"\x96\x0et+E\xa9\xb5*\x95Z\xab\xaa\x82I\xfe\xac>\x10\xac\xc1*VuV+\x17\x85\xcf\xca\xa6\xf0Y\xb5)|V\xb1\xdc\x870\x84\xb3X\xdc`[\x11Q2\x00\xe2\xadcF\x9c\xfc\x00\xd6\xd7\xa7\x11Z\xff)\x1a\xa1\xf5uj\x84\x84\xff\xbdM1\xb4\x8eK?}N\xb9O5\x94{\x19\x07p\xcc\xf6\xc9\xda\x81\x16\x9ft%l\xc7\xff!\xc2vn\x85\xe6\x92\x13\xb6%\x1b\xefI\xec=u/\xbby\xf1\x0d\x84\xed3'l\xef\x15\xc2\xc6n\xf5\xf38\x9bG3\xfad\xb1p\x8d\xe6\x7f\xef\xac\xe8~bWt\x1f\xc7\xa5\x83\xed\xb1\xba\xd7\xcecqC\xec\xb5\x13\xdck\x17q\x00\xe7\xd4\x0f\xe0\xe2\xfa\xf6\xda\xc5u\xee\x8a\xf74\x9c|\x86\x11\xdb\x10\xe3\xe6\x86\xb8\xb8\x82+H\xd5\x18?'\xe1\xb4\x89\xcf\xa8\xb7\xa2JRn\xea?\xe4\x89\xd7\xe9\xce\xceC\x1f\xbf\xe7^U\xe6\xbd\x00\x07 \x92\xd0\xe8\xe2\xfe*#_\x11\xf2\xb9\x13\x80\xd8\xa8K\xc3!\xfb\xa5\xc9\xde\xd1\xe8%\xcf\xe6m\xbd(9\xbe\xe5\xfa\xbai\x1d\nM_\xe1L\x82\xbb\x7f\xbb\xd1N\xa00\xc0l\xe0\x01\x02\xb3\xfe\x16\xec\xc0\x80A\xfc1W\x1b\xee\xec\xf8\xf8\x99\x89/\xc0\xcc*E\x1b\xa3\xd8\x90\xfb\x90-X}-\xd8\xa5I\xb4\\\xc5GC0e\xc1i\xe3z(\xf1V\x8d\x8a\xa1\xfcn\xad\xfc\xb9p\xed\xff#\xd6\x8b'\x8d\xc5{\xc2H\x91\x83`\"\xd4\xc9\x98\x1f\xda\xa3\xbe\xcf9\"\xfb\xfa\x959HZ\xa4\x16d\xc0\xf5\xd0m\xd9T\x05o_\x84\x07u\xe0\xd0\x08\xcf\x92gB\x01(\xd1\xc0P\xf5\x18\x8a\xf5o\xa6\xce\x87\x06\x19\xc5;E`\xaci\xfdIm\xfd\xe3\xab\xae\x7f\xd3\xfd\xba\xb1\xfeIke*\x15e\xb3E4!\xde\xc0\xde\xa68\xa6\xba\xb4\xcb\xd0\xd0Q\x1d\xa5\xeb\xca\x05\x83\xeb\xdd\xe9N\xd1Z\xeb\xdd\xa7\x91\xac\xae2\x8b.V\xa6o\x8d\xcf\x16(U\xc3\xa0.x\xc5X\x11;\xd8\x18\x92\xb8\x1c\x99\x8c\xa8|\x16\x8e\x1e\xc5`]\\\xc1b,.\xa2V\xe95h\xb8_{\x95\xa6\xab\x16\xaa\xa2\xa3sZ\x1f}\x99\xa6\xc7\x18\xe3W\x9cLi\xe5d\xc22gQ\x95d\xb1\x83\xe6\xa1\x8fw#\xfb\xe9n_\xc4\xb4\xb6\x88\xd1\x95\xd6\xef\x8fXWa\xba\xb6\x86\xdd\xd4V\x85.\xa9\xa9\xb9R\x10\x14\x0e\xf0L*\xa8\xbd2\x99\x8ea\xc8\xea\xcc\x06\x06=\xd4\xc5\x95\xb5\xa0\"\xee@]\x92\xf2hQ<\xbflH\x11\xf3=\x97\xd6\x10!\xad$\x13Le0H\xac$\x13\xc4o\xd2\x16&\xd0i\xb2n:R\xa7\xd9&z\x1db9S\xed\xd9\x97\xba\x9d\xdc\x8e\x91 \xad^\xff\x92\x9fH\xdb\xe2\x07D\xbf%\xa0\x03\xee\xd9\x8f\xcb`\xb2\xfa\xeag\xc8[je\x1e\xda\xb2\xf3Y3\xf3\xb9D\x05\\\xa0\xd6\x15\x85\x9a!\xbc\xd7H\xef\x87q\x00Otz\xd7\x0fO\x9e\xbe4h^\xdf\xb2\xf7/\x1c\xa4\xfd?\nw\xbd\x96\xfc\xa15\x8f=kF\x99\x92\x19\x8eTN8\xaa;\xeaE%\xfdK\xf9\xaf*upK\x19\xf8\xd9z\xea\x1er=\xc0!\x03\xc8\x1f\xb1\xd7pO14z\xd4..\x16ho4K*\x87\xd3\x08ut\xec\x9f&J\x18!\xa9\xa6\xef\"%o\x1c\xfb\x01\x94.\x93Jh\xc4\xfb\xf5\xf2$Y`\x85\x04\xdb\xf3z[\xb4\x06\x11\xf5\xd7\xdbx\xf4\xa4P/\xbeu\xd1\x06\xbe\xb5i\x03\xdf\xb6i\x03Y\x17\xaam\xed\x8b\x9aE%\x80\xb8\x7fT\x12\xc8\xaf\x01[\xa6X\x97\xfeK\xa4\xc4vH\xf3\xf5\x8cz6V\x04\xc4\x82S\x91\x1b\x97g\xda.\x8f\xf6\xcdFk\xa3\x87\x1acP\xe6{0\x98\xde\xac\xa6m*\xb0GOc\x1a+\x88w\x9b4\x81&G\xf1\x94\\\x90\xe9{\xf2\xc5\x010\n\x89\x7f#\xa2\xce\xddz\xf9\xe9\xbd{\xeb\x08\x1cm*l\x17\xcd\"W\x87pa\x84p\xefn\x1d{!\xa7,\xd2\x94]\xd2I!\x17;\xf6\xde\xa9\xdb\xec:\xbb\xed\xbcI^u\"\xa6\x9d\x9a\xcf\xaa\xb3R >\xce,\xac?/WY\xaa!\xe4\x9c\\ \x052\xae\xee#\xbc\xb86\xd0\xbf\x8a\xb2\x0eK\xbe\"\xd7\xd5/7C\xb8\xf7\xdc\x1b!\xc7r\xb2 \xe3\x9eK\x0f\xa5\xa9\xc3\xb1\xfc\x85Y\xbb\x04\xdb&\xc6\xf2\xba\x9f\xbe\xf2\x12\xc3\xcc\xb91\x8f\x97\xd9e\x94?\xc5\xb0\xc7}\xce\x14\xc2\x01\xe4\x98\x92|\x1fB\xea!\x7f\xd8\x8f2\xc1'J#\xe0\x88\x8e\xb5\x94[\xbd.}wOo\xf5*\x10\xc0\xe2\xf5\xad^\xa6\x8a\x1dP1\x16D\x0d+\x8f\xfd\xabA\xed+\xfb\xb8\xcfD%\x84h\xb4\xebP\xe79)\xed\xad\xb8\x08\xa1\x97\xa0\xc7\xae\x0c\xc4\xcd<\xa5\xd0j\xb3\xde\x96\xbc\xcc\xd9W\xcfD\x95(Q\xfdBW\xd7X^\x92\x92ci\xe9!L\xeaT\x14\xc7\xc4$N\xf9T\xd2S?\x90\xf7f\x8b\x90R\x12{[\xbb\xc2\x12\x83\xdaEM\xd1\x13\xebV\x00\x01\x1c%\xcd\xa8\x13\xba\xc8-\xc4\xfd\xa0\xec\xc0\x87f\x1fJ\x85X\xd86XN\xe4e\x06\xf8%\xaf\x8d\xd6,g\x8b\x0f\xa5\xfaV\xe3\x0e\xed\xc6\x8eH\x8f^\x97\xb4\xc9*\xbbV\xf5 v\x897\x98\xda\x12#k\x0b!4n\x91\x98\xa6Qe\xac.CU\xf4{\xef\xdc\xba9#\xe9\xda\xf1Lq\xe4\x82cK*\xf2\x16.8\x0d\xc0V\xf2\x13\x8a@s\x8e\x03\xbc\xd6\x11~\xa1\x14Z\xe3Z\xa2\xad\x81\x01\xf8uG\x12\xd0\x03\x86\x13]G\xc8\xd4O\xae\x1f\xd4|\x82\x9a\xf0'0\xf5\x19Ok=\xbaT\x8db\xc0d\x9fbNT\xcf`\xde\x00UOz\x80 M\xf4\xe5\xc15\xc3\xe2Z\xa1n\xb0\xa8 KP_q\xeei\x89y\xbb\x89\xaf/S\xa3\x19\x08\xe3@\\6o\xbd\xef\xc2\x92\xc2\xe9!\x1c@\x0f\x19\x1f\xd8\x87^\xd03c2#\xc1=\x8d\x1eU^\xdf\x82\xe96\x1c\x8fE\xa9\xfe\xad\x01\xba\xacn\xa3\xd2\x14\xffE7\xa3-YBJ\x99\x14\xaei\xe1E\x83gN\xaf\xc9Y\x82\xd8\x01N|\xdbg\xb2\xfe\x06\xf2\xf3\xd4iE\x97\x159\xd4\x01\xad\x8a-VM\xd9\xe9\xd4\x19?K;n\xb0\x00\"\xeb\x02\xd7p\xad\xe1\xa0\xf2\x08\xf60?\"\xc3\x14\xd8\xe7\xf9\x90\x1a\xdbAU\x03`\xcdZ\x1b\x01\x84\x03\xf0\"A\xe5\xb09_\xb4K\x8b\xd2\xb7\xbcb`b-\xc8\x9c\xba\x83\xec]t:\xa7\x1d\xe1& \x93\xca\x08\x95\x86(;}\x12\\\x8f0\xbd\xa7F\xbb;\x98\x06\x8d\xbd\xb8\xe3n\x81Tj2\\\xa7\xae\xd0\xb8|E\x0c\xfer\xb5C\x82q#\xddz\xe4yYx\xac\xdc\xbb\x18K\x85\xe9\xb2`\xe8\xbaJ\x9djL\xd4gf\x0c\xc8\x01}?(u\x7f\x03\xad\xf9\xd9\xa9\x97\x93\x9c\xbe\n\xbb\xa8\x07\xf8\xbeF\x0f\x99\xdd\x00v\x06N\xbdD\xd9\xe1rE]l\x0c\xa2\x17\xf5dR\xe4\xf4\xba\xe4\xbe/\x96\xb1\xca\x8c:\xf0\xa2&#\xa4\xd3l&I\x1e\xd7w~\xcb|\x9ex\xb4T%\xf1m/\x04X\xfeq\x07\xbd\n\xf6\xfe\x83+{*\xfaw\xa5R\xa0P\xaa\xaf\xd4\xf3K\x83\x94-\x03\x9eD\x0d\x1d\xf1nc]\xf1{\x917\xc1+\xeb\x94\xf3J\xe2lW\xaa9\x8f\x9d\xa46E\xe6\xd2\xb3\xbb\xf2\xb2\x94R\xc1\xb3@5\xb7\x19*\xe4]\xaa\xe7\xad\xcb\xea\x91/y\xb8\xe8\"l\x9d\xd1\x82l8\xb5/\xb2f:l5\xd5\xe1T\xbf\xb6\x18\xa8\xd5?\xc6ty\x95\xe2L\x94\x96\xf7\xed\x9cb\xb5z\xeb\xcf\xb1_S\xb5Z\xcf$\x0e\xc6A\x0b\x1d3\xc3@\xa2\xa0\x1b\x05\x8e\xaa\x94\xb7\xd5\xfc\xa4P\xb0\x00\x12OG\"\xe5e\x18\x7fgQc\x1ev\x913\x90\x0e\x89\x84\xcbK\x1eC\xb0t\xec\xe5\xa8\x0b\x0d\x97\xfdp\xaf\xd1.=E\xd9\xfb\xfc\xc4\xb1\xc0g!\x03\x0eM>aE\xa5\x14nu\xe6<\xba\xa2\x13r[\xda\xe2<.\x12\xe3t\xc8\xa7\xa5\x9f\xe2\x8a\xf1B]&\xe9\xd9f)`\xa6\xcc\xd2/n\xba\x9fj\x9f\xc9\xfa\xed\xac\xc3\x90\x8aC\x8d1s\x9d y\x0dFB\x1eq\xee~\xc4W\xb42lW?mH\xa9.\xdd.\xba\xab\xd1\x1a%\xbf\xfa\xc8\xcf\xba\xf7\xf7\xf2*\xebb\xe0\xbdq\x8d\xb5\xb9\xac\x9a}/\xc3\x8b\x0e\xbd\xbe$\x9dT\x18\xcb\xf0\xa2\xeb\x99\xfa\xb2\x92\x8f\xc8\xa9\x137\xa3Yc\x06p\x00ob\xee\xc2\xf2\xd5MPZF\xf1\xd5\xa7\xc3\xbb#\xbc;\xd7\xb9\xa5\xa43&jC\x1eA\xdf|\xf69Zu\x80\x9d\xd2\xfe\xeb\x90\xce\xfb\xcb\xf0\xc23T$6tV\x17\xbe]\xa5\x04\xc3\x1ecMzT\xb9\xe3<\x90_\xe7\xd1\xa2\xa3\x99\xa1\x18\xcc\xefW4l|\x8eV\x1fc\x1a-\xbau\xcb\x81.\x87\xdcM\x05\xc5\x13\x82u\xeb\xafi\xe5\xd0d\x06\x03}\x7f4\xfcL:,/\xad\x18 \xae\x80R\xac\xbfkF)\xd6dw\x94b_}\x0bJ]E\x92\xf8\x87\x13w\xab\x940\xfa\x18\xa3\x9a\xb7\x92\xbc\x0d#+[\x18^\xc9NS\xa3vY^L\xa4\x8b\xaa\xb1yJ\x81\x96J\x18\x08vlo\xedL\xd4\xf3o)\xfb_0n\x1a\xc1\x87\xa2J$l\x9b\xa1\xd2L)\xfd\x14\xdf\xde\xbc \xdb\xdb9\n\xa9\xa2AC\xa1ry]\xfa\x01\xe4\xc67.\x03P\xcb \xfd\x17\xadJ\x92vY\x16Z\xf1\xc6b\xdf\xd9\xe5Zv\x85\x16\x8f\x12y\x89q:FY\xaa\x17\xfaN\x85\xc5L\xdb?\x00\xf7\x88G\xf5\xb2F?\xaa\x97!VB\xbd\xa4\xe9&o-N%/\xae\xc3\xaf\x14\xa9\xb2x\xa9\xcaKF4R\x11\xc3\xdb\xfa\x01\xbb2\xe1\xac\xea\xf6\xf6\x04\xdf\x1e\xb4\xb8\xb6\x82n\xafM\x02\xc8P\xe3y\xc0H\xdbp\x08\xef\x84\x98\xf3\x9cad\x86/\xf04\x7f\xa1\xf0\x0c\xf9/X\xdc6\"`\xa5\x00\xda\x87\xdd5\xaf\xec\xe0\xb9*SQ\x1cZ\xdd\x98\n\x19C\xd0\x91/\xed.\x86\xcd\xc3l\xfe4\x99vpt\xa1\xf32\xbb\x00\xd6e\x9a\xab\xd9\x06\xday\x04(\xb6\x17wP\x1e\x0ea\x00\xb7`\xb7\xd8h\x16\xd2%\xcd\xa4\xb3V\x05\x9f\x9b+\x7f*\x8a\xdf\x0e\xf4Uo\x8b\xd7\xf8\xc0\x9c\x16\xbf\xf6\x0d\x1b\xed{\x14\xd2o\xdf\xb9\xbd\xf7`p\xff\xf6\xdd\xdb~P\xdc\x86G\x8f`p\x176@\xe0\xf1\xe3\xc7\xb03\xb8\x1b\xc0\x9d{\x83\xfbw\xee>\xd8\xfd\xbe\xfe\xdem\xe5\xbd\xdb\x01\xdc-\x9fc:w\x8f\xc06\xdc\xbe\x7f\xef\xce\xde\x83\xbd\xc1\x83{\xb0a0\xfd\x17\xdb\xd2\xff\x12\x9f\x0d\xee\x05\xb0\xb7w\xe7\xde\xfd\xbd\xbd\xbbE\xf3\x87\xe2s\xec\xa6x\xf3v\x00\xb7\xf7\xee\xdd\xbbs\xff\xc1\x83\xdd\x07\xbe\xda\x84e\xcby*\x7f\x10c\xad\xcb\x83\x8eP\x83!\xdc\x1e\xc0w\x90\xc26<\x8f\xbd'\x147\xcd\x13\xea\x11\xdfg32w\x0e\x8e\xbbS^\\+~\x85^\xaa\x93r\xe9\xa6\x98\x11v\xd4\xdaA\xb7\xc6\x1d\xdb\xf5\xb5\xe5\xac\xa1 \x88:RX\xb9SW\x06\xb3\xbd\xf8\x9a''Sr\x01\xa8o\xbc\x8eG\x0b\x19\xe0\xfd:\x1e=c\x7f\xbf\x16&\x8b\x8c\xdd\x12\xa1\xa3\xfc\xb6\x08\xac.\xee\xab\x81C0\x84W1>\x89\xe2l\xc5s\xe3\xe3'\xef\x93<\xad\xe6\x95\xd1\x81\xac\xa6D\x12\xee\xad\xd5\xd9a\xeb\x93y\x18\xc5\xbcma\xcb\xe4\xb7\x93\x98\x86\x11F\xa5\xe3\x10\xb8\xee\x12c\xc4S\xdd)9[D\x1dB#\x0b\x01\xe5+1\xae\x84N\xed\xb3:l\xb8\xf7\xbbZ\xff\xcdT15\xcb\x02V\xe1\xae\x93a\xb5\x90&\xa4\x93\xc4( \x1a\x9b\x8bO\x03p\xa3\xaab\x93t\x14\x1a\x97\xe1\xeae\xd5\x07\xd9\x15FW\x00\x02[\xf7:,\xda\xc4\x8c\x06,x4\x82\x05\x08\xd8\xc9Uv\xeb\x87\x18\x93\x9b\xb4f\xeexj\x06\x92<\xd5\xaa}\x19\xda\xf9\xb9\xb5\x9d\x11 \x80\x8e\x9d\x1a{g \x87\xf5\xb3\xb9e\xb3mQ\x97d\\\xd0\x84\xa7aXo\xaegX;\xd7<\xacW\xf6a\xf52\xa4\x81\x15\xe3\x07\x1c\xc0O\xef\xdf\xbe\xe9\xf3G\xd1l\xcd\xd5\xb6\x82Z:\xe6\x16}f%\xc0\x87\xc6L\x9e\x86\xe6\xbe\xb6b\x10\x85G\x05\x07G\xe11\xfe\xbd\x83\xec\x9cS\x07\xcf\x1d:`\xac\xcf6\xec\xdd\xbb{\xe7\xce\xed\xbb\xdf\xdf{\x00\xdb\xe0Q\xc6\x90\xdd\xf3\xf9\x9f\x8f\x1f\xc3^\xf3\xf4\xad.\x94h\xedCT\xaf\xc2h`\x95\xcb\xe5\x95|\xb3\xad\xaeu@J\x1b\xdeV\x82\xa5\x00\xf8\xba\xf2\xd0R&\xa2G\xbe\xaf$-\xc5f\xc5}k\xcb\x97\xac\xf7\xc0\x96GC\x85\xa8\xdel\xe7\x0c\xd2\x80[\xee*1~\xd8\x7f\xeb\xe4\xdd\xed\xa1W\xb0\x9f\x15\x90\x8d\x18ds\xf8\x1f&;\xb0\xad\xc7p \xa9\xb8\x00c\xcc\xef>\x7f\x07\x0e\xe09\x9b{\xce\xd3\x91\xa2\xd5F\xfe\x8cd\xca\xd86\xf0[\xad%\x86T\xe5%\x95p\xde\xc6\x0b\x12\x9e\xb9p^\xd2,7b]\x8c5\x87\xb2oY,\xb6/op\x02 \xf5/\x01\xdc\xe8'3t\xa65~\xc6\xf3\x93(\xde\xf9\xd6s\x96\x14\x1b\xdf+\x88\x81\xb8\xc7\xe8\x80\xc8H\x13\x94\x94\xc8\xcd\xc7\xa9\xab\xcb\xdd\x92z\xbbj\xcaj\x97>\xae\xe0_\xc7\x0e|\xc7\x08\xd5\xebv\xefq<\xf9\xbf^I\xafzC\xfe\xf1,\x0el\xc8\xe6<\x86_#:w9\xa7\xa4\xcc\xa3\xf6b\xc77\xc6\xd3\xc9\x00\x81\xe6\xf8M&\xcb\xca\x9dK\x9fQ\x842=\xec\\\xea\x1b\xd4\x9bE\xdd\x96#t\\o\x0e\xbf3\x8f\x85\x18\xc4kA\x0b\xb3\xb2\x93\x9cv\xd5|:\x9a\xaa\xd3p=\x9b\x0d\x9b/s\xb89@;Q\xf2l\xf3\x12\xda\x15+\x81\xfaX\xb1$\xa8\xb7+&\x85\x17\x81\xaa\xa4\xf5\xf1\xde\x8d\xca\xf2\xf1{?V\x9a\xe6\xf7N\xa8\xe6\xe3s\xaa\xf9\xfa\x82\xd6?oBE\xe6\x97\xdb\x87\xb8 W\x04\xea\xcb\xe6\xfd\xa7\xc9bA\x10\xd2\xfbp\xac)\x90\x81\x01b_5\x0f\xd4\xb4\x92G\x1a\xe7 \x9e\x97o\xa5y\"R\x05^hGI\xf7!\xd3\xe5{\xbb\xbb\xd3O\x9f\xf2\xe9\xfd\xdd\xdd\x1d\xf6\xefl6\xfb\xf4)\xdf\xbd\xcd\x7f\xee\xde\xbe\xc7~\xce\xc8\x1e\xfe\x9c\x91\xbd\x19~3\xc5\x9f{\xbb3\xfet\x97\xf0\x7ffc\xd3\xe0\xcc\x14\xad\x100(\xc9\xa8J\xc7.\xbb\xc1i\xb0\xfb\xa0\xc6\xeb0.\xb2wx\xb1\"\x13J\xa6\x10\x16\xed\xf4\x14c\x8f\xbc\x07\x89\x96\xb0G3\xf0\x94\xf8\x88-\xc5D\xb0\xd9\xc8\xecA\x1cE\xb4\xaf\x11\x1f\xe8\x9e\x864<>\x16\xd9F\x9bX\xa9h\xf1\x84\x14[\x83\x0c\xbb&\x9a\x1aTQP\xb9]\x14\x82M\xaa\xf7yQ\xc4\xbcz\x933\xc4a\xf5f\x86ofUB4\xe9\xb6:\xb7\x1f\xe8\x97\xe7\xce\x83\x96\xe3\x18\xa8\xc8\xcb\xc1Co\x1b\x8e\xeb\xca\xe6\x15\xc6\x0eOT\xe6\x04R\x9c\x80\xf2\xd1V\xc4\xb8\xab\x9b7\xd9\x1f\xb1\x8fJay8\xc6\xec\xaf\x98\x1dA\x95\xfe(\xeb\xf2\xca'\xfe\xed\x07\xb7\xb5\xb3\x1e|_G>\x81\x94\x0f\xeei\x90r\xd0\xc4\xc7\xbd6\xd2!k\xb9pG\xe1\x99\x0e\x15\x17\x98\xb5\xf8&\xe4\xcd\x03\x17\x0b\xb2\xca\xb2\x8c\x8d\xa7s\xc4H\x9dY\x8a\x11\xa8\x15\x03\xe4\x1c\x81\xec-\xd8?sx\x0c+;]F\x9d!\x0f\xd0\xf5\x9b-bAK\xfeX\xa9-6\xc5%n\xb6u\x06C\xd8\x194G\xbd\xe62t\xe3\xfe\xa9\x00C\x08\x07|'\x82\xf4\x8e\xae\xb6\x8dy\x01fx\xfc#\xa9\x0f\x80\xff \xbc\x06\xe8\xf6\xf6\x19<\x82\x956\x11\x00\x1b\xd6\x92\x81ttf\xe0n\x8e\xb1(\xcc\x99\xc6Q\x9c\x01 \xf3\xb1\x89\x13\x18\xc2\x02\x0e \xf3\x8e\x03X\x06p\xc6\x03\x91py\xf7!\xf3\x96\x01\x1c\xe3]\xbe\xfa3\x0d?SK\xe2{b\x92\xae\xd9{'>0\x018\x8aM)\x0b\x10\xa2\x03\xfd\xb3\x93\x94\x84\x9f\x1bO\x9a\xe7\n\xeb\xe8\xd46\n\xb6e;\xd8\x0c\xf0\x93\xc4;\xc5\xd7n\xde\x04oY\xe6\x8c\x9e0\x08Q\xb9-f~\x89K\xa7<\x16\xdf\x18\xdel\xeb\xd1\x06\x050B\x02\xb4\xd0\xb8\x04\xb2\xc8\x08Nb\x89\x0bt\x8c\xfbh\"\x96\xb6\x18\xb8a8\xdf\xba \xda\x13y&N\x10t\xba-~0\xfc_\xff\x9f\xea\x876n\xc8H\xa5\xeas\xa9\xd4_\xdb\x11 /%\x11\xa7\x98&o\xbf\xa0Ml\xdb\xc5\xf0\x08\xd2\x87\xcd\x95C\xd3\xb8GG\xf1\x18\x01\xa7r\x86\xbbZ\xfeOI\xef\xd4\x91\xcc\xdf\x19\xd4y\x83\xe2pkRyQ\x91\xa98^\x9b\xf4\x1e%\x19\xa5\\S\x93\xfc\xa3*\x08\x9f\x1de\x87q\xbe\xe4\x8a\x9f&{\x92\xda\xad\x1db\xe2\x85\xb8VE\x06\xcf\xf7\x85 \xde\xae\xec\x13\xad0\xe6\x9bak.X\xcc\x00z\xec\x0fBz\xfc\xc4\x0d\x9b\xf7\xab\xfd\xe9\x8f\xb4\xcce),\x99\xf2\x15\x06Qch\x10\xeb4\x18h\x9e%m*\x97-\xd2\x8f\x93)aB3\xdek6\x81\xab\x89\xa2w\xb3\x1d\xca\x8d\xd4\xac\x1dZiG\xa3sbk\x9es\xe0\x16\x90A\xc1\xe4\x00\xd2\xfe\x0f\xf9lF\xcaS\xab\xf95\x03\xa3\xc7\x8e\xb7\xb0\x1fe\xb5\xb7Q\x8a\x8d\xccJ\"E\xe2\xa9(\x89\xee\x0f\xfc\xc2X\xdc}\xdf\x1b\x988\xda?''\xabp\xf2\xf9\xe7d\xb1\x9eE\x8b\x05\x0fY\xe9O\xc9*%\x93Z\xedG&O0\x96t\x15\xd29k}4\xc6L\xf1\xf3h1MI,\xbe,~\xb2\xe7e\xb9\xb4)\x99E1\x91\xfb\x0bqr\x91\x84S2\xed\xe9\x14\xab\xa4\xd8a\xfbz\x0e\xa2K\xd1\x19\xda_4\x1e7\x95\xd4\xe6qF\x7f\xc9\x18#\x8716Wk\x08\x83J\x02\x9b\xced\xd4 #\x0c\xea\\t\"\xee\xdf\xd1p\xcb\xb8\xdf\x92~\x94\xb1\xfd4\xe5Q\n\x95\x97\xf8f:\x80\xc8\xcbQ\xe5\xa4\xa7;a\xb7\xb1\xdf\xdd\xbd\xaaZ\x91\xf2\x83\x8d\xd1\x81\xb4]\xb9\xd8\xbe\xb74g\xaa<\xc9\xe5;Z\x87\x17\xa9!\x10\xfa\x05\x91E\x90\x8e\x85;_\xcd\xdf\x84p\x8f\x92H\x16'\xf4\xe2\x9a\xa9\xeb\xf2\xaaX0\xb8_\x97\x818\x16|\x7f\xbf\x15\xc2m\xec\xc4.\xf72\xf0\xb8\x1a\x88\x07\xf1\x17\x9cD\xa1X\xe1\xd2\xe0#H\x1e\xfa<\x85\xe8(\xf2\xc8(\xde\xde\x1e\xfbc\xbdv\x8f\x7f!\x082-h\xebU!\xa0\xd7\xd9\x0d\x1a\xd8.v\xc1^\xfd`\xe3\x8a\x8c;\xdf_\x05^bJii\x18\x8c\xc4{\x07\xc0\x90a\x1f\x12/\xaf\xb8 9M\xae\x97g\x042\x9aF\x13\xaa\xa8\xf6*^X\x0d?\x11\xe9j\x13{\xdf?\xa8\xebF\x94\xe9\x1c7E@&\xbas\x98\xdd\xfb\xbe\xf6\xe5q\xff\x1d \xa7\x8cN\xbe\xa7\xfc@YV_`\x80\xbe\xeb\xf7\x0f\xcfHL\x0f\x97\x11\xa5$mv\x10\xb6\x81Q^%\xd1\x8f2Jb\x92b\xd1M\x8er\x8d\x0ft\x96{\xb1%\xea(\x01\"\xb88\xf6\xee\xef\xfa\x82\x03h\xbe1CA\xfdc\x14\xd3\xfbH\x07\xd9\x9e\xad\x9c\x9f\xcd\x99-85\x1b\xd4\xc0\xb6\xe8G\xf1\x9c\xa4\x11\x15J\xaf\xbb\x1a\xf3\xc0\x8a\xa3\xdd\xdd:\xb1\x06\xa12\xd0 \xd5\xec\xfe\x8am\x9fU\x7fJN\xf2\xd3Er\n\x07\xca\x0f\xaf\x97\xd1\x94\x84\xcb\x9e\x0f\xfbmC\x9f\x06(\xfb\xb3!\xd4w\n\x08\xe1\x88\x81\xb2\x8eK\xe5\xd4\x98X]7\xf9\xb3\x86O\x19\xf7\xd0#i\x9a\xa4=\xc6\xbd.\x92\x8c\xb0?\xa6$\xa3i\xb2f\x7f\xae\xc2\x9c\xdfKI\x96/Iol\x8a\xd6Y\x1a\xd1%\x01\xa1i\x8e\xbd\xbd\x81\xa8a\x81b\xab\xae\xbe\xa0$\x16\x04\xa28\xa3a\x94w\x86\xe5S\xdf\x0f \x13j\x85F\xb6?\x13 OJ\xe5\xb8)\xdaS\xe1!h\x0d\"M\xb0 \xdd\x147i{ym\x8f9q \xa8\xaa\xe2{X\xae\x93^\x89\xc7_\x14xfSJ\x9e\x15\xc5\xdd\xc4\xcb\xacu[*\x15\xce\xc3J\xaa\xc4\xa0N\x04\xdd\xe2\xaa\xd1\xd8\x0f\n\x9d?l\xb3\x86\xab\xd4\x17\xf6\x8b\xaf\x0dJT\xed]RR\xae\xdd\x00\x0e\xb5\x86I\x06\xba\x1c\xeb,zH\xb3\x11\xdf\x9d\xe0\x8aP\xd0\xcf9\xe5Uy&\x85F\xc4KQ\x15\x92\xaa\xdbf\x86\x94\xa6\x19}I\x94\xb8\x83a!\x0c\xd5NK\xcc\x12\\u\xaa\xe8\x1d\xc5g\xe1\"\x9aB\x9c\xc4;\xbc\xd9[\xe2p\x98\xcc\xf3\xf8s\xcf\xb7\xc5\xd3\x18&\"\xb6\xb5\x06n9: \x06\\*A\x02\xee\x15\\L\xc2\xe0\x99\xd7\x86,\x1c\x89\xc4*?\xc6\xc8\x1f\xcf4\xff\xfa\xc7e\xa5\xf9\x9f\xa5j\xf3\xed\xcc#<]\xb1bND\xd8\x10\xa7\xe4#bn\x13\x0c%\xd7\xe3\x06N0e\xa7\xb4z\xe45\xe7\xcb\x16B,\x02\xe7(\xfby\x9c\xcd\xa3\x19\xf5|\x08g\x94\xa4@\xe2)\x10\xc6\xf5\xf7\x10\xd7\xce\x11\xedd:;\x04\x16GU\x97\xb6q\xcb\xc8\x86\x0f\xdf>\xe7M6\x88C^\x1c\x19L\xfa\x8f\x19\xb4 &>\x92\x9b\xf6<\x8d\x84\xae\xbd\x0em!\x85\xcb\xb5:\xa8\x8cw\xc0z{[\xee\x9b\xea3\x9fW\x8fb\xcbP\x1d\x90\x0e\xfb\xea\xaa\x83\xb6\xb5\xda\xa2\x02LH\xb8\xab\xdc\x04n\x92\xa2HV\x8d9,\x99.j\xa4#\x97^\xeeF\xe3\xcf\x15\x1a\xaf\x1b0)\xb8\xa8\x9b7\xe5\x1eVh\xdf\x16\xe1l\xd1\x01\x9b\x02_\xebiHC\xb6\xd4\xa8\xf7b@\xf3v\xf9\x9a:\x12E\x8e\xa4\x05M\x95\xc8\x17\xb36t\x94\xb6\x02\xb8\xff?{\xff\xbe\xdc6\x924\n\xe2\xff\x7fO\x91\xc2o\xc6\x03|\x84h\x92\xba\xd8\xa6M\xeb\x93e\xb9\xc7\xd3\xed\xcbH\xb6\xbb{\xd8\xfa\xa9!\xb2H\xa2\x05\x02l\\(\xab\xc7:\xd1gw\xcf^#\xf6\x01\xf6\x9f=o\xb0O\xb0\xb1\x11\xe7MN\xef\x03\xec+lTV\x15P(T\x01\xa0,\xf7\xec9\xdf\x87\x88nS\xa8B]\xb2\xb2\xb22\xb3\xf2r\xef\x1e\x92F\xc7e\x8bJL\x9a\x16\xfa\xe85\x87\xe7\xd2}C.\xb8\x18\xd4\x9d\x1b\xa9\nU\x17$\x85\x7f\xb8wO\xf7\xba\xe0\xfc\xaaK\xac\x91\x81\xdb\x05\x0c6to\xd7\xf6OO\xf86F\xc3\xe7%\x83\n\xc1\x88\\\x8b\xdf\xe5\n\xe7Y(\xd7\xc9\xffRj\x15u\x1a\x0f3&\x0d vdA@\x11D\xe3\x06.7N\xeb\xb6ix]\x8es\xdf\xc8\xec\x08\xf5P\x19\xd1C\x91\xebN\x1b\xa9\x80.\x02\xd25f\xf1\xa6r\xf3,Hv\\f\xb8\xa9\xc0#\xc8>\xbbl'\x98\x99\xd1qyg\x8eK\x19\xb9\x92SB\xc5\x9fC\x81 \xdfs\x8d'\x0f\x9f\xa3\xd4<\x93 (\x87\xa2z\xc4+]\xf8\xc9[/K\xca.P5]l\xf5\x8b\x94_\n\x86r\xfaT\xd7YBd)\xa9\xd5\x9c\xda\xc91\x95\xcd\xa2\x885\x86z\xb2p\xc3j\x94G_U\xac|\x84\x11<\xdcy\xf8p\xbf\xf7\xd0\xa4/95\xa2n\xae>\x7f2b\xfe\x8dU:N\xf2#\xbb\x87d\xb6B\x9dS\xa6\xf0=(\x1f\x08\xd2\xa9\x9a\x93\xe6\x05\xf1\xa6]z\x08\x88\xb2aQm\x88a%\x80(\x07\x1ac\xa2U\x8dA3!\xcb'\xf6t\x04\x1fQ K\xff\xa5\x9dloSY\xeb\x13\x1d2F\xf7*\xfd5(\xfd\xb5[\xfa\xeba\xf9\xbb}\x17\xd2NG\x9bk\xe0\x86\x9d3\x08U \x0e\xe8!\x92CS\x9e9\xa9h\x0cz\x98\x9f\xb9\xd59}\xac\x87Bn(\xd7H\x8f\xaa\xbd\xf7\xe9\xe9\xa9*+(\xd6/l\x8b\xbe\x16\xef,\xb7XtG\xf7\x0d\x9bI\xce \xb0|\x1f\xef\xfc\xc9\xa5}\xc8#/\x1eV\xdceM\xf3<\xd4\xcf\x93\x0f \xc4$-\xe4.\x18\xc3!\xbf{\xd56\xa0\xcb\x1b\xe3n!%}\x08\xb2\xe0\xaa\x86\x04\x9d\x8e\xf2I\xfe\xa4u`2u\xfc\x93\xb1\xe3\xd2\x05Ln5FY,\xc1z2\x86K\xda\x7f[\xa4\xe0!I\xc10\xea\xf6\xd7\xc2\xb6\x96\xde\xf5\x05\xa1\xab\x86\xf3@\xf5B\xcf\x92\xd94\x17m\xfb\x8a\xce\x9d\xc7Ny0\x0d\xc0\x1a\xa9\x89\xbfL@\xb84\xaer\xae/\xa1\xe0M\xfd\xc9\xa5n\x9c\xad\xfax\xd9\xbc\xc2\x02\xdb\x99\xe6M\xd7\x13\xe2\xbb^1G\xaa\xca\xb4\x1c!Q\xb3\xcd\xd1\xd1\x05u\xc9\xa4\xe5\xdclJ\xaf>\x97\x08 \x8a-l\x8b\x8e\xa7\xb4\xad\x1f\x97\x07\x99\xa7R\xe6\xe3s\x1e+\x02\x8fi\x84\xef\x9a\x0e!\xe5\xe89`]!u\xac0J\xf9\x91\"\xc4\xcf!l\xa5\xec6\xf5i\xa9\x0d\xbb\xa4\xc0\x91\x0f\xa3\x9f\"?\xb4-\xbc\x13\xe9\xf3\x9eyI\xcd\xc1%\x0b\x1a\xdc\x9f\x92\x14>\xb1EQ@\xbc\xd8F\xd9&\xd4X\x94\xd6\xa9Z\x0c\x1a\x8a\x94\xed]\xf5\x00=\x00Lu$\x97H\x91B\\\xb9@[-u\xf2,\xc8\x1c\x06\x9a.\x88\x04\xe5p\x93\xf0\x96\x05\xc5\xa2\xad\xea/\"\xc4\x13Wmt\xd5\x07\xef1qlf\x15\\\n\xdb#\xf0\x8dDI<\x88\xed\x8f\x81\xc5r\xa4\xf4\xa46\xf7\x14\x08uf>\x80\xfa\x81\x82\xb8\x91\x81\xa7\x10\x15p\x8c\x8a\x13\xbf!\xb2\xb2?\x03;c\xd6I\xc5\xe7>\x95\x8e#\x18\xf2\x1f\xe5\x85f\x9b\xc7\xc6\xe9g\xb5\xa6\x96\xe2\xa9\xb4ow:\xb1\xcb\xc1\x81\xab\xbe`Zf\xfefX\xbc!\xdd\xd4\xf3\x03\xae\xe7\xe7\x02\xbc\xa8\xecr\x08A1\xc4\xcc\xa4\x91\x93\x1f\xb3\x85\xa7xn:\x1d}xc0jFA\xb2m\x17\x13\xddFw\xa0\xaam\x0e\x085)q6\x89\xab*p|\xd2\xf5\x82 \x9a\xbc\x0f\x13oF\xdaE\xe1m\xb1+(\xca\xd7\x98\xc5\xc6l\xa7N\xa2\xd55\xaa\xde\x04\xe7c\x97\x83\xe4\x8b\xe0\xbc\x1eSaS\x9c\xf7k\xc2]\xb8M\xc1\x974\xb9\xee\xf0+~\xde\xb9\xc5 K\x19E\xc3ev\xb9{\x13\x9bp\xf4\xb9\x8c\x0c\xbb\xde\xe1\x13\x7f\n=\xd95\x93)\x98\xffd\x910\x17Ql\xc7\x024\xa5\x9dB\x14\xe2\x9d\x02Y\xae\xd2k`J\xe8?i\xe6Bd%9\x13\x02\xe4\xfb\x17\x89\xfd\x7f\xabMrb\x8c\x1dj\xd6\\)=rU\xa1\x98$\xb3\xd2,_V\xf7\\\xce\xcbVD:\x9b\xce\xdej9\xa6\x93v\"I\x8fk\xbfr\xc9\x84\xd9\x93C\xd8\xe9\xe8/\xb20\x1a\xfa8\xe4vq\xc5\xbd\xaaQY\xb6\xadJ\x0f\xf2_\xb2B'f{\xb2^C\xc0\xa5 \x8b\x9d\x9d)\x8c`\xe5\xc5 y\x19\xa2[J_\x17\"e]\xf2;+\xe1\xa0\x9e\x12b\xa43=z\xf2\xf5\xe3\xca\x0d\x9dQ@N\xdd\x98\xffyE\x93-a\xf8\xa8\"\xd3}\xfa$\xd4\x0c\xc5\x8d5\x9f\xf1\x10*\xe2;k\xc7\xcd?qku@G\xec\x92\x18\x86pl\xf3\xcblJ\x10M\xf3\xe4\x04z$TP\x8e\xd4\x9ac`\xfc\xef\xdd\x13\xbd\x98\xdaF>\x99\xa5\x13-\x83\xc6\x88>\x0b\xdb\xa2\xf5\n%\x01\xe6\x15\x11#$\xd2N\"\xd2IS\x95\x97q\xfc\x0b\xdb\xe2u\x02\x92$\x90.\xbc\x10\xaeh\x8d\xa5\x17_Zl\\\xa8\\\x15`\xc3f\x85hw \xd6\x82\xfe\x11\xe1\x95\x19\xde!\xf8l\xe1\x91\xbf\xe3R\xf94\xc2\x01[\x8e+}_R\xa9pMQ\x05\x80:\x8dRI\xe3\xa8*\xd5\x1c\xb9\xc9\xbe\xab\x08\xc2l\x05C\\A\xbe*lic~\xc4\xf7\xe0 \x17\xf0\x86\xfc\x88<0\xe8\xb5\xd0\x0e\xc7\x91u\x7f\xdb\xa8\xec\xd4\xce\"\x07\xa0aFa\xb1\x95$\x85\x07\xc7\x1f1T\xd4\x8d\xe7\xd7(\xa5\xbb\xa8\xb8\x92w\\Q\x10\x9f\xb7\"(R\xc3\x9a\x0bM\x06q\x07\xfc\x04\xc2(\x05\x7f\xb9\n\xc8\x92\x84)\xa9\xd2a\xe5\x06\xc2_\x91\xd67\x10\xb5\x01\xd5\xa2\xb6\x97\x13\xc9\x95\x8f\xae\xc6\x91d8eb\xad&^B\xa07\xd4\x96\x01:\xe0\x0b{\xac\x1af\x0f\x99 }1\xb6\xdfo\xd3\xfe\x98\xfft!\xad\xc9\x13S\xd3\x15\xbfOi\xec\x8b] 5^wI_0\xd3\xb3\x0e\x95n\xe9\xce\xc7%\xc5 \xa0\xa3?N!Z\xa5\xc9\xe8\x8f?Yn\xa9\xb6\x9e\x1f\xa3\x8b\x8c^([\xcc\x90\xb0\xcf\x15r$\x9c\"YJ\xf9\x1dP\x92N\xa3,U\xde\x908\xa6\x92;\x0c\xe1\\\xb9%\x80\xb2\xc3\xb5\xce\x88X<\x0b\xdb\x8a\xc2,\xa4\x03\xb5\xd8m\x92\x08\x88\xca.\xdf\x99\x1e%\xee.\xbc\xe4=\xd6b7\xd8\xa5\x17\x8c\x06,lk\x12\x10/\xccVB\xa7\xb6\x8c\xd6\xdc\xf6\x8d\xc4vn\x1e:\xd7\x96\xce\xfc\xd0O\x16\x96\x0bKm\xf14\xf6\xfc\xd0r!\xd0\x96\x8a\xfdy\xad-\xe5\xb3saB\x89G\xf5\xe3\x90\x92\xeaYM\xd9\xb9\xb6\x8cS\x9b\xb5\xe3\xa2\x85/\xde\x82E\xb2\x96\x10\xaf\xf5\xcf\xafb?-]\xbcn\xa9/\x91\x08\xe6\x9f\x04\xfa\xa8\xf8\xe6\xf5\x9d\x19\xaf\xa2qm\x913d\x86{\xd3\xc68P\x808^2\x18\x91x_\xe4\x11\xc2n\x14N\x88\x00\x0dZ\xbeu\xa3\xb0\x04e=\x9e\x07\x8d\x14\x174v\x15Mrz;\x01B<|\xb3\xbe \x9fs|\x92\xd5\xba\x8e\xa2\xe5\xc5\xf3\xa7\xf8{{\xbb8\xcf\xca\xb58\xfc\x8c+\x8cQ1m\x886~(h\xc1\x7fc\xeb\x84-\x06\xe3b\x17\xe8A\x8cx\xa8\xd1-\xac\xb9+9-3#\xd2\xda\x9c\xab\x171\x89M\xd0\x05\xa1\x12\xe7\xd4*\xcd\xadq(\xfa\xb2\x83\xdd\xees\xa9\\\"\x97\xe8}\xc4\x89\xbb\xf0<.Ux\n}Z\x89\x87_=\xb1\x0b\xfa\xcf\xe3t\xae\x04\x135\xf3\x82\x84\x00v\x0b1IVQ\x98\x10\x17\x84\xady\xa8^\xc0\x96\x96\xb8\xa6\xb4\xd3\xe1\x93C.\xa4\x8b\xedm\xba\x1b\xaf\x1b\x80(H\x15q\\8\xb7\x1b\xa9\x19C8\x86`\xec=;\x17\x14\xc6D\x17L\xb1f\x90s\xe3\xb6j \xcc\xe7Z\nb\xeehYO\x9bx\xdb\x8d\xc7\xc5\xa6\xdd\x9e\xd7u[\x1cva\x97\xfdnw\xf6\x0by\x96\xed\xc4\x9c\xf8k\xbbi{;\x00P T%\x1b\xfb\xaeb\xb2\"\xe1T\x00\xa5\x08P\xae\x96\xb0h\xcd5*\xf4\xee9\x9a\xf0%\x0cy\xf8\x1fcr\x06\x07\x90\xd9\xf2\x0b\xf4n\x92\xfe.[d\x95>\x1d\xc18tK\xaf\xce\xb0\x8a\x08\x1e\xad'x\x12*\x8b\x03\x9b\x1d(e\xfe\x80\xbdS\xb8\x02\x86\xf4\xfc\x9c 1f\xa1 \xb4\xfcn\x0fY\xb1\xe2F.\xe4\xb7y\xb6S\xb9\xd4\xaf\x18\xc1T\x18\xf3Z\x9d\xd5&*\x03\xf3\xda\x17L\xd4P\xbdL\x15\x8f\xc6\xc9\xa5\x90\xc3I\x89\xa3\x17\xd8\xa1\x0d_O?\xea\xd7|T0\x97\xbc\x9c\x07\xccfV\x1cBb\xe4exT\x96\x1d3H\xc5+\xa3t\n\xf6\xb95\xbcX\xc4\x9c]Hy\xc4YnH\xaf\x1f\xf8Vmp\xd2\xb8\x18\x98Y\x83\xedCy\xe6\xfa\xcd\xb2\xe9\xac\xf4\xad\xe4\x8a4\x16\xe7\x1a\"x\x02\xfec\x88:\x1d\x07\xe2qtf\x82A\xad\xc2\xb6b8\x04Z2\xb5\xe61\xdcNlR\x9c\x9f5:8D\x89LZl\xfeY\x97eg\xb03\x17\x9d\x97K\x80\xd8F\xc9\xa7\x8aM\x9c\xf9\x11 \xe4\xbf\xc6\xbd3i\xf7\x9a\x16\xbensF\x95\x1b\xd7:\x899)}Y\xb8Ap\xc3\x0d=\x861\x8a\xce8\x13'gm\xcc\x06h\xb9\xeaA\x10\x18\x8dRY\x84,)lVD\xfb\xf5\xb8\xdcJ\xa8\x07\xbc+*+\x91c\x8d\xcb\x11\xdd\xb9\xba\xf7\xecB\xa4\xa2\xc9\x89\x0d\x0eM\xb1\xa4\xec\x8a%}\xceq\xae<\x94\x04\x85K\xbe\xa6\x9b\x1c\xabu\xeb\xefM\xf3\x93\x0eF\nf\xb8\x8a\xaa\x18m;Z\xc4cL\xdb\x02:?s\x95\xa3\xa68eR\x85\xddo\xc4T\xe0f)eC\x13a|T1?)\xdf@\xbc4GP.\xa2\x9c\xeb\xec\x0c\x15=\x14\xe5n\x9b\x00U\xa8Z\xe9.b\x1c6\xf0\xc92\x1dG\xcd\x16q\xdc\x96\xfb\x08\x0fnd\xde\x0d\x16\x94\xca9R(\xe6\xf8W-\xa6{\x15{\xab\x8dN\xf7\x9a\x1b\x80\xb6g\x7fl8\"\xf2\xe3\xc1\x07?\xe4\xa2\x1d\xd7B4\x89\xbd\x94\x9c,l\x8b\xcefE\xa6\xc0\x85\xfb\xb0\xec/!t\xf1\xf5\x92s\xca,\x1f\xda\xb9A\xf1\xb3[\xbe>0i\xcd\xc0x\x8dI$S\xed*\xf2\xe6\x9a\x04\xce[\xe7\xb00&\x1e\x94!!\x84\xd3\x12(l\xbf4G&\xa7\xfa\x14]\xb6B\xc5o$W*\xa3\xa6^\xb2\xde\xf7\x99Ho\xab\x1f`=a\x95\"\xc4~\x9c\x9f\xef0\xa2+t\xe3\xb9 \xa9\xdb\xb2\x0e\xdaLJ>S\x14\xbb\xc6\xfe\x19\x94\xe3\xd2JR\x01/\xb4EE \xa9\x9b\xdc\xed\x1b\xd1K\xaa\x9bR\xe6\x9f\x87\x81\xadM\xe5\x07\x065\x86\xaf\xbb.\xd7qF\xf3\xfc\x8a\x11\x19$D\x82\xf98:\x93vz\xf7\xc2\x0f\xa7\x9c\xba\xd1\xa2\x1a\x8f\x9cT\xf6\xa6l\x86\x8c\x84B\xe7\xfc\xfe\x908\xc2\xfb;\x16\x14\xa7\x10#\xaa\x13\xd5\xd3\x9e6\xee&\x82\x84\x94|\xbb\x9b\xa3\xd8hL\xaa6rM\xd1Q\xd8\xd2\xc5Qu\x8e\xe5\xd9\xa1\xdf\xc7\xf9,\x8e\x96\xf4T\x86\x11\xbc\xfb\xa7\xa2\xac\x1c1\xdb\xc50\xd8\xed\x02g\x97bpW\xa3M\xb4iB\x1fNc]\x84\xbaz\xa4\x8dI\xeakO\xea\x1a%\xcb\x8dv\xd0\xe5\xcf\xb9\x1bK\x0b\xbb\xa3[_\xf5@\x93\x1bQMd\x01\xfc\xac\xa2\x9c\xd6\xbc.Z3\xee9t\xb2\xce\x98\x9b\xde\x01\xfa\xe0\x14\xc6\x9b\xed\xfbA8\x97\xb8\xd9\x9c\xe7\xf1\x85\xb8 |,\xd0Z\xc7\x00\x91F\xcf&\xe9\xde\xb420\xbb\x16\x02\xe5\x8f\xf9k;\x8f(\xee\xb6Ppo\xf1$\\\x07\x94-\x97'\x18\xb2\xd9\x85\xbaA\xa9/\xcb\xb0\xc2A\xe1\xed+\x9e\xccZu\x96A\xcc*\xfd\x99;d5\xd0\x92[\xc3\xbd\xafg\xef\xe2j\xf4\x85\x8a\x0b\xcd\xb4\xb6\x05%\xaa\xc3\xe7,o_\xfb\xadf\x04\x95ru\n\xe5\nL\x95U\xdf\x86\xb2\xa8\xaaO\x95B~>?\xf6\x9f\xec\xa4\xc8\xb0\x12#H\x84\xec\xd4\x9a\xca\xe1\xf0\x13\x12\xcch\x15\xfc\xf7\xd3'\xb8\xf2\xc3itU\xa5/\xbe>\xb272\x12&_&}\x00\x7f\xc81\xcd\x9f\x16\xaeS\xdds4\xc4~\x816\xc8\x06\xf0\x00\xf2\x9a I\xdf\xf9K\x12eiK)'$W\x10\xd9>;\xc0\x8a\xaf1\x1cB\xc1\xff\xb8\x80\x03\xe0\x85\x15\xb5\x05\xf6\xfb2LI\xbc\xf6\x82[v,>\xd7\xf7,J5]\xcb#C\xfdK\xe9\x83F\xf1\x873\xf9\xa8\x88\xad&\x96\x8fJ\xda\xd2\x98\xcc\x94\xec/\xec\x8d<_\xe5#l\xb7 $\xa55f\x10\x89\xdd\x1c\x0f4s&a\x1c\x05A\x1b\xfd\x90\x0c\x1d;\xa5\xcd\x05\x84\xff\xf9r\x8a\xd2\x87\xfc\xaa\x8a_\xb4\xb7,\xd4\xf4w'\x9d\xa9\xd6p\xb4\xb7s\x84\xf3\xe1$\xf5\xd7\xe8'\xda\xf5\xc4\xcf\xcf\xe9\\\x7f?\xc8/R\xa5\xaa\x1a\x8dV\x91bQm\x15FPl\x99\xe6\\ri\xf7<\n\xc5\xe4\xd9\x9dD\xfe\xb7\xee\xb2G\xe3q\xe5bD\xab}G\xec\xb9\xe5\x92L}\x16\x9b\xa5\x99\x84\x95\xbfP\xb2e\xb2\x01\xa95(\x0e\xe6\xac\x8b\\\x98\xef\xbc\x0d\x87\xa0|\xa3\x1dD\xb5Ni\x18\xe5\xe2\xe2|\xb8M\xde\x9a&\xde\xd9\x14P\xcdGU\xa2\x9f\xc8Q\x88\xea\xd1S\xd8#\xe1\x8d\x82eA\x07R~\xab\x99F\xdfDW,W\x8em\xb4\xfeF\x13\"kA>Zz\xd3\x1eV\x8eq\x90\x1a*l\xd7\xd7\xf0\x92\x89\xef\xd7\xd6\xb8\xf0C/\xbe\xae\xaf\xe2%d\x7f\xb7~$\x93d\xd0Ta\xbb\xa1F:\xeb\xef\x07\xa4\xa9\xcevc\xa5\xd8\xbb2\x94\x83\xe4\x9fm\xc8+\xd9hq\x95\xfbwWwxys\x1b\xf2\xfc\xe8\x18\x19Ee+\x90\x0b\xf7\x07i\xeb\x07.(`3\xff.\xae\xa3\xf8T\x18\x9e5\\\x03\x91\xc7\x8f\x9db`u\xca\x97F\xdc\x85V\xf8+\x9e\x16\x83\x846h\x08\xadP\x11Z\xa2#\xb4EI\xf1H\xd3\xc0\xdaM3 \xbc\xd4\x0f\xfb\x8d\xbd\xd7\xee^\xf1\x88\xbey\x9bM]\xd7nwhEZ\xa0\x05\x8d\x13\x8fP\xe9\x98\x87\xd5\xb8'A8X\xd4\x87\xd8\x12\x0f\xa5\xd96'\xdaez\xcdbQl\xf5\xb4\x9f\xeb4\x84\xba{I\xbc/\x13\xd12\xb6\xca\xc1\xc5\xed\xd213\x1a\xf1X\x85,\xbdQ\xd5'\xc4z\x1f^\x86\xd1U\x08\x82\n\x0c\x81\x0d\xdb\xa8\xc7`\x07l\x99\x12\x15a\x1d\xf2\xb8t:\x8e\xab\x05\xdac#)\xf9(\x92\xc6\xb06)\xe74a\xa0\xd3Dh\x04\xb3\x89k#\xa9\xc0\x0ef~\x10|\xe3\xa1\x96\xce\xbb}/\xb5X-\xcfkV\x9aW\xc0z\xdc\xd9\xa8\xc7Z\x84\x95U\x98\xcc\xfek\x04+\x96f\xdc\x96:^\x98$g\x10\xe3\x0d\xbc$}MP\xce\x16\x81\x11\xe9\xabwQ\x8a\x82\x92\xfc\xeeh\xe11\x8f:\xd9\x1b\xb0\xa4\x0c\xcc\x7f\xe6gUV\x13\xd6\xfa\xc9\x08\xfa\x83\x07\"c\x03<}\n{0\x1a\xc1>\x1c\xc0@\xbc\xd9\xa5o\xfa\xbbp\x00;\xe2\xd5\x0e}\xb5\xd3\x83\x03\xd8\x15\xaf\xf6\xe9\xab\x01\x1c\xc0v\x1f\x86\xb0=\xa8\x1d\x92g8>\x852\xb0\x98\xfev\x19DU!\x7f\x13\x07h\xb4;\x19<\xa4{\xd9\xee?\x1a\xc0=L\x0f\xebH\xb6L\xe5\xa5\xb0\xfe\x9f\xff\xeb\xff4PY\xf40*\xaas{A\xc91\xac_w\xb4\xea\x06\xd27\x0d\xa4_;\x10\xd0\x0df\xa0\x0c\x06\xffV;\x1c\x98:\x1c\xf0\x0e\xdb\x13O\xae\x0f}\xacC2I\x90\x08\xd1\xbd~\xa8`\xfd\x13\xc9\xd7\x0c\xa3y\xa1Wf \xe5qY\xe5}@?t\x94}\x91\xa7l+\xf3[nuS\xb1\xa8`\xb5\x1d\x89\xcb4y?\xe7#\xde\x96\x02\xa0\xd5\xef\xbdD\xab\x01\xa0\xebe\xa7\x85'\x10q0!\xf9\x08\x1dWjt\xf2\xc5\x0cs\xf2n\xb6\"\xa9\x0f\x03\x80\x97\x91\x93\x85\x17\x1fESr\x98\xda\x92\x07\xac\x1aWZ<\xb4\xd1\x98J\xdd{{\x83G\xfb\x80f\xf9OF\xb0\xb7\xbf\xd3\x7fT2\xf8Rp\xa9B\xd0v\x95\x85\xe3)\x9a\xc7\x12D\x06gj\x9d~\xa5N\xff\xcc\x85\xb0pS\xd7\xe6\xd9\xae\xbc\xd1\x9bxh\x89\xa32\x93\xbef&\x83\xe6\x99\xf41\xe5\x85v\xe1\n4C\xa8\xd7\"R]\xaa:\x90\xef\xc3\x0f\xa4\x03\x89]~X\n\xe5@jQ\xdaH\x0d\xf7@fr\\\xc3\xbdtL\x9bS\x82@\xaf\x1a\x0eL\xb7\x12\xa4\x1623\xed\x16\x13\xe3\xafl\xb3\x1d-\x91\xeaq_\x93\x83\xd2ZqV\x83\xbb\x9d\xd9*F\xec\xc06\xde\x94\xa8X\xb1#\xec\xd1B\xb1\x1a\xb5\xf8Qj\xfa\xb3\xf6\x83\xe3\x1a\x86_\xc2\xb4\xb0\x81f\x05w\x87j\xda\xadtP\x8b\x1d\xf9\xa0{.\x02X\xc1\xd4a\x036\xac\xcc\xcc\x8e\xe1|\xa8\x07\xc6\xa2\x86yj\x82\x85\xd4\xb0\xf8E\xca\xd1\xdcX\xc6\xc7\xa8d\x1b\xe4\xa7\xf5\xc2\x7faq\x9b\x9fA\xb9`\xa8\x80\x1f\x97\xcdU\xdd\x9e[\xed\x7f\xbfHB\x87\x9e\x989k&\x98x&\xe7\x18:\x06\xd9\xba\xf12u\xbd\x84\x02>\x1e}\xae\x9a\xdeJ4\xb2\xbd\x8d\x83\xa1\xab\xb7=`bv\xdd\xc0\x90\xb1\x92F\xe6\xb4\x1e\xc3\xe0\xf7\x1f\x03o\x0bC\xef\x8cD\xca\xbc\xf2\xa8v\xf4\xa3\x12\x9d\x97\xb7\x8f\xd9\xb0\x98\xe9 \xcb[\xbeJ\x15E\xb8~\xf5\xeb\xca\xf9\x16V\xa9\x8c\x1c\x9e\x01\xb6\xc1\x0e+\x94[\xbf1\xb4,x\x8f\xf9M\xeb\x86FKL\x1bFR/\xd4S\xcf\xf2v|\xa2!\xa4\xfaq\xd5\xf3Bw*\xa0(+p\xeb\xe1\x14bLy\xd2\x92\x04\xa3\x9cR\xb7\xba\x99)e?/^\x17\x176\x035y\x1f\xcfq\xae\xcf\xcb\xac\xd1\xae#\n#\x04J\xd9T\xca9\x13\xa2j\xda\xf0\x92\xc9}n\x8b\x91\xc6^\x98\xcc\xa2x\xc9\x8c1tn1\x18\x17\xfc\x9d\xa8\xd7\xc2r\nT\xaeY\xe9E/T\x85\xdd\xbcV\xbd\x1fG!\xb5\xe1y3\xb90\x0bi[qY\x1c3\x06\x0e`\xcc\x06\x85\xd0\x857\xb9\x14qj\x96Y\x90\xfa\xab\x80@\xea/Ib\x8cw/\x06\xb2\xc8\xc2\xcb\xdcG%\x1f]\xf1\x86\xa7\xec*L\xadx\x1aWW\x93O[<\xe2\x80apl\xe1}\xe0+\x86;\xb6_ k.\xecc\xe1 \xf8\x9a\xa8\x1bEW\xb6Z\\\xe9\xf1\xa6\xb0\x01\xd58\xdd\xd1\x8e%\xc4\xd1\xd9H\xcak\xae\xaf\xc1\xc1\xc8\x82]\x98\x8a)\xe8kk\x14\xdafZ\xa9|\\\xe8\xad\x97t\x0154\xd5\xa4P\x1e\xb5\x89E\xf2\x89J\x06O\xc5\xbb\x91\\\xc3\x9cgd\x16d\xc9Bj\x80\xfd=\x12%\xc2\xe4\x1e\x0d\xb6W1\xc9\x1d\xf5\xb2&\xbd\xa8\x8e\x9d\x12\xbe\x18e<\xd3\x8fL\x1a\xcd\x81\xfcW)g\x9a\x96\x19\xf3r\xdaZ^\x14\xcaDz\x9c\\\x15\xfb\xa7~\x1e\x9e\x89\xeb+\xdd\xa4hLH\xabLB)\xb1`Z\xc4\xba\xaf\x84 \x10\xe7e\xe5\x9e\xe3\xc8\x0b\x02\xba\x0d\x8bE\x9eF!\x81\xab\x05 \xe1*\xcf\xa8\xb45\x82\x9e\xa5\xe9?U\x89f\x89:n\xd8]\x92\xfaAP\xdajj\x979d4\xbe\x00\x85\xcc\xe6W\xf2\xaa\xb9\xd2;;b\xdcJ\xb4adw\x99@\xab\x93.Q\x90\xdc\xe9\xa9\xdc~\xc5\x97\xac\x18yy0\xa5\xfd\xd6$(T\x00\\|m\x080c\xec\xb6*\xc9\xea\xbb,{\x9a\xd5\x9d\x99(\x9b\xc8\x07\x0c\x85J\xe9\x10J\xf37\xd2m;qa+V\x10I/\x1e\xb5>r\xecXY#<_\xbe\xd0\x89sc\x04\xb1\xeaYP\x7f\xa9R\x0b\xdb\xdc\xe7\x84\xc8\x10\xc5[\x04\x01p\x16B\xb8\xc4\xae`\x0c&\x95\x81\xe9U\xb8,[n\xd4\x15M\x16\xfc/\xe9\x96\xb9-f@\\\xdd\x06=#$Z\xe6i\x90\xf93\x95Q\xac\xb6\xa6l\xb1z{\x0c\x96{=\xe4D\x969\x90\xab\xc4]!.\xb7b\xb5%\x9eZ\x97\x89\x17sH\xcaBQ\x14\x1f{\x93E\xb9\xa2\x94\xe2|\x12\x93\x12.\xb4K\x8b+\xf0*bDSKU\xb9\x0din3\xda\x04@Lgz\xef\xde\x06\x8c\xb6\x9e\x15DK\x97\x10\xbd\xd9\x1c \x18\x04\x10\xd2qxV\xa9|c\xf3\xb4\xb8\x18\xc9X]+\xb7\xa4h\x84\xdb.\x97\x16\x9e\x0e\xfc\xfd3\x9a\x940`\xc7iZ93\xcd\xf5\xf5\xab\x96\xbc\xf6^\xdb\x98X\x16\x95\x18\x84\xa9/\xf0\xe2\xee\xde=\xae\xad\xd8\xc6\xc4\x0c>\x86\xb6\x1e\xe6\x8e\x95x#\xd4\x9c\x1d\xb9\xd5\x1c\xcb\xfe7\xbb\x0f\x06\x8eM\x87\xc4\x91\xd6K\x12\x7f\x1e\xc2\x10\x8bv>\xd7\xa2\xd0\x05\xdf\xc5Tr.x.\xcf\xe6:P\x13\xa4N\x9aH\x0b\xe8\xee+\xe8#\xe7\xcc\x8f\xaf\x95\xaf\xf4\xaeY\x13\x17x\x08@\xad\x07\xd6$\ng\xfe<\xab\xc9$.\x985\xbdl\xd1\xe4\xc1\xb5\xf6\x82\x8c\x0cA1\x02\x96\xd6\x15&^n>V\x9cN\xec\xcec\"]\xe5\xc6\x15\xc9\xba~\xe8\xe6a\x97\x87\\\x8c\x84\xc55\xd4B\xd1\xdd8\xa12\xa5h J\xa6\xb9*k\xc4s\x06\xa60\xa4\x87>B\x86\xb1\x14\xe8\xa7U\xacR,_\xaa\xe0m\x11\xcfn\xfc\xe8\xa1\xe3b:\xd4\xf1\x19\xcbl\xdd@U]\x9d\x02\x9cr>\xde8=\xcb\x99y\xfaG\xb9\n\x92=\x82\xfd<\x86t{\xfb\xb1#|\\-\xcf\x82\x0e\xd8\x9dN\xe8\x14\x1a\xa8\x9d}U\xae\x97\xf4(\xc2i\xc2\xb6f!K\x98\x8bE\xb9\xc4a\xd3\x06 \x0fq\xef\x82\xe5@\x87\xfe\xef\xef\xa2\x8dY(\xbc5\xf1\xec,\xdc\x06\x1e\xc3\xcd\xe32\xcb\xd8z\x8d4\x14\x1f\xe5\x1b\xc3\x9a\x15b\x8f\xc2\xe7\xe0\xa9E\x9c\x8a\xea\xa1\xba7\xe9\x93\xd9\xe8\nU\xde z\xf4\x07\xdd\xed\xf2\xcd\xe7\x12'&r\xe8\xb2\xad\xeb\x91\xbeTM:\xe7\xe7$}s\x15\x8aj\xcfI2\x89\xfdU\x1a)\xf6\xd3\x99\xe9\x83\xd7\xdeR\x0dh\xe2\x99\xea\x9e^//\xa2 iq2i\xd7\x98\x91`~4\xc76Q\xf1\x14\xe5D\xb9\x06\x86\x18\xc8\xec\xc4\x11\xccN!~kC\x0d\xeaW\x1a\x9b\xb6\x99\x87M\xc4\xc2\x14j\x14?\xf2\xd2k\x9b@\xee\xb2\xfa]\x19\x81L\xaa\x0e\x0f0\x82\xdb\x7fY3\x91\xed{r ]/g\xffS\xb9\x95\xcf\xdc\x15}\x1d\xff\x1b\xda\x0fUUs\xa4w\x03\xa3\xdc\xe9mq\x94\x9ek\x9a,xt\xfb\xe4\xc4n<8\xd3B!Fj\x85\x0b$w\xc4\xd8\x10O\xb7\x1a\xe18>C\x07'\xe1H\x91\xa1<\"\xbe\xa8\xacH\xd8\x00g\xb9\x8fv\xfc>\x1f\xfa\xd6\x16W\xf6\xb1\xf0\x03\xe5\x14r\x9f>\x19\xb4d\xc8\xd5\x9b\xf4\x83\x0b\xd24\xdaVX\xa1\xe7\xa3\x88\x0b\xd6\xf99I^E\xd3\x0c\x0dN\xd4\xa5D>G\x16+Yt!/N\xc8\xf7\xde28BnE\x93\x16\x7f]D\x88\x0e\xed\xbdAO\x83q\xc8\xfc\xb0\x80\x0dq\xb7\x18\x04\x1c@\x0cC\xcd\"\x0bSS5\\p\xd1\xa9n`\xb5\xa8\xaa'\x0f|-#\x91\xe3\xaf\x9bx3\xf2M\xe4M+ \xacjID\xce3\xb1\xd0\xc8q|\x88\x03I\xba!\xb9zG\x89@x\x1c\xc7v\xa1IB*\xad\x1c\x97\x1bz\x916\x11\x84\x9d\x87\x06q\x88\x8e\"\xb6\xcbs\xf0\xc3I\x90M\xc9\x10\xc6\xa1=\xe8\xed8g\x12\x12\xfcC\x07\xd3\x1f\x0c\x9c3\x85\xb0-W\x81?\xf1S,\xdf\x1b<\xc0P\x06{\x83\x87\xfc\xdfG\xec\xdf\x9d\xde\x1dM\xe2N7S\x10y\xcc[\x99t\xdf\xbd\xf9\xea\xabo\x8e\xcf\x8f\xde\xbc~\xf1\xf2\xabS|\xf5\xfe\xed\xf3\xc3w\xf2\xab\xda\x9d6\xe8\xed\xfdN;-[M\xbd\xaa\xf6\xd2@\x165\x07\xf3\xf5\x8a\x0c!\xab\x9e\x10+\xef\x9a\x02d\x08v\xcf-\xb6\xa0c\xff\xfdF\xd5\xe2\x02(\x9a?\xd2M\xa3\xf9<\xa87\x0ej\x18\x91&\xabJ>\xa2\xd4\xd4uy12\xfd\xbaYL\xb2K\xce\x19\xe4\xac*\xaf\xa8Y\xff\xfc#63K^\x81\x1cod\xad\x89n\xaeU\xad\n|\x1eA!2\x12\x8dJ\x0ef%l\xec\xef\xa9\x0c\xc8\x97\xc2F^\xa7\x85b'\xa7\xca~\xc8\xe2:\x94\xd1\x8c}U\x1d\x04\xdf\xbca\x83\xae@\xa3i\xd8H\x17\xa1\x18\xac\xa0\xa9\x16\x8b\xde\x19\xba\x9br\x87\x94\x1a\x10\xf9\x1c\x18\xdeQy\xa1\x8f\xb7\">\xdd\xd1\xd6%\xb9N\x90\x91&\xdc\xa3\xc2\xc2\x1d\\\xbc\xc3\xe47C\x16\x14w\x1c\x9e\x9d\x95t.\xa22\xdeZ\x1e\ny\x05%\x0c\x0e\xe9\xd8f]\xa0\x91\x86T\x1d\xc3\xd0\xa7\xb1O\xff\xd2\xe2O\xa3haT}7~\xb9\xd1\x01\xcc \x9a&\x18\xde4\n))\xda2\x1ew\xb7\x1c\x9d:4\xbf\x1cJyK\x96\x87\x98\x90\xfc\xeezE8o\x0c\x1d\xb0\xc4\xed\xaa\x977\xbae\xba\xafn\x18\xec\x86\x9b\xf8\x91~\x0f\xef\xedj\xb7\xf0#\x95\x05\xcbP\x18.\x1a\x0e\xed\xc1\xbecg\x94\xf2\xec;\xb6\xe5\xa7$\xf6\xd2(\xa6\xe8\xd3t\x94\xa7r\xf0\xb2\x1b\xa7F;\xa8\xbb\xba.h&\x8c \xa6#\xa8\xe2EH>\xa6t\x13i\x12\x91\xd3\xdd\x80m\xe3b\xbc\xcc\x87\xbd\x19\xb0%\xf5\x84\n?N\x1a\x1fh\xc1\xba\xdb3\x93\xc0=\xe9\xea\xa3\xc4\x94\xfb$i\xca%\xe8W\x14\x9dEf-\x17\xd7.B}\x04\xe5\xd02N\x81\x98\x06\xae\xf7\x18\x85\xbd\x07;\xbb;\xbc\x7fV\x1f;\xa2\xc8\x82\xce\xdf\xf4-\xf3\xc2L\\\xecd@\xcb2\xd8\xe6\xcdt\xe88\xb7\xf9\xa0\x9e<\x81~\xcf\x81\x0e\xec\xef\xed\xed\xec\xdf\xcd\xa6\xaf\x1c\xa9\xfc\xe0\x18\xf4\x8dg\xea\xc0\xe9\xceI*\x0e\xf9\xe6[Y\xa4\xf3\xeaIjd\xf1H\x03\x8b\x87<\xd1E@L\x0c^l\x13n{\xe4\xdcz'\xf6w\xf4\xd7#\nOV\xa10(\xa4\xb5\x03\xdb+\x92.\xa2z\x034\xc9\x8dl\x0b\xa3\xcd\x0b\x9a:\xf6\xcf0\xc0\xc5\xd8\xfa\x97\x7f\xc9\x87\x83\xaf\xa21\xa5Ng\x9b\xcd\x9b\xae\xf6\x0eJ\xbb\xfd\x1d&\xf5\x0evv\xf9\xbfLM:\xd8ej\xd2\xc1^\xaf\"\x0e\xf7\x1f9B\x14o\xd3Y#C\xad\xc3G\x99E\xf6\xc7\xa1\xddwlK\xdc\xc6\xbf\xf3\xe6\x96s\x06#\xb0~\xc1L\x8d\x1d\xba\xcf\xb7F`\x8d\xd9E\x0b\xfcrf1\x1d\xc1N\xcf\xe1VK\xa5\xe8\xbd\xa2\xa1\xba\xb0\xdd\x1c\xf2y\x9b\x16t\xe89\x80\x01L;`\x9d\x95\x9c\xe3\xb6\xda\xe9\x07d0n\x85\xf6\xee\x80%G\n\xed\xdd\x1d\xc7\x1cx\x8d\x8f\xe4\x01\x9d\xa2^\xd7\x1c\xda\x8f\x1e9\xb65\xf5\xd7Tl\xb0<\xad\x19\xccF\x81\x86\x1fT\n\xd5\x9b\xcc\xaeW\x00\xa0\xd5\xe4%]\xbf\x89\xd0\xd4\xb3\xe6\xe8\xaa\x81'\xb1\xdeV\x813\xe9~\x95\xea\x10\xd3\x95\x9a]\x8e\x13\xc0\x96#\xe6\xb1\xc7\x05I)|\xd1j\xe9\x99\xda(\xca\xd4of\x9b\xb7\xb9\xf5e\x86\xab\x92X\xeb\xc8\x0b\xff\x94\xc2$\n\xd7$N\x81\xa3y\x1a\xc1*\xf6\x97>\x06+\xc4)l*\xd25m\xf7\x81\xe1\xfc\xe9\xef\xe8%\xe8~O\xe5_\xaa\"t\xff\x01\x17\xa1\xfb\xff\xaaE\xe8\x87\x86\x83]}\xcf\x01\xbb\xab\x03,\x05x\xcf\xb1\xad\x97\xc7\xe7oO\xde\xbc{\xa3\x1ez\x9e\xaa\x9e*\x17\xab\xda\xab\n\x15U\xba/F\x8c>?\xf9\xe1>/b9FxXV&\x1e\xa7\xdd\x17\x8f!F\x8b\xb3) HJ\xe4\xac7\xe3h\x1c\x9fir\xa6\n.W\x8d\xed\xaa\xa7\xa3%c\xe5rP\xc7v\xa6b\xbc\xbb\xdc\xca\x1d\xefF<\x05\xdd\xd1\x80\x1b\xd8\x0d\xad\xe7B\xb9\x98{\xe3\x8c3\xb4'\xc6\xec\x93hzVX\xc0\x8c$}\xac\xcf\xb2\x19\xdf\x16\xf1\xf7\x0c\x14\xc5\x80\xf75\x1c\x1b=\x92\xff5(\x8f\xf6\xf4\xa4b_wEG\x99\xc2\xbeco\xb5\xa3\x16\xb78\xd99\x80<.5T\xe9\x00\x82\xa8\xfaz\xc2\xcc7\xab\x10Gsv\xcfaJ\xa2\x8c\x19Z{\x08\x8b{\xf7`\"\xfc\xb44\x1f>\x96\xa3@\xe1j\xe0w\x94,\xe0Z\xb0d!\xff.\xb2'\xd8\xda\xa7OEk\xfa\x05\x9a\xdcv\x81vM<\x12\xb7\xe3\xb3~\xb1\x1c\xba\xe1\x90\x01|\x99\x1c\xe7\xf7\x8ev\xaf\xc0\xe0\x12\xc2\x9a\x18\\\xce\nS.#f\x96\xec)&\x10Km\xcb\xa2\xfb6\xb7\xfa\xbf\xedT*H\xc5pmWg\x9c@ \xb6I\xb5\xdb8\x95\x92^\xe2\xdf\xf4\x94\xff\x15\xe9)\x0d\xe4j\xb0\xa3\xfa\x1dD-8\x18\xc9j7?\xb1j\xcf\xd19I\xdf\x8a\x8aof\xf5A\x92s\x90pZF\xf7\x94\x0b\x11n\xabqt\x06C\x93i\xdf$\n\x934\xce&i\xc4r\xe3\x83\xe4\xb7_.=(\xff-\x1d\xbb\xc3\xf2g\x9c\x08\x1c@\x06\x8aG\xf3\x86\xe0\xef\xdfzK\xcaV\xc7\x9b\xf5\x9e\x1f\x9d\xc2w\x07\xfdH\xf3\x03\xdc\x15\xda\x97\x9e\xe3\xf2\x93h\x8f\x1f\xad(\x0e\x08\xcf\x94\xdd]\xc7\xc5\xfdLe\x03\x177\xed\xa4,\"\x04\xecUI\xb9\xc0\xf2\x82'\xe2~wQq\xcc8:==\xc9XN\xbe\xaa\x19\xc7\xd1\xe9\xe9)eH\x9f\x93I\xe0\xc5\x1e\x9da\xd5E\xe3\xe8\xf4\xf4\x03\x15\xafx\x13ji\xe0\x930=!\x93T_\xfe\xfc\xcd\xab\xdaB6\x17c\xf1\xbb\xe8\x92\x84\xfa\xc1?\xf7R\x8fy\x11\x92\xf8eJ\x96\xfa6^\xf8\x81a\xe4\x7f~\xf7\xea\x9b\xc3 8\x8a\x82\x80L\xf4S\xa7U\x9a\xca_D\xf1\x92k\xbb\xf5\x15N \xfd\xdeX\xe5\x15\x99\xfa\x9e~\x86\xaf\xfc%\xa1b0.n\xf5\xcb\xd7\xde\x92L_GS\xf2\xca[iJ\xa3\xa9a\xd5\xdfz>]\xb1\x9f3\x92\x18\xd6\xe5m\x90\xcd}\xcd|\xd9{\xc3pN?|\xf5\x0d\x1eC\xfa6O?|\xf5:[^\x90\xd8X\xfc\xd6K\x17\xa7\xc4\x80\x0b\xb4<\xf2C\xc3\x80O?|U\x87H\xa7\x1f\xbe\xca\xfdM\x0d5\xa2,\x9e\x10\x16z\xdeP\x83n\x94\xd3\x05!\xa9\x1e\xaa\xef\xc8\xc7\xf4]\xecM.\x8fL[%\xafa(\x8e\xb2I\x0e\xbb\xbc\xe4\x86\xa5\x0b\xf7m\x0cY\xc98\xf05<\x81\xa9\x904a\xdd\xe9\xe8\xf8\xd4k\x17\xe60\x82\xe9x\xad\x18\x9d\xd2g #X\x8c\xe7\x9a\x92sd\xe7u%\x170\x82sJ\xf1\xcfu\xa7\x11\xf0c\x18\xdd\x89\xed\x0bz\xf6~\xfa\x04\x9e}\xe1\xc2\xcc\x85\x95\xe3\xc2\xc58(\xde\x05,\x07s2\x9e\x9f\xb1\xe8\xbaK\x8d/\x03R\xd6kz\xa2\xc7\x0e\\\x8c\xaf\x99\x1a\x99~~\xedB<\xbe>+\xf4\x99\xd0\x96Z7*}\xb4>9\xf4\xbd\xe1~_\xd5\x05e\x82\x954In\xfd\x9d\x07\xfff\xf9\xf4_\x8e\xe5\x93\x99\xd7pl+\x0b\x93I\xb4\xa2\xd2L\xa22o\x1a\xa7m \xdf\x84f\x01\xfcq|\xc6\xae\x00\xfa\x0f\x1c\xdbG\xef\x8f\xbf\x9b\xf5{\x15I~\x1c\x9f\x8d\xd33\xc5\x89^;\x11\x93~\xbf\x16\xf5\xf8\xa2\xea\xc4\x93\xbb5\xc4j\xbfMe\xb7^\xbe\xa1T\xa6;\x11lV\xe9-c\xae\xf6U\xab\xa8\x19\xbe\xae\xdc\xed\x04\x8ckS\xde\xae\xd8[U\xc3\xb0`M\xab\xaf\xa7\x9ct\xa8\xd6\x91k\xf6~W\x1d\xca5\x17,\xd5^\xe7\xfc\xfd\xae\xd3M\x88\xb2e\x97\xbc\xad=\xc7V\xbe:\xe7,\xb1*\xd5^\xf0\xd6T\xf8\\\xf1\xf7*\x01\xfc\x88\x1cf\xae\x8fW\x8eE\x91\x0c{B\x12\xc5\x91\xf0\x18\x8b\xf8\xfd[\xb9\xe8\x10F`\xf1\x8fp\x87\xcf\xecS\xa5\xd77\xf5\xea\xdb\x9f0\x92\xde\x08\xce\xbb\xb3r\x01\xa5\x84[[\xf5\xaa]\xb3\x7f\x9d\xa0\x8e\xc7\xdd\x98$Q\xb0&\xb6\xba\xa6\xf2CX ZY\xe6\x19\xd1\xdd\xcb\xaf\x01\x93\x15\x99 a9\xab\xdd\xc3\xea\x93\xdao\\xc\x96v5\xd9\xfaA\xb2\x0394zl\xf1\xa58!?1\x86\x163_\x8a\xac8\x0b\x12\xdao\x1cY*\xab\x8a\xe55\x1e\xb27*\xf6\xbdl\x9c\xf3\xba\x9aX\x05\xa4s\xc4\xde\xc2\x98\xaf\xe5\xc9\xe4w\xf1,p)\x0e\xdb\xc1)\xa8\x89\xb4J\x7f\xbej\xa2s \xae\xb4\xd2\xee\xb9Q B\xcb\x14\xc7\x01\xf9Y\xe7\xe1\xbc\xcf'\xfa\x1a\xcb\xe6\xa4U\xa0J\x94i\xf7|\xcd\xe4\xc9>.e\xf7\x1c\x00\xe9F\x97\x18\x94e\xe6\xf9\x9ahc\xea\x93\xe0\xc5\x03\xdf\x1b\xcd\xd5'\xbc:E\xb8\xe6\xda3\xac=\x8d\x96\x9e\xdf\x94 \xc4\xb8\x81\xe5\xc7c\xc1.>}b19)\xec0\xdc\xd8[\xc6E\xd1\xbfF\x18\xa4t\x8b)\xf9=d=Fh\xedoc\x0e\xadY\x97\x84)\x89m~\x81\xe0\xd91\x8a\xe6\x94\xc5\x9du\xc9G?\xb5\xb9P\xbf\xd5sX\x1d\x8c\xb4\xb3\xe2\xe6\xff\x070\xb1?\xda\x16\xdfw\xdb\x93\x85\xe7\x870\xb9\x9e\x04\xc4b\xa1\xea\xe9:\xbe\xb4)\x06\x1f\x087\xd0\xd0\x85\xc4\x85 -N\xb0d\x08\x13;6S\x03P\xf7e#Xp\xfc[\x19\x9f\x1f\x9f\xc4\xc4\x94f[<75\xf4\x08\xc2B\x19\x1d=v \xb3\xc3q\xd4\xe9\xe8\"\xc8\x8a\x87n\x12\x1e\xe1&p\xd4p\xad\x9a\xde\xde6\xf6\xb6)\xfe\xea\xb1QF\xac\x1c\xe8\x7ff\xaba \x9c\"\x1c\xa7\xf2\n|\xb9\xd8)\\\x83Rm\xd0I\xa0\x12\xddS\xad\xb7~\xedJ\x9d4\xc2n-\x05S\xab\xc2\x85t\xcf1S\xb4\x8d?X\x184\x84\x01\xe9\x9e_\xd1\x02\xe2t\xcf\xd7,F\x1d\xe9\x9e',{\x04\xe1+l\x13\x86y\xa4{>\xe1\xc6\x94\xf4\xa0xe\x13\xd4]\xd4\x8e\xfcu\xbb\x91\xbb\x86\xc8g X\x9a\xb0{\xae\x0d\x05\x0f\x18\xec5\x9f\x14\xde\x90\xf39\x19\x8e\xdf\xfac\x17\x03M\xb2\x00\xf6bc\x15\x87\x1fL\xd0\x88\xe7\x82\xeefd\x1e\xa6\xe0\xa7 f\xaa\xa9\xa4\xfc \x9c_\xa2%\xd5A[\xe6 $!\xbd\xf9,<\xbf\xd2zGV\xaaM\x87\xba\x84\x82\xf2c\xe0\xca\xc5\xd3\x8ec\x11\xe6\xa1\xf4<~\x8d\x07L\x1f\xcf\xe6\x13\xfe\xfb.\xd9\x80\x93\"\xf3\xed\xadO~g\x88y\xc39\xfa\x87\x0c\xfd\xfb\x14\xbfC\x17\xb6L\xe3m7N>\xbe\xfa\x89\xb4X\xbf\x86\xb5\xbb1\xce\xbf:o\x85\xc9(V\xfc\x12\xf7\xfaq\xed\x86\x9d\xf2\xa8I\xc7.\x88Ma\xb9`\x9d/,\xc7\xc5t\x14\xae\x1c\xd5\xbaU\x14\xa3\xd4F4a\xed\xe6\x98\"\xfeT\x88K-\xd0O\xca\xf1\xb4\xcb_\xe6\x7f\xdd\xb8\xec\x107O\x92\xa9\xf9r\xce\x0e\xff\x92O^\xf6&\x91U\x97\xe5l\xe5\xebJ\xe5\x85\\\x991\x8a\xc5\x80\x9c\xb2-\x8f=\xd8\xddw\xecc\xd9\x86V\x1d\x1f [\xc4\xfc\x16\xa2\xdcO\xb6\x88uu\xac\x0b\x97-\xac\x8f\xa8\x0c5\xd2\x8a\xa9\xec\xca\x19\xf7\x06\x15\xb0\xca\xb5F\xe5\xd4\x83\x94\x92s\xe9\x07\xd9\x18z\x16\xf3?\x87\nL&R\x08_\x0e\xe3<\xf0\xa8\xa7\x96a*\xdfW|\x1e\x98\xb8>\x14\x12Jy\x9d\xcb\xfb\x08\xd1\xa5\xce.\x03\xca\xd6\x89L\x85\x90\x8f\xd3\x88C\x8e\x12.\xcd\xa4\xa0\xc6x\x1a\x8f\xab\xd8%\xb8\xc2\"];?Q\xf0z\xf45\xc6[\xc8\xb3\xf33&\x05KNx\x89\x8c\xcd\xe7]*s\xfe\xd4\xe6\x828\xc5\x93\xed\x18\x97\x13\x7ff\x94\x83\xe6\xc1\xe9Q\x8d-\x1b\x9e8.\x04v\xd0\xfd\n:\x10t\xbf\xc5\xff\xbf\x80\x7f\x86\xadK\x15!\xdf\n\xa6\xe8\xb8\xf41\xb3&\xb5eZ\xc1\xad\xdd\x1f8\xb6\xfcJD\xa3\xcb\x0d\xddY\xc7\xa7\xa5.%z\xa3\xce\x8d\x82\xa7i\x91\x05\x83\xf4\x93\x8e2\x81\xa4z\xea\xb9\xb9\xb4\xef\xb0\xe8\x9bzD\xab\xc0\xa9\x18\xae\x8dl\xd3\xd6\xa5S;j\\\xef\xa6a\xf3Q]\xd9\xf9\xe6\xc8\xd7\xed\x98'\x93i\xc0S\x05\x92\xf6%\xd3\xd4\x0fv\x1fJV\xf0\x95\xbe\x8f\xbb\xcc\xc0\xb9\x8b;\xc8~#\xa3E\xdd\xb4\xbc h\x9a\x92\xcc\xaa\xeaO=F\xb5L\xf6BxsQ\xaf\xbe\xf1y\x15\xb3\xca&j/\xa9\n::\xd6\xdc'\xcaO\xa4\xb7\x9b\x93\x1f\x8a\xe8\x86\x14\n\xf4YSZN\x8f\x91\xf6zV\xb4\xb0\x82\x11D\x9dN3\x07\x98\xd4\xa4p\x10O\xc8(/#\x81tov:n\xa1-\xa3\x18\x81$\xb2\xfd\x08\x01;\xa6\xacE\"\x98\xf4\xb1w\xc6(\xdf\xf6vFKb;l\xe2\n\x8dB3p4\x97\x9a\xd2\xd6\xbb1o\xf9\xa8\x8bG\x97oG\xddu\xdb\x83%\xf6&\x8d{\xf7\xae\x10\xdd\x8c\xc5\xfe\x06X\xbc9nUW\xbd\xd8vP\xa3\xcd\xd3\x88\xb7P\xbf\x02>[\x81\xd8\xf6\xebV@\"A\xf8\xf3V\x97\x83L\xe9\xa5N\x9dgp)\xdd\x1c\xa0\xda^\n \xc84<S l\xc4\xe5\xb6\xa6m\xef\x97m\xe2\x81\x8d\x9fIN\xb38Z\xdaQ\x83\xad\x0c;7\x07F\x90\xe8ma[[\xd6\x17\x01T\xb6\x8a\xb4\xe3\xaa\x86Y\xe8\xcf\xd5\xf7z~A\x02\x9c\x9e\xd8\xa0g\xbf\x06\xa6\x90\x1f\xb9MP\x85:\x9f\x00\xf10\x0f\x80\xb0\xba\x00\xe2\xd1\x9cj.\x0el\x83\xee3]\x1b\xa9\x1d\xd5\xdczk\xe9\xfa\x9d\xa4\xa9\x90\xc8\xa5\x9e\xcbV=\x00\"-u\xe2\xf4\xa6\xa2.\xe4~\x0e\xbb\xfb\xd2\xba\xc5v\xdc}\x0b\x1d\x88\xbb'5wJ3?\xf4\x82\xe0\xba\xad\xba=\xe3\xb7\xc4~\x1e\xc1\x9aJ\xc2\xe2\x0f\x83\xae=4\xddjk\x98\xdd\xca}q(\xab&\x8d\x96\xd7\xfc3\x8fRGT\x84\x95/R\xea\xf8\xab\xca2\xcb\x8f\xce\x9a\x8c\x8al\x94\xad\xf8\xc2\xe3\xe2 u6\x1a\x96\xf9\xae\xf2\x0b\xa2n\xc5\x7fD\x84?\xd8S\xb0\xf1\xb4\x06\x0f\xd3\xb85\x0e\xd2C0\xd5g\xe0\x86<\xd1\x97\xce\x9eV\xdcB\x87]\x82\x86\xed\xfc\xee\x7fX\\\xc68v\x88\x97$\xcd\xd7\xd2m\xe0\x19\xda\x83\xbd\x01\x8f=\xb7\xc3\xff\xdd-\xc7\xaa\xdb{\xc0\xff\xe5\xb1\xea\xf6x\xac\xba\xfd\x1e\xff\x97\x7f\xbf\xcf\xbf\xdf\xe7\xb1\xed\xf6\xf9\xf7\xfb\xfb\xfc_\xde\xce>og\x9f\xb7\xf3\x80\xb7\xf3\xa0\xcf\xff\xe5\xed=\xe0\xed=\xe0\xed=\xe0\xed=\xe0\xed=\xe0\xed=\xe0\xed=x\xa4\x8d\x9d\xc7|j\xdb\xc0\xa2\x11\x8b*\xbeNQ\x1ep\x13\x8f\xe3#\x1e\xae\xb2J\x10\xe5J\xd1\x94\xa0\x17\xb0\x82xH\x06\xd1z`\x8b\xd9\xb5\xf71\x9eJ\x1e\x16#\x8f\x1dR!\x8fr\xa3M\x08\x9a3\xb4\xdc\xe4r|\xe6\xe2\x9c\xf3\xccPy\xa4\x9c\x8c\xf9\xe9\xc6\xf0\x142\xb3v\x80g\xb9\xeb\x14\x99\xa52\x8c\xa2\xe3Sj\xd2\xef\xf7w\xfb\xfd\xbe\xc3r\xf7\x8a;\x91\x13/\x9c\xf3K\x11R\x8e-\xbe\xf6\x02\x7f\n\x93hJ`E'c2\xab\xe4w\xd4\x04\x9e\xb0H\x9dp\x80\xb1~0B,\x8b\xe4\xd9\x01\xdb&\xb0=b\xe5\x0e<}\n\xfd\x1e\xca\x14\x7f\x84~o\xb0\x0b\x1d\x16\xffS\x97|\xcc\xb4'C\x9eSP\xcd\x9c\xbb\xe1\x8ek\xc22CT -\xa52`D\xec]\xb5\xc7\x03\x16;\xa3\x1b{W\\\x10\x8d\num\x1dnP\xcc\xf1\x18\x8e\x84\xf0\x14\xbc\xc7\x0edl]x\x08Z2\xf6:\x9d3\x07\xe3D\xdc\x87\x9eF\x8a\xb0\x8e\xa2,L\x0b\xe7\xac\x90\xcc\xbd\xd4_\x13U|\xe0\xc1\xf8\"x\xaa\x1ar\xf1\xc7\x8e\xe0\xe9\xd3\xa7#\xe8;\xdc\x9b\xb53B\xc3#zb2\x07\xd7\x90\xbdz\xac\xac\xd3\xef\xa7\x84\xdb\x948\x17 \xda\x9a6aQ\xb3n\x1b\x16\xb5\x9a6\xa2\x8eD\x97\xfa\xd0\xad\x00\xe2\x88o\xe7\x84r\x93\x1d\xea\xe6\xe1DM\x99/\xe2[\x10\xd6\x18\x97\xad \xac!\x15\x92(\xec\x84E\x0b%\xac\xf1g\x11\x07\x93dBW\xc5\x0b'\x8b(\xdeH2\xa9\xe5\x06\xf9b`\xd4z+\xf4\x96\xc4\xaaK\xec\xf9\xd9\xc3\xbf\xf0\xe7\x1b\x8d\xbd\xcd\xd0Y\x9b\x16\xfe\xf7\x05G\x1e\xf8\xe1\xe5\xdd\x8f\x9d\xb7\xfa\xc5G\x1f\x05\xd3\xbb\x1f\xfc\xef0\xf0\x99\xff\x91\xdc\xfd\xc8\xd3\xf4\xf7\x18z\x14\xa6\x93(\xf8\x12\xbb\x956MG/\x9a\xff\x82;\x96v\x95\xf8\xbf\x90/7 \xde\xfa\x17\x9c\x83\x9fz\x81?I6\x9aB\x9b\x19\xf8\xbf\x03\x16mLvZ\xc1\x1e\xc9\xfd\"&\xb3/\x0b\xf8d\xe9\x05\xc1F\xa3o3x\xd1\xea\x97\x06=}}\xb9\x19\xe2\xb7\x1a\xbeh\xf6\x8b\x8f?\xbb\xb8\xfb\xc1g\xbf\x07\xd5O\xb2\xd5\x17\x18\xf9\xea\x8eF\x1e\xda\xfb;\x8em-\xbdt\xb2\xb0\\\xe8\xd7\xd7\x96\xc62\xce\xebi\x15\x9dz\x88\x88GH\x02i\xddE\xa2/+\x1aP\xcf\x90\xe7_\x0b\xc7\xc4\x9c\xdaB2\x9b\xf7\xe1@\xd8\xd81\xcf\xa8!\x9a\xb7q}n\xe8\x8c\xc9\x99P\xd8\xc7\x95X\x1f\x10n\x9a\xd5\x9f\x03\x93\xeb\x14-\x17\x06\xb7\x00g\xecV\xdd.\xa0\x15D\xa3&\x88f%\x88\xc62D\xe3\x96\x10\x95\x04\x88\x18C\x95\xf9\x08T\xf6\x86\x832rX\xe8\xa5;\x03hB\xbc\xf8\xdf\xd0\xf3\xce\xa0\xb9\n\xfcT\x8b\x9c\x15\xcbI3\x98\xc4EFh\xf7wUc=\x10z\x8f\xeakv\xb9\x867eU\x8d\x885A\xe3\x14\xcb\xbb\xb8\x98X\x92\x89mYt\x8e\x1a\xa4is\x1d\x02\x92%\x9a\xd0\x01\xe8\x03\x01@\xd9\xd7f$\\\x8bx\x12\x9d\xdc\xceMM\x86\"\x7f\xbb\xe5\xcb\xa9\xd3\x8a\xa8x8:\xfdgkf\xc2\x9f\xb80\xc1p\xd3\x01\x0b\x8b_\xe7u\xbe`\xa1;\xfdy\x18\xc5\xe4\xc8\xc3`}\x96o\xc1\x90\x1ey\xd0\xa1e\xcb,H\xfd\xc0\x0f\xb1hY*\xcaB\x1f\xaf\xda\x0f\xc0\xcaJ\x05I\xeaO.\xaf\xe9\xfbk\xfe\xde<\x84i\xbd\xd3\xfb\xba\xbc\x9a\xb4\xb3\xdd\xc1\xa3\xddG\xfb\x0f\x06\x8f\xf6\xd0\x8e\xff\xe9\xd3\xa7u\x0d`4\xd9b\xbf\xa7\xdd\x04\x83\x9c\xbb\xb0\x80\x0eXs\x93\x85\x00\xaa\xfaX\xf0\xaa\xb8\xdc\x02\xbb\xcb\xbc\xe6\xed\xd0F\xfe`\x1fl\xfd\xf0C\xe2X.,t\xd7\xd0\xf9\x83\x0e\xec\xd7\x0c\x17y\xc0\xce-\xdb\x9e`(1\xd4*C\x07\x92q\xef,\xc7\xf0\xa70E\xad\xe1\x8aG3\xe1*\xa4\xa9+>p\x1c\x17\xb6\xd0h\xbf\xa4\xe0\xc2\xc4\x1f\xbd\xb3\xfc\xe2-v\xebY\x9f\xd2\x83S\x0f0\xd0\x00\x04\xf0\xa4\xaa\xe4\xde\x86\xc1c\x08:\x1dG^\x99B\xa3\x16\xa0\x15\xaf\x8d?FZ\xe5w\xe9\xb9q\xdc\xea\xe098\x9e\x141\x15\xf1\xf2\x9f9\x00\xad\xe8\x07\x0c\x12}\x87g\x89\x90\xc0\xc6b\xc5O\\X\xe5\xad\x8e`\xed8\x8f\x1d\xb8\xee\x06^\x92\xbe\xc4\xb6\xf1>\x83\xf7s\xef\x9e\\\xa4\xc6\xf4\x16\x0f\xdf\x8cSv%S\x84\xf5\xde\x9a\xb1\x06(\xc9\xc4,<\x9f>\x01_1\x96\x93G]>:\xe8bp\xb0\x86\x03X\xf1\xb2\x9e\x0bk\xfc\xa42\x02\xc5,\x99\xb9*X=A\x1a\x85\n\xb3\xe7H\x10\xb3[Q\xb6\xf2\x99\xa9\x92+8\x80\xf1\x19\x0c\x05\x0d\xcau\xb1\xaa\x14\xa8\xd7iK,\x82\x81\xe5\xba\x05Su+>@b\xaa\xc2\x82\xa9\x8a+LU\xa8c\xaa\xe2M\xd9\x80z\xe5|f\x87\xf6\xe0a_U3\xfb\xbchg0P\x8b\"^\xb4\xd7\x7fHIL^&\xc6\x80A\xf1\xf5\\\x1a.f\xda=?'\xc9\xabh\x9a\x05\x18G\x1e\x86\x9a\xa5\x98\x92\x99\x97\x05\xe9P\xbd\x9f\xff\xa7\xea/q\xd2\x8e\xfd.\xff\xca\x85\xa8\xf8i\xa46|L\xd5\xbe'\xd1r\x15\x85\x94\x80\xe8F\x06\x98{B\xf8.}\xe3]GYJ\x17\x8fw\xd8\xb4Y\x8a H\xa8\"_Ny\xb7_S}\x8eW\xe2\x82U@\xbcr\x0b\xc2\x03\xc7\xcb\xe1\xea\x9d*\x9aLl\xca\xf9=\xd4\xa1 \x16\xed\xf5th\xc2\x8a*\xc8\x95\xe5E;j\x91\x97\x17\xed\xabEI^\xf4@>\xda\xf0\xd5\xfe\x9e\x1e\x15'\xbf?*\xcej/\x18\xf3\x91\x91:\xc1\x9f\xd2\xde\x1c\x9b\x1dN\xe8\x88\xe3bA\xa6\x16\xd8\xa4{~\x8e\xce\xe7\xe7\xe7\xc8&\xf4\xdc\x02\x1f\x1d\x9b8\x0e?\xadX\xf5\xfcxTE\x0c\x1d\x98h[\x9e\xd4\x96\x0b)\x1fFTz;\xae\xce\xe5\x92\\\x0f\xc1\x8aI8%\xb1\xe6\xa6\x94\xe3]#3\xb0\x96\xf3c\xac\xe2he\x88?\x03\"UFwN\xd2#\xb1\x85\xcduYd\xf0dE&,!P\x14\xd74\x1c\xb3\xd0\x1fq\xdc\xa2.\xdd\x13\xc4\xb6\x8e\xa20\xf5\xfc\x90T\x1cn\xe4'buO\xa2\xab\xbaZ\x99h1\xa8\xab\xe5\xb1Z\x18\xb57\xb10\x9c\xa9\xb9\xf2\x84U~\x17\xad.\xbc\xb8\xa9\xf2\x8cU~\xe6%\x9c\xde5}\x10\xb0\x0f\xa2\x90r\xeb\x1f\xbc\xc0\x9fzi\x14?\xf3\xa6s\xd2\xf4)&t\xe8\x06\x917\xf5\xc3\xf9i\xea\xa5Y\xa2F\xb2\x97\x9f\x05z/S~\x89\xdd\x9f7\xb0\xf7\x94GZP\x04\xb1\xad%I\x12oN\x90+\xb24J\x01(6A\"P\x9d;T\xf2\xdcQ\xb6o\xf2\x94\xa4\xcf$\xf0\x92\xe4\xb5\xb7$C\xb0\x92+o>'\xf1v\xe6[\xda\xfa7.L\xe0\xc0\xd8\xcf\xc4\xc5$l\x0eO\xc6\xe6\x82\xc5\xe1c!_\xb4b|\xaa\xfe[\xcc\xed\xddv\x9c~8\x8b\x8c#\xbc\x93\x1e\xf8\xc0\xb7'\xf9\xee\xf8=\xba3t\xe2`\xf8\xb7\x99\xe7\x07d\xfa\xaf\x12\x94\x8b\xdd\xd6\xbd\xa5~\x1a\x10c\x0f\xd6\x0b\x04\"\xa4\x11\xd0a\xc1\xe1\xdb\x97\x80l\x88Oi{\xd7r\xcc\x83\xf08rKkq\x84\xae\x95_dE\xcc\xe4\x013A\x9b\x18>\xf1,\xbd\x8f\xdf\xfa\xd3t1\x04\xeb\xe1\xc3\xde\xeacM{\xacz<\xf7\xc3o\xc8,\x1d\x82\xe5ei]\xffE\xfd\x13\x7f\xbeh\xf9AJ>\xa6\x87\x81?\x0f\x87`M\xd0\xdf_\xbfDP9\xdf\xf3\xb7\xff\n\xb01&\xcb(%\x85\xc7n#NZ+\xcb\xe5\xa4v\x8a\x88\xb9\xb5B\xe5_\x92MD,\x8c\x06\xcc\x9cq\xac6\xf7\x11\x89\x1eL\x15\xb2\xa6\nA\xbes\xaa:\x0dE\xea8+\x85H\xba\xb1\x8b&sNIb\xa9\x89(m\x1bl\x8a\x8a\x90;\x15\x8f\xa5\x81\xd3\xd5\xe6Am\xd3\xa2d\xdc\xa7\xcf\xff\xd6\xdf\x91\xad\x96\xa9p\xf2\xc8\xb1\xadrGV\xb3\xf4g\xe6\xd4\xa5J\xbe\x92\x86\x14\xe06\x17o\x83\x87{\x1a\xc1J\x02\x93^\x1ely\x01\x12\xabb\x9f\xa8^\x8c\xb3\xcd0\x8ba\xf5U\xeb\xce\xc2\xabk\x8b\na\x94\\\xb3qWvmy$C\\\x1d\xa7;\xdb\x10b2\x10*\xed3\x89\x8c\x02U\xbd\x8d($\xbaas\x0e\xb6\xca\"=b\x0ey\x0f\xf7\xaa\xfew\xbd}\xa7;\x93\xfd\xe8\xdb\xb4\xd8r\x12\xaa\x01\xeb\xe7Mb\xf0\x88\xbb!>\xe2n\x86|V\x83G\x0ft\x9b\xf4\xf4zy\x11\x05m\x9an\xb2\xf34\xd8\xe1\xaa;\x98\xdby\x1a\xbc\xad\x0d\xce\xd6\x03\xb5q>\xfeG}\xa7\xfb\xf5\xf1\xf7\xe5\xb2 /S>\xe1\xa9\xe5\xd4\x1eXj\xb9G\xeaxXn\xb9=\xf55\xcf-\xa7\xbc\x9d\xe6HR~\xbf\xe6\xefU4\xbd\xe6#T=\xe4\xe6\xfc\xbd:F\x9eV\xae\x82\xed\xec\xb5\x1a\xfe\x92\xa5\x94\x1b\xe83\xcaU\xb0\xed#\x9b\xa8\x1a\xfb\xee\x94\x81E\x95\xd6\x8e\xf9\x08\xd5\xea\x87|U\xd5N\xdf\xb0\xf7j\xf5\x9f\xf0u\xc5\x0d\xf5\x12Fp\xa8\xe6\x90{ #x\xa3\xbe|\x85i\xe1\x94\x97\xefP\x1ed\x18].9\xc2\x92\xbf\x9c\xbey]~\xff\x16FpD\x8f\xf2\xa3n\x82\xaaW\x7fv]\xaeqB\x05G\xdb:_\xf8\xd3) U\x11\xfc5+M\xa3\xb7\xb1\xbf\xf4\x99\xadv\xb9\xc67\xe8\x00\xa6\xcd\xb9_\xae\xf8\x9c\x92{\xdbJp\xf4\xdb1\x99\xfbI\x1a_\xab\xcd\xfd\"\xd7\xaa\xa4\xb9|\xc1J\xa3\xd5\xb6\xa1\xc2{M\x12\xf3r\x8dg\xa6\xf8\x01\xef\xca\xf5~F\x88\xfe\x955V.\xfa\x1eF\xb0\xf53F\x0e\xffY\xca\x08\xa0\xfc\xdd\x9d\xf9\xe1\xf4h\xe1\x07\xd3\xf2\xd7\xdf\x02\x8f\xf18\xa9w\x8d\xe3G\xdf\x03\xd8\x1a\xc1\xa9\xfd\xd2\xfe\xfb\x0d7\x0f\xd33\x91\xed\xe2\xb1@\xd1\xf0K\xd9\xe4\xac^0\xe0\xda\xac\x07\xc6J7N\xd7\xd3\x16V\xd9\xf2\x1bG\xad{\xe3\xc8\xd1\x0f\x0c\x8c\x00H\xa4\xf8\xd2~\xaf\xbf\x9dE\xd7\xd5) HJ\xe0\xfd\x98\x9c\xb9t\x92\xbc=\x1e8,\xc5;\x8a\xf7\xf4\xe7Kl\xa6\x12 \xf9\x06\x86\xf0\xb2\xbcd\x1fj\xb5\x9e \xd9\xd0\xff\xc2|\x0dO\xedw\x05\"\x98\x0d\xd8 K\xa5\x9bV\"|\x96\xbb\xff\x1aF\xf0\x8c\x8e\x98o\x8b\x12\xd6v\xc5\x91]\x02b\x0dBi\x1aI+\x00h\xd5R)\n\xf3\xbb\xba\x19|\xd5\x82\xd5+5<\x12\x8b\xf4\x95\xfd\"_\xc0%\x8b\xf2\x0f#\xb8\xe2\x19\x8d\xe8;Z\xe2\xdb\xbf\xe0\x9d\xdb\x01\xc6c\xc8 \x10f\xe4\xa3\xfd\x9d\xb0\xbc\x93\xe3\x93\xb31a\xb7\xa6\xe2\xf7\x88\xe7\xa8\xc0E\x0bM\x1b\xa1hr\x08\x1f\xed\x1e&\xb6\xd0a6\x0c\x8b\x0e?}b\xd8w\xe2\xc2G\xbb\x8fyv)\x7fR\xf4K\x87\xffm\x0e\x0d\xfa\xed\xcb*_\x0bU`\xfe\xa1\xcd]\xe3R\xeb8\x91;\x93\x87\xcca\xfc\x9a'\x82#th>K}\xc2\xa21\x8a|\xdf\x11<\x05\xff\xb1\x03_\xd9)\x83R<\xf61n\x00\x19\x87\xba\x10\x96b\x05\xeb&\xf0\xe7\xd6\xdb\xe9\x9b\xd2](.|\xcaRY\x19{\xde\xc2\xda\x05\x02!j\xb0\xbc\xa3[>E\xa6\x94\x19\x04\xd8[6#\xd9\x85\x0b'\xff\xf3\x17\xf1[\x94p\xecY\xf8 ]\xbc\xf4\x0c\x0b\xd5k\xd9\xf2\x14\xff\xd2f\x8d\xfc\x19s\xdc\xbd\xd0\xe0\xb5\xa0S\xf9\x90\x08\x1f\xd2\x0b\x16bY\x8f\xa7\xc2n\xe6\xd2\xae\xb1_\x11\x80\n\xab\x8dW\xb6\xca\xa7O\xca\x8e\xe2x[\x8d$sS\x07\x8e\xbf5\xae\xb8\x1a\xee\xe2\x95}\xc1\x9c\xa0c\x1e\xc1 \xe2\x11\x0c\xba\xa5\xdc\x8fl\xf4\x94\xd9b) qe(e;\xc9\x7f%,T#\x0bDa\xc6\x9b\xb8n\xfc\xdfm<~N\xc2\xd8\xf8_a\xe0\xa1\x170\x04>\xa9\x88OJ\x84\xee(&\x95=v\xc4\x9a\xe0f\xcb\xc4\xacB\x8e\xc1\xef\xc5jElJ\xbf\x8cI\xcd>\x8c\xca\xb3*\xea=\xc3\xa5\xf5l\xfb]]\x14,\xc4P\xba\x9ddB_\x0d\x99n1\x96\xb4\x88\x0f\"\xe5(\xaeDN\x17W^+\x9d\xcfX\xaf\xe43\xd6\x93\xbc:\xdd\xca\x14\x89\x94\xd3\x01\xc9\x19\xa9\xac4\xca=\x04\x9b\xf4E)K\xc4\xffOr\xd3\x87\x98\xb4\xe8/.\x15Q`\x04_a\xc4\xa1\xbd]\x07\xff:\xc6\xff\xff\x8d\xbe\xdb\xe7\xaf\xfe\x8c\x15z\x0f\xd9_\xdf\xf1\xf4\x97[\xa1\xfd\xf0!\x02\xd5\xa3\xb3\xb7t\xe2\x82\xe5\xd2\x8f\x91\xbcL\xbb\xf5\x17\xcd|\xbc\x1f\xecEIuE\xc7\x9b\xd9\x19&B\xca0\x11R\xc6T:\xcfTh3\x84\x1dJ\\\x8bl\x17\x90o\xe6\xbfRaa\xe1%/9\xfa\xbb~r\x14\x85\x13/=]\xc5\xc4\x9b\xa2\x90#\xf8/\x17\xcd\xce]n\n\xe623_\x97\x87rt\xd1x\xc8\x95\xe4(W\xac\xcb;o\xee\xca\x99\xfd\xb9\x9d\x91\xe5Z\xf4\x18H\x19\x85\xf8k\xb1E\xd2\xf4\xb1\x03\x0b\xfb\xaf\xe34-'\xbd-HP\x8a\xd9J\x16\xdd$\x8dbB\xa95o\x85\xa4E3!mfm\x93t\x1c*\xedP\x08\x9e\x96`\xc7\xf7w5\xa0Q\x14\xb7d\x15}\xfb9=\xd3:#4^<\x80\xe7tO\x0d\xd9?\xa3j\xea]\x85\xfc^\x92\xeb\x17\xcd]\xa19\xe7\xd7h\xceY\x9b\xd3\xc1\x03\xc6\x01W(\x13\x94\xc3\xed\xf8!<\xd7\xdb\xd3\xd1\x9e\x9e#\x177\x92\xe3\xbb\xd72\xf1YBNI\x9a\x92\xb8AJ\xfb^\x17I\xb2\xd2\x92\xbf\\\x05M\xf6\x05\xdf\x97\xb3\xd7\x01\x94\xf5\xba\xaen\xa1\x0d:O\xa6\x9ao\x91\xca\xaej\xe2F\x99\xf0S\x1b\x93\x96\xfd\xc1>e\x9cN\xedb\xab\xfa\xd5\xafj\x8a}\x92\x0c\xe1\x0f\xe5\ns\x92\xbe\xb9\n\xc5\xf7\xcfI2\x89\xfdUJ\xd1\xe7/u\x15_{K\xda\xd8\xdf\xea\xea\xb0m\x90\x0c\xe1\xbb\x12\x1cQ\xc1R\x06\xa6\xbd\x85\x07l\x8d\x88/\x8e\xc1wjxL!\xa6\x8d\xc3,\x08\xce0\xfe\xcd[[p\x9d\xd6\xdfo\xf8\x9b*\xec\xbd\x8a\x11\x8f\xf2 [\\\x85b:.X\x7f9}\xf3Z\xe3@\xce\xf5EM\xfb\xae\xc4\xfap\x86-=\xe3Y\xe4\x1f\xebb7P\x81\x82sd\xc5a\xef\xebSx\xf3<\xaf\x9c\x1d\xea\x9f\xb9`\x9f\xdb\x95\x94?\x9c\xc1\xffZ6\xe6\x9e\xf3j6i\xc3\x8c\x8b\xbe\xb4\xba!\x16\x1a\x08\xf9\xcc\x8au\xa6\xe3\xd2~\x89c \x03\xc0\x91\x84\x8e\x9dN\xc3\x85\xb7\xdc`\xe9\xa8\xaaz(\xa1\x95\xa4B\x18\xbfFV<\xb4\x07\xfb\x8e\xacZp\xe1u\xa9\x1eK\xc2\xf2f\x86\xd9\xe4\xde\x15\x84\x1b\xff~\xe5\xa5\x0b\x17,\xfa\x0f\xb7S\x81\xc0\xe6J\xc3\x1c\x07\xb6z\xad4\xff\xd2\x0d\xd6\x9ec[K\x92z\xba\xd0\xbb\x1a\xe5m\xa4\xd7\x9a\x8b`\xa4\x8e\xaa\xf3\xf4\xaav\xebI\xa1\xe4\xf3\x93\xe3\x8f) \x13\x9f\xca&\x9f>\xd5\x13D!\xf8\xd4R\xd7 \xa5\x9a\xa8]o\xa5\x9eK\xec\\\xddH\xd6$L\xf9p\xa20\xb1\xa9\xc0\xaf\xec\xc7rW\xf5<\x0e\xe0Q\x9c\xa2\xf7\x91I\xdaC\xb5\x9c\xbe\x90>\xfe\x10\xac7\x16t\xa0\xd3\xf1\xaa\xbc\xa4x\xae\x86j\xb0Z\xf1\xe8\xb4wu\xb0\x0b\x94\x1cR\xd5\x91}}\xfc\xbd68\xf9\xeb\xe3\xe3\xe7C\xd8\xeaWKf^\x92~M\xae[\x9c=\xa0u\xe9\xd0\xa9\xbb\xb85$s$e\x86Fr\x99u\x8a\xde\x14o\xd1\xcd\xc2\x90C\x81e\x01\xc0\xe51J\xe3y\xbd\xa44\xa0\x17\x06{\xac\xbcz\xe1\xb9b\x1d\xd7\xd4\x9d\xa9\\\x93x\xf4\x8b)x\xfcq|\xd6\xad\xe6\xce\xd7\x84p\x9b\x93\xf4[\xe2]n\x02\xf9[\x01dK\x1f\xe3\xa5\xa8M\x8c\x11\xab\xe5\xe73\xc0q\xd5\x06\x1cQ\xf8\"&\xe4\x97\xc6d\x82P4>\xa1\xc7F\xd0\xa5\xc8\x8d\xe6\x146?\xa68\x98\xe8\xef\x19rD\xed\x0c\xab[\xd3\xe4\xca\xbd\x93\x08\x19\xa4'\xc6\xfb\xa6\xe4G\xe6\x89\n\x05]\xac\xcd\xd4\x16\xb2\xc0\xba\xe5\xb5\xc2\x83\xbc\xbaB9\xf7\x90\xb9\xfc2\x94\x02\x84\xf6\x1eug,\xa1J\xef1x\x05\xf30y\xec@\x92g.\xa7\xe7\x867\x9e\xa0\x96\x04\xe5{\xe4*2=O%\x19\x89l\x06\xd0\x87\xfb\x06\x08\xb1\x08\xef~\xc2RY\xc9\x07\x90If\xb5\xb0*\x92\x9c\xd8\xbe}\xa6\xab\xca\xed'_\xe2\xbd\xea \x1a\xb1\x1b:!oV\xcf]+b\\\xbfD\x06\xaf\xfcp\x1a]Q\x88\x16\xbf\ns\x17\x95m\x86\x83\x9aB\x9b\xb5@\x05\x80\xb1\xce+\xa0\x9d\xa8\x8f\x81v\xad1\x1b)|\x8bM\x9e\xe1\x88\xf3Di\x8d\x17 \xe6\xbc7\xb9\x94\xaa!!\xcd\xf9\xe3\xc5\x10\xb9kQ\xa3\xbd\x92\xcdS8\x97\xedn\xf4\x08\xe0\xc0\xdf\x1b-\"\xfa\xbd\x07\x8emy\xc9u8y\xb9\x91\xfd\x86\xf8\x94%GA\x1dL\xab\xef\xda\xd9}<\xba[\xbb\x8f\x9d^\xaf\xc6\x08+\xf9\x0c#\xac\xaa1\x90Y\x12.\xf73\xc4q\xf51\xa7U1\x9fV0\x94\xb6\xb2J\x95}\xbd5D\xd4F\x8c\xa1T\xd6G\x12\xba\x15S\xf9\xe7\xde=4\xa3+\x07v.\x14#\x84eCe\x11\xd9\x12\x92\x82\x97@.Ml\xa9\xe1\x18\xf44\xb0\x02\xa0!h\x17\x05e1+w\xe6\xb0\xc0\x0f\xe1\xef7\xd5\xbb_m\xca\x1b\xf3\xde\xb5\xf9\"R\xd1\xe8\x05o I\x82\xcb\x0d6\xba3\xbbb\x12\x00\xd28XF2\x188\x0e\x1d\xc0\xf8\x8c\xdf\xc5(Yf\x91l\xdf\x86:\x10}f\x8a*W\xc2\xc9\x88\x0c\x0d\xa3V[(\x95Y%\x96\x0f5\x95\x1ceF\x10\xc2\x90\xe5\xc0 \xdb\xf0\x17h]\xb0\xd5wL\xfa\xf6\xc9\x82L.\x87\xd2uB\xabM\xdb\x8aN\xecT\"\xe2}.\x9d\xd8\xfdlKD\xc3!\x14s\x1bUVg\xb3\x81\xdd\x8e\xdc\x08\xc5\x1bZ*\x15\x1d\xb6\xa20M\xf6l\xbb\x06\xdb\xd3==\x97\xb8S\xb1\xf2b2\xfbN_\xb5\xf2bl\xdc\x8e\xfa:\xe1\xd5u\xe9\x89\xe9{\xb5\xf9\x19\x7f\xaf\x0e'\xe0\xcd\xab8\xba\xc2Li%+\xe2r\x85\x85T\xe1\x857I\xa3X\xb1\x85\x9a\xb2\nA\x14\xea\x1bXW\xe3@\\7\xca\xf0mn\xc4\xe7Za\x19\x8d\x87b\x12\x9aD\xfc\xa5\xb7\x1aB\xd4]z+\xbdp?\x8b\xe2co\xb2\xa0u\xf8O}\xbdI\x94\x85):\x1e\xd3\x1f\xfa:i\x84\x04\x90\xd6\xe2?\xf5\xf5\xa20\xb8\x1e\x82&\xe7Y\xb5zn\x9c=\x04\xbf[\xe3\xd3\xf66\x8bI\xa9n\xe9E\xb5~ \x03\x86\xa0\x01\x8e\xbc\xc2C\x98V+\xf8 \xfau\xe5U\xbcn\xf9\x8df\x90q\xb4\xa2\xc7j2\x04\x8d\xf7\x1c\x1b\xd2Q\xe0%\xc9\x10f\xa6r\x8e\x93C\xd0\xac\x13\xab\xf1\xca\xff\xe8\x87C\xd0\xc0\xfe\xf9\x9bWC\xc8\xaa\xef\xd7$N\xfc(\x1c\xc2\xa4Zv~\x9e\xe05\xd6\x10\xd6e\xe4\xd4S\xc8V\xa99\xea\x89\x8e\xacQ3\xf4\x12\x7f~/\x94V\xe9y\xaa\nM\xe2\x02\xb0\x81\xb2\xf5T\x0e\x96\xa5\x13M\xaf\xa2C\xae\xb6~\x1bE\x81\x9a\x8e\x14g\xd1\x9dEY\\W\x8bR\xbd\xfb?\xdc\xef\xdc\x9f\xeb\\{gFA\xc8\xb6,\xe8@\xea\x94\x82\xbd\xff\xe1\xde}K>\x8f\xaa\x0d\x06\xdas\x0d/|i\x1df\x85\x86\x7fN\xa20e\xb9\xb9H\xfe&c7\x88\xb5=\xact\x0b\x05\xd2\xb2\xa4\xd8\x93f\xb3a\x19\xefV\x91\xdb\x99l\xe7c\xc3)\x1b\x88\x9c?]7\x8e\x85\x18\x87\x86\x93\xc4\xe9\xc4$a\xde\x1fb\xc6\x97\xe4\xfamLf\xfeGi\xce\x1c(a\x05(\xf1F@\x996\x03\x85\x0d\xa7\n\x96\x0cK\xf3\xb1U+x50Md\x98j\xa8 ;\xe8(l\x13\x05\xb6\xe5\x05(\xe97\xec \x95\xb1\xd7\x14\xe3b\x84o\xd4M\x17^z\x82\x88\x99\x08d\x17\x8e\x9c\xb05b\n0\xdbW\xa8'm\x87\xbe\x9f\xa0\x9a\x08\x89\xf1a8=a\xf8\xfc5\xb9\xa6\x1dd\xd0\x01{kB\xe7\xcf,yP\xb9C\xff\xc2\xe4\xf2\xf8\xeb\x00,\x0b\x860\xb3\xf1O\x87\x8a2\xf7Qg\x1b\xa2\xe1\x10S\x05M\x9cztYK\xe8\xe2V#g\xacy\xd4\x0c\xd5\x89V\xcc\x90\xdd\x0c\xa1hf\x87b\x08U\x83\x17\xbaV\xe8\x9a\x8b\xa4`j\x13\x8c\x8c\x81\x1d\x96+\xa3\xc6\x7f\xea\x82\xe7\xb8\xb0\xe8\xc6$ ^Bl\xaf~\x0e\xd7&,\xe34\x83\x0eVj@\xfc\n\xa4\x8b\xa3)\x11\x06;u\xf6@\xa5\xad\x81\xee[\xca\xee(\xbd\xacl\x10\xba(\xdetJa\xe0\x87\xf3w\x91\x1d\x88\x89\xdej \xf9F\x96z\x95\xf7\xb2\xf4\xfa\x0e\xc7\xbcp!Q\x04\x8c*\xfb\x96\xb3^u\xa7\x98xP3J\xf1\xa9dM\xa0\xb9x\x10D#(c\x92.\xc9:\xe2\xd1\nS\x17@\x90\xe3\x91z\xdfX\xa6\x0c\xc8O~\x91\x01\xeb\"p S\x01\x9b]q\xb1U\x10\xa6\xda\x0d\xc3|\x19\xa6\xd1\xb7~\xba\xf8Z\xac\xf6\xcb0%q\xe8\x05CX+\xc7,\xe3m\x1b\xf5&B\x87G+\\s\xd7\xc3\xbaA\xe4\xfcp=\xf3/\xf4\xe4M\x00 \x02\x00z\x92Z1\x10/\xf0\xf3\x8b\xf1j\xa1\xbd\xaf\xd31\xdb\xa1M%\xaf\x86y\x0b\xc3\xc1\xae\xd0\xa0Pl\xad (\x07\x12\xac\xaa\xdf\xad\xa2\x95)\xf3\xb5\xc0=\xdc\xbd<\x12|\x15^P\xa7p \xc9\x15~_1B\xaa\xd5\xbfi\x95T\xb2\xc2\x08\x0d\x0f?}\x82\xd8\xb6\x06{h\xcb%\xd16\xdbq5\xf3\xe4w\x1cOx8\x90(\nN\xfd_\x880>V`B\x0f\xb7z\xb3\xa9\x0c\x934\x97^yZAS\xa6o-\xf6\nH\x96\xc6\x86\xebQ\x01\xda\xd2\x98\xb9\xd1kXP/\xb4\xeb\xf8\xf4 2\xfa6\x9f/3:\xce\xff\x1c\xb1\x8cp\xa1\xa0b0\xa2g\xa7\xc6\x02\xb9\xca\xe7P\xce\xa2\xc4\x83\x0fU\x80\xd0\xa7\xc2\xcf\xb7\x84\xc1m\x90\x1cd\xd8m\x82\xe8\xa0Cv\x11\xa8P\x07\x0e\xd0\xe2<\xe8\xf0\xbeb\x92\x05zp\xa6\x8b\x98T\x00\xda\xe6\xc0\x80\xcf\x84V|'\xd0\x8a\x19\xb4tG\x8cx\xda\x03\xac\xe2\xa5\x01z\x98U\xe5\xc0*\xc8\x0c:o\xf8L\xa8\xf9w\x025?\x87\x1a\xe3&\xaa\xb6\x03\xb0)\xe0*\x86O\xd5\x16\x0c\xe7\xdag\xc4\x0fk>\xd7\xfa\x05\x1f\x15?f${\x1f^\xd7\n\xb3\xe5\x05\x89\xe57\x05Ty\x17\xa4\xfb\x87?\xf0\x91\xd1wE\xfe\xf4\x99\xcd8V\xcb\xca\x93\x87y\xd0\x81 \x9dp\x0f\xc5`\xc7\x05\x8d\xc5\n\x9dqM8\xd65\x8a\x9bR\x93CLd\x93\xe8\xa1R\x96\xd0\x89\xc6\x1f\x01d+\x8bkfOq\x0dO\xf2$<\x8f\xe1\xba\xd3q`\n\x9d\x11\xa4\xf6\x8a\x9e\xc9\xe3\xeb3\x17\xd68\x97\x95\x0b\xd7\x0e_\xbd\xea\x0808\xa6\x99C\x98\xb3,\xa5\x06rC\x87?o\"bK\x17\xdd\xc0\xe7\x9c\xbb\xab\xa1\\\xd8\x1c\xbb\xe8\xec\x920\x8d}\x92\xe8\x81!\x9e\x1c(\x17\x0c([\xf6\x12Fp\x8e\xa9\xe9m\xc7\xe9N\xa3\x90<.\x01f\xc9\x0c,%\xd8\\t:f\xe8\x88\x87B\xa9y$\xc6\x01\x98\x01$\x1e:\x89\xabb|\xe6\x91\x88\x07\x0d:lifWhZ\xbbF\x03fN.\xae\xc6\xbd3\x87\"\x9e\x98kO\xcc\xb4\x1e\xac\x06[B\x86+\xb8\x91K[\xac \x01>\x1a\x92\x91\xc9\xcfi\x11+\xba\x0eCb\xdb\xda\xe9[naG\xc2n\xdd\xce\xd8HN\xe1@\xec~\xb8\xf2\xd3\x05\\\x92\xeb\x04\xfenAG\xdcg\xd3\x176qx\x9a[\x17P\xd9d\xddX0\x84S\x17>\xb65?3J\"\xd3R\xc1\x0d\xa5\xb8\x96\xa5\xf2\x1a\xadn\x1b\xeb\x8f@\xad\x8d3\xf7\xe1\xbaw\x8f\xff\xca\x1d\x8b\xabg\xa5\xf5/\xff\x92\x07\n\xd1\x9f\xd3f9)\x97\xf2\x80\xc5\xcdEg\xc3\x18\xcd\x9b\xd3\xb1\xafZ\x80\x1b-\xb2\x89\xc6\xdc\xfa\x0e S\x1e+\xdb\x08me|=\x1a[#k\x08\xd6\xa8g\xc0`k\x88\xc5\x83j\xb8\xa7\x1b\xa3\xc6\xc0\xfa\x03\xc5\xc9\xcaE\xc0\xfd\xf1hxv\x7f\xde$\x9aK\x0d\x91qzV\xed\xb7^\xa6\x0c\xef\x06(=\x9c\xb6 (\xa3\x01-\x1en\x02\x14\x06\x0e\xdb\xea\xb2\xcd\x9c\x8e{\xe8\xe8Ma\xc5\xfe\xee\x9f\xa1\x8dD\x92]0.\xc0\x1e\xd0#Z~\xd1w\x1c \x9a\xf6\xa8\xf7i4p\xee\x1e\xa0\x05\xbe\xea\xf7\xce\xdd\xdc\x80\x0d\x9c\xba\x9bn_\xaf\x07\x18R\x12Y\xb1\xe4\xc7\xa2\x8b\x8b\x98\x95^\\h\x83~z\xd3iL\x92\x84\xd5a\xbf\xb5\xd5b\xc2{\x89\x89\xbe\xa38\xf5'\x01\xe1u\xf0\xb7\xb6Z\xe2Oy%\xfaK[%\x9b\xfa\x11\xabB\x7f\xe9\xaa\\`\xf1\x85\xb6\xc8KX\xfb\xf4\x87\xb6\xc2\xd4g\xe5S__\x1c\xf1b}\xcf\xfe\x9c\x15\xfbsmq\x10M.\x7f\xce\xa2\x94\x8f!\xffS[9\x9a^\xb3j\xd1\xb4\x12P\x05+\xb0\xa5\xd3/\xdcE\x96\xa6Q\xc8*\xe0O]\xa5\x89\x17\xae=\xb6\xb8\xec\xa7\xbe\xd2*\xf5yS\xfc\xb7\xb6\x9a\xcfgE\x7fh+D|i\xe9\x0f}\x85\x80\x97kc\xc6N\xa2`\x1eG\xd9J\xd4\xc1?t\x15\xa7^\xca\x90\x91\xfe0U\x08\xfc$\xcd+\xd1?\xb4\x15\xa7\xac\xcaT[H\xd8p\xa7D;\xdc)I=?Hx\x15\xfc\xad\xad6c\x90\x9d\xce\xb4P\x9d\xfa^\x101\x9cb?\xf5\x95\xd6\xbc\xc6Z[\xcc\xc7\xa9\x1f&\x87\x82v\xfed\x89\x85d\xa9/\xbc S^~A\xb4 \x9a\xf9$\x98\xa2\xe9`l[\xe2\x0f}\xc5\xb9\x8cf\xc5\x9f\x86\xcaYLD\xc5,\xd6\"\xd3,\x8a\xd0+\x93V\xc2\x9f\xfaJ\xf1\x92W\x89\xb5s\\\xf4\xb1x\xd1\xd7\x16\x0eX\xe1@[\xb8\xc3\nw\xb4\x85\xbb\xacpW[\xb8\xc7\n\xf7\xb4\x85\xfb\xacp_[\x88V\x1f\xb4\x98x\xda\xf5\xa0\xef9P\xd8Om\xa5b\x97-\x8c{l\xc1[\xd1\xb7\x90.\x19\xca\xd1\x1f\xba\n\x8c\xc4j \xac?\x8b1\\&-\xc7\x9f\xdaJK\xb6%\xfc\xa5v?\xf8\xe1*c8\x87\xbf\xf4U\x12^A\xbb+//\x18 //\xb4p\xbc$\xd7s\xc2P\x95\xfd\xd4U\n\xbc\x0bN!\xf0\x97\xb6\n\x99\x93\x90\xf5\xc4~j+1h\x05Zp\x05~x\xc9\x8b\xc3K]\x85\xa5\xe7\xb3\x81\xd2\x1f\xfa\n+^\xae]\xe8\xa5\x17_\xf2\xf2X\xdf\x01 3V\x81\x84\x99\xa9\x82\x9frR\"\xfe\xd0W\xe4t[\xe7w\xc8+p\xec\xc5_\xba*\xa1\xc7Ha\xe8iIa\x181\xbfaV\x87\xff\xa1\xab\xc8\x04F\xac\xc6\xc5Z]%\xb6\xbc\xfa\xe3*Z\xa5\xc5F\x12\x7f\x18*\n\xba\x17\x19i^\x94\xa5\x02\xa7\xd9O]%\xd6\x97\xb6\x93\x95\x17{l\x05\xf0\x97\xb6\x8a?I\x05]\xe5\xbf\xb5\xd5D\x15Sq4\xcf9F\xf1\x87\xae\xe2\xcfX\xe3g]Q\xcc&\x12kg\x123(\xc4Z\x08\xc4\xd9\x05\xe3\x99\xe8\x0f]\x056.\xed\x80\x12o\xc9\xfa\xa5?\xb4\x15\n\xd41#NB&\xf9r\xf2\xdf\xfaj\x81\xc0/\xf6S[i\xe9\x05\x0c\xc5X\nN]\x15L\xa3\xc4\xea\xe0Om\xa5\x95\xc7\x07\xb4\xf2\xf4\xa3I\xe3(d$\x95\xfd\xd4W\xba\xe6\x0c<\xfe\xd2V\xc9\x18\xeb\x9ddZ\xe6;\xc9\x96K/\xbe\xe6U\xf0\xb7\xbe\x1a_\x07\xfd~IY\x1c\x95\xd8\xb6R\xe6\xdb\xa2\xa9\x92\xf3\xce\xa9\x89yN\x19\xd9M\xb5$7%\x1f\xd3\\\xa4\x11\x7fh+R\xde\x82\xd5\xa2\xbf\xb4U\x16\xac\\\x9br=\xcd\x8f\xec\xd4tf\xa7>?\x0e\xe9\x0f}\x85T\xc0\x03#L\xeb\xaa0\xaa\x99jIf\x1a{\x93K^\xeeM\xb44\x9e\x11x-u\xcf\x18\x82fZ\xec\\{\xac\xe3\xb5\xa7\xedy\xedO \x13\xa7\xf0\x97\xae\xca\x15\x17r\xae\xf4R\xce\xc4\x8f\x85T\xc9~j+\x05\xfe\xea\xad\xc7\xd7A\xfc\xa1\xab8%3\xc1\xaf\xcf\xb4$\x82\x04\x81\xbf\xe2\x02$\xff\xad\xab\xc6v\x92\x9e5Yzs\xce\xdd,1\x93C\xb5J\xe0\x87\xac\x06\xfda\xaa\xe0\xc5_\xc5\xde\xd4G3f^\xb5x\xa5\xfbh\xe9%\xe2\x1cO\xb4k\xbc\x12\x10Z\x19\xa0\xb3\xf2\xd2\x94\xc4\xa1\xa8C\x7fk\xabE\xc1\xf5\x9c\x13@\xfe\xdbT-\x9f\xa9\xf8CW\x91\xce\xc9\x0bJ\xb3-\xbf\xd2~$\x88kl\"\xadi\xc4\x89L\x1a\xe9\x89\xfd\x9a\xd3\xc3\xb5v\x1d)Q\xc8\xa9\x83\xb6BNtSFuK5\x0c:\"v {\x07:\xa2:\xbbvn3\xdd7\xb9\x07\xfb\xc2\x9e\xecs\xc7\xd1\xdf\xdb\xd8\x01Yx\xe4\xd0\xfe\xe4`\x8cw\xa0\x03\xd6\xd8\x83s\x8f<\xf5\xf6\x97[\x8f\xebcYT\xdckx\xa8\xe7}5V\xb0\xf0\x8b1\xf9\x18\xd7\xda\xa2\x08[\x92\xcfQ\xe9\x03\xb7\x08\xd6\xab\xf5E/3Z\xe3\xc9\x13/\x8c\xc2\xebe\x94%O\x9fj\xb4\xb7\x81Q\xe5\xeb1s\xb9\xb5m\xe1/\xddN\x00\xd4eQ^ym\xe7\xf7\xba\x86zt\xbaX/\x9f\xb7\xa1\"\xbb\xe0\xc5\xaa\xfc\xae\xd7PQ0\xf2\xeb:F\x1e\xf2\xc08X\x91\xdf'\x9b*\xf2 ck\x11\xcf\xd8T\xd1\x0b\xaf\x870\xb5c\xd9\xf6\xef5^`\x9bA\xf9f\xd6\xa4\x82\x17\x8f\xb8\\*\xe2\x99\x14\xe6\xce.DM\xf7\x8b\xca\x15\xccVal\xe0\xc8\xf6\x1d\x0b\xdb\x12n\xdf\xf0\xa3\x05\x1d\x88\xa0\x03\xd6\x8f\x10\xcd\x8a\x94s\xac f\x05\x0b/\x01?\\S\xea\x93{\xcf@\x18\xa5\x98\xc0\x82\x8a\xdd\xfe\x94\x88\xa9vM\xe9C\xc5C\x11\x14\x13I\x8dCC\xb2W\xf1`D\x89\xf2\xa5yV\x1b\xb0B<\xb4\x0b4\xad\xacD\x17\xd0=e\xc8\xbc\xe4\xf3\xa4\xd3\xf71\x16\x99\x02\"\x0c \x8d\xef\x12\xf6.\xc9V\xab\xc0gi>$\xa8\xb9@>\xae\xc8$%S\xf0B\x06\x9d\xaeu\x9b\xebX\xf1\xe4w\xe0<\xd0\xc2\x04\x9e@\x96\x1b\x06L:\x9d\xb6\xa0\x99aj\xc9\x0c\x93\xe2r\xcc\xa2#\x1e\xd3\xb1O\xe8\xaf3\xcb\x05\xaf\x05\xe4\xe8\x02\xcddCJ\xf4T.\x8c.>c\xb2:sx\xf5\xb91\xdc\xe2\xea\xb7\"\x11\x1eb\xf9\xde\xfa\x82;qC$O7@l\xef\xcb#\xb6\xd7\x1a\xb1!\xf1\xc3y@\xe0\x84x\x93\x94s&\x9f\x87\xe5\x9f\xb3\xf0\xa6\xack\x02C\x7fWB\xbce\xd3\xc5/\x99\x19\xb7^c\xe6P\x14zK\x16)K?+\xf5\xf1\x1a\x8d\x9eM\x0f\xc3\xc1\xae\x14\n\x16\xe3\x0d\x97\xde\xe0h\x8a\xad\xdd\x8c}\xe2\x11vp\x95\xc6Z\xb5pc\x1b\xa2W\xab\xcf\x97Gv\xb1\x92\xf4s\xac\x91a\x8d\x7f\x1c\xba\x1b\xb8(\xbc\x92\xbb%\x91\xabu\xb0R\x1fD\x9bk;\x1d\x933Ge0\xe4\x05\x88\x8b\x05\xf0\x0d\xc0\x0e\xab\x94\x05I\xca\xebhJ\x1a9\x8a\xcf\x81\xa1\x89d0\xbe\xf2w%\x18\xff0\xceM\xcc\xb5\x11\xd0\xf2\xa9\xd6L\x93\xdaq`%+\xb3\xad\xd1\x08\x92:T\xbaC\x8e\x8c\xf5\xd98g\x89\xeb\xf2C\xc8\xea\xf7:\xf0 e\xdd\x85\x97H\xd1\x95\xecI+\xd2\x0f\xf5\x0cZ\x17\x19\xb4v\xac\x19|.{\x06\xff\x00\xd2\x15\x85\x1b\x1c\xd1\x1a\xe9@\x8aTW\x11\xd0jL\x0d?o\xeb\x16Q\xd1\xc4\xce`\x810\x1f\x83\x07O \xcd\x19tO\xf6\x866=tR+\xba\xf2\xe9\xd8\x93\x89j\xed\x04@\x12y\xfer\xfa\xe6u\x91?H\x9bYB~6\xdcih\xb2*\x1f~-\xb6Z\x14\xe2\x89\x99o\xcf\xba\xf3\xf2\x16\xe8B)\xda\xef\x8e2R\xe8i\x16\xad\xbb\xb4\xd2\xa4Y\x14\x13\xba\xa0T\x9b\xa9_~\x8c'C\x98\x0f<\xb2\xb7\xfa.\xe4\xab'\xe2\xf4\x96\xd6&\x87U\x17\x8eU\xb1\x14\x8f\x8f\x05\x99\\\xe6`L\\\xb8\xc8R\x88\xc9\x84\xf8k2\x85?&\xe0\xa5\xe0\x87S\xf2\x11\xfe\x98t-\x17\xce1\x99\x0bA\xe7m\x05l\xe6\xd5\xfd]\xb6`\xef1d\xa5\xe5\xc8\x9a\x97\x03\xa4\x1d\x94\x8e\xb3\x86%\x01(\xfb\xd5&\xe5\xd1R\x02\xed\xb4\xa2\x8e\xd0\x9a\xc6\xb6\xd9\x9f\x86\xadxw\xfb-Y\xb4\xb0&\x15\xcfg.\xe9\x7f=\xac\xc6\x8f\xac\xc7\x1f7\xe44Z p9\xb30\x9e\xb4\xc4\xd9Y\x9bf\x817\x1d`\xac\x84;\xe1C\x82\x1c\xd4\xf5\xdb\x01\x1a\xb7D\xbb\x0dswL \xf9\xe8M\xd2\xdf\x11\xeb\x93\xd6X?A\xacO6\xc5\xfa\xc9g`\xfd\xe4\xce\xb1^\xa0p\x86q\xed\x18\xff\xd4\xc4\xb5\xe4;%\xa0;\xa5\x15J\xd3\xda+\xdc)A\xcb\x9d\xb2\xb5\xda\x0cN\x97\x84\xcbdA=9\xfe!|\xe6M\xf3+\x0cZ\xa0\xf0l\x0c\x06,\xc6\x80\x05\xdcs\xe5\x87\x10/\xff\xd0\xd1E\xfb\x95\xec\xf7\x92:\xa5\xef[l\xd35\xf7s[\xd9\x89\x0bAu\xb7\x07\xedv;\x85\xdb4\x07\xdb\xf4\x1f\xb4\x8f+oo$\xafM\xa8\x06B\xd2\xe1\x8f\xd0Z\xe5\x891x\xf2\x02\xf8\xf4 \xfap\x1f\x0b\xf0\x07\x81!f\x00c^2\x84\xfeR\x03@\xe8\xfb^\x18\x02\x13,\xfc\xa4\xbb$I\xe2\xcd\x89\x14\xf8(I\xbd\xc9%\xbaW\xb5j|j\xc8\xff \xcaC\x9b\x11\xa5\xc8\x85\xcc\x85\x04)\xbc\xd6\xe5\x93>6=\x883\xa6\x89D\xa23\xc1\xa4V.\xb0X\xa5\x9e\xc3S.`b&dE\x8f\xbc \xf0\xc3y\x11j\x0dp\xe7xi\x14'0\xf5c2I\x83k\x91\xe4\x85n\x94(\xa6D\xe3\xe2\x1a\xd2\x05\x81\x1fWq\xb4\xda\xa6D'\xf9\x11V\xde\xe4\xd2\x9b\x93.\xbcO\x08\xfc\x987\xd8E\x865\xff\xd3v~\xa4\xfbl\xe2\x05\x01mb\xd9\x85\x13\xe2Ma\x19\xc5\x84r\xae\x8b4]\x0d\xef\xdf\x9f]t\x97\xe4~\x96\x90m\xfcz\xbb\xe8\xc7\xb8I$<\xc48\xd0\xe3\xe8\x0c\x0e\xd0\xd93\xf7W\x15\xef\x18\x91x\xb7 \x85\xacS\"\x9a~\x82\x86\x97\x94\xf1N &?g~\x8cZEY\x9eb|\xb7\x9f&\\\xd4\xf2\x13\xf8\x91vD\xe9(\x0c\xbf\\\x1f\xb9\xbf\xae\xe8\x88Nn\x08\xa9]\xc2\x91&Op\x90\xaf\xe6\xbb\x17~8\xb5\x19\x19\xda\xeak\xc0\x9b\x8b]~r\"F\xaa~\xd7\xabF\x981`\xfc\xba6\xa4\xa3\xe9@v!3a\xbd\xb8k1_\xe1\xf0\xb6\xe7\xb6\xe7p\xe2p\xd0\xee\xa8(\x1d\xa9K\xfay\xdbS\x95\xbeM\x05[\xcf\xd7\xa9\xba(\xaa\x17\x93\x1eb\xd7\xb6\x96\xf2%W>\x8b\x92\x9b{\xef\xe9\xe13\xf1\x12\x92;e\x0fk\xaa\xf0\x9b\xf7\xba*\x85\xbb\xb8\xbe\x16\x14\xd06\xa5 `\x0d S\x84\xe6f\x0c\x9e\xb7\xac\x19\xce.\x99[\xd1\xbas\x8b\xb6I\x97\xacI|m_7x@\x97=\xdeS\xb9\x89\xbaD\x0bk5Bc\xa3\xa8\xb0.9r\x86\xcc\x913\xe4\x8e\x9c\x93\xa6\xdb\x95\x8d\x1c;\xd5\xe7\xa6\xd1\x0f|+n\x953\x82\xce\xc1\x17)O[9\x98\xc7\x8a\x83y\x1b%\xc2c\xd8\xb2}LhPv\xec\xae\xfd\x12\x8a\xbb\x10\x9fyuK\x0b\xd97\x83f\x03gs\xdd\x98Zr\xbd\x18Z\xa8\xad\xb39*\xaf1\xf1\xc5\xb5\x9d\x8d\xfbg\xad&\x02mt;&\x8c\x16\xe1\xa5\x1b\xbf\xaf\xf6\x7f\xd3\x8a\xcc\xcd\xeb\xbd^\xc5=\x8b\xf1|R\xf5\x85p\x00\xdc.\n9?I\xbd~B\xe6\xc7\x1fW\x85k\xba\x05-\xa3\x13\xf1\x9e\xa4\xfc7\x9c\xd3\x14I\xa1\x18\x95\x18[\xff\xf2/R*B\x0b7p\x835\x19\x91\x07\xc8^W\xe1\xc8\"q\xd1\x81\x8b\x11T2W\x1a\x80\xbb4\xc7\x14\x93\x12\xcb\xe1\\rjW\\i1\xb7\xe8*\xe4\xc5\xda\xcc\xb5\xfa\xebJ\\\x82\xfa\xa8O2\x00\x9e{\xa9\x94\xb1g\xea\xa5\xc4\x90\xb4\xa7\xf2%[\xdb\xe2\xdb\x98\xcc\xc9\xc7\x95\xc6\xeb\xd9\x84F\xed\xe0y^\x8f\xac\xfaT\xd1\xe2\xc4n8\xaa\x19\xd2\xd6\x1d\xc3\x8d\xc7\x9e\x98\xbd\x17\"gS{\x86\xd6\x1f\xc5\xac\x0e\xae@]\x05\x0e\xe6\x16#\xaa\x1bP[\x1a\xd3\x14\x89\xae\xfc\x17\xffH\x8a\x88 #v\xc5&g/\x08\x14I\x05F\x94\x95\x0e\xba\xf2\x8b\xc0\x055\xe8\xe7\xad\xccb\xebb\x01\xe5W\xfaw\xd4\xbe\xd5\xdf\xeb\xeewy0\x84[\xb5\xb6.\xc2\xec\xef=tLa\xc5\xfdV\xf6\xcf>\x7fu\xf8\xfa{C\xbc\x87$\xf5R\x7f\xd2\xae\xee\xaa\x08\xb4\xde\xa26\x8f\xf2\xba\xc1\x07\x0b?\x98\x1em\xfa\xd5\x9c\xa4\xcf\x199\xa0;P\xf9\xe6\xfc\xd5\xf1\xc9W\xc7\xcf\xcd\x9f\xbe\x0c\xfd\xd4\xf7\x82\xd3\x14S=l\xf4\xe9\x914\xdcM>\x8dI\x88\xfe\xbd\xe2\x8b7\xaf\x8f\x8e\x8d \xe4[\xe8[?\x08^\xb1p\xaa-@\x92\x7f\xf6\xdc\x9f\xde\xe2+\xda\xd9 \xbb)\xd4\x80\xd4\x84G\x8b(\xa3\xe0\xe0m\xbc_MK\x10m;I\xf5\xbb6\xe3}\xeeOo\xf3\x19v\x17.[\xc3\xe7\xfd\xeb\xd3\xc3\x17\xc7\xe7\xb7\\\x13\xdd\xd7\x1b\x03Y\xd7\xc8\x06S\xcf\xb0\xaa\x94\xcf\xc1z\xf3\xe1\xf8\xe4\xe4\xe5\xf3\xe3\xf3g\x87\xa7\xc7\x1a\xe6\xa7\xda\xce\xc4Htp#\xc6\xfe\x9aLq7\xbd\x88\xa3e\xcd\x8el\xd3\xd7\xcc\xd8\xd7\xd4OV\x81\x87I\xceZ\xb2\xe4\x80\x84W\xfa\x0eT\xbd\xaex\x0c\xd7F\x82\xa6\xb6\xee\x8d\xb2\x9c\x9a\xd8\x9e\xf2\x93\xdf{\x84\xec\x9e;,\x85\x86\x0b;\x1d\x87k\xb4\xc7\xe1\xd9Fw\\\x1aR\xdaz\xdci\xb7\xf25f\x1b\xfc\xfb\x8d\xab+\xd3\x060\x85\x9a\xa1\xddzT\x86\x01}\xc6X*g\xc7\x06\xc3Q\xbe\xc5\x00G\xea\xbb\x11L\xed\xca[ly\xa8\xad\xbd\x11BJ\xa7\xf1\x06\xc3^Il\xaa\x00a\xfenS\xf8\xe5\xccC\xeb\x01l\xb5\xaf\n\xed\xf6\x10\x94\xf7\x91\x1f6\xb7*\x1e\xc1\xe85\x1b\xf5\x8b\x07\xc7\xa3\xda\x02\x86\xadm\x01A\xe8\xbd(\xbb\x88W\x9d\xed\xba\xa5Odo\xf9.\xfc \xadhy6\x9b\xef\xa3\x0c<\xbc\x10I\xc9r\x95\xfa\xe1\x1c\xd2\x88gi\x07\x0fb\x92\x90xM\xa6\x88)t\xa4.\xfc\xf8\xc7\xe4G\x17\xd2\x85\x97\xf2\x03;\xfc\xe1O)\\\x10\x88B\xbc\xa9\xb1\xf8\x8aZpI\xae\xbb\xf0\x9c5\xe5cn:/,,\xa6E\x8b\xf8\x86x\xd3\xc7\xb4\xce\x95\x1f\x04\x90\xa4\xf4\xff\x17\x04\xbc\xc9\x84$,94o\\\xb6\x17\xff\x93>t\xbe\xe9\x11z/\x04\x9a!\xee\xb5\xeeA\xf5\xd7&\xab\x03\x12\xcf=\xa9.4\x1c\xc0d\x1c\x9eqE}\xfbq@!^F\xb6\xee8D\xbd\x87\xe7\x82\xd5z}\xe9RR\xc8^GY,\x19\x0b\xe3\x0dY\xba\xf0B\x88\xc2 \xe9\xc2\xbb\x85\x9fP\xc8\xcf\x02\x7f\x92\xc2\xd2\xbb\xa6k3\xcd\x08m\xc9c\x87Z\xd7ba\x99\xd7\x91?\xb5Q\x8f\x8ct\x0bo\xad\xe3\x86\x80\x93\xf2S\x7f\x01,?\xbc\x13}\x1ch\xf5in\xd6\\\xe3\x86Q\x99Mh\x9a\x97\xa5\xd1\x85\x1fN\xcb&\xf7\x1b\xdcA\xeb\xd3\xfd\x80d$\x98\xa8\x88E(b%cbF\xacs\xcd'\xf7\xeeQd*\xb3p,tm \x8f0?\xc3\xcc\x9b\x10\x13BEk\x12\xc7\xfe\x94\xa3\xd4,\x8e\x96\x1c\xa9\xe8\xd7\x90\xac\xc8\xc4\x9f\xf9\x13\xb40\xef\xc2q\x98d\x0c\xc3RVkI\xd2E4\x85\x10\x93\xd1N#\xbc\x01\xa6-\x06\xde\x8a\x85\xf2\xc4\x91\xf0jhjH\x1c\x97\xdd\\\x94\xb7\x82\x08\xbb\xfb\xe9\x93\x96a\xbc\xcd\xcc\xbe\xc8V!\xedn\xe3\x90q3\xa7\xf00\x11\xa5\xc8`\x1cZ%\x0d\x7f\xaaL7K(\xd9/&\xc8\x160\x8a\x8bAQ2\xceg\x02/\x19\xe9v\xe1\xa7,I\xf9\xb71\x99g\x81\x17\x17\xb6\xf4.=w\x08\xda\x86n\xde\xff\xc6\xbd\xe9 \xea:\xcf\xd7T\xa8\xe1\x8c;\xde\xc7\xfb\xa4\xf3\xf3\x98\x0e\xf60K\xa3g~8}\xeb\xf9\xb1&\x863\xc8\xac\x83G\x8f\x96P\xddf\x19\xcb\x14\xdee\xdc?.)\xff\xedh\xa3\xd0\x8b\x07\xd7Xm\x8c\x19Vxx\x8d\xd5x*\xad\xb9ch8\xf6Z\x98\x8e\xadp\xda\x95\xfe\x9a/\x02\x03{\xc5\x12\x01\xcd\xaa_;0\x1b{gt\xd2\x93\x86\x96jbQ\xcb\x0f\x9d\xd3BG\x00\x9bF\nu\x86\xd3h\xbd\x82\x01\xc4W\xe8\xe6\xd6g\xa4\xa2+(y\xbb\x13\x0c-\xf5\x9b\x16E~\xd6<\xa4w2\xf6Zr\x8f\x80\xfb\x1b\x03\x9b\x9b\x99\x80k\x95\x00\xf2\xd7\xea\x0e|\x1f\xe6V\x04\x94D\xc3*\n\xfc\xc95\xfc1A\x94\xbe$\xf8\xf3jAB\xb6\x03\xe7\x14\xbd\x8b\xadI?Ab|\xcdV\xbff8\x07\x10\x8f=\xc6\x13\xd0\x1f\x14\x19`\xa8\x1b!\x8b*\xcc\xea\xae\xf3\xba\xed\xa0\xcfCT\xf3\xaf'\xcd\xf0d\x11\xadY*\x16\x8f\xf6\xe3\xe6\x1f\xd7~[\xc3+T\x8f\xf8V\x84~a<\xef\xcbbIds\x8b\xb2\x9a\xfc\x01\x9a\xf7\xc4\x05kI\xe29\x11\x89\x97^G\xcf\xb3U@\x0fd\xf25\xb9Nlg\x08G^H\x8f]\xac\x06a\x14n\xb3f\x12$\xe0\xc4\x01\x8d\xc8\xc2r\xa7\x95.\xf5\x90\xe1k\xec\xeb]\xcc-ZXo\xe9U\xc4\xe9w\xc2\x8e{\xca\xe9'\xde\x92P\x14\x1c\xe2\xd1\xdb\xead}LA\xb4\xc2\xa8\xb3\xf4L`Vr\xa2\xea\xc4\xcb\x12nNv\x15\xa9j[\xdb\xa1G\x9c\"L\xdb\x8e\xe088\xdfMw@i\x9c\xf4p\\\xd0\xb7\x97\xe4:\x11,0gL\x0d.\xaa\xc2\x86\xb0\x15ZL\x9bL\x11e\xf6\xd2x\xee\xa1OI\xd7[\xad\x82k\xccE\xe2\xe6\xde \x89\xc1\xd1\x91>(\xd4\x1a\xbe2\xdf\x8f\n\x9b\xb8\xc2\x11%n\xae\\\x18{\x84\xe6\xd3\x1bC\x1ek\xe2G\x83t\xebf\xfbl \xf0\x87>\xd9I\xbb\xfd\xb8\xfel\xc0\x1b\x01n\x04\xea-\x87z\xdd(*\x10f=\xa7\xbb%\x16`WzR[\xd1\xe77\x06\xfd5A#h@X\xb4\x9e\x9f\xfb ~\x84F~\x9a$\xeb\xa0'\xa9U\xa4]6\x0f\xb0\xa4\xaa\xbf\xf5\x18\xf5\x06/\xad\xc6xn\x1c#\x8fY\xce/\x90Z+\xb7p|L\x1f\x1fwI\xf8sF2r\"5\xc51lc\xe95\x9fpK8 c\x9c-\x15`\xb7\x87\xd5\x859\xd90HV\xa2\xf6\x85|\xab.\xf3\xf6p\xae!m\x05d\xeb\xc8%Q\xaeT\xe3\x1a{P(\xd0\xa4*,\x88|p\x94\xf9o\xecY<%/\xc2T\xdb\xaekP\xf5Cg\x04\x83\xa6\xf6A\xd1Y6\x8b\x05\xc0%\"2\x0e\xa1\x03\xfd\x16|*&\x84\x181\xca\xe4\xdf6\x10\xc2\x0d\xa2\xaf\xc8\xb3\xb7\xe2\xda\xedj\x96c\x91\xd07&3\x0cj\xe6\x96\xf6\x850R\x0f\x0b\x93\xf9T\xe4\x172ODh\xef\xf0\x13\x85U\x80\x03\xedk\xdbiT\xe8E\xb6\x865\xf3\xd0\xb0\xaelO\x86\xcc\xf4\x1f5]\x0caI%_\x8e\xfe\xb9\xbf:\xe5]h\xd7\x16=\\\xe4\xeb)*\x050~\x9fR\xc1\xc4\x97.\xee,G\x81\x88\xa7\xdf\xad\x0d\x12o\x8c\xca\xf2\x92\xb5KH\xae\xe0\xc2\x95_\x96\x82\x88`\x8ef\xb9P\x87\xe2<\xd5\xa0'\x12\xdf\xdb+\xd9\x02\x9c8\x8e\x0b+\x9b\xb80\x17?R\xf1c\x89'\xacz-\x82\xbe\x08\xdd\xa9rS\xa2V\xb3\x1d\xd4U\xc8\x83c\x17\xed.XR\nx\xbb\xdb\xedR\x86\xb9\xaa\xdab\xcb\xe3/W\xcc\x1c\x05<\xf8\x915\xf0#\xe7$\x91\x99N\x1cy\xfe\xd3E\xa64'\x13\x8fJ\xb4\xfc\x83A\x14\x92\xffJ\xcb~ \xca\xad\x8d`p5\x80e\xd1\n5\xa9\xd3Y\x80BM\xc1\x0c#\x12j\nD\x04BM\x91p\xd8\xd3\x14\x89(\x83\xba\"\x1eWPS\x84\x91\x04u\xefE\xc8@\x8d\xd62\x8fa\xa6\xf9N\x0er\xa5\xf9\x94\x85\x052N\xcc\xf0\x15\x8f\xc8a*a\xc1\x174\xa5\xdcU\\7\x05\xe6N\xab\x98\xc3jy\xbe\xb0j:\x19\xbb\x10\x96L'C9\x9f\xeag\x10\x0e\xee>\xc9n\x00\x8a[\x13\x17\xac\xf3s\x92\xbc\x8a\xa6Y@,WA?4\xaa\x1f\xca\xd2\xcc\x0d\x1eI\xfc\xf0\xa9\xa3\x1e|\x8aUt\xce\x85\x98dh`\xef\xdeE\xab\x0b/\x1eB$\xfa\xa9\xd42Y\xad\xde(\x84\xd2\xcd\x89\xfc\x8e\x86*\xda\x94\x90\xfa\xa8\xf9\x89\xbb\x05\x14\xe0\x00b\xd0\x8dMX\xd9V\x1c\xb6\xe0\x1f\xbe(\xd5\x03be\x87v\x7f\xf7\xa1\x9a\x03\xd4\x17E{=]^QVT\xc9\x1c\x9a\xe5E\x95l\xa4^^\xb4\xaf\x16%\xdcfU=\xa8&\xcc\x0fWy;\xa3+\x82-\xed\xef1\x9e\x88\xae\xdb\xae\xa3\xb6\x1a\xf0\xf3l\xdf\xd1\xa5*]\x19\xcfg\xd4'\xa6\xe5uN\xeb\xd7\xd9D\xcdoJ\xd0^\xd4r\x07\xd2\xb9a\xba\xff\xb2{.\xf8\x02\xd7\x1d.\xe9\xea\x9c\x7fho\x88\xb8=\x172\xf5\x03\x9br\x9f\xc8v\x9d\x9f#\x13\xd6s!.*\x11\xc7a^E\xb9 \x1d\xea\\B\xc5\xa5|7\n\xdf\xc7\xc1\xd1\xc2\x0b\xe7\xa4\x95+V!\xe6\xa5^<'i\x9dCN\xd4MH\xca\xc4\x00\xb3\x80\x97\xc5\x81JE\xc5\xa3\xf1\x8b\xbeq!\xea\x06\x917=]\x91I\xab\x01GL\x0e\xebR\xa6\xf7\x10\xeb\nA\xeb}\x1c\xa0\x87\xb9\xae\xc64\xba\ni7j\xba\xf3|\x0c\x08\xb7S\xcc\x8e\xd0j\x18z\xb8\xa1\xe7\x9ax\xb3\x88\x89\xc1.\xa6\x98\xb2Mp\xc0\x14\xae\xd87\x99\xd2Y\xe0\xcdrw\x15\x935 \x85t`\x1b\x06.f\xf6>\x0eZ\x0d\\\xea;b\x82W7\x8b\x83\x0d:\xc4\xb1z\xf1\xa4~\xff\x88G\xc0\x89\xa2u\xd0]yqB\xd8\xd7\x8e)\x834\x19[Y\x1cPq\xdb_z1\n\x91\xd6Y\x1ew\xd2\xac\x9c\xa5\\\xd8\x95\x1fN\xa3\xabn\x10\xf1k~\xdcW\x93\x08#\x1f\xdc\xbfoA\xa7Rc\x11%\xa9\xe6\xf5\xcaK\x17\xe6\xeeXmJ\x98\xf8w\x0b?I\xa3\xf8\xba\xfa\x06/v\x98\xcc^-\x93un\\\xac\xb4,\x97\xc5\x1c<\xa0\x83e@KH\xec{\x81\xffK\x0e8]\x86\xde\x9b*\x1am\xb4>b\xd3\xccIz\x14\x853\x7f\x9e\xd8\x0eE\x8c\x84\xa2\xf4\xd8\xa0p\xc1I\x11I\xc7\xc4n\x86r\x899\xef^\xe7\x12Pj\x88v\xc5]\xb2\xf0B\xa7\x0d\xa5\x81<\xb5 \x99\xbe\x0c\xa7\xe4\xe3\xd0\x90\xc2\x1e8\x03$\xe1\xae1\xcb\xb1\x89FE\xe1\x0b?HI\xfc\xc5H+\x03\x7f\xe0]GYZ\xa6k\xacc\x9d\xfd [t\xae<\xd1\x0f\x02\xc9q\x8a\xb4\x90\xa1F\x14'\x14\xd8\xa6\xf8\x92\n@\xab\xfap\xdag\xe9\xa5\xd6\xf9\x88b\xae'\x9dbL;B\xdfF\xa5\xb7\xe3\xea\xa8\xf1\xbe\xcd2\x1a\x98kl\xc29g\xd5\xbc\"L\xd9\xd4\x8cYf\xa0\xb5\xc6\x992\x88T^\x10\xf4\xf3D\x9du\x8b \xd6a\\\xcau\x86f\xa5*\x11Z\xc5\xea\x8e7\x7f\xc4.q\x9a\x08\x02\xde\xa8\xd1\x1d\x1cr\xa2P\xb7\xe9\x0b\x15\xb0\x86\xe0\x9bU\x981k\x7fc\x1a\x03Hg0v1F\xc7`|e\x0bl\x10OkZ\x03z\x9ch(j\xbc\xb7o\x81D\xe2\x06\xec\x8ep\xe86g\x02\xe7\xd7\xa53\x816\x94\xf3\x1c\xe9\xb8\xd0\xf8vK\x10=C>\xe4\xf6@`Z\xce;\x9dy\xc3\x1eb\x80\xd1z\x07\xca\x0f\xbb\xfb.\x11\x13s\xe5\xb8h\x18!n\xae\x89\xf7!\xb6\xf5\xcc\x98pU<\x11\xab\xf8\x8d!i\x9fx\xd0\xc9\x8f\xae\x93\x1f\xce\xb9\x95b\x97\xffIwHVK\x1e\xbc\x9a\x9bqk\xe6\xf9\x01\x99\x1a\xda\xc4\xf3\xde\xebN\xa2\x00\x15\xf3V\x8c\xd9=!S\xdf\xff\xff<\xcf\xab\xb3\xac\x0b\xd0\x11\x80\xe1\xa7y\x9c+\x83\x0f\xa2x\x16\xb5\xf72<`\\=I\x9bb\x17f\xfa\x15TIW\xd3-+}\xa6\xccFh\"\x8eO\x9e\x9aYh\xadE:?\xdd\xfeP\x1f\xdc/5\xb6\x87\xe2\xe1\x1b'\xa50\xad'v.\xe7\xcek\xac\xa4(\x03\xb6j\x98\x03\xcb]\xd94\x054\x07e.S<\x9f\xdd6\xff\xb0\xf6\xb3E\xba\x0c^Dq\xfeQ\xd5uK<7.\x18\x87\x88\xf9\x95\xf2(f\\`\xf4\xf0\n\x86\xa2\xad\xf9;\xd6g\xd3\xdc\xfci1\xbe\xfa\xe9L\xfd\xc4\xbb\x08\xc8t\x08Y}\xc5(d<\xeb\x90\x116I\xd0\xad\xff\x8e\xaf~PO\xb0\xeb\x808uLL63{[\x08b+\xc9\xb0\xcdH\xc2\xd2\xac\xd6\x01RF\x10\xd1\xf4v\x16\x07\xdb\xfcS\xe3\x87)\xaa\x8dY\x9a\xad\x1az\xaa\x01({c\xfeFl\xa5\x02\x94Y\x1c\x98\xab\xb7Z\\\x9e#\xd1pi\xea4\xef7\xffV@\xe4\x19\xbek\xe1\x13\xf8\x93\xcbaem\xf5\x03u\xc1:\xfe\xb8\n\xa2\x984\x05;3\xa2\xc4\xd4_\xb7F\x88\x14\xb5\xd4\xfa\xcd_\xb7\xf17\xe9\xe3*\xf6V+\xf2\x85;a\x13\xd9\xbem_\x91 b\xe6\x8d\xb6\x9c\xd7\x0efA\xfc\xf9\"\x1d\x82\xb5\xd3\xab\xc1\x86+\x7f\x9a.\x9a*%\xf1d\x0831\x90\x1a6#\xa0\xfd\x9d^y\xf39\x89\xe1\xfdK\xc3\xack q\x89\x80'\xac)\xcb\xa9\xfb\x04\x13v\xb7]\x96\xd2^\x11\x8bS\xb7YN\xb3\x8b\xa5\x9f\x0eaaZ\xc1Uw\xe9\xad\xda3\x0b\x92\x04\x9et'A\x14\x8a\x898\xf4\xd3\xfa\xe3\x87q\x06f\x9an\x92\x7f\x1d\x1d\xa5W8\xf73\xc7\x95\x9a\xbe\x91\xa8R\xceCK\xdb_\xbe\xacb\x90Qojd\x18\x94\x02\x80`J~\xccxy\x7f\x15\xce\x1f_x \xd9\xdfu\xfd\x0f\xcf\xde\x9c\\\xf5\xbe\xfej\x1e\x1d\x1e\x1e\x1e\xbe>}\xbf8~??<<|\xb6K\xff&G\x87\xaf\xe8\xbf\xaf\x1e\x04\xfb\x7f\xa5?\xbe\x7f\xf1\xec\xd5\x87\xe3\xf7\xb4\xc2\xfb\xd9\xd5\xad\xfe\xeb\x05\xbf<\xbb\x1f\xf6\x9e\xcd\x16\x1f\x9f\xad~\xba>\xea}\xdc\xbd\x7f\xff\xfe\xfd\xce\xcf\xeb\xdd\xa3\xbf\xac\xfa\xcf{\x8f:\x9dY\xbast\xff\x97\xbd\xfb_\xf7\xf7\xef\xbf\xdfy\xf0\xe8\xfd\xec\xea\xf9l\xef\xe1\xfd\x9f\x1f<\xea\xbc\x8f\x07\xcf\x07'G\x97\x8f\xe8x\xfe\xfc\xdd\xc9\xe9\xbb\xe0\xd5\xe1\xf1\xf1\xe1U\xf8\xe8\xfe\xfd_v\x0e\xe7\xeb\xdd\xfb\xeb\xef_>\xbf\xaf>\xef_\x91\x9f\xfc\xfe\xe5\xe1\xe1\xe1\xf3\x87\xa7\xefO\x9e}\xf8\xf3\xfcY\xf0\xb7W/\x0e\xa3\xbf^=?|w\xf2\xf1\xe2\xbbg\x0ff\x9d\xf5\xdb\xaf\xc3\xe0\xbb\xc3\xbf\x85\xfb\x97\x83\xc9l\xe7\xf0\xd1/\xf7\xdf\xce\xde\x1c=|\xf9\xf2\xfb\xd0\xdf{\xb1\\\x1e>{\xf5\xf0\xc5\xab\xc5\xd5\xbb\xfe\x83\xc9\xa3E\xb8\xf0\xff\xf6M\xff\xe8j}\xfcM?]\xbe}\xde\xfb\xf9\xf4\xeb\x9f\xf7\xe7\xdei\xfa\xed\xfd\xcbW\xdfy\xe1\x87\xe5\xe1\x87\x93\xe7\xef\x83?\xf7\xdf\xac\xb3\xec\xdd\xcb\xd7\xd1\xfe\xe5\xa3\xde\xe9\xc7\xd9\xc3\x9f\x937\xe9\x8b\xfd\xf9\xeel\xd6\x8f\x92\xb7;o\xc2W\x93\x0f\x0f\xa6\xbb\xab_\xa6/\xdf\xa7Y?:\xdc\xfd\xd0{\xfe\xb7\xe8\xeb\xe5\xc7ep\xfc\xfd:}\xfe\xfe\xa7\x9fNw\xd2\xe5\xd7\xcb\x9f\x9fuV\xdf_?\\=\xef\x7fx;{\xf0\xd3\xdb\xe3\xde\xcb\xdd\xde\x9f\xff<\xf1\x9e]\x85\x19\xd9\x9f}\xf5\xcb\xfc\xfat/\xfd\xee\xe5\xfbG\xfbo?<\x88/\x9f\x7f\xfb\xe7\xd7\xdf|\xe8=\xffz\xf7\xc5e\xf4\xf5\xf2\xc5\xea\xf5^\xf4>\\\xfb\x0f\xbf\x8e\xc8\xe1\xe0\xfe_\xbeK\x96\xdf\xfd5\x8b.?\xf6\x12\xff\xa4\xff\xd5\xc3\xf4\x9b\xcb\xd7\xfb\xe4\xd9\xa3\xe4\x9b\xab\xbf\xac\xee__/'\xd7\xde\xdb\xfb\xef\xe2\xb7\x9d\x93\xb7\xcb\x8bW\xaf\xfc\x8f\x93\xbf|\x98\xbf;\xe9{\xef\xff\xf6h'\xfa\xea\xbbd\xfe\xdd_\x0f\xbd\xaf\xf6\x8f\xaf\xe8\xb2\x1c\x9e\xbe\xff\xf0\xe6\xe4\xeb\xbd\xa3\xef_\xbe\x1c}F\xd0\x19\xd2\xbd\xb8N\xc97Lj\xae\xd3.\n\xad\xe2\xc4N5\xf2\x18\xaai\xc6=\x8d\x84\xc34-\xaa\xe9\x1c'\x16;\xf0\xcf`\x87\xd0\x81\xd8\x81\xfb\xb0\x0b\xdb\xd2]\xe9\x8d\x0b\xa4\x9bF\xcf\xaeS\x82\xa6a\xf5\xd7f\xb9\xe9 \xb3\x10\xc4Q2\xcb\x17:*\xe6\xfc:\xee\xf3\\\x14!\xb9\x82\xa8\x92\xe4\xa7\xc6N\x03\xc7I\xa0C+\xb1q*f\xc3x{\xe6BF\xe99%\x06=\x97\x05q\x86\xa7\xd0\xc3\x0b\xe2m\xd8\x85!\xad\x120\xfb\xc5\x00\x9e\xc0\x8c\xfe\xd3\x19\xc1\xae\x83\x90\xf5\xc7iw\xb2\xf0\xe2\xa3hJ\x0eS;p\xce\xe0\xc9\x13\xe8?\x84O\x95\"\xe8@\x9f\x17\x0f\xf4\xc5\x03V\xbc\xaf/\xddq($\xc6I\xa7\x83\xe6\xfa\xf0\xf4)\xf4\xf7\xe1\x1e\x0c\xf6\xf6\xd4\xf7\x0f+\xaf\x07{{pO\x0d-5@)\x9bI\xcf\xe6\xc9\x18\x06K\xe7\xf2\xf4)\xecV;Q\x18\xb3~\xab^\xfa\xbdZ\x90\xed\x9a!\xf6\xf4)\x0cZ\x03\xc0\xd1\xa2\xb4WF\xe0Y\x1c-o\x87\xc2B\x97\xc5\x8d\x12\xe0\x8f\xb0\xc3\xc2=\x8e9>\xf782\xc36\xf8,\xc7\x83G\xff\xe9\x8c\xa0\xbf\xbf\xf3p\xc7\x81\x88\xb1\xe13\x8a\xe0\x99\x8b\xd1n\xb1\x04\x9e\x82\x07\x07\xe0\xc1\xb0x\xa7\xb2\xc0\x0c\xd2>\x1c0@\xa7c\xda\x0d\xdd?\xbc\xd1x\x8c\xc0\x19\x9c\xd1\xcd;&\x0c\xae\xf7`\x7f\x87\xbe\xb0F#\xcbq`\xc8\xb1\xc2\xcf\xd7\xcbf\xed\x0cp\x1d\x1e:\xd016\xdc\xef\x89\x96)b\xe4-\xf3\xae\x06RW\x15\xee=\xbf\x93\xfe)\xf2C\xdb\x92\xec\xb4$E\x91d\xc5\xc9 \xea\xf3\x7f)\x84\xa5\xf8\xab\x92\x9f\xdc{?L\x1f\xb2u<\x90\xff\x18\xb2\x90\x88lQ\xac\xc3gG\xcf\x8f_|\xf5\xe7\x97\x7f\xf9\xfa\x9bW\xaf\xdf\xbc\xfd\xeb\xc9\xe9\xbb\xf7\x1f\xbe\xfd\xee\xfb\xbfy\x17\x93)\x99\xcd\x17\xfeO\x97\xc12\x8cV?\xc7I\x9a\xad\xaf\xfe_\xea\xde\xb4\xc9\x91d9\x0c\xb4\xdd/k\xf6\xfe\xc2~q\xa4\x86\xdd\x99\x83\x04\n@\xdd\xa8F\xd7\xeb\xd7\xd3#55\xd3\xfdl\xaa\x1f\x9fH\x00S\xcaJ\x04\n9\x0dd\x82yTW\xcdT\xafQ\xd2R\xa2H]\xdc\x95(R\x07\x0f\x1d\xe4.IQ\xa4\xb4\x07wy\x99\xed\x9b\xf9#\xfa\x03\xfb\x17\xd6\xc2#\"32#\"\x13\xa8\xaay\xd4\xc2\xac\xbb\x00\xcf\xc88=\xdc=\xdc=\xdc\xafo\xbe\xec\xf5\x07\xbb{\xfb\x07\x87G\xc7\xed\x1d\x8b\xa7\xcbat\xa4\xc8g\xe9\xc1\x13HN\xa0\xdd\xf6\x1cqS+\xc3+b\xc18\x93Q\xd9s\xe8#O\xe7\xec\xe0\x9b\xa9z\x9e\x1d\xa4\xf4\x14\xc35\xc0O\xc0\x1e%c\x0e\xa4\x8b8z\x87\xc4\x13\xa3\xba\x15Q}\x99\xc3W\x178\x1bAO\xd0\x0b\x02\x1e\xac\xb2e\x1a\xac\x97\x98\xf0f\xaf\xaaE\xbb\xca\xef\xe7`\"\x95\xd7s\x9b.\xa6v-;\xfcN\"\xb0x\xad#\xbc\x03=\x0eq\xa3\xe4\xf1\xc8\x87\x8c0\xd3\xfeN\x8b%\xd7\xcc\xc3\xdcD\xf1s\xa4\xe0\xa1\x90\x85+.m\x90\xad@H\xff\xb4G\xb0\xeb \xc2\xd8)] Jr(\xf5\xec\x1f\x1c\xf6\xfb\x07G=\x8a\xd7\xf4 \xba\x8c#\xa6St\xdd\x1f\xf0'\x8c|\xb0\xe7\x03*\x9df\x02\xf3\xed\x88y\x18Q\xfc?\x92p>B\xc8\xa0\n9\x90\x00\x07\xbb\xf0\x08\xa2\xea\xad+>}\x99f+\xe4\xdf\x82\xb1\xd5\xb1d\x0c\xea!\x06\x1d\x0c(jY\xe7\xbaG\xbbZyC\x9eM\xd2\x8d\x897\xab\x0b\xbb\xa7\xa0\x02\x0b\xabM\xe7\xfa\x08>\x84\x80\xca\x02\x942\xa8\x12\x05\xdd\x17v\x9f\xce\xab\xe7\xe8K\xf80\x82\x04\xe7L}F\xd9r\xe7P\x85\xa3\x9f\x10\x9cb\xc3}\x18BO-\xb2\xe6E:\xf4\xb9\xa6\xea\x05K`\x04m\xa8\xe6T@\xc4B^\xbff\x14f\x01\x8f\xf8\x18:s6\x08X\xc0\xd3\xa7#\xe8\xcc\xa9\xe4\xd0\xa6;\x18\xe6t\xdb\x9d`\xf9\xc1\xfe\x01|\x88\xe1\xb2E\x03.\x88\xfa\xe6\xd0\x19\xc1\x91\xa3i\x91\"p\xa4\xb6\x14\x95[\x8a\xf3\x96\xb2\xbc\xa5l\xf3\x96(\x91`7 #\x07\xfb\xda\x87N\xf5\x06\xaa\xe1~3}5\xc2W\x8b\xcc3\x19\x9c\xc2+\xef\x15\x9da\xd8\x81\x1e\x15\xbc\x16\xf9\x9ck\xf44\xc8\xf0>\xf5\xd2Ew\x1d\xbd\xb3\x07\xec\xee[D;Z\xbe\xc8\xaa7\x17KU\xe3\xa8?,U\x15Q$\x94\xf6\x0ce\xe8\xef\xe2 \xad^\x93\xa9\xcdiBq\x9b\"6\x0b\x19\xcf\xd1\x9b\xd6\x1c\xe8\x91w\x9e\xa3\xb7o@o\xf4\xb00\xa07\xc5\xd1\xc1n\xce\xbc\xe5\xd1t\x06{\xb4\xc2\x12\xe8\xf0\xd0\xd1\xe3:\xc5\xe5\x98\x93\xd5H\xdf\x8d\x19/B\xa7\xaf\xa3y~\x85\x12\xd4\x13\xe8\xc1\xed-\xbf#\x8b\x8e\x1b,K\xc4\x13\x14\x8cq\xa7i0\x97\xce0v\xd4\xbbH\xd0-)H^y\xafl\x82>\xf2\xcc\x90\xca\xd0\xe3\x14lJ2\xf2\xc7\xbcJF\xbc\xe7tp\xb8\x0b\xb0\xae\xf92\x8ab\x1b\xbf.\xa3KZz\x87=\xf8\xe4\xd5\xc0q\x81P\\K\xa0\x8cM\x9d\xccq\xe0 \xf4\x91\xf3d\x9d\x0ee\xcb\x1f\x8e\x80\x96\xa7\x07\x82\x11\xee\x94%<\xa5\xfd9\x855\xec@\x02CXW\x10\x89n\x89\xa5CQ,\xa1E\x07\xac\xb6v\x9b\xd6\xb6\xc3j\xcb\xeb\x99\x8b1\xc9\x83(\xb5\x82Om\x82\xb5u\x18\xe6\xca\x8d\x05\xac\xb6\x11,q\xf8\xc8\xbd*E\x96\xe6\xf7F\xd0s\x9c\x13\x08hcG'(\x9f\xb5aQ\x88\xbd\x1e\xa5T\xed\x11\xcc(\xad\xdeAzA\x85\xa7:\x12\x94Qd\x0e\xe0\x96\xbe\xeb\xd3w\x83\x13\xf0\x19\xc5Q\xaa\xcf\x8a\xea\xb3\xbcz_W=\x7f\x15:0\x9b\xc2\xed\x08\xfa\x03\xba\xb1\xae*\x1c\xae\xe1P,+p\xca\xdb6\xf7\xea\x0c\xed\xdd\xc1Q\xe5\xc8[x\x85\x96\x1dk7i\xb2\xb8\x921\xd08\xdb\xc6\xdd\x9f<{\xfd\n\x1d2\xf9W\x9d\x87M\x9e\xe6fXI{S&yMW8\xccwS\xf2\n\xf9\x85\xdd@{[w\xa3\xf1\x9a\xf4\x0e\x92g\xed\xa8\x14\x0d]LPd\x87\xf6\xee\xae\xe2w\x1c\xf0GG{\x8e\xd6\xa57\xfa\xf1\xba\xf4n\xe3\xdd\xde\xa8KU\xd3(H\xf9\x185q\xbbh\xf9\x8a\xe3.\xf3\x11\xa7\xef9\x1b7\x0b\x924^g\xa5\x8eq\xa5j\x94\xcaxM\xd8\xfc\x9c\x12\x03\x161\xc1\xe0\xc3\x11\xdf\xd4(\x8a\x8bP3\xeclT\xf5\x83vN\xa0\x85>\xfaH\xf2\x92Rv\x00f\xee\x0fy\xbc\x0b\x9e\x94\xc0\x85\x16z\xce\n\xa7!\x96\x1f\xc19\xe1\xe34\x18\x85\xde\x83\xef\xb1\x84 u\xda\xf0\x88M\x15\xcb\\n\xa8g\x1e\x84\xderY7\xe4\xfa \xa1\x9f\x16\xfa\x13%]\xbe\xd4\xd2w\x83\xd3\x18l\xd84\x08\xf9L\x9c\xfb2su\xfa\xf1i\xa1\xda[\xf7X\x9ca\xa7:\xe7\xc5\xa9\xf3\xcd\xcd\x9aTN\x9e<\x80\x12\x0bV\xc5\xeeYf1\x8b\xe1\x11\xa4$\xf6.\x96E\xc0\x7f\xe5\xc2V\xd14{\xf2 \xbcb\xb7\x1a\xdb\xfa>\xbc\"\xb4\x8f\xf6\x1d\x17B\xfb\xf8\x00=\xa5\x8b\x0e\xd0\x96\x06\x1bu\xbb\xe07\xfd]\x1d\xc7 \xed\x03\xc7\xb6p\xb6\xd2(\xaez\xea\xb0\xeb\x80\xbb\xa6x\xe1\x94\x89u\x83\xe4\xa5\x98\xebM4\xc89\x85\xd2\x9eUyD\x15\xdc\x8a\xe3\x80\xa5t\xf8\xeew\xf3\xee\xe1\x9d[L\xb7U\x8d\xc9\x12\x97|k7\x9a\xde\x0dWt\xefAWtww_Y\xcb\x81\xd3\xe5w{\xbc$ .\xc3Mj\x92\xd7U\x9a\xca\xd8\x8e\xbbg\xd0\x86\xb8\xfb\xb1\x0b\x16\xabU1\"\xb2V\xd8\xe8\x0e\xa4I\xdb\x08\xa1\x9an\x9a\xeeU\xaf\x94\xf2\xa8\xef\xbd\xaa\x14\xc5p\xeb\xa0:\xbd,F\xfd~5v\xbc\xc7j\x19T\x8b'9J\xf1\xc9\xd3cj\x0b\xbd\x07C{p\xec\xd8F>-\\\xf1\xbe\xd2\xc4e \x068e\x9a,\x91\x88\xceQ\x0d}\xc8t\x9a?K\x8b\xfd<\x80\xce!e\xe9\xc9z\x19\xa4\xb6e9\x1a\xc7-\x1d\xeb!\xe3t\xaap\x9b\xf7\x8e\x0b\x87\xd0\x1aA\xc2\x82\xd5:<\xcf\x91\x9c\x1e\x91=\"\x8e\x93\xab\x89\xe8\x0b\x92%\x86\x1e\xabj\x85\x88R \xe6\x0cm/t\xces\x911We\xd3\xf3o\x9f\xd9F\x82\xee\x9cYC\xa2\xee\xfc\x84\x9e\x8b\xc0\xd7\xe4\x15\xcak^\xbbx&\xf5\xec\xbc\xd2\xb1\xdfnO\x1d\x17\xcf\xa1\xf4\xd0\x14\xdb\x0b\xa7\xebG\xa1\xef\xa5\xf6\xdc^\xa0\x02\x9a\xc2\\<\x89\xce\xf2>\xdc0\x0b\xcc\x15<\x85\x9b\x13\x07\x96\xec\x9e\xd3\xc2\xc5\xb3\xf3l|Cke\xe2\xc2xM't1^\x1b\xf4j\xd2MK\x18B\xb2\xc9\xe6\xd9\x90\xe4<\xe4\x81\x83\xd6w\\Cr(\x0elRO\xb1\xc3\x95\xbd\x19\x88\x8d\x7f\"\xb5\xda\xdf;vl\x8b\xd6n\xb9[\x88\xc65f\xb8\xc0\x8e\xa9`[Fp M7\x19E=\xf5\xda\xf9\xdc\xfe\x89A\xefv\x928\x1f\xda_xW^\xe2\xc7\xc1:\xbd\x9dy\xa9\xe7\xec\x04+u\xd4;\xe3\xcf'\xd7\x83^gr}\xf8b\xbasY-\x12\xb1:\xc7\x9f\x0f\xa7mg\xb8s\xb9RI\xdd\xd8\xeaZ.X;\xb2\xef\xb9\x19K\x12/\x0c\xd2\xe0K\xf2\x83x\xd9t\xf3@\xd8\x92\x98R5\x15\xd7~\xe8Y\xce\xd2y\xb4n\xb4\x12 k\x95\x85\xde>\x1d\xf7\xa6\x0e<\x85\x8e&'\x95\xed9\xdc\xd6\x84\x8a{\xaf\xbb\xa2\xd2\xb3\x1d9\x8e\xb0-1\x0bm\xdcMI\x922\x15\x8e\xe5]DY:\xbcXz\xe1[\x0b\x86\xe0a\xc4<\x19hB\x81M0\xa0\xc0\xe3\xdd=\xbd@\xb4\xbb\xbf\xeblc\x1e\xc6`\xf8\xdd4\xfa$zG\xe2\xe7^Bl\x0c\xd1\xda\xa6C\xa6t \x03\x96W\xe3\x9e\x1a$\xaa`\xbb!\xec\xe9\xc3:\xf4\x0f\xef\x1e\x98\x027Yy4[\xcaUE\xf7\x0e\xaa h\xf8\x04\xefU\xb98\x93\x05\xaad\x8f\x89\x02\x87U\x81\xc2\x03\xae\xfeS%\x81\x98N\xb8\x14\x93e\xc8\x05\xcarIf 8\x85\xa4+\xf2\x87\xe5\x05\xebg\x0d\xb3\x12V\xe6\x0d\x03k\xf2\xa4\x8e\xfal\x80\xaa\xc2<\x92\x93\x1b\x06<\xdfX\x1b,K-\x9a\xc9E}8\x05_\xa4\xfb\xa3\x9b\xa2\xf2\x82\xe0\xc1DS\x19\xaf\xc2\xeaa/\xc3B\x15;\x1aA\xc7\xa3\xdb\xae\xd3\xa3\xbb\xad)~\x80\x89\x9dm.!t\xfa\xdc7\x83\x07\xc1K\xb9\xa2\xb9l\xf2f\n\x90\xd89\x81v;\x84'\x10\x9f8\x10\xf0\x00\x83<\xbcv\xa8\xe6\xc6\x16s\xfa\xa0\x18\xcb9\xa5!~.Z\xed*\xc7\x11\x15\x8f\x83\x1c\xd7TdfX+\xe5\xb2\xdb\x10\x1d\xcd\x87\xac\x88\xdf\xde\xc6\xf0\xa4\xa5\x12 \xae\x86(qW\xf5\xda\x86\x94G$5\xe8m\xc4\xccUB\xd8\x95\xb4$\xef\x95.\x06h\xdbf]\xd4/`\xcc\x9d\x06NE\x07B\x18\xc2\x8c,IJ\x10R\x8ap\xd8\x8c\xa8\x02\xf5\xaa+\x99O\xfa\xb6\x13-D@1\x88\xbb\xe2\xdb\xee^\x95\xe8 \n\xaeO\x92\xb5\xbb\xaf\xcb\x92\x85\x8c\xe0\x8eC\xc8\x0bhu\x83\x04%zSx\x01:\xa5\x01c\xda\x11\xa3H:r+>\xcc]\xe5\x149>\xe5\x88hZF\xb3\xb2\xbe|\xc2\xcb\xc7v\xe8B_:\x9e\xd0w\x93e\xe0\x13\xbb&\x91\xb27N\xa76\xa5\xaaI\x193\xef\xbeR&-H\x93\xa8 0^\xefe!0)\xdfd\xdc\xd7\xe1\x14\x02J\x8dQK\xf9\xe8\x11\x84\xf0\x94\xd9\xf4R<\xd7\x88\xa6\xb6\xd8\x03\xdbv9f\xa4Z\x99_\xf3P\x98YOx\xfbt\x08<\xc5\x1eS\xda\x1e@\x1b\xbd6P\n\x0c\xf9\x03\x1c\xa0\x93\xbf\x84a\xfc\x02\x87\x91\x7f\xfar\xc8_\x0e\xa1\x83\xceXO\xa1\xe7\xb2/#\xad\xd9\xf0\x8aG\xbc`\xac#@\xd6\x11\xc3\x13\x08N\x1c\x88Xh\xb1t\x1c\xd3\x9e\xe8\xfd\x11\xa3;\xe3\xc6~u\xb76\xed\xe2A#.\x19\xe5\xb3\x94m\xb7\x94\x1dp\x1bIO3\n\x18ZJ\x0b\x15\xc4\x16M\x08\xb2`\x8d'\x93lv\xd4\xebu\xe8\xdf\xf9|>\xad\xb8\xa3\xc7\xa2Po\x97\x15\xea\xed\x1e\xcc'\x93lN\x06\xf8sN\x06\xf4\xe7\xa07\xc3\x9f\x83\x9eZ\x05\x9dd\x0b\x9b\xd9\xf5\xc7\xac\x99\x0bSs\xe8\xd85\xfe\xbc\xa1S\xe8\xc3e\x9f\x0e\xe5Jg\xe4\x00\x8b\xcf\xe6\xf3\xa9\xf3\xd5\xe0\xbd\xa52\xf0\xf2`/\xe6\xf3)\x02|sC o(\xcfk~\x9b\xe7Fw,\x16\x89A\x95Y\xb1\x999\xe9\x11\xf6g>=\x15i\xefm\xde\xe9A\xaf7\xe3\xb5\x8e\xb9G\xcd\x94\xd3\xcd[\x0bEL\xc7X\x87\xe5|XU\xff\xce\xa5^\x8e#\xd1\xd5S+\x0f\xed\xe6BX\xad\xbf\xd2\xef%\x8cx\xb6X\x1bGg\x9f\x8e\x8a\x91\xe2\xa0\xe7\xd0\x06\xdf\x05\xeb\xd2\xba\xeb\x9eH\xf9\xa9r\xe9\xb0+\xc2w\xdf\xc6\xd5s\x898\x10V\xa3\x01\x8am\xac;\xb1\xf0\xd1Z\xe3\xc7\xff\xe5\xe7~mj\xddkd\xf5\xccY\xc8JvdS.\x9c\x1f\xf13<\xe2;\x18\xb7\xc72\xdb=\x1a\xf7rC\x02U\x13\x9f\xd31\x8d\xa8F\xde\xd7Pr\x14\xff\xa2\xdc\xdf/\x1d\xb7\xdb\xc1\x14\xe9y\x00O :q\xd81\x87\n\x06\xe98\x98\xa2\xeb\x8dA\x92l:\xcf\xd4`\x83A\xcfU=s\xa3\x96g<\xb9\xf6{\x9d\xc9\xf5\xec`r=;\xeaL\xae\xe7\x07\x93\xeb9~\x99O\xb2^\x9f\x92\x82\xac\xd7?\x9cOw.kpf[zx\x1f\xe4\xb2S\x14\xdfR\xc7a\x96q\x81>\x11]\xdb\n2\xdd}\x12\x0f\x9dJ\x90\x03\xebG?g\x0d\xc1zV!\x14\xd6\x8f\xfe\x96\x1e\xfc\xb7\xf5\xe0\xbf\xa3\x07\xff\x8fz\xf0\xcf\xeb\xc1\xbfI\xc1\x9e\x02\xfe-=\xf8\xdf\xe8\xc1\xffV\x0f\xfewz\xf0\xbf\xd7\x83\xff\x1e\x05?W\xc0\xbfC\xc1\xbe\x02\xfe'\x14\\M\x91j\xfd\xe8\x0f)x\xa6\x80\x7f\x81\x82\xab D\xad\x1f\xfd}=\xf8\x17\xf5\xe0_\xd2\x83\xff\x17\n&\n\xf8\x7f\xd5\x83\x7fW\x0f\xfe==\xf8\x1fP\xf0K\x05\xfc\x0f\xf5\xe0\x7f\xa4\x07\xffc=\xf8\xf7)8P\xc0\xffA\x0f\xfe\x03=\xf8?\xea\xc1\xbfL\xc1\xaf\x14\xf0\x1fQp\xf5\n\xab\xf5\xa3\xff\x89\x82_+\xe0\xffY\x0f\xfe\xa7z\xf0?\xd3\x83\x7fE\x0f\xfeU=\xf8?Qp\xa4\x80\xff\xb3\x1e\xfc\xbf\xe9\xc1\xff\xbb\x1e\xfc\x7f\xe8\xc1\x7f\xac\x07\xff\x1a\x05\xff@\x01\xff\x0b=\xf8_\xea\xc1\xffJ\x0f\xfe\xbf(8S\xc0\xff\xb7\x1e\xfc'z\xf0\x9f\xea\xc1\xff\x9a\x82\xab d\xad\x1f\xfd\x19\x05\xdf(\xe0\xbf\xd0\x83\xff.\x05?S\xb7\xc3oS\xb8\xa7\xc2\x7f\x9d\xc2\xdf,\x14\xf8\x9fSx\xaa\xc2\x7f\x83\xc2\x93jH#\xebk=Y\xfeZO\x7f\xbf\xd6\x13\xda\xaf\x91\x88+\xe4\xed\xeb\xbf\xa3\x07\xff\xbc\x1e\x8c3\xa0\x10\xc3\xaf\x7fA\x0f\xfeE=\xf8\x1f\xe8\xc1Hh\x15\x8a\xfa\xf5\xdf\xd7\x83\x7fI\x0f\xfe\x87z0\x92 \x85,\x7f\xad\xa7\xd6_#eR\xa8\xf5\xd7\xbf\xac\x07#\x99P\xe8\xef\xd7\xffT\x0f\xfe\x15=\xf8W\xf5\xe0\x7f\xa1\x07# R\xf0\xed\xeb\x7f\xa6\x07\xffs=\xf8\xd7\xf4\xe0\x7f\xa9\x07\xe3\x9e\xfd\xab\n\xf8\xd7\xf5\xe0\xdf\xd4\x83\xff\x8d\x1e\x8c\x9b\xf3R\x01\xff\x86\x1e\xfc[z\xf0\xbf\xd5\x83\x91\xd9\xff5\x05\xfc\xdbz0\xca\x00\xca\xc6\xfc\xfaw\xf4`d\xb1\n\x07\xfb\xfaw\xf5\xe0\xdf\xd7\x83\xff@\x0f\xfeC=\x18\xd9\xb7\xc2\xd8\xbe\xfe==X\xcf4\xbf\xd6s\xc7\xaf\xffH\x0fFv\xf2\x93\n\x18\xd9\xc9\x17\n\x18\xd9\xc9_W\xc0\xff'\x05\xbfU\xc0\x7f\xac\x07#'\xf8D\x01\xff\x89\x1e\xfcgz\xf0_h\xc1\xdf\xfc-}i\xe42\xd5\x981\xd6\xd7\x7f\xaa\x07\xff\xb9\x16\xfc\xcd\xcf\xe9\xc1\x7f[\x0fF\xd2\xabH#\xdf\xfc\xbc\x1e\xfc\xf7\xf4\xe0_\xd4\x83\x91 (\"\xcd7\x7fW\x0f\xfe\x05=\xf8\x97\xf4`\xa4\xdf\x8a\x90\xf2\xcd?\xd2\x83\xff\x89\x1e\x8c\x84Z\x91/\xbe\xf9\xc7z\xf0/\xeb\xc1Hc?S\xc0\xbf\xa2\x07\xff\xaa\x1e\x8cT\xb3\x1a\x93\xc1\xfa\xe6\x9f\xeb\xc1\xbf\xa6\x07#\xa1>S\xc0\xffJ\x0f\xfeu=\xf87\xf5`\xa4\xc8\x8aT\xf0\xcd\xbf\xd6\x83\x7fC\x0f\xfe-=\x18)\xf2\x1b\x05\xfc\xef\xf4\xe0\xdf\xd6\x83\x91\xf4VC\xe4X\xdf\xfc{=\xf8w\xf4`$\xa6\x8aP\xf8\xcd\xef\xea\xc1\xbf\xaf\x07\xff\x81\x1e\xfc\x87z\xf0\x7f\xd2\x83\x91\xc6*\"\xe47\xbf\xa7\x07\xff\x07=\xf8?\xea\xc1\x7f\xa4\x07\xffg=\x18I\xef\x0f\x150\x92\xdew\n\x18I\xaf\"\xe3~\x83\xa4W\x11f\xbf\xf9c}i$\xbd?\xa3\x80\xffD\x0f\xfe3=\x18\x89\xe9\x97\n\xf8O\xf5\xe0?\xd7\x82\xbf\xc6\xd5y\xa92\x1e\x9c\xab@\xe1<\xdf\xb0\xe3\x9a\"\xb9|\x83\xc2R\xa4\xc2Q\xb0|\xac\x927\xe4\x1bI\xe1\xcab\xf2\x08a\x8ex\xdb\xab\xe9\xee\xa3Q\x945u\xdc(5\x84tL\xa6\xa5\x17\x9aT\x895J!\x83_\xc8\x81>\x1d\x89\xa2q\xcbx\xf1~\xa3\xeaKo\xde\x12zc\xbcK\x92\xf2\xe4\xdd\xdc\xf2\xc6\x9c\x92\xe4\x81\xa3}\x93\xdb]\xb2\xc2\xee\x82\x1aL\xa6x&\x9b)\x9euv\x12\xf4 \xeb\xf5:\x93\xeb\xc1|r\xbd\xebu&\xd7{\xbd\xc9\xf5\xfeEgr}\xd0\x9b\\\x1f\xd2/\x87\xf3i{\xe7\xae6j\xd1\xc9\xf0>\x9d\xf4:_N\xc7\xcf:?3\xbd\xc5\xff\xbf\x1a\xb8\xef\x11v;\xeeu\x8e\xa7\xf4+{\xc8\xbf \xf4v\xfc9\xfb\xd9\xeb\x1c\xc3t\xe7\x8e\xdd\x0f\x99g\xd8Vv\xae\xdc\x085\x99\\{\xfedr}\xd1\x9fL\xaeg\x87\x93\xc9\xf5\x9c\xfe\x87\nV:\xe1l\xc6q\xca\xd9\x9c\xe3\xa4\xb3Y\x9f\\_0\x85k\x8f+\\\x0f\xe60\x99\xa4\xf4\xf5\x8b\xc9\x84\xbe\xeb\xf5P/;\x9fO&\xe1d\x12c\xa1\xc1\x11\xfbs<\x99d\xfd\x83#Z\xa2\x7f\x84\xd6\x16Z\x11\xfb\xd3g\x7f\x06\xec\xcf.\xfb\xb3\xc7\xfe\xec\xb3?\x07\xec\xcf!\xfb\xc3\xea\xec\x1d\xb3?\x1ek\x81un\x9f\xfe\xd9\xed\xf5\xaaq\xae\x98y\xcd\x826\x0b\xecm0\x9d\xcd\xda\x96\xba\xe1P\x0b=8\xe4\xc3>\xbc\xd0[\xc9\xe8R\xd3I\x9d\xd3\x99\x9a\x1fL\x98\xb6{r\xad\xda\xba<\xad\xe9Mt\x0d-A\x95\x06\x8dU?\xeb\xfc\xcc\x84)\xdaQ\xd3\xceT\xed\x93\xeb\x191\xd9\xd7\xb60\xe4\xf9w2\xe4\xa1\x89l\xbcq\xbf\x96\x92E-\xcb\xed~\x9e\xcer\xb6\x96\x8a\xce\xeb\x8b.x\xd1-\xcd\x07\xb7&\xdb\xa9S\xb5>\xce\x8c\xd6\xc7\x85\xc1\xfa\xa8\xb5\xb5\xe2\x1d\xe8\x8d\x0c\x92\x0b\xbdA\xf2\xaad\x90\xd4\xd7G\x9f\xcd\xca\xaf\xdd\x14&\x96\xf1<\x8fs\x8f\xf3\xdf\xa6\xd3\x86\x96:\xfbt8\xbb].oW\xb71\xb9Mn\xd3\xdb+\xe28\xa7\xdc^9\x8e]\x98\xbb`}`\xa9\xf6NX+\x15}t\xfb\xc9'\xb7\x9f\xde~\xf6\xe2\xf6\xec\xf6\xcd\xedO\xbd\xa8T\x04mX\x9a*+\xfa\xb7\xdc\xa4\x7f\xe2\x8d\xa6\xe6-\x17\xf7\xfb\x87\xf6\xe9\xb0\x7f\xf6\xe6v\xf0\xea\xa3\xdb\xdd\xcf>\xba\xb5O[\xe3\xfe`w\xeaL&\xb37\x7f\xcd\xb1OG\x93\xc9\x05\x92\xf1\xf3\xa9#\xbf\x93\xa4\xb7\x83pv\xbb\x1b\xcfJ\xef\xa4\x8b\xfc\x9dg\x9d\x9fa\xef\x04.\\I\x03\xbb\x97\x8dJ0\xaf\x9b\xcd\x98\x97Y\xe48\xa8\xe6\xf4a\"\xc7a\xd5\x05\x98'@\xeb7:\xd0V;\xcc\x82l\x06_\x12vw\x9b\xe7\xc6\x9cy\xa9w\xae\xcf\x7f\xba\xf0\x92\xc5\x10o\xb6\xc5\xae\xf2p\xe5\xad\xf1\x99\x1d\xd1q\x07\x1a\x0f)\x91f\x0b+(=\xbd\xbb\\\xa6\\\xc6\x11rYU^\xe3\xf6o\xc55\x97\x0bf\x8a\xdb\x8b\xc7\xe1\x03\xed\x9d\xdd\xc4\xec\xc8\xa8\xb3%\x87\xdb\xd9\x92Y\xd6\xcc%\xf1b\x1b-\xc8\x04\x03\xb9\xe8\xa4_1\x13T\xd2U\xfd\xcaD\x18\x7f;f\x1e\xeb\xe3\xfe\xb4\xde\xb4N?\x89\x9c\x0b\x92\xf6\x81e\xed\x92\xc1\xdc\xab\x11\x13x\xca\xf0K\x82\xf2i\x19\xb8\xf0(\x12fe`\x82%\xbd\xf2\x1d\x8f-/u\x1c6\xca\xd2Z\x84\x970\xb5\x9d\xf1d\xfa\xd5\xfb\xdb\xe9\xce%\xd2\xf1\x0f\x1eYR\xb1r3\xb7\xf9}\x07\xa7\xfb\xe1)R\xf4\x89\xed\xdc\xe2\x06\xea\xb69`\xea`M\x1f\xf4\xbb\x1f\x9e2~\xf5\xc1\x9d\xe9z\xcbn\xa1\x0b\x1b%n\xc2\x03\x01o\x1e`\x18\x8d!x\x0e\x13\xfb\xb3\xd2\x8d\x9f\xcdQ'\xcf\xe5\xa6$\xbe\xccs\xb9\xed\x8c?\xefN\xdb\x1f\xect\xc95\xf1m\x8cR\x16\xe0m\xa8\xe2[\xf7\xe5\x8b\xf3\xef\x7f\xf6\xfa\xcdk\xbc\x87j\xe1\xa5\x15\x8b\xdf\xf6Kb\xdf9\xefw\x99\x03W\xd9\x15\x7f\xbb\x99hE\xcc\xd9%\x08\xb7M\xfa)\xed^gl\x9d\x9f\xfbQL:_$\xe7\xc9\xc2\x8b\xc9\xec\xfc\xdct\xa7\xe8\xae*\x05\x8dc\xff\xc6\n\x83\xe6C\xdbf\xb3&\x18\x03\xd2\x96\x85\x87\xac\xe3\xd1\xa3\xdc5\\\xa6I\xe3T\xef\xe6Y\x90\xa5\x0e\x0b\x1e\xc6c\xc6\x90;\xcf\xbe\xce\xfb\xd3:?_F3/Y\x9cSF\x7f\x9e\xc7\x94;?\xd7\x1c\xb9\x14\xbf\xf4\xf2\xf6\xdc\x16\xb5J\x93$\xa6\xa3<\x17\xc1\x1cl\xc5\x83\x0b\xa4\xb33Q\xa6\x0fJ\xde\xca<\xc4P\xbe\xdau\x99\xf4\x85\x7f-\xbf\xba\x82\xd7]N\xd9\x8dU\xe12\xfe\xa0s\xff\xe3\x9f\xce\xfc\xda\xc2i\xf9\n;\x8e0\x90\xc6\xfd\xa0\xe3\xac\xc1\xb1\xa61j\xf6\xb2X\xf9\xe6a\x16;\xa8]\xde\x89L\x18\xeb\xbb\x10\xb2\xdb\xc8\xe8\xc7')\xd7\x08\xf7\xfa&L8\xb8/uh\x12I\xc6\xd3\x07\x12B\xb42\x08\x0b\xd5\"\x89a\xebe\xe0\x93\xa6\x89\xdf\x08\xb9\xf4Bo\xccPH\xbb$-;\x14\xc1\xb6l\xba;\x8b\x04i\x1d\x8c\x1aE\xba\xebh\x8d\xa9\xda\x0bl\xc4k\x15.t:\xf9\x1c\xb9\xd0\xbb\x13\xbb\x15\x93\xf4\x974\xf8\x90\xc7\x13+T\xb6\xe3p:\xee7q\x9f\x87\x1cI\xee\x8b[\x1e\n\xa5t\xa5\x9b\xb1\x0f\xdf\x93Mw\xb2:\xad\x18q\xca\xae\xb9E\xc7\xa7\xd5n\xb7%\x0c\xe1at\xc6\xb4\xe1)^\xb3\x0f\xc7\x01\x9dm\x96\xe0~\x83}m\x1e\xed~\xe3hM\x18\x14\x8bT\xa5\x0e?P\x99n\x96\xdd\x95\xfb7\x12#3r\xb3\x1b\xa1\xa9\xb6;\xf2\xd5Q\x8clb\xb1\xac\xdb\x12\x80e\xcd\x96\x00\x17Q\xb4$^\xc8!\xa7\x94\x0d\xf0T\xae\x16\xb2\x9d\x94\xae \x93\xc8F\xf7\x90)\xb7_\x8c\xd2&\xc0\xb5\xb8$\x1b\xa8\xee\xbf\xdd.0\xd6\xf4-v\xa1f\x03\x16\xdd\xd0\xef\xbe\x101QO\xd3P\xd7\x80\x95\xbbe\x86\x1brv6\xcaoW\xf5\xef\xb7\xedv\x8f\xf6\x1c;\xb4\xf7v\x0f\x9c\xad\x8c\x90\xe63{_\x7f\x1f\xeaPw\x18\x0b\xed\xc3\x83\xc696,s^\x80q\xb3\xcc$\xd0zE\xe0!\xdd]F*\x0c\xb7\x02\xbci\xad\xbe/\xeaH\x04\xb5\xdc\xd5\xd4\x00\xfc\xaed\x84\xe1*\xc3\xda\xbe\xcb\x1f>\x8e\xc4\xf6\xc6\xe9\x14/lx\x86l\x17\nT\x85\xd0^\xfa\x94\xe0\xe4\xd3a\x14\xe0}\xe4Jp\n\xde8AQ\xdc\xa7\x82\xaa\xaf\x91\xc7\x01\xee\xa3Q<2\xdc\xa1P\xe2\xf8p\xbd\xeb\xd1\xde\xd6\xa8 \xc8l`\xa2\xf8\xfd\x928\xf4\xe8\x11\xa6*\x18\x0f\xa6\xec\xd6*\xfd\xde\x9b\xba\x0c\xd8\x9fR~\x96\xb7\xa5\x18\x8e\xa1z\x04J)Af<\xd4Ub<\xdcu\xd6\xfa\x87\xd5\xfbF\xe2:\xa1N\xe5\xd5W\xd5]\x83\xa69\x14wx<\xddd&H\x98\xf8]|e\xf8\x18\xba+`i3b=\xe5\xa3\x0d{\x0e\x96\xbc\xc1(M\x0b\x17f.\xac\xd9\xaep\xe1\xca@1\x91\xee\xca]\xbeAO\x8b\x99\x0b\x0b\x17\"\xb8\xe5w\x0c\xaf\xe8\xa6\xbc\xa9\x1fA\xcd\n\x8a\xb7\xee~\xfak\xbc\xad[]\x91\xeaA\x94Yy\xb6:\x8b\xdeC\xdel>L\x91\x8d\x85dZ\x96\xcb\xfd\x0f\xdea\xb91\xd1\xdf\xcd$\xc6\x07j\xeb\x9e\xa2\xa1>|P\xbf\xaf\xf7b\xea\xf7\xaaV4$\xd5\xbd\xc6 \x1f\x9b\x1e\xf04\xc4\x17D\xf4\xcbh\xae\xde\xd7\x04I8\n\x0d\xb5@.\x1dQF\xe7 &\xfa\x042\x16C\x9aO\xabW:\x13\x96\x11\xbd\xdd\x0e9\x06Q\xa8Z\xbd2\x0e\x10)z<\x13?\x85F1YH\xc9\xf7\x13\x8c\xcd\x8cX/\xc8\xee\x1e\xeb=\xd5\xf6zz\x83\xe8^\xbf\x8a\x12\xc8{\x95@H>\x17\x8e\xaa\x885\xe7\xf0*\".U\xb1\x00\xbdI\x84\xad\xeb\x99\x08\xa2WuOY\x94K\xc5\xdeM\xb5\xc4L.\xc18v\xb5\xc8\xd5\xfd5\xb0B>\xb9q\xe1\xd2\x85\x95\x0e\xfd)\x9a$\xdalT\x17\xf8\x84h\x9e\xbc\x83\x11\x9c\xc3),`\x08\x9e\xf6\xddk\x18\xc1E^BW\xc7\x19e\xf4\xb4\xa2wT\xacY\xc3)\xcc`\x08\xef\x1c\xfak\xa6\x16\x7fA\x8b\xd3Z\xaf\xe5\xe2\xd7\xa6\xe2\xcfD\xc5\xd7\xean~F\xf9\xb9\x8f\xd62u#\xe3&\xf5\xe5`Q\xad\xbe\xba\xd7\xcey\\\xe23\x0c\xd5\\\xb3\xbb\xf2\xf6Zgy\x85+T.\xae\x04;s\\8\xa7\x909S\xfc\x06\x9aU\x1bB\xc4\xa1\xefJ\x0f\xd4\xb1\xb5\xec\x10\x1ea\x90|=\x8dz\x0d#8Cer\x1e\xd9\xc8:?g\x89\x0eg\xe7\xe7\xa6\x0c\xd3_\xc0\x08^H\xaf\x91\xeakzj\x87\xf6\xbe/\xea\x0e\x83o)\x8e\xc3)\xa4,\x984*Vk2H\xbe\x84\x11|\x81Z\xd8\xa28\xd1\xcbD\xc6\xc9\xbe\xb4\xdf\xba\xf0R\xcc\xe3J=&n\"\x03\xb5pQm\xb5\xf6L]\xbe;3F\x95\xd3qc\xec\xb1\xfe\xd4\xb7{\xbc\xaf\xf5\x0b\xc9\xbe}\xbf\x90\xaa\x8c&;\x88`\x01o6\xb3\xd31\x99V'\x83~2\x89\xbey\xb3\x19\x06\xb5* \x94#2\xaf\x8eLq\xe0\x88\xca\xbe\x1a\x99v~\xab\x93\x1b\xde\xcf\xe2\xb3\x91D\xc4\x99i\xe8l\xc48\x7f\x9cbXs[f\xf3t\x8aM\x90\xa6&\x8c\x08m\x8acx\xac\x8fi\xac\xb8\x9ad\x06\xa9\x81\xbbE\x1d\xeb\xa5\x80\xbd^\x95\xdf\xfb*_\xa7\"\xc0@\xe5\xfe9\x8b\xfe\x1e\xd3\x15WytI\x1c\xf8\xc8K\x15G\xd5\x92$\x80a\xd7k%\x81O\xbd\xb5N\x0c\xc8\x9f\xbfB\xa5v\xb5\xc8\x8d\\\x849\xb6T\x8b\\\xcaE\xce\x88\"l\xacJ\xcfQ\x97^-r^*\x82\xca\xf4j\x91\x0bE\xee\xf9^6\x9f\xab\x1d~W\x996\xef\xa7\x02\xf2\xaeZ\xe8z\xe3@\x94g(\x17\x9c\xc25c\x0b\xaf\xe7\x1b\x07\xfe\x13\xb4:v\xe1\xda\x85\x17.<\xab\xa2~\xf2.\xc0\x08|Z\x1d\x96\xef%\x04\xde\x0d\x158p\x06\x98\xcayA[\xa3r\x9e\xd0\xdb[`\xcf_\xcf\xe7 I\x8b\xe7\xecw\xad\x00B?)\x06\x10\xbb\xc0 vy\xf4T\xf6K-\x8f\x1d\xbd\xd0w4\xb7|6\xf5\xb6\xf5\xc2\xa6\xc4=\xc0\xab\x1e\xec\x1bqtY\xbf\xb1\xb5\xa5\xda\x1a\xc2\xd7\x06\xf8Um\xef\"\xbb\x9d\xba\xd0\xd6i\x9d\xf1\xedE\xed\xdbi7\xf4V\x84\xe9/\xf1\x1b\x06jY\x91$\xf1.9\x98\xff0T\x7fc\xe8\xf4\xaa\xbeYfYR\x83\x88\xe6\xef\xcf\xf4\xef\x0bQ\xcd3\xbcvi~\xed\x0b\xe6.P\xcd\x1d&>\xb9Xf\xd3\xfa\x13\x0ch\x8d'\xbd\x96\xd0P\xa0\xb4\xfaE#\xf6 \xe9\xed\x19\xd74\x98\x9b{\x9b\xd7\xf5\x16\xe7\xc3 \xaf\xc1\xed\x08\xe6.<+\x0e\xa2\xe6\x86_b8\xc5\xd7\x88\x88\xaf\xd1T m\xe0Zy\xf0Y\xa1\xb1q\xe1\xa5az\xcf\xcd;\xba\x10\xe3\xcfD\xccJ:\xa83\x11M\xb6\xf4\xa2^v\xbc\xbb\x11\xdb\xe9\x16 3\xf5\x94\xed\xae.i\xdb\xca\x87<\xad\x0e\"\x8cA\xf5\xa5\x89\xb7\xaf v\x85\x15\x8e\xdbm2\x85\x11:\xf5\xa7\x95\xcbq\xce\xb7\xa11\xfbv\x86W;65\xa1@\xd3\xb0\x8cx\xb0\xd7\xd3i\xcc\xfa\xaa\x08\xf5@\xda\x03\x9ewO7\x89\xa8Q\x81G\x10\xa8\xf38gv[\xcd\x89\x123\xef\x19S\xa5.1m\x82M\x1c\xc9\xd2\xd4\xf2\x8d\xf4\xa8Hm\x00#X\x9e\xc0\xba\xc6\xe4\x81\xb9\xb9\xc7k\x83]\xa0e\xfb\xa8\xb1\xc0\xdc(C\xc9\xcbn\xe1lh\xe3\xa0m\xcc\xd03YG\x13i\x1b3\x96[\x88>\x96T\x0c3\x0d]\x14\xe6\x82V%Bg\"+\xea\xd8\x0f\x8dCO>+T4\xf4\xe9il\x0dO`i\x9c\x99K\xb4\xa7\x88\xf91\x98UV\xe8\xce\xb80L_\xe6\xe4\xfa$\x1fox\xae\xf0\xfc\xbb@,J\x11\x7f\x86\x90\xd9\xf4H\x8cP\x86^\x89\xc9\x8c,\x9b3\xce\xe1\x94\xf6p4b\xc7y\x8fW\xc2P\x13\xeb=7\x9b\x9cQE\xa3\xe7 \x171\xf1\xde*OT\x83\xf0\x0d2L\x94\xb2\xfd\xc2\xb7\x1d\xfdF\x16u\x14\x1f\x0dI\x88\xbf7\xa6\x89\xbf@!N\xaaU?\xf5\xefP\xba\x93\x8a\xa9\x03\xba\xa0\xfb\xe6\x1dm\xad\xdc\xc9\x80\xa7lS\xa0\x8c\xd3\xdb\x96\xd8\xf0r\xd8\xf5\x0b\xfa\xecBV{#D[\x16\xdb|'\x97}\xc7\xfc\xd0\xd9\xd4o\xc0\x12\x13\x99)\xe7?(\x82o\x99\x88P\xa6\x91\xfa\xeb\x0e{=}\x0c\xca\xbb\xfbN`\x10\xe1\xc8\x85\xe0\xce\xc7\xe2\xbd\x9e\xfe\xbe\xd0Qc\x97\xd4ZE\xcd\x11\x8b\xefnpHc\xaa\xc6\x08o`G.\x84\x1b\xdc\x0ehf\xb2\x1a\xbd\x816^=)\xc5\xa7\xcf5KR|\xfat\x1c@\x1bX\x8c\xfaqh\xf0>\xbf\xfbl\x9b\xf2\xae\xe8\x8c\x11\n\x0b]s\xe6\xf92y\x11f+\x96\xb0K\xd5R\xf0\xd7.I*\xf1[vfNT\xddEV\xca\x0c\xa4#\x15\xc2J#\xa9\xe5\xc6S\x18V\x0c\xfe.\xc46\xcb\x1b\x94\xd7\xa6\x0dO \xd5XD\xb8'\x1aMh5K\x0c\x0c!\xd0\xe3\xa4\xf7-#M}\x92\x83\x9e\xc8\xe9/c\x91\x9e\xe0f,\x0f\xbf\x86\x89a\x8cN\xf4\xe2D\xea\x15\x8d\x83v\x1b\x13\xc4o@\xc1\x9aB^7N\x84\x81\xb8\xdc\xfd\xa6\xe6\x9eAy\xdc?\xd4_B\xd4'\x0dQme<\x81X\xbf*\x82&\x06\x1b\x9a\xee.\xd7\xf6r\xa8\x8e\xc4\x85\"\xec\x84\xb2\x92\xe8D\x83\xa99\x02\xa3\x00\xca\x9e\xb7\xd0\x19$\xd3\x96ZWJ\xb5\x96(\xbci\xcb.P\x0e\xbe\xbd\x859\xfdoI\xff[\xab\xa5f\x98\xb3\xfc\x94\xb2\x8c\x1c}\x99\xae\x8d\xca0\xba\x9c\xa1r\xce-\xa3\x84\x87~)<\xbe}\xcb\xcf74\xbb\xeb\x8b\xf2\xb3m\xb1*\x90m\xdf\xb0.\"8BUS\x01\xb6\xd6^LB\x0e\xc0\xf7\xd7\xac S,I\x05\x0b\xd5P\x05\xf8Z\xaa\xd2a\xe2\xda\x8d\x0bW\x0e~\x9f1\x03\xf7\x8d\x9e/\xcd\xee\xbb\x8b6&'\"-\xac\xa0\x17\xe9\x89\x03\xb1\xc8\x8a\x12\xea{\x17\xdfy+\xeasS\xec\xe96\xa2\xce\xb6\xdc\xb4?\x0c\xb4#\xe0w\xbab\xae\xa3\xf8\xb6h\xd4\xdd\x15\x1a\xa6\xa4\x1d\xfd\xaa\xec\x16\xe9',\xc3d\x82\xc5\xf4d\xe3|\xfa>^F^\xba;\xe0\xb6w$\xe3\x95\x87\x07{\xfa\x87/\x85\x86E\xf7\xa4\x7f`|dj\xacP\xd9\xe8\x1f=_z\xab5\x99\x99K\x98\xda\xa4\xcfJ\x8db\xa6\xdc\xb1\x0e\x83*o\xea\xeb+\xe9\xeb+\xcfr\xf3G\x05^\xe8\xee\xd5\x07D\x01r\xfbGu58\xae(\x0f\xd0\x18R\x81 \x03H\x05,<(*`a\x0b\xa9\x80\xd1\xfeQ\x85q\x9bG\x05\xfcC\xe2\xbd\xcd\xfb\xd1\xea\xbb\xdbm\xc1\x88o\xc1 '\xf8\xf8\xb3\xd5\xca\xc6tW61\xf7\xc6\x1d\xd9\xec\xcf]#L\xa6fu\xe5F\xfb\xb8F\xf3Ul\xf1\xbeb\xf3\x03\xbe\xcf-6\xc3\xa5d_tr\x18\x1b#\xdd0\x9a\x9177k\x06S\xab\xc0tQx&U\xeba)\xca\xb1\x9e\xb4T\x8f\xc6\xb5\x80\xd2\x10vs\xb8\x98\xe0\x11\xaf\x1a-O>I4~\xba^\x1da\x14\x9f\xfa\xc4\xd3W\xb6+\\Q\x95\xfe\xb1\x98S\\\x8b\xb3\xfbG}'?Zn\xce\x15\xfa\x86\x03Z\x7f\xa3\x03\xdav\xb2eu\xe9P\xf7\x14\xcb \xe3U\x7fx\xa1=\x1eO\x0d\"YHE\xb2\"\x85\xbct\xc8\nq\xff\x97U1-\x9eF\x8e\xb9:\x98\xa4\x8fm\xeeU]\x19\xd2tm;\x19b\xa0<\xe5\xbfQ\xfd$\x99\xbbF\xa0W(\x11>\xc2\xdc\x92{{\xdb\x9cv\xa9\x06E\x8eD\x8e~\x0c0\xe0\xf2\xa1nu\xed\xa6\x99\xba\x9a=!\xf22uW\x1bR\x9b\xca\x92\xf7\xa2\xb1\xd2\x90\x07\x86\x84\xd0\x067\xd9\xbdA\xd5W\x92\xfbP\x0e\xaa'4\xeeC9\xa8\n]\x89^F\xe3N\x94\x8as\x06=t\xf9v\\\x81b0\x0e\xbb\x1axg\x8d\xd0\xa8\x02] 4\xab@g\x08\xad\xe6\xdf\xa3\x07#\x89 \xb2L'\x1a\xb1\x84\xee\xae+4[\xc7\xf8\xbf$\xe4\xd8}\x87\x1dJ\x82\xd2\xbb\xc8\xed\x8b\xd7\x02,\x12\x95\x8a|?\x8eVABD1J\xae\x93hyElV_V*\x8c\xc2FQ_\xc6\xceD\xa5\"\xb9\x90Q\x14\xf3\x9cB\x87\xda\xbcA\xf5\x87\xd2P\xe7c*.;\x96\xb6sM\xc69\xc4>8\x05\x9f\xa2\xba\x9a*\x93\xc7?\x10^\x12Z\xfb\x1e\xdaT\xe7\xb5\x96r\xcd\xca\xa9\xdc\xce\xe4V\xa0\xab\x07\xa7\xd3P\x85\xc6\x03AWE\xbe\xca\x86j\xea]\x0e\xca\xebo\xa8\xc2`\xfe\xafV\x91\xe3\x87\x81\x94\x80\x96MT\x92U_mGovw\x1d;\xb4\x0f\x1d\x17,\xb1&\xa6(5[\xdej\x94j\xe6S\xfc\xf0\x15\x9f\x91\xf4\xe1+\xe5\xcb\xf0@\x15\xf7\x8f\x0c\xa1\xd4\xb6\xb7D\xe4\x82\x87\xb8\xbf\xe7\xf2\xdb)B\xb5\x1e\xd6\x18E#\xaeeW\xb7>p\xa6\x91\x8e#\x9d\xba\x94\xa9Kx~\xb4\xd8\xce\x1cSX[\xd8\\\x8a\xa9\xb9B`\xba\x01\xa9\x0f_\xb57\xd0)\x0b(\xbb\xd4\xc5\xaf\xd2\xad\x86PhV\xcb3\xfewXe\x8bs\xd5\x04\xbf\xdc\xf0\n\xa1A\xc6\xc8\xf8\xe1\xd1c\x99A\x13\xdb\xc7\x95%\xcdW+\x85\x9e;\xd0\x05%\x90Z\x90L\xac\xec\xd4\x90\x07\x17\x89\xd8\x9bh \"\xb8\xc0s\xb8\x85\xe5\x03\xc92\xfd\xa3\x8dn\x83\x1bL[\xb8\xf0\xba@I,\x9d\xa7^|\x96\x86\x1a\xc0)\xa6\xc1mJ|k\xe8\xfe\xce\xf8\xf3\xeex2\x9d\xb6o'c\xfbthwN'\xb3\xb6}:\x9ct'\xb3\xb6s\xea\xdc\xdac\xeb\xf1\xd4\xb1\xe9\xb3\xd3\xd6d\xe0\x8c?\x9fL\xa6\xb7\x93I\xd7\xf9\xf0\xd4\x99\x0c\x9c\xc9\xf4\xd6>\x1d\xe1\x1b\xb7\x93\xf1d\xea\x14_o?p\x9cj^3:\xdc\x9d\xc9\xc4\x9eL\x9c\xd3\xea3\x81\xebGN\x83\x1b\x8a\xe9\xc8\x02\xc5\x0c\xed\x1d\xb0\x9b\xb8\x98N\xf6y4#\x98RV:\x98X\x16r\x14\x11\xfa,.O\x17s\xa2\x8cLGa^GLq\xab\x94C\xff\x83>f\xa2E\xe5y\xaa3A\xc9!%\x18D\x8f:\xd16\x8bH \x8a\xce\x89f\xbf\xf9\x1a\x99I\x06C\xec\xab_\x05\x90,y\"\xf8\x00W5\x84\"\xb4\xa2[\xf1\x14\x026 \n\x8c\x11x\xdf\xf3\x17\xfa\xb8\x07w\xa6\xb4{\xbb\xfa\x83\xc6\xdench\xc3\x1ab\x86\x1b\xb6\xc5\x8f\x92\xe2\x8eK\xdct\x00\xbc\xcf\x11\xad\xd4\")\x9d\xc8\xef:5}\xc35\xfc-mj\x8a\xedL\xd8\xd4\xf4,\xe8\xf0\xae~\x00\xb9X\xe0s\xcb\x07\xe5Q6)\x82\x009\xb9\x15j\xc9\xbcd\xa0\xdd\xf6\xe1 \xcck\xafg'6\x19\xfbS\xa3\xdf\xceR\x90g1\xf7\xd8\xbf5=k\xa1\xbf\x8d\xfa^\xca/s\x97\x1eh\xc5\x074\xac\xd1>\xb6F0\x87SX\xc2\x10Z-{\x0ef\x031g\xa1s\xfc\x9b\xd9k\x17\xe6\xdc\xbekKq\x13\xef\x8d\x87\x06$\xbc\xbb\x97\xc2\xae\xde'doW\xef\xbf\xa2\xca5\xd9\xa6\xc8c\xe8z\xc4\x9cD\x98G\x01\x06\xbcj\xde9w\x9e\xa7\xbc@\x9d\xc2Z,1)\x87\xa8\xaaz\x8c\xdeu\xca7\x91J\xee\xd3\xfd\xb8\x12\xb9\x0e\xee\xd3\xd9\xbd\xdd\xaa2T\xa8\x83\xf4\xa9\xb2\xf7vu\xc4\xe8S/]tW\xdeu\xd3\xb0\xcd\xc2\x98W\xb3\xf5TMA\xcb\xcb\xd5\xaa\x9d\x8aO\xde\x95\x88\x98\xc1+\x13I\xcb#\x93B4\xc9\x13\x9e'\xe8\x0d\xeeA\x1b\x12\x0c\xbc\xe62^\x1c\xd0\xf9\xdeu\\H\xee\x8f\xb6\xc2\x15V\xd1o\xe44V\xf6eb\xde(!\xb4\x01\x05\x9e>\x0c\xa1\xd3wN\xf06K\xd4\xe9\xc0\x10\xda\xed\x88%TW\x90\x85N\x13\xb1\xe9\x91\x0b\xbd\xca$Et\xa4\x9d\x86\xbb\xc7D\xdb\xdbm\xce\xc4_#\xec\x98d\x12\xf8 \xe8\xeb%\x12\xb1w\xe9\xd2\x12\xe8\xa0\x10N`\xd8\x18\xc2\xc1<\x82=\x9d\xa8\xd2\x87\x9d\xaa\"\x0b\xe3\xbbt\x0f\x8f\x0f\x0f\x8ew\xfb\xbb{G\x07\x83\xdd\xfe\xfe!\xd9\xed\x1dm;\x01\xb9\xaa\xfb\x94\xf9^1S\x01\x13\xe3\xa8\x04\x8b_;\x01{\xcc\xc2\xbeu\xe8\xfa\xf7\x1d\xf8\x10\x1d\xeeR\xb1SR:r\xfc7\x92!w\x9d\x0b%^3\xd7&\xe8\xb4\xc3\xaf\xbcW*-\xd8\xf9|\x92\xb4o'I\xfb\x83\xea)\x83Ex\x1ew\xda\xd3\xde\xf5\xb8\xd79\xf6:\xf3i\xfb\x83\x9d@\x15Vv>\xef]\x8c{}\xcdS\x9f=\x8d\xc6\xbd\xce\xa1\xe61\xe5\xe0k/N\xc8\xcb0\xddvI\xe8\x8e\x91\xa3\xbd #`\xbeqR\x95\x10\x05\xb6yc\xa1J\xd3p=\\\xe0\xbf\xd6\xc6\x91\xe6\xd7\xcfN\x8b\xef\xecJ\xb3^\xe8\x89\xd9\xc9\x9e\xdd\x10\xa2\x9b\xa1T\xea\xbd:J\x11\xe4\xae\xa5\x19e\x19\x8f\xda\x95&\xd9e\xb1r2j\x95\x00\x87,\xac6K\x14\xa3\xdd\xc4xN\xf3E\x118\x85\xb9\x9dv\x93e\xe0\x13{\x80j\xa7S\x18\xc0\x10\x8e\xe8\xa8=\xa9X\x84}\xba+r\xf7\x15uK\x03\xb7\xdb\xab\x8a\xd8\x99V \xe7\xa6\x8f\xbdf!\xc9\xcc\x01\x19\xf7a\xb2\x12\xe5W\x86iC)4\xaf\x86\xb2-\x8aGL\x8c\xa1VE\xf1\xfcc\xd3\x172.\xdaf\xf0\x04\"\xe6\xe8\xd4\xc7\xb8q\x81\xed\x8d\xb3)\xbbH\xe6\x9c\x98\xf5\xd1\xa6\xd8\xe7\xdb\xae\x84\x9eN\x18\x82\x0d\xa9\xea\x98L\x08T\x1b\xac\xa7\x86)\xe0\nd\xf2\nT\xef\x1f\x89\x83\x93\xf0\x8d\xd0\xd2\xdeV\xab$\xd5x\x18\x1b\x86\xb1\x8e\x08\xf7e\xae\xe0\x18\x96\xa2\xdfz\xb9\xbe+\xe4\xee\x9f\xe1\x98L\xb7\x8f\x99ne \xc1\xec8~*\x99/\xb9\xd3\x05\x0b\x97!\x9clx<\x18\x92|\x1a\xcd\xb2%\xb1\\\x85\xc1,32,E\x8es\\\xbcs\xbd\x8a\x82/\xc9\xec\xcc[\xad\x97\xe4\xe38Z\x9d\xf9\x0b\xb2\xf2`$=|\x1e\x13/%\x7f\xe3\xd3O^\\c1\x16J\x0d\xbf\xfe\x8d\xd5\xb2\xf2R\x10\xceI,\xfdN\xd4\x9a\xb9\xa1\x1bH\xd7Wk^\x9eh\xf0\xa9\xaf\xa4H \x90\xe7\x87\xf6\xde>=n*H\x85\x8f\x0ev\x9dM\xa3\xb1\xc8|\"\xed\x16\x13\xc9e9\x95\x1a\xcc\xc8\xdc\xcb\x96\xe9\xb0z\xab\xf4;\xea7\x81kj%\"\xf3Q\x8e\x04&\xaa\xcc\xbb'\x90L)\xf3^= \xb2\xa2\xe7d\xe5\x05\xcb-Z\xc8\x12\x12\x7f\x97\xb0\xd5\xe8\xfa\xd1j\xa3\xb6x\xbf\xceg^J:i\xb0\"\xd6\xe6-\xa2\xaf\xc5G^J\x9cn\x1a\xbd<{\xcd\xbc@m\x8d\x1dBs\xda\xc5\xcd\xb9y[\xbd\xcd+=\x9f/#/}\xe0\xaa\x830%\x97\x0f\xdea\x1eD{X#T\x88\x8fX\xe5<\xee\xb6t\x8c\xe9r\x94fQ1\xf8\x0f\xb5\xfd2\xba\xab\x07\xd0\xfaN\\\xe5\xfel#\xb0{.\xc4]\xe6`\x11\xcco\x1c\xadB\x03rC\x8b\x9a\x82H|\x02|>\x8f\xe2\x95g\x88\\EI\x827\xc6\xfc\x91\xe7\x16\xb4!\x98\xa2\x0b\x90\xf6\x12\x92\xc0K\xec]\x90|\x9c\x85\xbecGx\x82\xb2\xd1\x1ek\xfd |\x1bF\xefBxs\xb3&C\xa0\xf5\xa5\xd8\xbb\xba\xa9\xf1M\xc40\xa7J\xa9^u)\x0e\x85\x9e\xf0%\x17\x97\xb2\x9fB\x1f\x8a\x9c\x14\x94\xc9\xe7E\xc6\xfd)\x15\xde\xe4\x9f\x98\xc7\xca8{\xcaR\xe8\xe2\xc5\x81\xf0\xf9\xadY\n\xb4yw9\xfd\xd0\x17\xf1\xb0\x08\xbf\xc4\x17\x10\x8dg/\xf0\xf9\n\xba\xdel\x16\xd0\xc9\xf1\x96\xdfo(?\xc7\xf2AJV\x86\x02h\x14\xe9\x06\xa1\xbf\xccf\xe43\xe2\xcd^\x87\xcb\x1b}\xd1\xb5\\\xf4\x87q\x90\x12ZV/\xe8I\xd3\x9f9e\xdc\x99\x11\xb2^\xdePz\xb6\xfe\xeb\xe4\xc6\xc1#\xff\x07\x1f\xc4dnma\xa5\x94\xe5\x8a\x92ou7\x08g\xe4\xfa\xf5\xdc\xb6\xfe\x8aU\xc9\xcc >\xefM\x16\xa2H\xef\x7f\x1c\xb0\xe0\xb7\x91\xe4\x1a\xae\x176kb\xec\x82hc.f\xc3 \xaf\x8a\xdb6^\x1c{7*\x97\x01\xedy\x01U0\x85\xb7\xf9\xc8l\xed\xbe\xe2\xc1\x06\x14\xcc\xae\xba1\xca\x9fY\xe56\x8b\xfc\xc9E\xf5+*\xd8-\x1cX\x8c\xaf\xa6t%\xe8\xdf\xee\x8c\xacc\xe2{)\x99\xe1\x8d/\xf9Q\xccq\x0d\xd8\x05\xb6\xea\xe3w\x02\xbf\xf0\xf9\x1a\xef\xb9\xcfh\x81\x11\xa46-A\x85B\x83\xd0\x8f\x13\xcd\xb4N\xbe\x03\xb3\xcav\xe9\xd7\x8c\x06W\x90\xbe\xee\xebQ\x01\xaa\x11\x0c\x94y\xf4\x1d\x97\xc5,\xb0o\\\x8c\xb2\xb6\x82\x11\xf4O`\x05O`\xef\x04V\xed\xb6\x03\xb3\xb1U\xee\x12\xa5\x95+:\xb4K}\xb78\xd2\xcfTT6\x91i\x8e?\x0c\x19\xe0\x94\xa7\xb2 \x12v\xbdl\xde\xf5\xc2\x9b\xd7s\xd4\x92\xb1\xaf\xdd\x95\xb7.<5\x9a\xee\xe6\xb2\xf8\xf3:\x9f\x08\x18*ME!\x11M\xe1\xd7\x07lj\x9c\xdas\xfa\x94\xd2q\xd2%a\xb6\xc2\x10\x8c\x82c\xcb\xdf\x87|\xa9B\xca\x0e\x97\xc1\x97\x04\xbb\xe7\xd8\xec5g\xdc\xa3uX\xf3`IX\x8a\x8d\x08\x1d\x9b\xd0\xa5I\x17/_U\x12\xdbU\x19\xbf\x9e\x96\x89\xe1u\x13V\xfe\xd1#\xa6\xb6\x17\x00\xf4h)\xb8\x01{\x8e\x1cF\"C\x8aO\xc6{\xd7x\x04\xd9\x88\xa1\xb2K\xcb\xdf\x1aO\x8d\xb6\xe1\xa9x\xff\xa5\x86\xa7z\xf8|\x13\x86\x19m\xc90\xa3&\x86\x19\xd5\xb3\xf25c\xba\x9b\xf0\xd4\x85\\4\xe7\xa9\xfa\xb23l\x99#\xb4\xbe\xc8\x15\xd26\xfd\xb3\x9b\x9ag\x97(\x86]\xaf\x96\xfa\xc7\x94\x86]b|2\xfd\xf3s|\xbe\x8e\xc9<\xb8\xd6\x97\xb8\xc8kH\xd6\x9eo\xa8\xe6\x1d\x9b\xda0[\xe9\x9f_\xe7\x87d\x03\x03\xcfj\x188\x9a\x07\x1c\x96\xda\xfc\xc7\xc1\xc5\xb3&.\x8e\xd1Y1l\x8c\x15F\xa9wI'\xc7b\xfe\xb1\xf69\x9c\xc29\x15\xcb\x87\x16\xba\xb6;\x94A\xb8p\xc1\xf4\xf37c\xfa\xdc\xba^-\xc3\x043e\x9f\xd3B\xf8\x13o\x03^\x18\x04\x1c\x99)\xa0[\xe5\xdcD|i\xe99\xc5\x07J8\xf0\xef\xed-\\\xd2\xff\xbez\xef2\x08\x0f\\'\xff\xa0e\x18\x96\xc0e\x97\xc7\xe0\xcd\x85\xbf+\xee\x95;u+\x1cbIy\xc3R\x8dZe\xe4\x0c\xf43\x17;\x90\xe5\xa4\xa2\x953?>\xe4\x08U\xfd\xbe\xf8h\xf8\xd3\x8c\xb6>\xdb\xbau\xc1V\xb6n]L\x03/9u\x01%\x9c\xa2\ns\xab\xe7^\x9a\xc6C\xb81T\xee\xc2\x95\x1e\x1b)e?3\xb8XB\xc1\x8a4\xabb\xdfsY\xce6\x9a\x15\x17\xce\x0c\xebb\xdfsa\xb6j\x9f\x97R\nm nk\xd3\x12\x01\x9f\xfa\x17zq\xbbA\x9c~F\xc5ii\xcf\xd0\x9d\xb8\x14\x1b\xf0\x85Y:\xa5}{Q\xb9jh?ct\xa3\xf5b\xfcL\x12\xbcooa-?(Dn*\x8c\x1b\xa6\xab\xd4\x0e}\x8b\x11\x89\xfc\xab\xe8!\xff\xdd\xa58\x1b\\di\xed\xb2\x89\xcf\x15\x8f.YF\x05\xac\x0b\xa54\xda\xd9\xfc\x971\x05K\xf5\xf3\x85\xe8_-\xd3\xae~\xde\x8a\xb78F\x99)\xbd\xf8\xdc\x8c\xf3Q\x0br\xf8l\x9a\xb3,\x14\x9b\xbe\xa0#\xf8\x82>\x91\x80\xcb\xf13<\xf7\xe0\xdf\xf2\xa3\xb7\x14\xfe\x96\x0214f\x82sQ\xbf0\xb5\xa9^\xe4O\xb9\xb3#P;\xef\xca\xce\xe9\xf2\x0cV\x84A1\x00\xbbT\x86\xc1Mv\x19\xe9s\xc5\xe3f\xa6lt\xcd/\x94\xd1\xe3%\xa5\x14|\xa7 \x19\xf5\xa3\xd0\xf7R\n\x1fJt\xf5e\xc3\xb4\xd5\x91Fq\x98\xe4\x0d5\x11\xea\xb2\xb49\x04\xebYx\x93.\x82\xf0\x12|/\x84\x0b\x02\x0b\x12\x13\x83T@;\xedo\xca\x11\xaa\x0d%\xa6s+%r\x0f\xc8g6\xa0\x91|\xe6\xae\xcb\xf8\xbf\xe4\xae\xb1\x12h\xc63&\x94\x17\xf5\x1d]\xd4w\xecT\x96\xb0\x80kl\x85o\xe0\x14\xc6\xfa\xbe\x1b\xfb\xfd\xde\x85kZ\xd1u\xb5\xeb\xef\xb5v\x90\xa5\xd9\x17\x81\xca;\xeci\x19K\xd1\x08Z\xd2s\x05\x82n8vX\xb5:\x01\x1aJ\xfc\xa5\x17{\xb4\xc1!\xb44\xd7\x1b\x83pF\xc2t\x08\xd6$\xad\xdc\xae\xab\x9a\xcb\x00o1\xd4X\xa5h\x7f\xa2\xa2?\xcb&\x13W\xa5<\xc7\xa9\x06\xab\\\x0d\x87\x96<\x05\xf6\xabn1PxK\xec\x0f\x9c\xeeY\x1a\x13O#\xfe\xa3N\x8c~\xb1\xa4\x15\x83\x8a\xf5Jo\xf5\x04\x919\x80\xd24\xcd\xc9\x01=\x05\xd0\xa5\x11\xc7\x1e0\xd1!\xbf\x92k\xb3\xf7\x9c\xee\x17Q\x10\xda\xe8KgYU\xdb\x9a\xf8$\x94\x8c\x19\x84oC4\x08\x1b\xbdD\xd3\xb1\x142\xe0-\xb9I\xec\xd4\x19\xf7\xa6SdyI\xf7\x9c,\xc9\xaa0\xdbr\x80\xa0\xdc\x91\x9bC\x02?\xcaB*\xfd\x84\x12\x0c1\x89\x0d\xab\x0c\xa3-{20%q\x9c\xadS\xcc\x00'\xc0\xfa\x19\xf3\x99\xd3\xbe.4\x14\xf0S2\x957\x95\x87\xf9z\xad\xcd:\xde\xf24l-\x02\"y\xab\xf5m\xa8~r3g\x1b\x1e\x8f\xac\xc7\xd0f\x0epmxl=6\xbe\xf8\x1e\xbd\xa6\xc7dj\x14,7 \x93\xe2z2\xc7\x08%\x94\xad\xf8\xe0\xa5\\\x81B\xfa\xbb\xb9Pv\xc6\x18\xd1\xca\x0c\xf7\x1a\xc4'\xe9\"\xcd\xa48\xb6\xb6\xf9\x0f\x0cty\xee\xcf\xbc\x14\x95RK6\x9d\xb6\xf5\xa45~\xfe\xd1\xb37\xcf\xc6\xf4\xc0)J8\xb9\xe3\xde\xced:\x99>\xdd\xb9t\xc1\x9aN\xa7\xd3\xa7y\xf1\xa7xx\xb5\xa6\xd3\xa7\x16V\xcdW\x13Q\xdf\xe7\xa1k\x96\xd2=\xaed\xc3\xf8\xc5\xf2G\xbb\xb7N\xc1\xc2\x01!T\xd9YpJ1\x90\x0f\x19\x86\xa2\x0b9\x15\x816\xf4\xf1r\x81\xbdd\x89\xb5]T%\xb5zyo\xd1\x13\xd3,T\xbc\xc77no\xa5\xc1\xd5\x8865\x0b%L\xea\xc6w\xf3\xfe$\x9a\xee\x189\xb3~F)E\x19B\xa4\xdf\xd49}\x18\xd2U\xd3\x16\xc9\xc5\xfdd\x08s\x83F.\nS\xe4l\x06e\x13#aC\x08M\x9d@\xca5\x04\xaf\xeey\xd5e\x15\x94\xa9xo\xe0#^\x1d\x1f)\x11\xf2\xc2HL$\x97&\x8a\xcf\xba\x08\xf1\x82 \x12\x89\xcc2\x0f|\x0c\x9fK\xa7$\xbf\x9d`\xa6\x9a\x81\xd14\xce\xd3X*\x95\xd5\xed\x1d\xe1$W\xbc\x94,\x82yZ\x0d\xa8#\x7f*\xc6=\xadKX\xb5|d\x07N\xb3\xc2\x8c~p\xf25gp\xf1\xd1K\xe9z([\n;F\xed\xf5)\xce;\xe3yB\xa1f\xf3\x94\x0b\xa7`=\xd9\xa1T\x8d\xffn\x83\xf5\xd4\x92Kq\x06\xfa\xe8\x11\xb4BZz\x12\xf2\xc7\xe8W\x8c\x17\xc9t\x1b\xcf\xbc\x8aQ\xa3\xd9\xa3\xd5\x92\xf1\x04\x9dr\x8b\xdf]o\xbd&\xe1\x8c\x8a\x0d\xae\x8cO]\x06\x0cJ@\x11\x1d\xccn\xf5\x1c\x17Z\xbdMH\x04]4\x8e\xc9\xf9\xac\x95\xe7K\x9a.i\xa2\x8a\xdd/,\x07\xa7`\x01++=CI\xca\x02\xcb)\xde\x8dq\x85D\xf5|\xfaqo\x08\xd8\x8eiM\xc4\x02\x97\x96\xa5\x15W\xb7\xa4xC.\xa8\"#\xae\x0c\xde\xbd3]\x87\x82\x1a\xa7;-\xcd\xd0\xd0\x0bD\x1a\xf4H6\xa8_9\x0d\x0b\xd5\xb52Q\x16\xf41\xc5\x08\x00\xdd\x04eh8e\x99Px\xaax\xb3\xb5\xc3\xb2\xcc\"\x9c\x89\xcc\x0bW\x00>\xa3\xfc|,A\"\xda\xac\xf894\xb6\xb1\xe0q\xe4\xcd[ef\xe6\xfe\x0b\x863\xe4:}\x13\xf8o\x99\x13J\xba\xe5N\xbc\xaa\x95\x0f+\xc4\x0e\xf5\x1e\xf6\x1c\xda#\x96\x8c\x12\xf2\xd8\xab(\xc9 \xb7\xc79\xe7\xd7V{\xa2\xd0\xb2\x89\x08\xe3\xc1\xd2L\x1agv\xa3g\x94\xf8\xf8]\xb2\nR\xdb\xa2\xd2\x99\xa5\xb5\x9c\x8a\x0f\x15P\xd8\xfaoHT\xeb\xe6\xf1\xa6v\x1e=\xfb\x8a'\xa0[\xbb\x98\"\x91\xb2\xbd\x9e\xa3\x0f\xed\\\xd3\xca\xa5q\xf8\xccf\xdf0\xcb\xe9\xb75\xcb)\x95\xf58\x88\x843\x0b\x7f\xc6\xc4\x9by\x17x\x00\xa7\x04H<\xf7\x97QB\x0c\x91\xee@\x7fl\x00\xc3rT!\xc2M\xa0y\x1c\x0b5=$p\x94\x08\xbb\x92j\x02q\x1b\x8f\xee2\xd4\xc5s\xae\xbe\xe6+\x12'\xa8\xd3\xb0\xfa\xdd\x9ea\xd7\x93\xd0\x8ff\xe8\xe1\x19w\xc5wFr)\xbd\xfa^\x8a\xd9\xd4%K\xb2b*\x85\x02\xf6\"\x87\xd5b\x9f\xd8\x87\xfa\xe1\xa2\xc2a\x08\x99\xcd\xb4\x81E\xecD\xbc\xc8\xc5\x82\x15\xe6\xbe\x06&%\x0c=\x0dm\xe2\xf5 \xc2\x9a\xcb\xf2@\xa2L\xe5@\xba\x88\xa3wH\xc61(\xacm\x85Q\n^\x92\x04\x97!\x99A\x1a\x81\x07,\x14uK'?\x88\xcf\x95\x94\xaa\xbb\xde\xdePdG\x96\x143\xe6\x8a=[\xea-'\xaa\xa1[\xaa\x81\xa9\x80\xdaT\xc0\x10\x94V\x0e\xbc\xdfD\xdb\x08\xaf\xdc\xd6\xc9\x8a\xe2c\xa2R\x86#\x1f\xa5y\x9b.\x89\xc4p\xd9\xee\xa1Ccv<\x91\x01\x9a\xca\xb9\xe2 \xed\xe9\xc6$S\x9dW!$\x96\x91=\xffU\x8a\x1a\xba\xbbg\x88\x18*\x0fG\xb0\xf3\xf2\x00\xadG\xd6\x10\xacG\xdej}R!\x8a\x8f\xad\xc7\xf4\xc9\xcffQZ}d=f/\xad\xa3Dy\xf4\x04\x1f-\xd5w\x9e\xe2\x83\xcb\xf4\xa4\xa0\xa3\xd2\xb0\xb7\xbal\xc5\x89\x17\xa7lH\xbcru\x8f=~d=y\xfax\xea\xec\\\xd6LF\xa5\xc2pL\xaaI\xb4`\xb8m(\x8a\xd2%\xba\x93\xd2\xbc\xf3[\x11\xfd}\xa7\xfb\xe2\x8a\x84\xe9\x8bU\x90\xa6$\xd6)\xf9\xd5\x83t\xccc\xa1.\x02\xe5Z>\xfd\x84\xf6\xee\xbec\x07.&\xd3\x0d\xba\x9f\x15\x14\x93\xb6x\x80\xc0\x1f\xc6A\x9a\x03\xf7\xf6\x8f\x11\xf8Q\xb6^\x92k\x06:\xe8!\xe8M\xec\x85\xc9<\x8aW\x1c\xdaG\xe8\xf7\xbd$y\xb3\x88\xa3\xecr\xc1\xe1\x03\x843\x9d8;\xd8\x05r\xc2\x8f\x00\x9d\xc1j'\xffJ\xca#o\xd2\x9c\x07\xfa\xd3h\x8a\x06a\x1c\x0e\xbb0\xc5X\x0dZ\x89\xe9\x1b\x18\x1bh\xede \x91\xbe*\xc7&}\x93\x91\x96\n\x85\x05\x1f\xc2\x1ac\x92d\xab\xd2\xf7\xdaSY\xd8\x8d\xc2\\$\x0b\xd0\x81\x0e\x01\xb1\x17\x84\x96\x0b\x11B\xce\x83\xe4,\x9d\x05\x11\x957\xe4\x81\x11$*\xb7\xb7`\xb3j\xa8\x18\xe7\x82\x87\x02\x11\xfd\xcd\xc46\x17\x92\xaa\x16\xef\x8a\x874k\xf5M\xf3\xebi\x07\x9bac\x19\xe7\xb8)\xa3c\x9b\xcd^\xb2A\x85\x86{\xe03\x92\xa4qt\xc366\xff\xb1i\xb3\xbe\x9en\xa3\xaf\x90\xed\xb8\xdcN\x1cw\x97A\x92\x92\x90\xc4\xcf)\x1f\xc2\xfd\xe4\x82E(3\xb5\x1c\xc1_\xab\xf4V\xdf\xe2\xdc\x88&\xab\xe8\x8a|\xc2\xdb\xa9\xac\xb9\xf2PZ\x7f\xf5Uy\x9d\xab\xcf\x8a5\xd7\xbe\x89#\xa2\xc2\x92\xaeU\xf9\xa9\xa9\xd5ym\xabsm\xbd\xc5\xd3\x9a\x9d \xc8-\xc3\xe4R?\xab\x10\x19\xdb\xe7\n\xb6\xcf\xf3w\xca\x10v\x94\xa1\x04\xc8b^\xceM4\xdca\x8ec5d]\x7f\xab\xaf\xa0\xeaG=\xa7\xcb\xc2\xe3\x96\x19\x9e0\x1e6\x86\xc8\xa9\xa2R\x8ee\xa9\x16\xcbZ\xcd\\\x0d\x84\x00i\xa7 %\x19#\x8e,E\xbe\xb9Y\x13.I>\xf7B*LR6\x03\x1e\xf8K/I\xc0K\xc0\xcb[\xd2\x1c\x0b\xdf\xf3\x0d\x94\xcb>\x0b\xe2\xcd\x80E\xa3\xe1\x90\xd4\x0b\x96e\x08?\x0e\x8c\xaa^\xcb:$I\xd5\x8c\xe6\xf5r\x9a\x10m\xf5\xf3A\xb7\xa21S~H\xaeS\xa6\x8eR\xc7\xa9\x8af\xf2P\x9eb\xc0\x92|\xb8\xa8\xf5\xc1\xdb\xc0\xc3\xd2\xac\x90\xf2\x94\x10\x17\xdam\xa9\x9a\xf2l\xb8\xa5\xb1g!\xea\xbe\xbf\xfd\xe1\xe7\xfd\xddd\x0ex\xec\x0ci&\xd0\x11\\\x1ec\x051\xb6\x19\xb32b\x13}\xe7\xe2xQk\xddy5\x15'\x1a\xda\xa3.\x9d\x91Z\xbf\xc3\xbe2\xc4\xd3\xd2\x80\xaa8^Y\xf2\xa2%:\xbd.t:RU\xda\x98\x85u3\x82\xb1\x0e\x9bf\xa4\xaew\x0d;\xb0\xdc\xda\x17Q\x106\"\x1c\x9b\xffQu\xfe\xc5E\x0f\x8d\x17s)\xean\xdeY\xe6Zl1m<\xae\nO\xcdM\xe7\xed\xc4\x81\x10\xda#4\x81\x13\xc3\x9a \xaeR;\x7f\xe8{u\xcf1\xc5]o\xb9\x8c|\xbbg\xf0cV0\xa6\xd0\xf57\xa0]13xj\x0eXl\x08\xde\xde\x0f\xc2\xc4\x9b\x13;\x85\xa7O\x9f\xa2v2+O\x9fG\x97\xf3\x04\xb2\x13\x07'.\xc36\xd8\xacF\xfc\xe2\x04^\xde\x8e\xd67,\xb0\x01}\xa5-\n\x96\xa2\x18dl\xd2MS\x1c)S\x9c\x03\xdeSI\x0b\x03s\x06\xdd L\xd6\xc4OK?\xba~\x96\xa4\xd1\x8a\x91\x89\\9\x93/\xd0\xb8ZpZ\x87\xecb7\xe7/i\xd4jlXC0\x92\x1c}\xb8\x1e,.\x05z\xcfMo\xec\xe2h1^\xe3\x89{c\x7f$\x1d\xfb.sw\xbd\xddF+\x90\x88\x0fS\x1cu\x13\x92\xbe\\\xad\xc8,\xf0\xcc\x1e\xae\xdc>\xc3|\x8cx\xcab5&\xb3\xfc\xf1k\xaej\x007\xdb\x98L3\xc0M7iw\x16\xf9\xa8(3\x97[\x97\x12B~_ \xc9k\xcc*\xa7}`\xcc\xa7N\xab\xc2\x8clk:'o\x82\x15\x89\xb2\x14NaM\xc9\xb5[D\x8c\xe7yk\xa6\xccq\xfa\xab\xf7\xdd4bW\xdb\xf9\xe9[$\xb6aQ\x8b\x9a\xe8\x88\xf8Hf\xa0Z\xca-\x7ff\xb6&\xaa\xaf\xf8\x98\xf4[0\x94Q\xa7\xae \xb4\xa1v\xd7Q\x92~\xca\xb3\xf9\xb3\xac?\xc1\x8an\xc93?\x0e\xd6\xa9\xd1\xddG|\x04\x11\xd79\x08V?x\xcc\xefF\xe1\x8a5Woh\xcf\x85\xbf\xbc|\x13\xd3\xab~\x88\xde\x84 \x7f\x18o(f\xc0\xb6,\x17\xac\x0f-~\xa8(\x1a\x0e\xab\xa1\x94K\xb5\xe8W\xc2vP!\xc5\xab~\xbe\xf0\xc2\x90,\xe1\x14l\x1b\xa3\xa7\x90wP~\xe4t\xe9\xbc\xf7\xf5\x03\xaeE\xae\x99\x9d\"\x057\xa9<\xb7\xc0\xd3\x08;1(M\x8a\x01\x0bQ5\x86\xc6E+\nc\xe2\xcdn\x92\xd4K\x89\xbf\xf0\xc2K\x82i\x92\x97\xa3\xddvD\xbe\x8b\xe2\x0e.Z\x06\x0d\x97\xbd@r\xfb\xaa\xdf\x85\x94\x1f_x\xfe[\xe3qV|\xbc\xf82\xd1\xf9\xdb\x89\x8f\xe1\xae=\x14l\xc8\x1f'S\xa6\xdf\x8e\xed\xc4q!i\xb7M\x08\xb7fG4y\xed\x16J\xd9:\x1f\x82\x85y\x89Yzw\xf0\xab\x81\x9b\xa1\xa1\xca\x1a\x1f\x15T\x8e::\"\xa1\x9f\x94\x86\xbb;\x02[h\x17\xeb}\xf4\x1a}\x9e\xe7\xdc\xf5\xa6\xaeL}\x9a@\xf1im\xb8{\xe4O~:\xed\n4k\x16p\xc4'\xc6\xf7(\xd6\xd5\xf7^|\xf2\x14P\x0d\xba\x0b\xdd\x07\xfd\xae{f\xdf[\xdd\x87\xd4\xf9O\xea>\x0d^\xda\xd5\x0f\xf6\xa9\xbfm\x9f\xe2qo\x93\xbbU\xf2\xe7.\xfd\x1a\xdc\xa5_.\xc4\xe3\xfe\x8f\xa3w\xbbw\xef\x1d\xfd\x7f\xf0-\xf7\xb1\xd1\xd5[\xf7A{\xfd\x12U\x0e\x1aw\x0f\xddG/Q\x97J\x98\x84\xa3\xbc\x00\xcc\x83\xd0[.7\xa1\x0f\xccp?\xdf\xe0\xbc`|\xba\xa9\xdfoE\xb7g[Y\xc8\x02\x02\xcedY(!\xcby\x11\xa9?\x0fN\xbc\x08\x12\x0c\x83=\xc4\x02\x92\x0d\xb8\x949\x14y\xb1\xd9\x15`\xf3[Q9\xfb0\x90M3\xf1E\xdd\x03\xe9.#\xdf[\x9e\xa5Q\xec]\x12)\xa2\xa3:)r\xfeTm\x855\xef*\x10aQ.\xb7\xaf\xe5GBa\xc8sn\xa07\x99\x95\xc6\x19a\x87\x7f\x1e\xd2.t\xbai\xf4I\xf4\x8e\xc4\xcf=\x8d\x01Y\xfe\xb5q\xf0R\x10wal+\x8c>\xe2A\x88\xd0\xc0b\x8a\xbd\x0d\x92\xb1\xa9\x1a\x15\x13\x8a\xb14\x9eapm\xb4ai\xe5\x12\xa1m\xa1\x85\xa8\xd2\xb5\xaa\xef\x91\xee\x1e\x81\xf8\xd0*b\xcf'\xa5*\xe0\x14\xfc(L\xa2%\xe9\xe2C\x16\xc0F\x80\xdeyq\x88g%\x1c\xa4\x1aD\x0f\x8c;-W\x170R\x93\xa2I\xaap\xc4j\xda\x87\xc6\xad\xb4\xd1\x1e\xd2+\xe2J\x19\x96\n\xb0\xe4\x06r\xac\xcb\xa3\x14\xda\xfb}\xed\xad\xcfH\xdd\x1e\xdc\xb6G\xe9\x82d\xde\x8b\n\x1c\xa2+\x15\xa9\x01\xc9\x0bG\x12MpS\xac\xb8\x1b\x84\x0b\x12\x07\xd8yt,q%\x98\x1d1'\x93H\xd2\xab\x9f\xa7\x92\xcbH\xddd\x01\xa2\x06\xb7DT\xdb\xde\xc2\xb3\x86.\xcf\xe1F\xcbS~k\xd0\xbf\xc3K\xfd\xfe\x81S8\xc5\xdc\xf1}\xc9}f\x93\x1a\x9a\xec\xcd\xfdc}\x16\xc4\xfe\xb1>\xcf\xcd\xdeAs\xac\xf6\xeaBqK\x04\x0bH-\xc7P\xd2\xeb\xcc\xb3\"zU\x8c\x97R\xd1*g\x13)\x8a5\xe6\xd6\xcb\n\xebWau\xe8z\xc9M\xe8\xf3\xe4\xadYw\x1d\x07\xab \x0d\xae\x08\x9c\xe6.0pZn\x02\x87u\xbc\xef`6\x0c\x1e\x03\xca\xd6\x948pl\x82w\xe5*\xcf\xa4zi\xb1C\x07S\x0e\xc8\xc0\xfd^\x9f\x01\xe9\xd7\x01V\x93w\x15\xfd~\xec\xfd\xde.\x82\xd6,!\xa7\x00\xee!p\x16$\xeb(\x07\xf6\xd1f\xd3]y\xd7\xcf.sX_\xc0\x04\x80\xbd\x19\x939\xba\xa7\x90X\xc0\x0f\xe8\x8e\xa3\x88\x92m\xb9k\x9a\x10i\xef@\x17\xb9\x1du>\xdeE\xa2\xa2\x12>\x99/#9\x97\xf5f\xe8\xc4\xd1$H^y\xafl\x8c\xfb\xcf\xd2x \x96\xa40\x82W\x18\xc3\x153H\x0d\xd8\x9e\x92\x07\xc6\xcb\xc9l\xfd\xe4\xe8\x02\xd9]\xb1 v\x89\x0b~y\x81\x03L\x9dBe\x1f\xbb\xc8?_&\xb9\x8eDv\x04\xb9\xd1\xb8\x83\xbf^\xd3\xc6\x13x\x8c\xa5\x1f\x83\x17\xce\xe01/\xfe\x18|\xe6\xe2sA K\xd0]\xfc\x92\xa4\x0b\x12W\xb5\xe5|\x19\xcbazr\xd1\xc8:?\x17\xd1\x19\xce\xcf-\x16\xaf>\xec\xce\xa3\x18\x9dp \x0cYf)\xcf.B\xe3\x93\xfc[X\x0c#\xe24\x9f]\x0c\xcbh\xd5 s\xd7\n\xa8\x8c\xd1(A\x87c\x82q]R\x1e\xa8\xddW\xee\x13\xb1T\xce\xe7\xe7\xeb8\x9a\x07K\x12\x9f\x9f\x03\x8f\x14^@0$\xa6\xdf\xcd\xd63/%/\xc2+\xbcJ\x9d\x87\x9fx\x90\xbd\xd3\x88\x93\xbb\xba\\\xbcBU+\x89Y\x17A8S\xb1TS\x90.\x95\x8a\xb6r\xe2\xff\xd2\xc3\xa4x(y[\xf1u\x7f\x99\xbc\x08\xb3\x15\x89\xbd\x8b%i\xa2\x07\x9b%j\xd0\xde\x84\xa2\x934g7\xd3\n\xbc\x1f\x18\xe27\xacK\xa5vk\x0ew\xc5n\n\xec\x90\xa58\xf3\xf9q\xdf\xb3)\xae\xa1Ux\xdeM\xa28\xb5\xb5\x04v\x8d\xa9W\x11\xf9\xd7\xb8\xdc\xc3\"\xfbL\x83\xc6}>N\xa7\xc8\xcf\x99\xc4\xed\xd2\x01\xca\x93e<\x88\xf1\xde'\xecE\x96R\xf8T\xd4\xe3\xbb\xb0t!\x1c\xa7S\x17R\x91gD{\xa3\xdctX}\x10\\\xde;\xacRR!\x81\xea\xf3E\x1c\xe9\xd3E\xec\x1d\xf5\x9d\xee\x8a\xa4\x8bh\x96\xe8(\xed\x9e\xf2\x1eg\xd6\xc7\xba\x04\xd3\x9a\xbd\x80g\xc2r\xc9\xf9\xa6\xbbfYl\x0cff,?\x96\x1c\x14J\x89\x1d\x94\xf0\x9d\x0b\x94\x81\xa3J\xcc\x80\x19B\xc9*hL\xdd\xa5?H\xa1o\xb7\x0bW.\xdc\xb8p\xe9\xc2\xca\x85s\x17.\\x\xe7\xc2\xb5\x0bg.\xbcp\xe1\x99\x0b\xaf]\xf8\xc2\x85\xb7.\x86\xb1Z\xe2\xe9KO\xf0\xaf\x98T\xdc\xe2\x020%\xe5\x9cw\xe7\xbai\xc6\xabS\x89\x9eK25\xc5\xfb3\xcct*\x831\xb8\xd3\x08\xce\xba\x97$e\xd1\x87\xcf\xba \xfd\xba\xc2\xaf\xcc\xac\xe1b\x94\xce3f>q\xdcB+\xd3\x8dI\x12-\xafH\xcc\x82\xcc\xbe\xe5\x9c%\x87\xd2=\xfd\x05\x8f\xbc\x144\x04a\xe1\xfc\x97\xfbU\xe5\x04D\xa5\x1e\x94\x1fcp3\xb4\xd6\xbf\xb5#\xa7\xe8\xd2\x88\xf1\xe8\x1b\n\xa4Et\\\xf2%]\xad\xfc\x1c\xfe\x82\x16\xcb\xb8W\xf2%I-\xdc\xb4\x11\xf3\xc5s\\x\xa9\x8dhO\xfb\xc0\xd2\xf2a\x94\xe4\xc2\xfbp\x9e\x93\x13v\x86\x8f\xc6\xbd)\xeaQ\xaap\xd1\xe7\x11\xcb}c\xd6\x08iF&D\x8b\xd8\xb6\x9e\x07\xb1\x9f-\xbd\x18\x82\xf0*\xe2\xaa\x1c\x17\xac\xe7/?{\xfe\x83O\x9e}v\xfe\xf2\xd5O\xbd~\xfe\xec\xcd\xcb\xd7\xafLVwZ\xeb\xa5\xad\x89_\xfe\xbe\x08i]3\x8d\x0f\xd4\x13\xbe\x1a/\x99=2p\xe1\x99\xbc.\x89X\x17n\xc1\xa7bH\x99|\xbap\xe5\xe4y\x07\xe9\xfe\xa8\xd5\xb6\xe1\xe1Y\xbf\xaa\x86\xa1\xb2{\x02\xb5h#\xae\x12\xe4\xa8[\xe0\x90\xc1\xa5\x10\x8dm\xba\xa0\xc9\xa7\n\xbe\x14\n3\x18V\x90\xccqMh\x9ew\xfa\x81\x17\x89\xf9\x03\xa0\xbf\xb0f\x99\xf2\xfb\xe3\xb8VD\xcdu.\xa7\xfa\x7fXR \xdf\xefD\x8e\xc7\xf5\xc4\xb8\x0b\x8d\xd3\x14\xd4.kP\xa6\x06\xba\xcc]\xb8M\xefK\x0dj:\xf7\xc0\xcb7\x0e\xe8\x1e\x0b\xb5\x8b\x17\x88u\xa3\xe2\x97\xe2\xae\x9bi-\xffQ\x1c\\\x06\xa1\xb7\xd4Z\xfb\x85\xb0>\x84/\xd4\x87\\\xd2\x7f\x85\x91\x83\x90\xdb\x8b\x9fj\xd9K\x92nr\x0d\x94\x0f\xf2m.\xe7\xbd\xb5S\x07\xb9\xdc)\xdc\xb0@\x0f\x1c)R\xba\x18*\xd5S[^x\xc9\x16-\x1b\xd6Q\xe3\xda\xa3i\x8a\xf1\xdbMZ3\x900`\xfd\xd5\xf7\x00\xe7\x04\xfd{W\xccM\nF\xf0\x12EU\xee\xbe\xc0~\xbc\x96\xd1\x82=\xb1P\x9a%\xba Q\xea PL\xd8 #\x8fP\xac\xbc\xd4\x0f\x03\xcf\x83\xe7\xf4\xc8'\x89Fn\xde1l\xc5\xdatb\xa3R2\x9f\x9aK9B\x9dC7\x7f\xae\x0ey\x81F\x0f\xccI&\x83\x9f\xe5`>K\x85\x1b\x95\xfdZD\xf1X\x94T\xfa\xfa\xb8\x15j\x7f\xe9\x18\x870S\x1f\xe4g\xe1\x0d&8e\x92-\xdf\x9ej\xb3\xd5\xed}\xa1\x8aj\xe6{,n9\x87\x8e\xba\x86l\x0b\x86\xb8\x05\xc3\xb2\x8cFP\x92 \x99\x8c\x96q)\xb3j7\xde\x92\xa7\xe7\x8an^\x1bg~\xe5*\xa1iki\xc8G\xc1T\x18\x17\xc9[\xa8\xa6=w1\n}P\xefF\x8cH\xdf8w\xbc\x1b\xc5\xd09\xcf\x1d\n~'Mk\xcaW\x8dNhA\xddB\xd6Y\xba\xa3U\xbd\xcb\xf5\xb7\xd6\xcf\xac\xbb\xf0\x121\xf7\xda\xee\x16XP\xd3q\x8e\x18\xb4\xaeT\x93pum\x7f\xa1\x0b\x8c*\xeb\xbe\x86\x10a\xd8*#\x89\x8d\xec\x0b\xcdSN\xbb\";\x13\xa7\x1d\xb5\x15\xe4D\x91\xfdN\xf7\x0cyEd_\xab}\xcer\xc8\x83\x9c\xf0\xfb\xc7\xba\xfc}\xf4\xe4\xaf?\xe1\x0ft'|\xd4Kv}o\x9df19K=\xff\xed\x9b\xd8\xf3%\xb6B\xe48\x1d\x8d\xf6\xa8\x90;#2u\xa7.\xf7\x98\x07\xe5\xfc\x1fj\x89\xa4\xa2c\xd2\x9e\x85#;\xe1\xa1\xb6<\xc6\xd4x4R\x91\xb8\x1f\xed1\x89\xc8\x14\xc9n\xe1F\xa2l\xd8\xf5\xa3\x19\x8a\xddxO\x87\"\x1a-CJ\x02\xcf=\xd6hs\xa3\x02\xe3\xc0\\I\xc1\xe2\x84ln[`\xb1l\x88\xad\x8f\x882\x8f\xa2!X\xb1\xf7\xa5U\xa5Qj\xd9\x0b\x8a\xf1\xd6\xec\x9d\xb7A\xd94\xfe\xf2f\x08\x16\xfdS\x0d-\xecb\x80\x9a\x08s\xb7]x1\xcb\xe1\x16\x7fy\x83\xb4\x81ve\xf6\xce\xc3\xf7\x1eXo\xbbgH\x8d\xaaU\xdc\xa2\x11g\xe5]o\xa0\xd41\x18\x08\x8a[8\x91\xe2o\xeb\xc2\xa0\"w\xa3\xa3n*+:Q\x1a-yhk5\x8df\x17\x9et\x1cS\xf9\x9d\x8cc\x8d\xabi\xa3\xbfN\xc8\x02\x15\xd0}\xdd\xe8{\xc1\x04\xfe\xfe d\xf0\x04\x92\x13h\xb73v\x7f\xad\xd8\xa0\xd9\xd4\xc5\x80\xb7yh\xa2jv\x82J\x1c\xb407\x8bh1\xfd\xdb0\x1c\x1e\xee3\xc3\xa1\xa4ag\xa6\xc3\xc3\x83o\xdbt\xa8_D>V9\xae\xac\x95\xdb\xd4-\x8c\xb4X^\x87\xdaE\xd5;`=\xb0>Y\xe1\x1eA\xd9d\xd1\xb4\x9d\xaa\x1d\x17\xe6f\x8c\x84\x9b\xaf\x0d;\x9em\xebzr\xa7\xbek(&oB\x1fR\x9d]A\x1b*Ks\xc7\x81\xe3\xb0\x1f=\x82`,\xec\x12\x98\xbe\xa1\xf5 f\xd6*\xfe\x1f3\xfc\xe7w\xe5J\x17nS/\x08\xf9n8\xea\xddc7\x88\xd9\x96\xc9\xfc\x96{\xa5\x8e\xd7\xc5E_1\xe7\x88\x08\x17\"\xa06r/\x91\x9d\xbb\xfal\x1eE\xd6\xc3\x18\xda\xc50\x95\xa9\xe4wa\xee\x8a\x0d\x95#b\xc9\xb6\\NDy\xdf\xceW\xee\x92\xba\"\x18\xbb\xc6\x04\xb4\xd4[E\xd7\x1b[r\x16\x9bZrf\xf5\x96\x9c+\x83%\xa7\xd2\xdc\xcd\xa6\x06\x9fK\x9dE\xb5\xac4)\xbf\xb0\xd2\x12\x0c?\n\xe7\xc1e\x86\xb6W=\xd1 \xb9mV\x1f\xf5Z\x04I\xaa#+j\x9akJ\xa2\xe2&a\x05\x84\xc0b<\xb3-\xd1\xa5\xe1RF=\xeb\xfc\x9c\x10t\x1b8\x95b\xcb!\x8c\x1e\xe5(h\xd5\xc5\xbc\xe70\x82\x99P\xc8\\U\xdeva\xe5\xb8RA^,\x1c\xa7S8\xd5\xc5[\xe7O\xe8\x1f\x16\xac\x0d=O\x11:\x821\xb3\xa5\x92i\x01\xe2\x91:\xca3V\x11\xf5B\x9f\x0c\x91\xd0o6K\xae\x1c\x0eL|J\x13\x15\x88\x88|\xcan\x0d7\xb9\x9f\xc8\x8d\xd4\x01{\x03\xaf\x91 \x97\x8df\x8fX\x8c\xadCg\xf7u\xe8\xe7\xf1|\xce\xcf7\x9c\x8a\xf9|\x88\xa2\xef\xa63\xc1i\x84^\xcd\xcd&\xa3\xa5G\x9bR,\x05\xfd\xfb-\xbb\x82X\xce8\x9dn\xf0\x9e\x8a6,\xb6(}[\x9d1\x10\x92w\xc4n\xbe\xd1\xc5\x8b\xc7\xd1\x94\x8a\xb0\x91\x03A\x11\x927\xd0\xcd+{J\xe5\xe4\x81\x88K%4\xfa\x1c\x05\xe3q\xc4]\xe40ie\xdcM\xd6x\xeb1r\xa1\xaf\xbb\xb7\x87\x96\xb4\xb8h6\xaem\x96kc\xc3:\xcf\xf8\xa6eg\n\xc4\xac\xf1~\xe2U\x1e\xd1\xa2v\xdd\x0dt\x82r\xe3\xa0\xbc\xa0\xe6\x15\xd1\xafc}\x1cx\\\xc5Pc#c\xb6!9\xd5\n\xbb\xebH\xd8\x89\x85\xc0\x13\x08\xe9r\x13\x07\xa21\xa1\x0f\xcb\x17\x1dI\xcd%8l4\xc0\xe0\x15\xec2+\xaf\xb7w\x82\x847\xa0/\xb3\xaa\xf9.\x8e\x0bC\x8e\xb6RnJ\x15\xb7\xc9\xaac\xa9\x9b\x80Mnl-\n\xe2\xb2\x08\x92\x86{F\x0d\xf7\x8a6\xb9\x89Un\xaf\"\xaf\xdc\xbf\xf5\x86\x9bVu\xad\xbb%\xdd\xd1\xfd\xfa\xb2\xd1\x8d\xaa\xbf\x14\xfc\xa4\x9fue\x16L\x98\xf7\x1d\xfd\xaf\xf7\xba@\xcch$\xb1\xab:O\xc6K\xe7vP\x85S\xc62\xb7#GGx\xe6\xb6\xec\x0b\xcd\xbc\x08o\xec\xaf\xde3]\x9c,\x1d\xd7_\xa1\x16\xaeb\xccU\x02\xad.3\xdbgq\x88\xf3C#\xadTn\x8c\x08\x9f%:\xa3\xdf\x81\xfb\n\xcc\xdc\xd5\xa9\xea\xd3_\xa3W\xd5\x88\xcd^\x9e\x9b\xb0\x12\x99\xb8h\xaf>p\x80D\xf7+i\xb05\xdeG\xd2\x0b\xe8,d\xa7\xe3\x10-\xcf\xf4o\x19%\x1c\x91\xf4\xce+\x19\xa5\xd5\xeb\xfb\xef\xdd\xedN5\xa8\xf6B}\xd7\x86iy\"~(\xce\x14\xcb\x8aC\xa5\xae\x8b ,\xc5]\xb9\xefQ\x88\xadS\xffX\xa3\x1d(%\x94\xbb\xe3\xa1.`\x9a\x8d\x94\x8a\x07\x0f\xd4\xed\x8d\xce\xd1B\xb3\xcc\x04S6\x92y\x1cUrq\xd5\x9d\xb6Y\xe8v\x14\xddq\x0d\xc7\xa8Gv\x99\x8ax\xea\xb8\xf0\xbd(Z\x12/\xb4Q\x94!E\xb8e,\xc0LA\xe8\x15\xfd\x10c\x96\xf4\xbcG\x07N7HI\xec\xa5\x91>\x90\xe3\xb1\xde}|O\xb9\xcd\xc5\xf6\xe8\xa0\xba\xa3=\xfd\xd6M\xf4\xead_\xbf\xff\xe7\xbc\xcdj\xe5\xcb*^mt\xacV\x0f\xcb\x8b\x878\x8cj\x9e\xcb\x87Q\xf5)\x1e\xe64\xf1\x17\xdf\x1bO\xf2\xe5\xa3\xfa\xb6\x9b\xa8\x10K\x8d\x1e\x94\x8d\xa6\xa4\x17\xb5\xa6$\x0c\xb2T(\xe6\x13\xa6\x98\xf7\xed3\xa4A\x9e}\xc6\x83#\x02\x8f\x16\x8eh\x8e\x0bG!\x11\x0b\xf6\xec\xe4q\xf2\xca\x95\x1bb1\xe0 \xe8\xcc$\xee\xa1S!\xde\xa0\xe1\xbb\x93y{\xda\x97P\xc4\xe9\xa7$\x85a\x11\xbf\xb9\xcdo\xeb\xd1\xf3\xb9}S\x928\xfa\x0e&+\x1bA\x8a\x17\xd1o\x0c\xd2\x10;\xd5\xd1V\x1b\xa4\xf0r\xed\xa5N\x95B\x8c\\R\xb1&t\xe0\x86\xf9\xf2\xa5Z\x07J\xf1\xe1#5$\x0cU\xa0*\xe4\x06\xb3\x05~\xc7\\\x08\xe7|\xa9\x98\x91A\xb5M\xd8\xef\xb0\xbb\xf1\xd48\x178\x0f\xe7\xe8\xe5\xfa\x8e_Ge~4\x94`\x8a\xf9\xa1\x07\xe4\x0b\x18\xc19\x06\x16\xb3\x8b\xc9i]tgQHN\x1c\xb4\xbf\x9f\xc1\xa9\x10\xe2\x983\xf0\x05\xd3\x98p7\xf6\xfc\x17\xe5\xdf\xf6\"\xd7\xa6\\\xbb0\xb3opg,\xf0\xae\x15\x9f\xe6\xebj\xa3\xed\xb6!a\x16]9Mv\xa0\xc2\xdbs^\x83\x0d8\x03\xf2\xda\xebF\x8f\xe3uQoW\xc1\x89k\x8e\x10\xbfz7\xa4\x82]#\x05\xbb*\xc7\x92\x1c\xa9\xb6\xc0\xa2\xd8vx0\xdb:\x9bt\xd5\xd8\x0c| f\x8c\x07\xd8\xb3\xa2\xfbn\x8d\xccW\x89\xb0\x1b3\n8\x1b\xa7,\xcb\x1f\xcb\x9e<=q\xa0\xdd\x8e\xb5\xd4\x0b\x8b\x8e\x80\x17\x9d\x8a\x9c\xab\xf6\x9a\xa9]\xac\xef~\x17\x03\xab\xb9\xe0u/\x13.:\xd5\x1fI\x0bo V\x13\xd3\xb5\x10\x17<&.\xe2\x93~\xf5\xb4Zry\x97\x83\xd8F\xb52/J\xa4J\xc4\x08}y\xfa\xf9\xf9\x8c\xb00\x94A\x14\x9e\x9f\x0f\xc1\xc3\xd0\xa2D\xe7\xccw\x1ez+R\x94\xb9\xb2\xab\x0e\xd0\xef\xcb\xea\x91\xb9\x1dT\x9b\x9cG1}\xbd\x1e\xcb\xf8\xa0\x17\xcc\x0e\x86\x7f\x86\xec\xcf\x08\x02;'\xe8\x8aR\xa4\xf4\xfb-\xb9\xf9x\x93\xc6\x0c\x8e\xe3\xb8\xf9\x08\x04!$(\xd3.\xcc:\xfc\xc5\x98L\x99\xa7s\xce\xc1Hm\xd7\x16^\xf2\x92c\x89\x98\xcb\x98YA\xa4'\xcc\x9f\xcf\x92 J\xaa\xf4 y\x8e\xaa\xaa\xb3\xb5H\xf6R\xa9N-\xc0kU\x1f\xa8\x95s6V\xad\x92\x83EE\xfc\xa7\xf2\xfa\x8a\x92\xc3\xca\xbb\x08\xe3/\xe2w\xe5-\x9e\x13\xa9\xf2\x9e\xc8\x9a\xc4\xde\xe4\xbf\x94w\x13\xe2\xc5J\x93\x0c\xc8\xdfd?\xd4\x17\xd7\xc4\x0fHR}\x93A\xc5\xab\xec\x97\xe6\xdde\x90*o.\x834\x7fo\x19\xa4\xca[\x92\x08PyWz\xc2k\x90 \x9azrAA\xa9'\x7f\x92\xd7\x93C\x94z\xb20\xf1\xa35E\x83\xea,HOx=\x12\xa4\xe4E\x82$F\xa2J\xd5\x9d/\x119\xdaFU{.\xba'\xda\xaf\xb5 \xcb\xba_A\x95*;\xae\xd2\xb1\xc0\xdc1\xb9\xe5MZ\x15\xe4\xdb\xc6\xec\xedL\xef\xd1\xad\x90Qh\x83\xe5(\x0e\xa1\xa5\xdfx\xa4x=\xdf\xb4\xd5\xa4\x92M\x0b\xd4Q.\xcb\xa3\x0cddr\x9b\xa6U\\>\xe1\xed\xe8\xb5\xa3\\\xee\xae\xe4\x86\xc7\xe0\x189\xc6\xd9r\xa7\xf4\xbd\xca\x11\x11{\xe5[\xae\x98S\x8b\xbd\x105\xbf\x10\x94\xe2\xf0\x97\x04f}\x15\xe5\x99\xd0UQH\xe5\xf7\x89\xa5%\xe9g\x8f{[G1b!\xcfP\xdf\xa0\x93\x1cR\x8c\xea\x9f\xcb\x0d\xfac\x90\xd8\x1c\xc52\xdc}4\x9b\xf5:?\n\xb1\xab>Z4\xb9\xbd\xa5\xcf\xe54\x05\xac\xecY^\x16#\x98V\xb3\x18\x9e\xf2\x8b{\xb4\x1d~'\x8ecj\x87\x87\xfe\xb0\xa3b\xd1=\\\xf4\x80\xa2=\xf3\x93\xc5X&\xe3\x1e\xf7q\xc7\x07\xf4E\x17\xbcq\x9f\x03\xbf\xc5\xae\xe7}\xefO\xc7\x11\xe2xvr\xaf~;\xae\xa8\x8c-\xe0\x1d\xf0\x97k8\xb5\x99\x16\xd5\xa1n\x17\x1b\x83\x07\x8f\xa9\xc1\xe4\xac\x1e\x93=\xee^^\x8f\xebyn>c)\x1f\xd9\xc1\x06{\x81\x0b[\x19\xc5.\xf3f\xa0\xaf`\x1a\xc0q\xb2 =\x8d$,\xdd\x9c\x9eJ\xd2\x7f\x86\xe8\xe0\x8d#\x89\x9e\xd6\x93R\x9f!J\xc6\xe24\xb1\xbe\xf6\xa7\xe3\x00\x91.\xba\x03a}\x90\x9e\xe5\x17q\xf3\xce\xd0\xf7\x85\xdf~\xe0\"B\xd3g%\xd0 \xb4\xb0\x18\xb7\x7f?z\x04\xbe n\x0e2\\\xbf\xbb\x8e\xd6\xb6\xe3\xb2E\xe1\xbf\x9c\x0dj\xdeb\xbbH\xd7\x016\xd9'\x9b\x86_\xe1r\x8a,\x97\xa8\xd5\x7fG\xff\xeb\x1eRY\xc5\xf0\x7f\xcco'\xb2\x90\xb4]\x0ci\xc7\x83:\xdf\xe7B\xe2VB\x9c\xdc\xf66G9\xb4w\xa7\xf6W\xef\x91P\xa6\xf6+\xef\x15\xbb\x83\x98\x16I\x1e\xe0\xe1fk\x03\xa9\xbf5z\x18=XYt\xbe\xe3\xb4n)\x1bW\x89\xe4C\x88\xc5\x12\xb9 .:\xc2\x19\xbc\xe0\xca\xc2[PHi\xe18\xd8h\xd7\x95\x85\xac\xa6\xe0\xa1,_6K\xac\xe3B\xc8~\xb5\xdb\xa9\xf3\xed\xf0BIc\x85\xf9\xa3\x90\xf1\xb7p\xa0\xec\x0c_&Va\xe9\xb7\x86*<\x0c\xd1\xd1\xc8+\xdf\x02\xbdy\xc8S\xa0^\xc9\xa0G\xf5\xd0(\x8a\x9a\xe48\xcd|hJF\xf7\n\xc7\x15\xcd\xe09\x82\xb8\x10\xa1\x7f\x01ECM\xd8\xe4\x0dh\xe1F\x18\xce\x8e\xb9L\xcag\x83\xa5d\xc9G5\x00\xe1\xc7\xbb;\xe3<;C\xf9x\x86j\x16M\x136#\x9e\xcb\xf3~\xf3S\x1aC\xfel\x0b\xe4\xe7\xbdi\xd5\xf6\xa6\xe1\xc8@\xe4\xe6=U\x90\xf54\"\xb2W\x16\x91\x93\xb2\x88\x9c\xe4\"\xb2W\xfc\xd2\x88\xc8j\xcd\xc6\x9er\x89\x98\xae\xd4\x86\xd3s\x0f\x96e&\xe4p\xc7\xed\xe5\xcaD\\\xed\xeaw\xf4\xbf\x1e\x86\x07j\xef;\x85v\xff\xb8\n\x8f8\xfcH\x7f\xbfM $..\xcfT\xef\xe0$\xa6\x8bo\xe5b\xdb\x05\x0870mL\x15\xc1\x93\x184\\x\xe7J\xd3\xa5\x0bk\x17\xfd+\xe7\xdcAQ\xa5/u\x0f\xaf\xd0\xba!\xc2\xce\xa9\xcfo\xf0\xb9\x08\xc1X\xc6\xe8\xe2=\xf4\x08\xaf\x97\xe5\x84\xa4QD\x17\xd6\xe2V\x8c\x91\xa1DJ\x07\xbcVj\xd4\xd4\xebC\xad\x80\x88\xd7\x1737\xbb$\x17\x9f{.t\xfa\x945\\\xf1\xcb'\xcb<&\xc2\x9a6\xab\xda\x9c6rX\x8eli\x02\xe1\xaa\xc6o\xf9}e\xfa\xa2P\x04\xe9m\x9e\xbb\xda\xdb\xed\xda\xfb\x93\x90\xbb\xbbI\x11\n\xb4s&;\xee\x8d`\xbc\xc0\x88\x15\xa1p\xe2c\xd4=t\x98\x0d\x0e\xa7V#\xbd\x89O\xcc\x18\x12\xdd\x95KF'\xd6LZ^b\x96|\xe1\x92\xdf\xe0D#>(\x7f\x98\xe9\xa8.R\xec\x8c'4@~=c\xc17\x8a\x80\xc8\xb8\xb7X4\xd8\x88\xf1+\x1e\xcb8\xc6T\nQ\x98\x92\xeb\x14\xf30\xc5\x97\x89\x93\xfbo\xc6,yD\xc00%*P\x88\xae\x89)Et#id\x99\xbe\xf9\xdej\x8a\xc2q\xc5\xeeEr\x9fp\xe3\xa6\x08\xe9\xd0\xd3rV-\x1e\xfeCT\x0f\xa9\x19a\x84\xfc\xccD\x8a\xb4\x1b\xcc\xcc\x9a?\x1e \x13jS\xf9\xd3\x82\x9c\xdd\xd1\xdaXO\x16\xe3\xa4\x08\xda\xcb~\x04\x85MF\xe9>\xbf3\x86X\xa1\xf4\x8a\xffX\xe2\x8f\x9cq\xc5\xdb\xf5e\x81\x0eZZ\x94\xc6\x1b 6-\xc0\x88\x8e\xc3\xa9\x0es*^8\x90u\xe9\xcf\x0dD\xa1\xc4\x9esa\x85\x8b\x14Z \xa5qJ\x12{\xad\xe3\x0fj\xefs\x1a\xc2\xa8\xa2\xe8\xaf\xf9x\xa6\xbd`\x9b\xe1M\xfb\x0d6\xc5g$\x8d\x03rE\n\x8a3\x8b\x08#D\xc1j\xbd$T(\x12h(\x90\xf8\xb1\x96*\x89\x0fk\xda\x9e\xbb\xa0\x1bqe|9\xb5\xff\xafq\x9c\xe5\xcdj\x1aoM\xdf\xf8\xfb\x0f\xd6\xbd\xbc?\xdb\xf5P\xac\x08\xe6n\xe0oh\xd1\xb1\x04)\x04\xaf\xaa\x8a\x81\x85\xca3q\x1a\x93\x8a\x01\xf9`\xbb\xad\x0f\xeaW\xe3\xe7D\x19\xc0R\xfb\x12\x88\x03\xfe\xa64I\x7f\x8e\xc7\xc1\xe8\xe9\x8e\xbeM\xcf\x8e\x1c\x93\x8c\x1f\xe1\\cVF\x9ct\x84x\xb3\x03I\x1elH\xf2\x7f\xd5\xefa\xe9\"\x1asj*\xee\x84y\xccO\xb1\xd5\xe9x\xe2\xe4R:\xac\xb4z\x98\x9fP{]L\xc3\xbf.I\xfa\x19G\xd0\x1f\xd38z\xc5 <\x16LV\xb3\xfd\xef\xa7\xd4\x92\xd2\x0f\xe96X\xe8B%DsXD\xecm\xf1\x88\xbd\x04\x86\"\xa5b#s@\xaf\xb2\xee\xf3\xb33\xba\x1c\xf8\xa5K\x12\xdf[\x17\xfaT\x19\xa8N\x95`,\xcd,H\xc4dP2z\x19\xbc\xd8\xfef\xd1\xec\xdf\x84\x98\xfcl\x16\xc4$\x01\xaf\x08}g\xf4X*\xc5\xbb\x96\x82L\xf1\x10La\x9ea\x81\x12\xcfN\x9f\x1d\x83)ya\xa2t)[\xc2 \xb4\xdb\x01<\x81\xf8\xc4\xc1\x19\xe6\xf9{\xe4B\x01\xde{\x8c\xa0Mg\xff\xe9\x08\xfa(\x05S\x01d\xb7\x8ftgp\x08\"\x03!N@\xc0\n<\x1d\xc1\xdeQ^v\xff\x10\xcb\xd6=\x7f\xf4\x08\xf6\xf6i\x81\x8c\x12\xc6\xc9\x04\x83F\x15\x96\x89\xfe\x01Zr\x80\x12K\x1b\xfb\x1a\xb0*[\xfdJ\xd8\x01\x82uup\xc4\x1f\x88\x0e\x1e\x17_\xf5=D\xe8\xc1~\x0e=\xee\xe5\xd0\xe3\xc3\x1c\xda\x1f\x0c\xf02(\xce\x13\xce\x11\xa5\xe0\xac\xcbe \xce\x9b\xf5\xff\xfe\xc5\x9fY\xb5\xfbPuz\xd78Q\xc8\x18\x8b\x1a\x18\xf6\x0dO\xdan \x91Y\x8a\xcfJt\xe5r\xec\xeeX\xd6\x1b\xbew\xf2\xdb:\xa1\xdd\xef\xdf'\xb0\xa76p=\xad\xd8:?'\xc9\xa7\xd1,[\x12\xabJ\xb5y\x9a 9\x8d\x82\xc3T=\x98K\xaf\xceQ\xc5x}9I\xbd\x94|\x7f\x99]\x06a24l\xdadM|\xd33\xfa\xf1\xb0\xcdd\x08\x99Y\xc8O\xc8\x92\xf8i\x14'C0\x04c\xd2\xbf\xcbR/\x19\xbb\x068\xb6Y\xe6\x13Zs\"\xa6\xc2\xdc\x8f\xbc\xaf\xd1F}\xf5\xf4}U\xf1\xf0;\xfa_\xefU\xf9mn\x87\xf6~\xffX\x89\x90\xcd\xed\x0c:\xbb\x84o\xd3'{J\xa0e\xfeh\x7f\xaf_}\xe4\xe5\x8f\x06J\x90i\xd1\x87\xbd]\xc79\xf9N\xfeL\xe0\x0e\xf8z\xc5O\xca\x98C\x81\x9f\x05s8\xa9\xa0)\xe3\x06_U6\xa7|+G\xa3\x10\x93b\xe6\x05!=\xb65\x1c\xac\x0bC\x1d\xa7eEF$\x93\x19\xbc\xd8(i\xd9\x8fC\x9d\x84\xb9\xd1\xbdB\x99\x07\x1e\xb4X'a\xb1\x1c\x97\xd5 \x93\xdfQ\xbf\xd1q/\x95[B\x97$\xfd$\xf2\xbd\xe5s\xdc\x04\x9b\xc5\xfa\xb3{\x18\x8c\xd8\x8b\x13\xf2\xd3\xde\x8a\xbf\xea\xd8\xb1\x18\xfcv^\x0erC2]|\xdc\xe9t&a\x16/\x87`-\xd2t\x9d\x0cwv\xd6$M\xd2(&\xdd\xe4\x9dwyI\xe2n\x10\xed\\\x0dv\xc4\xaf/\x92(\xb4&\xe1,Z\x9d\x07\xb3!X\x7f\x85?\xe8d\x815 \xd11\xddK\xa3\xf8\x07\xa5:\xa3p\x19\x84\xe5\x1aEAk\x12F^\x96.\x06\x9f\x91Y\x10\x13?-\xde\x1c\xee\xec,\xe9\xbc-\xa2$\x1d\xee\x0ez\xbd\x1dV\xb2\x13\xf3\xa2\xddE\xbaZZ\x93\xf0\xb1v\xd0\x1bQp\xc9\xb5c\xd07hR\xe3\x87\xa9^\x7f\xdc\xdb\xdf\xebi\xb7od\xc4\xdcZ\xf4Q\xbcH\x85\xb5\x120\xfe\xa6\x88\x15=#\xeb\x98\xf8^Jf\xe0\x853\xc9\x91&K\xc8\xac\xdb\xe0C\x03\xf2\xfct\xa9\x98\x87#\xe9\xc9IK\xbbg\xfe\x82\xac\x98uu\xf7\xa8\xf4\xe4\xe3g/?9{\xf6\xf1\x8b\xf3\xb3\xe7\x7f\xed\xc5\xa7\xcf\xb8\xc1vP*\xf3\x93g\xaf_\xc9\xcf\x07\xbd\xdd\xd2\xf3\xe7\xaf?{Q~^~\xff\xa3\x17\x1f?\xfb\xc1'o\xce\xab\xed\xec\xefj\x8b}\xfc\x83O>\x91\x8b\x1d\x95\x8b-#o\x86\xa1\x02\xe8\x97\xea\x83g\xf4P\xc1\x9f=c\x17\xce\xc4\xe3\xc4\x9b\x93O\xc4\xbb\xe2\x87\xae\x80\xa8C\xfa-\x17\x9be\xab5\xc6\x0c\xa4_\xaa\xef\x7f$\x1e\x8a\x1fr\x81\x9f~\xf6\xe9'/\xae}\x82!\xe89\x1e\x96\x86\xf6\xe9\xcbW/?}\xf6I\xddZl8\x87\xe6\xe9K|/D\xd5\x81E\xbfY\xa5gH\xe1\xd8C\xfcZ~\xeaG+\xee{\x12\xd9\x16\xffQ.\xe1\xcdf\xcf\xa5\xf0\xe1X\xb0\x0c\xb3\xee!\xdfI\xfe}\xd5\xab\xfcA>\x9b%0\xbfD\xa5h\xa0\xb3|\xeaJ`/\x9f\xaf\x128iVH\x97_\xf0U\x85\xf2\x1cF0(\x83(\x92\xed\x96A\x14u\xf6\xca\xa0\x85Z\xd7L\xad\xebJ\xad\xeb\x86\xb9\xc2]\xf7z\x9d\xc9u\xefhr\xdd\xfb\xde\xe4\xba\xf7|r\xdd{\xd1\x99\\\xf7?\x9e\\\x1f~\xdc\x99\\\x1f\xedM\xae\x8f\x0e:\x93\xeb\xe3\x8f'\xd9\xc7\x1f\x7f\xfc\x02\xff\xffxz;\x9ed\x1f\x1d\xd1\x97\xb3\x8f\xbe\xf7\xf1\xc7S\xfb\xb4E!\xcf\x19\x84\x96pn\xed\xd3\xe1\xf8\xf3r\xb1\xdb\xcf\x9dJ\xb1\x9dr\xb7.y\xb7\x8e\xf6\xcb\x1ez\xe5R+,\xe5N\xc6\x93\xe9\xe4\xab\xc9\xfb\xea\xe3s\xfa\xf8s\xfbt\xd8\xbam\xb5n[c\xaf\xf3\xe5\xa43m\xb7\x9c\x0fv\x82r\xc9\x8b\xa2\xe4\xf8\xf3\xa2>\xc7>\x1d\xfe\xc4\xb8\xd79\xf6:\xf3\xe9W\x83\xf7\xb7\xec\xfb\x97\x93\xce_9\x99\xecLN\x87\xdf}4\x9a\xb4'\x1f\xb8\xe7\x93n\xeb\x7f\x98|\xf8xbO\x1c\xfa\xf6\xd4\xf9\xf0\x83\x9d@\xc7\"\xde\x19YD\x9f_B\xc33\xe3.\xfb.\x11q\xb5\xaakcU\xc7EM\xbb\x83\x0dj:\xdb\xa6&\xec\xdf\xb6}}alao\xaf\xa8\xea\xb8/}\xdf\x95\x9a\x18\x94~\xeco\xd0\xe03\x83yG+\x9e\xee\x1d\xa1\xb9\x02\xa5K~\xd2>\xc5 9{G0\xa4\xc7\xea'\\\xef\xb0;\x80[`\xc9\x9c\xd91\xbb7@}O\x87\x16j\xd3i\x19B\xa7_\xdb\xb1\xd7\xe6\x998\xca\x15]\xd6\xa4g\xb1\x96s\xc8\x7f\x87\x00\xb9\xc8\x05\x85\xf4\xfb\x07\x12(\xc5BU@?_.\n\n\x19H\xae\xe9\nA\xbd\x81\x04\x9a\xb3R{\x12(f\xa5\xfa\x05\xe8\xbf\xa7\x90]\xe95\xd4}\xec\x16/=\xb6\x1e\xc3\x10\xf6\xa4a\xec`\x0f\xe5\x96&\x14r(u\xe7\xff\xf9y,\xb3/A~\x13\xcb\xc8#E\xaa@\xa1G\xbd\n\xf4\x98)\xabk\x17\xe1\x8b\x9a#\xc6\x93\x11\x1c\xec\xef\xef\xee\xc3)W\\a\x96\xe9\xe7\\\xdfd\xa7\x85\x03j\xf9\x01K\xe9\xd9\xa6\xa7\xb5\x0e\xd6p\x00O\x9fB\x9fJX\xfb\x07\xbb\x83^\xf9\xd1#:\xdf\xbb\x8a\x11\x15\xe4\xd3\xd8[\x90\x13\xd3\x0e\xf6\x0f\x1c\x17^j`\x9f\xb2\x84r\x9f\xc2\x13\x18\xec\x1f\x9c\xc0\xa7\xed\xb6\x03o\xc7\x9f\xd23\xd9k\xfbS\x87\xc7\x19\xe8\xb9\xf0\xb2\x00\xea\x88\xd3\x1b\xad\x1e_hb\xc9;\x08P\x01C\xdeQI\xb7;\x0f\x96$\xf4V\x84\xb2\xf6 \\g)\xde\xdb\x8f\x92 \xc5;\x96i\x97\x9e\x1fd\x18t8\xf0,\xf5\xe2\xb2\x9b\xbc\xda\x97\xe7\xda\xbe0Q\x99\xf7\xb3\xf6\xfd\xef\xeb\xdf\xefF\xe1\x0f\xbd8\x0c\xc2Kv\x96\xcc\x7f\xf2\xeb\xea\xe8y\xca\xeb\xd7-\x0e]\x97\xcf\x94\xd3\"\x15\xd9\x86\x8d\x16\x1a\xf1\xbe1d\x0b?\xa2\x8f \xed^\x918\xa1\xc3x\xf4\x88\xcd\x845\xcb\xd6\xcb\xc0\xf7R~3\xf5'h\x93\xc0\x8eT\x98Q\xca\xe5\x91\x0fC)`\x15{\xb3\\\x12<\x9f\x8a\x96 \x90k\xcfO\xf1b*\xc9U\xba\xb4\x9a\\\xe3n\xc7\x8c+R\xa67m;\x93\xae\xf8\xf6\xc1N\x97\\\x13\xdf\x0e\xc7=\x1e\x03\x8d5\x14,\x97\x9dy\x14\xafdw\xffh\x0e\xe9\x82\x80\xda[*\x8b\xa1\xf4\xf82L\xedx\xdc\x9f\xbal\xafDe\xf8@\xc0\xa5\xb8\x8e\xac\xb5,d#\xc1lhX\xbf\x983\xde\xe6,\xf2\xf3A\x15\x13:\x82\x90E-\xef\xfa\x0b\xe2\xbf\xfd$\x08\xc9\xf7b\xe2\xbd\xa5\xe2[Dw\x90h\n\xef\xdc\x0e\x8a\xaf\xdf\xe7\xad&\xd9\x9a\x8a\xb1d\xd6\xd0hiu+*\xb67\xcf\xfe\xeav\xe8\xa2\xe2\xca\xc0\xb0\xdao\x9e\xfd\xd5\x9a\xc5N\xdfE\x85\xfe\xdf\x12\ny\x16\xd1\x0e\xbf\xd1u8\xef\xa6$I\xed\x18\x03@(K\x9bz\x97\xb0\xf0\xc2\xd9\x92\x80=\x0f\xe2$\xcd+t\xc4$\x94\xfa@[\xc9C*\xa4\xde\xe5\xa7\xde\xda\x85\xb8@\x9b\xc7\xe9\x82\xc4\x84\x1ep=X\xc7\xe4*\x88\xb2dy\x033\xe2/\xbd\x98\xcc \xc9\xe6\xf3\xe0\x1a\xa9\xa2\xf5\x18\xda\x10C\x1b\x1e[R7\x1e;.\\\xb0.\x07\xe6.\xafcB\xab\xb1\x13\xe2G\xe1l\x83>\x8b\xce2\xbf\x87r\xe0\xfc\x92\x96Q\xa5=\xaf\xc4\x92\xe2@U)\xa4\xc8\xdf\xaa\xaa\xe9\x08<\xd1\xa3\x02\xbac\xb0\xd8;\x94\xd8\xf2+\x1e\x888\xb4\x19\xa5<\x08V\x120sz$E\xf5f\xf9\x08\"\xfa\xa7=\x82\xbe\xc3e\x06t\x0e\xf0\xaa\xb6\x15&\xfb=\x19AF\xd7,C\xb9\xa7\xdf\xdf\xeb\xf7\xfb\xc5d\x93\xeb5\xbb\x83\xcf\xa2\x1c\xfc\xe4\xd9\xebW@\xab\xf1\xfc\x94(\xb90A\xdc4\xbca\xab\xe6I4\x84.E\x92\xc6\xc4[\xa1\xc3\x81\x17\x84 \x84Q\xd8Y\xc7A\xc8\xb6z^m\xa2\xab7\xed\xc6$\xc9\x96\x98/\xd53\xad\x99f\xc9>)\x96Lqo\xb9\xe2 \x04\xd0-\xac\xe2,\x833\x1cw\x83\x84\xa7\xdb\x0f%\x0c\xe4\x1a\x9a\x15\x89/ \xac\xbc\xf5:\x08/\x93\x13\xc4\xb6u\x1c]\x053\x8a\xddQ\x16\xfb\x84\xe7o\xa6\x9b@&k\x96\x93\x87\xd8\xa4\x87E[\xf2*xKn\x12;t\x9c|A=x\x02>\xfd\xc3\x164\xc3\x80\x8f\xde\xd4\x95\xe2\x9ce\xd87\x9b\xb0\x90\x94!\xfa\xdb\x04\xecG\xabW\xcfM?\x920Z\xce?\xac\x9b*\xdf\x85\xb9\x8a\xd7Aa\x08\x0cd.\xc3S\xf2\x08#\x91\x95z\x97\xc3\x1bo\xb5\xecF\xf1\xa5;\xe8\xf5\x06C\x9c?\xe6q\xabAsZ7\xbb\xeb\x18$L(2E>\xc0\xa5\xe2\xae0\xf4\xa0\x1d\xe5s\xe7\xc3\x13\x98\xd3?l\xee\x04.Dc\x1fS\x90\x1b\xb07/\xa6\x96\xc1\xe7)\xea]\xe9\x94'y\x8cb\x9e\xde\xa9X\x13\x06\xb0\x99\\\x04t\x8f\xdd\xde\xeaD\xa7\x11x\xecI!`\x95\xe5\x022\x13(\x06o\xc9\x0d&\xe0#\xe3`\xcaB$\xe5\x97~\x83\xe6D>\xea\xe2\x7f\xb9\xd1Y\x8a\x1f2p)\x05\x8d\x92(I\xd1s\x87\xdd\xe8\x12?\xdbmz\xac\xd8\xe5\xc8p\n\xb6\xfc\xc8\xcd\x8f\x9a\xb552Y\xaex\x8d\xca\xe8lz<\xc0\x89\xbd\xa0,\x9en/A\xa8\x18\x85\xc7gmt3\x92$S\x1c\x80\xa8\xacvf>6\xf1\xee\\\x86\x97s\x0e\xd5\x0e\xe1\x84;\x10\x04\xda\xb8\xac\xdc+\xeb\xda\x0e\x1c\x1e}TS[\xbb-\xd7\xa7\xdd)\xb8\xdbv\xd9\xd1\xca\xe0!7\x8bj\x0c~\x9b\xb4\xac}\xf9=\xbc[\x04Td\xe8\xf7\nA\xae\xbf[|\xe7`C\xbf[\xef\x90\x15\xe12\xaa%pv\xbeD\x07\x83\xe6\x89v!\xa6x\xc5\xd6\xfbe8\xa3R*\x9e\x9f\xf8A\x96.\x80\xfc\x90\x16\xdez\xd8\xefu\xbb\x8c\x87\xb0\x0d\x8b\xe1\xc6\x0cq\xa5\x9e\xcd\x0c\x99\x06\x8f{\xc16\x08\xe3\xbe?\xc5\x89\xfb\xd2\x85V\x1f\xbd\xe3\\\xd1\x94@\x0e\xa7\xdc\xbfM\x1aw\x0bf\x8f\xb4 g\xf7|HO\xb9\x83\x10\x9f`\x87\xf3\xb1\x0bo&\x13\x01zj\xf1 !?\x9b\x91\xd0'@\xc24\xbe1\x8a\xd9\xcc\xc7\xacDd\x88\x96\x96\n\x12\xd0\xf28\x8e\xd0\x83\x13Kd$p\x07\xc5\x89\xb4\xfb6\x08g0\x02K\xf4\xc0r\x8b\xcd\x841\xc6\x9a\x04\xca\x9f6\xd3\xa8\\\xc4D\x8c\xd6\xef\x80*\xa6\xd3!\xee\xee\x16\x11\xc2\x1b\x04\x90\xdc\x7fBW\x8f\xb4a\xe8\xf8M\x1a\x18\x8f\x1f+\x99i\x87R\xe5\x03.\x01m\xc2-0\x12m\xc41~\xb3\x17\x86\xb0\xcb\xa4\xa4@D\xb1\xc58\\t\x19Z-k\xf3Z\xd8\x1b\x16\x0b6 \x0b\x94\x91N\xf20\x8a\x03\x9b4\xa7\xbc\x98\x8b\x01\x92\x14p00\xb2~\x89r<\xc9\xb3\xf8\xd1\xd1\xc7\xba\x83pi\x97m\xd2\xbdBL\xcc\xc2\xfc\x04K\xc2\x99\xd0 \xf0\x83\xe8\xbb ]\x04!xpE\xe2\x0b/\x0dVt\xe5\xab\n\x1eS\xa8#.\xb9I\xe3m\x9d1)._M\x96D\xe0T\x9c\x80\xbdK\xa1\xf3\xe0\x07H~\x10\x06r\xed/\xbd\x15C\xc0\x95\x17\xbfM\xac<\x0eqe.X\x16\x85\n\xdd\xcd\x15;\xf2\x195\xf4*:\x9dJ\x9bI\xe6/JGn\xe6\xa5I1\xaf\x8c>\x8c\xb4o6\xef\xeaB7\xaf\xe7*WJ\x15\xba\x02\xe3L\xcd\x97\xd1;J.\xe9v\x8d\xe2R\xff\xcb\xab\xa6#\x7f\xc8\xc8Z\x17\xfa\xf60\x99u\xfd\x1c\x0d\xd1m#F]\xe6)\x08\"\x1a\xc3PU\x83\x85\x8eT\"W8\x85STs\x0d\xe9.\xe5\\\xa2(Ea\xe2\xa9\xee\xb1z~\x16\xe5\x99\xb6-\x0bs\xcd\x9a\xb4\xea\xa8Y\x0bQ\xb3\xf6\x18=\xc1k\x89\xf7\x0f\xcd\xc4[C\x96\x8f\x18Y\x0e\xefA\x96\xcd\x82\x8c\x9e4\x87\xc0K\xc8\xe4\xd9\xd0\x81\x12fV\xb1Zl\xdc\x90o\\v\xd4l\xbd\xb0C\x07\x93\xc76\xd7\xa8\xe5\xb0\xd2\xb6\xc9u \xc5~,\x0f!\x8cf\x04VYR\xe0\x9b\x97\xc2\x92xI\x8a\xaa{I\xcbVb\xd3\xf5\xbb\xa9a\x81\x7fJ\xd2\x86i\xf8\xc2U~I\xf2\xc6\x85K\x17V.\x9c\xbbp\xe1\xc2kf\x8c\xd20\xed7\x06f\xfe}\x033\x97\x16{\x19$) I~Vb\xbfl+Zc\xd4\xd9T\xe8j\xa1\x88\x1e\x9d\xcf\x82\x00pyE\xfc\xcc%\x15\x06@\xb5'\x8c\xd0\x19b]\xc8eLA\x85A\xeb\x1f=R\x04Q\xfbM.\xaf\x96\xc578e\x93\x00\xc3\xca!\x93\x9f:\xd0\\W}\xf8\x84+\xc2>E\x97x\x07\x0d\x1e\xf4\x85O\x0d\xde\x9a'L\x82\xba\xbd\xc5\xcdx\xe2\x94\xbbwZ\xf4\xee\x86\xc9c\xdfJ'a\x88\xd5\xeb\xd6\x8f\x07j\x80\x11\xbc\xa1\x9d\x8cr\x0b\xce\xa7\xf4\xc1\x9ao*z\xea\xbb\x80\x11\xf8\xc5\xa4\xcfs\x92F\xf0<\xd6\xa6\x9c\xecu\x99\xd5\x94\xec\x88\xf9L\xc1)\xbf:\x8eg\xaf\xd789\xdb\xd8X\xdcB\xc9\x9b\x98Og\xc0=w\xcc'4\xe0^;_\xd5\x8475=\xcb\x91T\xfb\xf4\xaa\xf6\xe9M\xed\xd3K\xc3\x06\x04\xeeG\xa3\x0b\"|\x87\xf3\xe3\x92\xab\xac7;?z\xc6$D\x18\x84\xa8\xa9\x1e.\xd6D\xd2\xa1-\xab\xc8\xb4\x07\xecP\x80\x07\x9a\xfd#\xfe\xfd\xf6\x96\xd2\xf2\xb8\xf9\n%\xd2\xc1\xd0\xc5[\xaf\xec\x08h\xd4A\xc9\xefI\x07<\xadL-\x7fX\xaa\xdf\xa6\x91:'pm{t\x9f\x1b\x8a6\xc8W\xf2\x87\xf6p\x9f\xf9[x\x0e\x9c\x99\x1a\xafH\xca\xb9\xc4\xe8Q\x11\xfe\xffc\xee[\xbb\xdb\xb6\x95E\xbf\xf7W\x8cx{\x1c2\x92\x15I~$Qlk\xa5i\xd2z7ur\x9a\xa4\xfbt\xcbj\x16-A6\x1b\x89T\xf9\x88\xed\xbd\xdd\xf3\xed\xfe\xb1\xfb\xcb\xee\xc2\x0c\x00\x82$@\xd2N\xd2\xd6k\xb5\xa1@\x10\xcf\xc1`\xde\x93\xb2d\xe3\xcf\xb5\xdbG\x97\xad\x82\xbf\xe4%\x9c\x82\xfe\xc0\xae\xb7\xd1w\x02\x12\xb6\xf1c\xa4\xc6\x149}\xb6\x8a\xe6\x1f\xa4\xd4\x9a__\xc8l\xb9\xa8kX\xf5\xf2\xa88Z\xc4\x9b\x8f\x02K\x8b\xa2\xb5@r\x02\xb8\x91\xf8\xe4\xff.\xd4\xf9\xc5/$\xc2\xaf_\x97\x86\x9c\xcc\xf2\x0f\x01c\xad\xb9g\xd1\xd5\x93\x14\xee\x9d9\x07\x96\xfa\xee\xf8\x9f\xd2\x13aD\xd8\x98\xf9\x0b~\xf1\x07kN\xcd\x04\xa9\x12\xe8o\xfc ~\x02>\xcc\xa3U\x14\xf2\x95^\x07IR \x9bW\xfe3\xbbKC\x1d\xb3\xa2\xff}\xaey\x9a\xe6X\xdcz\x12_\xf0 \xae\xb3U\x1a\xe0\xd9\xf9\xc0\xaea\xed_\x830q\xd6W\x05\xd5\x1b\xf6\xb9\x19\xdf\x88\x19\xef\x13\xcb\xe5\xf3\x0b\xf2\xd3\x80Mp\xed\xe42yN\xedi08\xc8Y\xcb \x9cG\xeb\x0d\xea_\xd8\x95ec\xf9l\x91\xceS{\xfb\x04\xa2\x18\x96\xd1j\x15]\xb2\x05\x9c]\x83\x8fj\xd0\xd4?\xcbV\xa8\xeca\xebMz\x8d\xca\x0d\"\xfcr\x9c\xa8\xbc\xa6c\xf3\xc6P(\x11\x0dEYeP\xae\xa4\x037DZ\x04T\xca\xa7\xab\x1f+A\x06hB\xb1s\xbc\xd9+k{-b\xd9\x1b\x97\xb7(Hk\xc6\x88\x9e\x81\xa8Qr3\xbfVnV\x80;\x9b\x17c\x93\xe8\xac\xf2Q\x15\xf2\xc4\xd1AH\xb3\x01\xda\xba j\xab\x9c\xae\\\xd4&\xf1d\x81~\xc5\x16\n\xfd\xfe\x81\xc4O\x0f\xce\xbc*\x01d\xa3~\xcaZ]\xccY\xb3\xd4\x93\x88u,\xf9\xc6\x17\xf5\x84\xd2\xc7FB\xe9\xda\xe0\xad\x04\x02H\x859\xa8\xbbi\x86\x05\xd2\x89=\xde\xe9 98IbM\xe9\xc9k0\x1f\xefs8\"\x82ac\xe5EUmN>\x8f\xf6D\x8f\x03\xea\xf1?M\xfeip7\xb2*\xf6(\xc3T\xd3=- \xabM-a\xa5\x8e\x1a\xf3z\xad\x96W\xe8\x0b\xab\xec+i\xd2\x08v\x17\x05\xd8\xfd\xa8\xc1.\xc7\xb7\n~al\x13\x1b\xc7\xf6\xcb\xe4\"\xa7?\x08?\xc2>9\xc5\x9f\x04\xe1\xf9\x8a\xc1\xefY\xc4\xab\x8a\xbdGZ\xa2n\x96\x86\x83t\x1b6\xc3\xdc\xe9\xe78):\x83a95\xbb\x04\x1e-\xc4t\x9f\xff\xd4`\xe2m\xf3\xa9i1\x9eZ\xc9\x88\xf0]\xf5\xd5\xa0\x8d\x18m\xe0\x95\x87d\x03|\x14c\x8dd\x9b-\xce\xa2\xa9\xab\xcbv*\x1aO\x87~\xfb9TrM\x9f\xfcE9\xd0\x7f\x98\xfa3\xafp\xc1\x1c\xa3\xef\x88>\xc9\x16-Rp\xd1\x910\x83\xe3\x1c\x8b\xcf\xcf\xd2\x08]\x89\x1f*Vf\x17\xc6\xf0hO\xfd\xe4l\xc3\xc0\x83#\xfe\xbf\x16\xba\xb2\x80\x14\xda\x11\x19m\x07\xfc\xbb'\x10lo{\xd8\xfb\xd3\xb6k\xc5\x99\x14\x0c\x1b\x87~5\x07\x07\xb0\xebA\x172\xc5R\xa9\x13x\xc1\xae\xfc\x05\x9b\x07k\x7fU\xef\xd2\xa4\xff\xe9K\xf9\x9b\x1b\x95\xe0\xc5N\xb7\xd0ZJ,\xf0!\x8c.C\x10\x11\xd3\x94\xcc\xac\xa6\xeb\xea\xc9\xa8\xc7\xa4~\x8eI\xe9\xe8\xdb0i\xb5\xe1/\x84I\x17Qv\xd6\x06\x93\x96\x06\xd3\x82\x96\xb8\x0dj5\x8f\xc2\x88Z51NGC\xb26\x0c+\x0c\\\xcdXu\x97d\x18\xcd\x8a\xef6X\xd5\xd2H+s'2\x81{#\xac\xdf:\xcf\xdd\x98\xa3\xcd6-V\x07s+\x93\xa7U\xe0'\xb7\xb2x2\x18?\xf6\x8a\xa6N\x9aH\xbd\x14\x8eE7\x84\xbc\x97\x85J\x0c\xb0\x10\xe3(\x19\xc5iw\x92.\xa6\x0fge\xddU\x95\\\xe5`rWS\x14\x94\xba.\xa5\xbc\x95\xdf\x94v\xe1\x9c]\xd1\xcd\xc1\xeb\x8d\xbbl\x06,\xbe\"\xcf\xdd%\xb9}\x12\x92F\xa6w\xe7Q\xfe\xbc;\xd2\xcaw\xf2g)\xe8\xc3\x1f\xfbz\xa5\xc7\xda\xb3Vg\xe7\xa1V_+\x7fL\xa1\x1e\x96\xb5P\x8e7\xce\xbe\xd6\xbd\x10\x9b-IF\xff\xa6\xf9\x18 \xee\xec\xe6\x86\xec\xfb8\x98\xb78X\xcd\xe4J\x80\xbe\xe4ErWX\xad\x8b\x03\xb6\xac\xa5B\x84u\xc6\xb2\x89b\xb8\xe3\x14k\x98g-\x8f\xef\xce^\xdbA\xd4\x0f\x00}eZ\xf4\xd9$\x95h\xbcj\xf29.\x9b\xa5\x8f\xbc\xcdK\xac\xd8l\x05\xe1+1\x8bT\xd3h\xc6gsU@\"\x13\xed\xe6DdP\x14\xdc\x1c\xda\xb3t\xe9\x7f\x99\xc6\xbf\xdfYZ%\xfej\xe3\xb6\xcb?\xbb\xc0\x04\x8af\xf8\xc2\xff\x83\x8c\x078~\xd2wB\xe8\xaf\x0b27Kr\x01\xf9w\x179\x8e\xb9\x14\x15`D\xcb\x10\xfe\xec\x0c%-#\xc6\xbb\x0d\xbeWw8\xbd\x1e\\ \xcc\xe7\x16k\x08C3\xcbv4\xb8<\xd8n\xc4\xf2P;\x1d\x85F\xc8%X\xa0\x99\xa2\xc5\xea\xa6*Q!R\xa4'\xad( \xfd\xbd\x16 \x94\x07\xd0\x96\xde,\xca\xd8\xc0\x998(\x9b\xaa\xa9\xab\x95\x08\xcdnn\x07\x96\xdf\xd5\xc9E\x94\xad\x16h\xabs\xe1\x7fd\xe0\x87\xd7\xd2\xf2\x1a\x95\xb0\xd2\xdf\xbb\xb5\xba[\xe9\x15s\xd1\xd9\x8fjVh\xe4)l\xe1h\xf5\x91\xb9\xda\xd4\xeb\xf1\x84\x06\x13\xef\xfbs\x19;OwM\x93\xfb\xfc\x9e4\xccw\xdc\x82\xcf{~\x05\xb2\xcf=!\xae7\x8c\xbaFh\xbf\xb9\x01g\xe9\xafVg\xfe\xfc\x833\xeb\xc9\xed\x99\x80X\xb7\xda\xeaS\xac=+\xccT\xac\xd1\xd6\x16\xbc\xa7O\xa8\x18\x1f\xcd\xa1d\x10\xa2\xf1=\xdf\xfe\xce\x01\xc6\xe0\xc4\x95\xec\xc2\xbd#H\xfds\xd4< \x98?\x13\xbe\x13\xa2uN+\xf6\xf0 `i\x9a\x97\xdeC\xff\x9b\xca.\x93\xc3{\xd3N\xdeq\xebr#4\xa1'\x13\xdd\xa31\xd9\x82!\xbfS\x9a\xa1s\x94+\xe1\xd0\xcbI\xf7\x91\"~\x94W,\x7fdI(\xd5\xc2\x8a\x7f\xbe\x8a\x12&\xcc\xf8K'\x99_\xe8\x95\x89\xdf\xdc\xc0\xeb\xafr\xf8R\x8f\xcaw\xe1\x87v\x9e\x85\x1a\xfa\xaf\x00\xa9\xc9\xc3P\x90~Z\x18!\xe1KP\x0d#\x94\xf6W\xec\xdc\x9f_\xf7\x94K\x8f\xc8l\xa6m\x18\x99=I\xb1U\x0b\x97E\xdc\xf1\"\x9f\xd1\xfcU\x0f:nIs4\x10tw\x07-z\xcc\xd20\x9ck\x06\xed\x9d\x13m|d\xc1\xdf\xadMC5\xbc\xect\xd63\xfa\xba\x15\xd8=\x19\x0f\x05\x0e\xc8\x8d[\xb8\x07\xa9xH\xc8k\"kiR\x1b\xeb\xe6\xcc!PKNCd\x06\xf8L\xd1\x19\xa0\xa8\xa1\xad\xcd\xb1\xd4\xa8\xa3m3\x04;\xd26\xf8hR\xfc\x05\xfbUPC\xdd[gZ\x1b\xd2\x01\xe4\xb2~1\xc0\xe2\x7f\xb1t\xe7\xae\x81\xa8\x16\x04\x9d6&\xd2;\x8b\xeb\xed'\xe1\xe1\xf7\xd34\x9cI\x19\x1b\xc7\xa7\xaf\x85\xc4\x81\xf0\xa9\x12\x82\xe5`Z\x90<|e\xef\xbc\x88\x0f\x06\x1ak$\xce{\xee\x9e_\x8f(\xdaV\xa4x\x0e\xed+\x8f\xbcbD\x17\x11\xe1A\x1f7_\x90\xccpV\x13\x14\xd0\xad\xfd\xb8\x12\xb7\xe5\xe7\x9c\xa6\x17\xd3D;\x8d\x8df\x9cV\\\x98*\x92\xde\xda\x82sr\xf0,\xee}T\xdc{P\xa18\xc2(\xdc~\xfa\xe6\xd9\xf1\xb1\x16O&\x01?f\x10\x84)\x8b71C\xc7\x87\x04\xd9-\x15tNnmR \x1b\xd0\x82\x9f\x9d\xc0\xee~\xf3\"{\x82\x14hXa\xad\x82\xe6I\xbd\xadc\xc9\xaa<4\x8aQ\x16*\xc03\xf7\xe0(\xecG\xede\xfc\x9dk\x8c\xc2XL\n\xc3d\x86(~G\x0e$\xbd\xa0\xe2\xda\xc9\x901\xa5\x05\xc8\xa7\x80K b\xc9\xd4Wrs\xf3\x82\x1e\xec\xef\x8d\x1e\x8aX\xa9\xfaG\x03Y\x93\x97\x8b<\xfa^\x19\xf7Q\xb2\x04\n\xc5\xd9\xa8YK/\x82\x84\xb6\x100\xfd\x01\xfe\x96\xd131!\x92\xfa!H\x1eQ'\x91\xf1\xd8\x99|\xbc\xb9A\x9e\x9b\xbf\xcc\x03Y\x1eb\xda*\xf9\xab\xd8\x04Q\"XE<\xde\xdc\x90\xd5\x02\x7f\x8b\x01\xaa\xf8;\x19\xa9J\xbdQ\xe4\x1a~)\x7f\x14\xdb.01|j\xf9\x981\nx\xb0b\x8bcQG|\"\xe8wK\xe5\xb7\xf4V\x0d\x1d\xf7.\x07\x06Q\xae\xc9\"\x06j\xb4(\x8e\xd0\x7fJ\x89\x84^\xa6\x1b\x02a\xa1:\x9fH_\x14\x11-m\xa7\x81\x08\x0c\xc5^\"$\x0d\x1c\x158(\xac\x1e\xd3P\xbb\x80<\x08\xf5A\x90\x9bFX8\xb7&\x92\xf3\x89^\xe7 \x0f\xf8\xb8\x0d\xc3'\x1e\xfc\xe0Z<\x8c\xc3|n\xb5\x07\xf4k\x9b8Z\x13E\xc3!\x9d\xe3rW\xc8G\xcb\x96\x1c\xcc-B\xf9\x88\xf3\xfc$\x91aFZH\xac<\x04[\x0c\x07\x10\xf0\x7f(\x04\x1bs\xa3i<\xab\xc7-\xdf\x1b\x0f\x9c<\x99\xdf\x99\xf6/XJ\xaa&T\xc9\xaf\xaa\xe7\x95\xd7\x1a\x8a-\x95\xb5\xe4\xb2N\x07\x06\x9f\x82<\x81C\xe0\xe6\x8aC\xa5\xa1W\x184\x085\xec\xda\x83\xb3,\x85e\x94\xf1[.\x8a\xd9\xad\x128\xe4I\x0c\xbe\xeeU\x93\x1e|\xdf\xb3\xe6+h\xd2B\xb4\xd8S\x04\x99\xb8\xcf\xaeR\x16.\xdc\xea\xf2\xd1\xa1\x1eCV\x9c\x0f\xef\xac\xb4\x1d\x12\xf8\xee\xd8\xd8W\xdaOc\x02\x87Z\xcc,f\xf3\xfd]gS\x8d\x0f\xfc\xe9\xe9\nL\xc1D\x03\xb7\x10z\xb1r\x97r<&.\x12\x89e\xcf\xb2\xe5\x92Pw\x15e\x86E\x94\x19\x8b\x9f\xf3h\x95\xad\xc3B\xa0\xd3\x1c\xee\x02-\xa3\xc19K\xdf\x84\xc1f\xc3\xd2\xa6\x05\xae\x98\xabW\xcfbG\x1b\xae\xa7\x0b\x0dL\xbc7\x88\x00\xf0\xbb\x1a\xc5\xf0pOD\xc0\x91\xf1o\xf4\xd9\n\xeb\x00~\x9do\xd3yvN\x07\xa7\xf1i\xf8\xff\xfe\xaf\x9eU\xc0\xe9\x07\xe1\x82]\xbdZ\xba\xdah\x10\x8b?M\xdd\x80\xf4\x17\x96\x90U\x01lS\xf0\xc0\xc2\"oc\xbf\x0c\x1e\xc0\x88(\x0f3\xb3\x86\xe3\x86~\xbf\x0f8\xf8\xee!\xec\x99\xb9\x946\xeef\xb8Dz\x1e\xbd\xd2Jd\x9c\xec\xd3\xa6\x97\x93Ww^\x9a\xcc\xba,n&\xd0\xf8vieZ\xacJ\xa4\xafJ\xc6\xd7\xf7\x13VE@\x94/\xd7CL\x80\xa8\xba\x80\\\x11sSJ@1\x94\xe0\xbc|4\x00\xefR\xc0\xfcn\xb9\x16t\x0d{\xde\xd5\xee\x8b.8\xbf::\x82\xd2\xcf\x90L\x19\xd86\x1b\xb5\xe3\x18\xef\xf8\xfc\xe8s\x82\x15)\x88{A($\x8f\xea\x1dFK\xbe\x87\xaarN\xb1\xf8)q0\x0e\xc6\xa3W\x98\x00\xf9\xba.\x9f\x9b\xc0\x04\xf9{Q@*\x10\xd2M0\xb9\xa096p\x85\x88\x8az\x19\xd3\xaa1\xde\xad\x11M+L\xf3\x89Hs\xa0])z\xe3\xfc2\x8e]C4\x9c$\x8d+\xd9\xfd>\x04\xe1b\x9c\xabs\x0b\xef\x94\xf7\xd7lu\xdb\xc6\xcd#\xaf\xdb\x17\x91\xe7\xf1Mz\xbdbcp\xd4z9\x7f\xf5q?\x8b\xa2?\xf5\xb8\x1bL\xa7Z\x1f\xf7\xc2\xb1N\xe3\x8c\xe9\xc7\xf8m\xf9\xf7O\xef\x9e\xcbc\xcd\x0b\xf6\xf4\x8f\x97\xfe*)\xd4~Q)x\xfa\xf2\xcd\xf3\xbb\xa2\x85\xbas|\x9b\x81\x7fN\xfc\xe1LE&\x81o\xa2h\xc5\xfcpF}T\xf2\xd2I\nT\xa8\xe1k\xe7^\x8bmL8\xc1\x9a\x82\\\xd2\xad0\x91\x0b4\x06\xb1KmN\xb1 E\xb4\xea\x8b\x16{,\xf7\xbbM_&\x8c\xd1\xae/9\xaf\x17\x96y\xfd\x1d\x10\x88%3\xe2m\xb3\x9aV\xf2\xa6\xed\xe5\xe344\x94\xb5o\xe8\xa1\xd6\x90|*c\xba\xc0\x84\xe9\x820\xfd; :\x12\xd7\xe8\xb2k#\xe0\x04v\x87zS\xc3\xca\"\x17\xee\xe4FU\xe8\x1a_\xe7\xbfD3\xeed\\\xbc\xc7\xf3\x1e\xa8\xf2\xe9i\xdf\x9d\x8c\x83pys\xcc\xff;y\xe1\xddPQ\xe8\x877'\xfe\xc9\xcd\xc9\xd3\x13\xcf\xfbZ7\xb9\xc7\x80\xfc\x98\xadW\xeb\x9c=\xb0K \x8d\xbc\xf3r\x15\xf9_\x84{\xd6\x85\xdb\xa4\x15\xe1\x88\xd6\xedD\x82\x80\xf1t\xda'\x9d\xeaf{\xb3\xcfN\xd2\x18#\xc1\xc8\x11\xc2!H2BX\x1eW\xa8\x91~\x1a\xbd\x8c.\xe5\x89\xe6\xa4\x04L\xf8=>\x06\x11\xfcw:\xeb\x81\xd3\xdd\xceu\xe7\x0c\xe9\x95#q\xc1\xb8d\xf2\xa7h\x91\x1e\xf0\x9a\xcb\x9c\xf4\x10\xa6G0\x11wY\xff\xf5\xab7\xc7o\x8f\x7f~\xfe\xfe\xf8\xe4\xc5\xf1\xc9\xf1\xdb_`,_\x9d<\xff\xeei\xf9\x95\xd3\x0f\xfd0o\xee\xc4?\x811\xb0\"\x85!0\x9b\xcb\xeeFf\x04E2\xe3\x05\x07\x9cZBCX\xe7\xc5Dh\x04\xb7\xe8\x8aIB#\xe6\x9f\xdb \x8d\x10\xees\xb2y\x8c\x0f\xda\xa8\xd8\xdf\x89\xd4p\x89\xd6\xe8\x1c\x92\x1b\x86\x81\xd4hKk\x14\xf0\xa4\x0d\xe2C\xb3l(HN\xfc\x13\xde\x17$\x97A:\xbf\x00\xd7*;\x98\xfb \xd3\xe5\x90cc-\xd0\x16\x07\x81\xcf\xcc\x1dQcJ\x8a\xdb\xa6\xb1\x93\xa7'\xb5\x8d)1m\xab\xc6\xfc\x13\x83<6\xf7x\xb6\x1e7!\xf4\xfb\x12\xab\xc5O\xfeg[\xad\xe3\x93\x17\x9fo\xb5\x8e\xc3e\x9b\xd5\xaab\xa0/\xb7Z\xdb\x9fu\xb9\xb6?\xebzm7.\x98\xe9\xb4\xe7\x9f\x0f\xfa\x03\xc3X\xb4{\xa9H\xf6\xf6 S\xc9\xbc&\x10\xaak\xcaa\x0e\xbfP(\x02fX\x87L\xfe,]C\x99\xfc\n*\xe4\x97\xa2\x8e\xb4\xffy\xdb\xae\xed\xc7\xd7N#A\xd7\xd8\xe2\xa4\xf4\x8b\x93no\xd3\xd9\xcd\x14NO\xd3Y\xd7+\xbc\x1c\xeb\xbd\x17~\x10}H%\xf7=\"\x10\xb1\x85\xfb\xee\xbfn\\N\x8by\xe5n\n\xdf{\x13\xcf\x9b\x14(\xb9V\xea\xdc4X\xb3$\xf5\xd7V+\x96\xcfN\xac\xe5\xe1\xca\x83>\xbbbsA\xb3\xa9\xd2H\x96~\x01r\xcd\x10\x07\xc5\xa23\xd9\x08\xb7L\xf3\xb5\xa7\xf47H\x81\xa9yx\x8a(\xcb'\xa1\xe7'\xf74\xf3\xee\xe7q\x1c\xc5\xae\xf3\xad\x9f2\xe5K\xcbx\x99)(S \xf2\x89v\xd9t8#\xda\xa7\xcb\xa6\xa3\x19y+e\xf4sg\xd6\x83\x0e\x9b\xee\xcer\xf3Wv \xbc\x03\x97\xff\xaf\xff\xee\xed3W,\x83\xc9\xff.\x10\xe1)\xba\xbc \x8aN\xd1e\xd3\xbd\x19\xc5\xa5\xe8\xb2\xe9\xfe\xac\x07l\xfapfC\xc2(p\xc5\x80\xb7\xd3\x873A\x94\x0ez\xb0\xe3=\x81U\xeeK\xb9\xf3\xc4\x83\x15\x1a\xf6\x99\x90\x14\x88\xa8\xd1\xddU\x15\xfd\xd9\xc0\x8bM\x1f\xcfp\xe1\xf9\x9e\xed\xb3]\xb8\x0f\xee\xfe\x00\xee\xe3j\x0df\xd0\x85\xae\xcb\xa6\xc3\xe1\x8c\x83\xd9@\x8a\x00qC\xf4/\xb77\x9e\x88\xcb`]6\x0dzV\x1eFS\xdf\xda\x82e?a\xe9\xdb`\xcd\xdce\xff\\\x93?\n\x0d\xda\xa5\x0b\xce\xd3o\x9e}\xfb\xfc\xc5w\xdf\x1f\xff\xe3\x87\x97?\x9e\xbcz\xfd\xdf?\xbdy\xfb\xee\xe7\x7f\xfe\xcf/\xff\xf2\xcf\xe6\x0b\xb6<\xbf\x08~\xfb\xb0Z\x87\xd1\xe6\xf78I\xb3\x8f\x97W\xd7\xff\x1e\x0cG;\xbb{\xfb\x0f\x1f=\xee>8<\x0dOc\xe7\x96\xec; x\xbe\xc4\x86\xddY\xfbm\xc1\xd3A\xa3b\x9cc\xc7\xc8\xa2\x1e\n)\xf2_H\x1eCa\x9d\x8e\xa8\xe3\"b\xcfr3vi\xbcN1\x00a\x7f\xb7Qk\xc4\xe0\x00\x06\xad4?(\x13\xdf7\xbe\xb6\xe2\xc1\x18\xfe\x0b\x1e\xa1\xf0\xb9\x08\xf6\x9f|q\x06E\xe9\xc5\xf44>\x0d\x0fgB\x86a_\xf4\xa0v[|\x8c\xffc|\x95\xd8\xb7{n\xd1\x07)\xff\xee\xc1\x13\xe0\xab\x9c=\x01\xd6\xedz\xc0\xe0\xbf\xd0\n\x8c\xe4%\xa4\xce\x99\x8b\xfc\x10pt\x04\xc3}\xd8\x82\xd1\xde\x9e\xd7\x03\xbd\xf8Q\xb9t\xb4\xb7\x07[\x90p\xa4\x9f`\x12\x90\x83\x03\xd8\x87\x1b\xf0\x158\x04\x12\x1c\x98\xe9r\x15[4\x00\x19\x087\xc3\x81\xdd\x87}T\xd1|\xd2\x90`\x0c\xc3GJ\xd0Slk`lk$J\xf1S\xe1q\xc8\x97F\xaf\xb3\xab\xbe\x8c1\xe9\xc62\x8e\xd6\xea\xc1\x9d#O\x80\xe8\x1e\x1f\xe7u w[\xa9\x08\x06\xf6\xe0,\x0e!\xd0\xf6Z\x93\xb6\x00\x1d\x93s\x8b\x15\xa1X\x80/k\xc45~\x0d\xae\xb1@\xe7N :\xf1\xe4\xfb\xd3\x00\xb7\x8fo\xfa\xfe\x0eR|Z\xe9\xc8T\xba_*\xdc\xdf\x81-@s\x1c>#7\xe0\x10\xfb\xc8\x83.\xa4SfW\xa8\x16\x01t\x87\xf4\x87\x9fyD0\x86Q\x0e\xae\x85v\x06\xa6vv+\x85\x07\x07P\xeeq\x7f\x17\x1b\x1e\xe6\xc0\\h\xb9:\xc0\x83\x83J\xc3\xfb\xbb\xc5\xf6z\x10\x17\x01O\xfd\xfad\x02\xc2\xca\xceVd\x7f\xc58\x93U\x02\xc1*,\xbc%\x89\x16\xd5x2X\x9c9>\xf1\xca\xb7\x19\xf2\x97\x985\x12\x83[o\x03C\x80\xca\xfc\xb8\x91>z\xae\\\x83\xf9\xe1\x0b\x9f\x90 \xd8\xea6\x16\x88|\xa1\xf3)\x9b\xe5I\xc0\x94\xa8\x96\x16|\xe6\x08f\x15E\xb2q\xb3=\x87\x08\x84\x13\x84\x10\xd7\x1b\xf0\x04\xa2Id\xd3j\x08\nY\xdfo\xecZ\xfe\xdd\xc9P\x07i\x9f\xe6>x5a\x81\x90\xa8;1k^\x16\x11\xce\xa2U\xd2\x0e\x058\xc5SyG\xfa\xa6*\x9c\xf8\x93<\x8cZ\x1c\xfa;\x9e\xe1\x8d\x1f\xc4\xc9\xdf\xeb\x10\x0b\x7f\xdd\x9a\x83\x9a\x89\x19=\x8dc\xff\xda\xf5\xa5\xdb\xa3R\xf4\xf0\x13\xec\xdf\xed\x04\xfbx\x82\xcd'7h}r\x03\xf4\xe1G\x93!\x0d\xe1~`\xd7 \xff\xba\xec\xd6ok%\x9b\xb2\x19Ge\xd1t\xc0o\x19\xfcw6\xfb\xd3\xa1\xde\xb2\x8f&\x9a\xfac9\xd4\x99\xf0\x06\xb6\xeccT\xd8\xc7\xcc\xb8\x8f\x99m\x1f\xf9ne\xb8[Ae\x89{\x10\x89\xb5\x0b\xc4\xda\x05\xb8vV\"&\xfa\xeb\x0fp\xf1\xd6\xbe\xe51N\x98Uun\xf6)\xfcrg\xb8\xf6\x82\x0dB\xb0\xc4\xfe\xd2\xee\xb1\xb0'L\x10\x15\xa2\x0d\xa7lV{\\>/\xc4\xdb\xf0\xfc\xdf\xcd\x8f\xf2\xb7\xe4A\x16.\xd82\x08\xd9\xe2\x13%/5\xcbp\xfbE\xf5*\x19\xe6o\xcb\xcf}\x8c\x82\x85\x8c(V\xd7\xbb\x89\x93\xab\x13\xfa\xfd\xcd\xbc\xa1\x7fK\x1e\xc4\xec\x9c]}\x11U\xca-\xe4f\x01F\xa6\xc1zm.'\xe5Mg\xa6\xb19\nxp\xfa\xc0\x9d\x9e\x07\xeb\xd9}\xef\xeb\x07R\xb3a\xae\x1e\x1bb\x0c\x80\x18\x94\xf3@\x8a\xdd\x07V%\x02i:\xa4\x05o8\x1d\"\x1b&\xd5\x07G\x9c%mq]\xf3\x9e\xd0\x9aw\xcar\x03\xa0\xb8`\x0b\x947Si\xe5K\xdf\xc1\x7f\xce\x8a\xcbS\xa2-:\xa9\xdf\xca\xab[0\"\xea\x81e\xc5P\x93\x95kFY\xaf\xcc\xc7|\"\x92PT\x1au\xd0\xd6\x14\xe6\xb6\xf8\xa4vC\xf8Zu!\xed'Q\x16\xcf\x19ty\x81ua\xd3\xfe\xf9*:\xf3WB\xe7\xd7=\x04\xe7\x9cB\xf5\xe5\xa9\xe7\xf3Wkz\x15\x9c\x87Q\xcc\x9e\xf9\x89\xfe.\xe0\xef\xd8\x97BfO\xb4J\xea~\xd1\xa21]\x06\xe1\"\xbaT@A?\xfb,\xd9\xc4\xc1\xda/\x19\x06\x06\x8d\x98\xd1\xa8N\xf8-y \x07\xff\x17\xe3\xc6\xaa\xbaF\xfe)\x18p\x11\x06\xf8\xe6{\x16\x11!\xc8\xf48}4\x0e\xe3g\xa1\x9eM\x8f\xfd\xf0\x9c\x8dkyo[TQq8^\xc7\xd1y\xec\xaf\xe9P\x84\x18\xfb\x8e\xef\x98\x0c-v\x16-\xae\xb58<\xce\xf3+\x0e\xf9I\x10\x85oR?ek\x16\xa6\x8eVu:\x98\xa9&\\\xe7i\x1cG\x97/\xc4\n\xe7_\x96?`\xea\x0d}\x8bN\xcf\xb7\xfd\xca\xc0\xe6\xebZ\xb1\xba5hD\xd4\x9f\x84\x8eEt\x9c\xe6\xcd\x0f\xb4\x8d\x0f\xeb6\xbe~\xd3\xff\xb0`s\x9b\xc3\x0b\xdej\n\n\x88\x81\x95\xdb0\x14\xbfu(\xe0\xbbc\x84\x82\xbc\xaa\x82\x02^\xd7\n\x04\xc5\xfae \xe0\xc0v\xeb\xaf\x0cf\x10/\xfc`\xc5\x16\x90F\xca\x16B!\x0c\xbb6\xc5\xd8\xc1\xc6\x8f\xfdur\x0b\xab\xd0H\x06T\x0d\xfd\xb5 >\xc5\x0di\xec\x0cW\x1c7\xba\x07\xce7\xabh\xfe\xa1t\xde\xec_\xe1\xf2Mp\x0d\xe4\x02\xbaQ\x0fB\x199x\x8a\x96\x0b\xfc>\x9e\x0egt\x01\x0b\x95\x8b^\xdd\x91\x08\x02#F\xe5\x9f\xd2g\xf5&4w\xbe\xa1\xe5\x00\xfe\xd4;Z\xdd\xba\xcat\xed\xcb\xda8X<\x00\xf6F&\x8b1\xf7\xd1N\xa98\xa3\xda\xe5b\xbfN\xdaW\xac\x9a4\xcb\x15J\x08\x0f\x0e\xe1q\xb1h \x870,i\xb3Vp\x08;\xa3\x12(\xf0\xb2\x9db\xd9\x05/\xdb-\x96-x\xd9^\xb1\xec#/{X,\xbb\xe6e\x8f\x8ae\xe7\xbc\xac4\xbe5\x1c\xc2ni,\xefyY\xa9\xdf3^V\xea\xf7\x12\x0ea\xaf\xd4\xc7\x15\x1c\xc2~\xa9\xbd7\xbc\xac4\xb7\xe7\xbc\xac\xd4\xc7S\xbe|%7\xc4W\xbc\xac\xf4\xedo\xbcl\xbfX\xf6\x01\x93\x15\x96*\x1eca\xa9\x97\x1f\xb1\xb04\x95\xb7ph\x80\xf8\xc1\x18\x9c\xd3\xd3\x81\xe1\x1ez\x88o|\xc3\x9bG\xf8\xe6\xcc\xf0\xe61\xbeI\x0do\x86\xd4Qhz5\xc4W\x1fM\xafF\xf8jiz\xb5\x83\xaf\xca\xd4\x1c\xff\x1b\xd1\xd0\xcbBh\xfe\xb7\xb3;\x86{\xa7\xa7\xce=\xc3\xd8\xa9\xaf\xd3Scg\xd4\xdb\x89\xe9\xdd>M\xed\xbdi\xa5F;\xd4\xeaK\xf3Kj\xf5uI\xc6P\xac\xfa\x8c_\xd6\xce\xb5\xd3\x03\xe7\x17\xfe\xbfk\x96\xe0\xb3\xf8\xe7\xf9\x1b\xfe\x0f\xd2\xbc\xce+\xfa\xff \xff?>\xd2S\x84\x8f\xf4\xffWX{\xb9\xc4\x8a\xe2\x9f\x17/\x9c\x99)\x90\xc6\xeb*\x92\xcc\xc5\xb5%\x0d4Y\x9e\x1c\xd6z\x93\xf5(X\xc6ho\xcf#B\xe8\xca\xa1h\xbd\xa3b[\xca\x02\x19\xab\xef\xef\xed\xed\xc8\x0f2\xf1\xc1\xae\xe1\x033\xc9\xde\xa1FvG\x8fw\x1f\xef?\x1c=\xde\xf3\xbcb\xf8\xdby\xb4`\xb0\x89\x82Bz\\\x8av\xb8\xf6\xafe\xda\x85\xf3\x98\xf9)\x8b)\xf3\xc2\xe0\xea\x85\xf83\xd1\x0d8\xd0wb\xa0\x8f\x8a;[\xf8%o\xbc\xd3SG\xc4p\xcc\x836\x0e\xf0\xfbm\xc5'{\xd0\xd5\x987S\xb0\x92\x9f\xaa\x9b\xa5\x85\xac\xc6\x9d\xc9crG2\"\xb6\x0c0\xfd\xa3\x9f^\xf4\xd7\xfe\x95\x8b\xf9\xc1E\xf1\xcd\x0d\x8c<\x19\xda\xfbC\xb09\x0e?\xfa\xab`Ami\xbf\xf58\xdc\xcbUt\xf9\x92}d+\xa4`\x83\xe4$\xe2kz\xee\xa6\xf9\x1bO\xfa\x1fie\xb2\x97\xf4z%\xe2m\x17\xaeU\x1bE]\xcd\xffkH\xdfU\xe0\xdcrw\xfe\xff\xfca\x919\x87\"\xfb \x19iP\xc6\xd5\xb8\xa40`J'C\xce\xff\xd1\x13\x8a\x88:\xa4\x8c\xe4\xf14\x10Z]q\x16\xd84C\x0f\xeeN\x87\xc8\x99,7]\x1d\x91A/\xff\xcc\xc0\xd5r\xd0\xc8\x94\xff\xb6\xd7\x03\x97\x12\xb8\x95B\x90\xf7eV!\xde\x0foOdt\x98\xf7u7\xcb\x1e\xf8\xd4\x99\x8f\nk\xfd\xd5\xd4\xe7\xe3\x0b\xa7\xd9\x0c\x0e\xcb\x91oA\x13p\x17\xe1\xd9\xd5@\x8c\x03\x0e\xb6\x98H\xf3H\x05;Q\x9c\xfe\xc0\xae)\xd5\x8c\xfaQ\x8c\xde\x1e\xb2\x7f\x06\x0b\x19=]\xfd\xba\xb9\x81G2\xf6y\x18\xfd\xc4\x96\xd4\x86x\xd4[\x08\xa3g\xd1z\xe3\xa7?\xf2\xe3Lu\xb4\x02\xbd\xe6<\xe2\xd0\x8d\xeeV\x97b)\xb5\x02\xbd\xe6\x1d\xe2\xc5\xcb\\Du\x9f<\xbf*\x86\x98\xc7\x9cWa\x1e\xa6\xbe\x98I\x9a\x97,2\xfe\x85\x9f2a\xa7@\xa5Y\xc2\x16\xdf\xeao\n\xc1\xfdL8\xe2\xc4x\x98\x10\xe8\xc5i\n\xe0\xb0\x14:\x96y\"w1)\xe6\xb6\x87\x04\xd7|l\x89f\xaa\xf4\x04\"8\x80\xe4\x89\x879\x1a\xd0j]\xa6\xe6\x17n|\x98\xf8?\xf2\xd0\xda\x87\xfcCD\n\x0b\xd1A\x82\xa9\xdd\nox\x97\x14\xc65Bc!z\x0eu!\xc4\xa9\xe0\x03C\x01\xd7\xddC\x08<>\xc4\xeea\xd9\x9dL\x80\xb0_\xbbD/\xebbo\x9bc\xebJty\x1f4\xce\xce\xd4\xf6\xb7U\x14-\x19\x0e\\\xb1\x15\x87>z\x9c\xd76\xf4okC;\xa3b`\xaa\xe1h\x1f\x99\xf7\xfda9\xf2\xd5\xe8\xf1\x1e\xff\xc5)\x94\xdcm\x82\x93$\xe2\xd7\xcd\x0d\xec=\xdc\xd9\xdd-~\xc7/\xe3\x1d\xfe\x8b\x92Q\xa8\xaa\xbc|\xbf\xd4\xf5p\xb8;\x1c\x0ek'\xf2\xc2:\x11\x9cb\xa9\x1fl\x99?\xbe\xcf\x1f\x9f\xe6\x8f\xaf\xf2\xc7\x0f\xf9\xe3\x8f\xf9\xe3e\xfe\xb8\xa8\x1d\xd6;\xeb\xb0\x1e\xfcz\x1a\xde\x07\x19\xc8D\xdfn\xf9\xc4\x0f\xd27\xd5X#\xbfs2\xa7X\xf4\x0b\xe7U\x8aE\xff\xe4\xb4M\xb1\xe8g\xc0\x88\xd2\xd5A\xfeP\x1fg\x9d\x8f#\xd2\xed\x9b:\x86\xe8'sK\xf9\nO:\x85\xfa\xa8\xbe}Kx\xa0R\xce)\xd5\x7f\x8b\xec\xa3\x85\x04%\xa5\x9d\xc4x<\x9do]\xba\x8c|,;\xcb\x1f\xdf\xe4\x8f\x97\xf9\xe3\xfb\xfc\xf1i\xfe\xf8*\x7f\xfc\x90?\xfe\x98?.\xf2\xc7\xeb\xfcq\x9d?n\xf2\xc7\xe3\xfc\xf1*\x7f<\xcf\x1f/\xf2\xc7\x8f\xf9\xe3\xf3\xfc\xf1713{V\x17C\x82\x07\x839\x8a\x97\xbf\xed\x10\x0bb\xf2\x06\x0e[\xff\x13a\x05c\xdd\xef\xd7\x9a\xcdS\xff\xe3m'@\x91\xdd\x9a'\x02\xe2\xe6\x8a\xa7\xa3\x861\x83\xca\xffB\xb3\x9c\xa3\xfa'\xe2'=\x81.\xe7\xf50\x9b=_\x07Q\x01&\xfcqL\xc9\xeb\xa0\x0b\xffp\xe7\xc4L\xa2\xd2\xa2\xb63{\x98K\xc8A1\xb2V\xfa\x83\x83g\xe65A\xfb\xcf\x8d\xd0~\x0f3\x934+\xf7\xe4\x9fb\xa4s\xaa\\p\xcaV\x1aI\xc8LK\x84\xd0\x111h\xfb\x80\x0e;\x9c]\xdb\xdf\x19\"\x11P\x8dO\x1a!WL\xdf\xec\xef\x8c\x06\x90\x07+\xdd\xd9\xdd\xe1\xcc6\n\xa6^\xbb\xc3\xc1\x08\xbd\x96\x19lS\xeb\x949f[|\xd6%\x1e\x8e/\x1b\xa7\xdd\xc6$\xf3z+\xcce\xbb\x87\xd0AJ\xe6\xdf\xfc\xe2\x99@:\x8df0\xa6[\xee\xb5\xd9\x1bM\xff\x93\xba\xd4\xba=\xf3(}\xa8\xb9!\x11\xfc\xc1\xbee\x05\x99n\xb0\xdeDI\x12\x9c\xad\x84\xb7\xfb\x18\x02!\xaa$\x0b\x10\x8a=\xe64\x11v\x7f\xb8\xf5\xfc\xfc\xd7\xf64Rp(\xe95)\x00\xc4\x90k\x06-@\\D&\x85XRF\xf9E\xc8\xcf\x1b%\xd46\x7f7\"|\xa4\xde\xf1Q8]\x07\xb7K\x1e\xcam\xbalNC\xa7v\x86\xdf[\x19a\xdb\x909l\xe4(u{\x88\xb9/\xa9\xf4\x85a,\x8a\xf8\x99\xb2\xf1/E6\xfe{G\x98\xa2_\xd0\xfe1\xf8\xf39\xdb\xa4 \xaa\xde\xf0\x06^QN0\\\x81{M7MqZ\xd3\xd5\x8cff\xbfy\xecW\x8ad\x87cc\x95\xda\x90\xd3\x06\x83,#\x9b\xdf\xa9\x97\x8f\xfeOA\xc6G\x87\xbe\xcc\xb3\x17\xf4\x07r\xc8a\x8f\x8er\xd8\x83\xce\x10C\xdf\xa8\x9f\x03Cj\xe0\x04\x14\x94P\x13\xe5$\xad\n\xf9\xe9,\xed\x01E\x85+r\xb9\xe5\x14\xa6\xbc\xf9y\x0fV=\xb4\xff\xa8\xbaIq\x00Ea\x87z\x85\xbe=\xf2MU\\\x86\x02;W\x93P\n\x8dX\xae$Q\xbbM\"@-al~\x13\x18\xda\xd1\x8a\x1aZ\xd4?.\xa0:\xa5\xee\\g Z\x12\xf8pF\xa9n([y\x9d\x05\"\x14D\xacDB,\n\xfa\xb6\xec \xf1`C\x0fE\xf6\x9c\xd5\x10\x1b\xceW&\xe2@\xedb\x1c$\xa1\xd6\x12\x91%\xc2)'p\x16\xd3h6\xeb \x1cCf\x80>\xe5`\xa7\xff\x08\xee\xf1t\xb58A\x02\xf8\xf1l\xf0\xa7\xdc\x9b\x823\x1e2\xeb\xbb\xac\xb3\x14[\x875\x8b\xc9\xcc'\"r\xd3\x84\x13\xaa\xe2\x11\x1c\xe5\xf1MS-\x1d{?\xf1\x97\xec\xdb\x92\xb5B\x8d\xe5\x1eM1\xee\xb3\xab\x94\x85\x0b\xb7z\x8e\xc8Fs\x0cYq\xb7\xf0\xc6/\x8d\xeeN>?\x02\x90\xc85V\xba\xd6\xf0\x83\xed\xbc\x7f\xcf\x92\x1f\xa3E\xb6\xaa\xc6.\xfd\xe8\xaf\xb2\xa2w\x1f:\x8a\xf5\xcfY\xfa,\n\x97\xc1\xf97\xd7\xefb\x0c\x86\xdb_D\x97\xe1*\xf2\x17T\x0e\x87\"\x1eB>\x80\xdc\xe9h4\x18j;h\xf8\xd4\xae\xf1*\xdb\x16\x18\x15\xbd\xa2\x92;\xe0C]\x86\xfd%K\xe7\x17^\xc5E+\x9f\x93qJmvU\xd51\x92-\xca\x97\xb8\x9fl\xd8\xfc)\xd6L\xccH2\xf7\xe7\x0dJ\xcb\xe1\xa6^?\xbd`\xe8\x07\x17\xe9\xe9F\xe5\x9f:E\x91y\x14\x80\x9aSM\xbe\x8c\xce\x88\xa8.\xed'\xa9\x9ff \x1c\x1d\xc2\xee\x00\xd3[\x04\xfdl\xb3\xf0S\xf62\xf2\x17Ax\xfe\x06\xdf\xbb\xce\x12\x1d\x17i@\x9c\xb3\xb8e\xb5w\xf1\xcaux\xc1<\n\x93h\xc5\xfa\xa8\x14se\xffo\xd9U\xaa\x91'Y\xbc\xe2@\x86\x17\x07R\x89\xcc\xe5[)\xdcQ\x7f\xf1\xd7+\xea\xc1s\xc3~\xca\xae\xca!\xb4\xa1\xaaF\xfb[\x9d\x1f\x1d\xf2\xcfY\xda\x12\xd2R^\xf78t\xcbw\x15L\x80\xc1\x18\xa6l\xf6\xf7\xc2\x12\xa5s\xaf\x08w~\xfa\xf7\x0c^\x84H\x91\xcb\x1b<\xef\x0b&\x10\x83)9\x93\xd4\xc7\x96\x83\x17\x16[F5\x9a;\xdc\x7fT\xea1\x11#\xd9-\xe2!j\x93\x02I\x92\x0b\x06\x07\xbcL\xbe\xf0\xdc\xa0\x07I\xff\xdd\xebo\x9f\xbe}\xfe\xfe\xd9\xab\x93\x17\xc7\xdf\xbd\xe9\xb5\xdc>\x0c\x0e\x8d\x80\xeccp\xd1\x7f\xbc\xf1\\\xd6\xdf\xf8\xd7\xfc\xa8\xeb(\xde3\xf7\xfa\xf6\xd5w\xdf\xbdl\xdb\xab\xbc9U\x07f\xb5/\x02UEt\xa2\x86\x9c\xf0\x97=\xe8\xc4\xc5\xd1\x05\xc2\xf3t\xe6}\xc5\xf7\xf9\xc1\x83\xff\x03\x14J\xe2G\n\xdb\xf4\xee\xa7\x97\x87\xc9\xa5\x7f~\xce\xe2\xed,\xd8\xe6xg\xe1\xaf\xa2\x90m\xa3N$\xed\xff\x96\xf4\xd7\xfe\xe6\xff\x07\x00\x00\xff\xffPK\x07\x08v\xf2\x8aA\x86\xba\x01\x00\xc5\x87\x08\x00PK\x03\x04\x14\x00\x08\x00\x08\x00\x00\x00!(\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0e\x00 \x00swagger-ui.cssUT\x05\x00\x01\x80Cm8\xec\xfd{s\xdb8\xb27\x8e\xff\xff\xbc\n=\xbb\x95\x9a\x99\x1dS!EQ\x17\xabf\xeb\xc8\xb1\x93q6r\xc6\xcem\x92\xad\xad)\x8a\x84$\xda\xe0\xe5\x90\xd4\xcdz\xf6\xbd\xff\x8aw\\\x1a $;s\xf6\xf7\xad\xb3\xd9dl\xe2\xd3\x8dFw\x03h4\x00\xb2\x9bl\xed\xe5\x12\xc5\xda\xda;\xfc\x9fN\xe7\xe5\xdf\xfeo'\x08c\xdf\xc6\xde#\xea:I\xd2\xd9\x0c\xbbzW\xef\xfc\xbf\xce\xec\xfac\xe7\x9d\xe7\xa0 A\x9d\xff\xd7Yz\xe9j=\xef:\xa1\xff2@N\x88\xed\xe4%M\xf7\xb7\x97\x8b0H\xb5\x85\xed{x\x7f\x9e\xd8A\xa2%(\xf6\x16\x13'\xc4a|\xfeWs\xde7,\xe3\xdfD\xfd\x9dU\xea\xe3\x03\xf6\x02\xa4\xad\x90\xb7\\\xa5\xe7F\xd7\xb0&\x9a\x9fh)\xda\xa5Z\xe2=\"\xcdv\xef\xd7Izn\xe8\xfa\x8b\x89\xb6E\xf3\x07/\x85K)\xce\xf3\xd0\xdd\x1f|;^z\xc1\xb9N\x95\xd8q\xea9\x18\x9dQ\xcf\x12\xcf\xa5\x9f,\xc20E1\xf5h\x85l\x97y\x14\xd8\x1b\xea\xf7\x049\xa9\x17\x06\x07\xd7K\"l\xef\xcf\xe78t\x1e\xe8\x16\x1b\x87\\K\x99\xf0\xe7=\xe4OJ\x19\xbb\x83!\xf2;\xb4\xa4\x0bo\xe9\xd8Q\xc6\xf0\x8cy\xbc\x8eii}\xdb\x93UZPT\xea0\x90\xdf\xe9\xeb\xd1\x8e\x96+>T\xca\x9d\x87\xbbL\xe4\xdd2\x1f:\x16a\xec\xf3\xca\xfbg\xba\x8f\xd0/1JP\xfa\xaf3\xbe Y\xcf}\x8f)\x01*\xcbf\xb5\x92\xa2(\xfdW=\xb6\xdaQ\x84\xec\xd8\x0e\x1ct^\x14\x01\xd5\x974\xe7\xe7\x9a\x1f>j\x8b\xd0Y'\x9a\x17\x04\xcc\xd4C\x8a\xaa\x04-\x85o\xc1\x16\x95\xf3 \xde\xeb&\x91\xed\xba\xd9l\xa0K\xda\xd0\xb0\x89\xbd`)n@+\xae\x92^\x02,E\xa7\x11\x87p\x9df\xbevnD\xbbr\xec\xed\\\xe4\xc0\x8fh\x972\xb3$\xc2n\x82\xd2C\xd5\xb0\xaei!\xbf\xd3\x1d\xe6\xff\x0e\xb8a\x01\xa3%\n\\h\xda\xac\xe7\x14j\xd6$\x9e\x16\x83a5\xacW\xdd>\xb5\xe7\x18M|{\xa7m=7]\x15\x1d\xa5\xd6\xf2d\xbb\xf2R\xa4\xe5\x83\xf4y\x11y1Sl\xb8\x8cQ\x92\x80\x83\x8f\xd2(Xw\xe1\xbaw\xd9\xeb4\x04\xac\xeb\xac\x90\xf30\x0fwP\x1f\x89m\xd7\x0b\xffu\x92Vd\x0e\x15\xac\xfd9\x8a3\xef-\x19\xe7^\xa9%\x91\x17h@\x17\x14\x10\x85\xeb\x94&:\x94C\x90\xa0\xa1 \xb2cg\x05v\xdfLY\xb9\xc7LJ\x0f\xd3\xc2\xc5\"A\xe9\xb9\xd6cB+\x8aU#K\xf1@s2nX\xdc\x06\x11]\x13\\@\xd2q#[C\xbf\xf00\xd2\xd6\x11\x0em\xb7R\x82pt\xcaG\xed\xcaO\xe9X\x00\xa5\xb6\x87\x13:\nE\xc1Z\x12\x85&k\xdf\xb7\xe3}\x8d\xc0^\x92j^\xca\xf4*\xc7\x0e66\xec\xc4\xb4V\x8b \xed_\xcc$\xe4G\xd8N\x115\x93Rd]\x17\xcd\xd7\xcb\xce\xdf\xa8q! \xb1\xe7v\x96!v\x01\xac\x96\xf7;\x90\xe2\xaf\x8b\xc5\x02\xa2\x98c\xdby\x80)\xd8\xf8\xa7\xa4X\xc6\x9eK\x04Ndx\xdbY\xc7\xf8G\xd7N\xeds\xcf\xb7\x97\xe8e\x14,'Y\xf7\x1d\xf4\xcf\xbc\xcf\x17\xef\xef\xb6\xfa?\xde,\xc3\xe9t:\xbd\xf9\xf0iu\xf5i\x99\xfd\x98\xffs\xfdj\xfau:\x9d^^]\x0e\x07\xef\xb2\x07o~\xbf{\xfd\xe5\xd7\xbb\x8f\xf3\xde7\xdd\xed\xbd\xde\x7f\xbb\xbd\xb8\xf8\xf6f\xec}\xfbp\xf1v\xfe\xe5u\xf0\xed\xf3[\xfc\xf5\xcb\x9d\xe58\x18\xff\x96\x11\xecW\xd1\xe7\xd7+\xfd\xcb\x951{\xef\xdfl\xe6\x1f\xacU\x81\xb7\xfa\xf3\xdf\xa7\xc5\xff.\xb7/\xd1\xaf\x17\xab\xaf\xbd\x14\xbb\xaf.\xbco_\xdch~\xaf{\xc3\xe1\xfa\xe5\xb5w\x11}\xbb\xd4\xbd\xcf\x8f\x9fofW\xc6\xf6\xb6\xf79\xb4?\xad\x06\x8e\xff\xf9#z\xb0>}5\xa3\xf8\xeb#~\xb8\xbe\x1f\xfd|}\xb9\xeb\xbf\x0fV\xa9\xf3\xc6\xc0\xee\x9b\xab%zc$\xf3`6@\x97\xba\xf7\xf5\xcb\xdd\xe6\xab\xffi\x90\xfd>\xff\xf2Y\xff\xfaa\xe4]\xff\xba\x1c\xa07\xc6\xd6}\x93\x8c\xaf\x1f^?\xcc{o\xf1\xf5\xeb\xd5\xcd\xa7W\x17\x97s\xf3-\xbe\xbe\xfc\xb4\xbe\xf1\x8c\xfb\xd9\xc7\xab\xdd\xf5\xa5c\xbd\xbb\xbf2\xde_\xce\xf67\x1f\xb6\xcb\xd9\xfdtw\xf3a\xb4}\xffa\xb4\x9b\xbd\xd2\xb7\xb3\x8f\xe1nv\x19\xeeg\xaf\xa6\xcb\xeb\xea\xef}\x7f\xf9\xdb\xafo\x1f\xbe\xddG\x1f\xee\xae\xbe\xd6\xf28\xfe\x9d\xff\xdb\x87\xb7\xa1\xfb\xeb\xdd\xf6\xbd7\xda\xb8\xa6k\xbe\x0b\x9c\xc7w\xfex\xffm?\xda\xbd\xff\xf8`\xbd{\x9c\xee\xdf=^\xef\xdf\xfd\xfe\xf6\xe1\x9bg<\xa2/\x96\xfe\xf5\xf7e:\x0ff\xf7\x04\xdf\xabo\xbf\xdf\xdc;>\xde\xbao\xf0f\xee]\xec\xbf\xbd\xf9:\xf8\xfa\xe5\xed\xc6\xfd\xfdv|\xed]7:xcl?~\xd2\xc7\xd7\xfeJw\x7f\x9d\x0e\xde\xed\xc7kg_\xdb\xe2~\xde\xd37\xe8\xcd\xeb\xed\xbb\xc7\xab\xf5\xec\xd58\x9d\xe7\xfaY\xa5\xf37\xd6\xe3\xfb\xe0F\xff\xe4\x7f\xa6d\x9e\x07\xb3u\xa9\xd3\xf5\xd7\xde8}g\xaeV\xce\xab\xd1\xee\xdd\xfdt\xe3\x18w\x96\xf3\xe6\xd3\xe6\x93\xff\xf9qn~\xde\x7f\xed}\xfe\xf0\xed\xcb\xd7\xfbk\xef\xa2?\xff\xb2[;\x8fQf{EY\n9\x9c+\xe3\xe6\xfd\xc3\xdd\xe6\xab\xf99\xfd\xf6\xc5\xd2?|\xba\x1d_g\xb6~e=\xd8_n\x07\xb3\x8fw\x97\xef?~\xed\xdf\xe8\x9fz7\xfa\xe7\xd7\xb3\x8f\xaf_\xdf\xdc/{\xb3\xc7o\x97\xb7\xf7\x0f\xdb\x9b\x87\xdb\xfe\xec~\xb9\x9d]]\x13\xfc\xf0\xda1\xefVs\xff\x06\x13\xfc\"\x9a\xdf\xad\x1a\xbf\xcb\xe8\xd2\xf1?\xaf\xdc7\xe3\xfd\xe77\xe3\xcd\xfcR\xf7n\x0b\xfd,?\xbdYm\xdc7\xe3G\xfb\xcdx{}usy}y\xbd\x9d}\xfc\xb4\xfc\xc7\x95\xb1\xfa\xda\xc3\xeb\xbc\xec\xd5\x83\xf7\x9b7\x1d\x95v\x1a\xdc\xbd\xf9\xbc\xb7\x7f\xff\x86\xbf]}\xdb\xcf{\xfa\xd21\xef2\x1d\x0e\xec/\xd6\xa3\xfb\xe6\xf5\xfak\xef\xf3\xdb\xbbK\xdd\xcb\xf0\xef|\x1c}\xbb\x0c\xcd\x9b{g\x7f\xfbpk\xde\xdc\x7f5o\x1f?\xedf\x9f>\xf5n\xef\xdf\xbe\xba\xd5?\xedo.\xa7\xfd\xd9\xc7\xe9vv\x7fe\xce>\\\xd7\xfc\xbe\xbd\x19\xdf\xbb_\x0c<\x0f\xee\x08~w4\xbf\xc7V~\x9bL\xf6w&\xe0\x93\x99\xaf\xbe\x1a\xe7~\xf9\xe9\xe1\xeeM\x81+\xfa]\xde\x0f?\xf6\x97\xbf]\x8e\xfb\xce\x9b\xd7\xf7v\xef\xb3~\xfd\xe6\xf3:\xeb\xef\x8ew\xfd\xf2\xb7\xe4\xe2\xc3\xcfof\xd9\x08q\xff\xe1\xd3\xdd\xc5\xe7_\xef\xed\xaf\x9b\xc7\x97/\x1fG\x97\xef\x92\xcb\xfe\xd2y\xf3\xbb\xf7\xf5j\xfa\xe6\xe2\xfa\x1fo.\x02\xf4\xf2\xe5\xe2u\xb4\x9d.\xb7\xd3\x8b\xf1hj\xbf\xeeE\xf7\xf8\xd3mF~\xf1\xf6\xee\x93u\x15?\xbc].\x97\xbf\xfc\xf2S'F\x11\xb2\xd3\x8e\xde\x11\x8e\xa4\x9a1x\xc6\xc1\xf4\"\x1f\xe6n\x8b\xc1t\xba\x18\xbd\x1c\xaf\xfew0\xfd\xdf\xc1\xf4?u0}\x7f\xf9u\x7fw\xbf\xba\xba\xbb\xcc\x06\xd3\xaf\xfb\xd6\xc1\xafe0m\xf8\xdd\xaa\xf1\xfb\x0f\x1aLo?\xb6\x0e~G\x0d\xa6\xb7\xed\x83\xf3\xf7\x19L7\xaf>\xe8\xc6u6\x18\xcd\xea\xc1\xd4\xbf\xeb\xbf\xb4~\xbex\xfd\xdb\xc5b:{\xed\xbf\x9c],w\xa3\xbb\xe9\x9b/\xaf\x02c:\xf5?,\xcd\xfe\xed\xe0\xe1\xe2\xf2\x1f\xb37\xb3\xcbW\xdb\xebWhv\x8d\xfc\xd7/\xad[{{\xe5E\xd3/\xdbO\xab\xed\xd5\xfd\xecr3\x9f~\xc1_\x1e6\x9f/\xb6\xeb\xd1\xe6\xf6zz1\xbd\xda^\xbc\x8aV\xa3O\x03G\xcf\xc7\xa5+\xfc\xfa\xe3\xc3\x87\xf5\xad\xff\xea\x95\xd2\x00<\xd2\xf2x\x97\x1c\x85\xb3`\x99\x1d~\xef#T\x8f\xbf/\xc7\xf7/\xfb\xb7\xd3\xafw\xbf\xaf\xa2o\xcb\xe9\xf4\xc3\xa7\x87\xff.\x03\xd9\xe6\x7f\xbf\xbdL\xa6\x17\xaf\xaf\xdc/71\xba\xcdF\xe6\xdbj\xe0|\xd9\xbf\x9d\xed\xec_\xeft\xe72\xdc\xbc\xebY\x8f\xef\xfcb\x1c{\x97\x8f\xb5\xe3\xfe\xd7\xdf\xa7\x9b\xd9\x87\xfe\xf6\xddv:\xfa\xcd\\m\xbf~\xb9\x89\xbf\xfd~\xbb\xfc\xea\x7f\x0e\xec/\xfd\xf1\xf5\xfa\xe7\xe1f\x7f\xbd\xb4\xbf\xdc\x8e\xaf\xb1c|\xfcxq\xe3\\\xdd`\xfb\x0d\xbeF\xc1[\xfc\xc9\x8c\xde\x7f~s3\xb0{3\xeb\xdb\xab\xeb\x97\xb9\x8f^f\xfd\xf7\"\xfd\xf6\xfb\xdd\xaa\x19#\x96\xe3\xeb\xb2\xee\xf7\xbe\xf5\xf8\xde\xcf\xc7\xe0M\xd6\xe7\xf31\xf9\xd7\xbb\xf8\xb7\x0fo\xab\xb9\xe2\xeb\xc7\xcf\xd3\xe5mo\xbc\xff\xf6aj\xbc\xbb\xff\x9a~}\xbc\xda\xcd>L\xcd\xf7\x1f\xfa\xbb\x9b\x8f\xcb\xc7\xd9\xfd\xa7\xa4\xec'\x9b\xd9\xe5\xc3f\xf6q\x9a\xce.\xaf\x06\xb3\x8f\xd3\xc1\xec\x9e\x18c_]g\xe3~\xed_\x8d<\x99/\xea^\xad\x1b\xd35\xdd\xbde\xce\xf6\xd6\xc6\xf1\x9d\xcd\xec\xe3\x83\xf5\xfe\xc3h;\xf3F\xfb\x99gd\xf4\xa9cf}\xf1u\xff\xdd\x17\xeb\xf1z\xdf\xf0\xbd{\xf3\xf9\xf1\xab\xf96r~\xbd\x8b\xe6\xbd\xfe2\x1b\xbf\xdf\xfb\xaf\xbd\xb9\xf9Y\xff\xed\xc351Nf\xe3\x00Q\xa7\xcc\x1e\xfb\xff\xc0\xb1\xf9\xf7\xe9\xe0\xd6|\x8b\xbf\xfe~\xb7q\xf0\xddf\xde\xdb\x12\xf3\xe2E87\xef6No\xb5q^]\\\xde\xee\xa7\xfb\xd9\xe5\x95q\xfdju\xf3\xf5\xcbM4\x0f\xb2\xb2eT\xf0\xb9\xb8\xf9\xf81z;\x0fn\xf4\xaf_\xac\xfbo\x9f\xf0\xd5o\x1f\xdef\xfc\xd7\xf6\x17\xfc\xf0\xfe\xe1z7\xbb\xbf\xd6\xdf\x7ft\x1eo\xee\xddW\xb3\xc7\xab\xdd\xdd\xc7o\xaff\x0fo/\xef>^\xeb\xb3\xcb\xe5nv9\xdd\xcf>:;\x82\xdf\xd5\xbcwc\xcc\xbf|^\xbbW\x0d\xbfoo(~z+\xbf|\xee\xac\xe7\x13\xec\xf8\xb8\xf7\xed\xcb\xdd\x1b\xc7\x1f\xa7\xd7\xbf\x16\xba|\xef\x8b\xe7\x85\xdb\xfb\xab\xfd\xec\xfe\xd6\xbay\xbc\xea\xdd\xe8\xd7\x8f\xf9\xbc\xf0p\xbd\xbf}\xb8y=\xbb\xbf\xdd\xbe\xbf\xbc\xda\xce.\xafw7\x8fW^\xc3O\xde\xfa7\x97\xa3\xf0\x1f\x97\xe3_\x7f{\xfc\xf4\xb2\x8d\xa6\xfd\xef\xe2\xe5v:\xbd{5\x9d^O\xa7\xcb\xcb\xe9\x87\xeb\xe9tuu1\xdd]]\xbc\x1c\xddN\xbfd\xe3\xe6\xed\x14\xf8\xdf\xd7\x8b\xe9\xed\x15\xf0\xfc\xfa\xeajzu1\x9d\xce.\x98\x82\x8b\xe9\xe5\xd5\xab\xa9~u7\x9d^]^\xf0<\xef\xae?\xbe\xbe\xf8\xf4\xe5\xea\xc3\xf5\xe6\xa5=\x9dn/\xa7\xb7\xd3WW\xb7\xb3\xbb\xe9\xe5h\x1a\xbe\x0f>~6n?^\x0e\xdf\xbeMV\xbf\x99\x9b\x0f3\xf3\xb7\x97/\xbf)\xcd/\xc6@m\x829*\xbe\xcf\xe6\xd7W\xb7\x0f_\x96\xbd\xe9\xff\xc6\xf7\xff\x7f\x1d\xdf\xab\xce\x01t\x1c\x9e\x8d\xad\x8asV\xcfH\xc9y\xab\x8c!U\xe7\xad\xc7\xcf\xbf\xe2\xed\xb7\x0f\xe3\x0f\xdf~\xbf\xd9\xb8\xbf\xbf\xbd\xcf|\xe9\x9b7{\xb6\xf8Y%\xae\xbfy\xfcj\xce\x1e\xde^\x15I\x97\x99!\x1f\xbf\xdb\xd7\x1d\x0d\xbf\xaf\xad\xfc\x9e-\xbeoOn\x1c\x15\xdf\xdf]\xb6\xf2\xfbN\xf1=\x1a\xbc5\x1f\xb2\x11\xe2\x91M\x96\xe8\x9f.\x93\xd9vv\xff\xe1.\xfc\xfa\x9b\xf5\xe6\xbf\xfb\x1f~\xbb\x99\xdf\xdd\x7f\x9e]\xdd\x1a\x8bWw\x97\xcb\x9f\xbd\xe0\xe5\xe0\xe7\xb7\xc6\xf4\xed\xa7]\xb2\x9c^\xbd\x99NM\xe3b\xfav\xf6A\x7f\xf3\xb5\x18\xcf?|\xfa\xfc\xfe\xee\x1f\xd6\xab\xaf\xd7\xd7\x92\x04J\xb3\x15C\x1f\x8e\xa1\x7f\x03\x8e\xcf\xccCwO=\xe0N\"\xb8\xf4A\x04\xd7\xa3\xcf\xcd\xb8\x98\xfe\x95\xdeZ\xae6\xe6\xe8\x87\xfc\x01\x9dE\x18\xfb\xf4F\xacA\xff\xda\xa3\x7f5\xe9_\xfb\xf4\xaf\x16\xfd\xeb\x80\xfe\x95?\x0b\xb4J}\xba\x15\xf9Nu\xb1\x89\x83|\xdb\xc3\xff\x12\x95\x96\xdbT\xa2\xe2\xc8N\x92m\x18\xbbB@\x8a\xc4\xbcS\xb4K\x85\x85\xeb\x98!,\xb64\xe9G\x1e\xbd\xc7c{\xf4.UH7\x9a>'\x101\xe7\x94\xca\xf3Q\xd4\xb3|\xd7\x93~BKPmK\xd2\x0fW\xf4\xaf\xb4-\xd6\xf8\x94\x0dH\xba7\xd8I\x84\x9cT\xcb\xf7\xd8\x0e\xe2\xf3%b\"M3\x06\xbbq\xb5\x9b\\\x9d0\xb2\x06\xdd\x9e\xf5BF5\xde\x19\x03\x96\xca\x18\x0e\xbb\xc3\xa1\x94\xac\xbf3Y\xaa\xa1\xbc\"s\xd7\xe7\xea1\xcd\xaeiJ\xa9\x06<\xd5`\xd0\x1d\xb4\xc8\xc6\xb7\xc8\xd2\xa5$\xa3\x9d\xc5U\xd3\xeb\xca\x1bd\xedF\\5\x03y5C\xbe\x9a\xa1\xd1\xed\xf7Z\xea\x19r\xf5\xf4\xe5\xf5\x18;\x83#a\xcf,2$\xc5\xc9\xb5C\xedq\xf6< \xf1:E\x934\x8c\xce\xf5I\\zd\xc9M\x9f`\xb4\xc8~'\xce\x0eT\xe7k\xb2\x9f\x1f5/p\xd1.\xfb\xe5\xdf\xff\xe5#\xd7\xb3;\x89\x13#\x14t\xec\xc0\xed\xfc\xe8{Ay\xea\xc0\xd4\x91\xff\xd3A,W\x90<\xa17d\xd4'u\x08\x80P\xadO\x00\x84\xed\xdd\x02\xaaM\xa9g\x00\x84*\x9d\x03\xaa\xaf\xbd\x7f@\x95)t\x11\xa8\xb2\xf6^\x02\xe9Q\xa5\xa3@\xb5\xb5\xf7\x15\x88J\xa9\xbb\xe4\x84\xcf\xdfc\x14\xbaL\xf9\xb0>\xbd3h\xe9G\xfeS\xba\x91\x7fb/\xe2\xe8\x14;\x11G\xa7\xd0\x87\xf8\xba\xd4\xba\x10G\xa7\xd4\x83\xf8\xda\x14:\x10_\x95J\xff\xe1\xabR\xe8>\xbc\x06\x95z\x0f_\x97B\xe7\xe1\x89\xd4\xfa\x8e\xff\xe7w\x9d\xb6^\x82\x9f\xd2K\xf0\x89\xbd\x84\xa3S\xec%\x1c\x9dB/\xe1\xebR\xeb%\x1c\x9dR/\xe1kS\xe8%|U*\xbd\x84\xafJ\xa1\x97\xf0\x1aT\xea%|]\n\xbd\x84'R\xeb%\xf8\xbb\xf4\x12\xb2^\xcf_\x1e\xe8c\xa0\xb4XN\xb8A1y\xce>?W\x9d?\xfd\xbf\x9e\x1f\x85qj\x07)K\x12\xa4\xb6\x17\x00D\xf9s\x82\xac}\xa6;\xf0\xc2d\xd3\xee)\xf2\xc0t\xacH\n2)\xcc\xbe\x85\xa0\xfeirBd\xc7\x89)\x94\x08\x9f&\x11D\xc6IDQ\xce\x97\x9a\x83\x82\x94v\x9d\"\x19t\x1e\x84\xe5O\x13\xa2\xac\xf6sn\x90\x98/\xb54\x8c\x8e\xe6\x93\x86\x11\xc7'\xef4Gs\xe2;\xc5\xbc\xea\xc7G\xf3*\xc88nY\xe7=\x9a\xd7\xf1\x8b\xab\xda*L_P\xaaN`\x98SX ms\n3\x89yNa'\xb1\xd0)\xec\xda\x82\x12\xd5\x11\xa51\xdd\xf1N'\xb2\xdc\xf1\x9c\xc4\x86;\x9e\x97\xccn\xc7s\x93\x99\xedxnmV\x93\x1a\x08\x1f]\x9d\xc8@\xc7s\x12\x1b\xe8x^2\x03\x1d\xcfMf\xa0\xe3\xb91QL\xb7<\xfe\xce\x1f\x83\x07a\x1aqL\x1389O\x94\xc2\xe4zMt\xfc\x18\\\xf1\x08\x92\x13\x84\x05\xa9\x14\xe4%\xe9\xda|[uD\xaa\x98\xfb\xa7\xb4\x03 Ri\x86\xaf\xdc\n\x89\xc0\xf8\x14\x81\x01\"\x15\x811)0\xed\xfb6}\xcf-g9)\x1f\x95\xd18s\xbb\xa7;O+\x9alt\x00\xe8\xb2\xc7\"\xda\xfa^]1\x1e\x00\xd4E\x81\x88~N\xdf_\x86\x18\x94%\"\x0e\xb8\xe2\x90wz\x80>\x7f.\xa2\x0e\x80{\x81\x94\xba\x8e\xef\x8bs;\x9f\xd2\x8f7\x03Av\x8a%\x08\xf2S\x8dA\xb08\xdd\x1e\x04\x93\xd3L\xc2\xa9\x0f\xb2\x8a\x82Y\x14\x86\x9b\xb9\x9d\xcd\xe3'\x98\xca\x7f\x92\xa5\xfc'\x1b\xca\x7f\x06;\xf9O4\x93\xffT+\xc1\x06\xc1'\x19\x04?\xc9 \xf8\xc9\x06\xc1\xcf`\x90'\x0ee\xac\xe6@\x83\xd04Zq\xd5\xaf\xa2\x13\xbc\xe3 \xc3\x05\xc8\x8eA\xb0a\x18\x1c\xd8\xb5\xe3\x07m\x19\xdb{\x06k\x9a&\x87\xf5=\x17\x82Z\x96\xc5A\x01\xd8p8\xe4`\x89\x877\xcd\x85\xef\x128\x1e\x8f9 .\x8c\x0d\xc1m\xdb\xe6%\x0d\xc3\x00\x92\xc1q\x1c\x01k\x00\x8c\x10\x82u\x9b\xdf\xd2d\xc0\x8b~\xf6\x87\xc3\x83P\xf6&g\x85\xd3\xc6:\x0d]%\xd8\xfeQ?\xd3_\x9ce\xb1\xf8Yw\xfc\x93\x80p\xd4B8\x12\x11\x0e[\x08\x87\"\xc2A\x0b\xe1@Dh\xb5\x10Z\"\xc2~\x0ba_Dh\xb6\x10\x9a\"\xc2^\x0baODh\xb4\x10\x1a\"B\xdd\x92\x13\xeaB\xed\xe8\xbd6\xd2\x9e\x98\xd6h%6 \xea|\x8c\xe1\x9c6^\xces\xda3\x1dt\xd8\x82\x88uX\x92\x08p\xd6\x82\x88uV\x92\x08p\xd4\x82\x88uT\x92\x08p\xd2\x82\x88uR\x92H\xa8\x08\xd6AI\"\xc09\x0b\"\xd69I\"\xc01\x0b\"\xd61I\"\xc0)\x0b\"\xd6)I\"\xc0!\x0b\"\xd6!I\"\xc8\x19K*\xd6\x9f(2\xb1+\xf1\x8eH\x11\x82N\x98O`1r\xd9\xc1{\xa8\xf7u~\x9c\xe5\x81\x8bE\xdf0\x07\x82Y\x01\x82\x0f{\x16?\x89\x84\xb1\x1d,\xf9\x81~`\x02\xf3\xf32\xc4<\xd7\xf9\x10@\xee\x11\xc6\xe1\x96\xc6\xf2\xaf\x0e\xa8\xa5\x85\xe0\x7f]\xcc\x17\x86\xcdO\xa8\xd1:\x8e0+\xb0\x85z\x8e\xcdO\xe6\x05w\x90\xc2\xee\x0f\xccE\x0f6J\xe4\x05l\x04\xe2Z\xba>\xe2\xad\xb2\nS\x08\x9d\x99f\xce\xcf\xa9 r\xa4\x0b\xa7v\x10o\x9b.\x1f\x8e\x94\xc1\x10B\x01\x837\xcc\xe1\xd0\xe2\x9b B\xc7\xf6x\xc8\x0b]E\x19<\xc1\x18\xa1\xb9\xc3\xeb$\xb07l@\xa2\xeb\xc6\xbc\xcf\xb3\xce\xa5\x9e\xe35k\x1b]\xef\xf7\xc7|\x08\x03 Mk\x88\\\x91W\x01\xf8\xf1\xc0q\x80 &\xc7\xa3\x04$q\\\x04\x91l\xedd\x85\\\x88`1X,\x16\xbc\xf4%\x01\xa4H4Z\xb8\x0b\xde{K\n\xb8s,\x16\x0e\x9a\x8bH\xa0\xde\xef.\\\xbe\x15d:\x91\"\x10f\x88\xe6\x9aV\xbe\xea\x84&\x80\xde\x7f\xd2\x9d\xc7\xf5\xd0\x1d\xdb\xae\xb7N\xce\xd9\xa1\"6\x18@\xd7\xe8Y1b\xd3\xadq\x8f\x85\x81(\x93EA\xa0>\x032\x00\x8cf\xe8\xac\xe4@R9\xd6\"\x0fc\x067\x1e\x8f\xc7\xc0\xea\xaf\xdew+\xc0y\x92<[iUz!\xd7\x90\xc5:P\xa41\xad\xd8U,\xe0UV\x1bbU\x96\xb5q+\xf7\x16[\xe4\x82*\xe2y\x15\xdb\x81\xa2\x96\xc8\x05kO\xb6\x1cX\xe7\"\xd3Q\"\xff\xe21\"\x17\x03\x90\xb0\x97\x01@\xd0\xd1x\x9c\xc8\xd7\x00\xa4\xc8\xddx\xa8\xdc\xe3\x98\x8c\xdfS\x9c\x8eO\xdd=\xd9\xefT\xa4Sw=\x86\xdb1\xde\xa7\xe0~*\xb9\xbeX'\x12oB\x97d!B\x8f\xe4\x80\x02\x87\xe4p\xb0?\xb20\xa1;r@\xa17\xb2\xc8\x16g|\xb6\x01\x90\xcbN>\xdd\x15\xdbe;\xc2\x13\xfd\xef\xe3\x88\x02\x9fc'!\xc0\xe7X\x88\xd0\xe78\xa0\xc0\xe78\x1c\xecs,L\xe8s\x1cP\xe8s\xc7M\xb9,\xbc6oc \xa2\xa0<\x9e\x06\xfb\x1c\x9b\x80}\xba\xcf\xe1\xe7\xf49|\xb2\xcf\xd1\xfc4\xadx d\xc5\xaeH\xf5\x02/\xe5-\x82\xf8,\xe4d\xa0\xf93\x0eZ\xdeF&\x91\xc0&f\xb6\x84\x08\x03D\xe3\xf2w\xd4\xb5\x0f\xd1\x07\xb8!\xdcn\x8f\xb4-\xd8\x92a\xb5\xc8(\x1cDd\x17\x1e\x08\x9b\x86\xc7\x81\xd6\xe1`\xa0\x818\x14l#&\xee\x15\x9a\x89\xdb\xbe\x17Z\x8a\x0f\xf5\x85\xc6b\xf7\xe2\xebm\xc0v\x83\xa9\x0cl[\"\x1a\x15\x1a\xd1W\xb4!\x8b\x13\x98\x90\x85\xc1\x16\xf4U\x0c\xe8+\xd9\xcfW3\x9f\xafj=68\x16\x1b\xcf?\xc1v\x023\xe1V3aE3\xb18\x81\x99X\x18l&\xacb&\xacd&\xacf&\xacj&6\x9e\x14\x9b \xc3f\xa2\x80\xc9\xcav\xc3\xadf\xd0\xd7\xba\xf3\x87\xe7zG\xef\xf4\xa3]\xa7\x17\xed:\xf4\xa6\xcbD \x05\xd6\xd4\x13\xd54R\xaa F\x815\x99PM\xbd\x92\xbe\xbd]r$Xc_Vc&\xb9\xaeP\x1f\x84\x03k\xb3\xa0\xda\xfa\xa5\xc4m\xb5\xc9p\n\x83\xf0\x01t\xa2lT\xff\xd3\xfcHR\xd9\xf3\xbb\x92\xa0\xb2\xef\xebM-\x95\xb6\x99\xf8x\x87\x12T\xf8,>\xa5\xe0T\n3{\xedi\xfe\x9f\xe8h\xc2\xba\xbe\x83\x9f\x81u}g7\x93\xd6\xd9f\xf4\x13\xbc\x0c\xac\xefOp2\x99?\xe1?\xd1\x9f\x84u}\x07\x7f\x02\xeb\xfa\xce\xfe$\xad\xb3\xcd\xbe'\xf8\x13X\xdf\xf3\xf8\x13Ua\x14\xa3\xfa\x0b\x1e\xda.\xff\xb4E\xfdq.m_~\x08\xa8\xf9\\W\xe2\xc4!\xa6?%\xd2\xcdb@=\xff\xe6\x11\x13\xb0\x15Q\x9f~\x80S\x89E\xa4\xa7W\x9fRb\x8a\xf3\xf0N?\x14\xe9I\xbe>#\xaf\x8f\x0fa\x8b*\x8d\xb2J \xc4-j5\xaaZyD^\xb1QT\xcc\x97fu\xf7\xf2\xba\xf9\xc8\xb8\xa8\xbbW\xd6\x0dD\xceE\xdd\xbd\xaan\x1e\x91\xd7\xdd+\xea\xe6K\xb3\xba\xcb\x86k\xa2\x96\xd7M\x07\x10e\xfdM\xe3\x01L.A\xd5|\xa0<\x97\xa1P\x80&\xd2@\xad\x02\x00Q\xc9P+\x01\xc0\x142\x94j\x00\xca\xab{\xd4\x9a\xb6\xf00>HoS+\xcc\xd0\x07\xde\x99\xb3\x98\x01\xf0\xe7\xc2'\xb3B\xc8-Ko\xcf\x8a\xa5\x0e_\xa4 \x9f\xcf\x1d\xbb\xaa[\xe4\x99u\xf5B\xe7o$\x10\xfb?!\x84\xc0\xc9+9D^Z\xcb!\xec\x08\x8d\x1c\xe2\xbe@\xc8!r\xf8J\x10\x89\xcf75\xc9\xdc\x9e\xa8K\xec\xf9u\xb3\x84\xce_\xcb#\xf6\x7fB\x1eI\x17 \xe5\x11\xf6\x82F\x9e\xb6\x8eP;\xad\xb0/(t\x06\x85p\xb5\xe8!\xbe\xa4\x83\xf8\xd2\xfe\xe1\xb7t\x0f_\xda;|y\xe7\xf0\xdb\xfa\x86\xdf\xde5\xfc\xb6\x9e\xe1\xcb;\x86\xdf\xd6/\xfc\xf6n\xe1\xb7\xf6\n\xbf\xb5S\xf8*}\xc2W\xe8\x12~[\x8f\xf0[;\x84\xaf\xd2\x1f|\x85\xee\xe0\xab\xf6\x06\xffI\x9dA\xe8\xf7X\xe2\xf7X\xea\xf7\xb8\xc5\xef\xb1\xd4\xef\xb1\xdc\xefq\x9b\xdf\xe3v\xbf\xc7m~\x8f\xe5~\x8f\xdb\xfc\x1e\xb7\xfb=n\xf5{\xdc\xea\xf7X\xc5\xef\xb1\x82\xdf\xe36\xbf\xc7\xad~\x8fU\xfc\x1e+\xf8=V\xf5\xfb\xb6\x80\x88&v\x16\xe7\xf6\x82}5j\xf6t\x8e\x16a\x8c\x0e\xe5\xc7{\xcf\xff\xd2\xf9\x0b\xfd\xe5A\x98\xcd\xc1\xc1\xc8\x8e\xcf\xe7a\xbab\x01\x87\xbf=\x86\x99o1\xcfqI\x92I\xc7\x14U\xdc\xf2\x960esqMAYt\xd2N\xb9\x93O\xa3b\x91\x9aRP\xaa\xa6\x18\x12\xac)U\xd8 V\x9d\x8e\x9dl\xa8\x93\x08\xecK\xe5\xf5e\xe2\xfa\xea\xd2\xc2\x82\xc9\x8c[\x17\xc2\x82a\x99`\x98\x12\x8c*u\x03\xd9\xe7\xfc<\xe6S\x81L\xf1\\\xf2A\xc2\xae\xeb\xcd\xdb?4\xd8u\xbd\x94E\x01\xfd\xc5m@`\xa9C\x17k\x0eb\x17\xddn\xaa\xc5\xe1\x96\x81\xc5\xe1\x16Bi\xcb8\\G<\xb6x\xceQ8!^\xfb\x01+A\xfeP\x80\x05+ \x8b8:m\xe1\xed\x90{(\x90\xd8\xde\x87\xeb\xf4<\x7fD\xbc\xfeJ\xa1\x7f\x1c\x18\xdbg=Lf~\xb2\x1c\xf6\x00\x12\x01;\x01\xcfC\xe0\x07\x00\x1046\x89\x83\xbd\x81C\x08\x1d\x82GJ}\x02\x84K\xdd\x02\x10\xa5\xdd3DDR\xe7\xc8\xd73R\xffPp\x10\x85\x01\xd4\xcd\x06:\xa9\xd3\xf8m>\xe3\xb7\xb9\x0c\xcbA\xe41\x1c\x0ev\x18\xbf\xcd_|Uwa\x81ro\x01\xd0rg\xe1\xe4P\xf0\x15\x98F\xee*\xfe\x93<\x05v\n,w\n\xdc\xe6\x14\xb8\xcd)X\x0e\"\xa7\xe0p\xb0S\xe06\xa7\xc0\xaaN\xc1\x02\xe5N\x01\xa0\xe5N\xc1\xc9\xa1\xe0\x140\x8d\xdc)p\x9bSPt\x0b\x8cvu%D\xee\xbd\x0e{5?\xd12\x10\xf9,\xfb\x9dfS\x9a\x08\xe4V\x99\x99aJ\x90\x90E\xc4c^R\xcd^\xa7!\xb5E\x90==7&\x95\x94\xe7F\xc7\xe8\xe4\xd9|\xfa\xb7\xc6\xeb\xf5\xfc\xe7\xea\x85\xa9@\x15\xf9\xe1S\xae\n\xbd\xa9\"\x7f\xe7A\xfd\x13\xc0\xa1\x8c$H\x1ea\xece\xeb\x89\xea\x0b\xe3\x13\xb2\xcc\xf5\xe2\xe2\x95\xff\xe5\x17\xcb\xeb\x9a\x88\x92\x82\xe5\x04|\nH\x90\xc5H@\xf5\xab0\xf6\x1e\xc3 =A\x808\xdc\xb2\xb5s\xfd#/\xdf\xc6vt\xa8\x19d\xbf\x9dg\xffL\xe8_A\xbd\x03\xa4\xc5\xc3 \xfb@P\xaf\x16\xa3\x0d\x8a\x13\x04\xd4_\x15M\xe0\xc7B+6,\x8f\xb6fU\xa3\xd0\x9c\xb4L\xa2R\xd8\xbc2\xb9Z\xcd,\x91\x8c`\x0d\xd8\x1b\x96\xc9K\x91\x9fhIj\xc7)%N\xf1\x19\xfd\xfcyS\x15\xf90\xff9\xff\xbcy\x92\x8f)\x05\x0f\x889\n\\\x805\n\\\x96q\xf6\x88c\x8b\x02\x17bZ\xbe\xe8\x93\xe7[\x14\xb0\xac\xcb\xa7$\xf7\xe2\x11\xc4{n'(\x1b\xc8\x00\xeeU\x11\xcb\xbf~N\xd6P=\x845\x1e\xa3\xd4Y\x81:\xcfKx\xad\x17\x8f\xc9\n\xcag4\xff\x04\xe1Ee\xd0\x8aE\x06\x07\xac\x97A\x85\xc6\xcb\xf9\xe4\xb6\x03\xb84\xa6jxp\x96\xca9T\x86\x02\x98PF\xc9\xf9@6\xc9\xb94&\x01\xf80\xca\xcf9\xc1\xba/uS\xaa\x1e\xd4\x0e\xa9\xe5\x9c\x13\xa8\xe4\xfbu\x92z\x8b=\xd0q\"\xdby`\xfb\x0d\xf1\xac\"\xac\xb2T\"\xedW8\xb6\xf3\xe4\xac\xa8\xbeS?\x01YsF\xa9Q|\x07\xca9\xb1\xfd\x87|\xc8\xd6\x00\x99\xab\xc2\xccQ\xbaE(\xe0+(\x01L\x0d\xd5S\xb6\x8a$\xb2\x1dT1\x83k\xb2\xf3\xd74\x1eh~\xae\x97\xa4\xb17_\xa7H\xc0\xb2\xa0\xa29\x96\x08\xb6\xf7\xe4A\x0da\xc3\xc29\xda,X1\xa3\xbaP\xc3\xaa\xe9Ar{Ul\xd8~\xd4p\xa2\xba\x91\xcc4\x15\xab\xda4<\xaf\xca\x0c43\x89\x11*\x9e\xac\x11\x1a\x96\x84% \xaer;0=\x95\xb4\x04\xd9Qk\x96P_-\x0e\xdf\xea\xccl\xebz\x81\x8d\x8bh\x9c\x88A\xb5\x1c|\xaeO\xca\xffB\x9c\x0c \xa7\x1e\xcb\xc9(9\x19\x10\xa7\x9e\x84\x93\xc9r\xea\x95\x9cz\x10'S\xc2\xa9\xcfr2KN&\xc4\xa9/\xe1d\xb1\x9c\xfa%\xa7>\xc4\xc9\x92p\x1a\xb0\x9c\xac\x92\x93\x05q\x1aH8\x0dYN\x83\x92\xd3\x00\xe24\x94p\x1a\xb1\x9c\x86%\xa7!\xc4i$\xe14f9\x8dJN#\x88\x13\xb6\x93T\xe6\x9cz\xf6?\x96\xe38\xfb\xdf\x84\xf8\x19\x085\x97Y\xd4\xa7\xcb\xd6C\xe5\xbbm7\xe8\\\x9f\xd4$\xe0\xca*\xe7e\xc8\x96o\x0d/\x83\xe0e\x00\xbc\x92U\xec\x05\x0f\x99d\x15i\x80\x966)F\x81\x00\x05)\x89\x0d\x80\xd8\xa0\x88\x0d\x85\\\xdb\x81\xe7O\xe4\xfd\x88\xc6\x9e\xbe\xa4\x86\x18>\xf7\xaaZc\x0e\x0c/\xbe\xcb\xc2\x1a\xac\xe5\xf8\xb55\xcbFmA\xf6\x9c\xcbk\x81\x04\xadK\xafgZa\xe7\xd5W<\x8e^d\xf3\xd4\xa7\xad\xb3a)\x9e\xba\xd4>\xcd\xb8\x7f\xcaj\xfbT\xab\x7f\xbf\x057+\xd1\xf3\xae\xb9a\xee\xcf\xb2\xec\x86Y?\xe3\xca\x1b\xae\xe0\xb9\x17\xdf\"\xfd?\xd7\xfa\x9b\xeabOY\x82\x8b\x18\x1d\xbb\n\x17\xf19a!.bu\xdaZ\\\xac\xa9\x13\x96\xe3\xacY\x9f\x7fE\x0e\xd6\xf0|\x8br\x90\xfd3\xaf\xcb\xc1:\xbe\xd3\xd2\x9c\xb2\xee3\xad\xce)\x9eO^\xa0\x0b\xb8\x9d\xb6F\x170;u\x99.`\xf7\xc4\x95\xba\x80\xeb\xd3\x17\xebB\xc3\x1c\xbb^\xe7\xe7\xeb',\xd9\xe5\xcc\x8e\\\xb5\xcb\x99\x1d\xb9p\x973;r\xed.gv\xe4\xf2]\xce\xec\xc8\x15\xbc\x9c\xd9\x91\x8bx9\xb3#\xd7\xf1rf\xc7/\xe5[\xfc\xf6\x89\xaby\x96\xfb\xe2i\x0bz\x90\xddS\xd6\xf4T\xf7?aY\x0f\xd3\xb3+{\x85\xa5\xbd\xc21\x9a\x9c\xa7\xff\xcc\xcb}\x9e\xdf\xb3\xaf\xf6\xfd?c\xb1\x0fTr\xc2Z\xdf?a5\xf8\xacK}P\x80\xd65\xdfs\xad\xf4\xfd\xa7,\xf4Y\xe2\x13\xd7\xf9\x90\x0cO^\xe6\x9fb\xd7?g\x95\x7f\x9a\xc1\xbf\xe3\"\xdf\xff\x9ek|\x88\xf9\xf3,\xf1!\xce\xcf\xb9\xc2\x87\xf8?\xfb\x02\x1f\xd6\xfd\xb3\xad\xef\xfdgZ\xde\xc3|\x8e^\xdd\xc3lNY\xdc\xc3\x9cN\\\xdb\x8b\xb4t\xca\xd2\xde\xff\xde+{\xa0\x82g\\\xd8\x03\xdc\x9f{]\x0fT\xf1\xbd\x96\xf5\xfe\xf3\xaf\xea\xfd\xe7\\\xd4\x83\xccN\\\xd3\x83\xbcN^\xd2\x83\xdc\x9e\xba\xa2\x07\x99>\xc3\x82^`\x93\xa3\xd7\xf3\xec\xcc\xfc\x94\xe5\xbc\x8c\xd7\xb1\xaby\x19\xafc\x17\xf32^\xc7\xae\xe5e\xbc\x8e]\xca\xcbx\x1d\xbb\x92\x97\xf1:v!/\xe3u\xec:^\xc6\xeb\x84e\xbc\xd4]\x9f\xba\x8a\x97\xae\xae\x8e^\xc4K\x17\x84'\xac\xe1\xfd\xa7-\xe1!\xf2\xe3V\xf0\xa2\xc5:~\xe6\xc5:\xcf\xef\xd9\x17\xeb\xf8\xcfX\xac\x03\x95\x9c\xb0X\xc7',\xea\x9eu\xb1\x0e\n\xd0\xbav{\xae\xc5:~\xcab\x9d%>q\xb1\x0e\xc9\xf0\xe4\xc5\xfa)v\xfds\x16\xeb\xa7\x19\xfc;.\xd6\xf1\xf7\\\xacC\xcc\x9fg\xb1\x0eq~\xce\xc5:\xc4\xff\xd9\x17\xeb\xb0\xee\x9fm\xb1\x8e\x9fi\xb1\x0e\xf39z\xb1\x0e\xb39e\xb1\x0es:q\xb1.\xd2\xd2)\x8bu\xfc\xbd\x17\xeb@\x05\xcf\xb8X\x07\xb8?\xf7b\x1d\xa8\xe2{-\xd6\xf1\xf3/\xd6\xf1s.\xd6Af'.\xd6A^'/\xd6AnO]\xac\x83L\x9fa\xb1.\xb0\xc9\xd1\x8buvf~\xcab]\xc6\xeb\xd8\xc5\xba\x8c\xd7\xb1\x8bu\x19\xafc\x17\xeb2^\xc7.\xd6e\xbc\x8e]\xac\xcbx\x1d\xbbX\x97\xf1:v\xb1.\xe3u\xc2b]\xea\xaeO]\xacKWWG/\xd6\xa5\x0b\xc2\x13\x16\xeb\xf8i\x8bu\x88\x9c[\xac3\xf4\x87\x05\x0e\xed4\x7fG\xce\xe4\x0fz-\xcc@\xe3\x12\x9a\xbf1\xa7\x05\x1b\x94\xd8\x93\xde\x82\xb4\xc8\xdf\x82\xa4.W\x83V\x12\xad\x81+\xbcYH\xfd\xfc\x81\xe6\x1f#\xb2\x7f\x94\xc4\xbe\xba\xc0\xb0l\xc7\x98\xb9\x06\xab\xc9\x86)\xd9\xa8\xd2\xc4\x0e\x12-A\xb1\xb78,\xc2 \xd5\x16\xb6\xef\xe1\xfd\xb9fG\x11FZ\xb2OR\xe4\x9f]`/x\x98\xd9\xce\x87\xfc\xd7\xd7a\x90\x9e\xd9\x1b\x14xq'@\xbb\xea\xe7\xb3\x15\xc2\x1b\x94-r\x9b\x9f:\x01Z\xa3\xb3\xf5|\x1d\xa4\xeb\xb38\x9c\x87ix\x16d\xff$h\x19\xa2\xce\xda;\xb3c\xcf\xc6g\x8d\x14\x8ct\x9c`K\x14\xc6K\xcf>\x83\xc0\xb9t\x9a\xa0E\xc2*J*\x9e\x80\xc7:\xa1\x8b\xa8\xf7\xa0e\x0f(\xa2Wa\x90\x84\xd8N\xce\xfc0\xb0\x9d0\xfbO\x98G\x13,\xa3u\xec\xa1\x98!\xcd\x9fun2\x95\x96\x00\x11}\xad`\x8a\x03\xa3\xf6\xc6\x1e\xa2\xb6\x17\x86\xa3x\x00v\x15R\xa7+\x84\xed\x84&/\x9e\x9dI\xccT\x16\xa9Z5\xf5|D\xd7\x91?\x81\xa0\xf3\xd0\x0d\x03\x8f\xc2^\xe4\x8f:\xb3\x8f\x10\xde\xb1\xb1\x97\xa4!m\x85\xe2\x99\x80bi\xc7\xb6\x1f\x06.-|\xf9\x10\x14\xc9N\x1eP\xbc\xf10\xa6\xfd\x84x\x0e\x91\x95\x8d(>\xa1\xe5\xa56\xf6\x98\x0f_/\x12\xad\xc8\xc3\x91\xc0\xe2\x89\xc2`I\x8f=\xf9;\xafT\xebc\xb0e\x95\nu*\x0c\xd0^6\x88\xaa\xca\xe1\x1f-\x06X#V\xaf\x11\xd25\x8d%M\xb2-r\xc8}\xee\x93\xefT1\xf7E\xf8\xc5\xd6\xa0\x00\x06\x0f\xe8Q\x80\x1e\x0f0)\x00\xf7y\xfa\xc5\xb6/\x17q\xb1\xb5(\x80\xc5\x03\x06\x14`\xc0\x03\x86m\xcd\x1cQ\x80\x11\x0f\x18S\x80\xb1~\xfc\x9b\xba\x19\x8f\x15Z\x84E@Fa1\x90]X\x0cd\x1a\x16\x03Y\xa7U\xe2E\xf1\xb9\xb36\x1b\xb1\x18\xc8L\nm\x1f\xb1\x18\xc8X,&\xb3\x97\x82\xc1\x14F\x05\xba\xbf\x8b\x8d\xe8\xb7\xb5\xc3` \xa0 \xfdv\x0b\xfa\xed\x06l\x11v\x91\x7f\xed\xac\xd5|~\xbb\xf5Z\x1b=b \xa0\xed\xfc#M'\xb6R\xdb\xe0\xc7\x00@+\xe1v+\xe1v+\xe1v+\xb5\x08\xbb\xc8?v\xd6j%\xdcn\xa5\xd6F\x8f\x18\x08h%\xcc[\x89\xc2xA\xb4N\xb5\x18%\xa8\xb9\xdfnG\x11\xb2c;p\x8a/qN4?|d\x1f2&Z\xa7i\x18\x14l\xce\xcfs\xfc\"t\xd6\x89\xe6\x05\x01\xfb\x16`\xa2F\x1eZ~\x86\xed\\\x9fD\xb6\xebz\xc1\x92]\x18\xaf\x8cC\xb9\xd1\xca\xbf>y\xd5\xab\xca\xf8\xd7\x19\xaf\xcc\xaa\xac\xcf\x97\xf5\xab\xb2\x11_f\xd5\xf5\x0d\xf8B\xadW\x17\xf7\xac\x17l\xa1\xa5W\x85\x16\xfb\xa9\xe5\x956\xac)\x87<\xa5\xa1\xd7\xa4\xfcg\x9a\xf3\xcd\xe6\x1cBl;\xf3\xb0\x0d-\xddf\xc5\x15\x93\xf2\x01\xc5\xa4\x84@1-#\x0b\xc8D\xdb@R\xb2\xc0U\xf1\xce\xb9\x12\x90\xfd\xcc\x96{\xc1\n\xc5^ZA\xca_\x15\xe6\x89\x03\xe39\xd9t#q\x1e\xa2\x18\xf2\x1f\xa2\x18r!\xa2\x18\xf2\"\xb2n\xd8\x91\xc8\xea!_\"\xcaAw\"\xcaa\x8f\"E\x10;U\x86j\xf7+JX\xd0\xb5(qA\xef\xa2\x04\x86\x1d\x8c\x16Y\xecc\xbc\xd0\xb0\x9b\x11\xfc$\x9eF\xa0*gS\xf06\x85\xa8d\x95E\x132\x0f\xf4\xa5\x0e\xe8K\xfd\xcf\x97\xba\x9f\xdf\xe6}\xbe\xdc\xf9|\xb9\xef\xf9-\xae\xe7\xabx\x9e\xaf\xe2x~\x9b\xdf\xf9mn\xe7\xb7z\x9d\xaf\xe6t\xac\xbc\x02\x9f\xf3U\\\xce?\xce\xe3`\xe7\xc2R\xe7\xc2R\xe7\xc2R\xe7\xc2R\xe7\xc2m\xce\x85\xe5\xce\x85\xe5\xce\x85[\x9c\x0b\xab8\x17Vq.\xdc\xe6\\\xb8\xcd\xb9p\xabsa5\xe7b\xe5\x158\x17Vq.\xcc9\x17\x05Lc\xdby@\xee\x01\xa34E\xb1\x96D\xb6\x93E^]\x83\xfb>E\x01\xd4\xd2\x8c\x19\x0b\xd7\xba\xba%\"\xf0\xd1\xd2\xe6\xd8\xf72x\xfb\xb8z\x009\xe6\xdf/:F\\\x80\xa2Mb\xa8\x92\\h\x05\xa9\x15f\x83\xba\xaac[\xc2\x11\xb46\x84\xafB\xa1\x1d\x12\x91\xf1\xb1\"s\x04\xad\"\xf3U\x14\"S\x14x\xa5%!\xf6\xdcC\xbe\x8f^u\x16\x0e\x93z)F4\xa6\xdb\xb38\x98\x13F{\x06e)\x98\xfa\x00\x8a\x94;O\xbbT\x1cL$\x18\x0f\xb4\x9e\xc9\x0fk\x89}%\x81}EyY\\\x9b\xb82\xc9\xb0\x92dXQ2\x16g\xb1^\xe5\x05\x0f\x87\x14\xedR\xcdEN\x18\xdb\xe5 Vv\xd1\x9b\xc1\xce\xb8'\xe7\xb6\x93z\x1b\x04\x14\xe4\xcb\\\xe0\xf9*\xdc\xb0k\xe4\xfc\xb9\x80\xff\xc6K\xbc\x145o\x1cMc;H\xbc\xea\\g\x18w\xba\x86\x95t\x90\x9d \xcd\x0b&\xd2R\xbe=\x85\x90\x87p\x9df*:7\xa2]\xc7\x0d\xd3\x14\xb9\x1dg\x1d\xc7(H_eLX\xba$=d\xff\x14Yn-\xddGP\x8e\xc0\xdf\x16\xab\xc1\xda\x15\x81\xd9zk\x90\xe5\\,\xe1o{D9\x1f\xc6\xf8[\x93(\xe7\x03\x19\x7f\xdb'\xca\xf9P\xc6\xdfZd\xfd|0\xe3o\x07\x04\xc0\x84$\x18\x92\x12@U\x8c\x08\xc0\x00\x92qL\x00\xc6\x90\x0c\xc5+\xd4\x1b\xd0I\x9b\xf1\x859\xf2\x85\x93\xdc\"\x0c\x042\n\x0d\x01\xedBC@\xd3\xd0\x10\xd0:\x8c,\xa0\x81h\x0cl#F\x1a\xd0L4\x06\xb6\x14\x8d\x11\x1b\x8b\xc6)\xec\xf6\xab\x8e\xdd\xa5\x15\xfdV#\xfa\xad6\xf4[M\xe8\xb7Z\xd0o5\xa0\xdfn?\xbf\xdd|~\xbb\xf5\xfcv\xe3\xf9j\xb6\xf3\x8f3\x9d\xd8J\xb8\xd5J\xb8\xd5J\xb8\xd5J\xb8\xd5J\xb8\xd5J\xb8\xddJ\xb8\xddJ\xb8\xddJ\xb8\xddJX\xcdJ\x98\xb3\x12\x05\xdb\x1a\x07\x91Z\xb7\xbd\x83H\x9f[\xf3 R\xe4\xb6\x7f\x10ipk\x1d\x84\xaa\xcb<\xa1*e=`\xab\xf5\xaa\xb2\x1ePVq\xe5\xd6\xd0[\xcd\xac\xe8L\x9e\xce\xac\xda`\x9a|Y\xd5\x08\xb3\xcf\x95\xf5+\x9e}\x9e\xa7U\x95q\x0b\xf6\xad6\xa8\xca\x06|\xd9\xb0*\x1b\x02eU\xfb\xb8U\xfeV\x1bUt#\x9en\\\x95\x8d\xf9\xb2,\xe0\x10\xf5\xb7\xad\x96\xae\xbc\xd8\xad\x95\xd35\xb3\xff\xf1\xa0mX\x00\x93\xaaY\x83\xee`0\x18\x0c9d\x9e\xc7.0\xf9b\xbc}\x80?0.\x9aM\x13b/mJ!GmJ!_mJ!w%\xea\x85=\x96\x00@NKH\x06\xf9-Q\x0c\xb9nS\x0cz/Q\x0c90Q\x0c\xf90\xa1\x16\xc8\x8d\x9bb\xd0\x93\x9bb\xd0\x99\x9bb\xd0\x9f\x89b\xc8\xa5 \x9b@^\xdd\x14\xc3\x8eM\xdaD\xe0\xdb\xa4\xeaZ\xdd\x9bh\xab\xcc\xc3\x1bX\xee\xe4\n^\xae\x10\xc6\xe4\x01\x8a\xc4\xf3}\x99\xe3\xfb2\xbf\xf7en\xef\xb7x\xbd/uz_\xea\xf3\xbe\xd4\xe5}\xa9\xc7\xfbR\x87\xf7\xa5\xfe\xeeK\xdd\xdd\x97z\xbb/uv_\xea\xeb\xbe\xd4\xd5}\xa9\xa7\xfbrG\xf7[\xfd\xdc?\xc2\xcd}%/\xf7\xd5\x9d\x1c\xf6g,\xf3g,\xf3g,\xf3g,\xf3g\xdc\xe2\xcfX\xea\xcfX\xea\xcfX\xea\xcfX\xea\xcfX\xea\xcfX\xea\xcfX\xea\xcfX\xea\xcfX\xea\xcfX\xea\xcfX\xea\xcfX\xea\xcfX\xee\xcf\xb8\xd5\x9f\xf1\x11\xfe\x8c\x95\xfc\x19S\xfeL!\xc2\x0d\x8a\x178\xdcj\x1b/\xf1\xe6\x18\x1d\xaa\x07\xe7\xe5\x03\x01|\xe5\xb9.\n\x1at\xf1\xbb\x00\x9c8q\x88q\x03.~\x17\x80\xf3H\xaa\x86\xf2;\x1b5p\xc7\xc9\xac\xedZ\xa4\xde\xb1rk;\xb9\xe4;Vvm'\x97~G\xcb\xaf\xedd-\xd8\xf3-\xd8\xb7\xb4`\xcf\xb5`/o\xc1\x9ek\xc1^\xde\x82=\xd3\x82\xfdi\x01-\xebXY\xe8p\x94oQ\x04\n\xeeE\xe1[=\x8cB\xab8\x19I\xa0\xecg\x0c\x91\x92\xab14\n\xde\xc6P\xa88\x1cE\xa2\xeas\x0c\x91\x92\xdb14\n\x9e\xc7P(\xcc\xc1\xaa\x81&\xe7\x92\xfe\x91\x1e\xe9\x1f\xe7\x90\xfe1\xfe\xe8\x1f\xe9\x8e\xfe \xde\xe8\x1f\xef\x8c\xfe\xb1\xbe\xe8\x1f\xed\x8a\xfe \x9e\xe8\x1f\xef\x88\xfe\xb1~\xe8\x1f\xe9\x86*\x1e\x87\x8f\xf48|\x9c\xc7\x1d3\xc7\x92`%\x8f\xc3'x\x1c>\xde\xe3\x8e\x9dki\x02%\x8f\xc3'x\x1c>\xde\xe3\x8e\x9dsi\x02 XKR;\xf5\x9cCq\x055\xcc\xdf\x8d\x91\xb2\xb7Ob\x84\xf3;\xa2\x0d\xaazB\xe3\xecy\x12\xe2uJ\xe0\xaa'4\xae\xf8\xa8~\x0d\xca\x7fU\x18\x8e\x0f\x80\xe0\xd9\xc8\xae$;\x05\x94\x8bOA%-\xa0pE#\x14Z\xa10\xa9\x94M\xf3\x15[\xe6+7\xccWk\x97\x7f\\\xb3\xc4-\xc0\x8a-\xc0\xca-\xc0j-\xc0\\\x0b\xe8N\x92'r\xc3\xc8v\xbct\xcf\xbdu@\x1b7e\xdd1[8\"\n\xd9\xbb\xe9\xda\x90(d/\xc1k\x03\xa2\x90\xbdm\xafYD!{\xad_\xeb\x13\x85\xec\xfb\x034\x93(d_T\xa0\xf5\x88B\xf6\x8d\x08\x9aA\x14rJ\xd0\xad\xa6P\xe7$\xd2{d1{0\"\xd4\x1a\xce\xccy\xfb8L\xed\x14i}\x8b>o\xb0\x08c\xff\xbc(\xfb\xb1o\xb9h\xf9\xd3D\xf0\x1cd7\xd6\xc5\xec\xc6:\xcc\xaex\x0e\xb23L\x89x\x86)\x90\xaf,\x809\x8e$\x12\x1a#\x81\x88e\x01\xc8\xb1\xd7\x93\xc8\xd8\xeb d,\x0b`\x8eC\x89\x8c\xbd\xa1@\xc6\xb2\x00\xe4h\x1a\x12\x19MC cY\xa00\x96\x1e`\xd7\xd2\x88\x0f\x1c<\x8fwI9\x9e\xe6`R\x96\xa7\xfa\x98\x9c\xe9\x89n&ez\xaa\xa7\xc9\x99\x9e\xe8lR\xa6\xad\xfe\xa6\xe0p\n\x93w\xe3\x85\xfes;\xa1\x84\xe1\x89>(\xe1x\xb2\x0b\xcax\x9e\xea\x81\x12\x9e';\xa0\x8c\xe7\xa9\xfe'\xe1\xf9D\xf7\x93z\x1a~nO\x930<\xd1\xd3$\x1cO\xf64\x19\xcfS=M\xc2\xf3dO\x93\xf1<\xd5\xd3$<\xdb=\x8db:\xc7\xb6\xf3\x90EP\xf9y\xce\xf3x9\xb7\x7f\xd4\xcf\xb2?\xdd\xf1O\x10t\x04AG t\x08A\x87 t\x00A\x07 \xd4\x82\xa0\x16\x08\xedC\xd0>\x085!\xa8 B{\x10\xb4\x07B\x0d\x08j\x80P\xdd\x02\xa0:\xdb\xae\xed\xca+\x02\xde\x02\xbbJp\x8e}qf\xe8\xfa\x0b\xded\x05|$\x82\xb3f+\xe0C\x11\x9c5]\x01\x1f\x88\xe0\xac\xf9\n\xb8%\x82\xc3M\xed\x8b\xe0\xac\x19\x0b\xb8)\x82\xb3\xa6,\xe0=\x11\x9c5g\x017Dp\xd0\xa4%\xf6\xaf:{\x93:@v\xacQ\x10\xc3`V`\xae\x1d?h\xcb\xd8\xdeW\x08\xd3dVw\xbe\xe7R\x00\xcbb\x96ad\xe1p\xc8\xacG\x13\x0foP\\\x15s\xefB\xc3\xf95\x0b\x1ad\xdb6#A\x18\x06\x94\x08\x8e\xe3@lH\x08B\x08\xd0E\xae\xdd\n\xb2\xe8g\x7f\x00\xf5\xd7\x80\xc5\x02PV\x8c\xdc\xba\x92\xa1\xde\xd7\x19\x0cQ\xbcX\xf4\x0ds\x00IJ\x81\x86=\x8biN\x18\xdb\xc1\x92\x10c\xc0]\xe9_\x86\x98\xe00\xe7\xae\xd9\xef\x11\xc6\xe1\xb6Dd`H\n\n\xf4\xd7\xc5|a\xd8\x8cy\xa2u\x1c\xe1Z\x10\x0b\xf5\x1c\x9b\xbd\x9c\x90s\xa2qv\x7f`.z\x80\xea\"/\xa8=\xd1\xb5t}\xc4\xe8n\x15\xa6\x14&S\xe0\x9c\xb1\x10]>\xd2aW\xa0Q\xb6\xe9\x0eA\xb7G(\xa8{\x869\x1cZ=\xd6\xb3I\xc0\xd8\x1e\x0f\xfb\xb0\xdf\x11\xb01Bs\x87iW`o\xf6M'5\xe6\xfd> \xcd\x1c\xafQ\x03\xea\xf7\xc7\xec\xcb\n\x88r\xd3\x1a\"\x17\xb4)\x89\x1a\x0f\x1c\x87u\xe1\x1c\x85\x12\x1a\xe8\xb8\x88\x03n\xedd\x85\\\n\xb6\x18,\x16\x0b\x04\xc2(\x15\xa0\xd1\xc2]X \x8eq\xb9\xc5\xc2As\x10H\xf5\x10w\xe1ro'\xc3a\\_\xb1/\x80\xd5-AZkK\xad\x8e<\xe6\xb6\xf3\xb0,\xde\x91ZPH\x83\x90\x8ap\xd4B\xc8\x85$\x15\xe1\xb0\x85\x90\x0bP*\xc2A\x0b!\x17\xaeT\x84V\x0b!\x17\xbcT\x84\xfd\x16B.\x94\xa9\x08\xcd\x16B.\xb0\xa9\x08{-\x84\\\x98S\x11\x1a-\x84\xdc\x0cY\x11\xea\x96\x9c\x90\x0b\x81\xe6K\xad\x8e\x828\xca\xb6\x80\xa8&\x86\xdc\xa7-<\xaa\x89!\x17j\x0b\x96jb\xc8\x8d\xdaB\xa7\x9a\x18r\xa5\xb6@\xaa&\x86\xdc\xa9-\xac\xaa\x89!\x97j\x0b\xb2jb\xc8\xad\xdaB\xae\x9a\x18r\xad\xd6\x00\xact/\x9e\x92\x0f\xc7\xe6K\x8d\x88\xc8x\x02.8\x9b/\xb5&>\xe3\xf1\\\xa86_ju\xb4\xc6\xc3\xb9\xc0m\xbe\x14A\xb90n\xbe\xac\x824\x1e\xcc\x05u\xf3\xa5F\xc5u< \x17\xe2e\x92\xd7Q\x1e\x8f\xe7\x02\xbe\xba\n\x01\x01\x17\xfeU\xba/\x02<\x9e\x00\n\x06+\xc7\x80\xe0\xect9_\x16+\xe4\xc8\x8eQ\x90\xf2\x14D!l\xe3l\xc2\x03\xda\x01D\x98\xf3\xa5\x00\x0c\xc5\x9b\xb5\xa2D$|\xf49_je\x00\n\xe1\xf9X4s\xa3,\x1c\x85\xd0|d:_VA\x00\x87\xe7\xe3\xd4Zz\x11 \x18\xb5\xce\x97U@\nt\x02 \x86\xadk\x11RA\x11me\xb8<\xd4\xe4I\xa0\xf8v\xbe\xd4\xea\x10\x176\x1f\x1b\xedfM\x11\xa1\xf9\xd8\xb7i\x88\x88\x86\x8f\x84\x9b1&\x8b\xe0\x80A \x88\x8b\xf3\x81C\x00\x07\xa2d\xa2\xb3\xc2DP\xcc\x9cu\xd8,l\x86\xc6U>\x82\xaeZ\x91\x87\xab\x10 \x10O/Eh(\xba\xae\xdb \xa0\x81b\xed\x8a\xa6\x0e\xb7\x81\x81\x0d\x88\xbc\xb3a\x87\x08\xbe\x013\x02qxC$R2\x14\x957T\xe2\x0e\x06\xc4\xe8\x0d\x99hT\xe1#\xf6\xf9\xb2\x0e\xd79\x020r\xcf\xef\x97\x17s%t\x07\x9d,\xce\x7fn\xd6N\xec\xbb\xd7rd3\xf3\x8a\xb9\x11\x18\x8a%71\x17\xf0zn\x16sl \x14Cn\xe6.\xd0\xd5\xe4-\xe6W#(v\xdc\xcc^\x80\xe5\xacx6\xdc\xac_\x00\x8bY\\\xcc\xa8,\xa7Xq1A\x01%\xc3\x021C\nE\xb1\xe5\xe2\x86R+U\xe8 Q\\\x0d\xa1\x18r\x81\x05)\x81\x9c#\x81\xa1Xr\xa1\x07\xe1[y8\xd1\xe2\x7f\x05\x86b \x05'\x05E\x0bC\x88\x17;\xdc\x10\x1dI\x1b\xeb-]-C\x90\xecd+h\x92l\xd4\xcax$f\xcc.\x8fH\xb2a+\xe3\xa1\x981\xbbt\"\xc9\x06\xad\x8c\x07b\xc6\xec\xb2\x8a$\xb3Z\x19[b\xc6\xec\x92\x8b$\xeb\xb72\xee\x8b\x19\xb3\xcb1\x92\xcclel\x8a\x19\xb3K5\x92\xac\xd7\xca\xb8'f\xcc.\xe3H2\xa3\x95\xb1!f\xcc.\xf1\x88\xae$\xed 5\x82d\xdc\x96' Ie\x9d\xa4F\xc8\x98\xc3\x1d\xa5J%\xb41\x1f\xca\x99\xc3\x9d\xa5J5\xb41\x1f\xc8\x99\xc3\x1d\xa6JE\xb41\xb7\xe4\xcc\xe1NS\xa5*\xda\x98\xf7\xe5\xcc\xe1\x8eS\xa52\xda\x98\x9br\xe6p\xe7\xa9R\x1dm\xcc{r\xe6p\x07\xaaR!m\xcc\x0d9s\xb8\x13\x95\x81\x9e\x98w\x05 Y\xcb\xa2\xc3e[HW#\n\x8e\xd0\xd2\x00\x0c\x17\xa9\\\x8d\x94=\x174\x02\x8b\"8~$\xd3;\xd2*\xd8(\x12X\xb2\xc0\x01%\x91\x10\x92V\xc0\x84\x95\xc0\xb2\x19\x8e0\xcb\x0c\x92\x94\xb7\x94\xaf \xe4\xac\xd3MR\xceT\x84\x08,\xc9\xe0\x18\x94\xc9NIk\x00\"Q 9\x00\x07\xa5dJK\xae|&4\x05V\x89p\x94J%\xc1\x14\xda!\xadC\x10\xb6Ry\xb3\xf6~@\x06\x9c\xc0\xbaP\x18\xc7V\xa96i\x0d-\xcc\x05\x81-\x95\x98\x93\xf2'q\x82Z\x84i\xbc\x9a\x89B \xbddci\xae\x1a\x85\xb0z\xa9\x12Y/\xd9\xe0ZZ\x93 \xce^\xaa\x84\xdaK6\xda\x96\xd6$\x08\xbc\x97*\xb1\xf7\x92\x0d\xbf\xa55 \"\xf1\xa5J0\xbed\xe3qiM\x82\xd0|\xa9\x12\x9d/\xd9\x00]Z\x93 V_\xaa\x84\xebK6b\x97\xd6$\x08\xde\x97*\xf1\xfb\x92\x0d\xe1\xa55 \xa2\xf9\xa5J@\xbfdcziMpdBl\xf6\xb5\x8fA\x92\x9e\xab\x16\xef\x13\xbb\x83\n\xb5\x89{\xaf\xda\x02\x80\xd8NT\xa8M\xdc\x83\xd5V\x04\xc4\xfe\xa3Bm\xe2^\xac\xb6D 6,\x15j\x13\xf7d\xb55\x03\xb1\xc3\xa9P\x9b\xb87\xab-\"\x88-Q\x85\xda\xc4=ZmUA\xec\xa1*\xd4&\xee\xd5j\xcb\x0cb\xd3U\xa16q\xcfV[wT;l\xe2\xaajDQO\x15\x14\x01\xdbo\x05^\xca\x8c\xe3\x03\xed\xcc\x15\xd0zsN\xcc\xad\x810<\xf9\xad\xbb\x82\xa0\xd8\xbd\x133,\xcb\x19n\xfc\xc6^\x81^\x86X\"\\^\xcap\xe27\xfd\nl\xb1\xc7 \xe6U\x96\x93\xdc\xf8-AR'm\x0c)\x14-$\xb0mX\xd0\x14{\x80b\x9ee9\xc5\x0d\xdaT$%h\xe3I\xa1(\xce\xd0\xc6#\xe1\xb0\x91\xe0\x05\xbd,\x84\xe2 \x9f\xbc\xcb\x08\xaa\xcdI1\xcb\x1a\xc1\xb97\xbbsYjK\xca\x0d\xe2\xc4\xefjR:\x92\xf2#0\x0cW~\xdf\x93PQ\xbec\xd6\xa2\xc6\x02Cq\x85vF\xcbN!g\x08\xf1\x02\xb6M\xc96\xb5p$A\x14_hg\xb5 \xec\x8dd\xcd\x98\x97R\x9c\xa0]WB?s\xbc\x968x\x03ax\xf2\xdb\xb2\x05\x81\x9c\x1d\xcf \xda\xb2%U#\xe7G`h\xed\x01\x9b\xba\x04E\xb5\xaf\xdb\xc2\xb8\x86Q\xbc\xa1\x9d\xdf\x82\x88\xd8\xfc\x15s&A\xb4\xaf\x03\x9b\xc3\x14I\x8b+Q(\x8a3\xb4\x81L\xd1\xb4\x0d\xc74\x8c\x96\x1a\xd8e\xa6\x88\xa43$\x81a\xb8\xf2\xfb\xd0\xa5\x07-\x15b\x02\x12T\xf0\x05\xd2&\xc2\x08\xa18\xa6#\xe5.c,\x0e\x19\xc8#=R\xf6l\xe0\x00U\"\x8a!\xeaC@\xd2\x1a\xa8H\x02b/\n*\xca3CR\xe6Dh\x01\xb1\x16E\x19\xf5\x01#)s\xca 9\xf6\xa2\xb0\x839\x8f\xa4\xa0}y=\x928\xa4>\xc4$\xad\x84\x8a\x19x\xf6\xe2\xc0\x849\xf3\xa4\xd0\x92\x96\xaa\xc4\x91\nyP\xaa\xbd\xb3\x11\xb37_\x898t!\x8eVI\xeb`\x02\x18\xb8\xdf\xc1\xb1Ly\x16Kn\x0f9kQpC\x1d\xdcR\xb1\x85\xbc\x1aQ\xb4C\x9d\xf5j7\x059\x07\xf0\xd5\x88\xc3\x9f\xeax\x98\xbcw\xcb\x99\x0b\xe3!\xfa0\x99\x82\xae\xe4\x15\x89\x03\xa4\xf2\x00\x9a\xb4\x06\"L\xe2Y\x8b#&\xf2\xb4Z\xbb\x19\x889\x1e\xaaD\x18B-\xdb\xf9KY\x8bc*\xea0\x9c\x82 \xa4\xd5\x88\x83,\xf6\xfc\\{ML\xa8\xc5W&\x8e\xba\xe8Sw\xd2\xaa\xf8\xd8\x0b\xe8\x84\xc20\x8c9\xa9\xa7R\x93\xdc\x85\xc5q\x19{\xbcO\xa5\xae\xb6 K\x18\xa8Q\x87\x02Uj\x92\x07&\x92\xc8\xadu\x17\x99\xc0\x08*\x00\xf7\x94#[?\x08\xbe\xdf\x1a\xd9F]\xd4\xedY\xdc{j#\xbb\xd7\x94C\xc5f]\xcc\xbfY7\xb2\xfbu)\xffj\xdd\xc8\xb6\xeaR\xfe\xdd\xba\x91=\xa8K\xf9\x97\xebF\xf6\xb0\xa9\x97\x7f\xbbn\x84\xeb\x06k\x18-R\xae\xd5\xd8\xa0\xcb\xc1\xa6\xe3\x1e\x03\x820&\x8d\x01\x94\x80\xfb4\x04\xd0\x04\xb6h\x08\xa0\x0e<\xa0!\x80N\xf0\x90\x91\x05PL\xdc(&\xce\x06\x16N3\xb1\xc1\x00@\xd5\xc4=\x16\x05\x81L\x06\x04('\xee3\x18@;\xb1\xc5`\x00\xf5\xc4\x03\x06\x03\xe8'\x1e\xb2\xf2\x00\n\x9a7\n\x9a\x87i\x1a\xfa\x9c\x86\xe6\x06\x8b\x00U4\xefq0\x08e\xb2(@I\xf3>\x0b\x02\xb44\xb7X\x10\xa0\xa6\xf9\x80\x05\x01z\x9a\x0f9\x99\x00E\xa5\x8d\xa2\xd20\xe2\xb4\x94\x1aT1\xa8\xa2\xb4Gc \x88IA\x00\xe5\xa4}\n\x01h&\xb5(\x04\xa0\x96t@!\x00\x9d\xa4CZ\x0e@!\x1bF!\x93\x16?\xda@\x1ab\x89@\xbdm\x00\xbdq\x84\x10\x1d\xafL\x96\x0cP\xf0\x86W0K\x05(}\xc3+\x9d\xa5\x02\x0c\xb1\xe1\x0d\xc1R\x01\xc6\xd9\x00\xc6\xe1\x1a\x06Xl\xc5\xce\x125\x11<6\xae\xc0Y\x83!\x02-\xb6\x82\xa6\x12\x96\x10\xa2\x03\xa6\x17\x86\x0c\xb0\xd8\n\x98q\x18*\xc0b+`\x12b\xa8\x00\x8b\xad\x80y\x89\xa1\x02,\xb6\x82\xa6*\xb6a\xc0\xc7\x85l\xfd\xe0\xdb\xf1\xd2\x0bX\xdb\xf8\xb6Q\x95@\x06\xf0\xed^]\x0c\x95\x9aU)\xf0\x95'\xbb_\x15\x02\x9fU\xb2\xad\xaa\x10\xf8Z\x92=\xa8\n\x81\xaf-\xd9\xc3\xbaN\xa0\xa1\xb8j(\x18\xbf\xf8\xd8\xa0\x8a\xc1&\xe3\x1e\x8d\x81 &\x05\x01\x1a\x8f\xfb\x14\x02\xd0\x00\xb6(\x04\xa0\x06<\xa0\x10\x80.\xf0\x90\x96\x03PH\\+\x04\xec\x9b~l\xd0\xe5\xa0J\xe2\x1e\x03\x820&\x8d\x01\x94\x12\xf7i\x08\xa0\x95\xd8\xa2!\x80Z\xe2\x01\x0d\x01\xf4\x12\x0f\x19Y\x00\xc5\xcck\xc5\xc0\xf3\x8c?7\x18\x00\xa8\x9ay\x8fEA \x93\x01\x01\xca\x99\xf7\x19\x0c\xa0\x9d\xb9\xc5`\x00\xf5\xcc\x07\x0c\x06\xd0\xcf|\xc8\xca\x03((\xad\x15\x04\xc4)~j\x90\xa5\xa0j\xd2\x1e\x05\x81\x10&\x89\x00\x94\x92\xf6I\x00\xa0\x91\xd4\"\x01\x80:\xd2\x01 \x00t\x91\x0e)\x19\x00ElhEL\xe4n\xb3\x01\x143Qp\xa4\x0d\xaf-\x96\x0c\xa2\xe248i\xf5\xb4\x0d\xa7\xd4I\xab\xe7m8=OZ=q\xc3\xa9~\xd2\xea\x99\x1b\xde\x1al\x83\x00\x0b\xad\x98Q\xbf\"\x81\x87\xbc\x154 \xd0$\xa0\x85V\xc0\xc4\xc0\x90AT\xfc\\A\x13\x01\x16Z\xf1\xb3\x07M\x03Xh\xc5\xcf'4\x0d`\xa1\x15?\xc3\xd04\x80\x85V\xc0\x9c\xc34(\xb7P\xfb[-\xe9\xd7\nFv\xfer\xce2\x96\x01\xf2-d\xa9 \xe5BA \x84I\"\xc0\xc4\x0b \x00s/$\x00L\xbf\x90\x000\x03C\xc9\x00&a\x08\x84(\x0f\xc3A\x04\xa9\x18\x1e\x07\xc1L\x0e\x06&d8\x14\x98\x93\xe1P`Z\x86C\x81\x99\x19^.09C\xc2D\xf9\x19\x1e#H\xd1\x00@\x08g\xf280Q\xc3\xc3\xc0\\\x0d\x0f\x03\xd35<\x0c\xcc\xd8\x00\xb2\x81I\x1b\x12'\xcc\xdb\x00 A\xea\x06BB@\x13\x00\x82 \x1c\x00\x07\xe6p\x00\x1c\x98\xc6\x01p`&\x07\x92\x0fL\xe6\x90@8\x9f\xc3\"\x04)\x1d\x0e\x06\xa1L\x16\x05&vX\x10\x98\xdbaA`z\x87\x05\x81\x19\x1eN&0\xc9\xc3)\xaa=\xcf\x03kN1\xd5\x03\xeaS-\xdb\x03)Y)\xe1\x03)^)\xe7\x03\x19C)\xed\x03\x19H)\xf3\x03\x1aM-\xf9C\x92*\xe6\x7f8\x92cR@<1D\x0b\x91\xc2\xd3\x9aJ\"\x88#T\xcd\x05q\x84\xaa\xe9 \x8eP5#\xc4\xb7Q9)\xa4\xe5\xdfs\x8f\xe1\xbc\x10Q(H\x0d\x91\x08\x08`\x12\x000AD\x94\x839\"\xa2\x1cL\x13\x11\xe5`\xa6\x88\xac\x1fL\x165\x00Q\xbe\x88E\x08RF\x1c\x0cB\x99,\nL\x1c\xb1 0w\xc4\x82\xc0\xf4\x11\x0b\x023H\x9cL`\x12\x89@\x89\xf2H\x1cD\x90J\xe2q\x10\xcc\xe4``B\x89C\x819%\x0e\x05\xa6\x958\x14\x98Y\xe2\xe5\x02\x93K\x04L\x98_\xe21\x82\x14\x13\x00\x84p&\x8f\x03\x13M<\x0c\xcc5\xf100\xdd\xc4\xc3\xc0\x8c\x13 \x1b\x98t\"pp\xde\x89\x01\x08RO,\n\x02\x99\x0c\x08L@1\x180\x07\xc5`\xc04\x14\x83\x013Q\xac<`2\x8aUPk>\nT\x98ZJ\n\xd2\xa2RV\n\xd0\xacJb\nP\xb6Jn\n\xd0\xbfJz\n0\x89J\x86\n\xb2\x92R\x92\x8a T\xcbS\xb1\x04G\xa4\xaa8R\x80\x12\"\x04\xe7(\x85\x84\x15K\xa6\x98\xb3b\xc9\x14\xd3V,\x99b\xe6\x8ak\x9b(y\xa5\x90\xbdR\xf8&Kd\xeb\x9a_\xc5fPF\xab)\x14%\xb4\x08\x04\x040 \x00\x9c\xcej\xca\xe1lVS\x0e'\xb3\x9ar8\x97E\xd4\x0f\xa7\xb2|f\xad\xc0\"\x0c\x16!Jd\xb10\x08e\xb2(8\x8d\xe5\xf3\xb1=\x0b\xb2X\x10\x9c\xc4\xf2\xf9\x98\x9d\x05\x0d9\x99\xe0\x14V\x83\x12f\xb0X\x88(\x81\xc5\xe1 \x98\xc9\xc1\xe0\xf4\x15\x8b\x82\xb3W,\nN^\xb1(8w\xc5\xc9\x05\xa7\xae\x1a\x988s\xc5aD\x89+\x1e\x08\xe1L\x1e\x07\xa7\xad8\x18\x9c\xb5\xe2`p\xd2\x8a\x83\xc19+^68e\xd5\xe0\x04\x19+\x1a JX1(\x08d2 8]Ec\xe0l\x15\x8d\x81\x93U4\x06\xceU1\xf2\xc0\xa9*FA\n\x99*Hc\xaa\x89*@\x8f\x8ay*^\xb9ji*^\xe1jY*\xde\x08jI*\xde0j9*\xc0X\x8a)\xaa\x86R5C\xc5P\x1c\x95\xa0bi!R\x88\x12\x9c\xae\x94\xd2S\x0c\x9drv\x8a\xa1SNN1t\xca\xb9)\xb6}\xea\xa9)\xbf\x8c\xd4\xa0\xccT]&JL5\x00\xa8\xdcl\xca\xe1\xb4T]\x0cg\xa5\xeab8)U\x17\xc39\xa9\xa6n8%\xe5\xd3k\x04\x16`0\x00QB\xca\xe7\xc3\x7f\x16d2 8\x1d\xe5sq=\x8b\xb1\x18\x0c\x9c\x8c\xf2\xb9\x88\x9d\xc5\x0cYy\xe0TT\x0d\x12f\xa2\x18\x84(\x11\xc5\xc2 \x94\xc9\xa2\xe04\x14\x03\x82\xb3P\x0c\x08NB1 8\x07\xc5\xca\x04\xa7\xa0j\x948\x03\xc5BD (\x0e\x07\xc1L\x0e\x06\xa7\x9fX\x14\x9c}bQp\xf2\x89E\xc1\xb9'N.8\xf5T\xc3\x04\x99'\xaa\\\x94x\xa2A\x10\xc6\xa41p\xda\x89\x82\xc0Y'\n\x02'\x9d(\x08\x9cs\xa2e\x81SN\xb4b\xda3N\x80\xa2\x14\x13N\xbc\xf6\xd4\xf2M\x9cF\x95\xd2M\x9c\x92\x95\xb2M\x9c\xde\x95\x92M\x9c)\x94rM\xbcu\xd4RM5\x9db\xa6\x89\xc6\x1f\x93hb(\x01B\x88\x0e\x9a{T\xd2L4\x95j\x96\x89\xa6RM2\xd1T\xaa9&\xa6]\xa7\xa5\x98\x04\xd9$\\\x85SP6\xa9)\x14e\x93\x08\x04\x040 \x00\x9cMj\xca\xe1lRS\x0eg\x93\x9ar8\x9bD\xd4\x0fg\x930\x13\xd7\xb3\x08\x83E\x88\xb2I,\x0cB\x99,\n\xce&a>\x16gA\x16\x0b\x82\xb3I\x98\x8f\xb2Y\xd0\x90\x93 \xce&5(a6\x89\x85\x88\xb2I\x1c\x0e\x82\x99\x1c\x0c\xce&\xb1(8\x9b\xc4\xa2\xe0l\x12\x8b\x82\xb3I\x9c\\p6\xa9\x81\x89\xb3I\x1cF\x94M\xe2\x81\x10\xce\xe4qp6\x89\x83\xc1\xd9$\x0e\x06g\x938\x18\x9cM\xe2e\x83\xb3I\x0dN\x90M\xa2\x01\xa2l\x12\x83\x82@&\x03\x82\xb3I4\x06\xce&\xd1\x188\x9bDc\xe0l\x12#\x0f\x9cMb\x14\xa4\x90M\x824\xa6\x9aM\x02\xf4\xa8\x98M\xe2\x95\xab\x96M\xe2\x15\xae\x96M\xe2\x8d\xa0\x96M\xe2\x0d\xa3\x96M\x02\x8c\xa5\x98Mj(U\xb3I\x0c\xc5Q\xd9$\x96\x16\"\x85(\xc1\xe9J)\x9b\xc4\xd0)g\x93\x18:\xe5l\x12C\xa7\x9cMb\xdb\xa7\x9eM\xc2eP\x06e\x93\xea2Q6\xa9\x01@\xe5fS\x0eg\x93\xeab8\x9bT\x17\xc3\xd9\xa4\xba\x18\xce&5u\xc3\xd9$L\xaf\x03X\x80\xc1\x00D\xd9$\xcc\x07\xf9,\xc8d@p6 s\xf1;\x8b\xb1\x18\x0c\x9cM\xc2\\l\xceb\x86\xac{U\x1fl?w\x15\x1fV\x00w\x17\x1f\xd4\x00w\x19\x1fR\x01w\x1b\x1f\xd2\x01w\x1d\x1fR\x02w\x1f\x1f\xd2\x02w!\x1fT\x03}\xe7\x1e\xd6\x01}\xe9\x1eT\x00}\xeb\x1ej=}\xed\x1ej:}\xef\x1ej7}\xf1\x1ej4}\xf3\xbelq\xfb\xc1\xcb\x033f\x90\x17UD\xa3\x1d\x05\x01\x07<\x12\x01\x8ey$\x00\x1c\xf6H\x008\xf2\x91\x00p\xf0\xa3d\x00\xc7?\xf6\x00\xabh\x08\xe4q\xe0(\xc8\xc1\xc0\x81\x90C\x81c!\x87\x02\x87C\x0e\x05\x8e\x88\xbc\\\xe0\xa0H\xc0\xe4\xe3\"\x00\x04\x87F\x1e\x07\x8e\x8e<\x0c\x1c y\x188F\xf20p\x98\x04d\x03GJ\x02\xd72XBHp\xbc\x04\x80\xe0\x90 \xe0\xc0Q\x13\xc0\x81\x03'\x80\x03\xc7NH>p\xf8$\x80\xb2\x11\x94\x83\x81\x83(\x8b\x02\xc7Q\x16\x04\x0e\xa5,\x08\x1cMY\x108\xa0r2)l5\xaa\x9ef\x0f\xc8\x83W\xc2\x81\x96@\xc0\xe3l\x03\x80\x87\xd9\xa6\x1c\x1ee\x9brx\x90m\xca\xe11\x96\xa8\x1f\x1eb\xe9\xfd[\xe1\x08\xcb\xc2\xe0\x01\x96A\xc1\xe3+\x03\x82\x87W\x06\x04\x8f\xae\x0c\x08\x1e\\Y\x99\xe0\xb1\xd5gF\x1b\xd1\xd0\xca\xe1\xe0\x91\x95\x85\xc1\x03+\x8b\x82\xc7U\x16\x05\x0f\xab,\n\x1eU9\xb9\xe0A\xd5g\x07\x18\xd1\x98\xca\x03\xe1!\x95\xc3\xc1#*\x07\x83\x07T\x0e\x06\x8f\xa7\x1c\x0c\x1eNy\xd9\xe0\xd1\xd4\xa7\xc6\x1a\xd1`\xca\xa0\xe0\xb1\x94\x06\xc1C)\x8d\x81GR\x1a\x03\x0f\xa44\x06\x1eG\x19y\x14\x86Q\xc1\x88\x89\xeb\xe1F4b\x12\x08x\xc4l\x00\xf0\x88\xd9\x94\xc3#fS\x0e\x8f\x98M9\x96\xdc\xca\x05\xfajr\xc1\xa8\x10\xa6\x95C\xdb7\x12Kf\xae\x1d?\xb4\xf2\x92}I5\xe3\xf3\x80\x0e)\xda\xa5\x9a\x8b\x9c0\xb6S/\x0c\xce\xb1\x17 -]\xc5\xe1z\xb9\xa2 \xd6\x81\x8b\xe2\xac\x98\xa3\xa9K\x18\xc7\x0b51M\x10\x06Ha\xe9s\x00d\xce\xd6Q'\x88\x0d\x91)H\x0e\x91\xe5\xc2+H\xaf\xb0p+\x9b\xe4\x9f\xd4\"\x9eJ\xa5A<\x95B{\xc4\xa2\xe3\x93D\xe7\xa9TD\xe7\xa9\n\xd1)\x8a\xb4D\xd9\xd8[\x06\xe7YT\xc0\x94\xc7dy>Q2\x00\x87\x048(HQ\xac`\xed\x03#E\xed9bA\x18\x08(\x0b\x83)\xc5Q\x90G\xc1\xfbR\\y\x83DF\xbf]D\xffh aaZ-G#`a0$\x0c\x0d\xaa,\x9c\x7f!~\x11\xc6\xfe\xb9cG^jc\xef\x11\xb1P\xccBq\xb8E\xb1c'\x1cr\xcd\"\xd7Q\x04#\x03\x16y\xd2p\x98\x12\xce\xa1\xd4\x12\x00-n\x0c\x00\x16\xb7\x07\x00+\x0c*\xcan\xda\xb8\x98Z;9\xb0\xa4\x99\x1cV\xd2J\x0e\xab\xd0HA{8\xb7\x92\xb5\xe7\x08\x1f\xe4\xb1\x92\xf6pX`8]h\x833\xe6\xc1\n\xd9n>\xab/\xc2 \x8b\xf5\x1e\xd19\x1fR/4\x8b\xa5K\xd6s\x80\x94\x0f\xa1\x17\x06Ql\xf2\xc5=\xa2\xb8\x07\x05\xea\x0b\x93@\x18@\x90\xbe\xe8S\x00\x88\x85E\"\xf8\xe2\x01Q\xdc\x1d\x0d\x01\x06C\x12Q\x00\xda{\xc3\x81\xd5\xbd\x16$\"\xf5g\x9d\xae\xc5\x02\x005a\x04\x9a\x01d\x07\x1a\x01\x99\x82F\x08\xacA\x83`\x83\xb0\x18\xd0&\x0c\x080\x0b\x8d\x10X\x86\x01\x15\x18\x05\xeb(\x8cU\x99\xc9|\xa1\xc5\xfcV\x83q\xb4\xa4\xbd\xfc6s\xf9m\xd6\xf2\x15\x8c\xe5\xb7\xdb\xcaW0\x95\xdff)_\xc1P\xfe\xb1v\x12\x98\x04\x0bM\x82[M\xc2\xd1\x92&\xc1m&\xc1m&\xc1\n&\xc1\xed&\xc1\n&\xc1m&\xc1\n&\xc1\x80I(\x8c\x8f\xecd\x1d\xa3C\xd3O\xb2\xce\x03b\xb2r\n\xd8\x17\x01\x03;\x8e\xc3-\x01\xedq<\xbd\xc0EAZLi\xc5\xcf\xe7Fs\"+m?\xcf\x98\xf86\xc6\x9acG\xe5\xe8\xb0\xb1c\xcf\x0e\xd2\xf3\xe69\x8dO\xe3u\xe0\xd8):\xe4\xc9\x81<5\x82\xce\x83p\x1b\xdb\xd1$\xdc\xa0x\x91\x7f\x9c\xcfs]\x14Lr\xa9\xea\x87\x08c/J\xbcDa\xcc9\xc0\xeaH\x94\xd5\xcb`[4L\xa3EJ\xae\xe3\xbd'\xea\xb9\x1e\x88UU\x9d\x11\x9c\xaem\x05u+\x0c\xf1\x95\xc2|u\x13\xf8\xc7X\xc0W1\x80\xff<\xfa\xf7\x8fT\xbf\xff\xdd\xb4/Q4VW4>F\xd1XE\xd1\xf8y\x14\x8d\x8fT4~\x8a\xa2)\x96U\xb9\xe6\x84Aj{\x01\x8a\x0f\xf5\xa3\xfdy\xe2\xc4!\xc64E\xb1h\xa6\xb7\x12\xecu\x1aN\xc8\x9d\x96\xec\x01\xa3\xddX\xcb\x1e\xf2t\x0c\x0cS\xb0\x86Y{\xe7<\x00bj\xec\xd9\x1buIARPX\x8d9\xf4\x94\x03\x15\x04V\x18M\xcaV\xf8'7\x02\xa0\x84\xdb\xe0\x1f\xdb\x04\xb1\xb4\xf8di\x01JXZ\x0cHK\x8b\x82\xbd\xe8\x10\x85\x89\x97'\x02\x17\xde\x0e\xb9\xff\xd7\xf3\xa30N\xed \x9d\xfcQ\x97\xd8\xf3$\xc4\xeb\x14\x11\x85\x19\xe9y\x8c\x9c\xf4G#\xdau\x88\xbf?\xd1Eg\xc4\xdf\x9f\x14\xcc}\xe0\x04\xcc\x1c\xe7\xcf\x94QAH\x15\x9f\xcc$\xf7\xff\x83\x04\x17\xc9\x88\xff\\\x19)\x01\xb6\x89\x16\x84\xb1o\xb3#u\xf6\x88F\x16\xa370\xa0\xd3\xb0(\xa6#\xc9(>>'X\x0b\xc5\x07J\"\xb9\xe0\x90\x8a\x13\x8d\x85e\xd2)\x88\xa7\xe0m\x8d\xcclt!\x14\x19\nCx\x89\xfd#\x05\x96\xca\xa6jfp\xe6\xe6e\xc3\xbcl\x14f\xa3\xcd\xed\x04\x1d6(N=\xc7\xc6e:;{\xc6\xef\x91l4\xdfsY\xa8\xef\xb9.\xe6\x80i\x18\xb1\xc04\x8c\xb8\xaaS\x9f\xab9\x0fp\x14\x0c~\x00\x9a\x91\xf9\x8ezK\x00\xb4\xb01\x00\x16n\x0f$B\xd1$\x856)8q\xd9P^o\x92vr`q39\xa8\xa0\x95\"\xbb\x1d\xed\xf8e{\xf01\xed\xe1\xc0\xe2\xf6pPA{\xf8\xfa\xcb\xf6PX\xd7\xf3\x0fad;^\xba?7\xb8\xa23\xf6\x01\xf41\xfa\xecq\xf1\xfdym\x8b\xe6\x0f^\x99\x15/f\x90\x92w\xa7kXI\x07ez\xf1\x82IK9'\x86\xbc\xd6J\xfc\xae\xc5\x13\xdaN\xeamP\x03\x19M\x94d\x0c\xd7\xa9\\\xc8p\xcd\xec\x9e-q\xb8=\xe3\x9e@\x82\xe7\xcf\xbf\xa3\xbe\x14\xea\x15\x18|\x95-\x03\xf3S\x11\x9dn\xfe\x9f\x1a\xa8\xab\xa9\xedXQ\x9b\nKC\x95\xf5\x9e\x89Py\xb3\xda@y\x1b\xd9\x16\x18\xdf\xa7\x05\xcd\x06{^+\xa4w\x16R\x98 _\x7f\xb6\xef\xe1/\xe3p{\xd0\xfc\xf0Q\x0b\x93\x9dVd\x0f\xfd0LW^\xb0<_\xc6\xf6>ql\x8c\xea\xb6\xcdm\xe7aa;H\xdbx\x897\xf7p\xd6\xf2r\xc1+)\xa24\x93of\xe5?a;E\xdf~\xd4\x7f\x9a\x88\x9e\x03\x1a\xe5Xu\xba=A\xa7:\x02z:\xe4\xac\xa5\x16^\xdb`\xd7\x89\xe1.\x9b\xeb$\xb7\xc0\x8fFW\xb7HM\x11O\x81:\xcaaI\xc4\xac;\xe6Yu\xc7\x00#\x0d\xdb\xf1\x12\xfd\x7f\xc5A\xbc\xe0\x18\x1f\xe1\xd1OEI\x9d\xa5\x80\x88L \xf2\x9a\xb2\xb4\xcdwz\x90\xeb\xf4\x84\x06o\xf7\x1f\xc0\x17\xb3\x87L0\x1dzAZ\x8fH\xce:N\xc2\xf8\xbc|H#\x93\x95\xed\x86[\x0d\x02N\xea\xc5b\x8c\xb0\x9d\x89\x05\x99\xdd\xc6\xb8\xd3\xb5\x92\x8e\xb3\x9e{\x8e6G\x8f\x1e\x8a\x7f\xec\x1a\x03\xeb\xac;\xea\x9fu\xfb\xfd3\xe3\xa7\xc9\x91x\xb1\x88\xe7\xf6\"\xcd\x04\x0d\x83\x14\x05\xe9\xf9_\xfe\xd2\xf8\x7f\xb8\xd3\n\xe4\xb9\xde\xd1;\xc6 \xdauz\xd1\xaeC\x9e\xf7\xeb\xfd4Q\x86\xe5\x07;c\xdb\xf5\xd6\xc9\xb9\x17\xacP\xec\xa5\x93f\xd2\xe4\xd6\xd1\x93\"\xf3\x99\xe7e\xf4I\x11A\x1a\xba\xfeb\xb2ByN'\xff\xf91\xcf\x98\xee\xce5\xf9\x9cu\x846Ui$\x1a\xcd\xfd\xbb\xd0\xeb\x99\x18Ej_\x10d\xcc\x97\x9a\x1dx\xbe\x9d\xa23\xc1s\xa8/\x11\xa5\xc2\xd0\x89=\xc4IM\xdb\xec(\xd0\n\xa6\xa5~\xd4\xf4Ce\x17\x9d-2\xea\"\x83-\xea\xd5E=\xb6\xc8\xac\x8bL\xb6\xa8_\x17\xf5\xd9\"\xab.\xb2\xd8\xa2\xf1x\\\x17\x8e\xc7c\xa0\x98*\xe7\x00\xbe\xbdk\xa45\xfa\xc3\xfe\xc8\x1c\xf4\x87,\xaa\xf4\xf2\x1aY\xfe\xce\xc3\xbc\xd4\xb3q\x0d\xe3\xb3\x95\x8f\xda:HP\xc3(\xff\x8d\x86\x04(IQf\xa0h\xaf\x15\x11T\xdeM:!\xb3\xaf,\xc2Ej\xb05>\x10\xbf\x9e\x1b\xecB\xa2\xa4k6\xae \xda\x95\x01\xd6\x01c{G`\xcd#\xb0\xfd#\xb0\xd6\x11\xd8\x01\xa3\x17\xe8`\x7fA\x8f\xbd$\xd5b\x94 \xa1q\x08\xc4\x9a{\xf1\x1c\x99\xaf\xd6'94I\xf7\x18i\xe9>B\xc5\xd1*\xa1%\x8b\xed\xa5N\xf4sDm7u\x8f\xdbo\"9&(B\xb1\x9d\x86q\xce\x94\xe0at-A\xfb=\x7f\xd9\xf1\xfc\xe5\x81\x18\xd2\x9b\x9cG\xfe\xab\xeb%\x11\xb6\xf7\xe7s\x1c:\x0f\x02\x1d\x06\x0fI\xc7>\x94\xe7\xe1Mk\x88\\\x17\x9a\x02\xf8\x01k\"-\x95\xd5\x06\x0d\xb6\x0c\xa2\x9c\xf5\x0b\xa9\xc6\x03\xc7Y,\x9e_\xaamlG\x11\x8a\x05\n\xec\x0f\xf4hW\x1a\xf0\\\xef\xe4\x9b&\xa5\x0b\x9d\xeb\x9d^VH\xcd\xf0\xdecVRN\xcf\xf3p7\x01\x9f\xd2\x12\x84Qn\x1a-\xb5\x97Z\x82\x9cL\xeaCe4\x82ymH\xcdO\xb4\x05F;\xf2Y\xf6;%I\x18{\x993V\x99\x18\xaa\xcc\xf5\xe2\xa2\x9a2%:\xa98\x12%N\x88\xd7~0\x01\x9f\n\xc5\x7f\xba\xd8\xe4 \xe0F,\xeai\xfe\x8b\xe6\xa5\xc8O\xaaG\x95E\x0c=\x0b\x97\xb2\x7f\x8c\xea\x9f \x134\x8aB\xc4^\xc2E\x81\xbddR\x9b,\xef\xb9F\xb4\xeb$!\xf6\xdc\"\x1c\xb3\xc6g\x03\xebld\x9cu\xcd\x9f\x84*)\x9d\xb8\x99\xf5\xa9\x1b\x1e:\x1bj\x93\xca$\x8e\x18\xf5I'\xd4;V\xb4\x9b\xe4\xa5\x0b\xdb\xf7\xf0\xfe<\xb1\x83DKP\xec-&U\x1f\x9e\xf7\x0d\xcb\x10\xf2\xee\x06\xa1\xe6\xa2\xc4\xe9$\x91\x1d\x1cH\x03d\xfa>7j\xd5\x9f\x1b\x93\xe2?BV\x9dd\xb3\x84\x82\xa2\\\x85}^\xab\xfdD\xc2\xca\xb71u\xde\xa9_5t[\xcc\x04}]\x9f\xa8HK\xf4\xd1\xdc \x8eWVd\xc7\xb6\x8fR\x14\xff\xf1G6\x15\x90B\xf5\xa2]\xcd\xdf\x8av\x1d\x9db\xef\x87A\x98o\x10P\x82\x0ft]V\xdb\xc6C[\xad\x9a\x06\x1f\x0e\xfc\xca&\x9b\x04\xcch7\xa9\x0e>\x90\xfe`\xa9{\xb9\xc5\xdb\xc3\x82\xedq \xdc\xcd\xc8j(\xba\x02\xd1\x07\xfe\xaa\xeb:\xb3\x10\xe9\xb3\xc3a\xb3\x921\x99E\x8c1\xe6\x16;\x00\x04\x14\xad\xd3M\xedy\x1e8\xa0\xf8\xe9#\xceQ\x0eOV]\xfc\x9c\x8dC\x87\xc6\xdb\xfa\xfc\x90s\x04\xa3\xf3\x85\x17'\xa9\x16.\xf2\xf0\x83a\xdb\xd1;\xfa\x11\xbc\xbaebs\xd5/:9\xe7S\xa7\xf3*\xd7Y\xfc\"\xb3\xbe\xad\x999L\x1eSY\xfa\x8bj\xb5\xd9kV\x9b\x99\x9f\x00kd \x9b\xf3\xfb\x8f\x9a\xa5\xbf\x00\x13=U\x111\xb4.c{\x0f6\xab\xeb%Z\x18\xa1\xa0\x19n\x92\xb5\xef\xdb\xf1\xfe \x1a\xe13\xef\x16h\xa8fQL\x8a\x95'V\xd6\x1a\x95s\xd0\xc4\xf7\x82*\x82\xb5\xb2\xdf A\xd9\x1b\x83\xa3\x9f\xe0~c\x00\xcb\x7f\x83\xe980\xe6(\xd9\xcf\x8e\x01w\xb0=G\xf8\xe9\x1d\xef\xa4\xa9\xfe\xa8f\x95\x922C79,\x0fu\xbd\x1eG\xb9\xc30'\xcc\x1aJ\x02\x95\xfd\x91\x9a\xa1$\x9d[\xc0j\xd5g'J\x95Q\xadi\xeds4\xae\xe8C\x9a\x8f\xd2U\xe8\xca\xe6\xed\\\xcf\xf5\xd6\xe5H'f\xd0A\x16\xa8e\xe3\x05w\x03\x8c\x99\\L\xba\x0b\xe5\xd3ONC\xf5\x04\x9d\xed+\xf2v.\x16\x0b\xc5F\x86\xf9\xd2,3\x80\xe7\xb6\xf5\x97\x92$\xb2\xd3\xd5\x11\xd0?\xfepQ\x14#\xc7N\x11\xa5\xccAD\xf4\xacS{[n~\xbdq\x08\xbdc\x16\xab\x19\xfa\xb7'w\xd0\xc96\x8c]m\x1e#\xfb\xe1<\xffW\xb31\x96\x85c\xaa\xf1R\xb9\x19N\xec\xe8\x0f\x07\xa3h\xc7l\x81\xff\x07\x9a\xaf\x17\xed\xd8\xd3\x9d\xcal\xd8\xcd:,\xbc\xa6\xab\xd4p\xa6\x8b*r\xc8\x16\n\xb1\x17\xe5\xebR\x82\x81\xa9:\xe4<\xdfH\xf3?4\xe9\x90\xd1\xbeZp\xc7\xc8\xad\x18\xe0\xf7\xea\x00\x9f\x98\x95\x9e=\xb2\xe7\xa4\xab\xf6\xad\x19\x19\xcb\xb0m\xc4,5\xe0\xf8\xaab\x19\x85IJ\xbc\x8f\"3p\x7f\xec8c}\xc2\xae\x80\x87\xe6YO\xef\x9f\x19\xfd\xbe0\\\xa1\xb8\n\xa7\x1drN(\xea:\x81\x19(\xb3\n\x1f\xf5p\xf9h9\xd7\xac&\x17\x8em\x98\xbc&{V\xef\xcc\x18\x18g\xfd\x91\x82&\xd7j\x8a,\xaa:\x9e\x17(\xb1\x02\x9b\xd3\xd4\xa8\xc2\xdeE\x18\xa5\x88\x95kl\"\x13\xf1\x9a\xec\x8f\xcf\x06\xbd\xec\xff\xad\x8a,\xd8\xaa\xe92\xaf\xec$v\xa0\xd8j\x9cN\xd4\xa8B\x0dK\xc4:\xe6\xc0\xb0\x17\x0b^\x9d\xe3\xe1\x991\xb4\xcez\x96B\x17_\"5\xc7,\xaa:\x9e\x17(\xb1\x02\x9b\xd3\xd4\xa8\xc2>\xb2Sg\xc5\x88e\xe9\xc8tz\x9c\"G\xfaY\xaf7<3\xc6\n\x8a\xcc\xd9*\xa9\xb2\xa8\xec\x14n\xa0\xd4J\x8cNS\xa7J\x05\x19WF\xae\xb1n\xf4\x00\xb7\xcc\xa6\x1cc\xa4\xe6\x96\x19W%e\x16u\x9d\xc0\x0c\x94Y\x85\xcfi\xaaT\xe1\x1f\xe6\xb1^\xc2H\xa6\xbb\x96m\x0fym\x9agc\xfd\xcc\x18\x0c\xdb\x95Y\xf2U\xd2gQ\xdbi\xfc@\xc1\x15Y\x9d\xa6U\x95*\x88\xb0\xbe>\x15:\x98\xd0\xa2\xa2y\xf6\x07\xce\x14\x8d{\xc0\xab\xa5\xc4\x95(i\xb9\xa8\xefd\x96\x07Hzun\xa7\xe9ZR\x0b!\xa0\xb3B>J\xb8\xa4\x9c\x1aY\xa7[\xfe\xa0\xa5^\x8aQk\xaef\xe1\xe14kD\xb3\xd6*\x9eh^\x90Eq\xd4\xd6b\x1eI\xe7{T:\xb5oU%\xd8{M\n\xd2\x1d\xb9.b\xbc*\xb5\xe7\xa7\xad\x82\xa8\x9a\x8bex\xdd,b\xe3\x1b\xd8\xf3N\xedy\x07{l\x1a\x8d<\x89N\xf1b\x16,\xc7\xaf\xfe\x8a\xfa\xd8\\8\xb7bbv\xf2\x99\xcf\x96\xf5X[C\\\x85\x89\xecb\xdf\xbe`5\xa8WeF\xb4\xa3\xceK\x11)l\xc1\xfe\x1e\xbb\xbdW\x08Q\xfa\xf8\x81\xc9\x90\x81\xbeI\xae\xbe\xb5r\xaf\x1aLJhh\x97\xa28\xb0\xb1\xe6\x86N\"\x87\xe6^\xfdGy\x13\x8a\xb5+\xbd\xcdX\xbb\xa8U\xa5\xb5\x8f7\xa8\xa4)\xdc\x11\x12ik\x84h\xb2ALf\x14h\xd3\xf3\xb6 :\xa6\x01\x020%\x7f\xc4fR\x9f\x9e\xb3\x15\xaa\x939\x0fC\x13\xa3\x1dr\xd6)\xaa\xe0\xf50\x98\xbb\x81\xfc\x9d^\x0ci\xa7;O\x03r\x1c$\xc7\xe5>7.\xcfCw\xaf\xe5;\xb0u,r\xd2\x98\xf7?s \x82\x97\x9ez\x86\\/=P'\x16\xf4V\xfab#\x83T\x9a\"M'A\x189i\xb5\x9bkB\xb3W\x8c\x92(\x0c\x12\x94h^\x100f\x96\"\xb9\xee\xc8\x95[\x82\x9eXN\xa3\xa7u\xc6\xaa\x96,\xec\xf8#I\xedt\x9d\x80{\x0fOeJ<\\\x07n\xe8\xac}\x140\xb9]\xe3\xd8d\xf6X\xcf\xfeH\xaa\xce\xcf>1\x9f\x0f\xcd\xcf\x93UY\xef\xbe\x8e\xfc\xc9\xf36\xb78o\xf5?\xd1Zb<\xfd\xe3\x8f\xc2g\\o\xd3\xf5\xed\xf8\xc1\x0d\xb7\x01\xec]2\xca\x18\x05.\x8a\x91;+9\x80\x9b\x7fE\xa0\x93\xbf\xb9\xcd\xa1\x8f\xc75C-\x10\x9a\x91\xa7\x1c\xa8d\x9e\xd1\xef\xf7\xd1q\x9a\xe1\xf6\x9dT\x1aW\xa9\x85\x9dEThY\xc5t\xa2\x038\xad|g\xc9\xedg\x90\xdc>\x1c%\xf0h<_\xe8\xfd\x89\xe2\xbd'\x15\x89\x9a\xd6\x14\xa9\xf3\xe7h\x13}\xd8qd\xcc\x0d\xddy\x82d\xec\xce\x95\n1'T\xba:N\xd3\x8b\xc5BxbN\xb8\xd3\xaaeSW\xf3\x1b\x0e\xed|\xe4+\x0e\xdd\x93G!\xa9\x0ej6gl\x9b\xfd\xfa\x96\xb7TP\x15F1w\xa6\x0b\xee\xfb\xcc\x95\xef<\xa2)69\xb3\x9f\xca=\xce\xecwx\xe7\x93{\x98C\xab\xe0c\xb5\x8fV(H\n\xf1\xb3\xa0\x83z@\xfd\xa24\x06\xd5/\x89ae;\xd6\x8er\xcd\x15'\x18\x1at\xf3\x96\x86\x16\xban\xb1\xdc\xcf\xba\xddAr.y\xe5-W\xc5{\xc0\x9d\xd0\x05\xd6~2\xf4\xdf\xbb\xbe\xe7\xc4a\xfe\x80|iN\xe9!\xbb\xeaHN_g\xce\xe8\x0c\xd8\x13\xd6Y\x1f\xc8\xdcQ+\xd7y\x89\xf8\xc4S\xee)\xe5\xca\x138tJZj\xe8\x8ezc\x138\xed@n2\xf2\xc6&\x0d\xf8\xd1K=\x8c\xbd\xb5\xdf\xf9\x82\xe6g\xc4\x84/\xe9\x97L\xc4P\xb6\xd9\xd4\xeb\xc5\xed\x90\xdb\xdb+r \xc4+\x88\x88eT\x8f\\\xf3\x9bE6\x83\xdaG \x8ej\x83\xa7\x95\x98s\x1a\x96\xe0P\x13\x07\x93\x8bX'n\x9e\xbe^8i\xa7XQ\xba\xbf+\x1dLzr\x13\xbe\xe7\x92\xa7\x1a-\xb5\xe2\xb8\xb5U,,N\x88D[\x94T/`\xeat\x93a\xd6\xcb\xcf\xe6T\xa0\xe0\x85\xb9\xd5l\xd2\xf8p\xe5\xb3\xe5\x89J\xe2x\x7fq\xd1\"\x9bW\x9a1\xc1x\x8e\xa37\x91\xed\xbc_'\xa9\xb7\xd8W\xe3L\x8d}\xaa7\xfei\xce\xd0\xa2\xf4\xfaQ\xdbH.\xa6,3uD\x8f\xd1\x81\x1e\x03'\xf2,\xfdEs\x18\xb5\xce\xd9\x95\x8c\xa5\xa7O\xf3\x13\xa6g\xc2\x13\xa8T\xb1\xc0\x1fO\xe8\x11\x12-\xcc\xd1\"\x8c\x91 aI\xb5\x93\x8e\x9a\x88Dm5\xdb\x11G\xc8\xb5\xbcG\x01\x07r\xeb \xec<\x0e\xd3\xfc\x87\x8e\x91t\xbc`\xe1\x05^\x8a:\xd94n\xc7g\xc4%\xcf\xc9\xf1\x14\xcd{\x12\xb8\x04x\xb1\xf7i\x9d\x15\xff/\x0e\xbe\xe6\xf3b\x1aF\xe5\x9e\x039;\x0c\xd8{\xb1y\xa6\xa9\xf6\xf3S.\xa0\xff\xfb\xbf*\xf2\x07\xb4_\xc4\xb6\x8f\x92N\xd5\xb0C\x1a\x02\xf7\xa0\xf3R\xf4\xa3\x91\xae\xe3\x80t\x1a\xea\xf9\xbf\xff\xfd_\xcf\xccO\x14\xec\xe7&\xa5N\x93W\xc3\x9c\x02I7\xfb%\x0eq\xa2\xd9\x8e\x83\xa2\xb4\xda\xac)\x87dj\xf3g\x19#\x14<\x85g~\xf5\x83\xe0ED,\xdd!\xf2!K\xcc\xb1\x17<\xa0\xf8`\xe9/\x9a\x17\x86P\xba\x15 H1\xcbc\xb5\x9d\x95y8\xba\xab\xda\xdd \xcc\x93 u\xb8\xe1\x05\xdc\x92\xb2\x06\x9d\x81O\xcf3\xa7\x83\xce\xfaU\xb7\xba\x8b\xea\xeb\xdf$\xc7\xcf6(N\xbc0\xd0\xa2\xd8^\xfa\xf6\x81\xdc\xaa\xa8\x83K\xe4\xb3\xe9?\x9a\xea\x8f?|\x94$\xf6\x12==\x82:u\xde#\xe5&\x06\xfcn\x0f\xf9@\xd8\xcc\\\xa0E>q\xd8\xb4\xcb\xc5\xf4\x82\xc6\xfe\xdd\xf56\xc4\x8bE-\xcbY)\x9dmTb\xde\xc9\x171Mt\\m\x97\xba(\xfbS\x8b\xdb\x8fv\x9d~\x11\xf6\xb2\x8bN\xba\x9ay\x1a\xb4\x9d\xb5&\xaf'\xf5\xc8\x83\x9a\xec\x19A\x93?6h&\xfcH\xbc\x8c\xed\xbd|\x05\x9as\x89\xec\x18\x05\xe9s_e8a\n\x9d\xa7A\xf6WK|\xd1\xc5\xad~\xa9\x19\x8e\xee\x9f\xae\x97\xd8s\x8c\xdc\x7fU\xef\x9b\x08\xc2\xcc\xe5p\xb8En=[uM\x8e\x90y?\x00s\xb9\xc9b\x9aer\xd7\x9fx\x04\xdf&\xc7\x0e\x1c\x84\xd9Sa\x8b\x81> \x97_e\x01i\x12\xb9\n\x0b\x0e|u\xf6:]\x85\xb1\xf7\x88\xe8\xeb\xd8\x13z\xb4\xab\xb8T\x07=\xe5\xa7?y\xe1$\xf5\x16\x89\x86\x05\x0e\xed4\xff\xb6\x0cm>p/\x9e\xa1\xdf,\x0f\x0b\x0fc\xf8\xc8e\x86-w\xaa\x80\xfe\xd9\x1f\x8fu\xd4\x03\x92[T9\xc7Q\xcb\xb8D\xa7\x0d\x9f\xe4\x8aZ\xc0\xb8\xe8\xff\xc7\x0fN4\x83r\x1f\xbcxU\x15\xd7\xb13\xadv\xb8\x03\xe2\x0c\x07l\x0b\x18\xe4\xa4\xf9_F\xdd\x95Y\xec\"\xf3\x98\xb5\x83\xb9\x18P\x0e\x0e\xca\xa2\xd3\\3\x0f\x95s\xce}\x98\xb8\xf7Y\xf6B~w\x8ef\xcc\xa8V\x06-\x0f\x80\x13}E\xcf\xfe\xb4\x89-\xbc\xf5\x0bO*\x05\xeb\xa1\x9e\xfd\xa1X\xcf\xd7i\x1a\x06\xec\xdb}\xc2u\x9a\x0d.\xbc\x02\x0bx\xd7\x0b66\xf6\xdc\x03\xbfVIV\xf6\x03\xeat\xfbI\xc7\x98\xc0O\xdb\x0e\x03\xffu\x81\xb83Fe\xd0{\xc4\xc4\x9b\xa7\x18\xac\xea\x1e:\x7f\xbc\xa7\xcc\xd9\xca\x13\xbb\x8ba\xf6\xa7\xb3\x8e\xf1\x8f\xae\x9d\xda\xe7\x9eo/\xd1\xcbd\xb3\xfcy\xe7\xe3\xc9\xdcN\xd0\xa0\x7f\xf6\xdb\xaf7\xbdo\xfb\x8b\xfe\xfc\xcbn\xed<\xea\x9e\xfd\xeb\x9d\xee\\\x86\x9bw\xa6k\xba{\xcb\x9c\xed\xad\x8d\xe3;\x9b\xd9\xfdt;{5~t}\xc7\xbb\xfe\xf5[\xf4\xedw\xf7\xd5\xdc\\\x8e\xaf\xef\xa7\xcb\xd9\xab\xe9\xbe\xf8{\xfd\xf3\xf5\xab\xe9\xf2\xfar\xb7\xfd\xfa\xfb]x\xfd\xe6v|\xfd\xa0\xeff\xfb\xbe>\xfb\xb8\\\xde\xec\xfb\xfd\x9b\x8f\xf8\xfe\xdd\xfd\xb59\xfb\xa0\xafg\xf7_\xfb\xef\xee\x9d\xed\xfb\xfa\xe7\x07\xf3\xfd\xab\xe9\xf6\xfaU\x7f\x7f\xb3\xef\xefo\xee\x97\xeb\xd9\xbd\xb3\xcf0\xb3\x0f\xf9s\xeb\xe6\x1e'\xef>\xce\xd6\xef?N\xfb\xd7\x97\xb3\xf5\xfb\xcb\x9b\xfbw\x1fj|\x9aa\x9b\x9f\x1f\xcc\xf7\x1f\xa6\xdb\xf9+\xfd\xf1\xdd\xfd\xc3\xf6}\xfe\xdf\xe5\xe3\xd7}V\x9f\x93\xbe\xbb\xbf\xee\xdd\xd4?\x17u\xbc\xfb\x90\xd5\xf1\x90=\xdb\xe5|\xef\x97\xeb\x9b\xc7\xa9U\xfd\xfc\xfe\xa3\xd3\xbf\xbe\xbc\x98\xcd>N\x97\xb3\x8f\xaf\x93\xb2m\xe9l\xdf\xdf\xdd\\\xbe\x1e\\{\xa3\x9f\x7f+\xf4\xf4\xf3O\x9d<\xaf[\x9c\xfc*b\xceN\x10j1\x8a\x90\x9d\x92\xf3ZqS\x9f{#\x84<\xa3\xd9SK|f0\x95(\xa8Y\xb9G\x11\xb2\xe3,Z(F\xa4\xfcEm\xecC\xe6w\xc0\xdd\xff\xe9\xafq\xeaE\x18\xfd\xabJ\xfeZ\xd4\xc15\x0b\xf4V\x80\xd1\x9f\xde]\xe9\xbd\x07.\x89\xd8\xcbg\xd8\xa3\xee\x94 8\x19#\x9d\xbd\xe0\xa5\x94\xdd}\xea\x99\xa4\xfch\xe1?\xb3%\xf5/\xc8\xb7=\xfc\xaf3A\xe9\xc2\xc3HX\x18\xd9I\xb2\x0dcW\x08H\x90\x1d;+aq\xb6\x1e\xa3\x0b\xb3'v\x8clRE:\x91l\xa2\x1dh\xc4\x0c\x8f\xc4\x86\xa1;\xce\xfe\xb4\x0d\x8f\x8b\x85\x9a\x15\xff\xf3\xd5\xd5\xbct&\xdf\x8a\x91\x1b\xbb\xeaO\xd2V\xb4\x81\xea\xd6\xb4\x01\xcbV\xb5\xc1\xf2\xd6\x81\xa0\xaa\x95\x7f\xca0\x00d\x8ar6\x07C\x7fq6\xd6_\x00Y\xb6:\xa5k\xba?jF\xb4\xcbF]0\xe5K\x96\xff\xbb\xa7\xbf8\x1b\xb5\xf2\xeb\xc9\xd9U\xc5\xff6\xf5\x17g\x96\xfe\xe2l\xd8\xcaQ\xeb\xb7HX\x95\xff\xbb\xaf\xbf8\x1b\xb4\xf2kaWs#3k\xff\xab\xd1g\xd1(8\x1403\x07y|\xbc\xd9\x9a\xeaQ\xb7\xe8\xf9\xd5\x137l\x92\x01u\xcb\xbb(\x8e:-\x00\xccMUK\x8aw|\x1d\xf8\xd0\x17\xb8\x1fU\x0f\x11\xce:\xe6\x0f%\x13[r\xe4d\xc2\x9c\xd5\x88QN\"P\xc0\xb3\x9f\xd9rV\xc8y\x98\x87\xbb\x03\x19\xf5\x97+Y`mD\xeez\x08\x1eW*\xd5\xb3?peOx\xfd\x86\x80aD\x1dD\xef\xeb:\xf1\xd1\x8d\xc2\x0e\xe4y\xb9J\xf3,HU\x8bP\xba\xae\x16\x85\x98L\xaag\xff\xaa\x9b\xca/\xa5\xa5t?\xe7\x8a\xfa{\xb7xC\x8f\xf0\x8dJt.K#\xf7\xcb\xf27/Tn7 \xcf\x91\x8f\xca\xedn2\x0ef\xcf|\xd0[Q\x8c\xff\xa1Q\xf6G\xf4\xb2$=_\x02T i!\x97\x08\"\xde\xf1\x90\xf7\x83\xfa\xa7\x13U\xd7\xfe\xca_\x85WFKk;\xcf\x7fB.e0^Y\xf9\x1a\xf8/\xc0\"\xd8Y\xd9q\x82\xd2_\xd6\xe9B\x1b\x9d\xbd0_%\x9be'\xb7\xe0/?\x18\xfa\x0f\x9d\xc2\x82\xbf\xfc0\xfa\xa1\xb3\xf1\xd0\xf6\"\xdc\xfd\xf2\x83\xd9\x19v\x0c\xbd3\xfa\xa1\xb3\xf3q\x90\xfc\xf2\xc3*M\xa3\xf3\x97/\xb7\xdbmwkv\xc3x\xf9\xb2\xa7\xebzV\xc7\x0f/\xcc\xab\x17\xe6\xab\xc8NW\x9d\x85\x87\xf1/?\xbc\xe8\x99}\xa3?\xec_\xfd\x90?\xd0\xe25F\xbf\xfc\x806(\x08]\xf7\x87\x8e\xfb\xcb\x0f\xb3A\xd74\xcd\x8ea\xbd3;\x86\xd1\x1d\x0c\x86\xd8\xc8\x9eh\xd9\xbf\xfdN\xaf\xd3{W<\xce\xc40;\xa3\xac\xec\xf1\x87\x97EMY\xa5/\xcc\xab\xbf\xfc\xd4\xb1\xf4\x17\xcdZ\x93\xd6\xa8\xeb\xd98\\j\xeb\x1d\xf35\x9d \xf9\xa2U\xea\x1e\x8b^\x1dV\xaa^\x03,`\xd8\xe9f\xbaw\xe30\x02\xb8K\x19\x8an\xc1\x8c~\x12V\xe5\x87\xae\x8d\xa9z\xea-m\xae!\xd4\xfe63)\x16\xbf\x9a\xe5\xdcP\x7f\xf3\xc3\xe2\x86\xe2\x937\xf8\xf9\x05JuY\xafm\x81\"\xc8\x07\xe8\xd1\xaeS\x9c\x9c\x92\xbe\x04Z\x8ckUj\xb5\xb1&;\x06g\xf5\xc90\x82O*J\xd8\xd2\x17U\x80{6U\x9e\x9c\x9fk\x95V\xb8\xd2\xba\xe9K>#f\x81=h\x16\xd8O8\x9a\x04\xd5\xff\x94\xd7\xce\xd5\xb1J\xaf8/':*[:\x16\xe96'\x9d\xffQmM\xa7\xeb\xe00AZ\xfe\xf8\x88\x94\xfc\xf3e\x9bd\xc2\xad\xc8\x0f\x83\xf7\xd8c?\x03\xf2\x0d^\x8d\xe8\\\x1eN\xb4Ir\x82[\xf8\xa1+O\xef\x98\xfa\x91g\xea\x85\xb5t\xba\xc4}\xd9$\xb2\x99\x1b\x11<&u\xabc\xb9\xb6\x9e\xfd\x11\x9d\xcc\xe5(\xff\x9e\xba\xcc\x8dK\xf5w\x0f\xe5\xcc\xb44\\.1b\x8fh\xc1\x81\xd7@\x14x\x95\xa6\xccF\xa9N\xd7D\xbe\xc2\xebo\xb8\xe1]\xf8*`u\xe4\xa9\x08\xe8C\x0e$\x03~**\xcf\xf1\x8cu\x17-\x81\xf3=\xe5s\x8eN\x0bc/\xcf\xa6\xe9/\xb2(a\"*\x10\x1b\xaa\xeb\x84\x18\xdbQ\x82\\\xf1\xa9#\x81P\xf9c1\xe7\xf2\xac\x1et\x02\x8d\xdd\xc0\x12\\\xa1=*\xd2k\x0f\xe0\xaa`\xb0\xd7o\x82\xc1\xec\xe7:\x1a\xcc\x83\xea~\xa7\xd7'c\xbd,\x8c3\xf4\xce\xe0\xdd\xa8k\x8d;\xc3n\xdf\xe8\x18f\xd7\x18v\x8c\x1e\xd6\xfa]k\xd4\xe9w\xad\xf1;C\xef\x18#<\xd0\x06m\xf1\x1b\xb7W\x90\x05/\x90\x16\xef\xd7~\xa4\xa5a\xfe60`\xe1\";\x01\xc43\x10\xbfz\x8a:;\xa8u\xfb\\g\x03-\\\xdc\x87\x97\x1f\xe3$\xa0\xd5\xbb\xa5\x8aG+/H\x0f\xc4!\xbb\xfcG\xf6cc\x04T \xab\xd1\x1d!\x7f\xc2\x9f\xe3\xab\x86\xff\xae\x81\xfcN~\x14\x08\xf8\x1eo9<\xaa\x04od\xb85\x84\x1c\x9e\xb8D\x95\xad\xfb\x99\xc3F\xe5\xc9\xb2\x02\x9a\xd4W0ub\xf2\x97\xbdR\x9a\x97M\xc2\xbdz\xc1)1{\xeb\xfc\x0b\x0f`\x9a,\x96b\"7Qh\"\x7f\xef5\xcd\x9e \xd1\x9e\xe5-\x86'\x85Ap\xb2\xe8Y\xdf\x13.\x0f\"\x06:w\xbc\x86S\xd5\x13_\xa3\x0d\xf0;\xe9\xcd\xde\x1c\x9f\xe3\xde_\xce\x92[\xac\x07\x90\xddEo\xdd\xf6\x02\x0e\x0b05\xa8\x0d\x99\xf9\xeaQ\xda\x17*F\xc0e\x97\xfa\x82\xc3Q\x1f\x1c\x02\xde\xc6\xa7>\xd8\xb0\xdf\xeej\x91\xb5\xc5F\xc3\xe3\x98\xd1Q \xf1\xda\x90\xa3\xb8\xe4\xa7\x83\x18&\xad#\x12\xc7\xa6|\x90\x08\x0cLM\x0b\xa3\xfa\nVf\xab\xe6\x15;\x96B\x85\xf3pw\x90\x1e\xdai`T\xc2\x19\x8ca\x95\xcd\xcc\xbe\xcc\xa7\xae\xe4\x08\xb7\xe6Ni\xd5L\xba\xd0\x0b\x87,\xf1\xa4\xce\xf4Ty\xcf\xb4\xf4\xec\x0f\xc4\xac\xa9U\xdb\xdaq\xe0\x05K\x903\xb7|\xab^\xdcR\xddn\x17\x1fV\xe4_Q\x97\x8du\x7f\xcf\xfe)\xa7\xe5\xee<\xb6\x1d\xa4\xe5\xabZjF\x84\xceBEq\x18i\x81\xed\xb3\x87\xb8\xa9\x15I#\x1d@\x9c\xfbx\xa5\x18\xcb\x06\x10(X\xfb\xb2\x0b\x8f9(\x0b\xb1\xed\xf4 \x9e4\xba \x8a7(\x16\\\x1f{\xb6\x0bYd%\xa2\xebW\xf47f@\x06\x9dU\xbf[\x9d%\xaf\xee\x1e\x94\x01E\x8fUcE\x92\xdas\x8c:i\xf55\x16So\x01\xba\"\x9b\xd5\xd2eQ \xf8\x85\xdb u\x1f\x82H\x82i\xc4\x9dNy\xe5\xf0\xeb\xfaKWik\xa3\xdb\xe1^\x0eE\x1c|\x87I\xbbN\xe8G\xeb\xack\xadc\\\x0f\xcd\xfc\x91~\x10_\x1cC\x07\xf5E\x9c\xaa\x9d\x88&l\xce\xf5\x978\x9c\xdbX+\xea\xfa\x8f\xbe%*\x90\xb4\xd6S9\x00\x92g\x9c{\xd50$~=S\xf5\xaa/\xc0\xdd\xcb1C\xe0\xed\xb9\x03@/\xc3\xa12nZ\xb5>?\xaf~\xe0\x99\x94\xc3]\x9a\x9fLJ\xe3\xac?\xd4\xbcX\xafg?\xd6,`\xc0\xf8tu\"\xa5O\xbe\xe2\xab\xd8\x84\x82ZU\xde\xefN2IZ\x12dp\xa7|j\xda\xac\xec\\\x80B\xaa7\xb7)\xe9E\xa2\x91fl\xe9Q{\x0f\x03\xe2\xe6 \xf0V\x9f\x92m\xfe\xea\xc6\x9c\xed\x99\xact\xd5vz\x8cI%\x13\xd7b\xf2c\xf2\x8a\xeb\xb7\x9e\xda\xa9Bf\xae\xaa\xbe\x8c\x93\xb0/\x93\xe0\xce\x02\xc1\x1f\xd52\xf9\x17>Ix\xd2\x97\xcdJ\x86B\xfa?\xfe\xc8grI\xc4\xd1\xd7O\x99\x14\x99\n\xba1\xfa\xef\xb5\x17W\xaf\xc7\x11\x0d\x12\"*\xf86+\x1c\xe0i\x03\xfasCM\xca\xac\xe2\xf6\x97R\xf0\xf2e\xd0V1\n\x0e\xd8o\xae6\xb2\xa0]\x8a\x82\xc4\x0b\x99l2\x81\xf0\x14^\x9csLW\xe5?\xccBT&|m\xfe\x13+\x8d\x91+V\x81\x1f\xa5\xfb?66^\xa3?\xf8\xc4\xb5ID\x03\xe5\xda\x91\x8b\x0e\xb8\x17\x0cJ\xb9\x97\x93=\x15L\x0e\x8f\xe2\xd0\xad\xee%5\xc1<\xffjH\x8c\x80\xab\xee\xfc\xa6^\x1aFs\x9b\xfeb\x0dpE\xa7|s\x0eDZ\xfd\x17~\xcd`\x89\xb1O\xdb%{r\xbe\x07\x14\x98:U\x95\xe7\x06\xd9!U%WB\x8eb\xf9^3\xbbIR\x1c\xb9\x90\xaf_\xd8cD\x95\x84E\xca\x06\xd8\xcc\xe2#\xd1\xca\n\xf5+J\xd61\xae_\xd3\xf7d\xad\xe7m5\x9b\xd6\x9b\x93\xea \x01\xca/r\xa2\xc0e\xaevfO\xd8{\x9dy)\n\\\xf56\xb4\xcc$\xa5\x86\xf8seV\x7f\xb8\x80\xbeJV]h\x12\xdf*\x91\x8b\xd3-f!\xed\xf4\xb3WOw\xeb 8\x99\x0e\xa8\xe3p\xa76\xa9\xbcgG\xcf\x9aJ\x1d\x82\xf6\xd2<\xc0\x92\xbf\x19\xf2\x18\xa1\x8a\xa9\x9f\x93\xa3\xd7\xc8\xd1\x9b\x94\xff!\x94#t\x0b\xea\x04$\xb0\xee(\xcf\x0dR\xbf\x1f#<\xf5\xb4\xbc\xd5$\x89D\xc88\xae_\x1e\xf2\x90\x9c\xe1$\xae\xd5Q\x8b\xa8\xb2qG\x0e:^\xb0\x08\xeb;\x1d\xc0K(\xb3\xf2\xce*\xbf\xee\xd7\xf5m/`\x97urt\x87=\xc4\n\xc0\xb1w\xc6?\x8c\x80g\xc5z\x89\xe0w\xda+\x0f\x0b\x19\x0d\xa0\x02\xf6\xf3\xc8\xc5C\x13z\xd8\x87\x1eZ\xc7\xbf9\xa0\xa0,\xdenU\xad\x8f\x8b\xdbb\xea\xe9C\xdd:\xf2\xa4.\xf4\xee\xf7\\\x0e\x9b\xd5\xeeQ\x1b\x11-\xb6\x80\xae\xc9\x16\xb5\xd2\xef\xbc3\x16\x83\xb1\x03xay7\x9f\xdc\x9f\x02\x98u\xe7v\x824\xe0\xe80\xa9\x0b\x93:\xdbZ\xcf#G)Qh\xcc.\x9bF5\x07O{w/\xc1\x95\xff2\xaad\xc1`\xb5\x1c\xae(\xd6\xef\xe4\xcb\x9d{\xc5\xc0\xc2.\x8d\x93u\xc4\x1dd\xb5\x86\xcc\x01\xb7\xa1;\xea\x8f!\xf3\x92\x92\xe7\xaf\xdbST\x057T\xd9\xebt\xa5\xcd\xd3\xe0i\x01\x0e\xbd6\x7f\x8e\x17U\xc8\xa5,\xeeK\xbba\x80\x0e\xf2\x14rN\xf8\xa4\xa6)M\xd4\xcf\x1a\xbb\x912w\x88\xd7\x040)\xd0&4\xd1\x9a\x97\xe3\x01\x9c\xc0\xe4\xa1\xc1\xdeo(\xd2\x89-\xa7\xe6d\xdc\xe1M)a\x1dl8E3#v\xcd\xcbc\xffV\xb4\x13\x1d\xb7bH\xeb\x8f\x8e\xf3\xc1\xbe\x94\xae\xf5&\x9a\x84\xa0\x08\xa3\xd9\x1b\x90R)Q\x1c\x87q\xc2\x0e\xa8\xd4\x06\x18?Y=y0M\x9c0BIg\xd5{\xfa\x94\x9f\xb3\xd2\\\xb4\x90\x1f\x8b(\x1b\xaa1V\xe9\xc1\x0eXu$\xe2\x92\x9acc\xf4)b^\x80E>\xe5C\xd2\xea\xfaZ\xebd/\xf9&\x15-v\xf9;\xdb\nx\xd3\x0b$e\x8fl\x08\xdf=\x7f\x92]\x05U&\xc4\x8b\x9f\xc0M/\x86\xae\x882\x9f>P\x9e\xb4\x06S\x90\x8c\xd6a\x8f\xba\xac\xa44P+\xb99t\xc7\xb1\xf0\xb7\x03x9\xad\xbc\x971\x02\xeej\x8c~\x9a4\xaf\xc6\x02\xdfAV\x00\x0d\x9e\xd6hH\x0d\xfav\xe0\xff\xb4,\x94\x9d\xee\xf2kaq\xb7\no\x9aTZ\xe5\x1d\xf9J\xef\xff\xbc\xfc\xdb_;I\xb8\x8e\x1d4\xb3\xa3\xc8\x0b\x96\x9f\xee\xde\xfd\xd20\xea:I\xd2\xf5\xed\xe8o/\xff\x7f\x01\x00\x00\xff\xffPK\x07\x08_;\x94/\xe8Y\x00\x00\xa8X\x02\x00PK\x03\x04\x14\x00\x08\x00\x08\x00\x00\x00!(\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0c\x00 \x00swagger.yamlUT\x05\x00\x01\x80Cm8\xec\xfd\xfb{\xdb\xb6\x928\x8c\xff\x9e\xbfb\xd6\x9f\xefs\xec\x9c:\xf2%\xceu7\xfb]\xe7\xd6\xa6M\x1a\x9f\xc4\xe9\xd9\xdd\xf3\xf6#C$$\xa1\xa6\x00\x86\x00m+}\xfb\xbf\xbf\x0f\x00\x92\"%\xe2F\xc9\x8e\xd3rv\x9f\x934\"\x80\xc1`07\x0c\x06\xfc\x12M&8{\n\xdb\x87\x83\xfd\xed;\x84\x8e\xd9\xd3;\x00\x82\x88\x04?\x85\xb7\xcf\xdf\xc1\xc7\x97?\xc1=x\x8b'(\x9a\xc3\x87W\x1fO\x01\xd1\x18&\x1fN^\xc0\xf7H\xe0K4\x87\x98E\xfc\x0e@\x8cy\x94\x91T\x10F\x9f\xc2\xf6\xb1\xfe\x98P\x81\xb31\x8a0\x8cY\x06\\ \x81\xe1s\x8e3\x82\xf9.$\xbaW\x91!\xcaQ$\x1b\xf2\xed;\x00\x178\xe3\xaa\x93\x83\xc1\xfe`\xffN\x8a\xc4\x94K\xac\xf6(\x8b\xf1\xb0\xc4\x11`\x82\x85\xfe\xcb\xd2\xd8o\xe8\x98e3$\xff\x03\xd0\x88\xe5\x02\xc4\x14C\xc4(\xc5\x91\xc01\xc8n\x8av<\x9f\xcdP6\x7f\n\xa7S\x0ci\xc6R\x9c \x829\xb0\xb1\xb9\x8d@\x13^\x8e\x0bp\x0f\xbeG\x04\xa9\xc9\x16\xff\x96f,\xce#\xdc\xf8\x06\xa5iB\"\x85\xd2\xdeo\x9c\xd1\xe2\xa7\x0c\xf3\x94Q^\xffv\xfbp\x7f\x7f{\xf1\x9fKS\xfb\x99\xc5XQ1\xe7\xb5Ox4\xc53To\x04 \xe6)~\nl\xf4\x1b\x8eD\xe3\x87\xc5,\x9b\x0d\xa0\x8e\xe4\xb0\\\x83\xa5Ol\xcd%\x8cr\x92\xc4\xc3&\x85\xea\xa0\xb1\xe2\"#t\xd2\xf2A\x94\x10L\xc5\x90\xa2\x19\xee\xd6\x9e\xcdfDtj:a\x9d\x9auF\x95\xe3\xec\x02g\xdd\xa7j\\ G\xdb\xa5=T\x07\xfb\xd2\x928x, 3F\xc99\xce:\xb5\x05\xc0Wh\x96JQt\x81\x12\x12#\xc1\xb2{\x92b-\xdf\xa6\x19\x13,b\x89\x99s\xc19E\xf5\xc5aj\xfa\xc9\x03_\xa8\xe3\xfc\xc8\xf0\xc9(a\xd1\xf9\xa6\x069\xd87|\x83\xd2\x8dM\xa4m\x08\x8a\xc5%\xcb\x0c\xd3pv_u=A\x04\xdd;l\xdb\xcaSD)N\xba\xc9\x91\x84p\x81\xe9\x10\xc5\xf1\xda\x8c\xb7}\xf0\xe4pp\xf0\xf0\xf1\xe0\xc1\xc3\xc1\xc1\xd3\xc3\x87\x0f\x1f<\xdc\x0e\xdd\x8e\x0d\x11~\x8ai\x8c\xb3\x19\xa1\xa2l\xb4&\x86\xfb\x83\x83\x07\x83\xb6%bbj\xdax\x0d\x8cf,\xc3@jJ\x93\xd1\x125n\xc1\xadE\xb7\x94\xe0\xdef\xe2jHh\x8c\xaf6\xc5\xa2\xdb\x8c\xb6-\x8b\x84,\x8d\x14'`n\xc4&x4\x11\xa5O\xf7\xf6\xf6\x07\xea\xff\x14W\x95\xf7\xc9o\x13V\x14_\x89\xe1\xedD-\x92\xf6\x05\xe5\xf9\xadB\n\xa5\xe9mBG\xed\xbd\x0c\xf3<\x11\xb7\x8aL\xf8\x82\xc4\x98F\xf86\xe1$u\n\xe38\xdb\x90#\xd7\xb0nG8\x9a\xde?\x04L#\x16\xe3\x18\x8a\x11\xdcS\xd2\xd6\xdaA\x8c\xd3\xf3\x07GQ\x8e~\x9b\x9c\x7f\xc1\xe8\xe1\x97tr\xfe\xf9\xfeCA\x7f\xbb\x8c\xbf\\\x1c\xa1qt?>4\x85\x82\xaca\x03\xf0\xd5\xba~\x1a\xd7\x11v\x02_\xe2\x81W\xf8 \\!(\xe84^\xdbpv\x03\xceIA7\xf5n\xd3F\xb0\x1bj\xce\xc9\x82\xd7\x84\xc1\xcf8\xf32B\xc0\xb5|%\xb8\x0d2/J\xc3\x06\xa8m\xd8*\xbd'\xba\x80\xde\x13- l\xa2\xbd'\xda{\xa2\xcb\xe0^ \x08Y\x0d\xd8\xe0\x8a\xf4\x9eh\xef\x89z`\xd5{\xa2aH\xf5\x9e\xa8\x17^\xbd'\xda{\xa2.mw\xab\xff\xc7\xb3g\xd5\xc0\xddr\xed\xb6\xcbd\xbb\xdf\xb5:\xf8\xa3\xe8\xc2\x94o\x87\xb4\xd0\x00$\xff\x1a\xe1L B\x0bMR|\xbe\xe9\xd4\xbb\x14eh\x86\x05\xce\x1a\x1f\x13\xfa\x14R$\xa6\xb5\xf9\xaa{\x01M\\`\x99\x0c\xcf\x15\xf2+\xdfd\xf8sN2\x1c?\x05\x91\xe5\xf5Ty\xc3&\xba\xba\xb7\x12\x86\xef\x94!X\xa3%OqD\xc6$ZE\xae\xcf\x17\xf4\xf0e|C\x19\xfd)M \xfd)\x8d[\xc4oR\x05y\x18\x11^D\x00oB\x80\xbf\xc9\xe0\xb5\xd6%8\xd7\xbc\x04\xf7J@\xc8j\xc0\x06W\xa4?\xa5\xe9Oi<\xb0\xeaOi\xc2\x90\xeaOi\xbc\xf0\xeaOi\xfaS\x1a\x97\xb6\xbbU\xa74}\xbe`\x05\xce\xc9\x82\xd7\x84\xc1\xcf8\xf32B\xc0\xb5|%\xb8\x0d2/J\xc3\x06\xa8\xdd\xe7\x0b\xf6\x9eh\x01\xbd'z\xfd\xdb\xad\x0e\xbd'j\x00\xef\xd5\x80\x0d\xaeH\xef\x89\xf6\x9e\xa8\x07V\xbd'\x1a\x86T\xef\x89z\xe1\xd5{\xa2\xbd'\xea\xd2v\xb7\xca\x13\xed\xf3\x05\xdb\xda\xaf\xe5\xd9\xf46qo\x13\x1b\xc1{5`\x83+\xd2\xe7\x0b.C\x9f/\xf85\x06\xee\xf3\x05\x1b\xe0V\x14\x1a:\xf8\x12\xfd\x16\xe78\xfd\xbc\x7f\x91\x1f~\x99\x9cO\xce\x8f\x9e\xe01\xda\xa7\x9f/\xbf\xd0\x18\xd1\xcf\x0ffG\xd1\xa3\x14\xdd\xcf\x8fP\xfa\xe5hr\x98=\x99\xf0\xf4\xf3\xe4\xe1\xe4I\xc4\xef\x9f?\x89\xf2q\xebX\x17L\x10:\x19\xa6\xec\xd2t0\x176\xa5\xed\x83}\x93eT\x05\x8d\xd2\x8c\xb0\x8c\x88\x8d\x90pi\xbcn\xa2k{IvygZ/ \x87>\xddz\xddt\xeb\x15i[K\xbb\xee\xa5\xad\x82^\xda\xd6\xc0c6\xbd\xb4\xbd>i\xbby\x03\xf5yy\xdf\xa2\xb0M)\x13\x80.\x10I\xd0(Y\xc8\xa1\xaeb^\\I\xe1\x8e\xf8\xb4E\xb4\xc78\xcdp\x84\xc4\x92\xd0[\x92\xf8\xa7W0\x9a+?\xa9\xf8}E\xba\xd7\xde}\xb9\xd3\x82\xdc\x07,2\x82/0\xa0\xfa\x131\x90sB'@\x04W}\x0f\x8a\x96\xd7\xa8\x15\x163XA\xf1\xf4j\xf9g\x87:Xa\x9e\x9a:x\xfe\xe2\xf9\xab\xc3\xfdW\x8f_\x1e=|\xf4\xe0\xf1\xf3'\x0f\x8f_=x\xfc\xf8\xfe\xf3GO\x0e\x1f?x|\xf8\xe4\xe1\xf1\x8b\xfd\x87\xaf\x1e\x1c\x1c\xdd\x7fp\xf4d\xff\xf5\xf3\x97/\x8e_\x1d>8~t\xf8\xfc\xfe\x8b\x17\x8f\x1e>\xbfSb\x10\xaaM\xaet\x89w\xa1\xdf\xc0\xb9 Rz-MkC\xaa\xa3\xddk\xb6\xee+\xbbPz\xb9\xff\xf8\xc1\xc1\xfd\xc7/\x9f\x1c\xdc\x7f\xf2\xe4\xfe\x93\x83'\x87O\x1e\xbc~}\xf4|\xff\xf8\xc9\xc1\xfe\xa3\xd7\x07\xaf\x0f_\xbc|\xb5\xff\xf2\xfe\xa3\xe3\xc7\x8f^\xbc\xda\x7fxt\xf4\xea\xf0\xe0\xd1\x8b\xe7\xaf\xef??z\xf2\xf0\xc1\xc3e\xfc\xacJ\xcd\x10O\xa80\xbc\xff\xf0\xf1\xd2\x8f\xa2%\xb8iUZv\x955\xe3-\xd5\xea\xc1\xa1=\xc1\x15;v\x88\xb51\xb6\x1e\x15\xaduZ3A\xce\xa0\xb8U\xdc\xa2\x19\xcb\xa93\xab\xecv\xc5\xd5cL\xd9\xcc\xfe\x89\xd7\xdcK\xa8\xd8\x8f\x0bt\xde\xf64\xce\x02\\\xe4\xd2\xd0e\xec\xed\x07\xad\xcau\x86g\xdd\xdeUrD\xac\x9cK\xe2^\x0c\x8f\x98\x98\x17!|\x8c&\x80w\xaf>\xbdx\xf3\x8f\x97\xfb\x87c\xfe\xf2$C\x8f\xdf\x89\xd1\x07>\x7f~p\xf9h\xf4\xf9\xf4\xdd\x83\x07\xff\xcc\x0f\xee?\xfe\xf2\x8f\xd1\xeb\xe8\x9fWG\xdf\xbdx=?~3\xc1\x0f\xfe\xf9\xf3\xc9\xf8\xa77\xf9\xc5\x97\xe7\xff\xfb\xf0\xc9\xbb\xf9\xe7\x1f\xf8\xe7\x97\x8f?\x1e\xbc\xb9$\xaf\xd2\xef\xc8\xa7\xd1\xc3_>\xc6\"I'\xff\xf3\xcc0\xb4\xc3&\xf4 $x\x11\x13\xca\xae\xac\xfc\xe2EO\xa8\xd3\x94q\x91\xa1\x88\xd1\xbd\x93|\xf4\x13\x9e\x7f\xc4Qz\xf8\xe0\xe1\xb9)\xfd\x13\xb4\x93\x91o\x1c\x8f\xe3\x8b/\xfbG\xbfL\xc5O?N\x1f\x1f\xbfx\xf1\xcb\x97\xe4\xcdct\xca\xf8\xf7\xf3}r\xfe\xfa\xbf\x7fz\xf3\xcb\x0f\xff\xb8\xff\xdbO\xef2\xc6\x7f0\x89\xaa(\x92\x9bo\xa8\x95\x88kE|\x99\xce|\xe8\xc3\xf1\xe7\xdc|\xcc\x0f\x1b\x18Ig\x00mT\xc1%\xcc\xaa\xe0\x8c\xb8N\x10\x1f^\"*-\xd2.\xcd\x9b\x07Y\xfb\x06OA\x0e\x92\xf3M\x0c\xf1\xf0\xfe\x83\xa3\xb6\x11\\\x0f\xe7\xad\xa5\xe0\xad\x9b\xdcg\x8b[\x05\x89\x07\x01\xc0gw\xb6\xf6bwb\xde\x94\xdeK\xe1\xcd\xbc*\xc3\xecUz\x8d\xdbw\xf1\xf0M\x16/0a\x94E\xd3\xc6\xb3\x95wZ\xd0j\xf9L:D\xf8\x02S\xc17\xea\xb6\xa8\x87\xa4j\xd4\xd1~\xcb\x0cs\x8e&x\xa0\xc7\xae\xfdlX\xa8\x06\xf2K\xca\xac\xee\x7f\xe9 \x00\xcf\xa3) \x0e\xdb\xcdq\x9eqL\xe3m\xb8\x9c\x92hZH\x08\x0e\xa4\xf9\xc6\x99t4\xc6,I\xd8\xa5\xf4\xe40\x8dSF\xa8x\n\xdb\xdf\xbf:U\xab\xf6\xffo\xebs =\\\x0cb\x8a\x9aL\x8cQ4\x85\x19\x8b\xf3\x04C\xcc\xa2|\xa6\xd0\x93\xfe!\xbb,\xb1\x1d@\xc2\xd8\xb9z\x83\xf4\xeajX\xfc\xdb,\x06B%2\x8d\xee\"\x96i\x0f*\x96\xc8\xe9p\xc7=\x1e\x9f\xef\xc5,\xe2{<\xc5\x11\xc4$\xc3\x91`\x0d\x9a\xd7\xfc8\x89m\xd0\nq\x15\xe6\xdc\xdc\nIf\xd6.\x9d\xeeYS\xb6\xf1\xb9\x89\xca\x7fk\xe2\xf4\xacH\x15t\x85\xa5\xf6\x1f\xa6WW\x17\xdb\xed\xf4\x08\xea\xc3\x8bp)\x9a`\x13]N\xd0\x04\xafzj\x9a\xa2\x84\n\xcf\x18\x8a#\xc4U\xca\x1a\x99P\x1c\x83\xb8\xba\xd32t\xeb\x87 \x18 \x18\xe7IR\x7f\xf9>b\x94\xe73\xbf8\xea&B\xae#\x16\xb7\xc54*\x8cM\xd4\\R\xed\xa7S,\xa74\xcb\xb9\x80\x11^L\xf3\xa3\x88O\xaf\x06\xeag\x9e\xa7)\xcb\x04\x8eaT\x91c\xc6b\xcc\x81\xd0(\xc9\xe3\xa6\xa5w\xb6\xa5\x82![g;\x19\x16yF\x01\x8d\x05\xce\xe4\x18\xfa\x0e\xda\xdd]8\xdb\xe2s\x1a\xd5\xbf\xc0\x19\xbc\x98\xe2\xe8\xfc\xf4\xea.\xa0Z\xecRw\x88\x9a\x9fg*\xbe\x82.\xd1\xfc\xee\xa0\xf6\xa51\xefeS\x91\x8e>\x93\xa2\xcf\xa4X\x02/o\xcac\xee%\x04xP.ri\xe82v\x9fI\xd1gR8=\x1c/z\xc2\x9a^\x8d\x87=\x12\x8e\xc7\x06|\x18_\xef\xc5\x0b9\xa7\xd7\xe0\xe3\xab\xac;\x92\xd4\xe7&\xf5f\xe8\xb5\xeaM\xe9\xfb\xe2\xe7\xe0S\x8b\xd3\xab\x85UA\xe8\xa4p\x91j_oH{G\xd2\xbc\x18nX\x87G\xadT\x83\xaa\xd3\xd5S\xa4\x12b\xd4V8\x1e\\4w\xb9H\xaea]~\x9d\xab=\xa1\xe3n:\xa0kZM\x9f\x8f\xe2\xb7 M\xcc\xd9z\x97X1\x9f\xfa_\xc3J\xc9\xff\xb1\xf1\x1e4\xd5\x87\xa6\xdcL\xf75BS\xe1\xa1$\xad\x80/\x91\xba\x1a\x10a\xce\xc7y\x92\xcc!\xc6E9\x04\x1aC\x86K\x9b\xa3\xd6\xcb\xb5ka\x97\x19\xaa\x1e/l\xb1\x88\xee-[B\xea\xfe\x80P\xf3\\\x10\xc5z\xf0Z#\xca\x0c%\xda\x9a\xabM\xbe\xdb\xe5|e\x9bj\xb2\xea\xb6\x1b\xb6M_\xe2\x16{R\xd9\x8f]\xac\xd3\xd6\xdeZ\xad\xd3 \xabTZz\xd2\x9c->\xf8f\xacS\xbdn\xb5\xef\xbe\x9eu\xea\xda\x17\xad\xba\xee\xe3\xc5s\xf2\xdf\xf8\xe8\xa7\x93\xcf\xe4\xb7\xff\xf9_\xf6\xd3\xeb\xd7?\xbc\xfa\xf2\xe3\xe3\xe8\xf0\x87\x93\xe3\xf1\xc5\xe1\xab\xd7\x9f\xa27\xd3\xab\xfd\xf9 \x9a\\\xbe\x9a\x9e\xce\xf7/N\x8e\xbf\xfb\xfe\xfb\xe9\x8bW<\xf9\xe9\xbf\xd1\xd1\xf1x?\x7f\xfe\xddl\xfcq\xca\xde\xbd\x98\xfc\xf2%\xfe\xfeu\xf6\xbf\x1f\xde\xbc|wz|\xf9j\xf2\x8f\x7f\\\xfe\xc8\xde\x15\xc3nZ\x04m\x9e\xb6\xad\xa6\xba\xcd\x1cu\xe4z\xb7\xaeH\xabi\xbe\x86\x7fa4\xc7\x1d\xaa\xc2fW\xbaLp\x0f\xd7d\xed\x00\x91\xd3\xe4\xf6R\x85\xde\xa6\xb6\xdb\xcc\x0e\x1d\xaf\xc5\xbcn7\xad-\x1d[\x0c\xde5X\xc6\xcbP\xb7L\xd4m>\x7f\x05\xd3\xd9j6;y\xd2\xcd\x91vS\xd9I3X\xc3Dv\x98\xc7ac\xafi\x16\xfb\x98\xc4N\x84\x1c\xa6\xb0\xdd\x0c\xee\xd6\xfbW0\xec\xb6\xf7F\x88\x9e\xef\x8dP\x82h\x84\xf9\xde\xefE \xb1\x8e%\x98\xa4\xb5VP\x1f\xca>\x8b\xef\x96\xcd\xc1\xe7\x88\x96g\xc8\x1b1\x8fZ\x0b)\xad\x16Dk\xde\xa0+P->\x03B\xcb\x8aj\x0d;\x13\xd6+\xb2\xd4\xe52j\xb0!r\xdcNu\xb0Z\x1e\xab\xda\xb3UkZ$\x93M&\x19\xb5\xa3cw8\xb4\xa1Y\x0b\xfa\xf6\xdb\xd0zk\xed\x9b\x82\xd7k\xfbfO\xf9\x1cc\x9c\xf1\xa2S\x0fO\xa9v\xcd\x9f\xc6\x101B\xb9vO\x18]l'\xc1\x00Q&\xa6\xd59\x83eC\xdd\xb4k\xf2\xe7\xda{V\x87\xabX\x0e\xd3\xacT\xfa,\xa61\xceT\xf4A\\\xa9\xa309\x9ffA\x84\xebv\xc1\xa4c;\xcc\xf0\xe7\x8d\xdad\x92'\xd7\xd5w\xc5\x82L\x9e\xa0i\xf6\xf0j:\x15\x0f\xb2\xd9\xe7\x0bL\x1f\x1e>\xa6\xe7\xc9U\x92\x7f\x99_<\xfe\xf2\xe4\xb7\xcf\xbfE\xb3\xa8\xb5\xab\xa5\xfd\xa9i]0\x11\xcb\xe0'<\x97\x93W\xcb%7\xcd\x04S\x9c!\xb1\x14\x0eh\xe9\xb9sL\xb96\xbb\xad\x8f\x98\n\xb8 \x08^\xa8y\xc2/l\x8e&8\x83\xff\xe7\xd3\xfe\xfe\xfe\xc1\xeb\x87\x8f\xf7\xb7Zz\xb0\xbf\x8d\xe9?\xbc\x1e\xf4\xde\x0f\xf9\xa8\xe5\xbbo\xca*:0T\xc3Y\xbbc{\xad\x1d\x14\xff\x96s1\xc3v\xa7\xd3k\xa0\x83\xc1a\xdb(cl2\xdf{\x87\xb6\x05B\xc73\x9c\x17q2\xcb\x13$\xac|9b,\xc1\xa8M2\xd4\xfa\x1f\xa3\x84\xb7\xcf\xc7v\xe7b\x01\xaf\xb8 \xd2n\x97\xdc\xa6b\xbbKA\xca\x08Q\xca\xd4\xc5\x8c\x9c\xe3x\xb9\x8a\xcd\x02\"F\x7f\xcb\xa9n\xa4\x8aP\x94bn\xc8h2\xbf\xbb\xd4\xcaDg\x1b\xcb]W\x8d\x00+\x8by,\xb7\x07k\xd9\xd9*d\x8c\x1a;\xb5[\xe4\x87\xf6\x1a\xa7UXPG\x05\xcbE\xea\xe3\x82\x1a\xba\n\xf4>.\xd8\x80\x1b\x11\xa3}\\\xb0\x8f\x0b\xf6q\xc1\x9b\xb3\x80\xbd\xe3\x82\xe5M\xdbL\xbf\x1e\xb4h\xd51\xb0\x81r1m l\xac\x1f\x10\xacy\xc2U -\xe5\xf9\x14\x0d\x97\x03\x1a\xc7y\x15U\xb8-Q\x8a\xdag7\x1c\x94\xe8\x1c\x10\\\xa2\xba\\\x90\x15\xca\xc3\xe6\xec\x90vQc\xe1{\x83\x80XCEl`\x9b[\x9f\xe9p\xb4U\xf1\xbb\xde6)\xe0Fl\x13\xd0:4!\xd1\xedV\xa3\xeb)\xc3\x0e\xaa%@\x07\xe0\xba\x0e\x90kJ\xe8d/\xc6 \x9e\xa8\xe7s\xf6~\xaf\xfe~\x1c\xc7\xd9\x1f\xe5O\x84\xd1*\xd2\xbd\"y[\xe4\xae\x96\xba\x8d\xbe\xee\xb4\"\xf7\\\x07\x83\x8f\xa3\xe8\xb8\x0c\xee\x8d\xe1e\xd9\xaejc\x10\xc3\xad\xd4XK\x04\x07*>\x94$P#\x91\x8e\xe7\xa3\xc5\xc4\x8b6\xcb:\xef\xa3&|\xf1/\x01j/X?\xbc\xff\xa9\xf6\xcb\xd7;\"*\xc8a{\xf0\xd7\xba-\xbc\x9e\x0c\xb6\xf6\xc0\xa7(k\xdf\xf3\xd6f\xc5A\x9b\xb9\xdd_.B\xe2k\xa8V\x8b\xbebUu\xbb8\xd3|\xb4\xd4\x8d\x875w\xdd\x88\xaf\xf5,\xa6\xfd\xa0\xad\x93\x12\xb6lQ\xe7fqnK\xf7A\x8aO\xef\xb5Mh\xf7g\xae'/\xe9\xba\\\x9f \x03\xac?\x7fk4\xed\xd5Z\x03B\xc7\xeb\xcf\xdf\xfa\xf3\xb7&\xf4\xe7o\x05\xdc\x94G\xb2~XCz\xa7\x8b\xe8Ay>\xd7\x8c2l\x1f\xed\x1f\x98\xbb\xfe \xcf\x17\x91\x05\xc2\xe12c\xde\xc1]S\xb4$4\xb8\xbb\xf7{e\x94\xa9\xdf\xfe\x12\xc1^\xcbl\x1a\xd4\xb0\xce\xe6}*-t\xfda1\xa5\xaa\xf1f\xa6\xd4\xc1V\x0d\x08c\xff#\xc7\xd9\\\x85\xac\xa2<\xcb0\xad\xc7\xd2`\x84\xc5%\xc6\xb4\x1e\xd2V\x19\xcfhe\x8e\xb7>\xc4\x1dd\xe7\xad\xe7Z\xad\xe7\xdf\x98\"\xd5\x96&\xc6(\xf5\x1a&\xc0\xb7\xe5\x91\xac%\xbe\xab\xf5\xdaP\xa8\xdaK\xf8\xe6t\xa4\x9f\x02\x1c\xf6gl\xce3\xb6\x8aX\xfdi\x9b\x82\xdb~\xdaF(\x11\x04%C\xe7\xf1\x99\xa1}\xd7vQ\x86\xd5*\x0e\xcdo}\xe9\xf6\xa6\xea\x883B\x87\x82\xcc,#\xaf\x94\x81\xeb&w\x16\xed;\x89\x18\xfbi\x18\xa2\xad;\xa6\xdc\x01\xfd\xd1X\x05\xfd\xd1X\xdb\x88\xfe\xb3\xeb\x8f\xc66\xe4\x88\xf6Gc+\xd0\xc7\x10\xcd\x9f\xf5Gc\xfd\xd1\xd85!\xde!\xdc\xb0\x80\xfeh\xac?\x1a\xab\x81M\xc4\xf7Gc-\xd0\xab\xb5\xfeh\xac?\x1ak\x83\xfeh\xac\x80\x9b\xf2H6\x13[m\x8bC|S\x87d\xadq\xda\xfe\xb8\xac9\x9b\xbf\xdaq\x999&\xdd\x9f\x98uq\\\xd6s{0\x15Y\xab\xf2Y\xc3\xfc\xec|\xaf\xc3#\xf4\x0d>\x82x\xdd\xf6\x1e\xa1p\xf0\xe9\xc7\x16\x11\x07S\x07k(\x8cM\x1f\xc6U2>\xc3\xb5}j\x97\xd7\x9f\xe5&\xaf\x06Z\x12\xd8wZ\x87\x0f\x16\xd6\xcd\xc0J\x0b\x15\xcd\xa8,v\xcb8c3+>\xbf\xa0\xa4\x86\xcf\xc7,\xfa\xc5\"l7\x82\x92`\x01\x08\xbd\xe4b\x0d\x84\x02\xc4vy\x90\xd8`\x02\xd8\x19\x93D\xe0\x0cFs=)\xcd\x10\xbc\x8c&\xddz \xedy\x90\xf8\xff\xcb\xf0\xf8)l\xff\x9f\xbd\x18\x8f\x95x\x92\x16\xcc\x87\x1a%|\xeb$\xaeeH5H\xff\x970\x98\x82\x8aB\x16'w\x0d\x0e-9\xed:\x0e\xec|\xea\x17n\xc86\xe8\xcf\xe6\xfa\xb3\xb9%\xf8\xa6<\xe1\xfeln\x05\xfa \xa6\xf9\xb3\xfel\xee\xcf~6\xc7\xb3\xa8D\xfe\xab\xe0\xdf!\xc4\xb1\x80\xc54b.\xbe\xde\x1a\xac5\x87\x0e9\xb2\x0dq\xb8\xffm\x9d\xd7\xf5E&\x9d*\xa3\xab:\xeeO\xf2\x1ap#J\xb0?\xc9\xebO\xf2\xfa\x93\xbc\x9b\xf3_6s\x92W\x0fL\x18N\xf0\xae/xT\x19-\x7f\x8d\xc8Q@dsq \xb5\xa0\x11\x88)\x12\x8d#(\xc2a\xc4\xa84\xcf\xaa\xf8\xec\x9f%\xbai\x11j6q\xc6\x8a\x83\xc8\xcew\x1c\xbaY\xc1\x9b\xb5\x83\xb5\x85\x8a)\xcf\xf90\xcdG\x06\xc1\xef\x98\x86K\x8fUx\xca\xb1\xd2|t\xf0%\xfa-\xceq\xfay\xff\"?\xfc29\x9f\x9c\x1f=\xc1c\xb4O?_~\xa11\xa2\x9f\x1f\xcc\x8e\xa2G)\xba\x9f\x1f\xa1\xf4\xcb\xd1\xe40{2\xe1\xe9\xe7\xc9\xc3\xc9\x93\x88\xdf?\x7f\x12\xe5\xe3\x95q~C$\xc1\xad!'\xbb?\xcc\x05\x12\xb9e\xedL\xf7<\x04;\xc7\xed\xf5;\x1d~O\xe9\xbbv\xac'Wg\x19c\xdb\xceg\x8f3F\xc9\xb9\xf9y`\xa7\xca 1\xa6\x82\x08\xe3\x8b\xcf\xce\x0e.\xf1\x88\x13Sd\xc3\xa3=\xc7Q\x9e\x111\x1fF\x8c\n\x14u?\xb5\x8c\xb1@$q\x18\xe7\x86\xf6RP:/\x10\xb9wS\x9bRW]\x13*24\x14WCeB\xb4/\x97\x9d{k\xa3\xec\xaf\xfc\xb8HX\xb9\x9e9,\xfa\xb7_\x94\xf2\xe8\xfd\xe0\xc9\xa3\xfd{\xfb\x07\xf7\xf6\x0fN\xf7\xf7\x9f\xaa\xff\xff\xdf\xd5\x01#6\x9b\x11\xce\xafg\xcbd\xc6@\x9cs\x1e\xe0\xa2\x94\x84\x19\xba\x1a\xde\xc4\x18\xd1\x14\xd1 \xbe\xf6\xa1\xf24F\x02\x87'\x044\xc1\x97\x03:Z\xab\x8b\xf67a\x90\xf6\xb9`\xcd\xd9\xf8\xe7\x82-\xe5\x02lv6\x1d\xec\xaap\xab\xbb\x96\xad\xf2\xa70\xb9\x83\xe2\x84n\x0b\xda\xdb\x14\xf2\xb5\x9e\xd7_\xe3\x05\xb8-g+\xfav\xab\xf9\xfamf\x93\xc5l\xb3\x97M\xd6\xb2\xcd\xda0Y\xca\x16\xe2\xb8\xaddkc\x8b\x85lU\xf6vUo\xb5\x8d\x1d:\xcbn\x17;\x1a[mbG[?{\xd8\xd1\x89\xd5\x16\xb6\xb4\xb5\xda\xc1~{c\xd5\x8c\xf0\xb4\x80\xed\xf6\xaf\xd1\xfau\xdb\xbe]\xf1vY\xbd\x9e\xfd\xfaX\xbc6{w\x8d\x0d`6\x0d\x9d\x16\x9b\xc3,\xb4\xdb\xb8\x9b\xe8\xddi\xdd\xae;\x88\xd3\xae\x0d\x18\xe0Zl\xdakM\x8d]\x18\xb3\xba\x8f\x00C\xa8\xa6\xfd\xca\x1c\xcb\x05\x9a\x11\xa2\xb1\xfc+\xe6\x03x>\x87\x18\x8fQ\x9e\x08 \x022,\xf2\x8cr`4\xd1\xc5\xa7\xb4\xa9T\xf5\xb5\xc0hP\xfc\x9b9 \xae\x99\x8fZ\x9a\xa1Z\xd7\xd5\xfe\xd9\xb0\x82\xb6T\x89\xd3)\xae\xcdF\xa2Xt;\x80w9W\x99\x11\x98\x88)\xce`[\xe3\xbf\xbd\x0b\xdbZR\xa8\xbf\xb3\xa6\xe8\xda\xae\x84\xc8\xf6\xa0\xf6C\xcdt]\xa2\x82m~)\x9a`\xd34tA\x8e \x06}<1X\xa1\xc2\xaa`\xad!q\xe05~BfD\xd8\x10\x98\xa1+2\xcbg\x05\x0e\xd2\xc2W\xe1[Hq\xa6\x90\xeb\x88\xd5\xad\xb7\xa1\xfb\xb0\xb5\xd3\xf4\xf61\xbe\x9d\xd3\xe8\xc3\xd6\xab\xed\x8c\xae\x96\xcb wv\xd0\x87\xad-\xed\xfd\xcct\x8f\x8e\xfa\xb0u\x1f\xb6V\xe0\xda2\xd7\x1d\xe7\xed\xc3\xd6-\xe0\xcb\x01\xdd\xac\xf1\xed\x16s|\xfd\xd8\xb2\x7f4\xf6\xcfq3W\xfa\x12\xf5\xc70\x8b\x1a\x91\x9c\xd0I\x82\xff\xe4wp\xdd\xb6\xa1\xb7\x92\xf7\xb5\x0b\xd7_\xe1\x05\xb8mB+\xfa}@\xd6H\x1c\xb7\xfdgm\xdc\x07d+\xf0\xb3\xf4\x1c\x9d\xf4\x01\xd9\x1at\xc5\xdbe\xcfy\xf6\xebc\xcb\xf5\x01\xd9\x06x\xd9m\xeb\x0e\xe2\xb4\xd8\x02\x06\xd8D@v\xd3\xb1W\x1fko\xbd\xd7w\xff:\x96\x9f\xe5%\xdeo\xce\xe0\xbb\xde\xe8\xa1\xc7\xdd;\xc7\xceZ\xdc\x1e\xeb\xdaC\xc7\x10\x94\xb3$xg_\xfa\xcf\xfe\x12\xefW\x11]\x1bz\xde\xe0\xaf'\xc4\xacO\x1d\xf4\xe2\xac\x01\xb7A\x9cy\xd4{ZO\xae\x19\xday\xd4w\xb2\xdb\xec\xd7\xf5\xd4\xc1\xa6\xc5M%mR\xc6\x92\xa7]\xb6U\xfdq#\xe9q\xe3\xf2\x91\x82\xa2g\x90=\x7f+;*(\"\x940\xc6\xf1\xb0C\xc4@\x1fDwiI\xe88\xd1\x8c\x99 .\xc2\x9d\xb3\xaa}P+\xe5,\xa8\x01\x17\xce\xda0\xc3\x1c\x87y\x9ci\x86/\x86\xc5\xdc\x83B%\xeb\xb2\xf6\x92F\\\x8f\xc15O\x97]\xea{\x93\xfcO\xc9\xdf\x0bfS\xe5&\xb4W\xea\xb9d\xcb=\xcc\xd0U\xd7\x96$\x8cY'L\xea\x0b\xc5eA\xed\xd6\x08yH\x9f}9\xcbg\xb5i\xbb\xaaP\x11\"\x83\x91\xbc\xd1\xcd\x90 >\x95\xbb\x81\x93 \x95\xb3$t\xcc\xbam\x08\xd9\x83:\x06\x90\x92~B.0]\xba!y\xa7\x05\xb1\x95\x86\xadM\x02\xb6\xc8\xca^+&X\xf6\x14\x98\xd1d\xcb\xf89Yd\xfb\xd4>1\xad\xaa\xc1\x0c\xdet\x16\xd0;G\x06\xd0\x860}p\xa7\xfc\xf6z$\xd2\xf5\xda\xb0\\\xa0L8\x8d8\xa3\xf1\x19\xe3\xab!\x1b\x8f[\x15\x9d\xa3\xb1>\xb0\x18\xe6T\x90$\xb8\xb1\xd4\xb18\x1e\x8e\x12\x16\x9dswJ\xc0\xb2\x84\x08\xb4$\xd3|\x94\x90\x08\xce\xf1\\\xd5)b\xb42\xe1V\xf6gW\xf1\xb3\xbd\x90?V\xb7VR\xad\xf4c\x03\xea\xfb}R\x0d\x01\x15T_\xf1\xe4\x1a8~\xc44n\x94b\x12\x0crG\x07\xd7S\xaa\xa6\x93\x0830N\x9b\xd7nv\x16\xec\x11\x00\x8bdX\x89$l\xc6\x95\x075\xb5\xc6\x1c\xb6\xb7W\xb0\xd5\xcb\xfc\xbcY\x96\xb1\xa5R\xa3\x11\xfb\x0d\x19F\xd7Rr\xb1\xb50\x10X\xe4d \x1e\x85r\x8c\xd1\xaf\xd6BA\xe0\x9a\x088'\x03\xb6\xa2A\xe0\xc6\x0b\x9ca=7]\xc0E\x1b\xf0\x99\xa7\x06\xf7l58\x0b\n\x81\xdf\xdcK\xf0\x88~\x96\xe0\"\x97\x86.c\x1b*\xedu\xae\xa2\xe9U\x1ah-\xd6s\x8c\x00n\x1c5\xb8\xb2`5|\x85BD\x12\xac\xc5\x88\xc0\x87\x90\xe0EL(\xbb\xb2\xf2\x8b\x17=\xa1N\xd3\xc0\x02E\xe0.R\x04\x9d\xf0X\xb3X\x11x\x16,\x02_\xe4\x9c\xf9v\xae\xe2E\xb0\xc6H\xc1f~_=\xcf\xb9\x89\xfa\xeay\xf6\xbd\xe8\xa9\xe4\xdc\n.t\xbc\xbez\xde\x8d*\xad\xbez\x9e\xdf\xd8k*$\x1fe\xe4D\xc8\xa1\x84\xbe^\xf5\xbc\x15\x9f\x16XV9d\x8b\xbe:E)\x16A\x8aM\x1e\x19\x14}\xd6\xdc\xf9\xa2\x89\xcb\xfd\xf7\x0f$\x04km\xcf\xe0\\\x98nFWC|Ab\xc9\x17C\x14xR \x05\xde\"\xe2uIh\xcc.\x83:\x98\x11:,:Iq\xd6\xa5\x87\x98\xe5\xa3\x04\xabN\x86\xfa0`\x18\xe7Y\x87\xd32vI\x05\x99\xe1\xb5:Q\\3\x1cg:D5\xac\xe1\xb6^7\x1a5\xcf>:\xee\xa2 \xbb\xd8\x93l\xc28*\xf3pC\x82y\xd5c\x1de\x1fwZ\x06o\x0b\xe2qC\xc3\x9b \xde}\xcf.$9hTN\xa8=|\xd7\x98\xc5\x92v\xae$\\\xae\"\xb0g[\xe5D\x86ry\xb6\xce B\x14F\x18\xce\xb6\x04\xbe\x12[g\xbb\x8d\xd6g[\xd5\x88\xc5Y\xdd\xd6\xd9.\x9cmq6\x16\x97(\xc3\xc3<\x9dd(\xc6[g\xb5f\xc5\xe1\x07\xe3bX\x0d6\xfas\x06\xd8\xfa7M\\\xb3\xeb\xdf4\xd9\x90U\xd3\xbfi\xb2\x02\xbdCj\xfe\xcc\x15i\xfd\x8b\xbfi\"\x88H|M\x16\x0d\xf5\xd9\x84\xb4k\xe8\xdb\xa0\x965\"K\xdd\xdc\xda\xaf\xf9\xe6\x8f\xa1\xcb\xc6\xa2t\xbb3\xd8\xed1\x962\xed2\xc6)\xe3\xc4\x98\xe5\xd5)\xe4\xf6\x97\xcb$\x0fv\xce\xfa\x90\xaa\x93\x1b\xba\xea\xd2>\xa4\xda\x80\x1b\xd1`}H\xb5\x0f\xa9\xf6!\xd5\x9bs>\x82C\xaa\xa5\xd5\xb3\x89\xf7F\x82B\xa5\xba\xa8D\x15*\xba\xd32\xce\xd2'\x8d\xea\x13\xcar\\\x89\xaa^\x7f\x08\xc7\x9c\xb0y\xc1D#\xc1\xb21\x15\xf5c\x8b\xddfz\x91\xd9\xb0\xe8\xb6\xf1\x0b{\x8d\x19q\xa8>\xb8^Y\xa0\xd1\xb4\x97\xee\x0d\x08\x1d\xafO\x16\xe8\x93\x05\x9aP\xd1\xadO\x16\xb8\x19\xc3\xbc{\xb2\x00\x89\xa5{VF$\x9a\xa9\x03G\xfb\x07\xe6\x9e~\xc2sH\x11\xe7\x97,\x8b\x81p\xb8\xccX=T\xdd)\x14\xe3\x15p\xde\xfb\xbd2\x9c:\xe7\"\x14=\xdci\xc1\xad\xf1A3\xf4\x0c\x88\xc6\xc6\x1b\xcc\x7f\xe50\x8c\x0ff\xc5\x93 \xb6\x0b\xe0\xe6;\xe4\x1d\xb1,\x8c]\xd7; \xfb\x0f\xd3\xab\xab\x8b;\xe5P\xb7\xc0@\xeb-\xed\x1a\x84\x8c\xd1b\x8bt=\x9c\xfb\x86\xdc\xb3ud~\xdbK\x9eG\xfbG\xe6\xee^\xb3\x9c\xc6@\xd9\x92\x10\xbd\x16\x99\x7f\xc1\x04\xee|\xc2\xa8\xea]X\xce\x17\xf5\xef\x8d\x8a\x1e\xb7\xea\xa4\xf1+\x0b\xf6\xeb\x12\x84\xd7{\x18\xa9\x16\xd5,\x05\x0d{v\x9d\x036\xa6\xa7\xef\xdb,x\xaf.Zv\xda_a\xc7[\xbf0}\xfd:\xf0D\xeb\xa2\xb5Y\x7f\x88\xe5\xdcd\xae+\xe3+\x15\x995\xb7m\x9d\xc1\x98\xe0$^T\xa7\x99c\xae\xeb\xccP\xb6Z\x9a\xa6\x9e:\xb7u\xa6\xcc\xd8\xb3\xad\"9\xd0T\x8dY.i\x7fd\xb6\x02\xfd\x91Y\x7fd\x16\xd2{\x7fd\xb6\x02}P\xd5\xfcY\x7fdf=23Xw\xb7\xcd\x1f\xd3`2\x0c\xad\xd8.\x18`\x8e\xf9u\x9b\xe2A\x9a\xb8?4j4\xed\xe5[\x03B\xc7\xeb\x0f\x8d\xfaC\xa3&\xf4\x87F\x05\xdc\x94i\xba\xee\xa1\x91r\xfao\xf3\x89\x91\x8a\x1e\xee\xfd\xae\x8c\x86\xceGE\xb2\xf5\x9d\x16\x8c\x16\xbf\x9a\"\x88P\x9c\x18\xb5\xd5\xdd\xfd+\xc7;|0+\x1f\x907\x94,n\xafv\xdc\x11\xbbo\xf6\x94(\xdc\x1a\xeez\x16\x12d\xcav\x16&\x9dO\"j{\xf4Z\x04\x89\xba\x06\x1c.@\xbe\xc7\xf5\xc7\xe0\xb69\xa8~@_'\x06\xd4|\xa6Q\x90Y\xab\x9c\xa9Y\x11\xdfc\xc1\xc3:\x1c\xc0\x9bq\xedf\xa0\xa4\xf6\x82\xb8)\xa61\xa1\x93\xc5=\xab\x1d2\xc0E\x11l\xd8..:\x9c\xa8r\xd6\xdbw\x81\x08\xc8\xb0\xc83\xca\x01Q\xc0\xb3T\xcc\xf5\xf0U\x7f\x1a\x8dA\xf1\xdf\x7fU w+$\x83\xe1z\xb9\xa7\xe7i\xbb\x1cm\xbcR\xbe\x81\xbe\xdb\xaf\x91o\xa0c\xfb\xd5\xf1\xb5\x06\x08\x16v\x8b\x96\x9d\xe4\x94\x16S\xd5~\xd8k\\7\x0f\x90M\xda|\x99T;\xad\xcaxY)/l\x92F\x1e=\x0cTE\xac\x19\xba\x1a6\x8b\xe7CN\xa5\xbcA\x19\xae\x07\x86(\xa2\x8c\xe3\x88\xd1\x98_\x87\x10\xb9\x15\x1bsFh_!\xa0\x01!c\xb4\x05\x0dV\x98\xab\xf3\x06\x7f\xfc\xf0h?|\x8b\xff\x07\x13S\x9c\x0d\xa5j\xf8O\xe9\xd5P&\x95~\xbd`\xb7T)\x98\x8b\xa6\xf6\xf0\xb4l\x8c\xbbrS\xf2C\xa9pB'\xeb\x0b\x10m\x8b\xd8\xc5\x87o\xa3\xdb\xbd\xef\xcd{JL3\xcc\xa7,\xe9\xce\x84\xfb\x83\x07F5\xb6\xa6\xfa\xba\x7f\xff\xc8\xd0\xf1bA\x86)\xa6(\x11-\x81\"\xefa\xf6\x0fn\xd7\x162\xb0\xd8\xa66\x90.Q\xb2\xfe\xf6\xd1\xfd\xac\xa1~W:\xd0\xda\xb7\xf1,\xcd\x9fD\xf1Z]\xe2\xc5l;3\xf1m\xd4\x04&\xfe\xe8\xca\xc7\xdb{1\x91\x84\x18\xe5jAc\x9c\xe0\x89\xaa\xcd\xba\xf7{\xf5\xf7\xe38\xce\xfe\xd8\xcb\xf0%\xca\xe2\xd2\x9fX\xf5\xc5\xee\xad\xfaFe&o\xad\x9f;\xad\xd8\x15q\x9e\xe3(:.3\x1f\xc6\xf0\xb2lW\xb51xe\xad\xcb\xd9\x12\xd9yt\xf9\xe4\xa1\x88/f\xe8\x0b:\x8f/\xcf/\x0f\xf3\x07\x8f\x0e\x0f\x1f\xe18\xcf\x13t\x18\xcd\x1f<:L\xc6\xa1;Xz\xf7\xd2\xb5Ve\x9f\xa0 \x12\x8cP\xa2v\xe38c3\xf5~CA\x04\xc2\xa8kG\x97\x1d\xf2|&\xa9 \x1b\xcb\xff,{\xc6(\xa38\x86\xd1\xbc\xde\xa5\xfcO\x04\x9c\xd0I\x82k\x14n\xd2o\x8d\xcd\xfc\xb2\xc6#\xd7\xb6\x9d;\xd8\xd1\x05QL;\xfcfm\xe8\xaaX\xf8\xb0\x88_\xb5\x7f\xe6e\xeb6(\xe7yZ\xada\x89\xeb/P\"\xb1v\x865\x0f/\x8f\xe8a\xd2\xda\xa7&\xb2}2\xe6cP\xc7A\xa8\x93\xea\x1a\\\xb4\xd7\xe0<\x0e\xf5\xa2\xbd\x06\x0f\x8fF\x83\xfbP\xb4\xcb\xa8->\x8e\x920\xb7\x83\xd5\xbf]w\xd1/PS\x89\xce\xd5Pt'-\x1b\x96}\xfbO\"\xa6q\x86.+\xd9_\xa1\xb3\xcdkR\xbf\x94~wZ\x10\xe9\xd6\x85\x87\xd8\xbf\x9ed^\xf3\x03\x97Ky\xa6\xda\xa2\xa8fWZRK_\x85\x19\x8b}ni\x9f[\xba\x04\xdf\xd4\x01~\x9f[\xba\x02}\xee\x95\xf93\x9b\x89\x01\x7f\xdd\xdc\xd2[\xe1\xcf\xf4\xc9\x95\x8d\xa6\xfd\x06o@\xe8x}re\x9f\\\xd9\x84\x8an}r\xe5\xcd\xd8f\x9b\xf4<\xbfBVe`lx\xef\xf7*\x06\xa6\xfe\xfd\x1b\x8e\x15\x87d\x01\x1ag\xd3\xa0\x86u6\xefSi\x91\xe8\x0f\x8b)U\x8d73\xa5\x0e\x81\xc0\x80(x\xf9n\xcbJh\xe1N\xcb\x9c\xcb\x8fu\xbcz\xb5\x8d\x8ef/\x87\xaf=\x82\x13\x01\x11\x87\xeb2\xf7\xae\xf7Z\xbb\xd1$q\x88$\x87 \xe2*\xdd\xed\xee\xf7\x1b\x8e\xb1\xf9\xf1\xec\xea\xf7\xed\xa1\xb4\xe2\xc4\xa7\xe4\xed\xe5M\xec\xc1\xc4}\x84\xad\x84>\xc2\xd66\xa2\xff\xec\xfa\x08\xdb\x86\xac\xb8>\xc2\xb6\x02\xbd\x03n\xfe\xac\x8f\xb0\xf5\x11\xb6\x8d\xaa\xba\xae\xa2\xa6\x8f\xb05\xe0F6x\x1fa\xeb#l}\x84\xed\xe6l\xb3\xf5\xfdN]\x05\xb1\xf2\xe3\xbe\xfaUf\xdf\xa0\xdbe\xe1\xa3\x95\xe9f\xdfp\xb4\xedZ33\xcb\xcc\xc9\x92^(Y\x8a8\xb821k\x89\x96\xdb\x96\xde\x06p:%\\\xf2\x81lT2W\xcdh\xba\x9c\x92h\xaa~\xcc9\xce\xe0\x92$ d8\xc2\xe4\x02\xd7\x10\x85qNC2r\x02\x82\x00\xd7e\x81\xb5l\xd4\xd0\x04\xc6e\x96\x08,\xb5\xd3q\xeb\xaf\xb9W\xc3BN\x1fp\x9a\xa0\x08w\xe0\xc9zKOf,\xccy\x8a/\x81Q<\xf0g\xa7>\xfcTB\x1f~j\x1b\xd1\x7fv}\xf8iC&N\x1f~Z\x81\xde;5\x7f\xd6\x87\x9f\xac\xc5\x03\x97\xcdf\x93V0\xd09\xd4\xb0\x81u\x8d\x9b\xeb2\xda\xfa\xb0Y\x1f6\xbb=\x82\xa9\x0f\x9b\xf5a\xb3>lvs6\xe5\x1aa3\x96U:\xf4\xf6%\xa9U \x17\x1bHF\xfb\xeb\xa4o\xfdR\"\x0bub\xd6+\x1a\xdei\x99\xbc\xce\xe3RA C+u\x81y\x8d\\\x98\x80\x08\xc3\xad0\x93X\xc1\x07_\xcf\xb6\xec\xc0'\x0b\xe08\x19\x0fG\x8c\xc6\xc3[u\xb1\xfa\xdb\xbdm\xaa\xe1\x02%\xc3\x88\xcdf\x84sb.\x9f\xd8\xd3t\x19\xdai\xea\xa7\xae*a\xb3\xa1P\xaf\xb7\x9a\xd9c\xb9\xe0\x02\xa9\x9a\x8a\xc3\xce53\xfe:\xaa\xe75^R\x1f5\xfaU\xf1\xedo_\x8d\xf4y\xc1\xd7\xbf\xf3\xfa\xdd\xe6\xdcm/*5\xa4jRK\x85\x7fo\xb5\x1c\x80u\xbf\x19L\xc0\xc8\xbb\xe7\xaa\xc3\x80S\xa9~\x07\xbbv\xda\xcd\xec\xe0\xaf\xa2{\xc3\x8eY\xab\xb3C\xc9\x95\x15*\xdb\xdc\xab\\\xc6r\x9be6\x96\xac\xbd\xe0\xf4\xe5>=\x18\xb9?^-\xa1?^m\x1b\xd1\x7fv\xfd\xf1\xea\x86Ba\xfd\xf1\xea\n\xf4\xa7\x18\xe6\xcf\xfa\xe3\xd5>\xbb\x7f\xa3\xaa\xae\xab\xa8\xe9\x8f)\x1bp#\x1b\xbc?\xa6\xec\x8f)\xfbc\xca\x9b\xb3\xcd6\xe9{\xde\xf8\xd1d3p%\xdd\xc6\x9c\x121\x1f\xa6\x8c\x15u<\x03#7\xaa9\xc8\xe6\xab\x05\xa0=|\xcf\x00\x87\xf2\xba\xb4y\x1fD\xd9\x0c3-;\xfc\x01\x8c\xb4\x12p\xff\xe6X\xc9\x11\x8aH\xd5+;8\x1b\x9a\n\x17[Vm\xc4h\xce\xd7\xeaa\xb1\xcd\x05\xba\xf2l\xd9\x91#f\x84\nB'\xeb0\xc3;\xdd\x05\xccX\x9c'\xd8\xcd\n\xf2\xfb\xdb\xcd\x02\x92(C\x83 \xb0,\x1b\xa1\xe3D\xe1=T\x9eM4Etb\xb4\xd9\x1c=\xcc\xbc\x17~\xa5e\xe0\x93Z\x13\x86\x12u`\x8f\xc3\x98t\x94\xb0\xe8\x9c\x0fS\x9c\x0d\xe7\x18\xf9>\x1e\xb8&\x9bV\xd3\x0c\xe6\xd2\x17\xc5[vEO\x0b\x82i\xc3\xea\x96\xf3\xeau\xd0\x12Q\x9a\xa3\xe4^\x9a\xb1\x0b\xa2\"\xd1k\xd3T\xf7\x08\x8b\x1e\xffr\xb4\xe5y\x9a&\xf3\xbdZ\x99\xf5\x00r\x9e\xaa\xe7\x1ft\x17\xc0\xc6\x101B9\x10\xaa\xcf\xc6\xa6\xa8\x8a\xae,S\xf2\xa3jr{h\x19\x14o\xe9K\xd2/ d\x8c\x0d\xd8\x83\xdb\x0d~\xdd\xfb]\xcd\x9fP\xc5'\x1dr\x1d\xeb\xcd\xef\xb4\"\xf2\x82\x11\xda\xfeY\xc7\xf3\xee\x1c 6S?\xac\xb1\xcf\xaac\xea\xc8\x80\xdem\xdfo\xcb\xb2\xcb\xcb\xcb5M\xb6;3%\xa3\xd9\x1e\xca\xc5t\xef\xe2`\xaf\x88\x10\xf0\xbd\xdf\x0b\x1f\xba\xe5\xd5\xecjA\x8e\xf5\xc7\x8bWa\x8b\xff\x8e\xb1@$\xe1\xca$\x8f\x81\xd1\xea\x96t\xd1\x81N\x95$\x8c\xbe\x89\xabN\xba\x92\xfa\x18x\x1eE\x98\xf3q\x9eT\xad\x07^\xe4\x0f\x12w\xc5\xdcV%@\x03\x9b\x05\x05\xc6\x84\xe2\xe26x\xf1ol\\$Kd\x1aM\x95\xe5\xb4D\x99\x05\xac\x11!\x94M\x87y\xd6\"\x9c\xc1GV\xf9\x9d0\x1c\xc3\xa7\x0fo\xf72\xccY\x9eE\xe51\xe8\x14 \xc8)\xf9\x9c\xe3d\x0e$\xc6T\x901)\xc8 \xc7\x0566t\xa7^=\xc2\x19A \xf9\x82\xe3;\x86\xaf\xd2\x8c \x16\xb1\x04F\xf9x\x8c3\x98a\xce\xd1\x04\x17\xb7\xef\xf5\x9c`\x96s\x01\x11\xa3\x02\x11\nH@\x82\x11\x17\xa6\x1e\x19\xc5\xb0\xb5\xb7%\xd5t\x86\"\x813\xfddZ\x82\xb8\x00\x8e'3\xbcX\xb8O\x1f\xdens%?\xd5\x10\x86\x0e3)\xc48\xa6\xc6\x11eW\xe3\x88\xd8\xcc,_?\xaa\xbd\xc8A=@)\xc5\x00]\x96?\xb0#1\x9b\xe2\xe2\xe1~\xbdy\x97/H\x970#\x93\xa9\x80\x91Q\xdc\xa8\xa9\xaa\x84\x00\"\x0dz\xa9&uP\x86\xa78\"c\x12\x01\xc73D\x05\x89ZL\x1b\xeb\x99\x98\xd3<\xd1;\xf7)\x8c\xe6b\x9d\x0c\x89wR\xc8\x8cp\xf5<\xe7\xc2\xf8X\xb12\n\xc5\x8cF\xec\xc2\xc4:\xc5\xb4\x0bfoN\xd9\x8e\x8f\xca\xa2-l\xe0\x0f\x85\xf9Z\xd6\x11*\xcdY\xcdP\xe3b\xfdT\x8b\xbd\xa6\xd9\\\xc2\x87\x93\x170\xc3b\xca\xe2\x05\x0e1\x1e\xa3<\x11f\x0b\x9aBN\xb5\xa2\xc4\xb1\x16\x81\xd5\xc8\xb56\x1b\xb2\xa3U\xff\xa6\xb0\x81!\xaa\x1e\x1b\xa3\xb1\x84\n<\xc1\xd9\xca\xaf%\x93\x10*\xee\x1f.\xfdZ(\xc3 \x1c\n\x8f\xe6v\x84;\xec\xf6\xbd\xc7\x16r\xf1\xe4\x026l\xe5\xfb\xda\xf9\xdd,}cgV\x0f\xa0\xa3\x0f`\xecM!\xe5\xf4\x026\xe2\x07t\xf6\x04\x8c\xfd!O_`Mo\xa0\xa3?`F;I|=\x82n>\x81\xb13ea{y\x05\x1b\xf7\x0b<=\x83\x8d\xfa\x06\x1e\xde\xc1\xc6\xfc\x83\xf5<\x84\x0e>\xc2F\xbc\x84\x8d\xfb NO\xe1\x1a|\x85\xeb\xf2\x16\xae\xc1_\x08\xf1\x18\xba\xfa\x0cV\x19\xee\xf2\x1a6\xe87\xf8z\x0e\x81\xbe\xc3\xc6\xbd\x07\xb7\xff\xb0\xb6\x07\xe1\xc8\xab\xf30\x81\x9c~\x84\xbf\x95\xb4Y_\xc2\xeeMh\xf0\xc1\xec\xec\x98\xce\xcfJ\xf3\x88K\xc1\x85\xb2\x11\x11\x99\xdc\xc4f\x0c[\xbb*u\x04JX\xc1z\x80\xda\x97VJg\xa5h4\x86\xa3\xa6Y\xb8d\xfeUV\x9d\x815O\xca\x8d\x93\x90\x91B\xbb\xd0#\\\x1d\x02\xb1Li\xf0\x14E\xe7{9\x95\x7fH\xbd\xad\xf9\xa2}\x07\x15\x8a\xdel\xd8\xb01\xe4B\x0b\xb6R<\xa8\xcb>(\x8e\x89\x96\x15U\x02|\\\xf8Y\xbc\x98Vk\x7f\x12\x1f\xbd\x84\xed\xe3\xbd\xd2\xe7ap\xf0\x14N$\xfeR.\x14SA\x15\xd1 \x85\x17\xdf}gQ\x93\xaf\x19\x831c\xf0\x0c\x06\x83\xc1\xbf\x1b?\x93\xc8 :7\x7f\x80\xe8| \xd1x\x9d\xb1\xd9\xce\x98\xb1\xbb\xe6O\x07\x03\xb3\xfe#c\xd8\x91]}R\x139e;\x7f\x93}\xdd\x85\xdf-2\xdc\xd6\xdf\x1fv\xda\x1d:h\xf7#\xba@\x1b#\x1e\xf8\xb2\xa5\xa9\xa8|\xaf\xd6\xfe\xcc\xae\xa8BuK\xf6!\xd5a\xeb'?~|\xffs\xfb/\xcf\x9e={f\xe6\x01\xd9n\x11s\xd1v$\x93\xe2\xa00\x82\xb4_\x97s\\\xc6U'y\x82\xb2\xf6\xfeV\xbb\x11\xaa\xf4\xf6\xc2l\xd9\x05<\x1b\xe18^\x180\xbb\xda\x1co\xeb\x0e\x19\xa275\x93b\xac\x1c\xd9\xb3\xff\x92\xa4;+\x82 \x95\xd9V_\x9c\xf6\x0dR\x88\x9f\xa7\x16\x07\x04E\xe7R\x06-\x1c\xe21I\xb0Yo\x942\xeb\x04g\x9cQ\xeb\xb6-\"qc\x92q1T+\xfc\x0c\x0e\xcc=W\x0d$S\x96\xdf\x1f\x86k0\x00+V[\x8a\x96[Oa\xabm\xd76\xc90\xd0\xb3\xdc\xda\xb5\xf5\xa7\xe6\xf73\x9a\xc9>\xffCO\xe1?\xad\x0d\xe4\xfc\x96\xbe\x0f\x9d\xe4\x9bq\xe1p5yMs\x03\xe1p\x89\x93\xe4\xde9e\x97\xba4\xc1\x14q@\x10\xe5\xbc\xcc\xacZ\x06\xf3\xe6j\xb2\xfc\xae6\xe0\x97\xf6\x81\x16\x9e5t$\x03\x1b\x9c+\xa4Y\xba}\xb03\xb5\x19K>\x9f\xb2$\xd6L\xae1\xd7[\x99\xd0j\x7f\x80\x8e\x00\xb6w\xa5\xb7L\xfb8\n\x85A\xa5\x9cw\xa4\\+I\xb8\x12\x1a*#\xa6\xbf\xfe\xeb\xd7\xbb\x96\x8d\xb4 \x9ek\x0ehg;E*\xd9\xe5\xc1\xe0\xf0\xe0\x90\xb7\xdd\xe9\xd7P*\xea\xf6b\x10:\xcdo\xb5\x8a\\3u\xa9\xa8m\xd0H]*\xfeM0\xf8\xac\xaa\xbd\x8c\x9b\x81\xaf\x95\x84BcB`\xabK\xbe\x9c\x9f\xa7N\xb6\xee\x0042\xd2\xd4\x94Vs\x9c\xab$\xb4\x13\xf5\xbb\xc2\x8f`\xaeB\xc1\x0b*\xb4g\x9c\xe5b\xaa[\xdd)q\xbe\xa5Ig\xf5\xb9\xd7\xa1\x81\x8c\xfe\xa8\xb1n\x0b\x02\x94\xfaK_\xf2\xd8h\x9a\xd9\x0c]\x0dgx\xc6\x86\xd5\xb9\x89\xe5\xbc\xca\xebH7'T<\x13\xa2\xcf\x84\xb0o\xcak8D\xd8@\xba!1d\x1aV*e\xb3)\x87\x0b\xfc\x16\xaaD\x8aO\x13\x9aK\"\xba\x90\xc9\xa8\x10\x0f\xba\xf0\x9d:w,\x84M\xa1\x8c*\x01\xae\xa4\xf6d\xe9XM\xcdPz\x86v\xa1<\x80\xf74\x99\xabCr6\x066\x1es,\x80e\xd0D\x17j\xd9\x0e\x1c\x8beZ}.\xac\xe2\x12\x16\xc4Z~c\xc6\xc0\x02\xad\xca\xac\x85\x88\x1a?\x13\x1d\x97\x04c1\x19EJ\x9a\xcfpF\xa2\xf2\xdf\x94C\x16!Z=Ns9\xc5\xb4$|N+\xb1\xbf\x14\xa1|\xa3zK$\x0fU$\xd4\xa7{\xb94\xd1e\x07a\xf4lv\x7f\xcd\xc4]R\x94-\xe4U\xb9\x8f\x9e\xd4U\xdf\x96;\xcb\xa4?\xb5=Q\xe7\xe0B\x1f\xe5\xc9\x92T\xd7\xa7V\xf5\x7fz3\x86\x04\x8fEq@J\x84\xf6\x98\xcb\xb8\xa2:\x82\xd7\x1bD\x0f\"\xe9<\x9a\x03F\xd1\x14P\x9a~E*\xd6\xad\x80E{\x1b-k-$E\x15\x872%h\xa4\x8d\x02\x84\xc6$B\x02W\xc98\x05\x05\xd5\x87\x05#\xd5\xbb#4J\xf2x)j\x88\xa0Q!ry\xc5\x94F\xa9\xd9;\xd2Jh\x18\xc2\x8d\xce>\xbd\xe1K\xab\xb54\x05\x15h\x95\xaa^\xab~\xb5\xbd\x16\xfbQn\xb9A\xb1\x9b\xc8\x84\xb2l)\xc5\xa1\xdc\x8d\xcd!4e\xd6]\xd8\xd5\xa7\xb1*\xe1\xd3\xf8\xa5\xab\xe7\xbf7\x9a\xeb\xf2\xf0\x96\x10@ac\x19\xdd\xffF\xcdY\xef\x10@\xd1\xeb\x9d\x92\x0e\xb7\xdb\xfd7\x19<\x9d|)\x8b\x13\xef0:\xdc\x8f\\\x19\x9a\xba\x9d\xf7M\xba\xee\x1bv\xdc\xcdn{\x98\xd3\xee\xe1\x97\x14\\\xe9\xe5\x93\x14^H\x93\x91K\xe8\xcb\x8ei\xe8\x1d\x90\xde\x01q\xda+\xf7\xeae\xd7M\xd8\xa9\x1fK\xdc\x16%\xbf\xfd\xd0\x0b\xd5\xbb\x0d\x04\xad\x97\xb2J\xdd\xaa\x90\xe1\xc3\x19\x16(F\x02\x99\xd5iM\xf0\xbcTm\xde\x15M\x1a\n6J\x94\xb9^v\xa7\xf5j\"U\xdd\x84p\x81\xa5\xa0\x934\xa8\xba\xaa\x8b\xe8\xf6;^\xcd\xc1\x8a/n\xad\xde-'~Kvz\x9d\x06]\xb7\xabZ\xa2aN\x890\x0cb\x9f\x9a\x06\xebS\x95\xceijpMV\x83\xf3\xc1J\x8f)\x97\xe06?\x9a_\xcb}]\x9d@\xea\x0dQ\x9c\x1c\xd7\xefHL\xc8\x056g\xe7\xd6\xfb\x92DWw\x16\xf43\x0bw-\xb9&\x80\xafRF\x8d\xef\x10\x97`\xd7zu\xa8i@C\xe0\xb7\x840*\x95x\xd6 \x95\xb2K\xed \x1d\xec/~W~\x18\xa3\xb6$j(n\xaeX2\x94\x14d\x88\x14\xe9(\xeam\xb1J\x00\x13\n,\x8bq&\xff\x8e?\xe7(1\x1e\xda.@\xad\x9e\x96J\x9f(\x11\xdb\xbc\x10\xff\x8ef\x07\xc5\x92>\x83\x83\xff[Mq\x81\x8d\xab\xb9\xba\xb8R\xda\xb5\xb5I\xb0\xb1f\x8d\xc5\x0d\x8c(\xc3\xea\xf1rG\x87\xd5\x04d\x17\xdb\xb2\x8bmGv\xb6\x86\n\xf7g\xf0p\x17\xc44\xe7O\xe1\x00d{9\xb5\xfd\xff\xfb\xd0\x83UQB\x10\xb7\xefb\x1f\x99\xa2\xc1!Y4x\xefx\xd7aF \xc5\x14t\xdc+!\\\x91\xb1\xd8\xeb\xe5o\xa5\xbd\xed\xbd\xdf\x8d\xdf\xd8\x02\x99MX,km{!\x89Y\x1e\x89\xe5\x1cg\xe4D\xad\xe1A\xe5\x05\xb7\x14\xfb\x88D\xda\xdb2\xad\xb4\x9b\x945\xcd\xb2,6K\x92\xd6\xf7\x99\xb2%\x8c\x9d\xe9}\xd90.\xea \xf7Lg\x15\xe8/\xe3\xe40\xcbsQ\xff\xa6\xb7\xeb\xce\"\xc2+\x7f\xa9fg\xecO\xed\xf8\xda\x9e\xdb7l\xac\x98\xf04A\x86c\xce\xf0\x19Zx\xac\x18\xa9\x8a\x97\x15j.\x9fL0\x97\xfe_!\\%\xa7U\x93uu\xa6\xa3\x96\xdavl\xbd8\xe1\x83\\e\x8f\xba9\xbf\xb5=\xb23\xb5\x9b\x03*\xa3\xb7J\xf8\xafY\xc4\x84j\x85*7Ri\x14\xb7+\x9b\x9a\xa9\xacP\xe9\x8f\xde\xfb\xa3\xf7\xfe\xe8}\xde\xf4\x03\xbd\"]m\xdd\xec-9\xaf\xfd\x01|\x1f\xffj\xfb\xfd6\xc5\xbf\xfa\x03nw\xb0\x0b\xfa\x03\xee\x02\xae\x99\xb8\xee\xa3\xd9\xfe\x80{\x13T\xec\x0f\xb8\xff:\x07\xdcKA\xf8\xe2\x1dX[~{@\x08^\x9du/\xbc\xe3\x86Oo\x8e\xb8\x7fk\x01w\x93e\xd1\xc9uq\x86\xcd\x1d:\xde\x192w\x05\xb7\xacA-\x8f`\xb9\xcb\x02\x02\x9f@\xb9\x87!\x03N\xdb}\xf9\xdb\x80\x10\xb9#(\x06\xea:\xa2o\x80\xdc'<\xee\x1b\x1c\xf7\x0d\x8d\x87Pf\xb3aqwP<($\xee\x8c\x13Bh@|\xadp\xf8\x86\x83\xe1\xddB\xe1\xeb\x07\xc2=\xc2\xe0.9\xa1\xc1#\x04\xee\xb9\x97]\x01\x05\x0d\x9b\x0d~\xdbv\xb9O\xdc\x0f6\x1d\xf6\xee\x1e\xf4v\x91\xafK\xc0\xdb\x8a\xac!\xdcm\x0ev;\xf9\xc0Ofm6\xcc\xed\x17\xe4\xb6\x86\xb8\xc3\xe6e\xe4\xa4\x0d\x06\xb7\xfdB\xdbn\xb4\xd6\x0bk[\x82\xda\xbe1\xb7\x0d\x85\xdc\xfa\x88[\x1fq\xfbf\"n\xcb:),\xa3K\xfe{=\x03j\x83Ig^9]\x81\x85\xb6\xc5J\x9d\xe9+\xd5\xd5R\xa9\xe9\xa54hz\xfemW\xde^\xc3=\xe4\x98\xc6CL\xd1(\xc1\xf1\x9f\xdd\xbf\xb3NS\x83)\"\xb2\x0c\xed\x11\x92e\xf03@\x00>b\x1a\xbf\xd2\xc8\xe9\xfa\xa0\xcd\x9d\x88\x1a\xab\x04\\ \x91\x9b+\x14\xee\\N\xb1\xaa\"\x88\xaa\xddm\xb6\xfee\xc7\xb2\xd7v+E\xab\xae\xa1/\x8f\xd8\x88\xe1\"X\x83T'\xd6\xe2\xf1\xa59\xde\xb2\xaf[\xfa\xf2\xaa\xf6]\x1fi\xd5\x16\xa8\x0e\x0e\xb4,i\xdb\x94\x8d\xba\xfe\xbd\xd2\xef\x95\xfe2\\\x83\xd2\xf7\xd2\x9fJH\xf4\x13\x9e7\x92=\xce\xf1|\xf9\x8eW\xce\xb1\xf91\xa1\x12\xde\x17Q$\xf8\xa5\xe4GsB\x8e\xba\xfa\xe0\xe6\x02'I\xdc\xcejE\x8b\n\xabOj\x93\xb4|\x1cIy@y\xce\x87*\xc8\xe7\xb3\x9b,l\xeafP\x83$(\xc19\x02x\x8d\"a\x86\xae\x86\x92c\xbc\xac\x0f'\xd1\xfd\xc8\xae\xa1 \xfe\xb6~\xe3vV\xbcI:Q\xf76\x8aG]\xf7\xb7\x1d\x98O\xda\xca\xad\xd5\xe1\xc6\xf1fYyy\x86\xc1\xbd\x033\xfe\x0d\xbd\xaa\x94T\x91\xc6U\xbd\xa4\xa5.\xc8\xf2\xf2\x19i\x1d,\xe5\xe4K\xeb\xfb\xaa\xa0\x8cn\x12\xe3\xd6\xca\xaf%l\x98m\xd0\x04\x0fi>\xd3j\xeb\xe6\xd7\xc1\xd72\xd1\xf0\x0e]\x01\x9a\xa8kf%\xa1v\xd5\xcb\xd9\ny\xdbc\xc3\x1aN\xab[ \x12\xc3<\xd1\x05\x0e#\x94Dy\x82\x84\xd6\xf0\x84\x03q\x1a\xdd\xef\xd0\xd5\xf1\x04\x97\xef)\xc1\x1e\xfc\x8e.p&QS\xa8\xb8\xf0\x10d\x86\xff0{\xe1\x8b\x95\x89\x8b\x116\xb4.\x9b\xa1\xb6\xc4\xdeM\xeb7\xd5\x1d\x8b\x88e:,\xbf\xb0VQ\x9ans\xd8\xca\xe9\x88Q\xe3\x8b^\x0bHqFX\xbc%\xf7\xa5~-\x9a\x93\x191>\xa6\xb7\x80\x19\x8e\xa6\x88\x12>S\xeb\xf0[\x81k\xba\x1a<\x84\x88\xc7\xd45\xf8\x10@C\x1f\xf8u\xf6\xd8\x07~=\xd1\xec\x03\xbf]\x03\xbfv\n\x1bR\x9d\xbc\x12$\x97\xba\xd2\xe9\x92\xa6t\xac>_RC\x9f/i\x97\xb6\xbe\x02\xe1\x18>}x\xbb\x97a\xce\xf2,*^\xfcW\xe6DN\xc9\xe7\x1c's\x90\x1e\x84 \xe3\xea\xf2\x94\xe4\\\x8b;\xa12\xdc\xab\xd7\xec\xcd[Re\x1eG,\x81Q>\x1e\xe3\xea\xf5\xecA\xe1F\xaa\xb9\xe9x]a\x1e\x012+\xd4\x04#[!\x1dF1l\xedmA4E\x19\x8a\x04\xce\x06*B\x94 .\x80\xe3\xc9\x0c/*\xa5}\xfa\xf0v\x9b/\xa7i6A!UUy0\x8f*\xbb\x1b\xe7\x89\xba|\x86\x12I\xc1\xb8Q\xbb\xabg\xa2\xba]\x14\xf3\xb08\xd7H\xda\x89\x8c\x92\x08%j\x0f\x99GV\xd5{v%ic\xb9\x14[\x83-)\xc5\xa4\xf7\x80\xa2\x08\xa7B\xc5+\xcc\xcd\xdfPH%\xb1I\x84wA`i\xe7\xe6\xa6\xf3\x01\xfc\xc0.\xf1\x85\xd4\x0bcf.#\xf5\xe9\xc3[^d\xe2\xe7\xba\x12\x93\xe5\xc6\xb1\x94\xa0\x18\xce\xa6B\xa4g\xbb\xfaO~\xb6+\xdd~\xca\x8a_\x17E\x8fX\xaaukkE\xe2\xa2C, O\x01\xa9\xb9\xdbn:g\x17:\n/\xf4\x1dk\xc5Z\ns\xc1\xaaw\xe9\xd5\xd9\x10\xd1\xca\x0f\x99\xfd\xcd1S\xd6\xc1S\xcb\xda\xfe\x1d\xde\x8c\x173\x92lQ\x94\xd2\x8e\xabI+\xdb\x87\xf3|\x86c\x8b^\xfe\xbb\xd4M?\x9c\x9e\x9e\xc0\xf7\xafN\xcb\xe0\xf9\xa7\x0fo\xf5\x1e\x9b\xab\xfb\x10\xe6\xa2P+\x0f\xed\x9f\xceS\xfc\xeb\xbf~56\x80\xb2\xd21-\xf8\xadP#j\x85\xd2\x8c\xc5y\x84\x95\xa9%U\x989\x18\xf7w8^XN\x1cP\x86\xb5E\xa5kUG(\x92\xb2\x85\xb1\xf3<\xad\xf2\xa5G\x88/U=\xac\x83\x9e\xb8\x05\xedO\x1f\xde*\x1c\xa7\xe8B\xb1\xe0\xac\xb6\x87b\xbd\x89P9%\xf9\xf7\x0bFb@\xd4\xe6\xcbh\x04\x95\xf8\xc8\xf0\x98ex\xb7\xec@\xf6\x8b\x04\x19\x91\x84\x889P\x8c\xe3\xb2\xb4\xa7\x12y\xd9\x85e&j.\xd1\x14\xd1 V\x8d\xd4\x9e\x1d\xc0\xce'\x8eK\x9fYRI\xb2\xa7\x8a>(\xfeD\x14Ml\xb3\x1fe\x18\x9dK\x19Tt<\xb8k\xe6(}\xce\xa3\xa2\xfb\xe3\x9cFz\x87\xc9y\x14\xb2+\xca\xb3L\x95\xc2\xad\xd7\xd46\x8bK\xc9\x8fL\x15\x7f5\x97\xd2.t\xd9(\x1f\x83t\xd9\x11\xc7\xbb\xca@\xd5\x05S\xe5\xa0\xaa\xe8\xac\xb2\xf6\xca}i\xecJ%yQ9Y{i3\xd9\xd3@\xf3?J \x1fDlf\x93\xc6\x1f\xd5N\xe5ET]\x1d\xd7-I)\xd8)\xae\xeb\xe8\n\xaczk\xdf5+Ae\x8d\x8e,BIW\xda\x95\xceKu\x83I\xbb <\xc5\x11\x19\x93\x088\x9e!*Hd\x88A]\xc3\xa5\x8fe\xf0\xb5\x92\xde\x15\xe7\x86H\xc7\xe2j\x06\xce\x8a\x1dS(w4b\x17f\x9e.HPl\x85\xf6\xfa\x14n\xcc\xce\x8e\xe9\xfc\xac\x16=\xa2\x80\xb2\x11\x11\x99\xdc\xc4f\x0c[\xbb*u\x04JX\xc1z\x80\xda\x97VJ\xe7\xa5Bm5\xb3p\xc9\xfc\xab\xac:\x03k\x9e\x94\x1b'!#\x85v\xf5$\x03\xcf\xd3\x94eJ\x83\xa7(:\xdf\xcb\xa9\xfcC\xeam\xcd\x17\xed;\xa8P\xf4f\xc3\x86\x8d!\x17Z\xb0\x95\xe2\x81K\xc1Z\xcbN\x9d`\x8a3\xe5yk?\x8b\x17\xd3j\xedO\xe2\xa3\x97\xb0}\xbcWWH2?\x1c<\x85\x13\x89\xbf\x94\x0b\xc5TPEtB\xe1\xc5w\xdfY\xd4\xe4k\xc6`\xcc\x18<\x83\xc1`\xf0\xef\xc6\xcf$2\x88\xce\xcd\x1f :\x1fH4^gl\xb63f\xec\xae\xf9\xd3\xc1\xc0\xac\xff\xc8\x18vdW\x9f\xd4DN\xd9\xce\xdfd_w\xe1w\x8b\x0c\xb7\xf5\xf7\x87\x9dv\x87\x0e\xda\xfd\x88.\xd0\xc6\x88\x07\xcf\x94m(G\xd9\x00\x85\x08\xdfy\xcd\xd8 J\x10\xe7\x0e\x02i\x14e#=\xc7ZC3\x0e\x06\xcaU\xa4\xbb\xef \xdd\xc9\\L\x19\xb5\x10Oc\xf5\x9a\xb1\x9d\xc1``\xd6\x06\x15\xe1v\xac\xdf(\xe6Sd\xedJU\xd9\xc9\x1bM\xd4\x97\xaf>\xbe\xf8\xf0\xe6\xe4\xf4\xfd\x87\xbb\xd6\xb3\x85\x8aQ\xed\x03\xeb\xa1\xed\xe4E\x89$\xb2}\"6\x12.caA\x81\x8c\x97\x10\xf8Dg\x0b\x14\x14\x82j\x83\xa8\xaf\xfe\xed\x19P\x92X\x19\xdc\x8e\x97\x81\x93OUy\xa4\xe8\xbc\x92\xc5\xa5\xa3\x01\xa3\xf9\xc2\xec*\xb5\x87\xaa\x19?j\xb7z\xcbR\xf297\xd8,\xdb-&\xd5\x9e\xf4\xdf\x07\xea\x07i\xaen\x03\xaai;\xa9 %'\x98t\x83\xe6\x90\xf6\xc1*\xd5B\x93y\xe9W\xae\x04\x0b*3\x19\xd0XgY\x19.\xc3!.`{o\xbb}\xa8B'\x96(+o\x17p\xc1\xd1[c\xc6\x06#\x94\xa9\xc9^\xed\xcd\x07_\xb64\x15\x95\xef\xd5\xda\x9f\xd9\x15U\xa8n\xc9>\xa4:l\xfd\xe4\xc7\x8f\xef\x7fn\xff\xe5\xd9\xb3g\xcf\xcc< \xdb-b.\xda\x8edR\x1c\x14F\x90\xf6\xeb\xd4\x99\xa7\x8e\xb3Nrc\xda\xc8j7\xb2I\x8c\x17f\xcb.\xe0\xd9\x08\xc7\xf1\xc2\x80\xd95\xa7M\"C\xf4\xa6fR\xe8\x8b\xfdg\xff%IwV\x04\x13\x1a\xe7\x8b\xe5\xe2\xb4o\x90B\xfc<\xb58 (:\x972h\xe1\x10\x8fI\x82\xcdz\xa3\x94Y'8\xe3\x8cZ\xb7m\x11\x89\x1b\x93\x8c\x8b\xa1Z\xe1gp`\xee\xb9j \x99\xb2\xfc\xfe0\\\x83\x01X\xb1\xdaR\xb4\xdcz\n[m\xbb\xb6I\x86\x81\x9e\xe5\x96\xed\xcceK\xcd\xefg4\x93}\xfe\x87\x9e\xc2\x7fZ\x1b\xc8\xf9-}\x1f:\xc97\xe3\xc2\xe1j\xf2\x9a\xe6\x06\xc2\xe1\x12'\xc9\xbds\xca.u9\x89)\xe2\x80lE\x83\xcc\x9b\xab\xc9\xf2\xbb\xda\x80_\xda\x07Zx\xd6\xd0\x91\x0clp\xae\x90f\xe9\xf6\xc1\xce\xd4f,\xf9|\xca\x92\xb8^\xb9BoeB\xab\xfd\x01:\x02\xd8\xde\x95\xde2\xed\xe3(\x14\x06\x95r\xde\x91r\xad$\xe1Jh\xa8\x8c\x98\xfe\xfa\xaf_\xefZ6\xd2&x\xae9\xa0\x9d\xed\x14\xa9d\x97\x07\x83\xc3\x83C\xbeea!\xfd\xa7\xadl\xc1\xb4~\xbd\x1e\xd6\xaf8\x00\x864\xb1\xe5J\x04\x1fqvA\xd4\x13\xf5\x96R\x04|/A\x02\xf3\xe2\x94\xcaP\x81\xe0\xad\xfa\xe4yQj@\xe4Y!\x1fu\xd32\xd7K\xb7[.5Pk{\xa7\x9c\xeb-\xad0\xa0\xe61$-\xb7\xbb\x8d\x9d\x81\xf3\xd8h\x8a\xf8\xd4\x96\xcba\x89\x958\"%)\xca\xc4\x90c1\x9cb\x14\x9b\xd2\xfd\xad\x98\x83\x13{ \x96W\xf8\xc0y X\x82O^\xa3\x99T\xe0C.p\x93\xacJ\x02:A\x99\xe0X\xfc\xa0(\xb7\xba\xdc\xfa#\xc5\xb4o^\xb6q\xc9fY\xe4z\xd7\xcf\x99\xc2ULWgf\xeb\x1cyB\xc7\xa6\xb7\x1c=p\x02/\xbc\xc0}G\x03|\xd7\x1d\xfc\x93\xcbT^\xdb\xcd\x0e\xe9\x135\xd4P\xe5\xa0A\x84R]\x1b\xaa8\"+\xfe9\xcb\x93\xe2y\x884cR&:\n+T\xeb \xd5\x05\x88h\x8a\x08\xdd\xb5\xb8\xc4\xc5\xdbU\xfa=\x8a\xa4\xd6H\xd5\x0f\x01]<_\xe1V\xf8Y\x1a+K\x87e\xf4uq>\xb3m\xa9\x10\x0c\xaa\xde0\xd6y!\xda\x18\x99\xa1hJ\xa81\x0fVa\xd7*\xb9K\xf0XRS\x81\x99\x12<\xba\xf0\x93s\x82\xcc\x9c\x17L<\x87\x89\x91\xc0\xf7d\x7f\x86/\x95\xb9o\xd6k%lpG\xdb\x858\xf8N\x10|\x84\xb9\x06/=X\x82\xd7L\xc1{\xb6\xe0\xd6\x8f\xd5g^z\xb2\x04\x1f>*\xc1Mr\x08!;\xf8\x93\xdeS\x9f.}\xdc\xaeWKP,\xab/\x15\x0co\xc2\"\x80\x05br8\xac\x0e\x16\xb4\xd4\xac\xbd\xe0\xb6\x0c\xf2\xa7\x1bBo\x91g~C\x03.\xd3c\x9c\xa9W[\x94\xfc\x06\x96\x8b4\x17\x8b\x7fK3|a\xbd\x9d\xa1^H\xbd\xf19,.\x9b\xde\xccx(Moh$\xb5?\x8a\x04\x86\x1b\x1a\xb2\xbc\xafrC\xc3U\xfc\xb70{,\xf6\xa8\x14\xd4\x8c\xe3l\x88\xe28\xc3\xdc\x95\xb8\xbe6~\x0dcN\x0b\xbc\xc6\xfd\xee\xca<\xd2\xa5dO1\x8d\xd5%\xa0\xc2O.\xac\xfd\xd6\xc3ecu6\xa7\xd6rk+q\xe5\xa4\x8c=\xcf\xde\x99e\xefE^\x0f\x02C\x90\xc5|zU$\x9f\x95\x812ed\xea\x93\x08mF\xfeW\x11\xa0\xd0\xa9\xba\xdf\x1dx\xdc\xd2Q\xe9tI\"\x89\x06S\x9ca\x95L\xa4d\xd8\x00\xe0\x9fx;\xc3\xf0[\xce\x05\xa0I\x86\xb1}\xbaE\xf6\x94~\x15P\x853\xad\xe3\xab4\xcb\x19F\xb4\x98\x95F\xfd8M\x7f@|\n1\xc3:u\xa5x]\x16Tb\xb4mM\xae\x0cY\x1c\xae\xdb\x83/\xa5\xa5\xdf\x08\x86\xab7\x94\xc7\xcdd\xed\x02\x8d\xf2QaC_&\xed`\xbfl\xbd\x01\x9e\xf7\xbd\xcd\xbd\x11\xc6w\xda\x94n|5\xc4\xb9\xf6\x92\xf0\xf0\x82 q\x0d\x8ck\xfa\x14~a\xc2\x1a!Y\x02\xf3\xba<\x85\x13e\xf0\xa0\xc4\xaf;WT\xa3 \x1d6N\x88\xa7\xaa!c9\xb5>\x89U\x870\xb7Y\x83\xed\x16J;\xb8C$M\x08\x94u\xd0A\xde\x81\xb7g\xbf\x80\x0e\xcb\x07\xbe&\xd92\x04\x85]\x9a\xd0\x81z\xd0\x91\x82\x12<\x034M\xe8\xc2w%\x84o\x89\x12B\x17\x1c\xba/:t]\xf8\xc0\xa0O\x13\xbcB@M\x10d\x86\xb9@3G\xd0~\x01\x1d\x08\xe2\x1bOm\xc2\xa22\x9c\xd3\xf7l\xc2\x1a\x18z/\xd5\x029\xcf\xdb\xba\x1a\xba\xf0}\xb8\xbc\xad\xde\xbe\x08C\xeb:)\xd6\xc5\x04\x91Z\xbd\xf9\xb2p\x9aai1\xef\x167AfD\xddb\xf1\xeaL\x7f\xae\x0cn\x1d^\xab\x15\x98\x183g\xb1\x1d\x0d5\xbb\xc5\xf5\xa9\xb2\xecG>\x0b\x10(\xafC\xe5to\xd9/Ao\xd9\xf7\x96\xbd\x1bz\xcb\xde\xf55\xf4\x96}\x98\x0e\xd4\xd0[\xf6F\x08\xdf\x12%\x84.8t_t\xe8\xba\xf0\xbde_Bo\xd9k\x08\x97\xb7\xbde\xbf\n7m\xd9+\xb18\xbc`\x82\xd0\xc9\xd0Y\x0b\xbaj\x15\xb6\x10a\xa2p\xc1\xb3\xb7\x03\x9f \xd1\xd3\x11\x13_\x91\x13\xca\x9f/\xcb\x03\"\xc9\xa4e\xc9\xc9\xc5a]\xad\xba\xa4\xa5JC \xd5\xc2\x14f5\x88K&\xfb\x1a'$R%y%\xd7:x.\x91\x86\xe80J\x08\xa6b\xa8\x8b\xb5~\xedc\xab\xda\x0cLO\x02\xacB\x00.\x10\x88\x0f\x14\xa2\x11\xc7\x81VU N\xd0\x01/p\xe4 \xb7C\x07\xc4\xa0#r\xe0\x93\xc5\xdc\x0e\xa1\xb9\xcd\xed\xd0q\xae\xb0\xc6|\xc1/;\xba\x1d\x02\x05\xd62\x94\x02\xcc\x99I\xdd\x0e\xce\xfc\xeav\xf8\x9aH\x87\x8a\xe0e\xf0\xcb\xdb\x0e\xee\xb6\x99\xe7\xbd\x94\xcd\x1d\xdc\x9bg\xf6w;\xf8\xe6\x84\x07w\xdc\xc8!\x0f\xce\x14o\x87\xd0\xfc\xf1vpg\x95\xb7CgF\x0e\x8b\xe8\x94\xd0y\xb8P\x9b\xa9\x0e\xf6\x1c\xf6v\xd8\x00\xa2\xbe&U\x13<\xb3\xe0\xdb\xe1+\xc9\xfe.\xf1\x02X\x8f\xc8\x10\xeeZ5a\x8d\xc0Q kP\x1b\xd6\xa48t\x0d(\x95\xd0\xc5\xc1^\x86\xee;\xb2\x84\xae\x8c\x03\xeb3\x0f\xac\xcb@k\x05\xa0J\xe8\x10\x88*\xc1\xff\xeeA;\xacA\xbf5\xe8\x16~{\xa1\x1d<\xee4\xb4\xc3\xd7\x98\xb6\xf7\x8d\x82v\xf8\x1a(\xbb\xb3n\xcd\xe0{\x15#\xb8c\x9f\x875\x9a\x10v\xa1\xa3\x1d\xbe\x06\xf9}\xaf\x84\xb4\xc3\xd7\xc0\xd8}\xa9\xa4\x1d\xbe\x06\xae\x01\xd7R\xda\xe1k \xedy\xb1\xa5\x1d\xbe\x06\xc2aWc\xda\xc1\xff\xc2L;\xdc\xfc\xbc\xd7\xf1\xce\x9d7t\x82z\x0b\xb8\xcd\xd3\x0e\xda\xb8\x08!yG\x8b\xb8\xab%\xfc\x0d\xf9\xa0A\xd9\x06%\xacc\xa4\x87\x9f\x86\x95\xd0;\x9f>\xd0QY[\x1c\x07\xe4h\xac\xc2\xc6\xd0\xefv\xe8\xa0!8\x1d\xaa \x1b\x9bC\xa7%X\xc7\xef\xd2\xf0B\xb9;\x1f\xc9DgpK\x1b\xad<\xe2S\x19V\xe5\x05\xf2\x0e]\xab\xd7fu\xff\xfe\xee\xd7zs\xd2\xa35\xaf\xc5W\xd96\xea\xba~\x987\xa9]\xc8K\xc4k\x8f\xe8\x8e\xe6\x80\x8a\xbb\xf6A}-\x02r~\xd4X\xc8\x08\x8e\xbd\xdd\xbd\x0ez\xbf\x8b\xb6_\xcc\xc5\xbfMW+\xa8\x83\x05\xd4\x81\n\x1a\xba\xd0BCg9\xbe\x96\x00YCx\x14o\x05wE\xb8\x03qa-\x02K\xc0\xf1\xe1\x83\x07\x07O\xba4]\x93\xd0\xb0\x1e\xb1A=6\x15\xa5\x87\x0f\x1e\x9e\x1f|\x8b\xe8\xafc\x91\x9d\xa8\x17\x9b\x7f\xc2\xf3F\x8c\xef\x1c\xcfy\xed-\xa1nvT\xce\xb1~t\xe5}Q6w\xf1vth\x9eKh2n\x13\xd6Z\x9du\xbc\xfa*V\x9cf\x84eDt\xde\xd07\x8a{\x89u\x08\xb2\x1d\xe5NW\x89\xd3Q\xa0\xafA\xcc\xce\x1b\xb4\xa3(\xefHPX\x83\xa8\xb0\x9e\x10_\x83\xb8\xb0\x0e\x81a]\xf1\xfd\xf5\x10\xef.\xb8\xafMloLh\xaf#\xb2\xd7X\x91n\"\x0f6!\xaco\x1c\xebn\x17UJ\xe8\x88n\x18\xaa\xd23ct\xe8\x7f,\x16\x88U\x186\xa3\xf9\x17D\x05\xa1x\x18\xe6#\x85\xf9F\x01>Q\xb0\x94\x0f\x97\xed\xc1\xaa2p\x054t\x10\x82\xc1\x8a1\x98X\xd0\x89`\xd0U\x0dv\"\x1ct#\x1etWz7\x8bf\x17\x15w\x0d\xcam\x03j\xad\x9b\x9c\xedD\xed0\xa9\xa6a\x0d\xf5u\x038vSU\x81\x88\x05\xa2\x14\x12\x1f\xef\x88\x89o\xec;4\xac\xfaV\xaa\xd3\x17\xea\xc6\xe0\xb1\xba0\xb8\xee=\xc6\xa2\xf1\x9a)x\xcf\x16\xc0;w\xc4o=K\xf0a\xa0\x12\xdc$\x87\x10\xb2\x83?\xe9\x03\xf36\xbc24|r1|lj\xa7%\xed\xc9\n\xbe\x8c\x10\x94\x1d\x11\xb0\x18~\x19\x0f]s\x1b:f1t\xccW\x08\xcfLX+\x07\xc1\xdf~\xdcT^AP\x06Ap\xae@\x00\xd7\x04l`OK\xa6\xc3\xe0~\x16\x8c\xf79}\x07\x0c\x1c\xd3\x0f1\x9d|\xcf\xd3\xd5\xe9\xb8GO\xedg\xc5~\x18y\x9c\x86\x1bN\xb8\x0d\x1d\xa2U#\xae\x89\x9f\x1d\xaf\xe6c\x83\x1f\x8aw\x02%\xa1\xf4\xdb\xb3\xc5\x7f\xcb\x05\x94K\xd3\xb2\x95\xfe\x91\xe3l\xbe\xb7\xf4\xe0\xe1\x87\x93\x17\xc5\xbb\xc0\x0bdJ\x81Pk\xdf|\xb1\x90BN\xf1U\x8a#9a\x9ce,\xab\x10\xa8\xb5\xd9\xd0\xbb\x85\xaa\xffU\xbe\xb5pj\xc4\xe2\x16F\xb7\x1b\x076#\xaf(\xb1\x17\x84C\x8c\x05\"I\x8b\xb8\xb1\xe9U\xa3>u\xe8Q\x97\xfe\x94\xcd\x87yf\xb4\xa0\x92ly\x8d8c\x82E,\x81Q>\x1e\xe3\xeaQ\xd6\x81~sB\xcf\x0df9\xaf\xb64 \xb3I\x92`\xc4\x85y,F1l\xedmA4E\x19\x8a\x04\xce\x06\xea\xbdh\xf5$6\xc7\x93\x19\xa6\x95\xdc\xfa\xf4\xe1\xed6_~\x0f\xb5 \n\xa9\xaa\x18\x93yT\xd1\xf2Z\xb7\xa2o1\x94\xa2\xe4\x0e\xe2@\x0c\x8fCK8\x93\xa8\x18\xdf\x8d=\xbb\xabg\xa2\xba\xe5S\x96'1\x8c\xa4\xdc5\xf6\x87 B\x94Q\x12\xa1D\xed!\xf3\xc8;x0\x19\xecJ\xd2\xaa:\x0b[\x83-)\xbc\xd4[$Q\x84S\x81\xe3\xbb\x03\xc3\x03\xde\x12\xdePH%\xb1I\x84wA`4\xe3\x90\xf3\x1cIr\xe8\x92U)I$\xa6\xfaa_\x18\x11\x8a2\xb3\xe5\xaa\x9e?\x99\xa7\xb8x\x87DL\xf1\xdc<\xb4\x16u@\x84\xf4\xb4s^\xaf\xb5)\xf0\x95Z\xeac:\x1f\xc0\x0f\xec\x12_\xe0l\xd7j\x95|\xfa\xf0\xb6\xb4z\x8a'\xd8\xcd\x03+ \x8a\xe1l*Dz\xb6\xab\xff\xe4g\xbb\xc02\xa0\xac\xf8uWqc\x84(\xb0T\xbf\xfc\x9d\x98\xa7-5P\x9e\x16\xc5F-\xe3\xe2\xecB=\xfd\x8e\x04\xccP\xca5k)\xcc\x05\xab*\x8e\xaa\xe0\x1f\xd1O\xa5 s\x94n\xcc\x92\x84]\xf2\xa7\x96\xb5\xfd;\xbc\x19/f$\xd9\xa2|q\xbf\x9a\xb4\xb2\x088\xcfg8\xb6T6\xfd\xbb\xd4M?\x9c\x9e\x9e\xc0\xf7\xafN\xcb\xc7i>}x\xab\xf7\x98z^\xdeb8\xac\xbc\xdf|:O\xf1\xaf\xff\xfa\xd5\xd8\x00\x8a'\xe0 -\xf8\xadP#j\x85\xd2\x8c\xc5y\x84\x01Q\xad\xc2\xcc\x89k\x7f\x87\xe3EA\x10\xae^\xe3A\x92f8\x96\xe4\x8eP$e\x0bc\xe7y\n\xc5\x15D\x18!nI+d\xae\n*\xeaI~\x96\xc1\x14](\x16\x9c\xd5\xf6P\xac7\x11*\xa7$\xff~\xc1H\x0c\x88\xdaNW4\x82J|dx\xcc2\xbc[v \xfbE\x82\x8cHB\xc4\x1c(\xc6\xb1b\xa3\x91\xba\xd2\xabX\xcd\x96 \xc9\xa8\x14\xb3t\x82U#\xb5g\x07\xb0\xf3\x89\xe3\xb2f\x92\xa4\x92dO)\xb34\x7f\"\x8a&\xb6\xd9\x8f2\x8c\xce\xa5\x0c*:\x1e\xdc5s\xd4\xcfL\xe0\xa7 \xa4\x0e\x19\xe74\xd2;L\xce\xa3\x90]Q\x9ee\x98\x8ad^\x0b}[\xc4\xa5z,i<&\x11A\x89C\x97\x8d\xf21dXj\"\xbc\xab\xca\xc8\x10Q\x0e\x9as\x1ck#\xaf\xdc\x97\xc6\xaeFxB(\x95\x93\xbd$bjQ.\xab\xaf\x8b\xdb\xa4\xf1G\xb5S901\xd5\x82\x82.K)\xd8\xd1F(\xe0Y*\xe6\xc5\xd6\xbekV\x82d2\x150\xb2\x08%5iuF@fi\x82g\xd5\x1b\xf2<\xc5\x11\x19\x93\x088\x9e!*Hd\xc8\x11U{u\x0d\x13\xc8\xc3\xe1\xf1\xb5\x92\xdeIq4\xc2\x80\xb43P3pV\xec\x98\xb2d\xd0\x88]\x98y\xba A\xb1\x15Z__\xf3\xc0\xec\xec\x98\xce\xcf\x16\x1e\x0f\xa2\x80\xb2\x11\x11\x99\xdc\xc4f\x0c[\xbb*u\x04JX\xc1z\x80\xda\x97VJg\xa5h4\x86\xa3\xa6Y\xb8d\xfeUV\x9d\x815O\xca\x8d\x93\x90\x91B\xbb\xd0#\x1cx\x9e\xa6,S\x1a\xde\xab+$\x99\x1f\x0e\x9e\xc2\x89\xc4_\xca\x85b*\xa8^\n\xfc\xc5w\xdfY\xd4\xe4k\xc6`\xcc\x18<\x83\xc1`\xf0\xef\xc6\xcf$2\x88\xce\xcd\x1f :\x1fH4^gl\xb63f\xec\xae\xf9\xd3\xc1\xc0\xac\xff\xc8\x18vdW\x9f\xd4DN\xd9\xce\xdfd_w\xe1w\x8b\x0c\xb7\xf5\xf7\x87\x9dv\x87\x0e\xda\xfd\x88.\xd0\xc6\x88\x07\xcf\x94m(G\xd9\x00\x85\x08\xdfy\xcd\xd8 J\x10\xe7\x0e\x02i\x14e#=\xc7ZC3\x0e\x06\xcaU\xa4\xbb\xef \xdd\xc9\\L\x19\xb5\x10Oc\xf5\x9a\xb1\x9d\xc1``\xd6\x06\x15\xe1v\xac\xdf(\xe6Sd\xedJU\xd9\xc9\x1bM\xd4\x97\xaf>\xbe\xf8\xf0\xe6\xe4\xf4\xfd\x87\xbb\xb6(\xd9\x82Q\xed\x03\xeb\xa1\xed\xe4\xd1\xd9\x02\x05\x85\xa0\xda \xea\xab\x7f{\x06\x94$V\x06\xb7\xe3e\xe0d\xe9\xdc*:\x97\xb2\xb8t4`4_\x98]\xa5\xf6\xd0\x8fn\xb6[\xbdE\x90L\x9a%\xedCm\xb7\x98T{\xd2\x7f\x1f\xa8\x1f\xa4\xb9\xba\x0d\xa8\xa6\xed\xa4&,\xca\x05\xb6v\xa89\xa4}\xb0J\xb5\xd0d^\xfa\x95+\xc1\x82\xcaL\x064\x16\xb8-D\xa8A\xc51\xb6\xf7\xb6\xdb\x87*tb\x89\xb2\xf2v\x01\x17\x1c\xbd5fl0B\x99\x9a\xec\xd5\xde|\xf0eKSQ\xf9^\xad\xfd\x99]Q\x85\xea\x96\xecC\xaa\xc3\xd6O~\xfc\xf8\xfe\xe7\xf6_\x9e={\xf6\xcc\xcc\x03\xb2\xdd\"\xe6\xa2\xedH&\xc5Aa\x04i\xbf.\xe7\xb8\x0c\xafN\xf2\x04\x19JY\xafv#\x9b\xc4xa\xb6\xec\x02\x9e\x8dp\x1c/\x0c\x98]m\x8e\xb7u\x87\x0c\xd1\x9b\x9aI1V\x8e\xec\xd9\x7fI\xd2\x9d\x15\xc1\x84F\xa0\xba\\\x9c\xf6\x0dR\x88\x9f\xa7\x16\x07\x04E\xe7R\x06-\x1c\xe21I\xb0Yo\x942\xeb\x04g\x9cQ\xeb\xb6-\"q\xea\xad\xd8\xa1Z\xe1gp`\xee\xb9j\xa0\xf2\x12\x8a\xef\x0f\xc35\x18\x80\x15\xab-E\xcb\xad\xa7\xb0\xd5\xb6k\x9bd\x18\xe8Yn\xed\xda\xfaS\xf3\xfb\x19\xcdd\x9f\xff\xa1\xa7\xf0\x9f\xd6\x06r~K\xdf\x87N\xf2\xcd\xb8p\xb8\x9a\xbc\xa6\xb9\x81p\xb8\xc4Ir\xef\x9c\xb2K\xaa\xe4\xcc\x14q@\x10\xe5\\\xb0Y\xe0\xe6j\xb2\xfc\xae6\xe0\x97\xf6A\xf9bq\x85\x8ed`\x83s\x854K\xb7\x0fv\xa66c\xc9\xe7S\x96\xc4E\xf9Y\x85\xb9\xde\xca\x84V\xfb\x03t\x04\xb0\xbd+\xbde\xda\xc7Q(\x0c*\xe5\xbc#\xe5ZI\xc2\x95\xd0P\x191\xfd\xf5_\xbf\xde\xb5l\xa4M\xf0\\s@;\xdb)R\xc9.\x0f\x06\x87\x07\x87|\xcb\xc2B\xfaO\x81&\xb5C\x83{\xf0\x11g\x17$\x92\xd4\xdb\xdeKF\xb3\xbd\x11\xe2x\x8f\x15Iy{\x17\x07{\xea\xcc\x8b\xef\xfd>E|\xfa\xc7\xb6n:Y\xdc\xb1\xe4\xf9l\x86\xb2\xf9S\xf8\x1e\xeb\x13\xa6\xe7s\xf5\xb6\xf3\xe7\x1cg\x04\xf3\xe2\xc8L\x92vB.0U\x89\x15\xa5\x94b)\xd6s|\x13/\xb7/\xbe(O\x99j(o\x1f\xee\xefo\x9b\x8f\xaa\x80\xe7Q\x849\x1f\xe7I\xd5\xba.\x157tHe\xce\xff1v\x06\xce\x83\x1bs\xd2\x893Z\xe1\x88Ux\xe5\xf3X1\x07'\xf6\xe0\xce\xdb\x11^\xf9:>y:7\xf1t\xbfW\x1e\x8e5\xff\xc6P\xf1|\x1d\x16\xb9\xde\xf5s\x96\xa5\x0f-@\xef\xc4 \xbc\xf0\x02\xbf\xf2\xf1^\xeb\x0e\xb5\xb5wVWw\x16\x7f\xdf\xf4\x90>q;\x0d~E\xda\xa1Yt\xdd6\xd5F9v\xdf\xf2\xea\xbe\x85\xd4\x9b\x85\xd1-\x1d\x86\x96L\x0f-\x8e\xee.\x83\xee\xb1\xa47\x96\xd0j/L\x1e4\x8c+s\xc8\xb3\xac\xf8\x06w\xb4;\xc9\xd2k\x82\xe0#\xcc5x\xe9\xc1\x12\xbcf\n\xde\xb3\x05\xb7~\xac>\xf3\xd2\x93%\xf8\xf0Q n\x92C\x08\xd9\xc1\x9f\xf4\x9e\xfat\xe9c{^\xab\x7f\x81k\xaf\x19y\xcd$\xbc<\xb5G!\xeaM\xa1\xe7]\xc7xS\x03.\xd3\xc3Y\xd1\xd9Z\xa19\xac\x16\xf3\xa6\xe6\xe0[IyS\xe3\xb9\xeb oj\xa4\x80*\xc6\x9b\x1a\xd2\xb3\x06\xf1\xa6\x86\x0b\xab \xec_+x3\xf85\x8c9g\xe9\xde\x90r\xbcR\xa6\\\x9b\x17 \xae\x9c\x94\xd9\xc8=\x01\xa7\x82q\x12\x18\x82,\xe6\xd3\xab\"\xfd\xab\x0cU)#S\x9f\x05h3\xf2\xbf4\xe1\x07?(\xfb\xee\xbb\x03\xeb\xa3\xca?\xab\x07\x93UB[\x92H\xa2\xc1\x14gX\xa5\xf3(\x196\x00\xf8'\xde\xce0\xfc\x96s\x01h\x92al\x9fn\x91\xbf\xc42\xc9'*\xa0h\x1d_%:\xce0\xa2\xc5\xac4\xea\xc7i\xaa\x0201\xc3:y\xa4H\xa2\x96]s\x9b\x82\x16W\x86<\nW\xca\xffKi\xe97\xc2\xd1E\xe2\xb32\xcaQqH^\xcf\xe56'+\x99\xb4\x83\xfd\xfd\xbd\x0d\xf0\xbc\xfb\x81\xbf\x0d2\xbe\xd3\xa6t\xe3\xab!.\xdfN\x1c\xaa\xe7\xef\xdd\x93\xd0\xe0\x89\x05\x04`\x02\xe5\x13\xfc\x06\xb1\xd4\x84\x00\x04 \x10 (\xbb\xf7\xfa\xd2[\x14\xd5\xc1\xef\xfaP \xfd\x13\xfc\x05\xf4O\xf0\xd7\xa0\x7f\x82\xdf\xabMPQ\xfc0\xb7Y\x83\xed\x1eH;\xb8C$M\x08\x94u\xd0A\xde\x81\xb7g\xbf\x80\x0e\xcb\x07\xbe&\xd92\x04\x85]\x9a\xd0\x81z\xd0\x91\x82\x12<\x034M\xe8\xc2w%\x84o\x89\x12B\x17\x1c\xba/:t]\xf8\xc0\xa0O\x13\xbcB@M\xf0\xbeyYB\x07\x82\xf8\xc6S\x9b\x10|1\xb5\x8450\xf4^\xaa\xfe \xfe0\x8au1A\xbe\xe9'\xf8\x95e?\xf2Y\x80@y\x1d*\xa7{\xcb~ z\xcb\xbe\xb7\xec\xdd\xd0[\xf6\xae\xaf\xa1\xb7\xec\xc3t\xa0\x86\xde\xb27B\xf8\x96(!t\xc1\xa1\xfb\xa2C\xd7\x85\xef-\xfb\x12z\xcb^C\xb8\xbc\xed-\xfbU\xb8i\xcb\xfe\x16\x16\x82\\\xf0\xec\xed\xc0'H\xf4t\xc4\xc4W\xe4\x84\xf2\xe7\xcb\xf2\x80H2\xe9\xbaE)\xab\x85)\xccj\x10\x97L\xf65NH\xa4\nSJ\xaeu\xf0\x9c*W9\xd4\xe5(\x87H\xd5\xca\xfc\xda\xc7V\xb5\x19\x0c=\x92L5\x04\xe0\x02\x81\xf8@!\x1aq\x1chU\x05\xe2\x04\x1d\xf0\x02G\x0er;t@\x0c:\"\x07>Y\xcc\xed\x10\x9a\xdb\xdc\x0e\x1d\xe7\nk\xcc\x17\xfc\xb2\xa3\xdb!P`-C)\xc0\x9c\x99\xd4\xed\xe0\xcc\xafn\x87\xaf\x89t\xa8\x08^\x06\xbf\xbc\xed\xe0n\x9by\xdeK\xd9\xdc\xc1\xbdyf\x7f\xb7\x83oNxp\xc7\x8d\x1c\xf2\xe0L\xf1v\x08\xcd\x1fo\x07wVy;tf\xe4\xb0\x88N \x9d\x87\x0b\xb5\x99\xea`\xcfao\x87\x0d \xeakR5\xc13\x0b\xbe\x1d\xbe\x92\xec\xef\x12/\x80\xf5\x88\x0c\xe1\xaeU\x13\xd6\x08\x1c\x95\xb0\x06\xb5aM\x8aC\xd7\x80R ]\x1c\xece\xe8\xbe#K\xe8\xca8\xb0>\xf3\xc0\xba\x0c\xb4V\x00\xaa\x84\x0e\x81\xa8\x12\xfc\xef\x1e\xb4\xc3\x1a\xf4[\x83n\xe1\xb7\x17\xda\xc1\xe3NC;|\x8di{\xdf(h\x87\xaf\x81\xb2;\xeb\xd6\x0c\xbeW1\x82;\xb6]\xddh\x87\xb0\x0b\x1d\xed\xf05\xc8\xef{%\xa4\x1d\xbe\x06\xc6\xeeK%\xed\xf05p\x0d\xb8\x96\xd2\x0e_\x03i\xcf\x8b-\xed\xf05\x10\x0e\xbb\x1a\xd3\x0e\xfe\x17f\xda\xe1\xe6\xe7\xbd\x8ew\xee\xbc\xa1\x13\xd4[\xc0m\x9ev\xb0=\xca\xd3\x0e\x1d-\xe2\xae\x96\xf07\xe4\x83\x06e\x1b\x94\xb0\x8e\x91\x1e~\x1aVB\xef|\xfa@G\xf1\xa0\xa1w>;\xf3u \xdd\xb7b ]\x19\x07\xd6g\x1eX\x97\x81\xbe\xb6\xf3\xe9\xf3\xa0S;h\xca\xf9>\x9dZ\x07\xe7\xdd\xb6vXk\xa3\xac\xb7M\x82\x9e\x8fj\x87\xb5\x19-,\xa3\xb4 ]\x1f\xa0j\x87\x8e\xcfR\xb5C\xc7\xc7\xaa\xda!\xfc \xabvX\xeba\xabv\xe8\xee\x85k\xd8\xd4#X\xed\x10\xf44V;t\xce^j\xc2\xda\xfbdmq\x1c\x90\xa3\xb1\n\x1bC\xbf\xdb\xa1\x83\x86\xe0t\xa8&ll\x0e\x9d\x96`\x1d\xbfK\x83\xefc`\x1d\xba&\x14\x90\xf5\x89\xb0vXgN\x1e\xcf\x89\x05\xf5\xd7\xfe\xf4X\xf5\xc8XP_\xa6\x07\xc9L\xb0\x90\x11\x1c{\xbb{\x1d\xf4~\x17m\x1f\xf6p| \xdd\xac\xa0\x0e\x16P\x07*h\xe8B\x0b\x0d\x9d\xe5\xf8Z\x02d\x0d\xe1\x11\xfc\xf0| \x9d\x89\x0bk\x11\x18\xba>H_\xc2Z\x84\x86\xf5\x88\x0d\xdd\x1f\xaa/\xe1\xeb\xa2\xbf\x8eEv\x0d\x0f\xd9\x97\xb0\x81\x07\xedK\x08M\xc6m\xc2Z\xab\xb3\x8eW\x9fv\x7f\xf0\xbe\x84\xaf\x80{\x89u\x08\xb2\x1d\xe5NW\x89\xd3Q\xa0\xafA\xcc\xce\x1b\xb4\xa3(\xefHPX\x83\xa8\xb0\x9e\x10_\x83\xb8\xb0\x0e\x81a]\xf1\xfd\xf5\x10\xef.\xb8\xafMloLh\xaf#\xb2\xd7X\x91n\"\x0f6!\xaco\x1c\xebn\x17UJ\xe8\x88n\x18\xaa\xd23ct\xe8\x7f,\x16\x88U\x186\xa3\xf9\x17D\x05\xa1x\x18\xe6#\x85\xf9F\x01>Q\xb0\x94\x0f\x97\xed\xc1\xaa2p\x054t\x10\x82\xc1\x8a1\x98X\xd0\x89`\xd0U\x0dv\"\x1ct#\x1etWz7\x8bf\x17\x15w\x0d\xcam\x03j\xad\x9b\x9c\xedD\xed0\xa9\xa6a\x0d\xf5u\x038vSU\x81\x88\x05\xa2\x14\x12\x1f\xef\x88\x89o\xec;4\xac\xfaV\xaa\xd3\x17\xea\xc6\xe0\xb1\xba0\xb8\xee=\xc6\xa2\xf1\x9a)x\xcf\x16\xc0;w\xc4o=K\xf0a\xa0\x12\xdc$\x87\x10\xb2\x83?\xe9\x03\xf36\xbc24|r1|lj\xa7%\xed\xc9\n\xbe\x8c\x10\x94\x1d\x11\xb0\x18~\x19\x0f]s\x1b:f1t\xccW\x08\xcfLX+\x07\xc1\xdf~\xdcT^AP\x06Ap\xae@\x00\xd7\x04l`OK\xa6\xc3\xe0~\x16\x8c\xf79}\x07\x0c\x1c\xd3\x0f1\x9d|\xcf\xd3\xd5\xe9\xb8GO\xedg\xc5~\x18y\x9c\x86\x1bN\xb8\x0d\x1d\xa2U#\xae\x89\x9f\x1d\xaf\xe6c\x83\x1f\x8aw\x02%\xa1\xf4\xeb\xaf\xc5\x7f\xcb\x05\x94K\xd3\xb2\x95\xfe\x91\xe3l\xbe\xb7\xf4\xe8\xe1\x87\x93\x17\xc5\xcb\xbc\x0bdJ\x81Pk\xdf|\xb1\x90BN\xf1U\x8a#9a\x9ce,\xab\x10\xa8\xb5\xd9\xd0\xbb\x85\xaa\xffU\xbe\xb5pj\xc4\xe2\x16F\xb7\x1b\x076#\xaf(\xb1\x17\x84C\x8c\x05\"I\x8b\xb8\xb1\xe9U\xa3>u\xe8Q\x97\xfe\x94\xcd\x87yf\xb4\xa0Sly\x0f8c\x82E,\x81Q>\x1e\xe3\xeaY\xd4\x81~sB\xcf\x0df9\xaf\xb64 \xb3I\x92`\xc4\x85y,F1l\xedmA4E\x19\x8a\x04\xce\x06\xea\xc5f\xf5(5\xc7\x93\x19\xa6\x95\xdc\xfa\xf4\xe1\xed6\x87\x14\x19^R\x96\xa0\x90\xaa\x8a1\x99G\x15-\xefe+\xfa\x16C)J\xee \x0e\xc4\xf0<\xb3\x843\x89\x8a\xf1\xe5\xd6\xb3\xbbz&\xaa[>ey\x12\xc3H\xca]c\x7f\x08\"D\x19%\x11J\xd4\x1e2\x8f\xbc\x83\x07\x93\xc1\xae$\xad\xaa\xb3\xb05\xd8\x92\xc2K\xbdE\x12E8\x158\xbe;0<\xa1-\xe1\x0d\x85T\x12\x9bDx\x17\x04F3\x0e9\xcf\x91$\x87.Y\x95\x92Db\xaa\x9f\xd6\x85\x11\xa1(3[\xae\xea\xf9\x93y\x8a\x8bwH\xc4\x14\xcf\xcdCkQ\x07DHO;\xe7\xf5Z\x9b\x02_\xa9\xa5>\xa6\xf3\x01\xfc\xc0.\xf1\x05\xcev\xadV\xc9\xa7\x0foK\xab\xa7x\x04\xdd<\xb0\x92\xa0\x18\xce\xa6B\xa4g\xbb\xfaO~\xb6\x0b,\x03\xca\x8a_w\x157F\x88\x02K\xf5\xdb\xdb\x89y\xdaR\x03\xe5iQl\xd42.\xce.\xd4\xe3\xebH\xc0\x0c\xa5\\\xb3\x96\xc2\\\xb0\xaa\xe2\xa8\n\xfe\x11\xfdT\n2G\xe9\xc6,I\xd8%\x7fjY\xdb\xbf\xc3\x9b\xf1bF\x92-\xca7\xef\xabI+\x8b\x80\xf3|\x86cKe\xd3\xbfK\xdd\xf4\xc3\xe9\xe9 |\xff\xea\xb4|\x9c\xe6\xd3\x87\xb7z\x8f\xa9\x07\xde-\x86\xc3\xca\x0b\xca\xa7\xf3\x14\xff\xfa\xaf_\x8d\x0d\xa0x\x84\x9d\xd0\x82\xdf\n5\xa2V(\xcdX\x9cG\x18\x10\xd5*\xcc\x9c\xb8\xf6w8^\x14\x04\xe1\xea5\x1e$i\x86cI\xee\x08ER\xb60v\x9e\xa7P\\A\x84\x11\xe2\x96\xb4B\xe6\xaa\xa0\xa2\x1e\xc5g\x19L\xd1\x85b\xc1Ym\x0f\xc5z\x13\xa1rJ\xf2\xef\x17\x8c\xc4\x80\xa8\xedtE#\xa8\xc4G\x86\xc7,\xc3\xbbe\x07\xb2_$\xc8\x88$D\xcc\x81b\x1c+6\x1a\xa9+\xbd\x8a\xd5l \x92\x8cJ1K'X5R{v\x00;\x9f8.k&I*I\xf6\x942K\xf3'\xa2hb\x9b\xfd(\xc3\xe8\\\xca\xa0\xa2\xe3\xc1]3G\xfd\xcc\x04~\nB\xea\x90qN#\xbd\xc3\xe4<\n\xd9\x15\xe5Y\x86\xa9H\xe6\xb5\xd0\xb7E\\\xaa\xc7\x92\xc6c\x12\x11\x948t\xd9(\x1fC\x86\xa5&\xc2\xbb\xaa\x8c\x0c\x11\xe5\xa09\xc7\xb16\xf2\xca}i\xecj\x84'\x84R9Y\xf5\x9a\xbf\x19\xb1\xd5\xf7\xbdm\xd2\xf8\xa3\xda\xa9\x1c\x98\x98jAA\x97\xa5\x14\xech#\x14\xf0,\x15\xf3bk\xdf5+A2\x99\n\x18Y\x84\x92\x9a\xb4:# \xb34\xc1\xb3\xea\x15w\x9e\xe2\x88\x8cI\x04\x1c\xcf\x10\x15$2\xe4\x88\xaa\xbd\xba\x86 \xe4\xe1\xf0\xf8ZI\xef\xa48\x1aa@\xda\x19\xa8\x198+vLY2h\xc4.\xcc<]\x90\xa0\xd8\n\xad\xaf\xafy`vvL\xe7g\x0b\x8f\x07Q@\xd9\x88\x88Lnb3\x86\xad]\x95:\x02%\xac`=@\xedK+\xa5\xb3R4\x1a\xc3Q\xd3,\\2\xff*\xab\xce\xc0\x9a'\xe5\xc6I\xc8H\xa1]\xe8\x11\x0eX\xa5Zh2/\xfd\xca\x95`Ae&\x03\x1a\x0b\xdc\x16\"\xd4\xa0\xe2\x18\xdb{\xdb\xedC\x15:\xb1DYy\xbb\x80\x0b\x8e\xde\x1a36\x18\xa1LM\xf6jo>\xf8\xb2\xa5\xa9\xa8|\xaf\xd6\xfe\xcc\xae\xa8BuK\xf6!\xd5a\xeb'?~|\xffs\xfb/\xcf\x9e={f\xe6\x01\xd9n\x11s\xd1v$\x93\xe2\xa00\x82\xb4_\x97s\\\x86W'y\x82\x0c\xa5\xacW\xbb\x91Mb\xbc0[v\x01\xcfF8\x8e\x17\x06\xcc\xae6\xc7\xdb\xbaC\x86\xe8M\xcd\xa4\x18+G\xf6\xec\xbf$\xe9\xce\x8a`B#P].N\xfb\x06)\xc4\xcfS\x8b\x03\x82\xa2s)\x83\x16\x0e\xf1\x98$\xd8\xac7J\x99u\x823\xce\xa8u\xdb\x16\x918\xf5V\xecP\xad\xf0380\xf7\\5Py \xc5\xf7\x87\xe1\x1a\x0c\xc0\x8a\xd5\x96\xa2\xe5\xd6S\xd8j\xdb\xb5M2\x0c\xf4,\xb7vm\xfd\xa9\xf9\xfd\x8cf\xb2\xcf\xff\xd0S\xf8Ok\x039\xbf\xa5\xefC'\xf9f\\8\\M^\xd3\xdc@8\\\xe2$\xb9wN\xd9%Urf\x8a8 \x88r.\xd8,ps5Y~W\x1b\xf0K\xfb\xa0|\xb1\xb8BG2\xb0\xc1\xb9B\x9a\xa5\xdb\x07;S\x9b\xb1\xe4\xf3)K\xe2\xa2\xfc\xac\xc2\\oeB\xab\xfd\x01:\x02\xd8\xde\x95\xde2\xed\xe3(\x14\x06\x95r\xde\x91r\xad$\xe1Jh\xa8\x8c\x98\xfe\xfa\xaf_\xefZ6\xd2&x\xae9\xa0\x9d\xed\x14\xa9d\x97\x07\x83\xc3\x83C\xbeea!\xfdg\x8a24\xc3\x02\xd7\x13m\xef)\xc9\xabK\xee\xd5: \xf4\xe9r ;\xc3\x9f\xff?\xf6\xfe\xadIn#\xd9\x12\x85\xdf\xf9+\xfc\xd3wlH\xcd\x14\xabZ\xbdg^8GcC\x91Tw\xcd\xa8I\x0e/j\xdb6\xb6-\x85\xca\x8c\xaaB\x13 d\x03\xc8\xbal\xed\xfe\xef\xc7\xe2\x06\x04\x90q\xf1\x08D\x16\xab%\xf7\x87n\xaa\x12pD8\x02q[\xcbW\xec\xcb\x96m^@\xdf\xee\xcd\x90;\x96\xd3\x96%t_\\M\x1e\xfd\x91\xb57\xe5\x9a\xff\xfa\xf4\xac\xba\xd8\x9e]\x14\x1d;k\x14+\xf0\xec\xe6\xbb3\x01\xbaug\xbfJ\x12\xd1?\x9e\xca\x9b\xaf\xc64\xcfn\xbf\xdd\x16\xed\xfd\x0b\x132\x13\xd7\xc2\xdf\xf7\xac-Y\xa7p;\xfe~\xaf\xca\x1bV+>\x92\xee,\x9b\x1d\x93\xa1>\xdf\x1c\xfax\xa2+.\xe1.\xa3\xe8O\xff\xf8\x87?\x9c\x98\x95\xaa\xb4(u\xfe\xb8e\xb34_B\x8a\xdd\xc2[$S\x8b\xec\xeb \xa1\xbf\x03\xf4\xca~\xb4\x84\xd7\x07\xd8)\xd9\xdc\xa2\xb6]\xa6\x96\x10=H\x8c 7\xe4\x06\xcd\xd4R\xda\x9d\xb6\xf8OB[\xec\x0b\x87\xf4\x97\x0e\xa9/>r\xd3gj\xa8-\xa0\xa9\xa1S@\xb5%\x04\x04\xbb\x9f:\xb5\xe8\x0cYm\x0bJ\x88~Uc\xe1\xcaz\xc3\xee\xe2\x8a\x16\xd7\xee\xe3\xfb[tR\xad\xb6\xe3G,e\n\"2k\x07\xee\x86\xc8\xbbm\x19\x9f1\x9f\xa8\xa4\x90m)\x12ZP\xce\xe4\xe5b\xc2-\xb7\xd7\x0c\xc5\x92\xcb\xc6A\xa0\x9a\x9b1o ]*f\xf6\x17\x98\x17\x10\xd9_\xc7\xf6\xd34\xb3\x9f\x19\xcd\xecif\x1f6\x9a\xd9\x87\xae\x06\x9a\xd9\xc7\x8d\x81\xd2hf\xef\xb4\xf8OB[\xec\x0b\x87\xf4\x97\x0e\xa9/\x9ef\xf6\xdahf/-\xbe\xbf\xa5\x99\xfd\xa1=\xf4\xcc\xfe\x11*R\x8em\xf6q\x94'\xaa\xebI, \xb6\xcb\x89m\x9f\xaf5@\xc4\x1b\xe9Ru\xcc\xe1\xc5\xa8i5\xf4\xb7\x0d\xf7uY\x95k\xa1\x90\xc9[m\xa0\xcd \xdd\xcc\x95\xd4\xc5\\\x15B\xb4\xf3k\xc3VF\x0dV\x08\x92\xa9\xb4\x88\xb2@dy@u\x8dl\x139\xab\x8a,\x13$\x94\x0b\x02\x1cd\xbb%\x14\x0c\x12\x0b\x07\x18\x16\xb3\xddb\xb9\xcdvK\xac+,\xa8/\xe0\xd8\xd1v\x8b\xec\xb0\xe6\xa6;\xb0 \x93\xdanA~\xb5\xdd\xbef\xa1c\xbb\xe0\xb9\xe1x\xdb\xd1n\xa7<\xef\x19\x9b;\xda\x1b\x92\xfdm7,'<\xda\xf1\x84C\x1e\xcd\x14\xb7[,\x7f\xdcnaV\xb9\xdd\x92\x1br\xdc\x8e\x8e\xb6\xe4\xc7\xc5\xce\x99L\xf3s\xd8\xed\x96\xa1\xa0\xd8)\xd5\xd4\x90,x\xbb}\xa5\xbe?e\xbf\x00\x96\x05\x19\xe2\x97VS[\xb0q\xa4mA\xb4aa\xc4!uCI[\xca\x02{n\xe9_\xa4\xb6\xd4\x86\x03\xcb\x1b\x0f,m@\x8b6\xa0\xb4%lDi\xc3\xe7\x1e\xd8mA\xfc\x16\xc4->{\xc1n\x88\x9c\x06\xbb}\x8dj\xa33\n\xec\xf65\x8a\x1cf\xdd\xba\x0d\x9b\x8a\x11\xed\xd8\x97\xbaa\xb7\xb8\x84\x0e\xbb}\x8d\xf0cSB\xec\xf65J\x1cN*\xb1\xdb\xd7(kDZ\x8a\xdd\xbeF\xa1\x91\x89-v\xfb\x1a\x05\x8eK\x8d\xb1\x1b>a\xc6n\x0f_\xef%\xab\xf3`\x86N\x94\xb7\x88l\x1e\xbb\xf9N\x07\xb2[\xe2\x8c8u&\xfcO\xb4\x06\x8db\x1bh[2I\x8fG\xc3\xb4\xd1\xe2\x13c\x89\xdd\x834Z|&\xb7km\xe9\x9f\xa2\xb6\xd4\x86\x03\xcb\x1b\x0f,m@_{\xf1\x899Y\xcan2r\xd83\\M\x0b\xe6\xb6\xd9m\xd1\x87\xb2\xec3\x89:\xc7\xcan\x8b\x1bZ\x1c\xa3tj\xa9'a\xd9-\xf1|,\xbb%\x9e\x9ae\xb7\xf8\xb3\xb4\xec\xb6\xe8\x84-\xbb\xa5\xaf\xc2\xa5\xe5:\x8d\xcbnQgt\xd9-\x99\xbd4\xb5\xc5\xdf\xc9\xe2\xee8\x82\xa3qh\xd9\x8a\x9f\x06:H\x8b\xa6CM-[\x1d\x92^\xc1\x92u\x974\xec\xa9d \xae\xcb\x1a\n\xefYev[R'\xc4\xb9fQ\xfe\xecg\xa0\x0d\xa7\x9dE\xf9r\x9d\x8c\xe6\xb2\xb1\x8f\xe8\x18z\xb9\x970\xee\xa7\x8c\xf6q'\xd8kK\x9b\x05%\xcc\x80\x12\xa2 -%\x16\xd2\x92\xfb\xf1E\x1d\xc8\x82\xce#\xfa\x04|m\xc9\xc1\x85E\x01\x86\xd4\x93\xf1\xb5-\n4,\x0b6\xa4\x9f\x98\xaf\xed\xeb\x16\x7f\xc9\x8c\xec\x08'\xeak\xcbp\xb2\xbe\xb6X2\xee\xd4\x16\xbd\x9d%\xab\xfa]\xfa\xc9\xfb\xda\xbeB\xd9u\xa9c\n\x9b\xd8\xef\xa4\xf68\x89\x1d\xfa\x82`&\x7f\xa0\x89]yb@aAPaY'\xbe \xb8\xb0$\xc0\xb0\xb4\xfb\xfez\x05O\xef\xb8\x8f\xd6mg\xeb\xb4\x97t\xd9\x0b\xdeHZ\x97\x079:\xeb\x07/uZ\xa2\x8a\xb6\xc4\xe2\xc6\x15\x95\xaf\xcc\x9az\x85\x87\xc5\"K\x15W\x9a\x8b\xfb\x7f/\xea\xbe\xac\xd9*n\x8d\x14\xb76\x8aX\x13E\xf7\xf2\xf1}{\xf4P\x19\xf9\x06\xa4%t\x82\xd1\x03ct\xb0 )`\x90:\x0c&\x05\x0e\xd2\x82\x07\xe9\x83\xde\xc3\x163e\x88;\xc2\xe0\x96aXK\xebg\x93\xa2\x1d\xd7\xabI[0|=@\x19\xd3\x86\xaa\xc8\x82E\x16)f\x7f<\xb1$\xd8\xbd\xef\xd8m\xd5\x9f\xf8p\xfaJd\x0c\xbe\x14 \x83K\xf3\x18\x95<\xa9\x91Y[\xf4=\xdb\xeeD\x0ec\xdf\xc0\xb6\xec*Vl\xa0\x90\xd9\x8aA\x7f2\x9b\xd1\xb6\x97j\x90\x84\xed\x81\x0fv\xf3\xe1.=4\xdd@\xbdMLk\nph\xe4sB\xac\x02\x0c/&\xcc\x80 \x86\x0dP\xa1\x03\x14\x0d\x01\x15@\xc0\x8f\x19Q\xec\x13TM\x01][\x004w\x04\xf7>\xb5a\x1a\x90\xb6p\xc8!&\xec\x80\x0f}$o\x03\xc5\xd0\xc0p10s\xea\xe0L\x1a\xd9\x14\xb0\x0d!\x8a\x1d\x11\xf12p\x8c\x87TnC\"\x8b!\x91\xaf\x10\xcfLX\xc4A\xc0\xcf\x1fs\xf1\n\xa2\x18\x04\xd1\\\x81\x88V\x13\xf1\x01#g2 \x0f\xc7\xcd`\xd08}B \x02\xd5\x8f\x99:a\xf1t\x81\x8e#<\xd9\xb1b\\\x89\x10h\xb8\x03\xe1v8,\x0e'q\xd3\xf2\xf9\xcb5?n\xf0\x83:)\x90\x87J\x1eD\xab\xfe\x9b\xbfB\xfer,\x1f\xd3\xff\xd9\xb3\xf6\xfe\xec\xe0\xf0\xc3\x0f\xef_\xa9c\x82\xc7\x02\xe9N\xc1\xf00=\xb5\xb0\x86}\xcd\xeevl\xcd+\xcd\xda\xb6i\x87\"\x18\xf7d:\xbbP\xf8?l\xbb\x9e\xd6\xban6\x96\xc6\xee\x9f \xf8&zJf/\xaa\x0c\x1b\xd6\x17ee\xe9r|c\xabsL\x0d\x8c\xa5\xa11\x94\xdf\xbe\xda\xb7\xceY\x14\xe2\xcb\xc7}8\x00/\xe1\xf3\x87\x9f\xceZ\xd65\xfbv\xad\xce\x95\x16_\xcc\xbe.\xff\xbeg\xd5=\xf0\xcf\xa8//Kf\x1cJ\xeca\x84\xc8\x03\x1a\xf4\x99\xc9\x9e\xc3\x89\xdb\xa6o\xd6M\x05\x17\xfb\xcbK6\x9c\xd1z*\xcf\x9d\x90u\x83\xed\xbe\x1b>k(\xdc\xd3\x92\x8a\x15]\xef~VS3\xf8\xe6\xec\x1bX_\x17m\xb1\xeeY{*\x8e\x8f\x16'dw\xecj\xcb\xea\xa1\xef\xfa\xfc\xe1\xa7\xa7\xdd\xfc\x80\xd4\xa9\x89B\x0d\x82L\xee\xa7\xf6\x96\xc3\xbbE|\xd5\xa3D$\x9f\x15\x1d\x94\x8e\xb3\xa2\xb9\xfd\xc2\x8b\xe26\xfd\xf9\xd3\xa7\xf7\xf0\xa77\x9f\xf4\x015\x9f?\xfc$\xbf1q\xda\xbcg\xf2pp\x9c\xf3\xa7\xfb\x1d\xfb\xb7\xff\xfbo\xce\x1b@\x9d\x08_\xd6\xaa\xbd\xa9aD\xbc\xa1]\xdbl\xf6k\x06E-\x8707y\xed?\xc3\xcbQ\x14\xa4\x13'\xf2\x14H9>\xfd\xd6\xdd\xa2\xde6={\x01=\x1fC.\xf7\xf5Z~a\xbc\x1e\xaa\xefZ\xef\xdb\x96\xd5}uol\x7f{\xbaKq`\xd2\xe5e\xb9.\x8b*0\x96]\xec/\xa1e|$b'BJ\xa6\xec\xf5C\xf7\x1d\xdb\xc8i\x9e\xfe.\x9d\xae.\xd8UY\xd7\xbc\xb2\xb7e\x7f\xed\x19\\\x0e\x0f\x1b\xf7\xf5\xc6\x1f\xc5\x97\xdaA\xd3_\xcb\x8e\xa2\x9e\xf7R\xf0LNC\x81mw\xfd\xbd\xfa\xb4\xbfu\x0f\x82b6z\xe1\xe9\x94D\xa5\x05NPnw\x15\xdb\x0eG\xcaw;\xb6./\xcb5tl[\xd4}\xb9v\xf0D\xc5\xb7\xba`\n\x84X\xf4`gI\x7f\xe1\xdd\xd1\x05\x83B.\x08\x8c \xce\xc1\x05\xeb l\x88\x92\xfd\xf2\xb2\xbe\xffe\\\xf5\x145\x14\xedE\xd9\xb7\xfc#v\x97\xd0\xeaJ\x8f\x11E\xd5\xa8\xa6\x07\x85\xfd\xd5\xf2\xdeY\x0c4\xb2\x84\x17\xd3i\xe1l\xfa7\xcc\xea\x1cM\xf3\xbd\xfep\xaa\xf2B\x14[\x8d#\x1dt\xfb\xdd\xaei\xc5\x08\xbe+\xd6_\xce\xf65\xff?>n\xcbva\xff\x82\xd4@\xef\x9e\xd84\x97\xb0\xefe\xc7\xa6\xbb\x87\x8ew\xac\xc5fS\xca\xbe\x02\xaeX\xcd\xda\xa2\x17\x85\xe7\xeb,\xad\x04e\xf5\xc7\xcb#_\xa1\xfdyo\xee\n\xde\xf8\xe1\xbb\x17\xf0\x9e\x97\x9f\xf7\x0b\xaa*\x85)\x07\xfe\xea\xbf\xfc\x17\xcf0\xf9c\xd3\xc0e\xd3\xc0\xf7pzz\xfa\xdf\x9d\x97\xf1\xc2\x14\xf5\xbd\xfb\x82\xa2\xbe?\xe5\xc5\xf8\xb1m\xb6\xcf.\x9b\xe6[\xf7\xa5\xa7\xa7\xee\xf1\xaf\xbc\x84g\xdc\xd5gQ\x91O\xcd\xb3\xff\xc4}}\x0b\xbfz\xfap\x9f\xbf\x7f\xf8c\xf7\xc7@\xec\xfeWqSd\x0b\x1e|/\xe6\x86\xfc)\x19\"Tv\xcf~l\x9a\xd3uUt] @\xb2\x88\xfc&YG\xe3Fw\x19\x1c\x91\x1bB\xf7/\x81\xd0\xbd\xbf\xef\xaf\x9b\xda\x13|\xeb\xdb)\x1b\x1b\xaa\xff\xc1\xf2\xd1\xfep\xfe\xd7@8\xff\xd4x\x04\xe2x(_|\x0f\xffiwq\xfac\xd3\xfczzz\xfa\x0f\xf7\xc5E}\x7f\xc2\xa7\xa1\xfc\x8e\x9d\x9cD\xfd\xa5h\xbb\xeb\xa2\xe2A\xf6W\xc4\x17\xc2y)\x85\xc2\x18\xed\xf8H\xa8$\x03\xad\x0ee\x0b\xb1?l\x18Z\xea\xea^\xaf+\x0f6\x0b\x86i2\x14\x97=\xb3m\x12J\x13\xfb\x18O\xcf\x9e\xda\x1f\xa5\xc6D]d\xb1\xda\x05\xa6Z\xf47\x97MszQ\xb4\xa2\xb2wg\xf7\xa7\xff\xfe\x8d\x8c\xa2X{Y\xfd\xb9\x97\xa2\xa2\xa8\xdfp\x1f|8\xb4^\xf2\xbf>\xbe{k\xff\xe5\xfb\xef\xbf\xff\xde\xdd\x06\xf8}\xe3\x9e\x8b\x9cG6\xbc;P\x93 \xb9\xae\xdbwLo\xb0^\xed\xab\xc2!g}\xe8\x86\xdf\xb2a\xe3\xb4\xe5\x04\xd8\xf6\x82m6\xe3\x04\xe6DN\xc7m\xee\n\xc7\xee\x8d1\xa5\xb8\x14\x0b\xd9_\xfe'\x0f\xdd/j3a\xb2Y\xad_\x8e\xfd\x03Q\xdd\xcf\x0b\xcf\x02\xa4X\x7f\xe1}\xd0\xb8 \xbe,+\xe6\x1e7t\x9f\xf5\x9e\xb5]S{?[\xb5\x13'\xce\x8b]\x897\xfc=|\xe7\xf6<\xdc \xb8 \xea\xfa?\xc6\x8f`\x00\xdeR}#b\xf9\xcd\x0b\xf8\xc6\xf6\xd5N\xc3p*k\xf9\xcd\x89\xcf\x9f\xa8\xdf\xdbb\xcb}\xfe\xbf\xb2\n\xff\xc3{\x03\xaf\xdf\xec\xfa\xd8J\x9e_\xaa\x05\xd7\xb4\xad\xc9\xd6Pvp\xcb\xaa\xea\xf9\x97\xba\xb9\xadE?s]tP\xc0z\xdf\xf5\xcd6\xf2\xe3\x9a6\xf9\x139\x81\x9f}\x07\xfa\xd4\xe2\xa18\xbc\x01;\x16W\x85l\xd2\xf6\x87\xfd\">F\xdd\xce\xaf\x9bj\xa3$hE\xc9\xe5\xa7\\\xd6\xc3\xf7\x01r\x07\xd0\xeeJ~2\xf6\xe7\x88\"\x9c\x0e\x83\xf33\xde\xaf\xe9\x10\x1el\x0d\xe9\x1d\xd3\x7f\xfb\xbf\xff\xf6\xad\xe7C\xca\xd1\xe6\xa6\x0f\xf47;\x11*\xee\xf2\xbb\xd3?~\xf7\xc7\xee\x1bO\x13\x92\xff\xbf+\xdab\xcbzf\x92m\x9f\x8b\x9e\xf7\x85\xa2\xea\x18.\xca\xfa\xc5|+\xbbe\x7f\xdf\x97-\xdb\xbc\x80\xbe\xdd\x9bAw,\xa8m\xc4\x8b\xbe\xb8\x9a<\xfd#ko\xca5wvV]l\xcf.\x8a\x8e\x9d5\x8a\x1bxv\xf3\xddY\xddl\xd8\xaa\xac/\x1by\xd3\xd5\x98\xe5\xd9\xed\xb7\xdb\xa2\xbd\x7f\x01\x7fb\xfd\xdbf\xc3\xce\xeb\xcb\x06\xfe\xbeg\xadF\x1b\xd4v\x0dp\x17B_J\xf7\x90\xcd\x8e\xc9\xf8\x9eo&w?\xd1\xd5\x94\xf0\x96Q\xce\xa7\x7f\xfc\xc3\x1f\x9e\xba12\xe8\xf6\xeb5\xeb\xba\xcb}5\xdcmv\xc7\x99\xd015\x0dY\xcdbb\x9a\xd3+\x04\xa1#\xbd\xd4_y5\xca\xbd\x0f\x80\xe0C\xc4\x15\x7f\xf4\x00\xe4\x88\xbd\x99\xb1ayE\xb2\x03\xb2\xe3\xf9\x1e\xe4\x15\n\xcf\xf3\x98\xe9\x9bw\xb0\xcf\x02\x8f\xaa\xca\xaeg\xb5\xe0G$\xdd_\xb3\xfe\xb6i\x1d\x11\x0d\xdc\x8bhR\xce{\xd7\xd7E]3\x1b\xbc\x8a\xb89\xb8\x93\xb7m\xea\xf2\x8b\x8b\xe9\x16p.6D\x8f\xf6\x99\xf4w\xa1\x83q\x82u\x07hw\xeb0#\xc6\xe3\xc7P0w\xf7\x0b\x0b:\x1d1\xf8\xa4\xc4\xbe\xd8\xedV\xc97/i\x8eW%\x866\xeb\xbc\xfdb_V\x9b\xd5t\x14\x8c\xb8\xfd\xaa\xc1t\xcf\x81\xa7o\xd8\xce\xfbt7\x19\xd0K\x04\x0c\xb6\xf9PcP\xd7\x14\xbd\x97\x82\x89h\xf5\xe22IX\xdb6\x9b}\xc5\xfc\xa0<\xe2P\x8e\xa4\x87*\xbf\xce\xeb;?\x1b1\xee\x99\xebk\xb6\xfe\xd2\xed\xed\xb3\xfb\xe1\xaa\xbf\xc8\x92\x95\xc6\xd2\x91O}\x7f\x96%=\xb7\x8bpV\x17\xdbU\xb7\xf9\xb2\xa0\xe5M\xa6K\xc6\xc3\x0e\n\xc2\xff\xc3\x98\x91\x0d\xe4\xa7\x01\x0bpz\xb5\x11\xa9\x0e\xdc\x0c\x1c\xaa\xbf\xefY\xd7O\x1f;\x90\xa6f\xd3Am\xc4\x9e\x92F\xec)bO\x8dF\xec)bO\x8dF\xec\xa9\x9e\xd8Sv#\xf6\x946bO\x11{\x8a\xd8S\xc8Y\x12\xb1\xa7\x06#\xf6\x94i\xc4\x9e\"\xf6\x94\xc5\x88=e\xbd\x86\xd8S\xc4\x9er\x18\xb1\xa7\x88=E\xec)bO\x19\x96\x83\xc9B\xec)a\xc4\x9e\xfa\xad\xb0\xa7b\x99K\xdd}\xbd.k%_\xe2\xe0-}\x94\xd7\x0c\xb4%AUR7\xba\xd8J\xea\x1e\xf5\xeb\xa3%+M\xaao\x9a\xf4u\xd14\x15+\x0e\xb7\x7f\x86\xad\x03\xcb\xefA\xbcO\x85\x06%\x990\xe2}\xd3\x80j#\xb8O\x1a\xc1}\x04\xf7\x8dFp\x1f\xc1}\xa3\x11\xdc\xd7\x13\xdcg7\x82\xfb\xb4\x11\xdcGp\x1f\xc1}\xc8Y\x12\xc1}\x83\x11\xdcg\x1a\xc1}\x04\xf7Y\x8c\xe0>\xeb5\x04\xf7\x11\xdc\xe70\x82\xfb\x08\xee#\xb8\x8f\xe0>\xc3r@/\x04\xf7 #\xb8\xef\xf7\n\xf7\x8dj\xdf\xac\xef\xce\xaa\xa2g]\xef\xc5\xfe~\x12\x97\x0c\xc7\x1f}d\xfd\x00\x03\xca\xbbG\x01\xf1\xe7\x1d\xeb]p\xe0\xa1\x1bu\xe1\xa3E\x06\xe5\xe9\x0e\xae\xb3a\xbc\xfb\x0d\xbe\xa3<|G\xc9\xf5_\x01[\n\xa4]\x07\xf7U\x02\xe7\xb2\x05J\x07\x88\x12\x02\x02\x01\x03LQ\xa5avR\xb4\xc5\xa2a^g\xf6-\x11\xcf\n!7*\x06ad\x0c\x12\xd01\x7f\x05\x8a\xfe\x1a\x8d\x90A.\x94\x0c\x12\x912\xafC\x1e\\4Z\x06\xcb\x113\x88F\xcd\xbc\xae\xd4n~\x14r\x06\xb9\xd13\x88D\xd0 \x16E\xf3\xb7\xec\x01a\xc3\"i\x90\x1bM\x03\x1c\xa2\x069Q5X\x8c\xacA\x1a\xba\x06\xb9\x106HB\xd9\xfc\x9fC\xd1\xb1M\x18i\x83\xe3\xa0mpD\xc4\x0d\x8e\x83\xbaA$\xf2\x06i\xe8[\xa8\x0b\xc6!p\x90\x17\x85\x83\x08$\x0e\xe2\xd18H@\xe4\x10]\xe6\xb7\x08T\x0er s\x10B\xe7\x00?=C\xa0t\x109\x8b\x8bF\xeb\xbc\xde\x04\x92\x87@\xec \xa2\x94\x19\x91;\x88B\xef 7\x82\x07\x89(\x9e\xbf]ua$\x0f\xd2\xd1<\xa7?\xfe\xc4\x10\xa2\x07\xd9P=\xc0\x83S\x80A\xf7 \x0e\xe1\x83\xd0\x96|\"\xd2\x07\x08\xbf\x9e]\xbfL\xa8\x1f$\x05\x17\x8f\xfe\x01\xa2\x96 ( \xa4\"\x81\xe0\x8fj>D\x10\xf0\xa8 \x91A@\xa3\x83\x80\x8bz\x9fw\xb3\xb75\xab\x82\x98E\xb7\xacS\x08\xb7\xf8\xbc\xc6\xef\x91\x7fr\xa7\xeak*\xaf\xea\xa6\x9d\xed_\xeb\xafq\xfa\x08\x19\x99\xa5/\xf6P\xc4\xdb.\xef\xed\xd6Zx\x8a\x11[\xf8Uj \xfcCI\x1b8\xf4\x16\xac\x84\x02\xad\xb80a\xf3@\xd1C\x01W\xe5\x0d\xabA\xbav\x89/\xd8|>\xd1\xb1!\xf9\x05m\xfdW`\x11\x90\xfc\x82\xc7by\x0f^g\xf6\xcdo\xcf^Pn\xfe\x03\x849\x10\x90\xc0\x83\xf0W\x80\xe4\x17R\xb9\x11\x10\xcd\x8f\xf0\xba\"\xf9\x05\x92_H\xe5P@\x1a\x8f\x02rq) \x89O\xe1\xff\x1cH~!\x8e_\x01\x91\x1c\x0bH\xe3Y\x84\xba`\x1c\xd7\x02\xf2\xf2- \x82s\x01\xf1\xbc\x0bH\xe0^ \xbaL\x92_\x90\x16\xcd\xcb\xf0z#\xf9\x05\x92_\x98Y\x1e\xfe\x06\xe0i\x08\x80\xe1q@\x1c\x97\x03B\xe0k\"\xa7\x03\x10~I~\xc1cI\x9c\x0f \xf9\x05eI|\x10\x88\xe2\x84\x00\xc9/`\xb8\"p\x0c\xbe\x08`\xcaH\xf2\x0by\xb9$\x10\xe4\x93@*\xa7\xc4\xe9\x8d\xe4\x17p\x1c\x14\xa77\x92_@rS \x9a\x9f\x02$\xbf`\xb5\x14\xee\x8a\xd3\x19\xc9/h#\xf9\x05\x8b\x91\xfc\x02\xc9/X/\x08\xee(\x91\xfc\xc2\xefH~\xc1FE \x01\x86\xc1<\x8d\x89\x04\x18,\xb7\x93\x00C\x04\x01\x81\x04\x18H\x80a\xb4\xac\xc4\x82\x18RA\x14\xa1\x80\x04\x18\x96\x92\x07\x12\x88\x03YH\x03\xf1\x84\x01\x12`XB\x10\x88!\x07$\x10\x03H\x80\x81\x04\x18H\x80\x01\x0b\xecg\x05\xf5S\x00}\x12`p]\x16\x04\xee#@{\x8c\xbc@\x0cXO\x02\x0c$\xc0\x80\x01\xdeI\x80A\xd8\x12p\x9d\x04\x18l\x9e\x82\x00z*x\xee\x1c\x1bH\x80\xe1\xd0H\x80!\x01\xf4\x0e\x03\xde\xb1`w\x04\xd0\x1d\x0dr\xc7\x01\xdc$\xc0\x10\x07b\x93\x00\xc3`$\xc0\xa0L\xa7e_\x9b\xe9\xaf\xa0R\x86g[\xd9c\xc6p\xdf\xee#2\xc1\x83\x89\xe0$\xf9\x00\xe1(\x92\xe4\xc3\x11\x83\x1b\x16+ \xc9\x87\x1cQ$\xc9\x87\xdf\xb6\xe4\x83P|\xd8\x94\xbc\x85\\\xecyt\xcen\xbe;[7\xdb\xed\xbe.\xfb\xfb\xd5\xaei\x140m\xd3yx\xa5\xaf{\xdf4\xd5\xa0\xee \xd17\xf5\x0bp\x0f\xb0n\xca\xba\xb3\xca:L\\<\xd1\xb5~\xa4b\x0ec4L\xeb\xbf\x02i`\xc3\xeaf\x9b\xbc]^ly\x03O\xbc\x1d\xb3Y\xfd\x9a\xad_5\xa5A\xf3\x82\xbe\xf9\xc2j\xb5\xd7,K\xaf\xbfF>\xdb\xe5\x7fZ\x97\xdb\xc2\xce\xdb\x96\xc5u\xed\xba\xbe}\xf7\xe9\xcd\x0b\xb1n\x94\xd7\xa9\x05X)\xf6\xc8_\xb3\xb5\x9a\x9a\x0e\xb8\x849?\xb5:\x94\xcbu\xfb\xc3\xba\xf2\xaa.\xfa}\xcb\xba\xe1\xdb\xe4\x1d\xf5Us\xd5\x88\xc9\xe0\xe1\x9an\xca\x80\xe3\x1f\x83\x0e\xca\xf4\x1by\xdaM\xbf\x12\xcb\xdd\x07\xc1\x16\xec\xa1\xc9\x17\x94\xceA\x9a~\x88\xb3K\x88\x88$\x8d\x88H\xben\xe5\x08\x18\xde|\xe0\xfa?j\x80|j\x1d\xb76\xacbWB\x15\xe7\xec\xd7\xe1\xdf+\xa5M\xf3\x8f\xb3\x96\xdd\x16\xed\xa6\xf3\x08\x17\x19\x8b\x97\xd7\xf2\xfe\xb2\xa9?\xf1y\xc0\x07y\xefd\x90\x93\x13\x04\xe5\x15\x8a\xf5\xba\xdd\xcb\xee\xa0\x103\xb7\xc1\xd5\xc0\x9e\xb5\x8e\x80\xf6\x07\xa9+\x1f\xedP\xa8j\xfd8Z\xee\x10\xe0\xd5R\x1d\"Y-\xff\xed\xf6\xbaIs\xd6PZ\xa0\x9e\xd2B\xb5\x95\xe6\x9d\x01H\x0b\xd6V\x9a\x7f6 \x0d\xe5\n33\x90\x16=?\xf0\x06B\xcc\x1c\x02\xb3\x04iIs\x05\x8f?\xb5\xcb\xe5\x9b1H\x8b\x9f7\xf8\xb7U\xb4\x8d\x9d\xc7k\xdd\xdf\xc9\x0ed\xdc\xf0\x93}\xd5\xd8\xa8\xac~\x9aK\x11v\xe5\xe2i\xa7\xff\xcd_\x80\xfc&\x023\x1b\xdd\x0b\x0eo\xb4\xaa\xd4\x04\xc4\xd2;\x0e\x0f\x9a;u\xf0\xd3\xbfF\x9fB3\xec\xc1\x92\xbe\x9a\xaf4\xc3\x96c\xb2\x8e\x8a \xa8\xec\xb7\xa2yO\x1b\xa4g\x9a}\xf0\xa9\x89I\x87}\x98N\x9fo;\xe6\x174\xd3\x96F3\xed\x07\x9ei\xfb\xb0\x86\x83\xb9\xb4\xab%\x1e\\8\xf9\x12\x87_\xb5\\$\xf4\x8d\xcad\xba\x9c\x8e\x05\x0b\xb1\x8cc\xac\x1a\xce~=\x98e\xfa$P\xc7\xcf;r\xe50\x0e\xbc\x81\xd5\x02-\x14\x0e\x7f\x0e}x4\xa8\x0f\xf6\xcf4\xa8\xcf'\x97\xa1\x89\xa5\xf1\xf1X\xbc\x85\xc6\xf7\x8cC;\x8d\xeaS\xa3Q\x9dF\xf5\xe4Q},\xf9\xc1H\xec*\xf9\xc1\x85\x93\x92\x0f\xbf\x1e\xbb\xe4Y\xe7#\xa3\xf4wx\xfa\xd1\xb4C^\xf1t\x022:\x99-\xfd}\x93\x0e\xd3\xdb\x13\x1d\x85G:\xed8\x92@\xba\xe3\xfb\x0b\x0f\xeeF\xc0\xadM\xb03_\x02\x1fr\xf4Pf\xfd\xda/\xe7['\xf8\x01\xce|\x89\x8b\x87\xb8I\xfb\xa2AN\x1a\x0dr4\xc8=\x8e\xa1\x82\xaf\x1b6mq\xab\xff\x82\x190\xfe\xaa\xeey\xa9\xea\xa9G\x0d\xedk\x08@\xcc\xb81s\xfaD\xc7\xe5\x91\x0e\x1e\xf3\xb8E}\xae\xb32\xcf}%6\xab\xb8.~\x16\xef\x0c\xfd\xfc\xbcYPg/\x8d:{\xea\xec\xb3w\xf6\xd6\xbe^T\xbcs\xf7\xe0\xef\xc5\xefC\x7f-/\x1f\x12^\x0cg\xb0m6\xfb\x8a\xd9{l\xe3:\xe9\xf0\x89\xae\xd6#\xed\xab\xcd\xb0\x986\xe5]\xc9`\x98/ylG:F\xd3\xb0\x8c\xe6\xfd\x88\xfc\x9f\xd0H\xa4\xec\x8b;\xf77\xe6\xf9\n.\x8a\x8e\xad\x06U8\x1f=!\xe4\xa8\xa9\xf7]\x16O\x93\x11m\xc5\xea\xe2\xa2b^O\x87,\xd5\xd1\xec|Ui\x08\xf2\x9bl\xa3\xa8\xf1M\x8dh\xea3\xf9\xf0\xfe\xd5\xcc\x1f\x8df4\x9a=\xf8h\x167\xdd\x1fw\x0blh\x94\xa0m\x97]W6\xb5g\xa2?,\xd8_\x0dW\x0fcF\xb1^\xef\xb7\xfbJ\xe8!\x8c\xce\xc4\x07T\x04Xl\x16\xb7\xea\xb2G;r\x8c5\x0c\x8c\x1eF(\xcc\x11D\xfe\xb9TBF\xe3fb\xcb\xd6\xac\xbca\x16\xc6\xcc\xc2\x91\xc4UX\x08|P\x10\"\xa6\x05>,\x08\x96NZ\x90\x92\x86\xf8FB(\x1b\xe0\xdc\x847\xe4\xa4E#n\x9e\xcacihI\xc8\x9b\xd3\x1b\x92\x82\x16\x87\xc0\xb9\xb4LE\xf7d\xf9\xd4Q\x03\xb0\xcd\xd7\x99\xad;\x1a\xd7\x96\xc3-4\x18O\x7f\xa3\xc1\xf8\x08\x83\xb1oi\xf9\xdb\x86\x9c\x02\x13\x8bf\xdfw}Qo\xca\xfaj\x15&\xd1\x0f\x9f\xf4\xbb\xf1\xb69 F\xa3\xf7b\x13\xf1 (\xfe\x19\xc6\xa1\xdb':>\x8ft\xa6\x11\xe0\xc0$M\x08\x9c>\x81f\x03s\xa3\xd9\xc0\xcc\xe2f\x03\x80\n\xa1\xef\xb37\xc8\xe8F_bq\xf2l_?\xd7\xfb\x0b\xf5\xb7\xba\x91\xdb*2[\x94@)\x86\xff\xba+o\x98\xcc7.\xd6_N\xa4Tg\x07\x9d\x08\x1ftE]Z\xcf<\\_\xb3\xf5\x97\xf8\xd4;O\x95\x833\xa2\x99?\x8b\xd4\xecl\x82d +m\xc2K\xa3\x99\x12\xcd\x94\x1e\xc7L\xa9\xab\x8a\xee\x9a\xa1fG\x1f\xe5\xa5\xc3\x94H\xdc\n\xecF\xf6\x92\x97\xf8\x1d\x17\xe5\xe8\x89\xae\xfa#\x9d\x04\xa9\xd0<\x8e\x8fj|u;\xd6\x96M \xe3\x0f\xf5yx\xce\xc5\xb8\x14\xda\xe8\xae\xad\x9b\xe0S\xc2c/\xccZ\xc3\x1b\xde\x8a\xccQ\xd7\x1c)\x8d\x86\xe6\xd0@T\xc7O\x94\x9d\x98v\x94k\xa1W\xd2_+\xc5\x93\xaeoZq|\x89\xe3n\xa1\xe9_vBLZ\xabdWk\xb1\xad\x08\xc5\x8e\xbf\x99\xb6\x14\xff\xdej\x0d\x8f\xae\x17\x92\xcfVob\x06f\x9d\x01\xc89\xc0H\xf9\xd5\xca\xedE\xcb\x06\x8c\xa2Vjz\x85\xaa\xf5\xb5C\x0b\xbdY\x0b\xad\xe8P\x96\x9bj\xc3\xd3\xfc\"\xf57\xdc&\xe0\x92\xc3r$le\xc8\x98Lf\x16Y\xb7\x1b\xe9\xb0\x1c:,'\xe9\xb0\x9c\xc0\x96\xa1\x1a\xab\x82\xb3\xe3\xf0~\xa1\x1e>i\x0e,\x8d\xe6\xc04\x07N\x9e\x03\x8f%\xef\xfa\xa2\x15g\xdd\x1d\xe8\x0b\xfaf!\xb3\xbb&\x95\xd0'\x9f\x0c\x17)\xe9\xc2\xb1.\xf3o]\x8d\xa8\xf3\xfa\xc5\x8ac\x1d\xbc\xd0\x80\xea\x19\x93\x1b\x9c\xf9+.\x1d?\xd6j\x93\xacc\\\x18I\xd6\xf1\x88\xc1\x0d\xb7Q\x92u\xcc\x11E\x92u\xfc-\xca:N\xf8\xa3\xec\xa6\xdc\xb0z\xcd\xcen\xbe\x1b\xfe\xed\xde\x96zYUo\xd4E#\x1d\xa8\xaa@\xdfi\xdd\x822nz\xa2k\xf6Hw\x9f\xa6\x110\xed\x9fr>\x8b\xdb\x14\x02:\xf3\x91\xce|t^Ig>\n\xa33\x1f\x0f\x8d\xce|\xa43\x1f]Fg>\xd2\x99\x8f\xc2\xe8\xccGw\x9b\xa63\x1f\xa5\xd1\x99\x8ft\xe6#\x9d\xf9(\x8c\xce|\x14Fg>\n\xa33\x1f\xa5\xd1\x99\x8ft\xe6#\x9d\xf9Hg>\xce\x0d{\xfe\x1e\x9d\xf9(\x8c\xce|\xfc\xad\x9c\xf98\xdad\x85\xa8\xf1\x0b\x05TN\xc1\x99\x83\xf55\xb1\x0c\x85\x11\xcb\xf07\xca2\xb4\xa7\xe3\x18pd:\xc1\xd0\x04B?\xbc\x7f5\xaf\x04Q\x0d\x89j\x18\xda\x97\xc4l\xed\x01A\xb3\x04\xcd:\xaf$hV\x18A\xb3\x87F\xd0,A\xb3.#h\x96\xa0Ya\x04\xcd\x124K\xd0,A\xb3\xd2\x08\x9a%h\x96\xa0Y\x82f]F\xd0,A\xb3\x04\xcd\x124kX\x0e\x98\x8c\xa0Ya\x04\xcd\xfeV\xa0Y_\xc6?eQ\xc7\xa5\xa8R\x16\xf5\x11\x83\x1b\xce\xff\xa5,\xea\x1cQ\xa4,\xea\xdfr\x16\xf5Sg\x1a\xf5\xd9\xaf\xfa_\xab\xeb\xa2\xbb\xf6\x9d\x03~\x90T=\x10y\x04,\x01M=\xfe\x85\xfb\xb2\xe6Y\xffV\x92\xac\x93HB\xbd\x17\x90\x0f\xeeEc6s\xb3C\xf18 >\x05\x86\xf7\xc3\xedI`\xbbx\x84\xc3a\x10j\xcf\x00\xb4'\xc2\xecNp\x12\x07\xb2/\x82\xd8\x93\x00v(*\xfbA\xed\x80\x85\xd7S\xc0u\x1f\xe4\x85\x82\xd63\x03\xeb(X=#\xa8\x1e\x84\xd43\x01\xeaK\xe0\xf4h0=\x03\x94\x9e\x19H\x0f\xc0\xe8\xd9A\xf4\xe3@\xe8\xd9\x01t<|\x9e\x06\x9e{\x82\x1e\x82\xce\xb3\x01\xe78\xd8\xdc\xb2nw\xf7\xaf\x99!\xf3\x10`\xbe\x10.\xf7\x80\xe5\xc1\xe9I\x10(\xc7\xcd_\xf2\x82\xe4!\x88<\\\xa64x\\\xf7\xec\x16\x87!p<#4\xbe\x00\x18\xb7\xd3Y|\xb0x^P\xdc\x0f\x89\xe7\x00\xc4Q\x88n\x00\x0cGC\xe1n\xd4*\x1e\x06w\xfb\xb2\xee\x10g\x01\xc0c\x82\x85\x05\xbf\xc31A\x03\xdf \xb0\xb7}7=\x13\xe4\x8d\x02\xbc\xc3p7\x06\xec\xf6F1\x16\xe8\xc6\xc2\xdc.\x90;\x03\xc4\x1d\x01p\xa7\xc3\xdb\x1e\x10\x19\x0bmg\x06\xb6=%\xb2\xb6\xd4$H[\xefDZ\xfc9\x00\xed\xccp\xb6\x1b\xccN\x85\xb2\xc5\x8e\x80\xad\xe0v ;/\x8c\xedZ\xf8\x05!l\x17\xc6\xe6\x82\xaf\xf3\x82\xd7\xe9\xd0\xb5\x03\xa6N\x02\xa9\x83\x80t\x1c\x1c\x8d\x06\xa3#\xa1\xe8\x18 \xda C\xbbK\x83\x85\x03q\x10t$\x00\x1d\x01?[\xab\x96\x17zv}\x14\x0b`g\xeb>\x85\x13tN\x83\x9c}\xf0r~pyyKB\x03\xcbXXy:D\"\xb2\x1b\xa3R\x1bU2\xe3\x0c8\xd0Fg&H\xa3DFJd\x1c\x8d\x12\x19)\x91q\xb4\x14\xac\xc5\xe9\x8c\x12\x19\x0f-\x13\xee\xb2\x0cyI\xc0^\xb2\xa0/\xd9\xf1\x97 \x02s\x04\x0c\xe6X(\xcc\x11p\x98\x18$&\x15\x8b\xf1\xf6\xe1!4&#\x1e\x83Ed\"1\x99\xec\xa8L\x18\x97Y\x8c\xccP\"c\xb0diH\x8d\xd5\x15%2\xa6`6!\xd4&\x0fn\x83\x04#\x82\xd8M\x04z\x13L(\x8bDp(\x91\x91\x12\x191\xd8N0\xaa\xb1\xf8\x0e\x1e\xe1\xa1D\xc6\x99e\xc6{(\x91\xd1\xb4T\xf4\xc7\xea\x8c\x12\x19#\xb0\xa0%h\x90\xd5\x1d%2Zo@\xe1G\x94\xc8\x98\x0fM\xa2D\xc6\xc5XS\x9e6\x87\xc6\x9b\xf0\x88\x13.\x91q\x92\xd9bx\xb2\xaa\xd1\x8a\x8b&\xca\xb1\xe2\x0f\xaa7l\xa5&(\xdb\x1c\x9c\"\x08\x90\xe1\xc8b\xeb\xe2\xdc\x9f\xccs\xd5\xdc\x9c\xdd|w&\xea\xdf\x9d\xfd*\xff\x7f\xc5\xbd\xfbrx\xde\x8b\xcb&\xc7\"\x8e\x11\xd4\x95\xbdjn`\xdbl\xf6\x95\xfd\xa8\xc4?57\xd2\xcd\x13]\xd5G\x9a\xc3s\xd3\x88\xf3\x8ceh\x0e\xe7\xc4\x932M\xae\x9d \x08\x0f\xf1iY%\x16\xc2}\xa3\xae?\x1c\x9f\x9c\xc5\x84 \xce\xa5\x8b\xc0\xda\xb2\xd9$rp'u\xfa\x89\xd5W\xfd\xd0\x84\xa5{\x90\xee\xe7\x05\xdf\xb0]\xd3\x95=.V\xd3\x8b\x11\xc1R7d\x8d\xd6\xb6\xacW\xca\xaf/Vv\xa0\x12|`%\x84\n&-\x04Z\x82\x08[\xddl}\xab\xb1\xe0\x0b\xe5Vl\x9b}\xed\xa8\xa54\x84\x1b\xcc\x06\x1a\xb7WM9\nh\x17\xd07_X\xad6\xc0dutv%\x1f\x82\x8bZ\x15\xce\xb7\xd7\xfa\xf6\xdd\xa77/\xc4\xacU^\xab\xa6\x7f\xa5\xd8\xa1;\xaf{50\x0e\xbb\xa2\x9dw\xf3_\x8d\x9ar\xc1\xe0~hW^\xd5E\xbfoY7t\xc5|\x89t\xd5\\5bH\xb2\xcf,'A\xfaKY\x97\xdb\xfdV\xb7^\xb1N(\xc4ko\xba\xa2\xe2\xed\x9a\xd5|\x19\xe2\xfd\xb0\xb8m\x8b\xbb\xd5\xf0\xcdd\xfb\xba\xdd\x04\xfa\xe2N\x94[>J\x14\xfb%\x0f\x19\x9fy\xf0\x0fs\xfc \x81\xbf\xc6\xa1F\xae\xd5\xe8y]\xf6eQ\xa9\xfdg\x98\xb3\x0b\x06\xdb6u\x7f}\xb0w\xdd\x17Uu\x8f\xebW\xccK\x11\xbd\x8a\xb8\x80\xdc\x0e\xd2\x16\x0b\xe9y\x9d\xd9\xf7u<\xcb\x9c\xdc\xd0\x1e\x84\xe1=H\x80\xf8\xfc\x15\xd0B\xda\x18\x98\x0frA}\x90\x08\xf7y\x1d\xf2\xe0\xa2!?X\x0e\xfbA4\xf4\xe7u5\x8am\xe3\xe1?\xc8\x0d\x01B$\x0c\x08\xb1P\xa0\xbfe\x0f0!\x16\x0e\x84\xdc\x90 \xe0`A\xc8 \x0d\xc2bx\x10\xd2 B\xc8\x05\x13B\x12T\xe8\xff\x1c\xf4\x14$\xf4\xdd\x1c\x052\x84#\xc2\x86p\x1c\xe8\x10\"\xe1CH\x83\x10C]0\x0eF\x84\xbcP\"D\xc0\x89\x10\x0f)B\x02\xac\x88\xe82\xbfE@\x8b\x90\x03^\x84\x10\xc4\x08\xf8\xe9\x19\x02j\x84\xc8Y\\4\xe4\xe8\xf5&\xe0H\x04\xec\x08\x11\xa5\xcc\x08?B\x14\x04 \xb9aHH\x84\"\xfd\xed\xaa\x0b\xc3\x91\x90\x0eI:\xfd\xf1'\x86`I\xc8\x06M\x02\x1ea\x03\x0cD q0%\x84p\x85D\xb8\x12\x10~=[\x97\x99\xa0KH\n.\x1e\xc2\x04D-\x13\xa0LH\x853\xc1\x1f\xd5|\xb0&\xe0\xa1M@\xc2\x9b\x80\x868\x01\x17\xf5x\xa8\x13\xa2\xe0N\xf0B\x9e\x90\x0b\xf6\x84X\xe8\x13\x16\xc2\x9f\x80\x08o\x04\x0c\n\xc7\x80B\x01SF\xcf\x97\x90\x0f\x16\x05\x0c4\n\x0b\xe0Q\xa7C~\xa1\x0f\"\x85\xdc0)\x04\xa1RH\x85K\x9d\xde\xe4\x1a\xd5\xbf\\G\xc0\xa6\xe0Ew\xc0\x0b\x9fB\x12\x84\xeat\xe5\x85V!\x15^uz\xf3H\xaeK\xcb\x07\xb3\x02\nj\x85\x04\xb8\x15\xe2 WH\x81]!\x1az\x85\xc0h\x1b\x80\xc3 \x02\x12\xc3\xc2\xb0\x90\x02\xc5B,\x1c\x0b\xfe\x8a\xa7\xc0\xb2Ng\x06\xe8\x89\xfddp\xf0\xac\xf7\x83\xa8\xaf\xfc\x10-\xe4\x85i!\x04\xd5\x82\x1f\xaeu\xde\x93\n\xe3B\xc6\xb6\x1b\x01\xe7B\x14\xa4\x0b\x07\xc2\xf1\xda$\xb4\xb8\x00\x02c\xb5+\x89\x17\x04B\xfa\xfe\xc3\xbb\xf7\xef>\xbe\xfci\xf5\xf1\xd3\xcbO\x9f?\xae>\xbf\xfd\xf8\xfe\xcd\xab\xf3\x1f\xcf\xdf\xbc\x8e\xb8\xeb\xf5\x9b\xf7\xef>\x9e\x7fZ\xbd\x7f\xf3\xe1\xfc]\xcc\x8d?\xbf\xfbt\xfe\xf6O\xf1\xf7\xbd\x7f\xf9\xf1cT ?\xbc\xf9_o^}\x8a\xba\xe5\xc7\x97\xe7?9o\xd0\x99\x96 \x01\xc4\xee\xaah\xec\xf8\xa3h\x03\xe2M\x8a\xb5\xbf\xfc8\xd5^\x90\xf8\x8d f\xb2\xbb\xeb\x19\xb3\xda\xddM\xd0\xdb\x14\xbc\xd5\x9c\xa4\xa7\xeb\x19\xa4x\xe4\xae\x93\x89\xda\x06:\x8ez\xf2\xb49\x1d>|\xfa\xbb\xa1\xd00\xe4\xf2\xca\x87\xc2f\xdf\xea\x13\xf4\x15\xdb\xc0\x1d#\xa7d\x81\xb2@\xe3=,\xe5\xe4g\\!%o\"g\x19\xe5\x87rX8\xf9wO\xa9x\x832r\xa3\xf98t\xed\x01\x86vE\xd7\xb1\xb8\xa2\xe9O\xf2\xb0p\xfa\x97|\xc5\xbb`\xac\x86\x96\xfdM$>G\x95R\xf6\x02\x87e\x94\x7f\xcfW\xc2\xcb\xa2\xac\\E\xbb,\xeb\xa2ZII\x08 \x0e\x1d\x99\xaf\xf0\xf4\x9euO\x17\xef\x86\x17\x17\x1d\x9fq/\xf6\xf3\xb4n\x96\x17\xa6nV|\x05\xb1\xbaa}\xb3\xd0\x19\xb6\x03\xff\xc4_\xd8\x07);1\xb6\x93\xae/\xeaM\xd1n\xa4f\x87RR\xb9jnX[\x17\x87g\xba\x8c\xe6\x97&\xe9\xf6\x17\xdb\xb2_\xf5\xe56G\xa2\xd4\xa6\xe8\xd9s\xee\xcbz\x9d\xd6oa\xf5\xe6a\x1e(\x14?\xfc\nG~\x9a\x924\xaf\xca\x11\xea\xdb\xc1}=\x08\xad#Tp\x00\xa5w\x84t\x85m\xb4\xd1\xaaG\xc1\xc2\xfb\xa1\xc3\xbc\x8aHhM\xa4TU$%L\xd6\xf5E\xfb@_\x9bz\xe2\x03}l\x98f\xa2'\xa6\x93\x89\xdf\xbai\x99zw[\xbe2m\xd5\x08\x18\xe8\xd9\\\xbd\xda\xae\xb8R\xcd\xec\xb0\xc2\x932\x8e\x17\xced\x92\x86?\xab}<\x1byR\x9a\xf7\xc3\xf7\x7f\xf05\xbb\xebW_\xd8\xbd\xfd\xad\x04\xdfI\x10-\xee\xcb\xbeb/\xe0?\\\xdf\xab~\xbeV\x91\xe1\xffTT\x0b1!\xe3\xff\xf1\xbe\xb8b\x1f\xa4f\xe3\xa9\xfc\xdd\xe1Lr{\xb9\x1b\xee\x96\x87\x90\xc1\xb6\xe9z`\x82\xb0 \x98\x0e\x96[E\xef\xbc0\x00\x1e\x86\xa6\n\x81\xb3\xcb\x92rP\xbc\xfe\xe2\x1f\xf5\x9e7>\xde\xf6t\xc6\xbd\x91\xde\xed\xc2J\xcd\x10\xady/\xb4\x12\xce\\\xdd\xc7m\xd1A\xc7\xfa\x13(\xfbN3\x84:\xd8\xd7\xb2\x01n$ \xe2\xb6\xec\xa6\xef\x14#\x0d\xa4Y\xb8(u \x9b\x87\xb3\x91\xbb\xfc\xe1\xfd\xaby\x05H/\x88\xf4\x82B\xa3\x04f\x04\x80\x04r\xb1l\xba\xa4\x17\x84 \x12g!\x11\xa7\x10\x88I/(#Y8\x86(\x1cE\x12&\xbd\xa0\xa5\x84\xe0\x042p\x16\"p< \x98\xf4\x82\x96\x90~c\x08\xbf d_\xd2\x0b\"\xbd \xd2\x0b\xc2\x92u\xb3\x12uSH\xba\xa4\x17\xe4\xba,H\xc6\x8d \xe2b\xd4pb\x08\xb8\xa4\x17DzA\x182-\xe9\x05 [B\x98%\xbd \x9b\xa7 )6\x95\x10\xeb\x1c\x1bH/\xe8\xd0H/(\x81\xc8\x1a&\xb1\xc6\x12X#\xc8\xab\xd1\xc4\xd58\xd2*\xe9\x05\xc5\x11SI/h0\xd2\x0bR6\xe8\x05i\xb9\x15\xc9]2|MV\x933\x18rv\xd7\x04\x7f\x1dIP\x02\x8d\xd5\xa0\xd4|\x9e\xf4\xb0\xac\xc3\xaf\xc74\xb42\xf7\xbe\x12\xa3\x10Y\x96c2\x07\xadl\xc1\x87g\x08\xfaX\x81\x0f\xcb\x04\x96\xc0\xc5nf7\x8a\xcd\x8ddp#X\xdbQLm\xdd!\xde4\xfdd\xbfk\xd2\x0d\x8a\x1f'\xfd\x8f\xfcK\xb1\xd9\xb4\xac\xeb4\x93_p'0\xeb\xf1\xe3\xec\xd7\xdd\xa8\xe0\xe8=\x84YO\x8b\xb4\xd2\xe6n$\x97\n^\xd5\xa8t\xa5/=\x7f\xad\xebl\x95\xda|\xa2\xeb\xfd\xc8\x956]\x84\xb1$\x1e\xaa\x11\xedc11\xbdJ\x99\xde\xa2C\xb0\xf8\x80\xa0\xae!\xea\x00H\xf8SZ\x12\x81\xcd\xe3/J\x1b3+\x89-Hc\xcbMd\xc3S\xd92\x91\xd9\xd2\xe8l\x1ew\x91j\x98\x0b)m\xb9Im\x91\xb4\xb6\xcc\xc4\xb68j[$\xb9\xcd\xd7\x86\x13\xf4/\xb3\x12\xdcP\x14\xb7\x8c$\xb7\xa54\xb7$\xa2[&\xaa[\n\xd9\xcd\xe3\x0c\xadwy\x04\xc2\xdb\xf1(oG!\xbd\xc5\xd1\xde\xb2\x13\xdf\xb0\xd4\xb7\xac\xe47<\xfd-\x9a\x00\x17O\x81\x0bv\x858e\xcb\xc54\xb8\xa0\xaa%jB\x85 \xc3\xc5\xcc\xba\xa2 q\xbeA\x10\xade\x89+_FZ\\\x0c1.35.\x8d\x1c\xe7kA(\xfd\xcaD\x82\x9c\xc3[\x8f\xd2\xae\xccC\x92C3\xbd\x10D\xb9(\xaa\\H\xfa-\x85.\x17\xf2\xe9\x84\xcd3\x91\xe6\xe2\x83\x89'\xce\x85\xea\x96@\x9eK\xa4\xcf\xf9\xe8\x07\xd9(th\x12\x1d\x8eF\x87%\xd2!\xa2\x1cO\xa6\x8b\xa1\xd3\xf9\xd5(\xb3P\xea\"Iu\xcbhu\xa1\x80FP\xeb\x8e@\xae\x0b\x96\xce\xd9\xd2\xf3Q\xec\x10$\xbbt\x9a\x9d\xc3]\x1fT\x9d\xccJ\xb5\x0b\x91\xed\x12\xe9v\x0e_a\xb5I\x04\xe5\xce\xaf4\xe9\xd3\x99\xccM\xbc\xcbN\xbds\x93\xefr\xd2\xef0\x04\xbcx\n^\x14 /\x81\x86\x17K\xc4\x0bhG\xfaK\x87\xa5Fa\xe9x \x84\xbcHJ\x9e\xa7\xba)\xb4<\x87+\x84Zd\n5\xcf\xd3\xe4\xc3J\x91\x19\xe9yA\x95\xc8cP\xf4r\xb5\xc5\x08\x9a^\x0cQ\xcf\xae\x01\xe9S\x80\x0c\xae\xdf}\xea\x8fx&\x90\xef\x1e\x94\xf2c\x0c;\xc8w\x97W\xf5\x11\xc9\x18\xf2\xdd\xe0Q|\x8cb\x11Mo\xc4\xec<\xe4\xd2z\x1c\xe5t\\\xcd\xeca\x19\x97\xbe\xe7>\x14\xf7r\xb4\x80~\xe2W\xe2c\x8e\x16]\xbecr4G\x0bh;>\xfc\x1a\x8e\x08\x078\xfd\xc6\xa0#\\w\x9cS\xb9q\xec\x92\x0f\x7f\x0b\xaa6\x06\xeb\x83\xd3t\xc3\xe85fy\x14B\xa9\xb1\xf7\xc8\"AH\xa51\xf8=`\xbe\x08\x84>c0\x18\x80\xd2fD\xb8\xc15\xc8hUF\x84\xf6b^\xe5E\xa4\xeeb\x8a\xea\"Rs1\x18lL\x03F\xa9-fxR\xf8\xb5\xe7SY\xb4\xf7@\x11rt(5\xba\x99\xfe\xdc\xcc\xdf\x87\xf7\xafH}\x8e\xd4\xe7\xb2u\x87I\xe4=R\x9f\xc3P\xf6\xb2\x10\xf6R\xe8z\xa4>\x97\x91\xa4\x17C\xd1\x8b\"\xe8\x91\xfa\xdcRZ^\x02)/\x0b%/\x9e\x90G\xeasK\x88x14\xbc\xcc$<\x1c\x05/#\x01\x0fK\xbf\xb3\xec\xac\x93\xfa\xdc\xd4\x10\x84;\xec,)\x9alG\xeas(\x8a]\n\xc1\x8e\xd4\xe7\\\x97\x05Iu\x11\x94:\x8c\xb6Z\x0c\x9d\x8e\xd4\xe7H}\x0eC\x9a#\xf59aKhr\xa4>g\xf3\x14$\xc6\xa5\xd2\xe2\x9cc\x03\xa9\xcf\x1d\x1a\xa9\xcf%\xd0\xdf\xc2\xe4\xb7X\xea[\x04\xf1-\x9a\xf6\x16Gz#\xf5\xb98\x9a\x1b\xa9\xcf\x0dv\x0cj[\x8e6\x17Ak\xc3\x93\xda\xa2\xd4\xe7J\xb3\xe7\x9e\x9e\xf25^2\xc1\xc3\xe4n?\x94\x9b\xb9\xd2\x9c\xd9#\x95\xe2\x98\xb0I78\xaab\xf4\xed>U\xedd\x89$\xc6\x99\xc2\xc8;\x8f6\xc6ku\xc9\xa0\x8dQ\x08\xc1\x17\xf5G\x81\xfbue}U\x1d\xd6z\"\x8c\xa1\xdd<\xd1U\x7f\xa4\xc2\x18\xbaf\x8f\x03\xcb\n*jD\xed\xe5x\xce7\x1bD\xba\x92\x1f\xe3\xe7!\xf8\x82'\x8d\xce\xc5Dl\xa5E30\x82\x85\xff\x0d\x9d\x8b\x89 \xa2\xea\x86\xc6\x08j\x8e\x8a\xfe\x02\xe4s\xf8\x9f\xd7R\x9aI\xeb\xe99\x0e,\x14W\xf6\xe5\x8dcV\xef\xe2]\xd1\xc9\x92\xc2\xe8d\xc9\xdf\xd5\xc9\x92z\x12\x10C\xe5\x99M\x1c\xb4\x11\x95G\x1aQy\x88\xca3\x1aQy\x88\xca3\x1aQyz\xa2\xf2\xd8\x8d\xa8<\xda\x88\xcaCT\x1e\xa2\xf2 gID\xe5\x19\x8c\xa8<\xa6\x11\x95\x87\xa8<\x16#*\x8f\xf5\x1a\xa2\xf2\x10\x95\xc7aD\xe5!*\x0fQy\x88\xcacX\x0eZ\x05Qy\x84\x11\x95\x87\xa8<\x8f\x97\xcaCG\x94\xa5\x9e\xffDG\x94\x1d1\xb8\xe16JG\x94\xe5\x88\"\x1dQ\xf6{?\xa2l\xe0c\x9e\xfd:\x10\xf2|\xe7\x96\x19\xcdA\x13\x9b4KSq2\xf51\x9be-K\xcb\xdf\x89<\xc5D?\xf7\xfc\xf580\xab\xab_n6\xad\x8f\xc4\xa9~z\xec\x1cN\x17\x87!\x89 \x15db\x067\xe2\x83\\\xa0\x00\x073\xf0\x00\x1f\x17\xb1\x0f\xb0/I\xed\xcaj\x91\\K\x04\xa32/\x9f\x12\xc9\xa6\x8c\xe7R\x86\x03\x94\x99G\xe9eQ&+G\xa9B&\xb0\xcdf\xde\x88l&\x8d\xc8fy:\x16\"\x9b\x11\xd9\xccnD6\x13Fd\xb3C#\xb2\x19\x91\xcd\\Fd3\"\x9b #\xb2\x19\x91\xcd\x88lFd3iD6#\xb2\x19\x91\xcd\x88l\xe62\"\x9b\x11\xd9\x8c\xc8fD63,\x07\xf1\x87\xc8f\xc2\x88lFd\xb3\x7f\x06\xb2\xd9\x80;\xbb\xca?\\0;|OB\x80\n\xd8c\x1d\\\xb6\xcdvR\x8f.cE\x16\xf1*\xc4YY\x1e\"\x85y\xd4\x96fP\x88!Bl\x9dO\x8f[\xbbizfeG\x18N\x9e\xe8\xfa=R\x86\x84\xa8WV~\x84\xe7\x80\xb7\xc0\xae\x91\xf7`\xb7\xc0\xbd\xee\x03\xdd\x027\x86\x0fr\xf3:\x08o\x14\xe5:\xbc-\x19\xfc6\n\x10\x03\x80\x7f\xb2@#\x04\x7fK#\xf8\x9b\xe0\xef\xd1\x08\xfe&\xf8{4\x82\xbf{\x82\xbf\xedF\xf0\xb76\x82\xbf \xfe&\xf8\x1b9K\"\xf8{0\x82\xbfM#\xf8\x9b\xe0o\x8b\x11\xfcm\xbd\x86\xe0o\x82\xbf\x1dF\xf07\xc1\xdf\x04\x7f\x13\xfcmX\x0e(\x92\xe0oa\x04\x7f\x13\xfc\xfdx\xe1\xefEp\xf2M\xd33\xdf\x99I?\xf3\xdf\x07 Y\\-A\xe4\xab\xf2\x86\xd5\x07\xf5\x9c\xa0\xc8\xe2\xde'\xba\xa6\x8f\x14?\x16Uz\x1c\xb8U01?j\xdf\xc6sP\x07\xafs\xfa\xf1Hr\xe3\xddu;f\xe7\x05d\xdau\xcb\xd6E\xcf\x1b\xff\xfb\x96]\xf2 \x9a\x84\x1b~\x91\x0f\xe8~\x81\xb2\xeezVl\x14\xa8u\xe9\x9cS\xc1 \x8d\xc1{F\xd5X\xdd\xbd\x94X\x08m\xe4\xe4\xb1\xbc\x84_*V?S\xcf\xfc\x16\xbe\xff\x1e\xbe\xfbEML\x8b^U\x96\x0f\x1eNw\xb7Ll\xe6}w\n\xe75\x14\x95g\xa3Sn\x1f\xae\x8b\x8eu'j\x93ULmf\xb2.\xce\xfb\x7f~\xf7\xe9\xcd\xea\xdd\xfbO\xe7\xef\xde\xae>\xbf\xfd\xf8\xfe\xcd\xab\xf3\x1f\xcf\xdf\xbcv\xad\x0b\x82o\x12\x80\xd5{\x8f\x92\xc1s\xd7\x13\x91w\xfc\xeb\x9b\x8f\xc8+_\xfe\xf0\xf1\xd3\xcb\xf3\xb7\xc8\xab\xdf\xbeC_\xb8\xfa\xeb\xf9\xa7?\xaf~~\xf3\xc9u\x8bF\xff\xa3\xaa\xaaZ\x8b\xff\x13z\x1cG\x84\xf9\xbfVi\x88\x86\"\xcd\xdf\\\xa4\xc57\x1a\xdb}\xbe\xa6c\xbb>\xd4\x80l\xf7x\x9a\x91\xfd\xf2`c\x92\x96\xd4\xa4\xc6\x9bq\xfd\xa74>\xc4\xbe\x93]\x14\x13\x02_E\xaf\xa6$r\xa7\x9d\xf7\xf4\xba\xb5J\x8eN\xc0\xa1\x1c\xd6G\x1e\x8f1\xc2\x07\xeet\xbfxg \x0c:Q\xddo\xfe\xfc\x1f\x1eg\xdd\xae*\xfbT<\x89\x97\xc0x\xb6\x0cY=a\xc5\x85\xbe\xa6\x97\xd2\xc9\xba\xa9\xbb\xb2\xd3g\x92\x0et\xcd\xf3\xd7'\xf2\xd3\xe6\xd3\xb7\x13\xbdy\xe6\xae\x93\xeb}M*#\xa7\xf4\xfa<4\xeeO\xce\x9fd\xdfq\x80-\xd2i\x7f\xc2\xe8\xb4\xbf\xdf\xd5i\x7fb%\x1b\xc3=\x95\xcb\xe6\x0f\xef_\xcd\xbc\x11\xf7\x94\xb8\xa7\xa1\xd1\x0f3\xd6\x00qO\x89{\xea\xbc\x92\xb8\xa7\xc2\x88{zh\xc4=%\xee\xa9\xcb\x88{J\xdcSa\xc4=%\xee)qO\x89{*\x8d\xb8\xa7\xc4=%\xee)qO]F\xdcS\xe2\x9e\x12\xf7\x94\xb8\xa7\x86\xe5\xe0\x01\x12\xf7T\x18qO\x89{\xfax\xb9\xa7\xd6\xd3\xbf\xe8\x9c?\x08\x87\x91\xce\xf9;bp\xc3m\x94\xce\xf9\xcb\x11E:\xe7\xefw\x7f\xce\x9f` \x9d\xfd*8I\xbe\x03\xfe\x9e\nf\x93\x99H\xb0\xb1\x1c\xe5\xd7\x8c)\x05\xe7\xafO$\xd3I\x9c\xe1\xf7T\xf9;H0x\xa2c\xf1\x88\xf3\x0b\\\xd4\x84$jS0K \xb8\xbf\x1e$\xf7x\xf2\x03\x02\xce}lc\xcc\xbexr^\x00\x94.`\x06\x97\x15\x905'\x00\x9b\x11\xb0,\x1f *\x1b \xd8(|\xd4\xeeXJ7\x96\xca\x1dC\xe1FR\xb7#)\xdb Tm/\xf7\xbf\x0f0\xff\x1f\xe2x\xca0\xe3?\xd8\x18\xa4\x85\xd9\xfe\xb1\x0d\xc3vW\x88\xe9\x1f\xd3Hlw\x04X\xfe\x91\x0dFZB\xb3\x19o\xc5\xf4\x82\xd22\xb3\xfb\x93\xb9\xfd\x0f\xca\xec?\"\xaf\xff\xa1X\xfd\xc7\xe2\xf4?8\xa3?\xcc\xe7Gt%\xd8\x16\x9f\x91\xc9\xef\xe0\xf1\x87K\xb2\x98\xc3\x9f\x93\xc1o{;H\xb2r,W\x99\xa8\xcaDU\xb6\xfd\x9e\xe9\xd3&\xaa2Q\x95\xedFTeaDU>4\xa2*\x13U\xd9eDU&\xaa\xb20\xa2*\x13U\x99\xa8\xcaDU\x96FTe\xa2*\x13U\x99\xa8\xca.#\xaa2Q\x95\x89\xaaLTe\xc3r\xd0F\x89\xaa,\x8c\xa8\xcaDU\xfeg\xa0*\x0b\xf4\xcdUv\xf1\xe3\xa4\xd4\xe2\x0f\xeah\xd8\x01:\xdb=\xe0\xb9\xb0\x82\x86\xb7-\xeb\xfe\xec\xe6\xbb\xb3\xa2\xae\xf7E\xb5\x123\x94n$\xa2\xd8(w/\xc5\xa5\xef\x87+\xf5\xb6\x14p_\xbc\xf7\x94\xbe`\xf4%G8]\xa5 \xd7n\xee\xec\x89\xae\xdf#\xe5\xdd9\xe2d\x9aww\xc7\xbb\xaf\x13\xde79x\xbcFb\x83\xef\xc0\xe2l\xf2V\xa4\xf9X\xf5\n\x07\x9e\xbf1\x14&lstv\xd0\x90\xe8\x18Ui\x84\x0f\xfb6G\x8f\xb0\xb5\x8a\xea\"\xcb\xfa\xb22$\nm]\xe3\xb9\xbeD1\xf6\xed\xdf\xe6\xe0\xc8\xd3/\x0e\x9e\xd4\x8f\x8f\xb6C\x9cE\xc5\xb4L\x1d\xe1\x18.G_\xe7\x88\xa7\xc5\x95\x9d\xd92\xc4:\xbd+\x1b_\xfc\x87\xf7\xaf\xe634\xea\xd2\xa8K{\x9c]\x9a\x98\x90{\xa6z\xef\xc5\xef\x93\xceL&\xa8\x88\x9c\xac\xcb\xe1\x0b\x1c'\xf6\xd6\xce\xec/e\xddKW\xea\xd7G\xdb\x9b\x99\x011m\xba\x0e\x91Q\x99\xea\xcf\xea\x00\xe85\xc8\xb6\xd9\xec\xab\xbc\xea\xb3<\xda\xab\x0d\xab\x1b\x07}:\xd8P\x94\xb6j\xaf\xe0\xaeuS\x8a\x05,\xf7k\xb9~\xe8VWm\xd1\xb3\x95\xc4\xaf\x97=y[\xdc\x95\xdb\xfdV\xcfN\xa5K\xbe\x9e\x1e\xbbp\xfe,oa\xb6\xc5]\x9eB\xc4<\xb3t\x10\xdf\xd1\xcf,k\xdc3\xaf\x9a\xa2Z]4\xf5\x86\xa5\xa6\xe1\xa8'rG\xfc%\xefX\xbb\xe6\x83\xa5\xf4 E\xdflmk\x81\x8b\xaaY\x7f\xe9V;\xd6\xae\xeeY\x91\x96\xa5\x83H\x01\x1a\x8a7\x0co\xf2\xc1\xbc\x98\xc0\x1f<\xb9\x071v\xcbn\x055p\xab\xa1Z\xf5i\xc4L\xa5a\xda\xf2\xfb\xa3\x1a\xa6\xe5@\x83\x19\xa8\x8d\xa5\xbaj\xdf:%\xb2\x18)+\xc3 %\xe9\xe3r\x84:Q\xf9\x1be\xdfA\xb7\xbf\xe8v\x85\xa0\x91\x8d\x9bp_\xd8\xbduP\xff'\x1a\xd01\xe3\xf9d8\xd7Z\xf5C\xc4\xb2\x8e\xe3:\xccI\x9dl\xaa\xfa\xbc\xa7\xed:\xefL\xea\x7f\xa9\xef\xa5\xbe\xd7~\xfbc\xeb{}p\x84\xfeF]\x0dp\xe8*\xcdnC\xf6\xa8|J=\x9e\xad0v\xba\x97SZnJ\xea\xfd\xac\x86\xba\xb0\x1ee\x94/\xec~RD\xfe\xdf\x1a%\x19J\xa6Pv]\xa7\xac\xa5\xf4\x0ep]Ut\xd7e}\x85\x19\xe2f\xe3\xda\xe1\xaaK;S\xafA\xdd?\x19\xb3>\xaaK\xfe\x89\xc6.\xe7\xf7\x9b6\xf4\x94W5\xdb\xac\xd4l\xff\xb6\xac7\xcdm\xe4\xa0\xa0\xcd\xe8\xae\xacS\xfdmY\xaf\xd4\xe3\xf8\xaa\"\xcb\xb3\x1cl\xd8Ms[\xf7\xe5\x96\xad\xfeV\x94\xd5j\xa3\xc0\xcb\xa4g\x89F\xb4\xba\x14\xc9\x1fM\xbd\xda4\xfb\x8b\x8a\x89z$\xb9\x0b\x16\xfd\xe0y\xb2&\xc7xX\x18]\x1a\xb6{\x14\xb6~\xf0\x95\x0d\\\xf0\x0b\xd9\xb9\xe9O\xce\xf6\xfa-\xfb\x1f\xae\xb3]\x8e\xb3\x92\x1b\xfeH\x93\x89\xe9o4\x998\xc2d\x02=\xce\xf1\xbe\xa4\xac\xafVe}\xd9x\x86\xbb\x8f\xf2\xb2s~\xd50\xe8\xa9{\x85\xc2\x8dX\xc4U\x95$\xf5\x17}\xd3\xea\xf1l:\xe2\x19n\xd4\xef\x8fv\xbc\xe3\xb5z\x1c\x0dL\xd12\x92[\x08\x1f\x87\xd8f\xb5\xaf\xfb2\xbd\x91\x8e\xcdlS\xf4\xec9\x1f\x16\\\xae\xd4\xben\xb9e]_lwc\x9b\x80uQ\xd7\x8dH\xff\xd8\xd7\xb2T Je\xff\xae\x9a\xedE\xd77\xb5k\xefQ\x17\xfaP\x01\xca4\xbb\x1a\xd4\xdcB\xe7| \x0d+\x91\xf0#\x12\x10{\x9d\xbe\"ju]tp\xc1Xm\x94\x18\x9e})\xab\xca\x97\xa7\xb6\x97\x99\xfe\xda\x89\x9bG\xd5\xb1\xde\xceP\xde\x96]7\xce\x9e\x84`\xd7\x82\x03\x8f\xc3S(@\xc5I\x96Jo\xa4\xaaR\xc1\xb3!\x95\xae\xe3m@\xeb\x18\x8a\xef\x08\xd8\x0d\xf3\xe4\xab\xf2vd\x0f\x80`1\xad:\xd6?l\xe5\xaf\x9b[\xd8\x16\xf5\xbdl\xe1\xa2\x1ec[\xf8[#\x8f\x18l\x14\xc7j*o\xa8-<\xf9\x01\xf8Y\xfb4:MS\xb5A\xff\xfct\xd6\x11\xbb2p\xb7M]\xf6M\xabB_:Z\\U\xde\xb0\x9au\x1d\xf0)\xe0M\xd9\xdf[\xf6\x9ad\x18\xc4\xc3\xd4\xbc\x085\x12h\xf3\x9d\xae\xb8`1A\xa7!\xd2i\x88\xd8\xd3\x10\x01\xf5\x0d\x9a\xea\xac\xb2V\x13RoY\xc3\xd5\x87\xf7\xaf\xc6E\x81\x9a\xc9v|\xachm\x8d\xc8\x91\xf1\xbenZ\xe9C\xa8\x03\xb4\xb2\xf2\x03\xff\x96\x8f.b\xa5cF\xc6\x1a\x0e}\xc7\xc7f;\x96\xdb\x9bG\xd2\xb2\x1d\x13\xf9y?\x14\xed\xf0\x92\x02\xa4\xf4iXD\xcbt\xd1\xd2\xa7)1\xde\xf5\x9693D\xad\xbalN\xce&\xd3T'\xf7e\xf8#-\xc5\xa6\xbf\xd1R\xec\x08K1/\xcd\x9c\xf4\xa4\x83[\xb6\xe0\x1a\x9cIO:op\xc3J\xc8\xa4'\x9d#\x8a\xa4'\xfd\xdb\xd7\x93vn\xb1\x9d\xfd\xban\xean\xa5\xb6t|Z\xd2\xe6\xb2\xcf\x84\x99\xe6k-I\x98X\x0b\xf9\x1c\xe9Uyr\xed\xbc=\xd1\x81x\xa4\x1bo7E\xb52c\x96u\x95\xe8\xddK\x0b\x0c\xf0\xe1}\xb4\xe0\x0c\x01\xb7\x87\x96g\x07-\xb4\x7f\x16\xde=\xc3\xec\x9d\x85\xd6\x84i\xfbf\xd0\xec]\x12u\x98]3\xc7\x9eY\xc4\x8e\x19\xfaM\xa6\xaf\x963\xef\x94\xb9\xf6\xc9\x90\xbbd\xf9*\xbcx\x7f,\xbc2\xcf\xbb7\x86\xd9\x19\xc3\xef\x8bY\x0b<\xef\xd3\\\x1bgj\xf1\xcf6\xfc\x0e\xd1\xa9\xbb\xfb\xb0\xc9/\xd8\xc5u\x96\xb55-\xadiim\xfb\xfd1-\xad\xcdi\x96\xab\x11\x9a\xd7\xe8\x0fB\xff\xe7@\x9b\x9a}\xa2\x86\xaf#eB\xab\x19d/\x84\xfa\xf8\x04r\xc3*v%fr\xdd\xd9\xaf\xea?\x9aV\x14\xdc7\x814\xfa\x82\xd7\xfa\xa6\xd7\xa3\xab\x91\x93+\x96M\xe3\xdf\x05\x1dW\xce*\x87\x87\x0d\x9eTx\xac\x1c\\\xdbS\xd4u\x8fv\xb29V|e)\xa3\xb6\xaf\xf1\xc1\x8d%\xf3\x7f4\x8b\x8fR\x98\xb6(\x0f\xd0\x0c\xb8\x0f\x15PC\xb8y\xed\xec\xf9\xfaS\xbc`\xeb\xeb\x7f\xf9\xe3sV\xf3\xcex3|\x99\x1e\xc5dn\xbdP\xa0Q.\x0fGim\xc3\x1c\xe1+\xd5\xfa\xe0\xf9\xcbk=\xb8t\xd7\xba\xbb.Z_[H\xab\xaa\xf4\xaa&`\xe6\x0b\x10\x1a\x95\xf2\xc7\x96\xadYy\xc36\xae\xb2ac7\xf6-sf\xd8ES+\x95\xcc\xbe\xf9\xc2\xea\x0e\xaeY%\xc4\xad\x9c\xa8?@\xb1\x16\x93b\xb5\xd9\xe0\x06\xe1\x9b\xdbZ\ne5\xb5\xd1\xba\x948\xa9\x90\xe7m\xd6\xa5@Rd\x01<\x12\xb47\x8dLRln\xe5\xceJS{\x94?\x03\xaf\xf4\xa2\xa8\x8a\xdaE\xdd\xcf\xd8A8\x93\xfc\xa4\xa1\xdaL\xb1\xe5\x91^\xe8\x06\xdbJ^5\xa5y\xb0\x82h\x10J\x8bSVGo\\\xf1\x17X\xd4\xaap>\xd9\xd7\xb7\xef>\xbdy!\x04\xb4\xe4\xb5\xc3\x89L\xfc\xf6\xf3\xbaW\x1a=\x83@k\xe7m\x04J\xc0GM\x9a\xdd\x9fkyU\x17\xfd^~?rf\xc1\x1b\xe1Us\xd5\x08u\x1c[\xab\xc0\x84h\xfc\x88\xcc\xf5\x00\x7f\xc2MQ\x89M\xeb\xc6\xfc\xd0\xd8\xdd\x9a\xed\xe4\xae\xb8\xd5]\xd9\x1b\xd2\xa9\xf6\xda\xa8\x96:W+R\x9d\x83\x8a]\x07\xdb\xa6e\xd0\xed\xcb^o2Z\x9d\xad+\xb1\xb3>\x0c\xd8\x87a\x08\x07\xc16\xf0\x8f-\xa6\xaaf\xddX\xf7t$7\xb8\xbd\x1d~\xa7>\xb2\xc3,\xedg\xd8L\x9d\xa6\xf2\x1a{\xac\x93\x15[\xd6$ \"O\x10y\x02K\x9e\xf0a\x93j\xb3\xc0\xb6\x12\x08fe\xd9\x1c\x9dYW.\xa4\xcc#\x8d6\x1c\xf2\xcc\x16\xe8\xe4\x16:\xb9\xc5ntr\x8b0:\xb9\xe5\xd0\xe8\xe4\x16:\xb9\xc5etr\x0b\x9d\xdc\"\x8cNnq\xb7i:\xb9E\x1a\x9d\xdcB'\xb7\xd0\xc9-\xc2\xe8\xe4\x16atr\x8b0:\xb9E\x1a\x9d\xdcB'\xb7\xd0\xc9-tr\xcb\xdc\xb0\xa7h\xd0\xc9-\xc2\xe8\xe4\x96\xdf\xc3\xc9-S6\x91\xe1j\xb2\x98\x9c^5A\\\x87\x9f\x0e\xa9\x80\x16\xcd\xb4\x05\xfc?J\x03L\xcd\xb1\xa24\xc0#\x067\x9c\xc0Fi\x809\xa2Hi\x80\xbf\x834\xc0\x03\x12w\xd3\x1er\xb8\xcfZf\x12\x8d\xa4;\x1b\xa3\xfb\x83y\xdd\xc0\xdf\x9e\xdc=f\x04\xfa\x98\xda\x13GOtD\x1e)E\xdb\xac\xdfc#i\x9be;:\x0b\xf3\xf7M\xd3\xee\xda\xf5W\xaa\xb9\xb5\x0c\xba\xf6cj\x9b\xd9\x16\xbc\xfe\x14\xcdD~\x91\xe3<\x13\x13\x84M\xd7\x7f\xf5 \x18eX\x10\x84\x0d\xebz=l\xe0#\xc1\xea\xbe\xf5~%\xfen`4g\x870\x1a\xe2\xbb\x95\x86\xf9z\xa5\xad[&\xbb\xb1kV^]{\xc9\xd0\xd2\x90/RZ8C\xd3\xb4\x98\x97/mVz\x98,\x9b\xd4\xdf\xe4z\xd7\x0f\xe4k3\xdb\n\xf4M\xf3\x05v\xd5L\xf0\xd9f\xeb\x86/uEA\xdc\xe2\xb4\xa6%\x051\xa4r8ZB \xa75\x98\x1f\x1fz'2g\xbd\x84\x9c\xd1&A\x1c\x1d\x87\x82(H0E\xb5\nd\x10\x8c\x16\x15\xc4\xf8\x90\xcc\xca3 \x89\xfaMs\xc8\x11\xde\xc4\xccp\x12\x99\xae/\xda\xde\x9d}\xa2M\xf2\xd1y\x17\xf7\xd5#2\x16eHM\xdc\xaa\xa99\xe2n\xa3{}>\xf6\xce\x8an/>d\x01\x1f <\x99a\xf4\x87/\xae\x8e\xe6\x1c\xf4M\xdd\xb7\xf7F\xbe\xc6\xe4\xd5!z`\x90h}\xcb*vS\xd4=lY_l\x8a\xbe\xf0\x95wRZ5\xae\x08\x1a\x93\\9\x19\x05P?.\xcd\\\xfa0\xfdR\x8d\x9d\xef\xaa\xecz\x99v\xb9+\xda\xbe\\\x8bm{\x97\x9ba\xd2\xf4\xd4\x9c\xfa\xd7W\"\xff\xc9\x93\xc2t\xd96\xdb\xc9\x13\xf4k\x1f\xae\xd3\x9d\x86\x87\x1c\x9c\xf348\x139\xc3c4\x0f\xe6#:\xa8\xf6\x03\x9fl%P7<\xda\xb4\xe21\xf2\x8f,\xa7x\xdaD<\x99\x9e\x08$\x06\x03f\x80\xed\x99\xc1\xe4^/n:\xb8s\xe2K\xb8\xb3\x972\xd60\xfe\xbc%o\x0d\x7f;i/Q9'\x88\x17\"\x0d\x9fk\x82}\x81\xd2\xe69&\xa5=\xbbd\xfc\xba\x03\xfepi%Q)%\xd11\xc2\xa5\x92D\xc6i\x96BRZ\xb2G\xd0A\xc2\xa5\x8dD\xa5\x8c\xa0\x83\x14Wm_\x9a\x88:\x15L]\xe2\xe1\xfeH\xe3\xc3\xccf_Ij\x89:\xbd\x0c\xf8\xa2\x00\x15\x8c\xaf\x19\x04O\xe5'U\xc9\xf0\xd6\xf1\x05\xb3L\x11fY\x1d\xb51O \xe6t\xc4\xe5sxs=m\xb3#_\xce'\xa6\xce\x96\xdaB\xd77\xad\x9a\x90\x89\\O\xbe \xac\x98\x99\xcfiu5\x16\xcf\x93\xe0\xc9\xbf\xe6\xc1\xe3\xb8\x99Q\xd6<\xac\xfc{\x7f\xde\xb4\x1b\xd6\xb2\x8d\xc85\xa5\x84\x01\xbb\x07J\x18\xf8=%\x0c\xcc\xbfQ\xfciU3o\x16f\xaa\xcc'\xf0>\x81N\xb1RF \x05yV8\x94P@ \x05v\xa3\x84\x02a\x94Pph\x94P@ \x05.\xa3\x84\x02J(\x10F \x05\x94P@ \x05\x94P \x8d\x12\n(\xa1\x80\x12\n(\xa1\xc0e\x94P@ \x05\x94P@ \x05\x86\xe5 wSB\x810J(\xa0\x84\x82\xc7\x99P@T\xf68\x9e0Q\xd9\x8f\x18\xdc0 \x9b\xa8\xec9\xa2HTv\xa2\xb2+*\xfb@;\xf2\xf1\xd7\xff\xc3\xc2_\xffy\xb8q\xc2Z\x1f\xfdAY_6\xe2-\xc9\xa3\xad\x86'\x0f\xbe|,\xf5\x8f\xb2\xf8\x96\xc7\xa9\xab\x1f-E}\x8c\xc0\xe3 3\xe8sz\x1e\x90\xb6=\x7f\xe4d\x923\xe5j\x8f\xe1r0\xe9L\x7f\xff]\xf0\xbeA\xb3\xbe\xcbZLf\xed\x8b\xb65\x7f\xbdu\xb7\xefV\xbb\xfd\x85\x93\x7f\x16\x8c. \"\x0c\x08\xca\x08\xe0\"\x0c\x11Q\x86\x04\xfa\x88\xd7\x99\x1dC\xf0l\xa9\xe5\xa6\x91@\x98J\x02 t\x12\x7f\x05\x8a\xfe\x1aM)\x81\\\xb4\x12H\xa4\x96x\x1d\n%k,\xbd\x04\x96SL \x9af\xe2u\xa5\xe0\xef(\xaa \xe4\xa6\x9b@$\xe5\x04bi'\xfe\x96=PR\xb0\xd4\x13\xc8M?\x01\x1c\x05\x05r\xd2P`1\x15\x05\xd2\xe8(\x90\x8b\x92\x02I\xb4\x14\xff\xe7P\xf0e_\x90\x9a\x02\xc7\xa1\xa7\xc0\x11)*p\x1c\x9a\nDRU \x8d\xae\x12\xea\x82q\x94\x15\xc8K[\x81\x08\xea\n\xc4\xd3W \x81\xc2\x82\xe82\xbfE\xd0X \x07\x95\x05Bt\x16\xc0O\xcf\x10\xb4\x16\x88\x9c\xc5E\xd3[\xbc\xde\x04\xf5\x05Aq\x81\x88Rf\xa4\xba@\x14\xdd\x05rS^ \x91\xf6\xe2oW]\x98\xfa\x02\xe9\xf4\x17\xa7?\xfe\xc4\x10\x05\x06\xb2\xd1`\x00\xcf\xe6\x00\x0c\x1d\x06\xe2(1\x10\xc2\xb0\x13\xa91\x80\xf0\xeb\x81\xc92\xd1d )\xb8x\xba\x0c j\x99@\x9b\x81T\xea\x0c\xf8\xa3\x9a\x8fB\x03x\x1a\x0d \xa94\x80\xa6\xd3\x00.\xea\xf1\xb4\x1a\x88\xa2\xd6\x80\x97^\x03\xb9(6\x10K\xb3\x81\x85T\x1b@\x847\x82r\x03\xc7\xa0\xdd\x00\xa6\x8c\x9e/!\x1f\x05\x0704\x1cX@\xc5q:\xecE\xc6\xae\x9b\x8e\x03\xb9)9\x10\xa4\xe5@*5\xc7\xe9M\xaeQ\xfd\xcbu\x04E\x07\xbcL\x02\xf0Ru \x89\xae\xe3t\xe5\xa5\xf1@*\x95\xc7\xe9M\xce\x03=\xbbf\xf9(=\x80\xa2\xf5@\x02\xb5\x07\xe2\xe8=\x90B\xf1\x81h\x9a\x0f\x04F\xdb\x00\xf5\x02\"\xe8\x17X\xca\x0f\xa4\xd0~ \x96\xfa\x03\xfe\x8a\xa7P\x80\x9c\xce\x0c\x82\x0d\xf6\x93\xc1Q\x81\xbc\x1fD}\xe5\xa7\x03A^J\x10\x84hA\xe0\xa7\x069\xefI\xa5\x0cA\xc6\xb6\x1bA\x1d\x82(\xfa\x10\x18\x14\xa2\xa9\xfd\xad(+\xb6\xf1\xa3S\x87\x88\xb0ivtxn\xd8\x95\xbe,\x0f\xe8D\xfd\xdbk\xa6\xf6{L\x89\n\xfe\x1d\\0V\xab\xab\xdd\xed\xa0m\xb6B\x01\x83m\xa0\xeb\x8b~\xdf\xc9M\xf1\x031\x0bi\xf2\x12W,\xb05P\x0f*\xe7\"\xa1\xf2\xef\xce\xdb\x9e\xc9r\x8e\xe2n\xea_\x02\x04\xb1\xdf\x82\xd81b\xf5~\xeb\x9e\xc7?\x87\x1f\xde\xbd}\xbd\xfa\xf8\xe9\xe5\xa7\xcf\x1fW\x9f\xdf~|\xff\xe6\xd5\xf9\x8f\xe7o^\xa3\xef\xe0\xff\x15y\xf9\xf9\xdb?!\xaf\xf7:\xd7\xaa\x07QU\x90\x8a6\x0f\x00A+\xe9\x1c\xd9\x8c\xc1 \xd7\x89\xddx\xf1\xdb\xb3\xb2^W\xee\xe9A\xc7\xaa\xcb\xe7\xa3\xb8\x8c\xa3\x11\x8c|\nyV\xec\x03Tm\xfe\xc8\x11]\x17\xdc\x16\xf5\xc7\xb2\xeb\xf6\x12yp\x0fX\x06\xf6>zul\xa1\x9a\xa5[\\\x81\xe1\xba\x19\xfdq\xfc{\xcf\xdam\x07\xf6s?G\x0b\x08\xbaeC\xf7\xb7M]~a\x16U\x8d\xd1\x10/\x18\"b\x04\xe3S\x8d#\xb4\xaf\xf7\xdb\xa2~\xde\xb2b#(Pb\xde\x17\x8a\x11`\xe2\x04\x8a'\xd0;y\x12p\x9c:\xea\xc7\x9a\x8aR\x1a\x05\x1d\x7f\xec\xca\xab\xba\xe8\xf7-\x83g\xec\xce\xbf\x94\xfe\xfc\xbei\x05\x9f\xf1\x7f\xb3\xfb\x8b\xa2c\xce\xce\x1b\xe0\x96]te\x9f\x03\x13\x98\xd4X\xb9\xb5\xd6H\xffV\x95\xf5\x17_\xd7\xb3\xde\xb7e\x7f\xbf\x12+\x9a\xb5W\xde/\xa5\x84\x81w2\x7f\xbc\xb5&l[\x94U\x10J\xd7\xae@\xb9r\xd7\xd9)\x003ZJU\x95[=\x10H\xf0j\xa8\x84\xfa\xd5^\xaaQk\xd4/\xb2\x88(\x16FX\x11\xfb\x86\xe6\xc5\xd2o\xe7\x04\xca\xcb\xf1\xc7\x13\xd1\xa3\xaa+<\x94\x1b-\xbeXv\x07\xd3\xbb\xab\xbd!\xee\x16\n\x91Oa1\"@!U\xc5\xf8 \xddDO\x88\xb6e=h+:\xddM'\x92}\xa3e\xf6X(@\xebf\xbb-\xbb\x0e;h\x8e\x97O\x06F\xe3\xcfc\xfe\xc1\x91\x87\xbc\xf1\x99\xab\xb6\xe8\xfdj\xa4\xd8\xb7\x02\x16\xbf\x93\x8a*\x99G\xe3\"\xaf/\xe9@\x12\x0f\x06\xb0\\\x8a\x8d\x8aU1b\xd8C\xc5\x0b\x901\x03U\xa6\xd0\xc6=\xe2\x83\xd0\x16\x13ZP\x8f\xd7K\x1f\xa3\xd9\x88?\xaf\xaf\x8b\xf6J\xcc \x83n\xc6\xd9\xe0 \x88\xb4\xa7KA\xf2\xf2\xcbg\x02l\x8b\xbb\xd5W\x0e\x80.\xc2\xa4]m\x8b\xbbr\xbb\xdf\xce#\x12t&{\xc7\xf1\xcb_\x175\xb0\x1b\xd6\xaaPF\xc7F\xb2R\x1eC\x88\x8c\x92X#\xb5)\xca\xa0\xd8\xaa\xe0\xf1\xb7\xac\xe8\xd8\x01\x99\xd7\x88\xb4\x0cR\xd0U8\x88\xfb\x1d\x1f\x1d\x82Z\xbe\xc8\xc0aG\x1c\x88\x0c\xb0QJ\xfd\x1d\n B\xfc\xc1\xf6U\xde\x06\xc8x\xf2Mm\xecq\xd9\x96\xf5\x8a/T\x0d!\xfa\x05\xa30\xb6\x9e\x96\xa7\x1el\xb7<\xed\xc4\n\x1a6l]\x15\xf3\xf4\x89\x993\xd1\xe2\xd4\xd5\xda\xa1\xad\xbe\x98\xf2\x0d\x89\x02\xc6\xb2i(\xd4 \xf4\xcd\x95\xdc\xd0\x12`C\xaf\xf3L\xac\xae\x8a\xad\x91\x8fb\xdf\x80\xfc\xd9\xa8.\x9f\x08\xe8\xd5\xb7\xcaK/[`w\xf2\x05\xca\x97-\xa6\x0ee\xed\x18\xbc?VEw\xcd\x87.\x9d\x9d\xe4\xa2\x10\x17<\xac\xf2\xcbS\x18\xd6\xe41'\x92x(xpM\xdb\xba\x06\xb6uQ\xad\xf7\xd5\x00\xdd\\\xee\xf9\n\xcb\xfe\xc0}m\x1eB\xc0c\xd7\xec{({\x91\xb1Q_As#\xd6\xa9\xc3\x16\x02\xfc\xf5\x9a\xd5\xb2\xaa\xf6\n\xb4\xd3\x0d\x19\xfbS\xa7\xd3\xd2\x93Y\x17Sv|\xac\xdf\x94\xbd&\x87\x15F\xf3\xb1\xfa\xbb\xbdn:6\xa6\x14\xd9\x1fj\xbe\xc6\xb2\x9b\xd00\x8d\x16!\xaa6V\xc1\xeaiS\x0e8\xad\xdcl\x17\\B\xfbS'\xef\xef\x14~nDXw\xcd-ku\x1a\xa0~]l#\xb0Wg\xb3\xd5\xfb\xad\xa2\n\xf6\xa7m\xf7U_\xee\xaaR\x16n\xfa\xec\x83\x1b&_\x9d\x91\xdf3Q\xaa6\xdfL\xf7T\xe6\xfe\x08\xc1d\xe7\xa9\x02\xa4_,\x8c\xf4\x8b\x7f\xa3\xfa\xc5\x07oT\xe4\xe7Y\x12\xda\xbc\xaa\xc5\x96\xad=)SlK\xc4#qbi$N\x9cg\x9e\x17\x9b]&[-\x89\x13#2\xc9\xfa\x1cYd)\x19d$N\x9c1[,&S,*K\x8c\xc4\x89\x97f\x84%d\x83e\xc9\x04\x8b\xcf\x02#q\xe2%Y_1\x19_ \xd9^$NL\xe2\xc4\x81YRt\xf6\x16\x89\x13\xa32\xb5R\xb2\xb4H\x9c\xd8uY0\x1b+\"\x13\x0b#\xbd\x1b\x93\x81E\xe2\xc4$N\x8c\xc9\xa6\"qbaK2\xa6H\x9c\xd8\xe6)\x98\x15\x95\x9a\x11\xe5\x1c\x1bH\x9c\xf8\xd0H\x9c8!\x93)\x9c\xc5\x14\x9b\xc1\x14\x91\xbd\x14\x9d\xb9\x14\x97\xb5D\xe2\xc4q\x99I$N<\x18\x89\x13+#qb\x12'&q\xe2\xf1o\xc9\xc1\x0d\xcb\xea\x928q\x8e(\x9281\x89\x13\x1f\x88\x13\x9f\xfd:\xfc[\xfe\x96\xaaV<\x88\x15\x9b\xe7\xad\xdbu\x8a\xc7K\x06\x7f\xbb\xa2\x1cF\xba\x89\\\xf1\xe1\x83\xd4U\x8f_\xa6\xd8\xc5jHbK\xe1\xc4\x86\x83\xfb\xf3\x98\x0d\xee\xdc2\xc3\xf1\"\xc38\x89ao4!\x18Q@P>\x10\x11\x05tT!\x95\xf8\xe1\xf1\x17%*\x9c\x95\xfc\x11\xa4\x7f\xe4&\x80\xe0) \x99H i4\x10\x8f\xbbH\x19\xe1\x85T\x90\xdcd\x90H:HfBH\x1c%$\x92\x14\xe2k\xc3\x03]\x04K\x0b\xc9L\x0cAQC2\x92C\x96\xd2C\x92\x08\"\x99(\")$\x11\x8f3\xb4P\xf0\x11\x88\"\xc7\xa3\x8a\x1c\x85,\x12G\x17\xc9N\x18\xc1RF\xb2\x92F\xf0\xb4\x91h\xe2H(\xd7\x9b\x95\xa2\x12\"\xa9$\xd2T\x1c\xbe\xc22\xbd\x08\xaa\x8a_\xa2\xd7'\xd0\x9b\x9b\xb0\x92\x9d\xb2\xe2&\xad\xe4\xa4\xad`\x88+\xf1\xd4\x95(\xf2J\x02}%\x96\xc0\x12\x10\xdd\xf5\x97\x0eK)\xc0\xd2X\x12\x88,\x91T\x16OuS\xe8,\x0eW\x08\x99\xdd\x14J\x8b\xa7\xc9\x87%v3\xd2Z\x82\xf2\xba\xc7\xa0\xb6\xe4j\x8b\x11\xf4\x96\x18\x82\x8b]<\xd7'\x9d\xdb;\xd0\xca\xd10\xb2\xb9\xb8\xb5q\x8ad\xae\x90\xc6u\xf8\xc3\n\xe6\xfa\xe4rq%O\x92\xca\x8d\x16\xca\x0d\xee\xa5\xf8Drc%r\xa3\x04r\xe3\xe4q\xd1\xe2\xb8 \xd2\xb8>a\xdc`\xfcp/{\xa9$.F\x10\x17'\x87\x9b\xa9B\xb9\x84p\xf12\xb8f\xb9\x16\x15|\xb8j\x91\x00n@\xdf\xae_\x8e<\x07\x85o\x83\xaf\x12\xd0Q\x81\x8c\x92\xb7A\xe5\xbf\xb0\xdcm\xe6\x9ae\x16\xbaE\xcb\xdc\x06En\xe3\xeb\xb9T\xe0\x16/o\x1b_6\xef;\xc8&l\x8b\x95\xb5\x0d\x8a\xda\xc6W0Y\xd0\x16'g\x1b,PX\xca\x16\xf7>r\xca\xd8.\x11\xb1\xc5H\xd8\xa2\x83\xe2\x17\x13\x8c\x0dL\x8ct-f\x94\xc0\x0b\xd7\x86dk'5Y.Z\x9ba\xa0\xc2\xcb\xd5\xe2\xde\x02\xc4K\xd5J9Z\x8f\xbfEB\xb5\xc1\x18\x01*N\x80\x92\xa8\x0d6xm\xf8`\x02Z\x9c\xd6\x14\x9f\x0d8D\xcb\xaf\xe2\x84i\x8fT\xed\x18IZ\xd9\x97\x05\x1c\xe6\x10\xa4\x8d\x92\xa3=b`PB\xb4\x83\xd0l\xc0aP\x866\x18\x1a\x94\xc8,*\x1c\xb81\x01\xa2\x82\x96Y\\\xd6#-\x8b\x16\x96\x0d\xc6\x02W\xbb\x8c\x92\xb2hA\xd9p\xc9\xd2\xc4d\x95L\xa8\xc5\x9f[J6\xa7\x90,RF6ZD\xd6\x14\x8c\xb5W\xce-!\x9bW@\x16#\x1f\x9bW<\x16!\x1d\x9b$\x1c\xabEbm\xfe\x82\xb2\xb1i\xa2\xb1j\x7f\xd1\xe2\xcf-\x19\x8b\x16\x8c\x9d|SX \xccA\x01s\x89\xfc%\xa9_*#\xf5KR\xbf\x1c\x8d\xd4/I\xfdr\xb4\xac\xc9\x0e1\xa9\x0eQ\x89\x0e\xa4~\xb94\xbd!!\xb9!KjC|b\x03\xa9_.Ih\x88Ig\xc8\x9c\xcc\xd0\xa3R\x192&2`\xd3\x18\xfa\xb8$\x86\xd8\x14\x06R\xbf\x9cXt\xd2\x02\xa9_\xa2R\x15R\x12\x15H\xfd\xd2uY09!\"5\x01\xa3\xed\x18\x93\x96@\xea\x97\xa4~\x89I> \xf5KaK\xd2\x0dH\xfd\xd2\xe6)\x98`\x90\x9a^\xe0\x1c\x1bH\xfd\xf2\xd0H\xfd2!\x8d \x9cD\x10\x9bB\x10\x91@\x10\x9d>\x10\x97<@\xea\x97q\xe9\x02\xa4~9\xd81R\x04r\xb4\xb9\x88\xf4\x00|r\xc0oU\xfdr\xaax\xe6*\xf3\xf4\xaaI\x99G\xb4\xf3\xc8eF\x8b\xbd]\x97]\xdf\xb4\xe5\xba\xa8Ve}\xd9\x9c\xfd*\x99}>5\xb7?\x0f\xb7\x9c\xd7\x97\xcd \xdf\xc6\xeb7z\x9bk\xb8I\xb7\xba\x86\x13\xa5\xb6\xa9\xbf'\xba\xb2\x8fT\xa5\x8dW\xf1p\n?)\n\xbfd\xf2\xda\xe7aQ\xa2\x87\xb6\xc8\x8c\xe6,\x1b\x04A\xb9kVl\\\x14q\xaf[\x08\xba\xe6\xa6\xf6F=l\x1cy|\xe4E\xd1\x95k\xb8\xa8\x9a\xf5\x17Qo\xf7\xf5\xa12\x01\xaa\\\xdc\xc4\xd32Q\xa7\x10\x07eJ+v\xbb\x87}$f\xc3M\xda+\xad\x88\x07\xebb\xd7\xef\xdb\x81\n\xaa\xff\xdc\xee+&\xb3\x1avm\xc3\xbf\x1f\x7f\x11\x8b\xe1}J$\x8c\xff\xc7\xfa\xba(\xeb\x13\xcfjR x\nf%\x1f\xb7\x87\x9b`S\xf4\x05\x8f\xcb~-\xcb\xa6\x96(\xb2T\x1e\x87z\xe3r\x846\x9e:\x0e\xd6\x95\xd6\xf5\x82\xa2\xd3\x16u'\xc7\xf1m\xb1\xbe.k\x87\x00\x8b\xe0a\x95\xf5\xaat\xa4\xb2\x01\xee\x95\xfaX\xdd\x80s\x81aw\x03< 7N\xcc\x94\xc5\x0b\xf4GG\xf6\x00\xbb\x96\xdd\xcc\xf3\x8a\xdd\xee\x81\x9e$\xbe\x0f\xc5\x01x\xa0G\xb2\x9br\xc3\xea5{\xa0\xc7\x0d\xedo\x9c\xfex\x86%\xde\x037\x1d\x0b('C\xb6\xf2M&u\xb2'\x9b\xac\"\x86i\x92\xd8L\x84O\xac\xde\xb0v[\xd6\xbd\xeaT\xe4\xf0c\x9b\xd1\xdc\x14U\xc7\xbc\xe9ev\xca \xf8h\x83\x80\x1b\xcd0\xe3\x18N\xa3Z\x1a*\xd613\xe4(\xd5j\xaf\x1f\x93\x16\x1f\xaf]-\x0d\xa7`-\x0d\x11}@\xbe\x01P\xee\xfc\x9a\xd6\xe3u\x887\x00\x91o\x01\x12\x08\x9eA\x87\xbd\x15\xe9\xf7\xad\x14\xa4\xa1 \x9fAO#!4D\xfc\xd4\x16K\x00\x0d:\xdc\x15\xfd5\x9a\x08\xaa\xcd\x86\xf1D\x13B\xb5\xe1\x89\xa1AW&q4\x82 \xaam!QT[\x1ca4\xe8N\x91\xd9\xa2\x88\xa3\xdab \xa4A\x87\x97M\x1bE$\xd5\x16E(\x0dzK\xd1\xcf\x96\x86\"\x98\x06\xbdL \xa8\x18\xa2\xa9\xb6l\x84\xd3\xd1\xe1\x12\xe2\xa9\xb6\x04\x02\xaa\xb6,DTmxBj\xd0\xd5\x84\xb0\x1a&\xa6j;\x02AU\xdb\xb1\x88\xaa\xda\x8e@X\xd5\x16C\\\xd5\x86&\xb0\x06=\x99\x04W\xd1\xbe\xc3DVmQ\x84\xd6\xa07\xd1O`\x89\xad\xda\xfa8\x82\xab\xb6X\xa2k\xd0a\x8cb\xb7\xb4\xc5\xc4Wm\x01\xf5ni\x11S\xc7\xe0ri\xb4\xd8Yf\x14A6\xe8\xad\xd7\x04Z\x04QV[L\x89#\x89\xb3^_\xd3\xd9,\x82@\xab-\x8aH\xeb\xf5\x14\xd4\x03\x97\x96B\xb6\x0d\xb7O\x946\xb8\xb4\x14\xf2m\xc8a\x8f\xd2 \x97\x96\x87\x8c\xab\x0d\xc9+\xd5\x16$\xe7j\x8b \xe9j\x0b\x08\xf8\nK!\xedj\xc3\xf8\xf7j\x80f#\xf3jK\x0b>\x9e\xdc\xab\x0dS\xf3\x04\xb2\xaf\xb6$\xd2\xaf\xb6@\xc4\xf3\x91\x80\xb5!\xc9\xc0\xda0\xa4`\xe3Z\x049X\x1b\xf2\xad\xc4\x93\x85\xb5\xe1I\xc3\xda|\x8a\xe5\xd2\xb2\x90\x88\xb5E\x91\x89\xb5-!\x15k\xc3\x84>\x82d\xac-;\xd9X\x1b\xaa\xbc\x81/)\x9e\x84\xecuwq\x1f&#kK!%{\x1dj6\x80_\xf9\\Z\nI\xd9\xeb\xb0\xd7{n\x1e\x15ti\xb1\xa4e\xaf\xb3\x91\xd0\x8c\xd8\xee@\x90\x98\xb5\xf9\xc4\x99\xa5\xf94\xd2\xa5\xc5\x93\x9b\xbd\xee\x02*\xea\xfa\"<\x01:\xd0@\x0cr\xb4GQ]Z,!\xda\xeb\xec\xf3\x87\x9fN\x11\xc4hm\xb1\x04im\x11Dim\xd1\x84\xe9\xd9\x8dH\xe2\xb4\xb6\xd0, \xa8z-\x0dKn\xc5\x12\xaa\x07\xbf\xb1\xc4\xea\xe1\xc6\x18\x82\xb5\xb6@0R\x08\xd7^\x87\x08\x95vi)\x04\xec\xe0\xc7\x14Vl\x97\x16O\xc8\x0e\xf6\xe2\x01\xf5vi\x1e\x82\xb6\xf7\xbeT\xf2\xb6\xb6\x9c\xed=\x82\xcc=\xb8F\x93\xba\xb5\xb9'H>\xf5wir\xff\xc7\xa7\xef.\x0d\xa3\x04/-f'%E\x15\xde\xdff\xdaf\x8b\xd6\x86\x97\xe6S\x88\x97\x16S\xa3$\xb5xi\xd1\x9a\xf1\xd2\x90;x>\xfdxi\xb1*\xf2\xf6\xbb\xbcZ\xf2\xee[\xdc\x8a\xf2\xb6{\x82\x0fIP\x97\x97\xe6\xd3\x98WW\xe0\xe2\x1d\xd3h\x96\xaa\xceK\xc3h\xcfK\xc3)\xd0K;Busi\xd2K\xc3+\xd3K3K\x9a\xadB\xc3\xb5\x8b\xb4\xea\xa5!\x84n\xb33M\x82\x1a\xf6\xd2\x90\x8d\x01\"\xe3\x07\x19U\xed\xa5\xa1b\x88Q\xb8\x97v\xc4zGj\xde\x07\xfd=cw\xa7x\xe5{iA\xfd{i\xa9QX\xaa\x85/\x0d\xaf\x88/-\xb5\xb4\x88w\x96M#\x7f\xea.\xa4\x94/-\xa8\x97/-\xb5\xfa\xc9\xda\xf9\xd2p\n\xfa\xd2\x90E\xc4\x12\xdfc\xdeb\xbc\xb2\xbe\xd7]\xd1/\xd2\xd7\x97\x86Q\xd9\x97\x16\x19\xb8P\x06 $\x07\x0f\xab\xbe\xefu\xa7\xfa\xf4\x14\x0d~i!%~i\x93\x1a.\xd7\xe3\x97\x96y\x18\xc6+\xf4K\x8byk\x10\xaf\xd6\x1f\xf4'\x9d,\xd2\xec\x97\x86\x8c#D\xc4\x12P*\xfe\xd2\x90\x1f\x94\xb6\xd8\xb0\x03Z\xd7\x1f\xe5\xca\xd0\xfe\xc7 \xb6\x8f\x86\xd3\xf8\x97\xf6\x00A\x89Q\xfdG9\x94\xbdp@\xfb\x1f\xe5).\xa6\xe8S\x02\xa4=PhQ\xe7\x06\xa0\xbc\xe9\xb3\x05\xc2\xa7\x07\xa0\xdc\xe1\x82\x8b:g@ZD@cFEH\x08~\xec\xf9\x03A\x87\xb7E\xe7;\x85@\x1a\xfa,\x02i\xc8x\xc5\xd4=\xe3\xe9\x04\x83C\xdc\x19\x05\xd2\xb0eM;\xaf\xc0\xe9nT\xad\xf7R\xb2\xe3\xcf.p\xba\x92g\x1a`O0\x90\x16}\x8e\x81\xfb\xe9\xe3\xf9\x06\xfe\xd3\x0c\xa4%\x9di\xe0\xaf:\xead\x03i\xb1\xe7\x1b8\x1d\x19m\x1aq\xca\x81\xb4\xa4\xb3\x0e\xdc%(\x07\xce@\xef?\xf1@Z\xda\xb9\x07\xde\xca\xb0\x8d\xe7\xf4\x03iig \x1c|\xadB\x1ce\xaaB2\x9c\x7fPv\x11G \xcc\x94Q>\xbc\x7f5/;\x9d\x860Ya\xd3i\x08\x16\xc3\x0e-\xb1\xc9r\xb2\xfd\xd2i\x08\x88$8\x1bw(:\xf9\x0d\x9f\xf4F\xa7!h\x8bMf\xf3\xeex\xc6$\xb1E%\xaf\xd1i\x08K\x93\xd2\x12\x92\xd1\xb2$\xa1\xe1\x93\xcf\xe84\x84\x1c\xc9e1Ie\xe8d2:\x0d\x81NC@\xcf\x92\xa2\x92\xbd\xe4j\x89NC\xa0\xd3\x10r%`!s\x7f\x82 W\x11\x89V\x18\xad\xff\x98\xc4*:\x0d\x81NC\xc0$<\xd1i\x08\xc2\x96$.\xd1i\x086O\xc1\x04\xa4\x94\xc4#:\x0d\xc14D\"\x11\x9d\x86@\xa7!L\x8cNC\x88K\xce\xa1\xd3\x10\x06\xa3\xd3\x10\x94\xe9\x93\x05\x0eX\x7f\x93E\xe4\x9458\xf2\xff\xd4\xdf\x873\x04\xfaC\xady\xb3[Zx\xa6\x008\xd8\x91\xae\xb3\x06\xe6G\x0d\x88\xfa\xab+m\xe7\n\xbc\x1f\xe239S@y\xb0P\xe4&\xa7\x08|\x94\x97 'z\x85\xf9h\x0f\x110Ca\xda\xa40\xf2\"\xf5\x15\x8a]t1\xa3\x1a\x82$F\xbf\xb2\x83m\xb3\xd9W\x96\x9d\x08g\xb9 \x88ca\xc8\xa1\xc1m\x9cIef,NE\xd5\x90\x8cN\xf5\xb9\x89\x15\xbe\x8f\x7f\xb9-\xee\x0c\xbd__\xa9|*\xd7a\x82\xef\xa4\xe0\xd3\x87\xea\x82kN\xd3\x00\xcc\x1bb\xca\xae\xa2\xb3\xbao\xbd\xb8a\xd6r;\xb7\xc4\x8c\xa2\x18\xb5\x01\xfd'1\xc5,\xc5^\xe3\xf02\x1c\x9e\x0c\x9a\x82\x80\xa5\x8d\xff~\xb6c-\xec\x8a\xb2=\xeb\xdb\xb2\xb1&\x04\x18'\x8f<\x92\xc8\x1c\x96H\x07h|\xcdF\xf7\xaa\xafq\x92gv\xac\xed\xca\xceJ\xb0\xe7\x81]mX\xdd8\xb2\xe4\xe2>\xae\xd1\xdb\x84x\xc7\xff,v\xc9\xd7MY\x83\xf8\xbd\xac-\xac&\x04;Bv\xabAV\x84\xe2A\xc8\xab\x05\xffa\xea\x8b\xe8\x0fD\x7f\x08\xed\xfd\xe3\xbeU\xa2?\x10\xfd\xc1u%\xd1\x1f\x84\x11\xfd\xe1\xd0\x88\xfe@\xf4\x07\x97\x11\xfd\x81\xe8\x0f\xc2\x88\xfe@\xf4\x07\xa2?\x10\xfdA\x1a\xd1\x1f\x88\xfe@\xf4\x07\xa2?\xb8\x8c\xe8\x0fD\x7f \xfa\x03\xd1\x1f\x0c\xcb\x01E\x13\xfdA\x18\xd1\x1f~+\xf4\x074M\xa0i*\x0fI\xa0i\xaa =\x80_>a:LX\x01\xfcr\xf5\xf7\xc7K\x06\x18*l\xda\x94\n\xc0+iB{\x07\xb5\x1e\xcdY\x02\x08\xe27u\xd3\xafd\xea\xf5\xca\xa7L\x19\xd8\xc1X\xe2aRk\x89<6M\x85\xc6\x1dyT>\xbc\x7fE8#\xe1\x8c\xc1M6\xcc>\x15\x10\xceH8\xa3\xf3J\xc2\x19\x85\x11\xcexh\x843\x12\xce\xe82\xc2\x19 g\x14F8#\xe1\x8c\x843\x12\xce(\x8dpF\xc2\x19 g$\x9c\xd1e\x843\x12\xceH8#\xe1\x8c\x86\xe5\xc0|\x08g\x14F8\xe3\xef\x0dg\x9cg\x92\xda\xd0\xc6\x9f\xc7\xc4O\x8d9\x16Ue\xe4z\xea\x1d\xc5~-\xd5\xbb\xaf\xca\x1bV\xab\xe3\xf7\xac\x80\xe4\xe8Q\xfd\xfahaI_\xa6m\xff\x15 \x1f\x19\xc6\xa6]\x15\x9bM\xcb:\xc7U\xa8}\x0f\xcc\xd6\x01X\x1e9\x81`\xf5\xdf\xe6g\x14\x88\x07\xf9 \x01\xe8Ct\x99\xdf\"\xc0>\xc8\x01\xf8A\x08\xf4\x03\xfc\xf4\x0c\x01\xfeA\xe4,.\x1a\x04\xf4z\x13\x00!\x02\x08\x84\x88Rf\x04\x04!\n\x14\x84\xdc\xc0 $\x82\x83\xfev\xd5\x85\x01BH\x07 \x9d\xfe\xf8\x13C@!d\x03\x0b\x01\x8fy\x01\x064\x848\xe0\x10B;\xfd\x89\x00\" \xfcz6\x133\x81\x89\x90\x14\\<\xa8\x08\x88Z&\x80\x8b\x90\n0\x82?\xaa\xf9\x80F\xc0\x83\x8d\x80\x04\x1c\x01\x0d:\x02.\xea\xf1\xe0#D\x01\x90\xe0\x05!!\x17\x10 \xb1`$,\x04$\x01\x11\xde\x08`\x12\x8e\x01N\x02\xa6\x8c\x9e/!\x1fP \x18\xb0\x12\x16\x00\x96N\x87\xfcB\x1fh \xb9\x81K\x08\x82\x97\x90\n`:\xbd\xc95\xaa\x7f\xb9\x8e\x002\xc1\x8b\xb7\x80\x17\xd0\x84$P\xd3\xe9\xca\x0bvB*\xe0\xe9\xf4&\xe7\x81\xbe\xf31\xb3\x01\x9f\x80\x02?!\x01\x00\x858\x10\x14R\x80P\x88\x06C!0\xda\x06\x00*\x88\x00\xa9\xb0\xc0(\xa4\x80\xa3\x10\x0b\x90\x82\xbf\xe2)@\xa9\xd3\x99\x01Cb?\x19\x1c`\xea\xfd \xc4\x11\xee\x1e\xd0\x14\xf2\x02\xa7\x10\x02O\xc1\x0f\xa0:\xefI\x05V!c\xdb\x8d\x00X!\nd\x05\x03h\x9d\xda\xdf\x8a\xb2b\x1b?:u\xd14\x15sn\x1d\x0f\x1b\x12\xde\xab\xb0+}Y\x1e\x85\xd8m\xe0\xf6\x9a\xa9\xfd\x1e\xf3L^\xfe\x1d\\0V\xab\xab\xdd\xed\xa0m\xb6\xc3\xa1\xb4\x02\xdc\x95\x9b\xe2VmWP\x97\xb8b\x81\xad\x81z\xd0\xfcTk\xf5w\xe7m\xcfd9\xcf\x06\xf5^\xf5/\x01\x82\xd8oA\xec\x18\xb1z\xef\x90\xaa\x05\x81\xb2\xff\xf0\xee\xed\xeb\xd5\xc7O/?}\xfe\xb8\xfa\xfc\xf6\xe3\xfb7\xaf\xce\x7f<\x7f\xf3\x1a}\x07\xff\xaf\xc8\xcb\xcf\xdf\xfe y\xbd\xd7\xb9\xce\x0d\x8d\xaa\x82/\xb9\x15\x15Ol#\x90\x0fR\xcdX\xcdJ\xc6\xb3\xa8\xc5o\xcf\xcaz]\xb9\xa7\x07\x1d\xab.\x9f\x8f\xd2\xcc\x8eF0\x1c\x8a\xbd\x92\x87.?@\xd5\xe6\x8f\x1c\xd1\xf5\xa6/\xaa\xf1,\xebn/\x91\x07\xf7\x80e\x9e\xf8n\x9c\xee\xed\xa8\xe8X\xba\xc5\x15\x18\xae\x9b0\x03\xcc\xbf\xf7\xac\xddv`?4z\xb4\xa1\x02\xfe/t1\xba\xbfm\xea\xf2\x0b\xb3\xe4\x1e\x8f\x86x\xc1\x10\x11#\x18\x9fj\x9c\x80\x7f\xbd\xdf\x16\xf5\xf3\x96\x15R\x9fZ\xcc\xfbB1\x02L\x9c@\xf1\x04z'O\x02\x8eSG\xfd\xd8\xb1\x92c\xfa\xe2\xf8cW^\xd5E\xbfo\x19\xbd\xbb\xda\xd7\xfes%p\xe7]D\x05hS\xf4\xec9\xf7\x95-H\xf2\xa8\x0cw\x88\xb6e-\x8f\xd3\xf05\xe5\xe9D\xb2o\x04\x00^\xb1\x9e\x85\x02\xb4n\xb6\xdb\xb2\xeb\xb0\x83\xe6x\xf9d`4\xfe|x\x9a\xcb\xdc2\x0dy\xe33Wm\xd1\xfb\xae\xc4\xbf\x15\xb0\xf8\x9dTT\x10T\x8a\xca\xb8\xc8\xebK:\x90\xc4\x83\x01,_\xb7\xac\xe8\xe5\xaa\x181\xec\xa1\xe2\x05\xc8\x98\x81*Sh\xe3\x1e\xf1Ah\x8b -\xa8\xc7\xeb\xa5\x8f\xd1l\xc4\x9f\xd7\xd7E{%\xe6\x84A7\xe3l\xf0\x04\x049\xfcR\x90\xbc\xe6'`\xccm[\xdc\xad\xber\x00t\x11&\xedJ\x1f;3\x8bH\xd0\x99\xec\x1d\xc7/\x7f]\xd4\xc0nX\xabB\x19\x1d\x1b\xc9Jy\x0c!2Jb\x8d\xd4\xa6(=\xea\x11\xda\xca\x9a\x7fm\x1d; \xf3\x1a\x91\x96A\n\xba\n\x07q\xbf\xe3\xa3\x83w\xa4\x01|\xe0\xb0#\x0eD\x06\xd8(\xa5\xfe\x0e\x05\x10!\xfe`\xfb*o\x03d<\xf9\xa66\xf6\xb8l\xcbz\xc5\x17\xaa\xabq\xa1\xba`\x14\xc6\xd6\xd3\xf2\xd4\x83\xed\x96\xa7\x9dXA\xc3\x86\xad\xab\xa2\xf5\xec\x11m\xcbZ\xb48u\xb5vh\xab/\xa6|C\xa2\x80\xb1l\x1a\nu\x02}s%7\xb4\x04\xd8 \x80\x02\xbej\xb6\xba*\xb6\xcd~\xa0\x12\xdb7 \x7f6\xaa\xcb'\x02z\xf5\xad\xb2\xf7\xca\x16\xd8\x9d|\x81\xf2e\x8b\xa9CY;\x06\xef\x8fU\xd1]\xf3\xa1K\x8b{\xb8(\xc4\x05\x0f\xab\xfc\xf2\x14\x865y\xcc\x89$\x1e\n\x1e\\\xd3\xb6\xae\x81m]T\xeb}5@7\x97{\xbe\xc2\xb2?p_\x8fo\xa6\x13\xb1k\xf6=\x94\xbd\xc8\xd0\xa8\xaf\xa0\xb9\x11\xeb\xd4a\x0b\x01\xfez\xcdjYU{\x05\xda\xe9\x86\x8c\xfd\xa9\xd3i\xe9\xc9\xac\x8b);>\xd6o\xca^\x93\xc3\n\xa3\xf9X\xfd\xdd^7\x9dq(\x95\xfd\xa1\xe6k,\xbb \x0d\xd3h\x11\xa2jc\x15\xac\x9e6\xe5\x80\xd3\xca\xcdv\xc1%\xb4?u\xf2\xfeN\xe1\xe7F\x84u\xd7\xdc29\xea\\\xb0\xe1u\xb1\x8d\xc0^\x9d\xcdV\xef\xb7\x8a*\xd8\x9f\xb6\xddW}\xb9\xabJY\xb8\xe9\xb3\x0fn\x98|uF\n\xcf\xc8\x06Sg\xec\xc9T\x9f\x0d\xb8\x8ft\xdb\x15W\xea$\xad\xc3^j\xf2\x98\xf1\xc2\xa9|\xdf\xf8g\xd5\xeem\x89<\xd2\xbc\xf3\xba\x80\x9e\x1f\xbb\xebW\xce\x9c\x91`G\x1ad\x08\xf6e_\xb1\x17\xf0\x1f\xae\x1eV?_w\xaa\xfc\x9f\x8a^[t\x9d\xdc\xd5{_\\\xb1\x0f\xec\xef{\xd6\xf5\xa7\xf2w\x87\xb3\xf1\x88K\xee\x96\x87\x90\xc1\xb6\xe9z`\x82\xa4*\xd8\xad\x96[E\xfbZ\x18\x80\xbd{\xbd\xabB\xe0\x1cd\xe4^f\xa975\xc7\x83\xe4t\xd7h\x88\xec\xb8\xf8qf\x88\xd6\xfc\xc3]\xc9\x8f\xc6q\xf9m\xc1\x87\xac\xfe\x04\xca\xbe\xd3\xac\xf0N\xf4|\x12\n\x11{\x07\xb7e7}\xa7\xae\x8a\x88\xf4\xb91k\x0d+\xc5x\x90\xe7\xa6m\x94g\x1c~ u\xc6\xe9o\xa4\xce\x88\x9b\"AB\xe2\x98l\xab\xa4\xce\x88H\x12\xebs$\x88\xa5$\x87\x91:c\xc6D\xb0\x98$\xb0\xa8\x040Rg\\\x9a\xec\x95\x90\xe8\x95%\xc9+>\xc1\x8b\xd4\x19\x97$t\xc5$s%$r\x91:#\xa93\x92:#6\x11+k\x12VJ\x02\x16\xa93\xba.\x0b&ZE$Ya\xb4\x07c\x92\xabH\x9d\x91\xd4\x191\x89R\xa4\xce(lI2\x14\xa93\xda<\x05\x13\x9eR\x93\x9d\x9cc\x03\xa93\x1e\x1a\xa93&$)\x85\x13\x94b\x93\x93\"\x12\x93\xa2\x93\x92\xe2\x12\x92H\x9d1.\xe9\x88\xd4\x19\x07\xfb]\xaa3\x8e\xbc\xbfq\xd2\xf3\\\xf4\xbc/\x0e\x13[&\x8bH\x95\x0e\xc3\xea\xe2\xa2\x92\x1b/\x12\x11\xe4a3\xd0\\\xa1\xc5(is61F\x10#\xca\x0by\xaf\xf1\xb7\x96\xfd}_\xb6l\xf3\x02.\x8bj\x02+YW\xea\xba\xc8#\x90{\xfa\x85\xdd\xbb\x8a>\x03H\x15\"Z\xa8^\xbfe\xfd\xbe\xad\xa5\x0e\xa0\x84\xfa\x14\x14<\xc0\xa7b\xf7\xeaj\xb6\xcd#j\xc0+\xea\x87DO\xe1\x1d\x1f\xa3\x9bZ,o\x9b\xcb\xcb\x8e Z\xf9\xb4\xb8`\xec\xbew\xac\xcf\x1c-\xc7^\x86%\x88\xb2|\xae8\xce\xf6\x11TeD(\xeb\xfd\x96\xb5\xe5Z\xffMt\x10\x8ao 7r\xaeY\xad\x03\xbf\xaf\x87\xbd\xb3\xd9\x8c\xf9\\x\xabX\xd7\x8d!\x94\xbbM\xfb\x8e\x87\xfa\x0b\x8b\x8c\xe7\xd4\xfd\x91\x83;\x83\xa9-\xe1\xad\xcam\x89\x8d\xae\xb8V#\xf7.\xf4Z\xee\xab\x9a-X\x91\x19\xf6\xd5\x0co\x95\xbb(\xe6\x9f\xce/\xa1b\x97\xbd\xda\xb0+{\xd9\x83\xeby\xae\xd8\x12\x96\x1f\x88|\x08\x8f\xf3\xc5=\xb0b}\x0d\xc5n\xf7\x15\xa3hb\xf0\xe3\xfd\xbeX\x1aw\xf0\x88\x8a\x16\xda@\xdf\xee\x19\xf0\x7f\x94\xf5\xa6\\\x0bZ\x95\x02\x87T\x04\xc5\x85\xaa!\x99\xee\xcaz]\xed7\xb3Yl!\x9f2\xa0s\xb37&\xb0^c\xd3\x98w\x9b\x13\x1a\xca\xc4\xd9\xe7\xf3n\xf6\xb6fU\x10\x13\xff\x96u\n\x94\x17\x9f\xd7\xf8=\xf2O\xeeT}M\xe5U\xdd\xccys\xfak\x9c>BFf\xe9\x8b=L\x1f\xb5'\x96\xbat\x82\x9f\xba\x85\x82\xcf~\x1d\xfe-$a\xff\xa1Tz\xbd\xd2\xc1\x83r\xb0\xc1\xf8\xaa/\x1b\xf1\x02\xe4\x085\xfe\xa04eu\x08\xec\xca\xc1Ot\x1c\x1e\xbbp\xb0\x8b\x8c\x90\xc4e\xc2\xc9\xff\x06\xb7\xd51\xfb\xd2\xb9\x85\x7f\xe3e\x7fq\xa2\xbf\xdehB0\xa2\x80`j \"\n\xe8\xa8B*_\xc3\xe3/J\xe67+g#\xc8\xda\xc8\xcd\xdb\xc0372q7\xd2\xd8\x1b\x1ew\x91\xc2\xbe\x0b\x19\x1c\xb99\x1c\x91,\x8e\xcc<\x8e8&G$\x97\xc3\xd7\x86\x07\x96\x07\x96\xcd\x91\x99\xcf\x81btd\xe4t,eu$\xf1:21;R\xb8\x1d\x1egh\xe9\xde#\xf0;\x8e\xc7\xf08\n\xc7#\x8e\xe5\x91\x9d\xe7\x81ezd\xe5z\xe0\xd9\x1e\xd1|\x8fx\xc6G\xb0+\xc4\x89\xf4.f}\x04\x05zQ\x13*\x04\xf7#f\xd6\x15\xcd\xff\xf0\x0d\x82hY^\\\xf92\xb2@bx \x99\x99 i\\\x10_\x0bBI\xf1&\xf2A\x1c\xdez\x94\x0co\x1eN\x08\x9a\xd8\x80\xe0\x85D1CB*\x96)\xec\x90\x90O'J\x94\x89#\x12\x1fLq\xc4\x83\xb9\x84\xb6\x91\xc29\x96\x828\x9c\xd3\xdf\x88\xc3\x19j\x95\xa3\x11\x87\x938\x9cv#\x0e\xa70\xe2p\x1e\x1aq8\x89\xc3\xe92\xe2p\x12\x87S\x18q8\x89\xc3I\x1cN\xe2pJ#\x0e'q8\x89\xc3I\x1cN\x97\x11\x87\x938\x9c\xc4\xe1$\x0e\xa7a9\xf8t\xc4\xe1\x14F\x1cN\xe2p>N\x0e\xe7\x94M\xe1*\xf3\xf4\xaa\xd9\xb9\xea\x9a\x98s\xe42\x1f\x9d\xb2t6\x9e\x0e<^\xe6\xe11\x19\xc4\xd6\xcf\xfaN\x0b\xb7i\xf0\x8a 7\x0d\x0e\x9d$'\xcb\x93\xd4e\x8f\x96\xed$\x03p\x0c\x82S\x88\x91\x13\xdc\xa4\xc2\xec\xf2df\x1cy\xd9FH\xa6Q\xa6zee\x17y\x89)\xac\xee[/\xda\xeaBx\xc1\x87\xf2B\xa8\x11I\x0b\xa1\xbd\xdc\xe4y\xd1M\xed=\xbf]Z0\xf8\xd2\xc2g\xb9K\xc3\xbd*i\xb3R\xea\xd7\xa5\xfeK\x9f\xd4n\x9c?\xee\xf5\xd67\xcd\x17\xd8U\xc5\xda\xba\x01*M\x1di\xce\x9f\xe9?\xb67:.\xe1\xa3{#c3-\xa9\x8e\xcd\xbe.\xef\xc6\x83\xdcq\x81\x19]y\xf6B\xe4\x11\xe5\xab\x80p$\xe0\x03\x13S\xd9\xd9\xd3'\x03\xb2\xe2\xb8\xa9K<\xe0&\xa8.~\xb3\xaf$r\xa6XxP\xf4\xa8\x10\x1c\xa9\xea\x9e:\xc5\x96\x11\x1bR\xcb\xa0\xfa\xa6\xee\xdb\xfb\x91BV\x1b\xc3x\xe0\x9cx\xb1y\xdf\xb2\x8a\xdd\x14u\x0f[\xd6\x17\x9b\xa2/\x10\xccF\xd5I\n.\x19\x8eM\x16\xc5'\x8b\x08R\\\xb5\xb3\xb1\xca\x96\xf1\xcaP\xcc\xb2\xa3\x05\x01K?\xcb\xf0\xd6\xf1\x05\xcbJP\x8b\xa3\xa8e%\xa9\xe1\xea\x9c\x8d\xa8\x86\xa2\xaa-#\xab\xd1\x19\xc9\xca\xe8\x8c\xe4\xdf\xce\x19\xc9\x08\x06\xa6w\xf5\xe2%e\xce\xbcYx>\xb3\x13\x94\xad\xcb0\xa2gJ#zf\x9e\x15\x0e\xd13\x89\x9ei7\xa2g\n#z\xe6\xa1\x11=\x93\xe8\x99.#z&\xd13\x85\x11=\x93\xe8\x99D\xcf$z\xa64\xa2g\x12=\x93\xe8\x99D\xcft\x19\xd13\x89\x9eI\xf4L\xa2g\x1a\x96\x83*G\xf4LaD\xcf$z\xe6\xe3\xa4g\xd2Y\xcaq\x07\xd5\xd2Y\xcaG\x0cn\xf8\x14`:K9G\x14\xe9,\xe5\xdf\xf2Y\xca\x82\xae\xde\xdf\x9d\xdd|w\xd6\x95\xdb}U\xf4j\x17w\xd7t\x87\x04\xf4\x8f\xea\x12\xd0\xd7v\xc0\xee\xd8z\xdf\xf3\xee\xa2\x80\xbe-\xea\xae\x10\x1bur\xe1\xd2\xf5\xe5\xb6\x10?^\x15'4s\xed\xf7\x89\xae\xf4#e\x94_\x15\xdd\xaa\xac/\x9b\x00\x89J_\xa6\xfb\x13\xfeo\xfeR\xc4a\x9e\x17\xcd\xbeW\xe1\x18\xfb\x10\x15O+\x13\xcfYN\x08\xb2\x13xAn\x8b\xbag\x16eS\xc0l\xcc#\x08E\x98\xcdo\x80?\x15\xdd_EAtL\xb6\xc5]\xb9\xddoa_\x97\xbd\xd8\xb5\xbdm\xda/p\xab\xd09 \n\xf5wnv\xd5\x8e\xb5\xbcp\xb6E\x18\xaf5\x0f\xee\x03\xd5\xf9OE\xf7\xb9\x1b+\xa6\x0e_m.\xc5K.\xd6\xbd\xc4\xd1\xd7M\xad\x00\xd6\xa9+\xd9\xf7\x05\x1a\x94\xea \xcb\xce\xec.\xf5\x06\xfeq\x9a\xce\xa6\xe8\x8b\x85\x01tb9\xb8&\xf3\xba\xe8\x0b1\xdd\xa9\xefEi\xc6\x81\xf7\xb2\x15g\xd3\xca\xd5\x83@Z\xebM\xe5\x00K@\xf7PM-\xfa\xe8\xbf|\xfe\xf8\xc9\x03\x85U\xac\xbe\xea\xafa\xd7\xb2\xcb\xf2N~\x9f\x82W\xc9\x07\xae\x8e\xf1 }\xcfdid!\xf6U_\xee*\x17x\xa4\xcb8\x14\xc1\x8a\x9eU\xcdUb\xa4q\x81\xfc\xa9\xb9\x9a\xee`T\xcd\xd5\xa4OJ\x8d\xa7\xe5\x02v\xc3\xea\xfe\x11k\xe8\n7\xce_\x11!\xe7V\xf4}[^\xec{\x7f\xdaE\xa8\xba\xd2\x02i \x80\xab\xba4L\x00\xa499\xb6\xa6\xa1b\xa1-\xf8\xd1\x8f\xe6\xc5\x8aG;\xd6\xe3\xcbz\xc3\xee\xb0\x8f?\x9c_\xd9\xcd>\xeb\xb2\x1b\xee\xab\xd5\xf6\x86\x7fQ/u\x8b\x93\xeb?E\x03\xff\xc2\xee\x9f\xcbE\xc3\xae([\xdf\xde\x05\xb7\xf9Q\xefE-\xbfV\x14\xa5\xdeSLQ@9lw|\xad\xa2\xc96\xb0a7\xac\xe2-R\xac\x9c\x8a\xbe\x17\x8b\x99a\xa7\xd5\xe9\xd0\xec\x9az\x0fJ\xa3\xb7\x0e~`We\xfdC\xd5\xac\xbf\x9c\x0c\x7f{Sof\x7fyu\xcd\xd6_>\xdd\xb9?\xeaz3\\\xfb\x9aU\xe5\x0dk?\xddy\xd0\xb6\x9f\x8a\x9e\xb5'\xe6\x9c\xb7\x83mq\xcf\x17o2\xfdr\xa3\x96\xd1\xfd5\xeb\x98\xea\x18\xed\xb1\xc6EZ\xc4\xb93(\x04\xd0U\xe5Z,\xcc\xe5+\x90=\x84b\xdd\xdd\xb2\x96\x01\xdb\x96}\xefd\x00m\xf6\x92\xb7);~WM\xc7\xf1\xc0\xd5\xf3\xfbv\x7f`\x98\xdb\x9b|\xeb\xdeH \x90;\xa8v!\xdc\x8f\xac\xbd)\xd7\xect\xf0A\x84jaD\xa8&B\xf5hD\xa8&B\xf5hD\xa8\xee\x89Pm7\"Tk#B5\x11\xaa\x89P\x8d\x9c%\x11\xa1z0\"T\x9bF\x84j\"T[\x8c\x08\xd5\xd6k\x88PM\x84j\x87\x11\xa1\x9a\x08\xd5D\xa8&B\xb5a9\xc8\xadD\xa8\x16F\x84\xea\xdf\x03\xa1\xfa\xa2\xd9\x98c_Y\x1f\xfc\xc9Iz\xb6a?\xffO\xcb._\xc0\xd3\xff\xff\x99\xb1qxV]lO\xfb\xbb\xd3\x9b\xefFDJ\xca\x1c=U\xf7\xceiv\n\xc0\x9a\x12\xed\xfa;u\x8dM\xe3\xf5O\xac\xfft\xd7I@\xef\x92\xf5\xebk\xde\xa9\xdfu\x82\x0cj\xa2\xb5\x13\xfe\x9cq\x93\xfa\xf9a(t\x81 \x19\xc5\xd2\xe8\xdf\xd3'\xe3\xd3 \xb73\x8dp;\xdc\xbe\x0f\x10nG\xb8\x9d\xf3J\xc2\xed\x84\x11nwh\x84\xdb\x11n\xe72\xc2\xed\x08\xb7\x13F\xb8\x1d\xe1v\x84\xdb\x11n'\x8dp;\xc2\xed\x08\xb7#\xdc\xcee\x84\xdb\x11nG\xb8\x1d\xe1v\x86\xe5\xc0P\x08\xb7\x13F\xb8\xdd\xef\x01\xb7\x93\x89q\x86\x8b\xc9\"R\xfe\xaas\xc6\xaa\xb2\x93{\xde\x86\xd0\x84\xb8\xe2`E\x9a\xa2\xa51\x87K,@\x89c\x01\xbfn\xaa\x8a\x89\xe2\xfc\xa8\x96\xef\"1\xfc\xa0\xae|\x1e\xc0\\U\x15?\xf2\x9a\x9eK\xc1\x13\xfe\x87\xe6\xb2\x1b6\xde\xcdDC\xa1\x89\xd2\x19\xc7\xf1\\T\xcd\xfa\xcb\xd2\x00`\xc5DH\x11*Un\x87\x14\xa1\x8e\x18\xdc\xb0\x96\x11)B\xe5\x88\")B\xfd\x16\x14\xa1\xc6W+\x04NV\x17\xee\xee\xfb\x8f\xb3\x9d\xdc\xe7\xf0\xee\xc3\xeb7\x1fV?\xfc\xeb\xea\xf3\xdb\x8f\xef\xdf\xbc:\xff\xf1\xfc\xcd\xeb\x17\xd6\xbf\x0e\xbb\xc6\xea\xfc?93\xec\x9aV\xc8B\x89G\x9f\xc2;\xfe\x7f?\xdc\xeb\xc6/\xbe\xab\x97\x1f_\xc9\xef\xa9\xec`]\x1c\x1c4g\x94\xe1\xe5\xc7W/&\xff5\x9e8\xd8\xad\x99:n\x90?\xc1\xe9\xe1\xf5\x9b\x89\x0b\xfe\x9f\x83\x0f\x1e\n\x87\x93\x94\xd7s\xf0\xdd\xb1z\xbf\x9dN2\xec\xe1u]\xf2\xf2\xe3+\xd7O\xbc\x1e\x93\x97*\x197>\xf7n\x02\x93C\x12\xec\x87\xb6)6\xeb\xa2\xeb?\xdd\xc1\x85\xfe\xb79Y\xb1\x12\x96\x8c\xbb\xd4\xcf\x0fCX\xea\xe3\x99A\xfd\xddp|\xb4\x8bg\x93$\xb0\xe4;\x8c7\x88\x13]\x06\x0f\xdfU\xe7\xfc}\xd2sC\xf5<\xcb\xb5\xfd\xddu\xd1]'\x16d\xf2J>M\xa7\xa9|\xedwm\xdb\x1cX7\x1b\xd6\xed\n\xd7\xe1\xa9\xc1\x87\xaa\xba\xf1\x85\xacp\xa3\xd5#\xe0U\xb3\xb1-\xc9\xecT-\x08\xd2\xb5\x00\x15\xe9I\x08\x06\x95\x0b\xfeL+D\x96\xae\xab5y\xd0\xd3\x0fr\x88\xe43\xca\xeeD\xef2?\xb5\xdc\xd8\x16\xb7\xabcKL\xf17\xdf\xec\xfb\xdd~\x18\x7f\x0d!\x98\xa7\x1dT\xcd\xd5\x15k\xe1Y[\xdc\xaa\x87}{\n\x7fq\n#\xb9\x11\xda\xba\xa9\x9fo\xf8Jr[\xd6e\xd7\x97k[\x8c\xab\xe6\xea\x11KPm\xbb\xabUP\x83(\xdc0\xa5\x85\x9b'\xf8\x14\xc6\xa4\x05\x1b\x01\x04\x94\xbd\xa4\x85\x82+\xed\xeb\x08^ \x97\x81k\x90\x81\x90\x86\xd3\x00\x93\x86\x0b\x8c4Dx\xa4\xa1\x83$\x0d\x1f*i(\x850i\x11Q\x93\x86\x14\x00\x93\x16\xe9\x1d\xd7_MmT\xd72\x8e\xaa\x1e^0\xdc\xb6\xc5n\xc7Z>ko}\x8c\x9f\xd1zuvpQo\xd4\x1a\xaeh=\xa4\x13\xd3dE;(\xeb\xaeg\xc5F,6\x8b[\xd9\xcd{\x90\xa8\xe8\x9a\x7f\x14\xcf\x91T\xcc\xde1\xb9\n\x0e\x9a\xe1a\xb2\x0f\xa49 \xa2\x00\xe8\xef\x02R\x93\x1d<\xfe\x0e\xf8n\xbe>(k\xc2C0\xe5!w\xd2\x03>\xed!S\xe2CZ\xea\x83\xc7\x1d\x0f(:\xf9aq\xfaC\xee\x04\x88\xc8\x14\x88\xccI\x10qi\x10\x91\x89\x10\xbe6<\xa4H`S!2'C\xa0\xd2!2&D,M\x89HJ\x8a\xc8\x94\x16\x91\x92\x18\xe1q&R&\xc2\xa9\x11GI\x8e8^z\xc4Q\x12$\xe2R$\xb2'I`\xd3$\xb2&J\xe0S%\xe44\"\"Y\">]\"\xd8\x15~\x8bH\x98\xc8\x902\x11\xdc\x10@M\xa8\x10\x89\x131\xb3\xae\xe8\xe4 \xdf x\xd1\xdc0D\xfa\x04\xb6|\x19S(b\x92(2\xa7Q\xa4%R\xf8ZP\x17N\xa5HN\xa6px\xe3O\x0b\xa5S\xe4J\xa8@g\x05 \x92*\xa2\xd2*\x02,\xe8\xa4\xd4\x8a\x90O'\xc52S\x82E|0\xf1I\x16\xa1\xba%$Z$\xa6Z\xf8\xa8\xaa\xd9\xd2-\xd0 \x17\xb8\x94\x0bl\xd2\x05\"\xca\xf1\x89\x171\xa9\x17\xbe\xe4\x8bL\xe9\x17\x91 \x18\xcbR0B\x01\x8dH\xc38B\"F\xb0t\xce\x96\x9e/\x1d\x03\x91\x90\x91\x9e\x92\xe1p\xc7/\xf3%edN\xcb\x08%f$\xa6f8|\xc9\x95\xa1oq\x8cH\xcf\xf0q\xc8})\x1a\xf9\x934\xb2\xa7i\xb8\x135r\xa6j`\x925\xe2\xd35\xa2\x126\x12R6b\x936\xbci\x1b~\x12=\x9eF\x8fM\xddHH\xde\x88L\xdf\xf0T7%\x85\xc3\xe1\xcaH\x8f\xc0}\x12\xb84\x0eO\x93\x17'Mz\x129\xb2\xa6r\x04\x929\x8e\x93\xce\x91\xab-F\xa4t\xc4$u\x8ci\x1d\xa6\xf5\xe5\x96u}\xb1\xdd%\"C\xb8\x95\xef\xa7r\xdc\x90\xdf\xb5\xec\xa6l\xf6\x9d\xca}\x80\x1f\x9bV\x91\xdc:\xf8\x1f\xf0\xdd \x94\xfd\xd3\xce\xf3fo\xc5\xb5\xa2\xf9o\xca\x82\xf7\xd5\xaeW\"zP]\xbf!!C\xee\x0b\xdc4\xfd\xb8\xee\x94%\xf9\xa9\xe8\xfaW\xcdv[:\x8f\xd6\x1a\x8b\n\xdf\x7f\x0f\xdf\x9d8\x87Z^\x03\xbe\x1a\xed\xcaN\x94\xc0\xe6\x90\x8e\xdc\x1b,T]i\x08\x8a\x0d\xa2\xea\xd20\x01\x90\x86\"\xd4\xa0b\xa1\x0d\xb5\xe3%\x0d\xc9\xb89\xd6\xe3\x83t7i\xf2\xf1\x98#\xf4\xc0Ck\xb7\x19\xaew\xd1FG\xee\xb9\xae\xfb}\x1e\xb97\xd0e\x14\xc7I%%j:\x8f\\E\xaeY'\x9e\xed\x9a)\x99\x8c\x05\x81e8{}\xb3\xf4:\xd7\x05\xfa\xeb\xa6c\xaeG\xcar9\xdc\xa9\xe9H\xa7\xd2\xfe\x1b\xf7\xcaU{\x17\xe7\xc1\n\x12N\xdd3}\xfa\xdf)\xfc\xf5\x9a\xb5\xac\xe8\xe0\xa7\xe6\xaa\x9b,/\\\xeeD\x0dN\xbc@\x87\xb1\x88\xd9\xb2\xbe\xd8\x14}q2\x94C,h\xa7U\x0dW\xd3\xbd\x0b\xfb\xb1\xac\xd7\xec\x05\xac\x9bn\xdbt\xcf\xbb\xcd\x17\xf8\xc3\xe9\x7f\xfd\xe3\xe9w\xdf\x9d\xf0\x7f\xfc\xd7\xd3\xff&\xfe\xff\xbf\x1d\xdc\x1dn+\x9f\xee\x06\xdew\x80Z\xd5\xb2\x8a\xdd\x14u\x0f\xfd\x9d}q\xd5\x19$9\xb9\xc6W\xba\x0e\xf2|\xdfNNt7l\xddl\xe6\xc7N\xfb\xb23\xc1L\xceXrh\xa3\x99\x19B\x876\x92\xf8khf\x11\xfe\xcc\xa4%\xf1\xa1H\xfc\x15\xc3\x82\xca\xc2\x81Ja@\x91\xf8kF\xdeS\x0c\xeb)\x8a\xf3D\xe2\xafK\x99N <\xa7,,\xa7x\x8e\x13\x89\xbf.\xe16\xc50\x9b2\xf3\x9ap\xac\xa6\x8c\x9c&,\xa3\xc9\xb2YI\xe2\xafSCl\xa9`gI\xd1\xfc%\x12\x7fE\xb1\x96R8K$\xfe\xea\xba,\xc8S\x8a`)a\xa4Mc\x18J$\xfeJ\xe2\xaf\x18\x1e\x12\x89\xbf\n[\xc2<\"\xf1W\x9b\xa7 \xd7(\x95i\xe4\x1c\x1bH\xfc\xf5\xd0H\xfc5\x81Q\x14\xe6\x13\xc5\xb2\x89\"\xb8D\xd1L\xa28\x1e\x11\x89\xbf\xc61\x87H\xfcu\xb0c\xb0\x85r\xb4\xb9\x08\xa6\x10\x9e'\x84\x11\x7f\xcd|h\xa3\x13\xc4\xf0\xca{ \xc9\x88(\xe8%\xb0R\x9f\xac\x84\xf5\x03\x06\x08\xad\xb8\xf5e\xafo=\xc8\x92\xa3,\x87\nr\xd2\x9e\xc3\x0f\x1f\xde\xbd|\xfd\xea\xe5\xc7O\xab\xbf\xbc{\xfd\xc6\xa9&\xe7\xb8\xfc\x87\x9f\xde\xbd\xfa\xdf\x98\x0b?\xfe\xeb\xdbW\x98\xeb^Z/\x1cd\xe9\"J\x1b\xdek\x18\xd0\xc7\xbf4\x1bf\x88\x10\x8a\x9d\xfbA\xa7\x8eG\xdb\x01c\x82\xc0u\x0f\xc0L\xf8\xf0\xfe\xd5\x00g\xda\xda\xbe/\xea/\xe0\xdfY\xdb(\x02\x89\xf8\xf8\xf9\xf3\x85\xac\xa0\xa3\xdf\xb2\xbf\x94\x83X\x89\xbf\x1a\xd8so\x88\xf1 T\x8a?G\xc8\xb8\xc8~\xad\x12\xca\xae\xb7E\xd9w\x0e(A\x8c\xf1wj\x17u-\xd8l\xbdT8-\x0e\xc5\x86\xdd\xc5\xe5o\xfc\xa0\xb4\xfc\x8fY\x0b[\x80\xa2\x9a\x8c\x8a)#T\xcd'\xac\xb8\xc2\xbe\xb4\x96\xf6eRq\xa5&\xacm\xcf\xa7\xdc\n\xc2a\xcf\xe6\xc5\xf27\xea */\x14;FP^\xfeg\x1f\x85\xc9+'\xf36l6o\xf9\x17\xb7$\xe4\xd3\xe9\xa1\xb6g\xbf^\x17\xdd\xf5?\x94d\xa3\xf3p\xdb\xe1X[\x19\xca\xfb\x89L\xe0\xe1\xb1\xb6\xea\x87\x87\xd1\x87\xc4\x1chKG\xd9\x02\xb1\x19\x82[\xf9\xe1\x11J\x1a\xb1\x19\x88\xcd`7b3\x08#6\xc3\xa1\x11\x9b\x81\xd8\x0c.#6\x03\xb1\x19\x84\x11\x9b\x81\xd8\x0c\xc4f 6\x834b3\x10\x9b\x81\xd8\x0c\xc4fp\x19\xb1\x19\x88\xcd@l\x06b3\x18\x96\x03Y&6\x830b3\xfc\x1e\xd8\x0c\xd7EgvQ\x93%\xe4S\xfe\xe3p\x9c\xe4\x9d\xb8\x96G^\x9c\x1fw\x02\xac\x16i\xba \x9a\xd85\xbbS_\xf1\xe4@\xa7\xb2~1\xdf\x18w\xb2#,\xcb\xf3\x10\x8e\xb7\xdf]\xb5\xc5\x86\x9d\xdd|w&$\x05\xd8f\xb5\xab\x8a\xfa\xecW^9\x1f\xaa\xf7R^\xfd\xbe*j\x95\x87\xcf+\xa1\xe5Y\xaa{P\xee@=\x01\xb8[>\x7f(\xfbND\xce\n\xfe\x19^\x9f\xe8\xca>\x04\x04\xd8\xc7#n\xae\xa3\xdc\xbc{$\xfe\xa3\x10&\xf5PR1\xaa\xf1\x98\xc7\xb9A\xd1\xab\xcf\x9c\xff\"\xe2z[t:\xe01\xf0\xf2\xff\xe1\xed\xd0\x88yJ\xe6\xb7\xf0qf6\x87\x0f\xef_\xcd\xbfuJ\x05'\xf04\xb4s\x88\xd9|\x03\x02O \xdf\x14\xbd\xc8;\xaf\xcdX;\xfc\xc9ssZ\xf8\xb3f\x12\xb8\x1e\xdc\xb2b}mH\xc9\x0f\xcf\x15\x05fw\xf63m\xfa2\xf9\xcb\xd2\xfb\x9c\xbc6\xcf\xb9\x9f\x05\xdf\xdf'uN\x8fj\x82#1B\xbf\xc3\xad\xda \xdd\xb1\x96?\xd7\x83\xee\xfc\xc4\x8a\x1b&\xdei\xdf\x08\x9e\xca\xbf\xb3\xb6Q\x13u\x85\xcb \x8a\xcbs\xa9\x0b\xb0Q\x91ux+\xeb\xaeg\x85\xb5\xf5\xbb\xb8#\x10\x13<;\x87\x04\xe6\x81;P\xfa\xd7\xf6\xff\xb1\xf7\xee]r\xdbH\xbe\xe0\xff\xfa\x14X\xef\x9ek{G\xaa\xd2\xdb\x96\xee\xfa\x9e\x95J\xa5vM\xb7\xa5\x9aR\xc9}\xbbg\xe7T#\x99\xc8L\xba2\xc9\x14\xc1\xac\x87=\xfe\xee{\xf0\"A\x12O\x12i\x95\xed\x883gZ\xae$\x83@\xe0\x15\x88\xdf/\x00f8\x13\xa1\xc4a7\xb3\xa2\xf7rG8g\x1bp\xde\xe9$\x88@\x89\xb1\xe3\xe4\xc5\xa2\x1cY\xf7:\xaf\xd7\xc4\xd1\x19xHL\xbb\x1a\xa5 \xdc7\xb3R\xb1(%4$/\xd9\xb0!Ce\xf1 [a;\xd0Mw\xd9J0\xb7\x96y-\x0f\xcb\x10C\x97\x07\xdcq]V\x14e\x1c\xdf\xc6\xbb\xba\xdc\xe0:\xcf\x1c\xc8\xa9*`]\x1a\x1eP\x0b\xc2\x858g\xe2\x82\xd6\xb8v\x8e=\xc7%F>&\x87\x9f\xcb\x11\xd0N(x\xf8\xa2\xb1\x8c\x0e\x87\xbeAP\xdf\x11\xe3J\xcb\xea\xf0\xf2:R3;\xc2\xb9\x1d\x89\xd8\x1d\xe3\xf8\x1d\x0eu\xfcp\x99P\x86\xc7d\x8eGj\x96G$\xcf#1\xd3#\x8e\xeb\x11\xc9\xf6p\xf5\xe1\x86\x07\x12\xca\xf7H\xcc\xf8\x08\xe2|$d}L\xe5}\x8cb~$\xe2~\x8ca\x7f8\x94q^\x88\x9f\xff\xb1\x17\x06\xc8\xfe8 {a\x81\xc4\xf1@\x923AB\xb9 I\xd9 \xe1|\x90hFH<'\xc4;\x15~\x1d\xc0\nI\xc0\x0b\xf1\xde\xc5\x18\xe4P\x05\xb0Cb\xbc\xaeh\x86\x88k\x11\x9c\x95W$\x80#\x12Z\xbe\x84<\x91\x18\xa6Hb\xae\xc88\xb6\x88\xab\x07Q?_d4c\xc4\xa2\x8d}\xcd\xc7\x19I\xc5\x1a \xa6>\x040G\xa2\xb8#\x1e\xa8w\x14\x7f\xc4\xa7\xd3\x8a#%b\x91\xc4\x1b3\x9cI\xe2\xab\xdb\x086\xc9H>\x89\x0b\x8fK\xc6) f\x95\x84\xf1JB\x99%\x01V\x8eg\x97\xc4\xf0K\\\x0c\x93D\x1c\x93H\x96\xc94\x9e\x89\xcf\xa0\x11\\\x93=\xb0M\xbc\xa5\xb3\xf6\xf4t\x9c\x93\x00\xd6\xc9x\xde\x89E\x1d\x0f::\x98'\x89\xb9'>\xf6\xc9H\xfe\x89E\x97\xd8\x19\xba6\xc7\x01\x1c\x14\x17P\xee\xe2\xa1\xa4g\xa2$\xe7\xa2\xd8\xd9()\xf9(!\x8c\x94xNJ\x14+e\x04/%\x96\x99\xe2\xe4\xa6\xb8\x99\x02\xe1\\\x81P~\xca\x08\x86J$G\xc5Q\xdd1<\x15\x8b*\x8d\x03\x126$\xc2\xb8*\x8e._,\xddl\x95\xa4|\x15\x0fce?\x9c\x95T}1\x82\xb7\x12\xc3\\i\xb9+]\xf1\xa1O'\xaf\x8f\x1e\x90\x02\xcf\xd6d\x8e8vDU\xd6\xdc\x83\x9c7\x82\x80\x9c\xe4\x95\xe6-\xcco\xd6&\xcf\x14\xe7X\x0fk\xcd\xbc\xa6\x1d\x9a\x84}\xcag\x1d\x9cu\xb7\x0d\xbe\x94\xc7\x93\xb3\xc24\x18U)\x03\xceUE\xb2\xdaW\x8a\xaf(Y/\xbe\xee\x16f\xc6#oz\x1dP\x99e\xbb\x8aZo\xb7\xa7\xa5\x18\x14YY\x14$\xabeDL\x19\xe8\x8aT\xf9\xe2\xb6\xc5\xbd\x0br\xed+\x96,ONe\xf0bv+\xb5\x88\xd1\xb3\xad\xcar\xa1\x82\x94\x16\x15\xea\xac\x82>\x9d\x82\x17\xcc\xea\xf5\xb6\xd6\xe5!T\xd6\xe6M\xad\xd8>\x9b\xed\xe7\x99>Z#\xba)\xcbz\xb5\xbeE8\xabJj\x0b\x99\xb1\xa6,T\x87Q\xd5\xee>\x1c\x90\xc4\xaf1\x84\xc6'\xf1\xeb<%H\xe2\x87$~\xd3\xef\x90\xc4\xaf $\xf1C\x12\x7f+I\xa1\xdd\x18`7\n\xd6\x85$\xfe\xa9`\xee\x08(7 \x90\x1b\x0f\xe3B\x12\xff\x14\xf86\x06\xbcM\x0c\xdd\x86\x01\xb7 a\xdbP\xd0\xd6\xb0\x1f\x83$\xfe\xae\x04\xc0\xb4\xa1^R4D\x0bI\xfcA\xc0\xec\x18X\x16\x92\xf8m\x8fy\xa1\xd8\x08 6$E=\x06\x84\x85$~H\xe2\x0f\x81Z!\x89\x9f\xcb\x14p\x15\x92\xf8M\x9a\xbcp\xeaX0\xd5\xba6@\x12\xffP \x89\x7f\x04h\xea\x87Lc\x01\xd3\x08\xb84\x1a,\x8d\x83J!\x89?\x0e\x1c\x85$\xfeF\xf6\x01\x88\xa6\xe8s\x11`h8\x14\xaa\x16\xea\xd0\x84\xf8M9\xdf\xad\xc9\x85\x8c\xb9P{N\xfc\x0f\xfc\xc1\x1f\xe5s\x9d\xb4\xf8uNy\xb0T\xe8R\xf1\x1b\x8a\x16U\xb9\x11\x08\xa41I\xbe\xabQ>qg\xf3\xe4\x8d\x86\xd2\xa5\xfe\x0c\x00\x90=Y>(\xf2!\xf1\xf1\xdea\x0d\xb2\xaa\xc6wd\xf5'|SE[v\xf6t\xd8\xa6`\x19k\xcb\x82\x0e!_g);\xdd\xa3\xd3\xc9\xb4\x1b\xe6\xb1\xea\xad\"\x02G\x87\xdf\x1a\xae\xb1\xfeXK\xaf\x93\xf0\xe0v\x7fx\x88x\xa6LP'y\xd5~\xd9\xa0Pi\xea\x16&\x00_\xee\x0e\xae\xf1\x10so\x90\xf6\x9e\x19\xdeC\x0e(3\xa0\xccC\xf1\x8f\x1c!\x802\x03\xcal\x16@\x99\xb9\x00\xca<\x14@\x99\x01e\xb6 \xa0\xcc\x802s\x01\x94\x19Pf@\x99\x01e\x16\x02(3\xa0\xcc\x802\x03\xcal\x13@\x99\x01e\x06\x94\x19PfMR ~\x802s\x01\x94\xf9\x8f\x822\xbb\x8e\x8a\x97XX\xe181\xbew\xd4\xad\xf6\x86@\xce\xc4L\xd5\x1c\x19\x8f\xdb\xcd\xba\x01\xfc\x1b\x82\x85\x1a\xfe\xcc\x8f\n\x16y\xbc9\x95A\x85\xc1!\x10\x0bR\xcb#u\xd9\xda\x17\x01k#y\x80\xfd' \xb2+iO\xb0_\xe0u\x07\xdd2\x04\x0cl\x88\xfd\xe0\xde\xef\xf6pYUcq\xbe\xec\xe1/|\x96\x13G\x04\xbb\xae\x02\xd7\xcc\xfeQ\xea:R\xaa>\xf0\x84\xe1\xce\xa1\xf7\x8d]E21\x1f\xad|x\xf2\xe8[\xa3\x8a\xcf\x07u\xb5\xa3l\xb3zI\xaa\x82\xac\x9b\xd3\xd5\x0brSw1\xdc\x9c\xca\xbc]t\"\xb5q\xe7C;y\x94\xd6e\xc5\xc6\xbdH1\xe6^\x85<\xfd\xb8\xab\xc0W\x97\xb3\xd3#q\xb8\xb1\xd8\xc3\xab0\xd0\x9a,qv+k\xaa\xc2\x10\x1d~\x82Y\x9f|\xf2\xce\xf2\x14l\xbd\xc3\x86%\x8e:\xa4\xbfvB\x82\xdehXH8)9\x18\x18\x06\x05\x8e\x01\x02\xdd\x80\xdf(\xb8\x8f\x7f\xc2\xa2\xd0\x0b\xf6%\x80\xfaF\x02}\xf6C9\x82`\xbeI \xdf(\x88\x0fa\xebA@u\x18\xc07\x06\xdes\x05\xdd\x83\xc0\xbd\xc4\xd0^\x10\xb0\x97\x10\xd6\xf3\x82z\x89 \xbd)\x80^4\x9c\x97\x00\xccK\x0c\xe5y\x80\xbc\xe40\xde~@\xbc\xe4\x10^8\x807\x0e\xbes\x18\xdd\x07\xde%\x83\xee\xc2\x80;\xc3\xce\xc1>\xbf&\x06\xed|\x90\xddD\xc0\xce\x01\xd7y\xdd\x13/T\x17\xe6\xbf\xa4\x85\xe9| \x9d\xbfL\xe3\x00:5\xb3\x1b\x14\xfa\xe0\xb9\x84\xe0\xdc\x04h\xce\x0c\xa8\xbb\x80\xb9\xb4\xb0\x9c\x1b\x94K\x01\xc9\x05aJ\x1e8.\x18\x8c\xb3\xc7\xcd\xe3\x818\xbb.c\x8c* \x04\x17c\xacP\xf8\xcdo\x93`\xe8m\x04\xf0f\x8e\xe7%\x02\xdd\x82 7?\xe0\x16\x02\xb79\xad\x18\x0b\xb5\x85\x02m6\x98-\x01\xc8\x16\x01\xb1\x8d\x07\xd8\x1c0V(\xb8\x96\x18Zs\x94\xc8\xd8SG\x81j\n@3\xe8\xb3@j\x89\x015;\x9c6\x16L\xe3\x11\x01S\xc1\xcdPZZ \xcd\xb6\xf1\xf3\x82h\xb6(\xbf\x0d@K\x0b\x9f\x8d\x07\xcf,@\xd9(\x98\xcc\x0b\x89\xc5\x01b\xc1pX$\x18\x16\x03\x85Y\x810{iB\x01\x890\x10,\x12\x02\x8b\x00\xc0\x8cUK\x0b~\xd9\x06\xc5\x04\xe0\xcb\x18\xa7\xb0\xc2^\xe3@/\x17\xc0\x95\x1e\xde\x9a\xde\x93\x82\xa1\xadP`\xab\xbbD\x06dY\x99!\x82\xf1\xd9V\x16\xc8\xa1\xf7,d] \x81\xac+\xc8\xbaj\x05\xb2\xae \xeb\xaa\x951\xb0\x8cU\x19d]\x0d%\x11D3\x0d\xa4\x19\x01\xd3$\x01j\x92C5^\xb0f\x0fp\xcd\xbe\x00\x9b=@61\xa0\xcdX\xd8\xc69\x87\xfb\x80\x9b\x84\xd0M(x\x13 \xdf$\x07p\xfc\x10\xced\x10\x07\xb2\xae\xbc%\x1b\x07\xea\x18UA\xd6\xd5\x18x\xc7\x07\xf0\xa4\x81x\x02q\x0b/\xcc\x13\x01\xf4x\xb3_\"\xc1\x1e\xc8\xba\x82\xac\xab\x10\x18\xc8k\xd5X((\x1c\x0c\x82\xac\xab\x9e$\x86\x86 \xebJ\x97\xb1@\x91Q\x19d]E\xc0FS\x80#\xa3:\xc8\xba2\xbe\x10\x045A\xd6U:\xe0 \xb2\xae&\xc3Ri\xfa\\04\x15\x0eN\x85e]i)@\x9a\x1eW\xd6\xd5 \xb3\x86\xa8\x00\x89\xbc\xe2n#7\xbe\x94_\xe0W\xf0\xac&\xd2\xa3*\xf051\xa7\n\xf1\x92\xeav\xc5\x9cT\xb2\x0f\xf0\x14\xa0~.\x11\x8f\xf2\x97U'\x98\x94\x17/\xfb\xb1\xf76\x8f\xaa\xaev\x9e4*\xd4\x05\x86\x9a#&\xad\x07\xa2\xe6\xb3\xec0++r\x98\xadpQ\x90\xf5\xe1\xd5#\xf5O\xc7q\xa8G\xf2\x89&U\x8aG\xa7WD\xdc/\xa8~d\xcbS7M\xa9\x93a\xa4\x94\xdcS\xd5\xbc\xa39E]s\xe8R\x7f\x06d\xcc\x92\xce$D\x9d\x1c*{\xb0\xe8f\xedE\x91\xac\x1a\x88\xd8o\xb6\xf6G\x94H\xb1\xdb\xd8\xf7\x1a\x0f\xd0\x87\xf3W\xe7\xc7\x17\x1f\xdf\x9d\xbc;9?y\xf5\xb7\x93\x7f\x1e\xbf\xb9\xf8\xf8\xee\xc3\xe9\xf1\xd1\xc9\xdb\x93\xe37\xde7\xd9{\xde\x87\xce\xcf\xfe\xf1\xfe\xf4\xf8\x9d\xf7\xb9\xa0\x87\x8e\xfe\xf6\xfe\x83\xb5`\nW\x1eY\xaf\x90\x10\x16\x13\x91\xaa\xc7\xd1 B\xf9&\xafi-6\xab\x14\x1c0\x91\xcd(\xc0 {\x0b\xc9\x1eB\x1dS\xbc\xa8\xf2}\xc4*s\x1fIk\xdeG\xec\xff\xa3\xb2B\x9dZ:v\xc6\xfe\xe6~\x89\xde\xc8=\x87\x9e<\xe8\xd0\xc4\xf4\xb0\x81\xadj\xcf\x16\xfc\x9f\xd8\x04Lk\xcc\x93\x17y4zKxxx\x85\x8b9]\xe1Kc\xf4\xb0\xa7XV\xb2\xaf\x1bg\xcc\xb9X\x93\xf9R\xeant\"Z\x93\xad\xc2c\xb2rW\xd4\xa4\xda\xe2\xaa\xbe\xed\xe7]Z?i\xfa^V\xb2\x85\xba\xee\x7f\xec\x00\xbd\xdf\x92\xa2\x9d8qe\xb7UE\xf0\x9cC\x1c\x94\x14s\xee\x15U$#\xf9\x95\xd8%\x92\xda\x12J\xe6\xd2\xed\xf3\xfd\xc2\xcd\x08+\xc3\xba\xa4D\xe8\xcdp\x81\x8a\x12\xad\xcbbI*\xb6\x04\xf2x\xb6\xfa2gP\xf0\x0f[\xbf\xe7,PY\xcd \x9bh\xbbx\xf7\xfe\xddq\xc0\xa0o_\xf8\xf8\x8e\xffo\xc0\x93\xee\xe7\x9aY(\xaa\x1c\xa1\x93\x8f\xadz/\xd1\xcf\xa4*\x1f\x88}%\xf3,\xa5\xf9\xad\x8aT\x8b\xba\xfa_\xcf0/U\x1f\xe1\x9dm\xc6\xe6\xc0u~\xc5[\x96\xf9\xc7\xc5\xadPz_zQ\x1b|\x8b\xe69\x07\x19x\x1a:\x9f\x0d\xd8\x03.\x00K\xbcZ\xaf\xc8-\xba&\x95p\xe4\x9cc\xa4\xd3$m q\xa5\x17\x8f\xdc\xe0\xac^\xdf\xaa\xd8\x82(\x85\xe9S\xc6/\xe9\x13\x8ao-\xef\xcd=Ak\xb8\xd5\xbb@\x01\x1e\x06\x7f\xa6\xac\xea\x8b|\xee\n+\x06\x8c+\x14\xd1\x0d\x91\xfc\xaa}\xce\x95\xe6-\xafe\xc8\x80#yN}|\x9e\xeax?\xf6\x86\x97\x0f\xa4\xa9\xb4j\xbb\xb6\xb9\xec\xd5\xb2t\x10uG\xf7\xc5\xaa\xdcZ\x1b\xca\xe5\x80\n\xb1\xba\xa1B\x02\xea\xe3\xbbF\x1e5GE\xb4\x85n)S\x15\xbd\xcf\x1d\x181\x8c%\xb8\xc6\xda\xd1\xde\xf5\xe4x\xe3\x1b\xae\xd2A\x0cR\xa7 p\x13\xf3\xbd{]\xe1+\xcb\x045\xfd\xe8~\xbf\x1d\xca-\xfe\xb4k\x97)\xf9I5y\xe5\x14\xe1eE\xc8\x1c\xed\xb6e\x81\xe6\xbbJ\xde\xaco\xd5\xd7\xf8\x07\xc6'\xbc\xda\xf1\xc8\x86\xdc\x81\x1cM\xf9\xb2(\xfb\x89\x0bj4v?!,3\xb5age\xb9&\xb80M>\x9d_\xec\x97\xb1\xb9\xd2\x05\x0f\x7fiY\xa2\xbf\x1en\xcb\xaa\xa6\x87\xbfH\x96\xaa\xebB6E\xdelr \x0b\x9eFx\xd4el\x9bR\x07\xef\xa9j\xdf\xed\xccA+UK\x91T1\xa5e\x96\xe3\xe6v6\xd1\xcd\x05\x81McR\x0f\xd5\x8c\xe7q9\xd2\x08\xa7$\x11z\x03\xe1\xaeT\x1bo>\x99\xe7=G\xf2`X\xea`@\xe2`@\xda\xe0\xa4\xa4\xc1\x90H{\xda\x84AO\xba`\x9adAo\xd3\x06\xa6\n\xee)Q\xf07O\x13\xdck\x92\xe0\xf8\x14\xc1\xdf4A\xd0Q\x18wr`\xa2\xd4\xc0\x89sUT2^hJ`HB\xe0\x98t@\xd7\x9e\xab\x95\xd8T@o\xca\xdfgH\xf8\x8bJ\xf7\xfb\x0d\x92\xfd\xfc\xa9~c\x12\xfd\x9c+?\xf2\xae\xfe\xc8\x9f?\x140>P\xf0z\x85\x92'\xf7\x85\xa7\xf6\xf9S\x97\x02\xab:1\xa9/(\xa5\xaf\xf6$\xf49\xd3\xf9\xbc\xb5\xf0e\x9e\xa4L\xe4\x0bL\xe3\x8bH\xe2s\xa6\xf0M\xae{\xda\xe4={\xea\x9e\x7f\xc0\xf4\x93\xd9\xb6\xf9\x96\xac\xf3\x82(\xa8\x84ME\x0f\xca\"S\xcb\xb9\x9a\xa8L=fF\xeak\xb6j+\x96\x8b\xa9\x19\xc4\x0d\xdfl\xdf\x8a(\xd9\xe2\x8a\xb9\x96<}\x84\xf7d\xaaL\xc0\x1d!y\xdb/\xf7/\xcdsS\x86\xb7|\x13].L\xdfb\x9e\x01\xb3\\3\xcf\xf2A\xc4uioJ\xc7A{p\x90(W\x95\xe5\"\x8aR\xeda\xe0\xc8\xee\xb1!\xd5\xe5\x9a\x08\xf5\xac \xe4&\xa75)\xb2\xfe\x0b\xfc\x01kR\x89T&S\x02p\xdd\xae\x15R\xf35\xa6\xa8\"u\x95\x13\x13}m\xc2\xb6\x0e\xd2s\xbc\xc5\x85\xf4\x1cH\xcf\xf9\x1d\xa4\xe7\x8c\xc8\xce\xe9i\xd3\x93sz?\xbd&\x94\xf3\xda\x98\x8a\xa3\xd6\x9f\xb9\xcfY\xa2\"\x82J\x11\x96\x93\x95d\x15(\x132G\xbc\xa7\xae\x99\xde\xfa\xdf1\xccv\x90(\x04\x89B\x90($\x04\x12\x85 Q\xa8\x15H\x14\xaa!Q\xc8,\x90(\xa4\x04\x12\x85 Q\x08\x12\x85\x02\xbd$H\x14j\x04\x12\x85t\x81D!H\x142\x08$\n\x19\x9f\x81D!H\x14\xb2\x08$\nA\xa2\x10$\nA\xa2\x90&)\x926 Q\x88\x0b$\n\xfd\x19\x12\x85Z\x82\x8e\xa6\xa6\xb3\x91T\xa4\x0c\x11\xdc7\x1f\x1c<\xf9\xe2\x9c&\x9bA\xf0\xa2le\xe1\xdb\xbb=\x16d\x0f\xdc\xfbC\x81\xc7_pL\xd6A\xc4\xd7\xf6\xeb\x12\x14<\xe2/\n\xb6\xb1\xa2\xe7+\xe8Q\x82\xfc\x82\x1e\xde\xfc\xb1\x87D\xb6\xcc\xf6\xb6\xf36\x14\xf7\xc6)j\xd8\x9b-\xd9\xc8E\xfb\xd7J%\x9f\xba\xb3\x19\x00M\x8d\xe6\x17z#X)#\x1d\xa3\x9a\xd2\x02\xfa\x06n\xde\x1f\xcf\x19\x91\x05\xb3\xf1\xe3\xbc!\xabn\xd1\x9d\xa7z\xbbm\x80|\xf5@\xde\xba\xa0\x00\x182\xa0J(0\x94%d\x14\x18\xe9\xd07\x88G9\xb6gi\x01I/$\x99\x1a\x94\x0c\x87%\x13\x01\x93\xe3\xa0I\x87:f\xd0`pr2<\x99\x1a\xa0\x8c\x84(\x13\x83\x94q0e$P\xe9\xea\xc3\x0d\x84\x19\nU&\x06+\x83\xe0\xca\x84\x80\xe5T\xc8r\x14h\x99\x08\xb6\x1c\x03\\:\x94qH\xd3\x0f]\xee\x05\xbc\xdc\x1f|\xb9\x17\x003\x0e\xc2L\x0eb\x86\xc2\x98I\x81\xccp(3\x1a\xcc\x8c\x873\xbdS\xe1\xd7\x01\x80f\x02H\xd3\x03j\x06:T\x01\xc0f\x8c\xd7\x15\x0dn\xba\x16\xc1YyE\x02\xe0\xcd\xd0\xf2%\x848c@\xce\xc40\xe78\xa0\xd3\xd5\x83\xa8\x1f\xea\x1c\x0dvZ\xb4\xb1\xaf\xf9\xe0\xceT\x80g0j\x17\x00zF\xc1\x9e\x1e\x94b\x14\xf4\xe9\xd3i\x0d\x81&\x02@\xe3\x8d\x19\x0e\x82\xfa\xea6\x02\x08\x1d \x85\xbaB\xc9\xc9\xe0\xd0`@4\x0c\x12\x0d\x05E\x03\xac\x1c\x0f\x8c\xc6@\xa3.p4\x11<\x1a \x90N\x83H}\x06\x8d\x80I\xf7\x00\x94zKg\xed\xe9\xe9\xe0\xd2\x00\xc0tua<.\x085=\x88\x9a\x1cF\xb5\x03\xa9)\xa1\xd4\x1005\x1eN\x8d\x02TG@\xaa\xb1\xa0\xaa\x13Vu\x83\\\xe10W(\xb4:\x02\\\x8d\x84W\x1d\xd5\x1d\x03\xb1ZTi\xf0e\xd8\x90\x08\x83Y\x1d]\xbeX\xba\x81\xd6\xa4P\xab\x07l\xdd\x0f\xdc\x9a\xaa/F@\xae1\xa0\xeb\xf0\xca@!\x06\x8ci\xf0\x9c\x7f\x7f\xab\xdd\xba\xaa\xa1\x83\xda\xcd\xab:\x84%v\xab\xa6\x18\x8f69\x8a7L\xe6\xee\xdf\xb9\ni\xe0J \x0d| q\xc5\x854pH\x03\xffli\xe0\xb6[\x90\xf5\x04pmv\xed\xe7\x82\x9f\x99r\xc1M\xaa\x0e-\n\xb5\xdc\xf0\xe65H\xc7\xee\xfe\x06\xe9\xd8!s\x9e\x90Q\x0c\x08H\xc7\x0e\xe1=\x98B\x05\xd1\xac\x871\x9c\x07H\xc7N\xc8t\x88\xe19D\xb1\x1c \x1d{*\xb7a\x04\xb3! \xaf!\x9e\xd5\x00\xe9\xd8S\xd8\x0c1\\\x86\xc4L\x86:\x88\xc7\x90\x90\xc5\x10\xcaa0\x84' \x1d\xbb+\x01\xac\x85P/)\x9a\xb1\x00\xe9\xd8A<\x851,\x05H\xc7\xb6=\xe6e&D\xf0\x12B\x92\x8dc8 \x90\x8e\x0d\xe9\xd8!\xcc\x03H\xc7\xe62\x85k\x00\xe9\xd8&M^v\xc1Xn\x81um\x80t\xec\xa1@:\xf6\x08\x0e\x81\x9fA\x10\xcb\x1f\x88`\x0fDs\x07\xe2\x98\x03\x90\x8e\x1d\xc7\x15\x80t\xecF\xf6\xc1\x0fH\xd1\xe7\"\xb8\x01\xe1\xcc\x00H\xc7F\x91\x05\xd9K:\xb6\x02eE\"\xec\xa1\x82\x9c\x0f\x7f\xe9\xe1\xf6\xbf\x1e\n\xbcR\xfbA\xfc\xc1u\x9d\xda\x7f\x0f\xb3\xb8\xd5\xf7,\x89\xdc\x0dF\x1c\x9a\xcb\x9d \x85\xbbS$\xf9\xe0\x9d\xcd\xe2\xee5\x98\x0d\xde\x1bE\xd5\xa8\x9d(\x9d7@\x15\x12\xe1I\x8e\xcf\x85\xa1sc\xb097\x067\n\x81\xe3\x9f\xb0(\xf4\xe2o \xd0\xb7\x91\xd8\x9b\x9d\xd0\x17\x84\xbcM\xc2\xddF\xa1n\x08[I\xc4u\x18\xe66\x06qs\xc5\xc1\x83\xf0\xb6\xc4h[\x10\xd6\x96\x10i\xf3\xe2l\x89P\xb6)\x18[4\xc2\x96\x00_K\x8c\xaey\xb0\xb5\xe4\xc8\xda~p\xb5\xe4\xa8Z8\xa66\x0eQs\x18\xdd\x87\xa7%C\xd3\xc2\xb04\x833o\x9f_\x13\xe3h>\x14m\"\x86\xe6@\xd0\xbc\xee\x89\x17=\x0b\xf3_\xd2\"g>\xdc\xcc_\xa6q\x98\x99\x9a\xd9\x0d\n}\x88YB\xbcl\x02Zf\xc6\xb8]XYZ\xa4\xcc\x8d\x93\xa5@\xc9\x82`\x1e\x0fB\x16\x8c\x8f\xd9C\xd9\xf1\xd8\x98]\x971l\x94\x04\x15\x8b1V(\"\xe6\xb7I0\x1a6\x02\x0b3\x87\xd8\x12\xe1`A(\x98\x1f\x03\x0bA\xc0\x9cV\x8cE\xbfB\xb1/\x1b\xf2\x95\x00\xf7\x8a@\xbd\xc6c^\x0ed)\x14\xefJ\x8cv9Jd\xec\xa9\xa3p.\x85i\x19\xf4YP\xae\xc4\x18\x97\x1d\xe1\x1a\x8bo\xf1\x88\x80\xa9\xe0ft+-\xb6e\xdb\xf8yq-[\xe0\xdd\x86i\xa5E\xb4\xc6\xe3Y\x16\xecj\x14r\xe5E\xa9\xe20\xaa`\x84*\x12\x9f\x8aA\xa7\xac\xd8\x94\xbd4\xa1\x18A\x18.\x15\x89JE`R\xc6\xaa\xa5\xc5\xa3l\x83b\x02\x16e\x8cSX\x91\xa8q8\x94\x0bsJ\x8f8M\xefI\xc1hS(\xd64\\\"\x9bk\xce\xbbhC\xf8!\xa7\x8esJ\x9d\xfb\xd0n\xda\xeb\xc9\x1b\xf3'\xbb\xc5\xea)\x81\xe4\x99\xa6\xc3\xf5!\xcft2\xea\x9f\xa6\xcf\x05#\xff\xe1\xd8?\xe4\x99\n\x19W\x90\x1e\xa6n+P\x03\x83\x8b\xc7\xd4\xc2`\xe71L.\xa0\x15\xf9\x1e\x94|\x806\x9bK.A\xd2\xcfV\xf2}\xe4\xf6\x16\xe4\xa6\xbe\xa0\xe4\xd3\x8e\x14Y\xe0]\xcb\xef\xc8M\xfdA\xbeqF2\x92_1\x97\xa0\xdeUr\xb9e*Q%\x7fP\xaa\xb9_\x84\x05\x97\xa0\xd1$\x0bfL\xbc5|E>vg\xd3n;\xb6\xbc\x90\x16\x88\xc2I\xbdd\x0d \x90s\x137\xa6U\xb6\x1e\x0c@\x04T \xa0\x02\xe9\x12W\\\xa0\x02\x01\x15\xe8nR\x81\xda\x85\xa1K\x00b\xcb,\xa1\xb5\xf0\xf1\xbd\xfc\x1f\xc3\x12\xd3(\x04\"\x10\x17 \x02\x01\x11\xa8\x15 \x02\x01\x11\xa8\x15 \x02\xd5@\x042\x0b\x10\x81\x94\x00\x11\x08\x88@@\x04\n\xf4\x92\x80\x08\xd4\x08\x10\x81t\x01\"\x10\x10\x81\x0c\x02D \xe33@\x04\x02\"\x90E\x80\x08\x04D \x02\x01\x11H\x93\x14\xa4\x0c \x02q\x01\"\x10\x10\x81\xfelD\xa0}\x90R\xd8_Z\xe9`\xed#&\x02\x85|t<\xf5\x8b\xf3\xf4.\xc9\xedD\x12\x95\xb5\x03\xdb\xa8+J\xd4\xf7\x15k\x85\xfdS\"?\x98R\x01o\x9d\xe2%9\x13l\x96\x03\xf1\xbbE\xd9'\xb6\xder5\x9c\x14\xb8en\xd9\xa6\xa45\"\x1cO\xe1 \x8c\xe1\xd5\xba\xac\xf1\xd8;<\x02\xe6\x15i\x02k\xac\x9f\x7f\x9e\xd7\x9f\xff\xa3\xe5\x04+$O\x83\x8dl$\x08\xddDY\xb9+\xea\x0b\xae\xcc\xe6u^c\x8a(\xa9\xef\xa3\xbc\xa6\n\xa0\xa4hW\x88\x11?\x17\x98\xcdun\xe8j\xfe9D\x14E\xe3\"\x95\x1d\x17?/\xd0\xf2\xec\xf4\xa8\xe9\xcc\xca\x7f\xa6\xe8zE*S'\xb2\xe0\xdfYY \x1d\x9c+\xa0\xd8N\xca\x1bg;\x17\x0e\x07\xe9\x961\x9aC\xbd\xf1\xa1\xdc\xb4\xe5vF\x95*\xb2%\x03\x14Q\xa0\x88Z\x04(\xa2@\x11\x05\x8a(PD5IA\xd7\x03\x8a(\x17\xa0\x88\x02E\xf4\xcfF\x11\xd5\n\xd2\x10{\x0e.\xc9\xad\xad<=`O2e\xb0\\Z\x04\x91S\xb0*t\x82\xc1AC\xab\xe1!\xb2e/\x96\xc4)\x03\x8a\x14e\xa7\xca\x1c\xa0\xf7\x05\x07\xda\xf9\x1e\xba\\,(\xa9\xd9\xb6\xb4[\\\xa4\x85\xf8)\xe9P\x9c\x98\xad>I\x0e\xac\x92\xd6X\x0b\xbc\xa6^kY\x02&\x06#\x8a\xf2\xd9\xec\xd8\x0bV\xc8\xcapS\x16\xbb\x0d\xa7\xb6\xc9\xbf\xf1Y(\xc3\x05\xab\x8f\x88\x16\xadH\xa1\x0c\xbf+\x9a\x00]\xcf-?\xe1\xda\xd6\x84\xd2\xd6\x84\"\xa4\xb5\xe3`\xef%\x89\xb4gW\xfd\x9e\x8dk9\x15P3\xef:\xdf\xe4\xa1\xd6\xe5\xcf*|\xd9\xc6j\x12\xc1[\xbd\x07\x0b\x1f\x89\xf6\xef3\xde\x8aP\x8d\xfe\xa7\x93\x05Z\x93E-\xa3\x82y-\x96 \xe5L\xf3\xb8\xb3\x18 \xe2#\xcc\xce\xb3[\xc1\x93\xc0\xdb\xedg\xb4\xa2\xce\xcdj\xdfw\xd9R{\x83Y\x94\xf7\xd0\x92O4\x88\xfd#/\xe6y\x86k\xd2re\x84\x05\xf9\x83\xb2#\xe9\xea\xf2\"[\xef\xe6=W\x19\x8b\xaf4\x10`\xaf\xc58\xa0\xacE\xa6\xd9\x92\xa6\xd1\x12{\x93\xcb\xc7\x93>I\xb3W\x05\xbe\xbb\xa8\x08\x95\xc8?\x1f^\xedxdC\xee@\x8e\xa6|Y\x94U/\xae\xafFc\xf7\x13\xc22S\x1bvV\x96k\x82\x0b\xd3\xe4\xd3\xf9e\xbf<\x7fz\xf8\x8b\"\x1d\xff\xea\xa0\xf9\x1b\x99\x18\xbc\xca9a\xd3\x1a\xa7\xdd\xce-\xdc~\xe6\xb6\xad\xc2I\xfb\xf7\x94\xfd~\x1f\x9c\xfd(\x8eE\xd8\x11\x8f\xca\x8c\x86\xebg\x15\x81\x86{~\xfd\x080\x1c9 \xbc\xc2F\xe2\x8a\x0b\xbcB\xe0\x15~n^\xe1\xa0\x17\xd9I\x80\x0d\xafPO\x1b\x91\x03\xac\xbf\x10#m1\xe1\xee\xc4\x00\xd6\x93\xf3\xad\x98\x8f\xf0\x9a\x96\xcasaK\x9b\x98\x9bd\x94SYlQ\x95\x9bv\xfe\x1a\xe8sLg\xc0T\xec\xfe\x06L\xc5\x90\xb9T\x080\x15\x81\xa9h\x16`*r\x01\xa6\xe2P\x80\xa9\x08LE\x9b\x00S\x11\x98\x8a\\\x80\xa9\x08LE`*\x02SQ\x080\x15\x81\xa9\x08LE`*\xda\x04\x98\x8a\xc0T\x04\xa6\"0\x155I\xc1\x1a\x03\xa6\"\x17`*\x02S\xf1\xcf\xcbTTl\x14kI\xba'\xe5\xa5,\x82\x053\xdf#\x01G;\x8b\xceA\xbe\xf9\xef\xfe\x19\x9bG\xedk\xb6\xe355\xcd\x9c~C\xa8~\xb0\xa6R\x17|\xae\xa6\xf6E\xf9\xd0\x9d\xa5\xe7h5\xbf\x1b\x00!\x9c\xa6 \xa7i\xc2i\x9ap\x9a&\x9c\xa6 \xa7i\x1a\x04N\xd3\x84\xd34\xe14M`\xbd\x1at\x01\xeb\xb5\x91?.\xeb\xd5u\x9a\xa6\xb6\xedJq\x92\xa6\xbeo\x84C4\xb9\x0055b\xef\x07\xd4T\xa0\xa6J\x01j*PS\x81\x9a\n\xd4T\xa0\xa6\x025\x15\xa8\xa9\xa1^\x12PS\x1b\x01j\xaa.@M\x05j\xaaA\x80\x9aj|\x06\xa8\xa9@M\xb5\x08PS\x81\x9a\n\xd4T\xa0\xa6j\x92\x82&\x08\xd4T.@M\x05j\xea\x9f\x97\x9a\n\x87h\xc6\x9dP\x08\x87h\xee\xd1\xb8\xfe\xe3\x1f\xe1\x10\xcd\x14V\x84C4\xe1\x10\xcdP\x0e\xff\xe1/\xdb\xe6`\xcd\x0b\xc5>\xa6\xbf\x1e\xee\nN\"\xbd\"s~\xe4\xa6\x83\xea\xafu\xa5\x8f\xcdK\xaf\xb2\xcb!\xcf\xbf\xd5\x89N^\x1f\x0d\xa8\xb7\x8d\x9a\xfe!\x92Z8V\xad\xe2\x9c\xe9\xabJkL\x02\xe8\x96E>qg3\x00\x9a\xba$eaX1\x02\x0f\xe5L\xd2|\xd69\xe5\xc3Uk\xb7\xfe1\xa9M\xb9{:\x80E\x08,B`\x11\x02\x8b0\x9eE\xd8\x9d\xb7\x87\x14B\xf9\xdf\xb5\x8fC\xd8[\x8b\x80;\xc8\x05\xb8\x83\xc0\x1dl\x05\xb8\x83\xc0\x1dl\x05\xb8\x835p\x07\xcd\x02\xdcA%\xc0\x1d\x04\xee p\x07\x03\xbd$\xe0\x0e6\x02\xdcA]\x80;\x08\xdcA\x83\x00w\xd0\xf8\x0cp\x07\x81;h\x11\xe0\x0e\x02w\x10\xb8\x83\xc0\x1d\xd4$\x05\x8f\x0b\xb8\x83\\\x80;\x08\xdc\xc1?3wpH\x0c\xb1\x95JQ\x05B\xf8\x01\xf1\x05\xec\xc3H\x06\x00\xc9\x1a\xd8\xb0\xe2\xe2Y\xb9^\x13\xbe\x95}+\x1f\xc9\xe8\x95\xf6\xfb&/N\xf8w\xd0#\xf9\xd7\xdf\x98\x91\xd3\xfe\xcdB\xcc\x11\xcfEss\xc4\xc1*^z\x8e\xd4\xdeg\xe34\n'\xb2rd)\xe4C@\xcc\x112\x9a\x98\xb3\xed\x9e\x1f |\x1c\xe0\xe3\x00\x1f\x07\xf886{v\xa7\xc50>\x8e\x9c\xb1SPr\xe0l/\xe0\xe7\x98\x7f\x07~\x8e&\xc0\xcf\x01~N+\xc0\xcf\xa9\x81\x9fc\x16\xe0\xe7(\x01~\x0e\xf0s\x80\x9f\x13\xe8%\x01?\xa7\x11\xe0\xe7\xe8\x02\xfc\x1c\xe0\xe7\x18\x04\xf89\xc6g\x80\x9f\x03\xfc\x1c\x8b\x00?\x07\xf89\xc0\xcf\x01~\x8e&)\xb8\x12\xc0\xcf\xe1\x02\xfc\x1c\xe0\xe7\xfc\xe9\xf99&\x9a\x88\xadp\x8a8\xe0`\x0b\xc4\x17\xefO\xc6\xceQF\xfb\xd5\xc1\xbb\xe9\xe3\x9b\x9c`\x91\x136\xd1\xf1\xfb)\xe7\xc3\xbb(\xf9\x95\xb7F\xceL_\x99|\xe6\xceRf\xda:EA\x95\x9e\xc8VsA%\xb7[\xff\x88\xa0Z\xbb^\x8aO\xa0\xfd@\xca\xb6*\xcb\xc5\x1e\xca\xb3!\xd5\xe5\x9a\x08\xf5ld\x91\x9b\x9c\xd6\xbd[\x9e\x91\xfa\xbe\x95Q\"\x95I>\x00\xae\xe5\"\xc3j%4_c\xda\\}:\xf4_\xad\x8d\x84\xbc\xa8,ps\xbc\xc5\x05n\x0eps>77g\xd0\x8b\x8cW\xe45\xd4\x1c\xfd.e9\xb6\x04\xc5\xcfr\xa9\xef\x82_\x1b,\xe6\xd6~-\xc5T\x84\xd7\xb4T\xe7\xfa\xb1eLLK2N\xa0\x8c\xb5\xa8\xcaM\x7f\xea\xeak\xc3\x83\x96\x1b\xcek\xc0\xfc\xe9\xfe\x06\xcc\x9f\x90IU\x080\x7f\x80\xf9c\x16`\xfep\x01\xe6\xcfP\x80\xf9\x03\xcc\x1f\x9b\x00\xf3\x07\x98?\\\x80\xf9\x03\xcc\x1f`\xfe\x00\xf3G\x080\x7f\x80\xf9\x03\xcc\x1f`\xfe\xd8\x04\x98?\xc0\xfc\x01\xe6\x0f0\x7f4I\xc1\xc2\x00\xe6\x0f\x17`\xfe\x00\xf3\xe7\xcf\xcb\xfcQ\x14\x14kI\xba\xf4\x9e\x94E\xb0\x80\xe7{$\xdf\xf03\x03\xb6\xa1\xcc\x1b-\xb2 \xd0\xd13\xf1z\xc3\xc0a>\xb7\x04\xf0{f\xe2\xf3\xd1\x8cpd_\x9e\xaa\xa2\x81\xfbl\xc0\x0b\x1ds\xd6\xeb\x9a\x10\x9b\x81\xaa#?)\x1f\xb8\xb3<\x1dUK\x1bD8\xbc\xa8L\x88\xf9\xba2\xedm\x01Y\xcbJ\xa0\xc5\x1a/\xb9\x8b\x96/\x90lK\xc1\x92\x01\x8a\x8e\x12\xa0\xe8\x0c$\xae\xb8@\xd1\x01\x8a\xce]\xa6\xe8\xc8\x15!\x9c\x9f#\x189\xfd J\xacWr\x12\xedW\xd5\xc1\xd3\xb9\x0fD\x1d \xeap\x01\xa2\x0e\x10u\x80\xa8\x03D\x1d \xea\x00Q\x07\x01Q\x07\x88:\xad\x00Q\xa7\x11 \xea\x00Q\x07\x88:(\x9ak\x02D\x9d\x8e\xc4\x19\x0f\x88:\x1d\x01\xa2\x0e\x02\xa2\x0e\x10u\x80\xa8\xd3\x8a}+\nD\x9d\xce\xdf\x81\xa8\x03D\x1d!@\xd4\xa9\x81\xa8cT D\x9d\xdf\xa0 \xbf{\xa2NY\x14\xe2\x14\x1ez\xf8K\xfb\x1f\xbf6\x0c\x1e\x07\x13G\xbbN\xe4\xa8y\xf3H\xbe\xd7\x1e\x88#/\x9fR\n\x07'\xbb`\xd4~\xb7QH\x8a\xb9\xf1\xa8\x9c\xe1\x87\xe4Sw\x96\x84\xa3\xea}7\xe0?\x8e\xf0[\x03_\x02\xe7\x96qL\xf1\xac\xf2a\xd4\xf0&\x85-B\x1b\x106#\xc5nc\xdfP=@\x1f\xce_\x9d\x1f_||w\xf2\xee\xe4\xfc\xe4\xd5\xdfN\xfey\xfc\xe6\xe2\xe3\xbb\x0f\xa7\xc7G'oO\x8e\xdfx\xdfd\xefy\x1f:?\xfb\xc7\xfb\xd3\xe3w\xde\xe7\x82\x1e:\xfa\xdb\xfb\x0f\xd6\x82)\xf0|d\xbdB\xe2tL>\xf0vR\x8c\x03N\x7fS\xad\xc5\x99\x16\x1c\x15\x92\xcd(\x10\x18{\x0b\xc9\x1eB\x1d\xeb\x98\xa8\xf2}\xc4*s\x1fIk\xdeG\xec\xff\xa3\xb2B\x9dZ:\xb6\xff\xfe\xe6~\x89\xde\xc8\x8d\x15\xaf\xa1_\x13\xd3\xc3\x06\xb6\xaa=\xf3j~\xdaQ\xde\x93+6\xdf\xf0\x90\xfb\x96\xf0\x18\xf8\n\x17s\xba\xc2\x97\xc6\x10iO\xb1\xacd_\xb7v\x17\xa2$_(\x9d\x88\xd6d\xab@\xa7\xac\xdc\x155\xa9\xb6\xb8\xaao\x05\xb30\xe0\x93\xa6\xefe%\xf3F\xea\xfe\xc7\x0e\xd0\xfb-)\xb4 \xb6\xb2\xdb\xaa\"x\xceq\x1cJ\x8a9w\xfd$IP\xdd\x06\x18P4\xd1\x01\xfa\x85\xe3\xbc\xcal]R\"\xf4f\xb8@E\x89\xd6e\xb1$\x15s\xfex\xd0^}\x99\xd3D\xf8\x87\xad\xdfs\x16\xa8\xac\xe6\x84M4\x9e\xa9\xeczE$*A\xf41\xc1\xdf&\xbc\x14\xbbB\xfe\xc7\xfef\xb5\xf7go\x8e\xcf.\xde\xbd\x7fw\x1c0\xe8\xdb\x17>\xbe\xe3\xff\x1b\xf0\xa4\xfb\xb9f\x16\x8a*G\xe8\xe4c\xab\xdeK\xf43\xa9\xca\x07b\xf3\xcc\xdcgi~\xab\"\xd5\xa2\xae\xfe\xd73\xcc\xcb\xe6\nK\xd6\xd9fl\x0e\\\xe7W\xbce\xd9&\xa0\xb8\x15J\xef\xcb\xed\xc2\x06\xdf\xa2y\xce\x91\x14N\x8f\xe2\xb3\x01{\xc0\x85\xd25\x1c\xaa[tM*\xc2zo\xed\x1c#\x9d&iK\x88+\xbdx\xe4\x06g5'\xaai\xa50}\xca\xf8%}B\xf1\xad\xe5\xbd\xb9'h\x0d\xb7z\x17(\xc0\xc3\xe0\xcf\x08\xf7\xdc\x15;\x0d\x18W(\xa2\x1b\"\xf9U\xfb\x9c+\xcd[^\xcb\xb8\x08\x87+\x9d\xfa\xf8<\xd5\xf1~\xec\x0d\xdf\xee\x8f\x12TZ\xb5]\xdb\\\xf6jY:\x88\xf2\x92/V\xe5\xd6\xdaP.\x07T\x88\xd5\x0d\x15\x12P\x1f\x1bw\xb2\x15udi[hm\xcfF\xefs\x07F\x0cc\x89 \xb2v\xb4w=9\xde('^9\xd8O\x1c\xc7W&\xe6\x01\x8a\xba\xc2W\x96 J\xf2\x0b& \xc6~;\x94[\xcc\xf6\xab\xaaH\xf2\x93j\xf2\xca)\xc2\xcb\x8a\x909\xdam\xcb\x02\xcdw<\x12\xe6\xa2v4\xfe\x81\xf1 \xcf\x10\x0d\xaf\x11\x1fu\xc6Mv+\xfe\xd1\x11\xfe\xbdf\x19w}2d\xda8Q\n\xe6r+\xd9\xb8\xd0X\xeb\x17l\x83\xdaF[ye\xb1e\xfaT+\x9c\xf1\xc7\xb6\xb8\xf2\xf8\xd2\xe1\\b<\xc87h\xdb\xdc\xd7\xb5\xc5\xcb\xbc\xe0{f\xc3\xaeS\x1d\xb3\xaa\x1e\xb1\x1d\x198)\xa5\xa1 7\xf5\xc5%\xb1,O\xde\xd6\xf6\xf2+l7\x9a*Q\xdfWw\x98\xb2\x7fJ\xa2\x11\xa6\xd2\x11=\xc5Kr&\x8e\x94=\x10\xbf[\x94 \xe66S\xc3\xd42\xd3\x11\xb4)i\x8d\x08\xa7\xefp\xce\x8f\xe1\xd5\xba\xac\xb1\x85g\x1bl\x00\x7fv\x84uF\xe1\x9f\xe7\xf5\xe7\xff\x10\xb9%\xacK)\xe2\x98\xc6R\xb2qnu\x13\xf1\xb5\xe7\x82+\xb3\xcd\xaa\xd7\x98M\xbc\xf5}\x94\xd7T\xf1\xe1(\xda\x15b`\xcd\xc5\x9a{\x9d\x1b\xba\x9a\x7f\xc0\x8a\xa2h7\xd3\x96\x9d\x88r^\xa0\xe5\xd9\xe9Q\xcb\xaf\x97\xe1Z\xca\xf6\x00\xc6\x0d\x91\x85n\x99\x95\x95\xd0\xc1\xa9\xa9\xea\xc8a\x15\xfce;\x1d\xbe\x91\xd1-c4\x87z\xe3C\xb9i\xcb\xed\x041+\xb2%||\xbf\xc6U\xd3H\x1eD\xa4k\x16\xde3m\x98H\x1f\x8f\x85\x1b\xc3!\xe5 R\x9e \xe5\xc9\x95\xf2d\xbe1|\x18\x84\xef_\x19~\x16|e\xb8E!\\\x17.\x04r\x91 \x17\xa9\x15\xc8E\x82\\\xa4V \x17\xa9\x86\\$\xb3@.\x92\x12\xc8E\x82\\$\xc8E\n\xf4\x92 \x17\xa9\x11\xc8E\xd2\x05r\x91 \x17\xc9 \x90\x8bd|\x06r\x91 \x17\xc9\"\x90\x8b\x04\xb9H\x90\x8b\x04\xb9H\x9a\xa4\xc8\x0b\x81\\$.\x90\x8b\xf4\xa7\xc8E\x1a\xa6\x8b\xf4s\x91Z*\xd9o\x92\x05\xd4\x92i\x0e.\xc9\xad\xadT=0M\xb2S\xb0\x9c\xd4+R\xef\xaaB0\x19tP\xff\xa0\xa1\xb2\xf0\xe0\xd4\xb2\x17\xc5\xe10\xbd\xa4\x829\xe8)\x07\xe8}\xc1\xc1m\xbe{-\x17\x0bJj\xb6!\xec\x16\x17i\xc1uJ:T\xfb\xbe\xcb\x96\xda\x1b\xcc\xa2\xbc\x87\x96|\xa2A\xec\x1fy1\xcf3\\\x93\x96\x9f\",\xc8\x1f\x94\x1dIW'\x0f\x01\xed\x9a\x13\x8b\xaf4\xe0[\xaf\xc58\x94\xab\xc5\x84\xd9b\xa2Q\x01{\x93\xcb\xc7\x13\xdak\xad^\x15\xb8__\x11*1w>\xbc\xda\xf1\xc8\x86\xdc\x81\x1cM\xf9\xb2(\xfbY\x16j4v?!,3\xb5a\x87gW\x9bO\xb5\xb6\xa5K\x8alI\xce\x0f:\xbczt\xc8\xd7#\xf9\xa0)\x17\xf2\x88?y\xca\x9f\xea\xa4>\xb6\x0b\x99j\x92|\x96I\xe2\x919\xc3Q\xd3tO\xd5\xf5\x8e\xe66\xeaV\xd1\xa5\x97\x02\xcb\x8d\xa2\x9f\x88;4\xca\xa6\x9c\xef\xd6\x86\x08\xb1\xb5P\xc8\xcb/\x90X\xd5\x85\xb0\xb5\x83\x82\xe0\xa2\xc0; \xf0\xde\xe0|Ht{P\xd0\x8e\xa5\x14\x0dX\x01o\x92\xb1F\x1d q\"\x8a\xd1\xf9\xd1]\x0eA\xc1\xd1\xba]\x9f\xcdS\x05\xb3y:\xc3\xa0\xa5\xf0\xb4\xa5\x01\x0eO\xf77\xe0\xf0\xf8zg+\xc0\xe1\x01\x0e\x8fY\x80\xc3\xc3\x058\x0c\x8a\x1f\x03\xc4\xbb\x01\xf7Qp;\xff\x84E\xa1\x17lO\x00\xb5\x8f\x04\xda\xad\xf0d\x18\xcc> d\x1f\x05\xb1#lM/\xa8\xc3\x00\xf61\xf0\xba\x0b\xf4\n\x02\xd7\x13C\xebA\xc0zBX\xdd\x0b\xaa'\x82\xd4\xa7\x00\xea\xd1pz\x020=1\x94\xee\x01\xd2\x93\xc3\xe8\xfb\x01\xd1\x93C\xe8\xe1\x00\xfa8\xf8\xdcat\x1fx\x9e\x0c:\x0f\x03\xce\x0d;w\xfb\xfc\x9a\x184\xf7A\xe6\x13\x01s\x07\\\xeeuO\xbcPy\x98\xff\x92\x16&\xf7\x81\xe4\xfe2\x8d\x03\xc8\x1dY$>x\x01\x1a7\x13Z\\\xc0xZX\xdc\x0d\x8a\xa7\x80\xc4\x830]\x0f\x1c\x1e\x0c\x86\xdbq\xabx \xdc\xae\xcb\x18#N\x02\x81\xc7\x18+\x14\xfe\xf6\xdb$\x18\xfa\x1e\x01|\x9b\xe3\xe9\x89@\xef \xc8\xdb\x0fx\x87\xc0\xddN+\xc6B\xdd\xa1@\xb7\x0d\xe6N\x00rG@\xdc\xe3\x01n\x07\x8c\x1c\nn'\x86\xb6\x1d%2\xf6\xd4Q\xa0\xb6\x8aE\x1a\xf4Y \xed\xc4\x80\xb6\x1d\xce\x1e\x0bf\xf3\x88\x80\xa9\xe0f(;-\x90m\xdb\xf8yAl\x1b\xcaf\x03\xb0\xd3\xc2\xd7\xe3\xc1k\x0bP=\n\xa6\xf6B\xd2q\x80t0\x1c\x1d F\xc7@\xd1V \xda^\x9aP@0\x0c\x84\x8e\x84\xa0#\x00hc\xd5\xd2\x82\xcf\xb6A1\x01x6\xc6)\xac\xb0\xf38\xd0\xd9\x050\xa7\x87\x97\xa7\xf7\xa4`h9\x14X\x1e.\x91\x86Lq\x84)-\xb3\x9c;\xff|&\x11s\x94H\xf3\xb4\x1e\x8f\xbc\xad\xcar\x11\x95\x83\xe7\xd9\x87\xca\x92mHu\xb9&B=\x9b\xff\xc8MNkRd\xfd\x17\xf8\x03\x17+\xc2v\xdd\xd6\x9cn\xf13\xc2\xb5\xec8\xacfB\xf35\xa6\xa8\"u\x95\x13S\xa8\xa6\x1e\x8f$T\xe4*\xa7yY\\\x088l\xe2\x8e\xdd\x9f\xed,\x1aK|\xb3\xc5\xf4\xd4\xe1\xd6T\x0b\xe9\x94\xa6mcS\\\x9b%Q\xfa\xe2\xcaVa}M.\xfa\xcb\xfc\x8a\x14MY\x06\xef\xfbC\x01\xefX\x01\x98G\xc2\xb4\x9dI=\xdf\x8b\xef\xe4l\xc7\x9cU<\xe2\xc2\xa6\x9fZ\xe0\xba\xa2\x14\x06]\xd7\xab|M\xd0%![6M)e\xefxs\x9a\xc6>\xdf\xf6\xe3\x0diB\xe2\x88\x96\x1b\x1e/\xa7\xa4\xa0;\x8a\xf0zYVy\xbd\xdaP\xb4\xc1\xb7([\x95%\xf3\xa2L\xc9\xf5l\xe2\xacm\x81ri\xb7\xbc@\x19\xa98T\x93\x95\xc5\\\xc6\xa6\xc9\xc1\xf2\x00\xadp\xc5\xc3i\x97\xf4\xbe\x18\xdb\x0f68[\xe5\x85\xc9\xe1\xebG\x0d\x8d\xab\x08o\x1eJP\x86)\xa1\xf7;\xd6\x15\x06\xe9[\x97\x96\xbc\x13\xdaK\xcf<\x8e\xbc\xd8\xf1\xc0\xa6\xe9\x933\x826e\x91\xd7\x02]Y\xdf\n\xed\x98S\"\x08\xeb%\xd2\xa5\xed5\xf2\x92\x18\xcf\xc2\xe5\xf6\xec\xfc=.\xcd;I\x96\xb7#\xc9\x1b\xbd&\x94G}\xb4A\xcb\x1b\xee>\x0f\x92\n\xec\x9d-\xcdb\xd62\xbb\xef\xd2\xb2\x8b\xaa\x1cD\x7f\x9c\xd3\x1e\xa4\x98C\x8a9\xa4\x98\x0b\x81\x14sH1oe\x0c\x06nU\x06)\xe6CI\x84\x87OC\xc4G`\xe2IP\xf1\xe4\xb8\xb8\x17\x19\xdf\x036\xbe/t|\x0f\xf8x\x0cB>\x16#w\xce\xe1>\x94\x191\x87\x14so\xc9\xc6!\xe8FU\x90b>\x06K\xf7\xa1\xe9i\xf0\xf4@\x90\xd8\x8b\xa9G\xa0\xea\xdeT\xdfHd\x1dR\xcc!\xc5<\x04s\xf7Z5\x16w\x0fG\xde!\xc5\xbc'\x89qxH1\xd7e,*oT\x06)\xe6\x11\x18\xfd\x14\x94\xde\xa8\x0eR\xcc\x8d/\x04\xe1\xfa\x90b\x9e\x0e\xe5\x87\x14\xf3\xc9\x1c\x804}.\x98\x07\x10\xce\x04\x08K1or\x0d5-\x9d}d\x877 \x02\xfcf\x8a@^\xbc\xec\xc7\xc0\xdbd\xca\xba\xday\x92d\xe3\x12&\x15\xd2\x1a\x973\xa9e\xca\x1f)\x0d\x96k\xbe[,\xd7\xcc\x98\xc0\x02\xc1n\xf4\xb9\xb2-\xbb\x9f\x92\x8f\xdc\xdd\x8c\xcb\x9em\xef\x06\xbc\xe5\"+\xb4\x1c\x97^\xa3Y\x01\x7f\xe4/\x10\n(\x14\ne\x7f\x08 \x88?\xa10j\x85\x904|\x10!A\xac\x10!{\xacF4ODHH\xe0\x0b\x8d\xe2\x8cXU\xa9\x92F2G\x84\xd4\xa3\xf8#vu\xa5\x9bE\"$\x8aKb\xd5\xd2\xe1\x98\x041J\x84\x8c\xe1\x958\xec\x87\xebPv\x89\x90q\x1c\x13\xab\xba%\xa9\xa9\x81i\xa2\xa47\x85\xba\xe3\xd1\x93g\xa0\xda\x83\xfc\xa3\xf01\x1b:\x90\xd0\x08\x16\x80S\x999\x14\xec\x88\x8c\xa4f\x03 ?#\x00\x8d`\x05\xb8+\xa0\xb2\xe4C\x98\x01(\x15;\x00\x8dd\x088\x152\xe3\x06\xb3\x04\xd0t\xa6\x00\x8af\x0b8U\xb5\x99\xf4\xe1\x8c\x01\x94\x9a5\x80\"\x99\x03(\x96=\xe0\xee\xd9\x0d\xb3 \x94A\x80R\xb3\x08P\x18\x93\x00\xa5d\x13\xa0\xc9\x8c\x024\x8eU\x80R1\x0b\xd0(v\x81{8`J\xe6~\x86\x01\xda\x0f\xcb\x00\xed\x91i\x80\xf6\xc36@\x91\x8c\x034\x8eu\xe0\x9b\x82\xc3\x98\x07(-\xfb\x00E0\x10P<\x0b\x01\x8d`\"\x04L\x99_\x07\xb0\x11P\nF\x02\xf2\xb1\x12P\xb8{\x16\xc0N@\x91^\\4K\xc1\xa9\x8d3\x18\x02\x98\n(\xa2\x94 \x19\x0b(\x8a\xb5\x80R3\x17\xd0H\xf6\x82\xbb_Q?\x83\x01\x8dg1X\xf5\xb1/\xfa\x98\x0c(\x19\x9b\x01\x85\x83\xf2(\x84\xd5\x80\xe2\x98\x0d\xc8\x07E\x8ed8\xa0\x00\xbd\x0e\xb4#\x11\xdb\x01\x8d2n8\xeb\x01\x05\xd4r\x04\xfb\x01\x8de@ \xcf\xbd\xc6\xc9\x98\x10(\x9c\x0d\x81\x02\x19\x11(\x98\x15\x81\xc2\xac\x1e\xcf\x8e@Q\x0c \xe4dI\xa0TL \x14\xcb\x96@\x13\x19\x13(\xc0\xbc\x11\xcc \xb4\x0f\xf6\x04\n)\xa3c$\xa4cR\xa0\x106\x05\x9a\xc0\xa8\xb0*d\x0f\xbaX\x15(5\xb3\x02y\xd9\x15h,\xc3\xc2\xaaM\xecQ\xdd\xdb\xf5\x00\xa6\x05r\x02\xc2\xc8\xc9\xb8@\xa3X\x17VUN6\x06\x1a\xcb\xc8\xb0js\x9c\xa7 $\x1d3\x03\x05\xb13\xd0\x08\x86\x06\x8aci\xa01L\x0d\x14\xcd\xd6@\x9e\xd56\xe1M\xec\xa1\xcc\x0d4\x86\xbd\x81b\x19\x1c\xc8]\xf11L\x0e\xab2\x8d'\x11:d\xc2\x18\x1d\xce\x01Q,\xdd\xac\x0e\x94\x96\xd9\x81|\xec\x0e\xe4fxX\xdf\x19\xcb\xfc@ \xfbn\x04\x03\x04E\xb1@\x90\xf1T\x08!f\xdc\xdc\xf0p\xc8f\xbd\xcbs\xf8{^\xaf$\xb4*\xae>\xe7D\xa4\x1e@\xaf\xa6]\x93:m\xc6U\xe9\xce\xbci\x07\x0f\x9b+A\x8d\x87\\\xd8\x0f\xb7h\x0e+7\xf0\x1d\xc4\x07\xb4\xf3\xcc\x0d\x99\xd0\xf2\xd1\xf1\xc7H\xa8\xfb\x18\xec\xe9\xbdA\x072XcC\xb2\x16\xffm\x8b\xb44\xf7A\xc8\xc4\xf7\xe6j\x08\xb4\xc5\x94\x8aH\xb2~\xe3\xbb\xf8\xdd\xa2\x8c\x1f\xab\xce\xd5\xd8\xef\x8e0\xbc\xca\x0f\x80\x9fh\x00\xff\x89\x14\xd6`Ss\xfe\xbc\xedB\x02-\xff\xcb\x16\x19\xd1M\xa4\x1f\xe5oy\xfc\x1a\xf3c\xe9\xef\xa3\xbc\xa6\n\x0f\xa0hW\x8813\x17!\xcf\xeb\xdc\xd0\xd5\xfcC\xb2s/~\xae\xc2\xe4\xcd\x82\x93\x17hyvz\xd4\x9ep \xa7I\x8a\xaeW\xa42u\"\x0b\x1c\x95\x95\x95\xd0\xc1W\x04u\x8e\x8cZ\xcf\xd8\xc2\xc5\xa3\xa8\xbae\x8c\xe6Po|(7m\xb9\x9d\xf3kE\xb6\x84\x0f\xf0\xd7\xb8j\x1a\xc9\xe7\xc1t\xcc\xc2{\xa6\xcd\x7f\xe9N\x9b\xb6\x01$N\x90\xe8\x92\xbc&\x9c\"\xd1#\xa6\xb1\x16\x12\xfb\x93\xe6q8\xbb\xa1\xfb\x1b\x9c\xdd\x102\x1b\x08\x89em\xa8P\xb7Ua(c#)[\x03\xcen\x80\xb3\x1bZI\xca\xc2\x88a`D\xb1/\xe0\xec\x86\xa9L\x8b\x11,\x8b$\x0c\x8bxv\x05\x9c\xdd0\x85M\x11\xc3\xa4\x18\xc1\xa2\x80\xb3\x1b\xe0\xec\x068\xbb!\x94\x05\x91\x94\x011\x86\xfd\x00g7\xd8\x1e\xf3\xb2\x1c\"\x18\x0e!'\x13\xc40\x1b\xe0\xec\x068\xbb!\x84\xa5\x00g7p\x99\xc2D\x80\xb3\x1bL\x9a\xbcl\x83\xb1L\x03\xeb\xda\x00g7\x0c\x05\xcen\x18\xc1\x10\xf0\xb3\x03b\x99\x01\x11\xac\x80hF@\x1c\x1b\x00\xcen\x88C\xfc\xe1\xec\x86F\xe0\xec\x06)\xb1g7\xec\xe3\xb8\x06\xe3\xd5\xe5\xdd[\xea;E\xe9\xa1f\x12gVw\xb0\xebW\xbc\xeb\xf0\xdcA\x03J\xf3\x80\xd4\xb2\x17\xb9\xe1(3\x9b|\xdc@s\xdc\xa5\xfa\xfb\xbeG\xbf\x13\x9e0\x18Q\x94\xcff\xc7^h\xa0\xbd\x14\x1d\xa3b\xb7!U\x9e\xa9\xbf\xf11\x9f\xe1\x82\xd5G\xc4f\xe4\xb5\xe8\x02`n\xc2a\xfd{\xf3\xb9\xb65\xa1\xb45\xa1\x08 \xedx\xb6\xf4%\x89\xb4gW\xfd\x9e\x8d\xeb\xbf^\x7f\x9do\xf2P\xeb\xf2g\x15\x84k\xe3\x04\x88P\xa9\xde\x83\xeb\xe6\x8a\xfd\x8e\xb6\xad\x08\x8c\xe8\x7f:Y\xa05Y\xd42\x06\x97\xd7bRV\xae+\x8f\xf2\x8a\x01\">\xc2\xec<\xbb\x15\x97Y\xe0\xed\xf63ZQg6\xb4\xef\xbbl\xd9\xbb\xe1\x9f\xf7\xd0\x92O4\xfc\x00\x83\xbc\x98\xe7\x19\xaeI{\x80\x85\xb0 \x7fPv$]\x9d\xbc(\xa1kN,\xbe\xd2\x00n\xbd\x16\xe3\xf0\xad\x16\x07f\x0b\x88F\xea\xe9M.\x1fOh\xaf\xb5zU\xe0\xbe|E\xa8\xc4\xd9\xf9\xf0j\xc7#\x1br\x07r4\xe5\xcb\xa2\xaczQt5\x1a\xbb\x9f\x10\x96\x99\xda\xb0\xb3\xb2\\\x93\x0e\xad\xaa\x99|:\xbf$;s\xe7P\x1d\xd0q\xf8K\xef<\x94_\x0f\x05yK\xfbA\xfc\xc1uN\xcf\xff\xb2\x9d\xd3\xd3\x1e\xd3\x13p@\x8f~rQ\xa3\x0fk\x00\xae<\xc3G\xd2\xcb\x02\xce\xee\x91O\xfc^\x8e\xee\xb1\x91\x1bF\xd1\xd3j'G\xc1\x1b\x9e\x0f\x89o'g'\x84q\x13\xc60\x13\xdc\x0c\x84Q\xfc\x03\xfe \x8bB/\xfb \x01\xf7`$\xf3\xc0\x8a\xd7\x86\xf1\x0e&\xb1\x0eFq\x0e\x10\xb6&R\xd4a\x8c\x831|\x03\x17\n\x18\xc46H\xcc5\x08b\x1a$\xe4\x19xY\x06\x898\x06S\x18\x06\xd1\xfc\x82\x04\xec\x82\xc4\xdc\x02\x0f\xb3 9\xaf`?\xac\x82\xe4\x9c\x82pF\xc18>\x81\xc3\xe8>6A2.A\x18\x93\xc0\x10\xca\xb0\xcf\xaf\x89Y\x04>\x0e\xc1D\x06\x81\x83?\xe0uO\xbc\xdc\x810\xff%-o\xc0\xc7\x1a\xf0\x97i\x1cc\xc0\x91/\xe3\xe3\x0b$d\x0bL\xe0\n\x98\x19>.\xa6@Z\x9e\x80\x9b%\x90\x82#\x10\x04r{\xf8\x01\xc1\xec\x00\xe7\xad\xf6\x91\xcc\x00\xbb.c\xd0< ' \xc6X\xa1|\x00\xbfM\x82\xb9\x00#\x98\x00f\x80!\x11\x0b \x88\x03\xe0g\x00\x84\xe0\xffN+\xc6b\xff\xa1\xc8\xbf\x0d\xf7O\x80\xfaG`\xfe\xe3\x11\x7f\x07\xae\x1e\x8a\xf6'\xc6\xfa\x1d%2\xf6\xd4Q(\xbf\n\x8b\x1a\xf4Y0\xfe\xc4\x08\xbf\x1d\xdf\x1f\x8b\xee\xf3\x88\x80\xa9\xe0fl?-\xb2o\xdb\xf8yQ}\x1b\xechC\xf4\xd3\xe2\xf9\xe3\xd1|\x0br?\n\xb7\xf7b\xf4q\x08}0>\x1f\x89\xce\xc7`\xf3Vd~\xfa-\xf7a\xa8|$&\x1f\x81\xc8\x1b\xab\x96\x16\x8d\xb7\x0d\x8a H\xbc1Na\xc5\xe1\xc7\xa1\xf0.\xc4==\xde>\xbd'\x05c\xed\xa1H\xfbp\x89t% \xfb@\x87Z;x\xbd\x01\xdd\x91\x08'\x1a\xd4\xe9\xf0C\xefg~ywTF\xa3g\x13+\xab\xb5!\xd5\xe5Z\xdd\x0d^.\x10\xb9\xc9iM\x8a\xac\xff\x02\x7f\xc0z\x18\xbcT&\xf3\xf2q\xed\xbeu\xdcR\x8bQ0D\xd0q\xfb\xc1\xdb}\x7f\xaex=\xedp\xfd\xa0c\xf5\x13\x177\xfa\x10}\x7f\x1c!\xfe\xe0|\xfb\xdd\x0b\xb1G\xe6\xd7\xa3\x0e\xcb7\x1fM\xe0<&?\xea\x80\xfc\xeeA\xf8\x06m!G\xe3\x8f9\x14\x9fwB{\xe9}\xc7\xe1\x8f;\x08\x9f\x1fxo\xb3g\xe7\xef\xb6\xd9\xd3\x90$\x9f*G\xbe_M\xc8\x98\xe7\x02\x19\xf3\x901\xdf\nd\xccC\xc6|+c\x10l\xab2\xc8\x98\x1fJ\"4{\x1a\x9e=\x02\xd1N\x82i'G\xb5\xbd\xb8\xf6\x1e\x90\xed}a\xdb{@\xb7c\xf0\xed\xb1\x08\xb7s\x0e\xf7a\xdc Q\xeeP\x9c;\x12\xe9N\x8eu\xfb\xd1\xee\xc9x7d\xcc{K6\x0e\xff6\xaa\x82\x8c\xf91H\xb8\x0f\x0bO\x83\x86\x07B\xbc^D<\x02\x13\xf7f.G\xe2\xe2\x901\x0f\x19\xf3!\x88\xb9\xd7\xaa\xb1\xa8y8n\x0e\x19\xf3=I\x8c\xa2C\xc6\xbc.c1u\xa32\xc8\x98\x8f@\xd8\xa7`\xecFu\x901o|!\x08\x95\x87\x8c\xf9t\x18=d\xccOF\xf0\xd3\xf4\xb9`\x14?\x1c\xc7\xff=e\xcc\xf70lkYzd\x83\x06\x86\x1e\xbc6\xb9d\xde\xd4\xdf\x1e\x8e\x1d]\xe4\xc1k\xfb/\xf2\x1a\xd7\x84\xd6\x9e\x02\xf7\x13\xbe\xf5wPyE\xaa\xaa\xe2\x9bm\x0dW\x17K\x15\x9bnT2j\xcd\x91\x12\xf6fG\x19\xady\xd2o\xe7o]\xe4\xf2.\xe5\xf9\x96EA\xf8n\x9f\xe7\xfa\x8aq\xd2\xfe\xb1\x93\xed\xeb\xc8\xdc\xd5\x8ey8\xe2\xcf\x1f\xb5*:\xf6jU\xf3n0\xbc\xadA\xe5\xef6\xfa\xa8n\xb1n\x92n\xffK\xf2\xa1\xbb\x9c\xa7+\x8bz\xc1+\x9f\x14S\xb5D\xfc:\x15\xa5\xeb<\xe3\xc1(\x8e\x1a\xc54G\xdf\xff\xfa\x03\xf0\x94\x9ap\x96\xa5\x16\xc0SR\x9fJ[\\\xe0)\x01O\xe9s\xf3\x94,\x97y\xf4\x17\x94 T\xa5\xc1*\x08\xf4$.@O\x02zR+@O\x02zR+@O\xaa\x81\x9ed\x16\xa0')\x01z\x12\xd0\x93\x80\x9e\x14\xe8%\x01=\xa9\x11\xa0'\xe9\x02\xf4$\xa0'\x19\x04\xe8I\xc6g\x80\x9e\x04\xf4$\x8b\x00= \xe8I@O\x02z\x92&)\xa8\"@O\xe2\x02\xf4$\xa0'\x99\xe8I&\x9c\xbe\xc1\x9a4-\x13\xe966\x02\x89\x95?\xd2\xe2]v\xae\x88\x89\x1a\xa2\xf8\x08'\xaf\x8f\xb4\x8a\xf0\x1d\x1cF\xd9\n\xe7\x85\x99\x01\xf2{\xe4~\xdc\x11\xac*\x9fO\x08\xd1\xf4\xd9_\x8aD\xd2\xf6P\xf3\x8a\xd8\xf4\xf4d\xdf\x16#cx ON\xb5rY\xe2T\"\xaei\xb1\x8f\xbbU\x84X\xdbF\x88\xa7\x85\x84\xf8\xdaIHkX\xd7SA\xf6\x93\x0f\n \\\xa0\x85\xca\x14f\x02d_\x16\x04\xd7\xbb\xca]\xde\x10\xeb \xf1\xd8PHl\xb5\x1c!A!\xeb\x9cr:y{r\xfc\xc6\xfb&{\xcf\xfb\xd0\xf9\xd9?\xde\x9f\x1e\xbf\xf3>\xe7xHq^F\x15\x98\xdf\xc4C\xaa-\xae\xea\xdb\xb06\xd1^\x10~\xc4\xb8\xa5\"h.\x0f\x99\xc9\xbd\x0b \n\xeb\x0e(jNA}2\x88\\6K\x85\xaf\xf7\xad\xe4\xd45\xf4=9\x81\xcf5\xa9\xa0\x00\x0bw\xf8\xb1\x9f\xdd@\x9dqk2\x94\xbb\xb6\xc6\xaefAf\x94\x08\x1ad\x88\xa1\xb6\x15Y\xe47.\x0b\xf5F\xc1f\x93\xd7\x9c-\xd3\xf0k\x99\x82v\x92\xea\xb7\xbf#\xe0\x172\x12P\xe0h@\xe2J\xc0\x0b\x7f}Px\xab\xa30\x08\x11\x05\xad]L~\xe06;\x15&\xcbicC\\\xaf\xa4!\xc5\x12\xc6LyIn\x1dQy$\xa3bYY\xd0\xba\xdaqZ\xdf%\xb9E\x8b\xaa\xdc\xf0\xd7O1?\xafv\xaet\xf1\xcd\xbdS\xdd\x8c \xbc\xdd\x92b\xfe\x15{\xf7\xe0\xaf\xe4\x96\xfd\xef}w\x19\xfao\xf0J\xdc\xe7\x85?8\xf8\xda\x1c\xa2\x9e\x935\xbe\xbd\xd8\x92*/\xa7x\xef\x01\\\xe1^\xef\xe5\x1fF\xe2\xc3cf\xef\x90Y\xe0D\x8d\xfey\xbb\xa5l<0}o-\x07r\x13\"4j\xd3\\\n\xe3\xef\xda>^\xc4B\x06Ou\xca\xac|U\x91X\xd2\xdf\x1f\xf3\x01l\x1a\xb3\xed\x15w\x86\x0d\xa7\xe8\xf8\xda-x\x06^\xa9|t<\x19^\xdd\xe2i\xee.\xde\xce\xe2\x1d\xc462\xaf\x92\xe6\x16QI\xdfm.\x14E[L\xa5\xdf)\xae\x1d\xfd\xb4#\xb4>\x10\xbf[\x94\xf1$\x1d\xae\xc6~\xe3\xa8\xe1U~m\xe0D\x03\xf8y\xf5\xd6\x19\xac\xb9\xb5\xd0v\x8d\xa5\xc6\xa6\xb1qCu\x13\xe9\x17@Z\x1e\xbf\xc6\xfc2\xc3\xfb(\xaf\xa9\xe2mQ\xb4+\xc4p\x9a\x0b*\xcbun\xe8j\xfe\x91\xaa_\x12+j\xd5\x89|\xe6\x05Z\x9e\x9d\x1e\xb5\xbc\xda\xf1\xc8\x86\xdc\x81\x1cM\xf9\xb2\xe0\x87Q\xeb\xca\xd4h\xec~BXfj\xc3\xee\xefd\xea\x96\"p\xf8K\x87'\xee:\x96Z#s6\x99\x86E/\xc9P\xcf\xcb\xb0$\x17\xdeS\x95\xbf\xf3\xb9\x85V\"\x97V_\xd3\xe5\xf5\x8a\xe1\xe6\xc8d\xb2\x96\x0by\x11~O\xd2\x837\xb6\x9d(\xe3\xcf\x9d\xefW{\xf2\xd5\x9cyjN\xe3\x08\xf1\x91 Pp\x96\x9f\xd7^\xf2\xb1\xb1\x19~!\xf9}>k \xc8\xed\x8b\xab\x8c\x87\xa9\x9f0\xab\xcfk\xa7\x10\xc4\x02\xc5\xe6\xf3\xb5Y{V}uD6_\x1d\x95\xcb\x17V\xa3\xc4\xd9|\xa1\xb9|Q\x99|\xa6\xfa9\x12\xf9\xd2\xa4\xf1y{\xb2+\x85ol\x02_@\xfa^X\xf2\x9e7uoB\xe2\x9e?mo/I{\xdeI\xd9?%\x07\xa4\xeby\x9b\x1d\x05\x0f-\x944QoD\x9a\x9e\xcf\xa2\xc1)z{6\xca\x94\xe4\xbc\x11\xa9y\xa1\x89y\xbe4\xb6\xbd%\xe5y{:\n\xea\xed(\"\x1d/\xa8\x85Q\x18-!lyO\x99\x86\x17\x9f\x84\x87f.\xcaNl\n^|\x02\x9e?\xfd\xce\xdb\"\x01\x99\x07aC\xb2\x93\x91'Xx;Z\xf3\xa4*4\xe3\xe4*\x913\xd7\xb9\x13*\xc3\xb6\xc9J\x85\x89\x16\xcd\xd2\xfe\x8097\x0b\xc98\xb3\xd9\xf1\xdd\xfb\xf3\xe3^v\xe0\xba\\\xe6Y\xb3Cnx8\x02>\xa3\xe5\xc6\xd6\x84b\x965\xf0r\xfc\xf6hw\x89\xc7\xc5\\K\x19\xe4\x95f\xfb>1*\xd9$%O\xb2Q\x13\x89\xd1\x01\xadK\x84\x0b\xceZ2U\x9b\x92-\xae\xb8[R\xf4\x03:B\x84M\xd8\xebD\xb4 7\xc4\x8c\xa0\xc7H\xa5_u\n\xcc\x83H\x84\xd6x\xb6\xce\xa9\x91~\xd5I~\x9c\x91\xfa\x9a\x90\x02\xd5\xd7\xa5\xa8\xcb\xc0d\x7f\x80{\x81*RW91\xb1\xfe&l\x81!\xd5\xc9[\\Hu\x82T\xa7\xdfG\xaaS\x8aL'G\xa2\x13zMhs\xfb`\xd7\xd7\xbd\xcfY\xb6\"\x02\xcdV\x191k\x99Y\x19\xea\xde\xc2\xaa\x1c\x90\x03\x9d\xd3\x1e$ZA\xa2\x15$Z \x81D+H\xb4j\x05\x12\xadjH\xb42\x0b$Z)\x81D+H\xb4\x82D\xab@/ \x12\xad\x1a\x81D+] \xd1\n\x12\xad\x0c\x02\x89V\xc6g \xd1\n\x12\xad,\x02\x89V\x90h\x05\x89V\x90h\xa5I\x8a\xa4\x17H\xb4\xe2\x02\x89V\x7f\x86D\xab\x0e\xe9K\xd3\xd4\xe335@\x95\xa4\x1c\x1b)\xb4{\xba\x91hL\xe2\xc0\xa1d\xf7qH\xd4\x91E\xa0e\x90\xb5\xf8\xdd\x11\x7f\xf7\x03\xa7\xb6\xa8\xdc\x02\x0db\x17\x9c\x17\x03\xd5\xbeQ5\xa4\x93Y\xb2\x0f\xb4/\xc9\x07\xefl\"B\xd3\xe2\xf3\x0b\xdd\xb6V\"\x86\xcfX\x8a\xf5;|\x7f<\x13cj2B\xb7\xe8N\x9a\xb8\xdb\x06\xc8W\x0f\xe4\xad\x0b\n\xc0\xf4\x02\xaa\x84\x02\xe3BBF!{\x0e}\x83\xe0\x8ec\xaf\x93\x16\xdd\xf3\xe2{\xa9\x11\xbep\x8c/\x11\xca7\x0e\xe7s\xa8\xcb\x8b\x08\xa4o2\xd6\x97\x1a\xed\x8b\xc4\xfb\x12#~q\x98_$\xea\xe7\xea\xc3\x0d\x1e\x18\x8a\xfb%F\xfe\x82\xb0\xbf\x84\xe8\xdfT\xfco\x14\x02\x98\x08\x03\x1c\x83\x02:\x94q|\xd0\x8f\x03\xee\x05 \xdc\x1f\x16\xb8\x1740\x0e\x0fL\x8e\x08\x86b\x82IQ\xc1p\\0\x1a\x19\x8c\xc7\x06\xbdS\xe1\xd7\x01\xe8`\x02|\xd0\x83\x10\x06:T\x01(a\x8c\xd7\x15\x8d\x14\xba\x16\xc1YyE\x02\xb0\xc2\xd0\xf2%\xc4\x0bc\x10\xc3\xc4\x98\xe18\xd4\xd0\xd5\x83\xa8\x1f7\x1c\x8d\x1cZ\xb4\xb1\xaf\xf9\xb0\xc3T\xe8a0\x04\x16\x80 Fa\x88\x9e\x90\xff(\x1c\xd1\xa7\xd3\x1aOL\x84&\xc6\x1b3\x1cQ\xf4\xd5m\x04\xaa8\x12Wt\xc5e\x93a\x8b\xc1\xe8b\x18\xbe\x18\x8a0\x06X9\x1ee\x8c\xc1\x19]Hc\"\xac1\x12m\x9c\x867\xfa\x0c\x1a\x819\xee\x01u\xf4\x96\xce\xda\xd3\xd3a\x8f\x01\xe8\xe3x\xfc\xd1\xa2\x8e=\xe6B \x13c\x90>\x14r$\x0ei\xd1%v\x86\xae\xcdq\x00\x16\xe9\x02L\\xdzD29&iG%S\xe2\x92!\xc8d<6\x19\x85N\x8e\xc0'c\x11J'F\xe9F\x8c\xc21\xa3P\x9cr\x04R\x19\x89U:\xaa;\x06\xaf\xb4\xa8\xd2\xb0\xc0\xb0!\x11\x86Y:\xba|\xb1t\xa3\x96IqK\x0fr\xb9\x1f\xec2U_\x8c\xc0/c\x10\xcc\xe1\xa5\x86B\x0c\x18\xd3\xe09\xff\xfeV\xbb\x19VC\xfc\xb4\xabau\x08K\xecVM1\x1emr\x14o\x98\xcc\xed\xbb\x17\x16\x92\xab!\xb9\xba\x91\xb8\xe2Br5$W\x7f\xb6\xe4j\xdb=\xcd\xbd\xb4jm\x82M\x91a\xad\xcf\xd7g\xa7Gr[\xd2\xbc\x04\xc9\xcd\xdd\xdf \xb99d\xd2\x132\x8a\x02\x01\xc9\xcd!\xc4\x07S\xac \x9a\xf60\x86\xf4\x00\xc9\xcd \xa9\x0e1D\x87(\x9a\x03$7O%7\x8c\xa06$!6\xc4\xd3\x1a \xb9y\n\x9d!\x86\xcc\x90\x98\xcaP\x07\x11\x19\x12\xd2\x18BI\x0c\x86\xf8\x04$7w%\x80\xb6\x10\xea%ES\x16 \xb99\x88\xa80\x86\xa6\x00\xc9\xcd\xb6\xc7\xbc\xd4\x84\x08bBH\xean\x0c)\x01\x92\x9b!\xb99\x84z\x00\xc9\xcd\\\xa6\x90\x0d \xb9\xd9\xa4\xc9K/\x18K.\xb0\xae\x0d\x90\xdc<\x14Hn\x1eA\"\xf0S\x08b \x04\x11\xf4\x81h\xf2@\x1cu\x00\x92\x9b\xe3\xc8\x02\x90\xdc\xdc\xc8>\x08\x02)\xfa\\\x049 \x9c\x1a\xb0\x8f\xe4\xe6\xbb\x9f\xd5\xac@P\x91xz\xa8 \xde\xc3_z8\xf9\xaf\x87\x02\x1f\xd4~\x10\x7fp]\xa9fN\x86V\x9f4\xe4C\xf7\xae\x01H\x93\x12\xdd\xf9\x9e|\xf6\xcefE\xf7\x1a\xc4\x86\x96\x8d\xa2>\xd4N\xd0\xcb\x1b\xef \x98$\x87\xbb\xc2\xc0\xae1P\x97\x1b\xd2\x1a\x05h\xf1OX\x14z\xe1\xac\x04`\xd6H(\xcbN\x90\x0b\x02\xb2&\xc1X\xa3@,\x84\xad\xa4\xdc:\x0c\xc2\x1a\x03`\xb9\xc2\xcaA\xf0Ub\xf0*\x08\xbaJ\x08\\ya\xabD\xa0\xd5\x14\xc8*\x1a\xb0J\x00W%\x06\xab\x00*!\xfc4\x01|2C\xc6.\xe8)-\xf0\xe4\x86\x9dR\x80NA\xa8\x89\x07p\n\x86\x9b\xec\x91\xe1x\xa8\xc9\xae\xcb\x18\x85I\x022\xc5\x18+\x14`\xf2\xdb$\x18\\\x1a\x01-\x99#V\x89`\xa5 P\xc9\x0f)\x85\x00JN+\xc6\x82I\xa1P\x92\x0dHJ\x00#E\x80H\xe3!$\x07P\x13\n\x1f%\x06\x8f\x1c%2\xf6\xd4Q\xb0\x91\x82\x88\x0c\xfa,\xa0Qb\xc8\xc8\x0e\x18\x8d\x85\x8bxD\xc0Tp3X\x94\x16*\xb2m\xfc\xbc0\x91-\x8em\x83\x88\xd2\x02D\xe3\xe1!\x0b\x144\n\x08\xf2\x82>q\x90O0\xe0\x13 \xf7\xc4\x80=V\xa8\xc7^\x9a\xd0\x90{\x18\xcc\x13 \xf2D@<\xc6\xaa\xa5\x85wl\x83b\x02\xb4c\x8cSX\x81\x9dq\xb0\x8e\x0b\xc2I\x0f\xe0L\xefI\xc1\xe0M(t3\\\"U6\xa7\x1fN\xb0\x1c\x1a\xea8\xf7\xd3\xb9\x0f\xed\xa6\x91\x9e\xbc1\x7f\xb2[\xac\x9e\x12\xc8\xdb\x84\xbc\xcdF\xe2\x8a\x0by\x9b\x90\xb7y\xe7\xf36;hl\x92\xd4\xcd.\x9e\x0c\xd9\x9b\\ {\x13\xb27[\x81\xecM\xc8\xdele\x0c\xf8mU\x06\xd9\x9bCI\x04\x84O\x83\xc2G\x80\xe1I\xe0\xf0\xe4\x80\xb8\x17\x12\xdf\x03(\xbe/X|\x0f\xc0x\x0c4>\x16\x1cw\xce\xe1>x\x19*\x87\xecMo\xc9\xc6A\xe7FU\x90\xbd9\x06D\xf7\xc1\xe8i\x80\xf4@t\xd8\x0b\xa6G\xc0\xe9\xde,\xbaHH\x1d\xb27!{3\x04l\xf7Z5\x16p\x0f\x87\xdc!{\xb3'\x89\x01x\xc8\xde\xd4e,\x1coT\x06\xd9\x9b\x11\xe0\xfc\x14x\xde\xa8\x0e\xb27\x8d/\x04\x01\xfa\x90\xbd\x99\x0e\xde\x87\xec\xcd\xc9\xe0\x7f\x9a>\x17L\x00\x08\xa7\x00\xfc~\xb27\xdb\xd2\xf4\x00\xed\x94\x9f\xb0\x02\xc7\x83o\x0f\xc0\xda}}\xdb\x96\xb5\xca\x93V\xb1\x16.<\xac+\\\xd0\x05\xa9\x0e\xaf\x1e\x1d\xceIQn.\xea\ng\n\n2\xa5\x99\xbeaO\x9d\xf3\x87\x9atR\xbc^#\xfev^\x88\xe1+\x94\x18sE\xb5\xf7\xef\xa9*\xdf\xd1\xf4\xd0\xa1At\xa9?\x03\x16\xc7:\xcb\x84 TH\x1c\x07\xc9\xcf4'\xa9\xd7\x82\xb8\x93s\xe7d[V\xf5\xa1\xa4\xf1hC\x96\xf2\x00\x9bU\x1f\x8f6V8cK\xb1\x1b\xb3\x10\xc0\x9f\xf4\x82\x16\xbbb\x99\xcf\xd6\x04\xd5\xe5%)\xcc\xee\xc8\x0cSr\xc1\x1b*\x95]\x98\xc6no\x96\xc5\xa9\xc8\x1a\xdf\x92y@\xb1B\xec\xdc\x8e\x83\xae\xf75\xfc<\xb3\xde\xc9\xd1\x87\xc7\x0f\x9b/\x1b\x15\xf2\xd2\xd0f\x13`|F\xdaW\xb5E^\x88\xe9\x83}\x85\xb5\xb9'eF\x1f\x0f\xa8\"\xf5\xae*\x86c\x9f\x8a\xc1\xaf\xeb\xee\xab\xdd\xe2\xa5|x\xd8f\x9d\x0f\xb6\x0fvz\xa3\xf6g\xb9\x9f0M\x02B\x9c\x03\xce=\xdc\nrS_\\\x92\xdb\x89t\"k\xc4\xd7F\xe2P\xa2\xbe\xaf\xf8\x1a\xec\x9f\x12\xfa\xc0\x94\n|\xe7\x14/\xc9\x19\xf9\xb4#\xb4>\x10\xbf[\x94\xb1\xa9Z\x10\x8b\x98ZfB\x826%\xad\x11\xe1\x80\x02G!L\xf3UY\xe3\xb1)\xec\xe1|*\xebT\xc4?\xcf\xeb\xcf\xff!\x16o6\x1e\x15\x94\xa5\xe1&6\x16\x80n\xa2\xac\xdc\x15\xf5\x05Wf\x9b\x84\xae1E\x94\xd4\xf7Q^S\x85\xd0Q\xb4+D\x07\x9c\x0b\xd0\xe2:\xa7\xdd6u\x8f\xf8\x1e-\x87\x8eg\xe2\xe8\xab\xef\xd9\xe9Q\xbf\x12b'\xdf\x8e\x02 \xe3t\x7f\x032\xce\x1ep,\xd7.\xa0\x9d\xaa\xd9\xf4d\xeb\x86\xbd)P\xceyX\x0e?\xb1\xd2phY\x0ef9\xd97\x13$\x9f\x15\x97=\xe4\x94\xcfx\xd2\xe3pLz\x07\xe8}\xc1y\xa5\xdc\xed(\x17\x0bJjTV\xa8[\\\xa4\x11Z(\xa9\xf5u\x869\xf1\x9f\xa4\x83\xad\xa4\xf5\xe2\x17xM#\xdc\xf8\xceba0\xa2(\x9f\xcd\x8e\xbd\x89GV\x86\x9b\xb2\xd8mH\x95g\xeao|\xcf\x9d\xe1\x82\xd5G`\xa3+R(\xc3\xef\x8afZ\xed\x05\xa1O\xb8\xb65\xa1\xb45\xa1\x00pw\x9c\xdbxI\"\xed\xd9U\xbfg\xe3Z\xf6g\x9ay\xd7\xf9&\x0f\xb5.\x7fV\xcd\xe0\xb6\xf5I\xac\xd7z\x0f\x96\xf3}?1k+\x80I\xfdO'\x0b\xb4&\x8bZb\xe0y-\x82\"*t\xccY\x16b\x80\x88\x8f0;\xcfn\x05-\x18o\xb7\x9f\xd1\x8a\xfa*\xdb\xbe\xef\xb2\xa5\xf6\x06\xb3(\xef\xa1%\xdf\x013\x1f\x00\xe5\xc5\x9c\xedXIK\x0d\x17\x16\xe4\x0f\xca\x8e\xa4\xab\xcb\x8bl\xbd\x9b\xf7|`,\xbe\xd2\x10\xdez-\xc6gl\xcd\x9f`\xabp\xc7\xd1\xec(\xfbxB{\xad\xd5\xab\x02\x8f\xa5\xb3\xa5T,\xad|x\xb5\xe3\x91\x0d\xb9\x039\x9a\xf2eQV\xbd\xcd\x93\x1a\x8d\xddO\x08\xcbLm\xd8YY\xaeI\xe7*\xacf\xf2\xe9\xfc\xe2>\xfa*(\x8ap\xf8\xcb\n\xd3\x95\xeb\xd0*m\x17\xd4\x04\x13\x0c\xa1\x04\xd3n\xc2\x12U\xb8\xa7\xacp\xf7\x83\n6\x97b\xd4n\xc5\x1e\x1a\xf0\xae\xea!\xdb\xd5\xd4A\x81\xc0\x90@l@\xc0\x17\x0e\x88\xb3\xc5\xe4P\x80\xdf\xb2\x89\xc3\x00\xfe @T\x08 `[\xd3V \xc5\xae\x0665\xb0\xa91\xfe~\x9765lQ\xb3u>\xf6\x1b\xfa*/\xd0\x8a\xdcH\xbd_\xb7\xa8n\xc8\xba\x86\xa6\x03\x03\xe3\xe2\xff\xbc\xca\x8e\xc8\xff)\xff\xbd\x13\xf4o\xad\xa4\xea\x98\xcf\xb2\x07J)\xda\x94\xf3\xdd\x9a\x18\x17\xec\x93\xd7G\xe7\xf21\xa1\xf7\x9e\xaa\xe6\x1d]\xb7u\xeb\xe8\xd2\x0bXr\x13u\x83\x95}\x13u\xad\xd2\xca\x84\xc5\x9f\x92b~A\n\xe6\xb8\x1a\xb2h\x91\xc3\xf7k\xc5\xec\x05v\xc5\xbf\x9e\xa1^i\x90\xf8_\xcek\x9c\xe7T\xfc\x9bu\x9d\xac*)} |\x08\xbej\xd9\x86\xaf\xec%\x14-\xaar\xc3\xc9\xd46g\x81+3y\x05\x15\xc9H~E\xee\x8e\x85z\x05Jh$\x8e_G\x99(`\x8d\x17#4h}\x97+\xba\x9c+\xd8j\xde\xd5\x07\x8b9,\xe6\xbf\xf9bn]\x0f\xd7\xb3\xcd\xe15\xa6\x1bqr\xb3jI\xd3\xe2wT\xce \xe5 \xbab\x0e'5\x9e\xe3\x1a\xf3n\xcfF*\xad\xd9&\x1e1e\xbcO\xa8\xf5\xacwN\xf2\xfc\xee\xa3\xde\xac\xf4\x17\xcc/\xb9#\x1dJ\x94\xc72iG\xf5\x08\x07\x10\x95U\x04\xd7\xa6\xa1/\xc4\xfb\x11\xd6\x17.\x98\xef7ZC\x00`\x98\x17\xb4\xc6E\x9d\xe3\x9a\\lI\xb5\xc9)5b\xa8B\xbe\xfbpz|t\xf2\xf6\xe4\xf8M\xc4[\xef\xde\xbf~\xff\xe6\x1f\x11/\xbc\x7f\xf7\xb7\x7f\\\xbcz\xf3\xe6\xec\xf8\xc3\x87\x88\xd7\x8e\x7f<>\xfb\x87\xe7Sj}\x1bQ\xad0WB\x88\xd5l/\xd1+>i\x9c\xdfn\xc9\xc7\xa2I\xf5q*\xdb\xaeqFV\xe5zN*\xc1\xcf\xe5\x01h>/;\xdf36\x83^\x80w\xe5\xac\x9c\xf3<\xc7Y>\x9f[\xbd\x19\xa36\xbd\x8dt\x9d\xef\x8b\xf5\xed\xab\xf9\xbc\"\x94\xb2Y\xb1\xaer\xee)\xd4%OA\x12?\xc4|\xa7iT\xfd#\xc7W\xa4\xba\xe5e\xdf\x15\xedG\\\xe3A\x00\xdb\xad\x06m\x1c\xf1\xc1b/\x93,\xf3\xc4\xd1\xd6]:x1\x8e\xcab\x91/y\xc24\xa5<\xdaT\x95\"\x91\xd9\xe43\xcb\x1a\xb0%\xeb\xa4X\x94\x8d\xf3\xd7D\xa9\xd8\xbc\xcc\xd7A$\x16B\xe6\x9d\xab\xa7{\xfa\x80\xf0\xc1\x05\x08\x1f\x7f\x1c\xc2\x87\xad\"\x92\xea1'Q\xdb%\xe1]\xdavK\xcd\x1fa\xb3\xd4\xfd\x0d6K\xe1^\x02\x9c\xad\x02g\xab\x98\x05\xceV\xe1\x02g\xab\x0c\x05\xceV\x81\xb3Ul\x02g\xab\xc0\xd9*\\\xe0l\x15{\x9f\x86\xb3U\x84\xc0\xd9*p\xb6\n\x9c\xad\xc2\x05\xceV\xe1\x02g\xabp\x81\xb3U\x84\xc0\xd9*p\xb6\n\x9c\xad\x02g\xab\xf4%\xf4\x9c\x0b8[\x85\x0b\x9c\xad\xf2g8[\x05\xb2*\xe3R\xd6 \xabr\x8f\xc6\xf5\xe7\x03BVe\n+BV\xe5\x1f;\xab\xb2\xcfE=\xfcE2\x1f]\xf9\x93G\xe5\x9c\xb4\xac\xd4&\xae?'\xdc\x91\xe8\xb2T\x11\x9bLHKQ\x95\xba\x06\x0c\xd5{\xaa\xc6w\x9d\xa0j\xc3\xf0G\x91\x7f\x9c4So\x10\xdaK}q\x12L=\xea=\xe4\xd2\xe0\xc2Y\xe2\xe31\xb4R\xa7\x81\x91\xd7\xc8(\x90P\xea\xad\x12\n \x93\x8e\xa1\x92F\x12IG\xd1HcI\xa4\xa3)\xa4!\xd0\x82\x90\x84\xf4\xd1\x91\xe4\xd1\x94\xd4\xd1\xdf\x868\x9a\x9e6:\x9a4\xea\xa5\x8cz\xc7\xd3D\xbahJ\xb2({ \x8a\xd1\xe5\x98\xe0\xbc,\xbdX\x92\x1ep\xf4\x80\xa3g\xf8\x1d8z\x9a\x00G\x0f8z\xad\x00G\xaf\x06\x8e\x9eY\x80\xa3\xa7\x048z\xc0\xd1\x03\x8e^\xa0\x97\x04\x1c\xbdF\x80\xa3\xa7\x0bp\xf4\x80\xa3g\x10\xe0\xe8\x19\x9f\x01\x8e\x1ep\xf4,\x02\x1c=\xe0\xe8\x01G\x0f8z\x9a\xa4\xe0K\x01G\x8f\x0bp\xf4\xfe\x0c\x1c=\xc9'\xd0tL<\xd4\x13\xd9h\x06c(%\x87\x1c\xcf\xc3YM\x9d\xe4\x12\xf9\xcck\x8e\x95\xa1uNkq.!\xdd\xe0J`\x01\xfcw\xc9/\xe1 _S\xe5\x1e\xaf\xa4\xa3\xea\x9e\xaa\xfe\x9d\xa5\x98\xc8\xe2&\x85\xa0,\x01\x12 R\xb6\xd6\xe41L\x1en.\x17\xcd\x9f\x15\xc8;\xd8l\xc3\xe1:\\\xe0p\x9d?\xdc\xe1:\x83\xb6T\xf7(\xe9SI\x10\x82o\xd2s\xd8\x9f\xde\xceN\x8f\x00\xcc\x070\xdf\x17\xc9\x0e \x06#\x00\xf3\x01\xcc\xb7> `>\x17\x00\xf3\x87\x02`>\x80\xf96\x010\x1f\xc0|.\x00\xe6\x03\x98\x0f`>\x80\xf9B\x00\xcc\x070\x1f\xc0|\x00\xf3m\x02`>\x80\xf9\x00\xe6\x03\x98\xafI\n`\x15\xc0|.\x00\xe6\x03\x98/% \x98\x0f\x87\xfc\x8c=A\x05\x0e\xf9\xd9\xa3q\xfd}\x14\x0e\xf9IaE8\xe4\xe7\xcft\xc8\x8f\xe0\x1f\x1c\xfe\"\xa9=\xee\x83~\xc4\xc3'\xc5\xa2l\x0f\xfci\xc8A\xcd\xd1\n\xf2=#\xf9J;l\xe1\xce2\xaf\xacGY8\xc3\xd2\x920\"_V3\x8b\xfaO\xd9m\x95\xb1zo\xab?\xff\xee\x8e\x14\xea\x1e\xbb\xf1\xa6%\xc0,HE\x8a\x8cH\xf7O]M\xfa\xf7\xde\xb9O\xbaL9\x9d\xa8-\x86P\xd2\x98\xfdz\xc5\xa6\x9f\xbc\xce94\xad\x9d24w5\x07\xe2\x9d`\x93;\x0f \xf2\x17\xe6\x15S\xc1\xd7\xef\x16\x0enJ\xd6,\xe1\xe4\x86d\xbb\x9a\xa0M\xbe\x14\xc3\xc5\x14\xfc^\xe3\x19\x19\xcb\xda\n\x01\x1b\x10\xfa\x1b\xfb\x02\x9f\xfaTI\x9b\x93\xbb\xe4\x02%o\x97\xe5\xe8\x81\xcbr\xa89\xcf)3\x82\x1f\xbc\xa1\xad7`{\xf8cG\xe2et~\x83\xb6%\x15[\x0c>\xddv\xa6\xa2k\xce\xbbh\x1b\xdb\x1a\x03\xe5t\x14^I\xe9 ^\x92m\xcdiI\x15o\xacb\xce!>\xb6q\xba\xd9\x96\xcc\xd3\xba\xcam\x90\xb5 \xe4I\xd7\xe1\x00\xfd\xfb\xceNZ\xd9Q\xb1B\xd1\xb2\xaa\xad\x9d\xc8\xcd2\xf2\x0d|&\xb3u\x99]^\xacH\xbe\\\xd5\xf6(\xaa\xb7\x03\xa1\xb0\x99\x00\xb5\xcd\xf7\x9a}\xf8{\xfe]5%\xf0\xb2\x0c[Iv\x06;\xfd\xa7\xbe\xb9\xc8\x8b9\xb9\xf9M\xcb\xef<\xa8\xea\xfc\xe6\x84\x15H8\xe6\x9b\xb2(\xeb\xb2\xc83\xe1A\x90\x8a\x0f\x10\xe9(\xf2:;4}\x85\xb3z\x87\xd7\xe2\xeat\x9cIOeNn\xee;\"\xcd\xcc\x1b_b~\x1a\x12'`\x98c\xc5a\x83\xfe\xd5\x8c\x96\xeb]M\xceoN\xd5`\xe2\xb5\x12\xf4\xb0N\xb9\x9a\xd1\xc6&.\x8b:\xce\x93\x10L\xec\xe5\xba\x9c\xd9A\xf5\xb2\x9a\x13\x1eGb\xcbb\xfb\x11#T\x9c\xcf\xb2\x8bmY\xd5cW1Z\xe3zg\xa3\xe2\x89\xe6\xfe\xc0\x1f\x11U\x17\x8f\xf3\xf0\xa3{\x92\xf3v;\xd7\xd9p\x0f\xd0\xd1\xfbw\xe7g\xaf\x8e\xce/>\x9c\xbf:\xff\xf8!\xe00\xb5\xe1;\xaf\x8e\xceO~<\x0e~\xfc\xe4\x9d\xe3\x85\xe6\x84\xb7\xd8\x82\xb9B\x01\xad8+\xdc\xba\x87\xb2%v\xfec\xdel\xd6\x18\xe8b]\xcb\x0e\xd6\xdb\xad4P\x94\x17VU\xe4\xa6&\xc5^O,\xac=\xa4\xd1\x80\xfe\x88\x82\xa7\x054\x96:\xea\x9a\xb5\xfa\xec\x01\xd7\x14\x97\x94>\xea%\x90\xa6\xa6\x90\x86\x93H\x13\xd1H\xc7\x11I\x1d\xea\x98A\x83\xa9\xa4\x93\xc9\xa4\xa9\xe9\xa4\x91\x84\xd2\xc4\x94\xd28Ri$\xad\xd4\xd5\x87\x1b\xc2i(\xb141\xb54\x88\\\x9a\x90^:\x95`:\x8ab\x9a\x88d:\x86f\xeaP\xc6 \xa8~\xa2\xe9^\xa8\xa6\xfb#\x9b\xee\x85n\x1aG8MN9\x0d%\x9d&\xa5\x9d\x86\x13O\xa3\xa9\xa7\xf1\xe4S\xefT\xf8u\x00\xfd4\x01\x01\xd5CA\x0dt\xa8\x02h\xa81^W4\x15\xd5\xb5\x08\xce\xca+\x12@F\x0d-_BBj\x0c%51)u\x1c-\xd5\xd5\x83\xa8\x9f\x98:\x9a\x9aj\xd1\xc6\xbe\xe6#\xa7\xa6\xa2\xa7\x06s,\x03(\xaaQ$U\x0f\xa7l\x14Q\xd5\xa7\xd3JXIDW\x8d7f8e\xd5W\xb7\x11\xb4\xd5\x91\xc4U\x17\xf1'\x19y5\x98\xbe\x1aF`\x0d\xa5\xb0\x06X9\x9e\xc6\x1aCduQY\x13\x91Y#\xe9\xac\xd3\x08\xad>\x83F\x90Z\xf7@k\xf5\x96\xce\xda\xd3\xd3\x91[\x03\xe8\xad\xe3 \xae\x16u\xec1\x17\xc551\xc9\xd5Gs\x1dIt\xb5\xe8\x12;C\xd7\xe68\x80\xec\xeab\xe4\xb9\x08\xaf\xe9)\xaf\xc9I\xafv\xdakJ\xe2k\x08\xf55\x9e\xfc\x1aE\x7f\x1dA\x80\x8d\xa5\xc0:I\xb0nJb8)1\x94\x08;\x82\n\x1bI\x86uTw\x0c!\xd6\xa2J#\x9b\x86\x0d\x890R\xac\xa3\xcb\x17K7-6)1\xd6C\x8d\xdd\x0f96U_\x8c \xc8\xc6Pd[\x92l+\x0d\xf7D\xe3%q\x9a\x02E\x18\xfd\xfd\xd5\x87\x1fZ\xacY\x11\x12\xee\x19\xde\xb7]\xcd\xd2j\x9d~\xc0\x0b/\x1b\x9c\xee\xc2\x05Nw\x81\xd3]Z\x81\xd3]\xe0t\x97V\x92Bq1@\\\x14\x0c\x07\xa7\xbbL\x05\xdfF@oI\x80\xb7x\xd8\x0dNw\x99\x02\xb7\xc5\x80m\x89\xa1\xb60\xa0-!\xcc\x16\n\xb2\x19\xfcg8\xdd\xa5+\x01\xb0Z\xa8\x97\x14\x0d\xa9\xc1\xe9.A@\xda\x18\x18\x0dNw\xb1=\xe6\x85\xce\"\x80\xb3\x90\xb3Kb@38\xdd\x05Nw \x81\xc6\xe0t\x17.S\xc008\xdd\xc5\xa4\xc9\x0b\x7f\x8d\x05\xbf\xack\x03\x9c\xee2\x148\xdde\x04\xc8\xe5\x87\xb8b\x01\xae\x08x+\x1a\xdc\x8a\x83\xb6\xe0t\x9780\x0bNwid\x1f\x00V\x8a>\x17\x01^\x85CW!\xa7\xbb\xc8\xb4`MGg\x17\x19\x96U\xce\x9a\xa3\x7f\x9e\xc0\xc4Cb\xc6\x1e#p\xb8\xcai]V\xb7\x01\xc7 |/\x9e4\x9c(\xc0/s\x91\x8a\xe4\xdb\xc6C\x05\xbe\xef8\x12\xae-\x8f_\xf2\x89\xd5\xfa\\h%Xgx\xe9-\xe5I\x91\xd72\xee\x9d\x17}\xba@\x9d\xf3\xe7&\x17E\xf6)\x7fi~\xe0g@\x101\xf15\x07BL\xfe\xbe\xec\x8c\xfe\xef\xff\x85\x14\x84\xe6\xb4\xcd'Z\xca?h\xc7\xba\xf4\xc5\x9f2\xef\xfb*\x92\xd9\xdf\xeaL\x0c\x1e}\xb6CG\xdc8\x02N0>\xe3<\xf2$h^\x0b:, \xee\xe0\x13AF1\x1e|\x82\xd0n;\xb7\x9f\x88\xd1\x1b\xdd\x1f\xc5\xb3\xe6\x030\x9aI\x9d\x9f\xad O\x16\x99\xdb\xb6\xee\x9e\x15\x04\x05\xac\"(\xf8\x94\x89 \xc3\xa3P\xe3#\xb4\x8f\xb3&BN\x9b\xd8[=\x9cyA)O\x9d\x18{\xeeD\xe0\xc9\x13\x1b\xbaL0\xf4,\xc0Og(\x18\xe6\x95\xe3\xa2\xaen;'\xd7\xb4\xa78\xf4\x87\x01\\Z\xc7\x05.\xad\xf3\x8e\xc0\xdf\xdb\xa5unB\xa3\x1c*\xd39\x8dj\xe3\x06\xb4F.@k\x04Zc+@k\x04Zc+@k\xac\x81\xd6h\x16\xa05*\x01Z#\xd0\x1a\x81\xd6\x18\xe8%\x01\xad\xb1\x11\xa05\xea\x02\xb4F\xa05\x1a\x04h\x8d\xc6g\x80\xd6\x08\xb4F\x8b\x00\xad\x11h\x8d@k\x04Z\xa3&)(f@k\xe4\x02\xb4F\xa05~>Z#\\q7\xf6\xfe0\xb8\xe2n\x8f\xc6\xf5_\xce\x06W\xdc\xa5\xb0\"\\q\xf7g\xbe\xe2\xee\xb0\xc2\xd7\x87\xbf\xf0R]\xccq\x8d]w\xde\x9d\xe1k\xfd\x1a\x10\"X\xeal*Y\x0b*\xcc\xa2*7\xa2\xc1\xf1\xb5`\xfb\x89\xfb\xa4L\x17\xc8t\xc8\xeb}\xcd\xf7\x94q\xee({\x9d\xd5*\x8a\xbf\xe0 wK\xae\xca\x1bf\xac\xce\xce\xa3k\xc8{\x86w\x06\\%\xde\xf2}\x83\x8e'\xb8\x0c\x1a\x1d\x18.\\\x80\xe1\x02\x0c\x97V\x80\xe1\x02\x0c\x97V\x80\xe1R\x03\xc3\xc5,\xc0pQ\x02\x0c\x17`\xb8\x00\xc3%\xd0K\x02\x86K#\xc0p\xd1\x05\x18.\xc0p1\x080\\\x8c\xcf\x00\xc3\x05\x18.\x16\x01\x86\x0b0\\\x80\xe1\x02\x0c\x17MR\xb0\x0d\x80\xe1\xc2\x05\x18.\xc0p d\xb8ho'#\xb6\xb4\xf8fJ\xed\xc6\x1d\xfeh \x96npU\x87B\xb1\x1f\xd8\xc3\x030\x16q\x1d\xf2`\x01 \xba7\x98\xac\x0b\x7f\x1d\xaa\xbb\xa7\x0c\xf2gG`\x7fb\xeb\x13G\xb1\x1b^HcRanC\xc7\xf5\xa0\xb3Cs\x8f\xc7g\x0d=\x01\x10Z.\x80\xd0\x02B\xdb\n \xb4\x80\xd0\xb6\x02\x08m\x0d\x08\xadY\x00\xa1U\x02\x08- \xb4\x80\xd0\x06zI\x80\xd06\x02\x08\xad.\x80\xd0\x02Bk\x10@h\x8d\xcf\x00B\x0b\x08\xadE\x00\xa1\x05\x84\x16\x10Z@h5I\x81\x96\x01B\xcb\x05\x10Z@h\xef\x1aB\xdb)\x1b\x87\xbb\x86\xf8\x9c\x00;9@\xd7\x9e\xc1\xbe\xaf\xd2&F|k\\\x13\x07\xc8\xfbj\xbd6\xe4\xdb\xe2\xf5\xba\x9f_\xcb\xba5V\x89\xb8.\x9c\xb7\xaf\xf1\x9e2\xc2\x1dEy7\xe5\x9c\xdc\x15\xc4\xcdz\xed@\xaaH\x93\x84\x8cW\xe4\xe6\x01)\xf8\xc5.\xf2\xb4\x8c\x8a`\x1e*\x9c\x91\x9a\xf9x_\xf1\xd0e\xce\x86eM\n\x84i\x96\xe7f_\xff7\x08\x8f\xc9B\xcf0%\xcf\x9f\xaar\xb3\xeei\xbb\xb8H\xbe\xf0\x03kYq\xd8\x05\xad\xab]&\x0f\xb9\x10K\x01F\x7f\xfd\x11mq\xde\x0fD\xc1-\x15\\\xe0\x96\x8a?\xdc-\x15f\x9eH\x7f\xba\x1e\xcf\x12\x19,%\xc0\x11\xe1\x02\x1c\x11\xe0\x88\xb4\x02\x1c\x11\xe0\x88\xb4\x02\x1c\x91\x1a8\"f\x01\x8e\x88\x12\xe0\x88\x00G\x048\"\x81^\x12pD\x1a\x01\x8e\x88.\xc0\x11\x01\x8e\x88A\x80#b|\x068\"\xc0\x11\xb1\x08pD\x80#\x02\x1c\x11\xe0\x88h\x92\x02\xaf\x07\x8e\x08\x17\xe0\x88\x00G\xe43rD\xe0z\x8a\xb8\xb3\xff\xe1z\x8a=\x1a\xd7\x7f\xb1\x02\\O\x91\xc2\x8ap=\xc5\x1f\xf9z\nN\x91\xcb\xca\x82\x96U\x9d\xef8Q\x8e/M\xd4\xce\x8a;\xe5\xbf\xf3\x92*0yS\xcewk\"\x16\xb5&\n\xdc!\xbe\x1d5\x9f\x10\xaf\xdfS\xd5\xbb\xa3\xc47\xdd\x08\xbaXU!/\x1f\x80\x14\xac+\xce]\x9c\x9cak\xb6bn\xd7V:f\x92m\xd4\xe5^)\x8fC\x11UP\xdb\xee\xb2\x05\xbb\xfb\x16w\xec\x9a\xf7 \xf1\x9d Z\x8c$\xc2\xc8\x92\x9d\x9d\x1e\xf5\xf4\x89\xadt[\x02`\xc3t\x7f\x036\xcc\x1e\x80\xa4\x88i\x91#F\xb8.+\xc7\xd4\xf8\xa3z\xe6\xd5\xae^\xb5S$\xde\xd5\xab\xb2\xca\x7fV\x8b\xcf\xa2\xe4\xeez\xab\xd18ev\x95\xc9'\xee\xec\x84\xc9\xeaxG:\x9a\xb0bY]\xc8\xad\xd1\xe8.\x93U\x84\xb7\xc6\x85\xa4\x05\xb8\x15\xb9&o\xff\xf4\xddk\xb6N\xe37\xf3\xf8\xb0#\xf1\xe8Y\xdb\x93\xfa\x81' \xecr\x01\xc2\xee\x1f\x87\xb0\xeb\x8a5H\xaf\xa4;s\x06y'&5\x87\xbd\xe9\xbc\xa5\xec\x82\x97\x02^\xcao\xe8\xa5\xb8\x82\x85\x10\x93\x8b\x0bx@Ln\x8f\xc6\xf5G\x93 &\x97\xc2\x8a\x10\x93\xfb#\xc7\xe4\xbet\xee>\x0f\x7fi\xfe\xad68\xae\x83\x8a\xbb\x1b \xfb\x8e\xd4\xb2\x91\xb0\xefH\xef)c\xdc\xe1\x0d\xa9\xcd\xa5\x18\xb5I \xdbVzV\xf8\xb0-\xa5\x7fC\xe9\xdbN\xa6\xdfL\xc6\xfa\xddC\xb7\x9bo\x0c\"\xbdnp\xba\xa5\x80\xd3}\x87\x9c\xee\xc1\x0cl\xeb\x89\x83\x07;\xd1\x95\xe6\xd7\x06\xc4\xafK\x19>Xt\x87\xdfD\x08\xdf\xbd\xd2\xd4\xe5%)\xd8\"\x83\xb7\xdb\xaa\xbc\"\x87\xbfp\xbe\xeaE>\xff\xf5\xf0\x97mU\xde\xdc\xfez\xf8\x8b\xfc\xadr\xad5\xaf\xc43\xed*#\xff\xbb,\x10F\xcb\xfc\x8a\x14\x88\xabS?T<\xc7\xdc\xb8\xd4HU\xf7T]\xef\xea\"#\x8a\x99t\x9dQ\xc6\x19\xb5\xbep\xfb\x8ezS\xb5\xf9\xa8\x97{\xe6\xe7\xbaP>G\x98\xd22\xcb9\x0b\x9f'#\x08\xbf\xf0\x92\x14\xc3\xf0a\xb7\xfdd\xcfi\xd6*\xf9\xdfl\x95b#\x959\xc1\xdd\xb6\xb3\x84\xb7D\x1a\xb7x;(\x10\xa4\xf2\xb5;\xfdO $ms\x81\xb5\xe8\x0e\xadEj\xdc\xda:`\xdcX\x9c\xb8\xd0h\xbbU6\x11\xedC\xb1\x9a\x1e\xd3\xe9\x8e[\x1d\xa9ay\xf4\xaf\x89\x1a\x18\xb8^\xab:\xd0\xc1\xca\xe8Z\x0b\xef>\x04(\xcby7\xc6\xb1{\x19\x0d\x18\x89\x8e\xa54\xe0m\xf7r\x1a\xa0`\xd206\xaa\x88^T\xdd\xf8\xe1\x04\x17\x07\xf0>\xc0\xfbB\xf1>\xe4e\"\xa1\xa6(\x9a\x7fWv8\xf0y\x81\x96\xccyk\\>\xe9\xa6Pt\xbd\"\x95\xa9\x13Y\x0e\x88\xc8\xcaJ\xe8\xe0\x87i\xa8\x98\x86\xa2\xab\xaf\xb0\x88\xfab\xb6\xab\n\xfb\xe1\x0b\xb8\x98\xa3/6\xe5<_\xdc~\xe1\x8d\x96\xf31\xd2\xc4\xcay\x0b\x8d\x84\x9f\xc5h\x0bZ\xd0\xe5\x12.\x07\xb7-I\xb2\xf9#,\xe5\xdd\xdf`)\xff\x8d\x97r9-j\xca&\xae\x99\xbf\xef\xa5\x9c\xee\xb6\xdb\xf5m\xd8\x02\xfe\x81?\xeb\xdeL-\xaar#\x16\x08mC\x95\xcf\x8dk\xba\xd0wO\xd5\xed\x8e\xae\xe9i7L\xa2\xce13\xab\xb4:\xcc\xac0\xb3\x0e\x7f\xbfK3\xeb\x9d\x9a\xfe\xdab\xb1\x1f{zc\x83[A\x13kw^\x15\xd3\xa1}.=\x17\xd3\xa5N\xb1\x11\xee\xe2\x86\xd4x\x8ekl\x0f4\xdd\xf9]\x90^\xf7\xce\xdf?\xc3 J\xb7\xf9\xc8\xe7\x1d&\xb4\xb8\xa5\xa4\xbd\xa3\xa4jC\xc0\xd6}\x08\xef\x90\x89\x8a\xc3\x0f8\xd4\x0b\xb4\xdamp\xf1\xa0\"x\xce#\xcd\x85~\xdf\x87\xbdH\xf4v3+\xc7O1\xbdB m\x1c\x1b*\x10\x9e\xcd*r%\xc69/\x0d_\xd7\xecEa=?UA\x98.\x01Q\xcd\xaa\x9c,\xf4\x1f\x1bg\xc5\\\x8a|\x83\x97l\xda\xcdS\x15\xc5\xb1]l\xbe%-\xc6\xfe\xa5\x16\x7f1\x1b\xf0'\xc4\xbd}sT.\xec\x97\xdfd+\x9c[j4'Y\xbe\xc1\xa6UM\x88{\x89\x15\xe2Zh\x95\x84\xd6Z\x95G9?\xad\x0f\xd9\xfc\"\x0epd[e~\x1d\xc7<\xbf\xca\xe7f\xde\x14\x13\xa6Dxi\xbf9*7\x9b\xbc\x8e\xedbl\xce\xbb\xa8o\xfa\x8d\xd2\xb3\xb7\xd9\xda\xc3E\xd9\xd4i\xd0\xa0\x9f\"{\xa3\x0c\xfb\xabK\xad\xa9\xdf\xba\x9e\xef\xf6_d/F\xa7\x1f;\x9e\xeb6\x10\xb2\xf4id\xf3\x03,}\x1by\xd6\x7f\x0b\xc4i\xed\xe7\xc8\xb5\xdc\x1b\xdf\xea\xf5y4\x98R\x91\xa9\xef\xa3a\xffG\xb61\x80\x1c\xe3\x00\x99\xc6\x022\x9a\xbb3&z\x7f\x98\x8bi\x17z7\xf4\xee\xc0\xde\xfd\xac\xdf\xa8w\xb8w\xaf0]\xf5\xfb\xb5\xa5\x9e\xe8\xf8\xf8\xd9\xdb'O\x1f>}\xf8\xe4\xe9\xd1\xb3\xc7O\x9f=|\xf4\xfc\xf1\x8b\xd7\xcf\x9e\x1f?|\xf3\xe6\xe8\xc9\xb7o_\xbdy\xfe\xec\xd1\xdb\x87*\x9c\xbd\"\xf9rU\xf7\x95\xb7\x1d\xee\xaf?\x9e\xe2\\\xee\xdf\x02\xd6\x98N\x83\x1a\n\xdak\xbc\xde\x13?\xd0\xa5\xfe\xa5\xe6\xef\xaf\xf4S\x89\x07Z;\x9b\xdb\x19\xc9VO\x1e#R\xb0V\x9ew\xf2\xf1\x1a\x13e%\xdd\x94\xf4\xd1\x9cl/\x9f=\xcdv\xf8\xa7\xe5\xe5\xcf\x04?\xffy\xbb\xbc\xfc\xf4\xe4y]\xfct=\xff\xf9\xea)^dO\xe6\x8f\xbf\xb9\x87\xb43\x86\xf7Q\x8e+\xbcfV|\xf4\xfc\xe6\x96l\xb6d\xb3\xdd\xbex|\xf3bu\xfb\xf3\xcf/\xae\xab\xe5\xe2\xc5\xd3\xea\xf9O/V\xcf\x16\x8f\xaf\x9f\x16\x8f\xd7l\xefR\xe6Ep\x83\xccIQnB\xfb\x0e\xad\xf1\xa5\xda\x89\xf5\xd9\xec\xee7\xbf|\xf6\x90u\xd6\xef\x9b\x8e:x|L\x07=\xbf\xe1\x1b\xbd\xe0\xca\xc6\x8c\x937\x0f\xbf}\xf6\xe8\xc9\xb7o^=~\xfc\xe8\x9b\xa3\xd7o\x9f\xbc~\xfa\xe2\xf9\xb3\xe7\xce\xf1#bm\xc3\x8f>y\xfe\xad\xfc\xe3\xc8\x85jC\x8d\xd3y\xd4,=\x98W\x17\xfd\xe4?\xebl\xeeHh\xc4\x86\xe9\xdd1\x8f\xbb\x93%~\xdb\xf8Jo\x8ct\xc5\xb9\x16 1\x8e\x9f\xae\xd8\xaa+$\xe6\x1br\xa4)\xd9\x90M\x98#@\xf3e\x81\xeb]5\xbd\xa9-\x9a\x90\xaf\"M\x15\x8c!\xeb\x1f\x8e?\x1e\x9d\xfc\xc7\x9b\x87\x8f\x17\xf4\xcdi\x85\xbf\xfd\xa1\x9e\x9d\xd1\xdb\xd7\x8f\xae\xbf\x99}:\xff\xe1\xd9\xb3\xbf\xef\x1e=\xf9\xf6\xe7\xff\x98\xbd\xcd\xfe~\xf3\xf4\xdf\x8e\xde\xde\xbe:Y\x92g\x7f\x7fw\xba\xf8\xeb\xc9\xee\xea\xe7\xd7\xff|\xfe\xe2\x87\xdbO\xdf\xd3Oo\xbe\xfd\xf0\xe8\xe4:?\xde\xfe[\xfeq\xf6\xfc\xc7\x0f\xf3z\xbd]\xfe\xe3\xbb\xde'\xb7\xbb\x99\x99>\xe8\xecK\xee\x9e\xc4_5\xb6\x9f\xb7\x81\x1b\xdb\x94\xb4\xaepV\x16\x87\xa7\xbb\xd9_\xc9\xed\x07\x92m\x1f?{~\xf9\xc8\xf0\x96#\xaa\x17\xfe\xbdWW??|\xfa\xe3\xaa\xfe\xeb\xbf\xaf\xbe}ut\xf4\xe3\xcf\xeb\x93o\xf1yI\xffr\xfb0\xbf|\xfb\xbf\xffz\xf2\xe3\xf7\xff\xf1\xe4\xa7\xbf\xfeP\x95\xf4\xfb\xfe\x10\x16\x19\xbd\x17b\xb2\x1b\xdb\x19\xbe|\xf8e\xbf\x7f\x91O;Rd\xa3\xbbW\xab\xb1\xd26\xc8(n\xa2\x0d\xf5\x9b\xdd\x8e\xbb\xa1\xa8m1\x1f3G\xb1S{\xd7\x9e\xc1\xad\xea\xf9\x93gOuM\x7f!\xde\xe5'\xc4\x1d\xb2Y\x01\xb9-\x81\xfc5\x13\xe2\xab\x9f\x10\xa7o(\xc4[[%\x01~\xa2\x10\xb7y\x84\xc4\x7f\xb5\xe79\n\x19\xfa\x8fB\x9c\xea\x1d\x1e\xa0\xd7\xf8>\xb3;u#_\xc9\x84\xb8=M!\xbf\xb1\xbf)\xc4\xeau\n \xe8\xb7>\xf3!\xa5\xc6\xd1'\x02,\x88F\xfa\xa4B\x9cx3\x1aQ\x82 ^\xaa\x10\x9f\xaf*$\xa0X\x0e\xbfU\x88\xdd{\x152\xe5\x1b}\x7fV\xc8\xc8%h\xe0\xe1\nq\x96\xcf\xe6\xed\x06\xbc\xea\xf6|\x85\x98\xfd_!\xe1\xca\xfb\xbe\xb0|\x7f\xe0\x11\xcb\xbfO[r\x1d\x83\xd5?T\x1dS\x81\xb7\xc2\xc8?\xcez\x1a>\xd4\xf3s\xe9\xbf\x0c\xca>,k\xc7C\x89p\x0d;\x05\xeex\x1eF\x83\x99\x8d4\xf0-,\xc60-\x94\xb6\x06M\xb9\xd1\xb1z\x05\xa1\xbd\xd4\xec\x01\xd8\xd7\xfdP\xbd\xda\x1a\xdf]\xd9\x0d\n\x0c+mD\x139\xe3I\xae\xcd\xea`M\xfe\x0dWb\xe3\xfak\xed\x03\xf6\x1e`^a\x9d\x8d\x14\xbb\x9aZ\xc6v\xd87F\xae\x97\xaeU\xd2\xdf\xb0\xdd\xd5\xca\xbc\x0e\x86jy\xbd.\xb3\xcb\x937\xc1\xb3UL\xe4?\x02\x80\xe0\x1f\xc3U=\xd8%\x07\x0d\x11C~\xaex\xdb\xb0\xe9lJ\xa7C\x87\xc3\xdd\xb3\xdf~\x11\xb5\xe3F\xfe\x9e\xe09 \x07\xf88\xed\xb9sR\x9f\xdb\xd8\x02\xe3Z\xedf\x0f\x14-3\x0e1Q\xc3\xa2\xce7v\xdc\xb0\xf7\xce\x97\x8f\x1f>\xfa\xe6\xc1\xa3\xc7\x0f\x9e<<\x7f\xf8\xec\xe5\xb3'/\x1f\xbe8x\xfc\xed7\xff\xf6\xf0\xd1\xcb\xd6\xed(v\x9b\x0bC\xfc\xc3V\x10\xd5.kL\xeb\x8b\x19\xb3\x9c\xc1\nA\xddb\xcf\xad\xda|\xbc\xdbo\xd1\xc8\x99\xce\x9ccn\xed\xc7\xc8\xd6\x97\x91%\x1a\x14:\xa5EZ@\x04\xfd\"\xda\xf7\xc93\xbd\x813N\xb0\xba\xd8\xe3\xb42\xc75\xde\xa7\xfe\xf6V\xe5}~\x85'\xa4\xfe6\x9f\xca\xca\x82\x92\x82\xee\xf6\xfa\x11\xbc\xdd\xeeS=\xef[2Sr\x9f\xdf!W\xf9\x9c-\xbe\xfb\xfc\x06\x9b3JJ\x0cwF\x1b?\x13\xca\x8e@\xc3\xd5#\x9c\xa9\xc1\xe4\x8aT\xb4s\xdaH\xc4\xd4\xcc\xe7\xf5\xd8\xb9\xf9\x91>\xcd\xe1\xed6\xf6\xfd\x87j)\x0e^\x84W\xda\x9am|\xc5\xfc\x1a2\xae\xdf(\xa8\x90\xc3u\x1cY\"\xeb~\x17Gwu\xbb\xeb:\n*K\xd8\xfa\x8eLk<\n*\xa0\xde\xa0\x96\xf5\x1e\x8d[N\x7f\xc3\x15P\x89\xc1\x0f@\xae\xc2#o\xe8\xc2{\xee\x8c\xc5/@.\xdf\x00Y\xad\x83|\x16B\x13\xadd\xf0\x15PP?y\xf2\xac\xdfQ\x8c~\x03\n\xea\xd5#\nn\xf0!\xf6\xf6-\xeb\"\xbf\xb7/\xba}\x8b\xbd}\xd6\xe6g\xec\xed\x83C\x9fco\x9fr\xf8\x1f{\xfb\xa6\xc5\x17\xd9\xdb\xf7\xec~\x89\xf3\x931\xfe \x9a\xea\xa3 \x93\x9f\x82\xc6-)\x06\x9f\x05\xf9fL\xb3\xef\x82L\xfe\x0b\n\xd65\x95T\xd0\xd1\xafz\xcdtM\xda\xbc<\xcac\x82\xb5\xbf\xf3\xea\x1fl\xed\xdfVD\xf4\x0d\xe3<\xb1_\x14\xa1Y\xdb\xccS\x95\x10g\xed[\x0dy1'\x03r\x8a\xf7}\xdd\xa96\xe0qf\xe2\x0c\x9a\xa8\xb5*w\xc54\x88\xcf\xa0\x94\xed#h\x8d7\x86\xd9+Bq\xf0\xc6B\xd3k\xfd\x9eu$4\xdf\x1b\x1e\xef`\x9el\x848G\xado\xdc\xba\x06\x98\xd7@h\xe2 k\xc52! \xf1T\x10\x05T\x12\xb9\xa7(\xf9\x80o\xa2\x12\xe2\x9c\xae\x84\xb8l\x8a\xc2\xec\x8a\x92\xd86\x80\x91\xe3\xef\xfe\x16\xb6\xcc7\xbb\xf3\xa3o\x9e\xfe\xc7\xfa\xb2\xf8\xf4\x8f\xbf\x1f_/\xbf\xf9\xb1x\xfe\xc3\xb7\xef7\xdf\xbc\xdd\xfd\xf3\xe1\xf1\xfb\xa7\xb3\x9f\xaev?=\xaf\xae\xbf\x7f\xb49\xff\xf8\xef\xd5\xd9\xee\x87\x1f\xfey\xf5\xea\xd5\xa7\xf3\x17?\xfe\xf4ny\xfa\xf0\xec\xd5\xe1\xf9\x9b\xed\xf3\xdd\xe1\x8b\xc7\xaf>U\xff\\\xfc\xef\x7f\xff\xb0}\xfd\x1f\xdf}\xa7\xc2\x1eq9\x1eb\x84tO\x9f\x89X\xcd\xfb\xa1\x13\xeb\xebv\x15\xc8\x1aFA>c{\xc2)\xc81\xe7:;\xad1\xb4\x82\x90)\xbc\x82\x82\xcb\x187\x1b\x1aC-(\xb8\xe0\xfd1\xe6\x08\xbb \xdfT\xe1\x9e$>\x93\xa3\xa1\xc41\x03z\xe7?\xff\xec\xe7\x99\xfb\x82f>\xef\xbc\xe7\x9e\xf5\xbcVD ,i \xd9 _\x1d\xcd\xa1\x1b\xe4\x0d\xdf _\xc5\xa6V\xc8\x12\xcaA\xfb\xfe\xae3\xbe\x82\xf6\xfdu\x7f\x88\x07\xed\xbb\x08\xaep\x0f\xda\xf7\xc7\xcd\xa1\x1f\xb4\xef\xcfz\xc2@h\xdf\xdfw\x84\x84\xd0\xbe\xbf\xed\x0e\x0f!\xdf\xe7c\xc3Dh\xb8\xea\xc7\x87\x8a\x90-\\\x84|\xab\x86{\xc5\xb0\x84\x8e\x90\xcf\x08\x08\xb9BH\xc8\x16FBQzu\xb5\x10\x83\xe9\xbc\xfa\x07\x8a\xc1\xf4\xba x\xf2\xe0\xc9k\x02\x9e\xbc\xf9\xc7\x80\x81\x8e|\x83\x1d\x81'\xbf\x97\xf9\x1e<\xf9\xcfT\x04\xf0\xe4\x7f\xfb\xef\x83'\x0f\x9e\xbcW\xaf\xae\xd6\xc2\xb2\x89\x02\xda\x06\xdf\x1c\x82\xc5(\x91f#x\x8c\xc6y\x9a\xe0\x03u\x05| %6\x10\x1a9z1\xda\xe3\x81HA\xc04\n\xb1N\x00@\x8dB\xf4\xe8\x9b\x19K\xe2\xad\x1d\xacF\x89\xbe`\x05\xaeQ\xa2\x0f8Al\x14\xfb\x91\xa8M\x9f\x10\xae\xdf\xf9m\xe7hk\xbem\xbe\xb7\xc0\x05n#\x7f\xafE\x01=\x17y\x07t\x90\x11Q\x82A\xdd\x8a\x13\xf4Fa\x15G\x81\x95G\xfeiS>\xe4oN%\xde)T\x88\xcf\xee(\xdc\xf6(\x99\xfd\x7f\xab\xe3$\xf6\x08\x92\xbf!k\xb2\xe4\x97K\xc8\x7f\x95\xd5\x19\xb9\xc6\x95\x1cG\x83\xce3\xec&\x8e\xf9\xdcX\xfd\x18\xd7\xb8\xe7\x12G\x9ff\x89\xf8\xb9\x06mu\x90e\xcd\x9bz\x12\x911e\xdb\xd1\xf8M\xbd\x86\xa9\xda\xe64\xed\x10]2=\xbbi\xc7s6REc\xd2\xe0\xd6\xac\xf4\xe7\xd1\x9e\xcc\xe5u\x01\x1c\xd5\x8d\xe9>BRt\"!\xfd\xae$\xc4\xeeDY\\\xa8 \x1e\xb9\xe3\xc4 \xef\\\xe3\xe8tB\\'\x03\x85k\xd7N 0\x1e6\x96\xb6+\xdd\xa5\x91\xf7\x1aSrF>\x05\x8f\xb5E\x15~z\xae\x8c ,_\xe0U\xf5\xfcf\xb5\xaa\x9fU\x9bOW\xa4x\xfe\xf8\xdb\xe2r}\xb3\xde\xfd|{\xf5\xed\xcf/~\xfa\xf4S\xb6\xc9\x9a\xd7;\x83\xe5\x03)\xe6\xa4R\x83\x04\x95\x15\xfa+\xb9\x9da*/\x06\xe3\xb7.\x15\xa4\xc25A\x18\xd5\x15.(\xce\xd8\x9bR\x9b\xf7\xc8\x07\xad\xb4_| E\x8d\xaer\x8c\x8ex\xb9\xd1\x8f\xe5-^\x92\n\xfd\x7f\x1f\x1f>|\xf8\xe8\xed\xf3o\x1f~!\xdf\x8a\xcd\xf9\x16\n\x1f|\xbf\x9b\xc9\xdfl\xe7\n\xb8\xd5\xb4^\xf2\xf0,\x01\xcf\x9b\x8f\xd4\x9b\x9d\x83D_\xbe\xc8\xe8\x93\xcb\x17\xd9N]\xfe~U\xd6y\xb1\xbc\xd8\x96\xd7\x11\x93\xc0#mL6\x11\xdfm\x95\x97U^\x07W\xb0\xd1rNn\xeaS\xaeE\xadz\x01m\xbc\x95/\x18\xa6\xc0\xee\xcd\x0c\xe2\xba7W\x99\xf4\x8e\xe0z\xae\xf9$\xff-\xe8IZ\xe3z\xe7\xee\x88\x8b\xbc`*\xf1z}{1\xe1l\xdc/o \xfd\xb2;UX'\nm6?x\xd8\x88\x1e}\xc03Z\xe3\xdc\x98\x075J\xdf\x97E\x99\xaepEy\xc1f\x8f\x8b+R\x87\x1d\xb3\xedSJw\xb3M^_x\x8f3\x11\xb0\xe8\x9clK:\xcc[\xfac\xaf\"r\x9a\xa05\xae<\x86:\x95\xf3A\x8a\x91l\x18T\x8eY\xea\x8d\xde0\x01\x1f6\xdf\xa6\xf0\xc7n\xc7Pc\xcbN^\xfa\xd6\x84 \x8bh8Pw\xce&\xc7\xc8\x8b\xb5z\xf3\xa1g)2\xcd\n\x839p\x84\x8e\xee\xbc7B\x81y\xae\x8bT\xf4c\xa9\xdc\xbf\x00\xc3]\x95\xb5\xc7\x13\x08\xedC\xa5{I\x8d\xf7\xebJ~\xf7\xf6\x9d\x8d\x98\xb5\\\x87\xednv\xf7<\xbd\x9fp\xbe\x1e^0\xd8\xdd\x06\x98\xfd\x95\x9eC\xc5\xafZ\xf7\xcc\x1e2\x96vAW\xb8\x1a\xee\xb8B\xdd\xaf \xcfgS\x16\xf9e\xe0\xc9x\xe2v\xf1\xdax\xd8\xe0\xe0\xe1k2\xa3y\x1dv\x12\x8a\xba\xf6\xf4\"+\x8b\x1agF`z\xf0\x92\xf1B[\xc3\xb3\xb3\xb2\x98_\x98\x8fh\xb3\xcf\x01_\xea/\xe7E]\xe1\x8b\xfaF\x9c\xb8?\x1c\xdf\xfd\xcb\xcc\x1a=\n]\xd8\x15L\x0fs\x01\xc6\x96\xa3\xd5\xe0\xf5\xb3:\x9b\x84\x17\xdf<|\xf0\xf0\xd1\x83\x87\x8f\xce\x1f>|\xc9\xff\xef\x9fJ%\xc7g\xe9\xe8\x83\x85*\x1c\xd8\xb8\xc6\xfa0\xd9\xe0\x9b\x8b4Z\xb2\x15.\x96$\x81\xb2\xddv\xce\xb6\xd1\xa3\x8e\xf0\xb1\xd9\xba\x05;\x82\xa7\xeav\x06\x08\x99\xab\xe3\xb0\x90\x809e\x86\xd7\xd8\x10\x9b\n\xea\x16\x06\x97\xcdo\xbb\xbe\xbbf?\x04\xd7\xd9\x02\xc2Q\xfb\xa8\x86Jk\xf8\xa8\x0b\xdf\xf6i|R\xd4U\xbe\xef\x18\x1a\xbf\x15\x1a\xaf/\x06\xcd\xa8k3\x182\xf6\xf9\xac\"\xdc\xba\x83I\xcd\xf3\xde&/\x0c#l\xf0B\xd3\x8e\xc7\xba\xd1\x02\x1a\xd0Z\xff\xf0\xae\xdey\xc6ZO\xc3\xb3\xc3\xba\xd9ju\xc7\xa6\x85\xdf\xd8h\xdd%\xd3f\xb5\xf6\xa932\xff\xed\xecE\xab,\xf2\x8d9\xad\x83\xde\x187\xfe\xff\xaf\x8a,^\xa2/\xff\xcfC\xed\xca\xf7C\xdd\"_\xf6,\xc4FLx\xfeyTSe%\x9bl\xf9\xe3\xee\x16C{\xe8Tb\xedb\xd6\xb6>\xd6\xec\x8b\xde\xe4\xb4>i\xee\x94\x0d0\xc3\x1d\xdf\x1fQ\xb2^\\pw\xf47A\xcb\xefZ\xe8\xe5\x8a_xe\xf3X\xff\xb8u?\xdd\xcd\xd6y\xf6W\x12>\x9c\xf9#\xae\xbe\xeb\xbe\xb1\xf6C\xbe,\xf2b\x195tD`3`y\xe4\x94\xc9\x8br\xb1\xa0\xc4\xfd\xa0\xd8n_\xec\x8a:\x1f`\xf9\xbd\x05\x97R2\x17\xd9X\xd4\xb6Ak\xde8\xc5\x15\xde\x1c\xf1\xddBx\xe5v3\xba\xc5\xe1P-\xeb\x04\xed\x0f\x11\x91\x8c\x1f\xf0M3{\xd1\xf6\xe3\x11\x1a\xbe\xfc\xd2\xd5\xc4M-?\xec\xb6\xdbuD\x87\xfas\x11*\x96e\xb9\\\x93\x83mU\xd6\xe5l\xb78xUD\x98\xeavK.v\x95\xbb\xcb\xba`\xe1W\xe8\xe3\xd9\xdf\x0e+B\xcb]\x95)\x8e\xc4\n\xd7hW\xe4\x9fvd}+\x830\x8b\x9cPT\xaf\x08\xd7\x8f\xca\x05\xfb\xb7\xa6\x86\x92*\xc7\xeb\xfcg2\xbf\xd7\xb5~]f\xe5\x1a\xcdv\x8b\x05\xa9\xd0\x86P\x8a\x97\xe4\x00\x9d\xafr*\xcb\x886;Z#\x1e\x87\xc9\x0b\x84k\xb4&\x98\xd6\xba\x96\xb2 \xe8\x8b\xc3/P\xb6\xc2\x15\xcejR\xb1\xf7 \xcf+@\x94,7\xa4\xa8e\x81X]\xbe\xa4h\x8b\xeb\x95P[\x91mE():\xfa\xd8\x83\x8b\xddz}\x8b>\xed\xf0\x9a\xd5l.\xea-\x95\xf0\x1a~\x85)\xca\x0b\xfd\xb5\x7f1\xb5\x87\xfd\xc6z\xb3\xab\xb8/\xf3\xaf\xafE\xa9\xb8\"\xba*w\xeb9\x9a\x11\xc4\xaa\x842\\\x94E\x9ea\x9df\xb5(\xab\x8d\xae\xfd+r\xb0<\xb8\xcf*\xcf|u\xf4\xc5\xc1\x17(\xa7\xa8(k\x84\xb3\x8clk2\xff\xfa\xe0\x9e\xfe\xc2I\x81\xb6\xcc\x1cyF\xee\xa3\x9a\xe0\x0dE;\xba\xc3\xacZ\x82\x0b\xbf\xcd\xd7\xec\xfbu\xc9+5\xcb\x0b\\\xdd\"\xbc^\xf3\xfaQ\xde\xc8]\xa3\xdc\xea\xea\xc9\xcd\x96d5\xcakT\x97hGyM\x98\x1e\xd6P\xe4\x86\x1b\xfcUq{\x80\xbe/\xaf\xc9\x15\xa9\xeesJ\xc1\xc7\xb3\xbfQt\xbd\xca\xb3\x15{\xa5\xab]WN\xb3\x15\xd9\x10\xf4\xafU]o\xffu_\xfc/\xfd\xd7}TV\xa8(\xe5\xaf\xf7y\xbbg\xb8\x90\x81i^3Jj\xb4\xdb\"\xcc\xebp\xaf\xdb\xff\xaeH%z\xee\x06o\xa9hD^\x9e\xbaT\xfd\x0ei\xee,\xe2,\x88\xf5\xba\xbc\xa6/;v\xfd\xbf\xd1\xc9\xa2-\x05k\x84mU^\xe5s2o\n\xca\xfe\x88)\xddm\xc8\xfc\xa0\xfb\xea\xab\x02}\x7f~~\x8a\xfer|\x8e\xcaBuI\xd1\x17os\xb2\x9e#\x8c\xfe\xb3\xdf\x85\xceo\xb7\xe4\xbf\xfe\xf3\xbf:\xb3\x04\x9fO\x99\xcde\xbb\xb1\xee\x82kn\xa1mU\xcew\x19A\xb8@\xa4\xaa\xca\xea\xa0[\x82\xedv\x9dgX\xd6\xb1\"\xac\xc5\xcbk2gf\xc8p\xc6\xc6MY^\xee\xb6\xf2\",\x8af\x98\x92\xb9,l\xa7\x08\x1f\xcf\xfe\xc6\xbf\xb7\xc2WlJ \x1b\xad_\xcdE\xc7\xc2\xaax\xec\xdfWe>G\xb8\xe8\xb2\x03\xc5\xc7\xf8\xd0\xa8\xc8\xa2\xac\xc8}\xf5\n\xd3\x84\xeb|\x96\xaf\xf3\xfa\x16\x15\x84\xccyS\xcd\x08\xe2C\xb6\xba\"\xf3\x8e\xa6\xb2@\"\xea\xc6\x1f\xe3}\xf8\x00}\xf5\x91\x12\x95\x0c\xc6\xea\xc8\x1a\x9d\x8d@\xd1\xea\xb8\xc0\xcbn\x9df\x15\xe1k\xa5Ru\xf0\xb5\xde~\xef\xca\x9a\xbcD5\x9b\x9b\x16\x92\xf8\x82y\xe9\xe4H\xccvUE\x8az}\x8b\xf0\x15\xce\xd7x\xb6n\x86E\xb9X\xe4Y\x8e\xd7\x83\xd9o\xb6[\xa0\x8a\xb09\x8d\xdcG\xb8\x98\xb3\x11%\xd5q\x9e\x0d\x1b6m_\x9d\x91e^0oH\x10n\xf4\x11t\xbb%\x07\xa2\xe7\xe0mN\x0f\xb2r\xd3\x9d\x0f>\xf0\xfeJQY\xaf\xc4@(\xfa\xe3\x0b}\xc5\xbe\xb5\"\x88l\xb6\xf5\xad\xec\xe0_\xa3\x0ds\xa2\xd0\xac3\x9cx\xd1X\x11P\xce\x96*6\xc5\xf2.\x85\xe8\x96d\xf9\"\xcf\x10%\x1b\\\xd4yFU\xf7s;yBD/~\x89f\xb7u\x08e\xe9\x076lf\x04a\xb1\xf1\xd5\x16\x99\xc1\xca\"\xa7n<+\xaf\x88*d\xa7\x03q\xfb\xdd\xb3\x7f\xef_\xaf\x8a\xdb\x7f\xa9e\x88\xb2\xc1\x85\xabY^W\xac\xab:\xbe\xabf\x16\xbc.U\xa3 }X\x99\x93\x8d\x7f>-\x89\xef\xce\x86\xcb\xa8\xae_\xad\x90M\xd3\x9e\xaaN\xb4\xceg\xbc0r6\xa2\x88\xee\xb6\xdb\xb2\xe2\xf3\xf3\x16g\x97\x87\xbb\x82\xfd\x0f\x9b\x95E[P\xd57\xf5\xa5\xa6\\\xa0]-\x86\x9c\xea\xe2\x9c#\x89\xe7\xf3\\\xf4\xf7\x86\xdb\xc5\nS\xaf\xca9U\xc5d\x9a\x85\x19\x95\xb6c\xe1\xc9\xa0G/\xd1)\xfb6\xeb\xdf\xb2\x18\xb81M^\xa0\xa3\x7f\xfb\xb7\xceD\xf9\xb6,\xd1\xa2,\xd1w\xe8\xe0\xe0\xe0\x7fj?\xb0O\xe0\xe2V\xff\x13.n\x0f\x98\xf2\xb7U\xb9\xf9jQ\x96_\xeb?\x1e\x1c\xe8\xb3_\xbe@_\xb1\xc7?\xf2\"\x9c\x97_\xfd\x0f\xf6\xfc\xd7\xe8\x97\xce\x1c\xd0}\xe7\xd7~]\x1e{\xea\xf2\xef\xf8\nGU\x06}\xc7WJ\xa6)\xb0\xfc9\xfd\xeamY\x1edkL\xe9\xa0\xf8\xe2S\xec1Q:\xed\xd1\xffi\xaaWS\xb1'\x9e\x8a\x9d\xde\xd6\xab\xb2\xe8TM|\xebmY~upp\xf0u\xb7QD\xb5\xbe\xfa\xda\xd0T\xbc\x9a\xaeZ\xb2\x07OD%\xdf\x1c\x7f8:;9=\x7f\x7f\xf6u\xd7\x85n\x1b\xb2\xafN(\xecW\xef\xa9\xa7z\x7f)\xf5\x9a\xf1\xaa\xbd\xfc\x0e\xfd\x8f\xed\xec\xe0mY\xferpp\xf0\xeb\xbd\xee\xd7\xef\xb3\xe5\x95=\xb3\x15\x8b\xcd\x0f\xb8\xa2+\xbcf\x95\xee\x17\xa8[\xc1\xbe\xee\x8e\xe2|\xd1S\xfb\xb1\xd8\xb4\x8a\xf9gy'\xe1O\xfd\x1f\xdf\xa1\"_\xf7:@\xffkMK3\xf7\x93\xd7[\x8d[\xe5\xb8\xa0\xd9m\xbb\x18\xa9y\xe4:_\xaf\xd9\x0fs\xb2\xc0\xbb5_\x8d\x94\xa2/\x0d\x8b\xcd!\xf3\x98\x0f\xf8\x0fl\x81\xfd\x92\xf9O\xcd<\xc6\xe68fw\xf6\x07a{\xa5\xaa\x99B\x8a\xf5-w#M\xcew\xb3l#\xbc\xa8\x89X\xa3\xb8w\xff\xe5\xe1\x97J\x91\x9c\xcb\xd4\xe7\x84\xbf)wR\xe8\x8bEY\x1e\xccp\xc5\x0bzsx{\xf0\xf3\x17\xa2~\xc2\xe7\xd2\x9dE\xfe\x99/\xd8\x13l\x1a\x93\x7f\xfc\xf7\x0f\xef\xdf\xa9\x7f\x7f\xf7\xddw\xdf\xe9\x16e\xbf\xb5\xfb\x08\xb1\n\x96\xac\x0b\xcb%Cxj;*\xe7\xf5\x8a,wk\\)\x0d\xc3\x17\xd9Cs\xd2N\xf9\xf7\x11\xd9\xcc\xc8|\xdeN\xfe\xf7\xc5\xca\x8b\x9b\xdd\x8769/x\x85\xfe\xf5\xff\xb2*\xfdK\xba\xda\xcd\xa2\xa5\x1b\xe8@\x0d\x8c\x97\x1d\x97\x04g\x97l<\xb4.\xe8\"_\x13}\xdeP#\xe6\x94T\xb4,z]O\xee\xd8\x16yE\xeb\x0bn\xc9\xef\xd0\xa3\xffiz\x84'}\xcb'\x1e\x9b\xe7%\x84z\xda\xbf\xe0\xb5\xfa\xe2%\xfa\xc2\xd4\xff\xbaE>\x10\xe5\xfb\xe2~W\x03/\xd9;\xbcaZ\xfe\x1fQ\x94\xff\xd5{\x84\x95\xac\xf7\x84\xa9x'\x0b\xe9*u\xdbF\xd87\xa7\xe8\x9a\xac\xd7\x0f.\x8b\xf2\xba\xe0=\x7f\x85)\xdb\xe8\xedh]n:\xdd\xa9\xdb\x01\xee\x0bW\xa0\xd7+\xc4P\xd4>\xc6\x1a\xbcX\",\x9a[\xa9\xfa\x17\xefj\xaa\xd5W\xe5z.\x9a\\\xfb*\xdfo\xca\xde\x82\xe4\xceOv\x16\xa5\x85\xablz\x07\xfa\x8a\x8d#U\xb9\xc1\xd6D\xedn\xff\xeb?\xff\xeb\xeb\x97\xd3[\xae\xab\xb4\xdfx\xbczL\xc9\xa3\x83\xc7\x8f\x1e\xd3/:\xcd\x82\xd0\xb2\xdaf\x07K\\\x93k|{P\xed\x8a:\xdf\x90\x83c\xb6\x03\n\x8e\x96\x90\xf6id\xf6Q\xb3r\xee\x81\x18Z/6/\xea'*KWZ\xd0\xa9{\xc0\x1f\xa9\xf7\x10\xd8\xaa\x07\x01!]\x8d1\x1eew\xc0\x85$\n\x11 1\x07\x8a\x84\xa4 \x17 \x19\x1f4\x1a\xa82\x06\x91\x84\x8c\x0c% \x19\x1dP\x1ahj\x02L\x83\xb0\x92\x90\xe8\xe0\x92\x90\x89!&\x83\xb5p=\x084 \x99\x18n\x1a\xe8\x93\xae\xc6\xf0C\x13CO\x03}\xc3P\x94\xfcN\xb2\x80\x94\x90 a)\xa5 YpJ\xc8\xc8\x10US\x9ad\x81*!I\xc2UB\xd2\x05\xad\x84$ ] q\x07\xb0\x84\x8c\x0fc\x0dgQCXK\xc8\x94\xe0\xd6@Y?\xd8%\xc4\xe0K\x98f\xa9i\x81\xaf\x81\xba\x99a0\x8f\x08\x87 1\xde@\xedX\x8a\x8d\x012!\xbeUzd\xb0l8q\xa9\xe0\x99\x162\x13\xe2*A\x8a\xf0YG\xa1\xd8\x02u\x9bbb(M\xc8\xf4\x80ZG\xddp\xc1\x9d\x18b\xeb\xe8\xaa;\xe16!c\x83nB\xac\xd1*!\x86\x00\x9c\x10g\x18NH/.\xc1%,$g\x7f\xffWs\xdd\xa3\x83tB\xc2*\xef\n\xd8 q\xd5\xd4\x19\xbc\x13\x12\x18\xc2\x13\xd2\xb3\xc0\x94p\x9e\x10kPO\x889\xb4\xd7\xfcf\x0c\xf0 \xb1X%$\xd8'\xc4\x15\xf2\x13\xa2\x07\xfe\x84\x8c\x0c\xff \xf1\x04\x01\x85\xc4\x85\x02\x85\x98L\xe1\x0c\x0b\nI\x10\x1c\x14b\xfc~\xaf'%\x0b\x17\nI\x184\x14\x92,t($U\x00Q\x881\x8c(D\x8f\xfe\x08\xd1C\x8aB\xa6\x07\x16\x85$ /\nI\x17d\x14\xe2\x0f5\nq\x06\x1c\x85\x04\x84\x1d;\x0fZ\x83\x8fB\xfa3\xea \x9c%$4\xa8e\x0fGJ=\xfe\xa0\xa4|\xd0\x1d\x9a\x14\xd2+|\xaa0\xa5\x90\x84\xc1J!iB\x96B\xd2\x04.\x85Liog\x10S\xaar\x842\x85\xb0\xc9\x7f=\xdb\x1c\xe0]\xbd:\xb8zt\xc0y\x82\xe1\x19\x07\x1b|s\xb1!\x9b\xf2\xa2 o\xf9\xd8\xc3jg\xb1\xcb\x8b\xfa\xb9:\xe7\xad\xbe\xb9\xa0\xf9\xf2b\x9d\x1b.\xf6\x0c~\xffgr\x91\x95\xb4\xbe\xd8\x92\xea\x82\xed[\xc6(b\xa5\xb8\"U\xbe\xb8\x15\xba\xc8\xfc\xf1\xb3g\x8f^\xa4PEI\xb6}\xfc\xec\xf9\xe5\xa3xe\x9d\x0d\x8fh!\x11\xb1\x91S\xf2\x96\xfd\x890\xe3\x8b\x9d.\xdbS\xed\xea\x15\xda\x94\xf3\xdd\x9ao\x9d\xf4&\xe6w\xb4\xbd\x12\xc7\xf8\x9c\x11\xba-\x0b\x1a\xce \x95\xc7\xff\xb4u\xe8\x94M\xfe\xda)\x9c\xfa\x9b\\\x13\xb2\xb2\xaa\xf8G\xc5`\x15|\xf1\x83\x9eI\x82\x12\xaejc\x84\xd9\xba\xa9u\xef[\x13\xc6\x96\xed\x91\xe5tq\xe5dQekLyBD9U<\xd9\x1dM\x1e\x15KN\x1bI\xb6\xc6\x91\xd3F\x91-1\xe4\x89\x11\xe4\x81\xb9\x87\xcee\xea\xe8\xf1\xc4\xd8q\xe2\xc8\xf1\x84\xb8q\xea\xa8q\xb2\x98q\xda\x88q\xb2x\xb1?Z\x9c,Vl\x8b\x14O\x89\x13\x1b\xe3\xc2\x06\xe7l8\xdfL\x8b \x1bb\xc0##\xc0\x86\xf8\xafu\xa1\xb4\xc6~\xdd+\xe8\xc8\xb8\xaf\x91$\x89\x02\x88\x92&7\x865\xa6\xd8\xa3\xca\xff\xe6\x8d\xa9|\"\xfe\xc6\xa1|\x05\x9d\x9d\x1eIMb\x83ot\x93\x84\xb3\x15\xed%m5/zP\x83\xad\xd3\x81\x93\xb6i]\xb7\xd6\x1a\x81~\x91\xd3'G!-\xdf\xf1c\x91\xd5?\x9f\xa0\xcb\xee\xab\x8fS\xea\xf5\xdb\xd3\xa85\xf8\xf0\xb1\x8a;]\xc1\xd0\xc7B\xba\xb0\xdc\x02\x9c\x9d\x1e\xf5\xfa\xee\x0c\x17\x97\xac\xef\xbe!E\xb9\xf9XD\x1cj\xd5\xcbC2\xd6\xa8St\xfeB\xeb>\x8aBK\x17V\xf7\x13\x97\xf9\x15)\xe4\xd3\xbb\"\xff\xff\xd9{\xf7&9r\x1bA\xfc\x7f\x7f\n\x9c.b%\xd9\xdd%k\xd6\xf6\xddOw\xda\xd8\x1e=f\xda\xd6\xa3Wj\x8dc\xc31Wbe\xb1\xaa\xd2\xcaJ\xd6\xe4\xa3[\xed\xc7w\xff\x05\xc9dV>@\x12\xcc\xccj\x8fw\x13\x7f\xd8\x9a\xae$\x08\x82 \x08\x02 X(\xbb\x0dJV\x88\xfdc#\xde\xfc\xebA\xa4HeNG\xc2Kc\x9a\xecj\xc9\xe0m\x92\xa9*\x16J\xe2\x9e\xfe\xfa\xf8\xbb\xb2o\xa4\xa5\xa4,\xe4\x06\x86\x8c\xc5\x95\xc3O\xee\xdfK=\x8cB\xc8\xadGdk\xa9\xd2\x05pi 7\xc6Z3\xffa\xae\xc7\xddD\xf8\xb4b\xc5sx\xfa\xff\xea\xee\x8f\xb8\x9b\x9f*\x03\xb7\xf2\x915\xbb\x17\x1b\xcd\xbe\xa3m\xa7\xee1K\xcd[w-?z(?j\xd6\xf8\xe8\xeebu\xff\xcf\xe1wgP\xec\xca\xfc\x19<\x05\xd9J\x92\xf7\xeb\xff\xf7\xbb\xce4\xb1$fy\xf0\x1dnT\x94tuE\x83Q\x19}\x90\xc4\xb9\xa2\xbb\x12\"\xf3\x9b\x11\xfd\x86 \xf5\x17\xd2\xdf\xcc\xb4\x1f9\xd0\x98s&q\x96Q\xd1\x0d\xda1\x8d\xb4\xb9\x04\xe2To\xa7e\xc5\xc4j\xea\xe3H\xd7/\xea.\xb4\xb7\xbc`kf\xde/'\xad3Z\xd1HE\xccRR1\x8c\xdf\xe4<\xad\xd0\x0b\x88\xbe\xf0\xef(\xbd\xd0\xc3\xd6\x16@\x0d}m\xa1\x01\xd7\x19\x1ap\xcd\xa1\xc17\xa2\xf1ZD\xc3H]\x82s\xba\xdfM\x80\x86\xd10R\xcf\xf4\xf0i\xbdc\xc9\xa5\x08\xd59\x1az\x9aG\x03\xb6\x1e48K\xc1\xa3r=\x81F\xd2\x80\xeb%\x0d#\xb4\x93AN\xd3Q\xad15tIwa\x9a\x116\xf7,]\x93Y\x0f.\x12\xb1!@JF\x88\x81\xd0ZI\xaa\xeey\xa7o\xf57-j\x8f\x8e~ \xf9\xcb\x91MJ*\x8d\xcc4\xf0=\x87_\xd7\"\xb2\x8e\xf3C\xc2|W\xc5\xed\xd3R\xb5\x878]\xcb\x13}e\x92\xe7\xe5v\xcb\xf3\x82\xaf+\x12\xd5\xe4\xd4d\xf6\x9bW\xa5\xaa\x93X\x8e\x0f9\xb7\xd4]\x9a-\x83 \x02U\x0b\xe6\xda\x81\x02\x1d\xf69O\xd7K\x9e\xca\xf3\xf3\xcf\xea\x91\x8e\x1eI\xcd\xef\xbb5\xc75\xd4\xe7\xd4\xde\xaf.\x8d\xfe\x91\xa7\xebW\xba3\xed\xd1\x92\"\x0e\xb52f-\x0eU\x85\x0d\xe1\xd1\xed\x8e\xab\x13<\xeb\x0f\x11\xe2\xbc\xad\xe6$\x02\xd9\xfa(\xa0:T\xbdt\xf1\xbe;\x08lp\x03\xc2\x00RJ:a\x00#8\xfa\xfc\x9c$\xdf\xea\xf23\xe1\x87\xdc\xaan\xcd\xcf\xca> \xaa\x81\xe0\xd2\xd4/\xb4Th\xe62\xbd\xf4\xcc\x1e\xd9R\xc2,]\xab,3\xd5q\xc7e\xf9\xee\xfd\xf5\xabg\xca\xd9\xad\x7f\xae\x02\xda\xb1\xcaK\xbbL\x8b*\x1cY{rZ1I}\xb2kK\x96y\x00I\xea\xf1\x9f\xca8\xd39\x12[\xb1\x15\xca\xc5r\xd4\xfc\xed\x1a=\xd5D\x99\xa3e\xfd\xdfb\xa3]\xdb\xca3\x1d\xa7\xb5\xc7\xe8\xc0\xb6\xd5\xf0\x9e\xe1\x18\x8f\x1ft\x04\xb0\xfes\xe5\xf06\xa7\xd8A\x8e\x0c\xf5\x0em\xab\x08\x08P\x0e\xdb=\xbfU\xb5\x0d\xfe\xadk\xda\x19\xfc\x86/\xf2\x9f\x95K\x94\xe5\xb9\xf6\xe5^\xb1-\xff\xc0\x7f*y^,\xf4\xef\x1d$?\xc9e\xa4\x9aKt\x92\x05\x1c\xf6\"/\x80+G\xa4\xf2Y6\xa5\xbf\xff\x9e\x97w@=\xb7D=\xa4\x9e\xb5\xaa\xd0\xab\xf1\xa8\x7f\xe8G:\xe4<\x1b7t\xc3{\xda\xb5\xdc\x9aC\xd5o|($]\x1b\xee\x96\xe5\x90\xf3\xe2\x0c\xa49Q\xf9\xd0s(S-\x08k\xed\xea\xbc\x8d\xab\xb2\x0b.\xdf]_\xf7P\x9c\x1f\x8df\x15\xb6\x0fW/\x0c\x91\xb8;D5\xac\x1a\x0dUs]-G\x92`DyYf\x9b\\\xf8\xd1\xae\xb4&PY\xd3*,\x9a\xbarHHg\xca(\xd2Q5\xb1zw[\"\xa1\xecLc\x8f\x05\x0b\xc6\xbeu\xf6G\x1b\xe1\x0d\xbb\xa3\xf6O\xba\xc5\x1f\x00\x8e3\x90\xe3e\xdc\xde\xde\x0b\x8e\xfd\x17l{0\xb8\xcfS@8Y\xc3\x08\x7f\x01\x8a\x0c\xf1-\x1e\xc1\xe67\x00p\xfb\x0e\xc0\xe3?\x00\xe2H\xa7\xf2#\xc00_\x02\x8a\xc7\xe9\xab\x0b\xc0\xfc\x16\xce\xcd\x1e\xdd\x8c\x9d[~\xb3\xf5\x93Vs\xa2I\xa8\xda\xe4\xa3\x0d\x80\x93\x9f\x80-\xa6\x82S\x92,\xe6\x82K\x99\xfd\xbc\xde\xcf\xa4l\xa9\x13\x9b\x0f\x1e\x03\xc2mB\xf8\x8d\x08\xbf\x19A\x1d\xf5\x94\xa6\xc4t\xc6\x04\xd9\x9c\x18hP\x0c1)|\x84\x92\x8c\x8a1f\x85\xd3\xb0\xf0\x99\x16N\xe3\x82\xb0\x86&50|\xfb\x13Led\x0c13N`h`\xa6\x86\x93\xe7\xbe\xb5;\xa1\xc1\xe109,F\x07\x9drdb'0=|\xc6\x87\x9b\x88a\x06\x08j\x82\xf4\xbaj\xcd\x94\xd9\xd3\x8f\xb7q\x95\x87CQ\x0bq\xaa\x15\xb8\x94J%8\x95\xf34\xe3\xdb8/x\xd6.\xf4\xa7\xde;\x9a]\xaa\xb3K\xf5\xfe\\\xaa\xb8A\x1bhD\xe7\x81V\xf4D9\x92\x01R\x8c\x07\xd2\xc0\xb1\x9d\xfe\xe3\xbda\x96\x00\xe7\xb1\x1d\x1e\xe4\x04g\xa0\x13\x08\xbb\xce\x94\x01O\xa8-\xeen\xd0\x13\xb0\xc0\xa7\xfe\xdc\x15\xfc\x04\xe7\xf0m\x03\x1f\x1f\x08u\xae\xa2NBf\x13s\x7f )e%\x0d\xa9\xafOd\x1fM\xe1V\x14\xa0KF\xd7\xa1\x7f\xbf ^4\xf8\xdb\xa3\xa4E\x83\x88\xadE`\xe7X\x04\"\x14\xdd)\xa3\x04#L\x1bZ4\xe2Zn\x0d\xbaI\xb0\\\xe4\x8d\x87\x0d\xc0\xa2\x07\xc7\xfb!\xe6H\xbc\x01\x9a8\xc1\xd1\xac\xd0\x13d\x84\xa6\xfa\xaf\xfaJd\x9cj\xb3\xb5k\x83\xd8\xe4\x82\"|\x8df\x15\xb6\xdev\xde\x91\xc2\xc6NA\x16\xbc\x8eP \xf3;U\xc2K-\x16#7\xb4\xe3\x06\xa6\xd1\xb5v-\xcd\x8e\x9c/\x94Z\xd7\xf9U\xb5 Gf\x8a\xff\xe1\x12\xd4\xb0\xb6\xaf\x82\xca\xa2f\x95q\x98\xf1\xa2\xccR}\x90\xd2\xf4UG\x82\xda\xfcV6\xf7\xb6u\x9c\xad7*\xb7a\xbd\x80\xf7\xa9\x14\xcdT\xb9\xce\xf4\x835 2IB\x03\xd9\xf1\xa8\x9a\xf3\xc2\x08;\xe1u\x1b\xab\x05n\x1f{E\x82\x1a~Z\xeey\x16G\xe6o\xea\xe0\x17\xb1T\xd2\xa1/F\xedxj\x98U\xa6\xb5a\xde\xb4G.\x15\xaa\x84\xe7\xf9q\xd4\xfabV\x99K\xee|\xe1.\x16T\x03o\xe0k\xb3`\xf0\x0dv\x97\x1d\xa7\x90\x9a%o;\x85\xe8SVS2*\x05Q&-\xe5\xae+Q\x1d\xffp\xb9\x81\x84o\x8a\xea\xfa\x99\xf26$I]]E\xad'-t\xba\x03\xc9\x8a\xd5\x1dp\x16\xed\x80\x1d\x0ef\xdc\x8d\xc3\xcd\x90\x85\x0e\xce\xf17\x90K.\xa8\x99\x17Pd%\x07\xed\xa6\xd4N\x89\xfa:n5j\xf5ao\xbe\xe24J\xcau\xeb^\x1d\x83\xd6\x0d\xf5.\x87\xd5\xbe\xd98\xe5I5\xdb>\x96\x7f\xba\xcc[<\xed\x10\xac\n\xc7HU\xcd\xa3\xc2\x08\xe9Q\xaa\xa5\xe0.*\xb1\x8c\xb7\xa9\xc8\xaaO\xda\xcb\xbf\x89^\xf3\x00\xb1X\xeauc.\xe6~\x14{\xa3\xbc\xfa\xa5&^\x0b\x01\xb9\xd8\xf3em\xac\xa2\xe5L\x1a\n\xb09\xecfE\x13]A\xa8\xeb\x13h6\x8c\x8d\x80\xd6\xd5:\xe2\x14\xb6\x1f\xae^\xa8\xedS~Q\x91\xac-\xf6zeV\xa8\x8e\xfd.\xe0\xd5\xd7g\x0eE\x1dh7\xf5\xfd!tu\x8d\xf9@F\xfb?\x02|\x1f\xe8j\xa3\xe9\x1a\x8c\xf4 ?\x87\xd5\xb3q\xc47\xc2\xa9\xd1\x11\xa1\x86\xcdc\x93\xa1\xea\x93Z\x88nw<\xe3\x0d\xf7F\xbb\xeaDG\xe6T5\x1a\xb5\x7f4GU\xaf\xb8\xf6b\xaaz\xea\xad\xa6\x8c\x1f\xb8\xaa\xa4\xf7-\xcbj\x96\xd9\xd7S\x85F\xcdow)\xd5\xb2}\xf3t!\xad_\xb24\xfb\x8d1\xfc\xfc\xd8\xf8\x04\x9f\x87\x916\xf8t\xd67\xc5\xee\xae\xd9'\xf2\"c\x91H%\x1f\xbf\xe3\xc5\xb7\x89\x88\xbe|{\xf7=\xcbw\xc1zB\xbd\xb2\xb7\x8c{V,\xe9\xe4\xbdc\xf9\x8ep\x9a\x06\xbb\xc3\xf5\xc0\xb2b\x99\xf3b\xb9\xe3l\x8d\xbfY\x8f\xb8\xb1\xecN,\xc4e\n5&[\x00\xd3\x15\xbc\xec\x0f\x11\\\xc3\x04\x82o\xf9\x8aeE\xce\x8b\xef\xd5\x88\x7f\xd1\xf9Q\xcd\xe5\xe5\xcb\xe6\xec\x0c\x9b\x9ai\xf8Y\x95C@8\xa0\xc9\xd5A\x08E\xa6\n\"X85(\xc6\xde\x19|\x13\x9c\xfc\x07\xb7;\\\x03;\x1cN\x83\xda\xe7\xb5\x94:'\xcdy\x9a\x979D\xec\xa0\x97\xbc>,\x9b?geR\x99\x0b\x87LD<\xcfu\xf5/\xc5\x0f\x04_e\x11\xab\x9f\xa3\x1d\x8b\xd33,\xd8\xab\xcdC\x1d\x18M\x1a\x1f\x83r\x88\xeb\x80\x93\xa2\xc5T\x0c\xd4TX\x8a\xcc+\x06\x9a:!\x0f\x11\x97\xa9zAT\x9a\xae\x19Ks]zl\xcf\xa2]\x9c\xf2nxSQ\xd1\xd2@\x06\x1cS\x81\xbfON\\\x98\xd8\xc4a\xaf\x97\x13\xd1\xadY\xc1\xcfe\xfb\xce\x17\xaaH^_\xbf\x1a\x18\xb12p\xa5\x04>\x82\xc1\xa5\x9c48\xf5\xb1\x01'\xe5\xe0\xa5\x1e\xecz\xba\xfe\xd9\xa9\xaf\x0d\xf8\x93N\\\xac\x02\n\xbb\xc0\xcf2\x8f^\xef|\xd4\xd6\xef\x06\x94\xa8\xa8\xb7\x90\x8b\xe5\x94;\x0e\x1c;\x96h\xf5z\xd6\xdaZ.\xfb\xce\xb7\xf2O\x13w_\xbf\xa7\x9eO\x8c\xb8;\xaeM\xa6\xe2\xf4\\\xea%\x10eq(\x8b\xe3\xdf\x0e\x19\xbfA\xd5\xa7:\xd5\x9c\x8c\xc6Z\xa3O\x8c\x97\x1d\x0e\x13cT\xf2W\xd9\xf6\x13\xa3\xe67\xf1\x9a\xa7\x11\x9f\x18m=\xff\xc7m\x13\xb1?\xa4\"\x129G\x1e\x80\xaf\xb1\x0c\xea\xbf\xb5\xc9\xeb\x05\xdf\x8a\xa6\xd5\xdb\xa9\xba\x89\x06\xd7<]\xf3l\x1f\xa7E\xb5\xf8\xb4vmE\x13[\xf7-`\x98\xb5V|\xb5\x8e\x10O\xc4\xb2&ay\x14\xa3sb\xfc\x16\xd0\xf5\xd7\\\xfb\xb4L\xa9SeL\xe8\x13\x8f6\x1b\xfe]3j\xf1\xbd\xda\xe7\x7f\xf5\x14\xa9\xb2mN_\xaa0^\x92\xc8\xc1\x83:\x1c\xb3\x8ck\xbd\xb3\x00\xf8#\x7f\x98q\xf8s\x99\x17\xc0\xb6\x19\xe7\xd2\xfe\xb1>p\xa1s\x02U1Y\xb4?U\xccp\xcfYZQ\xafI\xbc8\x1c\xe4\xc9\x0b\xd6\x82\xeb\x82[\x95#Nv\x92sI\x16\x9a7\xfeR\x9a]\xad\x9a\xbf\xca\x19\xbb\xd1\x16\x13\xab\xaa\xdaW\xb8\xd6-#\xaf\x81\xce\xac\xae\xd1\xa2\x83#\x82q\xf2c5\x11|\x06\xc2\xba\xd4\xc6%_\xde\x88\x82/\xed\xc4i\xf0\x1a$\xfe\x1e%\xa8\xbe\x98\xfdwRG@\xec\x0c\x0c:\xe7\x17\xde\x95\xd8\x04\x9e\x96\x96\x9c\xe4&\x9c\xc3\xc7\xcb\xef\xde\xbdz\xb9|\xfb\xf1\xbb\xe5\xf5\x7f^\xbdZ~z\xf7\x87w\xef\xff\xf8n@\xcb\xab\x0f\xaf~x\x7f\xfdjX\xcb\x17\xef\xdf\xbe\xbd\xbc\x1e\xd4\xf6\xfd\xd5\xfb\x8f\x17o\xb6\xc6\x87\xf4\x81\xfa\xdc-m\xa8\x0fuv\xd3\xbf\x0d\x03(\xf1\xb2\xfaHD\x9c\xae\xf9W\x1a 49\xa4\xeb\xa7:\xb2@\xeb~J\x0e\x84l\xa1r\x97j'\xc1\xcbS\xbb(\xf8YU2x\x1f\xeb\x12\xc6\xfa\x9f\xcaXs\"T\xa7\xff\xe3\xd9^\xd2\xec\xdeG\x1b\xfb\xad\xed\x13e!\xaef\x0b\x91\xder\xb6\x10\x8f0[\x88\xb3\x85\xe8\x02\xa2\xee\x80\x00\xfd\x01\x01\x86G\x00\xdb\x81\xbe\x07h\x98-D\x02P'\n\xc2'\x0bB'l\xb6\x10{0\x80\x12/\xabg\x0b\x91\xbe\x85\xfeSX\x88J\xad,oD\x11\xa7\xdb\xa5\xba\xb9\xee\xb7\x16\xbd\x0c\xa5\xa9\x92\xa3,\xddo\xbf\xa4\xa5\x1c\xd8\xa3o S\xe5\xe6\xa5q$K\xe1yU\xb9\x91\x8fnw\xe3X\xd6a\x9a\x9a\x81Vt\x95\x99V\xdc\n\x89c\x93\xc4\x91\x9cg%i\x16\x99H\xa4\xc1\xb3\xd4\xd7l\x97\xac(X\xf4\xe5\xbe\xdc\xd9\x0d\n\x97\x8e\\\x1a\x0d\x84>\x81\xd8/\xd4\x8c\"\xee\xf6\xc4\xbe!\xa0\x7f\xb0\xa4@\xe1\x10@\x00\x04\x12\x01\xae$*\x1c\xa8\xa9U8\x04\x8e\x05\x06\x8c\x07\xdc\xc9Y8\x10\x15@\x17\x8cB\xb0&r\xe1`M\xef\xc2\xe1>\x89\xa3\xaa\xae.\xd0\xd2\xc6\xc8\xe8\xf0\xf42\xea\xc9\xd3\x80'\xe9\x0c\x07j*\x1a\x19!\x96\xb2\xe6OP\xc3\x81\x9a\xb6\x86\x83=\x99\x0d\x87`\xc1\xa3\x9d\xa0\x0d\x04\xa3\xa7\xee\xf9M\xc0S\xe7p\x18A\x90\xcf$h\x83'\xf9\x0e\x87{\xd2\x9d!\xe7<\x18\xc64\xa0\x9b\xe0m\x18pP70\x80{0\x90\x83\x10z\x807\x10r\x80\xeaB\xf8\xca0\x10:\xe10|\xd2a\xe8\xc4\x0f:\xf0\x1b\x088\xf8\x1b\xf0\xa7<\xe20\x80/\x03\xf8AO\x9a\xc4\xc1\x91J\x89\xc3}\x0c\xcb\x9b\xe8\x88\xc3}\x90f\xafRc\x07j\xe6'\x19\xa1-\xc1\xbe\x0f\xb4\xbcQ\x1c\xee\x83\x9d\xbe\xccS\x1c\xee\x832{\xee*\x0e\xf7A\x13!\xfb\x15\x87\xfb \xce\x93?\x8b\xc3}\x10F\xcb\xc0\xc5\xc1\x9f\x97\x8b\xc3\xe9\xc75\xe4t\x16\x92\x00LBhK\x12\xc6Ao\xa2\x14\x16\x06Zh\xa1\x96\xd9\xcf\xf0lB\x8a\xfa\x19\x18b\x1c\xd2\xbd\xec\x06\xe6CI\xc0r\xd40\x1fJ\xac\x10\xbe$\x0c\x84N8\x0c\x9ft\x18:\xf1\xf7}(9\xde\xc2\xa6rFs\xc4^\xe6\xb6\x0f\xce\xc2\xb7}\x18$\xc0\xc3\xc4\xd7h\xa6\xe5&a\xdb\x90\x86#\x04\x83\x96\x91\xd4\x86s\xf8\xf6\xcd\xfb\x17\x7fX^\xbe\\\xbe~s\xf1\x1d1[\xa7\x0b],\x17\xdf~|\xf5\xce\x9fl\xd4\x86.\x12b\xc6R\x1b\xbaH\xde]\xfa\x12\x97\xdaP\xa71\x8dgK\xf8)L\x83^d\xeb\xd7 \xdb6j\xe9\xea\xea\x07\xdf&\x91\xf8r\xf92\xc8\xaf\xac\xa1^\x8e\x10\xeb\xe8\xac\xaf\xc1\x11\x82\xa3\xfbm\x18,\xcf\x83\xd5\x1c!\x86\xda\x87\xd1d\x869U5\x90\xd3\x05\xda0\x9a\xd6 \x96\x0e\xb1\xe35\xbcP\xe6\xf4\xc7x\xab3\xf4\xa4\xedaB\n*\x03\xc1\\\xc9\n@\x19\xa7\xc0*\xbc~s~\x18\xed\x1a{\xfbBY\x1d\xddV\xb7\xd5\xec\x05\x04\xfap\xcb\xf2\xeaXQ\xe8[y\xcc\xdcN;:=\xdc#9\xae\xbfV\xe54\x1c\x02\xf6\xb8\x90\x9d\xedH\xab\xff\xdb\xd0\x9d<`\x17\x0f\x18\x9d\x86\x901j\x08\xd6q\x83\x16\xe3\x80\x85x(W\xfd\xaa\xdc.\x08f\x16\x0cb\x98\x04\xbe\xfe\xe6\xb7\xbf}\xfa\xff\x854\x19\xc88\x18\xc6\x01-a\xaa\x9aH\x00\xb1k\x8aO/\xb0G\x9f\xbf\x8e\xea:z#\xb7\x8b\x17\xeaV\xc2\x85\xba\x94\xe0\xbb\x1b\xa1\xdd?V|\x8d[4\xac(\xf8\xfe\xa0\xeeE\x14\x02\xf6q\x9ep\xb6V\xcf\xf3mwE\xf5\xe0X\xd3w\xd4H\x04k3\xca\xaa\xee\xec\xaam\xf2\xb2\x90\x96\xf8\xb1\xc6G\xa8'\xdb\x8b \xcf\xf5 Q\x98\xebA\xb6\xc0\x15\x87t\xd9R\xa7\xaa\xc7E\x8a\x0c\x12\x98\xe7\x8e\xf6\x85\xc6\xf5\x02#x\x81\xb1:zTnP\xfc\xad5\xff\xde\xc0\x19-\x14F\x0ez\x11\xa6\x8a \xe5\x9e\xed-\xa0\x13\xf7\xb6\xe6\x0d8\x05\xf4d\x19Nk\xdf\xa4F\x80\xecq\x1d\xf76L\x8e\xd5X\xe20\x1dtHT\x06\xef\x1f/\x15Oyr\xa9\xdd\xb2B\xf7\xe1\xeaE\xef\xd5/{qz\xb53\xcf\xe5\xe9\xe7\xf2\xf4\n&\xe2\xe7\\\x9e\xbe\x07\x1e\xd4\xfe\x03\x02\xed\x9e!\xcc\xe5\xe9\x1dS1\xf99d.O\xaf`>\x8e\xf4\x81`\xa8\x8d=\x8e\xf8\xefj\x91$\x11\xa5\x90~\xd3j.O?-\x8d\xbeKBC\xf1\xce\xe5\xe9\x01h\x97c\xfc\xd7`\x86\xf5?\x97\xa7wL\x8c\xdf\x02\x9a\xcb\xd3\xcf\xe5\xe9\x9d\x06\xc2\\\x9e\xbe\xfd\x8d\xcfD\xd1@K\xf5\x9f\x8b\x8f\xd2\xc6\xebWcm\x98\x8b\x8f\xfas$ L\xa0)\x06\xbe\x06\xd25D\xda\xa9B\x83+\xc4\xd4\x06\xeauC\xa2\xee\x80\x00\xfd\x01\xde\x03\xce\x11\x02\xd8\x0e\xbe\x1d\xbe\x0b\xa4Sc\x1b\x02\xb8\x01\x81\x1c\x91\x10tM0D.\x0c\xd0E\xd3\x00u\xa2 |\xb2 t\xc2\x88gV\xb4 \xe5\xba\x9f7tQ\x7fH\x1f\xa8\xcf\xdd\xd2\x06r\xa4\xc6\xc0\x00J\xbc\xac\x9e\x8b\x8f\xd2\xb7\xd0\x7f\x8a\xe2\xa3sy\xfa\xd0\x96\xb3\x85x\x84\xd9B\x9c-D\x17\x10u\x07\x04\xe8\x0f\x080<\x02\xd8\x0e\xf4=@\xc3l!\x12\x80:Q\x10>Y\x10:a\xb3\x85\xd8\x83\x01\x94xY=[\x88\xf4-\xf4\x9f\xc2B\xfc\x07\xa6C\xcf\xe5\xe9\xfb0\x97\xa7\x9f\xcb\xd3\xfb\xbe\x0b\"\x00\x02\x89\x80\xb9<\xbd\x06\xa2\x02\xe8\x82Q\x08A\x15\xe0\xe7\xf2\xf4~\x98\xcb\xd3\xe3@M[\xc3a.O\xef\x86\x11\x04\xf9L\x826\xcc\xe5\xe9\xa9&x\x1b\x06\x1c\xd4\x0d\x0c\xe0\x1e\x0c\xe4 \x84\x1e\xe0\x0d\x84\x1c\xa0\xba\x10\xbe2\x0c\x84N8\x0c\x9ft\x18:\xf1\x83\x0e\xfc\x06\x02\x0e\xfe\x06\xfc)\x8f8\x0c\xe0\xcb\x00~\xd0\x93&q\x98\xcb\xd3\x87\x91\x16v\x0d\\\x035\xf3\x93\x8c\x90^\xbe\x8d\x967\x8a\xc3}\xb0\xd3\x97y\x8a\xc3}P6\x97\xa7\x0f$n.O\xdf\x80\xd3\x8fk\xc8\xe9,$\x01\x98\x84p.O\x8fC\xb8\x05F\x8a\xfa\x19\x18b\x1c\xd2\xbd\xec\x06\xe6CI\xc0r\xd40\x1fJ\xac\x10\xbe$\x0c\x84N8\x0c\x9ft\x18:\xf1\xf7}(\x99\xcb\xd3{\x8bP\xe00X0h\x19Im\x08-c\x81C`q\x0b\x1c\x02K^\xe0@/\x84\x81\xc3\xa0\xf2\x188\x84\x9f\xc24\x10\xabl\x04b%\xd5\xe4\xc0!8\xba\xdf\x86\xc1\xf2:^\x86<\xb0\x8c\xed]R\x1a\xe4l\xb6\x94@\x19qn\xd8\xb3\xafK9\x83\xce]\x8e\xe0\xcc\xb5;@+f=|'\n\xfe\x0c\xf6e^H-\xb1\xcd\xb8T!P\xecX\n\xbf~h\xa1l\xcb\xfeQt\x89\x0c\xf8O%K\xa4r>\x7f\xda\xa7\xaf\xa5\xf7\x95r\xbd\x923\x9d\x1f],I\xbc\x8f\x8b\xbcz\xfa\xa1r\xae\xe4\xf1_zU=|\xcf \x0c\x9eV\xb6\xe5\xcb\xb4\xdck5{:>\xfav@\x0do\xd9W`[\x15\xd91\x03>\x838\xd5|\xc9\x17\xbf\xb0UK\xb9\x96\xbcSe\x89$%e\xc2\x94V\x88X\x12\x95 \xd3\x11\x9f]\x9cC\x9c?\x93]\\l\xf9\xcb2S\x9b\xa4\x05\xdf\x13\xf8+\xbb\xe1\x99$E\xe7&[\xbe+\xe2=\xff;\x96ol8\xbb\xae\xfa\x19\xc8\xd7q\\\x93\xd4\xd9yvY@\xbe\x13e\xb2\x86Hd\xda\xc3\xb6\xae\x8fa\xecpx\x98\xc3\x832]\x89T\x15\xc49\xf0,\x16\xeb\x07`M\x00\x12\xc5\x8eg\x90\xc7\xfb8a\xd6ju{\x1e\xedX\x1a\xe7{5?;\x96\xae\x13\x89\xfcO\xefD\xb1\x8b\xd3\xed\xf9Eq\xfe\xb1`_\xb8\xad\xbd\xaeS\x96\xff\xf8hW\x14\x87\xfc\xd9\x93'\xdb\xb8\xd8\x95\xabE$\xf6O\xb8$\x80\x97\xfb'\xb7\xf1\x97X\xff\xcfU&\xc4\xe6\\l4\xd2\xf3\xd7\x17\xff\xf1?ow\xac8\x8f\xf3\xf3b\xc7\xcf\xd3\xaaWV\x9c\xe7\xea\x83C&V \xdf\x9f\xb3t}\xbe\x13\xb7\xe7\x11K\xcf\xe3\xe2|\xc5\xcf7\xf1W\xbe~l\x9b\xe9{Q\x8d\xd6\xe9W\xaf\xbf\xe4\xbc\xd0\xbb\xe3\x9e}\x8d\xf7\xe5^)\x11\xe5\x1c\x16\x05K\x8e^\\\xb9\x98$\xb5\xca\x9dkA\x18\xb1T*\xb9\xa3\x7fW\xb9\x93+\xc3X\xbf-c\x9d\xa0tm\xa4j\xc3\x92D\xe2\xd8\x88\xac`\xab\xe4\x0e\xcat\xcd3Cc\xa5\xea\x14-Vl/u\xfcB\x1a\xe6O\x7f\xfd\x9b\xff\xfd\xdb\xff\xf5;\xa9q\x9f\xbe\xfd\xd6\xadh-\xfe\x01\xcd\x81J\x01\xafy\xa1\xee=s\xd8\x89[\xb8\xe5Z\x18y3\xb8\x8cNv\xb2\xe1,gi\xd4S\xd0\xb5\xb19\xa9\x86\xae\xec\xc7\xa5Dq:\xd7\x9bE<\xfdL\xadm\x9b\x8a\xab\x19\x97\xa8\xa2B\x97\xb8P\xd6\x9b4\xd7T7y3\x16\x1f\xa1\xe7\xb62\xe7\x8e\xf7\x94\xca\x9c\xe7p\xf1\xed\x8bK\x89YbM\xd9>N\xb7g\xeam\xa3\x8b}\x9c\n\xf9\x97~\xbdC\xfbS\xa1\xc3\xe7\x85\x1d\x0eKg\xf5<\xf2\xba\xa7\xbc\xd6\xf9\x83\xee\xa9k;H&+~4O\x8c\x15U\xe8\xd3N\x7f\xeb\x07|*\x0b\xb4\x8bZ\xaf\xdd\xea\xc7\xf3\x8c'\xfc\x86\xa5\x05(;U\xae\x9c\xae\x05\xad\x82C\x95\xde`\xeb?\x97y\x15\x16R\xe5OVQ,Il4\x99]C\xde\xf3\x9fO\x02av\x0d\xf5av\x0d\xfd7p\x0d\xb9c\xc8\x96hnx(\xb9\x83\x88\x18Q\x96\xe3\xcak\x04a\x81\xe4~\n\x16\xaa#p\xbd\xd0\xcf\x1f\xb2\xaeL\xcbj\x9c\x9f<\xef\xfc8?y^\x83\xa3\xaa\xaew\x03\xf0X:\xf3\x93\xe7\xc9\xfc\xe4y\xbb\xe1\xfc\xe49\xf8\xf4\xb1\x81 \xac\xc89\xc5\xb5\x05\xfe\xfa\x9f$ID)\xa4W\xef\x9c\x9f<\x9f\x96F_\xe1\xc9\xa1x\xe7'\xcf\x01h\x05\x17\x0f\xde\xd2\x8a\xc3\xfa\x9f\x9fY\x10:a\xc43+\xda\x84RB\xd6{\x1d\xae\xfe\x90>P\x9f\xbb\xa5\x0d\xe4\xdb\x7f\x06\x06P\xe2e\xf5\xfc\xa0%}\x0b\xfd\xa7x\xd0r~\xf2<\xb4\xe5l!\x1ea\xb6\x10g\x0b\xd1\x05D\xdd\x01\x01\xfa\x03\x02\x0c\x8f\x00\xb6\x03}\x0f\xd00[\x88\x04\xa0N\x14\x84O\x16\x84N\xd8l!\xf6`\x00%^V\xcf\x16\"}\x0b\xfd\xa7\xb0\x10\xff\x81%\xb6\xe6'\xcf\xfb0?y>?y\xee\xfb.\x88\x00\x08$\x02\xe6'\xcf5\x10\x15@\x17\x8cB\x08zU|~\xf2\xdc\x0f\xf3\x93\xe78P\xd3\xd6p\x98\x9f\xbd\xc0\x1e}\xfe:\xaa\xebh~\xf2\xfc\x08\xae\xd9\x9c\x9f<'D^\xbd\xfb\x92\x7f/\x9a\xebA\xb6`~\xf2\x9c\x12\xc0\n\x8c\xe0\x05\xc6\xea\xe8Q\xb9A\xf1\xb7\xd6\xfc{\x03g\xb4P\x189\xe8E\x98*\x82\x94\xcfO\x9e\xff\xd3=y\x8e\x94\x8awV\xa9?\xd6\xa7o\xb4\xac\xd0\x85\x14\xa7\xaf\x8d\xd7\x8f<\xfc\xb1s\xad}\x06?y\x8e\x1dQ1%:\xf6\xc5s\xcb\x9a\xb3\n\xa7\xe5\xdc\xe7P\xd5.5-\x9b-\xcb\x0c\xddD=\xeb\x83b4^\xc0\xa7\x0fo\x9ed<\x17e\x16q\xf5\xe8\x8d\x16\xd52\x8d\x7f*yr\x07R~\x8bx\x13W\xa7\x9e\xa2\xaalb\x8b\xfa\xe7<\x8bY\x12\xff\x85\xaf\xf1\xbbY\x87L\x14\"\x12 \xac\xca\xcd\x86g\xa64\xca\xa2zzJ\x8dE\xbf\x8dW\xad#`\x05$\x9c\xe5\x05\x8eO\xa4\x1c\x1e\xbcy\x98\xc3\x81\x15;\xd5\x01\x8a\xae\xbe\x87\x8e\xf7&\xd1l\xca$\xb9\x83\x9fJ\x96H\xae\xac5\xcf\xaa.\x14w\x1e\xb1\x1c\xe2\x14G\xf0Yv\xffd+\xc46\xe1\x0b\xc5\x8bU\xb9Y\x98'\xe4>?\xd6\xd4+\x94\xd5\xdbW+U6\x06\xbf\x9e\x10\xb1T\xa4q\xc4\x12\xb5@\xf0\x1e\x1f\xf1\xc5vq&Y\xa8\xae\xe6=X<\x90\x9aAUW\x8d\"~(\xd4[dx\xd3\xcb\x14\x0e\x92\xa9q\xc4\xcf\xa0\xe0l\x9fC\x99\x97L\x0e_\xdf\xcc?\xc4\x89\xa4\xae\x10\xba\x88i\x9c\xb2\xec\x0eX\x82=\x84\xad\xa5\xb5\xaa\xb0Z\xec\xf8\x1d\xde%\xffz\xe0Q\x01q!\x0f\x19enJ\xe6(a\xe0_\xd5T^\xa4w\x0b\xf8^\xdc\xf2\x1b\x9e\x9d)\x85\xf6\xe9\xc3\x1b\xfc\xf0\xac\xf7[\x89F\x8a+.\xaf\xd1\x8e\xef9|\xde\x15\xc5\xe1\xf3\x99\xfe\xff\xfc\xb3\xaa7\x90\x8a\xea\xd73%e\x11KA\x1c\xf4\x8b(\xc9\x1d\xa2\xb05\x94\x87\xaa\xfe\x8f\xa5?\x9e\xdd\xe8W(\x0b\xd8\xb3C\xaeEF\x8e@\x1d\xab\xaaBA\xca\xcf\x10\xebZ\xb1\x0c\x1f\xdbF\xa8w\\\x9eY\xe6\xee\x97p\xb99\x8e@N\xf9!\x13r3Z\xd7\x83T\xdb`\x9e\x97{\xbe\xb6\x14\x1a\xfa%\\\xa4\xf0\xfd\xf5\xf5\x15|\xf7\xea\xda<,\xf9\xe9\xc3\x1b\xbd@\xefb\x9e\xac-\x92\xf9\xa7\xae\x88_\xdf\x1d\xf8\x8f\x7f\xfa\x11\xfd\xb8z\x18H=(\xa7eH\xeb{5\x0b\x87L\xac\xcb\x88\xabGo\xb2LX\x12\xa7\x7f \x17\xc7{\xa1\xb9\xaa\x15\xac\xde\xb9\xe1k\xc9\xd6\x88ER'\x08\xf1\xa5<@u#\x00\xe4\xae\xb6\x06\xcb\xbb\x8d\xf6\xa4\xa6O\x1f\xde(\xbav\xecF\x89\xd5\xbe\xb1\x16\xd6z103\x0c\xf9\xef\x1b\x11\xaf\x81\xa56\x07\xa9&J-\xfb\x8coD\xc6\xcfLc\x89\x93\x15\xf1*N\xe2\xe2\x0eR\xce\xd7JDV\xea\xf6\x8b\x12#[\xae\x8aH\xa5:L\xb7\\5P\xebn\x01\x8f>\xe5\xdc\\Y\x97\\\x91b\xa7\xde8Sr\xc7R\xb6\xb5\x8dx\x95q\xf6E\xea\x8e\n\xe9\xe21.-\xfa]S\xf5:\xe6\xa6L#\xbdR$\xed\x95\xbe\x89\xca,\xe3i\x91\xdc5\xbcf\x8e{\xc9b\xb3\x89\xa3\x98%\x8e}dUn \xe3rw\xe0g\xea\xb6p\\\x98\xceJ9\xb9\xca\xda\xa9\xd7\x97z\x84>\xb5\xd9\x92\xea\xbd%\xab\xe2Zhyf\x878_Dbo\xd3\x98\x1f\xd5j\xcb\xab\x17,\xd5S\xb3\x1d\xcd\x02\x8f*\x0b\x8c\xef\x0f\xc5]\xb5<\x1f\xa3\xc8\xf6\xca\xb3\xb2\xb2(\x125@\xe5J\x8c\xf7\x87\x84\xcb\x8dN?\xc8\x94\x1fx\x14o\xe2\x08r\xbegi\x11GHJ\x8f\xf5!.\x8fI\x11bn[,\x8e\xb7\xd5\xbb\xb7U]\x8e\x86\xc1\xd0\xb3\x0d\xcc\x8d\xef\x95\xb8\xb1\x18\x1bz\xa8\x958\x87>\x87\xf5\xf9\"\xbd\xfb\xdcx\xa7.\x05\x96\xad\xe2\"\x93\x8b\xcfAU\xa5\xa3{\xe8X\"\xd2m\xf5\xeai\x7f\xca\xa4\xd6TJ_S\xb5\xea\x9bS\xcd>\x8dU\x84\x88\xd9\x95\x11\xfc$^)R+\xbd\x9eC^\x1e\x0e\"S;\xe7\x81E_\x9e\x94\xa9\xfc?\xb9_\xea\xf9VVI\x17\x9d\xb2hP\xe3Al\xa0,\xb4\xf21\xcb9\x97\x8a\xef\xf8.\x18ly\xca3\xf5Z\x99>0\xd4\x97\xf4/\x10}\xa7\xa7\xa8\xdf\xcf\xab\xafL\n0<}\x06W\x92^\xb9\x8e+\xd2Y\xb3r\xde\x8b_\xfd\xca\xb2M\xbd\x16\x026B\xc0sX,\x16\xff\x07\xfdD2\x81\xa5w\xf8\x8f,\xbd[\xc8\xae_gb\xffh#\xc4c\xfc\xb3\xc5\x02\xdf{\xe2\x0d<\x92(>)\xa2\xaf\xc5\xa3\x7f\x918\x1e\xc3_-\xfa\xd4\x86\xe7\xefv\xde|\xe3\xe1\xcd\xef\xd9\x0d\x1b\xcd\x1cx\xael+\x89}\x04\x17\xe2\xfc\xd1k!\x16Q\xc2\xf2\xdc\xc1\x04M\x92l\xa0\xc7\xd3h\x84\xf7\x8bp\xa7f\xcf\xbfz\xd8suW\xecDja\x90\xa6\xe4\xb5\x10\x8f\x16\x8b\x05\xae\x89k\xe6<\xb2\xfe\xae\x04H\xb1-\x94k\xb2\xf1\xa5f\xda\xcbW\x1f_|\xb8\xbc\xba~\xff\xe1\xb1\xcd'r\x144{g\xba;;\xbb~\xe3a\xd7w\xc8\x93~\n$\xab\x9e=\x87\x7f9\xac\x16\xaf\x85\xf8\xebb\xb1\xf8;\xfe!K\xef\xce\xa4\xb9&\xbf>h\x03\xe4-\xcb\xf2\x1dK$\x13\xed\x84\xdb\xd8\xd4\xed\xd9\xd2m\xbc\xe9t\xfa)\xdd\x1f\xbbUD)\xc1V_\xfd\x8f\xe7\x90\xc6\x89U@\xed\xb4 \x92(\x0fm\x8a\x8fF\x0f\x1ac\x1bVwGS\xc5hl\xfd<\xc6\x9dq0\xf6\xb0\x959\xb2\xe7?D\xcc\x90'\xf2,\xbaP?HS\xee!\xb0\xc6\xae\"w\x9c\xaa\x82J\xbf\x075\xeb\xfdNj5\x9e&w\xe6\xdc\xd4;\xf0\xd6\xa6#\xb0MQ=\xc3,\xcf\xdb}\x92\x9f<\xecwQ\x1d\xe8\x0c\x89\xfa\x04\xc7+\xc9|\xb0\x11b\xb1b\x99\x1a\xdc\xd7'w\x8b\xbf<\xd0\xdc\xd2g\x0d\xfcX\xa5Hy \xbf\x95\xdbK\xef\xe7\xdf\x7f|\xff\xae\xff\xd7\xe7\xcf\x9f?\xc7\xe7Q~\x7f\xf4\x03h\x9bJ\xc8eZ\x19\x0c\xfa\xac\xa2^\x10\xd6\xfe\xb5m\x89>S\xdeG!?_\xf3\xe36\x7f\x06|\xbf\xe2\xeb\xf5q\xc3?3\xaf\xa6\xf7\xd15\xb6\xdd\x8db\xc6\xe7\x7f\x97\xec\xf8\\\x1dr[^G\xc3\xdc\x85Y\xf2\xcf,F4\x8b\xbe\xc85\x7f<\xacm\xe2\x84\xe3\xfa\xd7\xe8\x87+\x9e\xe5\"\xb5.\x9b\xca\x83\xa3^[Y\xaa\x99y\x0eOq\x8c\xf5\xc7*TX}\xfb\x0d]\xfb\x03X\xa9x\xa0x\xf3\xe0\x19<\xc0VM{\xb8\x0b=\xa2\x07g6\\j,\xef\xd8^\xe2\xfb\xbf\x9a\xe4\x7f\xb3~,\xc7\xd2\xf9\x96:\xa0\xcbMu0h\xcb\x84\x9e\xcd8\x87[\x9e$\xe7_Rq\x9b\xaau\xbdc90\x88\xca\xbc\x10{\x8b\x90\xb7E\xf0L\x1b\xa0\x1d\xb94o\xf5\xd4\xddJAK\xb7\xc8\xb9^\x89]\xbf\x93\xcfjA\x189\xdc\x89d]U\xb0:R\xa6\x1a\x188BBF^[\xb3g<\xbbw\xd0\x81\xa1\xa1c\x18\x08\xe3\xef/\xfc}\x8f\x0b\x04\xe9\xc0O\x03]?\x044A\xf0g\\\xd8\xa7#\xe5\xdd\xcdpd\xa8\xa7bt\x13\xe3\x98\xa0\x8e3ba \xe4xC8}o.=l\xd3o\xfbwl\xac\x83\x824\x94\xc1\xfa\x023\xf6\xb1y\x831\x01a\x98\xb6\xc7jd\xe8\xc5\x19t\xb1\x87[\\\x81\x16\x94\x0b\xd4\xe0\x8a/\xac\xd2\x0d\xa8\x8c\x08\xa5\x10\x82(\xe1\xe1\x13$X\xe1\x0b\x99L\x14,AznI\xca\xa8\xd0H7\x142&\x08\x82\x04=F\x85;\xba\xe1\x8d)\x03\x1b\xd6\x90F\xd7\xcf\xdb\x0dcL\x13\xc0\x98,t1m\xd0\x82\x16\xae\xf0\x06*\x88!\nJp\xa2\xe7\xc5\xef\xf7Fu3\xbbC\x11\xc4 \x04!\xfc\xd0\"y\xca\x90\xc3\xa8`C?\xb80]Xa\xba\x80\xc2\xf0\xd9\xf5\x06\x11|\xe1\x03\xa3\xbe\xf1\x90\x01j\x89c\x0e}G\x80\x80\x88cL8\x00w\x0b\x1e=\x87d\xc7`\xfbf\x14By\xff\xfa\x14\xf2\x11\xc5\x93\x8a]\x97B>\xc3\xaeIa\xd8\x90\xebQVl\xedkQ\xc5 \xae6`W\xa0\xac\x87:\xef\xd5'\xcb\xb5'2B\xec\xba\x13r\xd5\xc9\x8f\x0f\xb9\xe2\x14\xe2\xbc\x06\xd7\xd5\xa6^\xefS^i\xaa\x97\x05[E\xf1BU\xd2\xbdb\x193sLX\x18{\xf6u)O\xddn1\xb4\x05\xfb*.=\xd4\xae\x94}u\x1c\xdff\x9c\x15\xc6\xf7\xf0\xeb\x87\x8d\x9e\xb6\xec\x14\xfdH\xb3I\x9a_R\xa5\x9f?}\xd8\xe7r\x831G\x13\"\x89\xf7q\x91\x1b\x9f\x9e.\x8e\x9c\xc7\x7fA\xf8\xfaB\xb2=\xcd\xcb<\x90\xb7\x9d\x8b\xc7\xe8Z\xc3W\x1a2+@\xf1\x9fXCu\xa4\x19\x02l\x96\xe0\x14\xfdb3\x06\xa3gM\x82)z=\x98\xedl\xcb\x97i\xb9_*\xd4\xe3\xf9\xe0q`\xb1\xaf \xad\n\xb1\xa9 ?S\xeea\xd5y\xdf\xb7'\xad\xf5\x15\xcb\xe3H\xf5X&L)\x8a\x88%Q\x990\xfd>\xc6.\xce!\xce\x9fI\xd4\x17[n\x0c\x08x\xd2\xc1\xf4Wv\xc33\xd9\xb5~\xc1\xb5\xf3k\x11\xef\xf9\xdf\x17\x08g\xd6\x15>\"_\x86\x8d^\xf6\x8e\xc4Q\n\x13\xba\x89D\xa6c\xb3ks\x84\x90\xdb\xf7\xc3\x1c\x1e\x94\xe9J\xa4\xca@<\xf0,\x16\xeb\x07R\xd2\x94#\xb4\x83,\x8f\xf71\x92\x84\xb5\xe7\xd1\x8e\xa5q\xbeW|\xdd\xb1t\x9dHd\x7fz'\x8a]\x9cn\xcf/\x8a\xf3\x8f\x05\xfb\xd2s\x912\xf5\xe0I\xfe\xe3#\xe5`}\xf6\xe4\xc96.v\xe5J\xd9t\\v\xcf\xcb\xfd\x93\xdb\xf8K\xac\xff\xe7*\x13bs.6\x1a\xd9\xf9\xeb\x8b\xff\xf8\x9f\xb7;V\x9c\xc7\xf9y\xb1\xe3\xe7i\xd5\x1b+\xces\xf5\xc1!\x13\xab\x84\xef\xcfY\xba>\xdf\x89\xdb\xf3\x88\xa5\xe7qq\xbe\xe2\xe7\x9b\xf8\xab\n:5\x860\xb5\xea\xe8M\x9b\x8e\x1c\xf2BoW{\xf65\xde\x97{\xb5\x08\xd5\xc1O\x85\xfe\xeb\xda\xf3R\x98%5\xda\xba\x8fX\n\xab\xae\xfb\xfcX\x8d^\x15\xbf\xcf\xe3t\x9bTr\xd9s\x03\xc9CE%\x05\x1b\x96$\xb2\xedFd\x05[\xc9\xf3x\xba\xaeN\xdb{\xf6\xb5R\x0d\xaa\xef\x1e\x96\x97\x95\xb3 \xce\xe1\xe9\xaf\x7f\xf3\xbf\x7f\xfb\xbf~'\xe5\xe4\xe9\xdboqEd\x1e\xb2\xa9t\xd1\x9a\x17<\xdb\xc7)\x87\x9d\xb8\x85[\xae\xe5\x84\xb7^\xb7\xd9\xb3d\xc3Y\xce\xd2\xa8\xd6L7\xedh6\x84\xa9\xa6*j\xbd\x94M\xd0\xa9\x0d\xba\xfb\xde\x91\x83\xd6h[\x89*\xb5\xbd^\x8d=\xe3\xb2i\xa4B\x90\x92\xa6$\x8et\xe2\x8a\xba\xab\xd7x\xb2G\xcet\x99\xb7\xaeX\xbc{\x7f\xfd\xea\x99v#\\|\xfb\xe2R6\x97MS\xb6\x8f\xd3\xed\x99\x8a\x88\\\xec\xe3T\xe8\xd0N\xcd\xb6\x11\xc5\x13\xa4QO\xbfk\x0e\xf6\xa4\x17\xccf\xeb\xeeL\xca\xb7-\xc7\xd5(\xfd`\xa8\xd7\x83\xe9f\x02u\xec\x8aF@AIv\xf5\xe3y\xc6\x13~\xc3\xd2\x02\x0e\xf23)|&(\xdcXS\xc0\xd6\x7f.\xf3\xeaI\x07\x1d\xe9\x88bIJ\xcf\x9ayu\xc3\xd3\x82l\xc3\xa8O~\xe1\xe0\x1b+\x8a,^\x95\x88\x059\xed\xd1\xc3zC\x1a5\xec\xad\x01%\xf4\"\xd3\x10Dh \x11\x8d\xa8{'\xbf\x83\xa9\xf7kK\xba\x1e\xaa\xf9\xb90\\U\xc1i\xa3\x13\xbf\xf0\xbbs\xed\x8c;\xb08;\x03\x96\xe7\"\x8aU\x90\xc5l\x84\\\xb6^ 6p\xad\xc6\x15~\x1d;\xce[\xb2\xba\xe67<\x91\xccWaU\xb5\xa5\xed\x9a\x0e\xb98\xd5C\xd0\xce\x13\xa3S\xcd\xb1\xe4[\xbe\x8dSe\xb2\x9d\xd5\x7f{\x95\xae;\x7fy!OZ\xd7_\xa5\x1e\xef\xb4\x7f\xc9\x93\xf8\x86g\xd7_km\xfdF\x9a\x8agPd,\xcdY\x15c\xda\xb3;)\xec?\x95<\x8b\xf9\x1a\xca\\\xdb<<\xe7z\xe4y\xdfzo\xf3\x93,\xf8H\x8a\x90\xe5\xa8\xd2\x10\x8d\x8etQ\x9bud \x97\"oe\x87\xc9$\xa7\xcd\xbf\xfe\x04\x93y\xa8\xa7\xe4\xb4z\xa1\xad\xa0\x9a(\x90\xf5\x8c)\xabf\x13\xec ,\xcb\x03X\x1625\xb8\n4\xa0\xaaL\x83C\x0fi\xf0\\\xa7\xb4\xde\xd2\x1c\x8f\xdaR1 Y\xb5\x1e\x9fi,\x0fkv\xf2\xc3\xd8\xb4%\xab\x1c/\x85{\x16\xa0s\xf99\xdf\xfc\x1e\x8e\xd8\xfezw\xc8[\xdd\xed\x97\xb8{\xa8,/sOu\xf1\xab\x1aC\xdd\xcb'%4\xb5\xd0V\x9e\x87\xa5r8\xd8$\x8a\xe4\x81Aj\xafZ\x85\xc4.\"\x16\x9f&\xf8\xe6\xd1\xee\xdb\x04\xf0\x85(\xfa\xa1\x11\xb0\x85G\xe0\x94t\xd8B%0I\xb8\x04\xd0\x90 \x0c\x9f&W\xf8\x04\xc6\xf1\xc9\xbf\xdf\x85\x86S`\xd2\x90\nx\xc3*\x00Hh\x05\xbc\xe1\x15\xf0\xf1m8g\xf0P\x0bL\x1dn\x01{\xc8\x05F\x84]\xe0\xe7\x15z\x81S\xab*tj\xc7\x85c\x10\x84+\x1e\x14\x92\x81\xc9\xc22@\n\xcd\xc0i\xc23\x80\x87h`\x98*t\x84k\xc0yn\xf2>\xb8\xee\x8b\xb2\xf6\xee\x19O\x19\xc2\x81\xc1a\x1cpW\x9d\x0eb\xae5\xac\x03\xd4U\x86\xdci\x9e&\xc4\x03\x80_\xf8\x1e\x1d\xeaQ\x88i\xe1\x1e\x98}\x08\xb3\x0f\xa1\x82\xd9\x87\xf0O\xedCh{\x07:\xc75-\x13\x04\xe7\xc0\x98\x1b\xef\xe8\xd9\xdc*\xd2\x16Q\xb6\x9c\xc4\xc3\xd0Tju\xf8!\xbb\x7f\xa8\x1e\x96\x14m=<\xd7\xb3\x15ew\x87B,jR\xc93\xd5\xe3\xb6\x93\xa4\x06{\x10\x0e\xd3\x9aN\xcc\xd5\x9a\x05\x87o\x0e\x8b\xca\x963 \xacd.\xd8\x1f\x94 \x10\xdc\xde#2^i\xeb\x19\x05V\xe7E\x08\x92\xdec1a(\xac\x0f\xc4 h\xd0\x87a\x90\xefz\x0f\xc2 \xdf\xf8\xf3\x98\xb1\x07`h2\x87<\xfa\x824\xec<\xf6\x120\xf5\xf8\x03/\x16\xbe[\x1fv\xe9|\xef\x92\xec\xf7GR \xe2\xdd'\x0f!\x0d%\xcbE\xd2U\xb5h~hN\x1c\x81\x9a\xd6:q\xce_K.\xd1\xdcfJ\xc3\xd6z\xa05\xab\xc7Y\xa8k\x87a\x9e\xf1\x1dg\xeb\x81r\x84\x9fW\xb4\xc2\xd4.#}\x9a\x8d\xdb\xaf\x9cX\xfa\x00\xa7u\xfas~\xa4\xcag&\xd6\x87\x1b\x88\xd8\xa1(\xb3j\xf7\xa8\x8f5\x90\x95 \xcf\xd5\xf6q\xc8D\xc4\xf3\\_\xe12\xdc\xeb\xa0\xab=\x95\xd1\x8e\xc5\xe9Y\xd7K\x10\xa7QR\xeaK`I\xd2\xf8P\x85\x89\xe5\xd8\xcaH\xd3`\xaeq\xea\xde\xd1\xba9\x0d\x93\xf2a\xde\xed(/X\xc1\xb5\xd1\xa6o\x8c\xedY\xb4\x8b\xd3\xd6\x81X\xf5L}\xb8\xab\xfbr\x89\xe3S\x97\xeb\x9e\xf8\xc6\xd3\x11\x854O\xcee\xbb\xc6\xaf\xea\x96\xa2~P\x05\xa7>Hzw,G\x9eF\"I\x1br\xea9\xb0\xacX\xe6\xbcXv\xd7\xae\x01+\x85\xe0=\x01\"\x15\xd0\xea\x9f\x14\xd6nBB\x13\xdcN:\x1b\x1b\xc0\xc7\n\xf0\x1d\x02\x8d\x91\xc6\xb2\"\xe7\xc5\xf7\x8a+\xbf@>P\x9a\xf1\xf2ew\x9a\xb57o\xd9\xa7\xce+9\xb6bv\x12\x95^Sz\x0d\xcb\xa5\xd7\xf8N\xfe\xe7\x04\xdd\x1d}Q\x13 \xeb\xd2\xbe\xc9\xc4^{N\x0e\x07\x10eq(\x8b\xe3\xdf\x0e\x19\xbf\xa9\\\xf8\xc7\xf6\xaa`\xdf\xa44\x1d#m\xe3q\xb1\xc3a\x02,J^\xaa\xfaA\x13\xa03>\xd7 P\x1d/\xeb\xd5\xdbJg\xdf=\x98\xab\xaa\x14s\xee\x08h\x7f\xad\x0dO/\xb8\xd6\xc9\xa8\xdef\xd4Ey\xb8\xe6\xe9Z9\x9d\x8bjAh\xcdev\n,\x81\x89d\x81\x14_\xd1Q\x8c\xc9\xf5\xd7`e\xb2{\xa7\xbf\xfeZE\x0e\xcc\xbdl\xb5\x81j/\xa4\xde.\xff\xbd\x8a\x12\xe8J\x88\xbfz\xdas\xf2k\xf7\xb1\xaa\x99\x96$r\x80\xb0\xe3\x19W\xf5\xac\xd4\xdaZ\x00\xfc\x91?\xcc8\xfc\xb9\xcc\x0b`\xdb\x8cs\xb9\xd7\xa3U\xacD&\xe7E\xddt\xef\xf5\xa3\xc2\"{\xce\xd2\x8abM\xd6\xc5\xe1\xf0=\xcbw\xb0\x16\\\xd7`\xd2\xd6\x04\xaf\xbf\x9f\xf9\x08\x1f\xe3m\xca\xd7o\xf3\xeduUTB?\x8f%\x97\\\xae~j\xd6\xcb\xb1\xbf\xbb\xa4\xa1\xde-,\x8f9\xd4`\xe5\xff3\xf8A\x14\xbd:\x8c\x84\xd6\x9a\x9f\xcf\xe0J\xedK,\xb1\xa3\xc0\x0e\x06m \n\xa7\xcf@\xd5\x90\x892]\xfb{sY\xc2\x1a\x1a\xdd\xfd\xeb7\xd6\xef\xf0SF\x1b\x08k\x1c\x88\xeb\x1c\x9c\x86\xf8\x11\x88,\x05\x9fq\xde\x04\xef\xc9\xa5\x0d\xc4QC\xc0\xc8%8\xce8\x9d\x0f\x89\xf3l\x80&^\x06(\x93\x00a\x13\x01!\x93A87\xa1\x9f\xf7OQ\xdd\xcf\xf6\xa2\x0d\xcauDo\xc31\xc3\xd3\xfa\x0c\xf5\x11\x02{w\xb2\xf2\xd8\xb1#\x12\xa9\x81*O4\xbd!\x95=\x936\xb6\xbf\xcb)FJ\xdd\xa2\xe4np,S$w'yZ\x14\x05?\xab*\xa8\xeec]\xd1U\xffS\x197Vd\xea\xc4\xd9\xc8\xb9\xd8\x084AJCc/\xc3~VV\xd4j\xb6\xa2f+\nf+\n\x05\xa2p\xd2\xb6\xb9\xd9\x8a\x02:K\x81\xa6\x835\xccVT\x03(\x93\x00a\x13\x01!\x931[Q\xd4\xdeg+*`\x8b\xfa\xd9ZQj\xd9/]\x0f-\xd5_\xfa\x99\xe6_\xeaG\xb98}_\xde%\x17\xd0\x8bk\xa9Qd\xe0\xa5q.JA0\x19\xdcG7k3Y\x9b\x1d\x99\x84\xa2\xaa\xcc\x99\xe2V\xc8\xf6\x9b$\x8e\xd4\xb5\x0d)1\xc8\x1c'\xd2HXFI\xcc\xd3b\xa9/\x0f\x9c\xd2\xb5\xd9\xa0hi\x89\xf1k \xecb\xbe\xbe\xa0f\x06a\xe7$\xf4\x07\xc4>\x01I\xb3\xc0\x81\xd8)\x04t\x0c\xf6B\x92\x18P\xd27,-\xe9\xb4C \xfd`O\x00\xc1\x81\xb0P\xbb`\x16.\x9a,\x82\x03\x9aB\x82\xc3}\x10DQ+]\xa0\xa7\xa6\x90\xd0\xa1\xe9+\xbe\x84\x15\x1cB\xd2XH\x08\xbb\xa9.\xee\xe4\x16\x1c()/8\xe0\x8908\x04 \x8b\xffTg \x08-e\xbflB?\xed\xc6\xf2\xdd0\"\xfc\x96\xab\x01G\xe2\x0e\x0e'\xd6[\xd4\xf3 \x843\x07h&g\x1b\x02\x0f\x8f\x06\x02\xb9\x04\x038\x05!\x87J\x03\xd4\xc3@\x17\xc2\xa4\xdb@\xc8d\xc2\xb0 \x85!\x93\x1a|\x08\xed4\xf3\x1dF\x0d\xb8\xd3\xa5p\x08\xe4A\xe0\xd8i W8X\xd2\xb0p8\xe50\x9cIS8\x9c\x92\x1c\xf7}\xda>P3\xc6H\xc8\xbaYe8\xf8s\xcdp8%\xdb\\\xd9j8\x9c\x92\x1a<\xdf\x0d\x87S\xd2\xe1\xc9\x98\xc3\xe1\x94\x049r\xeep8%1\xfe\xac=\x1c\xdc\xb9|8\x9cn\x1c\xa1'\x8f\x90\x84A/2,\xa1\x10\x87\xee\xb3\x138\x04X:!\x16\xce\xcf\xc4N\xf7Fe\x0c\x84\x1aV4o\xab\x81\xd9@\xb7\xc2l\xa0+\x08\x13k\x03!\x93 \xc3&\x14\x86L\xea}\x19\xe8u4\x834\xa5z\xf4x\x99\x8d>X\x0bo\xf4!X\x18\xc3E\xd1h\x90\xe5&a[j\xa3\x81\x13\xee\xcf\xc6h\xc39|\xfb\xe6\xfd\x8b?,/_._\xbf\xb9\xf8\x8e\x90\xb9\xd0\x85.\x86\x8bo?\xbez\xe7N\xb6hC\x17\x01![\xa3\x0d]\x04\xef.]I\x1bm\xa8S8\xc6\xb1!\xec\x14\xa2A/\x94\xf5\xeb\x84m!N\xd7*\x84R=\xe1\x0d\xdf&\x91\xf8r\xf9\xd2\x9b\xcd\xd1\x86zIALw\x84\x06FR\xdb0HF\x07\xa9$B\x88\xb9\x0d\xa3H\xa3;\xf14\x90B\xb3m\x18E\x1f\x99u\xa1\xf6\xae\x86\x17\xca\xfc\xfc\x18ou\xb6\x91\xdc\xe7\x8d+ZE{\xcd\x15 \":UyJ\xe3\xf4\xb9\x9fC\xe9\xd5X\xdb\x97:\xea\x88\xa3\xba-b\xbc\xfb\xb7\xcc\x93\xb2\xd4z\xbfdu\x07\xcc\xdc\x0e9\x1e\xde\xed\xd4\x1f\xd7P\xce \x89K\xde\xfd\x86\xba\xcb\x1ci\xf3I\x1e}\x07%\xee\x9e\xc4\x91h\xa0\x8eGC\x90\x1e\n^H\x81\x8b\xc8R!\x15\x87 \xa6@0c\xc0]c\x15\x87`\x06A8\x93\xc0W\xa5\x15\x87\xfb!-tw\xa6\x96P!\xa2#\x94\xafq\x01%\x81\xa5\x0d\xc1\\\x0d=\xc1\x1c\xecO\x89\xba\xe0\x84t\x19\x8a|\x84\x04\xac\xcf\x90\x95\x19\xa0\xb0\x02\x99\x10$\xec\x01\xaa*\x80\x11\x10\xc8\x0c\x08WR\x81L\x81P\xc6\xc0\x10\xf5tz\xa2\xc2\x14\x13U-\xa9\x97\xd3}\xc8$\x0cVJ\xa1*)\x90\x93\xf4e\x0fC\x95\xd1\xc9(\xa2'\x1d\xd6-\xe8\xa4\xf8\xc9\x90\x16\xacH\x97n\x17.\xa1G\x7fO\xab\xbb\xbf\xb0\xb4\x88S\xbe\xf4\xdb\xa0~\xdb\xd3cs\x92\xb4\x15MG\x91T5\x81C\x1a\x88\x0b\x9e\xa4\x98I\x83\x04\xf2@!D\x0d\x93\x07\x0c\xf4AC\x98\xd2=\x0d T\x15\x1b\xa2\\\x95\xe2\xf4\xe0\x0bS\xabt}A\xe6\x92\x7f\x05k\x08T\x9f\x13\xf6OW\x95\x84N \xdd\xf9|H\x01\xbd\x8c\xcd\x99~#\xd5\xf3\x0b\x95\xb9|\xa1\x12\x97}y\xd3\xda\x15\x81\xe2jd\xcb\xb3\xa2\xe0\xfb\x83.u/`\x1f\xe7 gk`:S\x1at\xa6\xb4\xf1a4\x12d\x8e\x0cAU\x10\xaen&)\x81\x85\xc4\xf84\x0e,\nc\x8b\xdb\xcd\xb5\xafZ?Y\xf9g\xc0\xb7T~~\xb5\xafl\xb1\"\x9b]1e\xed\x14o\xf4\xc6\xc3\x14{D&$\xf6\x12\x10e \x88\xa7\xd0\"'\xc11\x92\xd6\x88\x96\x07\xd1\xea\xf0[\x1c\x04\x05p\x84\xf1\xaa\xe0\x08^+\xc3\xc1b\x874Y,\x0b\x022\xdc\xa2\xb0Z\x13\x04\x8c\x1d\xf2&\xb2 p\xeba:\xcb\xc1i5\xd4d\x93\xd5\xb7e\x19\xa1\xec\xeb.\x1d\xff\xa2\xf1.\x17\xefBq-\x11\xe2\xe2\x98fY8\x16\x04\xd5\xdaB\xc4\xdf\xd9\xb4+\xf2\x88\xb0\xd3\xba\x9eD\xb4;\xa2\xf6\xb2\xae\xfdJ\x90\xb2V\xbd\xd7\x80\xdd\xa0\xb7~\xd1\xb5k7\xd8G\xd6u\x1dU\xd3UWqm\xd2\xde\xab\xe7:\xae\x96\xeb$u\\\xbb\xb3\x8a\x95/ Os\xb7\xdei\x80]\xa6>m\xfc\xb7C\x83c;8\xb5\xaa\x16\xb5\x8e\x16\xbdr\x16\xb1VVPu,\xf7\xc3w\xa1\x15\xb0\\U\xaeB\xebZ\x85V\xb2\x9a\xfd\xa20\xfbE\xbbp\"\xbf\xa8\xc5\xba\xf4\x8a\x1bfYz\xcc_/\xce\xce\xd0\x9cU\x92\xc2e\xd9b\xf5\x86Qe\xdf5\x87\xd40\xea\xd6*\xfaE\xab\xf7\xa6\xde\xe9\xd5)\xea\xd6w\x9cw\x8d\x1a\xe6]\xa3\x06\xafp\xcf\xbbF\x03\xe6]c\xde5\xfek\xef\x1a\xae| tH\x98hZ\xab\xd4\x911\x8c;\xd3\xe3\xdc\x1cVC\xaeQ/\xae\xc2\x83V\x8d\xeb\x1c\xf8\x82\xcfx\xde\xd73\x02\xb6o\xec}\x8c\x01\xba\xb5o\x05\x80O\xa1\xd8\xe2\xd0T\x8b\x00\xff\xd6^\x93\x99n\x19\xd8\xbe\xb6\xd4_\x0e\xb2\x10\xc0k%\xc0\xc4\x96\x02\x0c\xb0\x16lm|\x15\x93mi\x9e\xa4M\x16\xdb\xb0,w\xee\xdd\xbb\xa0M\xfb\x82\xf3\xf6\xfc\x88\xfd\xfaT[*\xc1\xca\x00\x1f\xe5\xe0\xa5\x1e\xdc\x16\x07x\xf9m\xc0gy\x80\xf7\x96\xb9\x97]\xe0g\x19\xc1\x12\x01\x975\x02v\x8b\x04|$\xba#%^\xeb\x04\xa8\xf8\x91\xa1{\xab\x00\x0f_3\x8e|\x91a\xd4\xba3\x12\x07[16\x8e\xa0U{\xd1Z\xbd\xd8;\x07\xf3n8\xef\x86\xf3n\xd8\x82y7\x9cw\xc3\xea'\x8a(\xcf\xbb!\xfcS\xee\x86\xbe\xfb\x10\xd6\xe1\xdaD\xdfY\x91>\x18\xdbtn#\xfb\x0cL\xe5\x07\x00\x9b/\x00\xc8u\xe3Q\xbd\x86\xeb2Oe\xf8\x01\x16\x8d\xa7\xf6\xfb\x98\xdd\xe2\xb4\xaa\xdc[\xbf=\xb4j\xbb\x97& \xd1\x05\xb4\xba\xec\xa4-\x00\x1a\xc2\xed-y\xee\xad\xbc>u\x97\x94\xebG\x1a\xe8\x15\xd5\xe1X-\xdd5\xd4Au\xd4C\xaa\xa7\x1f+\xa3;\x10\x86\xd6L\x0f\xad\x94\xee\xaf\x8fN\x98R_\x8dE\x02\n\x9a\xc9\xe3\xaev\x1e\xd4\x8d\xaf(\x12\xb1\x9e\xf9\x84+\xda_C\x8f4@\xa0\xd8u\x1aH&\xb1\x01\xd2H\x818\xab\xe0ze\xdd/\xe5\xde\x05L\x1a\x08A\xac\xbcK\xd7;\x18 \x0d\x08\xa8\x8b\x9640\xa0\x0d\x0e\xe8\xcbu\xdan)\x0bu\xcaeJ_\xa4\xb4%J\xe2\x86o\x91@\xd8\xe2\x9c\xa4O_h\xbf\xfe\xce\xd7\x99\xad#G\xddW+N\x1b.\x7feW\x9b-1e\xdd\xb5\x13\x95\xfar(\x16\x8fJ\xf1)\x13\x8f\x1a\xf1N-a\x0d{\x95\xc6\xf8N\xdc*\"X9\xd4*\x00E\xe7P\x0b\xbe\xb5B\x94\x01|A\x92\x96\xff\xc0\x1e|K=x9\xdeG\xde\xcd\xc0z\xa4\xf8=&j\x15R\xcb\xbd\x9c7qN\xaf\xc5e\xcb\xdb!\xd5\xda\xe8-u\xdb\x12\xf7\xde\x00rbua\x06\xcb\x9d \x0d#5\x92j\x8e\xfe\xe2\x95n\xf0\xfa\xccB2\xa5m-\xec\xf9\xd2\x8e\x16\x1e/Y@\xee\xb4\x86\xe0\x0cj\xd3\x8c\xe2c\x08\xcf\xa6\xb6\"\xf2dYk\x18\x92kmo\xe9\xcb\xb8\xd6p\x0f\xc5\xe6\x9dQ\x1e\xdd\x83;&\xe0\x8f\xf0\xf8\xe2;\x84\x03\x87o=\x02!\xcc@`\x17\xf8wq\x0d\x011\x1d\xc2\xe8\x808B\x00b4\x872o\x06\xfc\"b\xc0\xc7`\xa03\x19\xa8\x8c\x0e\x8a\xe0\x10\xe27^w2a\x004\xf71\xd9{\x1e\xd0\xa3\x95U\xde,q\x0d\x14\xb9\xf0\xafg\xafC|\xfc\x88([\xc0T\xf9\xe4\x1a\xdcY\xe5\x1a\xd0\xdc\xf2\xaa9r\xdfJ\xc3li\xcc\x96F\x0d\xb3\xa5qR\xcd4[\x1a\xb3\xa5\x81\x00\x89\xd1\xb3\xa5\x01\x14V\xcd\x96\xc6?\xd8\xd2\xf0y\xc1\xaa\xaf\xdc\x8cq/E\xe7\xed6\x0d\xa3\xf0\x9f\xf2Q\x08\xdf|\x8e\xba\x07\xd7\x1f\xc9\xad\xb0\xdf\x86\xd3@\xbb\x13W\xa1\x1b\xe6\xe6\xf2\xdc\x92\xd30\xd2\x0e\xf5\xdc\x9b\xd3@\xd8\x81|\xfd\x80\xe7&\x9d\x06BG@\xec\x0c(w\xeb4\x84\xde\xb0\xabZ\xd1h\x85\x00z\x81v\xe7N\x03AG6\xc1,0\xef\xfd;\x0d\xde[x\x1aNI\x84o\xc9w\x81~;\xcf\x8b\xeax{o\xe0\x1d=\x0d\xa17\xf5\xbc\x08\xf5\x08B\xef\xebi\x08\xbd\xb5\xa7\xc1\x7fwO\x03Y\x10|y\xee\x1a\xc8\xe8|{R\x13\xdc7\xfb\xaao\xc2;\xa6\xa5\x1b\x12\xef\xfai8\x91n\xa1\xd8\xdf\x10\xc6\x04\xf0\x9bbm\x088\xf8\x18\x08\xe0\x06\x04r\x04\xa8\x07\"\x03\x14\x03\xb8\x0bt 5@\x9d(\x08\x9f,\x08\x9d\xb0\xa0\x03T\xa7\x89;\xe5^\x03\xfdF\xa1\x86\x80\xf1\x06\x8c3\xfc\x8e\xa1\x06\xc2MC\x0d\xa7 \x9b|oO\xc3)H\x98\xf66\xa2\x86\xb0;\x89\x1aN16\xea-E\x0d\xa7\xa0\xc0\x7foQ\xc3)\xfa\x0e\xb8\xc9\xa8\xe1\x14D\x10\xef6j8\x05\x01a\xb7\x1d5\xd0\xef\xdf\x89\xdb\xf3\x88\xa5\xe7qq\xbe\xe2\xe7\x9b\xf8+_?n\xf2_j\xeca\x02\x87\xa9\xf3k)\x1c9/\xb4\xda\xde\xb3\xaf\xf1\xbe\xdcC\x1e\xffE\xcd\x8d\xd2D\xc7\xd5(EP\xf6\xae\x9d\\\x11Ka\xd5\x94\x9d\xa37+N\xe5\xb2\x8d\xd3mR\xe5.\xb6n(\xb1tm\xe6t\xc3\x92D\xb6\xdb\x88\xac`\xab\xe4\x0e\xcat\xcd3CK\xe5ES}\xb60\xbc\xd4\xdeo\x88sx\xfa\xeb\xdf\xfc\xef\xdf\xfe\xaf\xdf\xc9\x19\x7f\xfa\xf6[\xf5MK\xec\xdak\x1c\xd6\xbcPAe\x0e;q\x0b\xb7\\\xcf?oi\x9c=K6\x9c\xe5,\x8d8\xa24\xbeo\xc4\xf5\x08\xca\xa2\x97\x0d\xec\xcb\xfbE-\x15\xdc2A\xb2v\xad\xba\xdb\x88D/ \xb6\x97s\x1b\x8a\xc2\xbe\xca\xe9\xb9\xb1\xf6\xdc\xd7\xeep\xfbY\xb0\xa1\xf9\xae\xad|\xd66#\xf0\xccV_\x0ek?[\x15aa\xf7\x14@^\xb7\xed\xfcQg\xb3\xee\x8el\xc9\xfe\x0c\x90\xb0~\xa0\xd6+\x1d\x1d\x8b\xd2\x19\x0f\xb7Z\xe5vK\xdc\x12\xcd\xd6\x98\x08\x0fW\xf5\x8c!<\x16\xed\xb4\x81\xac\xc6\xb33\x92\x8c\xc6\x8c\xedy\x88\xce\x99n\xf5\xec\xcf\"D\xf2\x05\xa9\xe8\xad\x19qT\x04\xe3r\xf5\xdcYyT\x1al9u\xd4\xf6\xfd\x8c8jKG>\x1b\x15\x85%\x1b\x8d\xda\xdc\x9dKf\xcf\x1a\xa3\xe1\x9f\xae\xf2}g\x9bU\xa7\x84o\x8f\x1b\x1ca\xab\xb5\xdc*\nQw\xd3\xe8(\xeb\x0d \xdf\xde_\x7fg\xeb\x13\xbc^\n\xc7M\x1e\xa7N\x03\x97\x8d`\xc0z?g,j\xdf\x99q\xa4-\x81\xe0\xa3\xdd\xac\x99\xca\xb60\xe0\xbd=\xe3\xb35\x0c\xd8o\xc88\xa6b\xf2\x97W\xf1\xbb-$t6\xef\x81\xe7\xc6\xca\x88\x95aO:#K\xaf\xc5[F\xca\xf9sR\x0e^\xea\xc1n\xfb\xd4?;m \x03\x14\x7f\x97;?\xcf\xcb.\xf0\xb3\x8c\x98u\xe7\xcc\xb3\xf3\xdf\xe1 I\"J\xa1\xdf\xa62\xe0\xb8\x8b1\xb4{\xef-\x84\xa1\x88\xc7\xd9b\x06h7%\x86\xd2\xe8\xbb\xff0\x14\xaf\xfdV\xc3P\x8c\x84\xbb\nCQ{n \x0cEK\xbbW\xe0\xbfI0\xac\xff\xe9lE\x03XZ\xff\x00{m\xf2}q~\x91|\xde\x10\xbbp\x0f\x1b\xa2+\xd5\\\xd3\x88\x87\x81\xadA`\xcf\x14\xf9&\x88\x94$N`\x9e\xaf\xeeXX\x0et`\xb2w`z7=\xa1{P\nwk\xfe\xbd\xb9\xd8\xb4,kr^5a\xaa\x08R~_\x95\x8c\xbc9\xd0\x01=Y\x86\xd3\xda\xd1\x82\x92\x96\xd1\x94d\xf7)8(\xed\x18I-\xee\xa0C\x13\x8d-\xa9\xc5\xa8\x1e\xc0W\xff\\\x8b\xbe\xd9\xd2\xa3 \xe7Z\xf4s-z\xb0%\xb1\x0e0d'6\xd8\x1d\xa2?\xc2\xect\n\xbdW\x1a=\xb2\xe8\x11\xf7q\xe8]\x82>\xa9\x98[\x85\xdc-\xe2\xa4Y\xc6\xc4\x9b \xdc\x83p\xfb2\x99\xacH\xbb\x08\xb1\xe0\x00\x96B\xa4\xd1\xf7\x84\xb3/\x90\x8e*g\x01\x9b\x9d\xa3\x8e\xd9\x80\xd5k;,\x8dXk\xceZd\xd4h\x04\xf8h\x00/\x1d\xe0\xaf1\xe6]\x9a\xd0\x90\x0bg)/g\x15\xb1\xa9\xba\xf1G,`x\xd4\xc2\xc5Ab\xe4\x02\xc6D/,\xf8\xc8\xf5\xbf\xa8Q\x0c\xf0\xd6\xfa\xf2L\x97\xab\xcc\x82w\xa6}\x07\x7f{\xe5.2j\xd7 \x85P\x9bk\x82Uw\x1f\x9e\x0b\xa2\xc3\x07(#\x02\xd2\xa8\x00\xbc\xce\x1f\xa8{\xf39\x80\x80 \x0b\x06\xfc\x95\x0bH,\x05\x1a[\x89N\xa1\xc6\x87\xf6\x8a\x04\xfeh P\xa8\xf7RM\x8f\x9c\x80\xbf\x92\xd5Xr\xbcQ\n\x98\xa0\x93i\xa2*@\x8e\xac\xc0\x044\xfb\xa2,0A\x1f\xee:Rc\xb1\x13\xa2/0A7\x84ZPc\xbb\xa0Ee\x80\x14\x99\x81\xd1\xf4L\x1f\xa5\x01G\x01\xa6\x11\xb6\xedI\xf7~G\x11%\xff\xa6\xd2@\x8e\x16L\x9a7}\x04\xfc\xa3\x82y\xd3\xc7?\xb4o\xfa\xbe\xe2C\x9a\xee\x7f\xeck\xe3\xa4(\x11\xd0\x99\xec/\x1b\x14\x1a1\xc2\xda\x10J\x04\x05F\x8e\xb0&\xeer@\x83\"H\x00>\x8f\xad\x81!A&\x9f\xf0[\x7f'\x07\xa1\x80. \xc4\xc5F(\xdf\x13\xd8\xa1\xbfT\x8f78\x05\xe1\xbd:\x869q\xa0\xaa\x87\xd2\x92\xb29<`\x85\xe92Wu\x1cGM\x1c\xab\x9ar$\xf0:nT\xbbT\xe6\xa9\x02\xe9\xf7\x10\x97\xf5\xdc\xa0\x9eH\xd7\x13\xeeN\x13\x06\x03\x94\x01\x81?\x1a\xa0a\xba\x0e\xfdj58J`\xc5D\xbd+\xed\x0b\x8a\x01\x8d\x03~S\x89\x10C\xd00\xb27\x19uK\xe7 \xcfS\x9e\xa5\xe5]X\xfee\xe5]T\xde\x01\x80\x7f\x10@[N\xd3t\xe5[H\xc1\xcb\xc8\x1dSvF\x95)K\xc8;j\xdf\xf2!.\x9eQ\xfd\xf8\x82q\xe0\xeb\x00Cn\xa9q\x82\xe2\xc1\xda\xbb\xab\x98`{\xed\xd8G\xc2-K\xdd1r\xab\xb8Z\x16\xb6cI\xbb\x16\xb3c\x19{\xe6\xdd\xb9\x9e\x9c\x8bv8b\xfb\x12\x9dpqZ\x96\xa5K\x86 \xf3\xd8_\x1c\xde\xe5\x17\x88\xd5\xb5\xd4\xc8K\x039\x988\xdb\xb6\x0f\x1d\xb8y>\xb0\xf6F\xc3 \xae\x10\x0d\xac\xb8q\xc5\xb2\xe2\xa3qi\xe8q\xf5VK\x7f\x8dt\x9c>\xbaE\xd7\xc1\x83\xb1p\xc8\x8dI\x8b\xf3\xa53\x10\xfd\x88k\xe08F\xdcLD\x03\xf9\x94\x00\xbeU\x19\xd9U\x91%PO\xda\x1b\xd0\x889\x1a\x90\x1f\x8a\xce\x97$9(\xe0^s\xaf\x83\xce\x13h\x1f\x1c`G\xae\x07:\x03\xeb\x94\x80:\x1eH\xb7\xb0\x19s\x9e[g\xc4\xa68\xfb\x01r/\n\xcc3\xe2\x08\x84\x0f\x90\xdeio\xccx}\xdcN\xfb\xddm\xbb;|\xd9\xb8\x8ak\x82\xcf\xa2\x0b\xb9\xabq\x1dfi\x9c\x0e\x8e\xce\xa8\xc6\x12o\xe8X\xa3w\xeb83Y\xd5\xa2U\x06\xfc;D'zNm\x86\xfbw\xc6F\xc7\x1bak$*>E4\x1c\x8d\x82\xbb\xa2\xdf\xc9j\xbfX\xb1\x9c/n\x9e.^\xf2\xe8\x85\x88S\xf2\x94\xacy*\xf6N\xde\xb2\xbd(S\x97\xe2\xc5E\xb1\"\xa46\xc6\x18\x14\xe2\x0bO\xabwKt\xbfq\xaawr\xc9\x0c\xf9\xa7(\xde\xb3\xa4\xea\xb0\xdeU\xf4\xe9\xf4z\xc7\xab\x1f`\x13\xf3d\xadv\xa8T\xf6R\xf9V\xe3\xfd!\xe1{%\xf5j>\xcb\xbc\x10{\xd8\xf3b'\xd6\xdd\xc5&\x8f\xca?\x95q\xa6]v[\xb1\x15\x87L\x14\xc2\xf0r\x1d\xcb\xd1\xadJI\x9b\xe6i\xc2\xb7\x8a\xd2\xea_\"\xfb\xc0oY\xb6&s9L\xd9d\x0d\xe4\xc7O\xa6=\x15w\xe6\xbd\x89\x03\xd1\xdd]\x19p~n\xb71&\x94\n\x0d\xd3\xc9\x86\x06\x8a\x84\xd8\x05\xde\"%M\x85\xac\xa3\xd9fJ\xaa\x96*f\xb96\x8d\x1e\xe6\xe6\xdf\x92 Z\x16l\x92\x19h\xa7K\xad_\xa6qq\xb7,Xo\xbbj\xcd\xa3T'\xcb\xfa\xa0\x82\x0bd\xbb\x81H\xcb<\xa8\x85\x9c\xf2u\xc6n\xd5\x92X\xf2T\x9e\xcfz-VB$\x9c\x1dOh\xf5>\xd8\xf8{k:\xea7n\x1a\xc1a\x9d\xbfw\xd0\xbfH\xc5.\xff\xdad%\xec\xc5\xbaL\xb8\x8d\xcb\xffQ\xf2\xec\xee\x85\xe1\xdd\x95\x10\xc9\x07\xf5\x08SN?d\x1c\x84\xe8e\xef\xcd\x0b\xfa\xe7\xb2\xa0{\x83\x94\xd3U\x0f\xa9^5\xea\xcf\x0f\xe5\x1f\xe24GTAmc\xd8\x05F\x8eDm\xfb\xe6\xbf%\xcb\x8dL6[?i57L\xfap\xf5\xa2\x1a\xa5SV\x8f\xaaHk\xa0y\xdc\\\\\xbb\x99[\x8e\xe8b\xdcC\x11.\xc3\xd7\xf2\xe0\xfa\xb3\x16do\xa8\xde*\xd4\xdd}\xb2\xf99v\xbf\xd2r\xbb\xd2B\xaf\x06wR\x0d\xba\x085X\xa9\xd6\x80/HBS\xff\xb5\xd9\xc1K\xd4Jf\xfbEE\x03c\xd6.\x82\xaeZ\xcd\xc8/\xf4E\xed\xd3]C\x8dL\x0d4S\x13\xa1\xa3\xab^\xe4\xf1\xd6\xa7bD\x9dq\x87\xde^\x98v\x0d\xce\x9b\xc9\x84\x9b\x89~\xf4\xb2eD\x97{%<\xedi\x0f\xd8A0->d\x1bi\xe2 \xdcKDv\x0c\xed\x04o$#\xc3\xd5\x1d\xa1j\xb1\xac\xe1{k\xb2\xbc\xf9\xb8\xefqII\x9e\x99E\x9bn%\xb3\xa8\x93\x80\x0d?x\x06\x9aH\x82\xd9\xff\xc7\xea\xc8w\xa1w\xc9\xe09h\x1d\x19}^\x94\x0eK\xbam[\xac>r\xd7\xfcZ\x08\xf8I\xd2\x1e\xc6`\xcb\x00\x07p\xb9\x83\x89\xcaj}\xfc\x0df\xec\xa1\xe1G\xe8\x8d\xf5\xd0?R\xab?\xf1\x82g\xc6u\xd98A7'\x84\x14*\xb1x%\xc0\xae\x90\xdd\xde WC\xb7\x97\xc2\xd1\xd2\xe3\xad8\xb6\xecz,\x80\xe2\xb5@\xe6\xce)3\x95\xb4T\xce\x0e\xa2l\xd4\x0bW\xa57\xe6\xb9\xb2\xc9\x03\x05%\xaa\x9bZ\x84\xe5\xf8AK`\xf4\x9f\xe5_[\x9a\x0d2\x1e\xf1\xf8\x86\xaf\x07\x0bN\x97\x18p\x98\xcfS&H[\xcdf\xa7\xe5k7\x99\x1d\xcd|\xe6\xf2`\x13\xc4B\x1ef*\x8f\xb1Kz\xc8lf2\xcdX\xa9\xa2\x81m\x0d\xec\x90m\xba\xf2E\x904\xd6\x16ii\xbd/\x8b\xbc`\xea!\xf6\x89O\xac\xa4\x15\xd1k\x0b\xf3r\xf8/\xbe\x1c\xc0\xc9\x12\x87`6O\x8c\xe2\xf8+<*\xd3s\xb3\xdb\xa5\x8f\xfb\xc2\xd5$T\xae\"\xd6P\xe7q\xca\xbf\x1ex\x9a\xc77\\ZPE\xc6\xa2/g\xf2\xd0 ns\xc8\x15; g\xca\x97\x1a\xedx\xf4\xc5\x7f\x80 \xac\xac\x01\x0b\x1c\xe1F\xe8&\xfa1Q\x17\x17\x83\x97w\xae\xdbu\x977\xe9\x10A>\x0c\x1f\x1dR\x07\x9e\xc5\xc2\xe2`B\x97\x17\x1a\x7f\xaf~\xcaXT\xf4v\xdbA\xc7\xe66\x1b_\xdd\xf0\xb4h\xe7-\x1ceJ1\x0c\xf8MUM\xe1\x08\xdf\xab\x8c 9\xfbR\xb0\xe2(.\xd4\x1a\xaf\xd2\x93\xf2Bd*\xfd\xaf\xdd\xe8z'\xbf\xcf!\xe5|\xcd\xd7RH#\x96De\xc2\nu\xf54\x13\x87,V\xff\xd6\xebZl /\xd8\x17]\xe3\xe1\x0bO\xdb\xde\x14)cG\x07\x8a\xb9\xe5\xc32^\x9b\x8b)\xb0M\xc1\xe5\"\xd1\xc3\xd8\xb1\x1cD\x14\x95Y\xc6m\x9e\x96J@\xda\xa7\xef\xeaon\xe3\xe9\xc0\xb6\x95b\xb3Z\xf2\xe6\x83\x8e5_\xff\xb9b\x9eYJ\x83\xcc2u1\xd7\x92\x8b\x8a\x88\x9c/'\xe8o]\x15o\xf0\x9bu\xafR\xdc\x05\xac\xe4@\xf2\\O\xea\x15\xdb\xf2\x0f\xfc\xa7\x92\xe7\xc5B\xff\xdeA\xa2\x0fw\xb2\xb9D'Y \xcf0y\x01|\xb3\x89\xa3\x98\xa7E\xd2\xdc-\x91\xe4)\xef\x80\x90\x15d\xcb]\xd5\xfe\x169\x1e\xf5\x8f\xb4\xdc\xafx&\x85\xaf\xba\xfb\xdb\xc8`\x8d\xbb/\x134\x87\x1aI\xa1]*$\xdd\xfd\xe4\x96\xe5\x90\xf3\xe2\x0c\xe2B\xdd\x05(\x95\xde,S-\x08k\x10\xc5\x8eg\xb7q\xeeJ/rj\xc0\x01j\xb8\xc2@\xd0\xbdu\x93\x8b(*\xf7j\xb9\xae_t\xcc\x7f\x82\xf2\xc5N\x0c\xa7\xd0\xbf\xb33r\xb83\x12\x1f\xa0[\x00Z{\xc7\xf1\x83\xc6|Wh\xba\x06\xcb\x17~(\x80INee\x9aJ5\xaf\x96\x10\xcf\xce\xd4%\x99UK\x93\x17\xc0\xd2;\x95x\xe8\x15\xd3\xbe\x81A\x96\xd1{\x89X\xcd\x02z2\x01\x1dji\xd7\xf6\xb5\xc67\x89i\xed\x94\xd1\xa3\xe9E\x96M\xbb]\x89\n\x03\xba\x13\xf6\xad\xc8^[\x0f\x87\x07\xd9\x8c\x81\xd6\xe2Dv\xe2x\x0bQN\xa1\xb9{\\\x9fB.\x92\xc4T-\x0b>\x80\xf0\xd6;ap\"\x05#?_\x96Y/\xe1|\xc4\xc1\xfe\x02>}x\xf3$\xe3\xb9(\xb3\x88\xab\xcb\x88\xfa2v\x99\xc6?\x95<\xb9\x039\xb0\"\xde\xc4\x95][T\xf7\x17\xfa\x85\xa6\x00r\x9e\xc5,\x89\xff\xc2\x91\x83\xb7Z\xeb\x91H`Un6<3\x17\x1f\x16Z(4\xed\xb0/\xf3\xfa\x86\xb8\xdc\x1a\x12\xce\xf2\xa2\x8fK\xa4\x1c\x1e\xd9\n\xb1M\xf8B\x8d}Un\x16/\xcbL\xc9\xec\xe7\xc7\x9ab\x85.\xdf\x892Y\xcbmQ\x0e\xba\x87)b\xa9H\xe3\x88%j\xe5\xf7{z\xc4\x17\xdb\xc5\x99d\x95\xd2\x7f\x0f\x16\x0f\xd4\x12\x13\x85\xdc\xb4\xf9\xa1\xe0\xeb\xc7\x98\xb7\xe52\x85\x83R\x1a\x11?\x83\x82\xb3}\x0ee^29\\\x9d\xd5~\x88\xa5a\x9cJ\xb5\xb8\xe3\xb0\x8aS\x96\xdd\xe9P\xe5\xdd\x81\xf7\xcb\x99*\xa1)v\xfc\xae\xdf\x95\xd4\xb1Q\x01q!W|\x997/\xbb\x14\xf2\x9c 6p\x91\xde-\xe0{q\xcbo\xa4\x95 \x17\xf8\xa7\x0fo\xaa\x95\xdd\xc3'QH\xf1\xeb\xcb_\xb4\xe3{\x0e\x9fwEq\xf8|\xa6\xff?\xff\xacr\xf3SQ\xfdz\xa6\xa4G\xda!B\xad\n5\xe2\x9c\x17P\x1ez\xf8\xf4m\x1d\xa4\x1f\x9e\xdd\xf0L\x0fy\xcf\x0e\xb9\x16\x05Eq!\xea+=j?\x8e\xb5\x8ab9l\x84\xdaV\x9e!s\xf1K\xb8\xdc\x1c)\x94\xd3w\xc8\x84\xd4(\xebz\x10j\xff\xcd\xf3r/\x15\x18\x82\xe0\"\x85\xef\xaf\xaf\xaf\xe0\xbbW\xd7P\x05\x04>}x\xa3\x17\xd4\x9d\xda\xc0\x19\xfc\xa9+\x8e\xd7w\x07\xfe\xe3\x9f~\xec\xa1\x03s\x96I\xcd\xbc\xebMGq\xf2\x90\x89u\x19qi\x0d\xf0,\x13\xbd\x17Y\x145\xc7l\xfb\\)f\xb5\xa5\x1a\x95\x1f\xc9\xb5*\xc4\x97\xf2P\x1f\xc5VL\x9e1E\x8a\xaa\x15\x90CQ}\xef\xd8\x8d\x9a\xfa}CF\xd7ZH\x99!U\xfe\xfbF\xc4kiW\"\xa8t\xc7j\xf9e|#2~f\x1aJ|\xac\x88Wq\"\xf7{\xb9G\xe5\xe6\x08,UDv\xc3\xd7\x08>\x91J5\x94n\xb9\xfaX\xad\x8d\x05<\xfa\x94ss\x95N\x8eZ\x8a\x87\xba\xe7\xad\xe4\x83\xa5l\x8b\x8dr\x95q\xbd\xdbU\x08\x17\x8f\x11'\xa9(\xf83(\xa4\xce\xdc\x94i\xa4%X\xd2[\xady\xb5\xc7\xc9sv\xf3t\x8b\xb3U\xa8Cy\xffP[\xe9\xeaU)O\xcaR\x03\xf33e7\xc6\x85\xe9\xa4\x94\x93\xa5\x0e\xa1\xb5\xdc\xaf\xf86V\xb6~\x0f\x99\xaa6\xdeW\x17w\x07\xbe\xd0\xf2\xc8\x0eq\xbe\x88\xc4\x1e\xd3R\x1f\xd5\x8a\xc8\xf5AZ.\xb8\xb4\xbb\xba\xe1Q\x15\xbd\xe3\xfbCqW-\xa1\xc7\xb0\x97\x86I\x0f\xdd\nY\xccj0\xcaV\xaeMZm+\xe7\x07\x1e\xc5\x9b8\x82\x9c\xefYZ\xc4Q\xde\x16u\xb5F\x02\xb6b\xc7}^\xdf.\xfdV.\xe3\x157\xe6Xc\xa3\xed\xed\xab\xd5\xe6\xc4V\xe2\x06\xd9\xa0\xf5\x90*\x91\xb4\xe6Gu(\xf8|\x91\xde}>\xde\x1be)\xb0l\x15\x17\x99\\4\x0eJ\x8c\x1ed\x89\xe8\xf0B\x9fL\xdaS!\xb5\x95R\xa8\x9a\x92U\xdf\xdch\xf6e\xac\x87\x8e\xc8\\\x19\xc1M\xe2\x95\"\xaf\xd2\xa39\xe4\xe5\xe1 2\xb5\x03\x1dX\xf4\xe5I\x99\xca\xff\x93\xfb\x8e\x9e\xc7\x1c[%\xfd\x0dWl\xa0,\xb4\x820\xcb/\x07\x9d\xe1\x10\xeb\xb5\x08[\x9e\xf2L\x1d\x94\xf5a\xa8\x8e\xe6_t\xf4\x91\x9e\x826\xfeW_\x99:t<}\x06W\x92>\xb9\xee*RY\xf3\xae\xe8\x8b_\xfd\n\xd9\x06^\x0b\x01\x1b!\xe09,\x16\x8b\xff\xd3\xfbY\x0e\x96\xa5w\xfd\x1fXz\xb7\x90\xdd\xbd\xce\xc4\xfe\xd1F\x88\xc7\xfdO\x16\x8b\xbe\x9e\x8f7\xf0H6\xfd\xa4\x08\xbc\x16\x8f\xfeE\xb6}\x0c\x7fEt\x1b\xd6\xfe\xef\xf8\xd8\xbf\xf1\x8c\xfd\xf7\xec\x86\x0d\x1e<'\x14+\x9e=\x87\x7f9\xac\x16\xaf\x85\xf8\xebb\xb1\xf8{\xff#\x96\xde\x9dI3F~y\xd0\x9b\xf7[\x96\xe5;\x96H&\xe1\x84b\xac\xe8\xf6\x86t\x15o:\x1d}J\xf7\xc7\xae\x14!J \xd5W\xff\xe39\xa4q\x82\n\x18\xde\x7fG\x92\xaeU\x04\"\xfaR\xeb cP\xc2\xea\xee\xb8\xbd\x1b-y\x1b'\x89\xfc\xa1\xba\xf1.\xb7\xc46\xba\x87\xc8v\xfdD\x9e\x8dTm\x80\x854m\x1eJ\x1b\xb7\xd6\xd8R\x9b\x9b\xdb\x98z\xc6\xda\x08k\xd5\x98&w\xc6\x9e\xef\x1d\xb6j\xb3\xa9:\xcd\x17\xe6\x8c\xf7\xf0\xc9\xc36\xba\xea@a\xba\xd6'\x08^I\xcf\x83\x8d\x10\x8b\x15\xcb\x14\xd1_\x9f\xdc-\xfe\xf2@\x8fX\xdb\xc5}\x13_u\xf9@~'\xd5s\xeb\xa7\xdf\x7f|\xff\xae\xfd\x97\xe7\xcf\x9f?\xef\xf3^~w<[j{B\xc8\xe5Rm\xa6\xda\xbeV\xd5\x81\xb4{\x7f[&,k\xe3\xe97/TV\xddq\x1b<\x03\xbe_\xf1\xf5\xfa\xb8!\x9eU{k\xe7D\xda\xd8\x9e\xb47\xef\xf3\xbf\xcba\x7f\xae\\'\xad\x92\x10\x86\x89\x0b\xb3\xfc\x9e!\x06\"\x8b\xbe\xc8\xb5w\xa6\xfaCU\xbd\xb5\xfa\xee\x1b\xbfF\x05@{}\xa0\xc6\xff\xe0\x19<\xc0$\xbb=\xac\x85\xa6\xfe\xc1\x19\x86G\xd1\xfd\x8e\xed%\xae\xff\xabI\xfc7\xf4CIw\xe7;\x1f\xf1\x97\x9b\xca\xb0m\xcf\xb1\x9e\xa18\x87[\x9e$\xe7_Rq\xab\xfd\xba;\xe5r\xaf\x1c\xb1}Am\x8b\xd3\x996\xb6:2\xa6\x15A\xa3K)8\xea\xa6\xb6\x12\x9b6\xc2\xcfJ\x88\x8d\x0c\xedD\xb2n\xb9\x82\xd5\x12\x88\xd3Z\xf6\xa0\xf2$T\xa2\xd7\xc6\xa5\xd0\xd7\x12\x07\x8f\xe4\xfa5\xc3\xed\x1d[\x8d\x17\xe5\xc7?\xfd\xf8\x18\x11\xce1\xf3\xdd\xee\x00\x9fr5l\x89\xea\xe9\xe2\x9b\xa7\xdf\xe4\x0f\x90i4\xffjY\xd5u\xb1\xc3\x8c\x17e\x96\xeat\x7f\xf3\xc7|\x8e7\xcf\xf1\xe6S\xc6\x9b\xdb\xf7(\x11_7%7\xb6\xd1\xac\xc2\xf6\xe1\xea\x85!\xb2\x1dl\xee\xb9\xd7'\xf7\xad\x93\xe4\xb8@]\xe6\xd6iw\x1f\xc4't\x96\xdb]\xe5\xd39\xca's\x93[\x9d\xe4#\\\xe4S9\xc8\xdd\xee\xf1A\xce\xf1i]\xe3V\xc7\xf8\xb4nq\x8bS|\xa4K\xbc\xc7\xee\xbe\xb5<\xb5;|\xa43|bW\xf8\x08G\xf8\xd4n\xf0\xc9\x9c\xe0\xd3\xba\xc0's\x80\xfb\xdd\xdf\x939\xbfm\xae\xef1\x8eo\xd4\xd1\x8dX\x9b}}3\xce\xc9\x8d8\xb5\x07\xba\xb4\x11\x87\xb6\xd7>\xea\x19|\xee\x1dt\xa0#\xfb\xe8\xb8\xc6\xf8\xfb\x0b\x7f\xdf\x13\xbb\xb0\xfb\x0e\xec \xdc\xd7\x93:\xaf\xbb\x9b\xe1H\xc75\xe2\xac\x1e\xe3\xaav\xfaj-nj\xaf\x93\xba\xef\x17\xa3;\xa8\xfbm\xff\x8e\x8du\x90k\x9a2X\x9f[\xda>6\xafK:\xc0!\xdd\xf6?\x8ctF;]\xd1vG\xb4\xcb\x0d\x8dr\x81\xea\x82\xf69\xa0\xbb\xee\xe7\x11\xceg\x82\xeb9\xdc\xf1\x8c\xb8}}N\xe7\x89\\\xceH\xcf-I\x99\xd4\xd9<\xb1\xabyRG\xf3\x94nf\xab\x93\xb9\xeb\xb9\xeb:\x98\xa7q/O\xe6\\\x9e\xd6\xb5Ls,{\xdd\xcaD\xa72\xc5\xa5\xdcs(\xf7{\xa3:\x17\xdd\xced\xa2+\x99\xe0Hn\x91<\xa5\x13yb\x17\xf2t\x0e\xe4\xe9\xdc\xc7\xc3g\xd7\xeb:\xf69\x8e\xb5\xfav8\xed\x86x\xec\xeawx?\\\xbd\xa8p\xb5\xfdt[q\xa3\xcbq\x1eD\x1e\xd3\x93\x96\x0fU%i\xa4\x943%_y\xad\xbb\x13\xee\xca\xeax\x95\xd4isj\xffAI\xfba\x19\xfb\xe9\x80T\xfd\xcb\xb4\xb8\xcfT\xfdJ\x80\x8ec24\x9b\xb9\xae\xea\x18\xa5\xc0\"\xe5\xe1nV\x05Q\x7f-\xe2:c\xc9H\x17.\xa4\x81\x05:\xf7q\xba\\7\xc5\x1bfQ\xfa\x99\x88Roho\xe34\xde\x97{#3\xd5\x85\x0d#\x0eRTx*-4\xfd8\x03\xe8\x0b\x13\x06\xd7\x9e}5\x13M\xbbJa\xf7\x17\xbce_\x15\x1d\x1a\x8d\"\xe3B\x8eTnR%\xad\x9fi\x84h\x87|(\x1dZ\xec\xfa\x04\xe8\xbf;znM\xb2\xd6k;\xd6\xf4\xe4\xe9[$\x9e\xee\x8dH\xf7 0\xbf\x8c!a\xc5y\n\x19\xff3\x8f\n/%z\xdd\xf4\xe9\xd0\x7f\x1fC\xc5\x86\xc5\xc9\xb1\xfbM\x9c\xb2dY\xb0$\xb9[j'\xd6 /\xfd\xc3;\x9e?$y\x1e\xd8*\x97\xf6\x04\xe9\xdb\x87\xa9\xa0!M\xc5RZ6\xcb\x1b^\x08B\x83\x96b\xb9\x96c\xff\xa0\x86\xde`\xab*\x1f\xc6\xb25(\xd6Ta'$\xb4b\xf8\x98\x97\xab}\\,\x8bxO}d\xb6\xfbT\xae T\xf1t=\x06\x8d~\xab|\x0eo\xfeL\xc3\x9b\xd5#\xf2y\xc1\xb2Q\xd2R\xe1\x19%,-&\x9b-\xb5\xf3\xa0@\xc6+\xce\xec\xa5=\x98U\xfa\xc5\xb2\x10\x90\x10\xe3\xc7\x86-\xd4#\xadi\x03Q\xec\x1f\xdf\x16j\xfd\x0c\xb3{<6\x8f\xd7\xdeq\xda:d;\x07\x17\xf4)\xec\x9b\xfb\xb2m|\x93r\n\xbb\xa6cK\xdc\xbb=\xe3\xed\xff4vL\xc7\x86\xb9O\xfb\x05\xb7]\xee\xcbn9\xda,\x0d\x15S=\n\xa4\xe4\"\xf8\x0e\xa9e\x83$\x19;h6\x04P\x82-\xbd\xcb\xc3H\xda\x9b\x03\x11\xb6\x85b\x1b;\xfc\xd7}wb\xf0\xe6\xdf\xc34\xc6\x02\xe8!\x9b\xf8u\x89\x96\xc53i\"\x1dt\x92\xe9\x9c\xf9\xa5\x9d\xc5EI/5\xc4z\xb2K\x9b\xe8\xc3_w0\xe9N\xa75o\xad\xcb\xdc)\xc0\x8e:\x01\x96\xc5>\xd0f\xfeo\xfcp\xe9tJ`b5p\x92\xc7I\xff\xad[\xdd{\x94:h\xcb\x97V\x0d\xa8\xd8\x1bz\xe6\xfa#s\xfd\x91\xd3\xd7\x1f\xe9\xee\x05\x01{MN\xdal\x06\xbe\xd9X\x9d\xb3\x9dO7\xb6\xbe\xe9\xa7\xe8\xea\x17\x1c3\xae\x1fK(D\xf5\xfd\xa0U`\xbaB\xde\x1b\xb2JN\x8b\xd67<\xdd\x16;\x13.D\xb3\xa6\xeb\x8ci\xd7\x98\xdb\x1f\x11\x06]5\x184j4a\x1ff\xe3w\xf8\xbe7\xe9\xae7\xde\xf8\x85\xee\xe0G\xa5\xfd\x83'\xf5\x1f\xc8\xab\xa5\x9f\xfe6\xe15\x00\xb0\\\x05\x80\xceu\x00\xd0>h\xf7zl~BX\x8d\xea\xf3Ak\xf1\xa7Rd\xe5\x9e\xc8\xcc\xa1I\x86\xd5\xec\x1fx\x16\xf1\xb4\x90\xbb\xa8TXj\x17\xcb\x0b\xf6\x857\x1e\x8c\xb8\x11\x05\xaf\xc4Cok\xfd]y\xd5KU\x8dD\x9a\xc7k.\x05R9\xd3\x9a\x92S\xec2\x9e\xcb\xf9\xbc\xa71J \xc9\x8a*\x87\xe3?y\xaeF\xa4\xafu4\xe5]Z!\x0bx\xa9\xbdq\xb8\x14\xfdz\xf1\xdb\xe6@nx!\x96\xf7<\x1am\x02\x88\x0d\xfc\xc0\xab\xb9QkB='^\xfd\xa7\n\xafw\x87\xe7\x9d19\x18\xbe\xae\x19`\x86\xfc\xf4\xc9\xbf\"\xa7\xd8\xa9\x1f\xfam\xd9\x11\x15\xd1\xc1\x96\x84\x19\xed\xb3!\xabnB\x97S\xef2\x0e\xb8\xf6F\xfb\xceXX\xde\x1e\x19}\xba\x9b\xf0\x92\x0ex\xde \x99\xf2\xb2\x0eLya\x07\xdc/\x91\x8c\xba\xb8\x03\x13^\xde\x01\xef\x05\x1e\x18z\x89\x07\xc6\\\xe4\xc18vwP\xf2b}\x95d\xc4\x85\x1e\x04\x976\xa0\xac/\x93\x8c\xbb\xd8\x83\xa0+\x0f\xd6\xd7I\xa6\xbe\xe0\x03\xe3/\xf9\xc0\xf4\x17}`\xdce\x1f\x18w\xe1\x07_\xa2(\x91\x93]\x03\x82\xc9\xaf\x02\xc1\x94\xd7\x81\x80t%\x08\xa6\xbc\x16\x04\xceWL\xc6]\x0f\xc2\xd68\xfa\x92\x89V5\xdeKC0\xfa\xe2\x10\x82\x10{\xcfd\xf0u\"\xb0\xbdi\xe2\xd9\xe2\x1d\xef\x9aP\xf6\xff\x81W\x8c0\xb5g}\xdd\xc4G\xc7\xb8\xebF\x1dd\xea\xf2\x11\xfa\xc6\xc9$\xd7\x8e`\xea\xabG\x80\\?\x82\xf1W\x90:\xd8\n\xe4\xb5\x93q\x97\x92\xc0wW\x07\\o\x9e\x10.(\x81\xed\xb1\x85\x80\x8bJv\x1c\xbdD\xf5Q\x97\x96 \x80\x19\xbe\xcbK\xe0\x1d\xb7\xf7\x12\x13\x84]d\x02\xb4r\xff\xc8\x0bM\xe0\xbb\xd4\x04\x9e\x17Q|o\xa28\xb8D\xbd\xe4\x04\x84\x8bN\x80\xbe\x8d2\xea\xc2\x13\xd0.=\xc1\xa0\x8bO`e\x8c\xf7\x02\x14Lw \n\xecT\xf4$m\xd2\x0bQ0\xf2RT\x07\x15\xf6z\xca\xc4\xd7\xa4`\xe2\xabR\xe0~C\x05{E\x05{Ge\xaa\xabS0\xe5\xf5)\x98\xfc\n\x15\x00\xf5\x1a\x15P\xaeR\x01\xfd:\x15\x10\xafT\x01\xfe\xae\n\xfe\xd2\x06\xfd\x02\x8e\xefm\x15\xf2\x15+\xa0]\xb3\x02l\x18S^\xb7\x82\xb1W\xae:\xb8\x907W\xa6\xbc\x84\x05\x93^\xc4\x82\xd1\xf2\xe0\xbd\x90\x05\x84KY\xd0z\x7f\xa5\x7f9\x0b\\\xa7\x99\xee%-\xf0\xe5\xd5z\xbf\xb5^\xd6\xc2?\xb7]\xd8\xc2\xbf\xee]\xda\xc2?C.n\xe1\x1fv.oAHb\xf3\xb1\x81=\x93\x7f\x9aDg\x03\xf7\x95\xf0l\xef\xef\xf4\x89\xcf\x06\x90\xcbT8I'N\x84\x0e\xa6\xe74\x89\xd15\x19\xfdK^8\x19\xa7K\x946`\xbf\xec\x85St\x9a\xc4i\x03\xedK_\xe0\xb9\xf8\x05\xc3\"B\xc8%0p\xfb\x8a\xd0\xcb`\x9e6\xfdKa\x9e\x06\xf6\xcba\xce\x86'\xb8$\x06\xb6\x8bbNBlW\x80\xa0\x91\xab\xd3\xbf\x074\x18\xa5\xe5\x02\x19\xcc\xe96\xff\x85\xd2m\x1c\xd7\xd0`\xa8\xe0X\xaf\xa4\x0d\xc48\xf9\xf54g\x02b7\xaeOJ\x180D\x91\x12\x10\xab\x8f\xc3s\x10\xcd\x18\xfe\xd9\xf2\xdd\xd1L\x83\xc1\x8a\xa1\xb0\xe6\x1bxt\x83\x7f\xa1\xc3\xf4Y\x07\xbe\xbc\x83\xa93\x0f&\xce=\xf0d\x1f\x8c\xce?\x986\x03\x81\x92\x830\"\x0ba\xda<\x04R&\xc2\xb4\xb9\x08\x84l\x84\xc9\xf3\x11<\x19 \xc3r\x12PD\xce<\x85I2\x15\x88\xb9\nh\xcb\xa0\xfc\x85\xd1\x19\x0cS\xe70\xd8\xb3\x18&\xcec8E&\xc3\xc4\xb9\x0c\xd4l\x86\x89\xf3\x19\xdc\x19\x0d\x93\xe74\xd8\xb3\x1a\x02\xf2\x1a\x86g6\xa0\xc8leR5\x8c\xc8n\xb0\xe67xM\ng\x8e\x03\xcd\xe2\x98.\xcf\xc1\x9d\xe9\xe0\xa7f\xd2l\x07w\xbe\xc3d\x19\x0fcs\x1ez\xe8\x94E\x83\x1a\x0f\xd3\xe6=\xd82\x1f\xc6\xe7>\x10\x02\xfe\xce\xfc\x07b\x06\x845\x8c\x1a\x98\x05a\xc7\x83\xc4\x96F\xe7B\x840\x87\x92\x0f\xe1\xe7\x02)'\"8+\x02\x8f\xbcM\x90\x19A\xc8\x8d\xf0eG\xf8\xf3#\x9c\\\x0b\xc9\x91\xa0eI\xe0y\x12\xa33%\xc8\xb9\x12C\xb3%\xecl\"eLL\x9a3\xe1\xa0\x05\x91\xc4Q\x99\x13=lH&\xc5\xa4\xb9\x14\xb6l\x8a\x91\xf9\x14}\x92\xfb\xf9\x15\xd3gXxr,\xf0,\x0b<\xcfb\xcaL\x8b\x89s-N\x91m\x11\x92oA\xcc\xb8\x08\xca\xb9\xa0g]X\xf2.l\x91vz\xac\xdd\x9f{\x11\x94}A\xce\xbf@\x074u\x0e\xc6\xb4Y\x18\x96<\x8c\xa931\xa6\xce\xc5\x18/#\xa4|\x0cZFF;'\x03\xcf\xcap\x9e\xc1\xb0\xcc\x8c\xb0\xdc\x0c\x7f\x00\x9f\xd0\xc0\x95\x9fA\xce\xd0\x08\xc8\xd1 fi\x0c\xc8\xd3\xf0ejL\x9b\xabq\xff\xd9\x1a\xfe\xe9>e\xbe\x865C\xc2+T\xa7\xcb\xd9\x08\xa2\xe9\xb4y\x1b\xd6\xcc\x8d\x7fL\xee\x86/{\xe3\xfe\xf37\xb0\x0c\x0e\x7f\x0e\xc7\xe0X\x9b%\x93\xc3\x17\x84\xb7esx\xda\xe1\x19\x1d\x9eF\xee\xac\x0ez\xdc\x7f\xba\xcc\x0eGn\x07)\x82\x8a\xc5\xd4}\x19\x1e#\x10;\xf2<\xec\x99\x1es\x89\xb1\xe0\xdc\x8f\x89\xb3?\xa6*1\xe6\xcd\x01\x19!Z\xceL\x90\xc1xO\x90\x0f2W7\x9b\xab\x9b\x9d\xa6\xba\xd9\xdf\xd0\xe4\xa2\xb0r$\xa6\x11)\xbd\xa8\xb1\x8f\x05'\x18\xa9M\xae\x9b\\D\x92\xdb\xff\xe6u\xff\x1d\xf9d\xc8|P&]5#M\xf8\x0f\xa2\xe0\xc13}#\x8a^\xadx\xd2D[\x93\xc3\xc2\x97\xb4\xa4\x81V\xefX'\x99\xb4?uo\xdd/\xf9!\xe3\x11+\xf8Zn\x11|\xc33\x93>\xf3Y#\xcb?C\x9c\xe6\x05g\xeb*\xd1\xaa\xde\x8bs^\xf4\xc3\x82R\xe5\xc5<\xef*\x06\x15\xacXk\xe7p\xbc\x81\xcf O\x1fU\xf8\x1f\xc3\xf3\xe7\xf0\xf4s\xe5pfE5\x08\xe5\xa4\xba\xe5*\x90\xfd\xb4{\xa0\xb8LU\xaeP\xe7\xaf:t\x1e\xb1\x9c\xe7gU2\x81\xa2U\xf9\xa9\xcc\xb9\xb7\x10\xf0\xc3\xfb\xebW\xcb\xf7W\xd7\x97\xef\xdf5\x8f\xc9\x0b\n\x87mW\\,8\x9d\xdf\xfd\xe7\xab\x8f\xce\xdf/\xbe\xfdx}q\xf9\xce\xf9\xcd\xbb\xf7\x9e\x9f\x97\x7f\xbc\xbc\xfe~\xf9\xc3\xab\xeb\xf7\x1d\xa9\xa8\xdc\x1d~\xc2\xaby\xc2\x04\xf0\xb4\x99\xcd\x984k\xf0\x98\xb9\xb8\xaf\x0b\x02&\n\xfb\xba?]\xd8W\xf8\xa4a_\xf6\xa6\x0e\xff\xc82\x81\x1a\x02\xa6\xf1\xd8\xc4g\xca\x03HU\xf9^/C\xd4k\xa5j\xc8UraT~|\xc3\xf1\x84(t3@\xbf\xb4O\x8fu\x80\x8d\x9d(\x15\xe7\xe2\xd0$\xcd\x12\x84\xeb\xcd\xea\xb3\xee\x1f\x1aH\xef\xaa\xfar!(+\x11x\x86\xfd\x11\x9aU\x88\xf5\x0e\x1f\x8c\xff\xdd\xfbg\x9d\xffnqa\x00\xbe\xa3\x8cu1\x1f\x7fi\xf7\xa1Nv7\xa6f\x9d\xb57\xad\xc0\x03\x97pKB\xff\xa80\xf0uC$\x8f\x84\x94i\xac\x12;\xeb\x9a\x86\xea\x1f\xf9!i\xd6M\xb5\xbbi%\xce\x066=\x92\xd4\xef\xb8\xb8\xd0-UQ\xc4\xbc\xe8z\xa4._\x9e\x19\x1f\"\xcf\xce\xea\x97:{|\xeaW\xe0kZ(\x14\xdbGQ\xe1\xae\xbe'? O\xa0W\x85\x07\xbbf\xcf\xcf\xc1\xf6\xef\xd6\xabG\xa7\x00\x95'\xfbr\x1f[\x9f\xbeS\xdf\xdcV\x8d\x1e\xa9\xdd>\x90\xfa\x7fC\xa9\xcf\x06T\x9e\xef_\x98iT\x9d\xb7U\x9c\x1fH5\xca\xf3\xa1\x15\xe6;<\x0f\xaa'\xdf\x90\xbb\x8e\x12T\x7fR2,?\x89\xd3mE\x82H1\xc5\x9fc\xf2\xfc\xa1\x91\xb8A\x90\xe7N\xc4\x05am/\xd2\x82|\xd3\x8e\xb0 \x1f\xe0\x91\x95\xde\x87\x13GT\x1a\xbc\xf9\xa1\x8eT\x10\x98\x82\x9e\xbe\x9dR\xd7R\xb4\x9d\xb36\xd2\xb0{\xd2\xb0\xaf\xaeqg\xeav\x04\x029M\x8f=G\xc3e\xb3\x83\xce z\xb2\xb33\xca\xfa\xee\x81\x8br\xc8r\x1d\xac|\x87)\xc7\x01\x8aph\"\x1e\x94z\xa7\xe0S8\x97\xf0s\xee\xec\x9a \xe6\xb2\"'\xd6\xc9\xce\xaa\xc4S\xea\xc9\xcf\xa7\x13\x9fLOy&\x9d\xf24z/\xe7P\xfc\x04jY~\x13\x9e:qch\xc8Is\x8a3fgo~\xdf\xd0I=V\xb4\x1fvw/Y\x9b\xaeqi\x18\x8b^\xf1h\x13\x92\x0e\xc15\xc7P}\xd1\x98\x94\nS_K\x9cH7L\xa2\x11\xa6\xd7\x03\xe3W\xff \xd7|[\xc6\xe3t\x1bx\xd8\xb4<\xcf\x88\xaa\x8a\x96\xa0y\x9fel}\xdd\xa4\xcdv \xa9p\xd0\x0e\"}=E\x1er\xd76\xf9\xefc\xfa\xb9\xac\x8c\xe9\xf4\x05\xa0:\xa3?\x92\xc9\xf4F\x1f\xf5@\xdd\xd1G4\x85\xfe\xe8c\x1d\xa2C0,\x13\xea\x11@\xac\x06\xf7\xd9y\x8c\xa5 \x17\xf2>N\x0b\xb9\x92\x03\x15\x96l\xb6\xec$\xe0\xa3+\xb8\xf2B\x16U\x95\x8eH\xc4\xea\xfe\xa2l_}\x13\xa7\x9bD9\x84\x97R\xd8\x97\xbaD\x0e\x0d\xeb\xbezU\x93\xa5i\xc9\x92\xaa\xba\x0e\xc4\xe9\x11'H\x9c\xbd\x8e\xf6\xeckX\x07>|\x1e\xaf\xc9\x11_\xe5\x8cB\xf1m\x05K\x96+\x91\xae\xb9o\x0b\xa8\xb0\xc9\x06\x92\xa9\x95;\x11t[`\x85\xd8\x9b{@\xabDD_r\xb9\xb1,\xef8s\xfb*\xac\xde\xe4\xaa;]Y\x8c\xaf+\xa4\xb2[\x90H\xfbBY\xed0\xfa&k\xe3!Q\xe3\xb4\x95\xb3\x0f{\xb1.\x13\xde\x95C\xe5\xcf\xbdP\xf3y\x95\x89\x9b8\x97\x9a.8qC\x0b\xc4\xf2Pc \x0e\xdc\xeeS\xeca4n\xe9\xaa&\x93\x1a\x93\xba\xf5\xabe\xb1\xf1\xa1r\x11\xba,s\xe7\x98\x9d\xee\xef&\x82']\x0c\x88?\xbc\xc5\xe5K#\x84\xc1\xec\xad\xc5w4[\x8f\x0b\xc1\xc2\xce\xe3\x0746\xf6\x06E \x1f\xd4\x8d\xac \xd4-\xc6\x0d|\x12\xdc\xf9\x0e\xaf\xfb\x05\xde\xca\xbe;.\x99&\xd3I\x812La\x83\xcb\x19\xe4W\xdc\xe0W\xde\x94\x1e\xc2\x948\xd8\x15yHg\x14\xdc\xc4K\x074\xe5\x0e6\x05O\xc1LP\xf4\xe0R\xf6\xce>\xfc!D\xba\xe2\x9f\xfa\x01]\xbd*j\xfb\xe4EC\xbc\x08\x0b./W\xf9\x81Enc\xa2\x15R\x91\xcf=Y\x16a\x1d$\xa8y\xc2\xf2]\x9cn\x07\x98\xd2y\xbcM\xf9zY-\xde\xdb8]\x8b[\xe2\xbe\xda\\\xb1\xfb8]V\xa8\xa4\x02\x08\xc2\xd3\xd8\x9f\xd7\xe26-\xe2=_\xfe\x99\xc5\xc9r]\xd5\xecp\xe2Qc_nT\x9d[\x91.\xd7\xa2\\%\\\xd1\x12\xde}\x0f\x97\xa6&\x14\x11f\x8d\xd6U[z\xbbk]\xe9r\xa5\xb34\xccdvL\xd4\xe6\x1c\x8f^q=\x8b\x94\xb6p\x9c\xb2\x02\x145\xdf\xd5\xf2\x1e\xb9!\xe1\xec\xa4\xd3\xf8d\xc8\x81\x93\"K\x8e\xe6V\x92\xbcr\x15\x8etr\x19\xab\xf7\xdb\xa9vQ\x9b\xdc~\x8c\xb7i\x9cn/\xd3\x8d\x08\x16\xde\x1b\x96\xa8\xe9\x88\xd3\xed2N7\xbd\x18?I\x8c\xd9z\x9d\xf1<'q\xff\xcf\xaa~\xc5\xb2L\x8b84)\xcaR\xbf\xa02l\xe3=\xcf\x0b\xb6?h\xcf\x1a+D\x06\x11KS\xa1j\xab\x96\xa9\xee\x17T\xbf\x8d\xf6\x85\xd8\xaf\xf2B\xa4\xb8 \xb7\x12\"\xe1,\xc5\x85\x07\xf9\xcd\x96\xa3u\xbb\xe3*\xa4\xaejh\x17\xa6\xd2\xab\xa2q\xc7r]e\xe4H <\xfa\x12'\x92XQ\x16 \xba9[u\xd3nx1\xe7\xc5\xe3\x96\"\xc8\xf3\xa3nQ\xd9]\xc4\xeb\x96v\xe5\xd2\xb0\x8dU\xb6\\e@V\xc8\xe1Q]\xde9\x97\xac7UgT\x10\x1c\xf8\x8d\xca\x9a\x8b\xdb\xc5}U\xaci\x99\xf3bj\nw\xe2\x16\xf6,\xd5=6\\\xae\x8a\xe9\x7f\x16:\x1bR;\xec\xb2\xd6-\x06\x873\xd7\xb4o,\xb8f\x04\xce\xfc\xfc0\x87jI\xc9\xb3\x83\xce@\xda\x8b4.Dg\x18\xc5\x8e\xc7\xadiL\xe2\x1b\x9e\xf2<\x07\xa9\xd7n\xe2\xe2\xaea\x8e\xe9au\xd7\xabQ$\xad\x0eU\xf2\x9f\xca\xea\xd3\xa9d*\xe0gViS3\xb5\xaf*#z\x84\xa2\xa7\x1a\xcd*l\xf2\xd4]\xfd\x93\xac\xb9\xc2\xf7]L]M\x9bo\x81\xea5\x87P\xdau\x9b\xa3\x91O\xbf\x8d\xd5pv\x1d\xe7\xd2rn=g\xd7t\xd3\xea:\x87\xb6\xeb\xe9;\x92\xc6#\xcdC_\xa7L\xaf\xf7\xbc\x9ao,\xa5\x83\xf5\x9f;if\x84\x0el\xcfU\xad\x0f\xfbZ\x90\xa2\x07]\xba\x8f%\xc9\x91\x10\xe3P\xc1\x12\xdc\x03L\x9c91\xdd\xe7U\xfa\xf9'\xa6\x833\xb1Xw\xd9\xd8\xf6D\xab\x08h\x9c\xc2V\x9a\xe2\xf5NXU\xe0\xcc\xa5\xc2\xcb8\xb4\x8b\nG\"\xd3\x1f\xaa\xca\xa1\xd5f\\\x17\xed\x94zP\x1d \x9a\xc3l\x8d\xcd|\xf9Q\xec\x8fD\xa1u;3~\xe0\xaa\xe0\xfc\xb7,\xab9k\xab0\xdb\x1a\xa3\x12\x8fn}Y]\x8e\xd3g\x1e\x04\x9dc\x9a\xed*|\x14\x03\x01\xd34d\xdb\xa0\xb7s#\x82\x8d\xef\xd6N\x87D\x7f\x87\x1e\xbe7c\xbb2\xbe\x1f\xdbvbl\xe1M\xb5\xfb\xa2\xfbnc\xc7\xf5\xec\xb5N.\xa2\xd1\xc8IvV\xc7\x9e\x1aN\xd1\xa0\x1d\xd4\x9266|\xd7\xec\x9f\x1cZ\xfb%\xbaS\xaa\xa5T\xa8'j\xe4J\xfaV\xa4\xeb\x8f\x8d\xc2\xba=V\xb4\xd3\xf4\xbe}\xff\xee\xa5\xbdJl\xf7w\xf9_\xce\x1f/\xdf}\x87\xfe\xdahX'\xda\xb8\xba\xc65\xf7ql\xb55\xd0(\xa7Y3\xb6\x99eg\xe9\xe4\x19\xa0\x192)\xc4i\x95\xabSO~\xa7\xb4,\xce\x12\x89O\xff\x0b\x9bi\x9d\x99_=\xcd\xa3\xe3?N|\x97\xef\xbe3\x08/\xdf}\xe7\xc4X\xa6+\xbd\xefX\x10\x1a\xf2\x08\xc4\x1d \xeb\x88\xd4\x0b\xb1\x97\x0b6$A,\xaa\x9b\xa8\xd8\xa2-p\xda\xd2f\xdd6\xad\xd8\x85z\x0fL\x1dn\xcdGP\xa5W\xa9\x9d\xdbx\xe8\x9a\xe82\xcetP\xbf)\x19\xe6\xd7\x00kP\xf6C4\x9cZ\x83{(\x1b\xd6\xa1\xf16\xdd\xea\xc1\xbe\xad\xd6)k\x9e\xf0\xad\xb2^\xcf@\x1557\x9e\xce\xc5\xc3\x06\xf2=\xfb\xba\x1cJI\xcfZ3\xc8Z,6\xe1\xd5.\xa9\xbaPek\xab\xeb\xa0\x93\xba\xb9\x1aQw\x08\x9d\x11\xe8p\xd9\xb4\x03i\xe0D\xc7\xb3fqr\x07q*\x05\"\xb7\xbc\xde\xd8\x18]=z\xcbP\xca\x834\x0c\x96\x01\x91\x0d\xcf+\xa7\x0d\x84FZ\xd4\xfb\x8d\xea\x0f\x98\xecHCX\x0f\x1a\xcb\x13=\xae\xd6\x9a\x1b\x0d\x04\x9d\x84\x1e\x93\x81\xd8Z!\xd6\xe5\xff\xe1\xb8\x94 :\xa0=\xc9(\x87N\xb4^\xfak\xc5\xdf{K\xb4\xc6\xae\x0f\xb5\"\x9a\xba\xc8\xb56\xac\xebb\x00\xd1\x83\xd6B\xc3\xfek\x90\xec^\x078\x19\x1dQ\x19\xa1\xc1\x8d\xf66[9s\x8a\xe8K-\x12!;T-EK\xca\xf1\xa13\xe0^c#\xb6+\x1e\xed\xfe\xf5\x9bs\x9eF\xa2zLB\xfdZ\xbf~R53S_\x8fi\x08\x11\xbd\xc64\"z\x9ba\xbec\x19\x0f\xeaY\xb7\xa8f\xb7929\xa9\xd5\x8f\x19\x8fx|\x83j\xa8\xda\x9e;N[7\xf8&m\x11\x9di\xab\x8a0\xe7\xb0\xe3\x89*k\xccR`\x91\xb2\xf7\x17p)\xcd\x96\n\x95\xb8Mu\xddc\x916\xf8\\=\x8b\xa8\x1e\xfa\x14Q\xac\x8e\xce\x1ak#\xe1^\xdcjO\x85HywZ\x9c\xa2\x16\xec\xc3^w\xa4\x14m\x867\x05\xb7\xc4\x02y\x07\x9dJr\xc1-\xbdt\x82\xa6\x92b@$\x99NE\xb8D\xf7P\xfc\xad}!x2\xc9\x86\xa9\xa5\x1b\xba\x12.a\xc5\x12\x96\xf6\xb3\xad\x88\x82I\xcdL\xc4j\xb7\xfb\xd5M\x8b\xb3\x83k\xb4\x1fQ\x8c)\xcd~ta\x19\xa0\xd5_\xf7)\xc0\xa6\x8fMb\xb9a O\xd5\xbd\xeb\x86(\xf1\xaf\x11?\x14\xd5\x81\xadh\xbc\xdd\xd9\x9e\xc4\xee{C\x95\xfcV\xa3\xcaa/2\x0ey\x19\x17\xca\x1d+\xcd\xc0(\x89eo\xc6\xb1\x97\xa3z\xef8\x00\xaa\xc2\xdb\x8b4\xfe\xe2\xf5\xcb\xb4XS5i\xcc\xf0\xae\xdc\xb3\xf4<\xe3l\xad\xc8U\x0fe\x19\x9fcO\x8c\xf5s\xed\x85;+\xd0eD\x19\x04M\x9f\x80\xbe\xe2\xc1\x92\xe3\x8f\xf5\x9c\xc3#\xfeu\x01\x9f\xaeDV@\xcb|\xfa\x03\xbf[\xb1\x9c?6\x84\xdd\xf2U\x1e\x87\x19wU\x13\x94\x12\xf3[\x12\xa7_\xea}\x9cGe\x16\x17wK%\x17\x91\xeb\x16J\xaf\xafn[\xb4S\xbeg\xb1zk\xbd\xfe\x1c\xaa\xcf\x0d k^\xb08 \xb2%\xaa&F\xf5\xeaj\x04u\x97\xd5\xaf\xc8\x1aj\xc8#\xea\xd5h|\x8cH\xf3\xf7q^\x88,\x8eX\x12\xe4i\xdeq\xb6\xee\xcb3IIVoOwt\x9fv>\xaeX\x1eG\xda\x1b\xaa\\\x81\xedo\xb0>\xc0\x11\xc8\xaer\x89\xbb\x7ftl\x85\xe0\x8e\xf9\x00\xb0\xc3a:t\xee\x13\xfd\x0b\xa9\x80\xd2\xbc\xcc!b\x07\xadV\xf5y\xd0\xfc9+\x93c\xbd\x9a\x88\xe7\xb9\xf6\xf1\x18\xeeu\xd0\xa9-W\xfe\x14\xedX\x9c\x9e\xf5jz\xa7QR\xea\x07\xdf\x92\xa4\xf1\xa1<\xb339\xb62\xd24\x98\xfb\xd1\xbaw\xd4\x87\xc0\x8eO\xb0?\xec\x15\xc3\xcc\x0by$+2\x96\xe6Z/\xefY\xb4\x8b\xd3\xd6\xab\xcd\xaagj\xad\xf5\x1dr?\xdd:#\xb6\x10\xf2\x804:,oA\xbd`\xa8\x98\xd7\xa7^K\xf8!\xe37\x13\n\xf8\x8e\xe5\xbb\x81\x02\x89\xbc\xdd}`Y\xa1\xe2\x08\xdd\xe5m\xc0J!8\xa9TM\xfba\xd7\xfa'\x855N\x0b\xbe\xe5\x19\xfa\x85+\xf2\x0fV6\x80\x8f\x15\xe0fG=iW,+r^|\xaf\xb8\xd2\x9dnu\x8c/\x96}\x12\xbc\x12d\x0b\x93KTzmiA\x91K\xb0\xf1\x9d\xfc\xcf \xba;\xe6\nL\x80\xacK\xfb&\x13{\xa5&\xd8\xe1\x00\xa2,\x0eeq\xfc\xdbq\x0d40\xa8T\x80Ii\xaa5\xe5\x04\xb8\xd8\xe10\x01\x16%/U\xb4z\x02t\xfcF\xdaa\x11\x9f\x00U=\x7f\xc7\xed\xa5\xa3\x9e\xf4-l\x1ez\xc4\xf5'\x1d\xebU\xd5\xf2\x90\xd5\xdb\x8d\x8eg]\xf3t\xcd3u\xddR/\x08\xad\x9e\x1a\xbe\xa3\x9c\xf7\x8c\xbcis\xe2\xe4_\xed\x07|\xa7\x9aq\xef\xf2}\xd4-N\xd8\x0e\xfb\x0f\xfbO\xe4\x19<\xffG9\x0c\xc0\xb8\x0b\xe2T=\xbd\xbah}\x7f\\\x1a\x87r\xd5\xcb\xefq\xeay\x97\x96\x97\xcd\x96e\x86\xaay\x8f\"\xf6q T\x1d\x97O\x1f\xde<\xc9x.\xca,\xaa\x0e@\xea\x08X\xa6\xf1O%O\xee\xaas\xc9&\xae\xb8WT\xd7\xfe\xb0\xa7\xafA\x1d\x14\xcc\x13\xccxi]ul\x8dD\x02\xabr\xb3\xe1\xf5\xf3\xb3U\xe52=\x16\xd8\x97y}\x02\x05V@\xc2Y^\xe0\xf8D\xca\xe1\xc1\x93\x07\xca\x0b\xce\xa2\x82g\x0bu\xf8VA\x8e\x9co\xe5\x11\xdb\xcc\xf4\xa7\x0fo\x1e\xe6p`\xc5Nu\x80\xa2\xab\x1d*xo\x05\xf2f\xb7\xe2Y\xd5\x85\xe2\xce#&W:\x8e\xe0\xb3\xec\xde\xfa\x02\xee\xe7\xc7\x9az\x852\xdf\x892Y\xc3J\x1f\xb9Ql\x11KE*\x0f\x1aJ'\xe0=>\xe2\x8b\xed\xe2L\xb2P\x99\xa2\x0f\x16\x0fL\xb0\x98E\xf2\xc4\xcf\xd7\x8f\xf1G\xe6TE\xf4\x83r\xccG\xfc\x0c\n\xce\xf69\x94y\xa9\x8a\xee\x1d2\x1e\x89\xfd!N$u\xd5\xb3\xc3\xab8e\xd9\x9d*\x01\x87a\x93\xbc\xc9\xb5p\x15;~\x87w\xa9o\x14B\\\x98\x1awU-X)\x0c\xfc\xab\x9a\xca\x8b\xf4n\x01\xdf\x8b[~\xc33}7\xee\xd3\x877\xfd\xb5\x0b*\x87%\x8ev\xe6\xb1u\xbc\xc3<\xda\xf1=\x87\xcf\xbb\xa28|>\xd3\xff\x9f\x7f>\xd3i/\xd5\xafgJ\xca\xa2\xc6q5\xb9C\xeb\xd5\x83\n\xe1\x01Sc\xb5\xf4\xc7\xb3\x1b^\xc5\xc5\xf7\xec\x90k\x91\x91#P\x97h\xabl-\xa5\xaf\x94-\x9f\x03\xf2t'\xa8] I\xc4m\xfe\xcc2w\xbf\x84\xcb\xcdq\x04r\xca\xcd\xbb\xf9\xf5 +\xef^\xb9\xe7kK\x1d\xec_\xc2E\n\xdf___\xc1w\xaf\xaeA\xa4f\x19\xe9\x05\xaa\x1f\x8e\xc7%\xb3\xf7\x9a\xf4\xf5\xdd\x81\xff\xf8\xa7\x1f\xd1\x8f\xc1d\xdc\xa5F\x86\xf4\x16\xa7f\xe1\x90\x89u\x19q`)\xf0,k\xfbd\x8f\xf0K\xb88\x9e\x90r`\x19\x97r(nuT/b\x91\xd4 B|)\x0fuj\xdb\x8a\xe5|\x0d\x02\xaf\x16nSo\xa0\x1f\xd6WIP7J\xac\xf6\x8d\xb5\xb0\xd6\x8b\x81\x99a\xd49G,\xed\xd6\xae7\xa0\x89R\xcb>\xe3\x1b\x91\xf13\xd3X\xe2dE\xbc\x8a\x93\xb8\xb8S\xf5_M8K\xa9\xa8\xec\x86\xaf-8EZ\x85pU\x03\xb5\xee\x16\xf0\xe8S\xce\x8d\xa3\x80\xeb\xf7\xfe\x95\x9e\xd1r\xc7R\xb6\xb5\x8dx\x95q\xe5\xdb0H\x17\x8fqiy'\n\xfe\xac\xaa\xf2X\xa6\x91^)\x92\xf6J\xdfT7\xf8\x93\xbbf\xbefje\xb5P\xa9\xa6\xfdTM\x0dF\xb0 \xe3rw\xe0\x95\xbf\xba\xce\x84\xa9\xafU\x1d\xd7\xd7\x8aoc\x95\xf9\x85\xeb\x8a\xb8\xd8Y\x94~\xff\x0ds\x9b\xc6\xfc\xa8V[^y\x9a\x8a\x1dK\xbb\x9a\x05\x1eU\xeeE\xbe?\x14w\xd5\xf2|\x8c\"\xdb\xab\n\x9b+\x8b\"Q\x03T\xbe\xe9\xda\x97\\E\x14\x0e<\x8a7q\x049\xdf\xb3\xb4\x88#\xe4\xe9j\xe4J\xac\x06\x8fI\xe1<\xd9\xd1,\x8e\xb7Ru\xac\xb8\xf1\xa75\x0c\x86\x9emPm\xaal%n,\xc6\x86\x1ej%\xce\xdda\xfa\xa8\xf9|\x91\xde}n8\xbaS`\xd9*.2\xb9\xf8\x1cTU:\xba\x87\x8e%\"\xddV\xd1\x82\xfe\x94I\xad\xa9\x94\xbe\xa6j\xd57\xa7\x9a}\x1a\xab\x08\x11\xb3+#\xf8I\xbcR\xa4Vz=\x87\xbc<\x1cDV\xe8\n\xcb\xd1\x97'e*\xffO\xee\x97z\xbe\xf3\xbe\x07\xab\xb2hP\xe3Al\xa0,\xb4\xf21\xcb9\x97\x8a\xcfx\xffY\x02[\x9e\xaaBT\xeb*rQ\x1b\xd5\x17\x88\xbe\xd3S\xd4\xef\xe7\xd5W&\x05\x18\x9e>\x83+I\xaf\\\xc7\x15\xe9\xac\xde\x10\xe3\x14^\xfc\xeaW\x96m\xea\xb5\x10\xb0\x11\x02\x9e\xc3b\xb1@\xd3\x95\x15\x13Xz\x87\xff\xc8\xd2\xbb\x85\xec\xfau&\xf6\x8f6B<\xc6?[,\xf0\xbd'\xde\xc0#\x89\xe2\x93\"\xfaZ<\xfa\x17\x89\xe31\x9ee\xed\xc0\xf3w;o\xbe\xf1\xf0\xe6\xf7\xec\x86\x8df\x0e\x82\x0bq\xfe\xe8\xb5\x10\x8b(ay\xee`\x82&I6\xd0\xe3i4\xc2\xfbE\xb8S\xb3\xe7_=\xec\xb9\xba+v\"\xb50HS\xf2Z\x88G\x8b\xc5\x02\xd7\xc45s\x1eY\x7fW\x02\xa4\xd8\x16\xca5\xd9\xf8R3\xed\xe5\xab\x8f/>\\^]\xbf\xff\xf0\x18w\xbd\xe9\xae\xb4\xa0\xd9;\xd3\xdd\xd9\xd9\xf5\x1b\x0f\xbb\xbe\x138\xa7\x14\xab\x9e=\x87\x7f9\xac\x16\xaf\x85\xf8\xebb\xb1\xf8;\xfe!K\xef\xce\xa4\xb9&\xbf>h\x03\xe4-\xcb\xf2\x1dK$\x13\xed\x84\xdb\xd8\xd4\xed\xd9\xd2m\xbc\xe9t\xfa)\xdd\x1f\xbbUD)\xc1V_\xfd\x8f\xe7\x90\xc6\x89U@\xed\xb4 \x92x\xad\xeetG_j=h\x8cmX\xdd\x1dM\x15\xa3\xb1U\xf5\xeb\xd5\x9d\xc9V\xeea+sd\xcf\x7f\x88\x98!O\xe4Yt\xa1~\x90\xa6\xdcC`\x8d]E\xee8Ud\xa1\xdf\x83\x9a\xf5~'\xb5\x1aO\x93;sn\xea\x1dxk\xd3\x11\xd8\xa6\xe0\xda\x9a\x91\xe7\xed>\xc9O\x1e\xf6\xbb\xa8\x0et\x86D}\x82\xe3\x95d>\xd8\x08\xb1X\xb1L\x0d\xee\xeb\x93\xbb\xc5_\x1ehn\xe9\xb3\x06~\xacR\xa4<\x90\xdf\xca\xed\xa5\xf7\xf3\xef?\xbe\x7f\xd7\xff\xeb\xf3\xe7\xff?{\xff\xda]G\x8e\xa4\x87\xc2\xdf\xebW\xc4[\xefY\x96j,\xb1\\\xed\xf1\xf9\xa0\xe3\x9ee\x8ab\xd5\xd0\xae\x92tDj\xc6m\xafY\xac\xe4\xde \x99\xd6\xde\x99\xbb3\xb1)r\xce\xe9\xff~\x16n\x99\xb8\x04.\x99\x00\xab\xab=\xc0\x87\xee\x12wf\xe0\x92@ \x10\x11\xcf\x83?\xfe\x11\xff\x8e\xec\xf9\xd9\x0f l\xaa\x9e-Si0\x88\xb3\xcaq$\n\xb0rw\xdc5\x08\xaa\xd0\x15!R?\xe6m\xfe\xd5\x0c\n\x92\xab\xef\x95\xb4\x1f\x10\xef\x81\xb6\xed\x8a\x94\x82_\xff\x0b\x1b\x8e_\xe5!w2c\xf4\xc1=QK\xfe\x8d\xc7\x88n6_\xd8\x9a\x9f\x0fk\xb7\xed\x8e\xe0\xfaW\xe9\x87\x8fd\x18\xfb\xce\xbbl\xa4\x07\xe7\xb6\x1dFz\xcd\xbf\x8c\x0fB4?\xcc}\xb8\xf2\xd9?\xa4k\x7f\x00o+\xbe\xe5c\xf3\xed\x1b\xf8\x16[5fwOD\x8f\xbe}\xe5\x93\xc5\xfb\xf2\xbe\xd93y\xffY4\xf9\x1f\xbc\x0f\xb3\xbeX\xcf\xa6v\xe8\xe2V\x1e\x0c\xcc9!\xbef;\xc2W\xb2\xdb\xbd\xfe\xd2\xf5_E\xfe\xc9=\xcf\x9c\x94\x99#\xf8$7\xa7\xe0+a\x80Z\xf3R(#\xadZ6\xd1\xba;\xe4\\\xcf\xa7\x9d[\xc9\xaf|A\xa8y(\xa8\xfd\xb4\x9c\x16\xbe\x9c\xac\xa4\x11\xf6\xb3\x9c\xbe\xae<^\xcd4s\xe1%\x87\xae\xc8\xa1p\xdc\n\xcas\xf6/\xff\xf3_\xbe\xf3L\xf2\xdc9bV\xe4\x9f&|\x18\x98\xb8\x1fN\xfe\xf0\xc3\x1f\xc6o=\x9f]\xff\x97\x00s\xe1\x9e\xe25X\xea\xd8\x89G\x82\xc7\x14\xa8QA\xbc\x0c7\xf8\x8c\xee\x92O\xf3\x18\x93\xc0o8\x02\x15D\x86c\xc4\xcc\xedr\xd4pBs1\x13C\x0c\xb8\x8d\x8d\x8a\x81\x97\xa2\xd2\xef'\x18\x8a\xfc/\xee\xb14\xc5\x06\x8e\xad\xbe\x9b\x0b\xc2\xe0$\xff\x93\x06L)\xfc\xd8\x0cX\xf2=\x87\nK\x021\xa9\"\x12\xfd\xd6\xc6Nd\x9a\xa0\x9b\x9a\xc8\xfdf\xfc\xb7\x97m\xb7\xd9\x9d\xc0Hv\xb7\xaf\xe7\xbcE\xeb\x0b\xcc\x99\x9fX\x9adz{\x909k\x8b\x9ec9\xe2v$\xf1\xc7v\x1c\x8f\xc2\xd7\xd7\x04#:s~\xbf\xdd\x01+\x03\x0d\xffI\xff\x87\x11T\xd2\xffN\xc9\xb0\x1f\xfdid\xaa\xd0u\x01!'\xefm.\x11\xe7M\xc9\\\xb8\xb9\xb8YqsY\xd2 \x8f\xbbh}\xce\x1c*\xae\x1f\x9c\xec\xb9\xb98ytsY\xd2\x93\xa5\xb9us\xf1g\xd9\xcdeIK\x18\x07\xd4\xce%\x08\xad\x9dK\xe1\xae/\x06\x1bz\xa5\x99g\x8b(\x04w.(\x18W\x93\x9b\x16*\xf3iVH\x1c\x905\x08^\\\xa1\xe8\xa8^U8\xc9'\xd9\xdd^c\xf81Q2lwD\xbas\xda{1\xf2\xb3\x05l\xc9f\xd7\x0cd\xab\xd8\xb2\x1da\xf2)%H\xefG\xa8\x1d\xff\xa4e\xed;\x99\xfc\xaf\x80\xf6w\xe2\x10<\x81\x9b\xc4\xb9B\xa2wd\xa6\x13.\xf1\x85\xe05Pg\x10\xe9lm\x07 \x8f\x92\xac\x9c\x7f\x10\xbe\x9d\xb5\xddx\x02\x97\x92\x95\xc6\x10\xa7\xf2\x11\xec\x94\xa1\x86\x0d\x89\x98\xdd\xd2gj\x88}%\x12\x1cx\\\xbe\x1f\x06\xb2\xa1\xb0iv\x9b\xe3N\xb9\x1b\x0da\xb7Gf\x1d\x9b\x15\x1c\xbby4G\xde\xff\xfeH\xa1\xa5d\x10\xfbC\xff\xc0\xcf\x07\xd3\x81 \xfe\xf9\x9et\xa2+\xd0\x0c\xe6|\xd6\x8f\x8df-<\x1f@\x1fpc9\xb6#\xdb\x8f\xb6\xed\x04/ktp\xdc\xd7\xfb~4\xeb\x99\xb8\x9f\xccJ\xf4\xcf\xd0\xce\xa9\x1d\xbc\xb2\xf9K\x8a\xa6\xcfM\xe5\x94\xdb\xc2Go\x1b$2W\xc1\xac\xc5\x18\xff\x13yi\x92D\xc11\xcdzC\xa6O@\xb6\xdc\x17\xcf\xa7\x92$e\x17\xcd3%\xee\x8f;\xda\x1ev\xadh\x84)\x9f?\x88\xcfl\x13a2\xfb~E\x12'\x9f\x88\xda\x88\x0b^\x99\xb6\x13\x1a\x89\x8d+G\xe7KY\x02\xa3\xcf\x93@\xa7\x98\x11\x87\x08\x02\xabC\xf4\xe3\xd0\x0c|\x00%\xc8ER\xd3\xb2\x95K\xf9L\x14F\xec\x81\x0c\xe228\xee\xde\xeb~\x95\xc2\xf6\xfd\x9c\xbb7\x10NSo\xb6_\xfd\xf8\xf2\xd7\x8e\xe7$\x8d\x84Nd\xb8v\x85\xbf\xdeO\xaf^\x93\x8e\x0e-\x19\x7f\x9dm8~\xa6\xb3\xd08\x0bI\xb7}\x964\xaa\x05\x8d\xafc\x99\xc2R\xcf \xb3X:\x0fyL\xdd6h\xd9n7'i\xdb5\xda)\xfc\xf8 \xc5<\xda\x1b\x02UC\xd4\xc69\xb3\xa7\xcd\xcf\xe8M\x91\xa3Z\xa0\x1d\x0e\x81\x80\x14\xad\xb5\x08\xd4\x9fx\x10\xa8\xe5\x8ax\x1a ]\x13\x18\xf8\xb7\x81h\xbf\xbc<\x90\x01\x0eM;|O\x87\xb6\x9fN\xf5\xee<)\xd0#W\xa8\xea\xcb<\xaa\xf33S\xe7h\xaf\xd6\x86j\x1d\xeba\xd2-IF\xf5\xf3[\x86I\xc4\xfe\xcc]6\x1b\x01_\x9dq\xaa\x88\x0e\xf1\xdd\xf1f\xde\xc3c\xae;lU\xf5\xfd.yMu=\x95\xb7[\\\xdb\xeeJ\xa4\xd3\xa9O\x1a\xdd\x9a\xefW\xe8{N\x158\xe7\x7f\x0d\xcd\x86\xf7E\xdd\x8d\xd1mY\x83^\xcb\x7f\n\x8c\xefx<\x1cvO*F\xc7~\xfaF\x8d\xbf9\x9a\xd60p^\xba\"\xa8\xfd\xeb\xc1x\x17}\x1f\x97a\xca1\xad7\xef\x19\xce\x7fz\x8b0\x01@\xcc\xf2\x8d\xd9\x84H\x0dI\xa8\xfc\x90 \xdbv\x8f\x90\x07@~\x1f\xd61\x0b\x84\x04\xd9}\xc0\x1d\xe9K\x1a\xbe\x8ew\xc0\x11\xe3\xf4?\x9b\x7f\xc0\x92\xd7:\x80\xc6|J\x02[`\xe7\xe4\x0d\xa0\x03\xef0\x15\xc0\xdaE\xe4\xb0\x16@\xf8\xdba\xec\x05\xc1W\xc2\xdfh5\x93\x81%'\x87\xce\xc0\x12%\xc9\x0d\xeci\x9e\xc4p\x00\xc1\x0e\x97a:\xd0\x04\x1a\xf9\x9b\x99\xc4\x07\x9a$\x83\x02\xc1\xd7!\xcf\x96\x02\x91\x0bh\xb4\xfe\xf9\xae*\xf3\xec[\xfd0\xbf\xbb\x9c;\x1d\xd9\xc1\x9cM\xbb,n,\xe6\xa9X\xec\xb1M\xd8\xf1\xa2\xde\x9e\xf8\x8eQp\xdf\x0b\xec|I{_\x91\xde\x14\xdb\x01\x03{\xa0\x7f\x17\\\xd6\x85\xf5;a|,\xf2vCG\x9c`\xe7q\xfe\x9c\xb9#\xba\xf2n\xb1=\xd1\xfb)\xd0}1c\xc1\xa1\xbbc\xe4\x9b\xfav\xc8,\x0fe\xa9}\xb2\xe8N\xe9\xdb+\x97\xec\x96\xe1\xaeg\xed\x98\x86$\x8d'\x08\x9b1\x05vMg\xdf\x04\xbbs\xd8\x1e4\x7f\xd4\xdd\xceZ\xf1\xe3\x8b\x99\xe0\xdf\xd5\xa4\x18\xbd\xbfQ\xdb\xfc\x80u\x8a\x9e\xfe,\xdd\xb5\xaa-s\xab\x17\x9c\xe8\xea5\x01^\x8e\x97\xbf\x99k\x02p\x0fE\xd4\xf6\xf2\x9az\xba\x80\xef1 \xd8\xfd\x83>\xa3\xef\xb3r\xb3\xe5X\x7f\xb3\xcf\xf3\xb75\xfe\x9e\x855\xa0\x90}\xe6\xb1\xcd\xa2vYF\xcb\x0b\xd9b\x9e\xcd\xdf\xf1\x9f\x8a\x82}^Q\x9c\x8f\xac\xbf\xb0\x8a\xe9F\xe4,\xf4\x9d'\xa3G\x94\x88E\x18\xa7\xbc\x89\x0f\xb4(Vk\xd4`\xcb\x7f\xa9\x8c\x1e-w\x05h\xdf\x7f\xf1\x08;\xec\x9a\x8d\x03]\x04\x91\x00r\xd8\x11^\x8f/\x04\xbd\xa0\xcf\xa10\xb4\xd5o\xabb\xd5\xbdc\xd7>\xce\x19\x8c\n)\x95\x08)\x89\x06)\x8d\x04)J\x81\xb4\x80\x00 \xa3?\xf2\xf6\xdf\x18\xed2\xd4Gs\xce\xc8\xfa\xfb!\x9d\x19i\x0b\xcd\xa1<\xd2\xf0\xbb\xdf\xe0\xf5\xfb\x1b\xa6\xfd#\x8f\xec\x88.\x0fZxi\x8e\x82\x0e\x0d\xa3\xf9\x85(\x8e\xfc\x04G\xe9MA\xdd'\xeb\xa9\x8dL8\xa4*>b#/\xadQz\xfb\xd7R\x1a\xc5 \x8d\xd2\xdb\x80\x8ea9*#\x0f\x91\x91\x97\xc6(\xbd\xe1\x8b)\x8c\xc2\x04F\xde\x8a\xfd\xe9M\xe1q,L\\do\x9a^\xda\xa2\x10iQ\xb4\x93x>SjG3\xc9\x8a\xe6.F\xa9\x8a|DEv\xc6\xd5J\x9a\xa2\x15\x9a5NP\x14_ve\xc9\x89\x16R\x13y\xfb\x0c\xd1Yo\x9f\xac\xb7O\xc6\xd3\x18\x13r\xf7\xea\xed\x93)\x83\x93\x92\xda\x18\x1f\x85\xa4\xf4\xc6\xc5 \x8e\xf5\xf6IYR\x12\x1e\xeb\xed\x93\xf9\xe9\x8f\xf5\xf6\xc9\xc5\xa9\x91n\x93\xeb\xed\x93\xa5\xd2&\x9f#qrI\xeadb\xf2\xe4\xa2\xf4\xc9\xf4\x04\xcaz\xfb\xe4\x9at\xca\xb2 \x95\xf5\xf6\xc9PjeZre\xbd}\xf2Y\xd2-\x83\xc7\xd6z\xfb\xa4-\xbdx\n\xa6\x9b/\xb9\xb6=AN\xb0\xfcTL\xf0$c\x82?\x1d\xd3\xc9$+\x94\x90\xb9: To\x9fLL\xd1D\xc5\xd5\xdb'\x8b\xa6l\xd6\xdb'\xe7R8\x89sA\x1ag\xbd}R+\x85\xd2:W\xeb\xe7xrg|T19y \x9e\x8bS<#I\x9e\xb14\xcfz\xfbdn\xc7\x8a%~\xe6\xa5~&&\x7f\x16\xef\xfa\xe2\x14P\xaf4Zo\x9f\xe4\xa5\xde>Y$\x8b\xb4p\x1ei\xbd}rAN\xe9\xbf\xbd\xdb'\xc1\x9e\xddsv\xa6\xa1\x16\x8dQ\xad\xf4\xfa\x95\x14\xf5\xafM\x8a\x1a\xc8DN\xa3BE\x04$$@\x9b\xf7\x9a.\xce}\xbeoG\xeaY\x15\xec'c=h\xd7L\xf2\xd5&\xf2\x1a\xe5m\xae\xe2\x80\xb7ja\x88+d\xb1Y\xb4\x08d&S\xbd\\\xcbE\xce\xae\x9bfl7\xe2\xd6Y\xde~\xf7\xb9\x90\xfd\x1f\xb6\xfe\xb9T\xdcP\x8c\x9a\x89\x81u!Js8<\x8f\xe8\x985\x03p\xa6r\xbca\xd3\x1c\xc4%0\xc2\x02S\x7f\x1e\x8e;y\x95\xeaa\xe87d\x1c\xc59\x8b\x8f\x07\"O\xeaQ\xfe\xf3\xe6\xbei\xbbWX\x08\xa3\xed6\xbb\xa3\x88\xc9\xecv\xda\xc3\xcc\xb4lX\x7f\x8f\x1b\xd1\x16i\x80\xc8Vx\x93\xb4\x9b9S\xf2\x05r\xd1\x91p\xdd\x13\xa0C\xd3\x8d\"d\xb3o6\xf7m\xe7$X\xf1V\\\xb7N\x00#\xf8)|\xf7\x07\x04\xbf^\xc8/\xf3\x0c0-\x1e\x90\xe4\x03\x8d\xf7N\xac\xa0\xc3@\x1e\x9ei\x01\xdd7\xe3}\xe6$\xf7\xa4\xe8\x1d\x9a\x81^\x8f\x84^cjF\x95\xc8\xd1?\xd6z\xc0\xb7B\xe3g^\x83}\x01\xb0]\xe2\xd7E\x84\x86\nR\x86\x0b\xe2C6}\xf0\x8f\xcd@GB\xff\x91\x8f\x1c6e\xf8Q\x8c^\xe3MJ\x9a\x91h\x13d\xf5L\xacX\xd7b\xd2\xb1\xe5o=\xcb\xfeT\xb8\xfa\xd9\xaa,,\xd8\xee\x17\x8f3r\x83\xfdp\x80\xfeH\x0fG:\xffm^k\x96\x14n\xe6=[\x1bgPOY\xb9\xcd\xe1PX\"\x9f\x7f\xd2\x0e,,\x9a\xb0SR\xb7!\x85\xc5N\xdf\x7f\xde>\x115\xca4M?\x92\xb5\xf7\x08{\xeb76{\xb1\xa2\x0d\xebn\xdaV\xc5)\xea\x8at[2\xec\xdb\x8e\xca\xc5'\xd4\xa7\xbe#>4\xbb\x91\xa0L\x11\xee\x0d=\xe8\xfd<\x01\xad\x1b\xd2\xb71\x1c\x1d\xc4\xc6(\xc5\xf2)\x87\xa9\x83\x85\xb8:H\xc0\xd6A|\xcf\x8a\xedX4\x80\xb3\x83\xf8\x08B\xe2(B\x06\xe6\xce+\x90\x1a\xc9\xe3\x9e\xdc\xcd\x95\xd8;\xaf\xb0\x00&\x0f\xd6\xe2\xf2\xbc\xd2x\xa3\"\xd8<\x80\x02\xf8^Q\xcc\x1e\xac\xc4\xedy\x85q\xb4N\x02v\x0f2\xf0{~\x81\x84\xc60|P\x12\xc7\x07q,\x1f\x94\xc2\xf3A\x16\xa6\x0f\x96\xe3\xfa\xa0\x04\xb6\x0f2\xf0}\x01\xfd\xe49\x1d\xabR\x18\xe7\x07\xcf\x84\xf5\x83\xf2x?X\x80\xf9\x83\xd5\xb8\xbf\xa0\x0e\x0fc\xff`\x15\xfe\xcf+j\xc2\x05\x060\x80 M\x80D\x1c \x94\xc6\x02B\x14\x0f\x08\xb9\x98@\x08\xe1\x02!\xcd\x04\x8a\x9e\xa4\xd3\xad\xa4\x928A\x88b\x05!\xb1e\xeb0\x83\xa8(\xb5G\x84q\x83P\x12;\x08y\xf8AT\x9e\xdc\xe8\xfd\x86M\x06\x8e\x10\x95\xc7\xdaC=XB(\x82'\x844\xd8\x1c\xc4p\x85\x90\x8e-\x84\x10\xe0h\x05\xc6\x10\"\xf2\x02\xb8Q\x08cGaE\xef\xd6cH!\x11G\n+Z\x15\x18\xf3\x92\x98R\x08\xe1J\x817\xca\x8b-\x85\x15\xddZ\x811\x85\x04\x9c)\xc4\x9b\x12KpK\x19\xfd\x0c\xdc)*\xcf\x04l\xc4\xb1\xa7\x10\xc5\x9fB\xfa@d\xa3\xa5\xca\xe1Qa)&\x15\x82\xb8T\xb0{\x90\x83M\x85\xfc\xbd\"\x05\xa7\n\x89\xa3\x0e\x19xU\xaf\xc0\x1b\xb2\x1c\xb3\n\xf1q\x81\x84\xb1\x81\x08~\x15\xe2\x13Z\x95\xd4\xe1\x83UX\xd6\xa0\xb8\x04l'$`Z\xe1y:[\x10\xdf\n\xd9\x18WH\xc7\xb9\xc2\xf3\x0d\xc72\xcckP\x9c\x9d\x88\xb7\x04\xf7\nq\xec+\xa4\x0dB\x8aV\x87\x05\x03U\x0c\x0b\x0b><,\xa4ab!\xde\xff\x94>\x15\xc5\xc7B\x18#\x0b m\xca\xc5\xca:\x02\xd1\xd4\xad\xd5\xf8YG\x92\xc2\xd3z1\xb4P\x1aG\x0b\x1e,-\x14\xc6\xd3\xc2|\xeaE0\xb5\xe0\x98i\x8bp\xb5\x8e,\x8e\xb3\xf5ak\xa1\x00\xbe\x16\x9b\x188\xc6\x16rq\xb6\x8e4\x0cw\x0b)\xd8[|\xb5\x04`\x86^`\xa3\x844\x9aoIy\x9f>\x9e\xa9\xb6\x85\xa1\x8d\x1f\x995\xb8\xfc:\x17nDjv\x8e\xd1+\xf1\xa3t\x18\xf3\x84O\x1e\xfcSf\xa7\xd8F\xda\x11\xf6\xfd\xf6\xb8[\x87\xf3]u\xc7\xa0\xd1H\xcb\xa6\x97\nR\xd8\xf7\xd2\xe3\xcb\x93L0\xab\x9cm\xab3:\x04\xab\x1d\xc3 \xf9\x8fe\xa6\x7f\xc4\x10\xae\x1a\xa6v\xeb\x19\x9e;?c7\x8dttp\xac\xd0\xecv9\x9a]\xabJk%\xa8?\xf1\xe8d\xcb5\xfb4\x88:\x0c\xdfI\xd5\x1d\x88\xf6\xeb\xcb\x03\x19\xe0\xd0\xb4\xc3\xf7th{\xc3=2Cd\x9f\xa9\xa7n\x05\xaa\x7f\xf3\xe8k8]\xf5\x0c\xed\xe1@\x86\xb1\x1d\x0d\xff\x02\xeb\xf9\xf5\x96t\xfd~\xcd,\x9d\xdf6l7\xf6g\xee+c\xca\x11\xf8\xef\x12E\x8f(\x19d\x9d\xc7t\x8ax:\x01\x19\xfd\xb1\xefw\xcb\x95G\xdf\xef|\xaa\xa3\xefw&?\x00\xfbC\xdb\xdd\xf6\xab\xd4D\xd7\xd3k\xa1\xc0\xaf\x17\xdc(\xbd\xe4\x0dd\xa4\xb5!\x89\x8e3\xeb]|\x94?i+c\xb9\xae\xd6\xd7\xd5\xb5j\x8d\xd6/!\xa2\xec5\\z\x9d\xb6\x99\x1b8J\x87\x8e\xd0\xb3\xbb\xfey!IN=j\xf1\xdf\x90\xcd\xfd\x7f\xfc\xc3k\x85+2\xd1IaQ\xae\x919i\xef\xebq\xd8\xce.\xe5\xe84\xb6\x05\xfa\x06E\xfaN\xafo\x9a]\xd3mr\x07%\xbd\xabV\xbd\xa8?W\xfd\xf6\xf5\x9e\x84:i\xea+\xda\x0c\x14\xf3\xbb\x88\"\x8ekLE\xfcf=\x9d\xabT\xdah>\xd3j\xca\xe6\xf5\xa4\xa3\xa2\xb2\xc4\x02\x12'K\xbd\xf3\xbepVJKu\xd3\xe2\xbc\xa3\x83\x16\xde4\x07X\xe8%\x7f\xf6\x1cp\xcc\xccC\xd3Qf\xcc4\xdb\x866X\xbb\x8cV)\xcb\xb9\x19\x84\xa3\xcd\xa8P\xfe\xb8\xd4\xdb\xa4w\xc8\xcc\xcd\xdb\xb5#\x15\xb8\xebC3\xd0\x96\x9d\xf45\xcf \x02*\x9e\x9b\xd3\xddq\xa3\x109\xefs.\x01C\xa2\x04\xe0\x1aA\x1e\xab\xca\xe9\xe3;\xe2\x07o\xa6\x19YB\x1d\x881\xe7\xa4\xf1\x92\x94\x96\x1cW\xfa\xac\\\xfe\xef\x9c\x85\x9b\xec\xb8\x14a\x03\xdbQ\x994\x9f#\xceB\xef<0\xc6p\x9d'\x10\xf7\xfa\xcdn\xaa\x8c\x069B\xd2\x1a\x84\x1e*\x02\xa1\x93\xe7e\x96J\xb0\xee#6L\xcc\xa2\x8f\xef\xb1\xae\x15\xdf\xe2\xf6\xbb\x16\xbab&:*\xcac\xb6'\x18\xec\x89\xfdLN_\xb4-\xf0\x163\xbe\xe7\x1e\x85\xec\xeb\x04\xcb\xba\x80\xf36dGK\xd4\x80|d'\x98,\xb6\xc7\x9d\xc8\\\xc0\xa4\x0ddC\xda\x07\x02\x0d\x0dv\xadP\x97\x02m\xa6}Z[bC\x84(Q\xcb\xba\xd5\xf2g\x83\xb6m\xc4\xaa\x0dze\xd0\xe8\xad\xe3\x9d1D\x18\xfb?\xd2\x0b\x18i\xcf\x93sv;\xe1\x91\x19\xdb\xeenGto\x8cV\xadp\xbd\xcc\x02\xd9,\x9e^\xd1\xb2S:6\x1el\x9e\xbf\xee\x87-\x19\xc8\x96\xbb|\x90\x88(J*m\x99\x96\xa1\x9d\x11\xe9\x91\x14\x18\x8f\xe5MyJ\xef\xdc\x1d9yg\xd4\\1\xbfQ@o\xae\xb1\xd06\x10\xd9\xa1EY\xb2\x1e\x7f'\xe1\xbc\xe7\xed\xcd:\x0b ,\xca\xedM\x19\xd8\x95\x81\xaa\xd2-#\xae\x00\xc4\x8fRM:\x1e\x8f\xd8Xh\xaadB\xbf\xce\xa9\x112\x95P(\xe3{\xb2\xe3\xbe\x86\xa6\x83f\xc3\x8dm\xb7\xc3\x17\xcc\x00pO\xaa\xfd\xd7N\xf8)\xfaN\xd3M\x92\x14\x8a\xd3\xa2\xf5\x9b\xb6\x99\xb2\xe1\xb8\xad\xa5\xa5\x95\xb9\xf2n\x99$\xb7\x1e\xcf\xa7\xf0lT\xab\x17\x9c\x93\x83\"J\xf0\x9b\no\xcf\xc2\xd7b_\xefLd\xad(\x0f\x0d\xffPsB\xe1\x9c\xcc\xc2\x07\x9a}\xb7\xbd\xf8l\xee\xc8\xbd\xffpu\xfe\x86\x13\x0bH\xb7\x94@\xe8\xb7|k\xbc\xe8\x94%7\x11W\x899\xe2\x81^\x0b\xc5\xedV2a\xba\xd8|\xfd\xf3\xb1\x1d\xc4\xa4\xb8\xeb\xefz\x8e\x12N\xf5b\xe0\x1b\x8d\xe9\xc3x\xe7\xf3_\x18\x92f\x87\xcd7\xd8\x8cY\xec\xb7P\xbe\n]VuUTW\xc5s\xb9*\xec\xb1\x8fZF^\x8bL\x17\xf0=&A3\xc9b\x16\xd9b3l\xd2\xdb\xab|\x14a\x8a\xe54\x8f\x80\xf3\xa9W\x12*\xcf\xe4\xc9\x96\xbc\x18\x95r\x98D\xd9\xbbU\xf97*\xea\xa5L\x0e\xeeS\xb1-g=A\xb2\xc7\x80\nS#\xaf!E\xf6\x93\x1f\xaf\xa2=\xe6\xe2\x11aA\xc2c\x9aGu\xbc\x92\xe4\x18\x85\xd6\xc7\xe9\x8dW\x13\x1b\xaf\xa24f\x87Ul\xc4\xe2d\xc6kh\x8c}\xe4\xa2Q\x02\xe3\xb5\xd4\xc5L{#\xe2\x82\xa4\xc5k\xe8\x8a\xc3\xb4\xc4\x05\x08\x89\x93\xa8\x88\x97Q\x0eg\x92\x0d\xaf\xa5\x19\x064:\xee;\xcf\x15\xa5\x16.O*\\\x94N8\x8dHx\x1d\x85\xb0g\x80C\xe4\xc1\xcbi\x83gz`l\x8d{\x08\x83i*U\xf0Z\x92`A\x06\x8c\x08\xc4\xe9\x813\x88\x81=\x94\xc0\xc1->H\x03\x1c\xdf\xff\xcbQ\xff\x86H\x7f\xc3\xedXG\xf4\xab4\xa9%,D\xf1[\x88\xdc7\x83\xd6\x17_I\xd8V\x9eA\xe5\xcb\xea\xb3\xa4Q\x94\xc47\x97\xbe7\xca=\x1b\xa0\xecM\"\xeb\xc595\x97\x11\xf4\xe22\x1c\xce\xbal:\xde\xd4\xc1H\xa1\xe0\x0d\xf7;\x89vw!\xe1\xae\xcb\xe1W\x80d7J\xaf\x1b&\xd6\x8dQ\xeazGi \x8dn\n\x81.F\x9d\x9bI\x9a\x9bH\x97\xbb\x8e(\xd7CE\x9bB\x8e[\x90\x16\xd7\xd3\ng\xa6\xad\"\xc1\x85\x00\xe1mA\xaa[\x9c\xe4v-\xbd\xad\x97\xca6\x83\xc4\x16=\x86\x04\xa9j1\x1eM\x8c\x9e\xb6\x1c1\xedzJZ\x84~v\x15\xf1l\x90d6\x9d^6\x89XV\xfa1R(e\xe5\xa3Q2Y\x94a\x15\xaf=\x95\xc63N\x1d\xbb\x8046\x91.\xd6\xe9F\x06E,:\x8d3\x88`\x1do\x0bJ\x01\xbb\x8e\xfc\xd5G\xf4Z\x96\xe25o>$\xd1\xba\xa6\x10\xba\xea\xdb\nF\xe2*N3\x189k\x88\xb85|\x82XM\xd6\x8a\x13YxiZ1\x82V3\xba[\x88\x9a\xd5{\xe4\xc3\xe8XS\x89X\x93(X\xd3\xc8W\xa3\xb4\xab\x0b\x08W\x93\x10\xe5\xb3\\m\xb4\xcb\xd0\xab\xce\xb9\x10X\x84?\xad%\xce\x8c\xb4\x85\xce\x11\x07\x0f\x8d\xaa\x1ew\xf0\xc9\xf2f\x86\xfb\x1b\xa6\xfd\xc3\x08z\xe8\x7fO\"M\xa5\xcb\x83\x16^\x8a\xd4\xa0C\xc3h~!ZT?!jzSP\xf7\xc9\x1a\xfa\xd3\x89\xe6\x14\x91\xe7#>\xf5R\x9e\xa6\xb7\x7f-\xcdi\x9c\xe04\xbd\x0d\xe8\x18\x96\xa33\xf5\x10\x99z)L\xd3\x1b\xbe\x98\xb64LX\xea\xad8\x91\x8b\xc5\x19\xc7\x0cbR\xee\n\xb6\xc4\xd9\x9b\xa6\x97\x92t\x15\xe3P8\x837\xb5\xa3\x99\xa4\xa3\x06\x125L7\xea#\x1a5Z\xba\x9ebt\x85f\x8d\x13\x8a\xc6\x97\xddZ\x12Q\xb8\xc1\xbc\xbf\x0b\xe9C\xbd}\x86(\x16\xd6O\x18\x19\\\xce\x904(\xb0\x8a\x1a\x94\xb3\x94\xe9\xcb\xda\x9d\xdf?\xb5Ep\xc2w\xe2\x87\x84v\x95\xb2\x05D\xc1\xb9mVz\x00\x9cW\xbdF\xcc2O\x80&D\xf7 \xb8\x946y\x1e\x01M\x90\x93\xcc\xf1\x9b8HC\x87\xa5\xa0\xc0\x90P\xa8\xba}\x8d\xaa\xab\xba\x1d)U\xb7\xff\xed\xeb\xf6e\xbe\xfcE>\xe8E\xa7@C\x94u\xf1\xbd\xf1[\x81\x13\xa1)\xcf8\x1d\x8ab\xdd|\x1f?\xf5\xa6v\xd5\xea\x99\x9a=r;\xb1\x0e\xbd\x19=\\p\xe6EX\xb0\x92\x8f\xbc\x81\x13k\xdcAZ\xea\xa4:\x1f\xc6V4\xc2y9\xad\x11\x7f\x1d\x83\xe07\x88\x98\xae#\xfd\xfc+FA\x0b\xd1x\xfeuB\x9b\xcb\xe8:\x13h13\x9b\x9fI\xcb\x19\x1a\x8a\xd5T\x9cE\xc2\x94q\xfaM\xe3\xf5)\xfb)\x97rS\x9eI\x84\xb0\xe5\xfc\x9aqU\xfd;\x8bF\xaeQ\x17\xbfI\x10r\xb1Z\xc8\x08>\x1a3\x7f\xf5\xf2\xd7\x96\x9b&\xcem\xe8\x8a\x06\xae^\xe6x7\x8b-\xed@\xe8q\xcaiK\x9e\xeb~\x0e\xcc\xf8\x00\x19_p%\xe3\xa5\xc5p\xa9 \xf4p]\xfaY.Q3\x017\x12(\xcai\xe9\xd5\xff\xe1\xcd\xab \x83\xa5\x9f\xbb\xb2\x1cke1\xbeJ/S%]\xcfQY\x8a\x9d2\xccK\xb9\x8a\x91r5\x17%\xef\xaf}\x02\xf6\xb2P\xae\xe6\x9fD!8\x1e\xe6\xc9\x1c\xceI\xce/i\xf7\x06\xa1EY\xc33\xe9\xe7\x94\xccd\x93L\xe2\x91L\xe7\x8c\xcc`\x8b\xcc\xe0\x89D\x14FA6\xc8\xb2<\x90\xc5\x18 \xe3\xdc\x8f\xc5X\x1f}|\x8f9L\x8f(\xab#M\xe1s\\\xcb\xe4\xe8em\\\xc9\xd7\x8805z7J/^\"\xbc\x83\xaedd\x9c\xd9\x17\xb1\xf1\xfd&^w\x1e\xff\xa2\xe0[\xd4\xc4\xb9\xcc\x8b\x058\x17\xf3\xd8\x16\xadYno\x86\x99\x0c\x8br\xa0u\x899\\\x8aA\xa2@\x0f\x7fb\x949\xd1%QKgKt\xdf\xfd\x0b\xd6\xd7U\xdc\x88)\x9d\x8d\xf1!\xfa\xfb\x16\xe5@\\\xc0~h\x12Ee2\x1e\x06\xb9\x0e\xfd,\x87!~Ct\x14R9\x0dcl\x866\x8fa\x06\x83a\x02w\xe1r\xd6B\x84#0\xc6TX\x88\xa3\x10\xa9\xd9\x98)Y\x8c\x846\x03a\x0e\xf7 \xc25\x98\xc52h\xb3\n\x96\xe4\x13\xf42 \xda\xf4j6{`\x19\xde\xc0b\x8c\x81e\xb9\x02\xd3X\x02\xa3\xfc\x80\xf2\x94\x1cc\x06\x94\x8f\x059\x01\x1d\xf2<\xb7\xb6Tv\xb70\x03`\"\xf7_\x02\xeb\x9f\xd1\xe4\x92L\x7fY\x1c\x7f.\xa7_96\xbfr<~\xeb\xbfn\x94\xbb/\xc6\xda\xa7\xd4\xb7\xcd\xd4'lp\x9b\x85\xcf\xc7\xce\xe7\xb7\x81\x0b2\xf2\xa1\\|6\x0b\x9f\xd1\x92\x12\xfc{\xe8a\xc4\xe6\xdcKa\xdb\x8b\xf2\xec\xc5\x19\xf6\x82\xdcz\x89\xacz6\x9f\x1e\xda?c\x14\xf39\xf4\xe6 \xb3\xcd\x9e\x17\xaf\xdd\x98M\xb6\xa0\xd9\x0b\xbc\x8c+o\x923\xceM\x9c\xeb\xc4\x1b\xa2\xfd\xc3p>\xeb\x7f\x8f2\xe3\xd1t'2\xca\x83\xe7=\x1a\x1bM-\xc0}\x87\xb3\xde\xa5U\xefBKVs\xdc\x81\x95'\x02(\xbb\x1d\xcak\x97\xd6\xd65\\va\x16\xbb\xb4zWR\xd4att(\x11]Z+\x16\x91\xcf\xf9i\xe7\xd0\xca\x12\x02\x97\xc6D)H/g\xef,(\xb1\x9c\x8fR.\xd8\x99H\xc0\xd3\xd3!\xba\x90:n\xee\x80&.H\x1a\x87\xd1\xc5\xd9\xa1\xd8\x15Dq\x0b\xd4U\x98\x16.\xac\x1f2\xa8\xe0\xb8\xdb\xd1\x12\x97F\x02\x87\xf6\x0d\x82I\xbb8=\x98w\xa9A\xb4\xe3P\x94\xe0\xcd\xc7\xf4\xe5'u\xcbl\xfar\n7tf\xab\xb2\x8c\xbc-J\xdbV\xa0s\x8bI\xda\x10\xb7?\x98\x04u)\xf4l^b6o\x97\x16\x00Q\xd7\xf0\xad\xd9\xdcjAV\xb5\x856]\x0e\x87\x1a\xff\xeb7zG\xcd,_\xbc\xd6\x92\x8ci\xf9\\i*\x0e'\x05\xceA\xeb\\~4\x8b\x13-\x93\x0dm6\xfa\xa5\xbc\x99\x07-\x9b\x01M\xb2>Iq3\xf7YA\xd63\x8b\xef\xac$\xd3Y\x84\xe3lw\xb3?a-?in6\xed\xc9\xc3\x0f'\xa7o\xcf.~\x11~\x82\x9f\xfb\xbb\xe4T\x9a\xfdxw\xddv[\xf2h\xaf\xb4\xb6\xa3\xe4\x8e\xcc\n\x153\xbcv\xaa\"\xc0\x17(y \x1d}\xe6\xc4Y\xfe\xb8\xf1\x97\x80Bk(\x1d\xda\x9b#\xc2/\x8b5M\x14\x14y\x19\xd8\xe8!\xca\xf2\x8a\\s+Jpo \\?\x97\xbd+\x9d\xaaq\xd1\x0f\x0c\xd3`\xc1\xd7\xa19\x1c\x98\xea\xba'2\xe9\xf2\x0by\xe2\xca\x887 \x11\xd8\xd8\xac\x89\xa2\x88\x06\x8e\xd0v#%\xcd\x96\x13\xb25_y\xe4\xd5\x7fU\xba\xc5Ww\xc9e\x9c\xb3\xa95\xb5\x96t \xfe\xa02\xd0\x8c\x06+\xa2\xbf\xf9\xeb\x1b\x02U\xee\xd1\x17\xf2\xf4\xbd\xf06\x1f\x9av\x18\x85K\x90\xe9\xa8\xb4V\xfb\xdb\xcc\x9b\xa6\x13\x0f\xc2\xb8k7|c\xd7[-k\xfc\xca\x9aL\xf6-\xe5Z\xe7\xc8\xdd\xbaco\xec\xbd\xe4\x91l\x8e\xb1\xfd\xc8T\x08\xda\xa64\xd2\xe1\xb8\xe1'b\xd9\"n\xd0v\xc0\xd5\x003\x0b\x1f\xf9\xbb\xd6\x8d}\xbb\xfe\x0e\xd7;jP\x93U\x0e\x92\xfffL\\k\x9a;O\xe0\x03\x9d7\x855f\xce\xd8\xd7vF\xe0\xa7f\xbc\xe8n\xfb\xe4\xfe\xdf5\xe3\xf5\xd7\xa6\xa3\xaec\xd4s<<\x06\x0e\xbb?5\xe3?sY\xca\xbaQF\xe4\xb1k)\x0f{\x7f\xed\x87/\xf0U&\xec\x88]\x95>\xf2\xf8;\x19X\x0d'Z\xb3\xd8\xb1\xa7L\xa3>\x8fs\x93\xe6M\xf5\x8e\x19\xa7\x1b*\x12\xd06}'\xf3\x9e0\x01lHg\xeb\xf8q\x9e\xf3\\\x88L,C\xbf\xc7'n\xf9$\x7f\x8emC\x9b\xc4>\x1b\x19\"~\xad\xfa\xae\xa1\x0d\xcf\xeb\xea\x9e\xb8t\x18\x08=\x0e\x9drA+o>w$t\xdb\x1d\x19\xb4\x05\x0d\x17\x14~\xf9|y\xa5\x893\x93bv\xa4\xbb\xa3\xf7p\x18\xc8m\xfb(2Myj9\xc7\x0e\x11v\xdcfK\x80\xd5**\x13f\x04A\xee\xdf\x9c*\x9d\x94Xl?\xb7:\xcd\xd4\x8a\x89\xee\xed\xef\xa0\xed\xc4h\xb1/\x15\xef\xae\x14\\\x0d\x85\xa2\x86B \xa7I\x94\xb5\x96\x04\xc4E[\xc6\xa4^\x84h\xfc\x0e&Q|\x91 U\xe2\x96\x0c\xdfP\xe7\xbd\xa0\x1dgX\xc6\x17\xf2\xf4z\xde\xdf\xd9Ay\xec7m3\x9f \xb06\xf1\x99\xe95M\xac&\x88\xdd\x9c+\xda\x11\x9a9c\x12\xb6\xe4\x81\xec\xd8\x97\xe6\xfe\xa5\x86\xd2fs\xaf\x87\x9b\xb5Ec\xceY+!Ca\x11\xdf\x92\xbb\xb6{\xbb\xeb7_^M\x7f;\xef\xb6\xd6_\xce\xee\xc9\xe6\xcb\xd5#\xdb\xe5P)\xef\xc8\xae} \xc3\xd5\xa3\x95\xf0\xf2sC ;p\x0dM762\xbfj\xdf<\xb1\xe3\x8b\xe2J>\x8e\x1c\xf0qOF\"\x17\xaf\xc7\x10\xfa\x87\xa2\x86\x90&K\xe93\xedO~\x0dc4I\xec\x0f\x1alD\x9ck\xd5\xa8\xfc\xc8\xbf\x047\x0d\xac\x81Dw\x1b\xcd\x1cM\xderLU\x84\xac8L\xfd<\x87ND\x14\x8cw\xfd\xa3:\xc3\xf3t\xc8~/f\xa8\x89\x123\xd7|\x8d)x\x8c\xc8>@8\x93\xea\xeaq1EUF\xf4DrS_\xdd\x13\xb8a\x1aD\xcaR\x93\xf5\xf1\xbe\x19\xef\x97\xd8\x05L\x90\xa6<\x80\xbd?\x87\x14\xb6d<4QP\x93l\xd3\xfbf/\x1e\x9f\x82\x18g\xfd\x96h\xb2l1)n\x0bW\x1f\x08\x807\x93\xa7\xda\x99`\x15\x1aB^H\xad\xc2\xbf\xe9+\x95\xcc\xf7B><4_\xaf\x17\x1aW\xc6\xaaa#\xda\x1f\xe9\xe18\xa1\\\xb4\xdd\xe5\xc5\xc8\x0c\xaf;2\xc0K6\xab\x84\xd0\xefN\xe0\x17\xae\xb25)]\xdf\xbd\xde\x12J\x86}\xdb\xb5#m7\x9a\xdd\xf7\xcc\x8a\x06q3\xe9r\xec\xaf&\x8a\x1f\xd9l\x8c\xa5.\x08\xd1[\xb6m\xa9?\xfe\xdb\x98q\x98\xe5\xa9\xfd\xe27\xb6\xfcV\xa8\xfe:\xd6 Q<]\x11%\xd8!Q\xc2\xdd\x12\xc5k\xa3\x8a\x125'!l\x8e\x8a\x92 %n\x1a\x8a\xb2v\xfb 7\xde\xe7\xf0\x12%\xa6\xff\xcd\x12\xef\xc9\xea\xbd+8\xc7\xb0\xf6gomz\x89ul\xbdy\xe8\x8e\xa1\xe67s~t\x8e\x9f\x10i\\\xae+\xcd\x10\xa6\xce\xc3\xd2\xa1\x16\xab=U\xf5\xb3%\xb2]\xa4\xf5\xdb\xc9i\x05I;\xd2)z^Q5\xfa\xebY\xec\xef\n\xec\xd5\xa7\x86+i\x10\xb7t( \xd3lr\xac\xf4i%W\xac\\W<\x1a\xe4VK\x9dhJR\xb2\x03\xad\x00\xdf\n\xf0\xad\x00\xdf\n\xf0\xad\x00\xdf\xa9T\x80o\x05\xf8V\x80o\x05\xf8V\x80o\xe0\xdd\n\xf0\xad\x00\xdf\n\xf0\xe5\xa5\x02|e\xa9\x00\xdf\n\xf0\xcd\x80\x80V\x80o\x05\xf8&\x00|i\xbb'#m\xf6\x87%\x8eD\xd3\xbf\xd9\xce.\x98\xc3@\x1e\xda\xfe8\x8a0\xe4 \xfc\xc8N\x90<\x169\xc2?\xc0\x0f\xaf\xa0\xa5/\xc4\xb0\x7f\xe5\x7f\xe5Sd\xdb\x1a\x89\x1b\xe6\x1d\xd7|%\xab6\x9aT~\xf0\xd0\xd3\xc9\x1a\x955\xfe\xdc\x8c\xf4\xac\xdf\xef[\xaaWn(8\xf8\xe1\x95\xa1fY\x8b\x985:\xb6#\xaf\xa9\xa64\xd5\x94&\xbd\xd4\x94\xa6\x7f\x0b)MSHH\xe6\x88\x08\x01S\xf6\x92\xb0-7d\x1c\xc5\xf6\x82\xc4\x0c@\xfa\x8c^Y\xeakj\x0d\xb4\xddfw\xdc2\xab\xb0\x1f\x89O\xb4\xac_n(\xa35P\xfcU\xbd\x02%\x85gjr\x17FG\x89\xca\xa2\xe2`\x9d\x814#\xfc\xdc\xdf\x8d\xa6y$\xda\xf4\xcaq$i3@Q\xbe\xbe\x9aj\xe1\x86\xad\xd9`\xbd\xb1\xe6\x99\xfd\xb2\xed6\xe4\x0dl\xfaq\xdf\x8f\xaf\xc7\xed\x17\xf8\x0f'\x7f\xff\x87\x93\x1f~x\xc5\xfe\xe3\xefO\xfe\x13\xff\xff\xff\xc4\xdf\xc0\xbf\xcf\x9cE\x13\x0b\xd9M7d\xd2G\x91;\xcb\xcc\x0b\x9b\x87\xfaj\xf6X\xd3\xe6n\xd4\xc2\x9f\xc22W\x86=\xcf\x82\x1d\x85I\xb0%\x9c\x0fV%\xf9l\x86\xa7\x03\xedOxR\xee\xd8r\xf6\xdb\xb3~\x7fh6\xf4mKO\x99\x02\x16j\xc6Q\xb0\xaeR%\x8fth\xaeoZ:^s\xd6j'\xc6\x95\x92 Cv\x86~G\x15\xa5\xa3\x1c\xf14\x15\xab\x1f\"\xff\xd9\xf6\xe9 Rm\x9e\xcfC\xb8[\x93)\x97\x9b\x96\x8a\xcdg\x1e\xe8\x96#\xb3\xb8k\x90\xf6@\xba\xf18\x90)81\x91\xec\xf2/E\x9b/d\xe4\xde\x7f\x01\xdf\xd3!uR\x9e\xa8P\x1c\x97\xb8\xf1#$h@gUc\xd7\xb3\x1a\x06\xd2laln\x95KU\xfc\x9d\x8d'\xc7iq p\xdfI\x07.\x1c\x85wL|`\xfax2\xb6w\x9dd6\xbel\xef\xba_\xa6$%gtu\xbe\x8f\xd7py\xf1\xd3\xfb\xeb_>\xbc;G\xe85\xf4_\xdf]|:?\xbbB~\xb8:\xff\xefW\x9fO\x7fF~\xf9\xf9\xfc\xa7\xd3\xb3?]\x9f\xfer\xf1\xfe\xc357\x94\xc5w\x94\xd4\x1e\xfe\x9a=\xa9s\xb2[\xb39-\xb6$\xdeo\xd8\xb3_\x84C\x97\x8e\xc0l\xf5\x89f\xe0\xee\xd8\x0cL\xc1\xf0\xa5\x0e\xc1\x8e{Z59W%\xf3\xb48\x0c\x18U\xb3O&\x0d{Y\xc7@\xd8:\x9a\xfd\xb1\xeeh\xbeq\xfe\xa2Wdu\x8d\x9f\x00\xf8y\x95\x0d\xc4\xbb~#g\x89\x14\xff@\x06\xa1\x0f\x04\x0d\xb6J\x86\x10*\xf6\xea\x11k\x84\xfcro\xdc?\x89\xdd^@.\xcdf\x88\x1c\x08\xd6O^\xe1\x93\x8e\x11\xb2x9(y\xa4\xc7f\xe7\x9c\xa3\xd9)\xe5\xa0lb\x19U1\x9f\x91\xf2x\xd3=30<\xd1\xde\x84~\x14\x9d\xbbi6_\xbe6\xc3v\xb4\":\xd6`\xcb\xeaN\xf7m\xd7\x0b\xdd\xaa}h\x18\xc8\xbe\x7f\x10h\x08\xe14\xe1\x18\xd5iM>\xfcprz\xa4\xf7\x8b`:l\xb4\xc9p\xcd\xec\x98\xa5f\xfc\xff1\x90\xdb7\xf0\xe2\xff\xff\xbd\x16G\xfc~n\xca%\x97\xcc\x1a\xf3bz\xc9oa\xe8\xed0\xe0\xe2\xfat\x98\xe9a\x06\xf2\xe7c;\x90\xad|o\xe4\xa13M\x9c\x04\xc5j\x7fa\xe3( $\xfd-\xdf\x11\xf8\x82\xe6!\xc8}C\xa7;\xbaL\xb1j:\xbf\xed\xb7O/F\xd3\x8b%ws\xee\xfd\xe1\x8e\x02%U\xe5\\\x1f\x86v\xcf\xa3\x19\\\xd6\xb4q\xf6\x1dq\xc2\xc5\x87\xe6i\xb4\x0ft\xb7d:e\xdd\x12\xcd\xe6\xf7\x8f\xe1\x8fdB\xa5\xdf\x12\xa1\"\xee\x9a\x11v\xed\xbe\xa5\xd3\xc8\xe9F\x99\xd6v\xd9H\x83\n\xc4\n^\xc7\xfa\xc3{15]\xc8&DB\x825938X\x97n\x00\x947\xbd\xb8@\x8f0\xb3_@\xac\xf9\xea\xed\xb7\"Iz\xdb\xf3\xbc'Ez\xa3\x89\x11zIX\xef\xbax\x15\xf1\x99\xa7K;*\xb42\x19i\xbb\xe7\xc7\x89\x87\x96\xa9\xc1\xbd\xc4\x81\x9fX\xeb!)\xbdEl\xcbX\xcc\xeey\xaf;\xdd\x92\xae\xdfc\xc7\xb7\xe0\xb9\x10km\xf4\xb5\xd8a\xee\xaco;\xcd\x16\xe5\xc2T\x85\x0d\x98\xbckdb\xa1\x9c\xfb\xdc\xfad\xfb\xc9\xac\x16\xdcI'\x8f1\xf6\xd0\xdd\xf0T\x05\xce\xbat\x9c\x92\xc6x\xe2\x05\xf4\x9b\xcdq\xd0u\xc9\xa1yZ\xc7\xc7\xe5\x12b\xdd\xc2\xb1\x1b \x15\\ \x96\xf6R\x17\x85\xb5\xea\x1a\xb1C\xf3\xa4\xb4\xc7-\xb3\xc8\xe0\xe2\xd6\x927\x89\x9a\"\xda\xd0l6\xfc{\xf2\xdd\xe1\xd0<\xcd\xaf\xdbC\xc0\xf5<\xeb\x9ax\x96\xc7\xd1\xe9\xa3j\xcfK\xa1#\x8f\xa3\xc8\x10\xe1\x7f\xdd\xcal 1\x91\xed\xc1V\xfb\xf7wNM#\xa1R\x0fNoo{2\xc2\xdfu=\xfd;\x99\xa0!\xf41\xdb\xe48)\xc5\xed4\x9fmYjwC\xf6\x04}\x9er36\xf5\xab\xf9\xa6b{;\x0f1\xdb\x0f\xc4p\xbd$\xedDfh|\xc3\x99\xc5\xe9\xe8I\xd4\x13\x02\xf8\x10|\xa7\x92#U\xae.\xaf\x81\xb7{\xe27\xb2\xbfX\xcf\xbf(\xfb\x9az:\xaf\xd1\xba\x17\xc2\xa2\x97\xb7\xcc\xb09\xe3\xfa\x98\x9a\x03\xd3\xc6C\xdbP\xa2U\xca? ;G\x91G~\x07\xac\xe8\xcc\xe6\xbea\x1a\xb1w\xb3\x8f\xd9\xa3*\x97`\x922\xbe\x12_\x99\x9b}\xb7M\xbb\xe3/\xe1\xa7\x145a\xac,\x07\xb5\xff\xcbA\x15\xc6\xd3\x94\xce\xac\x8e\x9c\xec\xd7)\x9f\xcc\x9a\x04\xb3!\xf7v\xe8\x9b\xed\xa6\x19i\xf2!\xef\xed\xa7\x0f\xa7\xef\xceN/\xaf\xfc'=\xeb\x91\xb7?\x7f8\xfbo\xbe\x1f/\xff\xf4\xfe\xcc\xf7\xdb\xe9\xf4\xe3\xcc\xe1\x18\xae\x1d\xd7.F'\xb5c\x117;\xd4o\xc2ZW\xab\xe6\xea\xf1\x92\x0c\x0f\xed\x86\xcc#\x04\x9f>\xaa\x96\x8a\xddF?\x01\xfa\xdb\xf5\x06\xfe\x95\x0c\xbd\xf4q\xf2H \xabG-d\xaf\x04>hN\x7f\xf9_\xf5\xed\xf7q\xee\x80v\xbcS\x89\xff\xe2\x9eE\xf8\xda\xb0s\xec|\xb5$W\x0b\x8fr#\xe3\xacF\xdc\xb7%\xeet\xe4Q\x04o\xb3\xd8\x17qZ\xc5\xfe\x98\xdd\xa8\x06\x94gt\xc6\xc9\xab\x9b!\xb9\xdb\xcd\xdf\xa8S\xb4U\xa7\xab\x9a%\x80\xee\x13\xe9\xd0\x9eGg(\x11\xd5#\xeb\xe6\xea\xf1\x93\xd0R\xc9\xa72\xfax\xcd\x8f\xd3K\x9dV`\xcfo%H\x99\x01\xec\xa0\x8eh\xfb=\x821\xb3\xeaBh[c\xab\x1c}L_\xe9\xe8\x03\xdajG\x7f?5\x1eH]\xf5\x10\xb4+\xca\xac~M\xe0\xa7\x8fg\x8e\x06@{\xb3X\x0b\xa0R\x9eS\x13\xc0\"m\x806\xef\xf94\x02,\xd2\nh\xe3\x9eO3\x80\xab\x1d|\xdb\xb8\xab+\xa6\x15+\xff\xc9\xb3\x03\xd4\xe4s\xa6\xde\xf4\x9a\x94\xa7\xcf?\xafNZ\x88\xbd\xa5\x8f\xd7\x83\xf1\x0e\xfa\x1e\xfe. \xd8]H9\xf3x\x8f<\x1e\x1c/\x7f\xc2\xc2\xf2B\xf2a#\x84\xe9\x05\x1c\xd7\x1b\x14\x9e\x82\xef\x05\x07\xe3;\x8b\xc4\x10\xa3\xfe\x911\xba\x82\xe2}\xf9S\x06\xe6\x17\x92\xc7&\x8c\xfd\x05\x0c\xff\x9b.\xfc\xff\xb5O\x0d\xa9\x80\xb00\x16\x18B\xc80p0\xc1\xf0\x1b\xf9j\xbc8a\x08~yQ\xfc\xdf\x1fp\xcc0\x84\xbd9>\xec0\x04\x06C\x94\x00\xf0600\xa2\xc4A\xb7\\\x84\xe7\xb7H\x87D\x89\xe1\x8a!\xdaAQ\x82\xf8bH\xe9\xac(\xf1.\x8b\x12\xc1\x1aCZ\xefE\x89b\x8e!]Z\xcc\xed\xa7\x975\xf8\xe3\xa0@\x93\x1a#\xf8\xa8\xe8H\x1aXW\x94\xb4\x9e\x95\xc4#C\x14\x93\x0c\xebq\xc9\x1ei\xde\x01H\xe9~A\xd42+A\xe42\xf8\xd0\xcb\x90\xd0\xd8\xa2(f\xf0!\x99!\xda\x92\xd4\x0d\x8c\xfa\x10\xcd\x10\xdb\xbbLd3$\xef\xb5k\x11\xce\xe0A9\x07kN\xb4V\x16\"\x9e\x01E=C\xf1\x86D\x10\xd0\xbc\xc2G\xac\x01\xc8f\xe0W\xff\x14EDCL3\xc7VBQt4\x04\x11\xd2P\x14%\x0d%\x91\xd2\x10BK\x03d!\xa6\xa1 j\x1a\xa2\xc8iX\x8b\x9e\x86\x1c\x0456bO\x07\xe5M\xc6P\xd4\x90\x83\xa4FdM\xd9\x11\x80\xa0\xa9!\x13Q\x8d\x88\xe3YV\x14AUCqd5\xe4\xa3\xab\xa1<\xc2\x1a\xf2P\xd6\x90\x87\xb4\xc6\x97(\xda\xc8b\xf8k(\x8e\xc1\x86\x928lH\xc2bCI<6\x040\xd9\x90\x89\xcb\xc6\xd68\x82\xd4\x06\xa9j\xa2hm\xc8Fl#\x02]\x0c7\xac\xc7q\x83\xff(\x16\xdc\xe2\x83)\xfb\xf1\xfd\x7f%\xb6\x1bS{Sl\x9c\x1a\xf8n\x88\xb6#\x0f\xe7m \xe3\xa8o\x04\xeb\x0de\xf0\xdeP\x1a\xf3\x0d\x08\xee\x1b\xf2\xb1\xdf\x964\xea \xc1!\x13\x0d\x0e1\x904\xf8Q\xe1\x90\x82\x0c\x07\x1c\xc4\xba\x08!\xee\x97\xe1 \x04\xb3\xd0\xe2\xb0`0b\xa8q\x88\xf6;\x8a\x1e\x87e\x08r\xc0\xc6#\x17I\x0e149\x04\x11\xe5\x10A\x95Ch\x94R\xd1\xe5\x90\x800\x07\x04e\x0eyHsHC\x9b\xc3*\xc49x\x07&\x8a<\x87r\xe8s\xf0\xb7\xc2\x99iE\x91\xe8\x90\x89F\xb7D\xb9\xd8t(\x8dO\x87\xc2\x18u\x08\xe1\xd4\x01\xc1\xaa\x03\x82W\x87b\x98u(\x89[\x87\xe2\xd8uH\xc6\xafC\n\x86\x1d\xd2q\xec\x90\x88e\x07T;\xa3\xa8gX\x80|\x0e\xe3\xda!\x1d\xdb\x0ei\xf8v\xc0\xbaQ\x12\xe7\x0e\xb9XwK\x96\x83|\x87\xa2\xe8w(\x8a\x80\x87\xec\xf9\x10E\xc2C\x02\x1a\x1e4D<\x00\x8a\x8a\x87d'\xb4\xeb/\xcfB\xc8;:|\xdb6\x9d\x85\x92\x07\xc8E\xca[\xc2\xe4M\xaa\x0eZ\x1eB\x88y\xf0\x04\\\xe9o\x10w\xa6\x9e\x90j\xf0\x0c\x1a\x0e\xa3\xfa\x9a-\xca\xf3F\x88\x83\x81\xd2`\x9fT\x89@\xe2!\x1eA-UM\x00}\x0fS5!\x04>$\xa0\xf0!\xba\nUY\x8f\xc6\xf7\x08\x14\xd7\x93\x9a\x88|Hh\xceZd\xbe#H\xbf\xb1\xc7F\xe7C1\x84>$\xa0\xf4!\x1f\xa9\x0f\xd1\x91+\x8a\xd8\x07\x0c\xb5\x0fP\x00\xb9o\xc9\x13vz\xefZ\xfd\xb9\x08~K\x1c\xe6n,\x87\xe9\x87\x85\xb8~\x08~\xcd<|\xbf&hB\xfa\xeb\x18\x7fV\xd6\xe0\xfc\x93\x12\x19e\xb3\xa7LF\xf9o\xaa\xa52\xca\xd7\x90\x84F4\x7f\xf1G\x92\x9e\xafhc\xdb\xb0\xad*\x97\x9b\x06E\xddy\xf7\x04\x1cm\xe7y<\x94\x1f\xb7\x1aa\xa7\x0b\xc9\x01\xd7)0\x9d./\x1dG\x97\x89\xa1C\xf0s\xe8\x18zps\x18P\xa9\x10^\x0e\xc7\xca\xa5\xe2\xe4,\x8c\x1c\xda'\xbf\x9e\xc8\xc6\xc5q\x98\x96\xbe\x14V`\xe2hA<\x1c\x8e\x85\xcb\xc2\xc1)\xe4\x9b&/\x80\x81s\xf0o\xe8\x17\xc1\xa6SQ\xcc\xdbz\xbc\xdbj\xac\x9b\x8en\xd3\xc7j\x15\xcem-\xc6m\x1aQ\x8ek\x17\xc6\x05\xae*\xb8\x92h;\xd1Q\xb5q\xc9\x15\xfc\xcd\xac4\xa4J\xe1KX\\p\xed\xa2\xe1\xf9 \x19\xb8\xf3\x8d\xebAr{K6\xb4\x9d\x82b\xdf\xde5\xe3ah7\xe4\xdb\xc9\x18\x12jr\x9a\xef\x82\x1d\xb9\xdf\x13\xd8\xb7\xfb\xb6;\xeee\xb5*AcN\xb2\xd8\x93\xfd\xa1\xefw\xe6\x0e\xf7\x13Y\x97\x9b?\xcf\xd2\x08/\xc3\xd5\xa3\x87\x8f\x81>*\xe5\xa7LP\xf4\xd2\x87\n\x02\xa8 \x80\n\x02p\x1e^\xec\x8c\xa9 \x80\x04\x17\x8f\xcfc\xa5\xfdZA\x00\x15\x04\xe0\x96\n\x02\xc0\xa5U\x10@\x05\x01T\x10\xc0\xa2\x86T\x10\x80^*\x08\x00y\xbd\x82\x00\xb0\xea*\x08\xa0\x82\x00*\x08\xa0\x82\x00*\x08`*\x15\x04PA\x00\xaaT\x10@4\x19\xbe\x82\x00*\x08\xc0\xfdk\x05\x01T\x10@\x05\x01T\x10\x00\xad \x80\n\x02\xa8 \x80\xd4\xf9PA\x00\xb2\xd0\n\x02@\xbej\xf0\x0cZA\x00\x15\x04PA\x00\x15\x04PA\x00\x15\x04\xe0\x05\x01\x18\xa9\x8b\xc1\xac\xff)\xdf\x9f\xbf\x82f\xfa\xf3_F>\x83WdCj\xdb\x05\xb69-\xbd\xcb*\x9039Q\xab\xefZqg\x11\x92<9\"\xd9\x93K[\xe8\xd9*}\x1b$\x96g\x19\xdc\xa8B\x19e\xf1lK<\xdf2X\xe1\xa2\x9cKo\xd6e\xb0\x8a\xd4\xccK,\xf7R \xc6s\xf0B\xa3\x95\x96\x81\x89\xe5`\xa6\x8fW<\x0f\xd3\x93\x89\x99^\x85\x93\x8d\x99\x9e\xce\x12\xcf\xc7\x8cd\xb5`9\x99!3\xb3\xfc\x0d\xce\xc1\xec\xcc\xf0\xdc\x10%\x9c\xa1\xe9\xcd\xd1\x8c\x1a\x93\xfe<\xcd\x98\x1d\x1eIb\x8c\xda\xe2\xb1!\x13\xc5w\xbc0~\x8f\xd9\xca)Y\x9b\xf1\xee\x8a\x12\xcd\xdcL\xea\xba()\x03 JB\xfef\xe2X\x88\x92\x94\xc3\xb9@b\xcc\xe46\xcb\xd2L\xce\xf8\xe0,\xc9\xe5\\\x93\xcd\x99\xde\xc3U\x19\x9d\xfe\xe9\xcf\x94b4\xa7\xb3tVg \xaf3u \n\xe7v&dw\x06\xf2;S\x1a\x9d\x91\xe3\xe9\x91\xe6\xcf\xf2\x8c\xb7'uk\xa4\xa1L\xcf\xe8\xae\xe8f{\xa6\xef\xe79\x19\x9f\xfe\x9c\xcf\xd56en\xe6\xa7/\xf7\xf39\x1a\x94\x90\x01\xea\xe6\x80\x06\xb7\x95\x98\x83\x0e\xcf\x04\x8d\xea\xf7\xd8,\x85\xf2\xf9\xa0\xb1\x8c\xd0\xd29\xa1\x85\xb3B#y\xa1\xd9\x99\xa1esCS\xb2C3\xf2C\xcbf\x88\x8a\xd9\x1a\xc9\x11-\x9b%\x9a\x90'Zt\x93\xc2\xb7\xa5\x8e<\xd2kg7\xf2n \xdeM@&\x83:i\x8dJ\xbe\x1a\x19\xf6\x9f\x8a{z\x1cE4\xe9csG>\x89\xac\x84\x13\xf1\xbb%\x84\x0d\xa3`\x94e\xe2\xd8\x18\x10\xd8\xf7#\x05\xc2C\x1a<\x06\xa2\xbdB{\xda\xec\x16v\xe8\xe8eAut\x0f\x17\xcf\xfb\xc3\xff\xa3;\xeeo\x84o]\x05\xc2\xb4h\xcc\xad\xf5\xae\xdeU\xce\xf8|\xcd\x85\xd8\x0b\xeak3\n\x8a\xe3\x96\x8e*\x967\xc2\xb1\x13\x13a+\xc2!_\xdbQ|\x03<\xb1\x14I\xf1N\xcb\x1a\xbfz\x1c\xdf> \xf5*E}\xfax\x86f\x91\xff\xd2o\xc9\xc5\x944\xe3\xcc:w\xc6\x89=w\xfe4r\x88\xe5V<\x1d\xa4\xb4\xedYp8\xaf\x99\xd9{\x97\xf0U\xd4\xc6~P#\xc1\xc4\xf3\x04 \xf67\x156@k\x86\xd0,\"\xdd\xd1\xe1\xa9\x7f\x0d\x97\x17?\xbd\xbf\xfe\xe5\xc3\xbb\xf3\xeb\xcf\xef/?\x9e\x9f]\xfcxq\xfe.\xf0\xd4\xbb\x8bO\xe7gW\x81\x07\xae\xce\xff\xfb\xd5\xe7\xd3\x9f\x03O\xfc|\xfe\xd3\xe9\xd9\x9f\xaeO\x7f\xb9x\xff\xe1\x9a\x9fa\xf5'\xa5\x7f\xecMB\xcb\xc2\xdb\xefe{\xd7\xb1\x8fo\x7f2m0E$\x8d\n\xfe\xeb\x91l\x8eCKm{\xfb\xee\xd8p\x12p\x8b\xe6\x9c\x17\xcf\xf0y\xda>E\xae\xb8\x92!\xb0\xed\xee\xd0Vt=\xab\x95\xa9\x17\x18\x9b[\x95i\"\xfe\xce>@\xb7\x95\xa9&\x9b\xbe\x939.p\x14\xe1{!\x88\xcd\xe1kv\xf2]\n\xf3J\\\x94\xcer4\xcc\xda\xb9veEl\xfaA\x98T[\xb5\xc2\xc6\xd9\x98\xe0Wb\xa8\x7f\xaa\xc9\xac\x89S\xe1\x86#\xbf\xa1C\x9c.\xed\x05y8\xde\xec\xda\x0d_\x1a\xdfh\xcd\xe2KQ5B\x985l\xe1\xb3\xa1k\xb0\x97\xf1\x05}\xa9\x19e +\xda\xb4\xab\xb2l*t\xb9\xd8\xb6T\xdc\x8e\n\xdaPa\xfb)\xcdvJ\xb4\x9b\xfc\xeby\xad\xbd\xe4\xb5\x90~#\xeb\x08\xb3\x8c\x9e\xdf*Z`\x11=\xb75T\xc4\x12\xf2[AQ\x0b\xe8\xb7\xb7~\x16[>\xb6\x8a\x14\xea\xc4\xa7\x95\x0cEp\x02\x17<\xbfpr\xed\xc8\xcb\xa8\xcc\x8c0\xda\x0bW\xa9\x90`EmG\x18\x8f\x9b{\xf6\xda\xae\xdf4\xf2\xfa%d\x02\xe8i\x91S\xe3ge\xf8a\xd8\x92\xe1\xed\x93\xae\x045\xb5\xa4\xab\xa4\xd7\xf0\xe1\xd3\xbb\xf3O\xd7o\xff\x84\xe8\x00\xed\xc7\xd3\xcb3\xf7\x8f\xef\xce\xe5_'\x8d\xe2\x15\x86+\x13\xbcv\\\x8cg\xd5\xf7\x03\x9d\xd5-\xbf\xc6\xe9\x04d\xf7U\xb3\xb8\xf7\xf9\xf4\xf2L\x0c[;\xc2\xa6\xd1\xdcKf'\xdf\x18\xff\x9a]U\xe3\x86\x88\xed\x90W\x81\xbc\xcb\xc6\xe2\x8d\xf9\xcf\xe9m\xd6y\xe7u9\xd1\xb4\xb6\xf2g\xf9\xf6\":5=<\x7f\xd8K>\xd1\x169)\xc4~i:\xc5\x16\xd8\x99\x14\x05\x98x-\xc3\xf0A\xbb \x9c\xc4\x0f$)\x07!)\x06\x1e\xf1\xc2F\xe8z\xc0H)\xa8H\x18$\xb2\n\x1e\xb2\x1a\x18\xc2\xfbk\x1f^\xbd\x90\x90\xd5`\x10\xb1UX\xd2<0\x90\x1c\x00\x08?u\xd8\xbdAr\x94\xd6\x80>\xfc\x00\x8fLhG\x12\xa8#\x1d\xc0\x91\x01\xdd\xc8\x00m \n\xa3 4\xa3,(\xa3\x18\x1c#\x0e\xc4(\x06\xc1\xf0\x81/r`\x17hl\x8f\xa6\x80+\xd6\xc2*\xbc\x10\x8a\x95\xe0 $7a\x99\x0b\x05\xa2;\xe8Jx\xc4\x0c\x85\xc0\xc6\xf7\x9bx\xddy`\x08\x01~\xd0\xc4\xb90\x88\x02\x00\x88<\xe8\x835\xcb\xed\xcd0\x13\xee \x07Z\x97\x98\x03l\x08f\xed{\xc0\x0cQ\x18\x83\x9b\xd1\x9c\x0e]p\xdf\xfd\x0b\xd6\xd7U@\x85\x94\xce\xc6\xc0 \xfe\xbeE\x01 \x0b\xa0\x08f\xd6f&\xfc \x08<\xf0C\x0eB`\x03t\x14R\x01\x061h\x81\x0d*\xc8\x80\x13$\x00 \x96C\x08\x90\x84\xfd\x18l\xa0\x10`\x00\xa9\xf9/\xa6'9\x03\x1e`\xc3\x01r\x80\x00H\xe2\x7fV\xca\xbf\x9d\xe2_2\xb9\xdf\x9b\xd6o\xe7:\xdb\xa9\xfce\x92\xf8\x8b\xa5\xef\x97M\xdcOK\xd9\x8f&\xeb'\xa6\xe9\xa7$\xe8;\x99\xecnm\xa9\xa9\xd6\xe1t\xfc\xc4D\xfc\x84\x14|\xa3\xc9%\xd3\xee\xb3\x12\xee\xdd\x04\xfbr\xa9\xf5\xe5\x92\xea\xd7\x7f\xddh\"},\x85^\xa9\xef)\xa2\xb58|\x9d\x18)\x8b\xc4\xa2\xe9\x14(S\xa1@\x15\xee\xd6\x84\xcd\xf9\x7f\xb4\x9f\xecS$P\xf6\x85<\xbdP\x1e\x91\x91\xfc\xf9H\xba\x8ds\x99\xb6u\xbc\xf0$\x81\xf9\x8d{%w\ny\xa9\x7f\xab#\x84\xb8\xce\xff\x95\x9chF\xef\x0d\x95<\xe5\x8emx\"?\xb5\x98-\xd5%\xfe7O\xd0\xc0]\xfb@\xf8\xdc\x1c\xc88*\xd79\xbf\x94~\x16h\xa6\x00\x1f\x06\x9e\x15\xca\x16\xcc\xaey\x12\xf9\xc4_\xe4\x01\x0cO\x1a\x9b\xdd\xa5\xd6'\x9b\x83\x88\xfc\x13y\xb3 h\x7fx\xbd#\x0fD\xe5*c\xa9\x04\x97\xed\xfe\xb8k\xa8J\x84Kv\xcc\x96\xbd\x86]'\xc4d3J6*<:F\xc3\xe7t:\xf1O\x8ae\xd3\xa9w\xa4\x08_*\xdd,z!\x1b\xeb]3ZK\xd7h\xbb\xfaY\xb5U\xcf\x17on\xfa#\xe5\x14L\xfc\xf8.m\x0d9\x10\x06\x03\x93\xd3\x0e\xbc-\x90s})\x92\x81\x19>\xd9\xff\xd4\x8c\xff\xcc+\x9abM\xcdc\xbb?\xee\xe1\xd8\xf18\xea-|\xed\x87/\xf0U:\xc1\x84\x17\x87>\xba\xe9\xa5\x072\xb0F\x9cX\xbdXq\xf3i\xac\x0f?5\xe3\xe7qnpc\xf0`5\x1b*\\\xbe\x8a\x10K5H\xf8\xea<\x1fX\xfc\xa8ev\xb2\x7fM:5\xebS.\xb8\xc6~\xa5s\xe6]C\x1b\x91\xdc\xf2$rO\x06B\x8fC\xa7\xf2\xdf\xd5\x86\xca]\x90<\x03^#\xb5\x83\x0b;h\xf0\xcb\xe7\xcb+\xc47\xb5#\xdd\x1d\xbdg\xca\xf0\xb6}\x14\xf3\x9c\xc7\x89\xf8\xaa'\x87fh(\x11\xb5\x8bJ\xd9^\xc2\xf6t\x9c\x97bj\x80\xe1\xc8Zy'\xbf3 ?\xf7w\xa6\x01\xcb\xf3\xd0\xb55\xeb\x19\x17_#\xf56\xd6+\x11\x82]\x10%\x0e\xde\xaaW\"X%\x05\xaa\x15C\xf3\x88\xb2\n\xa6U\xafD0$\xfd\x1e\xaeDXAs* M-yJ\x05[\x7fF\xf7\x03\xfeL\xccnK\xc0A\xa8w,\xfb\xcdg\xb8]=&\x9bj7\xfd\x16\xc9\x83\xed\xb7\x138F\x02\xaex\x14\x89\xc7d\xe7p\xb9\xf6\xcdf \xe9[\xb9\xc2n\xfdu\xb4\x7f\xe5\xdb\xac|\x9b\xa8\xb4\xca\xb7 \x95o\x13\xaf'3)C IH\xcd@\xdfLN\xd7\x10%#iC\x94\x8c\xd4\x0d\xdfB\xf74\xb5XR\x87(eS;D)\x96\xe0!J<\xcdC\x94b\xc9\x1e\xa2T\xbe\xcd\xca\xb7)\xdc<\x95oS+yI'\x8e8Z\xf96\xe3\x89*\xa2\xc4\x98&\xe3I+\xa2T\xbe\xcdeI.\xa2T\xbeM^bI1\xa2T\xbeM\x9a\x91>#J\xe5\xdb\\\x98|\xe36\xb9\xf2m\x96H\xd8\x11\xa5l\xda\x8e(i\xc9;\xa2DSxDIL\xe41\x1e\xae|\x9b\xbc\x94L\xfc\x11%+\xfd\xc7\x91V\xf96K\xf3m\x86O(\x13\xdf\x19\x0f\xe4(N\xac\xe9\xaf\xc2\x17 \x1c\xf8d+\x1c\x87\x03\xf9\xf3\xb1\x1d\x1c\xc7\xc0\x8c\xa2\xb7\x87H\xf0\xb0M2\x05(\x90\x7f\x1f\x99[\xc3f\x9a\x08\xf7\xf6\xb7\x9c\xb2A\xd2\xb8YrN\x8f\xf4\x9e'49\xb7\xca\x89\xba%\xe0\x9fI\xbbz|!\x12s\x1az\x1c\xc8x\x02\xe7\xcd\xe6~j\xf9\x94\xc8$\xf2t\\\xbe\x97\x86OR7\x18D'\xde0\xb6w\xf1}\x8b\xad[\xce\xcd -\x85~\xb39\x0e.Q\xce[\x9e/\xf0@:\xb5B\xd4{v\x83^*\xd7\xe7D-\xc7\x9f\xc3\xbf\x99\xe3!iG\x18\xc8-\x19\x06\xe1\x90jT\xc0\xa2\xdd\xf3\xd3\xe6\x9c\xbcuh\x9e\xc4o\xb7\xc4\x0e\xa9\xa8\xf2\xf5\xbe\xdf9\xdb\xa0\xe7\xe6\xaf=\xd9\xf7\x89\x91uEE@\xf6\xbd\xca)\x98\xcf\xc3\xfc\xafb\xc6\xa9\x0f\x00\xbe\xb8\x8a\xe0\x91\xed\x8f\xf4\x1a\xbb\xe7\xd7[\x7f\x9cJ\xccaG\x93\xf5\xa8\xf8\x8f~\xfd\xaf\xb4M\x84R\x12\xa9+Z\xc2\x12Wz]o\x7f\xbd\x9b)\x86$\xafScj\xec\xbe1f;y\xa4\xa4\x1b\xdb\xbe\xbb\x16\xce\xe0\x1a\x13\xaa1\xa1\x1a\x13\xaa1\xa1\x1a\x13\xaa1\xa1\x1a\x13\xb2K\x8d \xd5\x98P\xdc\xe2\xa81\xa1\x1a\x132J\x8d \xc9RcB5&TcBI5\xd7\x98P\x8d M\xa5\xc6\x84jL\xc8*\xa9\xfe\xfe\x1a\x13\xaa1\xa1\xd8\x1cy\xc6\x98\x90\xef\xda\x0c\xc7\xef,\x1c\x1a\xd3\xe9D\xfd\x95\x7f\xcfM\xd3\xcd\xae\xfa\x1b\xdb\xee\xe6.m'P\xf3\xf5\x9etR\x1d \x9e\x0f\xbd\x1ev|\x1e\x8f\x8a&\xfb\x84\xcdKf\x00 \x056\xb2v\xd8\x1b\x8a\xc7g\xcaf\xe9\xa6\xe9^\xf0\xf3\x9e@\xa1lE\xd8\xc5\xf1\xcfs\xdaT\x87@\xb7\xeb\xbb\xeb\xcd\xd0\xd2v\xd3\xec\xae\xab3\xbe:\xe3\x8dR\x9d\xf1\xd5\x19_\x9d\xf1\xd5\x19_\x9d\xf1H\xa9\xce\xf8\xea\x8c\x8f[\x1c\xd5\x19_\x9d\xf1F\xa9\xcexY\xaa3\xbe:\xe3\xab3>\xa9\xe6\xea\x8c\xaf\xce\xf8\xa9Tg|u\xc6[%\xd5\xd1Z\x9d\xf1\xd5\x19\x1f\x9b#\xd5\x19_\xdc\x19\xff4\xcd\xba\xf6\xae\xebu@\x89qf\xbbz|\xab\xd1/q*&Nfjp\x83\xb2!hv\xbb \x84\xc2\xfe\x1f\xfa\x0729\x8a\x9a#\xbd_F\x9f;\xa1M\xa6\x170\x84\xc0$w\xe2\x8b<\xd2\xfb~h\xffU\xac\xab\x81\xec\xf8\xc9\xc8\xcf\x14\xa5\xcf$uh\x17\xaeE\xd1\x95W\n\xb8!\xae\xacd\xa3yK\xd4\xd0\xcf\x08\x17\x8d\xb3\n\x89G8\xb1\x08\xcf \x7f\xe1\x15\xa8s\xf5&|H\xfb\xbbtq\xd2\xcd\xbd\xdc)%\xd3\xe3\x04\xf9\xd1\xc4\x99\xc8\xa1\x19\xedc\xc2{\xa6\xab\xe66}\xd7\x91\x0d\xbfSl\xaa\x90\xd9.\x8d\xce\xe8\xa6 \xdc\xb5_\x0c\xbb!D\x97\xcb\x0c\xb6~\xe4s\x02!-\xbb\x9a\x08jG\xdat\xdbf\x90\xe6\xd0\xe4n\xba\x19\xfaf\xbbiF\xde8\x9d\xca\xcd\xe6%{;\xd1\x8d\xd187\x99BP\xad\xfa\xd6N\xcc\xc9\x17o\xa2\x9eXS\xc0)\x14\xf3\xb1\x14\x8d/\x85bK%\xe3J\x05cJ\x81xRV,\xa9\\\x1c)\x16CZ\x19?Z\x1d;\x12\xfejd\xb4\xbcq\xa3\xd51#\xf4\xde4\xef\xcdiy\xb1\"8\x1e\x1cy\xbe8\xd1\x9a\x18Q(\x1e\x94\x1d\x0bJ\x8a\x03-\x89\xf9d\xc5{2b=\xa8Z)\x1a\xd3)\x1d\xcf)\x18\xcbI\x89\xe3\x14\x8c\xe1\xf8\xe37Ec7x\xdc\x061\xe91-\xb56^#b3\x8e8,V\xb3:N\x83\xc6h\x02[q 6\x13\xdb\xa5K\xc5d\xfc\xf1\x98P\x0b\xf2\xe20\xce]l\xd8ml\x85\xe2/y\xb1\x17g\x95\xb8\x1bn\xc9\x98\x0bE\xe2-y\xb1\x96H(\xc1\x1bcI\x88\xaf`\xce\xd6%q\x15\xec\xfd\xbf\xe0}_\x19KI\xeb|<\x86\x12\xeaiB\xecdQ\xdc\xc4v2e\xc7K\"\xb1\x92P\x9c$\x1c#\xf1\x8cJzl$\x1e\x17qc\"Y\xf1\x90\xa4X\xc8\x9a8\x08\x1aw\x88\xc7?\x8a\xc5>\xd0\xfa\xad\x99\x94\x15\xefp\xe3\x1b9\xb1\x0d4\x96\x91\x15\xc7p\xe3\x16ec\x16\x81x\x85\xeb\xc6u\xe3\x14\xa5b\x14\x05\xe3\x13\xa5c\x13\xa9q\x89\x84\x98Dr<\"-\x16\x81\xb8\xed\xb1ZS}\xcb\xb1\xf8Cr\xec!)\xee`5\xbel\xbc!+\xd6\x80\xc5\x16J\xc6\x15J\xc6\x14r\xbewB,!\x1eG\x98\x95\xbf\xdf\xaaV\x0e\xc3\x15\xe4N\x1e:\xa7\xd5TN\x1e\xf2\xa6\x92\xc4M\x18i\x13]N\xd8T\x90\xacI\x8e\x93q\xc2\xce\"iri\x99\x10J&\x93\x8e =+\x16\xa2a\xf2Q0\xa1uz\xa8\x97\xb0\xa0JI\xca\xa5\x18\xddR\x00\xddA\xabw\xdd(\xd5\xbb^\xbd\xeb\xd5\xbb^\xbd\xeb\xd5\xbb^\xbd\xeb\xd5\xbbn\xfd\x14\xdb\xa5\xabw\x9dV\xefz\xf5\xaeW\xefz\xf5\xaeW\xefz\xf5\xaeW\xefz\xf5\xaeW\xefz\xf5\xae\xff\xee\xbd\xebXv~Nf>\x92\x8b_0\x0f\x1f\xf1\x84e\x91\xe1\xa4\x12\xe1\xd0\xea*5Ju\x95VWiu\x95VWiu\x95VWiu\x95Z?\xc5v\xe9\xea*\xad\xae\xd2\xea*\xad\xae\xd2\xea*\xad\xae\xd2\xea*\xad\xae\xd2\xea*\xad\xae\xd2\xea*\xad\xae\xd2\xbf\x9e\xab\x14\xa7*)LS\xb2\xbb\xd9\x9f\x1c\x0fwC\xb3%'\x0f?\x9c\xfc\xd2o\x8f;\xf2O\xe2X\x9d\xcc\x11\xc1tEZ\xf2\xaf\xee\xdck\x0e\x07\xd8\xf3\xfa\xe4S\x0fz\xb5^I\xe1\x94\xdeM\xdf\x8d\xa4\x1b\x8f\xa3\x92\xe6\xa9\xcd\x18F\xa3\xd7\xd3 \x8e-u\xf1\x86<\x9b\x8f\xaetd\x08?\xee\x9a\xa2#\xe7?6^\x12*><\x1fU\x95\xad\xad\x9a\"\xbc\xbe\xfc'5\x8f\x8eZ:\xb2|\xccP8\xd6\x90\x8d\xfd-\xfd\xca\xe68\xed\xd9\xf0\xed\x84u\xcf\x87\xa7\xd9\xc1\xb7}\xf7Z\n\xf9\x166\xfd~\xdft[\xddg\xb9=\xf2nh\x7f\xa1SV\xfb[r\xd7voy\x86\xb50S4\xf3C\xca\xe4\xde\xb8\xc3a\xd7\x92\xed \\p\xbfH\xb3\x1b{M\x1c\xeb\x8d!\xbe\x87-\xa1dC\xd9\x82\xe5\xce\x8cf\xee\x82\xea\x1a[\xedb\x91A\x03w\xed\x03\xe9\xe6\x01\xe3\x1eB]\xa2j\x8axa\x10\x1b?\x9d\x86\x95\xed\x067\x84t\xdc\xb7)\xed#U\xe1+h)\x1fwM\x9c\xe9\x1a\x91\xae\xc6\xc9\xab;\xb7\xb5\x1d\xa1?\xd2\xd7\xfd\xed\xebmC\xc9\xac~Ts\xaeZ\xb6\x88t\x12\x9b\x7f\x14i\xea\xad\xa1\xb6\x06\xd2l\xee\xd9\x06#\x8d\xc4I>\x9f\x0e\xe4\xb1\xa5\xca\xc8\xa5mt\x16\xaaU\xc7Z\xf4\x9a=\x8f\xcfO#\xa3\x9eYi\x1c\xf3`\xa6\xcf\xcf\x1d\xd9K\x9f\xcb\x81\x0cL>\xd9\xeaV\xf7\xcf\xa4y |hi\xcf\x17\xdf\xbf\x92\xa1\x97V\x9dtr7L\x9f\xbe\x16x\x90\xed4\x08\xddHI3\x89Z\x04\x130UJ\xb8g\n\x1a@\x97v\xec\x834\xc8\xb7\xec\xbc\xc2\xbf\xa5\xf4\xf9\x8dd\xfa\"&iTH\xa3\x1a\xed\xe2'\xf0\xd91<\xfb\xd7\xa6E\xd5\xdd*\x98E\xdbmv\xc7-w \xbf\xb6\xaf\x82\x1e\x8f\x9b{\xe0\xb6\xce]K\xf9\xe2n\xa9\x98\xa8\xdc9\xd6\xd0~`\xca\xf0\xb8\xdbBs\xa4\xfd\xbe\xa1\x92?J\xd5C\xd5BUj\xe6z\xb3c\xfb\xe3\xf5H\x1b\xea\xcc5+:\x87\xc7\xe6(\x1a\x99\xf3:\x03\xc3\xfe\xbe\x8219\x7fD\xae\\<\xaeX4\xce\x1b\x8b\xc3\x0e\x87\x89\x91\xb8Rq\xb8p\x14nU\x0c\xael\x04\xce\x1b\x7f+\x1b}\xf3\xc4\xde2#o\xcep\xbb\x87\xf2\xd2Q\xb7\xcc\x98[\xe1\x88[F\xbc\xadt\xb4\xadX\xac\xadl\xa4\xadX\x9c-\x1ee+\x16c\xf3E\xd8r\xe2kh<\x0d9\xd4\xba\xfa&/\x96\x86\xc4\xceVF\xce\x90\xb8\x99w\xa3\xf4\xc6\xcc\xc2;\xe8\xcax\xd9\x1c\x1f\xc3\xc6\xf7\x9bx\xdd\x85#en\x9c\xac@\x94\xach\x8c\xcc\xde\x0c3\xe3cHL,'\"\x16\x0c y\xa2a\xd1X\x98\xeb~O\x8f\x83\xb9\xef\xfe\x05\xeb\xeb\xaa\x08XJgc\xd1/\x7f\xdf\xa2\x91\xaf\x05q/\xd3\xcd\x99\x19\xf3\nF\xbc\xfc\xf1\xaeP\xb4\x0b\x1d\x85\xd4HW,\xceeG\xb92b\\ \x11\xae\xe5\xf1-$\xba\x14\x8bm\x15\x8al!5\x1b3\xa5hL\xabpD\xabh<\xabd4\xcb\x1b\xcb\xb2\x03\x04v\x1c\xabL\x14\xabX\x0c\xabl\x04+-~\x15\x8d^%\xc6\xaeR\"WN\xdc\xca\xad-5\x86\x11\x8eY%F\xac\x12\xe2UF\x93K\xc6\xaa\nG\xaa\xca\xc5\xa9\xcaE\xa9\xd6\x7f\xddh\x84*\x16\x9f\nG\xa7.\xde\x9e\xbd&\x1d;\xd2le\xb0I\x9d\xd8_\xb7|h\x84g\x8e\xb3xk\x8ez\x10\x1e4\xe0\x1e4S\x95\xb5t\x9c\x83\xbf\x15\xceL+\x1a\x88\x86\xcc`\xb4%\n\x03[\x16\x0eOC\xe1\x105\xc4\xee\xaa\xc7.\xf1\xc6\xee\xa9/\x13\xb2\x86\x92ak(\x1e\xba\x86\xe4\xf05\xa4\x84\xb0!=\x8c\x0d\x89\xa1l\xf0\xddK\x8f\xd7\x9e\x1a\xf8\x8cA1\x93C\xdb\x90\x16\xde\x06\xac\x1b%\xc3\xdc\x90\x1b\xea\xb6d\xa1\xf7\xd0\x97\x0b~C\xd1\x008d\xcf\x87h \x1c\x12\x82\xe1\x90|\xf7|^`\xdc\x12&\xe2\xd4\x91\xe08d\x07\xc8-az\x8c>1H\x0e%\x02\xe5\x96\xbcv\\\x16,\x87E\x01s(\x1d4\x87%\x81s_\x146%\xee\xab\xbd&\xa5%\xc7}\x0d\x8c\xe8\xb88\xf4+\x80\xa4\xd7rl\x9f\x99\xc4\xd0\x8d\xfb\x06\x1d\x06)\xd8\\Q\x1c\x84nT\xb6\x07\xad+\xdf[\x86\xd9\x15\xa5 r\x17\x11h^ee~40o\xb4\x12\x15\x08'\x9c\x8c\xbd\x92v\x98k\xd2\x04) \xd1|\x06|\x96\x05\xa7\xb6\xfe\xfa\xf7\xe6\xfb\xdf\xcc\x93<2\xbb?Kur\xa6\x1a\x7f\xc94\xd8\xe2Y>\x07\xba\x94\x9c\n\xf8[\x15\xcb*\x16\xc7\xaa\x80\xbf\xb4x\x95\xf0\xb3;cT\x01\x7fK\xe2R\x991\xa9\xc2\xf1\xa8\x8cXTF\x1c\nQ\x18\x05#Ne\xa3M\xc5\"M\xf1(S\xb1\x08S\x05\xfcU\xc0\xdf\x82HP\x05\xfc!q\x9e\x9c\x18O\n\x06\xae\x02\xfe\xb4R\x01\x7fP\x01\x7f\x15\xf0W\x01\x7f\xa5\xa2'\xc5\"'e\xa3&i\x11\x93h\xb4$1R\x92\x12%\xa9\x80\xbfYVV\x14\xa4\x02\xfe\x92\x00\x7f\x01\xbf^\xd8\xbf\x96\xee\xdf\xc3\xe5\xa8\x910\xfd|\xed\xcd\xe6d\xd3\x0f\xe4\x84\x1d\xca:\xb2;y\xf8\xe1\xe4L\xfcg\xb2C\xcf\xf6\xdeI\x87\xad\x04(\x890\xc7\x1c'`\xa2\x81t\xb3\xa5\x8f\x9eAHw\xdc\xeb{\xfck\xb8\xbc:\xbd:\xbf\xfe\xfc\xfe\xe2\xfd\xc5\xd5\xc5\xe9\xcf\x17\xff\xe3\xfc\xdd\xf5\xe7\xf7\x97\x1f\xcf\xcf.~\xbc8\x7f\x87<\xcb\x9eD\xfe|\xf5\xe9O\x1f>\x9e\xbfG~\xf1\xfc\xf9\xec\xe7\x0f\x97Z\x05rc{\x93\xdc\"?\x98\x82\x7f\x18\xe19aF\xfe-[\x9ar\x84Zn\xf4\xf7\xdd4t\xc2\xa1\xc2\x96\x1a\x1fQ\xc3\x0b*Z\xf8\nXK^\x81\xec\xe0+`\xff\xcb\x0e\x01F\x13M+(:\xaeo\xe0\x9d\xdc\xc8/-L\xa91\xceo\xe0tj:\xd31\xff\x8b\x1d\x04G\xda\x0c\x94\x88\xad\xbb?\x10~\x8a\xbeo\xba\xedx\xdf|1\x13\xfd\xacocKk6L\x83\xed\xc8\xf6NJ\x9b\xa4\xc0H\xc9A\xb9\x816\xfd\xb1\xa3d84\x03}R!)\xa4\x12\xac\x86M\xcf4\x0b\xb5\xc5\x9f\xc0\x87\x03\xe9\xd4\x93\xa3E\xd4:\x90f\xcb}1#\xe9\x04(i \x1b\xd2>\x08s\x89\xd0\x11\xad^|,\xbb\x01\x1c\x85\xb5\xd9\xf5\xa3\x847m\x9a\x0e\xba\x1e\xd8\xc1\x94\x0c\x13ZN\xd5\xd5\x0f\xaa*\xad\x06\xab\xd2~\xd8\x12\xb6\xa6\x9c\x95\xa9\xd0f\xfa\x82lG\xf1<\xe1\xb2\x8f\x9d\xfc\xc7\xd2E\xfa\xe1\xd3\xbb\xf3O\xd7\xef?\xbc?\xf7\xaeM\xf1\xc8\xe7\xf7\xfc\xff\xd1\xdf\xec_\xa6\x05\x17\x91\xee_g\xbe\x86\xbd\xe1H\xab\xd7\xc2\x9cb\xaaT\x0d\x87\x1a;\xf3\xfbYM\x7f\xa3F\\\xd1\x03o\xc9\xae}\xe0c\xc8\xb6\xb5\xeeI\x88y%7\xc0}\xf3\x04\xdb\x96\xfb\x1dn\x87~/V\x05{\x00\x0cZ\xc5 N\xf5\x04_\xc9@\xd8\xf7\xa6'X;\x9cV4\x83\xde\x04\xf2\xd8l\xe8\xeeI\x19\xb5\xa2&L\xb8\x94\xad/\x1eW\x99[+\xcb\xa3\xc4\x93B6\x87~\xa0\xd7\xed6\xd1\x11\x15\xf67q\xb7\x89w\xf5\xcb\xee\xf6_\xa5}*\x1cp|\xfd`1\x1b\xb5\x05~\xe3\xfc)\xbd\xb9j\xbc\xe6!\xf27o\x1ax\x15\x11\xbf\xbe\xef\x0f\xeb\xa2\xbeVK0\xdaO\x15\x92\x9c\xab\x9b\xa3Y\xc3\xf8\x8a\xef6b\xba\xcaLh>vjn\x8d<\x98\xa4\xcfS\xee\xa6U\xfd\xe4V!\x1d\x9a\x07\xa2@=i<\xcd\xb2\xa1/\xfaC\xf3\xe7\xe3\xac\x8d\xe4\xcbj\xe5\xb4#4w\x03\xe1(\xf7\xbe\x93\xa0]SQ\xbf\xe0\"q\x0d \xed\x99i\x9f=\xb4\x07\xb2k;\xa2\x8ewl\x99\xbc\xee\xbb\x8dR\xdbj\x11=\xc1\x0d\xa1_9:V\xfaU\xa5@\x11\xd5e\x87N\x18\xc9\xa1\x19x\x1e\xc7\xae\xdf|\x11\xf9\x18\xaa\xd9|\xe7\x92\xb1;\xbe\x93\x13\xae\xd7\x0f\xdco\xdd\xdfJaL\x9f\xb3\xeeL\xab\x98O\x19\xfba\xa9\xee\xb5\x07\xbd\xd6\x9b\xb3\x8e\x13L8gM\xa2_\xcb\xbf\x16\x8b\xadCk\x0db\xeb/4\x91\xd2\xd7\x9d|A\x1f\xadi\x824\x86\x1c]\x80g\xcc/\xd4B\xdaV\xdb\xd9\xfcs\xb5\x9d\xab\xed\\m\xe7\xa4EZm\xe7j;W\xdby\xc9\x1e^m\xe7\x82\xb6s\xaa\x11(\xab\xe5\xb3g\x1e\x04\xf5=V\xdak\x96 \\\x1b9V\x16b\xb0\x89\x08\xc6\x1c\xb3\xe0\xcd\xe4{\x82x@\x8a\x9a\xeb\x13\xbee\xaf5\xfd\x81}V\xdd\x9a\xd3\xfa\xa1\xab\xf0\x88\xfa\xf6\xa9nLm\xa7\xa8l|\x80\xb2U\xf5o\xa0\xa6\x83*\xfaY\xd4\xb3\x9cj\xfcKz\xedEY\xa3\xb0\xf8\xe6\xaf\x81M\x89\x8f\xbcM\x97\xb3\xe1\x9e`\xe6\xa7--\xe3\xab\xaa\xc6Y\x0bm\xf1\xc9\x08\x15*\x12Z\x11\xb1#\xf9\xf3\x91t\x9b\xd4\x9b^\x8e\x01>7y\x98V\x12U\x0d\xdb\x866\x89\xd2\x8d\xe4#C\xf6\x14}b\xd2\xac8\xd58\xd5\xcc>\x11\x92M=\xad\x17\xedKN\x13\x83M(\x9e)\xd3nD\x84\xa5#\x1b2\x8e2\xe9n th\xc9\x83H\x19\x1fi?\x99\xb4\xb2J\x01\x07\xd9\xb3V\xbc\xd2-o\xf5\x17e\xe6\x1efS\xf3\xac\xd9\xed\xd8\x02\x19Ud\xa7e'~\xb6J\xd9\xdbJY\xab\xa4Q\xa35-\xdf\x14\x07B\xf9\x86\xa2\xbe \xef\x8e\x08\xf3M\xadq\x1a\xc33\x0d\x1b\xd5\x18\x9f\xf6\x130\n\xf1\xef3\x8e!Y\x97\xf2=\xcd3\xef\x15/r;\xd0\x911\xcd8\xf6\x9b\x96',\xa9\xccyK\x8b/2\x9dd\xc5\x8b\xad\x11\xc91i\xeft\x9a\xc8\xca\xd44\x97r\xd9\xedP2\xc3\x1d*S\x13\xe4d\xbec#V\x99\x9a\ne\xc4C~V<\x94\xcf\x8c\x87\xbc\xecx\xc8\xcb\x90\xc7\x97(\xda\xc8by\xf3P\x01r1\n\x96\xac\xca\xd4\x84\x08[\xcb\xd4\x84\xde<\xe4O+\xd0\x82y\xb3cY\x0f\xe8\xe9\xae`\xa9't\xc5\xe0P\x1a\xd9!=\xb53q:\xa35\x01\x07\xd9\xaf=\x19\xbe\xec\x08HV\xa4[ \x8f\xedHI\xb7!\xba\xfck\xe7\x12\x1c\xf12z\x7f\x0d\x97\xf4\xb5\x19\xa7h\xc2\xaaT\x80\x81<\xb4c\xdbw\xd7\xddq\x7f\xa3b\x94\xa6\x1c\xe4<\x19\xa0\xda\x91M\x16J^\xc8\x9e\xe9\xa4\xa6\xab\x964\xe7\x81\xe1\xa5\x99\x9a\xb3\xea\x06\x8aps\xe4(\xb2Y \xb7Qq\x11\x8a\xaa\x13\x9fn\xc6!\xf4=\xab\x88\xed\xde\xec\xedO\xf2\xbd\xe9\x9e\x11h\xbb\xcd\xc0\xcf\xf1LYP \x0d[\xfa\xb2\xd6\xfb\xd6\xa0\x16\xfaB\xc8\x81)\x13%\xe4=\x1f~}\xb5\xf2Cf\xb3'\x93c\x13\xc6~O4v\xa1fw\xd7\x0f-\xbd\xdf\x8f'@\xb6\x1b`\x95rH8\xa2C\x82; \xec\x10X\xe6\x12\x88\xaf\xe9bn\x81\xdf\xd41\x90\xe8\x1axV\xe7@\xc8=\xb0\xccA\x10p\x11\x84\x9c\x04\x017A\xe4\x94\x9d\xe2*\xc8q\x16\xa0\xe2\xb45\xe8~\xa8\x90\xc3 \xda\x99\x95N\x83\x88\xdb\xc0\xef8\xf0\xb8\x0e\x82\xed\xf4\xb9\x0f2\x1d\x08\x8e4E\xe7\xe9\xb6-\xeeDXs;\xba\xbf_+\x9d\x0b\x8e\x9ci\xff2~\xf1L\xfdxKqjPQ\xfc\xb30.w\xda^0\xd1!-\\\x908T\x14\x94>\x14i\x87\x9ax\x9c)p;\xdb\x05\xb3\xe1<[\x1e\x87\xe6\xae\xedx2\x85\xe3p\x98\x7f\x9a\x8e>\xf3#\xe9\xce\x85\x8e<\xd2\xeb/\xc4\xf6\xb3\xc6\x8e\xf1N\xce\xb3\x1dGUE\xc9W\xc74\xf6\x9f2\x9d\xbe\x19\xa5 \xf2\xb1\xb9#\x9fD\x10\xf2D\xfcn \xf93;!\xf1\xd7\x998\xd6uv\xc8\x1c)\x10\x9e\xc4\xce\x9d\x14\xda+\xb4\xa7M*\xda)\xee\x97p\xd6\x18\x17\xcf\xfb\xc3\xffCxe\x84gJ@\x18\xb4\xcc{['\xeb]\xe5Z\xf2\x9a\x0b\xb1\xf5\x06;7\x8e\x84\xb2\xf3\xe7\xa8\xf0\x17#\x1c;1E\xb7B\xeb\x7fm\xc7\x14P\xad\xa8R;,\xf7FnR\xdb\xc1\xdd\xa7\x8fg\xf3\xf9Y&\x0d\x8d\xcc\x8a\x1b\x88\xa5\x1b6\xfd \x1e\xe4\x9e:\x159VyF\xcc\xf0\xe4v\xa5\xdeM\xa3o\xea\xc9\xcb~?7\nE0\x0f\xe4@x\x9c\xfam3L#\xebC\xd4\x1b}\xe4\xd3\xc3NcS\x99E\x1e\xf7\x9d\x98a\xdc\x7fi\xbb:\x16,\xa6\xea\xa9\xab\x9e\xba\xea\xa9\x03\xcbS7\xaep\xd5\x8d\x88\xaf.\xe4=\x9b\x8c\xb8\xeaG\xab~\xb4\xeaG\xab~\xb4\xeaG[\xaa\x1c\x92\xfcZ\xd5\x8fV\xfdh\xd5\x8f\xe6\xef)S\xe7\xc7\x833\xdc\xd4\xbap\x1f\xc4\\~\xe0\x94r\x0d\x85}s\x18\xc5g\xe7-\xa5\xfd\x14W\xe6\xe6\xa3\xd4\xff\xcd(\xed\xc4\xf1\x8d3\xfa\x7f\x07\x17\xb7s\xdb\xd8\xe7:\x0c\xfdC\xbb%\xdb\xa9\xf9\\\x95\x8e\xe3qO\xb6\x0e\x0f\xe2\xdf\xc1i\x07\xffxu\xf5\x11~:\xbfR\x16\xd8\xe7O?\x8b%\xf3\xc4/\xd3o\xdc\xeb\xcb\xaf\x9e\x0e\xe4_\xfe\xe7\xbfX\xc2@E\xf8;\xf5\x95\xc5\x16\xcf\xc7\xef0\xf4\xdb\xe3\x86@\xd3\x01\x19\x86~\xb09\xbc\xfe\x0eN\x0f\x87]\xbbid\x9f\x07\xc2\xe6H\xffU\xd8N\x9bf\xc3\xd6b\xdf\x7f9\x1e\xa6 \xfaM\xc3,+\xd1h\xa7)\x9f?\xfd\xcc\xeb\xbdo\x1e\xf8\xa7\xdek\xb3q+\xa6c\xa3\x9a\xc9\xfe\xfb\xa1o\x99\xfdf3u\x81\xac\x94/\xb0\x81\xdc\xf6\x03y\xa5^\xe3\xfb\x0cmo\xda]K\x9f\xa0#d\xab\x92\x12\xb8\x02\x18\x1e\x1cV@\xa6e\xd4\x06\xcd\x1e\xe5+\xe0\x04^~\x1e\x89\"\xb8b\xfd\xe5\xe9C\xcd^<\xb3o\xba\xe6\xce\xed\x9f\xda\xf5\x95\xb8\x93\xef\xeco\xfb\xbe\xa7\xdc\x8ejG\xb8=v\x1b1WYK\xe5\x9a\x9e\x0d8-\xcf\x03\x1b\xcc\x9e'\xa7\xb8\xc9\x1dj:\xc0@\x98F%\xc2S\xdfRU\x017|\xf9f;\xcd\xf0\x1br\xd7v\xfc\xf8\xc0\x8c:GA\xba\x97\xdb\xbb\xfa\xe6\x92\xcf\xf4Q\x12\xc6\xd1\xfb\xa6\xb3\xd7+\xbc\x94\x1b<\xd9\x1f\xe8\x93\\\x1a\xdf\xc1\x9eo\xfe7\xce\x82\xe4\xcd\xe4\x19\xd3-;B0E/\xd2\x91\xd4\xad{0\x92}\xd3\xd1vc\x90G\xf2\xb9\x9e\xb8Qz\xb3\x8d\xc2;\xe8/l\x11\xde\x10hXe\xedV\xdb\x06\x9d}On!\xcdM\xff@T\xc3QRJ\x0f\x99\x97Q\xf7\xaf\xa7\xdd\xd3\xafj\xc3\x1c\xd9\x92m\x86\x9b\x96\x0el\xd2\x07\xda\xa0t\x17\xe7\x99\xd3\xc4 20}\xd8\x99\x86\xe1\nP\xb4\xe1\xc65\x00\xf4z\xd4\x9enL\x85\x8fj\xf2\xed\xda\x1b\xde0\xa9\xf7F\x18\x8f\x07\x9eII{~\xb8\xfa\xfe\xd8\xb1\xffc\xbb\x83\xf8f\xa3;\xcb\xed\xcd\x90\x19\x84T,k\xb5tF\x9e\xd76S\xa8\xf1\\?\x9e\xd7#\xdc\x1d\xd3\xfd\x01\xac\x1e1\xd0\xba\xc4\xf3\xc7\x86M.\xf8\xe1\x0d\xcf\x1e\xe4+E6\xac\x99\x06\xae\xed\xe0\xec\xdf\xff{GI\xff\xd8\xf7p\xdb\xf7\xf0G899\xb1\xd3\x86XuM\xf7d\xff\xb9\xe9\x9eNXE?\x0e\xfd\xfe\xe5m\xdf\x7fg?prbk\xe0\xf6\x16^\xb2\xd7>\xf3f]\xf5/\xff\x1d{\xef;$\xab\xc9}\xf7/X_\xff\x10\xe9\xeb\x7fm\x1e\x9aU\x9d\x85?\xf2\xbd\x9eI\\\xd8\xb7v|\xf9c\xdf\x9flv\xcd8\xa2]\x13U\xb3GE\x8b\xb5\xc7\xedZ\x8c>O\x9d\xfe\x8f\x91N\x7f|\xa2\xf7}\xe7t[\xd4\xfbc\xdf\xbf<99\xf9\xce\xfd\x98\xa2\xcb/\x91_\xf8g\xe6\xc3\x902\n\xec\x85\x0b1\x08\xef\xce/\xcf>]|\xbc\xfa\xf0\xe9\xbb7\xce8\xcc\x13\x01\x13-\x84c\xdd\xff\xfbH\xf7\x7f\xea\xed\x9e\xf3\xae\xbf\xf9#\xfc\xbb\xc3\xcd\xc9\x8f}\xff\xff\x9c\x9c\x9c\xfc\xc5~\xa4\xe9\x9e^1\xb3\x81=w\x10\x9b\xe6/\xcd0\xde7;6(X\x03\xdd\xce\xdb\xf58\x95\xb4\xb7V\x15\x9f\xbb\xfd\\ o\x02\x9fl\xfc\xa9\xff\xdf\x1f\xa1kwX\xc6\x1fR\xb31S\x98\xa1\xce\xc7E\xe9\x0de\xb0\xc1\xcd\xd3\xbc\xa5*\xad\xc6\x996o\x9e\x94_\x92mV\xba\xb0\x17\xc8\x96\xf9=;c\x9c\xf0\x1f\x98\x11\xf1B\x1d\xc3\xd5.<\xc5\xd3\xc5\xf7\xd1\xc5M\xaa\xac\xdb=)\x1b\xd99\xb2L\xe6 4\xb7T\x92#\xf3S\xd2\x8b\xef_\xe8\xc2\xa4\x81\xae\xaa\x15\x169\x91\xf3\xe4\xdb\xdb\xbe?\xb9i\x06\xde\xe0\xc7\xef\x9fN\xfe\xf5[\xd1Was\xda\x863\xaf\xee[\xf6\x14S\xab\xda\x0f\xff\xf5\xf2\xc3{\xfd\xdf\x7f\xfc\xe3\x1f\xffh\x8f6{f>\x95\x89\xbd\x9d\x83\x16\xe4F'\xac\xd6\xe3H\x94\x03\xfc\xee\xb8k\x8c\x18\x85\xfb2{pK\xe6M\xea\xd5\x9c\x88*g\xfb+\xb9\xef\x19g9m\x03\xe1\x90,\xf8\xf5\xbf\xb0\xae\xfe*\xf3\x19\xa6-W\x1f\xb8\x13\xb5\xb8\xde8\x06X\xb3\xf9\xc2\xd6\xd5l\x9e\xdf\xb6;b\xeb)\xb5\xfa>\x92a\xec;d\xca\xcaS\xf2m;\x8c\xf4\x9a\x8f4\x9a\x9e*\x1fc\x9fZ=\xf5\x87\xb0N\x04@j\xfb\x96\xf7\xf8\xdb7\xf0-6w\xcd\xae\x9c\x886\x7f\xfb\xca\x95\xc2[\xfb\xbe\xd93I\xffY4\xed\x1f\x90\xc7Xk\xad\xa7BM\xbe\xb8\x95\x86\xa3\xf9-\xc5\xb7hG\xf8Jv\xbb\xd7_\xba\xfek\xc7W\xd1\xbd\xc8\x86?\x8e\xb4\xdf;S\xd1\x9c4\xaf,\xe4\x81\x98Ibyk\x15\xb2 \xd2\xddA#\xa6\x87.\xeeW>M\xd5L\xb9\xefw[\x99r3\xd7\xceO\xfcr\x86\x810\xef.\x13\xf4\xc3\xc9\x1f~\xf8\xc3\xf8\xad\xf3\xd9\xd4\x7f\x99N\xb1q\nl\xe0\xd1\x19\xd4Q\xa7S\xe6jb\xd4\n\xd6\x97\xad\xf8]\n\xb3\xa9r=^\xfc3\xe5\x11\xe6\x95\xfdsK\xef\x17\xfa\xf5=\xa1\xf1\xd9\xd3,\x9a[\xc3\xe3 \xcdI\n*@\x0d\x8fG\x03\x0d\xf07\x1e\x1e\x87y\x10\xab\xcb\xbc\xba\xcc\xab\xcb\xbc\xba\xcc\xab\xcb\xbc\xba\xcc\xab\xcb\xbc\xba\xcc\xe7B\xab\xcb\xbc\xba\xcce\xa9.\xf3\xea2\xaf.s\xbdT\x97yu\x99W\x97yu\x99W\x97\xf9\xdf\xa6\xcb\xdc\xf4\x1f\xf3\x9fq\x13\xd7\xe7\xc1\xd6\x1d\xe7\x963\xda\xf5\x9dKY\n\xc6\x1bp\x98\x7fl\x86Fa\xcf\x1c_\x1cB+.N\xbd\xd72C\xd7\xf6\xe3\xad\x81\xb5\x19\xc3`\xc97\x10\xcf\n\xdf\xa6N\xdeF\xfc@l\x8a\xee\xb8\x8a\xfe\x19rF\xc2\xc5\\\xbc=\x83\x9d\xc8\xbb\x16\x82\x0e\xecQB\xc9\xe0\x83\x08\x88[\x85\xf8?\x85\xd8\xc5x\xc0\x836\xdaNS\x0fnS\xe7&)\xb5\xbe\xef\xb7\xc7\x9dvNr*\xc5+\x86\xd0\xb7\x03\xcf\xf7\x03\xdf\xfd\x99\xde\xa3\xe4\xf3~K\xeb\xcau\xe4C\x04\x91U\xea\xdau\xed=)o\x86R\xc5\xbf<_\x96\x8b?|\xcd\x17\xaf\xce\xef\xea\xfc\xae\xce\xef\xea\xfc\xae\xce\xef\xea\xfc\xae\xce\xef\xea\xfc\xae\xce\xef\xea\xfc\x86\xea\xfc\x96\xa5:\xbf\xab\xf3\xbb:\xbf\xab\xf3\xdb*\xd5\xf9=\x95\xea\xfc\xfe\xdbu~\xeb\xce\xbd\xd0\xdd9\x0e\xcdB\xe5\xb9\xd5\x7fH\xcb\xba\xaeI\xe05 \xfc\xf7\x98\x04\x1eu\xe5\x1b\x9e\xf5tO\xbe\xce\xaf\xf5\xe9\xe3\x99j\xb8\xf4\xe7\xc3[2\xf2\xb3\xa7\xb6\x10\xf80\xbf\xe2\xee\x90\x84\xebu\x94\xc0\xa0\x12H\x8c\x1b,\x8f\x18\xe9\x81\x83u\xe1\xb6\xe4\xbbu\x10j\x1c]\x0e\xa2\x01\xa249\x86`+\xf8\xa1\xcbv\xda\x08\x81v\x827\x1c2\xff\xe6i.D\x1d;\xa2\x14\x0c\x90\x88\xe2\x0f\x93\x88R.X\"J\xb1\x90\x89(\xde\xc0\x89(\xd8Y$1|\"J\xa9 \x8a(\xe1P\x8a(\xab\x02*\xa2\xac\x0e\xab\xe0c\xc7\x0e\xb4\xfe\xe0\x8a(\xabC,\xa84\xa1\xc9<\x81\x16Qr\xc2-\xa8\xc0\xe3\x01\x1a4\xe8\"\xca\x9a\xd0\x0b*\xc8\x1b\x8e\x11%3(\xa3\x84$\x84f\xd07\x93\xc35\xa2d\x04mD\xc9\x08\xdd\xf8\x16\xba\xa7\xa9\xc5\x82:\xa2\x94\x0d\xed\x88R,\xc0#J<\xcc#J\xb1`\x8f(\xbe\x90\x8f(9\x81\x1f\\W \xc1 Q\x90S\xa4Oc\xae\x0d\x0c\xa1\xc2|\xc1\"QV\x86\x8cDA\x02G\xa2DL\no\x10I\x94\x14\x8bce@ W\xa6*\xc8d\x85\x95D\x89\xb5&/\xc4\xe4\x88\xe3!'$\xd0$J\x81p\x93(yA'G\x1c\xb7hP\xe3!3\x00\xe5\xd6\xe4\x04\xa4D\xc9 K\x89\x12\x8c\xd7\x88\xe2 Q\x89\x12\x0dT\x89\x82x\xd5yI\x0fZ\x89\xe2\x93\xe38.3\xc3X\xa2\xa4\x0fN,\xa4%Jl\x14\xa2\xe1-Q\x16\x04\xb9DAF'7\xe0%J0\xec%\x8a?\xf85\xfd\xee\x0d\x81\x89\x12\x18\xb5\xd4p\x98(\xb1\xa0\x98(vhL\x94\x8c\x00\x99( a2Q\x96\x07\xcbD\xf1\x0dS4p&J\xa1\xf0\x99(\xde\xb6 31+\xa0\xe6H\xb3\x02l\xa2\xe4\x84\xd9\xdc\x1a\x9c\xb0\x9b(Y\xc17\xb7\xc9f0N\x94\x92!9Q\xbc\x819Q\xec\x98\x88(v\x90N\x942\xa1:Q\x8a\x05\xecD)\x1b\xb6\x13%-x'J4\x84'Jb \xcfx8\x18\xce\x13\x05\xd3\xfeh\xf0G\x94\xd4\x10P8\xc0'e\xa5\x85\xf9\xe4\xc3\xf1`\x9f(H\x87J\x06\xfeD\xc9\n\xff9\xd2\x9cp\xa0(\xe5\x82\x82Z5EB\x83\xa2\xe4\xce\x91h\x98P\x8a\x8b\x04\x0bE\xb17.\x1f\xd1\x94(\xa1\x13L&\xe9\x94!K\x12P\x19\x7f\xc3x\xa8\x90V)|\x03\xbf\x80|\x0bz\x08@\xa9<\xe3\xc2\x8dzk7/\xf5\xd6\xeezkw\x91[\xbb\xd3\x82\x8d+pC\xe2=)\xcf\x0d7\x86\xc2\x80\x06\xb0oy \xb02he\xc5\xc5\x8aE\xc4*\x88(-\xda%<\xec\xce\x18U\x10Q\x05\x11-\x8bD\xa1G\xf5b\xf1\xa6\xb2\x91\xa6b1\xa6xt\xa9X\\\xa9\x82\x88*\x88hA\x84\xa7\x82\x88\x90\x98MN\xb4&\x05WSADZ\xa9 \"\xa8 \xa2\n\"\xaa \xa2R\x91\x89b1\x89\xb2\xd1\x88\xb48D4\x02\x91\x18{H\x89:T\x10\xd1,++\x8aPADKAD\x86\x05k3`a\xa0\"''\x1d$\x1c\x86\xe3O4a\x06\x0e\xa2\"\x8e\xf4\x1f\xe2NsZ\x11G\x15q\xf4;E\x1c\xd9\x9a#\xe0\x86\x0f\x06\x00\xf4\xd7\xbf7\xdfW\x8d\x9e\x19\xc4\x92#\x00+\xb0@f\x08\xe0\x99\xe1@\xd8\xcaL\xbd\x0fG>\xbb\x0e\xdb\x13TU\xa2x5\x84(\x01=!\xdf\xcfR^\xa2\x04U\x98\xac\xa6\\3\x93\x95\x9a(\xb1$\xdfr\nN\x94\xb8\x9a\x13%S\xd9a\xf2\xdcJ2T\xa0#\xcb\xf6\xc3\xba\xb5\x15T\x87\xa2\xf8\x94\xa2(\x19\xaa\x11\x99\xc2\xf6\x98z\xa3\x8c\xa2\xac\\\xd1\xb4\xa2\xf5*Z\xaf\xa2\xf5\xa2\xb1LTZE\xeb\xad\x8d~*! 1P\xf4\xcd\xe4\xb8\xa8(\x19\xd1QQ2b\xa4\xbe\x85\xeeij\xb1\xe8\xa9(ec\xa8\xa2\x14\x8b\xa4\x8a\x12\x8f\xa7\x8aR,\xaa*JE\xebU\xb4\x1e\x1f\xa9\x8a\xd6\xd3K^t\xd7\x11G+Z/\x1e\x11\x16%\x86S\x8bG\x87E\xa9h\xbde\xd1dQ*Z\x8f\x97X\xf4Y\x94\x8a\xd6\xa3\x19qjQ*Zoa\x94\xdbmrE\xeb\x95\x88\x8c\x8bR6>.JZ\x94\\\x94h\xac\\\x94\xc4\x88\xb9\xf1pE\xeb\xf1R2\xc2.JV\x9c\xdd\x91V\xd1z\xcf\x87\xd6\xeb\xdd;\xaeD \x1db\xd6\xdfwe\x88\xd14\x8b}\xebU\xa8\x91#\x9a:\xe0\xf2\x90Vx\x1eTx^\x85\xe7\x95\x82\xe7\xd9\xb34\x14\x1e_\x1b\x9a\x1f}A\xf9~\xbfo\xe9^\x06\xe6\x7f\xe1\xf9:\x1f\x07r\xdb>&\x07\xe2\xbf\x90\xa7\xeb\x83\xf6\n\xf8f\xb6\xb3L\xed\x8e\xeb\xd5\xb3\x8e\xaa\xf4\xa1\x86\xde\x83\xa8A,M\xb9d\x95:\xbb\x12\xd1\x84\x91\x0e\xc7\x0d\xfb6l\xb5\xde\x0e\xfd\x9e?\xf7\xb1\xe1\xeaq;\xads\xb5;6\x87\x03\xe9\xb6/\xd9\xef'\xff\x8d<\xb1\xffW\x1b\x81\xfd\x13\xaf\xfa\x15\xaf\xf2\xe4\xe4\xbb\xef\xcc\xf1\xeb:\xc2=)l\xfc\xce\xa6\x7f\x9dw\xdb\xe4\x01D\xa8F\xd1\xf13V\x93\x8c\xcb\xbb\n\xbb\x1dAk\x94|Yz\x89\x9f9Ib\xde)\xf0P)\xea\x84\x94\x93@D'UC}\xe4\xa9\xb7\xa4\xa1\xc7\xc1\x8d\xaab\xbd\x11\x05\xbd\xb2/\xa5A\n\xb4\xae\xaa\x9c\xbc\xf7;2\xef\x8d\xb3\xbb\x12mph\xab\xff'\xd9S\xfd\"@\xd9{\xa6\xc5d\x94\xe7(w\xa3\x8e\xdc\xf5\xb4\xe5\xf7\x01\xde\x13\xb8x{f\xc8z C\xcbLx;F)\xe3lr2\xc0}\xd3m\xc7\xfb\xe6K\x12.\xe6\xe2\xed\xd9\xf45\xe4\x81\xa4\xe9\xd8\xc2\xe1.D\xd9\xac-\xa1d\xd8\xb7\x1d\x01\xd2mz\xa6~G\x19\xe1\xe1\x0eV=\xceu\xdb\x1b'\xaa\xcd}\xd3ud'\x1eo6_\x08\x1d\xa5d\xd6{\xcf4\xb6\xc2\xf0\xe6\x82\x10\xb1\x08i\x15)Z\x81\xb9\xf3\xa4\xd3\xed\x1f\xec\xf3\x93\xee\xb8\xd7g\xcak\xb8\xbc:\xbd:\xbf\xfe\xfc\xfe\xe2\xfd\xc5\xd5\xc5\xe9\xcf\x17\xff\xe3\xfc\xdd\xf5\xe7\xf7\x97\x1f\xcf\xcf.~\xbc8\x7f\x87<\xcb\x9eD\xfe|\xf5\xe9O\x1f>\x9e\xbfG~1\xfe,\xdd\x07o\x12+\xe6{5\x19\x0e\xcd@\x9f|\xa3\xa2=\"H\x16RU\xc6\"\x83\xcd\xc3\x96\xec]eaG\xbe\x95\xa0 U]\xaf\xe2\xc6\xd1\x1e\xd9\x07\x1d\x91\xe3j\xfd\x11\xeb\xb1\xfe\xd7\xe7\xea\x8c1#\x93:e \xc4\xe3\x11\"\x01\n\xef\x94\xbd;\x83;K\x94\x150\xa7\xec\xf2MxZFv\xf3N\x90\xa1A2a\xfcy0\x98\xd5\xa0J@9\xc7\x8d}\x17X\xb8\xd4\xaa\xb0\xde_e^X2Pc#\xf2\x8cku\x00\xffn\xbb\xe6\xe9\xfa@\x86\xb6\x8f\xd9\x0b\x9eS\x84\x7f\xbar\xd9 d\xcb|\x86\xe3H\xf9\x99\x08nx(\x1b9\x7f\xaa]AFg\xf5i\xc7\xd5\xfak\xb69\xdd\xca8\xbe\xde\xe7\xf7\x1f\xae\xce\xdf\x98u\xee\xfa\xbbv\xc3\xbe\x11\xf7VNQP\xe1t\x15\xb9q\\\x17`\xf7\xe1NV\xa4a\x84i\x07g\xde\xdc\xdb\xe3N\xceS\xb6\xf4\x1a\xb9\xd6\xe4\xb2\x11\xf3\xa0\xe9\xf8AFJ\x1b\xc9\xa1\x19\xf8\x8e\xd2M\xdb\xa6h9\xe5'\x11>B\xbc\xb97\x04\xfe\x00\xea,d4\x82\x1fo\xc8H\x9b\x9b];*t~\xa3\xab\x82\x1bB\xbf\x12\xd2\x01\xfd\xda\x8b&Y\xb7.[V\xa6\xad\xf6\x9f\xcb\xc84fGI\xad\xechdWqy4qf\xa3\xb3\xb4\xaf\xaby}Z\xd7\xd6l\xc5\xb4\xed\x82=\xd9\xa7a\xa3^\x07\x0c\xc9a\x0cj\x8eF\xcd\xd5\xa61M\x9a\xa2E\xf1\xe9\xa2/+\xc3*O\x99\xdb\xda\x1c\x90\xe2\xa4\xbd\xe9Y\xc3\x1a3\xd7\xf4\xf7\xe4\xb5\xbcl=hs~>\xa4\x9c\xe4\xa8\x85z\xf6t\xe5\xd7\xb3\xe7\xe2\xb3'\xa6Z~O\xa7N\xf9^=t\xd6CgB\x8f\xea\xa1\xb3\x1e:\xe7\x92c\"A\x013 \x12L%\xec\x99\xdf\xe4\xd0i\x9c\xf9\x924\x03~\xd2\xc3\x8c(3R\xaa\xfe(\xa6\xef\x1c\x15u\x94<\xc6d\xea1\xdd4\xde\xc4\xb9\xdaU\xf8E\xb5\xe8\xd9\xacXg\x1e\x85\xac\xb4q\xd7n\xf8\x9e\xc4\xe9\xe7L-\xc0k\xc4\xacX\x81\xd1\x94\x02\x7f\xc7\xf0\xef)O\xd5j]\xd2\xc6Q\xe1\xdf\x15\xfe\x1d\xc3>\xfeo\n\xff\xb6\x82\xcc>-\xb6 \xccl\x8b\xf0\x06\x9a]\x1d:\xfd \xb9\xf22Y\x8fN\x9a{{\x8d_\xad\xa8r]t\xaek\x94\"C\x9c\x0d\xd6(\x94\xa5\x96\xa8\xd9$\xf4\xf8\xe6\xbf&r\x85\xddC\xbd\x90\xd3\xa0\xd5\x13\x83[\x14\x07\x9b\x86\xa1\xa6e\x81\xa6Ea\xa6A\x90)\xcd\x83\x98\x96\x04\x98\xc6\xe1\xa5\xab\xc1\xa5%\xa1\xa54\x0e,- +\x8d\x82J\x0bCJ\x83\x80\xd25p\xd20t\xb4\x00p4 6\xba\x0c\"\x9a \x10-\x0b\x0f\xf5!\x16\x8bBC\xcb\x03C\x8b\xc2B\xd3@\xa1E!\xa1!@ha8\xa8\x0f\x0cJS\xa1\xa0k\x81\xa0\x02\xf4\x89\x08\xc4a\xa0\x19 P\x0f\x04t\x9dc\x03\x92\xf6\xffr\xd0\xcf\x10\xf03\xdc\x8e\xa2\xa0\xcf\x10\xe4\xb3\x10\xe03\x0f\xee\x89\xac$l+/\x0b\xf5\xa4(\xd03\x17\xe6\x19\xc51\x06 \x9eI\x00O\x1c\xef\xb5\x0c\xdc\x89\xcbp\xb0\x1e\xd9\xb0\xce\xd4\xc1H\x81t\x86\xfb\x9d\x04\xe7\\\x08\xe6t\xb1/\x05\x80\x9cQ\x18g\x18\xc4\x19\x83pzGi |3\x05\xbc\x89A73\x81\x9b\x89\xb0\xcdu\xa0M\x0fL2\x05\xb0Y\x10\xae\xe9i\x853\xd3\xb2\x80\x9a\x180\xb3 ,\x13\x07efA21\x08fi\x00f\x10~\x89\xe1\xd20\xe8e9\xe0eQ\xd8ey\xd0e:\xe42 p)\xfd\x18)pK\xf9h\x14l\x89B-\xf1\xdaS!tq\x98\xe5\x02\x90e\"\xc4\xd2\xe9FixeIp%\n\xad,\x0b\xac,\x0b\xab\xcc\x9b\x0fI\x90\xca\x14@\xa5\xb9\xad \xbe\xdb\xe9w?\xb8,\xf3\xdaCu\xd5\xe1,\xd0w\xcf\xe1\xef8@V\xf9\x91\xd3\x9aS\x03d5@\xc6e\xf9P\x98\xfe\x10\xd5\x82 \x19&fU\xa0\x0c\xe5kN\x8e\x95\xd5k\x13\xf3\xe2F\xc5bF\xf5\xda\xc4\xb4\xd8\x90\xf0i;cT\xafM\\\x12\x03\xca\x8c\xff\x14\x8e\xfdd\xc4}2b>\x88\xc2(\x18\xdd)\x1b\xd9)\x16\xd5\x89Gt\x8aEs\xea\xb5\x89\xf5\xda\xc4\x05Q\x97zm\"\x12S\xc9\x89\xa7\xa4\xdc$X\xafM\xd4J\xbd6\x11\xea\xb5\x89N\x84!\x16\xe3(\x14\xdf\xa8\xd7&\xcaR2rQ\xafM\xac\xd7&\x9aR\xd2\"\x10 \xd1\x87zm\xe2\xfa\xd8\xc2\xfa\xaf\x1b\x8d)\xc4\xe2 \xce\xb5\x89I7%\x1ai\xe0\xa9\xf8h3Pq\xf1\x0e\x17\x8drB\xd6 \x82\xfeC\x9a\xd7\xbe\x06\x11j\x10\xe1o1\x88\x80\xba\xefW\xc5\x11\x0cIkB k\x82\x07\x06Q\x05\x18zU!\x0b1\xbd\xa7\x189\x11\xa0\xcb\x02}\xb2\x14d\x93AY\x01(m\xc5\\\x9bK\xf6\x80R=\xa0\x9d\x13%tA\x9c\x9f\xca\x02B\xfd\x95?/\xa1\xb4\x80\x00\xad\x05\x04z+\x8a\x87\xde\x02\x92\x1bY\x82\xe6\x02\xa2\x1e\xb2\xb2t\x17\x10\xa0\xbc\x00H\xa1\xbd\x80h\x8b3H0\xdci&(1l\"\x0cXJ\x86\xa1\xb7\x1f\x01\xa5\xadg\xc5\x80\xd0t\xb1\xd91`!C\x06\xf8Y2 \xc8\x94\x01>\xb6\x0cX\xce\x98\x01^\xd6\x0c(\xc9\x9c\x01!\x8d\xe3\xd77\x1e\xb5\n\xb1U\x1c[t9\x8c\x1a\x880 PGY5\xc0\xcb\xac\x01av\x0d(\xdf\xc9D\xa6\x0dD\x92K(\x82<\x14b\xdc\x00\x0f\xeb\x06\x94f\xde\x80\xf0\xde\x16\xde\xdd\xc2,\x1c\x10\xfb\"\x10\x03\xad\xf8\x189\xa0\x00+\x07\x14b\xe6\x80Dv\x0e\xec9\x9c\xa1\x03\xbc,\x1d\xb0\xf2x\x13\x9e\xfa\xb9T\x91\x96\xb8\xdbi\x0b\xf2\xd2EB\x11\xcaH\x08\xf6,\x93:R\x93\xa4H$\xb5?\x99L\x92\xda\x0f\x99t\x92z\xad\xba\xfe\xc19%\xa1z\x1c\xd2\xd7@\xf58T\x8f\xc3\xef\xdc\xe3\x80\x7f_\xcfY?\xe8ip|\x0c\xf0\xe9\xe3\x99j\xb0p.\x9c\xc0[2\xf2\x00\xbak\xeb\xbc\xe2Y\x1d\xddfw\xdcr\x9d)\xd6\xb4\xda\x0b\x8dQa\xdb\xa5\x12\x1cT\x02Q\x16&\x97\xb9d\x85;c\x1d\xf5\xd2\x02fJ\xdc/\x80\x1a8\x96\x9d6\x0d\xb0\xcb\xdc)\x8a\xd7zO\xaec\xb1c\xc4\xe7\x1a \xb9\x0b\x82L\x98\xab\x8c\xc8\xb0\x93$\xc1\x88\\\xec( \xbbJb\xce\x92\xa0\xbb$\xbd\xb9\xa5\\&1\xfb\x0e\xf2\xdc&\x884\xe9\xd4\xf0:NR]'!\x0b\xbf\x9c\xe3$\xe2:Y\xe8<1\xdeF\xbc'\xb9\xfe\x93\xe0\xfc\xc1|(\xcb\xbd(A?J\xcc\x93\x12\xf0\xa5\xac\xf2\xa6\x84\xfc)\x85=*\xab\xbd\xb8\x01\xbfJt\xb9\xc7\xd7fa\xefJ\xdc\xbf\x12\xf2\xb0D},\xcf\xd2\xe1\xf5\x9e\x96D_K\xdc\xdb\xe2\xf7\xb7<\x83\xc7%\xb2]\xc66\xcc\xb8\xdf%\xfa\x95 \xe6{ {_\xca\xf8_\xcay`\xd2}0K\xbc0!?Lp\x84\x03\x07?k6-\xe7OE\x84X\x97\"\x16\xe4R\x15\xc5\x87\x99\xb4\x9a\xa1\x0c\x9a\x91\xf6\x03\xd9\xeaV\xf9\xb46\xf4\xe5P\xef\x9e\xe4\xa5\xde=Y\xef\x9e,r\xf7\xa4\xf2\xa58\xabI\xcc\xb0\x9b]\xbf\xf9b\xbb4\x16,\xa6\xea\x91\xab\x1e\xb9\xea\x91\x03\xd7#\x97\xc6\xb4\xeb\xb8\xe4\x14\x14\xd2\xf5\xcc\xf9=e\x97\xf3y\xd3\x99\xe2\xfa\xd90\xf5D\x88\x9c\x03\xf1\xd3\x9fs\xe6[t\xd2\xc3\xf5\xb7I\xe5\xd0\xde\x9a\xa6 \x9f\x00\x1c{)m\x07\x81\x89\xe4\xde\n\xf6\xe2\xa4\x9bX\xc5\xaf@6\xf7\x15\xb0\xffe\x07y\xa3E\xb3\x9e\x8e\x8e\xcc\x1bx's\xef/u\x8a\n}\xa4\xde\xc0\xa9}da\x9b\xc3\xff:\x8e\xfc\x9c?\xf0\x08\xd2=\x81\xfe@\xb8w\xc5\xf5~X\x83\xec\x11\xd8l\xbet\xfd\xd7\x1d\xd9\xdeI\x81\x93 \x18)9`\xe7$Y\x81y\xec\xd0?\x9e\xa7\xaaM\xbf?\xec\x08\xb5\xeb LE\xe9Q\xd2'c\x1a\xb7\xb3\xb6s\xa0j:\xd1\x99\xe7:\xf0\x168|\xf1*\xf3\x1cr\xf8$\xcfp\xbc\xd9n6\xd9\xd6\x80g\x8d}\xaaF\x83\xd5\x9e\xd0\xa1\xe9\xc6[2\xb0\x0f\xf6\x8et\xfd\xfejh6\xe9~uv\x98\x8b|-\xff\x0e\xc8O\x82\xc6\xdd[\xdcw\xd1\xdf\xc2\xa1\x1f\xe8\xf7\xd2\xe9\xa6\x8d\xe2\xa8!H\x87fc\xee\"\xd6\x1e%I\x06\x94j8vw\xfc+\xd1\xfe\x0b\x99\xe6\xfdM3\x92\xeb-\xeb\xf5\x92>\xb0\xb7\x80\xbf\xa5N \xb2\x92\x81\x9d\xd4X\xfb\x90\xca\xf0Q\x98G\x1c\x0c\xa4\x87[\x05\xeb\xf3\xc5\xd9\xe5\x1f\xfe\x83%}d\xc7\xdfo\x9c\x11\x90\xbd\x97\xa3\x04m'\xcc\x9aV\xde\x06\x11\x9d\n\x1f\x9b\xa1Q\xcb\"a\x1a\x8c\xa4\xdb^\x93\x8e\x19\xfdN\xee\xfcM\xdf\xefH3[D\xd3\x19\xca\xfa\xbb\x7f\x9e\xe8\xd2A\xfc?\xf7\xc4n\xdbQ\xfcw\xb3\xdb\xc1f\xe8\xc7\xf1\xb5\x98A|d@\xf5g\x14!\xa8Y\x1e;4\xebS\xc5\xd0\x85\x03\xd9\x90\xf6\x81<_o\xac\nVu\xc88\"\x06\xba\x83\xb7B|\\c\xe51#\xaf\xbf\xe5\xfaD\xd5\x02\x07\xf6\x18\xa1d\x18\xa7\xcdQ$/\\\xf5p\x18\x98\x89D\xa1\x01f/\xa9\xc9(\x1c37\x84;\xc5\xa5\x98\x81l_\x81eC^\xa9\x8e\x9c\xcb1\x98\xaa\xe2\xfe\xa0\xe1H\x94S\xa7S\xaf\xc2M\xd3}\x81}\xbf=\xee\xc8\x0be\x18]\x92n+E(\xd1\xb3$eU\x19\xcb\x88\xf6p\xdb\xec\xc6\xb8.\xe4\xb6\xd8\xbc<\x17\x07\x1cy\xad\xd7tV\xa6\xe8{\xf8\xbb\xe0(V\x08\x9dX\xc2\xee\xd4\x0c%kIR\xca\x04\xa3\xc9HP\xb6\xe0Q\xb8\x90\xdc\xb7U\x8a\xd7\x91b\x8cP\x01\x05\xacIS\xbc\x90\xda\x9f\x12\x14\xb1\xcf0\xf0L\xc1\x943\x84\xd6-vx\x10\xf2\xcc\xb3C\xea\xcc_\x1ek\xd7\xa6\xfe:\xdb+9\xd8\xee.\x92\xa0\xcf5\x16w(\xb7T\x82\x8b%}\xb9\xf8\x17Lz?W/\x9a\xf0x\x95]8\xe8\xd2I\\t\xbb\xa7\xd3\xedv #\x8f\xe2\xd0\xa1\x95p\x0e\xc9\n\xcd~\xf0K\x9d\x86U\x17y\xfe@\x86'\xde\xaec7\x8b\xb4\x97\xe1\xfc\xbc6\x97\xf8\x14R\xf5\xc9\xda\x03\xf3\xcb\xf84\xfa4\xe6t\x9c\xe3(\xd4I/\x884\xf1i\xcf\x1a\xa0Ozox(\x9d\x9e]]\x9f}xw~\xfd\x8f\x17\x97W\x1f>\xfd\xe9\xfa\xc3\xc7\xf3O\xa7W\x17\x1f\xde\x87m\xb6\xa4\x97\xad\xfc\xf9\xc4\xb7~\xb9\xf8\xe9\xd3\xe9\xd5\xf9\xf2\x17\x7f:\x7f\x7f~yq\xa9}Z\xb9\x8c\x93\xde^j\x0e.\x15\xaa\x0f>\xf2\xd5?\xa8\xef\xb8d\xa7\x06\xdc\x8eLj\x9aH\xd5\x88\xb5\xe4\xa2k\xa9\xa4i\x16\x99N\xe2\xc46\xef$V2lb\xe5\xf2\x1b\xc7\xeb\xff\xa5\xbd\xe3Hb\xb1\xa4\xf8?\xd6\xd5('G\xbc\xc6\x9fHG\xc6V\xe3\xd3\xbe\x93\x7f`ky^cJ\x07\x84\x85\x81<\x86\x89\xc3\xdb\xa6\xe1.\xf3F\xf4Fd~I\x89\x19F\x83\xa9\x90\xde\xcd\xbe\x83[2\x90nCT\x9a\xb9\xcc;\xfe\xe7\xd3\xcb_xu\xf2\xf5\xe3a\xcb\x0e\xde\x1e\xaf\xd6g\xf1+\\=\xce\x07\xd1\xaf\xf7D\x1c\x93'\xdd\xc3O\xf0\xe4\x91l\x8e\x94lWy\xb7p\x8f\x03\x84,\x8a\xb8\x8f4\xc3\xfb\x00\xa8\x07\x02\xf2\xda\xe3X\x07+=\x12\x96\x14\xdd[\xe0z%\xc0\xe7\x99\x00\xd8\x8fw\x89\x13n2\"\x8d\xc9\xe1\xdb\xbc\xf8\xde\xc7\xb7>\xce+\xafF\xda>\x94\xc5\x16O\xd2Q-i\xf1cg\xb8\xa4\x17\x8d\xcc\xbf\xa47\xcc\xdd+\xf1%}\xe7\xca\xdb\xb5|\xc7\xc3\xa5\xc2\xd4\x00\xc7\xbeQt\xa7\xb2O\x93I\x0d)\xbf7%V\\h_J\xac\xad\xe0\x9eTr?\xc2\xd6(3]\x93m\xd2\xdfp3k\xc6\xbd\xbe\x99\xa5\x1c\xa0\xe7*\xc4\xc3\xea\xb0\x00_\xef{\xe0\xd7\x8c\xc8\x8c\xe8\xe9\xb0\xbc56\x0c)\xa6\xd9\xee\xdb\x98\xd1\xad\xce,\xecQ\xae\xe4\xe7kR\xa6Z\xe5\x97\xe8\xd4\xfe9\xcf&u\xa0\xd957d\x17\xa9\xc9X\xf7?\xb3\x178S\x8c\xaaLW\xc87\xd3\xe8I$\xa4\xb5r6S|J\xee\x8ao\xec\xfe\x98L2r\xebD-\x04c\x93\xd5G\xd4\x80\x86\xf0\xdb\x89x\xf3\xe4u=_\xc8\x81\xb5\x86\x92\x81\x8fT\xb7\xe57h\xdc\x10 \x8f\x87\x9eM\xd9\x87\xb6\x91\xe1W\x19\xdd\xd4CH\xff\xf5h\xdegt\x1cE\xecd\xec\x07j|\x9dj\x9e\xc8w~\x9f\xe6I\xe8\xfcU \x80\xa2I\x93\xa1\x94o\xf4&\xf9\xe3)\xac\xb47\x9b\xebC?D\xf9\x92G\xda\xd0\xe3\xe8\xac\xa0K\xfeg\xd1d\xf1\x08\xe7`\xb7u\xcc\xf2\xb3\xfc\xe5\xd5\xe9\xd5\xe7\xcb\xf8\xb1]>wzvu\xf1O\x9e\xa3\xb6|\xe4\xe2\xbd\xf5\x90k\xa0\x04*\xc5\xc3_\xd1F\xcf;\x99\x1c\xa9c\x87^\xe3\xe2\xeb\x91\xf3>\xfb|\x0f\xbec\xb2\xd5S\xe7\xe5\xb63^'\x8f\x94t\xab=\xa7\xb4\xde*Wo\x95\xab\xb7\xca\xd5[\xe5\xea\xadrS\xa9\xb7\xca\xd5[\xe5\xea\xadr\xf5V\xb9z\xab\\\xe0\xddz\xab\\\xbdU\xae\xde*\xc7K\xbdUN\x96z\xab\\\xbdU.\xe3\xde\xb1z\xab\\\xbdU.z\xab\x9c\x15Z\xba\xe8n{\x11@`\xdfEf\x13X\x01\x04O\x10\xe9Rs\x86:v\xbc'\xac\xeb\xf5-F\x9c\x99\x11Gf\xb2\x13\x13w`f;/W:.\xd7:-\xado(\x1f\xa1H\xda\xeb/\xfdV\x05\x9bh<\xd2g@\xf4\xd0\xa3\x19z,\x93\xcd\xb9'\x8f\xaf93\xed\x04\xc0\x1bH\xc3O\xb77\x84\xb2m\xef%?Y\xb7\xcc\xee\xa7\x9c\x94h\xd3\xb6\xca\x0c\xb1\xce\x86\x8b+\xbfiF\xf2\x7f\xfe\xbd\xaa\x7fh\xbej\x91j\xf9\x08\x1f\x0b\xe5\xa4\x1f\x8e\x1b*Y\x96\xb8^h\xe0\xbf\xfd\x13\x1c\x9av\xb0\x06\x90\xa3sNw;}\xac\x97C\xe8\xf7\xac\xeagF\x10;\xf8\xca\xc0\xe9:H\x87Y\xe2s\x8a\x82\x1c\xf83\x1b\x15\xfa\xcc\xc6\x83\xc9\x1f\x1b*L\xb6\xc2d\xcb\xc1d\xed\xb1\x0f\xea\x8f 0P\x17\xf0\xbd-\xc1\xbc8\xd1QXg\xfdv\xb9\x92\x12y\x1eSf\x08\xfa\x16\xfe&`Y\"\xb0\xeaS;)\x1f\x011\x08v\"\xf0\xb4w\xc1\xc4p\x14\xe0\xd7\xc5!\xeeb\x9f(\x08\xeb@\x1f\xef\xb9\x9dx\x1fb<\xb7\x9fE1\x16\xeec\x01\x9c\x85\xfb0\x8e\xb5\x80\xa5x\x0b\x88\xbat!\xd4\xf5\x04\xdc\x05\"\xce\x93\xce\xe6\xafq9\xfe\xc2\x95Q\x12\x83\xe1J_\x8b\xc3\x00X\x88\xc5\x00\x1f\x1e\x03B\xf3z\x05.\x03 \x1f\x9b\x01RK,5,e\xbd\x8e.MAr\xb3\xe7\x13\xd4\xf3r\xbe\x82I??\xb3!\x89j\xf2$\xbb\x0d\xd9\xb8Q}\x1e\x9a(\xb8NO\xaa\xde1\x84R4{@\xb7\x87\xb4{X\xbfG4\xbc_\xc7/\xd3\xf2\xc9z~\xa1\xa6O\xd7\xf5+\xb4}\x8a\xbe/\xae\xf1\x93t~\x19\xad\xff\xdcz\xbf\xa4\xe6_\xa1\xfb\x03\xda?8\xebW\xee\x00e\xf6\x80z\xc0\xab\x07\xbc\xb2\x07\x00Brd\x19 Y\xf9\xa7\x92\xa7\x8d\xa5x#\x0b<+\x8a\x03\xa1\x15\xa5\x1c\x90V\xb6t\xdd\xb1\xc3\x8f]\x11%r\xf0\x08\x0e\x1e@)4\x8b\x94\x85bZ\xe4oe\xda\xe99>\x94\xc1\xba\x88\x12G\xbc\x88\xe2\xc5\xbd\x80\x0d\xce\x15%a\x8a[\x96_.\\\x17\xaa)\\M\xe1\xe2\xa6\xb0C\x06\x8a\x99\xaf\xe9\xa1\x0eK@\xa2\xb5\xbc\x8a\xdb)NS\xa6uS!\x96\xbdX\x8e[\xe8Y\x07!\x8c?\xe6\xa0\x84aI\x92\xdd\xfc\x82\x0f-\x8c\xd7\xba0\xe9\xce/()\xf9\xce\xffzZ\x12\x9e(\x08z\x18\xd6\xa92\x8a\"\x89!\xa6&b\xce\x9f\xa2\xa8b\x08\"\x8b\xa1(\xba\x18J\"\x8c!\x842f\x85\xaeG\x1aCA\xb41D\x11\xc7\xb0\x16u\x0c9\xc8cl\xc4\x9e\x0ed\xf4\xa3\x8f!\x07\x81\x8c\xc8\x12I\xdc\x1e\x142d\"\x91\x11q\xc7\x034\xbc\x8fh]E\x11\xc9\x90\x8fJ\x86\xf2\xc8d\xc8C'C\x1eB\x19_\xa2h#\x8b\xe1\x96\xa18v\x19J\xe2\x97! \xc3\x0c%q\xcc\x10\xc02C&\x9e\x19[\xe3\x08\xc2\x19\xa4\xaa\x89\xa2\x9c!\x1b\xe9\x8c\x08t\xb1\xcf\xb0\x1e\xff\x0c\xbe\x94\xe8\xc4\x93\x00\x92\x16\x9d\xb2\xff\xaf\xc4Dcjo\n\xf1P+H\x1fkG\x1e>\xda\x12\xc6\xd1\xd2\x08F\x1a\xca\xe0\xa4\xa14V\x1a\x10\xbc4\xe4c\xa6-i\xd4APC&\x8a\x1ab\xe0b\xf0\xa3\xa9!\x05Q\x0d8\xf8s\x11\xb2\xda/\xc3A\xd6e\xa1\xaca\xc1`\xc4\xd0\xd6\x10\xedw\x14u\x0d\xcb\x90\xd7\x80\x8dG.\x02\x1bb(l\x08\"\xb1!\x82\xc6\x86\xd0(\xa5\xa2\xb2!\x01\x99\x0d\x08:\x1b\xf2\x10\xda\x90\x86\xd2\x86UHm\xf0\x0eL\x14\xb1\x0d\xe5P\xdb\xe0o\x853\xd3\x8a\"\xb8!\x13\xc5m\x89r1\xddP\x1a\xd7\x0d\x85\xb1\xdd\x10\xc2w\x03\x82\xf1\x06\x04\xe7\x0d\xc5\xb0\xdeP\x12\xef\xfd\xff\xb1w5\xbb\x91\xdb0\xf8U\x88\xb9\xec\xa5\xcd\xa1}\x82\x06\x05z]4\x8b^\x03\xcd\xd83Q\x11[\x03\xd9N\xbaE\x1f\xbe0%\xcb\xfa\xb3L\xc9N\xd0\x02\xcei\xb3\xb1D\x89\x94>~\x16I\x0bv\xaf\xf9\x06r\xdd7Pj\xbf\x81^\xff\x0d\xc4\x1ap\x88\xa2s\xb4Z\x182*\x86\xd3\xf5\xe0@\xaf \x07Z]8\xc4\xa6\xb1g}8l\xad\x11\xf7\xfa\n*\xc6a\xd7\xaaq#b\x97\xcaq\xd8\xbc\x1eV+\xc8\x81PE\x0e\xa6\x92\x1c\xec\xe0\xe2\x1c\x85%T\x93\xaf\x84\x8e\x9d4_RV\xe5\xdcN\xf7G\x0b\x1aw\x8f\xa5\x95r\xba\xbd\x1f\xd9%%Y\xc6\xc3\xcb\xa6OuL2]cn\xd4\xa7\xc3\x98&\x1f\xfb\xc8\xe38\xf28\xf6\xcd\xe3\xf8'\xba\x19\xbd=\x92\x9f\xc7\xa1;X\xd9\x92\xbf\xb3\xf7m%\xf6%e^\xd6\xe4\x7fe=s\x89\x85d\xef\n\xca\x82\xcf\xb2\xbb\x8aZ\x1a9]S~\x0f+\xaazj\x98\xec\xffc\xca\xfas\xe4J\x98=\xa0n\xa9\xae\xab\xe9\x92\xd8\x1a\xbaq\xbcn\xe43\xaa\xc8\xe5y\xd1U\x19\xf6\x11*\xf3\"Z\xcc>\x18P\xa5_\xad[\x80 \x9a\x0b.\xb2Um\xfc\x8bj\x8d\xf6\xac\xffw\xd0\xf9k\xf2~\xe1\xc9\xbf\xcdC\xb5\xee\x1a\x0e\xe7\xb0\xe7-\xc8\x19\xd8\xbf\xd3\xa5\xbe{\xe9\xc5\xebi\xef\x8bx#*\xff\x83\xbd\xf2\x8a\xf5B\xfe2\xf4/\xd9\x9agC\x1f\xdc\xfaG\xd2\xbb\xca/\x16\xf2\x99~/\x9a\xce)\xe2\xa2}\xd6\x11\x98]\xad\xe6(\xc2\x18o\x9c\xa0\x90\xfc\xef\x89m\\\x85J\x82x\x9b\x9e\x8eX\xcd\x85\x84\xa8\x82g+\xa2\x1f\\\x06\x03wT\xf9\x16\xcd\xdfL\xe3\x8c\xcbHaf\xe5\xcd\x92\xf1\x13L%\xbd\x00RK`y\x11\xec\xb9\x0c\x0eJ{P\xda\xdd(-\x15Sh\xae\xc1n\xee\xa2\xca\xba\xa3p\x1e'\x03\xc9\xf2.\x8f\x98myg\x17\x92\x93\x0d\xfbxT\x00\xde\xa7\x8f\xf74\xdf\xefR\xbce\xc0\xa7z>}\xe1\xcf]\x8a\xbf\xd2\x9f)\xc3\x10\xc8\xdaU\x1e\xde\x94\xb1\x0d\xf0\nX\xd7\x89\x8bJL\xc6\xd3I\xc9 ^\xf2\xa2\xe6, t\xba\xe1\xc7r\xba\xb8\xe5\x13F\x8aX?\xc5\xfc\xa2+ \xd1`\xc3*(]\x07q\xf6\x97\xb1{\x0e\xd6\xf6\xffgm\x90L\x1aW\"-l\x10N\x8c\x87\xb7p\x1ba\xc0\xc0\x85\x0e\xb3t\xf0\xfeR\xcb\x1a\xdc\xc8\xefEH\xf5 \x06\x86\xa6W\xc9)2\xf3\xc2:\x95\xe4eO\xd3\x99\xdb\xf4\xe4\x93h\xe6AE\xc33\xb2\xbe\xab\xc2\x90G&\x8df\x97\xc2\x85\xce\x1cqy\xf8\xe1B\xe7+\xben\xfc\xc4G\xb9\x0c\x00E\x1e\xab\xfbJ\xe0(\xfa\xd2|\x14E\xa7\xfb\xc1\x18\x1a0%\xbb\x97u\x8c\xa3\xb1&\xf5\xf3\xb9x\x1a\xb2\xa9\xcb\x01\xb3\xf9\xe1\x8ct\xf5V\xf7H\xc5\x86\xae\x96^\xd6\x8ccO\xde\xf6\xe3\x12\x8bM3'H\x00\x81\xc1u\xc7\xb3l\xa4g:]\xdf\xd8\xa1\xb3\xebD\xc66\x0b\xaf\x99\x08\x1c\xf3\x16Q\x8dS\xae\xc5A\x1a2\x98\x91\xf0+\x9f\x16a'\x1fL\x8b\xcaYJ1\xdc\xc5\x00\x8f.v\x13\xe8\xc5a\x8f.\xbc\x00\xfab\xe0G\x17\x98\x0b\x80\x8b\x10H\x17\xb9\x07\x0c.\x01a\n\nS`\xb8\x06\x87\xbb\x02b\x19$.\x81b\n\x16\xd3\xc0\xb8;4\x96\x80\xe3q\xeer\x9c\xbb\xe0\xcfq\xee\x92q\xee\x12\xf1\xfad2\x91zM\xfd6\xbf\xd2\x10\xf8C^\xf4\xa6\xc8\x9f\xbb\x9e|]H\xb1\xf7\xf6\xfd\xf6\xba\xa8L_\xedz\xe9\xf5\xees9\x05\x00\xf8\x0c\x1b\x00\x14\x00 \x00\x00\x00\x00\x00\x00\x00\x00\x00\xa4\x81\xef\x0c\x00\x00swagger-ui-bundle.jsUT\x05\x00\x01\x80Cm8PK\x01\x02\x14\x03\x14\x00\x08\x00\x08\x00\x00\x00!(v\xf2\x8aA\x86\xba\x01\x00\xc5\x87\x08\x00\x1f\x00 \x00\x00\x00\x00\x00\x00\x00\x00\x00\xa4\x81xF\x05\x00swagger-ui-standalone-preset.jsUT\x05\x00\x01\x80Cm8PK\x01\x02\x14\x03\x14\x00\x08\x00\x08\x00\x00\x00!(_;\x94/\xe8Y\x00\x00\xa8X\x02\x00\x0e\x00 \x00\x00\x00\x00\x00\x00\x00\x00\x00\xa4\x81T\x01\x07\x00swagger-ui.cssUT\x05\x00\x01\x80Cm8PK\x01\x02\x14\x03\x14\x00\x08\x00\x08\x00\x00\x00!(=\xb1\x8a\x88c:\x02\x00F\x10\x1e\x00\x0c\x00 \x00\x00\x00\x00\x00\x00\x00\x00\x00\xa4\x81\x81[\x07\x00swagger.yamlUT\x05\x00\x01\x80Cm8PK\x05\x06\x00\x00\x00\x00\x08\x00\x08\x00E\x02\x00\x00'\x96 \x00\x00\x00" + data := "PK\x03\x04\x14\x00\x08\x00\x08\x00\x00\x00!(\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x11\x00 \x00favicon-16x16.pngUT\x05\x00\x01\x80Cm8\x00\xbd\x01B\xfe\x89PNG\x0d\n\x1a\n\x00\x00\x00\x0dIHDR\x00\x00\x00\x10\x00\x00\x00\x10\x08\x06\x00\x00\x00\x1f\xf3\xffa\x00\x00\x01\x84IDATx\x01\x95S\x03Luq\x1c\xfd\x8c\xf1\xc3\xec0\xa7)\xcda\xb6k6\xb2\x9b\xf9\xb2k\xc85/\xdb\x8dqx\xc6\x94m\xcc{\xef\x7fO\xff\xf3l\xdc\xed\xf2\xe0\xfe\xf8\xc9\xffP\x14\x11/\x14[\xa3P\xc4\xa1\xbc?\xf1t>7\x12s\x13\x03\x85\xca7IR a\xb5j\x8f\xa71\xbe]\x88\xf6\xb9L\xf0\x1c\x93\xcf\xda\xe3)\x10\x93f\x8d\xe4\x06\x13\xcf\xde<\x9b\xd14\x95\x8a\x92\x81OA\xcfF\x89\xdd<\x9b M\xe6}L\xe4\x07\x15\xc5\xf5\xe3\xffI\x0c{\xd6\x8d\xffs\x994\xbasfh\xae?\xafk\x1aprw\x10 <\xb9\xdb\xc7\x86\xa6\xd1\x19I\n\xa8\xb1\xd7\x84y3g\x171T$\xb5c\x7fq\xfbbq\xbfk\x8e'\x1dQ\xb0\xc2,\x92\x0bx|;F\xe5\xf0\xef\x00\x83\xf2\xa1\x1fx|?q\xbd\xcb\xc2\x16\x80ZF\xf0\xc4J\xf3\xe3\xe4n1\xcc\x17k`:}\xcby\xe8\x98\xcbB\xc7|6z\x97r\xd14\x9d\x06\xd3\xf9\x8a\xe4\x94\x90\x8b\xb6\xd9\x0cP\xebc@\xd0|\xbe*\xc94\xc8\xa7\x98'\xcdh\x00\xe3\xd92\xa6vK}\x0cB\xa4\xf0+D\n\xc7\x81)\xb0\x10\x9a\xe3\xa9\xd8\x8bx\xe4(\xa2\xbb\x8dl\x0d\x01\xb6\x8a-\xf378\xbe\xdd\xc7\xa6\xb6\xc9\xd9\xc6d\xd8\\m\xf4\x0c\x92 uQ\x0e\xd2\xf5\xb3\xd1\xf1w\xdfQ\x16\xb34a$\xa1\xc4\xc4(V\xbcF\xd9\xdf\xa4\x91\xe9\xb0&,\x12+\xcd\x93\xcf\x1c\x1cb\xdc\xca\x00qt\xeb\xcc-\x14\x89\xfe\xfc\x0fm2j\x88\xec\xccs\x18\x00\x00\x00\x00IEND\xaeB`\x82\x01\x00\x00\xff\xffPK\x07\x08\xd4`4t\xc7\x01\x00\x00\xbd\x01\x00\x00PK\x03\x04\x14\x00\x08\x00\x08\x00\x00\x00!(\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x11\x00 \x00favicon-32x32.pngUT\x05\x00\x01\x80Cm8\x00u\x04\x8a\xfb\x89PNG\x0d\n\x1a\n\x00\x00\x00\x0dIHDR\x00\x00\x00 \x00\x00\x00 \x08\x06\x00\x00\x00szz\xf4\x00\x00\x04|ID\xc4\xcf\xd0@\x04&%\xad\x1e\x16\x0f\xf7\x8d\x97AR\xfa\xca\xe7l\x87\x05\xf8\xd2\xfb\x0c\x84\x1d\x0dLVY\xdc/ju\x13\x1a\x88\xd2\xa0\xaaa\x82|nzp_\xf4\x03\xc8 \xd4;^\x8a9}\xeeu\x9a\x91 `\x04\x14s\xec\xe1\x0c\xc6]\xa3\x05``\xd1w\x12*~ \x00\xf3\xae\xd3\xa0\x9cb\x82\xa2bx(\xb3n\x1fqx\xd2\xf2\xda4\x1d\x8a}\x1ck\xd4>\x9cI+\xeb\xb3\xf4k\xc8u`L\x93\xf3]4\xb5\xd0\xc3\xe33\xd9\xee\xd7\xf2\xd9\x19\xea\x18\xc9\xc1Y:\x18\xfb(-\xadN\x82\x06e\xd5\x1f0\xa2\x1dV\xf8\xbe0\xc1\x985\x01\xf8\xd2~\\\xa6\xa5\xb5)&\xf6\x98V\x80l\xe4\x03\xf8\x03\x04\x00s\x9a^\xec\x85\x00\xf4+\x0b\x00\xe1:G\xf2p\x96\x0e\xc4,\xe46\x1e5\xbbP\xdd\x15J\x80}\xce\xa4\xe2\xc8{m\xa4\xe2\xc3\xc2\x01\x07\xc0\xdb\xa4\x18-\xa1\x931\xba\x10S\xfa%\xb6P`\x10\x19v\x99#|Gg\x9b \x10W\xf6\x8dI1\xba\x92\xd66\x17E\x12\xfa\xd9\xa8\xf3UTe\n\x1b\x95\x9d\x81f\xe5\x18\xa5umc\x81\x86\xa6\xeb\xec \x804\xcbg\x17\xa19\xfa\xc6\xf7<\xa3\xbd\xf2\x0e\x7f\x02\x80\x97Y\xc7\xac\x184$h\xa3v\xba! \xcc{\xcd\xb4!\xb1\xd8\x92%h\xe3\x93\xdc\xd3_\xda1\xe6\xaei\xcf\x83\xa6p\xbc$\xf0\xb2\xda\x94\xa2q\x14B@\x13\xdb\xff\xf3\xd7\x0d\xfaA\xb9\xc5n{\x8e\xd6Y\x08\x01u\xc1'~\x16\x8e\xe9\x04\xa2\xfbA+\xc74\x0c\x98\xab\xd7:\xfc0\xd1v\xaf$\xa2#\xb7\xf1\x08\xfdm!OXh8\x10j|g\xd1\xe0a\xb2\x99\x04\x9a[y\x9a\xbdk\xf24C$\xa0\x9e#\x9f\xa3\xa8\x001\xc6\x1a\"\xc0\xe4i\xa6\xcc0\xf3\xf7\xb7\xf5XE\xb8\xe0\xa1\xc9\xc2\x0c\x90\x83\x80$\x838\xdf\xd6\xe3\xd4\x82FNG\x0f\x876\x8a\xbf1\xa8d(\xa7@\x8cQX\x90\xdb\x19\x9f\xc5YG\xe9\x9e\x00\xa5y3]\x9aJ\xe1\"\x00\x00\x00\x00IEND\xaeB`\x82\x01\x00\x00\xff\xffPK\x07\x086B\xc8\xd7\x7f\x04\x00\x00u\x04\x00\x00PK\x03\x04\x14\x00\x08\x00\x08\x00\x00\x00!(\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\n\x00 \x00index.htmlUT\x05\x00\x01\x80Cm8\x9cT]k\xdc:\x10}\xdf_1Q\x1e\x92\\\"\xfb&\x81p\xf1\xb5\xfd\x90\xa6\xa5\x81\x94\x06\x92}(\xa5\x14\xd9\x1a{\xa7\x91\xa5E\x92\xf7#!\xff\xbdX\xf6\xae\xb7\xdd\x90BYX\x8f\xe7\x9c9\x1a\x1d\x8d\x9c\x1ep\x0e\x1f\x1f>\xddBe,8/<\x95 \xc9yKE\xeb\xc9h(Z-\x15B\xd1\x92\x92\xc0y>I\x0f\xae?\xbf{\xf8r\xf7\x1ef\xbeQ\xf9$\xed\x1e\xa0\x84\xae3\x86\x9a\xe5\x13\x80t\x86Bv\x01@\xda\xa0\x17P\xce\x84u\xe836}\xf8\xc0\xffc\x03\xe4\xc9+\xcc\xef\x97\xa2\xae\xd1\xc2\xf4&\x8d\xfbL\x8f*\xd2\x8f`Qe\xcc\xf9\xb5B7C\xf4\x0c\xfcz\x8e\x19\xf3\xb8\xf2q\xe9\x1c\x83\x99\xc5*c\xae\xd7\xe0-E!\xbb'A\xa5\xd1\x9bbjD\x8d\xf1\\\xd7\x9b\xeaJ,:\x9c_\x9c\xaf.\xce\xa3\x008zB\x97\xb1\x90a\x10\xff\x9d\xde\xd9\xe5\xea\xec\xf2\x17\xbd\x90\x19\xf5\xc2\xc6\xfa\x18\x82\x9bC\xf8<<\x01\n\xb3\xe2\x8e\x9eH\xd7 \x14\xc6J\xb4\xbc0\xab\xff\xb7\xb8Y\xa0\xad\x94Y&\xc0\x1b\xf3\xc4]i\x8dR\x85\xb0\x8e/\xd0z*\x85\xda\xe7\xf2u\x02=q\x83\xbdL\x86\xe0\x9f\xd3M\x90\x14X\x19\x8b\xe3\xbb\xa8<\xda7\xfb#=CK~O\xb40r\xbdW\xd8\x08[\x93N\xfe\x1d\xdb+D\xf9X[\xd3j\x99\xc0a%\xba\xdf(\xd5\xfd\xa7\xf1\xd6\xaf4\xee'\xac\x0b;\xf9\xc1OI\x0b \xb9;\x0e,OcI\x8b|2\x18^Z\x9a{p\xb6\xdc%\xf1~\xc6\xa3\x1f\x8e\xe5\xdd*\x81\x94\xbfY\xe1\xbc\xd0R(\xa3\x91\xcf-:\xf4o\x14\xf7/K\xd2\xd2,#\xa3\x95\x11\x122\xa8Z]v\x17\xec\xf8\x04\x9e7N\xc51\\\x85{&\xc0\xad\x9d\xc7f\xc8\x97F;\x0f-A\x06\xc3m\x99\xde\\\x85\x9e\x8fGG[\xab\x12`Q\xeb\x8c\xd8v\xfb_}K7\xd3F\xfe]\xb1\xa1\x82h%q{\x8b\x9b6\x88/\xc4i }\xc07u~}\xe5\xad\xfd\xc9\x98\xe7q\xd8_}o\xf1\x92%\x9dx\x15\x9f\xd3yO\xbdX]\x1aA\xc9>t\xd6o\x93\xd3\x92\xf2\x04l\xc5\x8d\x92jz\xc1jN\xd6\xf2\xa9\x87\xfa\xb5]\x05\xcc\xf9\x1acB\xa9,\x9f\xd0\x08\x05\xb7\x962\xec\xdb\xb6\xe2\x16b\xc6\xd5\x942H\x05KfI\x06\x7f\x9c\x98\xa8\xc0\xd5\x9c\xa2\x0c\x13\xa3\xe7U\x8e\xb55;'Nk\xe6\xd0\x9d;\xd4%^\x14\xbd\xd5\xf7\x92QN\x8e.\x1c`\x079m\xe3\x9e\x8a\xfe\xed\xa2\xad\xe0y>\xe6\xe23\xdc\xf8u\xa7=\xa3\xf6\xa1\x98\xb4\x17g\xa9\xf4\x1dA\xa8Z\xe4\xf6\x88_\xfc)\xf8\xd5N\xcf,\xea\xb4\xabS\xf2\xd2\xe0v\x10\x90\x82\xbd\xb3\xe1\xc1g\xc8>\x120\x0c{\x1d\xbd\x1c\xd1\x7fd\xb4\xbf\x82|\xf7\x9f\xd0\xa7\x1e\x82\xc5`H\xc0\x94F3p0$H.\x0f]v3\xaa\x9b\x1c\x83EW}\xba4\x12O`_\xb5!H5\xd1 \x9a\x0c\xaa\xcd\x04\x8cE\xe7M:\xe1\x08\xfe\xefQ\xab\x02\xfe\xb7A\xeb\xb6k\xbb\x05{\xef\x8e\xde\x84\xcb\x9c\xb2\x8f\x04\xd7U\xf9\x9aQ:\xbe\xf51\xf1\x1a\xaaW\x97uR\xdd\xe7\xf59\x974\xb7\xfc5s\xd0\xc4P\xdf\xdd\"\xd7\x96\xc2\xdab7x\xb8;\xfc\x01\xfa'\x00\x00\xff\xffPK\x07\x08]\x12r 9\x03\x00\x00T \x00\x00PK\x03\x04\x14\x00\x08\x00\x08\x00\x00\x00!(\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x14\x00 \x00swagger-ui-bundle.jsUT\x05\x00\x01\x80Cm8\xec\xfdyw\xdb6\xf68\x8c\xff\xffy\x15\xd7\xfa\xf6\x9b!kZ\xb1\x9d\xa5\xad\x13\xc5\x93\xc5m\xb3g\xe2\xa4\xcb\xa8\x1a\x1fZ\x82,6\x14\xa8\x90\x90m\xb5\xf2\xef\xb5\xff\x0e.\x00\x12$\x01\x10r\xdc\x99\xf9<\xcf\xc3s\xdaX\\\xb0\\\\\\\xdc\xfdn\xc1tI\xc7,\xc9h@\"`!\xfc\xf9?\x00\x00\xbd\xec\xf4w2f=\x18\x0c\x80\xad\x16$\x9b\x02\xb9\\d9+\xe0\xd6-\xd3\xd3y6Y\xa6\x04\x0e\xe5\x1f}\xf5\xf6\x00X\x10\xc2\x01\xf4T7\xfaG\x132M(\xe1-\x8a\xbf\xfa\xf1|\x02\x87\xf2G0\x1c\xe1\x80\x0e\\\x839T\x7f\xf5\x8f/\xe2\xb33\x92\x7f|\xfedI'));&\xe6'\xffs\x15\xb0YRD\xd5\xf4\xd5\xd4s\xc2\x969\xd5\xc0\xa2\x1e\xf0\xeb<\xce\x81\xc1\x00\xfe\xbcz\xf0?\xe5M\xf5*\xd0 \xd7_\xe6W2\x85\x80\x0d\xf3Q\xa8\xda\xe5?\x14t\x1e\xd4^\xe5mg|t\xc3|\xc4\xbb\xa8=\xc4\xb6\x0e \x8fZw\xd3\x03\xd8\xdak\xdf\x96]\x1c\xc0\x9fW\xb5gW\xf5N\xe5\xa8\x08\x1f\xd58N\xd3 S\x83\x8b \x8b@\xfbEC\xfe3\x85\x01l\xedj\x0f\xca\xd6\xaand\x9b\xb4?\x87\x01\x90\x08h\x7f\xcc\xa7\xc5\xff\x98\xc0\xa0\x8ep\x11\xb4@F\xfb\x99\xc4\xc5\xf5\x1a\xde\xe2\xd2\xf7\x05J\xbc\xcb\xb3\x05\xc9\xd9J~\xd9\x86\xd08\xa3\xd3\xe4l\x99\xc7\xa7)\xb1\x80\x85.\xe7D=\xdfm??#\xec\x00\xf2:\xc4\xc2j\x8e|\x0e\xb46\x87\xe6\xe8\x15\x86 Z\x93\xfe\xc9 )^\xab\xbd\xd1\xc25\xfdR+\xc1\xe7\x1a/SV\x1f\x03\x1c\xf8}\xed\xb1\xd6\xb4? X\x04\xbd\xb8\xc7\x81\x1c\x01\xabO/k.Q\xb3;\xd9\x8c\\\x99E\x9e\xb1\x8c\xef\xca\xfe,.\xde^P\xb5F\x02\x9b\xf0\xfbz\xfb\x0b\x18@\xef\xf6$)X/\x02\x1a\xd0>'\x12w\xef\xde\x13\xaf]\x05\xc3\x06~P\xbd\xff\xde\xb2 P\xb0<\x19\xb3^59\x9d\xdc\xd0\xe0\x1b\xd5T\xd4D\xb5ZS\xf5\x8f\xbe\xbdw'\x0c\xbc\xbe3\x0f\x81\xe9+-\xb6\x08S+\xd9\x05PN#\xb6\x02\x02 -XL\xc7\x9c\xbe\xb10\x046\xcb\xb3\x0b\xa0\xe4\x02>\xac\x16\xe4(\xcf\xb3<\xe8=\x8d)\xcd\x18p\xe0B\x0c\xe34.\n\x88\x0b\x88\xcb\x1ezacG\xde\xcct\xaaG\x1c\xc1\xf3\x08)\x15\x0d\xf6\xef\xef\x87\xf5M\x94\xc0\x00\x82\x1c\x06\x90\x85|\x07\xe4\xf5\x1d\x90\xc3\x81\x01y%\x9cZ\x1bO\x1f\x8f\x01\x96M8\x96t\x98\x18\xc1\x8c\xafd9\x04|\x06|\x13\xef>\x00\n\x0f\x81\xf5SB\xcf\xd8\xec\x01\xd0\xedm\xd3G\xa0f\x8d\xc4\x99\x8e\x1e\x18\xdf\xc8\xfb\x15m\x81A\xfd\xe7z\xcd\x89\x11\xe4}\x9d@I4\xe9\x9d\xc7\xe9\x92\xf4 \xa1\x90s\x88\x05y\xff\"OX\xf9F\x18A\xb0\x1bA\xa2 \x10\xf2\xc9\xe5\xfdOd\xc5igk(\x0djo\xda\xb9%\x009.\x18\x08\xb0\xf6*E*\x16h\xdb\\\x1c\x04\xb9\xbc\xcf\xbf\xd6)H\xbd\xcf+\xbf\x1d\xa5\xef\xc4\xfaHJ\xc4\xa0\xc17\xf7\xef70\xadB,N\xca\xff\x9dX\x7f\xf7\xde\x7f\x0e\xe9\xad\x04\x84\xe8\x14\xe3=\x99\x92\x9c\xd0\xb1\"\x1b\x9c\xd7\x81Y\\\xd0\xbf18%\x84BB\x13\x96\xc4iR\x90 \xec@\xb1\\\x90<\x08kop\x12C&\xbd\xd0x\x86l1\x8e\xd3%c\xb65\x18@p\x9e%\x13\xd8\x85\x01\xe7\xd2\xe0\x10zK*N\xedI\x0f\x0e\x9a(\xcc\xe9\x1bg$+\xaep\xab\xe4\xed\xf8\xc7\x04\x0e\xf4s\xe9\xaf[R\x18@\x1cp\xec\xfa6l\xaci&\x1f\xdd\xb9\xfb]\xf3Q\"\x1f\xdd\xbd\x17\x86&>0n\xb3\x05\xea|6p\x05\xc4\x8d\x1e\xc4\xb6\xb9\xae\x87'\x16\x90\xdf\xba\x05t\x99\xa6\xb8\x92\xccr\xf6\x1cs,\xe1\x8ceN\x8a\x82\xcfs\xbe,\x18\x90\x84\xcdH\x0e\xa7D4\x90\xe5\xdaa\x14\x01?\xacz\xb0\xbd1v4\xd0\x8eT\x04\x88o5d@\xab\xd7\xf9\xe8k$\xca\xc8\x19\x16,_\x8eY\x96\x9b\xa0\x0d\x88\x0f\xe9\x92\x1c\x00i3\x85\xd0d\x1c\x0d\x8c%\xbf\x14\xdd6\xb3\x96\xd0fPw[/5\xc87'\xae\xf2PPk|\x88\xd3\xcfk\xc7\x01\x13\x92\xce\xc9 \xc2\xe0\xe4\x84\x1fT\x1b\xf2\x01\xb8\x1b*\xa0\xe7\xae\x83\xd6\xbc\xd5T+|\x85\x1e\xe7y\xbc\xd2x\xc3\"M\xc6D\xdb*\xa0o\x17f=\xae\xc5\xdc\xeb\x8b/\xf9\xceqNbV;\x99\xc20\xd2\xf1\xa4\xaf-9\xe7\xc7\x1b\xdb\xc8<\x14\x03C\x0f\xd5\xee\xc5}-6\xec\x8b\x80\x84^-\xe6\xce\x16\x97U\x8b\xbf\xfa\xb6\x989[,\xaa\x16_\xfa\xb6\x98t\xcf\xfa\xd6-\xd8J\xab\xa6\x7f\xf0m\xda@\n\xb5\xa6\xb7\x82-\xc1\x1c\x91\xe1t\xe4\xd7\xe0\xd2\xb7\xc1\x85g\x83\x85o\x83\x13\xcf\x06\xd3\xee\x15_\xaf\xb1[\xaf\xe6\xc6\xbe\xe3\x9b\xb5\xc6\xa7\xffbA.X7\x16d\xea\x8fD\xfcA\xfbI\xf1\x9c\x95\x9ck,\xee\xbc$+\xc2\xc5\xf5\xa5|\x81N\xc8%\xde(\xc4\x8d\xc7E\x91\x8d\x93\x98%\xe7\xfc\xa3T\xdc|\x9bOH\x8eo\x8d\xf9\x0d\xd5\x06\xef\xba_\xb5\xc0\x07\xd0?&\xfc\xbcJ\xda\xf4c\xca\x05\xc4\xbf\xff\xfd\xe4\xe4\xf9\xeb\xd7\x1f?<~\xf2\xea\xe8\xe4\xf9\x87\xa3\xf7\xf8\xc7\xc9\xdf\xff\xdekS\xd6E\xfb\x8b\x97G\xbf\x1e=\xb3\xbc>1t\xf0\xe6\xd9\xd1/\xd6\x0ff\xed\x0f\xde\xbe\x7fv\xf4\xde\xfa\xc19\x0c\xe0^\xfb\xf6\x1c\x06\xb0\x07\x0f\x1f\xc2\xb9A\xf1\x00\x03\x98\xc3\x0e\x18\x8e\x96\x15*\x9c\xda\xf7O\x8dZ\"\xa8\x8e\xb2\xad\xbd\xd6SC3'\xd7i\xc6F\xcb/\x9c\xd8J\xfa\xd8$g\xc4\xf6\"O\x92|dn\x91\xc8\xa3\xa1lp\xd7o;]\xf2\xd3\xcc\xf6\xf0\xd8q\x12q\xbee\xbd\x86\xdd\xb6\xf4W\x13*_\xc7l\xd6\x9f\xc7\x97\xfc\x90&R\xb2\x84\x1dT\xb4\xf0c\x88\xb3Tx8\x06\xa8O\x13Rh\x06\x0f\x81>\x80\x8c\x8b\x9f\xf90\x1b\xf1\xe3j\x98\xc160\x83\xac)A\x99{\xcd\xf6\xa9s94\x9e\x8c\xf4\x8b\xe4\x0f\x05S\xfcs\x80\x0cE\xc2\xe9\x02#\xc1cq\xba\xf2'^\x1d\x7f\xb2B\x12\x99P\xba\x9c\x9f\x92\xbc\xc6\x82\xba$o\x8a\xd0\x7f\xf4\xe8\x91 \xfc\xa0\x1a\xe5|&\x15\x1c,_\xa9\xbb\xfb\xdf\xdd\xfd\xee\xfe7\xfb\xdf\xdd\xc3\x19\xd2R\x05\xfb&~cn\x85/2m\xe3\xba\x0d|\x0c\x1e\xc2.\x1c\n o\x03\xab\xc9,\xe0\x00\xcec\x97\n\xaf\xc1\x14\xda\xdaxkb\xe2\x1aM\x05rm94\xe4Zs\xe8\x08\xa1\x1e\x1e\x0e`\x87\xe2\xc9^g\xce\x0d/3x\xc4\x01\xe85\xb0w\xd6\x95\x97\xa3z-G\xee\xb9a?\xf8\xb6\xc7\xfc\xda{\xed\x018}c\xc0!P\xce]\xcb\xc5\xd6\xf77\x83m \x9c\xf5n\x087\x9cC\x12\xef%\xa8di\x9d\xf4\xfa/\x8e\xdf\xcf9\x1dhS\xe6\xdf\xf9y\xd1\xbe\xfd\x06\x06\xb0\xdf\xbe\xfd\x9e\x9fR\x95tW\x19K\x8eW\xf3\xd3,\xe5\xeb(\xfe\xea\x8bM\x9d\x19\x8c \xcf\xc4I\xa7^0\x1cm\xaf`\x00\xef9\x8e<\xb3\x1d\x01\x1f\xcd4\x87\xcd\x92\xa2O\xc9%\xf3f\xc6?\xab\x95\xb2\xe8\xa8\x94\xc1\xa4Z(\xbe\x05\xf7j\xcb6\xe4\xdf;\xa8(\x1cB^\x9e!\x19\x1c \x91v\x9e\x86\x99Y\xb2\x9bd\xd4v\xe2z\xd2\xea\xef]T\xc19$\x81~\xcequJ\x9a\x96A\xfd\xe1\xe6>\xb7~\xf4ec\x9f\xb8\x19\x83\x866H\xb3\xf4!\xcexu\xf1\x93\xb9\x0be\x91\xe1C\xb5\"\x82\xd4!\x08\xa3\x85\xdf\x8c~tw'\x0e\xd3\xf7Hk\x87\xefG|\xcb\x90\xe1\xb3\x91a\x08\x0d\xb5\xcc@?\x13\xd5\xf0\xbcF\xf4\xb3\x07\x8c\xd5\xc9\xabCXp)^]\xbcpv\x81\x1a\xa0\xe6\x91\xa3\xb6cB\xd0 \xab\x84\xe8>\xcb\x8e\xc9g\xbc\xa5Z7\xb7\x0d\x1aP\x0b\"\xc5'\x93M\x18\x95X\xe4\x02\x181\xae4(M\xa9M\xbfut\xb9 cF&\x82A\x83,\x87DIE\xa27\xc8\xa6b\xcb\x15\x11\x7f\xfa \xa5\x1b\xf1\xe8\x00\xb5\\\xb6n\x8d\xab\xc8\xaf+_d\xfb\xf5\xcb\xe0\xdeg\x19\xcab\n\xe2r\x11\x96\xed\xb5 \xfdi\x9e\xcd\x8f(\xcbW\xe5\xcb\xc4w\x94/\xbfl\x94\x86\x81\x11} |\x9cR\x8aT\xb7\x96\xdec\xfb\xc19\xb6\xe0\xcb\x07\xa7F\x13\"4\x19\xdeo\x8cL\xff\xf5QSU\xb1\xec\x98\xe5 =s)\xdd\xb4\xc1\xf6\x86\xcf\xe5\x01=\xea\xd5{\x88\xe0c\xff\xe5\xd1\xaf\xc70\x80\xe7\xfc\xef\x9f\x1e\xbf\xfax\xc4\x7f\xfd\xce\x7f\x1d\xbd\xf9\xf0\xfe9\xfe|\x13\xd5\xfaOh\xc1Q\x1f\x06\xcdQe\xcb|Le\xf2\xd9\xb3M\xd3\xd8^\\\x7fQ\x11|''%\x00{|$\x7f\xf6\"\xe8]\xf5\x9cc\x1e\xc7\xe3\x19yO\x8a\x0e\xeb\xa8\xd6\xd5\x96\xe8\x0b?\xc4sOt-e\xbd\x8f\x14\x1fL\xf0\xfc\xd2\xdf\x1c\x88\x17+\xac\xef\xb3L\xc8\xb2a$\x1eI\xc1Q\xfbH\x9e-\xf2\x05\xd74\xca\xfe\xbb\xac\x18\xdaDR\"\xbdx\x04\xa3\xd8\xd2\x01\x98{\xc8\xf2\x0d\xba\x18wv\xc1\x82_#x\x11F\xf0km\xf1\x15\xbd\xf5\\\x133\xa6\xbf\x14-\xbf\xf4\xc7\xf4\x97\x0eL\x7fY\x1b`EI=\x9b6\x0d\xf1\xe5\x0d#\xfc\x90#\xfc\xa8\x8d\xf0/o\x18S\xf6\xbcz\xf8\"Liw\xc1\x82\x1f\xc4z\xfe\xe0\xbf\x9e?8\xd6\xf3\x87\x06\xe5b_\xb6\x96/\xfaI!Z\xc8\x08\xff\xa5\xb4\xb7\x1c\xbd\xa5\xba\x96\x8f_S\xe4\xbelko\xbf\x8a\xe0\x9f\x11\xfc\x12\xc1?\xdaJ\xd3\xe3\xa3\x7f\xa0\xc2\xd4&9\x12\xe2\x10\x1dOb\xe4\xca\xd0\xa3L'6\x1b\xb1\xaf\xcc\xd2\x83\xe2/\xa5q\xe9\x13Y\x15F\x1eR\x8cDr\x83\xd5PN\xf8\x07\xc2\xc7\xadF\x077\x19\x1auN>\xa9\xf4\xf3\x96\xf9\xa3\x80\xe1\xaf\xa0\xcb\xbb\xbb\x93\x86\xb3\xa8q\xef\xa9<\x0c\x86#\xaf\x8e2KG\xea,\xaa\x0c\x18\xff\xf04\xb0 7fm\xf0+\xdeZ\xf0\x95\xd4\xb5\x12\x12\x0cG\xa1_\xbbq\x07r\x08\xa3fR\x883\x0fy@\xd9\x05 \xdb\\\xf3\x93\xea\x8d\xdc\xfc\xc6\x1f\xd5\x1b\xd4\xfc\x86Q\xca9\xac\x84\x9cR\xf5d\x16*\xbfL\xd2\x19~\x8a\xe0|\x04\xfc\xb8O6\x92x6\x92Y\x97\x1d@/\xcc\xc2\xdc\x97OO\x08r74\x8b\xc2\x8d\xe4?7\xb0\xc5\x80\x1e\x06|(W\xd7k\x08)\xf1T\x97\x11\xc9\x9a\x99\x81\x9a\xd9D\xf0\xd2\xca\x91\xf0\x03\xa2\xb2l\xecE\x10\x0b3F\x0c\x0f\x07\x90<\x80\xd8\xeeF\x07r\x1cK\xde\xc6\x90r\xd1\nv \xe6\xb2\x95\xc5\xad\x0e\xd4b\x0b\xbd\x1e\x0b\x96\xc3\xbdQ\x84\x8a\xbb\xe5pw\xc4\xbf\x8c\x80\x84\xa5\xa6$\x86mh+\xe1\xa0%~\xa9K}\xd6zhU\xfb\x936\xab\x8c\x9et~Df\xfc\x17/\x93q\x85\xac\x90\x15+\xe7\x02\x0c\xc7\xc6\x8f\x81\x93\xa5P\x97r\xfe\xf0_X\x05\xfc\xedmx\x04 \x1c:\x1a\x07?u\xa7\xba\xacjOu]\xc1\x01|F\x07F.\xcaKL\x12\xe8L\x86{\x8d\x93\xa8\xfc\xa8}\xdb\x03M\xb2\xfc\x1ax2\xb5;\xb1*\xca\xa4y\x94\x0b_L\x8eR\x11XQ\x83\xe3M\xfd\x0c\xa3\xd5\xbe\x91\xba\xcf\x0c\x9bx\x19\xd0\xb0?\x8f\x17\xd5\xba\xbb\xda\x05m\xd2\x08Q\x0c\x1d\xa06\x10:Ts\x13b\x1d\xd2\xaf\xff\x81!\xa9-\xd0^t\xb4\xeaD\xd0\xeb\x99|\xcd\xf8\xd5\xeb5=\xf7\xf0;N\xd3\x17\xde*\xab\x85\xfbT1\xf0#/9\x1b\xc1\xa1\xb4 \\:\x7f\x95\x14\"\nfB\xc4\xf3_\xeb\xcf_\xc7\x0b\xa1\xbb\xf2\x1a\xce\xc4=\x1ce=\xae\xf9]\x0d\x14O\xdd\xd4\xaa\xe9\xaf\xf9Acf\xdf\x11\x1cwHe\xbe$\xb0%\xf5\xef\x0c-\xcc%Fm\xd9\x18%\xc1\x82j/\xeem\xa0\xa6\x97N\x08o\xa7V#\x06So\xb8\xb6f \xb8y\xf9f\x10\x868\xa1\x00=\x0f\xf4\xbb\x9bN\x10\xec\x93\xf4\xa7f[f\xc7Q\xd2'\x9f\x97qZ\xa0J\xde\xf4\x02\xd3^\xd8Ro\x07\xcc\x93#?\xf7Z\xf2\xee\xe5\x8d\x03\x11M\xa4\xd9\xb5+\x87\x07\xed&+o\xca\xc7\xda\xcd\xe6\xe7''\xb3\xb8\x98\xb5\x1a\xa8n\x97\xaf\xd4\x1e\xac\xd7B\x7f\xcco.\xe5\xb0\nu\xa3\x907\xc6\xea\xc6\x18=\xa5;\x90\xb2\xe9\xc1!\x0d\xd1\xf8\xdb \x1b\xe5Z\x81\x9e}\xe6\xb6\xf9H\\\xac\x06J\x88})#\x04\x1d\xe6\x8f>9'\xf9*\xe8T\xa8\xa8K\xb1B9\xda\x00\x83P\xec\x82Nv\"\xe3@\x98\x91 CNQ8/\x06\x94\xc3\x15o\xeeb\\\xa1\xed(\x00\xf4\xdf\x97\xfdq.\xc2c\x8f\xa8q\xda\x16\xa8\xe5gc\xee\xbc\xf1\xaaZ@\x0b\xcd\xd1\xd5\xbe\x88m\xda\x0d\xdbB\x90\xb4 \x0exg\x0d\x0f\xf9\xe6\xa5xK\xc7\x12\x10\xa9\x05\x81\x01$f\x08\x1b\xa17\x15\xc10\xc6/\x16 \xb6\x8frE*\xd1\xc7\x14<\xa8_\x1c\x9e\x9c\x13\xdd\xc2\xd8\xb4\x00\x9d\xa43\xfe{\x86<\x01\xe9\x9f\x11\xf4\x8a\\\x85\xfc \xbf\xab\xddB\x1cQ\x185\x95\x1ek\x06\x8a \x885V\xf1q\xaa\x11\x13\xbe\xa8\x0b/\xba7w\xd3\xbd-T4\xea\xf1bsM\x02\xe2\x1c\xbbj\xc0\x8c\x8fB\x9f\xa3\xbc\x1e\x1a\xfa\xa4\x86/\xcb\x1e\xdc\x86\xdd\xd2\x9fE\xfa\xbd\x84\x91zC}\xe8:\xd8\xfeY\x0e\xed\x9ff\xc4\xf9\xa7\xb4\x19tl5\x1b\xb4\xce:\xa0U\x8b\x8c\x11*\x02O_\xa1\x15q9\x0b\x99\x97b\xd5X\n\xad\x0d\xf3j\x9c\x91@\xbaZE\xa0\xe2\xfb\nF\x16\x10\xc3\xfb\x98\x9e\x118]\xc1n/\x8cpo\xe19\xb4\x1b\xd5W \x0d5\xe8[z\x1bv\xc3\x08i\xba\xf6\x02\xc5e\x94K\x18\x9f\x16\xe8z\xc8\xe0\xa1\xe4\xd8\xf8\xdb;T\x99pN\n\x16\xe75\xdd&\xa1\x13M\xb5y\x82C\xc3\xc1\xeaX\xa3\xa3\x07\xfe=&I\x1a\x04\x0cv8\x01\xbe\x0d\x94\x8bV!\x97\xcd7\xc3\x9d_JX\xfeb\xc6\x9d_\xbe\x0cwN\xcd\xbaD\x81/\x9aJ\xe9\xf1i\xc1\xf2x\xcc\x9a\x96 K\xb3'\xc4\xe5fz\xe1|z$\x9f\xea\x0f53\xd6\xf0\x1f#\x15`\x1a\x10\x12\xc1K\x8e\x19z\xdc\xc3\x19\xe9\x0c\x04\x82\x86\x15\x86\x93G\x94\x0f4M\xfb\xf0\x932g\x84\xa3\xb6gc\xa3\xcf\x8dL25\x7fY\xadG\xe9![S-U\x1e\xb2\x03\xc8\x85\x8b\xac\x15W\xa4\x8a\x88\x04t\xc80\xecn\x07=\xba\xb2\x11\n\x7f\xbc\xa3jgf\x1c\x15\xadT;\xf3\x9a\xac\x9fu\xc84Q\xe3\x14Z\x937\xbe\x95\x9956\x9bikJ \xaa7\xbd\\M\xa8/\xf4\xc3CbD\xf9Z\xdf\xb3\xb8p&\x02\x80\xa6\xa5S4\xdd\x08\x93o\xa9\x02\x1a\xbd|\xe9\xc6\x12\x9d\x8a\x9dU\x99\xaa\"\xc9V\xeb;-\x11;-\xe1;-{\x00\x89;\x16:\xe6\xdf\xe3bf\xb0\x03 \x1c@b\xd1\xf35vf<\x8a n\xee\xc6\xc4\xa8\xb4\xb5\n\xa3\x89\x17\xc8\xae\xb3=%\xb8\xac\xfbS\x03\xa1uw\xe6\x9d{8\xb9\x89=\xbc\xd9*(\xc8\xa1\xa65\xfb\xf7\xed\xf9\x98\xef\xf9\xd8o\x8fk\x8b8\x9cU\x87\x1c\x95\x87\x1c5\xee\x8b\xd2[\xc5c\xad\x91\xf7\x0dk\xbb\xb2&4iB\x86\x85{V\xd8\xf2SP7\xcb\x86v\x94\xb1\xe8$\x9e\x04\xd4\"\x83\x96\xbb8{\x00[\x01F\x9cKyT\x08\xa4\x18\x8b\xb7'\xb4\x10A&d\xe2\x08\xf2\xedm\xb9\xab\x1e\xd8\xa5\x91\xbc s#L+}\xf5\x8d\x025\xcb7\x86\xaaE\x9d\xf3D\xd7\x12\x8b\xed\xf2\xbd\xa5Y\xcb\nl\xbe\xd5\x98\xb6\x0e\x1dZ\x0e\\$\xe1\x8c\x8e{@,\x8dX(\xaf\x8d\x10\xe4\x12\xe5\xf3\xff\x02\x94\xaf\x0e\x15\xfd\x14)C\x08D\xca\xa2\xb6\x83\x80~\xa0\x94\xc6\xa8\x07\x1e\xcc[6LF\x11'T\xadC\xc226\xbeK\xa8\xa6%\x12\xbb\xe4A\x17\xdd\xa4.m\x12\x9a\xd8\x86\xc9H\x84C\x96c\x8b\xeb\x03;\xcdI\xfc\xa9\xbd\xa06lk\x1d[\xc6\xe5\xfd\x8f\xed\xbe\xc6\xc2Z \x9ai\xb1\x8d/\xdf\x08\xab\x8a+\x01\x8f\xaac\xb5Ka\xd8\xbdQA\xc1\x0d\x11\xa5\x02\x9eC\xb1(\x82\xf2\xe4\x1e6\xbe\xe6\xb4.+\xf67\x1f\xfa3\xbcsI\x03\xe6\xe4\xfa.v\x0dA\x1b\x0e\xa1\xf7\x9e,H\xcc`8\xea\xc1A\xf5\x0b\xbd \x98\xa6\x16\xda\x86^u\x0f\xbf\xe5wX2'\x05\xb4\x9d\x8e\xe7\xd7g\xcaML\xb8\x18\x82\x81\x01\xaf\xf5\x93\xd0q\xba\x9c\x10o.|Ft\xc5W;*\xab\xd1<\xa6,\xf0\x99Hm\xffpPYQ^\x8b\xd9\x13S\x85\x03\xa5\xad\xab\x8d\xec\x83\xb0\x13\xc3\x8e\x08\xa6k2\n\xcd\x91\xe6\xe4\x9c\xe4\xc5&n\xda\x1dp\x9d\x90\xcb\xb7\xd3\xeb\x83\x15\x0eQc\xb8\xb3\xe7\xec&\x8d\x0b\xf6\xfc\x06\xba\xaa0\xb4\xb3\xcb\xeb\x0bS*UT\xb9\xc4\x98+\xcaJ\xb0\xca\x03\xa36\\\xda<\xd1\xa8S A\xbd\xe6\xb2\xb9\x94\xb3\x11\xab\xba\x19\xb1Vl&<\x04\xaa(N\xc5\x02Q \x89\xd0\x98\xf0F]7\"~xP\xd8\x1a4\xa5\x91\xd2\x13\x0fI]\xf5\x0e\x87m\xcc\xd4\xa6z\xde\xb6\xf7s\xfa\xbe\x92\xf4}u\xc3\xf4\x1dU\xc6\x8a\xbc\x8b\x1f\x1au\x17\xda\xddm\xe8\xf5\xfb\xfd\xea.\xa1\x13\xd8\x86@\x08\x15\xeaE\xb2\xe0\xed\xc1\xe9\xaa\xf69Y\xf0\x86{!\x9e\x07\xed\x93`u\xb3'\x81\x1an\xa5\x8b\x84\xaf\xebCi\x9d\x11\xabk\x9d\x11\x8as\x08\x08\xec\xe8}\x87p[\xeb\xcf\xba?0@zW\x18\xe452!n\xf05B\x9d\xf84\xcd\x0c\xb6\x87\xc6\x90\xbd\xcf\x9d\xc6\xa1Rv\xaa\x1d.\xe8R \x02\xb2\xcb\xa7\x91\xb0\x15\xe0\x19S\xdd\x0d\xe1\xe1\xa0\xf4-]\x91`7\x82\xddP\x1eO+\x89\xdcg\x84\x05\xbaU@\x99\x0c\xf8}f\xb8\x8f k\x9f]\xab\xeb\x1c6\xe7eTemy,\xf6-\xf8\xbf:\x92\x0c\x06|.vi@d\x17p\xaf3\x94\xf6D\xb5\xd0\xb5\xf3 4\x13mp\x89\x03\xed\xc3j\xf5\x85\xe7#\x0eGB\xd4@sV7s\x16V\xd8\x8dz\xc3J$\xe0\x90\x93\xf2`k\x03S\xf8\x1a\xf3\xe0iw\xeb*G\xeaT9\xd6%\xc4\x08\x12\xa3\x06\xd1\xbcl\x19l\x8b\x11\xed\xf0\x01\xe4\xfe\x0b\xd4\x92\xd7\x8c\x00\xdc\xfc\x00\xae\x80g\x1co\x03\xa0\x969\xf9\x02\xd9\x0c\xce\x9b8\xec\x95 \x9d9\xd5!\x0d\xe8\xf3E\x7f\x84\x16\xc9\xbf\x98\x03P\xca\x17\x94\xd7c\x1f\x91kuC\x0c\xc1\x8a4\x16F\xf8}\xc8\x1fe\xb8\x1d\x9aU\xc5\x13\xfegy_\x92,\xf9 \x9eq\xe7ed\x91\x81\x8f8%*\x9d\xd3 \x89\xe0\x94\xe0\x9f\x17\xd5\x9fG\xea\xcfSRF\xf4\x887\xb5@\x1e\xf1\xbe\x0c\xf29jH0|\xa1/\x89-\xbb\x04\x9el\xc9|\x89 &v\xf6\xab\xd3\x8e\xdf\x0b\xaa$,\x11\xec\x87*\x7f\x06\xbe~\xe0\xbfk\xee\xdf\xbbw\xe7\x1e\xdc\xe2\xe7\xd9\x9a\x13s\xfb\xc6)\xdfd\xe2M;\x92\xe3^\xd9F\xb7\xbbG\x8f\x1e\xc1\xde\xfdP\xde\xe1O\x02V\xde|\xf8\x10\xf6\xee\x8b\xdc3!\xac\x9b\xce\xf8\xb6P\xa6\xe3._Il\x1en\xc1\xde\xee7w\xbe\xb9\xbb\xf7\xed\xfe]X\xc3\x9d\xfd\xfd\xbd\xfd\xfd{w\xbf\xe1O\xfc\x9c2\x9fZ:\xd2)&\xac\xd7\x8e\xe0\xeb\x92\x86Z4\xd5\xdd>\x8f\xaa\xa3\xb6\x07\xa3\xbb\xe3\xae\x9e\xb7\x9a#4Px\xc5\x18\xa8qY\xe6P\xa5=\x18\xd8}\xce\x12\xf4)\xdc\x92C\x15\x0e;\xc2\xa7\xc21P\xd0\xf0t\x17\xd66\xe7(q\xec\x8d\xe0\xbd\x80\xf5\x1b\x993\x83`:\x1cxF0\xf1\x19>\xe7T\x1c\x1b\xe7K}\x9d,\x0bp :\xdb\x08\xc7gq1{\x9aM\x88\x06\x19u\xcb\xa4\\\xc4\x96\xaa\x90-\x1d\xa4\x9e \xb43\x9e\x1f\x9a\xbe\xaa\x08\xbfw\xc2c\x8d\x84a\x97\x1a3\xa9\x9c\x0b\xcb\xaf\xc9\xf09\x19y}\xb9\xf5\xd6:n\xb05\xceOS\xb4q?/\x8e\xaaT\xd8\xe8\x0egz\xe25\x16[g\xdd\xe0\xd5\xbf\x96\xa3\xa0\xd9\x84|X-\xf8\x96\xdb\x0d\xa1\xb8H\xd8x\x06Au\xbf\xab)~\x8d\xe3\x82\xc0\xdeA\xe7{\xa0\xd1\xfe\xfe\x92&\x9f\x97\xe4\xf93\xfb\x1c\xd5\x85\xcd\x7f\xb7a\xf3\x93l\x8c\x01\xc3G)\xe1\xff\x88\xc96n\x96cp6mVj\x83\xdcR\xdaj\x19\xdf3\x7f\xcd\x97k{\xfb5\x89\xf4\xa3\xef\x16\xbc\x16{\xff5\xee}G\x88\xc8\x07\x12r\xac/\xa4,z=G\xd7\x06\n=V6\xd5\x01\xfe@\x97\xe7\xa6\xc7`\xefMFw\xc8%#\xb4H\xaa@\xc2\x02\xe2\x9c`\x92\xe38M\xb3\x0b2\x81\xb8\x80OdU\xf4\x9b\x89\xb3\x9b\xdd\xf3\x0de-n\xf1\xdc\x98\xc3X\xbf|\xd2\x11\xab\xab\xbb*\x86~iI\x8c;\xde\x94|\xbay\xf1\x01\xcc~\xb1\xea\xc2\x15j\xac\xc3\xa6$C\xb2\xc9Z$\x89\xc6\xc1\x9b>\x08\xad\x0d\xb9\xd5m\xfa\xa5\xcb\xda\xfe=\xf7\xe3\xc5\"]I6\xde\x12\xd1\xaf_W\x91\x83L\xf23\xb0\x03\xb2\xddD\xb0\xe6\x94^\x91\xbc\x16\xde\x7f\xa4\x08!\x96AA\x18\xc4@\xf9>\xa8 \xa7\xc6\x08\x19\x95{\xc2\x89\xfa\xfc*\xe7`\x9f\xfd\x06\xf4\xc4y\xeaot\xda+\xe5kI\xd68\xc3\xa0e\xb41\xe6\x03h@\xeb'4]\xf1&\x85\xd6\x14\xd5\xa4c\xe1\xd4{J\x80s\x0fd\xd2\xf7\xf4\"\xfdd\xe1\xedKu\x0c\x13\x8c\x92f\xa1 \xf5b\x16\xfc\x85;{\xf0\xb5HU\xd8\x1f\xcf\xe2\x9c3/\x8fY@Q\x98\xb1\x8aG\xc7\xa4\xed#\xad\xff\xe2\xbd?&U\xc6\x84\xa48*ic\x9bj\xbc\xf5\xdaa,_9\xf0V\xa9;\x8d4\xf3\xcf\xab\x08z\x7f\xefE\x82]\xb4\xea\x04\xc6\xb18\xe2]{\\\xf6cs\xf57\xa0Y\xd8\x16\x97\xdf\x91\x08>XE\xe6\x9fI\xfc\xe9u\xdc\xd02\n\x06/xGd\xe6\x02\xf9\x92\xa1qqF\xb6\xa1\xfc\x1c;<9I\xe6\xf3%\x92p\x8em''\x8d\x14\xed\x1d)\"\x03lE\xfc\x0e\x9e\x93&\xd2\xf3\xfe\x7f\xe7o\xec\xdd7$\xa6\xe4\x0f\xf6\xef\x192\x1f\xbf\xb7\x0cY\xb2\xf86)\xfa\x95e\x03\x9c\x91@\xc4f\xa1tV\xb9\xcd/H>\xcd\xf2\xb9P\x7f\xc7\xa2\x8d\x8b\x84\xcd \xa6\x90\xd0iB\x13F\xa0H\xfe \xbe;\xf0\xa3[\x8cw&\x0d\xfbE$\x0d\xfb\x8cMp\xfeb\x1c\x94\xf9\xd3\xf9\xb3>\x1f\xd9\xeb%\x8byO\x85\x16\xd6\xd2\xa5\xab\xce\xad\xe9\xed^\x91\x80*-?\xedO\xb3\xfc(\x1e\xcfj\xf1V\xc6@\x06u)R\x8a\xdc\x15m\xa9\x9b\xd4e\x8a\x82\xf6\x03\xe7g\xef\\ \x7f\x90\x8el\xe6\x1fI\x04'|\x9e\x1f\x89G2\x9d\xd2| B\x8a\xcb\x038r\xa9\x88\\\x8bd%!\x1d\x15\x86`{\x00\xfb]\xa2\x14\xda\x85\xe1Q\x95@\xc6p,\xbfN\x8a\"\xa1g\x82 \xc3^?\x91\x95\xc8f\xc1\x86\xd4\x94fR]\x82y\xe6/E\xfcU\xde\x97-\xdc\xbds\x9d\x11\xfc\xd76_\n\x85\xa7\x96\x01\xeau\xbc\xb0\xa6<\xfb\xf8\x85\x96\xc5\x93<\xcb*\x959\xff\x81\xa2s\x19K#\xf26\x85&\x93b\xad\xebb\xa3\xae\xff\xa1'\x85r\xcf\xa9 \xec9\xdd\xa0i\x9c\xc8r1\x89\x19y\x8e/\xaf\x0c\xd5\x0cm\xdfn\xba\xb29\x99g\xe7\xa4S\xd26\xccz\xe5nxBR\xc2'\xe0\xdbtk\xd6\xbeS^m:e\xd1IsA\xdc\x89\xa3\x85\x08Y\x92\x17\xa5G;\x94\xae \xa12\xce\x94\x13\x18\x92\x91l\xd4c,m\xf4\xb0\x8c\x06\x83]\xd1)R\xc6b\n\x14w\xf8\xc8\x96$\xda'\x91\xc4\xb9\x8c\x03\x15\xa6\x8d\x95]'\x1aw\xfa\xe2qr\x17K?<;Q<\x97)c\x12YM\xcbb\xd6RW\x01\x03\xc8\x82\xa5\x83\x06\xca\xe5*p\x02K\xe9\xac\xdb\x8e!\x03\xab\xd4qF\x82\x04cH\xd0p\xc3\xf7n\x04\xbd\x84\x9e\xc7i2\xe1\x94\xf8]\xccf69\x88\xcf&\x85\x01\xc4.\x0fT\xfe\xd2XNy\xc5\xa7\x8c\xd4*\xe5\xfb\xc9\xfe\x01?\x07I0\xae\x16\xd0\xa9(\x9d\xe2\xec\xc7r\xf6\xe2\xd7\x8a\xff\x92\xbb=H9\xbe\x06I\xc5\xcb\xb0\x10\xcf\x8e4\x82\xa9\x81\x07\x90{\x9eR\xd4\xe9Z\"\x1ee\xdfy\xd9\x9b\xe4\x9aZu\xd0\x1a;`\x9c\x92\xd8Y\x94Hk\xbc\xed\x16\xc3\x84?\x84Ym\xc0:\xea\x8d\xb3\xee\xf6k2P\xe7\x04J\x8b,_\xa9\xb8x-t\x11&\x06@\x8e\x86 b\xb1\xfeE\\<\x16\xf44@\x1f\xb6\xfe\xc9 \xa1\xc52'o9\xbd\x0e\xea\xc4[\xb1R\xce\x81\x97\xbd{\xee\xc1\xd6\xf9P?7\xf4\xd1pQ\xec\xd2\x0d\xb6\xb8x\xae41\x9b\xf5\xaf\xf7\xd3\xb12%\xc86\xebA\x9e[\xce\xb67spR\x1a\x11r\x01/\xfde\x9e\x8d\xbc\xd0\xbe\xd4\x89Y;\xdcKo\x1b\x94\x03\xdb\x99E:\x88\x08\xba3\x93\x80a\x82\x19\x86\x19eL6\xf7H\x94}\xea\x80\x80\xb6\xda\x9d{K\xed\x98\x8a\xc11`+?\xd2\xfeI*\xd6Fgk\xa2*\xaf\x03\xb24\xc8\xe15\x1a\xd2r?\xe8\x0c\xce\x9edp\x0c\xd3I\n.\xb9\x0f\xe0\xb3\xc1s\xe8{\x12\x01\xb2W\x8dd\xc0\xaf\x1f\xbf\xb3TO{\xc2\xdf\xd6\x81dS\x0f\xfedO\xfc\x81\xc3oOH&*j\x19\x1f\xac5>\x9c @,\x9d\x9c&l\x8e\xe0PN\xb14\x13.\xc8\xd4\xab\xcf\x9f\xaf\xd3\xe78[Rv\xed._\\\xa7\xcbOd\xf5\xa3`\x8aY\x0b\xba~\xdd\xfezs\xdd\xae\xbc;}\xd9\xdd\xe9 \x13\xa5FK\xa7\xe6*\xc2\x86V\xbe\xcd\xf1\xf8\x93H\xd3\xa9(\xcaW$\x90\xbf\xfc\xb4\xa1?t\xa6x\x14\x15\x90D\xc6\xaaVRJ[\xb3_u6k\xa6m\x1ce\xac\xe5o\xd1\xab\xf8\xc0\xe6\x8eyr\xb2\xc8\xc9\xb9\xc9\x14\xec\x97\x85\xe5\x9f\xbeIQ\xeb\xc5_\x9f8\xf2\xf6fJ\xaa#\x11d\xa5H\xc7\xf0\x87F\xe9\xa8\xb8!\xa5\xbb\\\xfc\xaa\x13\xbd\xcck\n\xbf8\x93R\x7f\x8fz\xed\xe0{>\xa0\x7f\x92`\xd73\xff\xdd?\x9c\xb8z.k\x92\x9b\x8d\x9c\n\x15-\xab\xadt8\x17\xc1\xa9\xc5\x9d\x12d~\xd8\x8b\xe0\xc4\xa1\xbc\xc1\x04pL\xf5\x86\x91/\n\xbc\x11h\xcaU\xb1\xb8I\x04q\x18\xc1\x96T}T~U\xe6\x0eD\x1e\\\x19~\x18$\xb2P\xd7!\xe7\x02\xa4\xf6`g\x0fK~\x1d4\xab\xc9\xf1\xeb\xcae\n\x17zvl\xc6g\x14{U\xf9\xc6\x9fp\x9bW\x93\x1cZ\xa1'\x8a\x8f\x19\x1f\x9b\x82@m\xc8C\xea*\x8b\xb2>c\x16\x95\xd4\x07Q\x97\xb4\xd5\x14\xa4\xa5\xa3@O\xb8\\p\x08\x19\xee6\x93\xbe\xc2\x82\x8f\xd2\xe9\xa6\xd4/\x89\x05\x8d`\xe9\xe4U\xb8D%$\xb6\xc0\xf8\xe9\x01GD\xb9\x9e\x84\xf3#G\xc12\x8c\xe0(\x881\xeb\xc3\x05?'D\x0e\xd7!\xff\xcc7\x9d;cn\x1e\xaa\x95\xa8\xf4W\xe1\xf6\xd9\xba\xff\xc2\xcf\x13\x976\x80c\xea[l\xcc\xf2\x08\x1b\x0c\xf8\x02h\xac\xf3\x8br\xa6\xb2\xbaP\x04\x99\xc9\x96\x83\xbbW$\xde\x0e\xaa$_U\xcb\x07\xda\xdf\x8f\x1e=\xe2\xf4\xe3\x16\x9c\x99\xf7\xf9\xb2\xde\x08\xba\xe9k\x1fY),\x1f\xef\x8f8^\xaci\x1b\xc3Z\xfc\xb1\xc4qI\xbd\xea\xb0\x82\nl\xc3\xb9\x84\xccH\xe8\x15\x07\xf5\xd5\xcdB\xfe\xe5C\xf1\x1d\xe1+\x0d\x070L\" \xbeK\x9e3\x17\xbd\xac\x12k`\xf5\x82Z\x86\x02Z\x9a\xe8:\x12\xdfph\xd1a2\xb2\xd3\xcc\x02M\xb46\xeds\x1c,\xd1-:\xe0\xaf\x15\xf5\x8c\xc6>~ \xd3V4\xa1\xba\xae\xc2\x90\x1f_\x8be1\x0b\x0c\x9eEV\xf2\x12+\xa0e~@\xce\x9c@.w=zmUj\x95[\xb7\x00\xb3\xb0\xd6\xd4+\"'c\x99\xd8Wl\x7f?\xce\x12\xc1S\x82\xc9h\x87\xbc\xa3QX\xe3\xc8\x98\x0fG\xa6.\xe5l\xc0\x86\xb6\x04x\xea\xca\x10\xab%\xf9'5\x115FEKl\xad\xfe\x01F.J]\n\xd9\xcd\xb4\x99wU8\x8d\xf2|\n\x0b\x90\xd1a\x9a\x82W\xc9\x99\xd6\x8e\xb9d\xb7\xe0\xb8\x85\x14\xa9\xe8\xb2\xf9\x1f\"\x7f\x9dJ\xdb\xff\x0e\xec\xc1!L\xfa\x8bLT\x82\x98\x0cSN\x8dZ7\x86|\xe4\x9c\x1f\x9f\x08\x06S\xfc\x0e#\xec9hh\xff&\x95)\\ \xcc\x11L\xbaX\xd2\xab\x08~\xbc693F\x97!vY6+\n\xf5\\\\ \x82z\xfdp\x11\xf9IP\xf6\xb1hF\x12EC\x84\xa6\xd7J\xd8x\xc3\\\xce\xb9%\xb8\xbb24\x1b\x95\xb3\xc3%\x13\x8f03\xf2H\xc4q \x19\x89\x99\xd8\x89&x\xaeM\x17k\x99\xa1U\x02\xe8\xa7$\xc8m\xa0\xd2\x04D&Y\x1e\x8a@b\x0e\xa9\xb2P\xf0]\x9a\x9f\xa7u\x18\x9a_\x1acL\xe5\xd6\x00\x82\x14n\x81 \xb5\x91\xae!\xa1\xce\x1a\xca\x1c3AUtz\xc9D\x93\x08|s\xe7\x0b5B\\.\xf3;|\xef\x8d\xe1\x10\x16\xc3\xe9\x08\xdc!\xeb3\xa1(\x9b\x08\x0b\x8cX\xe8\xfaZ\x99g'\xd4\x04\x13\x8f\x83B\xc0\x01E\x97\x85F\xde\xc7N\xf2\xeep\xf3\xaaU\xfc\x92\x0c\x01\xdf\xcf\xa2\xde\xcc<\x8c\x103v\x1fHV\x9f>\x80%\xa6\xf9\xe1\xb81\x80\xbd\x10\xe2\xe1r\x84hp\x0b5\x0bl\x98lo\x8f\x1c5\xeb@\x13J\x87\xf9H\xa8\xb8\x84/|\x80 \x05\xb7\xb1\xda\x98\x81\x90\xf0\xc7\x8b\x08\xd2\x08\x96\x11\xcc,\x90\x94\xe79\xff\xbf\x08S/\xa1\xc4\xe5?\x16,\x86{\xf0/\x98j\x9c\x8b\xba\xe3h\x0f?\xde357\xab\xda\x99\x99\x11\xf1tSr\x7f\"\xd1m\x86\x14\xfc\x00R\xf8\x17\x92\xfd\x14\xd6`\xc1\xd0\x0b\xed\x93\x82\x05\x8b\x08\xa6\x11\xcc\"8\x0d\x9b\x01\xf8\x1d\xe2\xc7yY\xed\xa3\xf2\x80\xb0\x1f\xb5B\xbdZ\xa6\xbf\xc9\xb5\x08Z!\xc5P\x80O\xb9\xa7\x1eb\x99=Q\xf3\xacslz\x97\x88\xf6\xf5\x0e\xdd*\x8d\xa4\xfa\xcc1\x06\xb7\xa2#\xe9\x92\x16\xf0%\xb5L5\x00\xa8\xbbn\x19\xa2\x81_0\x80\xafH\x90X\xed\xe7\xe0\x14\x17\xc6\x19e \xdd\xa8\xf8C\xbb\x7f\xedW_\xf8\xccv\xecj\xa8\xb6\xa7mct\xe6J\xb5\xe6Im\x10\x90:0\xf9*\xa7|\x06s\xb8\x0dw\xdb-\x8f\xd5\xb3\xfd\xf6\xb3i\xf9\x9d\xcds\x7fa\xf1\x188\x97\xb1CG\xc6\x80a\xe4\x9b\xbb\xf3XZ\xe4\xea \xe6\xc9+\xa9\x9d\x99/\xa4\x18:\xec\xaa\xe7D\xdd5\x1e\xc4`r\xa9\x03\n^\x89\xe3:\x87G\"kt\x0e\x0fa\x0e\x87p\x81\x99\x07\xf2\x08U\x0c\x18g\x8a\x85 X@\xfb,\x13\xf2w\x88ei\xd9\xc6n1\xe8'r\x9c\xfc!z6\xa4\x01\xe9\xd2\xf4\x96\x9a\xda\x0e\x7f\x13\x93\x17\x89\x9f\xa7\xc5\xc4\xed0\xa2\xe5\x01\x99\xb1\x8e< \x0b\x16\xc1\x05\xe1l2\xf3\xc8\x03\xa2 \x1f\x81=\xc6r\xc1\xb4#\xeeKsZ\xbcJ\n\x06\xc3^\x04\xbdQ;\xa9E\xad'\xcf\xa4\x16\x89\xaa\x15_%\xc5\x0f\xcb\xac\xe4\xa4\x9e\x95\xdcq\x9ar\x01\xb6d-1I3\x8e<\xcb\x93\xb3\xc4\xe6\xd9\xa6d.\xde\x13\xed\x8b2\xa1\x04n\xc1\x99!\x14\xd2\n '\x0c6\xcb\xae\xe1k\xbf@\x901\x04\x99d\xabjU\xf3\x1dE\xa00\xb1\x7f\xe5\xc4\xc6\xe0\xa1\x96\x0dvs\x975\xc0c\xe1!\xec\xc2!|\x92\x19\x0cq\x9b\xed\xca\x08SqsW\xa8\x1f\xf7\xc43f\x8c.\x03\xb0'\xd8c\xe8\xfb\xa4\x16\xd3\xfcNe\xcf9aq\x92\xba\x19*\xe5\xdeo})q\x06\n \x14\xdfb\x94\xc08^\xc4\xe3\x84\xad\x84A|\x00\x97Xo\xbb\x195 \xe4A\x14\xb12\xf1R\xd6x\x89\xf4ORrN\xd2\xea]\xfb\"n%~\xe1\x06\x89\x08\x9b\xa8BL\xcbuV^\xf6b\x14\x1c^\x9b\xb8\xdc;7\xd3\x05\x82E\xac\x14~\xad \xa4\xcf13z\x17^\xb9\xe2,k\xdbj\xb3\xf4-H \xcaJ\x1c\x9aU\x03 \xcb,\x992T\\h2\xaf\xcah\xaf^R\xba\x0d\xf1p\x91&c\xe4\xdb\xf6lQ\xbb\xb5\xc1&\xb4 \xf9&d\xa0\xd1\xcbn'8\xfe\x0d\xc9$tjZ\xfeTK\xab'\x9b\xc0\x15\xe6\xf8\xd3\xc8>!%%\x81j\xd7NE\xc1\x19)'(\x16\xcbb\xd6\x05 %\xbcU\x11\xfa\x96]\xae\xc1\xc9\xca \xe1\x1b\x16\xbai%\xe0\x9f\x90\x11\x91dQ\xd9R-;\xbe\xe6\x16\xbc\x8b2\xbb\x96\x16\x11%w*\xe8*l\xe3\x1e\x1e\xe6^%\xd9\xea`\xcb|\xf3:|R\x87\xecn\x04;{\xeeV\x97\x14wWW\xcb\xad\xf5\xb8\x16\xb0\xad\xa1a\x9f\xf0\xc8\xd9\xf1\x05\xb3#\xfbd\x99HnH7\x07\xb1\x17(\x9a@\xee\x00\xf0&\x89W\x1e\xfb'^i\xf7\xe1\x95\x90\xa3\xd9\x91o\xe2\x95vw\x1b\xe4\x19y\xec\x97g\xc4\xdc\x87\xd7\xb4\xce\xaf\x93\xd7\xe3qg\x9e\x91&\x9fx,\x08\xad\xd7\x89\xa6o\xc2v\x11\x8dz\xcb\xbe\xf5\x97\xce\xbf\xa8\xee_9\"Y\xe2\xaf\xac\xfa\xe7\x1e\xddfI\x19\xca\xedi\x17gOJ\xe4\xb3\xaf\xcd\x06\x05a0\x14\xb1\xabB.\x9e\xa8\xa7\xec\xdfW\x04\x86b\xd1\xd6\x8d)\xd0F\xd9)\x9aur\xa5\xfe\xd8 _\xbc\x02\xa1s@\xa1\x04\xc1\xa2\xd7w\xa6\xd7\xad\xec\xdc\x98\xc8_\x92d\xe2\x82\x05:\x9b\x135\xb8\x9c\x1a\x87\xa3s7\x91\xc6\xdcl\x94\x90\xc2\xb4\\I\x81\x12\xf6\x00&\xac\xad\xc1\x9a\xb1v\xe2\x89W\xcf\x8f?X2O\x9c\xa3\x05]\x83\x9cM\x7f5gV<\xc0\xb1\xa3h\xac%-\xa8f\xd2\x8cn\xd3\x7f\x9d\xb3\xe1\x8c\xa9`\x90sV\x05\x83\x9c\xb32\x18\xe4\x9c\x95\x89\"\x9f\xc8\x9c\x91\xda\xbbx\xbf|[\xbd\xa5~\xe1\x8b\xa5\xfd\xed\x89\xb2\xc5i\xb7\xd5\x17\xea\x17>\xaaR{=)\xf3|U\x0f\xcadOOj\xd9\x9f\xf0\x85f\xe2\xa0'\x0d\x89\x19_\xd2\x93\xf4<\xd1r\xf6\xc8\x87z\x0e\x9d'\xb5\xa4:\xa2\x0b=\x03\xce\x13=#N\x04\xf3\xb6\x08\xf4\x84L\xb3\xdcd}\xb4iZh\xe9\xd0\x84\xde\xcc\x0c#\xdb\xca\x8d\x81\xeb\\\x86^hL\x97Y\xbb\x88\xfaC\xe1\x13e\x0e\xad\x15\x0e\x80\x8f\\\xadK=\xe1p\xc4O2s7\x99\xf4\xbb\x10\xaaHs/LT\xbd\xb0S\xf2\x18\xf4Q\x0c]\x06,,R\x1fs\xba\x15\xd7\xc0\x8c\xb0\x85\x1d\xd4q\x86!\x8e\x06\xdfJj\xa0jSe\xe3\x80\x85\x95,\xf3\x80\xf2\x12\x06p\\\xe5\xce2\xcf\x7f+1\xabTj\x8e\x13\xbb\x0f\xa0\x10.\xa6\x05\xfaIJX\x14\xa3R\xfc\xb2\x12\xe4\x0c\xddD\x96%\xf48\x8d\x0f#X6)\x98\x01G\x1fO\x19i\x1d\xef\x9d(\x1a\xd4q\x14\x83\x8c\xbf\x00S\xa5\xf5\x13\x85\xfa\x0e\x84\xcd\xdc\x08k\xee\xc4\x0b\x07\x93:\x0e\xda,J\x88\x839&\xcb\xe4\xd8\xa5\x83\xd1\x80\x82\xf8Rf\x86\x0c\x1a\xbf6DN\xb5Y\x9c('\x9b\x8ceoRY\x91\xa1\x92/\x92~mq9M\xceD\x85\x11\xc4udi\x1fog,\x82\x15\x8b8\xd3\xe0J\xa3~b?\xad*^]\x1d\xe2F\x08KEay\xb2\x1b_\xc2\x04-,\xc8\x1dQ3Ryf\x87O-\x91\x88d\x1cv\xc3\xc6\xc4\xa0\x16\xf7\xcc\xe7\xb6\x8c\xc0jc\xad\xe9q\x96\xb5rV\x16O\x13u)b\x12K\xff\xa5C\x85`\xe2x?PQ\xee\xf8\xd3\xce\xa3\x82\xf4K\x89e\xe5\xc3]\xf4\x8c\xdd\x81\xd8\xfd \xaa\x18\xf9k\x16\xbe\x11_y\x04s\xc4\x1d\xfe\xf2\xdca\x0f\x95@\xe8\xe4\xe1\xd5\x95\xa0\xe3,\x9fvZ\xee\x87SG\xd1\x11\xd0\xd4\x12X\xedq'\x85\x03N5\xdd\x9f\xc8\x96\xd1\xb3k9$\xe6\\)`\xdcvx\x97/a\xd1t\xcb\xcfPs\xdc\xb1\xac\xc2\xa9\xd5\x7f\x01S$/\xf5\x05L\xe0\xd1#\xc8\xdc\xdf\x8d1\x00f\x9b\x1f\xeb\xea\x03\xc72\x8d\xcb\x05\x1d\xdf\xf0\x82\xe2\xb9\xf6\xc0\xea`\xa1_|\xed\x8d\x19]L\x97Z\xf4\xa5M\xe8k^\x89,\xb2\xc7E\x9d.\x85|\xf3ZJUh\xe7\xcbv;\xbe\xba\xf80\xd2\x86/a\x17\x82\x83.\xf5#\x92\x8f\xe1\x00\xd2.$\x079\xf2X\xb8\xa2\x17\x98y?\x13\x87R\xc2Q\x83\xf2S;\x0b\xedn \xe0\x9c\x92co ]l=\xf6K(qaL\xf6c;D\x96\xad\xec\\\xe7\x0e\x8d\xc2\xb2T\x93\xc3\x0e\x17\x92\x96\x9a\xaa\\\xfc\xd4T\xe5\x0co(=9\xc5_U\xd6\xa3e\xa9$\xcf\xf0\x87&5&\xe2\x86\xd4\x97\xc7\xe2W=\xb9\xd7\xd2\x0b\x14G\xcc\xa5Q;c\x18\x06}\xc6\x07$\xec\xfa\\|\xf34\x85_\xb6\xa1l\x03q,\xfc\xf1er\x1ewL\x05\x11N\xf3\x0f\x15qS\x8a\xd9\xd6\x07\xc8\x0b#^j\xbe\x14\x99kc\n\x96\xb3\x83sK\x1b\xc4u\xb8td\xcc\x19\x0b\x13\x9f\xb4\xe5\x89\x8d\xa1`\xe1\xd4$\x8d\xc5 \xa5\xf2F\x05\x92\x0d\x136\xde\xb2c\x18\xc0\xd8\x1c6h[\xd1\xa2>\xf2\xf2\xf8'\x95[\xa6\xdeUT\x83\x9d\x80<\n;-\xde\x12\x0e\xcb\x9b\xcaD\x16\xeb\xe3l\xc7 \xd8\xf0\xe6\xd8\xce\xd3\x95j6\xf4\x07(c\xf0\x88\xe6\x99J\xa4\x07\xea\x9c\x05\"?\x97dK\x91+\xe5\xa3\xe2\xe2\xa5g\x1a\xc3\xa7\xf6\x91\x94\x16\xf4\x86\xedW\xb7\xac\x9a\xf9A\xf1\xe5C!\xd0(V\x10\xb6\xe1\xdc\x86t5sD\xc9DJ\xbe\x15\xbf~ \xfc\x16\xd0\x15\x07\x0b\xab\x0eJ\x1f\x06\x11\xaa\x95\xa3'\x03\xffhg\x00\xe7N\xc4\xeb*\xf3n\xad\xe8\xe5L\xd2\xa3\x05\xbd\xa8\xa83Q\xeeX\x7f\xa2\xe2\x0f,\xe5\x8d5\xb3\xbe\x9en\x07\xf33\xd8\xd9\xf6\x0e\xf6?\xf1a\xff1\xc6\x03\xb6m\xc5\x19\x96\xa5\xcc\x8c\xd8H\x91\x9b>@\xb3\xd1.\xfe\xbd\x8d!c\xbc\x05\x83\xc7\x02\xc7\x87\xb8\xb9\xbf\x92.2\x15s\xdc[j\xd8\x86\x86_\x13\xa7R\x13\xfb+\xd1#\xd5\x91i\xac\x82N\xb7a\xccG\xfd \xc4\xe7r\x1fa\xf5\xac\xb4\xbe\xe3\x0fa\xa8\x8cG\xe9H\xee*.\xd8\x8da[e\x1f(\xf8\x9f\xe7\x86\x11\x8d\x85L\xc8\x1f\x8f#QF}\xcc\x0f\x00\xf1o\x82\xff\xba&2\x15\xd2X\x82\x11\x04\xf8\xe72|\x00\x0b\x0e\x11\xec\xb9\xe0\xbb\xc9k\n\xb5\xa1\x8b\xf1\x9a\xf1n\xd2\xe5N2\xc3 \x8a\x87\x18#!\xc8\xc6RH\xdc\x07|`x[Soat\xe3\xc4\xbc\xb2X0]|s\xeb\x16\xc6\x01\xa3h6i\xa8 :h\xc5\x1c#X\x90\x90\xa7bz\x9c\xdf(\x1e\xc0\n\x1e\xc19\xff\x87S\x82.Y\xe2\x14\x060E\n\xb22+I\xd4\xc5\xbb\x9bK\x92s:\x12\xfdV\xbf\xad \xa4\xcc\xfc\x9d\xfaP\xf4|\x8e\xb4\x0b\x060\xe9\xa0L\xa0\x18|\x05\xb2\x80/\n\xc6\xac\xcfj\x8a\x93\x1c\xd9\x98e\x88g\xdd\xa3\x01,B\x8898\x16\xb8h\xf8o!\xdc\x16*\x07\x85VSR\x0f(\xda2\x85O\x96\xee\xc8\\8\xce8\xa5B\xfcp\xae\x9c\xdc\x87\xa9S\x98\xe1\x0bs\"\x84\xeeG\x8f\xf8\x81\xeeZ\x18>\x80\x13\xa4\xae\x8b\xea\xf5\x10Ns\x12\x7f\xb2\x7fu\"\x05\xb5\xed\x01\x04bK\x85\xf05\x9c\xe0&\xd9)!#\xf7\xd3\xf0\xc4,\xdc\x9a\x177\x15X\xfdH\xaa\x11E;M\x90\x16|ev`\xcc\x97(\x15\xfb\xe1\xa1\xd8\x0f\xb5\x0f\xca\xe5,8%\x90\xef+\xea\xb2#\xa9\xca\x8e1\x8ar\xe3\x94\xa4KTkT\xc7\x89`\xbbI\x8d\x9d_V\xba\x1d\xc08\xce\xca\xbd*\xd5\xdd\xabf\xbe\xeeU\x9cL\\\xb0 \x16\xe2\x0eFj6\xa3\x1b-\xc7\xf1c\xbf|\x91\xb9\x9e/\xb2\x16A_eY[\xba#B0)\xb6\x93 F \xc6\x9a\xbe'\x15\x10~$\xf7l\x82\xeb++\xfd\xc5A!RJ\x8aU\xbf\xe9\x94\x92\xb9\x88GK7@\x8f\x04\x1e)\xa7\xc9[\xb7D\x82\xa8\xca+9A\x92\xa2 \xdf\xccrcY\xa9\xb7])\xe6\x84[\xf5.*\xe5\x94\xce\xfa\x9co\xcas\xaf\xf6\xdf\xb9\xdbw\x16z|.\xdc\xe1>\xb0\xaa\xbe#\xbf\xb5\xb1\xdf\xcd\xf9\xff\xfa\xfa\x8e\x1f\xdcP,Ka\x8e\x9b\x08gk\xf0\xb5oJ\xbe\xba\xea\xe1\x9dfT\xb1+!\xaa\x14\xe1(\x02\xe1\x8f\x03\xb4\xdb\xf7OD\xea \x91;<\x15\xf6e\x8f\xdc\xe1^sz\xeeT&\xac\x842a\xc5{|\xcd\x02Q\xdd\xe6\x88\x05\xadP?K\xeb\xbf\xbb%\x0ci\xda\x89\x14KoM\xbd\x14K>8)\x1c\xfc\xbcHI\xc1,\n\xff\xa2\xe2\xf8\xf9\xd1\xba\xb4\xa9\x12\x06\"o\x93\x19o\x85~\xa2KQ\x18K\xf28\x10\xda\xd3\xea\xe7>|\x0d\x89r\xdcD\x1b\x910V\xb6\x93\x9fZDXu\xc9\xfe\xb5\xf9H\x15\x0bJk\x96}\x14\xf6Y\xf6\x92\xac\xc8\xe4\x98|\x0e\xc2\xcd)3\x19\xeeZ\xb8\x86\xb0?M\x93E\xc0;x\x1d\x8b|:\x1anr\xa2\x9b\xd7p\xb5\x8e\xb9\xba\x933:\\\xa0\xf1L\x95}c\xa10\xfe)%\x86\xe6\xdc\x1bkj\x0bND\x96J45(/\xb5X3\xabm\xa6B\x80\x18Qi\x19\x0e\xf7F]\x8b\x9d\x0b\xd5\x9eXG9\n\x91j\xdd:\x081?\xe9L\x1f+\x12Z\xb5\x10\xcbB)\xb2\x19+\xc9\xb0\xf1=\xb9\xfc\x9e(\xca!|\xc3%\xe5\xc8\xcc\x9c\x0c\x07\xe3kt\x7f\xf7\xcc\xbc\xfc\xa6\xc3\xeb\x04\xdd\x954\xaf\x93\x93eA^\x92U\x01U)\x0bE\xf1\xdaI|m\x9d\xbe\xb7\xd0tc\x8f\x9b7\xff\xec\xafm\xfe\xd5_\xdb\xfc\xc7\x8e8\xb6\x7f0W\x8aXV\x1bA\xbd{~\x83o\xf1.\xafN\xad9CR\xe6\x08\x8b9\xaa\xe2%\x9d\x0d\x9d\x97e\x92\xe5G\xb2\xfe\x19\xfa^9\x15b\xfe\x83\x05}7\xc9n\x02\x0b#\x12\x99*\x8a\xf09\xcd\xe2\xa2\xd3\x0d\x15\xf4\x8e\x12:N\x97\x13R4\xab\xda\x97-\xaa\x176kv\x16\xdb[\x1c\xc7\xe3\x19yO\x8a%\x86Q\x12\x1aaE3\xe9Q\xf8\x91\xe2\xe3Z\xd9.W\x04\x93\x12C\xcc\xce\x14P\xa7P\xadzV\x9e\x8c\xa1\xf4:\x14\xbc\xa1]\x1da-v\xa5y\xa7n:?\xa1\xef\xe5\x07\xc1\x9b.\xa9^i7UW\xa2]\xbb\x98\xaeXx?'Vu)\xbbf\xee,_\xab.\xe4RHg\x1d[uU\xfb\x0c\xdd\\\x87\xbb\x1d\xd9\x90\x00\xc3:\xd5\xbb\xda\x87{\xa3H\xfb\xbb\xe5^\xd8\xbc\xdcfQ+\x19Q\x97-\x8b\xb9\x1f>\xf2\x95\xc2\x15\xfe\x9d\xcbLp\x00\xbf[\x11\xa9v\xd3F{?ws\xba\x9d\x148o\x12\xdd|s\xd2b\xa7\x01y3\xa4\xd3\xa7\xa82\xc6\x81bbz7\xc5\xadj\xa6d\x18&\x8c\xbe\xf6\xa2\xc4Nn\x14\xedp@N\x02\xe43\xbck\x13\xa0\xac\xc3\xd9\xa6N\x83\xf2\xa0\x9a\x91\xfaXZ\x04mD)\xeb\x98\xb2\x99(\xf9\xcc\xb9\x86\xc3o:\xeb*o@i\x94\xf8\x9atR\x19t\xb4\x93\x04F\xc9\xaf\xf6\xb7\xcf\xa5OZ&h\x83\xdbE\x05}\x13\x9c4H\xc9\xef\x1cZ\xcbHC\xb6\x18)\xd0\x92\xe3\x9bq\x01\xc0\xa2NhUE\xb4\xec\xf1\xef\xbb=\xd7\xdc\x1b\x9c\xea,\x16m\xeev\xba s\xe4\xe2\xb2\x88`\x7f\xd02\xe7\xcd \xa9S\xe0\xa3y\x06\xa0sW\x1b\x8c\x13\xf4\xbd(\xa4D\xdb\x961pW\xa8Yj\x90-W:\xc1\xb2'\xd4\x04\xc8\xbc\x8f;{\xb0cHa\x0d\x92{h\xd2X+WP\xa7\xb1\xb5\xc6--_\x8f\x8d\xeb\xe0\x0e\xa9\x81\x97\xa3\xe6\xe8\x90\xff8\x0f\xd7Q\x8c\xe4*\x82-\x1b\xec\xcc\xb1E\xae\x19\x19\xcfx{\x0f^[\xfe\x0f_\x95_\xc7\xc9\x8e\x9b1k\xa2\x9a\x15\x8f\xcf\xcbD\xbd~\xc7o\x86\xc7\xd4\x8a\xf7\xb2\xb5U\x11\xc4\xccq\xfaf\x7f-;P\x8e\xa7\xcd\x0bH[\xbb\xa1\xb4P(t\x98\x0e\xa6\xc0\xe5My\xae\xc5 \xd8\xcf\x98\xa5\xb9*/t#|\xe2p\xeb\x05%5\xe8|\x02~P%R\xdc\xde\x8e \xe3\x0d\xe5\x12\x02hn\xb6\xe7\xf9\xe4Sm\xfa\x84\x81Z<7\x1f\xe1\x03\xa6&\x1f\x918*/v\x03m\x036\xc3\xd3\xf9S\xe1\\\xdc\xc9\x8d\x80\n\xca\xa8s$\x89\xfb\x0be\x08K|\xb8\x12\x906\xb1b\xb8\xeb\xb0\x9a\xa9\x0b\xb3Y\x1a\x13\x83\xeaW\x1d_\xc6h*\xd4r\x02}\xc6\x8a\x882\xb7:\"\xcf\xd8\xcap\x82U\xf01\xf3;~\xb6\x81'\xbe\xc4\x8fX\"N\xf9\x0c7r#\xe2B\xc4\x1e\xdcF\x1f\x1c\x0cDD\x9f\x1c\xf9\xfe[Y\xc1,\xeb\xcc\x9b\xc4\xd1\xe6\x9d\xa8cf\xb7'|@\ni \xc8\xe1\x04\x0c\x12X\xaf!\xe6\x7f\xc5e\x8f\x1c&}\x96 \x15\xbav\x10\x07a\x05)\xf3\xa0\xa4\x93w\x0c;&\xcc,`0\x10\x9e~\x01\xdfl\x85tD\xda\x85\x03c\xa5\x89s\xe9\xd5\xe8>vR\xc5bV\xe1\x06K\xac\xac\xa5\x8c\xa1\xcb\xca\x80\x18\xc1\x16\x9eR\x992\x8b-\xcb4>A\xda<+<\x8ea\x99\xe1\x86\xc9p\xd3*)\x10\x93E\x15\x15\x93\xb6\xcd\xe9$\xa6\x9b1\xf8\xb1\x85\x11\xa4_\xa6\xa7\xca\x9c\xe09\x96!\xda\xa4\xc2\xbcf!F\x11\xb4\xdd\xe5\xaf\xf45\xbe\x9e\xb2N\xda\xf4x\xff^K\xe4\xd6\xd3)\xb4\xd1Zm\xab\xf8\xec\xeb\xe3\xb1\xbc7|\x96\xaa\xb5z\x10B\xd6yZrxmo\x17\xf0HC\xf9\xae\x93\xd8+\xfa\x1d\xba\"\xe0\xf9u\xe5V\x13\x10T\x13tM\xa1\xe4\xaa1 \x96\xd2\xe2\x11\x0c\xb0g\x91\xa8\xa3\x13\xc9'\xcfU\x92\\\xf4\xc6\xd05\x95\x9b(\x08\xeaXk;0\x7f\xf2=0\xddd\xfb\x86x`;\x19K|\xf6\x08 \x1c.\xef\xe72\xc8\xc2E\xa7\xba\x11\xdd\xc1i\xa7\x9d\xa4J\xa4\xe4\xc6\xd3\xb2\xc9u\xa7aE\xb5\x8a\x16\xdb]\xb8\xd9\xee0\x02C\xa0\xe5\xcd\xf0\xdc7\xb0,Y\xee\xb3.\x9b0\xf7_~\xdel@\xb0p\x93\xe3\"\x19\x12\xb5\xabk\x92uP\xa4De\x1d\\JZ\x11\xd6Y\x7f\xa4\x0cY\x832d\x918\xc2\xb2.\xba\xd0-7L+\xabG\x07\x8f\xcf1\x04+\xf9\x8d\xf1/\xde\x81\xe0\xf2\x8a\x1a\xde\x8ee<\x93\x83\xbd\x87\x8bY\x92\x12\xb0:\xe5\x81\xae\x0e@\xdb\x95>\xf3\x04\xfb\xd8\x88\xe6\xf9 ?\xde\x88\xe1\xe3\x8b-\x01\x0e\xfcE:e\xa9s$\x07P\xce\x86\x04E\x07\xed9WUC\xac[\x99_\x85\x89\xb2e\x1d\n\x04\xd0\xb8\xe7-\xf4\xbcJ\xe1!\x16\xac\xb9\x05q\x80U\xfb\x90(\xa7\x18\xa8\x0d\x07*M7R\x04*\xcb\x01$()\x86\xa5$\xb1\xb5\x8b\xc59\xedxeW\x95\xf3\x85\xe5_\xb7K(\xfd\x15\xa6\x8c\xdc.\xae\x81\\\xc5aG\xa1\xf3\x1b\xa3R\x92\xadJ\xbc\x94\x14\xc4\xcbd\x02\xea\xdc\x92\xa9\xe672\xcf\xa6\xbe\xf4\x06d/\xb9\xa4\x00\xa5\xfb\xf5po\xc4%T\xd4\x10\x06K\x15O\x81\xd8\xc5\x8f\xd18H\xab#\x93\x96\x84#\x8f\xc4\xf9\x99v\x93E~-\x85sn\"K\xa3\xa5\xad\xe5u\xb6\xa0\\\xb4\x90\xac\xa3g\x97\x1di\xbb(`\xd7\xaa\xdd C\xbb\x01E\xf533\xfd\xec\xa4\xa8\xc2#\x13]@M\xf2\x8b\"\xb8Kk\xda\xe8\xccN-\xc5\x9eT\xda\x8d\x9a\x83 \xeb(\xe2$\xe1>\xccq\xe4\x99(\xbdx\x08\xe2C\xe9^\xc6\xac\xee\x83e\x96i\xeb\x11\x91\xf4\x8b,g~\xd2\xacb\xa2\x022\xbc3\x8a\x80\x0e\xef\x8c\x10\xcb\xc9p\x7f\x04;@\x87\xfb\x86\x0c\xc1aU\x90\xbc\x91\x95\xc1j\xb1I\x86l\xa4v\xd2\x00\xf6\xdbm6+\xf4\xb9\x1a\xe2\xa0\x1f\xee\x99\x06&8\xd7_e\x8d\x0f\xe1\xd6\xfdR\xfc\xfa!h(\x04m8\xf5\xc2\x89S\xc2\xdfE\xc3+\x0f\xbb\xd1\x17\xe2 \x1fJ\x89\x1bV\xbc\xc8\xc9d9\xde@\x87![\xff\x15=+\x05;G\xd1\x87S(*,\xf9\xf2\xdd\xb6\x0c\xd4\x8a\xe5&\xdfWG@\xca&\x03\xaf\x0f:\x12\x89\xf9\xcc\xc3\xf5\xf4|\xff\xd5\x8b'\x13\xf5s\xec[N%\x8f\xbfu\x0b\xa8\xa6\xbf\xad\x85M\xae\xd7U4\x82\xf8\x05[\x03\xde\xedz-b[\xbd\xc6\xfb\xb2\x8a\xbf\xf8\x02\xa1Y\xea:\xf91OH\x90\xfbz8\x97k\xd6\xf2\xb3\x04\x81\x84\xf3\x84\x06u\xcb\x14\x0c\xfc\xf6u3\x0b\x9f\xf0\xf3\xac\xce\xc4\xdfE\xbcv&Bx\xb6T\xfd\x0bM\xa2\x81Z\xfa=i\xa9\x10\xe4\x95\xd9\x92\xf0\x81\x06\x94\xf6|\xba\x05Y\xe2\xc1\xb9\xe5\x9e\xc0U\x97\x022_\x1f~2\xc1O\x01\x86\xb0W>\x97\x1c\xdf\x1d\x07\xfe\xf5\xf5m\x1e\xec\xff\x06\x9c!\xaef\xa7\x00\x86\xba \\\xce\xe4\x9a\x80\x92X\xe0\x02\x88H@\xd2/\xb29\xb9N\x07\x1c\xbd\x1c\xcd\xcb\xfaR\xffFFJ\xe5\xc7\x8c\x11\xbb\xa5\xb3\xaf,Gq](\xe2\x00]\xb3\xbcy\x81\xf8\x87\xce\\\x08\xc2\xc4\"jr\x90\xfe8\xa3\x05\xcb\x97c\xd4,\xfb\xd1\xf7\xaf,\x8e\xdeI\x99\xcdFD a\x89\x116\xcb\xb3\x0bD\xf1\x0f\xab\x059\xca\xf3,\x0fzG\x97\x0b2fd\x02\xc3\x97\x11\xfc4\x02\xb6\\\xa4\xe4\x00z\xb0\xdd\xcaHk\x19\xc3?\xdd\xd1U\xaf\x88\x8cG\x08#x\xea\x1b`\xf5\x8b\xbb\xcd\xa5\x00[^\xb1A\x19\x17x\xbd\x9a\xfe\x87\xbb\xe9z\xc4V {\xfaUc\xb88\xb7\x15j\x81\\^\xbd\x12\x8f\xea\x1c\x9c\x14\xd7\\zT\xee\xf6\xd6\x13\xb41\xce\x9aY\xdd\xf1-\xe9\xa4/\xf3\xac\xbf\xd0\xb3\xcbW\xdf\x0bm\x13k\xa7.\xb5\x8c\x9eu\xe6\xba'\xf0Hf\xa3<\x10\xc5>\xe0\x10v\xf8\x0f\xbfs\x9fZ\xb6\xf2\xb9\xf4E\xfb\xc9x\xe0\xa3\x14m\xe7\xa5\xf9\xd3\x9f=0\x1f\x8f\xc0\xd3\x94@\x96\x03\x06E\xef\xa4\xc9\xa7r\x0f\x98I\xbc\x18\x14\x1f\xb5\x81@X\x97\xd9\x0b\x16yG\xe2d\xc1A\x94$\xd0\x99SLX\xb0\x13Z\xb0\x98\x8eI6\xd5*\x9e;\x9c\"\x10r\x88\x1e\xf5Ok\xc9>\xf3\xc0\xa6z.\x9bpr\xe8\xfc\xa2\xa8\x96\xea\xd6\xb2\xc6U(\xe5'\xb2*\xac~\x89\xea\xda\xf2\xe3\xca\xf4\x8b\xe5+\x8f\xb7\xf8\xc5\x8c\x11\xae^\x9d\xa8K\xceeB\xa6 %\xef\xf2lAr\xb6\x92\x9c\xaf\x7f+\xfc:#L\x13-7\x19\x83\xbat\x12$\xc2&7j\xe2\xaa\xdb F\xbf\x8a\xdax;\x8fo\xd3uF\x1a\x89\x98#\xe8=\x8d)\xcd\x18o\x1d2\n1\x85\xa4L\xcf\x9b\x93q\x96O\xfa\xbd\x92d\x8ah;\x07\x8bi\xba\xba3\xb7\xa9\xcb\x12\x8d\xd0\xbc\xae\xfa\xa7 \x9d\x04U\xd4]\xf7gW0\x8e\xd9x\x06\x086\xf7\x80\xae\x02\xe5\x9a\xae\x8e\x88X\xea'\x90\xeb\xa7\xf1\x9c\x94\xa1\xc3\x9fD(^\x8c?&d\x1a/S\xf6\x13\xe7\x960\xe7\x8c\xb5\x1b\xfb\x00\xc4\xea\x88\x80\xc3\x8f\xa4\xa9\x98P\x97\x05q2\x94)\xcaS\xab\x15C\x9d\x99t]\xa5\xe4\xa7\xb1P\"\xda\xb1\xa9h\xd3\x7f\xb1\xe0\x1d\x8b\xe0#gL\xde\xdd\\\x95\xaew7Y\xa5\xebm>!9\x99\xbc\x8e\x17\xf0g/\x82\xdeU\xbbV\xd7\xbbk\xd4\xea:\xd7k\x04\xf0\x95\x125\xfc\xed\x90\xadyh\xc9b:\x18F\x8a\x1f\xd2PT\xa6m\xd5\xd0z\xf7o\xaenS\x96\x9d\xe1S\x92I\x95\"}\xb4\xb5{\xa1\xcc\x88\xe0\x1c\xf5f\x95\xbf~g\xae\xdaG\xef\xae_\xfbHo\xb8]\x06\xb5\xd6p-\xf5\xb8\x0f\xb0+\x90U\x9f\x06\xa8\xb8\xd1 \xa7?rv\xbf\x91nDGD+\xf2i\xa30\xd8\xd2\xba\xdc\xe8E\xbe\xb9\x80\xa1\x0e\x90\xa1\x05\xd6\x12\xde\xe57/\xbf\x12\x17\xed\xa1O\xf3l~DY\xbe\x12\xbaRM\xf9\xd3\x8d+\x9b\x15J\x10\xc2\xdf\xa0U%\xc1#\xbf6\xab\x11\x85Z\xb7V3BEH\xe4\x12\xd5?\xb2.+\xdf\xd5\xaf\x99t\xe5$\xfe\xd5\x16\xd4\xd1\xc2\xf4\x9d-\xf2^\x18$\x1a\x84dRh\x84t\x00\x1fX\x1d\xbe\xc3\x99\xaanP\x83zY\xe7\xc0\xb0o#`\xc1\x1b\x16\xc1\xafa\x04o\xaeA\x81\xdb\x82\x1fR`\x13&\xd4\x9ao\xc4\x0dt\x96K\x13m\x8b\xa2i\xce\x86Q?rL>oD3\xb0q\xf5e\x9b.\xbc\xa9\xc3\xcd+T\xe8\\\xab\xc8l\xc67\x0e\xdf\xef\x159\xdc2%\x1b\xac\x8dQ%\x1b@\xa3\x86\xf74A\xd7\x1d\x89y*+\x87=8\xfc*l\x05\x896\x80 0\xb7\x13;t\xb2h\x06\x02\xa7\x02\x9fk\x87\xcd\x06`\xc8\xaf\x03\x06\xda\x00\xc3<^\x18\xf0\x15$\x18Z\x85_\xde|\xd9\x19\x119B\x94\xda(\xa99\xe0\xd6&\xaf\x99\xf3<\x1c\x97I\xc0l1KW\x9c@\xa9|\xcb\xff\x14\xeb\x10\x8a,=e\x0fV\xd5y\xd9|\x16\xc9|\xcd\x14\x0eD1 SWa'Q\xd8\xechB\x1b\x9f\x0e\x96\xd0\x01Au<\x99\x8f\x0bZ\xd7=\xb5\x0c\x1aV\xd4m\x82\xcd\xba\xa8\x9e\nye\x19\xa2N\xef\x8bRL@\x83\x8aP\x1a\xa2\xa2Y\xac\x02\x16\xc4G\xbf\xb0\xd2\xbcbZ\x0e\xd7RT' \x0b\xde\xb3\x08^\x86\x11\xbc\xd7\x97\xca\x14\x08\xe8I\xc4\xcbh\xc06%\x7f\xffe\x9b\xab\x93\xd2\xd8\xd7\xc7\xb8\xe9\xbcy3\xdca\x08r_\x96\xcc8S?\xbc\xff\"\x84\xbd\x11\x0ce\xbe\x18\xca\x14\x862\x85\xa1\xa2\xda\x96\xc2K\xaf\x9aa,x\xc6\"\xf8!\x8c\xe0\xd9\x97s\x10\x0e\xe4{v#\xc8\xf7Wb\x18\xf3\xc7/\xe3dn\x0c\xbf\xfe\xc3HT\xe1\xcf\x86\x88\xf4Jr\xba\xaft\xe8\x10)\xcct\xf1\x10\xedu\x94,D\xb3\x9fW\xff\x95\x88\x84\xc7\xa5\xed!\xbf\xbeb\x81\xb5\x88\x9e\xe6d\x11;\xdf*\xd1\x15K\xf4\xa30 \xaa\x12\xa3\xd8Z\xdd\xdc\x157-R,\xbf\xdaz9#\xa2\x1b\x81\xfd_\x83\xe8\x1e\x91\xa1~{\x01\xca\xf0\xca\x9a[\xb8\xa3\xa2\x86Z/\xd6\xe5e\x89\xde\x95\xae\x11\x82@\x0eS\x18\xa0~)\xde%\xee|S\x0e\x1e\xf7r\x06\x87\"\x91\x8b@\x89\x1cQ\xa2\xba\xb9'n\xee\xb5\xf3\xe5\xeb\x97\xc5e\xd1\x83&\xd4\xce\xe1z\x1a\x827\xf6G\xcf\xec\x8f^\xd9\x1fa\x8e\xaa \xa7\x11\x9c\x10.ZP\xed\xcd/T\xb0.\xa9\xe4A\xb7\xa1g\xd5\xb0\xd6:\xdc\xf8\xf8\xaci\xd4\xf9\xe7o/he\xf2qw\xe6\xa9L\x10v\xd0YY\x1d\xdd\x85\xe6\xf5\xcd[\x1b\xdc\x90\x18\xe2\x94ks\xe1\xe2\xeba\xf5\xb7\xd2Y\x18b6\x9b3\xf1R\xfeV\x92\x89Qe%\xfa\xbfuK\x1b@M\x9fk\x9eli\x1f\xd7l\x03v\x9dT\xff\x84\xcc\x17l\x85br\xf9c\x001\x95\xa2\xf6/\xa4\x9d\xf2\xb41UO\x8dq{\xd1*+\xb5\xb0P\xffM\xb3j-\xe9'\x9a]P\xf8DV\xd0\xfb\x1bl\x03\x81m\xf8[\x0f2\n\xfc\x97\xc2c\x8b\x91\xbc\x06\xbd\xad\n|\xb2\x98~Y\x8b\xc3\x8c\x14\x1ez\xc3\x9a1\xa1\xbeD\x85\xd2ku\xe0V\xad,\x846\x9a\n\xe7\xe0\xa0Z\x87v\x1d\xe6\xda\x1ax*\xd7\xed\x1b\xc7OCZ\x9f\xa9\xccS\xea\xca\xac\xd8\x9a)\xeb\x9ci\xfb\xe8\xae\xcd\xf4\x86\xb4\xfd\xce>\xae\xcf\x1eX!\x91\x07\x06\\k:jZ:\x00])e1Y_uk\xd8\x8dS\xbc9v\xf3\xdf8C\xe25\xc1\xff\x84 \xa1\xbeA62\x0dT\x1b@\x06\x0d\xf8\x1a\x04\x1ap\xa8w\x82\xcc\x16z\xd7j\xc0\xb1\x15\xa8\x8c\xc5\nuxO\xd7\xed\xd3\xf2\xd7\x19a\xefT\xf3o\xa7\x9c\xb4\xd8\x11E\x1b\x7f\xde\xcc\xe4\xed\x17(\xb2\xec(\x99--\xfe\xebu\xdd\xcb\xb0\xaf\xee\xf6\xde\xa3\x93D\xcf\xab\xb3\xc2\xdd\x993'\xfd9E\xff\xde\x94\xcacgk\x1c\x94\xc9\xe9\xf9\xb3k'\xa7O\xae\x9d\x9c\xde\xc5\xc1\x97\x92t<\x99\xd8\x8b\x11\x18\xb6\xa6\x17 S7 \xb7\x82-\x04\xe1\x16\x19N\x9b9\xa4\xeb,zF+[UFK\x0bUy\x1b\xeb`\x97\x0f\xda\xe5\xb73*Jdk\xd5\xb2\xab\x9b?'\x18\xd4\xa2\x1e\xf0\x9f\xd5\xc3V\xf9m\xf5\xe0\x19!\x8bF\xf1\xed\xfa\xc3F\xb3\xeaV\xfd%c\x01\xef\x8c\x1aJ\x8dg\xd4XA\xbc\xbc\xdd\xae \x9eQ\x8f:\xe0\x19\xed\xdb\xeb\x80\xe3CW\x1dp\x16\x144\x82#\x8ey\x05\xbd1\x07\x93\x82\xa2-Yf\xd0\xf6\x96D\x02Nq\xfb\x9f\x88\xb0?\x9bZ\xbd1\xa9\xaawL\x98U\x9a*\xbeH\x9a\xaa\xb8Vg\xbb\xf1d\xe2\xdb\xee\xa4\xc0\x9aq\xac\xac\xbcC\xb7\xb7CH\x026\xa4\xa3\xb0}\xec85\x8a\xe5\xb1\xcd\x8f\x1d\x8b\xfa\xc6x\xec(\x07\xa9Z$\xc1p\xb7yx4\x96>\xa1\x8c\xe4\x05\x19\xb3\x9b]\xfe*\xa3\x12\xf3\xab\xbd.0\xc4/\xbeC6\x94\x98NeS\x18\x9f\x17\xcb~-,0\xf0\x14N\xbfg\xd6'\xe7$_y\xb4\xac\xae\x12\x1dJ#\x8cE\xf5\x0b\x02 \x90\xcd\x93\xa4\xc5\xa6$\xeefZ\x1aHR,OY\x1e\xff\x7f8\xf2o\xc2\x91\xeb\xc6ry\xa2\x08&\xb2\xbai\x14Q<\xa4\xcf1\x85`\xc43G\xab\xe5\x10\x81\x93\xebi\xf4$9H7I=/K\xaf6\xd1q\xafCM\xd3\x1e\\[\xe7T\xdf!Y\xce|y\x819\x0d~.\xbdw:Nf\xde\xee\x93\x95\x8f^\xc2\xd08\xebn\xff/\xd2 \x15\x7f\xadz\x85iZ\x85\xb61\xcf#3t\x90c\xcc\xb9\xafa\xd88\x1d?\x85Xk\xc4\x9b\xea\x80L\xf9\xb0;\xd5[\xc5\x7f^\xfb\xb3\x99\xc2G\xf65\x8f?\x91\xe0\x0bu>8\xfb\xa48FM|J\xdb*\xa01\x8d`\xcaq\xac\xf7\xf7\xbf\x9f\x9c<\x7f\xfd\xfa\xe3\x87\xc7O^\x1d\x9d\x1c\x1f}89\xf9\xfb\xdf{mG\x90\x05\x7f\xbb\xf0P\x1aM:\x11\x81X\xaa5\xb1f\xb5&\x05\x05U([j\x88\xb1\x1c\x9c<4\xa5w<\xae\xf0|\xc1V\"|\xba\x04\xa3\x9f\"b\xd6\xbd\x17\xebJ\xae\x85#\x08\xa3\xcaf\xdf(_G\xd5\xb4\x88\xc8\xea]\xad)\xf3M\xc2}\xee\xa4Kc\xcc;\x10\x8c\xf9xg40\x99j,\xed\xce\xbf@\xa5u!TZg\xb4\xd2d]\xfc\xbfM\x93u\xe6\x86_\xa9\xee3\x14X\xd4\x7f-\xe8pJ\x95\x03\xddBSj-*\xa5\xd6\xa2\xae`R?\xeb\x0f$k\xb0\xa0\xba\xcej\xe1\xa3\xf0Y\xb8\x14>\x8b.\x85\xcf\x82\xaa}\x08\x038\xa7\xf2\x06\xdf\x8a\x88\x92\x11\xb0`N9q\n#\x98\xdf\x9cFh\xfe\x97h\x84\xe67\xa9\x11\x92\xfe\xf7.\xc5\xd0\x9cV~\xfa\x82r\x9f\x19(\xf7\x8aFp\xca\xf7\xc9\xdc\x83\x16\x9flJ\xd8N\xffC\x84\xed\xc2 \xcd\x95 l+>\xde\x13\x1a<\xf7/\xbby\xf4\x05\x84\xed\xad l\x97\x1aa\xe3\xb7\xfaKZ\xcc\x92){\x9c\xa6\xbe\xd1\xfc\x97\xde\x8a\xee\xa7nE\xf7)\xad\x1clO\xf5\xbdvA\xe5\x0d\xb9\xd7Np\xaf\x1d\xd1\x08.8\xb5<\xba\xb9\xbdvt\x93\xbb\xe2\x98\xc5\xe3O0\xe4\x1bb\xd4\xde\x10G\xd7p\x05\xa9\x1b\xe3g$6\x14\xaaG\xbd\x15\xd1\x92r\x93\xf0\x81H\xbcNvv\x1e\x84\xf8\xbd\xf0\xaa\xb2\xef\x058\x04\x99\x84\xc6\x14\xf7W\x1b\xf9\x82\x90O\x1b\x01\x88\x8f\xba2\x1c\xf2_\x86\xec\x1d\xad^\x96\xc5\xac\xab\x97J\xdbP\xae\xaf\x9f\xd6\xa1\xd4\xf4\x95\xce$\xb8\xfb\xb7[\xedD\x1a\x03\xcc\x07\x1e!0\x9bo\xc1\x0e\xecq\x88?\x12j\xc3\x9d\x9d\x10?\xb3\xf1\x05\x98Y\xa5lcH-\xb9\x0f\xf9\x825\xd7\x82_\x86D\xcbu|\xb4\x04S\x96\x9c6\xae\x87\x16o\xd5\xac\x18*\xef\xd6\xcb\x9f3\xe9\xda\xff\x98\x9a\xc5\x93\xd6\xe2=\xe6\xa4\xc8C0\x91\xead\xb4u\x05$\x0c\x05G\xe4^\xbf*\x07I\x87\xd4\x82\x0c\xb8\x19\xba\x1d\x9b\xaa\xe4\xed\xcb\xf0\xa0\x0d84&\xb2\xe4\xd9P\x00*4pT\xa7\x10\xeb\xdfN\x9d\x0f-2\x8aw\xca\xc0X\xdb\xfa\xb3\xc6\xfa\xd3\xeb\xae\x7f\xdb\xfd\xba\xb5\xfeYge*\x1de\x8b4\x19\x93`\xcf\xdd\xa6<\xa66i\x97\xa3\xa1\xa7:\xca\xd4\x95\x0f\x067\xbb3\x9d\xa2\x8d\xd67\x9fF\xb6\xb8\xce,6\xb12}i|\xb6D\xa9\x06\x06m\x82W\x9c\x15q\x83\x8d#\x89\xcf\x91\xc9\x89\xca[\xe9\xe8Q\x0e\xd6\xc7\x15\x8cbq\x11\xa2\x7fe\xd6p\x7f\x08jM\xd7-TeG\x17\xa49\xfa*M\x8f5\xc6\xaf<\x99\xf2\xda\xc9\x84e\xce\xb2:\xc9\xe2\x07\xcd\x83\x10\xeff\xee\xd3\xdd\xbd\x88yc\x11\xb3k\xad\xdfcj\xaa0\xddX\xc3\xcd\xd4V\xa5.\xa9\xad\xb9\xaa\x10\x94\xe3\xeacZMH\x9f\xcc\x86a\xc8\xfa\xcc\xf6,z\xa8\xa3kkAe\xdc\x81\xbe$\xd5\xd1\xa2y~\xb9\x90\x82\x8a=\x977\x10!\xaf%\x13\xccU0\x08\xd5\x92 \xe27y\x07\x13\xe85Y?\x1d\xa9\xd7l3\xb3\x0e\xb1\x9a\xa9\xf1\xec\xcb\xfdNn\xcf\xc8\x84N\xaf\x7f\xc5O\xe4]\xf1\x03\xb2\xdf\n\xd0\x91\xf0\xec\x17\xcb`Q\xd1\x98g(Z\xead\x1e\xba\xb2\xf393\xf3\xf9D\x05\x1c\xa1\xd6\x15\x85\x9a\x01\\\x1a\xa4\xf7c\x1a\xc1S\x93\xde\xf5\xc3\xe3\xa7/-\x9a\xd7O\xfc\xfd#\x0fi\xffq\xe9\xae\xd7\x91?\xb4.\xf3\x7frf\x94\xa9\x98\xe1L\xe7\x84\xb3\xa6\xa3^V\xd1\xbf\\\xfc\xaaS\x07\xbf\x94\x81o\x9d\xa7\xee\xb1\xd0\x03\x1cs\x80<\xa6A\xcb=\xc5\xd2\xe8\xbbnq\xb1D{\xabYR;\x9c\x86\xa8\xa3cCjH\x84k\x85\xa4\x9e\xbe\x8bU\xbc1\x0d#\xa8\\&\xb5\xd0\x88\xe3\xd5\xfc4K\xb1B\x82\xeby\xb3\xadf}|\xfd\xd7':|Z\xaa\x17?\xf9h\x03?\xb9\xb4\x81\x9f\xba\xb4\x81\xbc\x0b\xdd\xb6\xf6D\xb7\xb5E@\xfb\xcf+\x02\xf91\xe2\xcbDM\xe9\xbfdJl\x8f4_\xafH\xe0bE@.8\x91\xb9qE\xa6\xed\xeah_\xaf\x8d6zh0\x06U\xbe\x07\x8b\xe9\xcdi\xdaV\xd8c\xa61\xad\x15\xc4\xbbm\x9a\xc0\xb2\xe7tB.\xc9\xe4\x98|\xf6\x00\x8cF\xe2\xdf\xcb\xa8s\xbf^^\x1c\xfb\xb7\x8e\xc01\xa6\xc2\xf6\xd1\xccc\x82\xdf\x9e\xfa\xa4\x07\x9c\x85Y-H6\xc5\xfc\xda/\x8eQ\xe7\xc8\xff\x10\x16\x1e\x0b\xf8P\xbb\xc4\xdf\xf1\x9d\xde\xdb7\xff-\x13|\xfb\xa6\x9c\xe2\xdb779\xc9\x97du\x0dAC\xf8\x13\xd8\xfa\xa4\x93F\x8f\x1eU\xa3\x10\x98\xfcS\xcc\x89\x1aX\xcc\x1b\xa0\xebI\x0f1\xa1\x89\xb9<\xb8aXB+\xb4\x19,j\xc8\x125W\x9c\xa1\x84\x8ay\xbbYh.Sc\x18\x08\xe7@|6o\xa3oRZR\x04=\x84C\xe8aE\x028\x80^\xd4\xb3c2\x83\x01\xf4\x0czTu} \xa6\xbbp\x9c\xcaR\xfd[{\xe8\xb2\xba-,%\xfc_t3\xdaR%\xa4\xb4I\xe1\x9a\x96^4x\xe6\xf4\xda\x9c%\xc8\x1d\xe0\xc5\xb7}\"\xab/ ?\xcf\xbdVt^\x93C=\xd0\xaa\xdcb\xf5\x94\x9d^\x9d\x89\xb3t\xc3\x0d\x16A\xe6\\\xe0\x06\xae\xb5\x1cT\x1e\xc2>\xe6G\xe4\x98\x02\x07b\xc3\xb6\xb6\x83\xae\x06\xc0\x9a\xb5\x0e\xe4\xc8\xe0\x10\x82LR9l.\x94\xed\x92\xb2\xf4\xad\xa8\x18\x988\x0b2\xe7\xfe {\x9f\x9c\xcd\xd8\x86pS\x84Ig\x84*C\x94\x9b>I\xaeG\x9a\xdes\xab\xdd\x1dl\x83\xc6^\xfcq\xb7D*=\x19\xaeWWh\\\xbe&\x06?\xb9\xde!\xc1\xb9\x91\xcdz\x14yYD\xac\xdc\x1b\x8a\xa5\xc2LY0L]\xe5^5&\x9a3\xb3\x06\xe4\x80\xb9\x1f\x94\xba\xbf\x80\xd6\xfc\xee\xd5\xcb\xe9\x92\xbd\x8a7Q\x0f\x88}\x8d\x1e2\xbb\x11\xec\xecy\xf5\x92\x14G\xf3\x05\xf3\xb11\xc8^4\"\xae\xcb\xe9M\xc9\xfd@.c\x9d\x19\xf5\xe0EmFH\xaf\xd9\x8c\xb3%m\xee\xfc\x8e\xf9<\x0dH\xa5J\x12\xdb^\n\xb0\xe2\xe3\x0d\xf4*\xd8\xfb\x13_\xf6T\xf6\xefK\xa5@\xa3T\x1fI\x10V\x06)W\x06<%\xe5\x98\x88w\x17\xeb\x8a\xdf\xcb\xbc AU\xa7\\T\x12\xe7\xbbR\xcfy\xec%\xb5i2\x97\x99\xddU\x97\xa3\x94\n\x9e\x05\xba\xb9\xcdR!\xefJ?o}V\x8f|^\xc6\xe9&\xc2\xd69)\xc9\x86W\xfb2k\xa6\xc7V\xd3\x1dN\xcdk\x8b\x81Z\xfd\x13L\x97W+\xceDHu\xdf\xcd)\xd6\xab\xb7\xfeN\xc3\x86\xaa\xd5\xcd'\xd6\xaa\x1at\xf9\x8e5>&\xc6<\xa0\xea\xba\xf2\xe4\xf7\xc4.}\x93m\xb8\xdf\xa5\xf8\x81;|\xa3\xd3\xa5\x14Y6\xe7,,\xd5\";xn\xea']V\xc2%m\n\x97\xbc\xefa\x16\x01\x1d9\x05L/\xd6\x8aO\xff%\xf1%n5o\xf4M\x84=T\x8dQc\xa9]\xf3\x98\x1agd\xc7\x8a\xe8 7\xb3z8\xda\xb2\x99MF\xb1!rx\x0e\xa5\x02\xdc\xa6\xe3\xf1_-\xcf\xa1\xbc$r\x05\xfdF\x91o\xcc\xbc \xe8\x1f\xfb5\x9f\xc6\xec\xf5\xb5\xa51\xdf5\x02m\x13\xffb\xae\x93\xa4\xae&m\xabk\xea\xbb6\xb2\xd6Bn8k]\xc7\xa1\xae\x895o\xf1\x8d%O\xd9\xe2\x06ga \xd9\x1f5)\xc1WD\xd0\x8f\x12\x7f\x8c\xe1\xa7\xdd\xab\x0d\xcc\x90\xf5\x82y\x1e\xd8R\xa1\xa4.\xef\xfa\x14\x1f\x9fa]m\x9b>5\xaa\xfcd}\x07\xfe\x9cz\x0e\xddTnZ\xf8\x03c\xa1MUa:\xabU\x98\xee\xcc\xb6\x9c`\\\x90GV\xe4\x00}\x1a\xb1Z:\xc6-\xa9\xa4\xc4I\x04+\xceJ\xafB\x14\x13V\x95\xbf\xa7\x19D\xaee\xf1:\xad\xce\xf2l\xb9\xf8w\xb0\xe2~6\xbc@f\xbb{\xc7P\xd5\xc5\xf9wO\x06\xde\xc8\xb9w\xe9\\\xf8\x95\xb59w\xfe\x99\xe0\xdc\xbb\xf7\xb5~I\xf0\x04\"\x04r\xbd\x86\xe1(\xc4\x18\x06\xccY>\x8c#HFp\x00\x89\x87q\xd0A\xc7\xec0P(\xe8G\x81\xb3:\xe5\xed4?U\x14\x8cD\x90\x04&\x12\xa9.\xcb\xf87\x165f\xf1&r\x06\xd2!\x99py%b\x08V\x9e\xbd<\xdf\x84\x86\xab~\x9e\xd3M{J\x8a\xe3\xe5\xa9g\x81\xcfR\x06\x1c\xd8|\xc2\xcaJ)\xc2\xea,y\xf4J'\xe4\xb7\xb4\xe5y\\&\xc6\xd9 \x9f\x96y\x8a\x0b\xce\x0bm2\xc9\xc05K 3m\x96ay\xd3\xffT\xfbDVo\xa7\x1b\x0c\xa9<\xd483\xb7\x11$o\xc0H(\"\xce\xfd\x8f\xf8\x9aV\x86\xef\xea\xe7-)\xd5\xa7\xdbts5Z\xab\xe4W\x1f\xf9Y\xff\xfe^^g],\xbc7\xae\xb11\x97U\xbb\xefy|\xb9A\xaf/\xd8F*\x8cy|\xb9\xe9\x99\xfa\xa2\x96\x8f\xc8\xab\x13?\xa3Yk\x06p\x08\xef\xa9pa\xf9\xe8'(\xcd\x13z\xfd\xe9\x88\xee\x98\xe8\xcewn9\xd9\x18\x13\x8d!\x8f`n\xbe\xf8\x94,6\x80\x9d\xd6\xfe\xeb\x98\xcd\xfa\xf3\xf82\xb0T$\xb6t\xd6\x14\xbe}\xa5\x04\xcb\x1e\xe3M\x06D\xbb\xe3=\x90\x9fgI\xba\xa1\x99\xa1\x1c\xccO\xd74l|J\x16\x1f)K\xd2\xcd\xba\x15@WC\xdeL\x05%\x12\x82m\xd6_\xdb\xcaa\xc8\x0c\x06\xe6\xfeX\xfc\x89l\xb0\xbc\xacf\x80\xb8\x06J\xf1\xfen\x18\xa5x\x93\x9b\xa3\x14\xff\xeaKP\xea:\x92\xc4?\xbc\xb8[\xad\x84\xd1G\x8aj\xdeZ\xf26\x8c\xac\xec`x\x15;\xcd\xac\xdaeuq\x91.\xab\xc7\xe6i\x05Zja \xd8\xb1\xbb\xb5sY\xcf\xbf\xa3\xec\x7f\xc9\xb8\x19\x04\x1f\x82*\x91e\xd7\x0c\xb5f*\xe9\xa7\xfc\xf6\xd6-\xd8\xde\x8eQH\x95\x0dZ\n\x95\xab\xeb*\x8c \xb6\xbeq\x15\x81^\x06\xe9\xbfhU\xb2|\x93e!5o,\xfe\x9d[\xae\xe5\xd7\xd2\xe1Q\xa2.9N\xcf(K\xfdB\xdf\xa9e9\xd3\xee\x0f\xc0?\xe2Q\xbf\x9c\xd1\x8f\xfae\x89\x95\xd0/e\xba\x89;\x8bS\xa9K\xe8\xf0kE\xaa<\x1c\x1aUD\xa3\xac\xdf\xeb7\xd1B:\xab\xfa\xbd\x9d\xe2\xdb{\x1d\xae\xad`\xdaki\x04\x05j<\x0f9i\x1b\x0c\xe0\x8d\x14s>s\x8c,\xf0\x05\x91\xe6o)=C\xfe\x0b\x16\xb7\x8b\x088)\x80\xf1\xe1\xe6\x9aW~\xf0\\\x97\xa9(\x0f\xad\xcd\x98\n\x15C\xb0!_\xba\xb9\x186\x8b\x8b\xd9\xd3l\xb2\x81\xa3\x0b\x9bU\xd9\x05\xb0\x8a\xf3L\xcf6\xd0\xcd#@\xb9\xbd\x84\x83\xf2`\x00{p\x1bv\xcb\x8d\xe6 ]\xcaL:\xeeT\xf0\xf9\xb9\xf2\xa36\x16\x0ea\xcf\\\xf5\xb6|M\x0c\xcck\xf1\x1b\xdf\xf0\xd1^\xa2\x90~\xe7\xee\x9d\xfd\xef\xf6\xbe\xbds\xefN\x18\x95\xb7\xe1\xe1C\xd8\xbb\x07k`\xf0\xe8\xd1#\xd8\xd9\xbb\x17\xc1\xdd\xfb{\xdf\xde\xbd\xf7\xdd\xee7\xcd\xf7\xeeh\xef\xdd\x89\xe0^\xf5\x1c\xd3\xb9\x07\x0c\xb6\xe1\xce\xb7\xf7\xef\xee\x7f\xb7\xbf\xf7\xdd}Xs\x98\xfe\x8bo\xe9\x7f\xc9\xcf\xf6\xeeG\xb0\xbf\x7f\xf7\xfe\xb7\xfb\xfb\xf7\xca\xe6\x8f\xe5\xe7\xd8M\xf9\xe6\x9d\x08\xee\xec\xdf\xbf\x7f\xf7\xdb\xef\xbe\xdb\xfd.\xd4\x9bpl\xb9@\xe7\x0f(\xd6\xba<\xdc\x10j0\x80;{\xf05\xe4\xb0\x0d\x9fi\xf0\x94\xe0\xa6yJ\x02\x16\x86|F\xf6\xce\xc1sw\xaaKh\xc5\xaf\xd1K}R>\xdd\x943\xc2\x8e:;\xd8\xacq\xcfvCc9k( \xa2\x89\x14\xd6\xee4\x95\xc1|/~\x10\xc9\xc9\xb4\\\x00\xfa\x1b\x1f\xe8p\xaa\x02\xbc?\xd0\xe1+\xfe\xf7\x07i\xb2(\xf8-\x19:*n\xcb\xc0\xea\xf2\xbe\x1e8\x04\x03xF\xf1IB\x8b\x85\xc8\x8d\x8f\x9f\x1cg\xcb\xbc\x9eW\xc6\x04\xb2\x86\x12I\xba\xb7\xd6g\x87\xad\x8fgqBE\xdb\xd2\x96)ng\x94\xc5 F\xa5\xe3\x10\x84\xee\x12c\xc4s\xd3)9M\x93\x0dB#K\x01\xe5#\xb3\xae\x84I\xed\xb38j\xb9\xf7\xfbZ\xff\xedT1\xb7\xcb\x02N\xe1n#\xc3j)M('\x89a\x12A6\xb2\x17\x9f\x06\x10FU\xcd&\xe9)4\xce\xe3\xc5\xcb\xba\x0f\xb2/\x8c\xae\x01\x04\xbe\xeeMXt\x89\x19-X\x88h\x04\x07\x10\xb0\x93\xeb\xec\xd6\xd7\x14\x93\x9btf\xeexn\x07\x92\xdaI\xf5\xbe,\xed\xfc\xde\xd9\xce\x90E@F^\x8d\xbd\xb1\x90\xc3\xe6\xd9\xdc\xb1\xd9\xb6\x88O2.h\xc3\xd32\xac\xf773\xac\x9d\x1b\x1e\xd63\xf7\xb0z\x05\xd2\xc0\x9a\xf1\x03\x0e\xe1\xc5\xf1\xdb7}\xf1(\x99\xae\x84\xdaVRK\xcf\xdc\xa2\xaf\x9c\x04\xf8\xd8\x9a\xc9\xd3\xd2\xdc\xc7N\x0c\"\xf0\xb0\xe4\xe0\x08<\xc2\xbfw\x90\x9d\xf3\xea\xe0\xb3G\x07\x9c\xf5\xd9\x86\xfd\xfb\xf7\xee\xde\xbds\xef\x9b\xfb\xdf\xc16\x04\x843d\xf7C\xf1\xe7\xa3G\xb0\xdf>}\xeb\x0b%[{M\x87\x0bu$\xbe\xae\x8eD\x19\xa8\xc5\xef5\xceD\x91^\xa0|\xd08\x14;\x89\x9a\xec\xb6\xb1\xb0\x0c\xa3o\x0f0\xfc\x161\xa5>p<\xd82s\xf2\x93/M\xdf\xe0\xa73\xbf\xd1\xc0\xa9=\xbf\x93b\x9a\xd0 JO\x9e\xdd~\x817\xdd!:\xd3\xc1\x01\xec\xb4\xfd\xffLfN>*?\xc3\xd5\xb9\x9e>S\x99\xa8\x9c\xa3\xd1\xd2\x0c\x97{\xc7\xcb\xd53\x8d\x0b\xf6\xfc\x9a#+\x8dq\x7f\xd9\xe8n\"~\xc3\x13qn2~\xc3\xb7\xcb\xc5\x06}*Dm\x86\x15\xd9\x9d\x98\xf9:U\x96\x02.u\x8a\xa0Z\xb1\x10\x98\xf6j_\xfe\x89\x15\x8c;\xb23\xf2\x8b\xa8\xec\x8c\x9c`\xef*\xe7~t\xce\xafRDt\x04\x85VI\x15\x959\xa3\x03{J0\xef\xc9\xd1\x1eB\x0e\x07\x90\xab\xd0\xfdc=\x02x_94\x88\xd61\xc7\x81gP\xb0r\xee\xfc\"\xf2Qz\xab\xfe\x15$\xe4:\x8e\x9f\xa2\x9a\xbdW\xeb7\xe4\x9a\xe8\x89\xfd\x1b;\x0d6\xd2k\x87\x88\x82\xaa\x14]]\x0b\xa5e^\xafG\xd3\xdc\xba%\xf8\x8b\x99\x96dU\xe1\xed\xb5\xfc\x11EUmKV\xa5M\xdd\x117s^j\xc1\xe3\xd1\x00v1\x07\x85%\x90\xc8\x02(d\xbefUt\xd1\xce^\xf5\xa5<\xb4Z\xd5\x14\xc1v\xc61\x92/\xb2b\x13\xd3\xe6\xf5\x93|\xf8\x99\xf5\xaa\x12\x03%\n\xec\xc3\xd7\xea\xd7\x0e\xec\x89\x02\x03\x0e\xcb\x9f-\xf5\xa1~)\xa3\x01s\xca\xe5\xeaJ\xbe\xd8V\xd79 \xad\x8d`+\xc1R\x00b]Eh)\x17\xd1\xb30\xd4\x92\x96b\xb3\xf2\xbe\xb3\xe5+\xde{\xe4\xca\xa3\xa1C\xd4l\xb6\xf3\x06i\x84\xb0\xaa\x19\xd0~\xc7\xfe;'\xefo\x0f\xbd\x86\xfd\xac\x84l\xc6!\x1b\xc3\xff\xe5\xb2\x03\xdfz\x1c\x07\x92\x9a\x0b0\xc6\xfc\x1e\x88w\xe0\x10>\xf3\xb9\xc7\"\x1d)Zm\xd4\xcfL\xa5\x8c\xed\x02\xbf\xd3ZbIU^Q \xefm\x9c\x92\xf8\xdc\x87\xf3Rf\xb9!\xefbd8\x94C\xc7bq\x1e\xe5\xa5 \x00J\xff\x12\xc1\xcb~6EgZ\xebg\"?\x89\xe6\x9d\xef}\\\xc3\xbf\x8e\x1f\xf8\x9e\x11\xaa7\xed\xde\xe3y\xf2\xffq-\xbd\xeaK\xf5\xc7+\x1a\xb9\x90\xcd{\x0c?'l\xe6sN)\x99G\xef\xc5\x8do\x9c\xa7S\x01\x02\xed\xf1\xdbL\x96\xb5;W!\xa7\x08Uz\xd8\x89\xd27\xe87\xcb\xba-\xef\xd0q\xbd=\xfc\x8dy,\xc4 Q\x0bZ\x9a\x95\xbd\xe4\xb4\xeb\xe6\xd31T\x9d\x86\x9b\xd9l\xd8|\x95\xc3\xcd\x03\xda\x89\x96g[\x94\xd0\xaeY \xf4\xc7\x9a%A\xbf]3)\xfc\x1a\xe9J\xda\x10\xef\xbd\xac-\x9f\xb8\xf7C\xadiq\xef\x84\x18>\xbe \x86\xaf\x8fH\xf3\xf36TT~\xb9\x03\xa0m\xb8\"P_\xb4\xef?\xcd\xd2\x94 \xa4\x0f\xe0\xd4\xe0\x03\x81\x01b\x1f\x0d\x0f\xf4\xb4\x92\xefX\xfb\xb9\xc8\xcb\xb70<\x91\xa9\x02\x8f\x8c\xa3d\x07P\x18\x1e\xe8Y%\xe7\x86\xe7\xef\xc98\xcb'\x07\x90\x9b\x9e\xc5\xf4\x8c\x1c\xc0\xca0\x89\xf7dAb\xde\xa4\xe1YR\x1c\xc0\xccp\x7f\x9agsLmkK\x97|\x15\x01\xe9\x93\xcbE\x96\xb3\x02\x93\xc4 \xac\xbcr\xfb\xb4\xf5\x96\x05\x81\x82\xe5\xc9\x98i\xf9i\x94 ]\xdbn\x9a\x0f\x8d\xdeQ\xb3u\x15\xfb\x16G\xb0\x8c\xa0hn$L\xc6\x1e\xb00\x82-\xe3\x1e\xe6]\xa7m\xfa\xa7\xa5\x01C=OX&L;\xca\xf3,\x0fz\xaf\x13\x9aL\x132\x01r9&\x0b> \xc8\xc6\xe3e\x9e\x93\xc9\x03\xe0\x93d3\x024\xa3;s\xf5\xe2\x84\x9c\x03\xa1\xe7I\x9eQNu1\x02\x8b\xbf4]\xa6)\x10\xde*\xccIQ\xc4g\x04b:\x81x2Ix\xb3q\n3\x92.\xa6\xcb\x14.\xe2\x9c&\xf4\xac\xe8\xf7\x0c\x14\x9b\xa4\x05q\x90\xfc1\xe7i\x9a\xc0r\xf8\xf7L\xed\xfcfP\x07\x05\xeb\xe7d\x91\xc6c\x12\xdc\xfe\xbf\xc5\xed\xb3\xa8\x9b\xa8AE\xd8\xc6\xc3\xe9\xf6v;\x84\x17\x90\x8a\x85a\x9f\xc6s\x0c\x8dxN\xcf\xe3<\x89)\x83\x9f\x92,\xc5\xe4\xdb\x86\xfc\x92\xad;l\x96g\x17\x90\xf6\xa7y<'\xc5\x87\xec\x1dV\x91\xd9k\xa6b\xd3\xb0\xfa\xcb\x91\x98\x06w\xee\x86f\xdc\xcd\xaf\xdf\xba#K\xa2L~>!\xd3\x84\x12\x95\xfc\x9c\x8bE\xbd\x93\x13R\xbc\xce&\xcb\x94\xf4L\xa4T:I5\\\x9e0\x8f\x12\xe7\xbb\x9ef\xf3yF\x8f.\x19\xa1\x85\xcc\x7f\x8e\xf7\x1bwH1\x8e\x17XS\xf1UB?\xbd\x8b\xb1\xae\xa2J\x9d\xdf\xba]\xcc\xe24\xcd.\x8e>/\xe3TV#d\xfd\xd3e\x92N\xbe\xcf\xf2\xf9\xb3\x98\xc5\xe2\xb5,g$\x97OY&o\x92<\x89\xd3\xe4\x0frL\xe2|,\xda[\xc4y\xa1\xff>#\xec8\x9e/Rr<\x9e\x91\xb9\xf8\xee\xaf\x17\xc7o\xdf\x88\x9d\xd1\xe9\x01\xc6\xf2U\x07\xb3\x8c\xb6*D5\xab\x8eF\xe8\xa8o\xdd\x82^\x86\xbd\xf6D\x11\xb2\x86\xb1\xa0\xb7\xa4b\x9fNzp\x00\\\x82*\xf8\xc6\x8d\x97)\x0b\x03\x16\x86\x8ex\xd7+\x18\xc7l<\x03q8\xb6\x1e\xcb\xef\x1a\xd9\x1b\xae\xf8^\x16\x03J\xa6\xabNH\xc8F\x8e\x05\xc3|$\xf9f-\xa9<\x1c4\xfb\xc6\x1e\xe2<\x8fW\x1bt@d\xb3\xe8]\xa3\xff-\xeaI\n+\xefp\xd4\xeeH\xb0%\x92O\xd2z\x03b\x0eM\xe3\xabr\x84\x1eT\n\xae\xe6\xb3\x9eAB\x0b\x16\xd31\xc9\xa6\xb0RK\xd2\xe7[\xd2\xf5i /\xc6\x01U\xcf\x86\x8b\xb7\xd2\xb2)\xce\xb8\xcb\xb4\xbc$\xec\x8b\x8c\xce8\xdb\xea\x95\x8a\xd9\xac\xde4\xd5Nd\x98`\xf0Cv\xcc<\x0b\x05)\x15\xa3)\x87\xbb\xd2\xfd\xecF\xb0\xacP\x91\xb4\xb3\xf3v [\xe6\xf0\xc5!3$\xe80\x14\xbe\xeb*\xc6N\x879\x17\x0f\xc90\x1f\x89\xf4\x8at\x99\xa6fMt+\x13&\x82\x8cf\xf9\x1c\x0f\x0f\x81s\x03\xb8\x8c\x90N|O}\x91\xd6<\xc1vOIQ\xd2\x9dc\xd9\xc7\x92\x8eo\xbe\x175\x11\xaff\x9b\x99\x9a\x8dT\xe2u\xbc\xf0A'+\xca4\x93\xfa\xba\xf4\xa2\xf5ue\x01_Y\xa1\x8a5\xe5\xee\x84?\xdb\xa5\x84p\xc8\xef\xb1\xcb\x7f\xdb\xa8K\xc5x9^\xa7\xee$s\x1e\x08Y\xd7\x81 U\xda\xfcn\\\xdd\xa5\x18r\xb1\x01\x98\x8aU\xc1\xc8\xfc\xc3lI?\xbdN&\x93\x94\\\xc49\xf1E\x9c\xee\xfd\xcf\xfa\x93\xa4X\xf0\xb3I2\x8eH\x97\x9cp\xe9n\xd4\xf4\xb2\xd3\x82\x05\x1d[\x08\xcd\x93\x01 0\x959\x0b,\xbel`\x14#\xccw\x0d\xe7\xa0\\#\x0e\x80e\xf14\x9btC\xf9\xbcL\xb2\xa5\xaal[I4+55\xc1\x05?[.\xf8D\xfc\x93\xa8+\xe0\xec\xf7Ty\xd4m\xe8\xf5Bc\x06\xa5\x10\x19pK0\xf3\x95\\f~\x82\xf9l<\x8c\xce\xa9N9\xa5\xc0\xe1\xbc\xa7\xfc3\xd0\x8a)V/\x8a\x13\xb2\x0d\x0eu\x9a\x11\x99\x83\xc0p\xec2\xce>\xb0\x91\x1d\x96\xf5^\xfaI\x81\x9dQ\x91\xf8\xfe\xa05\x88\xf6\xfcg\xc9\xd9,M\xcef\xdd\xdc\xa5Z\xe1I6Fu\xab\x99\x01\xd9\xaa\xf8\x8c\x9e!s\xaf\x08N`\xe4\x92=\xcd(#\x94\xa94\xac\x8f\xe0\x1e\xb9S\xc5\x03\xe9\xafX'\xdf\x8d+\xb5\xec0\xba\xd2@\xa4\x83\xab\xfa\x88\x90\x0b\xdf\x8dP=\xb2\x1c\xee\x8e\"\xd44\xecE\xa8@ \xfd\x84R\x92\xff\xf8\xe1\xf5+\x91q\x18\x16\xa8V\x10r\xb2\xa8g\xbb\x80\x87\xf0\x0d\x92\xc9\xdf~\xc3\xfdJ\xa5\xe7\xdc\xd8\x99m\x86\x03\x84\xf7\x94\xaa\xae\xb7\xb7\x8b\x910\xafM+\xd8\xecE\xb05\x86\xf5\x1a\x16\xf0\x08\xbe\x15\xbd\x08\xaa\x80w\x87\xb7\x7f;\xbe\xddg\xa4`\xc18\x8c\xf8\xdb\xfc\x83\xdb\xc3\xaf~\xbb\x18i\xf7\x83\xdem9\xb2\xf5\xbal\x80\"iN\"\xf8[\xefo\xa0\xdcN\x92\x08z\x7f\xeb\xe9?\x97\xc3\x02v\xe0\xee\x08\xb6\xd1)\x9e\xf2g\xbd\x9d\x9d\xdf.\xefp\x99\xbc\xba\xf5\xf5\xed\xdeh\xb8\x18\xb9\x8de\xb8,SQ\x98\xa1\x1f/\x16\x84N\x9e\xce\x92t\x12\xc4\x9a\xc8}\x94\x12\x8efA\xafX\xc4\xb4\x17\x86\xfd\x82\xb0\xc7\x8c\xe5\xc9\xe9\x92\x91\xa0W\xb0\x15\xaa\x03\x86\xbdq\x96f\xf9\x01\xfc\x9f{\xf7\xee=\x80iF\xd9\xce\x05\x11 qO\xb3t\xf2\xa0\x17\xe1\x8a\xe1\x7f\xfa\xabxo4\\\xc0!\xae\xdd\x1d8\x84}8@\x08\xdf\x87C\xb8+\xff\xe6\xf7\xef\xc0\x01l\xdf\xfeW\x10\x07\xa7\x05\xcb\xe31[\xa7I\\\xac\xe9d\xadL\x0fk\xbeg\xd7E0_\x17$g\xe1\xe1z\xc9\xb2p}\x1a\xc4\x05Y\x93\xb3\x84\xae\xb3,\x0dHL\xc3\xc3uN\xe2O\xeb\x15#\xe1z\x8c\x8f\xf9\x81\xb3\x9e\xc5\xf9\x1aE\xdb\xc9:\x8d\x8bb\x9df\x94\xac\xb3\xf9\"]g\xb4`\xeb\x8c\xb2\x84.I\xb8\x9e\x90\xe0tyvF\xf2\xf58\x99\xc7\xe9z\x9c\xc69YO\x03\xbe\xc7\xd7$\x0f\x0f\xd7 M\xd8:\x0d\xc8Y\xcc\xc8\x9a0\x12\x1e\x86\xebI\xb6\x9ed\xcb\xd3\x94\xacI0\x9ee\xeb\xb48L\xa6\xeb\xb4 A2\x0d\x0f\xf9<\xb0\xf6\xe8\x9a.\xe7\xebsB\xd9\xfa2\x18\x93\x05[\x93\xf1z\x11\xa4\xc98a\xeb,g\xe1\x9a\x91\x80N\x8a5*M\xd69\x0d\xc3\x90w\x9d\xa6l\x96g\xcb\xb3\xd9:N\x0b\xb2Nh\x9c\x06\xe9\x8a\x0f\xe5\x92O'\x8b\xf9\xd7\x01\x89\xc73>\xfb\x84p\xb0e\xf3\xf5\x92\x8e\x03\xbe{\xf9\x00\xcf\xd2\xec4N\xd7g\x19\xcb\xd6g\xcb8\x9f\xac\x93`\xba\x9e/\x02\x81\x03\xc5Z\x1b\x04\x0d\x12\xb6F\x95~p\x92\xd11 \x0f\xd7i\xc2\xa1\xb5dk%\xfa\xacY@\xf2i<&k\x92\xd38\x0d\x0f\xc3\xc3u\x11\xae\xd3 \x9e\x9fN\xe25a\xebl\xfci\x9d\xd1\xb3p=\x0f\x92q\x9e! \\\xa3\x8ai-\xd4\x08\xe1\xfaM\xfcfM\x83xN\x8a\x05o)f\xc99Y\x93K\xb6&\x17\xeb$]gl\xbdL\xd3p\x9d\x05\xc8\x16\xad\x17\xc2\x10\xbe\xce\xd7K\xb6>'y\x9eLH\xb8^\x04\xf1\xf8S|F\xd6q\x1e\xcf\x8bu\x9e\x9c\xf3u\xc93F\xc6\x8cp@\xb0l\x9c\xa5\xeb\xe5i\x9a\x8c\xc3u\x1e\xc4 \xc7\x98 \x9ed4]\xf1\x85\x9b\xae\xcf\x92\x82\x91|\xbd 1[\x7f^&y5\xefb\xbc$k\xa1b[\xb3|\xb5\xe6T1\x0c\xd7Ep\xba\xe2\x8b\x1f\xa7d\xb2&\xe9t=\xcbr\xb6N\xce(\x99\xac\x93?\x10<1K\xc6kT\xe7\xacY\xbe\x1c\xb3\xf5\xf2\xb4\x18\xe7\xc9\x82\xad\x97\x0b\x92\xafWt<\xcb3\x9a\xfcA&\xeb\x8b\x84\x8dg!\x87\xe8|\x91\xf2\xc1\xcf\x08]\xcf\x92b=\xcb\xb3\x8b\xe2p\x9d\xc7\xb4H8\xd2\xe4K\xb2\xceW\xeb\xd5\x82\x041\xee\x8f \x99\xae\x93\xc9\x9a\xc6s\xb2\xce\xa6a\xb8^\x064\x18K4\x9f\x90i\xc0\xd9E\x8e'\x19]\xa7\xa4(\xd6\x85\x18#K\xd2p]\x90u\x91\xf0\x05:\x0f\xe2|\x9d\xe4l\x19\xa7\xeb,\x99\xacQm\xca\xd7\xe7\"\x18\xcf\xe2\xfc\x84\x89\x01\x91\x9c\xacgIJ\xd6 \x9b\x85\xeb\xcb,_\xaf\x12\x92N\xc2\xaf$\x01\x9cr~iw\x14r\x16T'9\x8a\xdc| \x97\xecM6!\xc14\x0cC\x91Al\xc1)\x94\xa0\xeb\x9cF\x1c\xf0\xf3c\xaa\x1d\x00{{\x0f`k\xb8\x17\xc1\xed\xe1o\xb7\xff\xbc\x1a\x06\xbf\xedl\x7f=x\xf8\xe8\xe0\xc1\xfa\xb7\xdf\xfa\xd1\xe1\xd6\xad\xbf\xff\xfft\xfa{{\xf8\xdb(\xac\xdfhPhI\xa0\xc7\xbc\xe3\x0cS\x93sR\xff\xb0\x07[x\xceH\x12=.\xa9\xf3\x98\x1fS\xdb\x90\xc26\x12\xe8m\xd8\x1b\x95\x7f\xee\x8f\x90 \xffvyg\xbc\xb5\xb3\xd3So\xf2{\xb7\xbf\xae\xff\xbc\xcdi\xe1\xff\x11-\x8e\x86;;\x8b\xd1\x03\x87\x07\xcf\x14\xb6\x070\xf6e.\x8d2\xda<^|\xc8\x1a|\x97M\xf5as\xb1\xe4\xc7b#\xc9~\xf9\xcapo\x04\x87\xf5\x9f\x07\xd0\xfbDV\x06\x96D)\x06\x0d\xed\xef[\xdb\xdf\xaf\xb7\xbf?\xaa1[\xaf\xe3\x85\x89\xe1k0\x90\xaf\xe3E?)\x84\x96\x04=\x81\x84\xf7\xc3\x06\x1cd\x9dc\xa4\xa2\x82\x0dE\x0b\x89\x89g\xe4\xfd\xd3*\xef\xfd^\xa5\x11\xea\xcfI~F\x02\x93\x14x.\xa3\xe5\xbbG\xc3\xdf\xe4\x8c\x155V\x07\xe2O\x0bK\xf4\xbc2\xecl\xed\x99\x9fM-:]p*=K\xe6o\x11\xc1\x04\x06(~&\x9a\x96RE\x06\x04!\xa6 \xe4\x83\x0b\xf8\xb6\x9e\xd4\x1c\x85\xc2\x07r\xd8..\x8e\xf72\xe3\x14\xc3'8\xfd\\\x8e%\xab\xc62C\x17Y\xe7Ws\x0e\x83\xceP\xf63|k\xaf\xe3\xad\x15\xe7i\x83\xb3\x08h\x99m'\x82\x9c3X\xc12\x82yS\x0d\xad_mTPB\xc7\x8a\x0b\x1d\xb1r\xfe\xc0\xec\x87\xb1H\x9a\xb72s\x83\x06b\xa1\xab\x86\x8d\xdf\x8c\xa5k\x05r\xe5\x86\xef\xa7\x9c\xfbHm\x18a\xc7\x15~ma \xdeI_n\n\xedo[\xe2\xe6\x8e\xee@\xf1\xf7\xa14\xe0M}\xe1\xd0\xba#\xc7\x14\xb7I)\xb9D\x8e\xf4\xfb$%o\xe29\xf9>\xcf\xe6R\xa6y\x96\x14\x8b\xac@\xe3\xeb\x8f$\x9ex\x94\x95W\"\xde\xedi\x92\x12~l\x0fz\xc1\xf0_\x0fF_\x87\x0f\x0e{\xb7\x93>\xb9$c\xa3\xe1\x00\xcb\x9e\x08\xdb\x00g\xea\xebm\x94MT-\xd8\x88\x93\xaa\x9e\x82\xcdh\xb2\xa1F\xaa\x8c\xf9\x19\x94\x12n\x99\xa6m\x08-\xe2b\x1c\xa7O\xe3\x82\xc0\x00\x9e\xd6\xef|/\x07\xd9 \x1a\xd9\xc3\xd3\x80Tf\xe2\xdf\xfa\xc3\x7f\xf5o\x8f\xbe\xfe\xea6\x17%B\x93\xc6*\xa6 K\xfe \x1f\xf3\xb4\xb3\x07\x0e\x802vlK\x8b\x1d\xe3\xc2\x9a\xd0u\xb8ekM18\xd6{\x0e\x8dG\xf0\x19a\x8f\xc7\x9c\xcb\xe7\xd8\x92gi\x9a\xd0\xb3\xf7\xa4Xd\xb4\xe8\x86F\xe3$\xab\x14\xfe\xfd\xa4\xd0\xb4\xff\x9a:\x84/\x8dMcP?\xf6\xccoV\xfa\xa5\xbaCx\x97Wry\xc2\x15,\xceY\xf1s\xc2fAo\xbfW\xea#u\x15*:\xe9\xf5\xc6b\xf7\xf4\xf04\xfd\xf3*\xac\xb0\xd0V\xa8\xc1LlK\xd5N\xd0\x93]\x88&\x8dv\x12K\x1b|\xcb\x06\xd40.s#a\xa9|\x93\xa6.5v\xa1\x0d2CVA\x887\x9b\xb7\xf1dB\xc8\"]\x1d\xb3\x8e\xbaLmJ\xf3\xdeP\x86\xffye\x0eLi\xe0hf09\xd9\x15\xdaU\x1cQ\x1edC6\xc2\xbdr\x08\x13\x92\x12F\x80\xdf\xe1B\x0d\xff\x87\xf3\x03\xe2\x0dj\xcce`\xcaV\xabl\x03\x06\xb2\xa7\xa2!\xbd\x08\x89)`\xd6\x95\x19HV We=\x95Y\xd7r\xa6X\xad\x16\xa4k\xc1\x89\xb0Z\x94\x87\x12 \x1d\x0c\x84F|s\xad\x89\x08\x84}o\xdf\x00R\xc5\xect\x19$\xcdQ\xc2\xe0\xe2\x13\x88#\x15\x03\xebS\xf4\xbd\xf8\x90\x95\xfe\x1c\x1ek$\xbe\xb1\xac\x91\xd6\x9b\x15M\x1a\xa6\xbf\xfa{\xe7\xb2\x92\xe7I@\x83oL>\x12ctH\xba\xf7\xcd\x9e\xe1\xd9T~x\xef\x1b\xa3{\xc5B\xb9f|\xbbkz<)\x1f\xdf5=\x9e\x95\x8f\x8d\xe3:\x97\x8f\xef\xdf36>W.%\xbb\xf7L\x8f\xcfpV{\xdf\x99x\xff\x95\xfc\xf4\x8eqR\xa7\nX\xfbw8\xe2\xd7\x9e\x97\x04\xfa\xa4\xc3w\xe1\xd6-\x0c\xe1P\xbeU\xd2\xb5\xd8\x8c\x8b\x12\xa5M\xa5\xea\x9bQ\xf3\xfa/\xbe\xb0\x170\x80\xf2\x08lO\xe5\xc8\xe0\xc0\xd3\xad\xd9o\xc9\xc8fsL{\xb06`]ndv\xae\n\x047&on\xfc\xd8\xd9\xf8\xd6\x16q\xdaW}(\x95c\x0dtO\xa9\x89\xfa\xc8\x06\x86\xa7\xce\x91\xf2~\x17U\xbf\xfc\xe7\xd4\x7f\x18u\x07\xaeN\x16\xce\xa1\xf8\xd9\x8c\x8b\x18Z\xc4a\x0b\x8br\xc7\xda\xf8\x9dz\xe3wD\xe3NN\xbcn\xa2\x97} \xefQ\x7f\xc8\xca\x87\xeb5 `\xcfk\xc7\x88\x0e-\xab\xfd\x18\x9d\x84\xab\xfc\xdf\xb4b\xbfM\x9a\x15\xd0\xfd\x00\x86\xd4\x92\xf6\xces\xa3\xc1!h\x02AR\x04\x182\xc5Q\xd5\xcaq\xf9\xa05\n?\xb6\x06|\xfc\x0e\xf0\x08'\xf8i\xd6&\x06\x82{k\xd4l\xeb*`\xb3\xc5{\x99k\xc3\x1cR\xceY\x0d\xa9\xc1\xeau\xd5\xdc\x12\xeds\xef\x93\xc5\xe1\xb1s\x7f\x80\xb2\xa7\xc2#\xa8\xc2\xc4{?\xc5\xe9\x92\xc0|Y08%\x90\x92\xa2\x006\x8b)\xc8\x96\xbd\xca\xd9?\xb68fn0\xa6\x87\xf61\x9d\xa1\xc2=\x97\xc3\x12\x8d{\x0d\xeb\xad\xd9\x85\xb4\xfb\xb4@9\xf3\xf6\xbfv\x0e\x7f\x9bl\x07\xbf\xf5\xf9?\xe1\xa1\xb2\x0chRjc\xa01H\xb6\xc7gp\xef,>\xaf\x9b\x8d\xcecP\x14#\x01\xcf<\x87\xf5\xc1\xe4\x9b\xeb7&<\x95\xb6\x02\xe2\xf0)\xb4Cn\x9a\xa4\xc4k\x80\xaf-\x0e\xc5~c\xec\xb1|Iz\xb2n0?D\xa7qZ\xe87\xb6v\xb5\xbf\xf7\x14#o\x1b\xf5\xa9\xe8\xdek\xe0\xcf\xcd\xce\xd1~\xe3\x16\x835\xa8{\xecc\x93/\xfb\x0c\xedw\x9b3\xb7\xdf\xe0\x92\xe2M\xfc&\xe0\x9f\x95\xce\xc2\x8e\x95V\xcd{\x8d\xec\x8d\xc9\xef\xdcoTJ\xd8S\xa2F\x9fe\xaf\xb2\x0b\x92?\x8d\x0b\x12\x84\x11l\xdd\xfe\xd7\xf0\xcf`t8\xdc\xdd\xf9.\xde\x99\x8e\xfe\xfc\xf6j\xa7\xfc\xfb\xae\xc7\xdf{\xfbW\xc3\xf0j\xe4E\x18\xf8\xc8\xbd&\xfc\xde\xea~\xefOL+\xde\xc4\x8f\xce\x8b.\xbc\x86\xf7\xcc\x1a3\xb0\xf9\xf06 \xf9\x1b\x8c\xf0\x95%\xd2\xc1{|[\x94\\\xc0{rvt\x89\xfe\xc8\xae\xa5\x9dfi\x9a]\xc0Bv\xd2\x83m\x93\x03{\xfd\x0co\xc7et\x8e\xec\xba\x9c\xed\xad[\xb5\xdfv\xae\xd6\xc6\xf1\"\xab\x87\x94\xe74\x9b\xac\xa4RY\xa8\x17\x13\xda\x13N\xf2\xf8\x0b\xcdX'\x97\xf3\xb4\x87\xee\xf2\xda\xcd\x9eEU\x99T\xea\xce\x9c\xa0\x9b\xc2\xc4\xf6j\x0c\xc2;J\xbe^`\x84\x8b\xe8\xc8\xa2\"\x8e\xcb\xd5\xca\xedv\xc7X47\x97|\x8e\xa5\xf3\xb1\xf6\xa6d=,oN\xab79q\xb6\xbd\xb6\xa8^\x9bf\xf9\x8f\xe0,\x82\xd3\x08N\"\xb8\x88\xe0(\x82\xcb\x08\x8eG\x0d\xe1\xd59\xf6J\xdfd|\xc5V\x92\x0eYB\xe4\x9f\x9f\x86\xcd\xb9\xbf\x97\xb4\x1e\xa6 I'\x90\x14@3\x06\x8b<;O&x\x02\x98(\xb6j\xf4\xdc5X>\xf1\x8f0\x80WA\x16\xc1\xb9\xc3%\xe1#\x1a8\xc4x>\xfa\xba\x1a\x80\x1c\xc2\xa4\xda:\x93\xae\xd1|\x86\x01\xbc\xe7\xa3\x998F\xf3Y\x1b\xcd\xe7MG3\xeb\x1a\xc2\xf70\x80g|\x083\xc7\x10\xbe\xd7\x86\xf0\xfd\xa6CXV\x00q\x96\x1d\xe1\xa3\xf9\x03S]a\x91\x11\xfbh\xfe\xd0F\xf3\xc7\xa6\xa3\x19W\xa3\x19w\x8d\xe6 \x0c\xe01\x1f\xcd\xd81\x9a'\xdah\x9el:\x9a\xfa\x91\xd85\x9e\x9f\x1c^K\xeaB\xee&\xf8 5\xe41#;\x8c\xcbQ\xd8\xfc\x02\x0e\xe1\xf7\x00Uh\xbd%\x176\xca\xbbo\xc4\xdd\xe7\x82\x88\xda\xf9\"u\xc9\xd9\xfedsb\xa9\xc8l\xfd`\xeb\x9a\xdf\x8f0\x80\xd7\x81\xab\xda\n\xce\xee\xc7\x0d\xc6\xf8c\xf7\x18k\x87g\xd7\x10\x7f\x86\x01\xbc\xed\x1e\xe2\xcf\x1b\x0c\xf1\xe7\xee!\xd6O\xe8\xae1\xbe\xc0\xec\x8d\x9dc|\xb1\xc1\x18_t\x8fQg\xb0\xbaF\xf8k\xc7\xd0N\x91\xf9)\xd90\x9f\x81\xfe\xaax\xd6\xe74\x18\xf6\x12F\xe6E/\x02\xc1g\x8f0\xc9N\xcb\xcc\xdd\xe5\xe9\x01\x9a`\xd5\xb5\xed\xf8U\xc3\xa4_\xd1E\x82#\x0b\x86\xaa\xd6\x97P=|'\x1f\xeaT\xe0Wd\xc0\xf8\xd3\xe7\\\xa8\x8c\xa4\xb9]\xac\x83{\xb0\xfcJDVKC\xde\x95\xe6\x85\x995\x0e,\x99\xc4\xd4\xe5\xac7\xdb\x89\x13\x1a\x83\xdc\x85\x12/a\x00\x1f\xba\x91\xf6\xa5\x0f.H`\xbd\xf4\xa5\xc6V\xab\xb7\xc1{\xa5\x9dF\xc1\xcd))7\xa3/w66X:Az\x05m*\xf6\xb7\x0cZ\xa6\xf8g\x0e\xef\xdb\x97\xf3T\xea\xae\x98U\xbeK\x84\xcf\xd5\xe5<\xc5m\x8b\x7fa~\x12\xd7\x9a\x0b=\x0f\xff\x86K\xf9\xf2\xdb?\xaf\"\xfe\xfdW_\xe5d\xaa;\x03\xac\x16\xe8\xb4F\xfa\xb8\xaf\xc5\x9f\x0b\x91\xcf#!\xf2w\x95\x16\xe6]\xf5\xe4\x10\xfe\xf6\xf0\x907~N\xf2\"\xc9\xe8\xa0\xb7\xd7\xdf\xed\x01\xa1\xe3l\x92\xd0\xb3A\xef\xe3\x87\xefw\xbe\xed\x1d>\xfa\x8dJ\xb7v\xf8\xe5\xf5+ \x97\xb8\xc40\x8e)g>O \x9c\x11\x8a\xc9\x19' B\x94\xfef\xf5~R\xd7yY^\n\xa7\xd3\x9fsQ \xb8\xfd\xdb\xf1\xd7\xbf\xdd\x0e~;\xde\x0e\xbf\xba\xed@\xf6\n\x88\xb2\x84\x94'*C\xddXx\xa6,\xb5\x93\xa7\xa8/\xfb\xe5\xf5\xab#17\xe1J\xe2\xe3\x01r.\xcb\xaa\xd5\xdb\x13\x9b\xe0\xfb<\x9b\x8b\x8d \xdbk\xcfH)\xc5l\x92]\xd2%\xd9%a\x08\x87M?\x98\xa4\xf2\x83\x81\x83F\x8eJ\xe9\xa3\xa9\xa7?q\xba}\x9d\xcb\xcc\x86\x7f\x1at\x85 \x93\x17V\xe2|\x9a\x8d1\xcbN\xbf\xc0\xc6-\xfa\xa5Joi\xdbZ=\xa1\xa4w)MD\x16\x94byZ\xb0<\xd8\x0b\xfb\xc5\"MX\xd0\xbbe\xd2\xc6\x80\xee\x9f\x9eCB\x81\x86@\xfb\xb3\xb8x{A\xcb\xdc7\xb9pS\xc4(\xc3a>R-\x0e\xb8XE\x86\x132\xce&\xe4\xe3\xfb\xe7O\xb3\xf9\"\xa3\x84\xb2 \x1f\xee\x8e\xc2\x11\x0c \xe7T\xe8\xd6-0\xbe\xb37\x12v\xd5\x9e\x0f>\xa9m\xdd^\xb3v\x1a\x1b7m\xb5Z\xc5\xfd\xca\x97\xab\x81\xd0\xd6\x8cD\xca\xfdA\x0f\xb6MO\xc9\x90\x19\x0d\xb3\xfd\xdf\xb3\x84\xe2\xf2\xb4\xa7&S\xf5\xb8\x07\xa5\xe6S\xcb\xb9\xa1r\x17Sr\x01$`\x9a\xb9\"\x82\xde\x92Mw\xbe\xed\x85au\xb7w\x1a\x17\xe4\xfe]\xd3\x18\xaa\xd4A\xed\xae3\x0c6K2Z\x1c\xe3[6\xaf\x9d8]\xccb\xcf\\\x83\xa0\xbb\x8f)m\xe2\xac\x17\xe2\x16J \x07h\x9c\xf3)i\xcf,G\xb6yc\xce \x9be\x93k\x8fF|n\x1b\x8fz\xea\xcdD\xb4\xc7\xc8\xe2\xb3\xbf\n\x9c\x8d!{\x0f\xd2\x80\x99\x8d\x14S~\xec\x8c\xc9I\xa5\x8a\x8d\xe6\xe4\xc7z\xfa+_^b\xf5\x10\xd1\xd8\x96\x1c5\x88\xbd\xeao&x\xbb!\x8d\xf8\x06\x8dL\xfb3\x0f\xb5\xc4k\xfb\xbb\xb7\xcf\"\xe8m\xf7\xc2\x91\xdc\x9f\xa6%\xb5R)\xe6\xda\xd4\x86\x94]\xb5\x95\xb48\xd6\x94J3N\xb8f\x15\xe1\xa2\x9aSN\x97\xcb\xc8F\x1e#\xf5\x91\xd7a\xae\x94b\x96\xbcd^\x04\xd8X\xa0\x063\x8ektL\x9a\xb31\xa5Q\x9e\xcc\x03m\x91~\xc3\xecx\xbd\x13\xb4\xd8\xf4z\xae\xe1Z\xb2\xaay\x0d\x93\xc3\xec\xb4\x82\xd9\xc7\xb6{Yd\xc8\xe3\xe6\xd54ig\x9b\xe8N\xc2z\xfb_\x97;%s\xdd\xb9l\x915\xf7\xdc_9Bi\xffY\x97\xf6\xa5ui=ZK\xbb\xd8ZZ\xbd\xfc\xa7\xf2?\xd5\x83\xb2\x90\x16\x0d\xee\xdd\x0d\xfbO\x96\xd3)\x91\xde\xe2\xd7\xca\x06hN\x88\xd9\x9cfI\xa9\x8c\x92\x99\xc8\x15\x0f\xff\x7f\xf2\xde\xbc\xbbm\x1cK\x14\xff\xbf?\xc55\xa7_\x8a,\xd3\xb4$\xaf\x91\xedx\xb28\xdd\x99\xc9\xf6b\xa7\xea\xd7\xa3\xf2xh\n\x92\xd8\xa1H\x15\x17;\xae\xb2\xe7\xb3\xff\x0e.\x00\x12\x04\x01\x92rR\xd3\xfd\xde\xe3\xc9\x89E\x12\xc4r\x01\\\xdc\xfd\x9e@\x15\xcb\xf2\x13\xf1\x83\x9c\xc7\xa2\xfc\x17$\x0b(\x81p\x047a\x16\xe6\xb0\xc8\xf3\xd5x{{\xe6\x07\xe4:I\xbex\xf30_\x14\xd7^\x98l\xa7\xf4\xbb\xedi\x12d\xdb\xf8\xf1\x16#\x9fRo\x91/\xa3\xd3P\xc4nd\x94\x86\xcb\xf3\xb9A\n\xc7\x90\x1fA\xba\xb9\xe9@\x0c\x9b'`=\xf1\xd3y6\xb94Q$\x157\x97\xa2\xcb\xaeB\x1f\xb2:\xeaq5ED\xcd$\xed\x1f\x94\xb3\n\xc8\x99uG\xe2l\xa2\x99\xa4\x16\x1dS\xe5\x15\x98C[\xd2\x1a\xd8\x12\xc58j\xc4\xca\xca\n\xef\xbb\xc4\xa8'\x14\xd8\xe7\xa4\x1f\xac\x932\x1a\xf1#\x9a\xacB\x19\xcbcf\x1d\xa8nz\xf5#\xcb\xfd\xe0\xcb#\xba\x80\x11\x98\xd9\xb8\xe9/:r\xfa\xb7W\x9b!\xb7\xd0}D\xb3\xc2\xb8\x17[\xd6\x18\xfd\xf6j?\xc5H\xcfk\xb5^\xd4\xb3\xbd\x88\xa8=\xad\xca\xa8\xf2\x84\xc84'\x04\x8b\xac\xc3\x8c\x102x\x06{p\n\x19l\xc1\x1e\x8c1\xf3R\x00'\xb0w\x04\x01\x1cCv\x04\x01E\xe3\xd1$\xa0\x05.\xe5\xda&AKb\xf0\x1b\xee\xa5n\xb6\xa3\x86R\xdb3\x93\xe9\xac\xd4c\xc1\xb0\x8d\xe2:q\xd1\x16\xd0\xd4\xc4\x9eux\x8a\x03\xb75 \xdb\xe5\xdf\x1c\xdcR,h\x8a\xc3\xa3p\x8afOSzb\xc2\x7f\xd1\x9f\x05\xfd\xf9_\x90\xcc\x90Zd\xcfV\xecYV\xacV\x11=\x7f\xf2\x84=O\xf0\xb9\x0b\xe4\xeb\n\x03\x9c\x80\x1fC\xe9\xd8\xe1\xfd=\xe3\xa1\xbf=\x8d\xe8A\\z)\x19\xc8\xb3\xbch\xe5X\xc4EK\xde \xe7\xb2\xe8H\xe9\xde\xa9\x8b\x16\x97\xb0\x8d\x99\x95\xd9\x03\xdb\xacN\xe4\x0b\x1d\xf3y\x1eJ\x91~h\xb2taQ\xaeo\n9\x8f\xc2pQfP\x88\xda<\xf1\xc5E;?/\xe5W\xf3\xd6\xf2f\xd8\x1a\x82\xc5\xf5\xda\xe4\xd9\xc2_\x911\xac\x9aoD\xa07\xed\xcb\xa5\xbfzY\xbe\xef\x8d\x1ef\x88\x9c\x1ew\x06F\x18\xe5>\xb3\xf5\xe7\xb6\xb6\x87X\xbc\xd9Z\xdb\xf9\x8a\x9f\xf4<+\xb5'#V\xd0<\xeb\xdaN6\xb9\xcd\xae\xb3\xcap2\xb1V\x0dg\x8d\xae\x9f\xbf\xf2~\xfe\xca\xfb\xf9+\xf6\xf3WM\xd9\x94\xc7\xfb\xcfl\x8b\xed\x7f\xcb\xed?\xe1D\x87.\x9b\xb3\xadi6,S,d\xf6\x9a\xc7\x99\xec&&z\n~\xb3\xaf\x82+\x11|t}\xbb\xf2\x11h\x9c\xc7\x84\xfeu\\\x1f\x1e\xb3R\xa5\xef\x85\xfc}\xac\x8e_\xf4\x97\x16\xaa0+r\x1ae\xcen\xbb\x14>\x03\x06F\xac\x05\xdf}\xd0\x8c\xac\xd00]\xe2]\xce\x8f\xe1\xb4\x0c\x9e\xa7\x9b\xb0\xb5N\xe0}~\x02\xefK'\xf0\xbe\xee\x04\xde\xef>\x81\x05\xd5\x00'\x80\xa6+)\x0b\x9e\xc7\x8c\x1c]\xe1\xbd\xcb\xe2\xb3\x9e\x02QQpm`2\xe2\xe5\xc9\xe8\xa5\xe3\xb14u\xa2\xc0\xf6\x1b\xe7\xe3\xad\xcfl\x9f\xb2\x15 \x18S\x16\xc6\xac@\x88\x05<\x94\x97\xb0\x86\xebk\xad\xb1\xa2\x98&A\n\x0f\xbc1t\xb4++\xf6\xc2\xac\xec\x96\xfa\xcd\xa0\x16\\U7\xed\x99\x96\xfco\xd2ar\xf4D\xed\xec\x8b\x89\xa7P6\xa9X\xec\xac\xd5\xe44B\xda\xa6#\x87\x8f\x81X \xdb\x89\x95\xa8/\xb1\xf2_\xa5\xac\xe0\xbft\x14\x8aQ\xec\xd8\x8c;\xe2\xb4\xc2=2\xc9\x1b\x9b\xa0\xaf\xe0\xaeI\n\x02\xf2\xc6\x8b\xb4\x1b/(7^\xc4I\xdfH\"}g\x8c\xf4\x9d\xc11DG0\xa3\x1b/\x98\xcc\x9a\xa4\xef\xcc\x10\xd0i\x85\xaa\xa6\xc44\xe7\xb1\xbdj\x9ds\xbaf\x0b3\xfd\x84F\xd0\xf6\xeaQKB\xa2_3\xcd\x92X\x18\x96D\xd8E\xbf\xa2K\x00#\xd5\xfa,\x10fW\xc1'S\xef\xe7\xa3\x19\x00-#\x1ce\x0d]\xc4y_\xa5\xc9\xea\xa2\x1cS\xd6\xe8{\xb9\xe2\xb4\x99V\xca\x95s\x83\x91\xab\xca\xc8\xf5.\x92\xb8\x03\x97\xd3\xac<\xa1-,\xe1\x18\xe6G\xb0\xa4\x8b\xc4<\xa5\x18ZJE\xb27.,\xcbEL{9\xa1\xfd]\xd2_\x97V\x89t\x03\x13\xb5K\x81x'\x9f\x82\x08\xae\x12\x80w\x1d\xf3\xd0\xb1\x19\x85xC\x17.\xbb\xb9\x1f[\xb7`\xa2\xdd\x82a\xb9\x05\x13\xc7\xe5 \x10\xc1\x87cH\x8e\xc0\xa7\xd0\x0c'~}\xbb\xf9\xe6s\x0eQ\x07vU\x01r\x88:]\x16\x7f \xf3\x8d\xb8r\xb7\xab!\xa2[\xae~\xfe\xcaq\x84\xdaq\xf8\xe58B\x8eJB \x95\x14\x0c\x95\x14p\x0c\xe1\x11\x14t\\\xfe\xa4h\xa2\x92\xc2\xa4E\xe2(\x8cLrC \xe3^\xca\xda\xf6\xd2\x17r\x97]H\xfb\xc9NV\\\x08\x9a\x91 \x89\xa7e\xd7\x9c\xe6V\x8bM[\xad\xc9\xe6\xb6o5\x90\xa1\x8b\xe1~\xe5H=\xe5\xbe\x9b\xb1}G\xb1jP\xee;\x8a\x9cW\x1c9\x9b9T\x81N3u\xef\x05.\xcc\xca\x99G\xa4\xb8\xf5\x8c\x02\xc5\xa6\xe3\x08&\xb3K\xfa\xcc\xa9v\xa1\xdf\xc6s2\x8bi\xe3Nl\x92\xe5\xa0\xc5\x8a\x0fNs\xf5\xea\x0f\x98l\x9d\x9d<3\xd3\xe7\x92\x05\x8bb\xb7U1\x060\xae\xbdk\x9eK\xb1\xa9\"\xb4\xd1\xd2r\x15\xb5:G\x97Z\"\xee\xff\xa5\xd3\xfe\xb1\xc7y\xd1~\x9cO\xff\x87\x8e\xf3\x9b2\xcec%\xffi=X\xbb4\xebK\xc4x7-\x18o\xd9\xb5\xeb\xe9)\xbdTw\xfd\xc2\x85\x9b\xda\x89\x8b\x1c\xe2M\xf7Y\x0b=%J\x9d\xc6\n\xed[u\xd5\xdc\xaa\x95|G\xfeT\xfc\x925\x85\xcc~\xecQ\x8a\xa3\xed\x1f\xcb\x9f\x8c\xc3\xde\xf2\xb3,\x9cWl\x92\x1d8p\x1e\xc6\xd3\x94\xc0y\x92.\x8a\n\x01\xfdk\x14\x06$\xce\x08\xbc{sQ>\xfcq\xbb\xfc)tR<\x8d\xd9\x9c\xe4\x92)\xd7\xf9\xdd\xf2:\x89\xb2\xa6\xae\x8a\x97\xae%\xb9\x94\xbek\xea\xae\x1a\x1fp\xcb\xca\xbb7\xd9Y\\,\x19\xda9\xd2\xc2\xcdH\xc4\xe8=\xa9pS\xf3\xe6\x18\x94Z\xc3\x89\xdcp\xbb<\xba\x83\x85u\x93\x7f\x1d\x98|\x11\xc9\x04\xb1\x8e5%\x96\x0b\xd6\x1e\xb34\xd4\xc2\xee\xbd\xbf$\x99M\x9c\xc9\xe0\xb2\xb5\x0355\xf1\xef\x0fL)<8\x82\x18\x8eaH\xffR\x84\x97O\xac+\xba\x15X\x0f1\x0f\xd3\xcb\x85\x9f\xbeL\xa6\xc4\x8e\xd1t.\xd6\xf7\xd7\x1a\x0cG;\xbb{\xfb\x07\x87O\x99}KK_s\xc5\xa6\xadK\xc4\x95\xabq\x84\x00$\x0b5\xab=\x8c\x8bXw-I\x91\xe8\xc9p3\xb4\xb6\xb2\xd2\xb6\xc2\x94\xd7\xc4\xbb\x9aE\xfe<\x83'PPZ\xe5\xa5\x1f,\x08K\xa5@[\xd1\xcbxo\xcaLG\x154\xe8\x17)\xd1$\x80\x06\x11\xa7\x82%m\xc2\x82M\x9c@\xc6\xb2\xb8\x02\xed\xe7\xb55!zV\xed\xea\xc3Vm\xfb\x0d\x8fx\x1fO\xc2\x8e8\xea\x19\x02\xddw\xbc\xabi\xb2|\xf3\xaa\x9d\xa2f\x16\xb2Z\xaeN\xbepTGU\xd4\xd1\xe4\x08\xa1\x91`P\xfa\xf3\xf0:\n\xe3\xb9Yy..\xda`d'\x94\x8b\xecjP\\3\xdbw\xa1\xcd\xa3K\xbe\x02\x9e\x91FC\x08\xa8\x97Y\xe7L\xaf\xd4\xb6vF\x16\xed\xa7\xb1\x98A5\xdd\\\x12bi\xde\x9f\xe8\xd7\xe6\x9f\xf4\xdf\xeb\xb6\xc0\xb4\xb9\xb5\x19\xd1\x9aU4(\xbd92\xec~&qa\x96\xd7\xb0\x81%M\xc4\x03w\x7f#\x98\xda\xdb[\xf9)\x89q\xc3:\xb2vA\xb3\x01p?U\xc5\x0d\x83\x83jI\x91\xd2U\x11\x87q\x84U\xa4\xde*Y\xd9\x8e\x83\xd8\x8a\xf6Y\x98U>y\x02+z\x96\xaa(E\x90\xac\x7fj\xb6%\xb8\xe3\xfa8\xe7$\x7f\x19%\x19\xc9rq\xc6\xbcN\x93%\xed\xf2\x18\xa6\xaeZ\xb4Y\xa6\x9d\xfc\x12\xf4\xfeT\x1b\x97^\x82 \xca\x0b\x99I\xba\x84\x13y\x18\xc2\x9c\xfb\x87\xd5\x81\xd8\xe8\x1c\xfd\x86vLt\xb2\xabsa=\xfb:\x91Z\xc6\x98\xcc\xd6\xce\x0e\xba\xf2T\xcf%7\xba\xf2Y\x07\xa7\xc3V\x98T\xdc\x11V\xf7\xa4\xaa\xfb#\xae\x13\xd4\x8f\xda\xd6\xce.\xb6\n'\xf5\xb7\x86v\x8e\xca@\xfcl\xc5\xe4b\xc5\xe01!\xf7\xdd\x08\x7f\xa9P\x1b\x84W) \xe8\x96\xadvl\xc3nD\x14\xe1KC!ub\xf9]\xafe\xd3\nf&L\xe7\xd1\xb2\xe9\xc9Y\x1b.\xdd/E\x14\x19\x8d\xa5\xf5<\xf8\x02\x9f\xaa\x04\xa4\xdc\xc5\xea\xb0\xac\xbeR\xce{\xe6\x1d9\x06k\xe4\xedy{\x96\xaeMM\xc0\xe6\xab+\x86\x01\xe8\xdf\x13q^~+);\xd0\x19\xe0N\xac/a<\xa5|}J\xb2$\xba!,\xf7Z\x9ca\xae)z#D\xc8\x1ff\xf4n\x95\x92i\x18\xf89a\x9f\xacR\x92\x91\x18\xcbq\xf3\xffs\x9e\xec\x8de}{\x1e\x85~F2\xeb\xb2I.O\xac,\xf0#?\xc5\xb2\xe4\xd7\x82\xc4\x01~\xb7\xf4W\xab0\x9e[\x97\x1d\x92\x11#y\xe5\x82__ \xe1\x8c\xe5\xb9\xc8\x85'\xac\xcc\xe1\xe6}\xc3\xb4\xd3Z\xb6x\xd8 \x0f\x9d\xc1?\xcc\xd0w\xb7b\x1bS\xfb\x87\xcf\xf1\x978\xb9\x8d\x81\xa9.\xc0\xfa\x81\x13\xa8?X\x10f\xb0$9%\x80\x90KD\x03oHf\xac\x0cae\xfe\xf6\xfc\xdd[\\\x04\xde\x0f\xcaju\\\xc8\x17a\xe6\xe5\xfe\x9c\xae8~G'\x0f7:\xfe\xe0\xf1\xed\xf9;>\xa1\xf8Z\xfc\xbe\xbf7\x8b\x96@b\xd3\x15\xb3\x07^c\xb9.\x98[Ky'\xd7\xda\xea*\xa1\xad\xb5Z`,\xbctu[\x1fO\xb9\xf4\x18f+\xef\xd4Q\xf35\xc9\xc7-\xee\xea\xa5\xe4\xc5\x8a\x05k\x0f\xeae\xe5\x85\x8c\xec\x1cs\x1e\x95\x9f\x96\x1f\xf8B\x9e%hB\x8c1 \xaf\xb7\xb8\xaf\x08'\x9e\x90\xcb\x9eK\x93^\xfe\xa4d\xc6LR\x9f\xc6\x82\xf2\x1d\x17\xf8\x92\x0e\xab%-\xd6\x95ii\xe3Rc\x0b\xbb\\\x82b\x81W\x165\xf4@\xea\\\xd9\xbdx\xf4\n\x85\x8dvG\x8em\xdd~\xc9\xd4\xf8j\x8c+\x1f\xee\x1b\xd8\xf2\x1d\xc7cR\xdd&s\xaeM\xdc+\x99\xe3\xda\xfd\xfc^\xf8\x02G\x91\xdb\xfd=\xd8\\\xf6\xe6\xd3\xd9\x0f\xc5C\x1f\xf5\xb0cH\x1c\xdbb\xfda\xc6`\x92\xb3\xd4\x83\xe3ey\x82\xa9\x92\xd3>\xb0\xd1#\xfd\\\x0e\x15_\x0f\xdc%\x80\x19\xda\xb1\xbd\xb7\x7f\xa8\x06\xacO\xf8\xab\xa7CG+7\x08\x8dC\xef\x1f\xa3\xde\x10\x9f\xfe\xe1O\xcd_\xe5\xbel\x13\x89\x0bmD\xdb\xc1\x00\x1c\x81\xab\xf6}\x15\x11\xa7\x17\x81)\xce\xf1\xa5\xf0\xae\xfa\xb0\xb3Y\x90\x08\x05S\xb0Gz\xa5,_\x96\xf1}\x88!\xe1\xcc\xef\xfd\x8e`*\xed1\xd8J:\xb5`bH%\xeb\x19\xc1\xbck\x98\xe3\xa6@\xd5u-\xef\x1a\xe3V\x18%[\xb0\xbcj\x94EbHW\x8e\xa4\x9e;G|\x9c\x06\xe6\xb5_`\xb7\x90\xa7\x16\xf3\xb5\x88\x0e\xa0_\xbe\xaf\xee\xa0t\x1b\xe8\x18\x9bIi\xc6\xb2\xf64c\xd0\xb3i\xe0\xcb+\x14(\xd67W\xa7\x1f\x9f\xf6\xa9\xe0\xa1\x1a/\x1f\xd8\xea\xd4\xd0\xcd:\x91\xb7\xd0\xe6\xfayN\x96\xab\x1c\xf2\x04\xa6\x84\x1d\xf5E\xca\xbc\xd9\x84\xbdni`\xa0*\x03\xaa\xcdl\xf7\xa2^%:u\xbf\x1d\xc9\x0f\xf7\xb5H~4\xfc\xbf\x16\xc9K\x07\xa0^\x1c=\xdc\xd3\x82d\xf7\xa9F\x1a\x1d\xdb\x0d!u\xc1\x1e\xab\xa9M\xfaz]\xa3\xf2\xc1\x05f\xbd\xb2\x02\x0c\xe0\x0d\x99\xf7Z\x8f\xaa\xa6e\x81\xbf\xe8\x0b,\xca\x02\xe7\xfa\x027e\x81\x8f\xfa\x02\xcb\xb2\xc0\x0b}\x81yY\xe0g}\x81;8\x81)\x9cB\"\x92.\xd1\x99\xe5\xd9\x97~7e\x11\xbb\xc6h&\xa5\xb6W_\xe8\x8a\xd7\x9c\xc2\x18\x16\xf4/\xcb\xecd\xa7\xbc\x95\xdf\x1f\x9c\xaa\n\x03\x9b\x8f\x9a\x9ei)\"\xca\x1d:1\x98\x9a|\x03\xf3\xe0^)\x11\x8a\xae&\x11\xd3\xb1\x14\xf6\x1d\xaa\x7f\xe8h(\xb1\x1d\xc0)\xbe\x841\xaa\x81\\\xb8c:!\xac[k\xbf\x85\xa5O\xb14\x8caI\xcb\xd1JB{\x86&yc\x98c\x07\xb0\x9a\x13\x98\xc1i\x07c\x00\x12\x83_\xd1\xb8z\x0b?\xf9B\x96n\x11f\xb5x\x1e]\xe2\xd3\x0c\xf3#\x83\xad\xea\xd6\xba\xbe\xa3W\xe0g\x04\x06\xe3\xcerP\xb7\x8f\xd1L\xa1za\xcd\xc3\xf5k\xb6u\xf8\\\xbd\xb0\xf2\xd1c*\xd7\xc60\x92\xaf\x0ea\xb1Z\x996W\x99\xb8\xccu\x95b)f5C\xe7\xdc\xad\x94\xa3\xfa\x1a5\xdau\x90\xc4\xa1\xd5\xfebr\xd9r\xc3\xea\x02\x88\xb3d\xd47\xca\x86\xa8N\x91\x19\xae\xfe\xd7\xfc\x0d\xaa5]\xc0of.\xfb\xcc\xb6\xef\xbc\x1b\x96\x14\x1b7^u\x87\xb8\xc4a[n\xe6r\x8c\xf4\x89~sM\xff\xdb\xb8\xa6\xaf\x9e<\x01\xdf\xbev\x01\xab5\xa7(\xc9\xbc\xd7\xcci;\xf3\xfe\x02'0\xa2?\xce\xe1\x04v\xe9\x8f\x8fp\x02\x87\xf4\xc7\x0bZf\x9f\xfe\xfa\x19N`\x07K}\x86\x13\xd8\xc7b\x9f\xe8\xdb\xd1\xa1[\x93\xb70Q\xfc\xbaR09\xeeT\x85=n\xc3x\x9a\xdc\xd2!\xb1_\xde;\x0c2q\x82ZL8\x15\xef\xc7\x86\xcf3\x12a\x10e\xfaW\xfd\x14\xdf\x8dAL\x84m\x89\xd9^\x84\x99\xe5\xc8\xa6_Zq\xdb\x9c\x8b\xdb\xe6\xdf(n\xeb\xe2\xbc\\~b\x8f\xf6\xd5\xd3\x16\x03\x81\xd1S\x9eE\xcaN\xeb\x9cT\xda\xceI\xa5\xa6e\xa1e\xa0\xda=\x1aPBEx`\xb0\xb0\x96\xd9(w\xb5\xc7\x7fT\x901h\xd4\x83\xa44r\x1ak9\x9b \x89g\xe1\xbch)q\x9b\x86\xb9x[\x1f\"\x86\xa0g\x07r\xec\xd6T\xb1\xd0=wfym \xd1\xd8\xde\xdb\xd9Q\xa6\xa8\x9a\x91Z\x7f\xf4M\xeavH\x8d\xfb\xd4\x8b7\xe3>\xfd\xff\xc6\xb5\xa7\x8e\xeb\x8f_z\xe52j\x17\x15\xd6\x94%\xc3#\xc8\xb5\x860\xb9\xde\x10\xe6F\xcd\xd4\xa0\xb5NoDr\xeb\xb0\xea+\x0dUx\x8072I/\xb9\xf7\x94\x89\xe3\x01\xbd\x89\x00=\xa8\xde\xef\xef\x0d\x06\x07\xec\xfd\xfe\xde\xde\xce\x1e]I\xfc\xd7\x13`\xf2&z\xb7\xaby.*\x1c\x94\x95\x1d\xb2\xe7\xc3a\x95]J\x14\x1a\xee\x96\xa5v\x86\xb5\xcf\x87\xa3\x83\xf2\xd5p\xef\xa9\x03<\xbf\xd63\x18\x0e\x87\xbb\xc3\xe1\xd0a\x97\x04\xd3&T4\xbe\xba!\xcf\x02\x87\x9d6\xa11\x8a\xfe\x18\xc06\xc1\xb6 l\x9d`\xf9}\x07\x9e=\x83\xa1\xca\xbe\x8b\x8b\"\xbf\xbd\xfd\x9d\xd1\x80~5\x1c\x8cv\x10&FM\xaf\xce\xac\xb6I\xf5k\xd1\x9a\xeeS\xad)\xf8\x0dw6\xdd~bO\xfc\xad\xdf\xfe\xe5\x92\xfe?\xd8zz\xf9\xfb\xd0\xdd\x19>8G\xdbs\xc5\xe0\x8dR\xc5\xdb\xff\xf9/\xb6}:\xfe:\xf1\xb7f\xbc\xf0\xe1\xc3\xfd\xa4\xfc\xe98\xdb\xcaW,\xe7\xec\xeep_+\xb4n7\xc5R\xc4\xa5|\x88\x89\x1d\xf0\x14\xcc\x01\xe3\xd0w\xf6PO\x92{\x01\x1f\xf1\xf3\xdc\x1e\xe0\xb2\x88Dx.F\xabc|\xab\xaf\xcc\x946\x9f\x0c/\xeb\xb9\xaf\xe0\x140\x80\xea\x9b8\xb7\xf3\xd2D\xcf\x85\xe1>\xa5h\x1a\xaf\x86\xf4\xd5\x00\xe3\xb4\x16v\x8cD\x8f\x01\xcc+\n\xb8\xc9\x93\xe3g\xd6\xe5v\x1d8S\xe9\xcd\xbc\xfe\xaai\x02B/\xeb\x895\x06\xeb\x89\xbf\\\x1diB#[\xc7\xf86\xca\xb5/\x9f\xe1\xcb\xb9\xf6\xe5\x0f\xd6\x0f\xf4\xe5\xafE\x92\x1f5b\xd15\xa7\xed\xc6\x88S\x16\xb2\x11\xb6\xac-\xe0V\xba=\x84x\x93K\x06a\x86\x1eK\x9a\xc1\x85\xe1:\xfa\xe0\xd6dVR2Lq\x0c\xe6z#c\xb4`\x149H\xf8W\x06\xe6\xbeKum\x0coH/2\x89/y\xe4\x1bm\x19]\x0c\x91\xfa<95Z\xdb\xc5l\xc0=\xd2\xe9q\xa0[\x1368\x8e@.y\x04\xf3V \x11\xff\xb4q<\nSW~\xbe5\xcd\xa9\xeb\xdd\\\xf8xN\xd3\x9fE\xcc\"\x1d\xbek\xcfgWJ\x1e\x84b\xd4\xfa\xe5\x17\xcb\x81c\x18p\xcd\x16)\xe3,\x86.X\x7f\x1eZ\x8e\n\x99\x9f\xfc(\x9c\x9e\xc5y\x98\xdf\xbddf(>}\x81x3\x99\x92\x8fI\x88j\xea\xc2e\x9ajZ\x17\x96\x0eI/A\xb4\xd4\xb5'\x86\x9ee\xae\x9c\x18\x08\xbb\xc5\x06\xff\xd7\x1c\x03\x84w\xb6\xb1\x12I\xd80\"\x83\xa8v\xea\xc2\x8d\x0e\x19\xb51Ak\xc9\xd8\xa5\xa0\xd6U\xe0\xcbS)\xc1;\x8c\xf5\xf2\x98\xae\x1e\x19E\xeb\x0dn\x8f1K\xfb\xeai\xcbD\xeb{\x87Z\xd1\xfa\x81Z \x13\xad\x0fGj-\x8f\x93\xad\xbb\x92\xf4\xdc ^_t\x89\xd7o\xba\xc4\xeb\xcb.\xf1\xfa\xbcK\xbc~\x07'L\xb6\x8d\x923.\xe3f\n\x13!A7\x8a\xbc\xcd\xa2\xf5\xc5\xba\xf2\xf8+8\x81kI\xd8G\xbf\xb9\xae \xff~\xd7\xa5Q\xaaD\xechY)\x89\xd8\xd1+\xd3f\x82v\x14\x91\xdfA]\xd0~\x87\x82\xf6S\xb8\x831\xc4\x0eJ\xd4\xe9\xb1\x8c\xc2\xa5\x00\x8fp!&G\xc9\xb9Q\xa0X\x98\x04\x8aw\x8c\xc4\xb8c\xe2@!2\xfc\xec\xb8\x80\xb2\xc2\x0d\x9ee,\xe4\x02\xc3\x15\x06\x08\x10\x02y\xf1\xd6\xbe\xe2\"G\xa301\xf5\x02\xa6\x9eJ\xdc\xffi\xc1\xa2Y\xf5\xa5*\xb3\xb8\xeak\xa0\xaa\xc4\xf8\x06Uw\"\xdd\xa0\xdb\x96J\x00\x15\x9a}hP=\xdc\xf0\xa8\x01\xdc\xcc&\xc4\x1c\"\xda\x85W``KtM0R\xdf<\xf22*\x95\xed\x82\x85\x11\x15~\xec?\x9c\xa0\xe1\x0coH\n\xba\xec\xbb%\xf9\xe4\xa0U\xcd\x0f\x0e\x8fF\xf6\xactu?\xde.}\"\x9e\x19\x03\xfe\xaegP\xa7\xf1X\x8b\x99\xea3\xb7\x0b\xc7\x85\xd4N\xbd\x8f\xb0 \xa9\xf7\x1a~\x84\xa4=\x02\x83\xe0o,\x0b&\xe4\xd2\xa6c0\x02)gF\x03\n\x05}\x7f\x0f9w\x88\xa3_K\xd9\xe0\xeb\xc3u0 #\xc6O\xae\xb15\xddG\x15\x8e\xba\xeaU\xdc\xc3\xfa$_\x84\x95\xd1\xfa\x83,on\x9a\x19\xd0\xfab:\x0c\xa3\xb4\x1aq\xd5\xc0\x05r\xe3G\x8em\xb1\xc7U\xf5F# \xcd\xb1Y\xc9\xdc\x11\x93\xb1[\x1d\xaf\xf6\x9d\xa4\x905Q\xe3S\xdd\xe6\xfc\xfe\xa2\xc6^\x9e\xb37\"\x19E\xa3\x01\x91xb\xacMT\xb1\x08\xb3SV\x160\xf1\xf0j\xb9\xd0\x84\xe7C\x91\xd89\xf6\xb2\x15 \xceIDh/2\xcd#\xbc\xfb\xb7,i\x15\xf7\x89\xa3\xcc\xf4\xad. \x8e\xb8x\xa7}\xbb\xa0\x0cmi \\\xd7\x1e\xd25\xa8XH\xff\xfe\x80\xb1lb\x9d\xa5\x80|}H\xc3\xb1\xc6\xdeF\\\x0f\x18\xd5\xd3\xd4l\xeeB\xd8\xf7x\x85j0\xe2\xd4\xb8\xf5\xd3\xd8\xb6p\x95\xde\xa6\xfejE\xd21\x04I\x11M\xe3\x1fr\x98\x13\x16\x17\xd4r\xdc\xa6\x9fa\xb3 \xad\x17\x99@dt{\x0c\xfe\xa1\x86\xf4\xcd\x86[\"\xe3\xf2\xcdGiZ\x7f\x15\xaa\x9bO0\xae\xcd\x944\xcc\xf9\xae\xbe\xc9v\xbc\x81g!\x8d\x9fW\x0c\xdan\x17\x13f\xe6\xfe\x0f\x9d.\xeeU\x1d\x15:\xc1\xa7h\xe3\xcf\x08\x91J\xde\x8eqCE\x02l?\xe6\"\xf7\x0d\xc3\x88\x1f-R\x1c\x1d\xa8RBLy\xd1\xe4\xd1d*\xa0\xa4\x06\x18\xda\x96\"\xb2\x887M\x8e*\xa5\xfcb\xd2\xcaQ\xea\xa1\xa7\x0f\xcf$\x8f\xa6\x1f\xaco\xfa\xc4V\x16\xae\xbdL\x03[\x03\x03\xed\xba\"\x0d[s\xa9tx?\xd6\xfc\xb2\xdb\xcc\x7f\xae\x8b\xf9E\x92D2\xb3\xd9\xab}I\x90\xac\xda\xa7\x0b\xab\x1bu1\x84\xdcv[uZ\xf2+k\x80\xfa\x99-\x9f\xb23\xa6\xf1\xdc\x95\xa2\xe6\xd4\x0b\xab\xd1s4\x87\x13\xba\xb4\xa3\xeb1\xda\xe8P\xb4\x8a\xe4Qj\xc7\x8ekN\xdb_\x1e\x0d\xa2\xdaZ\x89\x1a\xe1\xfe\xd0h\xcf\x9a\x93\xdcb\x91j\xe8\x9cg\xe2\xae\xb9I\xad\xe7A@\xb2\x8c\x9e\x7f\x18\xab\xb9X\xd19#S\xd36\xb5\x90d\xe1u3\x86\x8c\x99\x87\x95\x0e)kn\xe4~Vb\x0dw\x84\xb5\xac\xc4\x1e\xd7\xa4\xbab\xbe\xa5\xc9N\xb7a\x83\xcb\x81\xce\x88,\xb6w\xf6v\xb5\x8a\x91}Uz[\xf0\xe2\xaa\xe7\x02J\x9f\xecCu\xafD\xac\xd1]u\xe4L\xf1\xaf\x96\x9ei\\\xadV\x18\xb0\xb3\x0eS\xb4L\x9b\x93\xfcc\x92Dd\xaa\xe6\x87Xh\xe4\x1a7%2)\x1f\x97'\xeb\xb2\xc1\x1d\x9cy\x98\xde\xea\x13 \x928\x08#r\x91\xfaq\xe6\xb3\xd2O\x9e\xc0\x0d0'\xff\xe1h\xc72YOP\xeem\xa2l\xdb8\xccY6\xcfq;\xe3\xc5<]\xc34\xbf+i\xdb\x8ce\x18\xc3\xbc\x18\xecX\xae}\xa5\x88\xa54\x82\xabu\x1a\xd98\xa9\x9a\x81S\xb0g(\xb5\x0d\x08%\x19\xcd\x9f9.\xdc\xdaH\xfe\x95\xdf\x9e\x18\xc3\xb0?\xa8t\xe6z\xc0 \xfc(\xba\xf6\x83/\xff\xbb \x05\xf1R\x92\x91\\\x11{<\x16\"\xf5\x9a\xe3$\x0fgw\xcf\xa3H\xad\xbd\x1a\xc8\xa5nI\xdd5\xe3\xff1\x1f\xe7j\x98\xd2\x9a\xb2\x9d6\xb8\xf2\x95\xebj\xfa\xd7\xd8\x07\xa2\x19\xcd\xba=i[\xd5R%\x1b\x83v\xdb\xa8\xeb6\xe35\xe2]-\x93\"\xce1\x15\x06lA.\xdf\xb7V{\xd5F\xdej\xe1\xa2\x88G\xeb\xab\x96\xc5\xfe\x18\x8ev-\xc4\x9c\xe2\xb9C\x7ffI\x9a\xdb\xd7\x8e\x0b\xab\xcd\xcdz%Ud\xba*\xaca\xce\xa3\x1a6\xd7\x0b\x17tR\x04:\x9b\xc4\x06\x0fQ\x1f\xe7\xe8jE\xe2i\x18\xcf_\xf2\xd9\xcb\x9a\x0c\x1c\xba\x156\x0b\x96\xb3_xQ2\xbfHVo\xc9\x0d\x89>a\x88'c\xa0\xa3\x1b\x1e\xbd\xd6\x90\x9e(\xf4\xae\x82\"MI\x9cs\xc6\x0c\xf3\x89c\x9e\x03?\xc8E\x1b?3\x16\x0b\x8f\xe4\x88\x8d\xa2\x11g\xcba\n\x03\x8be\x03,VS?',\xb8WD\x97\xd4{\x7fI\xe8\xaa\x14\x0c\\\x1e.\x89\x9dt\x19\xab\x00\x87F\xe6\xadH:K\xd2\xe5g\xac\xf7\xcd\xec=\xa1\x84\x85\x9f\xde\xd9\xa1\x8bF\x0d\xcd\x85\xcct\xa7 *n\xa5F\xcf\xe2)\x8b\x0c\xae\xe7>{D\xbe#\nf \xf1\xaf\xf4\xaf\xedO\x82K\x97\xef\xc2\xe2:\n\x03\x11\xb8\xc6V}>\xfe\xd4\xfc\x95\xd8\xb2\xdf\x19D*R\x9c\x93\\\x1a\x1b\x9f\x90\xac\x03\x8d\xf1\xad8oC\x87\xc2-4I\xfb\xe0\xc4v\xb4\x14z)\x89\x88\x9f\x11\xbb\x89\xa0\x1c\x03\xd6b_\xb6!\xa4Z\x9d\xba\x99\xee@v]\xa1\x86\xf8\xd2\xea&\xb6\xa1\x02i$\x16$\xcf\xd1\x89>M\xc6N\x88\xc2-E\\\xd0\x93\xe2\xd5R\xa1k\xd6\xf3\xa7S\x8a\x9c\xc3x~\x91\xd8w\x8a8\xef\xb6M\xcc\xc9\xa3\x0b\x95h\xf1\xfe\x1e\x16\xc6(Y\xb3\x0e\xb7:\xa1\x88\xbb\x93\x8f\x1c=\x86!b\xf0\xf6\x95HKO\xd7\xc2]9\xad\xba\xd4v\xdaN\x19{\xc3\xa8<}\xf3\xe2\xe4\xd0\x04\xb5\x03-\xfd\x08\xb9|\xd4\xd7\xd6tWG\x8d\x82\xa4\xb3\x06/`\\\xed,2V}\x81^Sn\x8cL\x19\xee\xcb\x9a\xeb\xb4\xcc\x17\xd3\xb2`\x97t,7^\xbd\xaaf\x05m\xfb\x84\xe3\xb9\xcf\x1c\xb5\x97\xe75\xd1\xdbP\xf2\x16\xc3\xec\x05m3\x8c\xe7\xbcQFFb\xa0\x81\x9c\x0b\xe8PZ\xe0]\xb1C\x03\x8b\xbfGm\x08\x17Ji^\x9c`N\xbc!\xd2\x98\xdaQ\xb5\x8ed\x16\x15\xd9\xe2\x85\x02\xd5[\x85\x19\x8a)G\xceT\xca\xcd\xe5\x88/\xf5\xf3g\x16\xb1\x88\x8b\x94L\xc3\xbe\xe5\xb4\xe2>\xbd\xb6\xb0I^\xb0\xfe\x08@\x9f\xe7\xa9\x9f\x93\xf9\xddz}9\xa0}\xd1gOQ\x00\\\x92T\x87\xf8\xc95\xdd:\xbe\xf2Es\xda\xc5GO\xe9G7\xfa\x91\xb5M\x9a\x9f\xf9\xab\x1e\xa9T\x03[\xb3\xe6\\N\x97\xf0[\x8f\xd5\xf5\xd2\x8f\x7f\xc8\xc5\xb2\x06?\xc6&@\x1cP\x10\xc6\xe0c\xe8E\xf25\x87\xdb\x05II\xc1\x87\xe2c\x08\x85\x1c\xaeI\x18\xcf\xc5\xf6\xf4\xe8\xb8\xa6%5\x80\xfds\x19n2\xb2>z\x81\xd6\x19>]C\xce\xb0\x11\xdb{C\xc7l\xb4\xc3q\xc0\x01\x9d!\xbd*\xe9\xf7\x07\x17,\xbf\xa1B\x02FytP\x06r\x13]s\xeaxU\x9c\x8c\x87G\xa84\xc5\xd3.O9\xcc~@\xc1\xf2T\x17\x1f\x07_\x8d\x86\xea\xab\xd0\x14h\xa2\xd4b\xa0\xcd_\x861!\xe4\xf7\xa5\xf6\xa4\xd3[^\xc8tUSWz=@\xd7\x8e\x95\xf5\x0b\xdd\x1d%U|\xaf$\xe5Q\xcf\xe4\xd7,\xe2i\xa9\xa0\xa9\xcc*O\xab1\x8e\x0d]]\xcf\x83\xe8\xbb*D\xc4/\xd9;\xb1\x1b\x18\xd2\xac\x9d@hW\xfa\xae\xd6)\xe3\xfd\x97\xc3JR\xe8H\x86\x00c\xd4\x03U\xddk\x9d\xc3\x7f\xc4\xfc\xad\xd1\xf7\xc7oG\xb3\xd4\x93\xb3\x97J\xc4O}S&\xfc\xd6 \xd0\x9a^Bgx\xfe=\xc6( T\x0d\x86\xe6\xaa\x84\x94\x0bTu\xf2T;\xb6\x9f:.L\xaci\x98\xad\xe8\x01\xf2\x12=\xa9-\x17\xac\xab\xdcOylVz\x1b\xfbyx\xc3\xfc+1\x96c\xf6\x8a\xcd\xf7\xc7\x94\xd0gd\xca\x9eRT\xee\xcf\xd1\x08\xee\xa5\xa94B\x1f\xca\xdd%j\xd8p\xdf\x18K\xdb\x10\x1d\xad4\xfb\xd3ft\x03\\\xd4\xa7\xd8i\x96\x01\x8e{\xe3Y\x0c\x00\xec`\xf0y \x8f=D\xc5\xecX\xfa&\x9e\xf8\x9a\xdc!\x0d\xe8\x08Y\x1d\xe6B\xf5\xd4Y\x87S\xdd\xc31l\xb08\x8e1\xb7\xde\xfb\xa9i\xbc(i\x84\xbd&\"\x80\x13\xa0\xdcU\xd8\xb0\x9aR\xf6\x1bZY\x89\xc8\x9d\x1a\xc4\x81<\xb1\xbe\xfc\x9f\x9acN\xedL\x96\\\xd5\xa7l\xc5\xfa\xf6J\x9c\xea=$L\xcdAmh&\\H \xd4\xd5\xda,\xc9t\xd5\xc4\xabw\x05}\xa1\xea\x8fl\x87\xd9\xf8a\x88\xcc:7#M\x08\xafM~r\x02h\xadf\x9e\x95\xc6\x8c\xb4r\xa7Y\x9e\xac\xa4I\xe9\x00\xda\xfa\x80P\xeaGH(\xcfZ@\xc1\xb0\xea\x0bD\xbd\xbc\xc2\xda\xa3\x13\xa6\x80\xee\xbd\xb8:\xc1\xb1\"i\x86\x99\xc4\xbb\xd7N\x98}d\x85\x19\xdaj\xb4\xd3\xd6\x8c\xfc\xadv\xbf\xd4J\xf7\x96\x9a\xd6\xa6\xa7\x07\xae\x84z\x0c\x0d\x96\xd1\x0c\xf1\x0f\xd3\x84k\xa3\xd3\xeb\x94\x15\x95\xd0\x9aebB\x146\x89//\xb5\x12\xd1j_;.dU\xe7\x98kc\xe6\xf9\xc5|I\xe2\xfce\xe4g\xbd\x1dNd\xb8\xa8\xbe'5\x1f.\x84\x8d!b\xda\x0d\x8fn\x10\x93[\xf5\x18J\x99\xec\xbf\xfc\xd0\xa9\xdda\"\x16\xf9A\x9d\x98\x06\x8c\xa6.\x8f3E&\x18\xfbR>f<\x9e\x8b\x98\xa4\x19\x908H\xa6a<\xafgD\xc8\x17$\xc6\x8d\x87\xc9\xd2\xca\xc3\x0fD\xe0\x17\x1fx\x03\x06e\xb88c\xb9\xc1@/\xd57\xffF\x18\x19\x18\xcc\x04\xf4S\x13\xb5\x88\x85\xc0\x0cCC\x8c\x9b\x1f\x84}n}\xdc<\x9b\xa6\x0f\xac\xa2\x16gp\xbd\x03\x1d\xae\xdb\x17\x0c\xdb=y\x82LO\xb9\x1e\xe4w\xcdC\xbe\x85P\xc3\xd0>\xde\xf5]N\xde\xf2l\xdd1FWA\xcf\xf3\xea1\x1cWv\xcb\xeaV\xfd!\x99\xcd2\x92\xff@\x97@R\xe4\x90\xcc\xe0:)\xe2if\x9a]\xb5MZ9l\x82\x8d\xb6\xfd\x03\xc7\xd8\x0e\xdbs\xfd\xdb\xc9\xeb\x99\xd1\x99!juO!\xd5@\nuE\x80\xae\x08n\xe0\xb1\xee1\x05\xb3\xbe'\xad\x88)oCD\xb4\x00\xcf|\xd8\xbaU4J\xe2\xda\xec\x8f\xf5\xde,\xdd\x04\xa1\xb84\x9f#@\xcb\xe8\x0e\xf7\xf7\xcc\xed\xde*\xf2\xd9a\xdb\xd4od^\x98\x9dq\xbca\xc7\x8ei\x13 \xd4bIh\x83\x1d\n\xac+%\xee\xd1\xed$\x90\xce\xd3\x01\xdc\xc3\x82M\x9c\xde\xe2\x10\xf8\xe1\x8a\xd3\x81\xc7V\xea8\xdem\x1a\xe63/HX\xa7\xdcL\x8d\xe1\x98\x11\x91\x84rZ$\xb9)\x1bUJi\x08\xfag\xf3\x04\x86t`\x18\xbax\xb4\xb7\x07O \x9f\xa4\x1a=\xd7Z#\xd4$^\x85r\xdd<;\xa1\xbc\x95\x89jy^e\x96\xf1#\x0c\xbfB\xf8\xce\x82\xc8O\xe7\x842\xa8~\x0cK\xffk\xb8,\x96\x90\xa1;\xc7\xe0+\xe5\xb3}9\xcd\xf5p\xdfAWNJ6i)\x9e\x12a\xdf\xf7\x1c\xd4\xa2u%J'\x8b\x9c;JH\xcb\xf5\xdb\xb4\x0f\x92\xd6\xdasHe\xbc0\xfb)$,\xd0H\xf31\x9d\x88\xfb{ \x06\x14/\xf7\xb4\"0\x9b\xbd\xd5\xb8\xd6W\x8c\x9e\xa5\x13r\x80\xb4\x9c\xdb\xa1\xc0\xa9\xcd\xb2'\x9a\xedU[\xbe\x1b\xc3\xa3#\xa7\x14\x0d\x1bOB\x14\x88Z~\x16\x84\xa1\xa5\x17\x8b\xb2\x12\x91\x9f\x87\xf1\xb0\xb5\xc8u\x18\xfb\xe9\x9d\xa1\x08H\x12(\xfdq\xc2*A2\xaf\xad\x95\"\x9fm\xb5\x96`\x84vg/^\xdb\xc41\x02\x1c\xaa\xe6\x82l\xd4\xde\x9f \xdb\xea(\x91\xcf\x86\xfb\x11\xe9*\xb3\xd5R\x08\xaa~\x8f\xe0\xc7v\x08.\xc8\xd7\xeeZbx\xf6\xec\x19\x18\xac\xb6\xf9t\xfa\x19\xd9\xdf\xed\xae\xea\xb7.@\n\xa32cE\xa8\xedpzO\x0cp&\xcc\xc6\x1d\x95;\xf5\xe8f.\xcf\x8f\xd6\xf8T\x95\xbe\xeb\xd1\xd7M\x1b\xc7\"\xf6\x16\xd1F\xc6\xe7riz\xfc\xb9\xe2\x10L{5\xba\x94\x98*\x83\xc6\xa1B\x01\xa4\xa4\x189\xc0\xb64\xd3h\x10\xb7\xc4\x94;L\x99\xf0\x1cOn\xe49\xe1\x99,\x91;\xc575\x11\x1d=\xdd\xb7\xca'\x87 b\xa1I\xcf\x1cV\xe1f\xecB\x98\xbd\xf7\xdf\xdb\xb1S\x16K\xf8\xe1\\\xca\xb7\xb6`\xe8\x08\x91\x80(T\xbe\xdcDZ?\xa6\x07 \xe9p\x84@\xcb\x95V8\x00\x8f\xfe$7\xdd\\\x19@\xa2\x8c`m1\xa3\xd7\xcc\xcdm\xf4k\xafk\xf9A\x8bH\x8c\xd9\xdd#\xcf>K\x93%\xe5\x15S\x07\x15\xc35\xae\xac\xc6J\xe5\x15\xfb\xb45\x841\xcc\x95\x15eX!Z\xe1\x13\xaf8\x87'H\xeb\xb8\x069\x83\xe9\xd0\xad\xc4\x17\x92\xf6\x97\xc7\xd9\xc5\x08\xa4\xa7\xadE*\xf5\x04\xe7Z\xb5\x85#?\xcb\xdf\x18>\xc0\xb1O\xf2\xcb\xb6\xd1ky\x97\x1b?* {\xc1\xae0\x08Q\xce\x843Z\xfd\xe8q\x15\xfe\x06d\x12\xb2\xf0l\x86\xd8o\x85\xb4p\xf5%2\x89\n\xd6O\xb1\x14\\\x95\x89\x14\xd8\x89\xc6\xf8\xef\xb4\x8a\xc6\x99*h\x14\xe9!~\xb8q\xa1\x15>\xe0gY\xfd\xd1\x96\xf4\xcc(/@\xb2\xb6\xa2\xd8GL\x18X\xddw\xee+\x9fEO-`\x9bEQ\xe5\x7fc\xfc\xab\xd9o\x8dG\x8a`\xd6\xd4Q\xde\x8dai\x92FX\x00{\xe2\xa5\xc4\x9f~~\x13\xe7\xc3\xfd\x17gv\x0e?\xea\xdc\x18\xf5\xfb\xdc\xa8E\x16\xce\x8e\xa6A#M\x87j\x98#\x08\xe1\x18\x8a#\x0877\xf5L\x19\xf0\xc6px\xa1\x83\xfdG\xad4OQ\x1cp<\x1c\xc2\x16\x04\xadr\x1dQS\xf9!]9\xb4\x9b\xa1\xe3\xb2\xcfa\x93\x03(+\xe7-\xa0\x001V\xc9\x91\xec\x16K\"\xc1j\x0ca\xeb\x84\xf7\xc6\xe5P0 g3lb\xd8\x84\x0c\x9eAQ\x9e$\x05lA\xe60\x7f`\x84\xda3d\xe6\xc2\xad\xad\xb6!\x97\xc4\xf3\x8c\x07\x0b\\1\x1ep\x05\xc7\x90\x1d\xc1\xaa\x0d\xe8P\x03[{>\x1cCz\x04\x9b\x9b~\x1b\xfa\xa0\xc7\x84\x9c\xf7\xa2\xb8\xce\xf2\xd4\xa6|\x82\xef\x02O\x8d\xa1_X8H\xa4\xd6\x8a\x8a\xa0\xf0\xf5e\xc9\x84\xee4f\xba\xdb\x03\xe9\x89\xcaz-\x9a\xeb\x8eE\xc3+{a\xbf\xa6\x1bJ^\x16\x0e\xaa\xe4\x9a&@\xa6\x96\xae\xfa\xb6d6\x18(\xeb\x94smM.]Y\x14V\xb2\xf2L\"\x963\x87K&8\"r\x02\x94\xb8C\xa2\xafK\xa8\x98\xaf;\xe8\xdb~\x83\xae\xc1\xa6W\xc5g\xfd*~a\xff\xb6~\xa7\xbf\xf6\xad\xbb\x97V\xa3\x92W\x96\xde\xb6|\xd6\xa4\xadF\xa4\xa0\x15\x1b\xb6\x9d\xd3\xd3i\x84i!\x1c\xbe \x19+!\xcd\x9f\xcf\xf9M\xcaO\xc3!\x8f\xdaL\xd1\xc6\xde\xbe\x0b!\x9b\xf6\xc4)\x7f\x9a4yF\x94\xfc\xf0\xad\x0b\xfe\xbc\x8d\x9f\xad\xb3\x10t\xd8q\x8d\xc5\x84SH\x91\x07yq\x97\x13\x91\xf1\x9dbU\xf5!WQ\xe5u\x9b\xae\xb6~\xbdl\xeb\x17\x05\xf3;?_x\xcb0.i\xc6\x1e\"[:\x9f\xe8\x1aq\x04 \x8an\xdb\xd0&\xa5\xbd]\xb4\xafu1F\x07\x99$-\xc9\xe5\x03\x11,\xc1X\x82\x9e\xe0\x11e\xa5w\x9e\xc2)\xec\xc2\x98\xdd\x8dv\xe0\x14v\xf8\xdd\xf0\xe9\x10Na\x04c\x93\xe8\x05iE\xd8\x84\x19\x1c\xa3\xb0O\xc8\xeffm4D\x9f\x04\xb8\x11\x1c\xc3ptX\x12rQ\x8b^ \x04\x9da.\xd2'-.m\x8er\x19\xc3\xa7#x\xc2\x88X2\xa1\x83\x1b^:L8@\xd9\x17{g\x08O r\xe0\xf8\x18\xf6\xe1\x1e\xf6w\xe0 %^\x9f\x89\x0cb\xd8\xdd\xec;t\xd7`\xf6).\xb9\x7f<3>\xde\x8d.]e(!\xf6\xbe\xfe\xcc\x97F4\xdc+G4\x1c\xc1=\xd8bL\xf2\x10}:\xc4\xd1`\xf7\x80\x7fw\xcc\x13\x96\xdd\xdf#9+%x\xfb^\xe3\xdf}\xfc\xf8\x8b\xf2ng\x0dh\xd4\x9f\x15\x06\x08\x1d*\x10\x92@\xe6\xd7AV8\"\xef\x1b\xad\x89\x82\x8c\xa5\x92\x1bI`\xd2\x0eQO\x12\x97\xc6X\x94/\xc2\xcfi\xdd;.\xee\xe4!\xc5s\x81\xdc\x9e\x1d\x94i\xe4\\H\x19>\x0f\x98\x18u\x00O\x00\xf3\xc5\xdd\xb3I\xe4\xdc\x0c\xcb%w\x0f<\x95\x1cer\xc4w\x18\x1bg\xf3\x04fM\x8co\xc2\xd2\xdd\x14\xc9M\x19\xa7\xa9M|\x8a\x8aq\x8a^\xbe\x94$\x9f&\x1d\x1d\xb71>\xe7b\x10\x9d\xde\x02$\xdd\x85\xa5\xc9V&\xaeT\xaf\x0c\x04(\xc3\xa2\xa4\xa8=\xa4\xc7\xeb\xe6I\x9f\xce\xf0\xe3&u\x99j\xeeK\x07\x11\x157\x81l7\x8eO\xf9.\xf7\xb8b\xe9\x84\x1e\x0e\xb9w\x1e%\xb7\xe5\x93\xf6y\xd8$U\x84N\x82\x12V\x0dC\xc0\xba\x95y\xa8\xba\xb37\x1b\x1e8\x90{o\xde\x9f\x7f<{yq\xf5\xee\xf9\xffw\xf5\xe2o\x17g\xe7t=\x0dL\xb2\xb8\x139\x89\x0e1\x98\x05\xe9\x9fwy\xf6\x18\x83\xdf\x0b\xdf\x1a\xc5di\xd8a\xa2R\xb3J2\x9fie)\xbd\x00\xb0\xe5\x18N\x92\x1e\x01\x13\xc4\xc5{\xb5\xdb\x94\x1f\x89K\x8f;\x1e\\\xd8\x1dqZi\x96$\xb6c\x14\x87\x12\xca\x901K\xd3'O\x84'x\xf9\xcc\x1eb\xc2\xbcJ\xa9\xd8\\\xaa\x9d\xd9\x0d\xf8\x1864\xb2\x93\xfa\xbab\xf1u\xbe\xbc\xf3\xbf\x96\x91\xa3|\x1b\x05\xcb\xab$\x89\xce\xc3\xdf\xe8t\x1e\x0e\x9fb\xf2\xa1+\xeea\xd3\xb9\xe2\xb5\x13[sJT=\xbf\xb8`\xbb\x87\x1f\x8cT\x7fd\xf3\xf0EZ\x0b\xcc\x16!\xb5\xec Y\xeb\xa3v]\xd1\x91k\xcb\xb8\x06\xfb\xc9st\xf5\xa7\x0d\xb1_\x18\x1cJ+!\x13\xdetY\xa9Xa_hmM\x98\xe1K\xdd\xd5\xad\xcd\xccAV\xec16\x08\x02ZGc\xdf\xd43\xd0\xc9\xb5\xd5\\j\xb5\xd0B\x0c\x933\x0c\xd2\"\xd5\xa5\xbc\x07\x99\xc4\x97FvK\xc8\xa5j\xc7\x83\xad\xcb\xb3\x0f\xdcV\xdc\x84\xee\xcc\xbd0\x13\xe7>7F1\xb3\x812\n\xf7\xff\xa0\xf9\xa3\x97\xcf\x8c\xb9Q\x13\xce\x19_\xe1 \xdf\xb1\x16\xa1Z\xb7is\x91J\xce\x1e'\xb0p\xa1F\xe9I\xc7\xe7\xc6\xa0\xfe.\xbb\xf5W\xc3\xfd\xb6x\x9d\xa0\x06\x0fh\xd3\x13\x11\xad\x9eH6\xd7\xe4=\xc9(\x89]\x99\x0e/\x8b(\x0fW\x11\xa1\x10\x1c\xeeo]\x87\xb9\xf6X\xac)\x1a\x06Gh\xbeK\x8e\xd8\xf2\x1b9p#\xe2\x9f\xba\x98\xb4R\xc7\x7f e\x82\x1cB\x04\x04\x10\xeb`\xd9\x19}W\xb0\xec~#XvF\x8f\x02\xcbn\x03,;\x8e[=\xa2`b\x7ftZ\xb85\xa0\xb5\xbf\xfb]\xa1u\xf8\x8d\xd0\xda\xdf}\x14\xb4\x0e\x1b\xd0:\xd0Ck_y\x9d\xe8\xda\xf9\x83F0\xcc\xe6LX}a\xfc\x16x&\x8f\xa7\xf2(\xb1\xfa\xd5\x8b~S\xb1Z\x890\x90\x90\x1f\xa2\x19\x1e.\xba>M\xa0\xd9(\x96>>\xa1\xbd\xe5w\x9d\x1f\xe3\xeac \xa4\x89\xe4\xcc%\x19(\x1b\xa5\x1b\xd0\x83\xee\x14\x17\xef\xc5\xc7j1\x9b\x9c\xac\xa0\x0f\xb5\n\xbd(Vq\xf1\xc6_\xae\xd3x\x1b\x9d+.^\xef\xf3u\xeam\xa5\x8e\xa1\x1f\x85,.\xde\xfe\x87u\xda\xef\xb4\x1d\x86\xaa\xe2\xf3u*n\xa1\xc6\xa1\x17E\x0e=\xa9rX\x872\x87j4\x17\xfdF\xd3I\xac\x03\x94v\xd1Z\xc6\xfa3\x8b\x0eUz+\x8e\xb51\x14\xd4\x8b0w\xc4M\xb0\xac\xbef\xd3\xa0\xa5\xc9\x1eD\x0c\x12\x1c\xac)\x0cI\x1d\xa9\x93_\x0b?j\x8f\x1f\x01ZiC\x87lA:\x0c\x85\x8df\xeb\xc1\xc3\xcf\x80\xfb{\x8e,KY\x88\xde/\\\x19E\x18g+L+\xd6\xefd2)F\x98\xffRC\xca\xdf\xdaqq>=\xe3f\xd3%]Q\xba\xf3 \x8e\xe4\xfe\x92\xde\xd2\xcf\x83\x85\xbd\xed\xfd>z\xd8\x9e;\xde\xdf\x930\xb6-\xb0Dx\xb0\xb22\x9e\xec\x89\xa5P\xf7<\x0f,\xc7q\xc1:\xe6\xf4\x06\xae+]6\xf4:\\\x0c\xf2\xa4N\xa3\xf6\xef?\xd5*\x8fW;YU\xcfmf{\x8e\xda\x11\x0e\x90\xb1Z.-\xed\xb6\x94\x17\xcc\xd6,i\x9c\xa8\xb9\xf0u\xa7'pY\xef\xfd=\np\x06,\xd5\x9cr4\xeb)>\xee\x8f\x9e\xd2G\x80\xf6\xd1\xa6\xf1\xa6\xf0\x8c\xf7'\xa7\xbfZ\xdd\x84\xaa\xf2\x9d.\x04Je\xe6RH\x07\xb8\x10\x97\xbf\xd2\xf2WR\xfe\xaa6_/\xf1^\x88\xae\x03[t\xf5`\x0e,\xd8\xa2\xcb\xa9\x90%z\xa1\x0b\xbe\xc3\xcc7\x10\x9c\xa5^0\xe1*\xd8\x9ae\n\xd3\xec\x0e\x8e`\xc6\x0ci77gf `4\x991 `0\x99\xb5J\x00i7ia\xd6KZ\xda\x8c\x83\x1f!\x01\x0c\xe1\x18\x8d\x90Q\x02\xe8\xc31\x84f \xa0\x8c\xa5\x82\xa8\x98\x92>\xb1\xc6\xa4\xb6\xb8q.\x82\x92\x9b\xe3\xdbf z\xd3\xba\x7f\xad\xc6\x96\xf5\x90\x1a\x98:\xaf\xad\x11\xc9\xe4\xff[\x1b\x1a\xb66\x84\x1e\xfaz\x0cf=\xbdp\xdf\xd4E\x10\x86\x1cm}\xa5\x10?X\xac\x0f\xda0@\\X\"\xe2\x87\x984\xd99\xba\xa8\xf1\xe5\x1f\x1a\x03\x03\xa9\x91\xfe\xd4\xd8t\xa6\xeacz&IB\x07s\x1c\xcc)\xf9\n\xb2x\xa1'D\xff\xde\xc1\x0c\xe5\xa5O\x7f\xce\xed\xa9\xf7p\xc2\xf5z\xc9\xda\xeeU\xadud\xaf\x17\x17Fu\xc3\x1d\xee\x8e\x96\\\x02\xea!\x9e`P\x9e\xe3c8\x84\x1f)\xfd{\n \x8ca\x08[\x908\x0e\xdahk^\xf4\x1a\xf0\xfb\xb5\x06\xbc;z\xba\xfbt\xff`\xf4\xf4;\x8dz\xd7<\xea\xbc9\xac\x1d\x1c\x16\x03F\xaf\xc1}\xea\xbd?\xbeea\x99\x96j\x0b>y\xf4\xfa|U\x1bQ[J\xc6\x90\xeeB\x04\xc0\xc0e\xa0v!\xe1<\xae\\\xc7h\x87\xbd\xa3\x10\xd8\xed\xd5\x87\xb7\x8f\xee\xc3\xa1\xa1\x0f{#\xf6\x8e\xf6\xe1P\xe9\x83|\x97\xa9t]\x1f\xfb\x1d\xe1\x15\xd7OI}\x02\xff\xfd\xdf\xc4U\x83`\xe6p\x8a\xa9Z\xfe\xfb\xbfs\x97\x9d\x14,\x0c\xe5&=\xb5\xcb\x1dBD\xc4\x11B\x0f\xf6\xf2Q\xeaT!\xc9\xec\\\xf9&\x17\xdf\xe4\xe57\xb9\xf4\x0d)\x9f\x10\xc7`\x03\xecT:\xcf\xd2\xea\x1aaa\x0c\x90\xb9\x96\xfc\xa4\xa4\xc0`K\x8d\xcb/\xae\xb8\x0c\xf3\x9b\x08q\x86\x81\xbb\xa81\xe7\x9cNH8\x19\x13S\"\x80\x0d\x04)\x00\xd2\x95\n\x07\xaa\x85V\xf7\x80P\xd8\x0f\x11\xd5\xe0\xedYO\xb9\x1a\xe1\x92\x19!\xb8A\xaaM\x90\x13\xb2|\xa3\x05\xf7\x89\xe56!\xdcgoX\x12G\x9b\x9bt\xd89\x17\xae\xffxB\xe9\x1e\xe7\x88\x13\xb5\xec\x1b\xd8\x84\xf0\x12~\xd4\xb9v\xebIY\xfd\x88_\xfccF\x0c\x9b\xb0\xb5\x95\x8bq\x1f\xe1\xd2\x1et\x0c\x97~\xf0\xed\x03>\xec\x83\x10\x84\xc6\xa9\x1c\xe3\xd0U\x15\x1cl\xe2\xfa\xb48\xdco.\xab^\x8d\x8e\x0c\x8drK\x0f\x04\xca\xf0\x12\xcf\xfc~\xfdhN\xf6\xb7\xf5\x03\xa9\x8dZg\xfa\xf4cg\xf4Hx\xec\xaa\xfd\xb0\xcd\x00\x91\x1f\x8d\xf0\x11\x8b\xf37\xdc?88\x18\x0d)\x17Q\xbe\xdf\xe9\xd9\xedG\x82\xaf\xd1\xedF\x1f(gc+#\x18\xee7\x87P\x1b\xd5\xcee\xab\x08\x9fv\xfb\xff:\x8c\x06\xcfN\xf8\xe7\xc3\xd1\xa1\xc3E\xe1[\x9cv\\%\xb76\xa5\x12(X\x1d\xc7\xedF\x07\xff\x10\xf4W\x03\x8c\x84\xdb\xd2\xcb#$/\x9bX0T\xb0`\xda\x0e\xa4P\x03\xa4\xd0\x08\xa4\xb0\x07\x90\xbe\x13\xcaD\xdf\xebr\xc5\xa3:\xefG\xc0\x88\x10[\xd2>@\xaf\xd3\x9e\xd8u\x0d\xe4j\xc4fM8\xde\x88\xd8\xaaF\xe4b\x84\xfd\xce\xe8`\x9f\x0e2\x86S\xc6\x08\x0d\x86\x07\xfb\x03\xb8\x87\x18\xc6\xdd\x14\xc8\x1a8\xfa\xd1\xc3a\x83\xb8\xaf\xa1\xf0?n8\xdf\x0f\xd5\xaf\x87\xe9\xebx\x92>\x1b\xed\xf6\xean?\xe8\xf7\xef.\xb6\xdc\xect\x0f\xe4\xde\xd5\xdd\xd7Q\xe2k\xb0\xfb\xe3\xba\x9b`\x95\x95\xa2ac \xb8\xbe^\xdd\xf8^Pktc\xd8\xb7\x1b\xaf\x92\xe2:\"\x8f\x04\xc7ag?\x06\x82\x01\xed\xd7\x8fG\xc2\xa3\xbb\x1f\xc3>\xfd@\xe6\xd9\xc8\xcd\x18\x848\xc8\x86n\x92\xda\x01\xc7\xacXPm\xfbF5 P\x0f\x93\xd8\x81-\x8a\xf2M\x8e(\x899\xc6_\xd8\xe2\xf4\x81\x1b\"\xafBN\x13AI\xc4\x8dc\x92\x15eD\xc4 \x10\xd8\x86\x84\xc9\x81\x8c\xe8\x8d\x16n\xc5b%$\xb5d\xc2?\x10\x921\x161BSc\xa4$AS\x88\xcfJ\x88nm%\x18 \x8e\x93\n\x1a\x90&\x02\xa4\xe1w\x03i\x83\xa8h\xb7`\xd1\x00U\x85%E\x16{{.\xeaQ\x8c\xf9~pv\x10\xe4\xb3(IP\xd2\xcd\xb1\xb5\xbc\xca\xb8\xc9\x7f\xaf\x81\xe8(\x90o\x1e\xcb\xc8e\x92\xe3\xb6\xd1\x9cj\xb6\x87[\xcd\xd9\x90\xcd\x19\x8aH)M\xf5\xf7Z\x03,G*=|z\x0e\xb27\xa5\xfc\x07\x0e\x92\x8fF\x1d$\x1f\xbbf\x90\xc3\xb5\x06\xa9\xa3V\xbey\x90\xbb\xae$\x12\xef5RF\xb3\x88\xd1\x8ev\xa5\xe1\x8e\xaa\xe7\xc3}\xc3\\k\x963\x85\xcc{\xfd\xf4\xb7\x92E\x12d\xfe\x80\xe9_\x1f2\x06\xa8\x0c\x0dP\x19\xe9\xd7\xccN;d\x86\xbd!\xb3\xe6\x11+\xa4\xc72X6\x8c\x06G\x02\xd57\x8e\x07\x0c\x1d\xad\x97\x9d6\xce\x96\x84\x1d%[\x1a7o\xbd=\x18\x9e\xc5\xfa\x83\xa5#J\xef#Op_:n\x88\x10y3\x89z\xc1~\nsLv\xb6\xd3\x01]\xe2\x97\x05\x86(r\x95s\xdf\xa6\xa7\x94\x0f\xcf\x9e\xc1\x80\x9e\xa3\xc5w9\xaf\xd6\xa4\x00\xfeO\x99\xe8\x16*\xe2\x9b&[\xcc\x85D`\x84\x15\x81\xb1\xf6\x8co\xfecf\xfc\x0f!P\x86\xa3\x03\x17\xb6\x86\xa3\xc3\xb5i\x14R\xd3!Q\xd02\x9f\x84\xe1\xb7\xd0/\x7f \xf9\xb23:\xd8\xa7cE\x19B?\xd4\xfe\x07\xd20\x7f \xf3\x88\x81\xfe\x81t\xcc\x1fH\xc6T\xf9\x10\\%\xedA\x8f!\xb7\xcfm\x0f\x12\xa7F\x12}\x13A\xf3\x07\xd23f\x10\xd5\xb7o\xcdHB\xec\xe2\x1eP\xfc'\"~\x0c\xf2\xa7v(\xbeR\xe6\xac\xcb\xab\xa2ji\xdd\xf9RZ\x1a\xf6j\xc9$Ejo\xea\xedc\x06e\x12\x14\xad\xd5T\xe7\xa8\x82du\xb7\x1e\xddR\xa5\x9b\x1c\xa0Cd\xe9\"X\xd9\xd5\xe7\x8a\xa7\x97\x94\xa5\xa42E\x90\x0b\xd0\x0f\xf3\xb2F\xae\xe2HK\x12\x10\x9d\x17\x98\xf7eWz\xa7\xb0\x11 \xa5\xea\xa0\xdc\xad\x8e*\xf26\xc3\x9b\xdcO\xe7$?\xcf\xfd4\xef\xce\x86Z\x9a\xf1\x003\xd6T\xba\xa1o!K\x8a4 k\xb4\x90\xb6\xf5\x97\xd5v\x16O\xbb\xebJ\xeb\xce\x17%\xf4\xeb3*\xd9_\xe5\x18{iK\x9a\xa8\xda\xcbM\xadU.\x12\xb4L\xbf\x95\xea\xe3\xd6\xe3\x1cTn\xa8\x18t\x99+\x07\xb1\xc5\x96\x904 \xb0t \xc3#HxV\x83\xad-4\x0bK`\x13\x10I\"\xae\xa3w\xba\xb8/\xa5\x93\x11eA\x86d\x07X\x18\xaf\xf5\xb2\xfe\xb105\x8aY\xda\x1a\xedk\xf3\xb9d$\xaf\xf2\xb8\xd4Lubf\xf6\x14:\xfa\\\x98B\xef\xd7\x86\x08fa\x14\xad\x87\x084NWkg\xb6\x16\xe9 0\xa4\x06?6\x95\x1d\xa2M\x9f+\xe1\x85\xe6'.\xcf\xba\xd1\x95\x19 $\xde\xaa\x16\xb0\xdcdy\x04\x18\x80\xe8\x18m\x8c\xc5Am\x88\x8ff\xce\xb7\xaa&\x9b\xd1\xe4\xc33\xf9\xb3\x97\x19\xbf\xfb&\xf36\x80\x1d\xdb\xad\xe7\x02NM^\xc5&\xcf\x8fF{\x95\x12`:-\xc9\x9b)\xcb-\xe2T\xe9\x17a9\x00n\xab\x87>\xca\xb5A\x08\xbc\xe8OB\xf8_P\xaca\xb3\x977b\xe4\xd4\xfb@\x07\xfb\x19N`{\xf2\x9f\x9b\xbfl\x0f\xb6\x9e>\xdf\xfa\x0f\x7f\xeb\xb7\xad\xab\xcb\xed\xb9\xc9\xf5\xe6\xd7\xf6\x10\xae\x80\xca\xd9S\xb0\x06\xe8\xf4_O\x13:V\x1e\xd4\xfbfh\xf0\xb5Q\x01x\xa3\x0f\xd0\x96\x03\x8f\x8a3\x84\xed\xce\x1c\x97\x95\x83L\"\xc2\xf3\xeb\xf2:\xb4\xa7P Y`\x9bFb\x07\x07\x9ea4\xef=qD\xef\x1d\xec\xec\xee\xb6!\xdc\x90\xe7\x873\x97\x80r\x93>\x83\xbd\xfd\x9d\xe1\xd3\xae\xc2\xf4b\x89(vh\x7f\xb6\x86\xb43<\x99\xc4h\xe7\xa9\x0b\xc3\xa7C\x17\x86\x87O[\xd0\xba\xb8\x82$\xce\xc3\xb8\xd0\xe7R\x12\x979{\x10\xf0\xbe\xfb R?\x19\xa5z\xf2\xf5O\xd4{\\$\xed-u\xb6\xd2\x9e] \x97\xc9\xfe\xce\xc8\x98BP\\\xfd\xa0\xe2\xfe\xc1]\x8e\xb9\x8f\xc6>lR\xban\x8b\xa7 8>\x86!3t\xd9\xe2\xa3\xd1\xd6\xc0O\xc5\x84\xf3==\xc6c>\xc9\xab\xfd\x1b\xb3D\x15]\xfb\x8c58d\xd9Y\xba\xd2\x1f\xf0\xce\xc4\xad\xe3\x10\xf37\x1a\xec\xf6l}\xb4^\xeb\xf0\xec\x19\xe62\xc0\x00\xdb\x98\xd0 \xa6w\xa3\xc3^\xdd\xc2y\xea\xd7\xaf\x9d\xf5\xfb\x85I\x17F\xa3]\x16\xc2\x03\xf6\xe1 \xed!\xf6n\x8d\xbev\xa0F\x1c\x07O\xd9\xa0\x8b3 \xd2i\x05\xc9\x94\xc0*1x\x91\xc9U\xb2\xf1\xee>b\xbc\x87t\xbc\xbb\xe4\xeb*I\xf3\x0cN\xe0\xf7\x07\x89v,\xc1\x106<\xd2\x1b\x9b7#\xf9E\xb8$I\x91\xc3\xc2g~\xa0\xd7\x84\xc4 B\xe6W\xf0~\xd04\xe0w7\x10D\xc4O\xbf\xa1\x89\xa2\xb9\xe0\x19n\xc5\x18`e\xef\xab\xe8\xc2\xe5#\n>\x95o\x16T\xe3\xc9 \xf3\xe2\xda`\xf9\x8e5\xf5\xd0C\xb6z\xecv\xd4\xab\xcf\xb7!\xaab_\xd4\x97\x81\xc8\x0f\xa17\x955\xa6\xef\x10U\xb2\xa5SF\xcb\xd79\xfc\xb7\xb6\xd0\xac\xab\x94\xd2v\x07\x0f\xa8&l\xa3Z\xac\x8d\x95\xa0\x1d\x03f\x9d\x11\xdf\xc8\xbc\xa6\xb4\x10O\xe5\x9b\xb1\x8av[\x13k\xd0\xeaU4-\xdf\x19\xe6\xc9\xd4\xa9\xda\xe2=\xad\xdf\x8e\xd5,\x89\xad\x1d\xa3M\xa8Y\x15\xcb_\xb6\xb4\x9a\xe8\x1e\xe7\xa9\xcd&Jb\xb3\x00C\xbf\xd4\x9f\xcdx\x12\xda\xe6\xc6Y5f\x04\xb3\xb7b\x1a\x0b\x9bW\x05\xa5X\xe0\x14[\x14\x01\xc4\xed\x08\xc3\xa7b\xdd.D\x92\xecuj;\xed\xfbu\xdah\x16\x89\x88\xc0\xc4L\xd2\xb3\xad\xb0W\x1a\x8a\x01\xfb\xd8\xc6KR\xa6S\xf4\xed\x083\x11\xe9\xd79~@\xb1d$\xe0\x8aA\xc4x\xf6\"\x9e\xf2cv\xe9\xa5El\x9b<\xfc8(\xe4&;v \xf0D\xcfl\x8f\xea\xe6N\\\xfd\x8ev&T\xa7\x98K^\x86U\x1a_\xe9\xa1\xdd\x16P\x12Q \xab\xc8G\x14\xc8b5h+\xa5\xabV~\xe1\xf6o\xc6\x8c\xc2\xc4\x95\xda\x06\xf9\x12\xf4\xc2^\xe2\xean\x08d\xf2K\xc6\x9b\xe6\xe6a\xad.@\xa3\x01\x8eL;\x1a0\x8f^\xfb\xe6A\x05\xd8C\xebN\\h\x858(\x0b\x9c\x15(9\xe1B{\x96\xe6\xe8D\xcaZ\xaa\xab\xee\x86n\xec\xaa\xc5\xc4\x8b\xc9\xd7\xfc\"\x0c\xbe\xb4\x12\xa7b\x9fR\x8a\x80\xd1\xbc\x8d\xb8\xcdM\x93!\x94W\xa8\xc5\x9e\xc1\xb0 \xce\x12\x17\xc4\xcc'\x93\xb2*\xea\x97G\x10onRr-f\x86XR\xe8\xe8F\x98\xfd\x883\x1b\xe4V\x80\x0fe\xf7\x98\x15Z\xa2\x07\x03\xfa_aO%T\xe8\xc2B\xb6\xabG\x00\x9b\xcfF> <\x1c+[\x8e\xd5\\\xd4\xaaM\xbc<\xcc#\x0cJz\x9d&\xb7\x19I-\xfa\x90\xff\xe6a\xf2\x13\x8f\xc47H\x07\xd2\xdf~:\xbf\x11y5\xbd\x1b\x92ft\xfeX$\x93\xf2>+K\xe3\xbb\x1b\xfcn:}\x1bf9\x89\xb1\xde\x1b\xf6\x12\xdd\xd1\xd9\xef\xd9L\xfcL\xc92\xb9!ja\xf6\xf4y\x14\x89\x17\x99xC\x96a.~\xafR\xb2\"q\xa3%\xfe\xf8C\x1c4\xea\x8d\xa4\xea\xccK\x8d\xef\xc0\xc9e\x1dz\xd7a\xdc\x99\\\xa5A\xb5\xae\xd2$ YV~\xccC\xa4HA\xf1\xea\x8d\x04\xb7\xd3\xb6\xf9\x16\xac\xd2\xb6\xa5|\xb6\x98\x86\xe9\xe3z\xc6>\xed\xeaW\xb1\xf4\xb3/=z6\x90\xb6>h\xb8\x10E\xc5o\x15\x19AEO\x90KL\x9c\xcc\x90\x98G\x84\x1a\xa0\x8a\xd8\xda\x90Uu:}\x0f\x06\xb1\x15\x03\xf5\xcb\x8aU\x19C\x83k|\xc4@\x9aH/\xd5\xe2\xd0\xca\xbe\xe6\xa4\x0bk&f\x94\xd8\xc0p\xc7'0\xa4\x88E\xd2\xdeT\x98jx\xc9\x835\xc8\x8f\x9a\xf4DlLx+duZ\xb0\x19\xd7\x07\xa8\xc2{\xb5\xd7Lt\xcfP{\xea\xa8\x02|\x9fb\xdep\xe2\xd7\xb1\xaeof\x961\x17\xd6\x86\x88\xa2\x19\x0b\xd0 \xc3&\x91\xa1\xa1GnHzW\xcb\"\xdd\x95\xda\x0c\x19\xb7x\x92^j\xf8\x1bts\xb1\x19W\xcdp2\x9b\x04\x17B\xc7a:\xb5\xd05s\xf2Z\xde\xbb1\xf15\xc2\xb5 \xc7\xb8\x84cN\x0f;8\xc5\xe0\x14C\x1e\xd98e\x07\x1c\xcb\xb9 )\x85k3\xa9\x9d\xe4-\xa0\x16\x97\x00]\xfb\xa6\xef\x03}6\xc4Y\x9a,[Yv;4\xcc\xc3\x83\xf1\xb8\x8f\xbc\x94dE\x94\xbf.\xe2\x80\xae%\x17\x9f\x04\xc9rU\xe4~\xce\xd9\x94\xce\xcd&6Z\xe3\xe5\x03\xab/#\xf9\xa7GWJgH[q\xed\xa1L\x0c\x88_\xb9wuE\xb2w\xc9\xb4@\xf6\x8d\xf2i\x98:\xd6/\xa2\xfc\x1dY&,soB\x9f\"\xda$\x02\x8b\xbedH\x94\x11\x1d\xe5\xcb<-\x82\xbcH\xc9\xb4D\xb6}\x18\xefGP\x99\xbeBe6\x99s+\xc1<\xb8F\xea]\xc8\xfeM\x1dg\x87C\x06\xb30\xcd\xf2*^\";\x18\xfc\x18X\xf5p\xbb )\x01\xe2\x07\x0bX\xf1\\\xbb\x94\x11\xf0A\x9c%\x9a\xa3\xc3Gk\xb0\xb2SG\x0d\xa0\xd0\xbd\xc6\xd3\xf8~!wYC\x88UR\x8bq\x1dU\xb5\xf9\xc3\xd3\x0dY_\x0e\x8e\xdb\x93\xe4\"Z\x84\x9cW\x08\x81\xd3~\x03F\xfb\x11N\xfb\xe5\x93\xb4\x9d\xee\x03i(^J\xa6E@l\x85\x13\xea\"\x98\xc9\x84R\xcb\x97\xcc\x18R\xa3\x8es\xe1\xf7\x07E %\xb1\x9fu\x91\xb6\x8f\x04L}\x99\xd3\xf5m'z\xb5\x97\xc2\xa7 \xee#\xb6\x87\xc3\x03\xe5@D\xc6\xc6\x1e\xed\xee8zV4\xb6\x87\x83\x01\xa5\xfc\xda\x1a\x00Y\x84'\xd2'$6Z\xabK\x83\xea\x91TLZ\x12\xcc\x18tM\x96\xb4\x1a\xea\xc1\xaeaD\xed\xcc\xf5\x86\x1c\x0b\xd5\xc4G\x8b=\xb6\xf1H>Z\xedq\xac*$\xeb\xfb\x8e\xc9\x9c\xc6`\x8d\xbc=o\xcf\xd2\xad\x12\x8d\xfd\xe1\xd5\x153\xd4\xa4\x7fO\x84\xdb@o\xf0\x8d\x0e\x0e\xd6\x86\x9f\xcc\x85\xca)\xe7j\xb2\xeau\xa7Q\xbf`\xf7\x0ev\x95\xe7!\x7f\xbe\xa7<\xa7{\xc7\x9ap\x9c\xf8\xbe\x88\xa2K%Tx!\x17\xf8,\xd2\x9d\xab\xa524n?E\x13\x04f\x0fx\xe1\xcf\xcb\xcc\xde\xdf\x01R\xd2\x89Bo\x0b\xcc|2\xe6\n\x16\x08c\x8ev\x99q'\nF\xc6\xc8&?\x16\xb0{OGz\xc8>\xdd\xeb\x9cx\x0d\xbd,\x96q\xc2\xdej\xb7E\xca\xb2\\\xc4%\xd8\x1e\xdb\xf7\xd1Su\x96Y\xdf\xf7w\xd41\xb1Uqp\xd89$\xc3\x0c\x85\x0c\xde)\x83w\xb26\xbc\xf5\xb2> !\xef\x0e4#\x91NXJl\xb4\x93\xd4\x82V\x99h\xce0\x89s c\xa42\x84U\x98\xf9\xbc\xab\xbdx0\xc0\xad>\x96\x90\x1f\x14\xfbR\xb5\xa1\x17\xc6\x0b\x92\x86\xfc\x149\x1c:\xcd3-\xb6w\x06\xeaL\x16\xac\xae\xda*\xac\xea\xb2g.\xf8\xd2\x9br\x80\x19\xae\xbd\xa2\xd2\"\xf0\x14I\x83#\x88\xe0\x18*uFD \x80\xe6\xda\xa5\x04t6\x89\x14\x18\xce\xaa\xfa&\xc1%\x8a\xb9\x94G\x94)\x93\x1f\xb4\xebwg\x86C\x879\xc7\x88@\xda\xc9\x0cfU~IJ\x12\xce\x1a\x84\x96_W\x95\xb9P\xa8\x0f\x10\xfbo\x08\xd7\x89\x94\xf8S\xff:\xe2\xb1c\x17aV=9a^\x80\xf5\xf2\xb7i\x98\xd7\xcb\x97Oxy\xa6q\x89\xa2\xe4\xf6\xaf~4\xfb\xb0\"1'\xd3\xeb\x15\xd5K\x94\xb55>,\xabL\xe2\x80\xd8\x16\x89\xa7\x96\x0b\xabvp6\xb5\xf4\x9a\xba\x85\xc3\xc1\x95\x18\xc0y\xee\xe7\xc4#\xf1\x94L\xe9\xcb\xb4\xd4\xc5\xd9S\xd6\x85.\x1d}c\x0e\xb16[E\x0d\xf4\xe2;\x99\x1d*\x1f9\x19.\xaf!\x17,\xd1\xaf\xbf\x86\xf3\xc5\xcf~N\xd2w~\xfa\xc5r\xd56\xe2bIRZn\xdc\xd0\x85\xcfI>n\xa7\x98\xc5\xe6\xd6\x00b!7[\xdf\xfc\xd5\x80\x1c\xb7\xd7P\xa6$\xcb\xd3\xe4\x8eL\x1b\xdd\xef\xddE\xc9\x9f\x86\xf5V\xacS\xec-]@\x8d\x12\xb5\xf1TK\xac\xfe\xa5W\xf6\x0d\xbd\xce4\x80(\x0b(d\xb9B\x08\xd4\x06\xa2\xc7\xc8\x7f\xfc\x10*\xfd\xb3i\x10\xb4\x88Q\xe1M\x19,I\xe1z\xc5\xbf\xea:\xe4\xb1Av\x80\x14Q$6,\xae}W\xdeGyM{\xff]\x0e\xca\x9d\xe1\xc8\xb1\x1f{\x8a\x93\xca=\xabT\x91t\xd1\xe8k\xf6o\xff@w\x90\xb3\x10\xf7\xfe\xd7G\xf6;\xb1\x07.\xd2\x1e\xdf\x00\xccu\xcbk\xa9\x94\xa1flvl\x1f:]\xf2\xbe\x90;~z\xe2l\xfb\x98$\xc2\x16\xc0\xc4@\x0b\x82\xa6\xf9\x1d*8\xf4\xb2;\x19\xc1 \xc3Pz\n6\x05\xd6F\x0bez\xd0\xd2\xef\x1b\x86\"\x1a\x9a\xb2}\xd4D>\xca\xf1h\xa7\xe7\x8cm\x8d\xf6,t\xb7\xc5\xedVP.\xde\x16\x9bH\x03\x1f8\xe6\x1b.I\xa2\xf3\xf07R\xe2\xad:L\xe8vl\xa4o\xad\xdd\xfa((\xab=*\x1a\\&\x16\x9cNi\x9d\x94\xb9I\xc6\xed\xa8@\\%\xfb\xda:-q\xad\xcf\xdc\xba\"\xf6\xe6$\xa7\xf7\x88\xac\xd0\x01\xca\xa7O\xcb\xf1\xa2czu{\x02\xc3\x81C\x0b\xa4$\"~F\x98\x84\xaf)\xa1}\xd0\xa8oc\"\xd2\xa9b\x83\xe9X\x05\x08\xbd\xf2\xdbD-\xd5\x0b\x06\x8fY\xe4 \xeb\xa6\xd6Y\xe8\xa0[\xec1\x8b\x10\xe0\xe8\xc0\x01\xda5\x0f\xbauO\xab\xe8\x03\xce|\x91\x92\x06@\xbbD;\xe2\xfa\x16h\xa5\xdf\x05Zi\x19G\xa9\x114Z\\\xfd\x01\xd6\x88\xc8\x00z\x98\xcd\x92\"\xed\x02Y\x8bT\xf1[\xa0\x96|\x17\xa8%R\xf4\xa9\xd4Q\xf5\xf9\xe2Z\x0bp\xae\xd6\xf1\xb8\x8e\xca\xf4Gg\x81O\xdb\xe4ju\x03\x7fmq\xb3\x98tO\x95.%\xfcy\xb7l\xc4p\x94\xa7v\xb2\xfe9.\xf7\xe8\xd1-s\xb9\xd1#\xc8\x08\x89\xfa\xda\xd1\xcb\x8a\x0e\xb5\xe2\x96\xe1P}\xce\x98\xfd\xe1\xfe\x81c[Y\x1aX\x1a\x9e\xff5\xefH)_k\xca\xdfX\xfe\xc1\xc2\xf1\xb2U\x14\xe6\xb6%J\xcaR\xd8\xd8\xde\x1f8\"a\xf99F\xca\xe8\x03$\xce=\x93\x9a\x05\x98m\x94~\xe1\xda-tr\x84\xc8d\x0d\xafx4FH\xe4\x87\x14s[\xb1\xbf$\x16\x1a\xd1$\xd5=7\x9fDIxi\xd2cK\x9f\xf9\xd5\x17>/\x87\xf2\xd6M\xf6{\x0c\x19\xb3H\xe0\xde\xcb\xb9\xe3\xb0\xa8b,\xb6\xcbi)c\x871\x14\xe2\xb6\xf64\xa9\xd6\xc4\x18\xec)\x89HN\xf0\xbd+\xbd\x92\xd7\x94c\x97\x93(3\x85\xe54\xb5hu\xf84h!\x87\x04\x14\xa7}&>Ja$a\x87\xdc\xfeZH\xa1sM\x94z:9\xf4\xc1\xa9\xc4A\xc0\xb8\xcb^\xa5\xd76\xeb\xa4\xbe\xf5\x9bo\xb4o\x10\x81\xef\xeckw\xdf\xde\xaeJ\xc53Q\xdb\x81Z<\xe3\xc5UYj\xc4\x9f\xab\x12\xbb\x80?W\xeb\x99\xf1\xe7*2X\xa1\xd0\x8ci\xb3\xce\"B\x0f\xc4z\x81\xa9T\xe0\xb5O\xc9\xe4\xbbz\x81\x05+\x10%\xb1\xbe\x82\x1b8\x81\xb4\xfeh\xd9I\xb47t7\xd0<\xc8\xe7Z\xb2\xf9\xe5\"\x8c\xa6)\x89\xc7\x86sx\xe9\xaf\xc6\x10zK\x7f\xd5$\x0b\x80 1\xcf\xfc`A\xcb\xf0\x9f\xfarAR\xc49-\x85?\xf4e\xf2\x045\x9f\xb4\x14\xff\xa9/\x97\xc4\xd1\xdd\x18f\x8dw\x1a\xca\xe5e\xb2\\%1\xa1M'^y\xd3,\xf7\xb1HI\xadl\xedA\xb3|m\x05\x8cA\x03\x1cy\x86\xc7\xa0\x81J\x98\xfd\xe4G\xe1\xb4,Rx\xf5'\x9aN\xa6\xc9\xea\x82\x99De\xa6.\xbd\x8c\xfc,\x1bC`z\xcf\xd7\xe4\x18\xa6\xa6\x12\xef\xc2\xafa<\x86e\xf3\xfd\xab\x0f\xef\xc6\xe07\x9f\x97J>\x8d\xf1\xe9\xd5U\xb6J\x89?\x1d\xc3M}q\xea)\x829>\xfdc\x90Nc\x93\x87L\x12\xf0\x94\xb2\x1e\xf6h\x7f\xbf\x12\x14V\xe2\xa5\x85\x9f}\xb8\x8d\x85\xc8P\x8b\x9cF\xfb\xaa\x9eO\xcf\xa1~!wc\xd8\xd0XA\xa6d\xa6\x7fqu\x95\x91\xc8\xfc\x0e)\x84\xb1\x9a\xbeX\xeb\x10\x9a\x19O\nI\x9cG\xbc\x94T\xbbJ'?\x8e\xfaU\xf3\x85\xdcI\xd5\x88_BU\xa1\xe1\x1cX2C\x03Y\xd2\xd4*\xd3\xeb\xcf\x7ff'\x96vE\xe6\x98^\x994_\xe0\x1ch\xb6\x16NA\xdc|\xbeJ\x93U6\x86B\x03\xff\xe46\xa6|PhZ\xd6P\x01\xa7\x8a\x0b#\xbd\x0f\xea\xc7\x88\x060:`\xa4\xcc\xd0\xfaw\x1d\x97\x06&\x0b\xf0\x15\xe8,\xc0\xd1\x9b\x96\x11\x04:\xde\x19\xd5S)\x84t\xf1\xe4,3\xcf\nm9R2s\\\x88\xc4\xc3\x19:\x98\xc0&\xa0\xd2\xcfqky\x06=\xb6\x84\x05\xe91.\x9f4\x8b1z\xb7^\x10\x9f!\x1d\x14\x96\x921\xe6\xb5\xb6Q([\xd3\xe6\x99\x87}f\x1f\x93OR5\xe3.\x05\xdfTg\x18\xb5\x05\xa3&d\x98\x0eh\xea\x80\xef\x05\xfc\x8c\x84Fl\x8f2\xe2\xc3\x14\xbd\x944\xcb\xb4T\xf2-J\xc3\x9e)\x85\x11S\xef\xdd\xc01L\x8f\xe0fs\xd3\x81\xc5\xe4\xa6n\xd8s\x83\x811\x9b\\\xee\xc0\xad\xf7\xa9\xee\x8f\xf8\xd0\x18 \n\xdf\x88\xb0?\xa3\xf0\xcat=\xa5\x9d\\\xa21\x87\\\xb2\xd9|\xb5.\x96N\xcd\x96\x8c\x02^\x9a\x81e\xc3\xe0\xfeA\xb77\x02\xba\xdag.\xac0\xa9&z4\x05E\x9a\xd2\x03\x10\xfc\x1aK\x13\xd4\xc9\xaa^Fp\xca&C\xb7\x9e\xd2 P\xbbWs\x8f\"\x0f\xae\xa4P\x9a\xa7G\xfa\xf3x\xfa\x89\xc5F\xf8w\xd2\xa9t\xa8\xc6\xe81\x86\"w\x19\x96\xa5\x7f\xf8>\xa0?\xf8:'\x1e\xc3*\xf4\x17b\x1eu\xfc\x12M\xd1\x13_\xf8\x0c\xb8\x94\xa8\xb4\x7f\x7f\xa8*n\" \xd4\xba\xd0-\xdc|\xb5\x00~8h\xce~\x0cj\xdd2\x16\x8d\x87_\x17\xd2\xf1kHg!\x90\x0e\xdb5\xe5\xf2\x90q\xd0T\xc5A\x0c\xdel\xe1\xe39.\xaf\xe9\x12mi\xde9\n\xb6\xf1\x0d\xd8\x86=\xb7e$F\xf9\xbb\xba~\x8c\xe2\xbd\x15\xf3\x81\x99\xd1?cqG\xcbj\xb0\xd3rM\xec\xb4t`\xd5\x07;-;\xb1\xd3\xbc\xc4NK\xc7\x85;\x86\x9d\xee\xe0\x18\x96GpG\xb1\xd3|rW\xc7Nw\x06\xecT\xeb\xd0\xbc\xd7\xfe\xe7{c\xea\xc2B \x81\x9b\xba\xfe\x9c.\xfe:u\xfch&\xb8\xa6Gc\x0bD\x90\x12\x0c\x8d\xc9\xad\xca\xa4i\xf0'\xe8&M%\xb1\xd3\x81\xe3\x9d\xdf-\xaf\x93HO\xe9\xa6\xebU7:\xd4\x9b\x0d\x0d\x0f\xbf\xcd\xd6m\x83C!\xa9\x0c\xd0q\xc1\x7f\x8b\xdd\xdb\xc8 \x81|\xaa\xaa\x19\x19\xd3\xbf\xdf\xb0#bt\xf5\xfe\xb0sdf\x94+E\x12\xe4f]p\n\x13r\x89\x96g\xfe\xb7\xc8\x131\x1e~cxJ\xf8\xbb~\x13\x11\x1aB\x972\x95\x1b\xa9\xechH\x13W`\xe0b\xd8lD\xe1\x11k\x7f\xc0j\xa4\x93I\xfbF\xe8\xddV\x02\xa7`m\x0d,J_u\x8c\xbf\xc6p\xe9$E\x9cUb\xe7+F\x1c\xea9C\xc4\xcb\x8a\x15I\xaf\xb8yq\xc5lU\xd6c\xacR;\x97eqM\xec\x15$\xb1\xd0E\x9a\xc4\x17\x98\x98_\xcb @\x87]\x8a\xb8\x84\x89\x82\x9e\x0b\x03\xd6\x8dY8/D=\x1a\x9f\x81\xda\x93\x87\xbaU\xf1\xa3\xc0\xd6\\\x0e\xaa\xd7\xb9\xc2\x88\xc45(\xd7\xe0Z\x9f\x80\x98\xdc\xa2\xe9r-.w f\xf8\xfe\xb6\x07\xfb\x9d\x9b\\\xb7kj\xa6\xceJ\x98\xd8\x97~\x1c'9\xd0\x86\x11\xc5%)\x14q\x19sH\xbb[\xbe\xcb\xa0\x1a^\x1f\xcaxyt@\xfb\xa0\x81@P\x10\x91b\x04_\xba_S\xb9\"\xe6\xfb\xdb\\\xdd\x9ch\x19\xab\x99c\xe5\xfe\xf02\x9d\xd0\xec\xe3\xc9\xf4\x87x.\x89\x93\xa8>\x04\xdd\x0c\xd9\x03\x17B1 g\xed\xc3\xa9\xe7\x8c\xb9\x06\xa0\xb5\x18\x0d\xab;M\xf2\x99\x16f\xab\x18\xff\xf7\xc3\x8cr\xa8\x98X\xe6\xfe\xbeK\xceT\xc6\xd6\xe6Lm\xccX*\xd2dj\x1b\x10|\x048\xca\xc7\xa5\x9c'\xed\x92\xf30S\xef\xfb{a\x06\xde\xc4\x0b \xefg/\xcc\xde'\xf9\x82EcH\xdd\xda\x0b\x06\x8a>\x04K7=W\xf5An\x83\x0b\x93\xfb4\xa1\xee\x04NBpjbB\xc9\x079\xd5o\xad\x99\x94\xac\x88\xdfo\xdd0\xcf\x1e\xf5\xe8\xc6\xa5\x133\xda;f^\xd61lb\xd4L\xccP\x85\xc5\\\xefL\xcf\xc1\xe6F\xf4[e\x81\x1a\xcby1\x18/\x8c\x83\xa8\x98\x12\xa1\x95\xe9p\x1fG\xef\xe0\xb2\xad\xda\xeb\x07\xae\xc9\xed[S\xb3\\\x9bEM\xee\xe5\xfe\x9c\x9b[\xd3_O\x9eP\x1e>\xa4\x8b\x88\x89\x92\xe9O<\x13M!a\x1f\xd0\xaeJkJ\x86ofa\x94\x93\xd4n]\x91PAn\x8b\xc7J.\xb1v\xaeV*\xad\x93\xe6\x84i\xa2\x16r\xf3\x15\x9c\x0e\x14:\x88\xdf\xf7\xf7hK\xc6\xde/WQ\x18\x84,\x1dIy#\x97 _\xa5\x12\xe5\x8d\xae\x8e\x9e3\x85\xb2A/J\xfc\xe9\xbfs [Y\xe0G~jq1\xbex%\xd3Y\x89m]\xa0s&\xbac\xc6I\xbc\xc5\xbeA\x84LO\xbc|A\xa0\xec\x7f\x14f\x18\x07\xdf\x87,X\x90\xa5\xef\xc1\x1b\xf1*%Y\x12\xdd\xd0\x13!\x99AV\x04\x0b\xe6\xed\xdf\x08l\xe3Y\xcdIe\x86=\xc9r\x15Fd\xfa\xa6\x82\x9c\xcf]\x08,\xd1\x01\xcb\x85\xc9\xa5\xfa\xc1\xd9\xd7\xe6\x07\x02\x9e\xda\x0f(m\xf9\xce_)\x14v\x03\x9etK\xf2\x1d\xa4\xd5X\xd0\x8b\x01k\xac\x95\xdf\xe3{\xf2kA\xe2\x80\x98K,\xfd\xd5\ns\x1f\x98\n\xcc\xfc(\xba\xf6\x83/c9h\x97\xb8\x1e\x94H\xf3\xd0q\xea\x8b+\x9e\xb0\xadx9\xc1m\x8af\x16\x9eh\xa9z\xa6\xf1\x15m6GQ9a\xa8\\\xe7\xa7|\x84q\xed\xf3#\x16,v\xe8H2'R!!U\xae\x08Fj\xd2\xd6\xae\x16\xc3\x9aP\xc9Jz\x15\xde\xab\xb3\xd7\xcf?\xbf\xbd\x10\xfa\x95R\xc1\xdf\xb6\"\xc4j\xa8w3\xbb\x0d1\xb2\x9c:h\x1d\xdc\x03?#0\x1ck\xe7\x03\x83'\x8a~)p\x9c\x0c\x0c1\x02\x0c\xf1\x96\xb1\x9d\x91\xb9\x1d\xb9b\xb5)\xd5G\\\\\x86\xa6\x04\xd3\xa2\xfd\xa6\x86d~N\x93x\x0e\xcc3\x141\x88h\x12\xd7\xcf9\xc3&|\x16J\xe9D\x9b\xba!\xe4y.SA\x0e\xa2\x83u^{\x92;.l\x90^\xf1_\xc49+[K\x17\n\xa2R\xf0\xe6\xf9\x8a\x04\xe1,$\xd3\x12-\"C\xcfQc\x06v\x92RD\x19\xc6\xf3\x88\xf0\x11r_]\x07\x83\xc6\xfba,pn\xed\xad\xa72\xb5k\x84\xb1\xd1\x0d#\\w\x18\x7f{\xfe\xee-\xc7\xde\xb51P\xbci\x1a\x81\xf4\xae\xd1\x7f\xb1\x8f\xc9-\x14\xb6\xe6\xdcb\xc7\xa7V\xaa#\xf0\xf8X\xf5\x05\xac \x93\xbb\xad1\xd7$\xf6\x86\xc3\x9a\x19\xdf\xa1\x96\x96K\xda\xe4\x956\x81'\xf4\xa5\x1aXLn+\xd4\x1e+\xef>\x9f_\\}>?\xbb\xfa\xf8\xe9\xc3\xc7\xb3O\x17\x7f\x1b\xeb\x92\xa1\xfe\xf5\xf9\xf9\xd5\x8b\x0f\x1f\xde\x9e=\x7f\x7f\xf5\xd3\xf3\xb7\x9f\xcf\xc6\xb0\xab/\xf5\xfe\xf3\xbb\xb3Oo^\x8aR\x87\xfaR\x1f?\x9c\xbfA\xd6@)>2\xd4\xfa\xe1\xa7\xb3Oo?<\x7fu\xf6J\xed\xc6\xce\xa8\xf9E\x18\xd3\x85\xf1\xea\xc3;\xc1\x10\xbfD\x19[\x97\xf3\x12H\xb2\xd1P\x7f:\x02'v\x89\xc7\xab\x0e z8\x98NS\xe0\xe2h\xe2\xbd\xfa\xf0\xeey\x9e\xa7\xe1u\x91\x93\xf7\xfe\x92d+?\xe8\xfe6\xd3\x7f\xdb\xf5Y$>\x13\x00\xe8\xf5U \xbez\xc7\xe3\x9d\xbc#\xf9\"\x99\xf2\xef\xf4\x98\xba\x94W\xccP^\xe1\x85\xd9\xcb\"\xcb\x93e\xd9_J\x18\x16\xdeU\xe3\xb9\xb0\x97\xe4^U\x9a/\x9d\x16\xba\x1f\xf0`]\x95s\xa0\xea\xd7fL\x12f[\xbb\x87\x96\x0b\xb3\x16co\xdaw\xa4\xcd\xbc&Y\x98\x877\xc4X\xa7\x1e\xcb\xf5\xab\xfc\xc3\x0dI)\x07E\xa6\xc6\xe1\x9b\x90b\x93\xc9\x95/\xc3F\x06~\xf2/<\x05\xe2\xb0 \xf8L\x1e\xa5x\xa6\xefd\x19*(\xb5\xad\xbd\x01\xee?\x174[\xb4ms\x03\xdf\x9a7\xe8\x9c>\xeb\x08[\xb5\xf0j{\x02N\x14sA\xf9\xd2\xbbi\x00:\x96k\xb1\x88\xad\xd4\x8e;\x0es|\xcd(\xaf\x17\x19\xbf\x92w\x1b\x9c@\xc4\xca\x07\xc6\xf2\xf5\xcd\x06'\x10\xb0/dD7\x99]6lv\xc4\xa5\xe1\xd7jO4\xbeq\xd6\xf8\xf9\xd6\x7f\\\xf9[\xbf\xfd\xf2K1\x18\xbc\x1cl\xe1\xdfW\xfb\xec\xcf!\xbb}\xcdn_\xb3\xdb\xd1\xeb\xd7\xf4\xcf\xce\x01+\xbcs\xf0\x8a\xfdyMo\x87\xaf\xf1\xedh0x\xb9\xc5\xfe\xbe\xc2?\xac\xf0hx\x88o_\x0e\xd8\xed\xeb3z\xbb3\x18\x0c\xe9\xed\xab\x03\xfc\xf6\xf5S\xf6\xf6\xf5\xab\x97x\xfb\xea5\xbb}\xfd\xfa\x95&|Is\x05\xbdyu\xf5\xfc\xe2\xe2\xd3\x9b\x17\x9f/\xce\xae\xde?\x7fw6\x06k\xea\xe7\xfeVJ\xfc \x0f\xa7Vs\xfb}\xfa\xf0\xe1\xa2\xed\xa34Ir\xcdg\xf5/\xae\xce/\x9e\x7f\xba\xb8z\xf9\xd7\xe7\x9f\xb4F\x85Ji^\x0e6\xc1\xfa\xe5\x97-o\xb0\xf5\x14\x81\xfc\xe2\x00\xa19\xe0\xc0\xddg\xd0\xdcy\xcd\xa0\xb9;\xd0t\xa3Z\x1cz\xae\x1e]\x0d\xb3,d\x8e\xd2\xf1\xd4O\xa7\x0c\xff\xeb\x91y\xcbQ=n\xa4\x16\x00\xb4DV\xca\xf7\xa1\xb3\xea\xfa \xa6\xfai'\x13jj!3\xe2\xc00\xf5\x03\xb7\xbd\xb2I~\xe9\xc8\nr\x8d\xd6\x15\x8c\xa8B|3ln7\x13)\x8a\xe6\xcdFS\xcf\xef\xceO\x1c\x1c\xee\xd4\x18\x8a\x1df\xa3\xfc\xd4\xc0W4x\n\x8a\xef\xfc`\xf1\x89\xcc2.\xe1Bi\xc7\x157\x9d\xe264:a\x87\x9e\xcfX&E\x9cK\xf6\xf1\xea\xd8P\x98\x1f\xa2\xb5\x94^.V eZ\xaf\xc6\xae\x7fi\x94\xe7\x10\xb5\xdf\x92\xce\xa7\xf9\xd2K\xc9\x8cI\x91\xe7$\xffD7\xff;\xda\xea'\xe2O\xefl\xc7#\xf1\xaf\x05)\x08z\x04R\xcc\xdc\x86_\xe7$\xffk\x92\xe5\xef\x93i\xe7\x8e(\xbb*}c\xb7:6\x17q+P\xb5\x8dxSRN+3\xb1S&\x94>S+n\x08\xb0\xeb\xfd\xe0\xf1\xf3Z'74M+\xe3\x8c\x94^4'\x12\x95:(T\xc6\xc4\x13!\x97/_\x05I\x9c\x93\xafF\xdfdM\n\x10\x90\xd6S\xeae\x8b\xa4\x88\xa6\x9fWS?'\x08\x14_\x9ft\x18\xf0\xacA-B\x1d\x82\xbe\xc3\xec1\xeb \xb0\xc5\xa8]\xf6\xd5\xe3\x16`\xdcc\x016\x11P\xdbT\xadH:K\xd2%\x1b\xef\x9b\xd9{\x12\x90,\xf3\xd3\xbb~\xfe\xcb\xc4\xbb*\xf0\xcb\x17~\x1e,\x98\x86\x8f'\x8a\xc51\x9ajo\xac\x9f\nk\xe81`\xf8=0\xe0\xc8\x10\xedo\xb8\xfbT\xab?\x1b\x19\xfc6w\xf6\xd4\xf2\x183\xad2\x08\x91\"YN\x93\xa0\x10\xd3\xab J'^{\xe2\xc7\xbb\x84)q\xf4\xb5\xc5\xfeM8\xc7h\x9erf\xe5\x93\xe6{\xaf\xc8H\xfa|\xce\x1b\xde\xfe\xe5\xfal:'\xbfl\xff2\xdd\xf6r\x92\xe5\xb6\xa6\xa0\xf6\x1c\xd0\xf8x\xd0\x8d\xd7\xf0\xa9\x00\xd9\x82\xcc\x8b\x93\xa9\xc1:*\xe69V\x995\xa7~W\x8b8\xedz\x8e\xa5\x16?\x9e\xc7\xb1\x8cK:\x00\xc3Y\xb2,h\x93\xf4\xd2\xc5\x1d\xa5\xd9\xbch\xc5Z\xed\xb6E\xbe\x8c0\x8a\x1c\xda\x8e\xd1;\x07\xc6\xd2{\x8aP(\x1c}V\x00\xf1\x8bi\xfd\xd6\xd6]\x84Q)\xbbv\xd2p\xc8=\x16(\xdc\xf0?\x94db\x02\\\xdd\x0b:\xf7\x95\xd9B\xed=\xa5\xe1\xea2\x0bf\xeb\xc1\x03\xeb\x89\x92\x82a\xf9\xfc\xe9\x0d\xc6\x83\xd2C\xe1\x1c+\x10\x85\x84\xd2\x94A\x8e\xb7\xaf>\xbc\x93\x7f\xb3\xca\xc5\xddE\xf2\x85\xc4\xec\xc6\xcf\xfd\x8b\xd4\x8f\xb3\x19I\xdf\xe4d\x89\x0f_\x87\xbcQ\xba\x9d\x9fG\xd1\xcb$\x8a\x18\xc7\x8bO\x94\xdb\xd7I\xba\x14\x0e\xca\xf4\x9e\x85t\x16O\xde\x91i\xe8ce\xef\xc2%\x1e\x80\xcc\x8d\x9b\x9e\x03S\x8a\xce\xde\xf9+\x97\xfe\xc52\x1f\xfd\x90\x8e\xe1\xd7\x82d\xac\xeb\x1f\xa3b\x1e\xc6\xfc\x0f\xfb\xf2\xfc\xa7\xbf\xbc\xc5\xb5\x8e\x05\xce\x7f\xfa\x0b#\\\xc5\xddG?_\x9c\x93yy\x9b\x84q.n$(\x9c\xff\xf4\x176\xee$e\x83f\xd15^\x14\xb3\x99\xa8\x8b\x82\xfb|A\x08\xfb\x9c\xa2\xa1\x8b\xd4\x0f\xbe\xbc\xe4\x00/\x1f\xb0\xbb\xa4\x08\xb0G\x96\x88\xe7\xe1\xd2y\xcc\x18\x99\x93\xa1(Dl\xd1L\x1f\xb4\x93\xee\xccb\x92iv&\xddK)\xdd\x89\x8d73\xe0\xfb-\xa8,G\x15t\x81\xce\x1b3\xee\x8a\x94`\xc8Q\x17\"\xba\x10'\xd1%\xdd\xee\x1e\xc2\xb5c\xcd\xab8\x91\xa1\xa62\xbcI\x17\x024\x1c\xe9\xb1\x08T\xe2eQ\x18\x10\xfb\xd0\x85\xada\x97!\xafi\xbb\x9b[\xeb\xce3\xd5\x99c\xea{\x04\xc7\xeem\xd8o$xj\xee \xf6\x10\x9e\xd0s\xbf\xb9\\\xea\xee\x07\xf6\xc8PNrd\xb0w\x0de\xb8\xbb\x84\xa2;_\x0fAJ\xb8pG\xe5\xbd8\x0f\xb7o\x8a\xd8\xde;xp\xe5\xe5\xe3B\xd2\xb5\x84\x8c\x1d\xdc\x1d8\xdeL\xd7\xc3=},\xe6&\xee\xee\xda z&\x82E\x99M\xd0\x1e%\xe6&\xc6D\xf6\xc9\x08\xb9\xf6\x93\xa0l\xac\xb92T\x97\x93\xbe3\xb9&\xa4\xba\x98\xf4\xdd\xbd=\xc7\xde\x18\xd4D\x95\xa3\x9d\x03\x87\xc7\xedq\xc1jF\xcf\xd1\x9bG^QR\x8eG\xfb!\xc2\xfe\xee\xaa\x9e\x82\xe3\xa1%\x06\x8f\xb0\xb6\x12\xd1\xc2\xae4>\xfee\xb8\xba\xabPooRK\xfe}\xaa\xa5\xa8\x10\xa8<]L\xe3\xf54\x895\xe1\x18\x90\xdbB\xff\xdb\x9c\xf1Wbl\x9b'\xa5\xaf\x84n\x8e\xcd\xaeK\xbc\x9d\xa1qn\x1d\xed\xe4\xfe\x13!\xf5\x162n#\xb6\x87\x83\xa1c\x1b\xa7\x9a\xb7{@\x11\xbb>\xae\xef\xef\x0f.X~#\x8c/\xf4\n\xe5+7\xd1x\xa9\x88\xe7\x1c\xcf_\x07\xe8\xfd\xe0\xda\x9aQ|c\xa3!Vn\xcf>\xadU\x8ftat#\x89\xddk6e\xb3(\xdd\x01\xc0\x02\xcb\x86\xf1#\x17\x1c\x81g0@\x1e#ET\xf1t08\x18>}:\xda\xdb=\xd8\x1d<}:\xa4,\xc7\x9a4\xfd\xb7d\xb5lM\xa1\x07[0d\xe6\xc0\xd6\xbb0fVs(\x12\x06B\xc9\x0f\xf8\x17\x0cyFi\x90#\xb8 \xb30\x87E\x9e\xaf\xc6\xdb\xdb3? \xd7I\xf2\xc5\x9b\x87\xf9\xa2\xb8\xf6\xc2d\x1b\x15\x99\xdb\xd3$\xc8\xb6\xf1\xe3\xad) \x92)ar\x9f\xd30\xbe\xf1\xd3\xd0\x8f\xf3\x13\xac\xb2\x96:\xa6L\x1bHQ\x8e\xf5\xc4O\xe7\xd9\xe4\x92\x95\x8bi\x15\x9f?\xbd\xa9d\xdfRb\x19\xd8\x84\xa1\xeao\xc4\xea\xc0Qc\xae\xb6\"\x8a`I\xb2\xcc\x9f\x13t\xb4\xcb\x08>\x8f\x93xk)F<%7@\xe2\x9b0Mb\x14\xaf\xd2\x8f\xf1C\x1cG\x06~<\x05\x7f:\x0d)\x80\xfd\x08\x16$Z\xcd\x8a\x08n\xfd4\x0e\xe3y\xe6)n27<,d\x95oHM \xc0\xa8\xbc\x04\x85d\x14\xf6o\x04p\xe0\xa70\x89\x90\x9d\xc2\x8c\xb8\xb3\xd4_\x92\xec\"\xf9\x98\xac\xe0\x84\xceT\xf2\xc8\x8d\xd1\x87\xbe\xe3IC)]CJ\xb7\xeb\x1c\xc9\xd3\xf5Vk\x8bI\xa7x\x03\xedj\xaa\x86\xf7\x998\x03\x1a\x91\x04\xa1\x81\xf4r\xe1\x1d\xd5\xba+\xa4\xc6j.Up\xdat\xb1\x1aW)L\xf0\xd9%\x93\x94\xc6\xcd\xc8\xc0\xd887T\xe9\xdb\xbcu\xcd\xca\x9b\x932\xf2z\xdf\xa3\xdc\xb5_\xa5\x1a\xaf7\xa5\xa6\x0fi\x99\x8ee\xcdJMu2}M\xbf\xaa4\xda\x0bm\xadl\xd6{\xd7\xaaqU\xd7\xd6\x8aa\x0f\xfa\xd7\x8a\xc5;k]\x1b\x9e\xb2\xab\xa2\xae\xc2Od~\xf6u\xd5\xb7\xb6r\x8d\xb2\xcf:\x16i\x0f\xa7F\xb9\xee\xfe\x8e\x8dR\x1b\xaf\x14\x0f\x84^\xbd\xa7\x1fu\xf4\x1dq\xea\xda\x15\xe3WR\xcd\x0c\xcfIf\xe5X@\xd7\x9e0\xea\xe8\xdd\xa4(\xd5\xb9d>\xa6\xe1\x12\x0d\xfc\xfaV]\xedk\xd4\xeb\xe9P\x07\xbe\xd0l/|n\x88\xe5\xa0[\xe2P\xcf\xc4\xa7\xed?\x93O1\x970~S\x16{p\xca\x185\xb1\xbd\xb7\xebx\xec\xbd\x9e\n]\xdf\xfdWs\x8e\xe1\x04J\xc1K9'#\x0e\xd9\xbf=\x7f\xf7\xf6\xeck@V\xfcx\xc5\x97)\xf13\x9cY\xc2\x1f,\xfd\xf4\x0b\x0b\xfc\xc0n9\xe9pR%v\xa1\xe5)\xcc\xec\"\xfe\x12'\xb71\xb0g\x8e\xe5\xc0&/\x85\x95\x9c\x82\xc52\xfe\x89'\xe5)f\xe3\x99b9n\xd9\xe5U^\xa4\xe4<\xf7\x83/\x17\xa9\x8fQ\xc6\x0codk\x19)\xee\x01\xad\x10\x9fe\xb4$\x86\x0d\x14\xc4\x87\xc3\x9f\xd1.K\xe9\xcd\xca_iK|\x0b\xd6 9\xedOj\x8c\xbb\x90\xd6_\x8a\xb1\xb6\xae\xec\x1b9\x1b\x01\xce\xd3&Xc\xd0G\x0c\xc9)e\xd79 .lT\xc1\xfcq\x1e0\xe1\x07\xa3\nM\xd3\xe1(\xa1\xb4\xd6\x8e\x83\xd3%\x8884E\x91\xa0\xd3\x94*>$\xa5\xff\xc8$\xb6wv\x07\x8e\"h\x15\xbe\x83\xf8\xfe`o\x88\x96W\x07{#\xb5\\\xe5j\x82\xe5vx\xb9]\xfew\x8f\xff\xddw$w\xf1G\xecN\xf1T\xe6\xaat\xe9:b{\xd4Hu\x11r\x13\x08\xf5\xb90\x8dP\xa5\\E\x15\x103\xf5\xe6L\x14NX\x0c\xaf&\x92\xc8L\xd2-\xd1\xd3\xb61\xaaeso\x1af+\xca\xc82O\x0fo\xb5\xf032\xfdD\xe6a\x963\x05\x08Z\xeeNbs\x14\x89\xc2&\x8d\xa0\xec\x0f\xf4Y\xdc\xb4\nJ\x99\xaa\xdd\xbb\x12\xcd\x8a\xa1\xa2\x01\x8b\xf6\x05\x8b\x1c/\xbdy\xc3\xcf\xb6\xc6'\xe5\x0b\x17\xeaq\x86\x9a@\xd4\x04\xd4\x14\xe1\xfaz\xc1\x03\xa5\xfc^\x9e\xfa7$\xcd\xc8\xc5m\xf2\x91\x96\xb3\x89w\x95\xfb\xe9\x9c\xe4\xb4+.dJN\x9bf?\x02\xbd\x18}\xad\xbe\x98\xe6\x97\xd9\x99\xc8\x1dj\x14\x03!\x9e\xa3|=\xa6\xd6@\x05\xb8\x00$\xd3M7#X\xd2K3\xfaX\x1d1@]\xe6\xd1\x1c\xff\xcc\xb4H\xd1\xc8\x85\x99s)PH\x95\xf1\xb7-\xef\xce\x8f\xf5 \xa1\xfb\x9a\xafj\xcd\xc0\x1f\xb3\x84\x93o[\xc2\xd0 \xc8U\xdf\x05\xadB\x80\x16\x9a\xa9\x0bw\xa0I\xc6\x04\x1c\xae\xd3\x86\xce\xd7\x0f\x82bYD~^.\x85W\xbcM\x92u\x19pb\xf0\x83\xa8\xd5R\xb2\xad\xfa\xf3/\xe1\xea\x02;\xde\xab!U\x15nj\xe8U\x98\x92 _s\x14\xab\x9e\x95\x9f\xc59I\xdf\x12\xff\xc6\x00\xa6\xd2\xb4W\xd7R\xb5\xed\xaajlf\xcd;\xe3 ]L\xabF\x7fRO\xf1\xe97\x1f\x8d\x86\x93Q\x1fy\xaeyb\xf2\x88\xceC\xdd\xc9\xa8;I3\xc3I\x1aUI\xa6~Ws0a\xcc\xf9\x86\xc9\xd1\xacK\x8c\x04b+\xd9\xa1G\xbe\x92\xa0\xc8\xa5y{\x13\x7fH\xa7\x84\xd3\xedh\xfb\x95}$i\x86\x1b?\xb7\x193&\x13\x94\"\x0f\x91\xdd\xd8\xdd\xf5^\xf5f\x8f\x11\x81n\x0cZ+\xeb\xcd\xb9\xb3\xca\x86\xad\x95-\xfaVfy(\xe9\xf4\xae\xd2$A\x93\xaa7\xaf\xea\xf5\xd6\x17\xd2M\x03\xadH\x1e\x00\xcdF\xd8\xcb\xb3\x1b\x12\xe7\xccl\x01\xe7a\x0c\x89\xa7\x7f\xd3D\xf4\x8dr\xd9\x0b\xee\xde\xa7\xa9\x83\xbfk\x9d\xb2\xa2\xa4\xdb\xfa\x19\x06ku\xe51S@ZOw-\xfcR<\xd6\x1cD7\xdce`\xd1H\xf4I/;\x9a\xe4,\xfbh\xc4\"\x81\xfd\xfe\xe08\x93\x10#H\xe8\xeb\xc2\x94_\x8d\xf3\x81\xd9\xebd\xda0b>\x1a|z\xd3p\xfa\xb1\x1a\xbc\xeeY \x866\x00J\x84o\x0f\xa3|\xa1I\x8b\xb4=\xa3\xe4C\x9f9\x00)6\x84v1\x8b\x0b\x835XI\xfc2\n\x83/\x96>\x90B\xa3\xdcK\xc6\xe6\xf6(\xfe*)\xae#\xd2\xb7r\xa9t\xff&\xde%EF^%\xb7\xf1:e\xd7\xac\xfe]r\xb3V\xd95\xab\xff\xbc\xea_\xb2\xbbj\x90\xf4t\xf6\x06\x92\x8a\xfeu\xc4\x12\xbcbT\xc0\xdc\x05\xeb\xba\xc8s\xb6Cy2H+\x8cWE.?\xc8\xd0\x14K~\x92\x93\xaf\xb9\x9f\x12\x9f?sZ\xbc\xa8[#s\x88K\xf4\xb2\xe98\x05\xa0\xea \xc4\x85\x87s\xe3\xcd\x03\xb3\xceV]'DDJ\xf59\x8bY\xed\xc8b:=\xeeH\x8dx\xa8T\xf2SZ~\x92^\xb6a\x00\x96/\xe8\x11H`=\xb4\xc5\xf9\x8a\xdb0\x8a^\xd5Z4=g\xed\x9bG\xae\xc7AX\x1dO\x81\x94N(tz\x0c\xfey\x14\x95lC\x17\xd5)\x98<=\xe0\xeby\xbc\x15\x12[\\\x14O6\xfcpc\xb4\x82\x89&\xf1\xe5$\xbflC\x8ab\xfcf\xf0\xeb\xc4\x06\xe2B\xf8\xa4\x86i\xd0=\xb7\xb9\xa1<\x87)\xef`\x8f=\xf1\xa0J\x90\xf2\xd4\xe7\xc7{\x7f\xca\xbb\x84g\xe8\xf2\xa3r\xc5H\x83\x9a\xfd\xa1\xdff\x7f(.a\x87\xe8O2\x03|p^\xba@O \xda\xc8\xab\x8dF\x1e\x83\x19\xf2\xccv8D.7\xa4\\\x91~q4\x11K\xf3 \xdf\xdea+\xbc\x99\xebU\x13\xdefR;\xc0\xbe\x05\x1a.X!\xba\xd2$ Y\x86U\xffo\xdaHW\xf5b\xcf\x04M\xe8\x94\xfc\x01d\x88%\xe1\x14V0\x86\xa9\xe32\x80Q\xaa\x0c\x93\xb1\xfa^JP\xd5\xfd\xd2/\xe6\x8b\x9c\xe9\xc2[\xbbyu\xb5*\xd29\xe90\x81\x89*S\x0fc=\x12\x91\xf4\xc2\x8f\xbf\xf4\xcb\x8f\x1d\xd5\xeb,\xef\x0c,!\x0b\x01\xf0\x8d,a#\x85\x97` \xd5$A\xfa\xe8:7!\xb9\xed\x9aK(\x83\xe9\xd1\xd2U\xd0n\xbc\xd5\xaf~1\xfd\x89\x16e\x82\xf0\x99\xf4n\xc3x\x9a\xdc2\xcb\x81\xb2b\x8d\x87%H\x87P\xeea\xe2\x85W\xdcKM_\xb8<\x0eO!\x16!o\x7f\n\xc9-\xc6t\xe5\xfe'?\xb3\xc6\xc7\xc0z\xd1\xdc\x85MffJr?\x8c\xfa\x00\xac\x04\x12\xfb\x84\xb6\xdb\x199\xbb5B\xa6\x0b\x89\xda\x16oCRZIy@\x1bf\xa3\xf8\x85\xe7\x17s\n5\xcc\xa3e\xfb\xcc\x0bT^\x94\xfe\xb7/J\xb5\x93\xcb\xe4\xa6\x13_\x10\xcc\xa7\x1e\xe4o\xe2\x9c\xa4\xb1\x1f \x01\x1d\xdd&\xa8El\xdb\xae=\xc4R\xe5t\xe8\x9bi\xab}\xe1w\"\xd3\xbaF\x9e{\xff\xae\xdd\x90\x92\xbe\xde$#1C\xcah\xd7\xac\xc7?\xbdTS8\xa9\xd5\xf7\xdb?nH\x8d\xbcLVwi8_\xe4`\x07\x0e\x8c\x06\xc3}\xf872\x85\x9f\xfd\xdcT\xec\xefdz\xcb\xea\xabl\xc5\x02\xbaz\xd1E\xb0,\xff\xe3\xf6\xffQ}\xdc0\x1f(\xfa\xcd\x05u\xab\xd6:)\xa9D\xbd,\x91G3t\x02\xc8\x14\x16\xe1\xd9\xbe\xa5\x10\x17\xcdh\x95-\xe1,\xc4\x86\xafl\xeat\xf49plo\xcc\x9f\x0c\x92\x90\x85\xcbaR3Q\xa5$\x958\x81P1Y8\x81\xd0\x01\xc2\x9c\xfe\xda\xa8\xb32}L\xddb+u\xca\xaf\x13\xcf_\xad\xa2;\x9eP\xa9\x95\xbf,+\xaby\xc3\x86z\x82O\\\xe5D`F\xa0\xd4\x11\xc6\xc6\xa9\xc8\xcb\x93rG\x17\xde\x1f\xff\x9b\xe9G\xc2\xf2\xceZ\xd0\x1aKR\xc6c\xacy\x814\xeai0\x92\xd2\x85\x0eGk\xd7\xb4\xa2-x\xb2\x9e\x9e\xfa\x81C9\xc7\xd8\xb4(\xcb\xade\xf7\x95T\x9e\x0f\xf6zV\xc8\xdc.\xb8\x0f\x8a\xe3\x9e\x1b:\xd5\xf3?\x81A\xaf\xda]\x16*\xbc\xde\x9a\xe8i\xea\xc7\xd3diw\xfan\x18\xbak1\xf36\xdb\xf2\x82$\x0e\xfc\xdc\xae\x85\xc4\xc74\xc6cJeX\xce\x95\xe5\x82\xbd\xb9\x19\xc3&\xa4Ne\x0e\xb1\xb3\xff\xf8\xe43\x8dh\x06<\xb5e\xe39Sp\xec6\xe6\xcb\x07\x83\xd5|\x05\x8d\xdcc\xd9o\x87\x83\x81\x03\xa7\xfa\xd2\xd0-ZF\x94V\x06Y\x0d\xe9\xf2\xdd\x188.\xa46\xe5\x9d\x13\xa7\xdd\xd0\xdd\x14\x8c\\\xb6v\x7fh\xb4g\xcdInQ\\\xc1\xacW2q\xd7t\xfc\xb2\x9e\x07\x94aKR%\xdc\xb4\xc9\xf3\xcbBw\x0c^7\xe5\x0cE\xb2i\x0f_P\"\xf1\x11KTsP\x89\"\xeb\x9a\x17\xc7e\xce\x88F\\\x9f>=\xc1\x9d\x11\x9002l\x9aY\x94$iW\xef\x0c]\x0b\xb3\xf7\xfe{\xf4\x81\xd9\xc44\n\x03\xe6\x12\xc3v}\nc\x88\xd7O\xe8!\xe1\xa4Q\xaf\x87J\xe3>\xc3\x99\xa6\x91\x1b\xb4\xc4qn\xf4\xc1 \\R\xcaK\xddh\x98\xd6\x88\xcb\xd4\x93\x9d\xfe=\xd1\xb0n\x9aO\xea\x9d\xa91p\xf2\xa5\xf0\x8c\xba\x05\xd9\xe7\x0c&\xd5\xa9[\x92ofC\x08X\xe3\xd05\xef\x97\x7f\xa0\xe7\xaa\xd9Gr_\x9f\xc8b\xcf\xe4\xc3\xd9\x89\x0eR;Y?\xffZ\x97\x98gO/\xe69\xd0Iy\x98\x87Y\xf3\\\xc4A\xd5\x1f3\xbd\xff\xb0;\xc7\x9e\xd9\x14.cF<\x1ao[\x96\x94\xdeGk%\xcb\x82 \xb9\xd4\xb9\xf7\xa2\\\x7f`\xf0\x06\x8f\x1a\x11\xd8C\xb3\xe7\x1cH\x82']8`!^\x9ad\x97]\x84\xaaT\\\xe3%\xe72\xef<6\xa6f\x02\x0ds\xc21X\x1f,\xd8\x84\xcdMM\xf2oq\xddj\x93l@\xe3\xdc\xc1'\xad\x92\xf9\x99H\xeb\xa2\x8dfB\xaf\x7f?\xfb\xdb\x184\xf6#\xef\xcf\xce^\xe9\xd3\x17\xce\xfc,\xffw\xa2\x86\x873mg\xcc\x1a\x90\xc8A5\xb5n\x0b\xcc[]\x9f\xb6\xf2\x14\xacs\xca\xfdX\x1f\xd1X\x9f\x98e\x1d\x1b!NOk\x04a,\x97\xd5:\xf4\xdaj\x97{lT\xd4\x9bu\xd6R6P]_\xc4\xa5\x9fLq\x86N\xd2K/lNl\x13\xf2s\x92\xffL\xfc/\xeb@\xfeQ\x00\xd90\x84H\x84&<6\x86\x7f\x088zi\x05\x92\xf8uJ\xc8o\x9dBn\xa8*\x8f\xd0\x1e\xd4\xa3\x8b\x9b\xfe\xc2\xd8vO\x9e\x80\x00\x13\xfd\x1d\xd8u\xb6K\\:\x02\xb0\x8d6c\xfc\xee\xef\x0fe\xb8\xe77\xd9Y\x19yC\xfb\xf5Z\xb4\xc9\xef\xdf\"]\xd6W\xadw{\xcf]\xb0\xaa\xc8F\x0d\xf7w\x8e\xf2\xe4xG\x947\xf7^\xbe={\xfe\xe9\xea\xc5\xdfPs\x847\xf8\xeb\xfd\xd9\xcfW\xcf?_\xfc\xf5\xea\xecS\xf5\xe0\xfc\xe3\xd9K\xfa\xe0\xea\xc5\xf3\x8b\x97\x7fm<.\x1f\\\xfc\xf5\xd3\x87\x9f\xdfkJV/J\xc5\x05\xedCLn/(}\x1b\x9f\xa5\xed\x9eg|u4\x97\x0e\xc5A\xda\xa8\xcd+\xff.J\xfc\xe9\xb8%\x83$\xd4\x89y\xb5C\x18/\xf3[z\xa59@\xca^\x91\x8e^\x9c\xafH\xf0\x8d@\xc9\xbe\xbd\xf9o\x06\x81&\xbe^\xef>\xbf\xba\xa6;\xd7j2\x01\x0d\xc4]~\x9c\xadH\xa0i92\x1f\x02\x8dO\xb5\xad\x06\xbac\xa5\xfc\xd4/\xf2\x85\xa6\xd5Y\xedT\xc2\xd2\xb8\x80\x95b\xab\xaa\x18;\xc9\xaa\x92W\xd7w\xcc-\xb37_\xb6\xaf2X\\\xc6\xaeK\xdcY\xba?3\xa5\xc0\xe5\xda\xe1C\xdaH\xed\xfb{\xb4\x0fa6?\xc4\xa1\xef*\xeasMfs\x7f\xc7\xe1\xec\x96\x0b\x16s?5E\xaf\xeaE\x98H5\x0f\xf4\xee\x88\xfb\x0d\x19\x0bO\xf7?\xd03\xb0\xfb\x03\xbd\xf0e\x7f\xb0\xdb7\xdc\xb1\x10nli\x98\xa1\x98[U\x01W\xd3\x0c0\xe6\x16W\xe2\xd6\xd7\\\x92r?c\\@\xb6s\x04\x9b\x9b9\x1cCl\x0c\xb3\x99\x1a3\\3\xafa\x92\xdb)f\xcfK'\xc3\xcbv)\"\xbd2\xd9\x0b\x98\x9f@\xa9[{\xccm\x0fO \xa9?\x9f\x13\x96\xfc\xaa\xf6p\xe1\xa3\xe5J\xfda\x86%\x8b\xbauK\xb6\xde\xdc\x0f\x07{}$c*\xd8$\x93\xd0\x13)_x\xbc\xb5u\xd4\xe4C\xb8\x94~\x12_\xb2\xfc\x83\x92\x19\xb0\xf6\xac\xd8\x1a>z\x8f\x0c\xba\x93\xd1kFS\x0d\xe4\xeaj\xea\xe7\xfe\xd5\x95\xb6_\xa9\x9d;p\n\xf1D\xc3:\xe7\x94u\x16\x8f\xc7`-\xfcla\xd1\x134\xf6\x96\xfe\xea\xd1\xe31\xb8C\xed7\xe2\xf2\x89\xf0v\x06w\xa8]\xfd\xc6\xec\x11\n\xd7\x84\xeeD \x9dlA\xde\xa5!\x85\x86.:\xc6)\xf86*\x93\x12\x9b\xe0\xba tg\x89T\xddc\x94\xb8v\xc0M\xee\xdbZ\xbd'\xde-\xb9^\xf9\xc1\x97\x8fIt7\x0b\xa3\x88\xab\xe4\xa7d\x95\x92\xa0\x99\x17\x14=\xdeW~\xbe\xc8\xb8=I\x15z\x99\x7fY\xde\x9e\xb0\xf4\xb3z\x06\x8f\xb8`\xb1dM\xda\xd8f\xb5p\x91\x9a\xf0tk\xc5>#^\xd4x\xad0\xd6\xad\xfd\x0c\xffG\xfa\xa8\x11\xc64\xfa\xd8\x9c\xad\x13\x18>R_\xab\x9a&\xd4\x07@w\xdd\xf6\x7f\xda\xa7\xe3\xc1\xfdd\xb8\xf5\xf4\xf2\x97\xe9\x8f\xce\x9f\xb7\xbb\xb6\x88\x01\xa3$\x95\xb1\x8f>\xef\xfb\xc6\x86\xfd\xff\xb3\xf7\xef}q\xe3\xc8\xe20\xfe\xff\xbe\x8a\xc2\xe7\x9c\xac=\x18\x03I&\x97\xce\xb0,\x03\x9d\x1d\xce\x06\xc8\x0f\xc8\xcc\xce\xaf\xc3\x971\xb6\xba\xdb\x1b\xb7\xddk\xab\x9b\xb0\x9b<\xaf\xfd\xf9\xa8$\xd9\xb2,\xd9\x86\xb0{.\xcf\xd7\x7f@[\xd6]\xa5RU\xa9.T9\xd3\x18\n\xc9`\xc4*{\xf2\x04\\\xd5EI\xde\xf0A\xb2\xb1\xc7M\x87\x0b\x1e]\x80xX\x80\xc0\x1f`k\x97\xff\xfa\x0f\xf4e\xcfi}\x8c\xc5\xfb\x80\x99\xd2]L\xf5\xcd\x82\xed(\x17\xfa5\x8a\xe9\xa2\xf9z\x8b+\xd8\x18\xf1\n\x86\x03P\xba\x82*\xae}\xc8\xa1\x83\x90\xd2\xb1\xa1`\x1f^Y\xc8\x9dg\xfa\xfd\x99 w\x9e\xe9\x0e\xc6\x05V}\xa6\xd3\x99\xa5\x99*M\xc5%\x81^\x0d^\x18\xb9\x85\xd7&\xa4S7\xf7\xdats\xea&Zj\x8c\xa9\xa1\x96:\xc7\xd4\x95\x96\x8a\xe1\xdd\xea%q\xb9\xe1\x91\xe2m(\xfc9!\xb7W\x08vk\x97\xbb\xe3`\x7fQ\x97\x8c\xbb\xacqw=\xae\xd5\x947\xca\x9e\x84K\xb5X\xee\xf1\xd01j\x96\xf7E\xbeHJ\"\xb3%\x01\x0f*N\\^_\xd8\xc8|A\xa8Z_\x88YV\x8d,\xbf\x90\xf0\x93\xd6\xec\x8ao\x0fw=\x08ZK\xe3=_\xa62\n|c\\9r\xcf6\xfd\xbc\xd8\x9d\x8b\"\xf4\xc1>\xa4n\xc6\xdd\xdbh\xd7~\\\x81P*)\x18/\xf7\xf1Z>\xea\xbc\x967\xac\\\x9b\xa6\xc5z\xa6\xc3\xea\xc1\xe9\xb4T\xb1\x1cVE\xb5\xca\x96j\xe2a\xd5\xe0\xfa[\xaa\x98\x0f\xab\xa2\x82\x8fFn\xa3\x8a\x81\x8235\x05\xf2AV\x0d\n\x89\xfd\xecu/\x95e\xbf|\xce5\xaeG\x88nF`\xb4%\x13}W\xb4arq\xaa\xf49F\xb4v\xbf%T\xe1\xd8\xf2\xd5\xce\x90Au\xf2\x0d;\xdc\xb9>\x1e\x82\xe8[\x97x^\xcdJ\xc8x0l\xf3f\xf0\x03$o<\x94i\x91I\xee\xd2I\xb6\xb9y\xe5]\x19\x07\xcf\x8d\xf2\x90\xd7\x16\xf4\xa8\xa6_?h\x02\xccr\xfb\xfaZ\xb45\xb4\x0d\x1a\xacIQ&\xdc\xef\x92PE\x92IA\x92\xc5\xe4\xf3\xd9\xd4u\xd6;\x81\xe3u\xe7\xd8e9\x9e<\x11\x02:s\x8eW,\xcf~\xcf\x85cF>\xd3\xcb$\xd2n\xb1z\xf4u\xfaUX\x18V\xad\xd5X~\xefDa\x9a\xde\x84\xd1'\xa7\x92\x1eb\xf8Y\xb8!\x8aZ\xcb\xef-\xaa\xc5ka\x07\xc7c(\xb4\x94\xb3\x8de$\x8e4\x06F\x92\x0f\xa2\x85\x9d\x1e+_\x8b\xc2\x97|$*\x08\xe4LZ\x8d}\xa0G}K>\xed\x1a{ie\xf5\x11\x1aT\\]\xdb\xa2X&\x1f=\x10\x89\xfat\xe9w\xc9\xe7Q\xbbjU>\x93Ooo\x9f\xffk{k\xd5N\x93OW\x87\x07\xd9b#.D\x12SRS\xee\n\xb6\x90\xb3 \xb9\xb9B\xc8\xd0\x9e\xdc \x1e$\x93ps\xf3\xaaa\x8d\x10\xf6D\xe5\xfd\xe6YQ\xcd\x03zt\xfd\xbf\x0e\xbd\x81\xd68<\x14\xe3\xd5hL=wU\x07\x89\xdf{f\xcdx\xbb\xa6\xb5\x89\xcc/\x84\x97E\x93<2\xe9;\xb2\x92\x0c\x91\xe0$\xbb\xc2s(S\xfc\xc2u\xd9\xb5Y\x84\x10y\xf5]\xa9F\xfe\xca\x83i\x91/\x00\x9d\x83\x85i\x9aG\xca\xcf\x0fY\x19NI+\xe1\"\xcdo\xb5#\x81\x91\xa3n\xe2\x16\xdc\xa7\x0c\x0d*w\x94\xa1\xe7C\xe2\xe6<~b\xc8\xdb\xea\xa7G\xf0h0x\xce4\x1f\x0c\xceA\xe34\xc8rq\"\x88\n\xcc\x94\x8biRX\x0f\xf9\x1c\xdc\xb3\x8b\xbdg\x97\xd6\xc5\x8e\xeeI\xb0j\x9b{6I\xae\x0d\xc1\x14\x98\xc2\x05\xc2>\x14\xc14\x91Z\xc1\x8c\x86\x13\xaf\xcaoT\xb07\x8c],z\xaf\xf2\xe9?a\xec\xf5\xd2\x98\x16E\x01\xbe\xff\xc2\xce\x15\x01\xeb\x81`G{\x05\x87\x83h=u#e\xee\x8b\x97\xdf{\xae3\xcd\x8bq\x18\xcd\x9dA\xa8\xa8O\xe3\xf5\xd9\xaeY\x10\xf1\xcc\xe2\x06r\xf7\xb5.)\x10\x82\x88W\xaa\x18\xd7\x1dL\x8c#R\xc3\xf8$+T\xcfL\x8d3\xdb\xbaC\xfe\x01\x9e6\\\xe5n4\x84\xban)\x9c\xc3r\x97\xb1D\xb0/\x0c\xc2\xcb\xc6\xd1\xf5T\x04\x8c\x94\x8c\x0dFO[\xa1I\x13\xe7\x0b6\xd0n\x08\x93\xc3J\x7f\xd3\x89\x1c\x11\x93KI#2\x04\x97\x92v\xebx\x9e\xcf\x0d\xe1\x1b\xa3\x82Z\x91\xc6\xe0\xc6\xb0\x19\x96%kgP\xc5\x9fI\xfbs\x1d\xa2G\x8fK\x0c%\xdb\xfen\xee\x96\xac[ld\xb5x\xf6\xab\x17\xcc\x86\xf2\x83b\xa9|\xdd\xef@u\x0di^\x15\x945\xf1@\x06\xe6\xc5I\x1b\x8b\xf3LY\x1c\x86\xceh\xa5\xec\x03#H\xc4=\x88\xf8\x8e\x16\xe8\xcd\xef\x19\xb7qS\x1a\xe5\x1fqA\xd3\xba\x0f\xca\x17\x0d\x18$ \x945 \xac\x0c\x80P\xb6\x00\x01},\x98\x16\x1d\x05\xd3\x86%G\x9bd\xc3J7A\xc1\xa0\x01\xa4\x82B\xa9\xafv*V;\xf5D\x0c\xbd\xe8~(\xa9\xc6\x12\xadp\xb9\x02I<5_\x01={f2\x18\xcb\\\x8b\xb0rwW\x17nrt\xb7\xfbB\xc7M\xdc\xa7D[R\xa9\xaa\xbd\xb8TS\x82\xd5\x87\x88\xbe\x05\x97&\xb8\x8e}\x98\xfb\xb0\xf6a\xe1\xc3\x0c\xf6`\xa9\xaa\x89\xdbhU);n}dD\xa5Y\x94w\x87\xc2\x06\xde\x11\x06\xd9Oa\x04:\xbae\xcf\x0d\x92\xe0\xcd \xb6q\xc6\xb3\x1e\xe3\x8e\x84r8i\x99v\xb0\x1a\x13wf\xd4\x19E\xba3\xe6\xa6\x072F\xef\x1b\x88\xe1\x0fp\xf3\x06n67\xcd\xd46\xab\xd1]\x08G\xacwn\xe8\xce\x91T\xbd\xb9\xf2\xf0\x8em.\xee\xd8\xee\\L\xf3P\x06\x81\xb7_\x0b\x1e\x0b\xb2\xba\x9a]4!\x1a\xcd\x7f\xcd}\\\xc3\x1eTq'\xde\xc0\x066\xb9F\x8e\xc3\xf5\xbc \xce3b\xb8\x14\x06\xb5\xb3\xb9\xbb\xf6\xe1\xce\x879\xb7\xc5\xe3w\xc4\x03\xba\xf6\xd5\x0b~<\x1f\x1f\xfc\x99\xc7j\xa5\xc1\xf9\xf8\xf2\xc3\xf9)\xec\x89\xdd\xf6\x8d\xe7\xb3\xd5'u\x11\x1c\x8d\xdf\x1e|xw \xfd\xfe\xa9ww^\xf5\xf8\x9d~)\xfcL\xbf\x12\xff_\xdf\xdb\xdf\xb4BR<\xb7\xdcm\xec\xe8\xdb<1\\\xf1\xdc\xdf\x94\xd1rH\x85Fm\x8aD1pD\xee\xc5\x0d\xb1\x18\xddd\x83\x00\xad6a&\x1f\xec\x96\xd6+W\xa8\x869O_\xeaGCU\xcchc]}\xb5-\xdc\x0e\xa7}\xd9\x7f\xdep\x05\xa7\x07\x82\xc9\x8cxp\xf8\xda \xb39FQ\xde\xe2(\x10\xa6I\x16\xa6ig\xd7:;\x0eP\xb9&\xeb\xcf\x08r\xa4Q\x9a\x97b\x00\x9d\x05\x9aF\xe6\xdcu\xc5\xe0\n\x86\x0c\x0e\xba\xe6\xde\x93\xa8\x15{\x1a@\xba\xd2\xb0\xd9)\x81d-\xb0\x11s\x03a\xdbu\x8b|V\xed\xab\x05\x90\xd8\x81\xfb\x83GM?\xae\xff\x93U\xbcNh\xe7u*\xcffA$\xa0\xf8\x80\xbaa\xa7+\n\xae\x01\xd6\xa3T\xc5\x88,\xe7\xc9\xdfV9}\xd3\xe1\x8b\x83=7\x05 ?\xd9\xb3\xf0\xd6^\x0di-\\,\x1f\xa5\xb1\xd7C\x1a\xfb\xb7\xcfO_>Fk/:\x14\x0d\xa1j-}\x94i|\xd1\xa3b\xc8\xdb\x9a}k[\x83t\xd8\xa2<\xa3I\xb6j\xdf\x0c\x81\x95\xc5\xe3|0j\xf6\xbb l2\xfcX\xaen\xf8\xb5\xb5\xbb\xf2!\xf4\xe4e>\xe3@\x19+\xbc\xa9#:s\xe5b\xaf\xca\xfa\xf7Y\xc9v\xe50\xd2C\x0c<\x92\xbaH\x83\xea2\xfa\xa67\x851\x0b\x852\xb5\xd9@\xaf\xcd\\\x96\"\xbf\xce@ [\x92\x96FId\xb8\xb5\x9d\xa2p\xa1\x99\xb6l\xa3\xabvx>\xf6\xd0|yp\x93\x17t\x04N\xc8\xfe\x1b\xd0\x1f\xcb\x92%\x0b\x0c\xe11\xce\xe2\x11\x94\xae\x13\xca\x04\x92\xc5\\\xff\xb9\x99\xd4]\xcb1%<\"H\xb3\xaeD&\xeb5\xd6\x1f\xba\xeb\xbd\xa0!\x1b\x89Zg\xc9\x92\xf4\xfax\xa2\xb1\xae\x1f\xd3U1\x02\xe7&]\xe9&\xed\"\xc3a\x98\xbdO\xc3\xbb\x118Q\x98-\xd3\xf0\xae3\xdb\xe5\xbc\xc8W\xb3y\x9d\x9b\xf2\x04K\xa1y\x98\xcd\x08\xcb\x8c?,\x99RT\x01w\"\x8c e\xce\x92/\x96y\x99T\x0b\xe6Du\x82uu\x94Bb\x1e\xd5b\x1dS\xa6\x14\xfc\xb0\x8cQ&\xa0\x96\\a\x9a\xadhF\xc9gzB\xb2\x15\x16\xc2\xb7\x05\xc9V\xb6\xecK\x9c\xf8|i\x9b\xf5\x15v{e\xe9\xa9\x12\x1ek\x04N|\x93v\xcc\xe1Q\x11\xceX\xa6\"\x9c\xd93\xf0\xd9ey\xac\xd3\xca\xb3QRT\x19)\xb1\x80\x16f\xfd\x9cP\x99\xf3sb\x1bG\x11\xce0\xc0\xa3\xc8\x99\xb2\xdf\xf6\xacg\xeb\xaa\xf5|\xdd\xd5\xb8\\w\x96\xb3c\xc1\x8f\x8a|\x89\xb9\xf2\xa5%\xc3\x8ao\xd7\n\x9ec\x91\xd0\x05\xd7\xe3\xc5\x92&\x84\xcd'\xe1\xbf,\xd9\xb2\xa8\xb8[R\x9eQ\xfe\xb6e\x8dE\xb6\xd8\x9a\xa5(r67\x84\xfd7gy\x9bG\xabr\x04\xce\x94\xfd7g9\xce\x96\x08x<\x02\x981\xcb\x9f\xc9\xddQ~\x9b\x8d\xc0\xf9D\xee\xe2\xfc\xd6\x82\xca\xfeL\xee\xde\x17\xa4,y\xbe%\xfbi\xcd\xf8a\xc9s\xad,\xab\xf0\x0e-\x93\x19\x0f2\x92f\xca\x8cs\xe9\xca|Bh\x18\xab\x05\x16\"\xc1^H\xc2\x0c\xcb\xdf\x013U\xe0\xb8\x118\x0b\xf6\xdb>\x07U\x108\x99\x95qW\x1dY\xcfp\xee1gn\x9b~\x9e\x91\xef\x03\x9e\xd3\xba\x11D\x988\x99\xd16\xbb\xef\xc3\x121\xdd\x92\xfd\xb7eY\x95<\xcb\xaa\xb4e\xe1G\x89\xfd\x1ca\x19\x92l&\xf2$\x99\x05\x19\xbd/\xf2\x99\x80\x9b\xa5\xf8i\xcex\x1eRRm\xcb\"\xa4\xa4kKr \xdb\x08\x9c\x12\x7fX2\x11\xf2 \xb7Y\x89?\xec\x99\xf80J\xfe\xcb\x96-\xe5\x91=\xab.\x962\xa5\xb3\x9f4LS\xde\x07\xfe\xcb\x92mU. b\xec\x92\xff2g\xbb$\x9f\xa9\xdc\xd1T\xfe\xb6dM\x16\xa4:\xf3h\xb2 ]\x87\xdde\xbe\x8a\xe6\x87a\x16\x116\xa5\x94\xbdE\xf8\xd6\x91\x9d\x1f0\x98\xd7\xde_\xf6U\xec\x17\xcci\xdf/\x98U\xeeX\xcc\xdb\xb1e\xf1\xda/Q\xa9>Z\xa5\xd4d_3\xcdX\xd1\xcfy\xbaZ\xd4P\xb7\xc6\xd7\xae\xf5\xfc%L(\x87\x96[\xfe\xcb\x92mNp*o\xd9\x7f\xcd\x04\xb4Y`\xcex(\x1e\x85\xa6\n\xa2w|\xe4\xc0\xa6\x90\x18\xb9\x8d8\x04^P\xa6ID\xdc\xa7^\x93\x1dX\xa3j\xdb?\xbe\xa2VE\x93\x94>'2\xd2Z\x1d\xa4\xb0}\x990 p\xad\xa9\xa2~\xf99:\x8f\xf9)\xcc\xe2\x94\\\xe6\xcbwdMRw\x1d\xcc\x1b \x9e\x0f\xeb\xa0]=\xec\xf5{ll\x8e\xa2$t\x9ca@\xcc\xbe\xae\x19\xdb{\xf2\xc4\x98\x1e\xd4\xd5\xb6\\\x01j\xb3X\xb6\x9b7\xb5.5\x88\xdc\x0dc?\xbe|\x01\xe3\x87\xa0\xaa\xdf\xed\x0e1\x97b\x81\xcb|\x80S\xd1\x86\xa4\x98\xfa\xd0\xed;O>b\x00=j}\x95\x16\xde\\D\"\x99\xcc\xaf`\x0f\x96\x9b\x9b>D\x13\xf6&\x82\xfcV\xaf\xed\xe5\xe6\x11 `\x0f\x92V\xc0\xc6#\xc20%\xc9\xa2\x84\x94\x13r\xd50f\xcb\x87\x08\xb3P\xcb\x9d\xed\x1c\xabu[\xa1\xc7\x99\\\x89X2+\x1e\xa7\xd8\x91{\x9d\xcb\x86Wht/v\xbd\x07\xfbfp\xa2E\xb8\xfcqu\xc3\xd6\x11?(\xb5\xf8\x12e\x08\xb3\x9d\xd4\xe5G\xfd7\xd5\xa8\xd4 \xaa}@%Gg'H~\\\x88\xf3\x96W\xe4TGqc\x02\xe4\xa1\x0c\x1b;\x9d}\x16\x01o\x95\xf6\xaa\xea\xeb:\xee\xd9cC\x0d\xc6\xc2\xbf\x1c\x9f\x1e\x9d\xfdr\xfd\xd3\xc1\xe9\xd1\xbb\xb1\x1c\x0bR\xd4r(x\x86p\xbe\xbb\x1e\x9d\x9b\xba\x92\xde\x16\xa3s\xef1\xbc\xb7\xa2dUEf\xc1}\x96\xf2\xd8\x17_\n\x01 \xf3\x04\x90`uI\xe6\x08\x15\xd7\xc1\x93\xd5\xecO\x92\xf5\xf5\xa8U\x81\xec\x10\x96G\x1a\x97u\xca\x87\"\x10\x1f\x85N\n\xbeck\x98\xc0\xba\x1d\x9b\xf7\xd6\xb0\xb6W>\xc4\x93\xd5\x15\xef.n\xc7\xbdVHy\xe8;.\xf4Z\xfb\x03\xd5\x80b\x867\xa8\x9f-\x85bK7\x1aK\xfd8\xfdhB\xcf\x90\x8e\x88\xc86<4\xe9\xfbpF\xfe\xf2k\xcfA\x86\xb7\x17\xfa\xad\x1e+\xdd\xe9Kz-\x9c\x86\x9a\n\xba\x0e\xa2\x19\xfcm\xd2\xe3\x92\xf7$\xaa\xd3\x06UQ\xa0k|$+W\x85\xc0`?\x87\xe9\x8a\x9c\xe4YB\xf3\x02 \xba\xdeq*\xae.\x90T\xc0K\xdcu`\x984\x97\xed\x80\x0d\xcc\xb41\xed:|\xd8$\xac\x82\x82L\x0bR\xce\x95~\x95\x96\xfb@\xd3R/\xf8\x18\x94\xd2\xe8\xebzZ\x87\xecR\x1fm?To_-\x06\x08\x83<\x904\xc5\xd4Ur\xa5\xd1P\xb4\xe6\x94k\xb4^\x17\xab\x94\x94\xd7\xd7\x0d\xdd\xf0\xeb(\x8c\xe6\x04\x13-\xd7\x8b\x85Bp\\_O\x93,\xc6\xdcv\xaa\xa5\xad\xf7W5-\xc8\x04~\x8d\xb7\xb5\xfb\x06\xa8\xd5\xb1`\xb3\xe0ds3\xbbB\x85\x01\xae*s\x0fO\x83\xbe6\x82(_,\x93\x944\x07a\xbaB'\xa2\xfb\x06\x96\x83M\xa1\xe3hT\x0cQ\xc6)\xecI\xddn\xda\x8e\x04\x84\x13\x98\xfc~\xe3\xf5\x18\x07\xa8\x95\xa2\xae\xfe?\xd0\x07q\xaby[ OY\x92\xc7\xda\xe2\xae\xf3:\x86oD\xa9\xec\xc9\xd4)p\xd1!X\x86\x13!\x07G\xf9\xe0\xbe|\xd1Z\xe5#\xcd\x82if\x88M\xdd\x1a\xad\x0d\x1cB:\xd0\xf2\xa5\xa8a\x99o\x01\xa3\x11\x1a^\x12\xb1\xbe\xea>\xa3\x19Doq\xb5\x81B\xb5\x8c\x16V\xd1\xef\xc3\xa2$\x05\xb0\xe9C\xc3\xb2i\xbeB~\x1f6A7K\xd7\xf6Eq\x15L\xa5\xf1g\xebK\x98b$c\xfc\xff\xe5\xcb\x90]\xdf\x9c\x9d\x1b2\xcd\x0bb4\xf7k\xb9\xb1ZK\xcfx\xbd\x93\x94Hm\x9c\x8eI\xca\x1fs\x92\x82r\x89l|\xee\xc3\x8e\xc9\xf5!C+F\x13R\"\xd9K\x93C\xc4if4/\x0dS:\x82\xa4\x9e\xf2\xd6\xb6\xbb\xd7\n\x84SJ\x8a\xff=\x0b\xc0o~\xff\xa7-\x02\xc34\xf7@\x13F\x04\xa0M\x08\"/\xdb$\x18T[z'\xc10q8 \xc5cM\x02\xefA\x9f\xf2\x17\xcb\xd0\x0cJ\x8b\xae` \x8c\x00e\x06\xdc\xe3cs.\x86\x1dy\xf5Y\xd9\xd2\xa0\xe7\x87\xd9\xb0j4\xba\xa4\xda%fU!\xca\xce\x1e\xc3N8g]\x87E\x98\x853R\x8c \xc9\xd6a\x9a\xc4bg0\"\xc5\xb4'\xa0\x8d\xbd\xe9\x95:*=\x84\x13\xe6\xbe\xef:\xc5I\xd9Z(}\"\xdc\xeee\xf2\xfe\x17\xcc\xe5\xeec\xcc\xe5\x8cP\xde\xbb\x01jo\xc2\xcb\xc1\x9e\xdeB\x0d\xef\x15\xe1\xe9\xb6\xfa1!W\xda\x1e\xfd\xea\xdf\xdf\xf3{\xbf\xbb\x93\xce\xbd\xbb\xe6nC\nn1hq\xd6\x8e\x16\xc0\xc12/O\xc2\xcf\xed\xaf+\xf9\xb5\xfd\xa9\xc4OIy\x9c\xbd\x0boH\xda>x\x94\x8f^M\xc7\x9b\xf2\xa5,\xcf\x87l\x11\xd2hN\xe2\x8b(_\x92\xb2\x8e\x0dj\xfc\xbc\xb5\xe5\xb7*C>\x05{\x8bf\xf5x4)\x9d\x10\xa2\x14F\\\xed\xbe\xe1\xa3\x82\x1f 4z\x9ag\xfdz\xcd\x0fN7\x07\xa1\xca\xaf\xea\xecaq\xcf\xf3 \xdb\xdclCr\x15\x82\xfb\xf53\xe1\xdb\x11\xbd\x04\xb2\x9f[[V\xd2\x99\x0b{\xcc\xbc+\xea\x80\xb5\xbe\xb4u\xabP)\xb7$EP~J\x96\x97\xf9'\x92\xd9\xc3\xef\x80\xa2\x11\x0f\xfb\xdc\xc5\x19_l\xcb\xa4\xc3\x1e\xf7\x0cb\xfd\x9a\xc1\x16\x9ft\xbe\x06+}\xfeK\xff\xe1a\x15^\xdb\xa2`r)\xba\xeb\xfc\xdd\xf1\x8cq\xa5\\%\xb6r\xa7V\xaa\xd4w\xbd\xa8=B\x15\x02\x8f\"\xc1C]\xc7a\xc3\x17\x0d\xf6j\xa3\xa9\xf5\x0f\xd3\xb8m\xc8IL\xa1H\x9d\xc30\xfb=\x85(LSX\x10:\xcfc\xc830b\xd4\x96\xcb\x8d{\xcew+&\xa20S\xd8\xf5\x02)x\xd2no\xd0a\x87\x08\xe0\xe2\xe6M%\xf5^\x1f\xa4\x96\xc5H`\x1f\xb4\xaa\\\xf4:\xaf\xd8\xb1\xdd\x7f`}\x9d1 S\x14\xd5\x15jD8\xcdW\xb8\xc0\xb6y\x1b\xc1!\x8dd\xf2\x97\xedr\xedt\x19\xae\x9c\x87]+\x10\xe1\xc8\x18\xd3^\xdd\x9e\xa1\xe6\x8eJ\xd1?\xc7\xd9\xf4\xfeun\xfcs\xbak\x83\xe4<[\x93\x82\x82p\xfbKsX\x16\xc9\"\xa1\xc9\x9ap\xefON\xdf.\xd3\xd6\xb9\xe9\x0c\xec\xfb\x9d\xfb\xfa\xe5\xd0\xadpd\xd4w\xdd'\xb8\xf0\xf4\xf5B\xd7\x1f\x0dE\xfa\xae\xe7:\xc7\xe3\xeb\xf7\xe7g\x97gz\xd0\xd1U+jA\xe3s\xd9%\xc8\x02)\xcc\x12\x8e\x99\xdc\xdd\xef_x\xae\x93L\x8bpA\xf4\x86\xe4S\xe0\x05\xa0\xcdS+\x8f\xc2\x12\xa0I\x10#7\x97ix\x07{\xe0dyF\x1c\x1f\xa3R\xecx\x0d;\x17\xee\xa4\xb0,\"\x96\xed\xaf\xe1:\xe4VE#\xc7\xe7\xa4(\x0dP\xe3/\xa3\xbf$Y\x9c\xdfV\x08\xc3\x0b\xf2%\xc9\\\x1e*\xa0H(q\x9d\x1fx\xd1?T\xc2\xec\xb7{\x1c\xbf\xfe\xf0q[|r0?\x1a\xbc\xba\xc2\x95\x14 \xde\xbe\x81bk\xeb\x8d\x07\"<\x8b\x12oe\x92L\x8a+\xc3\x8d\xa4\x00\xcc\xd2\xd5\x0e\xc4\xaecE\xa0\x1eP\xa3\xb6Zi-#\x02\x16\xa2v\xe9.Kq\x8e\xcf\x8f\x17N\x91\xa0\x03t\x1f\x9a\x9f\x85\x93\xd3I\x88n,\xd1\xfe\x04=\x9fka\xd4\xa5\xe3h7\xfb\xff^D\xfa\x17O=\xd7\xf9D\xeeJs`\xdf\xdd\xdd\xfe83\x96\x8e\x17\x82\x86w\xf1\x07w(\xf9\xe0~>5\xd9$\x17\x13\x871\x11\x05\xd9\xfaky]\xce\xc3\x82\xc4\xd7\xd7\x8el\xd4\xfc\x0d\xef\xfb\x1f8\xa2\\\x8e(\xe7#\xfa\xc7\xd7\xbe\xf1\xd8\x10\xab\xa38\xd2\xf7\x9b\xd7\x90~R\xbe\x97 |6\xf5M\x04\x99O\xf3wy\x14\xa6\x84\x9f#\xbe\xe4\x9e'\xb0u\x82~\x07\xd1\xa1\xacsVG]B\xbb\xb2\x02\xcd\"-T\x18;\\\xc34%8be\xe9F\xc2\x12\x19\x1e\x008\xde5#8773\xd8\x84\xc2\xab\x18\x13F\xc4\xf7\x9dl\xd6\xbd\xf0\xd2\xe2\xea\xf7\xd9\xffx\xb6\xf7y\x0f\xa9\xf4\xe2\xe5C{\xfb\xa8\xa4\xd2\xee\xeeK/\x98\x9a\x899\x93\x07\x17\x13\x9e\xea\x1b\x87\xf9\xbe\x07\x95a6r$V3!='5A\xeeC\"\x03\x84\xa2\x03\xb6\xf6foz\xa25\xdd\xecH\x87\xc6\xcd\x8d~\xcf\xb9\xea\xf5\x80\xf3t\xd74\x03\x18{\xbdw-\x19#b\xcf\x04\n\xcem3X(\x03_\xf2\x18B\x82\xa7!\x0d\xdf\x11\xc6XI\xa0\x13L\x8c\xa5\xf9\xf2Eu\xd4\x9e\x19$a?\x86\xb1\x8cW\x04\n9ju\xcf\xc7=)g\x95\xec]}\xaa\xcb3\x11\xd5J\xa0\xd1*\x11e\x13\xe8\x8eVc\x1d\xbf\x81uy\xfa\xbdY\xd4\xf0\xbdM\xce\xd9\x07\xbe F\xefd\xc8\xbf5W|k\xfc\x9b\x03\x9b\x90\xa1\xbf\xdb8'e\xf6{\na\x14\x91%\x85\x82\xcc\xc8\xe7\x96\xd3[\x01\x11\x02\xa9~\xdb\xa6f[\x14\xa5\xc5\xfd\x9b\xd3x\xc6\xc3\x1el\x07\xdb\x9aH\xc9x\xe2:\xdb\xc1\xb6\x03\x13r\xe5jnu\xaa\xa3\xd6(\x80\xef=\xbe\xe9\xa4\xb8\xe2\xf6\xb8\xb0am\x03z\x8et\xd3\xfcn\xdc3\xe0\x11\xc5\x8d\x8c\xb4\xfd\x90\xec=L(\xb27F\xac\xda2Q\x16\xa2\xad\xd6 \xc9M\xa0\x9f\xefx\xc1\xf4\xa1k\x9b\x07\xfc\xcc\xe7\xec\xa9|\xe1\x81\xa1\xfe\xf1\x15\x83.\xd4\x19\xfe\xa1Gtq\xae\x91\xc4!xAs@\xdd\x1d\xd4\x97'\x90d\x1c\x93\xac0f\x95 c\x0b|\x1c\x06\xd3\xd65I\x1f\xac\xb7\x97DH\x8cf\x84*\xfc0\xef\xb6\xd9\x8d\x07\x0fXz\x7fT\xdf\xa1\xcd\xb5\xfd\xddFs\x90\xdf\xc1\x1fc\xc2\x05iI\x9e\xc19\x89VE\x99\xac\x89\x94\xb8\x92\xcf\x94dq\x92\xcdZ\xc5\xc2\x15\x9d\xe7\x05\xfc\x9c\x84\xd1\x9c\x94i\xb8\x86w9-\x17a\x96\xaf\xe1\x87T\xfe|\xf5\xfa\x8f\xb3E\x98\xa4A\x94/\xfe\xd0\xaa#M\"\x92\x95\x04N\x8e/\xb5oz\xd6\xcb9\xe6\x82w\xa2\x84{r|\xe9\xf5\x949\xcc\x97wE2\x9bSp#\x0f\x9e\xee\xec>\xdbz\xba\xb3\xfb\xca\xd8\xe5\x9e\xaa\xde\x93b\x91\x94\x18\x14,)aN\nrs\x07\xb3\"\xcc(\x89}\x98\x16\x84@>\x05\x06_3\xb6L9\x84\xd9\x1d,IQ\xe6\x19\xe474L\xb2$\x9bA\x08Q\xbe\xbc\x83|\xaaW\xcf\xce\x11(\xf3)\xbd\x0d\x0b\x02a\x16CX\x96y\x94\x84\x94\xc4\x95\x1e/Zf\xc04II .\x9d\x13p.D \xc7\xc36c\x12\xa6\x90d\xed\xca \xc8\x9cp\x9b\xd0y\xbeb(\x9d\x83M\x92g\xbe\xf0s\xcdz(?\xa7\xc9\"\x11\x0d\xb2\xe28\x8b%\xd0\\\xaf{U\x12\x1f\x07\xe5\xc3\"\x8f\x93)\xfbOp\x0e\x96\xab\x9b4)\xe7>\xc4 k\xe9fE\x89\x0f%K\xc4\x05\xf4\xd9(\xb7\xf3\x02J\x92\xa6\xac\x86\x84\x94\xc6\x89\xa9\xfb\x8eE\xf0\n\x80-\x06\x15\xd3\xcbz\x05\xb7\xf3|\xd1\x1cgR\xc2tUdI9'X&\xce\xa1\xcc}\xbd\xfarU\xdd+\xb0\xd2\xd3>\x1a\x1f\x81sp\x01\xc7\x17\x8e\x0f\xbf\x1c_\xfet\xf6\xe1\x12~98??8\xbd\xfc\x15\xce\xde\xc2\xc1\xe9\xaf\xf0\xe7\xe3\xd3#\x1f\xc6\x7fy\x7f>\xbe\xb8\x80\xb3s\xbd\xe6\xe3\x93\xf7\xef\x8e\xc7G>\x1c\x9f\x1e\xbe\xfbpt|\xfa'\xf8\xf1\xc3%\x9c\x9e]\xc2\xbb\xe3\x93\xe3\xcb\xf1\x11\\\x9ea\xfb\xa2\xe6\xe3\xf1\x05\xab\xfbd|~\xf8\xd3\xc1\xe9\xe5\xc1\x8f\xc7\xef\x8e/\x7f\xf5\xe1\xed\xf1\xe5\xe9\xf8\xe2B\xaf\xff\xed\xd99\x1c\xc0\xfb\x83\xf3\xcb\xe3\xc3\x0f\xef\x0e\xce\xe1\xfd\x87\xf3\xf7g\x17c88=\x82\xd3\xb3\xd3\xe3\xd3\xb7\xe7\xc7\xa7\x7f\x1a\x9f\x8cO/\x038>\x85\xd33\x18\xff<>\xbd\x84\x8b\x9f\x0e\xde\xbd\xc3\x96\x0f>\\\xfetvn\xea\xfd\xe1\xd9\xfb_\xcf\x8f\xff\xf4\xd3%\xfct\xf6\xeeh|~\x01?\x8e\xe1\xdd\xf1\xc1\x8f\xef\xc6\xbc\xe5\xd3_\xe1\xf0\xdd\xc1\xf1\x89\x0fG\x07'\x07\x7fb}?\x87\xb3\xcb\x9f\xc6\xe7\x98M\xf4\xfd\x97\x9f\xc6,\xa957\xa7pp\n\x07\x87\x97\xc7g\xa7l\xcc\x87g\xa7\x97\xe7\x07\x87\x97>\\\x9e\x9d_V5\xfdr|1\xf6\xe1\xe0\xfc\xf8\x82\xcd\xde\xdb\xf3\xb3\x13\x1f\xd8R\x9c\xbdeY\x8eO\xdb\x9d>=\x1d\xf3J\xd9\xaa5\x17\xf7\xec\x1c\xdf?\\\x8c\xeb\x9e\x1e\x8d\x0f\xde\x1d\x9f\xfe\xe9\x82uH\xcd\xacC\xcdv\xe3]\x9e%`!\xf7\xa5\xf4\x02\x92\x8c\xc1g\xc4\xe3\xfc\x8a\xf3\xb5J9\x12\x97$\x8d\xc4s2\x1b\x7fn:\xf1S\xe2oAS\xc7\xdd\xd88\xea\x874Z\xb6q\x10R&AE\x04\xaa}\xf9\xab\x0e\xca\x00#dI\xa8\x12\xa6\xc1XU\xa5x\xc26<\x1a\xd0\x19\xbc\x92\xf7w\x95M\x89\xa7\xb2U,\xc1E%\xa4\xcbdA\x1a\xd2.k%|\n\x1b\xd5\xf0$\xa3ZVK\x17\xebCF>/I\xc4N\x992\xa1+\xe1\x83e\xd0\x8a\xe4VI\x97\x14\xd3\\_#o|}\xedT\xf7PUh\x99\x96\xb0\xab9ak\xe1\x94\xcbH%\xda\x00\xc1\x10\xe0h\x17\xad\xccd\xd4\xfa:\xd0G\x1d g\xe7\xaa\xd3\x96\xc6R\xefS\xaf%\xab\x9c\xec\x18\xae\x14\xe5M,7\x9e\xec\xce+*\xe4jz\xb5N\x1aZ$\xf3\xeb\xf3\xaa\xbc\x0f\xbb\x06\x9d=k\x14M\xc3\x04\xa0\xf9]%\xe0\xc4\xb7\xa6~\xe0\nidA\xb2~\"w\xa5\xbb24iu\xa1\x0f\nc\x84\x12\x9f\x90\xfb\xa2G\xe1I\xee\xa2gz\x1e\x19$T\xc1\xc2\xd0S\xd2\xe8\xa9\x8c\x9c\xeb\x86\x93\xb2\xba\xf54h6\xaay*\x90%f\xeb\x06\xf5Y\x0b\xa5\xea\xc9\xd0x\x8cm\x03\ntN\xd5\xdd\n\xa8\x8b\xa2\x85G\xaf\xee\x83\xd9~i\x8e\x0c\xa35\xe5\xe2\xba\x97\x8bw\xb3F\xa2\x90\xf9\x8a\xb7\x04-\xd6\xd5\x94\xb6\xf7-\xf5\xf9\xea\xf9\x90[s|E\xdd\x96\x11?\x06\x9a\x13\\\x88O\x86\xd5\xa3\x8d\xd5\xa3m8\xa3ze\xbc\xd7\xbc\xc2f:\x0f,l\xec\xa0!d%\x1bMhA1\xcd\x80\x94\xcf=\x11Oq\x10\xbf|\x1f\xa5K\x9b\x00\xbb\xbd\xf4D\x89\x92\xc4\xd6\xd6b\x94\x88\xcc\xba\x01u\xb4\xd4{qZ'W(\x11n\xe7\xcf\xb8>\xba\x1et\x9a=\xea\x8e\xa7\x86\x1do\x0d7,Q6\x9d\xe4\x96\xbdc\x0c\xb9\x94\x08\xffqO\x9e\x98\xa6\x85\xf1\xf7[\xbb\\\xc6W[\x08M\xf2+6\xbcb\x92_a<\xf7\xc3\xa4\x88ViX\\90\x92\xa9\x04\xb3\xf9\x90 \x97\x0e;\x08P\xe2\xa3!\x00\xaa)\n\xac!\xf6#\xe56ih\x9f(\xcc\xd3D\xda\xd0\xf2\x0bR\x96\xe1LV!\xdf\xf6\xea/C+*i\x18}\x12\xd5\xf0\xdf{2\xd5P\x85\x14\xc57w\x04\x03\xf0 \x06\x922\xde\x06\xe1m\xca\xe4\xad\xf8\xc2-?\x84\x1f_\xe0~\xd5\xf2\xecn\x91\xafJ\xc7\x83Mpp\xfe\x1f\xacP\xf8\xfd+\xf35\xe3\x0bc\xc8#\x96n\xf2|\xcc\xd2\xf5k\x80\x95H\x7f\xed\x99\xcc'K\xbb\xd8\xc9\xa4\x10\x8d\xda8J\x84\xbb\x1d\xae\xf0j\xd0\x9d\xe2zS\xdc\x19? \x0b\xd7{\x03\x9b\x9b\x14~\x80\xcc\xa8S,g\xa2\x1do \xa4\xec\xbc$\xd4-0\xfeW1\xd9\xbd\xb2\xe9\xed\xd6\xbf\x14\xa5'\xde\x07\x86\xac\xfdF\xb2P\x8f\xc2`\x1ceS\x15\x9em\x94f\xe2{\xe9\xf9\xe0\x9c\x84K\x9b\x10x\x90V\xbc\"Un\x85\xd0\x13\x10e\xf1\xea\xf8\xc2\"\xd2|\xd1\x12\x81\n\x88\xda\xd5E\xf4\xa5H\x7fi\x84\xb4\xd4\x0ei\xc2< \x0ei\xc8\xad\x140\x1a\x99\xd1\xca\xaaL\xfe\xce\xf1\x05\xfbaX\xf4\xd4\xb0\xe8\xb9\xdfH\xae\x16=i\xa6\xf3E\x0f\x9b\x89|\xd1W\xcdD\xbe\xe8es\xd1S\xe3\xf2\xa8C\x1e\xacN\xdb\xf0\x9b\xb2\xb5\xcb\x1d\xa7\xd0\xca\x9c\x98\xeb\xdcK\x1f$\x9b\x9b\x19\xfc\x00\xc5\x1b\x0f\xc8$\x87M\xc0\xf81\xed\xb05\x92o\xd3\xe6l08\xbdx\xaa#\x1c\xa1\xf2\xfcZ\x07\x1bcL6\xa3\xaaS\x0b\xda\xba\x84\xc4m\x18\x0c\xd5\xe0\x8a]\xec\xb9\x8a\xb1\x90,@B\\Q\x1e(\xdc\x90\x1b\xb6[E\xc7Z\x8dj\x10\xb8V\xbe\xaf\xba\x03\x1dF\x83\x9a\xf7\xf4\xea\xbe\x8b`>%\x9e\xebkcZ\x83\xf6t'\x9a\x97\x8c\xf6\x14'\x03\x16\x0eq\xd37\xaa\xb6\x08u\xc7A\xab\x99\xb3\xaf<\xe8L\x15E\x15\xd56\xb8\x87\x92\x8dU;\xbd\xd9\x9ey)\x06!\xed\x0e\x1b\xb1z\x95\x9e\xe9\xab\x015\xf2m!e\x90\xbaB\x16\x8e\x08\xffl\xd0 \xcbcry\xb7D\xd2\xc9d\xfe\x88\xf7Af:\x92;\xa4\xc7zH\xa3\x1e\x83\xe9%\xdfW8\xbb\xd5\xd4\xec\xf1\xab&\x19t^\xb0&&\xbf\xe0l\x1e\xdd\x15\xec\xc3*HJ-7\xb2\xd4\x9a\xde{{\xfeAgPv\x9f=\xf7\xaa\xcb\xd5!z7\xafwv^\xee\xbe~\xfd\xf4\xfb\xe7/\x9f\xef\xbc~\xbd\xfbP6\xc5\xe4\xbf\x1d\xe7\xf1\x0f\x8c(\xc7_\xff\x81\xbe\xf1\xb93\x02\x02?\xec)\xa2\xb0\xfek\xb1{\xf5\xa6\x1b1I\xdc\xde\xba\xd4\xed\xe9\xceC\x80\xfb\xe9K\x9d\xc0\x04\x01\xdd\xdf\x08\xc1l\x13\xe4\x8f\x00\xc1\xd5NH\x1a\x10\x8cU\xa3\xb9cDJ\x83\xc5\x9env\xd0\xca\x00\x9d\xf7\xe0 \xe5]u\xeb\x05\xf9\xdb*)H\xe3\xc5uV4I\x1d/`\x03\xb3xb\x01U\xae\xfc\xe5\x8b\xdc\x8e7 \xdeD6^du\xc6zz\x02[}u=\xfbf\\=`3v(W\x99\xaf\xd6[FT\x0c\x04\xb6?\x06_>N\xdc\xfd\xd1\xe4\xffL>^]}\xf7\xc5\x9d8\xbf\xbf\xf2\xdc\xfd\x91\xbb\xbf\xf1q\xd7\x9b\xfc\x9f\x8f\x1f\xaf\xbe|\xfc\x18x\xdf\xed\x7f\xdc\xf5>\xea\x81Yx\x00\x98\x8f\xb7\xdf\xfd{oH\x07\x8b!S\xc3\x8eI\x17\x8bV\x92t\x01\x98F\"k\xc3\xad\xb0\xc7\xc6\x1ed\x08\xd4%R1JB\x158B\xa64\xdc\x0em\xa0F .?\x8f\x05\xc2\xa3\xc8n$\xea\x9b,A\xf9\xf6H\xa4\xd3<\xf7^\x86\x0e\xf7BD\xf7\xa4\x1f\xcd\xf2\"A\x99pm\xd3\xcaE\x17\xf5\xc1\xb9\xbe&\xe5I\x1e\xafR\xe2\xe8\x1a B\x1bAU\x08AC\x9b\x05Y\xe4\xc9\xdfI|\x11.\x96)y[\xe4\x8b\x8bhN\x16\xa1\x90*\xf0\x8f\x87\xa8,\xf8\x97\x93w\xe3\xcf\x98\x8d\xb3\x10\xf8\xf3/\x8bT+\x94dSR(\xefe\xbbfq\x00\x824\x81i\xd4\xac(z(\xec\x98\x89\x1b\x0b\xdd\xcc}\xf1\xfd\x0b\xcf\xb0\x0f\xf0\xd3\x8b\xd7\x9e\x91\x97\n\xed\xeb\x83\xa0\x10\xd4\xf3(T\xf5\xdaXKFF\xd0\xddZ\xfd\xae\xfdk-|\x19\xb6+\xe1\xa2\x99\xe1qm\xa5,\xa7\x95\xc7\x10F\x8bg\xbd&\x8b0I\xef\xd1\xc2\xaa$\xc5\x1f _\x8c \xca\x17\x83\xda\x12\xfdb,(\xd9\xa2\xc9\x828\xc3[t\xe5\xf5\x95\x17\xd0\xfc\xf8\xe2L\xa8\x84\x19\xf8\x02\x83<\x05\xd1\xc4\xf0\xb6\x06\xc5u\xe3\x95^O\xd3<\xa4\x8f\\u\x92Q2{\xf4\x0e\x0bT\xd8G\xff\x83\xb2\xca*\xf6\x94\xb88\x10 \x8dW\xad\xf2\xa5\xdd~\x13\xdc\xdb\xbcLw'\xa4\xcc\x82mt\x17\x9d\x0frr%\x99\xdeyF\xff3 \xc4f4h3a\xf2AO6\xc14/\x16\xa1\x812\x02\x81\x12V\x13\xd4O\xbcv`\x13\xb8\xa9\xcc\xca\x18\xd5S\xc2%\xf6.)\xdf\xae\xb2\xc8s\x13\xc6c%\\O\xda\xf9\x90}\xca\xf2\xdb\x0c\xb5 \x85K\x1b\xec]\xd7\xd4\xa46\\Xa%\xcb\x0d\x93<2[7\x89\x7f\x00\xa4\xa3\x15U\xd6\xfa\x8ep\xf7\n\xf6\x9b\xaf\xa3\x96)\xa8|r\xd3RP\xcbR \x99\xd9\xb1\x14\xca\x97\"P\xe1\x8035V\xb3Vg\xaa9\xef\x1c[\x16\x00m\xce\xb26\x844\x93\xcf\xa2\xe3\xdb\x0c\xc9\xb0\xcf\x0bC\xc0f\xf60\x1c6\xc3;j\xf3\xf7\x1b\xfc\xbe,\xc841x\xb4b\xcfuU\x03F\xab5g\xba\xe5S\x9b\xad\x16\xe6\xef\xe3\x8aG\xb6\x1c\xe0a\xc7\x01\xceN\x90\xd4C\xa8\xfa\x97\x9c\xe2a\xdf)\xee\xb2Y\xbd\xc3K\xff,\xa7\xe1\x8cM\x8e\xc3\xcd\xa5\xdc\x1b\xd8\x87\x1bF\x96\x8f\xd0>\x16u\x01\xee|\xb8\xe6\xde\xd2\x17\x13\xf6\xdd\xf9\xbcH\xb3r\xc4\xce\x8e\x1b\x96 _\xd1_\xc1\xb5\x85\xc0Q\x0f\x05\xc48\x91\x0d\xf9\xb2\xdc\x11\x83\x07\xd8\x03\xfe\xff\xcb\x17\x98qK\x10\x9f\xa7HU\x0d\xe5\x85\xe5\xe1P\x023\x11\xa9>\xae\x88\xbf\xf5$\x93nn\x9b'\x04\x9e\x0d\xd3\x81ns\xe5\x13\xc9\x1d\xc8\xfd\xb6\xb2\xca\x85\xdf^v\"\xe4V\x9d\xa6\xd6\xf94g\xad\xcf\xef\xdd\xba|\xb6\xac\x8b\xfb\x8d\x0bs\xaf\xf6E\xaeV\xa6\x01\xe4\xb6U;\x91M\xfd\x85\x99\xdc\xee!\xa7\x0f\x199\xad\xec\x19\xb4$\x95\x1b\xf0\xc2N\x9d\xb2\xbe]\xe8q\n\x0e9\xde\xd8\xb8\x98\x1c*\x84\xf7\x97/\xb0T?\xd4$7#\xc6-\xd3\xd5h\x87\x95\xe2H\xa2\xfa){(\xde\x03\x06\xb3h\xa9\xd2\xb5l\xf2a\x03\xff\xd4R\xbc\xc3\xba\x90Jc\x9d\xad\xde&;Wv\x96E}\x0ed\xff:\x0fm\xfd9\x93\xa5\x04D\xd91\xbd|\x16\x93j\xd4\x12\x1d\x1e^UG\x16\x92M\x07l\x04\x07\xd04\xb5\x9dN\x0e\x91\xef\xc1\xff\xcdOg,\xfd\x8c%~b\x7fJ\x9c\x8b\xee\x85\xf9\xdaw\x80\xc9\xa7\xd9\xd9=hw\xbe\xe1\xf3H\x9dA\x8d\x18\x94\x03p\x1byx\xba\x05\xce\xd5\x87\xad\xfa{d\x99.\x86\x15h\x82\xc7{Tw\xe5;\x05\xd1\xa8pa\xf0^\xa2[\x8e\x04\xde\xf7L[\x17j\x94\xcc\xa4h\xa8\x0fQ7\xa9\xcd\x118\x07\xd9\x1d\x9d\xa3\x0dT\x98\xc1\x0dAc7\x0bU\x80\xe1Q\x86\x9e\x08zC\xa5\x8doeH\xee\x11\xcf\x99\x018R\xcc\xdc\xb8 \xffSv\xd4W,\x15&\xcd\xd9\xf9\xdbB\xff\xb7lQo9WV\xa2]\xb8Xa\xc6\xe1M\xcc}\xb7\xf6\xfb\xab\x0fcV\xd1X\xef\xfaW\xe3=\xc8\xd4x\x89'\x05\x8e\x11\xff\xda\x84R\x86\x0d\xb3\x86\x9c+\x97x\xc3s3\x93\x19lL\xa24\x94\x81{M~\x0b\x92,\xc6\xc0*\xceG\xaa\x85c\xd3\xaf\xe1\x00\xcda;.\xa5X\x7f\x92\xba?\xd3\xbe\x1b.-\x7f\xda\xaf&Q\xcd][t\xcf\xd5\xf0\xc8\x9aq\x87\x95V\x9ex\x15\x87\x05O[\x84\x9f\xabxrU\xc6Fb\x85\x1b\x95 hw\xc1`\xd7$\x85\"2OCl\xd8YY~?\x8ds\xd5\xd8\xa0\xbb\xe2\xc4Z\xb1\xeaz\xc5\xb0\xd2\x0dGY>d\x01\x06W\x19/\x12\xca\xdd\xdcc\x9a\x12\xac\xa3\x9ayy\xbb\xd8\xf8\xaaMz\x9dG\xac\xfeI\xf3\xfb\xaeV\xbe$z\x0e\xbb\xd4\x03\xa9&\xe5\x06\x9b*\xc6(D\x06\xa8\x10\xbe\xebL\x1e\x152X\xacJ\xca\xd0g\x08<\x1e\xf2\x9a\x88[)\x8b\x1b\x05#\\\x11\x0eo\xf5\xcc6GD\x16 \xed\xb7\x9f\xe7\xfe\x8f|X\xf9P\xfa`\xf0\xc4\xac\x83\xb9\xabm\x03\x0c!'\"\xe5\n+\x1c$\xc4\xd4l\x01~F\x05'\xb7\x9d\xce\xd5\xd2\xda\xe9\xd2\xd0\xceDo\xb1\x9e\xa1\x8b#U^\xe3\xa9\xc6oc^5\x9f|\x03\xcd\xc3F\x1f eZ\xbe.\xbf\xff\x90E\xe1j6\xa7>\xac\xb2rI\xa2d\x9a\x90\xb8\x1a\x1bv-\x00\xf7\xf7\xb0\x89\x0e\xa2\x1d\xcf\xe4.\x84\xb7\x17\x05\"j5\xa7\xde\xa3&\xdak\xcdq\x82^\xa2\xd4\x19\x98\x90+\xbb\x92\x05\xd7\xc2\xc8<\x0f\xca\xdb\x04UXt9\x97i\xca\xa2\xb0$\xb0k\x8e\xf4/\\\xb0\xa2[t3\xd5\x82>\xa4\xdb\x9f\xb0\xd2\xa7\xbd\x95\xfa\xcdu\xba\x7f\x13\xcf\xee\xd9\x84\xfa\xf6\xf4\x9e\x0d\xca\x9b\x7fc\x99UE\xd4\xf7[\xe1\xb1\xfd\x18.\x97\xe9\x9d\xe8\xe0J\xd7{\xad\x84\xf4\xb9k\n\\\x83,\xd4\xfd\x1a\xc4C/\xc5\xeb-n\xda\xe2y\x95^t\xc9C4r\xc7\xe5Pnnz\x90N\xca+\xad\x8bF\xfc\xa3j\x954\xb1L\x18\xc7J\xcc\xd0N\xe5!\xb6\xe3\xc26$oX\xfc\xce\xa4\xb2\xda\x1aYV\xa7^\x17\x96\xecAU\x0d<\x93\x91[5\x02)~cx\xd3u\x94/\x0e\xfa\xff(\\\x1a\xc8.y(\x90\xaf:8\x02\xaaU\x94\x04\x08/\xa5\x9f\xf6\xae\x074\x87$\x8b\n\xc2\x90\x0d\xfa\xb7\x08\x9c\xd6\x92J\xe4\xea\x9b\xe9/\xd9\x7fZ\x84\x11\x1e\x82\x8d\x04\x0cL\xd7u^\xe7h\xe6\x00\x1b`\x15\xb9&<\xfa\x8du5\xd9\xc3\x03\x88d\x12\x83\xee\x83[\xfd\xdec\x8c\x8dyU\xd0\x08[F\xd8J8M\xf0\xad\xeb\xd4\xbf\x13\xfb\xb7\xdaA\x9a\x0e\xe3\xad\xd6F\x07\x81\xad\xed\xd1\xb3\x156:\xc6\\\x15\xe5\x9ci\xeb\x8ax_g\xf4\xd1\x87\x98~\xe6>y\xd2\xb9/\xda]2\xb7f\x05t\x8a\x0e\xc8\x1a#\xd6\x97G8\x02\x90K\xd8\x9eh\xa3\x0d\xb7J+\x19\x8a\xe8\x8dh\xf0#cC\xaa\x0b\x0eF\x9e\xa6\xb0\xf04\x96\x93!\xb3\xa1\x03\x83\xc6\x04N\xd0\x9bjo\xbc\xb1W:\xa9\xf6\xcc\x16\xb4\xf8\x0e1\x13]\xcbh\x03\xeat\x10,\x9b\xc8\xd26\x8d\xc4\xdd\xf1\xea\xdbx\xbfE\xfc\x19(?I\xe3\xc3H\x8b\x16e\xea\xeba\xbe\xca\xba\x05\x02:\xbboS\xae\xa0\xed\x85m\xc3YRy\x94\x14\xd3`q\xa0R\x87+\x96\x16\x9c\xfd\xf8F\xe3F\xec#4\x1c\xe6\x95\xbaJ\xa3T\xbfI\x80n\x0cD5\x0f4\x99\xfbl\xe7{\xcf\x0b.hA\xc2\x85\xa0H\x82s\x12\xc6\"\x02\x1b\xbe\xffR$T\xbcg\xee\xee\xeb\xefQ\x80y\xb4Z\xa6\xe437\x80\xe3)\x97E\x98\x95\xd3\xbcX\xf0\x8aww0\xf5}X\x96\x97\xf3\"_\xcd\xe6<\xf3\x8b\xe7\x83LMz\x1d\x01\xf28_&T,\xdc9>\xdf\xf1l\xf4\x9fA\xd7\x1e481II\x12\xc6|\xa1|\x84\x07\xaa\xe0\xa7PF\x8b\xbbf\xd24\xc9\x92f\xc0E\xdb9\xbd\xd19\x07\xfa#-\x0f\x08o\xd4~\xb6\x93F\xaf\xec\xf9\x04R*\x8c\xe6\xfb\xea\xb3\x16^d\nd\xe0o\xc2\xc8 \x82P\x1f\x1a,\xb9\x93\xc5\xe8fk\x8b\xf1y\x18v\x1d+`3h-k\xbe\x07\x02\xac1\xca\x8bO$>'\x7f[\x91\x92\x96o\x0b\xf4\xe9mJ\x96\x8bDP/\xcdPlO\xd3\xdb\x92\xcfW\xee\x91\xa5\xf5\xedk\xc7\xeeV\xb7\xd3]\x9b\x0fYq\x11\xc6\x06\x0dn\x8a\xfc\xb6\xe4\xd4\xcb\xc4Y\xef\x04\xbb;\x8e\x0f\xec\xc7\xeb\xc0\xb9\xaa]\x81\x04kR\x94I^y\xf9\xf0\xe1{\x8fk\xd2\n{\xda\x04\x87w\x99\xe8KpW\xed\xd3\x0b\x1a\xa2-\xfc\xac\xdd\x9dT\xd8\xad\xbc\xd0\x8e\x954H\xb29)\x12\x81\x15^\xed\x1aX\xaa\xc8h-\x02(|\x12z\xa6#\xdc\xe0\xcf\x06\x99IL\x05\xfe\xd1=\x0e\x80\xd4uvw\x9f\xefJG6\xed,\\u\xebC\x92\xd1W(i\x025`\x8d\xd7R1e\x03\x98\xfb\xa8\xa1\xc5\x1a}iE\x0d\x0b,l\xf983bg\x10\"6\xee\x82\x8a\xa3C\x0420\x84Q\x05e\x1fSU\xf6k \xd5\x11\x99\xf0\x8b\x8e\x93\xd9\x15\xfc\xeaz\x7f\xea/\x10\x19z\xb7\x0f\xbb/`\x04\xbb/\x9e\xbdzn\x99\x85FW\xd0\xaa\xf4\xcb\x17A\x0c\xe7\xb0\x0f9\x8c\xc4\\\xa4\xf5\x87\x94Q$)\x8c \xf2\xcd\x95\xd4\xb1~\xdc\xf6w\xafF\xe6az\x18\xa62,\xa7/\x0f\x02\x12\x1f\x15a\x92\xa9\x89\x1c\xe7i)\xcdr\xfclh\xa6\xc5\xa4\xa4E~'\x12\xcd+\x82\xf1\xf99\x7fE\x82\x98Dy,\xa2\xc9\xd8N\xaaF\x1eVxZ\xb5\x86B\xb2q\x16\xe5\xa2\xb7\xa4\x95\xf6\xe5\x0b8+:}%\xe5I*\x13\x87 l\xc5\xb5\xa1rD\xab\xe4)\xef\xb2HJL\xd8\xfb\x0dn\xe5\xf7\xdcZW+\x9cg\xa8\xff\xd2\xab\xb8\x0b\xedC\xb3\xef\xc4\xe4A\xdc\xaeoU\xec\xd8\xad\x84RpY\xf4]\x16u\xe7\xe3\x81\xe0\xb0\xe3\xd1\x8d\xfd@d\x14c\xff\xa8\xe4C\xb4\xb9%\xb2\x81\x8a\xc6 \x15\x7f \xf7\x1eII\xe6+\xbf\xd9\"X\x1b\xf9\x8a\x871\xf5\x0c\xc4\x87\x99\xa6\xd2\x9f\xad-\xe5x\xf71r\x80[\x9fJn\xeeC\xe1\xf9\xca9\xe5^\x08\xa6\xdco\xad\x03\x97\x9br\xb9\xa8\x14\xa9\x12\xc1\xd8\xf3+,V\x19\xe3\x15\xdc\xdc-\x1e\\\x81\x0f\x17\x1cT\xecZ(\xe89\x8aO\x00es\xd0A\\\xf5+\xf8\xe0\xad\x01\xec\xc1\xd8\xd5YD\xfd \xf1\xcc\x90{\x07\x7f\xb7\xb6 C\xde2\xb9\xa2dX\xea-gB}\x8cfZ\xba\xd78\xcd\xfcj4gsv\xed*\xef\xf6\x91\x1b\xbfXi!\x05\x01\xa8@Y'\n\xf8kl\xfa\xba\xdb\x8d\xfciX\xd2\x1f\xbb2T`\xa6\xd4\x88\x8a\xcem$\xaa\x03\xc2\xae\xb9\x03\x92\xdf\xdai`-\x8d<\xcc\xc8-\x84\xfcf\xb11\x016\xba\xe0\xce\xbc\xad\xb9\xe6s\x930\xd8p\xe7\xfc\x12\xec\x8ew\x00\x8d\xbe\xd9\x8f\x06-\xe05\x1c\xa0\xdeY|\x9f2n\xf6V#\xfaX~N\xa6(\xe1\xa2ok\x0e\x0e7\x08\x9e\x94f}\x0c\xbe\x86\xca\xc5\x87\xc4\xcb\xe2\x8b\xed\"A|^\xeb%\xd7u\xd1\xb5\xbd\xac8\x01\x95\xc22e\xaf\xfej/\x8eg\xb4R\x98\xbf\xef\xc9/\x9e\xe7\xc3T\xb9-\x1e\xb4\xa67M\xa4\xc8E\xe9\xc6k\x03\x15\xec\x19\xfaP\xf6F(_\x05>\xc7\xcb\x03\xe5\\\xc4\xa8+r\xa6\x18\xe6\xa4\xf2$\xe4a\x87\xf9\x17\x97\xb7^\x7fSk\xd9\x1d4\x9ake4\xa6Ad\xd0\x17\xf0Q>\"\x06\xa3<\x83\x9e<\x01\xaa\x10C\xb8\x06-\xe2Hb\xe4\x98\xa59\x06,\xfc\xd5\x15\x07\x84\xc68\x16n\x8d\xbb\x07\x8d\xf3\xd6\xdawj\xa4?\x0c\xb6\x0c\xeb\xca\xb1\xb2\x86:\xcc\xb2\xa0j\xf9PD\xcfo#\xd8\xc9g\x9b\xbf\x8a\xf87b&;\xc1\x91\x8b\xcd\xcd5\xf4\x8a\x0e\x83AtZi@l\xe6\x93(\xa9e\x05\xe6\x0c\x95R\xf4\x8a\xa3\xcd\x92\xcf\x1b:\xfd\xcb\xf1\xc6\x82k=\xa1w \xbc'\xc3\x1c\xbb2\xd0'\xce\x86\x0f+\xd8\xdc3\xc9\xd3\xd8\x93\x07a\x9a\xf2\x83\xa0\xe4^\xd8\xe4\xee\xe3;\xa6\xf2\x92\xe6\x83\xe30\xd2\x82\x1f\x00Mx\xd9\xdc\xc4\xac\x1dG\n'I\x18\xb9b\x11\x0b$\xa2\xaf\x89*\xe7\xf1\xecb\x04qN`?l\xe7L\x1b\xd6\xbb(\x08)&\xee\x94\xc8T\x9c|\x10\xcdW\x99\x85\xd1\x92\x0f\xea\x0b\x05DP\xf6\xddy\xb99r\xbf\x88\x87\xc1}\xb5B\xbb\x88\x99\x1a\xdc\x1c\x8c \xad\x16-\xf5\x19\x036\xd5\xc0\xc1\x0b\xae\n\xb9\xa3\x81S\xdau\xf4\xca\x83\xbd\xa6\xb9\xf9\x1e\xb2\xd4ZW\xa9\x87\x0bhn\xa4Z\xb4\xc8H^\x86\x06fM\x07\x9d\xc2\xa7\\\x8f\xb4\xbc:\x85*\xf1\x96\xb6\x07xx\xf0\xc9\xd5\x1b o<6\x0c\xb4=\x92\xa28\x9c6\xebJk\xe1\xe9\x0c\xc2\xca>A~\xb7\x171\xb3s$e\x1e|p\xf8pZ.\x92\xf4gF\xe8\x08\x0d\xad\x84\xc8\xb5\xdbI\xa3\xfe\xa8\xb7{\xd5\xd4\x1b\xdc\xda\xa8\xcfW\x1f\x1c\x8d\xe9\xe6}\x85\xa4\xacE\xbfBYI\xcbX//\xe3nH\x18\x07\x8e\x0f\xce\xd1\xf8\xfd\xce\xce\xce3\x8b\x8f3ho\xf0*\xb9\xd7\xfd\x99\x85E\x10\xb1\xb4\x9e<\x11\xbf\x82yX\x1e\x0b~\x0bl\xa1C\xa5\x9b\xe8z\x99&\xed\xd2Wh(\x07{\x03s\xfb\x16X\xb8\xf3\x0d=\xeb\x08\xe0\xd5/O\x92Z\x90\x1bsU\xdf\x94\xd4\xfc&\xdb\xed\x9c\xe3\x92\x0e\xa6\x9a\xbc\xa4\xc2\x8f\xce\xfaN\xcb\xaf\x88\x85\xe6\xbd\xe2;y\xce5\"\x9c\xb4\xee\xe5}P\x15G\x97\xc9\x92\xf4a\x07.\x01h\x1e4uP\x90\xc30\xcbr\n\xac\"\x1f\xd8\xafB\xdcp\xea\xac\x88\xd6r[$i\xbf\xa3C\xb2\x9e\x1b\xf0\x1b\x18s\xbb\x8d\xfd\x86\xc1#7\x88\x0b\x85\x8d\\\xa5\xab\xd01:W\xa1_V\xae8\xdd\x02\x17\xb4P'4\xb6\x1fi+$\x0d\x94\xe2\xdc\xed\xaa;L\xf0**Y\x06\xd3\"_\xe8\xf1\xe3\x00DH\x05\xcb\x16D\"\x85\xebWpT\x8dT\x18\xe3\x0b\xf6\xf1U\"@FmsEX\xbc\xe1\xd1$\xd3\xcd\xdak;\x86\xac\xaa}\xe1\xf9\x90\x0b\xb9\xfb\xfe\xb0\xb3[R\x03\n\xc8\xf0\xa5\x0f\xa7\x94\x14@\xb2\xd8\x16d\xd3D\xdd(G\xb4\xc5y\x86\xd8\x8b\x19\x9e\xdc\xab\x16\xe7m\xe7\xd2A\xb9\x9e1Y-\xc9'\xb4\\$\x80B\xdc\xd4\xa4\xf2>\xf7\nN\x1az\x80'\xe1\x1dn\x15>\x11\x98\x1bQ\x0fF'+Q_\xc0\xf1\x8c\xd1\xa3\xb9,A\xb1\xa3\xc989\xd4\xbc\x8er\x0dm\x1eg\xeb0Mb\xc8\xf2l\x8bW\xbb-N\x1a\xe4s\x1c\x0f\x95\xc5\xb9/\x8e\xe6\xbc\x87\xcdy/xJ.\xf9\xd0v\x10\x10\xb9\x069\x97\x99\xf2\x00\xd2n\xde$\xc0B\xc3\xde\xaf\xa4A\xb6\xf5AU\xae\xdek|S\xd5}\x078\xd1o\xf4\x8c\xd7Axw#\x17E\x8b[\x82{Jl_\xda\xe1\xc2G>F\xf2H}\xbeVz\x18\xf6\x8a\n\xee\xb2\xa4\xda\xa0\x8c\x88\xcc\x95\x0d\xcf\x15\x03,\xce#\xcc|\x9e\x94F\x18\xf8\xce\xc2\x18\xb9@>\x95\xd8j\xd3\xaa\x1b\xc9\xeaF\x0b\xb8:8\x12m\xde\x0c\x9a\xcb \xed\xfd\xa6\xeck\xa7\xc3GR-\x18\xc4\xed\xc1\x05\x0c}p\xc3=\xb6\x19\xd8Z\xfb\xfc\xdb\xb8\xe0n`\xc3\x1d7\x02\xc3\xcd\xbb\xfaH\xb1\xc2\x08\xf4P\x84\xda\x83\x07\xce\x08\xb2\x1eY\x85\x90<\x8c \xe9\xce\xc8v:\x8fgo\x07M\x1f-\x86S)\xca1O\xc3\xc8\xc8\xe4\x1b\xf3Z\x85<\x9b{\xd0vs\x06\xb5\xa4G\x95\x94\xacj\xfc\xd1\x89\x9e\xcb.\x8c\xb5\xf2A\xa2\x8cvL\xa0& \xc3\xa0j\x10\xf1\xa4\x11\xee\x1c\x1a77\xbb\xea^eCjo\xf0l\xcdV\xda3 \x1b\x16H\x9e\xbflm\xf9\xca\xad(:\x82\xac\xef\xcb\x14\xa9\x07\xbe\x19o\xcf\xda\x02\x13\xbc=\x93$q'\x11X\x12z\xd4\xba1\xef\xa6\x95\xd0\xd6\xd2\xe2\"O\xb8\x99\xa2\xf9\xbb\xfc\x96\x14\x87a\xc9\x8d,6\xdc\x893'\x9f\x19w$\xee\xdd\xd9\xff-\xfc\x11\x96Q\x92\xb0\x1f7I\x16\x16w\xf8+,\xc9\x8b\xe7\x98+*\x9f\x8a\xff[OE\xb1\xdd\x17\xe8k\x17k\x90\xbf\x8b\xf0VQ3r l\x82\xe3xZ?P\xcf\xa8\xb2\n\xd0Ng\xe9`\xb2\xde\xf3\xe8d\xb2G]W\x83+\x83\xf2\x81I3\xd7\xca&5X\xe6[\x93\xda\x89\x91\x83&U\x9c\x83\x91\x91\xe2F\xae\xba\x97\x93\xee\x18W\xe3\x80h\xef\xdd\xe6\xe8\xbc&\x84]\xdf\x87\xcf\xc8\\\x85J\x15\xd7C\x1e\xe3\xc4\x19\xb1\x96,\x96)Y\x90\x8c\x92\xb8\x87\xb5\xa9/\xe7\xb8h\\\xfdF\xb2x`g\xaa\xbb\x8c!{\xdb\x1a\x90 \xa9\x02\xc2\x055\xe2\xeeW\x11\xbd\xdf\x8b\x99\xa8\xcd\xbf\xa1\xe9$\x83{\xa8\xaf\xee\xa8\xa5\xcc\xabP\xf1MQ\xab\xb0\xc8\xcbc\x8e\xe2p\x87\x16R6\xcb\xd8\xad\x06\xd2\x192S\x80\x07q\xad\x1f\xb4S 7\xfdJX]\xd5\xb9\xaf\xd2\xb2\x19\xbf \xcc\xb3\x88TB\xb7\x0e\xd2\x8d\xd6*G;\xbe\xa2\x9a\xd5\x16Q\x83r\xa8\x14-Fe\xe0\x16\xacT\x97\x8c\xdb\xee^\xdbJY-\xd3\xd5v\xa5\x84\xae#\x14\xd1\x81\xf6\xd8\xda\xdb\xbcl\xf4\xc7\xca\xe7Z\x9aw;\xdb\xc7\xd8\x8d\xf7\xdc\xf9\xf5%\xf7Z\xfe\xd6\xb6\xe9*S\xf3ToZ\xae:O/\xbf\xcb%%Y\xecz>\xd0V\x0c\xf8\xdf\xd5=U\x03\n~\xcf\xa0\xd4}\xb6\xf3\xcac\xc7\xe1\xf1bA\xe2$\xa4\x04\x13w\x87\x85\x0ex\x8c(\x83F\x04\xf2\xbbf\xe7\xbf\xb9\x1b\x99\xfb\xe2\xf5\x8e\xe7z\x95\xdbN\xc6-a\x98\xc8\x17\xafw\xbfa\xa8\xeb\xcam\xfc\xcb\x1ds\xf0\x84\x17\xa6\x88?\x99\xfb\xea\xa9!\x86\x97n]-\x0e\xf6f\xc6\x95)jSWx\xa0R*E\x867\x9a\xff\xc5\xb4\xa1.y\xdf\x05\\W^\x1b\"_u\xa5\x0f\xb51\xa2\x12\x9f!\xb4\x98W6\xcb\xe1\x85@\x86\xc1W\xb9A\xb0W\x9b\xbaF\x9a\x93\x05~F\xa0sI\xf4p\x11y\"\xce]\x04\x7f\xd8\x83\x1d\xc6&\xb0\xb4\x914H\x96vN[\x90\xba\xa5\x1by\xde\x1b\xe0a\xee`s\xd3p\x1d\x85z>\xaa\x94\x95rq\xc2T\x1c\x8d\x13z\xe5C\xe1N\xbdz\x8c\x1a\xbf&R\x15w\xc9\xdf\x00\xcd\x0d#\x89\xd6i$\x05\x95Z\x07\x86\x11\xb5&\xd1\x1b1\xd3\x8bHaJ\xc2\xc4nD\n\x8aT\xb8\xf1\xe1+\x97\x12tw\xaa\x06,\x967\xce#\\r\x11\xc0\xe1\x92|\xa6\xa7yL\\\xc7\xe9p\x1cn\xd0\x00QT\xaf\x06\xdc\xaf \x83\xd3\xc1\xe6{\xf2\x80\xe7\x97\xeb\xdc=\x16\xb5\x9d\xdfC\xfc_f\xfd\xfe/\xb11\xe3W\xb3D\x05\xad\xd6\x9a\xe4\x94E\x8e[;Z\"B\xf3\xa3\xca\x8f'8\xd1c\xd0\xc8\x077l\x1e\xc4!\xe5\xe1|\xf6`s3\x81\xff\x80\xa7\\\xdd\x01k\x0b\xcay2\xa5.z\xa1\x10\xe2\x17ix-(\\6\x82 \xad\x96qH\xc9\xbb\xf0\x8e\xcd\xf3\x00*\xd7@\xb2cD\x0f\x83\x80u\x19\xde\xa5y\x18w\x84\xfb\xa9;\xf06I)\xe9>\xe5{:`\x10\xc9\x0e\xeb@9\xcfo\xfb\xc9C\xc6\xa0\xb6|B\xf5\xf8>\xe7\xc1\xb4\x94\x04#UE*\x17\xb0\xba\xfby\x06\xc5\xb6\xe1\xae:\x86ke\x1b\xb3\xd9\xc8\x14\xbf\x8e=l\x16\xb2\x91\xe1.\xc5f]\x88s\x17\xcd\xc3lF\x84UW\xff\x0c\xdes\xfe\xda\xbe\xe3\x1d\xe7\x11\xa70|\xe4)\\\xe41\xb9\xd7\x0c\x9a\xb8/c\xd0\xae\xf6\x06vR\xdc\xb1\xd7|\xf7\\\xf37\xa7\xcd\x9f\xb5\x91\x81Vr\x8a\x1b\xcfi\xb3p:Z\xd1\xca\xb1\xc1:m~\xae\xc2J2;\x83+\xee\xa2\xf2\xbf\x1ea\xe2\xf5mH\xc9\x8fd\x9a\x17d\xfc\x99D+\x14l\xd2 \n3\xf1\x8a~.y\"k\x0cOR%m\x1e\x96?\xe5\xe2\x12\xa6\xfa\xfeKB\xe7'\x84\xf2Y[\x86E\xb8 \x94\x14\xe6\xd4\xe3,JW%\xab\x94P\x9ad\xb3\xb7ya.\xf6\xe3\xddqL2\x9a\xd0;\xfc\x1e\xa6i~{Y\xdc\x1d\xd3\xb3\x15\x95\x85\x16\xec\xa8\xafn\x0ddj\xa1\xbf\x96\xcb<+\x89\xb9P\xa9\x16)\x1b\x05\xf8\x1b\x0dg3\x12\x9f\xc9\xb1\x96\xcd\xa1\x97\xac\xbb\x97\xe1\xac\xca{Dh\x98\xa4\xd5\xab)\xfby\x9e\xd3c\xaet\x87r)\xca\xa3Z\x88\xf6\xe6rzo\xc2\x92\xbc\x0f\xd1\xacO\x00@Rw`\x9ad\xf1Q\x95\xc6+!\xd1\xaaH\xe8\xdd\x91\x96U\xa6\xf3i.\xf2x\x15\x89\xa6\xa2<+W\xb2\xdd\xbc9\xc2eH\xe7\xb2\xfcb\xcd\xfd!I\xe3g\xfcM>SRdaz\x94G<_\x92M\xf9^M\xca\xb3\x83\x8bg\xbc\xec\x92D\xd5\x8f\xff,9\xa8\x9c\x932O\xd7$\xbeX\xdd\xd0\x82\x88\xe6Y\x06\xedC+\xbdQS\xf5r\x91\xaf\x8a\xa8\xce|Ay_WE}\x19\x8b,\xaf!>\x82\xa2\x15\x94\xb9\xafLA\xdaQ\xa5'GyA\xd1\x0c\xf1Wt\x87\xf8+\x9aH\xafn\x13cm\xbf\x97\xd0nVa\xb0\x1c\xfd\x08\x17\xecL\x9d\\1\x96bF\xe8q\xe6N\x9c\x05\xa1\xa1\xe3\x83\x83K\xe6T.\x9e5G\xb5\xd4\xf3a\xe2T\xdb\xact\xae<\x1f\x0f\x8d\x12Eh\xffy\xe1\xb9\x93+\xcfC\xc8\xea\xb1\x87\x94\x97\xa0\xc1I\xb8\x0c\x92\xf2$\\\nE%\xec\x93\xeb`\xb0\x06\xaf\xd6\xf4\x16\xc9I&\x12\xb5\xb9A2\x81\xf7\xe4$\\z*9\xea\xab\x98\xe1g\xae\xe0\xd2\x7f\xf7a\x9a\xae\xf7Bj%)\xbf \xb1O\x94\xe7\xf1\x0e+\x93%\xa7\xea]RR\xcf\xf5\xbc\xa0 l\x1f\xb9\x8d\xaet\xdd\xc1\xc8\x08\xa4\xb1\x081A\x959\xd9\x97o\x88\xb8\xaf?/R\x87[5\xd4\x89]r\x19F\x9c\xbbj}\x9b\xe0\x04\x0el\xca\n\xf8r0\xb0j\xce\xbb\xbe\xfc\xffP\xa3\xa87\xa7\xbe<\xe6AX\x8e\xb3\xff\x1a:\x87\xf1\x84|\xf2\x83\xa4d\xffT\x81$ \xca|A\xbe\x11f+\xe0\xd4\x94\x8d\xfbf\xe4\x92\x07\x1d\xba\xf49>\xa5$\xa3,\xc9\x0c\xabz\xc7\x14\x08}\xd3\x9aH6\xd5\xb1K\xbcj\x9f\xf7\xed\xef\xd6~f\x0b\xda&\xd5\xb8\x8b\x92\xfb\"\x8f\x81\x953Tz\"n\xceZ\x1fQ\xa7\xac\xb5\xb5x\\]r+vW\xbb\xd8\n\x1d\x93`1yb]\x8bM\x811\xd2\xcd_Fp\x89\xd1\xf30j\x15\xcb\xe8,V)M\x96aA\xb7\xa7y\xb1\xd8\x8aC\x1a:u\xb6\xbcX\x1c\xb1\x14\xcc\xcapE\x12\xe1q\xb8\xfdy\xeb\xf6\xf6v\x0b\x8b\xac\x8a\x14\xaf\xd7I\xecT~\xda\x8d\x04\xb96U\x06h\x14\n*\x15\xc0\x189\x1aI\x894\xf2\xe5\x9d\x00Z\x1d\xe3\x87\xf5\xe1\xde \x83&dy/\xb0c\xc7\x8a\x9c}\xc3\xa1\xd2\xc6*\xd1\xaa(HF\xdf\x0bR\x84\xd3e'\xcdS\x19A\xc5\xfd^\xbfrY\x99y\x04~1\xf4\xd2k\xd6\xc1\xce\xff\x893#\x14\xe1{\xc5\xff\xe5%\xfe\xe7\x1e\xba\xd8\xaf|\x89D\x0f\xfb9'a,\xf6B4g?\xd0\xcb\xa6\xa3E\xd2\x88z\xc5\xde\x15Wf;\xd7\x00Z\xf7\x9fS\x1e%M\xa5VX\xd1P\x08\xcb/HJ\"\x9a\x17\x9e\x1b\xf5\x05\x82\xac\xb0\"\xee\x8b\xaaBM\x9d\x9fs\x04\x9cHz\x94\x86V\x85\x1e\x15\x9d7Q\xd3d\x8f\xd2\x0c\xab\x8e\xa3\x0cG\xf7\xfc\xef\xeb\x04\xe1\xa35\xc8k\x14\xcdf9\xdd\"qB\xf3\xc2\xd6\x01A\x9e>J\xf3\x7f-\xf3\xac\xa2>8\x18\xe9\xb3\xacm\x86%\x87$\x8dp~\x94\xce\x14\xa2\xbe\x9e\x0e\xf9Vz\xbe\x97\\R\xdbC\xecSh\xccB\xf7\x11\xc5Qr\x8b\xce\x91\xcd\xca\x80\x89\xc3\xe8\x03~M\xa8\xa6d\xdc\x8f1\xce\x05\x8f\xca\x8a \"~b\x19\x9c\x151)H\xccg%X\x90bF\x18\xc3S\xd3\xa9#\xdd\x16K[\xbbx\x08\xb3\xf4mK\xd9\xdd\xd3\xa5\xdf\x00<\xcf\xd7\x97\xbeZ\x87\xf6\xaa7\xde\xe7*\xff7\xa8c\xd3\x96\xbaC\xb3\xc6\xb5\x88#)\xb9K\xf34\xcc\xfd\xee\x0b\x16\xd1\x98n\x0f\x8a0+8\xd8\xfe\x8a\xbb\x86\xf1Wi\xaf#\xc8\xcai\xde\x9e*m\xae\x16|d\x1aG\xfd\x98\xddP\xab6\xac\\\x83\xb57\xb7\xbb\x1e\xd8\xae\xda\xaa\xa8\xb3u,h\xc3\x9f \x84%\xe5\x0c\xe6\x0e,\x06v`{\xbd\xefNv\xb6^_}\xe7}\x0c\xda\xbf\xb6\x93\x80|&\x11#p\xb8\x0b\xb7]\xd3lH\xe9\x87\xb9+\xf1\xc0\xae\x10I\xeb2\x02\xaag\x12\xee\xdaB\x18s\xe3\xb3\xbe\xc6\xf1\x0e\x9a\x07\x0e \xca\xe4\xef\x04~\x80]\xaf\xb9\xfb\x05\x17\xdbf)%\x03\xd7\x93\xad\xb9\xd6\"\n\x1d\xec\x83K\xda!\xe9H\x87\xca]\xdd\xd5\x8d\xaad\xd5Uk\x18bc\x1bV\x83\x1c\x10F\xae\\\xb3\xb6\xf0d0\x15\x97K\xd9\xf0\x9a\xb7\x8f\\W\x1f\xb6\x9a\xbd\x9a\xf2\x0bB\xe7y\xdc\xab\x9f_-\xb7U\xa6.\x9f\x84U\xc6\x18\xfb-\xc6\xd8\x9bU\x07\x80\xc3\x95\xe5J\xdat/\x8f\x87\xf0\xa8\xb9\xda\xfanh\xbc\xdf\xe8r\xc3oCR\xbc\xe1\x0bB=\x974\xd9\xb8\xbe\xe3\xe5Z\x97f>vGd\xd5}\x1d\xb9\x95\xc8\xab\x12\xb2~[O$\xd5)\xeak \x9e\x0c\xc8\xca,\xf8}\xd4n(U\x1b\x89\xfc\x968\xba\x97\xd0\xab]\xbfY)=d\xd3\xeav}\xa0W\xbe\xd031\x82xS\xb0!\x08g[\x15v\xb5\"\xd4 F\x99D\xeb\xa6\xdcoI\xe2\x1fe\x96\xd5.\xda\x85\xa1P\xcd\xb6r3\xf0(\xed\xcb\xfa\x8cK+\xee#\x1e\xa5!V\x97\x99I\xac.@\x1e\xa5\x1dQ\xdd\x006\xa5\xfbf\xc6\xdc\x99;\x1fn|\xb8\xee\xbe\xceku\xac\x11\xd8\xdd\xaa\xc5Qe\xe7\xd7\x8c\xaeSu\xd0\xe9\x9b\x02\xf9\xa0\xd7\xa3\xae\x0c2\xd3FS\x18\xda\xaf\xb5\x06j\x07o\x13:\x97\xaa6\xe5\x80\x91\x19+\xd1p>'Z\xe4\xd0\xab\xf4\xa1#W\x1f\x03b\x17|\x8ekP\x11\xd5\x9f\xaf5\xe3S\x1f\x04\xcd\xdeU\xe9\x8f\xdc;\x83E\xb2\xfe|m\x85\xb6o\xe7\xb0~\xb6\xfbpnt\xca\x80|\xe4c$%\xb4\xbd\xa5\xa1h\xae\x97#\xeeC\x1fe\x8b\xb3\xbaz\x0f\xc7\xc6\xfbg\xd9\x87\xfa\x8a\xb6\xf7\x94\x92S\x82~\x81*\xc4\\]\x02q\xe5\x01W\xd9G\x83\xee\xcf\xa05\x1a\xe5\xc6\xcc\xa0?\xd1\x89\xc6\x9a\x83\xbc\xd0\xd8\x08\xe5z\xda<\xed\xb7>\x8c\xfd\xc1\x13A\x06\xdf{\x81r\xc6+`N\xab\xf3YEl|5\xaflJ\xb7\xf2d\x0e\"\xf4\xab\xcfH\xf8]\xf4\xcc'\xf7\xa2\x10\x02\xe9\xf0\xd0\x07QZ\xfdD\x06\xce\xb2@=\xc6A1\x8c\xbf\xd32\\G\xe8\xd9\x03\xfb\x08C\xfb \xf6\xed\xff\xd5\xea2\xf4^\xcbZuC\xb9w\x94w\x8c\x1d\xfb\x11TPn\xc8\x9fz6\xee!'\xb1\x0d\x8a\x18\x83\x10F\x95i\x10\x9c\xe2x\x0e\xf3l\x9a\xccJ\xb6<\xf6\x85\xc5\xcb,\x06\xb8\x17yAM>\xd0\xe5\xc3\xfd\x10\xd7{\x92\xe7\xef\x04\xf5\x0b\x94O\xe4\x05\xfd\xf1n\xd8\x9a(e\xcd\xee\x00\xba\x02\xd4\xea\x8f\x9c\x0f\xa3\xdej!t\x1fV\xd8?R\x94\xca\x1cL\nK\x14}P\xe9\xeb}\x90]\xe8\xb0\x11\xff\xea5)\xa6>\x0f\x0c\xf2\x9e\xdd\xd8g\xe9\x83\xbc\xee\xb3\xbe\x1a\x93\xbc'^z\x02{8t\x8aU\xb8\x05^\xd0\xf7\x0eV\xc1\xdb\xdd[\xbb>\x96F\xdc\xd9[\xd6\x01z\xa0\x8a\x0e\xca\x11$\xf7F\x04\x86\x9d\xd9\xdc\x82\xbe\xa6\x07e><\x86\xca\x9ck\x192\xaf\xf0~\x17\x1a\x9f\xf0LST\xb4\x1e\xa93\xbc\xbe>&\xa1\xf1~\x80]ik\x90=J\x8f\xb4j\xef\xd5\xb13\x8e#\x9b\xban\xf7\xe0O\x0e\x95\x1b_\x96U\xb2\xc9&\xa8P\xb4\xeb\xee\xd1\xc2\xa7\xc1-\x98\xb4\xfa\xee\xd1\xd0\xc1\xe0\x86\x0c:\x85U;\x1d\x0dh\xc6)M\xbd\x10\xa3\xfa\xe2\x90\xdeK\x04v\xef\xbbw\xa3JW\xf3|5\xa3\x92\xfcA\x8a \x03\x9b\xb4\xcaW\x8a\x81\x9c\xb0\x14E\xe7\xb89\xb2\x06\x9d,\x15\x9c2y\xc9\xe2\xd8\xc6\x08\xe2\xa4\x1eX\x0b\xa6\xcd\xc3r\xce\xc5\xac\xf8\xf30\x8f\x89q@\xa0\xe3y\xc3\xa5\x9aXq\x93\x11\xca\x03Y\x85JQI\xed\xb6Y\xf7NMi\xb7o^\xb7N,\xf3\x9ec\x99\x1ee^\x1d\xda-\xc2y\xe9)+\xab\x16\xc2@\x13\xa9c\x7f8\x98^'\xb2\xa3\x0c\xab\xe6\x0cf7\xf4{\x1f\xe3.\xbe\xffh\xfe\x19\xdb\xf7\x1b\x01\xa5\xb0\x80\xc7P\x90\xb0\xae\xca\x99\x98\x93\xdc0\x95&\xe5\xf0oD\x83\xbc\xd0\xd5c\xa1\xb8\x07T\x97\xd4\x9ah]\xba\xa1\x0d\x04\xd7y1\xa5N\xa4<\xac\x0c\xb8\x02p/Z\xd7\xc1\x8e}\xd0\xf7\x17\xf2i\xcd\x0e'\xfa>W\xf5\x93k\x1d\xff\x07Hj$\xdanH|\x8d:r\x06\x17<\xdc\xcc\xb1V\x1a\xc5\xf8\xcf\xce\xb6\x08K9\xd9Q\x02\x12\xaa\x11\xa2do\xe0\xd2\xde\x9f\xff\x81*\xa9lRz\x95R\x0d\xb3p\xf2\xaf\xd155\\\xa3\xa0\x99\xb2\xf4\xf1\xd2\xb9\xbd\x1f\x88\xd0\x85\xccU(y^y\x9d\xf7A\xb9T7\xe5#\xaa\xe5\xb5;\xbd\x97@x\xff\x83A\xac\x1a\xaa\xa0x\xa7\xd4\\\x8a\xdf\xb5\x7f\xb11\x1e7\xe5p\x95\x05M\x1f\nl\xcc\x8fP\xaa\x0b\x16!\x8d\xe6\xee\xf6\xffq'\xe1\xd6\xdf\xaf\xd8\x9f\x9d\xad\xd7\x9b\x1f\xb7\x82\xab\xef\xbc\xd1\xb6E\x0b\x97\xbb\xa0HJ\x19\x90\x80\xb1\xed\x1c\x92\xb3V\xd0\xc1\xd6)\xcb/P$\x8a\x14\x92\xef\xd6G\xe7Z\xac\x0f\x1f\x9e\xc33\xe6\x9ar^\xc3\xf6\xc1`h\xd47%\xa2s\x13gN\xe9\x12\xd54)]\x96\x8a\xb7\xac\xe3\xaa$\xf7\x90U\xb7\xdce\xf4\xd4)\x0d\xe9\xdd,zd\x8a\xc7\xa1S\xecF\x19-\x8d\x07\xdb\xe6Rp/z\xdf,M\x96\x03\x02\xcfJqj\xe5\xfa\xd1\xa0\x0b\x93\xa9\xeb\xd8\xc65\x7fm\xf7\xc4\x8c\xd6\xf61\xde#W\xf3> \x97\xda\xb6\xf9\xaf\xb7\x8d#\x8a5\x9c\xf8\xddp8\x98\xcf\xd4\xd7\x92p3\xf3\xa6W\xc2\x92\xd0\xd6+\xe7\xc7\xb9E\x12J\x80\xc7\x8b%\xbdC\xfb\x9f\x8az\xc6\xaf\x12N\xf1\x93\xb4\xa8\x92\x89\x9a\x16\xe0a\x18\xcd\xd5:M\x86S\x82O7\x7f\xc2\xb4\x0bi\x9c\xb5\x0c\x8b\x92\\\xe6\x95U\xd5\xc5\xf8\xf2\xfa\xe2\xf0\xa7\xf1I\xc3\x9c\xfa||q\xf6\xee\xe7\xf1\xd1\xf5\xc5\x87\x1f/\xcf\xc7\xc6oj\xda\xd9\xfb\xf1\xf9\xc1\xe5\xf1\xd9\xe9\xf5\xc9\xf8\xf2\xe0\xfa\xe7\x83w\x1fx\x99\xc3w\xe3\x83s\xf6~\x8c\xf9\xde\x1f\x9c\x1f\x9c\\(_\xce\xc7\xff\xbf\x0f\xe3\x8b\xcbF\xca\xc5\xfb\xb3\xd3\x0b^\xfc\xdd\xd9\x9f\x1aYXoO>\\\x1e\\\x8e\x8fZ\xe9\xedw\xa5\"S\x0fD\xdf\xc7'\xef/\x7f\xe5\xe9\xd7\xc7\xa7\x87\xef>\\\x1c\x9f\x9d\xaa\x19\xf0\x93\x9a\xf0\x9f\x17\xcd\x0c\x1f\xce\xdf\xa9\xaf\x17\xef\xc7\x876\x034\xd8\x83\x1b7s\x9f~\xaf\x93\x9d\xb9\xf8\xf2\xea\xb9\xfe%\x91e\x9e\xe9_B\xf1\xe5\xf9S\xfd\xcbJ\x96\xd9i\x15*\xc5\xa7g\xcf^\xe9\x9f\xd2\xea\xd3k\xfdS$\x9b\xfa\xdek\xd0\x8f\x1c&/\xfaT?%\xb6z\xc7\xe8\x8e\x82,\xd30\"\xee\xf6G\xba=\xf3\xc1\x01\xd0\xf1\x96\xcdkc\xad/\xd6Fsh/q\xdd>\x1f+3g\x8d\xaej\x9e\x1c\xcd\xbd\xf5-\xb6\xf9\xa7\x1d]\x18\xe0\x1c\xe0\x03j\xe9?\xb8\xf5\xdbok\x9d\xa1\x85\xde\xc5\xec\xe9\xc2\xf8\xa1]\xe0\x06\xf6\x88\x13\xcd\xbc\xb8! bO_>w\xf4\xc5\xcc\xa9q\x95?\x8b\x86\x9e8P,\xf7?x\xb4\x9f\x86\x0b2\x02K\xf0\xa8%?\n\xac*\x85I\xf9\x97E\xaa[\xfd\x00\x0crL\x80\xf3\xd6)\x89\xb4\x1b\x9b\xfe\x8b\xa6\x0f\x87o\x9d\x1c1\xb9\xddSS\xdcsjR\x12\x16?\xeb\xa7\xed\x83A\xfb\xf8A\xf3q\"\x14D\xdbj\x1c\x03\x96U\x9av\xa1\x91a\x1f)\xdb\xd3\xfd\xbf>\xa8\xfb}\xbb\xc1\xb2\x9c\x9f\xc8\xdd\x08tS\xbd\x87\xcc\x80\xb4\x1d\xfb\x1f:\x03\x1a\x1f{\xcf\x19`\xf0\xab\x10\x96\xdf2\xf6\xcb\xc7\x1d\xbbT{\xbe\x87\x0f\x10eD\x92r\xfe\x96\x01\x9d\xfc\xb7\x18PI\xe8}\xd9[\xdb\x80\x8e\xee= \xce\x9ew \\6^\x0bx\xca\xf1\x1ad\xc3\xb6\xf16\x89\xd9iEd\xbe4\xd9\xa5e\xaen\xd1\x19W\x05Z\xf4\xe5\\|\xda}\xd9\xfa\xb4\x96Ti\x9b\xcc]\x88O/_\xb4\xc8\xdcY\xf5\xa9Ej\xdfI\xc3R\x13\x93{c=\x14dh\x1e\xd51\x04\xe9v\x0ca%w\x1a\xf3xm`\x1e\xd0\x14Q\xfa\x9fA;\xc8\xe6\x18n\xdb\xfcG\xa3\xc8\xaaH\xb5\x12c\x03\x07\xd3(\xc2\x95\xa8\x1be>\x9b\xd8\xa0F!<\xd2\xb5R\x83\xb8\xabF-\x84\xf1\xc9\xbc\xae\xfa\xfaF\xab\xf5\xd0\xc2\xc7\xf1\x8a$\xf3l\xec\xd0'\x13O\xc8\xcb\x95\x84^\xcb\x8bt\xad\xd4\x81\x81\xb3T\x0b!\n\xd3\xca\x9cup\xa9uYq\xe9m\xa9\xe3\xbd\x81\xf3\xe5e\xd3|f)ca\xa0y1D\xb9\xb6Q\x9e\x18\x99\xf1fAS\x8b\xc7\x9d\xec\xbdZ\xbesi\xfe:@\x8a\xd0\x00\x95J\xccz\xbd 4\x14\x87j\xb3\xceS\x8b\xb4\xa2QOm\xde\xda({\xde#\x051\xd6q]r\x81\x8bV\xd7Q\x05\x0c\x95\x80\xc5a\xcb/e\xaa\x8d\xcc\xef\x86\xaa\xb8\xb9;>\xba\xa8\x16R\xc5J\xdc\xa6\x9bH\xab\\zS\xe8\xd3K\xfeV\x19:\xad9\xb8\xc5\xe7\x01\xe6,\xcdGLQe\x937J\x96\x8c\xdc\x99\x10)\x8a\xce\xea\xf8\x95\x9c027g \x85{R\x83\x1c\xd4\x1a\x16\x10\xc3@\xc0\x97/\x90\xb8\x18\xb0\n\xc1\xb6C\x87\xabD\x0bqF\xda\xb1i-\xda$\x1d{\xbez\"h\x91\\\xaa\xa0\x0c\xa7\xe4]\x1e\xc6\xc6h]j4=\xf3T\xf2\xa5a\xf4t\x9e\x8aX\xfb\xe8\xf1-\x0f2r\xcbx\xf6qq\x9fN\x9b\xa7\x8f=)Y\x93t\x042\xa0\x935\xdf\x82\x94e8c\xc4GP\x90\xb0\xcc;\xcc\xe4\xd2$\xc3|\x8b\xb0\xf8\xc4OQ\xf6+`\xc9\xa8\xdb[\xbfmb\xe4 .:\xb3\xcck{\xf2l[\x05\x03\x1d)\xde6\xf7\xc0Uba\x85\xb0\x0f\xce*\xe3\"et\xf2\xc1\xb6VTo\xad\xd0\xe3&\xe0M\xd1\x88\x1bz\xec\xd0\x1fH#}0\xc4\x95\xfb[\xa5\xbf\xa5Hf; a0\xecM\xab\x86d\xe5\x85\xa8\x7f\x7fBus6`\x8f\x82t\x83\xde\xbbO\xa1\xf2\xff2\xed\x00\x8a\x15\xecA\x18L \x8d\xe6\xf6L%f\x12S\xd5\x01`\x98\xed\xe0\xc2\xc0\xe3\xc8'\xaaD\xb2\xb8\xfa)\xec\xc3?\xbe\xc2\x08R{\x91\xa9\xbcT\x14:\xc2f\xb5\xa0\x0fh, 7\xe6mXd\xdc\x91\x84\x98\xa2\xc6:7\xc2tB\x99d\x11\x81\xf5\xb3`w'\xd8\x810\x8b\xe16IS\xb8!P\x90E\xbe&1$\x19\xac\x9f\x07;\xc1\xce\x1bX\x95\x04,r~\x11\xd0s\xc3\xf1|\x0ep\xb6XW\x0c4\x18i>\xedRv\x8e10\xd9\"\x8fI*/ZN\xc2\xa8\xe8\x88*5\xc7\x12\xd5\xcdVO\xee5\xe6\x16C9\xce()\"\xb2\xa4y\x87R\xf5B\x94\xe0\x04\x8cR\xc42\xcaz\x95\xeb8?y\xe5i\xc1\xad\x9dG\xf0\xfb\xf6\xca%x\x1e\xac\x8a\xd4\xaa\xfe\xc5&\x8fq\x15\x11\x83\x88wIFNW\x8b\x1bR\xbc\xcd\x0b\xb4\xcf\xdb\xb7}h\x86\xdd0\x84\xc2\x90\xcf]\xd5\xcd\x0bZ\xd8\\w\xcb\x1b\xb7\x0eT\x8f[\xca\xe8cH>\xac\x8dN3\xe4\x9b\xb0$Gyd\xe5\x1dA\xb8\x00mB\xc8\x08b{\xf6&x\x8c\xa0c\xd3\xb7ac\x04\xeb\xae\xec-\xc0\x18\xc1\xc2\x98\xfd\xab\x17\xd09\xc9\x06\xe8WA\xe3\x8e\x95M\x98\xbd\x03\xec\xe1\xf6\xad\xfc\x1a\xd6\xae*\x9eL\xc1Mz \x0c\xa8$\x02\x0e\xba\xf3\xcf\xcc$\x06\x082\xa3y\xfb\x9f\xe1\x1do\xa6(\xd6t\x0d\x11T\xe5\xbc\x81\xda\x9a\xeac%K\x08?\xcf\xd9\xa4LWi*\xb6\xc8\xcc\xbd\xf3\x95\x14i\x15\xc0\xd2\x96\xdc\xc8\xb5\x91\xbd~ \xfe\x9a'\x99\xeb\x04\x8eZ\x04)\x15FU\xcb\xd8\x93$\xa0\xdcE\x9b\x9c7\x1f\xb5s\x84\x8b iu\xccr\x9a\xef\x93\x89\x0f\x8e kz\xa3?\xcb\xa7\x11\xcf\xaa#\x10\xa8\xfa\x08\xb9! Dc\xbd\x85\x86X\x01\xda\xa1\x8e= #\x13/qV\xc6E\xf1#j\x99\xe4\xdf`9XhWfvS\xaaVr\xcb\xfc`r\xa5\x1dGo\x85>\xda\xa2&\xc6\xd8kZ\xbf\x96\x15Y\xcdh\xc7\nh\x81X\x03\xdfQ5b\xa8\x0f!\x0f\x80\xe2C\xec\xc3\xdc\x87\xb5\x0f\x0b\x1f*k\xdf[\x1f\xc6V\x85\xa1\xba\xed\xdbb\xd0\x86\xc1p\x0bo\xdexP\xde&\x9c\xca\x0f\x96\x05F\xfc\xe2\xc1\xd0\xbb6Z\x14\x96\x04vF\xddk;\xe5\xe7\xd7\xdf\x82\xf2\xae\xa4d1d\xe3\x12\x19\x8c\xf1y7\xdc\xb0\xe7\xa6 a;\x92\x9a\xfa\xd8\xc1\x05lH\xc2\x89\xc9\x8d\x00\x1e\xe9\x05`\x04q\x9e\xfd\x9e\xc2<\\\x13\x08\x81\x0f\x06h.\x0c`\x08\xe4\x99\x0f\xe1M^\xd0$\x9b\x05\xdcaQxS\xac\x96h\xe2\xc1\xda\xb0\x05\x07\x069\x93\xcf\xfbg2\xd3yQ\xc1\xc6\x92\xa2\xa8)d\xc1\xb1N3\x1fi\xe2\xbc\xa2\xf2\xf8P8\xef\x97#E\xaaS\x9e\xa1\xa4\xfc\xade\xee9\x04\x94\xd6\"R\xe8`\xacK\x0dw\xf3\xb6\x87U\x1eb\xe8\xd4\x14\x91\xf0\x12\x91\xf0\xa2\x1fh\xe1\x1bp\xb0\xe9\xf9\x16\xbclz\x86\xe0j\xd3S)\x14\x8au{\xeaw\x99\x1b\x9a\x1el\xf9\xe9\x83[\x0e9\x91K2\xea\x0b\xb6\xbc \xe5*\xa5'\xe1\xd2\x17\xbc5\x83\xf2_\x12:?\xe4\x0e=%\xcaV\xa0\xed\xa5\x0f\x89\x9b\xe2\xf9z\xbfi\x93O\xc5tL9\x1f6\x8c\x96\xd2\x1f\x13[r\xf7\xb0\xaat\x96\xe5\xe6a\xd5\x98\xd8\x19\x83\xa2\xd2\x90\xc7\xc8\xea\xdc\xde\xbb\xaa>bQ\x7f\x10\xbc^>\x18\xbc\"\x05\xbc\x96\x88x9\x9f\xc4\x8f\xba\x88sWP\x04a\x9a\xe2 R\xba\x1e\xf7f\x86\x8c\xcc\x10n\xc9\xf6\x0c\xe4\xa2lO\x9b\xbbZ\"w\xb5\xd4\xcc\x16\\.\xa1\xb8?\xfbdz*l`b\xa0\xe6\xee\xfa\x7f\x1b\x03ez\x1e\xc2T\x99\x9e{3Z\xa6\xa7\x9f\xf92=\xa8Pm`\xba\x16\xd2\xbd\xf6\xac>WW\x885\xe3\xf6\x87\xb4\xfa\xd0\xa2\x83\x1e:\xbd\x15f\xef\x94\x10u=\x96\xa3`\x04\xf6\x08\xf0\xb6\xe7A\x88h\xf7\xfb\xfba\",\xe4\x90,v\xeeW\x0e\xd4\xcdX\xd2|i\xf1\x91cz\xba\xa9g\xf9|\xc5\xe8\xf1&G\xb6\xc6\xdc6\xc9\xa4\xfa\xb4\xae\xf0z|)\xa8O5Xs\xd0\xcf\xde:\xba\x07\xfd\x95Q\xc3\xab\x8an\x13\xb8d\x00bW \xd6\x9d\x9a\x9c\x0d\xbb\x93\xab\xcac\xcfR\x9a\xd0\x074\xff\xcf\x8b!D\x84\x15\x9c\xa7\x8a\xc8X\xd4\xd6=\xc0\xae\xf5\xe1\x90\xdb\xc3~\x8e\x95\x83\x92{-\xafxz\x1f\xaf\x8dx0\x10I&>\xed\x06\x07\xe4\xf1\xfaz\xf4\xba\xbbG5c\xf1\x1aO\x87\x1d\xec!^V\xba\xbb\xbb\x9e\xafK\xfe\x02j\xbb{\x80\x8aL\xed\xa1Sc\xb3\xa1\x83\xcb\xc6>\xae \xd3\xdef\x9e\xd9\x9b\x19\x8a\x11\x86\xec\xfe6\xd0\xab\xbb\xda\x87\x89\xb1\xd4\x841j\xbb\xaf\xafZ\x1f\xaf\xda\x0e2\xe0\xd9\xf7\x0d\x9d{\xab\xb5\xc77^\xec\xffM\xc6\xc1\xf4+\xa8\x03\x0cC\xfaV\xf7LX\xbd}m\xdb\x02\xdc\xd3\x11x\x8fJ\xdcy{\xff~\x8b\x8e\x9fT\xd8l\xaf\x99m\x80\xfe\x10\xdb\x1c+o\xfdO\x1a\xdd\xc4\xe2\xc0F\x0cO\xc5\x83\xf7\x1bi\xcb0\xe9[\xd6\xee\xf0A\xa3\xab\xb4\xa5\xcdC\xe4.\xc1\xef\xbd\x84]\xf6X\xdf\xae'\x7f\xf1\xcf\x18\xe9#\x98\x13\xf0\xb058\xea\x9f\x85\xe9\xc2\xf0iS\xb7v\xd3\xbc\xed\xc1j\xae\x03&\xa5_=\xd7\xfc\xb9`'\xb6\xc9\xcd\x81e\xc9>uAK\xc3\xb8\xef\xbf\xe7h\xffv\xaf\xd1\x1e\xf4\x8c\xb6e\xe0\xf8\xbfa\xd0g]\x83n\x18y\xf6\x1e\x9c\x1d\xe34\x8c\x857\xff\xbe\xab\xf9\x96\xd9io\x17\x86*\xe5\xd9Tn\x8aa*{\xf9P\x95\xbd\x95&\xeb6\xe7\x12\xf1\x06\xc3\xf2YOu)\x12\x96\x0c<\x18\xca3\xe7\xe1r$qW`\xcc1\xc5\x1c\x95\x8e\xa8\x05m\xc2\x1e\xacl\x9c\xc1\xfd\xb4S\xac\x9a)\xe6\xec3\xbc0\xe0\xacD\x9b|M\xa6\xe0\xce\xe0\xc9\x13\x98)\xa1\xc7\xf4w)y\xd2\x93\x85{\xd2~\xf1\x93\xa4iY\x0d\x1bBK\x86{\xc7\xaa\xcf\x89\xf6\x1e3\x98\xa5w\xc6\x0b\xcf;\x1d\x07\xb9\x93\xd4\x87\xe8\x8am\x84\x8c\xad6\xd2X^\x17\x9bJ\xd4)\xd9k\xbe~\xf9b\x8d\x1f\x00\xca\xd6P\xcbLx\xc3\x1d\x1e\x0c\xdd\x0dt\x0e\x8e\xa1\xfcv\x84\x8b\xa52\xf9;w\xda\xe1\x9a\xea\x82=p\x0c\xbe\x97\xc0\xcc#\xa0H\x07\x83\xc8}\xa6\x1f\xaa\xc8Lq-\xfa\x91\xcaH\x01\xcd/\xd0\x12\x96\xb1\xcf\x02<*\x00?\x8eQ\xc8\xa7\xbe\xefi\xdfG\xbcP\xca\xfeD\xa2\xf3\xcd\xfcY\x90/\x8fcw\xc6\xefc<\xd4)\xe5d\x96k]\x136\xa97\xb0\x07)l\x823r`\x13\"\xf3\\2v\xb6\xe0\xb1>\xca\xa0D\x1c@\xe2\x0bLro\x90ko%w\xe8_]\x8bjX\xbe\x9f\xc3\" oR\xd2\xa5\n\x05\x18,\x9d\xe5\x1eU=\xe9\x96\x08\xb0\xa5,\x97aDFpc\xcd\xf8\xb5_\xbap\xfb\x08=\xedo\xbf{\xce\xabv+\xf7>\x15t]{\x12\x91\xec\xc35\x8c\xe0\xd6G5^=R\x1d\x0e\xa2\x9d\xec\"\xa0\xf0\"\xad\xa8u\xa2L+\x9d\x17B\x87!\xdfm\x7f\xe7\xd8\x17y\xac\xb6\xfac\x1es\x9c\xc4\x8b\x9bK\xb1\xc1\xdd\x05I\xf9\x9f\x17g\xa7\\0\xed\xb9cT\x8cW\xab\x81=`\x19\xb86\xbc;\xf6F0f\xfba\x8csi\xc8<\x16\x93\x0c\xa3\xf6\xa7\xf6\x86n\xa5\xb0\xa1|\x163\xaf\xb8\x01\xf9\x07z\xe6m\x8f\xe33\xee\xc4\x9bU\x92J2\xcc\xfd\xec\xf9P(\xc4\xa8\xab\x1c\x90\xf5A\x08\x9f\x0d\xb5\x11\xc3\x11\xa6R\x19\xbd\xfeq\xd7\x0d!\xe0\x84\xea*:\xea\x93\x9bG\x99u\xab0\x16m\xc2\xd32\xc0\xbc\xe1\x9bD>_U\xf8k\x0e\xd3p\x97\xcc\xc6u\x01{p\x14R\x12d\xf9mG\xa8\x9bLRg.\xd1\xd5\x05\xad\xd3F\x83x\xc5Qj\xa3\x0d\xd8\x82\x8bj\x0dyO-c4\xa8O}\xf5\x84\xa0\xad\xbfyuJ{\x1a\xea8c\xb9\xf6F\xd7}\x0b)\n.^\x98\xab~m\xccg\x9ei@\x8d$\x0b\xafI\xdan{\xf4aK\xf5\x04\x83\xa3\xaf\x1d\xab\xa3\xaf\x9d\xa6\xa3\xaf\x9d+T\xe37P\xef\x15%\xda\xfe\x96uR\xa0\x89\xd8\x07\xb9b\x9e\xc3}\xfeP\x0c1\xc9\xcb9Wf\x1fi\xdd\xa4\x9bT\xd2$\xc14\xebR\x9a\x0f+}\xd5\x01\xf4;\xe9\xe7\x07\xca\xea\xf6\xdf\x16\xa5\xce\xed>\x0c\xb9\xfa\x80\xe6\x1d\x8b_K\xd8\xa9\xfc\xb0\x1d_W8x\xednl\x8a\xf7\xc9\xed\x03\xcb\xce\x08D\xa6\xa3\xca\x9c\x9d\xd1J\xdb\x9f\x17\xe9v\x12P\x86\xac\xa6\x96N\xccq\x00\x15\x81\xd8\xe8\xbe\x0f\xb1\xfd\xec\x16\x80\xb0\xd2\xb8C\xd4},\x9a\xb85\xb1md\xa1\xfcm\xd1\xbf\xe7\x8a\xdf\x96\xa5\x96\xd8\xa2\xdfb\xd8V^\x92\xc4V\xednS,\xdc\xa9\xa5\xab\xc2\xb4\xd9b\x9fa\x0c\x97\xbb4\xa0\x1c+\xce\xc1_=\xce\xa8H@>/\xf3\x02\xfd>7\xe7\xbb\xb2\xf1\xcd\xdc\x97\xcf\x9ej\x90P\xdb\x087\xbdO\x19\x9b\xb4\xb57@,\x89\x91]\\n\x00\x12f\x11\xbaUD\nKA\x80\xe8\x11\xb4\x80$\x03\xe2\x01\xde\xea\x03\x9b,T\xb4p\xd1\x1f\xeb\x08\x92,\xca\x8b\x82D\x14\x92l\x9ds\x07x\x1b\x16W\x8e\xe4~3hv\xe7U\xd9(\xb9\xaf\x9f+\xcdT\xc3\x0f\xa6CD\"\x19\xb9\x1d\x805Y\x8f\xda{\x8d\xd15\xc1\xb2\xc8\x17 \x8a4YUdX\x9096\xe9\xca\xfcRm\xbe\xb3\xf6,;?\x861\xbc\x17mEyV\xd2b\xc50\xb3M\x97\x11O \x1f\x0f\x1b\x83\xbc\xd6\xf3y\xe7\xc5\x05*\xcb\x84\xbe\xe5D\"\xa3~1M\x0b.\xf3U\xb5;\x1c\xb4t\xf5\"}\xbfcZ\xa4\x01bB\xd4\xb0\xe3GW\x921\xd8D~\x9aLrv\x16\xe3\xbf=\xa0\xec\xdf\x08\nVG\xee\xe3\xeb\xbf\x04\xf2^>\xdf\xb5\x8c\xaax\x8c\xea_\xbd\xb0\xd4\xce@M\xd7g\"\x9f\x97i\x12%t\x04\x13\xd6\xb1\xe7\x8c\xe0u_>\xff^\xfc\x7f\xe1\xa9\xdeP\x1f\xde\xbb\x0eJR\x99\x97\x17\xbb\x167\x93\xec\x9b\x8e\xea@\xd0=\x9a\xc7\xca`s\xeb\xea\xbb\x91\xb7\xef~\xdc\xfe\xb8\xed\xed\xbb\x93\x8f\x17\x1fK\x0c\xc9\xd9.\x1eb\xf1\xc9\xc1\xd6\xff\x1f+\xe0\xffw\xb6^on\x05W\xdf\x8dX\x05\xdb\xedB\x8c|\xb1\\\xad:\xff\x86\x9e#\xc3r\xae\x87\xf3\xae\xb3\xec\xb3,\x7f[\x91\xe2\xce\x9eg[\xfatDG\xca\xd6l\x7fd\xd9\xc2\x15\x92x\xbb\xb6\\\xa7\xe1)\xeb\x13\x8fH.\xaf\x86w;\nl\x8f\xdc\x8f\xf1\xa6\xf7\xef\xdb\x18\xc8\xbch\x14\xebo\x04{\xac5\xd4*c\xa8\xa6}\xce\xc9\x87M\xe7\x08v\xcd-\xe3D\x8e`\xb7\xf5Q\xf5# \xaa\x9b\x8d\xd4\x8e\xaf3\xaepo\xb3\x94C\x015\xfa\x83s+\xc3m\x1a\xa4\xe2\xd4\xe2\xc2@\x8bp\xd5\xb9I\xf3\x9b\x91#d\x9e\xcb\"\xa7y\x94\xa7\x1e\x87{v\x96\xb8\xab\x8c\x94Q\xb8\x94\xbc\x13\x9bF\xcf7WH\xd2\x92\xe8\x8e\xea\xf6t\xf7\xd8\xf2A<\x981\x1cX\xb7E\xb0b\x1fJO\xeaz\x14\x93\xcc \x91\xac\x1bR-\x99\xad\xda\xd6uS\x84\xa1\xdb$\x03\x94\x90\xba\xacr6_\x93LG\xaf\xf2Ql\x14\x8a\xa0L\xc3rNP\xfc\xec\xd6o\x8c\xb0\xa5\x9cQ\x9f\x17dj\x8a\xfa\xd3J\x91\xbc\xe9\xef\x9a\xd9\xccp\x11u{;\xad\x02\xfaZ\x89g\xf3\xa4\xc8\xb5\x1e\x01\xe5\x0e\x9f\xd9\xbf\x80\xe6\xef\xf2[R\x1c\x86%A)\x8fc\xb1v\x17\xa3\x1f\xc1\xc6\x06\x9d<\xb5\xec\xbe\x82\x94\x94U\xff\xac\xbd\xd1\xf4+V\xf3\xd0\xa7\xb6C\x14*J\x8f\x1d\xf1*\xb17\xad\xbdPW0E\xcd\x82\x176\x83\xdc\xec\xa9\x94\x1a\xf7sn\xc1\xb0\x12\xc1\x91-\xdc\xcc\x02j\x97\xdd\xe6\x1c3\x96c\x9eX\xb8\x8a;\xd8\x83\x9dv\x7f\x10L+\x88f\x84\xd3\x02\xad\xf5\xe5f\xaaR\xb8=\x8e\x8f\xcb\xcf\x1d@s\"B \xfe\xb3Q\xf50\xabJ\xe4\\\xcc\xe7\xf1\x82)RH\xec\x9c\xdap\xd9q\x13\xb9\x84{.\xf6\xbc\n\x0f\xe0\x85H(A\xdd\x87Y\x03\xea\xe5\xef/_ \xe1\x1eu\x95\x8cU\x15\xc8\xf8\xc9\x17DL\xea\x9b\xe3\xf8\\l\xc1h7\xea7ku\xd7\x93\xa7l\x83N\xb6\xdd\xe0;o\xbbq\xf4xo\xe0\x0e~\x80\xb5\x10s\xbc\x81\xbb\xcdM\x0f\x91\xb5\xcbx\xd8\xf5\xe4\xee\xca\x9b\xec\\\xf9\xdc\x12{\xb2{\xe5C\xc9f\xa5\x84}\x98M\xe6\xb8\xef\x19|\xb7]j\xb2\x1c\xff\x8f\x1b\xa3,@\xfaX.=~\xc9\xe1dh\xfe\xa2f_\xb2>\xee\x83++\x15\xa0\xb3#tT\x95\xa4\x1861\xb7\x87A\x87\xb5\xfczf,\xcfs\xc6(\xfc\x15\xbb\x9c\xf7C\x14\x8eq\\z1\xdek\xcf\xf3\xe5@\xf1\x9f\\\xa5\xe5\xe4\xd9\x15\xae\x96Hd+\xb0\x9c<\xbfR\xebe\xff\x9a\xa8\xc0\xb0}8`\xcd\x02<\xe9\x90\x14\x12\xbf=\x84+\x15 @\xf1c?\xab\x8e\x91 \x9a\x87\xc5\x01uw\xc4\xdc\xea\xdfy\xef8GQ\x9f=\xa2\xd5*\xd3\x00?\x11\xa0\x92\xdd\x18\xe9\x0c9\x14g\xdb\xf1\x82r\x99&\xd4\xe5?\xe5\x0cn\xedz\xd2a5Q2x\xbep\"\xc1A\x8e\x1b\xbce\x93\x02\xb6\x18\xfd\xc1\xb7\xd2.7s\xdby\x03\xc5\xd6\xd6\x1b\x0f#{\xe0M\xd9\xa4\xb8B\xcf\x19\xac\xba\x08#\x13\xec\"~\x0d\x9a\x19\xdcf\x0e\x1fB\x06\xd6#\xee\xb7\xc3\xdd\xa9\x03Z\xb8 \xf7j\xe0C\xab\xc4\xd6V\xb7\x94\x19\xd7&\x0bVY9O\xa6\xd4u\x1c\xcf\xc7~\xb2\x89\xceq\xa9\x82\xea\xed\xcb\x17\xc8\xb8\x0e\x1cf\xcb\x84\xce\xfc\xb6)\xa2\x8a\xb2*\xbe\xbabl\xde\xd8\xb7\xbc\xa0*f\xe0\xfa\xa93\x19a\x97\xff\xe0\x85yf~{\xc8\xdeV%)\xc4b\xb36\xca\xf26/b\xfc\xcc\xbe2B\x13\xa7d\x89\xdf\xd9\xab\\\xb5Q\xab\xfcr\xb2S\x81}\xa3.\x86#\x04\x02d_\xf2\"\x99%\x19oP\xc1\x86\xa2\xbb\x88l\x93\x94\x8c*\x98\x95y\xf6\xd5\x97Mp\xb6\xb7\x1d\xd8\x94\xc5F\xe00|\x8dM3b\x01\xab\xaf/3\xb53Q}\x9b\xf2J\x85)B\x1b\xc4KBG\xbd\xac\xa7|\xf0\xe0\x13'\x94\x19R*\xeb\xaf\xae\x0bh\xae2\xca9\x86n\xa5\xd1\xdeX\x17\xd2\xdd\x84\x8b\xd4\xaa<\xa8x\xa0\x85d\x82\x17\xc9=\xe6_C4{9\xd7\xd0c\xee*Zc0K}H\x14p\xdd\x17~1\x12 \xb2I\x05\xb2\xd5\x95/\x0f(o\xc8Q\x8d\xc3\xe92\xd7\x84\xa1#\xa98\x9a\xa1\xa3I\xf8\x96\xe2\x13\xbd\xb9'\xba\xcbS\xd9$\xcb\x1e?\xc64#O7\xb4c\xdb\xa3\x8f\xf1\xe6\xbfos\x1a\x9a\xb2Yv\x85\xffxe\x0b'\x12!\xd0`\x99/\xdd\xaa\xc3bSS\x81\x96F\x8e\xa7\xcc\xbf\xfc\xa8\x14\x7f\x9c\xc9\x97 \xd17F\x95\x08\xa2\xcd\xf3\x94\xf5\xa9\xa6\xa56z\xa2N\x0f\xeb\x95\xa4\x8d\xfa\x94\xbcQ\x0c\xd0o\xf4=\xc8\xd6\x13\x0dW\xd9\xc4V\xad\x0b'3\xfbx\xe0\x8f\xc0\xf97\xcb\xb5\xb6\xfaHhP(\x82\x0da\x16\x1e\xb2M\x05&\xe5V\xf5\xf9*X\xc2\xc7@\x15R\x8c=\x08~\x8d\x99\xccF\x1f\x15\x05Rr\x02\xa1\x84\x1f`U\x91\xaf%;\xe7\xed\xf3\xcd\xca10ZM\xca\x0e\x0d\x9dT\xd2q\xc9$\x9d\xec^\xb1\x1e\x8a_\x1a5w\x8fnK\xa2\xa1>\x11\x93\xc6\x89\x98\x18O\xc4D=\x11\x13\xc3\x89\x98\xe8'b\"O\xc4\xa4\xa1\xde\xd3\x0e\xeei\xba\x9f\x14\x05F=\xb2o@\xd7vMNI\xf1\xa5\x8f\x04\x89\xf0\x8c\x84\xf5%\xd3\xbb\x0e\xcd\x1b\xca\xe5\xd1v>\x0f@\xc6\xc9\x95\xe3\xb7\xd0e\xd8%1s\x85\xdc\x04\x85<\x1c\xb7\x18\xa9\x88B\x07\x81\xb8;\xfa\xc4\xe3\xb4n\"\x1d)\xd0\xcb>\x9f\xf2\x91\x1d\xf9U\x97\xfc\x15\x9d\xc4 \xcc\xcd=%\x8d\x11\x7f\x15\xb9T}\xe7\xc7H\xfd\x05I\x7f\x96\xfeGG\xfe\xcc\xf8J\xf3\\\x92\x10\xcf\x87\x8d4X\xa6\xabY\x92\x95\x93\xec\xaa\x0biR\xb9\x86\xe35\xc9h)\xeby)\xeaQ\xab\xe9>5\xe4)G\x03\xb2\x167\xab\x1d\x1e\xad\x14D\x9fd\x10z\xb0r\xc3Iy\x85\xeb\\z\xb2\x17\xaf\x1c\x94;\x19<_\x82\x11\x17\xab\xd7\xb4\xed\x95\\\xd9h\xfe\x94w\xf94\\\x90\xa3\xa4\\\x864\x9a\x0b\xedd\xb6\x19\xcen\xb3\xcaP\x99{\xc9b]{\xed\xa0*BGY!8m\xceA\xad\x8f\xb1\x9c\x87%\x89\xcf\xc9,))\xd7q`uhS\xc6A\xcd\xb0|\xd5\xfc%l\xfe\xacR]\xaeS\xab\x0d\"\xf1<(\xdd|\x92\\\x89\xe9\xe8\xd9\xe9P\xa3?=\xae\xed\xefLy6HPh\xc3B\xfcR\xba\xed\x0f\xa2\x07>c\xd3;\x17\xaf\xb4/\x9e^'\xbfB/\x19\xf5\xc1\x17kwg\xa7\x02\xe7\x8e\xccH\x06\xb7s\x1c\x91%\xc9b\x92EI\x95M\x01\xf1Iv\x15\xc4J\x0ee\x10\xf2\x97\xa4K\x9a\xfd\x16\xfb\xaam\x95e\x83\xa7\xb6\xda\x91e,\xfd\x19\xd5!\xb5s/\xf3\xb2LnR\xd2\x82M\xe1\x01\xa0 \xa1\x19;\x9e\x10y\xbc\xc7\x11a\x8c\xc9>\"#\xafVf\x97\x9d\x81u0\xba\x8a\x83\xe7\x92&~0\xb0\x95\x0bu\xd6\xbf\xa7\x1b\xe5\x8fw\\)e\xc0M?\n\xa5,\xb2f.\x0e\xc3k\x11\xeb\x0e#m4\xd1G\xa7\xe6\xe2N\xc5\x8e!\x133\xeeI\x10\xadH\xb9\x93\x8b\xafr.\x9f\n\x9c\xc4\xf3\xe0\xad8\x17\x80\x0dD\x9fH\xa1\xf6L\xf4\x8c\x88 \xe6\xc0\xf66/p\xd2\x87\xce3 \xe2\x06T\xb7\xc7\x8flUk\x13V\x17\x16\xf6\x1d\xdc.\x84\xb2*\xb3[g]\x1b\xc3\x86\x8e\xbbNqn83\x08\x8f\xcb\xa7\x02)\xd4\xac1`^\xf9\xe0\xc9\xaeC@\xd1 V\xa0\x80\x96}\x96\xb2Iq\xd5\x01uP\x1f:b\xc2\xdbQ\x85\xe4\xd3u\xfe\xcaG\x92\xcd\xab4\xed\x82\xaa\xeb\x82\x94\xa4\xb1}Gv5Nh\x11[\xb9\xb8\xe4A\x8fg\xad\x8d\xc3\xe5\xe1\xe2\xb2\x94\x91]\xed\xe1Wd\x8e\xe4'\x8c\x97O\x12\x88\xedg~\x1f\x12\xa1\x1e\x0f\x9e\xdb\xde\xd7\xa2{\xd4\x88\x13$Yk]\xd6\x8evC\xbc>\xf6\xa0\xd0\xdb\x0d\xd5v\x8bI\xd8\xbc\x804j\xd9\xaa\xf4;_\xcf\x87S\xe9\xdc\xa3\xa2\x99VG/\xd0\xee\xd3\xdd\xa7\n\xdd+Hw\xf7\xb51\xfe\xc6\xaaC\xdd\xad\xa6\xb9P4\xfc\xe5\x0b8\xab\xecS\x96\xdff[\xb8\x8e\x9a\xf0\x85\x04\x11w\xe9p\x19\x163B\xf1biF\xe8i\x1e\x93\xb7E\xbe8\x16\xf7\xa8n\x81\x97\x84\xfb\x10\x06I\xb6\xce?\x91?\xad\xc2\"&\xf1a\x98\xa67a\xf4 }Cp\x7f\x99\xd8-\x82W\x14\xe6\xbcU\x16\xdf\xd0zc\xef4\xa9\x8a\xb6\xdeER\x8e\xb38)\xe7}\xf8X\xecK\x87\xe6\xcb\x93|U\x92\x0fK)\x94b\xd3C\xf3\xe5e\xbe\x8a\xe6\xe3,6%\x1f\xb2\xf1\xa7\xe2K\xd7\xb6N\xca\x93|M\x1e\xd0\x1dV\xcc\xd4\xb2\x92\xde\xdd\xee\x05\x0d\x0b\xfa\x80\x86\x8f\xf2\xdb\xcc\xd40\xd67\xa0e\xa1\x82{\x94\x14$\xa2\x129\xf4u\xa2>\x1c\xaf\xe5\xe9\xf8.))\xc9\x88M\x0b;k\xe6\x960i\xc0\x03M?T\x94\xd3\x10\x8cXx\xe6\x18\xa1\x8dA\xb4\x19\xde3\xcf\x18\x18\x18\x14\xfc\xc4\nS\x97\xd83J\x95<#\x90\xfb\xc6 0}\xac\xc6[},\x06-\n/M\xca\xe36\x95j\xb9\x16]WV\x80C\x97\xa6\x18\xbc4\xec\x9c\xd5\x9d0w\xe8\x01I4\xb6\xf3\x06r\xf8\xa1v\xd5\xfc\xe4 l\x90 )\x19b\x0fg\\[\x9e\xe6\xcb%\x89]\xef\x0d\xe4\x9b\x9b^\x8d\x1d'\xf9\x95\x0fE[U\x12\xa4\xc2\x10^X7\x90\xa9!\xe3\x03W\xe9!K\xc4Fr@/\x8b\xd5`J\xbe_\xbay\xff\xed\x06\xf7\xdar`\\[\xdaI\xbc)\x84!\xbf\x19\x87\x1f\x1a7\x7f\x1d+\\lnv;\x18B\x8azR\\\xb1Ue\xe4\x9f\xa2\xfd3)\xdajG\xa0\xdc\x15\xa0\x87\xe0'O\xd8\xa6\xe6\xc1\xb3e\xc1n!\xa9\xbe\xd8Xe\x97\xfaU\xe7\xde\xee\x847\xda\x05U\xf3\xb0\xac!\xaa\x0f\x80\x14\xf1E\xbb\xbd\xaeV0\x9e7\xef4C\x98\x0cq\x0el\xab\x08\x0ce\xf5@/\xed\xd6t\xd4|\x9f\xd6Zh\xbd\xbb\xb5\xa4<`k\x81\x0e#{\x91\xa5\xe4\x18\x82\xba\x14\xcf\xdb3\x9ew\xf9-Zw,\x16y\xf6\x90\xe6,U\x0cj\xfb}\xc8\xce\xa1{\xce$6\xd9,\xd93\x8f\xb4\x08\xd7\xa4(\xc9\xe5m\xfe\x9e1\x8c\xc3\x14\x11\xaa\xe6\xf4\xe2U\xa1!m\x8e3J\x8aw$\\\x1bZE\xd7\xe6FYu\xab\xed\xba\x1a\xadp'\xfc\xa0\\&\xc93\x93g\x0f\xfe\xf10_,\xf3\x8c\x11\x03\x05\xe9]\x00\x90'l\x1b\xbf\xb4Q7\xaf\x9fU{\xc9\xc7\x10\xa6C\xea\xcf\xcd\xf5\xff\xce\xfcfa\x8f8\xc6x8{\x042 U\x95\\\xf1:\xb9\x0dd\xcc\xb1\xaah\xcb\xa4\xa33j\x14kUQ\xa1\xc2\xc9\xee6\x86\x02\xe5^M\xe3FL\xccN\xcb\xca\xac\x9b}je/\x08\x1a\xca\x1c\x86\xab\xd9\x9c\n\xd7\xe1\x9d\xb2\x02v\x8aY\xcdr\xd6\xc2&\xd4\x12\x14\x86\xdb\xe4\x14\xf5Y\xf4\xadp\x91<\x1c.\xcc\x164&n\x97S7\x94\x13\xd7_\xbe\x00 \xca\"\x1a\xa7dA2|\xbfM\xb28\xbf}\xa3O+\xdb\xef4@\x9b\xaer\x99gq\x92\xcd>\x94D\x96\x93\xfaG\xd6\x1c\x9e\x0f\xcfxh\x9c \xcbc\x82F\xfd\xfb<\x8c\x1c\xc9\xf0\xe0i\xe8(|\xab5\x8e\xd0-t\x9f\xaa\x163y\x10\x85\xd9\x87\x92\x1c\x9d\x9dT\xe0\x1b\xe7\x11\x1a\xef\x06\xc9b\xc9{\xca/'\x9f<\xb1}\n\xe6a\xf9\x96\x84tUH\x7f'\x1b{\xd6z\x94\xcc\xae\xe3\xf8\xa8\x1d\xdc\x98\xd9\xed\xef\xbekB\xcdwp8'\xd1\xa7\x92Af\x98q\x81?$%\x94\xab%[_\x1e\xc0\x89\xce \x08.IP\xc7\xe82=['E\x9ea7\xb4J\xf56N\xcf.\xc7#\xb8\x9c'%\x8f\x0f\x95\xe5\x14n\xf3\xe2\x13\x08\xa3\xbd\xf4\x0e\xa9\xce,\xcf\xb6f\x8c\xc6I\"\xde\x13\xd6\x8fh\x0ea \xbf\xf1H\xca\xbf\xf9z\xd5\xbf\xa1\xb8\xee7\x1f~K\xf30f\xff\xd1\x08\xfc7\x1f\xa3Q\xfd\xc6\x1ds\xfc\xd6\xd7\xc1\x1f\xf3\xa2\xc8oK\x98\x16\xf9\x02N\xf2\x98\x14Y\xf2\xf7\xa2\xaf\xd4\x1f\xd1^\x14\xfe\xc1\xb5\x0f\xbe\xd6\xd7%\x17\xab\xe94\xf9\x0c(D\x84L\x98\xaf\xcf\x02p\xa24\x89>9z\xbdUE\xfb7y\x9e\x920chq\x89K\x8e\xab\xc3\x16\x07\xd7@$\xa2\x9c\xb7\xb1J\xed\x1a\xa51AU#c\\dE\xedenW\x90\xb036\x0b\xd3\xd6\x874\x89HV\x92z\x9a\xe0Y\xb0\x13\xec,\x0b\x02\xee\xe1\xaa\xa4\xf9\x02~\\%i\xec\xc1\x1789\xbe\xd4\xcao7\xde}\xbb-\x9e\x8eL\xd0~@\xddS_\xbe\xf0[\x82\x0d\xd7 \xe3\x18\xe7Z\xd2\xc8\x0e\x83Z\xb9GjVA\xbfY\x91\x1c\xb5\x93g\x0el\x9a\xfc`\xa1PP\xad\xecM\xbbOF\x92e-\xae\xa0\xab\x8d\x1a\x15$\xa4\x12=\xb9N\x9c\xacM\xea\x1daP\x12z@i\x91\xdc\xac(q3\x1f\x84\xb3\xe47\x8e\xd0\xfe7\xaa\xc2\x84\x93\xcc&2\x05\x85\x9d@Mb\xae\xbdr;'\x95\xd8\x0c\xa4~\xf2\x10\xac\xc2\xef\xe6\x03^\xde\x07\xe7Y\xb0\x83\xaa\xd6\xc9\xa3!\xd3\xd6\xd1}\x90\xd2\x118aJ\xffL\xee\xf4\x90\xbayF\x8b<\x1d\x81\x13\xd1\"m\x7f?!4\x1c\xa1\xdb\x82\xb0\xfd\xf1b\x9eLY\xcd\xa8W\xcd>\xd7C\xb0\xd0:\xb6\x03\x0e\x0dW\xb3\x90&k\x82\xf3\xd3\x86\x12\xf43v\x92\xc7\xc94!\xc5\x05\x0di}\x8d\xd4\xfe\xd4bO%\xa0\x16\xad\x1b\x83\x8aS\xc43dc\x83\xaa\x90PC\xc1\xb0\xf3\xbau\xcd\xf2\x08K\x99\xb9\xaf^\x1b\xd4_2\xf7e+=\xe1j1\xbb\xdcv\xf4\xd9k\xfc\xf7t\xf7\x95\x1e\xfd\x9a\x8b\xe4w\x9f\xeb\xe5W\x98\xfe\xec{\xb3X\xbe4b\x151d\x93h\x92S\x18\x93\xdd+!\\\xa7\xe8\xb5\xf8\"\xb9I\x93l\x86\x1eu\xa6IQ\xd2\xc3y\x92\xc6\x86)_\x8b\xab\xf6\xc4\xedc\xafH\x90d%)\xe8\x8fd\x9a\x17\xc2\xb1D]\xa1q0\x91\xad\xaeB\xd4\xc58\x0dQ_\x8b?3\xe94XM\xb7Z3\xb3ob\xdcl(07+\xeaTaK\xec\x840\x8fI\xa4\xcc\xb8]\xb8\x95\xba\xdc\xee\xba\xe0\xd7\xf7\xdc\x82\xbdCk4\xafh_\xf5\xd1\x88g\x1c\x1cZ$Q\xb4\xdaA\x91s:l2\x97\xd6\x03l\x88\x1c\xae\xba\xcf\x9d\xec\x1a\xee\xdfb\xac\x1b?\xef\\\xf1;v\x12\xf0`\x9b\x08\x89-\x0eK\x0355+\xed\x1eFl\x83\x89\x8e\xe5\xab\xc4\xef\xddK\x87|P\xcfR5\xfbZ\x0cc\xfc\xe6\x0861\xa3\x15\x8b|U\xa6w\xe7d\x99\x86\x11a$?\xe3\xe3N\xc2\xe2\xd3j\xd9DS\xeb\xb6k\x8c\x9e\xf2-\xef \x05\xcfuD\xd2d\x91P\x12_\x92\xcf\x03\x0d<\xe4\x84\x11\x8571K~\xf9\xbda\xe7\xb4\xe6\"\x1c\xe8>\x17\x9e\xa7n\xe1\xeb\x14\x08\xeb\x19\x8a\xf6\x18\xe4\xe4x=\x02\xfb\xe0\xae\xf0\xde\xcf\xf3!v\xf9u(E\xd5||\xeb\x95]-\x8b<\"e\xf9\x01=\x14\x97\x03\xc4e\x0d\xeb\xae\x9d7\x90)\"\xe67\x90\xd9u\xab+\xf0\xb2\xea\xabHS\x98\x02oXm\xf5@\xa5]\x7f|z1>\xbf\xbc>98\xff\xf3\x87\xf7=j\xf6\x88u\x0b\xe9\xd8\xc7\xe7GJ\x11\x84SJ\n6\xa7}\xd1\x0d\x06\xd9\x05\x9c\x9c\xfd<\xbe\x1e\xff\xe5\xf8\xe2\xf2\xf8\xf4O=\x1d\x9a\xf2\x0eL\x85\xb8\xf6\x9f\xd4\xa3\x8b\xf1\xc0\xf9 \x1b\xf3\xf3\x18M_\x8e\xffry}xvz9>\xbd\xeci|\xf5\xe8\x8d\x9f\x8fq-N\xcf\x8e\xc6=m/\x9b\xeb0T\xc9\xe9\x9e\xf2\x9a5\xa6>\x88\x1a\xb3{\x01\x9a\xd3\x05#\x9f\xe7\x94.G\xdb\xdb\xb7\xb7\xb7\xc1\xed\xb3 /f\xdb\xbb\xaf_\xbf\xde\xfe\xcc>kd\xf3\"\xa4s{\x99W\xdb'!\x9d\xe3\x9f\x93wZ\xc9r=3\x16{\xba\xb3\xb3\xb3]\xaeg\n\x01\xfe8C\xed%u\xd5\xe8\xe9\xb5\x0d\xf6\xc9\xc5\xc1r\xc9\x10(\xfe@S\xde\x0f\x19\x0f~\x1f\x85\xe9[y>*\x94P%\x826\xaa\xbfvV\xd3\x1f\xd6N^L\xa9\xad\xb4aI\x17\xac\x8e\x1e\xdb\xdb\x8cQ\x8d=s_\xed\xbc4\xd0\xf1\x99\xfb\xf4\xc5+\xcf\xcd\xdc\x97\xdf{AR\xfe\x1c\xa6I\\\xc9\xe6\x1a\xb9CE\x19\xdee4\x7f{\x12nV\x94\xe6\x99\xd9\xaf_4'\xd1\xa7\x9b\xfc\xb3\xf9k\xb2\xc0\xf8\xfe\xa6O\xf3$\x8e\x89\xa5\xd2\"\x8c\x93\xdc\xf2\x89\xa0\xed\xa6\xe9S\xb9\xbaY$t\xd4\xd2L\xb6i \xe9\xeb\x8d\xe2\xee\x0dv\xc8\xe3\xa0H\xfc.\xc9>10\xac?`x\x04\x99\\\xb8\xce\xab\x97N\xaf\xae\xb2\xde\xcc\n\x95X]\xadR\xa9\x9f\xc8\x93\xf2\xec\x10\xe5mR\xc7\xfc\xd5\xab\x9ev\x0c\xdePZ\xed\x88Q\xf5\xb4\xf4\xba\xd1\x92\xfc\xc5\xc002\x9a\xd2\x8a\x88\x11Ch-P\x18f2\xa1\xa8\x93\x19N\xb8.\xd6\x15\x17N\xcb\xee\xf0\xb7\x82\x84\xf1Y\x96\xde\xf1\xb78)\xc3\x9b\x94\xc4\x8c\xbcb\xfd\x1f\xa1\xcb\n\xe1 \xeb\xd7|%\xc3\x83\xc6\x10\xc2o\xd8\xad\xdfX\xd2\x12h\x0e!\xa3y\x160MH\x1a\xc3mB\xe7\xf9\x8aB\x98\xc1o\xb2\xc1\xdf`\x1efqJ\x8a@\x91\x93\x16$\x8bI\x01!\xb0\x8el\xe5\xac'XC\x00\xc7\\\x90\xc7\xeb+\xe7\xf9*\x8d\xe1\x86\xc0bEY\x171\xd4\xfeo\xc22\x0e\xbd\xf7\xfd\x16\xc0\x19\x9d\x93\xe26)\x19\x99@(\x90\x84\xbd\xab\x1d\xc8\x0b\xf8M\x8e\xf8\xb7\xc0d2n\xd9~$~\xf8\xfc?\xe2\x94\x8b\xbe\xfc\xb7\x98\xf4C\xd1\x97\x7f\xd2\xb4\xcb\xd2#H\x026\xf3\xbf\xeb\xc8?\xb5\xda\x13-\xdb\x9b\x16u\xc8m|\n\xbf\xcb\x99\x11\x94q\xdb\xfc\xbf\xd3J\xb0\xe5\x08\xe95\x9b31\xa9\xdc\xff\"\xe4S\xf8\x8d[~m\x82\xf3[\xd0\x0ckh\x94]::m\x00\xa2Oq\x0b) \x18\xbc/\xf2%\x1aE\x0c\x83\xcc\xa62td\x03^6\xbe\xc8\xa4\n-%\x16\xd1\xa4\xb8b\xc74\xe7\x9a\x1c\x06\x88\x8e/\xee\xeb\xf2\x0e\xcb\xa9D\xf5\x89\x83\xe0\xcd%\xdb\x89\x0c\xfb\xc7\xba5\xedV\xdb\x99T\x99\xafP\xd5\xdeN\xde.u!\x81|zI\xd4&d\xcd\x08\xfdY\xc7\xbe\xa6.V\x9a5\xf5\xf1\xb5\x8f68(\xbc\xa8\x12\xff_\xf6\xfew\xbdm\x1cY\x18\xc4\xbf\xf7U\x94\xf9;\xa7\x0f9\xa6\x15\xc9v\x9cD\x89\xe3\xe3v\xdc\xd3\x997\x89sbg\xfa\x9d\x9f\xc6G\x0f-A\x16'\x12\xa9CRv<\x93\x9c\xeb\xd8o{\x0d{\x01\xfb\xec%\xed^\xc2>(\x00$\x08\x14H\xcaq\xf7\xf4\xec;\xfc\x90X\x04\x88?\x85B\xa1\xaaP\x7f\xc4_\"X\xf5\x8d\x15\xc4\xdf\xee\xfb\xc4\xa6=\x8d\xbd\xeb\xa7\xea\x11\xaa\x8d\x84\xd9a\xf5Z\x1f\x81|\xdd4\x06i)vVn\xc6V\xc1\xb7+$T\x94Ql\xd7/\xe4\xfd\xa9\x1c^m|M\xb3q\xb4\"\xab\xc8vJ\xf2{\xa4\xfd\x10\xce.*\xf8\x1aFI\x10?\x1c;\xd5!\xb1\x08\xe8\xfd\x12|\xa7\xe4\x18\xb7\xcc2\xfb\xe2\x1f*\xf5\x8c\xa9\xc4\xb1]\x88\xa0\xd2f\xa0\xda)cI\xa9\xd5\xa0k7Z\x95T\x15N\xab\xcb\xd26|UO\xe5\x98\xb4/b*\x90\xb3@\x92L\x96\xc8h\x18\xc4\\@\x06\x8f#\x8a\xc4M\xb6\xc1\xc1\xaa\xa7\x95<\xd0X\xf0\x0dv\x06\n\x0bd\xae\xd6\xca%\xabN\x83\xdd\xa6)\x0e\xb9\x8f\x95\x8a2q\x9f\x8e\xcc\x87\x16\x0du\x00\x8f\xb0\x0e\xfeQ\xf0}\x82\xdc*\xda\x1f\xa2\xa0Xa>9\xe5FB\x80N-\xa2\xa4\xba\x9a\xec\xdbwFZl\xb1\x9a\xcf{i\x16#\xec\xc2\xedZE\xadV\xd1z\xff)\xa1\xfb\x89\xdd!%\xb2q\xdc\xa8cjW\x84\x87\x90\xb4\x10\x15\xe1\x04\xc4\x0fg\xcf\x9aK\x08*\x00#\xcd\x8a\xf89\x06Q\xb2\x071\x03\x7f+\xab\xdc\xb3G\x91H\x99\xb9\x95\xfal\xc4\x7f\xa1\xaa\x1e\xffp\xdf\xf8\x96\xd06\xd6\xef^\xc8\xd9y\xc1\x15\x9c\xeb\x0b\xb75\x10\x7f\x132\xa6^\xb7\xd0\xea\x12\x17\x8b\x18\x81'\xab\xaca\x85\xbd\x94\xbd\xceU\xd0I\xd7=\xb7B\x1e\x12b\xf5\x10\x91\x88wUl5\xfe\xe6\xa8^%\xb6\xaa\xc40\x84Z\xfcG\xbc\x8dV\xe9\x9a\xd1T\x07\xff\xc4\x97\x9f\xd8\x9d|\xf7\x89\xdd=\xc4Z\xd17\xcb\"Tf\x1bAV\xac/M\xaa\xbdCo\x08\xdea\xdf\x11y\xd1\x1bb\xf1\xae\x9d\xba\x9bH\xf8\xa3\x80\xfd/\x9c9\xf6=4J\x08\x14u\xf7\x1f\x8d\x0e\x87\x97\x8f\xae\xc3\x0e\xe7\x87\xbaZ\x1e1\"\x96c\xa3._\xc5\x0f\xfdV\xa0\xf4q\xda.\xa0\x1c\xee\xf2\xe2\xe1&@\x11\xe0\xf0U\x8466\xea\xa3\xb7)\x87\x95\xf8\x8dQ1Y/__ D\xf4w\x05\x83S\xbd\x18\x04\x81\x06M\xff\xb0\xff\xe5p7xx\x80V\xf8J\xd3\x8a\x07 \xce\xec\xe2\x8a\xf6\x0fP\x916\x18\xec\x9a\xd7\xe6\xf2z]\xde\xab\xef\xef\x05\x9d=\xda\"BN\xec\xb1\xe4\xbf\xd6l\xcd\x04\xdfP\x8f\xccm\xb7@h\xbbJ\xdb I\x94\x1a\xcf?\xfd\x14+\xe8C\x0csQ\xa9\xb8\xe4\x82\x8ah/z*B!\x11\x014\xb3\x8e@\x92\x04fF\x8a\x8e\xf2\xf7\x0b\xd8\xed\xe3\x95\xdb6x\xe0\xf3&\x86\xc0q5\x93a\xaeB\xf0\x02^\x16x\xa0g\xffs\x87\x16p\x9d\x1fh\xeb\xed\x1a^\xa2\x0e}\xad\x03\xbd\x01\xdb\xed?\xce\xdf\xa6\xeb\xa4h\x97\xa0\xd4R\xd1\xfd\x83n\x86RH3\x94\xdeXH\xfclZ\xdaT\xd77\x89!I d\xaa\xecr\xbb\x08\xed\x8b2\xd9k\xe9\xbc\x88U\xed\xe1\xa9mc\xaf-\x94\x9cEu\x84\xd2\xeeb\xbd\xf1\x8a\xa1\x95\xa9\xea,\x87#\xea\xad\x08\xbf\x88\"\x13\xf5\xcd!\x8c\x8a\xcb\x10\"\xebB\xbb\x11 \xaf\xa51^\x07\x11\x93\x91\x03%\xdej\x03\xa5\xbe)\x07\xda\xecM \x07\xfac\x9aM$-\xe8\x8aM\xf4bH\xe3\xder@Z\xc3(\x98\xf0\x11\x15fJ\x0crH\xf2\xe6\x1e-\xaa\xba!T3\x9aH#\xf4rd\xd8\xf0\x7f\xf0\x9e\x14\xac\xaa2\xbdo9l=\xc1\x82\xa6\xd4\x97\xbf|\x02\x99\x85\xf5_\xd5\x90\x17\x84\x9b\xa2a\xd2\x80\x86\xc9e \xf0\xb0\x0b0\xcfYA\x01\xd2\x05\xc5\xc4 E1[?\xa1\xc0\xf8\xe5\x0b\xd0\x05\x870\xba\x0c\x02\x85\xb0|\xd4\xa6{\"=jy\xe3\xe4\xd8=\x0e,\xa86\x8327\xc7h,\xac7\x96\xc9\x0e\xf9\xf9\xdb\xbe1\xcc\xe5\xec\x0093\xd6\x99.\xf7I]\xc0\xee\xae\x87#\xe7\x07\xea\x86l\xc77x\xc9'\xfe`/\xa0\xb8\x90\xbd}\x9a\x0b\xe1<\x86\xee\xaf\xa9\x8f#\xbd\xff8\xba\xdd\xed\xdeT\xc1\xdeP\x928I\xa7\x8c\x16j&\xf3(\xe3\xa5h/\xccP\x1b\xc0yI_(\xbaU)^M\x0d\x84?ARZ\x06\x0e\xf6\xf8\xde\x92\xc8P\xc0\xcbC\xd8\xdbE\xd5\xc1^\xa9[(`\x08\x1bJ\x9a\x15h\xad<\x15\xd2\xc5`\xf7)y\xdd\xbao\xde\xc2b\x98\xc7\x91`\xa1${si\xb0\xe3k8\x04u\x0d]\xe9V\xeaurB\xfbR\xaf\x81q\x0e\xcb \x80\xf5\xb2 \x86,\xa8+k\xec\xdb\x89\x85\x90\xeae\xde\xc3M\x97[\x18a\xf3\xf7\x18\xaa\x8b\x05|\xdfD\x8dJ\x0fdf,\xf2\x84\xe24\xa15\xe9\xd3\x0c\xe7\xa4\xd4Ex\xb5\x8c8\xa8$\xd2yO\x1a\xf7\xaam~X\x0f\xfe\x9e\xe8w\x01\xc2\x8eK\xf4\x94\x04\xbc\xea\xec\xbe\x08\xb5\xfb\xecI a\x8c>\x83j5\xcff!4\x82\xbe\x93\xbc\xa2\xf7\xe3\xcaJ\xd3\xb2eA&1\xd2a\xe7\xb3\xde\xd5]\xc1\xde\x08u\x12\xcd\xf8b6\x9a\"\xe8\xe5\xac\xf0\xc5\x0f\x0cb\xdd\xe6\xdec\x8e^\x05\x87\xc4\xf5\x9b\xc7yo*\xe6\xa5R \x0e!\xe2EJmm\x16\xba\xc1\xa0\x00\xaam\xfc\x01n\xf2G\xfa\xc6\xff\xef\xbe\xd8\xf8\xfa\xbeG\x94\xc4\xa8\x0b\xc5\xfc\x03\x9b\xac\xb3<\xc6$\x86\xebP\xf8r\xf1\xf7mWB\xb8w\x8d\x8dk\xedX\xc5\x95H\xaabs\xab\x9e\xa7|(\x84s\xb8f\x1c%\xe84z\xda\xce\xd2u\x82~\xbcY\x9a\x16\x8e\x9c\x98\xe6~\xc6I\xce\xa3\xfc\xa3BhmB\xc0\xec`\xf3q\x15\xc4\xb0\x99{\x16&B$fuq\x8e\x01\xcb{ \x94\xfe&u\xec\xc5c\x90\xfc\x1a\x14\xf4}\xe4\xc0\x02\x02\xd9\xd4\xf3\x95\xcc\\V^\x94\xb9\xc6\xa7\xae\xdbb\xdf\xb4u\xd5\x9f\x08\x15\xaar\xd4\xeeyjg|\xd4qV\xe9(\xb9l\x99\x18\xb9\xdb\xaa\xe4w_\xeb\xb2~3\xef^\xa2E\xa1\x19(;\"yH\xc3\x12\x91\x92\xbdL\xf9\xa9l\x9cD\x96,\xe1K\x89\xb9 \x12\xf9\x13\x0fl.\x89\xc8\xdfe.fyh\xf0wE\xc6\x98\xe5\xd8EN\x14\xcd\xb5Y]B\xf0q\xdbh{\xa3\xe8!w)l\xb1:\xc6\xd0\xa8d \xcb7Q\x08\xef\x83\xc7\xa6\xbeD\x08\xefOLY_\xba8\x0e\x1e\x93.\x8e\xcf\x06OZ%\xac\x86k\x04\xce\x06Q\x97\xc0\xbc\x81]G\x19\x17\xf2\xf7\x1ce\\\xc8\xdfw\x94q\xf1\xfe\xc0Q\xb6\x82Cx\x0c\xea:\x9cH\xa2<\x05y\xfd\xbd&iV9\xd9\"\xe4\xb4w\xde\xc8D\xdf\x84\xb0\x0c1\xd1\x1bnKL\xea\x96\xfa\xd7A\x08W\x98kv\x8d\xd9\xe4\xf6\x82\x10\xc6\xfcL\xf1\xef*6\xfbV\x90\x99S\xf4\x05?\x82)\xefo\xccE\xa4\\\xfd\xeaW\x06R\xcfa\x0c/\xe1\xf69\xdc\xba\xb6*\xdf\xa6\xfe\nc_p\xa2,\xa3\xe4/\xe1\x10\xae\xfc\x1b8\x84\xbb\xd1\xede\x08\xb7!\xf0\xc1\x99Z>\xb3\xa1$\x80\xd3\xd1-\xe7\xf5\x974\x11\xe1OI\xc5\x96A\xb7TA\xa0\x18\x9a\xbdf\xbf\x17\xd0\xcfjw\xff\xa0\x9a{\xdc\xb9\xb9\x9b\x0e\xad\x1dtn\xed\xb6Ck\xbb\xed\xad\x9d\ny\xe5\xc6\xbd$\xda\x891i\xe4\x7f\x14\n\xc3\x11\x17K\x86\x80\xd9\xf5&p\x04\x13\x18\xc2i\xad\xba\xe9\xeax/\xcd\xa9\x14\xdb\xc4a^j$\x8a\x10\xbc*\xd3\xb7g\xfa^H\xd3z\x9d\x0d\xe3T\x13Sv\xa5Y\xfcW\x95\xde\x1d\xcf\xdf\xf2\xe5\xf1\x04\xed\xca\xa4-\xda\x0fQ\x1eO\x8e\xd7\xc5\x9c%E\\\xa6bpV\xff1\xcd\x96\xef\xa3,Z\xe6F\xad\xd5jA~\xfe\xbeJ V\xf4V\x19;V\x05\xaf\x97\"!1\x16\x9c\x9c\xbd\xfb\xf1\xf5\xef?~8\x1d\x1f\x7f\xbc\xf8 _\xfd\xf1\xf8\xcd\xebW\xc7\x17\xa7\xf8\x83\xbf=\xfb\xf0\xfa\xff\x7f:>\xe3\x7f\xee\xe2\xcb\xf7\xb2\xbaU\xf0\xe6\xec\xf7g\x1f/\xea\x1f\xe2\xaf\xf3\x9f\xce~\xc6O\xc6\xef\xcf\xde\x7f|\x0f\x87\x8a(|W\x81T\x86\xcf\xf5\x13\x7f\xff\xb1yE\x9f\xca\x92\xdd=\xea\xf2\x1e\xbf\x19\x04\xb5C*\x9f\xa7\xb7\xaf\xf8\xa2\xc6\x1c4\x9d|\x9e\xecm_`\xea\xf9 A\xa1\xa3\xbbE\x1aM\x87\xcdbG\xb9\x16\xdf\xd2;A\xfe\xbb\xf5\xbeH\xaf\xd3u'V\xdf\xd5\xf5\xea\xbe]\x97\x13?\xe3\x7f\xed~\xcb\x18\xa6\xf7\x1d\xc3\x04\xa3=\xaf\x05\xe2\x7f\xcb\x08\xe6\xf7\x19A\x1d\xb1#\x85\xbe\xfdg&\xfe\xaee\xd1\x9ee\x96\x92\x0bV\xa7OZ\x9e\x10nEJn\x13&\x1e\x15\xf5\x92\x8a\x1c{zJ\xacv\xcf\xa26\x89\x89c'{|\xab\x8dW\xe9j\xbd\xf2\xec+\x8c:%\xf0J\xcc0\xaa\xae\xea\xf4\xc3\x13\xc8kT\x9ab\xcaK\x17\xf9\xf1V\x19\x1b\x97\xed\x8fSD=/\xa4\x89\x98gU4\xa0?\x17}i\xc4\xd0S\x17\x97\xd8\xa6E8\xbd\x12\xe1p\x10^\x8d\x1a9\xe8o+NV\x9c\x1c\xc5\x95\x94\xcay\xdcp\xc7X\xb3!\xe2m\xd1cY\xd6XKx\xd2\xf3\xc6\xe8\xf2H\xc4,K?\xb1\x84\xae ,\xa8\xa5[#]e!\xf2RM\xe6l\x19\xd15&\"\xc2E\xb4t\xf8\xfb\x8b\x9b\xb1kV\xf8\xdel\x91\xdeR\xe1\x82d\xc4\xf4uO\xe2x/\xbf\x8d\xae\xafY\xf6\xf1\xf5\x076\xc5\xb8\xcf\x822\x85\xe0E\xe51+t\x063\xcep\x88\x1c;\xbd\x84\xdd\xf2e;\xcd\xcc\xa4\xfe\xea\xe1\x8d\xbc\x9e\x92G\x04\x7f\xf2t\x9dM\xd8P\xe5\x90\xa7\xe1\xc1n\xd8b\x08\xdem\x94%qr\xed\xa8%%\xc1!x\n\x8f\xc4\x91\xbf\x8c\xee\xe0\x8a\xc1\x1a\xddgCXEy\xce\xa6\x90\xa3y\xc5m\x94\x83\x88\x0e\x86J\x8e\x9ce7,\x83\xf7F\x95\xe4\xdf\n\x89ml*\xc2|a\x1eRQ\x9b\xb0C\x0cB\x88z\x18J\x0c\xed+~M\x10a\xafm\x00\xf2\xfb!\xc4j\xdd\x03?\xa2<\x821\x13\x97qH5\x0c\xdf\no\xa8\x1e\xdc C\x88\x88.\\$U\xa7\n\x14\xaf\xf6\xeb\x92\x04\xd6\xb8\x11c\x11X\xc3\xb9\x11\x059(\x13\xab\x91u\xd62\x84\x87\x98\xa0\x9b$Tu.\xac\x8bt\xf5L\x84zu\x11\xb3\xa4x\xedhk\xa6\xd59g\x93\x8c92\x9b\xaf\x9c&\xba\xfc\xb9\xce\xa2\xa4\x18\x8b\xf3\xdfS\x03s`\x1e\x7f\xf2I\xca\xabrp\xa6+\x96K\xfbF |\x16\x01\xac+A\xf5\xa0\xc7\x9e\xa3l.}\x15\xcd\xf7JKy\xc5\xa5 A\xc0\x16p\x04\xf3^\x9dL\x1c\x82\x87\xf2\x06\x9a_\xf2\x1d\x92\xf7\xae\x8a4\n\xfc\xa8\xcc\xf8\xba\xc6\xbbM^\x96V\xbbgEy\x9d\xf3G-:\x89\xfc\xae\x8f\x14 \x87\xb0&\xe9\x8a\xcc\xc1[\xce\xc2\x9f\xa0\x06`*\x97s\x1cs\x08M\x82\x10f\xf5\xf79\xae3\xdf<\xe8\xba\xd5y\xf2\x93r\xf2\xb3\x00\xd3\xec\x99\xf2\x9b\x83&\\\xa5\xd3\xbb\xa1ji\x1d/\xa6\\8{\x15\x15Q\xe0\xaf\x1c\x8a\xcdu\xb6\x18\x8a\xe0\xce\xbe\x87T\xe3c\xb60Y\x0e\xf5\x08\xb8\xc6\x0eD`\xd1\x94e9\xc9\x96\xf2\x07AH\xb2\xcdPR3\xe2N\xdcI\xafB\xb7\xb0\xf9[\"U\xa9\xac\xc1w\xdf\xb7\x10\xb3f\xe2\xb2\xeeH\\l\x93b\xfd\xa9a\xe7\xb0\xcb\xce\xdc\x84\x8a\xd0\xc1\x00\xd4S#lr\xfbL26eI\x11G\x8b\xbc\x9d\xc4\xa5m\xb4\xcdI\xa3\x1eb{M\xee\xb3e6\xd9{r\x83\xb4\xec=\"r~\xc7\x0d\xe4\xd6\xe9\xb4\xdb\x00\xb98\xf3D\xba:\n\xc6\xf6c\xb6hV\n;m\x8f\xb3\xb2\x8fV!\xa1h\xe5\x1b\x8a\x96\xadVt\xd8j\xc57o\xb5\x1a\xbaG\xfa\xbe\x1bO8\xc7\xefF\xf7 f\x08(z\x13g\xd81\xac\xa5\x0e\xa6!8`\xa1\xd5\x12\xc7\xd4\x10\xd6\xee\x9aj\x11\xc7\xeb,\x1e\x12V\x04\xd0\xb8\xc3\xb2\x07\xd8af\xd2U\xf5\xb4\xef\xb0t\x93\x1df'\x9c\xbe\xd7\x0e\xa2\x95\xa8\xff\xdcJ\xb5\xe7a\xb6\xd2o\xe6\xd4\xfa\xbbm\xe3\xbf\xff\xe6\xbc\xff\xf1\xb7\xd9\xe6\xfc\xa5\x8e\xbf\xeaZ\xe4\xc1x\xc7\x99C\x13%\x90\xfe\x9a\x152\xeb\x1f]+\xef\xc6\x7f.:i\xcf\x84\x824\x8d\xf2\xbds\x0c\xae\x9e\xbaR\x15 \xbdh\xbeb\x93\x96\x8a\xabrx-\x15\xa7Ho8\xe68\x96\x0e\xcbQ6\xa0+\xdc\x94W2(}\xcd\xe1\x08\xfe\xf6\x15\x9cR\xc6\x12\xdb\x93\x08AW\xb9\xae\xb7\xb8T-.\xe9\xeaw-\xec\xf9\x95\xd05dD\xa4 \xfe\x8c[4\x97\xb7p\x08\xfeJ\xc3\x07\x1f\xad\xe2\xff\xf65\xe8E\xd3)\xde\x11E\x8b\xff\xe0\xf0\x11\xd6\xfa\x82-\xa3\xdb:%\xae\xaf\xf4\xb2Y/\xce\xcf\x8e\xcf\xf7\xfc\x80\xcb\xb0\xfd\x10\xa2J\xa0\xbe\na\xd2\x13\xb1\xf7\xd9\xf4\x1cul\xbe\xc8\xac\x0cC\xa2\xee\x8c\xcfXV\x08\xeb^\xe2\xbaU\xd1-\x1c\xd5\"\xf6\x89\xa6\xb2\xaa\xa9\xdb@\\\xa6\x9f\xca\xb4\xf4\x87`\x08\xfa\x7f\xfb\x1a\x82,\x0c\xe1\x96\xb2\xe3\xe3[\xee3\x1c\xc2i\xe9\xd1\xe0;\x88\xc89\xd1\xbc\x93\xa8\xf2\xf3|\x85a\xcc+\xd9\xf2\xd1_\xf24 \xa1`\x9f\x8bG\xabE\x14'!\xfc\xee\xd1\xef\x1a\xa8\xbcw\"\x82[\xee\\\xdc\xad\x98g4\xf6y\xe7\xf6\xf6vg\x96f\xcb\x9du\xb6` ?\n\xa6\xb6b\x13\x04\xb5\xba\xa6\\\xb3z3VL\xe6\x8eY }\xfd\xec\xd8'\x18\xd6i\x08\xde*\xcd\xcd\xdb\x0c\xf5\x94d\xf5\x9c.\x97\x12\xfd\x8dc_\xe0i\xe18\xf9e\x9c\x1bt\xf3\xe2`N\xb3!\xac\xfd\xa0g\xbfw}\x9f\xaf\xd2$gD\x03V\x81\xd5\xc0\xd7\xa0\xc7\xf92\xbf\x99[\x02\x8d+\xd3,KYo\xcaO<\xf7\x92#\xf5\x97.\x91B\x1b\xfd\xe5\x0bx\xaes\x0d\xd4\x15\x88\xfc\x02;9\xd5>\xa3\xed X/\xfd\x84\x0e\xcc_\xbe@\x06G\xb0hWw\x83\xa6\xf2v\xd0Z\xe8\xa8\xd2\x86\x8e\xeaqhP\x7f\x13\x16\x85\xa0T\xe0yG\x158\x94\x8c\xc1\xd8=\x00\xa9\n\xb7\xf9zP\xdd\xfd\x03\x00\x8f\xf5\xf2\"*\xd6\xf9\x05\xfb\xec\x9a\x08\x85\xe6\x98\xaai\x03<\xaf\xacQY\xa0l\xfch\x04D\xcb\xc5r\xb7\x89\x9b]\xf5K\xec\x90\x06\xae\xf9\xa6\x0c\x00P\xfb\xc4m\xf2C\xe7\xa6\xd2\x1f%\xdbh!M*\x17\xad#}\x03\x8bL\xa4\xcd\xe6E\x99\xdc\xb9\xc2sp\xfb\x10\xbc\x10\x98H\x16%\xc2\x04\xe0\x0ft\xee\xc5\xbf\xc6S\x96O\xb2x\x85b\x9e\xfe\x91\xf6\xbe\xf6\xa9\xfeA\x93m\x92\x96k\xcb\xf6\x0e\x02\xa0|\x86\x00\xfd\xec\x7f\xf3\x18\xbd\x01\x1a\xd7^\xfd\xf6l\xab\x10\xad\xfe\x14-\x17\x82\x81s\x99\x10\x95\x19\xa7\xc8\xe8\xbb\x98k*\x15!U\xeb&\x12Y\xb3\x89\x84\x91\xbb\xb6v\xb7o\x0d\xac\xd1\xd8\x94\xdedR\xea\x89\xab\x0bk\x0c\x87\x1cM-g\xea\xc6\xc4p\xb2\x19\x91\x0fT\x13X8\xa2^\xcc\xb3\xf46\xe1\xa8\xaa\xd3\x9f 4q\xfe\xb7\xb7\xf4\x8b4\x9a2a\xc8vq\xf6\xfb\xdf\xbf9\x1d\x0b\xeb\x8bs|\xf5\xf1\xfd\xab\xe3\x0b\xfdU3^\x98\x16\xc5\xbf\x14Z\xacUh\x86Flh\xb1=\"\xb4\x11\xa5\xed\x91q\xd2s\x0e\x9e\xd9 *PrH\x16\xe9\xf5\xf5\xe2\x9b\xcc\xd1\x08\xe5\xe5}\xac\xa1\x88e\x93\x064\xf9X@\x8ep\xc9&\x96\xbf\xfcH\xcc\xcc\xd3W\xa0D\x9br\xb2m\xba\x86\x1a\xfd\xbf\x07\xf6\x97\xafK;\xadL}D\x07AG\x03\xfd<\xc3\x8bmi\xae\xcf\x92\x9b\x9aA\x7f!\xcd\x17\x95\xc9?\x92\x1b\xe4e\x95}?\xe7\xbcr\xcd\xe0\x7f\x95\xe6\xc20[\xfdz\x1bq\xc1M\xf5%\xed\xb7e1\x9e\x9e\xd6Z\x90j\xe3\xf1U:\xbd\x1b#\xf6y\xb6,e5&\xb3T\x8d/\xfe\xf4\x9enN2Vx\xbfk4\x18\xd5\x1b<\x7f\x7f\xf6\xee\xfc\xb4\xa9E\xb1\xd3\x9b\x9a\\\xd7\xe1\xc5\xc14\xfe\xe3\xf1\x87\xd7\xc7?\xbc9%\xe6,\xa06\xbe\x91\x08/\xa7\x8d-\xde\xeb\xd8\xbf\xd1\x02\x95R1\xc2\x12\x7f\xb7O\xba\xc2\x0e\x1e\x9b\xf1\xad\x84/\xecc\xb3\xbap\x85}b\xbe\x16\xee$\xfb\x8f\xcd\xf0\xa8\x0b\xe19kjK&b,\xfbf\xf5\x99\x18\xcc\xb3\xc0\xf7\xe2\x82e\x11Fv\xaaWYq\xfe\xdf\x1f]b,\x14\x8c\x9c\x91p\x8e\x1a\xe2\x04\xe4K\xdf\xf4ui\x94\xd2@Sl\xcc\xe3\xbc\xbe-*\xc8:\xdd}Q\xfa\x9a\x87\xca\xd3\xd5l>\xf7\x13\xacdFQ\xe2+u\x17\xc2U\x08c\xe1\xea\xda\xae\xe0\xc50\x10\x98 \x0b\xf3R\x9c\x94\x9e\x8e'V~Z\xf5tr;\x15148\xe4\x1a\xf2\xad\x89J\x88\x9fM\xd5\x80\x96{\x1b\xebk\xdf$\xec\x16\x12\xe9\xa7\xee\xc8\xe7\xa6\x9eMT\xa9\x9b\x8c\xa8\xfbH\xec\xbe\x08\xf3\x13\xf4P\xc4\x10\xb5\xaf\x15B\xdb\x95>K\x07 \x0e[8<\xa4n\xe3\xce\x85\xd8k\xbd?\x11\xdc\x02\x1d#\x8e?\x9f\xe0\x10NF3\xcc\xfas2\xf2\xfe\xfd\xdf\xcb\x8d\x85\xafn8>\x9d\x8cn.\xed/\x8f\xe1\x10>\xa1\xc3\xb4\x7fC\xdc|\x9d\xc1!\xdc\xc0\x11|\x86#\xb8\xf5=\x96\x14Y\xccr/\x80!\x1c\x97~\xd9\xf6g\xe8\xd4\x85\xb1&\x84~\x1f\xfb\xef\xc9\xafyoF\x82@\x8e\xf5\xefQ\x1f?\x86C\x98\xf8\xefeT6v\x0b,\x08\x02\x8c\xe5i\x86\xbc\xe2\xd5\xc7\x98\xb3\x13?\\\xf8\xe3\x10N\xe55\xb7\xb8\x93S\xa8\xa0\xdf1\x8c%\x94\"^}\x16\xc24\x08B\xf8\xcc[\xc0\xbc_\xe5\x02\xf1\x1e?\x89X \xbc\xf5s\x19i\xf4\xb8#\x95\xf9T\x05c0\xb4i8\xba\xef\xbf\x87\xadk\x0c>\x8f[}\xeb\\,\x90\x1a\xda \x0e\xed8\x08a=*\xb8\xa8z\xcc\xff:\xe5\x7fMC |\xa49\xfc\xee\x9c\xf6ObNC\\D\xbej\xb7\xbe\x9a\xa6\xe3\xaeS\xc4Y^V\xd5\x91n8*\xcbU\x1d\xc2\x19\xb1U\xe0\x9a\xdeV(\xd8_I\x1f}\xfc\xff\x84O=\xe6S\xbf\n\xe1ntuI\\\xa8\xa2\x03x\xea\xa7\xbd\xf7\xb0\x0di\xefG\xf8\x1d\x08o\xff\xf3\x00\xe9\xef\x1d\x1d\x80e\xc3(\xf7\xfa)\xb0\x95\xf8\xfb\xfb\xa8\xd5\xddJ\xfc\xc7\x83\xc0\x9dQP\xf6\xf5\x04\xb6\x0e\x1d\x829?\x80\x0f\x02\x99\x9f>\x04/\xb2ds\x10\xc9w\x86\xedDL\xf5f\x83\xdc\xc0\xb6^\xe5\\!\xefg:\x07\xdaxLG\xc9|B\xe5\x85\xe1l\xc1^\xe0[9cd\xb0\x8d\x83A\xe0{\xafO\xc7\xef?\x9c]\x9cy\xf7\x0e\xb0\x11\"g\x92\x92\x894\x84\xc2\xd2z\xbdp\xc5M\xc3P\x82\xeb\x00\x12\x0ci\x89z{\x7f\x8d\xb0\xc0\xa8\x902\xc4/\xf1\xe1\xf32 \x0e\xbc\x84\xfcy \xbf\xe3G\xc0(\xdf\xde\xbe\x14f2\xff\x1d\xfb\x0bl\xed\xcb\x97\xaa5\x1a=\xcd\xa8\xe2\x9d\x17hw\x10\xf4T\nb\x1a\xa4\x99\xb8\x8fP\x95d\xd0\xdd\xcdzq\xa1\x01u\x0bb/\xb5\x8d\x0e&\x1d\xa7GN\x06\xd3\xac\x07\x8btj\xe4$\x8a\x08\xcdy\x8ca\xe8F\xf1%\x0c\xe9\x13\xc1\x0en\xaf\x07 \xad\x97\x1e\x19\x91\xef\xab\xc3hX\xffL\x86\x88:\x82\x08\x86T\xe4\xf8\xce\xd0\xdf\xdb#\xa0\x9f\x8d\xbc\xf1x\x92fl\xe7/\xf98\x9fG\x19\x9b\x8e\xc7\xe2\xa8\xf7]e\x87\xf0\xb7\xaf\xad\x1b\xcf\x01\xd2t$r8\xfa\xa9\xd0\x9c\xfe\xedk\xd02\x1f\x17=\xbd\x9fF\x91%\xeb%\xcb\xb8\xf04\x84-\x7f\x00\xdf\x03E\x01\x94\xf7\xb4\xaa\xb7\xeb\xa8w\x9b\xc5\x85\xaa\xb3\xef\xa8\xa3\x14#\xb5\x82o\xba\xd8\xa9Z.\xb7\xef\xfe\xe3\xc0\xdf\xd2\xb5\xd4\xfc\xddA\xe0\xcbh\xbf\xe0\x89?\xbc\xa6$\x1a\xa8g\x1e\x17p\x08\xd2\xa2\xaeT\xca\x8f\xe3\xfa\xcdG\xe8>U\xf8\x98\x98L}/\xda\xb3!Rj\xe0\xc71I\xc5\x12xyXQ\xc6#b\x15%L]<\xe34M\x98\x9d\xe0\x15\x86\x18\xcc\x0d2\x91\x7f\xa0\x9a\xdb\xf6a\x19V\x8f:Feg\x04\xaf,\xfb\x19\xd4\xfb\xd1\x10z\xc3cr0\xa0\x03R=\xde\xbb\xefv++4\x05\xd3\x8fC\x88\xc4y(\x17>\xf5\x0bS&V\x0f\x1e\x05~\xe2(\x15A\xa6]\xd1\xd2\xe4\x98rx\x01}\xe1\xd7\xfeR\xb8V28\x02\xcf+\x85\x00\xbeP1\xb6\xa4\x05/\xcc\x83\x00^\xc0\xe3\xc7\xbb\xcf\x0e\x90\xbd\x83\x97\xf0\xf8`o\xf0L4\xb4\x0d\x03\xe9\xa8\xc9iKd}\xcc+\x88\x06\x0e\xf6v\xb1\xf3\x887\xf0do\x7fO\xf6/\xeacG0\xc44H\xe2m\xbe\x88'\xcc\xcfC\xec\x04s\xd5D\xb0#\x9b\xd9\xe6\xe3\xdc\x91\x83z\xf1\x02\x06\xfd\x00\xb6\xe1\xe0\xf1\xe3\xbd\x83_v\xb7\x9b\xfa\x11\xa9\xab1\xb1G\x86-3\xe9\xbeT\xd5\x98\x1a\x9c\xb5\x0c\xf1a\x9e\xc6RWs@\xebj\x06\x96ng\"\xeb\x9b\x83\x94\xca\x9a'\xffT\xd6\x10\xcf?\x955\xfa\xf3Oe\x0d>\xffT\xd6\xfcSY\xf3Oe\xcd/\xa6\xacqjj\x06duw\x18\xd1\x03\xc7\xdd\xc9\xe3\xbe\x83o\xd3\xc2\xb3w\x12DQ\xfcL\xdb$\xa5\x0d\xf9\xca\xb7Q1\xef-\xa3\xcf6\xcf J\xe2\xa4\xc3 \xe9\x18\xb0d\xb4\x19\xf2\\}8\xe2b4l\x83\n\xc2\x19\xfb\xcc\x88\xc9\x0f\x1b\xac\x8f\x9e\xc8#4\xb2\x96\xc4\xb9\x9e1c%_\xbf\xceOK\xb9/,\xd27\xe9$Z0)\x1b\x95)Qpo\x9c\xcd\xbc^\xbeZ\xc4\x85\xef\x85\xde\x86\xec\xfb\xde\xde\xaf\xa2Dq\x04\xad\xdd\xa5\x95i\xc8o\xe5+6A\xfa}\x8f\x15\x95\xea\xb2H.hk\xca\x14\xcd\x13,\xc2CH\xfd\x16Q\x923?\nF\xf1e \x13\xef\xa4z\x92\xf3\xeeh-b\x17\x87J)h\xddR\n^v\xff\x89 \xab\\nL\x07/{`\xf2\xc4\x13Zs\xc2Y\xd9\x89\xca\xcdl\xb3\xb0\x93^\xce\x8a\xd7\xcb%\x9b\xc6Q\xc1l~u\xd2\x9b,X\x949j\xcc\xb1\xc6[a4\x7f2\x8f\x92\x84\x19~\x867X\xe3U\x9c\xaf\xa2bb\x98},m\xe5\xe55\x11\xca\xe7\xae\xed@CA\x1e\x0ea\x9b\x9fe6I\xe6'\xcf\xb5\x99:\x85\xce\x90\x01\x9a\xe1\xc5\xb5\x93\x9b\x95A\xd2x\x85\x10\n\x9f\xf0 \xa8\xbd1\xa6s\xd5\xcad\xdf\xc9\\ \xc2Q\xa5\xdeV5\"<\x96\xa7(D\xae\x1a\x9b\xac\xa5\xfd\x18]\n\xad\xed\xe09D\xd95n\xed\xbcR\xec&\xcf\x03\x95C\xa3,\x1d%\xdb\xdb\xe6I'\xf7\xcf\xf5h{{y\xd9\xb6\xd0\x02(\x7f\xe5\x0c&_\x87\x9b^\x92\xde\xb6\xb6\x86\xb5\x9c\x0d\xcd\xe1H(\x13|$\x93\xec\x16\xe6A\x8f\xd3\xbd\xdd\x10R\xfcc\xd0K\x93*\xb4\xf9\x95\x08T\x1f\xf9qo\x95\xe6\x85\xdc\x85Hk\x06\x18\xcfi\xd2\x8b\xa6\xd3\xd3\x1b\x96\x14o\xe2\xbc` C\x9aN.\x86\xd6\x00r{\x93^\xbc\xe4=\x9e\xa3\x17P\xceG\xd6<\xb5\x89>\x06<@=/\x04\xefw\xf54\x07\xf6\x88|ON\xc8C\xaejK\x8c\x1c]\xa5\xd2$c\xd1\xf4\x0e\x03\xee\x89p|(]/|O\xf8&a\xaa\x15\xf7\x88\xf2^\xb4Z\xb1d\x8a\xf9\xe8}\xed\xab\xa0g\xb7\xdc\x86\xc3y/c\xcb\xf4\x86\x89\xc6\x90g\x0e\xcb}\xea\xf4\x1c\x80\xa6\xcc\x959+.\xe2%K\xd7\x85\x86\x11\x9c\xe9\xa8\xbe\x0f\xeaF\xb3\xd6\xf7V\xa4Y\xa4\xd5C\x98VM\xe0_]\xb9\x15\xf7`\x1b\x9doh:\x8a\xeaF\x9a\x1f\xbf\x19\x02k'\x9b]\x1cv\xdc]\x13\"\x1f\xc8\xae\xdb:n\x81\xde\xa6\xec\xce\x13:D\xff\xe0I{V3G\x9e\x8f\x0cie\xea\x17vj8\x91\x90\xa8-\xb5q\xdc\x9b\xb9\xb2\xfe\xfa\xfd\x10\x92^\xc6\xf2tq\xc3\x02\x8cl\x8f\xa9\xfc\x96\xb1\x96\xdfjC\xc0X\x10\x10\x80yF+\x01\x91\x0dDg\x86v&\x90\xe2\x00\xe9|\xf3\x98\xc7\x8f\xcb\xc9Z\xdaT\x91wF\xb2x[[\x9c\xc9\xf3>\xb0\xeb\xd3\xcf+\xa4\x8di-%\xe6\x86s\xb6\xf8<\x95\xb0\x81\x9c\xf3\xe3{\xe1\x82ZN?\xed\xc9\xab7\x11\x9aA^\\\x89w\x9cK\xb10>\"\xc2\"F\xd2A\xc0O\xf0\x161\xeb\x9d\xa3C(\x17ac\xb7\x05\x00\x88l\x9e\xb6\nA&\x8c\xf1B\x88\xee\x0d\xc4g\xae\xdb\x84Zf\x97Nr\xa9\xa6\xeb\xc9\xea\xc9\xc57\x1a\xd1\xee\x9eC\xa69\xd8Cyc\x12\x15\xbe'\xf8)O0\x1dB\xc2\xab\x875\x9e\xd5\xeez5\xbe\xf4]\xb4d\xbf\x8e\x9c\xbdk\"\xa2\xdc\x934~Z\xe6\x0fR\x9aylj\xce\x854c\xdd\x9eKaf\xcf\x14Z\x16.@\xbc\x92\x0e\xc8\xba\xe4&\xe0&lS\x8e`\x01- peF$\xcc\x98'\xae\xf9\"\xbf\x90\xda\xb7\xd2\xccL|`\x1eH_\xad\xaedN\xa5\x92\xf4\xa6\xfeV\xd6\x9bii\xfdB`\xa3\xe2\xb2m\xc5\xcc\xe5Jp\xa7\x96\xb1C\x1el;\xa8D\xae\xf8\xc9\xa5\xe0\x8a-~\xa6\x13R\xb9Y\x94\xd2\xdd3\xf1\x1f\xef\x99\x18Ty\xeb\xd4\xfdr\xbat\xd9v\xed\xf4\xec\x80\xde\xa4O\xcc\xf7\xb1c3\x08\xf4\xb6\xac=\xe4\xbd\x93\x95tGS\x94Ey\x1e_;\xd4Q[\xb8\xb5[L\xaa\x944KE\xb4-\x1c\xef9\x92\x9c\xdf-\xaf\xd2\x05\x15[\x06\xb9\xe9\xe8j2e\xb3\xeby\xfc\x97O\x8be\x92\xae\xfe+\xcb\x0b\x8f<)e:\xd1'!dJ\xbf\xe4\x05\xbdY\x9a\x9dF\xad\xd1\x1a\nq\x86\x18\x0e\xadA(,\xc4r\xe1l\x1b\xf0\x0e\xca\xf3I\xdc\x95\x89\xa2\"\x08d\x98L\x0f\x93\xeeVn\x16_\xeb\xcc~\x9b\xd7\\\x84{\x9e\xc3\xdc\x94rC\xa49\x83PFK\x9f\x85\xa8!\x89{\xb3\xe7\x90\xc3KX<\xb7\xf9\xd2\xb2\xe5\x95\x90=\xd7\x9ap\xbc\xe0\xc2q(\x14!\\\xfe\xf3\xa7\xe510\xf1\xa7B\x98\xf1\xa7A\x88\x8a\x90y9\x86\xa5H\xc2u\x03/a\xf9<\x00I&\xa6!\xead\xe6\xa3eiQ\x95\x8cV\xa8S\x1f\xad\x1c2\xb8\x96a\x0d\x86\xdd\xb2J\xb5\xed\x9eA\x9f\xe6\xd7\x06\xa6nI\xec\x9e\xdd\x03j\xf7\xf8\xbc\xe0\x80s\x8f\xfe`\xf7 \xa8\xd9{<\xc5\xd7\x8f\xf7\x1e\x93)\x1a\xd6\xd4\x98\xa1t\xd7\xcc\xd2U\xae\xb9\xfdV)\xd4\x95_o\xc6f\xb9\xcc\xe2\xc7\x7f\n\xafh\x9c\x19\xea\xef5Jc\xf7\x9d\xff\x1d\xfb^\xd4\xdd\xa8\xd7\x9aof\x9c\x7f`\xd1\xa4\xd0\xf3\x10\xf2\xed\xa2W\xc9e>\xfd6\x9e\xb1\x8c\x85e\xe4\x82wg\x89\xc7\xbc\xbe[\x87e\xca\xf8\xa7\x8f\xbd\xa0>\xbf\x9e\x91\xd3\xbf\xbc\xaf\x0ceD\x05\xa2\xae\xcab\xafR\xb7\x85\xe0\xa9)\xd4u\x06\xfa$gi6a\x1f\xed\x00\x01\xe4j\x19\x1d\xfeX}\xab\x04x\xd6qp,\x04O\xeb\xba>\xbeE-\xab\xf1Z\xcfj\x9c\xd7\xf3#\xb3[X\xd4^\x1a)\x97s.\xd3\xe5z\x03ZkA\xfd\xcb8\x7f\xbf\xce\x98\x85\x15[\xfd&\x95AY\xd3r\xe5\xe2\x8di\xa5\xb9\x86\xa8p_\x82\x92\xf8\xcf\x02\x9b\xbc\x18\x0bc\xf5l\xfe\x90\xae\xafa\x861\x0c\xba\xfe\x07\x91\xcb\x13q\xb5k\x1fjk\x10\xf5+X;nb\xee\xbf\x04\n\xe8z\xc2\xb0\x07n\x9aT'\n^\x84\xef.\xf1\x17\xdf\xb8\xf5_\xbe\x97q\xdc\xed1q\xaf\xe4\xa1\xc9\xf0A\x7f\xd0\xdf\xfb\xc5F\x9a\xf8\x8f\xf7\xefm\x9d\x86\xe2\xd6\xd6`C\xd6\x98\x1eP\xed\x82\xf0\xfc\xf4\xe4\xc3\xe9\xc5\xf8\xd5\xd9\xf8\xdd\xd9\xc5\xf8\xfd\xf1\xf9\xf9\xf8\xe2\xa7\xd7\xe7\xe3\xb3\x0f\xe3?\x9d}\x1c\xff\xfc\xfa\xcd\x9b\xf1\x0f\xa7\xe3\x1f_\x7f8}\xf5\x0d\xees\x0f\xe65O\xc1u\xd7\x12\x0f\xa51\xe0\x01\xed\x92\xf7\xd82\xd0\x92v^\x074\xc3\xbd\xfb\xe4q\xdd^\xf4\xc9\xbe\xfe\xbb\x87)\x13=\x91k\xfe\xbcH3\xe65\x98}\xaa\x05\xed]i\xb3\n\xabV\xd2\xe5U\x9c\xb0\x0fl\xba\x9e\xa0\xd7gkKi\xcd\xdb\xa0j\xe9*N\xa6\"\x8c\xd0 \x1fY\xda\xa9\xb1\xd8\xd1X\xb4Z-\xee\xde\xc6\xd3\xe9\x82\xddF\x9d&\x189Z\x9ap2\x9fwia\xbd\xb1\x1b\x85\xe3 Ps\xe8\xd0g\\\x1bs\xd1\xd3o\xcb\x80\xc9|\xb0V\xf46\x8e\x8aFJO\x92.a\xf4\xb3\xda\xad/\xe7\xb1\x11\xf9\xc4\xb5\x98(38m-\x15\xf1\x16\xff\x88:\x9f0\xa5/\xc5BED*\xe5\xd3\xcf+\x8c\xf9\x00\xc5\x9c\x01K\xe6Q2a\x19\x14)\\1\x88\xca\xe9\xf6\xa8\xe8\x8ajq}\x16\x08C\xd9Z\x0d[+A\x8e\xa9h\x1bS&\xb0\xbf}H72\x99/\xa1g\xc6{j\xfb\xf5\x84pM\xe1\xef\xf1\x9e\xda~\xbd\x92\xa7W\xad\xa0D\x88)\xa9\x8e\x9c\xe1\xda\x8a\x1c(\xe2\xfa[X\xc6\x06&\xb0\xe8F\xe7MVS\x8bNM\xdc\xd0L\x8csAX\xd3\x82,\xd4\xe5]\xebj\x80v}M\xa5O\x95s\x98\xfaA\x08\xb32\x9a\x8dU\x0d\xb4\xa94\xda(\x8a\xd4\xdb\x0d\x15@\xea,\xb6\x06!\xef\xd5\x1e\x91\xfe(\xd9}&\xb23\x9f\xd9W\x14\xe63C\xfd\xc4\x84\xf9I\x08\x03\xda\x8a\x0b\xac]A\xbfu\xad\xe4\xd2\xbd\x92[Y/B;\x02k\xe9d\xf08X\xae\xf3\x82/\x19\xc6\xe2\x05!x\xe5=\xf8\x983\x98\xac\xf3\"]\xc2\xb2\xa4\xe8\xa8e\x88\xf2\xbbd\x02\x91\xf8\x9c\\^#-:\xeb\xa1l`\x0d\xe1\xdf\xca!Dw\x98\xb2}\x1e\xdd0\x88\x12(\x83\x1d\x83\x87jiPvG=\xf8\x89W\xb9K\xd7\xb0\x8c\xf3|\xc5\x16\x0b6\x85\x08PD\x89\x92\xe2\xe8\xdf\x1c\xa3Y\x11\x00P\xa7g\xd9\xfdT\x1a\x804\xce\xcd\x1dFs%E\x1bNSr\x7fA\x9a\xc2~\x85Y\x9cD\x8bEc\x1b\x03\xfb3\x9b|\xe8\xf6\x12\x9c\\\xcd\xc4\xd9 \x93\xa6k\x89\xe1\xb7\xb7]\xc8\x7f#3\xb6\x17\xa3\xc4aD\x92\xb6^\x80\x82\xa6\x92\xfb\xce]m\xe9\x0c\xc8\x15\xf7^\xbf{}Q\xff\x94V\"\xadI\xc3L\xb5hd\xec\xf1|}\x95O\xb2\xf8\x8a\x91\x11\x96\xafKq\x87\n\xf5\"\xe4'\x89$m\x92\x1f\xdc\x9bp\xf2\x93,a\x9f\x8b\x0f]O3\xf5H\x1d\x0f\x05Y\xf58!\xac\x1e*Th})BX\x8f\xd2^\xd4j?sS\xf9)\x11I\xacu+Fz\xb8\xdaJ\xb5C\x1a\x14\xb4 5\x91\x0e\xeb\x8b\xbb\x15\xa3\xe0\x9d^\xc9t\x89\x12\xd8\x8a\xec!\xac\x9d=\x96\xe4\xb6\xddJ\x9f\x95\xf6\xd4\xe2/\x7fn\x9e\xeb\xfaC\x93~@)\xa2\xe1pQ\xa2Ma9\xc3\xeaO\xa3\x0d\x82z\xd6\x89\x06\x7f;l\x90z\xba\x9cQ\xf8&\xe8\x843P\x0d\xcf\xf2&\x01\x81|\xcc\xc2\xc6\xf2\x05\x11)\x87\x0b]\xb4K\xecc\xeb\x0e0&Q\x91\xef\x94!x\xff\xfe\xef\x9c\xb9\xfc\xfc\x88\xff\xac\x07\x93\xff\x06\x89Z\x17\xf1\x1d~i\xd6\x9d\x8d\x14E\x1f\x9bWB\\\x1a(o\xc7\x84\xd8|I\x84\xc2Qfk.\x9f\x87\x9cp\xfa\xad\xd7\x10\x1eh\xa5Mo\xad\x8c\x1f;\xb9a\xb3X\xaf!\x92\xb9\xe2\xb5\x81\xe8\xa6v\xc1\x1c5\xea4\x90{\x89\x91{\x01\xcc\xd7\x8a\x7fm\xa1hS*\xdal^\xbc\xc0\x1b\x93\xc8b\xcbxs\xa8$\xe6\x1cIQ5\xd1\xb7\x9bH\x90\x1d\x17\x8e\x07a\xcd:\xda\xb3mY\xc8\xa3\xca-\xd7%\xba+2\xbe\x91\xf0I\x02^uV\xa1\xf7\x83 \xda\xe3~\xd0\x8bzB\xa3e\x82~cm\xd5\xa6\xf5\x9dkm.u\xc9\xcc0\xf2.\xacP\x97\xc7x_\xa6q9exIq\x19\xa8Y\x83^\xda\x8b/xQ\xc5\x18\x95\x08\xd0|\xda\xd0\xac\x8d\xdd\xf8\x80n\xbc\x18\xf5/I\x04)zBz\xf5k\xb0l\x18AWB\xca\xfc\xa2\x87j\x18\xc9\x80\x87\x15T\x88\x13\xc88\xec\x1fDq\xf8`J\xbc\x10\n\x15\x00\xb9\x8b\xf2S\\\x10\xd5(\xb7&}\xc0\x11xq\x12\x17q\xb4\x107P\n,*\xabr\x91\x82\xae\x9b\x83!\xa6\x1c\xbf\x89\xd3u.\xd3)gl\xc2\xe2\x1b6\x85\xab;]\xffP\x8b\xec\xaakM\xcb\xd1w\x81e\xb5g\x9f8\x9cQ-\xdb{y\xb1i\x1e\x19\xca\x84\x9frG\x1d\xc0#\xd3\x98]\xb8Q\x1cA=b\x02\xe5\x90\x86r\x0d\x1cA^\x1e\x07e\xc5j\xf5)}5GJ\x8a\xba\x13y\x06\n\x97Q \xaf\x1f\xfb5\xcb\x95\x82KXh\xc3kW\x8d\xf4\xaa\x0bL\xee!\xe8y\xc0\x17\xd6\xa3i~A4\xa6\x08z_\x18\x9fp\x1c\xe3@,\xf8\xaf\x9d5\xc7\xaa\x9d>G\x96d\xb3\xadS\xed{\xa7\xbd\x9c\x96\x0f\xa8\x84\x0e\x9e>\xe2\x08\x92\xb6t\x87\xa5G\x1f\xbe\xae\x0f^_\x0cm\x80Ay\xb6%\xfe\x9e2\xf0\xde\xdc\xfc\xb6\xcd\xbcag l\xbf\xe5\xa9\x8b\xb6\xf4}\x18j\xb1\x01\xd2\x92\xb0g\xc1s\xd8\xde\xe64={\x1e@*\xe8y\xe1\xb3Qr\x89\xcaT\x87\x1dh\xba\x19\xd4\xb5\x83\xf1\xc9A\xe0{E\xfaq\xb5b\xd9I\x943\x97\x15'}Hv\x02\x0eqA\xaf\x06\xb0C\xd8\x1c\x8bh\x97\x94\xaf\x7f\x81>_\"%\xc6!\xec\x14\xf0\x12R \xcb\x14\xb6\xd1h\x0b]\x81\x12Y\x90r|\x0c\xca\x8f\x12\xd8>\x844\x10\xe0\xe6\x1f'\xf2\xe3\x04v\xf8\xef\x97/1v7\xff\xe3\xd0\xcczU.h\\.U\x8aK\x95\xc1\x0bH\x9f\x07\x10\x8f2\xb4\xa5\x19e|$\xf4a\x17\xb7\xac\x92\xb9D|.\xc2\xc2\xd5\xf7F\x7f\xfe\xf3z\xb7\xdf\x9f\xfe\xf9\xcf\xeb\xe9\xd3~\x7f\x87\xff?\x9b\xcd\xfe\xfc\xe7u\x7fO\xfc\xec\xef\x1d\xf0\x9f3\xb6\x8b?glw\x86\xdfL\xf1\xe7n\x7f&J\xfbL\xfc7\xbb\xdc\xdc`W\xce#\xe9\x15,/\xdaM\xcf\xbabG\x08\x19\x85 \xa9\x03A\xe2\x86\xbdD\xac\x1a\xdee\xc6\x12\x03\xf8\nmo\xa7\x97\xb8v)\xbc\x80\xf8y h\x9e\xcfw\xd7(\xbdD\x0f0\xc76\xdb\x90\xb8U\xdbl\xf0\x9420\xae\x84\xf1J\xcdA\xc6\xd7\x8fI\"\xe3\xd6\xb3\xa0\xe1\x9a4\x04)\x9c\xf6\"\x05\xad\"H\x89[\x83\xa4M\x84US-\x99,ZQ-v\xde\x11(\xdeLXldhx5\xea\x13\xa6\xcf\xa0\xd6[\x04*\xb7\xc5{<\x0f\xb9\xec\xe5\xa7\xd5A\x17c\x1eHs\" \xc7)r`\xd7\x07`\xd7,q]e\x00\x88{9o\x14/\xb4\xbe|A'\xc1\xdaG_i\x94)\xbfO\xd8\xad\x1f\xf7N\xf0\x17\x97\xe38\x0bo\xe0\x13\x7fT\x15\xcc\x8e\xa0\xef\x9ax3\x94\xb3ng\x05\xfbd\x19\xf5\xc6\xba\x04}\x9c\xdf%\x13%,\x9b\x82tM\xd6vUZ\xeb\x95~\xcf\x12\x116\xc0U;\xd7k\xbf\xcf\xd2\xcfw\x97\x8e\xab\xf7\x16\xf9\x18\xad\xff\xdb\xc4\xe1\xcc\xe5F\x81\\\x0c:\x95\xe2_\xeb\xf2\xaf\xb8\xfc\xab\xcd\xc8\x86\xa2\xdd\xb6\xd6\xa1\xc52\xb8y\x92\xa5i\x17\xb5\x01\xdd\xeax\x0d\x11m\xff'\xfe\xb4d\x86jmY\xf8\x8fm\xd2\xecWj\x11\xf4\xd4\x10\x1b\xa2\xfa\xa0\x1f\xf8\x89\x7f\xb0\xff$\xd8\x88{ih\xd0\xdc%b\xf3\xec?i92\xcbKo\x19\xfa\xc8q\x80\nv\x15\xad\x0c\x95.\x06\x8a\x92h\xab\xa2-\xe53\xb4\x95\xfa\x89\xf0kV\xf4\x1c#\x02&h\xae\xaa\xf7\xc7x\x97m\xa7r\xc3\xacim\xdc\xee3\xda0\xe4\xc0\xca2\x14\xa1\xb1n\xed\x15\xa7\x07\xbbm\xd8\xae\xd8\x80<\x84E\x08\x13\x8a\x19@g\x02\xf8\x9e\x0c \xaf1\x8cv\xa9\xc8\xa8Dq\x07x\x1f\xc6\x019E \xfb3@\x1f\xdd\x97\xb0j&%\xc2\x8f\x9a\x9f0\x94nm\xce[\x11\xc5\x9a\xe85\xc7%\xb6\xdb\xbaq\xf08Kq\x87f\xbd\xbf\x96`\xe0\x12\x17?\xb63B\xf4\x04\xc5\xf9\xa0\xbb\xb8\xa0N\"!k!dE\xce\xfb\xdc\xc0\x0bX=w\x1d\xe5\x98\xa7\x96\x8c\xef\x02\xd2)\xba\x18\xdd\x10we\x1c\x00y\x80M\x8c\xf9\ns)\xd9\xbf\n\xe1\x0eC\x1d\x15\x88\xa1\x13\xcc\xca\xe8\x8b8F7\"\x9d\x13\x7fK\xb7\xa6\x99r\x8c]*\x1f^o\x1c`\xea\x9a8Y;\x92\x0c.\x0d\xcb:\xfd\xb9\xcaX\xf4\xc9*\xb1I!:\xa77\x8db\x0b\xa5\xf1V]V\xed\x93\xd8\xbf\xc6j\x9cA\xbd\x13\x9a\x1a\xbe\xfb\x17\xd2\xcdTl\x8bIP\xe1\xd2\xb50\x06p&\xbdl\xea\xb1 \n\xe0\x84\x04\x90\xd0\xf8*\xe2\xa7\xc4\x18+\x86/\xd0\x15\xee\xa3\x85\\\xdar\xe0\x8e\xe1|\xeb\x82\x90\x87\xc8\xa4'<\xcaQCZ\xfe(\xeaN\xe9\xf8\xd7\xbd\x84\x95o\x92\xf35\xc9\x9e\xc4\xac\x9a\x98\xefT\xcc\x97\x84\xa9e>N2\xbf\xf7$\xe8}\x8c\x93\xe2)\x8a\xb1\x0fr^\xee>\xa3B\x80r\xb1\x87\xbe\xc79\xd8\xbf\xaf\xe8)\xe2\xa5~\x93/\xddSz\xac\xbb\xedcr\xeb2b\xa1\xa5q(g\xf8l\x8e0\xf4_\xe6\xc7!$\x1dp\xa4D8x\xfc8\xf03\xc7\xd6M7\xebc\xd0\xa7\xa3RqN\xcd\xbf\n!'&v\x0d\x870\xf2X\x96\xa5\x99\x17\x827Y\x08\x7f5o\xca\xf2\"K\xef0\xb0N\xb4\x16\xef2\x96\xaf\x97\xcc\xbbt\xb9\x08\xdd9\x11&\x06y\x1b\xc3a\x88\xde\xe0ROf\xce\x154\x1aU\xe8F\x86\xb1]\x0f\xbd\xc9\xc5\xed\xd3\xdbt\xca\x9b\xdc\xdab\xda\x0b\x19Z\xd9\xb7\xeb\x99o\xbe|\xc1O3\xb9\x7f\xce\xca\x12\xc7\x1d\xa40r\x98\xc7\xd7\xf3\x9f\xa3\x82eo\xa3\xec\x93\xbd& id\xd5\xeeO\xed\x1f\xac\x89\xd1\x1d\xc1\xe0\x00\x8608\xd8{\xba\xef\x80Bm(\xfc,\xe0S\x12'\xa42\xa5\x10\xb0\x88\xaa\x82(\x90\xd9c\xd6!\xdd\x08\xc6\xfb\x9d-\xd24\xf3\xedr\x15\x96@\x08\x8a \\\xeeo\xca\x84\xed\x18\xe4R\xcb\xd8\x1e\x8b<\xe9\x9c\x8f\xd5_\x9d\xa4k\xf4\xa5W\xf5f\x8b\xf4V\xa4\x1a\xd7j\xb2D\xa4\xc8/\xf3\xb5\xb3d*\xe8W\xed-\x87\xb2\xf8\xb6|\x85.>\xc2\x9d\x05\x7f'\x8cM\x15\x91\xac5(Z\xa3\x8a\xd4\xda\x89 \x8aF\xfbbC\x9cO\xe6l\xba^\xd4G#\xf7\x8f\xf9\x12-\xe9N\x93I*\x87\xca\xacw\\\xae^\x17\xb3\xa7*\xe3|t\x1b\xc5\xc5\xab,\x8a\x13\x0dNr\xaeo\xd3\x8c\xd5\xdb\x9f\xa4S\x96\x99\xe0+{\x13oY\xf5\x8a\xa3\xc4\x1c/\xb2\xe6\x92\x82<\x0bzBE\xf1J\xb4\x15\xd8M\xb3[\x98\xfbU#\x81\xdd\x8fVX\xc3W\x97\xe7\xd7\x95\xdb\xf3\xcb\xa4\x1c[\x88\x8b:e\xb8\xaa8\x08>\xb4+\xd2\x95\x0dG8\xce\x8c\x03\x92\xd7\x17DK\x04\xa9\xa8\xad\xb8\n\xf1 \x14\"4\x03\xcc\xebV4\x06\xdb/w|\x10\xba\xd8f\x89\x1b\xda\x87\xea\xcdaU\x1a`\x14\nW\xdcx\x07 \xc7\xd5m\\\x16B\xeab\xe9%\x17\xc1\x0c\x88\xd8`\xabL\xcd\xe1\x08\xfc\xc8\xd8c\x9d\xf8\x04\xd4\x8d\x8b=\xac\xd6\xc9\xee\xa7\xaa(\xf1\xcc\xd5\x1ah\x9c{Y\x99\xb7\xde\xe4b\"\x94\x01\x8a*!\xd4%\xddRy\xd3\xc2*\xb1\xd06o\xb8N}aX\xb1\x91d'\xf6\xed\n\xa0\xb9xI\xb9\xfa!\x9c\x93\x97\xf7\x1ct\x11\x86.\xf2\x91f#\xbew\x82+B\x81\x9es&\xa2\xe4,zq.\xd8'?\x13\xce\x07\xfa\xb6A\xcd%e\xbb\nztn\xa5*1NKa\xa8W\xf7Mz\x9d\xdcD\x8bx\nI\x9a\xec\x88f\x1f\xc9\xc3a2_'\x9f<39\x9dz\xf0\xb8wLDnk\x02n\x11F\xb0\n!F\xe1\x93\x13p\xbf\xe4bb\xcc\xc7c\x0cY\x1a\x9c\x96\xf1\x97\xfb\x1c\xa3]\xf37?&\x93\xc5qi\x16\xb3\x0bi6\xc7\x1c6\xcdv\xde\xc6\xdc\x16\xbdY\x96.i\xdc\xc0 f\xfc\x94\xd6\x8f<{\xbe\x9aC\x9e\xe0({\xeb$\x9f\xc7\xb3\xc2\x0f \x9a\x15,\x03\x96L\x81\xdd`\xf0\x8f\x00s80\xb48\x10!\xfa\x10X\x02U\xbb\xb4\x8d[F5|z\xf6\xa3h\xd2\"\x0eQyd`nK\x0em\x8c\x0bXn\xda\xdb,\x96\x97{&\xb4\xa5\x8e\xaeJ\xf5\xa5\x8fw\xc0{\xfbT\xed\x9bz\x99\x0ci\x8c\xe9\x9ej\x03\xa2\xb0\xcfT,\xb6\xad\xd5\x16\x93`\xe2$\x84\xd5\xb9 \xdc$r\xc0/L\xe6\xb0b\xba\x98\x93\x8e|\xf5\xcd\xf8\xe3\x0e\x1a\x7f\xab\xd1xj\xc0E\xc9E}\xff=\xd4\xddEp)\n\xc1\x16\x1d\xf1)\x88\xb5\x9eFE\xc4\x97\x1ac s\xa0\xf9}\xb1\xa6\x1d\x89\xa2@\xd2\x92\xa6*\xe4Kx\x1b\x14\xa5\xad\x01\xee\xfb\xef\x914\x06\xa1XT3\x10d\xed\x17\xed\x94q\xa5\x87q\xf2J\xc6\xeb\xdb\x93\x9f\xea\nc\x82\x7fP\x01\xad\xea\xaf+\xce\xcf^bB\n\xae\x8d\xc7\x89\x80\x8e\xee\xfd\xc6\xfe\xf9 \xdf\xee,\x13\x82\x06\xbf^\xc5\x88,\xd5\xdf\xf5\n\xe3u\xa2\xd7)\x7f\x19\xb5\xaa:\xad\x87\x99\x90\x06\x10;\xd6\x8b\x05G\x10+\xccw\xbdq^\xb7K\xc37\"EE\x06\xe4\xf29\xc9AVG\xf4\x04\xcfoC{Th1\xdb|\xa4kxld&7/r\x15eu\x86\x9b\xa1;\xa1 \xfb\xc2\xba\x07U\xac\x9e\xf4\n\xc3\xa0\xa9\xe3*\x1c\x1a\x126;\xfcH\x1d&r\xcf\xb5\x9e\xe4\x97/_\xc2\xa0\xf6k\xb7\xf6k\xbf\xf6\xebi\xfd\xbb\x83\x10\xd8\xf6v`:]\x83\xe0\xb6\x03T>\xbd\xa8q\x17\x0c\xe7\xab\xa0\xa9\xcf\xbc\xb04\x06\xfd\x10\xfa\x1dc\xdb\x9c\xd3PPW*\xed\xc2\x97\xdd;\x97\xf3-e\x05\xc7\xfa\xa9\xef\xf1\xd7\xea\x9d\x17V\x8b\x1eP\xdfH\x9d\x88\xe2\x04\xd2*\xf5\xc6 \xba\xa3\x0d\xe1\xa4f\xe6\x02\x0d\xf3<\xa1\xe7)\x87\x04j\x92\x9e\xc8\xb0\x80\x0c\x87\xfe\xee\xc2N\xea@\xf7\xf3\xc9}\x82\xd4\xf4!\xc8\x82\x9b\x1a\x92~\xa8O\xf2X\x10\xd6\x8e\x13\xbb\xca!\x864\"\x01\x0bXV\x9c\x16\x17\x10\xce\x9c\xab\\\xeaK8x\x8bx\xf2\x89\x1ag\xa7>\xde\xb7\xaf\xb0\xc2v\xa1y\xa3zB|w(\xe6,eZ\x85\x90\xa8\xd9\x96\xe8\x18\x82\xb9d\xdarn6\xa5\x8bo%\x02\x88bS\xdf\xe3\xe3\xa9m\xeb\xe7\xf5AJ\x0b\x01\xa5|\xf2\x83\xe7\x86\xc0\xe3\x1a\xe1\xdb\xb6C\xc88z\x8eDWH\x1d-F\xa9{\xaf\xe3\x98\xdeu\x13I\xfaB\xfbU\xb9\xb0\x08\x07\x16\x0c7D\xe2\x15_$\x91\x93\xa4\x16^\x8a\xb8g\x92%;\xa6\xf4\xa0\xff\xd2\x15:\x99\xd8\x93\xcd\x1a\x02)Mx\xe2\xecd\x9a\x91$\x9f\xef\xc0\xb4\x95\x02\x0d\x01 \xa5\x0dM 1\x8a\x00\x8d\x9er\xfd\xa4r\x832\n(\xa9\x9b\xd0\xfeZ\x9al\x0d\xc3\x0f-\x99\xee\xcb\x17\xa5f\xa8n\xac\xe5\x8c\x87`\x89\xef\xa2\x9d\xb0\xfc$l\xd4\x01\xbd\x16\x97\xc40\x84s\x95q\x81\x13D\xd7<%\x81>T*\xa8@k-p0\xfe\xdf\x7f\xafzq\xb5\x8d|\xb2\x0c\xd0Q\x03\x8d\x13}\xa6\xbe\xc7\xebUJ\x82\x10C|\x18Q\xae\x04\xe4\xaa\x93\xc6\x96\x97q\xfcS\xe5\xf6\x00\x0b\x96\xe7P\xcc\xa3\x04ny\x8de\x94}\xf2\xc4\xb8P\xb9\xaa\xc0\x86\xcd*\xd1\xeeH\xad\x05\xff\x91\xe2\x95\x19\xde!\xa4b\xe1\x91\xbf\x93R\xf94\xc5\x01{A\xa8}_S\xa9HM\x91\x05@J\xa3T\xd38\x9aJ\xb5@or\x10\x1a\x82\xb0X\xc1\x04WP\xae\x8aX\xdaL\x1e\xf1}8*\x05\xbc\xa1<\"\x8f\x1cz-\xfe\x7f?\xd0u\x7f;\xa8\xec$gQ\x02\xd01\xa3\xa4\xdaJ\x9a\xc2C\xe2\x8f\x1a*\xea\xc6\xcbk\x94\xda]\x14?\xb0\xea\xa7\x9b\xa1 \x1ew\"(Z\xc3\xc4\x85\xa6\x80x\x00q\x8e\x81s\xe3\xe5JdH`6\x1d6n b\xcc2\xd2\xca\x8c\x96\x82\xd6\xf7B\xb8#\x8b\xa7Y\x14'^\x083\xb2T\xed\xcf%Y*g\x17\xc2\"\x109S\x8d\x8f\x13N\xaa'\x0deWd\x99\xa467AX\xc6\xbd\xde\x8au-!^\xeb\x8fo\xb3\xb8\xa8]\xbcn\x99/\x91\x08\x96\x9f\xcc\xa88\xb9_\x1b\xd6w\xe2\xbc\x8a\xc6\xb5E\xceP\x18\xeeM;\xc5\xb2\x8e\xeb\x06#\x1a\xef\x8b\x04\xf2\x8c\xab\x8cQ9^\\X\x17\"\xea!|\xeb\xc9X\xc6\x02\xc6\xd5.\xa0A\xac\xb20Pes 24\x00\xd4\xb2!8O\x05\xc4$1\xc1P\xb6\x14*j\xc5Jk\x1c\x8e\xbeBt\x91\xd1@k\xe4\x12\x1d&%qW\xa1\x0ej\x15^\xc2\x80W\xda\x11\xcd\xbe\xf3+\xfa/x\xcc\xad\x95b\xa2f\xd1\"g\x80\xddB\xc6\xf2U\x9a\xe4,\x04ek\x9e\x98\x17\xb0\xb5%n(\xdd\xde\x96\x93\xeb\x8bl\xca\xbc\xbdMw\xe3\xb2\x05\x88\x8aT\x15A\x08W~+5\x13\x08'\x10L\xbc\x17\xe7\x82\xc1\x98\x10\x11!\x9a\x06y\xed\xdcV-\x84\xf9\x8a\xa4 \xee\x8e\xee\x9ai\x93l\xbb\xf5\xb8\xd8\xb4\xdb\xab\xa6n\xab\xc3.\xe9\x89\xbf\xbb\x9d\xfdJ\x9e\x15;\xb1$\xfed7]o\x07\x00\xac`n\xba\xb1\xef*c+\x96L\x15P*/=\xb3D\xe4\x98iP\xa1\xf7\xc6h\xc2\x97\x0b\xe4\x91?F\xc5%\x1cA\xe4\xeb/\x02\xb4\xe3\xab~\xd7-\xb2j\x9f\x1e\xc2( k\xaf.\xb1\x8a\xf0\\J\x1c\x04OCeu`\x8b\x03\xa5\xce\x1f\x88w\x06W \x90^\x9e3|3\xc7%\xa1\x95w{\xc8\x8aU7r\x89\xbc\xcd\xf3\x03\xebR\xdf2\x82\xb1\x18\xf3&\x9d\xd5F*\x03\xf7\xdaWL\xd4\x90Jz\xc1\x1f\xc2\xc9%\xd6b9\xeb\x1c\xbdR\x11\xce\xe3\x9c\xfeh\xe0\xfe\x88U\xcc\xa5,\x87#lIXq(\x89Q\x96\xe1Qi8f\xd8^\x19\xfa)8\x90\xd6\xf0j\x11KvA\x18\x13%R\x92%p\x18\x9d\xfd\x9c\xfcB\xe9\xf0#\x0f\x0b'\xa8S\xa8\xcf\x9c\xde,\x9b\xce\x8an\xa5\x163\xb4\xff\x1cb\x0c\x15\n\xf1\xf6v\x00\xd9(\xbet\xc1\xa0Qak\x19\x0e\x01I\xa6nd\x9c\xc3w~Q\x9d\x9f\x0d:8D\x89H[l\xf9\x99\xca\xd9\x13\x850\x08\x0c@\xec\xa0\xe4cc\x93d~\x14\x08\xe5_\xa3\xfe\xa5\xb6{]\x0b\xdf\xb49S\xeb\xc6\xb5Ib\xcek_Vn\x10\xd2p\x83\xc60A\xd1\x05g\x12\x94\x82\x98\xdb\x00\xadT=(\x02C\xf0l*FRe\xb3\xa2\xdao\xc1\xe5.B=\xe0]Q]\x89\x9c\x11.G|\xe7R\xef\xc5\x85\x88\xa5\xc9\xc9\x1c\x0eM\x99\xa6\xec\xca4}\xcey\xa9<\xd4\x04\x853\xb9\xa6\x9b\x1c\xabM\xeb\x1fM\xcb\x93\x0e\x0e\x0d\xcc\x08\x0dU1\xdav\xb4\x98\x19\xde\xc8@\xfb\x9d\x00]\x9e\xb9\xc6QS\x9d2\xcc`\xf7[1\x15\xa4YJ\xdd\xd0D\x19\x1fY\xe6'\xf5\x1b\x88\xf7\xa4\x01\x12\xe0\xd9*\xd1<\x08(;CC\x0f\xc5\xb9\xdb6@U\xaaV\xbe\x8b\x04\x87\x0dr\xb2B\xc7\xd1\xb0E\x82\xb0\xe3>\xc2\x83\x1b\x99w\x87\x05e\xfd\x1c\xd1\x14s\xf2\xab\x0e\xd3\xbd\xcd\xa2\xd5F\xa7\xbb\xfb8\xef|\xf6g\x8e#\xa2<\x1eR\x8c\xc7\x83\x0c\xa5\x10\xa7[\xc5^NN\xa6\xbe\xc7g\xb3bS\x90\xc2}R\xf7\x97P\xba\xf8f\xc9\x99 \xcb\x87nnP\xf2\xec\xd6\xaf\x0f\\Z3p^c\x16\x9a\xa9\xb6\x8d\xbc\xa5&A\xf2\xd6%,HW4\xfe\xe8\x90P\xc2i\x0d\x14~Z\x9b\xa3\x90SS\x8e.[\x89\xe17R*\x95QS\xafY\xef\xa7B\xa4\xf7\xcd\x0f\xb0\x9e\xb2JQb?\xce/\x0d\x04\xd1U\xba\xf1R\x90\xa4\xb6l\x806\x93\xba\xcf\xd4<\xceG\xe9%\xd4c7kR\x81,\xf4UE\x0d\xa9\xdb\x1c\xee[\xd1K\xab\xcb8\xf3/B%3=\x85F\xc7\xf5\xfe\xca\xe1\xdc\x80\xfa\x1agt]^1\"\x83\x84Hp=\x8a/\xb5\x9d\xde\xbb\x8a\x93\xa9\xa4n\xbc\xa8\xc1#\xa7\xd0\xbd)\xdb!\xa3\xa1\xd0X\xde\x1f\x16\x81\xf2\xfe\xce\x14\xe7Z\x89\x11\xf6Di\xda\xd3\xc5\xddD\x91\x90\x9ao7\xe9z\xc2\x92\xf5\x92e\xbc.\x97\x13lj\xb3\x91k\nEak\x17G\xf6\x1c\xeb\xb3C\xbf\x8f\xf1,K\x97\xfcT\x86Cx\xfb]UV\xcf\xac\x10b\n\x1eG\x82\x05C0\xae\xe5j\xb0\xe3Mti\xa2-\x1b\x90\x88\x99Q\x16\x94\n\x83\x94<\xaa\x1b\xb4,_\xc9Q\xd7?\x97~,\x1d\x0c\x8f\xee}\xd7\x03m~D\xee\xd0\x02\xe23K;M\xbc\xaeZsn:\xf4\xb2\x8e\x84\x9f\xde\x11:\xe1\x94\xd6\x9b\x1b\xf4\x83p\xae\xb1\xb3%\xd3\x93*yA9Y\x08s\x9d{\xba6i\x17\xa7\xd6\xc0\xfcF\x08\xd4?\x96\xaf\xfd\xf2\x04 ;h\xb8\xb7\xe4=\xce\x11\xe7\xcb\xf5 &bv 5(\xf3e\x1dV8(\xbc~E\xd0\x92\xfa,\x87\x9cU\xfbYzd\xb5\x10\x93{\xc3}@\xf3w\x99\x1d~\xc1\xf2\xa1\x996\xb6`\x84u\xf8\x96\xe5\x1d\x90\xdf\x12#\xb0\xca\xcd)\xd4+\x08]Vs\x1b\xc6\xa2\x9aNU\x06\xf9\xe9\x9ca\x87\x0c\xc8\x96\x95\xa1g\xaa\xfbvDd\xafL>\xabG\xcf\xca\xd9B\x04\xb5\xe4\xff\x7f\xf9\x02\xb7q2Mom\xfa\x92\xd2\xe1\xef\x91\x93p93\xd1Y.\xa0\xc4\xb4xZ\xf9N\xf5\xc6h\x89\xfd#\xd2K\x07x\xf0\xcb^\xce\x8a\x8bx\xc9\xd2u\xd1Q\xccI\xd8-\xc4~*N\xb0\xeak\x8c\x87P1@!\xe0\x00d\xa1\xa5\xb7\xc0~_'\x05\xcbn\xa2\xc5=;V\x9f\xd3=\xabR\xa2k}d\xa8\x80\xa9}\xd0*\xffH.\x1f5\xb1\xbe\xd5|\\S\x97fl\x86\xb6\x91\xba\xec=3\xe6k|\x84\xed\xb6\x81\xa4\xb6\xc6\x02\"YX\xe2\x011g\x96d\xe9b\xd1EA\xa4C\xc7g\xbc\xb9\x05\x93?_OQ\xfc\xd0_\xd9\xf8\xc5{['D\x7f\x0f\xd2\x99i\x0e\xc7{\x1b#\x9c\x8f'E|#\xb4\xaf\x91\xfa\xf3[:\xa7/\x08\xe5M\xaaV\xd5\xaeW\xc0\xcbC\x99S\xc9l\x15\x0e\xa1\xda2~+/\xcaz\xe34Q\x93\x17\x97\x12\xe5o\xea\xb6\x87p\xb9\n1\xa4\xd5n\xa0\xf6\xdcr\xc9\xa6\xb1\x08\xce\xd2N\xc2\xea_Ta+*Rh\xd5\xe08X\xb2.za\xb9\xf36\x1c\x82\xf1\x0d9\x08\xbbNm\x18\xf5\xe2\xea|\xe8\x94\xe0lc\xe6\xd9\x11S-Eeb\x9c\xebq\x88\x9a\xf1SY$\xe1\x9d\x82\xe7\xc16\x17\x82q\xbeE\xfa&\xbd\x15 \xc9|\xa7\xfd7\x1a\x11ys\xf6\xd9\xa3\x8d{D9FBj\xa9\xb0\xd3\\#\xca'q\xdcX\xe3*N\xa2\xec\xae\xb9J\x94\xb3\x83\xfd\xe6\x91L\xf2\xdd\xb6\n;-5\x8a\xd9\xe0`\xc1\xda\xea\xec\xb4V\xca\xa2[G9h\x1e\xda\xfd{\xda\\\x95\x1e\xde\xf6\x16\xaf\xefnG6,\x8a\x931\x08\x95B.\xdc \xac\xab'\xb8\"\x81\xed\x0c\xbc\xba\x90\x92S\x11x\xd6r\x11T<\x7f\x1e\x94\x03s\xb6\x0c]p\x17:\xe1\xafz:\x0c\x12\xba\xa0!tBE\xe8\x88\x8e\xd0\x15%\xd5\xa3M\x03k\xb7\xcdd\x11\x15q2h\xed\xbdq\xf7\xaaG\xf5-\xdbl\xeb\xbaq\xbbC'\xd2\x02\x1dh\x9cz\x94\xba\xae\xc1\xe8\xa9mO\x82r\xb1h\x0e\xb2\xa5\x1eN\xb3}I\xb4\xeb\xf4ZD\xa3\xd0R\xd8\xea\x0f\xa5#\xa4n&\x1d\xd1{\xc5\xe5b\xed\x989<\x94\xd1\nE\x120\xdb+\xc4\xfb\x98|J\xd2\xdb\x04\x14\x15\x18\x82\x18\xb6[{\x88V{uJT\x05v(#\xd3Q,W\x07\xb4\xc7F\n\xf6\x99C)/\xdb\xe4\xac\xd3B\x80\x8e\x88\xd1\x08n#\xd7VR\x81\x1d\xcc\xe2\xc5\xe2M\x84z\xba\xf5\xfd{i\xc4j}^\x93\xda\xbcf\xa2\xc7\xbd\x8dzlDX]\x89),\xc0\x0ea\x15\"\xe7\xe4k\x1d\x9b\x92B\xed\x17\xd6[Dy\xf1\x8e\xa1\xa0\xadB#\xf2W\x17i\x81\x92\x92\xfe\xeed\x1e \x9f:\xdd\x1f\xb0\xa6\x0d,\xff,\xcf\xaa\xc8&\xf3\xa5\xa9\xc5\x8bC\x18\xec>QIb\xe0\xe5Kx\x0c\x87\x87p #B\xe3\x9b}\xfef\xb0\x0fG\xb0\xa7^\xed\xf1W{}8\x82}\xf5\xea\x80\xbf\xda\x85#\xd8\x19\xc0\x10vv\x1b\x87\xb4v\x1c\x9fJ\x1bXM\x7f\xa7\x0e\"[\xca\xdf\xc4\x05\x1a-Ov\x9f\xf2\xbd\xec\x0f\x9e\xed\xc2\xf7\x98\x14<\xd0\xac\x99\xeaK\xe1\xfd\xdf\xff\xd7\xff\xe9\xa0\xb2\xe8cTU\x97\x16\x83\x9ak\xd8\xa0\xe9h\xa5\x062p\x0dd\xd08\x10\xa0\x06\xb3k\x0c\x06\x7f\x9b\x1d\xee\xba:\xdc\x95\x1dv&\x9e\x85T\x88>\xa7\x90L\x93$\x12t\xb0\x1f\x1aX\xffB\xf36\xc3x^\xe8\x97YCy\\V}\x1f\xf0\x0f\x03c_\x94\x89\x0d\xeb\xfcVho*\x11\x17\xac\xa9\xa32\xc2\x99\xbe\x9f\xcb\x11\xefh!\xd0\x9a\xf7^N\xaa\x00\xf8z\x95\xd9T8\x8a\x07\xf0\xaf\xb0\xcb7P\xbfI)_\xa5n\xf4K\xf2\xee\xb6#i\x0e\x04\x80\xd7\x91\x93y\x94\x9d\xa4Sv\\\xf8\x9a\x0f\xac\x199Z=\x18b\x9f\x8b\xdd\x8f\x1f\xef>;\x004\xcc\x7fq\x08\x8f\x0f\xf6\x06\xcfj&_\x06.Y\x04m\xdfX\xb8Q_\xa4-\xd6 \xb2{i\xd6\x19Xu\x06\x97!$\x95\xa3\xfa\xce\xe0\xfeF\x1e\x14\xde\x9a3\x19\x103\xd9m\x9f \x1f\xa5c\xe1*4C\xa87\"\xd2\xc2M1\xeb7\xe2G\xda\x81$n?\xa8\x9c\xec\xf5\x8d\xd4r\x11\xe4&\xc7\x0d\xdc\xcb\xb6ksj\x10\xe8\xdb\x01\xc1\xc8\x95h\x84\xcc\x84\xdcbj\xfc\xd66\xdb#\x89T_z\x9b\x1c\xd5\xd6J\xb2\x1a\xd2\xf1\xcc71b\x0fv !\xb0bOY\xa4%j5\x1a\xf1\xa3\xd6\xf47\xed\x87 t\x0c\xbf\x86iI\x0b\xcd\x9a=\x1c\xaa\x91[\xe9\xa8\x11;\xcaA\xf7C\x04\xb0\x81\xa9\xc3\x16lX\xb9\x99\x1d\xc7\xf9\xd0\x0c\x8ci\x03\xf3\xd4\x06\x0b\xada\xf5WQ\x8f\xe7\x06\x87\x10\xd75\xd3\x8a\x91t\x0b\xff\x95\xcdmy\x06\x95\x82\xa1\x01~\\\xb6\xd0t|\xee\xb4\xff\xe3*\xef%\xfab\x96\xac\x99b\xe2\x85\x9c\xe3\xe8\x18t\x03%\xd5Mhs\xbb\xf5\xbd/\xec\x14\xd1\xe5\x9bD\xa3\x04c\x92V\x00\xd71\x89\xf3\xfc\x9c\x10$\x81\xe2/\xeao\xf0:I[\x91:\xd4\xa5\x88\xd0xK\xf5\xc0\xf8\x8f\x1cV\x1d\x9d\xebc\x92RL\xe3]\xc2\x8d\x99\x17\xbd\x81\x01\xae\xec\x93+\x8aAs\x0e\x19\xbc\xe0M(\xd2hW\xba\x91\xd9\x03\"\xbf\x18e\x97\x0e\xfe#E\x0d}\xd9L\x8a\x8e\xbcB_\xaf\xa1@\x8aG_\x08)\xdd\xc8\xce\x0e\x0e\x86\xaf\xde\xce\xae\x10\xb3\x9b\x06\x86\x8c\x956\xb2\xa0\xf3\x18v\x7f\xfd1\xc8\xb60\xf8\xce\xa1\xca\xd2Y\x1f\xd5\x1e=*\xd5y}\xfb\xb8M\x8bQOhly\x9b*\x96\x01\xfb\x8d\xaf\xad\xf3-\xb1\xa9\x8c\x1e\xa0\x01v\xc0O,\xcaMn\x0c\x9a\x05\xef\x0b\xcfijh\xf5|a\xf5\x0d\xa3\xa9\x17\x9a\xa9g};\xbe \x08\xa9C4h\xe4\x85\x1eT@\xa9C\xeb\xde\xc3\xd1\xc4\x98\xfa\xa45 \xc68\xa5\xeeu5\xa3\x9b\x1ei9Nn\xb4\\Pt\xa63LcS\x164\xa9\xd7\x11\x87\x11\x04\xb5\x84*\xf5\xb4 \xb1\x9d\x01\xabfu_Zc\x14Y\x94\xe4\xb34[\ns\x0c\xca3\x06C\x83_\xa8z\x1dl\xa7\xc0d\x9b\x8d^h\xa9*\xe9\x95\xb5\x9a]9*\xb1\x0d\x0f\x9c\xc9\x95[J\xdb\xca\xea\xf2\x983v\x80\xe068\x84\xae\xa2\xc9'\x15\xaaf\xb9^\x14\xf1j\xc1\xa0\x88\x97,w\x86\xbcW\x03\x99\xaf\x93O\xa5\x9bJ9\xba\xea\x8d\xcc\xfaW\x94W\x852ut\x88Y\xf8\xdc\x93M\xbb\xda\xc5\xf3'5Lw\xfc\xd4\x8al\xaeLd\xe1\x05\xa4D\xe0\x8d\xaa+\xdf,\xb6z\xfcZ\x99\x81Ri\x04\x19\x9bj\x88C\x99I\xeakN\xd7\x90`\x14\xf1.\\\xc5\x1c\xf4\x8d5*u3\xafT?/h\xfb%\xc2\x13\x83\xaa\xa6E\xf3h\xcc-RNT3y\xaa\xde\x1d\xea5\xdc\xa9Ff\x8bu>\xd7\x1a\x10\xbf\x0fU\x89\xb2\xbaG\x9b\xedU\xc6J_\xbd\xa8M1J\xf1S\xca\x1d\xa3\x8eg\xe4\xc8\xf4\xd1\x1c\xe9\xbfj\x99\xd3Hnl]\x12\xd7\xfa\xa2p.r-\xc9U\xb5\x7f\x9a\xe7\xb1v\xb1}\xb5\xab\x14\xc2\x88\xd4\xe6\x12j\x99GY\x15\xee\xde\x8a\x14\xa0\x0eL\xeb\xa2\xe3$Z,\xf86\xac\x16y\x9a&\x0cn\xe7,\x81\xdb2\xa9\xd2\xd6!\xf4\xcd\\\x86B\x8bi\x10\xcd\x1au\xdc\xb0\xbb\xbc\x88\x17\x8b\xdaV3\xbb,!C\xb8\x03TB[j\xa5V\x0b\xb5w~,\xd8\x95x\xc3\xe0\xee:\x816']\xa3 \xa5\xdfS\xbd}\xcb\x9d\xac\x1ay}0\xb5\xfd\xd6&)X\x00\xae\xbev\xc4\x98qvk\x8b\xb2t\x97ug\xb3\xa63\x13\x85\x13\xfd\x80\xe1P\xa9\x1dB\xac|\xa3]\xb7\x17!le\x06\"\xd1\xf2Q\xe7#\xc7\xcf\x8c5\xc2\xf3\xe5\x17:q\xbe:Al:\x174\xdf\xaa4\xc2\xb6t;)t\x88\xe25\x82\x02\xb8\x88\"\\cW0\x0c\x93\xc9\xc0\xf4-.\xcb\xd7\x1b\x0dU\x93\x15\x03\\\xf4\xea\xdc\x960!\xb6\xb7A\xdf \x89\x8e\xa9\x1at\xfe\xccd\x14\xed\xd6\x8c-\xd6l\x90Q\xf8\xc2fZ\x10Y\xe1Cn\x12w\x83\xb8\xdc\x8b\xd7\xd6\x98j3\xeb$G_\xcc#\xa9KEiv\x1aM\xe6\xf5\x8aq\x95\xdf~\x92\xb1\x1a.tK\xdf\xab\xf0*\x16D\x93\xa4\xaa\xd2\x8a\xb4\xb4\x1am\x03 \xe7\x069\x8eug\xb4iV\x10M]\x12\x99`\xbe\xc08\x80\xc0F\xc9\xa5U\xf9\xab/\xf3f\xa3\\`\xaeUX\xd34\xc2}\x97\x8b\x84g\x00\x7f\xfb\x86&5\x0c\xd0Sen\x92\xb7\x16\x89\x1d\xb9jq\xfe.z\xe7c\xfa_\xd4b\x14B\x7f\x817w\xdf\x7f/\xd5\x15;\x98\x9b!\xc5\xe8\xd6\xc32\xfc\n^ \xb5\xa7O\xef4\xc7\xba\x0b\xce\xc1\x93\xa7\x81\xcf\x87$\x916\xca\xf3\xf8:\x81!\x16=\xfbV\x9b\xc2\x10\xd2\x10\xb3\xc9\x85\xb0\x0eA\xf5h\xec\xadNv\xbd\xd6\x85\x05\x7f\xb4\xb8 Evg|E{g-B\x90Q\x00I'\xacI\x9a\xcc\xe2\xeb\xb5r\xc3\xea\xd3\xcc\x7f\xe4t\xd2js\xe2\xc2,\xd8C0\xcc\x80\xb5u\x85IT\xda\x8fU\xa7\x93\xb8\xf4Xhw\xb9\x99%Y7\x0f\xdd=\xec\xfa\x90\xab\x91\x88\xd0\x86$\x14\xc3\x8d\x13\xd4\xa35\x0cJ\xa6\xa5.\x0b\x1d!ez\x0d?\x13\xf9\xc1\x05K\x81\x9eZ\xd5*e\xfa\xad\n^\x17\xc9\xd4\xd2\x83\x83 \xc4\x8c\xa8\xa3\xcb\x10\xe2v\xaa\x1aR\x1ap\xce\xf9\xacG\xec\xb2d\xe6\xf9\x8fz\x15${\x05\xf6\xf3\x1c\xd8\xce\xce\xf3@\xb9\xb9z\x91\x07\xdb\xe0oo'A\xa5\x82\xda;0\xe5zM\x8f\xa2\xdc&|o\x96\x88\x9c\xb9XTJ\x1c>o\xb0\x90Q\xeeC\xf0\x02\xd8\xe6\xff\xfcM\xb51K\xa4\xc3\xa68;+\xc7\x81\xe7\xf0\xf5y\x9de\xec\xbcF\x04\xc5G\xf9\xc6\xb1f\xaeD\xf2 \x9eZE`\xa9\x1e\xec\xbd\xc9\x9f\xc8OB3\x01\x95\x03\xfd\x81\xba^\xfe\xfa\xad\xc4I\x88\x1cT&u\x1a\xe9\xeb\x00\xaa\xaa]\xb3\xe2\xec6Q\xd5^\xb1|\x92\xc5\xab\"5\x0c\xa8#\xd7\x07\xef\xa2\xa5\x19\xd3d\xed\xaa{~\xb7\xbcJ\x17y\x87\x93\x89\\cA\x82\xe5\xd1\x9c\xf9\x85\x89\xa7('\xea50\xca@\xe4\xe7\x81bv*\xf1\x9b\xce-G\xae4\x7fpOg\xa1H\xba\x9eQ>\xb6\xfa\xd2\x93M\xa0\xa1\x86\xfd]\x1d\x81\\\xaa\x0e\xcc\xe7\xbe\xfe\x07\x9b\x89n\xe0SJ\xe8\xb4\x9c\xfd]\xbd\x95o\xdc\x15\x8f)\xfe7\xf1\x07\xfb\xe6n\x89iO0\xce\x9e\xde\x17I\xf9\xc1Fd\xc2\xe3\xfb\xa7\xa4v\xa3\xddK\x12\x0c\x19\x92+\\!\xbd#\xc1\x87\xac\xa9\xe5HF\xd9%\xfa8)_\x8a\x08\x05\x12\xf5\x85\xb5$I\x0b\xa0\xf5>\xba1\xfcr\xe8[[R\xdb'B\x10\xd4\xd3\xc8}\xf9\xe2P\xe0![\xefR\x10\xceY\xdbh;\xa1\x05\xcdH\x15!x\xe31\xcb\xdf\xa6\xd35\x9a\x9c\x98K\x89\x8c\x8e.W\x06\"\xde<\xda}v\x81\x88\xbdX9\x17\xae\xdf/\xd6\xd7q\x92\x0f\x1d{\x8be\x99\xab\x08\xb0\xed\xe9z\xc2\xb2|\x08~\x9f\x0b\xbar\xe9\xcd\xe2E\xc1\xb2\xee\xc4\x80\xf5>\xb1\xbbs\xf6_~\xd0c7,\xd3\xc8\xb4\x13\xb4`u_\xb4d\x0bD\xa9mT4d6Q\xb2?z\xb8f\"\x16aw\xb2\xefDg\xd6[\xb2\xec\x9a\xf9N \x19\xc5T\";\xdc\x06X0\xfe\xe1O\x0f\x8d\x08\x9a\x1e\xa3\xf2 N~\x0dtH\xe8pZ\xbf\x06\x805)\xb2.\xc2\xc5B\xe5\xb6k^\x97\x89\xcb\x0f\xf3m%\x94\x0f:\x0b\xe5j2\xa6\\./e\xec\xc9\x95\xaa\x03\xc3{\xfa;\xfb/>\x83\x85uG\xc5\x19\x9b!\x18WS\x0bv\xc3\x16\xc32`|\xadl\xc9\xf2<\xba\xe6Go\xe9\xe6\x8d\xb5\x8c\x1e\xff\xbe\xa2\xb7K\xaf\xd5\xa4\xe1\xb4`\xfb\x97\xfc|\xc5&C(z\x9c\xc98W\xda$\xfc\xf5\x87\x04\xd6\x91\xb28f\xf35\xe8\xc0\xb1\xaaok\xa2\x80\xd8\xa1\xf8b\x15 \xbe\xc4l\xba\xc2G\x87\xf6\xf0\xc9\xae\xa9\xd4\x7fH\xed!Er\x08\xf7\xf8\xff\x15\xf4\x80 \x87\x8e7\xd3\x11\xd2\xe4]q\x8f\xc6\xff\xdc\xab\xfe\xdc\x0f\x02a:\xf3\xf7'_\xb4!\xa3\xeb\xc0\xe8\x80\xc67e\xb41\xc4ZI\xc7\xbd\xa0\x17'S\xf6\xf9l\xe6{\xd2\xe21\x9dA\x84g\xbd\x9f\x07\xa6\x11)\x947\xd1/a\xc7\xe9\xf6\x7fS:q\x1b] \x07ft \xa3:S\x96\xb6\x98\x05\xa1\xf0\xbd\x90\xea\x1e\xf4i\xe7z\xfb\xa1\xab\xc3>\x92\xd8\xed\x0ebB\xadqq3\xe1\x9b\x88\xd0\x90\xd7\xcdh\"\x91i\xdc*'4\xb1\xab\xe5\xef\x970\xc0\x83}\x1b\xbc4\xc3\x18)\x05\x0c!\x1b%\xb0\x0d\x83K\xa3\xea\xae\xac\x8a\xc0\x0b\xc1\xd3kj%X\x80\xbf\x9c\x03\xfc\x1a\x82\x97\xcf\xd3\xf5b\nW\x0c\"\x97Z\xc3O6\xc9$\xe0&~\xbf\xe9\xfdD\x9c\xbdEO\x1c\xfc$\xa1\xd1nu\x1dD}\xb0\xf7TCZ\x071\x0f\x91_\xfcMC\xe6\x1b(\x8dkw\xfa\x14\xf9\x11&@\x9e\xf2s\xeay\"e\xeaj\x11M\x98\x9f\xb0[\xf8\xc0\xaeO?\xaf\xfc$\x04\xef\x9aW\xf7\xbc\x80\xd2\x1b({\xa2\xdf:\x1e.\xa2\xbc@ss\x11Yr\xb1\xc0\x1fy\x19\x16\xd6@+R\xb4\x10\x98\xf6\xd8|\x1d[M\n\xa5\x8b0{U\x0cl\xd0q\xf5\xea\x80l\xd3\xb1\x94k\xae\x8b}JXU\x9a\x16cm\xaa\xa9\xd6\xc1B\x8f:n\x1aB\xd9=oG\xe3\xc8\xbf\xc5$\xe9A\x97\x9d\x90F\x1cs\xb0a\xdb\xe5\x92}\x11\xdd\xa5\xeb\xa2\xdb={)\x88\xfc\x03\xdc\xafS8\xfeP\x1c2}\xbf\xbe\xdb\xef\xbb\xef\xd7\x9fv\x16\xe5\xffW\xe0\xab\xff\xbe\xdb\xca\xc6\x99P\xaahvM\xa3\xa8HaM\xfc\xd0X\xb3& \xb4\xb0\xab\xe6\x98\xa4\xd3\xb8\n\x96hm\xaen\xe7\xa3J/\x90\x86\x90\xf7>\xbe\x7fu|q:~s\xfc\xa7\xb3\x8f\x17-\x8a\x82\xfaQ+\x88\x00\x9e\xa0R\xb9\xa7S\xc2\xc6\xde~|\xfd\xe6\xe2\xb4M\x91\\\xefM\x08\xde\x9b\xf5v\xfe\xd3\xd9\xcf-\x9dX\n\xca^>Oo\x13\x9b\x0e\xa9\xa3b]j\xed\xabO\x8ay\x9c\\\xbb\x1c\xe0\x94\x16\x1f\xdb\x95\x87T\xd5\xc8\xdf\xf8\xd8;\x1ev\x1c\x0e\x19\xe1\xd8\xd8\n\x07 \xf5\xb7g\xafN7\x06\x07\xce\x8d\x06GUi\x99N\x99c\xfa\x18\xea\xdc\x1fy\xbcJ\xee]\xaa\xfb\xab\x84\x0f5\x13\xb1C\xd0\xc6\xd9\xabO#\xfd\xad\x1c\xa5|\xd9\xce\xd7\xcbe\x94\xdd\xe1\x94o\xe7\x91\xc8\x0f\xc4\x7f\xc4\xf99_U\x11\x86}\x9de,)~D<\xd5\xdf\xb8\x98-u\xec<\xdd\xfbUO\x1d\x82\x95\x13de`Z\x97\xe5\x92\xda\xe8T\xa5\x9aS\x07\xf6\xe8Z#\x13\xda\xf2\x86\x04\xb4\xba\xb6&\xc9\x80S\xdd\xb50\xd6\xa5 {\xb4\xd6\x8brw'i\xb6\x8c\x16\xf1_\x19\xba{\x05\xd2\xfe\x1d\xfb\xd6wp\xae\xef\xe0\x00\xcb\xeb\xaf\xf9w 9\xcc\x1a\x0eu\xda\x8d\xa5\xdd\xab.\xa0\xd7SX\xe9\xa6\xb1pT\xff\xe9\x8e\x9e\xd3>kj\xef\x1a\xea\xe5\"0\xa6jo\x1bA\x94\xbaK\x06\xb6\xfc\xdb\x81\x1d\xdfBf\xc3c\xd3\xb8Hk\x18\xd2\x89\x94T\xf2\xcf\xdeAG\xd7/N\xa5\x8c\xa1\xd0jt9\xc0\x14\xf3\xe6d~\x12\x8c\xfa\x97!$\xa3\xc1%zc\xfa&EoTm\xab\xbb!\xd6\x13\xcd\xda\xc2\xa90\x14\xd7\x90#\x16\xfec\xd2\xc8Y\xa4\x0e\xac\xf7\xf8]\xfd\xaf\xce\xb0zb\xd2\x0c\xa9\x96x\x16\xf8^\\\xb0,\xc2\xa5\xb0\xc9\x9b\xe1K\xd9\x06o\xc7\x8a\x9b\xa1\xf4\xfd\xac\x87\x0dk\xc9\xc71{\xdaa\x8d\x9f\xddp\x8a\x8dsI\x8d\xb0\"\xf6\xfa\xab\xe5\x1a=\xb9\x1ce\x97f\xfe\xbdX.b\x93\xa4\x06\xaa\x1f#*Q(\xa1\xc8)NM^\xa5\x1a\x108\xb1[oA\x83 \xedx\xd3\xd9r_\xc4AB?\xe6*\x84\x93\x19oE\x913\xf3=\xbdi4\xc0\xd1R!?\xccb\x02\xa6X\x86Y\x97\xda\xa0\nMr\xb0z\xa6i\xc2\x86b\xdc\x9d\x83^\x878\xb0\x0d\xba\x8f\xa86\x98\x1f;\x08\x03\xeb\xe0\x1e\xd5\x05\xcb\x7f\x05\xfe\xe9\x97VE\xe4xk\xea^\xbe\xdb,Z\x1d+\xfdBC\xee\xe8\x7fH\x85\xc5\xde\xaf\xcb:.Paa\x99\x94\xaf\xcb\xa2\x81Y\x94\xcb\xa2\xbd\xfd\x03Z\x97AD_\xfd\xa7.\xe3\x97\xde\x97$:\xadHw\x81X\x95\xec\x99%\x91,yj\x954i),!c!\x9b\xd9\xb3\xba\x9eH\xb5\xc6\xc0x?\x93\xefwI\x84j\x08S\xfaK\xd8\xb9\xd4\xf4,\x99\xa6g\xd1\xac\x0f\xb3\x10fJ\x06?\x7f\x7fz\xd2M\xefQ\xe6G\xd0\xa2\")\x81\x1b\xa3\xe9\xa2Z\x04-Ru\xa5\x08\xe8\xa3V\n\x01\xc7`>~x\xd3m,\xb2\xb3u\xb6\xd0\xfb\"\xc4\xf6\x86\xce\xfep~\xf6n\xa3\xde\xfe\x92\xa7\xa6\xb4u\x96MY\xc6\xa6\x9a\xee%\xe8\xdc\xff\x87\xd3\xf3\xb37\x7f<}\xb5\xc1\x18P\xf8\xc9X\x9e.n\xd8\xd4\xbb|\xf8\xb1\x8c\xcf?\xfep\xf1\xe1tc\xad\x0c\xad\x8fI\x84\x13\xbd]\x98J\x13\xdab\xde\xa2\xa4Qs=__\x15\x193e>]\xad\x14\x04\x0ehd\xdd\xa1\xf0\xfe\xf8\xc3\xf1\xdb\x87\x9a:\x9f\x9d{\xe6Y\xb4|\x17- \xd0\xc4U\x85\xd7\x84\xd6o]\x15\xdb\x85y\x13\xcc1\x9cg/\xce\xff\xe7\x92\x88 7!tB\xea\xbd\xf0T\xe6\xe7\xcf\xfc$\x9d\"\xd1\xda\x8a\x05g\x0dG\xb0\x16\xaa\x88$Z2\xa17\xeby\xb0\xad\xde\xc6\x89|\xc7?\xde\x11\x05\xaa\x1d\x1f\xf3\xf7\x97_\xc4\xf61\xca\xe9\xea\x02\x8e\xc0\xc3\x19\x8d?/\x17\x1e\x0c\xe5/Z\x7f\xa0i\xf7\x18\xe6\xf3F\xeb$7\xd6dA\x08#\x0f\xa1\xc9\n\x86Wv\x93\x10f\x97A\x08yg\xac9}\xfb\xfe\xe2O\x02w\xc6\xaf\xdf\x9d\xbc\xf9x\xfe\xba\x95\xb0l\x84EoY1O\x89\x1a\x0f\x83Kq2Y\xac\xa7\xect\xb9*\xee\xfe\xc8Ak\xf3-\xc2\x1cx+.y\x1ee\xc2v\x1be\x89\xef\xfd\x1ce \x06\x1el\x02\x08L\xd0\xe4\"I\x0b\xb8f \x17^\x19D\x80c\xfb\x1f\xec\xae\x87\x16d6\n\xe4\x18\x1d\xd7\x81#\x0f\xb3\xe8c\x04@\xce\xd9g/\x84\x9c\xaf\xfd\xba}\xed\xffx\xfc\xe6uE3\xce\x7f\xbd\xe5\x8e\xf3\xb3\xe3\xf3=z\xad5\x05YGH\x04\x84\xfa\x9f0\"\xe7\xb4\xe3\xd1\xe7\xe5\xe2Q\xdc+X^\xf8\xb1\xd8\xde\x1c\x0d\xd6K\x96\x8f\xc5\x96\xa4\xbe\xe4{x\xd2\xe3\x9ca\xc4\xa1\xf3s\x8c\xf3\x8bd\xcc\x10ArB\x18\xb1\x86!6\xdfcl4]c\xb7_R\xd3\xefx\xfb1S\xd6\x8f\x1a\xed\x10m\x95\x8e\x15\x94\x01\x95K\xecV\x18\"\x8e\xb0\x9bh\x11\xf3\xc9\xbd\xe7\xad\xa3\x91\xfb\"\x84\xb4\x835\x18\x87FAR\xe4\xa2\xa2\xc8!(\x0b\x85Ks\xfe\xa4\xd1\x93\x1d\x15\xa5}\x7f\x08\x93\xfco\xdc%\xdavx(\x1cH\xdaq`t\xd9\x15\x07\xbaX\x03\x81\xc5F\xd6\xacCj\xdd\x12\xb0\xdf\x18\xf0\xe7\xa7\x17\x9c\x9b{\x7f\xf6\xee\xfc\xc1\xb8\xb8\xcc\x8c\x07\x035\x1e\xce.\xc3k\x9d\xde\xd2A\xc8\xd6\x0ef\xc3_\xa3\x13\x1d\xc2\x07\x8e\xc0\xd0\xea\xdb\xa0\x15\xd6\xd2dP,\x8e\xfcC\xd1V/!\xcf\xc6\xd2\x90_T\x92? \x9e\xaa\x88\x8au\xce\x19\x16U\xb5zS_\x9bP\x96g,_\xa5I\x8eY\x02\xb2\xa07g\xd1\x94\xa19\xd2\xba\xfc\xfb\xcb\x17K?\xc0\x17c\x824\\\xe3}\xb1\x1d\x8e*i\x08\x91\x8b\xdd_;(\xe4B\xc1\xae\xf7\xc3\"\xbd\x12\xda\x97iTDzPm\xbb\x8e?A\x8a\xed\x1aD\x08^\xc1>\x17\x9cr\x88\xd6\xf8\x112\xe9\x88\x95\xff\xf1\xf1\xf4\xbc\xedJ\x7f\x03\xa4\xfc\xaf\xcd\x902\xd6\x90\xb2U\xec\xf8\xaf5\xcb\x0b9\xe9\xd8\x05\xf9.\xa2\x05\x9f\xf9\xdb\x8f\x17\xc7\x17\xa7\xaf\xfe\x91 \xb0\\\x17Q\xc1\xa6\x1f\x1e\x0e\x10\x929<{\x7f\xfa\xe1\xf8\xe2\xf5\xd9\xbb\xf1\xdb\xd3\x8bc~B||0:\xd5$r9\xa4\"\x01\x92O\xec\x8e\x96\xa6F\xad,\x85\x83[\xeaz\x1eYN\xa0\xe5J(V\x0e\xb5\x0e\xae\xcf\xf3 \x080{dY\xbd\xd2\x0el\xfcI\xab\x90\x8d\x9f\x1eUX\xe2\xaa\xb7\xe0\x87ll\x9f\xaci\xd0M\x1b$\x98\x87\x87>\xc5\x9a\xb0\xa3qOL\xd9\x82I&C'\x87Y\x08\xe9e;\xde\xab\xc9<\xe8\xd6\x7f\x98\xb9\x94{\xbb\xe3T8-;?\xf9\xe9\xf4\xed\x83\xadI>\x993\xeat\xfe&*\x96\xf2s,\xd6\x11\xd5\x13\xfdTT,\x13\xca\x87/_\xb0\x9e\xbc\xb6\x1dR\x1fxc \x83s\xf1\xe6\xb2\x9e\x97$(\x7fv\xbe\xbf\xdd\xa3c\x99=\xdb'4\xdd\xf2\xb67_\xb1I\xccr\xaf\x8b\x1d\x00\xb9\x16!\xb2d\x99\xcf\xd0_?/\xb2\xf5\xa4H3\x12zZ*\xa8HK\x0f\x7fx\x08~\x82mD\x01\xdf\xdb\x98\xdbh\x08\xa9n+\xd0\xe9*\xe1\xa6\x16\x87\x15\xe7\xb8\xff\x8cV\xd8\xef\x99 \x91\x86\x85\xfb\x94\xce>\xf1\x07V\x948\xa9\xb1\xa7\x14\xf6\x93\xde*K',78\xdbU\xc9\xfd\x94\x89\xf6k\xe5S,\xafg\xc0\xaf\xd7\x98c\x8d\xb7\x82\x9f<\x99GI\xc2\x0c\x85\xdb\x0d\xd6x\x15\xe7\xab\xa80\xc35/1\x1di\xed\xd55\x11\x80\xee\xae\xed*\xf7F\xa67\xd8\xb6\xc3_\x83\xd4\xea\\\x1bWJ>s\xe6\xbeW\x97Z\xd7V(R\xf5\x08\xba\x82\x15B(|B\x92\xa9\xbd1\xa6s\xd5h\\\xc1\x1fu\xe1%x\xcez[\xd5\x88V|\xe7O1\xc6\xc1\xaa\xb1\xc9*G\xba\x8c\xd6\xcaQ{\xf0\x9c2lJ\xaa\xe8\xaa\x95\x11S\xb2\xbd\xed\xb8g\xbb\x1emo/[o\xda\xd7\x8e$\x1a\xf2\x06\xe8\xc7j\xe0\xa1\x15\xae:\x84\xcc_\x06!,\xbf\xd3^5\xc7\x86\xd7VG\xff\xc8\x93[\x00\x87\x90\xf8\xcf\xf6\x02\x7f\x16\xe0\xb5l#\xec\xd0\x94\xe1\"\x9e|\xf2#\xff\x0e\xe3\x94\x0ct\xfe\x0f\x86p\x83\xc6`\xbd$\xbdmm\x0dk9\x1b\xc2\xd0\xc2\xb12\x19N\xd8-\xcc\x83\x1e'{\xbb\xfct\xe2\x7f\x0czi\"\x8578\x84\xab\x10\xbb\x8b\xfc\xb8\xb7J\xf3B\xeeB$5\x03d>&\xbdh:=\xbdaI\xf1&\xce\x0b\x96\xb0\x0c\\\x01\x0b\xb5\x06P\xdb=\xe9\xc5K\xde\xe39\x86S\xcdU\xd0c\xf7\xd4&\xfa\x18|tt\xe3\x07\xca\xef\xea\xa6\x87\xf6\x88t\xa7\xa1\xab\x10\xb6\xc4\xc8y_^\x9ad,\x9a\xde\xa1\x1d\xc2d\x1e%\xd7\xcc\x838\x81\x85\xef\x89 \xaf\x1e_>\xf7\x88\xf2^\xb4Z\xb1dz2\x8f\x17S_\xfb*\xe8\xd9-\xb7\xe1p\xde\xcb\xd82\xbda\xa21\x91 \xa7\xdc\xa7\x06\xce\xd6\x16\xb5a|\xac\xb8\x88\x97,]\x17\x1aF\x84\xd0\xaf\x1f\xb8\xfa\xd1g}?\x84\x95q\x06pZ=\x84i\xd5\x04\xfe\xf5\xedq2\x1bM\xebh:\xea\x08\xc2\xcd\x9f\x9b!\xb0v\xb2\xd9\x18\xc9\xb5\xb5kBQ\x02\xb2\xeb\xb6\x8e[\xa0\xb7)\xb3\xb3\xfb\x94dvv\xfb\x8f\xef\xc3\xe2`\xb2\x10\xa4\x95\xa9_\x88|\x1b:\x9b#\xed\xedJK\x08[\xf1\x82\x91\xa2{3;\xa5\x98\xf8\x82\xf3\xc2\xa8\x05\xe3b\x92\xb4\xa4\xe5\xec\xc32\xce7\x8cs[\x8fu\xffd\xef[\x02\xda\x17\xba\xe5\xc0!l\xb9\xcc\xb9w\xfb\xbf\xa4Q\x8e>\x1eY\xa7\x8b\xa5d+\xf3\"\x9c%\x1d\xa1\xc5]\xa8\x8f\x89\xe1\xd40j\x8aw2\x9a\x13\xd8\xe3\x81\xccOC\x88\\\xb5\xa112\x85zn\xa4\xb3}1J/\xfd\x88\xd0\x10\x98\x8f\xd0\x0e\xa2\x8a\xc2Y\xb7=\x8a\xb3ztF\x9e\x0c$\xa3\x1e\xdb\xe0K=x\xeb\xb7\xeeM\xd3\xa4\xda7%`\xd5N\xf0\xf3\x00c\xfav\xd0\x80\xab'\xf3=\xce\x15\xcb\xc8\x1b\x89\x88\xd7 \xd2'\\\xb6exq\x918\xc2^\nM\xc0\xb7R_\x84\xc9\x8e\xe5\xff\x98\x0d\x87\x8b\xdb\x9b\xa1Q5\xe9\xc1>}\xca>1\xe5j\xa9R\xd83St\xca\xfc\x15\xe6\xa1,\xc4\xf0\xa7\xfd.g2\xba\x1f\xe4\xd4\xc9\xbc\x15\xa1d\xa9TP\xf5\x8dX\nb\\\x84\xdf\x19\x84(\xb2\xa3\xa7|\x8aQ\xe2\x82@Jb\xa1\x90\xdaa\x07\x06!J\xe9\xecy\x99o\x12\xc5\xbe\xed\xed\x05\xbc\x80\xc9s\xd7\x81\xc2%\xa4\xb5_\x8c\x16\x97\x0e\x82\xcc\x05w\xc2y\x81O\x01{\x995I\xc7\\\xa6_\x8d\xa6\x0e\xe9XO\xaf\xcd\xbb\xe1\xc2C\xee\xdf\x840\x0da\xc5\x99{QA\x98r\xceQ\x80\xb9\xe1\x9c\xfc\x0d\x0c!\xe6c\xc6@\x17\xfc\xcd\xe8\x92\x9f\xceT\xf8!\xebM\xe6\xaf\xb0\x83y \x00\xc6\x87\xf7\x9d\xfb\x13\xb5>\xf7E\xc2\xbd\xfdN\xbc\x1bq\x14{\xe31\x9a\xb9\x8e\xc7b\xaf\xe0\x9e\xe0\x8c\x88\xfc\xc0\x86z{V\x9cZ\x12\x19\xa2\\Z\xa1\x12V1Zb\x1a\xc3\xbf\x01\x95\xd7\xa3\x82\x0b\xf7\x1b\x9a\xb5k\xf4\xc9\xe4\xc5\xd261\xab9\x10\x16C\x95\x9c0\xc4\x0d\xc1\xab\x9b\xe2\xb6\xc5\x8f\xc10\x94\\&E\xb3\x07B\x06p\x9b\xf7\x7f\xf5\x1d\x8b\x9dv\x81\xc7/lN\x1cBQ7\xa1\xc8Q\x17\xcd>\xb3\xc9\xba`\xf2N\x0b_ \xfb\x81?\xe4ir\xbeb\x13\xed\x95\xfc\xe9\nJ\x11\xfb\x89\xbfO\x862\xe7%\x83=\x87\xa3<\x91\xecX\xad\xc5/c\x0b\\\x9bL\xa3\x0cU\xa9\xec\xf3\x15\x9bH\x07\x05R\x1aj\xc4VfX\xf6TL{(L\xd1rv\x91rx\xcbz\x89^\xc55\xa1\x90Z\xa9_c655\xa1\xa9\x1b\x0c+\xc71\x14 #\xcc\xe5\x04\x11\xbc\x80\xe29D\xdb\xdb\x01\xc4\xa3\xe8\xb2\x96&$\"\x0e\x08\x13d1\x82*N\x14\x06\x7f\xa8_\xcf\x9dD\x939\xa3\\\x8c\x94\xd4\x11\x8f\xfa\x0e\x07\xa5\xdc\x0eP\xbf\x0e\xab;\xce\x80\xb2K\xe0\x8f_\x8f\xb9I\xe5\xacq\xf2\xe9F\x7f9\x1a{\x05\xbd\x7f\xc9\xd8\x8c\xa3<\xdeb\xf3\xedh\xcc\xd2W\xa3\n\x81]n\xc2\x80\x87\xd4F\x7fh\\!\xcd\xb8\x94\x0c\xda[\xa4\xd7\xb2k\xe1\xb6\xea\x9b\x1a\xdc\xfah-J\xb5\xc1h\xcb\xb0\x8c\xf7\x1f/\xc3`\xc7\xd2\xae\xd0\x8aRcP\x95\xbf?]\xef\xa2c\xb8\xd1c\xbd\x9d\xa4\xcbU\x9a`VJ\x0b\x04e\x94\xb6\xf3\"\xcd\x1c\xd6\x01Z\xa0b\xbb\x02\xde\xaa\xd5z\xb1\xeb\x08\xab\xa6\x8c%S\x96\xd9\xa5\xb9\x0c\x1c\xfe\x89\xbd\x8dV+6=I\x93\"\x8a\x13\xaa\xea\xa2\xdc\xbeK\xb6L\xe3\xbf\xb2\xc0\x8fDvr\x91>:F\x1e\xdcJ\xa2\xe5T\x0bfiZ\xbcN\xf8\xda8\x9d\xd9\xf4\x99\x0d\x810\x1c\xe7\x0f1\xf8\xa19\xd0\xdc\x1e\xe8\x02\xc7J7)\xa05\x84\xb5\xfdYd\xdd\x88\x80\xc5\xcb\xba=\xd5Z/\x9a6r\xf6\x02\x0d\xd9(\xc2\xd9\xe2\xf4\x05\xbf\xa8\xe3\x17Tk\xeft\xfe\x02d\xe58\xf3\xfe\x94bf\xd0=\xea7\xb2\xf1uTD\xfa'p\x04\xff$0\xb0\x81y\xbb\xe6\xcc\xdbcj\xbe\xd7$[\x17\xcb\x12\xda\xe5\x0cK\xac\xd6\xd6\xaa5\xca\x01\x11?1\x0b\x16\xb2\xc0\xead\"\x0b\xac>f\xb2\xe0\xc0,X\xe1\xd2\x99\x97\xe4S\xac\xbe2\xde\xcee#O\x9eXC\xbd\x11\xe2\xffc\xf3\xfa|)?y\xfa\xf8\x19\xcd\xe6^\xff\xbal._W+\x1d\xb4C\xe5k\x13\x81\x06\xa3l \x8eR\xa7\"Y=\x9a&\xb9\xad*\xd4\xaf\x18\xf2\x8aM\x12\x1a\xefL\xda\xe1L\xcc\x02?\xeb\x952\xb3\x8a\xe8\xbf\xae\x19\x9594\xe7n\x0d)\x90:\x04\xfd\xd1F:\xab\x19\x06%r\x98\x8b\xda\xdbQ\xfb\xdc?\xb1\xbb!xb\x1f{\xf4A\xa0?\x9224r\xec\xd4#\x07>-\xf5\xd7\"\xee\xc7\xa9Hl\xcf\xe9\x91a\xbf\xf67\xf4u\x0fdn\xf3U\x96\xaer\xf9\xf7$M\n\xf6\xb9h\x81#\xb4\xc2\xf2\xebe\x10\x12\xe1\xd8\xcbb\x7f\xd5+\x89\x9dK9\x8d\x98KC-\x95\x9c\xc2\x0d\x1fp\xc2&\x85\x16\xdb\xa4-\x80\xeb\x8dL\x8eo\x9a_\x7fE31\xe6S\xd1'\xd5\xa3PD?\xbe\x96\xd1\ns\xd0_\xa4\xfc\x04@\xdb\xe7v\xa9\xc1h\xb0}\x9d\xf1\xde\x9a\xba\xc7\xd4\x1f\xf7\x9a|\x0d\xfc\xa4\x8c\xf1D\x146d\xf6Ij7\xee\x0d\xd4d#J\xb2\x01\x15\xf9\xadP\x107t\x1f\x96rl@5\xeeC1Z\xa8\xc5M\xef}\x96\xde\xc4\x9c\x97\xef\xd0\x18 j\xa6Y+j\x82\xe0\xb16\xa3Qn\xf2t_:\xdf@\x97Zh\xd2W\xb1\x81`h$\x0ci\xb4\xf4j\x8c(]r\xc6)\xe7\x8c\x1b=\xa7by\xd9JS&\xd2\xba'\x1670\xc9(\xbd\x0c!\xc3\x7f\x19\x99\x88\xa6i6c\xbc\xacp\xb0\x9f\xc44\x85\xcdc\x830\xde,\xb1C\x9d0\xb8x\x1c\xf58(\x82\x9b|\xeb\xa4\xff>\x14C\xa4\xac\xc5\xda8\xb6\xf6\x93\xe2\x8a\x03'\x12Z~\x8c\xb2G\xa3^\x13=\xb5\xa9J\xb1)U\x11\x14e\xa2\x90\xfb\xe7x\xb1\xf8\xc0&,\xbeA\xa1%o 2&\x81id%\xf9\xa3M\xb8\xda\xbd\x9b\xd2\xd4\xafM\xa4\xa7#y\xdc\x944\xaa\xcb\x06\x0e\xd8e\x1d7\x14 \x8a\xa4\xd3\x96\xa6\xee\x8b8A\x18\xb9n\xdc\xf4\xa7@a#\x0e\xc1\xcb\xd2\xb4p\xdd\\\xa8\xa7\x9d\xa5\xdb\xd8\xec\xc1A\xfa\x1a\xc8\xde\xd7P\x97B\xc9\xedn\xc5c\x03\x8db\xa9\xaaY\x08\xde\xf1j\xe55\xcc}\xde\xabl/x\x7f\xbek\xe6q\x88\xb7\xa2\x81\xc5\xcc\xb4\x1aUTJ\xb3$Z\x12z\x8e\x16\x90{\xd3\xf8\xc6\x92\xe5\xd5\x93\x17w\x0b\xd6\x14\x14i\x15M\xa7\xe8B\xee\x0d\xd8\xb2\x01k'\xe9\"\xcd\x86\xe0\xfd\xff\xa2(r\xe4\xbd\xb3W0\x04\xef\xff\xf9\xdf\xff\xb7\xff\x03<\xf7\xf9\xea\xc5\x9e\x00\\\x08\xdeI\xe9\xa8.\xd7\x96/\x0c\xe6\xbf>\x84\x02\x8e\xc0\xe38\x0f%\xb5\xf0`\xc8\x17\xd1\x0b!g\x0c\x8a9+\xbd\xe3=+\xe4w}b\xb7\xad\xca(\xb5&\xdd\x18f\xb9B[>\xab\xd8o!oW\xdcx\x9c\x7f`\xd1\xa4h\x17.\x9a\x0dI\xf5\xa7\xf3\xd1\xa5\x9e\xf2\x08k\xa7:\xd0\xc2\xdf&N\xfe6i<\xad\x92{\xf0\xb7\xd0*\xd5\xd1'RB\x9eHI+\x9f\x0b\xdd\x89\xb9z6%\xea\xea\xa9\xae\x02:\x9cI\xea\xe9 \xe1&n\x1a\xdcI\xc2\xc5\x1bwz\xda\xd2\xbd\xa8Dl\x01\xa3\x06\x0d\xa8Y\xb5\xed\xde\x1dZM\xfdJ\x06\x95\x91\xb7\x83Yy;\x88\x96\xa9\xe2v0\x85\x17\xc0\x9eC\xba\xbd\x1d \xd7Y\xbb\x1dt1\xb0\xa0\xdf.\xe9h\x9b9 \xd7\xc9TP\xb6XOG\xc5\x87\xea\"\x92\xe36\x89G:d;VL=\xc27\xbb\xc0c\xc6\x8d\x1f\x8e\x99Q\xd4\xddPgW0\xb4\x94\xc6\xf6\x19\x9d\x86\x10\x9b@\x8ag\xe0\x97\xc6[U\xe2\xbf4\x90A+\x13v\x0b\x17w+v*\x12x\xbdcl\n\x11\x88\x0fB(R\x981\x0e\xfd\xa8:#z\xf0s\x94\xc3u|\xc3\x12\x880\xd5\x8d\xaf\x99\x04\xa5\xfcPY'BM>\xe5\xe7\x89q\xe1\x9aZA08\xd6 \xa3-3*\x84\\U\xce\x8b\xc5\xbc]\xe4(\xb0\x1b\xfe\xf3N\xb1\x9f>\xfa\x14\xe0\xcf[?\xc2\x1f\xb7\x82[\xf3\x99\x1f\xf4\x16\xe9\xb5\x0c\xeeR\x9d\x86\xb38\x99j\xc7\x1e\xe70$\xb3Q\x0e\xa0\xd3%\xa1\xdb|_Nx\x08\x89\xff\xe4\x89i\xc8W\xe9\x8c\xeb\x97\x03]\xba\xa4\xaf'\xdc\x03\x99G9^\xb3\x0bG\x89w\xe9\x94\xe5C\x18\xddX\x12\xc2:\x04\xe1V\xa4\x90\xd5w\x10T4\xdb\x16\xb1\x93\x1c'\x838\x94\xd7x\n$x\np\xc4Jz\xf2,\x80\xa1\x8a_\x87\xb1\x89\x9d:\xee\x05\xca\x11\x92\xfd\xec)\xa4\xc6hl[\xfd\xc6\x03\xd0\x81\x8e\x8dwR4,\x0b\xa1U\xd1\x1b4\xb8@\xd26[g\xd0\x84\x1b\xec7\xf1\\\xf5Q\xcbKC\x93\xceO\xd1b\x8cz[\xc4K\xa2\xc4SE;\x8bt\x12-<\xbb\x06[F\xf1\xc2~\xbdL\x93bn\xbfN\xd6\xcb+F\x8ck\x15\xe5\xf9m\x9aM\xed\x92\x8c\xef\x07\xfbu\xce\xa2lBtP0b0\x9c\xef'\xde\x923^gD\x03\xb7\x8c}\xaak`\xdb\x94tN.W\\N*v\xb6\xfe\xab\xce\xb5\x92\xac\xae\xce\xe5\x16p\x04[[\xd9Hp\xce\x98b\x8e\xcf4\xcaX$+T\xe3}p\xfc\x12\xa9\x03\xcf'\\\x8c|\xc3f\xc5\xd0\x0c\xe1U\xabq\x91\xae\xac\n\x19\x9be,\x9f\x8b\n\xb8m\xf3\xb6}\x98\xf5\xac~Q:\xf8\x1c\x9aE\x17)\xfaK\xf7\xeejm\xb4\xee\xc3\xec\xdb\xe1\xe4R\x83\xfa\x83\xc7\xa6u\xbatM\xb7B\xc1E]\xd4W\x9c\x82\xb7\x86\xd6f\xbdY\x9c\xe5\x05\xaa\xf4\xddZ\x1b\x94\x9f\x12\x112\x06\xd3ic}\xferO\x8aS\x1cC/\xeeV\xd5\x89s\x93\xc6S_\xbc\xc7\xa5\x83\xc3v\x0f\x15@`k\xeaX\x8bU\xd2V\xc5T\xfbvW\xf9r\xae\xba\x15\x82{\"a]918\xe2\xc4]\x04\xd3AMy}j\x15\xde\x04F0\xa6o\xa0\xdc\xdd(\x07}\x1f\xcbz\xb3t\xb2\xce\xcds\x86v^~\xf0\xdd\x1f%\xf1\x12c\xdb\xbf.d\x90\xfb\x93t\x9d\x104\xf6*\xcd\xa6,{\xbd\x8c\xae\xd9\xd9\xba@\x06\xbf\xa1\xca\xf9\"\x9e\x10$Y\xab\xf1s<\xa5\x8e\x95\xab\xf4\xf3\x8f\x0b\xf6\xd9Y\xf0\xfb,]\xaf\xc8\xd2\xb3l\x1a'\xd1\xc2Qa\x92.\xd6K\xd7\xdcDan\x17\xcc\xc8\xa1\xcc\xc48n\xe9\x92\xf7i\x1e\x17\xf1\x0d1{^z>\xcf\xe2\xe4\x13]\xf6\x8e]G\xee/1\\\xb1]t\x9d\xc5\xd3\x0f\xd4Xd\xc1iB\x1c\xc5\xb2\xec|\x15%\xee\xc2\"\xca\x08X\xf1\xd2\x13\x84WS\x99\xb3WQ\xec\xeeX\x96\xd3}\xcf\xd2\xa4\xf8\x99\xc5\xd7s\xa2l\x11'\xecd\x11-\x89\xb5\xe7E?9>KW\xd1$.\xee\x88\x02\x1a\xdci\xb6\x9aG\x14\xaa\x14\xd1\xd5y\xfcWb\xedn\xe3izK|\xf0\xd7\xd7\xc9\x94\xc2\xae\xbf\xa6\xe9\x92\x98z\xbcX\x9c\xb9\xc6:[\xa4\xe9\xd4Y\xca\xb9\xd9\x86\xc2,\xfd\xc4^E\xf9<\xca\xb2\xa8\xb1B:\x9b\x91\xdb^\xd4x\x1b\x17,[\xc4\xcb\xd8Y\xa3e\x0c%A(\xcb\xbe\xda\x17p#\xefgv\xf5).\xbc\x10\xbce\xce\xff}\x9b\xfe\x95\xffw\xe6i\x9a\x1e\xa9\x89\xf9\xc4\xeer?\xeb\xe2\xee\x9d\xdauh\xa7\xe3Q\xeba\x0e\x9a:\x11\x13WL\xe6Qv\\\xf8\xfd\xa0W\xa4\x1f\xb90+5\x99\xbc,__ \xc3\x0b\x7f@\xd9\xa4\xa3!\xe8%gf\xf4\xd0\x97X\xa6\xa98\x8d{\xca\xd8\xa2\xf1q\xfe1\x89\x8b\x05\xcb\xf3w\x92i7\xdcs\xf3y\x9a\x15\xf3(\x99*\xad\xd5\xe9\xe7U\x94\xe4\"'\xa3=\xc5\xabh\xf2\xe9:K\xd7|\x8f\xd3\x00\xa8j\x1c\x17E4\x99/\x19Ev\xed\xda'\xb4\xaccW\xc4#\xa4KEA\x8d\xd3\xe4\x7fnR\xf9O]*\x7f`+\x16\x15C*\x8d)\xa1:\xb1;i\x87\xdd\xfd\xc7\xdeiD\x92\xc29F\x81\xa5\x8eC\xba^\xe9\\\x98\xc76W*W\xb6\xfb\xd0~H\x8b\x82\x93\xc2\xa6\x01\x8a:\x9d\x86)\xaav\x1a\xac\xa8z\x8f!\x0b\xf1\xa9i\xc0\xbcF\xa7\xe1\xf2\x8a\x9d\x06\xcb+\xdec\xa8\x1f\xc4y\xd84V\xac\xd2i\xb0X\xb3\xd3h\xb1\xe6=\x86\x8bbg\xd3`/\xd2U\xa7\xa1^\xa4\xabN\x03\xbdHW\x1b\x0d\x93\xf3&\xae\x11\xf2\xb2\x96Ny\x95?FY\x1c5\x11\xca&\xfeG\xafC3\"\xeaib\x87\xd4\xc3[\xf91Z\xc6\x8b\xbb\xae\xf3O\xd7\x05o\xd8\x05\x02Y\xdc\xb2D\xb2V\x0b\xacd\xad\x86\xe5\xf9\x8e\xfe\xe5P\x15\xc4\xf8\xf6\x9b\x84\xaa\xc4\x7fj\x06\xe3K\x85a\xd0`\x1f\xe3\x02\xee\x89\xf0\x80O\xfb\x96\x83\xbc4 \xc2rv\x0b\x1f\xd8\xf5\xe9\xe7\x95\xef\xfd\xe7\xc8\x83m\xc8z\xc7\x17\x17\x1f^\xff\xf0\xf1\xe2t\xfc\xee\xf8\xed\xe9\xf8\xfc\xe2\xf8\xc3\xc5\xf8\xe4\xa7\xe3\x0f\xb0\x0d\xde%]\xa9,\xfe\xdd\xbfXi\xcd\"\"\x1e\xfbZ\x06\x80(_\x96w\xa5\xb9\xf3\xaetkkmG`\xc7\x00\x81\x11\xf1\x9e\xcb\xfd2\xfb\x1a\x1a\xb4\xf9\xeb\x11\xbb\xc4\xb0\xaf\xa8\xdd\x85!\xf8\x91\xf6\xa6\x16H\x9bNs\xdc\xc5\x9e\x10\xf3\x84\xcc\xa3\xfc\x874]\xb0(\x11:\x80\xef\xbf\x87\xad\xaa\xe8\xddz\xc9\xb2xR\x16\xc5\xf9\xbb\xe8\x1dg\xfeT\x05%\xce\x99\x15\x0bx\x01\x83\xb2\xd6\xd9\x0d\xcb\x16i4eS\xab\xaf\x01\xa9\xc0\x03\x89<\x13[\x1f\x87V\xcbo\xa3\xec\xd3z\xf5c\x9a\xbd~\xd5\xaaJ\x13\xd3\xcez\xaf_\x8d\xeb\x88\xc0q\xe0\x90cHj\x85\xb4\xae#@\xce\x8a\xe3\xa2\xc8\xe2\xabu\xc1\xac>\x1d\x8c.f\x9b(\xbf\xf2\x89\xee\x89\xe0\xefM3\xfd\x90\xa6m\xd7\x95\xe5T?\x9c\x9d]\xd8\x93\xfd\xb7C\xcf\xfb\xb7\x0d\xe6i\xf4HB\xd7\x9a&\xd1uXK\xdcK\xf4k\xccT\xed\x8c\x0ePV\xea?\xbc\xfc\xe6\x1f\xc5,'\xf6\xd7Q\xad\xc2\x08U\xc8\xb4Q\x15j ]\x82\x0bF\x8b\x14.\x1f\xa5~\xd0\xf3huc\xe9\x07\xd6\x8b\x14tl\xb3\x0e\xf5\x94\xf6\xff\xe6n\xfc\xf2E\xbcl\xd8@\xfdRE\x1e\xab5\x86!\xfe\xad\x90\xbb\x93\xbe\xb2\xc4\x9d8?Y\xe7E\xba\xac\x16\x15\x01X\x91\x0d\xbc\xc1\x1a\xa2\xf8V\xf5 \x01\xba\xc1*\x1b\xbdtXl9\xc4\\RL\x15{\xa7\xc00#\xc6`<\xaf\x05\xd1\x11\x80ndk\x880\x92\xb6\xe0[a\xe1[\xd1\x8co\xa4\x1f!h8\x94\xf60cW\x9c&T\xbeD\xf5\xf0\xa6\xe2@hw]\x06~l\x913GgP\"x\x8a\xee\xbd\xba\x02\\\x98}\x89\xabb\x13pb\xb9\xe8\xeeT\x9b|\x02y\xf11/\xed>\xd0$Q\x81\xe8\x8eo\x8cK:@\xabzZ\x06\x0e\x9a\xbdQZ\xdfq4\x93\xa4?k\xfb\xa3|\x15M\x1c{\xb5\xfa\xea\xc8\xa0~\xef\xce\xfd\xb5\xc8\xa2\x877\xbc\xe8.O\xed\xe8\xb4\xd3\x8eN\xac\xf6}l:P\xa9\x8c\x8c\xf7\xd8\xa5s\xc4\x8e+|\x9b0\x08Hc\xd0}\x82\x14\x14\x06^Lz\xdaV\xd2(\x86\xdcA\x1d\xf7\xa0\x8b\x0886a.\xf3\x00\xf8\x8a& P\x89\x84\x15\xfaXmH\x15%\xa4\x1a\xc7V\xc7\xf4Mh\x145\x8c\xee==\xf0\xc9\xb71%r\x9e|\xa5\x85\x7fgJ\x94\x06\x9c\xad\nU\xf0\xe3\x06r\x84\x1d\xdb\x04\xc2\xbd\xd9\xab\xa3U' \xee\xddj\x1f\xabG\xc0F1\xb2\xd3\x03\x0c\xfb\x8b\x7f{\x0e\x9fc1J{a\x8d\x93\x9d8d\xc5\x97\xf4>\x12\x17\xe2m\xc8R\xfer\xc8f\"9\xe77\xcaf\x03*lq\xe2\xef\x0e\x1c\x11\xc6\xcdp\xeb2\xcf\x97\xd9\xca\xba\x92\xdc\xb6\x06\xa4\x91lnq\xb1x\xd7\x8bV\xccY\x9a\xa25\xcd\xebW\x95\x0dv\xcd\xdci\xc5\x92i\x9c\\\x7fD\xa3\"\n]\xda\xbe\xc1\xe5\xb7\xb1\xc6\xf0.\x10w\xed\xf2\xcaU\x06C \xf1\x04\xc3\x9aW\xf6B\x94\xfdL\xc5\xb1|\xff=(\x03>\x89\x98>\xeb-\xd7\x8b\"^-\xa8\xb4P\x15\x1e8\xc5=\x82X\xde\x94\xd9\xd8\"\xcc\x81B\x1b(\xf5\xd2UaGEu\xde\xba\xa3\xbbA&\xc4d\xdd\xe5 \xa9\xbb\x1cd#AhG\xe9\xe5\xff\xcb\xde\xbbv\xc7\x8d\x1b\x0d\xc2\xdf\xf3+J\xcc\xacCF4\xad\x8b\xc7c\xb7G\xd1\xeb\xb1\xe5\x8d\xb3\xe3\xcbZ\x9e\xe4\xeci+Z\xaa\x1b\xdd\xcd\x11\x9bdH\xb6de\xac\xe7\xb7\xbf\x07\x85\x0bA\x12 \xc0\xb6<\x93d\x1f|\xb0\xd5$\x88K\xa1P\xa8*\xd4\xe5\xac\x93\xc0\xa4\xd5\x92\xd2B\xdcn\xc1L\x89X\xd0\xcd\x0e\xb1\x8b\xa7\xf9\x197\xa4\xd2\x93\x02\xacPaLU2\xc7[\xf1\x0d\x9e\"\xed\xe7Gj\x82xQ:\x1a\x13\x137\"A\xc3\xa6\xde\x02O{r\xda\x01R\x907\xb3@&\xa0l\xdb!t\x87\xba\xa3#\xac\xb1\xe2k\xe2\xc7\xd3\xbd\xee\x17F\xcc\x12\x7f\xe9\x05\xef%\xa9\xff\x9cW5\x06Mq8\x9f\x84<\xc1b\x19\x99\xecA\xf3\x8c\xd9\x01Nz\xd6\x8c\xe2\x8d~\xb3q_xv\xb8\xf4\x97k\xf0\xc8]\xe7\x9b\xac\xfe\x1b\xeb\xcba\"\xe2\xa0U\xf6\xb6\x8e\xdd\xed\x8c\xbf\x07>QZ$\xc8\x9c1*\xc9\x92:\x89Sn\xb9*\x08\x07et2\x984!?\xf1\xbdI\x8f\xc9\x12\x8eU\xecs\x83\xaeP\xc2\x7fX\xcc\x17EXw\x8d%\x8e\xa20@\xf2\x10\xceoy\xe7\xec\"\xcf|~\xeb\x0e\x04\xdf\x85\xba\x9b\xd8\x0eP\xcd\xb9\xe3*.|\x1ec\xcb\x18\xd5\xe0\x96\x85\xaa5\xd9\xf9_\xc7\xd5kN\xbc'\x92\xa0\xd7\x0dA\xefch\xa8\xa6\x8d\xa8\xf9\x8eW\x13r\x1eu\x16\x99\xbe\xdc\xa0\xc9\xcfF\xb7\x8d\xc3\xee^e\xc1\xa3\xf1\xd3\xe7\xcc!\xc8\xb6\xc6\x06/\x0f\x15\x13\x87\xfa,\xf2\xaaf\xa0\xd7\xec-\xd3\xc6bVmZD\xb2n\xb1\xd6\xc8\x0cY\xe7\xa1e\"\xd6\xfe\\Y4{_Je8\xd2-\xb1\xbe\xdf\xd2N8\xc4\xde.\x99\x7f\xb6\x8da \xd9q\xaf\x19A\x08%Ztex\xb6i*42\xd3N\x0f\xbb\x8e\x07\x9amW\xa5]\x0c\xd5\x15?D>\x13\xaf\x17)G\xfe\xfa\xaaLm7\xb0m\xae\xe7u\x19O\xfbx\xbf\x1b\x91\x80g\xcdy\xd45q\xdc\xf0\xe7\xdd\xfb\x8c\x8a;:\xd3\x0e\x809<3\xdewx\x13 \x19\x93N<==\xb4\x96m\xd6\xab\xf7\x11\xcd\xfb<\x1c\x97\x91\x8fxz\xa2}\x91/\x8f\xee\x88\x98\xc7\x00\xf1\xd3\x0e^J\xb9\xccc\xd9\x92Zi\x8e\x86\xf4b\x86\xb3\x88)\xb1h\x03z\xb9S\xeb:\x84A\xfc4\xa1:z!=D\x11|\x8bI%\xbb\x17\xc2\x0cv]\xbc@Ax\xf9\x0eU\x80\x16\x0d\xa3\xbcu\xbc\xd6\xe6nP\x0bg\xab\x85\xf2\x18\x9e\xaf\xc8\xec\x12\x03K\xf1\xc05,\xf55\xe4\x0b\xf8\xbf\xe8\xa3\x05\xbb\xe0\xfd\xdfH/\x9a\x82Q\xb1\x03\x8a!\xb5A\xac\xf5\xf3\xe8<\xbf\xceHI \x87\xef\xed\x1f\xeeyMX\x89\x04\xd5\xc9\x13 \xf2\x10f6\xae\x98\x16MV,\xb6\xec\xc8\xb7\x1c\xc1\x86#\xdc\xab\xac&e\x16\xa72|\x8b\x8f\xc1%]<`\xc4\xac\x1a\x8cQ3p\xdd\xbb'NPf\xf5\xda\n\x95\xa5\xffF\x8dfK9\xc3&\xa4\x8c\xcb'%\x0b%(?\xea\x03\xc9g\x10\x088\x082r\x0d\x15\x9b\xae/~\xb3\x1a~\x1e\x04\x11\xe7\xb2)\xa3\x83\x87}\xd6zr\x04\x19C4\xbcr\xcb\xe7]r\xc16\xae)7\x99\xc7\x9c\x12\xba9\x89\xdb\x0b\xc3\x9d+s\x0c\x1c\xe1#\xb5G\xec\xd8\xf7\xc2\x86\x02\xb4q\\\xde^\x9c#\x00\xd1p\x8fy\x8f\xcbGk\x96\xc1\x97\xb9)w\xf3+\xd1\x92\xfb\x95\xea\xbf\x98t\x05\x86s\x16\xc9\xa1N0g\x8a\x1a\xe4l\x02\xcd\xadC7\x81,{\xf3uN\x92\xef\xbay\xd6\x94P\x17}\xd4\xfd\xf3\xdb\xd3\x0f=\xc7\x00Z\x9e\xbf}\xfd\xee\xed\xe9\xab\x0f'\x13\xd0\x88\x02'\xaf\xdf}\xf8?\x138\xe8\xbfY\x92\xfa\xc3M\xe1\xc4\xb8\xb7/~;'\x01\xdd\xe8\x11v\x83\xea\xea\xa4\xfak\x9c&s\x11\x15\n\xd1\xd6\xb0 \xf8\xbeN\"9\x05\x98@\x12\xd1\x99\x8a\xa4g\xa5\xef\x1d<\xd2'o\xec\x88\xd4\x067\xf1/\xb5=`\"x\x1f, f\xc68Y\x17\xf5\x8dD\xa4\x97\xf1\xac\xce\xcb\x1b'\x88R\x92o\x9bR\x1f;\xfa\x8d\xb1]\xe7\xd4\xa5\x90\xa7\xed\xb0l`\x90Dl\xa2\x94k8\x82<\xbcS\xd8\x9a7\x07\xdf\x05,Ve\x0f\nm\xf5\xf3\x95\xd6K\xdcpL\xd8\x00\xc5\x81\x94S\x04\xa7Tk\x9fR-\x86\xa9\xdc~\xc4v\xd5\xaf%\x83\x8e\xddb\x82ZK\xfbI\xf5\x01\xdd;\xc6M\xa8\x15\xc8&\x19l_\xac\xb7\xce\xd2\x88\xbd\xfc\x9f$#e2\x93cx\x9e\xc6\x95\xd5! \xf8\xd2j\xb0\xbeO\x9bX?\xad\x89:w\x92\xb8l-\xf9\xeb\xeby\x19\x9aQ\xfb\xe1#\xc6\xe1\xef\xf7rj\x08YB\x97\x81S\xec \xff\xa0\x9fiD\xd1\x94{\x91\xa7\x11,\xbc\x89\xe7.\x08H\x9c\xa1\xfc\x8b\x86\x7fW\xef\xceItIn\xe0\x18\xe2\x88T\xb3\xb8 >>\x08P\xc5T\xe7,G\xaa\x7f\xf8H57\x12\x7f\x8d\x89\xd9\xd51=\xa2\xc7\xc6\x9e\x92+\x9e\xa7\xa9\na\x16\xea\x13q\xd2E)BLr\xc2gQ\x1b\x04 %\xd2\x1e\xe5\x00\xd1\xb7\xcb\xbb`\x92\xaaxD\xf9\xaa\x9a\x13\xa2&\x94\x9a\x88\x94\xd10O\xbc\xae\xc26\x89'\x0dTy\x17u\xf4\xcd7|d\x18\xf4Or\xf83\x7f\x81 \xf1\x85p\xa2\x07\x8b\xc6\x0e\xa3\xf7\x84\x13\x94U\xeb\x05\x86\xda\xf0\xbc\xae\xb9\xc5\x97\xfaA\xb2\xd0\xa9h\xcb\xb2 \xa1\xc2tn3v(\xeeuo\x7f\x17\xec\xf6\xf7Q'\xe0%S\x7f\xe9N\xad\xc2\xec4\xfe\x92\xd7Q\x04lq\n\xf5\x177k\x02\xe4\x98\xf2\xa9\xf5?\xa2G\xbb\xb4!\xf6\x98\x07\x12\x06\x89\x0c\xa2\x92\x14i<#\xfe\x83\xe9\xc7\x8f\x7f\xff&\xfa\xe3\xee\xb1\x1fL?\x9e\xfdr\xfb\xf9\xec\xc12\x04\xef\xe3\xc7o\xeeyJ\xb5vW\x9f\xa5oT\x10\xfd\xf1\xd8?>\xfa\xf8\xf1\xa3\x1f|\xc6m\x1b\xed\xf2\x07g\x01\xb6\xf4\xcd~\xf4\xc7c\x86\x18\xdft\x03\xc2\xeb\xbd`\x85~\x8d\x8fV\xa7n\x96\x06|hF\xdc\x0d\x10?\x184X\xd8,\xef\xb7\xbf\xf9]\xff\xaf\x8e\xb2\xae\xe1*\xd8\x11\xb3(\xf3\xb5Qm\xf2:\xc6T\xde\x85\xff:.Z\x06|\xaf\xe3\xc2AQ\xd3\xaa\x85\xdbL\xb6\xd6y\x1e\x18\xdb8%5\xfb\xe8\x94\xd4\xad!\x9c\x92\xdaa\x08\xadZ\xca\x10\xfa\xcf{q\xa4\xaex\x92r*#\xbc\x8e\x8b>b\xae\xf8\xcbS\xd2am\x9c\x12\x9a\xcd\xa3\x8a\xd4\xecm{\x0d\xc3v\x0e\xea\xa1\xe5\x9fGK\xd2\xd7@\xb3D\xb8\xc3\x0d\xcc\xb9i\xa0\xe6\xe3\xd8\x16T\x8ew\xde\xe0\x8f?g4\xb4g\xa1\x85l\xf2\xf0@VQ<\x9fkF1\xecx\x0e<\x07\x83a\n\xd6\x98\x94\xfd)\xac\xf4Sh6\x94\x8e)\xba\xe2\x99\xe6\xbb\xee\x07\xc0\xb3\xf2\xe9\x9e/\xad\x13\x03Eg\x1a\xe9C\x1ai\xda\xbd\x19\xd3.&~~\x95\xd5>\xe1\x1e\x9b\xfe>ej\xf74\x8a\x8a-P[\\\xdf-\xb5T\xef\x8ae\xc8\xac\xc7c\xbd8s\xf4\xed\n\xab\x8bi}6~?\x0c7\xcd#.\xe9\x9av\xdd-*\xafq\x15D\xeb\xb8\xf0o\xb6\xd8.\xc3\xe3\\\xb3l\xf8\xddD\xf9.\xbb\xc9 \x00k\x0d\x00\\\xf7\x9a\n\x80\xb5\x1e\x00\xbf\xeb\xffE\x87E\x05\x85\xe9\x99\x8e/97\xf3%yo\x1eF\xf3\xa8+\x99\xc2y\xb6J\xd2\xf9\xab\x17:\x99\x0c\xc3Oe\xd2\xab\xfa|\x8c\xb5\xd7\xb5E\xc8\xf6>f\xd8G\xc6B\xd13\xcd\xffO\xd9e\x96_g\xc8s\xf8h\xc2\x0f~\\\x03c\x80\x16I\xca\xa2\xf2H\xd6\xe6\xef\xd1\x1f\xa7\x1f?~|p\xf6\x80Y\x1c\xef\x827au\xd3$#\xccM\x9a>\x0c<\x14<\xb19\xa69\x9b\xc3\xc5\x0d6\x9b\xc9\xf7\xaa\xf3\x87nB'}\xb8k\xf4\x05\xde\xef\xc9\xba\xa8o\xb0\xc1q\xf7\x1b\xde\xefk\xf2\xa96}(\xd4\xd8\xfc\x8f \xff#\x9a'U\x91\xc6hY\xca\xdc\x98\xf0i\xc6\x7fJ\x80\x0e\xce\xec\x93\x01\xa3B\xc4\x90Sz\xde\xbeh\xba\xd1Z\x97\x94\xa2b\xa3\x91\xefW\xcaE\xa5\xb7\xd7\x19)_\xbd\xe8a\xab\xd4\x8b\xa2\xe5\x8c\xae\xef<\x08B\xb8\xc6\xfc\x91\x80\xb1\xc8\xcf\xab|S\xce\xda\x1cE{'\x9d\xf6\xb4\xb6yvJXH\x9d\x92dcL\xab\xf4\xd6\x92\x14\xd03\xdf\xdb\x7f\x88\xd1\x923\xb9\xa1\xe8\xee\xeaW\x97\x92z\xc9$\xf5\xb2\xa5\xbe(\x87-\nY\x8e\xb9\xd2\x90Z\x1f\xb8\x0e/\xf7\x13\x93m\xa1\x1ck+:\x7f\xdc\x8cY\xaf\x8c\x8b#\xc2\x83\xf9(\xcch\xeb!6\xbaO\x1b\x8d\xa3\xa4z\x9do2\xba\xc9Xo\xdf\xed\xb7;+\xe2\x92d57\x90R~\x1ea\x8cr\xe5\x01^\x8e\xca\xd6\x0f<&\xec\xc9\xf7.\x176\x1d\xd5h\xf6\x03Y\xe4%y\xdd\xbaAu3\xe7/}c\xb8H\x0e\x87 h2\xaf\x03FSc\x03\x9e@\xa6\xaf\xc0\xec\x9e\xcc\xf6oby&05\xac\xbd\x84\xb9\xd9V\x8f\xc55\xe4\xc1s\xc6Z#\n\xc8\xfd\xc4\x1b\xd1\x83n\x9b\xddC1JA\x194\xfe\x91\x98\xd5\x8bb\xd5\x1b\x96y)\x87N|\xfd`\xea\xf6V\xae\x95a1\x97Va\xf1\xa6b\xf0\xc6r\x95\x92g\x030\xdbf\x8c\xa8\xc7m\x01\xac\x8e\x94\xb5\xdd\xdd\xb5\x8c&[\xdf)\xc8X\xa4\xc7\x16\xa4\xf6\xf5\x90\xaa|\xa2K\xc7x!\x82\xf7\x0f\x8d\xbb\xd8\x94K\xc2\x87N\xe6r\xf0\x95\xc5\xd5\x14\xc3j\x9eF\xe7EI\xaeHV\xbf\xdb\x94\xcb$3*j[\xc9\x94\xf6\x9e\x02\x81\xef\xe1B\xd2fb\xa6\xcd\xb4\x9c\xfb\x17Sr\xe6\xaa8\x03\x9c\xf8@\xd0\xfa\xe1[\xdaf\xb7\x7f\xc9\xe2 \x85\xcaN\x17\xa9\x86\xfa^\x92\xfa9\x8f\xecW\xc7\xb3\xcbg\xf39\xc9\xe6\x9b\xb5\xebHtVO\x836L\x82~\x9c\x0c\x86\xaf.\x99\xe5$Z\n\xe9\xcf\xbe\x1av\x8f\x18\xeb@\x1a\xae\x81s\x11\xd2*\xcav\x9e\x80\xa2\xe4Z\x88\x08\x87\x06\x8aL\xc1N\x9b\xcf\xa3\xf39\xb9\xd8,_\xbd0\xae\x00\x8e\x0d\x99\x9d\x16L\x7f\xb8y\xf5B\xc4\x9c\x17EcB\xdb\xfd\xc4\xb6\x14\x12\xcd\xf9z\x00y\x1a\xb0!|B\x8e\x9f\x08\xce\xeb\x1d\xdf\xbcC\xc8\xd3\x15i{\xb8\"\x8f.7\xfc\x18\xc4T*\x124\x12\x0b\xa6\xf5\xb4t\xaf0\x8f\xae#\xe8\xf0\xb1\x83\x839q\xf3)n\x1at\x1d\x84\x03\x18\xc4\x19\xe9\xd4=g\xb9]\xbbw\x87\x01\x12\x0e\xb6\xefpT\xecO\x89\xf2n\xa3{'\x19$\xb7\xe19@G\x1e\xcfk$Gi\xff\x15Y&UMJ\xc2\xe8U\xdc\xe5@\xaa\xd5\x9b<;\xad\xe3l\x1e\x97\xf3\xbf\xc5e\x96dK$\xbe\x0e\\\xb0\xf1FB\xa4>,I(\xf2\xc2N\xaat\xd8\xecH\xa2N2\x94;\xb5/\xc6\x86\xda?\xc5\xa7\xdb\x1b\x010G\x97\xeeu\xbf\xde\x9e\x969\x1b\xba\xe9{\xa09gH\x14\xcf\xe7'T\x80\xfc\x91{+2'\xa8\xeeSn\x1e\xb6\xb3\xaf\xb5\xadn\x1a]\xe7Wc\xd2\x8a\x08\xff{C_c1\x90\xc5\x9b\x881\xa4'6\xc9'\xd3<\xf0=\x8a\x00\xbb\x0c4w<\x959\xd1w\xb3\xcd,L~\xb5\xfd\xed?\x8b\x8bzS:\x06\xee\x80\xedW~\xef\xae\xc15\xb0\xf2\x9a\x8bKQ\x06`f\x1f]\xa9\xff\xd8\x05\xcc%\xe7\xa0^\x88$\xba\xeaL\x8d\xe6\xdf\xad\x84kwA\x0d\x1e\x1f\xe8\xc2\xf8\xd1\xe7\xfaP\x11\x87\x8f\xba\x99\x00\xb8[\xddw\x07A\xbb\xfd\x8d.M/\xf3aM\xf2\xecy\\\xc4\x17I\x9a\xd4\x89=u\xc2\xd5\x97&\xa0\x80\x8e\x14\xe6\xb7SQ\xdc\xbb\xc7\xb2Ox<\x8d\x00^\x1b}\xfe\xdcKI\xc1\x9e\x95\x1b\"*\xceXL\xff\x93yR\xc7\x17]\xa7`\x93\x03o\x92g\xaf\xb2E^\xb2(\xf4\x16\x0c\x17\x1a\xb6x`Jz4\xc5\x18\xfb\x04\xdd>\x8c)\xbe+1\xa0\xf7\xccc\x1c\x03\x1cj\x97\xc8G\xb7\x91M\xa4\xce\xc2'Zy\x1el'nI\xaa:/\x89l\xc7i\xf9\xd9\x05[lJ\xda\xc3tZ\xca\x9c\x0d\x13\xc6j\xedi\xeb\x14\xed;G\x9c\xe9\xc7\xab\xb52\x84\xdc7\xe5l`\xa1\xe30!\x90\x19z%\xd6\xd8D\x95\n\xbe2\x84*\x08!\xf1\xcb\xe1\xd0E*\xcc\x9d`\xa5\xd7\x1azr\xda\x18l\x1e\x13Q\x90\x007\x96\x1e\x83*\x16\x93^\x81\x17~\xa8\x87,\xc9\xe6\xad\xaa'\xd9\xbc\x8f\x15\xfd\x81I\xebP ^\xd9B\x7f\xb3\xab\xbb\xd6\xb4\xf1m\x12a\xbf\x1f\xee'\x87\xb8`\xf2\xf5\xcc\xb8\x8eD\x08*\x01\xf7\xb4\x12\x18b>)8\x10\xefg\x11=1\x10\x80\xbe7[\xc5e<\xabI\xe9\x85p\x9f\xa7\xf9\xe2\n\xee\x01\xb1\x04A\xcc\x1b\xa2\xcc\xe3`3\xdaV4Y\xfa\xb9\xddR-\xd2]\xbd\xc5\x98\xf7\xd5\xb0*\xe1\xf3\xe7a\x941\x98\xb8\xe3\x04F\xaa\xef+\x03\xf2[n\xd0\xea\xa82\xe3*3\xbb$\x99&\xd6\x15E\xc5V\xaa\x7f\x91\xb6\x9b2w\x86\x1d\xd4\xdd \xb4v\xd8\xd9\x0bp\x04\xaf\xe3z\x15\xad\x93\xccG\xa7\xad\xd6b\xfd\xc6\xfb\x02\x1dt\xf86\xf8@>\xd5\x83[!\x89fy\x9a\xc6EE|d\xe1\x12\x13bg\xf2e\x0fYs\xb8\xcf_\xb3Y\xe9\x12\xcf\x8aH[\x95\x82\x93CQ\x94\xf4<\x12\xcb/\xb8\x15\x8f\xe4\x96\xe2\xa6\x830>\x01\xee\x8d\xd9q\\\x11\x02\xa2XO8n\xfe\x14\xdcy\xd0\x84\xe2\xeb+B\xf5\xea\xa5\x86\xf7\x9e\xd5\xc9\x15Q\xf2\x08\x91\xe8\"\x9fwRH \x81z(\xbc\x8f\xee\xbb\xdf\xb5\xff\xda\n\x9cW6\xef\xdb\xc7z\x86\xb3\x17f:\xd6\xfb\xea\xb2(\x0e\xfb\xdfv\x1b\xafZ.^}\x0f\xaf\x94\xf5\xf2\xb0+\x15\xcf\xf8\xf3n?\xcc8\xfe\xf0\xdb\xee\xf3\x82\xcf\xad\x1bub\xce\xfa\x17\xe1\xb0\x1f>\xea\x0e`\xc5:z\xdcy|\x85\x8f\x0f\x0e\xba\xe3Z\x8364\xdb\x92u\xdf\xcb\xdfu\xc3\xb9\xf6n3\x17\xaa\x03\xdb\xfe\xc3'\xddQ\x9d\xf3\xee\xbb\xd3\xb9n\x1c\xdb\x92~\x00\xe4N\xe5\x13\x8cQ\xa6\x8b\x1f\xdc\xaa\xf6 \x8e\xba\x9e\xd2\xa7p\x04O\xda\x8f\x9e\xd3Z\x9dj\x97\xc68\xde\xcf\x8c&h\xcc4L&\xcf\xa2\xbb\xf6\x14\x1fu\x93qMZ)\xc8\xba\xac\xae\xce:\xec\xad\xb9Sz\xb6\xca\xa0\x80\x8c\x84\xabO\xfck\x96\x8ew\xd8\xfa\xec\x9d\xd8n!\xf2\xa4\xdd\xbe\x90\x96\xb7\xa9\x06%O\x8b\xa8\x9f5\xdbtv\xc6\xe6\xe8=\xec.\xd1\x14\xf2\x03\x8e\xc0C/~\x16\x8ck\xc2L\x155w$1\x1cC\x0c\x13\x88\xbb\xf6x1\x9a\xe2\x05\xa1T\x95\xd5\xc9\x9a\xf4\xaet{\x13\xa6\xfb~\xd5\x89\xf3@\xc1\x94\x85<6\x01w\xa9D\x07\x98n\xf8\xa8DU\xcd\xd1\xfe\xe8Q\x95`\xc8\x81s\x16\xbdC1\xa0\x88\xcek\x0eD\x1e\x0e\x89e\x87\xffQ\x8d\x88\xf0*\xabsLa\xbd\xc1\x85\"\xb8P\xd9\xb0\xb5\xe4\x07eUuKJ\xc9\xe3:B\xe0\xbe'\xb3<\x9b%)\xf9P\xc6Y\x153\xfeuI\xeawy\x9e\x92\xb9\xbf\x83\xcc\xc1,\xdaT\xe49\x9e\xe6|\x01;\xb3\xce\xa3\x82\x94T\x02\xf5\xdf \xb1\x11\xe4|\x10\xe1`\x7f%I \xe5)\xf2\xe1i\xbd6\xe9\x8d\xf0*d/\x84U\xb4\xc94\xeb\x86\xd6D\x9d\xed)\xf8\xec\x9e\xf4\x15<\x85\xbaI\xfb\xf74\x80\x9a\xab\x81\xf0\xb7\xaf\xbc\x1b\x1e\xec+\xb3\xa5\xf0\xb3\xf1\x96\xc2U\xa4\xcbj\xae\xf3Q\x13f%t\xe9>\x7f\x86\x9d,:_\xe5\x15\xbf\xdb\x18cC\xfc\xb3\x91\xf4\xec\xf8;\xdc\xdeU\x02u\x07\xfd\xde$\x1f)\x9f\x9dj\x9e=\x1f\x06\xdc\x1b3\xe0\x1c$U\x0e^=\x9b\xce.\x88\xef\xdd\x1b\x0fN\xdc\x06mX\xf20{\xfd\x9bW\x93e-\xbb\xf6\xc2\x16\x9e\xe7Y\x1d'\x19)_e\x8b\xbcO\x05z\x07\x83\xf8\x8bN\xf1}\xffl{a\xb3\x88\xc7\x08R%^\xbe\xc2\x11\xbc\xefZ\xa95\xc3}\xa1\xf8(%U;\x88\n\x0f\xe7\xf9\xa2\x15\xd9\x06\xe3\x11\x0d\xf4.\xe6N\x07\xa0\x10\xfdfn\xb4A\xde\xd3\x87\x1e1T#\x82\xd2\xb9\xff\xd8\x93\x8c;\xdfL\xe0E\x87\xeb\x10A\x11\xaa\x1fn\x18\x01B(L\xe0\xb2\xc3\xd4a\xa2\xd4\xd7y\x96\xd4\xb9K\xc4\xc7\xae\x84\xd1\x112\xcf\xd9\xbd8\xedl\xc0\xd2U\x7f\xe8B\x03\xb6\x1f\xa3\xd6\xb8\xfc2\xb4\xab\xaf\xaf\"\x92\xfdcC6\x82T\x8b\x00\x19\x92x\x86L\x08\x95\xf5\x9e\xc7iz\x11\xcf.\xd5\x8a\xb9F~\xa2\x87\xd8\xe0\x9c\x196\xbc!\xd7\xd6ik\xe7\xfc3\xcf\x19R\xfa\xde\xe1w^\x10\xc2&\"Y\xb5)\x89\x92\x14\x97\x03\x02\x93J\xf77\xab\x10=1\xde<\xc6\x13\xee\xd6XG\x17T`!sf\x0dQ\xf9\x1f\xd0\xacY\x8cJ\xdf$\x0b\x8c+1\x89o$#\xad\xb8\x9c\xc6g\xf4\x8bp8\n\x07\x83\xd6\xe9\xe6\xa2. \x9e\xf2\x92(8C\xacc\xc6\x82\\`\x11\xadbT\xaerH>\xa6\x90\xfcQ0\x1f\xba\xee\xd4N\x1c\xd6\xf7\x8bF|\x15]\xc5i\x82&#\x1c\xeb\xfc<\xe4|\xde\x8b\xb7\xaf9A\x11\x96\xec\xad0C\x0dr<\xf1B\x93\xad\x8c\x07\x94\xaa\x93\x18\x83\xa3\x15qU%\xd9\x12b`\x95!M. \xfca\x9e\\\xfd!\xc4\x97\x80\xfdr=\x85\xe8\x07\xdf\x07\x90\x97\xf0\xfd<\xb9\x82\x07\x7f\x8a\xd0-DL\xd0\xb1\xc7YJ\xdb\xc7\x0e_\xe6\xf9@w/\xf3\x9cu\xf62\xcfEg\x99\x1a\x03Z\x89U\xc6\xf9f\xec\xf5\xc3*\xa9`\x1d\xdf\xc0\x05\x81Y\xbc\xa9\x98W\xcd&K\xf0\x02!\xc9\xb38Mo \xcd\xe39\x1dP}\x9dC\x92\xcdIA\xe1\x9b\xd50\xcb\x8b\x84Tt\xc8lL\xdc\x07\xc7\xb0\xa5\x98\x9fX\xdc\x19\xf9\x0b\xd3m\x1bR\xf8 h\xe2\x9ci:\xb0\x9a\x9fRq\xbb\xe0n\xa7\x06\x05\x122H\xe7E\x99\xcfHU!o\xc6\xc3\x99\xfaUt>c\x7f\x1a\x15B\xf4\xeb\xa5~\xe2T\x92\x7f\xe3\xeb\xf2d`\x12\x8c\xa1QSa?\x1d\x12{\x0cSY\x80\x7f\xee\xcf\xd8\x15\x80Y\x07L{X\xb0\x1e\xfaB\x05\xe5\xde7\x17i2\x93\xf1\xbb-\x96)sa,k=[\xd4\x9237\xf3\x85\xf9\"\x14@\xab\xa1\x17E\x9eq\xba\xc3\xd2O1\xac@\x82\xa4d\x1e\x84\xb0\xd0\xb6\xa3\xbfk\xfd\xb1'\x07<\xc3\xd8xvS\x0e\xe0\xc0]!\x1f\x99\x19\x00\xb7\xa6\x12\"r\x84;o}\x93\x82\xfd\x06\x8e\xe0\x95\xb1\x89\x0b*\x82a\x13)\xfe\xab C\x00\\9\"\x89w\xf7d\xa5\"a\x16\xc2E\x08I\xe0\x88\x08\xc6C\x8b\x1bK\xe3\x92^\x07!\\\xdb\x8f.\xb7\xfb\xfcf\x95\x07N Ud\x1c\xce\x08\xa2_X\xdb%\xd6\xcf\xcd\x81\xf8p\xcfD\xe6j\xdc\xed:\"\x83\x8e\x0c\xc6T\xb5\xaf\xd0n{_Q\x96\x7f\xe0\x01\x020\xd4D\xa3\x9191\xd0/!V\xed; '\xaf\xcb\xddc/\xa7u\x8f/9\x0b\xfb\\\xcek\xa1;@\xeb\x98\x9e\xb7n\xeb\xa7F\xf7\xa0;\xde\x93\x10b\x1dD(\xac\x14N\x8e\xb9\xa5\x0d\x86c\xdd\xe0^\x1b\n\xee3\x8ffq\xf6\x9el*\x9e\x19\x8a\x8eb\xd3\xc92C\xc5\x0b2\x8bg+\xc2v:\xad\xa1oQP\xf6M[_6\x8f\x9e\xff\xf9\xe4\xf9\xff:\xfd\xe95\xaa\x16\x99\xf6Q\xdf\xc2\xa6\x97\x93c\xc4\xc7\xe2t\xd8D\xf9\xa6&\xe5\x9f?\xbc\xfe\xd1\xd4Ke\x1b_\x08\xdd\xa8\xbc\xa2\x88\x13b \xb5Q\xe1\xe2Y\xaf\x16\xe9\xba\x90\xa9\x97O\xe2\xce)\x94\x9e\x94A\xa8\xfaWf\xcc\xb1r\xb0e\x10\x8c\x80H\xf5\\\x06\x9c\xe1\x91\xbf\xe5j\x1b\x1c\xec\x85P\xc0.\x1c\xec\xa1S\xf4\xc7\x0c\xfc\x8a\x94W\xa4d\xd5g\xe6\xea\xfa\x99\xe9tWtg\x1dx!h\xaee\xfb4\x03\xb5K\x86F\x0e\x19\xaf\xdd\xd3\xef\x19P\x81\x07\x98r\xd5\x90\xe9'\x94GIV\x91\xb2\xfeP\x12\xc2\x1c\x1b}F\x9d\xe81`\xe4\xd3.X\n\x80P\xb3\xd3kE\xab>\xf2:\xefG|\xfa\x85\xf7O\x87\x8f\xbe\x0d\xf4\xcd\x9b\x8f\xa5\xc6\x0fH\x03$TM*\x1a\xe37|\xed\x98\x95@\xd9DS}\x1a\xa01\x8fN\xb9l\xd0A\xb1\x060\x00\xeb\xb1\xf6;\x98\xc8Z,\xe4+\xcf\xeb\xd7\xb3\xf8\xfb\x82\xab\xbb::?'\xd5\xeb|\xbeI\x89F\xcd\xc3C\xb2f~\xf7\xea\x0d\xc3\xe7b\xbc|4\x7f)\xd5f\x8e\xa1\xd4Z\xd8\xcd\x859\\\xdb\xb4\xeeV\x1d\x0d\xaf\x83r>\xff;\xaaVqA:f\xd3t\xe7\xce\xca\xe4\x82L\x94\x8at\xfa\xa8\xc2\xfa\xc7&)\xc9\xbc=\xe2yR\x15\xf4,v\xfe\x80\xf9\x94\xd5C=4+\x10\xdc\xe1\x12\x84-8\x98\x11W\x7f\x0b\xcd\xaf<\xc0\x14\x16I\\\x89\x90\xb2\xccK\xf5\x8e\x04\x1f\xf4\xb8.\xfd\xddt\xbd*\xf3k\x8c\x80t\xc2\xbfj/\xa9\xde\xbc\xdb O\x95\xcb\xe4\xc7\xdd\x1bJ~\x9b\xdc\xb3S\x14\xa9\xae\xba7\xa41\xaf\xdf\xc5\xde\x0d\x7f\xdem\xbf\xe2\xcf\xbb\x17\xc0\xfc\"\xb9\x97^\x80_$\xf7\xd2\x0b,\xf8\xf3\xee\xc5/\xbbH>x\xa2\xbbH\xce\xfc\xc3\xc7\xddy\xb1\xfb\xe3\xfd\xc3n\xfbW\xbc\xfd\xee\xb5\xfa\x9a_\xabw\xdbY\xf2\xe7\xddy\xb1\x1b\xe4\xde=\xf4\x05\x07\x7fw\xba\xe7\xbc\x99\xeep\xae\xf9\xf05W\xc4\xb4zw\x94\x9f\xf0y\xef\xda\xfa\xb4\xafN\x7f\x0eG\xddh\xda\x97p\x04\x0f\xdb\x8f\x9eQN@\x04\x00|V.\xf1\x12\xa9:\xebD\x18|\xab\xd6\x12\xa1\xeb\xba\x95\xde\xa9\x950\xf4n\\\xe7\xa5\xa9\xf6\x07\xb5\xb6\x88<\xd8\xae\xf2\x9a\xdfb\xcb\xdf\xd3gg\x94g\x9b*\x03.\xe3\x9b3O\xf7\xf4\x87\xcdbA\xca\xde\xbb\x17q\x1d\xff5!\xd7\xbd\x17<\xc7\x87\xee\x03\xd2{\xf82\xcd\xe3\xfa\xf0@\xdf=\xbe|\xf4P\xff\xf2UV?6\xbe\xd9\x7fd|e\xea\xecu\\\xf4\x9e1\x17\x14\xf1\xf8C\xe7-\x8b \xd8\xfb\xe8\x94\xd4\xfdg\xc8\xdf\xf5\x1f\xdf\xac/\xf2\xb4\xf7\xf8\xa7\xc487|\xf5<\x8d\xd7\x05\x99\x9bk\x98\xa6O\xdf\xb5\xe6O\xc9\xbc\xf2\x1e\xc9\xa8\xf8\xeam\xe7\xe3\xbf\x91\xf8R\x02ig?\xd4262,\xef\xab\x10~\x0e\xe1M\x08\xefu\xb7w/B\xbc\xbb\xc9\xe0\x1e\x9c\xf6\x99\xeb\x9f\xf8\xab\xe7\xfdW\xff\xe0\xaf.\xdb\xe7\x03ei_\xe1%\xee\x0b*\xb5\xc31\xbc\xa2\xe3\x90#\x98\xd0\xdfA\x10\xaa\xda\xd3\x17R\x84x\xd1ol\xe7Z\xcd[\xdaa\x9e\xe8\x0c^\xe2\xbdBWJ\xa5\x9f\xbe4\x89\xc1thW~M%\xee\x1fe\xd3\x18\xd5\xf7E\xf7\xe02\xc4\xbf\xa5\x1d\xff\x13\x8e`E[\xe9\xbd\xa5\xe5\x078\xa25\x8e\xe0-\x15\xb8\xf1\xafwz\x05\xc6\x85:\xc1\x8a\x8e\xe2G\x83\xaa\x03[\xf9 \xdb{F\xff\xfa\x01\xb5ToLr\x81\x98\xeeO\xac\xee1\xfcr\x0b\x13Xv'\xff\x13\x1c\xc3\x82v\xbd\xf1_0\x1d\xe7\x04f\xf4w\xcc\x7f\xf7\x1a7\x82F\xf4\xba\xf3z\xfa\xcf3\xd9\xc1\x1b\xee/\xfb\x8bA\xefH\xc7\xb8\xa6\x1d\xfe\x93N\xbf\xdf\xdb\xef\xcc\xbf\xde\xa3\x0d\xde{`!\x18\xcb\xa0\x8f\"\x7f\x85#x\x8f\x9aj\x1d\x9a\xfcU\x0e\xf2\xaf\xfd\x97\xef16#bF\x88~\xed\x0d*\xca\x08`\x92}\xe9\xd9t\x00\xde\xdcbXC\xbf\x14\xbb\xb1D&\xe7}\xd7\x12<\x08u\xe8\x7fn\xeb\xd2p\x9f\xf3\x02\xc7\x9d\x87\xa0t\x9c\xbbvLa\xf6g8\x82\x7f\xc01b\xc6\x1c&P\xc0\x04\xff\xbe$7\xd5\xab\x0c\x03\xe2\xf6:\xfd\x1b\x1c\xc1K8\x16{{\x02\x7f\xee\x01\\h5\xfd\xbf\xd1U\xab\x15\xde\xcf4\x93\xbf!5)1\xc6\x13z\xe8\x9e\xa1%\xfd\x0b\x9c\x8f\xdb\xec\xe4\x93\x91\x1c\xe7\xc1\x93.\x87$8N}\"\xaa\xef\x1e\x8f\x9669<\x12\xe6u\x81W~;\x18Z\xbc\x95\xeb`\xe4\xb8\xf7\x1f\x1b\x92\xc2\x1ety2\xce)?\xd6g\x85=x\xd2}\xbei\xc2\xf62\x0f[\x11A\x97\x1d\xa0\x15%#\x83\n\xdfV\x94\x8d\xe9\x19\x8b\xb2\x81\xce[\x14\x04<\xcc\xc6\xb0{{{}a\x02\xb1\x1e\xe8N\x06\xc1\xeab\xeb\x81v\xd8cX\xb9{\xd4\xf6\xab\x8d\xcb\x9c\xb4\xaeuG\xae\xf0\xe3\xc7z\xcc<\xec\xc9H|\xb0\x8f\x0f\xb7\x1dl\xe2+\xa9\xa0\x99\xc9\x18&\xec\xf7\xbe`\xf0]4\xcc\xa5\xde2\xfed\x1b\xa6\xfeF\xa3Q\xa3@\xaeZi\xd7\xa8L\xe1Z\xc6\xfb\xb0\x0f\x13\xc0\xe0\xfd}\xe2e\xbdc\x93\xa8KA\x1a\x0b\xb9\x82\xc5\xfd\xbc\xbf\xcf\xaebs?i:c\x1d\xa1\x14\xc9\x82\xf7o\x82\xa7\xb0\xbb\x1b\xc3\xf7\xb0y\x1a@\xc5\xcd\x11\xa65\xecB|\xa6?\x17Y\xe3\xfawr@\xa9\xec\x816\xb5/{\xa9\x9f\x06\x90\x8a^L=\x08\xf6\x87\x05\x0c\xcd\xfc\nS\x8a\x11\x96S3\x04\x9d\xdeo\xfb\x85\xefn%a\x0f\xbe\x1f\xf8\xa5\x01A\xbf\xc0\xf7\x91S*\xa6\x15i\x12\xab\x87\xe05*\x16\xaf{Y\xce\xb3\xd3*w1\xb7\x81A\x05c@B\x0d\xd5\xcbzZ\xae\xa6\xf5\xa7=H\x99\xf7$\xea\xe2\xd9\x0dV3\x05\xc9\x1f\x90\xfe1^w\x04N\xd1\x884M\xe9/\xafr\x9b\xc0\xbc^,q\xdayTs\\\x11\xb4\xdedQ}\xc94;3\xd8\xdb)\xb0\xa4k\xd9\x80\xc2\xcf\xfc\xfd'\x07\xc1\x17h\xcf\xbe\xf6\x92\x1bM \xf54\x03\xc3\x88\x18\xbd\xa4\x92l\x91k3\x87\xd1\x92\xe6Km\xee0\xc0\x94\xb5e6\x81C\xfdKT\xdcM\xe0a\xef\xa5\xc659\xb3\x1ao\x82\xb2nSrF\xb9\xb6\xfb\x9a\xfb\xd0~\xd3\xccOs\x96g\x8bdYEi\xbeDs\xc0~=F\x02J5\xdb\x00\xa8f\xa7\x89\x8d\x91`\x97Z\x92 \xcb[\xafDR\xc5\x12\xfe\x04\xfb\xa8\x87f'\x00\xa5\xca\x94\xb0\xee?\x05J&\xcb\xa7\x10\xef\xee\x06\x94F\xd2\ngjkZ\xb2\x89\xa0\xfa\xd3\x91\x12\x92\x95+M\x83)9\x8b\xe2\xa2H\x11\xe5\x06\x0d\xda\xc5\xe9\x1a\xd1\xb5D\xfd6&)f\x17\xee\x1e}\x88\xf7\xb3\\/\xdb}\x8fOY\x05\x8aD\xbd\xf7\xf4!{\x8d\x18\xd8{\x8fO=\xad[>^Vc\x0e\xa8\xca\xe4\x17\x8f\xa8\x99\xf4\x91\xc00]\xa7S\xc2\x9a\x07\x8e21]M\xe3\xd7\xb9vpc\x8f\xc4\xc6\x978\xae\xa5u\xfa\xb3\xc0\xc0`\x90\xce}\xc4:\xbe$\x7f\xae\xeb\xc2\xa7\xc4\x97\xbc\xa4\xaf)Y*\xf2\xaa\xc6\x1f\x06\xd5\xc3\xc5&I\xe7\xef\xc9?6\xa4\xaa\xd5\xe6\xd4\xe7\x06\xd2\xc1r{\xab\x1f\xf1G\xfa\xfa%\xa9\xf2\xf4\xaaU\x9f?\x1a\xac\xcfMM4\x9f\xf17\xfa\xaf+R&q\x9a\xfc\x93\xbc'\x95\xfa\xad\xfa\\\xffe^\xbc\x9a\xab_\xacHZ\x90\xb2\x8a\xe8\xf3\xbbEc7\xdc\x91\xc4\xad\xd6\xeb\x0c\xf0\x84\x9e\x96\x8d\xfa\x84\xfe\x10-\xf7\xe9\xd1\x15w\x1d\xa1\xb5\x8cGQ2\x81\xd2p\xd2\x98\xa3\xe3\xf2.'\xba\xa8<\x1aM\x8e\xe0C\xe8h\x91+\xc8\xc5\xa0Q>W~\xa1\x97N\x94r\xcd\xa7|a\x00=\xf0If\x1anF2\x15k\xceNDx\x0d\x83\xe7wGp\xd0\xb9\xdd\x00^\xb9\xe5\x9c\x7f\xf9\xfc\xd9\xc0A\xb0\xaf\xf5\x90e\xfb\x7fS\xc6\x17)\x19\x00e\xb6Y\x13Q\xc7\xc0\x10,I\x8f.\x01h\x82\x10C\x1d\xd9On\x01\xb0\x1e\xbf\xa8\n\xe9\x96#\x9f\x88-\xd3\x1f\x138Dl\x11\xad\x8c\xc0\x9d:\x9a\xfbY\x08^\xcc\xfd\x8a\xb3\xfe\xd4s\x17\xfb\x18\xde\x9c+\xef\xdaO\xbdRG\x05KL\x05\xb5_Gt?\x1f\x1c*\"\xaf?\x1d\x1c\x82J\x072\xff\xe1\x81\xf2e8<\xf8\xce\x97\xdfn\xfbek\xb4\xe3\xbe\xdc\xba\xcf\xc3\xc3\xc7\xe6O5R{\xfb\xd0o\xbd\x92$\xb2\xd4c\xb7@-\x0dr\x13c@\x1fy\xf6\xdb\x93T\xea\x07\x93\x1b\xf1M\xec\xb6.\x1f\n\x7f\x82\x83\x8e\xb5x\xc3\\\x1e\x9c\xc1q\xfb\xe7\xc4\x98\n\x8d\xb29\xbe\xa6\xf5Cc\xeb\x87\xed\xd6\x0f\xcfP\xff\x1eDW\x07o\x0bRbL\x9aWh^\x12\xd7 \xc6/\xb9y\x9d\xcf5\x1e\x9f*\xa8[\xa9\xddTE\x0b&kP,\x10&\xe8\xf87\x13\xf4#\xf0I\x10\xb0(Qy\xd39s\x84U\xd2r}\xac0\xc7\x96\x174\x86a\xab\xf6'\x01L \xe1W[\xfaE\x1e\x9e\x9e\x9e\xbej\xfd\xc5\xcc\x02\xc9@8K\xdd\x12\x8dC\x00\xfb\x12\x99\xc8\xad\xc0A\xbfnG\x84\x80]\xf0\xce1}P+QZ\xb5\xf3\xff\xfd\xfe\x9b\xff\xf1\xf7{\x7f\xf4\x83\xf3\xdd\xa3\xe9/\x1f\xcfn\x9fN\xbe\xff\xd3\xe7\xe8\xe3\x83\xe3\xf0\xe3\xc7?x\xde}\x96<\xed\\g\x99\x0b\x0df\xb0\\\xe8\xcc\xf3\xb0\xb1\xa1\xdbo\xfa\xad\x95~}\xff<\xf8\xe5 \xbc\x0dD\xd3J\xe6\x12\xff<\xf8\xa3@\x80\xe6\x83\xe9\xf9Y\xf0\xc7o\xf8s\xcb\xc6UF\x851X\xe7~M\x87\xd1\x0f\xa4nX\xdc\xd8v\xa0\xf0\x06\xbd\xfb\xfdtL\xa667\xb66+N\x1fw\xf6\x90\x03q\xc6\xc4\xcaDWA\xdc\xc1\xb1\xe0Vb\xcf\xeel\xb3g?\x7f\x86\x1d\x12\x15q\xbd\xaa\xfa\x8du\xaa\xb3jC\xb1-@Qs\xf1\xea\xfd\nR\xb6\xcf!\xc9\xa0\xd4\x9b\xa8*\xeaXZi\x9a\x1b\xa2\xcc\x03\x87\x85\xf7\xee\xd9\xfbg\xafO>\x9c\xbc?e\x83O\xa2:\xff\xa9(laSD\xb9\xe2\x0eg\xb4\xa7ibP\xa6\x8aB;\x8c\x07\xe9el\x83}\x1cX\x87\x04\xd0\x18j\xdbk\x8aR\x15df\x8c\x13\xa6+t\x95XX\xd1\xdc\xfd\xa35\xa9W9\n]-(\xbb7 i\xfed \x9c\xa8Z4:(]\xc1\x0c4\xbe\xc9\x06]-(\x85\xa1W\xb2D\xe8\xcd\xe0Gz\xa7\x97\xfe\x9b\xf6\xaf\xadT\x96\xa0U[b\xe3\x9a\x0bp*g\x95~\xe6\xef?\xee\x06\xff\x00n\xb6\x86o\xbby(\xea(\xa9\xde>;=t\x125\x98.$/H\x16\x17\x89\x91\x89\xe0Y\x15(\xae\x17\x0d\xae\xd3\xc9\x1ez\x1a\x16<\xa9N\xaf\xe3\xe5\x92\x94\x07#\xc6P\xb1O\xb6\x18\xc3\x81n\x0cy\xf1j\xce\x12\xf0\xd7Q2\x7fY\xe6\xebwq\xbdz\x8d\xf8\xcd\xdcI\xeb(%\xcbxv\xf3\xaa\xff6\xa6o\x97\xa4\x96\xc7\xf9\xfb\xf8z\x84\xf8\xc2\xd9[F}\x8f\xd9Ib\xd7\xd7J\xc9/\x12[\xd7\xbc5\x18!f\xbb\xd5\\+\x11\x8b\xcb&\xa1\xdf;x\xe2$\x83'Nb\xa3z\x89\x12\x19i\xc7p\xef%H^\xa2\xf2\x85\x83\x0c\xca4\xf7\x13\x19\xf0\"\xf6\xf9\x1f\x9b\xb3\xa8\xca\xd7\xc4\xb7\x03\x14\xba+\xc2\xee\x16\xb5uu\x91\xd7\x0c\xd9\x10\xd0>>\x9bK\xdc\x80#\xd8\xd0\x87$\x9e\xad\xd4\x87\x15\x8b\x93Q\xaeQ\xcb\xc5w\xc4\x98\x0dQ\x90\x99~mY\x005D/\xb3\xd4\xa1\xb3\xd9\xc1\xb5F\x96\xaf\x8e\xbe\xf9F\x8emn\xba\x8b\x82\xde\x89m\x0c2+\x0e\xda\xccx\xca\"\x9f\xbd\x17\xc2\xa2uZ\x0e\xac\x9d\xc0\x18\xcc\x92\x15\xafIMJ\x0d\xdb!\x8a\x1cgE\xc7\x19\x07\xb0\xe3\xb0\xe7D\x91r\xe0\x948\xf0\x08;\x9did\x0d\xf6{\xb3<\xab\x93lC4\xa9a\xd4r\xc5]qs\x9f9\x7f\x99\x9cqE\xa1\xddj\x83\x02uK9\xad\xa8tB\xffc\x91\xca3\x8a\xc6\xf8\xf4\x08\xa6\x99ev\xc0\x87\x86\x87\xcb\xb4r\xa8M\x076k\x84\xa6\xfd\x00f}{'\x13\xbd\xd4\x15\x12\x9d\x9f\xe7e\xb2L\xb28U\xc4)\xe6\x96\xa1}\x83\x12\x8cBT\xc2\xf6O\x96\xb7\x9f%L\xe7W\xed\xd6\x81\xe8\\\xab\xbbE\x86\x00Td\xc4\xac-\xf4\xba\xcd\x98\x02\xbc\x80#\x98M\xf7\x1c\x00NKa\x84\x91\xe9\x0d\x15P\xda0*:0\xaa\xac=\x9b\x19%\xfb[\xe4\xe5\x9bm\xcc\xce\x18\xeb\xb6\x04\x0e\x9d\xb9%U\x84ZV\x06\xda\xd7-\x92^\\QzQ\x07\xe0\x15e>\xdf\xcc\x08\x1f\xdc\x15\n\x02\xb3<\xab6\xeb\xf6\xb3\x8a\xcc6eR\xdf\x88g\x9f?\x83\xbf\x9a^\x9d\xa1\xb1\xdb\xd5Y\x08s\xb6\xf3V\xba\x0ca\xddB\x01\xb3A\xc6f\xa5\x909v\xa64\xed\xd0\xbf\xb97\xa0\x03\xc8\x80\x83m\xcd\x14\xf5N\xf5\x81{\x18\x98\x14\xe1\xbar\x03G\\Ab\x9f'X3pt\x8b\\\xa0\x8b\x10\x9d\x16(\xd1M\x1b\xa2;\x0f\x9e\xc2\x8eO\xa7\xe8_\xc0\x11\x9cG\x19\xf9T\xfbA\x10\xcd\xf3\x8c\x04O\xf9\xe4]\xc1%\n\xed\x8f\xb2z\x17,\x00\xa8\xdb\xbcD\x91#>\xa1(um'3\xdd\xc2n\x90N\xce\xc6\x8eZ\x94\xde.\xa3\x0c\xcf\xc9\xb6\xad\x01\x87\xc7\xa7\x91h\xa4+\xa7#QKW\x9e\x8fD7]\x19\x87\x82\xba\"\x17\xf92D\xa7\x95\x0eZ^\xd3\xe5\xa3\x98I\xa1\xe6_\xc2\x11<\xebb\xe6'\x8e\x99;\xf6\xab\x981\xe5\x8a\x87\"\xbf\xdc\x06uu\x85bb\x87\xd7v>\xc5mE\xde\x1be\x1e\x81\xb7\x19*p\xc4\\\n\xc4\xbcq\xfe\xd4q\x9d\xac\xb5\xb6\x150n\xfdJ\x0f\x1b\x8d\xf9K\xef\x89<\x89T\x85\x08G\x8e\xceMQ_E\xbb\xe0J\xd8\x87\xdf\xe9T\xb4\x85P\xd1\xf6\x82Z\x03\xf7\x17\xb6k(\xf8\xf0\x98\x07\xa4b\x11\xa1\\\x15rs\x08\x8d\x06\xab\xdf\xe9jL\xa7D\xb9w\xfc\xfb\xc7\xeb\xb3\x07\xcb\x84]\xfe\x0d\x80u\x9c\xe9\xc1\xe3'\x036\x16\xffo\x98\x1e\xdc\xcd\xd5s\x9a\xc7\xf3S\xa3\xc2\xb0\x94\x9c3\xd3R\xd0\xe6\x0d\xe9\xdb\xf5\xc9\xc6\xe4\xdb\xcb \x90(\xbf43\xf2\x9b2\xa5U6e\xca\\\xc5\x8c\x15\xab:\xae7\x15\xe6$\xc1\xbfl5Y\x8aPQ\x9b\xfe2\x7f\xb1\"\xf1\x9c\x94\xd5\x04\x12\x9fD\xfc\x87\x81B\xe8\x1b\x89\xe1\x08r\xf1\xe5\xd4\xe3y\x84\xee\xd3\x9d\xe7\x19\xf4\x10\x1b\xccC\xf9\xf93\x9c\xfb\xb1\xd9\x0f\xca\xdf\xa0kKM>\xb1\xf8\xe5\x17i~\xc1\x14X\x17\xe8'\x1e\x88\xcd\x1c\xd5+\x929(\xb9)\xc9\xceY{hH\x97G\xf3\xb8\x8e\xd9\xdf\x9b\xc0r\x00]\xf5\"\x01;(\xea\x84\xa63.\x8a4\x99\xa1\x02\xe9\xc1\xcf\x15\x8bO\xc1\\w\xfer\xfa\xf6MT\xc4eE|LA\xb4l\x8c>\xe3\x05\xf91\x8f\xe7C\x0c\xf4-\x1d\x85\x0e\x84\xa2\xe4\x98\x01\x01\x8e(\x85\xc8\xa3\xfc\xe2g0j\xf5\x9dX\x83\x9c\x8d\xf5\x84\xdbl\xeb\xb9\x01\xfd\xe9\xc3a\x91\xf7\xa9\x83\x9b\xe1B2\x9cT\xaaO\x19\xf6\x8c\x94a\xafM\x19\xf6\x18e\xd0\xe3\xaa\xce\xbf\x04\x94\xa5\x15\xe3SC\x8e\x10\xa1\xd6e\xf6@:\x1d\xaf\xf9r@ \xba9\xcd\xe8@\x85\xbf \x9a\xfaGI\xc5\x1d\xa1\xa6\xd9Y\x00\xc7\xac\xd2\x04\xa6\xf4\xff\xb3\x10\x7f\n\xb9\x8b\xe2\x93\xf0U\xd1@\x1d\xf1\xb7\x1b,s\xc0ld\xe0\xa4\xd0Gfy\x99\xf0#C\xc4\x89\x13\xcfd\x9c\xd1\xa3\xadl\xaeVm\xfb\x0dS\xe0\x17\x12\x15I\xf1\xa5\x06,\xcdM\xe3,Oy\xd6\x9a\x97\x98\xf0\xcc||\x90(N\xd3\xfc\xfad]\xd47\x18;\xd8|||\xd9\xcc\x8fE\xf2\x1dJ\x1f\xf5WX\xdd\x04@es\xfdb\xc8\xc8\x1f\xfb9\xcb\xdfp\xc1\xa2k\xa8 \xcd\xe5\xd7y\xff\xe3+\x91~'\x9b\xe5s\xf2\xd3\xfbW\x86\x80P\xa0p\x92\xa8\xcdM\xb8j\xe8\xa6\x99]\x1eX\x1dma\xd0\xfc\x16l\x81\x19\x95\xcf;\xf7\xe4:\xee0\x08\xcdW\xbe\xb9m\xa9rfd\xd4\xde\xbf8C\x97G\x18\xfe\x1d\x8e!\x8f\xd6q\xe1'A\xf4s\x9ed\xbe\x17zt\xf3z\xebMZ'\x0c}\xd4J0\xe9\xd4\xd7\x03`V]M\xc0\x0b\x0d\x06\x99\x15\xbe\xfd\x1f\x07{\x86\xf75{\xbf\xf7\xc4\xf0\x9en\xbfj\x02\xdeg\xaf\x0fP\xa4^\x94\xe9\xc0\x14\xd0\x9e\xe7\xb4M\xab\xe1{\xe0\xceU#\xda\x02\xce73U'7Dx\x85\xd1\xd64\x1b\xb8>\xa1\x9bvg\xa7\x8c\xaa\xcb\xa48\xa1\x88\x9ed\xcba\xab\x82\x9c\x87\xeb\xefo\x0bc\x88V\xe0l\x95\x1d\x83EQ9\xf6/\xa2)\xc6^ny\xe2\xbf\x9d6\x82v\xa3Q\x88\"6\xf84\xa1\xc7\xcf\xc6\x8f\x8d\xeeJ\xa2pc\x1fC\x1a\xd2\x10\xf2 \xd4\x05v\x0e)Oo$0\xeb\x86\x9dB\xa90Y\xa0\xe1\x91~\x14l\x85\xcc\x0e\x0eI6Of\x14\xa3u\xf1R\xbb9o`\x00\x8f\xd3\xdf\x8e\x95Aq\xc3*\xf9\x08\xee\xd4\xf3\xd0\x9d\\[=\xc7\xd6\xfe\xb1!\xa5!\x8203\xa9Y\xe4\xe5Z\x7f\xd0\x0c\x86fM\xfb\xfb9 \xc6X\xb3@\x83\x04\xb1\x9fL\xc9\x19;)\x07\x10|`3\x168\x15\x83\x8c\xc3d\x12\xf9\xf29\x7f\xf9\x01_\x9a\xed;P\xe8{\x80\xf4\xbb\x88\xcb\xfa\xe3\x03\n\xa9\xfbT\"y\x90D5\xa9j\xbf\xb0\x9a|\xf08j\xa6\xf8\x9d\x80J\x04.\x01d\xe4\x1a\xe6\xa1\x06\xa8=\xf6\xd4*\xd6\xb06\xa3\xb8(H6gAu\x92i}\x86\xf6\xbdC\x00\xd6om\xa6\xf4\x94\xe3\xac\xfc\xc40\x1d\x1ez\x98\xe1T\x7f\x07j\x91L\x1bq\x058\xf8V\x98)\xb2*\xd2\xa4\xf6\xbdco\x00\x01\xae\xa0g\x0b\xbc\n\xa1\x1b\x8aB-K\xba\x9b\xa6{\x03G ^ O\xf7\x07j\\\xa0=\x86\x19\x85nl\xf8q\x8e\xe9\x96\x04 db\xe6\xcd\x00\xb2t\x90#\xd7 \x87\xeb\xa6\xe3\x8bu>%f%6e\xab.ZCl\xa8\xf4\xf9PFmP\xa9u?\x0b\xa7(&\x8c3\"\xc4\xb5-\x9d\x8d(\xf2fSG\xb0C\x96\x0c\x08\xcfG\x12\xb0l\xbf{O!\x83\xef\x81<\x85lw7\x10bYC\xb8\x87\xac\x8d\x04gRG\x8b$\xadI9~1\xccZ\xfb[\xc1O\xde3\xb9@@\xd3LI\x8f\x84c\x0fv\xf1(\xf7\xfal\x1d \xa3p\x11BE\x99^}{L\xe1u\x04K\xd8\x85\xeb\xb0\xd9\xd4x\x928\xecj\xed\x94\xbe\xb2\xc1q\x08uT\xad\xf2M:\x7f\x91_gi\x1e\xcf\x9f\xa1Z\x8deg%\xe9\xc2p\xdd.\xed\xc3\xfc\xcc?\xe8eK\xa4Eh\xc5\xf7\x86\x94\xe2Z\xa3\xe6\xb9\xd0\xa7\xeb^\xae\x1a\x8b\xe7\xfe\xcb+\xf1Rc\x0f\xad\xba\x1a\x0b\x9b`\xf9\xec\xcf\xec\x8c\x136\xc1l\x07Ri\xf8m\xf9\xbf\xe9\xea K\xce5)\x97\xe4U\x86\xcf\xde\x96\xb4\x02\x1cA\x8ao\xb8\xc3\xb7C\xc0\x1bh\xd6Zz\xdf\xd8\x11\xdf,\x11\xb2]Y\x7fq3\xda\xfa\xb2E\xad\xfb\xad(B\xf2\xeeg\x90a \xbaK\xab\x9b\x03\xaa\x8c\xf5,2\x08\x82\xaa\x01\xbf_\xf2\xc8\xe85\xfe\x95\xf9\xa4\x97\xa8[6\xd1F}Z\xf9\xe0;\x8d\xc5\xfdZ\xa0\xb5\x169\x97\x02\xc5\xbe\xd5\xbd\xbd\x11\xdf\xf6Ru\x02?\xf5\xe4\xae\xd2\x83\xa3\xed(op\xda\xe8\x83a\x02\x9a\xf4\xee\xdd\x1d\xc0\x8f\"\xdbI \x88?=2\xaf\x14S+y\x94\xad\xe3\xf2RRj f\xae\nUL,!\x17Kn\xa0\x97\x01\xf6\x8d2\xc0~[\x06\xd8?\x1b\x08C(Ng9\xcc\xeb2.\x1c\x0f\x14\x16\x82\xfdi\x00\xd5u\xc2T\xc5QQ\x92+\xe4\x8d3\xf2\xc9\xca6\xce\xe2\x8a\xc0\xded\xb0\x0e\x08\xd3,\x93\x10[\xdb\x84X\x91\xc2\x1e5\x02\x14\x96u@O\x1c\x0c6\xbf\x92\x04\xac\xf9\xfb\xf3gL.\xa7\xdd6q\x10\xc2N\x1c\x95,\xa4\x04\xa6)\x9b\x91\xa2\xce\x07w\xb9Z\x18`\xe0\x08\xf6\x1d\x0d\xb1.J\x12_Zk\xda\xef\x87\xe5\xb5$\xef\xff\x11\x9d~\x7f\x1e\xda\xfb\x17\xb5\xe0\x9a=r[3\x12\xd5{\xcc\x1c\x9fdu\x08\xf4\xe7h8=\xf9u\xc1\xc4\x87\x1c;\x00\xe1\x89\x1d\x08,\xe3lmYjlm\xdfa\x1f(\xa7_<$|\xc6&\xe13\x1c\x96/y8+\xce\x81\x19\xbb\x90<\x9a\xb1\x1f~\xb8\x88\x08z\x92,\xec\x1f\x86\xca\x0ex\x14\x82\x8f\xf9\x1eJ\x8c\xed\x82\x071\x06y\xa1O\xcbt\xf8\"\x0b$\xe0\x1c\x90Q\xb2\xab*2\x8aa<\xa1{]=@|\x16\xaf\xd4\xadw\x07,\xa0[A\xed\x1a HU\xe4YE\xbe\x84\x82\x1c|\xf7\xebn\x8d.\x0598d$\xa47\x13\xa3\x0eP\x14\x84\xdc\xc1\xa1\x1b\xe4HT\xef\xb7\x89\xc8\xfexP=\xfauA\xc5\xc7l\xc9\x0f\xc3\xc0\xe0\x82\xbe\x8c\x8c\x18\x9c\xc3Da\xcd}goN\x82\xe5\xd0\x01\x83\x10$.\x1d;n\x04I\x0b\x0e\x9e\xe0b\x1e\xb0\xbb\xb4\xb8\x9e\xad\xfc\xfd\xc3\xc0\x10\xafFW\x9ai\x1c\xda\xa7\x01w\xb8\xba\xcc\xc4\x8b\x8e\xdd\x01.\x87\x0eh\xce\x1a\xf4s\xae\x94c\x19%J\xc5Z#\x08\xf8\x8f\xe7\xf9\x1c\xc3\xc5\xf2\x9fL]\xc5L@ \x97{Q\xde\xc6G\xf5A\xa8\xbb\x99S\x0b\x1b\xa5\x03\xda \x19\x8b\xf2\xcb\xd1\xeb\xf3\xd0\x02'Q\xeev}\xf0\x16\xd1\x0d\x9c\x89\x0e\x9c\x89\x04'}\x1cv\x93\xcfw\x0b\x82\xf1\xe1\x81\x1d\x8c\x92\x8c\xc6\x17\xe5\xa6\xa8}\x8f=\xf0\xc2^ \xefna]X\xf0 +y$\x9b{#\x86R\xd5y1`\"\xa9\x07\xf9-K\x93\x871S\xa7\xc6o\xa7\xf4\xcc?x\xa2\xd7\xf9i\x02\x18\xdc\xea\xd4D|\xa0v\x85t\x03\\\x16\x92\x10\x07'%![(\x8d\xdbnVB\xa125*{\x06%B>\x98\x07\xfe\xcfU\x9e}\xfe\xb4N?\xdf\xc4\xeb\xf43\xa6\x00\xfdx\xf1\x80\xf1\\_|\xb9\xd3\x8d\x10\xb2\xad9\xe1\xc3\xfd\xffxk\xc2\x81\xc1\xb4/1I\xa0\x06Q\xfe\x1eCi\xe2\xd5\x97\xf7\x00\x83\xa0\xe0M\xba]F\x16\xe6\x04\x99`\x02\xddkTS\xe3\xb3\x01\x13)#\xa3\x85\xbaR\xba9\xd8\xbc\x9b\x00\xcfti\xce\x95\xa5\x19GZ5S\x991+g\x9d9\xaa#i]\x0c3\x19\xeeW\xa4\xfc\x0b\x85\xf1\xd2\x8d\xcaiL\x85\x9d\xf1\x19i\x94ua6\xca2\x0db\xee0\x08Q\xb9e&\xeb\xd4\xfaJ\xdf:zAY\xf6\xb8\x88\x9b4x!\xe1\xc5\xf3\xb9\xb0\x8a\xff\xfc\x99\xb2#\xeb\xfc\x8a\xb4\x9f0\x06\xc5\x10\x99\xc6\xb8/;\xc6Z\xa6 ^\x0d\x82\x0f\xa7\xff\xf93\xd0\xb9\"$\xd7\x9b:\x16\x90D\xc9\xfb\xc6\xd1\xd4x=\xd8\xcf\x15o\xdfo\xe0AA\xd7\x07\x80|\x8a\xb7\x16\xbag/\x08)\x9a\xe7n8\xb4t\xc0\xa1\xaf\x8e\xc87Fcl\xb3\x87\x06\x1f\xe1\xa9\xbc\xd6Z\x92\x1aM\xaf\x7f\xb8y\x97'\x19\xa5\x08\xfd\x18\xb8\x00.n\x0f\x82\xbcw\xb2\x86\x86\xda\x88\xd1\xbf3\xff\xbas\xa3\x84\xbe\xecz1t\xeb\x7f\xce_\x1ej\x0d\x06\xae\x87\xec\x10N\xc4\xa7\xda\xdb\xdcO\xe26W\xf7\xf2T|\xaa\xb5~x>d\xc3p)>\xd5:\x0c>\x13o\x1f\xf7\x8d\x18\x9a+\xdc>4\xe3\xf9|2,'\x8b2(3\x81\x90\x9b\xe8>\x1d0\x1c\x1c\x92\x9b@\x91\x9d\xb4\x154\x08\xd6o\x89\x93\x85 $\xbaw\x94\x8a\xde\xe9|9a\xb6Ny\xfb !\xf5\xba\xab1S\xba\xe8\x1a'\x8a8\x899\x19\xca\x86\xa3\xe5\xdc\x06\xdd %\xad\xb7!L\x87\xb6\xa3\x89\x9a\x9b\x0e\x1ae=\xdb\x8a\x0b\xdd\x9a\xdaV\xf1\xaa!\xb6\xe6\x11f\xcc\xeb\xf85\xa9c\x1c\x1d\xa9\x00\x83}\xadI\x8d\xaa\xcd\xb5_3\xd5B\xc7\x8f\\\xd0\xfc\xcf\x9f[xEk^\xe9)\xd7U\xc8\x9b\x15\xe9l\xafl00\x9e\x85\xf5Y\x10\xde\xf1\xc8m\xc0\\v\x0e\xc7a<\xbb\xd0\x83`)A0\x1ee\x14\x06\xe0\xc2\xc8\x00h\x9f\x8a\xdd\xd7{\xa9a\xcf\x8a\xb8$Y\x8d\xa1\xba5<\xda\x10\x83\xd6\xf1\xf0\xac\xed\xf1\xaa\x95\x84\x9aG\x98B\x17\xf1\x95]\x9b0\xbf\x97\x92\xf9\xbd\x18aE\xfbE\x9f\x18\xd4\xc3\xa2s\xb0\xa5O\xf1\xba\xef\xfd\xa3\x01\xc6\"\x8d\xeb\x9ad\x13\xd0\x04}Yl\xd2\xf4\xe6\x8d\x08g\x84s\x1e\xe1;\xbe\xf0g~\xea\x93\xae\xf6\x1a\xf4\xe3\xc8:\xddh<1\x93\xea]\x99\xaf\x93\x8a\x8c\x18D\xc1\xb5\x86s\x9f`,\x14\xa7\xb1p\xcf\xae7\xe4\xda\x117\x86\xe3\xa3\xf0\xa1\xe0}m\xa5U\xb5\x01\xb8\xa8\xdb`\x08\xcf\xc1U\xc4j&\xf7\xaeL\xd6I\x9d8kA\xdcg\xb9\xf9\xcdg\x99T\x7f\xa9\xf2\x8c\xcb`+\xdd\xfb\xe7L\xde\xed\x89i\x16\x84\x92jn!/\x9b\xb4\xdc`\x1a\x18\xefQ\xe3\x1b\x9fT\xaf\xb9&b\x02W\xba\xd7\xcf\xe6s\\\xb0\xa6\xdaZW\xed\x7f\x92\x8c\x94q\x9d\x97#\xe6\xf5\\\x92d\xe5\xfb\x97\xcd\xd7ns\x13\x1fL@\x93P \xa9\x18\xdb=\x81B\xf7\xf2\x84\xe5\xaeu\x1eq+x\n~\xdc\x1fc\xeb \x95\xdf\x15C\x1f\xa9\x0c\xfd\x9dRap#t\xa3\x8e}A\xae\xb4'\xdb~\xba?\x94fm\xf8\xd3'{\x03\x86M\xb6O\xb7\xcebw\xb0\xf7\x9d\xf9\xd3\xff`s*q\xbfw\x07\xfeJz>\x8c\xe5o\xe8;\xae\xe8k\x97\xbcv\xcfF]_\x9d\x850\xb8N\xea\xd5\xf3\x92\xccIV'qZ\xc11xI6K7s\x82&`U\xbc&\xf7Y\x9cx\x8d+\xb6`\x03\xc4z\xdb\x14yd@hB\xe7\xbe\x81Pm\"p\x9d9\xbd&`G]XML\x01\xecX\xf5\x1e\xb0\x8cyTA\x8d\x177,\xfc=\x9b\xd1\xb6&\x9a\xd0g\xc6\xcf\x06\xd2\x1b\xcd\x9a\xe5\x99h\"\x88\x01\x8aw\xaea\xe0@\x95c/\xf2\xb9>x\xa7.\xcb\xc9\xef\xcc\xbf~\x85\xdb\xbdd\xe8\xb2,\x1e\xf0\xe9]\xc7\x97,\xb7\xf2_N\xdf\xbe\x11N\xbd\xb3\x94\xc4\xe5\xf3x\xb6\"6\xbb\xd6**\xd2\xcd2\xc9\xaa\xa8$\x8bJ\xf9\xb0cB|\xeb\x9aQ\x1eT\xc2R\x9b\x17J\x10\x97z\x95\x18\x92\x99\x9c\xa0X\xd8\x19\xe0<\x9f\xe1\xf0X\x14]\x12\x84\xdd\x19,TX\xf8\xd7C\xeae\xddf2\x84;\x01\xd3f\xba0\xe0\x97~JB\x8c\x9a\xb6\x07m\xd0i\n\xeb \x01N\xd5\xb0cI\x81\x931MM\xd3X\x13\xf2>\x08\xf5\xdf\xad\xf5\xdf1\x9cN\x08~\xc7\x8f.$\xec\x85\xb6~\x9c\xa6o\x17A\xd8\x8d\xf9n\x06\xb55k\x9b\xbc\x11\x1a\xa6<\x17qE^\xe4\xb3 \x9clCi\xf8\xf0\x07IfW[\xa1\xe5\xbdE\xa1\x82\xfe\x8b\xa4\x9aQ1$c\xec\xaa\x86\xebmj\xf3\xd5y\x1d\xcf\xca\\\xcb?\x8b\xb2\xce\xe7$\x15\x94\x86W\xefGE\x01\x854\x9e\xbb\xe4E\x86\x8eos\xdc\xac]b\xf4mv\xd5\x1b&\xdb\xb8\x1d\x8b\xf2\xa5\xee\xc7\xa2\xb8\xba!\x8b\"\xcf\x8a\x9e\x07\x87\xc9\x16\xb4[\x98\xeb\xa0[\x8fc\x1c:D\x91#\xb48v\x882\xac\xf2\xe6\x8e\x1e\xe6f\xb4>\x1b\xa283D\x9d\x0f\x9c}8D1(\xd2\xfd\x00&0\xeb%\x13\xb3\x9d\xe6\xa0\x90^\xc2N\x083\x8b9\x94pl1\x1cd\x8bE\x92\xa2{W\xff~\xde\xc4\x8fT(\x8c\xbe\xee\xaa\x1d\xb0\x0b3\x17\x19R\xdc\xb1]\xd2\xa3E\xfa\xcak9\xc66}\xd1\xd7^\xf2\xa6U\xc2\xa5\xaf\x89\xf1\xe3\x9dy\xf9\x0b^\xdb\x91\x97?g\xebr\x99\x14B\x97\x87<\xa7\xbe\xf25\x8b\xe7U\xd7\x1a\x19\x1d\xb8\xc1\x13\x89\xf8Ibd\xfai\xad\x13tc\x0e\xb1E\xbc\xd5\xbe\xa6\xffl\x04\x9d\x0b1fN\xed\x97\x18\x91\xd1\xcck\x8c\xe03\x1cy\x8c\xdb\xc0?\xe1t\xbf\x9b\xfa\xbd\xcfZn8\xf7\xa8\xb5\xb4\xe2\xd2\xfc\xbe\xe6\x15K\xbbY\x19Rnf\xfe\xd6\xba\x83\x83\xbd\xad\x93\xbb?\xd9Z\xfe\xdfZ\xfa\x1f\x18\xabU\xf6W\xdf\xdc\xb9\x10a\xe2\xc8\x0d\xfaOy\xa2\x9b\xd9\x03TAE\xb3\xb8\xa87%9\xad\xe3\xd9\xe5\x872\x9e\x1186\xbd\xe1\x04\x9d\xfe\x1b\xcd\xf2\xac\xaa\xcb\xcd\x0c\xdd\xdf'\xecYEkR^C\xfan\x06\xec\x99\xe5\xaaA\x1fx+k\x05\xde*Y\xe0\xad\x92\x05\xde*ww\x03\xc8\xa6e;\xf0Vi\xe0\xacqpkRU\xf1\x92`\xae\xc6\xbd\xb3\x90\x99\xd0\xd4\xad\x93J\xa7l7\x11\x8c\xac\xb9\x8bW\x9dUC\xf5\x05\xcf\xedC\x8f`\xf5\xa9\x02:\xfai\xd8q\xa8\x1a\xad\xf5\xfb\xed\xf12\xa9^\x96\x84\xa47o\xe25\xb1\xe7w\x90\x86\xe4S\xd2\xf2\xc7\xd1\xae\x1d;\xc4\xa5\x0b\x9d\x91\x80\x97Q\x92\xcd\xc9\xa7\xb7\x0b\xca\xa5\xfc \xee\xefS\xda\x9d\xcb\x87Y\xf30q\x0d=)WZ4BX#}$\xb1\x12e\xf4i\xf2\x1a\xb9K\x17M?\xc7:\xb80 \x1dX\xe5\x85\xa0f5\x0b\xc1\x13\xe7\x05\xfe\x10\xf9\xf8^\xb4\xbf\x98\x89\x90\xb4\xd5\x83j\xb6\"\xeb\xb8\xfb\xb4\xd5\x88\xf2\xbc\xdd\x95\xda\x0c\xef\xe8\x946\xa7\x1f{\x82cg\xfd= \x9f\xe2u\x91\x12\xefl\x0c\xc6v\xc8\xf7\xc3/ \xc3\xadW\xff\x96*X$G\xc6\xedp\x07\n\xda\xfe6B\xf3\x86~03\n\x87\x8cG\xf9\xc3`\xef\x8c\x9c\xed \xc5T\xef3r%\x91>\xb9F\xab\x8f~'\x1d!TP\xdd~E\xb1g\x90r\x97\xa4\xca\xd3+\xe2w\xb5\x82\x96}[G\xf3\xa4\x8a/R\xc6]-\xe2\x19\xc1\x00Q\xdd1\x84\x18]\xfb\x92<+\x92\xeaC\xbc\x94\xd9C\xfd:\xd0G)\x1e\xa2A\xb34!\x99\\\xc1Nt\xb7\xdfL\xcbxh\xd62\xfah\xed\xffm\x80\x91\xe4\x1e\x05\xba\x8a\x82\xa1\xd4\xa7\xf3\xa9\xc4[\xad\xb7A\x8a\xbb\xf9;\x03SY\xfa\xa9!\x8cb\xe6\xef?2\x06Q\\\x0cEP\xd4\x86\xb0[17\xf9'\x86\x00\x8a\x99\xff\xad\x8e#^s\xbe\xb7\x0d\xd8\x1ce\x0d48\x94\x82A\xae\x06CL\xe5\x8f\xe8\"\xc9\xe6~\xb6I\xd3\x90\x7f\x16\xf0X\x1f\x14\x9f1m\xad\xd2\x04\x7f|\xba\xb9\xa8KB\xdf\xce\xd5\xb7\xe4\x13\x99mj\xb4\xd0\x11\x7f\xd3\xc7\x9d\x18\x8fi\xebA\xabB\x13\xf01\xed=\xa4\x15\xdbJd\xe5g\xc82\x85\xb0\xb3\xe1\x87M\x92\xf2f\xae\xa2w\xcf\xde?{}\xf2\xe1\xe4\xfd\xf9\x0f?\xbd\xfa\xf1\xc5\xc9\xfbS\xd3f\x82#Xi_\xd0\x0f.h\x9b\xef\x99\xd4\x84\xed\xaa\x0f\x10r$-X\x9f\xfd\xdd\x90\x17\xaf\xe6\x13Xc\xe2\xfb\xf6\x86\xc0q+-\xc8\xac\xd1\xe2\xf1\xffY\xd8\x17\xfe\x00\x9d\xfc\x98 \xc5\xfe4\x99\x8e\xdao [\x14\xa5\xbd\xcbm\x17o*n\x0d \x84`\x1d(.\xe8y4\x96fe/l\xf4R\xc8\xc3xt\xef{\x83\xbe\xbb\x94\x08WRi\xcf\x02\x88\xd7\x06\xed/\x89Vy\x85\xbe\xba>\xff\xf3\x082\xfc#@ 3I\x80\xbf\x17\xbf\x8e`\xca\xc5\xdcY\x9e\xca\xe8(\xde\x84\x8a\x13^p\x86_^\xc4\x15y\x17\xd7+\xfe\xa9\xfcy\x04T\xba\xb3/\x80\xaa\x03\xc9\xc7\n\xca\x16e\xd3\xde\x80\xd01\xfc\xe9\xfe\x17\x98\xb8l\xadW{\xb2\xf7h\xdbO\x0f\x1fn\xad\x1f{\xb27` \xf4\xef%\x9a\xa9\xbf\xee\x9c\x1bG\x9bdv\x01\x89\xb8I \xd5\xeb\xb8\x18\x08.\x9e\xc3@\x84\xf0d\xc8\x1dX\x1a\x0chu\xbe\x9b![\x83j\xc8W8\x15\xedj\x87$\x82\xa1\x1fj\x9d\x85\x17C\x9e\xc42C\xa86h\xb4\xe0\xe5\x0f\xf6\x86\xdc\x81\x87Y2E\x14\xbd\xf6I@E\xc1\x02\x8d\xb6\xad\xaa\x1a\x11n\xfdP+5\x89x\xeb\xda\x81\x8b8\xda\x87\xda\xb7\"\x8e\xf6Cm\xc3\"\x8e\xf6C\xed2 o\xf0\x87Z\xafm\xe1\x0e\xfeP\xeb\x98\xed\x94\x08A\xb9\x00\x1e<\x80;\xf9\xb5\x98\x98K\x82^.\x12\xf6b\x98\xcdd,\x92g\xf1'\x99\x93\x8b\xcd\xf2GrE(\xe7\x98d\x8b\xdcR_\xde\xfaO-\xael\xac\xe2\x9f\x93\xaa\xce\xcb\x1b\xb3\xd5\x9a(\x8cy\xb07+|s\x1d\xaa\x16\xcc:|.Y:\xdb\x07U\x1dSi\xc46\xd4\xc2\xb5\xbd\xc6\x0c\xc3\xd2\"\xaf\xf8\xa1$d\x82\x9b\xea\xdc,4\xa9\xa5Z\xe5\xd7/\xe8\x02\x9a31\x89\x12\xa7\xa93\x1c\xd8\xd2Q2M\xa5 FY-h\x91&\x17\xafI\xbd\xca\xe7\xd5\xa4\x8b\xab\x9dd0\x14u\x035\x10\xbcu\xdc\x1d\xc6\\\x93RJ\x14\xca\xc1\x04\xfc\x06eI$\xb7w\xbe$5S\x16\xf0\xceE\x05n\xf3\xad\xd6\xe3\x8f\xfa\xd5Wq\xf5~\x93\xc9\xaa\xecg\xbf\xdau\x19\x17\x05\x99\xbfk\xce&\xfaT\x98\xfa\xac\xe3\xc2\x97\xd5X\x1d\xa5\x89@\x84\xe4\x91\xc0\x89\x1a\x13j\xd1\x01\xc7>fD\xd4T\x8c\xe7s\x7fz\x166\x1cp`\xf9\x80\xe3\\\xf3\x11\x7f \xbf\xdb\x14\xf3\xb8&\x1c\xec\xbe\xda\x94\xde\xd2`\xd0\x11\x87\"\xc1\xbcA\x02\x12\xc2\xd4L\xbd.\xc9\xcd\x04<\xa4L\x03h\xc7Y\x03\xbb\xee@\x14\xe4\xef\xe94\x1a\x9a\xc7\x8c\xf5m\x1f\x82z\x9bV\x87Z-1\xbbBc\x17j\x19\xaa\x8c\x8f!\x83\xfb\xb0\x0f\x13\xd8\x0bBd?\xf6\x9fB\x0e\xdfC\xf6\x14\xf2\xdd\xdd\x00\xcai\x8e73\xadK\xb6\xdc\xc1%\x17\xdd\xbfy\x94\x95 J\xf3e\x13\x86Jc\xbd\xa1\x16\xb39\x8b\xc1Fd\xe8\x90a\xcbtE\xca\x8b\xbc\x1a\x8a\x04\xb1\xd5B\xc9v\x99\xf3_{\xd9l\x0d\xc0\xbf\xcf\x82M\xbd)\x06\xce\x84]\xf0\xce(C\x7ff\x8b\xca&\xcaWX\xcb\x86*\x8dYNKx\x05P\x04dAE\\lk\xd4\x827\xb9\x83*\x13Qr\x83\x08\xd0-B\xfa\x99*\xf4\x99\x9ex\x98F\xb8d\xd70h\xf4\xde\xab\x10\xc0\x04t\x04\xda\xc7\xb0m9\xbf\xc9Qk0\xe9G\xc4\xab\xca\xad\xdcu\xb7\\m\x93P[\x14>\xd1\x9d^\x889\xcc\xc5G\xaeHy3\xce\xb1Y-R\x86<\xe2I\x98\x9d\xbe4$\x1bkU\xb1o*\xde\xb7T\xd4tL-K?\x0f\xc1\x988\xb1[0\x16D\x08\xb3\x10\x16!\x14\xe8\x14\xbf\na\x8d\xee\xab7\xf6\xb1\x80n\x85p\x1a\xc2\xf3\x10.Cx\x16\xc2\xdb\x10\xde\xb9A\xbe[,+\x11o;~\xd0\xadL,V&\xdeje\xbae\xdb\x95\xea\x16\xcch\xdd\xa7A\xf9\xa8\x00\x16C%\x96\xf9r\xb6[\xa4nq\x0fk1T\xec!*l\x85\xa5b\xb8$7x\xd3\xbf\x98.T#\x9a;\x07\xde\xc3\xff,\xe0\xf1\x9d\xd7L\x0f\xe3D\xe3\xd9\xe9\xa3>\xf9\x92\xdc \x0d1%.u-,\xe2\xff\x97o\x93f\xa4\x8f\xbfl@\xe0\x96\x11\xc4V\\\x93H\xd9\n\x9a\x89)\x98\x1b\xa2\xe2m1\x9d\x9f\x85\xa8G[H\xab+\xd5l*\x08Q\x8d\xa6>\xc2\x93\x1dC\xa9\xcc\xf1\xcfu\x88\x87B\xa2\x0dD1\x9b\xe6\xd17\xdf\x94dq\xc6\xb2\x95\xee\xec\x85\xa8=\xdb\xd9gf\xbf\"\xed\x91\xa4\x99\xfb\x0fC\xb4\x0d\xee\xb8\xbe\xd0\x9fU\xf3\xd3\x98 \xd3\xb58\xa7C\xb2\x15J\x1c0\xce\xc5'8\x82\x13\xc4\x1d?\x08\xa2y\x9e91r.Eb\xe4\xe1\x7f\x18m\xc0\xe8&p\x04\x9fD\x10\xf9\xe7p\x04\xf9\xf4\xf4,\xc4\xf8\x95\x0b!\xf7\x9c\x06!\x86\xac\xd4\x9c^\xcf\x83\x10\xdeb\x96\x17\xc4\xb2\x10\x06\xd3\xfa\x8e)\xf1\xd8\x84H\xb6\xf2\xaf\x04\xf5\x9dg\xff\x0d&K\x91^W:\xb2\xf6\x16\xe5\xb6\xd9\xf4\xed\x19\xd2\xb4\x80Y\xb8\xa5d\x19\xd7\xe4\xff$$\x9d\xfb\xa5\xcf\xd8\xd6\"\x08\xc1\xab\xf7\xbc\x10\x0e\x1e\xdd\x05\xcdr\xc9\x81e+\x18x\x9aJ{\xa7,d\x0c=\x83\xef\x1c\x1f\x0e-)\xb8\\\xcb\xbf\n>P\xa0\xbd\xc3\xcc\x06\x19\x8b\xd0\x96a$\xbbw\xff\x0d8K\xe9r\x80\x87\xfb\n\x0b\xf8\x1c%\xbcK\xcc\xddZ\xdc\xc5\xfe8tt\x15\x1c*\x82Q\x89\x9b\xf4\x8b_62\xb8CV\xf0\xf0Ny\\\xc7\xcc\xaaC\xe5\xce&v\x07\x94M\xb2\x91\x87\x98\xb3\x153\x0b\xc6\"c\xde\xc3\x80\xf3\x9e{\x8c\xf7\x8c\xadi\x02m\x85\xc9\x1cw \x9b\xcbq?Ty\xe1\x87\xfb!\xec\\P2s\x12\xf1]\xa4\xfc\xddM\xc05\xb68\xa5Hs)\x9426c>\x0ca\xe7\xfc\xce\x89\xe2\xc3;\xd8\x81\xf0/D\x14Y\xde\xbd\xeb/\x9b\x14[\xc1;\xd86\x92D/\x92,\xa9V\xfe\xc3\xc3;\xc1-\x87D\x89\xb6\xd2\x1b\xd9\xde\x9d\x8c\xec\xf1\x97\x8dl\x1b?sS\x913t\xf4?7\x95\xedp\xf26\x84\xd8\x9e\x98\xd0V\xa6Tj\xa7$\x97\x92\xaf\x87\x8f\x1dB\x1a\x9b\xca\x94\xd2\xbc\x10\xa9\xc8\xc3\xef\xdc\xee\x0e\xba\xc5\x10\x15r\xa8\xdc\xb2\xc4\xf1\x9d\x8b\x83\x9b D\x9b+\x0c\xc9\xcb\xcf\x8d\x82\xeb.\xe6\x8a\xeeBj\xe2\x1f\x852f\xac\xa2\xba\xc8uw\xf8\xdd8mc\xf5\x19\x88\x81[`1\xa5\xd5\x18\x84x\x8d\x1e\x02w\xa1\xae(%\x97\xb4\xa5zb;\x9a<\x1e\xdf\xf9N[\xc2\x11\xac\x85\xc6\xa1\xec\x88m7\xfeR\xbcZ\xf28\xa3K)\xc1\xed\xefo\xb3J\xfb[p\xa4\x02\xdd$l\xb7\xd0En\xc1\x97\xb1\xf1n\xc1`\xcaq\x1el\xc1Pn=\xd0-N>\xb9W\xf7\x1fQ\xe8\xb2\xd4\xd3\x9cA|\x14\xf0\xfd\xbd\xc7\xf6w9\x9a?d\x12\xfa\x16\xfc\xa0\x1c\xd6\x81JO\x0e(\xff\xb7\xa0<\xdfJ\xe1\xffV[\xf2\x7f\xce\x99\xc4\xbb\x85%3\x16c\xa2\xfc\xdd\xd6\xf7}\xe5\x97j\x8b~-Z\xc1\xf8\xb3\xf9\xb8An\xad\xa0\x91\xee\x8c\x9c\xcb9\x18\xcb\x7f9\xe73\xef\x96^\xcfc\xf9+\xd6\xf3\xc8\x93\xe8K\xf8'9\xe2\x91\xfc\x92\x1b\x0e\xdc\x86P\x8e\xe7\x87\xa6\x8fB$(t\xf7\x1e\x8ca\x7f\xa6\x07\xc8\xee\xd0Mu\xe0\xc8\xee8\xb07\x16k\x8a[\x9f\x04}\x03\xe2\x9c\x99\x1d\x96\x81\xcd\x8a\x18\xa4=\xe8\x9bxM&\xc0\xa3.|\xfe<\x14~Q\x94V\xe8Y\x95!\x92\x8f\xfd\xdc2\xfa\xd1Q\x8d\xecVN\x94(\x8d\xb6r\xb2\xd1@\xbbw\x9b(\x8aE\xe4\xaam\x16\xdb1\x1eU\xbc?\x9c\xcc\n\xa4\xf7\xd6\x92\xd4\x82\xd3\xac^\xe6%k\xce\xaf\xd5\x8c\xae\xbf\x0d\xd0U\x83\xec;\x84\xbd4\xec\xecX|\xb72\xd8J\xc9K`\xa1\x0c\xb9\xd2\xfb\xcc-u\xa7Z$\xe8q\xe8\x16\xe0~\x05\xe8. \xc7hno?\x02\xb8\xd6\xf9\xa9Q\x13\"\xd9\x11\xa5\x06>\xb1\x1c\x1f\xaa\xd7n\xcb\x1f`Z\xf3\xfc3_\x11\x14\xef7\xd9\xf3|\x93\x0de\xb0\x1a\x0d\x0buB]\x98\xfbDl\xb0\xaf8)\xde\xd7\x87d\xc8 \x7f\xf4\xb4\xf4K\xdc\xcc\xcbm\x951\xe2\xcf\xb4V\xedeX\xf2\xaa\xaf\x08\x0fA\xe7^es\xf2\xe9W\x03\xc9\x87\xa4\xc0\xe4\xcbj\xe7N0\xf2\xb2\xcd\xfa\x82\x94\x1e\xec4\xbe\xd9p\x0c\xf7\xf7\xc1\x94&\x0d\xee\x04Lt\xb7\xde%t$\xbdkX\x83\xbb\x1f=w@\xd8\x96\xae9\xd8\xc8\xb6\xcc\x92\xc7\x916_C\xd4\xb2\xb3\xb6\xbf\x87\xf2\x9c\xa7TG\x1f\x8c\xa1x\x91_\x08+v\x80}E(\x0d\x03\xa5a\xf1\xda\xe9;\xe8f\xe1y&F\x1e\xach\x8d\xd7\x0b\xec\x1f@\xc6\xbd\xcd\x19Dm\x8bE\x0bf\xd8\x19NY\xa1\x16\xb4\x9b\xd0\x1aqKV\x025\x82\x19sK\xf0\xbb+\x00\xde\xff\xcck\x88!\xcb\xb3\xfb,\x0f0\xf3\x1b\xf3Bp\x19-\xf0!d\x91\xf4\xf1b\xb1\x83\x1b?.1\xf5\xb0\xc5Ys\x1e\xcb'2=\x91\xf0\xd5\xec\xb19\xcd\xf7l\"\xad\xf7\x1fV$s\x82+h\x8cM\xd5\\\x1a\x1a\x88U\xd2\xcd\xca'\\\xed&\x86\xbb]\x7f\xe2\x14\xd0\xf4\xc5\x96E\xb2\xc3\xba\xcc\x15\xdd\xe2\x96\x93D-\xfd\x8c\xc7]\xfc\xb463,\xb0~\x0d\x8e\xbc\x03\x991D\xc3\x06\x97v\xe6\xebvL\x16\xb1\xd2hO\xd1qJP^!\x19\xd5\x19\xe3\x88Z\\\xf5\xae\xc8\xb4\xbf\xdc6xdA$q\xba+\xfesM\xe2)\xe6BW\xc75\xc1\xf0\xbev\x14p\x0c\x1ebY\xe1\xe1\x11\xb3\xc0\x14\xd8\xaet\x81mvp3dJ\xa7\xbf\x02\xb2\xb0\\\xc6\xdb\npV\x84iq[]:\xd5\xc4\x07\xb4\x81\xe8{\xd8\x13!n8U\xfeP&d\x0eu\xce\xf3;C\xdc\xf6\n\x86z\x15\xd7\x90T\xd9\x1fj\xa8W\xa4$;\x9e\x0c\xb7\xd9\x1dFU\xa4 \x95\x18C\xd8\xff\n\x00\xee\x11\xdf\xaf\x05^'>\xb5\xd9c\xfc\xafN\x14\x19''!\x11eN\xb7M]\xb6\x154S\xcd\xac\x95m\xfb\x070\xbe\x81\x06\x8d\xd9\xfe\xe9x\xbb\xda\xdc(\x03~\x890\x0e \xee\xfdkB\xa5\xaa\xe5k\x1c\x07\xaa\xd2h\x0c\xee90\x90\x8d\x97\x18\xa0\xe6p/\xd4\x0bBH\xe1\x04\x15h\xa8\x1c\x93'\x05\x95k\x9eW\xb8\x1f-\x01\xd8\xbf\x00\x1c\xcf7eI\xb2\xad\xa0\xe2\x08\x11!w\xe8\xb4u\xfc\x15\x1f\x04\x7f\xfa\x95tG\xfd\xfeG\xccu\x14\xf5\x89\xf4\x92\xbb\x95\xb6\x9b\x00\xe6\xd7\xb0\xfbU\xe8q\x17\xf4#\x00b\x83\x87:\x97\x99\xda\xc7W\x99\x05')o\x17\x1fn\x8aQ:\x80\x11\x1b[\xd8<|\xa5\x8d\xf8cr1b\xe0\x8e\x83F\xf07a+\xee~\xe0\xe7K\xf25t\x8f\x0d\xcb\x8a\xc9\xf1\xdb\xdc\xeaW\x80\xbf\x12\x14\xe3+\xcc\x86m\x82&\xfc \x9d\xd4\x90\xb8\xb4\xf54\xaa\xadf\xe1\xbe\x07z\x13\xa9\xe8D\xbe\xce\xd9\xc4\x83\x8f\x8c\x99\xc8\x98Y\xf44\xe8\xc6\xc3\x08\xfe\x04>;\xd1\xbf\xc6,gi\x9e\x8d\xa2X\x8e\x93\xfc\xcb\xe9\xdb7<@\x1feMsE6\xfd\x1a\xe7\xab\x88\x8d5b&\xb6\x89H\x97lb\x9f4-\x84 \xce-\x81W\x93\xcc\x97k.\xda\xac( a\xfbH\x14\xd09\xfe\xedW\xc6\x99sM\x19\xc0\xba\xb9\xcf\xb5\x19\xc9\xa0R\xcf\xc9\x11_D\x8ck:h\xf1\xec\x0e\xc2\x06\xed+\x97\xda\xa8\xdc1\xb8v\xb7\x88}i\x8a\xb0\xa6+}\xe9\xe4\xeb\xf6f\x87\x85\x88\x96\xed6\n5\xb6+\x9ekN_\x89\x00b\xf8\x1d\xfba\xfd\xce=\xca\x04\x1b\x8d\xaa\x8a\xf5\x13\x11\x0eI\xa0I\xa3\x9a\x0dB\xf5\x9e\x99\x07\xb3M\xbed\x131]0\xbbV@\x9a\x8c\x11C\xd5\xdfx\xd3\x16\xb6\x1f\xb2\x0c\x1e~\xef\x19Rl\xca8k\xea\xff \xf6\xf7\xb4\xd7\xe5\xd6\x98\xbc\xa2\xb0\xf5\xcb\\\x17O,\x9cT\x99r?P\x99\xf4\xc3\xf7\xfeF\xfepE\xa0$\xf1lE\xe6\x10\xc3*.\xe7\x90&\xeb\xa4\x86|A\xc7\xcbMT\xa0\xdcd\x95g\xa3V\x0eD\xa2DW\xb9>\x87.5\x93zK\x03\x97}&\x92\x08i\x9b\x19oy\x00\xe3\xac\x0f\xc0\x01\x00\x00\xd0_\xfe8M\xfd\xcd\x97\x8e\x0fi\xa0\x88\x97\x13\x82\x0cmfm\xe56p\xcdN\xd0-\xdb\x91\xb4/\xd8\xa9\xbc\xc3Q\x03\xcd:Xv\x04\xa5}\x89\xc4\xb9\x9aE\x1a]\x85o \xab'J\x8e\x0dtu-p\x1f\x1cla\xc7]\xa6\x95\xaa\xd9\x97\x0bPD\x11\x87\xc7P&_]\x89\x99\xf1\xfe\xa8o6\x8e\xd1\xa3\xd4\xe2\x0e\x06Qdh\xb2\x8a\x99 w\\\x08J\xbf\x0e\xd9\xaa\xfe\x98\\\xf8A\x10<\x85\x1d\x9fB\xc0\xaf0\xa9A\xcb\x8c\xff)\x87M\x00\xc4\xaf\xf8\xe5\x87\xf3`\xc6\xdft\x89\x12s\xcbi\n0;\xc5\x11\xe5\x16\x16I\x16\xa7\xe9X\x80\x8d\x071-; %\xd7\x85bL]Hc\xeaQ\x8dm;l\x10\xeer\x01\xb70\xde\x8c\xfa\xdc\xcd\x86\x15\x9ck\xde\xb2;p\xd2G0\xeb\xe7\x12Q\xac\xe2\xb0(\xed+Q\x8ck\xeeO-\x91A\x9d\x8cQEa'\xfe\x04\xfaY\xfeu\xe56p\xb1\xa4\x1d\xb9\xceRTj\x99K\x95cf\xd12!2%\xec\xee\x16\x97\xf8i\xd6\x1a\xd2,\xc0\xf1`\xbc\x1dxo\x90\x8d1&}\xef\xd5\xad\xeel:1J\x07%YT\x13X\x0b4\xd1\xd3sL\xa1<\x81\xe5p\xad&\x05\xd7\x04n,Ue\x04\x9c \\\x88\xaa\xfd\xa9\xb4O 5\x0c\xf9u;By\x93ay\\<\xf8\xc3\x87\x03\xf1\xe0\x87?=x\xfc\xdd\xb6\x9f>\xde:\xa5\xe4\xc1\xf6\x91\xef\xf7\xf7\xb6\xfdt\xff\xbb\xed\x13\x04\xec\x7fIF\xca\xd6+\xa9\x94\xf9\x8d\xe2\xed\xeb\x07\x93\x1b\x95\x98,2LT\x93\x8aY5\xe9\x07\x80\xb5jq\x80Q\x99\xecm\xebV\x9d\xe5Z\x8a\xa1$i\\'W\x04~z\xffc\x08\xd7I\xbd\xca75\xac\xe2\xab$[B\x0c\"\x13E\x84Y\xbe'\xf0\x07\x19\xf4\xf4\x0f\xf2\x1d\x7fZ\xe3S].Bh\xa0\xf8\xa9'\x97\xd6Z\xf5w\x9f2\x89ep\x82^b\x84\x9e \x9f\x0c \xcf\xf3M:\x87,\xaf%DJ\xb2 %\xc9f\x04.\xc8,\xa6X\x93/&\x80\xb3\x16\xb92\x11\xc3:c6\x0d$\x1e\xc4)\x1f!\xe9\x05h\xa3P\xfb\xde\xef=\xb7V7\xc6\xe9 \x9b\xbfwS\xa2\x89o\x8b\xda\x084\xe09\xd5\x98\x9eeA0\xc0\xb1 \xab\x80\x14\x99\x90\xe1U\xa6\x0c\xc2E\xc3 ,{\x8b>\xec\xbfr~\xce\x15\xabz\x1eA\x97\x91\xc6\xca\x10\xf3\x91\xa9C\xe1v\x81\xee\xb8W\xf9\xa4+\xce\xda\xfaKM\xf8\xed\xb6\xd0\x95\xbe\x03!B\xeaWY\x88\xcep\x0c\xbae\xae\x038\x86\x1a&\xd0_\x96:\x80 \xf8\xb4U8\x82W,G\xf8_N\xdf\xbe\xe9\xcf\xdb\xc8O\xf2\xcey\x1b\xb5>U`\x88\xef\xdd@\x90Zq}\xa6\xbd\x85f\x9a7.\x17\x7f\x0f\xfbR5V\xf7\xeb\n\xdc>\xed\xde\xd1\xe91\x1d\xcd\x18\x9b\xac\xe4e\x87\xca\xf6\x89J\x91'YMJNG\xe8\x9e\x87yN*\xacC>%U\x0dI\x06\xf3|\x86\xa1\xa9\xb5\xf9Th\x91\xadh\xce\x14\xcd(\xf9t\xbb\xc9\x16\xf5P\x9e\xe9\x11\xad\x95\xfe\xb21\xf9 \xea\x8c?\xdc\x14\x84\xeb\xfbN>\x15dV\xa3\xaa\x8f}\x14\xc2\x12\xadi\xe9\xbcU\x90\xd1\xc3\xd3\xdbd,\xaf\xcc\xdc\x03\x96|\xe0\xaau\xa3c\x9e\x92\xf7\x80Y(\x92\xe9\xde\x99\xbc!!Q\xb5\xb9\xa8\xea\x12s\xc1\x80\xe7\xc9~\xa6g0\xc1\x0cXHb\x1fx\x01\xd3\x86\xb9a\xdfb\x90~\xeb@\xc3\xd9\x82\x13\x89J\x9b\x8cT\xb3\xb8 >\x91\xc9\x9f\x1e\xfc\xd7\xfe\x83e\x88\xb9\x9d\x94g{\xf8\xec\xbf\xbazP\xd3\xd0\x8a\xc1\xa15\xfdkzg\x1d\xed\xa9\xbd\x7f|\xc0\x1e\xee\xbbv?\x1fdP~\xf6\xeb\xc6\xa4wG\xa3\x95\x11\x9b\x97D\xb3U\\>\xab\xfdZ\xda\x0b\xe9\xe9\n\xcb^\x86\xa6C\xf7u\x1e\xfe\xbc/\x8e_j\xdac\x8a!;\x98\xb9^ \x0e\xfb\xf1{\xfe\x03k\xd0_;t3;M~%\xf8\xcc\x10\xb4:1q\x0d\xf5\x01\xef\xc5K\xcdpsL\xf5\x95\xf3\xc0\x15\x1f\xf0\xda\xb9\x0cA\x1b2Sh\xd2\xec\xa7\x0e\xf4\x01\xc1)\xe01\xdd\x12\x13\x84\x00\xb22q\xe1\x17A\x93@Z\xdb\xda\xad\x9f\x19V#\x86#\xf0\xf1\xee\xc2\xfb\xbe*\xc8l\x1d\x17\xf7);\xf8'/\xa0\xd4\xed\xf7\xd8\x89\x9ep\xd6p\x84\xce\xfc\x1d\xdb\x81\xe9Y\x80i\xcf^\xe43\x0cZ\xea'\x98\xca\xd0\x86B\x1b8\x02\xcf3Q\xffq\x19\xadi[\x1b:|\x84Q\x81\xb7\xaa\xf9t\x83$\x86\xfe\xef\xda\x9c\xd2$n\x92\x18c\xb6\xcf\xfd\xd8h\xe8\xa1\xe3h\x86\xe7\x9eO\x13\xbc\"\xc2\xff\xb9\x93\n\xbf\x7f\x89\xbb\xfbW\xfdu\xe7 \xbd\xdaC\xa3Kr5\x94\x93k=\x94Xk9\x98\xb0K\xa6\x82\xd2~{1\x94X\xeb\x9c%\xba\xd5e\xb3\xbd\x16}jSH\x9d\x88>\xb5\xcd~\x1aL\xf2{:\x94\x13\xeb\xb9\x18\xae\x16J\x97B&\xef\xbfz\xc6\xd3\xea\xbf'\xcb\x93O\x85\xef\xfd\xdd\x9f\xc6\xf7\xffy\xb6;y\xf0\xe0\xf3\x83\x07\x81\x17\x82\x97x\x9a\xef\xder}\xf5\xf3\xe6\x8c\xf5(k\xf7\x9e,\xf0\xf0\xf6\xec2\xb4(x\x03&2M\xe2\xc7,_\x7f\x87\xebGk\x00\xe0\x17\x9c:\x04\xef\x0f\xf2\x1d#\x87\xbd\xe7\x1f\xf8\xa4\x07\x94?\xaf\x8d\x8a(f\xcd\xf1MI\x16\x06K\x0e\xa1\x91\xec\xce\xdf@\xdbE\xc1\x8b\x00\xbc\x86a\xa7\xd2^\x08\xda\x83I\x14\x94\xc8i\xad\xcb(\xa9^\x96\x84\xa47o\xe25\x99\x07~e\x0d\xeeN\xfb\xc2\xb4sJ\xf6#?\x93\x14\xd3~1\xaag\xe2\xda\xc20\x05\xd1\x04\xd6\x9b\xaa\x86\x0b\"Y8\xf0)\x9a\xdc\x7fO\x16\x81\x913U\x0bk\xc5\xe1\xfe\x98\x8f}\x02\x0e\xd9A\x16\x1b\xbc\xa3_\xd9,\xcamW\xa4\x14\x8e\x0b8B\xb1\xdc\xdek\x81\xa1\xb7\xf7\x1c\"E`\xd8\xee)\xf3\x9b\xb5en\xa3\xe5\xca\xf1\xbe\xca\xed\x02\x85\xb6\x96\xd2\xae\x0b8\x86\xdc/BH\xa9 gL.+\xca\xb8\xdb\x01\x8e, =-\xec\xb5A\x15X\xe6v\x88\xc0\x18\xd4\x01\x8e>\x0c%\xae\xdc>p\xc5!\xd0\x1f\xc8\xad\xd7V$[6\x91\xc7\xac\x9d\xdd8\"\x03\x12\x90\x95?\x0f\xe1*\x84\n\xcd\xbb\x1c\x16\x029\xa1M\x9aR\xb6\xeb\n\x8e\xc1\xbfA\x91y.\xfc\x07\x19\x9f\xe8/\x05u\xf1o\x02\xc62/9\xd1\x1dV\x93q\x99\xf6_\x06%\\)\n\x8c\xc6\x88\x80\xee\xa9%OhD\xe9(Bh\xe3_\x850\x0f\x82\x88+\xad\xe0\x18\x96\xf2\xef ,\xbb&]N[\x0ddl\xa3\x11\xbb\x0d\xb6\x00/\x8c\x051l\x01f\x18 j\xb0o@\xe0j\xa4\xa5\xc6\xc5\x98\xd3\xa9\xe9\xa9\xa2\xdeZ\xe7W\x84\n3\xb0t\xc8\xfaE\xf7\xefEK\x1b$\xa4\xe4\n\xd3\xdf\xb8-\xc77\x1c\xae\xd6\xca\xb63\x0b\x84\xc6\x89\xee\xca+\x14R\xd3f\x96\x17\xa12N\x91\x1b\xd0\x9acT\x14\xb9\x94W\xd6\xea\xb7\x81\x03\xe8\xdc\xce+\x10\xc4l\x9c\xc5\xb6Z\x84\xfa@\xab\x005\x15iST\xc4\xf5**\xc9|3#\xfe\xd6C\x00\xf52\x96ytNk\xbc:\x9d\xd6nA\xa2h\xc1\x8c\xfd\xee\xfb\x08F$\xa55\x15>hU7\xcc\x9d\xe4\xb9\xb2$S\xb5'\x7f:\x82=\xd4U\xec\x85\xcdmn\xe0\xd7AG\x1cv\xf2\xa4\xd3\x15q\xb1\xe3\xd7\xd3\xcc\xe1\xb2\xbf[\x86\xe2\xf2\xe8\xca\xad_\x8f1\xb7\xb9\xf5K\xe1\xa5q\xd1\x88\xe4\x17\xd6o\xed7\x12\xdd\"p\xc9\xc6\xb5\x81\x95\x011\xbf5\\\xf8\xf7\x9ejd\xb0W\\\x80T$\xbc\xd7&23\xcfg\xcf\xe3\xd9\x8aL\xe0\x9d\x1e\xb5\xe3\x8b*O75I\x167\x13\xc8\xf5uf)\x89K\xde\x8c\x9b\xd2\x85\xf33;\\\xf1;')\xa9 \xbb\x8a\x98t\xf1\xf7\xdd6\x91-\x94\x16\xcd 6\xa8x\xf4\x93TE\xf0 \xbc\xd5W\xba.\xe3\x82\xd7H\xf45\x96\xa4F2n0\xbfG\xdd\xf7\x04b\xfd[\xf2\xa9.\xe3Y\xfd\xb2\xcc\xd7\xd8\xc8F_M\xde\x06\xb9.\x87r\x19x\xce\xee\x920\x81\xec0\x88W$\x9e\xa3\xa1\x87}\xd3<\x9b\xcdHQO\xc0\x8b\x8b\"Mfh\x8f\xf3\xe0\xe7*\xcfBP\x9f\xdc\xc4\xeb\xd4\x1b\xde/\xc3\xf47\xcd\xe3\xf9)\xdaF\xef\x98\xe3\xaf\xdd:\xdf\x0c\x8a\"\xe8^\x84G\xf6\x80\x91\xce\xb6-_K\x02_\xc5\x0b\xf2c\x1e\xcf\x07=\xb4F\xe1-\xc7\x19#\x0fH\x97\xe1\x1dcF?\xe4\xe8\xa42\x81\x99\xbe\xaa\xb8\x1f\xf9\x8b\xfa\xc9%\xc9&\xb0\xe8\xd3\xa5\xa0k\xb9\xc3\xa7\x08G\xf0\xaa\xaf\x8a\xfc\xd9\xaa4\x17*V\xa2^\x0f\x10\xf5z\xa0cp\xd0\xeeD5J\xa9{\xe6FcMZ\x1enm\x0ds\xf0\xed\xf6\x9f>\xfa\x02C\x1a\xf5\xcd\xaf\xa0Z.\xad\xeb \xdb\x1a\xec\xc0\xb0\xd1\x0e\xe8\x8fI\x93\xc29\x17\n\\3\xba\xf6\x87\xc1\x14\x95h\x12\xa7Q!\x99\xb5\x94 ^1\xe8\xa7\x85lv\x1c\xadI\x1dS\xa4\xe6\x7f\xb24\\6\xe5\xe6f\x1b\xe5f\xdeUnn\xacZ\nf\xd0\xd4Isk\xfb\x08T\x0dl\xfb\x16\x1a!\xd8\xe813\x88i\x9b&\xc3$\xb5\x08;\x8fH\x88\xabL\xb1m\x89\x003\xf8Vhn],\xdag\x98\xee\x04\xb7\xc3\xf0X7[\xf0.\x80\x1d`B,8\x82Y\xcf\xfe\xa2[\xa8x\xcd\xf8\x1d\xfc\xc0\xdfca\xd89\xfb\xf4\xcbm\x08\xb3 \x88\x10\xd6n:\xd7i\"\xe5\xe8M\x08\xbf\xdc\x062c6\xe9\xf8\xa78\nb\x887I;\xc4\x97\xfd+\xe0_624\xe5\xb8\xed\xb8A\x0b.\xa4\xa3\x8b\x81\xa0W]\x13\x89\x94`\xfeqH2h#*\x8b\xbdT\xb9\xe0)(\xe6\x1d\x1d\\\xb5\x9bU;\x9b\x18'\xd1\x9a\x94K\xf2\x82\x90\x82\xae\x98E`\xba\xb5\xc5n\xe2\xad.\x98\xac\xdci|\x16\x04!\xcc\x18]\xa2\x84J\xd6\xe2\xba\x9b\xa9D\x96M\x08\x1eV\xf3\x02\xfaM\x9fG\x10\xc5Y\xd6i=\xc1XTc\x0eu\xeb\x19\xd9z%e\xf7\xdf\xc8\xd8T\xfd\xf5+\x1c\xd8\xf9\xd0\xadl\xd2\\\x90\x8e?&\x1b\x9b\xf0Qgei9+{\xd9\xd6q\x1d\xec^\x82\xe2\xbc\xec8\xa6O\xcf\xec\xea\x9d\xfe\x1d\xa2E\x1c\xe9wC\xa9q\xd2\xb1]+\xa3\xaa \xb3\x10\xaa\xa1})e\x90\xfey\xe2@\x84\xdd\xb4}\x9bi}\xa6,h\x19\xc9\xa5{\x1d\xcf\xca\xdcO\xed\xa4e\x94.E\xe0]\xe3\x87j\x0bR\x03\x0d$\xf2\x0e9\x1dv\xec\x18P\xb4\x04\xea\x8a\x88s/\x0bac\x10\xb3\xb4O%!\xd64d5\\\xfdoJ\xf6oB\xc9\x9a\xa4\xcd\xa3(\x99i/\xd0\xd1\xc6z\x1aa\xda\x08\xd2\xb1qC\xd9\x122d\x06NK<\xdd\xb4w\xf4:\x9f\x93T\xc0\x9d\xedjZ\xc7\x80\xeaN\xbbY\xe5\xed\xed\xbbx\x14\xe3>~\xaf\xc5\xff\x8f\xef5\xfd`\xcc.*\xd2T@\xdf\xf3l\x95\xa4\xf3\x92d\x13]\x8cq\x16e\xb0v3BM\x86l\x95\xe4\xe1&b\"\xca`\x0b$*\xca\xbc\xce\xff\xca\x9fgp\x8c\xbbe\xd3\xde-\x99R\xab\x89P\x8a\xc6\xc4W\xec\x99\xbf\xa7\x04\x8c\x08|\x12\x89\x99i\x94\xcb\xc6\xd3T\xb5\x84e_Ok\xc3\xa5V\xab\n\x1cAB\x913\x13\xa3\xd1\xba\x19t=\xf9~u\xc2\x19\x0fY\xfcm\xf8\xcbC\xdd\xcbJ\x98\xd7i-\xe8RA\x90\xb5\x0d\xcfTM\x91 \xf2\xae\x17i\x9d\xb4\xf6\xcc\xb0M\x86o-\xf3\x9cR\xc1\xdc7\x9a\xba\x81\x8d\xe8t\x1c\xc9I\x08S\xf3hd\\\xac\x11\x81\x89\\\xb8\xb9\xabnP\xf5\xb8$\x19\xc6\xc2\xda\xb1\xa5\x1bB\x1b\x13[\xfb\xa0\x08\xc5dJ\xd4t\x03v\xd5\x08p\xa3\xe3L\xee\x00;K\x17O\xcb38\x86\xc4\xa7\x7f\x0821a\x8fq\xbd\xe8\x83\xc1V\xb8\xe7u\xe2\xcb\x85f\xcdl\xd2t@\x91\xae_\x7f{\xc0\xa9;\x8e;G\x17\xc5\x97\xb1;\xa7g\x81\xd6\x19FL\xccE\xed$\xd9\x04\x19\x15\x92\x81$S\xd3,*\x7fS\x9ei\xef)\xe4\xf0}c\x87~\xef\x1e\xf8\x0c\x03\xf2\xb3\x10|D\xb8\x86lN\xcb\xb3\xe0)\xe4\xbb\xbb\x01\x0b\x911--\xd7\xfbb\x1a\x18\xe0E\xa1\xd7_eu\xd8\x8e\x18\xb3F\x0e\xdb\xaeu\x03A\x945\x82cfi4Q\x9f\x1e\x888\xc9Hu\xd0\xafE\x11\x1cu6\x0dN\xfb\x12Ui\x8dA\xa8\x05\x0f@\xdd\xc9#6\xa4\x98j9\xcd\xd0\xa8\x9eE\x8e-Y\xfe\x85\x1c\xad\xd4\xd0\xe8?\x04\xfalxg*\xc4w\xf4V4\xfa\xb7\x9b\x99\xf7\xd9X\x06o\xf8\xd6\xe5p\xc0\xf1\xf9\xdf\x8b5T\x7f\xfd\n\xdc\x84\x10\xc3\x1e\x0e\x89aZnB\xf0!\xfbZ\x8b{\xc1\x88\xeck\xe5;\xc9\x89<2q\"\x99\xff\xed\x00\xf6\x0cr\"W<\x03Y\x87\x99\x94\xa2\x1bKs\xab\xf2*\x03\x9b\x1a\xb7%f\x0b\x9e\x85\xb0\x08\xa1\x08a\x1e\xc2\nMF\xd7h\xbdv\x03G\x10\x97Kt5T2m\x1d\xa0uYc@!\xabL\x0f\xe8!\xda\xfaI\xf9v\xfdn\x97Z\x141\xf6\xeb\xd29\xf2\x14\x9e.O\x9f\x06P]'L>\x14\xd9, \x86\xce\xb1\xd11LW\xe8\x90\xd5S(\xce\xe1\x08nx\\\x99\x93\xacNJ\xf2\xa1$\x84\xa5\x18\xbe\x11\x86\xf5,\xb50\xad\xf6\x8f\x0d\xa9\xeaWYM\xca\x19)\xea\xbcd\xc9\x86\xe9\x9b\xaa\xc8\xb3\x8a\xb4^\x15\xf8\xaa\xad\xe7b\xd9Jo4\xb22\xcbGl'\xd2\x80\xa10\xea\xd5\x8b\xa4\x9a\x95\xc9:\xc9X~\xbe\xcc\x8d{\x92\xa6~\x06+\x90n\xe9O\xd9x\x83\xdf-\x1a\x98L`\xe1\xf6m\x1bh\x13(\xdc>\xebCu\x02s\xeb\x97\xb7!\xda\xce3\xf6[\xa6\xbe9\xbd\x8e\x97KR\x06\x0e!\xf3\xa0 {h\xadKe\xb15\x86\xf2d\x8aY\"\xb2\xac~\x1bv%\x8cN\xea\x0d*\x8c\xael\x863\xa2\xb0\xe1\xac\xdd\xc0\xd6\xcf\x80\xe1\x1a\xad\xab\xbaL\n\x11\x85\x14\xedl\x06\xadcD\xb1^\x12\xe1&\xfe\xd6y\x13/\x99\xe3/\xc9\xea\x10vJJ\xc2\xda\n|\xe6\xdb\x99\xa9\xcc\xe7\x12\xc1\xcfW]\x91\xf8\x97|Y2\xf4\xd6C\x16\x9f\xaeQ|Qn\x8a\xda\xf7X\x87^\x08K\x97\x19X2\xad\x8e\xc9\xac*\xb5\x18\x96L\xaaF\xc6\x960VI\xebb\xd8\x9f\x8a\xb8\xa5\x93j\x8b\x81\xc3F\x0e\x0d\x93\xb0p\xb9X\x9e\x14V\x9d\x99\x1f\x8ce\xaa\xfe\xbdX#\xfd`\xf2A&@s2\xef\x19O\xe6\xbd\xf6\xc9\xbcg:\x99{kjSE1\x0b\xe97\xf1z\xc0+\x809d\xaf1\n\xbb\xb9\x16\xc6\xe2\x8d(Yf\xe1\xb2\x0c\xb9\x9a\x9dG\x08|\x94\x89\x1eV\xfbFX\xed\xb7a\xb5?\xc4\xc5\x80\x8a\xdb\xe4\x13\x99mj\x16rZa\xcf\x86\x891#\xc2\x04I\x8ay\xc7\x86]\x1aDB\xf0\xfa\xe7\xae\x87O{G*}\xbc\xa9H\xf9\x92\xd4\xb3\x95g\x8d\xc1&V\xd4\xca0\xb0%\x9d@9\\M\x0d\xcaeI)\xac,\xffP\xa8\xb4\xdb\x10\x12\x831\xb7\xf5\xd6\xde\xac\x1f6\xed\xb6\x9a\x1d\x1d\x94\xe6k\xbb\xe4*\xd9\x0b\xfd\xdbF\xcd\xc1\x03\n\x1c\x03\x95\xd4\x0d\xa0\xcd\xb1-\xbe\xcc\x1f\xe2\xa5\xbeV\xd2n3\x87c\xf0\xf87\x1e\x18\xcd\xa4c\x96\xec\xe7\xe0m\x03\xe4\xe7\xf9\xba\x88\xeb\xe4\"I\x93\xfa\xe6u>7\xec\xe2\x8d\xc1\xdb\x96\x96\x05\xbe3\x92\x12\xc6\xaf\x90x\xb6\x92\xdd\x06\xf4\xa8\xb0s\xfa\x8d\xb6\xdbNb\x18\xd8l$&\xc5Z\x12\xc7\xf4[\xdaO\xa3:^Vp\x0c3\xfeg\x00\x13\x98&gc\xcd\xc0[\xce\xb4G\xaa3\xad]\xbb\x8a1\x1cX`\x1c\xfc\x8f\xddF\x0c~\x06\\\x97\xcd\x00\x9e\x17\xaf\xe6\x81\x9f\xe2\xfd_n\xdb\xf0\xa2\x0c\xa3\xc6\x04bk+:W\xedn)PDv\x1b\x11\xe7\x98\xed\x8d\xc2\x18\xba%\x8a\xa0_\x86\xfd\xd2-\x12q\x9c\xfd\xd9Z\xe4\xccL\xdeE\xb1\xf9wQ\x8c\xdaLgg\x01\xd0\x7fwwCH\xa6\x9e\x07\xbb0\x83]|D\xf1\xa5\x18n\x83\xa9\xa9\x9b\xb0D\xf4\xecK\xb0M\xfb\x8aP\xcc\xa4\xa2)\xed\x8a\xa2\xa4C\x04a\xacz\x04s\x16\x8a|\xfcp\x81wK\xe5^:L{m\xeeyA+\xb7:\x9c\xd3\xde\xcc\x89\x9bAQ\xe2\xb31\x17\xc6\xba\x06\x06Z\x7f\xa9\xd66;\xfb\xcaj\xb0\x10\xea\xa8\"\xe9\xc2\xe0'\xac\xde\xb2\x1d\xf6-\x10\xd6\xf1%9aL\x0c\x1cQ\xb2\xc1\x1e=+\x92\xeaC\xbc\x94\xb4\xa1\x92\x7f5\x95\x9d\xf4Vw\xc0\xb2\xea\xf7\x1dj\xce\xd4\xe1\x1b\x9d\xf63^\xb3hMh\x80\x1a\xd9h\xe2v\x07*t8?s\xad\xd9\x85Ic`\xa2\xb5\xa5\xe1@\x96w29$\x99\xe9>KVJh\xa5r\x9a\x9f\x0d*\x9c$\x81\xab\xb47\xf4\xc0x\xb5l\x9a\x9f\x05\xd8Xs\xf8V,,\x8d\xb9i\xceMO\xf0\xebi\xa2W\xf2\x9b\xf9\x0e}\xc3q\x91T\xba`\x81=\x1b\x0d=\xe6\xffK\"\xfaV \xf8\x8f\xd9\x03nK\xd9\x9e*=K\xfa\x84Q(\xf6\xbf\xd5\x9a T\\u\xdf\x7f\x93\xda\xb0\x02\x9a%\xd1\xbalj\xd6z6\xc6}\xa5g\x89\xca\xb4\x12:\xd7CMW\x0b\x16.\x8d\x1d\x1a\xfa~\xba\xf03:\x17*\x88\xa9\x13\xdf\x9a\xa5\x19w\x07\xf6\xe4` \xce\xf1\x7f\x86\xa6\xe7\x0b\x85O\x85\xd14\x1f\n>\x89*2\xdb\x94I\x9d\x90*\x04\"\xee*0JPV\x7f\xb8)\x08{\xca\x14\x08\xcac\xc3I\xc3\xa4\xaej\xb6\"&\xd9\x8c\x89\x9c\x9a;\x11m\xed\x8a\xd7\xee\xdf\x93h\xab\xcf\x98\xdc\xcd\"\x19\xfcT\x1ax\xf2\x05\xd6\x92\xea\x0f}\xa5\x82\x81\x87\x0f\xf4\x87|~\x13\xa2\xb6\xb8\xbc\"\xa5a\xf2s\xaeP\xa6U\xfe\x1a\x97I|\x91\x12\x83S\xed\n\xab\xae\xea\xdapE\xb1\xe4R\xaeP\x93\xe8k\xdd\xb4k\xfd\xb0I\xd2\xb9\xb1\xb2\x08\xe2\xf5)J\xaa\xb7\xcfN\x0f\x03\xbf\xd6\x1c\x147\xe8\xaeO\x1b~\x0b\xc7p.\xef!\x95\x88\xe8\x86 \x83\xef\x8c\xc4bS\xa6\x13cd\xa3YI\xe6$\xab\x938\xad&\x80Z\xf6Ut\x9d\xd4\xab\xe7\xcds8\x06/\xc9f\xe9fN0\x0ca\x15\xaf\xc9}\x16C\xcc\xd0h\xe3\x08l85gy~\x89q\xdeuF\x84\xfd\xf9\xc5\xa8\xfd\x7f\xa7A[z\xb4\x07!T\xb2B\x0fS\xe1\x08*\xca\xf4\xf3\x1a\x12\xed(=7\x80\xf2\x83\\\xaa%\xa9%\x91}\x1f_\x07CQew>\xa8\x91U\x9f\xfb^\xc3\xa4P\x89'\xc3\xd0\xb1Y^\xc3\"\xdfds\x9d\xab\x10\xed\xfb5F\x9e\x94\xd4C\x0f\xbeWmm\xd3k8\x86_na\x02\xaf\xf5\xd5\x7f\xc66\x87t1o\xb0\x86\x10\xd7\xf5\xf3{\x17m\xca\x14v\x8f\x8c\xa6\xa1\x83\xaa\x01F\x93\xcc\x01\x03$\xcd0\xdeT\xb2\x8dm\xbcU\xec\xec{c\x18\x9dF'\xf1\xc6pdr\x1d\xc4\xcf}\xcc\x0cB\xd8\xc9\xa4\xa5\x8d\x88(\x10ql\x0e\xe1]\x1fr\x12joBx\xc7\xd7\x80\xa2\x17J\xc1?\x07Q\x9d\xffT\x14\xa4|\x1eW\xc4\xc7\xa08G\xb0d\xca%=~\xbc\x97*\xfej\xfa\xe6\xccT\xb3\xe4\xd8\xce7b\x14\xa3\xbb=e\xa7\x0ch\xf7\x02\x8e\xe0\x99\xe2\xa9u\xea\xbfR\xc8_\x104\xcf\xdf\xb7\x9ek\x9a{1B+'4\x8a7S\x12%\xd9\x80-ai\x89\xb3\x85\xaa\xbd\x8b|~\xe3\xc9\x18\xb2\x8ca@\xbc\x8b\xd5\xbf\xa3\xc6h_Z\xb4-;\x11\xb5\xd0:\x8a}\x94\xc5k\xfck9e\x7f\x9fQn\xce\xf0>\xc1M\x1e\xb10\xadX\x19&p\xe9\xb3\xbfCx\x11tn;D\xc2\x96\xeb\xb8\xcc|\xef\x9d\x80+\x8f\xd4\xcf\x9a\xc6p\xfdI\x05\xf1\xfa\"Yn\xf2M%\x83\xdb\xd7+\x02<\n3\xee=X\xc5\x15\xac\xf3\x92\xbe\x893\xc83\xd2(\xfa1;\x00~\x91!\xee\xf7z\x88\xb39\xbe.\xe2\xaa\"\xf3\xfbI\xa6|\x8b\xba\x8d\n\xe6 \x8b#\xc6\xfa\x848\x83?$\xd9\x1f\xd8\xdb\xc8\x0bB\x11\\\xebh8\xf6bG\xd5%u\xeb\x8a8\x86\x91\xb9\x1bsCy\xf2\x85\xbd\n\x8cCHJ2\xa7\xbfvH\x84\xb7\xe2'\xeb\xa2\xbe\xf9+3\xf9nH2\xf7\xe2|/>h&\xd8\x06\x06\x856\x9dgQ\xe6W\xc9\x9chI\xb5:\x99\xb7]L\xf3\x98;\xa8@E\x8ev\xf5M\x81\x88\xa2\xd1@\x976\xaf\x0d\xe0[@I\xa3:\x90.\xdf\xcdK\x03d\xa02\x058M\xb48\xec\x85;\xb6vqA\x84\x97\x8c+\x1c\x91!\x041\x18\x15s\x80l\xf2\xbd{\x90Y\xb4\xce%\xf9\x871\x0e\x8d(rl\xd6@h\"3\xc1p-E\xa9\xfcj\xb8\xa6\xcdz\xc4\xd9\x9c\\\xa7f\xa6\xa4\xf1\xc7\xbe\xa9\xc3/\xcc*@\x0f6u\xe8N\x9d\xa0\x9d\xf1;\xcem\xd2\x9e\xae\x9b\x9e~\x0c\xe1]\xc0\x83\xef\x9ct\x1e\x07\xe2\xcc\xc3M\xda\xb6\x80\x97\xe7a`\xf1\xbd\xa43\xfc\xa9\x9f\x8aM\xf9~l\x98/q\x9c\xc8&\x8c\xde\x18\xa0J\x96\xbb\xe0cP\xfb{\xc8\xdeb\x18\xec&goE\xca\x04M\x8b\x06l\xceoC\xfa\x99\xbe\xa7\xe6\x10~\x8ec\x82#\xf8\xa9\xbf6\xfd\x13\x9c\x0d\xee\x9d\n\xe8>\xc3\xc1\x02#\xa17\xf6\xab\xec\x7foHy\xf3\xb6|\x99\x97\xeb\xc0\x7f\x17\x84\xf0\xeew\xed>Z?m\xf7\xac\xcama#\xb20\xb9\x97\x9e\x80ng\xbbMV\x06)/\xdbo\x14K\xa7\x1b\xc5\\\x11\x02\xcd\xb5\x12'A\x15\xa4\xbc\xec$TB+\x99!\x12\xffXp\xe6\x03\x86{\x15\xdf\x02J\x92\xb6:\x84\xa9\x87<\x9e\x87\xf7\x85~\xc9\x82\xd3Rv\xf1\xc7\xfc\xbaa\x17=6\xb0\xca;\x0bD\x9c\xb7\x81f\x1cj75\xcc\x03N1n\xbb\xf9\xfd\x8c\xc7\xd94sj9\xc5fDi\x97,\xae\x14\x91\n*\xc6\x8dL\x85*\xcd@6\xa59*\xdb\xd0\x0d_!c\xe9\xe5\x01\xfc \xee#\xcf\xe6\xa7\xec&\x86\xce\xb2\x9a\xaaUL>\x93;io\xba\xb2\xa1j\xbawF\xc7'\xda\xdb;\x0b(1\x14\x8dz\xbfxM\xcfn3o9zL\xcf\x98\x87\xc7\x83_\xfc\xe9\xdfo\xcfv\x83\xdb\x07K\xd5\xcf\xe3)\x0bs\x81\x862> \x9e\x06T\xb6\xd8T+\xbf\x9c\xee\x9f\xd9}6\x0d*`?\xdd\xe6f~\x16]\x89\xfd\x85\xbcq\xf3sJ\xac\x97\xa1b\xc2\xed\xaf\x86\x8fo\xe0\xc4g\xc3\xef\xf3\xa5\x0d\x9b\xfd\xb3\xb2\x13\xc9\xfd\x17\x99\x1c\xe6\xd6\x0b\xc1[\xda\x02\x81\xd0\xa5O\xa5\x97j9\xe8\xccd\xba\xdb\xd4\xf7\xd0\xb5\xc6\xb2m\xac;\xb9\x1c\xb1\x85\xcd\xae\xef\xc2\xe2\xcb\xd6 ]\xca\x95<\xb6\x19\x93l\x8b\xdfPj\xbe\xa9-\xdf\xd0\x13\xe6\x9d\xcf\x1dLgy\x8a\xb4\xf4\x9d_\xb6\x1f\xd8F\x9b\xe0\xbe[\xe5\x15z\x1e\x96\xf8\xd7\xf0\x17\xcc\x85\x8e\x92s\x14T\x1c\xfap\xc9\xac\xcb\xf1E\x84O\xf3\xe97H\x9e\x138\x86\x9cb\xf4\xe4\x01\xe6\xd4\xf0\x13\xd8\x85\x18\x9d\xf0\x82\xe9F\xf5\x00\x84c\xd8\xb4\\\x99`b\xc8\xbaz\xeb\xa7!hr\xb2\xdf\xfa\xe8\x9bk\xa7\x15\xe3x\x8a!=8H\x8e\xc2\x85\x0b\xc8\xdb\xc7z)R\xb2XX\x8c.j\xe5\x03\xa8E\x97\xb7}oT\xf3 T\x98\xf4K\xfc`;\x0e\xfd\xad\x8cma\xf4/\x8a!1\xc3\xcd\xa4\x83\x9b\xab\xba.\x06p\x87\x19\xf4\n\xdcL\xe4_C\xf8\x96\xe27\"\xb0\xbb\xad\xf6\xcc\x82\x99]\xac\x9caz\x17>\xc9\xae\x99+\x96\xf6\x89\xf0\x1b\x17&\xc6\xf2\xbfy\xf80E\xdd\xc4n\x98e\x8di&i\xa2\xe6nU\x03\x82\x7flH\xf9\x95V\xc86{ &\xb3\x8e\xbd\x8ep|\x08\x03\xf6\x17\x87\xc0\xce>w{\xbbw\x0f\xbc\x8b'?\xbd\x7f\xf5<_\x17yF\xb2\xda\xcf4\xbe\xa7:\xcb\xea\xbc\\\xbf\x88\xeb\xf8_\x12\x00~\xc64\xc1=\x0b\x16F\xa5\xe8\xd8\x11<\xf8\x87D\x13\xfa\xcbiC\x89-a\x1ee\xa7\xe3I\x7f,\xe6o]\xb6\xab\x1ei\x1d\xfc\x05\xfe\x93\x03\x0d\xa8\xbf\xee\x9c\xc5\xe8\xcb\xf9\xf9\x90\x12P\xc4`\xd2\x8a\xc8B-\xf9\xed\xe3q\x81r\xff\x05\x08\x8e\xb9bC\xa9\xcdu\x10*QU\xdf\xa4\x03\x95P/K\xd14\x1d\xf6\xae\xe9\xabr\x86%\x18\x8c_g\x1b!8moZp\x16\x13HP?_%\xeb\x82\"\xd4\xe0\x17|J\x13\xd8\xd0ol\x990X6\xa0 \xec\xec\x1b\xab\x99$\xcb!\xfa\x9f\x0b\xd2\xaf\x0bL\xf2\x1f\xc9\x98\x99\x19\xb06K5\xcc\x88l\xfa\x91\x0e\xbcM\xc6mF=n\xdb\xa5\x04+\xd2\x99\xb6\x8b\xe2\xcd )\xde*\x86\x8d|Op\xc3\xb1\\me\xa4\xb4\x0f\nq\xca\xacY!\xdb\\$\xc5\x8c\xa9\xbc}?\xf3\x86\x0fAQ\xf8n\x19\xb5\x15E\xc1-\xe9\x98r\x95\xf7\xe3\xe8\xce\xcew\xa7\ni\xb7\x0f\xc5\xb6\xe3\x07\xf6{\x82f\xb4\xf0\xd0IP\xcd\xc6\x1dJ\xee;e\xf4\xa1\xd0\xdf\x1e\xad'\xb7}U\x0b]\xdf\xa9\xc7S(K\xe6\x8c\x12\x9e\x9a\xbf\xec\x9ad\x11\x14\xbb\xa6g\xae\xdd\x81\xeat!\xc1\xb0\xff\xa8\xe3\xe5\xac\xdf`[t\xe2\xfd\x0f\x14\xfcM\xed\xfd\x9c'\x99\xefi\x9c\x13\x95w\xd0E\xd8_]#\x9b\x0cid\xe3F#\xdb\xd5\xb9\xb2[\x90\x17I\x85\\!\x99S\xfc\x88g5;\x01\xf3P\x1f\xc3\xdeb\xb8i8_\xb5VF\xf5X/\xb0Krcc\x04\x9cTl\x16M,3\xfd\xb42D\xcc\xafk\x88\x1e\x00W\xeb\xda\xe7(\n\x87\x13\xe6\xd6\xb2Ku\xe2(\x1c\x8e\xe1h8\x8f\xa0\x7f\xe6\x88\xc2\xa2\\2\xa6\x92\xb15M\xb6\xdc\xf1{lc\xca;/7Qhrv\xc1\x81\xa4\xf1\x05I\xbb\xe3`.\xf2_e4\xd1\xe0h\xd6q]&\x9f\xbe2X\xc6&r\xe1M\xb2,2 \x1c\xd3\x83\x84\xb9\xfbQ\x06\xef)\x05U\xcdX=\x0c#2a\xaa\xce\x10\x7f\xe9\xc70\xe0\x8e\x8a``\x8a\xb4#\x9b\xa7\xbe\x90`\x13\xee\x1c\xdb\x8ccB\xfb73\x9e[\xc0\x15\x1c`\x0b\xcaBkn\x02\xc0(\xed\xb3-Q\xc43\xf2\x82\xa4\xc9:\xa9)\x93\xee4\xfd\x94O_\x99\xf8o;o\x0f\x83\x15\x18RX\x0d\xcc\xbeH\x8a\xd1\x93\x9f\xfd\xcbM\xfe3\xc6\x0eu\x9dh\xde\x0d H\xeb\xa1AE\xc7\x1d\x92\xbe}\xc2\x1c\x92\x1e\xe9\x1d\x92\x985\xf9#]~\xff\xd4i%\x05\xec&\x0f\x8e\x7f?=\xfb\xffv\xbe\xb9\xf7\x07?\xf8\xe3n\xf8\xf4\xc8\x93\xf7\x19\xdcp\xb6?\x15\x8d&~L\xa7\x0f\xfe>\x8d\xef\xffs\xef\xfe\x93\x8f\xf7\xa3\xf3\xff:\xdb\xfd\xe6A\x12\xd5\xa4\xaau,\xd7\xb6~\x01O\x0e\xf7\xb7\xb7\xd1?\xd8\xfe\xd3\xc3/0\xefo\xbd\xfa\xb7\xd4\x8a\xca\x00\xa9f\x95\xa6\xdd5\xb5\xec[ a\xcc\x9a\xc1\x84(\x96\x08\x95\x9a|(\xd8\xe6`\"\x14\xb3\xdb\xef\xa2\xef=\x8bw\xa3\x86\xcbbtR\x8c\x84\xc2\x9d\x18\xdc{\xe7\xed1\x16b\x8c\x06\xdfeLx \x80\x89F[q\xeb\xd7\xd4\x10n\xe4\n\xb3-\xdc\xbb\x07;;\x1d\xfd\xea\\D\xc8\xd2\x7f\xb8\xee\xc7\xc6\x8aC\x98z3a\xf6\xac:\xfd\xde\x9c\xb2\xf0\x00<\xb6\xcfP*)\xe5\xa6l\xd1\xbd\\]H\xe3\xb4E\xdb8\xad3\xf42P\x14\xd8W\xf4\x1f\x16\xd3\xa6s}\xd5\xc0\x0bG\xd5\xfc\x94a\x7f\x8e\xc1_il4\x06X\x13\x19\xe0&\x83$\x1bN\xde\"8\x98\xf9t(\xb6$p\xa4^O\xb3\x01{\x0f\xb4\x07\xb0\x9d\xd3R\xa1\xcb\xf3\xd6\x7f\xfel\xbb\x10\x03\x8e\xfd9zN\x0c\x9b\x9b\xb0!X\x9bCy?.\x92\xffEx4\xcc8\x00\x0f\x17\x93\xdf3\xf2\xe0\x98\xfeB8\x19\xc8\xeb\xf0$\x08\xc1c(\xd1\xab+.\xcf;\xb5\xd9\x9dp\xaf\xb6\x08\xc0\xa6\xd6\x1e\x9e\x1d\xa8>\x18\xcc/^\x8c\xde\xce\xf2\x80\x8c\x01\x1aW\xc9L\x8c\x86\x85\xccp\xfd\x1e\x14\xae \xc1@\xc1\xf6[\xcfnAuYT\xc4Uu\x9d\x97\x03a\xcatE\xc8\xb3\x8a\x7f,\x0buA\xd9\xa3\xca\x01z\xa2\xc8\xb5\x8a\x9e\xa9w\x8ep\x04\xde\x0f\x14\xfcN\xf1\xbf\xbc\xe5\x81*-R\xae>R\xa1\xe0r\xf9\xb9\x87a\xdf\xe9\x06\x8eVq\xf5\xf6:\x13'`{x\xb9-_\xb2d\xb3 \xcf)Bi\xfa\xdeS\xa8\xe1{8\xf8\xf6\xd1S\xd8\xdd\xad\x03 ,\xda&\xf3\xca\xa1t\xff{\xd8\x7fD\xb9\xb1=\xc5\xf2\xb1\xe5\x17\xd4q\x0c2\xab\xef:>:\xbeR\xb3\x8ebJ:?\xe4l\xca\xb6\xb3V\x91\x18\x8e\x00s\xce\xd5Q\x91\xc6I\xc6>\xa7\x9c\x1a\x87\xdd\xac$qM\xfcl\x93b|y\xca\x0b\x96l\xda%|/\x1d\xb8\xe8\xdc\xcb@UV\x91iy\x86\xf8\x98\xd1?\xd8\xef\xee\x92sS\xe9f\xcd1)6)\x97\xa43\xfe,\xec;\x92\xa2\xba\xb6IC\xd9\xe1\xc3\xd9\x0d\x99T\x7f \x9d\x9b\xd6\x03\x81\xd6\xed\xc6\x0e\x96\xeb\xa8\xb3\xa5E*gVDk\xfa%r\x9cS:\x1d\x83\xe8\xe5\xe7\xedE\xf8\xfc\x99\x8a(i\x9a_\xbf\x13\x18\x8c\x0fw\xcah\x16\xa7\xa9\xdfEo\xba7\x18\x11 S\x0cv\xbb\xb37b\xc3\x0fy\x809LK&\xcd\xecBLp\x87D\xbb\xfa\xbd\xa0\xcd}\xef\xdf\x8c\xcd)A'\xd0\x16\x9aS\xdc@m\xa7\xae\x95^#\xc7\xe0g}\xc1:\x0b!\xd1*\xc0\x18\x8c \xbe>\x062M\x10\x9f\x15\xad\xb6\x84\x02}\xc5k\xfc\xff\xec\xbdk\x97\x1c\xc7\x95 \xf6]\xbf\"P3KU\x0d\n\x8d\xee\x06@\x11MAt\xa3\xbb\x014\xd4\xe8n\xf6\x03 \x00a\xa0\xac\xcc\xa8\xaaDge&\xf2Q\xdd\x8d\x11\xe6\x90#\x8a\xc2\x83;\xb3\xde\x91\xa8\x91=cy\xd6$H\x00\xb3^\xdb\xeb\xb5\xd7\xf6\x8e\xf7\x1c>\xd6>Gs\xa8\x99\xbf\x80?\xb0\xfe >\x117\"2\xf3\xde\xc8\xac\x02 R\x9c\x1d\xd59\x12\x1by\xe3\x1d7\xee+\xee\xbdqFcp[\xfcSc\xeeB\x81M\xe2o(X%\xf9B\x8e\x97\xbe\x9cjS\xf7\xf8a\xda\x0e\xada4\xd6\xe1j\xd2\x1b^\xf7\xebc6ms\xc2#v\xf4\x88\x01\xe8t1bT\xde.\x01\xbe\x90\xa6\xfe \x9cDs\xd4\x18\xca\xf3\xcb\xa6\x0f\x13\xd2H\n\x88\x9d]\x0foX\x06\xc6\xd1\xc0<.$\x95F'A\xfb\x8b\x93\xaa7\xa8_\xc9\xb1X\xce.|Tf\x17f-\x946\xc0<e\xbe\x9e\x9e5_O\x7f\xc7|\x9d\x9b\x9f\x97q\xc5G\xf5\xc0\xe4\xa0\xd8\x82\x80\xb2\xb9\xf9W40\x12\xd8\x0e_\xe7gO\x96>\xcf\x9d\x9eg\xb2\xd9\xef\xb1\x97o\xb0\xa3\xe2\xcb\xfc+\xecG\xec\xe5\x13\xec%f\xea\x9c:5\x7f\xfae\xd3\xff\xa9\xef\x9c8y\xb2hb~\xfe\xa4nbn\xbe\xdc\x06\xb4\xca^b/\x9f\xb07\xddND\x0bs]\xb9\xb0/\x9f:u\xe2e)S\xcc\xcd\xce\xcb\"\x1d\xf6\xdd\xef\xb2\xb9Y\xf6#\xa6\xbe\xa0\xb5\x97; C89k\x86\xf0\n\x19\xc2\xdc<\x19C\xf3\xd0:\x0d\xac\xc2\xce\xd5\xddh\x14;ns\x14n\xf5\xcd6\x8aaQ\xefV\xdd\xc5Cd\xbdr\xa0\xe2g\x9cD\xf1\x02kE\xd5\x0c{\x96fI\xeef\x91zH\xbb\xf4\xa1\xe8\xab\x16\"4\x85b|\xdfb_VaU3/\x16C \x1bTS=\xfe\xcf\xe6g\x8f\x0f\x8a\x16\xca\xf7\xc4\xd5\xc50\x97\xb2\xad\xadsK'N\xbf\xf22J\x1f\xd3\x97i\x89\xe1m \x8a\xbd[\xe7\x96\xe6\xbes\xe2\x95ib\x8c\x88\x90\x19uY\xeb\xa8-\xf3\x04\xa5\x13jh\xcf\xd1\xcd\xc4+\xe6j'f\x1e-\xf5W\x8b\xc0a\x00f\x95\x9eo_\xf5\x0e\x02E(6P\xbe\xbdF\xb7/l\x9f\x9e\xc3a4\xbe\xfa>\x8f\xbe\x9b0W\xb5\xbd\x93n\xfdY\xe9\x04H\xef\xc8P\xbf{\x02O\xb9H\xc7\xac6/;\x9b,;\x99<\x13\x19\xf9\xf8\x1a\xe33\x03\x9e\xed\xf8#\xde\xee@\xf5\xd2\xbf\x17T\xbc\xfe\x11x\x19\xcf\xa2!Vt\xa6\xe2\xbb\xcc\xf62\x03\xe7@\xca\x9f0\xb0\x05\xf9\x97\xfcc\x9aY2\xb5\xf0A\x97\xb9\xf5t;oC\n\x97\\\x12h\xb52G,~f\xba\x02/\xf6\x0fhp\xf1\xef\xa9\xea\xfb\xd2\x80\xa0\x0b\x1e\xf1\x85\"\xa03\xe3\xe8\xd3\xd1\x01\xf3\x91\xfag\xd6\xe92\xc7\xcc\xb4\x81\x07\xa5\xb2\xe9z&#\xad\"\xe94\x13ef\xb2\xca\xbc\x083E\xbaDSm\xc9\xd0\x02`bA\xc5\x18\x14\x1c=\xda|\xe7);\xbe\x1e\xdcP,.\xb81U\x87\xba\xc8\xb4\xe9\xfeX\xad~\xa7\x7fc\xf5\xe8W4\xf1\x8d\xd4X\x96\xcaj\\\xf6\xb4\xc67M\xd2\x8c\xba\xe4s\xb5{\xde/v\x88\xc5\xd3n\x90\xdc\x9c\xfeL\x1a%Y\xbb\xd3e\xb1\xf9K\x06\xea\x95\x9e\x88\x14{\xf7=\xd8\xc3c\xc7\xeawM\x0e\x04v\x8c\xc5\xd3l\x98\xc1\x8e/\xd8\x99\x8c\xed\xbb\x1e\xdc\xe8\xb2#N\x9b_wotY&\xff?\x9c\x8c\xdbZx\xd14\xa8\x90yi\xfa\xfd\xbb\xc5\xb1\xab\xc0\xee\x96\x1c\xa6\x8c\x7fR\xde,kHu\x9c\x15Y\x17\xcfT\x1e\xce\xbaki0\xadm\xf0H\x1bH\xab\x95\xa8\x8a\xef:\xffV\xe9\xbbA\x0e\xe9\xcc\xa9;\xa9(\xfb3n\x14\xcb\xb7\xf8j\xc0\x92_I\xf1\xa8\xa0\x0c\xea!d[\x8f\xd7go<\xaf\x04\xa49%=(\xc0\x0e\xe8u\xb3\x8d}\x9e8=ka\x9f\x13/\x98\xd5\xe2Fj`H\xad\xbbK\x19o\xd8\x9e?1[1\xb4_L\xa3pS\x1cw\xfd\xa0\x9b3S\xfc\x13\xacN<^\n\xa2P>*=s\xd3\xfc\xb3*\xee\xe5\xd6%p#\xfe[G\xc8s\xa9+\xd4\x11\xa2\\&O\xa9;\xdc\xf9\x8c\xf8o\xf5@\xd9\x14\xaa\xc0*\xa9Kw\x03\xd0K\xean5\xb5\xd5\x9e.\xa7d\x02\xa2w\x0b\x17P\xd4\x1f\x8f\xab\xfcO\xc3i\xe4Mt\x97\x85\xb0q\xa6\x8cM\x8bs\x95\x93JR\xe3\xa7R ~\xd3\xd2\xcf\x91\xb9\"\xbc\xeb\x8cN|.\x1f\x98?2\xdb\xe9\xaa\x82V--a\xaf\xb1Dp\xc2\xd9.\xe3\xf2\xeeDH[l\x81\xc5\xf2\xa3\xcc\xb8\xdcR\x179\x00\xa2\xab4V\x99\x0d\xed\xe8XAE\x8b\xa5\x95\"=x\xb0{\x9e\xee7\x8a\xcd\xce\xb93\xa5\xe6\xe4\x1d\x8a:\n\x16\x9b\x9dlF\x9d\xc7\xe7jJ\x8bl\xe2T\xd6\xb7,\xa5C\xd3\xacT\xa3\x05\x8eO\xd1\x93D\xd4\x10D\x94.\xc3\x0d\x89\xad\xaa\x0c\xa1S?\x06ql\xca\x1d\xdaw@\x9a@\xe4\x11cg\x04\xf75\x88\xd81Od\x01\xb8\xc3\xb2a\x12\xed\x8b-#\xcai\xbb\xb5#\x1a0\xce\xc1\xac\xef\xf8\x01\xf7Z]\xd6\xdaY\xd9\xde\xb9\xb9\xb1\xb9\xb2\xb5\xb8\xb3\xba\xb1~\xf3\xdc\xe2\xea\xda\xcarK\xa2T\xd8e|\x82\x18\x86\x16G\xac8E\x92\xba\xcd\xad\xae]i\xc5\xab[\x88\xb7:\x0f\xecf^\xd9\xaa<\xef\xb4\xcd\xb0\x90\x18j\xeb&\xcd+h\x1e\x81g?\x8c\xe2\x1f\xca\x8bL\x9ed\x87\xccOY\x18eL\xa8\xf9Q\xbfX\xe2\x94\xa9\xa8J\xe6\x87l\xeb\xdc\xd2\xb1\x97O\xcf\xce\x8b\x05/\xd6zc\xf3\xe6\xea\xfa\xe5\xc5\xb5\xd5\xe6\xf5\xd6\xcbR%V\x95\x7fE\xca\x92\x8fT)\x8eU)m\xe6l\x03=`\x90WW2\xd0\xac\xdd:\xde\xb2\xd8>a\x17\xc8\xe7!;\xc3,\x8f\x16\x8cKv>\x0b\xb31!b\x146h\x80\x1d\xd6\x84\xe3J\xd3\xe2\xa1|\x1a\xae\x8e:\nb\xf8\xaa\xf5\xcaWl\xf9@\xda\x16\x877\x14\x95-\x11a\x08\xde.\xc7\xb3]\x1f\xdc`\xaf\xc9)\xf4\xc18\xd6\x9e\xed\xb2\xa1N\xc5z\\f\xe7\x1b\x8a\xee\xc7\xec\x18\xe4\xe2o\x8f\x98\xa1\xbc\x95\x00^\xd9\xf8aA\xb8G\x82R\x0f\x8f\x1e\xc5\xf7\xc8^\xad\x89_\xe2\xfa1@\xf4AG.\x9e\xa7\xad\xee\xd6\n\x0d\xae\x8aL\xe3\xbf\xb4\xf6\x95\xa5\xd2A\xa7\xf9H\xac\x1c\xc4\xdc\xcd\xb8\xc7\x9c\x90\xe5a\xea\x0f\x04\xba\xf7\x9c\x94\x1f\x9b\x9be\xea9d\xa6\x08\xf3\xc8\xd9\xf3\xc3\x01\xcb\x86\\6\x96\xf0>Ox\xe8r\x0f\nH\x80\xf4\xe9c<\xe0\xf2\xa8\xef\xfb\xd9P~\xbe\xc3\x93\xe8\x98h\xd6\x03\x81\xb5z\x8a6\x17w.\xdc\\][[9\xbf\xb8vsqkk\xf1\xea\xcd\xd5\xf5\xe5\x957\xd4\x99\x02\xed\x8e5\xbd\xe5W\x9d\xb2\xdc9\xb1\xa0\x7f\xfc\xc7\x83iu\x1b\xa6\x96p\xc8\xbew\x86\x8d'\xdd\xcb\xc8\x85\xae\xf2H\xf1e\xc0\xbeg6q\x021\x1fr\x19\xc6\xe1\xf7}\xbd&\xec\xd2\xee\xf6\x0e[\xdf\xd8a=\xce\x06\xd2W7a\xd9\xd0 a\xc5\xa5\xc1V\xd0'\xb5\xb8\xa9\xa0Jf\xc9\xab\x0bzyqmw\xe5\xe6\xc6\xee\xce\xcd\x8ds7\xcfn\xec\xae/oO\xbf\x96\xf2\xde \xd8\x92\xb4\xdc\xa7\xd7\xc5\xf4n\xc0\xedV\xd8e^\x97\x0d\x04\x99\xeb|\xfd<\x8b\xd5\xd1R\xfd\xb3\x08\xccE \xc3@\xb9\xc5\x1c9\xc3\x06E\xaa\x83?n\x15\xf8\xe2\xcc\xe4!\xe4\x9a\xdct\xb2a\xe1)8\x90\xa7\xbb\x113\xf0\xaa\xe5\xdf\x9cU\xab]1\xbaZ\x1e\x032Y\xc3\xa8l\x02s\x7fz\x81\xd9&\x16\x13\x07\xe1\xe6\xa5\x91\x7f\xb3\x94\xdf\xce\x05\xe5a\xa3<\xcd\xc4qq\xc2\xe2\x18l\xaf\xbc\xbe\xbb\xb2\xbe\xb4rs}c\xe7\xe6\xe2:\x10\x14\x1c\xe12-\xbb5\x9e>\xf2F\x9f\xef3\x1d\xd6\xa4\x0e\xb9\xf2\x00\xebB>Msk\x9a\xb3\xef\xb2\xf4U\x96\x1f=\xdaa\xfe\xf5\\\x86`\xcau\xba\x9e\x0bN\x05\xf7\xf7\x12R\x16\x8d\xac\xda\x8bO\x054\xbfqC\xe2 \x1bRw\x0bU\xbd\xf6\xa2^\xf4\xd3IVJ\x96rB\xa6\xba\xa9\x10&\xb5%\x1bg/\xae,\xed\xb4\x00k\xc5z\xbcJFy$\xbf\xce\xc5\x01\x9a\xb6\xdf\xafD\xa2\xab\x1f\x9eq\xbe-_\xd9\x81\x826\xe5xEa:b\x87\xa9\x86-\x0cr\x8aa)\x9f(9\x92\x82\xc4\x1d\x07\x12\xa7>\x177\x81\x8dc\xfdv\xfdX\xe5\xa9K3'Q\x1c\xbeu\xbc\xf5\xed/6\xde\xb2\x1a\xc7\xa9\x1a\xc7\xa5\x02 X\xadm\xb9\xa5\x027\xedr\x8b\xc2t\xb9\xe3\x84\xa7\xe2X\xb5U\x88\\/\xe0\x025~(F\xf5C\xe6\x84\x1e\xfb\xa1\x18\xcd\x0fK(\xd4\xa9n\xcd\xb9\xad\x8dK7\xb7V^\xdf]\xddZ\x994W#/\x98\xa9V\xd4c\xf3\xb5P+\xcd\x02\x94o\xa1\xb5Eq\xca\x99\xcb\xd2\xd3O\xdd\xf1\xbc\x1fv\xd9\x0f\xd5\xc8\xd4\"\x88\x115,\x02\xc8\x1b_\xfd*83C'\xdd\xd5\xc9n\xdaz%\xbeyK\xb1\xb4\xb8.H\xdd\xd2\xc6\xfa\xce\xe2\xea\xfa\xcd\xdd\xf5\xe5\x95s\xab\xeb\x13\x96\xc6r%Q6\xc5\xa8e\xa87cB\xa0\xb4<\xe3\x85:\xd8\x98_\x83)kxD+\xd8E 1\x1e_\xd2\x98\x94\x1d\x05\x15I\xfd\xb3y\x0f\x96\x9cP.4OdT\xb2\xa3\x16\xb7$\xe48\x99\x14f=\x9e\xfa \xf7\xa4u\xcfB\x03\xd5\xba..\x97W\xb2I\xe6\xab\xc1\xad\xb2\xe5\xc2|,\x0c\x0fM+\xed\x83W\x99\xa3\xdc\xac\xa2\xe7\x9a\xb8\x98be\xce\x8e\x9c\xa9\x10\xf33\xe6E\x1c\xf0\x91\x1f\xf8if\x99\xfd\xee\xfa\xd6\xca\xf6\xc6\xda\xe5\xc5\xb3k+\xd3\xce\x7f\n\xfaZ\x8fQ\x81\x10\x07\xdb\x16\xff}\xfdk2\xd0\xea\x1f\x18j\x81\\O\xbc\xa3\xab\xc9}.~wo\xd0c\xa3\x7fb\xaa\xd2\xeb\xbdq\xc9\xe4\x9c\x03\x99\xf9\xe2K\xec\x9a\x98\xc7\xd4\xfb&\xd9\xc3\xd4\xfb\xd6(\xd7yZ\xae\xc3;f\xf7\x8b\x93B\xd4\xf3Iq/J\xb8\xd6\xdd\x87\x1d\xd6oW\xe4\xeb\xb0\xd3\xc5\x02\xb7\xd0\x03~\xf4#\xa1\x11\xd0F\x1aL\x1e\x89L\x19\xf6\xa3\x1f\xd5\xe5\x01\xac\x84t(\xd7\xfc\xc2\xab1\x12\x82y\xd2\xe6\xd7\xa3\x1b\xd2\xb79\xd4\xc6\x9dI1\x0b\xcd\xee\x81\x926\x94\xfdn\xf1\x1a\xd7]\x81\x88\x1f\xecLm0\x99\xf9K:\xed\xca\xf7\x92\xcf\x1enF~\x98I\x0f\xfa\xc0Du\x17\xfc\xee\x0cs\xcdW\xd8\xdb3\xaco\xbel\xc9p\xbd\x04\xc7\xe7\xe2y\xe9\x0b2u\x8bb\x91\xd4A\xebM\xbe>\xc5V\xadaR\xd6\x8c\x8a\x85\x12\x13\x1c;\x81\xef9\x99\xf4\xe9\x8aK\x1f\x84\xd6\xe5}K\x15\x9b\xc6\xb3-l\xcf\xbfR\xea\xbd\xd6w\xdb\xa6h\x1dI\x94\xb72\x9f\xb9\x99\x81{\xac^\x9e\x9d\xc3\x98\xab5Y\x0de@U\xe6\x0b\xa9#\xe1.\xf7\xc7<\xe92\xf3\x96\x84L)\"x\xe2\x11|\xcc4*!\x1c\xf9BQ\x0b_(\xad\x0cM)SN'Sr\ni\xcf\xcfw*\x8ew\x96<25\xbe\x93\xf4\x909\xfd\x8c'k\x91\xe3M\x13a \xafk\x93(\xcaVC\x08\xc4>C?\xe9w\xc9\xd1\xf7\x19?\xf4\xb3\x8d\xc5<\x1bB\xb2\x98<\x1b.\xca\xde\xd2\x197\n\xfb\xfe O\xb8\x80Zj\xc6 7)\xdc\x16e*(is\xee\xf9\xa1\xd7\x86\xcb\x0f\xe94\xdeT\x0d\xf2\x1a\x9dan\xb5\x16%O\x94\xa5\xa6\x99\x93\xf1\xcd \x1f\xf8\xa15\x0eD\xfcD?u0&W_\x12\x87t\x81Ez\xb3\xeay\xb7\x03\xcb\xd2\x185\x96\xf2\x80\xbbY$Z\xb4\xbf\x0fY\x93\x95\x16r\xdd\xd4\x0ft?q\xe2E\xdd\xbf\xfdQ\xae\x89\xee!U\xdaa\xdd\x05\x0c(v\xb5\x8a\xf0\x91B\xf8\x13\xa7O\xe2\x9c\x19>\xbc<\xd4\x9e?A\xb2M:\nt\xe2\xf4)\x0c\xca\x0dH\xe6\xd90\xb0&\xb7c`C(\xdbc\xd3\xed{&\xa3J(iWQW6\xbc#\x89\xea&$\xe80\x91D*\x05@\x06\xd1\xdf\xfczX\x93K\xa2L$x9\xff\xa7M6\nj}\xaf\xa7\xcfzY\x93\xf1\xb2Y(s5\x89\xb5\x18\xdb\n\x9d\xacL;\x0c\nQ|/\x1e\x0d\xd9\xd6\xa7\x85\x16\xca\xa5\xcdR\x14\x12\xdc\xd5r\xfaMz5?\xddX\xdc>\xd1\x91 \xcd&>\xb2\xc1\x16\xd8\xf5\x96%\xd3b\xcb\x12\xa6*\xd4\x82\xbc\xdd\x11r\xc8j\xd8\xben\xd2E\xa4]v=\xbbA\xd2\xc1\xc0F\x04\xec5\xe6\xcb\x07\x99\x13\x94\n\xb3![\x99\xfd\xdc\xebdq\xb5\xae5:u\x9c\xcd\xcf\xd2F0\xc5\"8\x0b,\x98\xc9\xa2\x8b\xdb\xe8=gHS+NB#\"\xf4\xeb\x1c\x8d4U\x98\x1a\x0b\xfci\xb0\xc0\x81\xb7[j\xb1 7O ~eX \xc3\x98-X\x907aA\xca^c\xd1\xf3b\x81\x0d\xcb\xd5\x96\xa5So\x19\xfb\xa6\x89F]\xed\n-\xa5#\xca+$\x84d^r\x14d\x8e<\x00\x90Kq\xf5;\xe8+$\x1b\x9e\xc3\x11\x16\x81\x8a\x87\x98\xb7\xf2\x14\xf7\xeb!\xa7\xfa\xaf2\xa9\x97\xfeT:'kT\xca\xc9\xdae\xc1\xcc\xf6\x85\x8d+7\x17ww.\xdc\xdc\xdc\xd8\xdc\xdd\x9c\x90oY\xfb\x95e3\xb1-\x9f\x9f\x9e\xd1L\xca\xb3v+\x1dF\xfbe\x84\x17\xa8Q\xda;\xfbx\xc4P6\xb6V\xaf\xad<\xefH(B'&Op?\x89F\x17\xb7;BW&\xa5\x80\x90\x0c\xc4\x80\x8b\x1c\xc1-x8CV\xbe\xe4\xc4\x1d\x1c\xf8n\xd4%\x1ef\xc9\xe16\xbf\xdd\x9e6\xe3\xba\x96\x0dP\xbaN\xdee8\xb0U\xff\xe4,\xaf\xcf\xd6\xe46H$t\xae\x06\nIe\x159i\xc1 \x17T*\x939\xcfjl\x0c\x95T\xab2\xc7H\xe9\xa5\x1d\xbf#W,\x92[\x1c\xda\xcdG\x85\xa9\xac\x94\xdf\xd4\x9a\x97\x87\x95\xc2}\x8aq\xca\x93.\x86\xa9\xb9R\xebFC\xfca`\xaf\xab\x19\x96u\x9aLm|\xdb\xccET\x0e\xbbL\xd5ot\x9f.xe^?*H3\xb7P\xce\xa6\n\x8f\x93\xf5\xb2\xc8)?\xdaS\xf7Ls\xa7S\x1e\x96\xda\xba\x1b]\x98j[\x7f\x98\x98\x11B\x066\xc3y,\xa1\xb7\x10\xad\xa6?\x8a77\xc4\x9f\xf3/\xe6D\x86\x92Q\xdb\xcfaX\x97,\xd9\xa9\xf1u2\xe7\x10\xde\xeb!o\xfd\n\xaa\x17u \xcfH\x95\x14$z]$\xd6T\x96\xc6\x81\x15\x96\x88\xd7\xb9\xd1-\xe7\x05\xac[\xaa\xb5\x8d\xf3\x1b\xbb;/f\x81,\xc4hf\xdf\xcf\x86\x97\xf2\x0c\xaeG\xa6\xc8\xa8h\xc9\xe4\xd5\xf8\x8c+\x9f\x81\xc0\xb2\xda\x10^\x0b\x9a\xd5\x98N,\xb8\x96L^\xc0\xa5\x8d\xf5s\xab\xe7w\xb7V$/z\xde\x85l\x1a \x18\x16,\xdcG\x8d\xea\xb7+\xc0t\xc1\xf6\xb8\x04\x83\x94s\xf2\xd3E\xb3x\x90\xd4\xad\xfaO\xaf`\xa9\xe7\xa2d\x0bLY\xe0\xbe\xa4\xd2\x0f\x94\x98\xee\xd9\xc3ug\xc4S\\q'2}H\x90`\xd5a\xa9\x9a\xe5\xb8i\xdbS\xde\x0e\xdb'\x89t\x15)\x08\x95\xa1 o\xc3),D9J\xb4z\xbe8\xe2\xafDV\x1a\xab\x04B\xf5\xc7\x8a\x9a\x05\xcb\x967\xcb\xe2\x01\x19\x82\xec\x90Z\xe5\xe8\x08enr\x1f\x8a\xbc#\xd9\xa9\x83p\xa6v/'\xf7\\\xd3\xf1tb\x0b\xd2\xa2l\x0f \xb4\x8d\xec\xe4\x80\xecT\xfb\xcaQh\xe4\xa05?\xcd\x88\x90\xc5\xca\x96\x8b\xe7\x16\xb4\x18\x12\xb6\xa2\xa9\x84-fD\xaa:\x81\x8b)\x9c\xae\x17\xbaXIYt\xac\xe2c\xb9T.\xc9T\xd2\x95/%\x86\xe0\x1b\x9b\xa7\xc3vn#\xb9]\x9c\x17\x91\x92\x12\xeb\xe1o$\xa7S#@H\x11\x80\xce\xcb\x8d\xc24\n\xf8\xcc\xbe\x93\x84\xed\xd6\x95\xc5\xad\xf5\xd5\xf5\xf3\x0b\xcc>2?e\x1e\x8f\x13\xee:\xe00\xeb\xb1}?\x08X\x8f\xeb0\x1e\xed\x91\x19\xf2\x83\x8c\x8d\x9c[Q\xc2\xc6\\g\x9aB7\xe2;\xd3\x04\xbb\x11\xe7\x99\xce`,I\x98?\xa1W\x1b\x8f\xc1\xbf\xca\x9b\x039PF\xa9\xba(\xd7\x95T\xd0\xbc\x97^b\xed6\xbcp\xa1$\xe3(\xe6i\xab\xd3\x99\xd9\xe3_h%\x99\xf4~v\xa30s\xfc0U\x17N\xb2\x87T\x8bI\xdc\"w\xeb\xdf]\xe5\xc1\x98+I(\x08\xa2}\xeem\xc3\xa8\xba,\xed\xa8\xe46\x99\x84\xfb]f9\xe9\xba\x1d\x1f\x9e\n\x95\xb9\xcd\xec\xf4\xc0\xaf\xa3\x07\xddI\xa2B\xfdbh|u\x92\x81\xbc\x08L\x0b\x07\xb79V\xcd\x15f\x8a\\\x9f\xbb\xc1^\xab\xfes\xa1\xe9TMEtT\xa16\x18\xfa\n\xaec\xe7~e\xc6\xa3\xfa\xecL\x9f\x84\xdc\x1c\xf14\x1a\xf1)\xc5fSG \x1e/\xe1\x9b\x9f\xa4Y\xbb\x06G\xac\xb2t\xd3.V\xe4\xbf\xc9\xfc}\x82da3rh\xa2\x84\xb8 \x92D_$\x13\xa9\xeeg1\xa6\x06\xe2\x0b\x9b:\xe3\xa7\xe2?\x10\x1b|\xe4H\xa6\x8c\x95\xcf\xbd\xcf*\x97#2\x9b\xf2\xce\xcc\xc8\x89\xa7h\xa5\xd4\xd2\x91#!\xec\x7f\xddv\x1b\xaf\xd1#s\xb6\xad\xd7\x87\x0b\x99W\x19E\x84\x8a\xa2\xf0\xa5\x11A+F\xe5]\xff\x16\xfbFhD\xfc\x80\xbb\xb9\xf4,\xb0j!]\x95\xe5f\xfe\x94E\xd7\x90\xd6\xceH2\x88\xa4\xaa($\xcd\x8aB5^\xb8\"\xe1\x17\xe3\x99R/\xad\xa0\xb7]\xcd\xcf\x9a\x04)|\x9aj\x9f\x83\x89\x94\x1a\\\xe7\x8e\xe8\xa8\x0c\xd6\xd90\xaayr,\x97%\xa6x\xc1M,C\x968\x0d\xcf\xc9\xd6\x1f\x95\xe2\x80/(\x03\x90>\xeeb\x9f\xaa_\xd4\x89\xae\x97\x1eJ\xd4\x7f\x81%5*\x88\xdc~+hb\xfb\xe5W\xdd\xca\x1d\xe0VMS\xf6s_K\xc8x\x1b[\xa9\xac\x0d\x80\x93_\xcd\x1by\xb0\xa3\x0b\xcc\xb1\x83K\x0f\xde\xd4\xd8(\xcb\xaf\xe6X^\xbf\x95rJ\x1d-\xfa\x86P\x89/\xe3\xf1\xd2\x0f\xebnB\xd3\xa1\x94\xd8Vn\xe7N\xf0}~\x08(\x86\xbe\xd1\xf5\xaa[*j?\x917G\xdf\x80\x15\xa4#K\xdba\xfb$y\xe7:2>\x16\x13\xfd\x8dj\x05I>\xd3\xb7\x10\x16{\x82\x02\xf1\xf3\xa2\xfd0\x98\xd2\x1d\x89Y\xc8emj\n\xfd+\xf4D\x9e$\xea\x02\xb9Y]aZQ\x9at\x8d\x8c\x7f\x8e\xa94u?\x10\xf8Tp\xfb\xc95\x02I\x9f\xfb\xa0\xc4v\xcc\xddv6\x93 ~'\xf4\x8a< \xda\x9d\"\x93\xbf.\xb6\x9b\x04u6\n\xfdk\x1e\xbbL\x14#8\xac\xea\xa2[7\xc6\x00\xfe ,\xdc\x0d\xb8\x934\xbc\x8d\xa1\x7f\xcf\x83dB\xfe\x0f\xa6h3O\x82\x05[\x9e\x16\xfc\x13\x03\xde\x96^\xd1G\x1a\x1e<\xd4?\xf5 \xe9j\x98\xf1\xc4\xe5q\x16%\x0b2=\x0f\xfe*\x96j:\xf9\xb5\xfc#w\x8du\xbf\x1a\xef\xee\xf2/\xe1i\x1c\x85)'C%\x9f\x7f\xfbcu\x13\xee\xf10\xf3\x9d ]`\xad\xd4\x19qEg\x1b\xe2\xe0\xf4O\x91\xb7&\xa7\xf6\xf2OP\xc98[\xa8\xbe\xe2y+\x8d\xc2\xee\x1f\x1c\xff\x83\xc9\xe4\xad\xf9\x94\xdc\xed\xccdC\x1e\xb6\xfb]\xd6o\xb8$\xb0Bj\x96\xc9r\xc8\xa6\xd5\x8c\xb4@x\x1d\xa2\x1d\xcc\xd1\xec\xb2V\x11*\xa4i\x8a\xf9\x08zG\xab\xe1\x0d\xf4\xaa\x1553&Nx\\N\xdf\x01r\x95\x11G\xfcg\x01\xc4p)\x90Ws h\xdf\xa8\x92\x1d6\xebLdT\xd9a,\xa8\x85\x90\xb5n\xc2\x02\xddT\x93\xbb B\xf8\x04\xbcQ\xae#\xb6\x04n\xfaW\xb3I\xe4\xab\xcd\xff\xb9V\xb7\x0d\xaa\xdbh7\xe3N\xb7\xb9\xc6)\xa2\xce\x8c_\xfe\xddm\xb2\x0c\x97\x7fU+qe\xb8pc@\xcc\xd4\xfag\xbb\xd9\xb0\xda5i\xe7\xd3\x04\xd8L\x8a[113\x8d\xd9!u\x10N3v\xd5\xa3\xd5B\xb3\x0d\xd8\xf6S\xb3\xb6\xbc.g<\x98 \xd1)]\xf0nQD\xe6;m&=\xf5\x98\xdc`\xed,\xa2\x88j\x1e\xa0\xa2\x9b\xfa-\xfb\xbf\x90\xb5k\x82\xe7O\xf5\xab \xca\x99\x9f:&\xe7\xab\xf2 \xfa\xed\xda\xe5\xbe\xace\xf3\x85\x9e\xa4\x1a\xf32\xab\xe2M\xdf\x8e7\xf6\xba\xea\xdai\xbaH\xb9t\xe6EG\xca}\xe9x6j7u\xdba\xfb\xf4 \x12\x9c\xa6\xee\xa8N\x9c\xb0\\R\xc9\x00NZ\xc5Q\xa0\x93\xb3\xb3\xb6P\x04\x00\x11\x0bm\xaa\xc6pr\xb6\xe6\xecXB\xb9\xfe\xe9\xc5\xb3}\xcd\x01\x18c\x95T\xb2\xda\xc8\x80gk\x91\xeb\x04 `-4\x9b\x03\xb5\xf7\x834K\xc4N\x92\xf2\xab\xceHU\xed\xb4\x0bi\xa9q,\xbf}bf\xec\xd8g\x0fw\x130Tk\xfb>|op6\x85\xf3S\xb9v\xc0U'^w7_\xa2\x96\x169\x9b\xe9\x87`C\xef`E\xb9\xee\"^O\xe9\xb9\\#\xac\x06*}\x99[\xb9*\xa0\xf2\xb7<\xb7\xe6\x9cFh9\xda\\)\x1f~\x97\xf96\x03\xbf9\x0d~\xfd\x1dIh5\xe2\x87U#>{\x8d\xb5\xa3&\xfb\xbdR!:\x02w\x9f\xab\xd8n\x12\xb4[\xe2CU\x89\x08KV\xfd\xc2\xa8?\x93'\x81@2x\x81]HH\x99\x8a\x84#\xe7%\x04\x03\x89ED\xfd\x06\x9f\x9f2\xe6\x0fx6%\xa6q\x15\x0d\x83\xdf\xdf\x94\xf6\xfc\x05\x19J\xf8\x0d\x9d\xa5v\xef\xe8*\xe1q\xde\xf6\xda\x9f\xf4\xf0\xf0\xbf\xbc\x87\x07e\xb0u\xb1~\x82U\xdb\xef>e\x00\x91\x8e\xad+\xc5sE]\x96\xce\xecn./\xee\xac\xdc\x84\xd8\x86\xed A\x0df\xef\xe0\xb9\xf1j\xb4J\xa1\x04\xd0P\n\xdc\xeb\xce\xc6\xf9\xf3k\xd3\xf6\xfa\\1)8U\x89\x19\xb2\x8a\x05;\x82\x02=\xa2o\xc2=\xf7\xf3\xc9\xd3\xd7\x0d[\xb5\xd9\x1f\xa6\x91\xad\xa7\x90o+ \x16\xea\x8b1e-\xe0\xf8\x15\x8d\xe7\xd09\x9f\xfb\xbe\x91C&\x1b\x95c\xb4[xtNa\xb2f%\x84\xda\xf7C/\xda/.3\x86NZ\x93\x00\x0d\xff\xb2\x99\xc09\x8c\xf2L\xc7uKJ\xbe\xccy\xbc\xe6\x87{\x17\x9ct8\xcd\xfd\xd2\x04\x1b]-\xf4K\x98|\xc4\xae\x9a\xfc\xb6\xb5\x1b[\xf2\xcc\x99\x90\x06\xc4$\x1d\xdaq\x06\x0b\x85\xbb\x10\x1dJ\xe5\xcb\xdd\"\xd1\xacEUq\xa4\x9a`UU\x00\xf4\xb2-|\x07@\xdf\xb1+\x17\xce\xd7'W\xff\xf6 \x89\xbc\xcc\xd8v\x93(\x08v\xc0\xf5.U\xffPw\xe0\xf2[\xc2\x1d\xefp'\x82r\x8a\xb8\"\x1c\xae\xd45!X\xcd\x0e\x8f\xfd\xda\xb8\xf6\xbe5\xf2\n\x0c-'g\xb1\x97d\xaej\x9c>AR\xa34\x86\xb6c\xde(\xdf\xa0l\x07V\xac\xe8\x7f}X\xc1\xd4*\xc5\xe5e\x9cH/\x0b\xc67\xc9\xcf\x06\x9c5\x81&5\xc4\xbdLKp+\xef\xf8c\x0f{\xd8h-\xafU\xde\xc2\xcfT\xee\xe3\x08r\x1f\x17\x9e\xf6y\x8d\x99\x1e\xb2*V\xa9y\xd4\xe9\xb2\xb0\xdd\x91\x8f0\nT\xf4\xc3Ag\x8aG`\xc5\xfeG\x13#D\\Yj\xae\xe1\xd6 0O@k\xa14\x10Bi \x84\xd2\xa0\xa1\x9eV\xa6\x13!\xef\x8b\xe3#+\x9fK\xa2\xd1j\xba=\x8c\xf6\xc3\xef\xf3C\x89\x88u\x0d\xc8\xdca}\xf4:ls\x7f1\x8d&\xeeO\x8e\xa5\xf1\xd8\x19\x16O\\\xa9\xa1,\xd5\xb4Rr\xc0n\xa7\xac\x9e:B\xcc\x12\x93\xef\xc8\xa4\xa2\xf5u\xe7\xe5\x9d\x8cyX\xf65\\\xbb-\xe3\xd0\xe1\xcaA\xd3\xa4M'\x83v\xd9Q\xe6Iw\x16\xf1\xd7P\xaaTs\xd5\xf6^z\xe9\xb9\x1b\xac\x8b\x84\x98\xea.\xbe\xaa\x07N\xff\xb2Z\x95hT7\xc4\xc3\xf4\xb7\xf9j\xa4\xd6\xd8\xca\x8a\x8b( \x107\xa1\xcd\x9bYTs\xfdd\xae\x9dp\x1eIE\x06\xafs\xfaTW\xe3T\x86\xb5\x0cf\xaa95[GX\x85RV\xe4\xb2z\x0c\x9f\x92`2\x85\xe6`z)\xa8p\xa7J\x9f$\xbbh\xc2\x8f\xb1\xc9\x06\x04\x0f\x90\xcc5\x1c\x8d\xd6\x11\xf08\x13\xc4\x8c\xe9\xcc\xf9\x91\xa9\xd8\xe9J\xc4o*\xd1L4|\x9c\xf9w\xfah\x12\xfd\xd3'\x9e\xebwhT\xba\xdd\xf6\xf1\x9b\xc7\x07]\xd6b\xad >\x1c\x13(\x94#\xe9\xa8o\xe8\xa6\xa0\xa2\xbb%\xaa\xda\xf6\x1b\xe6\x18J\xfe\xdav\xba\xf0\xdc@h\x8eP\xdby!\xe7rl\x95\x9f&2\xf3\xa9,l\xac\xe2\xf7\x8b\xd0S\xe0\x9f\x96\xeb\x043\xa9Y\x03\xd7xi\xf9i;\x01\xfd;0Z:\xef\x80\xe1:D\x1a\x0c\x92\x11%g\xc7e*\x92\xa5-t\xacq\xddF5\xb2\xe8\x8b[\xb9f!A\xca\xbd`&\xec\x87\xc5Zn:\x89\x98/\x17\x92\x8cY9u\xd7-\x0b\xc8G\x1eg\xb2\xa8\x96\xac\xff\xd68\xc4@\xae(\x96\xf7\xa7\xb1\xd7O\xc3%d\xbb\x8aWP\x87\x1340\xbb\xe5\xa9\xda\x8d=\x9e\x01m\xc4\x94f\x04M\xf0\x8d\x97\xaf\xfeC\xe1U3\xe5\x97\x84|\x14\xe7\x19\xf7\xb6\xb3\xc3@\xe6#\xae\xad \xd6\xb4\xe5\xf4\xd2(\xc83\x95S;\x99\x89\xa3T\xc6\xea\xd4W\x93\xf1\xf7\xec5v\xbc\xed\xe4Y\xf4#X\xc7\x1f\x0d}\xcf\xe3a\xe78[\xa8\x02:\xc7\xeb\x99O\xab\xef\x1fp\x0f\xf7\\\xbc\x90f\xafidx\x99^\xf0U\xf9\x1fG\xf0\xe0b\x91^\xad\xa7\xd221\xbdm\xa5\x9cN\x97\xb5\x8f\xc8wTZi\xe6d\xbe\x0b\xae\xd3\xe5\x81\xbd\xf4\x12\xf3eZ\xe0v2\x13\x8dy\xd2\x0f\xa2}v\x94\x15\xff\xb8Z\xf9\xd7\x1b\x9d\xc2\xdd\xde>\x17=\xd3IX\x88\x14\xc5 \x960\xc0\xf3\xdaT\xa9\x93\x8d_\x88\x96-\xb0\x86D\xe7\xba\xec\x02\xab\x89q\x13\xbf\xcaQ^`\x83\x06,.\xb3\x9f\x056\xae/I\xa4\xae\x056\xb4\x13\x1f{\x1b\xa5{\xe9\xfa\x95\xa8r\xa6i\x1d\xbf\x18\xc3\x9e\xccM\xef$\xf5UZ\xac\xed\x01\xb4_\xd4{\xa44\x8b&\xa9\x1e^;\xf1\xbb,\xb7SgDX\xb2\xa1\x9fvY\x9d]\xd5\x08\xc1\xa9\xd5\x90\xed\x1aCv\xda\xe9J\xeb\xed\xec\xab\xac\x0f\x8f\xf8\xf5\x8f\x1e\xed0\xf7z\xbfj\xc8\xee7\xbf\x16/\xd8\x9cO3\xa7\xc2 \xe5\xbb\x83\xc1\xcc\xcd\x9b\xd2\xb9\xec\xe6M\xed\x12]\xf2)\x0f:\x1d\xe9a\xa6L\xe2\xbc\xcb\xae\x8b\xba&\xc9\xb2\xdb\xe9\xc8\xf0\x99(\\\x8b\x1co\xa2\xfdL\xff4\x07\xf6g\xe2$\x8a\xd3\"\x93\xc2L\x16\xc1\xc1j\xca5\xc0\x14\x17F\x92G8\x939\x83\xae|\x04U}]\xf5\x1a8*\xbe2\xadH\xb0\x82?\xd4\xe9\xc4p\xc3\x10\x12G\x02{V\"J\x96K\xe6\xe9\xbc\xb4\xd2\xf06<\x92I\x82.\xaby\xf6hO\x88=\xad\x84\x87\x1eOj\xcc\xa6\x8a\xdaL\xbc]a\xc5\xa0Rdq0Q\xaai\xec\x84\x84\x9c\xd1F\xfa\x0b\xf0\x9c\x04\xe0Cm\xe1\xbb\xdd\xda\x9e\xb8z\x90B\"F\x1d?\xa7\xab|\xa3\xd3E)\x19\xee\xb6\x8b.\xcc\x15\xf37\xda\x87\xe7\x1bG\xfaCi\x176\xff\xfc\x1d\xd9/\xfd~G\xf6\xbf8\xd9\xb7\xe8\x85\x9a\x13d\xce\xe0\x0b\xd3\xec\xf0w4\xfbw4\xfb\xab\xa6\xd9\xcf\xe7\x1ag!?\xb5It\xa28='\x13\xb2=\x87\xe3R10\xc4Kt\xba\xaf\x93\xb3\xa7-L\xe3E\xe5\xfb\xfa\xe6\xeeG\xa3\xb7(\xc9{gy/\xa5TA\xbe\xd5~\x86\x85&`\x13\x87\x0f\xfc\x97\x85\xa1\x93\xcc\xd4l\x8a`\xa8)\xed\x19\xcc\x04\xeaB$\xf9tlD\xff\xa6\xf5\x1e\xc2?U/\x91\x0f\xc0w\x1b\xbc7'\xb6f7\x9a\x19h\xb3\n\x03\x13\xbf\x98F!\x9e\xfc\x146L\xf6%\xe6os\xe3jwf\xa2P\x90\xdc\x80g\x96G!m?\xb3\x8c/\xbd\xc4Zz\x10\xe5@\xcdP^\xec\xa6<\xdb\xf1G<\xca\xa5\xbb3<\xb8\x7f\x86\x1d\x99\xeb|\x95+_\x0b\xad1s\x92\xaf\xd3\xd2Y9\x15\xeb\xa1/\xefF\xf9\xbd\xc6\x96\xe7d\xce\x82?r\x06\xfcx:\x1e\x1c=\x18\x05\xaf\xf6\x9c\x94\xbf|\xb2\xbbya}\xfe\xda\xe1\xd9\x13\xce\x95\xadYgy\xd6\xbftkq\xdf\xbd0\xf0W\x97\xceF\xd7\xae\x04\xa1s\xe1\xf5\xd3\xab\xb7V\xf7/]8{r\xd5_\x1c\xf0\xf3si/\xbctzu4\x9c\xf5.,\xbe\xbcvx\xfa\x84w\xc2\xcd\xbd;\x97\xf2\xde\x89\x8b\xe1\xda\x9d\xd5\xfdK\xcb\x8bc\xf7\xc4\xb5p\xd5?;\xef\\\xb9|\xe2\xf5\xd1\xe9\x93\x9b\xdb\xab\xfb\xab\xcb\x8b\x83K;\x8b\xfb\xab\xcb+\xfb\x97\x96V\x07\xee\x85\x8b\x81;\x7f\xf9\xd0\x1b]>\xeb\x9e8\x1b\\=\xb1\xb5}\xf5\x8d\xad\xb8wg\xd6\xe7+s\xf1\xb5s\xc1\xbas\xe5u\x7f\xf5\xfczz\xf5\x8d\xf5;\x9b\xdb\x17\xd3k\x17.e\xee\xe8t\xda;\x1f\xe4\xd7\x0eW\x07\xee\x89\xadS\xbd\xf3\xbb\xa7WG\x17\x87W\xe7\xb3\xd0\x1d\x9d\x9e\xeb\x8d^\xcf\x9c+s\xc3k\xf3\xbb/\xaf\x9e?5\xee\x8dv\xbf\xb3z\xbe\nw\xcf\x9f\xbe\xe3\x88\xbe\xe6O\xbe\xbcz>\xc8\xc5\xdfW\xaf\xec\x0f\x9c+\xa7b\xef|0\xec-\xa7\x83\xab\xa3s\xb7\x9cy\xef\xb0w\xe2r~mi\xee\xf0\xda\x1bg\x83\xabo\xbc^W\xde\xdf\xbcup\xcby\xe3\xe2\xad\xde\xf9\xdd\xc1\xd5\x13\x83\xd3\xab\xb7v\xf7W\xfd\xb3\xb7\xf8\xce\xac\xbf\xbe\xb3\xe8\xaf\x9e\xbf\x16\xf7\xce\xef\x9f^\x1d\xc91\xf9\xab\xe7O\x85kW\xce\xcdz\x17V3\xf7\xc4\xd6ao>\x0b6\xb7/~\x87\xcf\xaf\x8f{\xa3k\xf1\xb5\xc3S\xb7z\xf3\x07c7\x9c;\xbd\xea\x9f\xcd\xaf\x1d\xce\x0d\xbd\x0b[\x87ko\xac\xcf\xba\xa3\xd3\xc9\xb5\xed9\xb3o\xfcDv\xab7\x7fj\xe4\\qso>\xd8\xf3\xce\x0fO\xf7\xb7W\x07\xbd\x91\x9b]}ck\xd6\xf5\xe7\x0eQ\xdb\x87W\xafl\xc5\xde\x1b\xeb\xb8\xdc\x1d\xef\xc2\xc5\xb13\xbf\x9b];\x7f\xee\x8es\xfe\xdc\xa1;:w\n\xd5\xdd\xbb\xfa\xc6zt\xf5\x8d\x8b\x87W\xdf\x08d\xfdb\xfc\xab\xb7\xd6wv\xe7\xc4\xffV\xfd\xb3\xa6-\x18\x93X\x93\x15\xb1&\x87\x9b\xdb\xabw\xd6K\xf5\xd6\xael\x0d\xdd\xf9\xe1\xd0\x0d/\x0e\xc5z]\xda\xb9:\xbbvk\xef\xce\xa5;W\x0f\xd6\x97/\x1d\\\xba\xf3\xfa\xfc\xfa\xf2\xca\xdc\xea\xf2\xee\xfc\xda\xad\xbd\x13\xebw\x06'.\xed\xbc~g\xfd\xce\xe0\xf0\xd2\xce\xa5\x93\xab\xb7N\xber\xf5\xca\xa9\xb8w\xe5\xdc\xec\xb5\xcb[\x87W\xaf\x9c\xbasmt\xfa\xb0\xb7}V\xae\x99s\xe5\xe2\x9cw\xfe\xf2\xc6\xd5+sb\x8dg\xdd\xd1\xb9\xdc\x9d\xbf6vG\xb3\xfe\xea\x85\xadS\xae\xc0\xa1\xf0\xe2\xd8;\x7fn\xf6\xda\xf6\xea\xe0\xea\xfc\xb9\xf4\xea\xec\xdc\xf8\x9a\xc4\xad\x83\xb87\xbau\xf9|\x90]{\xe3\xd2\xe9\xd5[\x8b\xdf\xb9\xb4\xbd:\xb8v\xe1\xb2\x98\xf3\x81{\xb8:\xb8:\xba\x1c:WN\x9e^\xbdu\xf6\x8eX\x0b\xc0\xab\xade\x81g\xde\xf2\xac\xef\\9\xb5w\xed\xca\xb5\xb87\n\xc4X\x8en.\x9d\x1e\xf6F\x81\xd8\x9f\xe0\xf2\x85\x8b\xc3^\xb8>\xea\x9d\xb8\x98m\xde\xda\x1f_\x9d\x0f\x0e\xaf\xce\x1f\x04\xe2oq\xe66\x07\xd1\x99\xd67D\"X\x8a\x82\xc0\x89Sx\xbab\xcd\x0f\xf7\xe4\x1f\xe0\xcb#\xff\\\x0d\xe3\x1c\xfe\xda\xe1\x07\xd9b\xc2!\x0d\xea\xd9<\xcb\"\xe0\x16[\xd2KX6\xa5\xfe+\xb3}\xcb\xb7{\xeb\x82\x11\xa5\xff51Ch\xcf\xecW\xac\xafS\xf6mF\x10G7f3i\xf4mF\x90T\x01H\xef\x81\x02\x10#\x88\xab\x00\x15#\x88\xf4\x13\xb7\x9b\xbf\xbf&\x87m\xdaqLx\xbd\xb10p\xab\x85!3\x16\x06\xae^L\x98}\x95\x85\xec\xbb\x8c\xbf\xca\xc2\xa3G;L\xc5\x0d\x17\x16\x86\x10\xa9\xe1jb\xd9tI\xa3U\xe9#G\xd0\xac:3\xb7\"?l\xb7X\xab3\x93%\xfe\xa8\x8dEg&\xb5\xfc2f\xd5wd\x96#\x9b\x14\nLl \x99R\xdbSb\x1c\xc9\xa8a\xa4|G\xdc\xe9(\x99\x05\x8a\x17\x12K]\xec+\x1aIPj\x0b\x9e\xdfE6\x85\xccj=\x98`9\x98\xd6j\xa0\x11\xa4\xd0\xd6\xebET\x95\x834\x0f\x82\xd4M\xb8\xed\x81)\xfd\x0bM\xc9\xfa2\x96\\q\xbc\xcb\xae\xb7\x8a\xf6e&\x9d<\x08j\xdf\x1e\x93\xc9\xec\x8cg\x8e[k\xf5\xe0 \x88B4\xaf\xad!\xed\x84\xd4J\xf7\x9d\xc1\x80'\xc7\\\x8dn2\xabN\xc8^c\xadcr(l\x81\xb5\xea\xbc\xc6\xa7\x1fG\x9b>3\xe97\x99e\xdc\xc0I\xd3u\xf9XZ\xdc\xf6g\xcc?+\xafj\x95\x7fw'\xbb>\xde\xe8Tb\xfd\xdb\xae\xc5\xceR\xa5\xde\x1e\xf1\x97\x1bE=?\xe0bI\xaa\xfb\x9c9\xbd\x80g\x0b\xacu\x0c\xfeB`\x8f\xa7{Y\x14\x0b\xb8\xfa\x13\x15\x08\x9cd \x9a=6\xf4JW\xb3\xafV\xe8A\xf0;J\x00\xbf\xdf\x1a%\x18\xfa^CV8\xa0\x01{\x9c\xc7K\x90\x8d\xb3\xa1=I\x0b\xf8\x0c\xa0\x93\xd0\x02\x01m\xba\xd2\x9bB\"\x88\xf8Sb\x05\xf1\xdb\x90DC\x0cE\x90\x8brw\xe2\xdf\xd0\xa2|\xabQ!\"k\x19\x94c-\xd9b\x8b< k\x86%\x93\xf1\xbe\xf4\x12;\x12NAe\xc0\xb6*C\xe8\x9b\xa9\xcc\xf5\x1a{\xb6\xe1\xd89\xf3C\xe65\xbb>z(\xedG;\xefL\xd2\xf6\xf5u\x83W\x1b\xec\xa4\x7f\xa2\x83\x1c\x1e\x0d2F\xdc)L :\xc8\xa9\xa85\xb1'\xa6z\x0b\xd8w\xd9\xdc4}0\x99\xd4Q\xbe\xe5\xd2\n\xa3\x90\x0b\x02=mT\xad\xa0\xea~\x98O\x91hob =\x84^\x10\xb9{0\x86\xae\xf9\xe8F\xc11\xf9(\xa5\xfc\xde\xd8\xd6\xf3\xda%t\x0cW\x8c\x0c%\xd7K\\\xc1\\\xca8u\x88=\x11\x97\xbf0\xa7J\xb3\xc3\xa0\xf6yl\xfd\xf3\xfc4\x0e\x9c\xc3\x05\xe9}\xacv\xd1\xf2nG\xf9\xd7`9+1\xc7\x9a\x14J/\x86\x19v\x8d\xc2\xf3;\xb6\xf3\xe2\xd8\xce$T\xf4\xfc\xb1\x1d\x0dK|jZ\xc9\xa9\xa8R\x16\xa1Z\xfb\x89\x13\xc7<\xa9u\xd2{!\xd8S\x1c\xc4vI\x85\xfe\x1d&}}\x98\xd4\x93\x8b\xfeU#\x93\xea\xe5+\xc5\xa5\x8e\xfe&\x98?\xcd\x91Y\x1af\xabF|.\x19t\xeaQp\xd2\x82f\xfc s\x12\xee\xb4*\xb7\xec2\xb5\x936\x1d}\xf1\xc6}\xd1\x02j\xb9r\x86\x8c\xa1j\xaa3Tw\xa1Ws\x80(\xdb\xd4\xe6\xab/z\xb0dV6(-\xc7b\xe9b\x08\x85lo\x81\xeb\xe8\xcc\xba\x17 \xd4jB\x00\xa7<02\x15&\xfc\xb5\xc0\xf8\xcc(\x0f2?\x96V\xa7\xeb\xad\x96\xf4\x0bo\x89S \xaf\xf6j\xb3\xac\xaa\xa3\x17Q\xa4\xedZ/~\xf5\xef\x1bC\x13\x9e_\xa9Q\x0f\x0d^\x16\x1d4\x14\x06\xedF\xafj}\xb9\xa4hte\x14g\x87\xb2\xdd\xfa\xe2\x91\x1e\xab\xdc\x17\xd8?\xf9<\x12{\xcd\xfe\xbd-\xb3u!\xc8\x17\x15\xfa\xc4\x81jt\x0f)Q\x16+\xf9\xab\xad\xa8\x17\xaa1\xab\xac\xc6\xb6\x86\xe5 \x97\x86N8\xe0\xc6?\x05\xfei-/P\x94\xbdV?\xdd(V\"n\xfdt\xd5\x80Z\xf6d\xd6w\xbb\xacu\xecX\xab\xa3DWA\xf6\xaaq\xca\xd3\x054|\x99\x012}R\x1a\xa2 Y1\x91m\x999\xb7)}\xfd\xddnQ\xe8\xb7\xc9\xc2\n|92\x87\xac\xfe\xd5\xa3T\xbd\xd7\xa8\xda\xab\x86\x93BM\xcb\xd4\x81\x9e\x99\n\x8a\x95\x9b\x9a\x18\xf2\xc9'\x91\x1a\x08\x9e\xd6m7\x93\x83p\n*\xe3K\xab\x02\x84\xd7+N3\x939\xc9\x80g3\x80Ei\x83\xf3\xb43\xe1\xa5\x1b\x01\x8f\xd8k\xcc\x9f\xce\xd0\xaf\x7f\xc6\xb7\x06\xe8\n\xb7\xfb\x91\xdd}\x9e\xe0~\xd3\xa4\xc4\xe7\x9a\xf6\x04=\xd4\x93\x97\xe5\xba\x103\x04\x81!\x13\x0f\xbbS\xd3l\x17\xdc\x1a\x12[\x88>\xc2\xff\xeaR\x8f\x85\xd0`.\xd8\x9a':A\xe8g\xbfe\xc1\x9f\x91\xb9\xb2\x17\xc2\xec\xd9d\x86\xcf\x9e\x83\xe9\xb3)\x88\xab\xf3e\xf4\x00\xe8 X`\xad0\x8ab\x1e\xf2\x84\x85Q\xc2\xfb\x9fCe\xd5e\xb0\xce\xb6\xd1\x8c\x98c\xf3\x04\x9d;\xf4\x03/\xe1\x96\x90\xeeIK\x0e\x9a\xbc}U'\x9a\x8d\x86\xdc\x1f\x0c\xe5c\x13ymR\x18\xf1\xebE\x89\xc7\x93\x05eUj\x10H\x9cd\xe0\x87\x0b\xac\xe1\xa1\x92\xd8\xf1\x95\xfa\xf2O\xc9\x04\xb0\x1ee\x8b\xa1?r2\xee} \xc9_\xdfN\x17'\xccO7\xc4Y\xf5\x1a\x84\xc2\xb1\x8e\x19,\x1fL\x85\xf0\x82\xb1\xd4\xe2v\x18\xa5n\xe2\xc7\x99\xbe\x00\x98@6\xef\xda\xce\xc1oO\xe5Q\xab=I\xdb\xd1\x0b8I\xdb\xa9'\x11\xac\xb41\xec5p:\x0e\x95\x8f1,\xfc\xc4\x9dI:F\xe3!\xe8by\xb3\xe3\xc5\x8b\xa6z\x15,\xa2\xa9\x1a\xc6\x82v\x00d\xec\x9b\xe1\xffK\x9dp\xbcZ'\x1c\xcf\xe6j\xe3\xeb*6\x1f\x1c\xcf\xe6j\x93+\x8057\xa2gs\xb5 \x14\x80\xe4\xecw\x15\xe0\xf4+\xa71\xa8\xaf@sd`\xb1\x86\xd8\xfdt\xbc\xaf\xc7OG\xffE\xb4\x91\xe7\xa5\xf5E\xfcQ\xd2\xb5\xa5 \xc1d\xbc\xd6\x8c5!\xee(\xa8\xc4\x1d\xb9\xe0\x15\xe4B\xdc\x91{\xf4h\x87\x05\xd7\xdd\xaaW\x90k\xb9\xe0SK)\xa8\x866\x99\xe5\x84\x11\x81\xdf\x19aF\x115\x9b\xd5\xc5\x1c\x052\xe6(\x99\x19\xf0\xecR\xe4\xf1@HO\x13E\xec\xd2\xf8\x94\x17?7^\xfc\xad\xdf;^z\x15\xfbxKf\x93+2\x87\xfd\xe1\xcc\x1f\xfc\xde\x0f\xca%~p\xfcx\x97\xb5\xa4\x05\xc0\xd6\x96k\xd2\xd8\x1eO\xdd!\x1f9\xa4\xc9\x9aB\xbaQ\xd0\xca\xc8\x14\xee\xaaIo\xf1\xfe\xb6\xac\xf2<\x93N\x14[\xab\xbc\xbf;\xd3\xf7C\xafx\xde\xdbf!\xb8\xdb\x85\x9c\x14\x84\xa1'\xc4 \xa5V8H\xad\xc2\x81\xf3<\xc2\xc1\xd7\xca\x18Uj!\xb9=\xcdJ:\x9f\x98\xff\x94)2\xca\xa7}\xf9\xd8\x81\xc2r\x83\xebK\xe5\xb2T\xc2o\xe7~\xd2\xc4\x99SY.l4\xd2\xb9\x8a\xcbo\xf1~}\xa1\xbe\x99\xc3f\xeds\xf9L\x11`>\xa3nz\x9b\x8d\x832\x8dd\xbb\x05\xecN\x9e\xe4V\x83\xb9b\x08\xa5%\x95\x9aXx\x0c\x857\x13\x7f\xe4g\xfe\x98O\xac0bgX+\x92#i\xd0\x1e\x06\x82\x04\xc2\xab\x902)\xd0\xef\xff~\xc2\xfbuna2 \xa9|\xccx\x00\xe1\x0f\x1a\x07\xcbt\xab=\x10\xb4\xec\x88S\x14sJ\xc5\xccIo\xa7P\xcc\xb8\xa3\x04\xb5\xd6\xdcI\xa1~\xe5[\xa2\x91\x18\x06\x93\xff\x7f,\xf3\xb3\x80\xd7Z<_`\x7f\xd0\xd3\xcd\x9b\x19?\xc8j\xfb\x8b\x05_\x10\xbc\xa8\xb6c\x7f4h\xec7M\xdc\x05\x16\xb6O\xce\xcd5!\x95V/\xe7g\xe3\x83\x86\x8d\xdf\xf7\xbdl8\xb9\xd8Du\x96\x19\x15t\x8d\xf7E\xbfs|4\xe9\xa5=\x95\xbcL\x92\xc2\xc0\x11\xd8<\xa1F/\xca\xb2h\xb4\xc0Zb\xb0\xb5%k\xe2_\xea\\G\x04\x15=\x94\x89\x1a\xfctcq\xfbD\xbbS:\x07\x1e\x8f\x13\xeeJ\xcd\xad\xa6z\xba\xef\xcbL\x84\xae1:J\xbe\xe9\n\xa5\x8c-\xb0#G\x06]y\x06\xcb\xa7+;\x8c9\xbc\x997j2\xf9\xb8N\xca\xcd\xd9]h\\\x99 \x87\xc7\xa3\xb6\xa1\xc6\xe6\x18Bo5\x86\xc6:\xcfelb*\xc0N\x90\xdc\x05\xd6@\x9d\xf5\xaf\xe0F\x8d\xf7)\xfa\x07\\\xa6\xf1\xa12\xfd\x0b\xe5\x14\xa7xL\xbf\xc0\x85\x05v8\xb9\xb8d;\x0b\xccm^\xb4\xa6\xcc\xb1\xb0\xff\x8e\xe0\x0b_n\xfb\x87_r\xfba\x08/v\xf7\xff\xf1m\xa8\x96I\xea\x1e\x8b\xd3\xbf)\xf6T\xbd\xf8X\xbf\xa9P,\xccG=\x9eL,\xe6\x87\x19\x1fLQ\xae\x17E\x01w\xc2\x86rZ\x03\xfc2\xc86\xfe\x92vh\xa6\x91C\xc9\xa9\x13\xef\x02\xd9\x7f\xe9\xd8d\x85O\x8c\xe7\xac\xb5\x0c\x95\xb0s(\xb7d\xe70\xe6\xd4,\xa4\xd7\xa8o\xf6YZ\xa2\xb9w\xc9\x89\xa5Lm\x93\xd0\xab\x1b\x17\x9b\xaaB\x97i\xae\xa46o\xca*\x15\x95\xa3\\\x0b8Um=\xd8\xcd\xa28\x1c\xc4j\x99\x92\x88?\xa9\xa8\xa2\xf1E!q\xc4\xaaE\x8a}n*\xc5\x0fbG(\xac\xb1`\x87EA \x00hx\xd3\x14*\xf1VS.\xf0\xd3\xf2\xc2\x14\xa8Q\x8d\xa6\x87L\xa5\xbf]\xfb\x9e\x18Q\xea\x08\xdd\xfd\x8e\x0c\x90\n\xa8\xc1/\xb7Y\xd6\x84\xe6\xda\xce\xc1J\xd6\x95EN\xce\x9d\xea\xd8\x8c\x7f\xb2\xd0\xec)\xab\xfdO\xc2\xe6N\xd8\x0dm\xf9\xd7kh36\xb0\x19\xc7\xf3.D\xd1^\xbb\xd5\xe3\xfd(\xe1\xdbjy\x14\xd9M\x1b\xd3:\x9a{\xe6a\xc2\xfb0\xcc\x94g\x8bY\x96\xf8\xbd<\xe3m!\x80\xb7\xba\xf6\xdb\xbfN\xb74LlzM\xa7q\x89;\xfe\x87\xd7\x17\x8f]\xfbA:{\xec\xf4\x91\xd7~0s\xe3\xe8\xef\x1f\x1f\xa8d\xc5Ug8\xba\xda\xf5i\x98\x8a\x85\xd1\x88\"\xf0\x94\xae\xf5\xe2\xf2\xf2\xcd\xc5\x9d\x9d\xad\x05v\xbd\x05\x97\xe8\xadj\x86P\x92\xda\x82\xd5\xe6c\xc2C).\x11\xd3(O\\\x8bE\x00\xee\x19\x1a\xfc\x89\xfcBm8s\x06\xee\x0eZ\xd2w\xbc*B\x08\x95;mgE\xd6\xe6\xa4N{\xac\xbb\x94\xach\xabN\xb2\xe7E\xfbaU\xa4\xbbK\x0d\xac\x10\xbbq\x86\x85|\xbf\xb0c\xd6\x08\x8f\xc3l\x14\x88clg}\xd9a\x1c\x0d\x12'\x1e\xf2\xa4\xbeP/\xe1\xce^Z\x0f\x0f\xfcp\xcf\xef\x1f6\x17\xd8\x91\x9b\xbc\xc0Z7{\x81\x13\xeeY\xd2\xa8w\xd4EK;\xb3(\xd0\xae\xcc\x12\x96\xa3\x850w\xff\xafI\x15\x05\xf8\x9fq\x8d\x91\xe3\x8aa\x7fJ\x86\xa6\x01\x04\xb1FN \xd6\xeb\xd9Gx\xd7\x17/m.\xb0\xd6K\xa4|l\xf9\xba\x18J\xccy\xfc\xe7\xb84|\xbf\xf7!\xfd\xae@\x8f\x7fNA\x00\xf8K\nH\x83H>)\xf1\xec\xf1_P\xe0X\x02\xfe\x1b\x02\x90\xb3\xbbGvDz\xa6\xb6\x9e=z\x9f\x02d\x94\xac\xb5\xca(\x85\xf9`,\x02\x90\xe3\xc8\x16?\xb2\x03{\x12\xf8\xd8\x0e\x94\x07\xf2\xd1\x13;P\xf6\xf9\xe8\xa9\x1d\x08\xb3\xf8\x1b;P\xe2\xfc\xa3\x7fm\x07\xca\x85y\xf4?\xda\x81\x12#\x1f\xfd\x1b\nL2\xb9\x02\xbf\xb2A\xc6r\x8e\x0f\x08]\x01\x18L\xe3\xaf(0\x05\xfc\xbfGhE8HEo\x9f\xfc\x84\x02\xee8\x89\xc0\xe7g\xff\xfc?`T\x8c\x06\xd2\xee\xfa)9\xd0\x1a\x80[[\x8c\xe2>\x1c\xf5\x7fO\xaa(\xc8\xcf\xff%\x86\x88S\xf0\xec\xfe=\xf2Y\x10>\x89\x88d\xe9bID\x1fcJ\xe6\x00F\xdf\x7f@\xbe\xfbr\xc1\xee?$\x80(]`\xado\xe3Y\xc4qpxN1#+\xa9s\xe28\x89\x0ej\xc6-@\xfc\xb6u$\x8b\x89\xf4\xac\xb2l\x83\x06|\x80k\xa4.\x10\xcf\x7fI\x0e\xb1\x81\xfco\xa4N\xea\x0f\xe4\xc0\xef\xff\x8cT\x12X\xf0\x07\xe4\xeb\xe1\xa8f\x17\x04DM\xe6\x9f\xe3n2?\xf0$\x8d&L\xd1@\xfe\x07\\'\x17\x02G\xeb\x13\x82Q\xea;!!\xfbn\x14\xfa!\x1c\x14\xcc2\x9d}\x05\xf9\x08S\xf5\x9e\xe3\xee\xb9\x11\xd0\xab\xfb\xefZ\x80Z\xcf\xee\xbdG\xa0\x89\xa4\xbaO1}\xef9\xc9\x98\xcb\xb1<\xc0\xfd\x9du\x92}.1\xfb]\xcc\xbb{\x05\x08\xa3\x1a\x80\x80dS`/\xd9\x13\x80?%\xf3\xee%{\x99\x06\x92%\xab]\xeb\xb3 s\x90\xfd\x81\xcf\x98\xe7\xf6\xbc\xdby$\x97\x1dK\n=\xee:y*W\x0e\x8f\xec\xac\x04q+\xac\xd7\x08\x1b\xc5\xd9\xa1\\\xf4G\x98\x92\xf4\x04~X\x91\x83'a\x94\x8b:oc>qV\x82\x82\xc0Ok\xc0\x99\x9430\xf9\xeb\xa9\xef\xff\x0b\xfd\x0e\xa2\x0c\x1dB\xb6\xcf9\x1co\xd2\x89\x96\xb4\xc8\xbej\x00f6=\x7f\xe0\x02\x05~\x88\x05O\x01\x02\xd1\xf3\xd9/0 \x16\xb0\x1c\xaa\xe1\xc3\xdf\xf3\x07\x91\x17\xc1\xb9\xc4\xb2\x93\x80\xc5\x01l\xe4GX~\x12\xc0\xcc\x1fq\x80ZF\x93\xdeV}~D\xd0\xdd\x1f\xa4\x99#\xb9\xc5_\x90\xa9\xfb\x83,\xf1\xa5,\"\xf4&Q\xe6=rr\x8b2\xd0\xc3{\x98\xd6\xf4\xfcAnF\x8e\xa9W\xcf\x1f\xa83\xfa\xd02)s\xda\x1e\x92\xe5\xd8s\x92h_\x80\xde\xc7\xd4\xa2\x178\xee^\x10\xdd\xe1J\xb8\xfa\x10\xcb,\xb2@z;w\x12 \x7f\x0f\x0b<\x12\xae'%K`5\xa1R\xc2,\x0d\x968*\xa5\x02\xb8\xb5}\xf6\x0b\xb2;\xe5R\x89\xbaT~\xf6\x1e\x96\x02\xa4\xae- \xff\x023\x86^\xb077/\xeb\x90\x03\x12\xec\xcd\x9d\x94\x10BE\x82\xbd\x13\x00\xc1\xc2\xb2LO !\x98\xa1\xf5B\xb1\x18g\x9e\xfd\x183\xda^\xc8o\xe7\xbe$\x07\xf7\xff\xda\x02^\x07\x94~\x8a%\xc0^\x08\x80w\xb1\xbau\xd6\xc8B\xff\x07\xaebd!2nh\xeb\x01\xe9]_i\xdb@\xfb\x99\x0f\xe8E\xe6\x1a\x1d\xf4@J\xf9\xf0>\x05-\xaf \xc8\xcf\x7fa\x81\x04\x12\x82YT/:\xf0\xa0\x0eV4\x04D\xd6\xf9\x19^\x04\xd1\xda\x96\xac\x83%\x11\x01\x91\x07\xd6\xb2\x08\x07\x1e\xd4!\xa8\x10\x1dx\xb2\xce\xcf\x08O\x8f\x0e.\xc8*\x96\x01H2\xfa3r\xf6\xa2\x83\x0b\xcb\xb2\nVo\x05D\xb2\xce\x9fciD4\x06u\xe8.\x1c\x0ce\x9d\x9fa\x92,Z\xdb\x95u\xb0\xbe\" \x92\x95\xfc\x9c\xf0\xfc\xe8`\x08u\xb0\x02$ \xb2\xce\xcf\xc8i\x8e\x0eF~\x08\x04\xea\x01\xa1\xf2\xd1\x81&^\x0f\x08k\x8d\x0e\x0c\xd5}\x80\x15\xb5^t\xb0\x0b{\x8e\x95\x0d\x01\x01<\xc1\x82i/:\xc8\xa1\xce\x7fk\x81\x00\x9e`\xa5S\xb4\x06{\x8e\xb5N\x01\x01<\xf9\xa5\xa55\xa8ci-\x07<\xb1`\xddeY\x85\xd0\x92\xe8@\x9e\xfd\x9f\x11\xca\x16\x1d\\\x06\xd4\xb2\xec\xece\x89[?'\xb49:\x18C\x1dB\x95\xa3\x831\xe0#V\xb6Dk\xb0j\x844F\x07\x97a\xa5\xb1V'Z\x83:XA\x11\x10Xi\x0b\x0e_\x86U\xb3\xec\xf5eXi\x0b\xfa\x8c\xa1\x8e\x05y\xc6\xb0\xd2\x04\x0b\xeae\xe8\xb3\xca\x98\xf6k\xb2o\xf5\x80qO\xb2\xf7\x8f\xf1a=\x0bZ\x10\x95\xb7zF=\xfa\xdf \x84\x8f\x84p\xf7\xec\xad?#\x90:\xc9>Us!R}/\x8d\xc4:\xff\xe0\x07\x96\xefR\x85\xff\x90\xc8#i\x14\x0c\xd3\\\x02\x7fEHv\x1e\xc8m{\x93lu\x1e@j1\x1bH)o\x7fj\x01HM\xf9 \xb6L\x08\x08\xe8\xcax \xce\xe6F\xdf\xb35\xa7@\xb8\xd6\x92\xb6E~\x8a%3\xd7@~J\xea\x80\xfc\x88\x89\xbc\x12G\xefar\xe9:\xb16ta\xf9\xcbu\xe2^\xa2d\xc3\xc7\x98\xd5\xb9N\xac\x9a|\x8c\xf5\x7f\x01R\xb5\xf0\xe8\\'VB\xecc\xcc9\x96\x9c\xd8\xcf\x9c`\xd9\xef\xf7y\xc2\xc3\xccw\x02\xc9\x14~\x82w\xdaubPY\x1e\xff\xe7\x7f\x8f\x1bq\x9d\x04\xb6\xf3-,1\xbaN\"\x15\xd3_\xd3\x05;\x0c\xf8!h\x17X\nqu_\x8f1\x82.\xe9\xf6>\xc5<\xd35\x10Z\x87{\xbe\xd4\xc7\xc9\xb2\x18\x08\xe6YKJW\xf8\x14\xa3\xb4\xab\x01xc\x96J\xaa=V\xc0\\7W\xf3\xa1\xa3\xce\xe34\x95\xc7\xf41f\xf6K\xb0e\x9fb\xb3\x8b\xab\xbe\x93\xfdW\x93\xf9\x18\xcb\xa9K\x02\x1086\x90[R\x1b\xb1\xce\xe6J\x7f\x86\xd6\xc7\xf8\x84.\xf10\xe3\xc9\xb2\x1c\xc4\xc7\x98\x1c\xb9\x12\xe8\xd9\x81K\xfd\xc4\xbe\xdfZ\x9f\xc3D|\xe9\x02\xa8\xd6x{\xdc\xa1\xfc\xfe\x0fdC\x87\x1c$\xe5\xbf\xc4b\x98\x84\x8c\x9c\xc4\x0e]\x1a\n\x12\xfa9\xedF\xaa\xcd\xa4\x17\xb0\xe4\xfd\x82l\x00\xa0\xc6\xaf \xd5\xf0\x13W\x91\x1a,\x9f\nP\xc0\x9d$\x89\xf6\xb56\xf2\xce\xffY_\xc6\xe8\"\xef\xfc_\xd6B\x1eX\xc4\x9e=\xc0\xb2\x8a\x02k\x0d\xf8\x01\x96K\x14\xdcS\x06\x9d\x07X>Z\x92\xf0e%\xd0c\xd9E\xd5\x16L\xf5cL\x9c\x15l[T\xfcs|\x9a\xa0\xd9KF\xd2\xc3B:\xc07\xb5\xb0\x87%u\x00\xef\x18y\xcf\xb2\xba\x92c|\x88\xb5z\xd7\x07=\xd3\xb6\x1f}}\x8c?\xc2\x07\xd2\xf5\x93\x11\xd8^\x9fb\x0b\x82\xeb'\xa9B\x8b\x0f\xb1\xcc\xb5$\xd4\xb7}?\xe5KQ\x98Ey\xb2\x1af|\x908\x923\xde\xc3\x87n)\x88R\xbe\x94'\xc1\xe1r\x94\xf7\x02\xfez\x1ee w\x90-1%\x8b2dc\x82\xbc'\x97\xe6\x97X\x0c\x93\x90\xdc\xcf\xac\xc0\xa5\x08\xac\x89\xcf\xee\x91\xe3\xad \x0b\xb6\x1ap\x03\x83Ey\xd7\x80\x88\xfd\x16@\xb7k`\xa3\x91 Y]\xdbw1\xec\xff\x8a\x02\x80\xd5\x12\x16\x14\x8d\xe2>L\x07Kb\xae|\x19a\xc4\x15\xdd\xb6\xd5\x0c\xf8\x01`\xd7\xdbx_\x8d\x99\x90p\xca(\x1chv\x8bI\xddR\x14\x0e\x92\\ux\x1f\x0b\xbaK\x05\x0f!\x18V\x80\xf0\x11\xb3\xe1\x15-#\xb5t\xdb,\xb4\xfaNw N\"\xb8\xd6\"\xacI\x82r7\xb3C76\xaf\nR@d\x9e(>\xac\xfb\x9e\x02g\xc0\xe7q)\xca\x05?i%\xa2e\xa6\x90\xec!\x99M\xee9I\"W\xe7}26 \x93\xeb\xf3>^\x1f7\xe7\xb1\x84<$s\xcdy*9\xc7C\xacM\xb9y\xa0\x97\x1b\xdbv\x01$\xa7\xf5>\xd6A\x96\x94\xbd\x95\xf0i\xf8~\x0f\xab\x9an.\x84b%\xf9\x126\x92\xc7J\xfe&\xd7:nn\xe4e\xc2\x96s#/\x13\x11+\xd7\xf2\xf2\x03K\x83\x11\\\xe4\x91c\xaf\x84\xbc{O,\x02rn\x90\x92\x90T \x92\"\xe0\xfbX\x8dv\x05y\xe7\xb7\xe3\x84\xbb5\xdb\"\xe1i\xee\xd6mN\x12\x1cjc.\xd6\x80$\xb00\xe7\x12\\\xcd\x93D\x1a\xe6?\xc6J\xb7\x9b'c$\xb3\xd0\xad\xd7E\n\x91\x85N\xbc~d\xea\xba\x87\x0e\xaa|\x83F\x04V}\x83v\x0f_\xc5\xb8\x87\x81\x9b \xda\xf3\xec]L\x90\x97e\xaep\x01z\x13Sc\xaf\x00a\xc1\xd4s\x02}\xa3\x81\x0f\xd8\xb2\xdeh\xd2\xdc\"\x00~\x8aq\xde\xd35(\x00\xc4\xb171QXv\xd2!\\\xb0\xe1\xbd\xf14\xe4\x01f\xea^\xc9>\x8f\x97\xd5\xeb\x05\xd2\xd3\xe0\xd7X\xc8X6Z\x15\xde#\xcf@pc\xcb \xb3cv\xe2\xc1g,\x1e,\xdb\xb5M\xf0\xf5\xf8 >\xb3\x9e\xd7\xb0]z\x1d\x7f\x8a\x8f\xf3\xf2r\x94%\x0e\x984\xdf\xc7\x94\xd7\xf3\xa2,\x05!\xe41FQ\x8f\x0b\x0e\xff1\xd6\xe7\x969p\x1e\xac\x18,\xf3\x00\xae\xbf\xc8\xdc5\x00\xcf\xde+\xe9_\x18i\xbd\xbe\x9f\xc2\xd1\xf9\x00\xbb\xe0,k\x85 \x8f\xc0\xd3\x00\xb28\x17\xe0B\xe9\x03l\xeb\xf5\x86\x0ep\x8a\x9fb!Y@`=\xb1\xcc\xb0\xec;n\xe2g\xbe\xeb\x04\x8bun[\xa52\xa06\xfc\x1a\x0b\xa7\x95\x12B\xd6\xd5mQ,,J\x9eW\x9eT?\xac/\xb2\xa3\xae\xeb\x7f\x8d\x8dx\x9e\xefH2\xfb\x10[\\\x96}g\x14\x815\x86\xc0\xbc\xc90#Gcs\x9e\x80\xa75\x10\xb9h\xd8 N\xad0\xe4\x00\xf8\x03\x07\x04\xe3\xdf\xe0U\xf2\xfc\xd4\x97b\xeeCL\x18=y\x13\xf4 \xc1n\x7f\xec\x83c\x83\x1d\x12\x85\xc6\x94\xfe\x90 \x9a?\x8e\xc2\x03+h\xf9\"\x9ct\x8c5\xde-P\xda\xb1\x1c\xe3\x05n\x94\xc8\x81\xbf\x8b\xf9\x9b\x17\xb8\x89|b\xe0\xd9\xbb\x98\x0f{Q\x10H\x94\xfe}\xdc\xbd\xb9\xa9\xc2:\xb2gD]\xacH*c\x06\xde\x0e\xaf\x06q\xa3Li\xc2?&(\x16eJ\x9f\xc1$[B\x94Pq\x1f\xd3\xa0\xe5([\xb9\x9d\x83>8+:f\x01S\x0c\xae\x01\xd8Z\xc1\xb5\x9d\xf4\xd9}\x8c\x1f+\xb0hX\x0d\xe5\xb0fX\xca\xe1\xcbJ\xd2 \xaa\xc9\x8a\xba\x05\xc2\x83\xd5Fz\"cpU\x01\x1fR8\x9f?\xc1R\x1c\xef\xeb\x860cZ\xd1:\x066\xc3p\x0d\xc07FR\x8bz\xf6\x04o\xc5\x8a \x8b -\x19\x08fy| \x89\xf7\x132\xedA\xaa\x8e\xca\x13l\xe4\x05e\xed \x96\xe2VJ\x86_\xd2\x7f\xe0\x87\x19OdW\x7f\x86 \x13\x87K\xed\xb71\x93\xe2\x01\x0c\x0d\xef8\x0f\xcc\xd0\xf0\xda\xaf\xe8\xe8\x0b\xbc\xc6\\\x03H'B_\x94c\xc6\x04IBR\xb8\x86%@\x99ky{\xe4\x04\xc1\xb6\x91\x08\x7f\x81\xe5\xe3B\x17\xb5\xd7\xbf\xcc\x13\xdc\xc6{\xd8Y\x84\x8fRI{\xdf\xc4\x9cS\x00\xe6NH\x10V\xa3$H\xba\xbe\xbdI\xfa]?\xbf\xc0Z\x9f\x91\x83'-\xef\x9f\xe1\x0b8\x1e\xaa\xce1G^\xd1.\xfe\x0474\x80`\x87\xd1\"\xb0M\x8e\x1b-\x82\xe0`\x0cT\xf4!\xc1\x80\xd8IR\xe0\n\xd8*\xc3\xb5\xf4\xfe\x18Sx\xe5\xb4\xfb9&\xd6+\xc6\xd9\xfbs\xda\x8f\x01\xe1Z\x02$\xb6\xf67\x04p[_\n\x12\xba\xc7o\xd7\x931~[y\x97\xdc\xc7k\xcdo\xa7\x81\x13f\x83,\xb1\x1fT\x00\x07<\xb5\x9f\x16\xa3\x07=\xa6#\xcd\x1dy\xc4\xce\xd8\xaah\xad\xdf6\xa0\x9c\xc3\xb5\xe8}\xcc\x92Vn\xe7~\xe0\xf7\x12?\x97s\xf9)\x16\x18JN\x946\x08\xd8\xae\x1ec\xa5\x81\xdf\x1e\x17\x1b\x8e\xa5h\xaeY\xe0\x07d\xc3\x13Mq\xf1\xa1_\xd1nA\xd8\x10\xc55\x00\xf3m\xaeI\x0e\xd1&W\xd4\xbe=\xc6\xd7&\xbcnCW\xc0tE\xf8\x06|&|i\xe7\x82\xa0\xdb\xb8[\xb0\x96~\x82'\xb0\xa2\"%\xc8IV\xdf y\xc9\x13\xe9R\xff'\xd8A\x8a\x1f\xb8\xa2\xc2\x11\xf2\xd9\x87\xad\xbf\x87\xe9\xd1\x8a\x80\xa4V\x10?\x88\xb9\x9b9:^\x86\xac\xfa\xca\x01${\xf0\x9d@^/S\xdeY\x14\xb03\xd7\xbe\x13\x04\xbe\xbc$T\x96G\xc2d\xcf\x81\x98\x80\xa5\xe6>\x88 \x98\x82\xf6\xf9Hu\xf5K|\xf3\xd0\xef\xfb\x10\xf8\xf8\x9f\xff\x06\xcf\xb3\xdf\xd7\x10Z)\xd0 \xdc\xd59\xcd\xe4\xb1\x9c\xd6\xd7\x00L\xe2\x8a\x01`5\xe2\x9c\x1f\x04\xdc\xc3l \x13\\(ec>X\xec\xea\xdf\x82\x9e\xfa\xb70 p\xc0B\x87\xc5\xaeb\x9e\x18\xeb\xfbA\x16J\xf4x\x0f\x9f\xd3~\x18 \x06\xf0\x9f\xc8\x96\x19\x96\x81\xf5\xb3\xbea\x19\xf8\x10\x9d\x8b\x92E\x10'\xee\x91=\x88\x12\xa7\x1e$\xfdX\x1eb\xc3\x87\x00\xc0\xbd\x00\xe6g\xe7\xa2<\xf1y\x92%p\x0bL\xe6\x14;I\xa6\xfd\x1e\xb0\x10\xdaO\x1cW\xba\xb3\x7fL&& \x92\xa9\xff\x04\xd3, \x12L\xfdc\xbc\x9f\x12rJV\xc2\xc4_\x82^\x96 <\x01 zE\x82\xb0\xe0.@\xf30\n\xb2 \x02\x04}aF$@\xd2\xe1\xfec\xac(I\x08T\xc2\xfb%A0\nl\xfa\x13\xa0\x93P\x0bK\x19\x02t\n\xa6\x85e` \x82\x06\xb1=W\x80\xbe\x03 l\x13\xe8'\x0e\xb0\x97\xb7\x08%HT\xe8\xc3\xbbX\x08?\xa7y\x05\xd9{\xa3\xfbb\x81p\xa0U\xaf\xff\x07\xf3\xe2\xf3\xca\x08\xfd9\xdevm\x9d\xfe\x1c\xb3\x17Y\xc3\x13\x12\x08^\xb8\x81\x81\xe0\x15\x18\xc0\xcd\xed\x13l\x970\xa2\xc9\x13L\xd6\x00$\xf9\xfb\x13L\x8e\x15\x0c\xe6\x8a\x91~\xc0S5Yz\xf3.`0\xc8'\x988\x9c\xd7\x1c\x0b\xab\x17\x03\x0d\xc0\xec\xf7\xbcTd\x1fb\xda4\x00? ,\xac\x0c\x065\xc5\xfd\x11l\xce\xdbXx:\xaf\xaeN0\xa7\x1e\xa8\xab\x13\x82qpc\x80\x9b\x19Hg\xcfgO\xc8\x1e\x83\xbc\xf2\x04s\xaeApK~\xc7\xd3\x1d\x84\xea\x00\x92\x05\n\x8b\x98a\x0b\x10\x10\x98\xec\xc5\x9ckud]\x96U}\xaf\x82\xcf\xb4\xaf\x01X\xc6\xf0G\x0eh^\xb6\xb6\x06~\xe8$\x87\xab\xf6\xd5\x199\x83@\x9d\xe8\xb71j\x0b`\xec@\xca$\xbaw#\x99\xc5\xb4\xf5)\xd6\xd4\xfd\x91\xb4<={\x80Y\xb8?\x8a\xa5\xc3\xec\x7f\xc2\xf8\xb4:\x8a\x03\x1f\xd4\x1f\xe2`\xe2\x87l\xc1v\xf9\xe5\x87\xae2\xb0\xbd\x8d\xafc\xcc\xde\xdd\xc3\x8a\xb7\x84\xa8\xd0\xfd\x0f\xb1\xbe\xec\x87*\x87\x06\x99\xd1\xaa\xc2\x12\x82q\xea;\xd9\x8d0s\x81\xc6<\xc0B\x9c\xca\x08\x0d\xb1\x1a\x98\x81V\x9c\x97,\x8d\xf2\xa4\xae\xd9Uy\x11\xc8M\xf6$\x92X\xc4\x0f\xb3\xc0I\x86\xd2 \xf7\x11\x16\xda\xfc0\xd3A\x14\x1fa!q5\x1c\xfb\xa9/\x1d\xac\xc0fb![\xba\x88\x89qz\x0bK\xe5\xab\x1b@I\xb0m\xd5\x8f@\xf4!X\xabo\xbc0\xc1\xf35\x00\xdf%\xac\x1a\xae\x86\xf9\x92o \xd8\xac\xb5\n'\xf9s\xcc\x07\xd5 \xff\x1c\x0b\x16~\xed*\xf9Z\xca\xfe\x18\xb3\xf9U\xcd\x15\xc9\xe12\\\x11k?\xdaC\x92\xe2|\xea\x87Z\xf0&49\xf5A\xc8}HF\x9d\xfa`#~\x88\xbd_%DZb\x1fb\xca$@c\xfb 2\xfb\x0e\xeb\xfcS\x9f\xe2\xcbp\xdf@\x08\xc1\xcc\xf7\x00-\xb0\xee\xe1+\xc0?`s\xe8\xaa\xbaq\xc1\xac\xdbW\xdf1V\\\xd4\")\x9e\xfa-\x0d\xc0\xeb\xa8l\x1b\x18%\xc0\xb4\xf1\xf7xm/j\x06\x86y\xff-\x0d\xc02\xca-E6\xff_L\x1d/\x1a4\xc5\x87\xe4\x96\x81`}\xea\xa2\xc1!,\x94\xde2\x10\x8c\x90\x17S\x9e\xc0d\xf0\xce\xde\xd2\x90\x7f\xc0\xf2\xc4E\xbdQ\xd8\xa6uKo\x14\xe6\xf8\xdfw\xe2X\x9e!|\xe6\xf64\x00\x930 \x90\x97\xbfX<\xf9\xbe1\x8abo\xa5=\x03\xc1\xab\xf9}\x18/\xe9\x1d>\xe3\xbe\xbf\xafw\x0b\x0b^{\x1a\x80\x91zo\x90@B\xa8O\xb1\x90\xf5}\x15\x0d\x8cwdOE\x03cn\xf5}\x85qX8\xd9S\xd64,\x7f|\xdf`\x03\xa6\xf1{\x06B\xea\x18l\xc0\x82\xd6\x9e\x86\xfc9&\x9b\xc1\xa2\xd6\\\xf0\"\xae\x99\xfc\x02\xf88\x04\x06\x82W8pJ1\x04\xf80\x06\xce q\xe0\x16\x13\xb3\xff5g\xd4\xf3$\xbe`\xdc\x0f\x0c\x04\xabOk*k\xe6\xaf\xb0\xf8\x14h\x00\xdeM\x01\x80\xfc\x8e\x98\x11\x05\xc6\xb3\xccR \xcc\x8exC\xd7\x1c\xf9\xe2\x9a\xbe\xc4\xc23\n\x1cH\xb8\xf61f\xf0kZ\xab\xc7RK\xa0\xed\x00\x98\x85\x98\x986\x1b@\xc6\xf6\xfd\x14\x8b\x18\x12\xd2\x97\xec\xe0}|\xf9 `\n\x84e#\x01\x02\xe1\x81\xa8\xa2\x02\x14\xc8\x95x\x07\xcfH\x06\xd6I\x81\xe5}\x8a)\x89\xb6\xe7|\x80y\x8f\x80e\xb2\xda;\x98\xcb\xa8\x1b\xd2'\xa4\xa7\xc5\xcc\xf1\xa1'\x8a'\x06\x84\x89z\xe0@D\xf2\x13,\xfe\x0b\x00\x98\xa8\xfe5\xb5\x18\x05g\xd5\xb2\xbf\x8f\xa9E\xd0\xd3\x10|\x98\x03\x9d\xe4\xef\xaf\xb0n\x10\xf4\x12\xb0:\xfc\x91\x0d \xea\\\xa7\x80=9\xecGX\xd1\x16\x904\x00D\xc6\x1c\x12`2\x8f\xd1#\xcc\xac\xd6\x8c\xb7!V\xd0\x03\x03\xc1B\xca\x9a!\xbd\xf8\xf8\x05\x06\x82\xa5\xa4\xc0\xe5\xb0\x13\xefb\xd6\x13\xb82\x16\x15\xaf\xc1\x1a\x90F\xb2\xa5\xf0\x99t\xec\xb9R@}\x1f\xb3\x89\xc0\xe48\xc4\x84QB\xc0\xe2AN\x9d\x97x\xda\xe1\x143\xf1\xc0K\xf2T\x03\xc9.x`\xd2x\x87l5\x18!1 \x06\xf2r\x1f\x9fT\xe9\xf2/\x88\xcfY\x81\x07\xe01GhP%.\x80\x90\x81\xb5\xb2\x0d\x89R\x8f\x8a\x85\xc9V\xb7\xec\xedN(\x89)\x80\"\x04\xb0,g\xba\xd1\xc7\x90\x1cj\xd1\xd2\x12\xf7\x03H\xc7J\x91C\xc0\xc1\xf9\xbf\xbc\x14x\x19\xa1\x94t\xd7.\xf9\x8dc\x0b\x85.Ur\x1b\xc7\xb6\x9ej\x11\xed5\x8ei\x87(u.\x88\xa0\x8dw\xb1\xe9VLZy\xe0\xeb,\x7f\xc4\x1f\xbeT\x06\x02|\xdf!\xe7\x85\xf73\xb3|\xa0\x1ec+5\x0d\xf8 FaQ\xa4j+$\xf6\x99\x80\x14!\xadT\x8b\xa4\xb5[-\xcb\xa8iA)r>t\xa9\xf4v\xee\x0f\x8a\x1e1\x11\xb6\x05'`\x8a[\x8a\x9e!\xa1\xa4\nV,\x8c\x0d\x83\xab\xd8\x82%\x1d1\xd4l\x98p^\x84\x98\xe1\xd9\xc8FJ)\x1f\x1f\xe0S_.\xa0\x90\xe9CL\x9c\xcbe\x8c}\xf2\x01\x16\x93D)\x08\x92)\x0d\x19\x0b,P\xa8:-|\xa7\x0feJ\xa1\x1aXG(\x17\xd0\x07\x00\xeb\x04(\xda\x03\xe3.\x8d\xf4 \x82\xd0\n8\\S\xfc\x80\x0bi\xba\x19p\xc1CD\x1a}\xf3C k\xc9'\x80\x9e\xbe\xb4\xee\xbb\xba\x99#\xf2\x9e\xf1 x\x8c\xd7+(\xf9\x04`\xedM\xc1\xe4\x1a<\xc1\xb4&\xe0\xa9\x9a\xacE\xce\xe0\xa9r\\x\x82o\xd4\x03\x9e\xa6\xa5\xab;,\x81\n\xb0\xb6\x13`\x0dZ\xc0\xf8m\xe5\xf7jYc\x01\xd5`\xb25kO\xaa*\x14\xa1U\xa2\x08\x12\xb0 \xe1\x8a\xeeHrA\x94\x80\"\x95\xb8\x0d&\xcdC$\xc7x\x00k\xd9\xb6|\x06\xd7\x92GD\x18\xd0~:T\x1eOJ\x04\x92X{\x12\xa5\xc0R\x01=1\xb4\x91\xec\x00\xa4\x00z\x93X>\x12E3\x1f\x10\xca\x98:Z\xf9\xc6\xf8\xb9\xa6\xafF\x88dh\x8c\x92X\x98ZS\xaa5\xa1\x95\xb5\xdfk\xa4\x81\xc08}ac\x88\x80\x80`J8vz\xbbg\xb3\xc7\xa4z\x82\x041Rc] B\x92vb\xf8\x8c\xc8\x8b\x06\x82\xed\xbbk;\x0b\xac\xf5]\xfcQ\"\x05\xe5\x9a\x99\xa5l\xa0\x9d\xce\x08\xdd6Ng\x84\x86d\xb5\x82\xa4T\x8c\x16l:QP\xa8K\x84=e\x9a\x9d\x7f@hQ\xc9U\x8d\x98v4K&t$K\xe0:\x97hK\x81\x0e1&\x89\xf3\x83,\xd1\xeerdRy\xe2\x19\xc3\x0e9\xb3ybB\x90\xc9\nV|\xd0>\xb2H\xf3\xda\x07\xcd\x02S\xb7\xfa\x1f\xe3\xdb+\x13.\x83g0r\x80\x16\xfc%\xd6\xec\x04\x80\xc3\xe3\x1b\x04v \xc4\x89\xf71\x91\x1e\xc1\xf7w\xf0\x94\n\xfeT\x032\x96\x0dl\x1e\x03\xb0a)Xa\x03\xb0\xb2y\xe0k\x92\x91\x93\xec\x01\xc5z\x0f\xdf\xfd\x8et\xb6\xc5g\x1fa\x99\xf9\x12H\xa0\xd8\xbc7\x82\xcf\x98\xbd\x8eL\xca*l\xe5\x18\xe9H\xe6{\x98\xb1\x8f\xb8\x93\xe6 \xf7\x8a\x07\xb6\xb0\xf2q\x89{~>2Ndoa\x82{\x89\x07\x81\x1f\xeak\x01l\xf4\xbe\xa4\xd5\x01l\x88\x1bi\x00>\xe2\xa3\xa1\xdc\x9c\xb7\xc9\xea\xfb\xae\x0c?\xfb\x18K:*-\xe8=l(\x19\xf9\x9e\xfd\x8d\xa2\x91\xef)\xba\xf0\x14\x13\xd6\x91\xef\xd5\xa4\xcf-\xb2\xc0`\xb2.!\xf0\xc6\x16^\x1b \x82\xd1a \x0e@R]\xf9\x08/\x81\xcc\xc9\xaa\x13\xaf\xde\xc3\x8cq\x14\xb8\x90\xad\x10\xdb\x8fG\x01\xb3\xb4g\x1e\x1a\xa3\xb0\x0c\x1e9\xf8%\xa6M\x12\x02f\x85:\x18\xf8\xfc`\x1f\xbb\xb0'\x9d\x8c?\xc6\xd4:,R\xcc\xd3\xb1\x97r\xc9S\xa0\xce$\x89\x97}]\xdf\xe5|\x86\xb7*4\x10lz_\xd7w9\x9fa\xae\x11\x1a\x08\x96:C\x93r\x96\xf6S\xce9k\x19\xb9Jt\x89Q|\x1d\xc88\xd6\x14B\xf8\x8c\x15\xca\xd0Pw|\xbaT\x82_\xb2\xd4\\{F\xbd\x8fYU\xc8\xf5\xdd+V*D% y\xc7\nQ\xaa\x02\x85\x99\x88g2\xfdu>p2\x7f\xcc\x11\x1fy\x13KW\xba\xdc\xce\xd0w\xf7\xa6*\x16N.u\x99'\x87\xcd%Ko\xf5`KS\xc8S\xaer\"a[AX\x04l[&\x9cf\xdc\xa3A%$\x82\x02\n\x96-\x7fD\xde]\xe7\xfb\xca1\xf9\x07!\x19\x82 \xaf&\xf4\x86\x17\xf1\xd5\x18\xb6\xae\xf9.6\xb8\x85\x1a\x80\x87\x19\xea\x988\x8a\xd9*,\x0e;\x16\x86:\xce\xcd\x06\xb8]\xdfX9\xd6\xcd\x06O\xeb@:4\xccRI\xef\x13\x96\x1aB\x1d\xd6b!\xc9\x03\x00a\xb95\xd4\xc6[\x028\x9f\x01\x06=\xa5\x030\xd1\x0eX\xb7\x0cM\xb8\x03!\xacCexx\x8a\xd5\xbbPj\x0b\xf7\x08\x0e\xc3Cq\x0f1\xf3\x0b}\x10>\x1eb\xa9/\x04\x8c'\x0d\xad+\x93'V\x11Be\xf2\xc4\xea^h|8\xb0\xba\x19\x1a'\x0eZGI)XD\x0e\xf5E2]Du\x97\x8c\xa5\xb5\xb0z\x13L\xc7P\xb9\n&\x03\xb1\xdc \x92M\xb2\\!\x92\xed\xd278dx\xc5\x15\x8emJ\xe5[\x1c\x1b\x19jM\xdbr\x0e@\x1b\xa3\xddh\xb5\xf5!&W\xa1\xd1[\x1fbkZ\xb8\xa6\xce\xc8\x13:8-\xc1c6\xb5\x1e\x9dM\xb8#Y\xd8[\x98\xbb\xadG\xa1\x04\xfa\xe1@\x13w\"l\xac\xebX\x11\"\x9d\x18\x01\x16K\xec\xfam62|\xd0\n\xf0\xe7\xf5(\xab&\x95\xc7\x86\xc9_\x01.\x06\x81)\x7fQ\x06\xc5b\xda\x86b\xe3\x9d\x0d\xe5\x0c\xf7\xc4V\x9e\xa2\x08\x0e\xcclh\xadX&\xcc2\xd6\xa3\x8c\x86\xe2\xd8ZB\xf18\x14\xe1\xa3L\xb9B\x13I\\@\x8c/\xb4\xbd\xa2r\x87\xb6\x03\xc7N}\xbb\xf0\x10\xf4C\xac\xd9\x02\x0cr\x98c\xe3\xd5z\x94aO\x00r\xe8Q\x19\xe3\x0c`[\x19\xabG\x00\xa1\x15\xb2`\x0d\x8dS\xb0by1\xd5U\x05\xca\xc8c\x1dHY\xea\xb2\x0f\x95^\xac\xd6\x95+p\x06\x93\xd7\xf5(\xab\x93\x07\x9f\xfc+[sT(|\xf2\xd7\xb6\xadV\xa2\x00\xf6\xc8\x93\x10\x85\x04v\x18 \x01\xd6\xa9\x01\x06H\x805\x8f\xf5(\xdbL\xb8\xcb=\xf5\xd2\x0b\xb6\xf3\x95\xe0f\xad\x9e\xfc\x1b\xdb\xe4t\xb1\xea\xba>\xb4P\xac->\xe6I\xca\xcbD\x0fOG\x94\x92\x195\xcb\xc8IdlTHc\xa7EOA%\x8b\xe1Y\xa86\xe4\xc1\xd9\xce{*\xe7\xdb\x03+\xb6\x97K\x15\xcdYX\x84.\x18\x8b9C\x83\xd6\x01V\xcb\x15Mb\xd3\x97(Z\x8c\xedO(k7\x05\n\xb7\x1c\xa2#\x8b\"\xae\xcb\xb9\x07\xbb\x8e\x0d\xfa%x\xb1\xeb\xd4XQ*\x86v\x1d\x1b\x1aK%\x8b\xf3\xf4\x1f\xed\x0d\x96\x16\xea\xc75\xb3Ck\xf4\xc0\xc23\x8bn,\x93\x93\xc0\x82\xccXx\xa2,Qeg\xc4Z\xa4J\x15=Y\x86\x81\x99?\xd1\xd6\xe3\x1a\xa9@\x00\x9c P \xf1mPH\xcd\xf1\xf4o\xe9+\xb4\xa1\x8e\x80\xbbG\xa5\x810\x8e\x02\x1d\\\x88M\xc9!?}\xc7Z &Id\xcc4\x8f\x1b\x88\xb2\x02\xabI\xd6T\xd6\x93\xb4\xf4\x9b\xa9|;D\xc8\xd7qx\x9f\x10\x8b\x96\x81\x10;T\xa6\xbc\xd1h/\xe8yr\xaa\xe2\x96K\xc0d\xa8\xaeK\x9e/\xa7\x07\xbfRD\xb5C\x04\x0dy\xa5A\xec\xc3\xf2+1\x0f\xcb,\x9a\xbfG\xbfrH\xda\xf86\xbe\x13\x0es\x9d-\x96\xd8\xb3\xc7\xfa='\xcb.^^\xd6\xcf\x14\x12+\xd8e\xf3\x82!\xb1\x18\x8cM-B\xe6\xc6\xa6\x16Y\xc6\xb1N\xbbe\x19\xc7\x18\xf2\xcf\xd8 \x17t\xb8\n9\xbc\xe3\"\xfe\x1d\xdf\\\x85cm\xcbz\x1f\xdb\xe9\xc3\xb1\x8ee\xb0\xf5\x06. v\x88\xb9\xc4\xb7\x815\x0b{\x9f\xd0\xdd\xb1\xe1\n\x0f\xfe\x9d\xad\xa6~[\xf8?X\x80\xfb\xc6\xe8Oh\xda\xbe\xe6\x99\x04\x15\xf65\xcf\xb4B\x14W\xa3\xb0P\x9b\xc7\xf1\xd5\xe1\x86I\x11\x81\xef*\"\x03\xc1W\x81Q\xdd\xf3\x99\x91\xba\xac%\xeffn\xe8\xf4\x11XF\x894\x00kc*\\\x1b\xef=Dk\xff=\xd6\x89\xa2\xda\x1797\xf4\x9bM\x9f\xe1k\xed\xc8@05\x8a\xe0!\x98g\x1fa\x9a\x13\xe9\xd7\xce\xb0\x93V\xe4\xa5\x91\n{\xc2\x96\xdd\x8d\x15H\xbd\xf0\x19\xde\xff\x88+\x00Y\xf8\xbeZ\xc6G\xd8\x95iC\x1b\xfeI[\x1a\x80\x0f\xa6\nV\xff5\xde\xa9\x0d\x93\xc4\x824e \xd8\xa4\x1d\x81\xb1\xfdC\xcc\xba\"\x9d\xa8\xe7\x116\xc3DC\x81\xfd\x9fc9&\xaa{\xa112\xa6hl\x06\x8f\x02\xbd&d\xeb\x03\xf3(\xe1#\xec\xb4\x13\xe9\xc4\x12o\xd2Z0\x17,\xcbn(O\x98\xcf\xb0\n\x1bi\x006]o\x8c\xf8\xc0\xb1\xceR\x01~\x83\x19\xe8\x86\xf4\x8f\x90\xe9\xa7\xb1M3*@x\xef#%R=\xc2\x86\x9fhT\xfb.\xec\x861\x9e\xe2+\xd2\xc8@\xb0\n`\\)\xb1\xf1i#\xe6\xa1\xf5\xc5U|\xbdo\n\x16E\xb0_Z\x14sx\xf0\xf0\x11\x96\x11\x8c\xef%y\xc5vC\x0e\xeb1\xa1 N\xe2k\xbf\xc8(\x17\x04)\xc0\xb3\xf01\xa6\x14Q\xe2\x81\xb5\xe7mL\x8b$\x04R\x8a\xd8`2\x13\x17\x16>\xa2\xc4\x13\xb8\xff1A\xe4\xc4\x1f\xa8\xec$d#\x13\xf5b\"\xde\xc6(I\x83\x08D\xb9\xc7\xf8>7J$\xa9zLH\xb1\xfd%\xe1\x0d\xa3\\\x90\x01k\xc7\x0fB\x89u\x8a\xa4O\xc8.\x1a\x08!\x94\xeau\x8f\x07\xb8\xca\x86\x11\xf4\xf0\xf6F\x06\x82\xa9\xc8F\xe1s\x8bq\xb2p\xc7%\x8f\x1a\x03\xc8\x81zx\xa97T\xb6\x06\xb2\xd2\xea;\xd9\x9a\xb1\"q\xefbanc\xccu|\x11!2\x12\xa6\x82k\x9f\xfd\x19fe\x1a\xaa\xc2 \xff\x94\xac\xfb\x98'\x9bN\xc2\xc3l\xc8S\xb86\xfc3|\xd4\xb42\x85M\x06B\xd7\x13\xd8\x87\xe7Q\xd1\x01-\x95\x94\xb8\xf2\x14s\xfc\x92}\x82B\x94m\x02\x016\x9d\xc4<\xcfF\x81\xc0\xc61\xf9\x8b\xe13&}1O\\\xc91\xfe\x19\x05\xf82\x1f\xca\x0c\x05\x8c \xd6\xf3Mlt\xd6\x94\xe7\x01\x99>O2\x1eJ\x81\xecM\xac\x85lj\xfe\x8ayu\xac\x01XX\xde\x84\xa7\xd2\xb1\x96\x1b\xc3S\xe9\x98\x1c\xc7Cxu\x00\x1f\x8ax\xa8^q\xa6\xfeX\xf1P=\x17\xfd\x17\xf8&tS\xf6\x8c\xe9z,;\xc6\xfc.\xf63wX\x9b';\x86Q\xe1S\x12\x07N\x08\xef\xc7\x93\xa4i\x00\x82\x84jx\\\x02\x06i\xb7-\xd5$\xd1?j\xf9\xec(\xc6\xff\x11\x16\x92\x05\x104\x7f|\xb2\x04D\xd7\xc2\xa6\x04\x01\xf3\xa4\x9aE\xde\x81\x93 p\xf3#\xb8\x11\xe4\xe0\xd3\xfa\x18\x0bE\x9bA\x9e\xea\x87\xd9?\xc6h#\xaa\x8d\xc2:\x88:l\x1f\x11\x1c \xf24\xdb\x97c\xfc\x08\x8b\xeb\xf1\xc8\xd6\xdaf\x04\xc9\xa8\xc4\n\xcba\x92\xcc\x83\xb1\x90\xb9\xb4\xa1\x10c\xd9\xa6\xbe|\xc5bml\xa4\x04l\xbf\x8a\xa3\\>\xf6\xf81\xde\x95M\xb9\xecO0\xd3\x05S\xe4}\xcc\x0d\xe3DE\x18a\xc2nL\x94\xf7\xb1<\x1d\xc3[\xf5O\xc8y\xd0\x96K\xfa\xdd\xad\xe9\x9b\xbb\xa50&:\x02\xee\xaaw\x83\xad\xe3(\xdf\xb3\x90\xb6-\x97,5%\xaa\x96\xf6\xda^\n\xab4f2e\xe3\xab\x05T\x8e\xd4\xc2\xb2\x96\x84+;\xce\x13\xccu%P\x87Ya\xe9J\x00\xb5\xc5\x10\x0fh3Q\x16\xc37\xe9\x16i\x08>E\x12\x92\xdaq0\xd1Qht\xf8p\xc1j\x19z\xc3\xc0\xd5S\xed\x98\x02m\x96\x1ej'\xd4)\x89\xfaN\xa0\x04\x00\xac\xb3\x08\xa0V3\xde\xc5\xca\x94\x00\xa698\\\xbfKx\x87z\x7f\xed\x1e\x96D7\x93(\x8e\x12\x9dI\xed\x1e\xc6\xcc\x02\xac\x12\xb5\xe1\xfa\xa2a\xf0\x9b\xb7\x80\xea\xb6-N\xf2\x04\x04\x83\x07\x98en\x1a\xa1\x11\xdb\xc6bc\x91\xc6\x86\xc9Mx\x95\x87\xac\xbf\xfc\xfc\x1b,\x96\xc6y\xe8*\x13\x17\x06\xbd\xae9,&\xd7\xb75\x00\xef\xc8\xed\xbal\x8b\xafk:\x87\xcd\x13\xb7\x0d\x9d\xc3\xec\xe2\xb6\xc1\xd9\xb7\xb0\x80\xf9\xbaY\x15\xact\xdf6\xab\x82\xf9\xfc\xed\xdc\xc9x\x12\xfa*3\x01\xc9\x8c*\xe0z\xf4\x98\xeb\xea\xd8\x94\xd7l\xdf\x15\x91\xc2\x02\xd5\xeb\xbb\x1b;\x0b\xec\xdb\xado\xe3*Qf\xf9\x9c\x98\x84KX\x9b\xd0B\xec\xbd\xbf\xfd;\xcc{\xb6\x8c/5\xde\xa0\xc4@0\xc3I\x1c\x0f\x12\x90\xde\xc3;\x91\x94\xb34a\xfa\xb1\xa5c;1\x1a&\x1a\x80u\xf0\xc4\xa4U\xc2'S@\xe4\x94\x1ea^\x9f\x14 \x97hs*s\x12fo[Z\xd9\xc4R\x97\xb9\xfc\xa2\xfd\xab\x1a6\x00\x10\xbc\x0f0]KLR%:\xe6\"\xa9\x12\x19Bq\x97f\x81\xa8JX\x84J\x8atKXQL\x8atK\x18\xf1\x13\x93n\xe9\x03L\x0f\x92R\xba%\xac\xe9l\x99tK\xefc\xa4O\x8aLLX\xd2(]\x03\x92E7 \x97\xb0\xc2\x94\x14\xb9\x98(\xeae>\x10M\xac5IH\xa8\xfd\xe7q\xbd-\x93\x8d [\x18\x13\x03\xc1\x1c%1y\x9a0\x05HL\x9e&\xb2[:O\xd3]\x1b@\xd4\xb9A\x01*O\x13\xa6\x84I)O\x13\x16\xd3\x93R\x9e&<\xa3-\xe3\xa7\x8f\x15\xfb\xc4@0\x03\xdf2~\xfads\x0d\x04\xd3\xd6\xc4\xe4i\xc2\xc6\xb3\x04\xf24\xe15\xd8\x02\xcd\x91\xe0>8\xc3b\xad'\xd1y\x9a0kM\xbc\xc0\xa4\\\"\x87\xdf\xe4p\"\xf8V\xe4p\xa2 \x15\x17Jh\x19\xc8\xe9\x04?9\xf0t+@g\xc9%\xd4\x99;\x81\xc9\x92k\xab\x08\x88K\xc6\xc6A\xdey\x0f\xeb\xae[+\xe7\x05\x91\xc3|5\x81W\xfe\xf1g\x8b\xff\x0fvV\xd6E\xd03r5\xc5vcT\x90<\xb7\x9a\x14\x890\xb0=\")\x12a\x90\xe6U\x0eh\xb2BZ\x90 \xdd\xe8\xc4\x16\xf8\x16\xdb\x84'\x93\x17\x7f\x13\x9d\xd8\xe2\xa7\x04\xe7\x8a\xc4\x16\x98ln\xc98\xba\xcf\xb1\x8e\x95\xc8\xcf\xbf\xa1]DR+'\x8cX\xc6\x88\xe3|]\x18\x8bQ$9\xe6>\xc8}\x820\xa7\xaa\xf7\x84\xb5v%g\x17fTE\x89J\xd4\xfbO\xf1\xfd_\xd1\x91I\xda\x85\xe9\xbfl\xaa\x9c\xb5\x0b\x93\nY\x80\xa6\xed\xc2*\xb5*\x86\xf3v\xe1\xd3b\x8a\x95\x12wa\xb3\x16*\xa3\xf3\x0ea\xf1G\x16;W\x8b\xa7\xe5\x04V:\xc2\x95\"Z\xa9\x10\xf8\x06P\x8c\x13EP\xf6.\xeb:\x97\xf2\x80A)\xc2.D)\x9c{\x8bPf\x9ff\xd4\xb2.\xa2N\x97\x85em\x0d,\xb0\x13[F,\xcfr\x13Z(\x8a\xa0\x8cYx:\xc4\x17\xf1\x01\xa1\xceVG\xc4\xa6B\x85\xf7\x1a\x96\xdad1\x925\x0bK\x04\xaaTur\x98R\xa9B\xa5\xa4WX\x8b\xab\x94\xd0\xf8\x87\x05s\x94\xd3\x8c N \xae\x9b\xc0\xbak\x02\x87\xee\xd7D\x88\xf2\xd3\xea\x83\x8d\xa4\xa2I\xa6CP1\xd0\xe9 \x08\xfa\x05\x90\xf3\x81HQEf\x1bL\x0c\x93jf\x1b\x02\xd6\x81\x0cO \x933 d0WLL\x02\x19\xbc\xe8\x89I \x83iKbn\xd3\xb0&\xb8\xa5uQ\xc2\x95\x8d.J\x04\xde\"/ \x1duqGB\xf0/\xcaC\xaf\x94\xe0\xfe\x03\xac\xde'0\xc6\x8e\xe53\xdc\xf8>\"\x9a]\\r;$<\xc2d\x03!\x04\x19\x85\xf0\x90\xb3[d\xea\xc0\x06\xb5-};E\xebh]\x1b\xfb\xc6l)\xc9\x8b\xec}\xedw\x99\\\x83\x08\xd1&\xb9\x06\x16l\x93\"\xb9\x06\x01\x15\xa9)\x082\x17t \xc7ni\xdf\xc3\xf7\xb0\xa5\xab\xe4db\x81H\xc2zE:\xe2\xc5\x93\xf7d\xbc\xb5\xe8:\xf2a0\xefR\x88\xdc\xc9'd'G*\xaf<65\x08\x00\x84\xaa\xfd\x0d\xcd\x02\xb5\xbdqn\x07\xce*\xa9\x16\xf538\xadX\x9c\x01G\x9f\xe3\xf4\xab$\xe3\x1fb!_\x00\xd4E\x1aa!F\xf0\xc5rQj d\xc9bG]\xc1\xfe\x92\xa0\x99\x04\xe9w\xfd,\xd0\xc4z\xf0\xd3\xdbJ\x96x@\x98\x9f\x80\x80\xaf\xd1\x9f\xd3\xb5Ko\xab\xdc!\x0f\xb0\xb0,!P\xefg\x965\xbf\xad\xfcg\x88\xd4t[\x076`\xb5\xa7\x08\x94x@(\xce\xedR\xf8\x82\xb5^\xe1\xd7o\xab\x0b3 \xb4\xd4D_<\xc04P\x82L \\\x0dPuH\xebJK\xd9{\x98\xd5\x97^\xae'R@=\x08j\xe1g\xa8\xc8.\xd2p\xc0\x86\x02\x85R\x8f\x17\xcb\x16\x06\xd8X\xa4h\x8a\xb0\x11Yn7\xd4#\xa6\xf8\x93;p\x83L\x1e\xf2Oo\xe75\x80\xda\xeb\xa5msk\x89u\xc8\xd4hR\x98#\xa7\x0d\x02I\x03mJ35\xee\x87\x98jogp\xfa\x08 U\x80\xbf\xb0\x01d[\x7fAD\xc6,q\x04\x9f\xe6q\xea\x07r \x7f\x83\x95$]D9_as\\\x9a%\xd2\xeeE\xb2\xdfm\xc3\x01|H\xf0Z\x1dL\xc2r\xf3\x9e~\xb3\x9b\xa8\x0e&\x16\x89\x02\xe0d\x91\x19\xe7=\x9d\xaa\xe7)\xe1\xbayo\x94\x83\x07\xf3S\"[\xe7=\x90\xfa\x9fb\xbb\xa2\x80@_\x84\xc0\xe6=\xcdE\x9f`\xb2\x9c\xe6=\xc3E\xb1^Z\x1c#\xdb\x1a\x990*+H\x11\x05\xcb\xb4\xcb\x11T\xd6\x0e\x8b\xb3d\xaf\xad\x12\n\xdb\xa6 \xd0\xdbu\xeb\xa3\xfd\x1f\xb1-A\x80`\xd3\x9f\x12\xec\x11 \xc8\xf2F8\x86\n\xf6\xa2\xfaj\xee\x96]\x8f\xb0\xd6*\xc0e\xd7#\x8cL\xe5`_\xd2\xb6%\xd2\xb7\xa6\x04r=\xaa\xeb\xa5\x14\xe1k\x19\xa7\x0eY\xb3\x80\xca\xaeGD5\x15p\xedzD\xd4S\x01\xacUPs\xb7^\x0b\xcd\xdd\xe1\xce\xd0\xb1_Bm\xc3e\xd2=\xc2\xf7j\xbf\x83!\xf0\x97\x98\xb8n\xc3v?\xa4\x15\x80}\xd2\xd3\x1a\xcf \xf2\x82OO\x9a\xc7\xf3\xe2;\x91M\xf3\xf8\x84\xf8N\x84\xc7<\xd6\xe4\x05[ \x05H#(\x11XM\x84 \x05\x009\xa0\xd8\x1e\x1b\xd2\x83\x05\xb8j@w\x0d\xb08\xa0\x96\xa6\x87\xca7\xfcWXQ\x9405 |!\x9c\xe6\xb1I\xdbJOSl\xa8!\xa55\xb1\xa2\x86Dp\xcdcE\x0d)\x1d\x8855|J\xc45#\xed\xd8\xb6\xbfn]*b\x90eI\xca\xe1\x94V\xa8\xa6h\x96\xa1\x96)\x9ae\x8e\x9a\xa2\x11\x9e\x9e\xc7z\xad\x89\xc0!@@\xd1\x08\xbb/b\xd6\x88\x19\xc6\xc4\xacachjb\xd6\xac\x90\x9a\xbc\xd7\xe9~\xa8\x8d'D\xba\xb9\x03\x91S\x9f`=q\xc7\x113\xfaA\x86>gN2\x80\x9dy\x17Oh\xc7\x91!\x9aX\xaf\xc8\xe4\xe7\xdf`\xe4\xcf\x94\x9d\x9f\xf8\xea\xef\x18k\"i\xc9@\xb0\xa6\xb1cl\x80\xd8\xfe\x92\x19\x08\x96\xa9\x94zF+H\xdd\x0c#\xbf\xce\x9c\xfcclw\xcdx\xa0\xbcb\xdf\xc5\xeclG\xdb\x8b\xf0 \xcc4\x00\xdb\xcd\xb3!O\xf8I\xd1\xd8=\xb2,\x02\xd4\x8f@b'\xd0\xac\x11\xba3\xe4\xf0\x06*\xa6g\x99\x06`\xb6)\x01\xe9\xa1\xc0\xf7\xdf\xe0\xc3)ac;\xc4w\xf7J\x197\xf1A\x91\xf0:cJ5\x03\xe2[\xbf\xa2/\xf5gC?T\x9e\x8d\x98\xdeU\xb3\x1dbh6\xdcS\xb1\xbdtD\xf5\xe3\xb9\xb0\xb1\xb5.N\x066\xc7d\xc3(\x11X\xf8 \xe6\x1c\x86\xbb\x93\xb6t<\xce\xaf\xb1%\x1a\xa5\xdb\xc0\xc4\xce\x92k\x03\x8bq(\xd1\x06\x99\xa0\xba!\xf9\x84\xe0\xa0\x00\x80\xec\x8d\x15z\x00\x01\xc1\xf8\x88\xa0\xa8\x00\xc2\xbb\xb9XP\xc9\xea\x1e\xe0\xce\"\x0e>B\xd8n\x99\x81\xd7\xee\x03r\xd2\xa3\xb8\x07\xe7\xed],\xd0dQ\xac\xd3\x18\xe3\xa1\xed\x18\xdb\x06\xa6\xed\x99\x81`\xca! *d\xe3)6\x1bdQ\n\xc3\xc6rSVx_\x93\xa3\xb6\xb5\xb8,\x99\xe4\xdb\x84\xb0$\x0e\xec\x91\x05R\\\x9f\xbf\x87\x15.\x0d\xd4\xde\x0b\xefaA\x0d\xc7\xee\x93\xac\xea4t\x9f\xa4W\xd7E@F\xc6HJ\xe2\xfa\xc9\xa5\x9a%\xac\x9f\\\xafe\x89zU\xe5\xd9/\xb0IL_\xc9\xd9z6\xb6\xc1\x8f\xb0\xdc\xbb\x93\xf8q\xc0\x97\xeb\xe8\xb2\x80\xaa\x9a\x96\xe1\x02\xea\x7f\x88]\x06\xb3\xc4\xcf\xd4\xd6~\x84e\xa3,\x89\xf9\x1d\xe5F\xf5gx\x0fw\x8c-\x00k\xbe\x99\xb1\x05\x10\xa2\xa5nz0\xfb\xcf\xd4U\x0f\x96_v\xb4\xf9\x9f\xa0\xb7\xb6\xff\xe3E\xd81\xcf\x0f\xd0>4\x04_\xc0d\xfb>\\\x8c\xdc'\xdb\xb4\x1f\x0d\xb9\xe3U\xf3K\x12\xea\x08\x85\x90w\x13&1\xbb& \x1e\x1f\xba\xdc@\xf0~\xefj\xd1\x07\x8b*\xb9\x96\x960?\xcau\x0d\x0c\x10M\xe9\x00\xfb\x0f\xf0\xb6\xec\xf6\xd4\x93\xca\xf8\xa67W\x80\x7f\xc0s\xde\xed%\\\xc6y\x7f\x86\x97,7\x10L\x13wu\xb4>\xde\xb3\\\x030\xfe\xed\xc2\xa8\xb0\x1c\x93\xc3\x98\xf0\xa9\xcf=\xed:\x809\xc6\xae \xd6\xc7\x04<7\x10LZs\xe3\xca\x89M]y\xe1?\x88\xf9\xe1\xae\x16s\xb0\xd8\x91k\x00V\xd7vM\xc0<\x16as\x03\xc1\x879\xd7\x9e\x85da\x86N\x02\xeen\x98d\xe6& -\x1ern\xde\xc5\xc2\xdaJ.\xdf\xa7\x12\xa0w1\x95\xca\xcbOWY\x80*6\xe5]l\x1e\xcd\xcdC\x18X\xfc\xda\xd5\x11\xf2X\\\xcf5\x00\xbb\xedC\xb0\xed\xc7\x98\xc1\xee\x86\x9e\x8e\xa9\xc5\xef\xe5\x00\xc8\x84\xd4\xe2Ce\xc0:\xa6\x16\xd3sY\x00\x07\xd5\xe2{(c\x8a}\x88\xf1SBt\xb6\xff\x07\xf8\xa8\xed\xaad\x0b\x9fa\x0c\xc95\x00k\xf4\xbb\x86\xc5c\xcd-7\x10L\x04\x9b.\x1cw\xe3\xc2\xb9\x86\xd0\x95\x02f\xa9Wv\xda|\x1f\xdb\x8c\x15\xb8r'KOh\\\xbd\xb3\xc5\x8a\xc5n,\xa4\x81b|\x18\x9eW\xe1\x96\xfa\xd8+\x98\x9c\xeaX91\x9aw?\xc8\x19\xd2%\x8a\xa7\xa4\xc8a\x8ak\xb77\x8e\xf1[MX\x9b\x94E\xd0\xad1\x96awU\x08\x14^\xe4\\}\xc7\xeb*\xbe\x0fm\x15v\x8d\xc1\xfbs, \xe6\x85-\x9cn\x93v\xbf\xc4\x95$\xa4\x187mSa\x10x\x7fb\x99=O\x0c\xa9\xc1\xe7)/?\x02e\x01jRC\x16\\9\x19~F6Z\x03\xb0\xd8\x92k\x0f\xaa_`\x82\xbbkD\x1d\xc2?\x8c\xa8\x83U\xb7\xdc\xbc<\x84\xeb\xecj\xdd\xe83L\xbbr\x03\xc1\xf2w\xae\x9d\xbb0M\xca\x8d\x0b\x17\x96ps-\x0b\x90\xd5\xdeUy\n\x08\xe1V\xdf\xb1.\x97\xef\x1ba\xfd\x11\x96\x9d\xc6N8\x80;\xc8G\xb8\xb9\xb1\x934\\\xab\x8c\x9dD(\xce\xd2c\x01\xaf\xd0\xd8I\xc2H\xe8\xbe\xf0\x9a\x06\xc6\xc2\xb1\x93\xd4\\\xc6\x08\x88o\x0b:\x17\x80\xfa\xb8\xc6\xb1\x16\xa7,\xed%Vz\"\x00\xe0`\x8f\xe5\x86\xb1\x93\x18O\x0clR\x11\xb0\xea\x1d\x03\xbd\xd2-\x97Q7\x0d5\x85*\xa6\xbd\xe62\xca\xc0g-\xa4-\"\xc4\xb6!`H\xd3\"\xaf\x03\x97\xca\x18\xaaH\xfc\xa1/+\xcd\xfa)f\xe1c\xc53\x9e\xe2\x83 \x002\x8a\xef)>\x08\x97A$\xc4\xe4l\x0c\x9f\xf1\xf0\x8a$f\xb8\xeb\"\x87\x19\xee\xa1HaFFe\xea`]H\xb6&%\xaf\xa7\x98\xe3^V\x9e\x9c\xf8\xa6m\x0c\xdfI\xea\x991\xe7j\xb9\x1e`qx\xcc\xb9\xd2W\xb1\n1\xe6A\xe0\xc3\xbd\x02&w\x97y\xa2\xda{\x93\x1c\n\x0d\xfa\x11\xad\x93\xd5\xd5\xc8j\xca\x97\x13\x9bb\xb9T\xc3\xd5\x13\x17u\xd5\xb7y\xec$\x8e\xf2+\xff+,B\xebR\x85\xe5\x07#3}\x04\x04\x13\xe5\xcbZ\x0c\xc7\xc2\xf6X\x030\xee\x8e\xb5\xc4JQ\xdf\xe4\x8e\xb4dz\x1c\x9b\x9c\x8b\x96\x0c\x89\x97\x8dx\x86\x95\xf1\xb1\x81\x10:[\x1b\xef=6o\x17\x92sg\xd8\x16!R\x86ma\xc5z\\\xba\x01\xb6\x90\x8b\xd2-\xb0\x15j\xeeKj\xa0\xbc\x8eZ].\x0e\x17\xd6\x00\xc6w\xfc\xc1\x1dG\xb2\x82G\x18\xf1\xafh\xbfV\xcc\xfd\xf65\x00\xf3\x9d}\xee\xa9\xf3\xf0\x18+\x00W\xb8\x07Q\xbd\x0f\xf1\xe8\xf65\xe4\x1e\xde\x17 \x81C\x89qj\x9f\xfb*[\xcc\xdb\x18\x97\xafht\xc3\xf3\xd9\xd7\x00<\x9f+\x063\xb0\xa0\xb3o \x98\x94\xec\xdb;\xdfO\xac\xa7g?\xe1N6\xb4\x82\xae\x18D\xc2\x87`\xdf \x12\xd6A\x0e\x94'\xd4C\xcc\x04\x0f\xd4\xce<\xfb\x05\x16\xc0\x0e\x94\x13\x14\xd1\x9c\x0e<-\xfe\xe0k\xe67\xf4za\x9b\xc2\x81\x06\xe0\xfd?\xd0\x0f\xb5\x90\xb7o\x0f\xb4\x8eL\x9e\xbb}Cf#\xc06\x90\x03\xf9\x15\xab\x00\x07:\xbd$y\xcb\xf7@\xdfA\x927|\x0f\xd4\xf3d\xe4!\xdd\x03\xfd\xe2\x0bf\x05\x07:\x99\xe0Gx\xaf\xde0\xe8\x80\x95\xef\x03\x03\xc1,\xef\xa0\x88\x0d\xc1l\xea 2\xd6A\xb2\x91:<\x9d\xbc\xdc{\xa0}>\xc8\x83\xbdo\x18L\xc2\xc4\xea\xc0`\x12&\x8a\x07\xc6;\xee#l\x1f<0\n\xd7G\xf8\xb6\xed\xc0\x88\xcc\xa4\xa7q\x0dK>\xd8\xaf%\x00W\x8d\x8d\x0e\x93\xdfC\x03\xc1\xb8yu\x11\x84\x12\x8c\xe6\x87\x0e\xd8\xaf\xf0\xfe\\\xd5$\x0b/\xda\xa1\x06`\xbc\xbc\n\x1d`\xd9\xe6\x10\xda\xc7\xa4\xfd\x90\xcbdBX5\xbb\xaaO\n\x96\xdf\x0f5\x00\x8f\xe7\xea*\xf4\x8b\xef\xa2\x0f}\xe8\x18+\xadW\x0d\xe2a?\x9fC\x03\xc1D\xff\xaaA\x14L \x0f\x0d\xa2`JxU\xd9\x0b\xb1\x08t\xa8\x0c\x86\xa4<\xe8;\x9f\xe1\x83z\xa8\xf4 l\x00\xb8fBQ0\xc2\xdf1\x10LT\xae\x99\x1b\\\x8c\x1ew\x0c\x04\x93\x90k0\x0d\xbc\x8cw\xe03F\x82k\xea\xe5vL\"\xee\xa8\xef\x98\xa6\xdc\xe1\\?\xe2\x89\x19\xc65\x9eDW|/\x1b\xd6?\xa3vM]\x9fb\xc9\xf0\x8e\xfa\x8eq\xe5\x9a\n\x9b\xc6]\xdd\xd1\xc8E\xa6\xa3,\xfe\xa4\x030\xf8\xff=\xee\xe0\x8e?0!c\xf8l^\xd3ar\xf8\xb6\xed\x8e\xc1;|v\xae\x19\xbc\xc3D\xfa\x8e\xc1;|p\xef\xec\xdf\x92k\x85 \xd7\x9d\xfd\x10\x00\xef\xb6\xcc\xf7\xbb\xf2\xaf\xbb]\xd6\xcfC\xe9g\xda\xe6]\x96uY\xd8a\x7fd\n\xb5\xf2\x94\xb34K|7k\xbdj\xbe\x8e\x9d\x84%\xec\x0c\x0b\xdb'\xe7^\xe9T\xbb\x8a\xe4\xf7\xf9\xeftf\xf2\x90\xa7\xae\x13\xf3K^Q\x93\xcf\xf0\x838J\xb2\x94\x9d\xa9\xf6[\xeeTw\x11v\x99\xdfeN\x97\xe5\xec\x0c\xcb\xaa\xdd\x88\x9fh\x84\xcf\xc4Qz\xc99x\xb5\x02\xf5\xfb\xac\xfd\xf2,;sF\x14H\x13w\xc6\x1d:\xc9R\xe4\xf1\xc5\xac\x9dup_\xe2\xd7\x8f\x12\xd6\xce\x8e\x1e}\x95e\xec\xbb,}\xd5VF\xb7<\x07-\xb7Cfo\xbe\xc3\x12\x9e\xe5I\xc8\x8e\xcc\xbdZ\xdb\xc8\xcb\xf3\xb2\x91\xd0\x14v\xd8\x19\x96\xb4\xa36\xb4\x98\x06\xbe\xcb\xdb9;\xca\xe6\xc4\xeat:]v\xe4\x08\x9f\x89\x9d$\xe5\xc9\xcc\xd8 |\xcf\xc9\xf8\x9a\x1f\xee\xb5\x9d\x0e{\xe9%\xd6\x96+!\x16\n\xea\xf0\x99\xc0\x0f\xf7\x96\xa20\xe3a\xc6\xce\x88e<2\xdb\xb1\x8f\xe7\xb4\x1a\x8bhGV\x17K\xc0^\x13\x7f\x9fa\xf3l\x81eG\x8f\x92\x8aw\xc9\x173\xebo\xd5\x97\x93\xeb\xec\xb33lV\xad\xb4\xe8\xf3\xc4<;\xd2\xb4\xa0\xa2\xcc\x91v\xc8\xbe\xc7^\x11\x7f\x86\xec\xbbl\xeed\xe7\xd5\x0e\x19\x81XX\xebd:j.t\xfe\xfe\x83\xf4\xe8\xf1A\x97\xb5X\xab3\x93E\xf2\x0eg\xc9Iy\xfb\x85\xe0\xf0F\xef\x16w\xb3\x19\x8f\xf7\xfd\x90o&Q\xcc\x93\xec\xb0\x9duY\xeb\xe6M\x9e^\x8a\xbc<\xe0\xad.\xc1\xd6 \xe7\x0b\xec\xc8l1\x82N\x97\xc9V\x9c<\xc8\xca\xd3\xac\x99%\xc5\x147\x1a\xc5Q\xc8\xc3,]`\x8en\x89\"\xfb~\xe2\xc4K\xa5\xa2y}\xd14s2\xbe\x19\xe4\x03?L\x17jXA\x1as\xb7\x0e\xc6Tw\xdb<\x90\xb9&\xd2\x05\x96\xd0^\xf4/-J\xf9\xd6Bw\xedu\x9d<\x1b>\xc7\x08\xa2\xe7i;r\xd2\x13Mm;r\x8f\xd2\x05\x96\xd6\xcf+\xe1^\xeer\xd1\xb5[\xbf\xd4\xfaWZ\x84\xc0>P\xf2\xf5n\xcd)\xbcK\xe9l\xdc\x0e\xdb'\xe7\xe7;\x16\xc9\x14@'0\xc87\xa0\x93\x18$\x88W_\x82NaP\xaeA'H\xadT58\x7f\xe2e\x0c\nt_'\xc9\x08]\xdd\xe0\xc9\x13\x9d\xce\xab\xdf20}JX\xbf\x9e\x1c\x08\x02\xc6g\x8a\xc3\xc8^c\x9c\xd96Um\xce\x02\xe3u+j\xe98\xa6\x1d\x0b\x92Mz-\x88t\x95\xd4j\x0e\xfeGw)\xbb \xf3 `G\xce0N\xe59\xc9P$\xcfc~\xc8xG\x93\xa18\x89\xb2(;\x8c\xf9\xcc\xd0I7\xf6CM\x90f\\'\x08\x04Q\x0bA\xd6\xc9\xae\x877\x04S\xb9\x1e\xde@|N\x0d\xb3L\x8b\x04-,-\x02\xfbF\x90J?\xdd\xdew\x06\x03\x9e\xcc\x0b\x8e7\xe3\xa7\x1b\x8b\xdb'\xe4\x9f)O\xc6\xb7\x1b(\x82\x103y\x91\x942\xc5#KtY.\xddJ\xa4\xec\xaa\x93\xe6\xc7\x03&\"\x99\xb0\x90\x00\n\x17^l\xb1\x97{fz\xaek\xcd\x03\xcc\x9f9o0\xefp\xde\xa4=/2+vD\x00\x01 \"\x80$)Y\xd5}\xb0\x96\xad$\"\x10\xd7\x1d;\xf6}'a\x00\x9b*\xfaf\xe7\xbe\x92\x1bl\xbf\x0d\xf1\xed\xd6\x8e\x12\xc6}-\x8cW[\xd1\xde\x07]=\x1d\x13W\x0d\xd8;#\xc5\xe1U^\x10z\x91R\x1c_aP\xfc\xeb\xbb\x9c6\xa2&\xday_\xf6\xa6\x0b!\xdf\x16\xc7\xce\x1cz\xec\xcb\x85\xcdc\xa7\x851\xd5\xf8\xec\xa3\xcc\x94\xf7t\xc8\xb0/\x9fq\x03\xf4\xc5L\xd94s\xb7\x89\x85\xf1o E\xe3\xdf\x12\xfe\xc6\xbfk\xdc\xce\xfe\xac\xd0\xfe\xddLI,e\xffvUw\x8f\x91C\x1d\x82\x83)\x84\x13\xbcXn\x86\x7f\x95\xb8\x17\x87\xed\x85\xf9K\x1f\x89\x15F\xfe\x18\xcee=\xbd\xce=\xfb\xb9MP\x0c\xed6\x93\xc4_\xbf?=#\xe1\x9f\xa3\xe4IY,\x92,\xfc\x99\x18\x88\x8a\x9cR\xd1JZ\x9e\x96\x8c\x1e\xa8Hy\x05!\xe2+ \x91\xd2D\x88\xe4\x9f\x86\xd8\x16\xbf\xe8\x84#\x0d\xaan.\x95-\xee\xceP\x7f7k\x87.\x83}\x7f\xed6\xccvq\xab\x8c'\xdc\x01\xc2+>t\xdf{\x11\xe6\x85\xd3\x06\xfe\xeav#q\x91]\x1d\x92\xbf\xdb\x8e7O\xb2\x03\x7f\xb60\xcc\x0d\xa4[\x93\x1d\x06\xbe\xee\x0e\x1d\xc7\xd8Q3\xa2\x14R\x8a\xe9\xe6\xb1\xba\x14u\x0e\xd3\x91\xa6\x94\xe2\xdf\x92Q\x01\x94\x0d\xb1\x14g\xd8J(\xcb>\xb6P\xbe\x84bn\xfe\xc1c\x7f\xf6}D\xf7|\xd2\x04\x00m\xfdk\x0d\x03\x11#\x03\x92\x96\xf9\xc2\x8e\xc9\x05\xf8\x14\x81\xf3\x1b\xbd\xda\xd6_\xaeQ\x056\xf3\xe6aT\x90l\x00|@}\x88\x18FE\x91-Q\xd6\xbdv\x1cG\xc1v8.X\x8b\xa2H-\xfc\x14!\xd7\xf2\xd3\xf0\xcf\xe4J\xbc\xa1\x84\xc2\n\xc3/;\xfd\xd0>\xe2?\xc8\x7f\xadt\xe5*\x99\xbfJV@o\x8d\x8a\xad\xf2\"\x12\x9f\x15\x0b&2\x7f\x92e\xfe\x95\x9d\xc1c\x18\xc1>d\xb0\x01#\x98\xc0\xa6\xe3\".\x18=\x82\x10\xbe\x82\xec\x11\x84\xeb\xeb\x0e$\xd3\x90V8\x96[\x9b\x86\xc7\xdd\xcd\xa4}\xfaws\xd9\x97\x155\xe3\xd3\xcb=j1\x8b\xd3\xe2\x98\x92\x8b3\xbf\xb0\x13\x87r\x93mV3\xd1^\xff\xac\xe0\xf7\xbf\xff[\xf2\x8c\x9a\x9a\xbdK\xa1\x82\xdc\x06W\x1f\x0f\xe3\xebVe\x91\xef\x84\x8d\\\x99\x81\xbd3\xd6y \x03+\x13%\xf5\x86\xa1Z\xa7GB\xa0\xd5\xe4E\x1d\xde\xd6\xc8\xd7\xe6m\xbev\x18\xf1\xb2\x12\x8f\xe3\xf6*#\xccK[\xe1\x9fB\x89\x7f\xe2\n\xff\x14\x1c\xff\x14\x12\xfe\xc9\x18\xfe\xc9\xe0+(\x1eAF\xf1O<\xcd\xba\xf8'\xd3\xe0\x9f\x04Ug\xb7\xc6?\x127E\xf1\x8f\xdfB/1\xc59]\xd1\x8e\xe9\x88\xaf\x84\xd7?)+E>gV\xa9\x8b\x07\x99\x0e\xa2\xa3MH\xaa\xa2\xfb*N\x88\x15u\x98\xa4Z\xa9\xf1P\xaf\xd4\xd8T)5X\xd1H%\xcdcEz\xa5\xc6\xd6\xef\xab\xd4\x10\xbfd\x91\x7f\xb3\xa1\xa7~\x14\x9d\xfa\xb3\xf7\xf9\xa4&b\x9as\xf9\xb6(\xd2'\xa8\x88\x8b\xd4\x15\xde\x12Lc\xf5u\x12\\Mj\xfa\xbcY\xe7\x90a#\xad\xfa\x92\x97?M\xe2\xc2\x0f\xd1\xdfL\xa3\xbc\x94:;\x08B\xf4V\xc8\xd55_\xa7\x84%\xff\xa9\xfa\xd6(\xe9\x12Q\xf1E\x18\xbf\x9f@(j}\xe6\x87\xc3\xb7c\xbb\xab\x9fKxI\x07\x90C\xbc\xbe\xec\xd8\xa6p\x8cUF\x14l\x91\xa8XQ'\xf1\xd1A\xb4\xff.%\xa8\xf5B\xc0\xedr-\xb1\xb8\x18*ex\xb7\x0e7\x0cI\xc9\xec\x8d_,\xba\xe5LJbU@TA\xa6\xa5\xb0)\x0b\xe7`\xaf\x15\x95\x1e\xb0:\x03\x9cH\xe0\xe9ul+O}J\xf5\xd0\xdb\xc4\x05\xebU\x02\xd5$\xda\xcc4\x9d'SI-\xfd\xb4\xa6-z\x94@\xda\x8e\x83\xf0\xbc\x03e\xe2yO\xae&\x12c\"\x9ekW\xdf\xdcb\\\xcd\"\xc6\xeb\xaf=\xc8\\\xc7\xaa\xf1\x81Z_|\x91\x91\xb9\x10\x13\xecc[0\xb9\xd9\xf8A\xcc!W\x16_\xab\xc6\x17\x99XI\xba\x9b\xf2\x00\xa3jc\xe90\xd5\x8c-\xf0=\x9bUR\xaaa\x02\x83\n\xf7LZ\n\x0c\xf9\xd1q\xd3\xd0\xbf\xf3\xa5\x0b\n\xfe\x94\x98\xd6\x12pX\x13\x98\x99\xc5\x01\xb8\xe4Q\x8f\xc8\x00\xfd\x86,s\xa5%)\x16I\xd0\xdbV\x8a\xee1=\xa2\x15q\x9e\xe9=\xc3\xd8t\x17r\xba\xdd=\x12\x99(J.\x8e\xb2\xab\xe7\xc5\xeb\xb2\x98\xb4\x8d9\xe5\xe7Z!<\xd0\xbdo\xbfko\xe3\xb0C\xcb\x8eY\xfey\x194uo\xa3Pu\xe7\xd0\xcb\xc8\x0e\xc5\x9d\x13\xf6\xdf9\xe1\xe7}\xe7d5\xf1\xa1\xbbu\xa4*\xdf\xd3\x85\xeb\xd6\x0b\x07\xdfNX'\x9e\x87g\n\xa8/\xab\xfb\xabb \xba\x95\x98\xb1\xf8<\xee\x96D\xec\x0ee\x06\x84GW\xa9b\x9c3\xac\x12\xe6\x07\x97dV\x16\x8a\n\xf3\x9e+4\xc5\xf2$~\xba\xf0\xe33\xc5\xf7\x01\x82\x8d\xf5\xd2\xcf\xde\x07\xc9E\xac\x92?.X\x95e\x12\x90\xe8\xe0\xd2_\xa6\x11QU;g\xd5:\xb4\xa1\xaa\xee\x12\xb85q\xc1\xe4\x01\x01\xc9gY\x98\xd2\xad\xb7*]f\xf7\xb3\xb3\xd6g|\xe9\xf8'\xe4\x02\x12\xefu\x16\x90\x8c\x04/\xfd\xb4y\xce\xe9ZG\xb4\xda\x99\xf7\x9e\x08\xe1w\x98\xe5E\x9bu\xa3\x80v\x05{p\x86]\xa8\x90\xd6)\xec\x81\x95\xe0)fw\xd3U\xcd\xef\xa3\n\xdar\x81\xc9f\xdb\xb6?H\xa2\\\x19n2\xbc\xf5(\xeb\x1b\xce\xf0B\xba\x97\xcc\nRl\xe4EF\xfc%\xbf\x08\xe9$\x98\x91k\xe4\x85q@._\xcfm+\\\xfag\xe4\x1e[\x88N\xa1_\x06a\xa2+<\x0f\x03B\x0bu,\xf0 \xdb\xd6\xe7qZ\x16*m\x03\x9f\xcb\x0c\xf6\xeb\x0b\xae\x85DOt7\x1d\x93f[\xf3\x90b\xecK\xf3;\xc1\x0e\xa1\x82V\x98t\n\xb5\xa3)\\lL;(.'\xd0\x8f*/\xae\"b\xb2^\x07\xf4\x1a\x880\x98\x07\x1d\x9d\xb6b\xf72\x026F\xeb\xdf\xfe\xf5\x8f\x96\x90}\xdf\x14\x07\x81\x0e:NN\xf0p\xea:/]\x88(\xc0\xdf|\x85\x1a\xbdfI\xba\xc1O\xb8v\xba\xf6\x17\xfc^p,\xe7#L7 iFf~\xa1\xdb\x0b\xca\x95\x0b\xbcQ\xd5\xa4\x97\x82\xfc\xb7\xd8\x0d\xd3\xf8nw\x88dj\xb8w\x9c\x12\xe1\xec\x1a\xa9\xb0\x06+\xab\xabta\x1a\xf6<6\xf2\xfeA\x98\xa7~1[<\x8f\xc3\"\xf4\xa3\xef9\xcb\xaa`J\xc4\xc3n\xff (\xf8\x12\xf1H\x13\x9c\xa0\x9f\x94\x05\x1b`\xc1\xbaz\x01\xb4\xcd\xc8\x9c\xde\x04B}E\xcehs\x13\x06\x8a\xcf\xe7\xb0\x0f\x01L`\xae\xffhU*\x15\x18\xa5\x8azu\x83\xfd\x86z\xef\x9d\n\x1f(\xa5\x1dZC<\x18p\x07\xc9 \xb24\x9d\xfd@\x05'yRf32\x81es\x04\x86\x83\xb2P5\xd3\xbbW5K>\x01_\xc1p\xcb\xfc\xf8\x04\xcan\x0dr\x99\xfaq\xf0\x8c\xa4\xc5b\x02#\x85t@\xf0\xdbJ\x01\x9c\x80\xda+a\xb8\x83$\xac\x02\xf8jA\xd8\x9c \xc2d\xe2WQ\x9f\x13&z.\xe4\\w:3Y\xfb\xa3!\x12j M\xd5\x15\x90\xd58B\x96L#\x06\xec\xdd\x19\xe8]\xe9 \xefz\x8c\xa7\x15\xe9\xa2\xad\xd2\x90\xbc\xc5\x14\xeb\x95\xb0\xaf\xad\x9e\x18g\xcc\x89\x9d\xee\xed\x05B\x98\xc8\x996\xedh\xd2L\x12\x03VJn\xf8\x17\x0b\x8dW-\xfa\xaf~\xb2\x19\xff\xd4\xd4\x81\\\xc9zS\x818X=f\xaf\xf2\x83\"i!\x04Y\xdbCQd2\x87Z\xd1nY\xbd\x8a\xd1\xc2\xcb\xd3(,l\xeb\xc7\xd8r\x86)\xd3\x15\xad\xc4\xf0\x186a\x9f\x1b\xb3\x11X\x87\x91\xe3\xfd\x94\x84\xb1m\x81\xe5\xc0:\x14`V\xe0\xf2\xcat\x10\xeaM\xa3\xb8\xaa\xa5\xa9\xf5\xc5\x06\x8d\x1d&/\xfa\xe5z\xd8\xb6\xa8\xa8\xf3\xe6=q\xdc4,\xb4#\xafF\x91\xb2\xe5#\xef\n\xf6 \xc5\xb7\x9f\x1b\xf13S\x918 /\xe8\x908!/\xe8\x908>/Pz\xbb\xcfT$N\xce\x0b:*\xcf\x88\xdb\xe9\xd6c\x9d *gf\xa0rf\x9f\x9e\xca1;e\xf6P9x\xa5\xbb=\xc2\x90U\xa1'L\xce\x18\xd3\xd3k\x88M\x9f\xd0\xcbI\xc1\xbe\xaa\xd5Hx\x06\x14gY\xee\xe3{?\x0b\xfd\xd3\x88\xa0\xc8c\x85\x0e\x85R;\xec#\xc8bn\xb3^(\xfa\xd3\x7f\x951O\xfc2\xcbH\xcc\xbf4\xd3j\xd5\xa4\xcfH\xf1\xa4(\xb2\xf0\xb4,\x88m\x05~\xe1o\x9c\xf3>\xfb\xe8\xac\xe6\xc2\xa9\xaf\x06K,\x8d\x05{\xd5\x8d\x82\x91pb\x83\xa9\x0e3\xa66\xc68AZ9\xd1\x97\x9f\xfb\xd1\x04|e\xf1\xb5f\x8f\xabE\x1f\xb4\xa3\x8c\xe3\xc0\xddd_R.\x97\x04\xac\x85\x8e\xe9/\xef\x04\xcd\xdc:\xdc\x00\xfa\xafh\x90\x08\xb4\xbd7T\x9cE8\x8c\xb3\xa8\\\x8b\x9f\x85\xc1\xcb\xa4\x8c\xdb\xc9\xff\xe0\xa32\x19\xdcB^\x0d'\xa4 \xbcH\xf9\xd3\x96\xebcZ\x08%>#\xc7\xcb,\xb2\xfa/^\x15Y\xd7Z\x8b\x1f\xc2(zKf$<\xc7\xcb2\x1f\xb0&\xbd\xa7|\xc8\xa2\xc4\xb2sJ\xdf\xc9^\x15\x1f$\x955{\xe3+\xf5\xdaS\xba\xaf\x1eqk#\xd0\xb5\xab\xf9\xceD\xc4\xd1\x15@/\x19o\x1e\xc6\x81D\xfc\x0d\xa4\xfc\niwyl\xc5F\xdf\xda6LF{h\x8c\x11Vdl\x0b\xb0b\x15`\xe9\x1b\xb3CVO`\xc9\xdc\xaa<>\xa2\x96:zu\xfa7\xb1[\xf3\xc5o>|\x80\xac\xc7\xb0\x11$\xac\xd9n\xa2\xf7Cf\x92\xda_\x0fqj\xa1P\xb7Zz\xe6\x0e\xd4\x08\xb7\xa7Ha\xb31\xf4`\xdf\xa9\xf8\xc4\x8c\xd3\xee\xfc\x98\x0f\xdc7\xcd\xe9\x1e `9\x98\xcf\xc9\xac\x08\xcf\x89\xf8\xd2\x88E\xd0\xfb\xaa}\x92{\xd5\x1d\xb2k\x94|\x92MgW{\x82\x06\x1e5\xb3\x04\x87\xc7\x14\xf4\xf2\xf0g\x0d\n\xe4c\xceo*\x14\x91\xd5|\xc2\x13L\x0d\xd8\xae\xbe\x93\xc8?%\x91\xb1\x9bE\xb1\x8c\xbeA%\xf3\x8d;aa\xd1\x8c\xbd\xd4\xea\x03\x04\xf0&y\xad\xeb0fT 3\xb7k\xda\xa2\x98\x00\xa6o\xe1\x13&p\xeb3\xa0\xe6g[\x8693:C\\!W\xd7\x03\xa7\xdb\xa8\xa7\xb3G\xf6\x8a\x841N\x8e\x905\xf5\x00\x1374\xbe\x0b\x88\xa3\xb4LY\x90`\x83\x8eP\xb7A\xd6S^\x0b\xde\xbd}1\xb1\x0c]7Dg\xa1\x9d\xe1\x8c\xb4\xb5\x17\xdb\xb5d\x8b\xd3\x0c\xd2y5|\xd8\xb4s\xd2Wk\xd89\xf9\xab\xdd\xa9}\xe0\xd5c\x89\x03z\x7f\x0d\xf1\x98\xce\x1a\xda\x06\xd4~\x1bC\xea\xf1\xdb\x95\xc4\xe5\x12\xcd\x11ns\x8e\xe9\xd3\xe2\xe8z\xaf\xf9\xfa\xec\x13\x13\xcfkZ\x8e\xc6\x14V@\x050`\xbf\x06\xa2\x03\xa8\xe2?\x92`B/\xf3\xbd=Hl$\xa6\xfa\xa9\x1c\x86\x1a\xfa\xeb \x9cc\xacH\xb1\x87\x89\xfaq`\xa2\x9fm\x88\x96\xb8}\x93\xe5\xa6\xb5\x05\xb9T\xf1s\xf2\xc3G\xccW\xa2\xcf&\x0e\x86\x83\x83\xb9\x91.\x0c\x9a\x16D\xeb\xf0Q[Ctj\xf4\x88[\xeb\x05\xee\x13\xbb\xce\xf1\xed\xe7&v\x8dtb\xd7H'v\x8dtb\xd7H'v\x8dtb\xd7\x88\x89]\xebQEL\xc0\xaa\x12\xabF\x9f^\xac:\xbb\x8dXU\x12\xac(\xa4\xa7]\xad\xadVy\xdc\x92Z\xdeJy|+\x11\xcf\x9dr?}\xbcM1\xc4)F\x19\xe9\xa3\xa6Q4\xb7\xa5\xeb\xb5\x10\xb2\xa5\x98\x81I\xdbMk\x1f\xa1w\xee1+\xa4p~\xe5\xd8\xed:\x15\xd2\x17\xb0>GI8\x962\x0fE4\xe5a\xf3\xe8\xe3\x9d\xb9\x8b\xdb\x0fYX\x90\xd7qt\xd5\xc0\xbc\xedG\xa7\xabp%\xb0\x1f\x0c\x08\x83\xa1\xb7W\xcc\xc0\x80\x96\xe9\xee\xaa\xd3g\x02\xd9\x85\x1f\x07\x11y\xbd\xea\x88[\xa0;\x14\xd0(\x10\xdf\xfb)O\xe2{\xa1W\x90\xbc\xb0\x0b\x16\xc0^\xb6\x1d\xe0yf`2\xc8\xa6\x00VY\xbe\xf6\xe17m\xaf\xbc\x91vlX\xc1\"9;\x8b\xc8\xf3\xfc \x08\x8b\xaf\x93K0$\x99\x91\x1f\x19\xbf\xb2\xb1\x0f[y\xe9\xdb~\xb9W(F5\x815\x8c'\xc0\xfe2~\xa7\xb6\xc0\x84\x1e\x98\xc7\xa46\x9d\x08W\xf2#\x8fE\xe1|!\x9e\x0e\x82\xd6W\xe5\xa7A\xa3p\xa4\xc3\xea\x14t'w{f\x1bV\xb2\xa9\x80\x15\xf8o\xfa\x08\x05u\xe3\x16\xaa/\xf1\xc1*S\x1d\xf6[\xdd\x02\x02V\xb1\x82\x001\x85\x16\x9e\xe0\xb6\x04\xf5\xdf_~\xa9\x9e\xaa-Ur\\X\x93\x1a\xab\\N\x18\x11\xd8\xf8\xb3\xd2\xeb\x0f@\x0b2d\xae\x8e\xf1o\xbc\xd4\xcf\xc2\xe0]\x1a\xf8\x85.\x08\xc2M\xd7X\xa2\x11\xf8*\xcbo\xb4\xeb\xac\xda\xa5;\x9a\xb2V\x10\x05+\x1e\x86a\xeaxXA%\x0f\x15ie\x88\xb6\"?\x99P\x9f\x0f\x101A\xa5\x9f\x1fx?\x86\x98O\xce\xfa\xba,\n\xb3c#p\xba+\xb3\xad#rY<\xc9\x88\xd2\x15M~JV}\x11\x9e-\xa2\xf0lQ0\xb0\x9a\xf4T\xe1\xee\xab\x97\x9ef\\zz\x13W\xe0\x81\xd2\xd3\x94U\xcc\x0c\xa3@\xf2\xad\x8f\"\x1f\xaa\xf0\xd5SK\x91M\xcer!9\xee\xd9'\xc7\x85s\x13\xa3a-vk\xab\xe7*o^`\x19XS\xbfo\x99fC\xe6%b\x11\xa8\x82R\xf4\xcf\xe9\xc6c\xab|\x13\xf8\x94\xdfqH\x9bX\xb8Rz\xfe\xb4\x15\x01\x15,\x17\xce\xf1_\n\xa2\x06 \x83y8\xbd|\x1e\xacd\x17\x0b\x9ck 3\x12\xe0\xed&\"b\xf6~\xc5\x08\xa2\xfa\xe0\xf5\x7f\xd1q\xae\xe8\x91\xc7\x00\xdb\xbb\xbb\xdc\xbc7~\x9e_$Y\xb0\xf2\xe6\xfd\x11\x9fO\xb1w7\xdb\x0d\xbf,\x12z\xddG\xa4\xa0\xbb\x12\x93\x8b\x8d\x94\xcfu\xc0\xd7\xb1\x08\"8\xf8\x0b\x0ea+|q\xf3\xdd_\xe8\xfdkz\xc2z\x88\xa7\x07\xdd\xe7C\xf6\x85>\x84^\x9e\x83,\xe4\xa1\nf\xda[\xd5\xe0\"\xc8\x8a\x0dF\xf4\xda\x12\x11\xb6\xe4\x94\xf8\x19\xc9\xf8\xbdj\x82\xf7\xdf\xe9\xc6\xc3\xe1\xdd\xea\xca\xbb\xf1u\x87\xd7B\xf0\xd9]u7\xba\xe6\xee\xf6\x8ac\x16\x89\x16.\xcf\xe7\x86\"\x87_m\xab\"\x9c\xbb@6w\x81h\x86#\x99\x01\x08\xc6\xe8\x7fl\xda\xa9a\x08\x81,\xfb\xeb\xd4\x11\xab\x12\x0c\xf6\xfe\xed\xd1\xd1\x1b\xccLK\xe2\x82\xcbR'P\xc6y\x99\xa6IV\x90\x80IR\x08\xa5\x97\xac\xffh\xc1:\xa4\xb0N\x7f\xddN\xfc[\x0f\xaf\x16\x017W8\xed\xb3e\x919\xf6.{\xd1\x002\xb9)c4r\xc6\xab7-\x98\xf4\x1b\xcf\xb4\xab\xccLH_+D\x0b\xb5\x1e\xd5$3c33\xf1e\x95\x82\x92\xaf\x1d\xcf\xe9\xc3\xc4e\xfd\x02$w\xb3\x00\x9d\x99\xa8\xb2\x92\x1b\xb3\xbe\xd1;'O}J\xe3\xd6\xab\xa7\x96\x1e*s\x9d\xd1\x01\x9d\x99\x00\xca\xb4\x9cd\xc8r2Q\xbby9\xd9\xc5=h9\xd9\xeau\x86l\x17\xd5\xec\x15\x06\xb7\xf54\xe5\x15\x87\x9e\x94\xbf\xe2\x11\xa4E\xefT3\x96g\xbe\x17r\xe2\x95\xa7*\x0f\xdbp\xdbK\xd0\x90\xd5\xd0\xa0\x1fL\x15\xe9G\x0d0tM\xb4k\xa9r\xbc\xfa\xf4\x07q\x05LT-\xa7j\xe4\x03\x82\xc8\x19h;\xe5)T\xc7\xa9Q\x07\x8d\xcb\xebxn\xd2\xd5\xe17\x12\x08B\x87\xa0\xba\xbd\xfa\xf2ws\xf6MZY~\xfbp\x03\x85\x82\xde\xaaYGW\xa7\x06 \x96\xf7\x95R>k\xf1\x80$\xa1\xe7\xbc\x8d+u\xe5;pKo\xea\xa2\x11[p\xb8;t\xdb\xa1\xba\x9eT6(\xc2\x9b\xd6\xa3Z4\xa4*U\xef\xfe\x8d\xe2Yw\xe5J\xffhB\x83\xed-\xbd\xd4`\xab\xc3\xd3\x87UQ\xc7\xad\xd9\xaf\x8a\x1e\xe8d\x07\xdb[\x0fu\xd2\x83\xedme\x8ckV\xf4yX\xf2\xc9\xfb\xd9lHX\x8dHym\x9aSyR\x16\x8b\xe7\x05YJ\xb9\xc7\x9b\x15\xea\xec\x0c\x93ZR\xd0\xacR\xa7\xa26\xa6<%3\x1e\xb6\xd0\x9ba?\x98\x90\xeb\xeb\xab\xe7\x01\x89\x8b\xb0\xc0\xa06b\x08\x7f&W\xa8*\xc2\xbe;\x8db`mQ\xf5i\x12\xe7\xe5\x92\xe4?0\x01\xd1JB\xfb\xdea\x17\x8aa\x8b\x0eQX\xe0\xd8Ek\xd0\x9a\xe12_\xcf#\xfft\xd0\x00\x05\n\x97\xd2\xf2\xb1\xbc\x0f\xb0\x8f\xd1\xe0z-%\xea\x0f\xbf\x0f\xf3\x10\x85'k\x9bj*\x8d>\x14FN\xfd\xd9\xfb\xba\xb2:\x1c\x14\xa2QK\xd4^uP\xdd^\x0cCR\xcd\xc00(FO\xab\xd7\xde\xec\xc2\xa5\x98\xbbzT\xca5U\xf6\xa8A\x1f\xf0\xb9j9\xf4\xbb04z\x04\xd3n%\xf1Qv\x95\x94\x05:\x07\xeb+'\xbc2\xf3g\xee\xa9\x1cr\xbd\x99X{}M\x96\xe5\xd2\x8f\xa2\xe4\xe2(\xbbz^\xbc.\x0d\x96P,\x87e\xc1\xeb\x1d\xc4\xfei\xa4\"\xd5\xc4\x83\xf1\x1f\xbc\xb9A\x0b\x12\xad\x10\x0e#\xa8\xebb\x1ag}\xcd\x05\xd6\x1c\x18L\xf6\xbc\xaa\xdc\x1b\x1fv\xc9\xb6`H(\xd9\xb3\xaa\xea\x80!\\UZ\xce\x97\xa8\xc5\xd4\xd7<\xad\x06\xfb\xc6\xa8\x13=a\xdd\x0b\xad\x8e\xbe\xe2\x05\x86e\xaeQf\x8f\xc3\xd8\x01\xab. \xa5?\xd2\xc8%\xfb\x80\x07\x85;BZZ_\xfb\x90\xd5~Z\xa1\xca\x1e\x0f\xb0\xa7\xac\xfe\xdb\xdaM\xbc\xef\x8b\xf7\xb0\x07%\xa5m\x0c>\x7fO(Q\xe5\x859e\xbe\xf4\xb5^\xc3\x1e\x9c0\x16ArS7\xcd\xee\x0d\xec\xc1\xa9\x97G\xe1\x8cP\x9c\xb51rx\x82\xef\xc6\xf7F\xe5\xdf\x8dS\xad\x1a\xb4oZ\xcd\xcd\xc7\xe8\xacO\x05w'}\x0eP\xf5\xdd\xb8\x9f\xd5\x838T>~\x155\xd3\xcc\x1c\xac\xfdX# \x02\xc5l\xc3\x82,\xc1\x82u\x9e}\x8b\xd9\x93v\xae^\n\xf7\x96\x8f\xaa\x1b]2S\xc3\xca\xac\xa0\x13\x1c\xa6\x04\xd5\xf6\xc4#2W>F\xf5ZQv\x86\x1f\xba\x9a\x9er\x0c\xd9x?\xd1~J\x83\xf9h\xdb\xd9\"\xb9\xfe17\xb3F\xedR\xcce\x17\xcd\x9bu-\x1c\x98\x06J\x18\x0d\xa2\x14\x8b\x88\xa7A3\x193=6H1]r 9K\xb3\xf1\xb4\xdd\x02*\xe5\xf5\xaf\x1b\x1e\x10r=\xf4fI\x19\x17\xf6\xad\xceD\x0b\x1c#2\xa0cmg\"7\xcf\xb0\xee$\xc4\xb8zO\x14\xe7W\xa0\xa6\xaf\x96\x0d\xa8\xb3\x18<\xe2Y\x12\xc1,\x89N\xd8\x85\x03\x8d\xdd\x8aN\xd0IK7\x13\xeb\x15\xbap}\x8aq\xc8nO\xda\xe1<\x93}\xa3\x1c\xe3\xb8\x1a\x99\x94\x06\x99P\x82\x8c:%\x9f \xee7\x9fV]\xbd\xf4S/\xcc_\xfa)\xf3\x17R\xd8\x1f\xd2\xe7\xda\x0e\xa5\x8e\x07&o\xd2\xcd\xe7\xa2\xcf\x8fh\x1e\x1bc\x95@G\xcaj\x88ZB\x1fA\xc1O\xe0\x94\xd1\x80}\xd9\x84j\xb6g\x02\x06\xfe\x80>\x99\x7f\x81W\xe6\x04z\xe2T\xa4\xac\xd6\xa2F]?\x84\xc8\x82\xf8\xb5|\xc9\xbe\xc2\xf4%\xc6v\x98\xdb\x94\xec\x94h\xae\xdf\xcc\x04\xd4\xe7\xa3#\x7f!\xa4H\xf2\x97-QV\xff\xbaK\xb2t\x03\x07%jsNo\x02\xe7}\x8b)\xb8\xb7 \xf4\x04\xd7\xaeBEN\xe0\xbd\xb6\xa2.^h#;\x1c\x06\xd8\xbb\x0b,\x7f\x13\xe31m\xc7i}\xdd\xbfJ m\x90o0\x01\xcbj\xdc\x9bm\xb2\xe6\x8e\xee\xad\x8a\"\xab\xef.\xb8\xcbY\x1e\x1a\x07\":\x9f\xf0\xb0\xe2\x98Z\xb2K\xb8\x1a\x0e\x8a\x8c!\x14,c\x1f\xc1y]-\xf5\x13\xdb\xa1\xa4\xe2\xeb:t\xab\x9e9\xb8\x93\x95\xff\x87d/oJ\x0f\xd7\xe0}\x82w=\xa3\xda_\xd7r\x01\x8c7\x80; \xfd\xa9\xbd\x81\xb9$\x03#%\x1a \x83\xa6\x87\xb1\xae\xda\xa5iN\\\xe6y&\xe2\xfb>\xade4\xdc\xff\xe8\xccmk\x8a\xafL + y\xf2 \xf05\x10\xe9\x00\x1c\xef=\xb9\xc2\x1b\xdfH\xa8\xf3\x8b\xa1_\xd8/\x9e\xa5\x97\x93\xe2mg\x06\x03r\x1c\x8bh\xf8fd\x0dm\xdcn\xacmr\x0f\x1e\xc6\xfeI\xd1<\xf9\xd2m\xa0\x06Zw\xcaM@r\x93\x83t\x17\xb8\xf1\xa9\xd1,\xb7Blo\xf4+\xd2\x08\xfc\xf8zP\xbd\xef[\xe0\\\xbd3\x01s\x9d\xf8\xa1/\xf9\xaf|i\xaf\x06\xc1\x03\xdc\xdc\xb5\xa6T\xedG\xa85W\x9be?\x84\x03W0\xcck\xea\xdb\x8e)\x0f\x19C\xe3\n3D\x9d\x12\x0f'\xb5\xe5sY\x0dr\xc0\xa9\x84\xd5h)\xf1\xf0\xc3\x9c\xd0^\x9f\xc7L5\xd4\xfba_\xa4\x90\xc1\x88g\x95 ~Fh\xa7F\x97\xab_\x03Z|t\x03\x8bo\x95\xa5\xf7\xb9\xe8M\x1dD\xb6%\xa9\xe9\xcb\xb5\xd4\x12\x01\xf5Uoi\xb8\xba\xda\xcd\x86\xbe\xac\xab\x92\x95\x94\xdb\x13\x98\xd6!SZ\xf1h\xe9\xaa\x06\x06\x1b\xaf\xf3\xcf\xd0\xa8\xc6e\xa6\x0b\x1d\x03\x16\xcc)\x95\xc1\x1e$H\xecdM\xd3\x91\xccl:\xd2\xf4\x93k\x81\xac_[\xe8\x89W\xab\x98)\x0e4\x94SZ\x83\x85\x83\x84\x9a\xbaZ\\?\xadod\xe9G\xea$\xedyq\x15\x11\x9de)%\xfb\xcf\xb2\xa4\x8c\x83\xa7I\x84\x19\xdc\xff\x7f\x0f\x1e\x9e\xce7\xb7\xbb\xf7t\xeb\xe4\x19\xc6\x92fj\x19\x9dL\"\x9c3\x1bx\xab\xdd\xa8E\x17\xdf\x92O\xfegj\x0d\xd6\x03E\xd9\x10(\xd2\xd8K5\x0dj?\xcf\xe9\x07\xdax\x16\x81\xce\x18.\xd0\x19\xc3\x05:c\xb8@g\x0c\x17\xacf\x0c\x17\xa8\x8d\xe1\x82\xda\x18\xae\xebd\x93r\x0f\x81-\xa5\xb1[\xf0\xe9\x8d\xdd\xcc)\xfe$c7\x15\xed'\x19\xbd(L\xde:\x9e\xc2\x83M\xdbn\x95Q\xf8\xf31\xbf\xe93\xae)jO\xe0\x1es\x11JPO-t\xde\xd98M.\xadc\x03}O!L\xeb%\xcc\xd7i\x8d\xf9M\x88\xe0\xc2\"\xeeX\x9a\x91\x99_\x08i\x80\x1dsI\x8e\\\xc0.\xd7>U\xda0\x86\x8e\xcd\xa7n}\xe3\xc2\xcf\xe20>3\x89\xffE\xdd\x89uW|e\xec\xfd\x94\x84\xb1m\x81^\xe8\x91\xe8{J\xbd\x97t\x16\x1d\xfa\xf3\x97kW\x86\x01\xc3Pd\xb9\xb9\xc9\xb6\x88\xa4\x94#5d\x0b#\x97\xa9\x1f\x07\xcfX\xbd\xbaoOzO\xcf\x9b:\x01\xd4\xcd\x1c!\xfb\x1c \x19_\xa6\xbf\xb3\x16\x9f\xe75\xf4\xef\x0e\x1a\x9f\xad\x83\x86\xc15C\xaf\xa8\x890\x91c\x97\x89\x02~\x93\x87\xde<\xc9\x96\xbe\xa2_\xee\x92\xc1\x03\x9a\xab\xfd1\x84K\xd7\xda\xde\x1eD\x18\xd9\xfb4\x8c\xfd\xec\x8a\xbd\xc1\xecB\xd6\xa9\x9f\x93\xddm\xf1F\xef\xa9\xc1@_\xef\xd2\xa0\xf4\xe4\xe0\x01\x12\xe7\xa12\xdd\x90\x84\xeaJ\x1eS\n\xf6\xc1\n\xe3s?\n\x03\x8b\xc9\xe0\xbbm\x86E\xd4\xfc\xa2\xd4\xd4\\E$\x9a\xdbU\xcaK:\xda|\xba\xa9\x08\xd2\xaf\x90\x07\x04a\xce\xd9\xdc\xc2\x0b\xf3g\xfc\xaf\xe6a\xf8\xcch{\xb7\xca\xbd\xdfL\xef\x0duR~\xe1\xe8\x9e+\xde\xd5u3\x92\xa7I\x9c\x13I\xea\x01R\xa6\\\xcd\xebJ\xde\xc3\xdbnEN\xd2\xb9\xcb\xc6\xf6}\x05\xd6\xd3\"\xb7P\x8b\xdc\x8c\x84R\x15\xf0\xacP\x06<\x8b\xab\x80g\x94\x88\xccX\xc0\xb3\x0c\xbe\x82\xe2\x11d\xeb\xeb\x0e\xc4\xd3\xac\x19\xf0,\xd3\x07<\xab\x15\xf0&\x92\xadJzwx\x95\x17di;M\xdb\\\xfc\xeb\xbb\x9cN\xc7HW1Z\x96\xd9e:v\xc6r\xbf2j\x96\xad8?\xde\x0d^L<\xad\xdb\xf6\x0f\xdd_\x8a\x8d\x0c\xcd\xd1J\x854\xb6\x80}\xc0\xd4\x18\xcd\x06\xacc`\x81t\x9b/\x95x\x0e)\xd5\xe7\xb1\x1d\xf3\xec\x05-XW\xc0]kl\n\x03\x88V\xd3Sag\xfa\xcc/|\x8b}\xe22\x85\x03\xcbZr\x8c}\xb78YWw\x18\xee\xaa\xffn\xe3\xa6\x81\xa8N\xeb\xdd\x8d\xa4\xd3\xba~(j\x84\xd2?\x14q\x1eT\xae\xcc\x98\xb8\xa1\xbe\xf0\x84\x0f\xb3\xd6\xc9:\x91P\x9b\x9are~\x00Ul*\xc59\xc6\x80\xa2\xfb0\x0d\x11|;s\xc2\x98\xcf.\xc4\x02\x94\xf5\x15\x9a\xe7\x0bH\x94\x13\x15S\x8b\xbc\x96\xa6\x9d\xa2\xdb\x8ei\x1b\xb3a{\x93\x0f?\xc8\x9f\xc9\xa6\xc4C6\xc5\xbc#\x03\xb7#6n\xc7\n{\x11W\xaa\xb4\xcc{\x9dq\x17\xf5\xd4\xb1\x1d\xe5\xd6t.\xed!\xfb\xe3Br\xbb\x9d {w\xc6\xef\xdb\x99\x84\xc5\xddeq>\xf7k\x84\xe2\x9b6\x8a%#\x17\xa8G_M\xb5e\x08Mn\x9d\x82\xa8\xa7\x89G\x9de\xa3\xb4}\xa2\xbcrl\xdah\xac\xd9\xb6\x81\xb1\xbai\xeb\xa5\x97\x914\xf2g\xc4\x8e\xc9\x05\xbc%g\x07\x97\xa9m\xfdb\xc1:`D\xc6k\xcb\x05\xeb\xccr:*9\n\x11\xa5\x04\x1f\xf8\xf3\xf7\xa5+\x95\xca\x8e\xd2\x8e\xedqG\n\x1a\xf2\x92Q'4\x0fSX\x8c\xb7v\x95T]\xf9;\xb2\xac\x14\xfb\xfer\xed\xb6\xa5\x82\x99\x0b\xbe\xf7\xee\xcd\xb3'G\x07'\x87\x07/\x0e\x9e\x1e\x1d<;9}\xfd\xea\xe8\xe0\xd5\xd1\xc9\xd1\xdf\xde\xfc\xfbZ\xaa\x88\xe0\xd5\x16\xf5\xf0\xcd\xebW\x87\x07\xbf\xcf\xaa\xeadR\xaa\x98\xac=\xeb\x91\xb8\x10\xeaH\xf1U\x16\x84a\xaf\x93\xef\x9f\xbc}\xfe\xe4\xeb\x17\x07w{du$\xc4 \x0c\x16{\xef\x89\xc2\xa8\xc5\x17K\xad\x069 \xef)\xef\xfe\xcc\x85\xd0H\x11b\x05\xe3V\x94.\xf8\xcd\xf5\xcdnq%\xd72\x8fQ[\xbd\x97\xf0\xd7;\x0f\xa4\xfb6\xa1\xcb\x82y\xf4\x92\xec\xc0\x9f-l\xbdh\x01\xe9>\xef^\x18\x07\xe4\xd2\xfb)gr?-\xd5Gw4\xb1U1\"\x88G.\xd3$+\xf2)#\x80R?\x9f\xf9\xd1S?'\xdf\x84\x11\xa1\xdb\xe8\xd8\x85s\x8c\x1b#.\xd1}\xe9w\xdbAH\xba~\x07-\\loo\xefR\xb2H\x8c\x03\xd7eg\xb43\xe8k\xc3\xb2\x0b\x1b\x8d\xad\xb1L\xd0\xd4\x11\xbd\xecU\x0c5*Z#\x93\xa6W P\xdfd\xc92\xcc\x91r\x89\xed\xed\x9d\xfb\x8e\x0b\x87H\x91\xd7\xa65^^\xf8Y\x91\xff\x102\x0dIlo?\xd8\x1d4\xc3\xd8~8FM\xef\xc3\x07\x9dU\xda\xde\x19\xd6F\x1fpno?TB\xe7\xf6\x8e\xca\xc0%\xb6\xef\xb7_3b\xef\xfeHZ\xe9\xe6H\xc7[\xf7\x1d\x1b\x05n.X\xf8\xaf\xd5\x83\x87P\xbbt\x82\xd2;\x9b\x08'\xb3\x13\xda\xff\xa6\xf8\xe3=ES\xf5~\x18\x92x4T\xa6'\n!|\x15\xac\xe0Da\xd7\x18W\x85\xe1\xfa\xba\x12{\xac\x11\xdcTxL\x19\x94J\x9cm\xd7s\x10\xa2\xb9\xc4\x1e\xa1MzB\x0f\x9bE\x0f;\x8b\xd3\xc6\x8d\x0cYZ\xd9\xfa\x1d\x992\x99C\xec\xe2O\x89;\xbav\xab\xcah]\xf3D\x08*Q\xd7\xc0W:\xb3Y\x17\x0e\xfe\xac\xabg\xb6E\xe2\"\x0b\x890\x9co\xc3\x8f\xbc~\xf2F\xca\x0b\xac\x8e\xd0\xd8\xfb\xa5j\xaf\xf9*\xaaP\x17\x8b\xb9\xda\xdd\x93 \x89)\xdb\xb2f\xa6\xfdoy.F;\xeas\xf1\xb0\x1d\x95\x91\x1d\x8b\x87m\xc1\xb6\x8f\x9c\xc6#\xe9,\xeflb4\xf3\xd8\x1e=tl+,H\xe6\x17\x98CV\x0f\xbb|q(,\xd5\xb3k\xa1\x82>y\x1b\xa9\x11\x11\xc6\xef\xf6U:\x9e\x98\\\x16\x142Gn;u\x00\xed.\xc4\xb6)+\x0b\xcf\xaba\xaf\xb6\xdc\x12\xc2Q\xdf\x86[\xbb\xeau\xdd\xd5\xe2\x95\xedm\x07\xf6\x95\x9coHr\xe81@N\xecv\xa2\xa1Jk\x10\xbb\xb8y!\xaa\x07\x90\xda\xadT\x079S\x16\x94\xf0\x18\xf2G\x0ed\xde\xdc&\\\x182\xcd\xd7\xd7\x8f](\xa6q[\x08!\xa8\x8c\x9b.\xd8\xfd\x91\x9a|\x18\xa9!q{g[\xb3duw\x1a8\xab)\x0e\x96wFGQ\x94l%\xf4q-#$9\x84\xcaES U\xa3\x14\x1c#\x05iBI\x1cv\xa9\xc2\xda\x9e\xde\xb5\x117\xed\x11D\xf0\x18f\x8f\xf46\xc0\xb45\x9bne>\x9d\xad\xaf\x1f;\xb4\xcd\xd2\xa9\xcdU:\x1f2\xe1S\x7f\x970[_\xef\xe9\x16\xaf\x87\x19\x841\xe4Ho\xe4\xd3\xd91\x0b+\xea\xd4r\x0f\xac\xf2\xe1\x03j\xa2\xaak\xe5\xcb/a\xa3\x19\xbbhE\x1c'a\xb3]\xd5\xa9{\xe9\x17\x0bo\xe9_v\xc1\x88\x95\x84q\x1f \xe9\x11\xba\xcd\xb0\x0dq\x1c\xf8\n6a\x9f\x9e8X\xa7C\xdc\xa4\x97 C)7F\"\xea\xf9P\xac\xbds'\xc0\xaf\x83\xfc\x10\x83\xb8SHbD\x9eM k\x0d|\xb3#\xa2\xf3k\x8dPp\xc8\x0e\x88B+\xc1\xc6\x94\xe3\xda}\xf8\x009%/\"\x14\x87\xf1X\xb4\x9c\x9a\x9d\x80\x8dr8o\xb6\xf0\xb3\xa7I@\x9e\x14v\x8ek\xbe\xb33~\xb8K\xbf\x0d\xe11\xec\xecn\x8d\x1e\xb2\x86\xd6a\x84\xe0\x87\xb6\x04\xb6\xdf\xf9\x98V`\x0d\xecn\x8d\xb1s\x9f6p\x7fk{\x8b\xf7\xcf\xeacGt'a\xc2\xdf2/\xbd\xdc\xc5N\xc6\xb4\xcc\x87\x0d\xde\xcc:\x1d\xe7\x06\x1f\xd4W_\xc1h\xd3\x81u\xd8\xdd\xd9\xd9\xda\xbd\x1b\x08\xef\xdc\x1f\x1c vu\xd8\x90\x02\x8b\x83\x12e~\xa5\x0d\x8a*\xdc\xbd7\x90\x19\x13\x1f\xb6\xc4\xf0\xc5\"K.\x802\xef\x98%\x1dO\x80\x05a\x0eqR\x00R\x00\xa7\x11Y\xd3X~dv\xc1\xa2\xf0\x11g\xc5sB/\x81\x07\xc88\x8c\xb7\xb7\xf1\xdf\xed\xdd\x87\xec\xdf\xfb[\xec\xdf\x07\xfc\xfd\x83\x9d\x0eg\xb1\xbb\xe9\x08\xaefHg\xbd\x84\xd4\xaejgd\xd2(\x99\xc6\xf6\xe8\xbec[E\xc2N\xd5\x91\x7ff!\xdbi\xfdlQVn\x9d\x82\xfc\xda\x1eX\xd3\x04o{\xf8\xf9\xd8b\x0c\xd7\xfd-\xc7\xe6\x14@\xed\xc9\x00UCV?mU\xb5\x89\xe9j\x90l\xa7\x90i\x1dK\x1ah\x0c\xa94d-\xe4\x85\\\xa3\x1c\xfe\xa6\xc32\xac\xd8\xa3\xcdQ\xbf\x0d\xf5}:I\xb5(\x9f\xae\xe3\x03\x87Y\x1e:.X\xbe\xd2\xfe\x10\x83ik{i\xf7\xd6)l\x99\x088\x9e_\xaf\xc1\xa0\xf9KDK?\x11\xa2\xb8;0)\x0d\xbb4\xc4\xd5\xf8\xa8s\x0c\xd5z0Le#\x9d\xc3*\x02\xb6\xcdTG\x02$\xd8\x86d6\x13U\x89\xf3U\xf5\xa7\xd2\xb0\xe9\x1bE\x1e\xe5\xf5|\xf56\xd7>\xcep\xdb\xf8\xc6z\xea\xc7\xff\xb1\x80Y\x12\x9f\x93\xac\x00\x0e\xe9E\x02i\x16.\xc3\"<'\x8c\xcdZ\x95\x9a\xef;\xf3\xdb\xbbm\xc91\xc3\xc6\xe3\xed-%\xcd:RJ\x15Z\xec\xd3\x03\xc1>\xdd\xff\xef\x99}\xd2\xb0\xa5\xdb\xbb\xea\x95\x1dw\xc48>\xc7\xca\x94 }~p\xf2\xe6\xed\xeb\xa3\xd7\xed\x80\x15e\x9b\xdfo\x16\xb7\xc5\x01\x9d\xf58g\xb9+\x0b\xde\x15E\\\xe1<3D\xc6@+\x0c-5\x84$w\xe1\xa1S\x90\x17\x84y\x1a\xf9W\xf4v\x88\x93\x18\xf3E\xdb\xe3\x9d\x11\x9a\xf5\x938x\xba\x08\xa3\x00Y\xb7\xc2\xcb3\xcacX?\xf9\xe7>\xf3\xe9\x9dXU\x16J\xee\xfb\xf7C\x18\x07\xc9\x85\x17$3\x14\xa18^\x92\x92\xd8F\x18\xb9\xc8\xc2\x82\xd8\xd6W\xec\xd3\xc7\xa2\x8a\xf7\xcd\x1eC\xd1_\xfdx\x8f\x17\xa1j\xd7\x9bEI\x8e\xe9\x0ds<\xc1\xdf<\x82lc\xe3\x91\x03\x01\x89HA \xaf\x01i\x1aN\xb3c\xbdMYn\xb7`H\x8dI\xf9E\xc1,8)\x9dfD\xad\x889\x95tF\\F\x11J\x90)\x15g\x97-x'\x0ecpcrA\xf9\xbef1s\xff\x8aYZ^\x82\xa6g\x98\xd5\xc2qei\xab\x90p%v|+\x9a\x7f\xa46\x1e\xec\x9c\x08\x0e\xf9\xdb\x0f\xf4\x94\x1f\xbd\x98\xff{\x90\x1d\x8cF\x0f\xd4d\xf1\xb8\x8d\xa0\xb9\xf0`w\xd7\xb1\xd7\xda\x02\x075\xca\xb8\xc1\xfd\xce\x97\xa8\xe4\x84t\x17\x17\xe0\"u_Sfiz\xacX\xf3\x98\xf2\xd5\xa5\xc3\xa4\x04>\x8a\xf31%<^\x9b\x91\x88,\xa4\xf8\xf0\x11\x14BX\xcb\xf7\x03\xbf\xa3\xa8\x01w\x83\xb9\xa8\xfc\xa7\xd0\x8e\xb0\xb5\x0f\x1f\xea\xd6\xd4[\x14\xddt\x8b\x1e>\xd4\xac$\x83N\xdb\xfa\xd9r\xd0\xd5\x82\xd2\x81\xcf\xf3\x83\xb8\\2\xbe\xc1\x96`\x18L\xe6\xd1\x82\xd2=\xac\x93\x83\xd0s\x8d\xe6;y\x1a\x85\x85ma\x8e}\xde!\xb9\xf9 \xed@\x95\xd0ti.\xa7m\xdd\xdc{'\xd3\xe0\xd6\xff]T\xf5\xdf\x92\xa8J\x83\xb2\xb6w\xdb\xef\xc3\x01\x94\x8c__\x94\xd5\xc5e\xbcN\xcfH\xf1FT|=o^\xab\x1aX$\x02\x9d\x01fp\x0e\xf1dMQ\x1b\xad\xa2\xf0)\xa9\x90\xc4y\x91\x95\xb3\"\xc9\xd0\xe4 \xc28/\xfcx\xd6-\xddo\xfe-\xdd\xbe\x93\xe6g\x1c\x0f\xec\x83\xdf6\x00_q\xfdw\xb6nz&9\xfe\xc8V\x17XT\xf7'g\x1f(;P\xb1\x0c\x0f( \xcd\x98\xca-\xc7\x15\xde\xf0[\xfc\x82E\xc6\x80'\x8f\xb5G\x9bc\xc7\xe5>\xb5\x94Z\xc0\x83\x1b\xb5\xb8\x05\xf6\xaa!kp\xd1s6\x17\xba\xb3\xa0\x13m\xe1\xe9\xe1\xe1\xdb2\"/\xc2\\\x11\xec\xe0\xe9\xe1\xe1!%M\x9f\x91Y\xe4\xb3x\xd3\xdd\x80 O\x0f\x0f\xd1\x14\x817\xd1.\x8dB\x12\x17o\xc9\xacP\x97?{\xfd\xd2X\xc8\xe6\xa2->J\xde\x93X=\xf8g~\xe1\x1fe~\x9c\xcfI\xf6\xbc Ku\x1b\xdf\x84\x91f\xe4\xdf\x1e\xbd|\xf1$\x8a\x9e&Q\xc4\"P\xa9\xab\xf4\x95\x7f\x93dK\xee\x85\xa4\xae\xc0\x9c%\xb4U^\x92 \xf4\xd53|\x19. e\x89qs\xbb_\xbe\xf2\x97$x\x95\x04\xe4\xa5\x9f*J\x93@\xb3\xebo\xfc0\x16\xe1O\xd4K\xf3&*\xcfB\xc5|\xd9{\xcdp\x0e\xbf\xff\xd3\x0b\xbc\x8a\xd4m\x1e~\xff\xa7W\xe5\xf2\x94d\xda\xe27\x98%X\x03\x0b\xb4< c\xcd\x80\x0f\xbf\xff\x93 \x90\x0e\xbf\xff\x13\x83\x94$\xd3\x80\xc9!f\\\xfb\xba\x9c\xcf\xb5\x03\xa4\x07\xe5pAH\xa1^\xd5#rY\x1ce\xfe\xec\xfdS\xddQ\xa9jh\x8a\x93rV\xad]Ur\xed\xa2+zb\x07\x945a\x94\xf89|\x05\x0b\xc1s\xc2\xf9\xfa\xba\x8aZ]\xba\x18\xc9~1=W\x18\xbcQ&4\x98\x9e)JN\x91\xacW\x95\x9c\xc0\x1e\x9cR\xa4\x7f\xaa\xba\x90\x80_\xc5'H~\x9e\xd0\xfb\xf7\xc3\x07(\xed\x13\x17f.\xa4\x8e\x0b'\xd3y\xfdn\xee\xc2\x19E~\xd33\xca\x80\xa5.\xa8\xe2\xd2 r]\xd2[=s\xe0d\xba\xc4\xcfC\xfa\xf9\xd2\x85l\xba<\xae\xc5\x9b0\x14a\xf7\n\x804J\xcb\xed\xfbj\xbe\x03\x11w\xe3\xbd_Q\x94:&n\xbc\xbd\xfb\xefv%\xff8v%z\x82\xef\xbec[e\x9c\xcf\x92\x14\xbdU\xda$\\\"\xfc\xf5T\x07\xa6\x123@2\xcd\x8e\x99R`\xe7\x01\x1a\xaff.\xfc\xa2\x97\xf6u\x98\xfaiv<%\xf4\x18\xc9\xf6\xf0\xca\x99\xe8$\xfeF\xd8\xfb\x0c\xed\\\x84\xb1\xa9/(\xa9\xf1v[\xc2\x92W\xc4V\xe35\xa7\xb0\xc6\xaa\xb8%*\x8d\xcf\x9c5\xdf\x16\xd4\xb0p%\xf7\xb7[\xaf\x03\xdez\x1b\x85,8\ni\xd7?\xe7\xef\xdb\xf6\x10K\xd6\xebN\x1b\xb5\x9c\xf1\xf7[\x8e\x97\x93\xd6\xba_\xb1\xb6\x1elvb\xe1\x9dr`m\x8f\xea\x84\xb7\xd6\x1e\xd5\x05\x7f\xdf\x1e\xd5\x01R\x9a\x95\x8c\xbeYx\x89\x85i\x96\xccH\xde\xf2D?\xc4\"\xae\x98k\x16=\x85=\xb0\xf8Gx\xceg\xf6e\xab\xd7\xf7f\x89\xee\x13\xb4\xb0\xdd\x83So\xde,xM\x0f\xc4\x9aY\xda[dW\x1a\x9eW\xe0\xc8C/#y\x12\x9d\x13\xbb\xbdz\xf2\x83\x1e\x1aM\xf6g\x8f\x1ea\xa1\x1e\xccS2C\xfcr<(\x1b\x96x\x88\xfd\xde\x85\xf7z\xd6\xf7\xba\xcb\xd2\x83d\xc7\xf0\x14\xfdQU|\x1c\xdf\x8b\xb7\xe4'F\xd9\x1e\x9c\x93\xb8p\x98\x0fK\xb1 \xb1\xfd\xde\x919\xb4\xa2\xd3\xcd5\xcc\xfcb\xb6\x00\x9cCK\xf9\xd6\x06\xbf7\xbdsF\x15\xb5V\xa8\xbcf\xaf\xa5\xf4\xbb\xe6d*m\xb5\xcd\xe21\xd0a;8\x85\xe6h[\xe0r\xd4\x87\xed@\xe8\xb9\x88w\xa2\x95\x88\xd02\xc4\xb7\xea\x0d8\xe7\xb6\xcb\xc4;\x99\xa9k\\\xe95\xaa\xf2\xd3\xe0.\x89wr\xcex\xcb\x11`\x8c\x9a\x93\x9c\xb1\x97\x9b\x8c\xb5\xac\x05K}p\xc5\x85\x995\x02M`\x1f\n/y\x0f\x13(\xbc\xb9\x1f\xf6\x84@\x87*A\x14?\x1c\xfd\xd5#^\x9d\x02\\\x7fm\x9649H\x96~\x18\xab\x17P<\xfa\x13,?%\xa5?\x124\x1b\x19\xf3\xb5[PP\xf9 \x89)\xfck\x0fF\x8e+\xe2\xff\x94H\x81\xec\xa1I\xb5\x8d\x81*f\x1e\x89\x0b\x92\xd9\\\xa7P\xda\x19\xf2\xe8\x98\xa1\xd8#\x97aas\x06\x7fm\xd3au\xf6\xd0\x1b\x81\xdbX\xefCd\x1f\xd8\x16?w\x1b\xb3\x85\x1f\xc60\xbb\x9aE\xc4B\n\x08Ma\xde\xd8\x14\x82\xf7!d\xda\xd2\x18\xfdK\"Z\x9cc\xc9\x04\"[\x91\x1dP~\x1a\xe7\xb2wYp\xfck>\x9f\x1f\x9fDd\xf7\x84\xdf\xbc6\xe0#\x88k\xd9t\xf8\xc8\x01\xdf\x8e\xa7\xe1\xfaz[9 ?\xf4\x90\xa0\x90\xdc\xad\x8e\xd5\xc8\x05\xd42\xaf\x89}z\xa9\x1b\x93\"z\xe6\xb5\xe9\xf8\xbf\xec\xc5Egl\xf1s\x03\xfd,\x1eD[(\xc4\xe5f\xfbxB\xb5\x13\xa5[\xfc\xbc\xa3\x80\xa9J\xe7\x14\x08(|\xc0C\xe0\xf0\xa3c\xea\xed\xa7\xde\xdeV\x85_54\xca\x80U-\xfa\xb7l7,\x01S\x05\x87\xa9\xaa\x02\xdf.v\x0b\x9b\x92u\x0e\x00'\x01J\xf4L\x0d>\xfa\xc6\x9dz\xd5\xbbv\xc2T\x8er\xaa\xddu)\xbc\x93\x00\xaf\x10\xfcA1\xbd\xcb\xd6\xa0\xf0N.hA\xe1x'\x94\xa2\xa7d\x85wB/\xc81\xfe\xf2\xc5W\xccG\xfdd\xc6\xed\x0d\xe9Eqd\x17(\xc40\x8e\xfc\xed\xb0\x91\xbb\x15o\xaeV\xf5\xac\xc5\xdeI\xa0\x03\x86\xb8\x9e\x14*\xcd\xf9\x9c4\xd7\xaf\xf9\xda\xa5\x9d\xb1\x1b\xb0:X\xf5\xe5\x073\xb4\xec9\xa5\xa7\x19\x89\x87\x00\xc2\"'\xd1\\\x97?\x8f>\xb8\xceo\xd0\xbcj\x7f(\xf1\x04\x12\xaf\xde\x7f\x17\x9e\\L\xc0\x90l\xb1\xaa\x16h\xd3\xb2\x8aGC\x95\x8bg\x18\xc5\"\x0c(\xe9}\xfc\x16/\x98\x11\xde\xcd\xaf\xf8\xef\xbb$\x03^\xb1\xbe\xb2\xde\xc0\xdb\x86\x9b\xdf\xa1wL\x05\xfe1\x03\xff\x11\x85\xef\xd8\x855\xddx\x87\x8d\x93\x8f\xcf<\x91\x01\xfb\xd7\xb3w\xd7\xda\xf9w\xe7\xdd\"2\xea\x1d\x7f\x8dg\xfd\xd0x`\x17<\x82\xe7\xa1\x0b\xe2PX.X'\x0b\xcbq1\xd4\xa9\x0bY\x9d\xc5\xbau*\xd4\xe0Cl\x04\x13\xd6n\x05)\xe2\xcf\x16r1.\xfa\xabf\xfe\xec\xe6\x97\xd5_\xd7.\xbb\xc4\xf5\x93d\xd2>A\xd9\xb1\xbf\xe4\x9b\x97\xbd\xc9e f h?\xfc\xeb\xbcSy!Wf\x84b= \xa7i\xdeco?\x189\xf6\xa1l[\xdb\x1e\x1f\x89\x07\x84\xfa\x17\xac\xdc\x13{)v\xcd\x9cS\xfc=\xec)\xd9T\xa6\x7f\xc6\xb3A\x19\xacf\xad\x9a3G\xba\x97br\xce\xfd \x19C\xefb\xfe\xe7\xa4\xb5&\xb3*\x07U\xb5\xc6\"Y\xcc\x89\xdf.\xcbi\xd9\x11\x9f\xc7\x1a\x05\x93Xp(\xcd}n\x9e#\x04\x97\xbe(v\x92\xc5\"\x13!\x88q\xeaa\x88kG{\xe5\xd41\xb9\x80\xecQ\x17\xba\x04U\xc8n\\\xfa\x86\xdf(\xa8'}\x8b \xd5GNU\x84Z\xe6=v2\xb0D\x86\xe6SoNwy\x88\xb2\x98\xe0\xcdv\x88\xdb\x89?}JA\x93\x0b\x16\xf4m\x82\n\xf5\xc6$\xe7\xf6\xdc\xfb\x13\xac\xc3\xdc\xfb\x01\xff\xff\x0d\xfc\x11\xd6^\xb7\x01\xf2\x8d \x8a\x0e\x1b\x1f3\x13S[\xc6\x15\xdc\xfe}\xec\xd8\xf2+\xa6v\x90L\xe0Y\xc7\x87\x8d.%|\xd3\x9e\x1b]\x9e\xbeM\x16\x04\xd2\x13\x15f\x02I\xf4\xb4\xe9V\xdc\xbe\xc3\x14\x16j@\xeb\xacS=\\\xbb\xa4+\xbc\xf6\xda1\x8e\x1a\xf7\xbbo\xd8|T\x17v)\x0eG\xb5o\x870\x81>\\\xd7\x19\xda\x9a\xfd\x9a\xc9\xeb\xb7\x1fl\x99\xa2\x85\x1ez\xcc\xea\xd9\xc3\x13d\xbf\x97\xc1\xc24-?\x8a\xfa\xa6$\x93\xaa\xea[\x8fa-\x9d\xf1\x10\x8b\x86`\x14\xdf$\xbc\x8a^d\x13\x0e\xe7T\x05\x1e\x9d\x1a\"4\x03o\xd2\x90$\x1f\xb8~m\xa4\xa7\xb1\xce).\xa7\xd7\xc8p9\xeb9\x0f\xb6\x14\xae\xaf\xf7S\x80\xe8!a\xe8\x1f\x90\x98F\xcc\xcbP =\x9b\xeb\xebn--\xa3\x10\x81(r\xf8\x08\x01;\xa6\xa4E.\x88\xf4iy\xcc0\xdf\xc6\x062\x18\x99\x1d\xf7Q\x85Z\xa6\x198\x98KM)\xeb]\xeb\x8f|\xe8\xa1-Ub\x87\xde\xf9\xd0\x8b%\xf3g\xbdg\xf7\xae\x00]\x0f\xc5\xc9\nP\xbc:luw\xbd>v`\x90\xe6i\x93\x08jw a;\x90\xd9\x89i\x07$\x14\x84?o\xa4\"dB\xaf\xf6\xd4\x91\xc7\xb4\x1b\xb6]\x05\x8a\xed\xb9\xaasmo\x0f\x98\x84\x07\xc2\xb8f\x0dk\xa7\x8f\x18\xd6\xc1\x9a@\x18\xcf\x92,\xa3\xb7u\x18\x9f'34K\xd2\xb9\x9a\xdd\xdc\xbe\xb8\xa3\x02\x14z~\xb5;\xf7\xf6}\x95\x9f\xbc\xc2\x86\xbb\xe4f\x01m\xcdc\xce\x9bi\xdb\x02F,\xb0W\xe3\xdd\xac\xe5C\xc2u\x1c\xa6\xdd\x98\xbb\x90\xaa\x08\xa8\xc0\x85\x85\x0b\xe7\xae\xb0\x07Ia\xbf_2\xd4Y\\\xf1\\\xa30Ze\xff|\xc5|Fq E-p\xeb\xd4;E\x13\x96\x0e\xdc(I\xe6\xb3\x9b\xfa!\xa20\xd5>sT\xf3C\x9dJ\x802|a\x9d\xe0<\x82\x00\x1e\xc3\xe9#8\xd5Y\x9a\xa2\x95\xe9\x92\x07\x8c\xbd\xb2}\x9b2#dzz\xecL7\x8f]XLG\x18+\xf0\xca\xc6wN\xed\xa7\xba\xc4\x9f\xb3\xca\x0cu\xd9<\x8ej\x13X\xa6\xf7\xc1da\xdcq\xea\x11\xaca\x97\xe7^L.\x0b\xdbq\xbc \x89\x89\xc6\x1a\xb7\x1alb\x9f\xbbp\xe5\xc2\x82\x07\x82\x82b\xd8\xd0\xae\x1d\xef\xeb\xb7\x07O\xfeL\xc9ezq\xbd=8z\xf7\xf6\x15\xec\xc1l\xb5C\xb6\xd3o%-\xe07\xe90\x90JFW\xe0:\xd8\x87\xc2\xa6\xf7\x14.\x7f\xcc\x97\xbfh_\\\x15\xafk\x8c,I<\xd6\xacB\xe6\x87\xe0'\xe1\xaf\x90\xa1\xd8\xb0rhs\xdb\xfa\xc6?4\x7f\x0d^\xab\xae!QR\x1b\x99Hf\xa0M@7Y\x98\x0c3\x1f\xe1+*\xcd\x11\xaf\x11;cv3L\x8c\x87\x86W\xd3\xe4\x98\x0b\xf5n&:\x8d\x1c/a\x98\xc3NuY\xa1f\x0b?\xf3g\x05\xc9\x9e\xf9\x85?Q\xba\x94q\xfb\x9c\xde\x85H\xbd\xc0/\xd0j\x8aNe\xde\x03\xdfJ$\\\xf5\xa1\x9a\x85'\xde\xdc.\xd0TOA\xf0a\x82\xb4\x12\xb9\xe0\xaeK\n\xac\x1aX\xa5\x90\xe3M\x88\xa7u\x14nLo\x18\x89\xfc\xa4%U\xed\xde\x7f\x82Y\x9b\xde?\x9ef\xc7m,\x1br\x16\xae\xef\xec'M3y`\x13`,\xd4\xac\xd3q H\x04\xe3\xaaB:\x1d\x1c\xc5\xd3\x12t\xfc\x01\xb8\xf3C#t\\fg\xde\x1bX\x87\xcc{kP1\xcd\xc3\xd8\x8f\xa2\xab\xa1\xd2w\x9f+\x8d\x93*j0\xe5\x88\xc5\x1f\x1a\xd1{\xacSr\xab\x92\xd9\xb4\xd5\xc7\xb1,\xa7\xd4\x1ab\xf3\xcfJ\xcchj;m\xbd\x8a\x89\xcc\xeal\xb4\xfc\xa8\x8c\xcb(\xebF\xa9\x8b\x8f<.\x86`V\x1b\x96^u\xf9\x11\x81\xb7\xebP\"\x02\xf7l\xb7\xc0\xf1\xd0\x00\x88E6\x18\x08\xf1\"\\\x84\xb9\x01\xdcB\xa5}\xad\xd0J\xc7\x1eACwn\x0b0\xa9\x953\x8e\x1d\xa3\xd2\xa4_M=dAc{\xfb\xc1}\xae\xa5\x7f\xc0\xff}\xd8\x8cj\xc7\xc3co?\xe4Q\xed\x1e\x8a\xf7;\xfc_\xfe\xfdC\xfe\xfdC\xf6\xfd\x0e%G\xf0\xdf\x11\xffw\xcc\xff\xdd\xe2\xffn\xf3\x7fw\xf8\xbf\xbb\xfc\xdf\xfb\xfc\xdf\x07\xfc_\xde\xde\x88\xb77\xe2\xed\x8dx{#\xde\xdeh[\x19e\x8f9\xdb\x0eY\x8b^0\x1aw\xc2x\x87U\x90J\xbc\x92\x9f\xf2\x10\x8f]\x94(WJ\x02\x82\xfe\xc1-\xc8CD\x88\xe6\x04k\xcc\xd0}\x84\xf1V\xaa\xa0\x19Ul\x91\x0e\x82\x94\x1b\xed\x83\xd0:o\x9f+\xb4\xdc8\xe9n\n?_$\xed{\x0c\xbeVL\xc0\xa2\xc2\xed\xc1z\x9d\xc8\xcf\xc78; \xc5'\xa3\xd1h{4\x1a9\"v>C\x18o\xfd\xf8\x8c\xebH\nYG\xe2\x03\xa6\xb3\x84Y\x12\x10H\xe9dtv\x96\\i]\xc0W,\xba%\xecc4 \x0cy\xca\xa2_\xae\x83m\x17\xb0\xb1\xc7\xca\x1dx\xfc\x18\x10~\n\xf8\x0f0\xda\x1co\xc3:\x8b\x99\xd9\x9b1\x17$\xfc\xcb\xb3\x0c[\xb7\xc3a\xbd`\xa6\x8b\x1b4\xda\xdcR`+\x0dPd\xfe\xc5pP`\xb15\xbc\xcc\xbf\xe0LiX\xcbnM\xe0A\x81\xa7d`\x12\xc3c(\x1f9\xc0-\xb9x\xe4\xd6bZ\xae\xaf\x1f;\x18F\xe2+&kiV\xa8\xc1\xa6<6X\xab\xf9w\xb3\xf4\xea\xeb\x83\xe2\xacM\xc7\xb6\x8a,\\Z&\x85y\x9b\x9bV-\xaa`\x059\x15\xb2u\xbb\x01\xf7\xc2\xca\x8e&\xd6\xdf\xa6:\xbc\xd4\xf6\xc3\xf6{\xba}\xd6\xd4\x82u\xf0YD\xce\xaeXS$\xdb\xfa\xff\xd3Z%\xff\xcf\xfac\x9b/\x8a\xea\xaau\xa5/\xda\xb5f\x03\xb8o\x90\x85\x12\x8aT\xb2\xc0\xc7\x1d\x0e#S\x04k\xb2\xe6O\xc9\xb1\xcd\xbc\xf3~\xfb\xf5\xff\xf8\xb7\xff\xc2\xe2\x9d\xf2\x9fX\xa6l\xe3Zs\x8b\xd3\xb5I\x98;s\x89J\xbe9\x86\xe3\xed0\xca\x807\xfe\x97_\x82\x9dLcZ;GWnA\xfbR\x94_\xca\x07\xb9e\xf9\xd2Z\x809\xec\xc1\xcc\xa3\xb0\xda\xc7\xa0\x81\x04\x8er0eT\x05\x8e\x803\xef6\xe1jE\x96]-w\xc1\xc2\xbc\xeccM\x85HTh\x11\x1ej\xc1\x82Z\x0b+\x8fT\xaem\xfdX\xfc\x18\xffx\xfe\xe3\xfc\xc7\x0c\xfe\xed_\xff\xeb\xff\xf5\xeb\x7f\xfd\xd7\xff\xf3\xb7_\x7f\xfd\xed\xd7\xff\xfc\xdb\xaf\xff\xc3o\xbf\xfe\x8f\xbf\xfd\xfa?\xfd\xf6\xeb\x7f\xf9\xed\xd7\xff\xf9\xb7_\xff\x97\xdf~\xfd_\x7f\xfb\xf5\x7f\xfb\xed\xd7\xff\xfd\xb7_\xff\x9f\xdf\xfe\xf3\xff\xfd\xff\xfe\xfa\xeb\x8f\xe5xs\xfc\x00\xff\xff\xf0\xc7rN\xe6sk\xc8\x19\xbb!M9\xde\xde\xc1(n-vF\x8f\x91g\xe2\x8a~\xd2{I\x0b\xd5q\xafm\xf3 $r\xc3 \xea\x02\x8a\x8d:\xe1%(n\xb1,\x8f\xc4\x01\xe6_Q1x\x14\xc8\xe9\xa7[\x8em\x89z\x96\x81\xa6\x11u\xfaVJ\\_\xa1X*\x17\xe4\xf6\x95\xe76V\xdcg\xf0\x18F\xb0/\xa5#\x1e\x1d\xd7\x06\xcc\xcaV2\x96\xf1\xc7\x1c\xd3\xacl\xe9Iy\xee\x1b\x11\xf9\xddN\xd0\xe493 \x18~j\x0d\xbc\x82O\xc7\xcdM\xe1\xd1\x0f\xb3DM \xf7\xdc)a\x03\xeaK\xbbd6\x15\xf9\xef\x02O\xf7\xc7J\xde_\x06\x8d0\x9eEe\xc0\x82]\xe8@C\xd4\xe9\x03\x8d\n\xed\xff\xa7D\x02\x8e\xba\x07\x0fS;\xbd\xc6\x08\x91\xab\x80\xc3\xed\x0ecc\x99\x06\xe3\x8e\x8c\xa4\xc4/&x\x83\xef:+v\xd9\xb7_\xa3\x91\x96\xb6\xb8\xa9\xb4\xb8\x0e\xdcO\x99`\x05x\xa3\xc0E\x91\x89>\xe4\xf1P[\"S\xf48\xe5a\xfaC\xd8\xdb\x83\x11\xdc\x83M\x05Ca=M\xca\xb8\xa8\x1d\xb7br\xe6\x17\xe19is\x12\x0f/\xc9\xdd\x0f\xbd(>\xc9\xd8\x93\xb8\x98%\xd1\xc78\xb2\xb4i:|\xd1\xfc\xc7<\xb6\xb4\xaf<\xfc\x99|\xbcY\xf0\xd6?\xe6$\xc2\xc2\x8f\xc2Y\xbe\xd2\x1c\x86L!\xfc\x14\x80\xb42\xf2\x19\xb4\xfa\x88\xf6\x17\x19\x99\x7f\xe4\xa5\xcf\x97~\x14\xad4\xfc!\xa3\x17\xad~\xf4\xc5\xa7\xef\xdf\xaf\x06\xfc\x83\xc6/\x9a\xfd\xf8\x13(O\xef~\xf4\xe5'\xc1\xfey\x99~\x84\xa1\xa7w4\xf4\xd8\x1e\x8d)\xb9\xbc\xf4\x8b\xd9\xc2rad\xae.\x0dfZ\xd5S\x8a?\xd5k\"\x1e\xc1\x19\x10\x93\x921\x91e\x0f(z\xa8\xd2\x99\xc5\xd3B\x9f\x19C2\xafO`_\xd8\xe11/\xaa \x9a\xc0q)o\xecL\x8bc!\xc8\xcf:qA >\xbe\xe1jrQ\xa3\xe5\xc2\xf8\x06\xeb\x99)<4`\xd0\x92\x86}K\xea7\x964\x93\x974\x1b\xb8\xa4\x12?\x91a\\\xb3\x04W\x95\xbd\xe1k\x19:,N\xd3\xdd\xadhN\xfc\xec\xdf\x01\xf4\xee\x963\x8d\xc2B \x9e\x1d\x03K\xfd: \x0dGl\x8fw\xda\xbe& D!\xdd\xd7L\xef\x86J\xb4\xae\x90\xc4\x9a\xa1\xf1\x8a\xe5\x9f\x9e\xce,\x9ew\xe2\x9e}\xea\xfc\xf1\x9eC\x99\xe3\x0f\x1f`\x1bu\x1e\x05\xc9\x8b\xba|\x7f\xe2\xdcsac$\xc2:\xd1zc\xac\xe7\x9f\xca\xb5|lH\xaa\xc4\x1a\xf3\xea:\xde\xbeC\xffkT\x92\xcb\x1d[*\xa3\xdc;-\xaf\x8a\xbd\xfd\xaaP\x05r\xe7\xdc\xf7Y\x12\xa8\xde\xb3\x9d\xfd\xfd{\x1e\xb9$3\xdb\xb2\xe8\x1c\x15P3DO\x02\x92\xad\x9a\xd0]\xaa\xe3\x06@\xd3'gOx!\xf14<\x95%\\;\x95\x8a\xfc\xedZ\"\xa7_\xab\x83\xe8\xe1\xe8\xd4\x9f\x9d3K\xff\xdc\x85\x08\xc3T\xcfY8}\x93\x93z\xc0B}\x86gq\x92\x91\xa7>\xc6\xf6\xb3B\x0b&\xf4\xda\x83uZ\xb6,\xa3\"\x8c\xc2\x18\x8b\x96\x8d\xa22\x0eQ\x11\xbf\x0fV\xd9(\xc8\x8bp\xf6\xfe\x8a\xbe\xbf\xe2\xef\xf5CX\x98}\xe4\xcf\x9b\xbbY\xc0>l\x8f\x1fn?\xdc\xbd?~\xb8\x83\xe6\xfe\x8f\x1f?65\x80\xd1g\xeb\x03O\xbc\x1c\x83\xa3\xbb\x10\xc0:Xg:\xfb\x01\x94\xfea\xd0\x06t\x8e\x90Z`J\xce%o\x876\xf2\x85\xbd\xbf\xf6\xe3\x8f\xb9c\xb9\x10\xa84\xd4\xd5\x83\xfe\xeeK\x06\x8b<\xbe\xe7\x9amG\x18y\x0cE\xcd\xb0\x0e\xf9t\xf3\xb8\x82\xf0\xc7\x80\xf1\xd5\xec\x94\x07?\xe12\xa5\x85+>p\x1c\x17\xd6\xd0\xb6\xbf!\xf1\xc2\xa4!\x9b\xc7\x95F.s\xcd\xe4O\xe3\xc1\xa9\xcf1.\x01\xcc\xe1\xab\xae\xe4{\x03\xc6\x8f`\xbe\xbe\xee\xc8;S\x8b\xd8\xe6h\xe8k\xe3\x8f=\xa5D\xbc\xf1\\;nw\xf0|9\xbe\xaaC0\xa2]\x00s\x14J\xe9\x07l%F\x0e\xcf.!-\x1b\x8b1\x1f\xb9\x90V\xad\xee\xc1\xb9\xe3|\x00\xbec,\xa3O{\xfb\xe8\xa0\xeb\xc1\xc19\xecC\xca\xcb6]8\xc7O:#hY.3\x8f\x06kS\xa0F!\xd3\xdct\xa4\x15\xb3\x07a\xb6\xe6\xa5\xd9FW\xb0\x0f\xd3c\x98\x08\x1cT g\xdb\xdc\xa0Z\xcc-\xd1\x08\x1a\xa2\xeb\x06d\xd5\x8d\x08\x01\x89\xac\x8ak\xb2*\xeb\x90U\xb1\x8a\xac\xcaV\xa5\x03\xcc\xf2\xfa\xd4\x8e\xed\xedQ[\xec\x9c\x88\x92q\xbb$\x14%;\xed\x12\x9f\x97\x8c\xee?h\x17\x95\xbchgk\xb3]\x94\xf3\xa2\xadNO\x11/\xb9?\xden\x17\xcdz\x03\xf7U)\x98\x88wrB\xf2\x97IPFD\x97C\x14$\x99\xff/\nW\x10\x8c\xbb\xc7r\xe2\xe9B\x99\xd5\xf9\xdex\x0c\x86v\x8a!o\xe1\xe7\xaf/b\x91\xbe\xb5\nC\x17s\x95\x0d3\xb6 \xdd\x84oP\x83\x10&\xa6\xf3\xcb\xa8\xe0\xa1\x99\x9a\xa0A7e\xbb\xb3Ts\xae|q\x1e\xfd\xa1z/\x96\x0eR-\x8b\xdaY;\xcc\xf4<\x18Y\xa3.E\x92\xd6Y0\xde\xdd\xd9\xdd\x1c\x05-E\x1b\xbdv\xad-o\xf4\xc0\x1b\xb7J\xe8}j\x9d\xfa\xf1OI\xab\xe0\x8c\x16\x1c\xfa\x85\x0b\xe3\x1dxR\x9e\xc1xs\xf4\x006\xefOv\xc6\x93\xf1.\xfc\xe9\xe5\x91t\x10\x86\xe9\ns\xb1\xf4\xde9\xc9\xf20\x89s\xbc*;/?|\x80_\xae]E\x89\x97_\xf8gg${\x17*\x9d\x97x\xb5 (\x02\xdd\x9e\x85\xc5[r\x1e\xb2\xf2\x85\xb2\xfcY\x98\x15W\x13\x08\xba\x85\xa7e\x18\x05G\xe1\x92\xe4\x85\xbfL'p\xd6\xad\xb2\xf4g\x8b0&\x93v\x0c\x85.\x07Ph\x1d\xaf\x82dy\x12\x06,\xcf\x94\x1ao\x06\xc9\xf2U\x12\x10S\x95<%\xb3\x89\xde\x88*\x8b&J5,/\xccMMG\xfeUR\x16\x13\xb0\xbe\xf6s\xf2\x02\xff\xd0\xb4\x14$\xb3\x83\xcb\xd4\x8f\xd9r[Q\x98\xebj.\xfd\xcbg,\xf5( \x8e\xfc3c\xff\xf30*Hf\xaa\x81\xe6\xa4~\x91d\xefp\x9e\x8b\xa2H\xf3\xc9\xbd{IL)^\x01=^\x98\xdc\xab*j\x86\xc5|\x97r\xfdB\xce\xca\xbcH\x96\xfar\x9eO\xf5uJX\xea\xaa\xe7A7\xa9N\xab.\xcfz\xf4\xac\xd4%\xbb\xaa\xea\x13\x92\xbe\x08\xe3\xf7a|\xa6\xaf\x94\xb1\xd6\x9e\xc7\x05\xc9f$-\x92\xacOc[\x7f\xc9\xb0\x97\xb2\x82f\xba\x19\xc9\xd3$\xce\xc9'\xea._$\x17\xe8\xd3M\x02\xbejj\x073\xa8q\xeb\xcb$ \xd1[\x12\x07$\xc3u\xb3\xc8\xa5\xbfL#\xa2\x83`\xe9+\x04\xe5\xe0\x19I\x8b\xc5\x04\xb4{R\xd7\xcf\x87|@\xa7ppY\x10<#\xb9~\x1fi\xbd\xa7\xc9r\x99\xc4\x83j\x97)\xc5\xc3$8,O\x97a\xc1\xa2M\xe4\x13\x98Zg\x04\xd5.i\xc9\xfeIr\xfc\x97e\xd1\xa5\xbf\x92\x94nU\x8e\xfa\x01\xe2\x07X\x89\xcb8\xad\"\xf3g\xc4\xd20\x9eiFrR\xd0>\"\x81\xb0u51C\x17\xad\xa9\xa9\x10\xc6a\x11\xfa\xd1!\xddX\xfd\xd1\x9a\xc7\x86c\x99,\xd3$\xa6|\xcb\xa4\xed<\x05jp\xa2\xfc?%\xd3\xe7^\xeag99D\xb9Y'M p\x82\x89x\x1c\x057\xf1:OF\xac)\xa5X?\xe5\xdd\xf8b\x8d\x1c\x9b\xdeq\x05\xd2\xde\xb1\xa2\xb7+\xed5\x91_\xe5\x05Y\xaa\xc8\x08\xf1T\xd8+\xf5\xf8\xcfU\x0eW\xb5M\xa9\xc7\xf7V\x03kl\x9b\xda\xb3\xd2\x8eJ\\\x1ff~U\xd4J=\xf6K\xdd\xb7x\xc4\x95\x90z\xec\x97\xb6\xb2f\xaeP\xdf\x98\xc6~X\x1d\xdd\xc5)\x1e\xbc]S\xaf\xcc\"\xfd84;\x01\xa9'C\x7f\x97@V\xc4&\xe8\xfb\xa4\xa2\xa7O)=\xdd\xaa\xdd\xfa\xbbEZ\xdb\xa7HRK\xfdS\x15\x9a\x078`\xb2\xdc#\xa5\xc0\x86\xb0\x073\xc7\x85\x13/'\x05\x1bCn\x97\x8e\x0b\x17\x02;=\xc1\x99\xe7^\x94\xf8\x01 0\x8fI\x9d=\x9d6\xb5\x16\xd3CE\x7fZ \xf2\x84\x16KQ\xb0\xe9BX\x8f\xb2\xc4y3^p\xd3\x85\xa4S\"%|ck$:.\xd3\xc0/\xc8\xbb,\xb2-\x0b\x07\xd6-|\x91\xf8A\x18\x9fQ\xe8/s\xdb\xca\xcb\x19\x06~\xd1\xd4>L\xc9\xcc\xa6\x83\xc8:\x83\xc0d)\xcdo\x82\xe4\"\xa6s\x07\x0c\xea\xc1g\xaa\x1d\"\xd6\xe8\xf4+\xda\xe0\xc5\xe8\x81#6\xc0\x81\x0b/C\xd2\xa7\xde\x14\x17\xac'i\xaa\x93\x97V\x91J\xb0\xfeI\xa8\x0d\xcd\x0f\x1c0s9\xb2\xc6\xdfK\x92] \xf8\xab\x9b\xd0\x8bR\xab\xe1\xe5bXj4\xc9\xa3\x89P\xe0\xc0T8\xbceL\x06\xd0x\x89`\xf7\xe1\x03\xf04\x1e\"k\xc7\xe1\xfb0MI\x00YM\x07\xc6 \xfc\x0bk\xe5_ \xc9\xf07\xfd\xf8_\xe0\xc2\xcf\x11\xed\x87\xf3\x90\x04\xbau\xe2x\xe8\xa2\x8b\x18\xba\xe7\xeb\x92bB\x0e\xf2L\xa6\xc8~\xbf\xcb\"\xa5\xac\x0d\xe5\x98\x8dM\xee\xbc\xa0G\x9b\x9d\xa8\xaf\xaf\xdeq\xb0Y3\xd6\xf8\xf0\xc1\xd8\x82\xe2\xfa\xc6K\xed\xb2;\x1d\nlo\xc92)\x08\xfb^M\x81\xab\xd8\x90\xd4\xeb\xbeU}\xa9`)\xe8\xa7\x9d\xd7M\x1c\xec\xc2\x01fb\xb0\x8d\xf3\xbc\xa4\xd5\\\xb8\xa0\x87\xf1@r\x03\xba\x96\x91,\xe9\xa5E\x1c2\xe1\xd8\xde\x19=\xe88\xf0\x8ev\x1c\x8f\x8b\xfd\xde\x93\xab|HC\xf5\xcau\xac\xa0\x99\xb6\xf5\xe1\xae4\xe1\xd8\x1e\xef\xdcwx\xbaM\x03\x95\xd1631\xbb\xed4\xb3s\x03\xacnX\"/C\xb3\xa3J8\x18\xdb;\x9d\xc0\xb0\xb5pq\xd2\x9fb\xb3\xb3\x03\xdc\x83\x1b\x1d\xbe[\xfbp\x7f\xdb\xf1\xe6rL\x94!-\x0e\x9cD{\x9bn7\x89\x9d1\xf3\x07\x1f\xdd\xe7~\xe4c\xeeW>\xbe\xaf\x04\xaf\xc3\xab\xe5i\x12\x0di\xbb\xd7J_\x9d\x8e\xb7\x13\n\x83G\xe9m\xe7\xb2\xe4\x913\xda[\xca\x83\xf4\xee\xb4\x83\xf1\xf2\x19\x8c\xb7\x1d\xef\xcf\x07\x7fk\x96\xb1\xd4\xa1;\xed\xf1\x88\xcc\xa1\xed\x011\x81\xf6\xc3vX\xa1\x94{\x87\xb4\x8d\x13x\xea\xd0\xb6O\xc2\xa2\x82\x94\xe6\xfbs\xfe^\x9d9tg\xdc\xae/2\x87\xb6'\xcc\xb2\x86n\xb5G\xc3R\x86\x8e\xdb\xb5Y\xc6\xd0N\xdc\x87\x0b\xbe\x9a\xed\xb9\x1e\xb0%h\x8f\xf1\x92Wo\xcf\xf5\x90\x8f\xbd]\xff)\x1bL'X\xca{\xb6\xe5\xed\xd7O\x04Bj\xbe~\x0d{\xf0\xb4\x9d$\xf4\x0d\xec\xc1\xfb\xf6\xcb#\xcc\xfb\xd9z\xf9\x12/\x08\x06\xd7\xcd\x92\xe7\xd5\xd5\xd1|\xff\x13\xec\xc1sJ.<\xafQz\xb3\x06\xbd`\x02\xdb:Y\x84A@\xe2\xb6\xca\xff-+-\x927Y\xb8\x0c\x99\xbfM\xb3\xc63\xd4\x03y)g(\x9f\xe7\x07q\xb9d!\x91\x9b\x15_\xd0\x1b\xd2\xb6r\x1c\xfd\x06c\x05\xb3\xabvs\xef\xe4Z\x9dd\xc6\x7fg\xa5I\xba\xa1\xa9\xf0\x0d\xecu\xb4I\xcd\x1a?\xeb\x02\xc2\xbcl\xd6\xfb\x1aW\xf4/\xac\xb1f\xd1\xf7\xb0\x07k_cf\x88\xaf\xa5\x8c/\xad\xbf\xbdy\x18\x07O\x17a\xd4R4|\x0b<\x82odvr\xe6w\xce}X\xdb\x83K\xfb\x0d\xf2fh\xd7\xab&\xd0\x87\xc5\xd8\x82\xba\xe17\xb2\xad\xb0Y*\xc2\x93,\xdf\xd7V\xbav\xbcn\xd0#P\x8aA\xae\x9dv\xddkG\x0eg\xa3\xb1]\x03 !\xbf\xb6\xbfQ\x9b\xd3d\x92\xac\xe2\x9biq\xec\xc2\x9b\xaa=\x1e\x10\x92 \xb7\xf9\x0d\xfd\xf9\x06\x9b\xe9\x04\xc0\xbf\x86 \xbcin\xd9\x0f\xbd|\xbb\xe0\xd9\xdf1\xaf\xf1K\xfbe\x0d\x08&\x1d%fL\xef\xaa'\x9b\xdd\x7f\x07{\xf032\xc5\x0c\xea\x1bP\xeb\x89\x9b\xbb\xb1\x88\x06\x80R4B:\x0b0\xa8\xa5F\x94\xfd\x97\xa6\x19\xfcm`l\x80\xaa\xe1=\xb1I\x7f\xb3\xff^m\xe0\x15\xcb\xe2\x02{p\xc13\xd6\xd1w\xb4$\xb1\xdf\xa1\x91\xc4>\xc6\xd7\xa9\x10\x10f\\\xa5\xfd\xbdby\x85\xa7\xaf\x8e\xa7\x053s\x11\xbf\xf7x\x0e\"\xdc\xb4Xw\x10\xea&)\x17\xb1\x89\x89\x8bT\x90\x0d\x93\xba\xc3\x0f\x1f\x18\xf4\xbdr\xe1\xc0\x1ea6uJ\xa6\xd4\xfd\xd2\xe1\x7f[\xad\x06\xfd\xb6\x86V\xd3b\xfey\x88q\xc8\x95\xd2\xf5\xad\xd6\xbc\xb3\xe0\x1fK\x9e\xe8\xb3\xa0CKXj+\x16e\x97IP\x98\x1fe\xf2\xc8\x81\xbf\xa1\xfe\x1d\xc3\x05&\x18\x06\xa60j\xdf\x8d)7\xfe4\xf88=k\x18\xaf\xe0\xc6\x13\x96\xaaP\xdb\xf3\x1a\xd6\xae\x01\x08A\x83\xe5\xf7\\K(0\x11f\xc1e\xaf\xd9\x05\xa2\xec\xda\x17\x9f\xff\xf9N\xfc\x16%\x0cz\xe8o\xbay\xe4\x18\x0b\xdbv4\xcd)~1d\x8f\x98\xdd\x05]\xff.\\\x0b)\x11\x89\xa9\x9e\x94\xff\xc8\x11{\x82\x87\xcd\x17\xb3\x8a9\x04\x7f#v+dSz7-\x0c\xe70l\xce\xaa\xae\xf73nmi\xdb/M\x81\x0d1\x08\x14=N2\xa2\xef&\xc4\xb0\x18IZ\x87{\x92\x92\xd0w\xf2b\x9c\xf3\x8cj\xa9\xca\xebw\xb3\xe1\xf5\xbb)\xf9\xe6\xbb\x9d)6\"B*\xaf\x13\xe0Y\xdajl\xc0SZ\xfe\x9d](\xcd\x03\xce\xfe\x9a\xbe:\x16\xf8\xc2\xae\x8f\xbc\xb8'\xbe\xad\x0d\xe9\x10\xa9\xab\xd2\x1d]+\xa5|H\xf2}O\xff\xf7-\xdd\xc3N.@\x18\x14I5\xa7T^\x8bXp\\\xf8\xa1\x99\xeeM\xce8h\x15I\xe5\xe3\xdd'\x04)0C\xdf\xfb?\xc8M?\xc5\xa4t_\xb8\x94E\x81=\xf8\x1bF\x90\xdby\xe8\xe0_\x87\xf8\xff\x7fF\xae|\xbc\xc3\xde\xfd\x89\xf1\xe8\xbb\xec\xaf\xbf\xf2\xfc\xc6k\x94\xdf\xdc\xc6e-\xe9\xfc-\x15\xc3`\xb9\xf4kD0\x0b\xfc\xbaWR\xf5\x83\x1d4$2t\xc4\xbe\xedc\xaa;\x1fS\xdd\xf9,[\xda\xcf\xed\xf5f ;\x91\xe8\x16Y\\V\x1d\xe7\xbfPva\xe1\xe7\xcf\xf9\x01p\xc3\xfci\x12\xcf\xfc\xe20\xcd\x88\x1f \x9b#(0\x17\x9d\x85\\n\xbd\xeb2\xd7\x0c\x97\x07\xe8u\xd1\xde\xd3\x958)W\xec\xcc\x91\x7f\xe6\x96q>KR\xda\\.LC-\xd7\xa2\x17\x01a8\xe2/\xf5!!\xe4\x91\x03\x81\xfd\x97)!\xcd\xb4\xe65\x12\"\x98\x8f*\xf0\xf2\"\xc9\xe8\xe5\x12\xf3V\nR7\x13\xd3f\xce\xed\x82L\xe3V;t\x05\x0f\x1bk\xc7Ox7B]\xbf\xfdG%;{Ao\xb5\xf5=\xb47\xdf\x87\x17\xf4TM\xd8?{\xdd\xe4\xea-\x04\xfc\x9e\\}\xd3\xdf\x15Z\xe0\x7f\x87\x16\xf8\xc6\x9c=>0\x1a\xb8\x83\x9b\xa0\x19<-\x8c\xe1\x85ZCA{z\x81t\xdc\x9e\x9c\xba\xc3H\xc6\x9799$\x05\xaa\xb1\x8d|\xda\xf7\xaa\xf0\xc0\x9d\x96\xc2e\x1a\x91!-5\x93\xcd^w\x8eJk\xa3\x19\xc3\xdb\x8dq\x84A\xd4\x07$+\xedZ%\x17\xb0\x0f\x976\xa6\xa5\xfc\xb3}\xc9h\x1d\xe3f\x07d\x1e\xc6D\xa8\xa8'\xf07CqH\xf2 \xfc\xb9Y\xe1\x8c\x14\x92\x8a\xfb\x19\xc9gY\xc8\xd4\n_\x98*\xbe\xf2\x97\xb4\xb1\x7f6\xd5a\xc7 \x9f\xc0_\x1b\xeb\x88\"\x96\xe6b\xdakx\xc5\x1a\x98|q\x11\xbel\xc7<\x16\x8c\xda4.\xa3\xe8\x18c\x99\xfdd\x0b\xba\xd3\xfa\xe5\x9a\xbf\xe9\xae\xbd\xdf1,m}\xc26\xb7\x851\x1d\x17\xac\xef\x0e_\xbfR\x04\x01\xa9\xb4\x0c+\x10?\x9cd#\xc7\x8c\xa3\x18=R\xc5\xe0\xa1,\x05\xa7\xc9\xea\xeb>ib!\xf1\xf0L\xde\x9c \x1a\x1d\xbb`\x9f\xda\x9d\xa4n\x9c\xc4\xffN\xf6\xbf9\xe3\xd5\xecb\x089.\xfaRJ\x87X\x987\xa44;\x06\xf5\x8eK\xfb-\x1c\x0d\x1a\x00\x0e$t\xect\x1a.\xfc\xc4\xb5*\xcf\xbb\xc2\x87\x06XIB\x84\xe9[$\xc6c{g\xd3\x91\x85\x0b.\xbcm\xd4cI\xb6^\xcf1_\xe8\xcb\x1aq\xb3\xbf\xfdb\xe1\x82E\xff\xb1\xf8=;\xe7j\xa6\x1a\x06\xd66\x07\xa9\x00j\xe9xG\xca)\xa2B\xa9\x93\xd8QBaU\xbd\x94\xe0\x073e\xda\xb7\x98\xc5\xe5\xed\x1a\xce(2HV\xa0\xea\xbb\\\x00O\xf1\x11\xed=\xf4\xe6,/\xcb\xe6#(kH\x8d\x1e9\x90W\x16\xe8\x94`/\xa7\x11\x12\xe5HN2\x10V\x1f`Ia\xb8\xda\x8av\x84\xdb\xc2\x9b\x90\x92]\xdd5\xfd\xe5\xda\x13\xa4D\xb3\x10\x83\x03\xd5\x86\x14\x02\x96/\xc28H.P\xc9\\\xfd\xe2BS\x05F\x84}C\xa1\xcdZ\xa0\xb8]v\x8b\xab\xb5\xa3\x83\xa88\x0c\x8akM\xd9H\xe1\x07l\xf2\x18G\\\xe58\xeb\x95n\xe9\x93\xd5T\x04\x88\xca\xda\xaa7\xf9\xbb\x18\"w\xf4Q4\xd1<\xc06\xcf\xbf\xdc\xd4\x14\x0e\x02\x00\xa6K\xb1-?\xbf\x8ag\xcfWR\xc8\x89OY\xfa\x12\xa4\xa5\x07}\xa7\xd6|\x15\xde\xe9UA^\xb0#0\xe4\\F\xdas\x89\xe9\xa5:%\x19\x96\xb4}:\xf9Ro\xd1\xdb\x13\x83/9p\x0f\xb6aC\xe2\xcd\xaf](\xbc\"\xf9\xfa\xaa <3\x9catm\x9e\xfd\xa4\xb0\xe7\xce1|\xf5\x15\x8c\x1e\xc0\x87N\x11\xac\xc3\x88\x17\x8f\xd5\xc5cV\xbc\xab.\xddr\xe8JL\xf3\xf5u\xbc\xa60\xb2\xf2.| \xe3\x9d\x9d\xf6\xfb\x07\x9d\xd7\xe3\x9d\x1d\xf8\x12Z\x89\xa4\xc6<\xc5\xb5\xb8:\xd5\x93\xd1\x0c\x96\xce\xe5\xf1c\xd8\xeev\xd2\xc2\xb6\xa3A\xbd\x8c6\x8dK\xb6\xad_\xb1\xc7\x8fa\xa6\x87wZ\xb0u\xfd\x12v\xb7\xe8\x0bko\xcfB)\xf7\x98\xb7\"\xf6\xcbf\xed\x8cq\x1f\x1e8\xb0\xaemx\xb4)Z\xa6\x80Q\xb5\xcc\xbb\x1aK]Y\xed\xa1\x0b)L7\xdc\xf4\xb5\x82\x7f\x16B\xc7D\x12>Ze\xcc8\x8f@N\x0f\xfb.\x8c\x8b\x07l\x1f\xf7\xe5?&,\x9f\x0b\xdb\x14\xeb\xc9\xd7O\x9f\x1d|\xf3\xa7o\x9f\x7f\xf7\xe7\x17/_\xbd~\xf3\x97\xb7\x87G\xef\xbe\xff\xe1\xaf\x7f\xfbg\xfft\x16\x90\xf9\xd9\"\xfc\xe9}\xb4\x8c\x93\xf4\xefY^\x94\xe7\x17\x97W?o\x8e\xc6[\xdb;\xbb\xf7\x1f<\\\xbfg\xf1h\xdc\x0c\x8f\xf8\x95t\xbe\x84\xaf \x7f\x04\xeb\xeb\xa5\x03\x19K\xc6\xedOK:\xf0\xa9/\x83r\xe9`,c\x95[[\xa4\xc7\xea\x02\xd8\xba\x84U\x01\xff\x01\xb6)\x1a\x13\x8c6E\x9e\\\x16\xf8\xc1vn\xc2\x84!f:^9mfw\x1df:\x8c_g\x8cB\xf7S9:z\xc1v \xa6\xff\xac\xef\xc1\x96\x83\x00c\x13\xba\x13\x14\xe5P\xec9\xda\xbd?\x1a\xed>\xd8d>\xf6\xd3\x92\x9e-\x06\xe9\x14\\w\xc6\xbc\x84\xa1\x0fV>>\xa6\xac\xb9\x80|;\xc4\x8cZ\x08\xff\x0f$\x98\x0f\xf1\xcd\xb8\xfdfWz\xb1\xbb\x05_B\xd8\xe6\xa9*\x8a\xa6{\x14\xaa_\xc9\xd4\xda\xb0d\x08\xdaD\x08\xda\x1dS\xd0\xb2NTE[JzC^\xcd\xc2\xcb\x88\x1f(T\x81<(\x8a\x02\x0cCW\x10\xea\x0f\xe0\x8f\x90PZ\x80b\x06\x85`\x94.\xfc\x88\xaek\xe9\xa8k\xa0\xbf>\xaeY\xb7\x8c^\xcb\x1b\xf7\xbb\xef\xd1~\x06\xf6\xb1\xe3\x11LT\x01\x0bR^e\x83\x96+\x9a\x0e\x10QR2a\xde\"w\xb8\xc3\xfe\xfa\x1e\xa4\x0c\xc3\x04\xf0%\x9f\xc3\xc6\x8cM\x02\x02x\xfcx\x0f6f\x94rX\xa7'\x18f\x18\xd8\x14\xeb\x8fwv\xe1\x8f\x10\"\xc2d\x1d\xb8 \xda\x9b\xc1\xc6\x1e\xcc_\xf9\xaf\xb8\x8c\xa7\xc0\xb6\x18x\xec\x83\x8dY\x04D1o\x92!\xef\x19j\xe9}\xd1\xd6R5\xcf?\x85\x0dX\x1c\xc3\x87=\x18\x8d\xe9\xc1:o\xddp7b\x8a\xb9\x10\xa4)\x9c\xb6\x0b\x17\xac\xda\xac\xb5#B\xe5\x96S\xb2\xb1\xab4bAj^)\xa3G$\xbcd\xac\x8c+\x81%[\xaa\xb8\x12X\xa2\x8a*A\x0b:_\xe4\xbc\xa0\x13l\x82\x99\x9a\x8e\xef\xb7U\xaf\xcc\xd6\xb4mf9\xc7ff\xad\xb7)o\\\x11\xe6\x82\xd9\x9a\xee\xec\xb6\x03]/\xaaO\x1e\xb6?\xe1\xf6\xa6\xe3v\xdfK1\xb7\xce\xac\x99\xc5\xa9&\xa0\xc3\xd5\xa7\x0f\xe8p:D\x1a&%\x1bm\x82\xca\x89IU_M\x8b(UA\x92t\x9e\xb15J\xe5{\xed\n\xb8\xd6\x88\x0d\xb4y\xdc\xd5\xcb\xab\x82\x7f\xb4\xdc\xc9\x84a\x8d\x8b\x05i\xbb@-p\xcb\xcd^\xc1\xbd\xce\xc5+\xb8\xcd\x9a\xbc\xe3L\xde\xc7\xd0\xf1@\xd6\xd7\xcb\x92\xa4x\x1eS\xd4\xd1S\x11\xe7\xfdF\xccN\xe1\xd4\x0c]M\x99xN\x932\x0e\x0e\xc5\xc45\x95\x8a$\x89N\x93K\x8d\xc34bz4\x00\xa8\\\x18\xe9\x1d\x81\x16\x01\xd5\x1b\xef4\x8c\x03\x1e\xf0\x87\x95\xa1\x82\x99\xdd<{p\xeaVn\xd63\x14r|w\xc8\xf6\x9ayUr\xe1[\xb3\x93\xfe\xb0\x85\xe2\xa9\x18s\xda\xfe\x99\xc7\xf6\xf9hQ\xc6\xef_\x86A\x10\x91\x0b?#\x8e\x1d;\x86\xc0i \x06\xf2\x12\xe1FNN\xde\x1e<{\xf7\xd7\x93g\x07\xdf\x1f\xbd~\xfd\xe2\xf0\xe4\xe0\xafG\x07\xaf\x0e\x9f\xbf~u\xf2\xf4\xf5\xcb7\xaf\x0f\x0fNNP\x87\xc7\xbcGsE$\x1c\x90\xc8\xc6M\x97\xd6D=\xe9!\xaa\xdd\xf9\x84\x12;b\xfa\x9ez\x98\\\xffS\xa5*wTf$6?\xaf\x8eXk\x0cO\xc2\xbdK\xd1\x1a\x05\xdfVN\xb5\xf8\x17?\x1e:\xadRk\xbce}$\x89\x0b\xd3\xee\xba\xbf'W\x13\xb0\xe8f\xd1\x19)\xdc\xa2\xf9\x05gTCC\xcb\xc2\x04a\xa6;\xdf\xe6\x90U\xe8\x81\x8dFLx\xc0hz}l\xd7\xd4\xa9\x07txp\xc4t\xb0\xf2\x0b=\xb0\xc9y\x80\x81\xd8&\xd0\x16\x0f\xe5}\x18t\x879\xa37\x1cJ\x91b\xc09\xfe\x1a\xc5JNC\xdb\xa8\x06KU\x9b\xdf\x94\xf1\xac\xf1-\xb1\x0b4\xa0\xd5y\xf9\xaa\x1aQ\x8c\xc0[\xfai-:\xd7jW\xe5\xa7\x1e@\xc7\xde\xb5\xfd\\;^F\x82rF\xec\x0b4\xa35\x0f\x957\xacA\xa0\xc0t4mTg\xeb\x02\x00^p\xfc\xc5qU\x8c,\x01\xb7\x06m\x1cH\x85\xfe\x03\x9a\xd7r\x1f\x00\x08\xfcF\x9b\xd6O\xf1\x9c\x07\x17U\xc0\xedX\x0b\xb7\xe3\xe6\xfd=>\xeeq\x0d\x07Nd&\xde\xc2\xcf_\xa0\xb7\xb6yD(T\xd0W\x19\n\xd3\xa8\x07T\xa9\xdf\x0b\xcf\x9f\x17${\xc1\x9d\xa7\x91\x83X\xdbt\xe1\xc0\x96J\x1cY3\x1f\x9bB:\x9a\xcf\x84\xdc\x0c?\x1e}\x1e\x12\xd52M\x14\xd9\x9f\xc5c\x82\xdc\xbb=`\xcd\x99dB\x18\xd1\x7f*\x07\xcd\x03\x00TY\x80\xeb\"\xfd4\x85\x95\x18\xb0z\xd3\xc5\xbb\xa1\xad\xf0\x18T\xba\xe3\xd13\x02\xceG\x16\x82K\xe2o\x06u\xfe|9\x81\xb9XZ}\xb5\xb7\xc4\x9f\x15\x93:H\xa2\x1as\nn\x8cqi\x12\xcf \x18\xc6\xe5\x96p\xce\xa7u{p\x92\x07\xa9\x8bX5xdw9\xb0\x01\xc2\x82!c\x87\xce\xf8\xbbo\x0c3\xcaW\x99\x91\x96\xb7Q\x0c\x14\xf6\x14q\xf7\x06\x0f\xab\x894\x07\x0c\xcdxE2b\xc4p\xef {(b`\x0bLmW\x97\x18\x9f\x99,.a\xbea\x8c|JN\x7fz\xe9\xa7\x0e\xbdA\xfa\x97\ndZ\x89\xf1\x18\x99fW\xb9\x87V+\xd6\x0f\xa9X\x93\x9a8\x1bB\xe6\xf7RH<\xc6-F\x82&\xd3\xf8x\x85H\xe0\x82\x10Y\x91\x0c\xe9J\xf8br\x013\xef\xa5\x9f\x9a\x19\x05\xe0\x84\x89\xcc\x15\xf7s\x93k\x99)\xc2\xb0\xfc\x08\x93\x80lZx\x94\x1d\x18\xd0x/\xa3\x0d\x12'u`\xc7\x8e\xc9_N~\xf8\x88\xab D \x97\x0c'\xc6/\xf5\xac(\xa8\xc4\xbe\xed\x07aO\x0d\x95\xc8\x0f\xbbm\xa8,\xe4\x08X\x9b.\x04\xde,Y\x9e\x86\xb18M\xb9\xc3r\xea\x9f\xf6&\xc97\xa3\xdf\xa3\xabt\x88L\xa8W\nC\xa6\x9b\xc7^\x91\xbcKS\x92=\xf5sb\xa3\x11P\x15+\xbeW\xec\x86\xa7\x9e\xcd\xcd\xb1\xf5H\xa2\x1aP\xacH\xe7!?\xe7<\xb6y\xac\xcc\xf8-\x1eTT;\xf28\x92&}\x9c\xc1:\xc5u\xa1\x9aU\xba\xcd\xa5L\xc9\x13A+\x0f\xd8\x80!\xb72\xdfN\xdb\xca\xab\x86o7@N\xef\xdfbx\x02\x915\xc7\xe7\xf3v\x07\x82\x05^\x06d\xc5\xcb\xa0\x03T\xc4`\xd6\xa2z\x1a\x02\x06\x8a^\x1c\x13\xa0\x14\x9dL\xe0\xf2\xa3a\xb5o ?j\xeel\xc0n\xf5\x9ef\xba]\xc3\x98\xd1\x06_\xa8\xf2W\x07\xdd\x86\xc6\xcd\xfd\xe8\xbfpi\xaf*\xac0\x8d\xeb\x0c\x0e\x1b\xf7\x9dc\xef\"\xf3S>\xa4\xdeK:\xe3\xf8U\x03h\x03\x04\xbe\xe2\x0e\xca\xa6q\xcf\xb5\xc6\xbbD\xe3K\x14\x10 A\x91\x9d0\x1f\x17\xb4UL\x8e\x1d\n]m\x9ad\xc8P@Z\xaa\xde\xa3\xd9~\xc4\xbd\x88\x87\xa3!\xaci\xa9:\x14Q\xc4t\x8fB\xbf\xd8~\x90\x90\x90\xcfY\xe6\xc8\x16\x89\x92\x87\xb2\xb4\xad\x10\x13\x12\xe4P$\x954\xaa\x96\xd2\x16\x0b\xbf\xe0\xafs\xf0\xb1\x91\xaa\xcc\x0e \x14\x0b\x02\x17\xec\xe4\x00CD\x8e\x0e\x11\xc9\x0f\xef\xe8\xc0\xcez$\xdd<\xf0\xe67\xbcO)\x88\x08\xbd\xafM$\x82\xb6\xf8n\xf1\xc4*\xd7\x8e Q\n\xa2\xce\x8c,\xb26\xb2\xa8%D\xfd\x01\x0e\x9a'S\xce\xa5\xa3J\xe7%?\xe2TN3 9<4)\x16A\xb87)qL\xc2\xd0J5\xf8^\xc4\x12v\x10K\xb1\xc2\xf0A\x16\xcaO\xb3a\x88\xc5\xef\"\x16\x9f!\x16\xb4x\xf5\x99M\xaa\x82\xd9\xe9\x1d\nH\x14\xd5\xca\x88\xa5\xb2\xbe\x0d\x15\x1c\x0d3Mb\x83\x0d\x1dn#\xcdlr\xc3GP\xae\xaf;h\x0e\xdd\xe0M\xca\x9e\xe5\x10\x8f@\xf1\xc8\xcf\x990\xda\x94\xcb\x8b\x9e\xc7v\xe2\x1cS\x8e{\xe6\x17\xb6\xaf \xad\xdb\xcfM\x10\\hBp\x02\xc0~?\x0c\x17\xf6\xa1\xb7\xc2\x80\xde\xd4<\x0e\x08\xf4\xa6a\x81n\x87\xdeP\xca7\x08\x99\x0d\x90\x94fM\x0b\x17\x15.X]^\xd0\x14\x08\x10\njL\xec\xad^\x0e\xf7v\xe2\xbe\xa6|\xfd\x1fg]\x06#\x16\xc1m\xb3C\xabr\x11\x15\xcf\xf5G\\\xe3o\xe2\x01K{c\x99\xe5\xc4+\x93\xc7z\xeaV\x83\x92\xaa\xb05<\xb6\xf9\xbe~\xf4\xd0\x96,\x8b\xb2[m\xce\x9d\xd2jJz\xaa\xd2\x98T\x14\x99\xb3\xa2\x84EEa\xf5RFz6\xb0\x97\xc1\xe1-\xf4\x1e/\xf9ix\x84u\xc9\x8f\xb0\"?2\xa7\x8a\xe6\xe4\xc3W\x90=\x02\x9f\x92\x1f\xe1\xd4o\x92\x1f\xfe\x00\xf2\xe3\x9c\xa7C=\xb0cAl`*$\x0d\xa9\x11\x1a\x93W\xf2\x87O^i\\\x81\x89(m\xd6c\xe9\xd8\x85\xcd\xa2\xca\x1b\xdb4X\xd7|\x14q\xc5] )\x08\xc6\xe6\xfa\xf0\xa1\xa3\xf1\x13jt\xf5R\xcah\xca\xab\x85[\xed\xc8\x1d\xe2Q\x9f\x18\x99\x84\x1f\x80nl4(<\x0d\xc5\xbc\x9ff\xc4\xa7\x07\xcd\xa9\x10\x17\x90\xc1\xa6 \xd2\xc6\xd7\xce\x8b\x85\x99\xcd\xe8k\x1a\xe4\xeb\xb4\xe8\xb3\xe1\x82\x017\x9b\xfc\x08\xe9\x1f\x05\xfd~\xf8\xd6\xbb\xff\xb7\x1f\x94(\xdeB*!\"\x06\x0cZ\x1e\xe0\x1d\x0e\xabI\x1f\xba5\x138\xf7^\x1d\xfcpr\xf4\xed\xdb\xd7?\xbc:9x\xfb\xb6_\x03#\x1e\xcc\x80\xa0\xcf\x92\xa5zR\xff*J\xfc\x80\xa5\xf8Y\xc8j\x84AM\x98\xb5\x1bX\x03\xe6a\xecG\xd1\xd0-\x12@\xd5[\xd9\xdc\xb5\xc9\x02\xb0p\xb42\xd7[b\xaa\x97~\xca(\xe8\xe4M\x96\xa4C\x90\xd5\x10\xf9\xb7\x11\xcf\xf4\xb6\x04M\xac\xd2\xb2\xe3!\x03H\x9a\xdb.\xc93\x8e^\x87\xaf\xca \x92q\xd8\xb2\x0c!\xee\xec\xa6\x87\x02\x8a\xe5\x0dVL\xc8\x81\xd5VG:P\xea[\xb6c\xfam\xf5\xea\xdaV:\xaa\\hCG\xddZ\xc5\xab2\x02-\xd4\x0d\x9b\xac\xa2\x1b\x0d\x8fT\xde!\x0dA\x860\x03\x95\xb4\"\x83\xea\xcbF\x9a\xcd\xea\x05\n\xd8j\x96\x04)\x9a\xd6\xd5\xd6\xaa2\x80Z\x15T*\x91\xc8r\xe6\x1a$\x91\xf0*\xf9\x1a\x067\xe8H\xe9\xf7\xc1n}\x89&\xb6\x9c\x8c\x9b\xc6\x14\x18x\xf4\xea\xf6`\xa7\xd91\x86\x95\xc1yu\x1b\x99&.\xc4\xc7\xc6\xaf\x9bp\xa7\xd0\x19\xb7\xbe\x91\x13\xfdk\x9a\xd5\xba\xee\xcb\x8c}w[\xdb\xbb\xaa\x8a\xa1Y;\xddC\x18\x9b]B\x98\xa261$\xe5ow\x18V\xa9\xa3\x1aoe\xd5\x8f6\xc2.\xc8\xb2\xd5a\xca\xa2j.%\x9d\x8b\xdfG6\x9c\xf3,K~\xaf\xa8\xb2 `9\x93\xd6\xd2O\xa7\xf9\xb1+$\x9fye\xb1\xde\xd8\x96\xee\x9bir\xac|)O\xb2\xb7\x02\xed\x13\xe3z\xf4Ub\xf3\x13\xb0\xdfW\xdd LU_\xf2}\x88W\x8d\xf4I#2\xa1*J\xc4\x81>Z\xc6\xaa\x9e$*\x9c\xe9xQr\x86\x02]\x850$\x96\x93\xa9\xef1Ij\xcb\xf7\xc3D\xec\x0b'F#\xb1\xa0'\xa3\xa5\xb0\x98*N8\xab8\xe1B\x84\x12\x7f\x04 |\x05\xc5#H('\x9cQ\xf8\x92W@wb\x05\x82GcpN\xa7\x13\x17\xa6\xf4\xba\xaf\x00&SY\xae\x0c\x8d\xe5\x85\x11C\x9a\x19\xc3\x08\xcfE\xd7\x036\xd7\x7f\xe8\xfe\x92\x13\x8d\x9f\xe0\xdb\xdeX];[c\x85\x17\xb0\x9c\x14\xa9.U\x07\xc8S{\xca \x9dE\xdbI\x99\xb4\xa3\xca_\x0f\x19g=\xae\xf1\xa64\xdc\xcc\xce0\xcce\xc6b\x86\xb2|7\xda\xb8\xa1\xedX\x9e\x98+\xc5\x9b\xd7#q\x86\x0c\x85.\xd9\xb6)\x87\x94\x9f\xe7\xe1Y<\xa4\xa9\xfeY\xe9'\xc3z\x99`\"\x98-g\xc59\x98\x93\x0c\xc9\xa7\xf2Z\xbd\xfb\xd9\xed{\xa1\xeb\xd8\xf6\x9ef\xb1\x055\xc1\x1a\xb7\xd4\xb9\x8cv\xb6\xdaYyJ\xcc\x1aP\\$O\xf8\x01\x7f\x93$\x11i\xa5{\xc3Yx\xf3\xa4\xccL\xb5\"\xd8\x83{?\xde[\xbfw\xa6\"\x86gZ\xbfi\xdb\xb2`\x1d\xd0\"\x13MG\xed\xc8\x05\xeb\x8b/\xefYf\x94>W\xca>Q\xd0C\xeb\xf0\xfc\x1c\xf4\xcfY\x12\x17\xe4\xb2`1<\xf9\x9b2\xa6\x7fo\x1a{Hu\xe7Ul\x0b\xc1\x9e\xba\x18_\xd0\x9e\xd8m\x0b\xd33_\x99\x84\x19\x0f\xb1\x81\xac\xaf\x9bg\x1aHaI\x94\xf3\xcdH\xce\xf0\x98\x98\xf1{r\xf5&#\xf3\xf0R\x9a3_\x94\xb8\xb3(\xd9J\x8b\xb2\xe8_\x146\x9c\xee\xb2\xf8XZ\x8d\xad[\xa14\xaci.\xafi\xb7\x98\x02_\xc9\xd66o\xadms\x03\x9a\xc4WD\xa9\xfbs\nq\x19\xaeo\xe8\x15\x0b\xbfx\xcb\xd4\xac\x02\xd8)\x05\xcf\x13\x9e\x02\xcb\xe1\x98xa\xfe\xbd\x1f\x85\xc1ADh\x0d\xda\x0e}\x1f1\xc6 Jb\xf2$\x0e\xde2x\xfe3\xb9\xa2\x1d\xf8\xb0\x0e\xf6ZD\xe7\xcf\xe2\x9e MF\xff\xa2T\x01{\xbf\x0f\x96\x05\x13\x98\xd9\xf8\xa7\x03\xeb`\xdd\xb3\x1c\x0cU\xe8\xb8\"\xf0n\xe4\x98\xc1\xe5\xdc\xee\x0f\xcf\x04{`Y\xcd\x85\x113dq\xb9h\x8d\x19e\xc0\xd9\x10\xba\x1c\x03\xdd\xab\x802\xd2\x88\n\x02\xbb\xc0([\xd8a\xb3\xb2O\x87\xb3p\xa1\xa4\\\x92\x97\x91\x88\xf89\xb1K\xf3\x1c\x96=We\xe3\xce\xaf\xef\xf4\xb9\x14P7 \"\x95\x81I\xcd\xd88\x1a(\xaco\x9d\x8e\xc6\xcb\xce\x01\xa1\x9b\xe2\x07\x01]\x830>;J\xec\xb9\x98\xe8\x8d\x06R\x1dd\xa9W\xf9,K\xaf\xefp\xcc\x81\x0by\x8b\xae9\xeb\xc8>\xe7Iv\xe0\xcf\x16\x93^b\x06\x84-7\xb3\xb5\x96\xa2\xac+\xec\xc5\xabk\xb4 I*\xb7f\x84\xa3\x94\x85\x84\x9aWp\xd4\x8e\xc3\xdc\xc4\x0cK?\xfdH\x03\x9e*\xa8`\xfe\x15\x9e\xbf\xcc\x15\xbb\xc0\x9c\x8f\x8diJ\x96~\xfa<.\x92\x1f\xc2b\xf1g\xb1\xdb\x98?5\xf6\xa3 \x9c7+\xe3\x8e\x0e\xd0\x00\xf2\xd1\xe0\xb2-\xd9h\x8ckU$\x88\x12\xfb$y\x82\x95\xe8[\x80B,\x80\x1a\xa5vRg\xd5\xf0\xa9\xa6\xa2\xce\xf0\xed-\xa9\xa8\xd1f\x9b.\xc2\xc0\x7f\xb1\xfd\xc0\xe9\xb34\x16)U<\x91R\x85B+g\xa3\x86H<\x9b\xdf\xa5I\xda\xa3\x83b\xa7\x17\xfdjY(\x16Epr\xdd\x06\xc4\xe4\x02\xbf\xef$gP\xd0\x8a\xe6Y7R\x85\xd1&1)\x8fm\x8dw0\xc7\x85\x84\xdb*\x1fN\xc5\xfaPv\x92\x16\xa5I\x12\x1d\x86?\xd7n\x9d\xcd5\xa1\x97\x9b9\x9d\x04\xa5 \x92.\x01\xdb\x1d\xb7\x8c\xdf\x06\x9c\x15\x90\xc5`\xc6m\x89\x1bc\xe61%\xe3\x1a{\x01g\xf0}\xfa\xb6\x9a/K\xc7T\xfd\xb9\x07#L\xc6$\xb0\x18\xec\xd1\xbbS\x91\x9bIAZ\xc6\xa4I\x83O\xda\x0bB\x9f\x0e=?p\x0dn\x02\xe4 \xad\xddJ\x80\x0e*`\x8fyl~\xd5r\x80\x12\xe6A\x05\xf7\x9dT\x15\xa0^\xceb\x91\x91\xce\x82\x0e\xb90\xe0\x96\xab\x95\xdd\xc9je\xae\xf0\xcb\xeb\\1\xe2\x19\xbe`\xcax\x1e\x8a5\xeb\xf2\x81\xdd%3\x98\x91\xdcf\xd5\x92;Y\xb5\xa4Z5FM\xa8\x9d\xc0VZ\xb8NB\x88n\x0b\x9a{\x8d\x99k|\xac{m\x9b\xa5Z\x1e\xef\xdeW\xc5\xa2\x8b\xed\x9d\xadv\"]\xbf\xbe\x10c{g\xbb\x13^\xaed\xe5\x0f\x1d\x17,\xaf\x9d\xc6\x95N\xc8\x9aX\x9ax\xc5\n\xc4#\x08-\x0c \xd2\xcdx\x80\xef\x05cB8\x8b\xe4{$\x9f\xf9)\xb1 c\x92&\x18Z\x9e\xe5Q\xb0\xb7v\xdb\xd22\xb8\x990\xae\xa2\x06y\xdc\xccj\"\x84\xc7w\x9a\xb90\xd7\x11H\xa9\x8bq\xf2\x84\xb9F\x1761_I#05\x86\x91\xfd\x12\xacSz\xa2\xfcX\xbc\x12YP\x90|sk\x07F\xbcd,\x16\xab\xd9\xc27X\xd7\x8a\xcb\xe5)\xc9\xe47\xf5\xaa\xf2.\n\xef\x8b/\xf8\xc8\xd0\x15\xb2\"wg\x94{)\\\xca\x83\xb2\x00\xcd\xfbP\xc2: \x05\xb2\x89L\xb0\xe3\xc2HM\x13/0\xc6\xa5\xf2\xc8\x9c#\xb3)59\x81\x18\xd6A\xa1y\xa1\xab\xd2\xe4\xcf\x0b\x8d\x06\xa1\x92j/\x99\xc4zII\x8c*\xbc\xf6r}\xdd\x81\x05\xac\xef\x01\xb1S\xba\x0f\xd3\xe5\xb1\x0b\xe78\x97\xd4\x85\xa5\xc3w\xaf;\x02Ml[\x90\xd8\xa2P\x99\x8d\x10\xf8\xf0\xcf\xfaP\xd8\x95\x8b\xd1\x04\xcf8m\xd7\x13Z\xe6\x0c\xc1\xa0\xf0H\\d!\xe91s\xa9\x16\xe5\x84-\xca\x9a}\x05{p\xea\xc5\xe4\xb2\xb0\x1d\xc7\x0b\x12L\x1d&-\xcc\x15K;#\xad\xcd\xc9\xfa\xba~u\xc4CW\xa9\x7f$\xda\x01\xe8\x17H\x91i\xd2\x8e\xe1\xae\xcdSU(\x92P\xdd\xc1\xca4\xc7\xca\x0e\xc2P\x0e_\x0d\xc6\xd6\x9e5\x01koS\x03\xc1\xd6\x04\x8b\xc7V\x17J\xb4\xf2\x02\xeb\x0b\n\x93\x1d5\xc0\xbd\xe9\xde\xe4\xf8\xdeY\x1fc.5TL\xc9q\xb7_#GY\xc6w\xb3(\x9b8m\xdd\xa2\xec\x8di\xf1d\x95Ea\xcba[\x1e;\xccd\xba\x89\x1az\xbaV\xeco\xd4D\x13//O\x19\x15`\x8f\xd1\x97Pz1r\x1ci5\xed\xbd\xcd\x0f{c\xe7\xee\x17\xb4\x86W\xf5\xd9\xb9\x13\xfd\xd7\xfd]\x87\xc7\xe8\xfc\xc6\x9f\x15Iv\xd5=\xc5\n)\xc0\x84\xa2H\xbfM\xa5b\xd1\xe9i\xc6JOO3e\x85 \xc8H\x9e\xb3:\xec\xb7\xb2ZFx/\x19Qw\x94\x15\xe1,\"\xbc\x0e\xfeVV\xcb\xc3\x80W\xa2\xbf\x94U\xca LX\x15\xfaKU\xe5\x14\x8bO\x95E~\xce\xda\xa7?\x94\x15\x82\x90\x95\x07\xa1\xba8\xe1\xc5\xea\x9e\xc33V\x1c\x9e)\x8b\xa3d\xf6\xfe\xefeR\xf01T\x7f*+'\xc1\x15\xab\x96\x04W\xca\nl\xeb\xd4\x1bwZ\x16E\x12\xb3\n\xf8SUi\xe6\xc7\xe7>\xdb\\\xf6S])\xa5\xe0\xcak\xe1oe\xb5\x90\xcf\x8a\xfePVH\xf8\xd6\xd2\x1f\xea\n\x11/\x8f4\xc5gYR\xa6\xa2\x0e\xfe\xa1\xaa\x18\xf8\x05\x03F\xfaCW!\n\xf3\xa2\xaaD\xffPV\x0cX\x95@YH\xd8p\x03\xa2\x1cn@\n?\x8cr^\x05\x7f+\xab\xcd\xd9\xca\x06s\xe5\xaa\x06\xa1\x1f%\x0c\xa6\xd8Ou\xa5s^\xe3\\Y\xcc\xc7\xa9\x1e&_\x05\xe5\xfc\xc9\x12\x0b\xc9R]xJ\x02^~J\x94K4\x0fI\x14`\xd2\xe7\xcc\xb6\xc4\x1f\xea\x8ag2\x98\xd5\x7fj*\x97\x19\x11\x15\xcbL L\xf3$\xc1\\\xb5\xff\x1f{o\xda\x1d7\x92$\x08\xbe\xdd\x8f\xf5+\x9c\xf1\xaa% \x03\x0c1H\x89\x94B\xa2\xd8J%\xb3[\xdd\x99\x92FRVMw0\x8a Fx0PB\x00Q8xdQ\xef\xf5\xcc\xec\xdc\xf7\xee\\=\xf7\xd9\xb3;\xf7\xb1\xc7\xec\xce\xf4\xf4\x87\xce\xfc#\xf3\x07\xf6/\xecs3w\xc0\x017\x07\x10$\x95U\xbbo\xf1\x81D\xf8\x05wssss3s3Q\x08^\xe9B\xc9R\x16I\xc81.\x86\x90\xbd\x18\x92\x99\xdb\x98\xb9Mf\xee`\xe6\x0e\x99y\x1f3\xef\x93\x99\x0f0\xf3\x01\x99\xb9\x8b\x99\xbbd&\xf7qB\xc4\x8b\xad\x80\x04\n\xbe\x92\x85\xcaU\xb6\xb0\xae\xb1\x85l\x85n![\"\xca\x89\x17\xaa\x00\x92X\x92\xc0\x06\xf3\xc4_\xe2\xe4\xe2+Yh\x89K\"X\x92\xeb!\x88V9\xe2\x1c\xbc\xd1ERY\x80\\\x95\xefO\x10\x90\xefOH8\xbe\xe7\x97\xa7\x1cQ\x15_\xa9B\xa1\x7f\")\x04\xbc\x91E\xf8)\x8f\xf0K\xf8J\x16Bh\x85$\xb8\xc2 z/\xb3\xa3\xf7T\x81\xa5\x1f`G\xc5\x0b]`%\xf3\xc9\x89^\xfa\xc9{\x99\x9f\xd0\x1f\xe0Q\x8e\x05x\x94\xdb\n\x04\x99$%\xea\x07]P\xd2m\xf1b) \xb1\x17\xde\xa8\"\x91\x8f\xa40\xf2IR\x18\xc5\x18M\x19\xcb\xc8\x1fTA<0B1y\xac\xa5\n\xe1\xf4\xd2\xdbU\xbc\xca\xca\x85\xa4~X\n*\xba\x17[i^\x9cg\n\xa7\xf1\x95*\x84\xdf\"?\xb2\xf2\x13\x1fg\x00\xde\xc8\"\xc14StU\xbe\x93\xc5T\x11[v|Zp\x8c\xea\x07U\xf0gP\xe2gTV\x82\x03I\xc8\x91$\x08\x85\x84\x84@\x92\x9f \xcf$^\xa8\x02\xd8/\xb2C\xa9\xbf\xc4\xef\x8a\x17\xb2@\x89:v\xc4I\xf9\xb4\x98N\xf9N\x17\x0b\x15~\xe1+Yh\xe9\x87\x88b\xf0F\x16\x89\xf3d\x8a\x13\x82\xafd\xa1\x95/;\xb4\xf2\xe9\xdedI\x1c!I\xc5W\xba\xd0\xa5d\xe0\xe1\x8d,\x92#\xeb\x9d\xe6$\xf3\x9d\xe6\xcb\xa5\x9f\\\xca\"\xf0N\x17\x93\xf3@\xaf\x97\xcc?\x91\xfd\xc80R,Q\xa4\xe0\x9d3\x1b\xf3\x9c!\xd9\xcdH\x92\x9b\xf1\x8b\xac8\xd2\xa8\x1fdA\xc1[`)\xf1F\x16Y`\xfe\x82\xceT[vf\xdb\xb3\xb3@n\x87\xe2\x85.\x90)x\x887\xb2\x08R\xcd\x8c$\x99Y\xe2O\xdf\xcb|\x7fJ\xd2x$\xf0$u\xcf\x11As\x12;\xcf|\xfc\xf0\x99O~\xf9,\x98qW\xfc\xfa\x9c$\x11<\x0c\x83\x95<@\xcaw\xaa\x18\xae$\x9a5Y\xfa\xa7\x92\xbb\x11oT\x910\x88\xb0\x84x\xb1\x15\xf0\x93_K\xfcY\xc0\xa3\xac(Z&Q\x95\x96~\xaa\xf6\xf1\x94\x9c\xe3\x95\x82\xd0\xca\x02\x9d\x95\x9fe<\x89T\x19\xf1N\x16\x8b\xc3\xcbSI\x00\xe5\xbb\xadX1R\xf5\x83*(\xc6\xe4\x87\x95\xd1V\x93\xc8J\x8a\xb8&6\xd2\x9a\xc5\x92\xc8d1M\xec\xcf$=<#\xe7Q\x10\x85\x82:\x90\x05\n\xa2\x9b!\xd5\xad\x94\xb0\xc8\x88P\x05{\x0b2\xa2\xaa]f\xb5w2\x1a\xfb\xae\x1e|\xac\xd2 eMv\xc3~\x18\xc6\xd7\xf8\xe1\xba\xe95j`)\xfdk\xe4\x0c\xeb\xe1\xb5r\xd9\xf7zq\xb4\xa8\x7fp\xff\xbeeL\x8df\x1f\xcal\xe3&\xf2s&\x8doi\x19\xba\xfa\xcaT\x94x\xf2\xc4\x8f\xe2\xe8r\x19\xe7\xe9\xd3\xa7\x84\xa8tn\x95\xaf\xfah\x99v\xe6\xf4\xe0\x8dB;\x06\x82#\xc1\x98\x9e9\x85\x12\xd5RN\x0c\x17\xca\x15\xe3\xb6\x14Dm*\x14\x95\x8aUKA\xc55\x9f5q\xcd\x0c\x19\x8e@0\x1cg\x8eR\xde\xda\n\x02\xd0\xb1 \xbc\xda\n\xfa\xd1\xe5\x88-\x9cD7\xb3{ \xdab;(_\xcd\xdb\xe4\xdd\xeaQ\x9a\x9c\xaa\x7f\x1fk|\xcc\xfaS\xd3wh\xb7\x9a\\\xdd\x94b\xe6\xf4\xd4U\x13\xf6u\x8f\xf5!8j\xefk\x16\xcf\xcbx]\x98\x91`\xc6\xc2OY \x03\x16\x8b\x9a\xef.W\x9cEq\xe6\x83\x8a>\x88\xd2`\xc6\xd5P\x07m~\xb0\xce\xe4\xbd\xc0\xac\xd5\x99#\xdcn\xad;[k\x83\x01\x93\x9f\x00+F\xc7\xef\xee\xf4CBF\x05f\x16\xc3\x8f\xc5\xf0\xeb \x12 \xc5\xb4\x14\xd3\xd2|\xb5\n\x03>cY\xacC\xcdc\xfcb\xc5\xa7\x19\x9f1?B\xe8\x0c\x08g\xb1\xfa\xd3|Q\xbfP8\x87\xa8p\x0e\xd9\x13-\xc8u\xd8\xefw\x05\x0d\xdc\xd6p|\x8f\x85\x05f\x89\x1e\x8fE\xdfC\xf16\xe9y,\xef\x0091AS\xddf\x11.\xe5\x95\x16\x0e7\x18,ey^\x7fl>T\xe8\xa5\xc8q\x93\xea\xe0Q\x80\xdd|%\xae\x89\xe4|\x0d\xc4\xce?>b\xe7\x9d\x11\x9b\xa5At\x1ar\x8c\xbf \xd9\x80\x9ba\xf9M&\xde\x16^Ja\xe8\xf7J\x887\x1cp\xba\xa6\xad\x0e\xdey\x8e\xf1\xeeN\xe4/\xc1\x98\x95\xb8\x9fC=y\xab}\xb1\xedA\x1c\x1cL\xe3\xa8\xb8;qu\xc5\xaa)\xd0\x9bri\xb7c\x9fz\x94\xd1\x99\xd1X\xa7\x16>\x00\x14\x7f)\x90]\xcd\xa4\xa8\x0e%|(\xf1\x8bCw\x0b\x17\x05\xfa\xafk\x12\xb9\xc6\xbbL\xf5\x07\xd0f\xe9\xf0q6q\xeb\x0c\x86>\x01I9\x01\xb1\x05\xd8\x91IY\x80\xa4\xbc\x8cg\xbc\x95\xa3\xb8 \x0cm$\x03\xf9\xca\xef\x95`\xfc\xc2875\xd6V@\xeb\xbbZ;M\xea\xc6\x81UL\xba6*\xf1\xec\xd7_\xcb\xebpd\xf8\xcd\xd61k\\\x17\xf8\xa5h\x1d\xb6\x18\x90?X\xf8\xe9\xab\xf3\xa8\xb8[\x1ev\"\xfd\xac\x99A\x1b\x00\x83\xd6\x8d5c7e\xcf\xd8/\x80t\xc5\xd1\x1a[4q:\xd0<\xe5\x18\x07\xb4\x06\xbb\xbe\x9b-\xdd\x02A\x8a\x95\xa1{X\xe6\x05\x83\x9e\xeb\x17\x8fm\x8f\x18\xd4J\xcc<\x07\x7f\x1e:\x8c\xdb\x97\xa6Xp\xbf\xf1\xf6\xd5\xcb\x01\x9eu\x83\xf9\xa55\\\x80z\xd6\\i`\x1f\xaao~\x1d\x96Z\x1c\xc1\x8eY,\xcf\xa6\xfd\xf2\x1a\xe8\xf2\xee\xb2\xdd\x9cL=\xb7\x862\x157\x1f[\x8fYV\x99\xe9\xac\xfd(\xa6dAb\xef\xec@\x1f\xa9\x9d!*:\x1e8\x1bC\x8f\x15\xb3\xa7\x9c\x87T\xe6\xa6\x80\xd5\x80\x1d\xd6\x8f\xa5\xb0},\xf8\xf4}\x01\xc6\xd4c'y\xc6\x12>\xe5\xc1\x19\x9f\xb1_I\x99\x9f\xb1 \x9a\xf1\x0b\xf6+\xe9\xa0\xe7\xb1\x13\xf4\xed\x05\xf7\xa4k`\xb3\xcf\xee\xf7\xb2\x04\xa5o\xd1r:\xfc\xf6\xe9`\xda\n\xe2\x9d\xbc\x8f\xeaWX\xd3jo\x05\x81v;QG\xd6\x99\xc6vY\x9f\x96\xa5x{\xeb-]t0\xddT\xcf\x0d\xa7\xf4\xff;\xac\xc6\xd7\xf8\xc5\xaf\xd7\xe44:\x1d\xe0\nfa\x1cv\xc4\xd9i\x97f\x99lz\x0en n\x85\x0f\x99\x17\xa0\x9e\xb7\xd6i^\x12\xdd\x16\xcc\xed1%\xfc\x02BK~oX\x9fv\xc6\xfa\x10\xb0\xbe\xee`\xae\xfe\x18X\x1f\xde\x00\xeb\xc3[\xc7z\x85\xc2>:\x93\x04\xfe\xa9\x8dk)V\xca\\\xac\x94N(-J\xaf`\xa5\xcc;\xae\x94\x8d\xd5zpz\xcf\xe5\x99l\xdeL\x8e\x8f\xa2O\xfdY\xa1\xc2\x10\x195\x9e\x0da\x80\xd7\xf9{L^\x139\x8a@\xd3\x06\xb7J\xc8Z\xfa%\x13\xe5\xa7K\xd6\xef\xb0L\xcf\xe4\xa5\xb2\x95\x93zln\xae\xf6y\xb7\xd5.\xe0\xb6(\xc0\xb6\xf8\x05\xadc#\xf5\x83vE\x92\x99>\x87(\xfcQR+y\xfd\xef\xa0pR\x7fu\xc5\x86\xec\x1ed\xc0K\xc6F\x8c\xc3\x85I\xb8\xed\x07\x0cZ\xa5\xb5\x0f\x96o\xcfhJ\x02\x17g\x97J\"\x81\xe8\x84\xe2=\xf0\xd8\x1c`\x92\xa37\x1ep\xb1\x13#+\xfa\xdc\x0f\xc3 :-D\x0e)\x83\x95\x03\x8e\xb9\xd9,H\xf84\x0b/Y\x90\xb2(F65N\x04\xd18\xb9\x84\xc0*_\xaf\x92x\xb5)\x88N\xfa5[\xf9\xd3\xf7\xfe)\x1f\xb0\xafR\xce\xbe.\x1a\x1c\x00\xc3Z\xfct\xdc\xaf\xc5:\x9b\xfaa(\x9aX\x0e\xd8\x1b\xee\xcf\xd82N\xb8\xe0\\\x17Y\xb6\x1a\xdd\xbb7?\x19,\xf9\xbd<\xe5\x9bP{\xb3\xfc\x8eu\x91hx(f<\x19\x07\x13v\x007+\x8b\xcb\xa1*\x0d\x89\xc4\xbb\x05/\xcf:\x15\xa2\x19\xa4`\xe5(\x18\xef\x94%\xfcgy\x90\x80TQ?O!\xdf\x1dd\xa9$\x067b\xdc\xa9\xe0H\xdb\xa5k\xa6+\xe61\xbc3\x92\xa1\x0d*\xb4^\xba\xd6B\x1co\x10\xd7\xdd\xd5#\xc6\x10c,\x91\xa4\xdbm\xee\xa4v\x9b\xbb\x8b\x10\xe11\xdb\x80\x10\x91A\xed\x16ucMV\xeaBb\xbcB\xadM\xe4\xd0\x0e\x9a5nvS}\xea\xc8\xf5\x82\x17\x9f\xae7\xbbAx-\xf0cc\xe9\xf8\xe3\xe1\xa4\xd3@X\x17\xd9\x8e\x0d\xa3\xa5[\xd8\xf6\x05k~\xbf\xeeu\x96&s\xa7\xcdWL\x95\x9e\xc5\xba?\xd5\xe5\x85\xec\x80I\xbb(\xe0\xfc4\xf1\xfa\x1b~zx\xb1*\xef\x81\xf7XGG@\xf2K\xca\xf4\x08\xaf\x9c\x82;\x89\xb7ZJ6\xee\xfd\xea\xaf*\xd7\x1b\xef\xfc\xd3\x1e,\xe0\x16k\xb2L\xef &\x9bpD\xa7W\xa2\xe3\xaa\x07\xf58r6\xe0^\xda\xddwiN\x98a,\x05\xb5+UZx\x07\xd9\x84\xbc\x9a\x9bSR~m8\x01ht\xb0T\x99\xa1\xcf\xfcL\xfb\xfa\xcc\xcfx\x8f\xc6J\xa3&\xcemY7\xe1\xa7\xfcbE\\1\xb6\xa1Q7x\x9e4#+-\xd0/v\xec\xe6\xad\x1a\x91\xb6i\x1bn\xdd\xf6\xd4\xe8\xfd\x088\x9b\xc6=\xb4y+\xc620\x03M\x05$\x98;\xf4\xa8\xa9C]iL\x9b\xd3\xb7\xea/YIs>\xc9\xf6Q\xc5V\xa6xl^;\xa9\xb0}\xc1J\xcf\x07z\xc2\xdc\xd3\xa4b7\xf0C\xd0\xe4x\xa7P\xe9\xdfR\xfb\xbd\xe1\x83\xc1\xee@z\x1e\xb8Vkg\xa5\x8f\xe9\xdd\xfb\xee\xa0\x88\x98@Y\xf3\xb6\x19\x1b\x07\xb2\x9d\x07\xa4}\xef\x83\xfb{\x16\x83]\xdfQ\x92\xb9\xdb\x18\x87aG\x8c\x9d\x1fn\xd3n\xa3\xeb&\xca\xa2\xb3\xbdep\x11Di\xc7I\xad/xuf\x19\x13\xd2\xc3\xd4j\xef\x8b\x9f\x1c\xb1\xdeg\x87\x9f\xbfxyx\xfc\xe5\xb3\x97\xbfe\xf1\xad\x90f~\x16L\xbb\x95])\x0c\xefTZ\xfaS]\xa3\xc2\"\x08g\xcf\xd7\xadu\xca\xb3\xcf\x90\x1a@\x84\x9dj\x9d\xe3/\x0f\xdf\xfc\xda\xe1g\xf6\xaa/\xa2 \x0b\xfc\x10\"\x17\xadY\xf5\xb9\xd6\xddu\xaa&<\x82\xbb\xb4\xaa\xc6\xab\x97\xcf\x0f\xad \x94+\xe8\xc7A\x18~\x89\x8eK;\x80\xa4\xa8\xf6Y0\xbbF-\xf1\xb17\xa8($@j\xc3\xa3E\x9c\x0bp\xc86\xbeZ\xcd*\x10\xed:\xc8z\xbd.\xfd\xfd,\x98]\xa7\x1a|.Zv\x86\xcfW/\xdf>\xfb\xfc\xf0\xf8\x9asB\xd5^\x1b\xc8T#k\x0c=\x87\xa2\xc5\x1c\x8dX\xef\xd5\x8f\x0e\xdf\xbcy\xf1\xd9\xe1\xf1\xa7\xcf\xde\x1e\x12\xbc\x8f\xd9Nh%:\xb0\x10\x93\xe0\x8c\xcf`5}\x9e\xc4\xcb\x86\x15\xd9\xe5[S\xeb\xb7fA\xba\n\xfd\xcb\x97p\xe3\xbb\x13G\xce\x80\xf0j\xf5X]\xac\xab\x1e\x8b\xd6H\xd1\xd4\xce_\x13\x1cgK(\xb9B\xed\x11\xa1\x9a;\xaa\xb8a\x8b\xfa}W\n\xb4\xc7\xd1d-\x15\x17AJ;\xf7\x9b\x0f\x8c\xda\xe2\x88.C\xa6\x19y\xa4\xabP\xd6\xd0\xb5k\xf7\xca\xd2\xa1\x1b\xf4\xc5\xd8;\xd6\xe8N\xad.8\x13\xaa\xa7\xed\xb3\x85c\xa4B\xcb#\xb2\xf4Z\x08\xa9\xed\xc6kt{\xa5q\xa9\n\x84E\xda\xba\xf0+\x98\x87\xce\x1d\xd8\xe8^\x94u[C\xac\xba\x8e\x82\xa8\xbdU\xf5(>\xaf\xdd\xa6_=\xd0\x9f\xba)`\xd4\xd9\x14\x90)\xb1\x97\xe0\x16A\xd3\xd9\xed\xb3\xe2 \x9c\x8d\xd8cw\xc1\x88\xf6y\xe8\xa7\xe9\x88\xfdV\x9c3\x1f\xf4!\x19_\xae\xb2 :eY,C\xcf0\x9f%<\xe5\xc9\x19\x9f\x01\xa6\x88\x9ez\xec\xeb_I\xbf\xf60\x16>n\xd8\xd1\xd1\xdd\x8c\x9dp\x06\x11\xf2A\xb4\x0b3\xdac\xef\xf9\xe5\x80}\x86M\x05\x19\xf3S\xe6G\xa5\xc1\xb4j\x11R\xb8?{,\xca\x9c\x07a\xc8\xd2L\xfc=\xe1\xcc\x9fNy\x9a\x06'a\xd1\xb8n.~\x97vRo{\x94\xd8\x0b\x80\xd6A\xea\xa5\x1e\x90~\xad3;L\xe3\xb9Cs\xa2\xd9\x01\x0b\xc7\xd1D\xca\xe9\xbb\xf7\x83\x95\xa7\xcb\xc0\xa1\xb6C\x10{\xe4\x1e\xebu\x9e_1\x95\x02\xb2\x97q\x9eh\xb6\xc2\xa0 \xcb\x16~\xc4\xe2h\xca\x07\xec\xdd\"H\x05\xe4\xe7a0\xcd\xd8\xd2\xbf\x14s3\xcb\xb9h\xc9\xc7Mm\xd0C\x07\xc8gq0s8\xc6\x95_\xc0\x8b\xc7\xa8\x80S\xb6\xa7Y\xff\xab?\xf2#\xb4\xc7\xe5\xfa\xd3\xde\xac\xbd\xc4\x07\xa42\xeb\xd04?\xcf\xe2\x93 \x9aU-\xee\xd7PA\xd3\x81u\x98f#\x98\xd6\x11+\x13\x88\x95\x8e3;b\x9d\x10U\xee\xdc\x11\xc8Te\xe1\xd0Ml\x05\x8f \x12\xc2\xdc\x9fr\x1bB\xc5g`\x87Q\x9a#\x86eXj\xc9\xb3ENDg\x9f\xe5Y\xfci\x10\xcd^\xfbAb\x89TY\x8dR\x19\xd5\x97\x99\x0f\xcbl:@\xee\x1f\xa6T\xbe\xbb\xa4\xbfw\xf5\xc0\x1c\xd7\x1bC\xbb\x8a\x1cC\"\xb6\xedJg\xf2^h4\xce;X\x8e\xad`\xd8\xc6\xf7\xda\xf5\x80sg\x85!w\xa6fm\x97M\xc7\xf9D\x0c:li\xa9\xc1\xef\xb3\xfe\x881\xcd(\x02\xd8\xd6S\xd6d7\x0d\xc6+\xe0\xac{\x05\xb7\xdc\x86H*\x06\x8a\x92w\xdb\xc1\xc0P\xbfmR\xf4\xe7L\xba\xcfN[\x03\x96\xeaO\xe0\x80\x13q;\x13\xb0\xac\x13@\x99\\_\x81_E\x85\x11\x81 \xd1l\x15\x87\xc1\xf4\x92\xfdJ\n(\xfd\x9e\xc3\xeb\xf9\x82G\xb8\x02O\x81\xdd,\x96\xa6\xa8\x02\xc4x\x89\xb3\xdf\xd0\x9d\x03\x96`\xe4\xd2\x85#^\x042\xb0\x11\xd5C\xf4\xe0\x8be\xcf\x8a\xb2\xdd\xa0/\xddA\xcb\xda\x1d8+(\x1ec\xd0\x93\\|\xc7+*7\xd6m\xe0\x15\xcc-\xbe\x13\xa1\x9fY\xf7\xfb\xea\xb1$p\xa4AY\x83\xaf~\"=\xf3Xo\xc9\x93S\xaeB\x1c\xbd\x8c?\xcbW\xa1\xd8\x90\xf9o\xf2\xcb\xd4qG\xec\xb9\x1f\x89m\x17\x8a\xb1(\x8e6\xb1\x99\x14\x08x\xe62\xe2\xc8\x82Q\xca*:=`\xf8Z\xbf\xf5.\x91\x06-\xf8\xb5\xec<\x96\xf4;\xc5\xed^p\xfa\xa9\xbf\xe4\x18\x06]l\xbd\x9dv\xd6\xc7\x02D+\xf0\xf0*\xf6\x044\x92SE\xa7~\x9eJk\xb2\xf3\xb8.\xb6u\\\xb1\xc5\xd5\x0e\xd3\x8e\xab8\x0e\xc9w\x8b\x15P\xe9\xa7\xd8\x1c\x17\"\xf5=\xbfL\x15\x0b,\x19S\xcb\x0dUeB\xd8 -\x16m\x96\x88:{i\xdd\xf70\xb04F\x83\x15\x10\xf1\xcaH\xb2\x96{\x8e\xe2\x81C\xad\xa5\x96]=\xaaL\xe2\xca{(I{\xe1\xd2\xd6#\xb2\xef\xde\xe0^\x98\xf0\xd5\xcc4\xa5\x9b\x13\xe3\x14\xc0\x0b\x1dV\xa4\xdbz<\xbb1\xe0\xad\x00\xb7\x02\xf5\x9a]]\xb6\x1e\x1524\x9e\xa3\x94\xc4\n\xec\xb5/\xd5[1C\xd1\xa9\x87P\x13\xb4\x82\x86)\x83\xd6\xe3\xe3 \x85J`\xe3\xb7\xb1E\x96&H\xaa\x89\xb4\x97\xed\x1d\xac\x88\xea\xaf\xddG\xda\xde\xa5S\x1fO\xac}\x94\xfe\xc1\xa5\x02\xa9\xb3p\x0b\xfa\x87\xf2\xf8d\xc0\xa3\x9f\xe5<\xe7o\xb4\xa6$\x86\xad}z-\x06\xdc\x11N\xca\x16g\xa3\x0e\xb0\xeb\xc3\xea\xd8\x1e\xd6\x97iF\xa2\xce\xb1\xaeT\xd7y{vB\x90\xb6\x12\xb2M\xe42\xab\xa9T\x93\x06sPV\xa2\x89yXP\x91\xd7\xee\xdc\xe9\xf0e\xf5T.\x11r\xb2]\xcf\"\xeag\xfd}\xb6\xdd\xd6>\xab\xc9,\xdb\x8f\x05L\x9e\x88\xb2q\xc4\xfal\xd8\x81O\x85\xe0\x0b\xfbH\x99\xe2\xeb\xfaA\xf8\x00\xe8\xab\"\xda\xad\xa4t\x9b[C\xe7&|\x0e\x0e\xc4\xbc\xca\xbaP6\xeaQi1\x9fq\x19\xcb\xc7>\x90\xc2\xcaWT\xa9\xb1\n\xec\x80Lv\xdcV\x81^\xe0\x10\xacY\x0evuUs2`\xa6\x7f\x85\xf8\xc4\x88-\xc5\xc9W\xa2\x7fq]]\xf0.\xe2\xd3=\xb1\xb9\xe8\xea)q\n@~_P\xc14\xd0\x14w=\xb7\x06\x91\x9c^\xad-'\xde\x04\x84\xe5\x15c\x97\x88\x9f\xb3cOO\xac\xf8\x10\xc1h\xc8Z&\x85\xe22\xa8_>\x90!O\x9d\x95n\x00\x9e\xb9\xae\xc7VN\xe6\xb1S\xf5\xc2\xd5\xcb%\xec\xb0u\xb5\x08\\EP\xc1\xe6\x0bMI\xbd\x98\xe3\x82\xacB\xef\x1c*\xda=\xd6\xc3\xc0\x07pnr\x06\x83\x81`\x98M\xd1\x16NO\xb0\\\xa15\n\xf3\xd9\xd7\xd8\xc0\xd7\x92\x93\x04f:u\xf5\xf1\xcb@%N-I\x86\x9bj\xe4w\x9a,\x93n`\xd0s\xd6\x12\xd3\x0c\x0co\xca\xe2\x91cs\xe6g\xa7zr\x00F\x0cg\xee\xca\xe0\x96\xc3\xfb;\x10\xdd\xf2v\xc7\xb3\xbdG\xdb\xe2)\x1b\x00\xb1\xd5\xc5.Ek\xfd\x12*5Z\x0b\xc1X\x1f\xeby\x96#$\x8f\xf2%O\xd0\x01\xfe\x86%\xd0\xe8)\xef*]Q[\xf3\x80\x96\xb5\x13b\x82\xc6\xbe\x07\xdf{\xbf\x83[\xe9\xb7D\x93\x8e\x9d'\x1b\xcf\xea\x08\xc4\xf6\xd9\xd0Bv\x18uz\xb8\xc1\xfao\xa3E\x80\xb7\x9e\x14A\xe3M\xa3*\xca\x927\x95\xe0&\xf5 >Iyr&\x86.\xce\xdcp\x0bXK\x1a\xc9\xa0\xbc\xe2P\xad\x12{\x10\xd1]+\xb4\x8fvr\x19:\xc7\xd6\n\x92;\xf0\xf7\x02\x91\x8a\x80\xc7\xf0\xcf\x00Bn\xa4\x98[\x8fYP\x11\xf0\x04\xb4\xcb\xa2\xb3\xc2)N@\xc8f\xb6<\x1a\xc4|\xecO\xf0\xe2\xa7xA\x07G\xb6\xbd\x8ai\"\x11\xbd\xc7u\xeb\xab-\x93\xd8\xa6\x16F\x8a\xe6\xbc6:\x08\xca\xaa +\x04\x04E\xc5F\x91\xe9\x99\xe6a\xabY\xf2\x85\x07C\xec\xbamm\xeaO\x06\x1e\xc7\x04;\xfb\xe2\xe5\x8bw\x8d\xc5?\xb4\\Q\xd5No\xb1\xcb\xb2E\x12\x9f\x83P\x05n\x119w\xdf\xf0Y>\xe5 \xeb\xdde}\x96\x81\x1b\x90\x9e\xc4`>c\xc5V\xc9fy\x82*[\x90 \x05\xdfH\xe3\x9b\x17sT\xaf\x81\xd8g\xe5\xa7)j\xe2DZ\"[\x0e\xd2\xb2\x19\x8f]\xc69\xca5\xf8\xc5*\x0c\xa6A\x16^\x16\x0bf\xc1U\xfb\xd8\xe0\x80\xbd\xab'\x81\xfe-\x8a\xc1B\xb0h\x15\xba!\x1a\x9e\xc5\xd1\xdd\x8c\x9d\xfbQ&:\x91\xf2\x8c\xf9\xd2\x01\x81X'\xa0\xbf\x93\xbd\xc2\x8eL\xfd\x08\x0c?\x80\xb9\x91\x86\x83,\x9ek-7\xb9\x96\x11\xd3\x1f -\x10\xad^\xdc{\xfd\xe6\xd5\xa7\x87\xc7_\xbd\xfc\xcd\x97\xaf~\xfc\xf2\xf8\xd9\xf3w/^\xbd<\xee\xb1>\xfb\xd2\xcf\x16\x83\xc4\x8ff\xf1\xd2q+\xa1\xcd\xb5\xe0\x9e{\xee ]\x85A\xe6\xf4z*\x80o\xe3\xe7k\x93\xdb\x15\xbd\x10\xb5\xe8\xed\x86\x01>\xdd\x00K@\xbb\xbfJ\xe2\x13\xf1\x1ed\x0b\xe63\x1c6|v\xc0>\x83 \x12\xcb5\x8b\xd9\xc2\x8ff!z\x99P\x98\xce\xfa\xec.\x8b\x13\x16g\x0b\x9e0\x1f\xd6 \x88\x18z\x08\xe1Ozh\xd6\xb5\xf2\xd1<\x8a_\x82\x8d\xd54\x06/\xa3 X\x96\x06g\x80:\x85yO\x81q\x1a\x9aM\xf3$\x01\xa3\x03\xc0)\x81\x1c~t\xc9\xf2\xe8}\x14\x9fG\xea\xbb\x1e\xcb\xa3\x90\xa7)\x0b\xb2\x1a\x12\x07\x11;_\x04\xd3\x05\xde \xa4>PAZ\x8f%\xfc\xd4Of\xd0X\x8c+\x06\xbf!\xc1\xd2\x0d\xcd\xd1\xa9\x86\xc0\xd9\x13D\xd9\xc1]\x8b&\x86\xd0\xfe95\xd3\xa0\xca\x01\xd3(\x0e\xc2\xf1\x06\xfa\xddEo)\x96\x87\xd83\x0b\x9d\xa4\xd2`\xc6\xb2\x12\x14\xc9\x80\x8f\xb2\xf8*/\xbd\xbc\x88\xceb4\xdcz\xed'>\x84u\xff\xb2\xf0\xb1\x9b\x15\xac\x84\xf4\xf4@\x124\xf0\x16$\xb6\xae]\x97\xd8\xbbD\xd6\x83]#+(\xb2\xf6\\\xf2X\xeb[\x95\xba\xd2v\xa4\xb2\xfey\xf3\xfa\xb7\x1e\xc0\xb5\x05_\x1bj\xa2\xe6\xd8[\x0bd\xb1^\x8d\x82\xff/1\xe9\x15\xbds\x04\xe5%\xa61P3L\xcdU\xf0}\xcf\x15E\x9c\xed\x8e\x9f\x82\x1a\x89\xa6\x0e\xb5\x1b\x81\xa4\xb9\xa5'\xbb\xb7Y\x9cp6\x8b9zc^\xf8g\x1c%\xf3\xc1L\xc9\x1c\x06\xecK\xff=g\xf2*//#\x8c\x94J\x85\xfa\xe6\x1b\xa4\xday\xf7|\x11\xa7\x1c\xa7&\x05\x99\xb0l7\x1d\x10\xc1k}I'\x0b\x14s\x0d\xed\x13\xba\x0d-\xb6\x84\x17\x19\xaaM\x07A\xaa^\xf5\xb8.\x85\xbbd\x1f$\xd8A\x8aB\x91\xe2\\\x9e\xd5\xa2\xa2\xa8\xc1e18&\x88*\x81\xdf^,\x979\xc4\x83/\xbeZ\xdec\x9a\xc7a\x18\x9f\x07\xd1\xa9rx\x10\x80S\xaa\xbb\xac\xcf\x02T\x1a\xdc\xedy\xacw\x17eL\x83\xbb\xe6\xd8\xe1\xc0%f\xef-\xff\x19(#\xf0\\\xe8\x0e\xe6A\x98\xf1\xa4\xe5\xa8 \xc7\xbba\xdc\xdf\xaa\x1da\xeaZ)Y/\xd7e\xc0\x07\xac\xa7]\x19\x04\x81\x04^\x94,J\x1d\xb0\x9e\xf2\xeb\xd0c\xa3\xe2G\xc0S\x14\x97\xe1\xc0ss\xe0l\x1e\xe7\x118\xa5\xbe\xab&E\x03\x7f\x16\xb3y\x10\x15a\x83\x04\\Q\xf0\xaf\xe4_\x853 \xbcC.\xc5\x1a\x0dp\xd6\xef>\x96\x9dD\xff\x13'\\J\xeaf\x83\xbbuw\xca\xb7\xbf\x1b\xde\x1aE\xf3\xd6\"\x0euo\x9c]tH\xa4d\x13UH\xa0\x1a\x12X\xaed\xa7\x97+)\x0bEQ\xe7\xad\xc8?\xeb\x02(M\xb6y+\x13\xa4W\xacB\xab\xa0\xd0b\xd7\xae\x07\x00/\xe7\xa9:#]>\x199\x8fP\xc4\xfd\xe8\xa1[\xedy\xe4<\xd8\xdb\xead\xe0Y\x1e\xa1\x87\x86\xafC\xe9l\xf0\x91\xeb\xf4\x8a\xd8\xe0\xa4\xad\xf3\xde\x96\xc5\x8a;r\x86\x0f\\\x8d\x8a\xaeq*\xb0\x1d\x084ER6\x8e\xd1c\xad\x16\xbb\x1c\xee\x14@4\x81:\xcdJ\x1c]~\xd7 \xc0\xcdV\x86\xf7~\xe2\xfc\xca\xf6\xd6\xd5Q\xea~\xe2\xfc\xd4?\xf3\xd3i\x12\xac\xb2\xab\x99\x9f\xf9\xee\xbd`i\xc2\xf2\xde\xf8'G\x17\xdb[\x9bG\x17{\x87\x93{\xa7\xf5\"\x01\xb69\xfe\xc9h\xd2wG\xf7N\x97\xe6qk\xdc\x1b\x08Bt\xaf7\xa1\xe1]\x05h\xeaGA\x16|\xc3\xbfJ\xc26a\xd5\x99\xb4\xb5\xf1\xe4\x8e!\xaf\x95\x89cA\x8fRKw\x12\x10j\x05\xfd\x010\xec\xaf\xe6\x0e\x1foM\\\xf6\x94m\x12\xee\x97\x9d\xdc\x95&\xe7N\x04\x12\xc0\xa5\x9fM\x17N\xe0\x8ad4\xd9\x11\x873\x96\x0c2\x9ef\xe8\xb6\xa4\xe7\x9f\xc4y6: \xfd\xe8\xbd\xd86r\xb8\x1d\xae'V\xbe\xb3\xa6\x15e\xb9<\x1e\xd8\xec\xff\x1f\x0e]#\xdci\xc3f\n.\xa2\x07Y\xfcE|\xce\x93\xe7~\xca\x1dpG\x02\xfa\xa3\x03&\x90\x94\x8d\x0c\x1f\x1f\x96\xe5\x15\xaf7\x84]\xca\x9e>r\xb6\x1f\xda\x96\xaf}z\x95\xb0\xdbI\x1c\xeeVG\xb3\xe6\x1a+\xbb\xb7W\x17]|/\xa6\xe4`H\xdelF\xde\x0d$g\xff\xbf1y1\xc7\xf5 \x8e\xba\xd9\x8cw\x03t!d\xb9\x96\xe5\xb8\xbe\xa2)\x84\x13\xeb\xc1r\xa3g\x8f\xf2\xaf\x0b\xcb\xea\x9aCh\x96\xf5\x80\xc5\x03\x19\x94@\x814F\x12\x18 \xd1\x90\xe2y\xa34\x93\xa8\x0e\x96\x91hd\x91\x0d\xa6\x0b?y\x969[\x16%L*\xcb'N\xe4\xb1\xa1\xb2P\x82\x08!\xd9 \x0d\x83)w\x1a\"\xb0\xe4c>\x01\xc5wU\xd8\x7fm\xda\xbb\xfd\xb0\x1d\xc4\xf6cl\x0c;\x9a\x14\xdf\x93\x98T,2\xe9\x02\xea\x80\xc5\x82w\xf7\xd8\x06\x98\x01D\xec\xe9>\x8b\x95Ux\xf1\xa9\xeb\x8e\xe6\xc1^\x9d l\xc1\xbb\x9b\xd0g\x8e\x08\x02\x97\xb4\x92\xf6\xc5b\xe3h[\xbf\xc4Ks\xb65>\xa1\x10\xb97>:\xcag\x0f\xb7\xb66\xc5\xff\xf9|^\xbf\xf4\x96\xa8B[;Xhkgw~t\x94\xcf\xf96\xfc\x9c\xf3m\xf1s{k\x06?\xb7\xb7\xcc&\xe0\xc6\x00|fg:\xc6\xcf\x9c\xd8>\x07\x86~\xe3\x9f\xb4t\n.\xf49\x07#\xbd\xd1\x19\xdf\x85\xe2\xb3\xf9|\xe2\xfe|\xfb\x03y\xc5Oo\xf7d>\x9f@\xc2\xd4\xfe\xa1T~\xa8\x08\xe1sU\x84\x01r\xc5[\xef\xa0V!T\x9f\x99\xf3-\x8e\xff\xe6\x93\x03\x15\xe1\xc9\x91\x9d\xde\xde\xda\x9a\xc9V\xc7\x18\x93)\x9f\xc8\x95~\x85A\xe2\\k\x1b=\xf7\x93\xfaY`\xaa\xf5r\x1c\xa8\xae\x1e\xf4\xf0\x1a<(\x08\xa3z\xfb\xb5~\xcf\xd9\xbe\x0c\x8c\xe0\xc0\xe8\x9c\x83\xfdr\xa40\xe8)F\x8a\xec\x9d\xf6\xae\xbb&\xb8\xe4*\xe7p_t<\xb9\xee2\xde~hc\x08m\xcb\x98\xf2%/G\xdb\x1b\xdf\xfdo\xbf\xf3\xbb\x93\xde\x8dF\xd6\xbc\x9d\xa8\xdd\xdd \x1c\xb1o\x14,\xbe\x0f,\xbe\x0b\xce\x1ez\xbd\x1b\xdd9\xd2h\x9c\x058\x06\x0b\n\x87\x9e\xf1\xd1\xc5T\x1c\x8bf\xbbG\x17\xb3\x87\x9bG\x17\xf3\xdd\xa3\x8b9\xbc\xcc\x8f\xf2\xad\xa1X\x19\xf9\xd6po>\xb9w\xda\x00\xc2u\xc9\xc3M`\xed\x80\xd0\x1a\xa4\x82 \xa9U\xd0\x0c<\x96\xd4a{} \xdew\x9d\xea\xd7{\x7f\xf8;\xbd\x11\xeb=\xab\xad\x9b\xde\x1f\xfe1:\xf9\x8f\xd3\xc9\x7f\x82N\xfe\x1f\xe8\xe4?I'\xffC\x91\xec\x1b\xc9\xff\x88N\xfe\xc7t\xf2?\xa1\x93\xff)\x9d\xfc\xcf\xe8\xe4?-\x92\x9f\x1b\xc9\xff\\$O\x8d\xe4\xbf\"\x92\xeb\xde\xf1{\x7f\xf8\xefD\xf2\xccH\xfe3\"\xb9\xee;\xbe\xf7\x87\x7f\x96N\xfest\xf2\x9f\xa7\x93\xffg\x91\xcc\x8d\xe4\xff\x85N\xfe\x17t\xf2\xbf\xa4\x93\xff\x82H~a$\xffE:\xf9/\xd1\xc9\x7f\x99N\xfeW\"90\x92\xff5\x9d\xfco\xe8\xe4\x7fK'\xffU\x91\xfc\xd2H\xfe\xf7\"92\x92\xffG\x91\xfc\xcaH\xfe\x9f\xe8\xe4\xbfF'\xffu:\xf9o\xd0\xc9\x7f\x8bN\xfe\x0f\"96\x92\xff#\x9d\xfc\xbf\xd2\xc9\xff\x1b\x9d\xfc\xbf\xd3\xc9\xff\x89N\xfe]\x91\xfc\x95\x91\xfc\xb7\xe9\xe4\xbfC'\xff]:\xf9\xff\x14\xc9\xb9\x91\xfc\x7f\xd1\xc9\xff\x99N\xfe/t\xf2\xdf\x13\xc9\xf5\xd8\x01\xbd?\xfc}\x91|i$\xff\x01\x9d\xfc\xa7D\xf23s9\xfc\x9eH\xf7\xcd\xf4\xbf/\xd2\xdf-\x8c\xf4\xff*\xd233\xfd\x1f\x88\xf44\xad\xa7\x7fK\x93\xe5oi\xfa\xfb-Mh\xbf\x05\"n\x90\xb7o\xff\x04\x9d\xfc'\xe9d\x80\x80A\x0c\xbf\xfd3t\xf2\x9f\xa3\x93\xff\x02\x9d\x0c\x84\xd6\xa0\xa8\xdf\xfeY:\xf9\xcf\xd3\xc9\x7f\x91N\x06\x12d\x90\xe5oij\xfd-P&\x83Z\x7f\xfbW\xe9d \x13\x06\xfd\xfd\xf6\xaf\xd1\xc9\x7f\x83N\xfe[t\xf2\xdf\xa6\x93\x81\x04\x19\xf8\xf6\xed_\xa7\x93\xff&\x9d\xfc\xbbt\xf2\xdf\xa1\x93a\xcd\xfe\x9a\x91\xfc\xf7\xe9\xe4\x7fH'\xffc:\x19\x16\xe7\xa9\x91\xfc\x0f\xe8\xe4\x7fD'\xff\x13:\x196\xfb_7\x92\x7f\x8fN\x06\x1e\xc0X\x98\xdf\xfes:\x19\xb6Xc\x07\xfb\xf6_\xd0\xc9\xff\x8aN\xfe7t\xf2\xbf\xa3\x93a\xfb66\xb6o\xff%\x9dLo\x9a\xdf\xd2\xbb\xe3\xb7\xff\x9eN\x86\xed\xe47\x8cd\xd8N~j$\xc3v\xf2\x9bF\xf2\xff!\x92\xdf\x1b\xc9\xff\x89N\x86\x9d\xe0\x0b#\xf9?\xd3\xc9\xbfO'\xff\x01\x99\xfc\xdd\x1f\xa3K\xc3.\x13\x1a\xc9\xff\x85N\xfe\xafd\xf2w\xbfC'\xffq:\x19H\xaf\xc1\x8d|\xf7'\xe9\xe4?M'\xff9:\x196\x01\x83\xa5\xf9\xeeO\xd1\xc9\x7f\x86N\xfe\xf3t2\xd0o\x83I\xf9\xee/\xd1\xc9\x7f\x85N\x06Bm\xf0\x17\xdf\xfde:\xf9\xaf\xd2\xc9@c\xdf\x18\xc9\x7f\x83N\xfe[t2P\xcd\xc4H\xfe\x9bt\xf2\xef\xd2\xc9@\xa8\xdf\x1a\xc9\x7f\x97N\xfe\xfbt\xf2?\xa4\x93\x81\"\x1b\\\xc1w\x7f\x8fN\xfe\x07t\xf2?\xa2\x93\x81\"\xbf3\x92\xff)\x9d\xfc{t2\x90\xde\xccH\xfegt\xf2?\xa7\x93\x81\x98\x1aL\xe1w\xff\x82N\xfeWt\xf2\xbf\xa1\x93\xff\x1d\x9d\xfc\x1f\xe8d\xa0\xb1\x06\x0b\xf9\xdd\xbf\xa4\x93\xff5\x9d\xfco\xe9\xe4\x7fO'\xffG:\x19H\xef\x8f\x8dd \xbd\xe7F2\x90^\x83\xc7\xfd\x0eH\xaf\xc1\xcc~\xf7\x9f\xe8\xd2@z\x7f\xdbH\xfe\xcft\xf2\xef\xd3\xc9@L\xbf1\x92\xff\x0b\x9d\xfc_\xc9\xe4oav^\x98\x1b\x0f\xc0*0v\x9e\xef\xf0\xb8fp.\xdf\x01\xb3\x14\x9b\xe9\xc0X\xde5\xc9\x1b\xec\x1bi\xa9\xd9\xb5)Hi\x8f>\xd7\x16rw\x12\xb0\x11\xce\xd4F`\xa3[\xa9p\x03\xc9Z=\xf6\xa3\x12;R\x96\xdf\x84\xc4M\x9am?l\xf7\xbcG\xabT\n\x0b\xc5}\xd0+x\xba\xea\x04u\xf4\xfa\xc0AA%\xd5\x10~\xa9\x86\x80\x00T(\x87\xcd\xba\xc9a)\xb5\x01\x18Tlmm\x1e]l\xcf\x8f.v\xfc\xcd\xa3\x8b\xfb[G\x17\x0fN6\x8f.v\xb7\x8e.\xf6\xc4\xcb\xde|\xd2\xbfw]%\xa3\xeadt\x93N\xfa\x9b\xdfL\xc6\xcf6\x7f{r\x05\x7f\x7f\xbe\xed}\x80\xb4\xab\xf1\xd6\xe6\xa3\x89x\xc5L\xf9\x02\xa9W\xe3\x9f\xe0\xcf\xad\xcdGlr\xef\x9a\xdd\x8f\xd0Pb-\xb5O\xa1\x939:\xba\xf0\xa7GG\x17'\xc3\xa3\xa3\x8b\xd9\xde\xd1\xd1\xc5\\\xfc\x01\x01\xab\x008B\x1c@\x8e0\x07\xa0#\xd4\x8f.NP\xe0\xba%\x05\xae\xbbsvt\x94\x89\xea'GG\xa2\xae\xbf\x05r\xd9\xf9\xfc\xe8(::J\xa0\xd0\xf6C\xfc\xf7\xe8\xe8(\x1f\xee>\x14%\x86\x0fA\xf9 \x1a\xc2\x7fC\xfc\xb7\x8d\xffv\xf0\xdf}\xfc\xf7\x00\xff\xed\xe2\xbf=\xfc\x87mn=\xc2\x7f>~\x01;\xf7@\xfc\xdb\xd9\xda\xda\xaa\x11\x18\xd46\xf5X\x9fE\xac\xcfz\x16M\xd2\xac\xdf3\x17\x1cH\xa1\xb7\xf7\xe4\xb0\xf7Nh\xa5\x91\x98j\x01\xd4\xb9\x80\xd4|\xf7\x08\xa5\xddG\x17\xa6\xea''5Q\xaak\xa0\x18\xa9}\xd0\xda\xf4\xb3\xcd\xdf>BA;H\xdaQ\xd4~t1\xe36u\xd3\x1az\xad\xf0Zz-\xd0\x18\x8d;\xf7k\xae)\x98\xfcB\x0d\x96S\x8a\xa4\x95Vt\xda\\t&\x8b\xae\xa9>\xb8\xb2\xa9\x12\xdd\xba2naU\xc6\xcd,\xca8R\xf5\xc8R\x8f\x85\x9d\xf4s3Z?wV\xd1\xcf\xd1\xed\x89\xbc\xda}\xcbe\xa9b\x19OQ\xa3\xa7\xe0\xdf\x17`\x03\xc5\x95s0\x9a]\x85\xe1\xd5\xf2*\xe1W\xe9Uvu\xc6]\xf7@\xaa\xef\xc6\x89\xc7\xa6\x1e\xeb\xfd\xb0g\xaa\xff\xd8\xcah\xe8\xb3\xab/\xbe\xb8\xfa\xf2\xea\xcd\xe1\xd5\xdb\xabwW?:\xac5\xc4\xfalnk\xac\xec\xdf\xbcK\xffT\x8d\xb6\xcf\xf79\xc0\x1d\xeb\x87\xd7\xa6\xec\x1b\xce\x06\xd8t \xea\xa6l\x10\xc0\x14\x97\x1d\xb0\x15\x18A#\xe3\xef\x17\x0eG\xd9Z\xa8S\xdc\xb5~d\xbdk}o\xfc\x93\xc1\xa4\xff\xc3{\x03~\xc1\xa7N,z\x10\xc35\xb1\xf2m\xf0\xe2\xf0\xf8\xf5\x9bW\xef^\x81\x91~\x0f\xac\xb8{\xe8\xc8\xd1I\x93\xa9{<\x1c\xa0E\xd3\x88\xf5z\xd7\x85\xc4F >\x18@`\xd6k\x8c\x14\x91~\xcf\x1d\xf7\x8e\x8f\xa7q\xc27\x7f\x9a\x1e\xa7\x0b?\xe1\xb3\xe3c\x9b\x95\xfdu\xa5\nv\xdf6\xed2\x83\xf6s[7\xb0\xa9\xad\x01\x88\xcb\xc2\x87\xcd\xe3\xce\x1de\xde[!JcN{\x05)\xe9\xd2\xe6>\xcb\xd8\x01\x1b\xb2\x11l\xda\xd7\x05\xbf\xa0\x9e\xc4 \xeb\xf88\x8cg~\xba8\x16{\xfdqqg\xe8\xf8\x988v\xb5\xb8OX\x17\xb9*PR\xf0\xa8\x02#\x983\xc7pZ\xcc\xb4\xf3sf\xc0\x8fULN\xf7\xd1\xa6\xb4\x98\xee\xa6@J\xb2VPx\x15\x86\x95.\xbeP\xd8\xfd\xde.\xf0\xbf\x7fx\x16\xc6\xe7\x07\xd5+>0\xc4X\x1b\xf8\xed\x0e\xb4\x01\xcb\xda\x06\xd9\xe4=\xacu\x9c\xe5\"\xeaW\x17#rdC\x8fEb\xe8\xfbh\x8d\xaf\x89\xd82i\x9d\x9c!\x83pS\x02\xd1\xc6\x96\x8c'\xb7\xc4\x88\x0cw(\xf6\x18\x83\xd7h\xcc\xd8*\x0c\xa6\xbc\x0d\xf2\x9d\xd0\x8bf}\x13D\"rN6\x9c\x88=A\xc7\x11N\x04\x9e\xa0\xd4\xd5\xd4M6\x14\xebm\xb0\x8a\xd1WD\x89\x8f`\x1e\xef\xb1\xcd\xcd\x02H\x1e\xdb\xba\xd6\x9e[@\xe9\x174z\x1c\xbb.\xba\x1dG\x93\xf1\xb0m\x0b\xba\xd5\xa1\x146\xaa\xd5\xb1\x08rW\xb91\xf6\x11\xba\xd2u5\x9b\x80\x8d\x01\xb0\x91\x15\xb0\xb1\x04\xac\xd3\xefkH\x12a\xec\xd0\xb1\xf8\xf0\xc4\x85\x08P\xe3X\xc0[F9j_\xdb\x0d\xc3\xddn\x1d\xae\x0d\x89\x12\x15\xf9\xcd\x95G+\xdb-\xa1\xebr\x01\xad\x14\xc9\x8e\xdf\xd2S\x1d\xd9\x9d\x1e\x9e\xe8\xd1\x81\x1b\xf0\x9bQ\xbe<\xe1\x89\x96\x90\x02\xe7\xa9%\x9c\xc4q\xc8}\xe9\xf4M\xf0\xa6\xc7\xc7@\x89\x8e\x8f{2\x10\xc0Hs\xce\xf7}\xceFe\x1d\xc0d\x9c\xf2\x0eb\xfc\x8f\xdc\x07\xdc\xa1>f\x1f\x1a\x16a\xd9\x0fz\x05F\x80\x8c4e\x03\xc1\x034\xeeU7\xdeHnk\xc8\x8a\xc9\x8d\xf7fK\x8f\xb6{7\xae\x8eI\xe5\xdc\xfdV\x90X\xa6\xa5(\x80{\x10\xe9u\xef\xac\xe2w\x9d\xbcI\x06\x8e/b's\xa9\xfa\xaa\x8dT\x11\xb8\x1d\xa2\x05&o\xaa\x05\xe0{(j\xec\xbb\xfe\xc8q\xa4N>\xe6\x13\xb8|\x90wu3k\xa6\x9cI\x8f\xbc\xbc\x00\x87\x95\xf3\x0ea'a\x07,\x1f\xa7\xc0C\x87\x82\xc1\x0c F\x9a\xb1\x1bH\x03w\x87\xf5[ \xf2\x02\x84!`AL\xd8~\xd4*A\xb2\x12\xc6\xd8F\xa3\x87\x15&\xe6\xce\x1d\x96\x8d\xb7&\xe3\xed \xde\x19\x14\xef[\x82\xbd\x13/\xc3\x89\xd8\x82\x8ao5\xdd`\x8e\xa4\x13Q\x88\xb6\x16QAB\xaf\x0d\xb5\xa1qwF]\x8d\xa3\xa064%U\xdbm0\xc4\xaf\x0bd#\x80\x99\x02\x1d\x91n4\x8d\xe1\x0b\x04K\xcd\xe4)\xdbg\x1b\xb9y8,\xce\xf4\x85\xdf\x98\x8dZ\xfc\n\x10\xb0\xf2\x8a\xc7\x03\x96nnZ\xa5\xabs\xd1\xbdqjq}=\x85`\xa18\xbbs\xc1G\xc0\x166\x9e\x8f\xb7&\x02\xb97\x1c\xf1\x06b\x92\xd2\x93\xcdFS\xac\x0f\xe8\xdec\xd6\xef\xa7\xec \x0b\xad\xbdZ\xb1}\xe6\xa8\xae\xb9V\xe7i3\x10\x0d\xaf,\xb9\x0b1IV\xaf\xde\xc5\xd0l\x04\xa5\xe6\x90\x04B\xdco8\xab\xe6\xd1\x8aG\xc6}\xb7\xd3\xbe3\x86Q)\x1bBQ\xe7.\x94\\\xb2}\x96;3\x8f-<\xb6\xc2U\xe1\xb13\x0b\xc5\x04\xba\xabwy f\x12\x0b\x8f\xcd<\x16\xb0+y_\xeeL,\xcae\xf3\x08\x1afP\xd5\xba\xc1\xa1\xad\xf5\xeai}J\xea\x07HT\xd1\xacu\x86\xbc\x01\x8b\xd8~\x04\xca:\xf3\xb5\xa2\xac\xe4\xd5o\xbd\xc3\xfa\xc7T\x7f\xbb\xf1x\xb7\xf4\xad\x9b\xf2r\x16\x8d\xe0C\xea~\x9fH\xaf\x97\x07b\xbd\xd5\xead\xa1\xeb\xa9\x8c \xbfLy\xd9\x8a\xe7ft1\xa6\xb1G\x91\xa5\x15V\xf0Gb\xab+\xdcT=a>\xdbd\xc3bM\xe6\x95\x83\\\x15\xd3\xfb\xfdH\xa2\x90H5\x9b7\xc6!\x17L\xe0\xe4\x1d\\M[\xf8Z\xc5\xd6\xde\x90\x93\xb5n\xc5u1\x9ade\xb7\xa9x\xa7\"\x9d\xd2\x1c \x14\xaa\xab?Sl\xbf\xaeq\x08ew\xea\xcdL%\xdfTO\x9f\x9b\x9c\xc1J\x0f\xac\xfaLy\xf0\xac\x9b\x97\xcc\xaa\xa5\x12\xff\xb2^b\xa1\x97\xc0M\xbb^\xe4\xec\xe6\xc2S\xc5\xa2,=v\xea\xb1K\n\xffO\x04+\xe2PG\xa1c\xc8\xc9\x88\x9cs\xb6\xcfN\xd8\x01\x9b\xb1\x11\xcb\xc9\xba\x87l\x9f\x1d\x17%\xa86.\xc4^/\x1a:\x17\x9c\xcd\x8a\x1d\xb0\x05\x1b\xb1sW\xfc\"8\xa6\xb7\xa2\xb8h\xf5P/~h+\xfe\\5|h.\xe7\xe7bK\x0fA\xd7e\xaedX\xa5!\x9cb\x8a\x8d\xd2\\l'\xe0+\xc5\x83A42>\xc5\xf76.\x8a\x06/A*x\xa964\xd7c'\"e\x8a\"\xdb\x98\x98\xb5\x11\x0bd\xeay%\xc3\x1c\xdb\x86\x13\xb1;lN\x0eM\xcc\xf6{\xb6\xcf.@\x0c\\\xb8\x96\xe9\x1d\x1f\x9f'\xfej\x05\x82jb\xa2\xc4\xf3\x8c\xed\xb3\xb7Z\xb5\xac^\x8d&w\xef\xc5\xb8\x9e5\x9d\x07_\xb1}\xf6\x9e\x1d0>\x00Wr \x11mp\x9a\xfe\x9a\xed\xb3g >-\x8bg4[d\x05\xf6\xa9\xf3\xcac\xaf\x15\x1c/\xdb|^\xd3l\xd0\x06L\xaac\xb6\xee\x9b\xd3w\xfd\xad\xd1\xd8\xea\xe4\xc1o\x9b6\x96\xd9\xdd\x1ev\xf5\xe3zv\xcbf\x1du.M\xb7\xef\x80\x02\xfel\xe6\x80w\xe1\x1a0\xc4\xe3k\xf4\xcd\x9f\xcd\xc0\xabP\x99\"\xb6D4\xca\xf0\x0d\xfb\x8b\xa0jj\xe1\x93\xf0\xad\x037\xba\x99\xae\xa6\x13O$w\xd3\xc8\xed\xb4s~\x9f\x8cX\xfb\xb7\xec\xbae\x00\xbb\x93\xb5}\xc2\x8a\xd06/I\x86\xb9\x93d\xf5\xb6(7\x17\x14\xdf\x90K\xfc\xafo\xf8\xa9L\xaf\xb7\x13\x9a\x1b\xbb\xe0\x01\xb6\xcd\xed\xbf\xd8\xa3?E o}\x93\xae\xf0\x03\x9f\xf9\x99aiZa\x05\xc0\xa3e#+\xf0\xa5\xbf\xa2\xf8\x00-\xd8\xfb\xf2\x84\x1bM,\xf5\"h\x97R/r\xaa\x17y\xcb\x0dn\xe3\xb2\x92\x0f\x12\xf0z\x91\x93J\x11\x10\x81\xd7\x8b\x1c\x1b\x8c\xcf\xa7\xf9|nv\xf8\xbc\x066\xffG\x01?\xaf\x17:,\x9c\xaa\x15\xeb\xde\xe2\x9b\xea\x02\x18\x83\x03v\x88\xfb\xc2\xabyg\xd7k\x8aX'\x1e;\xf4\xd8[\x8f=\xaf\xe3~z\x1e\x80\x0f4R\x8e\x05q\xdc\xceGF:\x93; \x1f\x9c\\f\xfc\x0bd\xf77\xc41P\xfb}u\xc50\xff\xd5|\x9e\xf2\xac\xcc\xc7\xdf\x8d\x1c\x88x8x\xa3:\x01\x00{\xd2\x1b \xfe2\xcbCG\x8f\xe9\x8e\x16:\xcb\xb6\xden\xbcu\x04u\x8f1\x18\x0c\xbce\xaeKl\xfe\xf0\xb5\xb9\xf95H_Y\xd2\xcf\x1a{\x178}\xee\xb1>%y\x86\xda\xb3\xc6\xda|\x10\x81Oq1&x\x03O+K\xe53\x1c\xc2\x9d\xe0\x0fK\xf3KK\xa7/\x9b?\x8b\xfa\xa0~\xc5(\xa9R\x7fA\xd7W\xbcZn\xa9vj\xaf\xf6\x0c5\xfd,\xb4\x8b\x8b\x80/sD\xfb)x{\x85\xb3\xde\x86\x12R\x00\xbb\xfa\xac\x15\xfb\x14\xfb\xf6\\\n\x1b\xec\x9f{U\xb4\xf5\n\xe0aa\xd8\xd8\xd5>\x9bz\xecyy\x14\xb5\x7f\xf858\xb4{\x0f\x88\xf8\x1eC\x15\x94\x0b\xb8\x91!|^\nm<\xf6\xda\x02\xde\x13\xfb\x8a.\xf9\xf8\x0b\xe55P\x0cJ\xfe\xb0J\xaf\x99\xb6\xce\xda\x94\xcf\xed[\xf4\xba\xec\x9c\x0c\xe1\x04\xd3K\xcb\xaa\xb8\x195\x82\n\xa5\x0e\x0d\x8e\xfb\xfdl\xc2\xf6\xc1\x86\x9e\xd7\xee\xa2\xb9\x1fC\xc4\xf5q\x86\xd786\xbe\xf6\xb0\xecv\xb3\x8f(\xf1\xc7\xd0\xe4xn\xe9\xb0\x8f\xf2\xde\x94\x02\"\x08@\xd8\x1d\x16\x9bp\x9c\x82f\x8e:\xcb\x0b6hJ\xf2\xffb=\xcc\x05\xe1H\x9c\xcc\xd5tC\x1b\xa1\x95z\x14\xd1\x8a\x04\xe34\x7f\xccV\x0dJ\n\xc1:M\xc7+\x8b$\x7f\xc3 A\xc0\x00^\x9aG\x9aA\xdb\xcc\xed\xa8\x95\x10\xdfX\x80\x190E\xc1\xc47`4\xa9\x0c\x87R4\xba \xa8\x98\x12\xf0o\xd4\xbc\xab\xa6\xba`-U\xf1P\xea\xdf*\xa0\"\x18\xb9P\x1c\x9eV\xec \x9b[!s\n\x1a\x10\x05\x1f\x8b\"\xe4\x12,\x07g\x16\xf0\xf9n!\xfe \xe1B\xe5%\x1cWg\x80E\x1c\xf0g\xc4|G\x9c`!\x15\xd1+\xb5)~u\x05\xc4 ;\x10=\xdc\xdf\xc7\xd3w.\x1bA\xd4\x84vO\xecJb\x90\xa8\xd0\x14\xfc$\xe1\xfe{#\xc7T\xe1.a{\x03\x9exZ\x1a\x92\x83m\xc6\xac\x89>\x83\xea\x07\xf0wi\x03\xfc1\xb0\\Z\xab4\xe8\xcf\x81\x17\xd3\x8a\x99\x03:\x16\xeb\xe6\\|\xad\xda\xc9@F\xec0R3\xd4D\x91\x01\x06\x8fE\xde\xb1.\xa6\x86\x14\xb2,|\xf3\\/{\x8eF\xdf\x08\xfa\x0e\x1bX\xaao\xa1\xc5\x0f\x81\xe0g?\xa8V\\\x9f\xf4\x13\x87\xcfJ|\xc7\xcd!F\x83\xb5 (\xd0\xdc|\x0b\x03>\x8e'b)E\xec K\xacK\xc9\x87\xa5T\x8fZ(\x9e\xcc\xf1\x01i\xd1\xac\xd9 \xc6q\xbf\x0f\xb1\x0e;\x80(\xf8\xde\x00\xa1\xa23\xaa\x91\xf2\xc7.K0(cf\x04'\x91\xbdKZzg7E\xa0\x05\xf9\xf7\xa9\xfb\xe2\x94\x94\xbcm\x0b\xb3\xc8\x1dbiZ\x9eHf\xeb\xc6\xd0\xb5|\xa7\x953[\x170C\xcbMz\x03`>\x84)-\xc1\xe3\x8f\x0b\xf0}\x1e\xc6~\xb6\xb3-\xb5\x08\x80\x80\xb5\xcc\xdd\xfbt\xe6\x8b({h\xcd\x19\xeeZ\xb3l\x1f\xfb*\xb06\x08Y\xcfC\x7f\xb9\xe23{ \xdb7E^\xe5\xa3\x1b[\x9e\x9e\xafaP\xad&\xdd^E\xf0P\xcb+\xe48\xb5\xf4R\x08afp#Q\nr\xea\xb3!q\xc5\xc8\x00\xa9N-MIrj\xc9J\x17TKVB\x9dZ2\x08r\xeaiRxSK\xfe1\xf7\xdf\x17\xfd\xd8\x18z\xeb-\xc1@.\xc1\xd8\xe1E\x94&\xb1\x1fm\xf8c\xb1*o`\xdaK\xfb\xa0\xd85\xac\xdfn\x81C\xae\x8f\x0dc5\xe9\xf1\x98L\xfb'u\xf6\x18O,,[$6\xe7\xc2\xec\xc6\xd5\x9c\xf6G\xae\xb9\x91o\x00\x03~\x87e\xa8\xea\xb5\x10\xe86\xcb\xd7\x86\xb3\xc6\x9e\xebh\x81\xb6<\xd93\x8b\xe9\x05}\xfd\xc8N\xe5v\\\x07\xae8y\xac\xa7\xd6\x8b\xed\xe2\xd9\x0d\x9a~\x9d\xc4\xcb \xe5\x1f\xa1\xe5\xb7<\xfb\x08\xad\xca\x95uK-o\x1b\x97v\xe5\x8aX\xdf\xc0\xb3\x12\x856.B8gE\x00\xda\xa8\xe1\xf4\x15\xc0\xf1!\xb2\x1c.\x90m\n(\xb6 \x99\x0f\xe9\x06\x96\x95\xd2E0\xcf\x9c\x06D\xd5.\xfe\x03k\xd1\xb64E\xf9\xc0\x89\x8b\xbd\xcb\xde\xb2x\x00\xf8q\xc3\xa2\xa2)-\x99\x8aS\xe1$\xec\xa9\xf4%\xa6\xf6\xbc\x91\xd8\xc0Y\x9f9\xd2\xc8\xfd\x80\xf5\x9e\xdc\x13TM\xfe\xee\xb3\xde\xd3\x9e^Jn\xa0\x82\xa1\x8aD\xe9\xa3Hf\x83\xa6\x10\xe4\xa0\xd4\xc2\xb3\xcfb`\xdf\xc2\xd4)kC\xc7\x138J\x96\xbf\x07\xfej\xc5#\xf0\xef\xe0\xe9\xf84\xc0\xc4\xb8\x92\xa8\xcc\x18\x9c\x0dq\x06\xdd\xd8\xeaB\"\xe0N\x06br\x01\xb5*\xbc4pi\x80*W\xbf2s=`=\x86e\xb5\x072\x0e\xd6\xabN/\x8a3\xe6\xa7ip\x1a\xf1\x19\xcbb\xe6\xb3\x95\x9f\xf0(\xdb\xa0\xf8\x07\xf5\x9ci\xfe\x91\xe8^\xaa\xa7\xf4H\xa3 f\xec\x0d\xe7\x8e\xd6[IT#\xaf\xd2\x02\x8a\x80\xfa\x82\xc1P\x94\xd6\xf5\x9agE\x7f\x14{\xe9P\xbc\xa2zlT\xca\xc2f\x08\x9a\xd7uJ\xb4\x0d\x17\x0d<\xc4\xd0\xe0\x84\xcb\x95\xd7\x1d\xc1\xe7\xaa\x1c\xd1\xd3\xce$\xd3*\xfa\xac]d+~}pK\xc7\xc3\xce\x83\x07\xf2\x80\xdd$\xe8W\xdbyu\x80\xbd;\xbd\x11\xeb\xdd\xf1\x97\xab\xc75\xa2x\xb7wW\xe4\xfc,\x8f\xb3zV\xef.VZ\xc5\xa9\x91\xf5\x04\xb2B\xb3\xceS\xc88\xcd\x1ek\xc1\xfa\xda\x04\xe3\x16\xa9\xb8$^\x92\xb2\x01\xf1*\xc4=\xce\xf8N\xef\xc9\xd3\xbb\x18c\xa1U\xd8\xa6\x04\xccFP>\xe0\xd9\xca\x8e\x92\xd0\xad\x91G}\x08\xf1\xe3\n\xdc\xa5\x19\xc1\xa3\x1dwpx\xc6\xa3\xecp\x19d\x19O(o\x1f\xe6A:\x913\xbd\x08\x0cu\xb5x\"\xe7\xe1\xd0ub\x0f\xfc\x97\xc4\x837%\xc5\x14_\xbc\x0f\x89?N\x82\xacH\xdc\xdd}\x00\x89\x9f\xe5\xab\x90_\xc8\xa4]Hz\x97\xf8Q:\x8f\x93\xa5L\xdd\x83\xd4\xd7~\x9a\xbe[$q~\xba\x90\xe9\x0f!\x1de\xe2x\xb0\x8bu\x97\x1f\xc1\x8a\xb7\xe97\xce4\xdf]6\xc9yL\x9fF\xf9\xe0\\\x0d\x07U \xb8\xd5\x88D.j\x80\xd5\xd8\xca\xcfS\xae\xbd\x1a\xc7&\xfa\x93\x01I\x85\xa2r\x1f\x82\x16\x13\x9e\xe6\xcb\xca{\xe3\xa9,\x1a\xc4Q\xc1\x92\xc5`,\x08 \x89\x1fD=\x8f\x05\x90r\x1c\xa4o\xb3Y\x00r\xfcL\x1b\x18\x1e\x9e\xc1\x119\xd4\x12l\x9c\xc7r`\x88\xc4od\xdb<\x96\xd6\xa5xg\xd2Ztch\x83oN\x0e\xd6\x87\x8f\xf9r\xc7\xe5H\xc7\xbaA/\xed\xd0 y\xa9\x8d\x0ff<\xcd\x92\xf8\x12\x17\xb6\xfc\xd1\xf5\xb3!M\xb7\xc5\x16:u\\OZ\x02$\x830H3\x1e\xf1\xe4\xb9\xd8\x87\xa4\x13\xe1\x1e\x17\x9bi\xcfU\xfbk\x9d\xde\xd2_\x9cZ\xd1d\x19\x9f\xf1/\xe4wjsndj\xf3oV\xd5\xe7\xb9\x9eW\xce9Y\x13F$\x98%\xea\xabz\xae\xed\xab\xd3\xc6\xafN\xc9v\xcb\xdc\x86\x95\xa0\xc8-br\xa5\x9f\xf5\x14\x1d\xdb\xa7\x06\xb6O\x8b:\xd5\x14<\xca\x08\x02\x04gL\xaf\x95\x86\xbb\x10`\xa9\x89\xac\xf7\x04!I\xb3$\x98f=\x92\xaa\xdf\x1f\xba\x03\xbc\xadDZ\x08\xec\xb6z\x9c\xaf\xe3R\x81f\x9cD\xb3\x8d\xf6m\x8d\x15\xa6\x91\x9ci7E3Wg#\xdf]\xae\xb8d%\x9f\xfb\x91\xe0&\xc5>\xc3|6\x0d\xfd4e~\xca\xfc\xe2K\xc4\xb9\xf0C\xe9\x86\x1b\x19\x9e\x05\xf7g\xd2LK\xa6d~\x10VS\xe4y`\xdf\xea\\\x99i\xbb\xbc\xe9E\xaa\x99QS\xbc\xad\xe5h\xe9g\xbe\xd5;Y\xc4/2\x94G\x99\xe34y3}(O\xc1\x16\xa9\x18.\x88}@Q>\xaa@%\xab\x82$\xf3\x98\x8c\x01\x80\xcdT\xa1\xe1U\xc6\x9eG \xfc\xfe\xf8\xc3/\xfa\xdb\x05\x062\x06\x89\x06 \x10\x06\xebc\xac!\xc6:c6Fl#\xf0R\x00V\xb6\xdat`\xe5\xeaH#z4\x10\x10\xa1\xcf3\x12\x01\x87\xc6\x10\x0f\xaa\x03\xaa\xe1x}\xca\x8b/ \xf0\x16\x91A\x949\x05a\xce\xde\x04\x11\x15\xf5\xae\x11\"M\xbdkY\x81\xd5\xaf\xfd4\x0e\xda\x1d\xb8#\xfc\xf7\xeb\xf0\x97\xd0\xa3|\xe6Tn4\x15\x9d\xc5kM=\x14\xc7\xc3\xacHoH\x02n\x8f]\x16\xb1\xfe>\xe8\xc03\xcb\x9c\xd1f\"5\xf8\xc5\xd1\xd4o_D\xcdcJ\x06~\x18\xc6Sg\xcbb\x8an`LQ\xb3\x0d\xedJ\xc8\xc0\xb19F\xb3)\xf9\xbd\xaf\xa2\xd4\x9fs\x87\xb3\xa7O\x9f\x82x\xd2\xaf\x82/\x17\xd3\xf9\x98\xf9\x8f]\x00\x9c\x0f\xdf@\xa8\x06x\xa3>\xf7@\x97\xb6\xbaD\x9b\x1fQ\xa5\xaf\nV\x0c||\x04\xba\x0d\xc4\x81\x01\xe2\"\xe1\x83`\xb5d\xf4\xb7 JW|\x9aU~\x0c\xa6y\x9a\xc5K \x13\xa5t\xa6\x98\xa0q\xbd\xe0\xa4 \xd9\xd5j.*\x11r5\x1c\xd6\x88YI\x8e\xe5\xf2\xa6(\xae]\xfa,to\xa0/\xd2\xc6k=rw6H\xa2\xb6\xef\xea\xeeN+nH\x8eD=\xb0\xefC0\xcb\x17\xcb%\x9f\x05~f\x95jH\x05\x0d\x1a\x19I\xbf3\xe6}7\xfd \xe1\xa2\xbb=\x7f\xda\xa0\x9baRw\xc3\x07\xb3x\n\x922{\xb9Uitt\xca\xb3\xd7\nI^\x81R\x83\xcc\xb0\xba\xb0\x12M\xad\xc0\x92D\xc0\xe4]\xb0\xe4q\x9e\xc9\xe8\x88\xdc+\xfd\x1c\xac\x92x\xca\xd3t\xd2\x835\xfc\xf3\x0fEpIy!x \x0b\xa0\xb1m\x1b\x1dQ\x8f\xa6\x07j\xa4\xdc\xfa\xb3p\x88\x0b_\xea\xb1 \xb8\xd8HG\x9d\xa6O\x80\x12u\xb0\x8a\xd3\xecK\xe9@M\x9c6\xf9 X\x8a%\xf9v\x9a\x04\xab\xccj\xef\xa3\x1eE\xc47\xb6\x9a\xa5\x88LJ\x12\x05\xb3nu\xd1\xa6?\x05\xf3W\x94o\xdb\xf4\xeaOF\xeb\x10\xf4\x07\xf7\x86\x12\x02N\xaf\xe7\xb1\xde'=y\xaa(?\x1c\xd5o\xd9UZ\xa1g\xc2qA\"%\x9b~\xbe\xf0\xa3\x88\x838\xdb\x01{J~\xce\xaaY\xee@\xc0}H\x0f\xb8\x11\xb9\x16\x0e\x07\nn\x93y\xae\x81\xa7\x01tb\xbb\x02\x14\x0b\x16\x82l\x0c\x16b/\x8e\x12\xee\xcf.\xd3\xcc\xcf\xf8t\xe1G\xa7\x1c|\xdd\xcc\x07\xd3\x84\xfb\x19\x97\xa2w\xa7\x97\x02R\xf5\x04`\xc0\x8eq^\x90\x00Yd\x9d\xae*\xd4\xb3~\xc5\x8e`\xd9\xc0\xec\xf1:\xe8%E\xbdt+\xc8d\xc5\xf2d\xfc|\x11\x8430s\xced\x9e\x1d\x8fD-\x94m\xabZv\xc0w\x87SI\xed\x9c\x85\xc7\xb6\x8c\x1bF\xea\x11\xa4\x03\xc43=}\xcf\xf8\xa1\xd8\xed\xe0\x16P\xe2G\xb3x\xe9\xc8@\xb5\xc8m\x14=h4a\xcc\x06i\x9c'S.ob\x08\x8c\xd1\x83sI\x1b\xa5\x812\xe9\x93|\x172%A4\xe3\x17\xaf\xe6\x8e\x0f\x02\xbd\x85\xd3\x97\xe9\xa0pq\x14\xd3b3q\x14\xeb\xd8\x9f\xcd@\xd8\xaad\x14\xb0*\xeb\x89NO.\xba\x1el\x7f\x1bC\x10\xfc\x0e\xfc,\xf3\xa7\x0b(\xe9\xf4\x8a\x85)\x052Ig\x00T\x89\x8c/XX\xa43\x96\xf9\xf5p\x93*&\xa1\xf3\\kR\xb5\x8d\x9a\x19/\x97DGy7q\x80\xd1\xe6MF\x7f\x156\xbd48.\x14\\\xea\x10\xb1 \x11\x0f#\xe4>#\xf6DwM\xd0\xef\xbb\xca\x97@Qo\x0c\xaaA\x8b\xdd>\xd3\xec\xbe\x9aW\xa1\xd8\x8fO\xfc\xe9\xfbF_\xe3\xe2\xf1\x93\xd3\x942\xb8S\x0fq\xacU\x8f\xdc\x86\xc2q:A\x01w\xe2\xa4\xae\xc7\xd2~\xdf\x86p+<\xa2\xe9sG\x1c\xa4\x1b\x8c\x08f\x0d\x16%\x18\x947\xac\xdfhd-M6\x18\xa9\x80t\xd4\xa5\x88\x04\x0d\x94\x86\xe88L#\xca!\x19\xebV=p\x85\xad\x8d\xc8N ?|\xf5'K.;p\x02\x1b\x1dW\x8f\xfe\xa8\x81\xa0RW\xa0Y;\x83\xa3\x9e\x04\xea \xack\xee\xbdz\x94\x91u\xd2\"\xbb\xa0\x1e0\xbc\xde\xb2\x1b\xdfRO\xa3\x01%\xf5\xb4\x98i\xd7\x1f\xe8\xd3p\xdd>%\xe3-\xeajw\xd3s\x9d~m_\xa7_\x1eK\xc6\xc3\xef\xa3w;\xd7\xef\x9d\xf8\xbb\xfd\x91\xfb\xd8j\xebM=\xa0\xb0\x0fA\xe4@\xd8{P\x0f\xcdQWJ\xd8\x98\xa3\xa2\x00\x9b\x07\x91\x1f\x86]\xe8\xc3\x0c\xd8\xb9i\x87\xf3\x825\xb7\xab\xe1oM\xb6\xe7\xf4\x8a\x98\x05:/\x94\xf2p^^aW\xf7W\xb3E\x90\xc2\x0d\xd7\x11\x14\xd0\x94\xc0\xba\x11\xc0\x0e\xec\xc5v[\x80\xee\xd7\xa2\x8a\xed\xc3B6\xed\xc4\x17\xadV\x06a<\xf5\xc3\xb7Y\x9c\xf8\xa7\xbc9\xe6\xda\xd4\x07\x02\xd8\xe6\x15\xa45\xda\x19\xd3U\xca\x95\xef7\xc6^\x97>#\xc0\x9c\xac\x97%9\xc7\xc3?\x9e\xfb\x9d\xc8\x1dd\xf1\x17\xf19O\x9e\xfb\x84\x06Y\xff\xd5\xf9^\x1fS\x97a\x9c^\x14\x7f\xc6W \x9f\x82\xe9ZO\xbb\x97g\xf6Wi\x9b(\xd7\xaa\xf5\x9b\x82M\x1b\xfe\x06ycS/\x119=\xd0\x10\xd5\xbaV7>\xb29\xf7f`\x90\xd0\xcb\x12\x7f\xca+M\xb0\x036\x8d\xa34\x0e\xf9\x002\x1d\xf0w\xa4\x92\xce\xfd$B7\xe0\xb0\xf7w\\SL\x17\x17 \xa9\xc9@%UZb\xb5\xadC\xebR\xea\xb4\x86hA\\\xc5\xf9N\x99\\j\x0cw\x86\x96+\xe5[\xbbd\x00\x98\xc0\\\x1f\xa8\xdc\x03\xc2\xa0\xe9\xf7\x82\x12\x890v\x98\xe1N\xbb4%!\x02\xe8\x8b'\x1e\x04\xd1\x82'A&\x1d\xc1\x0c\xc1\xd2C\xa59\x01\x9a\x99\x04\x9a`\xfd8\xd3\x8cF\x9a\xa0\xc5\x007\xf0\x94\xdc\xea/\xa4\xc1\xb6&r\x86\x8f\x1et\x9a\x9fj\xad\xdd\xebT\x1a>\xba\xef\x96f1\xd7\xac\xaf\x19\xd0ti\xa1M\xe3\xbc3\xa4\x02\xe8\x8bt\x8bK\x82\xbd\xf6[\xea\xf5\x89\x92\xaa\x08\xbc\xac]\x1e\xe0\x0c^H\xa2\x9b?\x88\xe2d\xe9\x87\xc17<\x81k\xa9\xa0\x96s2\xed\x8678.+\x95\x0d\xa5G\x0c\x7f\xe0\xa7\x97\xd1\xd4E\xcf\x04\xfe`\x95\x04\xcb \x0b\xce\xc4\xd6\xa7\x8c`\xd8A\xf5\x13p\xb1z\x0b\x0e\xeb\x19\\\xb3\xc0\xaaF\x89m\x17<\x7f\x8f\xea\xb5\xb5vE\xb1\x1d\x17bQU\x13\xf70Q\xbc>\x84f\x8a\xae\x82\xe5\x8f\xb3\xb7\xf5\xc8\x95Q\x8d\x96\x8146r\xf6\x86\xa0\x9f\x19\xcc\x82t\x15\x97\x89\xbb\x90\xb8\xf4/\x9e\x9d\x16i{*M&lc\xcd\x84\xcf\xc1@\x85'*}[\xac8\x81(\xfe\x9a\xab\xa6\x0d\x91v\xf7(D\x02\xa1\x8f\x7f\x92\x9a\xa8\x049\xf30\xd6\x1dbwC'\xa5>J_\xfa/\xd1_\x05\xba\xe8\x00,\x11Get\xa7\nN?\xee\xdcaA\xfay\x10\x05\xe0\xa2\x1a\x1c\x0dq\xf0\xf2\xe1\xc4\xd2\xdfP\x9bQG'0\xd4\x88\xc3\xde\xb6\x0b\x82[\x18c\x1a\x9cF0\xf5\xbb{;\x9d\x88F\xfb'\xac\xfb\xb3Re\x15\x1f&\x17\x18m6\x05h/\x0d\xe0\x9c!z\xa5\xdbT\xbf7\xb7\xb7\xd6u\xe7\xb1\xc60\xec\xb6\x99\xdadz\xe5\x8c\x03Q\xd0=\xb2pi:\x81>pn\xa3\x9f%b?\xa0\xbd\xd2\x0e\xef\xd7\xfd\xdaH\x02Y\xf7\x98$\x03V\xee\xd1\x01+\x05\x9dm\x86\x0e\xe3\xb4\xb3\x81\x08oCUgX\xec\xe5\xe8\x10\x03n^I\x97\n\x15\x9a\xebjtG\xd1\x1b\xc2\"\xfc\xd5J|\x1d\xf3 l\xe8\xca\x9f\xf4\xb4\xe6\xce\xa8\xe5\xcc\x9bbEt\xd8z\xa0\xda =6\xf7X4\xe6\x13\x88\xe9\x81Nx\xc8K\xe5\xb6\xe3\xea\xad\xe0\xf2\xae%\x16\xe0\xce\x90\xf6K9\xbco\x89 \xfcp\xcf\x1d,y\xb6\x88g)Ejw\x0d\xff\xc0\xa9\xe4\xec\xeaG\xa8\x90^\x0cp,\xac\x96\x9cv]6\xf3re\xa0\xa6\xb1\x9a\xad\xd9(\xa0(G\x12\xcb\x80\xd7\x86\x82!1\xe3\x9a\xdf\x80\x05\xa4\xf2e\x90uXX\xc4Q\n\xec\xbb=vVD*\xf5\xd8\x89\xc7\x8e!\xc8\xec\xa1\xc7.0\x9a\x96\xc7\xde{\xec\x99\xc7^y\x10tk\x0e\xe7/\x9a\xe2c\x00\x11y\xa1\x14i\xb9\xdc\xbd\x0b\xf14\xee\xd6\\#\xe8\x1aW-\x10\xff\x02\x9cu\xea\xc9\xae\x07Qq.\x06\xa7<\xf3 \xf2\xcd\xc5 \x15\xaf\x97\xf0\x8a\x9a\x0d\x0f\x02\xd9\\\xa0\x06\xc5\xf5J\xc1\xcc \xe1i\x1c\x9e\xf1$\x85\xe6_\xc9\xad\xa5H\x15\x8b\xfa\x19SA\xf3\xed\"-Vn\xc0\xd2\xb4\xaa\xa0 &\xf9\x10\x1b\xf2+\xf8\x1e\xf8\xbeq\x02\xb7\xec\xd2>n\xd2K\x91\x08\x8aIb\x9b|-f\xab8\x89C\xe0]_Z&\x9f\xf2\xac\x07\xab6@s<\xd7c\xaf\xc9\xe8%\xa2\x0f\xe8tO\xf0LAi\x808-\xe8 \x9e\xe2\x83\xf1\xd6DP\x80\xb0\x9e\xae\xfa\xbc\x8f\x9e\xa1\xecB!bd\x8a\xb7H\x9c\xde\xf3 \x99\xe6\xa1\x9f\xb0 :\x8b\xa54\xc7c\xbd\xe7/\xde<\xff\xea\x8bgo\x8e_\xbc\xfc\xd1\xab\xe7\xcf\xde\xbdx\xf5\xd2\xa6x\x17\xad\x9e:\x01!\x8bA\xa5\x92\xe8C\x03\x18o\xa9'r6^\xa3J2\xf6\xd8s}^R5/R\x89/\xf8\x90*\xfd\xf4\xd8\x99[x\x15\x14\xeb\xa3Q\xe0\x06\xc7gzV-C\xc5\xbb\x02\x8dh\xa3\xae\x13\x14\xa8[\xe2\x90\xc5\xaa\x10\xf4m:\xb2\x97xT\xc7\x97Rf\xc6F5$s=\x1b\x9a\x17\x9d\xbe\xe5IB\x93\x000\x19&\xa6\xa9\xb8C\x8eV\xad\xa6'l\xdd\x93\xfa\xed\x92\x02\xfd\x8e'lyRT\x0c\xab\xd0\n\xa6\xb8qZ\xe3*5\xa0\xfc\xda\xc12\xbd)5h\xe8\xdc-O\xdf8\x16k,\"'/V\xf3\x16U\x82\xf21\\c>\xa9\xfc\x8f\x93\xe04\x88\xfc\x90T\xf8+n}\xc4\x9e\x99\x99\x92\xd5\x7f \xde\x83`\xb7W?\xcd\xb2\xa7<\xebr\x15T\x0e\xf2U\xc1\xe8\xbdr\xb8\x0b\xbb\xdc\x01[\xa2\xb3\x07\x89\x14\\L\x86I\xf5\xcc//\xfct\x8d/[\xe6\x91r\x12o~\n\xf7\xdb._\xb3\x900\x86\xfd\xa5{\xc00\xaa\xfa\x9d;\xec\x12-\xa5\xd8>{\x0d\xbc\xaa\xb4`\xc0\x1f\xefu\xb4\xc0\x9c\x1e\x86\xa8\xa3\x1cE\x99\x83\x006a\xd4\xae\xf2P\xa2\x15\"N(\x83\x80\xc8w\xee\xb0\x13q\xe6\xd3X#\xaf\xe8\x18|\xa5\xd7\x15\xb0q4j?\xb52M\xa0#\x16\x7f!\x10y\x0bz\x0f6\x02\x1b\xac2\xf9y\x91,\xa1TZRA\xfcW\xf0\xe41\xab\x08\xf5i\xdf\x15f\x7f\xc5\x18Glaf\x14\x87\xe1\x0e\x00\xe6\xc8\xd9\xca\xe5i~\xb6\xbe\xbc\x8fMV\xcd~\x95\x05-\x8b\x1a\x883.A8\xe5\xe1\xf1\xae\xe4d2\xe0d\"\xe4\xd1\xfc2\xc6]\xbdC\xeb\xec\xe9\x85\xa8[\xb6&7\xbfj\x93\xacmi\x11\xe4\xa3\xdcTp\x17\xf1\xcb\x00}\xf5\xfe\x9e\x83\x14\xbd\x95\xf5\xe0\xad\xb0\x93\xdd(\x87.\xf7\xdc\x91\xda\xef4\xb0r9k\x02\xa0%u\x8b\xb0\xb3bE\x9b\x82\x97\xc3\x8f\xd6O\x1f\x82\xd8K\xd8\x93\xdd-\xb1\xa0\xa1\xe3\x1210\xe6\xbe\xd9\xff\x95\xf3\xcc#\xfa\xac\x0b\xbfF,\x00\xd7UV\x12\x1b8\xc7D\xae\xa4]\x81\xe3\xab\xd3\x8e\xf9\x15\xd8\x89\x02\xe7\x9c\xca\x83\xbd\"p\x0e\xcd>\xfbE\xca\xad\x1c\xf1w\x86T \x10q$\xb7h\x99\xea\xe2-\xb1\x97\x83`r0\xf5WY\x9e\xf0\xb7\x99?}\xff.\xf1\xa7\x9a(\xa9\xe2\xab\xa3U#\x15I{D\x94wR\xd1n\xf3\x8aphH\x88\x90\xd2\x9a\x90\x89<\x0b\x07N*\xddm\xe5\xb8\xa9I\x8f\xa4\xca\xa9=hdR\x19\xd50\xc2\x9b\xb8\x81*\x1b\x0d\xa6\xf1L\xe0^\x0eWu \x08D\x84\x8c\xea\x9a\x0e\xa8\xd7\x90\xc7\x93j\x05\xdc\x81\xa5\x90\x02}\x85t\xd7.H\xf7n\x0e\xed\x15e\x1e\xc7#\xd6K\xfcozu\x1ae\x96=\x11\x18\xdf\x9b\x9d\xfb\x1d\xcaf\xc97\x97#\xd6\x13\xffz\x06\x8a\xf3\xc1<\x8eY\x9f\xf1\xc1\x89\x9f\xc0\x7fQ\x0eh\x83\xe8\xca\xec\xdc\x87z\xb7,\xb8\xdd5\xa2B5Hn\xd7\x08\x9c`\xd1\x10\x94\x17q\x02\xc3\xe4\xd6c\xdb5\xbe\x1blu\xb9.\xe9\x04n\xb4b\xa4M\x8a\x1a\xedV<|\x9c@\xfc\xd1qBX\x9b\xb6\x9a\xecD\xe8\xac@\xac\xebV\xf3\x0bd\xf8\x87\x8f\x99\xcf\x9e\xb0\xf41\xeb\xf7}y\x85\xadX\xa0\xfe\xc4\xc3\xf8\xd4\xca=Q\xee\x9a\xea\x13\xcd5KT\xe8EHL\xff\x18\xaa\xc3\x87CT\x1dj\"vT\x1e>\xdc\xfe\xd8\xcaCz\x12\x15\x8f\xa1\xf9\x96\xed\x15Z\xf5\x1ex[\xac\xceC\xe3\xa4\xd26X\xb7-P\xa6\x94#\xda\x00\xda\x96S\xbd\xe3\xb2\xd31x\xc3-\xe6\x06\x8fg\xeb\x1a\x9f\\\xab\xef\x04\xc5\x94\x9f\x18\x91\x97\xa6\xf0\x16\xda\xc8\x98\x9ak\x0e\x1c\x86}\xe7\x0e\x8b\xc7J11\x11\xebr\xdd\x10\xb9\xed\xa8)\xd0\xfc\x01\xe2\xbf\xbc.W\xb9s\x9b\xf9A\xa4V\xc3\xee\x0dV\x83\x82\xb6N\xe6\xd7\\+M{]R\xf6Ulz\x1b\xcae\x88Ju`\xf7R\xbe\xeb\xeby\xf38\xee\xdd\x8e\xaa]\x0d\xd3\x00\xa5\xbc\x0es]l\xa8\x1d\x11+\xcae\xf6\xf46\xf5\xef\xb5\xeb\xa4\x9er\xc8N\xe9\x80\xe6\xb4^t\xd5Y\x953\xeb\xaa\xcaY4\xabr\xce,\xaa\x9c\xda\xe7\x96]5>\xa7\xed\xc1n\xab\x15.I\x8a1\x8d\xa3yp\x9a\x83\xf6\x95\xa6\x1a\xbc\xd0\xce\xd2\xae\xaf\x95\xa7\xa4&\xba\x92\x1b\xdf\x164*i\xe3V\x98\xe2X\xac\x87\xb69\x185\x9c\xea\xb8\xd7;>\xe6\x1c\x0c\x07\x0e4\x07s\x90&\xcer\"\xe9rp\xe6\x87\xb9\xe0h\x16J\"sV\xab\xed\xb1K\xd7\xd3\n\xcab\xd1\x98O\xd8\x01\xe5t]\xe6\x88\x7f\xe8\xb1\x0d\xacO!u\x9f\x8dQ\x9b\x9aM\xca$\xe9\xad\xa3\n\xb1\x1a\x8d\x8f\xa6|\x04\x94\xbe\x1b\x94<\xdd'\x98z*\x80\x8a\x95[>c\xb9F]\xee(J5u\x8c5\xe0*\x992\xdah\xb7\x8a\x05\x07;\x02\xba\xaf\xa2i\xe1\xd4\xe7\xf8\xb8#(\xe6\xf3\x11\xf0\xbe]!!\x89\x04-\xe7F`l\xd0hS\xf1\xa7@\xd7\x97q\x80J\xc4r\xc7|\xd2\xa1\x9e\x896\xe8`T\xd46!\xc6\x14\xeb\x1d\xe0\xed71y\xc98\x98\x08\x1e6pY\\\xfa\xe5\x8d)\xb8b\xae`\x94\xb7\x95s*%\xd2\x97(\x98\x8c\x03i%7\x14\x88\x99\x0c\xd2\x15\xdc|\x0c<6\xa4\xee\xee\x81*-)?\x9b4~V\x8ac\xa3&\xeb\xf8\xb6iG \xa2\xdfzG\xf1\xac\xf0j\xd18\xef\x16:!\xb6\xe3\xb8:\xa1\xf6\x19\xa1\xe7\xb1\xd9\x19<\xccbD(\xc9d\xac6-\xde\n\xdew\xcc\xf0\xc8\x92\xb1',\x12\xd3\x9d\xb9,\x18g\"\xb3z\xd91k\xb8\x08\x07\x1f\x8d\xc1\x81\x05^h\x95\xedn=\x06\xc2\x1b\x8b\xca\xd8\xb4\\\xc5I\xa9\xc9!\x1b\x95\xbaTu\xa3\xac>\x96&\x00t\xb9\xb55+\x88\x0b\xe8\xa9\xec\x03c\xedw\x8b\xba\xdc\xc6\xaa~\xaf\xc6\xb0\xdc\xfc\xeb-\xb7\xad\x9a\xbe\xeeU\x84G7\xebK\xa7[U\xbf\x10\xfc\x14\xcf\xaa\x06\x05\x1b\xe6\xfd\x80\xfe\xf5\x81\xf2\xc6,8\x8b\xa9S\x17z\xe2^:u\xe2z\xba\xd8X\xa6N\xe0R\x84g\xea\xe8\xe6\xd0hG\xb8t~\xfe\x01\x85q:{\xdc\xec\xf5G\x19\x8bi\xa1*\x17N\x88\xce\x88\x8bSc5T\xa4\xc72e\xb4\xc4\xf6Y\xfe\x03vS\x8eY\x9e\xa3\xea\xb1~\x1b\x04\xab\x04\xdb,\xf88\xd2=q\xf9\xbdf\xe7\x01\x1a\xdd\x1f,\xfdU\xbb#hU\x81\x1d\xb0\xcc\xe1\xe3\x08T\xcf\xe2\x7f\x15%\\\xe9|\xc9\xc9+Zi\xf3\n\xff\x07o\xbdc\x0d\xc8\xbd@\xe0\xd516O O\xc5\xbe\xa1Zq\x05\xd7u\x12D\xb3\xf6P\xb6\xddg\x16\x8f=\x8f(S9\x9c\xa8 \x85\xff\xd7<\xd5\xc5(\xda\xe0\x10\xce\xfdv\xba\xdd\xe9 \xadD\xcb\xc8\x98\xe2H\xe6I\\\x0b\xc8\xd5t\xdcF\xff\xed\xe0]\x00\xe6p\x0c\x82d\x0fe\xc4\x13\xd7c\x9f\xc6q\xc8\xfd\xc8\x01V&+}.C\x01\xd4\x05\x81]\xf4m\x8cY\x13\xe4<\xdav\x07A\xc6\x13?\x8big\x8e\xc6\\\xca%\xfa\xc8fAN\x1a\x90\x1bK7\xa5\xe5\xc9!\xbd\xfe\xa7\xf2\x9bur1\xaf\xe3U\xa7c\xb5yX\x9e\xdd\xc6a\x94\xc8\xd7\x0f\xa3f.\x1c\xe6\x08\x1f\x8c\x1f\xac'\xf9\xeaQ}\xddET\xb2\xa5V\x13\xcaV]\xd2\xdbF]\x128Z*%\xf3)J\xe6C\xe7B\x06\x08\xbf\x90\x0e\x12\x99t\x19\x0eh\x0e\x13'R\x02\xf4\xf8\xec\x16\xbe\xf2\xaa\x8d[\xfc1\xc0 \xe8\xc2zF\x9c3y\x89F\xaeN4\xf7tN\xb5\x10\xc5\x82\xa4 \x16\xc9\xdb\xdb\xf2\xc2\x9e8\x9f;\xcb\n\xc71t!b\xd9>\xe3p\x19}i\xe1\x86\xf0T'\xbe\xda\xc2\x85W[\xaft\xaa\xe2f\xe4T\xb05\x91\xcb\x96h\xcc\xc7I\x0bJ\xf5\xc8\x91.\xc9\x02\xe6\xa5R3e !\x03\x7f`/\x040\x9f\x1bzdf*'\x9cs\xe8n2\xb1\xc2\x02\xe0p\x02f\xae\xe7\xf2J*\x1a\xd2\x08\x82\xa9\xe0#\x0e\xc8\xe2l~\x02\xce\xc5\x9c\x128\x1b\xc7\x83Y\x1c\xf1\xc7.(\xe0/\xd8\x81b\xe2\xd0\x1a\xf8\x18%&\xd2\x90\xbd\xf8%\xf6ogVHS\x0e=\xb6p\x96\xb02fp\xddJ\x82\xf9\xb0\xfe\xd1~\xdf\x125K\xcc\x1c\x11\"\xa84\xf7\x9c6`\x03@\xe0\xb4\x123\xdb\x1c=\x8c\xd7\x03\xb9]\x0d'\x0e%B\xc8Py\"GZ%\xed\xb3\xc3\xc1t\xe1'\xcf\xe3\x19\x7f\x969[\xae\xcb\x9e\xee\xb3\x07\x0f\xb6\x1f\xed\x82\xc5\x12{\xb2\xcf\x1e\xec\xee\x0c\x1fA\xf9Cp:9\xee\xf7\xa3\x89\xb4g0\xc0y(\xedG\x0e\xad <+Ax&A\xd8\xef\x9f\xd9\x81v\xd6\x82\x8e\x1a:\x89=\xf0\xd4D\xb8\x02z\xbe\xa3\xad\x9d\x1a\x00\x9dS\x97^P\xe40%4\x15o\xd7\x1d_H~\x00\xbb2\xab\xc8\xee<\xb6,/\x89B\x8c\x90\xa2\xe6\x0d\xf6\xf5\x9a\x96\xe2\xd1\x8e\xd4R\\.O\xe2\x10U\x12\x8f\xee\xdf\x82J\xa2v\xc2)\xf48\xb5-\x1e>[\x91\xc3\xb6\xe9vH\xbe\xcb\xdcb\xc8{(8J\xcd\xf9Bm\xf7`\xfb\xb2\x88\xd3\xcbx\x9a\xc9\xee\xd5\x8d:i\xf5\xa22o\xac\x9b>\xddD\x89\xa8\x97\xd9H\xc6\x95Q\x14,\xd9\x04\x953F~\x16\xbfV\xdaM(B\x95\xc0N\xbf\xf3O'\xb7\xc74\xea\xba\x0e\x8b\x8aC!_\xfdZL\xd8\xac\x90\x98v\xd54\xcc\xbbi.V\x84B\xc2d\xfa\xc2\xfa\xed\x90\x1az\xed\x1b\xe8U;\x97\x14X\xb5\x06\x1a%\x8e+=\xda6i\xa5\xeb\xeaf&\xe7`\x81\x9b\x80\xb3(\xbb\xef50}57\xbb \x92\xc0\xc5\x98c\xac?\x8c\xa1q-wF\xe3\xca)\xb4z\x98\x8f\xbb\\\x8f5\x89[\xbd\xb3\xfc\xd6:\xeb\xc3\xcdrP\x04\x01\xf4CG\xf3j!\xc5h\xda^\x0b\x01\x1a{\xa5\x15\xa1\xe0B\xa6ND[ \xce8\xfa\xa2\x0c\xe2\xe8\xf8x\xc4r\xf0/\x9aQ\xe6|\xc7\x91\xbf\xe4e\x993\xa7n\x02\xfd\xa1*\x1f\x99:q\xfd\x93\xf38\x11\xd5\x9b\xb1L\x0ez\x86\x8a0\xf87\xc2\x7f\xfb,v\n\x8anHE*\xbf\xdf\xf3\xcb\xcf\xbb|\xccb:\x0e\x8b/cA\xc4R`jgv!\xfel\x9cM\xd0\xd6\xb9\xd4\xdc4vm\xe1\xa7/$\x96(X&\xa8\x06\xd1r\xd0\xa2\xaf\xa7\xa5\x18\x01\xd3\x83\xf49\xc8\xaa\xde\xaeT\xc8\x97Zsf\x01\xd9\xaa\x99a6.\xf7\xb1z\x932Y5$\x7f\x1a\xd5\x97\x82\x1c\xd6\xeaB\x9a\xac\x08\xefF-\x19\x19\xa9VO\xc5N\xc2\x9a\xf2\x97Q7\xe5~b|\x12\x13eM\xfcaV\\\xf1i\xc0\xd3zMLUU\xf1\x17Q7\x0c2\xa3f\x18dE\xbd0\xc8\x8cZ\x1a\x0fP\xab\xab\xe5\xc8\x16\xb4\x14\xa2\x9d\x82S0\xda)r\x8av\x8a\x14\xa3\x9dW\xddS\xdfoT!\xeb\xc2_E\x95j+\xae\xd6\xb1\xd8\xde1\xfd\xcb]\xbe\xaa\xc8\xb7\x031\xdcQ\xf01\xa8\x91Q\xd6g=\xd70 \xad\xfc\x863\xc5\xaby\xd7\xaf\xa6\xb5\x98Z\xcc\x1c\xe5\xbc:\xcaXG&\xaf\x0d\xac\xea\xfa\x89\xfc\x0e-\x1e\x95\x8cw-B<8\xc8(0\xce\xd1;E\xf7\xaa@D\xe8\xd5\xb4\xe7)\x98\xf6\xb0B\xd0^!\xae8\xe3\xafp\xcct\x13UHPM\x94l\xf9M\x1cj\xe9\x02\xda\xdd\xb5=\x19\xa1\xdf3\x108P\x9c\x03\xba\xf6/\xf8\x06\xfa\x1c$'\xeb\xd6\x8dG[E\xfc\x1b\x1bx\xd9\x87D\x93\xab+\x91\xaf\xc7*\xc0\xb2o\x8b\xb2\xe0\xc6\xb4\x1e\xca\xe0\xce\x1dV-2\xae\x16\xaa\xce\xfcm\x0cYM\xa0a\x12\xa5>U]\xc6`K\x81\x12\x88.\xcb\xb8\x10\xc0V\x17\xb2\xe3\xae\x8d*Uk9\xee\x02x\xe2_,\x04\"gg\xb8}\xed\xa1\xd8\xdd\x06\xfdR\x0d\xb2\x12\xf2|\xbd\x01\xa6\x86CqX\x18\x88\xe6\xa6)\x88\xf2\xcf\xa1\x1d)\xb0o\xa2R\x0d&\xee\xedY\xcc\x9e\xe9^`\xd6\x1d*\xc1N7O\xef\x01\xb1XR\x9e\x91\xd7g\xe1\xaeQ-\xea\x9d8\x12\xd1\x91\xa4\xa0t\xe2\xf0\xc1)'.\xd3i\x01R\x07)\x071a\x06/\xfbP'\xe5\x10\x9d\\\xdenC\x15\xa0\xfa\x81%\xf0\x07\xdc9\x93\x01\x8f\xb0\x90\n~$\xca\xe0\xad)\x88\xd1\x0d\xfd\x94\x1f\xc8\xd0\xc1Dv;\x14k\x8d\x89)\x04 J\xdej\x1eb\xb5\xa0\xff\xbd\xff\xbeW\xcd\x97\x87\xa2\xfd\xf2\xd20\xc8e'\xeec\xb6\xb9\x99@D\x9f\xfe>\xeb\xfdw V\x00q4\x89 \xd9\xf77j\xb5\x19\xea\xf7%Ik\xbfB\xd8\x12\x95\xc3\xcb\xf0\xd6`\x82\xf2{A\x02\xb8\x18h\xac\xc2<\xe1@\xb3q\xbf\x9f48\xf61\xd0\xb5\xcb>Q\x8b'\x7f\xcb\x17\x18\x86\x86\n8\xae\x8b\xf8Z\x00mc\x1f ]i\x06*)3=\x82\xd3\xbc\xdd\xc5\x8beA7\x9f\xe6\x99f\xc2JwG=\x01\xd8\x8bZ\xb3}\xeb\"QOPD\xdf\xf2\x8b\x15\x13\x8c}\xb8\xba Fe\xaf%>-J\xda\x06\xc0\x14>>f1{\xc2|\xb6\xc9\x86\x8f\x9b\n3\xd9\xb0t\xa7\x07\"\"\xb9?\x04\xa0\xed\xe4\xe3x\xe2j\x0eW\xad\xdd+Z\x83.\x0e'\xa0C\xe9\xf7ckaS\x05\xa9\x1e\xf9\xad\x96>\xb1\x03\x15\x8eN~N\x81\x8fl\x97\xfe\x9a6*#\x9f\xb8M\x9eV\xd0\xc8jo)\xd0(@ao\x03\x1a\xe5\xcdh\x04\xd2\xc4\x8eh\x94\xba,\xc7\x10\x0e\xfd\xbe%\xf0PK`\x03@\x1ah\xe3\xeaJ\xbe\xec\xb3q\xe3DS+\xb3\x9ao\xcd\x9e\xc8\xab{\xe2;\xf2V\x9c\xc4\xd4M\xe9\xfc\xc3 \xcaI\xcfa\xd2c\x81\xf6h(\x1b@\xd5-i\xe4\x0e\x19\xa2\xa2\xc7\xf2\xf1P&~\xc4\xae\x17}\x1fN\xc6\x01\xe0\xb8\xff\xf8F\xfdv=\xd5\x18N\xe05\xf0WJ8\xc9p\x8b\xe6P\xd7\xf3\x8e!\xdd\xc74`\xb2\xdf\x8c\xc9\xb9\xb4/o\xc6\xf5\\\xe9\xc1\xad\xa5B\xd8\x0e:\xac\x05\xc9l\xf9\x02\xbb\xec\x8bAT\x81X\x80\xe3\xb4\x0b=\x0d4,\xedNO5\xee\xdf\x07t\xc8\xc7\x81FO\x9bIi\x88\x88\xe2\xa3\xa7&\xec\xebp2\x8e\x01\xe9\x82k\x10\xd6[\xe9Yq\x15\xb7\xe8\x8c\xa8\xaf\x0c\xf7c\x0f\x10Z\xe4U\x92\x1e\xb3\x0d(&\x15\xe0w\xee\xb0P\x117\x176\xdcp\xb0\x8aW\x8e\xeb\xe1\xa4\xc8_n\x87\x96\xd7X.\xda}\x80.\xeb\xa4\xab\x03\x16\xc9\xa7\xe8|\x89\xd9\xfc\x0f\xe8_7\xe0\xca\xaa\x9a\xff\xbd-y?\x11\xdd\xd2\x0e\xc0\xa9\x9dt\xec|\x93+\x89k1q\xfa\xb7\xd79\xca\x81\xc2\x9b;?\xff\x00\x84\x92;/\xfd\x97x\x0b\x91;;\xf7\xbf\xcf\xb3N\xc1\xf5o\xec\xdf\x8e\x1c\xac\xca:_\x13\xack\xf2\xc6u\"y\x1bl\xb1F.2\x0f,\xe1,fpU\xe6-.\xb9\xb4h\x1cwZuU&\xab\xcd\x7fh\x8642\xc1\x03W\x84\xbf\xfa}\xee~\x9c\xbdP\x93XA\x10)\xd8\xf87`\xa0x\x86\xaf\x12\xab\xa8\xf2\x9b\xa0\n\xb7Ct\x08~\xe5#\xd0\x9b\xdb<\x05\xd2B\x06\x1a\xd5#++j\xe3\xe3\x08x\x10%\x83\x1b\x1e#\xad\xbe\xaf\n\x89@\xc1:\xa1\xa142\x11\xbc\x95\x89h\xdc\xa6\xb3\xca6\xddr \xeb\xc434\xb2\x96-\xfd(\x97\xb7\xfc\x8c\xf5\x10\xd6\xba\xd2\xad\xc7\xa9\x02\x9c\xd2\x00i\x0b\xaf\xdcD\x8fY\xae\x81\xb3\xe0\xc0\xfd\xb2\xa7\xa9\xe4\xc0s\xc5\x81\x8b\xbcT\xe3\xc0surH;\x9c\x1c\x9aN\x0d\x96\x13\x03\x9c\x16R\xf8\xe8p\x02N>\xfa\xfd\xbc\x0b\xdd\xbc\xce(\\O}\x06\xce\x11\x99\xc7\x02\xb0/\x10hHxN\xee@\x0b;a8\x1es\x91\xcb\xc7\xc1\n\xb2\x14\x82\x18 \x93\xc7\xbbk\xe3<\x9e\xa1B8C\xb5\xb3\xa6)B$W\xc1\xbf\xe5)\x0d\x91\xdf_\x03\xf9eo6\x1a{\xd3rd\xc8\xf4\xcf\xe7&#\x9b\x13,r^e\x91\xd3*\x8b\x9c\x16,r^\xfe\"Xd\xb3ekO%G,f\xaa#xn\xb0e\xd9 9\xbb\xe6\xf2\xf2t\"nv\xf5\x07\xf4\xaf[\xda\x03m\xbe\xc1\xe9\xcb3;C\xfa\x82\x9b\xe9K\\\x1aY\x1a\x17_R\xdb\xcd\xb7j\xb1\xf5\\\x84[6m\x88\x16!\xe3\x18\xb4\xdcx\x97B\xd3\xb9\xc7V\x1e\xd8WN\xa5\x81\xa21\x1f\x8b\xa6\xcc3\xd0n(\xc7sf\xfe\x12\xf2\x95\x13\xc6*F\x97\xf5\xc0$\xbc\x99\x97S\x9cF\xe9_\x98\xc4\xad\x04|C\xa9\xa8\x0ep\xaf\xd4*\xa9\xa7\x9d\xad0\xe5\xb1/A3\xbb\xb4`\x9f\xb7<\xb69\x14[\xc3\x99\xbc}2/\x9c\"\xac\xc4\x9b\xa9s\xead\xb1\x1c8\x1a\x00\xd9Y\x83\xe1\xf2\x87\x1a\xf8\xe2H\xb9\xe9m\x87]\xe3\xf5v\xf2\x02%+\xcc\xdd4\x17\x05$\xcct\xc3\xbd}6\x9e\x81\xcb\x8aH\x19\xf1!u\x8f\\\xd4\xc1\x01h \xeeM= nH`\x91\x89tb%}L@\xa8|e\x93\xdfbD\xa3\x1e\xe0?\xect\x94\xf2\x15\xbb\x901\x0d`\xbf^\xa0\xf7\x8d\xd2%2\xac-\xf4\x07\x1b\xe0~%\xbd\x19'\x10M!\x8e2~\x91A,\xa6\xe44u\x0b\xfb\xcd\x04\xe3G\xc4\x88)A\x89BbNlq\xa2[I#\x86\xfb\x96k\xab\xcd\x0d\xc7\x19^\x8c\x94F\xe1\xd6E\x11\x89\xa1\xf3jd-\xe9\xffC5\xcf\xb8\x1da\x14\xff\x8c,\x05\x1f\x043\xbb\xe4O\xfa\xc2d\x8d\xf1\xfc\x01\x03q\xbb\x13\xadaOf\xe3\xb4t\xdb\x8b?\xe2R'ct>\x03W\x9a\xa9t\x80\xc8\x0e\x98\xd2\xec:\xe0P\xdcY\xa0\xe0\xdc\xde \x86\xf6lbnG\xb8\xe2\x1b\x8bbh\xe7\x06Q_\x89Ri\x89R\xa9G\xaf\xaeXF6\x88\x8b;\xc9nCI\x14\xc3\xd5/\xc7C\xf5n\xd7\x90\xf5Gk\x8c\xb7\xdc\xb4gr\\\xe8)\xdc\xc2\xb5\xa1\x087wBy\x9b\xd9\xf4\xfeB\x1d\xb6q+\xa6\xa8\x00\x97\xbc\xb4\x94\xb3\xca\xae.U\xb3\x1c\xe2\x03NOp\xc9E\xb8\x00}\xcd\x05\xf9\xb2\xc5\xfd\xcc\x07OR\xd9\xb4\x03\x95\x85\x95#I\xe1\x1adr0=\xa9Q\xca\xc1\xf4\xc4-\x0d\xa0\xc5\xcf\x02\xd7\xf1G4\x08\xc4\x96)\x9d\xef\x001e\xa3\x12\xa9\x89\xeb\xe38\x8a\xc2\x9bu\xfbvA\xb0\xeb\x14\xb1\x9c\x01\xb1\xbc\xba\x02BY\xec\x9c\x0b\xdd\xabv\x95\x84b\xa2FEU$\x19 \x98 n\xb1\xf5^\xb9\xbcn\xa7r\xa2\x0bD\xff5>\xa6\xe8\x0f4\xaa\xba\x13\x0b\x8cl_\x1d\x92\xce\xc8\x9e\xf3\xa2\xe7&\xea\x1ac)~\xde\n3k2\xad\xc8\xcc\xee\x191\x18\x03\x99^\xbf\xc4\xed\xcb\xf4\xba7]\x15K\x8c\x0epc2\xb9\x1dn\x0c\xc5N/[p\xf0\xd8/\xfe\x8fd$d\xb8X\x1fG\\\xfd/\xd2\xdd:[\xabB\x19val\xb5\x0b7\xc6\xac\xc4M\x99s\xea\xa6\x11S\xa62[\xca\xec_]\x0e\xac\x96)\x14T\x1c\xfc\xa3\n\xf2\xb3\x01\x91\x96\xe8k!w{\xac\x0f\xde\x1eX\x9f\xf5\xee*3\xcf3?\x0cfL\x0dv\x19\xcf\xb8q\xf1\x8d\"I \xee\xeb\xb65\x11Z\x02\xf4\xc2\xb0r\xc7/ES1:X\xf5\xa5\xc9\x14\xb1Q%\xf4\xe14\xc2\x8aC\x8f\xcde\x13f\x19\xd1\x95i\xabS&\xbd4`\xee\x98\xb2\xb7Q\x8f\x18BH\x04\x9c\xfb\x12yj\xce\xb8\xf8=b\x9f\xf1\x8cO3>cy\x14'3\x9e\xf0\x19\x13\x88x%\xb0\x8e\xdd)\"sC\xf8\x9e\\t\xcec\xe7\x8b`\xba`A\xc4\x002K\xff=O\x19F\x1fc3hMpC\xf1\x9c\xa5\xf9t\xca\xd3\xf4\xde\xdc\x0f\xc2<\xe1,X\xae\xe24\x0dNB\xce\x9c\xf3\x05\x8fD\x13wu\xec\xbe\x0b\x13\xeb\x1eE\xcf\xe3(\x0df\x80N\x04m3*?\x1c7\x1f\x1b\xc6 \x15\xbd\xc8\x02\x89\xb5N\x0e\x84'T\x9dc\xac\xf0\x96:\xbbh9S$k\x9d)H\x13\x97\x8fz\x8a\xa8\x8b\xa6\xa5\x90\xe0#\xe9\x89\x9b\x14\xb7JOY\x06\x90k\x06[\x86\xe7\xe3\xfa\xc5\xfc\xea\xe5\xf3\x9b\x03\x88p}\xa5NYm\x91\x96\xad\x86*\xe8\xf9\xfdV\xe7Q\x9c\xca\xd6\xbf\xbd\xd1\xe8\xa2\x1f\xaf\xe28\xe5\x15\x19p\xe8\xa6]\xfc\xd3\xa2\x895H\xad\xcd\x89\xa3\x0eC\xaf\xfd4\xe5\xb3B\x10\xa3\x05\x84\xc6K4\xc1\x9c\xcf\xea\xf1\x8cn\x17~{\x86JG\xcc\xf3\xbd\xf1Qt\x94\x1c\xe5\xdb[\xdb\x0f\xe1\xef\xa3\xc9\xbd\xd3u\xc1\xac\xd0_\xcc:\x89\xfb\x85\xc2\xe2)\x1bnm1\xe5\x80.\x93\x0eX\xb7<\xf6\xe8\x11\x1c\x13\xff\xdb\xef\xfc^O\xde\xff\xcf\xd4=iAq\x9b\x97\x8a\xfc\xcao\xbc}\xf5r\xa0\xc0y\xe9pW6?\x04\xc5Fm\x19\xdd.p\xff_\x83\x9cJ\xcf1~\x19G\x9b\xd3\x98'S<\xc6e\xb1DD\x17o\xf2N>\xea\x85\x8d\xdb\x88\x11o\xd3&\x96\xdf\x0b\x06\xb3 ]\xc5\xa6L\x85p\xa9)\xfaV\xb3\x81\x08 6\xa5\xa2\x9dg\xa7]W\xe0\xcc\x03\xa7B\x1e\xab\xf93\x05\x89#\xf8\xe4AY\x0b\xdbg+\xc5\x96.@\x89P,\xd0\xd4\xb2@\xd3\xe2\xc7\x01\xeb\xe1za#\x06\xbea\ny#\xeb\x8b\xcf\x17\x1d%\xf1u\x86\x0e\xd6R\x9e\xbd\x0b\x96<\xce\xb3\xf6sO!\x00\x8aH\xe1\n\xb7\xe9\xbb\xc4\xa7\x06y\x94\xf0\xb9\x18@\xf9\xcb\x81\x88\xa7\xe0UNt\xe6\xce\x1d\xd6\x8b\xf8E\xf6.\x98\xbe\xef\x81u\x90J\x86\x05\xa4\xba)\x12E\xc5\xf5\xfb/\x8f,\xcb\xbasa\xd9\xff3[\xff\x97\x95\xfe/\xb5\xfe\xb7hpj\xf3@.\xfb\xca\xd8f\x18\xef\xbf\xd0\x98\x8a\xb3\x15B\xc8\x80\x0c\xa7 \xa3\xd7^\x92A\x15\x05.\xf1\xcf\xb9\xd8XE\xb3g\x18\x1ct\x7f\x7f_\xcf\xb9\xba\x92Q\xdb\xcb4\xb1m\x0fvvv\xd8\x88M\x9d\xb9\x83\xa6\xe8z>\x1aGmI\xcc^\xb2}\xf6\xf3\x0f\xd2\xaf\xd6\x90m\xb23\x97}\x82\xd2M%\xaa\xa8\x03\x07t\xde9\x05\"\x18\xec\xd5\x15\x83\x01\xb2}\x0dK<\x16\xb4O\xbbE\xda!\x1e\x0d\xaa\xfb\x1aT\x1d\x0d\x84\x9e\xae\xb0\xabl\xa1h\xbb\xe6\xc4\xae\x8b\nA\x08\xe8W\xb1\xb3\x91\xc6\x03\xd2b\xae\xb2\x8c}'@Hu\x12O\x84\x1e\x0b5 \x05\xfc\xa4$\x9c\xa6\xdf\xa7\xea\x1eT\x839\xbd\x0d\xcd\xdaP\x96\xd5\xd1\x96\xdc\x8b\xd0\\I \x01bp\xec,\xbb4\\Ctn`\xb9\xe5c\x88q\xc6\xf8\x8b\xdf\xb7\xb2\x05\x1a\xbe\x98\xd5\x11\xf3\xd1\xda\\\xb3\xe0\xca\xa4\x01\x87\xd8\x0e\x9e\xb2\xb8\xc9\xb7\x08\xbf\x98r>K\xd9\xd2\xbf\x08\x96\xf9\x92\x15z\x8b\x0c\xa1\xf2}9\x1b\xd9\x1e\xde\xdf\xbb\xffpg\xf7\xfe\xde\xf5\xdbk\x07\xe76\xad\x17\xdd\xd5\xafx\x04bG\xee\xb8\x1d\xcb8R\xc4^\x9c\x14{q.\xdd\xc0Kk\xf258\xe5\xe6\x8d\xd8G\x13\x9bf\xc4\xd7\xdd\xfb\x02\x8b0X\x04\x99\xeaZ\xbb\xc1\xc0i\xf9)b\x0b\x12\xa3W^\x11\x0cr\x00\x99\xd2\x1d\xc2m K\xcb\xe46(\x9f\x83\xf6xW\xeb\xae\xb1\xb32\x044q\xf3\x01\xc2F\x9a\xc9y)\xff23\xd3\xa6\xcc\x10\xda*R\x1f\xed\x15\xa9\xc3\xedm\xb8\x0f\np\x02\x18 \n\x8e]\xae&\x02\xdcz\xff\xf7\x1f\xfc~\xafq\x1d\x9av\xef\x84\x1d\x85\x8e\xb1 \x82\xc178j{\x15D\x96a>\xabK\xb5\xea\xbe;\xd1\x05\x87\x1f\xdc\xe2\xc2N\xe4\xec\x0co\xe2\xdb\x93\xf4]/\x1a\xee\x1d\x1f\xf3\xf4\xcbx\x96\x87\xbcW\xa7\xda2T\x90\x1eJ\xc1EY\x0f\xc4\xd3k\xb2UQF\x00\x89*\xec\xb1X\xbd\x96\x1b\xd0\x07\x93\xdd\x08\x1cq\xb8}Pw\xf3\x1b\xcb\xac\xfb\xdb\x10\x95\xb3\xc8S\x1d\xc0\x90cd\x1f8\x12\x99r\x9c\xd2\xef+\xb5Ca\x9c\xc0\xba\x9f\xbe\xf5\x88\xe9/\xc7\x04\xa8}\x87&\x8b\xd3x\xb9\x8a#A\x0e)8\xa8\xe7\xd9j5b\x97\xc5\x0cZ\xcb\xf9y\xb6\x88\x93\xe0\x1b_\xf4\xe4u\xbc\xcaW#v\xd2\xbd\x1a\xff4\x8bF\xecx\x8d\n\xafV<\x81\x8fA\xcd\xf3n5\xd3\x11;l/\xf9,\xcf\x16/2\xbe\x1c\xb1\x8b\xf6\xc2\xa2\xd9C4{{\xdb^:\x16\xc5\xb7G\xecY{Q\x7f\x15\xfc&\xbf\x14}\x19\xb1\xe7\xed\xc5O\xfc4\x98b\xe9\xf7\xed\xa5\xe5\x91\xe4U{\xc908\xe3ox\xba\x8a\xa3\x94\x8f\xd8\xeb\xf6\nA4\x8fG\xec\x8f\xb4\x17|\x11\xcd\xe3\xe7\x18\xd8\x9d'#\xc6y{\x95\xdf\xc8\x97\xabw\xf1k_\x8c2\xebP>\x8e\xc2 \xe2?\xf2\xc3`\xe6gq\xf2\xa9?;\xe5#\xf6\xaeCE\x85]\xe9\x88}\xb9F\xf1\x11\xfbi{\xe9\x02u\xdf\xe6\xcb\xa5\x9f\\\x8e\xd8\xcb\xf5+} A1G\xec\xcd\xfaU\x11~\x9f\xb5W\\\x04\xa7\x8b08]d\x82\xe1\x18\xb1\x9f\xb5\xd7H$\xa6\xa4#\xf6y\xf7\xd2#\xf6M\xf7\xc2\x9f\xc6\xb3\xcb\x11\xfb\xb4\xbd\xc2\xcaO\xfc%\xcfx\x92\x8e\xd8\x8f\xd6(\xfe&>\x1f\xb1\xdfh\xaf\xc0/\xf84\xcf\xf8\x88\xfdV{\xd9\x05\xf7g\xd0\x91\xdfl/\x0bF\xb4\xe9\x88\xfdZ{Q\xb8\xc5\x17e\x82y\x1d\xb1\x1f\xb6\x97\x8f\xcfxr\x16\xf0\xf3\x11\xfb\xed\xf6\xc2\xf38\xce\xc4\xc2\x8c:,\xb4\xcf\x830\xe3\x89\xb6\x9a\x93\x0e\x95^\x0b\x88\xe3t\xc6\x1d\x8aO\xf3$\x1c\xb1\xa0C\xc9t\xba\xe0K\x81\x83~\x87\xc2o\xb1\xb0\xd6\xf7\xbcC\xade<\xe3\xe1\xe1\x85\xbf\\\x85|\xc4\xc2\x0e5\xbe\x145~\x9c\xf8\xab\x95\xf8\xc6\xb4k\x8d\xe7q\x18\xfa+\xb1F\xd2\xaeUFl\xde\xb5h:b\xab\x0ee\x0f\xa3|)\x9b\x9eu(\x8e\x8c\x8e\xac\xb0\xe8P\x01\xcc6e\xf9\xb3\x0e\xe5\x0bg\xf7\xb2\xce\xb2S\x1dd\xb8F\xec\xb4C\xe9w\xc9\xe5\x8b\xecU\x9e}\x9ag\x99 \xeb\x97\x1d\xea|\xe9'\xefg\xf1y4b\x17\x1dJ\x7f\xea\xa7\xfc\x0b\xff2\xce\xb3\x11{\xdb\xa1\xfc\x8fx\x92\n\xde*\xf1O\x97>\xae\xb7\x11;\xe9^\xf1m\xe6/W#v\xdc\xa1F\xb1a\x1c^d#\xf6\xc5z\x15\x80|~\xd5^\xe7\xb5\xa2\xb7\xf0\x91__\xa3\xc2\x8bh\x1a\xe63~\xb8\\\x89\xd9\xfcq{\xcd\xa2{\x10i\xe4\xc5\x1a\x154\xaap\xda^\xed3\xceW_\x04\xd1\xfb\x11;\xef\x00e\xc1\xff|%H\xda\x1f\x1d\xc8\xd7\xe6\xb2\x02ap\xeb\xc6\n\xeaw\x03i;;}\x96\xa6\\p\xf8\x87E\x87\xc8\xd2\x9d\xe4\xd8\xb4\x9frV;K<\xef\xa4F\x88:\xb5\xf5\x9eh\x8b\xd4\x1c\x8dg\x05\xbc\xd9\xbc|M\xcbW\xbf|\x0d\xcaW\xeal\x8az@\xf9\x8a\x87\xbb\xb0L\x88<6-\x7f\xad\xca\xd7E\xf9zV\xbe.\xd5k\xe3\x89\xf7\x15\x87\xe0\x03\x8f\xa8#/\xe6m\xef\x1a\x11\x8e\x8a\xbc\x9d\xedz\x9e_\xe4\xdd\xdf3\xa2\xe5\x14y\x0f\xef\x1b\xf1\x80\xca<\xe3\xf8\x1d\x96yF_\xa6E\xde\xa3\x9dz\xde\xbc\xcc3\xfa\xb2*\xf3\x1e\xd6\xf3fe\x9e\x01\x97\x85\xca\xbb\xbfe|\xef\xac\xcc3\xda\\\x16y\xc3\xadz\xde\xa9\xca{\xb4c\x8c\xef\xb2\xcc3\xc6pR\xe6\x19\xdf;.\xf3\x8c1\x9c\x17y\xf7\x8d\xbe\x1c\x96y\xc3z\xdeE\x99g\xcc\xfb\xdb2\xcf\x80\xcb\xf32\xcf\x98\xf7\xf7e\x9e1\xef\xcf\xca<\x03.\xaf\xca\xdaq\x07\xdc\xebv\x11G\xab6\xcd5\xd9\x1amW\xc7\xceQzs\xa8\xc5\xe8=}\x10\xa0\xad\x1a\x04D\x10\xa0\xadj3b\x1a5w\xc9\x807\xbfU5\xb2\xf5x\xfd]ugDN48\x81\x1eD\x837\xf0\x03tX7#\xd7\x12\x8e\xa3\x00X)\x8d\xb3\xdb\x87.>\xaa\xdd\x02\xb2\xaaM\xf1\xc1\xaf\xf3\x14Y\x11\x8f\x84)\xc3\xf6\xd4j\x82\x10\xaf\xb4F\xf5\x98\x06z\xc2\xff\x8c\xf9H\xf5-\\j6\xaf\xbe&\x13\xc9\xd0\x19\x14&\xc5\x1b\xd3\xd1\x0c\xc6\xc2\x82D\xff\xda\xaalar\xad\xaf\xb54\xe7\x05ab\x9b\xe7\xac5\xd6\x1a\xec\xe4Y\xe5\xae\x1d\xb1s\xdd\xc7\x01n\x96\x06\xb8\xa9\x0c\x106]\xb7_$\xa9\x86;\xb8\xbfg0\x14.\xe7\xac\xa9\xcc\xb93D|\xc1\x83\x0c\x83\x9b\xd1\x1b\x98\xa3!G\xe2\xac\xf3\x00x\xcf!\x85\x97\xb0|\x0e\xcb^\xcf\x05\x8c\xea\xbe\xec\xc3\n&p\xed\xac\xa7\xcbY\x1f\x96\x8c\x8c\xb0\xaf\x86\x10+\xe6^\x99\xf4-\x0e\xc6\xb5p\xf7\xc7A<\x87\x0e:f,\x06!\xbdM\x1d\xd7E\x0f\n\xcd\x10\x88\xb3@\x17\xadi4\xc0\xab\xe8>\xb0\x01q\x8b)Q\xa4\x19\x944b\x924}\x9f5W\xc9%\xa6\xe0\xfd7!\x1b\xd5\x8d\xcd\xc9\xc6\xb3\x9d/<\xc10{6;\xc9\xe3\xc1B\xd4\x89\x9c!\xab\xc8\xa6NyT\xeb\x07\x12\xef\xd0\x19\xed\xed!)\x15\x14\xf5\xd9\xa6 \xac[\xe2\xef\x9e\xf8\xfbTKh?p\xf3\xc46]Y\xc0\x95\x87\xcd\xec\xcb0\xbf\xb5\x88i\xbc\xcb\x9a\x83A\xa0'\xd0\x92$VI\xe8BO\xb8\xd7\x82u\xa9\x14\xcf\xf9zU\x87r)\x1a\xa9\x96_\xf3N\xb7\xab\xe5+A\xe7\xab\xe5KQ\xbe\xe3\x0e\x12ZQ\xcb\xde Z\xbf\xe3:U^_\xf4^\x9d\xda\xb9h\xad*Y\xde\x88\xf2*;u\x88\xb1ws+\xb3\xf2\xc3[\x1eI;\x8e<\x9aT\x82q\x9e\xe0#\xb1\xee\xe5G\xaf\x18\x05\x17/!\x01\xf7\x9c\xdb*w_1\x0f\xa9(b\x0f`\x1fw\xc9\xc5`Q~p\xcc\xd8\x97\x8e\xdd\x04T\xef\xcf\x0e\x8a\xdd\xc9\xc9\x00\xa3\x8f]S\xa7\x8aG\xea\x87QC\xa7\x9cZ\x17\xed\xa6\xa6\xa13z\xe6*\xb9\xcbg\xad\xac\xfd\xe4\x87:W}\xb82\x1b\xc3\x1b\xa2\xe1\x08\xc2\xe5\xbcb\xf4]{>\x8a\xb5\xf8H\xff\xe0\x11\xd3\x0e\xafi\xc8M\xdb(w;\xbbr\xd5\x94\xa7\x9a\xa0\xf7\xe6 \xc8\x9f\xab\xe8\xf7\xa1q\xce\xd7\xf5\x8c\xa5P\xcc\xa3\xe3t\xd6\x0e\x8fi\xa9\x8b\xea\x84G\x11\x1f\xb6p\xa2)\x0f\xa7<\x98\xd3\xa6`\x85 M\xf0\xe9\xe0\\\xebM\x0bH\x83\xcfCt\xa7\xd4/\xc0\xb5\x08xH\x07\xe7\x9e\xbe\xc6]\xb3\xc5-\xa8\xd2#O\x18z~\xcd\xcd.\xd1\xd0\x91\x0e\xce\x93RZ\x8c\xbcE\xa37\xb9\xfc\x08c\xd8\x82|F\x18\x817\xba\xc2\x98\xa5\x0b\xe2[nq\xe4'\x11\xf1.ps4W\x0fDu\x86p\xcd\xb5=\xac=\x8fV\xc4oH\xede\xde\xc1\xea'c\xf2\x0c\x1at:\x9b\x02v\xe8\x14\xfb\x07\xda\xb5\xe2\xaf}tj\x15\x0e\xb2\xac>\x97\x83\xc6\xe0\xa0\xb9\xbd7\xa0aJcG\xf0\x1f\x19\xba\xbap\xdfPo@o\xfd\xd4\x11\xeed\x9d\xa1\xcb\xeb\xb0\xdd\xa6\xd8\xe2\x07\xce\xa1\xd3\x15\xfbn\xc3\xbb$~\x08\xde\x9d\x17\xd0.\x0fI\xcd\xd6\xf1\x83\x13rk\xd8<1N\"\x9cA\x13\x87\x9f\xd8\x81\x13\x9b\xa9\x01T\xf7e#Xp\xfc\x1d\"\xe6'&\x11\xe8\xdc.\xd5\x8f\xde\x95\x07\x9f\xd4\xf8\x8d\xc8\xb7\x08\xaf\xec\x89 O\xec\xa08uR\x94D\xad#\xff\xd8n\xe4\xfch\xd2\x0f\x9e{\x15\x0e\xce\x8d\x01=\xc3bR(`\x8b9\x19\x8e_\xfb\xb1\x8b:q\x19\x98\x99o\xac\xe2\xf0\x03\x8f\x84\x8f1\x8c\x98`\x1e\xe6\xe0\xa7 \x0d\x16\xb60\xba\x08\xe7\x0f\xe8&=i\xcb<\x81\"Z7\x9f\x85\xe77c\x08\x9b9\x93\xf3\xf9X\xcd\xf1\xaf\xfb\x18\xb8r\xf9i\xc7\xb1\xa4\xf9E@\xe0|\x14\x01\x9e\xd9\xf7#\xf1\xfd[\xb2\x01Gy\xbe\x8c/?\xf9]v\xc6\xe4\xe8\x1fr\xf4\x1f1\xfc\x0e\xfb\xd01\x8d\xb7\xdd8\xc5\xf8\xec\x13i\xb1~\x0dk\xf7\xd98\x7f\x8deQy\xbb*\xfe\x11\xb8\xd7O\xac\x1b\xf6RD.>\xe9\x83\xdc\x14\xdd>t\xcf/\xbbn\x1f\xe6\xdc\xd5Jx\xcc\\\xfaU\x17;=\xfaP\x07\xd1\x84\xb7\x9bc\x8a\xfcY!.V\xa0\x1f\x15=\xd7\xe0\xa1\xa8\xbb\xfa\xfc\x107O\x925Ppv\xfc\x97z\xf2\xf2\x92\x84\x8b/\xfc\xc7\\\xf2~\xf8\xeb\xbaV\xf9R\xad\xcc\x19\xc5b@nq\xa5&\xd4\x1d\xbb\xaes\xa2\xc4\x8c\xaa\x8d\x8f\x86\xe3fQP\x8ar\x07\xceJ\xae\x9ak\xd3\x15FWe\x9dtGI\xce\xca\xcey\xb67\x98\x80e\xd4\\\xe3\xd9\xc9jq\xe9\x07\xd9\x18v\x16\x8b\x9f\xe3\nL\xbc\"\x97\x8f\x841k\x80\x7f\xad>K\xd8\xb3S1\x8f\xceH\x0dTS^\xe7\xf2>Bti\xd2\xdc\xcb\xebH\xd6\x11\xaa\x10\xe48\xcd8$\x82\xe8\x18\x89\xb9\xd4\xc1\x84\xf4\xa6\xea\xb8\x89\xdd\x14\xe9\x07\xa8\x98\xa18Q0\x04\xecG\xbc\xaf\x1a\xb9\xf9#\xc6\xa4\xe0\x93#\xf1D\xc5\xe6\x8b\xc1\x82\xad\xb2\x15\xa5\x8b\x08\x0f\xfb\xfb\x80>r\xfc+a\x1c4\xbd\xe1\xbe[c\x0c-R\x9a\xe4\xc2Y\x0c~\x82\x1e,\x06\xbf\xe1\xffx\xbfr\\E\xc8\x0f\x92):)\xbd\x1c:\xcf\xf6\\G%\x15B\xbb\xba\xeb:j\x11\xa9*Xy\xbf'\xa5\x1e\x15rS\x9d\x1a\x83N\xd3\x1aK\xfe\xe8@G\x98@\xd1<1\xf4\x14\x10w\x1d\x1e\x8aD\x8bg50\x15\xc3u2\x06\xe0\xce\xb1k\x1d5.w\xd3\xb0\xc5\xa8n\x9cL\xee\x8d|\xd9Nro_+\x9aV \xe9\x1c\xb3\x86\x1ao\xc8N\x06x\x84\xbb\x03\xdc@\xce\x95\x8a\x15\xb6i\x91 h\x9a\x92\xca\xa9\xea\x0f=N\xb4R\x83\xd2\x92\xbb\xf2Z\xb57\x91\xa8b\xd6\xd8\xf8\xed\x05UIFm\xb9 A4iI\x90\x0f2\x96\x8b\x99\xc5\xbaf\xa4\x9c\x9d\"\xed\xd5\xac\x18|\x01\xf6\xc1\xef\xf5\x9a\x19\xc0\xc4\x90\xb6C\xfd\x88\xec\xc9\x9c\x02\xb2\xbd\xd9\xeb\xf5\x0be\x19\xc3\x88\x96\xa9\x0e\xd4O\x82\x9cE\x92'q\xc8D\x12\x89\x8d\x0d\x94/b'lb\n\x8d23\x084W\x9a\xd2\xd6\xd3eG\x90.\xc6\x03\x1e}\xc2\xf1\x07\xd7m\xcf\x95\x98x\x8d{\xf7[!\xba\x19\x8b\xa3\x07`\xf1\xc3q\xab\xbe\xea\xc5\xb6\x03\x8b2O#\xdd\x82}\x05\xa2\x81\x08\xc0\x1b\xd9V@!A\xf8\xf5KmMtgu\\\xdcuc\x94\xc1\xf2P\x93\x1b\x1f\xb9\xce4\x8f\\P\x87\x9cG\x12\n\xc3\xb1~%e\xb8\xa1 P\x8c%L\x85\x9aT\x03\x12lg\xd4\xa2\x9dt:\x9c\xa9m\xf5!\xd5gd\xc7\x167[\xb6\xc8Z\x19i\xda\x15\xe5\x86\xd6\xb7\x1e\xd4:\xfb\x7f\xd3\xd8\x87xj\xe8i\xfb\x0bzb\xffo5\xf4'\xea\x180N\xe9B\xc4=\xc66\x94SQ\x8b\x91f\xbb\xb1\xea\x8d\\d\xb9\x1d\xc5\x14\x84\x83\xf7Y\x8a.1\xc7\x17 \x8d\xaf)\x06v\x88\x07\xbf\xd1\x8b_\xfc\xb4\xfa\xac\xfc>O#\xad\xbd\xde\xcc\xf0\x91\xf6z3\xa9^o\x86\xce\xb3-\xd7!M\xd7\xf9ZNX\x1ay\xb5\xca+\x19\xf7ui\x13\xf0> \xa5\x00\x94\xde\x88\x90*\xa4\x06\x16o\x00\x9e\x035&\x98\xe6J\xeeE\xd8G\xbe\x9c\xa2\xdd\xc5\x97(\x88\"M\xd2\x0cPEScl4\xc8\xa3\xd5cl\x1c$\x04\xa9\")\xb6\x8d>V/)\xb5\"\x00\xc2\xaf|\xca\xf8\\\x9e\xaf\xbf\x00'qy\"D\xdb\x9a\x90\x81\x0cv\xe9\x04\xd6\x06\xf3D\x1e\x1d\x9fcgH\xae\xfd%I\xa5n<\xff9HR\x12\xceI\x10\x85\x1a\xad\x05\xc6\x7fC\x83\x1ey\xda\x98\x00z-\xf2\x7f\xe5\x15\x1d\x83\x1a\xaeq\x8a\xf2\xe3\x89\xc8\xa5\xadu)|\xce\xad\xda\x8frU\x95.M\xb5\x06\x92\xfa\xdd\xb1\xe0\\\x94\xb6\x8b5\xec\xc3<\xf2x\x94\x1c\x1e\xff\xeb\x94\xde\xa6G\xd1\x9c:]\x9d\x8e\x92\x8b~\x81;\x888\xe5p\xd6\xba\xb0Q\xec\xe3]\x92\x98x)\x8d_\x93\x94\x8c\xaby2@J|m\x00\xb1\x1e\xccI\x8a\xb7\xbel*\x8b\x06\xfc\xd6\x12\xe1\xbc\x0f\xedf\xbb\x16A\x08\xf5\xdd/\xc21\xc4\x06~\x0cS\xb2\xf2\x9d\xd4\xb4D\x80\xfb\x8e\xc7\xb2b\xef\xc1>\x86\xcf\xa5<\xfe\x0c\xcf\x0e\x1a\xa2\x9e\x1c\x1f\x19\xe6\xd4\xea\xdch2\xbd2\x9c&5\x93J_o\xa8\xc5\xc5\xef\x9a!\x8fLA\xae\xda\x804\xd0\xfe\xdaN\x95,\xb0>\xc1,\x8f\xa8\x15\xf1\x88Zq-D!W\x07\xe1ej\xcaD\x06\x8cf\xbapR\x0c\x93\xaaa\xc0\xa2p\xe1/\xb3\x98\\p#\xdb\xfa\x12/i\xda\"\x0c\xa0\xa2\x0djB\xcd\x07\x9e\xff\x8d\xeb\xa87\xa13\xaccm\xd5\x89\xc1\xf2*\xcbm\xa2\x8aNc'\x1e|\x80\x1e\xc4\x83\x8f\x16i^\xa4\xf7j+\xe8\x10\xa1\x9e\x8b$G\xc1\xf6\x82/\x7f\x18\xa4\x9c\xd0\x84\x1e\x9a\xa0c5E]\x08\x93blF\x93\x17\xf1\x1aOH\xe0\xb8U\x11\xd6v H\xe5\xa8\xb6\x82\xee\x1a\x8f1\x99}\xf8\xee\xe3\x12\x91\xd3\x1e4,\xb3\x96\xe8;\"o\xddt\xcf\xcfM\xf7\xca\xe8xbA\xc44n\x8d\x84\x11#\x11\x987\xda\x88n\xbe\xd6\x92A*\x00\xc3\x01E\x93\"\xa1u\x1d\x17r\xb0\xeb\x84(\x9f6k\x04\xdb\x00T\x82\xce\xba\xde&b\xf4\xd9A\xa32\x99_\xc2\xe9*\x15\xbb5+J\x0c\x01?\x88\xe9\x92\x864f\x0c\xd8\xc7,L\xfd\x15\n\xdd\xc2\xa9gIS\xc5\x95\xe7\x88\xach\xe2\xc4\xee\xc0\x0f\xe7\xf4\xf6x\xc1\xda\xaf\xbe\xdcu\xe1eM\xe3\xe5\x83\x08c\xa7\xeb\xae\x809&{\xd1\x0d\xa8\xe0c\xcb\xd6\xb7{\xec\xd4\xc2\xb4\xec\xfa\xb7\x94\xc8\xf9\xc8;\xd5yx\x11}S\xf7~\xb1p\xc6\xeb%\xeb`\x8b\xf7\xb5\xeb\xae\xb6\xa5\x18u\xd6\xeel\xf4;\x0c\n\xa37tU\xaf\xf8`\xd5\xb1\x9c/v\xd95\xab^\xcb7\x91\xdd\x93\xbb\xd5E\x14\xc0D~\x19\xd7\xccVA\x9c5\xfe\xc0O9@\xd0\xbe\xf1?\xffS\xfe\xec\xd6\xeb\xa3\x8e\x92\x87}}[~\xa9T\xa6y3\xc17e\xb0\xc3S\xb2\x14\xef)%\x9a\xb7\xf0\x92*BX\x95\xce\x94zMOX\xf7\x99\x91\x15\x04\xc2z.\x04\xc8\xf0\xa9\xa8\xe9\xb9\xad8w\xc7\xd4\x0d\xecC\x80\xb9\xa6d\x93\x0c\xde\xee\xe0&&\x8c\x99?\xaf\x93))\x03t\x93,Y\xd3pN\xe7')\x89S\x0d\x0c@H\x04E\xcd\xbf\xfa4\x98\x1bj\xa2C\n\x8f\xa9\xe4\x87:\x90\x820\x06\xefz\xd1j\xcd\xf6\x92\xa9\xa5k\x9ePA\xfbl\xa5qC\xc4\xf2)\x995\xd1Bhb\xce\xf4\xc0Z\x16\xbbfI\xd3\x0fr\xe3\x1c/\xf4#\xbc\x83}X\xb2e^:K\xe7\xbd3\x9d\xb9\xbaKS\xf48\xb9C\xb3(\x14n\x85pw\x87I\xb3ej\x91;\xcd\x8blD\x17h\x9c\xad\xde\xf9\x1e\x96~\x95\x028;+M+\xb7\xa5\xfa\x17\x15\xeb\xed\x93>\x9cT\x8an\xfbp2M\x18\x88o1MW@\x90\xc6\xb3\xe5\xfcIb\xa4(\xbf\xf8\xa5\xcf\xd7mp6\xc3\x83\xd2\x19\xb2\x0fW8m\x8c'\xaeu+\xb5!j$n\xe8\xaf\x9cs\xf5\x0d{dh\xed\xde`\xa7\xf9\x04\"t\xca\xe2\x1e]\x0f\xb9'\xcbU\xcb\"\x9f\x0e\xe5\x8e]Jk\xfa%\xd0\"\xf7+\xc4\x8f\x8b*vuY\xd97 \xb2}\xb8\xc8O\xe3\x074\xd6\x9d\xf2\xd3\x18\xf2\x01Ur\x1e\x82\\\xe0+z\xd7\x9c\x8a\x04\x14R35\xa46\xa8\xf9\xaf\xa7\xd2\xa8\xc4\xba\xbe\xec\x94\xbe\xa6qB\xab\\\xb4\xfa\x91\xa3\x83f;>\x91\xd9@\xde\x1d\x19\x15\xd4\xeaG\xca\x06\xe9`\x1d\xadMZM\xf5\x83\x0c\xb5\x98fn\xd0\xc3\x91\x08\xd3h\x84\x1c\xb5\xb8\x91\x92^l\x94\x1f\xb3\xa5\x1c(\x02q\xde\xde\xd0\xd6\x9e\x96Hx|`l\x91\xdf\xf7\xe1\xb4D\xe8\xf4\xa0Q\x0e\x8c1\x9c\xeaW%\xa6 m\xb4\x02\x91\x1f\xccz\xc1\xedp\xe8\xb5b\x9a%\x14y\xf2gBCy\x81;8\x17?B\xf1L\x81'\xffM\x03\xba$\x18\xa5\x84'\x92\xc4\xd2\x15\x86 \x95\xd9\xc0\xba\xa2\x94\xc4K\xa5\xa54\xbe;\x0c\xd3\xd8\xa7\x89\xcc\x97\xec|p\xfb\xd0i\xb0h,\xa2\x9d\xb3uG\x91\x17\xbaiWxo\x88P\xdbCW\xe1N\xb8v\x86;Kux\xea\xb4\x9eL\n;\x12 \x86X\x1d\xe1[i :z\xf0'i\xb4n\xa1\\\x03i\x00\x95\xa3\x8f\x19\xb7\xa5\x0dU\x05H\xd3\xe1l XP?\xb2\xb8\xd8`*}\xd4\x93p\x98\xd0\x01\x1eJ\xf2\n\x86-\x82\xf9eU\xd3\x14_\x93zb\x020\x83\x821\"L\x8c<\xbc\xf5\xe8:\xc5\xa8\xb4\x0f\xc4J\x06\x9c|\xa0v\x00\x156\xdf\xcd\xb4*vL\xa9\xf6\xd5\x8f\xd4J\x0d\xc4\x96\x140\xecC&\xf0\x16m\xc4\xc5NA\xef\x11\xae\x04\xaf\xa3\xba\xc4s\x86\xcc\x1d\x8b_\x85y\xe4\x12\xc5\xfd:\x1aHg\x9d\x0d\x18=\x07\x1fU\x11\xcfacC\x1b\x17B\xfd\\\x8b\x1c\xffU\xac\xf2\x1b\xcc{@H\xb1\xa4\x15\xf2\x81D\xc08\x8a\xc4\x9e$\xac\xb7w\x91\x97\x13\xe8\xd8\xe9\xd2pn3\x1d\x97\xad\xc8W\xe1\xc5>\xe4d\xabi\xa2 &\x8b\xb9kD6\xf4>tQ\xc3\xf1.\xf2\xba\x96\xd3M\xfd\x04\xe5\xd7\x85J\x18\x1bhw,\xe1\x9dm\xd0f\xb4P\xa3\xcc/0=/\x1f\xb0\x02\xb7\xa2\x10\x1d\x10\x9a\xc7\x01\xda\x96\x8b\xb9\x94\xdaV\x8a\x1b\x1b\xfe\\\\z&\xdfs\x8a\x8d\x0d\x7f6i\x1et\x1f\xbc\xa3\x0d\xd4\xfc\x1b\"\xf7F\x1a\xdfA\x92\x92\x94b\xd6\xf4\x1b?\xbd\x8c\xb2T(\xc5\xa2X\xde\x07\xb4Yy\xf8n\x10\xb7\xd6\xb0\x98\xf9?\x84\x84\x93\x8b8[\xa7-l\xac\xe5G\xe15\xed\x94*\xcc)\x95\xf1Z@~r&\xb0B\xa9B\x03\xbf+?\\\xb9\xaa\xa1\x18\n+\x10W\xb6rny-\x96*.-U3VI\"m\x10\xe8\xd5\xcfEL\xc9\xd57]D@}&\xa6)\xc5\xc6\xc5y\x8f\xfa\x02\x99>\xac+}z\xf0\x16Q\x01\x0e\xc8\xd4%\xbe2el\xcc\x17\xac\x9c\x05\xdb\xe5a\xe2s\xd7\xd7\xfc`@-^#wA\xe4\x11K\xfb@\xc4a\x99\xf6\xb11\xc7\xc2=\x8a\xa3W\x1do\x1f\xae]a\x0e,GA\x1d\xf2 \x06N\xbe\xf6\x00\xa4\xff\x16\x1cVi\xc58<4\xcb\xc6\x1fLJ\xf3\xc7\xf6a\x0c\xe2\xea\xa3R\xd3\xc9Y7\xb9\x83\x04\xf3\xc2\xfe\xd6\x98s\xd1D\x19\xc0\xfctf=\x84Q\xbc\"A\xa9\x07y5\xed\xa8o\xa4n\x1f\x0c\x1e\x7fz\xa0/\xfc\xd0O\x1a\xfd\x13\xf2\xda\x05\xc7o'2iNd\xda\xf9\xd3k\x88L\xda\x82\xc8\x84\xea\x8e\x11\xdbKe\x9csL\x0c\x95\xad\x81\xc9\x89\x17)\x8d\x19e\xe9\xa3\xe3\xb8 h\xf0P\xb2\xdd\xca\xdbC~\xfe\xfd\xa0)\xa8\x92\x80d;\xa2\xcb\x8d\x84\xdb\xb2\xa4\xa0\xd9\xb5\xb1\xd8\xb5\xcd\xfd\x81\xa26\x8b\xed\xbb[\xfd|0\xd9d\xab\x1f\xfb\xb1\x0e\x05\xc10\xcb\x11\xf0\x85GG\x8d\x0b\xf2\x03&\xca\x07\x82\xef!iJW\xeb\xb4\xfb j*\xb5\x01x\xe32\xae\xea%\xad&\x82\xea\x0eR\x94\n\xf6\xe5\x91Woc\x8c7`\xe7\xecc\x9adAzDVt\x0c\x0d\x01-\x18]{\x17yc\x83m\"p\x85\x0e?\x9d\xb8\xe2A\xa1\xab9u,\xc4@\x03q\xac\x95VM\xc0J?sy\xf6\xbcA\xcd+q\x95\x9f\xf1\x8a\x9eI\x89\x0fs(\xf2\xe6\x1d\xea\x01Q\xcb\xa7\xe9D\xaa\x82[\xfb\x0e\x11Z\xe5S\x07\xef8\xa7:[f\xb1\xc8\xfe\xe0\xdc\x0f\xaf#\x8c\x02j\xb3\x15P?\xb9\xdd\x80U\x8b\x99\xb7f\x8a\x95(?\\s\xc8\xd6n\xae\x11\x08rm-\xf8 \x90 \xa6d~\x07q\x16\x86~\xb8\xb4\x89\x01E\xabZc\xf9jU\x95\x1e\xe5\x19\xc6\x0d\xd9\xf0\xe5GL\xf4\xadA9\x0e\xcd\x9a\x85\xb0\xe0\x00\"<\x96\x10O\xfd\xe7\x8d*Z\xc9\xf6\x85\xf9\x06m&\xef\xa4\xa9Q\x10\x0dg\xe8\x14B\x18\x064\xd3W4\x96m\xd32\xc8\xca\x08\xe3\xeb\"\xafns\x1f\xa0(\x85\x1a+\x7f\xa9x\x06\x12\x13\nZ\"\x97\xc7\x85Pjb\xc3B\x0d\xdb|\xfe\xe4\x92\xb9\x8a]E\xa3\xcd0+\x90x!q\x92m\xbc\xcb~\x9b\xde\x01\x9d\xa9j\xba@\x07_m\xf0v\xe2C/1\xb6\xa1BU\xc3\x01\x97O\x9d\x82o\xe5\xad6l\x18\xd8\x87\xb9\xbd\x8a\xd4\x17\xdd\xe4D\xa8\x19\xb1K\xdcq\xd2\x9a\x99\x10\xc0\x957 \x13\xb8\x841\xac\xfb \x8e\x8b\x87\"i\xe3u\xa6\xfa\x11I\xfd\xb0\xabvZ06\xc6\xb1\x18k\xe3\x0b_\xb3\x07T\\MrQ\xc3\xc9\xf1\xae\x90Y\xa4ZV\xd2\xad\xc4\x8eX\x06F\xbaV\xfa\x99-}\xd8\x07\xe2\xf6+\xc97M\xc7\xf0\x8d\xed\xc42;S4\xaeX\x8ai\xb5$z\x99\xd7\x89\xc4\xcb\xdc\xb3\x07\x87\xd1v\xa6\x8d\x11\x1c\xda\x0eQ,E\xc3\x08\xdb\x0e\xab\x15\xd0\x0f1\x9e\xa0\xe1\xe1\xad\xed\xe1\x89\xed\xe1+=0\xa6R\x01\x91c\x9d$=\xb3\xfc\xce\xcal\xd8&?\"hg;\xf1Le\x83\x05\x93\x84v\xb2\xadW\xb7j\xee\xaa\x9f\xf0\x95\xc5\x9a\xb4Nu\xd4\xd1\xa83\xb1\x19\x1a\xe4]\xf9\xad,\x8d\xe9\x8dt\xa7W \xda\xc0\xc3A\xc9\xb2\x90\x07\xbc\x8ey\x90\xbc\xa6\xd7@\xe1:n\x1c:\x0dg\x18a n\xc9{Hr\xd5\xd9\xdf\x177Fm:\x04\xe5\xa8\xc9\xda\x13a\x10\xd7\x11 \xbf@n\x1e!\x14pE\xcb=\x8dE`\xa0(E\x03L\x05\x8bV/]\x17&r\x1dr\xef\xa2` \x9e>\xc8\xb8\xa3\xfaI\x1d\xb9\x99\xa8X\xa2V\xaf~~\x88\xeb\xae\xfaI\x9d|\xd3>\xacC\x17\xc6u\x10|\xd5\xd4\x93\xdc$\x01C\xc9'-\x07\xd2j\xc8\xcd\n\x04\xe2d-x/\xb1w\xd2Z\xb0\xf8R\xad\xb6T\x08\x14J\x06\"K;\x87\xa0\x8f{z\xcc\xa8B\x9dv\xb5\"]\x07\xd6\xc8/<\xec\xa6\xd4\x0bL\xe5\xfd\xacF\x11U\xb0\xb9F\x99\x13or\xea&\x0e*\xb3\x92\xb6`\xac}L:/\xc74\x10\x80\xa9^\x1f\x17\xca\xd8\xc2PB\xcc\xd5\xd0e\xaev\xbc6\xd3\x84T\xc3:\xe5\x1d\x943\xd0\x9f^\xd2\\\xa1\x02\xf3\x88&\x10F)\xac\xe3\xe8\xda\x9fS \xf0\x18\xdf\x7f\x0c\xbcA\x93b\xc8\x86\x0b\x9aH}\xdaE\x8c\x90*\xc7}e%\xc5\xa85\xf4\xb9&H\x0bz,\xf1\xcf\x02\x80Hh\xc5\xebK\xac\x81\xa8\xbc\xeb\x89\xf4B\x90Tm\xe0\x95\x88\xe0\xed\x9dt\x8a4D\xe8\x9dfx}!\xe2\x99\xa7\x85B_\xa8\x9b\n\xee\x02\xcf\x95\xb4\xa4P\xb2\xdb\x19\xe8f\xc0\xb3\xcd\x8f\xcb\xef6\xa0@\xbe\xfc|\xd0\xe0s\x1c !\x88#\xc4\xd4W\xab\x9d{lwa\xd1o \xae\x1d\x1e\x03\x9d\x0egu\xf4\xa9\xaf\xc3\x88\x9b\x9ar\xa0\xc9\xcbd\xcc\xc72\x9a\xb9}\xd8T\x1f\xabz|\xa0\xdc\x1d>\xd7\xd2c\xd1\xd6\xcc\xad\x9b+\xa19]\xdan\xce\x1f\xecs\xa6\xea\xed\xd9\xfd\xbd\xf6\xfa,\xcdMR\xa4L \xbd:R\x8e\xbf\xa5F\xf6\xab\xd1\x94\x0d\x03;\xd5\x0f\xac2W\xd8\x87\xa9}]\xb8\xa9G}e08\xacd\x92\x8f9\x10\x8b\xc8N M\x9d\xea\xfd\xbei\xa4\xef\xf5#E\xaaj\xd3\x16\"|\xa7\xc4p\x07\x81\xb4]\xa1\x12|\x7f R\x9fom\x8fJ\xcf_\x1d\x7f<,?/eU\x1a\xbc>|s\xf0\xe9\xdd\xe9y\xb5\x9fQ\xa5\x1fY\xef\xcd\xa7w\xefJ\xf5\xb6wJ\xf5\x82\x88\xcc\xf1\xc2\x94}\xa9>8\x08\x82\xfc\xd9\x01\xe3 \x8a\xc7 Y\xd0w\xf2]\xf9CWA\xb6\xa1\xfcV\xab\xcd\xb3\xd5\x1a\xb95\xf6\xa5\xfa\xfek\xf9P\xfeP+\xfc\xf5\xe0\xfd\xbb\\q-`\xb0W\x9a\xdb\xfb\xb7Go\xdf\x1f\xbc\xb3-G[0Z \x98x\x84\xbb\xedv\xd9\xb7n\xe9\xd9\x9a\xc4\x18F\xd1w\xba\xf8\xb5\xfc\x14\x93\x19\xcb\xe7\xe2G\xb9\x06\x99\xcf_\x95<\xa5|\xa7[.\xeb~\x93M\xfc\xb4\xea\x06\x1d\x15\x00-\x95\x8b\xb4Z\xdb\xfaDq\x08\xbdRyV\x80\xacT\x9eh\x9cE\xad^\xa1\x01F\xbd-\x15y\x18\x07\xbaL\xaba\x1f\xb6\xcaE\x0c\x81\xb6\xcbE\xf3z[\x97\xf5\xb6\xae\xebm\xad`\x1f\x9eL\xcfn\x87\xc3\x8d\xb3\xdb\xe1\xd3\xb3\xdb\xe1\x8fg\xb7\xc3Wg\xb7\xc3\xc3\x8d\xb3\xdb\xd1\x9b\xb3\xdb\xbd7\x1bg\xb7O\xb7\xcfn\x9f\xeen\x9c\xdd>{s\x96\xbdy\xf3\xe6\x10\xff\x7f3\xbb\x9f\x9ee\xaf\x9f\xb2\x97\xb3\xd7?\xbey3s&\x1dV\xf2\x8a\x97\xb0\x1a\xee\xbd3\x19O\x7f/W\xbb\xff\xdd\xadT{R\x1e\xd6R\x0c\xeb\xe9\xceY\xb69\xdc|\x8a\xff?\xab\xd6\xba\xc3Z\xfd\xb3\xe9\xd9\xec\xec\x1fg\x9f\xab\x8f/\xd8\xe3\xdf\x9d\xc9\xb8s\xdf\xe9\xdcw\xa6d\xe3\xefg\x1b\xb3^\xc7\xfd\xf3\x13\xbf\\\xf3\xbc\xa89\xfd\xbdh\xcfu&\xe3\xff\x98\x0e7\x9e\x91\x8d\xc5\xec\x1f\x9b\x9f\xef\xf9\xf7\xbf\x9fm\xfc_\xcf\xcf\x9e\x9cM\xc6\xff\xf9h\xff\xacw\xf6\xe7\xfe\xf9\xd9\xa0\xf3?g?<>s\xce\\\xf6\xf6\xcc\xfd\xe1\xcfO|\xddYqc<+F\xc3\xc2\x8an\xb4\xc5\xbf+\xd4\xbc\xde\xd4\xa1\xb1\xa9gEK[\x9b-Z\xba}HK8\xbe\x87\x8e\xf5\xc4\xd8\xc3\xf6v\xd1\xd4\xb3\x91\xf2}K\xe9b\xb3\xf4c\xa7E\x87\x1a\xbd\xbaF\xc5,\xc7\xf0\x14^\xec\x0bgI\xf6mg\x0f\x13Zn\xb0\x07cx\xb6\xc7\xca0\xaa\xf8\xd6&\xdc\x0b\x9bF4a\x1c\x0d7\xd1\x9ca\x83U\xea1\xb0\x8cacd\x1d\x98F\xff]\x8c\x82Or\x02\xdd\xb3a\x97\xf7\x9c\x97\xfc\xff\xb0@\xadr\xc1JF\xa3]\xa5(\xc5J\xd5\x82Q\xbe\\\xac(\xe4EjK\xd7X4\xdcT\x8a\x16\xbc\xd6\xb6R\x14\xf3Z\xa3\xa2\xe8\xff\xcfJ\xb6\x94\xd7\x00\x0b\x8a\x97\x1ew\x1f\xc3\x18\xb6\x95i<\xc1\x11\xaa=\x9d\xb1\x92=e8\xff\xe7\x7fc\x9d\x1d\xa5\xe4\xff\xc6:\xeaL\x91*\xb0\xd2\xa7\xc3J\xe93V\xda\xedZ\x17\xe1\xc0\xb8\x08\xb8\xfe\xbb;;[;0\x01\xeet\x87y\x0b_]\x92\xf8U4\xc7\x9c\xa8c\xed\x83\x9d\x9d\xcdg\xbb\xd0\x03\x87!\x0eka\x17^\xbe\x84\x11\xe3uvv\xb76\x87\xe5G\x8f\x18\xbc\xb7\x14o\xd9\x82_\xcb\xed\xe4\x8e\x85\x9a\x043\xee9\x9b;\x8c5\xfb\xa0);\x054\x97;\x85\x17\xb0\xb9\xb3\xfb\x1cN{=\x17\x8e\xa7\xa73\xd8\x87+\xe7\xd4\x85 \x8c`\x0c\xc3>|(\nu\xc4\xe9\xbdV\xc1\xa9\\\x94Dx\xdf\xc7\xc3\x17\x0f\x16~@C\xb2\xa2\xa8,\x0b\xd7Y\x8aN\xb4Q\xe2\xa7huH\x07\x81\x1fR\xb5\x0c6D!:\xd0\x97\xe6^\x1f\xcb[\xedX8\xcf,\xc6i}\xff\x0f\xed\xfbt\x10\x85\xbf\x918\xf4\xc3%w\x8d\xce\x7f\x8a@\x85\xa8U\x12\xed\xeb\x16\x87\xad\xcbQMe\xc4\x18\xb7\x9a\xd1\x99V\xb9{]$\xa4\xab\xcb\x8e\"7\xf0>\xd0\xc15\x8d\x136\x8dG\x8f8$\xba\xf3l\x1d\xf8\x1eF\x1d\x84h\x01\xff\xc1\xba\x84\xb9\x1fS/\xf5\xaf\x91\xc7\xe2IC\xf2\xa4:\xf9\x9b\xe5\x9a@<\xc6`&@o\x89\x97\x06w\xc0d]\x99\x03\x12\xe3E\xb3A\xb0-\x85w\xe0O~w\xd8\xa17\xeb\xb9g\x03\xf9\xed\xcfO\x06\xf4\x96zN8\x1d\xce\xb8\x17\x1b\xef\xc8\x0f\x82\x8dE\x14\xaf\x98\xa4\"\x1a\x04L\xb0I\xa1>Z\xc6\x8e!\x03\xf96L\x9d\x18\xc3B\xe2^\xf1\xcb\xe5\x9b\xb2\x9c\xcf.*z\xcbB>\x13r\x11\x88\xf6%\xccD\x9f20\x1b\xe7?\xe5\xc3}\x081\x12%\x1dx\x97\xd4\xbbz\xe7\x87\xf4\xc7\x98\x92+\x0c{\xc1v\x90\xec\n\x0d\xdc7\x8b\xaf\x7f\x88^\x93l\xcd8Y:o\xe8\xb4\xb4\xba\xd5\xccb\x07?=\x0c]\xea\xb8\xb2iX\xed\xd3\x83\x9f,\x8b\x9d\xdeDE\xc2O\x06\x988\x07\x08\xf2\xc7\xb8\x0e\x17\x83\x94&\xa9\x13\xa3\xa8][\xda\x94,\x81'o\x01g\xe1\xc7I\x9a7\xe8J \x94\xc6\xc0zI\x84\xeef\x90\x92\xe5{\xb2\xc6\xcb[9\xe2\xc7\xe9%\x8d)\x9a\xbb\xc1:\xa6\xd7~\x94%\xc1\x1d\xcc\xa9\x17\x90\x98\xce!\xc9\x16\x0b\xff\x16\xa9b\xf71\xf4 \x86\x1e<\xee*\xc3x\xec\xf6\xe1\x9c\x0f92\x0fy\x1dS\xd6\x8c\x93P/\n\xe7-\xc6,\x07;\x8dg\xb6xr::\xfa\xd1b'\x89\xb7\x0cy>\xb5\xf2\xba\xa2f\x10^\xe8QA\x18\x93Ib+\xdcH\x11q\x8c\xd1\x81\xf1(\x89\xb8\x83\xad\x8fw\xbfB\xed\x06\x11\xbc\x00\x9f\xfd\xe9\xed\xc3\xc8\x15<\x83C\xb0\x8e'\x8e\xb4\x03\x06PW\xf0~/\xf6y|8\x82|\xcfh\xb4=\x1a\x8d\n`\xd3\xdb5\xf5\xd8\x9e\xb8&\x81?\x87\xbf\x9c\x1c\x1f\x15\x11\x0cuv\x8bhp\xb5\xe2\xab\x96)4\x84-E\x92\xc6\x94\xac\xd0\x16\x89\xf8a\x02a\x14n\xacc?\xe4[=o6\xd1\xb6+n=\xd8\xbc2\xd3\x9ai\x96\xecu\xb1d5\x87M\xbc\x7f\xe1\xeb\xd5\x87\xa0\xdc'B8\x1e\xf8 \x17\xfd\x9cP\xc1@\xa1\xaaY\xd1xIaE\xd6k?\\&\xcf\x11\xdb\xc4\xdd\xd6\x1c\x92(\x8b=*.9\xd8&P\xc9\x1aC\xc3\x8c\xaf\x1e\x13\x16\x1d\xc58\xf6\x8a\xdea\xa2\xb7|A3x\x01\x01\xfb\xc3\x17\x14\x9dd\xa6\xd9,\xdf{)\xda&`r!\x1e\x95 \x9c\x12\xb6\xeb\xf9\x0fU#\xae\x03\xcf;\x05\xa3\xd5t\xaa:P\x05}\xf0\xeax\xcd\xb0\x90\xb3MN\xa4\x9e2y\xc4\x11\xf8\x07\xe6\x83N\xc9r|GV\xc1 \x8a\x97\xfd\xcd\xe1ps\x8c\xf0\x13\xa6\xf3u4gm\xf3\xf4\xd2~\xc2\x99\"\xdf\x96\x958\xe0\xe0\xf4\xf0BL\xc2.\x80\x17\xe0\xb1?\x1cv\x12\x17\xfci0\xd3\x9b\xe4!\xf6\xe6\xd5\xeau\xf09\x1d\xfc\x91\xf0\xbb\x95$\x8f\x82\xcc T\xa7X\x13^\xe0p\xbe\x08\xd8\x1e\xc3\x0c_5\xd6i\x1f2\xfe\xa4`\xb0\xca|\x01\x9dK\x14\x83+z\x87!M\xd2i\x84\x17\x7f\xf9\xadM8\x8dfZ\x01(\xb5.\xfe\xa7V\xb2\x94\x102D\x8aMN\xa3\x14JR\x8c\x1c\xf32\x15?{=&Vl d\x98\x80\xa3>\xea\xe7\xa2\xa6\xb5E\xce\xcb\x15\xaf1\x1e\x9d\x83\x87\x00\x02\x16\x9d\x9e\xd8\xf6\x92\x84\x8aSx|\xd6\xc3\xe4C\ng\x8a\x13\x90\x8dY!\xf37\xd3\xd9]J\xc69\x94\x19\xfflSx.\xb2~GZchqyr\xe8D\xees\xd7\xd4Z\xaf\xa7\xb6\xa7\xdd)\xb8\xdb\xb6\xb8he\x08\xf0?\x8f,\x979mz\xd6\xbe\xfc\x19n.}\xc62\x8c\x86\x05#7\xda*\xbe\x8bb\xc3\xb8;7x\x14\xe12\xd6k t>a\xf2\x90f@\xf7!fx\xc5\xd7\xfbm8\xe7\xe6\xcd\xc3\xe7R\x90e\x0b\xa0>d\x95\x1f<\xed\xcf\xba]\xb6!8\xf4b\xba1G\\e$/\xf8c\xcel\xce\xe9\xc2\xf7|V\xec\xe3S\xe4\xfe\x91k\xb3b\xe5\x1b\xc3~\xed\x8bD\xb3r\xc8ZR\xd0q\xb6wpl\xa6\x8d,2\xe7n\xefr[\x01\x0c\xfd$\x84\x96z]\xe81\x82\xdaTe\x93\x13\xc1\x90m\xc5\xad\xbe\x80MC\xff\x9d['u\x1bd\xc8\xbfke\xc0QNjTf\x81\xeb.R\xcc\xda\xcfc\xce\x15\xcf\xe2AL\xd7\x94\xa4N\xf7\x0c\xcdd`\xa3\x94(K\xd7\xf5\x8f\xda\xae\xafE\\A\x89Q)\xd1X\xe2\xf9\xdck2\xf4.\xaby\xb3A\xa8\xa5u\x99Q2M\xae\x11\xeetQ\x08\x95\xbcM1=\xfe\x831\xb8\xf2;;,\x88\x90 \xda\x11+lk\x9b\x93\x13\xfc~\xebX_Dtp5\x97\xbe\x92\xb9\xed\x0c\xfbP\xa6\xffHbY\xf1\xc6\xc8\xad\xef\x96}\x06c\x99\xbb*\x0b\x82v\xa3\xafu\x9f{.\xf0\x0d\xc2O\xdf\xdf\x04q_\xf0<\x1e\x1d\xcc\xce\xc2\xbb\x92\xc8\xe1\x96\xc7\xd7\xa6\xf3~q\xd8#-\xc8\x8f{1\xa5\x97\"^\x8c\x00\xb0+\xce\xb1\x0b2W\x89\x00\x93Z\x08$\xf4o\x19\x0d=\n4Lcm\x94\x80|b\x15\"\x93ji\xa9$\x01\x9dL\xe0\x08\x13\x9c\xd0W'\xc7\x1dd'\xe8\xe0\xca\x0f\xd1\xaaG\x8e\xa0\xdb/6\xd3>\xe3\x0c\x9b\x18\xca_\xcd4*g1\xf95\xbev\x07T1\x9dMq\x8b\x9f&N\xf3\x11P\xd8\x0f\xe8\xdaQ6\x0c\x9b\xbfI\x03C\x84X\xc9\xafv\x18U\xde\x15\x1cP\x9b\xd3\x82\xf1@\xc8\xcfw\xcc\xdcA\xe5\x851lq.)b\xef\x12%\x01g\xb7\xd3\xe9\xb6o\x85\xbf\xd1\xedC\x99\xd11\x98<\x1b\xd9\x816\xdd\xd5^\xcc\xd9\x00\x85\x0b\xd8\xdd4\x1e\xfd\n\xe5(lF\xd8\xecc\x9d \\\xdaem\x86W\xb0\x89Y\x98K\xb04\x9cK\x9d\x80\x10Do\xfc\xf4\xd2\x0f\x81\xc05\x8d/H\xea\xaf\xd8\xcaW\x15<\xa6p \x82sS\xe6\xdb\xb9\xe5\\\\\xbe\x9al\xaf\x11\x98H \x98,\xa5\xceC\x08\x90B\x10\x06z\xeb\x05d\xc5\x11pE\xe2\xab\xa4\x9b\xa7k\xae\xc0\x82\x1dP%\xf1\xa1\x87\xc9\xed\x84bG\x95QCR\xd1\xe9T\xfaL2\xef\xb2$r\xcb\xcc\xe5U\xf4\xe1\xa4\xbd\x1d\xdc\xeb\x0b\xdd\xbc\x9ew\xb9R\xaa\xd0\x15\x18!\xb5\x08\xa2\x1bF.\xd9v\x8d\xe2\xd2\xf8\xcb\xab\xa6#\x7fx\x90u\xce\xf5\xfd1x5\xc0h\x8c\xf6\x1b\xb1\xcb\x03KH\"\x1a\xc3\xb8\xae\x06\x0b]\xa5F\xaep\ng\xa8\xe6\x1a\xb3]*N\x89\xa2\x16+\x93Ou\x8f\xeb\xf2\xb3\xac\xcf\xb5mY\x98k\xd6\x94UG\xcdZ\x88\x9a\xb5\xc7\x98\xda\xdeJ\xbc\x7f6\x13o\x0dY~\xca\xc9r\xf8\x15d\xd9\xcc\xc8\xe8Is\x08\xa2\x86J\x9e\x0d\x03(af\x15\xab\xe5\xc6\x0d\xc5\xc6\xe5\xa2f\xe7\xc4 \xd9\x0en\xd3\xa2\xf6\x84U\xb6M\xae\x03)\xf6cy\na4\xa7\xb0\xca\x92\x02\xdfH\n\x01%I\x8a\xaa{E\xcbV:\xa6\xed\xbb\xa9a\x81\x7fS\xb4a\x9as\x01\xddqQ\x1b\xb6\xea\xc3\xb2\x0fw}\xb8\xe8\xc3y\x1f\xae\xf8e\x94\xe6\xd0~o8\xcc\xff0\x1c\xe6\xcab\x07~\x92\xd2\x90\xe6\xb2\x12\xff\xe5t\xa35\x0d1\xbfx?\xc7~~}\xa3@A\x16\x08~E\xfe\xcc9\x15^\x80jO\xd8Gc\x88u\xc1\x97-\xf8W\x11q\xad\xca\x88:\xefs~\xb5\xcc\xbe\xc1\x84\x03\x01\xd3_\xa9B\xa6\x90:\xf0\xba\xae\xfa\xf0\x85P\x84\x9d\xa2\xf1\xa5\x8b\x17\x1e\xec\x85\xd3\xfa\x19*N\x14\xe4\xa0\xee\xefq3>w\xcb\xc3\x9b\x14\xa3[q~\xec\xbb\x0c\x12\xc6\xd8\xbcn\xfdV \x832\xbfg\x83\xf4\xf3\x1b\x9cS\xf6`-6\x15\x93\xfa\xce1\"w\x0et/'i\x98\n\x80\x1d+}\xb8*\x1f5\xa5{\xc4\x1cR0\x01\xde+\xca^W\x08\x9c\x87\xdc\xb1\xf4\x0b%ob\x96\xce@X\xee\x98%4\xf6YXBr\xcf-\xcf.%Nj\x9f^[\x9f\xae\xacO\x97\x86\x0d\x08\xc2\x8eF\x97\xa7\xf2\x0b\xe4\xc7\x85PY\xb7\x93\x1f3\xa3\xe7\xbf\xf4Vn\x16'\xfbB`\xe6B\x1b\xa9\xf0\xb4\xbb\\(@\x81f\xe7\xa9\xf8~\x7f\xcfhyl\xb5\x84F\xad\x13\xd2\xc1\xb0\x0f^.\x02\x1auP\xea{\x8a\x80\xd7\xe8F\x880n\x03\xb1C'c\xfb\xdcP\xb5\x81\xbfR?l\x84;\xdc\xde\"s\xe1\xd6\xd4y\x85S\xce9F\xc2X\xf8\x94&k\xe2)\xa7\x8f\xaa[\x05td@\x0e\xfa\x8a\xdemp\xd3\xea\x84\xae \xf7\xf0\xc8\xd9\xe9\x8b \xf2\xae\xa4\xd6\x9a\x1d_(l9x\xd7\xb0\xe8\xc3\xbc\x0f\x97}\xb8\xe6w\x05n\x1f\xf7\xc6\xb5\xa0\xd2\xa2\xe8N\x109\x81\xdc\xc8|\xb2\xbf\x97\xf9\xfe\xc57$\xc1\xb7\xc3\xa5e\xf2+\xa6\x04\x88\x97vF\xe9\xba\x91Q2\xe5'a\x80\x17\xe6\xa0\xce\xba\x19\x17\xf8\x9d\xd8\xb3\xad\xbe\xd0\x83sM\xac.P\xbd\x85\xf2\xb1>G\x9b\x9caX\x1beQ\xf9a\x1d\x8e6wD\x8fC\xde\xe3?\xda8\xf4|\x01[\x15\xbb}0\x80\xa1|\xf2\x0b\xfc_[\x19\xab|\xab\xb1\xbd\xda\x06\xbc\xe2\xbe\xb0.\xbe\xf2\x9b4\x8e\xbb\x97%\xdc\xbdVp\x97\xd1\xdb\x1c\x7falR\x1b\xc7\xe6\xc3d^\xf0\x1f\x9c>\x82\x17\xadV\x04.hzC\xa9P\xf8xQ\x10P.\xc0R\xeeD\xc8H\xa3\xc7\xb6\x95H~\xc9\xc5=\x1f\xef\xd99\x9a\x88\x13a\x0dm//@F*%\xf6\xeb\x8a\xd4\xcdU\x0e\xe5\xeb\x84@\xb9N\xf0\n>%Q(h\xa9\x19\xe3\xc2\x97\x05z\x02\xf9\xe5H!\\ \x8ew\x8d\xe4Xj\x9b\xdb\xe0Qe\x04\xba\xb1/\xca$\x9f\xad1\xd2\xb8\x18\xe9\xbc\x874d\xc1]\x81'\x10\xf3{\x13\xac\xc0\x17A\xa9\xc3*\x89\nI\xb5ga\x1e\xde\nI'\xe0\xcc\x1f0G\xd6-\xd6\x1f\xb5\xd8\xb3\x0fQ\x13W\x90\xb1\xaasd-\x9d\xb3\xd1\xa2\xee\x83 \xd9<\xfdn[R]\x15T\xe7f!\xd5$\xf0y\x96g\x0b\x0c\x8a\xab}\xb4\x86Z\xfe9\xf9\xd1\xe9\x01 \xa7\xa9b\x11I\xf3\"\xba\x82\x87\x7f0\xe1\x16\xb7\x08\xa4\x15\xddntP\x04I\xa6\x95\xab.\x8f\x04$.S\xacnW\x12\\b\xf0deC\xdb\xde\xb2N\xbf.h\x89\x1bU\xe22\xfc\xdcg\xe4k\x82+-\x1a\"\xc8\x7f\x8d1\x80\x17\xc7K~=\xcd\x99\x1b\xef2Z!w\xb3B\x86\x92q-\xfe\xc2\xd7[\xe1A\xb3\xd8\x83b\x80\x83\xc4\x83\xbbI\xa0\xbc\xc8\x93ne\xb9\xb3D&\x9d%6F\xbfF\xf1`\xdf\x18\x11\xbe\x8e5\x0c^\x87\x0e1\xea\x16\xac\xe65m0D?\x0ey\xaf\x86]\x9b\xf9\xfe-\x89Y\xc6!X\xc7\x07_3FP\xc7\xd9\xb9q\x88r\xcf\xad\x19\x90aC*\x1b\xce0P\xc5\x1a\xa8j\xe4\xd37\x8d\xbe\x9d\xf2\xc4\xe9x5Y\xe9\x05;\xe4\x1e=\x92\xd6CDc=\xd4\x06b\xe6%\xebxP5{x \x0bdC\x169{\xc1\x1f\xb8}\xb8A\xd4[\xf7z_\xbc\xd9\xeb\xb3\xb3\xe3C\x82\xf3\xbe\xae\x98\xd3TLf\x02\xf4A\xe9\xc1\x1a\xc6\x8c\xb5\x1e\x8b\xb70\xc4\x88\xcc\xf1\xa8\xd8\xe2\x9c\x85M)\x0f\xecA\xed\xcd\xaa\x0fa\x11=\x01\xb6Q\x18\xc7\xb0\xca\xd9\xb8\x96\x83\xe7Zo\xf9\xe6\xc8\xfa\xe6Z\xf0\x8ccA\xed\xd60\xd1M\x17\x90\xee\xd8\xdaix^\x1e!\xb7\x16\xee\x0c%\xe9\xea\x8b\x83\xbbj\xfe\x05\xd5M\xf8\xdc\xfd\n\\e\x9f\x8fB_\xaaj`;\xa3\xb6\xa4\xd3(@W\x8ek\xc9A=P\xbc\xd53'[\xcf\xbe\xfez\x12\xdar\x0bUi!\xc6\xec\xbd\xfb\x9a\x0b\xc76\xe3\xb1\xb0\x1c[\xdc\xa0\xdf\x9a\xf2\x82\xd5\xfb(8\xf6\xd2\x821\xee\xbe\x01,e\x9e\xa5\x00\x8cE\x17\x18\x97\xe6Y\x85D\x19\n\x863\x0e\xa9\xd7\x8d\x83\xb7\xe6\xf9\xd0#1b4\xf6\xe3\xb2\xc3H\x88_u\xf0\xf2}\x94Kt\xfb\xfb\xfb%\xc3\xdfG\x8f\xb8\xf1\xe4\xc4\xca\xefK\x1f\x9f\x82\xe3O\xfcp\x19P\xf8[\x16\xb1\xaab\xedEBJ\xf3,5\x1b\xe9!b\x86\xbe\xd3o\xb1ST\x01\xc3\xb0k\xb69z\xb4P\xd3}\xfb]\x13\xa29\x85v\xd7\xb4\x18\x8fU3\"|W\xb3|\xd0Z\x8a6t\xabC2!>\xaa\xb16e\x9b-\xf6\xa2\xae\xab\x9bvW4\xae\x8a\xfd\xe6}\x98\xeb53\xee/\xca\x90\xfex\x9a\xcd\xdc\xd2\x01\xf3\x01}G\xd4I\xb6h\x11%\x9c\xd1\xa60\x83\xc3`\x93l/m\xa2+\xf1^.\xcal\xc3\x18\x9e\xee\xe4?\x99\xd80t\xe1%\xfb\xaf\xc5]Y\xc4/\xb4}n\xb4\x1d\xb1\xf7\x9eC\xb4\xb1\xe1b\xef\xaf\xda\xc2\x8a )0\xc1f\x1c\x1f^\xbc\x80m\x17z@r\x91*\xdf\x81\x97\xf4\x96\xcc\xa9\xe7\xafH`wiR?*(\x0f\x1c\xbf\x82/f\xbe\x85\xc3RR\x81\xab0\xba \x81&\x1eY\xd3\xdc\xd8\xd3\xd6u}g\xd8)iVPR\xbe\xf5M\x94\xb4\xde\xf0w\xa2\xa4\xf3(\xbbhCI+\x83i\xc1K<\x84\xb4\xeaG\xa1%\xad\x8a\x1aG\xc95o\x0e\xbd\xc6!\xad\xa7\xaa\xdb\\\x87\xd1|\xf1\xdd\x86\xaa\x1a\x1aie\xee\xc4M\xe0n\x85\xf5[\xe7\xc4\x89\x19\xd9l\xd3b}0\x0f2y\n|\x92<\xc8\xe2Ic\xfc\xd8/\x9b:)*\xf5J8\x16\xd5\x10\xf2q\x16\xe6j\x80\xb9\x18G\xc5(N9\x93T5}8\xab\xde]\xd5\xd9U\x86&_j\x8a\x82ZWO\xea[\xd9IiV\xce\x99/\xba\x19z\xdd:^3b1\x88\x9c8\x1ew\xfb\xe4D\x1a\x85\xde\xad\xa7\xc5\xf7\xedM\xa5|\xab\xf8.\x15}\xf8cW\xad\xf4L\xf9\xae\xd4\xd9\xdaS\xea+\xe5\xcfx\xa8\x07\xcf\x8a\xe5x\xe2\xec*\xdd\x0b\xb5\x99\xc7u\xf4\xb7\xcd\xdbHHg\xf7\xf7\xdc\xbe\x8f\xa1y\x8b\x8d\xd5\xcc\xaeD\xe8K^fw\x85\xd5\xba\xd8`\x9e\x95\x0b\x11\xd6\x19\xd6Dp|A\xbfh\x8a\x16\xe1YI\xaf\xb8\xb5\xd3v\x10\xf6\x01\xa0\xafL\x8b>\x9b\xb4\x12\x8dGM1G\xafY\xfb\xc8\xda\xbc\xc1\x8a\xcdV\x10Y\xaef\x91\xd74\x8a\xf1Y\x90\x17p\x95\x89rrn\x8cjw\xd4\xfb\xf6\x04o\xf2C\x14\xf9\xfd\x8b\xb5U\xe2#S:X+\xda\x839\xab\xc0\xe7\xfe\x1f\xdcx\x80\xd1'u%\xc4\xfduI\xe7\x16|{=\x8e\xbe\x14/\xc08/\xc3\xe9gg$y\x191\xde\x0d\xc8\\\xdb\xe6t\xfbp((\x9fS\xae!\x0c\xcd\x0c\xcb\xd1\xe0\xf2`:\x11\xabC\xedtr2\xc2]\x82\x05\x99Y\x94\xe8\xcb\xba\xaeQ\xe1\xacH_ZQr\xf2\xf7\x87@\xa1\xdc\xd1:\xf7f\xc9\x8d\x0d\xba\x93.\xea\xa6,u\x95\x12q\xb3[\xd8\x81\x15gur\x19e\xc1\x1cmu.\xc95\x05\x12\xdeI\xcbk\xbc\x84\x95\xfe\xde\xad\xaf\xbb\xf3{\xc5Buv\x9a\xcf\n\x8d<\x85\x8dg\xa5i1\xean\xa7[\x14\xe8\x9d\xcd\xba\x93n1S\xab&y\xc9ugw|\xed\x85\x11\xd2\xe9\xdd:OZ\xf7\x1c\x96\xf0\x02\xee\xd8\x1f\xf4\x1f\xb7\xd2\x1c\xe7\xa2\xde\xcet9s\x072\xe0\xbb2u;\x9dPp\xe2b\x90'lW]\xd3\xe4:_\xf0\x1b\xe6/\\\x82o\xbb\x7f\x05\xb1/\xb1t\xe7\xb6`T\x0b\x86N\x19\x13\xbfw\x16\xc7\xdb\x91\xf0\xf0;\x9a\x863\xa9cc\xf4\xf4\x0f\xa1q\xe0\xf44W\x82\x15hZ\xd2<\xfc\xc9\xdcy\x99\x1e\x0c\x15\xd1H\xec\xf7\xc2=\xdfN(\xdaV\xe4\xf1\x1c\xdaW\xdet\xcb\x11]D\x84\x07u\xdc\x0c D\xb3W\x13T\xd0\xadH\\\x8b\xdb\xf2[\xc1\xd3\x8bi\xa2\x9d\xc6Z1N+\x03\xa6N\xa4\x1f=\x82%w\xf0,\xaf\xbd_^{\xc8Cq\x84Q\xb8qp\xf2\xea\xed[%\x9eL\x02$\xa6\xe0\x87)\x8d\xd71E\xc7\x87\x04\xc5\xad<\xe8\x9c\\\xda\xa4\x166\xa0\x85<;\x81\xed\xddf \xbb\x82\x15h\x80\xb0RA\xf1\xa4\xdeP\xa9d]\x1f\x1a\xc5\xa8\x0b\x15\xe8Yxp\x94\xd6\xc3z\x18\xff\xd5\xd1Fa,bAQqv\xa0\xcc\xc3\xce\xc8\xa1\xe4\x17\xf2\xb8v2d\x0c-\x03\xa0\x98\x02\x82@\xc4\x92\xb1Wrhn^\xd0\x87\xdd\x9d\xcd=\x11+U}i(k\xb2r\x8e\x15#\xb7J\xfb\xaeE\xde\xe9\x90\xde4\xdf\xaca\xe6 \\B\xc0DL\xf8[F\xcfds/~\x08\x96G\xd4Id\\\xf6T~\xbd\xbfg27>,\x02Y\xb2\xe7\xc5\xafr\x13\x9c\x13\xc1*\xe2\xeb\xfd=W\xeb\xb3\xa7\x18\xa0\x8a=\x93\x91\xaa\xf2'9\xbb\x86o\xca\x1f\xe5\xb6KB\x8cL\xc2\xcd\x07\x8a\x81\xc0\xfd\x80\xce\xdf\x8a:2\x97 \xe7\xdf\x0d\x95O\xf9\xd3|\xe8\xb8v\x052\x88rE\x171\xccG\x8b\xea\x08\xf5\xa7\xd4H\xa8e\xaa!\x10O\xf7,\xf7'\xf2\x17eB\xcb\x97S\xc3\x04\x86b-\x11\x93\x86\xdd\xaev\xe5\x97s\x93t\xf2\xdc$EZ\x12_3#%$V\x11\x82-\x86\x17\x10\xb1?<\x04[\xea\xf8\xd3xf\xa7-?i7\x9c\xdc\x99\x7f\xd5\xad\x1f\x1b\xb1p\xe8\x96\xd9P4\xfb\x95\xd5\x1a\x89%\x95\xb5$X\xa7C\x8dOA\x91\xc9!r\x8a\x8b\xc3\xfc\x86>\xa7\xa0~\xa8P\xd7>\\d),\xa2\x8c\x9drQL\x1f\x94\xc9\xa1He\xf0K\xbf\x9e\xfa\xe0\xa7\xbe1kA\xd3-D\x8b5E\x94\x89\x07\xf46\xa5\xe1\xdc\xa9\x83\x8fo\xea1\x90\xf2|Xg\x95\xe5\x90\xc8\xf7\x85\x8d\xfdI\xf9\xa9M\xe3`\xa5\xccb6?}\xe9l\xea\xf1\x81\xbf>c\x81.\x98h\xe4\x94B/V\xa7\x81tL\x1c$\xf2l\xb9\xc8\x16\x0bN\xba\xeb$3,\x93\xccX\xfc\xf4\xa2 [\x85\xa5@\xa7\x05\xde))\xd8\x07K\x9a\x9e\x84\xfezM\xd3&\x00\xd7\xcc\xd5\xeb{\xb1\xa3\x0c\xd7U\x95\x06:\xd9\x1bD\x00\xf8m\x85c\xd8\xdb\x11\x11p\xc4\xadKi\xb6\xc2:\x80\x1d\xe7\x1b|?w\xcf\x86g\xf1Y\xf8\x7f\xfe\xb7\x9aU\xa0;\xf0\xc39\xbd=^8\xcah\x90\x8a\x1f\xa4N\xc4\xef/\x0c!\xab\"\xd8@2^\x06\xf2\x06\xf6\x9b\xc2\x13\xd8\xe4\x9c\x87^X\xc3q\xc3`0\x00\x1c|o\x1fv\xf4RJ\x1bw3\x04\x91/ A\xea\x90 \xf0B\xc5\x0d\x85\xbd\xfab\xd0\x10#X\x1c\"\xc8\xf8F\x052-\xa0\xe2\xabP!\x0c\xbe_\x01\x15\x81Q\x99\x84\x87\x98\x00\xe7\xea\"\xee\x8aX\x98R\x02\xaa\xa1\x84\xe4\x95\xa1\x01x\x8f\x07\xcc\xefUkAO\xb3\xe6=\xe5\xbc\xe8A\xf7\xf7\xaeJ\xa0\xd4=\x94F\x9c\xfb\xb5\xe6\xe6UB\xf6u\xbb\xda3\xbe\xd8\xfa\x8caE\x0e\xe2\xb1\x1fr\xe1\xb1x\x86\xd1\x92\x1f\xe3U9\xe3XH\xca%\x186)\xa7\xa0\x04(\xd7\xf5\xd8\xdc\x04%(\x9e\x8b\x02~\x05\x82;\x10\x85r|VP\x03G\xa8\xa8x/c\x0e5\xd4]j\xc9tNi\xbe\x92h\x8ev\x953Em\x9d\x9d\xc6\xb1\xa3 \x87\x93\xa4q\xb7_\x81\xf5\x95\x1f\xce\xc7\xc5}n\xe9Y\xae\x90\x1d7\x98w\xd4t\x9e\x98D\xa2\x94\x8b\x00\xca\x07\xbb\xfb/\x82\x00\xfd\x9b\x11\x02\xb9c\xde\xb7\x85A\x95\xb9\xfe\x97\xc3`E\xd6&\x18\xe4\x8e\xb6\xdf\x16\x04\x15\xd7\xd0\x7f=\x08\xd8\x08\x1f\xb4\x13\xc4\xedA\x13\x00|\x19\xbe\x07Ek\xabm\xf0u\x9e\x8cR\xc8\x01&h\xca\x98\x9d\x8f\x1eA\xf7\x7f\xc4\xcd\x1d\xf2\x02E\xb9\xd3\xc5 \x15\xcf\xbaG\xd5\xdf\x9f\xde\xbd\x13\xbf+\xbcv\xf3R7\xac\xb4\xad\xb9uL1\x10Y#\xe0T\xcc\xc1Q\xdaZ\x8d\xe9:\xa6 \x0d\xd3\xb1\xa6%\x8f\x84Q\xe8{$h\x98\x01\x14\xbdv\xffG\x93J\xb3~5\x12D74\xf6HB\x1f\xd02\xaeK\x9b\xc6\xb3\xf5\xfa\xc1\x8d\xe3\xa2\xb6i\xdc#+\x1a<\xb4q\xfd\xc8m\xeb2\xa7\x0b\x92\x05\xe9Iz\x17\xd01tsxu\xff\xe5\xfb\xfd\"\x8a\xfe\xa9\xfb]c?\xd5z\xbf\x97\xf6u\x1agT\xdd\xc7\xa7\xd5\xdf\x1f?\x1d\xca}\xcd\nv\xd4\x97\x17$HJ\xb5\xdf\xd4\n\x0e\xde\x9d\x1c~)]\xb0m\xe4\x87\x0c\xfc[\x12\x90\xeeT\xa4\x13\xf81\x8a\x02J\xc2\x19\xef\xa3\x96\x9cN\xb2\xa12\x03\xed\x17\x93\x1b\x1dQ0&\xc8\x95\xf6\xa00\x91\x00\x1a\x83X\xa56\xdbXG#Z\xf5\xc5\x81=\x96\xeb\xdd\xa6/\x1d\xc9h\xd7\x97\x9c\xd7\x1b\xc3\xbc\xfe\x1d(\x88)C\xe2\xee\x03\x93\x9c\xd6\xb2\xa7\xed\x14\x03\xd54D\xda7\xb4\xa74$\xbfUI]\xa4#u~\x98\xfe;P:\xae\xb4Q5\xd8Z\xcc\x89\xccn\xf5\xba\xa8\xde \x95'q\xa3ylw\x83\x1bB\xf1[\xd4i4C\x19\xad\xdb\x13y\xdesY\x8eN{\xbdh\xe6\xf6\xa1;\x14\x99\xfe\x8d\xe29j=z\x82!\x8b\x1b=\xbfp\x14\x17\xbcQ\xb5+S\xfb\x90\xbby\xf4z\xa4\x9fb\xe6\xb7\x959\x8ev\xddA\x1a}b\x02\xe9+\x92PG@\xa2\xb1\x9a\x0526\x1c\xab\xc8\x85b*\x15I&aO\x0f\x02\x9f$4\xb1\xe1\xe2t\xb3\x0f\xdd\x0b?\xecjR \xe4\x98>\xedC7\xf2R]\x95\x1c\x8e\xd3\xd1\x10\x13Uy\xbaZ%\x88OG\xbb}\xe8^\xd2\xdb\xee\xf7\xbd\x0b0\x8b\xb5\xe5b_\x08\x90\x1f\xe9\xf2\xf0v\xedt\x7fw&\xe3\xe9Fo6q&\xe3\xe1\xfdt\xb4\xf1l\xc6\x8e\xd8\xf3\xd9\x0f\xae3\x19\x9f\x9d\x0d\xe4/VaJ\x0fgXY\xa4\xc4\x9d\xdc\xe7\x15z\xda\xc7\xc5/\xd1\x8c3\x19\x97\x0f\xf2\xa2\x07^\xf9\xecl\xe0L\xc6~\xb8\xb8\x7f\xcb\xfe\x1d\xbdq\xefyQH\xc2\xfb#rt\x7ftp\xe4\xba\x7fV-\xef1.?&\xedU:\xa7O\xcczB\xad\xf0\xbc\x08\"\xf2]\xc4gU\xbf\xcdoF\x18\xa5u:\xbe\xe0`\\\x95\xf9\xa1S\xd5zo\xf6\xcdy\x1am@\x189B\xd8\x07\xc9G\x08\x03\xe4\x1a;2H\xa3w\xd1\x8d\xdc\xd2\x8c\x97\x80 ;\xc8\xc7 b\x00Og}\xe8\xf66\x94+tdX^\x8a\x13\x86\xdf\xa1\x16\xccH\x1fX\xcdE\xc1{\x08\x0b$\x98\x88\xc3l\xf0\xe1\xf8\xe4\xed\xe9\xdb_\x0f\xcf\xdf\x1e\xbdy{\xf4\xf6\xf4\xaf0\x96\x8f\x8e\x0e\x7f:\xa8>\xea\x0eB\x12\x16\xcd\x1d\x91#\x18CZf1\x04is\xd2/\xe33\xa22\x9f\xf1\x86!\x8e\x95\xd3\x10\xb6w1\xe74\xa2\x07t\x95JN#f\xaf\x9b9\x8d\x10~`|\xf3\x18\xbf(\xa3J\xff\x9dx\x0d\x873\x1b\x9d}\xee\x8d\xa1\xe15\xda2\x1b%Bi\xc2\xf8P\xaf\x1c\xf2\x93#r\xc4\xfa\x82\xe4\xc6O\xbdKp\x8c\xca\x03\x8f$T\xd5D\x8e\xb5\xb5@\x01\x0e\"\x9f^<\xe2\x8d\xe5z\xdc6\x8d\x1d\x1d\x1cY\x1b\xcb\x15\xb5\xad\x1a#G\x1a\x8dl\xe1\xf8l\xdcnB\xeb\xf7=\xa0\xc5v\xfe7\x83\xd6\xdb\xa37\xdf\x0eZo\xc3E\x1bh\xd5)\xd0\xf7\x83\xd6\xc67\x05\xd7\xc67\x85\xd7F#\xc0t\xbb\xbdx}8\x18j\xc6\xa2\x9cKe\xbe\xb7\x0f$\xcf\xe95\x810?\xa6\xba\xb4\xcb\x0e\x14\x1e\x083\xb4\x11\x93\x7f\xd6mC\x8d\xff\x8aj\xfcW\xce\x1e)\xff\xb9\x1b\x8e\xe9\xc7\x9f\xbb\x8d\x1c]c\x8b\x93\xca/\xc6\xbb\x9d\xa6\xb3\xfb)\x9c\x9d\xa5\xb3\x9e[z8V{/\xfd\xe0\x0c\"/\xf9\xc1\xe5\x1c\"\xb6\xf0\x83\xf3\xdf\xf7\x0ec\xc6\xdcj7\xa5\xf7\xdd\x89\xebNJ\xac\\\xab\x1b\xdd\xd4_\xd1$%+\xa3)\xcb7\xe7\xd6\x8a\xb0\xe5\xd1\x80\xdeRO0my\xa9/K\xbf\x03\xbf\xa6\x89\x87b\xb85Y\x0b\xf7L\xfd\xb9\x97\xdf\xe0 \x0b\x96\xcf\xc3\xcd\xb9\xb2b\x12j\x9erW1\xf3>\x8c\xe3(v\xba\xafIJs\x9fZ\xca\xcat\xc1\x99|\x91W\xb4\x97NG3\xce\xfc\xf4\xd2\xe9\xe6\x8c{-\x11\xfesk\xd6\x87N:\xdd\x9e\x15f\xb0\xf4\x06X\x07\x0e\xfbo\xf0\xe9\xf4\x95#\xc0\xa0\xf3\xc3\xf3E\x98\x8a\x1ek\x82G\xa9\xe8\xa5\xd3\x9d\x19\x8fO\xd1K\xa7\xbb\xb3>\xa4\xd3\xbd\x99\x89\n\xa3\xca\x15\x03\xdfN\xf7f\x82+\x1d\xf6a\xcb}\x0e\x8b\xc2\xa7r\xeb\xb9\x0b\x0b4\xf0\xd3Q)l\x87u\xb7\xa8\xd3?\x13z\xa5\xd3g3\x04<[\xb3]\xba\x0d?\x80\xb3;\x84\x1f\x10Z\xc3\x19\xf4\xa0\xe7\xa4\xd3\xd1h\xc6\xd0l(\x95\x80\xb8 \xea\x9b\x1bkW\xc4g0\x82M\xc1\x9e\x85\x8bQ\xd5\x1f=\x02o\x90\xd0\xf4\xd4_Q\xc7\x1b,\xc57\x1760\x88\xa6gCa?LR\x12z\xf4x1\xc6\xeeZph\x96M\xc6\x88\xfa\xdb\x93cA\xd7\x8d\x8e\x00\xdf\x8a\x10?\x90\xcc\xf0\x04\xfc\xdf\x8f\xc4t_\xbcP\xac\"L\xe6O\xdf\x0e\x0c\xc5\xcf4\xbe\xab\x0c\x8b\xc3hg\xdb\x1d\xfc\x88\xb6\xc2E\xaf\xe0\x11dd\xd8L>\x97\x1a\xb4(\x18\xba\x07?\xbez}\xf8\xe6\xa7\x9f\xdf\xfe\xe5\x97w\xef\x8f\x8e?\xfc\xd7\xc7\x93\xd3O\xbf\xfe\xf6\xbf\xfe\xfa\xdf\xe4\xc2\x9b\xd3\xc5\xf2\xd2\xff\xe3*X\x85\xd1\xfaoq\x92f\xd77\xb7w\x7f\x1f\x8e6\xb7\xb6wv\xf7\x9e>\xeb=\xd9?\x0b\xcf\xe2\xee\x03%x\xae\xe4\xf9\x1e+\xf6\xc57\xe0\x06J\x1d5^\x8e3\xfa\xe8\x1b\xae\x88B\x1e\x030\xe4\xbeC\xa1\xed\x9e\xa8\xe3 i'\xb9\xfcK\xa5\x19;\x8f\x06\x08\xbb\xdb\x8d7G)\xbc\x80a\xab\xdb\x1f\xd4\x8b\xefj\x1f\x1b)a\x0c\xff\x01OQ\x01]\xc6\xfb\xaf>:\xa3\xb2\x02cz\x16\x9f\x85\xfb3\xa1\xc60\x03=\xb2.K\x86\x91\x80\xb4\x8f\x12\xf3r\x07\x86;\xa1\xdc\xd3{\xf8\x1c\x18\x94\xc9sH{=\x17R\xf8\x0f4\x05\xe3*\x13~\xa5\x13\x88L\x11\xf0\xf2%\x8cv\xe1\x11l\xee\xec\xb8}P\x8b\x9fVK7wv\xe0\x11$\x8c\xec'\x98\x0e\xe4\xc5\x0b\xd8\x85{\xc8rt\x88$:\xa4\xba\xe3U,\xd1\x10dH\\\x82\x03\xfb\x01v\xf1\x9a\xe6\xab\x86\x04c\x18=\xcdu=\xe5\xb6\x86\xda\xb66E)\xbe*|\x0f\x19h\xd4:\xdb\xf9\x9b1\xa6\xdfX\xc4\xd1*\xff\xe2\x04(\x16 \xbd\xc7\xaf\xdf\xd4~\x15C|0)\x87S\xd0\xf67'm\x11:\xe6n.F\x82b@>\xd2Hk2\x0b\xad1`\xe7V\x05;q\xe7g\xd3\x08\x97\x8f-\xfa\xee\x16\xf2|J\xe9\xa6\xaet\xb7R\xb8\xbb\x05\x8f\x00Mr\xd8\x8c\x9c\x88a\xecS\x17z@\xa7\xa9\xf9R\xb5\x8c\xa0[\xfc\x0e\xf1\x1b\x8f\x08\xc6\xb0Y\xa0k\xa9\x9d\xa1\xae\x9d\xedZ\xe1\x8b\x17P\xedqw\x1b\x1b\x1e\x15\xc8\\j\xb9>\xc0\x17/j\x0d\xefn\x97\xdb\xebC\\F\xbc\xfc\xd7Ws\x10f\x89\xb6\xa6\xff+\x87\x9c\xacs\x08F\x85\xe1\x03\x99\xb4\xc8\xe2\xd1`\xf0\xea\xf8\xca3\xdfd\xcf_\x91\xd7\xb8*\xdcx\x1cP\xdb~\xe3\x97\xd2A\xee%\xccv_\xf8\x9c+\x83\xcd\x1ed\"uh0MgE>\xb0\\]\xcb\x01>\xeb\ny\x15\xd5\xb2q\xb3Q\x87\x88\x89\xe3\x87\x10\xdb\xadx\"\xd1$Jj\x16\x8eB\xd6\xcf\x1a\xbb\x96\x9f/\xb2\xd6A\xe6\xa7\xb9\x0fVM\x98!$\xf9\xa1H\x9a\xc1\"\"[\xb4\xca\xdf\x91#Ny[~!\x83S\xd7O\xfc\xb3\\\x8dZ\xec\xfa/\xdc\xc4k\xe2\xc7\xc9\xbf\xd7.\x16\xbe\xbb\x96\x9dJ\xc4\x8c\x0e\xe2\x98\xdc9\x99t\x81\xcco{\xd8\x16\xce\xbel\x0bg\xb8\x85\xf5[7j\xbdu}\xf4\xe7G\xc3!\x85\xe2^\xd1\xbb\x84\xbd]u\xf17\xb5B\xa6\xe9\x8c\xd12\x7f:d\xe7\x0c\xfe\x9d\xcd\xfe\xe9hoXG\x1dW}]\x0d{&R\xd1\x18\xd6\xd1/\xad#\xd1\xae#1\xad#[-\x82\xab\x15\xd5@\xdc\x07_\xc0.\x12\xb0\x8b\x10vF6\xc6\xff7\xd8\xc1\xe5s\xfb\x81\xfb8\xa1\xc6\x0bt\xbdw\xe1\xf7\xdb\xc4\xd6#\xd6\x0f\xc1\x10\x08L9\xc9\xc2\xbe\xb0D\xccIm8Mg\xd6\xfd\xf2mQ\xdeD\xe9\xff\xed<*\xffH\x9ed\xe1\x9c.\xfc\x90\xce\xbfR\xfbb\x81\xc3\xc3\xa1\xea\xd6\xf2\xcd?T\xa6\xbb\x8e\xfc\xb9\x8c/f\xeb]'\xcd\xd94\x7f\xffn\xae\xd1\x7f$Ob\xba\xa4\xb7\xdf\xe5F\xe5\x01\xca3\x1f\x03\xd5`\xbd6\xe7S\xeeW\xa7\xe7\xb3\x19\x11xr\xf6\xc4\x99.\xfd\xd5\xec\x07\xf7\xcfO\xe4\x05\x87\xbez\xac 9\x00\xd2z\xfa\x89\xd4\xbe\x0f\x8dw \xfc\xc2C\x9a\xf2\x86\xd3\x11\xcab\xf2\x16\xe1%\x93K[\x9c\xd8\xac'4\xeb\x9d\xa6\x85!P\\\xb2 *\x9a\xa9\xb5\xf2\xbd\x8f\xe1\x7f\x0e\xc4\xe56Q\x80\xceo\xe1\xaa\xd0-\x19\x13\xf5\xc1\x001\xbc\xd0*.H\xd3~U\x96\xf9J*\x913j\xbc\x83\xb6&1\x0f%(\xd6\x05a\xb0\xea\x01\x1d$Q\x16{\x14z\xac\xc0\x08X:X\x06\xd1\x05 \xc4\xd5_o\x1f\xbaK\x1e\xb9\xaf\xc8D_\x11\xf5\x9fV\xca3\x9b\xd2\xaf\\5i\xd6.\x94_\x08`\x1f\x9eU\xc8 \xec\xc3\xa8r\xad\xb5\x80}\xd8\xda\xac`\x03+\xdb*\x97\xcdY\xd9v\xb9\xec\x92\x95\xed\x94\xcb\xaeY\xd9^\xb9l\xc5\xca\x9e\x96\xcb\x96\xac\xac2\xbe;\xd8\x87\xed\xcaX.XY\xa5\xdfsVV\xe9\xf7\x06\xf6a\xa7\xd2\xc7!\xec\xc3n\xa5\xbd[VV\x99\xdb +\xab\xf4\xf1\x8a\x81\xaf\xe2\x93x\xc5\xca*\xef\x1e\xb0\xb2\xddr\xd91\xe6/\xacT\xfc\x80\x85\x95^N\xb1\xb02\x95\xf7\xb0\xafA\xfa\xe1\x18\xbaggC\xcdQ\xb4\x87O\x88\xe6\xc9S|r\xa1y\xf2\x0c\x9f\xa4\x9a'#\xdeQ\xa8{4\xc2G\xd7\xbaG\x9b\xf8h\xa1{\xb4\x85\x8f\xaa\x0c\x1d\xfbl\xf2\xa1Wu\xd1\xec\xb3\xb5=\x86\xc7gg\xdd\xc7\x9a\xb1\xf3\xbe\xce\xce\xb4\x9d\xf1\xde\x8et\xcfv\xf9\xd4\xceu\x90\xda\xdc\xe2\xad\xbe\xd3?\xe4\xad~\xa8(\x1a\xcaU\xdf\xb2\xf3\xba{\xd7\xedC\xf7\xaf\xec\xbf;\x9a\xe0w\xf1\xe7\xf0\x84\xfdA\xb6\xb7{\xcc\xff?b\xff\xe3W\xfe-\xc2\xaf\xfc\xffc\xac\xbdX`E\xf1\xe7\xcd\x9b\xeeL\x17U\xe3\x8f:\x9d,\xb4\xb6\x95\xabhn\x82\xb2ou-\xeb\xf3\xc8\x19\x9b;;.\xe7\x85n\xbb<\x80\xeff\xb9\xad\xdc\x1a\x19\xab\xef\xee\xecl\xc9\x172\xf1\xc2\xb6\xe6\x05=\xd7\xde\xe1\x8dlo>\xdb~\xb6\xbb\xb7\xf9l\xc7u\xcb\x11q\xbdhNa\x1d\xf9\xa5\x8c\xb9<\x00\xe2\x8a\xdc\xc9L\x0c\xcb\x98\x92\x94\xc6<\x19\xc3\xf0\xf6\x8d\xf8\xe8X\x07\x1c\xe8'1\xd0\xa7\xe5\x95-\xfd\x92\x87\xde\xd9YW\x84u,\xe28\x0e\xf1\xfd\x8d\\Vv\xa1\xa7\x08p\xba\xc8%G\xf5\xc5R\xa2X\xf3x\xe1y\x98n_\x06\xc9\x961\xa7\xdf\x93\xf4r\xb0\"\xb7\x0e\xa6\x0c\x17\xc5\xf7\xf7\xb0\xe9\xcah\xdfW\xfe\xfamxM\x02\x7f\xce\xdbR~\xab\xa1\xb9\x17At\xf3\x8e^\xd3\x00\x99X?9\x8a\x18L\x97\x0e-\x9e\xb8\xd2\x17I)\x93\xbd\xa4w\x81\x08\xc1]:YMLu=%p\x93Ym\xe1\xdb\xff\x8f\xcf\x06\xcds(\x12\xa2pk\x0d\x9e\x845\xae\xdc\x1b\xa4\xf9\xd5\x0c\x8f\x04\xe0?\xe7ARG\x90\x89\x86X?\xac=\x91\xe4!\x18\xa8>\x97}\xc8xg\x19^\\\xab\x8f\xa6\x19\x1b_8%3\xd8\xaf\x06\xc3\x05E\xcd]\xc6gGA1\x868\xd8b\"\x0d%s\xdc\x89\xe2\xf4\x17z\xc7\xb3\xcf\xe4?\xca\x01\xddC\xfa\x9b?\x97\x01\xd5\xf3_\xf7\xf7\xf0T\x86C\x0f\xa3\x8ft\xc1\xdb\x10_\xd5\x16\xc2\xe8U\xb4Z\x93\xf4=\xdb\xce\xbc\x8eR\xa0\xd6\xf4\"\x86\xdd\xe8zu#@\xa9\x14\xa85\xbf \x84\xbcLOd{\xe5\xf0\xb6\x1cu\x1e\xd3`\x85E\xe4\xfaR\xb6F,\x99g\xec\x0d\x92Ra\xaf\xc0K\xb3\x84\xce_\xabOJ\xb1\xfet4\xe2\xa3v3!\xd2\x8b\xdd\x14\xc1~%\x9al\xea\x8at\xc6\xfc~nc\xc4\xf1\x9a\x8d-Q\x83\xa5\x81\x0f/ y\xeeb\xda\x064`\x97\xd9\xfa\x85K\x1f;\xfb\xc1w\xd1\xec\x87\xfb\x8a\x88\xac\x16\xa2\x83\x04\xb3\xbd\x95\x9e\xb0.ydW\x1f\xad\x86\xf8\xf7P\xd5C\x9c Q0\x14x\xdd\xdb\x87\xc8eC\xec\xedW]\xcb\x04\ngV\x10\xbd\xb6\x85\xe3\xd6\x87\xdb\x95\xe4\xf2\x07H]k\xdb\xef\xea$Z\xca\x1c\x08\xb1\x05\xc3>\xfe\xd5\xbe\x8e\x9f\x8c\x0dmm\x96\xa3T\x8d6wQ~\xdf\x1dU\xc3`m>\xdba\xbf\x18\x87RxP0\x96D\xfc\xba\xbf\x87\x9d\xbd\xad\xed\xed\xf2{\xec0\xdeb\xbfx~\x8a\xbc*+\xdf\xadt=\x1am\x8fF#\xebD\xfef\x9c\x08N\xb1\xd2\x0f\xb6\xcc\xbe^\x14__\x15_\xaf\x8a\xaf\xc7\xc5\xd7\xd3\xe2\xebM\xf1\xf5\xd2:\xac7\xc6a=\xf9\xfd,\xfc\x01dT\x13u\xb9\xe57\xb6\x91\xfe^\x0f<\xf2#cs\xcaE\xbf2Y\xa5\\\xf43\xe3m\xcaE\xbf\x01\x06\x99\xae\x0f\xf2/\xf6\xd0\xebl\x1c\xbej\xe7\xd4\xd1\x84B \x0c\xe5\x0b\xdc\xe9<\xeeG\xfd\xe9{N\x07j\xe5\x8cS\xfd$\x12\x92\x96r\x96TV\x12\x83\xf3t\xde9\xfc0\xca\xb0\xec\xbc\xf8z[|\xbd)\xbe^\x14__\x15_\xaf\x8a\xaf\xc7\xc5\xd7\xd3\xe2\xebe\xf1uU|\xbd+\xbe\xae\x8b\xaf\x1f\x8a\xaf\x87\xc5\xd7e\xf1u^|\xbd.\xbe\x9e\x14_\x0f\xc4\xcc\xcc\x89^49\x1f\xd2\xbaJ(7y\x18r\xba\xaaP\xd9^\xcfv\xb3\xd5\xf9$\xc8\xae\xd2\xbf\xafD\x05\xfaM\xaf\x04f+\xf7\x96\x8d\xfdoZc)\x13\x83\xfd\xc5\xc3\xd4\x0e\x12 \x9f\xe7rd\x1d\xf6a\x01hQ\xcdX\x15\xe4Ya\x03\xde\xe3\xe9\xf2\x92[\xf1vA$\xd2\x9c\xbeg'\xc3\xac\x8f\x88\xe9\x1b\xf4\xdc\xb9P\xc1@\xf4\xb5\x00\xd1n$\x1c%\x0e\xbaq\xa8\x7f2\xb7&\xc6\x85\xdcM\x00\x13\x08\xe1%<\x83\"\xed\xd2o0\xc6\xf2\x9fa\x0c\xbf\xc2\x98\x8f\xb2\x13\xf1\x87\x7f\x871\xfch%m\x7fU\xa8Fu\x85\xe8`\x9e\xadJ\xbc\xb7\xe9.\x84\xdf\xfe\xa6\xd5\xdb\xdf\xee\xe3\xc7\x86\x9b\xd9N\x85!\xe3\xa1\xfd\x19H\xde\x16!\x08\x14W\xd3\xc7\x18\xa0\x1dz\xec\x9b\xfeF\xd9\xcf\xb9\x0b;\xe9\x94\xfc\x17'\xed\xf3$\xc6\xbeH\xdeL\x14\x85\xa3\xd1eY\x80\xb0Q~\x92\x1f)G\xe97\x02\x94\xdcYd\xc0H}\xa6\xd9\x90\x87D\xe3\xd9\x82\xccv\xa8 p\xa2\x9ah6\x9c\xe5\x19H\x15T0\xc5n\x04\xeb\xbd\x0d@\x9e$\xa9\xbe{\x8d\x96\xaf\xe8Q\xfd\xf7F?jM\x06{\x90o\xff\xd8\xf8\xb6\xc0\xed\xc2\xe7\xe51z\xbb<~\xdcuM\xf8\x0e\xb2\xf5_\x9b[\xbfg\xad\xff\xc2\xf3\x04r\xbca\xcd\xfe\xe4|dE\xbe)M\"\xb6\xfess\xeb/\x8d\xad\xb7\xc67(\xcb\xee\xb0\x0fO\x9c\xb3\xb0\xe7:\xd3\xdf\xcf\xc2\xd9\x0f\xee\x93\xa5~W\xa9\x1f\x94\xc9\xb3\x9a|\xe1r\xd9DP\x96\x0c&\x90\xa1\x9aA\xb8U@4\x08H\x92\xbeeo\xf0\xfc\xe0\x7f\xce#\xd3\x0d\xfb\x98\x7f;u\x0d{Z\xfd\xa0\xa8~\x16\xcaP0Ct\xffd$^\xfe6c,\x88\xc9k$l\xf5#b\x0c\xc6\xaa\x0b\xb01\xc1\xa7\xfaam'\xc0\xc3\xbc5O\x04\xc4\xc9\x15O7\x1b\xc6\x0cyJ\x18>\xcb\x00o\x80|\xb6\xd3\x13\xe81Y\x0f\x13\xdc38\x88\n0a_\xc7<\x9f\x1d\xf4\xe0\xcfN\xc0\x85I\xbc\xb5\xb0vf\x8ey \x05*\xfa\xc6J\x9f\x19z\x12\xb7 \xdb\x7fk\xc4\xf6\xc7\x98\xac\xa4\xf9~O~rA\xba\xe0\xca\x85\xa4l\xe4\x91\x84\xce\xb4\xc2\x08\xbd\xe4\x02\xda.\xa0\xe7\x0e\x13\xd7v\xb7F\xc8\x04\xd4\x83\x95\xfa(\x15\xf3wv\xb76\x87PD.\xdd\xda\xdeb\xc26*\xa6\xfepF\xc3Mt`Na\x83\xb7\xce\x93\xc9l\x88\xd7z\\\x86c`c\xbc\xdb\x98\xeb\xbc\xde\x0b\xab\xd9\xde>t\x90\x93\xf9\xe4`Zh:\xf5g0\xe6\xa7\xdc\x1fz\xb74\xf5#\xafSmk\xe6\xf2\x8c\xa2\xfa\x86D \x08\xf3\x92\x95t\xba\xfej\x1d%\x89\x7f\x11\x08\xc7\xf71\xf8BU\xc9\x8d@x \xb2n\x13c\xf7\xd9\xb1\xcb\xf3\xbf\x983K\xc1\xbe\xe4\xd7\xa4\x02\x10\xe3\xafin\x01\xe221)\xc5\x95\xd2\xea/B\xb6\xdfx\x8em\xfd{\x9b\x9c\x1e\xe5\xcf\xd8(\xba\xbd..\x97\xdc\x94\x1b\xfc\xb09\x0b\xbb\xd6\x19\xfed\x14\x84MCf\xb8Q\x90\xd4\x8d\x11\xa6\xf7\xb4\xf6\xf1g-\x14\xd1\x1aAq\xbcV\xc9k\xce\x1bTl\x87UE\x96\xe2CY+:\xae2\x90\x85*\x9d\xc0\x0b\x08\xd8\x1f=\x07\x89\xa2\xa3\xe31)oJf\xee\xa0\x88s\xc0P\xc4\x1b\xe4\xf6\x06\\\xcb\xdd\xf1*5\xba\xdc\xbc\x80aR\x9e9\x90\xd3XY/Z\x80\xfaR\xdeN\xder\xa5#F\xfal\x82.\x95\xea]\x98\x80\x87\xdf\xc7\xd0\x9dt\xfb\xe0\x0dr\xbb\x04\xdb\xb1\xc2\xdaXp\x95\xa8\xb8\x1a\x99b33>\x0e5>N\xdfh>\x91\xf1\xbb\x00\xb5K\xee\x13\xa1\x94\xb03sa\xa1\xe2\x06\x0d\x80\xfaA9/\xa9\xf5\x85\x11-\xca\xf4\x99'\xe8\xf7D\x82\xfe\xc7/1k\xbf\xe0\xfdc \x9eG\xd7i\x82Wo\xfc\x04\xe6i\xc2\x10\x02\x8f\x9bN\x9a\xf2\xb4\xa6\x8b\x19\x9f\x99\xf9\xe41OY\x8a\xc3\xb1\xb6\x8a5\xfe\xb4\xc6&K+\xe6w\xec\xfa\xd1\xffU\xd2\xf1\xf1M_\x95\xd9\xd5\xfb\x83|\xc8a\x9fo\xe5\xb0\x0f\x9d\x11F\xc1\xc9\x7f\x0e5\xd9\x82\x13\xc8\xb1\x847Q\xcd\xdb\x9a\x13?U\xa4}\xc1#\xc4\x95\xa5\xdcjVS\xd6|\xd0\x87E\x1f\xed?\xea\xdeR\x0cAQ\xd9\x91?B\x17\x1f\xf9\xa4\xae.C\x85\x9d\xa3h(\xc5\x8dXqI\x92\xcb\x04\xa1\x8b7f\x85o\x06\x02\xeb\xd1#\xb6\x05\x95\x02T\xdb\xdc\xdf\x83P\x84K\xa5\x02\x12\x86\x97 R.\xfb\xa8*u\x85Z\x8aVn_\xa6\xc1\xcc-\xa0\xdf\xfd!\xa6\x8bs\x86\xe3\x15\xf1\xderQ\x8d\xd3\xc2\xb6;\x9a\xc6q\x08\xba\xf2}\x9eR\xdc\x00W\x97\xaf\x1c\xcf*\xab\xde_\x8aU\x96\xc7\xcd\x04\x9cN\xcd\x96I\xa3!\x92\x9f\xb2r\xb9\xaf.\xb0\xc5\xa2\x95\xdf\x1c\xa7\xc4\"\xe0]V\xeeYM\xb9\xf1\x91\xd6H\x1f\x04y\xa5\xe8\xc2%~w\x9aT\x80J\x0e\xd9\xe2$\xd0\xb4\xa3\x145\xb4\xa8\xbe\\\"u\xf9u\xe7*K\xd0\x92\x80\xc0\x05O|\xc3\x13\x98\xdb\x8c\x10\xa1\xa4b\xe5,\xc4e\xe9\xbe\x8d<\xe72\xd8\xc8E\x95=\x135\xc4\x823\xc8\xf8\x0c\xa9\x1d\x0c\x89$\xae\xb5D\x88\x89p\xca\x18\x9c\xcb\xa9?\x9b\xf5\x05\x8d\xe1\x96\x80\x19O\xcb\xce\xffq\xbc\xc7\xdd\xd5b\x07 \xe4\xc7\xbd\xc1\xbe\x15\x1e\x15L\xf0\x90\x89\xe0e\x1dO,\x1d\xd6,\xe77\x9f\x88 N\x13\xc6\xa8\x8a\xaf\xd0\xc5\x8d\xd7\x93\xaf0\x0e\x83S\x81\xd2\xdc\xd4\xa9$|\x1a\xc1\x17\xf4<.z\x1eC\x97\xe1uo_\xed\xdd$\xedHZk\xa2\xee\x89}&g\xe4K\xda\xe2\x14t\xe4QNG\x90\xc9\xe3\x9d3\xd9\xac\xbe[m[\xb5b#\x914\xec\xd3\xa0y\x9fz-\xf7i5\xa7\xb6\x97\xa3o%\xa7vV\xbf\x8a\x9f\xa0\x00\x8eR\x93\xa0`\xfc\x18\xc2\xbb\xddn\x1fq\x02\x95 S\xb6?\xbci\\`3N\xb63\xe2\x87_\x01\xd22N*\x8dq\x04\xcb\x8a%f2\x96q8\xc8x\xa3eF\xbd\x0e\x17\xaf\xb099\x14R\x1e\n\xb2\xe6Y{lR\x8f\xf5\xee?X\xaf \xeb\xbf\x11\xa3\x9a\xd0\xa9\x0b]\x05\xa9\xeac(\xa8\xa5\xf6`.\x1d-e\xf0~\xc9iRx\x00\xdb03\x93\x98i\xc16\xc5l'4\xd9\xe8\xa8\x84\"D[\x1d\x95\xe4)$4B\x12J\xcad\xa6%1\xc1\xb7\xba\x1b\x0c!\xc4W\x9e5\xb8Xy\xfb\xc2g\xca\xc2\x13\xce!\xcd\x9a\x16\xfd\x9fAF\x1a\xd6\x88\xb4X#\x85\"\x84&\x8a\x90\xf3\xbe\xd3xV\xdeA*1\xf091h\xd8\x8c\xae\xd0U\xb6\x82;Q7\xdc\xb4+S-7\xc2\xbe \xf0\xad6\x9cY\x94\xcc\xb7!\xd7(\x89@\x03I\x93\xf4X2\xd5k\xf4m\x84\xaa*-\x0b\xb98F.\x02\x8a\x9eT\x10-\x801/|,i\x048W$Kz!K/'\x95\xf9\x87G\x8f\xf8\xc5\xa4DbT\xe0\xd6\xc1]+i\xe2K\xca\xab\xc1\xc5N*\xc4\xce\xeeKu=\xfed\xee\xa8.\xd2\xe9D\xb5\xff2+\x03sm\x94.\xd4\x8c\xce\x1d\x87\xc7\xbb\x94-\xa3\xfb\x97\x89~*\xb4\xb3\xbe\xa2\xb9\xe5c'O \xa6\xd1\x80\x98}\xec7\x94\xc0\x14\xa1zO[Xy\x15ia|\xdc\x9c1\xf7ui\xbc\x85\x0fy\xbd\xd4\xed\xf3ce\xe0'<\xb4C\xaa\x89\xce.?Uf851\xc3\xd4I\xa7\xfeL@\xcd<\x12{G\xd5X\x11\x15K\xb8\xc8\xd6y\xc4y\xeb\xb0\xee\xc4\xca\xd0$\xe2dZ\xb9R\xf5\x0d\x97\xa8\x90\xaar-\x82,\x9a\xfa\xd3p6\xabL+\xd5\x98\x03\xe6\xe12b\xbb\xd2\x8fR\xab\"\x9b\xb5s\xc43\x02\xb0S\xe8\x1fUOB\xa9\x97V\xcc2q3\x84\xc8\x03\x85}6GZ\x9c\xb0\x13\x08%\x8b\x85\xda\xcbR\x0e\xf2b\xe7\xe5n\x9fr\xfbR\xaadh\x1f$dA_W\xac\x15,\x96{|\x8a\xf1\x80\xde\xa64\x9c;\xf5}\xc4m4\xc7@\xca\xab\x85'~et_\xe4\xf6\xa3z\xb1Z\x07,\x0d\xe9\xd5\xac\x07x\xd9\xd6q(\xecC\x8f\x9aC\xcaX\xa3\x99\xf3h\xe1\x97i\xba\xd6\x04\n\xe7\x0fo\x12C\x0cq\xd1\xdfS\xc1\xec\xd57T\xd1\xb8\xae \xd9zC\xf3\xdb\xdb[\xf6\xf6\x17\xda\xb1+-l\x8e\xec\x0d,\xa3\xf5%\x8d\xedm\xec5Lr\xe1\x07\xa6P\xebzs\x04\xeda\":\xf9\x16\x98%\x1d\xca\x1a\x83\xc4\xd47~d\xbc\xde\x99S/\x9a\xd3O\x1f\xdf\xbe\x8aV\xeb(\xa4a\xea(Q:\xcfzh\xb2\xc0\x18+\xcd\xceM\x07\xdc\x7f\xc2_\xdc5!{NT\xaa\xf1\x05$\xed\xd1\x9e\x8c\xdcQ\xdc\x0f\xa1\xcb;R\x9d\xcd\xf95\x0dZOO\xd0#\xde\x85X(6\xd1H\xf2\xd1#\x10G\x0f\x0dkS\x8cP\xb2\xdbG\xb6\xa0\xfe\x94'\xf03\xd0\xbe\\\xf4I\xd1O\xf2\x8f\xc8\x0f\x9d\xee\xa3\xae[!o}H\xb9go 2U\xb0\x94.\x92\xd1@b\xfa\xfb\xfe\xe4\xd1\xac\xe7\xeeO\x9c\xe9\xef\x8f\xb8\x95\x04\xae\xfa?>?G(\x86V3\x01i0\x159\xe8\xb4i6\x8fb\x156\xabg\x0b \x9b\xe2\x87\xfc\xba\xd7\x89\xa7\xfe\x8c\xb1\xc9-x\xa6\xf8a\x08^\xf8FnU}\x1a\xb9o\xe4\xde\xee\xb6\xd67rk\xb8\xa9\xf1\x8d\xec\x1e\xde\xae\xa9\x97\xd2\xb9\xaag+W\xcb\x14\xdf\x97\xf2\x93$\x7f\xe2\x87-\xc8\xb8\xe1\xcaL\xdc\x94\xf5a\xdd\x87y\x1f.\xfb\xe8\xc9\xa8\x89\x01\xba2X\xe2.\x0d\xe5w\xa8\xf9-\xafSE\xb5Yl\x8a\x92?\xf4\xe9\xdd\x9ar\x9fh\xa2\xe6R\x06\x950\\\xe8\xcf\x10\xb9+\x03=\x02\xe1\xddK\x1du\x04.\x04\xec)\xec\x8bh=\x1c\x10)W\x1a\xd3\x01Y\xaf\x83;'\xeeW#>}6\x0c\xf0\xdc\xech\x8f\x16\x12\xb0\x01\xe6\xfc\xedJ\xbc\xa0Kn\xb7\xf2R\x90\xa1P\xdei\xa0\xe8\xc0Z\xb9f\xcf\x16\xad\xc6t\xa35\x97dC\xa2\xb8\xb3t\xbbj\x01\xce\xb9\x9ac\xe3\x90\xed\xe0Z\xb59\xec\x83\x08\x05\x1fe\xa9s\xd3oa\x94\"A\x91\xc2\x068\x08\x0f{\x00\x88%L a\xdc\xdaB\xbep\xed\xd6\xf3s\x00ga\xabn\xdf\x06\x88\x1cZ\x1d\xad\xe7\n2\xa0Av\x00\x13\xb8`\xaf\x8c\xf9\x9d\x8e\x8a-5 M\xdf\xe3m\xd3\x1a\xe81\x97\x01\xea\\\x0bz\xb6Bl,$^f+\x1a\xa6 \x0f\xe4\x9f^\xfaI\x1fo+\xa8Ei\xc2^V\x90\xad\x10\xbf\x9b\x97\x0f\x14t\xe5\xbd\xd4\x91\x80 $\xab\x02fkmC\x9f\x1d\xd3\xc2\xb3\xd1-]u5\xea\xcd_8\x97m\xe4\xf0\xfa\xc6BSyG\xd7\xa8\xdb\xaf\x8cT{r`\xaa\x0bF\x85\xee\xefQFrB\xae\xfbA:\xd9a\xe7-\x99\xfb\xe1\x92g\xdap\x18\x95\xec\xae\xc8\xedo\xc4O\xbbty\xbb\xb5PS\xe5~p\xa2{#\x97u\xff@ *\xdd\xeb9\xe1-]B\x0f\xab\xac\x05\x82\xe43\xa1\xaf\x0f\x9d\xd8\xa9\xc4\xcd\xccs\x08\x15\x0c\":`\x8c\xc1#\xe1\xe3\x94\xcd\x0dH\x02\xb9|\xd9\xa9\xd8O~\xd6\xef\xd0\x1a\x80\xc6\xa0]\x14\x14-\xba\xe7\xe7\xd8\xfe\xf99R\xe4\x7f|\x86I\x15LZ-\xa89\xe8\x16\x8fC\xe7l?s\x1di\x15\x85\xe2`\x9f\x81vw\xe8\x0e\x16NUp\xee\x832\x0c\\\xbc>l\xba.\xeb\x7f*\xc3\xd9u\x1c\xaa\xda\x8c\xa1\x9aM\xe78\xd5\x14y*\xd5G\xcd6\x9e\xb0*0\x8cl\x87\xa8\xebK%\\\x8aFx\xf9\x9c\xd0\x1cM\xd0@\xf6\xb8\xae\x06\xad\x9a\xc1\xfe\xe33\xbf|\x19\x8b\x83\xa6\x82z\xde%\xf5\xae\xc6\x8aEv\xebM\xab\x92\xf5\x02\xe5\x8b\x8d\xdb\x82\xe8\x1b\x8f\x1d\x0fC6\xf0:\x0f\x1b\xd9\x97\xed}\xde\xdf\x18\xc7\xff\xcc}\xe0~oV\x1a2p\xed|E[\nx\xab2\xb4\x90\xad\xf7\xb4I\x88\x9d\xad\xbd-m\xdc\xa1\xa7\xba\xb0C\xa1\xb3]\xad\xcd\x07\xfft\xbbZ=\x10\xe5\xd5\x83\xc0\x13\xbdVG\xb9\xe0\xf5w\x86\xa5\xd3\xf0\x99\xf2+\x1a\xf8![\x1a\xa7\x82U\xeb\x1a\x19Z\xf8\xe1\xfc\xf5\xf1\xfb\xa3hN\xc7Ui6\xa6\xe1\x9c\xc6c\xf0\x07\xfc[e\x92\xe1*\xca\xc24\xd7\n\x1d\xa4\xbc\x11\x7f\xa0\x7fR~\xfb\x9a\xc6\x89\x1f\x85cH\xaa\xad&x\xc3v~\xc1\xe8\x05\x9d\x7fZ\xcfIJ\x931d\x83r\x89\xe15>\xd2\x93\xec\"\x8d)}\x1b\xa6\xd1\xab(L\x89\x1f\xb2y\x14\xc2\xabB\xa1\xf5\x91\x1a\xcf\xcf?\x1e\x1e\xbc:=\x7f}\xf8\xeb\xe9\xf1\xf1\xbb\x93\xf3\x9f\xde\x1d\xffx\xf0\xee\xfc\xe7\xe3\xe3_\xce\xd1CWk9e\x7fM,\n{\xbbU\xc5\x8ar>\x87\xe7iL\xa9.i\xf8\x92\xa6\xaf\x82(\xa1I\xfaV\x10\xe47q\xb4\xe2\xab\x12\x0f\xccO5\xba\x16\x8aK\xc6*\xc8\xcaM1\xc3@\xb9b\x18\x88e\xa0\xf3|\xcc\xfc\x02\x921\xfbR/\n=?`\xcb_\\h|\xaepH\xeboAL\xf6\xf6\xaa\xd1\xca$5\xa9\xeewNM\xf6\x9e\xea4u\xac\xbc\x1a\xdd,\x13\xe5U\xaa$\x88\xe1\xd3j\xbf\x81(\xaf\xf6\xcb\xe9\xc9\xde3==\xa9\x11\xc35'3\xa3*Y\x9a\xf3\xf2\xcd\xea\xe1w)\xcaG\x95\xf2kQ^\x9d\xeeJ\x94W\xc9\xe4R\x94W\xc1p'\xca\xab`\xb8\xe0\xe5[\xd5\xf6\xcfEy\xb5\xfd\x1bQ^\x9d\xef!*\x18\xdb\xf0n|{6\xc4\xce>D>\xeeP\xb8p/\x07\x87\xd74L\x0fW~\x9a\xd2Xl\xf0\x8f\x94x)\x96\xbf\xf3\x93\x94\x864vVn^\xf7C\x90-\xfd\xf0\xe7\xecB\xd4V\n\x8f\xe39\x8d\x1dR\xad\xfb)\xf5\x83D\xd4.Q\x0bga\xab\xcaj\x9c\xc6\x84\x91d\x12\xa0\x80\xde<\x82\xe4\xc7\xbb#\xb2\xa2\x9a\xfbC\xf69\xf1W\xeb\x80*\xd5\xc7pS\xa72\xecs\x18\xa64~G\xc9u\xb9v\xa6\xaf\xfd\xea\x92\x84\xcbrMCv\xb3\x13\x1a\x94\x07<\x86s}\xcd\x1f\xe9\"\x8a\xe9\xdbp\x9d\x95\xab\xd7]\xb4>#d~\x8e\x92\x02\xb8\x020?\xb1\xb5\xf3\xbd\xbc\xf8U@\x92\xc4\xf1\x8c\xf5O\xe9mZ\xa9|\x89\x95_\x1f\xbf\x97\xd7T\xa2\xaaR\xf2*\n\x17\xfe\x1235\xb4\xab\x99\xb4\xaey\xc1\x17}\xb5f%\xe5\xb1\x96\x0b\xdf\x10/\x8d\xe2\xbb\x16\xb1>\xa5\xc2\x81\xde\xc0\xba\x1a\x98\xb2\x80\xa68\xcd\xf3\x0d!\xc8\xf5iL\xc2\x84\xf0\x1e\xee4\x15\x7fd\xbc\x80\x1f.O\xd2\x98\xa4ty\xe7\\c\xa5\xda\xd8\xc3k?\x8e\xc2\x15\x0dS'0K\xf3\xf8\xed\x8b\xc8\xbf\x99F\x08\x00\xfb\x8cw\xa9\x03\xa8Kb\x9flxY\x1c\xd30\xed\x8eu\xf7 \xbc\xca\x9c\xa6\xc4\x0f\x12k\x15?a\xac\xcf\xdcV\xe7\xd2\x9f\xcfih\xab!\xfc\x02mU\xae\xe8]r\x19\xc5\xa9\x97\xa5\xd6\x01\x05\xe4\x82\x06\xb6\nq\x14\xd09M\xbc\xd8_#\x07e\xa9J\xb24\xf2\"FMRj\xab\x87\x92\x97\x1d\x06\xf4vM\xc2y\x03\x9cH\xb2\x8e\xd6\xd9\xda:=zm\x9f\xde*\x9a\x13{\x05\x19\xb5\xbc\xb1R\x82d\x8c-\xaf\xadj\x14\xfb4LI\x13,\xf1\xce\xfa2\n\xe64\xb6V\x8bi\x92\xd8\xc1\x14S2\x8f\xc2\xe0\xce^\xe7o\x99\x1f\xdb\xdb\xe1\xd3k\xa8\x13\xc5\xd6\x1drM\x82\x8c\xae\xc8ms\x1d\xdf\n\x1d\xac\x13F7\x8duRzk\x1d\x10I\xa3\x95\xef\xd9j\\d\x89\x15t\x81\x7fm]\xef\x98\x06\xf4\x9a4\x10\x0eF\x7f\x16\x0b&\x9f[j-crqa\x87?\xa3\xc2\xd7\xb8]i8o\xe8\xd4\x8b\x02\x8f\xf1\xe1\x0du\xd0P\xae\xa1N\xb2&\xd6\xe5\xf2\xa20\x8d\xa3\x06\xca\x884\xe6\x82\xce/\xac\xe0F\xcf\xe8\x15M\x12\xb2\xb4\x82}\x11D7id]8F\xf9\x82\xa6\xfe\xa2\x9b\xd0:\xecu\x94\xf8aB\xadP\x8c\xa3\x9bFH\xc7\xd1M#\xa4\xe3\xe8\xa6 \xd2 M\x13\xff\xef\x08\x99R\x8d\x8a\x00\xf6\xfa\xf8\xfdA\x9a\xc6\xfeE\x96R\xc6\x1a\xb2s\xaf^E\xf2\x1dy\x8d\xbc\xc2W\x9c\xc2\x8aFgX\x95V\xc4\xd5\x81^\xa3\xb3\xb7W\xad.e\xb0\xaap#e\xb0\xaap\x83q\x08\x9f\xf5a\xb4\xd5\x87\xcd\xbd>lmV,[\x990\xb6\xb9\xa9 \x14\x1d\x0d<\x12~J\xe8\xeb\xe3\xf7\xa8O@\xde%\xf1\xd9\xcc\x91\x0fE\xbd/O\x11Q~\x19\xc5\xb5R\xda\xfcjS\xf3\xc8\xc3+\xda\xf7\xd1\x9cb3\xb2\x00\xa4\xc3\xa0,\x18\xa8U\xab\xca\"~\xd3Zm\x9c\xf1\xae\xd5\x01\xb2\x07\x1d\xee\xb2\xe7\xd4\x0dk1\xf5\xbbHv\xc1V\x9f\xb8F\x05\xcaz \x14C\xac\x06\x9a\x07\xbd\x0dS'/u\xdc>\x8c\x86.\x8f\xe7\xa7\x11?+cu:\x1e\xc8HT\x0b\xc0\xec\xbe\xec\x0b\x86\xe4\xabL\xf6Z\x13\xa6{\x95G-\xc5t\xbc\xaf\x84W\x03\xe35K\xf5\x96\xdax\xd2\x17\x85\\\xa1\xe3\x00\xd9g}I\x12:\xffH\x97~\xc2\xf8X?\n\xe5\xb6\xd0Vg\x9f\x8b\xec\x82\xf1zc\xe8F\xa1\"\xb9X\xbc\x10<\xb2N\xb3\xb8\xfe\xca+^^\xb7\xe5\x87\xfa\xde\x96\x9f9]\xd3pNC\x0f\xd9\xdai7\x8d\xd6*\xda\x86\xf3n\x1fX\xe1/\xf4\xee\x03\xe3\"\xc4O\x862b\x98\xf8\xfb\x03IR\xda\xd5$\xe5\xab\xf7\xea\x95\x9a\xffN\x80\xac\xce\xa1\x1d,\xcbo}#p\xfe\x18d\xb1\x80\x92 \xb2\xaf\xa3\x9bP\x0f\xe7_\xe8\xdd\xa7\xb5\xf8\xfe>\xca\x12\x8aU\x1f\n\xe7\x93\x94\xc4\xdf\x0be_U\xba\xf9\x02X\xe3{\xdf\x15\xdabd\xff,xs\xc9\xf6\xfb\x03\x9c\xf7\xf3\x05\x10\xe7/~W\x90\xcb\xb1}C\x98\x97J*\xe3\xbb\x13\xaa\xbe\xbc07\x9b\xba\xd0^\xa5I{r\xad\xb2\x83[C\xe7C\xb3ZD\xd7r\xf7\xa2G\xc5\xab\xf2\xe1\xabk\x18gim:o {\xd0D\xd3S\x9b\xe3\x105\x19\xa8\x97@k\xa9\x84ki\xb7\x00\xd7\xc4\xac\xb3F0j\xb2\x1c\xd7ymhL \xafe\xde\xb7\x01W\xa0\x94G!:1\x05A\xe9\xceIJ\x90\xbbIa\x02\xe9\x80\xfd\xac\xdeI\x14#b]\xdd\xe4,Y}t\x87\x92\x8f5\x84\xa6\xcd\xfa\xba\xd8\x0e\x1e\x86l\xb3\x99FC\x13^\x82\xbaT5\xf2\xd6\x18\xf3k9\xa8\x9e z\xe39]\x17\xec\xbczX\x07\x87\xe1\xbc}\xf3\x82Z<\xac\x07\xfeR\x13\x9d\xe0\xd7O7\xdc\x96\x10\x85\x8fG\"J|u\xb8h=\xd7df\"1M\xd9\xc4\"\x92\xd3\xa3G\xca\x8e-\x07\xba\x16\x031\xf7\x8e\xab\xe1\xf6AI\x18^\x16\x08\x00\xf9a\xf6.\xc6q\x17\xe1{kMp\x1c\xab>:\x0c\xd1j\x8f\xe7\xa9c\xf2\xcd\xcd`I\xd3\xd7$%\x8e\xcb\x81\xb3\x0f>\xdawEQ@\xe7NTu\x05`X\xbd\xc0,\xc4E\xa5\xac\xd8\x03udO\\X\xf0]V\x8bsbp\x05\x95\x97\xd9\xe7Z\x7f\xfb\xdc\x92GDH\x91m\xb7qn\x8c\x07\xc4\xf3\xb2U\x16\x90\x94\x9e\xdeD\x1f\xd8\xf1\xfb\xdaO\xd6x\xf9\x9c\xe0E\xca\xc2J\x8dn\x1b\xf6;\xa9\xcf\xbf\x83\xd1\xa2\xe6U\x13\x9fo\xb6\xe3[m\xc7s\xa7\x1a\xb0F~\xda\x1c\x1c\xf2\x93\x1fF7\x97\xbew\x89\x8bp\x0d\x13\xbe\"cp\xee\xc4u\xd8\xaa\xa9\xabBd0\xf7\x95\x1bv\xe3\xfa\xea\x1b\x04\xe5&\x02Q\x1dc_\xdf\x15C\n\xf5\xef5\x86\xd9S\xf6]3M\xc1\xad\xdc\x82\\0d\xb81\xad,:5\xd4\x17\xb6\x88\x0c\xd7\xf1\xd8\xdc\x04\x07cj\x05\x14\xc0)\x1b\xbb\x11z\xfe \xa6\x01% un\xdc~~\xe0\xf5\x0d\x01,\xf5\xae\xce\xeda\x06\x0fBu.O\xb6Z\xabo\x8e\xe1\x8f\x1eA\xa7\x85iD\xe5m\x87\x0e\xbc4\x0e~\xa1w\xb8\x1ayJ~\xd8\xd0\xd1\xa2\xcf\xd1s\x80\xf2\x83\xf7\xba\xf9\xbe\xb9t<]XD\xa8\xb1\xa8\xf8*\x1b \xba1\x8b\xdcQ\x1a\xda\xd6HX\x01J\x810\xc1\xaa\xac\x96\xbc\x0d\x1d\x9c\xdf\xc4d\xbd\xa6\xf1I*\xb2~\xa4\xe5\"\xf3\xd5\x01gT0\xd0\x980\xd7\x0d8\xaf\xd3\x0d\xb3\xd5\x05\x8d\xf3\x95c\x0b`\x19\x0b(\xacw\x97\xe7\x8c\xc3\x03\xcc\xdc3`\xf4\xb5%Ms\x93TG\x9cyn\x112\x17\x1d\xefk\x15\xb4+\"?\xfa{\x8dz)\x9eB\x81\xd1\xe1D\xafp}\x8f\xa5_)*\xef=\xd595\xab)\xde#q\xa4\x8a$\xe2V\xb4i\x197\xd5@\xe0\xf8\xe5\\L\x17\xf5\x85\x928\x18\xd60\xd7\xe2\xce\xaf\xcfV\x00\x13\xa0\x0e\x0f8\x92]\x04\xbe\x97SMd\x02\xe2\x01\x99\x17n\xa8\x07\xc9G\xba8\x8d0m_\xbf\x1ab\x0bp\xe1B.\xc8\x0d\xce\xa3\x9b\x90Vc\x96\x16K\xc8\xc4\xb7\xe42\xca\x02!\x06\xb5\x81\xa6\x84I]r\x03\xa9\xae\xac]a\xe4\xd0\xa7\x06\xe8c\xb9\xc8\x86\x16\xd3\x85LL)\x86_\xbf\x0f\x89\x8c\x03\xf0\xb5\x03P.W\xecX\x90\x13\xcb\x94\x8f\xc3\xc7\xafb\x1c}\x08\xf1m\x0c#\x9eG+,\xde\x8e\x90\xc0\xf1\xbdY\x062g\x89\xdb\x80\xf7\xff5\xc8\x8a<;\xe2fLW\xd15-\xa3';\xf9\xbf \x82~\x075\\)\xe2\x80Q\x03iP\x8a\xfc\xe6\xc1^\x0b\x13G\xedR\xa7\x91Xh\xf3\xfb\x1e\xe6\\\x9a@d\x89\xfc\xe2\xac\x8d\xc1V\xd8\xe73_\x81 W8z\xe6!\x8b\xf0\xa0\xfb\xfb\xe0\xb5\xc4\x94\xb9h\x16D\x92\xe4\x04\xc6|\xb05\xf5G`\xb8\x96\x07\x19uD\xb4\xe2Y[\xf1,\xad\\WlZ\xc9\xa0 P\x88\xd0\xb8S\x0ds\xc9ov\xf0\x9d\x80S'V\xcc\x17\x0c\xd3`]WVq_\x17\x95\x17\x04dV\xfa\xd1 \x81\xc60\xca\x96\xd1\x08\xd0\xaf\xca\x83\xa2\x9c\xb6\xb3\xe2\xbc\x7f\xf6\xab:\xa8y\xd9\xce\xa98D\x95{\xa9\xeb>\xac\xf8&w\xfb0e\xbf\x1a \xa9\xfe\x8c\xcf\xb0\xf4+\x0f\xd2Z\xf4\x1bv\x8e\xca\x00+~\x14\x0e\xde\x7f:9=\xfftrx\xfe\xe1\xe3\xf1\x87\xc3\x8f\xa7\x7f\xad\x9f\xafj\xf5\x9f\x0fN\xce\x7f<>~wxpt\xfe\xeb\xc1\xbbO\x87\xf5c\xb7Z\xfd\xe8\xd3\xfb\xc3\x8fo_\xe9\xaag\x9a\xea\x1f\x8eO\xde\x9e\xbe\xfd\xf5\xd0\xf6^\xa2y\xef\xf8\xd7\xc3\x8f\xef\x8e\x0f^\x1f\xbe\xb6\x0d0\xd0\x9eR~\xf2*K\xd2h\x95k;\xc6\xf0\x91.\x0fo\xd7J\x94\xfc\x94&\xe9\xe0\xc2\x0f\xe7NHo\xc4c\xa7\xfb\xbb3')\xb9'\xb1O\xdc\x0d\xcc\x01\x14\x0f\x0eNO?\xbe\xfd\xf1\xd3\xe9\xe1\xf9\xd1\xc1\xfb\xc3\xf3W?\x1f|\xc4\xbc@?\xfc\xb9\xab\xcb\x1ao\x0f\x85\xc1><\xb3\x8e\xd6\x07\xb9x\xfc\xea\x92\xc4\x185\xd1R+I~\xa1w\x96\x1a)\xc6\x1c3=\x0e\x82\xe8\xe6M\x16\x04'^L\xa99\xb6\x0c\xd6\xc3\x08%xjx\x96\x0e\x03\xcbp\x13\xcb\xa3\xbb\xd03w\x9f\xa5\xd1+\x11\x12\xc3\xdcD\x96F\x1f\x02rglE\\\xec\x9b\x9f\xd3 \xf8@\xe6s?\\\x1a;auN\xd6\xc4\xb3\xd6\xb9$\xf1\x89e\xd5\xbcK\x12\x04\x14-\x1c\x8c50\xb4\xc7\x18\"\xb87\x8e\xd6\xb7\xc0\xc2\x0bH\x92\xbc}m\x7f\xceYLS\x8d(H\x8cA\x89\xbc\x88\x01\xc1\x8cV^\x14\xa64\xb4@\x80??\x9c\xfb\x18\xe8\xc3^\xef6}O\xc3\xccZ'\xc6\xc1\x9a\x00%*\xbc\xf3\x13\xdb\x88\xa2xnFO/\x8e\x92\xe48\xf61L\x92\xa1\x0e\xb7\x0c2?\xa4\xa7\xbe\x05\xdey|\\\xc3,\xe6t\x81\x81 \x0dO\xfd\xd8\xdc\xb2\x08\x96c~9\xba \x83\x88\xcck\x91 \xf3\n1Y.\xad\x0bEC\x8f \x04\xc6\xe7\x8b(^Y\x1f\x1e\xd8\xe9\x14\xabr\xd8\xa2\x8f\xf74\xbd\x8c\xe6\xd6*G\xd1\xaf$\xf0\xb9\xff\xa9\x01 \xac\x1a\xe7\x0f\xcc-\xc5dE\x7f\x8cb\x8c\x16i\xa8sI\xc9\x9c\xc6f\xa4\xba\xa4\xfe\xf2\xd2\xdc\x05\x0f`d\x1c\xe4\xa5\xbf\xbc4\xbf\x1b\xd3\x85\xf5\xe1;b!`\x97\xe9*x\x13Y&\x96\xa6\xeb\xc3\xbfe\xfe\xb5\xb1\x86\xefY\x16\xd37/\x10\xden\xbd\xc7\xf0\x8d\xc6\x1a)]\xc6~j>\x81|3\xc4\xaf\xe8\xdd\x07\x12\x93\x95\xb5\x86\x15\xc9\xae\xfc\xd0d\xeet83ov*nd\xd9$e\xba]D(4\x7f2\xec\"~]\x19\x95\xea3\x08a\x08|\xda\xd7\xed\xbe\xca>3$WK\xbe\x052\xd5\xd0C\xe4\x87xVE2\x11\x9b\xf4\x99>?\x84.\xd9L\xac\xac\xe8\xa40\x9d\xe7\x89x\x04\x85r\xbas\xff\xfa\xffa\xefM\xdb\xdb\xc6\x91E\xe1\xef\xf3+`\xde9ij,)\x96\x9d\xc5Q\xe2\xf6u;\xce\xe9\xdc\xc9\xf6\xc6N/\xa3\xf6\xf8\xc0$$\xf1\x84\"8\\d\xbb;\xf9\xef\xef\x83\x02@\x82d\x81\xa4lgf\xeey.?\xd8\"P\x00\xb1\x16\xaa\n\xb58\xfa\xbe\xb7\xb9\xf2\x1e\xfe\xfd\xb7\xf4//\xdc\xdf\xae\xb6\x07\x0f\xf1Q\xe8\xa5\xdbX\xbb\xca\xcf\xc5\x9a\xa2\xee\xd6\x04\xd1DL:\xfd[\x91\x8ab\xf8\x8af\xde\xd2M\xdb/>\x01Ug\xb3\xc9yU\x1f\xbc9\xf1\xa8yVH\x94np\xe0\xd6u'\xe1\x82\x1bkd4\x0e\xa2\x88%b\xbb\x08\x9c<\x9b\x9c\x93m\xc2\xc86 g\xbb\xc8\n/B\x1a{\x00\xbds\xfe\x9cx\xa3\xd1\xf3\x81\xd4\x0c\x1d\x874\xcd`\xe1V\x17\xa6\\\xda\xd5O\xb1\xe6\x90\xce\xb5B\x98\x9a\xf4\xf4\x87\x9b3\xba\x80H\x0d\x8e\xf4\xb7^?a\xe7:`\xb3\x8c\x16\xadgkH\xb8;\x1f\x8c\xe7<9\xa1\xde\xd2\xcd\xeaF\x80E/br \x83~\x81\xfa\x89\x1b\x8d=\xd1x\xb1m\xd3\xc1s\xb3?\xa2\x87Z\xdfQn\xe42\x0f7\x99,\xf1\xfc\xd7\xfb\xd8\x7f\xfb\x96\xcdm_\x82\xaa\x1d\xedkT+7nI\xcd\x1cTC\xb7\xaa\xd0x`\x86#~\xf0\x808r\x06\xc05\x03T\xb2\xe5:)\xcb^G\x19K\xd64\x94\xe9\x83\x8a\xde\xbc\xa9\x13)p\xb3 \xcd\xe1\xf3r*\x82\x14\xfe\x8b\x06\x8bO{4\x0c\x19S\xf5\x83\xa9G\xc6V\xaa\xda\xea2\x13%\x0eI\xa3\x12 \xa2\xc0\xf6\xbf\xdb\x98\xa3\xdc\xaf6\x7f b'\xe1\x0d\xd5c\xb7U\xd5n\xb6\x85r\x86\xc3\x08\x16+20\x99\x91\xad\x0c.\xc1x\x81\x8c\xc8\xa4\x18 ]\x1c\x9d\x9c\xb1\x1c7\xa3\x9ez(\xf9AK\xbc=\xb5.d?\xcb[v\x18F\x15\x87\x1d\xc1Jf\x9c\xbc&UX\xec\xbaH\xef:7\x13[U\xfa\x9e\xe0\xe4\x05\xc9\x9e\x13\xbe\xbd= \xd1\x8c\x9f\x8bI\x98q\x04\x05i\xf5\x9c\xe6\xdcO\xc9\x8c\x9d\xdf\xef\xb6\xb3\x1c{XP\xa4\xbb\x1ec\xa0\x13\x89h\xed\xcd&C\xf2\xdd\x0b\xc9\x1f\x16\x02\xec\x03'Kr\xe6|\xff\xdd\x908/\x1e\xca\xcc\xef\x9d\xf3\xe6\xc1(J;/\x80\xb1\xfc\xde\x01`\xf5\x1b\xf1\xf4=\xdb+a_d\x97\xdc\xbf\xf9\xfeE\x96\xe8b\xc9\xf7/\x1e\xaaDK\x1d^\xd9\xda\xf5\x82\\\xaf\xc2(=\x00\x8eo\xfa\xf0\xe1\xd5\xd5\xd5\xf8jo\xcc\x93\xc5\xc3\xdd\x9d\x9d\x9d\x87\xe9zQ\xb4~\xbdhT5G\xa9x\xe7/\xceT\xf6\xe8\xf0\x85\x1f\xacU\xcb\xe0\xd7y\xf38\xa4 \xa3\n\xfc\xc5\x8a\xc6\n\x1a~!\xd0\x1e\x0f\xa7d\xb6\xdb\x1c\x01\xddi\x8f\x87\x8b\x84\xe7\xba\x9e\xe2\xd56\x1a\xe2 \xd9\x82E\xben\xc4<`\xa1\x9f\xb2L\xd5P\xbe\"%c\x9a\xd0\x95.(1\x8b*\xa6_\x90BY\x82vAM`\xeb\xdc\x11y\xb7\xb0\x90\"wDn\xcacy\xad\x8bdyT\xe5!l\x92\x1e&4\x13\x9a\x84\xe7\xcc9\xcf\xf0\x9c%\xb3\xdcog~#\x08\xa0,0\xad\xbb\xa7,w\xfa\xcc\xf1\x82\xc4\x0b\x81\xc5\xf5\xc2 \xfe@\xb3\xa5\xf8\xed\xb39\xb8n`a\x18\xc4)d/\xc4\x9f`E\xa5\xaf\x07\x08\x80\xa2\xfe\xd3\xe4?\x13\xea\x07,\x02-\xdd\x15M\xc1\x03D\xac\xaaR72\xf0\x93\x877\x0b^\xfc\xd4u\x88\xc244\xebHddJ'\xcd\xb8\xf4\x0d\xc1\xae\xa5\x060\x84;8/(\x1b\xfba6\x07\x0f>\xc4\x1b\x12*\x7f\x99\xc1xk^N:i\x88@\x9c6\\\x9e\"\xf3\xda)\xa2N?p!\xe4\xfcEpV\xd4\x02\x11T\xe8?\xe7/\xa5m\xb5\xf3\"\x0c\xa2\xcf\xe4\xe1\xf7\x0e\x99\x12\xe7\x85\xa3HP\xe7\xfb\x17\x0f\xcb\xdfN\xd9\x95`<\x0f\x12M}\xa9\xe4C\xd9e\xd4\xd3\xed]\x0f\x01T\xc8`Qwoe~q\xe1BO\xeeW\x1f\x9d\xb8\x82(\xe6\x83\x99\x80\xab\n%\xfb\xd0\x0e/\xa2>\xac$Nl\xde\xc1<\xa2S,\xd1p@\xa3\x19\xc9z$=-\x97\xa8\xcfI\x8eK7R5\x85x\x9c\xc1\x86\x02\xa6\n[\xfa\xa4\xce\xbe\xaa0\x83\x0dW>\xb1\xaa\xbe\x9e.\xe3\x0cN\x1e\xd7;+\xe3\x0c\xee=\xae\xc3\xaf\xf1\x15\xa5\xc2\x0c\xee\xd4;\xab\xc2\x0c\xee\xd4 \x91\x1b\xd5\xfc\xfa`\xaa0\x83\x0d\xbb\x8d\x0b)\xb5\xd9{6\x18B\xb8\xc4\x9d\xba\n\xa4\x8a7\xd8\x18\xbe\x13U\xf0\x11\x14\x9c\xf8\xeb\xebB\xa2`r\x0b\xa2\x85\x16{\xf7\xa8\x10\xf9;\xe4l\x19\xa4D\xd0\xf6\x82c%W4%:L,\xb9\xbc!\xff%\xce\xa9H\x9cS\xff5Fn6\xfed\x7f\xd3\x1f(Ka./\xde\xa1'\x83\xb4Z\xfd?36\xbe\xc8\xe8\xe2\\\x1a\xd7(s\xcfl\xac\x97\x85\x1e)\x99jY\x0c\x8a\x1fu&{O\x1dA\x1d\x88\n\x87\xf6\xc1?$\x0e\x81\x0btA\x8f\xa9\x91P\xaa;\x84\xcf \x9c\xda\x96\xb2\xe5\xc0\x8b\xe1\x1a\xc3\x91\x0f\xf6\x89]M\xb4uO6\xfc\xc9\x0eHu\x11\x9b\xd9\xb6\xfa\xce\xc0\xa3\xa4\x15B\x8a\x94\x9fL\x9cA\xa5\x81p\xcf^1\xd158\xf72W\x14\xddu\x86\xb0\xec\x07\xed.M>\xb6x\xdc\x90N\xb6\x133P\xfd\x15\xea!\x19\xf1\x88\xa8m\xa6\xd9\xf8b \xa1!\xda[\xe4\x05\xac\xf2\x07\x0f\xf4\xcfRN#h\xb6\xd7`\x99#a\xa6\xe2W\x87 \xd3\x91\x9b\x0dI\x00>\xb2\x16L\x06\x8e\x85\x88\xc7\x1f\x19\xf5o\xdc\x81v\xa6\xe5\xbe\xc4\xee\x0e\xa0QQ\x9aM \x12\xeb\x99\xa0\xb6v\x16\x97\x9a\xa1:3\xa6\x88\xdf\xe7\xafVKQd\xb6^6\\ \xcd\xc7q^\xc6\xc1\x05\xe7\x92\xa2\xcd\xca\xcfd\xbd\x85*Y\xb7\xa7}i\xbci|l5\x8ey*G\xf0g\xe9\xca\x02\xbe\xd8^\xcd\xa7F5\x97\xb7\xa9\xe6\x1f\x8dj\x16\xdd\xd5\xe8_b5\xbej\x1ca\x19\x8f\x8f.y\x02w\xd3\xe2\x7f\xed\xcc\xcbx|L#i\x0e\xe0x4\x8aCzc\x05)\xfc\xe1h\xc8L&4\x0b\xbc\xcc\xe5|\x1c+\x0f\x85\x8e\xaf\x12<\xcc\xab`\xc6\xe3\x93U\x9c\x05\xe0K\x90\xc9_\x08H\xe4%7q&\x81\xf4o\x0c\xccW >\x9a\x9d$p\xa3\x0e\x91\xfd\x9a\xd9o8\xf5\x99/\xfd\xd6:!\xbc@\xc8\x0f\x0b\xe0[\x96Q\xdf\x04^\xa9\x04\xbc\x80\x8a\x9f\x04\xb0)\x12\xe4\x08\x1c\x96\xe7\xa9\x18\xb0X\xfcG\xb2\xe5L\xe1\xd3$2\x81\x88\x80\xfc Z _$\xa0X\xe6\xc4\xeag\x13\xe8#\xcdX1s \xcd\x98m\xd6N\x19\x03\xf3\x0b'\x85\x1f8\x80lQ*\x7f! \x19\x0d\xa5\xcf\xc9T\xfeB@\xf24\x06I\x8f\x93\xca_M\x90\xb3`\xc5t\xb4$'\x0bV,\xc7B\x1ae<\xfe\x89\x87\xf9\xaa\xec\xdd\x1a^m\xfd\xfb\x99\x06\x99l\xfe\x95\xfce\xd0\x11\x18 \xf6{c\xff^\x8f\xb3\x84z\x9f{\xec\xfd\x1f\x1aeK_\xcb\x82\xe0~\xfdR\x1f\x98{\xf5\x8b\x1a\xb1\xf3\x199 \xea3\xd5\xcc\xc2W\xbe.\xfe\xc8)<\xf4ft\x81\x1du\xd2\xd3{\x00\xba\xfb\xd6 ?\xeap\xc6\xdd\xb5\xcb\xeaMW@\x05>\x06\xb9\xa9/\x86%\xfeA\xba\x1bU\x0e\xdc\xd4\x1e\x01\xb9\x8f\xfc\xcf\x06\x96k\xe0\xcb\x84\xd1\xcf\xcd,\xd9\xb0u\xe03nm6\xcd\xfd\x00\xcb%\xa6\x0c=+]a\xdb\xfbp>$\xaf\x06\xe4U]\x1e\x93\x01\xb1\xd7Vx\x1c\xe7\xe9\xd2E\x86 \x1b\x92W\xb3\xec\\t\xdcB7\xb7v\\j\xac\xdd\xef\x8c\x9cH4Y\xe0\xcb[\xceI\xb0Z|\xf3v\x0d\xc9\xb7\\Us\x9e\xac\xee\xb7\x0b\x1f\x19h\x88\x11'Q?Z\xbap\x9a_\xae\x02)\xb4\xd4\xbfn\xd7\x8d\xc0\x128E\xad \xe9*\xce\x1a\xd7\x8b]g4a\xf4~\xc7\xe1\xb5\n/>\x14\xad\xd3?\x99=$\x01\x82;\x7fj\xe0\xce\x1b\xa0\x9b\xe4\x89\xd0\x87p\xfa\x11\xe5\xfd\xe5%\x07&k\xb8\xa4\xe2\x94Fs\x12<\x1d\xae@\xb0\x0c\xb6\xba\x14\xc7\x1f\x96\xb5\xb4\xd4\x15\xac,\"\x90@\xc6\x14\xc5\xb2>\xb3\x9b\x05\x8b\xf0\xbc0\x88>\xe39\x82\x9e\xc1s\xd4\x1d\n\x96\xa5Ug\xb1<8\x0e\xf1\xac\xab\xcbN\xe1\xcd\xcf\xe84\x89Uf\x95\n\xc5\x89\xad%j5w}\xf3\xff\x80\xff\xbe\xe6WW,\xca\x83\x8c\xad\x90\xf2\xe4\xc7\x9ap\xedW\xd0\xa2\x99\xd1\xd1\xefG\xa3\xbf\x9d\xab\xff\xd3\x8b\xdf\xc6\xbf\x8d~\xf3\xcf\xff\xf2\xe7\x87U\xf0\xbf\"\xb7\x95\xff i\xb5\xd3\x06#B\xfe\x8cJ3\n\xedJ\x1d^\xd0\x199\x03\xf2\xfd\x01\xd9\xa9J0\x02[\xa4\x92\xbfA\xb0\x01\xe4{\xbf\xb4\xc5\xd8\x13|{\x15\x17u\x85\xc4\xf9Oy\x03\xfeW\xf03\xfb\xe5\x0bq\x7f\x05\xf3su\xcf!\x08\x98\xc7\nW\xfeU\xdf\xbd4\xdc\xbc\x16\x04NUFb\x86\x03\xc9\xe8\x824\\C\xea\xcc\x88\xaeX\x1aS\x8f}\xfa\xf8\x9aT\xe3ph\xb9\x94\xbee\xa8e\xc7 [\x07r\x9e\xb9e\x9dRZ[\x1a\xa4\x05,u%\xa99\x17\xb4\xbe\xa5\x9d*\xbcv\xee\xc6\x16\x08\xd5s\x18\x92\xd7Q\x90\x054\xd4t\xbb\xa0%\xe7C\x92\x0c\xc9\xd5@\xfa\xd8o\xfa\xf4\xfb\xda\xe6fP|\xfd\xa4\\\x98\xf0\x8d\xf71\x8b\xce\xe8B\x9a\xdd\x1cE\xfe\x87\xf2\xda*\x85\x0f\xb6,\xf6\xebZ]JA@\xd6\xa5[k\xe9\xa7h\xfe\xd6\xb5@)?\xce\x8a]yN\x0e\xc9\x89X\xdeR\xf3\xebD\xaet\xb2M\xae\xc5/\xb9\xfc\xadKC\x02\xf7@\xe0\x1b\x92\xaf]\x14O\xc7\xc9\xf2\xa68\x82\xe6c\x9ag\x1c\xc2\x88H\xd3\xba\xd6r\xc1x. M\xfe\xe3\x9fr\x14w4\xeb\xd3\xbfSwZ\xa9\" r\x99gY+-\xf7o\xd0\x8dNz\xb3\xa3Q\xff\xe8O\xbc(\x99J\xab\xbeN\x0f\xcc\xd0CCQ+\xd6\xc8\x03l\x83\xb3\xb0\xb8\xd2H\xe0J\x03?\xc7@\xa7\xa7~\x8f\x91t\xc6\x89\x06/\xee\xb3\xa4\xc5T\xcf\x0c)\x11\xd8\xcfP\x0d\xfa\x1ek\x03x\xa7\xfe\xa8N\xa1\x04\xe2\xa2\xd8\x0e\x04\xfdt8\x87\xd5\x8f\x03\xba$\x92\x96\x01\xcb.7P\x7f5&\xc6$6\xdc\xfd\xe3\xebP+\xa2\x08\xa2-\x80x\xf6r\x9a\xe5\xfc\xbe\xe2 \x94H\xdd@-\xa6\x8e\x06\x135\xa29\xc1\xdc\xeccOA'\x9b\xf4\xe4\x9fK,\x0c\xeb\xe8\x90\xbcm\x8e(\xc8\xd4\xc4\x87\xbcz\x9bk~ ]1\xd8\x10(\x01\x85.\xab\x94\xda'\xb9\xd4 \"\xdb\x07\xc4\x01\x15\xa5\xbc}\xc2\xfb\xc6\xcb0\xcc\xc2#\x9f%g\\\xf0\xf9\x81'\xdbA\x0eID\xa6\xfa\xf4\xa9\xd2\x1cf[\x1a\xad\x07\xfa\x03\xf4\x8eZ\x80^\xbfT\x15\x83\xech\xd0\xea\xd3\x1d;\xb5\xfb\xf9s_\x17\xe1Kp\xe2\x80\x93\x16\xb5\xad\xe6J1\xf7\x1c\x1f\x14\x0b\x85\x8f\xa5\xce#\xccRB\xca\x04divP=b\xc1\x7f\x98\x15\x1aYZUL\xd0\x1b\x86\xe2\x98M\x01R?T\xadu\xc0\x0df\x84p]\x83\x9d_)Q\n\x0c\xdc\x89\x1b\xb4\xd1\xc5f \xda\x86\xd3\x12\xbd\xef\xa5\xfcQ\x13\x8aT\xc5[\x18\xff7\x0f\"\xd7qng\xa7O\xca\xa5\xfc\xb3I\xa3 \xce\xf37\x15\x02,\x19{K\x9a\x1ce\xee\x8e\xd8\xbb\x90\xbcM\x1225\xe2^\x10\xeb\xca\xab\xd1\xb7\xbd\xa5\xa6Z\x89\xed~\x97X>\x86\xd3T\x94\x17\x08\xe2\x7f\xc6bs\xa4\x83\x89\xc0\xe8 \x84\x86\x06\x0c\xd8{\x05Z\x1bY\x9c\xd5i\xfbB\x94\xec\xca\xces\x12\x92\x17$\xd5\xb6\x94$\xdc\xde\x1e\xe8fI\x0e6\x19\x92t\x16\x9ew\x912\x8d\xe8\x14\x1e\x0b\x8c\xf0\x14\x9ba1\x8c6i\x0e\x0d\x06e\xdc\xceHv\xb0h\x81\x9b\xc1\xc9\xdf\x8czR7\xe8\xab\x16\xbb\xc5\x16\x00\x19=\xbe\x8c\x82o+\xd7\xefb\x8c\xb8M\xdc\xcb\x15 \x82f\xda\x96%\xb9\x17J\x9a\xdb\xa4\xb3\xbaMh\xe6\x9d\xda\xd4)\xba\xe56\xf1\xacn\x13\x9ay\xa76\xf5\xe0\x03\xb9M\xec\xaa[\x85f\"$\xb3\x9d\x01\x7fW\x14j\x13\xaapE@7`\n,\xa3 \xc4V\x19v\x8b\xf8\xfa-\xde\x95\xda\xd1\x15M\x8c!\xb9\xc6\x83\xe3\xde\x95\x03\xec1\x1f\x97X\x83\xee\xf0\xc9\xcee\xd9\xc1t\xfe\xd4\x8f\xe9\xac\x9f\xfc\xc8\x0co\x80\xade\x8cI\x0b\xcf\x98 >\x00\xf4\x03:\xf3\x08\xc3(Y~4Y\x1f\x7fl\x96 \xe7\x91Yq\x85+\xeb#YN\xed\xecZ;\x1f\x05\xfd\x0cD?\xd3\x01I\xeb\xed\x0e\xa4\xec\x1fX%pU\xf2\xc7\xd7\xc1,8\x07B\xbd\x83\x9d\xb33\x8f\xedW\x8e\x92Z@\xb8`r\x08\x03G L\xad\xdc\xe6\x89`\xcc*\x0c\x1fka\xf8f\xd8A\xecB\x11\xd1\xed9\x90\x81q\xc5dfn\xaa\xd1\xc4\x83M\xd6x\xebZ\x12\xe0\x10\x98\xa6\x87Pb.\xa6\xb0}\xf1\x0dI\xdc\xb5\xa7Hek\xc4\x03\xb2\x15#{\xe3\xcb\x172\x87\xb1\xc0\xf3n\xb5o\xaa_\x9e\x0f\xd0\xca\x1f< \xb1\xa8OL\xc1\\\xfc\xb0\xecR\x91\xd7!\x81\x90\xfbM\x14E\"\xfb\xe9\xa7\xa0\xe0Q\xe9\x94\x98\x1aC85\x07|;\x95k\xa3\xdc\xaa=j\xaf\xc9n\x06\xf6\x9d\x9c\xb2\xacm\x1b\xb7\xdf\x8d\x17\xdf\xdb`\xa3w\xa3`\xdf\xa6|^\x7f\xca\xddrX\xedI\xd1K_u\x81L\xed\xd8\xc5\xdf0\x10k3\x05\x84U\xd4l\x80\x12\xd8\x15\xe3\x98c'\xb2\xf5\xfc\xbd5\xd7]\xb0\xb6\xac\xc2\xda\xb2~\xac\xed\xdd\x99c\nZz-6|\xd6L\xc5\xd1\xe3\xd5\xe6m\x02\x05\xd0\x8f\xbfU\xb5\xa9\xc1\xc6\xf3\x92\x8d/G\x0b/\x16vq\xffx1\xaf\xf25\x03\xbd[\xbc\x07\xcf+\x9f1\xe0\x11\x1aKg\xa5\x05q\xa4B]e\x06\xff\xabIr\x89\xb8#uF{\xa2\xc8\x16 _\x03\xf8\x8c]gJ\xf8\xe8V,>\x03PF(\xe4\x16\xd6\"d\x9b\x04\x03\xe3\x98\xcc\xc9!\xa1P.\xaf\x95SW\x92\x8e\x14\xf2\x1aE\xc2\x1a`\xd1\x81\x10\x0bg]\xdbL\x8a\xffy\x07\x0e\x85\x8b]\x84\xed\x1d%F\xab\x1b\xd5 u\xe6\x91]\x95\x10\xabyC\x9e\xfd\xff\xe9\xe2\x19\x8f\xd6\xf9\x95c\x87[\x01\xd8\x0f\x07iV\xdezvT<\\\xed<'\x11yA\xb2B\xfa\x15mo\x0fH6\x8b\xce\x95\x0e\x87\xcd\xf2\x9c\xf4a\xe7\xda\xf8\xd9\xde<\xe6\xf58\xcdx|\x96P\xefs\x10-\xbaN\xc7\xce6\x81\xc3\x82\xb6&-\x19\xf5\xdboo\xb9\x7f\xd3\xd2\xde\xc4u\x9e6\x1f\xe93\\\xf6\xd9i*C\xea\xa7\x8f&\x8bA6\xe0\x07\xa2\xf4h|\xc7\x03\xf1\xe9\xb3\xba\xcb2\x0e\x86\x87\xa3U:\xea\xf4\xdc]_\xeaj\xeb&n\xe1e\xdd\xe5C\xe2\xac\xd2\x913\xa8\xe3\xda;\xb5\xfb\xe1\xc8\x1d\x0f\x1e.n\xd9\xbe\xb2u\xc9\xb0\x1b\x85kW\xe0\xe3\x8c\x7f\x12\x14$\xe2\x02\xfc\xeb\xbdv\xceF\xa5(\xaa!\x19\x07\xe9\xa7(\xc8B\x96\xa6\xef\xc0\x7f\xd9\xa0k\x1cZ]\x19iQ\x02h@9\x97\x9c\x87\x8cV\\\x17\xcb\x0c\xa5\xc0_z\xe0\xaa\xed\x04\xady\x11\xa4\xef\xe8;7\xab\xa1\x07\xbd2DU \xe80\x9c(s\xc4?\xe5\x83\x07\x84K/\x922\xd2\x05\x99\x82\x08\xbc\x11!\x80HG\xe3`\x96\x99\x04+\xd0\xcf\xca\xc4y\x13_7N\xf7;N\xca\xfe\x0e6)\x0f\xff~\xb7\x8d2\xa8\xec\x94\x11l\x95\xfbl\xf7Cwv4\xfa\xdb\xf9=m\x16g\xf4\xe7\x893\xb08\xc3\xbfCk\xfb\xb5H\xcb\x0b\xfe\xf8\x8a.\xae\xa2 z\xe6\x17\xdb\xb8\xb6\xd8\"y\xf9\x90\xcd\"pq-M\x89\xa5\x14>\x82\xd54\x8b\xec~\x05\xc8m;lpg\x8fw:\xf7\xafej\xbes\xbe#\xdb\xb0\x88\xc8\xb6x\xb9\xe7\x86M\xcc\x86i\x92\xa9\xda\x10q\x08\x87\xecL\xd9\xfcb\xa2l\x8e\xcdE\x97A7\x01?\xa9\xea\xa6\x1b\xdc>\xa4 !(|\xa7B\xda\xff\x07\xf7\xe0[\x13\x84\x9ft\x931\xbb\xce\x12\xeae\xbat\xd9\x1e+s\x8e\xcf\xc2\xbd\x84~\xd9}2\xc0\xec\xe09z\xe8h\x9e\xc1\xb2\xcc\xa3\x19\xabn\xc0s\xcc*=\x9a9?\xb3\xcb\xcfA\x06\xae\xff\x80\x1c\xb9*\xde3\xc8\x7f\xcb\x7f/3W\xf2E\xe6\xac\xd22\xe3\xedi\x99\xfe\xbeL\xe6\x90\xda\xf8jm \x12\xe3`hN3\x8d\x82\x15\xb8\xf8\x02OM\xdcu\x8et\x823$\xe5\xcbI\xe4c|KQ:\xc8\x98\xf4\x14\xd6R\xc7k\x0d\xd3Z\x93\n\xf5g\xad\x05\x9cqa5d\x89\xa0?\xcd\xae\x9c\x15)\xa2\x86\xf2\x0d:S]\x81My\x02\xe6v\xde\\\x0d\xa6k{q\x00\xe6\xfd\x18\xf6\xca\xa0\x8a}\x01Q\x1b\xae\x82\xc8\xe7W\x80\x04\xa5\xa8\x8d\x04csf\xca\x97!i\x02\x14\x83\xdf\x0e\x06#[\xbe\x0e\xaac\x82\xb4\xa5\xa8\xa22\xb4\xc6[o\x9f\xd9\x82\xc6\xa13v^P.\xe2\xe5y\x03d+0a\x90h(\xe2\xe4 \x1aE\x0d\x113\xce)\xa2\\b$5\\D\x91\xbc\xd2.P`\x88\xce\xd1\x8d_qIJ\xee\x8e\x946s\xfc\xdct\xc1,%_\xbb\x93\xba\x0f\xe3\x1c\x97:J\xc7\xcf\x8f\xf6\x8cCE\xbb#~\x86b\xc7\xb0\xdb\xbd\x19h\x13 zY\xc6@5\xeb\xf5\xac\x07\xaa\xe3-\x99\xf7\xf9\x92_\xebHU:,\x1c\xb8\x84\xe7\x95\xd4\xc3R;d\x0c\xc5\x98oj\x8c\x8c!R\x9b\x05\x1d6\xa3)\x98\xaa|\x1b\x88\x95\xe8x\xa1$ nf\x11\xed$\x1a\xecX6\xb2A\x9a\x93\xb2\xff\x98\xcf\x1a\xf1\xc8\xb0\x9aR\xe8f\xb9f\x850\xa8m\x10\x10(\xba\x15\x80^k\x80F\xfeWX\xddx\xe3Tx\x7f\xd5\xbd\xf6o(\xd8\x9fd\xd8\xc16H\x15\x99P\xcfg\xa4\xccFX\xed\x9e*\x90*\xf4P!^\x91\xa7\xdb\xa5\xabJ\xc8!h\xe8[\xaaR\xfd\xc0++\xddc\xd6K\xeb\x9c\xe6\xd0\xb5\x9e6\xa6\xd9\xff\x06\xeb.\x1b\x9b#\xd9\\O\xac\xa7\x8b\x8dj\x9f\xcb1\xca\x8a-uh\xfc\x9e\x96\xdfm\x1d%sR\xcc:aN\xa1F\xf9kJl\xb7\xffU\x8f\x1f]s\xd1M\xcc\x92\xc6m'\xa6\x11\xde.\x9b\x95\xfb\x9d]3/\xcf\xd8{\xf5q7k\xb7mK\xc74\xa5\xb1\x1bv\x1aI\xae\x0b\x85\xf6\x88\xaeZ,\xe4Azh`Ce\xfbk\xe8k\xa2\x14\xbf\xf9\x14G\xa68Xr\xfb=\xd1\x10\xee0\x82\xe7\xc43\xc2\xf7=\x1f@j%\xa9\xdf\xd7\xe6P\xec\x1f9KnNA\xf7\x96'Ga\xe8\xca\x9b\xdb\x99\xe8\xf5\x81\xa0i\xff\xcf\xe9\xfbwc)i\x08\xe67Re\x01D\xd8\xdf\x9d\x83\xda\xcc\x81\xea\xfd\xf9w\x03\xe9\x02`\xe79\x89\xc9\x8b\"\xf4\xd9s\x12oow\x0d\x01Q#\xee\x83\xd6Y\xdc!\xb3$j\xdc\xfdR'\xc3\x1f\xcfy\xb2\x82\x19\x08\xe0g\x9f/\x12\xf5\xd5\xa5\x1ew=\xdeb\xec\xe1\xd2\xb5\x1e;\xcd\xf6,\x95c\xadg\xe0\xe4\xbb\\d\xcbn\xc9*.\xfa\xec\xce\xb5\xe7\xa0\x01\xa8\xf4\xf3u|\x19D>\x1a\x9eO<\x1e\x8f\xb2\x84Ko\xb2\x1e\xa6N\xd0\xaaM]\xa1<\xba\xf0\xc0\xda\xea@\xbfe\xf3Kd\xab\x10`sn\xca\xe3\xe9\xc1\x03\x12\xa0\xdaq\xf8\x06\x13\xdc\xb4\xa3\xaa\x85;\x1b\x88}\x8b\xcc\xbe&\x17\xad\xd5\xe0\xb8\xb1N\x9b4+\xaeZ\x84\xe1x|N\\)'\xe4pG\xa1M\xde\x00{\x0f\xf4\x0f\xc1\x8d\xeeX\xc4\xf2\xc5MD\x11\xd2\xad\xc4Y]\xb8\x1aD\xec4I\xe5]\xa1\xab\xbe6$\x93\x1d\x90\x18\xb5\xdc\xc9\xb8\\\xeai)\x8f1RcK\xb7VbH0\xa9,\xdb/\x91\x0c\xbe\x80e'\xca\xe2\x1a\x1c\xaf\x039\x8b!\xd6\xa3\x16\xf2*x\x03_W\xcfr\xd9\xd4JJ\xf1\xc9&\xa4[\x03E\x01\xb5f\xd9\x81y\xaec\x0d8.\xf3\xca\x8au\xe2\x01\xd9\xda\xaaC\xb6\x926u/\xe8\xdfl\x7f\xda\xb6Fs*\ne\xb1\xd6\x05\xa8\xf4\xab\xa4\xd7\xd66\xed\x1c\xe9\x05\xb6\xc5d\xa5KA\x08\x02\xbd\xb7~\x02\x9a\x06\x1a\x85\xdc\xa3\xed*I+\x1ee\xcbv=\xaa\xae\xaf]1f\xd3n#\x10a\xb5\xdc2C\xe3-\xea\xa0i\xf5\xd32\xaa\xaa\x82>\xdf\x8ej\x0c\xa2~\x9a\xc7\\\xc1\xb0[(3eb*\xdd\x11H \xa99?,\xbbdl\xa2zZ_(\xfc3u\x05\xcd\xe2\xcd\"M\x9dC\xea\xad\x04\x17f5\xce\xe9\xc9\xf1\xc7\x93\xb3\x8b\x97\xef/\xde\xbd?\xbb\xf8ptzzq\xf6\xe3\xeb\xd3\x8b\xf7\x1f/~}\xff\xe9\xe2\xe7\xd7o\xde\\\xfcpr\xf1\xea\xf5\xc7\x93\x97\xce\xed\xbfi\x08K\xeaR\x11\x15o\xb9\x1e\x0d+\xc0\x85\x1f\x94\xe0q\xa0\xf2\xf2^\x0f\x8e\xdf\"\xb3\x90V\xa4\xf6{\x90\xfa\x15\x9c\xe6\xe2\xc7Z\xad\xae\x88K\xc7\x86\x1d\xc8\xaf\x90[\x10\xe9\x9f\xacq\xd3&\xc5 \xe5)Z\xa6\x1f\x92\x8cl\x8b\x92SiN\x01\xd2\xc8\xad\x9d\xba\x9c}0$Y\xb9:*#\x1c\xe2\xee\xd9\xb8\xe9K\xc2\xd0\xa5\x96\x94\x8b2\xf6\xab\x17,d3\x92!\x01\xc4\x03\xea\xd5\xd7\x99[\xbf\xa8 V\xe4\x10\x0c[\xbc\x80\x98=\xb7X@\x08\x90\xc0PDo2\xca\xdbb\xf7OI\xea\x96\xfa\xef\x03\xf9\xd1\xad\xc9\xb0\x16\xe0\xb7]7\xa9\xe0\xc6\x0c{\xf4\xa4b\x8fn-J4\xf7 .\x0ef\xe1\xb9\xe4~\xfa0>rEv\xb36\x80\xda[\xa1,\x8a\x1b\xa5Y\x90l\x9dl\xda\xed\xe5\"r\xbd\x08\xa6$\xefX\x04\xdf\x96\xe8\xb1s\x1c\x06!\x19X\xe8\x9f\x8a\x037\xd7\x01xg\xa8K\xb6\xd2n\xb7\x14\x87&\x16\xf9e9\x9cm\"\xbf2l[\x8b\x14\x12\xa1\xeaJ\x99oU$\xa7\xbf\xaaN\xcc\xe2\xd5\x0ei\xe1\xbf\xc0\xe7\xa3\xb9\xf7\xec\x02\\\xf5-\xaft5\xcd+\xd7r\xa4\xcf!-U\xee\xeez`nt\xbb\xd0\xbcE\xa0\xf8A\x9aoz\x8b\x90\xf6\xbaE\x08;n\x11\xf4/\xfc\xb8\xdap\xb9j\x81E\xc9\xff\xd8\xad\x9e\x12\xd7y6q \x82\xfe\x1fmRp%\xaf\xbe\x1f\xe1w\xb9\x13\x1c\x159nC\xa1\xf7\xbf\x8b\x9c:\xe8\xbe\x1f\xb1\x9c\xf8\xa6fT+\xc5@\x1b\xe2p\xbb\x187$\x07\x9d\x0ed*\x96QnE\xd7V\xac\x85]\xb1\x16\xaa'n(\xc5 \xa1:F\xc9\x8b\x032\xd1\xf2\xb9=G\xf9~ g;\xe7\x03\xe9\xdc\x16\xe644\xb8r\xa9\xc8K5\xd7\x00\xc2\x9b\xe6\xfc4R\xfa\x1efUq\xbc\x94S\xfc_&w\x0f6\x95\xbb\xab-\x9eK\xc9hZ8m\xec\x10Rv\x8c\xfa\xbfD\xfcH7\x92\xfc%\xf5]\xd7E\x92v\x10\xe3\x92\x9e\xc2\x07Z\xda(F%%\xe2\x96\xfc5\xafH\x9d\x1ar\xab\xa8.\xb7B\xa4o\xcd\x15o\x17\x995+\xac\xc9\xc0\xda\xe6\xf1\xb6D\xdbf3#E\xc9Yi\xc1\x89P2\xea\x82\xdb\x8e\xee\xa1\xafY)\xc5\xd8\x90\xfd\xff\x96\x94\xc5\xee.f\xcf\xe4\n\xf8]\x19\xe4X\xda\xf2l\xaeg\xa3A\x9f*v\xc3\xa85\xfd\x90\xf0\xa1\x9dQ\x04Y\xbfv\x90\xd6\xd6\xec\x14\x1cGgC8;i\xdd`\x99\x0dE-\xc5\xe7\xa4\x06\xa9\xbd\x86\xf28B\x17V\xc7\xaa\xe0bU\xd0\x86\x05q\x04\x12T\xd8\x0fQ}M\xf0\"\x9a\xf6d\xdffg\xa5\x95\xbeg\xaer+h_DR\x1d\xca9;\xf9\xe5\xec\xe2\xf8\xfd\xbb\xb3\x93wg\x16G\xacD]1\xc3\xd0X\xa2 \x8bg\x0e\x07\xb8\xcf\xae\xbb\xbcR\xce\xd5M}\x17\\\xc6{UG\xe7\x19K\xca\xfaP\xb8\xaf\x03\xcc\x1d\xa4m14\xdd\xd8\xfe\x8f_\x07\xa7'g\x17o\x8f>\xfe\xf5\xd3\x87\xff\xb7\nH\xdeq\x1c\xdbVCf\xf8\x16\xbc\x1dIp\xdb/\xd7\xcf\xc9\xea\"\xb4\x8f\x1aG\x14\xb5\xcd\x87v\x9c\x809r6W\x89\x19Wz0\xa5\x92\xa0\xb0\x9f\xcf\xe2\x1c\x84\xab\x97V\xe7wp\x0c\x0d\x0b\x973\xed'\x1f(6\xb5\x83\xf8\xdd \xcbn\x90\xb5\xf5\xe6B?\xb0\xe1=\xa9*\xddZ\x15\x0cC}\xcb{\x9d\xe4\x00Qc\xb3\"\xeav3\x99y=\xe8\x02\xf1,\x04E8\xf3z\xa8oIU\xad\x059$\xee\x1c\xa4\xb9su\xe4\x97\xc1cVC\xb2\x1eB$\x9e\xc1@\x86\xe3yK\xb3\xe5xE\xaf\xdd\x95y\xc0\x0b\x80!Y\xd5\xce\xfc\x18|\xf1\xad\x80\xb1h/\xabB:\x95M\xb8(\x11\xe8\x91\x04s\x17CBg\xcbs\xdd\xa2L\xd9B-\xb7\xb7\x07C\x12\x0b\xf2b\xad\xf9|\xed\x81\xc7E\x9c\x7f\x98\x8f]\x7f\xab\x9c`>h\x1a\x03zR\xbaUk\xb2\x89\xf5]\x980\xc2g\xde\xf9\xa0\xcdm>\xf8?\xd2\xe8}^\xfa\x0fi\xd2\xb5\xcdK\x17\x82\xf6\x00\xc3\x7f\x91\x95\\o=\x087<\x05\x9b\xe7^f\xfah\xb5\x84\x9c\xec\xd3\x81bA\xf6vLF\n7\x05\xe6\x92|!\x80\xeb\x96y\x1d\xa8\x98\x94\xf4g\xfb\x9eU'\xef\xdb\xf7?\x9d\\\x9c\xfc\xf2\xfa\xf4\xec\xf5\xbb\xffl9|\x89y\x00w#?\xe3\x1c\xae\xf4\xa9\xbb\x94{\xcd\xae\x11\xaf\xac\xc7E\n\xb1L\xed}\xcd\xeb\xc7\x13\xd8\xc3\xef\xde\xbf<\xe9;\xab\xdd\xe3\x7f\xd7\xfd\xdbB\xa2\x93\xfeT5\xe9IY\x93\x8em\xdbkV\x9bg\xf8-$a\x85\xc5w\x95\xb4H\xd4\xa9b\xe0\x05Qe\xd4\xbbm\xe6Q\xd5s\xcd\xe9\x0b<\xf8\xb0\x19b\x8f\xe1w\xf0\xc4\xde\xfcH\xbaBl\xb6\xf4O\xf8\x9bEt\xedA\xea\xadD\xd7\xa5\x9b'\xd4\xd6W\xb9\x17\xa8\xfb\xe1 \x86\xa7\xae\xfa-8)\xa5\xdb\xbb\xbb{ \x97\xde\xdd\xdd\xad\x0b\xb4\x89\xa1x\xb6_\x1b\xb4\xdau91\x85\xccy\xc7\x81\xbfV\xb6\x1b\x86\x17&\xd60Z$\xe6} \xa8\x89H\xa1\xb7\xb4\xb3\xe7\x82^i*\x89U\xc7FV\xbfu\xa0*x\x0fN \x11\x15\x0f\x81=.N\xde\xfd4%N\x9cp?\x87^ \xe8\xe4\xe7\x93\x1f>\x1c\x1d\xff\xf5\xe2\xf5\xbb7\xaf\xdf\x9d\\\x9c\x9e\xfd\xfa\xe6\xe4tJ\xb6&\xd5F\xd4FJ\x8b\x0b\x9b\xdfE\xa4\xd8\x1b\x13M\xfa\x8e\x8a\x0dL\xb5\x80v\xb9j\xdd0\\?Z\xbc.>\x9d\xcb@\x01\x1b\x88\xf1\xda\xba@\xa1\xc2\x14\xa2U{\xe0k\xd7\xde#\xf0\xe9\xd1y#+\xf8\x9c\x0e\x9e/n\xf1\xbd\xa4\x1f\xd4\xba6\xee\xcd\xf3 \x06\x15\xd8%\xb8\xd8b\xb3\xf8\x1c\xb8\x0d\xbf~G\xda\x8f\x1d\\\x83\xf5n_k\x1e\xbd9@?(p\x97C\xb2\x1e\x0cH2\xae\x07Sq}`\xc3\xf2!\xf8b\xca\xa4\x1f\xa2\x96\xb1\xd3O\x0f\xbfJ\xfa\x91*JTV\x9dT\xa8W\x1f\xdc.\xd4\xbd\xa2\x8a6mM\xfa\xc4(#\x06w\xcd\xdd5l\xfa~\xa5TOW\xfd\xa0\xc57\x16\xd0\xfaZKW\xf5\xa5\xdb\xaf\xbeH\x8a\xcf;\x98Z\xd2\xca\xd8\xb6\xe7\x96k\x9c\x0d\xc8V\xc3\xc7[\x0cV&\x80\xf8\x90\x05.\xcd\xf5\xc1[[|.\x98\xf5\x8d\xa7\x0em\xd7]Y\xdc\x96\x13\xbdj(o\xf1vG\x88\xc5\xe3]\xd4\xb9\xa55r\xc4O\"\xf3A\xc6\x84\xa3\xb4\x8c~\x90Q\xa9\xa4\xd4\xd0\xb1I5\x94\x17|_\x07\xca\xb5\x8c8\xac\x1f?V\x13p+z\xa2\xf3*\xdc\xa2d\xd7PV\xa7\x96\x8bs\xa5dW\xf7\x89\x99*U\xbd\xba#\x80P\xb5\xa5\x9e\xeeU|h\xee=y\\'P\xe68\xe5\x13\xcb\xfa\x1a>9}Y\xdf\xbe\xa2w&\xf5\xea\x96\xaa;\xf5v\xacK%\xfbzO\x05Z\xaa9\xce\x14Xd\x17\xbb\xd2\x07\xc7T\x7f`\xb7\xf2\x97\xe8\xca/\x15H\xcb\xe5rS:\x7fU\xd1 M\xdf\x15\x18u\xc8\xc8\x01 \xc5\xbe\x96:\x89xX\xe8\xc6\x02\x85\xbb\x0b\xe9\x94Z\xaa\xf7(\x12^*\x97Wbf\xd5c\x0d(*B\xf5\xa9\xa2\xb5_]\x82\x17\xcd\xb1\xbbB\xe9$\x8fGi\x96\xe4^\xaf\xebALM\xcb\x88\xf3eq\xf7\xeb\x89\xad\x9c\x06\x19;\xbb\x89YA\xf4\xcb\xbc@i\xc6\xd4\x92\x8d\xd0\x8f\xcd\x8c\xca%l-_\x0e\xdb\x0f4\xf3\x96\xd2\xffZ-?f\x91\x1fD\x8b\xb2\xedH&h\xd6\x80\x03#<\xff\xa3\xf4\xb9\xa5\x15\xeb\xb6&\xb5\xfcW<\xf1\x98\xbc-\xa8dk\xc1\x9f\x18!d(\n\xb9\xa0\xc6|\xb5|\xb5>j\xa9\x80,\xdf'r\xb1\x16C\x9e)\xafOJi \xef\xc71\x0d\xc3K\xea}N\xeb\x1f\xa2ah4\xe3\xe7 \x0c?I\xa4\x0c\xddi\xac\x0c\xabZD[\xe46\xab%z\xbd\xb3\x1c\xed\xe9\xc5\xf66\xbaV\xb2\xd6\x85b'\xdd\xe9\xd0\xb8\xf3\xe9\xaf\x83G\x14\xe6U\xe3\xaa\x14}\n+\x11{!\xcf\xf61\x1ce\xe8g\x0eJ\x82\x0b\x96\xc9\xe5%\xbdl\xb5|\xc6o\xf5\xbeS\x7f\x14v\xd9r\xb7X\x89\n\xc1\xfa\xd8x\x1f\x07)\x04\xbe*f\xb7\xe5lv\xbd\x96\xb6-\xcb!\xd08\xa8B\x08I\xca\xd0F\x13\xfafD\x86%1LV\x97\x1ay\x1f\xf6\xf2eF6\xe8\xf8\x87\x9d\xe9\xb3tl\xb2\xeb\xb6N\x05\xd2\xb8!\x91\x1e\x06b\x1eD\x99-\xa0\x07\xee\xaa^?E\xd4Vl\xa5V\x9b\x83#f\xed\xda>o=\x0e\xc6 \x97\xa4\x91K\x07u\x1c\x86\xee=7o\xd9\xf9\xa0\x96]\xadC#\xa7\n\xdd\xf0\xc1(Y/`2\ne\xaa\xc2\xc2\x83\x016\xbeV\xba\xb2\xc9bo\xed\x808\xa2\xd2\xeb;\x0fu\xdbZ\x0dn\xb9\x1ao\xb5\xf8\x8aq\xd6\xe3f\xa7IZ4_\x83\x12\x83 \x8a\xb8@|.\x96\xe1v,\x87\xa0\xc7\n\x08\xf4\xa4\x07\xe5<\x0f\x86\x15\xc1~\xa1\xaan\xce4\x90\x0543&\xdc\xb5 \x03\xd7\xca\xe5\xbd'\x90\xb78\xecQ\xcf\x18\xa4\xa1flp0H0,b\x08\xe6\xcd\x81\x07a|\x95|\x02i8\xdc\"x\xe3\x93\xb7\x1f\xce~m\xbf>\xb2,hI\x85\xcc\x11\x15\xdeD/\x92*\x81\xbe\x0cB\xdf\xa0\xd2\xb1(\xde\xc8z\xec\x1f\xd2\x8a\x187\xb3\x15\xb1\x9f\xa5\x03\xbd>\xbfi\xf4+\xa2E\xf0\x96ov\\\x02d\x8dmc\x97\xdcII\xbf\x87q\x8c\x0f\x1e\x90\xad\xac\x8d\xa7\xecs\x87\xd0\xc1\x92\xee\x0c\xdb\xef4\xf4S\xb9\xb8, \xbam\xe2\xa0mw\x07\x1d\x01\x05\x08\xe8w\x07\xd1\x9a\x7ff\xff\x99\xd3\xc4g\xbe\xe6\xa9A\x05\x00\xadU\x9a\x93e-!E )\xac\xd6\xf1*\xda\x82a\xd9\xb6\x08\xe8i51\xbf\x05\x1c\xd3W\xba\xa5\xd8\xa2&\xe1\xf9\xf6\x14r%\xdb&\xe3h\x95\x03\xe1\x92\x16\\\xb8e\x93\xb4\x84:p\x99\x8dE\xec\xb3\xe5/V4\xfd\xac\x10U\x9f\xed\xben3\xa7\x04\x1eVuM\xcc\xa3%\xec\x07\xf8\xdb-C \xc4v\xfc\x8e\xf9\xc1\xd6O5~N6 \xd1,9o\x0d`c\xf5\x14\x87\x8dKU\xd2\xb2\xf9\xd0\x18\xe3j=\xf2\xf4\x99\xb3Q\x83\x8c\x93\xa5w\xabL=\xfb\x8d\xa4AM\xca\xc6>\xa5\x81t3[6\x8f\xe8\xe8\x0c\x8d\x1c\x19\xa8\xa1\x0d\xa1VC\xf0 \\\xb5\xf2rpl\xac\xb6\x82\xa5~\xba9K=\x90\x1f\xc2j\xd5B\x8f\xfd\xcdj\x15g\xbe\x1d\x89\x96.w\xbf\x02\xdf\xdb{\x0f\x13\x83\x1d\xeb\xb5n\x80`7;\xd4_\xab\x0f\xf3\x81\xd1H\xaa_X\xf7\xaf~]Q\xbd\xef{\xe5\xceM\xa1\x9e\xe8T\x1b9\xd9\x86\x84\x95\xdeCyP\x011\xc7@I\xaa\x9f\xaa\xa4b\x1f\xe4\xd9\xf0z\xfe\x8e\x89\x0dJ\x93\x9b>\xfb\xb2P\x8e\xc1\xdayH\xe6ME\x80\xcc\xb0\x14\xab\xc2\x0f\xcb\xfb\x11M\xc7\x97\xce\xa8\x0f\xac\xa7\xe1\x97/\xf6\x83\xee\x10\x1f\xa3\xf2;\xd5\xd9jO\xad\\;\x99M\x94 \xb6\x1b\x95>SPk z\x0f\xd0a\xfdI{\xe2\xb8\xc8\xf4\x97 0\xc2\xde\xa6\xa2\xbb\x16\x16i\x08\xbc\xcc\xd6\xa4m1\x17D\xc3\x81\x0c\xd2\x9b\x83\x11\xb8N\x9dJ\xd7[jF\xab\xf7\x04\xc1@\xd5o\xd3\xbeX+\xc7&\x9dW\x11\x10\xe2\xd8\xe6\x1d\x88\xc0\xd5#X\xe5\x03\xeeW\x9f\x1cJ\x17\x98\xb4Ji~\x94\xeb\x1b\xbc\xa6td\xbb\x9e=\xa6\xd9Z\x07\xfe7\xfb]\xe1r\xa1\xb0\xbdGq\x8bw(\xeb\xf6\x80\xf8h\xe3t\xc9\xf3\xb0$K\x8b\xad\x13\xc3\xc4\xa0\xb9\xa25\xf3\xa1\x8c\x82\xacg\xb5\"\n?8 \xd2\x8c\x03\xda\xe5\xbb\xe1\x90x\xb0\xac\xb6|\xf1E\xd1\xa3!\x99\x03\x9f\xde\xbe{\x86$&\x87\x9a7\xeb$e\x01\x91\xd5\xdb\x1aI\x9d\x19\xb8(ab\x17\x81\x95 \xb6\xd5\xc57\x9b\xb4m0$\xb4\x10\xea{\xe2E\xcb$\xe6Cc\xe5\x1e`\xa6=-$\x909\xbb=\xd5O*|Y\x0f)My,5\xd0f\x1fb \xe1,\xect\x93\xb5\x08\xc6m \xcc\xccVii\x11\xb5]dHGo\x0f\x1e\x90\x89r\xa4+\x1d\xc6\x14\x85\x93\xd9\x8e\x85p6\x88\xb1\x03E\xb2\x08\xfc#\n\x88sF~T\xb9\x84\x13\x19\x132%;\xcfI^\xf1\xee\x96\xb7\xfb\xc5^\x1bf\xd9v\xb2\x89\xbbtH\x1c=\xe5\xa6'\xc2\x94\x1c\x92T\xea\xd8H\x8dE\xb9\x1c\xa6$\xbd\x05e\x85\xf8\xbf\xc1\x96#\xbakn\xa1y\xad\xaf\x87\x87\xda\x13A\xdfe*\xb0\xf1\x0f2d\x9b\x1bV\xee?d[,8\xd3#\xda\xe3O\xa8%\x809\xbc(\xf4\x02\xbe:\n\x91\xe0\x90\x845\x19\x81D \xe07\x0b\xc9(\xee\x03p\xaa\xc0\xd4\xe6\xa8\xa0\x8a\xb0@\x15\xd9P\xb7E\xe2\x95\xd0@\x15I\x15\xef}\xac\xcb\x06\\\x18\xe8\xa1\xec#o\xbf2\xc2\x86L\nO\xc2B\xe9Ut\xbf\x1fv\xb24\xe8V\x18\xaa).iEU\xd1m\xc8g\xbb,\xb7\x1d\xc5\xd9\xa4\xd7s\xe2.]\x10\x95\x0f0\xf2URb\xacMP\x9a\xd9\xa4\xc8\x1d\xca\xac\x1a5U%\xa16{Y\xf1 r\xaah\x88\xbb@\xd7OS\x92\x8d\xb9\xdb\xd6Ou\x1a\xbb\xa5\xd9d\x03\x896\xef'\xd1&-\xb2\xba\xd6\x90\xac\x9a\x18\xc4\xc4\xdd\xc5\xfc\x95:1fJ\xcd{E\xdbT\x8bm\xda\xddp8\x0d\xc5\xf0\xfd\x1cdK\xe9]@\x1c\x01!\xca\xa2\x91\xdeR/\xb4\xe2\xfe\x9c+\x1d\xe3-c\x1b\xd8\xd9Y\xf7\x9fy\xb9\xfb>i\x8az\xda0\x08\xeb\xc9\xcb\x14\xc62\xb2\x11\xee\xddZ\xdc\xb7q]4P\x95\x14\x16+|\xd1F2\xe4c\x85\xf4T\xa7[VS\xeb\x95\xafx\xba\xaf\xb8\xd0iA\x06N?_\xc9<\x88h\x18v}\xd9\xec\x05\xca\xf5\xea\xa7\xd5\xf9\xec\xad\xdb\xdf.*\xd5\xdaA\xcc\xd0\x0eb\xa8v\x10+\xb5\x83\x9em\xc8\x16\x0f\xfbI\xb2h\x96Qo\xf9\x91\xcdos\xa2.X\xf6!\xbf\x0c\x03\xafp\x94f\xe9\xb9\xe6\xf2#\xcd\xe5Ov\xda\x18w\x194\xa7w\xedn\xa4\x14\x99\x0e\x0e\x80=\xd3\xaf\xe4\x8f\xaf@I\x8b\xb7\x81\x0c\x04\xd7\xcbv\xc7g\xc8\x98\xd8\x06D\x05\xd5\xb3\x8d\x07||\xc6\xce\xfb|W\xcdl\xdf\x8d\x7f;\xe1s\xf3~\x10\xcc!*)\xe3B9\x86[\xdcQ\x15\xa8\xae\xa6\xae\xa6l+j\xa9\xacPbS\xf9\xfa\xb5\xaf@\xaa1\xb0\x1b\x8fQ/\xcc\x8d!L\xedc\x02\x96\xf0\xb4\xdf\xa6\xb2\x93\x19\x88\xcd\xaa\xc56R*X\xdd\xc9\x96a\x82\xd7l\x1d9\xcd\xb2no\x17\xc9_\xef\xde\n\x94\xb1<\xbdY]rp\xc7*\x7f\x8d\x057\\ys\x9dD\x8c\xdc\x98\xc9U\xed\x00\xba{\xb23\xd9\xd9\xc3{\x95\xfc\xb3Z*\xa3s\xf2\xa4:\xed\xe0W\xf3\x7f\xffo\x9dy\xeb8\xcc*\x04\x0c\xa8\xe6\xcd\x92s\xd8=3~^\xc3|\xe0\xb3\x1dkmy\x01X\x0f\x0cp\xab\x91i\xb1\xb2\x95V\xb2\xcf\x1b\x9d\x90F4\x9b\x19\xc7\xf2\x0e%;0_\x12CR\\Y\x19\xc1\x12\xda\xf6?\x18/\xb53^\x86^\x0e\xb7\x9a9\xed\x0c\xa5\xa9md\x1a\xdf\xba\\\xda\xddvG\xb8\xaa\x0e\xd2\xbf\xca\x04\xd7\x16\xdc\xd5r\xda\xe3\x96\xb4\x08\x02m\xbbS\xd6(\xc5\xd57@-\x8e\xd3\xbf\x891\x17\x1eb\xe4I\xdd3\xba\x0e1\xf2\x14\xb1\xe6*\xcd\xad\xf6'\x0d\x07\xa79x\xa4\xaa~\xbai\xd9\xacd#\xd5S\xabb\x1e_\xfc.6E\xd8D\x12p>%L9\x8f\x0d~g\x10\xef\x97\xaa\x1a\x87:_\x90\xaag\xfc4\xa3Y\xe0I\x1e\xca\x10\x0f\xe5);6\xa3\x19\x9b\xf2\xd0\xbc\xb4NP\xea\xe5\xb4\xd5k{\xd3\xdd\xa9\xe0\xe2\xcb6)\xe5\x8a\xb4\xe3\xb4V\x8b\xa4\xea!\xa8v\xac6EN\xfd*M;*5\x0c2\xfaUX\x1f\xa8\xb6\xfa}\xa6\xa9\xa8\xda\xccW\xc1J\xed\xcfV0\xad\xe6\xd9\xb2\x8a\nP7,\x0d \xc03\xaa7\x18\x12>\xa6\xbe\xff\x81\xf30\x88\x16g\xdc\x0dk\x18\xe1^\x1c \xef\xee>2\x10\xbfD\xfa&\x14o#@\x8a\xb5\xcf\x9a\xe7\x0d\xa9\xc5\xb8o\xe1Q@\x15\xc6eD\xd3|p.\x0eH\xb6L\xf8\x15\xacjA\xd8I\xfd_\xe7\x98F\x11\xcf\x88\xc0<\x84\x12/\xa4iJhJh\xf1%\x07\xc1\xee\xea\xd6\xb8\xd0\xb5\xca\xca%/\xce\x83\xea\x92\xa8\xce\xa1\xa6\x9bM\xf3\x14X\xd3\xac\xdb\xe6G\x9b\xbb\xd4\x10\xfb\xb0R\x9dB5Z\x81\xaa\x8e\xe9-\xf2\x97z7\xc6A\xfa:\xaa`\x17\xe0\xdc\xea\xb5\xe3\xb2\x19\xbcE\xd5k\xb2\xf6\x9en\xd8\x1c\xa3\xea\xba\xc3w\xbc-\xb5\x0b\xa1\xceU\xb5a{\xcc\xea\xdd\xa6\x1e\n\xde\xa6S\x96}\xab\xf6\xe8\xaa-m)1\x88\xc9a\x9b\xa8\x81\xdf\x07j\xb0\x9c\xc5\xfb\xb6\xb3\x189\x8a{\xac\x1a\xe4\x0e\xb5f\x87\xfa\x8e\xfbu\xa5\xc5[\xdb\xad\xfa|%\xf5\n\xab\x83jbbjb\xe2j\xa3\xbb\xcd-\xad\xbeb\xa8\xbc\xa0\x08\xfcc@\x1e\xc9\xf6v\x93\xf8\xaa6\x91\xa2\x9d\xdd\xd4\xf0R\x0b\xec\x1d\x02\xec\xd9\x88\xad\xe2\xecfJ B\xa5\xf1\xb9m\xe2\x10D\x0bW\xfa!\xa8\x93 m\x14|*\xfb\xc9\xaf\"\x96\xbc\xe4^\x0e\x12\x0e\xe55\x89\xaf@HfSb\xd06\x0b\xe38a\x1e\xf5\x96\xacP\xe5\x967P\xdcEn1\x9b\xf2\xc0\x9aT\xb7FX\x1d\xca0^\xceo\xd7{\xde\xd6h$\xc6!\x17\xbd\x1f\x8d~\xbb\xdecNm\xaf\xd5\xce\x02\xab\x8eW\xf3\xf0\xef\xaf\xc4^t\xdb\x1a\x04\xba\xadQ-\xda\xea(\x930\xce\xa3\xea\xd8\xd6j/qK\x8d\xda\xa0\xf7\x82R&\x15b\x03\x0f\x1b\xc0Q4\xea\x14\xb8\xc0\x01\xe7\x19J\xd0\xba\x07\xd1]j\x99\x99\x91Y]k\x86\x07\x0eP.\x06\x86\xf39\xe1\xcfI3\x80\x1d\x89\xea\x9b\xb4\x12\xb5{G\x1a\x03e\xcf }\x0e\xbfh\xb5t\x80\x96~N\"2\"\x01\xf9\x9e\xec<\x1f\x80\xbc\x8bU\xaf\x91\xa2\xd1\x08-\x16\x90\x11\x89T1@\x04\xd5b\x01ZL\xef\xfe\xe89\xc9G\xa3\xe7v^\x1dB\x02\xb71\x8dHK\x1b\xad\xb0\xac$R\x15\xa5\xff\xa9 a\xae\xb3j\x0b\x83\xf4(\xf2XZ\xa5\xc8m\xa7\xacm\x89$\xc9lr\xbe\x89\x96W\xdb\xdc\xf5gIk\xea\n\x06\xea\xb5\x88\x08\xda8\x07i\xe8\x88\xec\x0e\xbcS\x05\xd1\x01*\xf1v\xa6x\x1c\xb1\xeb\xec4\xb8\x0c\x83h\xf1\xdcJ\xa7\x93\xda\xc5X\xa6\x14Z\x9e\x14\xd6q\x12\xe9\x0e\x86d_2A\xe3H\xab)>x@j\xf8\xcc\x80\x90\x11\x0d[\xbeJ\xcaE\\\xc7 \x16c-\xfd\xb4G\xe0\xb6;\xd3\x94\x04\x981,=\x17\x8d\x9e:A\xe1U\x0fx\x1c\xab\x9d[\xcedVWa\xba\x9b\xa8\xe2vD\x81\xc0\xd0\xb7\x15q\xdc\xcb\x85\x8aEj\xfa\x08'\x07\xf1\x1bL\x19h\xb1:x\x16\xef\xcb\xfafqJh\xf3\xb0\x15\x83\xd7\xb5\xd7 (\x02\x07)\xd8\xce\x04\xd1B\x85M\xb4\xb8\xa0k\x9b_Qfv\xdb6\xf2\xf1<\xcc\xd3%\xb4\x82)-\xf4T\xaa\xa1\xf3\x86\x04Gv%+\xbb!e0\xc9`\x08\x85A\x17m\xee\xd6<\x91}%W\xcb d\xc4\xadKT\x8cX\x82 \x97\xe1\xe4E\xa5n-b\xe1 \xa1\x81\xc5Qd\xce\xf8\xf9\x90,\xc7\xcaC\xd7\x99\x9a\x03\x97U\xa6C:\xb53\x87j\xd8\x18;\x1c\x17\xc7v.\xde\xa6\xa9\xd1\x18&lu\x18$Du\x81\x18\x19\xf5\x01h\xde\x19\x96M\x06n\xb1\xa2\xaa!\xf8\xc5qv\xc5\x8f\x92\x05\xf0\xb5\"\xa7\xe2dx\xad\x1c\xefW\x1b|\xc1\"z\x192\x7f*0d5\xa7:\xc4X\xdc\x95\x9f_\xbf{\xf9\xfe\xe7\x8b\x1f\x8f\xde\xbd|s2%\xc1\xd8\xa3\xd1\xa7\x94\xbd|\xff\x96\x1c\x92\xab \xf2\xf9\x15\xc1\xca\xa5,\xfb\xb1Vy\xbb\xe4\xa81\xe1bQT\xc7\xa6\xf1\x85\x13\xdd\xb1\xce\xaa\xd5\x10\x88Sb\xab\xb5\xd6 mV\xdar\xfc\x96U\xb7U\x9a%4\xfeAJ\x1faQ\xf4\x13V\xeb\xdb\x0drH\xf8X\x06\xf0W\xb1\x89\x96\xa0Z-\x0e@\xa8N\x124r\x99\xb1\x81\x16\xd7v5\xe8X\x892o\xdb\"%\n\xbd\xaf&\xadx\x14d<9\xf5\x12\x1e\xca\x88\xe8]\xd3\xaaQf;\x94x\x98\xeb\xb9r\xad\"\x8e\x9b\xbeV\xdb\xda$<\x8a\xc1\x97U\x0c\x89\x93B#\x1dD\x8d\xa2\x8aN\xcc\x11\xe9)\xd3(\x17T\x1b\xd1$0f\x0c\x86\x06\x02\x05\xb4\xc6\xeei\xb7\xcfI\xc7U\"\xce\xf5\xedr\x81\x1eF7\xf18a!\xa3)so+\\(\xde,$\xd7\x12RoEr\xf5S\xc1.\xc4`?K\xe4\x067\x1d\x86\x0eY\x91q\x88\x8c\x03\xc4\xc5\x8a\xe9\x82\xfd\xf2~>O\x99\x0c\xd82\xf6\xb5\xc6\x82\xfe\xa1m4\xe4:z\xc3\xe6\x88\x00\xf5FW\xf5\xeb\x06U\x9d\xf1\xaaX\xf0+\xc1\x82\xceC+;\xbfm\xa9\xf1O\xd5_\xb7\x9a\x89\x92\xf8\xdd\xaf3\xaa\xea\x9acb!~\x1b\xd7\"\xed\x81\x16\xf6\x9e\xe0\x91\x16&\x8f\xeb\xf5\x84\n\xbe\xde\x1e\x0f\xa7\x97q\xbe\xc9\x10B\xd0q\x10\xfd7\x83qi\x8e\xef\xcb\xf7ou\xfc\x8d)I\xda OVqvcT\x9b\xb7\x02\x0b<\xf3!\xcc\x17A\xf4c~)\xb8\xdf~\xc0\x9f\xb2 L\xc5\xd9\xde\x05~\xb2\n\xb2\x8c%S\xf0\x9bg\x05\xfd\x11t\x88\x8a&\x87m\xb0\x05\xef\xe8\x95P\xd5\xf5\xf6/\xe0\xbc\x1e\xd7\x99\xa6\x00g\xb1\xa8e-\xa9\xb5\xf7\xb4\x9e\x9eV\xd4\xc8'\x8f\x9e\xd6\xd5\xc8\x15\x17\xb6[\xff\xbe\xd7-\x03\x01\x8e\xe0\x94\x85r\x08_G\x82\xd9\xa5\xf8\x98+\xd9H>N\x80\x16eE\xa9\xea\xc0c\xf1\xb9\xcd/v\xca\x7f\xb4\xbc\x97\x8e\x0b\xa2\xaa\xc3&\x92\x8eK\xa2\xce\x85X\xe3\xbd\x0c\xad\xea\x02)+\x1dP\xa9\x1f \x94S\x17D\xddu\x04\x94\xa4\xa8\xa2\xb0.F\x9da\xc6\xad=:\xb6\xd1w\"\x9e\x05\xf3\x9b\xa30\xc4\xbeU\xed(*\xf8B\x98\xfbv\xc9W\xbb\xe5Aa^Pk'\xa8Q\x94\x94Ldx\x99D\x8c\x14\x0c-\xd5\xca\x86\x8e\xef\xd5\x06\xc1\xab\xad\x83z\xc5\xb7\xb2A\xc0:\xdf\xf1\x9d\x8d\xcd\x12Z)l\x9b\x81\xc1&\x0d\xae\xf8\xa8n\xfb\x18b\xa6`W\x18hl\x11\xed\xca\xba\xa1\xc6]y\xed\xcd\xae\xf3\x82,\xc5>7\xb0.\xcc&\xcfR.\xbf\x12\x91%\xee\xdc\x14)\xa4C\x12\x0f\x86$\xa8\xf2\xee\xf3\xba\xe1\x15\x14\xbf\xe3\x01\xd6\x90\x05*]\xea\xddz\xdc\xa7@\x1dl{\xa8\x18\x8f\xb6h)\x94\xd78\xdap[*\xa8%\x96\x8d\x98KO\xe6\x85\x90\xe0\xc1\x03\xe2\xa4\xfa\x80\x01\x85/M\xb9\x8a\xac-\xd71\x8f-\xc8W\x8cZ\xf3\xe8l\xce\xeb\x82e\x928N\xa7$'\x87=N\x00\xcd3\x16tt\xd16u}\xff\x91F\x8b\xd6\xa0,`\xdb1\xce\xd8u\xa6d8vP\xb8\xb3\x1d\xfby\x1c\x06\x1e\xcd\xac\xd7\xb5 \x84\xaa?\xe3\n\xcb\x9dI\xb7\xa6C\x92\xc8\xd3\xca\xff\x00\xbb\xcd9\x89|@\xaaI\xe6\xd8\xb9=-rK\xcc\x16\xb6\x9e\xb9-\xbc\xa1\xf8VC\xed\xcf|X\xe4OA\x03\xa5\xe9\xf7\x95\xe0\xcc\x1e\xe9\xc2\x07\xc4\x98$\xb9\x12*\x84\x8dX4H\xb2mh\xe5-\xb1`\x9dv\xd4-k\"\xe6\x174mz\x86\x05\x95\xf3M#o\xc9!\xdep\xd7tKH\xb9,\xed\xb0\xd2\xb7\xc1\x9c{y\xda^iP\x02v\xd5\x99k\x7f \xb0\x86\x8f2\xd7\xe6\x91\xb0]$\x90\x8fa\xe2\x0b+\x80\xe2\xeazH\xf21\x8b\xfcf\x06>\xf9:XC\x9f\xd8=\xa8\x07\x00\x82.!b\x98\x04P\xb723\xf5\xd1\xaf\x8cpu\x14\x07\xe4\x90\xec\x10A\x04g\xfc\x14\xd40\xdcA\xe7~\x0eA\xf2\xee\x85<\xd2h\x02\x1f\xdfPa\x15\xf1]p\x06\x12e)\xec\xe8P\xedh\xb7>\xc6C=\xea\xaau\xf6\xe5\xe8)\x0d\xa7z\xf9\xd0,/^\xcd\x99R\xef\xd5\xae\x87\x9bt]\xf0\xbb\x1e\xd9&-\xee+c\x13\xadV\x90)\xde\x9bX\x0c\x06\xe03W\xb94\x8b\xf5\xf0p\xbb\x03#\xad\xd2\x14\x8f=\x1e\x864N\x99%`k_\xf4\xe6\x8bs\x83L\x89\xd7\x81\xe6\x04\x9c'\xd0W\xcfu\x8a\x90\xf3\xa9\xf5\xb8\xear\xb52\xd4\n\xcb]\xe7V\xf7icX\xbagbQ\x90CIL\x00\xf2\x801!\xd3\xe2\xd7\xf7\x05\x8c+\x01X\xe4\x0f\x15\xa2\x03\x08\xf0Zi\x94\xd5\x99,\xf2\xc1\xd4\x14?\xd9d\xba\x9c{\xc7[\xd2\x84z\x19K\x1ci\x19\xce[\x8e=^\x14\x16\xcb\xa4R4!\xa3\xa2\xb8\x18\x1a\x8c\xeb!=\x84\xb0D\x1d\x1b\xc8)\xd3\x86\xc8\xf4Q\x81\x1eN\xf6\xa5E\xd4\xb9\xc1f\x81;8\xef\xdc\x86DI\x1d\xde\xd2l9^\x05\x91[\x0e{\xc7G\xf2\xaa\x93\x03=\xad\x94L\xcd\xca\xe4\xf4\xb6\xa9\x95\x89\x035\x1a\xb3\xebL\x94\x7f\xf0\x80P\xf2=i\x0d\xc7C\x0c|\xdd\xe2\xa0\x8d\xa86Ri\xff\x92Z\x01\xed\x9aJZ9\x15\xb4\xd6i\xc7xx\x1a\xd0f7FTo\xc1\xe9\x87\xd7\xa7\x87\xf3\x0d\x11\xa0~\xe6%\"\x0c\xe1L\x15\xe8\x9aK\\=\x04\xc7Eb\xc1\x1f\x85!\xd4\x96\xba\x10/\xe8{\xc0 n$\xb8\x0c\xf9\x959\x00\xcb\x99q=U\x91\xa7+\x82\x8d:\xd7\x08\xb6\x91-\x8a\x1a5\xe1\xc2{b\x1d\xfeN\xb1>.\xc5\x93\xb3\xbc\x11\x13T$\x17\xdcKbWB\x00\xe1\xfdx\x1e$\xa9t\x91_(\"\x18I\x95\x82\x9a\xdb)\x12\xb1\xdb{n\xff\xa0\xdd\x16\xca\xd4\xa0+\xf5\x1a+\xea\x86\x8d\x82\xb2\xad\xa5\xeaCuH\xff\xd4\xfc\xd5\xdb\xb3G\xc5`-\x01\x9cl\x18\x9f\xed<'\x91\xb5'{\x92\x13,\x88\xbf6\x1cJ\xc1i\xed6\x89\x80\x1bQ\xa4\x90Fr$ /\x94\xea$%\xdf\x9b\x86b\xf6\xad\x16\x81\x96)\"\xd3\xd4\x8f\\\xceS\x92\x91\x11\x12\xa6\x8a\x90FHi\xfd\x04\x851b\x05\xb8\x91\"\x07\x8c\xbb\xd1\xe0\x9b\x9a\x7f\xec\xef\xedX\x8c\xb0\x8be(\xd5\x9c,\xfc\xfa\x96b{\xb6\"\xb0\x01WVe\x11$%n&\x13\x137\x1a\x14\xfaR\xc6:\x13\xb8\xc2\xf1$\xf1\x98*\xbb\xb6C\x88f#\x93D\xb1)\xd9\xda\x92\xf1mhR(\xda\x7f\xe0i\xa0\xb9\xb4\xad-w\xf2\x84< V 1\x84\x0d\x15\x8d;\x0f\xdb\xa4c\xd8\xac\x17~\x80F\x1e< {\xe0\xe9\xa6\xc9\xdb\xdc\xa1}\xfd\xda\xa1\xb9^\x97\x899\x19W\xec+\xe0\xf2\x8fL\x8b\xe3e0\xf6\xd9\x9c\xe6a\xf6S\xc0\xaeD\xa6$;Pd\xb6\xe5nI\x17\x83\x16_Qc0\xba9\xac\xder\xaa\xd4)\xeak \x84:\x118D\xaf\xa4W\x95\x9c\xa5v{\x13\xe0\x1d]\xb1\xfb\x9dwg\x99e\xf1\xf4\xe1\xc3\xab\xab\xab\xf1\xd5\xde\x98'\x8b\x87\x93g\xcf\x9e=\xbc\x0e\x83\xe8\xb3\xd3\x94\x90!\xf0\xbf\xbc}#\xca\xec?\x8c\xe8\x8a\xa51\xf5\x98\xd3\x94\xa05\xf1\x12\xf5<\x16e?\xb2`\xb1\xcc\xa6\xc4\x91\xaf\xa3%\xbc#>\x9a\xa8\xe7\xe5\xab<\x04O\xd6;H\xb6\xef\x07Y\xb0\xb6d\x86\xc1\"\x12s\xff\x03MY\x18DL|O\xa7\x8d.U\"\xf6\xd10\xe4W\x1f\x19O|\x96@\x99\xf2\x15\x85\x8e\x97\xf4\x92e\x81\x87\xb7b\x15\x87A\x96\xfb\x966&\xf42\xf0^\xf1d%>\x04/\xa39OV\xd8wR\x0fn\x07\xb1Z\xb2, .\xf3\x8cI7\x88N\xe5\x1d\xabJ\xe7\x8b\xa5g\xc2\x8bw\x0c>\xcf\xf8G\x06\xc6\x92\x02\xba|\xc3`\x7f\x0fVy\xb6D\xdb)\xc6\xfcU\xc2\xfe\x91\xb3\xc8\xbb\x99\x12\xa7\xf2\x8e\xd4%\xf2?$|\x1e\x84LA\xab7\x0b\xac\x98\xcf\xd3e0\xcf\x14\xb4x\x1f\xa5\"\x01+p\xc9\xaf\xf1V\xb2E\x10\xe19\x01M\xf1\x8c\x1b4\xd9\xa3\xa1\xf7\x16\x0e`G\xffD\x1a\xe2\xd1\xb8\xd8\x0f\x1e\x8d\xed\x9b\xc1\x0b\x83\x18\xffN\x18\xc4\x1f\xa8\x18tG\xfc\x1c\xc54[Z\xca\x7f\xcca,\x01,\xc9\xd1\x91\xd4\xb5}\x8a\x02\xc1w;\x95w\x0c\x9e\x87\xb3#\x1b?\x98\xcf\xf3\x94\x1ds\xe9\xabsJ\x9cZ\n\xd2\x1b?H$go\xa9\x11\xbc\x9eZ\xf2\xd6\x81m |\xbe\n\"Z\xc1\xef:\xa9\x0d\xbd\xfb\xb9\xa5:|\\}\xbca\xcc_0\xb5\xb7\xf5O\xe4[,dkj\xed\xb8\xd4[\xfb\x81z\x9f\x17 \xcf#_\xd4\x05I\xa3\xcb\"\x0d\xab4\xc2'U\xd0L\x91m\xda\x04\x9b\x9bD4\xfc\xc8R\x9e'\x1eK?\xb2\x7f\xe4A\xc2\xe0\xa3\xb6<\xe4\xe3\xf3 \x0c\xd1\x0f\x88\x8c\xf71\xf5\x02\xf0k#\xdeF\\\xbeZjQ\xa8\x08 -\xa8H\xeew\xdb\xe72\x96|d\xa9\xacB\xfe\xb6V\xa1q\x99\xf1\x86\xc1\x86\x9c\xfb\xc7\x02\x13\x08P\xf12\x02\xbc`\x035\xba\x0b\xc0-\xfd\xe5^\x9e\x8a\x99\xc5\xfb\xc2\xa3\xec\x15]\x05!T\xc5\xa3l4\x877\xb4\xa2(;\x05]\n \x98\x06\xbf\xa3\x03\xa7\xc0\x8e\xfc\xff\xce\xd3\xcc\x04\x1eQH\xb2\x95\xc9\x12\x96y\xcb\xa2\x80|\xb5\x02\xdf\x84eC\xc4\x8b\x05\xf0'\x9a\x04\x12U\x00\xe8Z\xbeZ\x80\x7f\xd6g!\xc0^\xd9\x0eC\xa9\xae\x83\x0fg\xc2Wx\x06\xbe\xc3\xe7\xf8\x0e_L\xf0\xe4]<9\xbc\x89\x97\x8a\xfe\x82\xdf\xa3\x08'\xbe \xf3}\x12\xb0(\x03\xcc\xf0#O\x82\xdf\x05\x9f\x18\x16%y\x99;Z\x16\xd9=\xea\xfa\x89%Y\xe0YjZ\xabL[=\xe0\xb8\xdb\xd1?1\xa8\x84\xfa\xa2:\xd0\x12\x99K\x9a\xb5\x91\xd6RNo\xc2\xca;\x02\xbf\xa4\xd1\x02Ned\x98a8\x8e\xfc\xf5/S\xe2\xc0\xef\x11\xf5\xd7\xa3k\xac\x16\x91\xfb> \x16AT\x02sxG\xe1\x03\x9f\xf1EB\xe3\xa5\x85\x90\x0fVt\xc1L\x92\x01\x12ZI\x86 \"xU\x11\xbe\x86\x80\xd8\xf1X\x8c/\xeb\xcfx*\xbeJ?\xe3_\xf8\xbc\x87'?\xc2\x93Y\x12\xb1\xf0-\xcd\x92\xe0zJ\x1c\xf3\x15\xe9\xad\xcc\x16\x93\xfa\x06\xe4UE\x892\xc9R\xca6\xd9\x9f\xd9\x0d\xdci\xa4P\x95\xfa\x8d\xd6qs\x1a\x8b\xd3^\x01\xaa\x17\x1c\xf2,Xi8\xf8\x89@Iy[\x81;\xcdW\x14:\xcbXr*p?\xac\x0b\xf9>Je\x02V@\xa040\xa6\x95'\x8d~\xb7\x1e6`\x8f\x0e\x05\"v\x14-\x00\xe96\xd2\xb0r\x1cp\x012\xb2+\x9a|f\xc9 \x90\x1c\xf2\xf7\x88\xa1\xb4\x86\xcc|\x1b\x18\x80\xab\xc0\x0ex*\xaf\x085h*o\xa1,\xc0\x05\xd7c\xbeZ\xa15\xf60\xde\xac\xb0?\x07>\xac?\xe3\x0d\x85M\xf1=U\x84\xcb-qV=\xc9R\x9d n\x87\xcb\x96lE\x15\xa2\xc6>\xcf-\xd2\x82(_\xbd\xf72\xba\x86\xf5[\xbe \xdf\xd0R]\xa4\x12\xae\x89\x164O\xbaa\xc73\xa5<\x04\xcd ld\xa7q\x00\xd9\xf2m\xdc6_\xb3d\x1e\xf2+k\xa6\xd8\xe4Z6:%\x8eN\x1a\xc5*\x0d\x1b\x17\x05s\xb6\x0c\xbc\xcf\x11KS\xb3\\\xa6\x13\x91\x821\x0d\xa2\xec\xbd\x92\x08\xc1\xcb\xc8&\x10\x8ai\xc4S6\x018\xf1k4A\x81\xb2e\x81&\xcb\x17\x1cRP\xe7\xb5\xf5\x88\xa4\xda\xcb\x9a\x07v=\xc9^\xaa\xf6)\xeb78\x1c[\xa0\xee\x0e\xe0\xf2}\xc4 \xc1V\x00\x97\xa3\xc8\xac\xa3\xec\x17]\x8f\xf8m\xad\xe2(\xfb\xd5\x80\xfb\xb5\x05\xeeo\x06\xdc\xdf0\xb8\x84\xa5,Y\xb3\xa30^R\xf0\x1bo\xbc\xb7\xc1\xa71\xf3\xb2\x8fby\x9b\xa5\xcaT\xb4,`\xee5+\xc6\xb7\x92\x80\x94\xc07\x9d \xa2r|\x18\x136\x17#(\xfea\xd5\xb1\xf9\xaf2\x17\x1b\xb2\x82\x9ey\x0d+\x0b\x00U\n\x08cP\xba=a1\xa3\x19(\x89A\x81\xe2\xcd\n\xfbR0\xe1N\xf1\x1b\x85\x93<\xe8\xc9u\xc6\xa24\xe0Q\n\x05\xea\x89-%_1\x9a\xe5 3\xcb\xe9$\xb4\x94\xd2oA\x074\xcdCK\x16\xcflR\x94\x04g7\x12\x1c\xf7\xa6\x1e\xb5\xb0\x87)c8\xc3\x9f.i\\!I!\xa1\x95$MC\x1e[\xbe\xa2 \x184\x8fyyH\x13C\xe8SO\xc2\xbe\xa5@N\n\xb9\x84SO\xc2K\xd9\xba\x1b'\x8c\xfaoY\xb6\xe4>\xd4U\xbeb\xf5\x94\xda]\x02\xb8|Ca\xfd\x97l\x1dh\xe1\xa5\xf9\x8aB\xb3\x15.\xe0\x169kKN\x90y\xcb\xb3 \x84\xe5h\xbc\xa1\xf5\xf3X\xd3\x86\xe2\xb7\x95.\x14\x99\xa5\x0c\x02@\xed\"\x884K\x82\xcf,[&<_,\x8dc\xb3\x92\xdevvV\x00\xcd\x03\xb4ZC\xdb)*o\xb8,\x03\x94\xf0\xcf\x96\x95 Y/i\xba\xa4IBeWE\xca\xc8\xd7I\xf8\xa7T!^\xae\x81\xa2\x14\xb7\xaf\x04\x01\xf3&\x88\x98G\xe3\xb2L(\x13Z\x0b\xfc7\x0f\xa2j \x91b-\xf26\xc8\x04\xdd\xb1\n\x8c\xa6\xad\x8a4k1s\xbe\xa1L\xeb\x8c\xf3\xcfL\xd3\xc2\n\xfc\xcaB\x0c\xa7y2\xa7\x1e;\x95X\xc81_1\xe8\x1b\xb1\xd4\xdf\xd0h\x91\xd3\x05\xc0W\x12\x90\x12\x19\xbd\x0c\xa5\xb7&\xb1d\x8c7\x146Y0 \x02\xd4/+\xcc\xaf\x05\x0cv\x96e\xec:;\x02\xfdV\x01\xc6\xae\xb3\x91\xd4v\xb5\x80\xbed\x1eO4\x0e\x00p\xbfH\xb1\x141\x91/\x94h\xc3\xbd\x02\xa0\xa0\xf9\xca\x17\x0c\x92\xa3\x1b!+\xe98$7\xc7%\x019. \xc8E;k\x14t\x91\xd6\x86\x06\n \x13\x05\x94%\xdb\xb6\x7f\x1e\x05\x9e\x8d\xb7Qy?\x04~\x00\xf5\xc1\xdb\xe82\xf0\x03{E\xa0|e@\x83\xaa:\x0e\x9e\xa5\x1fXr\xb2\x92\xc0Y:\x8a\x05\x85\x8a\x11\xbf\xeb#\xe3>\xd7Y\x8f\xca\xeb]\x0c\xf8G-\xaar\xd6#%\xb6\xc2\xc0^\x9b\xb2%g=2dM\x18\xf8\xdb\n\x87\xe8\xacG&\xcb\x88\x15P\xdb\n\x19\xd65\xf32\x9e\x9c\xcc\xe7\xcc\x13xF\xbe\x8e\x18\xbcc5\xb1$\xb5\xb1jk\x96dG\xfe\xfaW\xa8&\xc9@\xf0\x86\xa1\x1d\x91Y\xca\xdd\x00\xb4E\xecVB\xffZ\x83F\xeb\x0e\xd8\xd5\x0f\xfcZ@\xca_\x16\x983\xc0 \nL\xbe\xa0\x90ip\x19\x846n\x18P%>\xacW<\xf1K\x89\x8fxk\x91\xf7\\% \xa9Q\xb7E\xeam\xb4\xc2o\x8cp\x9a\xf1\xba\x90\x95\\\xdb\xef\x87\xafq\x04p\x8d#\x80\xeb\xe3%\x8d\"\x16J\xad[@\x91\xf5$\xec\x1ba\x10}>\xf2\xb2\x1c\x88^\x07^\xa7T\xbe[\xc1\x13/\xe1\xa1\x01.\xdfm\xe0?& \x88\x96\xb0\xcb\x04\x15EC\xe6G\xb3\xd2\xb6\x1aO\x97\xfc\xaa\x00L\x97\xfc\xca\x06x\x16dF\x95\x99x\xb3\x82\xca\xab\\\x05\x89_\xe2^\xaf\xc2\x1f\xc0\xd3\xb6s\xbd\n\xa7\x97\x14U\x98\xb8^\x85\x11\xbe\xc8 \xe7\x17\xf8\x00\xd4\x10\xa5SLAG\x81\x8a\xb3W})\xa4\xe8:\xbc^\x85b\xcd\xea\xf6`J;D\xfa2@\x1as\x83/\xae\x1b|q\xdd4\x17W= \xf9\xf2\xefh]\xbfs\xbe:\x8a\xfc\x0fT\x1cQ\xe5K\xab\x7fT\x8a*\x1f)\x17\x02\x81\xc0\x95\xf5@\x11Dz\x1982Ug`\x84R\xcc!\x04il\x85\xa4Y\x1dil\x806 \xb9\xec\xdb >v\xd6!\x17z\x1b\x84Z\xe1\xad \xb0\xb2m\x10zI[\x8c\xdc\x8a\x85h\xcfWk\xb0WH\xd9\xc6\x8cL\xcd\xc8]\xa4\xaa\x9d*#\x02\x8e?\xb3\x9b\xd4\x0d\x06\xe39ON\xa8\xb7t\xed\n\x84t\\\xae\x08\x19\xe7vgH\x02\xf1\xeb\xc1\x03\xe2\xd2q\xe3\xeb\x12H@\x18\xeax\xdf$@\xc7N\xddu\x02\xc7\xedW[\x82\xfe`\x0e\x15\xa4\xa3\x85Guk\xd7T\x81\xef\xe2>>\x1e\xe3>>vw\xeb\xd5\xcf\xc16\xbdj\xcb\xaa50\xdf\xea\xf8\x05\xa69k\xc3;\x8b\x80\"/\x0e\xc8\xa4\xe6=\xb1i\xaeN@2\x12\x02]\x83o\xd0xIS\xe6\x7fd\x8b \xcd$\x15\xaf\x97\x10\n.\x1e\xe5\xf1~J\x1c\x1eID\x85\xa0)\xfdh\xd7\xf6\x06\xb4r\x11\xe5\xa0e\x90\xf5M@\xd9&\x16LC\xe4\x01^\x9a9\x19\x8f\x7f\x08\xf3\xc4\x19\x12\x07\x04\x01\x10\x1b\xfb-\x8br\x95\xf2\x8a{y\xaa~\xff\x95\xdd\xbc\xe4WQ\xf9\xf6)V\xbf\xdf\xf2\x06\xe8I\xe47'\xab\xa9\xa2\xbf\xa1EV\x8b\x05q\x87\x0b\x12\xfbf*\x0dM\xa7=\x0d\x82Mc\xd4io\xd3\xe0\xc2du\xda\xcfB\xd8\xb0j\x9dV\x8d\\\xf1m\xdb\xb17\x88\x1a\xed\xa6\xa5a\xab\x85b\x0f\xdb\xc4[\x8e\xbb\xb4KP&\x84\xd3\xc2PA\x07\xc7o\xb1\xf3\x92Q\x12\xa4\xf1I\x0b\x14\x8f\x05\xd0%\xcf#\x1f|5\xc4v\xd8\x90\xcd3\x13\xf8\x0d\x9b\xdfn\x94\xbf\xba~m<\xc0\xb2n\x0d\x8a\xfa\x9e\xbb\x16\x07,6\xde\x80~\x9a\x03\xa9\xcd\xfes\xc3\x93J\xac\xe6aH\x96Cbq\x10\xa7\x06\x9fC\xb4xr\xa0]58C\x91\x04|\xa6\x98\xd7!I\xc6\xa5\xea\xba\x8e\xb8\xf3Ry\xb7c\xa9\x0bf\x99\xd5\xfe\xfd \xf9\x8c%N\x93h\xfce3X\xee\x9aE\xa0\x84\x9aNImF\xd8u\x96P/\xd3wtu\xca\xa4%|\xf4\xd6\xa2\xc3\xea_\x0fdF\x0em\xb1\xd3\x06d\x8a\x9a[\x88'\xbd\n\xdam\xde=\x9a2\xe3\xd8\x9bZW\x9a\x1b\xba\x1c\x82\x9d;Y\x923\xe9#\x9e\x8f\x95\xaa\xed\x89\x1f\x80\xc8Q\x9a\xf1\xf82\xb6\xc7R\xfa\xa2\xd5\x07T\x8b\xd1!\xb8\x82\xc7\xb3\x8b\xf6\xc1\x99mo^qd\x96\xc7d\xf1\xe5\xbb}\xb8<\xe9\xed_\x87\xe3\xd6\x12\x17\x8b\xf4\xfc\x8eI\x89\xe0_\xaa6\xe9S\xdc\xd2 \xb5\xa6\x14\x19@n\xa4E{G\x0b\xeaT\x8b\xbdz\xb1t\xe7\x83^\xdd\xd2$TG\x97$m\xd5\xd9!\xd5\x91\x0edFZ\x1c94\\b\xfa\x1f\xf2\xec\x0d\xf8\xd3d\xf5\xe8k\x16\xaf\xa3%\xf1*M\x97a\xd1\x03u\xb5c\xb5\xc1\xc3\x8d\xaf.!\xf5\xae\xcc\x0c\x1e\x99\xc9\xe6\xaf\xbb\xc9\xfbP\x9c\xc9\xc9\x95\x05\xdbc\x94\x9b\xd9\xdf\xab\xf3J!\xce\xfc(\x8f\xdd{u&g\xae\xd2\xeb\xf0\xb1jM=\xdd\x97\xf0\x8f\xea\xbdZ\xaa\xf4\xfa(\xacUz\x9d\xe9Z\xa9A\xab\xc3/\x14|\xdd\x07\xdf\x8d\x1c\xcd\xfa\xe8\\*\x1e\xad>\n\x17e\x84\xaa?\xbe\xd6\xf2\xaej\xe1\xe8g\x0e\xbd\xe4\xe0G\xc0\xa1Q \xdd\xe3\x9dD~\xe5\xfdu\xc6\xf4\x15\x89\x91\xaa\xfd\x0f8\x97\x8a\x95\xf1h\xf4!\xa47\xc6\xcf3ya\x08)a\xe0}\x86\x1fUn\xc7\xe3\xb1,\x91C]>\xcf/Cv\xac\x81\xfd\x84.\xf4\x7f\xd5*\xf9S\xfa7\x90/\xd7A\xa6\x7fC\x8c7\xfd\xf2~]\x02\x15\x8d\xf5\x13\x0e\x1c\x92\x9f\xcb.)<3$\x0e[\xc5Y\x00Q\xcc\x1c\x16y\xc9M\x9c\xe9\x17_\xfdH\x12\x0e\x15\xce5{\x16D\xb1lv\x10\xadi\x18\x00\xd4\xe7\x92_\xfb\xccn>$pO\x02\xbf%k\x16r\xea\xeb\xff\xcc\x7fI3Z\xbe\xbde\x19\xf5\x8d\x94\xa2\xd5+\x93\xd5\x83\x97\xb7\\v\x14^\xde\xe7%\x94\xee\xf5\xaa\xe4\x06c\x9afL\xfe\xc8S\xf9C\xcd\x93\xf8\x0f\x12m\xe2\xc4 _\xe8\xc6&4c\xe5\xc0\x80s>\xc7t\xf1\xeb\xa4\x8c}\x96\x83\"~\xa9\x1a\xd2\x8c\x86\xa1J\xcd/WrV\xd2<\x8d\x99\x9c\xb9,X\xa9P\xd4\xf0\xc6soy,\xc8\x87\xb0xUS\x0c\xbfu\x07\xe1\xa5\x18\x08\xb8\x1f\x0b\x8cE\xba\xe6a\xbe2\x1a{EA\xf6\x0e?\x97\x8c\x85\xcey\x0f)\x91f\x8d\xd8l\xe7|\x9c\xf1Oq\xcc\x92c\x9a2w@\xb6\x05c\x16\x06\x1es\xeb\x9b\x95(\xcbg\x87G\x10\xe3\xb7\x99\x0bv\x98\x19\x8f-\xd9\x1c\x15x\x90;\x8a5Z\x0c\xc1KiFD\xb6\x89s\x0f\x92\x8c\x04\x91*T\x0f\xe3\x0b)P\xe3Cr5K\xce\x8b\x80\xd9\x00Y\xf3\xd2~\xa2PS\x91X\x08\x07\xae\xad\x16\xca\xce\x18\xe2P\x8d/\x12\xce\x81.}\xfd\xb2\xac\x1f\xa9\xe9\xd4^\xd3e\x9ee\xd2\x0c\xf8@\x06\xe0T\xdb\xdbHH\x8d#W\xa6\x08TF\x13FU\x9a\xf1m\xfdK\xf4\xec\xb8\x95\x92\xbf\xd8\x90\x92\xe7(\x13D\x13B\x87pR\\\xcd\xd89.-\xd8\xba\xe9 \xf5\xfb\xd3\xeaGpjtPT\xc7\xeaD\xe8\x07\xa6O\x8b\x0e\xe8\x97U\xcc\xdd\x01}\xa2\xb0z\x17X\x81\xf1;\x01\xfd\x1e@pRt\x00\xbd\x86\xd5\xd5 $\x0f\x96\x0e\xb07\xe2P\xe9\x01\xa3\x0e\x9c^\x90\xc5a\xd4\x03Z\xe2\xe7\x0e\xc0\x0fp\xfat\x01\xf5X/\x1f\xd4\xa9\xd5\x05\xa6O\xb4\x0e\xb8\x8f\xe5i\xd7\x05 'a\x07\xd0\xa9<\x1b{@\xf5\xe8\xc3\xa9:S\xbb\xc0\xe4y\xdb %\xcf\xe2\x0e\xb0\xb3\xf2\x9c\xee\x80\xfc\xc9<|;`\x7fV\x07\xb3\x9d\xbf\x12<\xc0\x1d\x19\xe5\xbfj\x8a\xab\x9do\x94\xfe\x9e.\xdd\xa8M\x82\xac\x9f\xfbf#!\xb8\xd3\xdd\xba\xd9\"\x88(`\xba\x84)\xa2\x19\xde\xdd\x9a!\xc9\xf4\xf6\xa1\xdeU\xaeq\xe4\xe9\xba\xc9p\xbf4X\x81\x8e\xbev\xc9G\xaa\x80@Y\xf6\x01\xb4Nc\x15\xec}7\x1a\x7f[P\xe6\x1d\x80\xdd\x12\x18\xa2\xe6.\xbe\xdb\xdc\xbd\x14\x9cUGc^*\xae\xab\x17X\xd6\xdd\xb9\x97\x9a[\xeb\x01'9\xb9\x1e\x80}F\xf5e\xc1\x01v\x02\xf2\xae\xadkq\xadHz\x8e\xfb\x99\xc1\xf6t\xe1a\xcd\x12\xf5\x81\xeb\xb3\xa8\xcfJV\xaa\xbd\x8f\x16\xef\xb8\xa4g\x1f\x8fLABG\x9b\x8e\x9aB\x86\xbe%\xfa\xf4\xa4\xc5\xbb^\x9f\x9e\x9cU\xd8\xcd\xf6O\xad\xef\xf6)\x19\xe4\xa7\xe3\x1b\xab\xbb}\xe3g\xe0\x88\xdb?\x81\xf8\\\xd3O\x9fO\x1c\xf3\xb8\x93~;\xeeF\x98\x1f@d\xd1\xde\xd2\xa6?\xc4\xa6\x08\x96\n.-q\x9d\xfd'\x0e\x1e\xc8H\xf0M\x17\x10\x90\xa1\xbc%\xba)9\xadf\x01u\x80\x05\xed\xb7?\x17\x83!\xb9\xa8\x94\xbd\x07\xa1/\xdcV\xf3H\x1e\x89\xa5\xdcw\xeb\xd4e\xe3\x8b\x8c.\xd0\xdb1b\x08j\x05\x1fm\x17\x0f\x04z\x18\x90`\x83\xf8\xac\x9f\x08\x96\xfe\xcb\x17\xe2\x9e(\xde^G\x85\n\x0c\x89\xdf\x0d\x16_\xaamh\xae\x820|\xc9B\x961\xcb\xf0\xdc\xfb\xd8Djll\xbd\x8c\xce\x95\xc3Iw0$>4\x0dR\xbb\xfaU\xbcYd\xef\xc7\x90zG\xd9\xfb\xa3}\xd4\x81=o\x11\x18h\xf7nc\x8f\x86\xa1\x8a\xacn@\x97\xcd.~%c\x9aC\xbc\xf8\xe3\x90\xa6\xa9\xcb\xeba@\n\xa9\xb0\xf4\x8f\xd0\xd4\x06a\xd2/\xb1\xe0-\xb0\xec8e\xb9\xcf\xcb\x0b\xed\xca\xadhM\xfd\x8a\xdf\xd3\xa85o,\x9a+\xc4\x0b\x83\xf8\x92\xd3\x04\xf8\xe6>~\xda\xb54\xa9RP\xe9\x94\x1c\x126\xae\xa4\x17\xb7\xa6\xd5\xe4\xaee\x85Mw\xf0-\xa7;\x90^\x86\xcdI\x08\xeec\x12&\x93\xc9\xbf\xc1\xdaM\x98@\xe2\xbeV(\xff\xf6k\xafy\xf1\xc3-79\xb8\x87\xbd\xcf\xecf\n\xf7V\xf5[4\xa2<\x02d\xa0\xe0\xdf\xdce\xe2\xf1\xb2$\xfc+T\x80f\x83/\xb5\x96|\x1a\xb6\xe5\xaeXF[\xb2\xa51\xa8-\x17|\x19\xa0\xd8\x81\xc8\xb8\x16o\xb9\x1f\xcc\x03pA\x90 8wwR\xbf\x18\x14\x8f\xb7\xa4\xc9q5\xf4~\xe7v\xfd\xccnb\x10\x1cH9\xae\xd4\xfd8\x94nm\xa7\xb5x\xa4\x04\x17\x8f\x7ff7\xb7\xf8\xaa/\xb8V\xf3\xa3_\xbe@z\x1e\xd7\x9a\xc2\xc6\xea\x03}\xdbs\xb5\x0c\xbc\xe5\x86\xadi\x19\x83\xfbll%\x05Eg\xf4[b\x00:$\xc1\xb7P\xe9m\xee_\xfcP9I\xbd)qNR\x8f\xa26\x05\xa0=}I\x93)q\x08\x92\xfd\x06\xf4\xad\x9c\xa3$\xe1W\xe27\x02\xf2)\xd6\x00\x9f0\x83\xc6\x8f\xca\xd0\x04 >ZLM^\xf2\xabH\xc3\xc8\x9b\xc7&\x08\x0b\xa7\xc4\x91\xa4\x1a\x92\xfd3\x18K\xbe?E\xb2\xde\xb2(\x9f\x12\xa7\xa2\xf9\xda\x00:\x8a\xe3\xb4\x13H\xb2MS\xe2\xc8\x1fo\xb8\x87\x19O\xbc\xe5\xbf\x7fH\x82\x08\x14\x84\x00?9\x9f\xa2\xc0gQ&\xf0\x89\xdfjg\x80\xa3\xe0\xfd)q~\xa0\xdeg\x9b\x85\xc5\xb3)q\xce\xe8%\x923\xd9\x15}\n\x19\xc5\xcc#&{ba\xc8\xdb\xedf\xe6\x13\xd1M\x8b\xaf\xcb\xc9S5T \xc7\xec\xc7&\xa2\xc1G!ZR\xb4U\xca\xe6\x9b\x99\xbb;S\xb8(L-\x03\xbb\xfb\xb4m%\xef\xedZ\xd6\xf0\xde\x1e|s\xc1\xd0\xf5\xb9\xf7H\xe5Z\xd6\xdd\xdec\x18%\xcc$|O\x8c\xd1\x8f\x1cu\xcb\xb5\xf7\xb4c\xdb\xec\xed\xb7n\x9b\xbdg]{\xe6\xd1N\xc7\x8ey$Z\xfe:J\x19\xea3\xe7\xd1\x93\xb6\xed4\x81\x95\xf3\ns52\x81u\xf3j\x17\xcd\x12\x83\xf9j\x0f\xcd\x12\xady\xf5\x08\xcd\x12My\xf5\x18\xcd\x12\xc3\xf8\xea \x9a%\x06\xf0\xd5S4K\x0c\xde\xab}tC\x88Q{\xf5\x0c\xcd\x9a@\x97w\xd0<9\x1c\xe8x\xec\xc2xL\xd0\x01y$\x06\xe4]\xbe\xb2\xac\xe8 \xccQ+6\xd9\xdd\x15U\xbce\x19\xada\x0e\x9c\xcb\xb3\x9f\xc0\xd2\x0b\xfegvc\xbb\xd1\xcd\x04\xc99\x03\x90s\x19\xec\xf63\xbbir\xa9\xc0\xfcV0\x1ah\xc8\x97\xde\xe3\xab\n\xb9_\x1b\x8d@\xcf~[\xa3\xb4\x7f|\xabld\xa2\xfc\xe1\x93C\x8d\xcc\xc8\x94\xc8\xb0:\xe3y\xc2W\xc7\x8a@\xab\x07DF\x15d7\xa2;\x82YAy\xc0x\xd5\x06eJ\x9cr\xc6\xee\xc1\xc9\xb6\xd4\x11\xfb\xd7s0>\xcd\xa8t\xf7\xc3\x92\x7f\x1d\x03\xd3\\-\xa0\xbb\xc3R\x1bI/\xb5\xa9\xcf\xda\x81<\xb8]\xf4;\xa0\xee\xc4\x96\xdc\x91%\xb2q&\xd5\xb5\xfd?\x86i\xff\xb7X\xf1\xb1\n\x15\xfd\x7f\x8b\xb8\xe9\xdf\x04O\xb00\xa3\xbft\xf1\x84\x1a\xf1JhCv%\x13\x04\x16\x05\xd5\xba\x97\xd5\xfc\x11\x1b\x1b\xc9\x0d\xc6\xaf\x11\xa74\xcc\xe8\xaf\x1b5\xe5\xd7zS~\xad6\xe5W\xbc)5(\x1c\xa8Ws\xff\x86-%\xc8\x91\x86\xff\xdfj\x19 \xce\xf2\xf1\xa0\xb9\xac\x9eu\xd1\x1b\x88\xac\\\x1f\xe0\xcd\xb1\xbe\xc8x\xfc\x86\xadY\xa8\xe2\x02O b`u\x11\xf8\xe0\xf5KdO\x90\xecJ\x84\x8e\xa9\x8a\x91R\x84\xc0\x80 \xa9\" \xc2\xa9U\xa3y\xd8\xb0\xeb\x85\x8co\x83\xe8O^dta~B\xe0\x82q\xc6\xdf\xf0\xabB{\xd3^\xa9\xb6\xfd\xfe\xf4\xf1uQ\x87\x91F\xa6\x88\xda\xfesl{F\xb5}x\xab\x196\xa7\xaf:3\xf5x\xcfS\xb2U3\xa0\xcfS\xf6*\xb8\x14\x13\xb25\xb9\x8f\xb6\x18\x91c\x1e\xd5\x15\xe6\xc51\xff\xf0\xb7\x87\x87\xdf?\xac\xa6\x0b&\xf9\xe1\xdf_\xfc\xb6\xf5\xdb\xe8\xb7Q-\x0f7\xd4?\xfe\xf1\xe4\xf8\xaf\xa7\x9f\xde^\x1c\x9d\x9d}\xbcxw\xf4\xf6dJ\x1cA\xc7\x8c \xe4\xf0\x08b*\xa79\x1a&\xc3\xf7\x8fU\xee\x19\x97\xb1\xb4\xbb\xf0\x081\xe8i\x9ct%\xe6\xd5^\xc6\xd2LTt\x08\x01f\xd88aqH=&\x10\xaaC\x1c\xb2M\xe8\xb8\xd9~\xb2M\xbe;p\xbe#\xdb$\x13?\x9d??\xf8\xae_@s\x1a}dy\xca\x9a=\xe9\x8a\x80\xa8c\x9b\x16\x16\xec.\xd6\xae\xf6\xce\x8aJ 6QL\x93\x94\xbd\x8e \xf0\xe4dg0\x94\xc1\x7f\x80\x8eo\xf6\xc2\xb6/\xeeY\xa4\xf6\xe4\xf1\xe3\xddI\x17\x92\xab\x0fQ\x11\xc7KL\xf6d\x08=\xdc\x91\x91\"wdH/V\x84\xdb\x12ks\xf4\x88< \xc1s\xc2\xc9\x0bB\xd1\x10_E\x8d\xb9\x19f\x90\x93m\xf2h\xe7\xd9\x93!\xa1\x03Y:\x17\xff\xb6\x0f\xc8\xa3\x01\x89\xc4\x7f7\x13\x7f\xd9X\x0b\xa4\x8f2\x97\x0f\x06d\x1b\xcd \xdbd\xd2\x96\xb9\xdb\x96\xb97@f9#\xffq@\x121\x00\xffa\xc6\xa6&\x8d T\x91\xdaD\x17\xc48lo\xab\xf6c\xcdGq\xa0+?5 _\x88\x1b\xa9\x9f/^\x90\xc9\x93\xfb\xc0G\xe6\xac;\x93\xc7\xe3'\xe3]\xe7\xf6\xb5u\xd8,\xb9\x91\xfb\xe8\xc9`(m\x91p\xdb\xa5I\xdd\x9aG{bx40\x8f\xec}\xa8\xe5\xd9\xc6\xa1\xb7\x04;\x1e)kw\xd6\xa2/'\xe0&\x8a\xfb-\xe3\xce)pV\x85\xd5\xbb\x01\xac7\x1b\xe8O\xd4T\x8a\n\xdcL\x06\x11\x1e\x08\xf4\xc7\xed\xe6\x9e\xcd\x16\xa1\xa1\xb4\x04\xf2\x8c|&N\xfd\xc4u\x1e=rDY\xf1\xeb\xb13\xac\xb8\xf3\xb8\xe7\xf8WbB\xf6,\x83\x9f\xa86\x9d\xe6\x97Y\xc2\x04\xd2\xe3EX\xe0\xdb\x7f9\x1b_\\\xb0\xf4-\xf7\xf3\x90\x81!\xdeP\x86\x87\x8b\x98\x97\x01\xa6\xfe\x90\xf0u \x86BG\x1dm\xb6:p#w\xff\xf1n}\xe5\xf1\"\xeb\xd1\x00e#\x02\xabY\x83\x8a\xf7h4M\x1ejM,\xa7\xa2\xa7MIwL\xc5J_\x12\x1dw\xad\xda_\xae\x93\xefyDU\xad-\x83\x18\xb9u\xfb<\x0eK:r'\xd8\x96\x16\x19{O\x1f\x9b\x18T&=\xc1\xc7\x9a\xfes\xc7Z\x9f;-\x07\x9en\x99\n\x1a\x8d|o\xab\x1fU\x016\"n5\xe8\xdd`@\xb2e\xc2\xafH\xc4\xae\x88@2`\xdc\xe0:\xc74\x8axF\x04oJ(\xf1\x04\xc3IhJh\xf1%\x07\xa1~\x14\x17\x8b\x99\xdd\xaf\x95\x95y\xff\x862\xb3e\x1f\xd9\x9c%,\xf2t\xf3\xc4\x87\xc8\x92\xa6\xd1w\x19\xb9d,\"A\x14d\x01\x0d\x83\x94\xf9dD\xd2\xd3\x05\x1b\x93O)+\xeb\x1b\x83\xb4\xa2xu\x07$\xe3\xf2d\xcc\x96l5&\x1f\x19\xf5\xc9J`m\x9a\x11\x15hu~9^\xb1\x87y\xca\xa4\xa8cT~\xc5\xa9\xdf\x8a\xe1\xa3\x91\xb5-~\x1b]A`\xd0\xcb\x95 \xb8\xe1&\xaf\x80\x0b\x08\x95kn\x04C^r\x1e\xa2\x19\xa2\xb1h\x86\x8c\x94\x8bf\xc9\xa3\x15\xcd\xd2\xce\xc5\xb1\xac\x9b\xd5\xa5\xa5\x114\xc2[\x0d\xfdy?Ge\x8bLK\xdb\x90r\x9a:\xb2\x14\x95\xf2Jk\xc7,\xa5xd\xab\x0fr\xa4\xc7F$\x17\xe2\x01\xe0]\xb8\xa6b\x18kW\xbf(\xff\x1e\xd5\x160\x91r\x83\xb1\x99 \x0e\xec\xa2\xec\x1d\xf0F\x83\xa8o\xa2\x14u\x82\xd14\x0d\x16\x10\x9e\xbb\xaf\xb0\xe79\xc9\xc8\x0bB\x93\x05\x88\x94S%\xe6yN\xb2\xedml\xaf\xe8\xa5^\x14\x98e\x88\xe1t\xf1\x89\x84\x04\x91\xe8\xa1j^y,-i\xfa\xfe*R\x8e&o$-')qqN3\xa9\x1b\x1f\xcd\x92\xf3\x1e\xd7\xdd\x86 9~\xe8\xb4\x8d8Q\x9d\xf2\xccN\xa9Q \xdf\x93=\xd1\x1e\xc95\x01\x8e,\xfb\xbdwN\x0e\xab\xaf\xb8\xfb\xd4\x159 ?p\x1e2\x1a\xa1\xa6\x04\x0b\xa2\x0c\xe3\xe7\xcd\xbc\x1b\x84e\xd3\xe9x\x14n}S@\x0e\x89\xbb#\x0e=5\n\x03)\x81\x88\x9b\x88\x0b<\xa2\x80\x8b\xc0\xe6\xf7\x05\xbd\xe3\x8d\xe3H\xf2z\x1dNb\xdc\x99^u\xcd]Y\x8a\xe6\xd58\x00\xe5\xdb\xbdp\xd4\xeeJ\xcb\xd3\xe8\xcb\x17\xb2%\xe8oZ\xd2\xdf\xba\xce\x12j e$\xf5\xb2\x07\x82\x0d\xa8\xbb\xb2\xd5\x0f: \x95\x11\xbd\x8f1\xa9N\xd1\x1d\x87\xc5\xaf\xe0\xad\x96\x91\xa9\x00\x9a\x83\xe3\xd70\xdf\xa6\xe3\xf3\x96%\x0b\xe6\xdfit\xba$OX9\xb1_/\x8b\x02\xed\xacf\x8b\xf3j\xd2\x85\xa1H\xc1N\x1a\xcb\x08\x1b\xd3\xcd\xa6oKV\xb9*\x07O\xcc\xc8)L\x0b>\x81\x06\xa89}f\x0d\x9bL^\x90\x9e\xe6\x97\xa9\x97\x04\x97\xfd\xe7K\xb5\x1d\x97\xa9\x89\xc6\xe4Q\xaa+\xed\xd3\x86,\xb9)\x1a\xd1\xb7\x0d+p\xbeQ\xffZ9\x1ef\xe2\x81q\x1f8.\x92%\xdc\x92F~\xa8\xa8\xe2\xf1e\x10\xf9\x90<\x18\x0cI#\xdbE\xfc\x8c\x10\xb47\x9f*\x1f\xef\xd5\x9f^=qu\xb3\xaa\xbd\x13\xecd\xaf\xa6\x15\x92\x83\x97\x81\xff\x96\xe7Q\xe7]\xab~\xe0\xa3\xe64\xb9\x9b}\xef\xe7 \x0c?2\x8f\x05k\x84\x93h\xfb\xf0U\xcbN\x90[\x0c\xdc\xc3\xa8\xb9j\xf2@M\x7f\xe5\xfaik\xea\xa7hu\x9b\xd1\xf9\x84\xcc\x94)\xb3\xe8\xd5\x8e\x02~\xa3\xaf\xd7\xb17h\xa5\xd7\xcf\xc2jz\x15c\x18\x19\xb6q,\xb2\x9b\xecd5\x7fm\x9c\xf7?0\x16}H\x98GC\x0f\\\x19\xf9\xca[\x7f\xadi\x06H\xc0#\x10\xa3T\x1b%o\xe6\x99\xaf\xb4\xd4\xab\x99v\xa2\x0b\x01\xaa\xf1%\x0d-|\xfd\xd4&\xc6\xc4\x04}\xa7\x06\x14\x1fk\xfb\xb5\xcf\xa1VCY}\xf9[\x02:\xb9\x07\xc6\xd8\x8eK\xe9Z\xfb\xd9\x07\xec\x8b\x14'\x00\xd1\xd9\xd9L]\xe8\xaa\xc4\xc3m\x1c]\x9f\xea\x08&\xcd\xef\xa2\xf2\xebO\x96\xdcl\x00M\xcc\xab \x1a\xc7\xe1\x8dk\x11\xe2`\xcfW\xe2\xd1vo\xc6\xb6G}s9\x06y\x9a<\xb0\x97\xbdk\xb0\xcb\xb3\xccGQ+6r^\xee\x8a\x0e\x8aI?\xb0<\n\xe7\x9a\xfd\xcaDp\xd3\xb5\xc4\xc8o|\xb7\xab\xd1\x18\xf4\xc7#\xedb?\xd2k\xa8z\xe1\xb4T\xef\xc0~\xd3l\xca\xb4q\n\xc8|\xbe\xb6\xaf\xb8\x16\xe9e\x1f\xbc\xb5`\x99\xb4\xb7\xf2\xb5zu_\xec\xa59\x8c\xea\x15\xc7\xf5\x908g\x9cP\xcfci\n\x97\x12W\xb2\xfa\xe2\xf6kHnxN\"\xc6|\x92q\x88\xe0\x1f\xcco\xc8\x1fD]kNI\x96\xe4\x8c|%T\x16\x9f\xf3<\xc9\x96\xc5\xe50\x01\"\x12\xeeF\xe0~q\x00\xf7HcgP\x1c\x04\xf3t|U\xedQ\x9fq\xe8\xa7\xda\xa5\x1f}\xcdi;\x10\xdb\x11qT\x96l\xae\xab\xf6\xa2\x81\xf9\xd1\x96\xe5\xdf^\x0b\xad\x9c\x02\xb6=\xd7^G\xae\xeb\xa8\x1d\xbd\xf6\xdd_\x1cw\x16\nb\xd2AAL\xfa\xef\xfc\xcd(\x08\xaa\xefih\xbb`-\x95{\xbeuX\xc2\x8e0Hp \xe6\x80\xf5R\xad, /e\xba\xce\xc8!\xd4m\xc2\xb6\n\x88:\x84\x84\x1e\x12\x1d\xb1\xfe\xccU\xb4D[~@\x0ee=;dJ\x803u=\xbd*l\xe7\x8a+x\xa7\x10`\xe7UXT\x82\xe2\xb6]\xc5\x16L\xf2\xd6\x96\xeb\x81\xd6\x07\x8c\xe6\xa0\x18\"\xab\xe8\xc1\x95\xbcqN\x0eIN\xa6jY6i\xc8k\xa5\xf9\xc1\xd5\xf5\x99\xca\x01\x1e#q\xff\xf8\xda$\x95\xbb\xee\xd3d\xe0\xe9\x1a~\xc2#`\x10\xc0\xfd\x03\xd1\x88TX\xc7j\xc5\xd5U\xb4l\xac^um^\xb5\xdf\xaf\x16Z\x93\x03\xe5!\xe0~\xb4\x1e\x87v\xa5\xbez'\xc1K\x90ti[\xdcR\xd5\x8f8\xcd\x98U-\xea\x9a\xc7KR\x83\xa9#\x19\xb0>\xd4\x1a\x83\x82\xd3L\xd4K\xf9\xe5\xda\x81T\xa8G\xf2\xb2j\x9bj\xa44\xbf\xddyN\x02\xf2\x82D\x85zf\xb0\xbd\xdd\xc4\x91\xc0\xd3p\xa5\x194$\xd1,8\x07a\x12\x9b\x89\x9f\xe7\xf2\xeeE\xfe\xb6\xb6\xad\x18\xac\xda\x0e\xf9\xb6Sh\xd9\xe7\x05\x00\xca0\x1b\xd4|\x02\x82\xce#\x00\x06\xdb\x7f\x9e\xa4\xf2\xbc\xe9\x89&\x957\xc2\xa7J\xb4\xd6\xd1[(QV\xd0J\x83\xe3#C\x0c\xb9\x08\x8e\x04\x1a\xd6\nv5\x12\xaf\x17\x94\x1aw8v[\xa0\xcaS\xd2\x0e\xb4`\xd9\xcb^\xb5\x01`\x12\xac\x99\x0fd\xd5\xab\x84\xaf:J\xac\x82\xeb j\xc9/\xceS;H\x06\x8a\xdf\x08+\x8dh\xe7f\xd6\xf1\x8fZG@\xee\xc3\xd6f\xca\xed\xdc2k4\x0c\xc1\x05E[~K\xf9B\xf7\xb8\x0d$\xc8n\xfa\x0e\x85\x81\x0b}6\x0f\"V\xa0\xa0\xe6\xce+A\x17,3\xb0\x15\xc4\\k\xc2s\x1b\xfc)\x98 %\x02[\x89\x97,\xf5\x92 \xce0^\x8fV\n\x19\xdaMMPA\xcaPAEP\xa5'\x85[\xe9\x17\xb4H\xea\x86C\xe2\x0d\xc9\x1cCD\xa0['\x0d-L\xcd:\xcf\xc6\x8e\x0bx\xd4\x0eG?\x023\xc4`g\xeb\xb5\xf0\x12\xb1h\x7f\x0cX\x1d\xb83hc,\xda\x88\x16\xc1e+\xe2S>\xb8\xf8\xb0}\x8a\x13\x1d\x1d\xd8\x17\x84\xb1G3\x97\xbb\xde\xc0\xc6\xe5\x14\x87\xdbR\x9e[K\xf2\x82\xf8\xc5\xb9\xb5\xbd\xbd\xec\xea\xb8 \x1b\xfc\xd9\x121+\xd0\x8fRN\x9e\xad\xc1a]\xa6\xfe\xcfE;\xe7\xb3\xf5\xb9\xd5o\xbd~\xc4WV`\x1f\xee\x0d\xc9\xbaC`\xd8O\xfc\x1a\x89\xb1_\x0f\xc9\xaaC\xf2e\xcaW7\x16\x83\xa1\xa9j\xa56%\xfeMp\x14\xd48\x12\xab\xde\x97\x12\xb7\xd7Y\xd8\xed\x81\xa2^\x1aL\xd1\xf8\x90\x04\xb8A\x9a\xd6\xdcn\x0e:\x084\x9a\xb3%\n\x18\x96\x08\xd9@\xc6\xbaeWD)\xaf\xbe\x0d\"\xf0fH\xd8\xb5\xc7b\xd8\xcf\xdc\xf3\xf2$a\xfes\"\x9a\x9f-\x19\x89x4Zi@\x9f\xad \x8b\xd6A\xc2#\xe0\xab\xc5\xa2\x06\xc9^\x1e\x86\x04\x82\x9a\x92\x15KS\xba`\x84F>\xa1\xbe\x0f\x11OhH\x96,\x8c\xe7yH\xaeh\x12\x05\xd1\"\x1dc\xda\xe2,L\x99eQ\x89>\n\xcehV\x1f\xa6s\xbb\xe0\xc3\x83\x9d\x86f\xbb\xd5\xa1\xc8\n\xbf<\x0f\xff#}\xb8\x18\xf6\x13\x1d\xeau3\xf3\xb6\xb7\x9b\x01\x1c\x88d\xfa\x07\xd2\xee\xe1\x808\xaf\xa35M\x02\x1ae\xe4\xa7\x80K\xe1\x15b\x00\xd1H\x91\xf2\xact\xd2\xec\xcc\x1f_\xf1\x1d\x828Hi\x02\xea\xd5\x87\x89\xd0\xa4#\xa8l\xd8A\x95\x13C}L\xbaE\x91\xf6\xd1!\\k\x83<\xb04\xaf\x9a\x0c\x86\x98\x8d\xff`Hr\xd1QO0d\xa0h,\xc5o\xa2\x7f\xdc\x8d\x86\xe4\xe9\x90\xa4\xd8\x01T\x1c>s\xe3;\xcf\xc9|4z> \x01\xa8\xfc\xcd\xe6\xe7-R\xa2\xeaR\xb3\x99\xdd\xa2\x0b\xcf\x1c\x8c\xde\xbe\xe5\x8a\x06\x8b\xae\x8d&C\xa2E\xbc0U\xe4\x90\xec\x80Nvy|F\xe4\x05I\xe0\x86R\xe9\xd2\xb9l\x16\x9dK.~\xf0\x1c\xa7b\xea1V{o\x99\xc6\x9a\x96;\xe6\xc9\xa3.{d\xac\xab\xa6\xec\x06\xd6\x11w\xb3AE\x90u?\xad\xdb{\xba\xffo\xd1\xbcF\x88t\xd9\xbcI#\x02\xbbB7O\xea\x88\x82vK\x07\xba\xfa\x89\x9e\xad\x89\xcb\xca \x8eA\xc3\xb7\x91\xbe(\xe2\xa84D\xac\xd3\xd9\xb9E\x9e\x91\x835\xd0\xc0u\x0c\x1b\x0c\xa0\x88sP\xe0\x83\x8b\x00*\xe5\x13L\x9c\xfc \xd1\x8e\xc6q\x9e.\xdd\x1c_\xbb]\x06\xb4\xdd\xbb\xae>\x06\xba\x7f\xf5^\x14Hr\xeb\xa0.]%\xd5\x9d\x1aDj^` 3\xd9\xfe\xba\xaa\x9e\xc6\x81\x9b-\x9f\x8e\x88\xdb\xdaM\x1321\x1c\xe2j+c\xb3\x83\xaay\x8f\x8c\xebdx\x95\x14i8\xd3\x05\xd4>R\x8f\x14\xb9B=\xacR\x0ff%N\x943\x81\xa0\x9c\x90\x03Q\xf5!I\xc6?\xe4\xf39K\xc8T\x99}\xdaX\xb3CB\xc74\x0c\xb9\xf7)J\xe9\x9c\x15\xf0\xd5A\xee\xbd\xbb \xa9;\xed\xd21\xca\x91\xc3`]h\xa4+e\xe4\x06\x04QL0\xdc\xc6\xb8\x11h\"\xb3+\x02z\xdez\xe1\xa3\xba\xe3\xc5\xc7=\x1e\xdf\xb8\xc9`h\xf52\xf7uP\n\xf2\xdc\xc9\xde\xa3A\xe1\xeek\xf3-\x80\x0c\x88q\xe64\x1bi\xf4\x1d\xd9\xe9\x99TP#\x07\xe4(I\xa8\xe8\xc5\xa08\x99\x9e\x0fH6\x8b\xce!0|t~\x1f;\xa2\x13\xdfO\xf6\xefr\x1c%\"\x13P\x9d)+\xbc\x9f\x96\xed=\xedt\xdcqO-\xab7+\xba\xff\xa3C\xa3M\xfb\xa6H\x14\xabQ\xdd\x05\x16\xc9\x8a4\x82\xd5B\x13\x03\xcf\xccv\xce\xe5\xa9\xa0\x8f '\x88|v\xedH\xcd\xe0d\x0co\xd0\x0e\xf85$\")\xce3\x95\x14\xe7YeSm8\x93\xbb\xbb8\x93\xb0\xff\xb4N\xae\xabS\xfb)\xee\xdap\xff\xe9\x1e\xca%\xec?\xad\x9f\xf2b\xd4\x9d\x99D\xb8\xdaQ\xc0\xb9\xd3d\x19\n\x98\x974cu\x00\xcf\x04xK\xe3z\xfe\xdc\xcc\x7f\x07\x8eD\xea \xb1 \xf2\x91-N\xae\x1b\xb5\xf8&\xc8)\xcb\xea\xf9\xcbJ>Lm\x1dd]\x01\x01\xe9_\x1dde\x82\x00\x86\x91GF\x1dnQ\x1b\x14\xfaS\xc0\xae\xea@7&\xd0\xab\x90\xd3lo\x17\xea\xac\x03^6\x00\x9f\x01\xd4\xb1\xbbA\x1d\xe2\xef\xc4Z\xd3\xde\xc65\x89\xbf\xbb\xbd\xbc\xe7j+a1\xd6\xb7]\xa9\xfb\xb6\x1b\x90G\xf8R\x9d<\xc3tk\x04\x1b\xdbzH\x90\x9aL\xcd\xc9\xb8\x143;-\x91\x0c*^\xf5\x9aHH<}<\xfb)\x83\x07\xc1~\xe0\x00\xa6\xbb\xbf\x06@\xcd\"V\xb0i\x01\xbe\xf3\xf0\x18`\xdd\xbb\xc5\xb2O[93\xbd\x04,\xab\xa4{\xe3j\xd6h\x7f\xa76\xb2bYL\x9e4\x97\xc4K\x9a\xb1q\xc4\xaf6\xc5:\x9a\xdeA&0hj\xbf\xf5\xe9\xfbZ;\x02\xb5\xf9 \xc8\x01{\x8e\x88K\xc9\x08\xf5O+\x98L\x88\x86#\x0e\xa7\xef\xc9\x0e\xf6\x15\x0d\xb7\xbd\x9d\x91\xef\x0fHapnx\x8e\xdei\xaa\xd4}\x95\x1a\x82\x19\xae\xd7W\xdb\xb8\x9a\xcd,j\xbc'\x89\xe1\xe4\x11.\xe3hluEn?\xc3\xc9\xed\x06S\x9a\x93\x03T\x0d&\x85\xf4\x86\x16L\xd8}\x95Y-\xe0\x011\xde\x89G@ \xdb\xcd\xe0\xf0\x92\xb1\xbb\x80\xc6L\x95\xd6Os\xd8\xc5\x94\xa0\xf3[\xd5\x0c\xc9\x06$,\xf1\xb1\xe6|\x80D\xcafQ\x1d#[\xa8+o\xb3\xa9\xda\x7f\x86\xc7\x93\xd8\xdb\xe9\xbe\x1a\xb7R\xbc\x05\x08v\n\x13\xe3\xfb\x18iG\xf4\xbahU\xa1\x90\xfc\xaf$\xbf\xa2YPeL\xec\xbbR\x14\xd9\x85\"\xbb\xe7\x16\xc5\x10\xa2\xe7\x85\x1aW\xd6\xda\x9f;\xea\xe6Ip\xdan0\x1a\x81mu\xd1\x06\xa9Y\xcf]\xf3`\xcd\xe5U\xb4l\xfc\x0b\xb2g2\x06T\xdak\x81^c\xb1p\x05\x95A\xb6\xb7\x13\x08\x16h\xc3\x12\x9aP\x8ef\x89E\xf5\x1d\xcc\x95\x81\xdcNe4\x8f\xa6\x92\x92U\xb8V\x0bip\xeb\x83\xbeyp\xab\x95fa\xc2\xf7\xf6m\x11\xe5\xfap\x83\x81\xab\x83='bS\x92m\xe28\x1b6\xbd+\x12\xcb\xfe3\x1c\xcb\xed?{j \x1bWo+\xd8/\x03j\xf2xH\xaa\x8e\x8aB\x9a.e(\x882\x91\xe6\xd9\xb2\x9a\xb2\xe4i\xcd\xfd\x8f\x18\xa4&\x8cR\xb0\xae86Jku\xa5\x8c&^-\xed\x1f9Knj\x1f\xa0\xd9\xb2Y\x9dH\xad} asRs)T.\xb2l\x0c!P\xc9\x01\xb9\x1c\x92l\x9c\xb0\x94\x87\xebN\x97\xaejr\xc1\xc7\xdd\xd6\x04\xfc\xba\xe9\xa2\xa6\xaf\x9a\xafF\x95r\x1f\xf5\xac\x98\x91C\xb4\xf2b3V<\xac\xc3g\xe6\x0eRIl*y\x16H}.\xad\xd7D\x15\xdf\xf9\x01D\xe0\x96_\x81\x18\xcb\xa6\x1f\x0f\x99\xac\xafZ\xaa\x0d\xfb\x94\x88%\x15TW.\x85\xd0\xc1\xee\x8c\x8e~\xdf\x19=\x1bo\x8f\xce\xb7\xa7\x83\x87A\xf3\x98}8\x9d\xed\x8c\x9e\x9d\xff\xe5\xcf\x0f\x9bG\xed\xc3\xbf\xbb\xbf=\xfc\xed\xe1\xa1{\xb8\xf5\xdb\xc3\xc1\xec\xef\xbf\x1d\xfe\x96\x9e\xffe\xe0\xfev8\xfb;\xfc:\xac\x97\x02\xb3\x04\xe7\x0fgH\x9c\xaf\xe2\xcf\x17\xf1\xe7\xb7\xdf\xc4\xdf\xbf\x8b?\xff\xe5\x9ck\x03\xa1\x99\xf3B\xa4|\xef\x0c\xc9w\xcew\x90\x07q\x80E\x81\x04\xfeF\xf07s\xce\x07\xcd\xd3{\xe6|WV\x15\xd6\x00\xe6\x00\xf0\x1f\xa2\xf8C\xf1\xe7P\xfcy.\xfe\xfc\xaf\xb2\x90W+\x14C\xa1\x12\xfe\x7f95s\n\x1fFd\xb6-\x87\xf4h\xf4\xb7\x8b\xd1\xf9\x1f;\xc3'{_\xeb\xa3\xb0T\x83\x8f\x80\x0e\xdc\xf1_\x06u\xf85ja\xf8\xdftM\xa5!\x1b\xce\x958\x06\x80\xd3\xe0(j\xd6{\xabo\xff\x89\x05\xfa \x88\xcb\x84V.r,\x86\x89s[\x99\x05\x8f\x976\x83\xc8y`\xe3\xdf\x1ch\x84\xd3\x92\x99Zs\xe7-%Uk\xacEE\x83:\x87\xedF\x9d%\xfb\xe8Yri\x93q\xfc\xff\xec\xbd\xeb~\xdbF\x928\xfa}\x9e\xa2\x84\xec8@\x08R\xa4\xe4+mZ\xeb\xc8\xcaF3\x89\xedc\xd93\xbb\x87V\xf4\x87\xc8&\x89\x18\x048\x00\xa8K\xc6\xdeg9\xcfr\x9e\xec\xff\xeb\xaa\xeeF\x03\xe8\x06@\xdb\xc9dv\x07\x1fl\x11\xe8{\xd7\xbd\xab\xab\xe8\xfa:\x17<\x06a\xa6\\\x8d\xc9\xbc\xa2S\x95\xa6\xe4\xb5\xd2\x1b/4R\xa7\x94(\xb7\x1a@\xdde\x0e\xc7\xa1Q)I\xe9\xdb\xec3\xe2\x12\xbaF,-)\x05^\x05i\xb0f9K\xe1\xebm\x1a}M\x19\x05.\x19\x04\"gU-\x81\x80\xc9Q=,<\x01_.\\\xe7\xc81(s[\x94Q\x8b\x14g\\h\xd3\xea|\xe5xp\xc4\xe9\x02\x8c9a\xa8\xd7\x8f(S\xc6&\n\xf3\x9a\x97z4\x1d\x9e\xc3\x04\xff+\xaeV\xbd{\xb7\xbfD\xf2d\x18\xf0%\xa6\xfb\x99@4\xf89 \xe3Z{|\xf5x\x91\xcbA\x9e\x86k\xd7\xf3a\x0fS\x8d\xcb\xb4\xc54\n>\xe6\x06\xf3\x17\xef\xe7\x02&\x90\x91#\xc3\xa5Ew\xbd(\x07\xf0\x16\xcc\xff\xb2\xcc\xf9/\xeb\x02\xc3\x05J\xc1\x17\\\xf8>\x92\x81\xd0\xa4\xd4\xc1\xdfV\xa4\x8e\x1c\x8e\xe0V\x80\x9bV\x18\xc3\x96\xe6\xa9;\xf2T\x10n\xe3\x07(\xa2\xad\xc9N\x1c\xa7\xd2\xc5\xdf?\x8a82e\\\xac-\xfe5\xd7\xd6\xcd\x8b\x82\x91\xffl\x8by\x02\x13py\xe5\xeb\xe9\xf0\xdc\x1b\xe4\xc9\x0f\xc95K\x8f\x83\xcc\xe8>^\x15\x08O|\xa0-\x15\x13\xbb\xaey\x1f@m\xb4x\x19\x81\xab\xa6\x18\xc1\xf0r\xb0\xc6H\xea\xfb?q\x96=\xfd\xe9\xdf\xdf\xed\x9f\xf7\xfe]\xfc\xbfo\xbc\xef\xca\x87\x8dn\x83\xfb\xfb\x0e\xc2\x8e\xea~\xe8\xc3\x81a\xd4{7\xd4\xdd\x9d;\xb0\x9e^\xe3\x8dZ\xb74\xec\x03\xaf&\xd5V#\x91\xd6\xe7\xb0\x87m\xf1-,\x9a\xdf[N\xaf\xcd\x97t\x95&}\xe6\xc3\xb1\x8f\x9e\x87\xfd\x91\x8f\xde\x82\xc3\xc7\xf0\x0c\x9e\xc0F]\x85zfNP\xc6\x1f\x81\xec\xeeK\x1c\xbeD\xf4\xcd\xf4\xd9\xb9\x88/\xdc'tz\xcf\x87\xf4\x12\x9e\xc0{z\xcd\xfb{iP\xaa\xb8^J-\x1e\x13)\xa1\xcaGpY8\xffpJ\xf2\xef\x98\xa9\xbb\xf6\xd2\x87\xf7\xa2\xdf3ZO\xbcw0\xf4\xe1\xd8S\x90\x81\xaf\x8e1\xa1}YM\x98\xb3Y2go_\x9f\xaa E\xee\x99\xe7\xc9\xb5\xb1(\xbd\xda\x82-\xba,\x18_\xf2\x97\x8f\x8bi\x96\x17n\xf1y\x0bG\x15d\xb1K \xfce\xddG[\x95\xf7\x95Uy\xef)\x12\x94f\xec\xfb$\xcb]\xaf\xae\x14\x95\x7f\x7f\xf8\x00\x8e%\xb3\xd6+<\xd7&\x9c(U\x12\x8e\xe7\xce\xb9\xe9[\xe9\x974'\xf4adP\xd5\x11\xec_\x99\xef\x81+\x00\x7fS\x1d\xb2\xa0\xec\xfb\xef\x06\xfb\x9e\x0f?r\x82\x83\xbb\xe8\xc3\x1b\xb9b\xb4\xa1?6\xee$\x88Y\x9e\xc2\x04\xdeL\x9f\xb5\\\xa2?Et<\x15\xd4e\xdezq^\x0d\xffgA\x85_\xd0\x10_\xc3\x04N\x15\xa0\xbd\x80'\xf0\xfa1\xbc\xe0\xa3<\x1d\xccVAz\x9c\xcc\xd9\xb3\xdc}\xe1\xc1S\x18\x1d<\x80#\xf8\x19z\x13pn8\xcf\xc5?O\xa7/\x1a\xc6\nrY\x7f\xee\x97\x8b~ \x19\xc2\x198\x1e\xf4\xe0\xd2\x80\x15\xcf\x8b\x12\xedc\xb9LY\xf0\xbe\xb1T\xdd\xbc\xd4\xfc\xa5\xfe\xd6\x88GO\xe1\xe0\xde=\x99\xeeA\x1b\xbd\xe3H\xc9\xc0\x86\xe8eV\xec\xc3+-vvQ%\x1d\xe4\xc9\xb3\xb3\xe3\xd3\xd3\xf2\x17\xd3\x05b\x0e2\x7f\x93\xbd\xa0\x15\xe6\x08\x9c1\n\xa1\xea\xcd\x98\x83\xbeq\xbe\xdfu%D:\xe9\xfb\x0ez\xf07]\xe8\xeai\x8d\xf0))\x01\xc8\xba\nRb\xf2\xcd\xeb\xdb\x07\xce\xbb9\xccp\xea~)\x08\x9d\x06H\x97^+\x1f\xbf\x9a\x9e\x9c[.E\n:\xc5i\xd6\xac\xe06\xad\xa4\x8a/\xf5/\xbc\x8e\x95L\xf1\x8e\x05//\xb8\xd1/\x8d\xa8\xcf\x1b\xfd\x96\x8b\xd8q\x8dm\xfe\xd2\x80\x02\xdf\"\xc9\xff\x05\x97\x05\xabg\xb3`\xc3x_\x8a\x17!y\xfe\xc5#\x84\xfa\xd6L\xde\xeb\xf0^\x97A\xffR\xe2\xad\\\x92/\x18\xef_\xb4\xbd&\xcb\x9e\x92\xbe\xfeR\xe1\x8aC\x1f\xfeR\x05`\xde\xfc\xf7\xe5\xe6\x8f\xaa\x88\xaf\xad\xe9\xf7u\xf1]u\xf7\xbdW\x11\xb1\x8b/RH)\xc6*\xcb\x94\xa4||\xe9\xd5G\xfd\xfd\x8eb\xfdeQR\xd3A8\xb1[NO\x10\x90\xcb\xb8\xa1\x82w\xab\xd2\xa6\xfa\\9\xabj62\xbb\x18\x0d\xc8\x04e\x05e\xd0\xea\xd8\x04\x8d\xbf\xaa\x88\xb54\xc1&R t\xaf\xbfA\x0f\xfe\xda\x80\x89\xba\xba&\xf43\xfc[\x1a\x16+JP%^p\xdd\xc8i:eU\xd4\x05\x05P\xc3\xa0\x992~\xe2?\x06Lc\x9e\xa7\xc5\x199|\xb6\x1f\xfa\x9c\x88\x92 \x7f\x02\\N\xae\x03\xae\x8aM\xac4'\xec\xbbNhc\xf3&\xd4\x0b\xa6Z\xcc\xe2\x95\xadPh *\x1b @\x96\x87YP\xed#2\xcb\xdd!\xf5\x14+\xe6\x18#\xc1*\x9c\xd1\xb0.\x86\xe0p\xberD\xc0\xc7r]\x0ex\xfc[\x0f\x8f\xad\xb6r\xe2\x18\xa8\xabR\x94/\x14-\xca\x16ij\x0fB>Ht7/phz\xf4\xd5y)ZOSLQ#B\x96\x89\x8a\xc7\xe5E\xec{\xab:q\xber|p\xfexp\xe8\xe0\xd7\xd4FEL\x87<\x96\x83\x18\xdc\xa2\xf2\xe1\x8b~.\xe3)\xba\xd5\xd2\x97\xe1\xf4\xc7du\xac\x18\x1d\xcd6\x91\xdcl\x16\x85\xe24K\x1b\xa1O\xd4\xb0\x81\"\x97\xe2\xb7`\xbb\x14\xc2\xa5\x8aQ\x9e\x8f\x14e\xf8\x18\x02x\xa2\"\x84>\x86\xc0\x9ef\x1d\xfdO\xa6\x81\xc9\x83q\xba=\x17\x086\xdd\x9e7\x8c\x8eB\x93\nQ\x02\xbd&V>\x97\xaa\xc9\x96\xc89H\x11\x0cH\x1d\xf5i\xdc$\xae\xcb\x0eL\xe1\x1c\x85\x82\x90\xd4\xba\xd1\x9c\x93\xd5\xc3\xac\xa2Uu\xf8\x18\"x\x02E\xd6\xf9\xa8Y\\\x9c\xc1\x04\xb2id\x11\x17\x1d9\x16B\xb5\x19\xe1\xf1tF\xd1\x08f\x06\xf1\xd5z\\\xbe\x9c\xc6jf\xe2:zI\xc0\x88\xcb\xd2E\xacNN\xeb2\x86ya[6\xadXW@g_\xf5\x8bHU\xd3\xa2\xa3\xb4\xbe\x9c\x16u\xcem+Z\n\x96T\xdd\x9e\x0dm\xcf\xa6dB\xda\xb4\x1b\x1e0\x04\xf1t\xd3\xa0\xcc\xc7\xd39\xed\xc8\xdc\x12K\xcc\xf8\xb6\x11L;l,\xa1\x82f\x95-\x16\xc8\xe7\xb8\xc09\xf8\x87\x0f\xb0./\\i?\x99\xfaQ\x9f\\CD\xb7R@D\x97U\xc4\x16O\x9a\xf4\xf7\xb9\"\xb0\xd2X\xee\x9e\xcb\xa4\x8a\xb8\x1a\x90=\xc0\xabEx\x92O1\x83\xa2\x162*V\xd2E]V\xd6\xaf=$\x07\x1c\xa8VB+\\)\xe3\x03~]\xe9\xfe\xf8\xf5\xcf\xa5\xf5Y c\xc3\xbe!\xdf\xbbmC\x94\xf0\xcf\xc4\x9f\xbcM)\xff3\xfa\xcb\x17\xd8G4LL\x93+\x0b\xb14\x922\xfc\xc3\xd7\xb1tR\x999\x13\xeat,}+\x18\xfeQ\x9a\xc2\x87\x0f\x107H\xff @\xfc\xaa\x8c\xe8\x16\xc1R>x\x04\xd8\xa2\x03\xf0G\xd1\x90+\xe8\xc1m\x87\x05T\x18\xa1y\x99\xe8\x02\x91\xa2\xd4\x9f@\x83\xe4IU\x99\xce9\xe2(\xa1x[H3\xf5\x05\xb8(\xed\x173\xb6\xc4:\xb5t\x0d\x13\xb8\xe0\x8d\\\xd2\x16a\x9bD\x17E\xedz\x9d\x13\x98\xc0u\xfd\xf5MmR\xdad\nL\xe4\xfdL\x0d\x11\x17\xcf8\n\xafJ\xb4\xa0<\x90z\x1b\x1a\xb9\x06:\xfc\xd0X\x8bA9?\x13\x1c\xa5\x84\xa7\x1a\xdc\x92sN\xb1\x08\xae\xe0\xe77\x1c\x81\x8f\xe8\xbf\x89\xfc>\x86\x1b\x85\xb0\xf4\xca\xf34t\xe2\x0d\x97YM\x99@P_\xac\xdc5\xabu\xbd\xa2\xaeW\xd45\x93]\x17\xb4\x82\xa9\xae\x15q\xc2\x0c\x7f>n\xedu\xad-D\x135+^\xef\xc23\x13\x01)\xca\x90R\xa6\xba\x8e\x15\xb6[ B\xa9.\xbe<\xd2\x7f\x8c\xb5\xba>t%T\x1c\xbc*WY\x903\xf0\x8d]\xa9\x13[<\nso\xe8*\x8b\x0f7\x83M\xb2\xe1\x18\xc9\xdf\xdcH\x17\x96\x95\xd7\xb5[K\x7fx\x08\xffb\x1bE/\xd3\xb71Et\x9e\xbb\xb2\x19\xa3|\x8c\xe0\xe7\x95\x17M\xad\xfa\x8d\xe4A>\xb8\xaf\xb8\xd2\xbc\xe7\x16@H\x7f\x15\n\xed\xbf;\x1eyD\x17\xdf\x04b\xfc\xbb#\x8e\x92\x14\xf1~U4\xac:+\x0d\xe1U\xc1\xfd\x1a\x88`\x87\x85\xf2A.\x89[`=\x8eF{/\xe9?\xdf\"E\x93\xb5\xf2p\xa4\x13\x901g\xa2\xa8\xb1\xc9\x11\x1c\x15\x83\xc1\x8f\x9f*\x02\xee\xdd(xQ\x93\xdcT\xbd\xf6J\xbd\x8a\xb1\n\xad\xb5\x18D!\x9dJ\xd2\xd1*\xe9+\x99\xe5\x98v\x1e\x8dw\xfd\x91\x87^\xb0\xefiA\n\xca.\xff\xba)\x0c\xfaB_w\x06\x84e\xc7\x88q\x03\xf9\xcb\xd3\x10\xf0X\x9c\xef\xfa\xf0\x12\xfb\x92\xb2\xe6Kx\x8a\x12\xe8\xcb~\xdf\x03\xd9\x0e\x1e\xc0\xdeL_\x9e{\x9c\xd4!L\xcd\x98\xfbR\xdc\x7f+:\xe0J\x7f\xf9\xb3O\xa6\xe81<\xc3\x81\xd5>\xf6\xfb\x06Z\xbcG\xe7\xd5'\x16\xc3\xf7c^\xed1<\xf34*\xcb\xc7Pi\x89\xb2\x10\xead\x9a\xaf\x95\xb8\xfb\xf0\xf0\xfe\xdd\x07fM\x8ck\xfc\x87\xf7\xcd\xdff\x18f\xdc\xf8\x89\x83\xf9\x81\xa5\xda\x867\xf9\xd0\xfcm\x0e\x13xP\xbd\x13'\x1f\x8ez\x0f\x0e\xcc\xdf\xb8n9:\xb0\xb4\x8a\x91\xf1\xfa\x16]s\x89~\xc97q\xbf\xbfo.\xc0\x05\xa1\xfd\xe9O\xefn\x0e\x86\xfdw7\x0fN\xce-\xe5.\xb1\xdc\xbb\x9b\x83\x93w\xdb\xc3\xe1\xf0\xe0\xdd\xf6\xbb\xef\x86'\xfc\xdf\xfb\xa3\xf3\xfd\xa5\xb9\xd2\x855\x8f\n\x7f\x92+\x96.\xa2\xe4z\x0c\xceK\xf5'Em\x8c\x19\x9bgp\x1d\xceY\na\x9c\xb3%K3\xc8\x13\xd8\xa4\xc9\x8ceY\x83b\xed\xc4I\xde\xbf\x0c\xb2p\xe6\x8c\xc19\x8d\"\xb6\x0c\"\xd1*\x17\x1dn\x1e\x0e\xc1\x8d\x93\x1c\x02\xc0R\x80h\xb4I\xc28\xf7\x9a\x9a\x0d\xe3\xab \n\xe7}l \x9b\xa6\x17\xd4\xb49\xf1\x9d!\x9d\n\x08\xc55\x82>\xcc\xcc\x9f\xb9\x8e\xfac\x90\xaf\x06\x8b(\xb1\xe5\xae\xe4:\x01\x19\xb5\x07\x8b4Y\x1f\x0bo\x1a\xcd\x9dX>\xca\xad\xf8\xcc|<\x00*\xc6\xfe\xeb ^\n/\xdc\x8b)3\xdaE\xed\xad\x1f[o\xd4A\xd5\x1e\xaeB\x85\xa2I|z\xfe\x18b\x0c\xc4\x9eR\x84X\n]n1hI?\xe5\x9d\xc6\xf6\xbeql\xc5\xb0\n\x89\xc2\x0e\x07\xa9\xe1\x00P}\x93\x02y!\xef\x82<\xf8\x89\xb98\xd5\x03\xf4\xfbC\xceON=)\xf4\xe0\xd8\xa5\x13Su\xe6r\xe9s\xc9\xd6S6@\xca \xeb\x15N;;\xcd\xfe\x99}\xdf\xd5\xb6P\xac\x06\xda\x0e\x1f\xaf:\x0d}\xe1D-\x05\xef\x84\xae\xa9\xb9\xa4jk\xee[I\xaf\xe7y\x1c\xb5\xee\xdd;xt\x9f8\xc7\x93 \xdc\xbb\x7f8z\x84R\x0b\xaf\x08G\xfc\xc5\xc1\x10\xe3\xa2\xdc\xbf{ot\x00\xe24\xad\xde\x96G\x01\xce\xb8\xbc\xea\xba\xa3\xe1\xc1!\xdc\xe1\xbb\xf7\xe4 \x8c\x86(\xc5\x88w1\xffq\xff\xde\xbd\xc3\xfb(X\x89*9\x17\xa0\xb8r0\x06\xf5\xe6\x0b\xc2\xd2K\xfbj\x8a\xf6\x10\x13\x9a\x8f\xe4\xe4#O\x9el\x00\x05\xfa\xbd\xa1\xa78\xd7{\xa0\x0e}\n\xa3!\xdc\x01\\\x9e\x0f\xb4\x1dB\xa0\xa1\xb5\xff\x00b\xe5\x18\x1d*\xf2&\x0c!\xcd\x01\xcf\x02\x05\xb4\xed\x08l\xaf\x1aQM\xcd\xa5\x07\x07\x07\xd0\x83\x07\xf7\xe0\x1bp\x19<\x81\x83\xfb\x1e\xf4\xc1u\x87\x18\xcd\x0c7\xfb\xden=\xbf\xb1\xdd<\x90\xcf\x95\xb8\xfd`I\x89\x82\xb8\x80\x98 Gp\xe22\xd8\x879\x06\x95\x03\xbe\xae\xc2G\x81\xde\xe7\xdec\xdc\x8fk\xf8\x06\x16\xf8\xf91G\xe4 D\x1e\xae6\x95\xban\x06\xbb\x13\x97\xe3\xbe{\x8d~3\xf0\x0d\xf0*._\x99\x8d\xb7\xdb\xc4\x7f\xb4\xc3\x98\x86\xdaz\xce\x18L\x075\xf7a\xe9\xc3-9\xe2\x98\x8c\x9a\xf2\xb9\xd0I\xb6\xb5\xd4\xb5\xf9\x16\xbe|8\xbf\xba\xb2\x7f>\xae\x1b\xc8\xe4\x83\xfb\"(\x85\xeeA\xbd\xf6f\x82\x82\xd0\xf3\xe1\xc4\xbdF<\x86\xa7\xc0'xc\xe8\xea\x86\xf0\x9d\xca\xf1\x89\xfe\x11\xb3\x03_J\x0b\xd1u\xaf\x87\xa1\xa7n\xba\xfa\xfcA\x81\xfb/\xdd\xcb\xddp\xfc\xf4sq\xdc\x87\x0b\x9fC\x9b\xb8>QMr!\x1f\x04\xccK\xe9\xc3\xf5\x0c]\xb6\xa4\xb0\x96#\n\xa3\xa8$\x84\x83U\xc9{\xe1\x92c\\\xe0\x11tN\x83s\x8e\x9e\x02\xd5\xde\x13j\xdd\xb85\xaf\xa0R\xc7)\x06{\x99\xc0{\xd5g\xa2\xd5^{\x84\xd9\x97\xed\xa8\xc5\x91)k\x19\xdcS\x91\x81\xfc\x16\x9e\x88,\xe6\xbc\xd6m\x837\xa8h\xba\x0fy\x81\x1a1G\x0d\xf7\x02c\x82pBn\x02\xda\x98C\x12U\xe4\x84\xfe\x82\x96rk\x1a\x9f\xb5o\x10\xa6\xc7\xd2\xea\xe2\xf8{\xbd\x18\xa1\xb8\xde\xef-P\xda3\xfbb\xc9\x07g\xc6IK\xec\xa3\x8e\x1a=\x96\xc8\xcc\xd1q\xce\x919\x14\xc8<\xe7\x0b\x17j\xc8<\xc70(\xdec\x98\x0bd\xe68\xb8\x81>\x87<\xa9\xe8,\xfd\x02\x04^\xb9K.\xf3\xc2\x1f98\x0e=O8\x15\x9c\xb8\xc7\x0dF(O\xf9\xb4\x13OAj\xafW\x97\xf0\xf4\xe7c\xaf\x17\xf3R\xf5\x84S\xd0\x86\xc7\xef\x9b\x84\xa4\xea\x9b\xadU\x17\xbebi\x16&\xf1\x18\x1c4\xe6X\xb4\xd0\xed,;0\xe5\xb2\x96\x0f] \x1a\xc33;\x9b%\x1f\xb01\xbc4O\xd5b\xb4\x10\xed\xfeh\xfe,\xdb<5\x7f\x16.\xf6\xe3\x8e\x12\xb1\\\xd8\xee2\xb4V\xebv\x90\xb3,\xa7\x98|\xceM\xdc\xef;\xd0#\xd2iJ\x99-\x9f\x8f\x16\x02n\x9b\xcf\xdb8\xa4\x19w\x1b\xdfg\xcdh\xa9\xcd\xe8GW\xe6\xa6\xb9[\xb9k\xf8i\xf3\xab\x83\xac\x0fZ\xbeD\x94n\xac\xa6Y\xf9\x88qn\xeb\x8d\x15\xc1nP,g\x14\x02\xd3\xd5c}$\x15\xffC\xdd\xe3\xcf\x90\xe6\x86\xffy8\xb2d\xbb\xe9\x14\xdfC\xef\xbc<\x1f\xe9\"\xd8\xb6\xabb\xbe\xa6\x0c%\xe5\xb9\xf8\x95\xe6\xc9\x91\xaak\xf3\x16K\xab\x88\xf58i\xeb\xec\xc56\x8a:v%\"\x85vjR;1\xde\xad\xf5\x1dC\x89u\xda\xcb|@\x84 \x0d\xf8\xf2\x16z\xec>|\xf4\x88+\xb7\x03\"Kd\xdd\x97\xde\xc9@q\xaa\xba%\xf3.\xf7\xaa^+\x91,m\x8a5\xd2\x12\x99J%\xb1\xa9e\xf0\x81\x96\xb0\x87>\xd4l\xf8x\x84\x81G\x89w\x1cbzxC\xd8\x99\x18\xf2\x8a\x07\x86L\x90\xa19M1zC\x0c\x853D\xe5\xc89\xa8\xb7\x8cqE\xde\xf5\xf6+\xc29\xd3\x0ckU;\x8ct\x01\x1d\xb1\xc3\xca\x888\xac;1\xe6\xa3\xd1q \x1c\xac\x83\x9b?\xb3[\x14v0\x85\xa9zch:\xd2\xcdW\xa5\xaf\x99\x0c\xf5\x19I\xc9 \x13PV\x1bQ\xd61J\xa4\n3\x8c,\n\xbd\x9e1\x833zLJ\xa9{\xe5\xa3\xc9\x9eMg\xc5\xfd\xff-\xfaQ\x0fm\xc6\xc55\x17\xaf\xd5\x81\xa7)5\xc6\x1a\xed\xd7p\x04\xee\x02\xcb\x16gTk!D\xa9wk!\x8c\x8eEY\xfa\x8c\xc7\x94s\xf3\xed\xe1\x85\xe7\x83\xe5b\xf1\x86k\xd6n\xe0\xc3\xdc\xa3\xb0\xd3\xd39\x1e\xb4\xf3\xffI\x16[a\x1cTr\xe0\x9c\xf2\xff}X\x9d\x17\xafV\x16\xec\x87\x02a\x82\x02\x0f\x8a\x89\xe3\xf9\x97\xcc'6\x083\xfc\x9f\x83e\xab\x8by9Q\x90\xb8\xba[CJ\x19&\xb2\x1ecgw\x02\xa1\x8f9m\xf4IWYld\xf8\n\x030atO\x89\x94\xcdA>\xebpB\x95/)gTKm.)\xe5\xe9\x96a\x94\x8bE\x10e\xcc`\x8a\xa4\x06\x05>6\xe7B\xc9\xbe\x0b\xe30g$\xb1\xd0\xc1s\xbd\xbd9[\x04\xdb(ol\xc9q,@\xf3\xd1\xcc\xce\xeb\x84\xb2\x16sX\xb4l\xa7\x97\xbe\xc6\x0dA\xdef\"\x91\xc8\xb3\x1c\x7f\x1eA\xe8\x06(\x9b\xa8\x01\x046\xea\xc0I\xa4\xe1\x16F\xea\x06x\xb5\xc2\x90wW\x8c8qI\xe3\xe3\x9d\xf1\xbf\xba\x08\x92R0\x83\x9e\xb9Of\xb22\n\xa3/\x86\xc2\xb2\xd7\xe4c\xa9\xde\x1c)U<2W\xdc\xd24\x1bF\x84\xf0\xf2\xfb\xa2\x04\xe6`o&\xd6O\x0e\xfa\xeb`\xa3\xe5\x92\\\x07\x9b\x1a\xdb+\x9d\x85M\xcfKV\xcb\xe2\xb8%\xed\xf5<\x99\x035w\xd94\xe5\x05-\xfe*\xd5d\xa8\xa0q{\xcd\x81\xbfy\xbd\xae,\xf9O\xcba,\x99\xd7Y\xb6\xa1 \x97\xbfR\x1a\xd4\xda\xea\xef5\xeb*fb-\x9fn!0\xe5#\xc6\xee\x96\x82.\xe5\x82\xde\xc5\xec\x1ar\xb7\x80(\x97S\x8e\xcb0\x0e\xd2[\xc7\xf3\x8a\xd7\xcee\x90\xb1\xfbw[-\x07V\xa5\xe8\xde]O$M\xed$\xce^iY)\xcdA\xdd\x0f, \xcf\x0f\x87\xe6\x84\xe7\xf7;\x05\xf47\x1c\xc8(\xde3\x01\"\x9d1\x14\x19\x0bb\x91\xb1 uC7\xf6\xd0\xc2\xaa\xc4O_$ \xc6P\xacB\x17\x8e\xd1\xbeV\xb8\xe6 un\x81*}@\x9f6p\xc9 \x84\xbe\x8c\xd7o\x14\xc7`\xf0\x84\xe6\x81\xf0\xe0)\xad\x1a\xaf.j\xa5\x9eN\x14\xd4\x90\x13\xf4n\xc8p\xa5%\xfe5E\x84\x1f\xd57\xf3n\xdb\x86YfL\xb9\x16\xe0\x03\x84m2\x92\xde\xc0^C\xc3\x16\xed\nt2\x9b\x9bQ\xd0\xaa\xaf\xc8\x95-.\xfb\xf9\xb0?\xfd\x89\x02\xf2\xbd\xeb\x7f\xf5o\x7f\xbc\xf3\xf57\xbd\xc1\xbb\x9f.\xfe\xcf\x87\xff>\xdf\x0f\xa5m\xc5\x12\x88L\xfaw\xccVA\x1a\xccrtD\x81\x15\x0b\xe6,\x85E\xc8\xa29\xc4\xc1\x9a\x99\"h(\xf2_\xb2\xd2\x94\xd1\xda2\xe7\x8ef\x87\xb6iW\xf5msg\xa9\xb93\xc9 \xcc\xd4/f7\xba\x19\xc3F$Ak\x88I\x7fK\xbbqWL\xd0\xde\x16\x7f\xe6I\xcc\xc6\xba\x8d\xca\xe0\x10\xa8?\"6\xbb\xd9\xb0\x0b5Rk\x7fkH'%\x06\xbc\x1a\x849\x85\x88\xa7s\xf9)%/\xa5\xb7y\x92\x9e\xef`D\xab\x8f\x13\xe3\x97u\xda\xca\xc4\xbc\x95\xe8\x9f\xb8\x0e6\xa8\xf6\xfb\xe50\x81\x89\x0c>z\x12\xccV\xed\x81\xb1Us\xc1f\xc3\xe29%\xbb\xa9\x8f\x98n`\xa3G\xb5.\xab \x85\xc0\xd0]\x97\xbe\x18:\x98\xb3\xe9\xc8\xe4\x94T\xf4\x88{ \xc4\x93%\xcb5\xa1\xe4E\xb0f\x99\xcb\xbcz\xff\x9d\xe7:\xcd\x1b:\xef\xb4G\xa1\x9d\x9e\xb1\xc1e2\xbf}\x9b\xb1\xb9\x12\x1e_\xa5\xc9:\xcc\xd8 exC\xbaB\x9c\x9eE)\x0b\xe6\xb7\xc0\xffuL\x87jE\x8b\x18\x90\xad\xd3\x00\x83f[\x1e\xbb\x96\x83j\x0f\x02\x0e8\x84$\x8e\x92`\xde\x05\x05\xf8\xc3\xc5\xa6\x94e\xdb(\xb7Y\xe4\xb1I\xc6W\xa0k\x9b\xb1\xcb\x06X\xa1\xb3\x11\xbc\xdb^n\x9bI'_\xab\xef\xc2\x88\xbdFva\xa6R1\xca?&\xe7$I\x0f\x06|w\x9feZ\xb2c\x12\x97:\x8d0k\x826\x94\x9dj9\xef\xabn\xfdP\x99Q\x91b\xd8-\xa5\xe9l\x98A\xc6\x08t\xf5\xaa\x18\x82B\xa4j\xec4\x95\xa8)K\x05\xe2\xa9\x0e\xeb2\xdc\xd1E\x18\x87\xf9\xb7\xc9\xfc\xb6\x93P\xcf\xd7\x85\xaa\xf1\xb6N\xe3\x10\x19\x97\x91\xc6\xe9UL\x07\x01\x1e\x14\x0d\xbda7\xd8\x90\x9d\xf3i\x17\xc1.\xa3\x04\xc3\xda|\x1b%\x97\x9a~\x15f\xaf\xe4\xdf/\x17B^\x91\xed\xf3\xa2\x9d\xdb_$\xe9\xfay\x90\xa3\xf3\xf4w\xe2\xef\x8e\xfd\xc8\xe2\x9d\xfb\xa2\xcb\x05\x18\xcc\x15-\xaco_\xffp\xa6\xbd\xea\xd8\xad\\>M\x9d\xea\xd4{P\xa0\x0c\xe0\xf5d\xb9\xb4\xebJ\x07\x1an\xc1\x84\xe3\x8cL'\xeaC\x0d\x1a8\x1c\xf3\xf5v\xa7\xc6\xfa6\x97Uh\xbe\x07.\x1f\xbcXT\x1e\xf9\x87\x0f\xb0\xa7u\xd0\xb0f\x80WH+\xb2\xac`\x15\xdb8\xdbn\xb8\xa8\xcf\xe6\xf0\xad\x9c\x0d\xaf\xd9\x16\xfc\xada\x95\xecH!s\x94T\xb7\xd0\xe6\xe2H7(\x90Lf\x9ci\xbb\xce,\x89s\x16\xe7}\x1a\"\x1e\x1a\x9a\xb0LE\xc6\x11u\xb3Z]\x1f\x9c\x9c\xdd\xe4\xfb\x9b(\x08\xe3\xc7\\\x8c\xcfX>y\xfb\xe6\xbb\xfeCG\x05\x97-\xb0H\x86\x8cRo\x06\xbc\x95.\xdd\x18\xaayx\xd1\xf5\xd3\x91@\x8d\xa6qz\xc1f\x13\x85\xb3\x80S\xb6\xfd\x9b\xfe\xf5\xf5u\x9f\xa3x\x7f\x9bFda\x9bWgm\x94`\n\xec \nxI4\xa5\x95\xbf\xca\xeb9!\x8521\xef/\xf2\x1b[@j\xbdPy\x11\x0db\x90\xc8\x04P.\xd6\xa5=\x0dz\xad\xcd\xb6\xe2v\xa7\x9e$\x954`\xe1,\xd9r\x8d1\xc9QdS\xe4\x17x5\x082\xe0\x8bnC\xc8\x1d\xc6\xcc\xb1\xadj\x9d\x85BP-\x91\x97\x0e[\xac\xf3\xd8\x1a%8\x92;\xcfq\xd4\xbeO\xa5\xe5\x17X\xc7g\xebz\x83|\xc5bwk2D\x8b\xe1\xe6D\xfeZh\xd2m \x8ak\x05\x06\xc1Q\xda\xfb\xd85i\x88n^\x98\xf74Kx^\xb1\x84OQ\x956\\yq\xf3i#\xeb\x95\xda\x8b\xddU\x0b*+\xa6/D\xa7\x95\xfb\x0c\xb4\xe7\x00\xbe#\xda\x97\x91\xddB\xd1uQ\x8fj,\n \xae\x15\x9dt\xb4\xe7#\x94\xa8\xbah@\xd5\x9f\xb3$\xfe\x9c\xb6\xfft\xf6\xf2\x05\xf9qX\xa9W\xe9\xbdMY\x98Y-\x18\xf2\xcc\xc5U'\x80\x7f\xff\xe8\xa1\xeaP_\x7f\xa4\x15\xba\xb5\xc4x\xe6\x0f\x06\xf5\xddhK,\xab\xeb\x0d\x92\xd06%\xb7\x85m*S\xed\xccR6gq\x1e\x06QFn\xdf\xc5o\xaeF \xf9\x00\x8a\x00\xb7\xe2\x05\xa1X\xe22\xf9FE\xfe[\xb3|\x95\xcc\xb11\xfaS\xbe'\x87\x19\x86\x7f\xf8t*\xaa\x1cx4I\x18\xef\x1cC\xe9\x9d_\xb57\x18\xf6P\x13\x0ci\x96\xca`i^~\xc3\xec\xf3\xd2o\x19\x98\xb3\xf2\xceI\xd6a\xee\xf8\xb0W,NE\x98\xb2/Vn_\xacv\xd2W\x98;\xf3\xe4\xedfc\xcf\x04\x00\x05\x1a\xdc*\x8f\x0ftF\xef\x8f\xb8\xbcit\xe7\xfb\xe8\xe6r0r\xe2\xc5O\xe7?N\xde\xa8\xe8\x87k\xe9\xf8\x84\x7f\xa8\xc2\xe2\x87\x96\xc5)e\x0b\x96\xa6( \xd0[\x17\xdb)BRj\x1d|\x7f\xf2\xecy\xed\x0b]\xc7\xb7\xc0<\xaa\xdex\xd12\x8a\x92k6G\xb6\xf0\x1f'o I\x81\xb7\x06)\xfb\xdb\x96eyfB\x08\"rR\x83w\xe3nV\x99E\x07\xab\x8c \x83MV{L\xb1!/\xdf\xddq\x0cV\xc3F3B\xabxP\xbam8i\xbam\xc8\x9f\x94.\xdd\x93\x05]\xcb&\xd2\xc3l\"\xd0V\x1d\x0f\xf7\x04\xf3\x9b8\xc6\x06\xec\xcc3\x97\x16P\x83[\x10\xd7\x91\x0d\xaf\x13\x83\xf4 \x16S[W\xeb\xf6\xa6}_\x93\x86\x0d\x951\xf4\xd3\xa3w\xf1\xfe.\xbbY\xdb\xacq\xdb\xd5\xd0b\xa3\x08\x8a\xec\xe2C\xed\xb6\xbf\xfeH\x7f\x07\xb9qc\xa7\xb9A\xd0\xf7*\xf5\xab\x9e\xb5\xf2\xf9\x9c=\x98[\xf9*q\x84\\O\xb8B\xaa\xf3\x04\x1c\xe1\xea#\x95\xe4,\x0f\xf2-'\xb7\x0e\xfd\xe5`jLN\xf3\xe4\xa71\x1c\x0c\x87\xa2t\xf2^\xc5\x8b\xa5\x8fO'\xfc\xab\"\xe7\xe2\xed\x138TU\xe8\x95\xb49\x14\xbfj\x1da\x9118/\xff,\xc7f\xe7\x05\xbe\xce\xb5r\xfc_\x84\x9a\xab\x90\xa9j@\xd5\xd2/4\xf0\xb0\xc1\x82\xe5\xe68rW\"\x16\xa0\x19*tS\xc2\x18\x9c\x8a%\x01\xa7g\x08w\xc6\x1fy@5\x06\x87\x0e\xa7\xa80\xfaX\xcac*|E_\xcd\x8dp\x85m\x0cN\xa1\xd0h\x8dp\x0d\xa3\xf8\xd9*\x00\xf2'Oo[\xcca\xda\xa1\x03o\xdf7eO\x96\xcfG\x98\x05\xe8R\xd7\xd5\xad~odo\xcb\x8c8\xb6l\xc0R\xaa\xe6k#\xfel\xda\x0bM\xfd\x1e\x83\xa3)\x1aT\xa9\x8e\x9ef\xd1\xa8d&\xf4\x10r\xae0\x95\x9dtv:\x95\xfa\xd6\xb9\xe3\x17.P\x85\x1aV\x7f}\x1c\x05\xeb\x0d\x9b\xd7\xbf\x9e\xc6\xf9\xe8\xbe\xb9\x92\xe9\xfdi\x9c\x1f\x1e\x98\x8b\x9b\xde\x7f\x17%\x81\xfd\xc3\xfd\xbb\xe2\x83\xe5z\xea\xba\x93\\\x06\xba\xeb\xc6\x9d;\xc07\xe9/!\xbbn0\xbf\x99\x81\xc0<\x88\xa5\xf4K\x13V\xda0\xe3\x8d7;[\xe9\x8f>\xb4\xc2\x01\xb8\xd5E\x8d\xc4E\xf3@\xebP\x93h-\x11\x9b\xa8\xf8\xbbX\xd9\x11\xa3\x90\x0cB;\x8f\xdd\xd4\xc2\x82$\xcb\"\xf10\xd8L\x99\xe5\x8e\xa1V@$wO\xa0\x07\x8e\x8f\x81\xb1al\xba\x8f\xef\x97\xc6?g\x11\xcbY\xa7\xad\x17EU\x97|\"\x86\xbc\xda\xe5\xf6\x97,\xef\xd4\xb8\xda8\xb9@\xc4F\x82\x8c\x0e\xbb\xf5y\x8e\xcb\xa9R-\x1d\xaf\x82\x9d\x1c\xd0d\x07\x15\x07<77;w\x96\xfb\xca*\x93l\x80\x80\xf2\xea hk_\x08Ym\xb9Y\xe5SI\x96-z\xf4\xacs$\xe7B\xa6\xfc\xe1\xd4\x18\xe3s\xbaqT;\x957\x8c\x11\x9d\";\x98,\xa4u\xd1vkV\xdf\x8f\xba\x83A\xc3 9\xe0)\xb9p\x904\xa32\xfa\xde\x9bM\"\xfaT\xd0\xd5\xe57\x98L\x87\x99\xd8N\xef;\xce\x84\xc5y\x1a\xfe\x16S\xe9\xb6/S\x0eL\x06\xcf\x0fh\x99R\xc51H\x9b\xa1\xc9E\xc8\xb0\x00\x96\xb3\xf8[\xe4\xf3\xcfO~8ys\xc2\xf9%W\xd8}\xa1\x9e\xfb\xe0\xbc|\xf5\xe6\xf4\xe5\x8b3\xfe\xe7\xab\x97g\xf8\xe9\xd5\xdb7\x8ea\x81fZ\x97\xb3(\x89Y\x97\x15\xd7\xa4\xb2\x19ZP\xfc\x86\x15\xbcL\xe6\xb7\xfa)\xdbi\x1cZ\xee\xd8\x1aWP\xa4\xcb\xd7\xc6\xe9\xa9\x97\xf3\xd2\xcb\xf9gNe^9\xf9o\x9a\x14i\x0fc]\xdb\xb0k\x84\x85\xaa1\xae\xaa'\xf6JB\xeb\x18K5D\xd3M\x1a\x94\xcfm\x1a\x8d\x95\x9a\xb2\xc3*\xcf\x07\x9d\xfdi$\xba\xd1\x92\x91\xc5\xa8}\xa1\x1a\x82\x82\xe8\xcb\xe3X\"h5\x9b\xcf\x98R4q\x16N\xd5\xf3\x11\xcc\xd2\xd0\x95\x88c==\x1c\x8e|8\x1c\x1e\xf0\x7f\x0e\xf9?\x0f\xf8?\x0f\x0d\xe82\x1f\xa4l\x1e\xa6\x1d\xd2\x8d\xcb'\\\xa8\xfc.\x97\x9a\x95O\xb7\x96i\x11\xb7\x94\xbb\xa9Pjg\xc9\xdcz@_\x02\xdd\xae\xfb\xd0\x05\xe2\x9a\x95\xa7(\xa1\xa3\xe6\xc6\xcb\xc6;\x80\x1e\x1b|\xafT\xee\x84\xff|M\x06A\x98\xc0\x8c~f\x9b$\xc6{\x9ds\xfe\x1b5\xe7\xae\xab\xaf\xadQ\xcdi-n\x10v@\xb7\xbe \x99\xc3^\x9aml\xa1(\xfc\x9f?\xfe\xf0}\x9eo\xc4<\xec\xa6\x9apG\xcf8\xd0\xb0\xaf\xb9\x14h;\x1e\xb6\xd2\xa7r\x0dB\xc4\xb0\x13\x91\x92\x8f\x02\x9d\x8d\x1br\xc1\xf9Y\x14\xc9m\x13\x9b\xeb\x8a\xa8\xbev\x97\x110#\xa9\xfe0a|qR\xd1\xf8\xdb\xd7?\xa0\xca\x1c\xc2\x11\x84\x03\xed-\x8c\x81\x95\xfdI\xfe\xb3/\xf6\xa3\xcf+\xb5\xf8\xbcH\x93\xa2\xea\xc8\xd0\x0b\xe6\xe9\x97?\xf8257\x19\xbb\x82\xc7\xe0%x;\xe6\xf8\x08\x16\x9d\xa9\xb1|\xd2\xaak\xe8\x0b\x96_'\xe9{i^\x87E\x10Fln\xf2\xfd\x90\x8f\xe8:\x0f\xd7,\xd9v:o\x97\xcf\x17\xeb|\xc3b7Q\xc7Q \x9d\x7fa\xaa\x1d'\x8cg\xd1v\xce\xe8\xf0!)\x9d\xf6p\xc9*\x1c\\\x87\xf9\xea\xb8tND\x15\xd5\x16\xddn\xe46\x96|\xc1\\m\x17\x05\x17!/\x0c>\x00 B;\xf9G\xcb'\xe4\xea\x95\x80:B\x03\x8b\xbb\xb4|\xb8$\xc9+\xc5sWsoO\xb4C\xb7#:\x8a\x1b\xeb/mR\xa9\x99\xd8\"\xf9\x1cl\x92\xe8v\x11F\x91\xc9+X\xfd\xe5:[y\xd1_\xbfk\x90\xb1h\x01G\xf4\xdfXS\xb1>\xeb\xa2l\xec>\x1a\x9a\xae\xaf\xf0\xf7\x0f\xcd\x17\x92\x1e>\xb2\xdc<*\xef\n\x85!\xe6\x84\xb0\xdc\n\x1e2\x8f!)\xbfUQ\x02\xc6\xb5\x9c\xf7\x9f9\xbf\xc3\x87\xd5y$j\x1e\xf5\xf9\xd5!\xeb2\x0df\xef\x19\x9fHg\xd3\x00f\x84\x9b\x9e\xd7e*\x83\x0d+\x8c\xe7\xe1\x8c\x95Zo\xe7\xab\xd4\x01f\x96\xa3\xe4s]zJ\xd9\x86\x05\xad10@\xeb\xa5\xdej\x19d\xeb\xf7\xd2\x9e\x079+Y\xcdN\xcf^\x92\xe1\xac\\\xd6\x1c\x8dg\xce\xa2p\xcd\x15\xb31\xde\x0e\xae}\x97\xc1n\xf6\x0cR-}K\xc7\x90\x8a\xe0\x13\xb6\"\x7fA]\xfde\x1c\xdd\x8e\x8d9\x063\x96\x86A\x14\xfe\xc2\xf8\\vX\xad\xa0v{U>\x86\xbd\xc8\xde\x87\x9b\x17\xdb(\xca,c@p\xe6\x05\xbe\x0f\xe2y\x84\x91Q*V\xf3J\xa3\xba\xc6\x0eL\x04~Q\xf1\xc82\x1f\"\x9f\x8buE\x88\x04\xd3l\xa4%\xdb\xc0R\xd1\xdbZv\xa0{\x82F\x1eV\x89\xb8Xwe\xba !\xdd\x82\xaft\x7f\x0e\xbe\xb6Tq\xe36\xd6RW\xc2\xaf\x9a\x04\xfdP\xb9LQ\x06\xb4\x15\xa7\x93|D[\x01\x0c\xe8\xfbf\xb8\xe2\xcd\x9f+\xf4\x8fm\x81u\xb0{\x9c_\xa1\x84U\x8f\x97A\xefe \x80\xea\x87t\x10f\xe2V\xc1\x95\xa7\x0d\xff\x08\xa6s\x17#\xc4\xc3\xb8:\x07\x8f#\xfb\x84\xa3\xfd\xdc\xcd\xdc\xab\xd2\xa7s\x18\xf3\x9a\xb1^F\xb8x\\y\x9eA\xa5\xe2\x9b\xbd\xf6\xd1~n\xb2\xe0\xe0\x96\x15\xcc\xf0J\x0d\xd1\x10\xff\x8f\x97-\xdf7\x8a<\x0f\x8f\x07\"\xcb\xd6\xdaU\xdc\xdbJ\xda3\x13t\x808|\x98\xc1\x11\xdc\x0e\xb2$\xcd\xdd\x19\xdf\xe0. \x9a\x94\xa9\xf3\x92\xbc\xdd.\xe1 \xac\x95\xb7[\xafw\xd9\xa4\x7f_\xc0\x04\xd6\xd3K\x8b\xc1\x0b\xdd\xbd\n\x80\x9d^`&\x07wY\xbd9\xef^yp\x04K\x99S\x86\xb9\xbc\xa8\x0f FP\xf3Z\xd0\x96\xcf\xb3V5\x86\x1e\xb8\\8p\x06|\xe7/T\x9e\xd2\x0b\x95\x9b\xb4\xb9Q\x03\xd1\xaa\xbd\x91\xfb_&CfQ\xa0\x91\x99\xa9s\xfd:\xe1\x0b\x80n\xe5\xa6\x83 \xcb\xc2e\xec\xfe\xfd#606\xc6\xcdQ\x01\x99\x02\x89\x07x\x8aS\xdc\xf7-\xbd\xd7\xc8W!T\x05\x05\x810\xba\xd1\x9c\x88\xfa\xab\x00\x03\xa0_2\x08\xd4\xe4j9E\xaeD\xdc\x1b\x0do\x82\x81bjp\x04[\xed\xd7X\xffV_\x89\x19\n\xc4u\xe2\x11\x0c\xea\xcc\x01\x8e\xcc\xaf\xc7\xb05\xbc\xae\xf7\xb5\xb0\xf7%\xf9\x14u\xa1~a\xcb\xf2W\xbd\xc1\x8d\xb5A\x11\x18\xea\xa8\xf8s\xac\xa8X\xbd\x1d\xae\xa2\x1b\xb9N\xb1\xb1G\xda\xdfES\x86\x05]\xd9\xdb\xca(\xa5\xbc\xf8\x83N\x8b\xea\x0d\\\x15;K\xb0\x85\x9eU\xcf\x93\x1cy\x8e\xf6\xb3^u\xdd\xd0\xb7.n\xd0 Jop\xa5\xf57\xf5\xd6\x97-\xab]H<\xdaji/\x8be+^\xd6\x91\xad\x04\xd4$\xdc{\xea/4\xa2\x0bo\x93r\xd5\"\xf3U\xa7\xc8\x15\x89h0gi\xe6\x17\x1dY\xb0\xf3m\xfc>N\xaec\xa1k@\xb2A\xf1g\x93&W\xe1\x9c\xcd\x8d\xf8)\xc2\xb1\xe2\x80\x8b\xae\xa6\xb2\xa7\ni\xb7l\xda\"\x8c\x08\xa1\xd1\xa1\x95s\x12\xf9\xces1/\\\xfd\x06\xae*\x80\xba/&o\xd7\xab\xd5\x07z\xedc*\x82*oF!D\xc6\xc2)\xe8\x98\xee.:\xe1\xfd\x0bj]\xbd\xf8s\x8d\x9d\xa2\xff\xc2w\xb4h\xc2\xc0R~9\xe6\x8a?*&\xa8\xba\x07X@\xbc\xe1lF}\x1csE\x9f\xeb\x15\x8e^\xa7>\x9b\x1b\x98@8\xbd\xaeL\x06\x83\xc8\xb8U\x96\x1f{\x18\x0d\xeb\xce\x1d\xc9\xdc\xabw\x1c\x15\x0f?#\x1e~\x06O\xe0V\xe3\xe1g6\xe1\xf6\x18&p;=3\xf0\xefE\x89w\xc7\xd3c\xe2\xdd|\x07N$\xb7\xcd\\\xfe\x1e\xa3\xf8\xde(\x0e\nG0\x97$\x83C\xd6\xca\x87+\x9f\x0bV\x17>,\xab\x8c\xf5cm]\xdec\x07\xe8f\x16\x19\xcc\x9c\xcf\xd0P \x90.\x98\xcf\xff\x9f-Ko_\xa5l\x11\xde\xf0m8r\x0c1\x9e\xc4\xce\xbf/\xf2 \x0c\xe1\x08\x9eA\x0f\xdeW\"\xfc\xe0_\xbf\x8az\xdd\x82\xeb]\xf4nEN\xcd*\x12~Vn#\xb6B\x1c\xa4\x7f\xe0,v\x0c\x07\x06\xa5\x91\x1c(Qi\xa4?ME\x9au\xd29\xdb\xe4\xab1\xdc30\xc1 \x0d\xd6,g\xa9\x18\xc0\x88\x1d\x1a\nEA\x18\xd3j}1]0\xe8\x10L\x05\xda\xbce\xd5\x0ekl\xeeH\xcb\x92\xb1\xffn\xe0N\x7f\x1aL\xcf{\x1e:\xb2N\xffmt\x8e\xf7\xfa,\xbeW 6z\xdf}7\x9d\xfe4}w~\xfe\xcd\xb9gK\\\x03b\x16\xe5\xc2\x94h*m:\x86\xe3\xd4\x0d\xc5Gq\xa5\xda'\xb2\xc5n0!\x85\xbdb\xd6p\x8e\xcd\x97\xa9\x16\xcd\xacZ`/\x1e\xe8[ \x98/\x0c9Z\x15\x1504\x1a\xa5\xab\xae\xc0\xb0$\xdav\x83vF\xa7\xe2\x86;[`=\xfdQ\xc4R\xe4\xf6VB\xb3\x1b`\x08G\xb1\xa88\xa6\x08\x9e@<@\x90n\x0c\xf3\xcdg\x1cA\x0fC\xe7\xef2\xf3`::\x17[3\xf2\xa1/\x02v\x7f\xc6J\x04\xc6\xa0\x14`]\x0ci\xab\xe1\xdd\x8a&HQ\x92\x10\xa3\xc0E\xe8M\xd6\x01tA\xb0Ry\xb9\x0d\x1c\xa9r\xca\xf2\xa2%7\x1b\x89\xe4\x03\xc3\xc7\xd0\xef'm\x8d\x81@\xd0\x90\xa2\x98\xb3i\xd2\x90\xda[>(9LE\x0c\xb6\xc0Cl\xc44\x08\xd3sO\xb28\x9b{\x99\xfet\xb8M-\x1f\xb4\x18\x97\xc1\xe3H\xf2\x86Y\xca\x82\x9c\xa1\x0eg\xd2\xefl\xcf\x95\x08\xe5\xc7\xb7\x8d\xd8b\x91\x9f\x91+y\xe7\x95\xd7\x81\xb6\xc6\x1e\xc9\xd7\x1a\xfcq-\xcc\xbe\xc7\xd5\x87S 4_\x9f\xc6\xb9\xbb\xf5ad\n\xd9`z\xf6\xc2\xecE\xf0\xc2\xcdp\x88\x01b\x1f\x06\xbd\x17\x06\x9a\xcc\xc31\xe3\xab\x8c\xc2\x8c\x8a\x1c\xc8i\xc6P|\xcc\xe8\xd3\x13\xa4\xc7\x8a\xa9\xc1\x91\xda\xc0iv\x8eQ\xf0\xc7\x10N\xb7\xf8g\xeb\xc0\xcc\x18\xa2?\x1cT\xc3\xc6R\xcdm\x08l\xb3\x0f\xe5\xa3\x9b \xec\xa9\x15\xa9\x98\x9a?\xc3\xcc\xf0 \xf6\x84X\x88\x03U{B\xe9\xbd\xd1\x9e\xa0JX4\x96\xe7l\x07{\x02\x8ei\x10.\xe3$e\xba\xe4\xa7dB\xc3G\x1f\x87 \x8d\x0c\x13S\xacl\xbd\x80\xb0D\xbef\xcb\x93\x9b\x8d\xab}\xf10I\xa5n\xae\x085s\x85\xe4\x12\xbc\x83\xba\xe5S~\xc3?eI\x8c\x83=\x11\x9eZ\xc1\xa0\xf8\xe9#f\xb1\xcd\xb1\xf0B\x0e\x06\x17\xea'f\xa5\xc8f\xc1\x86\xbd\n\xf2\x95\xba0\x8b\xa5\x0c\xefy\xf1ml\xab`\xfcR\x1e\xfe\xd6\x90\xd7\xaf\xd5\xad^\xc0c\xbb\xcf\x01]\xd0\xbc\xccXzE\x1e\x9c\xd3syk\xf3\xf2g\xa8f\xfc\x80\xba<]\xbdQ\x17\xed<\xb4\xb6@\x95\x9cv]\x06\xb3\xf7\x14\xc8\xad4`\x98\x98\xa2mV\x07h\x8a\xfd=\xab/I)\x8b*\xe5\x9cJ1-\xb9\xa471<\x81\xf41\xc4\xbd^]\xcb@\xdb\xce4>\xa7e\xc3H\x0bd[\xb7N\x0d\x19VlQ\xb7/S\x16\xbco\x99\xd9\xc2\xcd\xe9\xbe\x88\xaf:\xe3\x7fm8\x14s\x11\x0b\xd3D\xa8\xdfR{E\xabJ\x81\xaaz\x1b\xa2\xa4\xe1\x08\x81R\xc8\x8a\xefF#q\xa8\x1b\x891\x94\xad,.`\x8a\x15\xfb\xa8n\xfc\xf0_n\x88\x89\xbf4jY\xdf\xac\x85\xab\xb2\x01\xd4,\x1a\x18b\x82\x92\xe9\x98\x96\xda(\xa4\xe7\x83<\xf9\xd3\xd9\xcb\x17@9X'\xea\x85k\n\x14\xa3\xe0\"D\x9epAK\xfdg\xce\x9ar\x8f\x84\xa1\xf2[\xe6\x91\x98\xb37\"\xde\x17\x94\xac3\x99\xb0\xced\xfd~\xa3X\x83\xe6\x18\xe4T\xd3\xec\xbc\xc1\xa2\xb8\x97\xd6.\x8e\xf9\xb0\xf1*\xd2g>\xdd\x9cWt\xd0\x08Mf$\xc0\x94\x8f\x98rO\xc5\xac\xb7\x9bg\x92\x0d\x1e\xd9\xac\x93+\xd6\x90o{\x13\xe4\xab1\xdd\x0c\xdc'\xf3\x98\x81\xe0\xb9\x1b\xfb\xc5\x1c\\HK\xae\xd7\x16\x03\xd2\x95\xc8\xf9\xc2\xe7n7\xaf\x18\xf2ADP$i\xa2\x1f\x86B3\xbd\xd0\x8c\x0b\x89.\x89\xa2\x1cJ[\xe7\xcb\x85\x1d2\x11`;\xee\xde\xd0o_r(\x96\x1d\x05\xf3\x86u\x87\x1d\xd6\xbe\xb9\x15\x11}9\xd5X\xa0;kr\x81\xedjF5\xfbEm9\xe0*j\xb2W`\x8f\xb9YDNMm\x08\x15\xb5\xcez\xbd&\xeb'\x07\x8e\x0d\x9e%f\x0d\xc0Q\xc3-f\xc3-\xae\xfau\xde\xbf`>\xff\x87\xed\x1d\x1fm\xd3\xf6u\xd8=\xcd\xc5X\xfd\xc5\xa5\x1c\xc1\x96\xdb\xeciZQ=+\x02\x97\x94:\xb6\x80\n,\x99\xbe\x9bE\x9cR\x08\xb3!\xf1\xf5\x82\xa1\xe7\x94`871tPL=\xd7\x98\xba\xd2\xe1\xf9\xeb\xf2\x9a\xd4\x02 \xf1\xda\x898\xdao\x95vJz\xb9\x90?\xb9bq\xfeC\x98\xe5,F\xfb\xa3\xed\x93\xeb\xac\x93m\xc6\xb6\x1b\x87\xac.\xd6b\xef\xd9m{!lk\x9e\\\xc7m\x05\xdf\xb3\xdb.\xc5f\xab ^2,\x85\x807Of\xdb5\x8b\xf3\x81\xfc\xe3$b\xf8;\xc8\xf3`\xb6\xc2\xda\xae\x93\xc4\xe59u\xad\xa5O\xb1k\x9d\xea\x8c\xbb\xd6+/@\xd7Z\xfazt0A\xc4\x15\xb9;\x16\xaa\x01iO\xb1\x99J\x9b\x80z\x86y[\x8c m\x84\xddV\x12\xa7\n~!R'\x1f\x03\xc9+\xf4\xc3\x12\xc9C\x9e\xadw%r\x80\xc7>\x8c,\x08\xc9 _\x87\xaehH\x02\xb1\x0d\x13\x0d_-\xc8h,i\xc0G{\x8bu\\\xb3\xb5\xa9J6\xe3\xdb\x9c}\n\xbeUju\xc27SO]0\xa7\xdeW1\xb5\n\xeap\x8eT\xc0\x01\x85n`\xd7@I\x99\xbcRD\xd6\x8fd\xad\x8aYJ&\xa8\x19\xff\x8dv\xbe\xb4\x9b\xa0bp \x91F\x90B\xb1Em\xbd\x9a\x01\xac\xc9h\xa8\xb4\xe3\xcfI\x02\xd69\xadW)\xe1\xafQ\xa9\xd63\x94\x1d\x95~\x8d!\xf6\x06\xd9*\\s\xf6\xdd:/\xb9dZ\xc6\xb7%\xeer\x86'\xf2v\xa2%\x06\xdd\x12q'\x90\xadi\x92\xa7\xd9DdH\xab#}!-Ck\x0d\xf6\xa3mo\xbd?C\xee\x17uK\xcb\xac\x82\xd2\xfb\xfa\xb1\x19\xd3\x8c=\x9d\x9ce\x99\x0f\x0e\xff\x831\x87\x1cij\xb56\xa2\xfciv\x12o\xd7\x14\x11\xc3P\xf7\xc3\x07\xdd\xa5\xec\xa3Kq4\x0b\xc8\x89\xe1\x08}\x0b\x12oPD\xb3\x9f@JVR\xfdUb\x04\x94\x9d|\n\x8d`JQ;p\xe12\x11F\xad\xfaQ\x85\xf4(\x1d\xa8Y\xf6F.y1ih\xba\xebU\xda\xd1\xe6\xf1\xb1\xc1,\x89\xb3<\xdd\xce\xd0\xc0=\x99\xe8\xdf\xd0t \x86\xabv \x8e\x8aI\x8d\x0d#3A\xb9\x1d\xea\xb4\x93\xcc#\x0ee\x11\xb6\xaa\x9fh\xf2\xf7\x1a_\x1c\xeb0:)9z\xd7\x8bR\xa2\xc8#Sz!\x07\xcf\xe5K\xed\xb5\xf4\x9b\xb6\xe1\x96!g\x8f\xc4e}\xc8 \x0d\x00\xb3\xc2\x8c\xd58\xb4/\x81[\xc9Bo\xea\xcc\x90\x7fG\xe9\\\xeb`\xe3\x86\xcdc5\xe4\xa4\x91\xf4\xdcz$,\xe9y\x15\xbdE\x80%7\x9f\xc6\xe7\x18W\x9dM\xe3Z\x10\xfc:\xb57\x8c\xca\x90\x87\xa6\xa4\\+\xbaZ\x18\x82G\x15\x83\xa3*2\x1d\x9d\xf3\xb5\xd4\x7f\x8eIX5;\xf0bT6\xb6\n\xae\xc2d\x9b\x8e\xc15\xf4u`\xed\xeb\xa0\xdc\xd7\xc19\x1e3z\x83r\xabx\xc5N\x9a\xd5J#Pg\xe4|\xeb\x9a\xad\x0d\n\xb91&u\xb9\x15\xcf'+:}\xf3\xa5\x13e\xc4\x85\\%\xf2F&Y\xb7\x94\xbf:\x9dF\xe7t\xda\xad\x1f\x91\xceD\xe2\xe8\xe1c\xd8\xc0\x13X\xa8\x067v#\x18o\x11#WL7\x0d\xa7\xe6+.\xf0L\xe7\x0d%\xae0\x97\xe3\xaa\xc1\x12\xb5\xc6\x12\xe1tn\x8b\xef^\xba\x8a\x80W\xde\xec\x12?\x96- \xe3\x13X7\xa9\x1b \xe6\x8a\x0e z'k8\x02>\xa8\x0e>\x83!%\xc0\xce\xd0\xebk\xba\xf4a\xeb\xae\xbcs\xa3\xbb\x99|D\x9clQs[\xbbz \x1fu\xadE\xa76m\xf3\xd7\x8av\x9a\xfb-\x1ex\xdb\x86 \x1f1V\x07O\xbd\x1d\xe1\x17VA\x13Z2\xe9+pk\xbe,)\x9f\xf2\x1a\xd8\x07\xa0\x97Z\xd5J\x18\xd5\\\xfd\xc0H5\xd3)\x17f#\xd5\"\x12$NA\x90\x84\x1dA\x8en\x1ecL\x1e\xcd)\xc1Hd6(R\x1a\xf0\x02\xe7zk\xd3\xd4,\xefg\xe4\x16Q\x8c\xdd/\x06=\x88\x93\x1f\xb7y\x907*\xe6j\xf0\xcc8\xf8\\\x0d^\xe6g\x18\x92\x1e\xcdH\x8f\x06\xc1\x07\x8a\x81V\x0f \xd5@\xc9\xbf\xd1<\xd2\xeb0_\xbd\xc4+R5\xdfI{\xba\xd5L}\xafl]\x8b\x8cg\x0f\x0c!\xf3\x8fC\xec>\x1a\xdd\xab\x10\xa0\x8b\x0b\x96\xfd\x98\xcc\xb7\x11^\xf3\xdf\xad\xcb\xd8\x1d=x\xc0\x17\xd0}t@\xff\x8d\xee\x8b\x9f#\xf1\xff\xa1\xe7\x97\x05[wt\xcf\x1b\xfc\x95\x05\xef\x7f\x0c6]\xfah\x10]}\x99\xc9\xf7p\xe4\xb9U?\x8ePtV\xbd,C^\x0e\xa3\x83\xbb\x95\xf7[j\xea~5Y0\x0d\xfa\xd1\xa8\x1a\xbb\"\xa2\xf2\xd5\xe6g\xf8\xfa^\xd5{d!\xbcG\x0e*\xef\xf1\xdcr\xb0d9_\x91\xf2\xa7y\xc1\xbb\xc2\xec\xe4&gq\x16^F\x95\xcb\x1e\x9c\xedd\x83\xed\"\xcb\x93\xb4\xf2\xe9\x8a,\xca\xa5w\xed\x01d\xab^\x076\xaa)Y\xb8\x88\x8ag\x904\x86%qbx\xaed\xd3V\xd7\xe3\xf2\x98\x97FYg\xc9:\x05\xd6\xc0{\x13(A\xdb\x89\xbf\xa4q\x1bcj\x06\xf9\x88 \x0b?\xe0\x1c\x8e`\xe5.\xc4\xec\x1d\x01\xcf\x8e\xe7a\x0c&\x94}1\xfa\xb6HU\x14\x16\xb37v`8\xf4\xab\x8b Yy\xca\xedAK\xb2\xc1\x9c-\x0c\x83\xf4\xd1?d\xc7m\xb8\xadj\xa8\xee\xa3\x83\xa1\xe7\xaaV\xf1\n\xde\x12o\xbb\xef\x0d1\x96Q\xb1\x963\xb7\xcd\x18\xf1\x00\xf6&\x80\x96\xa5[\x0fs\x7f\xc9\xbb,\x8b\x94\xb1_P\x18\xa4\x17\x9e{\xe5\xf9\xf0\x80\xd6Yc\xff\x1fI~\xdf\xba.\xa6l\xe3\x9f\x8f\x0b\xad\xd0]\x977I\xbb!\xb3\xf4|\x08\x06/NN\x9e\xe3\x01\xba\x0f\x89;u(\x8e\xae\xe3\x83\xb3\n2\xfe\xdf\x92\xe5\xfc\xbf\x8c\xe5\xce\xb9\xdf\x00w\x12\x96n\xb5.j\xeb\x8c>\xf2\xb5x\xc1!\xc6L\xd2\x1a\xcf\x0d^\x1c\xa0`:'\x03\xc4\x1c\x9d\x10\xcc`@\xb0\xb7(\xd2\x7f\\,\xc4\xe1TSP\xe3P\x065\xbeXL\xd99\x8d\xc2\\Zj\x86|U@\xe8\x9b\xbc&\x8c\x0d\x97\x18\xec\x0e\x91\"\xa8-\x02i^\x8b\xe5\xffQ\xdfc\xfa\xbbs\xa2\xf0G\xa3\x87\x96\xc8I\x8dh$\x07\xc6\xae]\xd4\xbe\xf5\x10\xaf\x9d\xf8b1\x82\x1a\x7f\x10\x1c\xab\xc6\x96\x04\xbbz\xe4\xb9N\xb6a\xb3\x90\x95\xd2\x84t\x93\xd8\x10\xf8\x8cb\nj\xe5\x1c?LW(\x84\xf1I3\xa2\xa0}\x8a\x9c\x85PJBHK\\\xcd\xce\xe5\xa9\x1c\x08\x82\xa6\xfb\x90\n\x90T\xe6\x10\xf2\x18\x9a\x86\xe7\x9e\xf2\x1f\x12\x85\x8b\x1c\xf1\x92\x96R7\xe3\xd6T\xf6\xdd\x85\x03Z\xe7\xe1}\xe3\xfas\xf6o\xe6\xba\xc2\xcd\xb3Z-0\xef\xa6\x10\x1a\x86UaBH:w\xab\xef#%\xaf\x18\xa5\x86\xaat\xd0$5DnU\x92\x9b\xe3\xdb\xea\xc8WxxT\x86\x93\xaeR\x00\x1b\\`\xea\x07\x17\xff \xd2\xb1\xae\x1e\x10\x94~\xae\xdbN\xcb\x90\xb2\x04hrojg\xd9\x86\xa3P\x8cr\xe3\xb2A\xd0D\x94+\xe5\x19\x17F\x10\xf0j\xa5\xaa\xd9\x90\x0b\x98Zk\xd6\xc3\xaa<\xd2A\x16\x91|a)\xe8\x9c5 \x94:\x83\xcb\xa7\xa3\xc6\x15Z\x05\xad\x01\xd2\xa4\xc8\xb2W\xf4\xda\xd4b7\xf9B\x1e;4\xcd$F\xe7yT\xf5r\x99\x021\x10\xf1\xa5Y=\xbete\x1c\xc4|\xdb&'WT\x043\xd6\x01\xa0M.\xca%\x00\x18\x9cv\x0d\xb3\x11\xb5\xfe;\x07\x99\x88%\x90\x07\xa2\xb9\x8f\x97\x08\xf6\xf6\xfe\xbb\x9aTF\xfd\xe57(fe!e\\#u>\x84\xb6\xa9\xa3\xdbc)J\xa35\xc4\xeb\x96\x7f\x8d\xb0E\xe7\"$g\xd7\x8b\x9c\xdcE\xd8\xe0\x82S\xbcU\xaf\xe7\x83@r\xa2\xcc~a$\x04\xbc|\x97\xb9)\x8e\x88M\xc3ss*|\xfb\xd2\xa5n\xa4\x8b\\\xe6av\xdbv\xf9\xa0Gg\x80\x92\xbd\x04\xf3\x91]x\x97@\x9b\xec \xe2s \xbeR\xd2s\xeey\"\x11\x03I\xf71_\x93\x99\x1b\xab\x9c8\xc8\xe4D\xfe\x85X\x89\xfd\xc6\xbe,\xee3\x1d0Z>\xff\x88\xd9\x8bD\x0f\xa6\xa9\x9bgi\x80\x10\x1f\xa2f\xcc_\xd4\x91\xc0\x86\x01)YK\xd1\xb7x\xcft/\xb8<\xa1\x14'\xc4H\xbb\xc8\xc5\xa5\x9bt\xcaP9\x9b d7\x0dM\xa8\xd8c\xb8*P\xfb\x0f\xf0\x05$\x94\xaa( \x04D\x8b9\xa3f\xb6\x08\xcc\xf6\x06\x12L\xeeU[\xc9,RQd\x91Wf\x16\xf9fa\x16\x876$uW\xc3\x9b\xce\xf1\xf5\xdd\xa17X\xd4e\x13\x8b\xf9\xe6\x8a\xea\xdcm\x15\x82%\xa5$\xed\xf3\xd6$\x13_\xe2y\x003\xd8\xe6/`\x02\x97\xf5\xd7\xd7\x9c\xbf\xe1!!\xa30;f?\xd4\x13\x98\xc0\x05G\x86\x8b&m\xef\xc6p\x1e%@\xf3\xcaz\xba\x89\xcd\xba\x18\xad\xe7D\xe5\x16\xe1Rx`W\xa5\xf9\x83*\xf4\x85'\x93*\xb8\x1ez\"\xb9U\x95\xca\x83#p/0\x91\x8b\xaen\x1aqm\xc6\xbf\\\xa0j\xea\\\xcc0\xeb\xe2\xe0b&\xa4\xc1K\x9dO a\xc0\xebsK\x1f\xf2\xe9\xf5y\xcd\xca\xc0)\xc0\xca\xe5\xcb\xe9\xa3\xc3\x94O\x04\xd3\x173\xf4\x97,\xf7WA\xe6g,\xf7\xdf\xb3\xdb\xcc\xa7<\x1f\xbe\x98\x8eO\xb7\x0f\x1c\x99\x9e\xce\xe7\xa3\xe9&&\xe0\x16\x82\xbcnZ\xa8\xacu\xb2\xc1 \x8c\xe1\x84\x9c\xcdq\x03\x1c\x1c**L\xa4Em]}\xc3K:{S\xa8uN\xb4e\x16 \xbe\x9e\x9cn\xa1LA\xfa\xd5\xc2\x8d\x0br\x8e\x06\x07\x1a\xae:\xaf\xb3\xab\xec*\x0f\xd1\xc5\x8c\xab\xec\x05\x05\x1frr\xed[\xd5})\x0f\x15z{R+W\x15\x89=\x9f\x82H\xcd\xcb\x8b\xe0d\xe1/\xcc1\xf1\xf6\xb2t\xdc&\x9a\xd1,\x06\xbc\xb5\xfaPjP<&(^W\xcd=dIY\xfap\xed\xf9\x90\x95G\x1a\xe3\xadOe\xf0\xf1|\xd8\xb8b;n(G\xd3\x85\x0f\x89\x9b\x0c\xfe\x03z\x90\x0c\xfe\x8a\xff~\xe7\xc3\x8d\x9c\xf9\x9a\xb3\x90\xb3\xc9J\x98\xa4\xcd\xb0\x16\xa1\x1eTy\xaf\xec#\xe72=O\xb5\xe7\xc3\xfe\xf4\xa7\xa0\xff\xcb\xb0\xff\xe8]\xff\xab\x7f\xfb\xe3\x9d\xaf\xbf\xe9\x0d\xde\xfdt\xf1\x7f>\xfc\xf7\xf9~8\xc8Y\x86\xb9\xd7\xcc\x81Wd\x82\x97\xd9*H\x83Y\xceR\xceW)\xcd\x00,B\x16\xcd!\x0e\xd6\xc6\x9c/\xca\xfa\x94'?$\xd72\xaftyq-sn\xb6\x84t\x9e6\xeb\xd4\x99\xc1\xf1\x11t'$#p\xc5\x98u\xa4\x95\xac\x82\xd6\x10\x93Iv[\x957{[\xfc\x99'1+9\x88\xb5$<\x11\xb7\xa2\xccI\xac\xc0\xa8\xe2\x99\xdf\x1a\xbcF\xc4\x80+i\xc3rS\xb2\xb0\xd6\xb5\x92\xb2C\xbd\xdf\xce\xd9~\x0d\xde}\xa0\xa5\x02\x14\x97sJ\x19\xf2\x13\x0c\xfd\xb1S\xbe\x0c2\x1eQ\xd6bs\x82\x0c\x91\xf9\xbf\x1e\xcd\x14\xbd\xeaL\xddu\xe9\x8bM\x87\xe7>0c\xe86\xadG\xdc\x03q\xee\xb6d\xb9\xe6\x1e\xf7\"X3\xae\xfd\xef\x90!\xaf:\xd7\xa9)\xab\xdcGS\xe6B\xdb\x1e\x19|\x13A]k\x90\xd9\xf8\x95\x04-\xb2 \x0dR\xc6\xe7S\xcd\xdb\xf2,JY0\xbf\x05\xfe\xafc\xba\xcc\\\xc9\xef\xdfi\x80\x06\x7fF(K0\xb5\xd4LM\x81\xec\xd8\x8eY\x93r\x97\xcf6\xdbF\xb6D)x\xff}\xb7\x8c;\xb1\xcb(aZw\x1bO\xa7\xa52\xf8n\x82F\xf1\xf8Z\x15\xb9\x97\xcdT*FW\xa9\xdc\xce?\xf2\x01\xdf\xddg\x99\x96\xac\x96\xdc}:\x8d\xd0\xe0\xc7 \n\xda0\x86\x8cvCP\x04\x9f1\x8cE\x9fQ\x91\x8f\x98\x03\xecm\xce~\xa0\x0b\xbb\x0d3\xc8\x18\x81\xae^\xd5C\x15\xfc\x12'\xd4i*QS| \xc4S\x1d\xd6G\xd54\xdf\xad\xa7E \x0f/JY\x05\xe9\"UC\x12\xa0\xd0\x9c\xdd\x81yZ\x0eE\x91\xd9\xdc\xa0\xa6\xcbG\xf9\x05\x16\x89\x8e\xbe\x8d\x92K\xcd%\xbf\x9a\xecXo\x9f\x17\xed\xdc\xbeL~\xcd\xfb\x90\xe1g:\xf6#\x8bw\xeeK\xcf\x7f\xce\xfb\xab$@\xef\xd8\xad\\>u\xc1\xa2I\x86\xd0z\xd7\xd2mC)\x87\xd4\xba\xd2\x81\x86[\xe8\xf7\xc9\x04\\\xca\xec\xc0:4\xc4\"\xb7\xb9;5\xd6\xb79\xbdB{\x00\x03\x90&\xf1\xf2\xc8?|\x80==S\xb5}\xcd\xd0\x00\xb3\xac\xc8\xb2\x82U\xe8\xd7-\xbe\x95\xb3\xe15\xdbr\xab5\xac\x92\x1d)\x84+hm\x0b\xab1\xa7\xe5\x83\x05K\xf9\xdffI\x9c\xb38\xef\xd3\x10\xf1\xf8\xd6\x12\x04\xadT7\xab\xd5\xf5\xc1\xc9\xd9M\xbe\x8f\x01\xa9\x1es1>c\xf9\xe4\xed\x9b\xef\xfa\x0f1\x04W\x05\x8b\xe4\xe1\x98z3\x10W-Z\xbb1T\xe3\xed\x7f\x0e\x12\xa8\xd14N/\xd8l\xa2\x90\x92<\xee\xdf\xf4\xaf\xaf\xaf\xfb\x1c\xc5\xfb\xdb4\xa2\xe8\xfc\xf3\xea\xac\x8d\x12\x8c\x96a\x8d\x88)\xd1\x94V\xfe*\x8d&!i\xcc\xe6\xfd\x0d)d\xb4\xe44\xf6B\xe5E4\x88AY\x12]\xb1j\xb1.\xedi\xd0km\xb6\x15\xb7;\xf5$\xa9\xa4\x01\x0bg\xc9\x96k\x8cI\x8e\"\x9b\"\xbf\x98t\x17\x82\x0c(\x93]\xa3e\xa2\xcb\x989\xb6\x9d\x9b\xb7\x99\x04\xda\x12&\xb7nq\xc9\xaaY\xa5\x04Gr\xe79\x8e\xda\xf7\xa9\xb4\xfc\x02\xeb\xf8l]o\x90\xafXl\x8aM\xfdQ\x92\xdf\x9c\x88G\xeb8\x7f\x13Pl\x17\"`G\x11P>vQP>\x15\x91\x90o\xb3A\x16\x94\xcf\xc7_\x0bM\xba-A\xc9\xf3\xbe&\xfd\x91\xbfzaS\xcde\xdc\x17\xf2\xba\x1f\n\xaf{u\xb5E:\xdf\x9f+\x1b\xc7`\x91&\xeb\xe3U\x90\x1e's\xe6\xe6\xd3F\xd6+\xb5\x17J\x99`\xcbk\xfa\xd1\xb2\x10\x9dV\xee3\xd0\x9e\x03\xf8\x8eh_Fv\x0bE\xd7E=\xaa\xb1($\xb8Vt\xd2\xd1>\xc7\xf37B\xd5E\x03\xaa\xfe\x9c%\xf1\xe7\xb4\xfd\xa7\xb3\x97/(\x06\xaf\x95z\x95\xde\xdb\x94\x85Y\xab\xe7\x0f\xf9\xf5\xd1\xfd,\x0fU\x87\xfa\xfa#\xad\xd0\xad%\xc6\x08\x94`P\xdf\x8d\xb6\xc4\xb2\xba\xde Q\xda\\F\xf9T\xf1\xcd\xac\x94)\x95\xe9\xbf\xb9\x1a%\xe4\x83\xc2Gv\xa5r4\xc7\x98\x8f\\e\xd7\xf5\xe4NQ\xd6VlL&p\xa5\xf7\xc9\x9c\xd1\xdbd\xce\xfcR\x82\x18`\x9a$\xcc\xbb\xc2l\\z\x06\xf6\x8a\xbd\xc1\xb0\x87\x9a`H\xb3T\x06K\xf3\xf2\x1bf\x9f\x97~\x7f\xf8P_\xa1\x0f\x1f\xc0I\xd6a\xee\xf8\xb0W,NE\x98\xb2/Vn_\xacv\xd2W\x98;\xf3\xe4\xedf#\xed\xbe\x8d\xc8}\xabe\x1a\x87\xa7\xd0\xa7{H\xa6\x8c\xdd\x1f\xdd\\\x0eFN\xbc\xf8\xe9\xfc\xc7\xc9\x1b\xc7+\xefcN\x7f\xa8\xc2\xe2\x07\xe5\x9d\xc1W)[\xb04EI\x80\xde\xba\xd8\x0e\x99V+\x1d|\x7f\xf2\xecy\xed\x0b\xf9\xcbZ`\x1eUoN\xf90&4\x9b#[\xf8\x8f\x937\x90\xa4\xc0[\x939\x873\x13B\x10\x91\x93\x1a|5\x8e\x8f\x0d\xf7\x17\x1d\xac2\x82\x0c6Y\xed\xd3p\xedz\xf2\x8c\xfe\x8ec\xb0\x1a6\x9a\x11Z\xc5\x03B\x1e\xd1~cxb\xfe\xe0\xf6H\x0b\xba\x96M\xa5\x87YT\xa0\xad:\x1e\xdc \xe67q\x8c\x0d\xd8\x99g.-\xa0\x14d\xf8\xed\xeb\xd3\"&\x19\xd7\x91\x0d\xaf\x93\xeeq\xe1:[\xb77\xed\xfb\x9a4l(\xad\xf4\xfe\xbb\xf4\xe8]\xbc\xbf\xcbn\xd66k\xdc\xb4\xda\xe5\x8d\"(\xb2\x8b\x0f\xdd2\xda\x8b\x8d\x1b;\xcd\x0d\x82\xbeWi\xed\x0e\x82|>g\x0f\xe6V\xbe\x9a+_\xfa\xbf\x17\x82\xbbH\xd0-\xae\xeeI%\x99R\xd5SXs\xfe\x17\xe6\nC\xf7\x0d\xf9i\x0c\x07\xc3\xa1\x8c\xfe\xfa^\xfa\x85\x88\x8fO'\xfc\xab\"\xe7\xe2\xed\x138TU\x8a\\\xf8E'\xfcW\xad#,2\x06\xe7\xe5\x9f\xe5\xd8\xec\xbc\xc0\xd7\xb9V\x8e\xffc\x8a\xfc\xaa\xa1\xb1j\x17)/7\x1axDZo\x1b4\xaf\xac\xc7n\xba)a\x0cN\xc5\x92\x80\xd3\xb3\xe4Q\x92\x07Tcp\xceD\xcc\x88P\x06\xa6\x90\xc7T\xf8\x8a\xbe\x9a\x1b\xe1\n\xdb\x18\x9cB\xa1\xd1\x1a\xe1\x1aF\xf1\xb3U\x00\xe4O\x9e\xde\xb6\x98\xc3\xb4C\x07\xde\xbe_=\xc3\xd0\x9f\x8f0\xc3\xe0\xd4\xcd\x94\x174\x97\xca\x91\xbd-3\xe2T\xa3\x1f\xcbGJ\xd5|m\xc4\x9fM{\xa1\xa9\xdfcp4E\x83*\xd5\xd1\xd3,\x1a\x95\xcc\x84\x1eB\xce\x15L`\xaa\xe2\xd5\x9cJ}\xeb\xdc\xf1\x8b(6\x85\x1aV\x7f}\x1c\x05\xeb\x0d\x9b\xd7\xbf\x9e\xc6\xf9\xe8\xbe\xb9\x92\xe9\xfdi\x9c\x1f\x1e\x98\x8b\x9b\xde\x7f\x17%\x81\xfd\xc3\xfd\xbb\xe2\x83%,A\xfbuP\xf9H^\xc0!\x94o\xd2_Bv\xdd`~3\x03\x81y\x10*[\xaf\xb0\xd2\x86\x19o\x9cS\x88\xdd\x87v\xa5\xc4\xc1\xd6\x10C$.\x9a\x07Z\x87\x9aDk\x89\xd8D\xc5 \xd5\xca\x8eP\x94D\xb5\x9d<\x83\x9a\xae\xde)?\xbeu\xb0\xb1:Di\x05`\x82\xa7\xd0\x18\xfd\xd4\xc7\xe8\xa706$\xff\xc1 ^\xc5\xf8\x85\x93z\x97\xad\x17EU\x97|\"u\x9f\xf6J\xfbK\x96wj\\m\x9c\\ b#\xe4f~T\x9a'\xa5{l\xebx\x154\xfbFU:\x96\x1d\xd4\xc2Bs\xe8h\xeb+\xabL\xb2\x01\x02\xca\xab'\x80\xa0\xad}\xe9\xf3\xdb\xe1\x1a\x14\xd4\x02\xdc\xc8\x1e=\xeb\x1c)\xdc\x8d\x88L\x95\xfb\xc5\x18\xe3st\xfc\xcak\xa7\xf2\x861b\xd0\xb2\x0e&\x0bi]\xb4\xe5\xfb\xd3\xf7\xa3\xee`\xd0\x92\xea\x8d\xc9\xc8lfT\xc6\x8b\x89f\x93\x88>\x15\xf23\xfe\xf5'\xd3a&\xb6\xd3\xfb\x8e3\x11\xae\xd2\xbf\xfeT\xba\xed\xcb4\xae\xdf\xf7\x92O\xd3\x94*\x8eA\xda\x0cM.B\x86\x05\xb0\x9c\xc5\xdf\"\x9f\x7f~\xf2\xc3\xc9\x9b\x13\xce/\xb9\xc2\xee\x0b\xf5\xdc\x07\xe7\xe5\xab7\xa7/_\x9c\xf1?_\xbd<\xc3O\xaf\xde\xbeq\x0c\x0b4\xd3\xba\x9c\x89\xf4\x17\xad+\xaeIe\xd2\x13\xdc\xbe\x82\x97\xc9\xfcV?e;\x8dC\xb3+\x96!\x16\xf5G\x1f\"Bnm\x9c\x9ez9/\xbd\x9c\x7f\xe6T\xe6\x95\x93\xff\xa6I\x91\xf60\xd6\xb5\x0d\xbbFX\xa8\x1a\xe3\xaazb\xaf$\xb4\x8e\xb1TC4\xdd\xa4A\xf9\xdc\xa6\xd1X\xa9);\xac\xf2|\xd0\xd9\x9fF\xa2\x1b-\x19Y\x8c\xda\x17\xca\x90D\xb7\\\x84\x96\xc7q,\x83nDm\xa6\x14M\x9c\x85S\xf5|\x04\xb34$/\xd5L\x0f\x87#\x1f\x0e\x87\x07\xfc\x9fC\xfe\xcf\x03\xfe\xcfC\x03\xba\xcc\x07)\x9b\x87)\x05\xd8\xed\xc4\xd2\xb8\xa0.RK]jV>\xddZ\xf6:\x88\x97UwS\xa1\xd4\xce\x92\xb9\xf5\x80\xbe\x04\xba]\xf7\xa1\x0b\xc45+OQBG\xcd&\xeb\xa4|,\xea\x93\x11\xf4\xd8\xe0{\xa5r'\xfc\xe7k2\x08\x02\x86^\xe5?\xb3M\x12g|{\xe7\xfc7j\xce]W_[\xa3\x9a\xd3Z\xd3%\x17\xd0\xad/H\xe6\xb0\x97f\x1b[(\n\xff\xe7\x8f?|\x9f\xe7\x1b1\x0f\xbb\xa9&\xdc\xd13\x0e4\xeck.\x05\xda\x8e\x87\xad\xf4\xa9\\\x83\x101\xecD\xa4\xe4\xa3@g\xe3bN\xa7gQ$\xb7Ml\xae\xeb\x91\xb1\xc4\xee2\x02f$\xd5\x1f&\x8c/N*\x1a\x7f\xfb\xfa\x07G&\xa2\x0f\x07\xda[\x18\x03+\xfb\x93\xfcg_\xecG\x9fWj\xf1y\x91&E\xd5\x91\xa1\x17L\x0f(\x7f\xf0ejn2v\x05\x8f\xf1\xc1$\x97\xcb\xe7\xa3\x8f`\xd1\x99\x1a\xcb'\xad\xba\x86\xbe`\xf9u\x92\xbe\x97\xe6uX\x04a\xc4\xe6&\xdf\x0f\xf9\x88\xaes\x8a\xfe\xfd\x0f\xe9|\xc3b7Q\xc7Q \x9d\x7f\xe1\xe5&'\x8cg\xd1v.\xe2\xd4%\xa5\xd3\x1e.Y\x85\x18\xa5\xec\xb8tND\x15\xd5\x16\xddn\xe46\x96|\xc1\\m\x17\x05\x17!/\x0c>\x00 B;\xf9G\xcb'\xe4\xea\x95\x80:B\x03\x8b\xbb\xb4|0j\xe4 c\xf1\\\x0f\xa6\x9ah\x87n*}\xa0\xf6\xd2&\x95\x9a\x89-\x92\xcf\xc1&\x89n\x17a\x14\x99\xbc\x82\xd5_\xae\x9e\xc1\x163[\x90lQ\x8d\x85\xf6\x07\xd1xiqv\xbai\x94\x9bn\x19\xdd\xbb\xeb\x0d\xc8\x98b\nd\x1b\x1a\xb7\xc0lQ\x14\\\xc0pLQ5\xd5J\x13\xa2Q'\x10\xcd\xa4*\x8d\x9b\xf4\xc6\xe5\x03\xd1|\x13m\xeb\xa9\xfe\xaa\xb6\xd0\xc6\xcd\n\xb5\x18\xef2\x89\xec\xdd\xf2`W\xf9Ml\xe9\x9eQF\xffE*KN\x910\xdc\x9a&\xe7J\xc4\x1b\xcd\xe0I\x11N\xfa\x88k\xd6\xc2\xbf\xe2Y\xee\xa2s\xfd\x8b\xe0E\x9d\xcee\xd7!\xae\x9a5\xdb\xfd,\xc8\x18\x0c\xc7V\xc0\x97\x0dX\x8f\xd7\xe5\x83\x0d\x1d>\xb0\xb7$\x1f-\xd9\x80\xb8z\xd5\x10Y@>\x98\x86\xad\xb9\x18\x0e\xe0\xeea\xfb\x00\xf0J\xac\xcb\xd7\xf4\xf0\xa0\x85\xdb\xc8\xc0\x86\xadm\x06\xd3\xa8\xd73'\xea\x94\x8fY\xf2\x82\xe6\xc9\xe1\xa4F\xf6\xfe\xb9\x0c\x1b\x92<6\x83\xa7\x13\xb8\xfb\x90On\xc6!\xeb\xde\x03\x0f\xd7z\x06}\xb8\xfb\xd0>O\xe5\x95\x8b\x0d\xdc\xbf\xa7\x1ax0,\x1a\xb8\x7f\x0fz0\xb2\xdc\x10\x86\x1d\x1ch\xa9\x97G\x0fT/\xa3\xe1Ac\xf0<\xf9\xa8\x15>|\xe0k\xcb-p\xab#\x045\x96\xb2o\x10\x08\xb0\xe5+\xf1\xe8\x01\xae\xc4'l3\x1f\xe8\x81}\xa0mPp\xd0\x0c\x05\x82\xc4\x98\xa0 \xfd\\(H\x7f\xe7P\x10\xea\x10\xf1\xeb\x83B\xfa\xd9\xa0\xa0F;\xba\x0f\xdf@\x0c=\x93Q\xfd\x0f\xf6_\x82\xdf\x05ER\xe2\x08\xfaz\xea\x94\x8f\xbe\xc6\xca\xf8\n\x15\xab\xa2XVP\xf2\xf2;\xb8w_2\xaa\xc7\xb0\x85'pp\xef\xfec\xe8\xf5\xb6\x1e\x04\xd3-\x86#\xfe\xa3\x03=p]\xfeqt\x1f\x8e\xc0\x19:\"]r\x0f\xb6\x05\x97\x1d\xdd\xf7<\x9b\x87\x8d\xcc\x9e\xd6hFo\xb8E\xd9\x9b\xf0\xfe\xca[\\\xf2ft\x9cR\xceP\xe1\xac\xc8\xb4T\xc5F\xcdRj\x94%\xb6j:I!\xf0=<$\xf9\x8fkNw\xefi\x7f\xdf/\xfe~\xa4\xbd\x1f\x1dh\x1f\x12\x0e\xfb\x87\x8f\xf8\x8c\x12\x0e\xfbw\x0f\xd4[B\xdc\x84\x10W\xbd%l\xc4\xb7\x8f\x86\xea-a\x0f\xbe\x1d\x1d\x1cX\x04xtd\x80>\xc4*\x1dh\xce\xd7P^(BE\x9b\x8b\xd3|K\x0f\x1e\x12\xbdO9T\xfb\x80\x05\x83ib\xb1\xdd*\x82\xc1\xeb\x1e\x0c\xef\x1a+\x8f\x1e\x1d\x00\x0e\xf7)\xdc?\x87\x1e\x7fs\xf0\x10>\xc0\xfdC\xb8\x03\x9dZ\xbew\xef\xe0\xd1}5\xe7{\x0f\x0e\xef\xde5utppWv4:\xd0{\xa2\xbe\xe1\x0e\xdc?\xdcm\x00\xcd\xd6\x87\xb0\xc1v\x80\x10\xd2\xeb\xe9pW2*\xbd}}*\x94\xb1\xb7\xafOa\x1dD\x8b$]3\xab\xdb!\x08\xfb\xc5hx\xc0\x07]\x81P\xdf\xb4\x18w\x87\xf0\x81\x12\xc5\xdd\xbfw\xef\xf0>b\xad\xa8\x9ex\xf0\xe4 \x8cx\x81\xd0\xf3p\xbd\x1e\xd6\xd6ktP[\xb0\xe6u4\x0e\xbc\x03\x01+\x02\x890\x8c\xfbT\x12qs\xe8\x15\x80\xea\x95c7\x96\x15\x95\x96\x88\x05\xd4\x97\xe5\x8e\n\xef\xd8\x94\xb9\x85#K\x98}\x17\xc6!E\xe4:\x02\x87\x93?,~\x99$\x11\x0b\xe2zSG\xe0\xe4\xe9\x96!Y\\\x04QF\x7f9\xfa\xb8\x0b:,\xf5\xa5hw}\xc9\xae\x1e5\xc51,8\x02F\x1e\x18vQ\x87h\xd1\xc2\xc5-&\x0c\xa4[+U\xa5\xc8\x9c\x0fX9\xf1:w\x04MF\x87UgR\xb9ht\xa5\x12\xfa\xd2\xd8\xca_\x89\x0e\xd8\xa2\x18%bD\xba\xe6H\x96\x03<\xb3\xa9\x7f\xe4\xf8B\x99b'\xf6d>\xa6%,qM=\xe3\x83\xcc1\x1c\xa8\x88$\\\xbd\xdbrvL\xd9\xf29GZ\x10+Z\xc0\x13\xd8r\x1e\xb4h2\xe1S\xaa\xe1EC\xa6\x879\xa5$n\xc9\x16\x11\xba\x19\xe6\xb7\xedU\xd3A\xca\x87\xafm\xf9\x12\xf8\xbcQ\x08Skp\x05\x13\x98\xab\xf9\xaea\x02W4\xdf%\xcds O\xe0\x8a\xcfs\xe9\xc1\x8c\xd3\xa4\x15\xf4p8\xf3\xe9\xf2\x9c\xf3\x1b^`-\xd4\xb0\xde\x04\x9a.V`\x08+\xbep\x91^\xdeLp\x88r\x97{\xe4\xdd\xb5W\xaf\x8bj\x02gf\xedDL\xc7o.v\xa1\x8f<\x024\x995\xbe<\xba\x04\x86\x88_\xa1-\xea\xc6\x87\x0f2[\x8fdFJ|,\xb7`\xa8\x9d\x17\"CM\xec\xba\x12)\xf1c \x08\xb5%$\x8fp\xdbW\x8e\x1b#vXn\x94P\xbdN\x8e\x93\xc1:\xb8\xf93\xbb\xcd\x94\xee\xae\xde\x18\x86\xc5\xd1m\x04\xfbU\xb5p\xa6\x84 ^`f\xa8\xb8\xc1m\x93T\xd2443\x15\xaa\xdb\xaf\xb0\x9b\x0d\x8e\xb3\xfe\xd1&\xc0r\xbc\xde m\n}D\xe1\xe9\xb9\x8f\xc86$,\x1b\n\x0c\xf3\xf1\x94\x99\x13\x96K\xf1\xff\x05\x9d\xc1\\\xd3\x7f'T\xe8\x86\xb0\xf1\xa6\"\x00\xdf\xd8\x04\xe0\xb3\xaa\x00|c\x11\x80\xcfp\x8c\xb9^tm\xa5\x1c\xbc\x82\x18<:]\xb9\x87\x0f\x10\x1c\xcf\xe0\x08\x07:\x821\x9c\xa8\x9d9+\xc4\xe0\xb3B\x0c>+\xc4\xe03RJ\xd5[\x12\x83\xcf\xa4\x12 G\xc0es\xe8\xf5(\xc2\xda5Y\x9b\xb1\x8f \x86\x91\xe6\xb4\xc7j\x0e\x035CJ\xba\xa2\xcdp\xd9\xaa\xa0\xf2\x8a\xbd\xde\x12\xabn=\xb8\x82'\xe0\xbe\x87 \xdc@\x1f\x96\\B\xa38\xd5\xb7\xba\x04~\xe5\xc3{N\xa2\xc4\x96]a\xf1^\x9bIl\x96\xc4y\x18ow=\xe6\x03\xe1\x0d7\xe4\x00\xf3\x9bo\xc5Ee+\xcc4\xdc\xf8\xf6\xee\xa1\x18'o\x077\x10\x8e\xc0\xe5\xebz\xa5\x86[]\xd6\x1b\x0f\xe3\xa9q\xd2\xf5\xc7\x83\xa1\xc0\x11\xea\xbfR\xf3\xd2T\xf3R\xaby-\x8f,\xd4\xf6\x188H\xa1\xb7\xf4zk\x1cn\xd6\xc4\xe5\x8f}\x90\xb0\xb1\xb6o8oN\xce\x97\xc3\xd3{\x1b\x04\xc1X\xfb^\x9d\x10B\x98\x8c\xf88\x81\xc8\xbd\xf5a\xc3\xdf]\x8b\xe2\xfc\xdd\xa5x'\x8e\xc4W\xeaH\xfc\xd6\xf3 \x98\xde\x9ec(KXMW\x82\x96\xf0\x17\x86\x9bY 4(\xf7\x18\xe5\x98\xdbsO\xbf\xa6\x85r\x06\x1c\xc1\xf1\xf4Xk\xe6\x12\xc6\xb2\x8b\xe9\xb1\x0f\x97\x16\xc5\x8c\xaf\x06\x06\xf5\xea\xf7\x17^\x93\xc1\x8cou\x99\x16\xdeb/D,\xd5.\x12UE\x8c\xa8\xef\xe7\x1f\xec\xbf\x16\nt\xaet\x95\xe5\xc3\x07X\xf2/^\xfd\x93\x0e\xb7\xe5\xdd\xe3;\xb7\x86'\x90\x19v\xce\xfb\xcc}\xe3Hb\xdd9D\x84\xcf\xd9\xa3\ns\x90B\xc5\x1f\xcak\xd69\x93\xc1#K*\x83\xc3\x87#\xaf\xfdtO\xba\x13\xc8\xebpp\x04\x7f\xffH \x0dAB\x8b\x91\xeb\xc7e\x9d2]\xea\x03\xaeF\xd5\x13\x03\x1e\xb6GI\xb4'\x85HE\xa7\xad~p\xa2|\xe2\xb2Z\xfa\xb3\xd6\xc8p\xd69\x8d\x0e-s\xba[M[D\x81\x05\x1f<\xea2U\xc3\x0cJ\xfaT\x7fD:\x94\x12\x16Qt\xfc\xfbG.\xad\x04\xa83\xd9D\x16\xbc\xf01\x0d,\x9a\x10\xe6\xe9\xe3#\x88\x0c\x82L\xec\xce\xf8\x07\xa0\x98\x81>\x84nDA:g6\xbd\x18\x8aU\xcfv[`\xf3\x19\xeb\xfe7{E\xdb\xdf\xc0,I\xde\x87L\x7fs\x9cln\xd3p\xb9\xca\xdd\x99\x07\x07\xc3\xd1A\xff`8\xba\x0b\xaf\x93u\x10\xc3\xd9*\xbf\x8d\xd6A\xdcT\xe1\x1e\x1d\x9e#\x0f\x99\xa3*O\xfcf\xc4\x99H)w\n\xc4\xd3\x0d\x95\xc3?&\xb0u\xe7>d\xed\xa1)M8SI\xe4\x9d\xb14\x0c\xa2\xf0\x17\x93~\\],E\xa0\xc4v\xd7WZ7O}\xf8P\xbdm\x88pY\xa8n\x05d\x86\x16\xc8L0\xa9\x1e\x88\x06\xc3\x0cB\xf2\xfe\xab\xee2\xeep\xd0\x12\xa8R\x81y\x1c\xac\x9b\x1a\x93\x1auX\x8b4A\x07|\x18\x9e\x9b\xfa\xda\xb6\xf6u\x15D-]\xe1uu\xe8\x813q\xa0\x07\xdbz\x8f\xc2R\x06)W\xb5\x9f-\xadW<#(\xca@\xdft\x18\x8b\xc7\xd4\xd9\x8b\xe0\x85\x1b\x99\" \x89\xaa\xd9\n\x831 \x0dxA&\x00\x03\x14g(\x98?\x86\x1f\x83\x9b\xfe\xb3%\xc3\xc1\xff\x18\xe4\xab\xc1\"J\x92\xd4\x8d\x9a\xa87\x1e\x87\x0c\xe6\xc9:\x08\x8d=\xe8o\xb0\xd7\xe4\x15$'(\xfa\x98\x9cUe\x9b\xea\xd3\xe6\xdd\xe0D\xc1\x8d\xb3C\x87?\x047\x9f\xd3\x9b\x90\xc5v\xe8\xf0sf\xd8\xeaF\xd4\x04\xf4j\xbfu\xa8\xaf\xb5\xd4\x81\xffj2k1L\xc9Y\xebF\xca\xba\x1aP?N\xa9\xab\x04\xfb\x8f\xe1\x9b\xfd\xf2k.\x9a\xed\xff4}\xb7\x1d\x0e\x87\x8f\xf8\xbf\x07\xc3>\xff\xef\x01\xe3\xff>\xa4\x1f\x8b\xc5y\xef\xdf\xf6M\xc7c\xdb\xdf\xeax\xac\x1a\x93\xb9\xfc\xd7'I\xf8\x1dC\xaa\x8b\xfek\xcb\xeb2-\x1c\xc4t\xefk\xd7\xfb\xe6|\x7f\xd9\x16\x8b\\\x1eK\xa0\xbbF\xc9\x9e;\xf4J^\x1ae'\x8d\xf2\xec\xdb4H\xbd\xe3n\xb3,\xb9i\xc8\x1c\xf32+\xb2\x92\xc7c\xbb<\x9eV\xcd\xd3\xb1E\xe4N\xd1U\x00\x1d\x07\xee\xdc\x81\x14m\x97\xf7\x0fG\xe8q\x11C\x0fF\xfa\xc9|\x83X^s\x08\xc1\xca\x16\xc1\x9a\x0e*\x9fbW\x07h\x1c\x12n\x1c\\un0\x1c\xcb\xe3\xcf\xd1\xf0\xe0.|C\xde\x1a8v\x0fz\x90\xf0\x1f\xd8^\x8f\x8e\xf2\xed\xe4'\xa7\xebp\x07w\x87ey(\x84}\xb8\x7f\xb7\xf8\xc7\xf3at\xf0\xd0Z\xc6\x83?\xc2\xfd\xbb\xd62\xe5\xcf!\xfeB\x1f\x84^\xa3\x1bg\xa3\xbd\xban\xf25\x9c\xc6Qh\x89\xbb\x0f1B\x04\xcd\xf4\xe0ny\x84i\xf3$S\xc3\x04R\x9a\x00\xe7\x97\xbc\x03\xfeR\xb5?zt`l\xa0^WTH;\xd8\x0d\xda\xd2O\xea\x90\xb2gw\xf3\xe7@\xc3la\xf9\xedF\xb2J\x91\x86\x0b\x96(\\\xa6z\xfe/\xcb\x19\xb2\xc4\x93\x86[d\xa1\xddAs\x9e\xb4`F\x80V!v\xc3f\x8d\xa9\xc5\x94\xb62\x99L h4\x0d\x83\xd2\xcbCx\x02\\\xbao)\x9c\x90S\xcd\xf0\\\x19\xa7\xc2^\xcf\x0c\xc8p\xbd\n#\xa6\x14'>\x14s\xbb\xd2v\xc7\x81N\xf3x\xe9\x8f\xcc\x19r\xfe`\xdfIK\x8a\x00\xd0\x9d\x04\x85v\xbaS\xbb\xc2\xach\xa3\x8eZz\x8d;\"\xbd\xc1\xd4\x99\xfet\xee\x9c\x97\xcd\x07d;\xe0\xa2l\xcd\x9e\xa3\xda\x12\xa4\xbd\xed\x92\xf0\x0ea\x81\xb0\x1a!%\x1bd\xc96\x9d\xd9\"Fx\xbe,\x18\xca\x82\xe48\x98\x0efI<\x0bD\x10Gv\x0d\xaf\xd9\xf2\xe4f\xe3\xa6\"\xe0\xcf\x07\xc7\xab\x99]\xc1H\xba\xd8`\x11\xc6\xf3\xe3U\x90\x9e\xc6sv\xd3fB\x93\x0f\x87\xd1\\\x87\x0f\x85\x89\xfd\x86\xb3\xa22\xceZ.>\x95,i\x89\xeb\xf9\x02E\x0b\xd7\x98X\xa2\x1c\xda\x1c\xdcx\x10\x05YN\xc3\x7f\n\xb9\xf7\xd8\xe38\xd0\xb8]\x86\xfc\xcc\xbeX\x8aoos\xb6\xd3R\xc8\xd9\xf0\xd5\xc0\x1b\xb4\xb4 \xe4\x95\x858\x83\xf5q&\xe6x\x8b\xc4\xc5\x9fu\xbe\x1a*\x17\x87n\xa6\xebc\xa6j\xf6\x0d\xe0\xd2\x0c\x9e\x88\xc6\xc6\xbd\xb3EY.\xe4\x1b\xe5\x98\xc9\x85\x8d\xea\x89\x88\xfe$\xe8t\x84\xfb\xd4\x92~KQ\xc6\x84\xeb\x8c\x94)?\x99\x0e\x8dq6tyg\x97\xd5j\xbd)\xa3?r\\Hc\n\xdc\x92(\xe8#\xb50\xee%\x7f>\xb6\xedA\x8a\x06W\xd9\x8b\xf1^\x0c\xd8D\xbc\x96\xa5$\xa9\xf2\xc9\x84\xbcA\x92B\xb4+\xcd\x89\x8f\x15}?\x87\x9e\xafdN\xe95\xca<\xa7\xd0=\xa8\x07\xee\xa2Q\xe0\x10\xde$\x9c\xf4\xbdJ\xc2\xb8\xc5\xe6!\x9f.\xb6\x0f\\\xdb\x99lW\xae\xb1\xc6=DjIU\xc4\x13\xd6\x12\xa1~j\xef\x1b\xa7o\xe1\xfajBo\x84\x85\xe8\x8bM\xac?\xb9\xcf\xd7\xf2\xf9w\xdf\x9d\x1b_\xeek\xbb\xfeQ\x1c\x16t=\x13\xf8\xba\xdf\xef\xbf\x8b1\x00\x96\xb3\xca\xf3M6\xde\xdf\xdf\xb0\x1c\xf3\xdd\x0f\xb2\xeb`\xb9d\xe9 L\xf6\xaf\x0e\xf6\xe5\xaf\x9f\xb3$v\xde\xc5\xf3d}\x11\xce\xc7\xe0|%>\xf4\xb7\xa1\xf3\x8e\x0e\xc1\x82\xd2>\xab\xa60\xf2\xc15-\x07\xf4a\xe6\xc1>$\x1dg\xa5?ie{\xb4\xa3\xc0\x0cz\x10\xc17d\xee\x1d\xdc\x83#8\xc08\x0e\xdf`$&\xfe\xbf{\x17\xfa\xf4\xd2C\x95\xd2\xa6\xe0\xd8\x9e\x02Py\x17#\x0e\xac\x08\\\xdf3t\xef\xf5\xf0\x00\xf2 \x10`\x0f\x88L\xd37.\xb1\xa0\x0b\x90\xbe\xd2\x81\x0f\x8f\x1eiPo\xc7\xce\xea\xf3\xd1\x87G\x1d\x8b\x7ft\x9b\xcb\xd9/%5\x90\x84h\x07S\x85|2wK\xf1\x9e\x8dG4\xf2\xb1\x84\xb4\x93\x8c\xc8N\xa4X\xbe\xdd\x8c\xbb[\xbb\xa1h\xd4\x1571\x91*y\xeap\x8c\x8fU|B\x87\xe6\xdcS\xc6\x9d\xdck\x8a\x1d)\x1f\xe1`\xf4|\x9b\x8a\x00\x90q;\xb8\xb3\xf9\x92\xbd\\,2\x96\x9bBz\xeb\xcf'\xed[\x9e\x8c\xc1\x92\xab\x80>\xff\xd7\xb8\x89\xd6\x85q\x9e\xfc%d\xd7\xe5u6]\x9c\xad>\x92Wc\x9c\xf0o\x93m<\x0f\xe3\xe5q\x14\xb28\x7f\xcdf\xb9\xeb\x0dV\x88'\xed+\x14H\x8a\xae\xf8Z\x0f\xc2\xf6j3YM\xe2j{\x95\xc5N\xbcc\xc3Q\x02zm\xa1n0\x05\xf2\x13Xp\x88\n\x91^<\x85\x19\x1cQ\xbc\x01Z\xc91\x04\xe2\xc3\x06\x8e s\x03N/\xf9\x9b\xa2\x00\xb1\xd2\x06\xccn\x80\x81\x19\x8bs\x96\xd6\xb60\xed\xb0\x8b\x99\xdb$]\x94I\xe1>\x1c@\x8f\xa3\x0b\xc7\xaa\x96]\xe7\x85=OL\xefS\xe6\x94\xe5\xc9f\x0c\x81\xbd\xc0:\xb9\n\xe3e\xc7\x0c\xfcP\xd0\x86\xbd\xbd\xfa!\x90|\x1a\xc6\xc3\x81f,\x80\xa7\xb1\x14.\xdfX[Jca\x833N\xbdUN\xb3\xa4\x14?\x90\x7f\x9cDl]s \x04\xc1G[\x17C,\x82\xd0E\x88\x9f\xfd\x17\x1a\x91\xc5\x8f7\xc9\xa6\xcb\xd0\xd0j\xef\x9a\xfb\xa0x\xd7j\xe0\xd4n\x18/\xc5\xc8yo\xea#/k^N\xa4\\\xddd\xe5\xd2l\xde$\x1c\x92wL]\x81\x9bkIN\xa9P\xa0#\xac\x95\x978\x8cc\x96\n\x89\x01\x97y\x86\xc8Bov\x1c\xa3\x00\xadn\x8b\"\xf5T+\xa2\xe6\xc9\x86\x93 \x14\xde\xe2A\x82,\xca\xb4\xfb`\x06W\x83\xb75\x06%\x0drv\x86\x1bQ\x8b\xeah\xa3G\xd2N\xd5\x08N\x96D2e(i \xcb\xaf \x9c\x03\xef\x8ek\xff_\xbb\xed>k@'h\xec\xe8S`M\xc9\xe7\xac\x04^~' \xdc\x15S>\x0d\nw\x86/\x01/\x7f\xa8\xbct\x82\xf9\xfc\xe4\x8a\xc5\xf9\x0fa\x96\xb3Xd\x0c*L.{b\xcaq\xf2\xff\xb2\x98\xcc/\xf8\x9a\xb9%\x9ac\xbc'&E\x1ag\x15fy\x92\xdeV\xad9\x9bm\xb6:\xcb\x83\x9c\xcc<\xa2\x90y\x9d\xb8L\x13\x92 \x08\xe1\xe05\xe3\x85Qj\xd4+\xd7%\x0b\xcaT*>\x0fj\x95\xf9\xe8\x82m\x9e8\x9e\xda\xdc\xea\x82\xb8N\x94\x04s\xc7o\x87 \xeakWE\xb1ql\xeb \xde\x06\x91%\x86=Wq\x1a\x86\xbdI6\x19\xaen\x9b\xe7\xb5|\x18\x86\xe8&K\xdc/,\x16\xdc\x8cRH\x15\x9f\x12T\xf1\xc4\x8bAQ\xce\x06\xf7\xb0\x87\x97\xf3\xc40e\xb0\xf7\xc1*\xc8\x10\x92v].iUL\x06\xa8\xd0\xb8\xde\xa0\xd0\x08\x9aO\x0dZ\xedC\xd2h\xa7 {\xc9\xa4x\xf0\xed\xed\xe9\xdc\xadM!e\x0b\x99\xc1\xef+\xc7\x9b\x8e\x9a\xf2\x05\x83t\x8ek\x1b\x05\xd4\x0c\x05$L&\x850\x99s\x1e\xc3:\x88\xdc \xe4\x98D\x08\xe9\x9c5\xb5+\xf4Cx2\x81\x14\xc8 \x1d\xd0\xff\xdc \x124\xa8\xa8\xd0\xac}\xd9\xa1\xd9D\xb6\xf6L\xae\xebW2\x8aO\xe1\x86\xe5\xb8?}x\xf7.\xf34J\xe5\xbe{\x97}\xf87\xcf\xe4\xc2i\xc5\x9aY\x14\xce\xdewB\x99\xd2\xb1!\x1b\xe4A\xbad\xf9c:\x89q\x9e9\"\xd8L\x1e,_\x04k\xf6\xd8\x13G\x9f\x9b eq\xfe\"\x997$\n\xdfs\xf7\x90\xb1\x8c(\xe0\xd7\xe0z\x15\xceV\xa4&`\x1a\xc8?\xb3[\xfa\xb5fy\xa0~\xcc\xf24R?\x82\x88\x97j\x8c\xfd\x82\x16\xc86h\x94\x90\xa8\xa8\x94\xa2\x10\xf5\x08d\xe52G\x95\xdf\xe3\x9a\x91\xbc\xfa\xc4\x1a5\xd1\x80\xb6\xb9R{\xca?\xd0\x88\xac\xb8\x96\x82\\\xc7\x8d\xeb\xe7k\xd5\xa7\x94\x02pW\x90\x06\xdd\xc5\x0b\xb3\x18\xe4y\x1a^ns\xe6:\x9cv8\"\x85A3\xd9\x12\xc6\xfe\xe2\xce\xf6W\x0e\xf9\xb7n\xc9C:\x1f\xcc\xa2 \xcb8\x90\xb5\x86\xfa\x91\x06\xdf\x06\xb7w\xf9D\x0d\x840-\xdcZ\xdcQ\x9b\x89\x10\x8fW\xber\xc4\xd1j\x87\xbdB\x0c\x88\xe4\xd1J;\xb9\xca$\xac\x10q\x8c>\x95.\x01egJ\x19'\x08\xcf\xc94\xd5\x06}W\xe2\xcac'\xd6\xa5?\x15^\x02\x93\x16c\x164\xab\xd3\xf2Y\xec\xcc\x19\xa9\x16]\xff,3\x9c\x0c\xfa\xb0@/\xeb;\"x\xd9N\xb3\x94(\xa7\xa4<\xf7\xef\\\xdet\x8c>^\xfa\xf3\x11C\xbb\xa2\x94\x91\xf9\"\x83\xf4\xac\xc1\xe8af'\x16V\xf2\x07{!\xe9\x07\xa7^~t\xcb\xdea\x18\x9e\xd1\x18J-\xc5[\xad\xc1f\x13\xdd\x92\xa7 \x8c9\xac\x7f\xf8\x00\xae~\xa2\x1c\x9a\x0f\xa0;\xdd\xc9\x13\xc1\x1b\xe9\x94\xb2\xc8\xc9\xe7\x83sq\xc1\xb2\x1f\x93\xf96\xe2\x92^y_0}\xdbX\xcf\xc8\xa0\xeb\x99\x926m\xdc\xd8\xbd\xeb\x19\x02\xa8\xf0\x0f\x07\xd5\x0f\xa1\xf8pX\xfd\x10\x88\x0f\xf7\xaa\x1f\xb6\xe2\xc3\xfd\xea\x07L\xf6\xe0\x0e+o#,^MJ\x85'G\xbc\x15\x94&\xf1\x0f\xb2\x88\xb9\x87\x0f\x1fT\x1b^P\x94\x17\xcft1\xd3\x90\xf4Y?\x83f\x83b=E\x9c\xd5:\xac\xcb\x9b\xb1-\x97/A,2E\xbdX\xb1h\xc3\xd2l\x90lN\xe7\xe5\xe1\xb6;\x02\xaa\xd1\x0b\x7f:\x0b\xfe\x91\x9c(F\xe7\x89Lj6\xcf:\xa9\x9e\xf1JA\xb5\x92\x9b\x0f..0\xfd\xd9\x05\xc5\\\x1b\xfa\x18\x19R\x16\xf2<\x91#\x11K\x93{g\xe3\xc1D8\xc8\x93\xe52bg\xab\xe4:\xeeJK\xa4\xb0\x1f\x0e6i\xb2i9c\xcc\x85\xd3\xeem\xb2\xcd\x9fa\xdb-\x15b!\xb7-\x9b\x8b\x91\x97\x1cG8$\xd5\xd5\xcd\xab>\xc25;\xc3\x896\x17E\xad\x96s\xae\xd7,K\xa2+6?\xdb^\xe6)k<\x0f\xc53P\xcd?'@;\xf9@$\xc6\xa95\x84!KV\xc9\xb5;u\xd4\x0c2\x87\xec\xd9\xe7>\xec\xd9\x9c\x9a)u\xcfq\x10\xcfXt\xccE\xe2\xae[\x869j\x04\xbdo\xde\xae\xf4\xf64\x7f\xb9\xcdO\xe2\xe02b\xf31\xec\x85B\xa7\xac|\xb1\xb6b\xc8H\x03\xc5\xd8\xdf\xa4\x1c\x10v\x1a\xfb'\x80[\xb6a\xb3\x1d\x80m\x13\x98b\x8a\xea\x0fA\x1be,j\x10\x0c\x7f\xcbU\xe60\x84.\x1b\x7f!\xbf$F\xc9\xc11\x87ejs\xab\xa3M8\xb9a\xb3m\xde)q\"\xec2-F\xed\x9e\xc6\xaf\xd2d\x99\xb2,\x1b7&\xf2n\x18c\x1d\xfb\xba\x0e\xf6\x13\xa1\xe5\x8cEl\x96'\xe9\xaf\x00/]\x08\x13\x1f\xc2\xab _\xd9aK\xdd\x07\xc0\xac\xf6\x1b6\xab\x12\x15.\x9b\xfd\xe9\xcc\xf5\xe8\x12\xb1\xa9\xc4\xd4\xe1\x03Wt\xa6a\xf9\xcdt\xebW\xde\x82_\x0da\x7f\x85\x0d\xb0\x10\xf6\xf2\x1eX\nu\xdf\x06R\xd1\x9b\xb2\x00\xd6 \xc9\xc8>[\x13zZr\x8a\xfb\xa6;\x97\xb57\xca\x11\xc1\x87\xad&\x85\xf8\xc2\x07\x81OA\x7f;5\xcf\xe3=\xbb\x1d\x83\xb3\x0e6Hb\xde$\\\x8c\xce\x1c\xf34\x84\xe8\xdc\xd9]B\x1aJ\xf2A\xb2i\x07\x98\\\xc8)\x1d\x89A\"\xc4\xb4\x9c\xdc\x1d\xe3E\xb8\xcc\xbc\xb63w\n&?Of'7\x9b \xce\xc2\xa4\x834\xc2\x85G\xb6\xf9!\x8c\xdf\x87q\x8bX\xb4\xa5\xe2a\xb6\x89\x82\xdb\x97]\xa5\xa3L\xaf%R\xd9I\xff\x8f\xe6\x9a\x11\xa9\xb6\xdb\x0d\xd7\xa6\x10\xc6\xd7a\xfe#\xa2]\xcb\xeaa'OO\x16\x83\x1f\x83M\xab\xd2\xfe\xb3\xd0\xf4\x17x\x13\xfcOg^\x0b\x8b\x03T4\xc6p\xda\xdc,\x7f\xf2`\xd9\xe9\x86\x05\xa7\xdfV\xef]\xfd\xc9\xa4\xee\x91[\x14-\xfa.\xf4,\xc7\xc2\xdd\xf4g\xce6)\x9b\x059\x17\xf1OI\xf3-^9B]3\xf6\xa5\x15\xa3\xee\x9a\xccS\xf2!\x0e4\x86\xa4\xbdh\xa1\xa7t\xb8JQ\xd6UZTi\xa8\xaa\x8a-j\x19\x96\xaf\xdb \xc4\x82u\xb7X\xb4\xf7R\xd2/;\\\xf0SzU\x8b.\ne\x15\xaaE\xf6\x80\xbaN\xd9B\xf2AW\x81Z\xf4O\xb0\xe8\xc6-\xda(4\xe8\xc7-B\x12X\xd5\xfd\x16\xce\x0ff\x89\x96\x04b<\xd2\xa9}mo\xb0f\xd6\xd5\x9a\xebzB\x04P\xf7_\xd7\x1fa-\x89\xa4\x89V\xb8\xb5\x0b\x8f\"\xf7\xc7\xb6\xabb\n\x9c\xc7\xf0s\xf3\x8c\nm\xba\xcdh\xdf\x11<\xba\x82\xb4v\xb6-\x96P{\xd3\\\xb5tR)*\x97\xde\xb5U\xd7\x0eiUu\xed][uqD\xa7\xaa\x8a\xdf\xcd\xd5\xa4<5\x86\xcb\xf6\x82\x82\x95\x8f\xe1\xba\xbd\xac\xe2\xe3c\xb8h\x19y!$\x8c\xe1e{Y\xad\xe5W\xcd\xa5K\xf2\xd0\x18\x8e\xbb\x94\xd6Z?k.\xaf Och\xd9\x9d\x92\xe44\x86g\xcd\xa5u\xc1r\x0c'\x1d\n\xa3T9\x86\x9b\xe6\xa2\x8bx\x0co\xac%l\x87\xab\xb5\xb7\x1f\xcf=\xbfrO\xe4\xa3\x9b\x0d^mSfJ1\xb9\x92\xe4\x02-\x1d\xb5\xb3\xa9\x12s\xda\xab84\x16t\x00\xdd\xc7J\xdf*\xbc\xa4Z\xd5\xc4\x0c\xaa\xb2\x84\x8d\xf2k\xc6\x05\xcc\x15#&\x00\x13\xa0\\\x14\xbf7\xc7\xaf\xc8\xe6\xf8\x15\xd9\x1c\xbf\"\x9b\xe3Wds\xfc\x8al\x8e_\xfc\xc3Pw\x1a\x8a\xc8\xb9\xcb\x92k\xfa\xb7\xf6\xd9\x9a5\xfadi\xfeX&k\x8cv\\ip\xc7\xf2?\xd9\xe5Jx\x18bq\x992\xa7\x9a\xd6\xc8\xe8\xd4\xf8\x19\x07\xa7d\xa0Z\xb2\xfc\x07$t\x06)\xbe\xab}j\x17\xdbT\xbe\x83\xaa\x1c\x9b\x14\xdf\xc1l\x9b\xa6\\\xbch\x10t\xd1>\xe9\xc6\x98T\xbc\xd1y\x0d\xef\xe8\xb6\xceO\xab\x90Yd\x1dg5r\xa4O\xeb\xd7\xf0\"\x11\xdc\x03D\xf0\x19\xbcS\xe0|\x8d\xe7\xf5_;\xf0ug\xd2Z\x86\x00\x93@\xd5bg\xfc\xa4=T@a\xb3\xe6\xb6\xac\x06\xa3\xa50\\\xfb(\xcf\xa7\xcc88\xd3\x90\xed\x99\x18\x87Nwg>\xccj|\x84Z\xff\x171\x16\xcf\xfftb\x8c \x8b(\x15\xfa\xd5|a\xb0\x8b\xd3\xac\xba\xf0\xc3WL\x91_\x15_?\x82 \xe5 u3\x8fr\xe8\x0f\x1f\xc3\x0c\x9e@\xf6\x18f\xbd\x9e\x07\xd1tv\xae\xd7\x9c\xce\x0ca\x01\xc5R\xc6x\xe1\xd1\xe6\x9c\x8b\x18\xd8\xca-fA\x14 \x96\xc1|\x98\xf2\xba\xe72\xf4b\x84IZ\xc3\xc1,J\xb2N\xeeV\xc2\xc5J\xb7\xfd\xa11\xfc9G\x85\x10\x7f\xbbU\xffz 4\xc3\x8bZ5\xa6\xc77\xe3\xb7\xe0\\_\x96\xe4ub[\x1d\x0d\x9eqwcj\xba\x03;\xa4\xd3\x15\x96\xa6\x1d\x86\x10\xeeb\xf1\x0e\x84\xf1t\xf0\xec\xec\x8d\xbd\x14\xdfm\xed\x04-\x90)m\x1b\xcc`\x98\x0e\x15\xa1)\xd6\xc1\xa9\x81sS\x8aT\x87\xaf]f\xcb\xd0\xd0\xc6\x8a\xe7\xe1U\x8dT\xeb\x8f\xbaV5\x06g\x1e\x06Q\xb2\xecoo\xacWq\xbfH7\x97\xc1\xec\xfd\x1f\xea\xe57Z<9\xa5>^\xcf\xff\x8d\xfaZ\xb1`\xfe)\x9d\xad\x0e\x95\x1c\xe8<\xbb\n\xc2(\xb8\x8c\x18\xea\xfbI\x1a\xfe\"\\\xb8\x9a6\xfbr\x9b\xe7h\xe0\xb5\x0f8\xbf\xdd P\x89\x92\x9d&\x86\xfc\xa0\x8f\xd3k\xa8\x91\xc4\xba\xb9 \xeb\xec\xbc\x02\xd9\xd5\xb2q\xf4\xd7\xe1<_\x8d\xc19\x186\x0cd%\xa2;\xf0R;\x8f`\x9b\xd5e5\xfdY\xa5l1\x06\xe7+\x9c_\xc3 n\xa20~\xff}\xa9\xb0\x05y\x91\xe9~Y\x00\x9c%q\xce\xe2\xdc:\xfbh\x80|\xee\x8c\xfd\xcd\xf5\x06\xeb`S\xcaI\xdex\xfd\xb7\x85~\xce\xda\xcc\xb6\xc8~[\x0e?\x9e\x9d\xbdi=\xf0\x98\x17,\xc1\x1a\xb7D>e\x13X\xcb\x19\x96\xce\"[\x0f\x81*\xa6\xb8\x96\x93\xdb\x92\x91\xaf\xc5\x00\\1{\xd6\xdd\xa1\xe5c\xb3\xb4y\xf8\xd4\xbe}9%\n\xdf\xfeK_\x12\xcf\xbf\xf4\xa5\xff\xc5\xfa\x92\xe0|]4\xa6\xce\x97S\xf2\xeez@\\\xd7/\x06\x1a}|\x93\xa8\x83g\x9bI&\xafim\xe6\xd4\x15\xffR\xda\xccO,\x80\xac\xac\x8dy\xa4\x8b(\xd9\xedU\xb2\xd9n\x1c4,6+u{{\xbb)>\x89\xa8\x13\x14\xee\xce\xde \x0b\x7f\xb1D\x13\xf9\x92:\x10\xef\xb2\x7f\x9d\x06\x9b\xcd\xa7\x08\xbc\x1d\xe4U\xad\xb3\x04\x8e\xc0\xb9\xccc%\x113\x88\x92\xd9{6w`\\\xfd\xb0\x8d\xc5\xa7\xae\xf2\xaa\xf8\xb5\xf3\x14\xb2M\x10kR\xbb\x1c@\xa3\x98\xfe\xcf\"\xe5\xe2\x82\x7f\xa5\xad\xf1W\x1d\x96U\x13|\x1b\xea\x9bG\x8c\xf4\x14\xddkm#\x8f\x85u\xf8_\x92\x0d\xfcK\xb2\x81\x7fI6\xbf\xbddc\xbd7\xc0\x06Y\x9el8\xd4\x07\xcb\x80\xf8\xb0\x99\xff\xc8\xcb\x05\xd2z,:\xb1\x88&\xe8lop\xa9\xff\x9f(\x8e\x94\x1c\xd5?\x8dy\xef\xc6R9\n\x96\x85\x94\x8b\x0b\xceH5\x9am\xf8\xda\x81\x0b8A\x1a\x06\xfd(\xb8d\x91c\xea\x06h\x9c\xd6\x8e\xe4\xf7\x0e]}!>\xfeO\xc2\x93\xd9g\xf2\xe4\x86\xfa\xe6\x11\xff/\xb4\"\xcc8K\xad\xf1\xd4D|\xa9q\xe1PV11\xdb\x99\x89\x0bo\xc5\x87\x1a\x17\xce\xc4\x87\x1a\x17\x8e\xc4\x87\x12\x17\x9e\xc9\xc8G3\x11\xf9\xc8\xc4\x8fg\xbf=?^t\xe5\xc7\xb6\xb0EU*l\xe5\xb9W\"\xafz\x95\x98[}g\x92:\x0fl W$\x16+\x18$1\xa7\xcd\xc7\xab ^\xb6g0\x02\x8d\xcf\xb1A\x1c\xac-\xbaXP\\[\xab\xb0\xe8\xbf\x7fDL`&\xf4\xe3\xfc.\xc3\xbb\xee|H\x9d\x06S\x0fb\xc7\x1b\xa9\x1f\xdf*\x15\xca\x0d\xc8\xe3\xd7\xd2}\x94,M\x91tv\xe8\xbfY8\x08\xda\x14t\x8a\xab\xd0\xc9@B\xc1\x154\x93H\xcd\xe6\xdd\x1a\x80U@\x819\xa25 \x1d\x19\xe4 \xc9w\x96\x99\xc5b\xcd\\s:\xd3\xa0~\xec\xbe\xc3b\x9a7\xb3\xe3Y|P\x84\xfa\xe0\xbf,8\x0ee\xd9)3\xcaN\xc1?@vj6\xe2t1\xf6\xc4U\x00i\x83\xa5\xee\x87\xeeyW\x1bR\x88\x85\xbb\x9d\xd0\x07t\xd2\xcd\x91\xff4g\xeb\xa6\xabH[*Jy\xe0\xda\x8cO\x19\x15\xfe\x96d\xc8\x96\xa3\xf6\xa4do\xb2\x97\xa5\xc0\x19\x8b0\xcaY\xfaIH\xb7\xb77\xc3k?\x96(\xea\x80\xd8g\xef\x7fc\xee\xbfc\xe7r\xe5D\xd4]\xbc~\x94\xdfnXC\x8c\xd8\xa6\xc1\xcc\xbf\xcc`&;\x0c\xa6Q\x8f\xb0\xdd\xbf\xd8\xdd\x088K\xe2<\x08\x9b\x0e\xd9\xf7\xf66h\x95\xe4b\x87\xb5\xdfE\x92\xae\x1b;Nb\x8a\xf2\"o\xa5(6h\xebvS\xa6\xf6mI\x97Z\x16&\xe8t\xc2\xd9v\xba7[\xb1u\xd0z`\x18\xe3\xf2\xb6\xb4\xb5\xd3\xe9\xa6.\xc3\x8c\x81\x95d\x9a\xe6\x9a\x81vy\xad\xe5\xdeK\xf9\x08\xf5\x13\x8e.\x0bN\xea\x7fA\x00\xbd\xcc\xe3VK\xb5\x00P\x8e^\x0b\xfa\xf3\xc8:\x82\xack\xef\\e\xa6\xa3yi\xa3\xee\xac\xcdjR\x96m\xc8\xce\x0fX\xc6\xf1`\xfciC\x15\x1e!\x84H\x1d=B\xeaS*\x00\xc4\xba\xb8e\xeb\xf8'\x8d\xb5e\x0c|\x8b\xe7I\xdc\xe4\x97\xb1\x83\x97\x8as\x8cn\x1bh\n\x9bs\xa25o\x03 \x01\x94t\x18\xf0E 7\x9b%\x1b\xd6\x9f\xb3E\x83/\x87\xa5\x9bMq,q\xc6[\xc9 H\x19l36\x87<\x81e\x1a\xc49\x041\x04\x9bM\x14\x8a\x80\xd3\xf3p\xb1`)\x8bs\x88\xd8\x15\x8b2H\x16\x10\xccf,\xcbx\x95y\x90\x07\x90\xc4p\xc9VA\xb4\xe0\xdf\xf2\x15\x03\x16\xcfy\xa3\xe9\x00N\x82\xd9\n\x9e\xbd:\x85up\x0bs6\x8bx\x7fI\xcc Ia\x9d\xa4\x0cp2\xd9\xa0i\xf7\xf5Q\xf3\xa6R\xf6\xb7m\x98\xb2\x0c\xbbZ$Q\x94\\\x87\xf1R\xb6\x04Dg\x80b\xe1'1\xcb\xe06\xd9\xc25\x9f\x9a\x9ac\x9e\xc0\x19\xa5\xd1\x85\xb7\xa7\x03\x07\xe3\x03\xef\xc6\x81?\x8d\xfb~\xac\xbb\xd64J<\x9f\xcb\x91A2\x9f\x06%\xc5\xbe\xf0\xdb\xb6\xa6w`\x00\x92\xbd\xb5\x05\x8dA\x10oR\xa9\xda\x19\x04\xa7z\x9ft] \xeal\xa3\xa2\xe4b\xbf7\x1b\xd5\xef\xf2<\xc8\xa7?,\x96\xa8\x7f\xb6\x93\xa1\xffy\x17\xb6\xbe\xa8\xda\xdd\xa6T\x8b\xd0\xaaH\x0b\x9aUo2\x905\xeb\xdc\xbb9\xbaw\x93kC\xe5\xe3\xd1\x16\x1a(\xd8\xc1}^h\xdc\xc1&\xfc3\xbb\xe5\xc3hR\xa4#*|\x19d\xe1\xac\xad\xecL9\xd17+\xdb\xb9\xce\x9a\xcc\xda_v\x1db\x06\x93E\x13C\x9a\x05\x19\x031\x0fgl-\x06bh\xb6\x83\x8dV\xce\x02\x1d\xb5&\xe8\xae9AW\xed j\xfaJ\x87\xc8\x1c:+\xec\x10\xf9c'\x0d\x0dHF\x15\x1a\x9a=\x8d&4\xe8\xf6\xf2\xb9LY`9V\x05\xb5\xbf\x08z\x9f\xb1\xbd\xd1\xbf\xb6\xf7\xf7\xb9\xbd\x92U~\xf2\xcev\x928A\xedn\xf3\\|p\xde\xc6\xef\xe3\xe4:Vas4'nTB\xc1\xf1a\xd1\xf5v+t8\x0bo\x1b?\x8d\x1bz\xe0\xf4\x7f\xde\xae7V\x15\xcb\x90h\xe6\x7f\xf8 \xe8\xefR\xba\xfc\x97L\xf9\xbfD\xa6\xe4\x82V\xd2@HU\x1c\x00\xd7A;E\x93\xd0\x14\x17e\xd7,\xcb\x82%k*\x9d\x16\xa5\xb3d\x9b\xce\xac\x02\xd4\xe7\x92\x1e\xdd\xc6\x83\xb3\xb5\x85m\x05\xcc\xd3}\x1b1\x13\xe4\xea\xcfe0{\xbfL\x93m\xd4)\xd5\xe7\xfbm\x80\x1e\xf5\x07\x97\xe7\x1f\x16\x98\xbay\xa7\xa1t#\xaa\xc9\x95\x16t\x7f\xea;w\x8a\xd4\x10\x9c\xe0\xe14\x1c[z\x9c\xfa\x92\xdbX\xd8\xef\"\x94w\x1b\xdc\x83.(u0\xb2\x81\x12\x95\xba\x99\xc4@\x19\xe6\xda\xf7.\xc44\x8d\xcei\xbc\xd9\xe6m1v\x03*\xfb:\xb9n+\xb9\xa5\x92\xc7I\xa3\xb0\x08*\xff$\x1e\x19\x9fp\xc1\xac\xad\xfc\x8c\xca\xff\x18\xa4\xef\xe7\xc9ukX`\xcaB\xe9\xfc C\x9d\xbe\n\xf2U\x9bO\x0e\x08\x17\x96\\\x04W\x12\xa4\xa9\xb9\xc2\x1c Y\x10E8\x85\xcc\xf5v;\xf0\x92\x8fdo$\x11\xf3%9\x9d;\x1e\x9e\x7f}\xba\xe9\xa2\xdb9W\xcb\x19\xea\xean{\x99Y2g\xaaT\xa2\xe2\x04\xbb\x0e\x07B<\x07t\xfe\xff\xff\x0f\\2pz\x8e\xbd\xa5E\x9b\x11\x84\xa2#OU\x16\x19\xcd\xe7\xce\xf1!9\xb7V\xc6\xb4\xb6\x9bF\x87\x98\xd5}\xc3\xf5\xb2y\xd3\x19j\xd0\xb62\xad\xb7\xf4I\xf7\x19\xcb\xf5\x9a\xb3l\x96\x86\x9b\x1c\xa3^7\xcf\xe5\x93\xc7\xa4\x1f\xfc\n\xbd\xa8\xeb\xd6\x96w\xf5\x8b\x8d\xe24\xde}\x0ca\xfc\xd9#\xa0;\x13j\x14\x88\xeec\x07\xc1\xa4\xc1\xf1\xa04\x18\x07\xbe\xc1\x07\x1a\x9dB\xb6mC \xdb\xc0Dx\x8ep\xe5\xabE\xcd*L\x9e\xf2\x92\x06\xfel\x82%\xcf\x87yS\x98\x8a\xae\xde\x83\x9f\xe4g\"\x1fT\xcd[\x0f\xb2\xa1\xfd\xe4\x1d\xc0\xea\xefD\x9f:\x0b\x1a\xa6\x80\xa9\xa6\xc3\xec\xf2\x907m\x97\xd3u\xc1\xa2N\xbbK\xbb\xa67e\xdd\x85+\x91\xfa\x8e\x15\x97\xbcZN\xe3\xc8[6\x0f\xd2%\xcbi\xe3\xede\xe5\xdd\xb7\x8a\xbf<#\x91\xbcmg\x85\xc0ega6\xf6\xc5\no\xfd\x10\xd3L\x87\xadz\xfc\xbf|\n\x8a\xe7\x93\xac\xbe\xffd>\x05\xb0\x9bN\xde\xe9f)\x88\x9e\x7f\x83\xc4\xdc\x0b*\x186\x8cb\xdb%|\x05\xdf\xd1m\xab\xde\x11a\xa9f\x9d`&\xf3a\x0b\xc1w\xb0\xcdXj\xbfP#v\xbfK\xf6RR\xce\x1b4o\xa9\x9c7\xccS*\xe7p\xd4Bs\xe4\xa8m\x8a<\x7f>r\xf0\xb4\x9a\x19\x7f\xeb\x94\xa8\xffp=\xbf\x8bc\x06\x94\\HZ\x95\x0e\xbaM,\xf5\xfcX\xd3\xf39\xda\xd8\xd6\xbe\xbe\xf0\xffK\xb5\xfdv\xed}\x978\x93\xf0;\xd0\xf6\xa3O\xd3\xf6wS\xdf\x17\xbb\x99\x08\x0c\xda\xbe\"z\xedj\x7f\xf2\xab\xaa\xfduc\xa3\xfetP\xfb[N\xccH#\xb1GH,\xd4~\xe7\xdb \x0bg\xe5\xe8\x88\x8e\xbdj\xab\xce\xdb\xac\xc3\xa7]tx\xfb\xb0\xad:\xbc\xadJ\xd0\xb6\x14\xad6\x89O\xd7\xe1?yLU\xdd\xf5\xad\xe4yR}\xb5V\xac\xa8\xaf\x8e\x0f\x1b\xfc\x9f\xeb\xaf\x0d~e\xcd\xc3\xf9\x82\xfa\xabpC\x9f#q\xa7?[j\x10\xafw$\xde\xfe*\xfa\xf1\x17\xdb\xa8WA\x96]'\xe9|\xe7\x8d\xd2\xed\x0c\xbf\xde>\xed\xbe\xfa\xc16O8g\x8bX\xcew!f\xd7\xfd\x8d\x98c\xb7}\xebXZ@P\xc7\xd2\x9f\xb6\xcb_\xc4\n\xf2Y\xde{\xff$V\x10\xd3\x11yy\xc8\x8b\xdf\xbf\x15$\xd5\xac \xf6R \xda\xf7;\x18I\xd2\x16\x99\x8d\x1c\x9b)\xb5\x176gf\xe0\xc14<\xe7\xb2\x85\xaf\x9b@\x9a\xe4V\x94q\x03\xf3n\xa2\xe5\x84Y\xa3\x0b\x94w\xf5\x9f\xc9\xc7aa\x8d\x1b\xb2\xb0\xf98,l>\x0e\x0b\x9b\x8f\xc3\xc2\xe6\xe3\xb0\xb0\xf98,\xc8\xb2R\xfe\xc0\x05Yw!M,\xfc\x8fGw\x1fxf#\xcb\xe2\xb77\xb2l\xbe\xa4\x91\xe5\xf7\xe6\xf80\xff]:>\x04\x9d\x14\xee\x85*\xd9A\xc3\xe3\xbb8\xe3 B\x17\xf8\xb3\x06\xc5\x07\xa3\x98\x0c\x8a\x04d\xae\xd0\xc8\xed5\xae`Bb\xf7\x86$\\%j\xb5f\x16]Wj\xce\xa2\x90\xc5\xf9\xa9H&\xba\x1a\xc8\xdfm\xed,\x8d\xed\x9c\xb1Y\xca\xf2r[\xf4\xae\xad\xbd\xdbJ{R\xacx\x8379\xb0\xb6\xc8Q\xd8\xbfL\xe6\xb7\xceg\xbb\xa7\x04\x9b\x0d\x9d\xb5\xad\x06\xe2O\xfb\xe0\xbe\x84+\x0b]\xdb\x1c\xc3\xf4\xbc\x01\x14\xc5\xe27\xa6\xdb\xd4W\xb51\xb9favkH\xea(\xd7y\xdc\xb8;\xfan\x8c\xe1\xd6X\xee\x1f\xe0\x8e\xf3\xab\x18\x9b\x9a%\xbd\xaeaU@\x85Vi\xa3?\x00\xbbEV\x81]\xa3\xab\xc0\x8e\x11V@\xb0\xe1\xbc\x83\xcdkKS\xec\x96/\x05\x8a0+\x9d\x8c^\"\xa9I\x07\xa3\xd7\x82Jv0zm\xba\x86y\x01\xe9J\xb2\x83\x85lE\xe5w\xb3\x90]Q\xa5\xae\x16\xb25\x9e\x1b\x84\xd9\xcbgg\x87\xcd%9\x89^\xbb^-\xfe\xe01\xd7c1\xea ^o\xc7\x9f\xcd-\xdd\x16-\x11\xf59N\xd9\x9c\xc5y\x18D\x19\xb5T\\\xa4oi\xea\xff\xb2\xf7\xef\xebm\x1b\xc9\xa28\xfa\xffz\x8a\x12fN\x06\x1c\x93\xb0(\xdf\x99(>\x89-\xef8c\xc7\xde\x96\x9d\xcc\xda\x1ao} \xd0$\x11\x83\x00\x02\x80\x944\x89\xdfe?\xcbz\xb2\xdf\xd7\xd5\xdd\xb8\xf6\x0d\x94l\xcb\x19c\xd6r(\xa0\x80\xbeUW\xd7\xbd\xe6\x98\x04\x06I\xfc\"6/\xeci\x0d\x8eu*I\xc8\xe2\xf9\xd9\x91\xc0\x9f\x14\xfc\x96\xfeSg\x98)\xba\x9d\xb9\x07\xdf\xf7\x0d/\x1e\xa1\x15\xe6Cj\x16\xe5\xc2\x82\xb8t9u\x80W\xc5\xdf;\xbaT\xa7\x9c\xad\x1fG![\xbff\x88\xbf\x08\x040\xf4\x0fsC\xe8;y\\/dK\x1dgT\x9a^\x99\xaf\x94?\x06\x07\xdc\x17\xdfm\xca\xd5\xc1\x18\xe8\xed\x16\x1a\x823\xd2\xb9\xbc\xacL\xca\x02\xbd\x0e\xd57\xe8P\xcb\xba\xca4\xe7Ft\x1e/\xab;\x0d\x9dj\xbd\xf5\xd0g\xa7\xff\xa5J\x9b\xc8\xde8\xd6\xb9\\mM\xc3\x14\xaaU\xd9Zj\x868\x86\xb3\x1d=\xbd\\'Z\xd3\x11F%\xc3\xcc9\xdd\xf8s\xfc\xb9\x1ci\xbf\x99\xf5?\xc9R}\xbcy\xf5l\x80{SRo\xd8\xea\x13o\xf2\x98\xe5F\xa9\x19\xd5~\xef\xea\x9f\x17\xd6\x1d}\x9d\xbe#\xac\x83\xd6\xfds\x1a\xb8\\\xd2\xd7\xab\xcei\x1b\xd4/s3F\x077\x88zm\xc7\xe0<\x89\xd3\xb3\xe13\xca6\x1e\xfa\"\xd6\x93\xb8\x87\x93\xf8\x10!5\x0e\\\x81i\xe7\x1b\x01*=\xb0~\"V\xe5:~\x82AB\x98\x01\xe5\xb4\x92\xb4\xb4\x13\xb2ij\xff\xcf\x068\xaf\xb57pe\xf9\x12;X\xf5\x19\xa3E\xa4\xf4\xe71\x15\x17\xa6\x9a\xf8y@UE\xf1\xaeL3\n\xa8\x1b\xa0r8\x11\xf2u\xa6\xdeDa\x7f>\x0dl\xb7\xb5\xb9\xc2 \xfd\xd2\x9f\xe0'/a\x83@\xfe\xd4JE\xfd\xb1\x11\xb0\xda*Z\x04\xcc\x9aV\x8d!\x08h\xe3=\xf9\xf9b\x9b\xa5\xb1b\x98i\xa3\x8dq\x96/}\x16\x18'\xc6r\x8a\xf94\xb4\x08\x87S6\x14\xd9\xda\xd4\xae\xa9d\xf8|(^\x81r\xafqR\x11 \xdb\xf3\xb9\x0bV\xbd6\xbf\xb8\x1bfiF\x98f\xdc\xbf@?B\xaeoi\xab\xe9\xb48\xf3\x8aA\x02B\xea\xf8\x95\x81=`i=\xb4M\xd7\x0e\x14W\xd9\xf0o\x1b\x92\x1b\xc6\xfc\xbf)\x08d~\xee\xafII\xf2\x02}\xe6)#\xc99E\xd4t\xaa9^|\xdce9\xbf\xfaJ\x8c\x19\xd9'\xc5\x96B\x1e\xd4\xdd;\xa3\x9f@f\xbc\x01'\x14\x8fZ>\xf5\xea\xe9\x0bk\xf642\x1cf\x15\xd8`\x02\xf3g=\xcd\xea\x89\xb3:\xc8,\xd8\xa6\x86\x9fA\x07\xbd\x0c\xda+\x86\xfa\x12\\\x1aB\xde*+\xc4\x87 m\xbd\xfduE{\xe9\xa3\xef\x93\x82YWl\xf6\n\x03\xfd\xb2_\xda\xfb\x85O\xe0n\x18\xcd,.W\xb5\xdfd\xf8\x7fl\xd3\xbdK\xec\x81=$\xfb\xa7\xf8\x8fe:W{-\x01W\xc2\xee\xb4\x92\x98\x9d\x9d\xe3 \xd3\xef\"\xe6\x9e\x0e\xcb^\x0df\xa5\xa1\xd1\x13\x12\xacS:]j\xe2\xa03y\xc1\x8a\x04\xef\xe6\xa9\xa2 \xb8\xb84\xadZEt1\x9cc^\xdfV\xe9\xc3\xe8\xdea9\xa2\x1c\xb8\x01s\xfc%\xba\x8a\xb7\x84\xfb\x8c\xd9PD\xaf0*(i\x08gpf\x06\xe6[\xa9\x9a\x19\xf3\x1b\xf5\xce ^\x9a \x1e\x19\xb6\x05p\xdd\xe4% 54\x89\xb5\xf5|\xed\xba\xd4\"\x9d\x8a\xb9OM\x0c\x8bJ]~\x170M\xc4.H\x8dTp\xe7Q\x9au\x94\xd0iO\xaf\x96\x03\xd6^r9\xbd(t\xdal\xea\xbfMM\x97\xf2\xb2\xd4\x15\x84$\xb5\xef\x18\x8e\xae\xc2\x03R5\xe0\xd0f\xb8\x1f\xcf\x03\xf2\x92\xf87<\xeb=\xb0\x859G\xc9H\xc7'eC\xda\xd6&\x887\x1e\xee\xbd\x0c\xf8\xba\x9e\xdb$\xc0\xff4}\xaf\xde\xd2v\xbf\x91\x15_\xb3\xfa\x97\x1d\x81Ej|\x18\x90\x1e\x1fx\xe7\xab\x14\xf9R(K\xc7\xddz\xcc*\xc7\xdd\xf0\n\x1cw{\xe5\x95\x94\x94\xa3\x94\x94W\"\xbb\x97Wj\xe3\x82i$\xc0GS\xd6n\xc3\xea%\x1b\\\x04\x8b\xe4\xb9\x112\xad\x1dq\xd0\x15O\x0d\x19\x0dq\xc1\xf1\xe1\x10R]\xe2\x92\x8d\x88\xf4\xac\\\x00\x15\x0en^\x10\x13?\xd7\xf8\x1f3\xc7\x82\x19\xe8Y2\xce]\xf9\xfa\x82\x1c\xc2\xd8\xcb\xe0\xe4h\xce\xbd\xb6\x02\x81\xc7#C\xdffU\xa4\xba\x16\x8c\xaf\x94\x96M\xad\x17T\x9b{6`S\xaa\xcd\x7fK\x9b|$\xe06\x8a\x91*\x11\xbc\xc5mZm3\xe1\x1covw\xcf\xd1q\x02\xb9H\x9doj\x8a`\x94\xc1/D\n\x019\x06E\x0bp\xb1\xcc\xf4d\xca==\x18K\xca\xcbJDIH\xce_,\xdctd\xf2\x97\x8b\xa0\xf72\xaf\xa0{\x92\xbe\xd5\xf8uXy\xd1C\xc3crx\x15\x1d qA`/g\x1e\xda\x8a\xf1\xc1\xb7t\n\x18\x84\xb9C\xa23\x9d\xcf\x0dv\xba\xa9\x9c\xc7\xf7\xb4\x89\x84\x94\xf5\x8148\xd8P\x04\\1\x0e\xb6\x91KOY0\xaa\xd5\x14\x9e\xe1\xcbsX\xa4cPE\xdf7\x16\xc9WO\x02\xe3\x98\xacF\xdf?\xe8\xd4\x1e\xe9\x89\xcdy\xc46\xaa\xd5y\xc4\xe6\xd3\xe6_\xfb\xe7\xca\xbf\xbe\xf2\xb2M\xb1r\x9d\x9c\x14Y\x9a\x14\x04\xed\xca\x87\xa8\xd3WP3E\xde|\xd6^ev\x1c\xd2\x1a\xba\x9c\xed\xd4\\\xdf\x95\xf8C\xcca\xcf\xf3y\xc8\xe0\xd8T\xb6^hS0\x87R\xa0d\xe9\xc0\xe1!\x92\xd1t\xc1\xa2X\xc4\xe7*C\xdd!\xaa\xff\x12\xfa\xc17\xaf\x9eV\xb2\x9e\x9bu\x03\xa5(A\xd9b.\x03Vr\xeb\x15 \xa3\x9c\x04\xe5\x9bZ\x9f\xd1\x13\xe8t\x0c+\xfe\xd1\xaf\x9c\xd1[\xf6\x93\x8bS\xa7\x95\x84\xe1\x8b\"9\xa6@\xb09\x8b\xe5\xd4\x19\x89\xba\x06\xa2y\x99Lp\xee \xcd\xe6q\x1a\xbc\xc3\x12\xeey\x1a\x9f\x9e\xceK]\x08c\xdbF\xc4\xff\x92B3\x0b\x11\xf1sI\\\x94\xb1\xde\x89\xa9\xce\xc9\xf5\xcc\xa1\x8aD_\x9a\x03\xe4Z\xd69\x19\xb3\x1f\x07X\x15\xd9\xbd\xf7y\x9c\x05\xd0\xd29\xad\x88\x1f\x92\\b\xf53\xed\x19\xbb\xe0\xc9F\x98\xa1\xa0=\xc0\x9b\xd4\x17\xb2\xce\x1b\xd9\xc1\xbb\x12L{\x81\xcc\xc9N\xea\xd1\x86\\d\xfc(\xc3e\xae\xe9\xa2I\xfb\xe1\x8e\xc1\x81u\xe1\xe8G\x1d\x1aGm8\xf3\xa1M\xa0%Y^\xc6;gr\xb1\xa9\xa7\x06=*\x06W\x9c\xdb\xa1X\xa5\x9b8\xac\x08\xe1\x9b,\xf4K\xdb|\xac6\x15\xcd\xeb$\x0e\x9e\xd0\xf9\xa0tI\xea?\xff\xf8\xa3 E\x0fq\x0e\x81?\xdbO\xd9\xf1\xcd\x9f\xf3?\xda\x10aTd\xb1\x7f\xc11\xeb\xb1P\x7f\xb07\xe4\x0f\xa5c\xf8\xdcR\xb2\x8a\xe9\xd4\xc3\x0eM\xca\x9a\xd6\xf0\x06C=T\xd5\x8e\xe5\x93\xac\x7f\xd3\xafx=\x0b3?T\xcax=\xc7\x07\xfc\xc8\x12\x98\xa2\x87\x0c\x98\xf3\x00\xba\\<\xdfPi8\x14\xe4\xe9!\xf8\xde\xbau\xebI\x9a\xbb\x9b1\x14#\x98\x81\xef\xe5\x9d\x9b\xfa\x86B\xa8\n(S\xa1{cL\xa9\xb0\xa2\xa7+\xcf@$\xd7\x974\xafm\xfd\xf9\xea\x10\xf1\xca\xf4\xc7cSE\x97u\xfdb\x92\x96\x8f\xd3\x00I\x12\x86\x87k\xdf[\xd6\xef\x11\x9b\xf4\x1d\x175<\xfa.\x1a\xc0\xe75x\xe3\x98\xd0\xber\xda\xb7{n-\xd2VlO\x1c\xca\x9f\x92\xa4\x9c`\xe4\xd8[JZ\xb6'\xce#~\x13\xa3\xc24y\x85\x80\xeb\x94\x12\xd7 ,\x16\xea\x9c\x81\x8a\x8d\xfb=\x0b\xcf\xd2\xber\x0c\x87]wm\xa3)\x1c,\x0enk_W\xe8p\xf9\x0c\xc3\xe2\xc8\xe8\xf5%.\xa4\x95z\xa7\\\xe0l=8\x98\xe3\xcc\xc1\x90\xf7\xed y\xcb\xa2\x15\xb5\xef\x9a\x92x<\xa2\xe24\x1e\x06\xc7\\\xe0\x96\x8b\x82`1iMn'\xd0E\xaa\x1c\x99f\x96\xd3\x0fm\xe2\xf6\xd1\x18V\xda\xf4\x06v\xcc\xd7\xed>\xf3\xf5\xe6\xd53-\xdf5\xd4)TD&\xd2-\xa0\x1e\x8f%\xa3\xb7\xd2\xa7Xh\x8e\xe7\x98\xe4[\x92\x83\xd8O\xda1a\xf0\xcc\xc0Q\xb1\xcf\x16\x13\xf6\xeeN#+\xe9~1\xafR\x99\xef\xd85\xb6\x1dw\xec[8\xa8\xd1 \x8d!H\xe3S\xd6d5\xeb\x13z\x8f\x1fk\xban8h$\xd4.\xd1\xd5\xf5\xc7\xca}\x9cv\xea1)\xfd(.\x0cy=J\x8c\xa4\xfdP\xab\xf8\xd1Vo\xe8\x92\x85cX_e(S\xd5\xfe& kfc\xa7\xd1G\x8d\xe0\xba7\x8d\xaf\x81S\xf9\xf8_1\xaa\xed\x84_K\xdd\xf4\xb5\xca\xf7\xb6\n\x8e\xc1\x0d<\x04\xe1\x86\xb8]\x95\x99\xae\x03\x18.4\x9f>7\x0e\x8e183\xb80\xb0\xc8\x0c\x8e\xa5'4\x04\x17m\xf2x\x06\x06\xe6\x9c\xf3\xa7\xda\xcc\x89\xf4j\xca+\xba\x98\xb1\xf7\xf5|<\xd2\xcc\x871\xb4\xb2\xea\xd7\xb1MS\x11=\x96\xe7\x97 k\x10|\xed\x0c\xe6\xe6\x06\xd5\xe1-\x97\xf0\x85\x97\xeb?C\xbc{\xdd\xf4\x9f+\xa5\xfe\x13\x9f\xf4\xb4\x96\x91x\"S\x80\xaed\x9a\xd1\x0d\x7f\xd0\xd3\x8c\x16\xfcA\xaf\x8d\x98?\xe8iF\x03\xfe\xa0\x97\x1dy!\x1a\xdf\x7f\xd0}\x94Q\xf1e%\xb4\xa7h}\xec@\x84\xa2\x83\x8a\x9aU\xab\x8f\xafO\xdd\xda\xda\xd6T\xa9\x94\xa5&*\x99\xfd\xac\x99B\xb9\xb0Q\xbcEm\xc5\x9bE\ne\xac\xd0\\\xc7]\xbc\xc9\xe3!\x96-\x9eU\xb9\xad\xce\x90\xcb\x19\xc2LG\xce`!z\xe9\x12o\x93\xc7.\xe6\xe5\x17;5N\x99\xa3\x00\x95\xe4\x99;\x87+\xd1\x14\xca\xe7*\xe5s\xd5\xd4\xe3\x8c\xdc\x91\xc7\x1d\x8f\xd2\xbc\xe7\xf3\x04`\x9d\xe3\x17\xc9|\x7f\xbaT\xba\x86f\x9b\xb3\xa6\xabd\n\x0f\xc1Y\x95eV\xccn\xdeL\x13*Q\n\xbf\x06/JoV\xef9 \xab\xaa\xd7K\x8a\xab\xb4\xb1\xc5\x0d\\\xa8\x15\xa6m\xcb\x9b\xd2\xc6\x16\x08z\xf9K\x14\xc7\xafH@\xa2-\xd2\xb6\xc2\xc2\xec\xa6\x94\xd3\x85\xe2}\xf8\x12\x81\x88;\xb2p\xac\xc7uB`\xdb\xa5\x02\xddr\x95\x03\x96K\x1eZ'\xf3\xb1o/\xa1\xec\xd4\xbc\"[\xa7\xd8\xa9t\xce\x1b\xba\xe3\xf6\xe4\xd3\xed\xab\x9e\x1a\xb1d\x99W\xf8t.\xffM\xde\xe41\xa3Bu\xb1\x83j\xf2TqF^\xb0\xc9s\x92\x94OXj\x08s\x85\x93-%I{\xcc\xf9\x03\x7f\xbb\x1b,4\x97f\x05\xff\xc6f\x0c\x18\x9f\x88~\x16{Q\xf1\x93\xff\x93\xbbB\xfd\xca\x8a)0\xc4K\x1b\xaf\x88\xa3\x80\xd0M\xb2\xd2U\xc9m\xf9dlzy\xc5|\x13\x9fDw\xc3F \x87\xeb\xa4\xd5:\xea\n\xba@=dU\xbf\xac\x12\x92\xb1\x9d]\xb5\x89\x89\xf5\x0c\xf5\xb5\x00\xb5 \xcb\x17\xf3_\xad\x12\x99\x95\xfeR\x9b-F\\\x9d\xdd\xa7\xcdB\xd3~\xa7\xca[\x93\x9a\xdf\xa8\xf7\x9f6\x8bC\x0b\xdc\xc2& \x8c\xe7\xe8\xae\xbei\xe9\xa1!,\xf0\xe5\xcf|L\xa3m|\x0d*\xb2\xc5\x8d\xc5\xe5*5:\xf1\x89+\xc5@M\x816\xcf\xa2\x82\x9e\x8b\xb4ez\x98&c\xc8u9g\xc4\xc5\xd1\x8f\xc7j\xba%\xaf\xa3\x85\xa5\xad2\x98\xc1bTi \xf3Q\xad\x16\xdc\xb9\xb0\xba\xb8XJ\xd1*3\xa4\x05\x9a\xd0\x8b\x9e\x1e/\xb1\xac\x90\x05\x96\xd0+\xcd\xac\xd0\x1b\xaarE\x169@\x01\x83\xb9\xe9JY\xa17T\xdb\xc7\x08\xaa\x91\x8c\xd8\xe3F>D%d\x13\x8a\"3\xa6\xb5\xfd\x06\xa6\xbaB\xde\xab[\x0d\xaf\x8c\x9fR\xa8\xc9\x17p\x856D \xce\xfe^]8\xe9R\x96mYy\xe6\xcf\xc9\xb2-\xad\xe1\x9b\xaaj\xf8F\xaa\x1a\xbe\xbe\xaa\x86\xefFU\xc3\xb7P\xd5\xf0\x8d{5|Y \xcf\x82K\x05m\xe8@\x04\xcb~\x16%~\x0d\\\xfb\xa7\xe4\xd8\xafi\x88\xe0\x10\xee\x9cq\xe6\x8c\x1bPC%\x02J\x0d\xc2\x8e\xb2`\x15\xc5aN4\x944\x1d\xc6\xa9GC\xb8t\xdf\x9aC\xdf\x0c\x90/\xb0p\xb2\x8e%_\xb0\xc38\x0d\x8e\xce3?)\xb4Q\x14\x19?\xb8I\xf6,J\xdeE\x89fFCQ\x04\xd8Y\xf8qAX\n\xfeL\x0dO\xb9\xf4\x0d\x96\xfd\x8c\xfd\x0c\x1dk\x95\xa0[\x06jSes\xcd@\x1f\xf3\x1e\xeb@\x97\x0c\xd4\x04V\x05\x164\xa1\x1aJ1\x9cb\xab\xb7\x15\xb5r\xc8\xe7yz\xa6\x19\xdcY\x14R\xd2\xe0\x1c\xec\xeb\xbccH\xb4\\\x95\x0cjpo7\x85>\x14\x88\xed\x08\\\xab\xbf\xc4\x14\xcf&\xd8\xe7 r8t\xa9\x9aw5\x9d<\x8f\xa3\xe4\xdd\x0f\x83>\xa6\"6:\xad\xa3\xb6\x86rT\xbc\xc8HB \xf6\x91j\x9er\xa3\xf9@\x92JC'xg\xe2)\x1a\xe6{\xce'BcX\xab\x9d\x16y\xba\xfe\xf1\xd8\xfd\xbd\x1b\xcd\x87\x1a\x0f\xa7\x9e\x94\xf7\xe3k\x97\xd0\xb4/\xd4g*\xa1>S \xf5\x99J\xa8\xcfTB}6,GS\xe6vc\x94\xa9\xe4\xeef:\x97\xf3\x05~\xed^sY\xb96@&\xecg\x1f_\xd8\xd7\x9b\xe9\xbe\x08\xfb\xe2\xfap\xc2\xbeP\xa4\xaa\xe1r\xcbT\x05)\x87\xc3@R\x0dc\xc9\xb4\x07\xe9r\x19\x13d1\xd5\xa0L\x82O\x93\xd79\x15\xf8\xf1\xb8T\x03o8\xf0#? Hl\x00.8\xf0\xd19 6\xba|\xfb\x0b\xa3\xe1.\x1b\xa0<\x08\xadU\x12\xabjq\x8cz\x8e\xed\x10s\xea\x1a\x81\xad2q/+P\x8b\xef^\xb0 \xf5\x8b[\xc6\xef\xce+P\x8b\xef\x9e\xb6\xdd\xce*\xc6J\xc3z`\xb8\xbd)w\x02\x15\x9f\xcf\xbc\x90d9 \xfcRW=\xe0\x1c!\xb98\xa4\x06;F0}n\x8bG\x08c\xcak\xf1\x0e\xa1R\x8dn\xe7;\x84\xd0*\xe0^\xf0\x8f\xf0\xe9\xd2\x95\x9c|\x89\xa0~\x1c\xa7g\xaf\xf3\x8b\xa7\xe5\x8b\x8d\x06\x83_\xb3y\x1b\x98-\xe49\xeb0\xff\xfa\x11\x13?\xd5\xe0O\x11\x9c\xb0\xbd\xf94y\x99\xa7\xcb\x9c\x14\x1a,\xf9\x15\x0e\xe1\x9d\xd7P\xea\xa8A\x7fB\xd0\xa6\xeeF\x0d\xfb\na1\xdd\xb7,\xa3\xb7\xb8\x1e#\xc6 %Q\x9ai\xb5@\xcf\xe0\x10\x1e3#_\x15\x02\xae\xd3\x8f\xbd\xa9\xe1\xb3<\x0d7\x81\x1e\xfc7\xee\x8f\x8c\xa9G\x9eEE9r\x1f\x8f\xe1\xc4iT\xd5\xd5\xf5\xee \x1c\xc2\xb6F\x9bc\x1c\xba{<\x86G\x9a\x97\xfe\xddQl9c\xf8n\x0c/4\xca\xab\xef\x9b\xbd<:/ \xeaI\x8b\x91\xfbX\xd3\xcc\xcf\xc8\x04\xd9\xcd\xda\x0f\x0c\xb6YKX\x0d\xfc\x0b\x03\xe6\xf8\xa6\x83\xfc\x91A\x06,w\x9d\x1a\xee\xbf\x19\x9c\x8d\xf2\xf5\x1f\x0c\xd4F\xf9\xfa\xbf\x18(\xc7G\x1d\xe4_\x19d\xe5\xd5\xc1\xb2,h_\xf9?\x9dW\x8e\xf4I^\xfe\xd9ma\xb3^\xfb\xb96\x17\xca\xfff\xaf\x98\x14\xc2\x84\xf2/!\xcf\xe9S\xe3\x86\xda\xa5\xf7\x19f\x8fe)d\xd1\xc4\xf9-\xec\x9b\xdc\x95\xd0\x9d~\xef\x19\xee+\x1e\x9a\x97{\xad\xec>,F\x87\x838\x9c{\xd3\xb9p\xe4\xe8\xe0R\xf43\xf1\x8c\xa1$\xb6\x16R\x10\x1e\x04\xb4\x7f't\xdfI\xd2\x84\x02\xd8\xe69\xb1\x12\xe6\x9b\xaa\xdb*\xe7c}2R\xf9\xf6\\\x06\xe2\xc0\x0dx\x047\xc0\x91\xe9x\xdbP\xea\xd5\x8e\xc2\x99F\x03\xfe\xefZ\x01\xaa\xd4\x80\xaa\xa6\xe0\x9fZ-\xb1\xc0[\x94ngp\xaa\xeea\x83S\xd5\xfa\x98\xb4}K4\xa7w\xab\x84\xd3Z\x0f\xd7\xf0\x9f\xd1\x1c\xf6\xb53\x84\xca!W=M\xffm\xa7x8\x1f:\xfdC0\xb0R\x8d\xab\xeb\xe2\xbf\x1f\xc3c\xba!\x1f\xb3-\xfe\xc7\x1f\xcc\xff\xe4\xf0\xf0\x10\x1e\xd7\xce(\xea\\\x13\x06?\xe8J\x15u\xeb \xd3\xd5S\x15z-\x03\x18\xbaU'\xee\xed\xe9TC\xe8d\x13\x10\xa7~\x18%\xcb\x89\x9fDk_c\x1f\x19\x8d\xe1H\x9bX\xc8`%\x91\xb5\x8d\xea\xcd\xd3$\xcd\xd7\xbe\"\x07\x10&x\xfa\xc5\xcf\x93(Y\xce\xe0qM\"Fc\xf8\xd5\"\xcf\xd1\xb0\xfe4\xd89}\xa9\xca\xab\xc6Bcf\x10M\x83\xff\xb01G\xfc\xaaX\xd4\xd1h\x0c?\xd1y\xfc \xc3=/\x91\xb6E6,\xc1\xf3N\xc24(v\x9f\xd1\x0f\x86YO\xa2$\x84u\x9a\x13\x08EF\x9f+^\xd8\xd6\x0c\x0c\x1f\xb91\xd0\xd5\xd8\xe6\xa99\xeb\xcceq\xeb\xa7\xa6\x18\xa4\xc23u\x1b\xff[\xd7\x86}\xb0\xac\xc5L\xc4\x91\xf6\x0bJ\x8b\xd6O\xda\xe8X\xf6\xb4\x91c\xa7yj\xa87\xd4\x0f\xbaa\xd7R\xc4\x0c~\xb3:\x85yA\x10;\xf1\xa3\xe2Ef\xf0X\x03\xc5+x\xff\x03\xdd%uj\xb8\xa6\xbaL\xeb\xaa\xdb\xd2\x95I\xeb]\x89\xab#\xb9\xcf\xe0\xb9\x86mi*\x12f\xf0R\x0d\xb9H\xa4Ev\xc4e\xcdP5\xb4d\xda\xecE-\x15\x996\x7fQ\xe6\x97\xab\xe7\xdc\xb1\x93q\xe1\x86nr\x17\xe4P\xb1\xe1*l|\xae\xc1\xc1\xbf\xeap\xd0z2\x98M\xfeX\x0d \x1cV5Ly\xda\x91\x1bgB\x03Q\x98\xe5H\xda~\xf5\xda\x16\x15b\x85;\x12\xda\x91\xe31T\x1f\xd1\xe9!\x96\x84\xbb\x83\x91\x90}l\x06s\xafh\xdd\xd1\xacs\xff\xe5\x0b\xafw\xd3\xf0>\x05\xf9\xd9\xcf#\x8a\xf0?3\xed;\xffH\xef\x89a\x18Mx6\x8ca_8Z,HPF[\">\x85\x9d\x11\xdf\xa9\x9e\xe2}3\xfe}\xf5\x15\xbc\xa4\xff\xbc\xc2\x7fLtq\xa7cV((T4Z\xd5\xd8\xff\xd2\x9eo\xec\xa33x\xf5aq\xdf\x96\x98\xf0H\x16\xa6!\x9b\xc1\x13\xc5\xcc\xd7S\x7f\x15S\xfc\xbcRu\xbc\xa4\x12\xf9\xbcL&\xcb<\xddd(ys\xfd\x95\x91\xb3{.\xdeW\xf5\xe8\x17+\xc9Y{Z\xd9\xce\xe20\x92|\xd9\xb5\xad\xec=3(\xacvJn\x9a\xaa\x1f\xb5(k9 \xf6C\xd3wz4\x86\xa7W\xb5\x97\x85 \x1aT\xc1dCw\xf3.\xcd)]'\xaaey\xa6\x19\xe0\xcf\xba\xd6*\xb5\xf1\x0c\x9e\xa9g\xbaJ\xea\xab\x89*\x11\xcc\x90(\xfb\xa0\x8d\xfd\xb0>\xb7[l\xc4Ul\x98\x86-N\x9b#\xd2\x1aK\xb9\xf5a\x06o\xcc@\xfc\x90\xda\x8a\x80\xbf\x97\xfc\xfe\x934w\x19C\xa59\xfc\xfb\x8c\xb4\x95\xce\xdf~\x1b\xa9A\xe4\x86\xad\x19\xbcV\xbf\x82\\\xac\x89\x9a\x10\xf4\xa0\xf8\xdet\xdc\xfe\x1f\x1d\x06\x93J\x17>\x83\xef\xad1\xce@2vq\x1bz\xb9\xc9\x89\xcce\xa8\xca|'w\x19j\x9c\x1c8)\xad\x87y\xb5\x99d\xcf\xf8\xa6\xec?\xaaQ\x85J\x8a\x0b\x8fY\xbc\xba>5\xcc6\xa1\xf3B\xfa\x12Z\xd4\x9e1\xa5\x17\xd2B\xee\x85\xb4\xa8\xbd\x90\xee5S\x19-4\xeeF_b\x8b\xfe\x03\xdd\x8d\xac\xfc~\x86\xc4\xfb\xe7\xf6\x0e-\xe9\x10\x87\x16\xe6\xa6\xd4\xb6\x13\xa9\xa1}K_\xaa\x0d\xd6\xd039\xa7\x14,\\\x9d\x91-5X\x80`QQ\x95=\xd5\xf0\x0d\x0b\x845\xb9\x9ed\x08\xa5s= Y\xd7V\xe9\xd9\xb1\xa9{+\xfe1\x0b\x17\x94-\x03\xcd\xa3e\x94\xf8\xf1\x0b\x9bW0\x12I8\xa2X\xbd\xb1\x84C\xc8\xcc\xb3z\x81K\xc4\xd5\x1d\xc1&\x8fJ\xadU{\xce\x12(Tu`\xab\xae|_j\x8d\xf9\xa7\x9d\xc4\x0b|:\x9f\x1b\x03\xbf\xcf\xe4/\xbe4\x04\x9a\xf3\x1a'?n\xd6\xd9\xeb\x14\x811;\xc4\x07\xb7.\xd7Z\x01\xd6O\xe8\xfc\x8d\x06b\x8d\x16\xb0\xae*(\x05\xd1\x08 \xa7\xba\x1e\n^P\xc5\xb9\xa9?{f\xaf\xa6\xd3\x05>v\x0c\xd0\x1a\xc3r\xcd\xe3\xc8\xe3\xc6ig\xc3\xab\x92\xfb\xba\xabcc\xafX\xd2\x83\xad\xa8\x99],\x8a\xedn\xe9\xdd\xd5\xc8\"{\xfen=\xab\x93\\D\x8a\x02\x04\xef\xc7 :Qg\xdc\xff\xea+\xb8\xf0\x82t\x93\x94\xae\xaeos\xbdY\xbc&\xb93\xd0d\xcc\x1a\x1e\xe3!N\xd4\x941\x94\x98\xef\x97JMT\"\x89r\xec[\xe1^\x982\x89 \x81\xae\x13\x06\x17\xae\xc2\x01\x05z\xacEu\xd7\xac\xb8\xd2V\xc8\xc9\xb4\x08{\x85B\x87!N\xa1\xbb\xcfL\"D\xb0\xb3\x08q=\x03\x19>i\xa6\xb2\x01\xc5\xa6?\xa32\xa3_\xc4\x04q\xed.&hK:\x9b\xb8\x8fK\x1d\x1b<\xb3\x8e\xf4\xdd\xf7c\x94P\xded\x19\xc9\x1f\xf9\x05\x91%W\xd9\x99P-\x86\x13\xaa\xfa\xbb\xe3\xcf\xa0\xc4\xf1g\xaa\xad\x10\x91S_\x94\x16\xff\xb1\xd4H\xcd\xc0\x95\x034\x11\x89Dc`\x14\xf5\xe9\xc6I\xac\xe2PR\x844\xc6\xa1D\x08\xa6\x8fC\xf1\x11F\x1b?\x82u\xf1\xed\x84\xf7\x82w\xecq\x9d\xc6\xc4\x18\xe1AO\xd8\xb2\x99G\xe4\xc3\x9f\x04y3'\x838\x0d\xe8<\x9d\x9e\xb6\x9d\x9d\xa5@\x83\xcd_\xdazUU\x02\x06\x9d\x02J$`\xd0\x98\xa2\xb2\x06\xdf\xca\x9ao\xfbO\xfbXy\x80J\xd8\x1b\x0d\x0e\xb2,\x0d\x91|\x84Wy\x04^7v\x99\x9e\xaa\xcd\x80\x078\xe4\xe5R\xfa\x87[D\xcf\x84\xfb\xb2\xd3-\xea\x96\xd0\x8f\xd8\xe9\";=\xa2\x8f\x7fz\xf8\x98\xc1\xa63J\xf5q\xb2\xad*\xca\xd7\xe6\xa6>\xe6$\xed\xd27b\xa5\xdb\xe1#\xaf\xd2\xb3\xee\xbe\xe6\x83M\x87j*\xa4\x0c\x9d,\x81\xcc\xfb\xf1\x95~\\Z\x9bS\xd7F\xb3\xb4i\x1d\xbb\xe2P^\xe3R\xfd\xc2\xf2\xa5*c\xbc\xaeC\xa2f*\xeb\x93\x1a\xacU\xe3T\x0d\x96[\xc0\xc8\xeb2\xaa\xcb~\xf6\x06\xe3<\x89H\x8cN\xe5\x1f\xb2\x114Q\xb3\xa2\xa1\xeafZECK\x8f$e~qL~\xc3\xec\xb7\xa6\xcc\xa0\xdbF\x8d\xa8f\x9d\x9f1\x1c(\x881=\xbb\xcb\x93}\x85\xb3!\xee\xe4\x93\xa9$ \xc8\xb0\xad\x12\xd5Q\x84\x0cUT\xa5\xdeT\xb8\x8a\x9e\xa3\xcb\xa9BAy\xfe\xb3\x1f\xcb\xf4<\x9d\x04\x96\xef\xdb\x05\x10\xdf\xcb\xcf\x04\xf6\x99\xebu&\xbcJ\xcf\x0c\xc7\xc2\xed\xe9\x9f\xe2X`\x03\xb59\x19(B\xc8\xcf\x04\xe2Q|\xe8?C\xa6\x14\x1eR\xa63\xfd\xf1\xb8\xfa\xe1\xa2\x92\x91+\x1a\x87\x9d\x14\xd6\x94\x88o]#1ap\x9d\xbd\x1a}&H\xdbG\xcc?Q\x02\x13\n\xf0\xe0\xee\xfe\x9f#g \n\x9f\x98\x949\x1a\xc3\xa6O\xca\x15\x82z\x1fp\x91\xe6\xe0\xd2\xaf\xd1 \xaf$p^Bn\x8c\x13\xceR\xff\x16\xa31N\xf4\xfe\xd7\x10\xc07P|\x0d\xc1\x8d\x1b#\x88O\x82\xb7\xcd7O\x02\xf5\xc1B\xb7v\xc4O\xb2\xbe\xb2\x00ei\xa3\xc2 \xf0\xe3\x98k\x0d\xc8\x18N\xe8\xbboE\x11\x87\x18O\xe1\xc8Cs\x85\x1fG\xff\xae\xa5\x07c\x19\x07zE\x1e\xa1\xe3\xed{?\xbfG\xadBz\x865y^\x936\xef\xab\xfa\x1a\xf3$\xaai\x00\xd7X\xe2\xbe\xa3\xdfc\x7f.\xa2\x98PN\x03S-\n\xef%\xaf|\x0b)Z\x0dY E\xac\xce\x9c\xc07\xacVa\n7 \x82o\x0f\x99;n\xc2\xe2\xbbqs\xf39}\xcc\xd6JV]u\xcc4\x19=E\x17\xdd}\x1fC[u\x95\xb5\xcf\x98\x9c\xbf\x8a\x96\xab\x98\xce9\xaf[I$\xc1P\x1d ]\xc6\xff\xf5\xbb\xf7&\x0b\xfd\x92\\\xaf\xfe}\x02e\xdfV\x1f\x90\xc1vV%h\xe87\x14\xa9\x88\x0f\x15\xc3\xb4:.,0\x86\xc4\xc4\xb9\"\x9f\xeaj!&A\x1a\xaa\xca2\x8eQ/v%\xed\x89\xa1Nx\xc5yY57q\xd5^\x1dt]\x9a\x14Z\xd5M\xe71\x07r\xcc\x96i'\xcb\xf5\xc9\x01YYN\xda\xb4\xe4\xc8\xd1\xf5\xfa\x97\x15!qU\x04KG\xd0\xd5_i\xcc\x19\x96=\x80uD\xbf\xa0\xae{\xfa\x9er\x00\xc6M\xd4W\xc3\x99Tpr\xa7\xd7\xe6N\"\x1e9\xcf\xd2\xbc,Z\xc7S\x9f\xbd\x85\x06\xe7\x99\x903\xf8>N\xe7\xee y+[\x83\xf2\"\xc3\x91ST\xa7\xfc@\xc4\x8ad\xdfL\x83\x92\x94\x93\xa2\xcc\x89\xbf\xeeH\xeb\x1d\xf6'ZT\xf5v\xf7\x0e\x0f\xe1,J\xc2\xf4\xccK\xfcm\xb4\xf4\xcb4\xf7\xd6\xc5\xb1\xbf%\xb4\x0f#\xddC7\xefsV$.\x88\x82k\xa3\x87\x1e\xff\xda\x9bW\xcf8\xc61\x0e\xfe\xcd\xabgn\xae\x91\xe9C\x9e\x0c\xa4\x8b\xa6\xbeL\xef\x1dyX/W\xb8\xb6\xc1!8I\x9aP|\x8e\xbcUN(G\x9c\xd2\xdf\x05)\xbf+\xcb<\x9aoJ\xe2V\x9b\xcfa\xb2N\xa3\x1cq\xcd\x00\xd13\xb3\xfb\x1ec$\x9cq\x15\xd3;\x1a\xd7\xdd\x9d\xa7\xe1\x05\xe5\xd9H\x12>ZEq\xe8F\xc8\xa6\x05t\xeb\xba=\xc0\x9c\xac\xd3-\xa9\x01\x1b\x93\x95\x93m\xfa\xae1Y\xa9\xea\xe8}/E\xc9\xeb L\xc9\x95\xbfR1+R\x89Y\xbeJ\xcc\xda\xa8\xc4\xacB%f\xc5\xfcAOb\nx\xca\xc7\xbe\x1cUKZYU\x12B\x98>+\xe0?\x81`\x95\x8f\xc1\x97\x0bV\xd1u\x14\xacr.Xml\x05\xabt\xa8`\x95{\"x\\\x84\xe1\xfc\xc2B\x04\xad\x84\x0e\xde\xd5\\T\x88\xac\xc3\x85\xbc\xa0\xf5QT\xa8\xba'\x02\x10M\x90\xd5k\xcc\xed\xe2-\xe5\x9f{\xad\xbcg]\x14\xf1T\x8f\x18\xfb\xf0\xfa\"#\xac\xd7V\xdd\xace#\xca~\xe4i\\|\x17\x04$+\x7f@\xf5\xaf\x89\x9f30})\xe6v2\xb0\x8f\x11\xba\xedY\xa5@\xf4\x11To\xa4\xdd \x8c\xceO\xa6\xac\x08\xbad\xea4EZ9\xd1\xd3\xe5\xb4d\xde{j\x00\xe1>\xbb\x91BH\xaa\x17\xbd\x1f3\xabs\xafp4\xdd\xad\x96\x82X!\x15\xc4|;A\xacX\xa5\x9b8\xacX\"ka\xc7\xb4/\x1a>M\xdd\xc0@\xe4NH\xff\xb6(\xbf\xcf\xde\xaab\xdb8x\xfdw\x1bN\x84\xd6q\xb0\xeaO9\x14n\xc6\x0e(\xbb\xd7\x86\x97\x07\xbc\xf1\x17\x15\x0f;-\xfa\xe5J4D\x7f\xb6\x9f2D\xe1\xcf\xd9\x1f}\xdch/\xffG\x92\x06\xf5$\xc1F^d\x1e\x19\xd5z\xe9)C\xd2\xc3\x03=yH,\xbdN65\xac!\xa5,\xf3\xd3\xb0\xcc\x13\x8bl\x841\xefm\xd2\xc6-5p\xc8\xdc\\\x06\xa6\x0d]U=\xd6G\xd5l\xf9\x11Zi\xed\x8e1\x89\xdf\xa34$#7\xd5x>\xac\xb1\x98\x8f\x13\xd4d\xd3T\xd1\xc6w\x9d8\xda\x12\xb1\x86\xa6\xca6~\x1d\xbbj\n\"\x91m\xf5\xaf\xbe\x92\xdd\x16Q\xa4\xb27f\xb5\x84\xf7\xb2\xf5D\xdd\xf8)\x1cB\xd1\xac\xf6\xc7\xa6rIJv\x82>b\xe7)\x95p\xc5\xb0\xe9\xacJ\xcd6\xe229\xee\x0c\xd1+T\x1b\xcc\x98\xd9\xe0J\x9a\xb3q\x01\x10\x971O\x16w\x05x\xd5\x88_n\xcf\xb5)q]\xec\xcfI]3\xc4\xe4\x08\xd5i\x0e8b\xa3\xcc\xad\xcb\xa6\xa5\xad\x16\xc3\x89\xab&(L\xb0\x97\\1\xa2\xe065\xc4\xa6\xde\x7f\xc5\x0c\xe6\x1a\xc0\xc6:\x89t\x17\xfc\xe5 \x8eQ\xbeJ#]\xc6\xabA\xc8Q\xe3b\x94\xe8\x92\"Df\xa5\x9a~E\xb5\xd5^\xea`i\xeb|\x94\x1a^\xae\x99y@\x93\x03\xaa\x93y@CP\x18\xf7\xd8a\x11\xcc\xbcd\x8fk\xd0\x1c'\x8a0}U\xfe\xa5\xe1\xdb\xd4B\xc9(\\k\x86b\x0e{o0=i\xbb\xe8\xa8\xc1\xf2\x1d\xba\xb4+\x8dS\xb8\xe1\x88K\xed\x8eS\xa1\xf0\x84\xde\xe39wU\xcd;\xf4 \xd7&\x03\xbc\xa2~\xd8\x04\xbb9\x8f\x1b@]j\xfe\xa1;\x18G\xc9;\xcd<=\xc3\xc7un\x07\xdd\x8c\xb5<\x9bR\xa5gS\xa9b\xa5\x81\xb3\xd3I\xdf\xc3\xa9T{8\x89\x0bYg\xa5\xa7\x93\xb8\xb0|\xc9\xc9\xd4\x00\x15\x027\x18F\xed\x0c\xcepx\x08)<\xac\xf1\xfc\x94'#A'_G\xce\xb8\x80\x99y\xb9\xd0\xad$\x08a\xc5P\x96\xb8\x8e:[\xb1\x1c':6\x15\xd0\x1d\xf8\xb1\xd0\xa6mQ\xafkh`\x91h#\x13\xa1\x8du\x1aZ\x8b\x90iH\x8cC\xaaO%M8/\x0c:I\x803\x07]u\xce\x8c\xa2\xc6\xe1\xa1.m30\xbe\xa4\xabK\x9aa\xd9\x0f\xa5\xaa\xc9\xdc\x15\x0e\xae\xe5\x87\xc0\xfeT\x85\xfeI\xad\x84U\x14\x85n\x15\x83\xde!\xa1K\x8d\xe7;$u\xe9'C\xeaGX\xd6\x99\x83\x98\x85\x98U\x8a\x1a\xb9'-\xfb\xcf\xaf\x85\xa4\x16\xa7\xea\xa0\xdf\x9b\xd6\x03\xf8\x1c2\xb9\x84*w\xacP\xe5\x8e\x15\xaa\xdc\xb1B\x95;V\xa8r\xc7\n\xa5\xe6\x8b\x98?\x91Z\x10\xdcP\xd8\n\xc2\xcaV\x80\xbf\xa6\xb7z\x05\xa4\x17R\x8b\x03\xaa\x07Te\xa5\xc3\x8fo\\X\xd9\x1a\x17\x88\xc4\xb6 C<\xb3hkjo);O)\x0e\x8d}\x914\xc1'+\xf2N%$n\x90\xba<2)\xb9\x12\xe6\xeb\xd3oF\xfd\ns%\x92\xd1m\xf9\x99\x8b*\xec\xe3\xd2/uJ\xeb\xbcO\xb2\xbbK/\xae\xf7h\xd82\n\xb4\x9a\x11\xc8\xcf\x9c\\\xd1Z\xef6\xfa{Q6\x84\xf4\xe8\xa5\xb8\xa4\xc3q\xfa\xac\x1d\xfd\x94\x02\xbf\xe1\n\xdd\x94\xaeF\xb3\xca\x08-Z\xe0RK\x1d*3\x9aP\xfeB\x0d\xc3\xac%\xe6\x02d\xccbb\xe1\x9a\x13\"\xa0Y\xaf\xb8B8\x9d\x12t\x8b\x10v\x9a\xdau\x0dk\xd0\xd4.\xab\xfeYhj/\xf8\x0cVx\xa4\x06\x9dW\xa0\xf6\xf6\xb1S8\x84\x95\x17%\x0b\x92c\xaeS\x8d\"\xe1\x0c\x0ea\xc9\xc5!5\xd4\x11\x1c\x82\xcf8u&\xe2h\x93\xfa\x9d\xd7\xd0\xe4\xdc_g\xb1>\x07\xe0q\x0d\xced%\x0d\xec#8\x84\xadU'\xdeqH\xe1P\xc5\xe5Q%\xfcw\x0c~\x9d\x86$>b\xbd\xd6\x81\xbf`\xe06%\x80^2\xd0*.\xd3TL\xe75\x83\xb7Tp?\x17\x9b\x16i\x97'\xa1Q\xf4\xc8\xbaPP\xf1\x05\xb8g\xee\xc8$/>\x15+\x84\xc5\xb2x\xc7\x9c1<\x7f;\xe6\x8a\xe7\xe7~6r\x7f\x7f\xdfe3\xba\xd7\xafp\x08O\xb9\xc4\x87\x88\xe9\xf4>\xa0\x16\xf1\xeaP?4M=ma\x98#\x94\xe0\x99W`m\xa0hq1r\xbb0T\xccf@KR\x1e\xe3M\xb6AF\xee\xaf\"\xec\xd70\x9b&A2J\x82x\x13\x92W\xc4\x0f_$\xf1E\x8b\xcb\xec^\xf4\xd0\xa3\xc7\xcd\xaf\xf0\x10\xcaJy\x95\xf0;\xa7U\x9fj\xc5V\xce\x9f\xb9\x8d\xcc\x89\xcd\x151\xf5]L\xfb[\xfaI\x85\xe6\x8d9T\xd1^\x9c\xba\xbe\xe8\x01k\xda\xf7V~Q\xad\x1d\x9d\xf2\x90g\xfb\xacnQ\xb9\x14\x07\x95T\x0b\xd2\x9b\xebd\x0c\xcfu\xf3(\x99C\xcdi\xc4\x80\x7f\xc9\xa3\x92hg\xfc\xbd\xde\xfcq\x8e\xbe\xcc\x94v\x9d[\x04\x8a\x89K\xb0\xc0\x94\x1d\xa2l/+&\xf5\xd7\xbf\xe6d\xe1\x08\x97.\xda\xae\x8a\xebQ\xe0;\xddu?Y8\xf05/a\xdcF\x0bTeo\x1a\x16\xff\xd6\xbc\x9a\xb1p\x0d3\xbe&\x16\xaey\xe5\xda\xb8\xb8\xe6\x95\xf2\x1893\xa4\xe0\xd0[{<5%V\xba\xa4YK\\\xc8t\xc9\xd9IqiMKw*\xcd]\xaeQ\xf2)\xe3\xfe\x9aW\xdb\xa4\xc2h\x9by\xf68[(\x8f\x19\x17\x97,v\xbc~V+-(J_\xd6^b\x1c\xeb\xf0q\n1A3\x06A\x05\xe4\x1b\x92\xa2\xf7\xf9\x18\xde\xed\x98\xdc`\x07M>8p\x03\xdc\x0ds#\xd7l,'\xf4K\x9f\xb9\x85+\x03\xff\xafN\xdd>D\xd7\x1f]\xa1\x9a\x7f\xb0n\x7f\xe7}-[\x8bn\xab\xa7\xa7z\x93\xa1\xaa\xf1\x17\xba\x86E\xd5\x1f_\x94)l\xd8&T\xa7\xc4\x18\xce\xcc\xbb\xcdj\xacL\x9dWQ\xf3\xe6\xd0\x1b6Y\xd3\xcet\x84@2\xf1Q\"\x11\xd6\xa8\x19\xcc5[o\xe84\xbe\xb60q\x1b8\x1e\xf5\x94\xb4\xec\xd7|-\x04#E9\x9b\xee-\xef\x1da\xc7(\x88\xc4\xd5\xc7\xe4\xb7^\xd2\xb9\xe6\xd51\xb1\xcb\xf4>\x8a\xf5\x1e\xc3\\\x9b\x83q\xed\xc7\xb5\x83\x81\xc3\x9d=\n\xd0E\xa1 \xe1\xa8^ar\xa43\x1a\x83\x03l\xe9\xbc\xda\x06Uq\x9b?i:\xf1\x9d\x16\xc5+K\x89u\x9a}MV\xfc\xa6Z^S{\xb1c\xa2\xd0\xd5^D>T\x88\x02L\xb5\xfd\"\x0fIN\xc2\x91\x9bhV\x94\x1fB3\xf8I\xb1p\xd5\xd4\x1di\xa6\xee\x91n\xea\xb8h;\x83#\xeb\x99\xd3\xf7e4\xae\x04\xfc+\xb5w\x0e0r\x1e\xc3C8\xf6\xcaT\xc6\x85v\xa2W\xba\x97\xe1\xc0}i\"T\xc8\xb5i\x14<\xf4JpP\x06 :B\xad\xfe\x11,\x17\x064\xa4p\xa4\xad\x87Yo\xdf\x9fR\xe0\xaa\x92j\x95{\x1f\xbc\x94\x05i\xa5\xb7 \xd5fCF \x85u\xe8\xf7\xf7]s\x89\xcc\x9a\xd7TL6T\xffm\x9b\xd0\xea\xbf\xf8\xcdke\x13Z)sG\xacTQ%+UT\xc9J\x15U\xb2RE\x95\xacTQ%+\xa5Mh%lB+\x8c\xc8\xbf-\xb5\x04\xb1g\xbd/W\xe6\xa0\xf6\xedP\xf4]\x91no\xf5\xf1\x0dE[[C\xd1\x97(\x94\x8e\xd1\xca\x14\x85\xa2\xb7\x88d~^\x90\x90oq\x85X\x85\x91\"\x1bt\xdd\x7f\xd9\x04\x1fd\xf2\x12!)\x9c\x1bSk3\x99\xff|\xa9\x16b)\x10S\x91@\x94\x14\xa5\x9f\x04$]\x00\x0b<4\xebC\x12\x1e,\xf9$\x8aQ=\xa52\x8f\x89+\xf1R\x16\xc6g\x91\xc3\xa0y\xe56\xe6\xb5\xe6\xd5] \xca\x0cobydn\xf3R\x9cD\xd5\xe31~\xca\x0f\xbf+^\x93\xf3\xd2\xd5L,\xd7\x1bZ\xf7\xbc\xd3\xe3\x92\xf2\x07\xac\xaa\xbbN\x03!C\xafO\x1b\xa4r\x95\xd9\x02PN\x90\xec\x15\xd7\xea\x88W\x07a\xec\x942@\xb9)\x95\xbd$b\x7f^\xa2\xabWc\xd5\xb4\xb4d\xd6\xc1g\x16YB\xad\xccu\xac^\xc9&\x97$T\x12\x17\xabR\xc2\xf9|5\x98_\x9b;Xz\x8d\x87\xf0\xfb{\xd0\xba\x0fo\x06d>-\xdav\xa3\xd6nT\xbf\x85\xf5A\x06X\xd5\xe8\xc1\\\xfb\xf2\xa1\xa6\x8b\x92\xcf\xc7~I\xb0\xbe\xe8\xebhMt\"\xf4\xba\x9a\x04\x8d4$\xc9\xf5\xd5\xbc(\xc5\xa7\xcb\x92\x8aL\x0d7\xffo\xc3\x87\xe9_\xad \xf6\x9b\x91W\x92\xa2t\x93\x11\x05\xf6O\x1c>#\x93\xc7Q\x91\xa5\x05f\xe6w\xde\xd2\xe3\xe3\xa6_\x96~\xb0\xa2\x07\xb5xI\x05.\xbe%4,\xa1\xdd\xb7\xa4\xe0\xbd~5\xb4G\xec[\xf4h\x82\xd7\xb9\x9f\x14\x0b\x92\xcb\xba\xd6|\xa3\xd75\xeb\xcfI\xdf\xd0(\x8f\xe9*8\xf4\x98u Jx\x9c\xb9\xe9$\xa4[\xf9\xa2\xca\xb1Q\x92\xf3\xf2\xe6\xaa\\\xc7\x16\xban\x0c\xce\xe9\x1e\xf0\xc2\xcaV%;(\xa5\xc9\x0ed\x17K\x80pa\x84\xed\xca?\xb2\xebT\x9f\x94`n\xf1\x8938\x84\x93\x0b\xca\xd0\x15\x9byQ\xe6n\xea\xc5~Q>MBr\xfeb\xe1:7\x9d\x11\xdc\x80\xe9h\x0c\xa7o\xbd_\xd3(q\x9d\x99n\x9b\x8a\x0b\xed\xfc*D\xd5l\x08=\x13\xd4\xc9\xfdpdZv\xe0K\x7f^\x99{\xc8y\x99\xfbA\xf9\x84\xe7oz\x92\xa7k\xde\x8fF7\x98W\xc4\xc8=2\x18\x84\xe8\x85!<\xb43\xcc\xeaG\xe7\xf3\xdc\xc0 i\x9fR\x1aTy]\xd6\x99+\xe8\xc7%\xb7yB\x8b\x17\xf9\x8b\x8c$\x1c3/eIq|\xa3\xc6\x16\xaa\xfa\xec\x06\x07\\\xd8\xa9\x06\x8a\xb88We3hw>\x863\xfd\xa4\x83q\xe2\x9bYf`\x11 #\xff\xb5\x9aM\x91\xcbc\x06g\x83\xc7\xa2|\x81\xb3\xdb\x14\xf1\x94\xe3`)u\xb8\xce\xa8\xfa2\xe7< $%\x96\xd6\x86\xf9\xa6\x84\x8bt\x93\xc3\xd7r/\xda\x99f\x96k\xda\xe7\x06'\x84\xa2\x81\xdbN~\xc8x\xd7\x9b\x14\xe8_7\xb3\xd8\x8f\x92\x9b\x8d\xd9\xff\xc8\x036\xf0k\xc2\x88\xa7\x181\xcc\xe0\xe6\xff\x8d\xd6\xfe\x92\xfc\xebf\x0b\x87\x12\x8f\xbb\xfd\x14\xaeSl\x97\x8e\xd6\xb0\xd1\xa4\xf9\x0e8\xa8Fv\xc0\xd1+\xdb\xd7K\xed!\x80\xf9\x9ed\x9a\xcb\xe6\xb5\xf6\xcf\x7f\x89\xc2r5\x03g\xba\xbf\xff\xff\x93c\" \xe5W7\x94\x073\x1d\xbb\xa8\xd0\xc8\xf0\xb9\xf37a\x94v\xe6\xce\xea\xb8P\x9f\x8d\xf4\x8bzC\x117G\xaa\x1d\xb1tA\xd1h\x1c\xd7O=\x9d\x11]\xado\x96\xacL\xb5\x89\xe8\xc48\xcc\x7f\x88n\x1f\x04O\x17P~\xfc\xbdQ\x9e\xcbtE\xe22o\x0d\xee\xe4\xf5-\xec\xc3C(lw\x80z\xf9\xad\xcd\x7f\x91:\x9c\xf1M\x92\x93 ]&\xd1\xbfIX\x99\x89p\x8e\xbf\x16\x81A\x94\x89\x10A\xee~\x81\xd4\xdd\xd3E\x8a~\xca\xd9/4\xa4\xf8\xd3M\xe4\x06K\x91@\x99\x8a)\xad\x8d\xf7Z\xb7\xa5\xe5\xa5q\xa4\xe1\xc5Vg,\xc0\xb0Tz\x9e*]\xab\xacm\x916UH\x98Yu'\xcb`\x95\xef\xd0}p\xf7\x8e\xc4\x88\xa7\xd7}\xd6\xbe\x9eY\x1c\x95\xeeM\xf7\x9b\x7f\xdd|x\xf2\x7f\xbf}{\xe3\xdb\xd1\xcd\xe5\xc8[DqIr\x0b\x0fK\xfe!\xc7\xa9\xb2\x0dEkY\"\xdc\x8e\xfa\xba\xdd\xdf\xc8\xb6\xbf7\xbf\xf9\xd7\xcd\x1b\xac\x9b\x9c\x11 \xda\x0f\xfb\xf6\x1f\xc6\xaf\xfe\xeb\xa6\xddw7\xb6\xdf\xb5\x9e@\xec\xc0\x9er\\\x80\xc8E0\xef\xf0^$~\xf8\xbdn\xd6\xf8!\xcf\x9d\xd9\xed\x850JuM|\xf0-Li\x13\x0d]Gm\xcb\x9b\xbe\x85\x87\xed?g\xf0\xbb\xe4\xdcg\xb1[\x82\x83\xed?G\xbd\xad'a\x89\xfb\xa01\x1c\xca\xf4\xa6\x01\x1c\xc2IGeSg\xb2\xa5\x7fu\xe2\xac\xe9x\x17c4\x07\xbb\x0b8\x042\x86\xd4]\xd8\xb8\x13\xf3uR)\xeau!]\xec\x14wK\xd6^\xe4\x96\x94uq\x1e\xc5i\x11%\xcb\xd7\xfe\xd2\x81\x19l\xf8\xdd\x17\x19I\xea\xbb>\xbf{L\xe2E\x1b\xdeyM\xe4\xb9\xbe\xe5\x01\x81\xed\xa3\xf7\xfdH\xe2\xba2\x86TeR\x8eLI\xeaX\xfdq\xa4\xe8\xbd\xe7\xad\x81R\x1e\xdf\xa7\x88\x15O&\xf2\x9e\xd2\xad\x95\xbb\xc9\x18b\x85\x92\x0fK\x89\xc3\x0d\x88\xfa\xef\xa3b\xb69\x83us7n\x8c\xa1\xd0\xd9Y(J\xa4'%L@\xe7\xbe\x1dVP\x07\nM\xa1|\xb8l\xb9\xf0\xef\x0c\xe7 ov\xbb\x1aV\x8f\x109\x1d\xac\x9c\x057 ds\x0f7 \xab~ET\xe8\xc4\x80\x05\xec\xcd\x18\xb0\xeb\xc6\xf0kh\xd0\xa6\x0eN\xb4\xc7\xc3\x81\x02o\x91\xe6G~\xb0\xb2\xdb\x1e\xd9 yK\xf7_\xf7\xe4\xa42jfw\xaa\xf0/\xed\xedu\xfc%F\\\xfb\xfb\xaf\xa6o\xe9%\x12\xb6\xde\xfc\xfb^\xdd\xc0\xdf!'\x19\xf1\xd1vB\x99\xbaoVe\x99\x15\xb3\x9b7\x97Q\xb9\xda\xcc\xbd ]\xdf\xfc5M\x8a`\x15G\xc9;\x92\x977[\xf0\xdf6\xbe\xd4\xfc\xe8\xa34\xbb\xc8\xa3\xe5\xaa\x047\x18\xc1\xc1\xfe\xf4\xf6\xe4`\x7fzg\x0c?\xa6 \x1cW\x1f\xf3\x9a\xef<\x8b\x02\x92\x14$\x84M\x12\x92\x1c\xca\x15\x81\xe7O_\x8b\xdbM\xd0\x9b\xd5od\x06X\xd4c3\xb3\x842\x7frw\xdeq\xe3\x08Ab\xaf\x12$\xc8\x08\xcaU\x9e\x9e\xa1\x9d\xe1\xf5EF\x8e\xf2<\xcd]\x87\x9cgL\xdd\xe6\x03\x7fI\x92\"y\x8a(]\x8e*^\xa3\x0fr\xd0\x05\x81\x1b]0\xe1\xa9@\xc4\xc1\xf4w(\xfb\x1f\xca\x19\xf7A\xa9~\xc3\xce\x98\x8fX\x16\xf4\xfe\xc4@S\x9d\x97Vg\xde!\xc5\x1b\xde\x97\xca\x1e\xb1O\xb1\xa9\xfd*z\xc7|\x8d\xa5\x00\xaa\x97\xd1\x0d\xe3[\x98~=\xa2''\x0b]qS\xb8q\x88F\xf8\x12\xbe\xfd\xf6\x10\xa6c:\xc4\xc3\xee\x18E\x8b\xf4P\xe2o\xb4\x1a\x1f\x86\xed5cxw:2\xe1\x82\xc2\xbb)w\xc9\xc8+\xd3g\xe9\x99\xa8D;\xac\x0f\x1f\xdd\x99\xed3,\xfe\xba\xa82\x1b\xd0_\xf7F\x7f\x8e\x82\xaf\xdb/\x05f\xd4\x05f\x84\x17\xfd\x80h8\x81\xe0\xb9\xaa\x8a\xf6\xa8\xe2\xa8\x8e\xceKM1\xef\xb4[\xb2;U\x97\xecN?\xbeZ\x88 t\x9d\xb1\x98-\x8b\xe6z\xddReh>t\xb7Jy\xa7\xd3Sr^\x92\xa4\xe8\x1d\xf6\xef\x99\xe7\xd4\x0c\x9c1\xf0\xa3)1\xd7\xda\x8e\xae\x1bB=e\x9ecG\xeb\xac\xbc0\x94\x89\xef\xc5\xd4\x8a*\xf1\x98S\xb5~'\x12\xfa\xc9\x88\xeb'\xafU\xc5x\xd5\xc8m\xf0\x10\xb1B\x85\x88Q\xc1\xbf(9\xea\x98\xf9S}\x02\xfb\xfc\x0b\x8f\xa3\x02)\x9d\x14\xa1\xf9\xb9\x8f4\x0f{\x8d\xda-\xf4\xf6\xbb\x0c\xaew\xf4\xa9-\xd4\xa7\xad\x9c\"\x0e\x9d\x96\xe9r\xa9\x11>B\xdesY\xfa\xe7\x9e\xeb\x86\xba\xbfQ\x92mJi#\xcc\x04\xee\x04+\x12\xbc\x9b\xa7\xe7\x12MY\xa3\x0b\xfd\x87\xf8\x1e\x1e!\xa8t\x90(tj^\xc9\xac\x9c\x8c\\Q\xc1\xda\xe3\x1f6\x1e\xb7\xa318\xc7$ \x01'\x95mL\xa7\xe7#\xf4Y\x95\xe8\xff\xa49\xa1\xe5&\x93Pj2Q\x94\x93T\xa4\x88\xbeu\xd0\xcb\x0b\xf0%\x17\xb4\xdc\xb0ag\xd4\xb0\xcd\x05-v\xe0.f\x82\xa1\xeeG_}\xd5\xfa[-F$&\x1bD\xc3\x02\x90TC\x18\xb9\x89'$\xc618\xcc9\x03\xad\xcb\x88\x13\xcc\xbaLD^\xc2\x84\xd5PB\x91\xbfOG\x9a\x96\x14\xebCK\\\xdbai\xb2\xad\x94\xc8y\xad\xc2W\x03\xa5\xd6\x9af\x1fS\x1aX\xc9\xb4\x9b\x1a\x94\x8a\xc4\xda\x05IxT6\xce\x15.\x04N\x1e\xe5\xe4\xdct\x0c\xfe\x186*S\x10\xe6\xf3\xe6\xd5*X\xcdA\x8b\x8c\x05\xc2\x00c\x9ci\xc6KX\xea\xf6\x13\x10u M\xd3\xc8\xca\xb5WHg\\\x18\xb5r\"\x19C\xae\x98\xdbF\xf4\"\x96\xf0`k!\x0e\xb3\xaf\xbe\x02\x07\xb5Y\xb8\xdf\xd2z\xa1t\xfa$\xc1\x9a\xe9\xa2\x96\x01\xcf\xc3\xa88>\xf3\x97K\x92\x1f\xa0N\xd6\x87\xaa\x8d\xf3I\x9d\xf9\xf6\x8f?\xd8]L\xcf\xcbi\x11\x8f\xed\xad\xefW w\xabT\x8aj\x88\xc67f\xd8\x0b\x9e=\xea\xab\xaf\xc0m\xf4A\xd1\x83\xddZ\xaa+`\xef \x07\xb0\x1e}tY8h\xb2Y\xcfI\xfe\x9a\xeb\xc7F\xae\xaf\x88\x93\xeb{q\xc90\xdd\x1d}\x9c|\xedU\x12\x86_\xa28~E\x02\x12m\x91;\x91\xd5\xdc\xb7\xce\xc5Ps\xea\x9fxw\x99R\x88G\x97\xda\x83Hd\xa2\x02 \x1b\xee\x84\x1cf*3\x9a\xcd\xeeJ\xab\xed\xe4F\xad|\xd4#q\xa8\x07,%\xf5h\xc4Q=\xd9\xac\x91w\xf5\x81\xe5b\x88:\xf7u\xad \x17\xcd\xc6{53lJoP\x18\x86\xd2\xd84\x1b\x8c\x03\xa1\xff\x9d\x893#'\xbfm\xa2\x9c\x84\x8cT\xe1\xae\xf2\xd9\x19L\xf72\xba\x89x\x8b(/J\xb7\xb3\x01\xb1\x90e\xc1?+jZ\xdam\xc7bTe\xd1\xee\xee\xb4\xfe\x86lo<\x99\x18\xf4\x01\xbc\x05\xec\xce+\xc3q\x9fX\xee\x8f|@V\x8e\xb4\x865\x98\xcb#.?sm\xaf\x9e\xd7 Z{\xfe\xa6%\xaa\x0b\x95\xb7\x1e#\xad\xe9M`Mo\xc2\xea\xb3\xe6\n\x0f\x85\x91\xde`\x95\x07cj\x11\xafX\xa5gGB\xdde(\xef\xc0\xa0\x1f\xa5\xebu\x9a\xd8\xbcs\x81^\xd9\xce\x8fE\x9a\xb0\xcc\xe7O\xd2|m*)\x9b\xbb\xcc\x98\xfc=\x0b\xaaQ\xc2\x9e\n\xc7\n\xc6n\xa8\x01\xcf\xe0\xb0\xc9\xa2\x9c\x9a\x0b\x98\xceM\xf6\xac\xb6\xc1\xc9`\x15Y$Zk6\xd4\xf6#\x83\x95)\xa8\xec3\x85W\x15S\x10\xd8\xea\x06\x06\xbbP\xd0\xf4\x8f\xa2\x9fh\xa4\xf3\xc1{\xf4\x135\xcd$E\xd9\xc8\\hot\x92\x91I\xbbwk\xf3\x93\xa1\xf4X\xc3\xc2\xa3\xc9\x05\x04\x83\x8b\xb65\x8dL\x81\x12R\x97\xe1\xe4\x88\xe1\xafm\x0d\x8ds\x06nSC\xe3\xb8\xb13\xb8\"\xddT&\xa4 \xde\x94!MEC\n-\x93\x12P\x89^\xfd\x81\xef\xea]\xb9H\xf3\xb5\xaf\xed\xe5\x0b8\x04\xf4\x81^!7Rv\x18\x11\xed\x86x \x87\xf0\x82\xbdP\x1a\x10\xf45%\x00\xb47\x8f\xfd\xd2wL5\xf8\x9eS\xe8'\x15t\x94\xd4\xa1\xe5\xea\x97\x9e\xd6\xc3\xae\x19\x0e5\xf8\xaf\xa2\xf3(\x0cD%Y\x17T\x16\xc0\x81t\xab\xc95\xaf\x9f\xe0\x10\xde\xc1Cx\xd7\xe5\xa1\x1cM$\xe7+8\xc4\xc0GW\xd4\xa2\xe8\x12\xf0\x91[Vy{\x95_y\x0c\x87\xb0n~e\xe0\xfb\xcf,\x12Y\xbd\xb1\x80\xf9\xcd\x02\xe6 \x1c\xc2\xdeT\xab)h0z\xcc\xe9\xfeY\x8dOl=:\xec\xe03:v\xda\xc1gM\xbew\x8c\xfd\xe1\xb7\x84(\x87\x86\xe37\xf5\xf7\x04h\xe3koh\x9bo\xea\xf0e\xda\x03\xec\xf5~\x1b\x8e\xf5\xed\xb7\xfa[U\x1b\xe3f\xccB\xd9\x15G\xb1\x02FWL\xd6z\xa4\xe8\xf3\xf6\xb3\xdc\xfbH\x17&\xa8\xb0\x99\xd9\xba$4\xdf\x8c\x12\xa7\xe5\xde }\xe9\ns\xf8\x0fq&\xba\nC\xffSx\xd82#\xd2\x06\xa1\xa2\x070\xeb=T\xf6\xa6=\xb9\xf8au\xc6\x00VF]\xddC\xabT\x0dA\x1ac\xbe\x10\xdaS\xf5\xd9\xa7\xea\xaf\xf3?\xff\xef\xefN\xc3\x8f\xee*f\xb39Y\x9a:\xe9cx9\x86_Q\x0fu\xe2\xc0\x0d\xf8\x15n\x80\xf3\xd6\x19\xc3w\x18\xc2\xb7\xf3\xac\xb5z\x92\xa7\xd9\x84\x9fg\xca)p\xffJ\x1b\x1d\x833\xd2o\xb5\x1d\xa7 $YN\x02\xbfT\xad\xcf\xfbq}\x96\xd6\xdb\xbf\xf1\x16\xc6\x846\xfe\xfep\xab\x15i\x9c\xe4\\g\xdcb\xdbq\xba\xc6\xb0\xa4}~%\x94\xe3\xaf\xae4G\xfa\xb1\x89\x9dgnW\x14o&\x14\x83\x0c\xeeR\xe7\xff\xb0H\xa9~\xfe\xb3\x1f\xeb\xcb\xb0\xc8g\xa8N\xa0\xbf\xa63\xf2X\xcc\xc8\xe3\xff\xf8\x19\xb9\xc2\x1a+;8wV\xdb\xa9\xe1\xe2\xa9!\xca\xe7Zz\xcc\xeb\x9f\xc8\xbei\xc2\x8a\xbd3\xd4\x0b\xc3\x1f\x7f\xc0\xde\x13\xb3$\xab\xed\x87\xca\xf9\x85\xb2+\xea\xb5\x14\xbdw\xbe\x89\xbe\xfdn\xebG1\xa6\xe2@V\xb4\xf8\xe6f\xf4-=\xe6\xe0\x06\xbc\xb1\x88\x8eo^\xc2|\xaa\xc1\x8f\xda7\x8f\x07\xf5\x8eU\xc9\xcd\xde\x8fZ3\xd5\xe0\x94~\xfb0s&\xd82\xbbi\xe3*A6i\x8d9\xfbM9\x98\xd7t,{\xcf\xb5'Z+\xcb\x13\xc6\xdc\xce\x0cY\xed*)\x07\xcb\xebP\x94\x8a\xcc\xd3\xa3\xad$o\xd0uX\xebM\xb8N\xf3'5\x84`\xabf\xf0T\x0d\xd4\xd8Z\xf2\xedVK\x9d\x8c\xd5\xa2\x14\x0f&\xd0p\xb9m\x83\xcfXx\xbd%\xef\xbb\xabV\x84\xd0\xc5+fB\xccc\x7f\xea\x1a\x12\xf5\\^(\x11\x087\xc3\x0b\x0d\xc5:\xd2-\xab\xf5\xba\xd5\x0e\x96\xdd\xba\x88\x06\xa4\xe0\x0e\xd9\x9a\xacVvZ\x1f{\x8d\x8f\x98\xb3\x8e\xd6A\xb3*\xa2\xf6\x8d<\x89\xa5\x84H\xefX\x01G\x816M\x1d\x8en\x9a\x84K\xda\xac\xa9\xc9\xa9\xec\xe0\xc7\xa4,\xa3d\xf9$\xcd\xdd\xa0'g4\x183\xcdD\xd4>k3\xf8\x89\xb96PY\xf5'\xe4U\xd4\xaf %\xa7~\xf6\xae\xca\x89\xf9\xfa\x97R T\xaeT\x81\xca\x95*P\xb9R\x05*W\xaa`\x98+U\xe0\x16\x8d\x8e\x06jO\xe2\xe0\xe3\xfb?-l\xfd\x9f\xbe\x04\x98\x0b@\xfb\x00\xf38\n\xde}j\x87\x17k?$R[?4goevS\xc30\xcb\xe0\x1aU\xferma\xe2m\xfd8\xe2\x85\x1e\xfcu\xe1\x9e\xa4c\xf0\x91\x02UO\xbe'\x8b4'\xfcp\x12\x00\xa8\xb7\xe3\xb3\xe4\xa5 \x7f\xca|::7\xdd\xd1\x18\x12\x8f\xf0?4\xc7\x82\x18\xb4\xf6\x04\xce\xf0\xf4\xd5\x9c\xa3kn\xe1\xe8\xfb\xec\x02\x12*\x837\xda\xcb<\x0d7\xc1\xb0\xb8\xfe\xca\xdb\x8f\x8d\\\x92r\x80\x7f\x94\x19\xc9O\x04 \xae^\xf5\x1a\xeb\xf8\xdb?i,\xbf)\xf6y\xce\xa2\xabme\x93y\x99\x00G)\x10\xe1G\xfc\xd8f\xa9\xa6\xae\xdb\xb1\x8d\x19X\xee\xab\xb2\xc6H+\xa0I\xd3\xc9\xf8\xaat2\x1bU:\x99B\x95N&\xe6\x0f\xe4\x15\xd0Z\xb9c\xaeY\xc6\x98\xfeG\x84\x1e\xfa/\x0f\x1e<\x90 \xe9\"M\xcac\xa6\xcfv\xa2\xd2\x8f\xa3\xa0\x1b\xa2\xd3\xfa34\xd2'\x03\xe3\x00m\x1a!)\x83\xd6\xab\xbb\xa4\xf6\x93\xee\x94\x1fc\xc72\x03\xaf\x18\x02#\xff\xdb\xe9\xd1\x8e\xa5\x9b\xc0L\xb9`\x00\xf5\x82\x81\xfeEP\xb1\x08\xc62@\xc0\x19\x04:\xac\xb6\x17\xd1\xc8u\xc4\xd6V\xf9\x05C#\x94\x06\x9ae\xe1wVyC\x87\xd0\xf2\xfe\xeb\xe39\x01\xf46&C>\x06\x90\xb7yz\xaaI\xca\x00\x9c>\xff\xc0\xcb\xa9\xea\xe3\xe4\x8dI\x06@\xde\x85\xdd\x86;$\xd3\xc0\xd0.M\xf2\xf4l\xd7^\xed\xd2\\\x90\xc6\xfa\x05\xb8l\x92\x02\xd8\xb1\xddV6\x82\x8f\xdf<\xf3\x1a\x1a\x90\x05\xa1\xf4HR\xe6\x17\xb2\x12\xb9&\xdd\xb1\xf0\x01\xee\xc8?d\x0c\x07\x06\xbf%\x10\xee\xbb'\xfb\x9ax\x10q\xa1\x0b\xef\xc9\xd4\xa2\xda\xcf\x9e$\x1f\x83\x1b\x8d\xaa<\x81\xeaL\xd5\xe2\x12N\xbc\x91\xd7\xf1\x19\x7f;\x12N\xb4\x1dOr\xee=\x02\xb3\xc6S\xa3G\x89\xb86\xb2\xa6Z\x0e\xec\xfa\xee\x9a\xd8W\x8b\xbd\x0c\xe2HJ\xb5`\x97\xf0\x0f\x10\xd7P|\x06\xd6lz \x13\x94\xb8vl:\x92(\xa3?]o|^Fb\xa39H\x13\x9b\xf6)\x97\x80\xb6CGx\xcb\x991\x95\xbe\x83\xa6D\x83\x97\xa0\x80\xe5\xdcb\xa6\x1f\x94F\xfdX\xc3t\x93CHS\xbd\x83\x94c\xeb\x88?x\xcbP\x82\xba)\n\x85x\xf7\xba\x89B\x9fT\x83\x19\xc8\x04\x1e* \xb9\x81\x10xP\xdc\xf93\xa8/\x1b\xfc\xbeDK\xd9g\xf9m#5m$\x90k\xaa/\x19\"m0I\x83\x84Q\x99\xe6F\x0d#SF\x92<\xb7P\\2md\xec_\xa4\x9b\xd2\x02\xbf\xb3p\xb9#\xcc \x884\xdcH\x18\xe55\xf8\xf3\xd5\x07\x84\xcaL\x04\x82gv\x8a\x8c\x04\xe6\xe1\x84W9\x9c+\xeb<\xf3\x0b\x93#\xc8h\xa7tj\xb6\xfc\xfc\xa2\xcdL\xeb\x93\xa7C+\xcc\x19gA>\x05\x0c?u\xc7;\x9e\x95\xa5\xe1h\x14\xec}\xd9<\xa2\x94V\xea\x9d\xf6jo\x9f\xaa\x8f\x9f\xf7c,Mgh\x86\xe9\x90\xf4\xa7\x87\xd031\x7f\x1fVg\xaf\xe9+\xcd\x99\x0fx\x08+\xb7\x03\xc5\x1c\xc3\x1a\xae_\x02\x16Co\xc4\xcd\xcc/W\xf8\xbe\xb2\x1f\xc5\xda\x8f\xe3F-F\xbf\x84\xee\xeb\x0d\x7fW\xf5gt\xce\xebFw\xff\xb3UT\x92\xe3\xcc\x0f\x98k;\x99\xe0\n\xabw\x95U\x15Gi\xaa\x01>\xb05)\n\x7fI\xb4\x07\x8b\x16]\x8cC\xc2\x8a\xa0\x93\x90\x04)3\x91;3p\xb0\x12\x8aah\xc1&/\xd0\xdc\x94\xa5QR*\xb9\x1f\xd9\xd8\xb0\xb6\xb5\x8e\xe6i\xaa(W\x07\x7f\xe2\xcd\xa3$t\x19:\xe4R\xbb\xb6\xf3\xe3f\x9dA\x99\x02\x1d\n\xc5\x96\xbc\xd6U\x88\x1fm\xb24\xd4\x04\xb6\x13m\x91C\xe5\xbc\x8c\x8f\x92ZtwJ\x8e%h\x9fEE\xe9E\x05\xfd\x8f\xdb\xd9\x0c\xf6\x9bI\xb2\x97\xb8\x9f\xb0\xc7v\xd5%>\xc4\xd2\x804\xc8!\xfa\xe3&\xe8\xe5\x91c\xcc\xa4\xdd\xa7\xd3\xa4Z\xc6\xd6\xe7v\xde\x19\x9f\x90\x90Z\x13I\x0c\x0fB\xc4\xfd\xc8$\xcd~3\xff\x99 \xd5\x95\xd2\xa86\xd6Z\xd1\xab\xf6+\x06\xda%\xd3\xd6\xad\x94\xda:\x17\xd3k9\xce\x88W\xa4t\xc0\xb1\xb1\x1d \x11\xfcd\xff\xadW\xa6o\xe8va\xf5\x8a\xe0\x06\x10\xaf\x88\xa3\x80\xb8\xd3N\xc7\x04-\x81^\x1d10\xa7\xccm\xf2\xa4-\xa51\xfb\xc2\x17\xbd.\xbf,\xf5\xbaA\x95\xbb\xefO\xa3\xe1\xfd\xe2\xa0jQ\x01\xe9\x12>\x87\xe2\x13u\x12O\xdc\n\xd7\xd0\x93\xb0\xca\x92\xf58\n\x9f\xa7\x9bD\x16Td\xab$\xaf\x95\xe3\xcdl\x1fE\x95\xce\xa837\n\xf0*?R\x7f\xb2\xda\xf3!;J>`\xea/\xd2\x1bT\xfbN\x9d\xe6\xa9s\xbf*\x9d\xcf+)0\x9dH\x13G\xa4\xc3\xbf\xc4\xf8?\x81\xb9\xa39\x04\x93\xb5\xa3\xe2\"M\xa6\x0e\xec\xaeV%\xddv\xb3\xda\x89\x89\x82^\xc8&\x8edR^dD\xb0\xb7\xc8f\xba ?\xfe\xa5\x9f\xd1\xe9\x11\x0b4\xd6\xec\xd4\x03s\xcd\xf4\x9c\xf5J\xab\xf7\xd5\xc4\x85\xa9\x06SZp6\xe22\xe9fR\xe6C`\xa5\x953\xe8\xdb\xf8\xa05\x81\x9bR\x8fm\x80\xaeE}\xc7\xda\xe9z\xa5\xdbB\xcf\x98I\x12@\x8fzU\xa9\xf9\x08\x93^~\x93\xe6\x16cI\xb5co\x91\xa7\xeb\x1f\x8fG\xee\x89C\x0f\xb5(@.\xff\xe6\xafE\x9a8o\x1b\x9c\xe3\xf8\xday:\xd3\x1e\xbd\x10!\x06\xcf\xa2\xe4\x9d&5\xfcug\x10\x13\xf7\xb6* \xfdg\xc9\x18^\x05?\x98H\xf9\xc1\xa8\xe2\x07\x93\x11\xe3|\xf6\xbf\x86\x0d|\x03\xc9\xd7\xb0\xa1\xfc`t\xb2i\xf3\x83\x1b ?(\xf8\xcd\x0f\xc5\x08F#M\x12i\xcc\xb2\xf8\xda_\xa2\x05\x17u1\xa7\x8d\x1bLx\xa5\xccn\xa1X,\xb8B\xe6\xad\xd9\xb2\xc5i\xaf3:5\x98\xb1\x96\xc7\x003\xfd)\xf2F\xb7\x87\xa8\xe6G\xe87^d\xd7\xb9\x87\x9f\x80c\x1a\x14\xadf\xed\xf4\x91\x0fq\xfaH\x07\xa4\xcad eK\x7f\xb9$aE\xb8\x0b]\xc6G\xcc\\lv 11\x0f\xf6\x8aB;\xee*\xdd\x92|\x1b\x913S\x8d\xc1\x17\x1c\xceA\xa1p\xb0\xf56\xad\xad\xb7U(\x9d6\xaa\x1e\xf8$\x9f4z\xe8/\x0bg\x0c\xa5\xc1Y\x98y\xcf\x08\xa7\x92\x08\x1dI\x8c\xb6\xe2\x9dye\xa86M\xd5OT\xc2*_\xb8\x84\x9f\x05\xec\xe4\xb6\x00\xf5(sF\x1d\xe8\x9cl\xd4\xee\n\x00=;F\xf7jbPL\xd9\x95\xe6\"\xe9}\xd3\x85\xef\xaa3A\xa7\x87\x1b\x0e\xf3\xa2S\xcd\x89o\x9a\x90\xda\xef\xc1\xe0\x93j\xf4}\x00\xd6\xc3t\x00\xab\x0f-\x0bN\x992\x86PG\x06\xc4U\xa7\xeb7\xc32b\xb36d\xb0\x15\x17\xf33\x8b, \xe9N1$G\x05\xce\xde%\x0d/\xad\xc6\x06\x1e\xc3\xc6\xd29}g_\x0b\x10\x1b\xcc\xa2\xa7\xc6\xf8[q\x898\\C\nSzE\xe1\x0c\xd2*\x19\x93\xc5\x0bt\x8b%Z/\x9c&\xe4\x8b\xec\xa9\x19u\x9b\xc0/s\xb2\x88\xce\xb1\xb0]\xbd\x0c\xc6\xb7W9Y\xcc\xc0\xf9K\xf5\x12\x8e\xc6\xa2\xd9\x8a\xde0\xda\xa1'\x1a\xb6\xfe\xdbR\xb0&\x08&\xca\x8f\xfeM\xe0\x1bVUDM1o5\x0c\xfa?\xa5u\x9cv\x01L*\x0b!J01\xc9\x1eHm&\xad;\x03\xe5[\x83SI_\xa4\xb3\x12D\xa4\x04\xc7Z\xe4\x10\xd2\xc6\xae^\xc9\xcd\xfa1\x1a\xbe?i$.H\xbcS\xfe\x077VQ!\xb0=\xaf\xff%\xf9\xc4\xe5\xf9}\xde\xea\xc7\xe5S\xf964\xb1\xa8\xed\xed*'\x91\xcc\xc3\x98\x8fb\xe4\x9e$\xc8\xdc\xc0\x1e{[V\xe4\xbf=\xab\xd7\x8a\x81\xd7\x1d8I#\xd7\x83\x89Y\xc7\xa1\x9b\x98tJ\xcev\xe2\x9fc\x8fnE\xdd\x99\xc3(\xa5\xe6\x0c1\x9a\x99\x81\x87J\xffB\xa2\xe5\xaa\x9cAN\xb9\x9dy\x1a\xb3,\xa4I\x9a\xaf}m\xfc\x9ez\xec\xb2\xe4\x00j\xf0\x96wl\x9c\x06\xef\xaad\x04\x94e\x1b\xee\x05l%z\x08\x9f\x0b;\xe9\x83\xce\xca$\xf6\xe7$\xc6\xf3HQ#|\x0cI\xdbT\xbc\xb3/\x03(\xdbW'\x1f\xb4\xb0=\xd8\x1c\x1b\xff\x05\xd7B\xcb\xf84Y\xa4o\xf2\x18\x8f'\xfa\xfb{\xbf /\xfdr\xa5Q8JS+\xa4\xaa\xd4\n\x91*\xb5\x82\xafJ\xad\xb0Q\xa5V(T\xa9\x15\xe2Vj\x05\xb4C\xb7\x01\xea\xdc\x0b\xdcR=\xdd\xbf\x16\xa9\x17zsn\xc5\x11h\xdc(\xbeD%5\xe1\x86\x9eY\xab\xb4\xd0\xe8x\xd8\xa95\xe7\x8b\xb5\xd3q3(\x16\x84\xb64\xd9\xe4jR\xe4\x9c\x00E\x1dx\xf3\xea\x19\x96\xc1-\xd1g\xc1\x81\xb7\xbb$\x80\xd11\xb6vn\xd1\x06\x0c\x85O\x8c\xa5\xd0\x9b\x05\xb8\x12l\x053\xc6\xc2\x00\xac\x85\x81\x98\x0b\x15\xf6\x86~i\x90\x89\x93\x01\x1aM\x00h:\x9e\xf3\x94\x9c\x7f\xfc\x01N\xb9\"\x10\x92-\x89\xe9\xc9c\x905\xd3\xfa\x0b\x14\x93-\x14|\x1c\x9a\xac\xfd\xc8\x08\xefc\xf2<\x87\xb2p\x16\xf1\x1fV\x8cL\xaa\x15/mX\x1e\xa3\x86\x8aq\x94.\x96\xf5*\xfc$*\xa3\x7f\x937y\x99%r\x90\xfb\xbb\x9d8\xc5\x14\x9e\x945\xd4\xb1\xf3L\xb5\xb9\xc9c\x1d\x10\xb3\xd3\x08\xee\xc4\xe4\xe5^\xa2\x0c\xa9\x83bR[S\xca\xd3A\xc7\xcc\xea\x83L\xee\x15x\xcdc\xee\x98\xbc\xcaV\xa8\xa6\xe1\xb1\x8e\x86\xd3\xdeh\xf99\xe4\x984\x829c\x085\x06\xbc\x9a\x19\xd4\x9cZ\xcd9\xd4\xba\x91\xb6\xcfA\x85\xa3\x8d\xfa\xa4\xb8\x949\xb9y8\xb0\xda\xfe\xd7\xedp(T\x87C\xa1:\x1c\n\xd5\xe1P\xa8\x0e\x87\x82\x1d\x0e2\x92_||\x92\xaf\xd7\xa0\x7f!\xf9\xe2\xb2%\xf9\xc2/v\x97 Z\xc6\x1cXo\xa1\xf8Zn\xa1\xeb\xc1_\xf5\xf7\xd6\x17v\xea\xcf\xb2\xb7v\xd6/4u\x0b\x8b4Ugp\xfa\x8f;\xf7\xae\xc7\xa6\x157\xffDB\xd1\x97\x94B\xda\x94BO0\x9f9K\xff`4\xe5\x03\x9fO\x1ed\xd7\xc8 $\x17\x06\"i\\\xf4&\x0b\xfd\x92\xb0\x86e\xc6\xdbO\x9e{\xe8\xd2d\xf2\x03K\x9d\x83\x82\xae\xa5\x96\xfdG\xa9\xd6\x90B\xe9\x8e\x13\xa7~\x18%K\x96\xd5\xb8\xf4\xf8\x9f\xc7\xa5_n\xb4B\"\xc5[g\xe1G1 \x07\xbf\x8bn\x85^\xb0\xc9s\x92\x94\x1cC\x0c\xd2\xeb\xef\xef\xb5\x82(\xba\xde\xb9\x1b\x0f\x0b\xea\xd1\x9e\xe5$tF\xdc\xdb\xb0y\xff/\xbe\xefk\xb3\xa07%W\xfa/\x8e\x0dmw{S\xfe\xbb\xaa\x1a\x7f5\x07$\x8e\x1f\xebU\xfaQ\xb2CN\xfa|XK rf\xaa'|\x9d\xce\xa3\x98\xcc`z0\xb4/N\x94d\x1b\xfbTCut$\x9f\x05\xfe\xba\xf2\xe5,\xf6\x03\xb2J\xe3\x90\xe43p\x18\xea\xc0\xfc\x02J\x7f\xa9y\xab\xbc\xc8\xd0\xbeE\xceu\xdf\xee%*j\x12M\xf5k\xd5\xc1_c\x8aS\xe6\x1b\xe2T\xd8\xe28\xa0U<\x84U\x81qs\x14\x94\xdcn\xf6\x81\x13x_O^*S\xf1R\x99\x8a\x97\xcaT\xbcT\xa6\xe2\xa5\xb2a%\xc53\xca\x15\xb4\xeeb`L\xa6\x89\x9cY\xe0\xc7\xa6\xfbR.,\xfb\xf8\\X\x08\x87\xf0\x84\xb7\xef!\xebAwO\xbb\xcf\xfa@\x1a\xe8\x84\xd7v\xf0\xa4yYse\xc0{\xa7\xe6\x96\xec8%\x11iK\xfb\xa4Wmn\x19|\xc4B\xa3K\xbf$\xd2\n\xae\xe2\x8a\x8a\xa30*\xbfO\xcfg\xb075\x12\x0bGI\xe4#\xc3.\x86+a\x80`P\x02F\x18\xc0\x13\x81H\x95\xc3\xd8?\xacq]4\xa7\xbef\x96\xac\xcdc\xaa\xd3dx\xb6E\x90\x8cD\x9boB;\x14U\xa2\xb7\xa1#\xf8d\xfel\x8c\xcf\x14\xe7\xde\xa34)6k]\xfeD\xa8\x9c\xd62?\xf7\xd7z@\xe6\xb5\x16\x15\xbcf\xb6\x1e8\x1a\xc2\x1eC\xe5\xb7\x96\xf9\xe5\xea\xb9E\x9a\x8e\xcd\x003\x0ep\n\xbfq\x9d\xefYE\x1c\x0dk\n\x9c\x82o\\\xe759/\xbf\xcb\x89o\x02\xcf\x18\xf8*Z\xae\xe2h\xb9*\x1f\xa5\xa1\xd1\x81,d\xef4R\xf0\x99\xde@\xef\xed\x08\x8bg\xe2Z\x91\x92\xe4\xbfD8[\xfe\xf7\x17OC\x92\x94Qy\xe1\xfa\xdc\xe7<\x1fyu\xd9\x94\xc2\x19s\xd3\xf7\xb3\xa8(Gn\xf7\xc8\xea^[,\xa7\xd9\xe8\x1c\xdb*\xae\xcf?\x9a\x93\xdf6\xa4(\x1f\xd9\xf7~\xddBb\xfai\xc4\xccN*Wq[\xf8,\xc8\xde\x98\xd5\x8c\x0c%\n\xd5\x03}\xfbK\xd1>\x12~=\xec\x05\x1c\xc2\x92\x89\xc7z\xc09\x02V\x07\x85\xd1[\xed\xca\xaa6\xcf\xd3\xf0b\x82X`\xf0zpB\xbf\xf4\x19\xe4\x04c6f\x907#8\xec\xdf\x8e\x92\xfa\xdd(\xd1\xd5\xfc\x1a\xc3\x9c.k\xaa\xa9\xae\xb9\xd8m\xb0\xa7\xa7\xc8\xf0\xc3\x0dpW\x0d\xeb\xa3\x03Q\xb2\xf5\xe3\x88e\x070\x0d\x8a\x93\xdf\x0b\x03\xadk\x8b\x0e+? c\xf2\x82\xdfT\x8f\x9d\xee\xbc\x0b:z\xd5\xc8\x8d\xce@\xaa\x91\x13\xab\n\xa3bp\x9a\x1ej\xca\xae\xee\x8e\x86\x13\x96\x91U_P[\x87\x11\x97i\x9b\x84Q\xa9mX\xd5h1\xa0\xc19\xa6\xa0(\x13\x08\xfc$ 1H\xd6\x86u\x04D%\xb50*\xd5PF\xeck\xa4\xa9(\xd3\xe52&O\x05\x99\xd1\xef\xbc\x87\xe0<\xc2\x1ebG\xe8+u\xd5\x02\xcd\xd2\xb3\x0c\x0e\xa6\xf9X\x95\xeb\xf8 \xd6q\xd8i\xbe\xdb\xf1N\xceKq\x8c\x89L\xb4\xc0\xca\x92\xa9?`\xf4U\xe3\xf8\xbf\xd5Oo;\xf1\xad\x89\xeb\xa9(\x81\xc1\xf9Z\x81\x9d\xad\xe4\xcb\x9a}\xa9L\xea\xd4\xbb\xab\xf0.k\xc7\x9c\xd4\x87\xd1\xaay\\\xf6D\x1eq|\n\xdf8m\x02\xe0\xf6\x04\xe0\xf8\xba\xef\xfd\xfe\xbe+\xbfW\xf3\x17\xca\x1f<\xaaz\x10V\xcf\xdf\xb7\x95\x03\xdb\xa6x\xda\xe5\x97\x9b\x98y\x05\x89\xd9\xfdY\xcdLDU\xde\x10T/\xa5B\xbd\xa4\xd0\x1cQ6\xf9\xe6\xf9:\xbe\x19y%)J*\xceJ\xe1(\x83\x8c\xcbf\x02D\xab\x08<\x84\x84\xc7\x80\xd0\x9e\x9e\x9e\xafYu\xb0\xe6M\x99\xe7P\xb4\x00\x97w~\xef\xf0\x10\n\x9db=\x86C\xd8C\x8e\x0f\x93\x17\xfe\xfe\x9e\x8e\xb2\x903M\xc4+HyLY5W'\x1c\xe1fW\xd4\xb0\x1e\x8d\x9b9\xf1\xf5\x9eH\xc5?\xd7\xb1V\xa1\xd7P\x06(\x12\x9cK\x94u@\xe2\x82\xe0\xdc\xb6\x92\xf3\x17x\x0c\xb8\x0e\xce\xb1\xaa[\xfa.i\xbb\x83L\x88\xacEMc\xda\xcf\xb5)\x0d\x17\xf8\xd97\xad7\x14\xd1I\xafXvK\xb7\xe3R\xae$J\xbcE\xe2E\xc9\x82\xe4\xc7X\xe2\x7f\xe4\xe6<\xdaF\x9dg\x8d\xbe\xb7\xa0h|\x8c=\x16/\xa6\xa8\xefT\xcc\x07+\xb0\xf0K\x1e\x95\xe4E\x12_H\xf3]*\xe6EL{kf\x14\n3\xa1\xf7Lj\x19B=~\n\xf4\xcf\xb5\xa44\x99q\xaf\xf0}\xa2\x90\x90\x0d\x8bOw\xd1i]bc\x0c\xa9|\xdc\xa7C\x06\xee\x92N\xed\x0e\xf8\xe3\x0f\x08G\x0c^\xfa\xf96\x03>\x14\xedl\xe8p\xde%\x98\x89\x82`\xa6\x1d\n\xac\x82\xa3\x84=\xa7Bl\xcb\xe0\xea\x95y\xb4vYA6\xbd!\xb6\xb1\x85\x95ek9\x99\xe8\xc7\xba(\xb0\xb3\xc3J\xea\x8eUh\xa8\xa6k\x0c3+\xd9\xf8;v\x8aURc\xbe\x14^\xc2\xfc\xa8\x0c\xc9\xef\xe5\x96\x8e\xeb\xe9J\x7f\xdd+\x10\xd0\x1f\x0f\xee\xdf\x1a\xfd9\x8a\x10\xfc\xf9\x1c\xc2\x189|\x92\x06\x9bK\x96 \xe2$\x88\x15\x94\xa1\x1cB\x98\x068\x0e\x8f\x9c\x93\xe0Q\xba^\xfbI\xe8:A\x9a]\x98Sd\xc9\xa8\xd4\x07\xf3\xcc\xf0\xb8\x12R\xcd\xb4\x95\x9ck\x88\xeb9%W\xe0\xfd\xae\x0e\xce\xac\x8bK:\x8fX\xee&\xd3\x17\xd5T\xb2]\xbf'\xa3\xd2dQ\xaa\xb3\xcb+\xdb)\xc9y\xe9\xe7D](\x11P\x14CTj)\xbb\xf0\x8ezrs\xe2\x87\x8c7b\xb6q5dk$tZ\xd4\xa0V\x89A[\xc52/\x91\x0bT\xb0E\xf2)\xfd\xa0\xe6\xf7\xebP0\xa7\x7f(m\xe8\xa14\x95\x9dJ\xf4\xc9\xf4\xbe\xecX\xa2O\x1eLUqlj\n$\xbc\xd1N$\xa5\x08(\xe3&\xab?U\xd9|\\gE\xfc\x90\xe4EW$\xa5\xe2h\xe9e\x9bb\xe52T\xc3\x84\x9d\xec\xef\xc9?\x9d\xb1x\x9d\xe5\xd1\xc5\x18N\xfe\xf8o\xce\xdf\xb0zf\x9d\xa1\x08n\xc0\xdf\x9c\xbf\x8dx|\xf4\x06M\x12*V\x93\x9e\xaa{\xfbrTC\xb1Wa@\x0e$9C\xc5U\xe6\x17\x8a\x8dP94.\xc6h{\xea\x9c\x1b\xdd)\xf2HR\xe6\x11)\xa8\x90\x04{.\x16\xba\xa1\xc7i\xe6%\xe4\xbctG#/L\x132\xfa\x9a\x8f\xc2d\x8e\xc4L`6\xd6\x91\x15\xefZ\xe3\xc8\x0d\xc7p`R\xcfS\x9e\xedd\xdfP\xa1b\x8dPS\x89#\xa6\xb8(\x12\xad\x1b\xab\xff\x038\xdd\xd5\xde\xc2\x0dpf\x98?m\xcdW[N\x0b\xfa\x84\x00\x02\xbf\x0cV\xa0>Yc\x86\x11\xb8\xc2}{\xc1{XD\x89\x1f\xc7\xaa\x15V\xaf=\xbd\x98\x12%\xf3\xf8\xa1\xd5\xf8\xed*\x06`h\x0e\xf8\xd6\x89GP\xae\xf2\xf4\x8c\xbb\x07u/\xc9<\xfc\x97\xfa/\xfaA\x8e\x8a\xf34\xbc\x90\xa5\xd6\xa1 \xcez\x13\x97Q\xe6\xe7\xe5\xcdE\x9a\xaf'\xa1_\xfa\xcc\xd1\nG\xe6\xbc|q\xfc\x9a\xfd\xdd\xdd\xbb\x1aNa\xa9\xd9\x8f\xc0-|:\xa7\x8e\xb9f_\x82q}\xaa\xfdy:\xc6\x8c\x1c\xf2\xfd\xc9&\x057\xe7\xc51\xf9\x8d\xefN\xdas\xf7\x14\x0e\xe1\xac\xbb;\x97\xc6\xdd |\xf4G\xfd\x8dw\xca7\xacq\xfb\x01\xcf\xf5qd\xdc\x82\xc0\xb7\xe1\x91v\x1b\x02\x9e\x08|\x0f>q0h>J\x8a\xd2O\x02\x92.j\xae\xdb{\x12\xa1\xb0\xd0\xda\xa0\xe7t\x83\x1e\xfe\xffq\x83z\x89\xbf&\xf4\xef\xaf\xcb\x8b\x8c\x1c\xb2{\xf4'\xdf\xb9(P\xf7\xde5\xeem\x90\xe25X\xedq\x10\x98\xb4?F\x8c\x91\xdb\x05m6\x9f\x1e\x9f\xe8\xb5\x87\xc1\xfcg\x8d=\x7f\xa6\xdf\xf3`\xd94\xf0}x!\xf6\xfe|\xe8\xabe\x0f\x1b\x94\xb7#E\xb5 \x84\x97\x13t\x07uo\xfe\xeb_\xc9\xcd\xe5\x18\x1c\xa7\xab\xd8\xe3\xe3/e\xe5\xac\xdb\x1c\x8d\xcf\xb9\x93[\x8aJz\x9b\x8f'\xc4^7F\xefK\xcc\xca\x97\x98\x95O\x11\xb32 Z%B\x95c\xb0\"k\xab\x9a\xd7\x0dp\xab\xcf\x0b\xf1#29\xd5 c\xa0.K\x1b\xb3\x072\xbeD\xc1/\xa0#\\U_\xb0\x1e\x19\xe2J~\x0dCiZ>\x98\x97\xad\xe3-Q\xde\x148\x01\n\xeb\x1f305\xd6\xff\x9aV\xf0n\xba\xa7\xb1\xd0\x17\x8e\x82H\x9b\xf8\x10\xebr\xdd*p\xcc\xa3\xdb\x1b\xb3x\xfd\xf2c\xff\x00\xca7\xbd\xd2\xad\xea\xbc~_\x91\xf64\xec\xa6\x993;\xae\xd4N+\xbcW\xc3\x95h\xc6\x94\xa3M\x1d\x17o\xc5T\x0e\xf2\x98wF[\x89\xc5\\\xe7[Q\x8c\xdb\xa8\xf6R\x16\x8a\xe1d\x16E\x92\x01u\xfcL\xebdY\xb2\x9b\xf7\xce\xa0Z`\x85\xbd\x95 \xb6%\xbbM[jw\x05\xdf\xf5\x8c\xaf\xf9\xc2\xf7} \xbe\xef\xcfg`\xfa\x14gF\xcd\"\x99\xce\x0d\xcb\xb0\x82|@\x90\x00s\xb1\xa8\xc2\x17\xf91\xac\xd1\x96D\xf8\x02'\xf6\xe6\xd8\xd8\x82\x04\x9b<*/\x1e\xd3}\x1d\x95\xa6Z\xc7t+\xe5\xc6x\xdf\x98A\xf9\x9br\x95\xe6\xd1\xbf\xc9\xf7%\xa5\xb0{\xdd@\xb6\xe6\x15\xb0W\xc4Qx\x05\xf60\x8c\xd4\xe5\xc5&\xff\xf8\x03\xfd\x9d\xae\xc4\xea\xc5\xbax\x890\xda\xcd\xb0\x96\x8a+\x89\xa3m\xce\x86z\"\x02m\xd7\x9a\\\x91>\x84\x94u\\\x9b\xdf\xaa\xb1\xad\xd4\xc6\xae\xcaAX\xb7z<~\xbaJq\xf5\x1f\x9b\xeb\xea\x93zo\xc8\xe3T\x03\xb7ht4P\x1f\xad\xd7\xd9wC\x15Xj\xad6\xd9~\xf8\x80\xd2\x88\xfbP\x89*\xf4\xa1\xc9\x87\n\x1a\xf94\xd2\xe45\xbe\xcchD\xfb\x9e+n\xac\xd3\x90\xc4\x942\x8da\x8f\x07\xaaz\xe4<\xf3\x93\x90\x84#\xa1\xea0\xb8\xc6\n\xf8Y\xff\x13\n\n\xd0\xdf\xc3\xf2\xe9\xdd\x98\xb4&\x18iW\xb5&\x87\x89\x11&\x10S\xc8\xe3\xc8\x94\x1a*S\xb8n=ZE\x9f\xba-\xcd F\x99[\xac\xfeK\xee$\xd8\x86\xeaOI7\x9a\xf7\xc3\xf0^6\x11\xbc\x1f\x8e\x0d[E!9&\xf1\xe2Er\x84\xd3j\xe2\xc5\xf4+\x0d\x15\x1bV\xa1\xb5B\xe7C\xf7D\xd2\x89\x07\xac\xf6F\xdes\x0c\x85!\x1a\x90\x0f\xad\xfd\x11s\x80N\xf0\xf5\x94T\xa3\x19\xb4cw\xd8\xaa\xb6\xf3\xf0 \xb8z\xd4\x82\x98p\x08\x991\x956P\x98|\xaa\xe8\xcd\xfe\xfc\xb2U\xe8b\xae.\xdcl\x88F'\xc1\x0c \xea\xf2\xb6\x0d\xb5\xde*\x8a\xc3\x9c$\x943\xfa(M\xebB\x0d\xcd\x0d\xc9\xc2\xcc\xaasM\xc3Q\xdaxi\x05\x9b\xbc@\xa5[\x96F\x892_\x1c\xf4\xb0\xb7\xba\xcb$\xe7?\xed\xe0v\x1fX\xab\x92\x04%\xaa\x1368\x8c\x8b\x95\xed\x12\x1eP\xe4\xd4\xc7\xa0\"|\x17S\xf6\xcb\xbf Ar\x985a\xbb\x87\xa7\x91J\xf5\x85\x02\x990\xb0h\x1d\xd1\x92\xe8\xb5\xee\xc1\xee\xfc\xeey\xde\xfb\x0e\x89k\xb0C\x1d\xaf\x0f$O\\\xf8i=\x10GO\x9b(v\xdc \xbb\x14\x87~\xbf\x1e\xd2\xf83\xf0\xf9\xbb\x96*\xc11\xfb\xa10\xdc_g\xe5\xe0\xe7!\xc1\xf8A\x19m\xc9k\x7f>\xc8VZ\x99aC\xbf\xf4\x0bR\xa2G\x8e\xfc\xc8\xb6\x92Q\xaa^\xa8\xd5\x12\xbd\xdb\x97\x13JP\x13\x98,\xa2\xa5\x02\x8a\x89%\x86\xc0\xce\x00\x13QW\xb9\x86\x9fS\n\xfc\n\xf9\xaa(Y*E\x18G\xc4\xef#\x8b\x18\xa0k\x1b\x12\xef\xc6\x0d\x97~\xba\x02\xb4HS\xd4\x98\xc1\x98R\xf9\xaa\x8d\x99\xc4\x83\xefc\x0b/W\xc9j7\xb2\xce\xb0-^\xffIg\xafq8\xb5\xe0ly\xef\xc6XG\xee\xc4\xd1\x90\xefG%Y#\x9fY\xd3\x9a\xc3\xc3ff\x9d\xc6\xd9\xf2\x10\x1c\xbe\xb3x^\x96\xc1}\xd3\x07\xadt\xba\x16G\xc9;U\x860\xa8\x92\xd9\xf0$8\x8e9\x9dJ[~\xa8\x86\xa5\x1aDD\xc7{\x14F%`\x8c)\xcb\xbe\xc1\x1a\xe1wX\x154\x8dqd\xd7\xa5\xe0\xe7\xc8\xf5Z\x08\xda\xb3\x88'\xe7i5n\xbbBlTW\xb6>l\xc7\xd6\xb9P\xcc\xb1Y<\x92\xcb\x8c\xe8_}\x05\xe9\x18\x8c\xcb\xa0\xa9\x84\xa65\x071b\xab\xad\x94\xd2.M\xa2\xa1\xf55 \xd5\xa6;h\x1d\x06\xda\xc4'\xa4\xa6\x993\xd0\x14\xb3\x14\x14Y\x97\xef\xb4\xf7\xc0(1~\xdef\xa4\x05\x15\xb1z\x12S\xca\x9f\xf4\xa4\xb2H\xbc\"\x13\xbe\x162\xa9l\xc3\x1f\xf4\xda(\xf8\x83\x9eT\x16K\x0dL(\xfe\xb8qS,W\x1b\x98\x16\x1f_<\xcbl\xc53\xbd\xcfn>\x06\xbf\x7f\x92wy\xdfk\xe3\xb3+\x92\x84ozb\xa2\xc2g7\xed\x8b\x8az\x9f\xdd\xbc6X\x1d\xb6\xb7\x8e\x8aG\xcde\x89\xe3\x01\xabE\xc92\xca\x17\xab\xf4\xcc=a\x94\xb3p\xc6@\xde\xd2o\xf7\xe9\xc0\x989Q\x8c\xbb\xe3\xa5+f\xe9\x0dSH\x85\x1a\xdfN\xa8\xb9\xe6\xbc\xbb\x0dc\x9c6\xf8V\xdd!\x1c\x19B\x9f\x9a\xda\xf8\xe6\x92V\xc7\x05J\xb2Q\xdb\xdb\xb7\x03\xe2E\xc5\xf1*=K\x9aK\xdf\x80\xa6\x1c\xc0[\xccB\xa0?\xa0\xed8\x12\xa6\"\x9d\xa7\xe7J\xdeX\xd5L:\xeejX~o\xa9\xfbu=h\x1e\xb4\xc6\xe3\x93\x84Z\x0f\x8e\x90\x9d\xae\x9ax\xb5ZYY2'P\xf6\xa7\xa9]~l\x97]C\x16\xde\xa7T\xa3\x9f\xf5\x06v<\xabc\xe3\x19\x9d\xe1]\xc3\x19\xed\xea\x1e\x82\xf2\x10\x07\xbe\xad\xd0^\xe2\xf06)g\n%\xc6\x9c\x89^\xcc\xa0c\x84\x16G5\xe7\x02\xfc\xa2\x88\x96h\x931\xeb,\xaa\xe3\x806<\xfd\x1aJ\xf8\xa6w*|\x0d%\xa5\xfcj4\xda\xf2<6\xf5\xa1Pj\x82\xed\xaa&s:\xb4d$\xba]%\xfd\xf6V~\xf1\xe2,\x11l\x0c\xd3\x16b\x04\x02\xeeZr\x92\xd3\x13(9\xc9\xdf\xdaF\xc2B\xe3x\xef\xe3D\x1f\x01S\x1bw\x89\xea\xc4&\xda\xc3\x06\x9aCN\xd8\x81\x9a\xc07PV\xb3\x9b\xe8g\x17\x1a+\\\x9e$\x860\xc6\xdc#\xc9fMr\x7f\x8e\xe7a\xebO,&1\xc6\x9a\x88t\xd3o\x04\xd0\xde\xfe\x18x\xf64\xba$X8\xd1\xcd\xbd\xb3<*+\x88\xd1X\xc1d\x12\xfa\xc1w\xe4B\x1a!\".\xdb\xa0<\xa8\x17\xaa\x9a\xff\x92\x87\x9fh\xa6\xa8\xe27(\xeb\xe66P\x89\xee=^ \x12\xd3B\xe5\xbd\x9c\x84\xe2\xea\xf7\xe5\xbd;\xeao\xb3\xc8\xa8\x8c\xae\xd0\"2\xd5\xb9\xb2\xe2U\x80G>\xee\xb9\xa4\x19\x92Z\x8eD$dB\xce\xe0\xf5EF\x8e\xf2<\xcd]\xe7\x91\x9f$i t\xcf\x80\xcf\x8e\x18\xf0\x0b\xf0\xab\xd6T\x825g\xcbT \xf8\xa014c\x87At\x9a4{\xf9\x8a,HN\x92@t\x956\x08+\xbfH\xfeV\xc2\x9c\x90\x04\xd0\xe5\xd4\x8f\xa3\x82\x840\x81b\x93\x91\xdc\x1d\xb5 \xe8\xb0H\xa8+\xb9\x0f\xf5\xfc\xee\x95h\x97N\x11m\x1d\xd8;\xc4\xcc\x9dt\xf2\x90\xc0V\x13\xd2z\xc2\x98}9\x8e@c\x9e\xdc\xa8\xcd\xba\xf2\xcd\xb1$\xe5K\x81|/\x16nd\xe9\x1e\x0dR\x0c\x1c\x82'\x18\xa5.\x1f\xd2W_\xb1\xc21\xa8\x84V\xa0\xcd1\x9dlz\xe0\xe6\xa4((\xf6\xae7E $*W$\x879a\x1fH\xf3\x06\x1e\x8d\x81\xe2\x99\x037\xaa\x86\x14\xabB\xea\xedX\x9fQ\x8c\x87q\xb1s\xad\xfd\xaaa\x97\xd2\xa4(\xf3\x0d\xe5\xcdL\x96o\xbb\xf8\x8c\x9a2\xea\x8b'\xd0K\xd0\xc2\x996b\x1fX7+\xda*M\xc9'.\x05M\x1cq\x87 \x97\xcfT\xd1\xc2(x\x08\xd2\xfb\x1c7f(\xb9\n\xb4<\x94\x8a)n4\x86\xa62b\x0c)\xbd\xa5-\xd7P\xac\xd2M\x1cV\xef\xbc\xc1l\xa5\x96\x95\x03\xb4\x019\x82\xf5\xc0\xed\xa1\x9d\xd7T\"\xaf\xc2\xb70\xa5s\xd5H\xeeY\xf3 \xd3\xb7\xf0\xb0\xfd\xe7\xacg\x1a\xef^Q+\x01;\xdd\xd7\xaa\x02P\xd0\xa03\xcc\x9f\x81\xa5p}\x910\x1f\x80\x9a$\xbc#\x17\x85\x9b#WNZu(F#\x8flI~Q\xb3\x8b\xdaC\xae\xd1b\xe2E\x05\xf2Ac\xb6y\xb2B\xc9\x0c\x01\xe2\x14\x1e\xfd\xedn\xa2\xb9I\xd1\xcf\x94\x9e\x03\xfd\xeeiW\x12:\xddKO\xa8\x9c\x1c\x9d\x10m\xc7\xe4{\xa0\x8f\xb4\x94S\xef\x18\x06\xbb\xc73\xf1\x9e\xae\xd7\x1b\xdc\xa5\xad$\xc3p\x08\xd1\x18H\x83\x89\x8f4\xbc\x8cNa\x06R\xa5\x19\xb4\x07\xf2\x9e%\x88t\xf7E\xdd\x1d|r\xdd\xb4z\xa14WR\xca\x9f\xdc\xef)\xe9\"\xfe\xa4\xa7\xef\xf3\xf9\x83\x9e\xbeo\xc3\x1f\xf4>U\xf0\x07=}_\xcc\x1f\xf4\xf4}\x81T\xdf\xb7@\xf0\xa0s7\xe3\x1f\xb9\xd7t*\x08\xd5\x8a\xc0\xf0\xe3+\x02\xf5e\x8c\x86(\x02\x15\xc1\xfb=\x97\x0c\xad\"0\x96*\x02\x83J\x11\x18\x8f\xc68\xd7\xfb_\xc3\x02\xbe\x81\xf8kXP\x81%8Y\xb4\x15\x81\x0b;E`a\xab\x08\x8c\xec\x15\x81\x01W\x04.yd\xb2\xff=\xaf\xa9n#\xc7\xf1>\n\xdd_\xcb\xaa\xe0E\xc5\x8b\xef\x8eoa\x01\x87\x93\xdak\xa0p\xc6<\x1e\xc7/\x1cz\xae\x9c8a\x1d1\xe5\xbc\xed\xb5\xf3\x9e\xf7\xeeQ\xc7\x13l@\xff\x1c\xe8\xab\x86\xf0\xb3,\x11\xde\x15h@\x15\x8aN\xce\x8f4\xe7G\xbc\xc0\x93\x1b\xbe\"E\x1aoIx\xbc\x99\x979!\xeeI\xb50\x1d\x85\xaed\x85\\\xbar\xf4\x900\xa5\x17(Z\nU\xdb\xf4\x02\xb1T\xa1\xba\xf9\x04\nU\xbd*\xd5F\xe5\xca\xb2\x1d:\xfaa3<\xcf\xfd\x80\xa0\x8d\x18\xb8#\xb9\xaa=F\xb8,\xa9\x90\x1dE\xb4\xebb\x94$$\x9f\x18z\xa7l\n\x1d&\xad\xdb\xda\x0d\xe1\x9c\x12k' z}\xa4\x99#\xa7\xcc\xb5\x9d\xb1\xcb|\x96\xc6\x98\xf8\xec/w\xef\xde5h\\\x17iR\x1e\xb3o:Q\xe9\xc7Q\xb0C\x9a4\xf5`\xc2\xfa\x90jp\x893GG\x99\x1a/\xa9`^h\xa7(\xdd\xe4\x01\x99\xc1\x91\xbc\xbb\xa3Q\x8d\x80\xe7\x94H\x9f\x8b<\xd0\xe7J\xc3\xb4\x95\x0fw\xc7i\xcf\xa2\x8e\x1b\x0bi2\xd9\xae\xd1=\xe9dj\x80\xa2\xf2\xe4\xa9\x8b\xa7\x8e/\xd8\xf2,'\x81_\xea\x99X\xe0\x02\xe6\nm\xa9^T\xa0I\xf5\x1d~\xe8\x9d\xc7\xad&\x85\x9b\x1b>\x91)\xf3\x1f5\xaf-\xe5\xdc\x03?\xfe.\x8e\x96\xc9\x0c\x9c2\xcd\x0c\xf8I\xaf\x8cr\xff\xc9\xf2\x15\xf7\x9c\xd8\xf7\x0e\xc8\xda\xc03\x1amQ,\x026\xf3(\xfe\xff\x82>\x19p\x08\xce<\x8dC=n\xeaw'\x08\xad\x84&\x0d\x04\xb4I\xca\x86G;Vk\xa5\xde~\xa6=\xa3\xef\x17\xa7\x1c\x99\xee\xfb9\xe7dv'\xcc`K\xa3\xa0A\xa7r\xdd\xb0AIy\x80\x1f<\x7f\xd7s:\xf6sc\xee\xb1\x0c\x81w\xef\xb9\xaa\xcb/\xc7\xddT\x00\x16(\xc7\x03\xbd\xd0V\x99\xc0\x0dp\xf0WN\x7f\x9d\xd2_\xbe\xae'F7\x07!\x0f\x1b-\xf1m\xbf\x00\x83\xd5\xab!\x9b\xf1:\x84\x0d\xcd\x00\x86+\x9a\xdb\xe2\x0e\x02\x81\xa1%\xeeIa\xf0 \xe0Q\xdc\x0b\xb8\xa1\xb3\xa8\x8dd\xd62\xf6\xa46\xa8U\x87\xcc\x99\xf1\xb8\xe7'\xe4\xff\xfc?\xa7\xfdV\xf9\xb1\x0f\xa4\xc4\xea@J\xf9\x81\xa4&\xb2\x18\x8dw>\xe1%b\xbd\"\x8e\x02B{s\xa0,\x08+\xae-/\n\x99\xc2CH\xbd2\xfd\xf1\xb8\xfa\x81S\x9a\xf2 \xb2\x8a\x80\xbc\x0c\x19\x07\xb1\xaf,\x1cU\xac\xc9\x074\x99\xb3{\xf7\xee\xe9i\x07h\xe9\x07\xd8\x1c \x0c\x97\x92K\x92G\x18:\xc6\xc1d\x12l\x86\xda\xf1\xfc\xf3U\xbb\x10\xd4\xbc\xaal\x7f\x1e\xd3\x13\xefX0\x816;\xd5f\xce\x9do\xe0\xef\xf0\xed\xa59]\xc9Q`\"\xd75\xa9\xd6EuZ\xd3\xe9>\x8d\x1e\xaa\x8c\xb5$\xd3\x82D\x1f\xabA\x8c\xe4\x19Is\xb5\xb2\xbf^\xe5z\xa2\x0e\x0c&\xdf\xda\xae\xe8\xaf\x1d\x8am\x88\x197\x91,\x1b\x1f)\xa4W\x9a\xd8\xed+E3\xb0F5\x18\x82n G9T@\xa2\x89\xd2\xdc\x8c\x19\xd5\xa0\x81n\x06\xa7 #\xca\x01(\x92\xad@W\xda\xfc\xe9*\xd1\x11U\xaa\x03\xd0\xf1\xa7/\xe8\xd8\xb8.\x89\x8eL\x9f\xfd\x99\xa3\xe3\xab\xabD\xc7$-\x07 \xa3\x01\xad>\xbf#\x11\x0d\x14Wv\x02\xbe\xba\xec XW\xff\xba\x94 \xa0\xaf\x08\x0e\xe2\xb4\xd0\x94K}\xef\xec\xe0G\x98\x19\xfd\x08\x99\xe1\xee\xba9Pe\xca\xcc\x90\x99\xd4M*\xe2O\xa41\xe4\x99*\x86^z\x971\xa8\xdc\xbc\xac\xdc\xc6\xa0\xf2\xf42\xbbR\x01W\xe1G\x83E\xffd&\xf4\xb7^\x94\x84\xe4\xfc\xc5\xc2\x95\xa4\x12j^\xa6\xd8\xa0%\xcf\xeci\xe1\xfa\x03\xdci\xac\x1c\xe0\xd6\x03\xdcw\xcc&y(p\xe7\xb1\xd2u\xc4\x81h\x02?\x83C\xd8R\xd2~\xb98\x17\xd8\xc5\xbb\x02\xe0\n\"l`wg\x06`\xedo/\x13\xe0d\xd5GK;3\xe8\xe7C\x1b\x9d\x0b\xb5\xeb\x82!\xc4\xaf\xf6L\xf0\xe1\x9bC\xd8\x18\xc8L\xbf\xc2\xd3\x89\xe7yo\xb5#pN\x9c1\xac\x85\xdem\xbd\x9b\xae\x1b:\xfa\xeef\x90\xa9Y\xdf\x0d\xd6:o\xa8\xcc\xb5:\xbd7\x98q\xc1\x18\x97\x05\x95\xe2\xb96\xe2\x98\xfbF\x8f\xd0\x7fX\xaa\xab)\xec\xcf~l\xb4R\nX\xceB\xc9+\x1d\x8aK\x91\xcb\x8a=\xaad\xce\x0c\x1e\xee\x1ej+\x0c\xfb\x1a\x13&m\xa9B\xa9K\xc5\x1b\xb6v\xa3\xa0\xda6C4\x11\x01=\xd4\xfc\x12\xe9\x8c\xc1>\xa51\xb4\xa4\xd8\x80K\xb1V\x078\x0bvN\xb4\x9ex\xd0\x10f\x0d\\\x87\x9dh\x0e\xb5\xe8\xeb\x1bU\x1fcpZ\xf17\xad\xe7\xbd\xbb\x1dy\x14o}\xb6\xb1mr\xc93UI\x9e\x91J\xf2\xf4U\x92\xe7F%y\x16*\xc9S]\xad \xeb\xc5qRy\xd4\xcd\xea0\x9c\xe9\xfe\xe7\"\x80\xde\x9d\xd3\xff]?\x19TR\x14\xa1/\xf4)e\xd0\xf4\x03\xc8\xa0;\xe6\xf8\x87\xeb\"\x83\xdaH\x89\xc9@i5\xddAZ5\xcb\x8a\xfe0Yqc+\xda\x16\x18D\xdb\x0d\x15\xd1{\x03\xb0d\xc4{\xe8\x9f\\E\xa4\x18J\x07\xa0\x06S\x9f\x0d$n\xc4yP\x81\xce\xc2K\x8d\x83/\xd2|\xedk\x95\xb6\xc0\xb7#\x7f\xe1|m\x94\xaa\xb654F\xaa\x1a\xc0\xd7\xd2 \x15\x9f\xfec\xc8\xa7\xb1\x1c\x1c|\x03\\\xa8d\xe1vKR\xd6\x0bG\xf7\xb6\xfeE\x94,\xafL\xf2\xc6\xa9\x19C%\x81\xf3\x95\xb8\x02\x11\x9cw\xf1\xa7\xb4\xdc\xb9\x97\x17\xde\xca/\xcc-\xe9\xe7\xeb\x14\x8fe\x18\x83i.)Y<_\xc7\xe8\xfa\xb7\xfa\x0f\xd9\x13vS\x07;m\x0c\xe3\x84\x83\x81\xf1h\xae\xbd\xf3?\xff\x8f\xfe\xcf\xc1\x14\xe2\xce\x0c\x9c1\x1c\x97y\x94,\xddT\xe7M\xdaL\x94T!\xe8Vw\xe6\x9e\x99&\x83K\xaa[\x03\xa7\xdf\xf2II4=\xbc\x9c\xc2\xcb\\\xfa\xeb:(\xbc\xc6Pz\xe2}I <}\x86\xa7k\x91\xe0I\x14Qj\x8d\xc3&\xd3\x13?\x1e\xfa\xd8\x92T\x8f\x7f\xf6%*\xd9\xb4z\x8c\x87\xc0\x15ef\xe2{\xb2\x97\x0d\xc9*\x05S\xd9\xd9yI3W\x92\x1c\xf9\xa2k\x80|}<\x8be:\xd5\x94?\xe8\xe9T#\xfe\xa0\xa7S\xf5\xf9\x83\x9eNu\xc3\x1f\xf4t\xaa\x05\x7f\xd0B\xf2X\x8d\xe4\xf1\xc7G\xf2\xe0\x8a\xb2\x14\xa5*\x05f\xcf\xbbF\xa6\xc0\xcc\x87+0\x95Y\x8a6R\xc5edR\\~\xb2,Ei\xf2:\xbfH7%\xa6\xdfV\x03'\x1c\xf8\x91\x9f\x04$6\x00\xe7\xcc\xab%\xf1\xe71 \xb5\x01\xfe\x86\xba\xdd\xea\xb3\xb1U\xa8<\xbf\x98\xa4\x1buT\xb7\xb6R\xfb|S\x96\xf6Y\xd1\x9dy\x99\x00o\xef\xf4\x94\xfe\x11\xe0\x84\xd8\x147\x97\x1f\xcb\x94\x0fd\x93\x8aa]\x1f\xaa\x9f6\x1dT\xd4\xfc\x1b\x83\xf3:\xbf\x80\xa8\x84tS\x82\xccdfp\xdd\xd4\x17\xf7\xaeX#V\x12\xaak?i\xe1\xe7\x0c\x9e\xf0\x1d\xd0\xa8\x86\xd6\x01o`\xa8\x19\x9c\xe3\xe8\x0c\xf6jc!&\xc8\xa8\x0f\x95\xebYp\xfc\xcb\xa1\xf2\xe5P\xb9\xbe\x87\xca\xfc\"\xf3\x0bC\x91\x16\xe2E\xc5\xf1\x99\xbf\\\x92\xfc\xc0t\x94\xb0\\?\x1a\x12\x86P~\\\xa4\xc7\xab\xf4L{\xe2\x94\xba\xc3\xa0\x19XP\x8f\xd6\x0bVQ\x1c\xe6$A\xa1\x0e\xcb\xfc\x98?bG\xa6\xb7$/\xa24\x99d\xb9\xbf\\\xfb\xca\x13,\x1d\x7f\x88\xe6NO\xd7\xa4(\xfc%\x01\xc5\xfd\xc9\xc4_\xcf\xa3\xe5&\xdd\xa8\x0b~X\xcd\xa5\x12hu\xab\x0e\x0ey\x83\xb4\x18\xca\x14\x18\xc6\xe2\n@]\xea\x06\x13\xc7\xa8>\x94\x99\xdb\n\xd2\x90\xd4\xad\x15\x0c\xf5X\"V? \xa9\xa4a\xf9j\x9a\x91\xc4\xcf\"\xf6\xea\"\"qXP6 IK\x98\x13\xc8rR\x90\xa4\xc4\x8a\xd4+\x02\x85\xbf&\xc0\xf1\x1c\xd2\x1c^d$\xf9\xee\xe5\xd3\xc6\xb8\xeeY\x8e\xdc9\xdedY\x9a\x97$\x14\x0b*z\xe7\xe7d\xc0\xf8\xf8\xd4\xa0\xf0\xf57\xe7\xc0\xdbw\xfeV\xcdR\xb9J\x0b\x02\xe5\xca/a\xed\x97\xc1j\xc0g\xf9\xb4\xcd\xe0\x96\xb7\xef%l\xf6\xdcE\x9a\x039\xf7\xd7YL\xc6\xbb~k\x1f\xbf5\xf2\x1c\x11\xd3BI\xb0\xc5\x16\xd5\xee\xf3\x0f\xb0\xdf\xae\xdf\xf6^GE\x11%\xcb\xcfgs;\xafWt\x87\xa5\xdb($a\xe3u\x08SR`\xad\xdd\"#A\xb4\xb8\x00\x9f\x1eoQg'X\xef$\xbe#\xa3$\x8c\x02\xbf$\xd5\xd7$\x1b\xb9\xdd\x00|\xd9\x83\x97\x11\x10Z5I\xed\x85\x04q\xf2\xcb<\x0e\xc5\xa6\x96=c|\xca\xe7\xc7\xfd_c\xd5\xe5\xe0\xdc\xf4l\x97\x0c\xd48\xae\xfd8\xae0Q \x96\xe5\xf2\x9cm\x12\x9a\xd9u\xb7\x03\x07\x13\xb6\xe3\x7f\xafY\x92v\x8a\xa0\x8f \xc9\x9eE\xc9\xbb\xcf]\xbd\xdd\x18\x87\x0d\xb2pq]\xa9\xde\x96F/1\xe1\xa0$\xe7\xe50$\xf3\x8d\xb8\x93\xa4\xa8\xe1\x96\x88V\xb5N\x05\x1e\x1a<5\xa11\xd9^\x96\x93-I\xca\xc7\xacG\xae\x84\x92*\xf3\x9b\xae\xb0\xa2[\x89\x15\xddn\xb2\xf4N\x0c\xb4\x8b\xd9&=>\xdbT\xe9g\xa9n\x1f\xe3j\xf7\x1d\x89)\xb6\xb9\xb8+F\xacLk\x0b\xa1s=B\xe7\xed\x19\x94O\x86R\x8a\xe6k\x1b\xd9\xb0RJ UU\xc1\xf3u\x9c\x143pVe\x99\xcdn\xde<;;\xf3\xcenyi\xbe\xbcy\xb0\xbf\xbf\x7f\x13_\x93\xbf\xf4\xcf8J\xdeI\xdf\x9c>x\xf0\xe0&\x16 \x94\xbc\xabM\xf0\x93\xa5\x05rc3p\xfcy\x91\xc6\x1be\xf9{^\x05QQ\xbcF\x94?\xdc\xef\xa3\x7f\x17\x99\xd5\xd3J\x16\x85\xc5\xbc^\xac\xe7i,\x9d\xdamD\xce\xbeO\xcfg\xe0\xec\xc3>\x1c\xd0\xff\x93\x0c\x06\x0bNm\x928\x0d\xdeu\xd3\xd3\xe9z\x97\xb1<\xe0\x12\xa4\x9b\x81\xf3|z\xc7\xbb\x0f\xf7\x7f\x98\xde\xfe\xf9\x8ew\xf7\xd1\xf46\x1cx\xf7\xf6o\xc1\xf4\xc0\xbb{\xf7\x0eLa\xba\x0fS\xb8\xe7\xdd\xbau\x1b\xa6p\x97?\xbd\x0bw\xbc\xbb?\xdf]\x1dl'\xde\xfd\xfd\xe9\xa3\xfbp\xcb\xbbw\xe76\xdc\xf7\xee=\xb8\x07\xb7\xe8K\xb7\x82\xa9w\xb0\x7f\x8b\x0e\x07\xf0\xd9\x01\x1cx\xd3\x07\x0f~\xbe\xff\xc3\xed`\xe2\xdd\xb9s\x0b\xf6'S\xf0\xee\xde\xbe;\x99\xc2\x14\x1fM\xef\x05\xfb\xe0\xdd\xb9\xfd\xc0\xbb}p\x9f\xde\xbb\xf5\xc0{p\x87>\xbd\xb5\x7f/\xa60\xf7\xbc[\xf7\xef=\xba\xe3\xdd\xbdw\x00\xd3\xfb\xde\xfd\xbbS\xb8\xeb\xdd\xb9\x03\xd3\x07p\xcf\x9b\xc2\xf4\xc1\xea\x8ew?\xa0\x9f\x80}\x98\xd2\xcfL\xe8W`J\xbf3\xa9>swB\xbf\x13xw\x0enO\xbc\xe9\xdd{\xde\x83;\xb7&\xde\xbd;\xec\x07m\xee\xee\xcf\x0fh\x97\x1eM\xef\xc1}\xdaG\x98\xde\xf5n\xdd9\x80\xfb\xc0&\xec\xdf\x9d\xf9\x1f\x8d>\xf8\xca_\x9bu\xff\x93\xac\xe0\xf3\xe9\x01\xdc\xff\xe1\xfe\xcfw\x10l\x10\n\x7f\x82\xd5\x97\xe4\xb9\xb8\xc4\xe2\xdf\xf6n\xdd\xbe\x0f\xd3\xdb\xde\xfd\xdb\x0f\x82\x89w\xfb\xee\x03\xfa\xff\x93\xa9wp ~\xdd}p\x0f\xf6\x9fQ4\x98z\xf7\xa7\x0f\xe2\xc9\x81w\xf7\xce\x94\n`\x07\xdaW\xf0Q\xe3\x1f\x04\xa0\x98B\x1f\xc7\x07\xde\xbd;\xf7'\xb7\xbc\xe9\x9d \xfd\xf9\x00\x7f\x1e\x04\xb2\x97\xee\x8b\x97\xaa\xdb\x80\xb7\xc5\xcf\xaa\x83\xf7\xbd\xe9\xfd[1vor\xcb\xdb\xbf5\x0dto\x80\xe8z\xf5\x9ca\x1a\xed\x1d\xf6\x89b\xc2\xf4\x0e]k\xf1;P\xbe\xf2)0AY,\xf7\x12\xf8p\xcb;\xb8\x03\xd3\xfdgw\xbd\xe9\xfe\x038\xf0\xee\xdc\x0f&\xde\xc1\xdd\xfb\x13\xef\xe0\x1e\xffqo\x1f\x17\xf7\xc1\xbd\x07\xe2\x81wo\x7f\x8a\xff}p\xf7\x01\xec\xc7\xf7\xbc\xfb\xb7\xe0\x9e\xf7`\xff~@!\xbc\x83{S\xfc\xef\xbd}:[\xf4\xc5x\xd2\x80\x99\x08 \xfa\xe9)\xb6\x83\xdf\x11\xed\xd2\x15\xec4\xfcL\xf4\xf3\xd3\xce\xfa\xa4\x1fyy\x89\xa9\xbf\xe7\xdd\x9e\xde\x07\x9c\xf8\xc0;\xb8w0\x11\x93\xc6~<\xb8\xf7\x00\xf6\x0b\x9c\xcc{\xfbS\x9c\xc8\xbb8\x91\x0f\xf6\xef\x03\x9d\xce\x00\x97@\xcc\x14\xfb\x81/q\xa0I\x05\xd4XQ\xfc\x14N8[\x81~\x93\xb8\xf3\xe9t\xc7\xd8\xc1\xc9=oz{\xfa\x81\xe6\xfd6\x1c\xdcV\xcd;/\xcbqe\xd3\xfd\x00\xeemo\xffp\xc7\xbb\x7f+\xbe\xe5!)\xba\xf3\xe0\xd9}\xb8\x1bO\xee\x02\xfb\xdf\xd4\xbb=\x9d\xd0\x7f\x9eQ(\x98\xde\xfa\xe1`\xfa\xf3\xbdO0t\x16\xf1~e#\xdf\x87\xe9\xfd\xd5\xed\xed\xe4`5\xb9\xbd=\xf8\xf7\xf3[pw{\xb0\x9a\xde\xff\xf9\xee\x0f\xb7\xfe\xbd\xbe\x05\xf7V\xd3\x83\xed\xe4\xe0\x87\xbb\xdb\xff\x8f\xbdw[r\xe4F\x16\x04\xdf\xfb+\x90l\x9d*\xb2x\xc9d\xd6E\x123\xb3\xb2\xd5j\xe9\xb4\xd6T\xdd2\xa9\xfa\xcc\xce\x90\xacj0\x08\x92\xa1\x8c\x9b\x10\x08ff 5\xd6\x0fk\xfb\x03\xbb\x0f;f\xbb/\xfb0k\xf3\xb2f\xfb\x0b\xf3)\xfd%kp\x07\x107D0\x98U\xea\xd3\xe7LS\xb2\xca\x08\x04.\x0e\xc0\xe1\xeep8\xdc\xcf\xeb\x9d\x1d|\x1c\xc5\x84Q\x18D\xfd\xf3O\x07\x13\x9a\xa6\xfe6\xaa\x9f+G\xfd\xe9\xd9Y\xd5\xa6\xd47\x1f\x9e9\xce\x95\xd5\x87\xe9s\xc7\xb9\xb2\xfa\xf0\xb4\xbaCK\xf1\xc3\xf3j\x13\x81\xf3F\xa5\xdd\x9b\xa9\xba\x9e}\xee0u\xdddA\x80\x9f\x9f\xbb\x82\xedxq\x18\xc6QH\xf9\x8d\xce4\xad\x1c\xc5\xba\xd4$\x9ekP\xd5\x0f\xce\x10R\xee\x91+\xf5\x19\xdeX\x04\xd1\xbb\xf5[\x0c\xd7\x95\xd0}\x8b~\xd6_D|\xc3\xe0\xc3|\xa9S\xfc(\xf0#\xf6*^3rEN\xa6\xa5T<\x0d\x85G\x9d\xbeR\"(\x1e\xba\xaa'\x9d\x8aJv\x86\xa7\xa7\xe6\xc5\xb4x\x9f\xc4[N\x93\x9d\xfe\\x/\xa0S\xbd\xf7\x1b\xe7-\xa9^\n\xe6y=rrE\xc4}\xc2\xe2\x0d\xea\x8c\xfa\xa0\xb1\x19\xc1\xc1qOOWoP\xedL\xc4nIV\xe9\x89J\xa3:\xcd\x8b\xb9\xc9\xe6\xd7\xbb\xa6\x92c\x93\x9c\x056-\xad\x8d\xba\xbd\x1e\xef\xc1\xd5\xc9\x8c\xb3~0gK\x03O\xcaD\x1f\xae\x1e\xfe\xfc\xbe\xba\xa4`\x08r\xf3\x11\x95\xb5UY\xc5\xfb\xc5\xa6G\x84\x15*\x1c\x95j\xb2\xa0tR~\xa9Z\xcb\xfa+\xb80\xc9\x06D\xecx|\x0b\xfd\xfe\x8a\xf3\x98\xf7{\xff\x81\xc7\xd1\x96\xfc\x993\x85\xdet\x15\xb0?\xe3\xa1\xa4\x18\x11o\xc7\xbc\x1b\xb8\x9c\x7f\xea\xa1\x13\x8e\xea\xbd0\x8b\x9f\x18\xabF\x8d\x8cM\x1a\x8c\x88\x02[\xab\xe7!\x87V\xe4\xdc\xb0\xfb\xb4_\xfc6\x98lb\xfe\x15\xf5v\xb9-{m\xd5`sy\x99y\xb4\x84i\xc4\xa6\xcd\x1b\xd7Z\xbf\xbe3+\xc4\xd2\xaa\x10\xc6\xa6\x01W\xd4\xef\x8a\xb4\xde\xf93\x8a\xb8\x82\xc1\x87zj\xaa1\xa1\xfcp\x9dj\x06#\x8d\x99\x9e\xae\x18\xf29\xd5\x91\x16\xedU3\x1eK\xd3~4\x18\x91H\xd3\x89&@\xf4\xa1Z\xb7\xde\x01:!\xb6W\xd6\x94~@\x14\x86\xcea=\xe5\xf5\xa4RZG\xe4\x1b\xb3\xbc?\xe2\xb8D\x15\xbax6\xfa\xa0\xa1\xea\x06\xe2\x03\x06\x0c+\xee2l\xe0\xf7+\xe6B\xd1\xa7M\xe1u\x92 ?H\x0dC\xfe\x15\xf9(|\xbd\x81\xa1?u\x1e\x07\xf85%\xa6%\xb1)D\xfeE!\x01\x9c\x8e\xc4\xa6\x97[&~\xcb\x19U\x14<\xb6/\x0ebZ\xec\xb6\xaf$\xa7nS\xe3\xe0\xba\x9b\x98\x93\xbe\xe9e\x0e\xe1Hk\xfc\x03\x16m\xc5n\x04B\xca\xd9\x08D\x92^\xef\x82\xc4\xe3\xf1\xc5\x80P2\xbc\"|\xce\xe6\xfeR1@\xb6T\x8d\xf8\xc3!\xb6\x84]r#\"-\xcea\x1d\xfa\x8f\x0b\xf7x\x9a\x03>\x1c\xfa\xe4\x92\xc4\x17\x03\xd2\xc3\xa5\x80\x8e\xf3m\x17\xc85\xf6\xaa\x80\xa0\x06\x19U\x16s\x0ej`\x9a5\x8c\xc1Q#\xf0\x91\xb0s\xb2\xa3\xa9\x0bC\xd5\xa7,b\xa9G\x13\xf6j\xed\x92=U\x0e\xce\x92\x80z\xec\xabH\xf8\xc2g\xa9K\x12U\xd9\xb0\x9a\xdf\x8b0\xa8\x8b\xa4?\x17\xb4\xfa\x19J\"?e\xb1`o!\xa6\xd5a\xed~\xef2/\xf3rQ\xd8\x88\xbe\x1f\x95\xeb\x03\x95QG\xb2\xd3\xbb<-\xd4\xda#C\x92b\xf6r\xed\x1eR\xc4.5\xb2\xb9Xj9\xeb\x9a\xf4.\x13\xce^^\xaa\xe2P9\xed\xc3g-\x17\xc0u\xe6\xcbS\xf8zy\xaar\x16\x00 3\xd2\xebR\xb02\x0e\x1b\x16y\xae\x85=R2`\xe0\xe2\x0f\xdeH\x91F\x08\x1d;\x17\x8ekjkX\x1b\x8e\xc305\xeb\x93\x80F\xdb\xef8\xdb\xf8wu\xc9)Q\xe4\x9a\x86\xa9K(Q\xdf\xc1\xc9\x0c\xf8\x9f\xd1\x19'i\x12\xf8\xa2\x7f\xbaH\x87\xa7\xdb\xc1@\x87\xf2\x86H\xde\xbc\x1f\xe0\x12\xc6\x1e\xbe\xf5\xb2T\xc4\xe1\x88x\xf3\xb3\xe5\xc0\xfa\xb1p\xe5\x99\xab,\xcb\xca8\xd4\xed\x17U7\x1f\xe3\xd1\xe3U\xef1\x19\x92\x1d\x0c\xbb\xdf\x8f\xfb\x9b\xc1@\x8d\xf8\xe3\xde\xe3R)\xa7)ia\xc6\xd5\xbc\xad\xd5L\xc1\x0c\xf6\xa3\xc9\xce\xdf\xee\x02\x88p\xf4\xe8\x11)\xbcj\xc3\xd5B\xca\x88\xcc\x133\xd90\xeb\x1e\x15}o\x80n)\xfa\xf6\xd3\xa0\x15\x83\x1c\x88\xa1\x87DK\xeb\xd9d\xc7\xe8\xda\x8f\xb6\xb5%\xd8\xbabv\xaa\x0d@\xc7\xdd\xb7l\xcf\x02\xecb\xb95S\xf1\x91k\xd1Yum\xad\xef\xbap\x00c\xda\x1bM\xeev\"\x0c\xfe\x98\xc1\xb1\xed\xe5\x8e\x93\xd3\x97=X\\;\xfe\x12<\n8\x87k\x95\x05\x01\x13o\x03?\x15\xdd T\x168\x08S\xa1\xa2#G#\x0b\x9a\xa7\x13\xea\xf3\x05\x0b\xbbC\x17\xf8\xd5Y\xca+\xa9A\xd6\x0cU\xe0\xd7;\x19s%\xaa\xad\xdd\xc3\xd5&\x98\xaa\xb9v2\xc0\xdee\x1c\xe8e\x03\x95\x93\x97dJ\xae\xc9c\x92\n\xca\x05\xaeP\xf3 \x96&FTu#L \xbc#'!n\x99\x04E\xb5`[\xdf\xa9\xcfE\x06!\x80\x0c\\\x93\x1e\xa2bR\x9d\x99\xbc\xe6N\xe0\x9a\xe1<\xe9\x17jW;\xe659\x07\xe1\xf1%\x05\x1b\x10\x03\x07R*\xce6\x06\x06\x0c\xf3\x15\xbb(\"\x8c\xc1\x11\xcb\x8cV+\xf0C\xba\xed\"\xb2\x9b\x01|LR\xee\x95 M\xb9\xa7\x01\xad\x8fS\xf6\xd0!oX\xbd~\xb85Q\xcf\xfa\x8f \x0d\xf4hc-4P\xf3\x80\xcc\xd5$\xa0]1.\xe1\xc7\xbd\xc7\xeaO\x86\xeb\xbfH\xbf\xc9i\xaf\xb0\xd0+#\x04\x11D\xbb\xd3C\xc8^'\x16X\xcb\x113\xd5T\x8f\xe2\x81G@\xa3\xb27\xd5r\x0c4\x0d\xf5\xac\xe2\xf5\xfd\x11\xd0\xa8\xecM\xb5\x1c\x03MC=\xfc\x08Pxm\x9e\xf9Q p\xd7\xa8v\xa2\xd8\x1d\xb8\x94\xd8i.E\x03\x7f\x1bi\x0eu\xaf\xd6\x8d`wb\x0c\xa93\xa43\x98\xa3\xca\xac\xea\x90\x1d\xd3\xb7]\xad|\x1d\xe5\x1e\xda\xb3\xf5G\xee\xd9qh\xbc\xae\x96O\x05\x8f\x1d\xa2jc\x15\x98\xbf\xa1\x96# q\xd7s\x8c\xe0\xc5BG\xe9# \xa8\x97_\xb3\xa0{\xf3k\x16\xb8\xca\x1f\x01\x80\xa3\x06?J\xbbC\xe0G\xa9\xab\xfc\x11\x108j\x08)\xaf\x0b\x15\x8d5\xa8\xdc\xce\x1a\x8e\x00\xc2UG\x9a\xad\x0e\xad\xb5\x1c#\xb3U\xf3f\x1e>V\xebN\x8e\xa8;i\xab\xbb&`\xee(_\xaf\xb4.\xf1\x90D\xa1\x1b\xa9\xec\xa4Vj'\xb5\x88P\x12\\9\x88l\x1ao\xc4\xd1M@\x81\x94\\whM=\xd6);\xbb\x13\x1d\x07\xad2T\x95\xf1\x11a`N\xcb\xbaTV\xac\xaa^\x93\xa0\xdb\x0f\xae\x87\xaeVu\xae\xd9R\xd3\xe3KU\xe2\xa0\x14\xf7\xf2\xb1\xa3\x99#\x16\x85\xca_SB\xc5\xb1\x88b\xc1\xder\xb69\x04\xad\xe1D\x7f\xc8\xc2\x15\xe3\x08\x9f\xbf&C2\x1dLD\xac\x1d\x938N\x97\x95\x88\xdb\xdbD\x9cm\xc0\x10\xdb\xc9\xc4P\xea\xcdV\xdf\xac\xc9Kr\x06G\xa6\x9c\x0c\xafHof\xf5\x0c\xf0u0\"\x8f\xd5\n2\xea\x1f\x03\xffX\xd5\xfe\xd2\n\xfd\xbf\xdeD\x8fuL\xdf\xc7=\xe2\xaf\xaf\xac\xc4\xff\xb8\xf7rn>\xf5\x96Jxw.:;.\x80Y]wD\xba3eI\xf8\xf1\xe5\x8eW\xc1M\xc7)Kz\xb0N\x14\x1fn\xce\xa22\xc0\xec_\xa6\x0c\x9a\xaeeSY.\xe3\xa0^\\m\xa1\xa1|k\xcf\x8e\xc0\x9f8PM\x9dj@\xeaT\xc4\xd6|\x14\xea\x07>\xcc\x0fNX;j\xe1l\xd6\xa6\xde\x17,\xac-\x0e\x0b\xcc\x11\x1dt\xe9Kl=4\xf2v\xf1\xc1CE\xb3Fr|o\xefR\xd7\xc5\x105-\x06\x92\xe3|\x01\xe3\xabC\xb4\xa2\xde\x0d\xac\x90\xbf\xfe\xaf\xffM\xe1|e\xb0\xd6\xc7\xc8(\x0e\xcd\xd9\xfa\x08\xcd\xdbZ\xd4D\x9c#\xf6^\xeb\x9a\xb0\xb9>N>rC\x7fL\x0d\xc2Q\xc3Q\x02\xf3\xba\xb2\xe9+\x1f\x03\xa5\xe4\x8ad\xc5\xf3\xc3.\xcb\xa8_\xe4\xa4\x84\xf5]\xc4\xa9\x90}8\x8c\xc8\xcb+\"\xf4\xe9\x1a\x19\x93s\xc5\xc7\x15\x9b.+\xcaP\x13\x05\xd6\x07F\x0b\x85/FmU\xd2X\x89\xb9B\xbf\x82\xc6\xea\xac\x9c\xac\x99\xa5iU\x15\xafh\xcf\x8a\xf5\x9c\x97\xda\xd4 Z\xab\x85=Tip\xc5\xb9\xd4\xcf\xf78P\x03ri\x8f\x0f\xa1\xa9\x8a\n\xd5*\xd9\xecya\xaf.\xa7\xe4SS<\xa8\xcd \xf5\x03\x0f\xfa\xea\xc6]1\xb9\"\xf3\xda\x94\xcd{@\xa8{\xe8\xdb\xff\xec\xf9\xc0q\xf03\xef)\xden\xb2\xbcpg\xe1l\xc38\x8b<\x08\x13\x0f\x19?ug\xd4S\xaa3}\xe6\xced\xe9\xa2\xa0~`\xf2~\xde\x0c\xdc\xb9\xce3=k\x82\x0e\x8e-C\x16 \x03\xdft\xea\xce\x9a\x86\x94\x0b8\x06\xb49\xcf\xdd9\x03?\xba\xf17\xf7&\xd7\xd3\xc1\xb2\x94iy\xc4q\xbf\xc3z\xaahd\xc5\xcb\x84\xdc\x1ej+\x92pvA\x18\xb9$\xb1F\xc6\x0b\xc2\x86\xc3A\xa1\n\x8c$\x12\xcf\xd9r~\xb6\x1c\x11x\x98.]\xa6W\xc5\x03vm\xe5Q\"\x10.n\x84Gi.\xf8\x04\x9a\x02D\xe66X\x01\xa2-\x13\xdfg\x01K\xfb\xbd\xde``\xe1\x16\xe4\x92D\x17D(\xf0\xf9\\,\xfb\xac\xd1\x84\xe3\x03n\xc3\x95,A\x1a\xbb\xc6\x8a\x160\xd7\x84i;\x17\x1c\xcb:\xe1SC6\xb3\xd4\xcae\x01\xa9\x830\xb1I\xca=s\x88\xde?]D\xa7[\xbc\xf6:\x11\xdc\x0f]\xe2m\xc0\xf6,p\xde\xdeRm\xa532?\x1b\x91\xa9\x03?\xf3\xbb\xd8\xf32^\x82CWm\xc2h\x0c\x8f\x14X\xa3\xa2\xbd$\x9b\xb0h?\xb2\x1d\xff\xd8\xc6\xafO\xab\xb6\xaa\xdaJ\xe6y\x93\x91\x0c3\xa7\xb6\xbe\x0b\x0b)\x9c\xe6\xa6#\x12\x8c\xe0\x18\xbb~\x04\xfd\xec\x9c\x9c(\x82<\xf1v\x94\x7f\x19\xaf\xd9\x17\xa2\x7f\x96\x9f\x17\x8f\xa7\xf5\"\x9fO\xebE\xa6\xedE\xb4G}f\x1d\xe4\xf7\x96\xb3^{\x11j\x96x\xa1\x8b#2_\x0eF\xa4\x9f\xc1\xd5b:\"S\xe07gDJ\xf2\xfc\xb3:T\x19\xc8}\x8d\xcd\xc0r\x0c\xc8\x15\xa1\x93$N_\xd1\xbb\x11\x8a\x01\x8a\xc1]\x90\x94\\\x92@\xb1\xb0\xe9\x19\xd4L\x01E\x0b\xb5\xa7\x83\x0b\x92\x0e\x87naR\x873\x0c|\x8f\xf5\xcfG$\x1b\x8c4[\x86C}\xf3\x05\x9a\x1a\x91\xd4\xa0\xb9Y\xf4\xe4\x9a\x8c\xa7dF\xfa>l7\xd9\xde\xa7H\x07\xa5\xac\xa7)\xda8\x18\xe9;\xd8\xd0F%\xc7\x1c%Xo 2m\xe3\xc7+\xb2\x19(X\x1c\x14\xb0\x1bq(\xd0=\xf0'\x82Q=p\xa1\xb8\xccF\x0b\xb4\xa4~\xc9\xd8\xd2\xca)\xd2J\x9aKM\xd3\x12M\xac\x954\x0d8\x85*Z=\xde+\x89R\xd4\xca%\x8dR\x92\xaa\xc0J[.a\xcf\xfc\xa0\x03jY\xd3\x82\xc6\xe2\x82\xf0\x82pt\xd2\xef\xab\xf5\xed\xf7\xf9\xa8`R]\xa56\x88\xe3\x83\x8b\x01\x10 \xaeQ'68S\xb7\xd40\xbfb\xc3\xaa\xe4(o\\\xe1Q>\x14 \xde\xa1=c\xde=\x9bx\xc8[\xef/N\xf9\\6W\xcf\xa6U{B\xaa\xd3\xab\x86\xf8h\xed\xff\xec\xfc\xccIA\xd3\x9c\xbc\xd4\xccp\x14t\x9apB\xe4\x80\xf5\x88\xecFd?\"\xe1\x88l\xbb\xd1\xc5\x03\xa4\xf4\x01t1\xa8\xd3\xc5\xd4\xd0E\x0f\xe8b0\"g\xedt\xd1\xeb@\x17\x13rE\x02K\x17\x15\xd1\xf2\x90.n\xc8%\xc6p\xe8?=G\x8a\xb6\x86\xac\x15\xea\xb8Ac\x9c)R\xa4\xf5\xe0\x82lj\xb4\x12\xc8\x80\xaf\x00\xde\x1c\x80f\x0fM(\xc1R\xc7m\x1ca\xfc)\x03\xa4\x82px\xa5(\xc3G\x04\x0fZ\xb6\xf5\xed`\x1c7\xea\x91\"\xc8\xe4\x9a\xf4\xc3:`\x16(%O@\x86^\x0fSw\x83\x02|\x1a<\x07d\x17\x03\x05\x8c\x93\xad\xd8\xd2\x9a)9J[\xde\xb1U\xbc\xacoX\xcdtD\xbcA\x99M\xa4\x93|s2\xdf\"w\xa8\xa6\xb9.\xbe\xe8\xb8\x9c\xa1\xc3\xe4\x0d\xfc?\xecK\xe9\x8a7m>\x1eS\xf1[\x99\n\x10\xccB\x17\xb4\xc7\x8eR\x92\xb6\xa1>\x92\xff\xf8\xc7\xf3\x9f\"g\xf1\x1b8K\xce\x99\xfc\x1agr\xf2\x1f\xffh\xfe\xe3\x1f\xe2?\xe9/\xc4\x7f\xfcv\xfe\xe3\xbb\xf8\x8f\xff7\xe5?\x0fA\xc1F\xfc\x83\x01\x8fpw\x07n>\xec\x0e.\"\x97\x84_\x90H\xed\xe0JX\x01\x08\x16\xcf\xa3\xe5\xc0\xce\xba\x99\x07\xbd\x03\x11f\x00]\xbb\x10\x91{\x8b\xfb\xd7\x1a\x0d\x90\xcaK\xdb\x0c\x18\x80\xfar\xc2{d\xb5\xf4\xa4b\xf8LJ\x0b\xd9\xaa\xd5\x816\xb1\xfc\xa2\x9a\xddx\xd6B}\xb5\xe8\xdfz\xc5c\x17\xa4\x06\x85\xf5\xc7\x8cB\n$t\x85\x8b\xe6F\x1cF2\x0f\xe8\x8a\x05#r2\x053\x1cGUE\xfdV\xb9\xae\xe9\x88$Z\xce\x0e\x14IMM5}`'z\xfb\xcc\x06#r\xb2\xa9^$\xd2\x93\x9d\x0f\x05\x18%\x0e\\\xdd\x04\x04\xa4\x96\xe4\x95K\x8c\x0en\xd6I\xbeaw\x9c\xc348Q\xd1\xdbpo8\xac}\x06/Q\xb9\xb2\x83:\x15\x1an0\xa0']\xe0%\x0e\x98[\xa0%\xfa\nmK\x90\xc3\x96\x0e\x11\xdd)\xdc% *^\x93>lG\xe7\xcbAG8+\xb4\xbf\x19\x12\x81\x0eh\xda\x82\xcdv\x006\xeb\x08V\xa3\x8e\xc6\xfc\xac\xae\xc6eEh~\x06\xa0\x96j\xac\xfa\xa50\x8c\x1f\x0c}\x95U~\x8cQ\x1d\x8f\xbd\x06\xb8\xe0\xe2\x8a\x82\x1eh\x02\xd0&\x886\xab\xd7x\xfei9\xc8\x97]\x91ji\x83\xf5l\x80\xf2\x8c\x9b\xd3\x9b\xdcs[,\x97@\xac\xf6<_$q\xd2\xcf\x03\xbe\xc4\xf9\xbe3\x8b\x04\x9cg]\x17\x13fJ\xac\xe1\xa8%\xe5p\xa3\x87p\xb5\x1c\x1f\xba\xe6\xf0\x98\xee\xe1\xab\x0e\x0e\xd6Z\xc3|\x1b\xccj\x98\x12\xb7\x14\xe2#G-\xf6\xc9\x1ft\xa3\x84\xc4\xd1\xcbC\xb8u\x10q\xea4\xb2\x96\xd2\x0567\x95n\x83\xae\x05\xb2\nT\x1f$W\xd9d\xbb\xbf\xe6\xcd^\xfdruo\x7f>\xee\x0f\x16\xf3\xc5\xf2\xe7\xf7\xc3\xeb'\x93O\x16o\xe4h\xf6\xeb\xcb\x93\xc5b9\x00E\xf0b\xf1\xc9\xb4\xf71\xf6\x10\x0ey\xa5\xb8\xbb\xef\xb0\xb7()\xcf\x1a\xb6\x0dy\xce\xef\xd9\xf6\xab\xbb\x04\xc4]\xb8&\xd4\x7f#\xe7=\x08\xd2\xb8\x88\xfa\x83\xf9\xf2\xf1\xa27\x19\x9d\\\x8f{\xfafO\xaf\x87\xc1\xb7\xb8\xb9\xdb\x83\xa6\x82\xcbA_\x95*_t\xaeC\xd31n\x97\x9d\x804[\xa5\x82\xf7\xa7\x0e\xbc\x1cL\xd2\x98w\x0cN\xaa\xeb+\x9ck\x9a\x13@W\xbd\xa5\xeeI\xec\xdf\xa0\xff\xc9\x03\xc7\xa5g\xe4\xa3\xc2h\xa3\x82\x04_\xfa\xeb\x11\xe9m{j\xe7\xbb\xb1\x92Q\x9e\x17E\x933$\x98\xbb\x92\xc0\x1e\xa3\xc0\xee\xa6+\xd5\xed\xdd\xce\x9c\xd5\xba\xf3\x93\xe2\x86\xb2\xafH>\x14\xb0\xd2{eo\xf9\x12\xe8\xb2\x18\x8f\x9bk#\x06\n\xc1\xee\x84\xdeLP\xbd\xd9\x1b\x1c\xdc\x1b\x9a\x9f\xd5\x80\x9f\x8d@OF\xf3\xdd\xc6f\x12\xd0T|\x13\xad\xd9\x1d~\xf7\xb4\x0c\xb7g\x81\x11\x8d/@|\xdfL\xd8\x1d\xf3\xfa\x19\xe8-\n\xa5^\xa2\xfa\xfc \x95-\xfe4e\x83N5\xd3\xd9\xe2\xcf\x8a%\x99\xde\x98\x06#\x92\xa0>\x8d\x0cI2\x9f.\xf5\xe0v\x08EG\x0e\xf1\x99\xe2\xef=\xb8q>\xbeo\xd6L\xadc\x07\xb5\xb6\xc5\xb1\xde\xb5\xb8\x91\xcc\xcf\x97\x1d\xa2\xe7\x91\xc3\xf2b\xf1\xf7\xd0\xee=d\xeaT\x0f\xba\x15\xf9\xdb\xcc\xce!>_\xfc\x1d\xe0\xf9\xc5\x9f\x82)\x80\x05\x93/\x921I\xe6O\x0d\x8a6\xabR\xcc/-ho\xfa\x01\xb9$Y!\xe1!\xfd}\xc8t\xd9\x95\xf6K,\xa9\x12aT\x04\x0d(\x8d\x91\x98}\xdd\xf4\xd9\x08\\\x1b\xa4#bR\x04\xea\xb4\xdb)\xe6\x07 7&\xd5\x1cZ\x9c.\x86c\xb9\x98,&rq\x8d\xff\xc9\x93\x93\x93\x139\x1a\xc9\xf1\xf8\xb4~\x98q\xba\xe8\xf7=)B\xc9e2X\x0cN\xb7~\xfd`\xa3>w\xde\x8c\xf4\xfe\xfb\x7fsL\x11W\x1f\xfe_\xc7\x87D}\xf8\x7f\x1c\x1fD8#\xbd\xbf\xfe/\xffw\xaf\xf4\xa5\xc1\xda\xa6\x8b4\x95\xcbQ.iIk\xab\x8a\xbe}\x1a\xe4\xa5\xd2\xde\xa8\xc8\nS\xcd\n\xd3&VXc\xc4v\xd3\x94v\xe7\xc7\x19)\x97;\xcc\x96I\x91\xed*,\xcd,\xdb\x85\x95 gQ9/U\xafx\xd0<\xc8Oz\xfa=<\xa3\xb9&\x01\x99\x91\xc0J\xc3\xf1\xa8\xdd\xf6\xac\xfa\xd3\xd2\x97?\x17\x13\x11\x7f\x1b\xdf2\xfe%MY\xbfbtS\xfc\xa9e\xc6'\x82\xa5\xa2O\x07\x16^Z0\xbf\x18\x8eA\xec\xfe\xef\xff_oPH\x9d\xfc|>z\x0f\x1f\xfe\xfa\x97\xffZ\xfc\xd2\x9f_\x9f,\x07\x7f\xfd\xcb\x7f\x85\x8f\x9fL'\x93\xfa\xd7\x9f\x9f\xe9\xb2\x9fL\xd5\x7f\xc5\x0c#[\xef\xa8T\xee\x8d\x9c\xbf\x19/\x07\xe3\xf1\xb8\xaf\x1e\xe4'\x83\xd3m\x085\xfc\xf5/\xff\xfb'\xe7\x95\xbc\x8bt0\x1e\xf7\x17i)\xdb\xffV\xcb6\x7f3^\xa4\xaa\xd2>>\xd5\xb3\x83\xff\x96\\mM?\x8an\xd5\x12\x8d\xf9\xe3\xde\xd2E\x1c }[\xa7\x08\xa7\xf3\xf1\"\xc5\xdd\xd1\xf2\xd4\xb5\xc3\xa2m\x16\x8a'}a\x0e\x02\x01\x7f\x8d`\x0e\xd3~\xe2#\x120\x85\xbc\x85N\xd6\xdb\xc8\x0e\x98^\xdb\xad\x04\xd0em\x10k\x13\x914WF\x91<\x80\xde\xf8\xceM\x9b=\x92\x1d\x91\xfb\x11Y\x8d\xc8\xdb\x11\xb9\xfd0\x82t\xab5\xbf\xab&\xc2\xb4\xd2\xc4`u.\xc5\x9a\xccFaK\xaer\x88a\xe8\xb60tx\xfct;\xdf\xea\x9c\xe4\xf2\x8al\x06\x17d;\x1e\xb7\x9c(\x99_a\x0c\xb6\n\xb9P\xae\xd2\x9b\x14\xd8_\xd9\x15<\xe8,[\xb1\x19v\xe1\x82(\xc1\xca\x03\xc2\x18\x97vAz\xe3\x13\xe3\x86\xc7\x1f\x0c.\xda\x87\xd9\xfc\xc0\xd7\x07\xb9\"'\xb4\xafPX\xefN\xc6d\xaa\x05\xc2\xd4\xeeW\xa6#rO\xaeH\xef1NL\n\xa6\x89\xa0:\xc0\xb2\x01\x1e[']\xe6\xc3\xfcT\xeb{U\xc3zDB\xf57\xe9\x06\xb5\xf9\xc1\xa0\xb4\xcdc_\xcd\x83\x9a\xcaQeJ\xc9f\xa0\xa7\xf4\xa8\x06\x89\x06z7I\xfdh\x1b0\x18\x8a{\xd5R\xa1r\x95\xb69f\x18\x8a\xbf\x1c\xe0{rM\xfao\xe7;\\j\xc5\xe3\xca\xcc\x91<\";\xb46\xc8\x89 Z\xc4\xce\xcf\x97\x15\xb6\x91\xf5\x0b\x02\x80\x9e`G\xb9\xa7K\xd0&\x7f\x0c\x10\xce\x1e\x08\xc2t\xa9X^qI\x1d^+\xae\x9fj\xca\x8f2V \xbe\xd1\xe5WW\x836\xfd\xf6\xe4\x9a\xdc\x1e\xb3\xcf1?\x18\xc5V\x1d\xb4\xeb\x97\xc4\xe9\xcc\x0e\xddQ%\x11ug\xc4\x11\x07\xbb\xed\xa7\xf7J\x9b\xce\x85\xc0j5T\x8b\x03VH\xff0\x02\xf4\xfe\xfa\x97\xff\xe2\x8a\xa0\xea\xfa\xbd',H\xd9G\xad\xfa\xa3\xee\xc1\xc0\xc0\xbc\xea\xf8\x15\xe4\xa9\xdb\xdb[\xf9\x1b\xb9\x98-N\x17\xa7N\xb9\xc9o\xd4L\x9f\xbe\xb9\\\x9c\xd2E\xfa\xe4\xe5\xa9\x91\x90\xda\xc5#Z3^7F\xe8s\x87^CX\x0b.7\x06\xab\xce&\xe82\xaa\xf9\x9c*\xe3\xc1\x8c\x9c4\xc4\xae`!\xf5[>\x8b[_\x08\xc6\x9b+\xd7\xf2\xf2\xd7Q!0g\xd3\xdd\x16\xf3Ko}\xe1\xed\x14\x92l\x99x}\x9f\xb0\xfeA\xa1\xc1\xa3)#\xbd\x8c\x07\xbd\xd9Add\xc7\xacy%\xb2\xccH4\x81\xc8dl\xfd\x9a\xddu\\\xf60\xaa\xd0\x83?\xf1\xc0\x11\xf9\xa6\xfak:w*\xfe\xe0\xc2n{6\x1c\x08\x98\xb5\xbf\xaf\xa1\xe8)\x90D\x0cjF\x18\x96\xafTB\xbf\xb0\xa3z\xa3s\x9c\xfa\xa3\x92[\x9b\xa6\x9f\xe3\x0c\xcc~j\xfcb63Sg\x8ez\xb9\xea\xb4\xe8\xf2\xf5\x11\x0b\xfc\xe8&\x9d\x11V\x1f\x12\x9a\x89X}U\xcb\xa4\x1c\x93\xda\x15L\xea\xd8\x8d\x0co:\x80*\xeee\n;\x80:|jg\x12eA\xab\xe2E\xdf\xc3i\xd8\xe3\x14,\x95\xee]\x96J\xce\xb1\xaemk\xee;\x1e|\x14\xb6+\xa0o\xb9\xffX\xe7\x1f\xb9\xdb\xa0\x1eXD\x822);\xea\x14\x04\xea\xd1\xb7\xd0\xb5\xdc\x9d\xabr\xb6 \x9f[Vw\xfa\xe6\x92\xce_.\xd2\xa5a\x0d\xdb\x01\x1a\x87\xea+\xa3\xbb\xf1xD\xfc~\x9a;\x18P\x89\xc3\xe1@\xc9\xc6\x90\x0bR\n\x9b\xaf\xbc\xad\x18k\xcc\xcbv\x01\x9e\xe8\x0e\xac\xe0\x90Q\xc9\xf9}\x85\x1b\x14.\x13(\xf4F\xa1\x7f5\xc91\xda\xee:l\xaf\xf6\xa5=e\x08\x05\xfb\x81\x82yo\x15\x06F\xbc;L\xf1\x88\x99tOo\xa3\xd7\xd0\x9a\xde\x11np\xc7\xba!\x97\xb6Y4\xbe\xcdM\xdf \xce%\x15\xec[\x05\xc6~\xbeYN2\x1e\xa0\xa6J\xdb%\x1b-\x1a|\xd4;T\xf5Y\xb5\xb4\x1e\x11\xef\x18\x12I\x1e\xa4\x0d'E\x8dx\x90\xab\xa5\x93\x8eJq\x92\x0b{\xebN\x05 \xb2\xc0C;f\x1d\x8c\x1d\xd1;m\xcc\xab\x87\xbf{9}`\xd5f&T\xfd\x99\x81\xe8p.E\xb4\x02\xf3\xa1#\xf1\xd0)\xb6\x98\xd6\xbd\xec\x91\xd3\xfb\xf0>\x15h\xe0\xd1\xd0\x8d\xc7\xdd\xe1\x0b\xd0\x92\x1eP=!\xc3|L\x0c\x91\xe8 \x0e\xa9_P8\xb4zh\x9f\x1f:\x8fG \xf2\xd1\xf3w_9\xbb\xcaJgWY\xf9\xec\xca\x1b\xd9\x834}vu\xb0\x9d\xf6m2\xee\xd5\x0eV\x82\xe7\x1e\xe3\xf1\x05pI\xadM9\xb9\xb2\x14\x9a\xe0\xadmC/\xe0Sf\xac\xd7/\x06\x8a-\xdb6:\xed\xe0\xf6:(\xe2\x88\xf89z\xc4\xfa\xe6+\x1a\xc0\xd9\xe2U\x8ew\xfa\xe4\xa4\xdc\xa1'\xe4\x0b\xcb\xc7&?\xa6\xd5\x8fg\x93\xe9\xf3\xc9\xd3Jj5\xd3\x97qr\xcf\xfd\xedN\xf4\xbd\x019?\x9b>'\xff\xcc\xd96\xe6\xf7\xe4\x7f\xa2^\xbcJ\xc9\xe5\x96\xb3\xedo\xd4?\xe3\x1f!e\xe2\xc5\xe1\xcbj5\xaf\xbeyM\xbe\xf5=\x16\xa5l=!\x85\x18\x86j\xdc\xd28\xe3\x1e\x83X\x86\x01\xe6IOC_\x8c\xf5\xcb$\xd9%\x07\xa0T\x15\xa6\xb3\xd3\xd3\xad/v\xd9JAp\xaa B\x80N\xdbF\xe1\xb4\xf4\x0e[\xd1Q\xd9\x80\xbd\xddF(\x9e\xfcI\xf8\x81q\xb0\xae\x9d\xe2W\xac\xc4\x9c\x02v\x9c_\x94v\x9fe\xc6Q*x\xe6\x89\x98\xcfH\\_\x88\x19\x0fR\xf7\xb6\xb5eG\x9b\xeff\x1d\x1f#v\xfb\x1f\xfch\x1d\xdf\xba?\x97\xb7\xda\xae\xcay\xa6\xd6.\x9b\xe9{3\xf5\x1c\xc5X\xac.'\xd0\"\x0c\xbe\xa3\x14\x9d\xf8\xe9\x97A\x9c\xa2\x13\x9ck\x18\x89WT\xec&!\xbd\xebGj\xaf2R\xd2\xfc\x0cvK#\xa2\x1d\nT\xfd\xd5\x17\x7f\xa0KC0\"\xe1\x8b{\x0b\xc51e\xf1\xeeV\xab.\x86\x98\xcb\x8bfz\xf5N\xf0\x07\xc1[\xdbP?\x0dJ\xd0\xb2OGX,\xcc\xce\x8cnV\xa5\xe9\x04\xb7F|\xb5\\\xef\xddX\x8d\xc0w\xc1mc\x8c\xa8\xb1\xfaU\xbe\xb6\nj\x0bf\x02w@\xa0,\xc8\xf3=\x94\xfb\x17\x1a\xe8\xa8\x03] s\x15\xef\x02#,=\xf74\x14\xc1\xb7j8bb\x19\x95\x93'\x1e\x0d\x02\x13%FS\xe9\xc1(\x8f\x86te\xa3! rM\x04\x99\x91\x13\xbco\n\xbe\\\xec\xe8\xa0V\x08\x8c\xc7\x05\xf1\xa3T\xd0\xc8S\x85\xe2\x89\" \xaf\xe9V\x15.\xfa\x83\x9a\xd9\xd1}m\x89R\x7f0Y\xa9\xa7>+\xfaY\xea2\x88%\xd23k\x16\x05\xcc\xcf\xa8V\x01\x86\x9c\xbc\xb6\x0e'\x83\xcd\xb1\xa3\x94 \xe0TH\x9a\xe4\xd0\x0cF\x8e\xb3\x0cw\x17^\x15i\xf8q}(\x90\xffc:Q(f{QH\x9b\x141\xbf\x99T \xcb\x85\n\xd5c3\xa9\xd5\x1c\x18r\xc2ssV\xcb\x91!\xb3~k\xce^b\xc2P\xa4\x90\xe2&.\x83#f\xe6u\x81q\x1e719\xcb=f^\xf2RvZ\xbe\x80\xdb\x11\x85\xc5\xd2<\x1f\x05\x81\x05j\xb3\xef-\xc3me\x14l_\xbf6\x17(\x88,H\x05\xcd\xfbQ\x83]Jy?\"1p\x99C\x9e\xb3H>n06}\x81j\xaa~U\xc0\x1c\x19t\xd6\xbe\x7f\xe2\xf2\xaa\xfd9\xcfPIS\xb2\xabS\xfa\xa4\xabTp\xea\x89WL\xec\xe2u\x07d\xc0\xa0f=S\xae\xd7\x05\xe1Ph\x9e\x1d\x1e\x04R\x94\xc3\"\xe2G*\x9b\x98\xech\xfa\xc7\xdb\xc8F\xa3\x8fP\x14a\xf3hI\xd0#X\x03\xfb6\xb8\xd8\x05Fv'X\xb4\xee\x08#\x80\x87\xf2\x1f\xcb\xc5\xfbf\xe4\xaan\xe7\xde7\xdc\xcc)m\x15\x1a\x16\x98\x91\x18AW]\x1b\x9b^a;\xd1\x1b\x00\x93*\xa4\x90\x0e\x13L@\xde)\x14\xd2\x81F\x90\x99R\xbe\xcd\xc01V\x83\x843(u\x01\xc2\x03\xb6\xce\x0d-\x81\x07q\x19\xe9$\xcd\x12\xc6a\x01\xe2\x0d\xe95\x0b\x98`\xe5\xae\x8c*;2\x8a\n\x84\xa8\xd3\\\x07\x81\x9f\xa4~:k\xdd\xa2\x17\x7f\xd6\xa4K\xebh^b\x90\x04\x98\x83(\x0b\x02%VD\xe4\x9a\xf4&\x93\x9e\x12~1\xbc\xa21\xf6Rl\x1f\xf4\xfcc\x12Y\xd5\xf1\x90D] \xb6V\xecvDN%\x0f\x7f\xc19\xbd/x\xe8\xd25\x0c\xf2\x8e\x18eq5r\x83\xf9\x15\x96\xa1\xdd\xeb\xb0\xceG\"\xc4\x9c\xbb\xc0\x1aU\xd2\x95m:j\xc5\x87q\xfd8\xcb1 p\xff\xe5\x8bh\xfd%MD\xc6\xd9\x11\x03s\"&\xdb ^\xd1\xc0\x11\x9e\xf1\xcfP\xed\xf7l\xcb\xee\xfeL\xc2,\x15dG\xf7\x8c\x88\x1d#\x8f\xb7\x8f\xc9&\xa0[\x92\xb2Z`F\xf3\xcbG\xac\xb23\xbc \xb8T\xc1@\x8a\x81\xcf\x00}\xb9\xb9\x80\x1f\xf1\x08\"\xe9\xad\xd9\xdd \xdf7Eh\xbf\x82\xe1(\x8c9\x94Jl\xb5\xdf\xb2\x1b\x8az#Pw}\x84\xeb\\\xc6H\xb9Wf\x99!}\xec\xe3m+W\xdc\xdc\xdb\x9d/X\x9aP\x8f\xc1\x08\xce\x08\x04dr\xec\x0f\x8a\xfa\x8e\xc3\xdb\x02\xb7\xde\xc5\x86+\x8d\x18W\xa0\x1a9#O\x90\xb2\x98\xf2\xfa\xd5\xb7\x9d\xf0\xcanw\xbb\x80V\xdc\x96\x08,\x86\xa1UE12\xa5\xf95\nb\x95\xe6\x8eiMJ\xd2\xeb\xc4\x81S&\xbe\x10\xe5\xbdb\x87\xbbkzC\xa3J\xa6\xfd\xc1\x9c-\xf30\xba]\x1a\xdd\xd6\x1b=\xba\xc5.\xed\xe8\xce\xa5]\x1a\xaa*xtK\xad\x0b\xa9\x82\x829\xfeu\x01n[\x07\xae\xcb PU\x06d\xe8\xc2\xebU)\x0c\xae\xf9\xb9G\xe4K\xc5>\xbb\x8cH\xb1U=\x92\xfd\x1e0\xdf^M\xc3I\x1a\xe4\xbb\xf5\xbass\xb9\x9a\x0d\xd5hf\"\xa0\x82\xfe`\x94\xc7^\xac\x10\x14\xd4\xaf\xe9\xb9\xd0\xdc\x0bo\x11D\xe0\xf8\x1d\xefDr\xb5\x13W\x94\x17\xef/\x98\xc4\x0b\x98\xf4l\x92\xee\xfc\x8d\xe8+\x12<&\xb8\xed\xf7QrP\xdc\x9c\"\xc1l\xe2\x88n\x1c\x9d\x189\x85\x16\x03\xcfu\xc5\x0e\xce\xc2x\xcf\xfe\xee\x07\x8f\x16oX\x95FR\x0de\xbbv\x13\\p\xe2 _\xc0\xa8\xc3\xb1\n\x8e\xb7j\xc1c\xfdtD\x1c\xd7m\xc9!\x8d\xd9G\x9d\x89m}\xc9tY1\xb5\xe6;\x93\xe4\x1dM;\xcf\xbb\x15\x8e\xd0\x9a\xa3GzdX\x9d|\xb8(\xdc+\xdc\xa5\x81LL'w\x81(e\xe2\x1b\xc3?\x8f\x80\xaa\xc6\x89\x8f\xe3\x80\xae&\x8fk\xb1\xf3\x90\x1b\x1d\\\x87\x96J:\x8f\xa2\x16\xbcE\xe5`\xb2\x83\xce\x0f\xb0\xe2\x07\xc1\x0f\xf0\x96y\xef\xb2\x87\xd1\x95 \xaa \xf5\xdcb`2\xd2{\xd9\xcb\xa3\xf8\xda\x91R+\xbdwy\x8a\x05{/{\xcb\xa3T\xc7%\xf0:\x0c\x05\x8a\xcd\x96\x0bYA\xbe\x1a\xc5\xcb\xfc\xaaC\xa7\xd7G\xfb\xc0\xcd\x97\x87\x84j\xe2G\x84\x0d\x08sk\x03\x84\x16\x98\xc9\x90<\xc6\x08\x0b\xb0\xf5\xc0\xa8`\xed\xf4<\xa7\x16\xf5\xd1+\xa5\xbcW\xa2xMou\x84\x88\xfcQD\xdf\xceS\xdc\xa5\x89\xa2\xd6\xc9\xc8\xfcm\xbe?\x8c\xb4\xda\xa3-f\x06\x14\xe5\x1d\x98\x7f<\x0d@\x14`\x85\xd3+T\xb5\xe3X\xfe\x9e\xb3M\x7f\xd0\x82 ~N\"\xa0R\xedoZ\xcf\x04\xbb\x13\xfdBm\xa8\xb7oROt\x19\xbd\x02\xcc\x1d\x05f\xb3On\x1e9bm\x87Dc\x1e\x07(\xe6g\xf9:\xc2\xf6e\x8a\xbcC\xed&\xdb\xe6\x95\x1b\x13u\xa3K1\x1b'\xabA\xd5\x190\xb6!\xb9\"\xbd\xb7\xab\x80F7\xbd\xae\xaa\x942<]P\xae$\x81[-k\xfb\x12\x85\x93\x9a\xa1\xa5\x8dC\xd2\x1b#s\x9bu\xa4\xfc5\x8c\xe9\x02\xa9Uek`\xd7\xf1k\xadF\xae*f\x89\xbb\xd5\xbc\xc0\x11\xcd\x19b\xa2uT\xf6X\xce\xa8\xb0\x15\xbb\xc3@\x1e\x93\xef\xfe\xf8\xc37\xaf\xbf\xf9\x97\xaf\xde~\xf3\x87\xaf\xbf\xf9\xc37\xaf\xffc7\n\xe6<\xd69\x82\x8c\xa9\xf2z\x8f\x0f\x1a\xfe\xd3\xfe\xf5\xac7\x7f\xd3[>\xb9\xee\xc9\xc7\xf37\x8f\x97O\xae\x1f\xcb\xf9\x9b\xc7\xbd\xab\xcb\x97\x7f^\xa4\xcb\xe1\xe0\x14\x19\xdc\xe9\xfc\xcd\"]\x9c\xf5\x1e\xbf\\\x9c^-\xee\xce\xa6\xe3\xc5\xdd\xf4\xeb\xc5\xdd\xa7_/\x87\xa7\x134\x0fQ\xb3\xdb\xbf\x9e-\x16\xe9\x93+\xf5O\x0foM\xdao\x83\xeb\xde\xa8\xe8\xcbd\xaer+Vy\xd9?\xf9\xdd\x1f\xbf|\xfd\x1f\xbf\xfbj\xa0^u\xeab\x91\x0e\xf3W1\"= \xeeQ\n\x15\xaa\xcf\x83'\x86\xdb\xe2\xbb,Tq\xd9?\x85F{\xe0o\xe6t~6\xfe\x9c\x8e\xdf}1\xfeO\xcb\xfcq\xb6|rZ\xad\xb3\x0c\x81\xb0\xad\xa8^\x9d^\x17\xda\xcb\xf9\xf7\x88\xf4\xb6~\xcfE\x0b\xd5\xa0\x7f\xb9\xa3\x9cz\x82q\x13Q\xddhZ\xfa\x8f\xa2U\x9a\\\xc8G\xbf\x9e\xbe8\xbb\x90\x8f\x02\xa1\x9e\xe1q\x8b\x8f\xe7\x17\xf2\xd1OY\x0c/O\x9f\xc1\xbf\x9f_\xd4\xaf\xdb\xab\x1f\x989tA\xd8\xd2n\xa4\xb0\xf7\xb0\xf8Q\xb2\x8c\x98//PUzb|]\x82\xf2g\xfe\xf4@nE\x10ON\xc4A7\x1bAE\x93\x1b\x8f\x88\xd0\x9a\xbaf\xab\x81\xc0\xaa\x87\x91c\xa91Ut\xe7\x8bh\x0d\x93w\xff\x87x\xcdR0'\xf6At\xd1Zv\x7fD\xa2\x81M\xec\x17h\xfeWh\xa4\xa1\xca\xf5\xb5\x8f\x81\x81\xd6\x0d\n\xab\x1b\xa4M>\x86H\xe3fJ\x89wq!@\xc9\xa1\xa9\xf0\xaa\xc3\xd12\n^\xb7Q\xf0\xdc\xa3pD'4\xed\xf4\xbbP\xe5\x06(\x8e\xc3x\xad\xdf\x8dr\xb2Y\xd1I[\xba\xdd\xbcp\xf5~]\xaf\x8f\xc8*\xd79Z\x0eA\xd0\xb1\xf3C\xd3\x01{\xf89\xef\xb02\xa29\x07/\xb2\xcd\xd3E\x0b\x92t\x01\xf3\xd4X!\xda)\x84\xcb\xdc\x99\xf2\x91\xecg\x0f\x99\xba\xbaX\xd4(m\x14V\xc2\xd1'85\xc3\x86\xe2\xb2j\x11|Adh9\xe1\xb3\x92q\xc5\xe1Ds \x0f\xad\xa8\xaa!\x83\xcc\xef\x18Q5\x1f\xfb.H\xdc8\x12\xf9\x0c\x1e\x1c\x88\x0f\x06\xd9\xe0\xd4\x87\x00l\xf1\xf2\xe3\x81\xfb\xabr\x06\x87\xb4\xa4\x1a^\x9e\x8e\xb4S\xb0I\xffz\xe6G\x82\xf1\x08\xbc\xf4\xd1@Z\xf2\xe7\xc7\x91z\x01\x92\x14\xf3T2\x95-\xe1~\xcaR\x99\xecb\x81^i\xeee\xc2\xe35fO\xe5&\xce\xa25\xd4$\xfd0\x8cW~\xe0\xb3H\xfa\xd1:S}`\xa9\x0ciD\xb7\xb0VU\xb9\x84q%tI\xc1\xbc]\x14\x07\xf1\xf6^z;\xee\xa7\"\xa4\xa9\xf4\xe20\xcc\"_\xdc\xcb\xb5\xcf\x99\x82\xe1^\xb2u\xe6a\xf5\xec\xa7\xccO\xa0\x1e?J\x85/2\xc1dH\xf9\x0d\x13~\xb4\x95i\x1cd\x08\xd1\x9eb\x81T\xae(\xdfR_=\xc4\x99\xf0\x7f\xca\x98\\\xa1\xa20\x95j\xfb\xaedf\xe9\x05\x8cF\xf8\x10\x8b\x1d<\xc4a\x92 \xc6\xe5\x9a\x85\xb1\xc7\xa9\x90k\x9f\x86q\xb4N%\xf4\xdf\xf7R\xb9\x8b\x83\xb5\x1fmS\x19\xf8\xdb\x1d\xb4\x9fP.\"Us\x12d\xe1\n \xca\x92$\x80\xber\xeaC\x13{\x16)y4\x95\xd4\xa3k\x16\xdeK\x8fr\x06\xd0\xc4aB\xa3{\xe9\xf1\x0c\x06{\x1d\x87\x007\xbbK\xe2\x94\xad\xe5\x06\x9aI\xe5&\x88\xd5X\xc9-\x0d\x02\xc6\xef\xe56\xf3\x05\xe5\x00\x8e\xbf\xa6\xf7\xf2\xc6WX\x11\xc9\x88e\xa9\xa0\\\xc67~Do\xa9\xe4\xcc\xf3\x13\x96J\xce\"A\x03\xf5w\xef\xb3\xdbT\xa6;\xff&\xddQ\x89\xce R\x009\xe6B\xa6\xf7\xa9`a*\xe9\x96E\xde\xbd\\1\x1e\xf8\x91\xf4h\xc88\x95\x1e\xa0\x85\xf4\xe2\xcd\x861\x85/\xeb8\x95\n\x05\xa2\xadd\xa9\xa0\x82I\xa6z\n\xe03.\xe4&\x13\xab8\x9074\xdb\xb0H\x06\xd9]\xc6\xefeH\xfd4\x8ed\x18G4\xdd\xc90KY\x16\xca\x88n\xe3{\x8a\xb8\xa6\xa0L\xa8\xcf\xd5\x1f\x80)\xf6|\x1a\xe0\xa8\xdeKA\x85\x88c)|\x16\xad\xa9\x1a\xe1=\x0b\xe4\xde\xa7?\xb2T\xee\xfd \xa0\xeaO\xaa\xd0f\x1f\x03d\xfb\xf8\x9en\x99\x04\xccF4P\xa3\xbfN\xa5\xb7c4\x91\x9e\xdaw\xc85\x8d<&a\xd1\xcam@S5\xb2Y\xaa\xd0,\xda\xc62\xf2\xa3\x1f)L\xb4^\x0e2\xdd\xc5j\xd4\xe2\x80r)b5\x03\"\xbe\xb9\x8f\xa5\x88\xe3 \x95\xb7j\x8d\xca\xdb\x98\xdf\xa4\x922\x1eK\xca\x13*i\xeaS\xb9b\xa9\x90+\xff\x86\xc9U\x00h\xf9\xee\x9d\x1a\xdeDzA\xb6\x92^\x1c\xabU\x19'rCy(7~\xba\x93[\x7f#\xe46\xe3\x99\xf4\xa3M,\x7f\x8cW\xa9\xbc\xf1o}y\xc3\xd9Z\x064Z\xcb\xc0\x0fc\x19\xf8\xd1\x8d\x0cY\x94I\xb5\x18e\x18\xaf\xa9\x8ch\xc8d\xa2\xf06Q_\x938\x15\xf2\xa7$\x8e$\xf7\xbd\x9d\xe4\xd9\x8e\xcb\x94\xdd\xddK\xe1'\xa9\x1a/\xa6\xfe\x89\xe5-\x8d\xb6\xf2V-\xe7[\xff\xc6\x97\xef\xe2\x88\xa9%%W\xfeZ\xae|\x05\xf0J\xad#\xe9\xb1Xa\xb0Z\xaar\x1b\xef\xa5\x1f y\xe3\x872\xf4\x03\x191!\xe3(\x901\xdf\xaa\xe5/\x93l%\x15\xc0\x82\x052\x8bby\xcb\xd6\xf2\xee\xeeN\xde\xdd\xbf\x93\xd4\x93t-)\x93t#\xe9VR_\xd2@\xd2P\xd2H\xd2X\xd2\x9f$\xe5\x92\xa6\x92\nI3Io%\xbd\x93\xf4\x9d\\Q\xb9Z\xc9\xd5Z\xae\x98\\m\xe4j+W;\xb9\xf2\xe5\xeaG\xb9\n\xe5*\x92\xabX\xae\xb8\\\xa5r%\xe4j/W\xb7ru/W\n|\xe9y\xd2[Ko#\xbd\xad\xf4v\xd2\xf3\xa5w#\xbd@z\xa1\xf4\x14)\x94\x1e\x97^&\xbd\xbd\xf4n\xa5w'\xbd{\xe9\xbd\x93k&\xd7?\xca\xf5\x8d\\\x87r\x1d\xcb\xf5;\xc9<\xc9\x98d[\xc9\xb8d\xa9dB\xb2Ln|\xb9\xf9Qnn\xe4&\x94\x9bXn\xb8\xdcR\xb9]\xc9\xedZn\x99\xdcn\xe4v+\xb7jb\xe56\x90\xdbPn#\xb9M\xe4\xf6'\xb9\xe5r\x9b\xca\xad\x9an\xb9\xbd\x95\xdb{\xb9\xbb\x91\xbbP\xee\"\xb9\xe3r'\xe4.\x93\xfeZ\xfaL\xfa\x81\xf4C\xe9G\xd2\x8f\xa5\xff\x93\xf4\xb9\xf4S\xe9\x0b\xf9#\x93?\x86\xf2\xc7X\xfe\x98\xc8\x1b&o\xb6\xf2f'o|y\x13\xca\x9bH\xde$\xf2\x86\xcb\x9b[ys/o\xde\xc9\x80\xca`%\x03O\x06\xbe\x0cnd\xc0e\x90\xca@\xc8 \x93\xc1^\x06j\xa9\xca\xd0\x93\xe1Z\x86L\x86[\x19\xeedx#\xc3@\x86\xa1\x0c\xd5\n\x96a\"\xc3\x9fd\xc8e\x98\xcaP\xc80\x93\xe1^\x86\xb72\xbc\x93\xe1\xbd\x0c\xdf\xc9\x88\xca\xc8\x93\x11\x93\xd1FF[\x19\xf92\nd\x14\xcb(\x91\x11\x97Q&\xa3w2\x0eeBe\xc2d\xb2\x91\xc9V&;\x99\xdc\xc8$\x90I(\x93H&\\&\xa9L\x84Lner/\x7fR4M\xf2X\xf2T\xf2L\xf2[\x99R\x99\xaed\xea\xc9t-S&\xd3\xadLw2\xf5e\xfa\xa3Lod\x1a\xc84\x94i$\xd3X\xa6\\\xa6B\xa6\x99L\xf72\xbd\x93\xe9\xbdL\xdfI\xe1I\xb1\x96b#\xc5V\x8a\x9d\x14?Jq#E E(E$E,E\"\x05\x97BH\xb1\x97\xe2V\x8aw2\xa32\xdb\xca\xecFf\xa9\xcc\xeee\xf6N\xee\xa9\xdc{r\xcf\xe4~+\xf7\xbe\xdcGr\x9f\xc9\xdb\x8d\xbcM\xe5=\x93\xf7B\xbe\xa3\xf2](\xdf\xdd\x0e\x16\xab\xd3\xaa\xe6\xb47\"\xe8\xffoq\xbb\x1c\xfc\xa6\xbf\xb8\xfdy:\x9a>\x7f?0\xba\xcc\xb2:\x14r_\xcf\xe6\x8b\xf1\xc5\xec\xd1\xd5b\xb8\xf8d\xb4\xb8]L\x96\xc3\xdf\x14\nD\xf6\x897Ub4\xa3\xb6B\x94\x19\x96\xf3\xf1dh\xc5\x87\xe5p\xd6\xbf>i\xfa\xb48]\x9c\x0e\xfa\xd7'\x8b\xf5pqz=\xe8_c\xca\xb5\x13\x90\xbaJ\xb7?\xb9>E\xa5\xaej\xff\xf6\xf6v19\xbadsG\xad\xf6\x17\xd4\xc5\x8b\xb1\x05|\xf8\xe87\xbf^\x9c\xfe\xd3\xd5\x7f~\xdb\x1f\xc8\xc7\x9f\x80@Tg\xe1O\xbc\x0du\xc8\x11\xb3@\x8c\x0f\xaf\x03y\x12=\x1a\x7f\xe2\x81&-''Y\xb7\"\xdf\xb3\x80\n\x7f\xcfl\xb9\xcd\x81S\xc8\xa3/\xfa\x117\x99$\x87NX\x9a\x87\xd0\xd2\xf7\x19I\x9a\xa1\xb54\x7fF\x1cZc\xf3\x0b\xb1\xdf\x0d\xc1~\xba\x10\xf7vj\xd4E\x08\x81\xdb\xe4\x03\xe3bX!\xf9\x17\xa2_\"W\x87\xf8\xb4\x00$\xc6\x95r\xba\xe8\x9fn\x0f\xdc\xb7\x8fJ\xf9\x07\xa7\xdb\x03<\x1b\xb9\x80\x0d\x0e#%9\x1b\x90K\xd2\x07\xf2\x14\x95\x92-!?9\xeb8\xa6$\x9fs\x87w8\x976\xf2UU0\xeb\xaa\x84\xf4#pK\xd5(X\xce\x17\xb7\xcb\x06\xc1rG\xd3\xaf\xb3 \xc8\x8b\x9a\"-\x12\xbf\xa3\x9a\x8c\xfb?x;\x16\xb2\x83\x15\xb8a\xf8\x0f1_\x7f\xa90d#\x18\xaf\x023\x9b\xbfY\xa4\xcb'\xd7\xa6JG\x15E\xe6\xdb]\x1e5\xd3S\x94\x06tM\x7f2\x1dR\xec\xca\xdcb\xc94!\xfa]\xcc\xd2?\xc4\xe2\xf7to)\xf6\x1f\xf9\xefb\xa1\xad\xd3Z\xb2\x7f!\xbee4\x15\x7f\x8c\x98\xe9q\xa5\x8c\x9f~S\x9b\xcc\x9c\x92\xf5]\xe7\xf1\xce\x13\x89r'\xba,\xd7\xea\x82\xd3](\xce\xeb`~\xb6,\x1f\xac\xb6J\xf1\xbd\x1f\xe9\x9e\xa6\x1e\xf7\x131Cg=0\xce\xbd\xfd\xaa\x9c\xd8\xa5G\x87\x86\xbe\xa3\x89\xa0\x9d\xf1\x13\x86\x8e\xe7\xd5\xfa\x07\xfb\x00\xc7:@\x9fw89c\x13A\xdb\x1avO\\\xded\xbbA^\xc7\x82\x87\x81\x7f\x827&NL\x0f\x9aWQ\xcdW\xac\xf99\x91\xa7\x0d\x05\xbb\xa0\x92\x01\xf3\x84\xd9\xf1m#Q\xcd\xc09\x88$\n#P\xf8\x08\n\xf9Q\xf6\xcf]\x06\xef\x01\xc7\xbc\xaf\x8abS\xd7C\xae\xc2\xbe\x18Jv\x84-7\xf5=\x06\xc2\xa2\xc1\xa6\xb3T\xe3<\xc1\x8e\xc3q\xf6W\x98\xc5\x8fs\xe6\x87\x1ej;\x8e\xc2W\xb8\x7f\xe9Zy\xbe\x1f\xecX\x7fq\x94\xbb6R\xf4g\xfb\xc0\x06\x1f\x80A\x0d\x8d4\xce\xa7\xde\x8a\xfd-fT\xef\xd5\xba\xce\xe9\xeb\xf2\xd6\xaek3E\x0d\x00\x96\xed\xd8\xde\x83\xe6\xd88N\xd3\x0d\x82\xe74;\xe1\x0f\x87\xe2\xb8\x89\xef\xfd\xa6k\x93\x8dh\xf0'\xfe\x80E\x9d\xf1\x00\xf7S\xb9\xc2\x13\xc6\xc3(\x8d\xfb\xa8\x00\xbe>uY\xc3VX\x91\xad\xa2A\x1e5\xf9\xbf\xe3,a\xd1\x9a\xad?\x96\xedI\xc6;S\x99?\xf1.4\xa6tO'\xe3\x0dJ\xa2\"\xb6:\xf7\xb8V\x80\xacn\x9ak\x1f\xec\x90\x94}\xc3d0\xa5=\xed+\x10\xcc\xbdGM\x05!\xf4}G\xaf \x0f\\*\xd0\xb2qv\x9e\xfb\xf4~D\xc3\xe4\x02\xe21=\xeav\xcd\xea\xd85R\xbd6\x05\xed?tN\x8c\xbe\xae\xa8P(\xe7\xc3\x05\xd1\x07\xe7XU\xb5\x83\xa3\xf8\x9f\xcc\x12\xc2\x12\xf6#^`}\xcd\xa9\x1f\xf8\xd1\xf6\x87\x80B\xcc\xf6.\xe3S\xae\xb6\x8bl\xe4V\xd1\x97\x17\xb7\xdb\xe1zS\xf3\xeeAy8,Nb\xd1\x19$\xc7X\x1e\x01J\xef\xb4M\xe1Q\xd4\xe0\x1a\x87\xab\xe3i'/F\x8a\xfa\xda\x94\xf7#\xedh\x11c$\xf16?\xa5\x1a\xb0x\x92\xfb\xe5\x84\xbb\xc0\xf9`\xbc7\xbeeFd\xbe\xc4(>\xfd\xa2\xdbx\x1d\x8a\xeaC\xa3a\x1b\x8c\xc8<\x0fa\xde\x1b\x91\x1e\x04\xa4\x86\xf02\xea-\xf0S\xd1s\x85(\x9d\x973Bm\x9f\x7f@m;\xaek9?\xfb\x80Z\xe0\x93\xaeg\xdaZ\x8f\xbb\xbc \xcbm\xea8\xaf\xd4\xd1\x00;\xa3k?\xda\x9aBO\x1f\xd0pP\xa9\xe3\x99{\xf6v\"\x0c\xa0.\x93\xef\xf9\x03\xda\x12t\x15\xd8\x1e~\xda\xa9\x87k\xb6)\x0em\x15m\xdc\x85\x8aPA\xb1\xcf+\x81\x0d\x97\xee\x98x\xd5\x05\x8a\x14<\x0b\xacW\xb6\x8a\xcb){\xdd\x81\xa1\x1b\x1bF.\x89o\xaf)\xb0\xe1pP\xa8BG\x92\x9f\xb3%\xc4\xe7\x82\x87\xe9\xd2%\x8e\xd1@\xcc\x08\xe6<\x87\xf3\x85\xf9r\xa0\xa9\xd2\xa0BzrJa\x9fh\xc1\xad\x11\x04\x82\xf0\xdf\xb1\xaa\x835\x87\xe6\xcd\xf6E{\xfb-\x00\xbee\xe2\xfb,`)\x1e\xa3\xa3\xa3\x04\xec$\xbaH\x10\xe8\x10\xe1dzA(\xb9\xd4GHl\x12\xf8\x91j\x98\"Q\xbd\xf1\x93\xaf\xc2D\xdc\x7f\xebG,\xedS\x08m@\xc9\xcb+\x12\xa1\x17\xfe\x93>\x9b\x88\x1fv\xfeF\xcc\xe9\x12\xae\xdb\xac\x82\x9bo\xa25\x8b\x84\xfb\xfa\x13\x00\xccq\xe0\xe1F\x08\xd4\x12\xcf\xf9Ru\x91\xc2\xf1\xe6\xc9tpA\xf8p\xe8\x90\x130\xea\x85\xf0\xb7;\xa1`\xcfF\x84M\xfc\x14@4\xb0[\xbe\x90\x19\xb9\xaa\x8f\x9dQ_\x07\xa6\xa7y1\xda\xa86W\x8da%#2\x1c\xdaAB\xaa\xa1\xb9RB9\x8b@\xe8\xad\xd7\xda\x12\x0e&\x1f\xe7\xda\xe7\n\x9f\xcaq\xa5\xcc\x0420S]D\x0bQ\x8b%\x99\x82q*W\x1f\xb3\xb3\xb3\xcf\x9e/\xe5|\x91\x9d?;\x7f\xb6\xc8\xce\xcf\xce?\xd3\x89\xd5R\x01\x94\xca\xce\xce\xe8\xd9i!,X\x111\xe1\x8e\x91\x03+G\x84W\xc7P\x81\xe8#\xa2\xb9<)\x03\x02\x94\x92\xe1>>\xb3\xc7\x02\xd5\x9b\xf3\xc0\xe55\xab7\xc2I0\x02'\x10\xb98\x9b\x8eHo\x11\xa9\x14\xabU\\\x88\xde \x8f^W.\x9f\x15\x18p\x93Z\x1b\xd6V}\x0e5\x94\xd3\xb3\x82p\xf2e\xbcf_\x88~4 \xd7:,,F\xf9\xf3t<\x14\x08\xfe\xa6P\xbf\xa7j\xe8i\xda\x00\xee\x85)\x19\x13o@\xfe\x89<3\xc7\xb5\x90\x08\xc5y\x95z\xe8\xd5\x8c>\x15\x99\xf1\x07k\xe6\xc1\xdc\xab\xd54\xa4\xef\x8f\x14q\xf3#f\xfe\xbe\xa2w\x05\x024*\x05\xb4Al\x1fz\x1epZ\x86U?@e\x18kM\x9a\xeb\xae\xae\x96\xab\xdf\x8a\x00\x9c\x0dj\xa8X\xac;\xdf7\xfd\xaa\x0e\x08/\xbaUD\x1e\xd6\x1a<\xa0\xb8Y\xc7\xfa\xe7li\xd5`(\x11\xb0\xa5\xa2\xbc\x85.\x14=\x9f\xbd\x1f\x95\xda,K\x1a\xadM\xd7]\xda\xeb\xfe\xa2(\x87g\x8f\xfdC\x90]V\x00\x1b\xa0\xe8w\xe1\xea%k\x83\xfa\x87\x84zGC\x9cr/\x978\x0d\xd0z\x15\xd9\x0c\x85%\xc8\x1e\x0c\xde\x97;\xca\xd3C\xaezKn1\x9d\x00F\xf6\xe4\xa9\x06\x19\x02\xfdA\xf0\xfd\x96z5w\xc2\x0e\x86\x0c\xd2\x1f\xb9\x04\x97\xf8\xa6n\x07\xdfP\x10\xbf$\x91#b/Z\xaa\x9d4\x0c\xf2x\xccr\xbb\x04\xa6\x96\xedq\xdd\xd92Q\xc7\xdeV \xa9j\x19\xa98]],b\xb0\x8c\x1a=\x14\xa9,\x81\x82\xb6\xe2\x92\xd4/\xaf\xffy\xa0V\x01F5\xf0\xf1\x10\xce,\x87`9\x02\xb7\xad\x8acpr]Z\x19Pjj\x1c\xc1\xdb\xc4Q>\x82(\xc7\xa8~\x0c\x1c\x93\x91iQ\x05|\xb7\xf6\x05\x19\x83\xe1\xac\xf6 \x1a(\xd4\xbf \x81\xa2\xbc\xf1p8\x80\x88ne\xc8\x06j*Ax\x03&?\x18\x01\x07;\xb3)gZ\x1c\xaa\xf54\xc5\xfe\xe0\xc8\xa8\x15&e\xf7\xcee\xf3xY\\\n\x8d}\xd4c\x9d\xd5}UUD+\xb4\x8d;J\xb42\xa9\xee\x90\x83\xee%b\xf6\x82\x0e,2c*\x96j\x12\n\"\xcd%y\x96\x9b\xe3L\x1ds\x18\x03^\\\x81\x8f\x9a)\xee\xdb\x9aVW\xbe\x03\xe2j-\xb9x~\x8b\xdd\x1fl\x02rHy\x15\xd2\x97W\xe4Y\xfb\xc6J\x81:\x1c\x1er\x06k\xf5\x9cZ\x86\xe3\xa3<\xf6{C\x8c*\x1d\x8b\nUf\xb5\xaf6\xe6TN\x05\xd4\x96\"\x1e\x91g\xe0\xe8\xc5va\x04[\xd2ZyP\xc2\xb8\xaf'*\x10\xd3\x19\x99\x8b\x91\x86\xd7\xa1<\xd1\xe1\xab\x18\xca\x8c\xa5\xcf\xef\x95\xf0\x96\x8bI\xef\x7f\x194\xecN\xdf\\\xc7F\xe8|C/^\xb1\x84\x11\xb3\xc8Z\xcf\xbe\x81\xec\xccd\xaf\xa3\xbaG\x86\xe4)yI6\x8dh\xadrM\xcf_\xa0\xd7\x96\x18u\x1def\xe0\xa1\x82\xe3s\xcc\x13\xb7\xd6\x04\x92\xf7\x08%\xe7\xbeg5'\xc0\xda\xfa\x9e\xda\x03\x0d\xc8\x98\xa4\x03rI\x9e\xb6V\xa45\x159\xc5\x01C\xf9\x89\xe0~\xd8/\xeej\xff\xac7\xb5\xad\x95\xf1\x82\x8d]\x03a\x16\x17\xe4\xa4?\x1cf\xa8\xd1A\xc1 :\x90\x16g$+\xcdH\xb6\x04\x9b\xbe\xd2$\xa84P\x7f\xd8<5]P\x03\xb5\xa8\x8d:0\xb1\xb8\xa2[\xca\\\x84\x00\x04\xf8\xe6\xd1\x06\xe5R9\x0b\x8aj0\xb5\x10\xb0\xbe\x81\n\x01\x9a\x9e\xb9\xe9\x0b\x90\x9en\xd4\xc5\x87vs<\xce\xc9MF\x86\x8ae_\x03\xeb\x81\x93\xbfn\xc4\x07\x94\xf1\x0e\xea\x93PN\xc3tFhG\xc2\x84\x8a\x85\x0c\x16\xa7\x93\x1c\xfd{\xa29\xf5\xb0\xbb\xc7Q\x9b\xf0\x10\xb5\xd9\x93\x97$l]\x89/\xce\xb5\xb1[\x05\xdb\xf7\xc3\xe1\xa0\xb5\xa0\x1e\\\x85\xeey\xac\xdf\x90\xde\xfd\x81\xa5\xc2\x8f\xb6\x1f\xb2\xfc\xf5f\xa3\x0e\x13\xac\xe4\xbd\x92\xc84\x11\xc8Y\x17\xab\xeaA \xeaaa,\x01\xc9\xf3\x91\xbd\"{\x14\xce X\xed\x9e\\\x92\x10\xc2\x11\x15\xd6\xe2~@fd\x0f\xd4,D\x81m^\x98\x0d\xa8/\x17[T\x1d\xe3b\x0b#\xcd\x0bP-TS|\x17\x8e6\x8cO)\x94`b\xb3\xa39\xe9\xf7K\xe8\x10\x97\xd0!^\x02`\xfd\x12\n\xc4\xcb\xc1\x00\x03\xa09IZ\xfb\\7\x8b=~\xabXc\x03+\x9fLGpW\xe7\x0c\xaf\xa6l\xec&-!\x97d}A\x92C\xb1\x0b6\xf3d\xa9/eE\xb0\xfa\xdbt6\x04\xaeA4SC\xf3sSE\xf3k\xf6\xd0\xb5k\xedtf\\\xfd\xdb\xc9Q{\x14\x93\x98\xcf\xd1\xa88c\xa0A{\xfa\xf4\xd3:\x8dF\xc1\xb3\x03\xde;\xdb-\xa2\xc8\xf1x}\x18\xe8\x12f\xc7K\xc7\x8a\x0dH\xf9\xc0aT>~\xb8\xaa\x9c{v\xe4)y\x99\xa6\xa0\xc1\x9a\x19@\x84g1\".wue^P \xed\xfb~0\xca\x97\xa8\xd5K#\x11\x8f\xbb3\xbf\x02\xa0M\xf1om\x9c\xdb&\xa6T\x190\xc5\x1b\xe6\xd3\xa5=\x1d\xd2K\x0b\x17\x13\xcd\x97\x16F\xac\xd6s\x93\x90!\x01Z\x94\xcd\x93\"}\xb2\xe9t\x9e,\xdd\x8a\x83\x12\xf9L\xff.xd\x99\x17:\x0cJ\x0eq\xbf~F\x86%9Gm\xd8\xd3V\xce\xf4\xec\xbcE\xee\xce\x80N>zD\x9e=G\xc9\x1b\xa4\xf0\xe7\x07\xa4pX jEN/HF.I\xea<|\xac\x88\xd8\xb5Vm{O\x11B\xda\xd8\x1e\x01\xbfrVT\xf5\xab(\xef\x9a\xfe\x93\xbe\x8f\x1b\x80G\x8fH\xff\xe4\x84k\xbb\x10-\x13j\xa1\xac\xe3b\xd8\xf1\xe6\x85\xfaaR\xdb\xa0z:}\x14N\xda\xe4\xcai\x90\x0b \xf5\xf9\x90s\xa9\xf4y\x9b\x90\x86\\9.\xa3\xe6\x80\\\x93\xb1\x12\xa8\x0dzE\xae\x89\xe6\x15\xf4\x02)\xe0\xd9S\xfd\xack\xe0\xe4\xb2\x84\x07\xf5Zlc\xbc0Z\xf5\xce\xc7\xad\x9d?N\x0e\x8d\x0f\xadD\xf0\x83\xa8F&_&c\xd7\x1e\xb3e\\.\xc9\xb3\xcf\x14ZF\xe4%y\xfeic5\xa8em\\b\xbc\x1d\x08b\x15=m\xa0\xa8\x1d\xdegj\x0e\"ry\xa5\x80i\x13\x9e\x9e\xa1\xee3R\xb0?{a\xa2\xa6\xb6\x88\x16\x16\xb4\xda\xd7\xa6\xe3\xf7B\xa9\x07\xa2\x87yj\xa7\xd7\xb534p\x87\xd9\xb2\x9b\x19)\x01c;\"\xf7#\xb2\x1a\x91\xb7#r;\"_\x8d\xc8\xdd\x88\xfc0\"_\x8e\xc8\xcd\x88|\xe1\x10\xe1\x00\x15\x94\x08\xa9q\xd4(\x14\xb6\x8e\xbc\x0d\x1a;=\x89\xaa\x12^\xaa\xa4\x95lB\x03\xd3\x96Q\xfe\xd0\x8dO\xe8B\xaa\xb5\xbe\xcf\xed\xb7\xef\x8aV\xb8gG\x12l\xace\xb6\xe4\x1a\xef\x017\xafV\xd8T\xa2\xffj\xad\xd4\xd07\xca\xd5<\x911I\xf0~fg\xfa\x1e\xf35\xe3l\xfd6\xf0S\xd1$\x97A\x9e\x19\xd972\x82\xdb\x87KlJz\xed\x08\xea*\x0b\x02&Z!\xfdpx\xac\xc9\xd2[\xbd\x07\xbak\xdb\xf7\x81\x81\xce\xe0\x82\x9c\xf4O\xfa`\xb6\x836\x98\xb0\x81\xea\xdfW\xd5AkD[K[\xe9Rkf\xee\xc9\x98\xac\x958\xf3\x0cX\xb6*\xadPhG.\xc9\xb4\x94\xa2\xa4\xa8uQ~\xa7\n?v\x9dg\x1b\xc6\xce\x17,<0\x80_}\xc8\x00\x06\xd5\xdd<\xea\xc5\xc0H\xc1\xec\xf5\x0b\x08\xbdq\xec6\x8a;\xf1\xfb\xeaN\xbc,\xdd\x82e\x965\x808\xab\xefU\xb4}`\xd3\xc6\x00\xf7\xa6y%j\xaf\xfe\x16f\x11\x88\x99\x1a\xf5\xb7Vn'c\"\xc8K\x9c\x14\xa7=X\x15\xba\xa0\xda\x9b\xb4\x08\xaeW\x83v\xf3\x80\xa9|\xf0&\x050\xbd\xb0'\xf9\n\xb7(tD\xee+\xd2:\xd1\xa6xj\\\x8a\xa6g\xf8~\xbc]\xde\x8d^\\?\xa0\x82\xe1KrE\xee\xec.\xe8\x07rI\xbe\xbc ?4)\x18\x14\xe9\xbd\x9b\xffP\xb4\xe3kW.\xdc\x1cP,4+\x15\xea\n\x05\xd5\xf8M#\xc7W_\xb7m\xf2C\xce\x08)HAg\x83&Eo\xeev#\xe7{\xe52\xee\xe6C\xb7\xa4\xb0\xd6\xf7\xf6\xeb\xad5\x1cXuAB\xc5\xaf\xca\x1c\x04q\x91T\xa8\xf5\x831\xf4\xd6bdn\xc7\xa8\xa4\x8cG\x8f\xda\xcd\x0cHY\xf2G\x1c\x07>?$\xe7\xf5q\x03\x9c\x8c\xf4\xde\xe8\xdc\x08\xcc%\xe6L\xc6\xe4\xbc\x14\xb7\xd3f\x98GKcAevi\xb9\x851\xd2Y\xad\x08\xca\xf3\x0bm\xc6\xd9\xcf\x13U\xcb\xcb\n!+\x14(\xa4G\xe8\xd8\xbc1k\x97\x82\xa1\x7fO\x9b\x8bv$\x08\x99\xb6g\x1b\x92sT+\xf43\xb3\x0b\xf4\x14\x17x\xfe\x99{\x08\x87\xc3lPVDd\xc3\xa1\xc2m\x16\xed'\xe6VCjn\xae\x94\xd2 \\c-\xeb\x84\xb3\x8d3?~\xd0\x85R+\x9a\xe3\xf1f\x80\x0b;S\xcb\xb8\xa1\xcey\x0f\xae\xf0\xa6Km\x1a\xd9\x8d\x04\xda\x9b\x19o9\xdb0\xce\"\xafY\xbdIW\x8a\xda9\xe2\xe1\x1f\x14\xa9\xe2*?\xae\x1d\xf9\xd1\x03RTI\x10\xcd\x06d\x8c\x82S\xf1\x08%+\x0b/\xc3+\xf2\xac.M\x15.\xa2\x14\x1b(1~C\xd9\xec\xd7\xe1U\xedx\xc7\xb6;.}k\xd1\xe0\xe6\x82Z \"Z\x86z\xac\xa1.\xf6\xdd\xaf\xf64\xfe\x90\xd9}03SR\xca\x07\xe9\xbcL\xea\x07Q\xe7\xe3\xe8\xf2A\xad,\x9c\xe8\xb7ka\x9f>o\xd3\xc2\xe2\xb5\xb5\x03\xd5\xe4ZW\xb3\x16\x1cd\xe6\x82<}\x9e\xf3`P\xce\x82\xca\x94\\^\x91\x17\x17\x03\xe2\x83\xf1Wci\x17\xd5;\xe9\xfb\xe4%y\x81\x10\xea\xfa\xb4.&.S\xb5\xd4\xae1kg\xd8OG\xe4\xa9\":\xf9\xcd\x90\xfa\xf7\xe7\xea\xbb\xda\xfae$7\xcc\xac\x01H\xf3\xcb&`=?(\x08DG\xeas\xf1:W\x13\x8d\xda}\x8bX\xec\xb8\xc9\xfd\x11\x94\xbev\x0c;\x02\xebG\xaa\x9dv+\xa8\x9c\xc6CH\x1fm\xc2r\x084\x18\xb3\x07u\xd1\xdb\xf9\xc1\x1a\x1ci\xcd\x97\xb5\x0ev\xec\x97\x99\x84&R\xd26\x0b\xbf\xacZ\xdd\xa4>\xc4\x12pd\xee\xe1\x88F\x8bV{\xa7K\xcb\x10\xcd{GG\x86\x8aa\x8e=\xe0\xe8\xf7K\xec\x91\x96\x88\x1a\xd5:|\xbfH\xc8\xe8R\xcb$\xfdg\xcf\xf3\x8b\xb8\xb5U\x17#mz\x81:_\x8eE\xe2\xf2B\xee\xc7x\x17\xc6BQ`\xb31l\xd7\xfcb\xb9F\xb5^\xe1>\xdc/\xb0\x9cM\x17\xb4\xbe\xe9\xfca\xa8\x7f\x00\xf7:\x82|\xdc\xa2\x06V\x9d\x1f\xbd|\xdc\xe5\xad\xa8\xea\xbf\xf2\x12\xef03\x87W\xfc\xe0# \x16\x85;\xdfg\xe7\xd5\xbb\xdd\n\x81O\xdf\\\xf6\xe7:x\x9fvu=_\xa4\x8b\xd3\x97U\xd7n>f^\x9c:\xb2\xbf\\\x9ev#4#B]\xb4&?\xa0\xa8H\xc5\xb5\xa1\xab\xd8o\xd63$e1\xba.\xbbxJvMF\xe4$\xdf\xdc\xedD\x18\xb4\xca;\x89\xa2M\x8apx\xb0[zyu\xc0<\xf4\xc5\x99{\xeb\xe4\xb5\xef<\x9f\xe2\xa6\xae\x9f\xb9H\x97\xa7w\xae\x8a|a\xbe\xaci_Y8{._rz\xdfv\x1c\xf3\xecS\x00\x1a\xa4\x96\x93\x96\x1b)\xe6g.\xa5<='\xb2z\xf5\xc0\xfc4\x18`t\xf9\xf9\xa7\xaaf\xa1d\xb7\xe9\xf9y-\xfb\xfb.\xdb\xdeg\x9f6\xf7\x9c\xd8c\xa5\xeaV\x11-a\xd1\x95\x9e?(\xb6R\x87\"W\xd2\xb5\xd7\x13\x0f\x0eC{\x82h\xc0\xe7\xe9|Zq\xd6\xb7o\x0b\xd5m\xfcm\xc6\xa1U\xb5\xb3e\x1c\x9fx\xa8\xfe\xee\xa6\xf0\xef9\xfc\xfb\x14\xfe}\x06\xff>\x87\x7f_\xc0\xbf\x8c\xae\xb1\xd4\xce\xc2\x03\x1e2z\xfe\x86\xd3P\xbb\xc1P\xff\x86\x14>\xc6\xe0\xd9\x0f\x9e\x00\xd28\x13I\x06\xef\xf09A`\x12\x1eo9K\xa1\xf3\xe8b\x12\x9e\x98g\xe0N\xc5=\x8e\xa6\xf1\x11\xd1\x13f\xd8\x04tY\xb0;A9\xa3\xf0\xbc\xc1\x0b\xaf=\x01~'\x04\xc7gF!g\x06p\xec\xfd5\x8b{\xcb\xc9&\xe6_Qo\xd7o\xb9\x808g\xcb\xf2\x0dP\xad\x95\xfa\x90\x1b76\xb9\x8b\xf9\x8aCr\xcc\x95)\xb5u\xc0\xdb\xb6\xecv\xf9\x16N\x8e\xc1BdL\"\x97\xb7\x88v\xf6\xdc\xf5\xcau\xd1\x8a\xa0\xce\xc8\x04\xb2\xc9\xc2];\x17\xbb\x0bJ[]\xe4\xd8Am\xd7\xd0RA\xbf\xa4\xfa\x08J\x12x\xb0,\x9f\xcc\x06\xcd\x14\xd7\x87\x0b\x1d\xa80\xd6\xbb\n\x87J#\xb7\xfb\x81\x1b\xbfZ;\xea\xb7\xd6J\xady\x030\xef\x1199}3\x1f\xcf$Y\x0e?9EW\x9b\xb4]$\x80\x1b\x08\x14C\xa9\xf6{\xb2\xa7\xf6\x1f\x10\x03\xb5M\xad\x92\xe8\xeb\xe7)Z$\xa6\xe4\x92\xe472[no\x9f\xc0\xb9\x947O\x97\xe6\xdaH\x1b\x9fE\xff\x05\xa0\xb8M\xe1\xd1+\xb9W2\xd7\xb2[\x05\x83\x83\xde\x98\x89\x01\xed\xf4\xcd\xecz<\x9c]\x9bq[\xb7\xb3\xdf\xe7\x9f\x01H\xeb\xd2\x81Y \xbek\x92 {se=S\xdf{\x18b\x0b\xce\xbe\xb8\xbf\xdd\x89\xde\x80\xcc\x9c5\x9f\x15\xaa\xeb\x05l\x839MB\xaf\xed\x06\xb7\xea\xdc\x18w\x0c\x05tq\xdc\xdb\x81\xb9o\xc1\x14D\x14\xeb\x9d\xed\xcdB\xca\x85\xfc\x04\xfc\xb3\xf5\x06\x05\x04\x1a\x91\xc4\x8c\xc3Ia\xd2Z\xeb\x8e\xdb-_:\x8a\x0b@\xe8\x0f\x98)\xec>\xc4L\xa1+\x1c\x8ao\x1c\x80C\xc1\x00\x8b\xf6\x97\x84\x83\xff\x92@4/\xfe\xae\xe0\xed\x9a\xc0\xa3\x81\xbf\x8df$\x99\xa7.\xc0>\x02\xec\x1d!<\xacw(\xd0\xb2\x8f\x00\xe9/\xa3W\x10\xbb\x87\x1e@|\xc0R\xe4\x0fm\xf3\x88n\xa9U\xf6\x8b\xb7\xa2d\xc6\x03\xcbh\x0f4\x05\x8f\x0b\x1fDW\x8c\xa0r\x8e\xdb+}\xfb\xa7Efy\xf4\xc88)\xcfiz\xe0\xa6\xe9p\x83\xbd\xd1\xaa\xa6;Q?4^\xa4\x0b\xdd!\x87F\x83|0q!\x058\x1a\x8909DdHW@7F\xa0\xc9\xc3\xf3+Q\x0f\xc4\x15\x95\\e\xe2p\xabrD\x9a\xf2\xc0{Y\x8a\xa8$\x91Y1\xc5j7\x8f\x19\x97F\xb2F\x8a\xa4\xad!\x8a\xca!\x8aE\xda\xa8\x16\xe9\xb8\xf8Hi\x12\x9b\xd689\xb4\xce\x89\x83\x8a\x11\xd8\xa2to\xbe\x99\x90\x91n\xcd\x97W{\xe9\xcdn\xad\x8e E\xbf8\xc1\x03!\xea\xc1\xad\xec\xd0\xfcj\x8f\x7f\x82QI\xed\xf3a\xea\x13\x9b\xdce\x03\\\xb0\xe2\xea|r\xedw\xd8\x06\xc7j\xd3\xe7\x1b\x13z{M\xdf}\x18d\xees\xe8\xbd\x1c7\xc5b\x14\xc7#\xd7\xe9\x8f\xce\x12\x95\xda\x89*\xe3F~\x91}\xb6\xb5\xd6o\x15\xd0\xfb,\xf7\x08\x06\x96\x85\x8f\x1e\xd9\x89x\xe9t\x9d\xb7)\xee\xc3\x8d\xaep\x03\x05\x87\xc3\xcd\xc1m\xbc\x9d\xb3\xcdQ{w\xdf0\xc6\x8d1\x81lm\x03\xd0\xf9h\x9b,m\xa7\\4\xfb\xeb\xbc\xd2\xd6\xc1\x01\xb9\"\xf8\x90\xbdJ\x866\xe9J<\xa8\xf8\xafc\xb3\xb6K2\xf0\xe9^\xdb\x0dn\xb5\xd1\xed\xa1\x1e\x91B\xaf\x1a-\xedIA$\xceF$\xfb\x10\xb6{\x04@\xdd\xb8]A\x03\xac`3\xd8Z\xf4\x8d2m>J$\x1d\x8f\x13I\xb7!\xf8\x98\xfcs\xddlKK\x0e\x11t\x82\xfc\xd3\x89'$_\x9d\x07A!\x05pZe2\x92\x8f\x8f\"k\xf3\x8d\x1b\xf9m\xd6C\xa8B\xf4x\xe1\xb5\x1b}\x9d`\x0d/\x86\x86\x8d\xf4\x89^a\xa6\xf7\xc5#>\xba\x1c\x81\xd2\xa0j)W4\xd9gE\x1f\x89E\xfb\x03\xd8\x12\x14\x13\x14M/\xdd\xc5\x18\x91\xf6\xab\x08\xb9\xb7b\xa7\x91\x1bu\xdfF\xd8\x82\x81\xd1\xbd\xb9\x8d\xb0\x05\xb0\xf4\xf15=x\x1b\xa1\x08\xee\xbe\x08`X\x83oW\x1d\x8adT\x1e\x8du7d%%\x0ciCX\xd2\x05i\x89\xd9F\xa0\x18\xb2\xb1\xfdW\x02\xfb\xcb\xfc\x02^\xd3\xb1\xe2\x01\xb6s\xb0\xac\x83\xf9\xb4\\\xf8\x03\x1a]_x\xb5\x14\xe4\xa5/\xdb\xee\x0f\xfa\xda-\xf0\xa6\xc8j\xb3f\xb7T\xa5\x8e\xd6<\xe3\xb4\x95\x82\x8d'\xd0\xc9\xc1a\x90J\x17@\x1e=\"t8\xcc/\x88t\x01\xadn\xec\xd3\x06\x9a\xef\xbe\xfdP\xca\xfc!\x92\xf8:x\xb8\x80\x1ch\x94,H\xc6\x9b\x11\xb9\xff\xc7\xfd\x04\xe7\xfd\x04\xef\xa3\x1d\xba6\x8a\xcb-\xdb\x87\xe2\xfd\x04\xb7\x91\x9a\x0f\x1e\xb6.\x8d,\xaf\x8f\xc5\x07\x95s\xf1\xd4\x11=\xceZ\xf37\xde\x14\xcc}\xce\x0fP\x13\x12\xd5\xaaE\x9dH#\x19*\xe8\x90R\x971\\\xdb\x0d(\xeb\\O\xc9\x7f>^\xba\x82%o\xd51>\xb9$\xf4\x82\xf8m^]\x88\xa1Is\x1f._\xa5]._\x99_\xdc\xc1\xbb\x0b9\xe8\xe1\x858i\xa9\xf9\xe9\xcdM\xd7\xfb\\\x9aN\xe0j*\xda\x0c\xa4\xcd\xd2b\xbe\xd0\xd3\x11\xe1f\xf1\x15\x97\xca\x01rSYzu\xa2\x03K\xc9\x1d\xf5\xa8\x8b\x19DY\x8c\xaaQ\xac\x8eP\x1eV\x96\xf3CMw\xb4\xc1\xfb\x85\xec\xef\xf2an\"\xeem\xe3\xdc6\x86\x1f\x8d\x88\x1d\x8e\xb0r\xfe\xf4\xb9#\xc0J\xd4?\xff\xb4\x92L\x1b\xe2\xae\x08vgbc<\x9d\xba#wD\xec\x16\xa7\x1as\x9d\xbbs\xb1\xd4\xa3\x89\xcd\xf4\xd4\x9diE\xbd\x1b\xe1{7&\x8a\xcb\xd3\x86`!k\x16\x98\x1c\xcf\xdd9\xfc\xc8\xd6\xf1\xc2\x9d#\xa4\xdc\xc4\x1ay\xda\x10Q\x86\x85\xc9\x8e\xa6\xbe\xad\xe93w\xb64[\x99\x1c\x9f7\xe5Ht\x8egg\xee\x1c\x81\x1f\xd9^?k\x18h{\x95\xc4\xac-\xcc\xdd0\xe0\xc5\x8b'&k\xc3\xb0S\x1d\x1e\xc8dk \xd1\"\xa8 \xe4\xf2\xaca\\Y$|qo2}\xd6%0J\xf6Q\x02\xa3\xe4^\x90\x9c\x81Q\xa8 \x8cB10JE\x11\x0c\xd9\xf7\x18\x81\x99}\xebG7\x8a@\x17\x16i\x1d\xea\xb4n\xe9\xb3\xb7\x81t\x91\xd8\xb7E\xcc\xd5\xbc\xc3\x1c\xc6\xabb\xbe9z\xf9J\x8d\xa1\xafXI\xf1\xf8f\xd63\xf1hU\x89\xb9\x0d\xa6\xdb\x1b\x15\xe3\xed\xf6\xc0H\x0bM\x9c\xd6T\xd0\xde\xd2\xd6 \xcc\x11\xce\xac7\x98\x9f-]\xe6:Y\xc5\xe7\xf5kE*[=\x86C\x9fG\xc6KLa\xd4KQ]j\x88\x02\x8ez\x8d\x8e\xac\xf6\x15u\xafI\x9c:4y([y\xd4\xdb\xb1\x7ff\xa2\xef\xc3\xe5\x97\xb3\x01\xe6W\xe8R\xd1o\xb9MP1l\x03b\x8f \x97$\xbe \xa2Mx\xe2s\x01\"\xcbI\xc1g\x08\x04\xe2\xd2\xa0\xfc\xa0@\x19!\x10\xce3\x86$N\xf1\xdeb={)w>\x17\xefG\xa5\xe90\x1b\xfd\x8e\xfe\xdb\x0fNIy\n\xf2!G\xf7\xf40\x98\x97\xc4o\xd6\nF8x\x91q1s\x02\xc3\xc9\xe7\x11\x8e\xd3t0\xc0}\x84{W\xd6\x18\xe8\x187z\xaa\xf5\x97`\xef\xd4z\xbb\x9dM\x12\x16\xad\xfdh\x8b7\x04S\xee\xcd\xf5H/\x1b\x06\x95\xe0d\xe8R\xa0\xf7P\xe4\xe1;L\xe8\x0f\x9aF\xff\xd8\x802\xcdaO\x1ct\xc7\xeap\xfcF\xa7\xdc\xd9\xaf\xc8\xb1bB\x9dd\xf1:\xc2\xa4\xb7\xbe\xf0v\xc4mw\xed\xd1\x94\x91\xe9\xd9\xcc\xfd\xe1\xf3\xf3\xa6\x0f/\x1a>m\x1a\xad\xa7\x9f65\xdf4(\xd3\xf3\xc6\x91o\x82\xebE\xd38>w\x8c\n)\x98\xd29vbk\xb6\xa1Y \xda\xcb5\xf9S\xeap\x94\xd5H\xec\"\xcb.\x80\x1c\x192\x06T\x89\xd7]7G\x83\xc1\xc5@\xd1&'G\x8e\xf4e\nE\x82\xd4\xb6L\xe8\xbb\xe2UJ\xa3\xad\xf4!\xa3Z\x87\x83Q\xce\x82\xca\xf6\xe2\x1f \xe2w\x1e\x8b\xaa2\xc8\xc9;\xa7\x0d\x17E\xe2v[?=\xbc\xd8\xff\x82\xf1\x81\xd1#\xe1h\x8f\xc8\x89p;\x9a\x85\xd3\xcb\xb3\xd2\xf5TSYyV\x9c\x88ck\x98\x1e\xacA\xbb(9\xa0\xc6\xb0\xf4\x19U^>\x9eS\x12\x7f<>\xac\xb9\xb0~\xd4\x1c\xcd\xfb\x9d\xd4\x189\"\x15\xab\xc9\xedE\xce\x14+\x1e\x92iC\xe8\xd9\xe2\xefC4\x1d\xec\x90\xfe\x9d\xe4[\xe1\x1d\xe5kh\xabE O\xdaw\xbd\xc5\xdf{\xf70\xd7Xzi|\n1SG\x87\x81\xd7\x80\xa7\xf1F\x1c\x02\xbc\x03\xd0N\xa3\x11\x0d\xeb\xc1\x13\xb7C0\x1ch\xdfiv\x17\x0f\x87\xe8\x19\x9a\x93\x96;\xdf\xb1\xa2rq\xe3\xfd\x1b$U\xf1\xc7RF\xd8\xa5\xc5\xb59\xb8\x0e\x9c\xa2\xc0<\x7f\xfe\x02\xfdP\x13\xbd\x19;+\xf4\xaa\xb7X\x9c,z\xbf\xfe\xe4\x9f\x1e=\xee\x0f\x9e\x0cG\x93\xd3\xd9\xc5\xe5\xd5\xcb\xeb\xdf\xcc\x97o\xde\xfe\xf9g\xf9\xfe?\x8f{f\xe3\xd2\x1bt\xbboQ6\xb4Z\x92\xabb$\xa9\xca\xe5\x8b.d\xd5\xd2\xd4\x96\xad\x8a\x92\x9bk\xa4\xf3\xf3\x06\xbf\x8b\x07(\xeep\x18\xe3\xc5\xdf:j\xf9\x8d\x8e1\xf1\xb6\xf0\xf9\xf3\x17\n)\xcc]\xb0(\xbf\x88\xd0\xc4\xc8\x8c\x8fg\x85\x10\xc3+r>r2w\xcd?\xb4\xc3J7\xca\xebM\x15\xf8\xf4\xea\xb6B\xbb\x90\x96N+\x14\xa2\xf2 \xb6\xf9\xc7/\n\xf3k]\x1c\xb6\xb1_5\xbf5\x0fuo\xb1\xe8\x99aV\x1b\xc1\x8f\xb3\xea\x8eE\xe4\xd29F\xb3\xa0\xa0c\x89\x1c\xe3*\xc8\xee \xb3\x11\x01\x0f=\xbc\xb4\xa1\xcc\x0c\xb5\xfa\xfcE\x93+\xa1\x8b\x81*\xe8\"w\xa4,rE\xe8\x12\xc3\xd7\xc1_\xb3\x0b\xb0\x84\xac\xdc\xa7)D \x81\x93\xbf\xe6\x8d,\x85sx\xb8\xceH\x0fAIU=\xd4\x85>>\\\xc0\x19+\xa8\xae\xf2\x00\xb6\xe5\xc5\xd7\x85_4\x84\xed!\xa4\xd9i\x85_\x08\x93?'\x8bh9\x04\x93]\xd2k7Q1\x91|\x9a,S\x0e1\xa6\\\xde\xa5\xb5u\xd2uU\xc4E\xca\x93G\xfd\xfd;Z\x1cJ\xb2\xadu>m\x91\xb1\xcf\x1b\xd6N\xdaN\xf2\xdb\xed\xd7R\xf4^\x06w\x91[\xb257\xfe\xcb9\"\xf3u \xce\x94\xbc$g\x18\\\xa0\xda6\xd8.\xcf\xc0)\x96\xd3\xa7\xb9\x82\xee|0\x02\x03\xca\xab\x83\xd7\xdcL\xaef\x9f\xe7~\xee\xed\x8c*\x9c\xd3|\xab\xb9\x00\xd0\x01\xaeC`\x9ec\xdc0\xb8\x99n\xda\xaa\x81\xcc\x15!\xa8\x05\x0d\xf3\xd1\xa74T\x93\xc7O\xb2\x08\xce\xc9\x98\xa4\xa3FF\xacWt:\"\x1c\x0f\x89\x1c@\x9a%\x97\xe2A~\x8c\x8e\xe4u\x0b\x10>.k\xf4v\xdd\xd8\x19TC\xb6\xf6\xd7\xb6\x80\xceH\x9c\xf7\x161\x0f\xda\x0dY[Xj\x96\n\\\xd2T\xc3\xea@\x11\x9b\x01\xd1\xc4\x82b\xef?\x9a\x8d\x17\xbc\xd8P\xa8\xd7$\x1e\x8f\xc9\xcc:\xc1/|\x84\xe7\x18\x1d6]\x82\xa7\xe7&\xa1%\xfa\xc0\x18J\x04wSxjou\xe6}\xd6\xc1\xd4;\"\xd7zF1\x06\xaa\xd6%T\xe6\xd8\xa2K\xbb\x15\nk6 m3\x8c{\xef\xf6\x98\xd6\xb6\xcb*\xb4\xf8@\xc3\x97\x02\xef\xb0\xdd\xd7\xd6qv02P\xa2\x90Y\x01\xe7A\xad\xfco\x963h\xdf\xfd\xff*\x8c\xa1\xb1\xed\x7f\x13|\xe1\xd9\xd3\x0elAg\xfa[p\x85g\x0d\xee0\xdb\x98\xc2\xc9\x95\xae\xe7\xef\x8e-4\xf5&\xe7\n\xad9\x8e`\n\x1a\x0b\x1f\xce\x13t\x05\xff` \x9dX\x82\x1f\xa5\x7fc\x96\xa0Z\xfc\x07K\xa8\xfcZX\xc2\x8b\x06w\xc3\x7f\x0b\x96\xd0\xd8\xf6\xbf \x96\xa0\xdd\x9e\xb5\xb3\x04\x9d\xe9o\xc1\x12tS\xffNXBSor\x96\xd0\x9a\xe3\x08\x96\xf0b\xfa\x81,AW\xf0\x0f\x96\xd0\x89%\x84\x94\xdf\xfc\x8dy\x024\xf9o\x8c)\xd8\xe46\xd3 \xb3f\x89\x0d\x00\xc50\x00\x14\xa8\xfaT\xea\x8b\xe76\xf5\xf33\x9b\x8a\x9e\xe9X\xd53\xdd\xd1Q\xb9\n\xfeR\xeb\x03\x9b\xa1-}-=mH\x0fZY\x98\xe7Z\xc6\xc2u4\x85\x97\x0c\x1a\xc8\xbb\xc8\xc9;\xeaZ\x03\x18\x89j6\x8a\xa1\x95=\x97\xaaU\x0f:\xdc\x16\x81\xd2`5\x0f\xf7\x9a\xfa\xa8\x10\x1e\xeb\xab\xa7\xcf\xc85\x8c\x02\xf4x\xaa\xf0\xe3i!\x9a\x1f\xb6\xee\x80\x91\x16U\x10H%bt;o\xda\xd1\xd5D\x85\x1c\x91u\xe1\x0c9>G\xa7\xb0\x1e\xc0\xc7\xfb\xda[\xad\xad\x80\xf7\xe3\xdc\x15\xf3\xc9t\xa0\xd0\xbc\xbe|<\x1a\xc1J\x9d\x91\xcc1!4\xc25\xe5t\x07\xbff\x81\x1f\xa63\xe27\x10\x97\x07\xd8Z\xe4RO\xf5\xdap+\xe2l\x9a\x0f\xce\x12\x17Nm\x06uF\xa9C*&\xb0\x01\xc0\xb1O>@\\\xfb\xbb\xdcW>z\x84\xfd\xd3s\xa4\xbax]7\xb7\xb0\x01\x05\x90\xad\xa3C\xea\xd3\xfe\x1b9\x7f\xb3X,\x07\xfd\xc5b\xb1\x18\x00\x83>9\xcc\xf9U\xb6(?K\xd5\xb1\xf8\x80\xcc\x18s\x08\xe3\xdc\xd4\xde\x07}p\xfc\xe1\xc0O\x9du\xe0\x87+2_\x0e\xcc\xee\xac\xfe\xbd\xe0V\xd4E\x0e\xe2\xc3\xe8Xv\x0cR\xa7\xcb\xeb\x87\x84\x8d\xac\xac\x1b\xdc=\xd6\x1c\xa1\xba\x17S\xbd\x93s\x7f\xa9\x06\xaf\xde\x03\xa8p\x96W\x9d&\xb8\x9d\xa9H\xfe\x95%ZXCqm\x07\x90\xd9\x08x\x1fc1\x1d\xbbhJa/\x9b\x17M\xcbU\x1d\xc5\xba\x9e\x92\x97\x07\x8c\\N\x1c\xf8ZM\x83 \xd6\xad\xb54EGo\xb9\x16\xd4\xa60\xc8~9K#k\xa7\x93\xe5v:\xf4\x82\xf0\xe3\xa3\xa3\xf3\xc3\x81\xd7\xa6\x0d\x02}\x87\xa2M\x81\xd5y\xf7\xc0\xeahG\x04\xfd\xd4\xe4\x8e\xab\xe1B\xd7\x8a}\xae\x96cT\x11k2\xe3\x05\x10\x05#-\x12\xe1\x1c5\xc65\x8f\x96\xcd\xe4\xaf\x1bMk\xaf\xfc\x12D9\xad\xaah%|\x0e\x82\x11\xbb \x86\x8e\x98\x1e\xb9\xb4\x08Y$f\xe4\xacN8\xda`\x84\xa8\xcd3\xe2\x82\xb1\x94\xb1\x99~\xcf\xe3\xe5\x04\xdan\xec\x08~\xd6\xd2\xc7\x87R\xf2\xd8\xc1\x80\xb3\xd57\x0f\xa0\xf1\x05\"\xcaK\x04\x94~\xc4\xc0\xe4\x05Y\xe4\xecY\xd5u\x99\xd1\x99|\xe6\xd0\x99\x14\xe2\x8a\x9e\x8d?\x9f\x9c\x80\xf2\xf4\xc9pqzum\x15\xa6\xc3\xdf\xe49\x96\xfd\xebY\xfe6^\xfe|6z1}_\xf8>\xb8\xee_\xcf\x16\x93\xa3J\x0c\x9e\x0c^\x9e\xd6\xf56\x05\xd8&\x8b\xf1\xf2\xe7\xe9\xe8\xfc\xf9\xfb\xc1\xac?\x7fs\xf9rqwv6^\xdc\x9d\x9f-U\xd9\x87\xf3\x91\x92n\xa7U\xc2z\xd1\xa8}\xd0\xd4\xa3_\xa5\x16\x9b\xa2\x13\xaa\x97\xbd\x82(\x04\xaa\x90H\xab\x0f)\xb8\xab?\xe9s\x9b9\xab\xc5\xa1,\x94U\xbb\xa1l~\xb6\xd4\x8dL\xf5\xd5~\x0f\xac\x08\x02\xb5\xe7:\xb1\x02C\xd1/W?(\x8ba\x1dd\xef\xd6\xfd\xc3\xc1]Be\x1d\x1c^\x96\x02|\xe69(\x8e\xd6[\xba\xc2S\xb2\xaa\xe3\xc3\xa3[\xed\xb2\xcb8\xb0\xb2\x87zF\xf2[\x98\x03E\xedN04i\x94\x874\xb5\x13\x986M`/\xa4~ b \x87m\x93\xe9\xfdc2K\xbf\x8f:\x99iu2?\x0e\x91.\xd2\xa6y\xcf\x8b1N\xe7:\xf6\xeb\x8e\xe8(\xa5\xfa\x0fD\xe6\xa4\xab\x18CwR\x0f\x0b\x99?>\x04\xd6\xf48\xfe\x05\xb7u\xf0\x17#\x94\xfa\x18\xffs\x0d>\x1d\xads\xbb\x8d\x80\xb2[\x16\xc3\x1f\xfdo\xb2\xd3\xd1E\x9f\x9ec\x04R\x81\xd9\xd4_(\xee\xd3;\xf8\xa3\x9b\xf6C\xfcW\xbfE\x1b\xa8\xc7O\xf0\x95\xfb\xa9\xf9;Y1f\x13'w\x89W|\xces\x05\xb7\xef\xd4s\xb0\xc6\nq\x19\xc0\x13\xf6-Lyb\xfeB\xa9P\xfc\x84 Y\xa2V\x85z\x8c\xd8-|\x8a6\xf8\xc7\xc7\x7f!\x16i\x14a\x7f\xe2\x84\xfe\x94\xb1 \xf6n`+\xa4\x92\x92\xd8DD\x85b\\\xa4\xf0\x9e2\xbe\xf7=\x86\x8fij\xe2\xa1\x9a\x81I}\xb6\xc7\x8f\xbe~G\xb8\xd2\x10\xffD!&\xc74\xb1C`_ \x0b\xfa\x84\xec p\xca\xa9\xfeD\x188V\xe8\x19\x12;?\x0dY\x9a\x82\x06\x8a\xf4D\xf4\xf4\xfc\xd33x\xc2\x16\x05\xccr\xc6\x01\xae=\x0bC\xe8/\x0e\xc1-\x86t\xbd\xf3\x10j\xf5w\x9c\xa5L#\xca]\x18\xf0\xc4\xb3`\x15^\xb1T\x88\xd3\xf8\xee\xe9\xe7\x93\xe7g<\x7fDd\\\xfbYx'8b\xe8&\xc1?\xf8 \xb1\x82j$\x16\x82z\xbb\x90E\xf8v\xab\xfe]\xb1tG1\xf4\xec\xca\x17^\xeccX\xde8\x80\xb9\xf6h\xa0g\xdd\xdb\xf1\x18\x83\xda\xe2\xd3\x98\xdd \x16\xa566o8f{\x16\x89\x15\xf7\x05\x1bS!X\xb4f\x98\x1d \x0c<\xee\x01\xa8u\x10\xd1q\x12\xd0\xfb\xd4\x8f\xb6\xda\xbf\xa3IR\xb9\xa9\x1f!\xea\xaf\x05T\xbe\xde\xaf\xd4\x1f\xb6>\xbfQ\x7f7\xd4c\xc2GX6\xcc\x84\xf9\x8d\xb6:\x84\xaf\x9f\x02zma*\xb7\xbe\xc0?\xef\xc28\xe1\xb1 \xc0\xbb\x154\x80\xbav\x1e\xae\x04=+~\x82\x7f\xb8^\x13\xde\x0b\xfd\x17\x97\x85@L\xfa\x91BK?\xe2\xdb\x0d\xbbO(\x16\x08h*60\xe0j\xd5\xe0\xa2\xa0[\x8dD\xa1M\xe17:%G\xa5\x10\xeb\n\xd3\xf1\x8e\x05zYE8wa\x16\xea8\xbf\xe1\x1e\xa0\x03\x19[=\xc4\x88; \x0dB\xfc\x9bPN\xdf\xbd\x03\xa4K\x02*L4\xe3\x84\xc7w\x10\x1f8I\xef\x01\xce\x9f2\xc6!\xc1,0\x96\xc6\x19\xc7\x95\xc5\x11iyz\x1fA^.\xf4\xb2a^\x1c\xad\x03\x7f\x83KL\xaf\x88t\x8bk\xf0\xe6>\xc1\xf4\x10\xa6*\x8d\x835\xc5\xc0\xc5I,\xfc\x0d4\x96\xe2\xc4\xa4\x82Q\x00+\xc5\xee\xa8\xd74\x01\xc7)\xb0\xc2\xa2-\xc0\x94\xad\xa1\x81,\xe2\x8c\xc2r\xcc\xc4\xf9\xd9\x19DaVx\xc6}D\xd0\xbd\xcfn\xc79\xf4\xb7l\xe5a\xf6[Aq\xf5\xdd{\xfe\xed= \xc3\xdd\xc6GD\xbf\xe3\xf0\xe9>L\xb7\xbc\xb7|8\xff( \xf9\x9f\x0e&\xbf\x7f\xfd\xea\xdb\xb7\xaf\xbf\xf8\xe7\xb7\xdf\x7f\xf5p\x01\xb8\xa2Eq+\x17+A\xf8I~CE+^\xc8Ic0}\n\xc7\x1aE3\x05\x14\x97\x9f\xea;\x8dN\x97\x0e\x06\x17\xa7\x15\x8d\\\x8a\xe5@u\x04\x98\xac3?\x9d\xbeW\x99\x1f\xce*\x8b\x97v\x1c\x04\xab\xc0\x0f\xeb\xfa\xf8\xa7\x9f\xb9\xb9\xa3w(Z8\xde8\xdd\xb8/\xa9<}\xee\xd6Iy\x9a}\xbai\xa6\xbf1f(9\x93\xf1\x0c'+\x1cI\xa0rA\xf1\xe7\xde\x1dF\xaa \xe6\xd3\xa5b %\xdd\x14\xb9&\xa0\xa1\xf8&\x12}\x95\xc1\xe85\x06#2}\x01\x01\xd6\x8b_Gd\x8aa\xb6\n\x97\x81\xfc~\xa4j\xa1}\xa0\xcc\xb4\xff\xe2\xf9\xf3\xa7OK;\xf2\xa0\xcc\xb6\xea\xc4\x1am6\xc0p\xa8\xb1k)2\xe9X\xf1\x01\x05J\xb5\xa7%\x98\xf8\\eY\xb6\x00\xe1\x14\x95\\\x0e\xec\x1e\xfd\xc2\xfe\xeb\xca\xb3\xac\x05\xb5\x99c\xf2\x95\xe0\xe1\xf6[v\xa7>\xfd1k\x88\xca\x01\x07*iC\xc4\x0e\x1am\xbf\xe3l\xe3\xdf\xcd\xd4\x8e$\xdaft\xcb\xc6.\xed\x8b\x1f\xdd\xf8\x9b\xfb\xc6\xf8*7\xaf)\xdf21sJ\x03\xe2>\x89!\xa8\x08\xe3\xee\n\x809\xa63\xd2\xfb\xeb_\xfe\xcf\xbf\xfe\xe5\xff\xfa\xeb_\xfe\x8f\xbf\xfe\xe5\xbf\xb8\xd4]\xfev\x17`\xfc\x91(\x0b\x1cJ\xa8\xfc\x8clF\xce\xab\xa7\x1c\xa5W/\x0e\x938b\x91p\x8e\xb5\x17s\xe6JW?\x9e\x05\x10\x8a\xa5\x07\x9e\xe4z\xa3<\xea\x8b\xda\x1c\x19+\x19|\x03\xc9E1\"x\xd7\x83\x88{\x1f\xca\x05v\xbb^\x8e\xaeV\xfc\\=\xd8\xa3\x0eA\xfd\xa0\xe7\x08\x83\xe8\x98mto\xd7\x05th\xbe72\xce\xf7\xd4\x06\xd9@`\x1aV\xcf;F\xd7\xc8 {;T2\x890\xb0}\x0f\n\x9fu\x90\xbeB\xd0\xa6\x91\x8e\xa5\xdb\x0dv\x1c\xc7\x83\xc0\x17\x02w\x94b\xa7\xe8\x00)\xc5\x00&y\\\x8e<\x14K5FH!\xc2\x87\x0dHR\x08\xef\x82\xbaP\x07\xfc\xbfr\xbf\xfd\x83,\x14?\xfe\xbb$\x0b-\xcb\xae\x0d\xab\xff\xce0\xc6q\x1d\xbe\x801\x8e\xaf\xff\xc0\x18\xf8=\x04cj\xe9\xe4(F\x82\x0c\xa1\x13\x0d\xfd8\xf4\xffCh~'0?\x94\xd4\x1f\xa2\xf1\xff\n4\x1d\xb6]\xf9\xd2\xe4\xc5}IU\x98w\xaffS\x0b\x83#&jf\x1e\xfez<\x8e\xeeQ?\xbf^s\x86\x07\x04\x943\xcc\xc5\x85\xef\xa1\xde\x97\xa6>N&\xcd\xd6>h=A\xc9\xbaZ\xfb\xf8\x07\x93|\x18\x99\x95\x1d\xda\x12:\xac\xe25\x8c&\xb6\xbc\xca\x84\xd0z{\x1a\xed\xf1D\xcb\xa3\x890\xca|\x16 T\xa6{~\x19\x9b\xbc8\xd0\x7f\xb6<\xce\xf0\xc4+W\xef\xe7\xa7]\x82\x1a\x1cZ\xe39\x18\xf3bNE\x8cZ}d\xe9k\xa6$ d\xf2\x1b\xd4\xf3\xfb\xf8\xdd\xc7\xc32\xcc\x05\xb5\xb0\x80\x99S\x0b\x06\x03\xb6\xf1Y\xb0N\x99\x8e\x11\xb5-\x00\xbf\xf1\xb7\x19\xd72\x01\x96P\xb2\x81>\x1b\xd0\n\xf1\xdd\x14\xfe\x05yl\x87\x87k\xa0X\xde=\x87\x7fA\xe9\xaf\xd6\x83\xf9\xab\x0f\xe2l\x9f\xf3\xf5\xa3\xfe\xc2,\xf8!\x0c\xbf\x1f%x.\x88a\xdbz7+\xa8\x04\xacw\xe0\x81mY\x84IP,\xa4x\xde\x12\x9aC6\x08\xe5\xa6\xfe\xfe\x94\xe1\xf1I\xc8\xa2\xcc\xfc\xf5\x05\xf6>d\xbaC\x11\x9e+F1\xce+\xceN\x9c\x08\x0bil\xc7%\xce\x84\x06\xcd\x9c\xad\xe1\x9fxk0\xef'\xf5\x0f\x9e\xe9q\xc8\xc8\xb3\x15\n\xb6\xf0\x0f\xb5\xe7\x00\xa6\xca\x94\x05\xfa<%\xdd\xd1u\x0c\xc7IiH\x03\x80\"\xd7\xc9\xa7 \xf5\x10\xdc4\xa1XPp\xff\x86\xe9\xa7\x18\x89N*\xee\x11\xdb1\x08]/\xcd\xc2\x90\xe2)\x05\x06\x9d\xd3R\xa7z0\xd8,`$\x05\x0b\x93@\x1f8*\"`V\x90P\x13\x0f\x0f(\xb4\x9a\x195gG\x82\xe3\xbf\x14)\xa0\x80\xbc0\xd6\x19\xf4`\x8f\xc7<{\x7f\x8d\x07\xb3\xb7+\xdes\x04\x8a\x03\xa3\xb0^\xba\x87^\xe0\xd2\x0d\xc46\xb8GQ\xd9<\xafQ.5\xaff&i\xe4\x87T0/\x0epm\xe8\xf706c\xac\x13\x04\xa7Qj\xd0\xd7\x92\x81\xc2\xea\xf5\xb9&\x16^\xe0' \xc5.\xaf\xd9F\x0b\xd1)\x9c\xe5\xb0 \xf0\x93\x14\x17\x87\x1f\xd8E\x81\xcb\x04\xcf\xcb\x0c\xdc\xf0`\x84\xe9\x1b\x86G\x9a\xda\xf6\x1e\xe8\xaf\xfdK\xf9\x96\xd3\xb5\xaf\x97'\x9cnq|J\x11\x97\x99\xa0\x862\x84\x06\xb2\xc2_\xa1+O\xe2\xe0~\x1b\xdbG\xcb5\xe9\xda\xa7A\xb1 n\x90N\xe01q\x8e9\x10\x01\n\x9e\xee\xc3U\xac\x0fq\xef\x84\xf9k\x1a\x05\xabzx\xd0\x1d\x14\x061\xed\\\xef}\x06\xe8\xbc\x87\xae;f=\x82Y\xdf\xb0\xdf\x06z=o\xd8\x97j\x12_Q\xc1\xfd;\x93\xa0\xc5\x88\xd70{z\xb819\xd5\x94U\xbdF\xfb8\xd8\xb3b\xc9\xdf\xf9\x9bM\x96\xb2o\x958\xa3\x99\xb2JL\xed\xde\xf3\x15\xd2\x0bH\x144\x12\x90\x13S\xbe\x0e\xe2XC\xf4u\x16y_\xe4\x8f\xbf\xcd\x1f\xff9\x7f\xfc\x1e\x1f\xff\x99fi\xea\xd3\xe8\xb7A\xa6\xe1|\xc5\xf8\x96\x15\x1e\xff`E\x8aW1Ovq\x10o\xef\xf1\xfd\x8f\x9b\x8d\xa1\xc5\xa87,\x80\xf3C\xc2\xbc,\xa0\xbc\xdc\x97\x1f\x92\xb8\x98\xe9\xb5\xb1\x84`\xaf3\xbe\xca\x02%\xb4\xb8F\x1d\"r\xf4B=\x8f!\x8b\xb4e\x89z\xe6\x1c\x97P\x08\"\x0f\x9a(l8\x05\xc4\x0f-^\xe3\xe9f\x08\x04\x99\xad\x91\x04\x84a\x16\xf8h\xea\x81\xa7\xb0H\x92\xd1\xd8!\xdektN\xe8z\xad\xabMv4\x121\x92b\xae\x89L\xc8\x91\x00\xea\x83\xdc\x04\xa8\x1e&\xfc\x84\xe44\xbc\xb7\x98\x1aj\"\x17j\xd2\xa6\xde\xcd\xa3%s!\x92\xb7\xd0\xa0p\xa8\xa1\xcd\"\xcd\x90\xf0 \x00t\x8cU\x0cc\xf5k\x14\x8b\x1c\xd2\x1a\n$\x9e\xc7\xb4m\x80%\xeb4\xf0\xb7\xfa\x01\xbfd\"V\x12q\xc0\xb4,A\xbd\x1b\xc5`\x10\xefW[K\xbcV1\xd7\x90y,\x08\xd4x\xe9\xf9V\xafj<\xcc\xeb\x8ey78\x94V\xc0\x08(2!/`Hvm\xad^\x8cB\x82\xfa\xab\x97\xa9\x17\xc7|\x8d\x89\x9a:A3\x8a!\x8cW4e\x86g\xd2\xd436>\xe6L\xcf \x84M00\xd3w~\x98!`\xaa\x8a\x8d\x9a \x16y\xf7&A\xd59Nw\xfe\x06\xea[1\xbd\xd2V>\n\x1e(!\x16\x96/ZB\xa9\xbfc\xc3o\xe1E\xed\xffz\x95u\x1d\xf3\xb1Z <\x89\x03j7\x1f\xf5\xe41\n+i\xfe9\xe1\xb11\x9e\xc3\x04\xce\x14)4\xf4\x05f\x07\xbb\x80\x8b\x1d\x12Pf\\#k\xf5\xe2\x08\x18'&\xf1\\\xa8]\x03\x97\xd5Y\xf7~\xaa\xf7,\xc8\x14\xd9z\xcbB\xcd\x06Y\xc0\xf6\x16j#\x04\xf8(\xfc\xaa\xbf\xe3XQ<\\\xf9\xf0nF\xa0 z)V=\xb6#\x82\xaf\xc5bq$\xc6\x1b\x1a\xfaA\xfejP\xdb\xbe\x8c\xe9\xfa\xc7,\x15y\x9a\xe0L\x8bA\xfa]c1\xbc\xed)\xf7i\x94\xe7\xbe\xb5h\xb6A\xd9\x03Z\xda\xc2\x06i\x0b\x1b$`\x9dc\x83?E\xb9\xd0\x08eY\xe4#\xe34 %i\xb5@8u9M\x1a\x950Y\x9e8D-?\x82va\x99\xdf\x00 7\x98\x00;\xb5\x1b\xd8\xa9)\xb1L\x17\xbaa\xf7\x89\x929R\xfd\x92&\x10X]\xbf)n\x00\xcf\x96\xd4\x02%\xcd\xc7,`\x8a\xd6\x8d\x0b\xecI\xd5\xcd\x82\xd0\x8ac\xf8\xae:\x99S\xe1@K3\xf9\xe4\x05\xb16P\x1c\xb3\x84\xef\xbc\x1d\x8d\"\x16\xa0\x00\x84=\xbdw\xa4Asw\xd0\x8f;\xe8\x07\xca\x1f*7\xfc\x03_\xee\xe1\x0b\x18|\xbf\x8b\xe3\x90Fk%09d\x94\xac \xa3\xf4P8\x81U\xaa\x97\xb4\x15{Vl\xcf\x02-k\xdbM\x9a\x17\x07Y\x18\xa56\x13\xbe[r\xad?kQm\xcd\xa28\xb4Y\xd7,\xd1:\x0d+\xcb\xe7l\x1a\x1es>\x07\xbbG\xf5\xc05ykbA\x81\xc2\x1f-q\x17H{\xc4\xc4\xce\xf7n\"\xad\x17\x0b\xecV.\xb0\xfaT\xb5\x05-\xef\x83T\x8a]g\xea\xc50j\xf5\\\xe0\xba!\xbd\xb3_\xfc\xc8>\xc6{\xb55\x81U\x03\x8dFqNL\xa3,\x1f\x07#\xad\xf3\xf8\xd6\xa6\xf1\xf8\xd6\x8e!\n\xcc\x06w\n\xe23\xb7\xbd\xe0\xb6\x17\xb8\xe7\x05\x03\xc5\xfc\xb5\x00\x95\xde\x13\xfb\xef\x98\xde[\xf8Z\x8f\x07\xe8e\xb5\x80 \xb5L\xc2\xbeh\xe2\x03\xa2\x88V\xe2\xe9 \xffV\x96L\xb3\xa4\x9ar\x1f\x86Lp\x1f\xe4\xf1}N}\x0e\x8b\xcex\x83\xe3.\xf0\xa3\x9b\x99\x99\xe3\xbb0\x98i\xebzH\xb7\xe2\xba\xfa`G\x03\xaa\x9cA\x8e\xde\xb2`?I\x8a&\x8f\x81\xd3\n\x89T#7\x9b\xab\x9d\x17$\x1a\x8f/\x06\xa8\xe8\x8c\xb6=ru\x05\xa6\xa6\xf1\x86\x88\xb9\xb9}:\x87[\x98\xeaO\xe5f\xd9\x88\xb0\xb9J^6x\xdf2\xa6\x9b\x95\x83\x0d7\xe4^\xbb-\xae\xebp\x93h\xf5\x16^\xa6\xad\xb7\xaf\xbdc\xfb\x11a\x03\xf2\xc7\xd5\x8f\xcc\x13\x85\xf0\xf2;\x9a\xfe\xf16\xfa\x8e+\xd1A\xdcO<\x1a\xc0\xe0i\xcf\xd1\xba\xd7l\x1e-\x1d\x9eT\x8c\xc9N\xc3\x91\x0d\xd1\x80o\xc0\xbb\xdc\xcf\x8b\x9f\xe7\x8bt\xf1\xc3\xf2\x89\xd4\x7f\x17\xef\x17\xefO\xb7a\xbdG\x89*p\xf9O\x95\xec\xff\xf4\xd2\x99y\x0d\xd6jk*\xe8x\xbe\x18/n'\x8b\xec\xec\xec\xb7\x9f\x8e\x17\xd9\xd7_\x7f\xfd\xf5\xf2\xd4q\xf2\x08%\xd4\x12\xc7\x12\xcb\xe1'\x8e\\{\xc8\xd5\xbf\x9e\xe1\xff\x1b\xb9\x13\x03\x91\xa4\xd7\x12o\xd6H\xc1\x02\x89\xd7-\xa4\xe7\xaf\xe5]\x98$\x83\x99\x9c\xbf\xa1\xe3wK9\xa7\xe3w\xc3\xc9b\xbc\x1c\xf6\xafg\x90\xa6\xdefK\xf9\xc9`P5\xb7#\xda\xb3\x154\xb6\xb8\x1d\xe2\"\x93`\x829se\xde\xaa\xccs\xd5\xcd\xb3\xb3\xb1\xfas~\xa6\xfe\xfd\xe2l\x91M_|\xa6\xfe\xfd\xec\xec\xabEv\x8e\x9f\xcf\xcf\xce?W\xff>\xdf,\xb2\xa7ggg\xcb\xd3m\xbd\xca{rEz\x06 \x8b\xf8\xff\x03hf\x15.\x18%m\xed\xe3D\xc9\x0f\x8a\x86\x90\xeb\x03\x16\xe5\xa4\x803XC\xdd\xa9\xee{2\xeb^\x0b\x03\xc0\xda\xe1f\x13\x10\xd1x\xa6\x18,\x18\xe1\x15\xbe\x81M\xa1\xee\x86]\x13\xe4:\xef\xec\xac\x05\xd2&\xea\xb3r\xc3\xedoH\xff\x0b%\xb5M\xfc\x14\xfe\xf6Y\xa3\x85\xa1%Sj\xd1\x9f\xe1=z]\xc6\x98\xb0_\x10\x01\x11\xe7\x0d \x13\xc3\xe1\x80Ds\x81\xebU,\xeb\xcb\x95\x14\xdc\xf5\xd5{\xd3\xb4\xba\x11\xe4\x0d\x8f\xc3vG\x80\n\xda\xb7m\x07\xae\x85:{J\x00\xd9\xf8\x11[\x17\xe7\xec\xd6\x8f\xd6\xf1-\xb9\x06{\x002\xd3\xef\xe5&\x9d6\x83v\xe4o\x9d\x8d*\xc8\xbe\"W\x84\xf2m\x06\x86`&\x92\xfcK\x8c\x0d_\xf0B`\xb3\xcc\xcf\x96\xe4\xba\xfc:#o\x9b\x02\x9a\xde\x95\x0c`\x9b&\x95\xe4\x10\xdfV\xc7\xd2\xfc\xde\xbb\xbd5\xdcM\xf6\x8c\xa7\xaa\x8bW\xa47\x9d\x9cM\xd4\xae\xfan\xc2Y\x18\xef\xd9Z\xc7\xbd>\xf9\n\x9ck|5Y\xc7\x1e\x80\xad^?\x87~\xe5i\x93(^\xb3\xd7\xf7 \xb3\xb6\x9bw\x13?\xfd!K\x92\x98\x0b\xa8\xead:\"wu0\xd4(\xfe@\x8aU\xb9\xc7\xe2\xcb\x06\xbf~\xeaw\xd3\xf2\xed\x8b\x0eu\xff\x11\xf2\xfcN\xe7\xf9\x9a\xd3ms\xde\xef \xef\xef_\xbf\xfa\xf6\xb5>p\xfc\nO\xa5\xdd\xd9_C\xf6?\xd4,\xad\xcd\xef\x95\xfd\xfe5\xe8\x83\xdc\xb9\xbe\xc1\\4dk\x95\xf5\x15M\xdc\xf9~\xb4\xfc\x1a(\xd27\xe4\xbaRLM\xddW\x93W\xf1;H\xfcB\x08\xae\x12g\xe4\x1bw}\x7f\x80v_\xb3\xbb\x86\xde}\x0f\xdf\xbfD\x8b|w\x96\xdf\xe1\xd8\xfe\xf1\xd5wp[\xda\x9d\xe9[\xc8\xf4?\xbf\xfa\xf6\xf7B$\xdf\xb3\x9f2\x966T\xf7\xa7r\x0f\xbf\x85\x1e\x96\x0b\x92\x19\xf9\xd6]\xf8'h\x86Ej\xff\xf6\xa7\xef\x1b\xfa\xfcu\xb9\x85\x9f\xa0\x05[\x86\xcc\xc8O\xee\xb5\xe4\xe4\x17\xdf5-Z\x85\xf6\xef\x14\xf5\xfd\xff\xd9\xfb\xda\xae\xb8m%\xe0\xef\xf7W\x0c~zR\xfb\xe05\x90\xa4\xb7\xed\x06\xc2!\xb0ii\x03\xe4\x02i\xdaK\xf3p\xcc\xaev\xd7\xc1k\xed\xe3\x17^z\xcb\x7f\x7f\x8eF\x92-\xdb\x92\xec%iz?\\\x7fHXk$K\xa3\x91\xe6E\xa3\x99`\x9c\x92\x8a\x88\xdc\xea\x18\xdb\x10\xc4\xff\x8f@\x98D\xd8\x16S\xfe\x08\xe8mBRI\xc1(c1\xc27\x94\xdb.\xd5\xc8\x87u\xf0\x15\xeb\xa0\x1eK\xbf\xc0\x0e\xbc\n\xa2\xc5\x92\xf7\x1b\x95\x14=\xe4\x8f\x08\xc9G\xc9\xa8\xf0P\xb0u=\xf4{\x84\x9e\x91\\ ${u\x7f\x1e\xce\x18\xb5\xea\xe1\x7fRZ\xef\xb7\x80\x7f\x83\x1d8c=\xa7in^\x97?\xa3T\xdc\x9e\x82\xe6\xae\xf6Kc\xa7\xffE\xf4\x85m\x10\xeat\xf0\xfdr\xaf\xdc\x88\x8e\xe8Ds\xf7\x8d!\xfd\x07\x8c\x8c\xa6\xed\xd4W\xb0\x03\x86\x95\xffo\xd8\x81\x89\xbe\xe8W\xd8\x81\xb9\xbe\xe8_\x18wM[D\x08\xec\x80F\xa4cON0(\xa0\xb6,aez\xcf;@F\x05;\x10\xbb\xffy\xf0\xe1\xe2\x03\xa3\xceq\x98\xbbW\x188\xeb\xca\xcd\xf1\xdf\x04\xffM\xf1_\xeay\x06\xdeH\xed\xdf\x89\xf4\xdf\x89\xb0\xd5\x10\xff-\xf0\xdf\xcc\xf8\x85\xd0\xfe\x85\xc2^\x9c\x11Cb\"\xc0[\x81\x96\xc21\xb1\xb0\xb3\xa9\xadpi+\x9c\xd8\n\xe7\xb6\xc2\x1b[\xe1\xc2V8\xb3\x15\xde\xdb\n\xafl\x18\xba\xb4\x15\xde\x12\x8bB;R\xc8\xa2r\xa0\x91.A\xd2\xa3\xa0\x8a\xf7PZ\x93T\xef\"\xe1\xe4\xc3\xbdD>\x98d7\xed\x97J\xcf\x12\xe1(V\xb9Gq\xa7\x1aSkg\xb5\xd6\xb8a\xb99}uh\xf8\x98R\xc6*\xb1\x97\x85ZI\xfb)\xa5LVB\xfaw\xde\x9d\x8d.\xdf\x9e\x9e\xbc>|3\x92\x9fz\xf2\x04\xa6\x81\xfa\xde\x17\x9b\x14\x0f\x82'\xfa}\xb9wz\xb8\x87\x0d\xfab\x9b\xaa\x17\x1f\xec\x9d\xcbb\xdc\xa8\xe4\xfbw\xc7?\x1f\x9f\xbc?f\x8d\x9f\x9f\xec\x9f\xbc9C\xa5a\xcb\xe7;\xd648\xdb{=\xba|}rz\xf9\xd3\xbf\xde\x8dN\x7f\x93\xa5\xcbF\xe9\xf9\xe8\xe8\xed\x9b\xbd\xf3QY}\xc2\x01\xde\xffx\xf2ftyp\xb2\xff\xeeht|.\x0b\x17\xbc\xf0tt\xfe\xee\xf4\xf8\xf2\xe0\xe4H\x16\xcc\x9a\x05\x97\xafO\xf7~P\xab\xde\xb7 \x0e\x8f\xde\x9e\x9c\x96\xe57\xbc\xfc\xf5\xc9\xe9\xfe\xe8\xf2\xd5\xc9A\xd9\xe3\xab\x1aR\xce\xf6\x8e\x0f\xcf\x0f\xff\xcd\xbav\xe4\x8b\x8dI\x96\xfd<\x1a\xbd\xbd\xdc?9>\x1f\x1d\x9f\xfb\x9ciV\xc4\xf1\xee\xf4\xf0\xf2t\xf4\xc3\xe8\xd7\xb7\xac\xe1\x9c *0\x0c\x11\x91i\xd5f\xfc\x05\xdfa7=\x9cZ\x0c\xecI\xb4\xbc\x0dy%\xa7OT\xdb\xf8Z\xb8%Uh\x80\xd8M\x88\x0f\x8c\xd7\xc6.%>D<\xb3\x97\x84\xcbnf\nX^\x82\x85\xe5_Y\xab\x02\xd7Z2\xa5^\xd2]\x8f\xed\xb3Gj\x97\xd2\x12\xb2P\xebx\xb8\x9a\x0e\xf8\xa2(\x87\xbe\xb3\xc3\xa4\x88\x12\x11c7!\x1e\xd6b-U\xf0UmF\xad\x08Oy\xed\x88\x94\xbf`\xecRQ\x9b\x12\x15\xbe\xaa\xcd&\n\xc9S6\x13\xbbgD[\xe8!\x01\xf0\x8e\x95.Wr\xee\xb8\x85\x94\x1b\x96RB\xfe \xb8*\xab\xb7\xc2\x82\xca\xcb\xdc\xa9\xe7\xf3\xadu\xaa\xdd\xfd\x0c\xdc\xed\x84\xf46\x18\x94J\xbe)&\x82\xfa\x08\xbf\xeb\xa1\xc6Z%\x9f\x07K\xce\xb1<\xbd\xb7\xf4\x04dv\x08\x92\xa0<.:\xb6?\x8f\xe2\x89\xc9\x9c\x01h\xd1\x1b\x87\xf9x\x8ey8\xbaZ\xa7ENR&\x92c\xe8rs\x93\xab \xfb-\xe9\xba\x9e\xac>\xdd8XiF\xd8S\xfa\xf0\x0c!g\x1a\xd3\x9e\xfc\xcd\xb0\xc8$\xea\xce\x16\xa6)]\x0c\x1bv\xf6\xe6\xf3\xd0c\x06\xac\x94\x06\x9f86\xb3p\xa1>\x9f:\x14\xf3\xc4\x89\xae\x97\xd85\x9a\xd8\xf4\x9d<\xef\xbf&\xa5a\x96K2\xf61\xdbNf\xe4\x13M\xc1\xbd\xe1\x1b\x12\xca\x04\xdb|$/\xb77\xc4\x1f\x0e\xac#7\xb8\xee\x9a\xbfn\xeae\x0f\xfb\xc8k\xdb\x92\x85&\xd1\x98\xd1\x0ej\xb4\x03r\x0b\xef\xcc\xc3dO\x1a\xa4$[\xd2$C\x1b$\x1b\xacT\xb4\x1d\x1f\xd2\x80.I\xe2:?\x8c\xce\x1dq/e\xc86\xe7\x0d\xc6\x18_\x8c\xe7a\x9a\x91|\xa7\xc8\xa7\x83\xef|D\x89/\xd2\x9a\x06\x19I&.#@\x8fGE\xa9>\xf3\x08Jb\xd3\xb1\xef\xf5\xc0%\xfb\x92\xcb\x06}\xe0\xf1\x18\x83\xafS\xba8\xc33D\xb6\xcf8e\xdf\x9d\x9ek\xd3\xdc\xa7\xf2v\xfc\x93'\x90\x97\xc6 !\xa8\xe3\x95y\x9e^\x94uIg\xdap\x1d\xc7\xf3\x82+:\xb9\xf7L[x\xa2\x16L\xa34\x93\xcdc1\x13\xc4k\xdb3\xa3\xc7\xf7\xfc\xbc0G\xe9oW\\\xb1\x81\xa1\xb8\xbf\xe4]l\xb6\xefw\x81\xde\xc8]7\xd70 \xd8v\x8c\x00\xca-\xads\xe2~\xbd\x9d\xdd\xcc^n\xcf\x80\xa2\x8f\xf0\x0e\x06~k\x0f\xd3\xf5\x9c\x97\xdb\x1b\xb3\x97\xdb\x1b\x0c\xfck\x03#$\x01\x86\xdb:\x13.\x19.j\x91\x18\x82\xc9\xbd\xe62\x82\xbe\x9e\x9d\\\xdczW\x97/\xb7Qo{\xb9\x1d-f\x90\xa5\xe3\x1dg{\xa3\xf1\xe6\x0eh\x82^\xf2;aL\xd2\xdc\xdd\xf266\x9c\x97_{\x9e\xa6\x83\xc0\xd4T\xae7\xed\xf3N\xea\x11o'\xb6\x07W36\x86\xe7\xa3\xfe{\xa3 \xd4\x1f\xc5Ir\xc3\xde\xf9\xe7\x9fl\xd1\x12\x1f\x8e\x82\xb3\x1fO\xde_\x8e\xde\x8c\xb8\xac/_\xec\x9f\x1c\xd5_\x9c\x8f~=\xf7\xbb\xa9\xa1\xf1\xf9\xa3\xe0\xf5\xe1\x9b\xf3\xd1\xe9\xe5\xde\xfe\xfe\xe8\xed\xb9y\xf5\xd5s.\xd5\x8b\xb4\xaf\x0fWFE\xa9\xfd\xee4\xb4\xdfs\x8d\xf6{\x8e\xb1l D\xe8U6&t\n\xe70\x14\x07\x9d\xa6\x86\x88\xa6!\xc2\xd5h')\x16W$UM\xdd\xa4<\x02\xe2\xc7\xba-\x9f\x07\x0ep\x1c.\x0c)O\xf5\x88\xf9\xd8\x12\xb3\x1a\x973\x9b\xcf\xcf\x17\x04]+\xd8\xff\xc1\x94\xa6\xa3pN<\x95\x0c\x8eQ\xfdT\xdf\x9cb\xe8/\x8d\xcfJ9\x7f\x86 \xce\x03\xc6\x99\xf6\xab\xe3 \xed\x91H\xaer\x07\xcewJi/S\xfb\xf1\xb1\xb3\x89R&\xb3@f\x8a`\\\x05\x969\xe1\xb9\x1al\xf9\x7f\xa5\xf4Q\x91m\xddA\xa7{J\x8a%M\x1a\x13\xc2\xe7\xa3\x83\xfd\xf3\xf3\x8e!\x18\x8eH\xe4\x13\xc61\xbd%\x93\xf3p\x96\x0d!\xb1\xa9f>\xac%\xe4\"\xfd\x80\x01\xff\xd8\x1f]\x8b\x80\x8d\x80\xab\xb2k#\xach\xc2/ \xa2$#i\xbe7\xf9\x18\x8eI\x923&\xdeG\xc4\x01\\i\xed\xba\xae\xb37\xcdI:Bg:\x06\x90p\xc1\xe0\xb3\xc9\x94\xcd\xf97c\xadk\xff]\x9b\x12\x1eT\xb0%\xd3\xf0\xd7\xca1]\xf9C\x0f\xbb\xb6\xb1\xbd1\x0br\x92\xe5.Q\x97\x10\x97\x0eV\xd2\x9d*M=\x18\xc74\xe1\xaa\xa0m\x03\xaba\x99'9\xa9:P\x06\xe8c\x1d\xf4\xc1y\x12\xe7/\x1c\xcf\x93\xa6*\x99\xeaA\xdd\xf7\xb9\xb8X\xfeS\x1fO\xd9\xde\x0f>8\xc0$G\xf9\xe2+\xfe\xc2\xafW\xa8\x82J~\x01,\xa8\xdf\xdd\x81\x84\x0d\x93-\xe2\x90\xd1\xa3}[\xddZ\x85\x0b\x9c\xae\xc8\x05V\xd6\x07\xedpiO8\xda\x13.\xea \x17\xf6\x84+\x1e\xcd\xf2\xca]\xbe>;<\x82j\xc5a\xba\xb6>\x86\xf4v\xcc\x15\xdd\xc3\xda\xe4\x1b\xb5.\xa0\x89\x0e\xfa\x970.z\x82_\x13\xb2d#\xd2\xc7ki>\x82\x15T(\x18\x0253\x04\xd0\xebJ\xea\x83\x8ebl.\xc2\xd2\x11\xac@_\xd6n\xb4\xc8\xec\x92(k\x84\x17\xc5\x07/H\xc2\x05\xf1\x91\xf4\xf2\x00\x0f\x98\x82<\x8d\x16\xae\xe7\xf3\xa0\x85u\xbe\xeaC\x16H\xd4\xf2\x04P\xfc7\"\x8f'\xeb\xc8\x02\x89\x1e\x91J\xb3\xc9m\xf7\x94\x18\x96hJ\xe6_W\x1a\x92\x07d\xb8\x85Q\xe4o\x87G?8\xca\x8e&\x05\x9d0\x88&\x1e\xd29\xfb\x8b\x13\x14w^\xab\xbc]1\xa0]\x10.\x97\xf1=\x1e.\xbf%.?\x8e#\xfcG\xc2\xff\n\xcbL\x12\x91\x07/\xa1\xe0\xbcA\x95PD\xb5\x88\xa3\xc9\"c\xc8\xc7\x90\x12Q\xf7\xa0\x93\xca\xe1\xf1\xdbw\xe7\xbaa\xf2\xbb\x0e\n:\xf0f\x1d\xb7\xb6\x0bs\xf9\x05E b\xad`\x7fy\x1eF\xc5\x8d\x92B\xe3\xc7\xa0{\xd8\xc8\xb0\xb9D3\xec\xc4\x07\xc7Qp\xd5\xd9\xa2\x9d\xcb\x83\x18\xaeB(\x18)\xf8\nY6\xf6d\xad\x1c(\xa7\x03\xfe\x9b\x0d\xcfM!J`\x8f\xfd\x8d\x7f]\x13\xcf\xe8P\xd9|\xd8G\x05#d\x04\x87\xff\xa4\x9dl\xcf\xc3\xa3\xb6'O\xe0\xdf\\\n\xa0^\x8f\x99\x079\xfb8P\xac\xfe\xebc\xaa\xf7\x1b\x18\x88\xc1\xad\x95d\xc0\xa9`E\"\x00\xd1\xcc\x19V\xee_\xa7\x1chN\xf8\x18+\xa4\x12\x82\xb4\xd3w\xcc\xa0\xb6\x86\x97~\x15RPn\x0eT\x04\xc1\x1d{\xaa,0\xdc\x80\xc8m7kw\xe4\xc2\xa4 |\xe8\xa6b\xf5\xc1\xb0\xa2\\\xe6\xfe\xd7g\x18#\xa8\xe3L\xaby\xea\xd5@\xf7\xea\x82N\xd3T\xf3i\xaf\xf8\xd4\xf3\xd5\x93\x01\xba\xb4\xc8h\xea\xb3\x82\xb8\x0f\x9d\x83\xb1\x97\xb6$@\xad\x94alb\xa5\x03\xa5\x03U2\x04b?\xd7\x92wM\xfa\xc8Tl\x13:b\xed\x99\xa9\x07\xf9}[\xa6:\xc3\x80>\x07'G\x0e7\x87\xb0\xc1\xbe\xc0\xef\xa6AB\xeer.X\xbf\xf0Z\x0c\x98W\x14\xa1B\x92R\x18;&n\xc2\xb5\x9a\xa4\xd4\x8f\x14\x8d\xff\x049CU\xe6\xf9p\xcajX:\xde\x9a ]\x97\xf5\xb3`\xbcxr\x17d\xa2\xb1\xbe'|}g\xa3\x8f\xf4\xddG\xf2\xee#u\x87\x1d\x924f#\xe4Qqa\x07\x9c\xdf\xef\x9e\x8d\xd7\x06\x83\xdf\xef\x9e\x11\xc6\x88K\xf3\xceZ\xa5\xeb\xe3\xdetH,\xf7\x0b\xa0\xed\x0b\xab\xd4\x0fr\xcaO1<\xc8\xe7)\xbd\xc5\x83\x1d\xa68\x8e\xd2\x94\xa6\xae#\x8b!\xca \xa19\x84%\xf2M\xce\xb0\xe5\xf7Z\xbd\xc5AU_t\x19\x0b\xd7~t\x12\xa5\xf9}\xf5E\xde\x90\x0f\xe1\x15M1N\x8d\x81x\x8c(]\xab\x1d9t\"J\xb5\xbd\xde\xbb#\xecp\x98GcnHa\xc2\x8a\xce\xec\xd2\x84\xeb\xb6\xe6\xe8\xec\xb1\xa55\xac\xde\x9c\xdb%w\xb2\xf6\x04\x19\x18\x1a\xa8NtV\xdd\x1b\xc1t\xb3M>f\xcc\xcf\x91\x9a\xf7\x08\xba\x916/1\xd4M\xdf\x1e\xf0,\xbb\\HK\xf8\x19J} x\xf5#\x06\xc5a\x98\xed\x04k\x9b\x9eW\xb7w\xbf:9\xf8M\x88\xcb\x95\\\xbd\xcb\xf7J\x18B\xc2\xb4\x03\x92L\xf8\x99Xj:$\xb2\x0bdH_\\\\_\x9b\xe0\x7f\x03\x99-\xb8\x14N\xb6\x1d%\x7f\xb7}\xd5\xac\xc9\x91\xa3\x80+\xea\xf0^\xf3\x9b2\x06W \xfd\x14\xf0\x93\xe6\x13\xb6}\xa3\x95\x8b\x1f\xef\xe9{P\xdeC*8kJ\xbc\x17\xb8\xef\x15u\xae\xc2\x0dL\xb4\x86h\xca]x\xd8T\x1f\x13\x97rnB\x8d\xdc\xe4\x80T\x85\x9c\x9dP\x91\x8c\x98\x1a\xfa\xc60\xb3\xb0\xdae\x18\xc4\xacCG\xc1\x11\xb2-\xf8'~\x9e\x904<\xf0_\x80\x8a\xa6\x17\x1e\x845\x02\xe9\x81C\x90\xf4\x82A\xfb\xcd0b^\xef\xb9V\xc2\x80\x7f\xe3]:\xf3e\xaaK\x1f\xc2\x15&Z4\x88G\xb3\xea\xd9-#\xf2\xd2\x94\xd8\xaa\xf9\xc0\xd6dF\xf2}\x9aL\xa3Y/\x1b\xd8\x1e7\xd2r\xdfdMly\xd6\"\x06\x8aj\xb7ij\xb2rW\x95.\xcf\xfaf\xc3\xc9\xe4GJ\xaf\xfb\xf2\x7f\xfd\xd9\x03\"\x1c\x8f\xa3v\xf8\xa9\xd4\x9f\x7f\xe2^\x84'Sh\xc6\xcc=\xcdU\x8cj\xf3ju\xc1\xf4\xfd\xda\x99\x97^\x90n4\x9b\xad\xd4\xae\x1c\xc5\x85F\xa7Q\x1a\xde\x8b\xe3V\xdb\xc6\xa6\xd1\x0fW\xdbZ\xed\xe5\x832\x16\x9e\xce\xb6\x0c\x8b\x9c\x8a\xa2G\xc5W\x16\xfev\xfcpS\xdeSvs\x1f\x9c\xcbK\x92\x1d\xd1 \x0f\xd3S\xef\xfc\x0d7\xe0\xa9\xa9\x02\x94\xd5)O\x8cb7q\x9f7o\x15PQ\xf0\xb4Y\x10\x89\x82g\xcd\x82P\x14|\xd3,(D\xc1?\x9b\x05\x99(\xd8T%f\xf6b\x8b\xbd(\xdf\x94:F\xdc\x9ey\xf5\x06, *T\xe0\xe9\xb1.\xa8\xaf\x88\xaf\xd6\xf4\x0dlF\xd8\x05\x81\x9f\xb1\x95\xee\xca\x9e\xe5\xb6k\x9e\xee\xa6\x0f4\x10\x1f\xf6\xdc|\x1ee\xdc]\x95\x15\x84\xcd\x027\x0f./\xd1Twy\x89\xccb\xd3\x87T\x01\xf2;\xd3\x88P\xd0%\xbb>\xba\xaf\xab\xe0\xc5\x82\x93\xb4\xb4\x88\x99 \"[/\xaa\x8554]\xc3\xe4`lM\x0dM7<\x01\x0f\x0e3z6\xa7\xb7f\x92[Zmh\xe6\x01,;\x87\x18\xf7Et\x94Li\xba\xe01 ;\x88\xc2\xd2\xa1\xb1\xeds\x0bz\x15\xc5d\x08[OWm\x96\x8aqz\x96\x91N:q1\xed\x84\x98wB\xc4rg\xf8D\x0cXx\x08\xc9\xaes\xba|\x0c\x9a\xc2\x1eh\xfa\xaf\x1e@Q\x0e@\xa7\xb3\xd5\xde<|\xf0|\xe5*\xc2\x83[\xb5Y\nS\n\xa3\xcbe)\xec\xc0\x18\xdf\xfe\xbd\n\x8d\x0fy\xf0SF\x13\x14\x15\xc2Kn\xa1D&\xad\xbc\xbd\xa24&a\xd2|\x8d\xe1\x03\x9b/\xb9\xe9\xb1\xf1\xf65M\x17\x1a.-u\xa8{\xa6*\xb5T\"*KZ:Q$JZzW(\xab\xe8\xb4\xa8{\x9d\xde\x95\x89\x82\xd67bQ\xd0\xd2\xbb\xb8\x94\xd7\x14\x88\xa6\x08>n\xbc]\x8aF\xb6\x9a\x8dp\x01\xed\xdb\xc6\xdb\xb9\x04\xdfj\xf5\xf3F\x16\xb5\x86\xb6\x90%\x9b\xdf\xb4\x061\x13\x89\x8a\xb5\n\xe1\xfd\x97U\x08\x97\xe5\xba`=\x08\xa2\xecT\x84\x85\xf6\x95\xa20\xb9\xf7\x1b\x90\x96bN\xad\x86\xa6x\xa1\x0f7\xe5\x9b8\xcar\x15\x82\x91\xb5\xedw\x98\xdc\xd7i\xf5\xaa\xe5*t\xa3w\xf2\xa1\xc9\xfe\xf9\x86\xb6]\xcd:\xff\x1c:\x7fK\xb5\x97:\x7f\xd6,\xd0\xe9\xfc\xaaF\xfe\xa9:\x7f\xac\xb4U\xe9\xfcuK\x80Q\xe7/\xd3J\x1dD\x93#\x1eG\xb6\x05\xf9\xd7\xa9\xff\x93([\x86\xf9x~\xc8t\x860\xe6\xceP\xc6:\xdc\npc\x07\xe2^\xd2\x92\xc0\xf5\x1a\x17\x1aCS7\xe9\xe4\x9d:\x16\xff\xf7\xd9J\x90\x84\xbb\xd0\xc3\x97Z\x17~:\x90\x18\xd5\x90h\x91\xd8W\xb0\xcb\x14\x08;5\x1c\x0e\xe4AN\x7f\xe2\xd7\xaa9{g?]\xd3a\xbb\xf4\x8b\xb4|.F\x17\xbb\xfc~i\xe9\xfe\x18a\xb8\x9a\xbf\xe0\xa6\x80>*\xa9\x0f\xb4=\xe3\x06\xc6\xd3\x06\xac\x9di6c\x02\xfa\xb88x\xa8\xc5\xc2\xe3\xf9\xaa7_\xc0\x18\xb6\xa1x\x01\xe3\xf5u\x0f\xe2\x8b\xf1\x07\xb5\xe6\xc5X\x13kQ\xc6Y\xc4S\xe5\x1d\x03\xf3\xc3=\xae\x93\x01\x8e\xc38\x16\\\x90\xf8p\xc1\xea\x96\xc1$\xb8\x9e\x96\x96\xdbQ\xaf\xc3\"\xe9\xae\xaez\x8er\x92\x17\xfbh \xa2`\x92\x80G\xec\x0e\x18\xa0\x88\x81X\xbeC\xba4,<\xd1\x9a\xec\x15\xe3\xb2\xf2\x9d\x90\x90\xb4\xc7Sl\x1c\xa3\xa4X\xac0\x16\x81\xe7\xd6\x17\xf5\x1f@\x9bvK\x14a\xf4\xf4%\xe4\x89\xbf\x81/\xf6c?+\x08\x0f]\x8c\x96\xf6b\xb4\x9c\x87J\x99\xb8\x8b\x87N\x08\x8f\xf3d\x8c\\\x07\x82\x85\xa6\x01I\x8a\x85\xd92\xcd:G93\xdd\x15\x7f\xb8\x1e\x0c\xf1\xac\xb7\xe82U#Ou\x1d~\"c\xf3s\xea`;V\xbe\x02u\x8b\x1a\x95\x91Jw\xc1\x89\x12\xcc\x07\x84\xd7\xab;\xee%`\x90\xa8Zm\xda\xa3\x96\xb8\x9b\x80\x82ff\xe5]P\xd1\xaceF@\xb69Z,\xf3{q\xa5b\xcd\xc2\xa2\xa0\xc6\xcb\x90\xc8\xd5\xfd\xc0X\xcft\xbb\xd3\xb8\x86b\xdc\xfch\xba8\x08\xf3Pn\x80\x11\xba\xbb\xaf\xb9\xce\xeb\xb2 JD\x0c\xda\x8e\x83\xa3\xdcu\x0e1\x91\xa4]\x10\xa9\xed\xb7b\x8b5Q\x89\xd5\x82\xc6\xea\x0eEs\x96\x9e}\x12\x1d\xadNC\xad\xa9\xeb\x92\x90e~\xaf!\xc4\xfa dk\xd3\x84\xa0\x85|\xdf\x03Q\xcb0\xcbni:\x91\xb8\xe7R-CFU2\x94\xb9\x07\xffk\xf0\xd9\xbd\xc2\x16Q\xf2\x06[\x1b\xda\xfcK'\xe4\x8a\x16\xc9\x98\x9cG\x0bB\x8b|\x08\xcf\xbe\xb1@+\xa1\xe7\xacb\xe9_0\xdb\xad\xd7\x9fU\x02\x95\x16\xcf^\x02(1\xdc]\xef-dJ\xf3\xe8c\xad\x1e<\xae\x06Bc_\xcc\xd1\xf7\xf5\xc2\xdf\xaa\xf2R\x1ady\x98\x0b!\xc0(\x9c\x1d\xe6D'\x9cY\x1c\xae\xd2 #\xf9\x19k\xba\xba\xdao\x8d\n :hg\x91ri\x88Kj\x19\xc9\xb98f\xacd\xf2\xefW\xb0g\x184w\x98b\x03\xef'\x8fj\xc6k\xbd\x1f\xb0\xcax\xe5\xa5<\x11\xce\xe4/\x19o8\x994\x07\xbb\xcaX\xfb\x04\xc4\x10T\x06;p\xe9J\x8a\xeb\x12\x8a\x04\x06\x048w\xcaslau\x1e\x8d\x80\xd5U\x10\x0d\x1az`\xa1\xdfx\xff\x82\x01\xe2B7^\x9c\x15\x1f\xaefF\xdbH\xed\xe5_\xa3-\x95\xd6\xd7\xf7Q\x1c\x9f\x921\x89n\xf0\xb4,\xeb\xa1@\x19\xe7J\x92\xde\xda\x8e\xd0\xa2\x94]\x8f\x89\x7f\xfc\x9d\x9cN\x9bB\xa0\x92\xa3~*:\xf9\xd9\x17\xb2\xa0\xdau\xc4>\xba$?=\xec\xa7KR\x84\xedV\xed\"\x84\xebR'C\x84\xeaR'\x0b\x842\x99OC\xbc\x11,\xb4\xbeP\xd5\xfa\xec\x06\xd4\"\x88\x92)I\xb9\xf8\xe0FA\x94\x93E\xd6\xedhV?Q\xe9\xe1s\xf6\x8ag\xf7\xef\xf0\x1f\xcbP\xb7\xb5\x88W\xd0\xa6h\xb3&\xbc\xec\xd2v\xe7\xd2\xd3\xed\x13\xb5\xddy\xd7\xc6\xaeH\xd5\xe1\xeaR5T\x92\xb5R;\xecQKf\xdf\xed\xbe\xb7/\xd6\x9c\x85\x96\xa1\xad=\x1b\xa2\xbf\xd7\xa0kz1\xfd\x9b\xf5\xe2\x8ey\x14\x0eW\xdc\xedc\x8dGC\x99\x04\x98]\x91\xfd-\xfet=\xd8\x86\xad\xea^\xca$X\x84KE\x10\xf2\x81v\x11^$\x84\xe6\xb4n\x96\xcf:.\x96\xc9\xd9\xb75\x0f\xe2\x13K\xdc\x10xZ\xd7\x9e\x92\x8b|J \x06\xaf\xf1\xf0[/\xd6J\xb6p\xab\x80'\xeb\x82j\xe5\x9d\x8f\x8b\xe5\xc5\xe6\x07\xbe\xe3\xc1:P\xcb\xdd\xe4\xce{Y\x1dsi\x1f-2\xa2\x0e\xa2T}\xbf>f4\x19\xf0\xed|\xc0\xf4\xeb\x01\xdb.\xad\x0e\x81\xa6\xeeY\xdd\xcd\xa0\xfbd\x05Z\xa7+\x1dF*)]\xf7]\x81\xfd\x04{\xf9\x94$\xa3\xaaO|)\xd8)\xc7\xde\x1dy\x9e\x13Y\x96\xbf\x19\xc7V\xf3\x124\xa6\xf6*O\xe0*O\x06\xd9\x02\xb4\xb3<\xe0\xfaH\xc7\x86K\x93\xfd8\x1a_\xf7\x10^\xd4\xa7\xc4^\xa5\x87\xb9]\x88\xb3\x11\x9d\x03\x03pL\x9e\xa8^\x90S~\xf4\xf3X\xd4\xad\x84\xb6p2\x01\x07\xd6\xab\xcd\xab\xc1\xf8\xb8\x1b\xa1\xf1[%B\x91#\x08\xbdM?06\xee\xbd\xc9\x04\xd8g\xb5\xc3\xef\xb4\xb4\xbc-R\xb2\x8a\xb5\xa5r;\xebeo\xf9\xdf\x81\xdf\xca\x07~\xabj\xa9\xff;(\xd3?\x7f\xd1AY\x97\xceB{\x1d\xa7\xd5\x0f\xca\x0c\xa7\x0bx\xf2%\xf4\x9b\xb4\x9f~\x13\xf69\xcc\xea\x10#\xc2\x9e\x1ba\xba\xbaX/Dz\xa5f\xda\xcfX.\x82\x08$\xb6\xdbFuA\x9d\xbb\xc6MS\xba\xf8\xe9\xccs)jYx\xff\xd3\xc9S\x9e`e\x1a\xc6\x999\xe1\x0b\xe8\xa5\xf9\xb2\x1d\xdb\x81\xd7\xaaB}\xb7I\xe1\xd3L\xe4\xa5\x07\xf1\xa3\xf7\xec\xde{\xb2\\\xa1\x9fl\x1f\xb7X\xc6\xd9\xc2\xc9H\x8esrN\xcf\xc2\xc52\xeee#\xaf\xbc\xbb\\\xf6\xe5\x19\xdb\x1cxm\x8e'\xcf%5w \xfd\xdd`\xa2\xb5\xcb\x1bEF\xd2\xf2\x990\xb4:\x0f\x93ILNVi\xfb\xa6\xccw\xdc\xed\xbb\xa1\x0c^\xe7\x03\xe8\x1b\xbd\x85\xe132\x80\xcf\xe9y\xb9V1\x81\x86\x9dO\x9d\xc3\xf2e\x9bdtw\xb4\xeb8\xf8B\x86\xbc\xffbN\x96\xbb\xce9\xb9\xcb\xf7R\x12>\x92\x9b\xd4\x0c\x0c& \xda\x93\xe50R\x9b+\x06\x04c\x1d\xf6\x08\x9e\xc4\xd8M\x16\xfda\x0d\xcfkF\xbddX\xac\x05d\xc3\x1fi\x94\xb8\x8c}x\xfd8\x97EGm\xb0\x89\xfa\x06\xa0\xad\xf5(w\xbe.\x11\x1f\x81\x1fu\xe3E\x1e\x86\xe2E\x87\x7fz\xc1\x818\x91F\xa7\x89\n,\xad\x17\xf0\x10\x92\xb58\x02\x8f\xef\xc2g\xbdt\xd3\xec\xa6\xe9n\x8c\xf8h\x98e\xd1,a\x8c\xcc.\xa6\xd7\x92>o\xf1\xfc\xceMuE\xe4y\xb6\xef\xf3\x95\xa6bJ\x03]~\n\x03'&=\xf3\xc2c(8\xb4Ta\xac\xe9\x1dH.R]\xa0\x89\xd6\x1b\xc9\x90\xeb$X\xa7x\xda\xc5\x9aK\xd1\x83XO\x9ck\x19\xfe7_@\x02\xdbj\xa2\x7f3\xf6@\x99\xb9\xfc\"1`\x0e\x90P\x99tG\xd2\xf0\n\x05\x8a\xdaO\x91|,e\n\xdb4\x9a\x15\x12hm\xb3L\xda\xc7P\xce\xe3\\\xa6\xc1m\x1a\xe5%D\x99}\xaaI\xa7\x845xM\xee\x19\xfe\xf5\x0b\xbe\xff$\xa8\xd6X>\xa1V\x85\x91\x07\x01u\x15\xd2\xe0\x99\xc3R\xf1\x9eG\x07l{\x157\xb6\x9b\xe6\xc5r\xa6\xd8\x14<\x02F\xbd \x14\x05[\x9b\xdf|\xab\x0f\x86Q|\x91\xbbOn{\x99\xf7\x92\x8a\xb5+{\xad\x9f\xb3\x04\x8f\xf5T\x8b\x80\x95\x9b\xc2\xa1\xed\x87IBs`\xeb\x12B\xce\xfb \xccj\xa1\xd8\xdas\xd2!\x90'}\xbd:\xb0\xa3D\xed\xd9)\x99\x92\x94$\xe32D\xdc<\xca`\x1ef\xc9\xd79\\\x11\x92@\xc4\xaf\xb1D\x19\x99\xc0\x00\xb2bIR\xd7\xabA\xb0\xa1\x90I\x87\xf8\xb0\x86\xc7\x0dJB\xc9Z\x10\x1fm8\xbb\\P\x81\x86F\x0d\xfa\x86X\x843\xc2\x98\x1f'\xfa\x93i\xcb-\xc7\xa2y$\xab9d\x93`I\xd2,\xcarSX\x05\xc9\x14\x92\xee\xd3\xbdd\xa5\xe3kU\x1f\xd0o,=s\xaf\xb0\x1e\xd2~=dO\xe9\x06\xf7\x92U\xe1\x82x\xe9\xcd\x86\xe1\xaa\x12\x9aGS\xbc\xe68,\xb7oxYU|\xf2\xa4\x02J\xf1\x88\xa8G\xbe\x066\xd8!\x08p1\xf8\xaeZP\xe1\xcb\x92\x91\x0e\xf4\xeayUd29\xb7\x89\x12\x13-%?\x93\xfb\x03zk7\xa0\xca\xa7\"\x0f\xa9C\x8a\xda\xfa pFI\xceS\xc20\xf1\xfe\x9a\xdcsdNi:&\xc7\x12\xed\xbe\xc85e0\x10\xb2.\xbe\x8a\x8b\xf4\x91\xfdcUM\xf4\xbbb?\xb8\x86\x80\xf0\x11\xe9\xd7\x1f\x1eQs\x1b6\xbd\x92\x86\xba\x84\x0f\xf9\xc8\x05^\xc4\x06/F\x83V-\x03\xfc\x8a\x84=\xb5\x0f'\xc1\x84\xf2\xf1Z*\xdb\x97^.L)\x8a\xed\xa5\x1b\x0d\xf2I\x82(\x13\xbc\x8e\xdf\xd1a\x02L\xd5)\xab\x9f\x19\xdb\x07\xcd\xcb\\\x87\xddGtg\xd3\xd7\xcf\xbf|\x90\x0e\xa6q\x91\xcd\xfbN#TS\x99\xf3\x9a\xb6\xb4\x13Hf\x8c!\xc7\xab\xb4\xafEk.\x1a\xb2}NOXz\xea\x97\x93\xd4\xa7cI\xc3\xc4$\xce\x18D|Z\xe5r\xad\xfeS\xca\xba\xec5\x9f\x98_\xa0\x86\x03\x1b\xc6J\x0c\xe3^$\x91d&--K\xec8\x81\x04\x0d\xb31\x7f!Wx\x14E\x9e\xa4\xac\x08\x0c\xa2X\xfe\xfeR\x0c\xe8\xf1i3{\x07\xdf\xc1\xa9\xee\xe5\"(\xdd\xe6\x98<\xd6f\x8c\xd8\x8en_\xa9Aj\xcd\x87\x9d\"\xa81r1\xb2\n\xf4=A\x07?\x83\xe8|\xc6\x84O w\xcb\x94d\x19\x93\xda\x17E\x96\x03\x89\xf29I\xe1\x8a\xf0\x06h\xaa\xc8\xd2>\x06\x1dv`\xbd\xfc\x90\x862I\xa5\"U\xba?\xe7N\xae\xc8\xdb\xa8\xe8Pz\xd4\x8ei\x92\xe5i1\xcei\xaaS[\xe4#g\xc0L\xef\x95F\xda\x8e8\xa0>R\xff\xb4\xbbA\xa9\xba\xec\xd0\x94\x8cICK\x92{\xbb\x02\x1bYM\xa2\x86]\xd0\xbe\x17\xf3>DUN\x8a\xe5l:\xeb\xa4\xc3t\xcf\xf2T\xa0a\xbd\xf2\x81\xf630\xbf\x8f\xe2\xf8S-\xcch\x95\xab\x8b!\xaeb`n\xdc\xbf\xe8\xb2\x97X\xac\xc9\x7f\x89K\xac\xdcH;\xb7\xd0D\\\xc6\xab\x8dF\xbf}\xe2\xe8k\x8b\xff\xcf?\xcb\x8c\x85\xb84+g[\xc5\x01\xb7Q\xd2[\x8f1\xddi\xf6!\xa9<}\xb5\x93Q~\xac1}I\xb7\x01\xb5\xe74\xbdK\x16\x9f\x83\xbc\xb8t#{k\x92Xzw\xf1o8\x97\x10\xb9\xbe\xec\xf4\xe5*\x91\x15J\x8a\x04R\xb1k\xbfM\x82\xec\x95\"\x9b\xbc\xbaG\xf5\xc6\xe68\xc3\xa3-TUNP\x1f\xb1\x9c\xef\x8a\x90\x0fB\xab2\x03\x16\x02\xd0\xde\\\x86PQ\xb2,\xf2S25\xc3\xc5}\xcd1\xf2\x916\x9c\xff\xf4I\x1aUZ\x7f\x89\x07y\x19\x96<\xf5\x98\xb8\xb3\xa9XA\xec&aR\x9a\x84\x13n\x12\xc6\xac\x85\xf6\xcfK\x1d\xca\x08\xf4\x80~/\x8e\xa0\x18\xc7\x07G\x12\x85S\x1aQ}pJ\xa2\xc0d\xd1u\xa2\xc0\x83\xfb\x16Q4\xde\xf2y\xe7\xed\x8b\xb9\xe5?\xe4k9G\xd6\xd3\xffqG\x0cKt\xf3\x86]\xcb\xdc\x95_/\x1d\x01\xc4o\xfd\xbe\x06C\x08\xfb\xb6g\x88\x17\x0eC#\x910\xba\x98v\x0c\x89\x95\xd3\x8e.0\x1c\x96\xe3a?\x8c=)z\xb5T\xadB\x99\xba\xb4(r\xaeueb\xe8\xba\"\xf3=\xd8\xd6\xdd\xd7\xad\xcd\x06D{\x93h\x8b\xc2\xad-\xa3\x0d\"w\n\xd9\xc1\n\x97\xf8W\xc7\x99\xa5\xe5\xae\xa0\xdc\xd3\x9d\xd1\xdd\x92\x8cs2QM\xfcmBIa\x07\x8e\xc3\xe3v\x01cz\xce\x85\xf0\xf09\xbb_\\\xd1\xf8\x83\xa6~\x04;\xb0\xf1\x7f\x7f\xcf\xd6\xff\xfc=[\xffjc\xd6\x86\x08\x11\xe2b\xb0\xfea\xf3\xeebs\xf0}8\x98~X\xffjC\xe3\xe6T \xe4\xe6\xd5\xc5\xe6\x96\x01\"\xe3\x10\xf4bs\xf0\xad\x01\x841A\xcc\xad\x7f\xa8\x93\x1d\xd8\xde\xaa\xa4f\xa9\xe9\x81B\xe7:\x11NM;R'\xc3\xd7\xed\xa6\xa6\xfa\xa62\x12OY\x0d\xf5\x7f}\x9b\xac\xa4\xdd,\xdb\x80\xc6x\xf6\xcb\xfey-\xe7\xd9\x91\xd6\xa7y\x949\x9e.\xec\xf2\xa4R\"+\x16,\xd3\xe4\xb4\xc1\xe7\xb0\x03Ga>\x0f\x16\xe1\x9dF\xac+K#\x8d\xf8\xd2\xef\xb6'\xef\xf028`\xdbNBou\xf2\xa7r^\x07\xea\xb9\xd8L\xaf\x7fH\xddC&\xba1\x1e\xa8\xac\xad\xf1\xac\x18\xb5 \xd2d\xddiz\xa7\xea{\xa3\x89\x9e\x08\xd2\xac\xa0\xc9\x97nK\xd3\xc2\xeat\xebX\xa2\xbe\x93\xe1\xba\xab5\xde\xed\x16\xd0hD\xa0BC\xaa\x066\xc0Z}\xf2\x04&B`\xf3@{i\xe5AM\x13\xa4\xb1\xcdc.\x15KF\xa9\x9b2\xa8PmBdF)\xdc\xbdQ\xe5/\xffF'U\x93\x17\x1a\xec\xc0\x8cm\x86\xbb\x90\xc3:\x8f)\xd6u\xc6\x0c\xcd\x0cJk\x9a)\xac\x12\xe6\x13\x18\xc2\xba\xe6\xf3D\xb8\xdc\xf2\x84~\x11\xe6\xf33\x1f\x97\x16\"\x1d\xb4\xe5,\x90\xcdp&\xc1`\x17bW\xe4!u\x9f\xa2\x86\xba\x0bOa\x08\xdf1l\x84\nX\x8a\xfdk\xd0\xb3\xfaK\xf5\x8ci0\x17\xed\xa1>\x1e\xd1\xf9\x10a6\x99\xc2\x87\x0c\x85\x13\xf4w\xd7\x0b\x1cSn\xb2\xd3\x96--e\x13\xb4\xd9\xebIH\x9fpLo\xa8K\xbc\xc6v\x02\xea\"\xbe\xea\xf6w\xb4\\_b|2\xb2Jv\x8ca*\xe9\xdbx\xa0\x17_\xa8x\xdcr\x9e26\xae\xa1Js\xa75\x91;\xe5#;M`\x00\xb1\xb5gJ\xc0\xbd\x98\x11W\xc2T\xb6\x9c\xff\xb5\xcdu\xb7%zB\xc0\x00\xc6\xac\xac\xad\x04\xd8\xfax\xdb\xa9\xf4/l\xe1\xff/k\xf9\xc6\x8c9\xca\x18\xd5f$\x17\x82\x99{\xeb\xf7\xdc\x05K_V\x18\x80\x8b\xb8\xea\xbe\x9c\xba\x84]\xb8q\x13\x1fBYi\xec\xa1\x05\xdf\xb8a\xae6\xab\xa3\xce\x9d?S\x08i\x02\x98\x1dk\x17\xae\xf89\x82\xdb\xa4\xb4b\xb5\xaf\xdf\xf5\x99/\xf3JHx\x1c\x06\xcb\x8cR\xd5\xa5\x8c\xe7\xe4\xe2.\x10L63EJQ\x1bP\x086\xf3\xdaV\xfe.\xb3\x86\xa80\xe6_k\x13N\xee\xf90\xad\xf0\xa9W\x14\x01g\xd6F,\xe2^\xb42c\xed\xcf\\\xb9\xa6\x00\xfb=\x17l\x86b\x8c\xaeq\xcf\xd7\xf4\xdc\xe8\xc5\x95c\xe4\xe8\x1ccbn\xfa0s\x85\x15\x06\xf7\xec\xb54\x88 \xe6f\xe0Y\xb0]\xb6[;\x8b\xf0\xee}\x18\xe5\xdc\xfd\x8cq\x98\xb9{\xef\xa6\x81x-[B\xc3{\xe8\xe3&\xee\xe4i\x18\xc5\xc8K\xd1em\x17\x9b\x96/a\x08\x13L\xe0\xd7\xffhT\xb1\x00#\"0)\x98\xc4B&o_\xf1\xebG\xb1X\x15\xd5\xd2ic\x87}\xbd\xf7\xb9\xafn2v\xa1\x80!\x8c\xdc\x85kH\xf0U{\xa9\xb8\x87IW \x1f\x12\xf7\xd9\x96\xa8\xdc\xa1\xe5I\xe7\xc2z\xf7\x9c`#\x8c\xe3\xe0c\xe6\x0c\xe1\xf9\xf3\xe7~\xab\xb0\xc8\xe7\x1b!6\x9aq\xa8\xa7\xcf\x9e\xea\xa1\xd0\x88\xc7a\x9e}\xffL\x0f\x93\x92I1&i&\xc1\x0c\x1f\xccd\xe2! \xf7\x8d\x01nI\xc6\x83\xdb4\\\x0ej]|\xf6\xfd?[\xf0\xfc\x10)k\x8e\xa5\xdd\x01 8'\xf1\xb2\xec\xe9\xd3g\xed\x01I\xc0\xda\xb8\xbf7\x82\xd5\x87\xfe|\xb3\x8dE \xd9\x18\xfd\xf3\xcd-3(C@mH\xcf\x9b&\x06'\xd8\x98\x10\xb2\x1c\xc4Qr\x1d%\xb3\xfa\xb8\x9eo\xb61[\x83V\x06\xf7|\xb3\x8d\x83\x1al\x1c\xde\xd3\"\x97\xc0m\xcc\xd6\x80\xcb|K\x83<\x9c\xe1\x1c.I\x1a|\xcc\xee\xb0\xf2\xb7}+7+\xb6'~Bo\x93\x98\x86\x93A\x91\xc6r\x96\xbekA\x914\xad\x93\xc6\xd6\xd3v\x1f\x18\x10\xdeG\x18\xe4i\x98dS\x9a.H\x9am\xcc)\xbd\x16-?mO\x95\xa1R\xedGB\xf3\x01\x9d\x0eP\xc9\x16\x0d\xb5\xc9\xa3OC\xcb0\x0d\x17$'\xe9\x80&\x84Nec\xed\x89\xeb\xd3\x18\xd3d\x96\x03\xe9\x0e*\xdbj\xcf+kK]\x04[\xedE\xc0@\x1ak\xffi\x9bN\x19Ts\xe9?m\x13(\x8f\x9dP'\xcd\xf6\x8c\n(\xba\xccxV* \xd9\xee\x1c\xa7\xdb\xc6\xce\xa0YF\x02N\x1d\xea\xd36\xbd \xa8\xe6h\xdb\xd4$\x00[\x03n\x0f%\xa6\x8dm\xe6\xbb6Rh\x98=knn\xed\xceq\xa8\"\x9f\x0f\xc8]N\x92\x8cAo\xe0\x06\xda\xdct44\x83\x95\xcb\xe3\xc5l\x83\xf1\xa0\xabp|\x9d\xc9\xd5\xa7\xc1F\xb3\xce<\xcf\x97\x03\xd6\x01YG\xc3M\x9au\xd4\x89\xd6\x90C\x13\xbc\xda\x1c\xd8vQ\xf6\xad\x8dVs\xc5\x8c\xa7X+\xfb\xd8\x8d\x8b\x94\xfc\xbf\x82d\xf9\xe0\x8aN\xee\x07d\x12\xe5\xb4\xdc\x93\x9e\xb5\xf7\x04[\xed\xb2\xc3m\x8aiV\x13\xdd\xac\xb2\x1d\x95\x9fl\x13\xaf\xa1n\xf9\xb5\xf6\xb2\xc0\x1a5n\xf1\xcc\x80\xfc\xda\x04\x19F\xdb`\x7f\xcf\x0d(m\x92\xe1s\x03y \xe3Sh\xb8E\xbe\xedmJ[OO\xfb\x86\x8f\"\xb0\x82C\\HQN\x16%\xde\x0d\x0b\xa0YQE\x98F\x04\xd1\xd6Q\xa38p\x1b\x93D\x91\x01\xe3\xcd\x06\x16az\xcd\x98\xa1\xfc\xaea2[\xd5\xe8\x84\xc4r\x80\xcf\x0d\x84\xd5\xacD\x938J\xc8\x00\xaf\xb6\x859M\x07W\xe1dF\xe4\x97\x0d\xb4\xd6l\xa4df\xd5B4\xac\x89f\xcd\x1b\x9e\x02r\x90\xe5\xe1bYV\xd6\xec\x00 \xd6\x8aINjs\xb2\xd5\x1ef\x86\xb71\xb3\x8d\xa9\xc0\xdf\xd6\xf7m\"\x910\xb5\xad\xba=\xbd\x8c\x06\x9b\xdcF\xd3\x18\x83R[\xd2\xec\x94\x08\xd3\xe04\x9a\xcd\n\xc1\x1aD\xfeT#U\"\x9cF\x9c~\xde&k\x99\xd5\xeecc\xb4m\xc8\"\x8f\xe2\xba\x8c\xdc\x9e\xc4\x9b\x88\xdc\xd6`\x9e\x1b`RJ\xf3A\x94|$\xe3\xbc\xec\xdcw%\xa46]\x0d5^\xd8I\xdc\xa8fly\xd0\xd4\x8e\xda\xb5\xa5\xad9\xbd \x8d[Z\xfc\x06M\x0e\xeb\xb0U\xbb8S\xbf43\x8d\x92 ,\xf8\x0d\xa1\xaf\x1dX\x07\x02\xeb\xe0|\x1d4\x0d\xbdR\xd7V\xfa'\xff\xa2\xc15\xb9\xb7\xe6O\x16\x95\xc5\x11\x0e\x83v\x95\xcb[\x0f>\xd0 %\x19\x8do\x08St\xeb\x17\x1d)+\x8d\x98\n\xbe\xb5\xf9\x0d\xc7\xee\xc3\x07\xef\x1f\x0f\xde\x8b\x7fll\xfc\x1f\xc8h\x91\x8e\xc9Q\xb8\\F\xc9\xec\xdd\xe9\x9b\x9d*\xc3\xe1\xe0\xaaH&1[\xe7\xc1\"\\\xfe\xe3\xff\x07\x00\x00\xff\xffPK\x07\x08\x05\xef\x9fw>9\x05\x00\xf8\x0c\x1b\x00PK\x03\x04\x14\x00\x08\x00\x08\x00\x00\x00!(\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1f\x00 \x00swagger-ui-standalone-preset.jsUT\x05\x00\x01\x80Cm8\xec\xbdys\xdc6\x9a0\xfe\xff|\x8aG|w\x152M\xd1\xdd\xad\xc3:,k\x1d\xc7\x9e\xf5\xbb\xf1Q\x963\xf3\x9b\xb7\xa3UQl\xb4\x9a1\x9b\xec\xe1!Y\x13i?\xfb\xaf\xf0\x00 \x01\x10 \xd9\xb2\xb33\xbb5\xacT\xac\x06A\xdcx\xeec\x0b\x16U\x1a\x95q\x96\xba\xa5\x0f\xc4\x83\xdf\xfe\x00\x00\xe0dW\xbf\x92\xa8t\xe0\xf4\x14\xca\xbb5\xc9\x16@\xbe\xac\xb3\xbc,`{\xdb\xf4v\x95\xcd\xab\x84\xc0\x19\xff#\x10\xb5O\x81\xb8\x1e\x1c\x83#\xba\x91?\x9a\x93E\x9c\x12\xda\"\xfb+\x08Ws8\xe3?\xdc\xd9\x05\x0e\xe8\xb8k0g\xe2\xaf\xe0\xfc6\xbc\xbe&\xf9\xcfo\xce\xcb0\x9d\x87I\x96\x92\x0f9)HY\x0f\xa1\xec\xab\xf3\x87\x07\xb7\\\xc6\x85\xdf,\x89X\x8e\x9c\x94U\x9eJK%^\xd0\xe7&\xcc\x81\xc0)\xfc\xf6p\xf2\x87\xbaPT\x85\xd4\xcd\xe5\xca\xf4\x89\x17\xe0\x92Y~\xe1\x89v\xe9\x0f\xb1b'JU\xdavLG7\xcb/h\x17\xcaKl\xeb\x18r\xbfU\x9a\x1c\xc3\xd6\xa4]\xcc\xbb8\x86\xdf\x1e\x94w\x0fj\xa7|T%\x1dU\x14&\x89\x1b\x8b\xc1\xf9\x10\xfb \xfdJ=\xfa3\x81S\xd8\x1aK/\xea\xd6\x9anx\x9bi\xb0\x82S(}H\x83\x88N\x8b\xfe1\x87S\xf5\x10\xfa\xd0Z\xb24\xc8\xf8\xf9\xbc\xbf\x87\xf7x\x1c\x02vL>\xe4\xd9\x9a\xe4\xe5\x1d\xff\xb2\xbdBQ\x96.\xe2\xeb*\x0f\xaf\x12bY\x96\xb4Z\x11\xf1~\xdc~\x7fM\xcac\xc8\xd5\x15\xf3\x9a9\xd29\xa4\xca\x1c\xf4\xd1\x8b\x13R\xd2\xa3^\x06\x97\x97\xa4x+\xeeK\xeb\xac\xc9\x8f\xd8 :\xd7\xb0JJu\x0cp<\xec\xeb\x01{\x9d\x06s\x97\xf8\xe0\x84\x0e]d\x1f\x88:\xbdL\xdf\"\xbd;\xde\x0c\xdf\x99u\x9e\x95\x19\xbd\xa9\xc12,\xde\xdf\xa6b\x8f\xd8i\xc2\xef\xd5\xf6\xd7p\n\xce\x93y\\\x94\x8e\x0f\xa9\x9b\x06\x14pL\xc7\x07\xac\xda\x83;\xd3\xceG*\xf7\xefT\x05\x81\xa2\xcc\xe3\xa8tN\x94[\x99\xc3)\xa4\xee\xfe\xd4S\xf7\x94^\xa8\x99\xf39N\xe7\x8e\x0fNN\x8a,\xb9!\xf4\xcf(K\x8b2\xaf\":\n'N\x8b2L#\xf2~A\x7f\xads2\x8f\xa3\xb0$\xec\x935\x05\x1b)\xd6\xe3[s^\xde%\xf8\xb2\xa0\x7f\xbcH\xe2\xb0 \x85s\xa1\xf6\x9ca\xcfE\x14&a\x8eu\xc9_+\x92F\xf8\xdd*\\\xaf\xe3\xf4\xda\xb9h\xe6PJ`\xb4s\xf9\xe9dS\x1f\xaa\x936\x9c\xa1\xb7\x8c^\x9a\xdf\x1e|\xb1=\x9f\xc9]\xe1\x12/Xd\xf9\xab0Z\xbau\xd3\xadvE+;\x138==\x858\x88\xd39\xf9\xf2~\xe1\x12\xcf\x83r\x99g\xb7\x90\x92[\xc8\xdd\xef~N?\xa7\xd9m\n\xd9\x1a\xa1\x9e\xf3\x1d\x8c\x80\xc0\x08\xbes .`EJ\x88S\x06\xd8c\xac\x90-X\x9d\x92\xd5\xf9\xcb\x8b\xb7?!l\x0f\xbe\xf3\xb4\x8b\xe6\x03\x05\xcaA\x19^3\xc8\x81\xbf\xe8\xe6\xd1\x99\xb1?\xee\xef!\xad\x92\x84\xbf\xe3\x1b\x8a\xaf\xc5\xdf\xf7\xf7\x83\xae\xca\xd6X\xed\x9c\xb7X\x9f\x0bl\xb3\xf9%\xb7\xda\xba\xf4`\xbd\x81\xbc\xd5\xe6\x80a\xb3\xd2Ou>\xf5\xd1\xc3j\xcd/}\xd6\xfcL\xf2y\x8b_j-\xf9\xb0bE\xa5@\xad+\x1fd8\x057\xc5\x0f\x94\xd2\xfa\x83\n\xf1\x9f\x8f\xbf`\xeb\xf4\x14R\n\xea\xe4\xf3\x96\x1a\xce\x9bq\xcd\xd2Yy1\xf0h\xd2\xa7\x9a\x9d\x97y\x9c^\xbb\xc4\xa3\x18\xb2lUzh\x1f\xa8\xca\xf3\x81\x1f\xe9\xac>\xd2\xf5\xb9\xb2\x1dm\xd0F%\x1e:\xba\xc8\x87\x85\x0f\x89\x0fk\x1f\x96\x8c\x06\x81\"x\xdd\xa6r\xe83\xaf+\xfc\xd1\\\xe1\xa6\xaepn\xaepWW\xf8`\xaep]W\xf8\xc1\\\x81\x12\x88\x94\x0b\xc8\xe1\x18n\xe8\xbf3\"N\x17A\x1a\xf8\x81\x12\xf3\xae(\xfe\xed\xc1k\xe8\x0ds\x8b\x97\xbc\xc5\x98\x9eB\xd1Z\\\xb7f\xfe\xe8\nN\xe1\xb2i\x19\xbf\x91\x7f\xe3\xa7'\xadO\xe9\xf5w#Dvx\x98\x10hz\xb8?\x94Lv]\n\xec\xb7\x96\xf4\xdd\x8a\xfe\xef&\x8b\xe70F\x90\xb9\x9aE\x17\x1e\xe5\xa0\xe0\x18Ro\x16]\xf8@\xe9\xa2kZm\x01g\x10\xba R\xc6\xc7p\x87L\x98\xe9\x0e'X\xef5\x7f\x83\xf4\x96\x0f \xfd&\xf1Y\x87\x95\xbb\xf2\xe9\xa1\xa0P\x1e\xb7\xe1g\xcf\x87\xcbYt\x01[\xa7\x90\xe0\xcdu/\xb1\xc6\xda\xf3YOW\xf2[\x17\x7f\x9dB\xa2\x81\xd5f)\xf2 bw9\xf6\xe9I\x83S\x98\xd0?\xfeHI:\xfa\xc79\x9c\xc2\x1e\xfd\xe3\x03\x9c\xc2!\xfd\xe3\x07Z\xe7\x80\xfe\xf5g8\x85]\xac\xf53\x9c\xc2\x01V\xfbH\xdfN\x0f}\xe5\xc6\x17\x9b\xdd\xce]\xe3\xed\xdc\xd3\x8b\xf9\xed\xd4\xef\x1b\xbd\x9dO\x9c'\xd7\xed\xcb\xa9\xf7n`]@b\xe38\xaa\xca\xdc\xd2\xb3\x1c;\xda\xa8\xf3\x8c\x02H\xd2>\\\x1c\xde:N\x83b\xdd\x10F\xa7\xe0\x00\xfd\"\xa5\x18\xe7\x14\x91\x0f\xef(\xf7(%\x90\x84\x11q+\x1f\x9c\xed\xbfVYy\xe2x\x88\x99\xbe\xf3|\x08a\x04\xces\xfamL\xffz\xf6\xc4\xe1d\x9b\xf3\xdc\xb1m\xeffD)\xe7\x8b\xe5\xf2\x94a \xe2\x86\x9e\x0f\xb9\x9b\x07\x1f`\x04y\xf0\x1a\xbe\x87\xd8\xed\xa4\xd2\x04\x1f\xe580+/\\:\x07\xeb\"\x11\\#\x12\x94\xd9O\xd9-\xc9_\x86\x05q\x91{$A\xb1N\xe2\x12\xbf\x0e\x12\x92^\x97Kx\x0e\xbb\xeat=\x1f\x1c\xb6\x86\x94!\xe9C\xdc}\xe8\xc9\xa9R\xc6\xac\xce\xe9\xce\x89\xbbz\x1b\xa7\xf3\xec\x96n\"\xfb+x\x1b\x96Kz\x97\xf1\xdf3\xf1\xfe\xd8\xf2yA\x92\x05\xfd\x98\xfe\xab\x7f\x8a\xef\x8eA\xc0\x01\xd7\x11\x84\xe82.\x1c\xcf\xf5z\xf0\xe05\xc7\x83\xd7\x8f\xc0\x83G\x9d\xa4\xca\xbe\x8e&\xd9\x8d;\xfa\xdfC\xaa\xd8\x89\xb8\x03\x9d\x16\xa0Kb\x90m\xc9\x1b[o0#\xa5\x91d\xe5\x7f\xf27\xed\xe5\xcc\xe9\\b\xfa\xbf\x01\xfb/\xaf^6\xf8p\xbf\xc8\xf3\xf0.\x88\x0b\xfc\xd7\xdcX:\xb8\xb1\xff\xe57E\x9e\xf2\xb0\xb3J9nN\x17\xd0\xbe\x04;\xf2\xe9nM^\xe5y\x96\xbb\xce\xcb0\xfd\xae\x04\x8a\xdd)k\xbd\xcc\xe6\x90\xa5\x00\xec\xac\x9aey\x9bB\xb0\xa6\x15E\xb4e\xb9Vt\xb5\x9a\x1e\x94\xf3\x95\xdfi\x9f\xd0\xf6\xd2\xce\xd3\x89wq\xec\x03\xb9 \x13\xcfuXq\xd3\xfee\xd9\xc7\xbf\xcc\xfb\xf8\x97\x9b>\xfe\xe5\xae\x8f\x7fi\x18\x9c?\xdb\x19\x9c\xe5\xa6\xec\x08\xe5aV}\x8c\xce\x15o\x99\xb2Ns\xc1:\xd9x\xa5.\xdee\xa9\xf1.\x8ckY#3\xa0q-W\xc8\xb5loC\x88\x8c\x05\xbb\xbc\x94\xd5\xa1,\x0b\xf2\n\xc7\x90\"3\xb3b\x8c\xc3Rc^\x9a\xd3\x8f\xb5\xcf\xb0\xb6`rh#Y\xcd\xf7\\\xd7\xdc\xc8\xe9)\xb2:\xdd\x92$\x90H\xc6F\x90d\xa7\xd2\xc5C\xaf'\x05: Dr\xecf\xda?\xa0Oq\x1b#T\n\xf3\xebjE\xd2\xb2\xe0\xb4e\xdfw\xf4\x89\xc2\x82\xc0\xf8\xb8\xb7\x1eH\x02{r\x0be{\x0b\xf5\x07[\x9el\xde\xb2K\x0c\x94\xb5\xfe`\xe3\xd3\xc74\xae\xd0\xd4\xa6\xe7\xa1\xf3m\xab1\xba\xa1\xd6/\xecm\xd5\xea\x95p\xbdN\xee\xb8\xf2\xaf\xde@s\x8b\x0f\xe6u\x11\\\x87\"!\x904!\xb2J\xa5n\xcaE\xce\xfc\xa6\x93\x9b\xcfl\xdc<~\xe6\xba\xab\xe0&\xce\xcb*L\xf0\xe25\xbf\x10\x96x\x9cW\x17\xbc\xfeG\xfa\xcd%\xfd\xdf\x16\xb2\xfc(\x0f`\xdc~\xe2yV\x8e\xfe\x1f\x85\x8b\x9f\xeab3.dk\x953\x1cu\xa8#4\x8a\xa2\x8c\xca\xc3f\xaa$X\xb06\xf7=83W\x96\xd5n\x16\xccE!H\xee\x96\x9e\x8f\xb0'\xa3gtk\x8c\xdc.jL=\x03Y\x04\xcd!\xaa\xeaf\xd5\x0d\x91 \x9f\x87V\x7f\xce5)\x1d\n\xbc\x91\xb8r\n\xf1\xcb@>\xbe\x88\"R\x14Y\xce\x08\x8a\xa2Z\xd3\xfd \xf3-\x0bA\xe1\xdc\x84IEx\xdb\xf4\xd0\x95\x0cY\xa5\x01\xbe\xf0\xfcMI\x0e\xf9\x08l\xa5\xee\xf4\xc8\xb3\xf3\xfd|\x0cO)\x9e0+~\x7f{\xe0\x8a\xcb\xf6\x82\xa2\xe6\xb6S\xa4 w\xd1\xbe\xa0\xea\xfa{A\xd8\xcc\xb3\x9f\xd8o\xe4\x1f\x9a\x1a\xb4\x8f\\\xb4\xebWS\xa3\x06u\xc8\x92K\x82j\xcb%\xda\xdd\xb3\xb0\x85\xa9\xbb7\xf5\x14dk>\xf4\x82\xc5\x0e\x16\xbcF\xecNh5\x99t\xef\xbf:\xb5\xf1\x01;b\x1b\x9f-I\xe67\xb1L\xa8\x9b0\xdf\xa2\x17\xb7}iT\x1a<\x05\xc6k\xd8\xaeL\xdf\xa0\xfb\xf8`uX\xff\x8d\n\x8dne\xba\xb2rCd\x82\x88\x9bc\x1f2\x1f*\x1fB\x1f\n3\xa8\xa4@d\xcbHc!\x03\xd0\xc6\xb9\n\x8fL\xc9T\x88\xe8\x1c\xc9-p\x18\xf76N\x99B\x8e|\x89\x08SJgQT\xe59\x99\x9f\x00\x9dd\xb9$\x90f\xe9\xceJT\x9c\x93\x1b \xe9M\x9cg)\xc5\xffH\x0e\xd3J\x8b*I\x80\xd0VaE\x8a\"\xbc&\x10\xa6s\x08\xe7sTe\x87 ,I\xb2^T \xdc\x86y\x1a\xa7\xd7E\xa0\x9f\n\xfa\x90\xa4 \x1dD*E;3}\xb1.\xcct>}(\x86\x1f\x9bi\x11W]\nR\xcb\x80\x9f\xfck\xf1\xe4\xda`\xdedz\xf8A^\xcc\x92\xd1\xe8\xc2X\xeb\xc1\xf3\xbc \x0dW(\x91}\x93\xde\x84y\x1c\xa6%\xfc)\xce\x92\x10)\x99\xd6WmJ\x8c\xdd\xb2(X\xe4\xe1\x8a\x14\x9f\xb2\x0f\xd9\x9aQ\x1a\xd1\x1f\xcc\x1f\x0e\x82\x01}\x16!OM\x9c\xae\xa4\xac\xeeW\xec\x0b\xb6bvaa\xa3\xd8\xa5\x8eS\xca8\x90`]\x15K7\xed\x10V\xab\xb35_\xacD\x9d\nW\xf2\xca@.\x0b\xe2tI\xf2\x98\x83\xed\xdd}O\xfd\x84\xb1\xe8\x93C\x1d\x03p\x1e}\xf2\xd4\xd8\x16e\xbf*\xe9M=?\xdaK\xec\x86\x0d\x91\xeb\xf9x\x0b\xc7'\x10\xc13\x10\x1c\xd0 D\xa3\x91\xbe\x88\xe2\xc8\x17\xb3H[\xc2\xa4io\xb6`\xcc\xb1Vt\n\xa1R \xa3\xc2f\x94|\xff \xb1\x80\xf9\x16\x8b\x97x\x9e\xccY\xd0\xef\xd4\x91U\x1c\xfb\"\x9b@\x89\xbbP/@\xa9\xec\x16\xb3,(\x83\x9c\x84\xf3\xf0*a@\x98\x1bi\xf0\x92S\xd8\x9a\xb4\xea\xdf\xe6q\xa9\xd6\xafKD}Z\x18&Iv\xfb\xefa\xb2x\xbf&)7\xbdS\x1bRk\xd4\xad\xb5>\xac\x9b\xcc\xd2\x88\xb8\x0eA\x83\xa8u\xf7r\xae[P\xc3\xd0\xf6\xfd=+\xbd\x14\x138/\xc3\x92\x04$\x9d\x13\xb4\xd6\xc9\x83\x94|)?\xc5\xd1gw\xc9\x86\xd0\xdd\xe9\xb2\xbd\x87%m\xcd5\x89\xf2\xccTb\"\xf3b\x8e\x18\xd7\xbf\xc7\xd7\xcb?\x87%\xc9\xdf\x86\xf9\xe7\x16 \xa9\x18\x06j\x86\x83\xfd\xa4\xa5$\xd5\xd4\x17b)w\xab\xde\xfdfB\x9e?h*sR\x94yvG\xe6\xad\xe1\x0f\x1e\xa2$\xcea\xa3\x15\xe7\x14G\xab |\x0c\xf3i\x8e\x98\xfaeP\x8f\x8d\xd60-D]Acu4a\xa12\x113@\xfe\xfd\xa7\xd0X\x9f\xd9&A\xabx\x1d\xdb)m\\p\xc9\xbf\xea\xa3\xfc\xb1C\x86?\xaa$\x11\x17\x16\xcf\xbe/\xdf#\xe2\xcb}\x7f\x13499\xda\xb3\xea\x8a\xec\xbb!\x8e=\xaetN\xd7\xb56\n\xeb\xa3\x8a7\x1c\xdf\xde\xc1\x9e\x01\x8f\xbf\x0d\xcbe\xb0\n\xbfv\xeds7\xde|\x02\xd2\x80\xcc\xe3\xd9\xb73\x88LZ2\x90\xb5\xfb\x87a\x10\xa7\x87\x1b/\xf0\xdf\x85A\x1c64!\xaci+\xc1J8\x93\xee\xa0\xcd\x19\xe3\xdb\x8f\xa8S\xc8\xb5\xb5U\xba\x1d\xf2-\xebg\x9a\x85\xeec\xf7\xdeb\xaeg\x16$\xee\xeb\x06\x96\x8c\x90>:\xf4\\\xa7\xc8#\xdd\xd4\x81\x92\xd3\xb5\xd0\xb6\xcc\x98\x1dI[\xfd\xe5:\x0e\x8c \xf4\xb8=\x8a#j\xca'\x06-\x08\x838-\xd6$*\xcf\xb3*\x8f\xc8\x90C \x08S\xe9f\xf96K \xc1\xa5\x87&\x12=\xb2Y`\xa4\xea\xa9\x8e\x10\x7ffn\xea\x83CYB\x07\xf5@q\xf3\x9b\x1e \x8a\xbc\xe8\xadm\x8c\x97\xa4\xcf\xaa\xe6\x8b\x8a\xd7;\x03\\\xa1\x92i\xb1\x8a\xe0\xd7,N\xdd\xda\xda\xd7\xc3\xf6\x90\xe2\xcd\xe1\xac\x86\x07p\x0c\xa1\xf8\xa9\x94\xc6\xcd\x818\x06wN\x12R\x12|\xefK\xaf\x14K\x8fF\xf2.\xd3[\xf56u0\xd2\xe2.\x1a\xef\x19e;894\xab\x90\xc1\x91\xf8\x08\xb9\xffot\x0d\x7fo\xc0\xb01\xd66_\xbd\x03\x93\xa2\xd9M\xdd\x83\x03\xcf\xc7\xf7\xe3\x86 \xb69\x98\x18\xaf\xe9\xe4@7\xf3\x0b\x8d\xaeT\x9f\xc9\x9d\xd9\xff''\x0b\xf3\x8b\xcb\xcb\x82$\xf6wx]\x8f[ \xcb\xe4%VX\xb7M&[\x83\x9c,\xa4\xcdh7\x13\x0dk\xe63\xb9\xd3\xf6\x14$\x96\xbc\x0d\x1ar!\x962\xc2\x88\xb6\xbc\x92>\xff\xf2/\xec\xf8\x1cC\xd5^\x1c\xfa\xea\x18\xca\xf6\x0b\xdc\x03\x83v\x1b\xb7 m\x97\xaf\xf3l]\x1cChX\xff\xec6%\xf917j\x12\x8f\xd9\xfbI\xb2]\x91\xc4\x1cA\x94\x93\xb0$\xaf\x12\xb2bn\x15}\x94 \x9e\xf1\xda\x17\xa25\xa2\x84\x9e\xc6*I\x0c\xb3\xe0o\xd4\xc1QZ\x83\xdfNY\xdc/\x1e\x14\xc3\xe4\x10\xd3\xc3CP\x03\xef\xae\xb9\xef\xc7\xc2\xf3!\x12\x85 3\x98\x1c\x01\xa1\xfb\xee\xf9 \x8bM\x03v\x84\x05\x1c8\xaeK\xda\xd5\x18\xf2Q+b\x19\x02\xa5\x8c\x810\xe6\xbb\xb7\xbd\x0d[\xa1v5]V\xeeV\xcc\x93\x11\xfd\x1fOZ\xcb\xb7\x84S\xd05\xe8\xb0\x03\xd3\xf6\xca0Y\xc7\xd2\x83*\x88\x96q2\xcfQ\xa4\xa1\xa1%\x94\xb9\xd2\xdaKx\x0e\x13\x13YQ\x0b\xb3\xe6\xc2\xac\xcd]\xd25bb\xac\x1bx\x06\xcb\x13\xb8\x19\x8d<\x98\xcfn.\xe4\xd1\xcdn`\x04S\x83\xfco\xec\xabc\x9a\xab'\xb05\x13\xee\x15\xc8=q\xe8z\xb5\x84\xe4\xc0\x97\x07\x8dO\x94\x9a\x16\xf1#\x9e\x8b;O\xdeD\\xi\x07\xee\xe8\x0et\x0cM\x08\x80\xe9ig\xee\x03c\xfc/\x0eP\x8a\x9e\x96\x14g7\x17\xc7\xaf/\xcc\xeb0*\xb3\xfcn\x90G\xa4v\xc9\x82\xab8\x9d\xbb\xdc\x07\xc9L8\x93@(\xd75/\xc5E\x10%YJ^\xa4\xf3\x8fL\xdc\xfd\x1f\xa4\x97\xb9n\xe6\x18p%\xbd\xcf\xa0,\xfd\x87\xdf\x03\xfa\x07?\xe7e\xc0\xa0\x8a\xcf4\xfb\xebB\x9f?\x1d\xc0f\xf0\xa2\xaa\x0d\x9brTd\x8a\x86\xdb@\x02m\x9b\xe8\x15n\xbfB\xc1\x03\x0e\xbb}j(\x12\xed\x9a\x8b\xb79\xd0\xa9\x14\xa03\x17@\x87\xdd\x9a\xfax\xc80h\xa9\xc3 \xb6\xde\xec\xe0#\x1e\x97\xcft\x0d\xb6\x0c\xef<\x0d\xdaT\x16h\xc3\xca\x15\x15\x11%\xb6T9P\x02g\xb0\xa6\xc5\xa7\x90\xd0\x7f\x8e\xc5/Z\xd7\x00\x9d\xee6\x84Nw\x1e\xac\x87@\xa7\xbb^\xe8t]C'\xbaz+\x06\x9dV\xf0\x0c\xeeN`E\xa1\xd3\xf5l\xa5B\xa7\x95\x05:)\x03\xba\x1et\xff\xf9\xddX\xfa0\x17@\xe0F\x95\x13\xd3\xc3\x1f\x17\x7f\n\x93xn:\xfe\x9bP\xa4\x8a\xbc\x88\x1d\x10AJ00&\xf7\xaa\x10\xc0\x7f\x80~\xe2T\xd2\x0e\x1f\x98Y\xc0\xdd\x83~\xa9@\x87\xb3\x03c%\xcc\xa0+wS\x8f\"P8\xe6\x87\xb0\x99\x8aq\xec\xfa\xc09%\xa6\xab\x8a\x8d\x04ef\x10\xd3\x0b\xc3R\xae!-H\xf9)^\x91\xac*a\x192\xb1\xc5\x15!\xdcK\x97\xcc\x9dn\x91|\xd5\xdfA\x94\x900\xff\x8a.B\xb3\xfc%\xc5s\xd0\x8c\xbe\xd6\xda4Et\xf9\xc6\x06\xc8\xc6\xbf\xcd(\xd3\xb5\x95\"\x880\xb4C\xf7\xb1)\xf6{\xda\xed\x94r\xa4\xec\x0b\xf5\x9a 9\x87\xd1\xa7\xd5\xdc\x1c\xb4l@8\x92l\xb5\x0e\xbd=\xb4\xdb\xe2\n,s[\x16\x10\xf1\xb0eg\x7f\xcdsHm\xb2\x04\xe9 \x9e\xc9?Z\xc4{\xa7\x80(\xad=\x18\xea\xfa\x03\x06\x95\xdb\x06\xa5\x1c\xde3\xf5\xe7\xb1\x04\x85\xa0w`\xb4\x8b\xca\xb6\x8a\xae\xa6\xa2-\x98\nu\xa6i\xfe\xd1\xfeV\xd3@Q\x0c\xb931]\xfe\xb6\x8e\x8e\xf9? J\xe4M\xd5\xeaY:9z\xe0\x83(K\xa3\xb0t#\xb4/\xc4\xb6}\x88D\xa5\xedmX\xba^\x9f\x96\xcet]\xb7\x166j\x96\"\x89\xd0]\x1b\xd4\xe28F\x83uC\x8d\x0f)\x01\x18\xd5\xfaerb;\xe7\xf8\x01\x85\x92\x91X\xd7\x13\x18\x8d\x12x\x86\xdf\xe0\x82\x14\xb3\xe4\"\xc8\xab\xd4\xb5X\xbc\x8a\xa5\x90\xbb\xec\xb9%\xc0%|\xec\x8e\x9a\xf6N\x865\xbc\x92\x0b[Jk\xbd\x1d\xdeP\x85 \x90\xf1d\xc6F\xe9\xa9\x95_\xf8\xc3\xbb\xb1\x830\xf1\xe4n\xd9\x864\xe2\xe9\x87^\xe2\xe9\xef\x08d\xb5\x83\x0c7\xed\xdd\xc3FC\x80V\x07\xc2\x1a\xa0\xbb\x03\xfb\xec\x8do\x1e\xf4\x05{\xe8\xbc\x89s\xbb*qQ\xa5\x92&3\xa44%%x;\x9b\xbbq\x15\x8b\xd3\xb8\xd6:\x0e\xe2\xf1(E\xc0hW\x03\xed<1`\xe9V5J\x1d\xdba\x01\x9d\xcf\xe4\x04Rx\xd6\"\xceO \xa5\xc41\x99\xa5\xb4+\x95@N5\xe28\xe2ZVr+\x96\xcf\xf3a\x82th\x0d\x05\xef\xef\x01\xa3s\x84\xeeR\xa1~\xe7\x92D2\xaf:=\xa6\xc4&p\x9bs)\xde\x06\xee\x85\xd2l\x1c\x94q\x89\xd6\x1f\xceU\x9e\xdd\x16$wh!\xff\xbb\x89\xba\x94\xde\xf0\xf0\x1bq\x10\xe6\xd77\x0c\x7f@\x1cp\xbbAd\xbe\xa4\xdfE]\x1b\xdf\xdd\xe0w\xf3\xf9OqQ\x92\x14\xdb\xbda/Q\xd9\xc0\xfe^,\xc4\x9f9Ye7D\xaf\xccJ_$\x89xQ\x887d\x15\x97\xe2\xefuN\xd6$m\xf5\xc4\x8b\xdf\xa7Q\xab\xddDj\xae\x97\xa1\x98]\xa8\xabw\x15\xa7\xf38\xbd\xeeVR\xe9T\xeb:\xcf\"R\x14\xf5\xc7\xb1f%\xedh[\x14\xdd\xce\x07x\xc89O\x1c\xed\xb3\xe5\x0f\x18\xd9&\\\x88\x91R\xe22y&\xc8\x81\xb3\xe1\xbd\xf9\xd3\xab\xcb7\xef^\xbfy\xf7\xe6\xd3_\xb0\xc6\x04\x9e\xd8V\x9a|)I\xda\x8a\x8bh[\x02\xa6\x9dk\xd3Q6\xf9-.\x0d[:7S-\x9f]\xe2y\x0d\xed\x04\xcf o\xd6\xae\x9c\xc5\x94\xc5\x9e\xa5\x17LD\x1a_|\xfb+$J%9\x9d\xd9]\xa5\x15\xd4\x8fYj\x8c=\xd35\xac:5v\x063n1\x95 N\xa3\xa4\x9a\x93\xa1\xa1\xcb(\xa7_\xf7\xa5\xbc~\xe0\xc6\x0fC[2D@3\x8c_<\x84\x85\xc7C\xe5.\xfdk{[\x84\xc6ce\xf8\xe7\xf66\xe4\xc2\x12\xbd\xd5\n\x1d_\xca\xde\xea\x9c\x06\xbeY\xc4IIr\xb7\xf3-IN(\x11\x17\xa2\x17\n\xfb\x06\xc11z\x0d, \xd4\xe3\xa740d\x0b\x08\xa1\x88\x96d\x15\x06\xf0F\xbcb\xf1\x0d)>\xc8\x16PT\xd1\x12[(Z\xc4a\xe0\x18\x8e\xe3\x12C\x1b\xae\xd6qB\xe6o\x9a\x95\xab8\x0b\xeb\x88\x018>\xcc.\xf4\x0f^}i\x7f \xd6\xd3\xf8\x01E\xcco\xc3u\x17E\nB0\xc4n\x90\xd1\xae\x80>l\xb1\x8e\x8dZv|\xcf\xc3j\xdak\xf0`\x9b\xf6\n\x8b0I\xae\xc2\xe8s+V.}d\x89{\xfdA\x07\xce\x17O:cW\xf1b\x86\xd7\x94\xf9P\x8a\x9e\x9a2C\x0c\xc3vw\x14\x90\x97\x0c\x90\x13\x83Z\xea\x04J\x86\xf9J\x0e\xbd\x1b\xc6W\n\xaf\xa8k\xff@\x12\x0d\xab\xe7\xc55\x9e\x16\xcb\x99\x90/\xb7\xf8+\x0c~|\xf5\xfa\xc5\xcf?}\xaa\xe5b\xa1`\x19:N\x848\x0d\xea07\xf1\xb5\xef\xf2\x80G\x01\xa4\x18\x97\xb6\x8e\xb3\xb1AyF\x9f\xab\x9c\x84\x9f\xdb\xaf\xba\x9c\xe1K\xada\xbd\xab\xc9f]q}\xa8\xa5/\x19\xc8\xfc9\xcf\xd2k`\x9e\x81\x08AD\x97x~\xce\x194\xe1\xbbP\xb3v]F\x01\xcc^\x81\x02vN\x0c\xd6N\xceM \xf3\xe5\x0b\xc8\x0d\xc9\xefz\x80\xa7\xc0\xb3\xb2\x1bN\xa8\x01*\x0dn\x9e\xd7\x916\x05XDn\x88\x83\xc6\x02\xdc,\xa7\x802N\xaf\x13\xc2g\xc8Mq=\xca\xa0\x95a\x9c\n\x98\xab\xbcm\xf9\xec!wA\x1e=\x8dl\xd3i\xd4\x81B\xb59P\xb8i\x9b\x81\xf4\xae5~q\x8f\xc9-\x84\xae\x01o1\xf4id\x89\x05\x1c?\xd6\x1d\xd3\x14\x11\x83\xcc\xa4\xb1M\x1bj\xab\xf8\xdb \xcaP2Ho\x05\xc6\xe4\x81Om\x16\xe9\x83}\xf9j\xcdl\xe9C\xac\x83\xad^},s\xee\x16\x06\xa1\x9b\xb2\xaf\x9a\x0e\xce\x0b\x8a$\x8e\x88{\xe8\xc3\xce\xa4o(\xdd\x0e\xf5{\xbb\xff+\x1d\xea\x87-\xeb?\x80\xd5\xf9\xb7:\xf7\xfb&?U\xe6\xdf\x12\xa7\x8f\xa3\xec\xb3\x9eC:@/+\xb7=\\7+\xf5\xf1\xa3&F\x1d4z\xfaQ\xcf\xd8\x91\x86\xda\xb8a\xfcJj\x19\xc3\xc1\xc8\xb21\xac`\xeaO8\xdc\x0e\xeeR\x81\x9e]G\xe6C\x1e\xaf\xe22\xbe\x19\xbcL*\xa1i\x04\x1d\xf8\xc2p\xbdX\xfc\xc5\xf6\x05a\xe5\xed#\xaeS\xb2FPW-\x16x\xe9\xcb\xfaG]\xed\xc1\xab\xddaR\xf7\xe0\xd0\x0b\xd8{\xb3@es\x0b\x06\x03\xe9\x8e\x1b(9-s=\x80\x08\x06\xf6\x97\x17o\x7fz%\xc2\xae9u\x82\xaa\xb0\xc8d\xdb\xc3U\x98\x7f\xe6\xa6?\xf8\x93\xc7V;mb%\xd1\xfat\xcd\xdc\x8a\xa7`be\x1ef\xb0p\x9bF\xcex\x02\x8c\xba\xa4\xc6b,\xf7\xa4\xe3\xf9\xf5\x90\xd7e\x95\x93\xf32\x8c>\x7f\xcaCth\xb4\xbc\x11\x86\x9cK9\x01X\x86q\x88\xb1\xac\xa05\xd1EYXhy\xbc\x8c\x0eY\xb2\xf6\xaa\xff\xca;,\x9c\xd8 \xe4HZ\xb9\xd5\xf2&W_\x8a\xb9\x0e\xa3U\xea}\x1a\x81s\x0c\x8e\x91f!h%\xd1\xb7 >l1\x07\x9dz\x1f(\x85C\x9a|$\xa6\xed\xd0s\x0b\xca\x94\xd6\xa0\x84\n\xbd\xf6\x026\xf7\x1d\x96\xcdK]\x95Z\x08>K\xdd\xe9x\xeaiV\xf7B\x01\x8a\xef\xf7w'\xe8\x88\xbe\xbf\xdb\xaa\xd7\xc8\xcb\xb1\xde.\xaf\xb7\xc7\xff\xdd\xe7\xff\x1ex\x92\xc5\xcbc\xc5\x9dv/\xc66(S\xcc\xda\xdc lCip,\xd4\xcc\xd6\xdc\xa9\xa5\x9ed\x00\xe7\xeeY\xeap3;Mm\xa0\xdd\x85!ru\xcd\xc4.\x17\x82\xcf\xb8\xa3Q\n#\xc8\xbd\xe6\x00\xef\x1e<>\xae\xce\xe3\x03\xfapV\xea\x11a\x89$%\x8a\x1e\xc4\x84\x87\xf7oE\x1f\xcax\xb9\xce\xb0n\x10=\x99\x05\x8c\xfdg\xf4\xe4\xea\x9bDO6\xdd\x8f\xbfOPa\xd3H\xf0ZF$N,7v\x91dY\xde7:\xcb\xd0\xe2\xe2]\xf8\x0e\x15\xce#\x14#\x8c\xe1\x18\\\xa1\xc1\xc81OZ\xbfD\xc1.\xaa\xe9\x0f\x10\xdcw@\xd5\x10\xb4|\xd4\x9a @X+\x18\xad\xb7\xba\xcc\x13xs\xf5h\xac\xe6_R\xe5\xb2!\x05\xdb\xf27\xfa\x18D\xd7]\xa6\x0b\xad1\xf4\xe4Nh\x0f\xc3\x1a\x9b\xdf6\x92\xdd\xe1#Ah\xb0\xe1`\x14E\xaf\xfc\x0c\x90N\xd6\x9dw0\x0e\"\x9b\x00\xb1\xa6\x12\xd8\x04\x1f\x0e\xbb.qoB\x99\xded2\x8f\x0dTf\x8f\xaefQ\xdaO\xc6\xbd\xb7\xce\x02\x0d\x1e\x15\xd6\xae\x8f^l\x85\xfc\xe2\xf2Z}\xf0\x0c+\xb62\x06VbNm\x19m\xea>\x16\xbe\xdc\xf0\xa8:\xa1k\xa4\xd7\xb0\xed\xca\x87\xc2\xe7\x99\xf0\x0c\x95(\x1e\x8efcC\x00\xe9\x04\xdf\xe8&G\xd9\xb0\xcc{\x1d\x9a/2+.\xba4\x9fZu\x83q\x80\xcf\x8c\x12xv\xbf\x96\xc5(\"\xcf\x98\x07\x00S\x1c\x17|X y\xc0\xe41\xf2\xab\xc2\x87)\x93\xb5\x9eu\xe3BhF\x96\xd4\xf8\x90q\x80\xfa@\xa0/\x16\xa9\xb1\x1d}6}\xc7Xn\x98\x91U\xbf=\x18\x15\xd0\x8f\xbf\x04\xc3.\x9f\xa2\xeb5y\xf01\xedo\x13p\xfd# \xa3\x92\x07L\xff?\x0e\xcf\x84\xec\x9c\xc0M\\\xc4%,\xcbr}\xfc\xe4\xc9\"\x8c\xc8U\x96}\x0e\xae\xe3rY]\x05q\xf6$\xa7\xdf=\x99gQ\xf1\x04?\xde\x99\x93(\x9b\x93>\x81\x9c\x999\xe6\xa3\x91\xc7,\xd5\x9d\xed0\xbf.f\x17X\x8f\xa4\xb4\x89\x9f?\xbey\x99\xad\xd6YJRY\xaf\x96\xc3\x08&\xba\xf2\x8c\xb5\xa1\x06\x7f\x17\xa2\x89,\x1f\x1e9\xbe\x89\x1a_\xf4\x87\x8b?i]\xff\x18\xe4\x10\xee\xba\xaa\x8e\xc1\xf4\xb83\xfa\xba\x0fq;\xacz\xdcs\xea\x06\x9d\x1b\x89\x82\xb2q4\x8f`\xe5\xebb\xf1I\x87\xf7\xcc <\xac^\xb8?\xb4\xff\x12\xeb,\xb7&\xc1\xb78(\x97a\xf9\x11[+\x98\xd8E)z\x1d&\x05Z>\xba\x18H[y\xf7)\xaf\xf8\xab\xb1\xfe\x8a+\x17r\x11\xcfW\xfdn\x19w\x9a\x8f\x88\xb9)\xf9\xf6\xb46^\xf0\x03>\x04\xa5\x9a\xfdO\xe0\x94\x1f\x94\x8d6P\x94v(\xa5\x9e|\xbf\xa5n\xd7\xf7\xf0iI\xe0\x8a 7W\xd9\xbcJ\x08,\xf2l\x05i6'\xc1\xaf\x85__D\xee\xf4\x1ah\xdf\xeb\xcd\xfd[X\x95\xcb,\x07\x80\xd7$\xcf\x8a\x02^\\e\xd5\xe7e8\x8f\x7f%Kx\xb6\xc0\xc2\x7fc\xff\x04Y~\xfd\x1c\x9e \x88\xd4\x94\xb5\x1a\x15\xf6H\x8aA\x12{\xf9\xa4uu\xb9\x1c\xaa\xc5?CC\\\xb4\xb2\xe4A\x93X\x0f\xef\x94\xf2\xb2\xbe\x10\xed\x98+\xd0le\x11|\xfa\xcb\x87W?^\xbe\xf8\xf8\xf1\xc5_.\xcf\x7f\xfe\xf0\xe1\xfd\xc7Op\x06\xd3\xc9\xde\xd3\xbd\xc3\xdd\x83\xbd\xa7p\x0c\x93\xf1\xd3\xdd\xa7{\x93\xc3\xa9\x96\xef\xd6\xd2ah\xc5\x95\x94\xe2\xa4\xc3yF_7\x86\x17\x1f\xc3\xf4Z\xf0\xc9\x14(%\xf1\x1cI\xd190Os\x865:\xcc+l\xb3p\x85\xbd\xd3\xcfqZ\x1e\nCc/\xb8\xbcDl\x7fy\x89!,\x1a\xf9\xea\xb1b*\x82l7o\x00}\x9c\xe8a\xe7\x18\x8c\xe5\xb8\xd3\xa1\x85y=\n\x1b\xc5\x06\xc2\x88\xcb5O\x80\x07\xc4\x97\x95 \x85\x9an\xa0i\xba\xbd6H\xde\x1b\x14\x0d6\x12\x0b\xeb\xb7\x15\x10\xcaN\x89MZ0\x1c\xc9=\x9d\x8b\xda,\xb9\\\x12\xe6\x86\xb2\x88\xf3\xa2\xac\x11?\xac\xaa\x02\xedgB(Z\xd1j\xe5G\x10A\xf6x\x08\x0f\xb63\x105\x01i\x0cr\x1c\xcb\xd6Db\xfd,\x0c\xaae\x0d\x89\xd9l\xe8;!\xb5Q\xe7\xcdm\x87BnR\xdf\x91~\xda\x9c\x89\x16\xcf-W\xe5lo\x03\x91\xcf\x83\xfc\xae\x1dK\xbb\x83\xedFW\xbf\xe0\xea\xae$?\xe1\x89\xf6\xd1\x0co\x0c\x98\xeb\xba)\x86g\x8d4K\xbf\xaa\xdfe\x8bEA\xca\xef\xe8\x11\xc8*4G\xbf\xca\xaat^\xd8vW\xef\x936\x0e#p1\xf7\xf0\xd8\xb3\xf6\xc3\xee\xdc\xf0~0\x00A#cI\xa5\x00n\xa7<\xf0o\x0b(\xd4F.\xd6*x\x81\x8fM\xc5t\x99\xcd#\xe9\x04L\xa4\x0b\x10\xd1\nk\x06H;\xaf\x8a\xc1\xd0O\xd9\xfdc\x93R\xb1\xc5\xd8tx \x1a>\xc7\x05\xad\xf3\xc9\xdf\xdf3\xe7P\xa7*\x17\x87][\xbfU\x04q\xf1\x8a\xc3\x0d7\xb58`\x7f\xe7\x08\xd0\xe2H`\x83!\x056\x94\x1a\xf6\x98n\x12H\xf8t\x0c\xf70g\x1bg\xf6\xd7\x02\x8e\\]\x16T\xa8d\x86\x8e\xb7y\\\x12\xd7\x02U\xd9'u\x96\x02\x97\xf9\x042#\xfc\xb1\x0f\xb1\xf7\xe8\xed\xf2\xfaL\x1f\xc5C\xd7\xb2\xa8\x15\xba\x141uH\xb3j\xd5\x08\xdc\xc3\xd2%\xc2\xe7\xc9\x166c\x08\x906\x9a]Iu\x82\xb8\xf8SLX\xda\xfdv\xb1\xc9\"L\xaa%\x8f\xb4!0\xdb\xa3\xad\xa9\x99-\xd5R\x0e\x11\x1dK\x1caX\xe2\x9b:\xd9f\xd7*pj\xb3\x1eIW(\xc2\x1c\xc3\xfb\x9d\x9cx\xb5\xa2\xcf\x8a Q\xbd\xe5\x84E\x14\xc7\x8eY\xc9\xc5j$a\x19\xa7\x93\xce*Wq\x1a\xe6w\x96* )w\xcd\xe8\x845\x82d^W/U\xb9\xd8\xe9\xac\xc1\x08\xed\xdeQ\xfc\xec\x96\x9eu\xc1\xa1\xe9.*\xa6\xdd\xe3\x89\x8a\x9d\x9e\x1a\xe5br\x90\x90\xbe:;\x1d\x95\xa0\x19\xf7\x14\xbe\xef^\xc1%\xf9\xd2\xdfJ\n\xcf\x9f?\x07\x83?\x114\xdb\x19\x16\xe4`\xaf\xbf\xa9\x1f\xfa\x16\xb2\xd37\x1c\xa0v\x0c\x19\xba1\xc0\x990\x96\xac\x86Ph\xf6SvK\xf2\x97aA0\x03\x19F\xa1k}\xaa\xebR\xcd\xe0\xeb\xa6\x8bc\x11w\xab\x9c\x11\x03\xec\xe7F\x14\x14\xfd\xf9\x02 \xe6\x83:\xbd\x93\x98*\x8b\xfe\xb8\x01\x01eM1\xf2\x05\xdb1l\xa3E\xdc\x92R\xee\x10\x85\x81\xdc?\x0eyNx.K\xe4\xce\xf0\x8d\"\xa2\xa3\xd8}\xa7.9D\x90F+Ie\x1ekp\x94\xfa\xdcB\x82\x852\xc6j1G\xce\xa5\x1ccQ\x88\x04D\xa5\xfa\xe5\x08i\xfd\x94\"\xc0\xb2#\x88\x82\x98e\xdc\xb9\x0e\xc0C\xe0\xc8]\xb7OF\x13\xf6h\\\x99\xc2J\x91\x86}\xda\x99\xc01\\k'\xcarB\x8c\xc2'\xde0\x81m\xa4u|\x8b\x9c\xc1\x86t\x1b\xf1\x85d\x10\xcac\xee\xc0\x19\x1e\x86\xae*\x8d\xe5\x0f\xe7Z\x8d\x95\x93\xb0(\xdfX>\xc0\xb9c\x12%\xfb\xec\x8d\xbc\xcbM\x98\xd4\x84\xbd`WD\xa0\x8a\x9c\x93W\xadP\x14\xe6\x1b\xad\xaf\xbf\x05\x98d,5\x8b%\xbc_(\x1d\\s\x8dB\xa2\x82\xcd[,\xa5\x16`\"\x05\x86\xd1\x18\xffM!\x01'\x04s\x0d\x8c\"=\xc4\x91\x1b\x17Za\x01\xc7ej\xd1\x8eTf\x95\x17\xc4,*\x91\xa0\xd8\xa7L\x18\xd8\xfc\xee\xbdWt\xa5\xa6>\x84\xf0\x04\xff-\xf8\xbf)\xfek\xb8o\xad\"M0k\x1b(\x1f\x06\x0b\x17U\x89\x8c]\xc7<{\xee\xcfo\xd2rr\xf0\xc3+\x97\xc0\xf7r\xb6\x11\xf1\x98\xef\xb9\xd5&H85\xda&\x8d4\x1d\xaaaN \x83g\x10\x9e@6\x1a\x99\x992\xe0\x9d\xe1\xf42\x0f\xc7\x1fQ\xf0\xc1C_-8\x1c\xce`\x07\x16\x9dr\x1d\xd1R\xfd\xa1\x88\xd2\x9dy>\xfb\x1cF|\x81\x8az\xdf\x16tA\xacMr \xbb\xc3\xc2\xd7\xb2\x163\xd89\xe5\xa3\xf1\xf9*X\x80\xb3}mR\x18A\x01\xcf!\xac1I\x08;P\xe08\xf9\xaa=Gf.\xdb\xd9\xe9\x9arM<'<\x88\xed\x9a\xf1\x80kx\x06\xc5 \xac\xbb\x16\x1d\x94\x85\x87\x11\xac=\x16\xa4\x97.\xfe\xbaw\xa5\x81\x9b\xc0\x98\xfc\xbb\xf5\x07\xe3\xeft\xd62\xcbq\x80\x0f1\xa9\xb7+3\xd6\xb3j@vt7k3\xe0[\xf5h\x07\xe8\x061o1J!\xdc\xdf\x9b\xf8\x18\xa1\x04\x97\x90\xb6\x81\xe2\xcd\x05-\xc3\x9b\xa3\x90\xe79\xc4x\x0chqLq\x01\xfea\xee!\xeb\x85\x9d\x19\xfc+L)/7\xb68r\x0bu\xe2\x92|\xe9P=\xe5\xf0\x1c2x\x02\xd3zh\xf8\xabK\xfeP\xb1\xb3W\xb1h\x87\xa3Q\xd5\x05>(\x9aX\x87yA\xde\xa4\xa5K\x82\xa2\xba*\xca\xdc\xa5|B\xe5\xc3\xd4\xf3ar\xd0!7g\xd4\x9a$(\xac\xccu\xcb\x19\xbdi\x98\x8a&\x1c\x00\xf4Dc\x83\x0e\xcde\xcf\xa1\xe1\x8d\xfd\xd5\xfd\x19s\nK\xc7\xc2C\x95\\\xdb\xa0\xd3\xd6\xd3\xd5\xd0\x9e\xec\x06\x03u\x9b\xb2\x11\xd2\xecB 8Q\xb3\xf2L\"\xc6\xb3\xed3\xc1Q\x19D<\xe4\xc4\x8b\xd2M{$\xfam\xc0\xf7\xc0dy\x9bL\xfav\xd8\xa4\x95\xb5\x19\xd4\xf0\x97a\x0d\xff\xd5\xfda\xf3A\x9f\x0fm{\x90VC\x0e\xec\xc0\x83\x93\xf2]\x93\xaeZ}\xb0\xb6\xb7a\xcbu \xc5NS\x0f9\x02~ \x19+!\xed_\xc5\xf9M\xcaO\xc3!\xcb\x84\x93R\xb0\xb1\x7f\xe0C\xc6\xb6=\xf6\xea?m\x9a<+H~\xf8\xda\x03\xff\xaa\x8b\x9fUY\x08\xf4\xe9TXL\xf4\xd5\xa7<\xc8\x0fw%\x91<\xa2[\x85\\E\x85\xfd\x0c\x1b\xd7\x8b\xaeq\xa5RL\xa1\x9af\x1c \xb2\xc5\x10\xf3\x18\x83\x1ab\x14\xddv\x81\xcd\x8c\x85\xf8\xf0E~\x93r\x16\x1bLS\xc5\x83N$\xc6L\x89\xe2A#V\xcaJ\xef\x1e\xc1\x19\xec\xc11\xfb5\xdd\x853\xd8\xe5\xbf&G\x138\x83)\x1c\xdbD/\x08\x91a\x04 \xad\x87[|\x83\xe1Z\x8c\xf8\xc5#\x8f\x8f\x81\x05\xf6kz\xe1kS\xc9p\xf4jY%\xcdh\xb2_\xcfh2\x85{p\xc5\x9c\xe4)Vt\x8a\xd3\xf1\xdeS\xfe\xdd3\xd8\xdf\x9f\x1e\x1dP\x92\x88\x92\xb3\xfbOw\xf7v\xbdo:\xff\xbd\xc7\xcf?\xac\x7f\xedn\xb0\x1ajYhY\xa1Cm\x85\xa4%\xab\xd4%\x0b\xe9\x92\x1d\xec\xef\xef\xee\x03\x06\xf4x\x06\x93\xc9do2\x99J\xcbd\x9c\xa2\x99$\xae\x8d\xb1(_\x84\x9f\xd3\xb6w}\xbc\xc9\x18tl!\xf7\xe7.(>\xa0?\x0f|\x11\xb5x\xc1\xc4\xa8c\xd8\x86\xc9x\xba\x0b\xf7l\x1397\xb3\x7f\xb0;\x1d\xc3={\xb5\xcd\x0c\xc2\xf9w\x1e\x05T\xa3SH\xda\x10\xdf\x06\xa5\xfb)\x12A\x8c\xd8\x15 \x14\xe3\x14\xbc\xbc\xafI>C8,\xee1\xc2\x13\x85\x1b\xf5\x16 \xe9.\x1c\xc7\x0e\x18s\xb32\x10\x04\xf4\x16\x06\xd3\xdcXz\xc0`8\xba\xc9}\xa6\x9a{\xdfCD\xa5\xedEv[\xe8S\xfeE\x82\xda\xb7\xbd\xf0\x81\x04\xe7Iv[\x97t\xef\xc3\xa8l\"\xab`,\xdc.\xbbBT\xdd\xb9#S\xa0\x837\xef\xce?\xbcz\xf9\xe9\xf2\xed\x8b\xff\xef\xf2\x87\xbf|zuN\xcf\xd3\xd8&\x8b;U\x93)\x9b\xcd\x82\xcc\xe5=\xb1\x13\xed\xf9\x8cn\xa4\x88o\x92\xc9\x92\x9e=G<\xb5\x02M\xb6J\xb2\xe3\xb4\xba\x96Y\x00\xd8\x81\xa8\xb3l@8H\xf1\xf0Q\xed\xb5\xe5G\xe21\xc3\x8e\x07\x1f\xf6\xa6\x9cVZd\x99\xebY\xc5\xa1%e\xc8\x98\xa5\xe9\xf6\xb6p\xeb\xad\xcb\xdc\x89\x0f\x13OR*\xb6\x8fjg\x0c4h\xe6\xb0e\x90\x9d\xa8\xe7\xca\xf5\xe8\xc9\xfa\xfc6\xfc\xc2-\xe4P\xc5L\xcf\xd4:\xcb\x92\xf3\xf8o\x14x\x1cN\x8e\xa6\xb4\xe82\xac\xae{M\xb6\xc1\xb6\xb1\x85\xe2\x0c\xa3\x1fo&\xd8\x1e\xe0u$\xb5\x1f5\xe9\x05\x0d\x16\x98\x1dBjW\x1a\x8b2F\xe3\xb9\xa237\xd6\xf1-\xf6\x93<\x9c\xcc\xf66\xff+@{U\xc2\xf3\xb8\xa9e\x17LbF_\x99\xc3\x9c\x16\xbe\xd6\x8a)\xe0)wh7S\xa3\x9d _\x1e\x98\x1a\x01\xc1\xcef\xab\xbf\x81\xed\xa7\xf8\x02Y>D4ca\xd6$\x1bB2\xf3\xbe3\x93\x05`\xde\xd4\x0f\x161\x0b\xea\x86\xc6\x86j\xa1Tb\x00\xf0}\xa7\x05\x17\xe1\xe7\xb4\x08\x17\x83\xe3\xafX2\xb5\xe9\xcdQl\xf1-\x9a\x94\"\xac\x0cjk\xcbmb\xa1\xdd\xdf\xc3V\x19\\\x8a&\x0c\xadG\xd9j\x1d\xe6\xa4\xcf!\x1bd\xf3\xca\xdar\x03\xdb\xd7\xf4QF \xd9\x8b:\xba\xb7P\xac\xb0/\x8c\xb6&\xcc\xf0Eu\\\xee2s\x90\x15{\x8c\x0d'\xf5\xaf\x98\xc5\xa1\xcfdN\x92\x99\xd2\"k\x98Q\x86\xde\xe2t\x8b\xc3\x98\xc5\x17xD\xc9,\xbe\xe8B\"\xa9\xe0\x1cY\xff\xad\x0c$\xf2c\x97\xddZ\x89>\xccw\"\x94zh\x8e\x04g0Q\xe2\xe1Bs^\x84\xf9k\xef\x89\x11l%W\xfe\x94-\xe5\x8fy\xc2}\x06\x06\xdf\xca\x84\xe3\xbf\xc1\x1ee\x80\x8d\xc3?\xa8\x01\x88) )\x0c1\xb3\x18L'\xf8u\xe6\xd5\xc1\xd0!\xb3\xa6\xbc\xfa\xceI\xe2\xa24\x99N\xf2\xe0{\x90-\x04P\xb0YQZ\x0c\x1f\x04\x01m\xa2\xb1\x11>\x98[S\x02$\x18W\x0b!\x0ca\x10\xa4C\xaa\x8b!\x89f\xe9\x85\x95\xdd\x12r)\x05=P\xbch\x86;f>IO\x1d\xa5\x8d\xc2N\x9cW\xdc\x18\xc5\xce\x06\xca \xbc\xfa\x9d\xf6\x8f>\x153\xe6FM8g|E\xf4\xd6\x9e\xb3\x08\xcd\xb9mEg+dg\x8fS\x98\xfb\xa0Pz\x12\xfa\xdc\x1a\xab\xef\x8a\xdbp=9\xe8\xf3\x0c\x17\x0c\x0e\xc6\x8c\xea\xd2\x13\x95F=\x91l\xae\xc9GRP\x12\xbb1\x1d^UI\x19\xaf\x13BWpr\xb0s\x15\x97F\xb4\xa8(\x1a\xc6'h\xbe[\x9e\xb0\xe37\xf5\xe0\x86\xbb&\x11Jm\x8dZ\xd9KA\"\xd1e\x17M\x10\x8b\xa8.\xcb\xee\xf4\x9b.\xcb\xdeW.\xcb\xee\xf4Q\xcb\xb2\xd7Z\x96]\xcfo\x8a\xe82\xb1\x7fLZ\xb8\x0dV\xeb`\xef\x9b\xae\xd6\xe1W\xae\xd6\xc1\xde\xa3V\xeb\xb0\xb5ZO\xcd\xabu\xa0\x15O\xd9?\xfbZ\xf1.\xfbg\xef\xf1kk\x8a\x1f\xd7\xb5\xbah\x9e\xdc\xb5\xc2\x8a\xa6\xa3\x8e\xaa\xc5~\xb6\x02\x08\x9c\xc1\x0b>\x9b1\xa5\xcc\x07\x84\x87\x92\xc7\x93wh\xf2\xe9F+\xf8\x07\x8d`\x98\xcd\x99\xb0\xfa\x1a#\xdb\xf4\\\x9eO\xe3Q\xe2\x0ck\x17\xfd\xa6R\xbd\x91\xda\xd4N*D3<\x8a7\xcda\xb69Y\xc1\x10j\x15\x06Q\xac\xe2\xe1\x9d\xbf\xd8\xa4\xf3.:W<\xbc\xdd_7i\xb7\x93:\x86a\x14\xb2xx\xff\x9f7\xe9\xbf\xd7v\x18\x9a\x86_m\xd2p\x075\x0e\x83(r\x18H\x95\xc3&\x9494\xb3y;l6\xbd\xc4:4v\xd1F\xc6\xfag\x1e\xf9Rx+\x1e\x83\xcd\xbd@~J\xe6\x8e8\x02\xc7\x19j6\x0dF\x9a\xec\x81\x8b\xe4\xd9dmA\xa5T\xa0N\xfeZ\x85Iw`\x170J\x1bzd\x0b\x122\x146\x9a\x9d\x88\x87\xe3\x80\xfb{\x0e,kY\x88\xd9/\\\x9bE\x9c\x16k-xr\x17f\xb2)F\x98\xffRK\xca\xdf9p\x81\x9f\x9es\xb3\xe9\x9a\xae\xa8\xddy\x10Fr\x7f\xc9`\x15\x96\xd1\xd2}\x12\xfc6}xr-2l\x80#\"\xe3\xd6\x8d\xf1\x10\x80,\xc8L\x10\x04\xe0x\x9e\x0f\xce3No\xd4\xe1r\x9e;]\xebb\x91'\xf5\x1a\xb5\x7f\xfb\xad\xd6y<\x05\xb3\xea\x9e\xdb\x0c!\xa2v\x84/\xc8\xb1^/\xaf\xed\xb6\xb4\x17\xcc\xd6,naT\"|\xdd\x11\x03\x8bv\xef\xefQ\x80\x83/b\x1d5\x9b)>\xee\x8f\x9e\xd3\"@\xfbh\xdb|sx\xce\xc7C\xe8_\x9dnBM\xfd^\x17\x02\xad1{-\xa4\x03|H\xeb\xbf\xf2\xfa\xaf\xb8\xfe\xab\xb9|\x83\xc4{\x19\xba\x0e\xec\xd0\xd3\x83!\xcd`\x87\x1e\xa7P\x96\xe8e>T\x1e7\xdf\xc0\x00\xc8B/\x18s\x15\xacb\x99\xc24\xbb\xe3\x13H\x98!\xedh\x94\xd8%\x80\xd1,a\x12\xc0\xc5,\xe9\x94\x00f\x18\xbc,\xe1:sZ\xdb\x0e\x83\x1f!\x01\xcc\xe0\x19\x1a!\xa3\x04\xb0\x82g\x90\xd9%\x802\x94\xc2(\xc2C\"\xbbI}q\xe3\\\\J\x91%\xd7.Ao[\xf7o\xd4\xd9\x9d\x1aR\x03\x03\xaavu\"\x99\xfc\x7fmG\x93\xce\x8e\xd0C\xdf\x0c\xc7l@L\x8b\xb9Y\x93\xb8L|$\xddt\x9f\xf3_\xadVj\x0f\x14\x1d@\x99\x83\xa6\xe4,J\xf9F\xad\x9b\x8f0\xc2\xe0\xb8x\x1d\xa7\x18\x97\xc03\x04d\xe1\xae\x92,r\x81p\x8c\x10\x84\x87\x0f,P\xc7\xcc\xe7\x91t.<\x16\xc9\x11\x92,\xbd\xa6\xfc\xaa\x88Fk\x0f\xa8q\xcf\x00\x85\x18D\xea\xc1\x19\x05\xcc\xac\xd8\x08\x899\x07Ay3\xd9\x9f\x89\xd5\x1db\x94_\xdb\x18K\xa8pGO\xea\n]\xacU,98\xc9\xc1{\x9e\xd7NM\"\xe2 \xe3\xef\xf0\xafA`_r\xeeeg1\xab\xca\"\x9e\xd7A\xa9\xec\xf1I\xf2:\xae\x805^\x86\x02^U'Q\xabJo\x08\xff\xc5/\xdbJ\x0b\x94c\xde\xf2^\xd6k\x18\xdb\xc5\xfb\xbc\xdc\xa0\xcf>\x8e\x8b7y\xb5A\x93_\xab\x8a\x80\xa6\xdb\xdb\x0d\xba\xed\xe5\xb1x\x9b_6h\xf3\x1fN\xd9q>h\xf0\xbd\xdc\x14Z\xf3o\xc4I\xd9,u\x01\x98A\x13s>\xd5\xbd\xa6\x98\xc2\xb1\xdf\xf9T\x97v\xfd\xdf\xf3\xf7\xef\xfa8\n\xbe\"\xe6\x1bJ\xdb9\x06\x11\x0c\xc4\xccr\xcc\xc32<\x06\xdd\x93\x0e\xe9\xa3&oFp\x19\xe6\xb9\x88\x0d\xe6\xf7\xc3R-\xf8*\x05,\xef\xe1\x14\xf6\xc6G\x07\xb6\x90q\xbfv\xe1l!A3I\x92\x1ec\x16\xac\x98\x03\xa3\xce\x97\xd9\x8c\x992@\xa2\xc1)js\xed\x0c\xe40\x87\xde\xcf\xff\xa8S\xfc\x16\x93{3drv\x1bDw\xcb&\xf5t\xb78r\x95\xd8\xa7\xbc\xc1\xb2\xa6+\xa9,\x82\xe3\xb0\xfbG\x98\xab\x1c.F\xe61}\xd3k\xb7\x9ce\x1dS\x8f\x07M\xfdm\xd7\xd4\x15St\x8d\xf1\x90\x877f\xc3\xcbk=^\xc659\xb1m\xd7\xf2Yv\x01#\x98\xee\x1f\xc0\xf7\x90\xcf2S\x90X\xd8t.\x9f\xba\xe6\"4\x12\x13\xd4H\xb0\xd8\x18\xf6H6\x0e#\x01E\x04\xef*NK\xbb}\xc7\x08\xc9 k\xdc\xb7O\xf9]\x9c^c`\x13Lj\x00W\xe4.K\xe7\x82\xf6ak6\xd0\x0b\xf7\xa5*\x82@\xa7\xc8\xc7K!\xbes\xd8\x18\x8ca\x80\xb8\xb0D\xc4\x0f\xb1i\xb2 \xba\xa8\xf1\xe3\x9fY\x03\x03\xe9\x91\xfe\xf4\xd8t\xb6\xe615\x88$t\xb0\xc7\xc1\x9c\x93/ \x8b\x17\x06\xae\xe8\x87\x1ef\x88\xd4>\xfd\x84\xdbS\xef\xe3\x86\x9b\xf5\x92\xca\xed\xd5\xadud\xaf\x17\x1f\xa6\xaa\xe1\x0ewG\x8b/\x00\xf5\x10\xdb\x18\x94\xe7\xd938\x84\xef)\xfd{\x061\x1c\xc3\x04v \xf6<\xb4\xd16\xbc\x184\xe1\x8f\x1bMxoz\xb4wt\xf0tz\xf4\x8df\xbdg\x9f5iOk\x17\xa7\xc5\x16c\xd0\xe4\xde\x0d\xbe\x1f_s\xb0lG\xb5\x03\x9e<\xfa|\xfe\xa4\xcc\xc88\x9dZ\xaer\x7f\xcf\x16`\xec\xb3\xa5\xf6!\xe6<\xae\xdc\xc6t\x97\xbd\xa3+\xb07h\x0c?>z\x0c\x87\x961\xecO\xd9;:\x86Cm\x0c\xf2\xafB\xa7\xeb\x86\xd8\xef\x08\xaf\xb8aJ\xeaS\xf8\xaf\xff*}=\x08&\xe1\xb9O\xfe\xeb\xbf\x88\xcf0\x05\x0bC9\xa2X\xbb\xbe!\xa5\x888RR\xc4^\x17\xe5^\x13\x92\x8c\xe5\xea\x92\xbe!\xe2\x1bR\x7fC\xa4o\xca\xba\x04\x93\x1d\x1b\x03\x985:\xcf\xda\xea\x1a\xd7\xc2\x1a s#\xf9IM\x81\xc1\x8e\x9eeE3\x86\x11\xec\xec\x101\xef\x13<\xda\xe3\x9e\xe9\xd2\x0f\xbe~\xc2\x87C\x00\x02o\x90\xd4s\x9c\xf8\x9a\x82\x83o\xdc\x90\x1e'\x07\xedc5\xa8\xd3\xa9\xa5Sn\xe9\x81\x8b2\xb9@\x9c?l\x1c\xed\xcd\xfe\xbaq \xb5\xa1\x0cf\xc88v\xa7\x8f\\\x8f=}\x1c\xae}A\xe4\xa2)\x16\xb18\x7f\x93\x83\xa7O\x9fN'\x94\x8b\xa8\xdf\xef\x0e\x1c\xf6#\x97\xaf5\xec\xd6\x18.D\xe2Li\x06\x93\x83\xf6\x14\x94Y\xed^t\x8a\xf0\xe9\xb0\xff\xd7A4x~\xca?\x9fL\x0f=.\n\xdf\xe1\xb4\xe3:\xbbu)\x95\x00\xdf\x03\x06\xf3\xec\x05\x07\x7f\x0f\xf0G\x94\x85\x91`[~q\x82\xe4e\x1b\nf\x1a\x14\xcc\xbb\x17)3,Rf]\xa4l\xc0\"}#\x90\x89\xbe\xd7\xf5\x89Gu\xde\xf7\x80\x11!v\xa4{0\x11\xa9\\\x07@\xd7\x0d\x80\xab\x15\x9a\xb5\xd7\xf1F\xf8UX\x81\x8bu\xedw\xa7O\x0f\xe8$S8c\x8c\xd0x\xf2\xf4`\x0c\xf7\x90\xc2q?\x05\xb2\x01\x8c~\xf4t\xd8$\xee\x15\x10\xfe\xfbM\xe7\xdb\x81\xfa\xcd \xbd\n'i\xd9to\xd0p\x87\xad\xfe\xf0\xe1b\xcf\xedA\x0f\x00\xee}\xc3}\x9dd\xa1\x01\xba?n\xb816\xd9(\x1a\xb6\xc6\x82\xeb\x1b4\x8co\xb5j\xadaL\x86\x0e\xe3\xc7\xac\xbaJ\xc8#\x97\xe3\xb0w\x1cc\xc1\x80\x0e\x1b\xc7#\xd7\xa3\x7f\x1c\x93!\xe3@\xe6\xd9\xca\xcdX\x848<\x9d\xa7\x82\xe0\x98\x15\x0b\xaam_\xea\x06\x04:2I=\x96t\xcc\xe6\x88\x12\xdbc\xfce\x1dN\x1fx!H\x13r\xba\x14\x94D\xdaB\x93\xac*#\"N\xa1\x84'\x1039\x90\x15\xbc\xd1\xca\x9dP\xac^I#\x99\xf0w\\\xc9\x14\xabXW\xd3`\xa4$\xad\xa6\x10\x9f\xd5+\xba\xb3\x13c\x808N*\x18\x964\x16K\x9a}\xb3%m\x11\x15\xdd\x16,\x86E\xd5\xd7\x92\x02\x8b\xfd}\x1f\xf5(\xd6|?\xb8;M\x06\\\xb7\xf4\x04\xb4\x96O\x197\xf9\x1f4\x11\x13\x05\xf2\xd5s\x99\xfaLr\xdc5\x9b3\xc3\xf5\xf0\x9b=\x9b\xb0=C\x11)\xa5\xa9>(\x1dl1\x1b\xfb\x91\x166\xd2>\xc9\xc1\x94\xf2\xef8I>\x1b}\x92|\xee\x86IN6\x9a\xa4\x89Z\xf9\xeaI\xee\xf9\x92H|\xd0L\x19\xcd\"f;\xdd\x93\xa6;m\xca'\x07\x96\xbd6\x1cg\xba2\x1f\xcd\xdb\xdfI\x16I+\xf3;l\xff\xe6+cY\x95\x89eU\xa6\xe63\xb3\xdb\xbd2\x93\xc1+\xb3!\x8a\x15\xd2cyY\xb6\xac\x06G\x02\xd4\xb7\xd0\x03\x86\x8e6\xcbN[\xb8%f\xa8d\xc7\xe0\xe6m\xb6\x07C\\lF,=Qz\x1f\x89\xc1+\x19\xdd\x08\x917wJb\x7f\nsL\x86\xdb\xe9\x84.\xf0\xcb\x10C\x14\xf9\x1a\xdew)\x96\xaa\xe0\xf9s\x18S<\x1a~\x13|\xb5!\x05\xf0?e\xa3;\xa8\x88\xaf\xdal\xb1\x17\x12\x81\x915\x04\xc6\xc6;>\xfa\xfb\xec\xf8\xefB\xa0L\xa6O}\xd8\x99L\x0f7\xa7Q\x14\x1d\x12]Z\xe6\x930\xf9\x1a\xfa\xe5w$_v\xa7O\x0f\xe8\\Q\x860\x0c\xb4\xff\x8e4\xcc\xefH\xc2\x04_K{0`\xca\xdd{;\x80\xc4QH\xa2\xaf\"h~Gz\xc6\xbeD\xea\xf5U\x8c$\xc4-\x1e\xb0\x8a\xff@\xc4\x8fE\xfe\xd4\xbd\x8a?i{\xd6\xe7U\xd1\xf4\xb4\xe9~i=M\x06\xf5d\x93\"uw\xf5\xe3c&e\x13\x14m\xd4U\xef\xac\xa2l}\xb7\x19\xdd\xd2\xa4\x9b\x1c\xa3Cd\xed\"\xd8\xd8\xd5\x97\x9a\xa7\x97\x94\xa5\xa41E\x90+\xd0\x0fI\xdd\"Wq\xe45 \x88\xce\x0b\xcc\xfb\xb2/\xbdS\xdc\x8a\x84\xd2\x0cP\x1eVO\x13\xa4\xcb\xf0\xa6\x0c\xf3kR\x9e\x97a^\xf6gC\xad\xcdx\x80\x19kj\xc30\xf7PdU\x1e\x91\x0dz\xc8\xbb\xc6\xcbZ{\x95\xce\xfb\xdb\xcaU\xe7\x8bz\xf5\xd5\x1d\x95\xec\xaf\x08\xc6^\xda\x916Jy92Z\xe5\"A\xcb\xf4[\xb99n=\x12\xc8\x8d\x1b*\x06]\xe6\xcaA\xec\xb1#$M\x0c,]\xc2\xe4\x04b\x9e\xd5`g\x07\xcd\xc2b\x18\x01\x03\x92\x14\xd6\xd1_\xa6\xb8/\xb5\x93\x11eA&d\x17X\x18\xaf\xcd\xb2\xfe\xb105\x9aY\xda\x06\xfd\x1b\xf3\xb9\x14\xa4\xac\xf3\xb8\x94\x8a\xa9N\xca\xcc\x9e2\xcf\x9c\x0bS\xe8\xfd\xba\x00\xc1\"\xc6\xf4\xf6\x1b\x00\x02\x83\xd3\xd5\xc6\x99\xadEz\x02\x0c\xa9\xc1\xd1\xa6vC\x8c\xe9s%\xb8\xd0\xfe\xc4\xe7Y7\xfa2#\x81\xec\xe2$\x07,\xb7Y\x1e\xd1\x87n\xe9t\xff\xa0F\xd4\x96\xf8h\xf6|\xabz\xb2\x19C><\x9b?{\x9d\xf1{h2o\xcb\xb2c\xbfj.\xe0\xdc\xe6Ul\xf3\xfch\xf5\xc7s\x97\x98\xf2\x9d\xf3\xc5b\xa9\x92\xacF\xbf\x1cF\xca\xe0\xe7\x19\xc3\x0dj\x91\xd5*\xfa\xfd`O`\x0c\xe7\xd1\xc4\xcf\xa3\xed\x9b\xa1Tf\x1bl\xe3\xcc\xab%\xba>SF{\xcc\x93\xc8\x8d}h\"{P,gL\x0bo\x87'\x06\x8b}\x04\"L\x93a\x01\"viB\x85\xb6|r\xacB\x96Q\xf8g7\x15)\xeds)\x01\xa6\xd7\x91\xbc\x99\xb2\xdc\"N\x95\xf9\x10\xd6\x13\xe0\xb6z\xe8\xa3\xacLB\xc0\xc5j\x96\xc1\xbfB\xb8\x81\xcd^\xd9\x8a\x91\xa3\x8e\x81N\xf6op\nOf\xff9\xfa\xe5\xc9x\xe7\xe8\xc5\xce\xff\x0bw\xfe\xb6sy\xf1\xe4\xda\xe6z\xf3\xba;\x84+\xa0r\xf6\x0c\x9c1:\xfd\xabiB\x8f\xb5\x02ul\x96\x0e\x7f\xb6*\x00o\xcc\x01\xda\x08\xf0\xa88\x13x\xd2\x9b\xe3\xb2q\x90\x89Ex~S^\x87\xee\x14*1\x0bl\xd3J\xec\xe0\xc1s\x8c\xe6\xbd/P\xf4\xfe\xd3\xdd\xbd\xbd.\x80\x1b\xf3\xfcp\xf6\x1aP_\xd2\xe7\xb0\x7f\xb0;9\xea\xabL\x1f\x96\x88b\x97\x8eggB\x07\xc3\x93ILw\x8f|\x98\x1cM|\x98\x1c\x1eu\x80u\xf1DYZ\xc6ie\xce\xa5$\x1e{\xf6 \xe0c\xaf@\xa4~\xb2J\xf5\xe4\xe7\x1fi\xf4\x98\x10\xaa\xb3Jo/\xdd\xd9\x95\xf0\x98\x1c\xecN\xad)\x04\xc53lU\xfc\xdfy\xc8)\xf7\xd18\x80\x11\xa5\xebvx\n\x82g\xcf`\xc2\x0c]v\xf8l\x8c-\x88\xb4\x89\x9c\xef\x190\x1f;&o\xeeo\xca\x12U\xf4\xdd3\xd6\xe1\x84eg\xe9K\x7f\xc0\x07\x93v\xcf\x83\xef\xdft\xbc7\xb0\xf7\xe9f\xbd\xc3\xf3\xe7\x98\xcb\x00\x03lcB\x83\x94\xfe\x9a\x1e\x0e\x1a\x16\xee\xd3\xb0q\xedn>.L\xba0\x9d\xee\xb1\x10\x1ep\x00\xdbt\x848\xba\x0d\xc6\xda\x03\x1aq\x1e(\x14!\x92\xb4&V\xd2\xdar\xf6\x99p\x86\x19X(i+\x93\xab\xfbu\xd6\x7fy\x8cw\xa6\xe3t'\x13>\xb5\x07\xbfS\xb8&h\xa8\xd4}\xea\x05,\xe8|\xd3q\x19\x90/\xeb,/\x8b:\x85\xf1\xe0\xd6\xf6\x0e5\x8a:f\xc5GZ1\xa5\xd3\x9cY\x86a\xf0y\xd0\xfb\x0b\xc7<\x02\xfb\x89\x15'\xa7\xc0\xefU\xc6\x8c\xae6\xfdb{\x1b\x90\x0d8=\x95\xee\xdd\xc3f\x93\xda\xdd\xf5\\\x16\xb1\xdf\x07'\xcaIX*~m_\xb1\\\xbbOw\x8d\xeb\xb5\xfbt\xcf\xb0`\xb4|_+\xafx\xf9\x81V\x1e\xf2\xf2\xa7\x9e\xc4\x0d\xd4\x07\xbbh/\xe6\x0d\x8f\x0e\xbac\xd0}\xa6\x1c?\x03\x0f\x9f)\xa7sV\xcfk\xad\n\x0d\xa2\x84\x84\xb9\x8b\x87\x9cX\xb3q\xddt\xa7\xd4FQ\x10)\xdd|6\xbe\xf0!\x9fMt\xbb\xff?\xb4\xffRd\xc0t\x0ctWT\x89\xd0\x9c$\x04c\xfc\xc4j\xf95\xa1\x102S\x0b\x97!\xdd\xd7J-,\xb0f\xe8+{_l\xb6\xf7O\xf7,gH\xf9\\_5c\xf8\xfb\x13HwvN\xda\xf0\x17\x05\xa8n9K/p\x01\xa5\xbc\xd1\x1aU\xc9K\xa5,\x9f\xe6+\"\x8ff\xf0\x90\x1b5\x92\x88y\xdad\xc9!\xf4/\xf2\xe8\x8b\xf9\xf4\xe81k\xd8,\xdf\xe5\xe5<,\xc3\xcbK\xe3j\xe4.\xf1\xe0\x0c\xd2\x99E\xbeW\x17\x1f\x83\xb3\x0c\x8b\xa5s\x01\xc7\x90\x06\xabp\xfd\xd8\xf9\xec\x8d-\xe0s\xa2_{\x06\x0e\xf0v\x8b\xa2\x8d`f\xc6D#9\xcb\xe8G!\xe5c\xc7<\xb1\x80\xb0\xc9d\xf7\xb1\x83CP#NH\xec6\xd2N\x8aY\xf3\xaf\x18\xeb\xd3\xb1a\xa8\x9a\xa8a\xd8Hmbbz\xbaY\x0c\x01q\xea\xdbb\x1bT\x12a\x14N\xe3\xb1s\xc6\xd8\"\xaa\x04\xe8\xd8\xe8\xbd\x81\x9d\x98\x1e\xb8\x9d1=l\x1b^\x17\xa7*XB\xf3\xa8\x94:lh\xc6\xd6\xf5\xd8\"\xc1\x0d\xc9\x0b\x8a'j\x0dS]TG\x86sn\xc6\x81\xe3u\xd7\x98\xd0\x1a\xb5]\x8b\xb9\xc6!\xads\xa6,{\x1bO\xa4\xe4K\xf9)\x8e>\xab\xb1\x98;bK\x82\xd8#Q_\x96B\x97\xb6\x08\x0f\x94\x8e\xba\n\xa3\xcf\xc6\x18\x0f\xa2%[\x98\xfb\x9b&\xab$\xb4\xc3J\x9b\xbf\x11\xb1\xb7\xc2.b\x1c\xa3&\x8d{\x02\xd5\xf6$\x80\x14\x16@\x81XI\xb7+X,\xb6\xd8\x93\xdf\xb1\xddb\xbd5}\xe2\x0f\xc0k\x86D+\xe7\xfa\xcd\xac\x83x\x1e\xfa\x86\xda\x93\xdb\xf1\x9b\x0e\xb5\x95{U\x7fzG\xdb\x93\x89\xf1[\x8f\xd6\xb7ir\xc4\xd35\xe0\xde\xd8Z \xcb\xc1\xe9}b\x1ci\x88\x16|\x8a\x1c6\x137\xc1\x83lV\x8dF\x17\xf2-\x99U\x1dq3\xe1[\xac\n\x8bX\xcc\xa5\xc4}\x0bb|\xdd\xc7\xe2? U\xdc\x801 N\xcb,\xda\xee\xde\xa6,\xda\x81\x89*\xc8y\x96B\x13y\x9f\xf5\x91\x8eqJ\x81 \x99q\xae3m\x14\x13\x0f\x86\xe6*\x9by\x86\xe0L\xeb\xf7R3\xe2\xaf\x98e{\xa3\x98\x9c\xa7\x1ek\xfe\xe4 \xb8\xf4\x02L\xa1\xa5\xa2\x84\x1c\x8e\xc1\xcd\xdc\x9cN\xcb\x9734V\x9e\x0f\x99\x1b\xb3H\xb0\xd5\xd0\xccr\x88\x1aL\x8a\xaa!\x01\x88\xd3\x8cc\x04\xde\x80gD\xe3\xa6E\xa1#\x1c\x9a~M\x19b/\xee2\xc5H6\x0fO\x1c\xab\xb8\x85\x01\xf8\xc0%5.1ghKYf\xe8\x98\x9fh\x9e\x13\x1a\x7fJ\x7f\x8f\x15?\xe4f\xee\x03\xb2\xae\xfd^so\xb6\xc6\xb4)\x03\xf3\xb7\xfd\xce\x83\xcb\xa5|\xa3\x1b\x93\xbafZO\xbeH\xa9\xbbwp\xe4\xb9\xce\"\xcb_\x85\x91\x08\xa5\xf5\xa8f%\x1e\xe0H\x17?p\x1e\xe0H\xe7\x0d2\xce\x1b\xe8\x10\x8d\x891\xf6\x9e\x1eJ\x8b\xe2n\xc6\xd0\xf9\x94\xfa\xe2 \xbd\x8d+\xdb\xca\xf4\xf1\x0c\xa6\x94~5\xd8)\x94p\xc6r\x15s\xf3\x8d\xd2g\xc9N\xab$\xa1'\xbcPP\xd7\xf4\xc2W\xa4#\xa8N\x0cy\xe2!\x16g\x15#\xd5\xa6\xa8P\x16v.N\xe4\xf0\x80\x91R\x19\xa1e\xa1Zv\x8b\x01\xd9##]\xcc\x93A\x1a\x12\xa2\xaa\x99 \xd3v\x05\x92V+\xc2_g\xed\xd7\xb7y\\\xb2\x97\xa1\xf2\xee\xc1\x87\x02\x19\xc7\xd8-\xe8\xb0\xe8\xcc\xa2\xe6\x90z\xc1\xf5\x90\xa8\xd3t\xc3\xf8V\xf9\xb00\xb3A\x96]\x89\x1a\xd3\x18\xf3\xe6D\xca\xe6\xecJ\x9bC\xc1\x99\x14\xba\xe8\x182\xce\xe1\xf3\xf7\x14\xae\xa5\xea\xfb\x149\x1c\xb9S\x1e\xc1\x87nh\xd4\x8cAz\xa3\x1d\x06q\x10\x8a\xe6 \x84\x86\x83P\xb4\x0e\x02\x8fa\xde\xde\xf4kR\x1a\xb7\xbc\xa0\xe5\x86\x9dV\x8fB\xd8}\x14Z\x89y\"\xbe\xdb\x11\x1d\x0ff\xc3\xf9\x16 I\x92\xe1\x1c\xdaD\xa9\xc1\x8f\xaf^\xbf\xf8\xf9\xa7O\x9c\xb0\xcc]\x0d\x0e\xb3 \xe7\xc70K\xdd\xfd]O\xcb\xdeO\xbe\xac\x938\x8aK\xfe\xfa)\xdd\x16w\x7f\xf7\x90\xff{\xe4I$\xcf \x18hgP\x05\x8d\x0c\xa9;m p./I\xf16\x9bWZ>\xd6AKG\xdb\x93\x05\\\x8a\xf5C\xea\xd6\x1abwz\xc0AI\xea\xee\x1eq\xaa;u\x0f<\xd7\x11&\x1b\x9f\xc2k\x01Z\x9c\x97\xe7\xe7\x1f\xab\x84\xfc\x14\x17\xa5\xff\xf2\xfc\xfc\xbc\xbcK\xc8\x8f$J\xc2<\xa4#\xa1e\x7f\xa2p\x85UHb\x92\x96\x1fIT\xe2\xcf\x1f\xdf\xbf\x95\xfff\x8d\x8b_\x9f\xb2\xcf$e?\xc22\xfc\x94\x87i\xb1 \xf9\x9b\x92\xac\xb0\xf0u\xcc;\xfd\xf7Oo\x7fz\x91$/\xb3$!8y,\xd1~\xbe\xce\xf2\xd5\xab\x84\xd0[\x8c\xbf\xcf }+J\xde\x92y\x1cbco\xe3\x15\xa1\xe8\x96\xa5\xe9}\x17\xae\xc8\xfc]6'o\xc3\xb5O\xff\xc5:\x1f\xc2\x98\xce\xe1\xaf\x15)\xd8\xd0?$\xd5u\x9c\xf2\x7f\xd8\x97\xe7\x7f\xfa#K&\x87\x15\xce\xff\xf4\xc7w\x88\xa5\xc5\xaf\x0fa\xb9<'\xd7\xf5\xcf,NK\xf1CZ\x85\xf3?\xfd\x91\xcd;\xcb\xd9\xa4\xcf\xd1D\x95\xa1sV@\x97\xfb|I\x08\xfb\xfc\x13eg\xf20\xfa\xfc\x92/x]\xc0~eU\x84#r\x82b\x9d\xc4\xa5\xeb\xf8\x02Z\x8cO0 ~X\xcb\x80\x8b\xd1\xc8\x04g\x11\x1e\xce\x8a\x8b\xf6\xbd\xa7\xe0%\x9fE\x867h0I\xe9\xf2E#\xf4V\xa14\xe6<\xdeJf\xd5\x05\x13\xd2%(\xf9\xa0@\"\x9bE\x94\xab\xc8\x02\\\xd7\x9e\x13\xaf3<\x14\x8e\xfe\xf6P[\x1am*\x96\x13\x02D\x0eH=\x1e\x86\xf5\xd0\x87\x9dI\x1f)e\xbb\xec\xdd\x94`m\"\xd7\x10\x80\x12\xf1\xf72L\xbf+\x81\x0e\x06V\xa4\\fs\xc8R0\xe6\xeaii+7\x1b$\x07-\x83Y\xca\xa9\x0d\xeav\xd2Y\xa8\xc7\xef\x13o\xa6\xbe\x1e\xa1\x87\x19\x16ZR\xa4s\xe3+\xb1\xe3B\xc8\x8b\x80Mlc\xd3\x9f\xa1\xe5\x8eF\x91\xbe\xff\xf4\xde1h\x1aeY\xcc\x83\xfa\xba\xd0^\xb7`\x0d\x1dl\xc9\xa9(w2=\xf4\\'^\xe4\xe1\x8a\xe8\x1d\x89'G\xe8b\x13\xab\"\x92$AA\xc1l0\x8f\x8bu\x12\xdeQ\xac\x97f)q|\x9c\xfb\xa1\x17\x84\xeb5I\xe7/\x97q2g\x99\xca\x83\"\xa7\x80\xd2\xf95\xbc \x8b(\x8f\xd7\xe5\xb1\xe33\xabV\x12DYZ\x92\xb4\xfcs\x9c\xce\xb3\xdb`\x9eEH\\zA\xb6&\xa9\x8bn\x03,j\xa7\xf3\x8c}\xfa\\T ^\x9f2\xc5\xf1\xb3_\x9e\xf0W\x98\x81)\x88\x92\x8cE\x8c/\xf08\xbd>\x81|g\xe7\xc4\x03\xae\x9a\x94t\x8d\xb3l\x96_\xd8\xad\x02\nWS\x89\x9a\xaf5O8\xcf\x94\xd7\x94\xa4\xed\xe7\xa7\x8c\xf0\x89\xabf\x04m\xdb\x0c\x93\xa2\x12\xb7\xf4\xfc:\xdce\xe8\x83\xfa\x9aK$)\xc68e\x0eX\xb4j\xe1\xaaY\x95\x08\xd2\xe0\xc7\x10\xbb\xa9/'\xe8\xed\x07\x87\x02}\xa0\xf7hDb-=~\xae8\x96\xf6\x01?\x9b\xa4\xabx\x17\xbe\xe3\x0e\xce\x1eW\x84\xbb%\xfa\xf5\xb0\x10\xa8\xa9\xb71\xcf.\x11t\xbb\x9e\xeb|&w\x85~\xf2\xd9\xa5U,\xcc7\x1av\x8e\xe1\xa3\xee\xc1\xc5?\x98\xec\xe7\xf1\xa34 #g\xce\xe5e\x94\xe5d\xe7\xd7\xe2\xb2X\x869\x99_^:\xa2O\xf3;\x8a\xe8\x1f;\xa1XL(f\x13\xfa\xed\xa1o:6\xc4\xe9DYZ\x94y\x15\x95Y\xee/\xc3\xe2\xfdm\xfa!\xcf\xd6$/\xef\xfc\xb8\xf8 \xce\xef\xfb\x85\xbf\xe6\xc5o\x8aW5\xbf\xe4\x97\xd9OY\x14&\x84a\x03_\xa0\x05\x9fc\x1e\x99j\xdbl\x95'{^\xb00\xcaTtQKf&\xf6\xfbV\xd6\xcc\x98\xa3\xcau+\xc6#\x9er\xdb\xf9\xb2\xb9\xc6\x18\xd0\x98\x99\xd4\xa0\xb8\xa5\x0d\xcdUfs\xcb\x10PA\xc8,\x94\x17\xbd\xfb\xb7!W9\x9d\x1cy\xee\x96\xec\xeeBq\xcb\xbe\xc7s\xde\xfb\xe0\xb0?\x1c\xbf\xe3\xb0\xa1\xfd\xc9%]\x8a:S>\xf7O\xbaD\x83\xaff\xc8\xbe\x1d\xc5I\xe8\x8d\xb7g\xb6\xaf\xe1\xed\x9a\xa1\xaebHvf\x17\x041@\xda\xee`\x9e\xa5*\xffI\x9f\x07\x06\xbc(\xe0\xc6\xe5m\xe66\x92\x8d\xeb\xad\x9d\x19&\xc2\xfb\x99X\xf7v\xc3[\xb071\xcb\x15[\x9cm\xebF\xd4r\xd7\x02\x89\xb7\xbc[]\xa4K\x08\xd5\xf1\xbb^\xefm2\xed:A\xfd[\xd5%d\xaf\xf3\x11\xff\x9c\xce\xc9\"N\xc9\xdc\xa1H\x84\xc9\x8f\xf8\xabwU\x928Fg1\xa4E;\x119\x0e8\xbf3\x94Jc)g\xc4\xe0\x98\x02QX\xa7\xe6\xd5\xf4\\\xe8\xd1\xca(\n\xbc\x12\xb1\xe7q\xac\x9d\xa1\xb0\x08\xb5\x00\x0e\xab\x80\xc3u+v\xca<\xcfFV\x03KBCP\xe3 m\xdd1T=\x80\xc1D\x02\x8c-\xa8?\x0f\xd3y\xb6r7\xdeM!\x92d\x86\x8a\xaeC \xc2(,]}\x17\xe9xK\x1f\x1c\xef\x92\xd2\x8e\xa3Q*\x92\x04q\xf8\xb1{\xf0x\xb4\xbbk\xbe\n\xfb^M\x8f\xb6/A\xee\xc6\x1c\\\xc7\x9c\xf4\xe3\xf2\x93\xc7\xae\x00\xdd_\xad)fA\xf4\x9bn\x8a7x^\x93\xddn\xaa\xe7\xa8\x9fS\xfd\xef\xa0z\xf6\x9fZ\xf0\xf1\xbe.\xf1\xcb\xcc \xaao\x12\xff\xbb\xf1\xf1\xc1\xc4\xb4\x00\xc1b\xc8>Rn\xc2^ $h\xdb\xe6\x92\x10\xa3\xad\xf3l\x15\x17\x843&\xa5+O\xc4\xea\xc5\xa4y\xb4\"\xd3$\xfdN\x0d\xd2\x9e\x1f\xc29|\xe0}Id\xa5=\xf3!\xea.\xd2\xdalX~\x1e\x04:\xceI\x91%7\x84\x03\xd0\xba\xf0W\x96\x858\xd7\xddZ\x1e\xbe\x82\xff\x98\xec\x99\xa5\x05\x93\xf1#O/\xb3?m\xb2JJk\xc5n\xc6\xffq\xd0L~\x04\x0e\xcc3R\xa4\xdf\x95\x98\xf7g]BN\xae\xc9\x97-\x8b\x8e\x94\x83\xd3\xaf\xba\xd0\xf4\x82b\x8e\xe4\xfe\xabiD\xeep\nO\x82'\x9a|\xc7\x88j\x9d'\xc1\x13\x07f\xe5\x85K\xb4\xbd\x128\xb6\xb5p0\x04o\x93Y~\x81J%\x1f\xb6\xac}@\x0f.7-\xef\xa6z\n\xf3\xe5'A\xa3\xfb@ e\x1b.Tn\xeaN\x0f\x0ft/\xdc\xb8~u\xa8\xbfB\xd2\xceD?\xc4\x01W\xc3 \x85\xd1\xf6\x08\xc8\xeb\xf7g=\xc0DPE\\\xe7\xa8\xed\xd8\xf1\xc0\xaf\xad\x84\x8e2\xd02\x90\xe0\x04\xcb*\xad\xbcFPS\x17I\xe2\x94\xb3f\x8e\xc7\x96\xa1\x9a\x0c\x83*+\x90\xe5\xc3\x91\xb6\x8c!\x9b\xf6\x0ckuWi9I\x0f\xd2\x11\x10\x93\xd9p\xd7N!s\xeb\x1d\xf3:\xb7\xccBPW2A\x9d)@\xb1s\x0f\xff\x1e\xfb\xb7\xc1\xd8\x87\\G\x82h5u\x0f6d\xb6L\x82\x9d\xd4\x9d\x1a\xc9\x9bC\xb3\x01\xc7dl\xf6CAi\xc6c\xc1l\xcc\x1d\x94\x98\xc0G\xfc8Eb\xf4\xb7\x0748j*\xfc\xa6[3:\x97l\xf7\xd0\xbd\x1bC`0\x0f\x84\x98\x87\x9f\x0e)\xf3[v\xb0\xb9U\xb0p\xb5\x08\x06\xbd\xd4Q{;\xb8\x00\xf6\x9a\x94\x92\x84\x89\x0d{C\xbf\x91\xdd\x03}K\x84\xcf\x90\x99\x12\xdd=\xd4\xad\xde\xb9\xcf\xd0\xa1\xceQp\x9f\xa1\xc3\xe9?}\x86\xfeA}\x86(\xaf\x94\xbaO=\x1f\x9c\xb7\xe1\xfa[9\xa1\x1d\xea\xde%\xdc\xebdj\xf6:\xd9\xdb\xd5\x0f ;P\xfa\xf1\x0by\xedG\xfb\x81\x18\xe1o\xc9\x11\x93|\xb628\x06'k\xe4\x0dR\xd5\x8a9\xba\xc4n\x89\xe7\xa1\xa4\xe7\x81\x82\x0c\xc6\xb6\x86\xfd\xc0U_3z\xae\x8f\xc6\xe3\xa7\x93\xa3\xa3\xe9\xfe\xde\xd3\xbd\xf1\xd1\xd1\xa4-nx\xf2\x9f\xee\xd9\xf1\xf8~6\xd99\xba\xf8e\xfe\xbd\xf7/O\xfa\xd6\xc0\xa2\x86\xc1\x10>|:FZxk\xcb%\xd2U\x13\xfa\x13\xc2\xb2\x9f\xc8F\xae13v\xe3hg\xeb\x94\xf9\xee\xe7AI\x8a\x12u\xba\x88\xb1\x84\x0b?\xcb\xffy\xcaC\x97\x96\xf0\xac\xd7\xefd\xc8J\xf5\xad\x82\xed$Xb\xeft\x0c\xf7T\nu:\x08m6\x17\xc2\xec\x84\xd5r\x1e\xa2\xb7\xe1\xc9/\xc1\xfd/3\xf7\xecx\xf6\x9f\xb3_..\xbe\xbfwg\xcew\x17\x9e{v\xec\x9em\xfd2\xf1f\xff\xf9\xcb/\x17\xf7\xbf\xfc\x12x\xdf\x9f\xfd2\xf1~\xb9x\xd2\xbe9O\xfe\xf3\x97\xdb\xef\x1fu@\xb8\x7f_\xa3o\xde\xd2\xc2\xdf\x8bm\xe8>A\x8a9k\xaa\x90bu\xc1U\x96%$L\x9b\x12\xc5Ik\x0bY1z\xbe*q\x9c0\xbaX&\xff\x12_\x10\xb6Cq*d\x88\x1b\xa9\xf9j|\xd4\x96\xe42\xf15\xb9!).\x9d\xf2\x13I\x03!\xe1^\x85_~\x8a\x8b\x92\xa4$o**\x855\xb3/\x8d\xac=\x84|C\xd0\xd5\xd9Xlo\xcc\x04\xda\x9a-8\xedi8\x1bD4k[\x00\xda9L}H\x83Wt-_\xad\xe2\xb2D\xdb{,k\x10\\\xb3\xf2\\\x0d\xa1\xbe\xd5\x16\xbd\xa9\xc3\xa9\xe3\xb7\xea\xfb\x89\xf6}A\xf4\x1av\xa8a3\xd1\x06\x91\xc9\x18\xdd\xc3\x99.\xd7$\x9cH%c\xeduV0K\x8cN\xabm\xf3\xb9\xf2\xd50N\x0f\xea\x8c\xc8*\xee\x8e\xc8 )\x11,\x96\xcd1\x8f&(\x1fsW\xbb\x06\xbf=Pr\x81\xd0\x999M\xd4AwK\xae\x16\xe0k\xee4\xdf*gF.\xedr\xe1\x97i\xa2\xd2x|\x0e\xd9\x14\x97b^\x91!9[\xb0\xb0\x1fb\xf1\x0dY7\xe9\xec\x17\\f\xc7\x1d\xf4~N\xa3\xb0\xba^\x96>Ti\xb1&Q\xbc\x88\xc9\xbc\x9e\x1b\x0e-\x00\xf7;\x9e}\xd7\xf1L\x927\xd6\xdf\x82\xd9t|)\x99 \xefB\xa9\xf6\xd0Z\xe3\xac\xc9\"\xcaW`V^\xd8\xc1.\x83\xcb\xa9\xe75\x0e~\x9a\xed\xb9i\xc9\xba\xfc\xf8\xd2&G\xbfE\x9ah \x7f\xd2\xe5\xca'5\xea\xab\xfb\xb4y\x17\x16\x17r\x82\xde\xb8\xaa}\x92\xb7,\"\xdcD4\xdb\xf6\x91\xed\x84\x92=\xa0J\x813)\xb9\xadG\xbf\xcd2\xe8!\xdct\x1d\xe9\x8d\x83\x0c|\xee\x92@\x0c\x89\x92\xfc\xcd/$\x87}\xfd\xfa2\xae@\xbb\xd2\"\xcaaS\xc4\xc2\x06\x11\x91\x9aOn\xe0\x14fZ\x91\x0f\xe4\xc2X\x91\xf8\xa6\xcet\xb0J\xbb\xbb\x0d\xf3\x94\xcc\x81\xa5\x0b8\xa5\xc8\xbb\x85ZP\xdbjD\x9b\xc7\x06D\x84\xddT\"\xf6\xb0\xde\x1d\xb7)x\x0e\x15vi\x19\x0dsa\x88\xb2\xb4\xc8\x12\xc2\x80\xbf\xeb\xb8i6'\x1e\xd0*\x18>s\x9d\x15E|\x95\x10P\xc8\x84\x15Ye\xf9\x1d$$\xfc\x0csR\x92\xa8$\xf3\x00\xfeu\x0eI=\xeap>\xa7e?\x17\x04\x08\xfbJ\xc7\xf6\xae\x07e\x06q\x1a\xe5\x84\x02\x9b$^\xc5e\xe0\xb4\xb6\xb4\x89\x93j\xa4\xbf\xc4\xf8\xcb<\x8c\x90\x08U\n\\\x91\x0e\xc9v\x932\x14i\x98\xaf\x96^\xb3?\xf9\xf67\xbaY\x82\xc2\xa7(Hy!\xd1\x95&dS25\xd2*\xbb!b\x0et\x98\xb1\xc7\xe3\xbb#\xc2\xa3\x9bNT\xf0#\xa0Y+\x82\x92\xfcKXi57\x10o\x00\xf6\xc9\x96#\xeeYkud}kyS\xfb\x7fQB\xe9w\x81`\xd8\x8c\x0e\xbf\xf4\xcb\xdb\x11w5^\xb0\xfbl$$j\x0c\x901a\x1a\xddQ\xa1s\xcc\xddT\x02k\x94\xea\x97V\xf5\x14\x83\xbdr\xd9T\x0b\x16)\x90T[Q\x15\x98\xaa/\x19<\xd5\xe3-\xab\xb8\xd0p\xa4jlX\x9d@\xb8\xb3C!\x8e!&\x0d\xf0\xc5Hg\xe1E3K\xfa\xab\x99\x17\x9d\xa5R\xc0'\xda\xeeS\xf5\xdf\xc4\xfe\xab\xf6\"I\x86\xf1Vf]{\xebz\xf4\\\x85\xad\x8e97!\xecYf\x1c\xddm\xf3Lg\xf4Q \xa0\xe3\xdc\xed\xed\xce{\xd1\x1e\x92\xb97\xebA'\xe8D\xaf\xccX\xdf\x1en8 \xb6\xb0\xbd\xd0nGLs\xdb'z'\xda\xf9\xc1\xe5\xd0`+\x18y\x9a\xdc\xc2\xd3X0\x83\x1e\xee\xbe Oi\xa1\x8bO\xea\xbbqbotV\xdf\x99\x1dh\xf1\x1d|%\xba\xb6\xd1v\xa8\x93Ag\xd9D\x96\xb6i$\x16'I\xbf\xc6g-\xe2\xcf@\xf9 \x1a\x1f\x8eav\xd17\xd6\x97Y\x95v\x0b\x04tv\xdf\xa6\x1e!\xed\x8dm\x9f\xb3\xc68\x83/\x83!u&z\xee\xd4\x15\x84\x05j?\xbc\xd1\xb8\x11\xfb\x0c;\xc2\x85\xa9_\xf5\x0b 5q.\xcf\xc5!{\xbeO\x0e\x9fz^p^\xe6$\\q\xd7\xdd\xe0# \xe7\xe1\x15Z(\xe0\xef?s\xbfg\xf6\xc1\xe4)\xfa\x86\xfcX\xad\x13\xf2\x85\xa9C1MLP;\xf9\xb1zGS,\xfd\x10\x16\xc5\xa7e\x9eU\xd7K\xa6\xfb\xd8?\x1c\xa4\x83\xed\x0d\xd1d\x0ett#\x92\x99\xb9\x18\x07MyW\x93\x7f\x06\x95?h\xc7\xc4$$\x89\x0b\x8c\xb4\x02\xc2o\x83!\xa1\xb4\xcc\xef\xd4\xa2E\x9c\xc6\xc5\xb2\xcf\xc7\x87>[\x9dK\xa0?\xb5\x96\x8fujG\xed\xa52*{=\x0e\x93r\xa3NQ~\x84\xd6%\x0fD8({\xa3\x80\xfa\xdd5I\xe7qz\x1d]\xed\xecP6\x8f't\x81\x1cW\xd0\xfam\x9b\xf2\x10\x0f \xa2,\xffL\xe6\xdcc\xb5x\x9d\xa3]\xac\xa9XlRIy\\\xd3g\xa7\x86\x00\xa8\xf4y@\xb5\xb7\xc1V\xa8\xe3r\xcb\xb7i\xd5fCB\xee\xe4N\x82\xab<\xbb-\x18\xf12sn\xc6\xc1d\xec\xf8@\xff8\n\x9c\x8b:\xfaW\x13\x0f\x8cA\xc9\xb1\x0f\xfb\x1e\x8f!\xcd\xbci\xb2:\xda\x8f\xda\xdb\xaa\xbe\xa6\xe7e\x88Z\xd9\xeb\xf6pP\xc8\xe2\xee\xeby\x04\xa3 N\x97$\x8f9L\xd8\xd5\xd36\x08\xb1\xa3\xf9\x90\xcc\xc9:'QX\x92c\xbc\xdeO\x0d\x0b\xd8V\x85'\x1c\xfa\xe8z%\xfa\xac\x99\xc6i\xec\xf1\x906\xed\x1aK4\x81h\xf2\xa6(\xde[\x1e\xfcfH\x0c0\xf7\xe1\x86\xf7i\x07\x0cw\xf8\xb1\xe5\xe5\xb5\x114\x03\x97\xaf\x85H\xb23X\xc8N\x1f\xaaW\xda\xf7D\xdcb\"\x0b~\x0dt:\x82\x12\xa6\xe5x\x9b\xcd\xd1\\l\xab\x94\n|\x16V\xd7m\xd7\xd3K(W\xb6\xc5\xfc\xf1\xe8\xf9x_\xbf1PZ\xb5~5X\xc6\xd7\xcb?\x87%\xc9\xdf\x86\xf9\xe7\xf6\x16\xd0'\xc2\x8a\xa2\xdd\x7f\xef\xff`a\x18\xdd\x19L\x0e\xe0\x18&\x07\xbb\x87{\x96UP\x86\x02\\k\xcbh\xd3\x18\xce \x86c\xbe\x16Q\xf3\"\xa2\xe4H\x04\xc7\xb0\xf0\xcd\x8d\xc8\x19\x15[\xef\xbd\x06\x94\x87\xc9\xcb0I\x98\xc0g\xe2\x0b4@\xe6?\xe6a\x9c\xca\x85\x0c\xe2i%\xeaw\x0c3\xa8esR\x94yv\xc7\x0b\xcd;\x92\xe0;\x9e\xe7fN\xa2l\xce\xbd\xablxJ\xa9C?N\xea\xdePB&R\xc1\x00kP-\xbb\xbf\x07\xa7*\x17\x87B\x98$spX@w\\\x9b*\x03\xb3R\x9d\xe2.\x8d\xb8\xb8\x04\x7f_\xe1U\xfe\x90g\x11)\n\xed\xe3,E_\xd1N:O<[\xdd\x94\x92\xfc\xdc41Moe\xd8h>\x9b\xe2\xc9\x99 \xfa.\x8d\xba\xeb1\xf7f\x1cxteG\x87\x94\\\xec\x9f\x95xJ}mE\x07\x0d\x85Q3\x07\xe2\xee\x91\x84\xa4\xbe\xf4\xb7\xe2\x86\xa5?\x0f\x88\x8a\x89g =\xba#G\x8aggGB\xee>\x1a\xe0\xbb\x0dNrc\x1fr\xcf\x97\xb0\x94\xfb\x8as\xe4~k\x1f\x98\xd0\x94 E\x85<\xb5\xe4\\=\xd3_\xd1\xc60f\xbfO\xc5\x1b\xcf\xf3!\x91T\xc5\x83\xf6\xf4R\x05\x8aL\x8en\xdae\"\x1f{\n>\xa4\xbbQ\x89\x9f\x1c\x9e\xa3\xe6@\xc2\x8b\xe8\xbc$V\x8aBN\"0!K*\xc1\xde\xb8\xac\xf7\xe6\x9d\xdc\xcad\xd0l\xae\xa4\xd9\x98&\x91B_\xf4\x03\xf1\x88\xb8\xc6\x1c\x07moc\xf4QA\x0ca\xda\x9b6q\xc4!\xf2\x9c\x969\x06(\xfc\xe0\x96\"\x86\xa5\xc26\xe6n\x03\xbb\x07\xcd\xf3\xd6:vb\xa4?\x0c\xd9\xb4\x04\xcd@t\xd0a\x16\x04\xd5\xdb\x87\xf2y\xa6\x8a\xa0\x98\xcf\xb6~5\xf1o\x84Lv\x82#\x069\x92ln\x89\x02\x02\\\xeao\xe2z\xcd\x98(k$\x05\xe6\nu|\xad\x90\x81\xcd\x82\xad\x1b\xda!\xc7\xa8\xae`&O\x98^\x0e\x95d\x05\x0b\xea\xc6\xa3^\xe0j\xf8\x10\xc2\xe8\xd4$L\xa3\x0f\xc69e\x88\x00\xcd\x7f\xfd\xfa\xf6\xb1\x1bSg4\xf3\xc1q(i\xc1\x10\x80z^F#\xac\xda\x81R\x18IB\xc9\x15\x8bP \xe3c\xcdd)\x8fg\x17\"0<\xc1\xce\xad\x0d\xcf\xb4\xcfz\x17\x05!d\xc4\x9d\xf2\x98\x9a\x8f\x0f\xa2e\x95Z\x18-\xf1\xa0\xb1P \xd29v\xd7M@\xc4\xeb\xe9\x16\xf0\xd0s_\xef\xd0\x04!\x93\xc2\xcd\xc11D\xf5\xa6E>e\xc0\x12\xed8\x98\x17\x8c\xde\xf9\x1a`z\x1b)\xa8\xe8S\xbb\x88\x0b@d?\x0d}2\x1e\x90@\x86\xf2\xado\x81$\xc3\xe0\xf0\x97n\xff(\xc1Abtx%\xab\xb10ld\x85\xfa\xb8\xd0d\xa2\xe1-\xd9O\xbe\x8c\x83\xc6un\x85\x9b%G\xa7\x0d\x0bc\x95Pj\xc0\x1b7A'\xc6SviU\x1aN\"\xda\xeb7\x8e\x05\xf2\xd3\xe7a\x182xe\x9d\x94\x80\xf1_\xbatM\xec\x10\x0d\xe46\xd59\xdd\xdf\x03Q$\x07\x14,Z\x88\x17N\xad T\xd2\x80\x99&{\x18+\\\xd59\xe7\xaa\x90;\x1a\xb8\xa4]\xa8W \xf6\x86\xe6fw\xc8\xd2j\xd3\xa4/\xd9\x94C\xeb\"5\x92EJ\xf2R0p\xad:\x8a\xd4A\xab;e\xe55\x16*\x85\x00I\xbb\x03,\x98\xc8\xec\xe2\x04\xca\x13\x8fN\xa3*\x96,4 \x12\x82t\xd9\xac;\xadyy\xb7\x81d\xaf\x18\xdf\xee\x96J\x1f\xee\xe6\xc4\xfc\xd7\x84\x9b\x93{-{\xac;l:\x8e\xc9\xe5J~0\xcc\xe9\"\xa8%\xae\x9b\x05|\x97U{\xf5\xd2\xbbv\xde\x10\x18\xc7\xe7hL7\x1b+\xc4E#\xf9\xe5\x96JZ\xc5f{)wC\xc2y\xe0\xf8\xe0\xfc\xf8\xea\xc3x<\xde\xb5\xa4F\x83\xf6\x05\xaf\x8b\xed.\xbb\xf8\xda\xb5\xb1\x08\xdc\x13n{\x9b\xff\x15,\xc3\xe2\x0d\xe7\xb7\xc0\xe6\xd3\xf8\x9a\x97IQ\xc7\xda__\xd0\x8bK\xef\xc6\xb0\xda\xbe\xe5,\xac|\xc3\xc8:\xdc\xef\xfa\xe5I\xb5#\xcc\\66-\x1b~\x93\xde\xf6\x15\xf0T\xcd\xdb-\xc9\x8a\xcc\x8f^\xf7a\xcb\x07\x84B\xf3^\xf1]\xedG*5^\xb6\x94\xf2>\xac$\x10\xb1\x8e\xd7\xa4\x0f:0 \x80\x8ah\x9a\x1c\x8a/\xc34\xcdJ\xa0\x0d\xf9\x18\xa7>\xe7\xeaM\x9d\x15\xd1zn\x8b$\xed\x1a:$\xebY\xe4Y\x03cn&\xbb*\xc6\x1e\x19\xdfa\x80\xe4X\xa6\xab\xea\x84\xfb>\xac\x9b\\\xce9nh./\xe8\xd2\x8e\xd2B$\x0d\xd6J*h\x91\xd9|\xf0\x91Zc>\x01\xdd\xfb\x13\x80\xe7\x10\xb4\\A6\x81T\n\x0eM\xa90\xca\x17\xb0\xf0\xd3\x02\x00Rj\x1b\xd1%sr\xd5$\xd3j\xeb[R\xf0}\xd1\xfa\x9d\xe7C\xcc\xe5\xeeg\xc3p\xb7\xa0\x06\xa4#\xc3\xb6>\\\x94$\x07\x92\xcem\xc1*L\xd4\x8d\x84\xa2\xf1\xb0\x98V \xefb\xca\xc3^\xeb\x9c\xb7\x9dK\x07I=c\nZ\"\x9e\xca\xa2H\x00\x89\xb8iH\xe53\xe6\xa9\xa8\x06\xe8\x7f\x1b\xde\xe1Ua\x0b\x81\xb5\x11\xf4\x14PfP\xa0\xb1\x80cM\xd6\xdf\x04\x05a= 9\xa4\xaa\xa3\\C\x9f\"\xd7i\x9a\xa5;\xac\xd9'\x1c\xd3 \x9f\x83\xc1\xbf\xb9A\xae\xb6\xee\x95\xba\xee9+\x89\x05\x1f\x1a[\xf7 f2S\xe6\xe6\xe7\xc6*\x01V\x19\xee~-\x0d\xb2\xed\x0f\xdaq\xf5*\xf1MM\xf7!\xf0R\xd7\xe8\x19\xd5A`\x8e\xdd\xdf\xdc)~}\xb1\xc7\x1e\xe9\xb4\x91<\x92\x9f\x87\xda\x08\xc3\xdeP\x8e\x06_U}A)\x11\x19K\x17\x9e\x99\x05T\x16\x8co\xbd\x03!J9Z|g\xde\x99Y\xaa\x16[\x8d\xac\x86\x91\xb4\xed\x02$ \xd73 \xaaf\xd0\xfc\x1d3\xdd\xd7d_c\xcb\xba\xa0\x05Q-\x18\xc4\xeb\xc1\x04\x0c}\xe7&b#k\xb3\xb5\x1d\xfa\n\x0b\x17\xdc}\xd8\xf0\xc6\x1d\x83A\xf3.?B\xacp\x0cq\x8f\xaa\x8c\"\x1cc\x1c~\xf9\x11\x92\x07c\xee\x05\xf9\xa17\x9d9;\xdb\x8f&\x0b\xd2\x1f Q\x8ey\x19\x8e\x8dL\xbe\xb1\xaeU\xc83:\x85\x89\xf9\xf02I\x8f,) \x1b\xf8\xd1 \x9e\x8b.\x88\x152\xce\x0f/\xb0/\x85\x82\x836 CO\xd5 \xe2I#\xdc\xd9i\x1c\x8d\xba\xda\xae\xd2!\xad+<\x9b\xda\x8bA\xa7!4a\x0c\xc8\xb3\x1f;;\xbe\xa4\x15\xa5\xe4\xab\xa4/\x93\xa4\x1e\xf8\xcb\xa8=k\x0bL\x98\xf6\x8c\x93\xc4\x9dD`A\xca\x1f[\x1a\xf3nZ)\xb6\xa5A\x14\xa4V\x19\x94\xd9O\xd9-\xc9_\x86\x05\xf3\xb0\xd8rg\xce\x92|\xa1\xdc\x11\xd7\xbb\xd3\x7fw\xf0\x8f\xb0\x88\xe2\x98\xfeq\x15\xa7a~\x87\x7f\x85\x059\xd8\xc3ZQ1\xe5\xff\xeeL\xf9g\x93\x83\x84\x88\x16\xc4\xdfyx+\x19\x19\xb9,\xd3\xa2\xa7\x8d\x03\xad\x8cp0\xb59\xe2\x90\xbbm\x8d[\xc1,\xae\x9bt5\x12{@ \xccM\x98 )\x10\xf7\xf6\xb6\x1c\x98\x8e\xb1\xb8\xb5\x8eZ\xc8\xbcr\x19\xde\xe4\x8d \x8bP\x1e3\x10\x8774\x17\xb2Y\xcan)@g\xc8J\x01\"\xe2\xc6>h\\\x0b7\xfdZX]\xb7y&\xd3\xb2)\xd3\x04fiDj\xa1[\x07\xe9F\x1a\x93\xa3\xb1/\x99f\xb5E\xd4 !\x95\xbc\xc5\xa8\x0c\xbc\x82\xb5\xe9\x92\xf1\xdamt\xad\xe4\xdd2\xa8\xb6k\x0bt\x1d\xa0\xf0\x01\xb4\xe7\xd6\xbe\xe6\x852\x1e+\x9fk\xe9\xde\xed\xec\x9f\x9e\xe1~1\x89z\xd3\x1a%\xf7\x8d\xf8[\xbb\xa6U*\xd7\xa9\x7fi\xb5\x9a:\xbd\xfc.\x93\x94\xa4s\xd7\xf3\x81\xb4\"8\xfd\xa1\x19\xa9\x9a\x9b\x11\xb3\xe8\x1f\x8d=\x8a\x0e\xdf\xacVd\x1e\x87%\xd9$\xb5~\x7f\x0e6\xfb\xbe\xf0\x03\xd2\x1b=\xe2\x9b\x0c#u\xf7\x0e\xf7<\xd7\x833\xee\xbf\x8c\xc9\x13\xd1\xb0\xf5p\xff+\xa6z\xd3\x84o>2\x87R\x99\x9a\xd3\xc2\xed\xea\xc1\xc3*\x83k5G\xec\xedPC\xfc\x1275\xb5h\xee\xca\x07\x850\x8a\x0c\xaf\n\xf5M\xf4Uy\x02n\xea\x90\x0d\x0b\x1f4k\xf4\xb8\x95=\xa5\xb2\xf8V\xaa\xdf\xa1B \xc5\x00\xb6\xcc\x1b\xd8k\xfc\\\x17Z\x84\x05\x86#h)\x0bo\xb1\x10Y\n\x16\xf0\xfc\x14\xb3\x14D\xee\x82\xa7\xfc^\xc6\x8d\x93\xd3\x0eDn\xe1.<\xef\x04X\xe4-\x18\x8d\x0c\xea(\xb4\xf3\x91\xa5\xac<\xccP\xc2Q\xe3\x8c\\\xf8\x90\xbb\x89\x94\x02E\xc3\x8f\xbc\xb47\xd3\xfc\xa0\x93\xa6xH\xb4\xb0\x91\x10Tj\x03\x18F\xd4\x9aDo\x96\x14\x8fHa\n\xc2\xc4\xeeA\n\x12]\xa5\xbcx`R\x82\xeeA5\x07\x8b\xd6\xad\xf3\x8b\xb0P\xcc\x9f\xc8\x97\xf2]6'\xaec\xcb\x99\x92ah\x01\xdbx\xb4\xb0\xb8]\x029\x0b\xfb\xcd\x1d\x858\x82g\xcau\x16#\x9bX\xf1w\xb7u\xa1\x90.\xb1!v0\xfdp\xaai\xe5\xc4c\x96\xa8\xa0\xcb\x9aJNY\xe4\xb8i\xe3\xc3\x08u\xfa?V\x1f1x\xe9Zf\x86\x176\x0e\xe6a\x19b\x98\xc2S\x18\x8d2\xf8W\x982s\x07l-(\x96\xf1\xa2t1\x04\x05\x17\xbf\x08\xafkN\xe1\x95\x06m\xd5\x83\x17dW\x05\xc9o\xd0R\xca\xbcx\xd12\xcc\xc3\xa8$\xf9\x8fa\x19\xb6\x82\xfe\xb3V,\x16\xeb\xbd\xf4\x02}X\x9a\x17\x0cai&X\x99\x94{F|(/P\xec\xc0\x15\x94\xa8\xbde\x04\xb0iq\x86\x88\xc5\x1e|3\x1c\xb6^\xe3v\xe4$$p\xec\xaa\xb0&\xc1\xb4\xe4\xf6f\xf6B\xe9\xe8D\xdcO\xdaM\x9d.\xa8C\x8cj\x1c\xca\xdb\xaa\xc4\x84|\xef\xd9\x8e7~\xb1\xb1\xdbze\xbf\x95\xc6\xa6\xffL\xae\xfe#.;:\xb0Th\x1f%\x1bH1\xdf\xa8\xde\xe0\xbb\x80\x8c_\xee\xea\xa2\n\x00\x16\xb8\xd5\xd8lA\xcaO\xf1\x8ad\x15J;\x0c\xdb!U\x182\x80\xa6\xba\xcb\x0e\xfb\xd8<\x98\x96T\xeeA\xba\xb2\x83\xe8\xcaoBeY3h\x9a\xb2f\xaay1\xa7l\\\xfb\xd3}\xfe\xef\xc1\xc6y1;F'\xd2S\x1e\x9a\x92\x8d\xa1\x86\x8f\xa7'P\xc3\x0e\xe7\xdda\x87\xd5X\xe9\x96|WV\xc8 \x84t\xed\x0e\x92,\xc2\xc3~\xdcJaF\x9fe\\\x94Y~g~\x99\xadI\xaa\xb2\x7f\x86J\x98\xf2\xab\xb7\xd6\xeb8\xd1+\xd9\xe6\x0b\xe2\x86K\xf1\x82\x9b3\x7f\x8b\xc9\xcal\x89\xfa\xccV\x1cta\xd8wmxr\xc3\x1dFm\xda\xb8\xb4C\xc5\x9b\xd7\xf1\xde\x0c\x82P\xab=Im\x08\x13\xf3\xb0Ih\x15$\x82B\xbb3\x87\xae\x95\xe3\x83\xf3C\x92]\xd1\x7f_g\xf9\x8a\"=\xe7\xc2;\x01\x16\x16\x13\x13\xf3U\x08\xc0]\xcf\x0b\xe6YJ\x90\xc4E\x8dE\x07\x92\x13z\x97\x98\xe5\x10\xb4\x93\x1f!\xc4)_3\xc693;QV2\x0b/\x86`5,\x91\x0d>\xec\x0b\x93;\x8c\xee\xe0P`\xe0\xd0k\xcb\x0b]=\xc9@\xaf;\xbb$\x1eW\xcf\\\x9f\xb8@h\xd6\xe7>\xdc\xf8p\xe7\xc3\xb5\xde|\x81y\x0f}\x98\x1b\xdc\x92W>\\\xfap\xe5\xc3m/\xbb\x08\x82\x83Z\x83\x08\xb6\xfa\xa2\xc6\x05/\x8c\xf1 \xe8#\xc2\x15v2\x00\x18\xef\x8fe\xec1\x87\xe0k*1C\x8a\x8ej\xd0\xacf/\xfbi\xf8\x86R8i\xad\xdd\xea\xfc\xca\xe2\xfce,\xdddD\xc3Gb\x00vmt\xf9\x05\xbd\xa5G\xe0\xc0\x1bq\xa0\xdb\x95\xce\xe1\xb4^[\n&n\xdaU^Y\xd0\xf1\x0bT\xca5\x82\xedV\x85\xf7p\n/f fNz1s\xfe\xed\xdf\xea\x8b\x85E\xe8\xfc\xf1bvcH\x1a\xfd+\x05\x86L\xdfxc\xe00?S\"\x00\xce\xe0\x1c\xce\xe0\xd6uHZ\xe61)\x10\xa2\xfd\n\xf6\xd4uoX2\xb7<\xbc\xc3\xa9\"\xa2z\x11\xf0\xafio\xef\xdb\x14\xd1\x1bD\xc5W\xf4\x96\xb8o\x18\x19\x8e\"\x0e\xcf\xf3P\xea\xae\x8b\ni\xf5+\xa6>G\xcfj\xf7\xca\x87/>%\x11(\xba\xa5<\x85\x89\xed\xb8\xe2\xabT\xd1\xea\x89\x0fK\xcf\xf3\xe1\x9c\xb6\xf0\x1e\xe1\x8c\xd8 \xec1H\xc3\x15\x93\xad\xbf\xe2x\xfc\xd7\x81P\xe6\xbd\xd5\x9f\xcb\xe3n\xf1[L\xf7\x8bW}\xeb\x15\xdb 1\xb4\x178\xb4_=\x1f\xc2\x19\xa1\x94\xc9\xaf\xf4\xaf/\xf4\xaf\xa5\x0f7f\x11\xdf\xcaj4\xc1\xe6t\x8c\x9bHw\xed\xd6\x15\xd3\xb4\xc8\x14(\x988\x86\xbb\xa6\xba)\xd3\x97x\xf8\xae\x1e\x83A\xb1\xe8\x9bl3A\x90\x89\x97\x14\xc2\xad<\xc0\x7f_\xd0\xa9gt\xea\x97>\xacf\x97\xa6\xf0\xa2,|\x91\x1b\x07\x1f`\x04q\xf0\x1a\xbe\x07wM\xbf{\xe5!\xfc]\x99c\x11\xad\xea\xc2A8\xf7FJH9\xb5\xd0\x0f]\xdfC\x1d\xa7\xa7\xd4\xd2\xe4\xda\x08{\x01\xc1\x8d\xba\xb9\xae\x08\xb3:\xcc\xeb4\xd2\x12}7,\xae\x05\xe4\xb5\x17\xbe+ mk\x0c\x1d\xd6\x81`\x1c\x06\xfd`\xa3\x91X\xe2\xd6\x9aF\xd2\xe30n\x1c\x8c\xd5\x1f\xb9+\xce\xca\x10\xf4S\xf7\xc64\x08DV\x1fX\x9a\x1etb\xe5\x93\xb9\x95\xba\x93}\x16\xa54u\xa7G\x9e]B\xccG\xf3\x14\xb6N-\xcaT\x91\xda{\x1e\xdf8\x9e\x0fN\xf8\xf5j\xd4\xa7m \xa1\xce\xdc\x0b\xc2f\xf2\x1b\x92\xfbS35|\xf4?3\xdd\xa2\xaa\xf6\x9bn\x9a\x19\xa8\x95s\x98\xab\xf1\xcc\xf9A\xa6\x93}\xcf\xdd\xd2)uc&\xf9\xbeu\xb1\xc7\xfa\x0cyB\xc76\")\xda @\x813\x163\x8d\xec\xe5\x9a\xb58\x85\xd0\x83\x94\x1e\xde\x8a\xed_\x88K\xb1\xbd\x0d\x11\x13^\xeb\xc1\x0d\xb8\xf3\"i\xc2\xe7\x16'\x1e\xff\x8e\x12p\xb3b4b\xf1}\xdd\xff\xca\xdc\x08[\xbb\xbfoZ3#\x97h\xb3M\xed\xdd\x9f}s\xaa\xe8\xcel\xfe\x95A\x93\xda\xc5\xf7\x06\xd7\xa4\x94\xb2d\xabV\"\x96c]\x8a\xbd\xe3y+\x91\xc5\x9de\x176\xf9\xae\x9ae\x8b\xf33\x8dW\x85\xf2\xf6L\xfd-\xd1x\xc7\xeag\x9c!?\x83J\x97\xe4n\xb8\xf8\x87\xe6\xc5o%\xe4no\xc5?s\x14\xd7\x03\xee\xcbu\xf8?;G\xb1\xf5\xec\x98\x12/\xfd\xcf\xcd\xa5\xdf\xb9\xcd\xbc\xb7\xf6.+\x16\x8b\xee\x04\xb6\xc1\x04\xd5\xb5<\xb6\xee\xd4RO\xd8,\xd1:{\x96:\xe6\x8c\xb7\x9b\xeda\x9f4m\xb2{\xd0N@\xbf\xfb\xf4\x9f \xe8\xa5\xe7\x7f@\x02\xfa}sR\xc4\x01\x19q-\xe7\xbf\xae`\xb3\x9f\xa4}\xf3@\xe6\xcd\xbe\xc7\x14.\x99y\xe6\x82g\x016\xbf\xa5TOhu\x14\xe1c*DJ\x9c\x82ns\x84 \xd6x6s\x8e\x03\x8e\xc1\xc5\x08\xdb\x98D\xf1e6'/J\xb7\xf0\xe4\xee\x9d\xe7\xc3\xdd\x1f\xa4\xa2e\xe7t\xa5\xdd\x91?r\xf8\x15\xc0!\xa4\xee\xde\xc4s\x13\x0f-i\xbb\x1aK\x1a\xd7\xcb\n\x83\xf4\xfa0\x91\xcc\xae\x1f(eI\xf7\xe1&H\xb3\xdb\xde\xd6\xb0\x96\xb5\xa19\x86\xce\x16\x06\x99\x94\xa2\x9c{\x01\x05zS\x1fb\xfcc\x12d\xe9\x8a]68\xa5\xd4\x07\xc6\xcap\xb3`\x9d\x15%\xbf\x85\x08h&\x18\x81i\x11\x84\xf39&\x1a\x94Se\x197Cj\x00\xc9\xbcE\x10\xafh\x8f\xe7Q\x1e\xaf\xcb\x82\x8e\xac{j\x0by\x0c\xdc\xa1\xdc\x07\xe7{)\xac\x17\x85\x94\xad\x11\xb9\x0e\x9f\x90\x83\xe4\xd4\x16\x1b9\xed\xcb\xc9\xd2\x9c\x84\xf3\xbb\xa2\x0cK\x12-\xc3\xf4\x9a [\x1d\xb9N\x81\xa3r\xbcNK\xf5\"\x08\xd7k\x92\xce_.\xe3d\xeeJ_yA\xbb\xe5\xbe3,\x123\xb1\xc6J\x16MY\xdcS\xab2\xb9\xd3\x94Q\xb2\xa0oN\x84bG\x8f\x99>%\xc4\xd7\xfa\xfe\x18\xd6\x1af\xa0\xb0\xfa\x18\x9a\xecC\x9b\xd1)\xf6\xc1\x9a\x95\x0fVy5},\xce\xf5\xf4\xb996{\xee\xa8\xeb\xd8i\xd7\xda\xdb\xb5\xc5\x04\x9bv\xdd\xd7q\xcf\xeamJ\xe9\xb4\x0c29\xa53\x1ed\xed\xa2O\xbe1u\x89]\xe6YH\x14\xe5\x1e\xea\x9bl\x9e\x857<\xb6U\x16,ZQ\xc4\x05!\x8c9\xc5sRd\xc9\x0d\xf10\x9c-F\xb1[\xc5\x05y\xec\xc2\xb4V\x80-\xcc\x9e\x9d\x04\\\xd1\xad\xef'\x00M\xd4\x9f\xd9\x99\xb2\x0en&9\x963O+N\xdemmQ\x02\xcf\xf9H\xae_}Y#h\x8c\x15\x0f\x9bAS\xb6\xdf\xd6\xda5#u\xa7\x87:A\xd7\xb8v(\xf2\xffA]\xca\x12V\xe3*\xeb\x9dq\x03\x84\xa3\xde\xc5\xb5Q\xd7\x88\xa1\x02\xae\x1b\xc6\xa46\x1eW\x8f\xb12J\x16\xb5\xaeX\x85\x84\x9d\xba5\x15\xcf\xfb\xcb\xb2A\xb9yp\x0e#\xc8\x91Y\xce\xba\xf5\xbc\xf4\x90(\x85\x98\xbf\x9dk*}9|\xd4\xa054\xcb\xae\x89\xecr#\xc2\xb5\xf3}\xec[(\x14\x8e\xba\x8a2\x9d\xd8B\xa9\xf0\x80\x84\x14\x97@\x08Q\x12\x16\x05\x84\x85\xe2%\xfb\xbbLG\x93\xd2\x0bO\xa4\xc9\xbe\xe9\xc4|{W$\xe3Z\xb6\xc8\n\xfe\x02J\xab^\xbc&oS\x96\x1a<\xc5\x18]\\\x9d\x03\xe9h\xd4E\xe8\xe7h\x89\x92Z\x08\xfd\"\xd2\x84\xac\xa0s\x01\x0f\xad\xaeB\xf6\x89\xe4\x95\xbd\x95\x07\x0b\xce\x97\xb1\x80J\xe5\x8c\\l\xb8_\x8f\x03%8WJY\x1d\xea\x1a\xdf\x98\xbf\xda\x1dO\xf5W\x19\x7fE\xe1\x8f\x9c\x86\xb0F|\x86\xdc\xa4\xb5\x89 \x0b\xd4,\x83\xa5\xb2\x1b,iA5\xfe\xd0\xfek#\xf8d\xb9\xea\";\xc1\x163\xc27\x12=\xe7\x14:\x01\xf9\xb2\xceIQ`\xd6\xa4\xaa(\x81\xc4\xe5\x92\xe4p\xc5c\xccf\xb9D\x05\xb1`\xcd\x0e\x8c6\x86J\x1a\xb8\x935s\xccc6\x96\xaa3\x8eJ\xc2\x8d\xed\xe5\x94\xd8-\xd3jC\xa7\xf5\x0d\x0c\x08@\x07\xaa\x91\x96\x85\x95\xd5\xcc\xbd\x0c1,\xd4\xdd\xc6\xfb\xc8\xa8\x11\xb1\xc7g8\xfd\\\xa1CD\xb2\xa1K\\\x83\xcbKJ!}\x93\xfb\xa3\x1aX\xef\x8e\xbfM\xfc\xa4\x03\x93}`\xea\xee\x99\xedz'-\xc5\x12zMS\xe09f\xe1\x07\x0e&\x9eb\x906e\xe5\xbb\xe3\x03\xe3\xf5\x0cMc\x06a\x97\xb6\xce\xb3u\xd1\x845\xa4\x98\xaa\xe4\x01HyIN\x16\x05K\x0d\xc5B\xcc\xad\xe7a\x89\xf9\x0f0Nr&\xad{\xbb\xef\xe2\xef\xd8w\xa4\xba\xdd\x87r\xf4\xa9\xe2# \xa3\xf2e\xb6Zg)\xc1\xbc7\xbf=\xf8J\x95\x82\x94\"EY'\x90\x91\x88\x11%n\xa69\xf4\x90\x04x\xd8\x8f\xdcu\x0e\xf7\xeb\xec\xef|~\x01I\xffZ\x91\x8a\x9c\xf31\xd4V\x15\xbe\x94\x87^\xab\xfb\x92\x87\xa2\x15\x11\x9d|p\xc4\x14T\x01\xa7<\xc9E\x96G\xe4gl\xa8[\xb6f\xe8\xf0u\xf3\xad\x906\x96\x03\x07W\xfa\xe0H]\xab\xe3\x8b\x14\xd8\x17\xcap\xaeP^Qp\x1d)\x85\xaa\x94 \n\x1fb\xb7\x90\x1b\x90Z\xf3\xd4/\xe3\xe2C\x95\x93\xd6\xa9\xe0 D,\x8cB]\xf3\x18B\xf5\xca\xd2\xc6\xa4\xb7\xc5\xb7\x00N\xa9{ ;\xaf\x0b\xf8\xa2\xe1\xbc\xe2mV\xa5%\x99\xf7\xc5\x0d\x14\x14\xb5fc\xa9NC\xdb\xbe6ae\xae/\x1d\x0dm\x18\xe6\xfa\x1f\xc9: #\x16\xa0ph\x1f\xe2n\x18\xea7\x8bm\x86\xec\xf9\xe3\xf7@,\xba\x1c\xac\xfe\x1b7\xfd\xdb\xb7\x1f\xb5\xfd\x04GU\x9e\xe3 \xdd\xdcu\xa2{\x16\xc3\xb2\x9a,\x98#H\xf3\xcburz\x05\x03\xc2\xd4\xf8\x0e\xfa\xdb\x1c\x8c'\xe3\xdd\xdfuQ\x9c\xf3W/?\xbe\xfat\xf9\xe3\xfb\xcbw\xef?]~xq~~\xf9\xe9\xdf\xdf\x9c_\xbe\xffx\xf9\x97\xf7?_\xfe\xf9\xcdO?]\xfe\xf0\xea\xf2\xf5\x9b\x8f\xaf~t\x86\xf4\xa9Q\x12\xd3\x897L*\xd1\x17!\xafu\x97\xcd~z\x14\xfc7T\xb7\xd1I\x8f\xd3\x7f\xba17\xa6\xbb\xba&\x14\n\xae\xb2\xf4\xd5\x97\x92\xa4\x94\xf8-0\xca\xf85)\xb5\x12RD\xe1\x9a\xfcH\xc8\xfa\xa78\xfd\xfc!\xc4\xa4\xcb\x84;\xbb\xb5\x8a\x8be\x98$\xd9\xed\xab\xbfVa\xf2\x1f\xe4\xae\xe0i\x05\xe3d.\x82\xbe\xb0jY^\xb2\xccz$\xb8*3^H\xf28L\xe2\xbf\x91s\x12\xe6\x11ko\x1d\xe6\x85\xfc\xfb\x9a\x94\xe7\xe1j\x9d\x90\xf3hIV\xec;L\xd1\x10\x96\xe4C\x98\x87+\xad\xa4,I\x9e*eo\xe3\xf4'\x91;Z*\x0d\xbf\x18J\xffX\xc5s\xa5\xe0\xc7\xb0$\x9f\xe2\x15Q\n\x99%\x8cR\xf4C\x96%$T;~\x1d'\xeawo\xd2\x92\\#\xad\xd3\x94\xbd\xabVWZ\xd1\xdb8\x8dW\xd5J\x1fn]Fi\xac\x97K\x12}\xe6\xdf\xad\xc8*\x8b\xff\xc6\xba\x8a\x8b7\xabU%\x84~\xa6\xd0>\xe2:_Q\xd6p\xfa\xd4d\xbd\x1e\xd7\xaf\x8fL\xaf3\xfe\xfap\xcf\xf4\xb6\x12\x1f\xef\xee\x9a^\x87\xf5kc\xd7\x05\x7f\xcd9S\xf9\x15\x9d\xdc\xff=\x7f\xff\x8e\xeb\x00\xfa\xec\x19\xec\x9eK\xc2*\x816\xc6\xce\x9b1\xb9-p~\x93\x85\xa4kb\x97\x0d\x11P\x15*+X+\xc6Z\x9d\xf4\xa4\x93\xb2\xa1\xf4:\xedD\xbc\xb8\xeb] \xde\xc8+\x17C\xd6|qy\xe4\x9a2\xfb\xbf\xe7.\xb2]\xaa\xdfj\xdd\xc3\xff\xcf\xde\x9fw\xb7\x8d#\x0f\xa3\xf0\xff\xcf\xa7(\xeb\xc9/C\xb6i\xc5r\x96N\x9c(\x9et\xe2\xa4\xdd\xd9z\xb2\xf42\x8a\xc6\x87\x96 \x8b\x1d\x89TH\xd0\xb62\xf2\xfb\xd9\xdf\x83\x02@\x82$\x00\x82\x8e\xbbg~\xf7^\x9e\xd3\x1d\x8b\x0b\x96B\xa1P{\x85i\x1a\xae;t@E\xb3\xe8\xd8\xaa\xfe\x8d\xbd\xbc\xf70@v4nv4K\x93\xe5O\xef\xdf\xa6S\x92\x125\xef7PO\xab|g\xabr\xe1\x11c*S(VN\xb1\x84,\xe5\x92\xf4\xd9\xbe\xb4}Z\xc0\x8b\x94\x19x\xa3\x8c\xcf\x04oM\x8a\xa6\xde\x93/\x1e\xf1\xfb\xcbp\xe5Q\xccd\x1fe\x14g[\xbe\"\xa6\xf5:\\\x95oB#\xc6 +;D\xf1\xf4C\xe2$\xa2\x80b\x16\xab\x1b\xb8\xa0jV\x0d\x159\xdb\xef\xcf\xa2\x05%J<\xa3\xb1 \x91hA\xefD\xa3\x8d\xf9\xf3\xd9i\x7f\x18N\xe6e\xeb\xc6\x1c\x01\xd2*0J\xc7h\x0dM\xc78{O\xe4^\xd7X#\x9a%\xfe\x18\xc8\xe2$]\xe2 \xc2qn\x08\xef\x03\xa4\x13\xcfcW\xa4m\xc9\xe8\\\xf4\x14e\x05\xdd9\x14}\xe4X\xfd\xf8\x9a{\x91\x13qj\xb6\x8a\x9bu\x97\x10A%^\x87+\x17t2\xa2LJ\xa6\xf9D)\xf2g\xcb\xfdP]W\xe2\xb1\x95\xe5\xa6\x9df&\xd8\xcb\xa0\x12\xd1\x08\xca\x90\xdfa\x97\x7f\xd9\xa8\xcfD=\xabr\xbc\x06\xcb\x9cP\xf7Z\x0f\x84\xa8\xed@\x88D\xa5\xa7\xdd\x00\xf2\xf2n\x1c@\xd4 L\xd9:\xa3d\xf9a\x9e\xc7\x9f_G\xd3\xe9\x82\x9c\x87\xa9]\xe4\x07\x9d\xe5\xce\x04\x13\xd2\x9fJ\xf7I\xc1\x85\xe9K*@\x97Fu/7\xf4H\x86\x0f\x8cyKc\x8fz\xe8\xbfE\x9c$\x8b\xe9\xc3\x1e/_\x8f\xff\xa9\xaf\xe2\xbd\xf1h\x05\x07\xb8v\xb7\xe1\x00\xf6`\x1f!|\x0f\x0e\xe0\x8e\xf8\x9b\xdd\xbf\x0d\xfb\xb0}\xeb_^\xe8\x9dd4\x0d't\xb3\x88\xc2l\x13O7\xd2y{\xc3\xf6\xec&\xf3\x96\x9b\x8c\xa4\xd4?\xd8\xe44\xf17'^\x98\x91\x0d9\x8d\xe2M\x92,<\x12\xc6\xfe\xc1&%\xe1\xe7\xcd\x9a\x12\x7f3\xc1\xc7\xec\xc0\xd9\xcc\xc3t\x83\xf2\xedt\xb3\x08\xb3l\xb3Hb\xb2I\x96\xab\xc5&\x893\xbaIb\x1a\xc59\xf17S\xe2\x9d\xe4\xa7\xa7$\xddL\xa2e\xb8\xd8L\x16aJ63\x8f\xed\xf1\x0dI\xfd\x83M\x14Gt\xb3\xf0\xc8iH\xc9\x86P\xe2\x1f\xf8\x9bi\xb2\x99&\xf9\xc9\x82l\x887\x99'\x9bEv\x10\xcd6\x8b\x8cx\xd1\xcc?`\xf3\x88\xb3<%\x9b8_n\xceHL7\x17\xde\x84\xac\xe8\x86L6+\x0fS4o\x92\x94\xfa\x1bJ\xbcx\x9amPs\xb2Ic\xdf\xf7Y\xd7\x8b\x05\x9d\xa7I~:\xdf\x84\x8b\x8cl\xb0l\xf9b\xcd\x86r\xc1\xa6\x93\x84\xeck\x8f\x84\x939\x9b}D\x18\xd8\x92\xe5&\x8f'\x1e\xdb\xbdl\x80\xa7\x8b\xe4$\\lN\x13\x9alN\xf30\x9dn\"o\xb6Y\xae<\x8e\x03\xd9F\x19D\xecEt3Y\xe4S\xe2\x1d'\xf1\x84\xf8\x07\x9bE\xc4\xa0\x95\xd3\x8d\x14}6\xd4#\xe9,\x9c\x90\x0dI\xe3p\xe1\x1f\xf8\x07\x9b\xcc\xdf,\xbcpy2\x0d7\x84n\x92\xc9\xe7M\x12\x9f\xfa\x9b\xa5\x17M\xd2\x04I\xe0\x06\xf5L\x1b\xaeK\xf07o\xc27\x9b\xd8\x0b\x97$[\xb1\x96B\x1a\x9d\x91\x0d\xb9\xa0\x1br\xbe\x89\x16\x9b\x84n\xf2\xc5\xc2\xdf$\x1e\xb2E\x9b\x15\x8f\xaf\xdc\xa4\x9b\x9cn\xceH\x9aFS\xe2oV^8\xf9\x1c\x9e\x92M\x98\x86\xcbl\x93Fgl]\xd2\x84\x92 %\x0c\x104\x99$\x8bM~\xb2\x88&\xfe&\xf5\xc2\x88a\x8c\x17N\x93x\xb1f\x0b7\xdb\x9cF\x19%\xe9fEB\xba\xf9\x92Gi9\xefl\x92\x93\x0d\xd7\xb3mh\xba\xde0\xaa\xe8\xfb\x9b\xcc;Y\xb3\xc5\x0f\x17d\xba!\x8b\xd9f\x9e\xa4t\x13\x9d\xc6d\xba\x89\xbe\"xB\x1aM6\xa8\xd3\xd9\xa0\xa9a\x93\x9fp\x97\x84M\xbe\"\xe9f\x1dO\xe6i\x12G_\xc9t\x83\xb1\xc4>\x83\xe8r\xb5`\x83\x9f\x93x3\x8f\xb2\xcd\xf7|L\xd1\xce\x06\x87\x11^\xf3z\x8a\xf6\xcc)E\xfb\x14\xab\xfc\xa2AB\xefGR\xbc\xdc\xf4\x86\x99\x06Pw\x06\xae_X\x8b\x8c1\xa6\xd6\xb7N\xf1\xadA\xcb[K\xc6\xd3z\xa7\x01\xc4\"\x83\xc9\x00K\xede\x84za\x00k[\x81\xe2&*H\xa1c\xc9\x84\x8e\\: .1\x19\n\x0fq[\xea\xb9A\x0d\xb1hMU\xdb(\x9a([0\x11\xa7\xc2\x9b\x8d{\x87\x95\x84\xbe$U\xa3\x81\x86\xb8H%\\\xa3\x08J\x80\xf6\xb5l\x12.\x9e\x86\x19\x1b\xd6\x93\xea\x9d\xe7b\x90\xad\xa0\x91\xeaG\x8f\xf6Sn\xe8\xf7n}\xea\x8f\xfe\xd5\xbf5\xfe\xee\xc6-&J4K\x7f\x92~\x16\xc6\x11\x8d\xbe\x92\x8f\xe9\xa2\xb5\x87H\xad_\xabz\xdb0a\xadW\x8b7\xd2\xc9\xd6\x8abp\xa6\xf6\xeck\x8f\xe0SB\x9fL\x18\x97\xcf\xb0%M\x16\x8b(>}G\xb2U\x12g\xed\xd0\xa8\x9dd\xa5\xc2\xbf\x1fe\x8a\xf6_Q\x87\xb0\xa51i\x0c\xaa\xc7\x9e\xfe\xcdR\xbf4\x8b\xe2\xa9\xd7\xaa\xac\x91Wq\xc2e4Li\xf6kD\xe7^o\xafW\xe8#U\x15*\x83\x89\xd7\x9b\xf0\xdd\xc3\xad\xf6\xff\xbe\xf4K,lz\xfe\x01\x98+X\x15\xaa\x1d\xaf'\xba\xe8\x89\xc4\x9b\x1a;\x89\xa1\x8d\x14\x9d\xe64\xe3\xd27\xe2\x17\xca7a\xea*\xb3\xa4\xc5\"O\xa2Y+\xc7\x9aM\x9bx2%d\xb5X\xbf\xa7i\xb4zI\xd65~\xcd\x927\xecZX\xaab\x99[\x94\x81:\xa7L=\xb6ut\xbb\xafZ51\x99N]K\xb7\xd9\xa8\xe4\x8f\xf1q\xb1\xcd\xd4&5\xef5e\xf8\xbf\x19\xb05d\xb1\x86\xa3\x91\xc6\xe4dVh\xe3\x98b\xee\xa1\x17a=D\xd4*\x8a\xc8mv\x87 5<\xa1\x0c\x15o\xe8\xd3V_\x9aU\x90\x91\x86\xec!\x15s\xb1\xa3F\x86\xa2\xdd\xa6\x94\xe2\x80^)\x0c\xb9A-\xeb\xcdp\xddp\xa6\x18\xad\x16\xb4m\xc1)\xb7Z\x94\xd5\x8dMn\xf5P%\xbeU7_n\xdf\xd3T\x94+\x98\x9d6\x83d\x91o\xb1\xd9\x84iM\x18L\xc4g\x1a\xd2\x1f\xa3\x03\xc6\x87\xa4p\xeapX#\xfe\x8da\x8d\x94\xde\x8chR3\xfdU\xdfc\x9bb\"\xfd \xee5\xfc\xfa\xa1\xc8\xbaq\xfbN=<\x05D\xee\x0d\xf4\xb0\xb83\xd0}\xba\x92-\x7f\xbf\xab{\xaa\x0f\x89\xaf\x16_e\x0f\xcf*\x07\x89\n-\xa3\x05\x19\xb3\x16\xf4\xa3\x18\xf5\xe3\x99\x17\x97\x0c\xb8N\xb7\x02\xaa'\x809:\xd7m\xa3\xc1\x01(\"A\x84A\x13\x11\x16Z5\xf2\\.hm\x8d\x95t\xf1<\xc0C\x9c\xe2\xa7Q\x93\x18p\xfe\xad\x9f%K\xd5s\xa2\x8d\xddd\xbd\xac\x95a\x8eb\xc6[\x8db\x8d\xdd\xeb\xb2\xbe%\x9a'\xdf[\x83\xdfc\xeb\xfe\x80\"\x10\xf01\x94\x02T\xef\x97p\x91\x13\x1e\xe8uB`A\xb2\x0c\xe8<\x8cA\xb4\xdck\x8e\xb1\xb9;\xfe0\xf8gv\x18\xd3#\xf3\x98NQ\xe5\x9e\x8aa\xf1\xc6\x9d\x86\xf5Y\xefI\xda~Z\xa0\xa4y\xeb_;\x07\x9f\xa6\xdb\xde\xa7>\xfb\xc7?\x90\xb6\x01EN\xad\x0d4\x04\xc1\xf8\xb8\x0c\xee\xc8\xe0\xfa\xdamt\x0e\x83\x8a!\xe2\x8d;\x0d\xeb\xb5\xceE\xd7mLx*\xd5\xf2+\xd4\xbc\n\xcd\x90\x9bE\x0b\xe24\xc0\x0f\x06\xbfb\xb71\xf6h\x9a\x13N\x1aD\xccR\xb8\xc8\xd4\x1b[\xbb\xca\xdf\x03\xc9\xca\x9bF}\xc2\xbbw\x1a\xf8S\xbd\x8f\xb4\xdb\xb8\xf9`5\n\x1f\xf3\xd8\xc4\xcb.C\xfb\xd9\xe4\xd3\xed68^\xb1\x9f}V\xb8\x0b[VZ6\xef4\xb2w:\xf7s\xb7QIqO\n\x1b}\x9a\xbcJ\xceI\xfa4\xcc\x88\xe7\x07\xb0u\xeb_\xa3\x7f{\xe3\x83\xd1\xee\xce\x83pg6\xfe\xf7\xfd\xcb\x9d\xe2\xef;\x0e\x7f\x0f\xf6.G\xfe\xe5\xd8\x890\xb0\x91;M\xf8\x8d\xd1\x0b\xdf\x9d\x98\x96\xbc\x89\x1b\x9d\xe7]8\x0d\xef\x951t\xa0\xfb\xf0:\x90\xfc\x0e#|f\x08xp\x1e\xdf\x16O\xebpzx\x81\x1e\xc9\xb6\xa5\x9d%\x8bEr\x0e+\xd1I\x0f\xb6u.\xec\xd53\xbc\x19\x9e\xd1:\xb2\xabr\xb67oV~\x9b\xb9Z\x13\xc7\x8b\xac\x1eR\x9e\x93d\xba\x16je\xae`\x8c\xe2\x1ew\x93\xc7_h\xc8:\xbeX.z\xc7\xd0\xf9LyS\xb0\x1e\x867\x17\xe5\x9b<\xc9\x85\xfe\xb5U\xf9\xda,I\x97!5\xbd8\xaf\x8cQ\xec\x00\xc3\xbb\xd3\xca(\xed\xef\x9e\x95\xef\n\xc4\xad\xa7\x1e\x01\x01G\xeet\x950\xa67\xb2f\xe6\\3\x91\xbdT\xcc\x0d\x01\xbf\x8c\xf4\xfd\x83Pe\xf4B\x99\xe0[\xbc_\x15\x9ay\x82\x97H\x16\xd306u\xackJot\x94MN\x92<\xa6&-:\xbbN0\x9c\x8fq$\xcal\xccl\x8d\xb9!\xd4eH&\xa1l\xcb\x8bx\xa6\".\x96X\x06r\xc1\xbe/\xb5i\x95\xcfw[\xbf\xc6\x94\xf1\x92\xf9\xeb\xfe\xf9\xa1\xc1\xc8\x0e\xd2\x00\xd7\xd0B,\xcc\x9e|V\xed\xaa\x9bdvhp\x08\x90\x17O\xef\xad\xd7\x11G6u\xac\xbc\x94\x80\xa7\xc8\x0fD\x7f\xc6/\xda\xed\xcf\xf2\x92\xb4\x88\x1b\xb8{H\xf7 ;\xde\xf88y\\bq\xf6\xe1\xf1\x80c\xe9\xf9\x81\xa1\xfc8h\xf5\xb9 \xb6\xe3\x13F\xd2\xd7\x01\x9c\x16\xb5#0\xb5\xfd\xfb\x00\x0e\xc75\xe1\xd5:\xf6R\xdf\xa4}E\xa7\xe6\x07\xb1\xd4 \xf2\xcfe\xf9 9\xf7w\x82\xd6\xc3,\"\x8b)D\x19\xe6\x0fY\xa5\xc9Y4\xc5\x13@G\xb1e\xa3g\xb6\xc1\xb2\x89\x7f\x85!<\xf3\xa2\x00\xce,N _\xd1\xc4\xc1\xc7\xf3\xd5\xd5\xd9\x00\xc4\x10\xe6\xe5\xd6\x99\xb7\x8d\xe69\x0c\xe1\x0d\x1b\xcd\xdc2\x9a\xe7\xcah\x9ew\x1d\xcd\xb4m\x08\x1fa\x08\xaf\xd8\x10\xea\xa5E\xd4\xeb\xa32\x84\x8f]\x87\x10\x96\x00 \xdbF\xf3\x03\x0c\xe1-\x1bMh\x19\xcd\x0f\xcah~\xe8:\x9aY9\x9aY\xdbh\xbe\xc0\x10\xfe`\xa3\x99YF\xf3E\x19\xcd\x97\xae\xa3\xa9\x1e\x89m\xe3\xf9\xdd\xe2\xb7$/\xe4n\xbc\xdfQC\x1eR\xb2C\x99\x1c\x85\xcd\xaf\xe0\x00~\xf6P\x85\xd6\xcb\x99\xb0Q\xdc}\xc7\xef>\xe5D\xd4\xcc\x17\xc9K\xcc\xf6w\x93\x1bKIf\xab\x07[\xdb\xfc~\x85!|\xf0\"\x0b\xb0qv\xbfv\x18\xe3\xaf\xedc\xac\x1c\x9emC\xfc\x05\x86\xf0\xb9}\x88\xbft\x18\xe2/\xedC\xac\x9e\xd0mc| C8j\x1f\xe3\xcb\x0ec|\xd9>F\x95\xc1j\x1b\xe1\x8b\x96\xa1\x1d#\xf3S\xb0a.\x03}!y\xd6\xa3\xd8\x1b\xf5\"J\x96Y/\x00\xceg\x8f\xfd\x00\xa2\xa6\xa1\xbb\xcd\xd7\x03\x14\xc1\xaam\xdb\xb1\xab\x82I/\xd0I\x82!\x0b\x06\xabV\x97P><\x12\x0fU*\xf0\x02\x190\xf6\xf4)\x13*\x03ap\xe7\xeb`\x1f,\xbb\xa2xJ.\xf6\xa1\xc5g\x90]$M\x93t_\x13/\xa7^\x97\x96x\xb0v\x9cP\x18\xe46\x94\xb8\x01Cx\xdd\x8e\xb47\\pA\x00\xeb\x86+56\xda\xbd5\xfe+\xcdl\nvNI:\x1a}\xbb\xbb\xb1\xc6\xd2 \xc2/\xa8\xab\xd8\xdf0h\xe9\"\xa0\x19\xbco],\x17BwE\x8c\xf2]\xc4\xbd\xae.\x96\x0b\xdc\xb6\xf8\x17\x166\xb2\xad9\xd7\xf3\xb0o\x98\x94/\xbe\xfd\xf7e\xc0\xbe\xbfq#%3\xd5\x1d`\xbdBO\x18\xda\xc7}\xcd\xff\x14%WD\xb9'\xda\x0f\xa7S\xf4M\x0c\x17?\x97O\x0e\xe0o\x8f\x0eX\xe3g$\xcd\xa2$\x1e\xf6\x06\xfd\xdd\x1e\x90x\x92L\xa3\xf8t\xd8\xfb\xf8\xe1\xf9\xce\xfd\xde\xc1\xe3O\xb1pl\x87\xdf^\xbf\x02r\x81K\x0c\x13\x9e\xe2\xf7\x84\xc0)\x89I\x1aR2\x05\x1e\xa4\xf47\xa3\xff\x93\xbc\xa4!LL\xa7\x8f\xa9\xb1\xbd[\x9f\xde\x7f\xf7\xe9\x96\xf7\xe9\xfd\xb6\x7f\xe3\x96\x05\xd9K \xc2\x10\xa2\xd1\xa0\x19\x8c\x08F\xc6B1\x16\x9eJK\xed\xf4)\xea\xcb~{\xfd\xea\x90\xcf\x8d;\x93\xb8\xf8\x80\xb0\x89$\xc2\xc3\xa8l\x8fo\x82\xe7i\xb2\xe4\x1bA\xb4\xd7\x9c\x91T\x8a\x99$\xbb\xa4M\xb2K\xb0\xbcm\xcd\x13&)=a`_\xc9y\x06Pxi\xaaYP\xac\x8e_g\xa2\x0eI=\xa9\x92\xbc\xd8\x12\x94\xe2\xfc\"\x99\x84\xac\xa9~\x86\x8d\x1b\xf4K\xa5\xde\xd2\xb4\xb5z\xa8\xa47\xee\x11y\xf0\x90~\x96\x9fd4\xf5\x06\xbe\xac\x17tS\xa7\x8d\x01\xd5C=\x85(\x86\xd8\x87\xb8^>%\xe5\x8e\x8a\x18g8J\xc7\xb2\xc5!&[\x1bM\xc9$\x99\x92\x8f\xef\x8e\x8a,]^:\xda\x1d\xfbc,\xdd;@u\xa1\xf6\x9d\xc1\x98\xdbU{.\xf8$\xb7us\xcd\x9a\xd9l\xec\xb4\xd5h\x15_\x86+\x07\x7f6\xf19\x12\x83\xea\x8c\x88\x0f\xdb\xd0\x1b\xa2\xb6\xb6\xf9\xb4\x9a\x99T^\x97~\xff\x8f$\x8aqy\x9aS\x13\x19{\xec\x83\x92\xf3\xa9d\xdd\xa0\"n\x17K\xd5yD1W\x04\xd0\xcb\xe9l\xe7~\xcf\xf7\xcb\xbb\xbd\x930#\xf7\xee\xe8\xc6Pf\x10jv\x9d`\xb8Y\x94\xc4\xd9{|\xcb\xe4\xb5\x13.V\xf3\xb0%\x97\xacz\x154\\j\x13\xe7=\x1f\xb7\xd0\x02S\xc1\x85)\xf1\x88\xfa\xccpd\xeb7\xe6\x92\xd0y2\xbd\xf2h\xf8\xe7\xa6\xf1\xc8\xa7\xceLDs\x8c4<\xfd\xb3\xc0Y\x1b\xb2\xf3 5\x98Y\xcb4\xe5\xc6\xce\xe8\x9cT\x94\x8c\xeeQ\x0cF\xbd\x91\xf4\xe6\xa5F\x0f\x11\x85m\xe1\xa5oz\xe5\xdf\xa2\xcc\xd1(\x0e\xd8\x06\x0dt\xfb3\xf5K\x9f\xfa\xff\xd9\xdb\xbdu\x1a@o\xbb\xe7\x8f\xc5\xfe\xd4-\xa9\x91J\x11\xdb\xa6\xd6d\xee\xaa\xac\xa4\xc1\xb1\xa6P\x9a1\xc25- W\xac8\xe5\xb4\xb9\x8ct\xf2\x18\xa9\x8e\xbc\ns\xa9\x143\xa4's\"\xc0:\x8f[d\xcaT:&\xcc\xd9\x98\xd4(\x8d\x96\x9e\xb2H\x9f2\\\xa3c\xb4\xd8\xf4z\xb6\xe1\x1a\x92\xab9\x0d\x93\xc1\xec\xb8\x84\xd9\xd7\xa6{Y\xa0I\xe7\xe6\xd44m\xe6\x9b\xb0\xecd\xf1\xd1\xad\x7f]\xec\x14\xccu\xeb\xb2\x05\xc6\x14t\x7f\xe6\x08\x85\xfdgS\xd8\x976\x85\xf5h#\xecb\x1ba\xf5r\x9f\xca\xff)\x1f\xf0\x94\xdfl\xa7x\xf7\xee\xfb\xfd\x1f\xf2\xd9\x8c\x08\x7fq[\xf5\xa3\xb3\"sSq\xf2\x95x\xa2\xa6\x19\xacX\x8c\xc0%S|o\xc49U\xfe\xe9\x18\x91:nT\x8cr\xca\x06\x89\x94\xae\x1cWjcD\xf59\x0eAaO\xf9T\x94d\xbc\x8bhBL^\x97\xc4\xb8\xbc<\xa4\xaa\x9aL[\xe4K\xe4\x14@-1\xe1c)+S.\xd9zZr\xfdP\xecx\x99\x97\xbe\xaf/\x9b%\xb9\xf4-\xa6\xd6\x16\xc3\xb2\xc5\x17\xae-F\xd6\x16\xb3\xb2\xc5\x1b\xae-&\xed\xb3\xbey\x13\xb6&e\xd3?\xba6\xadI-\xaf4\xbd\xe5mQ.\x87\x8f\x16c\xb7\x06C\xd7\x06\xeb\x898L\x0df\xae\x0d\xce\x1d\x1b\x9c\xb4\xaf\xf8f\x83\xdd:57s\x1d\xdf\xb41>\xf5\x17\xf1R^\x83\x85x\x91\xfc#\xe1\x7f\xc4\x8a3+\xcf\xd5\xcd\xee\xbc$kL\xcf\x17\x8a\x17\xe2)\xb9\xc0\x1b\x19\xbf\xf1$\xcb\x92I\x84\x99!\x00s\xb8\xc4e\x00\x1c`x~\xdc\x97m\xb0\xae\xfbe\x0bl\x00\xfd\xf7\x04k84\xe9\x07\xa6\x19\xf8\xfb\xdf\x8f\x8f\x8f^\xbf\xfe\xf8\xe1\xc9\x0f\xaf\x0e\x8f\x8f>\x1c\xbe\xc3?\x8e\xff\xfew\x8dji\xd5\xfc\xe2\xe5\xe1\xef\x87\xcf\x0c\xaf\xcf5\x1d\xbcyv\xf8\x9b\xf1\x83i\xf3\x83\xb7\xef\x9e\x1d\xbe3~p\x06C\xb8\xdb\xbc\xbd\x86!\x0c\xe0\xd1#]\xb5\xf3S\x18\xc2\x1av@\x93\xaa\x7fi\x90\xf7\x8f\xed5\xae\xf7\xeb\x89$A\xcf\xf9\x9f\\\xa5\x19\x13-?o9\xd8\xb9q\x18\x0b\xbb;\x92\xe4\x0b}\x8bT\x1c\x0dE\x83\xbbn\xdb\xe9=O*\xaf\x7fxh9\x89D\x84\x9bF\xaf^\xa9\x0e%\x0bH{\x98x\\\xa88w\xb0JH*r\x9e\xcb\x94\x05<\xd3\xc6\xeeCLw\x11?\x84h{\xdb\x87t\x14\xf1$\x89\x11\x13\xe8\xcd\xee\xf5\xa9\xd3l\xed\x01\x0d\xaa;:\x06\xa2\n\x98f<\\\x82\xf6\x8f\x8fy\xe9|\xe2\xfd\xc1OW\xf6\xc4\xa9\xe3\xb7\xd6Tb\x85\xf5A)\xe9a\x13\xc1P\xb9\x04\x8f\x1f?6\x995\x84\x92j\x1bb\x11C\xbd\xd9\xc0\x9d\xbd\x07w\x1e\xdc\xfb~\xef\xc1]\x9ca\x19\x99\xf8&|\xa3o\x85MZ\x93\x92\xcf\x04>\"\xcax#\x90\xb7Q\xf1\xe1\x06\x9c?l\xc5\xf2\xeb\xf9\x9c\x0dm|v\x90\xda<\x19jP\x16\x9d\xde\x92Q\x91\x14\x1e\x0da'\xae\x14,\x1cJ\xd0\xd5_&\xf0xXW\xc0\x9a\x06v\xd4\x96\xbd\xf1\x83\x18\xb9\xe3\x86}\xed\xda^\xbd\xaa\x8f\xa1\xbd\x0f\x0e\x80\xab\xc5i\xc4\x986\x97/\xb6\xba\xbf l\x03\x1a\xc5j\xb1\xb4\x8cC\x92\xe5\xe2\x99\xbc`\xac\xde\n\x02\xbf\x9f6\xabT\x83pd\xd6\x9c\x07\xef`\x08{\xcd\xdbo\x9c\xb3\xb6\xf3M\x9d\xa4\xcd6^\xf1\x93N\xbe\xa09\xda\x9e\xc1\x10\xde0\x1cye:\x02\xbe\x1a\x08\xf6<\xca0\xbb\x8833\xfe\\\xae\x94!\x99\xa7\xb4Z\x94\x0b\xc5\xb6\xe0\xa0\xb2l#\xf6\xbd\x85\x8a\xc2\x01\xa4\xc5\x19\x12\x89\xb2\xc0\xd6\xd3\xd0\xe0\x078Mb\xd3\x89\xebH\xab?\xda\xa8\x82uH\x1c\xfd\xac\xe3j\xad\xdcc\x18\xd4\x0fv\xees\xebWW6\xf6\x8b\x9d1\x00S\xd5h\x8a8\xe3\xd4\xc5\xefv5\xe0\xaf\xda\xf4\x1d\x05-\xe7Un\xb5\xc5\x96\xf5\xdd\xfdj\xef\x8e3(o\x90\xd6\x8e\xde`\xedR:ze\xcaM\xa4\x9d\xbb\x92\xb7\xdaiD\xbf8\xc0X\x13\xcc,\xb8\x14\xa7.^Z\xbb(\x92\x01\xa8G\x8e\xdc\x8e \xcf\x95-\x85\xe8>M0]\x83\xb5\x80\xb5\xbc$P\xd1y\xbd\x12\x167\xac\xd5\xe6!\xe7@\xa85\xc3\xfb\x96\xa9^\xd8\xe1\xc5\n3\xd3q\x06\x0d\x92\x14\")\x15 5K2\xe3[.\x0b\xd8\xd3\xcf(\xdd\xf0G\xfb\xe8.o\xeaV\xbb\x8a\xecj\xa6\x083\xc0\xfd\xc5\xb7\xc1\xbdO\x13\x94\xc5$\xc4\xc5\"\x84\xcd\xb5\xa0\x98\x9f\xfd0\xa6\xe9\xbax\x99\xba\x8e\xf2\xc6\xb7\x8dR30\xa2\x0e\x84\x8dSH\x91\xf2V\xe8<\xb6\x1f\xadc\xf3\xbe}pr4h\xe0\"\x14\xef\xd7F\xa6\xfe\xfa\xaa\xa8\xaa\xa8&\x1f\x81e\xb0\xbd\xd1\x918\xa0\xc75\x05t\x00_\xfb/\x0f\x7f\x7f\x0fCx\xca\xfe\xfe\xe5\xc9\xab\x8f\x87\xec\xd7\xcf\xec\xd7\xe1\x9b\x0f\xef\x8e\xf0\xe7\xbb\xa0\xd2\x7f\x14g+\x9e\xed\xbc6\xaa$O\xab\x99\xb9m\xf4\x85\x1d\xf0\xe6\xdc\x0bJ\xcb\xa3g\xe3\x0em\xd6\x1b\"\xdeK\xae\xb7x\xd9Of\x8e\xed\xbc\xf4\n'\x92\xc6\xc0^V\xa7L\xbe8\xb6\xa9\x1b\xdb\xcb\xab/*\x82\xef\xf8\xb84\x8e\xb2\x91\xfc\xbb\x17@\xef\xb2i\xcfQ\xfb\x99\x84\x939yG\xb2\x962\xc7JW[\xbc/\xfc\x10d\xc5\xafB\xd6\xfb\x18\xe3\x83)\x17\x06\x957\x87\xfc\xc5\x12\xeb\xcb\x8a\x0f\xa2\xfc\x99\x14\x1c\xcb\x8f\xc4\xd9\"^\xb0M\xa3\xe8\xdf%\x86HLdB\xcb\x82d\xbc\x02\xa8K\x0f\x89S\x00\xbe\xe8b\xd6\xda\x05\xf1^\x04\xf0\xd2\x0f\xe0Ee\xf1%\xbdu\\\x13=\xa6\xdf\xe0-\xdfp\xc7\xf4\x1b\x16L\xbfQ\x19`II\x1d\x9b\xd6\x0d\xf1\xc65#\xfc\x88!\xfc\xb8\x89\xf07\xae\x19S\xea\xb5\xdd\xf5=|\x13\xa64\xbb \xde\x8f|=\x7ft_\xcf\x1f-\xeb\xf9c\x8dr\xd1o[\xcb\x97\xfd(\xe3-D\x94\xfd\x92\xda[\x86\xdeB]\xcb\xc6\xaf(ro4\xb5\xb7?\x05\xf0\xcf\x00~\x0b\xe0\x1fM\xa5\xe9\xfb\xc3\x7f\xa0\xc2\xd4$9Rj\x11\x1d\x8fCQ+\x83\xd6\x88M\x17\xf6\x95\x18z\x90\xfc\xa50.}&\xebL\xcbC\xf2\x91$\xb26\x88\x1c\xca\xf1gQ\x0b\xab:4\xd2eh\xb1u\xf2Q\xa9\x9f7\xcc\x9f{\x16:+\xe8\xd2\xf6\xee\x84\xe1,\xa8\xdd{*\x0e\x83zm\x1fCG\x91\xa1#y\x16\x95\x06\x8c\x7f8\x1aX\x90\x1b36\xf8\x13k\xcd\xfbI\xe8Z)\xf5F\xe3Ff\x16}\xbby\x0brh\xd2\xe0\x88.\xa8\xdf\xe4\x9a\xbf\x94o\xa4\xfa7~(\xdf\x88\xf5oh\xa5\x9c\x83R\xc8)TOf\xcf\xbe\xabK:\xa3\xcf\x01\x9c\x8dAd\x8a\xed \xf1t\x92Y\xc3\x16\xa0gza\xee\xdb\xa7\xc7\x05\xb9k\x9aEfG\xf2_j\xd8\xa2A\x0f\x0d>\x14\xab\xeb4\x04v\xc29\xa9\xcb\xa8`\xcd\xf4@\x8dL\"xa\xe5H\xd8\x01QZ6\x06\x01\x864\xef>\x84\x1c\x1e\x0d!y\x08\xf9\xf6\xb6\xa9\x11\x10\xe3\x08\xd1S8f\xa2\x15\xec@\xced+\x83\x7f\x15\xc8\xc5\xe6z=\xe2\x85\xa3\xc18@\xc5]8\xda\x1d\xb3/\x03P\x02\xdas\xd8\x86\xa6\x12\x0e\x1a\xe2\x97\xbc\xe4g\x8d\x87\x96\x04s\x0dV\x99g\x83tZ\xa6\xd9\x9f\xbcL\xda\x152B\x96\xaf\x9c\x0d0\x0c\x1b\xbfzV\x96B^\xd2\xf9\xc3}a%\xf0\xb7\xb7\xe11:W\x9b\x1b\x077u\xa7\xbc\x8cjOy]\xc2>\xc7\xcc\xb9P\x1f\xa9i8s\xfbp\xa4E\xbe\xe2w5\x94r}\x8e\xf4z\xa8\xe9\x93j\xbe,\x03\xb8\x05\xbb\x85?\x8b\xf0{\xf1\x03\x89\xce\xf2C\xdb\xc1\xf6\xcfbh\xff\xd4#\xce?\x85\xcd\xa0e\xab\x99\xa0u\xda\x02-\xaa\xaa \xb8\x8a\xc0\xd1WhIm\xceB\xfa\xa5X\xd6\x96BiC\xbf\x1a\xa7\xd4\x13\xaeV\x01\xf4\x9e\xf2(\xde\x8c\x92\x15\x84\xf0.\x8cO \x9c\xaca\x17\x83\x1eAX'w\x83\xea*\xc9\xba#\xb8V~\xa0$\x01\xe0\x9eo\xa2\x1a#.ax\x92\xa1\xeb!\x81G\x82cco\xef\xc4\xd2\x84s\x8c\xc5\"T\xbd\x1f\x89\xa7\x8aj\xf3\x18\x87\x86\x83U\xb1FE\x0f\xfc{B\xa2\x85\xe7\x11\xd8a\x04\xf8\x16\xc4L\xb4\xf2\x99l\xde\x0dw~+`\xf9\x9b\x1ew~\xfb6\xdc9\xd6\xeb\x129\xbe(*\xa5'\xa2\xfaa\xdd2ah\xf6\x84\xda\xdcL\xcf\xadO/\xc4S\xf5\xa1b\xc6\x1a\xfdc,\n\x01\x11\x8f\xd2\x00n\xb0\x95S\xe3\x1eN\x89SIW\xc9\xb5\xb3U`\xe4\x91\xdb\xb4KM\xfb\xe8\xad4g\xf8c]\x05\xf3J\x9f\x9dL2\x15\x7fY\xa5G\xe1![Q-\x95\x1e\xb2CH\xb9\x8b\xac\x11W\x84\x8a\x88z\xf1\x88Q\xae\x14v\xd0\xa3+\x1a\xa3\xf0\xc7:*wf\xc4P\xd1H\xb5\x1bu\x1d\xb4\x93u\xb3\x0e\xe9&\xaa\x9dBc\xf2\xfa\x89\xea56\xdd\xb45\x05\x10\x1e\xa3\xfa\xc3\xc6\x819i\\\xac\xda\x16\xaei\xa1\\\x02/Wf{\x9b\xad\xcd\xf6\xb6C\x14 CuB\x03x\xc1\xe8\xd6\xd5Q\xbd\xee\xe5\xaaC}\xae\x1f\x1eQ-\xcaW\xfa\x9e\x87\xee\xf1lJ\xd3\xf5(wM}\xa2\xeb\xdcX\xbcS\xbe\xb3JSU \xd8ju\xa7%|\xa7%l\xa7E\x0f!1+q\xcfDY\xbc\x14\x173\x82\x1dH`\x1f\x12\x83\x9e\xaf\xb63\xf31V!\xae\xee\xc6D\xab\xb45\n\xa3\xcd\x14\n\xd7\xb5=\x05\xb8\x8c\xfbS\x01\xa1qw\xa6\xad{8\xb9\x8e=\xdcm\x15$\xe4P\xd3\x1a\xfdu{>g{>w\xdb\xe3\xca\"\x8e\xa6\xe5!\x17\x8bC.\xd6\xee\x8b\xc2[\xc5a\xad\x19*\x96\x121\xaeeEhR\x84\x0c\x03\xf7,\xb1\xe5w\xafj\x96\xb5\xd4\xb02\xe8$\xbex\xb1A\x06-vq\xf4\x10\xb6\xbc\x08O\x05\xb5*#(\xb9\xbc\xbdHT]\x84t{[\xec*]\xfdR1\xe5F\x8e -LK}\xf5\xb5\x025I;C\xd5\xa0\xce\xf9\xa2j\x89\xf9v\xf9hh\xd6\xb0\x02\xdd\xb7\x1aQ\xd6\xa1E\xcb\x81\x8b\xc4\x9d\xd1q\x0f\xe0\xd2\x08\x15\x9e\xd3F\xf0R\x81\xf2\xe9\x7f\x01\xcaW\xea\xc8\x17$\xb0\x08!\xe0\xb6\xaa\xa6\x83\x80z\xa0\x14\xc6\xa8\x87\x0e\xcc[4J\xc6\x01#T\x8dC\xc206\xb6KbEK\xc4w\x89\xb1\xf2\xbc\xa4\x9b\xb1M\x9b\x84&\xb6Q2\xe6\xe1\x90\xc5\xd8\xf2\xea\xc0NR\x12~n.\xa8 \xdb\x1a\xc7\x96vy\xffc\xbb\xaf\xb6\xb0F\x82\xa6[l=\x10\xafc\xef\xe1J\xc0\xe3\xf2XmS\x18\xb6oT\x90p\xe3En\x8b\x8dkQ,\xf2\xa0<\xb1\x87\xb5\xafY\xad\xcb\x92\xfdMG\xee\x0c\xefZ\xd0\x805\xbd\xba\x8b]M\xd0\x86\x03\xe8\xbd#+\x12R\x18\x8d{\xb0_\xfe\xe2^\x10\x8aZh\x1bz\xe5=\xfc\x96\xdd\xa1\xd1\x92d\xd0t:^_\x9d)\xd71\xe1|\x08\x1a\x06\xbc\xd2\x8f\xac\xf4\xe3\xca\x85O\xa9\xaa\xf8jFe\xd5\x9a\xc7\x94\x05.\x13\xa9\xec\x1f\x06*#\xca+1{|\xaa\"U\xd2\xba6\xb2\xd7\xa2\xba\xe4\x0e\x0f\xa6\xab3\n\xf5\x91\xa6\xe4\x8c\xa4Y\x177\xed\x16\xb8N\xc9\xc5\xdb\xd9\xd5\xc1\n\x07\xa81\xdc\x19X\xbbY\x84\x19=\xba\x86\xaeJ\x0cm\xed\xf2\xea\xc2\xd4\xeeC\x88\xe1\x91\xb2\xc4\x10;i\"*\xc3\x8d\xeb'ZlUB\xc4Ns\xe9.\xe5tbU\xbb\x11k\xc9f\xc2#\x88%\xc5)Y\xa0X@\xc27\xd6\xd9\x83\xeb\x12?\x1c(l\x05\x9a\xc2H\xe9\x88\x87\xb4\xaaz\x87\x83&f*S=k\xda\xfb\x19}_\n\xfa\xbe\xbcf\xfa\x8e*cI\xde\xf9\x0f\x85\xbas\xed\xee6\xf4\xfa\xfd~y\x97\xc4S\xd8\x06O\x08\x15\xf3B\xcd{\x00=8YW>'+\xcc{\x84I\xe74'\xc1\xf2zO\x029\xdcR\x17 \xdfU\x87\xd28#\x96W:#$\xe7\xe0Q\xd8Q\xfb\xf6\xe1\x96\xd2\x9fq\x7f`\x80\xf4.7\xc8+d\x82\xdf`k\x84:\xf1\xd9\"\xd1\xd8\x1ejCv>wj\x87J\xd1\xa9r\xb8\xa0K\x01\x9e!\xe5\xd3\x80\xdb\n\xf0\x8c)\xef\xfa\xf0hX\xf8\x96.\xa9\xb7\x1b\xc0\xae/\x8e\xa7\xa5@\xeeSB=\xd5* M\x06\xec>\xd1\xdcG\x905\xcf\xae\xe5U\x0e\x9b\xb3\"\xaa\xb2\xb2B\x0d\x85/\x18\x031.\xc3\x1c\xd4r\x07V\x87\x03\xe1Z\x89N\x96\xece\xeeSa\x19((x\xba\x0b\x1b\x93s\x14\x1e\xa1qY\x8d\xd3\x8b\xe1_C5G\xd1w@\xfd\x87\x0c1\x94\x9b\x0f}\xc0\xd7(\xdcR\xdf\xb5\x12\xdcC\xea9\xa5J\x8f\xea%]\x145b\x99\x9a\xffg\xaax\x99\xeb1\x0d\x94UxEG\xd4\x9e(\xb7\xea\xb1\xf2\x96ao\x00o8\xac\xdf\x89\x9c\x19\x14\xd3\xe1\xc0+\x9e\xe8\x1c\x9f3*\x8e\x8d\xb3\x83\xef*Y\x16`\x9fw\xd6 \xc7\xe7a6\x7f\x9aLU\xc8\xc8[:\xe5bT\xaf\nV~\xe8\x08B3\xe3\xf9\x9a\xd6\\M\x11~G\xdccM\xadPji\xa3\xfe5\x1d=\xa5c\xa7/\xb7>\x1b\xc7\x0d\xa6\xc6\xfb\xa2\xea\xc1\xfa(;\x8c\xf3\xa5\x08\xc0Bw8\xdd\x13\xa7\xb1\x98:k\x07\xaf\xfa\xb5p\x98\x8c\x93)\xf9\xb0^\x11@\xd2\x9e\x9dG\xbc\xfeYq\xbf\xad)vM\xc2\x8c\xc0`\xbf\xf5=Ph\x7f?\x8f\xa3/99zf\x9e\xa3\xbc\xb0\xf9\x07\x1d\x9b\x9f&\x13\x0c\x18>\\\x10\xf6\x0f\x9fl\xedf1\x06k\xd3z\xa56\x88-\xa5\xac\x96\xf6=\xfd\xd7l\xb9\xb6\xb7?\xd0@=\xfan\xc2\x07\xbe\xf7?\xe0\xde\xb7\x84\x88\xbc\xa6>\xc3\xfa\x8c\x18=\x1c\xc1\xc1\xd1\xb5\x8aB\x7f\xc8\xfa\xc8C\xfc\x81.\xcfu\x8f\xc1\xde\x9b$\xde!<\x95q\x19H\x98A\x98\x12,\xfa\x86\xd9\xb5\xc9\x14\xc2\x0c>\x93u\xd67\xd5=\x90\xdd\xb3\x0d%\xa2\x8dy9\x89\xd2#$\x80\xa7\xd4\x14W\"/R\xec\x9b}\xd8\xb2\x04x\xb1k\x92\xc4\xb3\xe84w|\xfb<\x8d\xa8\xdb\x9b\x82O\xd7/>\x80\xb9\xa4\x1e\xa8\xe5\x0d+N\xf5\xddH\x86`\x93\x95H\x12\x85\x83\xd7}\xe0\x1b\x1b\xb2\xab\xdb\xd4K\x95\xb5\xdd{\xee\x87\xab\xd5b-\xd8xCD\xbfz]\x06\x162\xc9\xce\xc0\x16\xc8\xb6\x13\xc1\x8aSzI\xf2\x1ax\xff1F\x08\xd1\x042B!\x84\x98\xed\x83\x12rr\x8c\x90\xc4bOXQ\x9f]T\xce\xc1<\xfb\x0e\xf4\xc4z\xeaw:\xed\xa5\xf2\xb5 k\x8caP2\xdah\xf3\x01\xd4\xa0\xc5\xcb)\xb3&y\xfddT\x93\x96\xa5y\x18\xf7@\xa6}G/\xd2\xb7\x06\xde\xbeP\xc7\x10\xce(\xa9\x16\niiG\x03\x05\xbep{\x00\xdf\xf1T\x85\xfd\xc9\x829\xf3Ld\x15\x16\xd6\x97)\xdc\xbdu\x9d\x11\xfcW6_r\x85\xa7\x92\x01\xeau\xb82\xa6<\xfb\xfa\x8d\x96\xc5\xe34IJ\xcd,\xfb\x81\xa2s\x11K\xc3\xf36\xf9:\x93b\xa5\xeb\xacS\xd7\xffP\x93B\xd9\xe7\x94\x11z\x14wh\x1a'\x92\xaf\xa6!%G\xf8\xf22h?c\xcd\xdc\x92}p)Y&g\xed\x92\xb6f\xd6K{\xc3S\xb2 l\x02\xaeM7f\xed:\xe5e\xd7)\xf3N\xea\x0bbO\x1c\xcdE\xc8F\x89\xcb\x03\xe1\n\xe2K\xe3L1\x81\x11\x1d\x8bF\x1d\xc6\xd2D\x0f\xc3h0\xd8\x15\x9d\"E,&Gq\x8b\x8flA\xa2]\x12I\x9c\x898P.\x80-\xcd:\xd1\xbc\xd5\x17\x8f\x91\xbb\\\xf8\xe1\x99\x89\xe2\x99H\x19\x93`\xf0Hk\xc5\xd8\x0c\x86\x10y\xb6\xb2\xdcb\xb92\xbe\\\xc2Y\xb7\x19C\x06F\xa9\xe3\x94z \x03\xb2\xc8\x1b\x9c\x11\x1a@/\x8ay\xb5\xfb\xcfd\xfd3V\x883Cf\x82%\x80-\x1e\xa8\xec\xa5\x99\x98\xf2\x92M\x19\xa9\xd5\x84\xed'\xf3\x07X\xa0\xd4\x9b\x95\x0bhU\x94r\xd6e&f\xcf\x7f-\xd9/\xb1\xdb\xbd \xc3W/)y\x19\xe2\xe3\xd91 `\xa1\xe1\x01\xc4\x9e\x8fc\xd4\xe9\x1a\"\x1eE\xdfi\xd1\x9b\xe0\x9a\xea\x96\xd9\xfa\x0e\x98,Hh-J\xa44\xdet\x8b\xa1\xdc\x1fB\x1c8\xc9yL\xd2\xa3gp BaE\x0c\xe3n\xa0\x9e\x14CQ\xb4S|\x83\xc1\xfb\xc3\xf2\xac\xe0w\xc3\x05\x15\xf5N\xb6\xc4M_pw\xd6\xc9,Iz\xda\xaat\x90\x90\"\x02\xae\xb2ks>\xc0f\x1f\xbfF\xd5\x92c\xb6\xf3\xa4\xe8\x08\xfd\x97\xea|\xd2\xa0\xe9\xc8\xd1\xec\xaeJ\xa0\xec\x86pM\x0fFl\xa9\xd2L\x12 \x84\x03\x07\xad\xaf\xf8\xde \xf0\xf3e8\x90\x7fI\x1d\x0d\x12\xd5}\x88Gj4^\xb3\xa8m\xcb\xf1\x81M>#\x18,\xdbi\x9d#\xd2m\x8dY\x1fN\xeb|%\xd0\x17\xc3J\x88\x87b\x85\xe3\x88\xfe7\xa2\x02\xae\xd6\x81\xfa\xebzQ\"KR\xea\xca\xe7\x1c\x11\xef\x17R\x98\xfd\xdb\xdb\xfda\xdd\x81uT\x1b'\xed\xedWd\xa0\xd6 \x14\xb2\x16[\xa90{\xcdu\x11:\x06@.)\"\x16\xe9\x9f\x87\xd9\x13NO=\x1f\x8f\xa1\xe3c\x12gyJ\xde2z\xedU\x89\xb7d\xa5\xac\x03/zw\xdc\x83\x8d\xf3\xa1zn\xa8\xa3a\xa2\xd8{;\xd8\xc2\xecHjb\xba\xf5\xaf\xf6\xd3\xb22\x05\xc8\xba\xf5 \xce-k\xdb\xdd\x1c\x9c\xa4F\x84\x9c\xc3\x0dw\x99\xa7\x93\x17\xda\xb7:1+\x87{\xe1m\x83r`3\xb3H\x0b\x11\xe1\xc1v\x1e\xc1\x043\x043\xca\xe8l\xee\x01/\xfb\xd4\x02\x01e\xb5[\xf7\x96\x9cI\xc9\xe0\xe8\xb0\x15\x0e\xe0\x9f\xb4dmT\xb6&(\xf3: K\x83\x1c^\xad!%\xf7\x83\xca\xe0\x0c\x04\x83\xa3\x99N\x941\xc9}\x08\xcf5\x9eC\x1fi\x00?\xd0f2\xe0\xd7O~6TO\xfb\xc2\xdeV\x81dR\x0f\xfenN\xfc\x81\xc3oNH$*j\x18\x1f\x8c5>\xac @\x0c\x9d\x9cDt\x89\xe0\x90\x90\x8f\x13\xee\x82\x1c;\xf5\xf9\xcbU\xfa\x9c$yL\xaf\xdc\xe5\xcb\xabt\xf9\x99\xac\x7f\xe4L1i@\xd7\xad\xdb\x17\xd7\xd7\xed\xda\xb9\xd3\x1b\xed\x9d\x1eS^j\xb4\xdc9E\x84M\\\xfa6\x87\x93\xcf\xc8\xbc\x14\x14\xe5'\xea\x89_n\xda\xd0\x1f[S<\xf2\nH\xa6}\xac\x0b\x025!\x0f\xad\xa9,$fGAA}\x10u\xa9FM\xd1\xd4Q\xf8X\xe4\x0c9\x84\x08w\x9bN_a\xc0G\x11%^\xe8\x97\xf8\x82\x06\x10Zy\x15&Qq\x89\xcd\xd3~\xba\xcf\x10Q\xac'e\xfc\xc8\x85\x17\xfa\x01\\x\x0cU\x18\xc4_\xc8\x1c\xae#\xf6\x99k:wB\xec;\xbeVy6\xf74\x9eEF\xf2\x92K\xa0En@\x8e\xac@.v=zm\x95j\x95\x9b7\x01\xb3\xb0V\xd4+<'c\x91\xd8\x97o\x7f7\xce<\xb1\xef\xeeR\x9433\x15\x002\\\x0cu\xf8Ue\x1a\x8e\xb7\x92\x8c\xba\xf2\x9c\xab\x84\xcc\x9ax<\xb9\x8a\xce\xadjx\x9e\x8d2\xf2\x85\x1e>jY9\x13@r\x97e\xe1\xdb\x1c-Cq\x7f\x16\xb1\x93\xc1\x01\xfd\x8a\x8f\xcb\xc4\xb9\xcdA\xfa\xbeb\xedb\x07\xb2\x9af\x17\xe9jy\x8am\x18\xa9\xc0\x94\x87\xca7W7\xb5\xa7\"\x1a\xaa\xf8\xc4\xb6\xe2\x80&pq\x1e\xa5U\xabi\xab\xf7pE\xfe^\x8a\x1a\xa3\x08x\xec\xd2\xf8\xad\xc6e\x02o\xabA0\xa6\xa5\x93\x17\x95n\x19\x86\xf4\xb1\x97\xd5z\xd2\x05A\xc3\xb2\xd2\xf1(\x1a\x17\x0e!\x9a\x81bf\xf2\xca\xd1\xe7\xc5\xa3]G\x89#l9iA\x84\x86x\xf7\xef\xde\x7f\xf0\xe0\xf6\x9d\xbb\x0fx,\xcf\xce\x10\x03ax\x1c\xcc\x9d\xdb\x83{w\xef~\x7f\xef\xae\xef3f\x0f\x1f\xec\xc1M(\xbeQ\xee\xdfa'\xd3\xde\xdd\xbd{w\xee\x0en\xdf\x0d\x80\xc2\xb6h\xea~\x00\x83\xbd\xefy\xf3\xf2\xde\xe0\x9e\xdb42\xe2(\x85\xa4\x02\xc5\x0fm\x15E\xa3\x11\x19\x0b\x01\xa3\xd6\xbb\xfa\xeb\x0b\xba\xba\x08\xde\xec\x0b\x15\xe6p\x18\xb2\xbf\xb9\x15.(\xffD\x9dz\xf1\xd2Q\x1c\xc0\xef-N\x11\xe6\xb9T\x0eCUz\x17\xc7\"g.\xa2\xf2X\x84G\x90\xf3\xd3\xd1HH\xa7\x88\x9e\xd1(\x193\xd4)s-\xb2\x1b\x03\xe7R\xe6\xb5Y\x19\xcd\xf0*\x1fi\x9d!\x16\x1b\xe1;6\xc0\xd3\xb9:\xdd \x9f\xee\x0c\xcfc9\xdd <\x02\x8cm\xda\x9abB\xe0l4\xc1I=\x84\xc9\xf6\xb6\x81![\xc0\x90\x7f\xa7\x17\xc8\x16p\xc0\x9b\x19\x8cq0\x11\xec3\xeeWQN\xea\xbf\xe3|\xb0\x17\xa2g\xd4\x02]\xc9.\xbc\x84IQaIH\xb3\x96\xec8\x18\xc4\x81\x0e~[!\xfb\x7f\xe1\x9a\xf0x\x08\x13]\x98\x8a\x15y\xe4\xc5\xa5Z\xe9\xb1\xf8\xdebp\xaf\xa0\x9b\xe0\xfah\x00\xe8\x88\x1a\xc0\x88u4\xf6+\x1c\x19q\xe1\xc8\xe4%\x9d\x0d\xc8\xc8\x94\x00O^\x11b\xb5 \xff\xb4\"\xa2\xe6\xa8h\xc9\x8d\xd5?@\xcbE\xc9K\"\xbb\x9e6\xb3\xae2\xabQ\x9eMa\x05\":LQ\xf0J9\xd3\xd81\x93\xf7V\x0c\xb7\x90\"em6\xff\x03\xe4\xaf'\xc2\xf6\xbf\x03\x038\x80y\x7f\x95\xf0J\x10\xf3\xd1\x84Q\xa3\xc6\x8d\x11\x1b9\xe3\xc7\xe7\x9c\xc1\xe4\xbf\xfd\x00{\xf6j\xda\xbfyi\n\x97\x02s\x00\xf36\x96\xf42\x80_\xafL\xce\xb4\xd1e\x88]\x86\xcd\x8aB=\x13W<\xafZ?\x9cG~R\x94}\x0c\x9a\x91D\xd2\x10\xae\xe95\x126\xd60\x93snr\xee\xae\x08\xcdF\xe5\xec($\xfc\x11fF\x1e\xf38..#\x11\x1d;Q\x07\xcf\x95\xe9b%3\xb4L\x00\xfd\x84z\xa9 T\x8a\x80H\x04\xcb\x13#\x90\x88E\xaa\xcc$|C\xfd\xf3I\x15\x86\xfa\x97f\x18S\xb95\x04o\x027A\x87\xdaH\xd7\x90PGue\x8e\x96\xa0J:\x1d\x12\xde$\x02_\xdf\xf9J\x8e\x10\x97K\xff\x0e\x1a\xdd\xe1\x00V\xa3\xc5\x18Z\n\xb1sE\xd9\x9c\x9b\xc5\xf8BW\xd7J?;\x1e%>w8(8\x1c0\x94|\xa5\x90\xf7\x99\x95\xbc[\xdc\xbc*\x15\xbf\x04C\xc0\xf63\xaf7\xb3\xf6\x03\xc4\x8c\xdd\x87\x82\xd5\x8f\x1fB\x88i~\x18n\x0ca\xe0C>\n\xc7\x88\x067Q\xb3@F\xc9\xf6\xf6\xd8R\xb3\x0e\x14\xa1t\x94\x8e\xb9\x8a\x8b\xf5\xc8M\"\x98\xe3A\x1f\xcc\xcf\x1e\xaf\x02\x98\x04\x10\x0605@R\x9c\xe7\xec\xffj\xb9z\xb5H\x7f\x93*\x11\xb4x\xb2\x04\xb6\"\x12\x0df\x81c\\\xeaWxS^q\x0eRQp.W\x88?{k\xe03V4\x1fc\x9ck\x0e\xdb\xc6\xd4\xb8\xd0~xs\xa8iA\xd6\xc2!\x15\x1c\xb6\x84\x9a1M \x14\nu\x84\xda\xb6@\xaa\xa8\x84\\!P\xb8\x80.\xa9\x80\x8e\xab\xd6\x10tb\xcf\x86\xf0\x08\"\xdc\xb1>\xbb%h\xbb\x97\xf0-\x1b\xf3\xd7w\x06\xa8\x9d\xe5\xf7\xe8(\x84m\x97rn\x86\xc2\x1f*\xee\x19\x8f\xcc\xe3\x82\x9d(\xac\xa8'5\x93\xe6y\x95\xbb\xe0&\xda\x93\x00\xce\x1b\xe7\xe5/\x7f-;aa$Z\xf8\x08\xce\x10Df\x11)\x81\x03Ht,\x82\xceo\xf2\x97\xffel\x82\x94\xcd\xb4/L\x1cNa\xc6&LF\xa1\x81Lg<\xf8\xc6\x911\xa0\xc4\x9bu=\xa2\x85#\xadC\x0f\x05O\x81\xf6z\xc3\xb1\xd2.\xc3\xed\xec\xac\xe0\x11,\xae,\xb7U\x08\xecn\xa0?\xe0cy\xc0s\xa1y\xc0%\xe5R,c\x14d\"\xce\xfc\x0c\x1e=\xc2#\xbf]L\x9b\xa1\x98\xa6[\xac\xca\x9beT0\x1e\xb3!\xfe\x89\xb4\xd1\x8b`3d\xc2T\xce\xf9 \x06yc[\xad\xf2ZIB\"-k\x01\x92\xbd\x98 \x87\x11\x1a\xcd\x8c\xab\xedm\xfd\x9a\xcf\xbb\x9e\xf2\x8cS\xcc\x88\xc7\x99\x99\x05\x93\x9c\x8cta^\x90K\xe9\x00\xb2\xaaQ\xcbi\x95ZrNj\xc5\x98\xa4:\xd9xyej\xf9\xdf\xacKz\xf9\x9f#\x86\x82\xae\xe9wy\\\xe6Z\x14\x86\xbab\x8e\xa1\x92\xc0\x8f+\x7f\xb8\xbe'&\x8a_\x1d\x0eZH\xe1\x9a1\x14K\xf2\xff }WXr\xee\xb3\x8a\xd5\xf4E\x99\x97P\xc0\x92M\x80\xb1\xee\x13\x93\xf1\xb4\xb3\xa6\xa5]\xcb\xf2\x1f\xd4\xb0\xbc\xd4\x00`\xde\xd8\xe0/\xae\xbc\xc1\xa5\x18\xc3\xa3B\x0b\x9f+\x86 2\xa2\x8e\xdf\x18\x8cu\x0c\xc9\x8b\xeb\xd9\x835U\xaev\x99\x90\xe4!\x06W\x87i\\./\xc3\xea\x19\x05\x12(\xf3\x08\xfd\xc6F\x0ce\xc0\n\xc3H\xd8\x87\x0c-\x01Z4\xaa\xac\x1a\xb68,\xca\x10\x89e\xd3\xe1\xadXv\xde\xa5f\xd7#\xd1)w~c\x91+\xba\xf3\xd2\xb9\xf6\xa5\xfeve\x0d\xac\xa4=n\xd0\x91\x94\xd3\x91\xa8V\xb6\xe8!\xa4\xa2\x84L\xea\x94\"9.\xea\x97\xa0\xe7\xc1X\xadwY\x9f\xdc\xaf\xfaY\xfcrm\x93\xe3L\xa6\xdb\xd4\x0c\xbcN!|\xd5\xe6\xa5\xe7w\x18(\x12(\xb3\xcf$\xfdJ9\x06\x13,@\xa7=}qE0H\x8a\xac\xa0k\x03\xad\x88w\x83\x06\xf0\xd5\x0f\xe0\x86\xdaKL.ZS;\x14P\xa6\x12\xca\xe8_\x19\x94A\x02\xdc\x99\xf2!\xd8\x8b6\x88\xfa\x13\x04\x17\xc9\xac\x0e\xc7\xd4\x98<\x0b\xaa\x8e#\x03)f\x8b\x89Z8\xd6\xa8\xa8\xadZ\n\xe1\xdcg3\xd5AI^\x97en\x9bT\xee\x96\xb6n\xb0\xbe\x99\xa8b!>Q\xf0\xce\xd7v\x1f\x91l\xc4\xc1'\xddS\x0f\xb0\xcc\x1e\xafy\xd6:6\xb5KD\xfbj\x87v\x95FR~f\x19\x83]\xd1\x91\xb4I\x0b\xf8\x92\\\xa6\n\x00\xe4]\xbb\x0cQ\xc3/\x18\xc2O\xd4K\x8c\xf6s\xb0\x8a\x0b\x93$\xa6Q\xdc\xa9\xf8C\xb3\x7f\xe5W\x9f\xfb\xcc\xb6\xecj(\xb7\xa7ic\xb4\xe6J5\xe6I\xad\x11\x90*0\xd9*c\x1e\xea5\xdc\x82;\xcd\x96g\xf2\xd9^\xf3\xd9\xa2\xf8\xce\xe4\xb9\xbf2x\x0c\x9c\x89\xd8\xa1\x0bc~=\x87<\x96\x9a\x88Z\xf6\xe5\x9cxJ\xcaI\x8d\xf0-O\x82\xc8\xa3\x96\x0c\xa3\xb1\xbd\xc6\x03\x1fL*t@\xde3~\\\xa7\xf0\x98g\x8dN\xe1\x11\xac\xe1\x00\xce\x89\xb7\x8b\x0c\xcfY \xe2L\xb1\x10\x04\xf1\xe2>M\xb8\xfc\xedcYZ\xd2\xd9-\x06\xfdD\xdeG_ \xf6\xacI\x03\xd2\xa6\xe9-4\xb5-\xfe&:/\x127O\x8b\xb9\xddaD\xc9\x032%-y@\xd8ArN\x19\x9bL\x1c\xf2\x80(\xc2\x87g\x8e\xb1\xe49\xbc\xc4\x11\xf7\xad9-^E\x19\x85Q/\x80\xde\xb8\x99\xd4\xa2\xd2\x93cR\x8bH\xd6\x8a/\x93\xe2\xfbEVrZ\xcdJn9M\x99\x00[\xb0\x96\xe8+\x83#O\xd2\xe842y\xb6I\x99\x8b\xf5\x14\xf7y\x99P\n7\xe1T\x13\ni\x02P#\xbbF\x05\x06\xdd\xb2k\xb8\xda/\x10d\x84\x83\x8c\xb3U\x95\xaa\xf9&\xbfo\xf4\x0d|\xac:\xb1\x11x\xa4d\x83\xed\xee\xb2\x06x,<\x82]8\x80\xb7\x82\xc7\xc3m\xb6+\"L\xdfJ\xa7\x04\xb4\x00\xf0gD\x1b]\x06`N\xb0Gp=\xe5b\xea\xdf)\xed9\xc74\x8c\x16v\x86J\xba\xf7\x1b_J\xac\x81\x02\x08\xc5\xcf\x18%0 W\xe1$\xa2kn\x10\x1f\xc2{t\xc2\xabG\x0dpy\x10E\xac\x88\xbf\x14\xd5^\xa2\xfd\xe3\x059#\x8b\xf2]\xf3\"n%\x8e\xe1\x06Q\xfa\xd0Z\xee\x00\xf8\xd8\xd6\xba\xd0\x13\x8e\xc6\xec$\xd3w\x13 \xbf\x0b\xae\x8a\xd4\xf7\"\xaa^\x98)y\x0e\xea(F6\x03\x16\x16\xa9\xcf\x19\xdd\xca+`F\xd8\xc2\x0e\xea8}\x1fG\x83o%\x15P5\xa9\xb2v\xc0\xdcJ\x169@9\x84!\x1c\x96\xb9\xb3\xf4\xf3\xdfJ\xf4*\x95\x8a\xe3\xc4\xeeC\xc8\xb8\x8bi\x86~\x92\x02\x16\xd9\xb8\x10\xbf\x8c\x049B7\x91\xb0\x80\x1e\xa3\xf1~\x00a\x9d\x82ip\xf4\xc9\x8c\x92\xc6\xf1\xde\x8a\xa2^\x15G1\xc8\xf8\x1b0UX?Q\xa8oA\xd8\xc8\x8e\xb0\xfaN\x9cp0\xa9\xe2\xa0\xc9\xa2\x848\x98b\xb2L\x86]*\x185(\x88/Ez\xc8\xa0\xf1\xab#r\xca\xcdbE9\xd1d.z\x13\xca\x8a\x08\x95|\x81\xf0k\xcb\x8bi2&\xca\x0f \xaf\"K\xf3x;%\x01,I\xc0\x98\x06[\x1a\xf5\x13\xf3iU\xf2\xea\xf2\x10\xd7BX(\n\x8b\x93]\xbf\x0c\x80J\xbe\xd4\x165\xc3\x0f}3|*\x89D\x04\xe3\xb0\xeb\xd7&\x06\x95\xb8g6\xb70\x00\xa3\x8d\xb5\xa2\xc7 +\xe5\xac\x0c\x9e&\xf2\x92\xc4$\x17\xfeK\x07\x12\xc1\xf8\xf1\xbe/\xa3\xdc\xf1\xa7\x99G\x05\xe1\x97\x92\x8b\xca\x87\xbb\xe8\x19\xbb\x03\xb9\xfd\x93 F\x9a\xee@n\xe0\x1b\xf1\x95\xc7\xb0F\xdca/\xdb\xec\xa1\x02\x08\xad<\xbc\xbc\"t\x9ce\xd3\x9e\x14\xfb\xe1\xd8Rt\x04\x14\xb5\x04V{\xdc\x99\xc0>\xa3\x9a\xf6OD\xcb\xe8\xd9\x15\x8e\xa8>W\nh\xb7\x1d\x80\x0c\xab\xab\xbb\xe5G\xa89nYV\x11 \xea\xbc\x80\x13$/\xd5\x05L\xe0\xf1c\x88\xec\xdf\xcd0\x00f\x9b\x1d\xeb\xf2\x03\xcb2\xcd\x8a\x05\x9d]\xf3\x82\xe2\xb9\xf6\xd0\xe8`\xa1^l\xed\xb5\x19]tW\xa1\x8b2 }\xf5+\x12E\xf6\x98\xa8\xd3\xa6\x90\xaf_\xa1P\x85\xb6\xbel\xb6\xe3\xcb\x8b\x0dcR\xf3%lCpP\x08&G\xf2\x19\xec\xc3\xa4\x0d\xc9A\x8c<\xe7\xae\xe8\x19f\xde\x8f\xf8\xa1\x940\xd4\x88\xd9\xa9\x1d\xf9f\xb7\x04\xb0N\xc9\xb27\x90.6\x1e\xbb%\x948\xd7&\xfb1\x1d\"a#;\xd7\x99E\xa3\x10J59;\x9b\xd98UU9\xfeTT\xe5\x04oH=y\x8c\xbf\xca\xacGa\xa1$\x8f\xf0\x87\"5&\xfc\x86\xd0\x97\xe7\xfcW5\xb9W\xe8\x04\x8a\x0bb\xd3\xa8\x9d\xa2i\xd0C\xc5\"\xb7\xeb3\xf1\xcd\xd1\x14\xfe\xbe e\x13\x88s\xee\x8f/\x92\xf3\xd8c*(w\x9a\x7f$\x89\x9bT\xcc6>@^\x18\xf1R\xf1\xa5\x88l\x1b\x93\xb3\x9c-\x9c\xdb\xa4F\\G\xa1%c\xce\x8c\x9b\xf8&\x1c\x0e|cHXX5I3~B\xc9\xbcQ\x9ed\xc3\xd0\xc6[t\xccXi}\xd8\xa0iE\xb3\xea\xc8\x8b\xe3\x9f\x96n\x99jWA\x05v\x1c\xf2(\xec4xK8(nJ\x13Y\xae\x8e\xb3\x19\x83`\xc2\x9bC3OW\xa8\xd9\xd0\x1f\xa0\x88\xc1\xa3\x8ag*\x15\x1e\xa8k\xe2\xf1\xfc\\\x82-E\xae\x94\x8d\x8a\x89\x97\x8d\x02P\xfa\x91<1\x8f\xa4\xb0\xa0\xd7l\xbf\xaaeU\xcf\x0f\xf2/\x1fq\x81F\xb2\x82\xb0\x0dg&\xa4\xab\xfarJ&R\xf0\xad\xf8\xf5C\xee\xb7\x80\xae8XXuX\xf80\xf0P\xad\x14=\x19\xd8G;C8\xb3\"^[\x99wcE/k\x92\x1e%\xe8EF\x9d\xf1r\xc7\xea\x13\x19\x7f`(o\xac\x98\xf5\xd5t;\x98\x9f\xc1\xcc\xb6\xb7\xb0\xff\x89\x0b\xfb\x8f1\x1e\xb0m*\xce\x10\x1623bc\x8c\xdc\xf4>\x9a\x8dv\xf1\xefm\x0c\x19c-h<\x16\x18>\xe4\xf5\xfd\x95\xb4\x91\xa9\x9c\xe1\x9e\x12s\xc0\x0d\xbf:N\xa5\x1a/Q\x88\x1e\x13\x15\x99f2\xe8t\x1bfl\xd4\x0f}|.\xf6\xd1\x84\x8dkR\xdd\xf1\x070\x92\xc6\xa3\xc9X\xec*&\xd8\xcd`[f\x1f\xc8\xd8\x9fg\xba\x11q\x99\x90=\x9e\x05\xbc\x8c\xfa\x8c\x1d\x00\xfc\xdf\x04\xff\xb5Md\xc1\xa5\xb1\x04#\x08\xf0\xcf\xd0\x7f\x08+\x06\x11\xec9c\xbb\xc9i\n\x95\xa1\xf3\xf1\xea\xf1n\xde\xe6N2\xc5 \x8aG\x18#\xc1\xc9F\xc8%\xee}60\xbc\xad\xa8\xb70\xba\xd1pda\x905\xff\xe6\xe6M\x8c\x03F\xd1l^SA\xb4\xd0\x8a5F\xb0 !\x9f\xf0\xe9-a\x08\xd9CX\xc2c8c\xff0J\xd0&K\x1c\xc3\x10\x16HA\x96z%\x89\xbcXwkAr\x8e\xc7\xbc\xdf\xf2\xb71\x81\x94\x9e\xbf\x93\x1f\xf2\x9e\xcf\x90v\xc1\x10\xe6-\x94 $\x83/A\xe6\xb1E\xc1(\xf6iEq\x92\"\x1b\x13\xfax\xd6=\x1e\xc2\xca\x87\x9c\x81c\x85\x8b\x86\xfff\xdcmaR8(4\x9a\x12z@\xde\x96.|\xb2pGf\xc2q\xc4(\x15\xe2\x87u\xe5\xc4>\x9cX\x85\x19\xb60'\\\xe8~\xfc\x98\x1d\xe8\xb6\x85a\x038A\xea\xba*_\xf7\xe1$%\xe1g\xf3W'BP\xdb\x1e\x82\xc7\xb7\x94\x0f\xdf\xc1 n\x92\x9d\x022b?\x8dN\xf4\xc2\xad~q'\x1c\xab\x1f\x0b5\"o\xa7\x0e\xd2\x8c\xad\xcc\x0e\xcc\xd8\x12M\xf8~x\xc4\xf7C\xe5\x83b93F \xc4\xfb\x92\xba\xec\x08\xaa\xb2\xa3\x8d\xa2\xec\x9c\x924D\xb5Fy\x9cp\xb6\x9bV\xd8\xf9\xb0\xd4\xed\x00\xc6q\x96\xeeU\x13\xd5\xbdj\xea\xea^\xc5\xc8\xc49\xf1r.\xee`\xa4f=\xba\xd1p\x1c\xff\xe1\x96/2U\xf3EV\"\xe8\xcb,k\xa1=\"\x04\x93b[\x99\xe0 Z\x01M\xe9{&\x1c\xc2\x8f\xc5\x9eMp}E\xa5\xbf\xdc\xcbxJI\xbe\xea\xd7\x9dR2\xe5\xf1h\x93\x0e\xe8\x91\xc0c\xe94y\xf3&O\x10Uz%'HR$\xe4\xebYn\x0c+\xf5\xb9-\xc5\x1cw\xab\xdeE\xa5\x9c\xd4Y\x9f\xb1My\xe6\xd4\xfe\x91\xbd}k\xa1\xc7\xa7\x9ce~M\xca\xfa\x8e\xecVg\xbf\x9b\xb3\xff\xf5\xf5\x1d_\xdb\xa1X\x94\xc2\x9c\xd5\x11\xce\xd4\xe0\x07\xd7\x94|U\xd5\xc3\x91bT1+!\xca\x14\xe1(\x02\xe1\x8f}\xb4\xdb\xf7\x8fy\xea \x9e;|\xc1\xed\xcb\x0e\xb9\xc3\x9d\xe6\xf4\xd4\xaaLXre\xc2\x92\x8d\xeb\x03\xf1xu\x9b\x0b\xe25B\xfd\x0c\xad\xffl\x970\x84i'\x90,\xbd1\xf5R.\xf8\xe0(3x\xfdb=6LIA\x0c\n\xff\xac\xe4\xf8\xd9\xd1\x1a\x9aT C\x9e\xb7I\x8f\xb7\\?\xd1\xa6(\xcc\x05y\x1cr\xedi\xf9s\x0f\xbe\x83D:n\xa2\x8d\x88\x1b+\x9b\xc9O\x0d\"\xac\xbcD\xff\xca|\x84\x8a\x05\xa55\xc3>\xf2\xfb4yI\xd6d\xfa\x9e|\xf1\xfc\xee\x94\x99\x8ev\x0d\\\x83\xdf\x9f-\xa2\x95\xc7:x\x1d\xf2|:\nn2\xa2\x9bVp\xb5\x8a\xb9\xaa\x933:\\\xa0\xf1L\x96}c\xd4%\xc2\xc3\x9c+1\x14\xe7\xde\\Q[0\"\x12J\xd1T\xa3\xbcTb\xcd\x8c\xb6\x99\x12\x01rD\xa5\xd0\x1f\x0d\xc6m\x8b\x9dr\xd5\x1e_G1\n\x9ej\xdd8\x08>?\xe1L\x9fK\x12Z\xb6\x90\x8bB)\xa2\x19#\xc90\xf1=\xa9,\xb4\")\x07\xf7\x0d\x17\x94#\xd2s2\x0c\x8c\x1f\x90\x93s\xcc\xbc\xfc\xae\xc5\xeb\x04\xdd\x95\x14\xaf\x93\xe3<#/\xc9:SJYH\x8a\xd7L\xe2k\xea\xf4\x8d\x81\xa6k{\xec\xde\xfc\xab?\xb7\xf9g\x7fn\xf3_[\xe2\xd8\xfeAl)b\x89:\x02R\xed\x9e\xdd`[\xbc\xcd\xabSi\x8e6\xb1?\xc0b\x8e\xb2xIkCgE\x99d\xf1\x91\xac\x7f\x86\xdeg\xb6\xbe\xdd\x07\x0b\xean\x12\xddx\x06F$\xd0U\x14as\x9a\x87Y\xab\x1b*\xa8\x1dE\xf1d\x91OIV\xafj_\xb4(_\xe8\xd6\xec<4\xb78 's\xf2\x8ed\xf9\x02\xf9\xdf8\x00\xc5\xa3\xf0c\x8c\x8f+e\xbbl\x11L\x85ZO\xebL\x01U\n\xd5\xa8g\xe5\xc8\x18\n\xafC\xf4\xb5\xa7fu\x84\xb1\xd8\x95\xe2\x9d\xdau~\\\xdf\xcb\x0e\x82wmR\xbd\xd4n\xca\xaex\xbbf1]\xb2\xf0nN\xac\xf2\x92v\xcd\xd4Z\xbeV^\xc8\xa5\xd0\xd6:\xb6\xf2*\xf7\x19\xba\xb9\x8ev[\xb2!\x01\x86u\xcaw\x95\x0f\x07\xe3@\xf9\xbb\xe1^X\xbf\xecfQ#\x19\x91\x97)\x8b\xb9\x1b>\xb2\x95\xc2\x15\xfe\x99\xc9L\xb0\x0f?\x1b\x11\xa9r\xd3D{\x9f\xb7s\xba\xad\x148\xad\x13\xdd\xb4;i1\xd3\x80\xb4\x1e\xd2\xe9RT\x99\x97%O\xcd\x85~\x0b\x19{(r\xd0G\x18&\x8c\xbe\xf6\xbc\xc4N\xaa\x15\xedp@V\x02\xe44\xbc\xab\x12\xa0\xa8\xc5\xd9\xa6J\x83R\xaf\x9c\x91\xfcXX\x04MD)j\x99\xb2\x9e(9\xcdY\xc5\xe1w\xe6\x14\xce\xdd)\x8d\x14_\x93V*\x83\x8ev\x82\xc0H\xf9\xd5\xfc\xf6\x99\xf0I\x8b8m\xb0\xbb\xa8\xa0o\x82\x95\x06I\xf9\x9dA+\x0c\x14d\xcb\x91\x02\x85\x0c\xdf\xb4\x0b\x00\x06uB\xa3*\xa2a\x8f\x7fl\xf7\\\xb3o\xf0Xe\xb1\xe2\xfan\x8f\xbb0G6.\x8br\xf6\x07-s\xce\x9c\x90<\x05\xbe\xeag\x00*w\xd5a\x9c\xa0\xeeE.%\x9a\xb6\x8c\xae\x8c\x07\x83J\x8dl\xd9\xd2 \x16=\xa1&@\xe4}\xdc\x19\xc0\x8e&\x855\x08\xee\xa1Nc\x8d\\A\x95\xc6V\x1a7\xb4|56\xae\x85;\x8c5\xbc\\\xac\x8f\x0e\xf9\x8f\xf3p-\xc5H.\x03\xd82\xc1N\x1f[d\x9b\x91\xf6\x8c7\xf7\xe0\xb4\xe5\x7fpU\xf9\xb5\x9c\xec\xb8\x19\xa3:\xaa\x19\xf1\xf8\xacH\xd4\xebv\xfcFxL-Y/[[%A\x8c,\xa7o\xf4\xe7\xb2\x03\xc5x\x9a\xbc\x80\xb0\xb5kJ\x0b\xf9\\\x87ia\nl\xde\x94gJ\x9c\x80\xf9\x8c \xf5Uy\xa1\x1d\xe1\x13\x8b[/H\xa9A\xe5\x13\xf0\x832\x91\xe2\xf6v\x00\x91\x87~ \x1c\x02hn6\xe7\xf9dS\xad\xfb\x84\x81\\<;\x1f\xe1\x04\xa6\x1a\x1f\x91X*/\xb6\x03\xad\x03\x9b\xe1\xe8\xfc)q.o\xe5F@\x06eT9\x92\xc4\xfe\x854\x84%.\\ \x08\x9bX6\xda\xb5X\xcd\xe4\x85\xd9,\xb5\x89A\xd5\xab\x8a/34\x15*9\x81\x9ecED\x91[\x1d\x91gfd8\xc1(\xf8\xe8\xf9\x1d7\xdb\xc0\x17W\xe2G\x0d\x11\xa7l\x86\x9d\xdc\x88\x98\x101\x80[\xe8\x83\x83\x81\x88\xe8\x93#\xde\xff,*\x98E\xady\x93\x18\xda\x1c\xf1:ff{\xc2k\xa4\x90\x86\x80\x1cF\xc0 \x81\xcd\x06r\xf6W^\xf4\xc8`\xd2\xa7 W\xa1+\x07\xb1\xe7\x97\x90\xd2\x0fJ8y\xe7\xb0\xa3\xc3\xcc\x0c\x86C\xee\xe9\xe7\xb1\xcd\x96 G\xa4]\xd8\xd7V\x9a8\x13^\x8d\xf6cg\"Y\xcc2\xdc \xc4\xcaZ\xd2\x18\x1a\x96\x06\xc4\x00\xb6\xf0\x94\x8a\xa4Y,,\xd2\xf8x\x93\xfaY\xe1p\x0c\xcb\x0c7\"\xdc\xb4L\nDDQE\xc9\xa4m3:\x89\xe9f4~l~\x00\x93o\xd3SEV\x1e'*\xb2\xea\x95\x8eY\x06B\x87\xd6\x81J8Nu\xfd\x95S\xc3\xa2\x03\x92\xd4\xd7\x12E\x9cqW\x02\xe3\xf3I+1\xbe\x12\xcb&|o7\x1b\xd8\xc2r\x90\xf9\xf66<\x82\xa4\xdcl\x13F\x83\n\xad\x9c8\xc7b,\xf8\x80\xe7X\x84h3\xe1\xe65\x031\n`\xa2\xa3G\x93oT\xd6 \x9b\x1e\xeb\xdfi\x89\xecz:\x896J\xabM\x15\x9fy}\x1c\x96\xf7\x9a\xcfR\xb9V\x0f}\x88ZOK\x06\xaf\xed\xed\x0c\x1e+(\xdfv\x12;E\xbfC[\x04<\xbb.\xedj\x024P\xb5N\xa1\xe0\xaa1 \x96\xd4\xe2Q\x0c\xb0'\x01\xaf\xa3\x13\x88'Oe\x92\\\xf4\xc6P5\x95]\x14\x04U\xac5\x1d\x98\xbf\xbb\x1e\x98v\xb2}M<\xb0\x99\x8c%.{\x84x\x16\x97\xf73\x11da\xa3S\xed\x88n\xe1\xb4'\xad\xa4\x8a\xa7\xe4\xc6\xd3\xb2\xceuO\xfc\x92je\x0d\xb6;\xb3\xb3\xdd~\x00\x9a@\xcbk\xe2\xb9\xbf}Y\x92\xd4e]\xba0\xf7\xdf~\xdet X\xb8\xc9q\x914\x89\xda\xe55MZ(R$\xb3\x0e\x86\x82V\xf8U\xd6\x1f)CT\xa3\x0cQ\xc0\x8f\xb0\xa8\x8d.\xb4\xcb\x0d\x8b\xd2\xeaa\x7f\x99q\xa2\x0b\xac\xe47\xc3\xbfX\x07\x9c\xcb\xcb*x;\x13\xf1L\x16\xf6\x1e\xce\xe7\xd1\x82\x80\xd1)\x0fTu\x00\xda\xae\xd4\x99'\xd8G'\x9a\xe7&$\xfcz-\x86\x8fo\xb6\x04X\xf0\x17\xe9\x94\xa1\xce\x91\x18@1\x1b\xeae-\xb4\xe7LT\x0d1oeve:\xca\x16\xb5(\x10@\xe1\x9e\xb7\xd0\xf3j\x02\x8f\xb0`\xcdM\xc8=\xac\xda\x87e\xf2'\x18\xa8\x0d\xfb2M7R\x84X\x94\x03HPR\xf4\x0bIbk\x17\x8bs\x9a\xf1\xca\xac*g\x0b\xcb\xben\x96P\xfa3L\x19\xa9Y\\\x03\xb1\x8a\xa3\x96B\xe7\xd7F\xa5\x04[\x958))\xa8\x93\xc9\x04\xe4\xb9%R\xcdw2\xcfN\\\xe9\x0d\x88^RA\x01\n\xf7\xeb\xd1`\xcc$T\xd4\x10z\xa1\x8c\xa7@\xecb\xc7h\xeeM\xca#3.\x08G\x1a\xf0\xf3s\xd2N\x16\xd9\x15r\xe7\xdcD\x94F\x9b4\x96\xd7\xda\x82\xf0\x8eJ\x90\xac\xa3g\x97\x19i\xdb(`\xdb\xaa]#C\xdb\x81\xa2\xba\x99\x99~\xb1RT\xee\x91\x89\xd1\xaa:\xf9E\x12\xdc\xd0\x986:2SK\xbe'\xa5v\xa3\xe2 HZ\x8a8 \xb8\x8fR\x1cy\xc4K/\x1e\x00\xffP\xb8\x97\x11\xa3\xfb`\x91e\xdaxD$\xfd,I\xa9\x9b4+>!\x1e\x1d\xdd\x1e\x07\x10\x8fn\x8f\x11\xcb\xe9ho\x0c;\x10\x8f\xf64\x19\x82\xfd\xb2 y-+\x83q\x97\x96;i\x08{\xcd6\xeb\x15\xfal\x0d1\xd0\x8f\x06\xba\x81q\xce\xf5\x85\xa8\xf1\xc1\xdd\xbao\xf0_?z5\x85\xa0 \xa7^Zq\x8a\xfb\xbb(x\xe5b7\xfa6\xed\x82,u\xe0\xdcRG\xe0\xcaK\x02\x99\xad\x0f;\x99\xe0w\x0fC\xd8K\x9fK\x86\xef\x96\x03\xff\xea\xfa6\x07\xf6\xbf\x03g\x88\xab\xd9*\x80\xa1n\x02\x973\xb9\"\xa0\x04\x16\xd8\x00\xc2\x13\x90\xf4\xb3dI\xae\xd2\x01C/K\xf3\xa2\xbe\xd4_\xc8H\xc9\xfc\x989\xe6\xc7\x14\xce\xbe\xa2\x1c\xc5U\xa1\x88\x03\xb4\xcd\xf2\xfa\x05\xe2\x1f[s!p\x13\x0b\xaf\xc9A\xfb\x93$\xceh\x9aOP\xb3\xecF\xdf\x7f28zGE6\x1b\x1e\x81\x84%F\xe8(6j\x0d\x810\x01\xc9\xcd\x818mI\x9c\xcc9\x88\x82\x04Zs\x8aq\x0bv\x14g4\x8c'$\x99)\x15\xcf-N\x11\x089D\x8f\xea\xa7\x95d\x9f\xa9gR=\x17MX9tv\xc5\xa8\x96j\xd7\xb2\xe6e(\xe5g\xb2\xce\x8c~\x89\xf2\xdar\xe3\xca\xd4\x8b\xa6k\x87\xb7\xd8E\xb4\x11\xaeN\x9d\xc8K\xcceJfQL~N\x93\x15I\xe9Zp\xbe\xee\xad\xb0\xeb\x94PE\xb4\xec2\x06y\xa9$\x88\x87Mvj\xe2\xb2\xdd F\xbd\xb2\xcax[\x8fo\xdduJk\x89\x98\x03\xe8=\x0d\xe38\xa1\xacuHb\x08c\x88\x8a\xf4\xbc)\x99$\xe9\xb4\xdf+H&\x8f\xb6\xb3\xb0\x98\xba\xab=s\x9b\xbc\x0c\xd1\x08\xf5\xeb\xb2\x7f\x12\xc5S\xaf\x8c\xbak\xff\xec\x12&!\x9d\xcc\x01\xc1f\x1f\xd0\xa5']\xd3\xe5\x11\x91\x0b\xfd\x04r\xfdq\x88\x81\xbcK\x93\xe5aL\xd35\xd7\x95*\xca\x9fv\\\xe9V(\x81\x0b\x7f\xc3F\x95\x04\x87\xfc\xda\xa4B\x14*\xdd\x1a\xcd\x08%!\x11KT\xfd\xc8\xbc\xacp\x00\x1f\x88p\xe5\xecPmA\x1e-D\xdd\xd9<\xef\x85F\xa2AHF\x99BH\x87\xf0\x9aT\xe1;\x9a\xca\xea\x06\x15\xa8\x17u\x0e4\xfb6\x00\xe2\xbd#\x01\xbc\xf0\x03xw\x05\n\xdc\x14\xfc\x90\x02\xeb0\xa1\xd2|-n\xa0\xb5\\\x1ao\x9b\x17M\xb36\x8c\xfa\x91\xf7\xe4K'\x9a\x81\x8d\xcb/\x9bt\xe1]\x15nN\xa1BgJEf=\xbe\xb1&>Jr\xb8\xa5K6X\x19\xa3L6\x80F\x0d\xe7i\xaa\xcd\x88yJ+\x8798\xfc\xd2o\x04\x89\xd6\x80\xc01\xb7\x15;T\xb2\xa8\x07\x02\xa3\x02\xcf+\x87M\x070\xa4W\x01C\\\x03\xc32\\i\xf0\x15\x04\x18\x1a\x85_\xde}\xdb\x19\x11XB\x94\x9a(Y\x1e\x13\xd5\xc9+\xe6<\x07\xc7e\xea\x11S\xcc\xd2%#P2\xdf\xf2?y7>\xcf\xd2S\xf4`T\x9d\x17\xcdG\x81\xc8\xd7\x1c\xc3>/\x06\xa4\xeb\xcao%\n\xdd\x8e&<\x1eT\xb0\xf8\x16\x08\xca\xe3I\x7f\\\xc4U\xddS\xc3\xa0aD\xdd:\xd8\x8c\x8b\xea\xa8\x90\x97\x96\xa1\xd8\xea}Q\x88 hP\xe1JCT4\xf3U\xc0\x82\xf8\xe8\x17V\x98Wt\xcba[\x8a\xf2$!\xde\x1b\x12\xc0\x0d?\x807\xeaR\xe9\x02\x01\x1d\x89x\x11\x0d\xd8\xa4\xe4o\xbems\xb5R\x1a\xf3\xfah7\x9d3o\x86;\x0cA\xee\xca\x92ig\xea\x86\xf7\xdf\x84\xb0\xd7\x82\xa1\xc4\x15C\x89\xc4P\"14\xe5\xa6\x10\x81\x97N5\xc3\x88\xf7\x8a\x04\xf0\xa3\x1f\xc0\xabo\xe7 ,\xc8\xf7\xeaZ\x90\xef\xcf\xc40\xe2\x8e_\xda\xc9\\\x1b~\xfd\x87\x91\xa8\xc4\x9f\x8e\x88\xf4Lp\xba\xcfT\xe8\x10!\xcc\xb4\xf1\x10\xcdu\x14,D\xbd\x9fg\xff\x95\x88\x84.1\xa6\x87\xec\xfa\x89x\xc6\"z\x8a\x93En}\xab@W,\xd1\x8f\xc2\x00:vr\xb1\xb5\xbc\xb9\xcbo\x1a\xa4Xv5\xf5rZD\xd7\x02\xfb\xbf\x06\xd1\x1d\"C\xdd\xf6\x02\x14\xe1\x95\x15\xb7p\x8b\xf3\xa4\\/\xd2\xe6e\x89\xde\x95\xb6\x11\x02G\x0e]\x18\xa0zI\xde%o}S\x0c\x1e\xf7r\x04\x07<\x91\x0bG\x89\x14Q\xa2\xbc9\xe07\x07\xcd|\xf9\xeaepYt\xa0 \x95s\xb8\x9a\x86\xe0\x9d\xf9\xd1+\xf3\xa3g\xe6G\x98\xa3\xcaK\xe3\x00N(\x13-b\xe5\xcdoT\xb0\x86\xb1\xe0A\xb7\xa1g\xd4\xb0V:\xec||V4\xea\xec\xf3\xb7\xe7qi\xf2\xb1w\xe6\xa8L\xe0i\x9e\xe6Eut\x1b\x9aW7oep#\xaa\x89S\xae\xcc\x85\x89\xaf\x07\xe5\xdfRg\xa1\x89\xd9\xac\xcf\xc4I\xf9[J&Z\x95\x15\xef\xff\xe6Me\x00\x15}\xae~\xb2R\x99\xa0\xda\x06\xcc\xd3\xec\x1f\x93\xe5\x8a\xaeQL.~\x0c!\x8f\x85\xa8\xfd\x1bm\xa6<\xadM\xd5Qc\xdc\\\xb4\xd2J\xcd-\xd4\x7fS\xacZy\xfc9N\xcec\xf8L\xd6\xd0\xfb\x1bl\x03\x85m\xf8[\x0f\x92\x18\xd8/\x89\xc7\x06#y\x05z[%\xf8D1\xfd\xb2\x16\x87\x16)\x1c\xf4\x86\x15cBu\x892\xa9\xd7j\xc1\xadJY\x08e4%\xce\xc1~\xb9\x0e\xcd:\xcc\x955pT\xae\x1b7\x8ey\xa6\xc48\xfb({\x8f\x9a\xf8I\xdcT\x01\xcd\xe2\x00\x16\x0c\xc7z\x7f\xff\xfb\xf1\xf1\xd1\xeb\xd7\x1f?<\xf9\xe1\xd5\xe1\xf1\xfb\xc3\x0f\xc7\xc7\x7f\xff{\xaf\xe9\x08\xb2bog\x0eJ\xa3y;\"\x18\xaa5\x91z\xb5& \x05Y([j\x88\x91\xcd\xe5\x87\xa6\xf4\x8eg\xa0^\xae\xe8\x9a\x87O\x17`tSDL\xdb\xf7bU\xc9\xb5\xb2\x04a\x94\xd9\xeck\xe5\xebb9-\xca\xb3z\x97kJ\\\x93p\x9fY\xe9\xd2\x0c\xf3\x0ex36\xdei\xec\xe9L5\x86v\xd7\xdf\xa0\xd2:\xe7*\xad\xd3\xb8\xd4d\x9d\xff\xbfM\x93uj\x87_\xa1\xee\xd3\x14XT\x7f\xad\xe2\xd1\"\x96\x0et+E\xa9\xb5*\x95Z\xab\xaa\x82I\xfe\xac>\x10\xac\xc1*VuV+\x17\x85\xcf\xca\xa6\xf0Y\xb5)|V\xb1\xdc\x870\x84\xb3X\xdc`[\x11Q2\x00\xe2\xadcF\x9c\xfc\x00\xd6\xd7\xa7\x11Z\xff)\x1a\xa1\xf5uj\x84\x84\xff\xbdM1\xb4\x8eK?}N\xb9O5\x94{\x19\x07p\xcc\xf6\xc9\xda\x81\x16\x9ft%l\xc7\xff!\xc2vn\x85\xe6\x92\x13\xb6%\x1b\xefI\xec=u/\xbby\xf1\x0d\x84\xed3'l\xef\x15\xc2\xc6n\xf5\xf38\x9bG3\xfad\xb1p\x8d\xe6\x7f\xef\xac\xe8~bWt\x1f\xc7\xa5\x83\xed\xb1\xba\xd7\xcecqC\xec\xb5\x13\xdck\x17q\x00\xe7\xd4\x0f\xe0\xe2\xfa\xf6\xda\xc5u\xee\x8a\xf74\x9c|\x86\x11\xdb\x10\xe3\xe6\x86\xb8\xb8\x82+H\xd5\x18?'\xe1\xb4\x89\xcf\xa8\xb7\xa2JRn\xea?\xe4\x89\xd7\xe9\xce\xceC\x1f\xbf\xe7^U\xe6\xbd\x00\x07 \x92\xd0\xe8\xe2\xfe*#_\x11\xf2\xb9\x13\x80\xd8\xa8K\xc3!\xfb\xa5\xc9\xde\xd1\xe8%\xcf\xe6m\xbd(9\xbe\xe5\xfa\xbai\x1d\nM_\xe1L\x82\xbb\x7f\xbb\xd1N\xa00\xc0l\xe0\x01\x02\xb3\xfe\x16\xec\xc0\x80A\xfc1W\x1b\xee\xec\xf8\xf8\x99\x89/\xc0\xcc*E\x1b\xa3\xd8\x90\xfb\x90-X}-\xd8\xa5I\xb4\\\xc5GC0e\xc1i\xe3z(\xf1V\x8d\x8a\xa1\xfcn\xad\xfc\xb9p\xed\xff#\xd6\x8b'\x8d\xc5{\xc2H\x91\x83`\"\xd4\xc9\x98\x1f\xda\xa3\xbe\xcf9\"\xfb\xfa\x959HZ\xa4\x16d\xc0\xf5\xd0m\xd9T\x05o_\x84\x07u\xe0\xd0\x08\xcf\x92gB\x01(\xd1\xc0P\xf5\x18\x8a\xf5o\xa6\xce\x87\x06\x19\xc5;E`\xaci\xfdIm\xfd\xe3\xab\xae\x7f\xd3\xfd\xba\xb1\xfeIke*\x15e\xb3E4!\xde\xc0\xde\xa68\xa6\xba\xb4\xcb\xd0\xd0Q\x1d\xa5\xeb\xca\x05\x83\xeb\xdd\xe9N\xd1Z\xeb\xdd\xa7\x91\xac\xae2\x8b.V\xa6o\x8d\xcf\x16(U\xc3\xa0.x\xc5X\x11;\xd8\x18\x92\xb8\x1c\x99\x8c\xa8|\x16\x8e\x1e\xc5`]\\\xc1b,.\xa2V\xe95h\xb8_{\x95\xa6\xab\x16\xaa\xa2\xa3sZ\x1f}\x99\xa6\xc7\x18\xe3W\x9cLi\xe5d\xc22gQ\x95d\xb1\x83\xe6\xa1\x8fw#\xfb\xe9n_\xc4\xb4\xb6\x88\xd1\x95\xd6\xef\x8fXWa\xba\xb6\x86\xdd\xd4V\x85.\xa9\xa9\xb9R\x10\x14\x0e\xf0L*\xa8\xbd2\x99\x8ea\xc8\xea\xcc\x06\x06=\xd4\xc5\x95\xb5\xa0\"\xee@]\x92\xf2hQ<\xbflH\x11\xf3=\x97\xd6\x10!\xad$\x13Le0H\xac$\x13\xc4o\xd2\x16&\xd0i\xb2n:R\xa7\xd9&z\x1db9S\xed\xd9\x97\xba\x9d\xdc\x8e\x91 \xad^\xff\x92\x9fH\xdb\xe2\x07D\xbf%\xa0\x03\xee\xd9\x8f\xcb`\xb2\xfa\xeag\xc8[je\x1e\xda\xb2\xf3Y3\xf3\xb9D\x05\\\xa0\xd6\x15\x85\x9a!\xbc\xd7H\xef\x87q\x00Otz\xd7\x0fO\x9e\xbe4h^\xdf\xb2\xf7/\x1c\xa4\xfd?\nw\xbd\x96\xfc\xa15\x8f=kF\x99\x92\x19\x8eTN8\xaa;\xeaE%\xfdK\xf9\xaf*upK\x19\xf8\xd9z\xea\x1er=\xc0!\x03\xc8\x1f\xb1\xd7pO14z\xd4..\x16ho4K*\x87\xd3\x08ut\xec\x9f&J\x18!\xa9\xa6\xef\"%o\x1c\xfb\x01\x94.\x93Jh\xc4\xfb\xf5\xf2$Y`\x85\x04\xdb\xf3z[\xb4\x06\x11\xf5\xd7\xdbx\xf4\xa4P/\xbeu\xd1\x06\xbe\xb5i\x03\xdf\xb6i\x03Y\x17\xaam\xed\x8b\x9aE%\x80\xb8\x7fT\x12\xc8\xaf\x01[\xa6X\x97\xfeK\xa4\xc4vH\xf3\xf5\x8cz6V\x04\xc4\x82S\x91\x1b\x97g\xda.\x8f\xf6\xcdFk\xa3\x87\x1acP\xe6{0\x98\xde\xac\xa6m*\xb0GOc\x1a+\x88w\x9b4\x81&G\xf1\x94\\\x90\xe9{\xf2\xc5\x010\n\x89\x7f#\xa2\xce\xddz\xf9\xe9\xbd{\xeb\x08\x1cm*l\x17\xcd\"W\x87pa\x84p\xefn\x1d{!\xa7,\xd2\x94]\xd2I!\x17;\xf6\xde\xa9\xdb\xec:\xbb\xed\xbcI^u\"\xa6\x9d\x9a\xcf\xaa\xb3R >\xce,\xac?/WY\xaa!\xe4\x9c\\ \x052\xae\xee#\xbc\xb86\xd0\xbf\x8a\xb2\x0eK\xbe\"\xd7\xd5/7C\xb8\xf7\xdc\x1b!\xc7r\xb2 \xe3\x9eK\x0f\xa5\xa9\xc3\xb1\xfc\x85Y\xbb\x04\xdb&\xc6\xf2\xba\x9f\xbe\xf2\x12\xc3\xcc\xb91\x8f\x97\xd9e\x94?\xc5\xb0\xc7}\xce\x14\xc2\x01\xe4\x98\x92|\x1fB\xea!\x7f\xd8\x8f2\xc1'J#\xe0\x88\x8e\xb5\x94[\xbd.}wOo\xf5*\x10\xc0\xe2\xf5\xad^\xa6\x8a\x1dP1\x16D\x0d+\x8f\xfd\xabA\xed+\xfb\xb8\xcfD%\x84h\xb4\xebP\xe79)\xed\xad\xb8\x08\xa1\x97\xa0\xc7\xae\x0c\xc4\xcd<\xa5\xd0j\xb3\xde\x96\xbc\xcc\xd9W\xcfD\x95(Q\xfdBW\xd7X^\x92\x92ci\xe9!L\xeaT\x14\xc7\xc4$N\xf9T\xd2S?\x90\xf7f\x8b\x90R\x12{[\xbb\xc2\x12\x83\xdaEM\xd1\x13\xebV\x00\x01\x1c%\xcd\xa8\x13\xba\xc8-\xc4\xfd\xa0\xec\xc0\x87f\x1fJ\x85X\xd86XN\xe4e\x06\xf8%\xaf\x8d\xd6,g\x8b\x0f\xa5\xfaV\xe3\x0e\xed\xc6\x8eH\x8f^\x97\xb4\xc9*\xbbV\xf5 v\x897\x98\xda\x12#k\x0b!4n\x91\x98\xa6Qe\xac.CU\xf4{\xef\xdc\xba9#\xe9\xda\xf1Lq\xe4\x82cK*\xf2\x16.8\x0d\xc0V\xf2\x13\x8a@s\x8e\x03\xbc\xd6\x11~\xa1\x14Z\xe3Z\xa2\xad\x81\x01\xf8uG\x12\xd0\x03\x86\x13]G\xc8\xd4O\xae\x1f\xd4|\x82\x9a\xf0'0\xf5\x19Ok=\xbaT\x8db\xc0d\x9fbNT\xcf`\xde\x00UOz\x80 M\xf4\xe5\xc15\xc3\xe2Z\xa1n\xb0\xa8 KP_q\xeei\x89y\xbb\x89\xaf/S\xa3\x19\x08\xe3@\\6o\xbd\xef\xc2\x92\xc2\xe9!\x1c@\x0f\x19\x1f\xd8\x87^\xd03c2#\xc1=\x8d\x1eU^\xdf\x82\xe96\x1c\x8fE\xa9\xfe\xad\x01\xba\xacn\xa3\xd2\x14\xffE7\xa3-YBJ\x99\x14\xaei\xe1E\x83gN\xaf\xc9Y\x82\xd8\x01N|\xdbg\xb2\xfe\x06\xf2\xf3\xd4iE\x97\x159\xd4\x01\xad\x8a-VM\xd9\xe9\xd4\x19?K;n\xb0\x00\"\xeb\x02\xd7p\xad\xe1\xa0\xf2\x08\xf60?\"\xc3\x14\xd8\xe7\xf9\x90\x1a\xdbAU\x03`\xcdZ\x1b\x01\x84\x03\xf0\"A\xe5\xb09_\xb4K\x8b\xd2\xb7\xbcb`b-\xc8\x9c\xba\x83\xec]t:\xa7\x1d\xe1& \x93\xca\x08\x95\x86(;}\x12\\\x8f0\xbd\xa7F\xbb;\x98\x06\x8d\xbd\xb8\xe3n\x81Tj2\\\xa7\xae\xd0\xb8|E\x0c\xfer\xb5C\x82q#\xddz\xe4yYx\xac\xdc\xbb\x18K\x85\xe9\xb2`\xe8\xbaJ\x9djL\xd4gf\x0c\xc8\x01}?(u\x7f\x03\xad\xf9\xd9\xa9\x97\x93\x9c\xbe\n\xbb\xa8\x07\xf8\xbeF\x0f\x99\xdd\x00v\x06N\xbdD\xd9\xe1rE]l\x0c\xa2\x17\xf5dR\xe4\xf4\xba\xe4\xbe/\x96\xb1\xca\x8c:\xf0\xa2&#\xa4\xd3l&I\x1e\xd7w~\xcb|\x9ex\xb4T%\xf1m/\x04X\xfeq\x07\xbd\n\xf6\xfe\x83+{*\xfaw\xa5R\xa0P\xaa\xaf\xd4\xf3K\x83\x94-\x03\x9eD\x0d\x1d\xf1nc]\xf1{\x917\xc1+\xeb\x94\xf3J\xe2lW\xaa9\x8f\x9d\xa46E\xe6\xd2\xb3\xbb\xf2\xb2\x94R\xc1\xb3@5\xb7\x19*\xe4]\xaa\xe7\xad\xcb\xea\x91/y\xb8\xe8\"l\x9d\xd1\x82l8\xb5/\xb2f:l5\xd5\xe1T\xbf\xb6\x18\xa8\xd5?\xc6ty\x95\xe2L\x94\x96\xf7\xed\x9cb\xb5z\xeb\xcf\xb1_S\xb5Z\xcf$\x0e\xc6A\x0b\x1d3\xc3@\xa2\xa0\x1b\x05\x8e\xaa\x94\xb7\xd5\xfc\xa4P\xb0\x00\x12OG\"\xe5e\x18\x7fgQc\x1ev\x913\x90\x0e\x89\x84\xcbK\x1eC\xb0t\xec\xe5\xa8\x0b\x0d\x97\xfdp\xaf\xd1.=E\xd9\xfb\xfc\xc4\xb1\xc0g!\x03\x0eM>aE\xa5\x14nu\xe6<\xba\xa2\x13r[\xda\xe2<.\x12\xe3t\xc8\xa7\xa5\x9f\xe2\x8a\xf1B]&\xe9\xd9f)`\xa6\xcc\xd2/n\xba\x9fj\x9f\xc9\xfa\xed\xac\xc3\x90\x8aC\x8d1s\x9d y\x0dFB\x1eq\xee~\xc4W\xb42lW?mH\xa9.\xdd.\xba\xab\xd1\x1a%\xbf\xfa\xc8\xcf\xba\xf7\xf7\xf2*\xebb\xe0\xbdq\x8d\xb5\xb9\xac\x9a}/\xc3\x8b\x0e\xbd\xbe$\x9dT\x18\xcb\xf0\xa2\xeb\x99\xfa\xb2\x92\x8f\xc8\xa9\x137\xa3Yc\x06p\x00ob\xee\xc2\xf2\xd5MPZF\xf1\xd5\xa7\xc3\xbb#\xbc;\xd7\xb9\xa5\xa43&jC\x1eA\xdf|\xf69Zu\x80\x9d\xd2\xfe\xeb\x90\xce\xfb\xcb\xf0\xc23T$6tV\x17\xbe]\xa5\x04\xc3\x1ecMzT\xb9\xe3<\x90_\xe7\xd1\xa2\xa3\x99\xa1\x18\xcc\xefW4l|\x8eV\x1fc\x1a-\xbau\xcb\x81.\x87\xdcM\x05\xc5\x13\x82u\xeb\xafi\xe5\xd0d\x06\x03}\x7f4\xfcL:,/\xad\x18 \xae\x80R\xac\xbfkF)\xd6dw\x94b_}\x0bJ]E\x92\xf8\x87\x13w\xab\x940\xfa\x18\xa3\x9a\xb7\x92\xbc\x0d#+[\x18^\xc9NS\xa3vY^L\xa4\x8b\xaa\xb1yJ\x81\x96J\x18\x08vlo\xedL\xd4\xf3o)\xfb_0n\x1a\xc1\x87\xa2J$l\x9b\xa1\xd2L)\xfd\x14\xdf\xde\xbc \xdb\xdb9\n\xa9\xa2AC\xa1ry]\xfa\x01\xe4\xc67.\x03P\xcb \xfd\x17\xadJ\x92vY\x16Z\xf1\xc6b\xdf\xd9\xe5Zv\x85\x16\x8f\x12y\x89q:FY\xaa\x17\xfaN\x85\xc5L\xdb?\x00\xf7\x88G\xf5\xb2F?\xaa\x97!VB\xbd\xa4\xe9&o-N%/\xae\xc3\xaf\x14\xa9\xb2x\xa9\xcaKF4R\x11\xc3\xdb\xfa\x01\xbb2\xe1\xac\xea\xf6\xf6\x04\xdf\x1e\xb4\xb8\xb6\x82n\xafM\x02\xc8P\xe3y\xc0H\xdbp\x08\xef\x84\x98\xf3\x9cad\x86/\xf04\x7f\xa1\xf0\x0c\xf9/X\xdc6\"`\xa5\x00\xda\x87\xdd5\xaf\xec\xe0\xb9*SQ\x1cZ\xdd\x98\n\x19C\xd0\x91/\xed.\x86\xcd\xc3l\xfe4\x99vpt\xa1\xf32\xbb\x00\xd6e\x9a\xab\xd9\x06\xday\x04(\xb6\x17wP\x1e\x0ea\x00\xb7`\xb7\xd8h\x16\xd2%\xcd\xa4\xb3V\x05\x9f\x9b+\x7f*\x8a\xdf\x0e\xf4Uo\x8b\xd7\xf8\xc0\x9c\x16\xbf\xf6\x0d\x1b\xed{\x14\xd2o\xdf\xb9\xbd\xf7`p\xff\xf6\xdd\xdb~P\xdc\x86G\x8f`p\x176@\xe0\xf1\xe3\xc7\xb03\xb8\x1b\xc0\x9d{\x83\xfbw\xee>\xd8\xfd\xbe\xfe\xdem\xe5\xbd\xdb\x01\xdc-\x9fc:w\x8f\xc06\xdc\xbe\x7f\xef\xce\xde\x83\xbd\xc1\x83{\xb0a0\xfd\x17\xdb\xd2\xff\x12\x9f\x0d\xee\x05\xb0\xb7w\xe7\xde\xfd\xbd\xbd\xbbE\xf3\x87\xe2s\xec\xa6x\xf3v\x00\xb7\xf7\xee\xdd\xbbs\xff\xc1\x83\xdd\x07\xbe\xda\x84e\xcby*\x7f\x10c\xad\xcb\x83\x8eP\x83!\xdc\x1e\xc0w\x90\xc26<\x8f\xbd'\x147\xcd\x13\xea\x11\xdfg32w\x0e\x8e\xbbS^\\+~\x85^\xaa\x93r\xe9\xa6\x98\x11v\xd4\xdaA\xb7\xc6\x1d\xdb\xf5\xb5\xe5\xac\xa1 \x88:RX\xb9SW\x06\xb3\xbd\xf8\x9a''Sr\x01\xa8o\xbc\x8eG\x0b\x19\xe0\xfd:\x1e=c\x7f\xbf\x16&\x8b\x8c\xdd\x12\xa1\xa3\xfc\xb6\x08\xac.\xee\xab\x81C0\x84W1>\x89\xe2l\xc5s\xe3\xe3'\xef\x93<\xad\xe6\x95\xd1\x81\xac\xa6D\x12\xee\xad\xd5\xd9a\xeb\x93y\x18\xc5\xbcma\xcb\xe4\xb7\x93\x98\x86\x11F\xa5\xe3\x10\xb8\xee\x12c\xc4S\xdd)9[D\x1dB#\x0b\x01\xe5+1\xae\x84N\xed\xb3:l\xb8\xf7\xbbZ\xff\xcdT15\xcb\x02V\xe1\xae\x93a\xb5\x90&\xa4\x93\xc4( \x1a\x9b\x8bO\x03p\xa3\xaab\x93t\x14\x1a\x97\xe1\xeae\xd5\x07\xd9\x15FW\x00\x02[\xf7:,\xda\xc4\x8c\x06,x4\x82\x05\x08\xd8\xc9Uv\xeb\x87\x18\x93\x9b\xb4f\xeexj\x06\x92<\xd5\xaa}\x19\xda\xf9\xb9\xb5\x9d\x11 \x80\x8e\x9d\x1a{g \x87\xf5\xb3\xb9e\xb3mQ\x97d\\\xd0\x84\xa7aXo\xaegX;\xd7<\xacW\xf6a\xf52\xa4\x81\x15\xe3\x07\x1c\xc0O\xef\xdf\xbe\xe9\xf3G\xd1l\xcd\xd5\xb6\x82Z:\xe6\x16}f%\xc0\x87\xc6L\x9e\x86\xe6\xbe\xb6b\x10\x85G\x05\x07G\xe11\xfe\xbd\x83\xec\x9cS\x07\xcf\x1d:`\xac\xcf6\xec\xdd\xbb{\xe7\xce\xed\xbb\xdf\xdf{\x00\xdb\xe0Q\xc6\x90\xdd\xf3\xf9\x9f\x8f\x1f\xc3^\xf3\xf4\xad.\x94h\xedCT\xaf\xc2h`\x95\xcb\xe5\x95|\xb3\xad\xaeu@J\x1b\xdeV\x82\xa5\x00\xf8\xba\xf2\xd0R&\xa2G\xbe\xaf$-\xc5f\xc5}k\xcb\x97\xac\xf7\xc0\x96GC\x85\xa8\xdel\xe7\x0c\xd2\x80[\xee*1~\xd8\x7f\xeb\xe4\xdd\xed\xa1W\xb0\x9f\x15\x90\x8d\x18ds\xf8\x1f&;\xb0\xad\xc7p \xa9\xb8\x00c\xcc\xef>\x7f\x07\x0e\xe09\x9b{\xce\xd3\x91\xa2\xd5F\xfe\x8cd\xca\xd86\xf0[\xad%\x86T\xe5%\x95p\xde\xc6\x0b\x12\x9e\xb9p^\xd2,7b]\x8c5\x87\xb2oY,\xb6/op\x02 \xf5/\x01\xdc\xe8'3t\xa65~\xc6\xf3\x93(\xde\xf9\xd6s\x96\x14\x1b\xdf+\x88\x81\xb8\xc7\xe8\x80\xc8H\x13\x94\x94\xc8\xcd\xc7\xa9\xab\xcb\xdd\x92z\xbbj\xcaj\x97>\xae\xe0_\xc7\x0e|\xc7\x08\xd5\xebv\xefq<\xf9\xbf^I\xafzC\xfe\xf1,\x0el\xc8\xe6<\x86_#:w9\xa7\xa4\xcc\xa3\xf6b\xc77\xc6\xd3\xc9\x00\x81\xe6\xf8M&\xcb\xca\x9dK\x9fQ\x842=\xec\\\xea\x1b\xd4\x9bE\xdd\x96#t\\o\x0e\xbf3\x8f\x85\x18\xc4kA\x0b\xb3\xb2\x93\x9cv\xd5|:\x9a\xaa\xd3p=\x9b\x0d\x9b/s\xb89@;Q\xf2l\xf3\x12\xda\x15+\x81\xfaX\xb1$\xa8\xb7+&\x85\x17\x81\xaa\xa4\xf5\xf1\xde\x8d\xca\xf2\xf1{?V\x9a\xe6\xf7N\xa8\xe6\xe3s\xaa\xf9\xfa\x82\xd6?oBE\xe6\x97\xdb\x87\xb8 W\x04\xea\xcb\xe6\xfd\xa7\xc9bA\x10\xd2\xfbp\xac)\x90\x81\x01b_5\x0f\xd4\xb4\x92G\x1a\xe7 \x9e\x97o\xa5y\"R\x05^hGI\xf7!\xd3\xe5{\xbb\xbb\xd3O\x9f\xf2\xe9\xfd\xdd\xdd\x1d\xf6\xefl6\xfb\xf4)\xdf\xbd\xcd\x7f\xee\xde\xbe\xc7~\xce\xc8\x1e\xfe\x9c\x91\xbd\x19~3\xc5\x9f{\xbb3\xfet\x97\xf0\x7ffc\xd3\xe0\xcc\x14\xad\x100(\xc9\xa8J\xc7.\xbb\xc1i\xb0\xfb\xa0\xc6\xeb0.\xb2wx\xb1\"\x13J\xa6\x10\x16\xed\xf4\x14c\x8f\xbc\x07\x89\x96\xb0G3\xf0\x94\xf8\x88-\xc5D\xb0\xd9\xc8\xecA\x1cE\xb4\xaf\x11\x1f\xe8\x9e\x864<>\x16\xd9F\x9bX\xa9h\xf1\x84\x14[\x83\x0c\xbb&\x9a\x1aTQP\xb9]\x14\x82M\xaa\xf7yQ\xc4\xbcz\x933\xc4a\xf5f\x86ofUB4\xe9\xb6:\xb7\x1f\xe8\x97\xe7\xce\x83\x96\xe3\x18\xa8\xc8\xcb\xc1Co\x1b\x8e\xeb\xca\xe6\x15\xc6\x0eOT\xe6\x04R\x9c\x80\xf2\xd1V\xc4\xb8\xab\x9b7\xd9\x1f\xb1\x8fJay8\xc6\xec\xaf\x98\x1dA\x95\xfe(\xeb\xf2\xca'\xfe\xed\x07\xb7\xb5\xb3\x1e|_G>\x81\x94\x0f\xeei\x90r\xd0\xc4\xc7\xbd6\xd2!k\xb9pG\xe1\x99\x0e\x15\x17\x98\xb5\xf8&\xe4\xcd\x03\x17\x0b\xb2\xca\xb2\x8c\x8d\xa7s\xc4H\x9dY\x8a\x11\xa8\x15\x03\xe4\x1c\x81\xec-\xd8?sx\x0c+;]F\x9d!\x0f\xd0\xf5\x9b-bAK\xfeX\xa9-6\xc5%n\xb6u\x06C\xd8\x194G\xbd\xe62t\xe3\xfe\xa9\x00C\x08\x07|'\x82\xf4\x8e\xae\xb6\x8dy\x01fx\xfc#\xa9\x0f\x80\xff \xbc\x06\xe8\xf6\xf6\x19<\x82\x956\x11\x00\x1b\xd6\x92\x81ttf\xe0n\x8e\xb1(\xcc\x99\xc6Q\x9c\x01 \xf3\xb1\x89\x13\x18\xc2\x02\x0e \xf3\x8e\x03X\x06p\xc6\x03\x91py\xf7!\xf3\x96\x01\x1c\xe3]\xbe\xfa3\x0d?SK\xe2{b\x92\xae\xd9{'>0\x018\x8aM)\x0b\x10\xa2\x03\xfd\xb3\x93\x94\x84\x9f\x1bO\x9a\xe7\n\xeb\xe8\xd46\n\xb6e;\xd8\x0c\xf0\x93\xc4;\xc5\xd7n\xde\x04oY\xe6\x8c\x9e0\x08Q\xb9-f~\x89K\xa7<\x16\xdf\x18\xdel\xeb\xd1\x06\x050B\x02\xb4\xd0\xb8\x04\xb2\xc8\x08Nb\x89\x0bt\x8c\xfbh\"\x96\xb6\x18\xb8a8\xdf\xba \xda\x13y&N\x10t\xba-~0\xfc_\xff\x9f\xea\x876n\xc8H\xa5\xeas\xa9\xd4_\xdb\x11 /%\x11\xa7\x98&o\xbf\xa0Ml\xdb\xc5\xf0\x08\xd2\x87\xcd\x95C\xd3\xb8GG\xf1\x18\x01\xa7r\x86\xbbZ\xfeOI\xef\xd4\x91\xcc\xdf\x19\xd4y\x83\xe2pkRyQ\x91\xa98^\x9b\xf4\x1e%\x19\xa5\\S\x93\xfc\xa3*\x08\x9f\x1de\x87q\xbe\xe4\x8a\x9f&{\x92\xda\xad\x1db\xe2\x85\xb8VE\x06\xcf\xf7\x85 \xde\xae\xec\x13\xad0\xe6\x9bak.X\xcc\x00z\xec\x0fBz\xfc\xc4\x0d\x9b\xf7\xab\xfd\xe9\x8f\xb4\xcce),\x99\xf2\x15\x06Qch\x10\xeb4\x18h\x9e%m*\x97-\xd2\x8f\x93)aB3\xdek6\x81\xab\x89\xa2w\xb3\x1d\xca\x8d\xd4\xac\x1dZiG\xa3sbk\x9es\xe0\x16\x90A\xc1\xe4\x00\xd2\xfe\x0f\xf9lF\xcaS\xab\xf95\x03\xa3\xc7\x8e\xb7\xb0\x1fe\xb5\xb7Q\x8a\x8d\xccJ\"E\xe2\xa9(\x89\xee\x0f\xfc\xc2X\xdc}\xdf\x1b\x988\xda?''\xabp\xf2\xf9\xe7d\xb1\x9eE\x8b\x05\x0fY\xe9O\xc9*%\x93Z\xedG&O0\x96t\x15\xd29k}4\xc6L\xf1\xf3h1MI,\xbe,~\xb2\xe7e\xb9\xb4)\x99E1\x91\xfb\x0bqr\x91\x84S2\xed\xe9\x14\xab\xa4\xd8a\xfbz\x0e\xa2K\xd1\x19\xda_4\x1e7\x95\xd4\xe6qF\x7f\xc9\x18#\x8716Wk\x08\x83J\x02\x9b\xced\xd4 #\x0c\xea\\t\"\xee\xdf\xd1p\xcb\xb8\xdf\x92~\x94\xb1\xfd4\xe5Q\n\x95\x97\xf8f:\x80\xc8\xcbQ\xe5\xa4\xa7;a\xb7\xb1\xdf\xdd\xbd\xaaZ\x91\xf2\x83\x8d\xd1\x81\xb4]\xb9\xd8\xbe\xb74g\xaa<\xc9\xe5;Z\x87\x17\xa9!\x10\xfa\x05\x91E\x90\x8e\x85;_\xcd\xdf\x84p\x8f\x92H\x16'\xf4\xe2\x9a\xa9\xeb\xf2\xaaX0\xb8_\x97\x818\x16|\x7f\xbf\x15\xc2m\xec\xc4.\xf72\xf0\xb8\x1a\x88\x07\xf1\x17\x9cD\xa1X\xe1\xd2\xe0#H\x1e\xfa<\x85\xe8(\xf2\xc8(\xde\xde\x1e\xfbc\xbdv\x8f\x7f!\x082-h\xebU!\xa0\xd7\xd9\x0d\x1a\xd8.v\xc1^\xfd`\xe3\x8a\x8c;\xdf_\x05^bJii\x18\x8c\xc4{\x07\xc0\x90a\x1f\x12/\xaf\xb8 9M\xae\x97g\x042\x9aF\x13\xaa\xa8\xf6*^X\x0d?\x11\xe9j\x13{\xdf?\xa8\xebF\x94\xe9\x1c7E@&\xbas\x98\xdd\xfb\xbe\xf6\xe5q\xff\x1d \xa7\x8cN\xbe\xa7\xfc@YV_`\x80\xbe\xeb\xf7\x0f\xcfHL\x0f\x97\x11\xa5$mv\x10\xb6\x81Q^%\xd1\x8f2Jb\x92b\xd1M\x8er\x8d\x0ft\x96{\xb1%\xea(\x01\"\xb88\xf6\xee\xef\xfa\x82\x03h\xbe1CA\xfdc\x14\xd3\xfbH\x07\xd9\x9e\xad\x9c\x9f\xcd\x99-85\x1b\xd4\xc0\xb6\xe8G\xf1\x9c\xa4\x11\x15J\xaf\xbb\x1a\xf3\xc0\x8a\xa3\xdd\xdd:\xb1\x06\xa12\xd0 \xd5\xec\xfe\x8am\x9fU\x7fJN\xf2\xd3Er\n\x07\xca\x0f\xaf\x97\xd1\x94\x84\xcb\x9e\x0f\xfbmC\x9f\x06(\xfb\xb3!\xd4w\n\x08\xe1\x88\x81\xb2\x8eK\xe5\xd4\x98X]7\xf9\xb3\x86O\x19\xf7\xd0#i\x9a\xa4=\xc6\xbd.\x92\x8c\xb0?\xa6$\xa3i\xb2f\x7f\xae\xc2\x9c\xdfKI\x96/Iol\x8a\xd6Y\x1a\xd1%\x01\xa1i\x8e\xbd\xbd\x81\xa8a\x81b\xab\xae\xbe\xa0$\x16\x04\xa28\xa3a\x94w\x86\xe5S\xdf\x0f \x13j\x85F\xb6?\x13 OJ\xe5\xb8)\xdaS\xe1!h\x0d\"M\xb0 \xdd\x147i{ym\x8f9q \xa8\xaa\xe2{X\xae\x93^\x89\xc7_\x14xfSJ\x9e\x15\xc5\xdd\xc4\xcb\xacu[*\x15\xce\xc3J\xaa\xc4\xa0N\x04\xdd\xe2\xaa\xd1\xd8\x0f\n\x9d?l\xb3\x86\xab\xd4\x17\xf6\x8b\xaf\x0dJT\xed]RR\xae\xdd\x00\x0e\xb5\x86I\x06\xba\x1c\xeb,zH\xb3\x11\xdf\x9d\xe0\x8aP\xd0\xcf9\xe5Uy&\x85F\xc4KQ\x15\x92\xaa\xdbf\x86\x94\xa6\x19}I\x94\xb8\x83a!\x0c\xd5NK\xcc\x12\\u\xaa\xe8\x1d\xc5g\xe1\"\x9aB\x9c\xc4;\xbc\xd9[\xe2p\x98\xcc\xf3\xf8s\xcf\xb7\xc5\xd3\x18&\"\xb6\xb5\x06n9: \x06\\*A\x02\xee\x15\\L\xc2\xe0\x99\xd7\x86,\x1c\x89\xc4*?\xc6\xc8\x1f\xcf4\xff\xfa\xc7e\xa5\xf9\x9f\xa5j\xf3\xed\xcc#<]\xb1bND\xd8\x10\xa7\xe4#bn\x13\x0c%\xd7\xe3\x06N0e\xa7\xb4z\xe45\xe7\xcb\x16B,\x02\xe7(\xfby\x9c\xcd\xa3\x19\xf5|\x08g\x94\xa4@\xe2)\x10\xc6\xf5\xf7\x10\xd7\xce\x11\xedd:;\x04\x16GU\x97\xb6q\xcb\xc8\x86\x0f\xdf>\xe7M6\x88C^\x1c\x19L\xfa\x8f\x19\xb4 &>\x92\x9b\xf6<\x8d\x84\xae\xbd\x0em!\x85\xcb\xb5:\xa8\x8cw\xc0z{[\xee\x9b\xea3\x9fW\x8fb\xcbP\x1d\x90\x0e\xfb\xea\xaa\x83\xb6\xb5\xda\xa2\x02LH\xb8\xab\xdc\x04n\x92\xa2HV\x8d9,\x99.j\xa4#\x97^\xeeF\xe3\xcf\x15\x1a\xaf\x1b0)\xb8\xa8\x9b7\xe5\x1eVh\xdf\x16\xe1l\xd1\x01\x9b\x02_\xebiHC\xb6\xd4\xa8\xf7b@\xf3v\xf9\x9a:\x12E\x8e\xa4\x05M\x95\xc8\x17\xb36t\x94\xb6\x02\xb8\xff?{\xff\xbe\xdc6\x924\n\xe2\xff\x7fO\x91\xc2o\xc6\x03|\x84h\x92\xba\xd8\xa6M\xeb\x93e\xb9\xc7\xd3\xed\xcbH\xb6\xbb{\xd8\xfa\xa9!\xb2H\xa2\x05\x02l\\(\xab\xc7:\xd1gw\xcf^#\xf6\x01\xf6\x9f=o\xb0O\xb0\xb1\x11\xe7MN\xef\x03\xec+lTV\x15P(T\x01\xa0,\xf7\xec9\xdf\x87\x88nS\xa8B]\xb2\xb2\xb22\xb3\xf2r\xef\x1e\x92F\xc7e\x8bJL\x9a\x16\xfa\xe85\x87\xe7\xd2}C.\xb8\x18\xd4\x9d\x1b\xa9\nU\x17$\x85\x7f\xb8wO\xf7\xba\xe0\xfc\xaaK\xac\x91\x81\xdb\x05\x0c6to\xd7\xf6OO\xf86F\xc3\xe7%\x83\n\xc1\x88\\\x8b\xdf\xe5\n\xe7Y(\xd7\xc9\xffRj\x15u\x1a\x0f3&\x0d vdA@\x11D\xe3\x06.7N\xeb\xb6ix]\x8es\xdf\xc8\xec\x08\xf5P\x19\xd1C\x91\xebN\x1b\xa9\x80.\x02\xd25f\xf1\xa6r\xf3,Hv\\f\xb8\xa9\xc0#\xc8>\xbbl'\x98\x99\xd1qyg\x8eK\x19\xb9\x92SB\xc5\x9fC\x81 \xdfs\x8d'\x0f\x9f\xa3\xd4<\x93 (\x87\xa2z\xc4+]\xf8\xc9[/K\xca.P5]l\xf5\x8b\x94_\n\x86r\xfaT\xd7YBd)\xa9\xd5\x9c\xda\xc91\x95\xcd\xa2\x885\x86z\xb2p\xc3j\x94G_U\xac|\x84\x11<\xdcy\xf8p\xbf\xf7\xd0\xa4/95\xa2n\xae>\x7f2b\xfe\x8dU:N\xf2#\xbb\x87d\xb6B\x9dS\xa6\xf0=(\x1f\x08\xd2\xa9\x9a\x93\xe6\x05\xf1\xa6]z\x08\x88\xb2aQm\x88a%\x80(\x07\x1ac\xa2U\x8dA3!\xcb'\xf6t\x04\x1fQ K\xff\xa5\x9dloSY\xeb\x13\x1d2F\xf7*\xfd5(\xfd\xb5[\xfa\xeba\xf9\xbb}\x17\xd2NG\x9bk\xe0\x86\x9d3\x08U \x0e\xe8!\x92CS\x9e9\xa9h\x0cz\x98\x9f\xb9\xd59}\xac\x87Bn(\xd7H\x8f\xaa\xbd\xf7\xe9\xe9\xa9*+(\xd6/l\x8b\xbe\x16\xef,\xb7XtG\xf7\x0d\x9bI\xce \xb0|\x1f\xef\xfc\xc9\xa5}\xc8#/\x1eV\xdceM\xf3<\xd4\xcf\x93\x0f \xc4$-\xe4.\x18\xc3!\xbf{\xd56\xa0\xcb\x1b\xe3n!%}\x08\xb2\xe0\xaa\x86\x04\x9d\x8e\xf2I\xfe\xa4u`2u\xfc\x93\xb1\xe3\xd2\x05Ln5FY,\xc1z2\x86K\xda\x7f[\xa4\xe0!I\xc10\xea\xf6\xd7\xc2\xb6\x96\xde\xf5\x05\xa1\xab\x86\xf3@\xf5B\xcf\x92\xd94\x17m\xfb\x8a\xce\x9d\xc7Ny0\x0d\xc0\x1a\xa9\x89\xbfL@\xb84\xaer\xae/\xa1\xe0M\xfd\xc9\xa5n\x9c\xad\xfax\xd9\xbc\xc2\x02\xdb\x99\xe6M\xd7\x13\xe2\xbb^1G\xaa\xca\xb4\x1c!Q\xb3\xcd\xd1\xd1\x05u\xc9\xa4\xe5\xdclJ\xaf>\x97\x08 \x8a-l\x8b\x8e\xa7\xb4\xad\x1f\x97\x07\x99\xa7R\xe6\xe3s\x1e+\x02\x8fi\x84\xef\x9a\x0e!\xe5\xe89`]!u\xac0J\xf9\x91\"\xc4\xcf!l\xa5\xec6\xf5i\xa9\x0d\xbb\xa4\xc0\x91\x0f\xa3\x9f\"?\xb4-\xbc\x13\xe9\xf3\x9eyI\xcd\xc1%\x0b\x1a\xdc\x9f\x92\x14>\xb1EQ@\xbc\xd8F\xd9&\xd4X\x94\xd6\xa9Z\x0c\x1a\x8a\x94\xed]\xf5\x00=\x00Lu$\x97H\x91B\\\xb9@[-u\xf2,\xc8\x1c\x06\x9a.\x88\x04\xe5p\x93\xf0\x96\x05\xc5\xa2\xad\xea/\"\xc4\x13Wmt\xd5\x07\xef1qlf\x15\\\n\xdb#\xf0\x8dDI<\x88\xed\x8f\x81\xc5r\xa4\xf4\xa46\xf7\x14\x08uf>\x80\xfa\x81\x82\xb8\x91\x81\xa7\x10\x15p\x8c\x8a\x13\xbf!\xb2\xb2?\x03;c\xd6I\xc5\xe7>\x95\x8e#\x18\xf2\x1f\xe5\x85f\x9b\xc7\xc6\xe9g\xb5\xa6\x96\xe2\xa9\xb4ow:\xb1\xcb\xc1\x81\xab\xbe`Zf\xfefX\xbc!\xdd\xd4\xf3\x03\xae\xe7\xe7\x02\xbc\xa8\xecr\x08A1\xc4\xcc\xa4\x91\x93\x1f\xb3\x85\xa7xn:\x1d}xc0jFA\xb2m\x17\x13\xddFw\xa0\xaam\x0e\x085)q6\x89\xab*p|\xd2\xf5\x82 \x9a\xbc\x0f\x13oF\xdaE\xe1m\xb1+(\xca\xd7\x98\xc5\xc6l\xa7N\xa2\xd55\xaa\xde\x04\xe7c\x97\x83\xe4\x8b\xe0\xbc\x1eSaS\x9c\xf7k\xc2]\xb8M\xc1\x974\xb9\xee\xf0+~\xde\xb9\xc5 K\x19E\xc3ev\xb9{\x13\x9bp\xf4\xb9\x8c\x0c\xbb\xde\xe1\x13\x7f\n=\xd95\x93)\x98\xffd\x910\x17Ql\xc7\x024\xa5\x9dB\x14\xe2\x9d\x02Y\xae\xd2k`J\xe8?i\xe6Bd%9\x13\x02\xe4\xfb\x17\x89\xfd\x7f\xabMrb\x8c\x1dj\xd6\\)=rU\xa1\x98$\xb3\xd2,_V\xf7\\\xce\xcbVD:\x9b\xce\xdej9\xa6\x93v\"I\x8fk\xbfr\xc9\x84\xd9\x93C\xd8\xe9\xe8/\xb20\x1a\xfa8\xe4vq\xc5\xbd\xaaQY\xb6\xadJ\x0f\xf2_\xb2B'f{\xb2^C\xc0\xa5 \x8b\x9d\x9d)\x8c`\xe5\xc5 y\x19\xa2[J_\x17\"e]\xf2;+\xe1\xa0\x9e\x12b\xa43=z\xf2\xf5\xe3\xca\x0d\x9dQ@N\xdd\x98\xffyE\x93-a\xf8\xa8\"\xd3}\xfa$\xd4\x0c\xc5\x8d5\x9f\xf1\x10*\xe2;k\xc7\xcd?qku@G\xec\x92\x18\x86pl\xf3\xcblJ\x10M\xf3\xe4\x04z$TP\x8e\xd4\x9ac`\xfc\xef\xdd\x13\xbd\x98\xdaF>\x99\xa5\x13-\x83\xc6\x88>\x0b\xdb\xa2\xf5\n%\x01\xe6\x15\x11#$\xd2N\"\xd2IS\x95\x97q\xfc\x0b\xdb\xe2u\x02\x92$\x90.\xbc\x10\xaeh\x8d\xa5\x17_Zl\\\xa8\\\x15`\xc3f\x85hw \xd6\x82\xfe\x11\xe1\x95\x19\xde!\xf8l\xe1\x91\xbf\xe3R\xf94\xc2\x01[\x8e+}_R\xa9pMQ\x05\x80:\x8dRI\xe3\xa8*\xd5\x1c\xb9\xc9\xbe\xab\x08\xc2l\x05C\\A\xbe*lic~\xc4\xf7\xe0 \x17\xf0\x86\xfc\x88<0\xe8\xb5\xd0\x0e\xc7\x91u\x7f\xdb\xa8\xec\xd4\xce\"\x07\xa0aFa\xb1\x95$\x85\x07\xc7\x1f1T\xd4\x8d\xe7\xd7(\xa5\xbb\xa8\xb8\x92w\\Q\x10\x9f\xb7\"(R\xc3\x9a\x0bM\x06q\x07\xfc\x04\xc2(\x05\x7f\xb9\n\xc8\x92\x84)\xa9\xd2a\xe5\x06\xc2_\x91\xd67\x10\xb5\x01\xd5\xa2\xb6\x97\x13\xc9\x95\x8f\xae\xc6\x91d8eb\xad&^B\xa07\xd4\x96\x01:\xe0\x0b{\xac\x1af\x0f\x99 }1\xb6\xdfo\xd3\xfe\x98\xfft!\xad\xc9\x13S\xd3\x15\xbfOi\xec\x8b] 5^wI_0\xd3\xb3\x0e\x95n\xe9\xce\xc7%\xc5 \xa0\xa3?N!Z\xa5\xc9\xe8\x8f?Yn\xa9\xb6\x9e\x1f\xa3\x8b\x8c^([\xcc\x90\xb0\xcf\x15r$\x9c\"YJ\xf9\x1dP\x92N\xa3,U\xde\x908\xa6\x92;\x0c\xe1\\\xb9%\x80\xb2\xc3\xb5\xce\x88X<\x0b\xdb\x8a\xc2,\xa4\x03\xb5\xd8m\x92\x08\x88\xca.\xdf\x99\x1e%\xee.\xbc\xe4=\xd6b7\xd8\xa5\x17\x8c\x06,lk\x12\x10/\xccVB\xa7\xb6\x8c\xd6\xdc\xf6\x8d\xc4vn\x1e:\xd7\x96\xce\xfc\xd0O\x16\x96\x0bKm\xf14\xf6\xfc\xd0r!\xd0\x96\x8a\xfdy\xad-\xe5\xb3saB\x89G\xf5\xe3\x90\x92\xeaYM\xd9\xb9\xb6\x8cS\x9b\xb5\xe3\xa2\x85/\xde\x82E\xb2\x96\x10\xaf\xf5\xcf\xafb?-]\xbcn\xa9/\x91\x08\xe6\x9f\x04\xfa\xa8\xf8\xe6\xf5\x9d\x19\xaf\xa2qm\x913d\x86{\xd3\xc68P\x808^2\x18\x91x_\xe4\x11\xc2n\x14N\x88\x00\x0dZ\xbeu\xa3\xb0\x04e=\x9e\x07\x8d\x14\x174v\x15Mrz;\x01B<|\xb3\xbe \x9fs|\x92\xd5\xba\x8e\xa2\xe5\xc5\xf3\xa7\xf8{{\xbb8\xcf\xca\xb58\xfc\x8c+\x8cQ1m\x886~(h\xc1\x7fc\xeb\x84-\x06\xe3b\x17\xe8A\x8cx\xa8\xd1-\xac\xb9+9-3#\xd2\xda\x9c\xab\x171\x89M\xd0\x05\xa1\x12\xe7\xd4*\xcd\xadq(\xfa\xb2\x83\xdd\xees\xa9\\\"\x97\xe8}\xc4\x89\xbb\xf0<.Ux\n}Z\x89\x87_=\xb1\x0b\xfa\xcf\xe3t\xae\x04\x135\xf3\x82\x84\x00v\x0b1IVQ\x98\x10\x17\x84\xady\xa8^\xc0\x96\x96\xb8\xa6\xb4\xd3\xe1\x93C.\xa4\x8b\xedm\xba\x1b\xaf\x1b\x80(H\x15q\\8\xb7\x1b\xa9\x19C8\x86`\xec=;\x17\x14\xc6D\x17L\xb1f\x90s\xe3\xb6j \xcc\xe7Z\nb\xeehYO\x9bx\xdb\x8d\xc7\xc5\xa6\xdd\x9e\xd7u[\x1cva\x97\xfdnw\xf6\x0by\x96\xed\xc4\x9c\xf8k\xbbi{;\x00P T%\x1b\xfb\xaeb\xb2\"\xe1T\x00\xa5\x08P\xae\x96\xb0h\xcd5*\xf4\xee9\x9a\xf0%\x0cy\xf8\x1fcr\x06\x07\x90\xd9\xf2\x0b\xf4n\x92\xfe.[d\x95>\x1d\xc18tK\xaf\xce\xb0\x8a\x08\x1e\xad'x\x12*\x8b\x03\x9b\x1d(e\xfe\x80\xbdS\xb8\x02\x86\xf4\xfc\x9c 1f\xa1 \xb4\xfcn\x0fY\xb1\xe2F.\xe4\xb7y\xb6S\xb9\xd4\xaf\x18\xc1T\x18\xf3Z\x9d\xd5&*\x03\xf3\xda\x17L\xd4P\xbdL\x15\x8f\xc6\xc9\xa5\x90\xc3I\x89\xa3\x17\xd8\xa1\x0d_O?\xea\xd7|T0\x97\xbc\x9c\x07\xccfV\x1cBb\xe4exT\x96\x1d3H\xc5+\xa3t\n\xf6\xb95\xbcX\xc4\x9c]Hy\xc4YnH\xaf\x1f\xf8Vmp\xd2\xb8\x18\x98Y\x83\xedCy\xe6\xfa\xcd\xb2\xe9\xac\xf4\xad\xe4\x8a4\x16\xe7\x1a\"x\x02\xfec\x88:\x1d\x07\xe2qtf\x82A\xad\xc2\xb6b8\x04Z2\xb5\xe61\xdcNlR\x9c\x9f5:8D\x89LZl\xfeY\x97eg\xb03\x17\x9d\x97K\x80\xd8F\xc9\xa7\x8aM\x9c\xf9\x11 \xe4\xbf\xc6\xbd3i\xf7\x9a\x16\xbensF\x95\x1b\xd7:\x899)}Y\xb8Ap\xc3\x0d=\x861\x8a\xce8\x13'gm\xcc\x06h\xb9\xeaA\x10\x18\x8dRY\x84,)lVD\xfb\xf5\xb8\xdcJ\xa8\x07\xbc+*+\x91c\x8d\xcb\x11\xdd\xb9\xba\xf7\xecB\xa4\xa2\xc9\x89\x0d\x0eM\xb1\xa4\xec\x8a%}\xceq\xae<\x94\x04\x85K\xbe\xa6\x9b\x1c\xabu\xeb\xefM\xf3\x93\x0eF\nf\xb8\x8a\xaa\x18m;Z\xc4cL\xdb\x02:?s\x95\xa3\xa68eR\x85\xddo\xc4T\xe0f)eC\x13a|T1?)\xdf@\xbc4GP.\xa2\x9c\xeb\xec\x0c\x15=\x14\xe5n\x9b\x00U\xa8Z\xe9.b\x1c6\xf0\xc92\x1dG\xcd\x16q\xdc\x96\xfb\x08\x0fnd\xde\x0d\x16\x94\xca9R(\xe6\xf8W-\xa6{\x15{\xab\x8dN\xf7\x9a\x1b\x80\xb6g\x7fl8\"\xf2\xe3\xc1\x07?\xe4\xa2\x1d\xd7B4\x89\xbd\x94\x9c,l\x8b\xcefE\xa6\xc0\x85\xfb\xb0\xec/!t\xf1\xf5\x92s\xca,\x1f\xda\xb9A\xf1\xb3[\xbe>0i\xcd\xc0x\x8dI$S\xed*\xf2\xe6\x9a\x04\xce[\xe7\xb00&\x1e\x94!!\x84\xd3\x12(l\xbf4G&\xa7\xfa\x14]\xb6B\xc5o$W*\xa3\xa6^\xb2\xde\xf7\x99Ho\xab\x1f`=a\x95\"\xc4~\x9c\x9f\xef0\xa2+t\xe3\xb9 \xa9\xdb\xb2\x0e\xdaLJ>S\x14\xbb\xc6\xfe\x19\x94\xe3\xd2JR\x01/\xb4EE \xa9\x9b\xdc\xed\x1b\xd1K\xaa\x9bR\xe6\x9f\x87\x81\xadM\xe5\x07\x065\x86\xaf\xbb.\xd7qF\xf3\xfc\x8a\x11\x19$D\x82\xf98:\x93vz\xf7\xc2\x0f\xa7\x9c\xba\xd1\xa2\x1a\x8f\x9cT\xf6\xa6l\x86\x8c\x84B\xe7\xfc\xfe\x908\xc2\xfb;\x16\x14\xa7\x10#\xaa\x13\xd5\xd3\x9e6\xee&\x82\x84\x94|\xbb\x9b\xa3\xd8hL\xaa6rM\xd1Q\xd8\xd2\xc5Qu\x8e\xe5\xd9\xa1\xdf\xc7\xf9,\x8e\x96\xf4T\x86\x11\xbc\xfb\xa7\xa2\xac\x1c1\xdb\xc50\xd8\xed\x02g\x97bpW\xa3M\xb4iB\x1fNc]\x84\xbaz\xa4\x8dI\xeakO\xea\x1a%\xcb\x8dv\xd0\xe5\xcf\xb9\x1bK\x0b\xbb\xa3[_\xf5@\x93\x1bQMd\x01\xfc\xac\xa2\x9c\xd6\xbc.Z3\xee9t\xb2\xce\x98\x9b\xde\x01\xfa\xe0\x14\xc6\x9b\xed\xfbA8\x97\xb8\xd9\x9c\xe7\xf1\x85\xb8 |,\xd0Z\xc7\x00\x91F\xcf&\xe9\xde\xb420\xbb\x16\x02\xe5\x8f\xf9k;\x8f(\xee\xb6Ppo\xf1$\\\x07\x94-\x97'\x18\xb2\xd9\x85\xbaA\xa9/\xcb\xb0\xc2A\xe1\xed+\x9e\xccZu\x96A\xcc*\xfd\x99;d5\xd0\x92[\xc3\xbd\xafg\xef\xe2j\xf4\x85\x8a\x0b\xcd\xb4\xb6\x05%\xaa\xc3\xe7,o_\xfb\xadf\x04\x95ru\n\xe5\nL\x95U\xdf\x86\xb2\xa8\xaaO\x95B~>?\xf6\x9f\xec\xa4\xc8\xb0\x12#H\x84\xec\xd4\x9a\xca\xe1\xf0\x13\x12\xcch\x15\xfc\xf7\xd3'\xb8\xf2\xc3itU\xa5/\xbe>\xb272\x12&_&}\x00\x7f\xc81\xcd\x9f\x16\xaeS\xdds4\xc4~\x816\xc8\x06\xf0\x00\xf2\x9a I\xdf\xf9K\x12eiK)'$W\x10\xd9>;\xc0\x8a\xaf1\x1cB\xc1\xff\xb8\x80\x03\xe0\x85\x15\xb5\x05\xf6\xfb2LI\xbc\xf6\x82[v,>\xd7\xf7,J5]\xcb#C\xfdK\xe9\x83F\xf1\x873\xf9\xa8\x88\xad&\x96\x8fJ\xda\xd2\x98\xcc\x94\xec/\xec\x8d<_\xe5#l\xb7 $\xa55f\x10\x89\xdd\x1c\x0f4s&a\x1c\x05A\x1b\xfd\x90\x0c\x1d;\xa5\xcd\x05\x84\xff\xf9r\x8a\xd2\x87\xfc\xaa\x8a_\xb4\xb7,\xd4\xf4w'\x9d\xa9\xd6p\xb4\xb7s\x84\xf3\xe1$\xf5\xd7\xe8'\xda\xf5\xc4\xcf\xcf\xe9\\\x7f?\xc8/R\xa5\xaa\x1a\x8dV\x91bQm\x15FPl\x99\xe6\\ri\xf7<\n\xc5\xe4\xd9\x9dD\xfe\xb7\xee\xb2G\xe3q\xe5bD\xab}G\xec\xb9\xe5\x92L}\x16\x9b\xa5\x99\x84\x95\xbfP\xb2e\xb2\x01\xa95(\x0e\xe6\xac\x8b\\\x98\xef\xbc\x0d\x87\xa0|\xa3\x1dD\xb5Ni\x18\xe5\xe2\xe2|\xb8M\xde\x9a&\xde\xd9\x14P\xcdGU\xa2\x9f\xc8Q\x88\xea\xd1S\xd8#\xe1\x8d\x82eA\x07R~\xab\x99F\xdfDW,W\x8em\xb4\xfeF\x13\"kA>Zz\xd3\x1eV\x8eq\x90\x1a*l\xd7\xd7\xf0\x92\x89\xef\xd7\xd6\xb8\xf0C/\xbe\xae\xaf\xe2%d\x7f\xb7~$\x93d\xd0Ta\xbb\xa1F:\xeb\xef\x07\xa4\xa9\xcevc\xa5\xd8\xbb2\x94\x83\xe4\x9fm\xc8+\xd9hq\x95\xfbwWwxys\x1b\xf2\xfc\xe8\x18\x19Ee+\x90\x0b\xf7\x07i\xeb\x07.(`3\xff.\xae\xa3\xf8T\x18\x9e5\\\x03\x91\xc7\x8f\x9db`u\xca\x97F\xdc\x85V\xf8+\x9e\x16\x83\x846h\x08\xadP\x11Z\xa2#\xb4EI\xf1H\xd3\xc0\xdaM3 \xbc\xd4\x0f\xfb\x8d\xbd\xd7\xee^\xf1\x88\xbey\x9bM]\xd7nwhEZ\xa0\x05\x8d\x13\x8fP\xe9\x98\x87\xd5\xb8'A8X\xd4\x87\xd8\x12\x0f\xa5\xd96'\xdaez\xcdbQl\xf5\xb4\x9f\xeb4\x84\xba{I\xbc/\x13\xd12\xb6\xca\xc1\xc5\xed\xd213\x1a\xf1X\x85,\xbdQ\xd5'\xc4z\x1f^\x86\xd1U\x08\x82\n\x0c\x81\x0d\xdb\xa8\xc7`\x07l\x99\x12\x15a\x1d\xf2\xb8t:\x8e\xab\x05\xdac#)\xf9(\x92\xc6\xb06)\xe74a\xa0\xd3Dh\x04\xb3\x89k#\xa9\xc0\x0ef~\x10|\xe3\xa1\x96\xce\xbb}/\xb5X-\xcfkV\x9aW\xc0z\xdc\xd9\xa8\xc7Z\x84\x95U\x98\xcc\xfek\x04+\x96f\xdc\x96:^\x98$g\x10\xe3\x0d\xbc$}MP\xce\x16\x81\x11\xe9\xabwQ\x8a\x82\x92\xfc\xeeh\xe11\x8f:\xd9\x1b\xb0\xa4\x0c\xcc\x7f\xe6gUV\x13\xd6\xfa\xc9\x08\xfa\x83\x07\"c\x03<}\n{0\x1a\xc1>\x1c\xc0@\xbc\xd9\xa5o\xfa\xbbp\x00;\xe2\xd5\x0e}\xb5\xd3\x83\x03\xd8\x15\xaf\xf6\xe9\xab\x01\x1c\xc0v\x1f\x86\xb0=\xa8\x1d\x92g8>\x852\xb0\x98\xfev\x19DU!\x7f\x13\x07h\xb4;\x19<\xa4{\xd9\xee?\x1a\xc0=L\x0f\xebH\xb6L\xe5\xa5\xb0\xfe\x9f\xff\xeb\xff4PY\xf40*\xaas{A\xc91\xac_w\xb4\xea\x06\xd27\x0d\xa4_;\x10\xd0\x0df\xa0\x0c\x06\xffV;\x1c\x98:\x1c\xf0\x0e\xdb\x13O\xae\x0f}\xacC2I\x90\x08\xd1\xbd~\xa8`\xfd\x13\xc9\xd7\x0c\xa3y\xa1Wf \xe5qY\xe5}@?t\x94}\x91\xa7l+\xf3[nuS\xb1\xa8`\xb5\x1d\x89\xcb4y?\xe7#\xde\x96\x02\xa0\xd5\xef\xbdD\xab\x01\xa0\xebe\xa7\x85'\x10q0!\xf9\x08\x1dWjt\xf2\xc5\x0cs\xf2n\xb6\"\xa9\x0f\x03\x80\x97\x91\x93\x85\x17\x1fESr\x98\xda\x92\x07\xac\x1aWZ<\xb4\xd1\x98J\xdd{{\x83G\xfb\x80f\xf9OF\xb0\xb7\xbf\xd3\x7fT2\xf8Rp\xa9B\xd0v\x95\x85\xe3)\x9a\xc7\x12D\x06gj\x9d~\xa5N\xff\xcc\x85\xb0pS\xd7\xe6\xd9\xae\xbc\xd1\x9bxh\x89\xa32\x93\xbef&\x83\xe6\x99\xf41\xe5\x85v\xe1\n4C\xa8\xd7\"R]\xaa:\x90\xef\xc3\x0f\xa4\x03\x89]~X\n\xe5@jQ\xdaH\x0d\xf7@fr\\\xc3\xbdtL\x9bS\x82@\xaf\x1a\x0eL\xb7\x12\xa4\x1623\xed\x16\x13\xe3\xafl\xb3\x1d-\x91\xeaq_\x93\x83\xd2ZqV\x83\xbb\x9d\xd9*F\xec\xc06\xde\x94\xa8X\xb1#\xec\xd1B\xb1\x1a\xb5\xf8Qj\xfa\xb3\xf6\x83\xe3\x1a\x86_\xc2\xb4\xb0\x81f\x05w\x87j\xda\xadtP\x8b\x1d\xf9\xa0{.\x02X\xc1\xd4a\x036\xac\xcc\xcc\x8e\xe1|\xa8\x07\xc6\xa2\x86yj\x82\x85\xd4\xb0\xf8E\xca\xd1\xdcX\xc6\xc7\xa8d\x1b\xe4\xa7\xf5\xc2\x7faq\x9b\x9fA\xb9`\xa8\x80\x1f\x97\xcdU\xdd\x9e[\xed\x7f\xbfHB\x87\x9e\x989k&\x98x&\xe7\x18:\x06\xd9\xba\xf12u\xbd\x84\x02>\x1e}\xae\x9a\xdeJ4\xb2\xbd\x8d\x83\xa1\xab\xb7=`bv\xdd\xc0\x90\xb1\x92F\xe6\xb4\x1e\xc3\xe0\xf7\x1f\x03o\x0bC\xef\x8cD\xca\xbc\xf2\xa8v\xf4\xa3\x12\x9d\x97\xb7\x8f\xd9\xb0\x98\xe9 \xcb[\xbeJ\x15E\xb8~\xf5\xeb\xca\xf9\x16V\xa9\x8c\x1c\x9e\x01\xb6\xc1\x0e+\x94[\xbf1\xb4,x\x8f\xf9M\xeb\x86FKL\x1bFR/\xd4S\xcf\xf2v|\xa2!\xa4\xfaq\xd5\xf3Bw*\xa0(+p\xeb\xe1\x14bLy\xd2\x92\x04\xa3\x9cR\xb7\xba\x99)e?/^\x17\x176\x035y\x1f\xcfq\xae\xcf\xcb\xac\xd1\xae#\n#\x04J\xd9T\xca9\x13\xa2j\xda\xf0\x92\xc9}n\x8b\x91\xc6^\x98\xcc\xa2x\xc9\x8c1tn1\x18\x17\xfc\x9d\xa8\xd7\xc2r\nT\xaeY\xe9E/T\x85\xdd\xbcV\xbd\x1fG!\xb5\xe1y3\xb90\x0bi[qY\x1c3\x06\x0e`\xcc\x06\x85\xd0\x857\xb9\x14qj\x96Y\x90\xfa\xab\x80@\xea/Ib\x8cw/\x06\xb2\xc8\xc2\xcb\xdcG%\x1f]\xf1\x86\xa7\xec*L\xadx\x1aWW\x93O[<\xe2\x80apl\xe1}\xe0+\x86;\xb6_ k.\xecc\xe1 \xf8\x9a\xa8\x1bEW\xb6Z\\\xe9\xf1\xa6\xb0\x01\xd58\xdd\xd1\x8e%\xc4\xd1\xd9H\xcak\xae\xaf\xc1\xc1\xc8\x82]\x98\x8a)\xe8kk\x14\xdafZ\xa9|\\\xe8\xad\x97t\x0154\xd5\xa4P\x1e\xb5\x89E\xf2\x89J\x06O\xc5\xbb\x91\\\xc3\x9cgd\x16d\xc9Bj\x80\xfd=\x12%\xc2\xe4\x1e\x0d\xb6W1\xc9\x1d\xf5\xb2&\xbd\xa8\x8e\x9d\x12\xbe\x18e<\xd3\x8fL\x1a\xcd\x81\xfcW)g\x9a\x96\x19\xf3r\xdaZ^\x14\xcaDz\x9c\\\x15\xfb\xa7~\x1e\x9e\x89\xeb+\xdd\xa4hLH\xabLB)\xb1`Z\xc4\xba\xaf\x84 \x10\xe7e\xe5\x9e\xe3\xc8\x0b\x02\xba\x0d\x8bE\x9eF!\x81\xab\x05 \xe1*\xcf\xa8\xb45\x82\x9e\xa5\xe9?U\x89f\x89:n\xd8]\x92\xfaAP\xdajj\x979d4\xbe\x00\x85\xcc\xe6W\xf2\xaa\xb9\xd2;;b\xdcJ\xb4adw\x99@\xab\x93.Q\x90\xdc\xe9\xa9\xdc~\xc5\x97\xac\x18yy0\xa5\xfd\xd6$(T\x00\\|m\x080c\xec\xb6*\xc9\xea\xbb,{\x9a\xd5\x9d\x99(\x9b\xc8\x07\x0c\x85J\xe9\x10J\xf37\xd2m;qa+V\x10I/\x1e\xb5>r\xecXY#<_\xbe\xd0\x89sc\x04\xb1\xeaYP\x7f\xa9R\x0b\xdb\xdc\xe7\x84\xc8\x10\xc5[\x04\x01p\x16B\xb8\xc4\xae`\x0c&\x95\x81\xe9U\xb8,[n\xd4\x15M\x16\xfc/\xe9\x96\xb9-f@\\\xdd\x06=#$Z\xe6i\x90\xf93\x95Q\xac\xb6\xa6l\xb1z{\x0c\x96{=\xe4D\x969\x90\xab\xc4]!.\xb7b\xb5%\x9eZ\x97\x89\x17sH\xcaBQ\x14\x1f{\x93E\xb9\xa2\x94\xe2|\x12\x93\x12.\xb4K\x8b+\xf0*bDSKU\xb9\x0din3\xda\x04@Lgz\xef\xde\x06\x8c\xb6\x9e\x15DK\x97\x10\xbd\xd9\x1c \x18\x04\x10\xd2qxV\xa9|c\xf3\xb4\xb8\x18\xc9X]+\xb7\xa4h\x84\xdb.\x97\x16\x9e\x0e\xfc\xfd3\x9a\x940`\xc7iZ93\xcd\xf5\xf5\xab\x96\xbc\xf6^\xdb\x98X\x16\x95\x18\x84\xa9/\xf0\xe2\xee\xde=\xae\xad\xd8\xc6\xc4\x0c>\x86\xb6\x1e\xe6\x8e\x95x#\xd4\x9c\x1d\xb9\xd5\x1c\xcb\xfe7\xbb\x0f\x06\x8eM\x87\xc4\x91\xd6K\x12\x7f\x1e\xc2\x10\x8bv>\xd7\xa2\xd0\x05\xdf\xc5Tr.x.\xcf\xe6:P\x13\xa4N\x9aH\x0b\xe8\xee+\xe8#\xe7\xcc\x8f\xaf\x95\xaf\xf4\xaeY\x13\x17x\x08@\xad\x07\xd6$\ng\xfe<\xab\xc9$.\x985\xbdl\xd1\xe4\xc1\xb5\xf6\x82\x8c\x0cA1\x02\x96\xd6\x15&^n>V\x9cN\xec\xcec\"]\xe5\xc6\x15\xc9\xba~\xe8\xe6a\x97\x87\\\x8c\x84\xc55\xd4B\xd1\xdd8\xa12\xa5h J\xa6\xb9*k\xc4s\x06\xa60\xa4\x87>B\x86\xb1\x14\xe8\xa7U\xacR,_\xaa\xe0m\x11\xcfn\xfc\xe8\xa1\xe3b:\xd4\xf1\x19\xcbl\xdd@U]\x9d\x02\x9cr>\xde8=\xcb\x99y\xfaG\xb9\n\x92=\x82\xfd<\x86t{\xfb\xb1#|\\-\xcf\x82\x0e\xd8\x9dN\xe8\x14\x1a\xa8\x9d}U\xae\x97\xf4(\xc2i\xc2\xb6f!K\x98\x8bE\xb9\xc4a\xd3\x06 \x0fq\xef\x82\xe5@\x87\xfe\xef\xef\xa2\x8dY(\xbc5\xf1\xec,\xdc\x06\x1e\xc3\xcd\xe32\xcb\xd8z\x8d4\x14\x1f\xe5\x1b\xc3\x9a\x15b\x8f\xc2\xe7\xe0\xa9E\x9c\x8a\xea\xa1\xba7\xe9\x93\xd9\xe8\nU\xde z\xf4\x07\xdd\xed\xf2\xcd\xe7\x12'&r\xe8\xb2\xad\xeb\x91\xbeTM:\xe7\xe7$}s\x15\x8aj\xcfI2\x89\xfdU\x1a)\xf6\xd3\x99\xe9\x83\xd7\xdeR\x0dh\xe2\x99\xea\x9e^//\xa2 iq2i\xd7\x98\x91`~4\xc76Q\xf1\x14\xe5D\xb9\x06\x86\x18\xc8\xec\xc4\x11\xccN!~kC\x0d\xeaW\x1a\x9b\xb6\x99\x87M\xc4\xc2\x14j\x14?\xf2\xd2k\x9b@\xee\xb2\xfa]\x19\x81L\xaa\x0e\x0f0\x82\xdb\x7fY3\x91\xed{r ]/g\xffS\xb9\x95\xcf\xdc\x15}\x1d\xff\x1b\xda\x0fUUs\xa4w\x03\xa3\xdc\xe9mq\x94\x9ek\x9a,xt\xfb\xe4\xc4n<8\xd3B!Fj\x85\x0b$w\xc4\xd8\x10O\xb7\x1a\xe18>C\x07'\xe1H\x91\xa1<\"\xbe\xa8\xacH\xd8\x00g\xb9\x8fv\xfc>\x1f\xfa\xd6\x16W\xf6\xb1\xf0\x03\xe5\x14r\x9f>\x19\xb4d\xc8\xd5\x9b\xf4\x83\x0b\xd24\xdaVX\xa1\xe7\xa3\x88\x0b\xd6\xf99I^E\xd3\x0c\x0dN\xd4\xa5D>G\x16+Yt!/N\xc8\xf7\xde28BnE\x93\x16\x7f]D\x88\x0e\xed\xbdAO\x83q\xc8\xfc\xb0\x80\x0dq\xb7\x18\x04\x1c@\x0cC\xcd\"\x0bSS5\\p\xd1\xa9n`\xb5\xa8\xaa'\x0f|-#\x91\xe3\xaf\x9bx3\xf2M\xe4M+ \xacjID\xce3\xb1\xd0\xc8q|\x88\x03I\xba!\xb9zG\x89@x\x1c\xc7v\xa1IB*\xad\x1c\x97\x1bz\x916\x11\x84\x9d\x87\x06q\x88\x8e\"\xb6\xcbs\xf0\xc3I\x90M\xc9\x10\xc6\xa1=\xe8\xed8g\x12\x12\xfcC\x07\xd3\x1f\x0c\x9c3\x85\xb0-W\x81?\xf1S,\xdf\x1b<\xc0P\x06{\x83\x87\xfc\xdfG\xec\xdf\x9d\xde\x1dM\xe2N7S\x10y\xcc[\x99t\xdf\xbd\xf9\xea\xabo\x8e\xcf\x8f\xde\xbc~\xf1\xf2\xabS|\xf5\xfe\xed\xf3\xc3w\xf2\xab\xda\x9d6\xe8\xed\xfdN;-[M\xbd\xaa\xf6\xd2@\x165\x07\xf3\xf5\x8a\x0c!\xab\x9e\x10+\xef\x9a\x02d\x08v\xcf-\xb6\xa0c\xff\xfdF\xd5\xe2\x02(\x9a?\xd2M\xa3\xf9<\xa87\x0ej\x18\x91&\xabJ>\xa2\xd4\xd4uy12\xfd\xbaYL\xb2K\xce\x19\xe4\xac*\xaf\xa8Y\xff\xfc#63K^\x81\x1cod\xad\x89n\xaeU\xad\n|\x1eA!2\x12\x8dJ\x0ef%l\xec\xef\xa9\x0c\xc8\x97\xc2F^\xa7\x85b'\xa7\xca~\xc8\xe2:\x94\xd1\x8c}U\x1d\x04\xdf\xbca\x83\xae@\xa3i\xd8H\x17\xa1\x18\xac\xa0\xa9\x16\x8b\xde\x19\xba\x9br\x87\x94\x1a\x10\xf9\x1c\x18\xdeQy\xa1\x8f\xb7\">\xdd\xd1\xd6%\xb9N\x90\x91&\xdc\xa3\xc2\xc2\x1d\\\xbc\xc3\xe47C\x16\x14w\x1c\x9e\x9d\x95t.\xa22\xdeZ\x1e\ny\x05%\x0c\x0e\xe9\xd8f]\xa0\x91\x86T\x1d\xc3\xd0\xa7\xb1O\xff\xd2\xe2O\xa3haT}7~\xb9\xd1\x01\xcc \x9a&\x18\xde4\n))\xda2\x1ew\xb7\x1c\x9d:4\xbf\x1cJyK\x96\x87\x98\x90\xfc\xeezE8o\x0c\x1d\xb0\xc4\xed\xaa\x977\xbae\xba\xafn\x18\xec\x86\x9b\xf8\x91~\x0f\xef\xedj\xb7\xf0#\x95\x05\xcbP\x18.\x1a\x0e\xed\xc1\xbecg\x94\xf2\xec;\xb6\xe5\xa7$\xf6\xd2(\xa6\xe8\xd3t\x94\xa7r\xf0\xb2\x1b\xa7F;\xa8\xbb\xba.h&\x8c \xa6#\xa8\xe2EH>\xa6t\x13i\x12\x91\xd3\xdd\x80m\xe3b\xbc\xcc\x87\xbd\x19\xb0%\xf5\x84\n?N\x1a\x1fh\xc1\xba\xdb3\x93\xc0=\xe9\xea\xa3\xc4\x94\xfb$i\xca%\xe8W\x14\x9dEf-\x17\xd7.B}\x04\xe5\xd02N\x81\x98\x06\xae\xf7\x18\x85\xbd\x07;\xbb;\xbc\x7fV\x1f;\xa2\xc8\x82\xce\xdf\xf4-\xf3\xc2L\\\xecd@\xcb2\xd8\xe6\xcdt\xe88\xb7\xf9\xa0\x9e<\x81~\xcf\x81\x0e\xec\xef\xed\xed\xec\xdf\xcd\xa6\xaf\x1c\xa9\xfc\xe0\x18\xf4\x8dg\xea\xc0\xe9\xceI*\x0e\xf9\xe6[Y\xa4\xf3\xeaIjd\xf1H\x03\x8b\x87<\xd1E@L\x0c^l\x13n{\xe4\xdcz'\xf6w\xf4\xd7#\nOV\xa10(\xa4\xb5\x03\xdb+\x92.\xa2z\x034\xc9\x8dl\x0b\xa3\xcd\x0b\x9a:\xf6\xcf0\xc0\xc5\xd8\xfa\x97\x7f\xc9\x87\x83\xaf\xa21\xa5Ng\x9b\xcd\x9b\xae\xf6\x0eJ\xbb\xfd\x1d&\xf5\x0evv\xf9\xbfLM:\xd8ej\xd2\xc1^\xaf\"\x0e\xf7\x1f9B\x14o\xd3Y#C\xad\xc3G\x99E\xf6\xc7\xa1\xddwlK\xdc\xc6\xbf\xf3\xe6\x96s\x06#\xb0~\xc1L\x8d\x1d\xba\xcf\xb7F`\x8d\xd9E\x0b\xfcrf1\x1d\xc1N\xcf\xe1VK\xa5\xe8\xbd\xa2\xa1\xba\xb0\xdd\x1c\xf2y\x9b\x16t\xe89\x80\x01L;`\x9d\x95\x9c\xe3\xb6\xda\xe9\x07d0n\x85\xf6\xee\x80%G\n\xed\xdd\x1d\xc7\x1cx\x8d\x8f\xe4\x01\x9d\xa2^\xd7\x1c\xda\x8f\x1e9\xb65\xf5\xd7Tl\xb0<\xad\x19\xccF\x81\x86\x1fT\n\xd5\x9b\xcc\xaeW\x00\xa0\xd5\xe4%]\xbf\x89\xd0\xd4\xb3\xe6\xe8\xaa\x81'\xb1\xdeV\x813\xe9~\x95\xea\x10\xd3\x95\x9a]\x8e\x13\xc0\x96#\xe6\xb1\xc7\x05I)|\xd1j\xe9\x99\xda(\xca\xd4of\x9b\xb7\xb9\xf5e\x86\xab\x92X\xeb\xc8\x0b\xff\x94\xc2$\n\xd7$N\x81\xa3y\x1a\xc1*\xf6\x97>\x06+\xc4)l*\xd25m\xf7\x81\xe1\xfc\xe9\xef\xe8%\xe8~O\xe5_\xaa\"t\xff\x01\x17\xa1\xfb\xff\xaaE\xe8\x87\x86\x83]}\xcf\x01\xbb\xab\x03,\x05x\xcf\xb1\xad\x97\xc7\xe7oO\xde\xbc{\xa3\x1ez\x9e\xaa\x9e*\x17\xab\xda\xab\n\x15U\xba/F\x8c>?\xf9\xe1>/b9FxXV&\x1e\xa7\xdd\x17\x8f!F\x8b\xb3) HJ\xe4\xac7\xe3h\x1c\x9fir\xa6\n.W\x8d\xed\xaa\xa7\xa3%c\xe5rP\xc7v\xa6b\xbc\xbb\xdc\xca\x1d\xefF<\x05\xdd\xd1\x80\x1b\xd8\x0d\xad\xe7B\xb9\x98{\xe3\x8c3\xb4'\xc6\xec\x93hzVX\xc0\x8c$}\xac\xcf\xb2\x19\xdf\x16\xf1\xf7\x0c\x14\xc5\x80\xf75\x1c\x1b=\x92\xff5(\x8f\xf6\xf4\xa4b_wEG\x99\xc2\xbeco\xb5\xa3\x16\xb78\xd99\x80<.5T\xe9\x00\x82\xa8\xfaz\xc2\xcc7\xab\x10Gsv\xcfaJ\xa2\x8c\x19Z{\x08\x8b{\xf7`\"\xfc\xb44\x1f>\x96\xa3@\xe1j\xe0w\x94,\xe0Z\xb0d!\xff.\xb2'\xd8\xda\xa7OEk\xfa\x05\x9a\xdcv\x81vM<\x12\xb7\xe3\xb3~\xb1\x1c\xba\xe1\x90\x01|\x99\x1c\xe7\xf7\x8ev\xaf\xc0\xe0\x12\xc2\x9a\x18\\\xce\nS.#f\x96\xec)&\x10Km\xcb\xa2\xfb6\xb7\xfa\xbf\xedT*H\xc5pmWg\x9c@ \xb6I\xb5\xdb8\x95\x92^\xe2\xdf\xf4\x94\xff\x15\xe9)\x0d\xe4j\xb0\xa3\xfa\x1dD-8\x18\xc9j7?\xb1j\xcf\xd19I\xdf\x8a\x8aof\xf5A\x92s\x90pZF\xf7\x94\x0b\x11n\xabqt\x06C\x93i\xdf$\n\x934\xce&i\xc4r\xe3\x83\xe4\xb7_.=(\xff-\x1d\xbb\xc3\xf2g\x9c\x08\x1c@\x06\x8aG\xf3\x86\xe0\xef\xdfzK\xcaV\xc7\x9b\xf5\x9e\x1f\x9d\xc2w\x07\xfdH\xf3\x03\xdc\x15\xda\x97\x9e\xe3\xf2\x93h\x8f\x1f\xad(\x0e\x08\xcf\x94\xdd]\xc7\xc5\xfdLe\x03\x177\xed\xa4,\"\x04\xecUI\xb9\xc0\xf2\x82'\xe2~wQq\xcc8:==\xc9XN\xbe\xaa\x19\xc7\xd1\xe9\xe9)eH\x9f\x93I\xe0\xc5\x1e\x9da\xd5E\xe3\xe8\xf4\xf4\x03\x15\xafx\x13ji\xe0\x930=!\x93T_\xfe\xfc\xcd\xab\xdaB6\x17c\xf1\xbb\xe8\x92\x84\xfa\xc1?\xf7R\x8fy\x11\x92\xf8eJ\x96\xfa6^\xf8\x81a\xe4\x7f~\xf7\xea\x9b\xc3 8\x8a\x82\x80L\xf4S\xa7U\x9a\xca_D\xf1\x92k\xbb\xf5\x15N \xfd\xdeX\xe5\x15\x99\xfa\x9e~\x86\xaf\xfc%\xa1b0.n\xf5\xcb\xd7\xde\x92L_GS\xf2\xca[iJ\xa3\xa9a\xd5\xdfz>]\xb1\x9f3\x92\x18\xd6\xe5m\x90\xcd}\xcd|\xd9{\xc3pN?|\xf5\x0d\x1eC\xfa6O?|\xf5:[^\x90\xd8X\xfc\xd6K\x17\xa7\xc4\x80\x0b\xb4<\xf2C\xc3\x80O?|U\x87H\xa7\x1f\xbe\xca\xfdM\x0d5\xa2,\x9e\x10\x16z\xdeP\x83n\x94\xd3\x05!\xa9\x1e\xaa\xef\xc8\xc7\xf4]\xecM.\x8fL[%\xafa(\x8e\xb2I\x0e\xbb\xbc\xe4\x86\xa5\x0b\xf7m\x0cY\xc98\xf05<\x81\xa9\x904a\xdd\xe9\xe8\xf8\xd4k\x17\xe60\x82\xe9x\xad\x18\x9d\xd2g #X\x8c\xe7\x9a\x92sd\xe7u%\x170\x82sJ\xf1\xcfu\xa7\x11\xf0c\x18\xdd\x89\xed\x0bz\xf6~\xfa\x04\x9e}\xe1\xc2\xcc\x85\x95\xe3\xc2\xc58(\xde\x05,\x07s2\x9e\x9f\xb1\xe8\xbaK\x8d/\x03R\xd6kz\xa2\xc7\x0e\\\x8c\xaf\x99\x1a\x99~~\xedB<\xbe>+\xf4\x99\xd0\x96Z7*}\xb4>9\xf4\xbd\xe1~_\xd5\x05e\x82\x954In\xfd\x9d\x07\xfff\xf9\xf4_\x8e\xe5\x93\x99\xd7pl+\x0b\x93I\xb4\xa2\xd2L\xa22o\x1a\xa7m \xdf\x84f\x01\xfcq|\xc6\xae\x00\xfa\x0f\x1c\xdbG\xef\x8f\xbf\x9b\xf5{\x15I~\x1c\x9f\x8d\xd33\xc5\x89^;\x11\x93~\xbf\x16\xf5\xf8\xa2\xea\xc4\x93\xbb5\xc4j\xbfMe\xb7^\xbe\xa1T\xa6;\x11lV\xe9-c\xae\xf6U\xab\xa8\x19\xbe\xae\xdc\xed\x04\x8ckS\xde\xae\xd8[U\xc3\xb0`M\xab\xaf\xa7\x9ct\xa8\xd6\x91k\xf6~W\x1d\xca5\x17,\xd5^\xe7\xfc\xfd\xae\xd3M\x88\xb2e\x97\xbc\xad=\xc7V\xbe:\xe7,\xb1*\xd5^\xf0\xd6T\xf8\\\xf1\xf7*\x01\xfc\x88\x1cf\xae\x8fW\x8eE\x91\x0c{B\x12\xc5\x91\xf0\x18\x8b\xf8\xfd[\xb9\xe8\x10F`\xf1\x8fp\x87\xcf\xecS\xa5\xd77\xf5\xea\xdb\x9f0\x92\xde\x08\xce\xbb\xb3r\x01\xa5\x84[[\xf5\xaa]\xb3\x7f\x9d\xa0\x8e\xc7\xdd\x98$Q\xb0&\xb6\xba\xa6\xf2CX ZY\xe6\x19\xd1\xdd\xcb\xaf\x01\x93\x15\x99 a9\xab\xdd\xc3\xea\x93\xdao\\xc\x96v5\xd9\xfaA\xb2\x0394zl\xf1\xa58!?1\x86\x163_\x8a\xac8\x0b\x12\xdao\x1cY*\xab\x8a\xe55\x1e\xb27*\xf6\xbdl\x9c\xf3\xba\x9aX\x05\xa4s\xc4\xde\xc2\x98\xaf\xe5\xc9\xe4w\xf1,p)\x0e\xdb\xc1)\xa8\x89\xb4J\x7f\xbej\xa2s \xae\xb4\xd2\xee\xb9Q B\xcb\x14\xc7\x01\xf9Y\xe7\xe1\xbc\xcf'\xfa\x1a\xcb\xe6\xa4U\xa0J\x94i\xf7|\xcd\xe4\xc9>.e\xf7\x1c\x00\xe9F\x97\x18\x94e\xe6\xf9\x9ahc\xea\x93\xe0\xc5\x03\xdf\x1b\xcd\xd5'\xbc:E\xb8\xe6\xda3\xac=\x8d\x96\x9e\xdf\x94 \xc4\xb8\x81\xe5\xc7c\xc1.>}b19)\xec0\xdc\xd8[\xc6E\xd1\xbfF\x18\xa4t\x8b)\xf9=d=Fh\xedoc\x0e\xadY\x97\x84)\x89m~\x81\xe0\xd91\x8a\xe6\x94\xc5\x9du\xc9G?\xb5\xb9P\xbf\xd5sX\x1d\x8c\xb4\xb3\xe2\xe6\xff\x070\xb1?\xda\x16\xdfw\xdb\x93\x85\xe7\x870\xb9\x9e\x04\xc4b\xa1\xea\xe9:\xbe\xb4)\x06\x1f\x087\xd0\xd0\x85\xc4\x85 -N\xb0d\x08\x13;6S\x03P\xf7e#Xp\xfc[\x19\x9f\x1f\x9f\xc4\xc4\x94f[<75\xf4\x08\xc2B\x19\x1d=v \xb3\xc3q\xd4\xe9\xe8\"\xc8\x8a\x87n\x12\x1e\xe1&p\xd4p\xad\x9a\xde\xde6\xf6\xb6)\xfe\xea\xb1QF\xac\x1c\xe8\x7ff\xaba \x9c\"\x1c\xa7\xf2\n|\xb9\xd8)\\\x83Rm\xd0I\xa0\x12\xddS\xad\xb7~\xedJ\x9d4\xc2n-\x05S\xab\xc2\x85t\xcf1S\xb4\x8d?X\x184\x84\x01\xe9\x9e_\xd1\x02\xe2t\xcf\xd7,F\x1d\xe9\x9e',{\x04\xe1+l\x13\x86y\xa4{>\xe1\xc6\x94\xf4\xa0xe\x13\xd4]\xd4\x8e\xfcu\xbb\x91\xbb\x86\xc8g X\x9a\xb0{\xae\x0d\x05\x0f\x18\xec5\x9f\x14\xde\x90\xf39\x19\x8e\xdf\xfac\x17\x03M\xb2\x00\xf6bc\x15\x87\x1fL\xd0\x88\xe7\x82\xeefd\x1e\xa6\xe0\xa7 f\xaa\xa9\xa4\xfc \x9c_\xa2%\xd5A[\xe6 $!\xbd\xf9,<\xbf\xd2zGV\xaaM\x87\xba\x84\x82\xf2c\xe0\xca\xc5\xd3\x8ec\x11\xe6\xa1\xf4<~\x8d\x07L\x1f\xcf\xe6\x13\xfe\xfb.\xd9\x80\x93\"\xf3\xed\xadO~g\x88y\xc39\xfa\x87\x0c\xfd\xfb\x14\xbfC\x17\xb6L\xe3m7N>\xbe\xfa\x89\xb4X\xbf\x86\xb5\xbb1\xce\xbf:o\x85\xc9(V\xfc\x12\xf7\xfaq\xed\x86\x9d\xf2\xa8I\xc7.\x88Ma\xb9`\x9d/,\xc7\xc5t\x14\xae\x1c\xd5\xbaU\x14\xa3\xd4F4a\xed\xe6\x98\"\xfeT\x88K-\xd0O\xca\xf1\xb4\xcb_\xe6\x7f\xdd\xb8\xec\x107O\x92\xa9\xf9r\xce\x0e\xff\x92O^\xf6&\x91U\x97\xe5l\xe5\xebJ\xe5\x85\\\x991\x8a\xc5\x80\x9c\xb2-\x8f=\xd8\xddw\xecc\xd9\x86V\x1d\x1f [\xc4\xfc\x16\xa2\xdcO\xb6\x88uu\xac\x0b\x97-\xac\x8f\xa8\x0c5\xd2\x8a\xa9\xec\xca\x19\xf7\x06\x15\xb0\xca\xb5F\xe5\xd4\x83\x94\x92s\xe9\x07\xd9\x18z\x16\xf3?\x87\nL&R\x08_\x0e\xe3<\xf0\xa8\xa7\x96a*\xdfW|\x1e\x98\xb8>\x14\x12Jy\x9d\xcb\xfb\x08\xd1\xa5\xce.\x03\xca\xd6\x89L\x85\x90\x8f\xd3\x88C\x8e\x12.\xcd\xa4\xa0\xc6x\x1a\x8f\xab\xd8%\xb8\xc2\"];?Q\xf0z\xf45\xc6[\xc8\xb3\xf33&\x05KNx\x89\x8c\xcd\xe7]*s\xfe\xd4\xe6\x828\xc5\x93\xed\x18\x97\x13\x7ff\x94\x83\xe6\xc1\xe9Q\x8d-\x1b\x9e8.\x04v\xd0\xfd\n:\x10t\xbf\xc5\xff\xbf\x80\x7f\x86\xadK\x15!\xdf\n\xa6\xe8\xb8\xf41\xb3&\xb5eZ\xc1\xad\xdd\x1f8\xb6\xfcJD\xa3\xcb\x0d\xddY\xc7\xa7\xa5.%z\xa3\xce\x8d\x82\xa7i\x91\x05\x83\xf4\x93\x8e2\x81\xa4z\xea\xb9\xb9\xb4\xef\xb0\xe8\x9bzD\xab\xc0\xa9\x18\xae\x8dl\xd3\xd6\xa5S;j\\\xef\xa6a\xf3Q]\xd9\xf9\xe6\xc8\xd7\xed\x98'\x93i\xc0S\x05\x92\xf6%\xd3\xd4\x0fv\x1fJV\xf0\x95\xbe\x8f\xbb\xcc\xc0\xb9\x8b;\xc8~#\xa3E\xdd\xb4\xbc h\x9a\x92\xcc\xaa\xeaO=F\xb5L\xf6BxsQ\xaf\xbe\xf1y\x15\xb3\xca&j/\xa9\n::\xd6\xdc'\xcaO\xa4\xb7\x9b\x93\x1f\x8a\xe8\x86\x14\n\xf4YSZN\x8f\x91\xf6zV\xb4\xb0\x82\x11D\x9dN3\x07\x98\xd4\xa4p\x10O\xc8(/#\x81tov:n\xa1-\xa3\x18\x81$\xb2\xfd\x08\x01;\xa6\xacE\"\x98\xf4\xb1w\xc6(\xdf\xf6vFKb;l\xe2\n\x8dB3p4\x97\x9a\xd2\xd6\xbb1o\xf9\xa8\x8bG\x97oG\xddu\xdb\x83%\xf6&\x8d{\xf7\xae\x10\xdd\x8c\xc5\xfe\x06X\xbc9nUW\xbd\xd8vP\xa3\xcd\xd3\x88\xb7P\xbf\x02>[\x81\xd8\xf6\xebV@\"A\xf8\xf3V\x97\x83L\xe9\xa5N\x9dgp)\xdd\x1c\xa0\xda^\n \xc84<S l\xc4\xe5\xb6\xa6m\xef\x97m\xe2\x81\x8d\x9fIN\xb38Z\xdaQ\x83\xad\x0c;7\x07F\x90\xe8ma[[\xd6\x17\x01T\xb6\x8a\xb4\xe3\xaa\x86Y\xe8\xcf\xd5\xf7z~A\x02\x9c\x9e\xd8\xa0g\xbf\x06\xa6\x90\x1f\xb9MP\x85:\x9f\x00\xf10\x0f\x80\xb0\xba\x00\xe2\xd1\x9cj.\x0el\x83\xee3]\x1b\xa9\x1d\xd5\xdczk\xe9\xfa\x9d\xa4\xa9\x90\xc8\xa5\x9e\xcbV=\x00\"-u\xe2\xf4\xa6\xa2.\xe4~\x0e\xbb\xfb\xd2\xba\xc5v\xdc}\x0b\x1d\x88\xbb'5wJ3?\xf4\x82\xe0\xba\xad\xba=\xe3\xb7\xc4~\x1e\xc1\x9aJ\xc2\xe2\x0f\x83\xae=4\xddjk\x98\xdd\xca}q(\xab&\x8d\x96\xd7\xfc3\x8fRGT\x84\x95/R\xea\xf8\xab\xca2\xcb\x8f\xce\x9a\x8c\x8al\x94\xad\xf8\xc2\xe3\xe2 u6\x1a\x96\xf9\xae\xf2\x0b\xa2n\xc5\x7fD\x84?\xd8S\xb0\xf1\xb4\x06\x0f\xd3\xb85\x0e\xd2C0\xd5g\xe0\x86<\xd1\x97\xce\x9eV\xdcB\x87]\x82\x86\xed\xfc\xee\x7fX\\\xc68v\x88\x97$\xcd\xd7\xd2m\xe0\x19\xda\x83\xbd\x01\x8f=\xb7\xc3\xff\xdd-\xc7\xaa\xdb{\xc0\xff\xe5\xb1\xea\xf6x\xac\xba\xfd\x1e\xff\x97\x7f\xbf\xcf\xbf\xdf\xe7\xb1\xed\xf6\xf9\xf7\xfb\xfb\xfc_\xde\xce>og\x9f\xb7\xf3\x80\xb7\xf3\xa0\xcf\xff\xe5\xed=\xe0\xed=\xe0\xed=\xe0\xed=\xe0\xed=\xe0\xed=\xe0\xed=x\xa4\x8d\x9d\xc7|j\xdb\xc0\xa2\x11\x8b*\xbeNQ\x1ep\x13\x8f\xe3#\x1e\xae\xb2J\x10\xe5J\xd1\x94\xa0\x17\xb0\x82xH\x06\xd1z`\x8b\xd9\xb5\xf71\x9eJ\x1e\x16#\x8f\x1dR!\x8fr\xa3M\x08\x9a3\xb4\xdc\xe4r|\xe6\xe2\x9c\xf3\xccPy\xa4\x9c\x8c\xf9\xe9\xc6\xf0\x142\xb3v\x80g\xb9\xeb\x14\x99\xa52\x8c\xa2\xe3Sj\xd2\xef\xf7w\xfb\xfd\xbe\xc3r\xf7\x8a;\x91\x13/\x9c\xf3K\x11R\x8e-\xbe\xf6\x02\x7f\n\x93hJ`E'c2\xab\xe4w\xd4\x04\x9e\xb0H\x9dp\x80\xb1~0B,\x8b\xe4\xd9\x01\xdb&\xb0=b\xe5\x0e<}\n\xfd\x1e\xca\x14\x7f\x84~o\xb0\x0b\x1d\x16\xffS\x97|\xcc\xb4'C\x9eSP\xcd\x9c\xbb\xe1\x8ek\xc22CT -\xa52`D\xec]\xb5\xc7\x03\x16;\xa3\x1b{W\\\x10\x8d\num\x1dnP\xcc\xf1\x18\x8e\x84\xf0\x14\xbc\xc7\x0edl]x\x08Z2\xf6:\x9d3\x07\xe3D\xdc\x87\x9eF\x8a\xb0\x8e\xa2,L\x0b\xe7\xac\x90\xcc\xbd\xd4_\x13U|\xe0\xc1\xf8\"x\xaa\x1ar\xf1\xc7\x8e\xe0\xe9\xd3\xa7#\xe8;\xdc\x9b\xb53B\xc3#zb2\x07\xd7\x90\xbdz\xac\xac\xd3\xef\xa7\x84\xdb\x948\x17 \xda\x9a6aQ\xb3n\x1b\x16\xb5\x9a6\xa2\x8eD\x97\xfa\xd0\xad\x00\xe2\x88o\xe7\x84r\x93\x1d\xea\xe6\xe1DM\x99/\xe2[\x10\xd6\x18\x97\xad \xac!\x15\x92(\xec\x84E\x0b%\xac\xf1g\x11\x07\x93dBW\xc5\x0b'\x8b(\xdeH2\xa9\xe5\x06\xf9b`\xd4z+\xf4\x96\xc4\xaaK\xec\xf9\xd9\xc3\xbf\xf0\xe7\x1b\x8d\xbd\xcd\xd0Y\x9b\x16\xfe\xf7\x05G\x1e\xf8\xe1\xe5\xdd\x8f\x9d\xb7\xfa\xc5G\x1f\x05\xd3\xbb\x1f\xfc\xef0\xf0\x99\xff\x91\xdc\xfd\xc8\xd3\xf4\xf7\x18z\x14\xa6\x93(\xf8\x12\xbb\x956MG/\x9a\xff\x82;\x96v\x95\xf8\xbf\x90/7 \xde\xfa\x17\x9c\x83\x9fz\x81?I6\x9aB\x9b\x19\xf8\xbf\x03\x16mLvZ\xc1\x1e\xc9\xfd\"&\xb3/\x0b\xf8d\xe9\x05\xc1F\xa3o3x\xd1\xea\x97\x06=}}\xb9\x19\xe2\xb7\x1a\xbeh\xf6\x8b\x8f?\xbb\xb8\xfb\xc1g\xbf\x07\xd5O\xb2\xd5\x17\x18\xf9\xea\x8eF\x1e\xda\xfb;\x8em-\xbdt\xb2\xb0\\\xe8\xd7\xd7\x96\xc62\xce\xebi\x15\x9dz\x88\x88GH\x02i\xddE\xa2/+\x1aP\xcf\x90\xe7_\x0b\xc7\xc4\x9c\xdaB2\x9b\xf7\xe1@\xd8\xd81\xcf\xa8!\x9a\xb7q}n\xe8\x8c\xc9\x99P\xd8\xc7\x95X\x1f\x10n\x9a\xd5\x9f\x03\x93\xeb\x14-\x17\x06\xb7\x00g\xecV\xdd.\xa0\x15D\xa3&\x88f%\x88\xc62D\xe3\x96\x10\x95\x04\x88\x18C\x95\xf9\x08T\xf6\x86\x832rX\xe8\xa5;\x03hB\xbc\xf8\xdf\xd0\xf3\xce\xa0\xb9\n\xfcT\x8b\x9c\x15\xcbI3\x98\xc4EFh\xf7wUc=\x10z\x8f\xeakv\xb9\x867eU\x8d\x885A\xe3\x14\xcb\xbb\xb8\x98X\x92\x89mYt\x8e\x1a\xa4is\x1d\x02\x92%\x9a\xd0\x01\xe8\x03\x01@\xd9\xd7f$\\\x8bx\x12\x9d\xdc\xceMM\x86\"\x7f\xbb\xe5\xcb\xa9\xd3\x8a\xa8x8:\xfdgkf\xc2\x9f\xb80\xc1p\xd3\x01\x0b\x8b_\xe7u\xbe`\xa1;\xfdy\x18\xc5\xe4\xc8\xc3`}\x96o\xc1\x90\x1ey\xd0\xa1e\xcb,H\xfd\xc0\x0f\xb1hY*\xcaB\x1f\xaf\xda\x0f\xc0\xcaJ\x05I\xeaO.\xaf\xe9\xfbk\xfe\xde<\x84i\xbd\xd3\xfb\xba\xbc\x9a\xb4\xb3\xdd\xc1\xa3\xddG\xfb\x0f\x06\x8f\xf6\xd0\x8e\xff\xe9\xd3\xa7u\x0d`4\xd9b\xbf\xa7\xdd\x04\x83\x9c\xbb\xb0\x80\x0eXs\x93\x85\x00\xaa\xfaX\xf0\xaa\xb8\xdc\x02\xbb\xcb\xbc\xe6\xed\xd0F\xfe`\x1fl\xfd\xf0C\xe2X.,t\xd7\xd0\xf9\x83\x0e\xec\xd7\x0c\x17y\xc0\xce-\xdb\x9e`(1\xd4*C\x07\x92q\xef,\xc7\xf0\xa70E\xad\xe1\x8aG3\xe1*\xa4\xa9+>p\x1c\x17\xb6\xd0h\xbf\xa4\xe0\xc2\xc4\x1f\xbd\xb3\xfc\xe2-v\xebY\x9f\xd2\x83S\x0f0\xd0\x00\x04\xf0\xa4\xaa\xe4\xde\x86\xc1c\x08:\x1dG^\x99B\xa3\x16\xa0\x15\xaf\x8d?FZ\xe5w\xe9\xb9q\xdc\xea\xe098\x9e\x141\x15\xf1\xf2\x9f9\x00\xad\xe8\x07\x0c\x12}\x87g\x89\x90\xc0\xc6b\xc5O\\X\xe5\xad\x8e`\xed8\x8f\x1d\xb8\xee\x06^\x92\xbe\xc4\xb6\xf1>\x83\xf7s\xef\x9e\\\xa4\xc6\xf4\x16\x0f\xdf\x8cSv%S\x84\xf5\xde\x9a\xb1\x06(\xc9\xc4,<\x9f>\x01_1\x96\x93G]>:\xe8bp\xb0\x86\x03X\xf1\xb2\x9e\x0bk\xfc\xa42\x02\xc5,\x99\xb9*X=A\x1a\x85\n\xb3\xe7H\x10\xb3[Q\xb6\xf2\x99\xa9\x92+8\x80\xf1\x19\x0c\x05\x0d\xcau\xb1\xaa\x14\xa8\xd7iK,\x82\x81\xe5\xba\x05Su+>@b\xaa\xc2\x82\xa9\x8a+LU\xa8c\xaa\xe2M\xd9\x80z\xe5|f\x87\xf6\xe0a_U3\xfb\xbchg0P\x8b\"^\xb4\xd7\x7fHIL^&\xc6\x80A\xf1\xf5\\\x1a.f\xda=?'\xc9\xabh\x9a\x05\x18G\x1e\x86\x9a\xa5\x98\x92\x99\x97\x05\xe9P\xbd\x9f\xff\xa7\xea/q\xd2\x8e\xfd.\xff\xca\x85\xa8\xf8i\xa46|L\xd5\xbe'\xd1r\x15\x85\x94\x80\xe8F\x06\x98{B\xf8.}\xe3]GYJ\x17\x8fw\xd8\xb4Y\x8a H\xa8\"_Ny\xb7_S}\x8eW\xe2\x82U@\xbcr\x0b\xc2\x03\xc7\xcb\xe1\xea\x9d*\x9aLl\xca\xf9=\xd4\xa1 \x16\xed\xf5th\xc2\x8a*\xc8\x95\xe5E;j\x91\x97\x17\xed\xabEI^\xf4@>\xda\xf0\xd5\xfe\x9e\x1e\x15'\xbf?*\xcej/\x18\xf3\x91\x91:\xc1\x9f\xd2\xde\x1c\x9b\x1dN\xe8\x88\xe3bA\xa6\x16\xd8\xa4{~\x8e\xce\xe7\xe7\xe7\xc8&\xf4\xdc\x02\x1f\x1d\x9b8\x0e?\xadX\xf5\xfcxTE\x0c\x1d\x98h[\x9e\xd4\x96\x0b)\x1fFTz;\xae\xce\xe5\x92\\\x0f\xc1\x8aI8%\xb1\xe6\xa6\x94\xe3]#3\xb0\x96\xf3c\xac\xe2he\x88?\x03\"UFwN\xd2#\xb1\x85\xcduYd\xf0dE&,!P\x14\xd74\x1c\xb3\xd0\x1fq\xdc\xa2.\xdd\x13\xc4\xb6\x8e\xa20\xf5\xfc\x90T\x1cn\xe4'buO\xa2\xab\xbaZ\x99h1\xa8\xab\xe5\xb1Z\x18\xb57\xb10\x9c\xa9\xb9\xf2\x84U~\x17\xad.\xbc\xb8\xa9\xf2\x8cU~\xe6%\x9c\xde5}\x10\xb0\x0f\xa2\x90r\xeb\x1f\xbc\xc0\x9fzi\x14?\xf3\xa6s\xd2\xf4)&t\xe8\x06\x917\xf5\xc3\xf9i\xea\xa5Y\xa2F\xb2\x97\x9f\x05z/S~\x89\xdd\x9f7\xb0\xf7\x94GZP\x04\xb1\xad%I\x12oN\x90+\xb24J\x01(6A\"P\x9d;T\xf2\xdcQ\xb6o\xf2\x94\xa4\xcf$\xf0\x92\xe4\xb5\xb7$C\xb0\x92+o>'\xf1v\xe6[\xda\xfa7.L\xe0\xc0\xd8\xcf\xc4\xc5$l\x0eO\xc6\xe6\x82\xc5\xe1c!_\xb4b|\xaa\xfe[\xcc\xed\xddv\x9c~8\x8b\x8c#\xbc\x93\x1e\xf8\xc0\xb7'\xf9\xee\xf8=\xba3t\xe2`\xf8\xb7\x99\xe7\x07d\xfa\xaf\x12\x94\x8b\xdd\xd6\xbd\xa5~\x1a\x10c\x0f\xd6\x0b\x04\"\xa4\x11\xd0a\xc1\xe1\xdb\x97\x80l\x88Oi{\xd7r\xcc\x83\xf08rKkq\x84\xae\x95_dE\xcc\xe4\x013A\x9b\x18>\xf1,\xbd\x8f\xdf\xfa\xd3t1\x04\xeb\xe1\xc3\xde\xeacM{\xacz<\xf7\xc3o\xc8,\x1d\x82\xe5ei]\xffE\xfd\x13\x7f\xbeh\xf9AJ>\xa6\x87\x81?\x0f\x87`M\xd0\xdf_\xbfDP9\xdf\xf3\xb7\xff\n\xb01&\xcb(%\x85\xc7n#NZ+\xcb\xe5\xa4v\x8a\x88\xb9\xb5B\xe5_\x92MD,\x8c\x06\xcc\x9cq\xac6\xf7\x11\x89\x1eL\x15\xb2\xa6\nA\xbes\xaa:\x0dE\xea8+\x85H\xba\xb1\x8b&sNIb\xa9\x89(m\x1bl\x8a\x8a\x90;\x15\x8f\xa5\x81\xd3\xd5\xe6Am\xd3\xa2d\xdc\xa7\xcf\xff\xd6\xdf\x91\xad\x96\xa9p\xf2\xc8\xb1\xadrGV\xb3\xf4g\xe6\xd4\xa5J\xbe\x92\x86\x14\xe06\x17o\x83\x87{\x1a\xc1J\x02\x93^\x1ely\x01\x12\xabb\x9f\xa8^\x8c\xb3\xcd0\x8ba\xf5U\xeb\xce\xc2\xabk\x8b\na\x94\\\xb3qWvmy$C\\\x1d\xa7;\xdb\x10b2\x10*\xed3\x89\x8c\x02U\xbd\x8d($\xbaas\x0e\xb6\xca\"=b\x0ey\x0f\xf7\xaa\xfew\xbd}\xa7;\x93\xfd\xe8\xdb\xb4\xd8r\x12\xaa\x01\xeb\xe7Mb\xf0\x88\xbb!>\xe2n\x86|V\x83G\x0ft\x9b\xf4\xf4zy\x11\x05m\x9an\xb2\xf34\xd8\xe1\xaa;\x98\xdby\x1a\xbc\xad\x0d\xce\xd6\x03\xb5q>\xfeG}\xa7\xfb\xf5\xf1\xf7\xe5\xb2 /S>\xe1\xa9\xe5\xd4\x1eXj\xb9G\xeaxXn\xb9=\xf55\xcf-\xa7\xbc\x9d\xe6HR~\xbf\xe6\xefU4\xbd\xe6#T=\xe4\xe6\xfc\xbd:F\x9eV\xae\x82\xed\xec\xb5\x1a\xfe\x92\xa5\x94\x1b\xe83\xcaU\xb0\xed#\x9b\xa8\x1a\xfb\xee\x94\x81E\x95\xd6\x8e\xf9\x08\xd5\xea\x87|U\xd5N\xdf\xb0\xf7j\xf5\x9f\xf0u\xc5\x0d\xf5\x12Fp\xa8\xe6\x90{ #x\xa3\xbe|\x85i\xe1\x94\x97\xefP\x1ed\x18].9\xc2\x92\xbf\x9c\xbey]~\xff\x16FpD\x8f\xf2\xa3n\x82\xaaW\x7fv]\xaeqB\x05G\xdb:_\xf8\xd3) U\x11\xfc5+M\xa3\xb7\xb1\xbf\xf4\x99\xadv\xb9\xc67\xe8\x00\xa6\xcd\xb9_\xae\xf8\x9c\x92{\xdbJp\xf4\xdb1\x99\xfbI\x1a_\xab\xcd\xfd\"\xd7\xaa\xa4\xb9|\xc1J\xa3\xd5\xb6\xa1\xc2{M\x12\xf3r\x8dg\xa6\xf8\x01\xef\xca\xf5~F\x88\xfe\x955V.\xfa\x1eF\xb0\xf53F\x0e\xffY\xca\x08\xa0\xfc\xdd\x9d\xf9\xe1\xf4h\xe1\x07\xd3\xf2\xd7\xdf\x02\x8f\xf18\xa9w\x8d\xe3G\xdf\x03\xd8\x1a\xc1\xa9\xfd\xd2\xfe\xfb\x0d7\x0f\xd33\x91\xed\xe2\xb1@\xd1\xf0K\xd9\xe4\xac^0\xe0\xda\xac\x07\xc6J7N\xd7\xd3\x16V\xd9\xf2\x1bG\xad{\xe3\xc8\xd1\x0f\x0c\x8c\x00H\xa4\xf8\xd2~\xaf\xbf\x9dE\xd7\xd5) HJ\xe0\xfd\x98\x9c\xb9t\x92\xbc=\x1e8,\xc5;\x8a\xf7\xf4\xe7Kl\xa6\x12 \xf9\x06\x86\xf0\xb2\xbcd\x1fj\xb5\x9e \xd9\xd0\xff\xc2|\x0dO\xedw\x05\"\x98\x0d\xd8 K\xa5\x9bV\"|\x96\xbb\xff\x1aF\xf0\x8c\x8e\x98o\x8b\x12\xd6v\xc5\x91]\x02b\x0dBi\x1aI+\x00h\xd5R)\n\xf3\xbb\xba\x19|\xd5\x82\xd5+5<\x12\x8b\xf4\x95\xfd\"_\xc0%\x8b\xf2\x0f#\xb8\xe2\x19\x8d\xe8;Z\xe2\xdb\xbf\xe0\x9d\xdb\x01\xc6c\xc8 \x10f\xe4\xa3\xfd\x9d\xb0\xbc\x93\xe3\x93\xb31a\xb7\xa6\xe2\xf7\x88\xe7\xa8\xc0E\x0bM\x1b\xa1hr\x08\x1f\xed\x1e&\xb6\xd0a6\x0c\x8b\x0e?}b\xd8w\xe2\xc2G\xbb\x8fyv)\x7fR\xf4K\x87\xffm\x0e\x0d\xfa\xed\xcb*_\x0bU`\xfe\xa1\xcd]\xe3R\xeb8\x91;\x93\x87\xcca\xfc\x9a'\x82#th>K}\xc2\xa21\x8a|\xdf\x11<\x05\xff\xb1\x03_\xd9)\x83R<\xf61n\x00\x19\x87\xba\x10\x96b\x05\xeb&\xf0\xe7\xd6\xdb\xe9\x9b\xd2](.|\xcaRY\x19{\xde\xc2\xda\x05\x02!j\xb0\xbc\xa3[>E\xa6\x94\x19\x04\xd8[6#\xd9\x85\x0b'\xff\xf3\x17\xf1[\x94p\xecY\xf8 ]\xbc\xf4\x0c\x0b\xd5k\xd9\xf2\x14\xff\xd2f\x8d\xfc\x19s\xdc\xbd\xd0\xe0\xb5\xa0S\xf9\x90\x08\x1f\xd2\x0b\x16bY\x8f\xa7\xc2n\xe6\xd2\xae\xb1_\x11\x80\n\xab\x8dW\xb6\xca\xa7O\xca\x8e\xe2x[\x8d$sS\x07\x8e\xbf5\xae\xb8\x1a\xee\xe2\x95}\xc1\x9c\xa0c\x1e\xc1 \xe2\x11\x0c\xba\xa5\xdc\x8fl\xf4\x94\xd9b) qe(e;\xc9\x7f%,T#\x0bDa\xc6\x9b\xb8n\xfc\xdfm<~N\xc2\xd8\xf8_a\xe0\xa1\x170\x04>\xa9\x88OJ\x84\xee(&\x95=v\xc4\x9a\xe0f\xcb\xc4\xacB\x8e\xc1\xef\xc5jElJ\xbf\x8cI\xcd>\x8c\xca\xb3*\xea=\xc3\xa5\xf5l\xfb]]\x14,\xc4P\xba\x9ddB_\x0d\x99n1\x96\xb4\x88\x0f\"\xe5(\xaeDN\x17W^+\x9d\xcfX\xaf\xe43\xd6\x93\xbc:\xdd\xca\x14\x89\x94\xd3\x01\xc9\x19\xa9\xac4\xca=\x04\x9b\xf4E)K\xc4\xffOr\xd3\x87\x98\xb4\xe8/.\x15Q`\x04_a\xc4\xa1\xbd]\x07\xff:\xc6\xff\xff\x8d\xbe\xdb\xe7\xaf\xfe\x8c\x15z\x0f\xd9_\xdf\xf1\xf4\x97[\xa1\xfd\xf0!\x02\xd5\xa3\xb3\xb7t\xe2\x82\xe5\xd2\x8f\x91\xbcL\xbb\xf5\x17\xcd|\xbc\x1f\xecEIuE\xc7\x9b\xd9\x19&B\xca0\x11R\xc6T:\xcfTh3\x84\x1dJ\\\x8bl\x17\x90o\xe6\xbfRaa\xe1%/9\xfa\xbb~r\x14\x85\x13/=]\xc5\xc4\x9b\xa2\x90#\xf8/\x17\xcd\xce]n\n\xe623_\x97\x87rt\xd1x\xc8\x95\xe4(W\xac\xcb;o\xee\xca\x99\xfd\xb9\x9d\x91\xe5Z\xf4\x18H\x19\x85\xf8k\xb1E\xd2\xf4\xb1\x03\x0b\xfb\xaf\xe34-'\xbd-HP\x8a\xd9J\x16\xdd$\x8dbB\xa95o\x85\xa4E3!mfm\x93t\x1c*\xedP\x08\x9e\x96`\xc7\xf7w5\xa0Q\x14\xb7d\x15}\xfb9=\xd3:#4^<\x80\xe7tO\x0d\xd9?\xa3j\xea]\x85\xfc^\x92\xeb\x17\xcd]\xa19\xe7\xd7h\xceY\x9b\xd3\xc1\x03\xc6\x01W(\x13\x94\xc3\xed\xf8!<\xd7\xdb\xd3\xd1\x9e\x9e#\x177\x92\xe3\xbb\xd72\xf1YBNI\x9a\x92\xb8AJ\xfb^\x17I\xb2\xd2\x92\xbf\\\x05M\xf6\x05\xdf\x97\xb3\xd7\x01\x94\xf5\xba\xaen\xa1\x0d:O\xa6\x9ao\x91\xca\xaej\xe2F\x99\xf0S\x1b\x93\x96\xfd\xc1>e\x9cN\xedb\xab\xfa\xd5\xafj\x8a}\x92\x0c\xe1\x0f\xe5\ns\x92\xbe\xb9\n\xc5\xf7\xcfI2\x89\xfdUJ\xd1\xe7/u\x15_{K\xda\xd8\xdf\xea\xea\xb0m\x90\x0c\xe1\xbb\x12\x1cQ\xc1R\x06\xa6\xbd\x85\x07l\x8d\x88/\x8e\xc1wjxL!\xa6\x8d\xc3,\x08\xce0\xfe\xcd[[p\x9d\xd6\xdfo\xf8\x9b*\xec\xbd\x8a\x11\x8f\xf2 [\\\x85b:.X\x7f9}\xf3Z\xe3@\xce\xf5EM\xfb\xae\xc4\xfap\x86-=\xe3Y\xe4\x1f\xebb7P\x81\x82sd\xc5a\xef\xebSx\xf3<\xaf\x9c\x1d\xea\x9f\xb9`\x9f\xdb\x95\x94?\x9c\xc1\xffZ6\xe6\x9e\xf3j6i\xc3\x8c\x8b\xbe\xb4\xba!\x16\x1a\x08\xf9\xcc\x8au\xa6\xe3\xd2~\x89c \x03\xc0\x91\x84\x8e\x9dN\xc3\x85\xb7\xdc`\xe9\xa8\xaaz(\xa1\x95\xa4B\x18\xbfFV<\xb4\x07\xfb\x8e\xacZp\xe1u\xa9\x1eK\xc2\xf2f\x86\xd9\xe4\xde\x15\x84\x1b\xff~\xe5\xa5\x0b\x17,\xfa\x0f\xb7S\x81\xc0\xe6J\xc3\x1c\x07\xb6z\xad4\xff\xd2\x0d\xd6\x9ec[K\x92z\xba\xd0\xbb\x1a\xe5m\xa4\xd7\x9a\x8b`\xa4\x8e\xaa\xf3\xf4\xaav\xebI\xa1\xe4\xf3\x93\xe3\x8f) \x13\x9f\xca&\x9f>\xd5\x13D!\xf8\xd4R\xd7 \xa5\x9a\xa8]o\xa5\x9eK\xec\\\xddH\xd6$L\xf9p\xa20\xb1\xa9\xc0\xaf\xec\xc7rW\xf5<\x0e\xe0Q\x9c\xa2\xf7\x91I\xdaC\xb5\x9c\xbe\x90>\xfe\x10\xac7\x16t\xa0\xd3\xf1\xaa\xbc\xa4x\xae\x86j\xb0Z\xf1\xe8\xb4wu\xb0\x0b\x94\x1cR\xd5\x91}}\xfc\xbd68\xf9\xeb\xe3\xe3\xe7C\xd8\xeaWKf^\x92~M\xae[\x9c=\xa0u\xe9\xd0\xa9\xbb\xb85$s$e\x86Fr\x99u\x8a\xde\x14o\xd1\xcd\xc2\x90C\x81e\x01\xc0\xe51J\xe3y\xbd\xa44\xa0\x17\x06{\xac\xbcz\xe1\xb9b\x1d\xd7\xd4\x9d\xa9\\\x93x\xf4\x8b)x\xfcq|\xd6\xad\xe6\xce\xd7\x84p\x9b\x93\xf4[\xe2]n\x02\xf9[\x01dK\x1f\xe3\xa5\xa8M\x8c\x11\xab\xe5\xe73\xc0q\xd5\x06\x1cQ\xf8\"&\xe4\x97\xc6d\x82P4>\xa1\xc7F\xd0\xa5\xc8\x8d\xe6\x146?\xa68\x98\xe8\xef\x19rD\xed\x0c\xab[\xd3\xe4\xca\xbd\x93\x08\x19\xa4'\xc6\xfb\xa6\xe4G\xe6\x89\n\x05]\xac\xcd\xd4\x16\xb2\xc0\xba\xe5\xb5\xc2\x83\xbc\xbaB9\xf7\x90\xb9\xfc2\x94\x02\x84\xf6\x1eug,\xa1J\xef1x\x05\xf30y\xec@\x92g.\xa7\xe7\x867\x9e\xa0\x96\x04\xe5{\xe4*2=O%\x19\x89l\x06\xd0\x87\xfb\x06\x08\xb1\x08\xef~\xc2RY\xc9\x07\x90If\xb5\xb0*\x92\x9c\xd8\xbe}\xa6\xab\xca\xed'_\xe2\xbd\xea \x1a\xb1\x1b:!oV\xcf]+b\\\xbfD\x06\xaf\xfcp\x1a]Q\x88\x16\xbf\ns\x17\x95m\x86\x83\x9aB\x9b\xb5@\x05\x80\xb1\xce+\xa0\x9d\xa8\x8f\x81v\xad1\x1b)|\x8bM\x9e\xe1\x88\xf3Di\x8d\x17 \xe6\xbc7\xb9\x94\xaa!!\xcd\xf9\xe3\xc5\x10\xb9kQ\xa3\xbd\x92\xcdS8\x97\xedn\xf4\x08\xe0\xc0\xdf\x1b-\"\xfa\xbd\x07\x8emy\xc9u8y\xb9\x91\xfd\x86\xf8\x94%GA\x1dL\xab\xef\xda\xd9}<\xba[\xbb\x8f\x9d^\xaf\xc6\x08+\xf9\x0c#\xac\xaa1\x90Y\x12.\xf73\xc4q\xf51\xa7U1\x9fV0\x94\xb6\xb2J\x95}\xbd5D\xd4F\x8c\xa1T\xd6G\x12\xba\x15S\xf9\xe7\xde=4\xa3+\x07v.\x14#\x84eCe\x11\xd9\x12\x92\x82\x97@.Ml\xa9\xe1\x18\xf44\xb0\x02\xa0!h\x17\x05e1+w\xe6\xb0\xc0\x0f\xe1\xef7\xd5\xbb_m\xca\x1b\xf3\xde\xb5\xf9\"R\xd1\xe8\x05o I\x82\xcb\x0d6\xba3\xbbb\x12\x00\xd28XF2\x188\x0e\x1d\xc0\xf8\x8c\xdf\xc5(Yf\x91l\xdf\x86:\x10}f\x8a*W\xc2\xc9\x88\x0c\x0d\xa3V[(\x95Y%\x96\x0f5\x95\x1ceF\x10\xc2\x90\xe5\xc0 \xdb\xf0\x17h]\xb0\xd5wL\xfa\xf6\xc9\x82L.\x87\xd2uB\xabM\xdb\x8aN\xecT\"\xe2}.\x9d\xd8\xfdlKD\xc3!\x14s\x1bUVg\xb3\x81\xdd\x8e\xdc\x08\xc5\x1bZ*\x15\x1d\xb6\xa20M\xf6l\xbb\x06\xdb\xd3==\x97\xb8S\xb1\xf2b2\xfbN_\xb5\xf2bl\xdc\x8e\xfa:\xe1\xd5u\xe9\x89\xe9{\xb5\xf9\x19\x7f\xaf\x0e'\xe0\xcd\xab8\xba\xc2Li%+\xe2r\x85\x85T\xe1\x857I\xa3X\xb1\x85\x9a\xb2\nA\x14\xea\x1bXW\xe3@\\7\xca\xf0mn\xc4\xe7Za\x19\x8d\x87b\x12\x9aD\xfc\xa5\xb7\x1aB\xd4]z+\xbdp?\x8b\xe2co\xb2\xa0u\xf8O}\xbdI\x94\x85):\x1e\xd3\x1f\xfa:i\x84\x04\x90\xd6\xe2?\xf5\xf5\xa20\xb8\x1e\x82&\xe7Y\xb5zn\x9c=\x04\xbf[\xe3\xd3\xf66\x8bI\xa9n\xe9E\xb5~ \x03\x86\xa0\x01\x8e\xbc\xc2C\x98V+\xf8 \xfau\xe5U\xbcn\xf9\x8df\x90q\xb4\xa2\xc7j2\x04\x8d\xf7\x1c\x1b\xd2Q\xe0%\xc9\x10f\xa6r\x8e\x93C\xd0\xac\x13\xab\xf1\xca\xff\xe8\x87C\xd0\xc0\xfe\xf9\x9bWC\xc8\xaa\xef\xd7$N\xfc(\x1c\xc2\xa4Zv~\x9e\xe05\xd6\x10\xd6e\xe4\xd4S\xc8V\xa99\xea\x89\x8e\xacQ3\xf4\x12\x7f~/\x94V\xe9y\xaa\nM\xe2\x02\xb0\x81\xb2\xf5T\x0e\x96\xa5\x13M\xaf\xa2C\xae\xb6~\x1bE\x81\x9a\x8e\x14g\xd1\x9dEY\\W\x8bR\xbd\xfb?\xdc\xef\xdc\x9f\xeb\\{gFA\xc8\xb6,\xe8@\xea\x94\x82\xbd\xff\xe1\xde}K>\x8f\xaa\x0d\x06\xdas\x0d/|i\x1df\x85\x86\x7fN\xa20e\xb9\xb9H\xfe&c7\x88\xb5=\xact\x0b\x05\xd2\xb2\xa4\xd8\x93f\xb3a\x19\xefV\x91\xdb\x99l\xe7c\xc3)\x1b\x88\x9c?]7\x8e\x85\x18\x87\x86\x93\xc4\xe9\xc4$a\xde\x1fb\xc6\x97\xe4\xfamLf\xfeGi\xce\x1c(a\x05(\xf1F@\x996\x03\x85\x0d\xa7\n\x96\x0cK\xf3\xb1U+x50Md\x98j\xa8 ;\xe8(l\x13\x05\xb6\xe5\x05(\xe97\xec \x95\xb1\xd7\x14\xe3b\x84o\xd4M\x17^z\x82\x88\x99\x08d\x17\x8e\x9c\xb05b\n0\xdbW\xa8'm\x87\xbe\x9f\xa0\x9a\x08\x89\xf1a8=a\xf8\xfc5\xb9\xa6\x1dd\xd0\x01{kB\xe7\xcf,yP\xb9C\xff\xc2\xe4\xf2\xf8\xeb\x00,\x0b\x860\xb3\xf1O\x87\x8a2\xf7Qg\x1b\xa2\xe1\x10S\x05M\x9cztYK\xe8\xe2V#g\xacy\xd4\x0c\xd5\x89V\xcc\x90\xdd\x0c\xa1hf\x87b\x08U\x83\x17\xbaV\xe8\x9a\x8b\xa4`j\x13\x8c\x8c\x81\x1d\x96+\xa3\xc6\x7f\xea\x82\xe7\xb8\xb0\xe8\xc6$ ^Bl\xaf~\x0e\xd7&,\xe34\x83\x0eVj@\xfc\n\xa4\x8b\xa3)\x11\x06;u\xf6@\xa5\xad\x81\xee[\xca\xee(\xbd\xacl\x10\xba(\xdetJa\xe0\x87\xf3w\x91\x1d\x88\x89\xdej \xf9F\x96z\x95\xf7\xb2\xf4\xfa\x0e\xc7\xbcp!Q\x04\x8c*\xfb\x96\xb3^u\xa7\x98xP3J\xf1\xa9dM\xa0\xb9x\x10D#(c\x92.\xc9:\xe2\xd1\nS\x17@\x90\xe3\x91z\xdfX\xa6\x0c\xc8O~\x91\x01\xeb\"p S\x01\x9b]q\xb1U\x10\xa6\xda\x0d\xc3|\x19\xa6\xd1\xb7~\xba\xf8Z\xac\xf6\xcb0%q\xe8\x05CX+\xc7,\xe3m\x1b\xf5&B\x87G+\\s\xd7\xc3\xbaA\xe4\xfcp=\xf3/\xf4\xe4M\x00 \x02\x00z\x92Z1\x10/\xf0\xf3\x8b\xf1j\xa1\xbd\xaf\xd31\xdb\xa1M%\xaf\x86y\x0b\xc3\xc1\xae\xd0\xa0Pl\xad (\x07\x12\xac\xaa\xdf\xad\xa2\x95)\xf3\xb5\xc0=\xdc\xbd<\x12|\x15^P\xa7p \xc9\x15~_1B\xaa\xd5\xbfi\x95T\xb2\xc2\x08\x0d\x0f?}\x82\xd8\xb6\x06{h\xcb%\xd16\xdbq5\xf3\xe4w\x1cOx8\x90(\nN\xfd_\x880>V`B\x0f\xb7z\xb3\xa9\x0c\x934\x97^yZAS\xa6o-\xf6\nH\x96\xc6\x86\xebQ\x01\xda\xd2\x98\xb9\xd1kXP/\xb4\xeb\xf8\xf4 2\xfa6\x9f/3:\xce\xff\x1c\xb1\x8cp\xa1\xa0b0\xa2g\xa7\xc6\x02\xb9\xca\xe7P\xce\xa2\xc4\x83\x0fU\x80\xd0\xa7\xc2\xcf\xb7\x84\xc1m\x90\x1cd\xd8m\x82\xe8\xa0Cv\x11\xa8P\x07\x0e\xd0\xe2<\xe8\xf0\xbeb\x92\x05zp\xa6\x8b\x98T\x00\xda\xe6\xc0\x80\xcf\x84V|'\xd0\x8a\x19\xb4tG\x8cx\xda\x03\xac\xe2\xa5\x01z\x98U\xe5\xc0*\xc8\x0c:o\xf8L\xa8\xf9w\x025?\x87\x1a\xe3&\xaa\xb6\x03\xb0)\xe0*\x86O\xd5\x16\x0c\xe7\xdag\xc4\x0fk>\xd7\xfa\x05\x1f\x15?f${\x1f^\xd7\n\xb3\xe5\x05\x89\xe57\x05Ty\x17\xa4\xfb\x87?\xf0\x91\xd1wE\xfe\xf4\x99\xcd8V\xcb\xca\x93\x87y\xd0\x81 \x9dp\x0f\xc5`\xc7\x05\x8d\xc5\n\x9dqM8\xd65\x8a\x9bR\x93CLd\x93\xe8\xa1R\x96\xd0\x89\xc6\x1f\x01d+\x8bkfOq\x0dO\xf2$<\x8f\xe1\xba\xd3q`\n\x9d\x11\xa4\xf6\x8a\x9e\xc9\xe3\xeb3\x17\xd68\x97\x95\x0b\xd7\x0e_\xbd\xea\x0808\xa6\x99C\x98\xb3,\xa5\x06rC\x87?o\"bK\x17\xdd\xc0\xe7\x9c\xbb\xab\xa1\\\xd8\x1c\xbb\xe8\xec\x920\x8d}\x92\xe8\x81!\x9e\x1c(\x17\x0c([\xf6\x12Fp\x8e\xa9\xe9m\xc7\xe9N\xa3\x90<.\x01f\xc9\x0c,%\xd8\\t:f\xe8\x88\x87B\xa9y$\xc6\x01\x98\x01$\x1e:\x89\xabb|\xe6\x91\x88\x07\x0d:lifWhZ\xbbF\x03fN.\xae\xc6\xbd3\x87\"\x9e\x98kO\xcc\xb4\x1e\xac\x06[B\x86+\xb8\x91K[\xac \x01>\x1a\x92\x91\xc9\xcfi\x11+\xba\x0eCb\xdb\xda\xe9[naG\xc2n\xdd\xce\xd8HN\xe1@\xec~\xb8\xf2\xd3\x05\\\x92\xeb\x04\xfenAG\xdcg\xd3\x176qx\x9a[\x17P\xd9d\xddX0\x84S\x17>\xb65?3J\"\xd3R\xc1\x0d\xa5\xb8\x96\xa5\xf2\x1a\xadn\x1b\xeb\x8f@\xad\x8d3\xf7\xe1\xbaw\x8f\xff\xca\x1d\x8b\xabg\xa5\xf5/\xff\x92\x07\n\xd1\x9f\xd3f9)\x97\xf2\x80\xc5\xcdEg\xc3\x18\xcd\x9b\xd3\xb1\xafZ\x80\x1b-\xb2\x89\xc6\xdc\xfa\x0e S\x1e+\xdb\x08me|=\x1a[#k\x08\xd6\xa8g\xc0`k\x88\xc5\x83j\xb8\xa7\x1b\xa3\xc6\xc0\xfa\x03\xc5\xc9\xcaE\xc0\xfd\xf1hxv\x7f\xde$\x9aK\x0d\x91qzV\xed\xb7^\xa6\x0c\xef\x06(=\x9c\xb6 (\xa3\x01-\x1en\x02\x14\x06\x0e\xdb\xea\xb2\xcd\x9c\x8e{\xe8\xe8Ma\xc5\xfe\xee\x9f\xa1\x8dD\x92]0.\xc0\x1e\xd0#Z~\xd1w\x1c \x9a\xf6\xa8\xf7i4p\xee\x1e\xa0\x05\xbe\xea\xf7\xce\xdd\xdc\x80\x0d\x9c\xba\x9bn_\xaf\x07\x18R\x12Y\xb1\xe4\xc7\xa2\x8b\x8b\x98\x95^\\h\x83~z\xd3iL\x92\x84\xd5a\xbf\xb5\xd5b\xc2{\x89\x89\xbe\xa38\xf5'\x01\xe1u\xf0\xb7\xb6Z\xe2Oy%\xfaK[%\x9b\xfa\x11\xabB\x7f\xe9\xaa\\`\xf1\x85\xb6\xc8KX\xfb\xf4\x87\xb6\xc2\xd4g\xe5S__\x1c\xf1b}\xcf\xfe\x9c\x15\xfbsmq\x10M.\x7f\xce\xa2\x94\x8f!\xffS[9\x9a^\xb3j\xd1\xb4\x12P\x05+\xb0\xa5\xd3/\xdcE\x96\xa6Q\xc8*\xe0O]\xa5\x89\x17\xae=\xb6\xb8\xec\xa7\xbe\xd2*\xf5yS\xfc\xb7\xb6\x9a\xcfgE\x7fh+D|i\xe9\x0f}\x85\x80\x97kc\xc6N\xa2`\x1eG\xd9J\xd4\xc1?t\x15\xa7^\xca\x90\x91\xfe0U\x08\xfc$\xcd+\xd1?\xb4\x15\xa7\xac\xcaT[H\xd8p\xa7D;\xdc)I=?Hx\x15\xfc\xad\xad6c\x90\x9d\xce\xb4P\x9d\xfa^\x101\x9cb?\xf5\x95\xd6\xbc\xc6Z[\xcc\xc7\xa9\x1f&\x87\x82v\xfed\x89\x85d\xa9/\xbc S^~A\xb4 \x9a\xf9$\x98\xa2\xe9`l[\xe2\x0f}\xc5\xb9\x8cf\xc5\x9f\x86\xcaYLD\xc5,\xd6\"\xd3,\x8a\xd0+\x93V\xc2\x9f\xfaJ\xf1\x92W\x89\xb5s\\\xf4\xb1x\xd1\xd7\x16\x0eX\xe1@[\xb8\xc3\nw\xb4\x85\xbb\xacpW[\xb8\xc7\n\xf7\xb4\x85\xfb\xacp_[\x88V\x1f\xb4\x98x\xda\xf5\xa0\xef9P\xd8Om\xa5b\x97-\x8c{l\xc1[\xd1\xb7\x90.\x19\xca\xd1\x1f\xba\n\x8c\xc4j \xac?\x8b1\\&-\xc7\x9f\xdaJK\xb6%\xfc\xa5v?\xf8\xe1*c8\x87\xbf\xf4U\x12^A\xbb+//\x18 //\xb4p\xbc$\xd7s\xc2P\x95\xfd\xd4U\n\xbc\x0bN!\xf0\x97\xb6\n\x99\x93\x90\xf5\xc4~j+1h\x05Zp\x05~x\xc9\x8b\xc3K]\x85\xa5\xe7\xb3\x81\xd2\x1f\xfa\n+^\xae]\xe8\xa5\x17_\xf2\xf2X\xdf\x01 3V\x81\x84\x99\xa9\x82\x9frR\"\xfe\xd0W\xe4t[\xe7w\xc8+p\xec\xc5_\xba*\xa1\xc7Ha\xe8iIa\x181\xbfaV\x87\xff\xa1\xab\xc8\x04F\xac\xc6\xc5Z]%\xb6\xbc\xfa\xe3*Z\xa5\xc5F\x12\x7f\x18*\n\xba\x17\x19i^\x94\xa5\x02\xa7\xd9O]%\xd6\x97\xb6\x93\x95\x17{l\x05\xf0\x97\xb6\x8a?I\x05]\xe5\xbf\xb5\xd5D\x15Sq4\xcf9F\xf1\x87\xae\xe2\xcfX\xe3g]Q\xcc&\x12kg\x123(\xc4Z\x08\xc4\xd9\x05\xe3\x99\xe8\x0f]\x056.\xed\x80\x12o\xc9\xfa\xa5?\xb4\x15\n\xd41#NB&\xf9r\xf2\xdf\xfaj\x81\xc0/\xf6S[i\xe9\x05\x0c\xc5X\nN]\x15L\xa3\xc4\xea\xe0Om\xa5\x95\xc7\x07\xb4\xf2\xf4\xa3I\xe3(d$\x95\xfd\xd4W\xba\xe6\x0c<\xfe\xd2V\xc9\x18\xeb\x9ddZ\xe6;\xc9\x96K/\xbe\xe6U\xf0\xb7\xbe\x1a_\x07\xfd~IY\x1c\x95\xd8\xb6R\xe6\xdb\xa2\xa9\x92\xf3\xce\xa9\x89yN\x19\xd9M\xb5$7%\x1f\xd3\\\xa4\x11\x7fh+R\xde\x82\xd5\xa2\xbf\xb4U\x16\xac\\\x9br=\xcd\x8f\xec\xd4tf\xa7>?\x0e\xe9\x0f}\x85T\xc0\x03#L\xeb\xaa0\xaa\x99jIf\x1a{\x93K^\xeeM\xb44\x9e\x11x-u\xcf\x18\x82fZ\xec\\{\xac\xe3\xb5\xa7\xedy\xedO \x13\xa7\xf0\x97\xae\xca\x15\x17r\xae\xf4R\xce\xc4\x8f\x85T\xc9~j+\x05\xfe\xea\xad\xc7\xd7A\xfc\xa1\xab8%3\xc1\xaf\xcf\xb4$\x82\x04\x81\xbf\xe2\x02$\xff\xad\xab\xc6v\x92\x9e5Yzs\xce\xdd,1\x93C\xb5J\xe0\x87\xac\x06\xfda\xaa\xe0\xc5_\xc5\xde\xd4G3f^\xb5x\xa5\xfbh\xe9%\xe2\x1cO\xb4k\xbc\x12\x10Z\x19\xa0\xb3\xf2\xd2\x94\xc4\xa1\xa8C\x7fk\xabE\xc1\xf5\x9c\x13@\xfe\xdbT-\x9f\xa9\xf8CW\x91\xce\xc9\x0bJ\xb3-\xbf\xd2~$\x88kl\"\xadi\xc4\x89L\x1a\xe9\x89\xfd\x9a\xd3\xc3\xb5v\x1d)Q\xc8\xa9\x83\xb6BNtSFuK5\x0c:\"v {\x07:\xa2:\xbbvn3\xdd7\xb9\x07\xfb\xc2\x9e\xecs\xc7\xd1\xdf\xdb\xd8\x01Yx\xe4\xd0\xfe\xe4`\x8cw\xa0\x03\xd6\xd8\x83s\x8f<\xf5\xf6\x97[\x8f\xebcYT\xdckx\xa8\xe7}5V\xb0\xf0\x8b1\xf9\x18\xd7\xda\xa2\x08[\x92\xcfQ\xe9\x03\xb7\x08\xd6\xab\xf5E/3Z\xe3\xc9\x13/\x8c\xc2\xebe\x94%O\x9fj\xb4\xb7\x81Q\xe5\xeb1s\xb9\xb5m\xe1/\xddN\x00\xd4eQ^ym\xe7\xf7\xba\x86zt\xbaX/\x9f\xb7\xa1\"\xbb\xe0\xc5\xaa\xfc\xae\xd7PQ0\xf2\xeb:F\x1e\xf2\xc08X\x91\xdf'\x9b*\xf2 ck\x11\xcf\xd8T\xd1\x0b\xaf\x870\xb5c\xd9\xf6\xef5^`\x9bA\xf9f\xd6\xa4\x82\x17\x8f\xb8\\*\xe2\x99\x14\xe6\xce.DM\xf7\x8b\xca\x15\xccVal\xe0\xc8\xf6\x1d\x0b\xdb\x12n\xdf\xf0\xa3\x05\x1d\x88\xa0\x03\xd6\x8f\x10\xcd\x8a\x94s\xac f\x05\x0b/\x01?\\S\xea\x93{\xcf@\x18\xa5\x98\xc0\x82\x8a\xdd\xfe\x94\x88\xa9vM\xe9C\xc5C\x11\x14\x13I\x8dCC\xb2W\xf1`D\x89\xf2\xa5yV\x1b\xb0B<\xb4\x0b4\xad\xacD\x17\xd0=e\xc8\xbc\xe4\xf3\xa4\xd3\xf71\x16\x99\x02\"\x0c \x8d\xef\x12\xf6.\xc9V\xab\xc0gi>$\xa8\xb9@>\xae\xc8$%S\xf0B\x06\x9d\xaeu\x9b\xebX\xf1\xe4w\xe0<\xd0\xc2\x04\x9e@\x96\x1b\x06L:\x9d\xb6\xa0\x99aj\xc9\x0c\x93\xe2r\xcc\xa2#\x1e\xd3\xb1O\xe8\xaf3\xcb\x05\xaf\x05\xe4\xe8\x02\xcddCJ\xf4T.\x8c.>c\xb2:sx\xf5\xb91\xdc\xe2\xea\xb7\"\x11\x1eb\xf9\xde\xfa\x82;qC$O7@l\xef\xcb#\xb6\xd7\x1a\xb1!\xf1\xc3y@\xe0\x84x\x93\x94s&\x9f\x87\xe5\x9f\xb3\xf0\xa6\xack\x02C\x7fWB\xbce\xd3\xc5/\x99\x19\xb7^c\xe6P\x14zK\x16)K?+\xf5\xf1\x1a\x8d\x9eM\x0f\xc3\xc1\xae\x14\n\x16\xe3\x0d\x97\xde\xe0h\x8a\xad\xdd\x8c}\xe2\x11vp\x95\xc6Z\xb5pc\x1b\xa2W\xab\xcf\x97Gv\xb1\x92\xf4s\xac\x91a\x8d\x7f\x1c\xba\x1b\xb8(\xbc\x92\xbb%\x91\xabu\xb0R\x1fD\x9bk;\x1d\x933Ge0\xe4\x05\x88\x8b\x05\xf0\x0d\xc0\x0e\xab\x94\x05I\xca\xebhJ\x1a9\x8a\xcf\x81\xa1\x89d0\xbe\xf2w%\x18\xff0\xceM\xcc\xb5\x11\xd0\xf2\xa9\xd6L\x93\xdaq`%+\xb3\xad\xd1\x08\x92:T\xbaC\x8e\x8c\xf5\xd98g\x89\xeb\xf2C\xc8\xea\xf7:\xf0 e\xdd\x85\x97H\xd1\x95\xecI+\xd2\x0f\xf5\x0cZ\x17\x19\xb4v\xac\x19|.{\x06\xff\x00\xd2\x15\x85\x1b\x1c\xd1\x1a\xe9@\x8aTW\x11\xd0jL\x0d?o\xeb\x16Q\xd1\xc4\xce`\x810\x1f\x83\x07O \xcd\x19tO\xf6\x866=tR+\xba\xf2\xe9\xd8\x93\x89j\xed\x04@\x12y\xfer\xfa\xe6u\x91?H\x9bYB~6\xdcih\xb2*\x1f~-\xb6Z\x14\xe2\x89\x99o\xcf\xba\xf3\xf2\x16\xe8B)\xda\xef\x8e2R\xe8i\x16\xad\xbb\xb4\xd2\xa4Y\x14\x13\xba\xa0T\x9b\xa9_~\x8c'C\x98\x0f<\xb2\xb7\xfa.\xe4\xab'\xe2\xf4\x96\xd6&\x87U\x17\x8eU\xb1\x14\x8f\x8f\x05\x99\\\xe6`L\\\xb8\xc8R\x88\xc9\x84\xf8k2\x85?&\xe0\xa5\xe0\x87S\xf2\x11\xfe\x98t-\x17\xce1\x99\x0bA\xe7m\x05l\xe6\xd5\xfd]\xb6`\xef1d\xa5\xe5\xc8\x9a\x97\x03\xa4\x1d\x94\x8e\xb3\x86%\x01(\xfb\xd5&\xe5\xd1R\x02\xed\xb4\xa2\x8e\xd0\x9a\xc6\xb6\xd9\x9f\x86\xadxw\xfb-Y\xb4\xb0&\x15\xcfg.\xe9\x7f=\xac\xc6\x8f\xac\xc7\x1f7\xe44Z p9\xb30\x9e\xb4\xc4\xd9Y\x9bf\x817\x1d`\xac\x84;\xe1C\x82\x1c\xd4\xf5\xdb\x01\x1a\xb7D\xbb\x0dswL \xf9\xe8M\xd2\xdf\x11\xeb\x93\xd6X?A\xacO6\xc5\xfa\xc9g`\xfd\xe4\xce\xb1^\xa0p\x86q\xed\x18\xff\xd4\xc4\xb5\xe4;%\xa0;\xa5\x15J\xd3\xda+\xdc)A\xcb\x9d\xb2\xb5\xda\x0cN\x97\x84\xcbdA=9\xfe!|\xe6M\xf3+\x0cZ\xa0\xf0l\x0c\x06,\xc6\x80\x05\xdcs\xe5\x87\x10/\xff\xd0\xd1E\xfb\x95\xec\xf7\x92:\xa5\xef[l\xd35\xf7s[\xd9\x89\x0bAu\xb7\x07\xedv;\x85\xdb4\x07\xdb\xf4\x1f\xb4\x8f+oo$\xafM\xa8\x06B\xd2\xe1\x8f\xd0Z\xe5\x891x\xf2\x02\xf8\xf4 \xfap\x1f\x0b\xf0\x07\x81!f\x00c^2\x84\xfeR\x03@\xe8\xfb^\x18\x02\x13,\xfc\xa4\xbb$I\xe2\xcd\x89\x14\xf8(I\xbd\xc9%\xbaW\xb5j|j\xc8\xff \xcaC\x9b\x11\xa5\xc8\x85\xcc\x85\x04)\xbc\xd6\xe5\x93>6=\x883\xa6\x89D\xa23\xc1\xa4V.\xb0X\xa5\x9e\xc3S.`b&dE\x8f\xbc \xf0\xc3y\x11j\x0dp\xe7xi\x14'0\xf5c2I\x83k\x91\xe4\x85n\x94(\xa6D\xe3\xe2\x1a\xd2\x05\x81\x1fWq\xb4\xda\xa6D'\xf9\x11V\xde\xe4\xd2\x9b\x93.\xbcO\x08\xfc\x987\xd8E\x865\xff\xd3v~\xa4\xfbl\xe2\x05\x01mb\xd9\x85\x13\xe2Ma\x19\xc5\x84r\xae\x8b4]\x0d\xef\xdf\x9f]t\x97\xe4~\x96\x90m\xfcz\xbb\xe8\xc7\xb8I$<\xc48\xd0\xe3\xe8\x0c\x0e\xd0\xd93\xf7W\x15\xef\x18\x91x\xb7 \x85\xacS\"\x9a~\x82\x86\x97\x94\xf1N &?g~\x8cZEY\x9eb|\xb7\x9f&\\\xd4\xf2\x13\xf8\x91vD\xe9(\x0c\xbf\\\x1f\xb9\xbf\xae\xe8\x88Nn\x08\xa9]\xc2\x91&Op\x90\xaf\xe6\xbb\x17~8\xb5\x19\x19\xda\xeak\xc0\x9b\x8b]~r\"F\xaa~\xd7\xabF\x981`\xfc\xba6\xa4\xa3\xe9@v!3a\xbd\xb8k1_\xe1\xf0\xb6\xe7\xb6\xe7p\xe2p\xd0\xee\xa8(\x1d\xa9K\xfay\xdbS\x95\xbeM\x05[\xcf\xd7\xa9\xba(\xaa\x17\x93\x1eb\xd7\xb6\x96\xf2%W>\x8b\x92\x9b{\xef\xe9\xe13\xf1\x12\x92;e\x0fk\xaa\xf0\x9b\xf7\xba*\x85\xbb\xb8\xbe\x16\x14\xd06\xa5 `\x0d S\x84\xe6f\x0c\x9e\xb7\xac\x19\xce.\x99[\xd1\xbas\x8b\xb6I\x97\xacI|m_7x@\x97=\xdeS\xb9\x89\xbaD\x0bk5Bc\xa3\xa8\xb0.9r\x86\xcc\x913\xe4\x8e\x9c\x93\xa6\xdb\x95\x8d\x1c;\xd5\xe7\xa6\xd1\x0f|+n\x953\x82\xce\xc1\x17)O[9\x98\xc7\x8a\x83y\x1b%\xc2c\xd8\xb2}LhPv\xec\xae\xfd\x12\x8a\xbb\x10\x9fyuK\x0b\xd97\x83f\x03gs\xdd\x98Zr\xbd\x18Z\xa8\xad\xb39*\xaf1\xf1\xc5\xb5\x9d\x8d\xfbg\xad&\x02mt;&\x8c\x16\xe1\xa5\x1b\xbf\xaf\xf6\x7f\xd3\x8a\xcc\xcd\xeb\xbd^\xc5=\x8b\xf1|R\xf5\x85p\x00\xdc.\n9?I\xbd~B\xe6\xc7\x1fW\x85k\xba\x05-\xa3\x13\xf1\x9e\xa4\xfc7\x9c\xd3\x14I\xa1\x18\x95\x18[\xff\xf2/R*B\x0b7p\x835\x19\x91\x07\xc8^W\xe1\xc8\"q\xd1\x81\x8b\x11T2W\x1a\x80\xbb4\xc7\x14\x93\x12\xcb\xe1\\rjW\\i1\xb7\xe8*\xe4\xc5\xda\xcc\xb5\xfa\xebJ\\\x82\xfa\xa8O2\x00\x9e{\xa9\x94\xb1g\xea\xa5\xc4\x90\xb4\xa7\xf2%[\xdb\xe2\xdb\x98\xcc\xc9\xc7\x95\xc6\xeb\xd9\x84F\xed\xe0y^\x8f\xac\xfaT\xd1\xe2\xc4n8\xaa\x19\xd2\xd6\x1d\xc3\x8d\xc7\x9e\x98\xbd\x17\"gS{\x86\xd6\x1f\xc5\xac\x0e\xae@]\x05\x0e\xe6\x16#\xaa\x1bP[\x1a\xd3\x14\x89\xae\xfc\x17\xffH\x8a\x88 #v\xc5&g/\x08\x14I\x05F\x94\x95\x0e\xba\xf2\x8b\xc0\x055\xe8\xe7\xad\xccb\xebb\x01\xe5W\xfaw\xd4\xbe\xd5\xdf\xeb\xeewy0\x84[\xb5\xb6.\xc2\xec\xef=tLa\xc5\xfdV\xf6\xcf>\x7fu\xf8\xfa{C\xbc\x87$\xf5R\x7f\xd2\xae\xee\xaa\x08\xb4\xde\xa26\x8f\xf2\xba\xc1\x07\x0b?\x98\x1em\xfa\xd5\x9c\xa4\xcf\x199\xa0;P\xf9\xe6\xfc\xd5\xf1\xc9W\xc7\xcf\xcd\x9f\xbe\x0c\xfd\xd4\xf7\x82\xd3\x14S=l\xf4\xe9\x914\xdcM>\x8dI\x88\xfe\xbd\xe2\x8b7\xaf\x8f\x8e\x8d \xe4[\xe8[?\x08^\xb1p\xaa-@\x92\x7f\xf6\xdc\x9f\xde\xe2+\xda\xd9 \xbb)\xd4\x80\xd4\x84G\x8b(\xa3\xe0\xe0m\xbc_MK\x10m;I\xf5\xbb6\xe3}\xeeOo\xf3\x19v\x17.[\xc3\xe7\xfd\xeb\xd3\xc3\x17\xc7\xe7\xb7\\\x13\xdd\xd7\x1b\x03Y\xd7\xc8\x06S\xcf\xb0\xaa\x94\xcf\xc1z\xf3\xe1\xf8\xe4\xe4\xe5\xf3\xe3\xf3g\x87\xa7\xc7\x1a\xe6\xa7\xda\xce\xc4Htp#\xc6\xfe\x9aLq7\xbd\x88\xa3e\xcd\x8el\xd3\xd7\xcc\xd8\xd7\xd4OV\x81\x87I\xceZ\xb2\xe4\x80\x84W\xfa\x0eT\xbd\xaex\x0c\xd7F\x82\xa6\xb6\xee\x8d\xb2\x9c\x9a\xd8\x9e\xf2\x93\xdf{\x84\xec\x9e;,\x85\x86\x0b;\x1d\x87k\xb4\xc7\xe1\xd9Fw\\\x1aR\xdaz\xdci\xb7\xf25f\x1b\xfc\xfb\x8d\xab+\xd3\x060\x85\x9a\xa1\xddzT\x86\x01}\xc6X*g\xc7\x06\xc3Q\xbe\xc5\x00G\xea\xbb\x11L\xed\xca[ly\xa8\xad\xbd\x11BJ\xa7\xf1\x06\xc3^Il\xaa\x00a\xfenS\xf8\xe5\xccC\xeb\x01l\xb5\xaf\n\xed\xf6\x10\x94\xf7\x91\x1f6\xb7*\x1e\xc1\xe85\x1b\xf5\x8b\x07\xc7\xa3\xda\x02\x86\xadm\x01A\xe8\xbd(\xbb\x88W\x9d\xed\xba\xa5Odo\xf9.\xfc \xadhy6\x9b\xef\xa3\x0c<\xbc\x10I\xc9r\x95\xfa\xe1\x1c\xd2\x88gi\x07\x0fb\x92\x90xM\xa6\x88)t\xa4.\xfc\xf8\xc7\xe4G\x17\xd2\x85\x97\xf2\x03;\xfc\xe1O)\\\x10\x88B\xbc\xa9\xb1\xf8\x8aZpI\xae\xbb\xf0\x9c5\xe5cn:/,,\xa6E\x8b\xf8\x86x\xd3\xc7\xb4\xce\x95\x1f\x04\x90\xa4\xf4\xff\x17\x04\xbc\xc9\x84$,94o\\\xb6\x17\xff\x93>t\xbe\xe9\x11z/\x04\x9a!\xee\xb5\xeeA\xf5\xd7&\xab\x03\x12\xcf=\xa9.4\x1c\xc0d\x1c\x9eqE}\xfbq@!^F\xb6\xee8D\xbd\x87\xe7\x82\xd5z}\xe9RR\xc8^GY,\x19\x0b\xe3\x0dY\xba\xf0B\x88\xc2 \xe9\xc2\xbb\x85\x9fP\xc8\xcf\x02\x7f\x92\xc2\xd2\xbb\xa6k3\xcd\x08m\xc9c\x87Z\xd7ba\x99\xd7\x91?\xb5Q\x8f\x8ct\x0bo\xad\xe3\x86\x80\x93\xf2S\x7f\x01,?\xbc\x13}\x1ch\xf5in\xd6\\\xe3\x86Q\x99Mh\x9a\x97\xa5\xd1\x85\x1fN\xcb&\xf7\x1b\xdcA\xeb\xd3\xfd\x80d$\x98\xa8\x88E(b%cbF\xacs\xcd'\xf7\xeeQd*\xb3p,tm \x8f0?\xc3\xcc\x9b\x10\x13BEk\x12\xc7\xfe\x94\xa3\xd4,\x8e\x96\x1c\xa9\xe8\xd7\x90\xac\xc8\xc4\x9f\xf9\x13\xb40\xef\xc2q\x98d\x0c\xc3RVkI\xd2E4\x85\x10\x93\xd1N#\xbc\x01\xa6-\x06\xde\x8a\x85\xf2\xc4\x91\xf0jhjH\x1c\x97\xdd\\\x94\xb7\x82\x08\xbb\xfb\xe9\x93\x96a\xbc\xcd\xcc\xbe\xc8V!\xedn\xe3\x90q3\xa7\xf00\x11\xa5\xc8`\x1cZ%\x0d\x7f\xaaL7K(\xd9/&\xc8\x160\x8a\x8bAQ2\xceg\x02/\x19\xe9v\xe1\xa7,I\xf9\xb71\x99g\x81\x17\x17\xb6\xf4.=w\x08\xda\x86n\xde\xff\xc6\xbd\xe9 \xea:\xcf\xd7T\xa8\xe1\x8c;\xde\xc7\xfb\xa4\xf3\xf3\x98\x0e\xf60K\xa3g~8}\xeb\xf9\xb1&\x863\xc8\xac\x83G\x8f\x96P\xddf\x19\xcb\x14\xdee\xdc?.)\xff\xedh\xa3\xd0\x8b\x07\xd7Xm\x8c\x19Vxx\x8d\xd5x*\xad\xb9ch8\xf6Z\x98\x8e\xadp\xda\x95\xfe\x9a/\x02\x03{\xc5\x12\x01\xcd\xaa_;0\x1b{gt\xd2\x93\x86\x96jbQ\xcb\x0f\x9d\xd3BG\x00\x9bF\nu\x86\xd3h\xbd\x82\x01\xc4W\xe8\xe6\xd6g\xa4\xa2+(y\xbb\x13\x0c-\xf5\x9b\x16E~\xd6<\xa4w2\xf6Zr\x8f\x80\xfb\x1b\x03\x9b\x9b\x99\x80k\x95\x00\xf2\xd7\xea\x0e|\x1f\xe6V\x04\x94D\xc3*\n\xfc\xc95\xfc1A\x94\xbe$\xf8\xf3jAB\xb6\x03\xe7\x14\xbd\x8b\xadI?Ab|\xcdV\xbff8\x07\x10\x8f=\xc6\x13\xd0\x1f\x14\x19`\xa8\x1b!\x8b*\xcc\xea\xae\xf3\xba\xed\xa0\xcfCT\xf3\xaf'\xcd\xf0d\x11\xadY*\x16\x8f\xf6\xe3\xe6\x1f\xd7~[\xc3+T\x8f\xf8V\x84~a<\xef\xcbbIds\x8b\xb2\x9a\xfc\x01\x9a\xf7\xc4\x05kI\xe29\x11\x89\x97^G\xcf\xb3U@\x0fd\xf25\xb9Nlg\x08G^H\x8f]\xac\x06a\x14n\xb3f\x12$\xe0\xc4\x01\x8d\xc8\xc2r\xa7\x95.\xf5\x90\xe1k\xec\xeb]\xcc-ZXo\xe9U\xc4\xe9w\xc2\x8e{\xca\xe9'\xde\x92P\x14\x1c\xe2\xd1\xdb\xead}LA\xb4\xc2\xa8\xb3\xf4L`Vr\xa2\xea\xc4\xcb\x12nNv\x15\xa9j[\xdb\xa1G\x9c\"L\xdb\x8e\xe088\xdfMw@i\x9c\xf4p\\\xd0\xb7\x97\xe4:\x11,0gL\x0d.\xaa\xc2\x86\xb0\x15ZL\x9bL\x11e\xf6\xd2x\xee\xa1OI\xd7[\xad\x82k\xccE\xe2\xe6\xde \x89\xc1\xd1\x91>(\xd4\x1a\xbe2\xdf\x8f\n\x9b\xb8\xc2\x11%n\xae\\\x18{\x84\xe6\xd3\x1bC\x1ek\xe2G\x83t\xebf\xfbl \xf0\x87>\xd9I\xbb\xfd\xb8\xfel\xc0\x1b\x01n\x04\xea-\x87z\xdd(*\x10f=\xa7\xbb%\x16`WzR[\xd1\xe77\x06\xfd5A#h@X\xb4\x9e\x9f\xfb ~\x84F~\x9a$\xeb\xa0'\xa9U\xa4]6\x0f\xb0\xa4\xaa\xbf\xf5\x18\xf5\x06/\xad\xc6xn\x1c#\x8fY\xce/\x90Z+\xb7p|L\x1f\x1fwI\xf8sF2r\"5\xc51lc\xe95\x9fpK8 c\x9c-\x15`\xb7\x87\xd5\x859\xd90HV\xa2\xf6\x85|\xab.\xf3\xf6p\xae!m\x05d\xeb\xc8%Q\xaeT\xe3\x1a{P(\xd0\xa4*,\x88|p\x94\xf9o\xecY<%/\xc2T\xdb\xaekP\xf5Cg\x04\x83\xa6\xf6A\xd1Y6\x8b\x05\xc0%\"2\x0e\xa1\x03\xfd\x16|*&\x84\x181\xca\xe4\xdf6\x10\xc2\x0d\xa2\xaf\xc8\xb3\xb7\xe2\xda\xedj\x96c\x91\xd07&3\x0cj\xe6\x96\xf6\x850R\x0f\x0b\x93\xf9T\xe4\x172ODh\xef\xf0\x13\x85U\x80\x03\xedk\xdbiT\xe8E\xb6\x865\xf3\xd0\xb0\xaelO\x86\xcc\xf4\x1f5]\x0caI%_\x8e\xfe\xb9\xbf:\xe5]h\xd7\x16=\\\xe4\xeb)*\x050~\x9fR\xc1\xc4\x97.\xee,G\x81\x88\xa7\xdf\xad\x0d\x12o\x8c\xca\xf2\x92\xb5KH\xae\xe0\xc2\x95_\x96\x82\x88`\x8ef\xb9P\x87\xe2<\xd5\xa0'\x12\xdf\xdb+\xd9\x02\x9c8\x8e\x0b+\x9b\xb80\x17?R\xf1c\x89'\xacz-\x82\xbe\x08\xdd\xa9rS\xa2V\xb3\x1d\xd4U\xc8\x83c\x17\xed.XR\nx\xbb\xdb\xedR\x86\xb9\xaa\xdab\xcb\xe3/W\xcc\x1c\x05<\xf8\x915\xf0#\xe7$\x91\x99N\x1cy\xfe\xd3E\xa64'\x13\x8fJ\xb4\xfc\x83A\x14\x92\xffJ\xcb~ \xca\xad\x8d`p5\x80e\xd1\n5\xa9\xd3Y\x80BM\xc1\x0c#\x12j\nD\x04BM\x91p\xd8\xd3\x14\x89(\x83\xba\"\x1eWPS\x84\x91\x04u\xefE\xc8@\x8d\xd62\x8fa\xa6\xf9N\x0er\xa5\xf9\x94\x85\x052N\xcc\xf0\x15\x8f\xc8a*a\xc1\x174\xa5\xdcU\\7\x05\xe6N\xab\x98\xc3jy\xbe\xb0j:\x19\xbb\x10\x96L'C9\x9f\xeag\x10\x0e\xee>\xc9n\x00\x8a[\x13\x17\xac\xf3s\x92\xbc\x8a\xa6Y@,WA?4\xaa\x1f\xca\xd2\xcc\x0d\x1eI\xfc\xf0\xa9\xa3\x1e|\x8aUt\xce\x85\x98dh`\xef\xdeE\xab\x0b/\x1eB$\xfa\xa9\xd42Y\xad\xde(\x84\xd2\xcd\x89\xfc\x8e\x86*\xda\x94\x90\xfa\xa8\xf9\x89\xbb\x05\x14\xe0\x00b\xd0\x8dMX\xd9V\x1c\xb6\xe0\x1f\xbe(\xd5\x03be\x87v\x7f\xf7\xa1\x9a\x03\xd4\x17E{=]^QVT\xc9\x1c\x9a\xe5E\x95l\xa4^^\xb4\xaf\x16%\xdcfU=\xa8&\xcc\x0fWy;\xa3+\x82-\xed\xef1\x9e\x88\xae\xdb\xae\xa3\xb6\x1a\xf0\xf3l\xdf\xd1\xa5*]\x19\xcfg\xd4'\xa6\xe5uN\xeb\xd7\xd9D\xcdoJ\xd0^\xd4r\x07\xd2\xb9a\xba\xff\xb2{.\xf8\x02\xd7\x1d.\xe9\xea\x9c\x7fho\x88\xb8=\x172\xf5\x03\x9br\x9f\xc8v\x9d\x9f#\x13\xd6s!.*\x11\xc7a^E\xb9 \x1d\xea\\B\xc5\xa5|7\n\xdf\xc7\xc1\xd1\xc2\x0b\xe7\xa4\x95+V!\xe6\xa5^<'i\x9dCN\xd4MH\xca\xc4\x00\xb3\x80\x97\xc5\x81JE\xc5\xa3\xf1\x8b\xbeq!\xea\x06\x917=]\x91I\xab\x01GL\x0e\xebR\xa6\xf7\x10\xeb\nA\xeb}\x1c\xa0\x87\xb9\xae\xc64\xba\ni7j\xba\xf3|\x0c\x08\xb7S\xcc\x8e\xd0j\x18z\xb8\xa1\xe7\x9ax\xb3\x88\x89\xc1.\xa6\x98\xb2Mp\xc0\x14\xae\xd87\x99\xd2Y\xe0\xcdrw\x15\x935 \x85t`\x1b\x06.f\xf6>\x0eZ\x0d\\\xea;b\x82W7\x8b\x83\x0d:\xc4\xb1z\xf1\xa4~\xff\x88G\xc0\x89\xa2u\xd0]yqB\xd8\xd7\x8e)\x834\x19[Y\x1cPq\xdb_z1\n\x91\xd6Y\x1ew\xd2\xac\x9c\xa5\\\xd8\x95\x1fN\xa3\xabn\x10\xf1k~\xdcW\x93\x08#\x1f\xdc\xbfoA\xa7Rc\x11%\xa9\xe6\xf5\xcaK\x17\xe6\xeeXmJ\x98\xf8w\x0b?I\xa3\xf8\xba\xfa\x06/v\x98\xcc^-\x93un\\\xac\xb4,\x97\xc5\x1c<\xa0\x83e@KH\xec{\x81\xffK\x0e8]\x86\xde\x9b*\x1am\xb4>b\xd3\xccIz\x14\x853\x7f\x9e\xd8\x0eE\x8c\x84\xa2\xf4\xd8\xa0p\xc1I\x11I\xc7\xc4n\x86r\x899\xef^\xe7\x12Pj\x88v\xc5]\xb2\xf0B\xa7\x0d\xa5\x81<\xb5 \x99\xbe\x0c\xa7\xe4\xe3\xd0\x90\xc2\x1e8\x03$\xe1\xae1\xcb\xb1\x89FE\xe1\x0b?HI\xfc\xc5H+\x03\x7f\xe0]GYZ\xa6k\xacc\x9d\xfd [t\xae<\xd1\x0f\x02\xc9q\x8a\xb4\x90\xa1F\x14'\x14\xd8\xa6\xf8\x92\n@\xab\xfap\xdag\xe9\xa5\xd6\xf9\x88b\xae'\x9dbL;B\xdfF\xa5\xb7\xe3\xea\xa8\xf1\xbe\xcd2\x1a\x98kl\xc29g\xd5\xbc\"L\xd9\xd4\x8cYf\xa0\xb5\xc6\x992\x88T^\x10\xf4\xf3D\x9du\x8b \xd6a\\\xcau\x86f\xa5*\x11Z\xc5\xea\x8e7\x7f\xc4.q\x9a\x08\x02\xde\xa8\xd1\x1d\x1cr\xa2P\xb7\xe9\x0b\x15\xb0\x86\xe0\x9bU\x981k\x7fc\x1a\x03Hg0v1F\xc7`|e\x0bl\x10OkZ\x03z\x9ch(j\xbc\xb7o\x81D\xe2\x06\xec\x8ep\xe86g\x02\xe7\xd7\xa53\x816\x94\xf3\x1c\xe9\xb8\xd0\xf8vK\x10=C>\xe4\xf6@`Z\xce;\x9dy\xc3\x1eb\x80\xd1z\x07\xca\x0f\xbb\xfb.\x11\x13s\xe5\xb8h\x18!n\xae\x89\xf7!\xb6\xf5\xcc\x98pU<\x11\xab\xf8\x8d!i\x9fx\xd0\xc9\x8f\xae\x93\x1f\xce\xb9\x95b\x97\xffIwHVK\x1e\xbc\x9a\x9bqk\xe6\xf9\x01\x99\x1a\xda\xc4\xf3\xde\xebN\xa2\x00\x15\xf3V\x8c\xd9=!S\xdf\xff\xff<\xcf\xab\xb3\xac\x0b\xd0\x11\x80\xe1\xa7y\x9c+\x83\x0f\xa2x\x16\xb5\xf72<`\\=I\x9bb\x17f\xfa\x15TIW\xd3-+}\xa6\xccFh\"\x8eO\x9e\x9aYh\xadE:?\xdd\xfeP\x1f\xdc/5\xb6\x87\xe2\xe1\x1b'\xa50\xad'v.\xe7\xcek\xac\xa4(\x03\xb6j\x98\x03\xcb]\xd94\x054\x07e.S<\x9f\xdd6\xff\xb0\xf6\xb3E\xba\x0c^Dq\xfeQ\xd5uK<7.\x18\x87\x88\xf9\x95\xf2(f\\`\xf4\xf0\n\x86\xa2\xad\xf9;\xd6g\xd3\xdc\xfci1\xbe\xfa\xe9L\xfd\xc4\xbb\x08\xc8t\x08Y}\xc5(d<\xeb\x90\x116I\xd0\xad\xff\x8e\xaf~PO\xb0\xeb\x808uLL63{[\x08b+\xc9\xb0\xcdH\xc2\xd2\xac\xd6\x01RF\x10\xd1\xf4v\x16\x07\xdb\xfcS\xe3\x87)\xaa\x8dY\x9a\xad\x1az\xaa\x01({c\xfeFl\xa5\x02\x94Y\x1c\x98\xab\xb7Z\\\x9e#\xd1pi\xea4\xef7\xffV@\xe4\x19\xbek\xe1\x13\xf8\x93\xcbaem\xf5\x03u\xc1:\xfe\xb8\n\xa2\x984\x05;3\xa2\xc4\xd4_\xb7F\x88\x14\xb5\xd4\xfa\xcd_\xb7\xf17\xe9\xe3*\xf6V+\xf2\x85;a\x13\xd9\xbem_\x91 b\xe6\x8d\xb6\x9c\xd7\x0efA\xfc\xf9\"\x1d\x82\xb5\xd3\xab\xc1\x86+\x7f\x9a.\x9a*%\xf1d\x0831\x90\x1a6#\xa0\xfd\x9d^y\xf39\x89\xe1\xfdK\xc3\xack q\x89\x80'\xac)\xcb\xa9\xfb\x04\x13v\xb7]\x96\xd2^\x11\x8bS\xb7YN\xb3\x8b\xa5\x9f\x0eaaZ\xc1Uw\xe9\xad\xda3\x0b\x92\x04\x9et'A\x14\x8a\x898\xf4\xd3\xfa\xe3\x87q\x06f\x9an\x92\x7f\x1d\x1d\xa5W8\xf73\xc7\x95\x9a\xbe\x91\xa8R\xceCK\xdb_\xbe\xacb\x90Qojd\x18\x94\x02\x80`J~\xccxy\x7f\x15\xce\x1f_x \xd9\xdfu\xfd\x0f\xcf\xde\x9c\\\xf5\xbe\xfej\x1e\x1d\x1e\x1e\x1e\xbe>}\xbf8~??<<|\xb6K\xff&G\x87\xaf\xe8\xbf\xaf\x1e\x04\xfb\x7f\xa5?\xbe\x7f\xf1\xec\xd5\x87\xe3\xf7\xb4\xc2\xfb\xd9\xd5\xad\xfe\xeb\x05\xbf<\xbb\x1f\xf6\x9e\xcd\x16\x1f\x9f\xad~\xba>\xea}\xdc\xbd\x7f\xff\xfe\xfd\xce\xcf\xeb\xdd\xa3\xbf\xac\xfa\xcf{\x8f:\x9dY\xbast\xff\x97\xbd\xfb_\xf7\xf7\xef\xbf\xdfy\xf0\xe8\xfd\xec\xea\xf9l\xef\xe1\xfd\x9f\x1f<\xea\xbc\x8f\x07\xcf\x07'G\x97\x8f\xe8x\xfe\xfc\xdd\xc9\xe9\xbb\xe0\xd5\xe1\xf1\xf1\xe1U\xf8\xe8\xfe\xfd_v\x0e\xe7\xeb\xdd\xfb\xeb\xef_>\xbf\xaf>\xef_\x91\x9f\xfc\xfe\xe5\xe1\xe1\xe1\xf3\x87\xa7\xefO\x9e}\xf8\xf3\xfcY\xf0\xb7W/\x0e\xa3\xbf^=?|w\xf2\xf1\xe2\xbbg\x0ff\x9d\xf5\xdb\xaf\xc3\xe0\xbb\xc3\xbf\x85\xfb\x97\x83\xc9l\xe7\xf0\xd1/\xf7\xdf\xce\xde\x1c=|\xf9\xf2\xfb\xd0\xdf{\xb1\\\x1e>{\xf5\xf0\xc5\xab\xc5\xd5\xbb\xfe\x83\xc9\xa3E\xb8\xf0\xff\xf6M\xff\xe8j}\xfcM?]\xbe}\xde\xfb\xf9\xf4\xeb\x9f\xf7\xe7\xdei\xfa\xed\xfd\xcbW\xdfy\xe1\x87\xe5\xe1\x87\x93\xe7\xef\x83?\xf7\xdf\xac\xb3\xec\xdd\xcb\xd7\xd1\xfe\xe5\xa3\xde\xe9\xc7\xd9\xc3\x9f\x937\xe9\x8b\xfd\xf9\xeel\xd6\x8f\x92\xb7;o\xc2W\x93\x0f\x0f\xa6\xbb\xab_\xa6/\xdf\xa7Y?:\xdc\xfd\xd0{\xfe\xb7\xe8\xeb\xe5\xc7ep\xfc\xfd:}\xfe\xfe\xa7\x9fNw\xd2\xe5\xd7\xcb\x9f\x9fuV\xdf_?\\=\xef\x7fx;{\xf0\xd3\xdb\xe3\xde\xcb\xdd\xde\x9f\xff<\xf1\x9e]\x85\x19\xd9\x9f}\xf5\xcb\xfc\xfat/\xfd\xee\xe5\xfbG\xfbo?<\x88/\x9f\x7f\xfb\xe7\xd7\xdf|\xe8=\xffz\xf7\xc5e\xf4\xf5\xf2\xc5\xea\xf5^\xf4>\\\xfb\x0f\xbf\x8e\xc8\xe1\xe0\xfe_\xbeK\x96\xdf\xfd5\x8b.?\xf6\x12\xff\xa4\xff\xd5\xc3\xf4\x9b\xcb\xd7\xfb\xe4\xd9\xa3\xe4\x9b\xab\xbf\xac\xee__/'\xd7\xde\xdb\xfb\xef\xe2\xb7\x9d\x93\xb7\xcb\x8bW\xaf\xfc\x8f\x93\xbf|\x98\xbf;\xe9{\xef\xff\xf6h'\xfa\xea\xbbd\xfe\xdd_\x0f\xbd\xaf\xf6\x8f\xaf\xe8\xb2\x1c\x9e\xbe\xff\xf0\xe6\xe4\xeb\xbd\xa3\xef_\xbe\x1c}F\xd0\x19\xd2\xbd\xb8N\xc97Lj\xae\xd3.\n\xad\xe2\xc4N5\xf2\x18\xaai\xc6=\x8d\x84\xc34-\xaa\xe9\x1c'\x16;\xf0\xcf`\x87\xd0\x81\xd8\x81\xfb\xb0\x0b\xdb\xd2]\xe9\x8d\x0b\xa4\x9bF\xcf\xaeS\x82\xa6a\xf5\xd7f\xb9\xe9 \xb3\x10\xc4Q2\xcb\x17:*\xe6\xfc:\xee\xf3\\\x14!\xb9\x82\xa8\x92\xe4\xa7\xc6N\x03\xc7I\xa0C+\xb1q*f\xc3x{\xe6BF\xe99%\x06=\x97\x05q\x86\xa7\xd0\xc3\x0b\xe2m\xd8\x85!\xad\x120\xfb\xc5\x00\x9e\xc0\x8c\xfe\xd3\x19\xc1\xae\x83\x90\xf5\xc7iw\xb2\xf0\xe2\xa3hJ\x0eS;p\xce\xe0\xc9\x13\xe8?\x84O\x95\"\xe8@\x9f\x17\x0f\xf4\xc5\x03V\xbc\xaf/\xddq($\xc6I\xa7\x83\xe6\xfa\xf0\xf4)\xf4\xf7\xe1\x1e\x0c\xf6\xf6\xd4\xf7\x0f+\xaf\x07{{pO\x0d-5@)\x9bI\xcf\xe6\xc9\x18\x06K\xe7\xf2\xf4)\xecV;Q\x18\xb3~\xab^\xfa\xbdZ\x90\xed\x9a!\xf6\xf4)\x0cZ\x03\xc0\xd1\xa2\xb4WF\xe0Y\x1c-o\x87\xc2B\x97\xc5\x8d\x12\xe0\x8f\xb0\xc3\xc2=\x8e9>\xf782\xc36\xf8,\xc7\x83G\xff\xe9\x8c\xa0\xbf\xbf\xf3p\xc7\x81\x88\xb1\xe13\x8a\xe0\x99\x8b\xd1n\xb1\x04\x9e\x82\x07\x07\xe0\xc1\xb0x\xa7\xb2\xc0\x0c\xd2>\x1c0@\xa7c\xda\x0d\xdd?\xbc\xd1x\x8c\xc0\x19\x9c\xd1\xcd;&\x0c\xae\xf7`\x7f\x87\xbe\xb0F#\xcbq`\xc8\xb1\xc2\xcf\xd7\xcbf\xed\x0cp\x1d\x1e:\xd016\xdc\xef\x89\x96)b\xe4-\xf3\xae\x06RW\x15\xee=\xbf\x93\xfe)\xf2C\xdb\x92\xec\xb4$E\x91d\xc5\xc9 \xea\xf3\x7f)\x84\xa5\xf8\xab\x92\x9f\xdc{?L\x1f\xb2u<\x90\xff\x18\xb2\x90\x88lQ\xac\xc3gG\xcf\x8f_|\xf5\xe7\x97\x7f\xf9\xfa\x9bW\xaf\xdf\xbc\xfd\xeb\xc9\xe9\xbb\xf7\x1f\xbe\xfd\xee\xfb\xbfy\x17\x93)\x99\xcd\x17\xfeO\x97\xc12\x8cV?\xc7I\x9a\xad\xaf\xfe_\xea\xde\xb4\xc9\x91d9\x0c\xb4\xdd/k\xf6\xfe\xc2~q\xa4\x86\xdd\x99\x83\x04\n@\xdd\xa8F\xd7\xeb\xd7\xd3#55\xd3\xfdl\xaa\x1f\x9fH\x00S\xcaJ\x04\n9\x0dd\x82yTW\xcdT\xafQ\xd2R\xa2H]\xdc\x95(R\x07\x0f\x1d\xe4.IQ\xa4\xb4\x07wy\x99\xed\x9b\xf9#\xfa\x03\xfb\x17\xd6\xc2#\"32#\"\x13\xa8\xaay\xd4\xc2\xac\xbb\x00\xcf\xc88=\xdc=\xdc=\xdc\xafo\xbe\xec\xf5\x07\xbb{\xfb\x07\x87G\xc7\xed\x1d\x8b\xa7\xcbat\xa4\xc8g\xe9\xc1\x13HN\xa0\xdd\xf6\x1cqS+\xc3+b\xc18\x93Q\xd9s\xe8#O\xe7\xec\xe0\x9b\xa9z\x9e\x1d\xa4\xf4\x14\xc35\xc0O\xc0\x1e%c\x0e\xa4\x8b8z\x87\xc4\x13\xa3\xba\x15Q}\x99\xc3W\x178\x1bAO\xd0\x0b\x02\x1e\xac\xb2e\x1a\xac\x97\x98\xf0f\xaf\xaaE\xbb\xca\xef\xe7`\"\x95\xd7s\x9b.\xa6v-;\xfcN\"\xb0x\xad#\xbc\x03=\x0eq\xa3\xe4\xf1\xc8\x87\x8c0\xd3\xfeN\x8b%\xd7\xcc\xc3\xdcD\xf1s\xa4\xe0\xa1\x90\x85+.m\x90\xad@H\xff\xb4G\xb0\xeb \xc2\xd8)] Jr(\xf5\xec\x1f\x1c\xf6\xfb\x07G=\x8a\xd7\xf4 \xba\x8c#\xa6St\xdd\x1f\xf0'\x8c|\xb0\xe7\x03*\x9df\x02\xf3\xed\x88y\x18Q\xfc?\x92p>B\xc8\xa0\n9\x90\x00\x07\xbb\xf0\x08\xa2\xea\xad+>}\x99f+\xe4\xdf\x82\xb1\xd5\xb1d\x0c\xea!\x06\x1d\x0c(jY\xe7\xbaG\xbbZyC\x9eM\xd2\x8d\x897\xab\x0b\xbb\xa7\xa0\x02\x0b\xabM\xe7\xfa\x08>\x84\x80\xca\x02\x942\xa8\x12\x05\xdd\x17v\x9f\xce\xab\xe7\xe8K\xf80\x82\x04\xe7L}F\xd9r\xe7P\x85\xa3\x9f\x10\x9cb\xc3}\x18BO-\xb2\xe6E:\xf4\xb9\xa6\xea\x05K`\x04m\xa8\xe6T@\xc4B^\xbff\x14f\x01\x8f\xf8\x18:s6\x08X\xc0\xd3\xa7#\xe8\xcc\xa9\xe4\xd0\xa6;\x18\xe6t\xdb\x9d`\xf9\xc1\xfe\x01|\x88\xe1\xb2E\x03.\x88\xfa\xe6\xd0\x19\xc1\x91\xa3i\x91\"p\xa4\xb6\x14\x95[\x8a\xf3\x96\xb2\xbc\xa5l\xf3\x96(\x91`7 #\x07\xfb\xda\x87N\xf5\x06\xaa\xe1~3}5\xc2W\x8b\xcc3\x19\x9c\xc2+\xef\x15\x9da\xd8\x81\x1e\x15\xbc\x16\xf9\x9ck\xf44\xc8\xf0>\xf5\xd2Ew\x1d\xbd\xb3\x07\xec\xee[D;Z\xbe\xc8\xaa7\x17KU\xe3\xa8?,U\x15Q$\x94\xf6\x0ce\xe8\xef\xe2 \xad^\x93\xa9\xcdiBq\x9b\"6\x0b\x19\xcf\xd1\x9b\xd6\x1c\xe8\x91w\x9e\xa3\xb7o@o\xf4\xb00\xa07\xc5\xd1\xc1n\xce\xbc\xe5\xd1t\x06{\xb4\xc2\x12\xe8\xf0\xd0\xd1\xe3:\xc5\xe5\x98\x93\xd5H\xdf\x8d\x19/B\xa7\xaf\xa3y~\x85\x12\xd4\x13\xe8\xc1\xed-\xbf#\x8b\x8e\x1b,K\xc4\x13\x14\x8cq\xa7i0\x97\xce0v\xd4\xbbH\xd0-)H^y\xafl\x82>\xf2\xcc\x90\xca\xd0\xe3\x14lJ2\xf2\xc7\xbcJF\xbc\xe7tp\xb8\x0b\xb0\xae\xf92\x8ab\x1b\xbf.\xa3KZz\x87=\xf8\xe4\xd5\xc0q\x81P\\K\xa0\x8cM\x9d\xccq\xe0 \xf4\x91\xf3d\x9d\x0ee\xcb\x1f\x8e\x80\x96\xa7\x07\x82\x11\xee\x94%<\xa5\xfd9\x855\xec@\x02CXW\x10\x89n\x89\xa5CQ,\xa1E\x07\xac\xb6v\x9b\xd6\xb6\xc3j\xcb\xeb\x99\x8b1\xc9\x83(\xb5\x82Om\x82\xb5u\x18\xe6\xca\x8d\x05\xac\xb6\x11,q\xf8\xc8\xbd*E\x96\xe6\xf7F\xd0s\x9c\x13\x08hcG'(\x9f\xb5aQ\x88\xbd\x1e\xa5T\xed\x11\xcc(\xad\xdeAzA\x85\xa7:\x12\x94Qd\x0e\xe0\x96\xbe\xeb\xd3w\x83\x13\xf0\x19\xc5Q\xaa\xcf\x8a\xea\xb3\xbcz_W=\x7f\x15:0\x9b\xc2\xed\x08\xfa\x03\xba\xb1\xae*\x1c\xae\xe1P,+p\xca\xdb6\xf7\xea\x0c\xed\xdd\xc1Q\xe5\xc8[x\x85\x96\x1dk7i\xb2\xb8\x921\xd08\xdb\xc6\xdd\x9f<{\xfd\n\x1d2\xf9W\x9d\x87M\x9e\xe6fXI{S&yMW8\xccwS\xf2\n\xf9\x85\xdd@{[w\xa3\xf1\x9a\xf4\x0e\x92g\xed\xa8\x14\x0d]LPd\x87\xf6\xee\xae\xe2w\x1c\xf0GG{\x8e\xd6\xa57\xfa\xf1\xba\xf4n\xe3\xdd\xde\xa8KU\xd3(H\xf9\x185q\xbbh\xf9\x8a\xe3.\xf3\x11\xa7\xef9\x1b7\x0b\x924^g\xa5\x8eq\xa5j\x94\xcaxM\xd8\xfc\x9c\x12\x03\x161\xc1\xe0\xc3\x11\xdf\xd4(\x8a\x8bP3\xeclT\xf5\x83vN\xa0\x85>\xfaH\xf2\x92Rv\x00f\xee\x0fy\xbc\x0b\x9e\x94\xc0\x85\x16z\xce\n\xa7!\x96\x1f\xc19\xe1\xe34\x18\x85\xde\x83\xef\xb1\x84 u\xda\xf0\x88M\x15\xcb\\n\xa8g\x1e\x84\xderY7\xe4\xfa \xa1\x9f\x16\xfa\x13%]\xbe\xd4\xd2w\x83\xd3\x18l\xd84\x08\xf9L\x9c\xfb2su\xfa\xf1i\xa1\xda[\xf7X\x9ca\xa7:\xe7\xc5\xa9\xf3\xcd\xcd\x9aTN\x9e<\x80\x12\x0bV\xc5\xeeYf1\x8b\xe1\x11\xa4$\xf6.\x96E\xc0\x7f\xe5\xc2V\xd14{\xf2 \xbcb\xb7\x1a\xdb\xfa>\xbc\"\xb4\x8f\xf6\x1d\x17B\xfb\xf8\x00=\xa5\x8b\x0e\xd0\x96\x06\x1bu\xbb\xe07\xfd]\x1d\xc7 \xed\x03\xc7\xb6p\xb6\xd2(\xaez\xea\xb0\xeb\x80\xbb\xa6x\xe1\x94\x89u\x83\xe4\xa5\x98\xebM4\xc89\x85\xd2\x9eUyD\x15\xdc\x8a\xe3\x80\xa5t\xf8\xeew\xf3\xee\xe1\x9d[L\xb7U\x8d\xc9\x12\x97|k7\x9a\xde\x0dWt\xefAWtww_Y\xcb\x81\xd3\xe5w{\xbc$ .\xc3Mj\x92\xd7U\x9a\xca\xd8\x8e\xbbg\xd0\x86\xb8\xfb\xb1\x0b\x16\xabU1\"\xb2V\xd8\xe8\x0e\xa4I\xdb\x08\xa1\x9an\x9a\xeeU\xaf\x94\xf2\xa8\xef\xbd\xaa\x14\xc5p\xeb\xa0:\xbd,F\xfd~5v\xbc\xc7j\x19T\x8b'9J\xf1\xc9\xd3cj\x0b\xbd\x07C{p\xec\xd8F>-\\\xf1\xbe\xd2\xc4e \x068e\x9a,\x91\x88\xceQ\x0d}\xc8t\x9a?K\x8b\xfd<\x80\xce!e\xe9\xc9z\x19\xa4\xb6e9\x1a\xc7-\x1d\xeb!\xe3t\xaap\x9b\xf7\x8e\x0b\x87\xd0\x1aA\xc2\x82\xd5:<\xcf\x91\x9c\x1e\x91=\"\x8e\x93\xab\x89\xe8\x0b\x92%\x86\x1e\xabj\x85\x88R \xe6\x0cm/t\xces\x911We\xd3\xf3o\x9f\xd9F\x82\xee\x9cYC\xa2\xee\xfc\x84\x9e\x8b\xc0\xd7\xe4\x15\xcak^\xbbx&\xf5\xec\xbc\xd2\xb1\xdfnO\x1d\x17\xcf\xa1\xf4\xd0\x14\xdb\x0b\xa7\xebG\xa1\xef\xa5\xf6\xdc^\xa0\x02\x9a\xc2\\<\x89\xce\xf2>\xdc0\x0b\xcc\x15<\x85\x9b\x13\x07\x96\xec\x9e\xd3\xc2\xc5\xb3\xf3l|Cke\xe2\xc2xM't1^\x1b\xf4j\xd2MK\x18B\xb2\xc9\xe6\xd9\x90\xe4<\xe4\x81\x83\xd6w\\Cr(\x0elRO\xb1\xc3\x95\xbd\x19\x88\x8d\x7f\"\xb5\xda\xdf;vl\x8b\xd6n\xb9[\x88\xc65f\xb8\xc0\x8e\xa9`[Fp M7\x19E=\xf5\xda\xf9\xdc\xfe\x89A\xefv\x928\x1f\xda_xW^\xe2\xc7\xc1:\xbd\x9dy\xa9\xe7\xec\x04+u\xd4;\xe3\xcf'\xd7\x83^gr}\xf8b\xbasY-\x12\xb1:\xc7\x9f\x0f\xa7mg\xb8s\xb9RI\xdd\xd8\xeaZ.X;\xb2\xef\xb9\x19K\x12/\x0c\xd2\xe0K\xf2\x83x\xd9t\xf3@\xd8\x92\x98R5\x15\xd7~\xe8Y\xce\xd2y\xb4n\xb4\x12 k\x95\x85\xde>\x1d\xf7\xa6\x0e<\x85\x8e&'\x95\xed9\xdc\xd6\x84\x8a{\xaf\xbb\xa2\xd2\xb3\x1d9\x8e\xb0-1\x0bm\xdcMI\x922\x15\x8e\xe5]DY:\xbcXz\xe1[\x0b\x86\xe0a\xc4<\x19hB\x81M0\xa0\xc0\xe3\xdd=\xbd@\xb4\xbb\xbf\xeblc\x1e\xc6`\xf8\xdd4\xfa$zG\xe2\xe7^Bl\x0c\xd1\xda\xa6C\xa6t \x03\x96W\xe3\x9e\x1a$\xaa`\xbb!\xec\xe9\xc3:\xf4\x0f\xef\x1e\x98\x027Yy4[\xcaUE\xf7\x0e\xaa h\xf8\x04\xefU\xb98\x93\x05\xaad\x8f\x89\x02\x87U\x81\xc2\x03\xae\xfeS%\x81\x98N\xb8\x14\x93e\xc8\x05\xcarIf 8\x85\xa4+\xf2\x87\xe5\x05\xebg\x0d\xb3\x12V\xe6\x0d\x03k\xf2\xa4\x8e\xfal\x80\xaa\xc2<\x92\x93\x1b\x06<\xdfX\x1b,K-\x9a\xc9E}8\x05_\xa4\xfb\xa3\x9b\xa2\xf2\x82\xe0\xc1DS\x19\xaf\xc2\xeaa/\xc3B\x15;\x1aA\xc7\xa3\xdb\xae\xd3\xa3\xbb\xad)~\x80\x89\x9dm.!t\xfa\xdc7\x83\x07\xc1K\xb9\xa2\xb9l\xf2f\n\x90\xd89\x81v;\x84'\x10\x9f8\x10\xf0\x00\x83<\xbcv\xa8\xe6\xc6\x16s\xfa\xa0\x18\xcb9\xa5!~.Z\xed*\xc7\x11\x15\x8f\x83\x1c\xd7TdfX+\xe5\xb2\xdb\x10\x1d\xcd\x87\xac\x88\xdf\xde\xc6\xf0\xa4\xa5\x12 \xae\x86(qW\xf5\xda\x86\x94G$5\xe8m\xc4\xccUB\xd8\x95\xb4$\xef\x95.\x06h\xdbf]\xd4/`\xcc\x9d\x06NE\x07B\x18\xc2\x8c,IJ\x10R\x8ap\xd8\x8c\xa8\x02\xf5\xaa+\x99O\xfa\xb6\x13-D@1\x88\xbb\xe2\xdb\xee^\x95\xe8 \n\xaeO\x92\xb5\xbb\xaf\xcb\x92\x85\x8c\xe0\x8eC\xc8\x0bhu\x83\x04%zSx\x01:\xa5\x01c\xda\x11\xa3H:r+>\xcc]\xe5\x149>\xe5\x88hZF\xb3\xb2\xbe|\xc2\xcb\xc7v\xe8B_:\x9e\xd0w\x93e\xe0\x13\xbb&\x91\xb27N\xa76\xa5\xaaI\x193\xef\xbeR&-H\x93\xa8 0^\xefe!0)\xdfd\xdc\xd7\xe1\x14\x02J\x8dQK\xf9\xe8\x11\x84\xf0\x94\xd9\xf4R<\xd7\x88\xa6\xb6\xd8\x03\xdbv9f\xa4Z\x99_\xf3P\x98YOx\xfbt\x08<\xc5\x1eS\xda\x1e@\x1b\xbd6P\n\x0c\xf9\x03\x1c\xa0\x93\xbf\x84a\xfc\x02\x87\x91\x7f\xfar\xc8_\x0e\xa1\x83\xceXO\xa1\xe7\xb2/#\xad\xd9\xf0\x8aG\xbc`\xac#@\xd6\x11\xc3\x13\x08N\x1c\x88Xh\xb1t\x1c\xd3\x9e\xe8\xfd\x11\xa3;\xe3\xc6~u\xb76\xed\xe2A#.\x19\xe5\xb3\x94m\xb7\x94\x1dp\x1bIO3\n\x18ZJ\x0b\x15\xc4\x16M\x08\xb2`\x8d'\x93lv\xd4\xebu\xe8\xdf\xf9|>\xad\xb8\xa3\xc7\xa2Po\x97\x15\xea\xed\x1e\xcc'\x93lN\x06\xf8sN\x06\xf4\xe7\xa07\xc3\x9f\x83\x9eZ\x05\x9dd\x0b\x9b\xd9\xf5\xc7\xac\x99\x0bSs\xe8\xd85\xfe\xbc\xa1S\xe8\xc3e\x9f\x0e\xe5Jg\xe4\x00\x8b\xcf\xe6\xf3\xa9\xf3\xd5\xe0\xbd\xa52\xf0\xf2`/\xe6\xf3)\x02|sC o(\xcfk~\x9b\xe7Fw,\x16\x89A\x95Y\xb1\x999\xe9\x11\xf6g>=\x15i\xefm\xde\xe9A\xaf7\xe3\xb5\x8e\xb9G\xcd\x94\xd3\xcd[\x0bEL\xc7X\x87\xe5|XU\xff\xce\xa5^\x8e#\xd1\xd5S+\x0f\xed\xe6BX\xad\xbf\xd2\xef%\x8cx\xb6X\x1bGg\x9f\x8e\x8a\x91\xe2\xa0\xe7\xd0\x06\xdf\x05\xeb\xd2\xba\xeb\x9eH\xf9\xa9r\xe9\xb0+\xc2w\xdf\xc6\xd5s\x898\x10V\xa3\x01\x8am\xac;\xb1\xf0\xd1Z\xe3\xc7\xff\xe5\xe7~mj\xddkd\xf5\xccY\xc8JvdS.\x9c\x1f\xf13<\xe2;\x18\xb7\xc72\xdb=\x1a\xf7rC\x02U\x13\x9f\xd31\x8d\xa8F\xde\xd7Pr\x14\xff\xa2\xdc\xdf/\x1d\xb7\xdb\xc1\x14\xe9y\x00O :q\xd81\x87\n\x06\xe98\x98\xa2\xeb\x8dA\x92l:\xcf\xd4`\x83A\xcfU=s\xa3\x96g<\xb9\xf6{\x9d\xc9\xf5\xec`r=;\xeaL\xae\xe7\x07\x93\xeb9~\x99O\xb2^\x9f\x92\x82\xac\xd7?\x9cOw.kpf[zx\x1f\xe4\xb2S\x14\xdfR\xc7a\x96q\x81>\x11]\xdb\n2\xdd}\x12\x0f\x9dJ\x90\x03\xebG?g\x0d\xc1zV!\x14\xd6\x8f\xfe\x96\x1e\xfc\xb7\xf5\xe0\xbf\xa3\x07\xff\x8fz\xf0\xcf\xeb\xc1\xbfI\xc1\x9e\x02\xfe-=\xf8\xdf\xe8\xc1\xffV\x0f\xfewz\xf0\xbf\xd7\x83\xff\x1e\x05?W\xc0\xbfC\xc1\xbe\x02\xfe'\x14\\M\x91j\xfd\xe8\x0f)x\xa6\x80\x7f\x81\x82\xab D\xad\x1f\xfd}=\xf8\x17\xf5\xe0_\xd2\x83\xff\x17\n&\n\xf8\x7f\xd5\x83\x7fW\x0f\xfe==\xf8\x1fP\xf0K\x05\xfc\x0f\xf5\xe0\x7f\xa4\x07\xffc=\xf8\xf7)8P\xc0\xffA\x0f\xfe\x03=\xf8?\xea\xc1\xbfL\xc1\xaf\x14\xf0\x1fQp\xf5\n\xab\xf5\xa3\xff\x89\x82_+\xe0\xffY\x0f\xfe\xa7z\xf0?\xd3\x83\x7fE\x0f\xfeU=\xf8?Qp\xa4\x80\xff\xb3\x1e\xfc\xbf\xe9\xc1\xff\xbb\x1e\xfc\x7f\xe8\xc1\x7f\xac\x07\xff\x1a\x05\xff@\x01\xff\x0b=\xf8_\xea\xc1\xffJ\x0f\xfe\xbf(8S\xc0\xff\xb7\x1e\xfc'z\xf0\x9f\xea\xc1\xff\x9a\x82\xab d\xad\x1f\xfd\x19\x05\xdf(\xe0\xbf\xd0\x83\xff.\x05?S\xb7\xc3oS\xb8\xa7\xc2\x7f\x9d\xc2\xdf,\x14\xf8\x9fSx\xaa\xc2\x7f\x83\xc2\x93jH#\xebk=Y\xfeZO\x7f\xbf\xd6\x13\xda\xaf\x91\x88+\xe4\xed\xeb\xbf\xa3\x07\xff\xbc\x1e\x8c3\xa0\x10\xc3\xaf\x7fA\x0f\xfeE=\xf8\x1f\xe8\xc1Hh\x15\x8a\xfa\xf5\xdf\xd7\x83\x7fI\x0f\xfe\x87z0\x92 \x85,\x7f\xad\xa7\xd6_#eR\xa8\xf5\xd7\xbf\xac\x07#\x99P\xe8\xef\xd7\xffT\x0f\xfe\x15=\xf8W\xf5\xe0\x7f\xa1\x07# R\xf0\xed\xeb\x7f\xa6\x07\xffs=\xf8\xd7\xf4\xe0\x7f\xa9\x07\xe3\x9e\xfd\xab\n\xf8\xd7\xf5\xe0\xdf\xd4\x83\xff\x8d\x1e\x8c\x9b\xf3R\x01\xff\x86\x1e\xfc[z\xf0\xbf\xd5\x83\x91\xd9\xff5\x05\xfc\xdbz0\xca\x00\xca\xc6\xfc\xfaw\xf4`d\xb1\n\x07\xfb\xfaw\xf5\xe0\xdf\xd7\x83\xff@\x0f\xfeC=\x18\xd9\xb7\xc2\xd8\xbe\xfe==X\xcf4\xbf\xd6s\xc7\xaf\xffH\x0fFv\xf2\x93\n\x18\xd9\xc9\x17\n\x18\xd9\xc9_W\xc0\xff'\x05\xbfU\xc0\x7f\xac\x07#'\xf8D\x01\xff\x89\x1e\xfcgz\xf0_h\xc1\xdf\xfc-}i\xe42\xd5\x981\xd6\xd7\x7f\xaa\x07\xff\xb9\x16\xfc\xcd\xcf\xe9\xc1\x7f[\x0fF\xd2\xabH#\xdf\xfc\xbc\x1e\xfc\xf7\xf4\xe0_\xd4\x83\x91 (\"\xcd7\x7fW\x0f\xfe\x05=\xf8\x97\xf4`\xa4\xdf\x8a\x90\xf2\xcd?\xd2\x83\xff\x89\x1e\x8c\x84Z\x91/\xbe\xf9\xc7z\xf0/\xeb\xc1Hc?S\xc0\xbf\xa2\x07\xff\xaa\x1e\x8cT\xb3\x1a\x93\xc1\xfa\xe6\x9f\xeb\xc1\xbf\xa6\x07#\xa1>S\xc0\xffJ\x0f\xfeu=\xf87\xf5`\xa4\xc8\x8aT\xf0\xcd\xbf\xd6\x83\x7fC\x0f\xfe-=\x18)\xf2\x1b\x05\xfc\xef\xf4\xe0\xdf\xd6\x83\x91\xf4VC\xe4X\xdf\xfc{=\xf8w\xf4`$\xa6\x8aP\xf8\xcd\xef\xea\xc1\xbf\xaf\x07\xff\x81\x1e\xfc\x87z\xf0\x7f\xd2\x83\x91\xc6*\"\xe47\xbf\xa7\x07\xff\x07=\xf8?\xea\xc1\x7f\xa4\x07\xffg=\x18I\xef\x0f\x150\x92\xdew\n\x18I\xaf\"\xe3~\x83\xa4W\x11f\xbf\xf9c}i$\xbd?\xa3\x80\xffD\x0f\xfe3=\x18\x89\xe9\x97\n\xf8O\xf5\xe0?\xd7\x82\xbf\xc6\xd5y\xa92\x1e\x9c\xab@\xe1<\xdf\xb0\xe3\x9a\"\xb9|\x83\xc2R\xa4\xc2Q\xb0|\xac\x927\xe4\x1bI\xe1\xcab\xf2\x08a\x8ex\xdb\xab\xe9\xee\xa3Q\x945u\xdc(5\x84tL\xa6\xa5\x17\x9aT\x895J!\x83_\xc8\x81>\x1d\x89\xa2q\xcbx\xf1~\xa3\xeaKo\xde\x12zc\xbcK\x92\xf2\xe4\xdd\xdc\xf2\xc6\x9c\x92\xe4\x81\xa3}\x93\xdb]\xb2\xc2\xee\x82\x1aL\xa6x&\x9b)\x9euv\x12\xf4 \xeb\xf5:\x93\xeb\xc1|r\xbd\xebu&\xd7{\xbd\xc9\xf5\xfeEgr}\xd0\x9b\\\x1f\xd2/\x87\xf3i{\xe7\xae6j\xd1\xc9\xf0>\x9d\xf4:_N\xc7\xcf:?3\xbd\xc5\xff\xbf\x1a\xb8\xef\x11v;\xeeu\x8e\xa7\xf4+{\xc8\xbf \xf4v\xfc9\xfb\xd9\xeb\x1c\xc3t\xe7\x8e\xdd\x0f\x99g\xd8Vv\xae\xdc\x085\x99\\{\xfedr}\xd1\x9fL\xaeg\x87\x93\xc9\xf5\x9c\xfe\x87\nV:\xe1l\xc6q\xca\xd9\x9c\xe3\xa4\xb3Y\x9f\\_0\x85k\x8f+\\\x0f\xe60\x99\xa4\xf4\xf5\x8b\xc9\x84\xbe\xeb\xf5P/;\x9fO&\xe1d\x12c\xa1\xc1\x11\xfbs<\x99d\xfd\x83#Z\xa2\x7f\x84\xd6\x16Z\x11\xfb\xd3g\x7f\x06\xec\xcf.\xfb\xb3\xc7\xfe\xec\xb3?\x07\xec\xcf!\xfb\xc3\xea\xec\x1d\xb3?\x1ek\x81un\x9f\xfe\xd9\xed\xf5\xaaq\xae\x98y\xcd\x826\x0b\xecm0\x9d\xcd\xda\x96\xba\xe1P\x0b=8\xe4\xc3>\xbc\xd0[\xc9\xe8R\xd3I\x9d\xd3\x99\x9a\x1fL\x98\xb6{r\xad\xda\xba<\xad\xe9Mt\x0d-A\x95\x06\x8dU?\xeb\xfc\xcc\x84)\xdaQ\xd3\xceT\xed\x93\xeb\x191\xd9\xd7\xb60\xe4\xf9w2\xe4\xa1\x89l\xbcq\xbf\x96\x92E-\xcb\xed~\x9e\xcer\xb6\x96\x8a\xce\xeb\x8b.x\xd1-\xcd\x07\xb7&\xdb\xa9S\xb5>\xce\x8c\xd6\xc7\x85\xc1\xfa\xa8\xb5\xb5\xe2\x1d\xe8\x8d\x0c\x92\x0b\xbdA\xf2\xaad\x90\xd4\xd7G\x9f\xcd\xca\xaf\xdd\x14&\x96\xf1<\x8fs\x8f\xf3\xdf\xa6\xd3\x86\x96:\xfbt8\xbb].oW\xb71\xb9Mn\xd3\xdb+\xe28\xa7\xdc^9\x8e]\x98\xbb`}`\xa9\xf6NX+\x15}t\xfb\xc9'\xb7\x9f\xde~\xf6\xe2\xf6\xec\xf6\xcd\xedO\xbd\xa8T\x04mX\x9a*+\xfa\xb7\xdc\xa4\x7f\xe2\x8d\xa6\xe6-\x17\xf7\xfb\x87\xf6\xe9\xb0\x7f\xf6\xe6v\xf0\xea\xa3\xdb\xdd\xcf>\xba\xb5O[\xe3\xfe`w\xeaL&\xb37\x7f\xcd\xb1OG\x93\xc9\x05\x92\xf1\xf3\xa9#\xbf\x93\xa4\xb7\x83pv\xbb\x1b\xcfJ\xef\xa4\x8b\xfc\x9dg\x9d\x9fa\xef\x04.\\I\x03\xbb\x97\x8dJ0\xaf\x9b\xcd\x98\x97Y\xe48\xa8\xe6\xf4a\"\xc7a\xd5\x05\x98'@\xeb7:\xd0V;\xcc\x82l\x06_\x12vw\x9b\xe7\xc6\x9cy\xa9w\xae\xcf\x7f\xba\xf0\x92\xc5\x10o\xb6\xc5\xae\xf2p\xe5\xad\xf1\x99\x1d\xd1q\x07\x1a\x0f)\x91f\x0b+(=\xbd\xbb\\\xa6\\\xc6\x11rYU^\xe3\xf6o\xc55\x97\x0bf\x8a\xdb\x8b\xc7\xe1\x03\xed\x9d\xdd\xc4\xec\xc8\xa8\xb3%\x87\xdb\xd9\x92Y\xd6\xcc%\xf1b\x1b-\xc8\x04\x03\xb9\xe8\xa4_1\x13T\xd2U\xfd\xcaD\x18\x7f;f\x1e\xeb\xe3\xfe\xb4\xde\xb4N?\x89\x9c\x0b\x92\xf6\x81e\xed\x92\xc1\xdc\xab\x11\x13x\xca\xf0K\x82\xf2i\x19\xb8\xf0(\x12fe`\x82%\xbd\xf2\x1d\x8f-/u\x1c6\xca\xd2Z\x84\x970\xb5\x9d\xf1d\xfa\xd5\xfb\xdb\xe9\xce%\xd2\xf1\x0f\x1eYR\xb1r3\xb7\xf9}\x07\xa7\xfb\xe1)R\xf4\x89\xed\xdc\xe2\x06\xea\xb69`\xea`M\x1f\xf4\xbb\x1f\x9e2~\xf5\xc1\x9d\xe9z\xcbn\xa1\x0b\x1b%n\xc2\x03\x01o\x1e`\x18\x8d!x\x0e\x13\xfb\xb3\xd2\x8d\x9f\xcdQ'\xcf\xe5\xa6$\xbe\xccs\xb9\xed\x8c?\xefN\xdb\x1f\xect\xc95\xf1m\x8cR\x16\xe0m\xa8\xe2[\xf7\xe5\x8b\xf3\xef\x7f\xf6\xfa\xcdk\xbc\x87j\xe1\xa5\x15\x8b\xdf\xf6Kb\xdf9\xefw\x99\x03W\xd9\x15\x7f\xbb\x99hE\xcc\xd9%\x08\xb7M\xfa)\xed^gl\x9d\x9f\xfbQL:_$\xe7\xc9\xc2\x8b\xc9\xec\xfc\xdct\xa7\xe8\xae*\x05\x8dc\xff\xc6\n\x83\xe6C\xdbf\xb3&\x18\x03\xd2\x96\x85\x87\xac\xe3\xd1\xa3\xdc5\\\xa6I\xe3T\xef\xe6Y\x90\xa5\x0e\x0b\x1e\xc6c\xc6\x90;\xcf\xbe\xce\xfb\xd3:?_F3/Y\x9cSF\x7f\x9e\xc7\x94;?\xd7\x1c\xb9\x14\xbf\xf4\xf2\xf6\xdc\x16\xb5J\x93$\xa6\xa3<\x17\xc1\x1cl\xc5\x83\x0b\xa4\xb33Q\xa6\x0fJ\xde\xca<\xc4P\xbe\xdau\x99\xf4\x85\x7f-\xbf\xba\x82\xd7]N\xd9\x8dU\xe12\xfe\xa0s\xff\xe3\x9f\xce\xfc\xda\xc2i\xf9\n;\x8e0\x90\xc6\xfd\xa0\xe3\xac\xc1\xb1\xa61j\xf6\xb2X\xf9\xe6a\x16;\xa8]\xde\x89L\x18\xeb\xbb\x10\xb2\xdb\xc8\xe8\xc7')\xd7\x08\xf7\xfa&L8\xb8/uh\x12I\xc6\xd3\x07\x12B\xb42\x08\x0b\xd5\"\x89a\xebe\xe0\x93\xa6\x89\xdf\x08\xb9\xf4Bo\xccPH\xbb$-;\x14\xc1\xb6l\xba;\x8b\x04i\x1d\x8c\x1aE\xba\xebh\x8d\xa9\xda\x0bl\xc4k\x15.t:\xf9\x1c\xb9\xd0\xbb\x13\xbb\x15\x93\xf4\x974\xf8\x90\xc7\x13+T\xb6\xe3p:\xee7q\x9f\x87\x1cI\xee\x8b[\x1e\n\xa5t\xa5\x9b\xb1\x0f\xdf\x93Mw\xb2:\xad\x18q\xca\xae\xb9E\xc7\xa7\xd5n\xb7%\x0c\xe1at\xc6\xb4\xe1)^\xb3\x0f\xc7\x01\x9dm\x96\xe0~\x83}m\x1e\xed~\xe3hM\x18\x14\x8bT\xa5\x0e?P\x99n\x96\xdd\x95\xfb7\x12#3r\xb3\x1b\xa1\xa9\xb6;\xf2\xd5Q\x8clb\xb1\xac\xdb\x12\x80e\xcd\x96\x00\x17Q\xb4$^\xc8!\xa7\x94\x0d\xf0T\xae\x16\xb2\x9d\x94\xae \x93\xc8F\xf7\x90)\xb7_\x8c\xd2&\xc0\xb5\xb8$\x1b\xa8\xee\xbf\xdd.0\xd6\xf4-v\xa1f\x03\x16\xdd\xd0\xef\xbe\x101QO\xd3P\xd7\x80\x95\xbbe\x86\x1brv6\xcaoW\xf5\xef\xb7\xedv\x8f\xf6\x1c;\xb4\xf7v\x0f\x9c\xad\x8c\x90\xe63{_\x7f\x1f\xeaPw\x18\x0b\xed\xc3\x83\xc696,s^\x80q\xb3\xcc$\xd0zE\xe0!\xdd]F*\x0c\xb7\x02\xbci\xad\xbe/\xeaH\x04\xb5\xdc\xd5\xd4\x00\xfc\xaed\x84\xe1*\xc3\xda\xbe\xcb\x1f>\x8e\xc4\xf6\xc6\xe9\x14/lx\x86l\x17\nT\x85\xd0^\xfa\x94\xe0\xe4\xd3a\x14\xe0}\xe4Jp\n\xde8AQ\xdc\xa7\x82\xaa\xaf\x91\xc7\x01\xee\xa3Q<2\xdc\xa1P\xe2\xf8p\xbd\xeb\xd1\xde\xd6\xa8 \xc8l`\xa2\xf8\xfd\x928\xf4\xe8\x11\xa6*\x18\x0f\xa6\xec\xd6*\xfd\xde\x9b\xba\x0c\xd8\x9fR~\x96\xb7\xa5\x18\x8e\xa1z\x04J)Af<\xd4Ub<\xdcu\xd6\xfa\x87\xd5\xfbF\xe2:\xa1N\xe5\xd5W\xd5]\x83\xa69\x14wx<\xddd&H\x98\xf8]|e\xf8\x18\xba+`i3b=\xe5\xa3\x0d{\x0e\x96\xbc\xc1(M\x0b\x17f.\xac\xd9\xaep\xe1\xca@1\x91\xee\xca]\xbeAO\x8b\x99\x0b\x0b\x17\"\xb8\xe5w\x0c\xaf\xe8\xa6\xbc\xa9\x1fA\xcd\n\x8a\xb7\xee~\xfak\xbc\xad[]\x91\xeaA\x94Yy\xb6:\x8b\xdeC\xdel>L\x91\x8d\x85dZ\x96\xcb\xfd\x0f\xdea\xb91\xd1\xdf\xcd$\xc6\x07j\xeb\x9e\xa2\xa1>|P\xbf\xaf\xf7b\xea\xf7\xaaV4$\xd5\xbd\xc6 \x1f\x9b\x1e\xf04\xc4\x17D\xf4\xcbh\xae\xde\xd7\x04I8\n\x0d\xb5@.\x1dQF\xe7 &\xfa\x042\x16C\x9aO\xabW:\x13\x96\x11\xbd\xdd\x0e9\x06Q\xa8Z\xbd2\x0e\x10)z<\x13?\x85F1YH\xc9\xf7\x13\x8c\xcd\x8cX/\xc8\xee\x1e\xeb=\xd5\xf6zz\x83\xe8^\xbf\x8a\x12\xc8{\x95@H>\x17\x8e\xaa\x885\xe7\xf0*\".U\xb1\x00\xbdI\x84\xad\xeb\x99\x08\xa2WuOY\x94K\xc5\xdeM\xb5\xc4L.\xc18v\xb5\xc8\xd5\xfd5\xb0B>\xb9q\xe1\xd2\x85\x95\x0e\xfd)\x9a$\xdalT\x17\xf8\x84h\x9e\xbc\x83\x11\x9c\xc3),`\x08\x9e\xf6\xddk\x18\xc1E^BW\xc7\x19e\xf4\xb4\xa2wT\xacY\xc3)\xcc`\x08\xef\x1c\xfak\xa6\x16\x7fA\x8b\xd3Z\xaf\xe5\xe2\xd7\xa6\xe2\xcfD\xc5\xd7\xean~F\xf9\xb9\x8f\xd62u#\xe3&\xf5\xe5`Q\xad\xbe\xba\xd7\xcey\\\xe23\x0c\xd5\\\xb3\xbb\xf2\xf6Zgy\x85+T.\xae\x04;s\\8\xa7\x909S\xfc\x06\x9aU\x1bB\xc4\xa1\xefJ\x0f\xd4\xb1\xb5\xec\x10\x1ea\x90|=\x8dz\x0d#8Cer\x1e\xd9\xc8:?g\x89\x0eg\xe7\xe7\xa6\x0c\xd3_\xc0\x08^H\xaf\x91\xeakzj\x87\xf6\xbe/\xea\x0e\x83o)\x8e\xc3)\xa4,\x984*Vk2H\xbe\x84\x11|\x81Z\xd8\xa28\xd1\xcbD\xc6\xc9\xbe\xb4\xdf\xba\xf0R\xcc\xe3J=&n\"\x03\xb5pQm\xb5\xf6L]\xbe;3F\x95\xd3qc\xec\xb1\xfe\xd4\xb7{\xbc\xaf\xf5\x0b\xc9\xbe}\xbf\x90\xaa\x8c&;\x88`\x01o6\xb3\xd31\x99V'\x83~2\x89\xbey\xb3\x19\x06\xb5* \x94#2\xaf\x8eLq\xe0\x88\xca\xbe\x1a\x99v~\xab\x93\x1b\xde\xcf\xe2\xb3\x91D\xc4\x99i\xe8l\xc48\x7f\x9cbXs[f\xf3t\x8aM\x90\xa6&\x8c\x08m\x8acx\xac\x8fi\xac\xb8\x9ad\x06\xa9\x81\xbbE\x1d\xeb\xa5\x80\xbd^\x95\xdf\xfb*_\xa7\"\xc0@\xe5\xfe9\x8b\xfe\x1e\xd3\x15WytI\x1c\xf8\xc8K\x15G\xd5\x92$\x80a\xd7k%\x81O\xbd\xb5N\x0c\xc8\x9f\xbfB\xa5v\xb5\xc8\x8d\\\x849\xb6T\x8b\\\xcaE\xce\x88\"l\xacJ\xcfQ\x97^-r^*\x82\xca\xf4j\x91\x0bE\xee\xf9^6\x9f\xab\x1d~W\x996\xef\xa7\x02\xf2\xaeZ\xe8z\xe3@\x94g(\x17\x9c\xc25c\x0b\xaf\xe7\x1b\x07\xfe\x13\xb4:v\xe1\xda\x85\x17.<\xab\xa2~\xf2.\xc0\x08|Z\x1d\x96\xef%\x04\xde\x0d\x158p\x06\x98\xcayA[\xa3r\x9e\xd0\xdb[`\xcf_\xcf\xe7 I\x8b\xe7\xecw\xad\x00B?)\x06\x10\xbb\xc0 vy\xf4T\xf6K-\x8f\x1d\xbd\xd0w4\xb7|6\xf5\xb6\xf5\xc2\xa6\xc4=\xc0\xab\x1e\xec\x1bqtY\xbf\xb1\xb5\xa5\xda\x1a\xc2\xd7\x06\xf8Um\xef\"\xbb\x9d\xba\xd0\xd6i\x9d\xf1\xedE\xed\xdbi7\xf4V\x84\xe9/\xf1\x1b\x06jY\x91$\xf1.9\x98\xff0T\x7fc\xe8\xf4\xaa\xbeYfYR\x83\x88\xe6\xef\xcf\xf4\xef\x0bQ\xcd3\xbcvi~\xed\x0b\xe6.P\xcd\x1d&>\xb9Xf\xd3\xfa\x13\x0ch\x8d'\xbd\x96\xd0P\xa0\xb4\xfaE#\xf6 \xe9\xed\x19\xd74\x98\x9b{\x9b\xd7\xf5\x16\xe7\xc3 \xaf\xc1\xed\x08\xe6.<+\x0e\xa2\xe6\x86_b8\xc5\xd7\x88\x88\xaf\xd1T m\xe0Zy\xf0Y\xa1\xb1q\xe1\xa5az\xcf\xcd;\xba\x10\xe3\xcfD\xccJ:\xa83\x11M\xb6\xf4\xa2^v\xbc\xbb\x11\xdb\xe9\x16 3\xf5\x94\xed\xae.i\xdb\xca\x87<\xad\x0e\"\x8cA\xf5\xa5\x89\xb7\xaf v\x85\x15\x8e\xdbm2\x85\x11:\xf5\xa7\x95\xcbq\xce\xb7\xa11\xfbv\x86W;65\xa1@\xd3\xb0\x8cx\xb0\xd7\xd3i\xcc\xfa\xaa\x08\xf5@\xda\x03\x9ewO7\x89\xa8Q\x81G\x10\xa8\xf38gv[\xcd\x89\x123\xef\x19S\xa5.1m\x82M\x1c\xc9\xd2\xd4\xf2\x8d\xf4\xa8Hm\x00#X\x9e\xc0\xba\xc6\xe4\x81\xb9\xb9\xc7k\x83]\xa0e\xfb\xa8\xb1\xc0\xdc(C\xc9\xcbn\xe1lh\xe3\xa0m\xcc\xd03YG\x13i\x1b3\x96[\x88>\x96T\x0c3\x0d]\x14\xe6\x82V%Bg\"+\xea\xd8\x0f\x8dCO>+T4\xf4\xe9il\x0dO`i\x9c\x99K\xb4\xa7\x88\xf91\x98UV\xe8\xce\xb80L_\xe6\xe4\xfa$\x1fox\xae\xf0\xfc\xbb@,J\x11\x7f\x86\x90\xd9\xf4H\x8cP\x86^\x89\xc9\x8c,\x9b3\xce\xe1\x94\xf6p4b\xc7y\x8fW\xc2P\x13\xeb=7\x9b\x9cQE\xa3\xe7 \x171\xf1\xde*OT\x83\xf0\x0d2L\x94\xb2\xfd\xc2\xb7\x1d\xfdF\x16u\x14\x1f\x0dI\x88\xbf7\xa6\x89\xbf@!N\xaaU?\xf5\xefP\xba\x93\x8a\xa9\x03\xba\xa0\xfb\xe6\x1dm\xad\xdc\xc9\x80\xa7lS\xa0\x8c\xd3\xdb\x96\xd8\xf0r\xd8\xf5\x0b\xfa\xecBV{#D[\x16\xdb|'\x97}\xc7\xfc\xd0\xd9\xd4o\xc0\x12\x13\x99)\xe7?(\x82o\x99\x88P\xa6\x91\xfa\xeb\x0e{=}\x0c\xca\xbb\xfbN`\x10\xe1\xc8\x85\xe0\xce\xc7\xe2\xbd\x9e\xfe\xbe\xd0Qc\x97\xd4ZE\xcd\x11\x8b\xefnpHc\xaa\xc6\x08o`G.\x84\x1b\xdc\x0ehf\xb2\x1a\xbd\x816^=)\xc5\xa7\xcf5KR|\xfat\x1c@\x1bX\x8c\xfaqh\xf0>\xbf\xfbl\x9b\xf2\xae\xe8\x8c\x11\n\x0b]s\xe6\xf92y\x11f+\x96\xb0K\xd5R\xf0\xd7.I*\xf1[vfNT\xddEV\xca\x0c\xa4#\x15\xc2J#\xa9\xe5\xc6S\x18V\x0c\xfe.\xc46\xcb\x1b\x94\xd7\xa6\x0dO \xd5XD\xb8'\x1aMh5K\x0c\x0c!\xd0\xe3\xa4\xf7-#M}\x92\x83\x9e\xc8\xe9/c\x91\x9e\xe0f,\x0f\xbf\x86\x89a\x8cN\xf4\xe2D\xea\x15\x8d\x83v\x1b\x13\xc4o@\xc1\x9aB^7N\x84\x81\xb8\xdc\xfd\xa6\xe6\x9eAy\xdc?\xd4_B\xd4'\x0dQme<\x81X\xbf*\x82&\x06\x1b\x9a\xee.\xd7\xf6r\xa8\x8e\xc4\x85\"\xec\x84\xb2\x92\xe8D\x83\xa99\x02\xa3\x00\xca\x9e\xb7\xd0\x19$\xd3\x96ZWJ\xb5\x96(\xbci\xcb.P\x0e\xbe\xbd\x859\xfdoI\xff[\xab\xa5f\x98\xb3\xfc\x94\xb2\x8c\x1c}\x99\xae\x8d\xca0\xba\x9c\xa1r\xce-\xa3\x84\x87~)<\xbe}\xcb\xcf74\xbb\xeb\x8b\xf2\xb3m\xb1*\x90m\xdf\xb0.\"8BUS\x01\xb6\xd6^LB\x0e\xc0\xf7\xd7\xac S,I\x05\x0b\xd5P\x05\xf8Z\xaa\xd2a\xe2\xda\x8d\x0bW\x0e~\x9f1\x03\xf7\x8d\x9e/\xcd\xee\xbb\x8b6&'\"-\xac\xa0\x17\xe9\x89\x03\xb1\xc8\x8a\x12\xea{\x17\xdfy+\xeasS\xec\xe96\xa2\xce\xb6\xdc\xb4?\x0c\xb4#\xe0w\xbab\xae\xa3\xf8\xb6h\xd4\xdd\x15\x1a\xa6\xa4\x1d\xfd\xaa\xec\x16\xe9',\xc3d\x82\xc5\xf4d\xe3|\xfa>^F^\xba;\xe0\xb6w$\xe3\x95\x87\x07{\xfa\x87/\x85\x86E\xf7\xa4\x7f`|dj\xacP\xd9\xe8\x1f=_z\xab5\x99\x99K\x98\xda\xa4\xcfJ\x8db\xa6\xdc\xb1\x0e\x83*o\xea\xeb+\xe9\xeb+\xcfr\xf3G\x05^\xe8\xee\xd5\x07D\x01r\xfbGu58\xae(\x0f\xd0\x18R\x81 \x03H\x05,<(*`a\x0b\xa9\x80\xd1\xfeQ\x85q\x9bG\x05\xfcC\xe2\xbd\xcd\xfb\xd1\xea\xbb\xdbm\xc1\x88o\xc1 '\xf8\xf8\xb3\xd5\xca\xc6tW61\xf7\xc6\x1d\xd9\xec\xcf]#L\xa6fu\xe5F\xfb\xb8F\xf3Ul\xf1\xbeb\xf3\x03\xbe\xcf-6\xc3\xa5d_tr\x18\x1b#\xdd0\x9a\x9177k\x06S\xab\xc0tQx&U\xeba)\xca\xb1\x9e\xb4T\x8f\xc6\xb5\x80\xd2\x10vs\xb8\x98\xe0\x11\xaf\x1a-O>I4~\xba^\x1da\x14\x9f\xfa\xc4\xd3W\xb6+\\Q\x95\xfe\xb1\x98S\\\x8b\xb3\xfbG}'?Zn\xce\x15\xfa\x86\x03Z\x7f\xa3\x03\xdav\xb2eu\xe9P\xf7\x14\xcb \xe3U\x7fx\xa1=\x1eO\x0d\"YHE\xb2\"\x85\xbct\xc8\nq\xff\x97U1-\x9eF\x8e\xb9:\x98\xa4\x8fm\xeeU]\x19\xd2tm;\x19b\xa0<\xe5\xbfQ\xfd$\x99\xbbF\xa0W(\x11>\xc2\xdc\x92{{\xdb\x9cv\xa9\x06E\x8eD\x8e~\x0c0\xe0\xf2\xa1nu\xed\xa6\x99\xba\x9a=!\xf22uW\x1bR\x9b\xca\x92\xf7\xa2\xb1\xd2\x90\x07\x86\x84\xd0\x067\xd9\xbdA\xd5W\x92\xfbP\x0e\xaa'4\xeeC9\xa8\n]\x89^F\xe3N\x94\x8as\x06=t\xf9v\\\x81b0\x0e\xbb\x1axg\x8d\xd0\xa8\x02] 4\xab@g\x08\xad\xe6\xdf\xa3\x07#\x89 \xb2L'\x1a\xb1\x84\xee\xae+4[\xc7\xf8\xbf$\xe4\xd8}\x87\x1dJ\x82\xd2\xbb\xc8\xed\x8b\xd7\x02,\x12\x95\x8a|?\x8eVABD1J\xae\x93hyElV_V*\x8c\xc2FQ_\xc6\xceD\xa5\"\xb9\x90Q\x14\xf3\x9cB\x87\xda\xbcA\xf5\x87\xd2P\xe7c*.;\x96\xb6sM\xc69\xc4>8\x05\x9f\xa2\xba\x9a*\x93\xc7?\x10^\x12Z\xfb\x1e\xdaT\xe7\xb5\x96r\xcd\xca\xa9\xdc\xce\xe4V\xa0\xab\x07\xa7\xd3P\x85\xc6\x03AWE\xbe\xca\x86j\xea]\x0e\xca\xebo\xa8\xc2`\xfe\xafV\x91\xe3\x87\x81\x94\x80\x96MT\x92U_mGovw\x1d;\xb4\x0f\x1d\x17,\xb1&\xa6(5[\xdej\x94j\xe6S\xfc\xf0\x15\x9f\x91\xf4\xe1+\xe5\xcb\xf0@\x15\xf7\x8f\x0c\xa1\xd4\xb6\xb7D\xe4\x82\x87\xb8\xbf\xe7\xf2\xdb)B\xb5\x1e\xd6\x18E#\xaeeW\xb7>p\xa6\x91\x8e#\x9d\xba\x94\xa9Kx~\xb4\xd8\xce\x1cSX[\xd8\\\x8a\xa9\xb9B`\xba\x01\xa9\x0f_\xb57\xd0)\x0b(\xbb\xd4\xc5\xaf\xd2\xad\x86PhV\xcb3\xfewXe\x8bs\xd5\x04\xbf\xdc\xf0\n\xa1A\xc6\xc8\xf8\xe1\xd1c\x99A\x13\xdb\xc7\x95%\xcdW+\x85\x9e;\xd0\x05%\x90Z\x90L\xac\xec\xd4\x90\x07\x17\x89\xd8\x9bh \"\xb8\xc0s\xb8\x85\xe5\x03\xc92\xfd\xa3\x8dn\x83\x1bL[\xb8\xf0\xba@I,\x9d\xa7^|\x96\x86\x1a\xc0)\xa6\xc1mJ|k\xe8\xfe\xce\xf8\xf3\xeex2\x9d\xb6o'c\xfbthwN'\xb3\xb6}:\x9ct'\xb3\xb6s\xea\xdc\xdac\xeb\xf1\xd4\xb1\xe9\xb3\xd3\xd6d\xe0\x8c?\x9fL\xa6\xb7\x93I\xd7\xf9\xf0\xd4\x99\x0c\x9c\xc9\xf4\xd6>\x1d\xe1\x1b\xb7\x93\xf1d\xea\x14_o?p\x9cj^3:\xdc\x9d\xc9\xc4\x9eL\x9c\xd3\xea3\x81\xebGN\x83\x1b\x8a\xe9\xc8\x02\xc5\x0c\xed\x1d\xb0\x9b\xb8\x98N\xf6y4#\x98RV:\x98X\x16r\x14\x11\xfa,.O\x17s\xa2\x8cLGa^GLq\xab\x94C\xff\x83>f\xa2E\xe5y\xaa3A\xc9!%\x18D\x8f:\xd16\x8bH \x8a\xce\x89f\xbf\xf9\x1a\x99I\x06C\xec\xab_\x05\x90,y\"\xf8\x00W5\x84\"\xb4\xa2[\xf1\x14\x026 \n\x8c\x11x\xdf\xf3\x17\xfa\xb8\x07w\xa6\xb4{\xbb\xfa\x83\xc6\xdench\xc3\x1ab\x86\x1b\xb6\xc5\x8f\x92\xe2\x8eK\xdct\x00\xbc\xcf\x11\xad\xd4\")\x9d\xc8\xef:5}\xc35\xfc-mj\x8a\xedL\xd8\xd4\xf4,\xe8\xf0\xae~\x00\xb9X\xe0s\xcb\x07\xe5Q6)\x82\x009\xb9\x15j\xc9\xbcd\xa0\xdd\xf6\xe1 \xcck\xafg'6\x19\xfbS\xa3\xdf\xceR\x90g1\xf7\xd8\xbf5=k\xa1\xbf\x8d\xfa^\xca/s\x97\x1eh\xc5\x074\xac\xd1>\xb6F0\x87SX\xc2\x10Z-{\x0ef\x031g\xa1s\xfc\x9b\xd9k\x17\xe6\xdc\xbekKq\x13\xef\x8d\x87\x06$\xbc\xbb\x97\xc2\xae\xde'doW\xef\xbf\xa2\xca5\xd9\xa6\xc8c\xe8z\xc4\x9cD\x98G\x01\x06\xbcj\xde9w\x9e\xa7\xbc@\x9d\xc2Z,1)\x87\xa8\xaaz\x8c\xdeu\xca7\x91J\xee\xd3\xfd\xb8\x12\xb9\x0e\xee\xd3\xd9\xbd\xdd\xaa2T\xa8\x83\xf4\xa9\xb2\xf7vu\xc4\xe8S/]tW\xdeu\xd3\xb0\xcd\xc2\x98W\xb3\xf5TMA\xcb\xcb\xd5\xaa\x9d\x8aO\xde\x95\x88\x98\xc1+\x13I\xcb#\x93B4\xc9\x13\x9e'\xe8\x0d\xeeA\x1b\x12\x0c\xbc\xe62^\x1c\xd0\xf9\xdeu\\H\xee\x8f\xb6\xc2\x15V\xd1o\xe44V\xf6eb\xde(!\xb4\x01\x05\x9e>\x0c\xa1\xd3wN\xf06K\xd4\xe9\xc0\x10\xda\xed\x88%TW\x90\x85N\x13\xb1\xe9\x91\x0b\xbd\xca$Et\xa4\x9d\x86\xbb\xc7D\xdb\xdbm\xce\xc4_#\xec\x98d\x12\xf8 \xe8\xeb%\x12\xb1w\xe9\xd2\x12\xe8\xa0\x10N`\xd8\x18\xc2\xc1<\x82=\x9d\xa8\xd2\x87\x9d\xaa\"\x0b\xe3\xbbt\x0f\x8f\x0f\x0f\x8ew\xfb\xbb{G\x07\x83\xdd\xfe\xfe!\xd9\xed\x1dm;\x01\xb9\xaa\xfb\x94\xf9^1S\x01\x13\xe3\xa8\x04\x8b_;\x01{\xcc\xc2\xbeu\xe8\xfa\xf7\x1d\xf8\x10\x1d\xeeR\xb1SR:r\xfc7\x92!w\x9d\x0b%^3\xd7&\xe8\xb4\xc3\xaf\xbcW*-\xd8\xf9|\x92\xb4o'I\xfb\x83\xea)\x83Ex\x1ew\xda\xd3\xde\xf5\xb8\xd79\xf6:\xf3i\xfb\x83\x9d@\x15Vv>\xef]\x8c{}\xcdS\x9f=\x8d\xc6\xbd\xce\xa1\xe61\xe5\xe0k/N\xc8\xcb0\xddvI\xe8\x8e\x91\xa3\xbd #`\xbeqR\x95\x10\x05\xb6yc\xa1J\xd3p=\\\xe0\xbf\xd6\xc6\x91\xe6\xd7\xcfN\x8b\xef\xecJ\xb3^\xe8\x89\xd9\xc9\x9e\xdd\x10\xa2\x9b\xa1T\xea\xbd:J\x11\xe4\xae\xa5\x19e\x19\x8f\xda\x95&\xd9e\xb1r2j\x95\x00\x87,\xac6K\x14\xa3\xdd\xc4xN\xf3E\x118\x85\xb9\x9dv\x93e\xe0\x13{\x80j\xa7S\x18\xc0\x10\x8e\xe8\xa8=\xa9X\x84}\xba+r\xf7\x15uK\x03\xb7\xdb\xab\x8a\xd8\x99V \xe7\xa6\x8f\xbdf!\xc9\xcc\x01\x19\xf7a\xb2\x12\xe5W\x86iC)4\xaf\x86\xb2-\x8aGL\x8c\xa1VE\xf1\xfcc\xd3\x172.\xdaf\xf0\x04\"\xe6\xe8\xd4\xc7\xb8q\x81\xed\x8d\xb3)\xbbH\xe6\x9c\x98\xf5\xd1\xa6\xd8\xe7\xdb\xae\x84\x9eN\x18\x82\x0d\xa9\xea\x98L\x08T\x1b\xac\xa7\x86)\xe0\nd\xf2\nT\xef\x1f\x89\x83\x93\xf0\x8d\xd0\xd2\xdeV\xab$\xd5x\x18\x1b\x86\xb1\x8e\x08\xf7e\xae\xe0\x18\x96\xa2\xdfz\xb9\xbe+\xe4\xee\x9f\xe1\x98L\xb7\x8f\x99ne \xc1\xec8~*\x99/\xb9\xd3\x05\x0b\x97!\x9clx<\x18\x92|\x1a\xcd\xb2%\xb1\\\x85\xc1,32,E\x8es\\\xbcs\xbd\x8a\x82/\xc9\xec\xcc[\xad\x97\xe4\xe38Z\x9d\xf9\x0b\xb2\xf2`$=|\x1e\x13/%\x7f\xe3\xd3O^\\c1\x16J\x0d\xbf\xfe\x8d\xd5\xb2\xf2R\x10\xceI,\xfdN\xd4\x9a\xb9\xa1\x1bH\xd7Wk^\x9eh\xf0\xa9\xaf\xa4H \x90\xe7\x87\xf6\xde>=n*H\x85\x8f\x0ev\x9dM\xa3\xb1\xc8|\"\xed\x16\x13\xc9e9\x95\x1a\xcc\xc8\xdc\xcb\x96\xe9\xb0z\xab\xf4;\xea7\x81kj%\"\xf3Q\x8e\x04&\xaa\xcc\xbb'\x90L)\xf3^= \xb2\xa2\xe7d\xe5\x05\xcb-Z\xc8\x12\x12\x7f\x97\xb0\xd5\xe8\xfa\xd1j\xa3\xb6x\xbf\xceg^J:i\xb0\"\xd6\xe6-\xa2\xaf\xc5G^J\x9cn\x1a\xbd<{\xcd\xbc@m\x8d\x1dBs\xda\xc5\xcd\xb9y[\xbd\xcd+=\x9f/#/}\xe0\xaa\x830%\x97\x0f\xdea\x1eD{X#T\x88\x8fX\xe5<\xee\xb6t\x8c\xe9r\x94fQ1\xf8\x0f\xb5\xfd2\xba\xab\x07\xd0\xfaN\\\xe5\xfel#\xb0{.\xc4]\xe6`\x11\xcco\x1c\xadB\x03rC\x8b\x9a\x82H|\x02|>\x8f\xe2\x95g\x88\\EI\x827\xc6\xfc\x91\xe7\x16\xb4!\x98\xa2\x0b\x90\xf6\x12\x92\xc0K\xec]\x90|\x9c\x85\xbecGx\x82\xb2\xd1\x1ek\xfd |\x1bF\xefBxs\xb3&C\xa0\xf5\xa5\xd8\xbb\xba\xa9\xf1M\xc40\xa7J\xa9^u)\x0e\x85\x9e\xf0%\x17\x97\xb2\x9fB\x1f\x8a\x9c\x14\x94\xc9\xe7E\xc6\xfd)\x15\xde\xe4\x9f\x98\xc7\xca8{\xcaR\xe8\xe2\xc5\x81\xf0\xf9\xadY\n\xb4yw9\xfd\xd0\x17\xf1\xb0\x08\xbf\xc4\x17\x10\x8dg/\xf0\xf9\n\xba\xdel\x16\xd0\xc9\xf1\x96\xdfo(?\xc7\xf2AJV\x86\x02h\x14\xe9\x06\xa1\xbf\xccf\xe43\xe2\xcd^\x87\xcb\x1b}\xd1\xb5\\\xf4\x87q\x90\x12ZV/\xe8I\xd3\x9f9e\xdc\x99\x11\xb2^\xdePz\xb6\xfe\xeb\xe4\xc6\xc1#\xff\x07\x1f\xc4dnma\xa5\x94\xe5\x8a\x92ou7\x08g\xe4\xfa\xf5\xdc\xb6\xfe\x8aU\xc9\xcc >\xefM\x16\xa2H\xef\x7f\x1c\xb0\xe0\xb7\x91\xe4\x1a\xae\x176kb\xec\x82hc.f\xc3 \xaf\x8a\xdb6^\x1c{7*\x97\x01\xedy\x01U0\x85\xb7\xf9\xc8l\xed\xbe\xe2\xc1\x06\x14\xcc\xae\xba1\xca\x9fY\xe56\x8b\xfc\xc9E\xf5+*\xd8-\x1cX\x8c\xaf\xa6t%\xe8\xdf\xee\x8c\xacc\xe2{)\x99\xe1\x8d/\xf9Q\xccq\x0d\xd8\x05\xb6\xea\xe3w\x02\xbf\xf0\xf9\x1a\xef\xb9\xcfh\x81\x11\xa46-A\x85B\x83\xd0\x8f\x13\xcd\xb4N\xbe\x03\xb3\xcav\xe9\xd7\x8c\x06W\x90\xbe\xee\xebQ\x01\xaa\x11\x0c\x94y\xf4\x1d\x97\xc5,\xb0o\\\x8c\xb2\xb6\x82\x11\xf4O`\x05O`\xef\x04V\xed\xb6\x03\xb3\xb1U\xee\x12\xa5\x95+:\xb4K}\xb78\xd2\xcfTT6\x91i\x8e?\x0c\x19\xe0\x94\xa7\xb2 \x12v\xbdl\xde\xf5\xc2\x9b\xd7s\xd4\x92\xb1\xaf\xdd\x95\xb7.<5\x9a\xee\xe6\xb2\xf8\xf3:\x9f\x08\x18*ME!\x11M\xe1\xd7\x07lj\x9c\xdas\xfa\x94\xd2q\xd2%a\xb6\xc2\x10\x8c\x82c\xcb\xdf\x87|\xa9B\xca\x0e\x97\xc1\x97\x04\xbb\xe7\xd8\xec5g\xdc\xa3uX\xf3`IX\x8a\x8d\x08\x1d\x9b\xd0\xa5I\x17/_U\x12\xdbU\x19\xbf\x9e\x96\x89\xe1u\x13V\xfe\xd1#\xa6\xb6\x17\x00\xf4h)\xb8\x01{\x8e\x1cF\"C\x8aO\xc6{\xd7x\x04\xd9\x88\xa1\xb2K\xcb\xdf\x1aO\x8d\xb6\xe1\xa9x\xff\xa5\x86\xa7z\xf8|\x13\x86\x19m\xc90\xa3&\x86\x19\xd5\xb3\xf25c\xba\x9b\xf0\xd4\x85\\4\xe7\xa9\xfa\xb23l\x99#\xb4\xbe\xc8\x15\xd26\xfd\xb3\x9b\x9ag\x97(\x86]\xaf\x96\xfa\xc7\x94\x86]b|2\xfd\xf3s|\xbe\x8e\xc9<\xb8\xd6\x97\xb8\xc8kH\xd6\x9eo\xa8\xe6\x1d\x9b\xda0[\xe9\x9f_\xe7\x87d\x03\x03\xcfj\x188\x9a\x07\x1c\x96\xda\xfc\xc7\xc1\xc5\xb3&.\x8e\xd1Y1l\x8c\x15F\xa9wI'\xc7b\xfe\xb1\xf69\x9c\xc29\x15\xcb\x87\x16\xba\xb6;\x94A\xb8p\xc1\xf4\xf37c\xfa\xdc\xba^-\xc3\x043e\x9f\xd3B\xf8\x13o\x03^\x18\x04\x1c\x99)\xa0[\xe5\xdcD|i\xe99\xc5\x07J8\xf0\xef\xed-\\\xd2\xff\xbez\xef2\x08\x0f\\'\xff\xa0e\x18\x96\xc0e\x97\xc7\xe0\xcd\x85\xbf+\xee\x95;u+\x1cbIy\xc3R\x8dZe\xe4\x0c\xf43\x17;\x90\xe5\xa4\xa2\x953?>\xe4\x08U\xfd\xbe\xf8h\xf8\xd3\x8c\xb6>\xdb\xbau\xc1V\xb6n]L\x03/9u\x01%\x9c\xa2\ns\xab\xe7^\x9a\xc6C\xb81T\xee\xc2\x95\x1e\x1b)e?3\xb8XB\xc1\x8a4\xabb\xdfsY\xce6\x9a\x15\x17\xce\x0c\xebb\xdfsa\xb6j\x9f\x97R\nm nk\xd3\x12\x01\x9f\xfa\x17zq\xbbA\x9c~F\xc5ii\xcf\xd0\x9d\xb8\x14\x1b\xf0\x85Y:\xa5}{Q\xb9jh?ct\xa3\xf5b\xfcL\x12\xbcooa-?(Dn*\x8c\x1b\xa6\xab\xd4\x0e}\x8b\x11\x89\xfc\xab\xe8!\xff\xdd\xa58\x1b\\di\xed\xb2\x89\xcf\x15\x8f.YF\x05\xac\x0b\xa54\xda\xd9\xfc\x971\x05K\xf5\xf3\x85\xe8_-\xd3\xae~\xde\x8a\xb78F\x99)\xbd\xf8\xdc\x8c\xf3Q\x0br\xf8l\x9a\xb3,\x14\x9b\xbe\xa0#\xf8\x82>\x91\x80\xcb\xf13<\xf7\xe0\xdf\xf2\xa3\xb7\x14\xfe\x96\x0214f\x82sQ\xbf0\xb5\xa9^\xe4O\xb9\xb3#P;\xef\xca\xce\xe9\xf2\x0cV\x84A1\x00\xbbT\x86\xc1Mv\x19\xe9s\xc5\xe3f\xa6lt\xcd/\x94\xd1\xe3%\xa5\x14|\xa7 \x19\xf5\xa3\xd0\xf7R\n\x1fJt\xf5e\xc3\xb4\xd5\x91Fq\x98\xe4\x0d5\x11\xea\xb2\xb49\x04\xebYx\x93.\x82\xf0\x12|/\x84\x0b\x02\x0b\x12\x13\x83T@;\xedo\xca\x11\xaa\x0d%\xa6s+%r\x0f\xc8g6\xa0\x91|\xe6\xae\xcb\xf8\xbf\xe4\xae\xb1\x12h\xc63&\x94\x17\xf5\x1d]\xd4w\xecT\x96\xb0\x80kl\x85o\xe0\x14\xc6\xfa\xbe\x1b\xfb\xfd\xde\x85kZ\xd1u\xb5\xeb\xef\xb5v\x90\xa5\xd9\x17\x81\xca;\xeci\x19K\xd1\x08Z\xd2s\x05\x82n8vX\xb5:\x01\x1aJ\xfc\xa5\x17{\xb4\xc1!\xb44\xd7\x1b\x83pF\xc2t\x08\xd6$\xad\xdc\xae\xab\x9a\xcb\x00o1\xd4X\xa5h\x7f\xa2\xa2?\xcb&\x13W\xa5<\xc7\xa9\x06\xab\\\x0d\x87\x96<\x05\xf6\xabn1PxK\xec\x0f\x9c\xeeY\x1a\x13O#\xfe\xa3N\x8c~\xb1\xa4\x15\x83\x8a\xf5Jo\xf5\x04\x919\x80\xd24\xcd\xc9\x01=\x05\xd0\xa5\x11\xc7\x1e0\xd1!\xbf\x92k\xb3\xf7\x9c\xee\x17Q\x10\xda\xe8KgYU\xdb\x9a\xf8$\x94\x8c\x19\x84oC4\x08\x1b\xbdD\xd3\xb1\x142\xe0-\xb9I\xec\xd4\x19\xf7\xa6SdyI\xf7\x9c,\xc9\xaa0\xdbr\x80\xa0\xdc\x91\x9bC\x02?\xcaB*\xfd\x84\x12\x0c1\x89\x0d\xab\x0c\xa3-{20%q\x9c\xadS\xcc\x00'\xc0\xfa\x19\xf3\x99\xd3\xbe.4\x14\xf0S2\x957\x95\x87\xf9z\xad\xcd:\xde\xf24l-\x02\"y\xab\xf5m\xa8~r3g\x1b\x1e\x8f\xac\xc7\xd0f\x0epmxl=6\xbe\xf8\x1e\xbd\xa6\xc7dj\x14,7 \x93\xe2z2\xc7\x08%\x94\xad\xf8\xe0\xa5\\\x81B\xfa\xbb\xb9Pv\xc6\x18\xd1\xca\x0c\xf7\x1a\xc4'\xe9\"\xcd\xa48\xb6\xb6\xf9\x0f\x0cty\xee\xcf\xbc\x14\x95RK6\x9d\xb6\xf5\xa45~\xfe\xd1\xb37\xcf\xc6\xf4\xc0)J8\xb9\xe3\xde\xced:\x99>\xdd\xb9t\xc1\x9aN\xa7\xd3\xa7y\xf1\xa7xx\xb5\xa6\xd3\xa7\x16V\xcdW\x13Q\xdf\xe7\xa1k\x96\xd2=\xaed\xc3\xf8\xc5\xf2G\xbb\xb7N\xc1\xc2\x01!T\xd9YpJ1\x90\x0f\x19\x86\xa2\x0b9\x15\x816\xf4\xf1r\x81\xbdd\x89\xb5]T%\xb5zyo\xd1\x13\xd3,T\xbc\xc77no\xa5\xc1\xd5\x8865\x0b%L\xea\xc6w\xf3\xfe$\x9a\xee\x189\xb3~F)E\x19B\xa4\xdf\xd49}\x18\xd2U\xd3\x16\xc9\xc5\xfdd\x08s\x83F.\nS\xe4l\x06e\x13#aC\x08M\x9d@\xca5\x04\xaf\xeey\xd5e\x15\x94\xa9xo\xe0#^\x1d\x1f)\x11\xf2\xc2HL$\x97&\x8a\xcf\xba\x08\xf1\x82 \x12\x89\xcc2\x0f|\x0c\x9fK\xa7$\xbf\x9d`\xa6\x9a\x81\xd14\xce\xd3X*\x95\xd5\xed\x1d\xe1$W\xbc\x94,\x82yZ\x0d\xa8#\x7f*\xc6=\xadKX\xb5|d\x07N\xb3\xc2\x8c~p\xf25gp\xf1\xd1K\xe9z([\n;F\xed\xf5)\xce;\xe3yB\xa1f\xf3\x94\x0b\xa7`=\xd9\xa1T\x8d\xffn\x83\xf5\xd4\x92Kq\x06\xfa\xe8\x11\xb4BZz\x12\xf2\xc7\xe8W\x8c\x17\xc9t\x1b\xcf\xbc\x8aQ\xa3\xd9\xa3\xd5\x92\xf1\x04\x9dr\x8b\xdf]o\xbd&\xe1\x8c\x8a\x0d\xae\x8cO]\x06\x0cJ@\x11\x1d\xccn\xf5\x1c\x17Z\xbdMH\x04]4\x8e\xc9\xf9\xac\x95\xe7K\x9a.i\xa2\x8a\xdd/,\x07\xa7`\x01++=CI\xca\x02\xcb)\xde\x8dq\x85D\xf5|\xfaqo\x08\xd8\x8eiM\xc4\x02\x97\x96\xa5\x15W\xb7\xa4xC.\xa8\"#\xae\x0c\xde\xbd3]\x87\x82\x1a\xa7;-\xcd\xd0\xd0\x0bD\x1a\xf4H6\xa8_9\x0d\x0b\xd5\xb52Q\x16\xf41\xc5\x08\x00\xdd\x04eh8e\x99Px\xaax\xb3\xb5\xc3\xb2\xcc\"\x9c\x89\xcc\x0bW\x00>\xa3\xfc|,A\"\xda\xac\xf894\xb6\xb1\xe0q\xe4\xcd[ef\xe6\xfe\x0b\x863\xe4:}\x13\xf8o\x99\x13J\xba\xe5N\xbc\xaa\x95\x0f+\xc4\x0e\xf5\x1e\xf6\x1c\xda#\x96\x8c\x12\xf2\xd8\xab(\xc9 \xb7\xc79\xe7\xd7V{\xa2\xd0\xb2\x89\x08\xe3\xc1\xd2L\x1agv\xa3g\x94\xf8\xf8]\xb2\nR\xdb\xa2\xd2\x99\xa5\xb5\x9c\x8a\x0f\x15P\xd8\xfaoHT\xeb\xe6\xf1\xa6v\x1e=\xfb\x8a'\xa0[\xbb\x98\"\x91\xb2\xbd\x9e\xa3\x0f\xed\\\xd3\xca\xa5q\xf8\xccf\xdf0\xcb\xe9\xb75\xcb)\x95\xf58\x88\x843\x0b\x7f\xc6\xc4\x9by\x17x\x00\xa7\x04H<\xf7\x97QB\x0c\x91\xee@\x7fl\x00\xc3rT!\xc2M\xa0y\x1c\x0b5=$p\x94\x08\xbb\x92j\x02q\x1b\x8f\xee2\xd4\xc5s\xae\xbe\xe6+\x12'\xa8\xd3\xb0\xfa\xdd\x9ea\xd7\x93\xd0\x8ff\xe8\xe1\x19w\xc5wFr)\xbd\xfa^\x8a\xd9\xd4%K\xb2b*\x85\x02\xf6\"\x87\xd5b\x9f\xd8\x87\xfa\xe1\xa2\xc2a\x08\x99\xcd\xb4\x81E\xecD\xbc\xc8\xc5\x82\x15\xe6\xbe\x06&%\x0c=\x0dm\xe2\xf5 \xc2\x9a\xcb\xf2@\xa2L\xe5@\xba\x88\xa3wH\xc61(\xacm\x85Q\n^\x92\x04\x97!\x99A\x1a\x81\x07,\x14uK'?\x88\xcf\x95\x94\xaa\xbb\xde\xdePdG\x96\x143\xe6\x8a=[\xea-'\xaa\xa1[\xaa\x81\xa9\x80\xdaT\xc0\x10\x94V\x0e\xbc\xdfD\xdb\x08\xaf\xdc\xd6\xc9\x8a\xe2c\xa2R\x86#\x1f\xa5y\x9b.\x89\xc4p\xd9\xee\xa1Ccv<\x91\x01\x9a\xca\xb9\xe2 \xed\xe9\xc6$S\x9dW!$\x96\x91=\xffU\x8a\x1a\xba\xbbg\x88\x18*\x0fG\xb0\xf3\xf2\x00\xadG\xd6\x10\xacG\xdej}R!\x8a\x8f\xad\xc7\xf4\xc9\xcffQZ}d=f/\xad\xa3Dy\xf4\x04\x1f-\xd5w\x9e\xe2\x83\xcb\xf4\xa4\xa0\xa3\xd2\xb0\xb7\xbal\xc5\x89\x17\xa7lH\xbcru\x8f=~d=y\xfax\xea\xec\\\xd6LF\xa5\xc2pL\xaaI\xb4`\xb8m(\x8a\xd2%\xba\x93\xd2\xbc\xf3[\x11\xfd}\xa7\xfb\xe2\x8a\x84\xe9\x8bU\x90\xa6$\xd6)\xf9\xd5\x83t\xccc\xa1.\x02\xe5Z>\xfd\x84\xf6\xee\xbec\x07.&\xd3\x0d\xba\x9f\x15\x14\x93\xb6x\x80\xc0\x1f\xc6A\x9a\x03\xf7\xf6\x8f\x11\xf8Q\xb6^\x92k\x06:\xe8!\xe8M\xec\x85\xc9<\x8aW\x1c\xdaG\xe8\xf7\xbd$y\xb3\x88\xa3\xecr\xc1\xe1\x03\x843\x9d8;\xd8\x05r\xc2\x8f\x00\x9d\xc1j'\xffJ\xca#o\xd2\x9c\x07\xfa\xd3h\x8a\x06a\x1c\x0e\xbb0\xc5X\x0dZ\x89\xe9\x1b\x18\x1bh\xede \x91\xbe*\xc7&}\x93\x91\x96\n\x85\x05\x1f\xc2\x1ac\x92d\xab\xd2\xf7\xdaSY\xd8\x8d\xc2\\$\x0b\xd0\x81\x0e\x01\xb1\x17\x84\x96\x0b\x11B\xce\x83\xe4,\x9d\x05\x11\x957\xe4\x81\x11$*\xb7\xb7`\xb3j\xa8\x18\xe7\x82\x87\x02\x11\xfd\xcd\xc46\x17\x92\xaa\x16\xef\x8a\x874k\xf5M\xf3\xebi\x07\x9bac\x19\xe7\xb8)\xa3c\x9b\xcd^\xb2A\x85\x86{\xe03\x92\xa4qt\xc366\xff\xb1i\xb3\xbe\x9en\xa3\xaf\x90\xed\xb8\xdcN\x1cw\x97A\x92\x92\x90\xc4\xcf)\x1f\xc2\xfd\xe4\x82E(3\xb5\x1c\xc1_\xab\xf4V\xdf\xe2\xdc\x88&\xab\xe8\x8a|\xc2\xdb\xa9\xac\xb9\xf2PZ\x7f\xf5Uy\x9d\xab\xcf\x8a5\xd7\xbe\x89#\xa2\xc2\x92\xaeU\xf9\xa9\xa9\xd5ym\xabsm\xbd\xc5\xd3\x9a\x9d \xc8-\xc3\xe4R?\xab\x10\x19\xdb\xe7\n\xb6\xcf\xf3w\xca\x10v\x94\xa1\x04\xc8b^\xceM4\xdca\x8ec5d]\x7f\xab\xaf\xa0\xeaG=\xa7\xcb\xc2\xe3\x96\x19\x9e0\x1e6\x86\xc8\xa9\xa2R\x8ee\xa9\x16\xcbZ\xcd\\\x0d\x84\x00i\xa7 %\x19#\x8e,E\xbe\xb9Y\x13.I>\xf7B*LR6\x03\x1e\xf8K/I\xc0K\xc0\xcb[\xd2\x1c\x0b\xdf\xf3\x0d\x94\xcb>\x0b\xe2\xcd\x80E\xa3\xe1\x90\xd4\x0b\x96e\x08?\x0e\x8c\xaa^\xcb:$I\xd5\x8c\xe6\xf5r\x9a\x10m\xf5\xf3A\xb7\xa21S~H\xaeS\xa6\x8eR\xc7\xa9\x8af\xf2P\x9eb\xc0\x92|\xb8\xa8\xf5\xc1\xdb\xc0\xc3\xd2\xac\x90\xf2\x94\x10\x17\xdam\xa9\x9a\xf2l\xb8\xa5\xb1g!\xea\xbe\xbf\xfd\xe1\xe7\xfd\xddd\x0ex\xec\x0ci&\xd0\x11\\\x1ec\x051\xb6\x19\xb32b\x13}\xe7\xe2xQk\xddy5\x15'\x1a\xda\xa3.\x9d\x91Z\xbf\xc3\xbe2\xc4\xd3\xd2\x80\xaa8^Y\xf2\xa2%:\xbd.t:RU\xda\x98\x85u3\x82\xb1\x0e\x9bf\xa4\xaew\x0d;\xb0\xdc\xda\x17Q\x106\"\x1c\x9b\xffQu\xfe\xc5E\x0f\x8d\x17s)\xean\xdeY\xe6Zl1m<\xae\nO\xcdM\xe7\xed\xc4\x81\x10\xda#4\x81\x13\xc3\x9a \xaeR;\x7f\xe8{u\xcf1\xc5]o\xb9\x8c|\xbbg\xf0cV0\xa6\xd0\xf57\xa0]13xj\x0eXl\x08\xde\xde\x0f\xc2\xc4\x9b\x13;\x85\xa7O\x9f\xa2v2+O\x9fG\x97\xf3\x04\xb2\x13\x07'.\xc36\xd8\xacF\xfc\xe2\x04^\xde\x8e\xd67,\xb0\x01}\xa5-\n\x96\xa2\x18dl\xd2MS\x1c)S\x9c\x03\xdeSI\x0b\x03s\x06\xdd L\xd6\xc4OK?\xba~\x96\xa4\xd1\x8a\x91\x89\\9\x93/\xd0\xb8ZpZ\x87\xecb7\xe7/i\xd4jlXC0\x92\x1c}\xb8\x1e,.\x05z\xcfMo\xec\xe2h1^\xe3\x89{c\x7f$\x1d\xfb.sw\xbd\xddF+\x90\x88\x0fS\x1cu\x13\x92\xbe\\\xad\xc8,\xf0\xcc\x1e\xae\xdc>\xc3|\x8cx\xcab5&\xb3\xfc\xf1k\xaej\x007\xdb\x98L3\xc0M7iw\x16\xf9\xa8(3\x97[\x97\x12B~_ \xc9k\xcc*\xa7}`\xcc\xa7N\xab\xc2\x8clk:'o\x82\x15\x89\xb2\x14NaM\xc9\xb5[D\x8c\xe7yk\xa6\xccq\xfa\xab\xf7\xdd4bW\xdb\xf9\xe9[$\xb6aQ\x8b\x9a\xe8\x88\xf8Hf\xa0Z\xca-\x7ff\xb6&\xaa\xaf\xf8\x98\xf4[0\x94Q\xa7\xae \xb4\xa1v\xd7Q\x92~\xca\xb3\xf9\xb3\xac?\xc1\x8an\xc93?\x0e\xd6\xa9\xd1\xddG|\x04\x11\xd79\x08V?x\xcc\xefF\xe1\x8a5Woh\xcf\x85\xbf\xbc|\x13\xd3\xab~\x88\xde\x84 \x7f\x18o(f\xc0\xb6,\x17\xac\x0f-~\xa8(\x1a\x0e\xab\xa1\x94K\xb5\xe8W\xc2vP!\xc5\xab~\xbe\xf0\xc2\x90,\xe1\x14l\x1b\xa3\xa7\x90wP~\xe4t\xe9\xbc\xf7\xf5\x03\xaeE\xae\x99\x9d\"\x057\xa9<\xb7\xc0\xd3\x08;1(M\x8a\x01\x0bQ5\x86\xc6E+\nc\xe2\xcdn\x92\xd4K\x89\xbf\xf0\xc2K\x82i\x92\x97\xa3\xddvD\xbe\x8b\xe2\x0e.Z\x06\x0d\x97\xbd@r\xfb\xaa\xdf\x85\x94\x1f_x\xfe[\xe3qV|\xbc\xf82\xd1\xf9\xdb\x89\x8f\xe1\xae=\x14l\xc8\x1f'S\xa6\xdf\x8e\xed\xc4q!i\xb7M\x08\xb7fG4y\xed\x16J\xd9:\x1f\x82\x85y\x89Yzw\xf0\xab\x81\x9b\xa1\xa1\xca\x1a\x1f\x15T\x8e::\"\xa1\x9f\x94\x86\xbb;\x02[h\x17\xeb}\xf4\x1a}\x9e\xe7\xdc\xf5\xa6\xaeL}\x9a@\xf1im\xb8{\xe4O~:\xed\n4k\x16p\xc4'\xc6\xf7(\xd6\xd5\xf7^|\xf2\x14P\x0d\xba\x0b\xdd\x07\xfd\xae{f\xdf[\xdd\x87\xd4\xf9O\xea>\x0d^\xda\xd5\x0f\xf6\xa9\xbfm\x9f\xe2qo\x93\xbbU\xf2\xe7.\xfd\x1a\xdc\xa5_.\xc4\xe3\xfe\x8f\xa3w\xbbw\xef\x1d\xfd\x7f\xf0-\xf7\xb1\xd1\xd5[\xf7A{\xfd\x12U\x0e\x1aw\x0f\xddG/Q\x97J\x98\x84\xa3\xbc\x00\xcc\x83\xd0[.7\xa1\x0f\xccp?\xdf\xe0\xbc`|\xba\xa9\xdfoE\xb7g[Y\xc8\x02\x02\xcedY(!\xcby\x11\xa9?\x0fN\xbc\x08\x12\x0c\x83=\xc4\x02\x92\x0d\xb8\x949\x14y\xb1\xd9\x15`\xf3[Q9\xfb0\x90M3\xf1E\xdd\x03\xe9.#\xdf[\x9e\xa5Q\xec]\x12)\xa2\xa3:)r\xfeTm\x855\xef*\x10aQ.\xb7\xaf\xe5GBa\xc8sn\xa07\x99\x95\xc6\x19a\x87\x7f\x1e\xd2.t\xbai\xf4I\xf4\x8e\xc4\xcf=\x8d\x01Y\xfe\xb5q\xf0R\x10wal+\x8c>\xe2A\x88\xd0\xc0b\x8a\xbd\x0d\x92\xb1\xa9\x1a\x15\x13\x8a\xb14\x9eapm\xb4ai\xe5\x12\xa1m\xa1\x85\xa8\xd2\xb5\xaa\xef\x91\xee\x1e\x81\xf8\xd0*b\xcf'\xa5*\xe0\x14\xfc(L\xa2%\xe9\xe2C\x16\xc0F\x80\xdeyq\x88g%\x1c\xa4\x1aD\x0f\x8c;-W\x170R\x93\xa2I\xaap\xc4j\xda\x87\xc6\xad\xb4\xd1\x1e\xd2+\xe2J\x19\x96\n\xb0\xe4\x06r\xac\xcb\xa3\x14\xda\xfb}\xed\xad\xcfH\xdd\x1e\xdc\xb6G\xe9\x82d\xde\x8b\n\x1c\xa2+\x15\xa9\x01\xc9\x0bG\x12MpS\xac\xb8\x1b\x84\x0b\x12\x07\xd8yt,q%\x98\x1d1'\x93H\xd2\xab\x9f\xa7\x92\xcbH\xddd\x01\xa2\x06\xb7DT\xdb\xde\xc2\xb3\x86.\xcf\xe1F\xcbS~k\xd0\xbf\xc3K\xfd\xfe\x81S8\xc5\xdc\xf1}\xc9}f\x93\x1a\x9a\xec\xcd\xfdc}\x16\xc4\xfe\xb1>\xcf\xcd\xdeAs\xac\xf6\xeaBqK\x04\x0bH-\xc7P\xd2\xeb\xcc\xb3\"zU\x8c\x97R\xd1*g\x13)\x8a5\xe6\xd6\xcb\n\xebWau\xe8z\xc9M\xe8\xf3\xe4\xadYw\x1d\x07\xab \x0d\xae\x08\x9c\xe6.0pZn\x02\x87u\xbc\xef`6\x0c\x1e\x03\xca\xd6\x948pl\x82w\xe5*\xcf\xa4zi\xb1C\x07S\x0e\xc8\xc0\xfd^\x9f\x01\xe9\xd7\x01V\x93w\x15\xfd~\xec\xfd\xde.\x82\xd6,!\xa7\x00\xee!p\x16$\xeb(\x07\xf6\xd1f\xd3]y\xd7\xcf.sX_\xc0\x04\x80\xbd\x19\x939\xba\xa7\x90X\xc0\x0f\xe8\x8e\xa3\x88\x92m\xb9k\x9a\x10i\xef@\x17\xb9\x1du>\xdeE\xa2\xa2\x12>\x99/#9\x97\xf5f\xe8\xc4\xd1$H^y\xafl\x8c\xfb\xcf\xd2x \x96\xa40\x82W\x18\xc3\x153H\x0d\xd8\x9e\x92\x07\xc6\xcb\xc9l\xfd\xe4\xe8\x02\xd9]\xb1 v\x89\x0b~y\x81\x03L\x9dBe\x1f\xbb\xc8?_&\xb9\x8eDv\x04\xb9\xd1\xb8\x83\xbf^\xd3\xc6\x13x\x8c\xa5\x1f\x83\x17\xce\xe01/\xfe\x18|\xe6\xe2sA K\xd0]\xfc\x92\xa4\x0b\x12W\xb5\xe5|\x19\xcbazr\xd1\xc8:?\x17\xd1\x19\xce\xcf-\x16\xaf>\xec\xce\xa3\x18\x9dp \x0cYf)\xcf.B\xe3\x93\xfc[X\x0c#\xe24\x9f]\x0c\xcbh\xd5 s\xd7\n\xa8\x8c\xd1(A\x87c\x82q]R\x1e\xa8\xddW\xee\x13\xb1T\xce\xe7\xe7\xeb8\x9a\x07K\x12\x9f\x9f\x03\x8f\x14^@0$\xa6\xdf\xcd\xd63/%/\xc2+\xbcJ\x9d\x87\x9fx\x90\xbd\xd3\x88\x93\xbb\xba\\\xbcBU+\x89Y\x17A8S\xb1TS\x90.\x95\x8a\xb6r\xe2\xff\xd2\xc3\xa4x(y[\xf1u\x7f\x99\xbc\x08\xb3\x15\x89\xbd\x8b%i\xa2\x07\x9b%j\xd0\xde\x84\xa2\x934g7\xd3\n\xbc\x1f\x18\xe27\xacK\xa5vk\x0ew\xc5n\n\xec\x90\xa58\xf3\xf9q\xdf\xb3)\xae\xa1Ux\xdeM\xa28\xb5\xb5\x04v\x8d\xa9W\x11\xf9\xd7\xb8\xdc\xc3\"\xfbL\x83\xc6}>N\xa7\xc8\xcf\x99\xc4\xed\xd2\x01\xca\x93e<\x88\xf1\xde'\xecE\x96R\xf8T\xd4\xe3\xbb\xb0t!\x1c\xa7S\x17R\x91gD{\xa3\xdctX}\x10\\\xde;\xacRR!\x81\xea\xf3E\x1c\xe9\xd3E\xec\x1d\xf5\x9d\xee\x8a\xa4\x8bh\x96\xe8(\xed\x9e\xf2\x1eg\xd6\xc7\xba\x04\xd3\x9a\xbd\x80g\xc2r\xc9\xf9\xa6\xbbfYl\x0cff,?\x96\x1c\x14J\x89\x1d\x94\xf0\x9d\x0b\x94\x81\xa3J\xcc\x80\x19B\xc9*hL\xdd\xa5?H\xa1o\xb7\x0bW.\xdc\xb8p\xe9\xc2\xca\x85s\x17.\\x\xe7\xc2\xb5\x0bg.\xbcp\xe1\x99\x0b\xaf]\xf8\xc2\x85\xb7.\x86\xb1Z\xe2\xe9KO\xf0\xaf\x98T\xdc\xe2\x020%\xe5\x9cw\xe7\xbai\xc6\xabS\x89\x9eK25\xc5\xfb3\xcct*\x831\xb8\xd3\x08\xce\xba\x97$e\xd1\x87\xcf\xba \xfd\xba\xc2\xaf\xcc\xac\xe1b\x94\xce3f>q\xdcB+\xd3\x8dI\x12-\xafH\xcc\x82\xcc\xbe\xe5\x9c%\x87\xd2=\xfd\x05\x8f\xbc\x144\x04a\xe1\xfc\x97\xfbU\xe5\x04D\xa5\x1e\x94\x1fcp3\xb4\xd6\xbf\xb5#\xa7\xe8\xd2\x88\xf1\xe8\x1b\n\xa4Et\\\xf2%]\xad\xfc\x1c\xfe\x82\x16\xcb\xb8W\xf2%I-\xdc\xb4\x11\xf3\xc5s\\x\xa9\x8dhO\xfb\xc0\xd2\xf2a\x94\xe4\xc2\xfbp\x9e\x93\x13v\x86\x8f\xc6\xbd)\xeaQ\xaap\xd1\xe7\x11\xcb}c\xd6\x08iF&D\x8b\xd8\xb6\x9e\x07\xb1\x9f-\xbd\x18\x82\xf0*\xe2\xaa\x1c\x17\xac\xe7/?{\xfe\x83O\x9e}v\xfe\xf2\xd5O\xbd~\xfe\xec\xcd\xcb\xd7\xafLVwZ\xeb\xa5\xad\x89_\xfe\xbe\x08i]3\x8d\x0f\xd4\x13\xbe\x1a/\x99=2p\xe1\x99\xbc.\x89X\x17n\xc1\xa7bH\x99|\xbap\xe5\xe4y\x07\xe9\xfe\xa8\xd5\xb6\xe1\xe1Y\xbf\xaa\x86\xa1\xb2{\x02\xb5h#\xae\x12\xe4\xa8[\xe0\x90\xc1\xa5\x10\x8dm\xba\xa0\xc9\xa7\n\xbe\x14\n3\x18V\x90\xccqMh\x9ew\xfa\x81\x17\x89\xf9\x03\xa0\xbf\xb0f\x99\xf2\xfb\xe3\xb8VD\xcdu.\xa7\xfa\x7fXR \xdf\xefD\x8e\xc7\xf5\xc4\xb8\x0b\x8d\xd3\x14\xd4.kP\xa6\x06\xba\xcc]\xb8M\xefK\x0dj:\xf7\xc0\xcb7\x0e\xe8\x1e\x0b\xb5\x8b\x17\x88u\xa3\xe2\x97\xe2\xae\x9bi-\xffQ\x1c\\\x06\xa1\xb7\xd4Z\xfb\x85\xb0>\x84/\xd4\x87\\\xd2\x7f\x85\x91\x83\x90\xdb\x8b\x9fj\xd9K\x92nr\x0d\x94\x0f\xf2m.\xe7\xbd\xb5S\x07\xb9\xdc)\xdc\xb0@\x0f\x1c)R\xba\x18*\xd5S[^x\xc9\x16-\x1b\xd6Q\xe3\xda\xa3i\x8a\xf1\xdbMZ3\x900`\xfd\xd5\xf7\x00\xe7\x04\xfd{W\xccM\nF\xf0\x12EU\xee\xbe\xc0~\xbc\x96\xd1\x82=\xb1P\x9a%\xba Q\xea PL\xd8 #\x8fP\xac\xbc\xd4\x0f\x03\xcf\x83\xe7\xf4\xc8'\x89Fn\xde1l\xc5\xdatb\xa3R2\x9f\x9aK9B\x9dC7\x7f\xae\x0ey\x81F\x0f\xccI&\x83\x9f\xe5`>K\x85\x1b\x95\xfdZD\xf1X\x94T\xfa\xfa\xb8\x15j\x7f\xe9\x18\x870S\x1f\xe4g\xe1\x0d&8e\x92-\xdf\x9ej\xb3\xd5\xed}\xa1\x8aj\xe6{,n9\x87\x8e\xba\x86l\x0b\x86\xb8\x05\xc3\xb2\x8cFP\x92 \x99\x8c\x96q)\xb3j7\xde\x92\xa7\xe7\x8an^\x1bg~\xe5*\xa1iki\xc8G\xc1T\x18\x17\xc9[\xa8\xa6=w1\n}P\xefF\x8cH\xdf8w\xbc\x1b\xc5\xd09\xcf\x1d\n~'Mk\xcaW\x8dNhA\xddB\xd6Y\xba\xa3U\xbd\xcb\xf5\xb7\xd6\xcf\xac\xbb\xf0\x121\xf7\xda\xee\x16XP\xd3q\x8e\x18\xb4\xaeT\x93pum\x7f\xa1\x0b\x8c*\xeb\xbe\x86\x10a\xd8*#\x89\x8d\xec\x0b\xcdSN\xbb\";\x13\xa7\x1d\xb5\x15\xe4D\x91\xfdN\xf7\x0cyEd_\xab}\xcer\xc8\x83\x9c\xf0\xfb\xc7\xba\xfc}\xf4\xe4\xaf?\xe1\x0ft'|\xd4Kv}o\x9df19K=\xff\xed\x9b\xd8\xf3%\xb6B\xe48\x1d\x8d\xf6\xa8\x90;#2u\xa7.\xf7\x98\x07\xe5\xfc\x1fj\x89\xa4\xa2c\xd2\x9e\x85#;\xe1\xa1\xb6<\xc6\xd4x4R\x91\xb8\x1f\xed1\x89\xc8\x14\xc9n\xe1F\xa2l\xd8\xf5\xa3\x19\x8a\xddxO\x87\"\x1a-CJ\x02\xcf=\xd6hs\xa3\x02\xe3\xc0\\I\xc1\xe2\x84ln[`\xb1l\x88\xad\x8f\x882\x8f\xa2!X\xb1\xf7\xa5U\xa5Qj\xd9\x0b\x8a\xf1\xd6\xec\x9d\xb7A\xd94\xfe\xf2f\x08\x16\xfdS\x0d-\xecb\x80\x9a\x08s\xb7]x1\xcb\xe1\x16\x7fy\x83\xb4\x81ve\xf6\xce\xc3\xf7\x1eXo\xbbgH\x8d\xaaU\xdc\xa2\x11g\xe5]o\xa0\xd41\x18\x08\x8a[8\x91\xe2o\xeb\xc2\xa0\"w\xa3\xa3n*+:Q\x1a-yhk5\x8df\x17\x9et\x1cS\xf9\x9d\x8cc\x8d\xabi\xa3\xbfN\xc8\x02\x15\xd0}\xdd\xe8{\xc1\x04\xfe\xfe d\xf0\x04\x92\x13h\xb73v\x7f\xad\xd8\xa0\xd9\xd4\xc5\x80\xb7yh\xa2jv\x82J\x1c\xb407\x8bh1\xfd\xdb0\x1c\x1e\xee3\xc3\xa1\xa4ag\xa6\xc3\xc3\x83o\xdbt\xa8_D>V9\xae\xac\x95\xdb\xd4-\x8c\xb4X^\x87\xdaE\xd5;`=\xb0>Y\xe1\x1eA\xd9d\xd1\xb4\x9d\xaa\x1d\x17\xe6f\x8c\x84\x9b\xaf\x0d;\x9em\xebzr\xa7\xbek(&oB\x1fR\x9d]A\x1b*Ks\xc7\x81\xe3\xb0\x1f=\x82`,\xec\x12\x98\xbe\xa1\xf5 f\xd6*\xfe\x1f3\xfc\xe7w\xe5J\x17nS/\x08\xf9n8\xea\xddc7\x88\xd9\x96\xc9\xfc\x96{\xa5\x8e\xd7\xc5E_1\xe7\x88\x08\x17\"\xa06r/\x91\x9d\xbb\xfal\x1eE\xd6\xc3\x18\xda\xc50\x95\xa9\xe4wa\xee\x8a\x0d\x95#b\xc9\xb6\\NDy\xdf\xceW\xee\x92\xba\"\x18\xbb\xc6\x04\xb4\xd4[E\xd7\x1b[r\x16\x9bZrf\xf5\x96\x9c+\x83%\xa7\xd2\xdc\xcd\xa6\x06\x9fK\x9dE\xb5\xac4)\xbf\xb0\xd2\x12\x0c?\n\xe7\xc1e\x86\xb6W=\xd1 \xb9mV\x1f\xf5Z\x04I\xaa#+j\x9akJ\xa2\xe2&a\x05\x84\xc0b<\xb3-\xd1\xa5\xe1RF=\xeb\xfc\x9c\x10t\x1b8\x95b\xcb!\x8c\x1e\xe5(h\xd5\xc5\xbc\xe70\x82\x99P\xc8\\U\xdeva\xe5\xb8RA^,\x1c\xa7S8\xd5\xc5[\xe7O\xe8\x1f\x16\xac\x0d=O\x11:\x821\xb3\xa5\x92i\x01\xe2\x91:\xca3V\x11\xf5B\x9f\x0c\x91\xd0o6K\xae\x1c\x0eL|J\x13\x15\x88\x88|\xcan\x0d7\xb9\x9f\xc8\x8d\xd4\x01{\x03\xaf\x91 \x97\x8df\x8fX\x8c\xadCg\xf7u\xe8\xe7\xf1|\xce\xcf7\x9c\x8a\xf9|\x88\xa2\xef\xa63\xc1i\x84^\xcd\xcd&\xa3\xa5G\x9bR,\x05\xfd\xfb-\xbb\x82X\xce8\x9dn\xf0\x9e\x8a6,\xb6(}[\x9d1\x10\x92w\xc4n\xbe\xd1\xc5\x8b\xc7\xd1\x94\x8a\xb0\x91\x03A\x11\x927\xd0\xcd+{J\xe5\xe4\x81\x88K%4\xfa\x1c\x05\xe3q\xc4]\xe40ie\xdcM\xd6x\xeb1r\xa1\xaf\xbb\xb7\x87\x96\xb4\xb8h6\xaem\x96kc\xc3:\xcf\xf8\xa6eg\n\xc4\xac\xf1~\xe2U\x1e\xd1\xa2v\xdd\x0dt\x82r\xe3\xa0\xbc\xa0\xe6\x15\xd1\xafc}\x1cx\\\xc5Pc#c\xb6!9\xd5\n\xbb\xebH\xd8\x89\x85\xc0\x13\x08\xe9r\x13\x07\xa21\xa1\x0f\xcb\x17\x1dI\xcd%8l4\xc0\xe0\x15\xec2+\xaf\xb7w\x82\x847\xa0/\xb3\xaa\xf9.\x8e\x0bC\x8e\xb6RnJ\x15\xb7\xc9\xaac\xa9\x9b\x80Mnl-\n\xe2\xb2\x08\x92\x86{F\x0d\xf7\x8a6\xb9\x89Un\xaf\"\xaf\xdc\xbf\xf5\x86\x9bVu\xad\xbb%\xdd\xd1\xfd\xfa\xb2\xd1\x8d\xaa\xbf\x14\xfc\xa4\x9fue\x16L\x98\xf7\x1d\xfd\xaf\xf7\xba@\xcch$\xb1\xab:O\xc6K\xe7vP\x85S\xc62\xb7#GGx\xe6\xb6\xec\x0b\xcd\xbc\x08o\xec\xaf\xde3]\x9c,\x1d\xd7_\xa1\x16\xaeb\xccU\x02\xad.3\xdbgq\x88\xf3C#\xadTn\x8c\x08\x9f%:\xa3\xdf\x81\xfb\n\xcc\xdc\xd5\xa9\xea\xd3_\xa3W\xd5\x88\xcd^\x9e\x9b\xb0\x12\x99\xb8h\xaf>p\x80D\xf7+i\xb05\xdeG\xd2\x0b\xe8,d\xa7\xe3\x10-\xcf\xf4o\x19%\x1c\x91\xf4\xce+\x19\xa5\xd5\xeb\xfb\xef\xdd\xedN5\xa8\xf6B}\xd7\x86iy\"~(\xce\x14\xcb\x8aC\xa5\xae\x8b ,\xc5]\xb9\xefQ\x88\xadS\xffX\xa3\x1d(%\x94\xbb\xe3\xa1.`\x9a\x8d\x94\x8a\x07\x0f\xd4\xed\x8d\xce\xd1B\xb3\xcc\x04S6\x92y\x1cUrq\xd5\x9d\xb6Y\xe8v\x14\xddq\x0d\xc7\xa8Gv\x99\x8ax\xea\xb8\xf0\xbd(Z\x12/\xb4Q\x94!E\xb8e,\xc0LA\xe8\x15\xfd\x10c\x96\xf4\xbcG\x07N7HI\xec\xa5\x91>\x90\xe3\xb1\xde}|O\xb9\xcd\xc5\xf6\xe8\xa0\xba\xa3=\xfd\xd6M\xf4\xead_\xbf\xff\xe7\xbc\xcdj\xe5\xcb*^mt\xacV\x0f\xcb\x8b\x878\x8cj\x9e\xcb\x87Q\xf5)\x1e\xe64\xf1\x17\xdf\x1bO\xf2\xe5\xa3\xfa\xb6\x9b\xa8\x10K\x8d\x1e\x94\x8d\xa6\xa4\x17\xb5\xa6$\x0c\xb2T(\xe6\x13\xa6\x98\xf7\xed3\xa4A\x9e}\xc6\x83#\x02\x8f\x16\x8eh\x8e\x0bG!\x11\x0b\xf6\xec\xe4q\xf2\xca\x95\x1bb1\xe0 \xe8\xcc$\xee\xa1S!\xde\xa0\xe1\xbb\x93y{\xda\x97P\xc4\xe9\xa7$\x85a\x11\xbf\xb9\xcdo\xeb\xd1\xf3\xb9}S\x928\xfa\x0e&+\x1bA\x8a\x17\xd1o\x0c\xd2\x10;\xd5\xd1V\x1b\xa4\xf0r\xed\xa5N\x95B\x8c\\R\xb1&t\xe0\x86\xf9\xf2\xa5Z\x07J\xf1\xe1#5$\x0cU\xa0*\xe4\x06\xb3\x05~\xc7\\\x08\xe7|\xa9\x98\x91A\xb5M\xd8\xef\xb0\xbb\xf1\xd48\x178\x0f\xe7\xe8\xe5\xfa\x8e_Ge~4\x94`\x8a\xf9\xa1\x07\xe4\x0b\x18\xc19\x06\x16\xb3\x8b\xc9i]tgQHN\x1c\xb4\xbf\x9f\xc1\xa9\x10\xe2\x983\xf0\x05\xd3\x98p7\xf6\xfc\x17\xe5\xdf\xf6\"\xd7\xa6\\\xbb0\xb3opg,\xf0\xae\x15\x9f\xe6\xebj\xa3\xed\xb6!a\x16]9Mv\xa0\xc2\xdbs^\x83\x0d8\x03\xf2\xda\xebF\x8f\xe3uQoW\xc1\x89k\x8e\x10\xbfz7\xa4\x82]#\x05\xbb*\xc7\x92\x1c\xa9\xb6\xc0\xa2\xd8vx0\xdb:\x9bt\xd5\xd8\x0c| f\x8c\x07\xd8\xb3\xa2\xfbn\x8d\xccW\x89\xb0\x1b3\n8\x1b\xa7,\xcb\x1f\xcb\x9e<=q\xa0\xdd\x8e\xb5\xd4\x0b\x8b\x8e\x80\x17\x9d\x8a\x9c\xab\xf6\x9a\xa9]\xac\xef~\x17\x03\xab\xb9\xe0u/\x13.:\xd5\x1fI\x0bo V\x13\xd3\xb5\x10\x17<&.\xe2\x93~\xf5\xb4Zry\x97\x83\xd8F\xb52/J\xa4J\xc4\x08}y\xfa\xf9\xf9\x8c\xb00\x94A\x14\x9e\x9f\x0f\xc1\xc3\xd0\xa2D\xe7\xccw\x1ez+R\x94\xb9\xb2\xab\x0e\xd0\xef\xcb\xea\x91\xb9\x1dT\x9b\x9cG1}\xbd\x1e\xcb\xf8\xa0\x17\xcc\x0e\x86\x7f\x86\xec\xcf\x08\x02;'\xe8\x8aR\xa4\xf4\xfb-\xb9\xf9x\x93\xc6\x0c\x8e\xe3\xb8\xf9\x08\x04!$(\xd3.\xcc:\xfc\xc5\x98L\x99\xa7s\xce\xc1Hm\xd7\x16^\xf2\x92c\x89\x98\xcb\x98YA\xa4'\xcc\x9f\xcf\x92 J\xaa\xf4 y\x8e\xaa\xaa\xb3\xb5H\xf6R\xa9N-\xc0kU\x1f\xa8\x95s6V\xad\x92\x83EE\xfc\xa7\xf2\xfa\x8a\x92\xc3\xca\xbb\x08\xe3/\xe2w\xe5-\x9e\x13\xa9\xf2\x9e\xc8\x9a\xc4\xde\xe4\xbf\x94w\x13\xe2\xc5J\x93\x0c\xc8\xdfd?\xd4\x17\xd7\xc4\x0fHR}\x93A\xc5\xab\xec\x97\xe6\xdde\x90*o.\x834\x7fo\x19\xa4\xca[\x92\x08PyWz\xc2k\x90 \x9azrAA\xa9'\x7f\x92\xd7\x93C\x94z\xb20\xf1\xa35E\x83\xea,HOx=\x12\xa4\xe4E\x82$F\xa2J\xd5\x9d/\x119\xdaFU{.\xba'\xda\xaf\xb5 \xcb\xba_A\x95*;\xae\xd2\xb1\xc0\xdc1\xb9\xe5MZ\x15\xe4\xdb\xc6\xec\xedL\xef\xd1\xad\x90Qh\x83\xe5(\x0e\xa1\xa5\xdfx\xa4x=\xdf\xb4\xd5\xa4\x92M\x0b\xd4Q.\xcb\xa3\x0cddr\x9b\xa6U\\>\xe1\xed\xe8\xb5\xa3\\\xee\xae\xe4\x86\xc7\xe0\x189\xc6\xd9r\xa7\xf4\xbd\xca\x11\x11{\xe5[\xae\x98S\x8b\xbd\x105\xbf\x10\x94\xe2\xf0\x97\x04f}\x15\xe5\x99\xd0UQH\xe5\xf7\x89\xa5%\xe9g\x8f{[G1b!\xcfP\xdf\xa0\x93\x1cR\x8c\xea\x9f\xcb\x0d\xfac\x90\xd8\x1c\xc52\xdc}4\x9b\xf5:?\n\xb1\xab>Z4\xb9\xbd\xa5\xcf\xe54\x05\xac\xecY^\x16#\x98V\xb3\x18\x9e\xf2\x8b{\xb4\x1d~'\x8ecj\x87\x87\xfe\xb0\xa3b\xd1=\\\xf4\x80\xa2=\xf3\x93\xc5X&\xe3\x1e\xf7q\xc7\x07\xf4E\x17\xbcq\x9f\x03\xbf\xc5\xae\xe7}\xefO\xc7\x11\xe2xvr\xaf~;\xae\xa8\x8c-\xe0\x1d\xf0\x97k8\xb5\x99\x16\xd5\xa1n\x17\x1b\x83\x07\x8f\xa9\xc1\xe4\xac\x1e\x93=\xee^^\x8f\xebyn>c)\x1f\xd9\xc1\x06{\x81\x0b[\x19\xc5.\xf3f\xa0\xaf`\x1a\xc0q\xb2 =\x8d$,\xdd\x9c\x9eJ\xd2\x7f\x86\xe8\xe0\x8d#\x89\x9e\xd6\x93R\x9f!J\xc6\xe24\xb1\xbe\xf6\xa7\xe3\x00\x91.\xba\x03a}\x90\x9e\xe5\x17q\xf3\xce\xd0\xf7\x85\xdf~\xe0\"B\xd3g%\xd0 \xb4\xb0\x18\xb7\x7f?z\x04\xbe n\x0e2\\\xbf\xbb\x8e\xd6\xb6\xe3\xb2E\xe1\xbf\x9c\x0dj\xdeb\xbbH\xd7\x016\xd9'\x9b\x86_\xe1r\x8a,\x97\xa8\xd5\x7fG\xff\xeb\x1eRY\xc5\xf0\x7f\xcco'\xb2\x90\xb4]\x0ci\xc7\x83:\xdf\xe7B\xe2VB\x9c\xdc\xf66G9\xb4w\xa7\xf6W\xef\x91P\xa6\xf6+\xef\x15\xbb\x83\x98\x16I\x1e\xe0\xe1fk\x03\xa9\xbf5z\x18=XYt\xbe\xe3\xb4n)\x1bW\x89\xe4C\x88\xc5\x12\xb9 .:\xc2\x19\xbc\xe0\xca\xc2[PHi\xe18\xd8h\xd7\x95\x85\xac\xa6\xe0\xa1,_6K\xac\xe3B\xc8~\xb5\xdb\xa9\xf3\xed\xf0BIc\x85\xf9\xa3\x90\xf1\xb7p\xa0\xec\x0c_&Va\xe9\xb7\x86*<\x0c\xd1\xd1\xc8+\xdf\x02\xbdy\xc8S\xa0^\xc9\xa0G\xf5\xd0(\x8a\x9a\xe48\xcd|hJF\xf7\n\xc7\x15\xcd\xe09\x82\xb8\x10\xa1\x7f\x01ECM\xd8\xe4\x0dh\xe1F\x18\xce\x8e\xb9L\xcag\x83\xa5d\xc9G5\x00\xe1\xc7\xbb;\xe3<;C\xf9x\x86j\x16M\x136#\x9e\xcb\xf3~\xf3S\x1aC\xfel\x0b\xe4\xe7\xbdi\xd5\xf6\xa6\xe1\xc8@\xe4\xe6=U\x90\xf54\"\xb2W\x16\x91\x93\xb2\x88\x9c\xe4\"\xb2W\xfc\xd2\x88\xc8j\xcd\xc6\x9er\x89\x98\xae\xd4\x86\xd3s\x0f\x96e&\xe4p\xc7\xed\xe5\xcaD\\\xed\xeaw\xf4\xbf\x1e\x86\x07j\xef;\x85v\xff\xb8\n\x8f8\xfcH\x7f\xbfM $..\xcfT\xef\xe0$\xa6\x8bo\xe5b\xdb\x05\x0870mL\x15\xc1\x93\x184\\x\xe7J\xd3\xa5\x0bk\x17\xfd+\xe7\xdcAQ\xa5/u\x0f\xaf\xd0\xba!\xc2\xce\xa9\xcfo\xf0\xb9\x08\xc1X\xc6\xe8\xe2=\xf4\x08\xaf\x97\xe5\x84\xa4QD\x17\xd6\xe2V\x8c\x91\xa1DJ\x07\xbcVj\xd4\xd4\xebC\xad\x80\x88\xd7\x1737\xbb$\x17\x9f{.t\xfa\x945\\\xf1\xcb'\xcb<&\xc2\x9a6\xab\xda\x9c6rX\x8eli\x02\xe1\xaa\xc6o\xf9}e\xfa\xa2P\x04\xe9m\x9e\xbb\xda\xdb\xed\xda\xfb\x93\x90\xbb\xbbI\x11\n\xb4s&;\xee\x8d`\xbc\xc0\x88\x15\xa1p\xe2c\xd4=t\x98\x0d\x0e\xa7V#\xbd\x89O\xcc\x18\x12\xdd\x95KF'\xd6LZ^b\x96|\xe1\x92\xdf\xe0D#>(\x7f\x98\xe9\xa8.R\xec\x8c'4@~=c\xc17\x8a\x80\xc8\xb8\xb7X4\xd8\x88\xf1+\x1e\xcb8\xc6T\nQ\x98\x92\xeb\x14\xf30\xc5\x97\x89\x93\xfbo\xc6,yD\xc00%*P\x88\xae\x89)Et#id\x99\xbe\xf9\xdej\x8a\xc2q\xc5\xeeEr\x9fp\xe3\xa6\x08\xe9\xd0\xd3rV-\x1e\xfeCT\x0f\xa9\x19a\x84\xfc\xccD\x8a\xb4\x1b\xcc\xcc\x9a?\x1e \x13jS\xf9\xd3\x82\x9c\xdd\xd1\xdaXO\x16\xe3\xa4\x08\xda\xcb~\x04\x85MF\xe9>\xbf3\x86X\xa1\xf4\x8a\xffX\xe2\x8f\x9cq\xc5\xdb\xf5e\x81\x0eZZ\x94\xc6\x1b 6-\xc0\x88\x8e\xc3\xa9\x0es*^8\x90u\xe9\xcf\x0dD\xa1\xc4\x9esa\x85\x8b\x14Z \xa5qJ\x12{\xad\xe3\x0fj\xefs\x1a\xc2\xa8\xa2\xe8\xaf\xf9x\xa6\xbd`\x9b\xe1M\xfb\x0d6\xc5g$\x8d\x03rE\n\x8a3\x8b\x08#D\xc1j\xbd$T(\x12h(\x90\xf8\xb1\x96*\x89\x0fk\xda\x9e\xbb\xa0\x1bqe|9\xb5\xff\xafq\x9c\xe5\xcdj\x1aoM\xdf\xf8\xfb\x0f\xd6\xbd\xbc?\xdb\xf5P\xac\x08\xe6n\xe0oh\xd1\xb1\x04)\x04\xaf\xaa\x8a\x81\x85\xca3q\x1a\x93\x8a\x01\xf9`\xbb\xad\x0f\xeaW\xe3\xe7D\x19\xc0R\xfb\x12\x88\x03\xfe\xa64I\x7f\x8e\xc7\xc1\xe8\xe9\x8e\xbeM\xcf\x8e\x1c\x93\x8c\x1f\xe1\\cVF\x9ct\x84x\xb3\x03I\x1elH\xf2\x7f\xd5\xefa\xe9\"\x1asj*\xee\x84y\xccO\xb1\xd5\xe9x\xe2\xe4R:\xac\xb4z\x98\x9fP{]L\xc3\xbf.I\xfa\x19G\xd0\x1f\xd38z\xc5 <\x16LV\xb3\xfd\xef\xa7\xd4\x92\xd2\x0f\xe96X\xe8B%DsXD\xecm\xf1\x88\xbd\x04\x86\"\xa5b#s@\xaf\xb2\xee\xf3\xb33\xba\x1c\xf8\xa5K\x12\xdf[\x17\xfaT\x19\xa8N\x95`,\xcd,H\xc4dP2z\x19\xbc\xd8\xfef\xd1\xec\xdf\x84\x98\xfcl\x16\xc4$\x01\xaf\x08}g\xf4X*\xc5\xbb\x96\x82L\xf1\x10La\x9ea\x81\x12\xcfN\x9f\x1d\x83)ya\xa2t)[\xc2 \xb4\xdb\x01<\x81\xf8\xc4\xc1\x19\xe6\xf9{\xe4B\x01\xde{\x8c\xa0Mg\xff\xe9\x08\xfa(\x05S\x01d\xb7\x8ftgp\x08\"\x03!N@\xc0\n<\x1d\xc1\xdeQ^v\xff\x10\xcb\xd6=\x7f\xf4\x08\xf6\xf6i\x81\x8c\x12\xc6\xc9\x04\x83F\x15\x96\x89\xfe\x01Zr\x80\x12K\x1b\xfb\x1a\xb0*[\xfdJ\xd8\x01\x82uup\xc4\x1f\x88\x0e\x1e\x17_\xf5=D\xe8\xc1~\x0e=\xee\xe5\xd0\xe3\xc3\x1c\xda\x1f\x0c\xf02(\xce\x13\xce\x11\xa5\xe0\xac\xcbe \xce\x9b\xf5\xff\xfe\xc5\x9fY\xb5\xfbPuz\xd78Q\xc8\x18\x8b\x1a\x18\xf6\x0dO\xdan \x91Y\x8a\xcfJt\xe5r\xec\xeeX\xd6\x1b\xbew\xf2\xdb:\xa1\xdd\xef\xdf'\xb0\xa76p=\xad\xd8:?'\xc9\xa7\xd1,[\x12\xabJ\xb5y\x9a 9\x8d\x82\xc3T=\x98K\xaf\xceQ\xc5x}9I\xbd\x94|\x7f\x99]\x06a24l\xdadM|\xd33\xfa\xf1\xb0\xcdd\x08\x99Y\xc8O\xc8\x92\xf8i\x14'C0\x04c\xd2\xbf\xcbR/\x19\xbb\x068\xb6Y\xe6\x13Zs\"\xa6\xc2\xdc\x8f\xbc\xaf\xd1F}\xf5\xf4}U\xf1\xf0;\xfa_\xefU\xf9mn\x87\xf6~\xffX\x89\x90\xcd\xed\x0c:\xbb\x84o\xd3'{J\xa0e\xfeh\x7f\xaf_}\xe4\xe5\x8f\x06J\x90i\xd1\x87\xbd]\xc79\xf9N\xfeL\xe0\x0e\xf8z\xc5O\xca\x98C\x81\x9f\x05s8\xa9\xa0)\xe3\x06_U6\xa7|+G\xa3\x10\x93b\xe6\x05!=\xb65\x1c\xac\x0bC\x1d\xa7eEF$\x93\x19\xbc\xd8(i\xd9\x8fC\x9d\x84\xb9\xd1\xbdB\x99\x07\x1e\xb4X'a\xb1\x1c\x97\xd5 \x93\xdfQ\xbf\xd1q/\x95[B\x97$\xfd$\xf2\xbd\xe5s\xdc\x04\x9b\xc5\xfa\xb3{\x18\x8c\xd8\x8b\x13\xf2\xd3\xde\x8a\xbf\xea\xd8\xb1\x18\xfcv^\x0erC2]|\xdc\xe9t&a\x16/\x87`-\xd2t\x9d\x0cwv\xd6$M\xd2(&\xdd\xe4\x9dwyI\xe2n\x10\xed\\\x0dv\xc4\xaf/\x92(\xb4&\xe1,Z\x9d\x07\xb3!X\x7f\x85?\xe8d\x815 \xd11\xddK\xa3\xf8\x07\xa5:\xa3p\x19\x84\xe5\x1aEAk\x12F^\x96.\x06\x9f\x91Y\x10\x13?-\xde\x1c\xee\xec,\xe9\xbc-\xa2$\x1d\xee\x0ez\xbd\x1dV\xb2\x13\xf3\xa2\xddE\xbaZZ\x93\xf0\xb1v\xd0\x1bQp\xc9\xb5c\xd07hR\xe3\x87\xa9^\x7f\xdc\xdb\xdf\xebi\xb7od\xc4\xdcZ\xf4Q\xbcH\x85\xb5\x120\xfe\xa6\x88\x15=#\xeb\x98\xf8^Jf\xe0\x853\xc9\x91&K\xc8\xac\xdb\xe0C\x03\xf2\xfct\xa9\x98\x87#\xe9\xc9IK\xbbg\xfe\x82\xac\x98uu\xf7\xa8\xf4\xe4\xe3g/?9{\xf6\xf1\x8b\xf3\xb3\xe7\x7f\xed\xc5\xa7\xcf\xb8\xc1vP*\xf3\x93g\xaf_\xc9\xcf\x07\xbd\xdd\xd2\xf3\xe7\xaf?{Q~^~\xff\xa3\x17\x1f?\xfb\xc1'o\xce\xab\xed\xec\xefj\x8b}\xfc\x83O>\x91\x8b\x1d\x95\x8b-#o\x86\xa1\x02\xe8\x97\xea\x83g\xf4P\xc1\x9f=c\x17\xce\xc4\xe3\xc4\x9b\x93O\xc4\xbb\xe2\x87\xae\x80\xa8C\xfa-\x17\x9be\xab5\xc6\x0c\xa4_\xaa\xef\x7f$\x1e\x8a\x1fr\x81\x9f~\xf6\xe9'/\xae}\x82!\xe89\x1e\x96\x86\xf6\xe9\xcbW/?}\xf6I\xddZl8\x87\xe6\xe9K|/D\xd5\x81E\xbfY\xa5gH\xe1\xd8C\xfcZ~\xeaG+\xee{\x12\xd9\x16\xffQ.\xe1\xcdf\xcf\xa5\xf0\xe1X\xb0\x0c\xb3\xee!\xdfI\xfe}\xd5\xab\xfcA>\x9b%0\xbfD\xa5h\xa0\xb3|\xeaJ`/\x9f\xaf\x128iVH\x97_\xf0U\x85\xf2\x1cF0(\x83(\x92\xed\x96A\x14u\xf6\xca\xa0\x85Z\xd7L\xad\xebJ\xad\xeb\x86\xb9\xc2]\xf7z\x9d\xc9u\xefhr\xdd\xfb\xde\xe4\xba\xf7|r\xdd{\xd1\x99\\\xf7?\x9e\\\x1f~\xdc\x99\\\x1f\xedM\xae\x8f\x0e:\x93\xeb\xe3\x8f'\xd9\xc7\x1f\x7f\xfc\x02\xff\xffxz;\x9ed\x1f\x1d\xd1\x97\xb3\x8f\xbe\xf7\xf1\xc7S\xfb\xb4E!\xcf\x19\x84\x96pn\xed\xd3\xe1\xf8\xf3r\xb1\xdb\xcf\x9dJ\xb1\x9dr\xb7.y\xb7\x8e\xf6\xcb\x1ez\xe5R+,\xe5N\xc6\x93\xe9\xe4\xab\xc9\xfb\xea\xe3s\xfa\xf8s\xfbt\xd8\xbam\xb5n[c\xaf\xf3\xe5\xa43m\xb7\x9c\x0fv\x82r\xc9\x8b\xa2\xe4\xf8\xf3\xa2>\xc7>\x1d\xfe\xc4\xb8\xd79\xf6:\xf3\xe9W\x83\xf7\xb7\xec\xfb\x97\x93\xce_9\x99\xecLN\x87\xdf}4\x9a\xb4'\x1f\xb8\xe7\x93n\xeb\x7f\x98|\xf8xbO\x1c\xfa\xf6\xd4\xf9\xf0\x83\x9d@\xc7\"\xde\x19YD\x9f_B\xc33\xe3.\xfb.\x11q\xb5\xaakcU\xc7EM\xbb\x83\x0dj:\xdb\xa6&\xec\xdf\xb6}}alao\xaf\xa8\xea\xb8/}\xdf\x95\x9a\x18\x94~\xeco\xd0\xe03\x83yG+\x9e\xee\x1d\xa1\xb9\x02\xa5K~\xd2>\xc5 9{G0\xa4\xc7\xea'\\\xef\xb0;\x80[`\xc9\x9c\xd91\xbb7@}O\x87\x16j\xd3i\x19B\xa7_\xdb\xb1\xd7\xe6\x998\xca\x15]\xd6\xa4g\xb1\x96s\xc8\x7f\x87\x00\xb9\xc8\x05\x85\xf4\xfb\x07\x12(\xc5BU@?_.\n\n\x19H\xae\xe9\nA\xbd\x81\x04\x9a\xb3R{\x12(f\xa5\xfa\x05\xe8\xbf\xa7\x90]\xe95\xd4}\xec\x16/=\xb6\x1e\xc3\x10\xf6\xa4a\xec`\x0f\xe5\x96&\x14r(u\xe7\xff\xf9y,\xb3/A~\x13\xcb\xc8#E\xaa@\xa1G\xbd\n\xf4\x98)\xabk\x17\xe1\x8b\x9a#\xc6\x93\x11\x1c\xec\xef\xef\xee\xc3)W\\a\x96\xe9\xe7\\\xdfd\xa7\x85\x03j\xf9\x01K\xe9\xd9\xa6\xa7\xb5\x0e\xd6p\x00O\x9fB\x9fJX\xfb\x07\xbb\x83^\xf9\xd1#:\xdf\xbb\x8a\x11\x15\xe4\xd3\xd8[\x90\x13\xd3\x0e\xf6\x0f\x1c\x17^j`\x9f\xb2\x84r\x9f\xc2\x13\x18\xec\x1f\x9c\xc0\xa7\xed\xb6\x03o\xc7\x9f\xd23\xd9k\xfbS\x87\xc7\x19\xe8\xb9\xf0\xb2\x00\xea\x88\xd3\x1b\xad\x1e_hb\xc9;\x08P\x01C\xdeQI\xb7;\x0f\x96$\xf4V\x84\xb2\xf6 \\g)\xde\xdb\x8f\x92 \xc5;\x96i\x97\x9e\x1fd\x18t8\xf0,\xf5\xe2\xb2\x9b\xbc\xda\x97\xe7\xda\xbe0Q\x99\xf7\xb3\xf6\xfd\xef\xeb\xdf\xefF\xe1\x0f\xbd8\x0c\xc2Kv\x96\xcc\x7f\xf2\xeb\xea\xe8y\xca\xeb\xd7-\x0e]\x97\xcf\x94\xd3\"\x15\xd9\x86\x8d\x16\x1a\xf1\xbe1d\x0b?\xa2\x8f \xed^\x918\xa1\xc3x\xf4\x88\xcd\x845\xcb\xd6\xcb\xc0\xf7R~3\xf5'h\x93\xc0\x8eT\x98Q\xca\xe5\x91\x0fC)`\x15{\xb3\\\x12<\x9f\x8a\x96 \x90k\xcfO\xf1b*\xc9U\xba\xb4\x9a\\\xe3n\xc7\x8c+R\xa67m;\x93\xae\xf8\xf6\xc1N\x97\\\x13\xdf\x0e\xc7=\x1e\x03\x8d5\x14,\x97\x9dy\x14\xafdw\xffh\x0e\xe9\x82\x80\xda[*\x8b\xa1\xf4\xf82L\xedx\xdc\x9f\xbal\xafDe\xf8@\xc0\xa5\xb8\x8e\xac\xb5,d#\xc1lhX\xbf\x983\xde\xe6,\xf2\xf3A\x15\x13:\x82\x90E-\xef\xfa\x0b\xe2\xbf\xfd$\x08\xc9\xf7b\xe2\xbd\xa5\xe2[Dw\x90h\n\xef\xdc\x0e\x8a\xaf\xdf\xe7\xad&\xd9\x9a\x8a\xb1d\xd6\xd0hiu+*\xb67\xcf\xfe\xeav\xe8\xa2\xe2\xca\xc0\xb0\xdao\x9e\xfd\xd5\x9a\xc5N\xdfE\x85\xfe\xdf\x12\ny\x16\xd1\x0e\xbf\xd1u8\xef\xa6$I\xed\x18\x03@(K\x9bz\x97\xb0\xf0\xc2\xd9\x92\x80=\x0f\xe2$\xcd+t\xc4$\x94\xfa@[\xc9C*\xa4\xde\xe5\xa7\xde\xda\x85\xb8@\x9b\xc7\xe9\x82\xc4\x84\x1ep=X\xc7\xe4*\x88\xb2dy\x033\xe2/\xbd\x98\xcc \xc9\xe6\xf3\xe0\x1a\xa9\xa2\xf5\x18\xda\x10C\x1b\x1e[R7\x1e;.\\\xb0.\x07\xe6.\xafcB\xab\xb1\x13\xe2G\xe1l\x83>\x8b\xce2\xbf\x87r\xe0\xfc\x92\x96Q\xa5=\xaf\xc4\x92\xe2@U)\xa4\xc8\xdf\xaa\xaa\xe9\x08<\xd1\xa3\x02\xbac\xb0\xd8;\x94\xd8\xf2+\x1e\x888\xb4\x19\xa5<\x08V\x120sz$E\xf5f\xf9\x08\"\xfa\xa7=\x82\xbe\xc3e\x06t\x0e\xf0\xaa\xb6\x15&\xfb=\x19AF\xd7,C\xb9\xa7\xdf\xdf\xeb\xf7\xfb\xc5d\x93\xeb5\xbb\x83\xcf\xa2\x1c\xfc\xe4\xd9\xebW@\xab\xf1\xfc\x94(\xb90A\xdc4\xbca\xab\xe6I4\x84.E\x92\xc6\xc4[\xa1\xc3\x81\x17\x84 \x84Q\xd8Y\xc7A\xc8\xb6z^m\xa2\xab7\xed\xc6$\xc9\x96\x98/\xd53\xad\x99f\xc9>)\x96Lqo\xb9\xe2 \x04\xd0-\xac\xe2,\x833\x1cw\x83\x84\xa7\xdb\x0f%\x0c\xe4\x1a\x9a\x15\x89/ \xac\xbc\xf5:\x08/\x93\x13\xc4\xb6u\x1c]\x053\x8a\xddQ\x16\xfb\x84\xe7o\xa6\x9b@&k\x96\x93\x87\xd8\xa4\x87E[\xf2*xKn\x12;t\x9c|A=x\x02>\xfd\xc3\x164\xc3\x80\x8f\xde\xd4\x95\xe2\x9ce\xd87\x9b\xb0\x90\x94!\xfa\xdb\x04\xecG\xabW\xcfM?\x920Z\xce?\xac\x9b*\xdf\x85\xb9\x8a\xd7Aa\x08\x0cd.\xc3S\xf2\x08#\x91\x95z\x97\xc3\x1bo\xb5\xecF\xf1\xa5;\xe8\xf5\x06C\x9c?\xe6q\xabAsZ7\xbb\xeb\x18$L(2E>\xc0\xa5\xe2\xae0\xf4\xa0\x1d\xe5s\xe7\xc3\x13\x98\xd3?l\xee\x04.Dc\x1fS\x90\x1b\xb07/\xa6\x96\xc1\xe7)\xea]\xe9\x94'y\x8cb\x9e\xde\xa9X\x13\x06\xb0\x99\\\x04t\x8f\xdd\xde\xeaD\xa7\x11x\xecI!`\x95\xe5\x022\x13(\x06o\xc9\x0d&\xe0#\xe3`\xcaB$\xe5\x97~\x83\xe6D>\xea\xe2\x7f\xb9\xd1Y\x8a\x1f2p)\x05\x8d\x92(I\xd1s\x87\xdd\xe8\x12?\xdbmz\xac\xd8\xe5\xc8p\n\xb6\xfc\xc8\xcd\x8f\x9a\xb552Y\xaex\x8d\xca\xe8lz<\xc0\x89\xbd\xa0,\x9en/A\xa8\x18\x85\xc7gmt3\x92$S\x1c\x80\xa8\xacvf>6\xf1\xee\\\x86\x97s\x0e\xd5\x0e\xe1\x84;\x10\x04\xda\xb8\xac\xdc+\xeb\xda\x0e\x1c\x1e}TS[\xbb-\xd7\xa7\xdd)\xb8\xdbv\xd9\xd1\xca\xe0!7\x8bj\x0c~\x9b\xb4\xac}\xf9=\xbc[\x04Td\xe8\xf7\nA\xae\xbf[|\xe7`C\xbf[\xef\x90\x15\xe12\xaa%pv\xbeD\x07\x83\xe6\x89v!\xa6x\xc5\xd6\xfbe8\xa3R*\x9e\x9f\xf8A\x96.\x80\xfc\x90\x16\xdez\xd8\xefu\xbb\x8c\x87\xb0\x0d\x8b\xe1\xc6\x0cq\xa5\x9e\xcd\x0c\x99\x06\x8f{\xc16\x08\xe3\xbe?\xc5\x89\xfb\xd2\x85V\x1f\xbd\xe3\\\xd1\x94@\x0e\xa7\xdc\xbfM\x1aw\x0bf\x8f\xb4 g\xf7|HO\xb9\x83\x10\x9f`\x87\xf3\xb1\x0bo&\x13\x01zj\xf1 !?\x9b\x91\xd0'@\xc24\xbe1\x8a\xd9\xcc\xc7\xacDd\x88\x96\x96\n\x12\xd0\xf28\x8e\xd0\x83\x13Kd$p\x07\xc5\x89\xb4\xfb6\x08g0\x02K\xf4\xc0r\x8b\xcd\x841\xc6\x9a\x04\xca\x9f6\xd3\xa8\\\xc4D\x8c\xd6\xef\x80*\xa6\xd3!\xee\xee\x16\x11\xc2\x1b\x04\x90\xdc\x7fBW\x8f\xb4a\xe8\xf8M\x1a\x18\x8f\x1f+\x99i\x87R\xe5\x03.\x01m\xc2-0\x12m\xc41~\xb3\x17\x86\xb0\xcb\xa4\xa4@D\xb1\xc58\\t\x19Z-k\xf3Z\xd8\x1b\x16\x0b6 \x0b\x94\x91N\xf20\x8a\x03\x9b4\xa7\xbc\x98\x8b\x01\x92\x14p00\xb2~\x89r<\xc9\xb3\xf8\xd1\xd1\xc7\xba\x83pi\x97m\xd2\xbdBL\xcc\xc2\xfc\x04K\xc2\x99\xd0 \xf0\x83\xe8\xbb ]\x04!xpE\xe2\x0b/\x0dVt\xe5\xab\n\x1eS\xa8#.\xb9I\xe3m\x9d1)._M\x96D\xe0T\x9c\x80\xbdK\xa1\xf3\xe0\x07H~\x10\x06r\xed/\xbd\x15C\xc0\x95\x17\xbfM\xac<\x0eqe.X\x16\x85\n\xdd\xcd\x15;\xf2\x195\xf4*:\x9dJ\x9bI\xe6/JGn\xe6\xa5I1\xaf\x8c>\x8c\xb4o6\xef\xeaB7\xaf\xe7*WJ\x15\xba\x02\xe3L\xcd\x97\xd1;J.\xe9v\x8d\xe2R\xff\xcb\xab\xa6#\x7f\xc8\xc8Z\x17\xfa\xf60\x99u\xfd\x1c\x0d\xd1m#F]\xe6)\x08\"\x1a\xc3PU\x83\x85\x8eT\"W8\x85STs\x0d\xe9.\xe5\\\xa2(Ea\xe2\xa9\xee\xb1z~\x16\xe5\x99\xb6-\x0bs\xcd\x9a\xb4\xea\xa8Y\x0bQ\xb3\xf6\x18=\xc1k\x89\xf7\x0f\xcd\xc4[C\x96\x8f\x18Y\x0e\xefA\x96\xcd\x82\x8c\x9e4\x87\xc0K\xc8\xe4\xd9\xd0\x81\x12fV\xb1Zl\xdc\x90o\\v\xd4l\xbd\xb0C\x07\x93\xc76\xd7\xa8\xe5\xb0\xd2\xb6\xc9u \xc5~,\x0f!\x8cf\x04VYR\xe0\x9b\x97\xc2\x92xI\x8a\xaa{I\xcbVb\xd3\xf5\xbb\xa9a\x81\x7fJ\xd2\x86i\xf8\xc2U~I\xf2\xc6\x85K\x17V.\x9c\xbbp\xe1\xc2kf\x8c\xd20\xed7\x06f\xfe}\x033\x97\x16{\x19$) I~Vb\xbfl+Zc\xd4\xd9T\xe8j\xa1\x88\x1e\x9d\xcf\x82\x00pyE\xfc\xcc%\x15\x06@\xb5'\x8c\xd0\x19b]\xc8eLA\x85A\xeb\x1f=R\x04Q\xfbM.\xaf\x96\xc578e\x93\x00\xc3\xca!\x93\x9f:\xd0\\W}\xf8\x84+\xc2>E\x97x\x07\x0d\x1e\xf4\x85O\x0d\xde\x9a'L\x82\xba\xbd\xc5\xcdx\xe2\x94\xbbwZ\xf4\xee\x86\xc9c\xdfJ'a\x88\xd5\xeb\xd6\x8f\x07j\x80\x11\xbc\xa1\x9d\x8cr\x0b\xce\xa7\xf4\xc1\x9ao*z\xea\xbb\x80\x11\xf8\xc5\xa4\xcfs\x92F\xf0<\xd6\xa6\x9c\xecu\x99\xd5\x94\xec\x88\xf9L\xc1)\xbf:\x8eg\xaf\xd789\xdb\xd8X\xdcB\xc9\x9b\x98Og\xc0=w\xcc'4\xe0^;_\xd5\x8475=\xcb\x91T\xfb\xf4\xaa\xf6\xe9M\xed\xd3K\xc3\x06\x04\xeeG\xa3\x0b\"|\x87\xf3\xe3\x92\xab\xac7;?z\xc6$D\x18\x84\xa8\xa9\x1e.\xd6D\xd2\xa1-\xab\xc8\xb4\x07\xecP\x80\x07\x9a\xfd#\xfe\xfd\xf6\x96\xd2\xf2\xb8\xf9\n%\xd2\xc1\xd0\xc5[\xaf\xec\x08h\xd4A\xc9\xefI\x07<\xadL-\x7fX\xaa\xdf\xa6\x91:'pm{t\x9f\x1b\x8a6\xc8W\xf2\x87\xf6p\x9f\xf9[x\x0e\x9c\x99\x1a\xafH\xca\xb9\xc4\xe8Q\x11\xfe\xffc\xee[\xbb\xdb\xb6\x95E\xbf\xf7W\x8cx{\x1c2\x92\x15I~$Qlk\xa5i\xd2z7ur\x9a\xa4\xfbt\xcbj\x16-A6\x1b\x89T\xf9\x88\xed\xbd\xdd\xf3\xed\xfe\xb1\xfb\xcb\xee\xc2\x0c\x00\x82$@\xd2N\xd2\xd6k\xb5\xa1@\x10\xcf\xc1`\xde\x93\xb2d\xe3\xcf\xb5\xdbG\x97\xad\x82\xbf\xe4%\x9c\x82\xfe\xc0\xae\xb7\xd1w\x02\x12\xb6\xf1c\xa4\xc6\x149}\xb6\x8a\xe6\x1f\xa4\xd4\x9a__\xc8l\xb9\xa8kX\xf5\xf2\xa88Z\xc4\x9b\x8f\x02K\x8b\xa2\xb5@r\x02\xb8\x91\xf8\xe4\xff.\xd4\xf9\xc5/$\xc2\xaf_\x97\x86\x9c\xcc\xf2\x0f\x01c\xad\xb9g\xd1\xd5\x93\x14\xee\x9d9\x07\x96\xfa\xee\xf8\x9f\xd2\x13aD\xd8\x98\xf9\x0b~\xf1\x07kN\xcd\x04\xa9\x12\xe8o\xfc ~\x02>\xcc\xa3U\x14\xf2\x95^\x07IR \x9bW\xfe3\xbbKC\x1d\xb3\xa2\xff}\xaey\x9a\xe6X\xdcz\x12_\xf0 \xae\xb3U\x1a\xe0\xd9\xf9\xc0\xaea\xed_\x830q\xd6W\x05\xd5\x1b\xf6\xb9\x19\xdf\x88\x19\xef\x13\xcb\xe5\xf3\x0b\xf2\xd3\x80Mp\xed\xe42yN\xedi08\xc8Y\xcb \x9cG\xeb\x0d\xea_\xd8\x95ec\xf9l\x91\xceS{\xfb\x04\xa2\x18\x96\xd1j\x15]\xb2\x05\x9c]\x83\x8fj\xd0\xd4?\xcbV\xa8\xeca\xebMz\x8d\xca\x0d\"\xfcr\x9c\xa8\xbc\xa6c\xf3\xc6P(\x11\x0dEYeP\xae\xa4\x037DZ\x04T\xca\xa7\xab\x1f+A\x06hB\xb1s\xbc\xd9+k{-b\xd9\x1b\x97\xb7(Hk\xc6\x88\x9e\x81\xa8Qr3\xbfVnV\x80;\x9b\x17c\x93\xe8\xac\xf2Q\x15\xf2\xc4\xd1AH\xb3\x01\xda\xba j\xab\x9c\xae\\\xd4&\xf1d\x81~\xc5\x16\n\xfd\xfe\x81\xc4O\x0f\xce\xbc*\x01d\xa3~\xcaZ]\xccY\xb3\xd4\x93\x88u,\xf9\xc6\x17\xf5\x84\xd2\xc7FB\xe9\xda\xe0\xad\x04\x02H\x859\xa8\xbbi\x86\x05\xd2\x89=\xde\xe9 98IbM\xe9\xc9k0\x1f\xefs8\"\x82ac\xe5EUmN>\x8f\xf6D\x8f\x03\xea\xf1?M\xfeip7\xb2*\xf6(\xc3T\xd3=- \xabM-a\xa5\x8e\x1a\xf3z\xad\x96W\xe8\x0b\xab\xec+i\xd2\x08v\x17\x05\xd8\xfd\xa8\xc1.\xc7\xb7\n~al\x13\x1b\xc7\xf6\xcb\xe4\"\xa7?\x08?\xc2>9\xc5\x9f\x04\xe1\xf9\x8a\xc1\xefY\xc4\xab\x8a\xbdGZ\xa2n\x96\x86\x83t\x1b6\xc3\xdc\xe9\xe78):\x83a95\xbb\x04\x1e-\xc4t\x9f\xff\xd4`\xe2m\xf3\xa9i1\x9eZ\xc9\x88\xf0]\xf5\xd5\xa0\x8d\x18m\xe0\x95\x87d\x03|\x14c\x8dd\x9b-\xce\xa2\xa9\xab\xcbv*\x1aO\x87~\xfb9TrM\x9f\xfcE9\xd0\x7f\x98\xfa3\xafp\xc1\x1c\xa3\xef\x88>\xc9\x16-Rp\xd1\x910\x83\xe3\x1c\x8b\xcf\xcf\xd2\x08]\x89\x1f*Vf\x17\xc6\xf0hO\xfd\xe4l\xc3\xc0\x83#\xfe\xbf\x16\xba\xb2\x80\x14\xda\x11\x19m\x07\xfc\xbb'\x10lo{\xd8\xfb\xd3\xb6k\xc5\x99\x14\x0c\x1b\x87~5\x07\x07\xb0\xebA\x172\xc5R\xa9\x13x\xc1\xae\xfc\x05\x9b\x07k\x7fU\xef\xd2\xa4\xff\xe9K\xf9\x9b\x1b\x95\xe0\xc5N\xb7\xd0ZJ,\xf0!\x8c.C\x10\x11\xd3\x94\xcc\xac\xa6\xeb\xea\xc9\xa8\xc7\xa4~\x8eI\xe9\xe8\xdb0i\xb5\xe1/\x84I\x17Qv\xd6\x06\x93\x96\x06\xd3\x82\x96\xb8\x0dj5\x8f\xc2\x88Z51NGC\xb26\x0c+\x0c\\\xcdXu\x97d\x18\xcd\x8a\xef6X\xd5\xd2H+s'2\x81{#\xac\xdf:\xcf\xdd\x98\xa3\xcd6-V\x07s+\x93\xa7U\xe0'\xb7\xb2x2\x18?\xf6\x8a\xa6N\x9aH\xbd\x14\x8eE7\x84\xbc\x97\x85J\x0c\xb0\x10\xe3(\x19\xc5iw\x92.\xa6\x0fge\xddU\x95\\\xe5`rWS\x14\x94\xba.\xa5\xbc\x95\xdf\x94v\xe1\x9c]\xd1\xcd\xc1\xeb\x8d\xbbl\x06,\xbe\"\xcf\xdd%\xb9}\x12\x92F\xa6w\xe7Q\xfe\xbc;\xd2\xcaw\xf2g)\xe8\xc3\x1f\xfbz\xa5\xc7\xda\xb3Vg\xe7\xa1V_+\x7fL\xa1\x1e\x96\xb5P\x8e7\xce\xbe\xd6\xbd\x10\x9b-IF\xff\xa6\xf9\x18 \xee\xec\xe6\x86\xec\xfb8\x98\xb78X\xcd\xe4J\x80\xbe\xe4ErWX\xad\x8b\x03\xb6\xac\xa5B\x84u\xc6\xb2\x89b\xb8\xe3\x14k\x98g-\x8f\xef\xce^\xdbA\xd4\x0f\x00}eZ\xf4\xd9$\x95h\xbcj\xf29.\x9b\xa5\x8f\xbc\xcdK\xac\xd8l\x05\xe1+1\x8bT\xd3h\xc6gsU@\"\x13\xed\xe6DdP\x14\xdc\x1c\xda\xb3t\xe9\x7f\x99\xc6\xbf\xdfYZ%\xfej\xe3\xb6\xcb?\xbb\xc0\x04\x8af\xf8\xc2\xff\x83\x8c\x078~\xd2wB\xe8\xaf\x0b27Kr\x01\xf9w\x179\x8e\xb9\x14\x15`D\xcb\x10\xfe\xec\x0c%-#\xc6\xbb\x0d\xbeWw8\xbd\x1e\\ \xcc\xe7\x16k\x08C3\xcbv4\xb8<\xd8n\xc4\xf2P;\x1d\x85F\xc8%X\xa0\x99\xa2\xc5\xea\xa6*Q!R\xa4'\xad( \xfd\xbd\x16 \x94\x07\xd0\x96\xde,\xca\xd8\xc0\x998(\x9b\xaa\xa9\xab\x95\x08\xcdnn\x07\x96\xdf\xd5\xc9E\x94\xad\x16h\xabs\xe1\x7fd\xe0\x87\xd7\xd2\xf2\x1a\x95\xb0\xd2\xdf\xbb\xb5\xba[\xe9\x15s\xd1\xd9\x8fjVh\xe4)l\xe1h\xf5\x91\xb9\xda\xd4\xeb\xf1\x84\x06\x13\xef\xfbs\x19;OwM\x93\xfb\xfc\x9e4\xccw\xdc\x82\xcf{~\x05\xb2\xcf=!\xae7\x8c\xbaFh\xbf\xb9\x01g\xe9\xafVg\xfe\xfc\x833\xeb\xc9\xed\x99\x80X\xb7\xda\xeaS\xac=+\xccT\xac\xd1\xd6\x16\xbc\xa7O\xa8\x18\x1f\xcd\xa1d\x10\xa2\xf1=\xdf\xfe\xce\x01\xc6\xe0\xc4\x95\xec\xc2\xbd#H\xfds\xd4< \x98?\x13\xbe\x13\xa2uN+\xf6\xf0 `i\x9a\x97\xdeC\xff\x9b\xca.\x93\xc3{\xd3N\xdeq\xebr#4\xa1'\x13\xdd\xa31\xd9\x82!\xbfS\x9a\xa1s\x94+\xe1\xd0\xcbI\xf7\x91\"~\x94W,\x7fdI(\xd5\xc2\x8a\x7f\xbe\x8a\x12&\xcc\xf8K'\x99_\xe8\x95\x89\xdf\xdc\xc0\xeb\xafr\xf8R\x8f\xcaw\xe1\x87v\x9e\x85\x1a\xfa\xaf\x00\xa9\xc9\xc3P\x90~Z\x18!\xe1KP\x0d#\x94\xf6W\xec\xdc\x9f_\xf7\x94K\x8f\xc8l\xa6m\x18\x99=I\xb1U\x0b\x97E\xdc\xf1\"\x9f\xd1\xfcU\x0f:nIs4\x10tw\x07-z\xcc\xd20\x9ck\x06\xed\x9d\x13m|d\xc1\xdf\xadMC5\xbc\xect\xd63\xfa\xba\x15\xd8=\x19\x0f\x05\x0e\xc8\x8d[\xb8\x07\xa9xH\xc8k\"kiR\x1b\xeb\xe6\xcc!PKNCd\x06\xf8L\xd1\x19\xa0\xa8\xa1\xad\xcd\xb1\xd4\xa8\xa3m3\x04;\xd26\xf8hR\xfc\x05\xfbUPC\xdd[gZ\x1b\xd2\x01\xe4\xb2~1\xc0\xe2\x7f\xb1t\xe7\xae\x81\xa8\x16\x04\x9d6&\xd2;\x8b\xeb\xed'\xe1\xe1\xf7\xd34\x9cI\x19\x1b\xc7\xa7\xaf\x85\xc4\x81\xf0\xa9\x12\x82\xe5`Z\x90<|e\xef\xbc\x88\x0f\x06\x1ak$\xce{\xee\x9e_\x8f(\xdaV\xa4x\x0e\xed+\x8f\xbcbD\x17\x11\xe1A\x1f7_\x90\xccpV\x13\x14\xd0\xad\xfd\xb8\x12\xb7\xe5\xe7\x9c\xa6\x17\xd3D;\x8d\x8df\x9cV\\\x98*\x92\xde\xda\x82sr\xf0,\xee}T\xdc{P\xa18\xc2(\xdc~\xfa\xe6\xd9\xf1\xb1\x16O&\x01?f\x10\x84)\x8b71C\xc7\x87\x04\xd9-\x15tNnmR \x1b\xd0\x82\x9f\x9d\xc0\xee~\xf3\"{\x82\x14hXa\xad\x82\xe6I\xbd\xadc\xc9\xaa<4\x8aQ\x16*\xc03\xf7\xe0(\xecG\xede\xfc\x9dk\x8c\xc2XL\n\xc3d\x86(~G\x0e$\xbd\xa0\xe2\xda\xc9\x901\xa5\x05\xc8\xa7\x80K b\xc9\xd4Wrs\xf3\x82\x1e\xec\xef\x8d\x1e\x8aX\xa9\xfaG\x03Y\x93\x97\x8b<\xfa^\x19\xf7Q\xb2\x04\n\xc5\xd9\xa8YK/\x82\x84\xb6\x100\xfd\x01\xfe\x96\xd131!\x92\xfa!H\x1eQ'\x91\xf1\xd8\x99|\xbc\xb9A\x9e\x9b\xbf\xcc\x03Y\x1eb\xda*\xf9\xab\xd8\x04Q\"XE<\xde\xdc\x90\xd5\x02\x7f\x8b\x01\xaa\xf8;\x19\xa9J\xbdQ\xe4\x1a~)\x7f\x14\xdb.01|j\xf9\x981\nx\xb0b\x8bcQG|\"\xe8wK\xe5\xb7\xf4V\x0d\x1d\xf7.\x07\x06Q\xae\xc9\"\x06j\xb4(\x8e\xd0\x7fJ\x89\x84^\xa6\x1b\x02a\xa1:\x9fH_\x14\x11-m\xa7\x81\x08\x0c\xc5^\"$\x0d\x1c\x158(\xac\x1e\xd3P\xbb\x80<\x08\xf5A\x90\x9bFX8\xb7&\x92\xf3\x89^\xe7 \x0f\xf8\xb8\x0d\xc3'\x1e\xfc\xe0Z<\x8c\xc3|n\xb5\x07\xf4k\x9b8Z\x13E\xc3!\x9d\xe3rW\xc8G\xcb\x96\x1c\xcc-B\xf9\x88\xf3\xfc$\x91aFZH\xac<\x04[\x0c\x07\x10\xf0\x7f(\x04\x1bs\xa3i<\xab\xc7-\xdf\x1b\x0f\x9c<\x99\xdf\x99\xf6/XJ\xaa&T\xc9\xaf\xaa\xe7\x95\xd7\x1a\x8a-\x95\xb5\xe4\xb2N\x07\x06\x9f\x82<\x81C\xe0\xe6\x8aC\xa5\xa1W\x184\x085\xec\xda\x83\xb3,\x85e\x94\xf1[.\x8a\xd9\xad\x128\xe4I\x0c\xbe\xeeU\x93\x1e|\xdf\xb3\xe6+h\xd2B\xb4\xd8S\x04\x99\xb8\xcf\xaeR\x16.\xdc\xea\xf2\xd1\xa1\x1eCV\x9c\x0f\xef\xac\xb4\x1d\x12\xf8\xee\xd8\xd8W\xdaOc\x02\x87Z\xcc,f\xf3\xfd]gS\x8d\x0f\xfc\xe9\xe9\nL\xc1D\x03\xb7\x10z\xb1r\x97r<&.\x12\x89e\xcf\xb2\xe5\x92Pw\x15e\x86E\x94\x19\x8b\x9f\xf3h\x95\xad\xc3B\xa0\xd3\x1c\xee\x02-\xa3\xc19K\xdf\x84\xc1f\xc3\xd2\xa6\x05\xae\x98\xabW\xcfbG\x1b\xae\xa7\x0b\x0dL\xbc7\x88\x00\xf0\xbb\x1a\xc5\xf0pOD\xc0\x91\xf1o\xf4\xd9\n\xeb\x00~\x9do\xd3yvN\x07\xa7\xf1i\xf8\xff\xfe\xaf\x9eU\xc0\xe9\x07\xe1\x82]\xbdZ\xba\xdah\x10\x8b?M\xdd\x80\xf4\x17\x96\x90U\x01lS\xf0\xc0\xc2\"oc\xbf\x0c\x1e\xc0\x88(\x0f3\xb3\x86\xe3\x86~\xbf\x0f8\xf8\xee!\xec\x99\xb9\x946\xeef\xb8Dz\x1e\xbd\xd2Jd\x9c\xec\xd3\xa6\x97\x93Ww^\x9a\xcc\xba,n&\xd0\xf8vieZ\xacJ\xa4\xafJ\xc6\xd7\xf7\x13VE@\x94/\xd7CL\x80\xa8\xba\x80\\\x11sSJ@1\x94\xe0\xbc|4\x00\xefR\xc0\xfcn\xb9\x16t\x0d{\xde\xd5\xee\x8b.8\xbf::\x82\xd2\xcf\x90L\x19\xd86\x1b\xb5\xe3\x18\xef\xf8\xfc\xe8s\x82\x15)\x88{A($\x8f\xea\x1dFK\xbe\x87\xaarN\xb1\xf8)q0\x0e\xc6\xa3W\x98\x00\xf9\xba.\x9f\x9b\xc0\x04\xf9{Q@*\x10\xd2M0\xb9\xa096p\x85\x88\x8az\x19\xd3\xaa1\xde\xad\x11M+L\xf3\x89Hs\xa0])z\xe3\xfc2\x8e]C4\x9c$\x8d+\xd9\xfd>\x04\xe1b\x9c\xabs\x0b\xef\x94\xf7\xd7lu\xdb\xc6\xcd#\xaf\xdb\x17\x91\xe7\xf1Mz\xbdbcp\xd4z9\x7f\xf5q?\x8b\xa2?\xf5\xb8\x1bL\xa7Z\x1f\xf7\xc2\xb1N\xe3\x8c\xe9\xc7\xf8m\xf9\xf7O\xef\x9e\xcbc\xcd\x0b\xf6\xf4\x8f\x97\xfe*)\xd4~Q)x\xfa\xf2\xcd\xf3\xbb\xa2\x85\xbas|\x9b\x81\x7fN\xfc\xe1LE&\x81o\xa2h\xc5\xfcpF}T\xf2\xd2I\nT\xa8\xe1k\xe7^\x8bmL8\xc1\x9a\x82\\\xd2\xad0\x91\x0b4\x06\xb1KmN\xb1 E\xb4\xea\x8b\x16{,\xf7\xbbM_&\x8c\xd1\xae/9\xaf\x17\x96y\xfd\x1d\x10\x88%3\xe2m\xb3\x9aV\xf2\xa6\xed\xe5\xe344\x94\xb5o\xe8\xa1\xd6\x90|*c\xba\xc0\x84\xe9\x820\xfd; :\x12\xd7\xe8\xb2k#\xe0\x04v\x87zS\xc3\xca\"\x17\xee\xe4FU\xe8\x1a_\xe7\xbfD3\xeed\\\xbc\xc7\xf3\x1e\xa8\xf2\xe9i\xdf\x9d\x8c\x83pys\xcc\xff;y\xe1\xddPQ\xe8\x877'\xfe\xc9\xcd\xc9\xd3\x13\xcf\xfbZ7\xb9\xc7\x80\xfc\x98\xadW\xeb\x9c=\xb0K \x8d\xbc\xf3r\x15\xf9_\x84{\xd6\x85\xdb\xa4\x15\xe1\x88\xd6\xedD\x82\x80\xf1t\xda'\x9d\xeaf{\xb3\xcfN\xd2\x18#\xc1\xc8\x11\xc2!H2BX\x1eW\xa8\x91~\x1a\xbd\x8c.\xe5\x89\xe6\xa4\x04L\xf8=>\x06\x11\xfcw:\xeb\x81\xd3\xdd\xceu\xe7\x0c\xe9\x95#q\xc1\xb8d\xf2\xa7h\x91\x1e\xf0\x9a\xcb\x9c\xf4\x10\xa6G0\x11wY\xff\xf5\xab7\xc7o\x8f\x7f~\xfe\xfe\xf8\xe4\xc5\xf1\xc9\xf1\xdb_`,_\x9d<\xff\xeei\xf9\x95\xd3\x0f\xfd0o\xee\xc4?\x811\xb0\"\x85!0\x9b\xcb\xeeFf\x04E2\xe3\x05\x07\x9cZBCX\xe7\xc5Dh\x04\xb7\xe8\x8aIB#\xe6\x9f\xdb \x8d\x10\xees\xb2y\x8c\x0f\xda\xa8\xd8\xdf\x89\xd4p\x89\xd6\xe8\x1c\x92\x1b\x86\x81\xd4hKk\x14\xf0\xa4\x0d\xe2C\xb3l(HN\xfc\x13\xde\x17$\x97A:\xbf\x00\xd7*;\x98\xfb \xd3\xe5\x90cc-\xd0\x16\x07\x81\xcf\xcc\x1dQcJ\x8a\xdb\xa6\xb1\x93\xa7'\xb5\x8d)1m\xab\xc6\xfc\x13\x83<6\xf7x\xb6\x1e7!\xf4\xfb\x12\xab\xc5O\xfeg[\xad\xe3\x93\x17\x9fo\xb5\x8e\xc3e\x9b\xd5\xaab\xa0/\xb7Z\xdb\x9fu\xb9\xb6?\xebzm7.\x98\xe9\xb4\xe7\x9f\x0f\xfa\x03\xc3X\xb4{\xa9H\xf6\xf6 S\xc9\xbc&\x10\xaak\xcaa\x0e\xbfP(\x02fX\x87L\xfe,]C\x99\xfc\n*\xe4\x97\xa2\x8e\xb4\xffy\xdb\xae\xed\xc7\xd7N#A\xd7\xd8\xe2\xa4\xf4\x8b\x93no\xd3\xd9\xcd\x14NO\xd3Y\xd7+\xbc\x1c\xeb\xbd\x17~\x10}H%\xf7=\"\x10\xb1\x85\xfb\xee\xbfn\\N\x8by\xe5n\n\xdf{\x13\xcf\x9b\x14(\xb9V\xea\xdc4X\xb3$\xf5\xd7V+\x96\xcfN\xac\xe5\xe1\xca\x83>\xbbbsA\xb3\xa9\xd2H\x96~\x01r\xcd\x10\x07\xc5\xa23\xd9\x08\xb7L\xf3\xb5\xa7\xf47H\x81\xa9yx\x8a(\xcb'\xa1\xe7'\xf74\xf3\xee\xe7q\x1c\xc5\xae\xf3\xad\x9f2\xe5K\xcbx\x99)(S \xf2\x89v\xd9t8#\xda\xa7\xcb\xa6\xa3\x19y+e\xf4sg\xd6\x83\x0e\x9b\xee\xcer\xf3Wv \xbc\x03\x97\xff\xaf\xff\xee\xed3W,\x83\xc9\xff.\x10\xe1)\xba\xbc \x8aN\xd1e\xd3\xbd\x19\xc5\xa5\xe8\xb2\xe9\xfe\xac\x07l\xfapfC\xc2(p\xc5\x80\xb7\xd3\x873A\x94\x0ez\xb0\xe3=\x81U\xeeK\xb9\xf3\xc4\x83\x15\x1a\xf6\x99\x90\x14\x88\xa8\xd1\xddU\x15\xfd\xd9\xc0\x8bM\x1f\xcfp\xe1\xf9\x9e\xed\xb3]\xb8\x0f\xee\xfe\x00\xee\xe3j\x0df\xd0\x85\xae\xcb\xa6\xc3\xe1\x8c\x83\xd9@\x8a\x00qC\xf4/\xb77\x9e\x88\xcb`]6\x0dzV\x1eFS\xdf\xda\x82e?a\xe9\xdb`\xcd\xdce\xff\\\x93?\n\x0d\xda\xa5\x0b\xce\xd3o\x9e}\xfb\xfc\xc5w\xdf\x1f\xff\xe3\x87\x97?\x9e\xbcz\xfd\xdf?\xbdy\xfb\xee\xe7\x7f\xfe\xcf/\xff\xf2\xcf\xe6\x0b\xb6<\xbf\x08~\xfb\xb0Z\x87\xd1\xe6\xf78I\xb3\x8f\x97W\xd7\xff\x1e\x0cG;\xbb{\xfb\x0f\x1f=\xee>8<\x0dOc\xe7\x96\xec; x\xbe\xc4\x86\xddY\xfbm\xc1\xd3A\xa3b\x9cc\xc7\xc8\xa2\x1e\n)\xf2_H\x1eCa\x9d\x8e\xa8\xe3\"b\xcfr3vi\xbcN1\x00a\x7f\xb7Qk\xc4\xe0\x00\x06\xad4?(\x13\xdf7\xbe\xb6\xe2\xc1\x18\xfe\x0b\x1e\xa1\xf0\xb9\x08\xf6\x9f|q\x06E\xe9\xc5\xf44>\x0d\x0fgB\x86a_\xf4\xa0v[|\x8c\xffc|\x95\xd8\xb7{n\xd1\x07)\xff\xee\xc1\x13\xe0\xab\x9c=\x01\xd6\xedz\xc0\xe0\xbf\xd0\n\x8c\xe4%\xa4\xce\x99\x8b\xfc\x10pt\x04\xc3}\xd8\x82\xd1\xde\x9e\xd7\x03\xbd\xf8Q\xb9t\xb4\xb7\x07[\x90p\xa4\x9f`\x12\x90\x83\x03\xd8\x87\x1b\xf0\x158\x04\x12\x1c\x98\xe9r\x15[4\x00\x19\x087\xc3\x81\xdd\x87}T\xd1|\xd2\x90`\x0c\xc3GJ\xd0Slk`lk$J\xf1S\xe1q\xc8\x97F\xaf\xb3\xab\xbe\x8c1\xe9\xc62\x8e\xd6\xea\xc1\x9d#O\x80\xe8\x1e\x1f\xe7u w[\xa9\x08\x06\xf6\xe0,\x0e!\xd0\xf6Z\x93\xb6\x00\x1d\x93s\x8b\x15\xa1X\x80/k\xc45~\x0d\xae\xb1@\xe7N :\xf1\xe4\xfb\xd3\x00\xb7\x8fo\xfa\xfe\x0eR|Z\xe9\xc8T\xba_*\xdc\xdf\x81-@s\x1c>#7\xe0\x10\xfb\xc8\x83.\xa4SfW\xa8\x16\x01t\x87\xf4\x87\x9fyD0\x86Q\x0e\xae\x85v\x06\xa6vv+\x85\x07\x07P\xeeq\x7f\x17\x1b\x1e\xe6\xc0\\h\xb9:\xc0\x83\x83J\xc3\xfb\xbb\xc5\xf6z\x10\x17\x01O\xfd\xfad\x02\xc2\xca\xceVd\x7f\xc58\x93U\x02\xc1*,\xbc%\x89\x16\xd5x2X\x9c9>\xf1\xca\xb7\x19\xf2\x97\x985\x12\x83[o\x03C\x80\xca\xfc\xb8\x91>z\xae\\\x83\xf9\xe1\x0b\x9f\x90 \xd8\xea6\x16\x88|\xa1\xf3)\x9b\xe5I\xc0\x94\xa8\x96\x16|\xe6\x08f\x15E\xb2q\xb3=\x87\x08\x84\x13\x84\x10\xd7\x1b\xf0\x04\xa2Id\xd3j\x08\nY\xdfo\xecZ\xfe\xdd\xc9P\x07i\x9f\xe6>x5a\x81\x90\xa8;1k^\x16\x11\xce\xa2U\xd2\x0e\x058\xc5SyG\xfa\xa6*\x9c\xf8\x93<\x8cZ\x1c\xfa;\x9e\xe1\x8d\x1f\xc4\xc9\xdf\xeb\x10\x0b\x7f\xdd\x9a\x83\x9a\x89\x19=\x8dc\xff\xda\xf5\xa5\xdb\xa3R\xf4\xf0\x13\xec\xdf\xed\x04\xfbx\x82\xcd'7h}r\x03\xf4\xe1G\x93!\x0d\xe1~`\xd7 \xff\xba\xec\xd6ok%\x9b\xb2\x19Ge\xd1t\xc0o\x19\xfcw6\xfb\xd3\xa1\xde\xb2\x8f&\x9a\xfac9\xd4\x99\xf0\x06\xb6\xeccT\xd8\xc7\xcc\xb8\x8f\x99m\x1f\xf9ne\xb8[Ae\x89{\x10\x89\xb5\x0b\xc4\xda\x05\xb8vV\"&\xfa\xeb\x0fp\xf1\xd6\xbe\xe51N\x98Uun\xf6)\xfcrg\xb8\xf6\x82\x0dB\xb0\xc4\xfe\xd2\xee\xb1\xb0'L\x10\x15\xa2\x0d\xa7lV{\\>/\xc4\xdb\xf0\xfc\xdf\xcd\x8f\xf2\xb7\xe4A\x16.\xd82\x08\xd9\xe2\x13%/5\xcbp\xfbE\xf5*\x19\xe6o\xcb\xcf}\x8c\x82\x85\x8c(V\xd7\xbb\x89\x93\xab\x13\xfa\xfd\xcd\xbc\xa1\x7fK\x1e\xc4\xec\x9c]}\x11U\xca-\xe4f\x01F\xa6\xc1zm.'\xe5Mg\xa6\xb19\nxp\xfa\xc0\x9d\x9e\x07\xeb\xd9}\xef\xeb\x07R\xb3a\xae\x1e\x1bb\x0c\x80\x18\x94\xf3@\x8a\xdd\x07V%\x02i:\xa4\x05o8\x1d\"\x1b&\xd5\x07G\x9c%mq]\xf3\x9e\xd0\x9aw\xcar\x03\xa0\xb8`\x0b\x947Si\xe5K\xdf\xc1\x7f\xce\x8a\xcbS\xa2-:\xa9\xdf\xca\xab[0\"\xea\x81e\xc5P\x93\x95kFY\xaf\xcc\xc7|\"\x92PT\x1au\xd0\xd6\x14\xe6\xb6\xf8\xa4vC\xf8Zu!\xed'Q\x16\xcf\x19ty\x81ua\xd3\xfe\xf9*:\xf3WB\xe7\xd7=\x04\xe7\x9cB\xf5\xe5\xa9\xe7\xf3Wkz\x15\x9c\x87Q\xcc\x9e\xf9\x89\xfe.\xe0\xef\xd8\x97BfO\xb4J\xea~\xd1\xa21]\x06\xe1\"\xbaT@A?\xfb,\xd9\xc4\xc1\xda/\x19\x06\x06\x8d\x98\xd1\xa8N\xf8-y \x07\xff\x17\xe3\xc6\xaa\xbaF\xfe)\x18p\x11\x06\xf8\xe6{\x16\x11!\xc8\xf48}4\x0e\xe3g\xa1\x9eM\x8f\xfd\xf0\x9c\x8dkyo[TQq8^\xc7\xd1y\xec\xaf\xe9P\x84\x18\xfb\x8e\xef\x98\x0c-v\x16-\xae\xb58<\xce\xf3+\x0e\xf9I\x10\x85oR?ek\x16\xa6\x8eVu:\x98\xa9&\\\xe7i\x1cG\x97/\xc4\n\xe7_\x96?`\xea\x0d}\x8bN\xcf\xb7\xfd\xca\xc0\xe6\xebZ\xb1\xba5hD\xd4\x9f\x84\x8eEt\x9c\xe6\xcd\x0f\xb4\x8d\x0f\xeb6\xbe~\xd3\xff\xb0`s\x9b\xc3\x0b\xdej\n\n\x88\x81\x95\xdb0\x14\xbfu(\xe0\xbbc\x84\x82\xbc\xaa\x82\x02^\xd7\n\x04\xc5\xfae \xe0\xc0v\xeb\xaf\x0cf\x10/\xfc`\xc5\x16\x90F\xca\x16B!\x0c\xbb6\xc5\xd8\xc1\xc6\x8f\xfdur\x0b\xab\xd0H\x06T\x0d\xfd\xb5 >\xc5\x0di\xec\x0cW\x1c7\xba\x07\xce7\xabh\xfe\xa1t\xde\xec_\xe1\xf2Mp\x0d\xe4\x02\xbaQ\x0fB\x199x\x8a\x96\x0b\xfc>\x9e\x0egt\x01\x0b\x95\x8b^\xdd\x91\x08\x02#F\xe5\x9f\xd2g\xf5&4w\xbe\xa1\xe5\x00\xfe\xd4;Z\xdd\xba\xcat\xed\xcb\xda8X<\x00\xf6F&\x8b1\xf7\xd1N\xa98\xa3\xda\xe5b\xbfN\xdaW\xac\x9a4\xcb\x15J\x08\x0f\x0e\xe1q\xb1h \x870,i\xb3Vp\x08;\xa3\x12(\xf0\xb2\x9db\xd9\x05/\xdb-\x96-x\xd9^\xb1\xec#/{X,\xbb\xe6e\x8f\x8ae\xe7\xbc\xac4\xbe5\x1c\xc2ni,\xefyY\xa9\xdf3^V\xea\xf7\x12\x0ea\xaf\xd4\xc7\x15\x1c\xc2~\xa9\xbd7\xbc\xac4\xb7\xe7\xbc\xac\xd4\xc7S\xbe|%7\xc4W\xbc\xac\xf4\xedo\xbcl\xbfX\xf6\x01\x93\x15\x96*\x1eca\xa9\x97\x1f\xb1\xb04\x95\xb7ph\x80\xf8\xc1\x18\x9c\xd3\xd3\x81\xe1\x1ez\x88o|\xc3\x9bG\xf8\xe6\xcc\xf0\xe61\xbeI\x0do\x86\xd4Qhz5\xc4W\x1fM\xafF\xf8jiz\xb5\x83\xaf\xca\xd4\x1c\xff\x1b\xd1\xd0\xcbBh\xfe\xb7\xb3;\x86{\xa7\xa7\xce=\xc3\xd8\xa9\xaf\xd3Scg\xd4\xdb\x89\xe9\xdd>M\xed\xbdi\xa5F;\xd4\xeaK\xf3Kj\xf5uI\xc6P\xac\xfa\x8c_\xd6\xce\xb5\xd3\x03\xe7\x17\xfe\xbfk\x96\xe0\xb3\xf8\xe7\xf9\x1b\xfe\x0f\xd2\xbc\xce+\xfa\xff \xff?>\xd2S\x84\x8f\xf4\xffWX{\xb9\xc4\x8a\xe2\x9f\x17/\x9c\x99)\x90\xc6\xeb*\x92\xcc\xc5\xb5%\x0d4Y\x9e\x1c\xd6z\x93\xf5(X\xc6ho\xcf#B\xe8\xca\xa1h\xbd\xa3b[\xca\x02\x19\xab\xef\xef\xed\xed\xc8\x0f2\xf1\xc1\xae\xe1\x033\xc9\xde\xa1FvG\x8fw\x1f\xef?\x1c=\xde\xf3\xbcb\xf8\xdby\xb4`\xb0\x89\x82Bz\\\x8av\xb8\xf6\xafe\xda\x85\xf3\x98\xf9)\x8b)\xf3\xc2\xe0\xea\x85\xf83\xd1\x0d8\xd0wb\xa0\x8f\x8a;[\xf8%o\xbc\xd3SG\xc4p\xcc\x836\x0e\xf0\xfbm\xc5'{\xd0\xd5\x987S\xb0\x92\x9f\xaa\x9b\xa5\x85\xac\xc6\x9d\xc9crG2\"\xb6\x0c0\xfd\xa3\x9f^\xf4\xd7\xfe\x95\x8b\xf9\xc1E\xf1\xcd\x0d\x8c<\x19\xda\xfbC\xb09\x0e?\xfa\xab`Ami\xbf\xf58\xdc\xcbUt\xf9\x92}d+\xa4`\x83\xe4$\xe2kz\xee\xa6\xf9\x1bO\xfa\x1fie\xb2\x97\xf4z%\xe2m\x17\xaeU\x1bE]\xcd\xffkH\xdfU\xe0\xdcrw\xfe\xff\xfca\x919\x87\"\xfb \x19iP\xc6\xd5\xb8\xa40`J'C\xce\xff\xd1\x13\x8a\x88:\xa4\x8c\xe4\xf14\x10Z]q\x16\xd84C\x0f\xeeN\x87\xc8\x99,7]\x1d\x91A/\xff\xcc\xc0\xd5r\xd0\xc8\x94\xff\xb6\xd7\x03\x97\x12\xb8\x95B\x90\xf7eV!\xde\x0foOdt\x98\xf7u7\xcb\x1e\xf8\xd4\x99\x8f\nk\xfd\xd5\xd4\xe7\xe3\x0b\xa7\xd9\x0c\x0e\xcb\x91oA\x13p\x17\xe1\xd9\xd5@\x8c\x03\x0e\xb6\x98H\xf3H\x05;Q\x9c\xfe\xc0\xae)\xd5\x8c\xfaQ\x8c\xde\x1e\xb2\x7f\x06\x0b\x19=]\xfd\xba\xb9\x81G2\xf6y\x18\xfd\xc4\x96\xd4\x86x\xd4[\x08\xa3g\xd1z\xe3\xa7?\xf2\xe3Lu\xb4\x02\xbd\xe6<\xe2\xd0\x8d\xeeV\x97b)\xb5\x02\xbd\xe6\x1d\xe2\xc5\xcb\\Du\x9f<\xbf*\x86\x98\xc7\x9cWa\x1e\xa6\xbe\x98I\x9a\x97,2\xfe\x85\x9f2a\xa7@\xa5Y\xc2\x16\xdf\xeao\n\xc1\xfdL8\xe2\xc4x\x98\x10\xe8\xc5i\n\xe0\xb0\x14:\x96y\"w1)\xe6\xb6\x87\x04\xd7|l\x89f\xaa\xf4\x04\"8\x80\xe4\x89\x879\x1a\xd0j]\xa6\xe6\x17n|\x98\xf8?\xf2\xd0\xda\x87\xfcCD\n\x0b\xd1A\x82\xa9\xdd\nox\x97\x14\xc65Bc!z\x0eu!\xc4\xa9\xe0\x03C\x01\xd7\xddC\x08<>\xc4\xeea\xd9\x9dL\x80\xb0_\xbbD/\xebbo\x9bc\xebJty\x1f4\xce\xce\xd4\xf6\xb7U\x14-\x19\x0e\\\xb1\x15\x87>z\x9c\xd76\xf4okC;\xa3b`\xaa\xe1h\x1f\x99\xf7\xfda9\xf2\xd5\xe8\xf1\x1e\xff\xc5)\x94\xdcm\x82\x93$\xe2\xd7\xcd\x0d\xec=\xdc\xd9\xdd-~\xc7/\xe3\x1d\xfe\x8b\x92Q\xa8\xaa\xbc|\xbf\xd4\xf5p\xb8;\x1c\x0ek'\xf2\xc2:\x11\x9cb\xa9\x1fl\x99?\xbe\xcf\x1f\x9f\xe6\x8f\xaf\xf2\xc7\x0f\xf9\xe3\x8f\xf9\xe3e\xfe\xb8\xa8\x1d\xd6;\xeb\xb0\x1e\xfcz\x1a\xde\x07\x19\xc8D\xdfn\xf9\xc4\x0f\xd27\xd5X#\xbfs2\xa7X\xf4\x0b\xe7U\x8aE\xff\xe4\xb4M\xb1\xe8g\xc0\x88\xd2\xd5A\xfeP\x1fg\x9d\x8f#\xd2\xed\x9b:\x86\xe8'sK\xf9\nO:\x85\xfa\xa8\xbe}Kx\xa0R\xce)\xd5\x7f\x8b\xec\xa3\x85\x04%\xa5\x9d\xc4x<\x9do]\xba\x8c|,;\xcb\x1f\xdf\xe4\x8f\x97\xf9\xe3\xfb\xfc\xf1i\xfe\xf8*\x7f\xfc\x90?\xfe\x98?.\xf2\xc7\xeb\xfcq\x9d?n\xf2\xc7\xe3\xfc\xf1*\x7f<\xcf\x1f/\xf2\xc7\x8f\xf9\xe3\xf3\xfc\xf1713{V\x17C\x82\x07\x839\x8a\x97\xbf\xed\x10\x0bb\xf2\x06\x0e[\xff\x13a\x05c\xdd\xef\xd7\x9a\xcdS\xff\xe3m'@\x91\xdd\x9a'\x02\xe2\xe6\x8a\xa7\xa3\x861\x83\xca\xffB\xb3\x9c\xa3\xfa'\xe2'=\x81.\xe7\xf50\x9b=_\x07Q\x01&\xfcqL\xc9\xeb\xa0\x0b\xffp\xe7\xc4L\xa2\xd2\xa2\xb63{\x98K\xc8A1\xb2V\xfa\x83\x83g\xe65A\xfb\xcf\x8d\xd0~\x0f3\x934+\xf7\xe4\x9fb\xa4s\xaa\\p\xcaV\x1aI\xc8LK\x84\xd0\x111h\xfb\x80\x0e;\x9c]\xdb\xdf\x19\"\x11P\x8dO\x1a!WL\xdf\xec\xef\x8c\x06\x90\x07+\xdd\xd9\xdd\xe1\xcc6\n\xa6^\xbb\xc3\xc1\x08\xbd\x96\x19lS\xeb\x949f[|\xd6%\x1e\x8e/\x1b\xa7\xdd\xc6$\xf3z+\xcce\xbb\x87\xd0AJ\xe6\xdf\xfc\xe2\x99@:\x8df0\xa6[\xee\xb5\xd9\x1bM\xff\x93\xba\xd4\xba=\xf3(}\xa8\xb9!\x11\xfc\xc1\xbee\x05\x99n\xb0\xdeDI\x12\x9c\xad\x84\xb7\xfb\x18\x02!\xaa$\x0b\x10\x8a=\xe64\x11v\x7f\xb8\xf5\xfc\xfc\xd7\xf64Rp(\xe95)\x00\xc4\x90k\x06-@\\D&\x85XRF\xf9E\xc8\xcf\x1b%\xd46\x7f7\"|\xa4\xde\xf1Q8]\x07\xb7K\x1e\xcam\xbalNC\xa7v\x86\xdf[\x19a\xdb\x909l\xe4(u{\x88\xb9/\xa9\xf4\x85a,\x8a\xf8\x99\xb2\xf1/E6\xfe{G\x98\xa2_\xd0\xfe1\xf8\xf39\xdb\xa4 \xaa\xde\xf0\x06^QN0\\\x81{M7MqZ\xd3\xd5\x8cff\xbfy\xecW\x8ad\x87cc\x95\xda\x90\xd3\x06\x83,#\x9b\xdf\xa9\x97\x8f\xfeOA\xc6G\x87\xbe\xcc\xb3\x17\xf4\x07r\xc8a\x8f\x8er\xd8\x83\xce\x10C\xdf\xa8\x9f\x03Cj\xe0\x04\x14\x94P\x13\xe5$\xad\n\xf9\xe9,\xed\x01E\x85+r\xb9\xe5\x14\xa6\xbc\xf9y\x0fV=\xb4\xff\xa8\xbaIq\x00Ea\x87z\x85\xbe=\xf2MU\\\x86\x02;W\x93P\n\x8dX\xae$Q\xbbM\"@-al~\x13\x18\xda\xd1\x8a\x1aZ\xd4?.\xa0:\xa5\xee\\g Z\x12\xf8pF\xa9n([y\x9d\x05\"\x14D\xacDB,\n\xfa\xb6\xec \xf1`C\x0fE\xf6\x9c\xd5\x10\x1b\xceW&\xe2@\xedb\x1c$\xa1\xd6\x12\x91%\xc2)'p\x16\xd3h6\xeb \x1cCf\x80>\xe5`\xa7\xff\x08\xee\xf1t\xb58A\x02\xf8\xf1l\xf0\xa7\xdc\x9b\x823\x1e2\xeb\xbb\xac\xb3\x14[\x875\x8b\xc9\xcc'\"r\xd3\x84\x13\xaa\xe2\x11\x1c\xe5\xf1MS-\x1d{?\xf1\x97\xec\xdb\x92\xb5B\x8d\xe5\x1eM1\xee\xb3\xab\x94\x85\x0b\xb7z\x8e\xc8Fs\x0cYq\xb7\xf0\xc6/\x8d\xeeN>?\x02\x90\xc85V\xba\xd6\xf0\x83\xed\xbc\x7f\xcf\x92\x1f\xa3E\xb6\xaa\xc6.\xfd\xe8\xaf\xb2\xa2w\x1f:\x8a\xf5\xcfY\xfa,\n\x97\xc1\xf97\xd7\xefb\x0c\x86\xdb_D\x97\xe1*\xf2\x17T\x0e\x87\"\x1eB>\x80\xdc\xe9h4\x18j;h\xf8\xd4\xae\xf1*\xdb\x16\x18\x15\xbd\xa2\x92;\xe0C]\x86\xfd%K\xe7\x17^\xc5E+\x9f\x93qJmvU\xd51\x92-\xca\x97\xb8\x9fl\xd8\xfc)\xd6L\xccH2\xf7\xe7\x0dJ\xcb\xe1\xa6^?\xbd`\xe8\x07\x17\xe9\xe9F\xe5\x9f:E\x91y\x14\x80\x9aSM\xbe\x8c\xce\x88\xa8.\xed'\xa9\x9ff \x1c\x1d\xc2\xee\x00\xd3[\x04\xfdl\xb3\xf0S\xf62\xf2\x17Ax\xfe\x06\xdf\xbb\xce\x12\x1d\x17i@\x9c\xb3\xb8e\xb5w\xf1\xcaux\xc1<\n\x93h\xc5\xfa\xa8\x14se\xffo\xd9U\xaa\x91'Y\xbc\xe2@\x86\x17\x07R\x89\xcc\xe5[)\xdcQ\x7f\xf1\xd7+\xea\xc1s\xc3~\xca\xae\xca!\xb4\xa1\xaaF\xfb[\x9d\x1f\x1d\xf2\xcfY\xda\x12\xd2R^\xf78t\xcbw\x15L\x80\xc1\x18\xa6l\xf6\xf7\xc2\x12\xa5s\xaf\x08w~\xfa\xf7\x0c^\x84H\x91\xcb\x1b<\xef\x0b&\x10\x83)9\x93\xd4\xc7\x96\x83\x17\x16[F5\x9a;\xdc\x7fT\xea1\x11#\xd9-\xe2!j\x93\x02I\x92\x0b\x06\x07\xbcL\xbe\xf0\xdc\xa0\x07I\xff\xdd\xebo\x9f\xbe}\xfe\xfe\xd9\xab\x93\x17\xc7\xdf\xbd\xe9\xb5\xdc>\x0c\x0e\x8d\x80\xeccp\xd1\x7f\xbc\xf1\\\xd6\xdf\xf8\xd7\xfc\xa8\xeb(\xde3\xf7\xfa\xf6\xd5w\xdf\xbdl\xdb\xab\xbc9U\x07f\xb5/\x02UEt\xa2\x86\x9c\xf0\x97=\xe8\xc4\xc5\xd1\x05\xc2\xf3t\xe6}\xc5\xf7\xf9\xc1\x83\xff\x03\x14J\xe2G\n\xdb\xf4\xee\xa7\x97\x87\xc9\xa5\x7f~\xce\xe2\xed,\xd8\xe6xg\xe1\xaf\xa2\x90m\xa3N$\xed\xff\x96\xf4\xd7\xfe\xe6\xff\x07\x00\x00\xff\xffPK\x07\x08v\xf2\x8aA\x86\xba\x01\x00\xc5\x87\x08\x00PK\x03\x04\x14\x00\x08\x00\x08\x00\x00\x00!(\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0e\x00 \x00swagger-ui.cssUT\x05\x00\x01\x80Cm8\xec\xfd{s\xdb8\xb27\x8e\xff\xff\xbc\n=\xbb\x95\x9a\x99\x1dS!EQ\x17\xabf\xeb\xc8\xb1\x93q6r\xc6\xcem\x92\xad\xad)\x8a\x84$\xda\xe0\xe5\x90\xd4\xcdz\xf6\xbd\xff\x8aw\\\x1a $;s\xf6\xf7\xad\xb3\xd9dl\xe2\xd3\x8dFw\x03h4\x00\xb2\x9bl\xed\xe5\x12\xc5\xda\xda;\xfc\x9fN\xe7\xe5\xdf\xfeo'\x08c\xdf\xc6\xde#\xea:I\xd2\xd9\x0c\xbbzW\xef\xfc\xbf\xce\xec\xfac\xe7\x9d\xe7\xa0 A\x9d\xff\xd7Yz\xe9j=\xef:\xa1\xff2@N\x88\xed\xe4%M\xf7\xb7\x97\x8b0H\xb5\x85\xed{x\x7f\x9e\xd8A\xa2%(\xf6\x16\x13'\xc4a|\xfeWs\xde7,\xe3\xdfD\xfd\x9dU\xea\xe3\x03\xf6\x02\xa4\xad\x90\xb7\\\xa5\xe7F\xd7\xb0&\x9a\x9fh)\xda\xa5Z\xe2=\"\xcdv\xef\xd7Izn\xe8\xfa\x8b\x89\xb6E\xf3\x07/\x85K)\xce\xf3\xd0\xdd\x1f|;^z\xc1\xb9N\x95\xd8q\xea9\x18\x9dQ\xcf\x12\xcf\xa5\x9f,\xc20E1\xf5h\x85l\x97y\x14\xd8\x1b\xea\xf7\x049\xa9\x17\x06\x07\xd7K\"l\xef\xcf\xe78t\x1e\xe8\x16\x1b\x87\\K\x99\xf0\xe7=\xe4OJ\x19\xbb\x83!\xf2;\xb4\xa4\x0bo\xe9\xd8Q\xc6\xf0\x8cy\xbc\x8eii}\xdb\x93UZPT\xea0\x90\xdf\xe9\xeb\xd1\x8e\x96+>T\xca\x9d\x87\xbbL\xe4\xdd2\x1f:\x16a\xec\xf3\xca\xfbg\xba\x8f\xd0/1JP\xfa\xaf3\xbe Y\xcf}\x8f)\x01*\xcbf\xb5\x92\xa2(\xfdW=\xb6\xdaQ\x84\xec\xd8\x0e\x1ct^\x14\x01\xd5\x974\xe7\xe7\x9a\x1f>j\x8b\xd0Y'\x9a\x17\x04\xcc\xd4C\x8a\xaa\x04-\x85o\xc1\x16\x95\xf3 \xde\xeb&\x91\xed\xba\xd9l\xa0K\xda\xd0\xb0\x89\xbd`)n@+\xae\x92^\x02,E\xa7\x11\x87p\x9df\xbevnD\xbbr\xec\xed\\\xe4\xc0\x8fh\x972\xb3$\xc2n\x82\xd2C\xd5\xb0\xaei!\xbf\xd3\x1d\xe6\xff\x0e\xb8a\x01\xa3%\n\\h\xda\xac\xe7\x14j\xd6$\x9e\x16\x83a5\xacW\xdd>\xb5\xe7\x18M|{\xa7m=7]\x15\x1d\xa5\xd6\xf2d\xbb\xf2R\xa4\xe5\x83\xf4y\x11y1Sl\xb8\x8cQ\x92\x80\x83\x8f\xd2(Xw\xe1\xbaw\xd9\xeb4\x04\xac\xeb\xac\x90\xf30\x0fwP\x1f\x89m\xd7\x0b\xffu\x92Vd\x0e\x15\xac\xfd9\x8a3\xef-\x19\xe7^\xa9%\x91\x17h@\x17\x14\x10\x85\xeb\x94&:\x94C\x90\xa0\xa1 \xb2cg\x05v\xdfLY\xb9\xc7LJ\x0f\xd3\xc2\xc5\"A\xe9\xb9\xd6cB+\x8aU#K\xf1@s2nX\xdc\x06\x11]\x13\\@\xd2q#[C\xbf\xf00\xd2\xd6\x11\x0em\xb7R\x82pt\xcaG\xed\xcaO\xe9X\x00\xa5\xb6\x87\x13:\nE\xc1Z\x12\x85&k\xdf\xb7\xe3}\x8d\xc0^\x92j^\xca\xf4*\xc7\x0e66\xec\xc4\xb4V\x8b \xed_\xcc$\xe4G\xd8N\x115\x93Rd]\x17\xcd\xd7\xcb\xce\xdf\xa8q! \xb1\xe7v\x96!v\x01\xac\x96\xf7;\x90\xe2\xaf\x8b\xc5\x02\xa2\x98c\xdby\x80)\xd8\xf8\xa7\xa4X\xc6\x9eK\x04Ndx\xdbY\xc7\xf8G\xd7N\xeds\xcf\xb7\x97\xe8e\x14,'Y\xf7\x1d\xf4\xcf\xbc\xcf\x17\xef\xef\xb6\xfa?\xde,\xc3\xe9t:\xbd\xf9\xf0iu\xf5i\x99\xfd\x98\xffs\xfdj\xfau:\x9d^^]\x0e\x07\xef\xb2\x07o~\xbf{\xfd\xe5\xd7\xbb\x8f\xf3\xde7\xdd\xed\xbd\xde\x7f\xbb\xbd\xb8\xf8\xf6f\xec}\xfbp\xf1v\xfe\xe5u\xf0\xed\xf3[\xfc\xf5\xcb\x9d\xe58\x18\xff\x96\x11\xecW\xd1\xe7\xd7+\xfd\xcb\x951{\xef\xdfl\xe6\x1f\xacU\x81\xb7\xfa\xf3\xdf\xa7\xc5\xff.\xb7/\xd1\xaf\x17\xab\xaf\xbd\x14\xbb\xaf.\xbco_\xdch~\xaf{\xc3\xe1\xfa\xe5\xb5w\x11}\xbb\xd4\xbd\xcf\x8f\x9fofW\xc6\xf6\xb6\xf79\xb4?\xad\x06\x8e\xff\xf9#z\xb0>}5\xa3\xf8\xeb#~\xb8\xbe\x1f\xfd|}\xb9\xeb\xbf\x0fV\xa9\xf3\xc6\xc0\xee\x9b\xab%zc$\xf3`6@\x97\xba\xf7\xf5\xcb\xdd\xe6\xab\xffi\x90\xfd>\xff\xf2Y\xff\xfaa\xe4]\xff\xba\x1c\xa07\xc6\xd6}\x93\x8c\xaf\x1f^?\xcc{o\xf1\xf5\xeb\xd5\xcd\xa7W\x17\x97s\xf3-\xbe\xbe\xfc\xb4\xbe\xf1\x8c\xfb\xd9\xc7\xab\xdd\xf5\xa5c\xbd\xbb\xbf2\xde_\xce\xf67\x1f\xb6\xcb\xd9\xfdtw\xf3a\xb4}\xffa\xb4\x9b\xbd\xd2\xb7\xb3\x8f\xe1nv\x19\xeeg\xaf\xa6\xcb\xeb\xea\xef}\x7f\xf9\xdb\xafo\x1f\xbe\xddG\x1f\xee\xae\xbe\xd6\xf28\xfe\x9d\xff\xdb\x87\xb7\xa1\xfb\xeb\xdd\xf6\xbd7\xda\xb8\xa6k\xbe\x0b\x9c\xc7w\xfex\xffm?\xda\xbd\xff\xf8`\xbd{\x9c\xee\xdf=^\xef\xdf\xfd\xfe\xf6\xe1\x9bg<\xa2/\x96\xfe\xf5\xf7e:\x0ff\xf7\x04\xdf\xabo\xbf\xdf\xdc;>\xde\xbao\xf0f\xee]\xec\xbf\xbd\xf9:\xf8\xfa\xe5\xed\xc6\xfd\xfdv|\xed]7:xcl?~\xd2\xc7\xd7\xfeJw\x7f\x9d\x0e\xde\xed\xc7kg_\xdb\xe2~\xde\xd37\xe8\xcd\xeb\xed\xbb\xc7\xab\xf5\xec\xd58\x9d\xe7\xfaY\xa5\xf37\xd6\xe3\xfb\xe0F\xff\xe4\x7f\xa6d\x9e\x07\xb3u\xa9\xd3\xf5\xd7\xde8}g\xaeV\xce\xab\xd1\xee\xdd\xfdt\xe3\x18w\x96\xf3\xe6\xd3\xe6\x93\xff\xf9qn~\xde\x7f\xed}\xfe\xf0\xed\xcb\xd7\xfbk\xef\xa2?\xff\xb2[;\x8fQf{EY\n9\x9c+\xe3\xe6\xfd\xc3\xdd\xe6\xab\xf99\xfd\xf6\xc5\xd2?|\xba\x1d_g\xb6~e=\xd8_n\x07\xb3\x8fw\x97\xef?~\xed\xdf\xe8\x9fz7\xfa\xe7\xd7\xb3\x8f\xaf_\xdf\xdc/{\xb3\xc7o\x97\xb7\xf7\x0f\xdb\x9b\x87\xdb\xfe\xec~\xb9\x9d]]\x13\xfc\xf0\xda1\xefVs\xff\x06\x13\xfc\"\x9a\xdf\xad\x1a\xbf\xcb\xe8\xd2\xf1?\xaf\xdc7\xe3\xfd\xe77\xe3\xcd\xfcR\xf7n\x0b\xfd,?\xbdYm\xdc7\xe3G\xfb\xcdx{}usy}y\xbd\x9d}\xfc\xb4\xfc\xc7\x95\xb1\xfa\xda\xc3\xeb\xbc\xec\xd5\x83\xf7\x9b7\x1d\x95v\x1a\xdc\xbd\xf9\xbc\xb7\x7f\xff\x86\xbf]}\xdb\xcf{\xfa\xd21\xef2\x1d\x0e\xec/\xd6\xa3\xfb\xe6\xf5\xfak\xef\xf3\xdb\xbbK\xdd\xcb\xf0\xef|\x1c}\xbb\x0c\xcd\x9b{g\x7f\xfbpk\xde\xdc\x7f5o\x1f?\xedf\x9f>\xf5n\xef\xdf\xbe\xba\xd5?\xedo.\xa7\xfd\xd9\xc7\xe9vv\x7fe\xce>\\\xd7\xfc\xbe\xbd\x19\xdf\xbb_\x0c<\x0f\xee\x08~w4\xbf\xc7V~\x9bL\xf6w&\xe0\x93\x99\xaf\xbe\x1a\xe7~\xf9\xe9\xe1\xeeM\x81+\xfa]\xde\x0f?\xf6\x97\xbf]\x8e\xfb\xce\x9b\xd7\xf7v\xef\xb3~\xfd\xe6\xf3:\xeb\xef\x8ew\xfd\xf2\xb7\xe4\xe2\xc3\xcfof\xd9\x08q\xff\xe1\xd3\xdd\xc5\xe7_\xef\xed\xaf\x9b\xc7\x97/\x1fG\x97\xef\x92\xcb\xfe\xd2y\xf3\xbb\xf7\xf5j\xfa\xe6\xe2\xfa\x1fo.\x02\xf4\xf2\xe5\xe2u\xb4\x9d.\xb7\xd3\x8b\xf1hj\xbf\xeeE\xf7\xf8\xd3mF~\xf1\xf6\xee\x93u\x15?\xbc].\x97\xbf\xfc\xf2S'F\x11\xb2\xd3\x8e\xde\x11\x8e\xa4\x9a1x\xc6\xc1\xf4\"\x1f\xe6n\x8b\xc1t\xba\x18\xbd\x1c\xaf\xfew0\xfd\xdf\xc1\xf4?u0}\x7f\xf9u\x7fw\xbf\xba\xba\xbb\xcc\x06\xd3\xaf\xfb\xd6\xc1\xafe0m\xf8\xdd\xaa\xf1\xfb\x0f\x1aLo?\xb6\x0e~G\x0d\xa6\xb7\xed\x83\xf3\xf7\x19L7\xaf>\xe8\xc6u6\x18\xcd\xea\xc1\xd4\xbf\xeb\xbf\xb4~\xbex\xfd\xdb\xc5b:{\xed\xbf\x9c],w\xa3\xbb\xe9\x9b/\xaf\x02c:\xf5?,\xcd\xfe\xed\xe0\xe1\xe2\xf2\x1f\xb37\xb3\xcbW\xdb\xebWhv\x8d\xfc\xd7/\xad[{{\xe5E\xd3/\xdbO\xab\xed\xd5\xfd\xecr3\x9f~\xc1_\x1e6\x9f/\xb6\xeb\xd1\xe6\xf6zz1\xbd\xda^\xbc\x8aV\xa3O\x03G\xcf\xc7\xa5+\xfc\xfa\xe3\xc3\x87\xf5\xad\xff\xea\x95\xd2\x00<\xd2\xf2x\x97\x1c\x85\xb3`\x99\x1d~\xef#T\x8f\xbf/\xc7\xf7/\xfb\xb7\xd3\xafw\xbf\xaf\xa2o\xcb\xe9\xf4\xc3\xa7\x87\xff.\x03\xd9\xe6\x7f\xbf\xbdL\xa6\x17\xaf\xaf\xdc/71\xba\xcdF\xe6\xdbj\xe0|\xd9\xbf\x9d\xed\xec_\xeft\xe72\xdc\xbc\xebY\x8f\xef\xfcb\x1c{\x97\x8f\xb5\xe3\xfe\xd7\xdf\xa7\x9b\xd9\x87\xfe\xf6\xddv:\xfa\xcd\\m\xbf~\xb9\x89\xbf\xfd~\xbb\xfc\xea\x7f\x0e\xec/\xfd\xf1\xf5\xfa\xe7\xe1f\x7f\xbd\xb4\xbf\xdc\x8e\xaf\xb1c|\xfcxq\xe3\\\xdd`\xfb\x0d\xbeF\xc1[\xfc\xc9\x8c\xde\x7f~s3\xb0{3\xeb\xdb\xab\xeb\x97\xb9\x8f^f\xfd\xf7\"\xfd\xf6\xfb\xdd\xaa\x19#\x96\xe3\xeb\xb2\xee\xf7\xbe\xf5\xf8\xde\xcf\xc7\xe0M\xd6\xe7\xf31\xf9\xd7\xbb\xf8\xb7\x0fo\xab\xb9\xe2\xeb\xc7\xcf\xd3\xe5mo\xbc\xff\xf6aj\xbc\xbb\xff\x9a~}\xbc\xda\xcd>L\xcd\xf7\x1f\xfa\xbb\x9b\x8f\xcb\xc7\xd9\xfd\xa7\xa4\xec'\x9b\xd9\xe5\xc3f\xf6q\x9a\xce.\xaf\x06\xb3\x8f\xd3\xc1\xec\x9e\x18c_]g\xe3~\xed_\x8d<\x99/\xea^\xad\x1b\xd35\xdd\xbde\xce\xf6\xd6\xc6\xf1\x9d\xcd\xec\xe3\x83\xf5\xfe\xc3h;\xf3F\xfb\x99gd\xf4\xa9cf}\xf1u\xff\xdd\x17\xeb\xf1z\xdf\xf0\xbd{\xf3\xf9\xf1\xab\xf96r~\xbd\x8b\xe6\xbd\xfe2\x1b\xbf\xdf\xfb\xaf\xbd\xb9\xf9Y\xff\xed\xc351Nf\xe3\x00Q\xa7\xcc\x1e\xfb\xff\xc0\xb1\xf9\xf7\xe9\xe0\xd6|\x8b\xbf\xfe~\xb7q\xf0\xddf\xde\xdb\x12\xf3\xe2E87\xef6No\xb5q^]\\\xde\xee\xa7\xfb\xd9\xe5\x95q\xfdju\xf3\xf5\xcbM4\x0f\xb2\xb2eT\xf0\xb9\xb8\xf9\xf81z;\x0fn\xf4\xaf_\xac\xfbo\x9f\xf0\xd5o\x1f\xdef\xfc\xd7\xf6\x17\xfc\xf0\xfe\xe1z7\xbb\xbf\xd6\xdf\x7ft\x1eo\xee\xddW\xb3\xc7\xab\xdd\xdd\xc7o\xaff\x0fo/\xef>^\xeb\xb3\xcb\xe5nv9\xdd\xcf>:;\x82\xdf\xd5\xbcwc\xcc\xbf|^\xbbW\x0d\xbfoo(~z+\xbf|\xee\xac\xe7\x13\xec\xf8\xb8\xf7\xed\xcb\xdd\x1b\xc7\x1f\xa7\xd7\xbf\x16\xba|\xef\x8b\xe7\x85\xdb\xfb\xab\xfd\xec\xfe\xd6\xbay\xbc\xea\xdd\xe8\xd7\x8f\xf9\xbc\xf0p\xbd\xbf}\xb8y=\xbb\xbf\xdd\xbe\xbf\xbc\xda\xce.\xafw7\x8fW^\xc3O\xde\xfa7\x97\xa3\xf0\x1f\x97\xe3_\x7f{\xfc\xf4\xb2\x8d\xa6\xfd\xef\xe2\xe5v:\xbd{5\x9d^O\xa7\xcb\xcb\xe9\x87\xeb\xe9tuu1\xdd]]\xbc\x1c\xddN\xbfd\xe3\xe6\xed\x14\xf8\xdf\xd7\x8b\xe9\xed\x15\xf0\xfc\xfa\xeajzu1\x9d\xce.\x98\x82\x8b\xe9\xe5\xd5\xab\xa9~u7\x9d^]^\xf0<\xef\xae?\xbe\xbe\xf8\xf4\xe5\xea\xc3\xf5\xe6\xa5=\x9dn/\xa7\xb7\xd3WW\xb7\xb3\xbb\xe9\xe5h\x1a\xbe\x0f>~6n?^\x0e\xdf\xbeMV\xbf\x99\x9b\x0f3\xf3\xb7\x97/\xbf)\xcd/\xc6@m\x829*\xbe\xcf\xe6\xd7W\xb7\x0f_\x96\xbd\xe9\xff\xc6\xf7\xff\x7f\x1d\xdf\xab\xce\x01t\x1c\x9e\x8d\xad\x8asV\xcfH\xc9y\xab\x8c!U\xe7\xad\xc7\xcf\xbf\xe2\xed\xb7\x0f\xe3\x0f\xdf~\xbf\xd9\xb8\xbf\xbf\xbd\xcf|\xe9\x9b7{\xb6\xf8Y%\xae\xbfy\xfcj\xce\x1e\xde^\x15I\x97\x99!\x1f\xbf\xdb\xd7\x1d\x0d\xbf\xaf\xad\xfc\x9e-\xbeoOn\x1c\x15\xdf\xdf]\xb6\xf2\xfbN\xf1=\x1a\xbc5\x1f\xb2\x11\xe2\x91M\x96\xe8\x9f.\x93\xd9vv\xff\xe1.\xfc\xfa\x9b\xf5\xe6\xbf\xfb\x1f~\xbb\x99\xdf\xdd\x7f\x9e]\xdd\x1a\x8bWw\x97\xcb\x9f\xbd\xe0\xe5\xe0\xe7\xb7\xc6\xf4\xed\xa7]\xb2\x9c^\xbd\x99NM\xe3b\xfav\xf6A\x7f\xf3\xb5\x18\xcf?|\xfa\xfc\xfe\xee\x1f\xd6\xab\xaf\xd7\xd7\x92\x04J\xb3\x15C\x1f\x8e\xa1\x7f\x03\x8e\xcf\xccCwO=\xe0N\"\xb8\xf4A\x04\xd7\xa3\xcf\xcd\xb8\x98\xfe\x95\xdeZ\xae6\xe6\xe8\x87\xfc\x01\x9dE\x18\xfb\xf4F\xacA\xff\xda\xa3\x7f5\xe9_\xfb\xf4\xaf\x16\xfd\xeb\x80\xfe\x95?\x0b\xb4J}\xba\x15\xf9Nu\xb1\x89\x83|\xdb\xc3\xff\x12\x95\x96\xdbT\xa2\xe2\xc8N\x92m\x18\xbbB@\x8a\xc4\xbcS\xb4K\x85\x85\xeb\x98!,\xb64\xe9G\x1e\xbd\xc7c{\xf4.UH7\x9a>'\x101\xe7\x94\xca\xf3Q\xd4\xb3|\xd7\x93~BKPmK\xd2\x0fW\xf4\xaf\xb4-\xd6\xf8\x94\x0dH\xba7\xd8I\x84\x9cT\xcb\xf7\xd8\x0e\xe2\xf3%b\"M3\x06\xbbq\xb5\x9b\\\x9d0\xb2\x06\xdd\x9e\xf5BF5\xde\x19\x03\x96\xca\x18\x0e\xbb\xc3\xa1\x94\xac\xbf3Y\xaa\xa1\xbc\"s\xd7\xe7\xea1\xcd\xaeiJ\xa9\x06<\xd5`\xd0\x1d\xb4\xc8\xc6\xb7\xc8\xd2\xa5$\xa3\x9d\xc5U\xd3\xeb\xca\x1bd\xedF\\5\x03y5C\xbe\x9a\xa1\xd1\xed\xf7Z\xea\x19r\xf5\xf4\xe5\xf5\x18;\x83#a\xcf,2$\xc5\xc9\xb5C\xedq\xf6< \xf1:E\x934\x8c\xce\xf5I\\zd\xc9M\x9f`\xb4\xc8~'\xce\x0eT\xe7k\xb2\x9f\x1f5/p\xd1.\xfb\xe5\xdf\xff\xe5#\xd7\xb3;\x89\x13#\x14t\xec\xc0\xed\xfc\xe8{Ay\xea\xc0\xd4\x91\xff\xd3A,W\x90<\xa17d\xd4'u\x08\x80P\xadO\x00\x84\xed\xdd\x02\xaaM\xa9g\x00\x84*\x9d\x03\xaa\xaf\xbd\x7f@\x95)t\x11\xa8\xb2\xf6^\x02\xe9Q\xa5\xa3@\xb5\xb5\xf7\x15\x88J\xa9\xbb\xe4\x84\xcf\xdfc\x14\xbaL\xf9\xb0>\xbd3h\xe9G\xfeS\xba\x91\x7fb/\xe2\xe8\x14;\x11G\xa7\xd0\x87\xf8\xba\xd4\xba\x10G\xa7\xd4\x83\xf8\xda\x14:\x10_\x95J\xff\xe1\xabR\xe8>\xbc\x06\x95z\x0f_\x97B\xe7\xe1\x89\xd4\xfa\x8e\xff\xe7w\x9d\xb6^\x82\x9f\xd2K\xf0\x89\xbd\x84\xa3S\xec%\x1c\x9dB/\xe1\xebR\xeb%\x1c\x9dR/\xe1kS\xe8%|U*\xbd\x84\xafJ\xa1\x97\xf0\x1aT\xea%|]\n\xbd\x84'R\xeb%\xf8\xbb\xf4\x12\xb2^\xcf_\x1e\xe8c\xa0\xb4XN\xb8A1y\xce>?W\x9d?\xfd\xbf\x9e\x1f\x85qj\x07)K\x12\xa4\xb6\x17\x00D\xf9s\x82\xac}\xa6;\xf0\xc2d\xd3\xee)\xf2\xc0t\xacH\n2)\xcc\xbe\x85\xa0\xfeirBd\xc7\x89)\x94\x08\x9f&\x11D\xc6IDQ\xce\x97\x9a\x83\x82\x94v\x9d\"\x19t\x1e\x84\xe5O\x13\xa2\xac\xf6sn\x90\x98/\xb54\x8c\x8e\xe6\x93\x86\x11\xc7'\xef4Gs\xe2;\xc5\xbc\xea\xc7G\xf3*\xc88nY\xe7=\x9a\xd7\xf1\x8b\xab\xda*L_P\xaaN`\x98SX ms\n3\x89yNa'\xb1\xd0)\xec\xda\x82\x12\xd5\x11\xa51\xdd\xf1N'\xb2\xdc\xf1\x9c\xc4\x86;\x9e\x97\xccn\xc7s\x93\x99\xedxnmV\x93\x1a\x08\x1f]\x9d\xc8@\xc7s\x12\x1b\xe8x^2\x03\x1d\xcfMf\xa0\xe3\xb91QL\xb7<\xfe\xce\x1f\x83\x07a\x1aqL\x1389O\x94\xc2\xe4zMt\xfc\x18\\\xf1\x08\x92\x13\x84\x05\xa9\x14\xe4%\xe9\xda|[uD\xaa\x98\xfb\xa7\xb4\x03 Ri\x86\xaf\xdc\n\x89\xc0\xf8\x14\x81\x01\"\x15\x811)0\xed\xfb6}\xcf-g9)\x1f\x95\xd18s\xbb\xa7;O+\x9alt\x00\xe8\xb2\xc7\"\xda\xfa^]1\x1e\x00\xd4E\x81\x88~N\xdf_\x86\x18\x94%\"\x0e\xb8\xe2\x90wz\x80>\x7f.\xa2\x0e\x80{\x81\x94\xba\x8e\xef\x8bs;\x9f\xd2\x8f7\x03Av\x8a%\x08\xf2S\x8dA\xb08\xdd\x1e\x04\x93\xd3L\xc2\xa9\x0f\xb2\x8a\x82Y\x14\x86\x9b\xb9\x9d\xcd\xe3'\x98\xca\x7f\x92\xa5\xfc'\x1b\xca\x7f\x06;\xf9O4\x93\xffT+\xc1\x06\xc1'\x19\x04?\xc9 \xf8\xc9\x06\xc1\xcf`\x90'\x0ee\xac\xe6@\x83\xd04Zq\xd5\xaf\xa2\x13\xbc\xe3 \xc3\x05\xc8\x8eA\xb0a\x18\x1c\xd8\xb5\xe3\x07m\x19\xdb{\x06k\x9a&\x87\xf5=\x17\x82Z\x96\xc5A\x01\xd8p8\xe4`\x89\x877\xcd\x85\xef\x128\x1e\x8f9 .\x8c\x0d\xc1m\xdb\xe6%\x0d\xc3\x00\x92\xc1q\x1c\x01k\x00\x8c\x10\x82u\x9b\xdf\xd2d\xc0\x8b~\xf6\x87\xc3\x83P\xf6&g\x85\xd3\xc6:\x0d]%\xd8\xfeQ?\xd3_\x9ce\xb1\xf8Yw\xfc\x93\x80p\xd4B8\x12\x11\x0e[\x08\x87\"\xc2A\x0b\xe1@Dh\xb5\x10Z\"\xc2~\x0ba_Dh\xb6\x10\x9a\"\xc2^\x0baODh\xb4\x10\x1a\"B\xdd\x92\x13\xeaB\xed\xe8\xbd6\xd2\x9e\x98\xd6h%6 \xea|\x8c\xe1\x9c6^\xces\xda3\x1dt\xd8\x82\x88uX\x92\x08p\xd6\x82\x88uV\x92\x08p\xd4\x82\x88uT\x92\x08p\xd2\x82\x88uR\x92H\xa8\x08\xd6AI\"\xc09\x0b\"\xd69I\"\xc01\x0b\"\xd61I\"\xc0)\x0b\"\xd6)I\"\xc0!\x0b\"\xd6!I\"\xc8\x19K*\xd6\x9f(2\xb1+\xf1\x8eH\x11\x82N\x98O`1r\xd9\xc1{\xa8\xf7u~\x9c\xe5\x81\x8bE\xdf0\x07\x82Y\x01\x82\x0f{\x16?\x89\x84\xb1\x1d,\xf9\x81~`\x02\xf3\xf32\xc4<\xd7\xf9\x10@\xee\x11\xc6\xe1\x96\xc6\xf2\xaf\x0e\xa8\xa5\x85\xe0\x7f]\xcc\x17\x86\xcdO\xa8\xd1:\x8e0+\xb0\x85z\x8e\xcdO\xe6\x05w\x90\xc2\xee\x0f\xccE\x0f6J\xe4\x05l\x04\xe2Z\xba>\xe2\xad\xb2\nS\x08\x9d\x99f\xce\xcf\xa9 r\xa4\x0b\xa7v\x10o\x9b.\x1f\x8e\x94\xc1\x10B\x01\x837\xcc\xe1\xd0\xe2\x9b B\xc7\xf6x\xc8\x0b]E\x19<\xc1\x18\xa1\xb9\xc3\xeb$\xb07l@\xa2\xeb\xc6\xbc\xcf\xb3\xce\xa5\x9e\xe35k\x1b]\xef\xf7\xc7|\x08\x03 Mk\x88\\\x91W\x01\xf8\xf1\xc0q\x80 &\xc7\xa3\x04$q\\\x04\x91l\xedd\x85\\\x88`1X,\x16\xbc\xf4%\x01\xa4H4Z\xb8\x0b\xde{K\n\xb8s,\x16\x0e\x9a\x8bH\xa0\xde\xef.\\\xbe\x15d:\x91\"\x10f\x88\xe6\x9aV\xbe\xea\x84&\x80\xde\x7f\xd2\x9d\xc7\xf5\xd0\x1d\xdb\xae\xb7N\xce\xd9\xa1\"6\x18@\xd7\xe8Y1b\xd3\xadq\x8f\x85\x81(\x93EA\xa0>\x032\x00\x8cf\xe8\xac\xe4@R9\xd6\"\x0fc\x067\x1e\x8f\xc7\xc0\xea\xaf\xdew+\xc0y\x92<[iUz!\xd7\x90\xc5:P\xa41\xad\xd8U,\xe0UV\x1bbU\x96\xb5q+\xf7\x16[\xe4\x82*\xe2y\x15\xdb\x81\xa2\x96\xc8\x05kO\xb6\x1cX\xe7\"\xd3Q\"\xff\xe21\"\x17\x03\x90\xb0\x97\x01@\xd0\xd1x\x9c\xc8\xd7\x00\xa4\xc8\xddx\xa8\xdc\xe3\x98\x8c\xdfS\x9c\x8eO\xdd=\xd9\xefT\xa4Sw=\x86\xdb1\xde\xa7\xe0~*\xb9\xbeX'\x12oB\x97d!B\x8f\xe4\x80\x02\x87\xe4p\xb0?\xb20\xa1;r@\xa17\xb2\xc8\x16g|\xb6\x01\x90\xcbN>\xdd\x15\xdbe;\xc2\x13\xfd\xef\xe3\x88\x02\x9fc'!\xc0\xe7X\x88\xd0\xe78\xa0\xc0\xe78\x1c\xecs,L\xe8s\x1cP\xe8s\xc7M\xb9,\xbc6oc \xa2\xa0<\x9e\x06\xfb\x1c\x9b\x80}\xba\xcf\xe1\xe7\xf49|\xb2\xcf\xd1\xfc4\xadx d\xc5\xaeH\xf5\x02/\xe5-\x82\xf8,\xe4d\xa0\xf93\x0eZ\xdeF&\x91\xc0&f\xb6\x84\x08\x03D\xe3\xf2w\xd4\xb5\x0f\xd1\x07\xb8!\xdcn\x8f\xb4-\xd8\x92a\xb5\xc8(\x1cDd\x17\x1e\x08\x9b\x86\xc7\x81\xd6\xe1`\xa0\x818\x14l#&\xee\x15\x9a\x89\xdb\xbe\x17Z\x8a\x0f\xf5\x85\xc6b\xf7\xe2\xebm\xc0v\x83\xa9\x0cl[\"\x1a\x15\x1a\xd1W\xb4!\x8b\x13\x98\x90\x85\xc1\x16\xf4U\x0c\xe8+\xd9\xcfW3\x9f\xafj=68\x16\x1b\xcf?\xc1v\x023\xe1V3aE3\xb18\x81\x99X\x18l&\xacb&\xacd&\xacf&\xacj&6\x9e\x14\x9b \xc3f\xa2\x80\xc9\xcav\xc3\xadf\xd0\xd7\xba\xf3\x87\xe7zG\xef\xf4\xa3]\xa7\x17\xed:\xf4\xa6\xcbD \x05\xd6\xd4\x13\xd54R\xaa F\x815\x99PM\xbd\x92\xbe\xbd]r$Xc_Vc&\xb9\xaeP\x1f\x84\x03k\xb3\xa0\xda\xfa\xa5\xc4m\xb5\xc9p\n\x83\xf0\x01t\xa2lT\xff\xd3\xfcHR\xd9\xf3\xbb\x92\xa0\xb2\xef\xebM-\x95\xb6\x99\xf8x\x87\x12T\xf8,>\xa5\xe0T\n3{\xedi\xfe\x9f\xe8h\xc2\xba\xbe\x83\x9f\x81u}g7\x93\xd6\xd9f\xf4\x13\xbc\x0c\xac\xefOp2\x99?\xe1?\xd1\x9f\x84u}\x07\x7f\x02\xeb\xfa\xce\xfe$\xad\xb3\xcd\xbe'\xf8\x13X\xdf\xf3\xf8\x13Ua\x14\xa3\xfa\x0b\x1e\xda.\xff\xb4E\xfdq.m_~\x08\xa8\xf9\\W\xe2\xc4!\xa6?%\xd2\xcdb@=\xff\xe6\x11\x13\xb0\x15Q\x9f~\x80S\x89E\xa4\xa7W\x9fRb\x8a\xf3\xf0N?\x14\xe9I\xbe>#\xaf\x8f\x0fa\x8b*\x8d\xb2J \xc4-j5\xaaZyD^\xb1QT\xcc\x97fu\xf7\xf2\xba\xf9\xc8\xb8\xa8\xbbW\xd6\x0dD\xceE\xdd\xbd\xaan\x1e\x91\xd7\xdd+\xea\xe6K\xb3\xba\xcb\x86k\xa2\x96\xd7M\x07\x10e\xfdM\xe3\x01L.A\xd5|\xa0<\x97\xa1P\x80&\xd2@\xad\x02\x00Q\xc9P+\x01\xc0\x142\x94j\x00\xca\xab{\xd4\x9a\xb6\xf00>HoS+\xcc\xd0\x07\xde\x99\xb3\x98\x01\xf0\xe7\xc2'\xb3B\xc8-Ko\xcf\x8a\xa5\x0e_\xa4 \x9f\xcf\x1d\xbb\xaa[\xe4\x99u\xf5B\xe7o$\x10\xfb?!\x84\xc0\xc9+9D^Z\xcb!\xec\x08\x8d\x1c\xe2\xbe@\xc8!r\xf8J\x10\x89\xcf75\xc9\xdc\x9e\xa8K\xec\xf9u\xb3\x84\xce_\xcb#\xf6\x7fB\x1eI\x17 \xe5\x11\xf6\x82F\x9e\xb6\x8eP;\xad\xb0/(t\x06\x85p\xb5\xe8!\xbe\xa4\x83\xf8\xd2\xfe\xe1\xb7t\x0f_\xda;|y\xe7\xf0\xdb\xfa\x86\xdf\xde5\xfc\xb6\x9e\xe1\xcb;\x86\xdf\xd6/\xfc\xf6n\xe1\xb7\xf6\n\xbf\xb5S\xf8*}\xc2W\xe8\x12~[\x8f\xf0[;\x84\xaf\xd2\x1f|\x85\xee\xe0\xab\xf6\x06\xffI\x9dA\xe8\xf7X\xe2\xf7X\xea\xf7\xb8\xc5\xef\xb1\xd4\xef\xb1\xdc\xefq\x9b\xdf\xe3v\xbf\xc7m~\x8f\xe5~\x8f\xdb\xfc\x1e\xb7\xfb=n\xf5{\xdc\xea\xf7X\xc5\xef\xb1\x82\xdf\xe36\xbf\xc7\xad~\x8fU\xfc\x1e+\xf8=V\xf5\xfb\xb6\x80\x88&v\x16\xe7\xf6\x82}5j\xf6t\x8e\x16a\x8c\x0e\xe5\xc7{\xcf\xff\xd2\xf9\x0b\xfd\xe5A\x98\xcd\xc1\xc1\xc8\x8e\xcf\xe7a\xbab\x01\x87\xbf=\x86\x99o1\xcfqI\x92I\xc7\x14U\xdc\xf2\x960esqMAYt\xd2N\xb9\x93O\xa3b\x91\x9aRP\xaa\xa6\x18\x12\xac)U\xd8 V\x9d\x8e\x9dl\xa8\x93\x08\xecK\xe5\xf5e\xe2\xfa\xea\xd2\xc2\x82\xc9\x8c[\x17\xc2\x82a\x99`\x98\x12\x8c*u\x03\xd9\xe7\xfc<\xe6S\x81L\xf1\\\xf2A\xc2\xae\xeb\xcd\xdb?4\xd8u\xbd\x94E\x01\xfd\xc5m@`\xa9C\x17k\x0eb\x17\xddn\xaa\xc5\xe1\x96\x81\xc5\xe1\x16Bi\xcb8\\G<\xb6x\xceQ8!^\xfb\x01+A\xfeP\x80\x05+ \x8b8:m\xe1\xed\x90{(\x90\xd8\xde\x87\xeb\xf4<\x7fD\xbc\xfeJ\xa1\x7f\x1c\x18\xdbg=Lf~\xb2\x1c\xf6\x00\x12\x01;\x01\xcfC\xe0\x07\x00\x1046\x89\x83\xbd\x81C\x08\x1d\x82GJ}\x02\x84K\xdd\x02\x10\xa5\xdd3DDR\xe7\xc8\xd73R\xffPp\x10\x85\x01\xd4\xcd\x06:\xa9\xd3\xf8m>\xe3\xb7\xb9\x0c\xcbA\xe41\x1c\x0ev\x18\xbf\xcd_|Uwa\x81ro\x01\xd0rg\xe1\xe4P\xf0\x15\x98F\xee*\xfe\x93<\x05v\n,w\n\xdc\xe6\x14\xb8\xcd)X\x0e\"\xa7\xe0p\xb0S\xe06\xa7\xc0\xaaN\xc1\x02\xe5N\x01\xa0\xe5N\xc1\xc9\xa1\xe0\x140\x8d\xdc)p\x9bSPt\x0b\x8cvu%D\xee\xbd\x0e{5?\xd12\x10\xf9,\xfb\x9dfS\x9a\x08\xe4V\x99\x99aJ\x90\x90E\xc4c^R\xcd^\xa7!\xb5E\x90==7&\x95\x94\xe7F\xc7\xe8\xe4\xd9|\xfa\xb7\xc6\xeb\xf5\xfc\xe7\xea\x85\xa9@\x15\xf9\xe1S\xae\n\xbd\xa9\"\x7f\xe7A\xfd\x13\xc0\xa1\x8c$H\x1ea\xece\xeb\x89\xea\x0b\xe3\x13\xb2\xcc\xf5\xe2\xe2\x95\xff\xe5\x17\xcb\xeb\x9a\x88\x92\x82\xe5\x04|\nH\x90\xc5H@\xf5\xab0\xf6\x1e\xc3 =A\x808\xdc\xb2\xb5s\xfd#/\xdf\xc6vt\xa8\x19d\xbf\x9dg\xffL\xe8_A\xbd\x03\xa4\xc5\xc3 \xfb@P\xaf\x16\xa3\x0d\x8a\x13\x04\xd4_\x15M\xe0\xc7B+6,\x8f\xb6fU\xa3\xd0\x9c\xb4L\xa2R\xd8\xbc2\xb9Z\xcd,\x91\x8c`\x0d\xd8\x1b\x96\xc9K\x91\x9fhIj\xc7)%N\xf1\x19\xfd\xfcyS\x15\xf90\xff9\xff\xbcy\x92\x8f)\x05\x0f\x889\n\\\x805\n\\\x96q\xf6\x88c\x8b\x02\x17bZ\xbe\xe8\x93\xe7[\x14\xb0\xac\xcb\xa7$\xf7\xe2\x11\xc4{n'(\x1b\xc8\x00\xeeU\x11\xcb\xbf~N\xd6P=\x845\x1e\xa3\xd4Y\x81:\xcfKx\xad\x17\x8f\xc9\n\xcag4\xff\x04\xe1Ee\xd0\x8aE\x06\x07\xac\x97A\x85\xc6\xcb\xf9\xe4\xb6\x03\xb84\xa6jxp\x96\xca9T\x86\x02\x98PF\xc9\xf9@6\xc9\xb94&\x01\xf80\xca\xcf9\xc1\xba/uS\xaa\x1e\xd4\x0e\xa9\xe5\x9c\x13\xa8\xe4\xfbu\x92z\x8b=\xd0q\"\xdby`\xfb\x0d\xf1\xac\"\xac\xb2T\"\xedW8\xb6\xf3\xe4\xac\xa8\xbeS?\x01YsF\xa9Q|\x07\xca9\xb1\xfd\x87|\xc8\xd6\x00\x99\xab\xc2\xccQ\xbaE(\xe0+(\x01L\x0d\xd5S\xb6\x8a$\xb2\x1dT1\x83k\xb2\xf3\xd74\x1eh~\xae\x97\xa4\xb17_\xa7H\xc0\xb2\xa0\xa29\x96\x08\xb6\xf7\xe4A\x0da\xc3\xc29\xda,X1\xa3\xbaP\xc3\xaa\xe9Ar{Ul\xd8~\xd4p\xa2\xba\x91\xcc4\x15\xab\xda4<\xaf\xca\x0c43\x89\x11*\x9e\xac\x11\x1a\x96\x84% \xaer;0=\x95\xb4\x04\xd9Qk\x96P_-\x0e\xdf\xea\xccl\xebz\x81\x8d\x8bh\x9c\x88A\xb5\x1c|\xaeO\xca\xffB\x9c\x0c \xa7\x1e\xcb\xc9(9\x19\x10\xa7\x9e\x84\x93\xc9r\xea\x95\x9cz\x10'S\xc2\xa9\xcfr2KN&\xc4\xa9/\xe1d\xb1\x9c\xfa%\xa7>\xc4\xc9\x92p\x1a\xb0\x9c\xac\x92\x93\x05q\x1aH8\x0dYN\x83\x92\xd3\x00\xe24\x94p\x1a\xb1\x9c\x86%\xa7!\xc4i$\xe14f9\x8dJN#\x88\x13\xb6\x93T\xe6\x9cz\xf6?\x96\xe38\xfb\xdf\x84\xf8\x19\x085\x97Y\xd4\xa7\xcb\xd6C\xe5\xbbm7\xe8\\\x9f\xd4$\xe0\xca*\xe7e\xc8\x96o\x0d/\x83\xe0e\x00\xbc\x92U\xec\x05\x0f\x99d\x15i\x80\x966)F\x81\x00\x05)\x89\x0d\x80\xd8\xa0\x88\x0d\x85\\\xdb\x81\xe7O\xe4\xfd\x88\xc6\x9e\xbe\xa4\x86\x18>\xf7\xaaZc\x0e\x0c/\xbe\xcb\xc2\x1a\xac\xe5\xf8\xb55\xcbFmA\xf6\x9c\xcbk\x81\x04\xadK\xafgZa\xe7\xd5W<\x8e^d\xf3\xd4\xa7\xad\xb3a)\x9e\xba\xd4>\xcd\xb8\x7f\xcaj\xfbT\xab\x7f\xbf\x057+\xd1\xf3\xae\xb9a\xee\xcf\xb2\xec\x86Y?\xe3\xca\x1b\xae\xe0\xb9\x17\xdf\"\xfd?\xd7\xfa\x9b\xeabOY\x82\x8b\x18\x1d\xbb\n\x17\xf19a!.bu\xdaZ\\\xac\xa9\x13\x96\xe3\xacY\x9f\x7fE\x0e\xd6\xf0|\x8br\x90\xfd3\xaf\xcb\xc1:\xbe\xd3\xd2\x9c\xb2\xee3\xad\xce)\x9eO^\xa0\x0b\xb8\x9d\xb6F\x170;u\x99.`\xf7\xc4\x95\xba\x80\xeb\xd3\x17\xebB\xc3\x1c\xbb^\xe7\xe7\xeb',\xd9\xe5\xcc\x8e\\\xb5\xcb\x99\x1d\xb9p\x973;r\xed.gv\xe4\xf2]\xce\xec\xc8\x15\xbc\x9c\xd9\x91\x8bx9\xb3#\xd7\xf1rf\xc7/\xe5[\xfc\xf6\x89\xaby\x96\xfb\xe2i\x0bz\x90\xddS\xd6\xf4T\xf7?aY\x0f\xd3\xb3+{\x85\xa5\xbd\xc21\x9a\x9c\xa7\xff\xcc\xcb}\x9e\xdf\xb3\xaf\xf6\xfd?c\xb1\x0fTr\xc2Z\xdf?a5\xf8\xacK}P\x80\xd65\xdfs\xad\xf4\xfd\xa7,\xf4Y\xe2\x13\xd7\xf9\x90\x0cO^\xe6\x9fb\xd7?g\x95\x7f\x9a\xc1\xbf\xe3\"\xdf\xff\x9ek|\x88\xf9\xf3,\xf1!\xce\xcf\xb9\xc2\x87\xf8?\xfb\x02\x1f\xd6\xfd\xb3\xad\xef\xfdgZ\xde\xc3|\x8e^\xdd\xc3lNY\xdc\xc3\x9cN\\\xdb\x8b\xb4t\xca\xd2\xde\xff\xde+{\xa0\x82g\\\xd8\x03\xdc\x9f{]\x0fT\xf1\xbd\x96\xf5\xfe\xf3\xaf\xea\xfd\xe7\\\xd4\x83\xccN\\\xd3\x83\xbcN^\xd2\x83\xdc\x9e\xba\xa2\x07\x99>\xc3\x82^`\x93\xa3\xd7\xf3\xec\xcc\xfc\x94\xe5\xbc\x8c\xd7\xb1\xaby\x19\xafc\x17\xf32^\xc7\xae\xe5e\xbc\x8e]\xca\xcbx\x1d\xbb\x92\x97\xf1:v!/\xe3u\xec:^\xc6\xeb\x84e\xbc\xd4]\x9f\xba\x8a\x97\xae\xae\x8e^\xc4K\x17\x84'\xac\xe1\xfd\xa7-\xe1!\xf2\xe3V\xf0\xa2\xc5:~\xe6\xc5:\xcf\xef\xd9\x17\xeb\xf8\xcfX\xac\x03\x95\x9c\xb0X\xc7',\xea\x9eu\xb1\x0e\n\xd0\xbav{\xae\xc5:~\xcab\x9d%>q\xb1\x0e\xc9\xf0\xe4\xc5\xfa)v\xfds\x16\xeb\xa7\x19\xfc;.\xd6\xf1\xf7\\\xacC\xcc\x9fg\xb1\x0eq~\xce\xc5:\xc4\xff\xd9\x17\xeb\xb0\xee\x9fm\xb1\x8e\x9fi\xb1\x0e\xf39z\xb1\x0e\xb39e\xb1\x0es:q\xb1.\xd2\xd2)\x8bu\xfc\xbd\x17\xeb@\x05\xcf\xb8X\x07\xb8?\xf7b\x1d\xa8\xe2{-\xd6\xf1\xf3/\xd6\xf1s.\xd6Af'.\xd6A^'/\xd6AnO]\xac\x83L\x9fa\xb1.\xb0\xc9\xd1\x8buvf~\xcab]\xc6\xeb\xd8\xc5\xba\x8c\xd7\xb1\x8bu\x19\xafc\x17\xeb2^\xc7.\xd6e\xbc\x8e]\xac\xcbx\x1d\xbbX\x97\xf1:v\xb1.\xe3u\xc2b]\xea\xaeO]\xacKWWG/\xd6\xa5\x0b\xc2\x13\x16\xeb\xf8i\x8bu\x88\x9c[\xac3\xf4\x87\x05\x0e\xed4\x7fG\xce\xe4\x0fz-\xcc@\xe3\x12\x9a\xbf1\xa7\x05\x1b\x94\xd8\x93\xde\x82\xb4\xc8\xdf\x82\xa4.W\x83V\x12\xad\x81+\xbcYH\xfd\xfc\x81\xe6\x1f#\xb2\x7f\x94\xc4\xbe\xba\xc0\xb0l\xc7\x98\xb9\x06\xab\xc9\x86)\xd9\xa8\xd2\xc4\x0e\x12-A\xb1\xb78,\xc2 \xd5\x16\xb6\xef\xe1\xfd\xb9fG\x11FZ\xb2OR\xe4\x9f]`/x\x98\xd9\xce\x87\xfc\xd7\xd7a\x90\x9e\xd9\x1b\x14xq'@\xbb\xea\xe7\xb3\x15\xc2\x1b\x94-r\x9b\x9f:\x01Z\xa3\xb3\xf5|\x1d\xa4\xeb\xb38\x9c\x87ix\x16d\xff$h\x19\xa2\xce\xda;\xb3c\xcf\xc6g\x8d\x14\x8ct\x9c`K\x14\xc6K\xcf>\x83\xc0\xb9t\x9a\xa0E\xc2*J*\x9e\x80\xc7:\xa1\x8b\xa8\xf7\xa0e\x0f(\xa2Wa\x90\x84\xd8N\xce\xfc0\xb0\x9d0\xfbO\x98G\x13,\xa3u\xec\xa1\x98!\xcd\x9fun2\x95\x96\x00\x11}\xad`\x8a\x03\xa3\xf6\xc6\x1e\xa2\xb6\x17\x86\xa3x\x00v\x15R\xa7+\x84\xed\x84&/\x9e\x9dI\xccT\x16\xa9Z5\xf5|D\xd7\x91?\x81\xa0\xf3\xd0\x0d\x03\x8f\xc2^\xe4\x8f:\xb3\x8f\x10\xde\xb1\xb1\x97\xa4!m\x85\xe2\x99\x80bi\xc7\xb6\x1f\x06.-|\xf9\x10\x14\xc9N\x1eP\xbc\xf10\xa6\xfd\x84x\x0e\x91\x95\x8d(>\xa1\xe5\xa56\xf6\x98\x0f_/\x12\xad\xc8\xc3\x91\xc0\xe2\x89\xc2`I\x8f=\xf9;\xafT\xebc\xb0e\x95\nu*\x0c\xd0^6\x88\xaa\xca\xe1\x1f-\x06X#V\xaf\x11\xd25\x8d%M\xb2-r\xc8}\xee\x93\xefT1\xf7E\xf8\xc5\xd6\xa0\x00\x06\x0f\xe8Q\x80\x1e\x0f0)\x00\xf7y\xfa\xc5\xb6/\x17q\xb1\xb5(\x80\xc5\x03\x06\x14`\xc0\x03\x86m\xcd\x1cQ\x80\x11\x0f\x18S\x80\xb1~\xfc\x9b\xba\x19\x8f\x15Z\x84E@Fa1\x90]X\x0cd\x1a\x16\x03Y\xa7U\xe2E\xf1\xb9\xb36\x1b\xb1\x18\xc8L\nm\x1f\xb1\x18\xc8X,&\xb3\x97\x82\xc1\x14F\x05\xba\xbf\x8b\x8d\xe8\xb7\xb5\xc3` \xa0 \xfdv\x0b\xfa\xed\x06l\x11v\x91\x7f\xed\xac\xd5|~\xbb\xf5Z\x1b=b \xa0\xed\xfc#M'\xb6R\xdb\xe0\xc7\x00@+\xe1v+\xe1v+\xe1v+\xb5\x08\xbb\xc8?v\xd6j%\xdcn\xa5\xd6F\x8f\x18\x08h%\xcc[\x89\xc2xA\xb4N\xb5\x18%\xa8\xb9\xdfnG\x11\xb2c;p\x8a/qN4?|d\x1f2&Z\xa7i\x18\x14l\xce\xcfs\xfc\"t\xd6\x89\xe6\x05\x01\xfb\x16`\xa2F\x1eZ~\x86\xed\\\x9fD\xb6\xebz\xc1\x92]\x18\xaf\x8cC\xb9\xd1\xca\xbf>y\xd5\xab\xca\xf8\xd7\x19\xaf\xcc\xaa\xac\xcf\x97\xf5\xab\xb2\x11_f\xd5\xf5\x0d\xf8B\xadW\x17\xf7\xac\x17l\xa1\xa5W\x85\x16\xfb\xa9\xe5\x956\xac)\x87<\xa5\xa1\xd7\xa4\xfcg\x9a\xf3\xcd\xe6\x1cBl;\xf3\xb0\x0d-\xddf\xc5\x15\x93\xf2\x01\xc5\xa4\x84@1-#\x0b\xc8D\xdb@R\xb2\xc0U\xf1\xce\xb9\x12\x90\xfd\xcc\x96{\xc1\n\xc5^ZA\xca_\x15\xe6\x89\x03\xe39\xd9t#q\x1e\xa2\x18\xf2\x1f\xa2\x18r!\xa2\x18\xf2\"\xb2n\xd8\x91\xc8\xea!_\"\xcaAw\"\xcaa\x8f\"E\x10;U\x86j\xf7+JX\xd0\xb5(qA\xef\xa2\x04\x86\x1d\x8c\x16Y\xecc\xbc\xd0\xb0\x9b\x11\xfc$\x9eF\xa0*gS\xf06\x85\xa8d\x95E\x132\x0f\xf4\xa5\x0e\xe8K\xfd\xcf\x97\xba\x9f\xdf\xe6}\xbe\xdc\xf9|\xb9\xef\xf9-\xae\xe7\xabx\x9e\xaf\xe2x~\x9b\xdf\xf9mn\xe7\xb7z\x9d\xaf\xe6t\xac\xbc\x02\x9f\xf3U\\\xce?\xce\xe3`\xe7\xc2R\xe7\xc2R\xe7\xc2R\xe7\xc2R\xe7\xc2m\xce\x85\xe5\xce\x85\xe5\xce\x85[\x9c\x0b\xab8\x17Vq.\xdc\xe6\\\xb8\xcd\xb9p\xabsa5\xe7b\xe5\x158\x17Vq.\xcc9\x17\x05Lc\xdby@\xee\x01\xa34E\xb1\x96D\xb6\x93E^]\x83\xfb>E\x01\xd4\xd2\x8c\x19\x0b\xd7\xba\xba%\"\xf0\xd1\xd2\xe6\xd8\xf72x\xfb\xb8z\x009\xe6\xdf/:F\\\x80\xa2Mb\xa8\x92\\h\x05\xa9\x15f\x83\xba\xaac[\xc2\x11\xb46\x84\xafB\xa1\x1d\x12\x91\xf1\xb1\"s\x04\xad\"\xf3U\x14\"S\x14x\xa5%!\xf6\xdcC\xbe\x8f^u\x16\x0e\x93z)F4\xa6\xdb\xb38\x98\x13F{\x06e)\x98\xfa\x00\x8a\x94;O\xbbT\x1cL$\x18\x0f\xb4\x9e\xc9\x0fk\x89}%\x81}EyY\\\x9b\xb82\xc9\xb0\x92dXQ2\x16g\xb1^\xe5\x05\x0f\x87\x14\xedR\xcdEN\x18\xdb\xe5 Vv\xd1\x9b\xc1\xce\xb8'\xe7\xb6\x93z\x1b\x04\x14\xe4\xcb\\\xe0\xf9*\xdc\xb0k\xe4\xfc\xb9\x80\xff\xc6K\xbc\x145o\x1cMc;H\xbc\xea\\g\x18w\xba\x86\x95t\x90\x9d \xcd\x0b&\xd2R\xbe=\x85\x90\x87p\x9df*:7\xa2]\xc7\x0d\xd3\x14\xb9\x1dg\x1d\xc7(H_eLX\xba$=d\xff\x14Yn-\xddGP\x8e\xc0\xdf\x16\xab\xc1\xda\x15\x81\xd9zk\x90\xe5\\,\xe1o{D9\x1f\xc6\xf8[\x93(\xe7\x03\x19\x7f\xdb'\xca\xf9P\xc6\xdfZd\xfd|0\xe3o\x07\x04\xc0\x84$\x18\x92\x12@U\x8c\x08\xc0\x00\x92qL\x00\xc6\x90\x0c\xc5+\xd4\x1b\xd0I\x9b\xf1\x859\xf2\x85\x93\xdc\"\x0c\x042\n\x0d\x01\xedBC@\xd3\xd0\x10\xd0:\x8c,\xa0\x81h\x0cl#F\x1a\xd0L4\x06\xb6\x14\x8d\x11\x1b\x8b\xc6)\xec\xf6\xab\x8e\xdd\xa5\x15\xfdV#\xfa\xad6\xf4[M\xe8\xb7Z\xd0o5\xa0\xdfn?\xbf\xdd|~\xbb\xf5\xfcv\xe3\xf9j\xb6\xf3\x8f3\x9d\xd8J\xb8\xd5J\xb8\xd5J\xb8\xd5J\xb8\xd5J\xb8\xd5J\xb8\xddJ\xb8\xddJ\xb8\xddJ\xb8\xddJX\xcdJ\x98\xb3\x12\x05\xdb\x1a\x07\x91Z\xb7\xbd\x83H\x9f[\xf3 R\xe4\xb6\x7f\x10ipk\x1d\x84\xaa\xcb<\xa1*e=`\xab\xf5\xaa\xb2\x1ePVq\xe5\xd6\xd0[\xcd\xac\xe8L\x9e\xce\xac\xda`\x9a|Y\xd5\x08\xb3\xcf\x95\xf5+\x9e}\x9e\xa7U\x95q\x0b\xf6\xad6\xa8\xca\x06|\xd9\xb0*\x1b\x02eU\xfb\xb8U\xfeV\x1bUt#\x9en\\\x95\x8d\xf9\xb2,\xe0\x10\xf5\xb7\xad\x96\xae\xbc\xd8\xad\x95\xd35\xb3\xff\xf1\xa0mX\x00\x93\xaaY\x83\xee`0\x18\x0c9d\x9e\xc7.0\xf9b\xbc}\x80?0.\x9aM\x13b/mJ!GmJ!_mJ!w%\xea\x85=\x96\x00@NKH\x06\xf9-Q\x0c\xb9nS\x0cz/Q\x0c90Q\x0c\xf90\xa1\x16\xc8\x8d\x9bb\xd0\x93\x9bb\xd0\x99\x9bb\xd0\x9f\x89b\xc8\xa5 \x9b@^\xdd\x14\xc3\x8eM\xdaD\xe0\xdb\xa4\xeaZ\xdd\x9bh\xab\xcc\xc3\x1bX\xee\xe4\n^\xae\x10\xc6\xe4\x01\x8a\xc4\xf3}\x99\xe3\xfb2\xbf\xf7en\xef\xb7x\xbd/uz_\xea\xf3\xbe\xd4\xe5}\xa9\xc7\xfbR\x87\xf7\xa5\xfe\xeeK\xdd\xdd\x97z\xbb/uv_\xea\xeb\xbe\xd4\xd5}\xa9\xa7\xfbrG\xf7[\xfd\xdc?\xc2\xcd}%/\xf7\xd5\x9d\x1c\xf6g,\xf3g,\xf3g,\xf3g,\xf3g\xdc\xe2\xcfX\xea\xcfX\xea\xcfX\xea\xcfX\xea\xcfX\xea\xcfX\xea\xcfX\xea\xcfX\xea\xcfX\xea\xcfX\xea\xcfX\xea\xcfX\xea\xcfX\xee\xcf\xb8\xd5\x9f\xf1\x11\xfe\x8c\x95\xfc\x19S\xfeL!\xc2\x0d\x8a\x178\xdcj\x1b/\xf1\xe6\x18\x1d\xaa\x07\xe7\xe5\x03\x01|\xe5\xb9.\n\x1at\xf1\xbb\x00\x9c8q\x88q\x03.~\x17\x80\xf3H\xaa\x86\xf2;\x1b5p\xc7\xc9\xac\xedZ\xa4\xde\xb1rk;\xb9\xe4;Vvm'\x97~G\xcb\xaf\xedd-\xd8\xf3-\xd8\xb7\xb4`\xcf\xb5`/o\xc1\x9ek\xc1^\xde\x82=\xd3\x82\xfdi\x01-\xebXY\xe8p\x94oQ\x04\n\xeeE\xe1[=\x8cB\xab8\x19I\xa0\xecg\x0c\x91\x92\xab14\n\xde\xc6P\xa88\x1cE\xa2\xeas\x0c\x91\x92\xdb14\n\x9e\xc7P(\xcc\xc1\xaa\x81&\xe7\x92\xfe\x91\x1e\xe9\x1f\xe7\x90\xfe1\xfe\xe8\x1f\xe9\x8e\xfe \xde\xe8\x1f\xef\x8c\xfe\xb1\xbe\xe8\x1f\xed\x8a\xfe \x9e\xe8\x1f\xef\x88\xfe\xb1~\xe8\x1f\xe9\x86*\x1e\x87\x8f\xf48|\x9c\xc7\x1d3\xc7\x92`%\x8f\xc3'x\x1c>\xde\xe3\x8e\x9dki\x02%\x8f\xc3'x\x1c>\xde\xe3\x8e\x9dsi\x02 XKR;\xf5\x9cCq\x055\xcc\xdf\x8d\x91\xb2\xb7Ob\x84\xf3;\xa2\x0d\xaazB\xe3\xecy\x12\xe2uJ\xe0\xaa'4\xae\xf8\xa8~\x0d\xca\x7fU\x18\x8e\x0f\x80\xe0\xd9\xc8\xae$;\x05\x94\x8bOA%-\xa0pE#\x14Z\xa10\xa9\x94M\xf3\x15[\xe6+7\xccWk\x97\x7f\\\xb3\xc4-\xc0\x8a-\xc0\xca-\xc0j-\xc0\\\x0b\xe8N\x92'r\xc3\xc8v\xbct\xcf\xbdu@\x1b7e\xdd1[8\"\n\xd9\xbb\xe9\xda\x90(d/\xc1k\x03\xa2\x90\xbdm\xafYD!{\xad_\xeb\x13\x85\xec\xfb\x034\x93(d_T\xa0\xf5\x88B\xf6\x8d\x08\x9aA\x14rJ\xd0\xad\xa6P\xe7$\xd2{d1{0\"\xd4\x1a\xce\xccy\xfb8L\xed\x14i}\x8b>o\xb0\x08c\xff\xbc(\xfb\xb1o\xb9h\xf9\xd3D\xf0\x1cd7\xd6\xc5\xec\xc6:\xcc\xaex\x0e\xb23L\x89x\x86)\x90\xaf,\x809\x8e$\x12\x1a#\x81\x88e\x01\xc8\xb1\xd7\x93\xc8\xd8\xeb d,\x0b`\x8eC\x89\x8c\xbd\xa1@\xc6\xb2\x00\xe4h\x1a\x12\x19MC cY\xa00\x96\x1e`\xd7\xd2\x88\x0f\x1c<\x8fwI9\x9e\xe6`R\x96\xa7\xfa\x98\x9c\xe9\x89n&ez\xaa\xa7\xc9\x99\x9e\xe8lR\xa6\xad\xfe\xa6\xe0p\n\x93w\xe3\x85\xfes;\xa1\x84\xe1\x89>(\xe1x\xb2\x0b\xcax\x9e\xea\x81\x12\x9e';\xa0\x8c\xe7\xa9\xfe'\xe1\xf9D\xf7\x93z\x1a~nO\x930<\xd1\xd3$\x1cO\xf64\x19\xcfS=M\xc2\xf3dO\x93\xf1<\xd5\xd3$<\xdb=\x8db:\xc7\xb6\xf3\x90EP\xf9y\xce\xf3x9\xb7\x7f\xd4\xcf\xb2?\xdd\xf1O\x10t\x04AG t\x08A\x87 t\x00A\x07 \xd4\x82\xa0\x16\x08\xedC\xd0>\x085!\xa8 B{\x10\xb4\x07B\x0d\x08j\x80P\xdd\x02\xa0:\xdb\xae\xed\xca+\x02\xde\x02\xbbJp\x8e}qf\xe8\xfa\x0b\xded\x05|$\x82\xb3f+\xe0C\x11\x9c5]\x01\x1f\x88\xe0\xac\xf9\n\xb8%\x82\xc3M\xed\x8b\xe0\xac\x19\x0b\xb8)\x82\xb3\xa6,\xe0=\x11\x9c5g\x017Dp\xd0\xa4%\xf6\xaf:{\x93:@v\xacQ\x10\xc3`V`\xae\x1d?h\xcb\xd8\xdeW\x08\xd3dVw\xbe\xe7R\x00\xcbb\x96ad\xe1p\xc8\xacG\x13\x0foP\\\x15s\xefB\xc3\xf95\x0b\x1ad\xdb6#A\x18\x06\x94\x08\x8e\xe3@lH\x08B\x08\xd0E\xae\xdd\n\xb2\xe8g\x7f\x00\xf5\xd7\x80\xc5\x02PV\x8c\xdc\xba\x92\xa1\xde\xd7\x19\x0cQ\xbcX\xf4\x0ds\x00IJ\x81\x86=\x8biN\x18\xdb\xc1\x92\x10c\xc0]\xe9_\x86\x98\xe00\xe7\xae\xd9\xef\x11\xc6\xe1\xb6Dd`H\n\n\xf4\xd7\xc5|a\xd8\x8cy\xa2u\x1c\xe1Z\x10\x0b\xf5\x1c\x9b\xbd\x9c\x90s\xa2qv\x7f`.z\x80\xea\"/\xa8=\xd1\xb5t}\xc4\xe8n\x15\xa6\x14&S\xe0\x9c\xb1\x10]>\xd2aW\xa0Q\xb6\xe9\x0eA\xb7G(\xa8{\x869\x1cZ=\xd6\xb3I\xc0\xd8\x1e\x0f\xfb\xb0\xdf\x11\xb01Bs\x87iW`o\xf6M'5\xe6\xfd> \xcd\x1c\xafQ\x03\xea\xf7\xc7\xec\xcb\n\x88r\xd3\x1a\"\x17\xb4)\x89\x1a\x0f\x1c\x87u\xe1\x1c\x85\x12\x1a\xe8\xb8\x88\x03n\xedd\x85\\\n\xb6\x18,\x16\x0b\x04\xc2(\x15\xa0\xd1\xc2]X \x8eq\xb9\xc5\xc2As\x10H\xf5\x10w\xe1ro'\xc3a\\_\xb1/\x80\xd5-AZkK\xad\x8e<\xe6\xb6\xf3\xb0,\xde\x91ZPH\x83\x90\x8ap\xd4B\xc8\x85$\x15\xe1\xb0\x85\x90\x0bP*\xc2A\x0b!\x17\xaeT\x84V\x0b!\x17\xbcT\x84\xfd\x16B.\x94\xa9\x08\xcd\x16B.\xb0\xa9\x08{-\x84\\\x98S\x11\x1a-\x84\xdc\x0cY\x11\xea\x96\x9c\x90\x0b\x81\xe6K\xad\x8e\x828\xca\xb6\x80\xa8&\x86\xdc\xa7-<\xaa\x89!\x17j\x0b\x96jb\xc8\x8d\xdaB\xa7\x9a\x18r\xa5\xb6@\xaa&\x86\xdc\xa9-\xac\xaa\x89!\x97j\x0b\xb2jb\xc8\xad\xdaB\xae\x9a\x18r\xad\xd6\x00\xact/\x9e\x92\x0f\xc7\xe6K\x8d\x88\xc8x\x02.8\x9b/\xb5&>\xe3\xf1\\\xa86_ju\xb4\xc6\xc3\xb9\xc0m\xbe\x14A\xb90n\xbe\xac\x824\x1e\xcc\x05u\xf3\xa5F\xc5u< \x17\xe2e\x92\xd7Q\x1e\x8f\xe7\x02\xbe\xba\n\x01\x01\x17\xfeU\xba/\x02<\x9e\x00\n\x06+\xc7\x80\xe0\xect9_\x16+\xe4\xc8\x8eQ\x90\xf2\x14D!l\xe3l\xc2\x03\xda\x01D\x98\xf3\xa5\x00\x0c\xc5\x9b\xb5\xa2D$|\xf49_je\x00\n\xe1\xf9X4s\xa3,\x1c\x85\xd0|d:_VA\x00\x87\xe7\xe3\xd4Zz\x11 \x18\xb5\xce\x97U@\nt\x02 \x86\xadk\x11RA\x11me\xb8<\xd4\xe4I\xa0\xf8v\xbe\xd4\xea\x10\x176\x1f\x1b\xedfM\x11\xa1\xf9\xd8\xb7i\x88\x88\x86\x8f\x84\x9b1&\x8b\xe0\x80A \x88\x8b\xf3\x81C\x00\x07\xa2d\xa2\xb3\xc2DP\xcc\x9cu\xd8,l\x86\xc6U>\x82\xaeZ\x91\x87\xab\x10 \x10O/Eh(\xba\xae\xdb \xa0\x81b\xed\x8a\xa6\x0e\xb7\x81\x81\x0d\x88\xbc\xb3a\x87\x08\xbe\x013\x02qxC$R2\x14\x957T\xe2\x0e\x06\xc4\xe8\x0d\x99hT\xe1#\xf6\xf9\xb2\x0e\xd79\x020r\xcf\xef\x97\x17s%t\x07\x9d,\xce\x7fn\xd6N\xec\xbb\xd7rd3\xf3\x8a\xb9\x11\x18\x8a%71\x17\xf0zn\x16sl \x14Cn\xe6.\xd0\xd5\xe4-\xe6W#(v\xdc\xcc^\x80\xe5\xacx6\xdc\xac_\x00\x8bY\\\xcc\xa8,\xa7Xq1A\x01%\xc3\x021C\nE\xb1\xe5\xe2\x86R+U\xe8 Q\\\x0d\xa1\x18r\x81\x05)\x81\x9c#\x81\xa1Xr\xa1\x07\xe1[y8\xd1\xe2\x7f\x05\x86b \x05'\x05E\x0bC\x88\x17;\xdc\x10\x1dI\x1b\xeb-]-C\x90\xecd+h\x92l\xd4\xcax$f\xcc.\x8fH\xb2a+\xe3\xa1\x981\xbbt\"\xc9\x06\xad\x8c\x07b\xc6\xec\xb2\x8a$\xb3Z\x19[b\xc6\xec\x92\x8b$\xeb\xb72\xee\x8b\x19\xb3\xcb1\x92\xcclel\x8a\x19\xb3K5\x92\xac\xd7\xca\xb8'f\xcc.\xe3H2\xa3\x95\xb1!f\xcc.\xf1\x88\xae$\xed 5\x82d\xdc\x96' Ie\x9d\xa4F\xc8\x98\xc3\x1d\xa5J%\xb41\x1f\xca\x99\xc3\x9d\xa5J5\xb41\x1f\xc8\x99\xc3\x1d\xa6JE\xb41\xb7\xe4\xcc\xe1NS\xa5*\xda\x98\xf7\xe5\xcc\xe1\x8eS\xa52\xda\x98\x9br\xe6p\xe7\xa9R\x1dm\xcc{r\xe6p\x07\xaaR!m\xcc\x0d9s\xb8\x13\x95\x81\x9e\x98w\x05 Y\xcb\xa2\xc3e[HW#\n\x8e\xd0\xd2\x00\x0c\x17\xa9\\\x8d\x94=\x174\x02\x8b\"8~$\xd3;\xd2*\xd8(\x12X\xb2\xc0\x01%\x91\x10\x92V\xc0\x84\x95\xc0\xb2\x19\x8e0\xcb\x0c\x92\x94\xb7\x94\xaf \xe4\xac\xd3MR\xceT\x84\x08,\xc9\xe0\x18\x94\xc9NIk\x00\"Q 9\x00\x07\xa5dJK\xae|&4\x05V\x89p\x94J%\xc1\x14\xda!\xadC\x10\xb6Ry\xb3\xf6~@\x06\x9c\xc0\xbaP\x18\xc7V\xa96i\x0d-\xcc\x05\x81-\x95\x98\x93\xf2'q\x82Z\x84i\xbc\x9a\x89B \xbddci\xae\x1a\x85\xb0z\xa9\x12Y/\xd9\xe0ZZ\x93 \xce^\xaa\x84\xdaK6\xda\x96\xd6$\x08\xbc\x97*\xb1\xf7\x92\x0d\xbf\xa55 \"\xf1\xa5J0\xbed\xe3qiM\x82\xd0|\xa9\x12\x9d/\xd9\x00]Z\x93 V_\xaa\x84\xebK6b\x97\xd6$\x08\xde\x97*\xf1\xfb\x92\x0d\xe1\xa55 \xa2\xf9\xa5J@\xbfdcziMpdBl\xf6\xb5\x8fA\x92\x9e\xab\x16\xef\x13\xbb\x83\n\xb5\x89{\xaf\xda\x02\x80\xd8NT\xa8M\xdc\x83\xd5V\x04\xc4\xfe\xa3Bm\xe2^\xac\xb6D 6,\x15j\x13\xf7d\xb55\x03\xb1\xc3\xa9P\x9b\xb87\xab-\"\x88-Q\x85\xda\xc4=ZmUA\xec\xa1*\xd4&\xee\xd5j\xcb\x0cb\xd3U\xa16q\xcfV[wT;l\xe2\xaajDQO\x15\x14\x01\xdbo\x05^\xca\x8c\xe3\x03\xed\xcc\x15\xd0zsN\xcc\xad\x810<\xf9\xad\xbb\x82\xa0\xd8\xbd\x133,\xcb\x19n\xfc\xc6^\x81^\x86X\"\\^\xcap\xe27\xfd\nl\xb1\xc7 \xe6U\x96\x93\xdc\xf8-AR'm\x0c)\x14-$\xb0mX\xd0\x14{\x80b\x9ee9\xc5\x0d\xdaT$%h\xe3I\xa1(\xce\xd0\xc6#\xe1\xb0\x91\xe0\x05\xbd,\x84\xe2 \x9f\xbc\xcb\x08\xaa\xcdI1\xcb\x1a\xc1\xb97\xbbsYjK\xca\x0d\xe2\xc4\xefjR:\x92\xf2#0\x0cW~\xdf\x93PQ\xbec\xd6\xa2\xc6\x02Cq\x85vF\xcbN!g\x08\xf1\x02\xb6M\xc96\xb5p$A\x14_hg\xb5 \xec\x8dd\xcd\x98\x97R\x9c\xa0]WB?s\xbc\x968x\x03ax\xf2\xdb\xb2\x05\x81\x9c\x1d\xcf \xda\xb2%U#\xe7G`h\xed\x01\x9b\xba\x04E\xb5\xaf\xdb\xc2\xb8\x86Q\xbc\xa1\x9d\xdf\x82\x88\xd8\xfc\x15s&A\xb4\xaf\x03\x9b\xc3\x14I\x8b+Q(\x8a3\xb4\x81L\xd1\xb4\x0d\xc74\x8c\x96\x1a\xd8e\xa6\x88\xa43$\x81a\xb8\xf2\xfb\xd0\xa5\x07-\x15b\x02\x12T\xf0\x05\xd2&\xc2\x08\xa18\xa6#\xe5.c,\x0e\x19\xc8#=R\xf6l\xe0\x00U\"\x8a!\xeaC@\xd2\x1a\xa8H\x02b/\n*\xca3CR\xe6Dh\x01\xb1\x16E\x19\xf5\x01#)s\xca 9\xf6\xa2\xb0\x839\x8f\xa4\xa0}y=\x928\xa4>\xc4$\xad\x84\x8a\x19x\xf6\xe2\xc0\x849\xf3\xa4\xd0\x92\x96\xaa\xc4\x91\nyP\xaa\xbd\xb3\x11\xb37_\x898t!\x8eVI\xeb`\x02\x18\xb8\xdf\xc1\xb1Ly\x16Kn\x0f9kQpC\x1d\xdcR\xb1\x85\xbc\x1aQ\xb4C\x9d\xf5j7\x059\x07\xf0\xd5\x88\xc3\x9f\xeax\x98\xbcw\xcb\x99\x0b\xe3!\xfa0\x99\x82\xae\xe4\x15\x89\x03\xa4\xf2\x00\x9a\xb4\x06\"L\xe2Y\x8b#&\xf2\xb4Z\xbb\x19\x889\x1e\xaaD\x18B-\xdb\xf9KY\x8bc*\xea0\x9c\x82 \xa4\xd5\x88\x83,\xf6\xfc\\{ML\xa8\xc5W&\x8e\xba\xe8Sw\xd2\xaa\xf8\xd8\x0b\xe8\x84\xc20\x8c9\xa9\xa7R\x93\xdc\x85\xc5q\x19{\xbcO\xa5\xae\xb6 K\x18\xa8Q\x87\x02Uj\x92\x07&\x92\xc8\xadu\x17\x99\xc0\x08*\x00\xf7\x94#[?\x08\xbe\xdf\x1a\xd9F]\xd4\xedY\xdc{j#\xbb\xd7\x94C\xc5f]\xcc\xbfY7\xb2\xfbu)\xffj\xdd\xc8\xb6\xeaR\xfe\xdd\xba\x91=\xa8K\xf9\x97\xebF\xf6\xb0\xa9\x97\x7f\xbbn\x84\xeb\x06k\x18-R\xae\xd5\xd8\xa0\xcb\xc1\xa6\xe3\x1e\x03\x820&\x8d\x01\x94\x80\xfb4\x04\xd0\x04\xb6h\x08\xa0\x0e<\xa0!\x80N\xf0\x90\x91\x05PL\xdc(&\xce\x06\x16N3\xb1\xc1\x00@\xd5\xc4=\x16\x05\x81L\x06\x04('\xee3\x18@;\xb1\xc5`\x00\xf5\xc4\x03\x06\x03\xe8'\x1e\xb2\xf2\x00\n\x9a7\n\x9a\x87i\x1a\xfa\x9c\x86\xe6\x06\x8b\x00U4\xefq0\x08e\xb2(@I\xf3>\x0b\x02\xb44\xb7X\x10\xa0\xa6\xf9\x80\x05\x01z\x9a\x0f9\x99\x00E\xa5\x8d\xa2\xd20\xe2\xb4\x94\x1aT1\xa8\xa2\xb4Gc \x88IA\x00\xe5\xa4}\n\x01h&\xb5(\x04\xa0\x96t@!\x00\x9d\xa4CZ\x0e@!\x1bF!\x93\x16?\xda@\x1ab\x89@\xbdm\x00\xbdq\x84\x10\x1d\xafL\x96\x0cP\xf0\x86W0K\x05(}\xc3+\x9d\xa5\x02\x0c\xb1\xe1\x0d\xc1R\x01\xc6\xd9\x00\xc6\xe1\x1a\x06Xl\xc5\xce\x125\x11<6\xae\xc0Y\x83!\x02-\xb6\x82\xa6\x12\x96\x10\xa2\x03\xa6\x17\x86\x0c\xb0\xd8\n\x98q\x18*\xc0b+`\x12b\xa8\x00\x8b\xad\x80y\x89\xa1\x02,\xb6\x82\xa6*\xb6a\xc0\xc7\x85l\xfd\xe0\xdb\xf1\xd2\x0bX\xdb\xf8\xb6Q\x95@\x06\xf0\xed^]\x0c\x95\x9aU)\xf0\x95'\xbb_\x15\x02\x9fU\xb2\xad\xaa\x10\xf8Z\x92=\xa8\n\x81\xaf-\xd9\xc3\xbaN\xa0\xa1\xb8j(\x18\xbf\xf8\xd8\xa0\x8a\xc1&\xe3\x1e\x8d\x81 &\x05\x01\x1a\x8f\xfb\x14\x02\xd0\x00\xb6(\x04\xa0\x06<\xa0\x10\x80.\xf0\x90\x96\x03PH\\+\x04\xec\x9b~l\xd0\xe5\xa0J\xe2\x1e\x03\x820&\x8d\x01\x94\x12\xf7i\x08\xa0\x95\xd8\xa2!\x80Z\xe2\x01\x0d\x01\xf4\x12\x0f\x19Y\x00\xc5\xcck\xc5\xc0\xf3\x8c?7\x18\x00\xa8\x9ay\x8fEA \x93\x01\x01\xca\x99\xf7\x19\x0c\xa0\x9d\xb9\xc5`\x00\xf5\xcc\x07\x0c\x06\xd0\xcf|\xc8\xca\x03((\xad\x15\x04\xc4)~j\x90\xa5\xa0j\xd2\x1e\x05\x81\x10&\x89\x00\x94\x92\xf6I\x00\xa0\x91\xd4\"\x01\x80:\xd2\x01 \x00t\x91\x0e)\x19\x00ElhEL\xe4n\xb3\x01\x143Qp\xa4\x0d\xaf-\x96\x0c\xa2\xe248i\xf5\xb4\x0d\xa7\xd4I\xab\xe7m8=OZ=q\xc3\xa9~\xd2\xea\x99\x1b\xde\x1al\x83\x00\x0b\xad\x98Q\xbf\"\x81\x87\xbc\x154 \xd0$\xa0\x85V\xc0\xc4\xc0\x90AT\xfc\\A\x13\x01\x16Z\xf1\xb3\x07M\x03Xh\xc5\xcf'4\x0d`\xa1\x15?\xc3\xd04\x80\x85V\xc0\x9c\xc34(\xb7P\xfb[-\xe9\xd7\nFv\xfer\xce2\x96\x01\xf2-d\xa9 \xe5BA \x84I\"\xc0\xc4\x0b \x00s/$\x00L\xbf\x90\x000\x03C\xc9\x00&a\x08\x84(\x0f\xc3A\x04\xa9\x18\x1e\x07\xc1L\x0e\x06&d8\x14\x98\x93\xe1P`Z\x86C\x81\x99\x19^.09C\xc2D\xf9\x19\x1e#H\xd1\x00@\x08g\xf280Q\xc3\xc3\xc0\\\x0d\x0f\x03\xd35<\x0c\xcc\xd8\x00\xb2\x81I\x1b\x12'\xcc\xdb\x00 A\xea\x06BB@\x13\x00\x82 \x1c\x00\x07\xe6p\x00\x1c\x98\xc6\x01p`&\x07\x92\x0fL\xe6\x90@8\x9f\xc3\"\x04)\x1d\x0e\x06\xa1L\x16\x05&vX\x10\x98\xdbaA`z\x87\x05\x81\x19\x1eN&0\xc9\xc3)\xaa=\xcf\x03kN1\xd5\x03\xeaS-\xdb\x03)Y)\xe1\x03)^)\xe7\x03\x19C)\xed\x03\x19H)\xf3\x03\x1aM-\xf9C\x92*\xe6\x7f8\x92cR@<1D\x0b\x91\xc2\xd3\x9aJ\"\x88#T\xcd\x05q\x84\xaa\xe9 \x8eP5#\xc4\xb7Q9)\xa4\xe5\xdfs\x8f\xe1\xbc\x10Q(H\x0d\x91\x08\x08`\x12\x000AD\x94\x839\"\xa2\x1cL\x13\x11\xe5`\xa6\x88\xac\x1fL\x165\x00Q\xbe\x88E\x08RF\x1c\x0cB\x99,\nL\x1c\xb1 0w\xc4\x82\xc0\xf4\x11\x0b\x023H\x9cL`\x12\x89@\x89\xf2H\x1cD\x90J\xe2q\x10\xcc\xe4``B\x89C\x819%\x0e\x05\xa6\x958\x14\x98Y\xe2\xe5\x02\x93K\x04L\x98_\xe21\x82\x14\x13\x00\x84p&\x8f\x03\x13M<\x0c\xcc5\xf100\xdd\xc4\xc3\xc0\x8c\x13 \x1b\x98t\"pp\xde\x89\x01\x08RO,\n\x02\x99\x0c\x08L@1\x180\x07\xc5`\xc04\x14\x83\x013Q\xac<`2\x8aUPk>\nT\x98ZJ\n\xd2\xa2RV\n\xd0\xacJb\nP\xb6Jn\n\xd0\xbfJz\n0\x89J\x86\n\xb2\x92R\x92\x8a T\xcbS\xb1\x04G\xa4\xaa8R\x80\x12\"\x04\xe7(\x85\x84\x15K\xa6\x98\xb3b\xc9\x14\xd3V,\x99b\xe6\x8ak\x9b(y\xa5\x90\xbdR\xf8&Kd\xeb\x9a_\xc5fPF\xab)\x14%\xb4\x08\x04\x040 \x00\x9c\xcej\xca\xe1lVS\x0e'\xb3\x9ar8\x97E\xd4\x0f\xa7\xb2|f\xad\xc0\"\x0c\x16!Jd\xb10\x08e\xb2(8\x8d\xe5\xf3\xb1=\x0b\xb2X\x10\x9c\xc4\xf2\xf9\x98\x9d\x05\x0d9\x99\xe0\x14V\x83\x12f\xb0X\x88(\x81\xc5\xe1 \x98\xc9\xc1\xe0\xf4\x15\x8b\x82\xb3W,\nN^\xb1(8w\xc5\xc9\x05\xa7\xae\x1a\x988s\xc5aD\x89+\x1e\x08\xe1L\x1e\x07\xa7\xad8\x18\x9c\xb5\xe2`p\xd2\x8a\x83\xc19+^68e\xd5\xe0\x04\x19+\x1a JX1(\x08d2 8]Ec\xe0l\x15\x8d\x81\x93U4\x06\xceU1\xf2\xc0\xa9*FA\n\x99*Hc\xaa\x89*@\x8f\x8ay*^\xb9ji*^\xe1jY*\xde\x08jI*\xde0j9*\xc0X\x8a)\xaa\x86R5C\xc5P\x1c\x95\xa0bi!R\x88\x12\x9c\xae\x94\xd2S\x0c\x9drv\x8a\xa1SNN1t\xca\xb9)\xb6}\xea\xa9)\xbf\x8c\xd4\xa0\xccT]&JL5\x00\xa8\xdcl\xca\xe1\xb4T]\x0cg\xa5\xeab8)U\x17\xc39\xa9\xa6n8%\xe5\xd3k\x04\x16`0\x00QB\xca\xe7\xc3\x7f\x16d2 8\x1d\xe5sq=\x8b\xb1\x18\x0c\x9c\x8c\xf2\xb9\x88\x9d\xc5\x0cYy\xe0TT\x0d\x12f\xa2\x18\x84(\x11\xc5\xc2 \x94\xc9\xa2\xe04\x14\x03\x82\xb3P\x0c\x08NB1 8\x07\xc5\xca\x04\xa7\xa0j\x948\x03\xc5BD (\x0e\x07\xc1L\x0e\x06\xa7\x9fX\x14\x9c}bQp\xf2\x89E\xc1\xb9'N.8\xf5T\xc3\x04\x99'\xaa\\\x94x\xa2A\x10\xc6\xa41p\xda\x89\x82\xc0Y'\n\x02'\x9d(\x08\x9cs\xa2e\x81SN\xb4b\xda3N\x80\xa2\x14\x13N\xbc\xf6\xd4\xf2M\x9cF\x95\xd2M\x9c\x92\x95\xb2M\x9c\xde\x95\x92M\x9c)\x94rM\xbcu\xd4RM5\x9db\xa6\x89\xc6\x1f\x93hb(\x01B\x88\x0e\x9a{T\xd2L4\x95j\x96\x89\xa6RM2\xd1T\xaa9&\xa6]\xa7\xa5\x98\x04\xd9$\\\x85SP6\xa9)\x14e\x93\x08\x04\x040 \x00\x9cMj\xca\xe1lRS\x0eg\x93\x9ar8\x9bD\xd4\x0fg\x930\x13\xd7\xb3\x08\x83E\x88\xb2I,\x0cB\x99,\n\xce&a>\x16gA\x16\x0b\x82\xb3I\x98\x8f\xb2Y\xd0\x90\x93 \xce&5(a6\x89\x85\x88\xb2I\x1c\x0e\x82\x99\x1c\x0c\xce&\xb1(8\x9b\xc4\xa2\xe0l\x12\x8b\x82\xb3I\x9c\\p6\xa9\x81\x89\xb3I\x1cF\x94M\xe2\x81\x10\xce\xe4qp6\x89\x83\xc1\xd9$\x0e\x06g\x938\x18\x9cM\xe2e\x83\xb3I\x0dN\x90M\xa2\x01\xa2l\x12\x83\x82@&\x03\x82\xb3I4\x06\xce&\xd1\x188\x9bDc\xe0l\x12#\x0f\x9cMb\x14\xa4\x90M\x824\xa6\x9aM\x02\xf4\xa8\x98M\xe2\x95\xab\x96M\xe2\x15\xae\x96M\xe2\x8d\xa0\x96M\xe2\x0d\xa3\x96M\x02\x8c\xa5\x98Mj(U\xb3I\x0c\xc5Q\xd9$\x96\x16\"\x85(\xc1\xe9J)\x9b\xc4\xd0)g\x93\x18:\xe5l\x12C\xa7\x9cMb\xdb\xa7\x9eM\xc2eP\x06e\x93\xea2Q6\xa9\x01@\xe5fS\x0eg\x93\xeab8\x9bT\x17\xc3\xd9\xa4\xba\x18\xce&5u\xc3\xd9$L\xaf\x03X\x80\xc1\x00D\xd9$\xcc\x07\xf9,\xc8d@p6 s\xf1;\x8b\xb1\x18\x0c\x9cM\xc2\\l\xceb\x86\xac{U\x1fl?w\x15\x1fV\x00w\x17\x1f\xd4\x00w\x19\x1fR\x01w\x1b\x1f\xd2\x01w\x1d\x1fR\x02w\x1f\x1f\xd2\x02w!\x1fT\x03}\xe7\x1e\xd6\x01}\xe9\x1eT\x00}\xeb\x1ej=}\xed\x1ej:}\xef\x1ej7}\xf1\x1ej4}\xf3\xbelq\xfb\xc1\xcb\x033f\x90\x17UD\xa3\x1d\x05\x01\x07<\x12\x01\x8ey$\x00\x1c\xf6H\x008\xf2\x91\x00p\xf0\xa3d\x00\xc7?\xf6\x00\xabh\x08\xe4q\xe0(\xc8\xc1\xc0\x81\x90C\x81c!\x87\x02\x87C\x0e\x05\x8e\x88\xbc\\\xe0\xa0H\xc0\xe4\xe3\"\x00\x04\x87F\x1e\x07\x8e\x8e<\x0c\x1c y\x188F\xf20p\x98\x04d\x03GJ\x02\xd72XBHp\xbc\x04\x80\xe0\x90 \xe0\xc0Q\x13\xc0\x81\x03'\x80\x03\xc7NH>p\xf8$\x80\xb2\x11\x94\x83\x81\x83(\x8b\x02\xc7Q\x16\x04\x0e\xa5,\x08\x1cMY\x108\xa0r2)l5\xaa\x9ef\x0f\xc8\x83W\xc2\x81\x96@\xc0\xe3l\x03\x80\x87\xd9\xa6\x1c\x1ee\x9brx\x90m\xca\xe11\x96\xa8\x1f\x1eb\xe9\xfd[\xe1\x08\xcb\xc2\xe0\x01\x96A\xc1\xe3+\x03\x82\x87W\x06\x04\x8f\xae\x0c\x08\x1e\\Y\x99\xe0\xb1\xd5gF\x1b\xd1\xd0\xca\xe1\xe0\x91\x95\x85\xc1\x03+\x8b\x82\xc7U\x16\x05\x0f\xab,\n\x1eU9\xb9\xe0A\xd5g\x07\x18\xd1\x98\xca\x03\xe1!\x95\xc3\xc1#*\x07\x83\x07T\x0e\x06\x8f\xa7\x1c\x0c\x1eNy\xd9\xe0\xd1\xd4\xa7\xc6\x1a\xd1`\xca\xa0\xe0\xb1\x94\x06\xc1C)\x8d\x81GR\x1a\x03\x0f\xa44\x06\x1eG\x19y\x14\x86Q\xc1\x88\x89\xeb\xe1F4b\x12\x08x\xc4l\x00\xf0\x88\xd9\x94\xc3#fS\x0e\x8f\x98M9\x96\xdc\xca\x05\xfajr\xc1\xa8\x10\xa6\x95C\xdb7\x12Kf\xae\x1d?\xb4\xf2\x92}I5\xe3\xf3\x80\x0e)\xda\xa5\x9a\x8b\x9c0\xb6S/\x0c\xce\xb1\x17 -]\xc5\xe1z\xb9\xa2 \xd6\x81\x8b\xe2\xac\x98\xa3\xa9K\x18\xc7\x0b51M\x10\x06Ha\xe9s\x00d\xce\xd6Q'\x88\x0d\x91)H\x0e\x91\xe5\xc2+H\xaf\xb0p+\x9b\xe4\x9f\xd4\"\x9eJ\xa5A<\x95B{\xc4\xa2\xe3\x93D\xe7\xa9TD\xe7\xa9\n\xd1)\x8a\xb4D\xd9\xd8[\x06\xe7YT\xc0\x94\xc7dy>Q2\x00\x87\x048(HQ\xac`\xed\x03#E\xed9bA\x18\x08(\x0b\x83)\xc5Q\x90G\xc1\xfbR\\y\x83DF\xbf]D\xffh aaZ-G#`a0$\x0c\x0d\xaa,\x9c\x7f!~\x11\xc6\xfe\xb9cG^jc\xef\x11\xb1P\xccBq\xb8E\xb1c'\x1cr\xcd\"\xd7Q\x04#\x03\x16y\xd2p\x98\x12\xce\xa1\xd4\x12\x00-n\x0c\x00\x16\xb7\x07\x00+\x0c*\xcan\xda\xb8\x98Z;9\xb0\xa4\x99\x1cV\xd2J\x0e\xab\xd0HA{8\xb7\x92\xb5\xe7\x08\x1f\xe4\xb1\x92\xf6pX`8]h\x833\xe6\xc1\n\xd9n>\xab/\xc2 \x8b\xf5\x1e\xd19\x1fR/4\x8b\xa5K\xd6s\x80\x94\x0f\xa1\x17\x06Ql\xf2\xc5=\xa2\xb8\x07\x05\xea\x0b\x93@\x18@\x90\xbe\xe8S\x00\x88\x85E\"\xf8\xe2\x01Q\xdc\x1d\x0d\x01\x06C\x12Q\x00\xda{\xc3\x81\xd5\xbd\x16$\"\xf5g\x9d\xae\xc5\x02\x005a\x04\x9a\x01d\x07\x1a\x01\x99\x82F\x08\xacA\x83`\x83\xb0\x18\xd0&\x0c\x080\x0b\x8d\x10X\x86\x01\x15\x18\x05\xeb(\x8cU\x99\xc9|\xa1\xc5\xfcV\x83q\xb4\xa4\xbd\xfc6s\xf9m\xd6\xf2\x15\x8c\xe5\xb7\xdb\xcaW0\x95\xdff)_\xc1P\xfe\xb1v\x12\x98\x04\x0bM\x82[M\xc2\xd1\x92&\xc1m&\xc1m&\xc1\n&\xc1\xed&\xc1\n&\xc1m&\xc1\n&\xc1\x80I(\x8c\x8f\xecd\x1d\xa3C\xd3O\xb2\xce\x03b\xb2r\n\xd8\x17\x01\x03;\x8e\xc3-\x01\xedq<\xbd\xc0EAZLi\xc5\xcf\xe7Fs\"+m?\xcf\x98\xf86\xc6\x9acG\xe5\xe8\xb0\xb1c\xcf\x0e\xd2\xf3\xe69\x8dO\xe3u\xe0\xd8):\xe4\xc9\x81<5\x82\xce\x83p\x1b\xdb\xd1$\xdc\xa0x\x91\x7f\x9c\xcfs]\x14Lr\xa9\xea\x87\x08c/J\xbcDa\xcc9\xc0\xeaH\x94\xd5\xcb`[4L\xa3EJ\xae\xe3\xbd'\xea\xb9\x1e\x88UU\x9d\x11\x9c\xaem\x05u+\x0c\xf1\x95\xc2|u\x13\xf8\xc7X\xc0W1\x80\xff<\xfa\xf7\x8fT\xbf\xff\xdd\xb4/Q4VW4>F\xd1XE\xd1\xf8y\x14\x8d\x8fT4~\x8a\xa2)\x96U\xb9\xe6\x84Aj{\x01\x8a\x0f\xf5\xa3\xfdy\xe2\xc4!\xc64E\xb1h\xa6\xb7\x12\xecu\x1aN\xc8\x9d\x96\xec\x01\xa3\xddX\xcb\x1e\xf2t\x0c\x0cS\xb0\x86Y{\xe7<\x00bj\xec\xd9\x1buIARPX\x8d9\xf4\x94\x03\x15\x04V\x18M\xcaV\xf8'7\x02\xa0\x84\xdb\xe0\x1f\xdb\x04\xb1\xb4\xf8di\x01JXZ\x0cHK\x8b\x82\xbd\xe8\x10\x85\x89\x97'\x02\x17\xde\x0e\xb9\xff\xd7\xf3\xa30N\xed \x9d\xfcQ\x97\xd8\xf3$\xc4\xeb\x14\x11\x85\x19\xe9y\x8c\x9c\xf4G#\xdau\x88\xbf?\xd1Eg\xc4\xdf\x9f\x14\xcc}\xe0\x04\xcc\x1c\xe7\xcf\x94QAH\x15\x9f\xcc$\xf7\xff\x83\x04\x17\xc9\x88\xff\\\x19)\x01\xb6\x89\x16\x84\xb1o\xb3#u\xf6\x88F\x16\xa370\xa0\xd3\xb0(\xa6#\xc9(>>'X\x0b\xc5\x07J\"\xb9\xe0\x90\x8a\x13\x8d\x85e\xd2)\x88\xa7\xe0m\x8d\xcclt!\x14\x19\nCx\x89\xfd#\x05\x96\xca\xa6jfp\xe6\xe6e\xc3\xbcl\x14f\xa3\xcd\xed\x04\x1d6(N=\xc7\xc6e:;{\xc6\xef\x91l4\xdfsY\xa8\xef\xb9.\xe6\x80i\x18\xb1\xc04\x8c\xb8\xaaS\x9f\xab9\x0fp\x14\x0c~\x00\x9a\x91\xf9\x8ezK\x00\xb4\xb01\x00\x16n\x0f$B\xd1$\x856)8q\xd9P^o\x92vr`q39\xa8\xa0\x95\"\xbb\x1d\xed\xf8e{\xf01\xed\xe1\xc0\xe2\xf6pPA{\xf8\xfa\xcb\xf6PX\xd7\xf3\x0fad;^\xba?7\xb8\xa23\xf6\x01\xf41\xfa\xecq\xf1\xfdym\x8b\xe6\x0f^\x99\x15/f\x90\x92w\xa7kXI\x07ez\xf1\x82IK9'\x86\xbc\xd6J\xfc\xae\xc5\x13\xdaN\xeamP\x03\x19M\x94d\x0c\xd7\xa9\\\xc8p\xcd\xec\x9e-q\xb8=\xe3\x9e@\x82\xe7\xcf\xbf\xa3\xbe\x14\xea\x15\x18|\x95-\x03\xf3S\x11\x9dn\xfe\x9f\x1a\xa8\xab\xa9\xedXQ\x9b\nKC\x95\xf5\x9e\x89Py\xb3\xda@y\x1b\xd9\x16\x18\xdf\xa7\x05\xcd\x06{^+\xa4w\x16R\x98 _\x7f\xb6\xef\xe1/\xe3p{\xd0\xfc\xf0Q\x0b\x93\x9dVd\x0f\xfd0LW^\xb0<_\xc6\xf6>ql\x8c\xea\xb6\xcdm\xe7aa;H\xdbx\x897\xf7p\xd6\xf2r\xc1+)\xa24\x93of\xe5?a;E\xdf~\xd4\x7f\x9a\x88\x9e\x03\x1a\xe5Xu\xba=A\xa7:\x02z:\xe4\xac\xa5\x16^\xdb`\xd7\x89\xe1.\x9b\xeb$\xb7\xc0\x8fFW\xb7HM\x11O\x81:\xcaaI\xc4\xac;\xe6Yu\xc7\x00#\x0d\xdb\xf1\x12\xfd\x7f\xc5A\xbc\xe0\x18\x1f\xe1\xd1OEI\x9d\xa5\x80\x88L \xf2\x9a\xb2\xb4\xcdwz\x90\xeb\xf4\x84\x06o\xf7\x1f\xc0\x17\xb3\x87L0\x1dzAZ\x8fH\xce:N\xc2\xf8\xbc|H#\x93\x95\xed\x86[\x0d\x02N\xea\xc5b\x8c\xb0\x9d\x89\x05\x99\xdd\xc6\xb8\xd3\xb5\x92\x8e\xb3\x9e{\x8e6G\x8f\x1e\x8a\x7f\xec\x1a\x03\xeb\xac;\xea\x9fu\xfb\xfd3\xe3\xa7\xc9\x91x\xb1\x88\xe7\xf6\"\xcd\x04\x0d\x83\x14\x05\xe9\xf9_\xfe\xd2\xf8\x7f\xb8\xd3\n\xe4\xb9\xde\xd1;\xc6 \xdauz\xd1\xaeC\x9e\xf7\xeb\xfd4Q\x86\xe5\x07;c\xdb\xf5\xd6\xc9\xb9\x17\xacP\xec\xa5\x93f\xd2\xe4\xd6\xd1\x93\"\xf3\x99\xe7e\xf4I\x11A\x1a\xba\xfeb\xb2ByN'\xff\xf91\xcf\x98\xee\xce5\xf9\x9cu\x846Ui$\x1a\xcd\xfd\xbb\xd0\xeb\x99\x18Ej_\x10d\xcc\x97\x9a\x1dx\xbe\x9d\xa23\xc1s\xa8/\x11\xa5\xc2\xd0\x89=\xc4IM\xdb\xec(\xd0\n\xa6\xa5~\xd4\xf4Ce\x17\x9d-2\xea\"\x83-\xea\xd5E=\xb6\xc8\xac\x8bL\xb6\xa8_\x17\xf5\xd9\"\xab.\xb2\xd8\xa2\xf1x\\\x17\x8e\xc7c\xa0\x98*\xe7\x00\xbe\xbdk\xa45\xfa\xc3\xfe\xc8\x1c\xf4\x87,\xaa\xf4\xf2\x1aY\xfe\xce\xc3\xbc\xd4\xb3q\x0d\xe3\xb3\x95\x8f\xda:HP\xc3(\xff\x8d\x86\x04(IQf\xa0h\xaf\x15\x11T\xdeM:!\xb3\xaf,\xc2Ej\xb05>\x10\xbf\x9e\x1b\xecB\xa2\xa4k6\xae \xda\x95\x01\xd6\x01c{G`\xcd#\xb0\xfd#\xb0\xd6\x11\xd8\x01\xa3\x17\xe8`\x7fA\x8f\xbd$\xd5b\x94 \xa1q\x08\xc4\x9a{\xf1\x1c\x99\xaf\xd6'94I\xf7\x18i\xe9>B\xc5\xd1*\xa1%\x8b\xed\xa5N\xf4sDm7u\x8f\xdbo\"9&(B\xb1\x9d\x86q\xce\x94\xe0at-A\xfb=\x7f\xd9\xf1\xfc\xe5\x81\x18\xd2\x9b\x9cG\xfe\xab\xeb%\x11\xb6\xf7\xe7s\x1c:\x0f\x02\x1d\x06\x0fI\xc7>\x94\xe7\xe1Mk\x88\\\x17\x9a\x02\xf8\x01k\"-\x95\xd5\x06\x0d\xb6\x0c\xa2\x9c\xf5\x0b\xa9\xc6\x03\xc7Y,\x9e_\xaamlG\x11\x8a\x05\n\xec\x0f\xf4hW\x1a\xf0\\\xef\xe4\x9b&\xa5\x0b\x9d\xeb\x9d^VH\xcd\xf0\xdecVRN\xcf\xf3p7\x01\x9f\xd2\x12\x84Qn\x1a-\xb5\x97Z\x82\x9cL\xeaCe4\x82ymH\xcdO\xb4\x05F;\xf2Y\xf6;%I\x18{\x993V\x99\x18\xaa\xcc\xf5\xe2\xa2\x9a2%:\xa98\x12%N\x88\xd7~0\x01\x9f\n\xc5\x7f\xba\xd8\xe4 \xe0F,\xeai\xfe\x8b\xe6\xa5\xc8O\xaaG\x95E\x0c=\x0b\x97\xb2\x7f\x8c\xea\x9f \x134\x8aB\xc4^\xc2E\x81\xbddR\x9b,\xef\xb9F\xb4\xeb$!\xf6\xdc\"\x1c\xb3\xc6g\x03\xebld\x9cu\xcd\x9f\x84*)\x9d\xb8\x99\xf5\xa9\x1b\x1e:\x1bj\x93\xca$\x8e\x18\xf5I'\xd4;V\xb4\x9b\xe4\xa5\x0b\xdb\xf7\xf0\xfe<\xb1\x83DKP\xec-&U\x1f\x9e\xf7\x0d\xcb\x10\xf2\xee\x06\xa1\xe6\xa2\xc4\xe9$\x91\x1d\x1cH\x03d\xfa>7j\xd5\x9f\x1b\x93\xe2?BV\x9dd\xb3\x84\x82\xa2\\\x85}^\xab\xfdD\xc2\xca\xb71u\xde\xa9_5t[\xcc\x04}]\x9f\xa8HK\xf4\xd1\xdc \x8eWVd\xc7\xb6\x8fR\x14\xff\xf1G6\x15\x90B\xf5\xa2]\xcd\xdf\x8av\x1d\x9db\xef\x87A\x98o\x10P\x82\x0ft]V\xdb\xc6C[\xad\x9a\x06\x1f\x0e\xfc\xca&\x9b\x04\xcch7\xa9\x0e>\x90\xfe`\xa9{\xb9\xc5\xdb\xc3\x82\xedq \xdc\xcd\xc8j(\xba\x02\xd1\x07\xfe\xaa\xeb:\xb3\x10\xe9\xb3\xc3a\xb3\x921\x99E\x8c1\xe6\x16;\x00\x04\x14\xad\xd3M\xedy\x1e8\xa0\xf8\xe9#\xceQ\x0eOV]\xfc\x9c\x8dC\x87\xc6\xdb\xfa\xfc\x90s\x04\xa3\xf3\x85\x17'\xa9\x16.\xf2\xf0\x83a\xdb\xd1;\xfa\x11\xbc\xbaebs\xd5/:9\xe7S\xa7\xf3*\xd7Y\xfc\"\xb3\xbe\xad\x999L\x1eSY\xfa\x8bj\xb5\xd9kV\x9b\x99\x9f\x00kd \x9b\xf3\xfb\x8f\x9a\xa5\xbf\x00\x13=U\x111\xb4.c{\x0f6\xab\xeb%Z\x18\xa1\xa0\x19n\x92\xb5\xef\xdb\xf1\xfe \x1a\xe13\xef\x16h\xa8fQL\x8a\x95'V\xd6\x1a\x95s\xd0\xc4\xf7\x82*\x82\xb5\xb2\xdf A\xd9\x1b\x83\xa3\x9f\xe0~c\x00\xcb\x7f\x83\xe980\xe6(\xd9\xcf\x8e\x01w\xb0=G\xf8\xe9\x1d\xef\xa4\xa9\xfe\xa8f\x95\x922C79,\x0fu\xbd\x1eG\xb9\xc30'\xcc\x1aJ\x02\x95\xfd\x91\x9a\xa1$\x9d[\xc0j\xd5g'J\x95Q\xadi\xeds4\xae\xe8C\x9a\x8f\xd2U\xe8\xca\xe6\xed\\\xcf\xf5\xd6\xe5H'f\xd0A\x16\xa8e\xe3\x05w\x03\x8c\x99\\L\xba\x0b\xe5\xd3ONC\xf5\x04\x9d\xed+\xf2v.\x16\x0b\xc5F\x86\xf9\xd2,3\x80\xe7\xb6\xf5\x97\x92$\xb2\xd3\xd5\x11\xd0?\xfepQ\x14#\xc7N\x11\xa5\xccAD\xf4\xacS{[n~\xbdq\x08\xbdc\x16\xab\x19\xfa\xb7'w\xd0\xc96\x8c]m\x1e#\xfb\xe1<\xffW\xb31\x96\x85c\xaa\xf1R\xb9\x19N\xec\xe8\x0f\x07\xa3h\xc7l\x81\xff\x07\x9a\xaf\x17\xed\xd8\xd3\x9d\xcal\xd8\xcd:,\xbc\xa6\xab\xd4p\xa6\x8b*r\xc8\x16\n\xb1\x17\xe5\xebR\x82\x81\xa9:\xe4<\xdfH\xf3?4\xe9\x90\xd1\xbeZp\xc7\xc8\xad\x18\xe0\xf7\xea\x00\x9f\x98\x95\x9e=\xb2\xe7\xa4\xab\xf6\xad\x19\x19\xcb\xb0m\xc4,5\xe0\xf8\xaab\x19\x85IJ\xbc\x8f\"3p\x7f\xec8c}\xc2\xae\x80\x87\xe6YO\xef\x9f\x19\xfd\xbe0\\\xa1\xb8\n\xa7\x1drN(\xea:\x81\x19(\xb3\n\x1f\xf5p\xf9h9\xd7\xac&\x17\x8em\x98\xbc&{V\xef\xcc\x18\x18g\xfd\x91\x82&\xd7j\x8a,\xaa:\x9e\x17(\xb1\x02\x9b\xd3\xd4\xa8\xc2\xdeE\x18\xa5\x88\x95kl\"\x13\xf1\x9a\xec\x8f\xcf\x06\xbd\xec\xff\xad\x8a,\xd8\xaa\xe92\xaf\xec$v\xa0\xd8j\x9cN\xd4\xa8B\x0dK\xc4:\xe6\xc0\xb0\x17\x0b^\x9d\xe3\xe1\x991\xb4\xcez\x96B\x17_\"5\xc7,\xaa:\x9e\x17(\xb1\x02\x9b\xd3\xd4\xa8\xc2>\xb2Sg\xc5\x88e\xe9\xc8tz\x9c\"G\xfaY\xaf7<3\xc6\n\x8a\xcc\xd9*\xa9\xb2\xa8\xec\x14n\xa0\xd4J\x8cNS\xa7J\x05\x19WF\xae\xb1n\xf4\x00\xb7\xcc\xa6\x1cc\xa4\xe6\x96\x19W%e\x16u\x9d\xc0\x0c\x94Y\x85\xcfi\xaaT\xe1\x1f\xe6\xb1^\xc2H\xa6\xbb\x96m\x0fym\x9agc\xfd\xcc\x18\x0c\xdb\x95Y\xf2U\xd2gQ\xdbi\xfc@\xc1\x15Y\x9d\xa6U\x95*\x88\xb0\xbe>\x15:\x98\xd0\xa2\xa2y\xf6\x07\xce\x14\x8d{\xc0\xab\xa5\xc4\x95(i\xb9\xa8\xefd\x96\x07Hzun\xa7\xe9ZR\x0b!\xa0\xb3B>J\xb8\xa4\x9c\x1aY\xa7[\xfe\xa0\xa5^\x8aQk\xaef\xe1\xe14kD\xb3\xd6*\x9eh^\x90Eq\xd4\xd6b\x1eI\xe7{T:\xb5oU%\xd8{M\n\xd2\x1d\xb9.b\xbc*\xb5\xe7\xa7\xad\x82\xa8\x9a\x8bex\xdd,b\xe3\x1b\xd8\xf3N\xedy\x07{l\x1a\x8d<\x89N\xf1b\x16,\xc7\xaf\xfe\x8a\xfa\xd8\\8\xb7bbv\xf2\x99\xcf\x96\xf5X[C\\\x85\x89\xecb\xdf\xbe`5\xa8WeF\xb4\xa3\xceK\x11)l\xc1\xfe\x1e\xbb\xbdW\x08Q\xfa\xf8\x81\xc9\x90\x81\xbeI\xae\xbe\xb5r\xaf\x1aLJhh\x97\xa28\xb0\xb1\xe6\x86N\"\x87\xe6^\xfdGy\x13\x8a\xb5+\xbd\xcdX\xbb\xa8U\xa5\xb5\x8f7\xa8\xa4)\xdc\x11\x12ik\x84h\xb2ALf\x14h\xd3\xf3\xb6 :\xa6\x01\x020%\x7f\xc4fR\x9f\x9e\xb3\x15\xaa\x939\x0fC\x13\xa3\x1dr\xd6)\xaa\xe0\xf50\x98\xbb\x81\xfc\x9d^\x0ci\xa7;O\x03r\x1c$\xc7\xe5>7.\xcfCw\xaf\xe5;\xb0u,r\xd2\x98\xf7?s \x82\x97\x9ez\x86\\/=P'\x16\xf4V\xfab#\x83T\x9a\"M'A\x189i\xb5\x9bkB\xb3W\x8c\x92(\x0c\x12\x94h^\x100f\x96\"\xb9\xee\xc8\x95[\x82\x9eXN\xa3\xa7u\xc6\xaa\x96,\xec\xf8#I\xedt\x9d\x80{\x0fOeJ<\\\x07n\xe8\xac}\x140\xb9]\xe3\xd8d\xf6X\xcf\xfeH\xaa\xce\xcf>1\x9f\x0f\xcd\xcf\x93UY\xef\xbe\x8e\xfc\xc9\xf36\xb78o\xf5?\xd1Zb<\xfd\xe3\x8f\xc2g\\o\xd3\xf5\xed\xf8\xc1\x0d\xb7\x01\xec]2\xca\x18\x05.\x8a\x91;+9\x80\x9b\x7fE\xa0\x93\xbf\xb9\xcd\xa1\x8f\xc75C-\x10\x9a\x91\xa7\x1c\xa8d\x9e\xd1\xef\xf7\xd1q\x9a\xe1\xf6\x9dT\x1aW\xa9\x85\x9dEThY\xc5t\xa2\x038\xad|g\xc9\xedg\x90\xdc>\x1c%\xf0h<_\xe8\xfd\x89\xe2\xbd'\x15\x89\x9a\xd6\x14\xa9\xf3\xe7h\x13}\xd8qd\xcc\x0d\xddy\x82d\xec\xce\x95\n1'T\xba:N\xd3\x8b\xc5BxbN\xb8\xd3\xaaeSW\xf3\x1b\x0e\xed|\xe4+\x0e\xdd\x93G!\xa9\x0ej6gl\x9b\xfd\xfa\x96\xb7TP\x15F1w\xa6\x0b\xee\xfb\xcc\x95\xef<\xa2)69\xb3\x9f\xca=\xce\xecwx\xe7\x93{\x98C\xab\xe0c\xb5\x8fV(H\n\xf1\xb3\xa0\x83z@\xfd\xa24\x06\xd5/\x89ae;\xd6\x8er\xcd\x15'\x18\x1at\xf3\x96\x86\x16\xban\xb1\xdc\xcf\xba\xddAr.y\xe5-W\xc5{\xc0\x9d\xd0\x05\xd6~2\xf4\xdf\xbb\xbe\xe7\xc4a\xfe\x80|iN\xe9!\xbb\xeaHN_g\xce\xe8\x0c\xd8\x13\xd6Y\x1f\xc8\xdcQ+\xd7y\x89\xf8\xc4S\xee)\xe5\xca\x138tJZj\xe8\x8ezc\x138\xed@n2\xf2\xc6&\x0d\xf8\xd1K=\x8c\xbd\xb5\xdf\xf9\x82\xe6g\xc4\x84/\xe9\x97L\xc4P\xb6\xd9\xd4\xeb\xc5\xed\x90\xdb\xdb+r \xc4+\x88\x88eT\x8f\\\xf3\x9bE6\x83\xdaG \x8ej\x83\xa7\x95\x98s\x1a\x96\xe0P\x13\x07\x93\x8bX'n\x9e\xbe^8i\xa7XQ\xba\xbf+\x1dLzr\x13\xbe\xe7\x92\xa7\x1a-\xb5\xe2\xb8\xb5U,,N\x88D[\x94T/`\xeat\x93a\xd6\xcb\xcf\xe6T\xa0\xe0\x85\xb9\xd5l\xd2\xf8p\xe5\xb3\xe5\x89J\xe2x\x7fq\xd1\"\x9bW\x9a1\xc1x\x8e\xa37\x91\xed\xbc_'\xa9\xb7\xd8W\xe3L\x8d}\xaa7\xfei\xce\xd0\xa2\xf4\xfaQ\xdbH.\xa6,3uD\x8f\xd1\x81\x1e\x03'\xf2,\xfdEs\x18\xb5\xce\xd9\x95\x8c\xa5\xa7O\xf3\x13\xa6g\xc2\x13\xa8T\xb1\xc0\x1fO\xe8\x11\x12-\xcc\xd1\"\x8c\x91 aI\xb5\x93\x8e\x9a\x88Dm5\xdb\x11G\xc8\xb5\xbcG\x01\x07r\xeb \xec<\x0e\xd3\xfc\x87\x8e\x91t\xbc`\xe1\x05^\x8a:\xd94n\xc7g\xc4%\xcf\xc9\xf1\x14\xcd{\x12\xb8\x04x\xb1\xf7i\x9d\x15\xff/\x0e\xbe\xe6\xf3b\x1aF\xe5\x9e\x039;\x0c\xd8{\xb1y\xa6\xa9\xf6\xf3S.\xa0\xff\xfb\xbf*\xf2\x07\xb4_\xc4\xb6\x8f\x92N\xd5\xb0C\x1a\x02\xf7\xa0\xf3R\xf4\xa3\x91\xae\xe3\x80t\x1a\xea\xf9\xbf\xff\xfd_\xcf\xccO\x14\xec\xe7&\xa5N\x93W\xc3\x9c\x02I7\xfb%\x0eq\xa2\xd9\x8e\x83\xa2\xb4\xda\xac)\x87dj\xf3g\x19#\x14<\x85g~\xf5\x83\xe0ED,\xdd!\xf2!K\xcc\xb1\x17<\xa0\xf8`\xe9/\x9a\x17\x86P\xba\x15 H1\xcbc\xb5\x9d\x95y8\xba\xab\xda\xdd \xcc\x93 u\xb8\xe1\x05\xdc\x92\xb2\x06\x9d\x81O\xcf3\xa7\x83\xce\xfaU\xb7\xba\x8b\xea\xeb\xdf$\xc7\xcf6(N\xbc0\xd0\xa2\xd8^\xfa\xf6\x81\xdc\xaa\xa8\x83K\xe4\xb3\xe9?\x9a\xea\x8f?|\x94$\xf6\x12==\x82:u\xde#\xe5&\x06\xfcn\x0f\xf9@\xd8\xcc\\\xa0E>q\xd8\xb4\xcb\xc5\xf4\x82\xc6\xfe\xdd\xf56\xc4\x8bE-\xcbY)\x9dmTb\xde\xc9\x171Mt\\m\x97\xba(\xfbS\x8b\xdb\x8fv\x9d~\x11\xf6\xb2\x8bN\xba\x9ay\x1a\xb4\x9d\xb5&\xaf'\xf5\xc8\x83\x9a\xec\x19A\x93?6h&\xfcH\xbc\x8c\xed\xbd|\x05\x9as\x89\xec\x18\x05\xe9s_e8a\n\x9d\xa7A\xf6WK|\xd1\xc5\xad~\xa9\x19\x8e\xee\x9f\xae\x97\xd8s\x8c\xdc\x7fU\xef\x9b\x08\xc2\xcc\xe5p\xb8En=[uM\x8e\x90y?\x00s\xb9\xc9b\x9aer\xd7\x9fx\x04\xdf&\xc7\x0e\x1c\x84\xd9Sa\x8b\x81> \x97_e\x01i\x12\xb9\n\x0b\x0e|u\xf6:]\x85\xb1\xf7\x88\xe8\xeb\xd8\x13z\xb4\xab\xb8T\x07=\xe5\xa7?y\xe1$\xf5\x16\x89\x86\x05\x0e\xed4\xff\xb6\x0cm>p/\x9e\xa1\xdf,\x0f\x0b\x0fc\xf8\xc8e\x86-w\xaa\x80\xfe\xd9\x1f\x8fu\xd4\x03\x92[T9\xc7Q\xcb\xb8D\xa7\x0d\x9f\xe4\x8aZ\xc0\xb8\xe8\xff\xc7\x0fN4\x83r\x1f\xbcxU\x15\xd7\xb13\xadv\xb8\x03\xe2\x0c\x07l\x0b\x18\xe4\xa4\xf9_F\xdd\x95Y\xec\"\xf3\x98\xb5\x83\xb9\x18P\x0e\x0e\xca\xa2\xd3\\3\x0f\x95s\xce}\x98\xb8\xf7Y\xf6B~w\x8ef\xcc\xa8V\x06-\x0f\x80\x13}E\xcf\xfe\xb4\x89-\xbc\xf5\x0bO*\x05\xeb\xa1\x9e\xfd\xa1X\xcf\xd7i\x1a\x06\xec\xdb}\xc2u\x9a\x0d.\xbc\x02\x0bx\xd7\x0b66\xf6\xdc\x03\xbfVIV\xf6\x03\xeat\xfbI\xc7\x98\xc0O\xdb\x0e\x03\xffu\x81\xb83Fe\xd0{\xc4\xc4\x9b\xa7\x18\xac\xea\x1e:\x7f\xbc\xa7\xcc\xd9\xca\x13\xbb\x8ba\xf6\xa7\xb3\x8e\xf1\x8f\xae\x9d\xda\xe7\x9eo/\xd1\xcbd\xb3\xfcy\xe7\xe3\xc9\xdcN\xd0\xa0\x7f\xf6\xdb\xaf7\xbdo\xfb\x8b\xfe\xfc\xcbn\xed<\xea\x9e\xfd\xeb\x9d\xee\\\x86\x9bw\xa6k\xba{\xcb\x9c\xed\xad\x8d\xe3;\x9b\xd9\xfdt;{5~t}\xc7\xbb\xfe\xf5[\xf4\xedw\xf7\xd5\xdc\\\x8e\xaf\xef\xa7\xcb\xd9\xab\xe9\xbe\xf8{\xfd\xf3\xf5\xab\xe9\xf2\xfar\xb7\xfd\xfa\xfb]x\xfd\xe6v|\xfd\xa0\xeff\xfb\xbe>\xfb\xb8\\\xde\xec\xfb\xfd\x9b\x8f\xf8\xfe\xdd\xfd\xb59\xfb\xa0\xafg\xf7_\xfb\xef\xee\x9d\xed\xfb\xfa\xe7\x07\xf3\xfd\xab\xe9\xf6\xfaU\x7f\x7f\xb3\xef\xefo\xee\x97\xeb\xd9\xbd\xb3\xcf0\xb3\x0f\xf9s\xeb\xe6\x1e'\xef>\xce\xd6\xef?N\xfb\xd7\x97\xb3\xf5\xfb\xcb\x9b\xfbw\x1fj|\x9aa\x9b\x9f\x1f\xcc\xf7\x1f\xa6\xdb\xf9+\xfd\xf1\xdd\xfd\xc3\xf6}\xfe\xdf\xe5\xe3\xd7}V\x9f\x93\xbe\xbb\xbf\xee\xdd\xd4?\x17u\xbc\xfb\x90\xd5\xf1\x90=\xdb\xe5|\xef\x97\xeb\x9b\xc7\xa9U\xfd\xfc\xfe\xa3\xd3\xbf\xbe\xbc\x98\xcd>N\x97\xb3\x8f\xaf\x93\xb2m\xe9l\xdf\xdf\xdd\\\xbe\x1e\\{\xa3\x9f\x7f+\xf4\xf4\xf3O\x9d<\xaf[\x9c\xfc*b\xceN\x10j1\x8a\x90\x9d\x92\xf3ZqS\x9f{#\x84<\xa3\xd9SK|f0\x95(\xa8Y\xb9G\x11\xb2\xe3,Z(F\xa4\xfcEm\xecC\xe6w\xc0\xdd\xff\xe9\xafq\xeaE\x18\xfd\xabJ\xfeZ\xd4\xc15\x0b\xf4V\x80\xd1\x9f\xde]\xe9\xbd\x07.\x89\xd8\xcbg\xd8\xa3\xee\x94 8\x19#\x9d\xbd\xe0\xa5\x94\xdd}\xea\x99\xa4\xfch\xe1?\xb3%\xf5/\xc8\xb7=\xfc\xaf3A\xe9\xc2\xc3HX\x18\xd9I\xb2\x0dcW\x08H\x90\x1d;+aq\xb6\x1e\xa3\x0b\xb3'v\x8clRE:\x91l\xa2\x1dh\xc4\x0c\x8f\xc4\x86\xa1;\xce\xfe\xb4\x0d\x8f\x8b\x85\x9a\x15\xff\xf3\xd5\xd5\xbct&\xdf\x8a\x91\x1b\xbb\xeaO\xd2V\xb4\x81\xea\xd6\xb4\x01\xcbV\xb5\xc1\xf2\xd6\x81\xa0\xaa\x95\x7f\xca0\x00d\x8ar6\x07C\x7fq6\xd6_\x00Y\xb6:\xa5k\xba?jF\xb4\xcbF]0\xe5K\x96\xff\xbb\xa7\xbf8\x1b\xb5\xf2\xeb\xc9\xd9U\xc5\xff6\xf5\x17g\x96\xfe\xe2l\xd8\xcaQ\xeb\xb7HX\x95\xff\xbb\xaf\xbf8\x1b\xb4\xf2kaWs#3k\xff\xab\xd1g\xd1(8\x1403\x07y|\xbc\xd9\x9a\xeaQ\xb7\xe8\xf9\xd5\x137l\x92\x01u\xcb\xbb(\x8e:-\x00\xccMUK\x8aw|\x1d\xf8\xd0\x17\xb8\x1fU\x0f\x11\xce:\xe6\x0f%\x13[r\xe4d\xc2\x9c\xd5\x88QN\"P\xc0\xb3\x9f\xd9rV\xc8y\x98\x87\xbb\x03\x19\xf5\x97+Y`mD\xeez\x08\x1eW*\xd5\xb3?peOx\xfd\x86\x80aD\x1dD\xef\xeb:\xf1\xd1\x8d\xc2\x0e\xe4y\xb9J\xf3,HU\x8bP\xba\xae\x16\x85\x98L\xaag\xff\xaa\x9b\xca/\xa5\xa5t?\xe7\x8a\xfa{\xb7xC\x8f\xf0\x8dJt.K#\xf7\xcb\xf27/Tn7 \xcf\x91\x8f\xca\xedn2\x0ef\xcf|\xd0[Q\x8c\xff\xa1Q\xf6G\xf4\xb2$=_\x02T i!\x97\x08\"\xde\xf1\x90\xf7\x83\xfa\xa7\x13U\xd7\xfe\xca_\x85WFKk;\xcf\x7fB.e0^Y\xf9\x1a\xf8/\xc0\"\xd8Y\xd9q\x82\xd2_\xd6\xe9B\x1b\x9d\xbd0_%\x9be'\xb7\xe0/?\x18\xfa\x0f\x9d\xc2\x82\xbf\xfc0\xfa\xa1\xb3\xf1\xd0\xf6\"\xdc\xfd\xf2\x83\xd9\x19v\x0c\xbd3\xfa\xa1\xb3\xf3q\x90\xfc\xf2\xc3*M\xa3\xf3\x97/\xb7\xdbmwkv\xc3x\xf9\xb2\xa7\xebzV\xc7\x0f/\xcc\xab\x17\xe6\xab\xc8NW\x9d\x85\x87\xf1/?\xbc\xe8\x99}\xa3?\xec_\xfd\x90?\xd0\xe25F\xbf\xfc\x806(\x08]\xf7\x87\x8e\xfb\xcb\x0f\xb3A\xd74\xcd\x8ea\xbd3;\x86\xd1\x1d\x0c\x86\xd8\xc8\x9eh\xd9\xbf\xfdN\xaf\xd3{W<\xce\xc40;\xa3\xac\xec\xf1\x87\x97EMY\xa5/\xcc\xab\xbf\xfc\xd4\xb1\xf4\x17\xcdZ\x93\xd6\xa8\xeb\xd98\\j\xeb\x1d\xf35\x9d \xf9\xa2U\xea\x1e\x8b^\x1dV\xaa^\x03,`\xd8\xe9f\xbaw\xe30\x02\xb8K\x19\x8an\xc1\x8c~\x12V\xe5\x87\xae\x8d\xa9z\xea-m\xae!\xd4\xfe63)\x16\xbf\x9a\xe5\xdcP\x7f\xf3\xc3\xe2\x86\xe2\x937\xf8\xf9\x05JuY\xafm\x81\"\xc8\x07\xe8\xd1\xaeS\x9c\x9c\x92\xbe\x04Z\x8ckUj\xb5\xb1&;\x06g\xf5\xc90\x82O*J\xd8\xd2\x17U\x80{6U\x9e\x9c\x9fk\x95V\xb8\xd2\xba\xe9K>#f\x81=h\x16\xd8O8\x9a\x04\xd5\xff\x94\xd7\xce\xd5\xb1J\xaf8/':*[:\x16\xe96'\x9d\xffQmM\xa7\xeb\xe00AZ\xfe\xf8\x88\x94\xfc\xf3e\x9bd\xc2\xad\xc8\x0f\x83\xf7\xd8c?\x03\xf2\x0d^\x8d\xe8\\\x1eN\xb4Ir\x82[\xf8\xa1+O\xef\x98\xfa\x91g\xea\x85\xb5t\xba\xc4}\xd9$\xb2\x99\x1b\x11<&u\xabc\xb9\xb6\x9e\xfd\x11\x9d\xcc\xe5(\xff\x9e\xba\xcc\x8dK\xf5w\x0f\xe5\xcc\xb44\\.1b\x8fh\xc1\x81\xd7@\x14x\x95\xa6\xccF\xa9N\xd7D\xbe\xc2\xebo\xb8\xe1]\xf8*`u\xe4\xa9\x08\xe8C\x0e$\x03~**\xcf\xf1\x8cu\x17-\x81\xf3=\xe5s\x8eN\x0bc/\xcf\xa6\xe9/\xb2(a\"*\x10\x1b\xaa\xeb\x84\x18\xdbQ\x82\\\xf1\xa9#\x81P\xf9c1\xe7\xf2\xac\x1et\x02\x8d\xdd\xc0\x12\\\xa1=*\xd2k\x0f\xe0\xaa`\xb0\xd7o\x82\xc1\xec\xe7:\x1a\xcc\x83\xea~\xa7\xd7'c\xbd,\x8c3\xf4\xce\xe0\xdd\xa8k\x8d;\xc3n\xdf\xe8\x18f\xd7\x18v\x8c\x1e\xd6\xfa]k\xd4\xe9w\xad\xf1;C\xef\x18#<\xd0\x06m\xf1\x1b\xb7W\x90\x05/\x90\x16\xef\xd7~\xa4\xa5a\xfe60`\xe1\";\x01\xc43\x10\xbfz\x8a:;\xa8u\xfb\\g\x03-\\\xdc\x87\x97\x1f\xe3$\xa0\xd5\xbb\xa5\x8aG+/H\x0f\xc4!\xbb\xfcG\xf6cc\x04T \xab\xd1\x1d!\x7f\xc2\x9f\xe3\xab\x86\xff\xae\x81\xfcN~\x14\x08\xf8\x1eo9<\xaa\x04od\xb85\x84\x1c\x9e\xb8D\x95\xad\xfb\x99\xc3F\xe5\xc9\xb2\x02\x9a\xd4W0ub\xf2\x97\xbdR\x9a\x97M\xc2\xbdz\xc1)1{\xeb\xfc\x0b\x0f`\x9a,\x96b\"7Qh\"\x7f\xef5\xcd\x9e \xd1\x9e\xe5-\x86'\x85Ap\xb2\xe8Y\xdf\x13.\x0f\"\x06:w\xbc\x86S\xd5\x13_\xa3\x0d\xf0;\xe9\xcd\xde\x1c\x9f\xe3\xde_\xce\x92[\xac\x07\x90\xddEo\xdd\xf6\x02\x0e\x0b05\xa8\x0d\x99\xf9\xeaQ\xda\x17*F\xc0e\x97\xfa\x82\xc3Q\x1f\x1c\x02\xde\xc6\xa7>\xd8\xb0\xdf\xeej\x91\xb5\xc5F\xc3\xe3\x98\xd1Q \xf1\xda\x90\xa3\xb8\xe4\xa7\x83\x18&\xad#\x12\xc7\xa6|\x90\x08\x0cLM\x0b\xa3\xfa\nVf\xab\xe6\x15;\x96B\x85\xf3pw\x90\x1e\xdai`T\xc2\x19\x8ca\x95\xcd\xcc\xbe\xcc\xa7\xae\xe4\x08\xb7\xe6Ni\xd5L\xba\xd0\x0b\x87,\xf1\xa4\xce\xf4Ty\xcf\xb4\xf4\xec\x0f\xc4\xac\xa9U\xdb\xdaq\xe0\x05K\x903\xb7|\xab^\xdcR\xddn\x17\x1fV\xe4_Q\x97\x8du\x7f\xcf\xfe)\xa7\xe5\xee<\xb6\x1d\xa4\xe5\xabZjF\x84\xceBEq\x18i\x81\xed\xb3\x87\xb8\xa9\x15I#\x1d@\x9c\xfbx\xa5\x18\xcb\x06\x10(X\xfb\xb2\x0b\x8f9(\x0b\xb1\xed\xf4 \x9e4\xba \x8a7(\x16\\\x1f{\xb6\x0bYd%\xa2\xebW\xf47f@\x06\x9dU\xbf[\x9d%\xaf\xee\x1e\x94\x01E\x8fUcE\x92\xdas\x8c:i\xf55\x16So\x01\xba\"\x9b\xd5\xd2eQ \xf8\x85\xdb u\x1f\x82H\x82i\xc4\x9dNy\xe5\xf0\xeb\xfaKWik\xa3\xdb\xe1^\x0eE\x1c|\x87I\xbbN\xe8G\xeb\xack\xadc\\\x0f\xcd\xfc\x91~\x10_\x1cC\x07\xf5E\x9c\xaa\x9d\x88&l\xce\xf5\x978\x9c\xdbX+\xea\xfa\x8f\xbe%*\x90\xb4\xd6S9\x00\x92g\x9c{\xd50$~=S\xf5\xaa/\xc0\xdd\xcb1C\xe0\xed\xb9\x03@/\xc3\xa12nZ\xb5>?\xaf~\xe0\x99\x94\xc3]\x9a\x9fLJ\xe3\xac?\xd4\xbcX\xafg?\xd6,`\xc0\xf8tu\"\xa5O\xbe\xe2\xab\xd8\x84\x82ZU\xde\xefN2IZ\x12dp\xa7|j\xda\xac\xec\\\x80B\xaa7\xb7)\xe9E\xa2\x91fl\xe9Q{\x0f\x03\xe2\xe6 \xf0V\x9f\x92m\xfe\xea\xc6\x9c\xed\x99\xact\xd5vz\x8cI%\x13\xd7b\xf2c\xf2\x8a\xeb\xb7\x9e\xda\xa9Bf\xae\xaa\xbe\x8c\x93\xb0/\x93\xe0\xce\x02\xc1\x1f\xd52\xf9\x17>Ix\xd2\x97\xcdJ\x86B\xfa?\xfe\xc8grI\xc4\xd1\xd7O\x99\x14\x99\n\xba1\xfa\xef\xb5\x17W\xaf\xc7\x11\x0d\x12\"*\xf86+\x1c\xe0i\x03\xfasCM\xca\xac\xe2\xf6\x97R\xf0\xf2e\xd0V1\n\x0e\xd8o\xae6\xb2\xa0]\x8a\x82\xc4\x0b\x99l2\x81\xf0\x14^\x9csLW\xe5?\xccBT&|m\xfe\x13+\x8d\x91+V\x81\x1f\xa5\xfb?66^\xa3?\xf8\xc4\xb5ID\x03\xe5\xda\x91\x8b\x0e\xb8\x17\x0cJ\xb9\x97\x93=\x15L\x0e\x8f\xe2\xd0\xad\xee%5\xc1<\xffjH\x8c\x80\xab\xee\xfc\xa6^\x1aFs\x9b\xfeb\x0dpE\xa7|s\x0eDZ\xfd\x17~\xcd`\x89\xb1O\xdb%{r\xbe\x07\x14\x98:U\x95\xe7\x06\xd9!U%WB\x8eb\xf9^3\xbbIR\x1c\xb9\x90\xaf_\xd8cD\x95\x84E\xca\x06\xd8\xcc\xe2#\xd1\xca\n\xf5+J\xd61\xae_\xd3\xf7d\xad\xe7m5\x9b\xd6\x9b\x93\xea \x01\xca/r\xa2\xc0e\xaevfO\xd8{\x9dy)\n\\\xf56\xb4\xcc$\xa5\x86\xf8seV\x7f\xb8\x80\xbeJV]h\x12\xdf*\x91\x8b\xd3-f!\xed\xf4\xb3WOw\xeb 8\x99\x0e\xa8\xe3p\xa76\xa9\xbcgG\xcf\x9aJ\x1d\x82\xf6\xd2<\xc0\x92\xbf\x19\xf2\x18\xa1\x8a\xa9\x9f\x93\xa3\xd7\xc8\xd1\x9b\x94\xff!\x94#t\x0b\xea\x04$\xb0\xee(\xcf\x0dR\xbf\x1f#<\xf5\xb4\xbc\xd5$\x89D\xc88\xae_\x1e\xf2\x90\x9c\xe1$\xae\xd5Q\x8b\xa8\xb2qG\x0e:^\xb0\x08\xeb;\x1d\xc0K(\xb3\xf2\xce*\xbf\xee\xd7\xf5m/`\x97urt\x87=\xc4\n\xc0\xb1w\xc6?\x8c\x80g\xc5z\x89\xe0w\xda+\x0f\x0b\x19\x0d\xa0\x02\xf6\xf3\xc8\xc5C\x13z\xd8\x87\x1eZ\xc7\xbf9\xa0\xa0,\xdenU\xad\x8f\x8b\xdbb\xea\xe9C\xdd:\xf2\xa4.\xf4\xee\xf7\\\x0e\x9b\xd5\xeeQ\x1b\x11-\xb6\x80\xae\xc9\x16\xb5\xd2\xef\xbc3\x16\x83\xb1\x03xay7\x9f\xdc\x9f\x02\x98u\xe7v\x824\xe0\xe80\xa9\x0b\x93:\xdbZ\xcf#G)Qh\xcc.\x9bF5\x07O{w/\xc1\x95\xff2\xaad\xc1`\xb5\x1c\xae(\xd6\xef\xe4\xcb\x9d{\xc5\xc0\xc2.\x8d\x93u\xc4\x1dd\xb5\x86\xcc\x01\xb7\xa1;\xea\x8f!\xf3\x92\x92\xe7\xaf\xdbST\x057T\xd9\xebt\xa5\xcd\xd3\xe0i\x01\x0e\xbd6\x7f\x8e\x17U\xc8\xa5,\xeeK\xbba\x80\x0e\xf2\x14rN\xf8\xa4\xa6)M\xd4\xcf\x1a\xbb\x912w\x88\xd7\x040)\xd0&4\xd1\x9a\x97\xe3\x01\x9c\xc0\xe4\xa1\xc1\xdeo(\xd2\x89-\xa7\xe6d\xdc\xe1M)a\x1dl8E3#v\xcd\xcbc\xffV\xb4\x13\x1d\xb7bH\xeb\x8f\x8e\xf3\xc1\xbe\x94\xae\xf5&\x9a\x84\xa0\x08\xa3\xd9\x1b\x90R)Q\x1c\x87q\xc2\x0e\xa8\xd4\x06\x18?Y=y0M\x9c0BIg\xd5{\xfa\x94\x9f\xb3\xd2\\\xb4\x90\x1f\x8b(\x1b\xaa1V\xe9\xc1\x0eXu$\xe2\x92\x9acc\xf4)b^\x80E>\xe5C\xd2\xea\xfaZ\xebd/\xf9&\x15-v\xf9;\xdb\nx\xd3\x0b$e\x8fl\x08\xdf=\x7f\x92]\x05U&\xc4\x8b\x9f\xc0M/\x86\xae\x882\x9f>P\x9e\xb4\x06S\x90\x8c\xd6a\x8f\xba\xac\xa44P+\xb99t\xc7\xb1\xf0\xb7\x03x9\xad\xbc\x971\x02\xeej\x8c~\x9a4\xaf\xc6\x02\xdfAV\x00\x0d\x9e\xd6hH\x0d\xfav\xe0\xff\xb4,\x94\x9d\xee\xf2kaq\xb7\no\x9aTZ\xe5\x1d\xf9J\xef\xff\xbc\xfc\xdb_;I\xb8\x8e\x1d4\xb3\xa3\xc8\x0b\x96\x9f\xee\xde\xfd\xd20\xea:I\xd2\xf5\xed\xe8o/\xff\x7f\x01\x00\x00\xff\xffPK\x07\x08_;\x94/\xe8Y\x00\x00\xa8X\x02\x00PK\x03\x04\x14\x00\x08\x00\x08\x00\x00\x00!(\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0c\x00 \x00swagger.yamlUT\x05\x00\x01\x80Cm8\xec\xfd\xfb{\xdb\xb6\x928\x8c\xff\x9e\xbfb\xd6\x9f\xefs\xec\x9c:\xf2%\xceu7\xfb]\xe7\xd6\xa6M\x1a\x9f\xc4\xe9\xd9\xdd\xf3\xf6#C$$\xa1\xa6\x00\x86\x00m+}\xfb\xbf\xbf\x0f\x00\x92\"%\xe2F\xc9\x8e\xd3rv\x9f\x934\"\x80\xc1`07\x0c\x06\xfc\x12M&8{\n\xdb\x87\x83\xfd\xed;\x84\x8e\xd9\xd3;\x00\x82\x88\x04?\x85\xb7\xcf\xdf\xc1\xc7\x97?\xc1=x\x8b'(\x9a\xc3\x87W\x1fO\x01\xd1\x18&\x1fN^\xc0\xf7H\xe0K4\x87\x98E\xfc\x0e@\x8cy\x94\x91T\x10F\x9f\xc2\xf6\xb1\xfe\x98P\x81\xb31\x8a0\x8cY\x06\\ \x81\xe1s\x8e3\x82\xf9.$\xbaW\x91!\xcaQ$\x1b\xf2\xed;\x00\x178\xe3\xaa\x93\x83\xc1\xfe`\xffN\x8a\xc4\x94K\xac\xf6(\x8b\xf1\xb0\xc4\x11`\x82\x85\xfe\xcb\xd2\xd8o\xe8\x98e3$\xff\x03\xd0\x88\xe5\x02\xc4\x14C\xc4(\xc5\x91\xc01\xc8n\x8av<\x9f\xcdP6\x7f\n\xa7S\x0ci\xc6R\x9c \x829\xb0\xb1\xb9\x8d@\x13^\x8e\x0bp\x0f\xbeG\x04\xa9\xc9\x16\xff\x96f,\xce#\xdc\xf8\x06\xa5iB\"\x85\xd2\xdeo\x9c\xd1\xe2\xa7\x0c\xf3\x94Q^\xffv\xfbp\x7f\x7f{\xf1\x9fKS\xfb\x99\xc5XQ1\xe7\xb5Ox4\xc53To\x04 \xe6)~\nl\xf4\x1b\x8eD\xe3\x87\xc5,\x9b\x0d\xa0\x8e\xe4\xb0\\\x83\xa5Ol\xcd%\x8cr\x92\xc4\xc3&\x85\xea\xa0\xb1\xe2\"#t\xd2\xf2A\x94\x10L\xc5\x90\xa2\x19\xee\xd6\x9e\xcdfDtj:a\x9d\x9auF\x95\xe3\xec\x02g\xdd\xa7j\\ G\xdb\xa5=T\x07\xfb\xd2\x928x, 3F\xc99\xce:\xb5\x05\xc0Wh\x96JQt\x81\x12\x12#\xc1\xb2{\x92b-\xdf\xa6\x19\x13,b\x89\x99s\xc19E\xf5\xc5aj\xfa\xc9\x03_\xa8\xe3\xfc\xc8\xf0\xc9(a\xd1\xf9\xa6\x069\xd87|\x83\xd2\x8dM\xa4m\x08\x8a\xc5%\xcb\x0c\xd3pv_u=A\x04\xdd;l\xdb\xcaSD)N\xba\xc9\x91\x84p\x81\xe9\x10\xc5\xf1\xda\x8c\xb7}\xf0\xe4pp\xf0\xf0\xf1\xe0\xc1\xc3\xc1\xc1\xd3\xc3\x87\x0f\x1f<\xdc\x0e\xdd\x8e\x0d\x11~\x8ai\x8c\xb3\x19\xa1\xa2l\xb4&\x86\xfb\x83\x83\x07\x83\xb6%bbj\xdax\x0d\x8cf,\xc3@jJ\x93\xd1\x125n\xc1\xadE\xb7\x94\xe0\xdef\xe2jHh\x8c\xaf6\xc5\xa2\xdb\x8c\xb6-\x8b\x84,\x8d\x14'`n\xc4&x4\x11\xa5O\xf7\xf6\xf6\x07\xea\xff\x14W\x95\xf7\xc9o\x13V\x14_\x89\xe1\xedD-\x92\xf6\x05\xe5\xf9\xadB\n\xa5\xe9mBG\xed\xbd\x0c\xf3<\x11\xb7\x8aL\xf8\x82\xc4\x98F\xf86\xe1$u\n\xe38\xdb\x90#\xd7\xb0nG8\x9a\xde?\x04L#\x16\xe3\x18\x8a\x11\xdcS\xd2\xd6\xdaA\x8c\xd3\xf3\x07GQ\x8e~\x9b\x9c\x7f\xc1\xe8\xe1\x97tr\xfe\xf9\xfeCA\x7f\xbb\x8c\xbf\\\x1c\xa1qt?>4\x85\x82\xaca\x03\xf0\xd5\xba~\x1a\xd7\x11v\x02_\xe2\x81W\xf8 \\!(\xe84^\xdbpv\x03\xceIA7\xf5n\xd3F\xb0\x1bj\xce\xc9\x82\xd7\x84\xc1\xcf8\xf32B\xc0\xb5|%\xb8\x0d2/J\xc3\x06\xa8m\xd8*\xbd'\xba\x80\xde\x13- l\xa2\xbd'\xda{\xa2\xcb\xe0^ \x08Y\x0d\xd8\xe0\x8a\xf4\x9eh\xef\x89z`\xd5{\xa2aH\xf5\x9e\xa8\x17^\xbd'\xda{\xa2.mw\xab\xff\xc7\xb3g\xd5\xc0\xddr\xed\xb6\xcbd\xbb\xdf\xb5:\xf8\xa3\xe8\xc2\x94o\x87\xb4\xd0\x00$\xff\x1a\xe1L B\x0bMR|\xbe\xe9\xd4\xbb\x14eh\x86\x05\xce\x1a\x1f\x13\xfa\x14R$\xa6\xb5\xf9\xaa{\x01M\\`\x99\x0c\xcf\x15\xf2+\xdfd\xf8sN2\x1c?\x05\x91\xe5\xf5Ty\xc3&\xba\xba\xb7\x12\x86\xef\x94!X\xa3%OqD\xc6$ZE\xae\xcf\x17\xf4\xf0e|C\x19\xfd)M \xfd)\x8d[\xc4oR\x05y\x18\x11^D\x00oB\x80\xbf\xc9\xe0\xb5\xd6%8\xd7\xbc\x04\xf7J@\xc8j\xc0\x06W\xa4?\xa5\xe9Oi<\xb0\xeaOi\xc2\x90\xeaOi\xbc\xf0\xeaOi\xfaS\x1a\x97\xb6\xbbU\xa74}\xbe`\x05\xce\xc9\x82\xd7\x84\xc1\xcf8\xf32B\xc0\xb5|%\xb8\x0d2/J\xc3\x06\xa8\xdd\xe7\x0b\xf6\x9eh\x01\xbd'z\xfd\xdb\xad\x0e\xbd'j\x00\xef\xd5\x80\x0d\xaeH\xef\x89\xf6\x9e\xa8\x07V\xbd'\x1a\x86T\xef\x89z\xe1\xd5{\xa2\xbd'\xea\xd2v\xb7\xca\x13\xed\xf3\x05\xdb\xda\xaf\xe5\xd9\xf46qo\x13\x1b\xc1{5`\x83+\xd2\xe7\x0b.C\x9f/\xf85\x06\xee\xf3\x05\x1b\xe0V\x14\x1a:\xf8\x12\xfd\x16\xe78\xfd\xbc\x7f\x91\x1f~\x99\x9cO\xce\x8f\x9e\xe01\xda\xa7\x9f/\xbf\xd0\x18\xd1\xcf\x0ffG\xd1\xa3\x14\xdd\xcf\x8fP\xfa\xe5hr\x98=\x99\xf0\xf4\xf3\xe4\xe1\xe4I\xc4\xef\x9f?\x89\xf2q\xebX\x17L\x10:\x19\xa6\xec\xd2t0\x176\xa5\xed\x83}\x93eT\x05\x8d\xd2\x8c\xb0\x8c\x88\x8d\x90pi\xbcn\xa2k{IvygZ/ \x87>\xddz\xddt\xeb\x15i[K\xbb\xee\xa5\xad\x82^\xda\xd6\xc0c6\xbd\xb4\xbd>i\xbby\x03\xf5yy\xdf\xa2\xb0M)\x13\x80.\x10I\xd0(Y\xc8\xa1\xaeb^\\I\xe1\x8e\xf8\xb4E\xb4\xc78\xcdp\x84\xc4\x92\xd0[\x92\xf8\xa7W0\x9a+?\xa9\xf8}E\xba\xd7\xde}\xb9\xd3\x82\xdc\x07,2\x82/0\xa0\xfa\x131\x90sB'@\x04W}\x0f\x8a\x96\xd7\xa8\x15\x163XA\xf1\xf4j\xf9g\x87:Xa\x9e\x9a:x\xfe\xe2\xf9\xab\xc3\xfdW\x8f_\x1e=|\xf4\xe0\xf1\xf3'\x0f\x8f_=x\xfc\xf8\xfe\xf3GO\x0e\x1f?x|\xf8\xe4\xe1\xf1\x8b\xfd\x87\xaf\x1e\x1c\x1c\xdd\x7fp\xf4d\xff\xf5\xf3\x97/\x8e_\x1d>8~t\xf8\xfc\xfe\x8b\x17\x8f\x1e>\xbfSb\x10\xaaM\xaet\x89w\xa1\xdf\xc0\xb9 Rz-MkC\xaa\xa3\xddk\xb6\xee+\xbbPz\xb9\xff\xf8\xc1\xc1\xfd\xc7/\x9f\x1c\xdc\x7f\xf2\xe4\xfe\x93\x83'\x87O\x1e\xbc~}\xf4|\xff\xf8\xc9\xc1\xfe\xa3\xd7\x07\xaf\x0f_\xbc|\xb5\xff\xf2\xfe\xa3\xe3\xc7\x8f^\xbc\xda\x7fxt\xf4\xea\xf0\xe0\xd1\x8b\xe7\xaf\xef??z\xf2\xf0\xc1\xc3e\xfc\xacJ\xcd\x10O\xa80\xbc\xff\xf0\xf1\xd2\x8f\xa2%\xb8iUZv\x955\xe3-\xd5\xea\xc1\xa1=\xc1\x15;v\x88\xb51\xb6\x1e\x15\xaduZ3A\xce\xa0\xb8U\xdc\xa2\x19\xcb\xa93\xab\xecv\xc5\xd5cL\xd9\xcc\xfe\x89\xd7\xdcK\xa8\xd8\x8f\x0bt\xde\xf64\xce\x02\\\xe4\xd2\xd0e\xec\xed\x07\xad\xcau\x86g\xdd\xdeUrD\xac\x9cK\xe2^\x0c\x8f\x98\x98\x17!|\x8c&\x80w\xaf>\xbdx\xf3\x8f\x97\xfb\x87c\xfe\xf2$C\x8f\xdf\x89\xd1\x07>\x7f~p\xf9h\xf4\xf9\xf4\xdd\x83\x07\xff\xcc\x0f\xee?\xfe\xf2\x8f\xd1\xeb\xe8\x9fWG\xdf\xbdx=?~3\xc1\x0f\xfe\xf9\xf3\xc9\xf8\xa77\xf9\xc5\x97\xe7\xff\xfb\xf0\xc9\xbb\xf9\xe7\x1f\xf8\xe7\x97\x8f?\x1e\xbc\xb9$\xaf\xd2\xef\xc8\xa7\xd1\xc3_>\xc6\"I'\xff\xf3\xcc0\xb4\xc3&\xf4 $x\x11\x13\xca\xae\xac\xfc\xe2EO\xa8\xd3\x94q\x91\xa1\x88\xd1\xbd\x93|\xf4\x13\x9e\x7f\xc4Qz\xf8\xe0\xe1\xb9)\xfd\x13\xb4\x93\x91o\x1c\x8f\xe3\x8b/\xfbG\xbfL\xc5O?N\x1f\x1f\xbfx\xf1\xcb\x97\xe4\xcdct\xca\xf8\xf7\xf3}r\xfe\xfa\xbf\x7fz\xf3\xcb\x0f\xff\xb8\xff\xdbO\xef2\xc6\x7f0\x89\xaa(\x92\x9bo\xa8\x95\x88kE|\x99\xce|\xe8\xc3\xf1\xe7\xdc|\xcc\x0f\x1b\x18Ig\x00mT\xc1%\xcc\xaa\xe0\x8c\xb8N\x10\x1f^\"*-\xd2.\xcd\x9b\x07Y\xfb\x06OA\x0e\x92\xf3M\x0c\xf1\xf0\xfe\x83\xa3\xb6\x11\\\x0f\xe7\xad\xa5\xe0\xad\x9b\xdcg\x8b[\x05\x89\x07\x01\xc0gw\xb6\xf6bwb\xde\x94\xdeK\xe1\xcd\xbc*\xc3\xecUz\x8d\xdbw\xf1\xf0M\x16/0a\x94E\xd3\xc6\xb3\x95wZ\xd0j\xf9L:D\xf8\x02S\xc17\xea\xb6\xa8\x87\xa4j\xd4\xd1~\xcb\x0cs\x8e&x\xa0\xc7\xae\xfdlX\xa8\x06\xf2K\xca\xac\xee\x7f\xe9 \x00\xcf\xa3) \x0e\xdb\xcdq\x9eqL\xe3m\xb8\x9c\x92hZH\x08\x0e\xa4\xf9\xc6\x99t4\xc6,I\xd8\xa5\xf4\xe40\x8dSF\xa8x\n\xdb\xdf\xbf:U\xab\xf6\xffo\xebs =\\\x0cb\x8a\x9aL\x8cQ4\x85\x19\x8b\xf3\x04C\xcc\xa2|\xa6\xd0\x93\xfe!\xbb,\xb1\x1d@\xc2\xd8\xb9z\x83\xf4\xeajX\xfc\xdb,\x06B%2\x8d\xee\"\x96i\x0f*\x96\xc8\xe9p\xc7=\x1e\x9f\xef\xc5,\xe2{<\xc5\x11\xc4$\xc3\x91`\x0d\x9a\xd7\xfc8\x89m\xd0\nq\x15\xe6\xdc\xdc\nIf\xd6.\x9d\xeeYS\xb6\xf1\xb9\x89\xca\x7fk\xe2\xf4\xacH\x15t\x85\xa5\xf6\x1f\xa6WW\x17\xdb\xed\xf4\x08\xea\xc3\x8bp)\x9a`\x13]N\xd0\x04\xafzj\x9a\xa2\x84\n\xcf\x18\x8a#\xc4U\xca\x1a\x99P\x1c\x83\xb8\xba\xd32t\xeb\x87 \x18 \x18\xe7IR\x7f\xf9>b\x94\xe73\xbf8\xea&B\xae#\x16\xb7\xc54*\x8cM\xd4\\R\xed\xa7S,\xa74\xcb\xb9\x80\x11^L\xf3\xa3\x88O\xaf\x06\xeag\x9e\xa7)\xcb\x04\x8eaT\x91c\xc6b\xcc\x81\xd0(\xc9\xe3\xa6\xa5w\xb6\xa5\x82![g;\x19\x16yF\x01\x8d\x05\xce\xe4\x18\xfa\x0e\xda\xdd]8\xdb\xe2s\x1a\xd5\xbf\xc0\x19\xbc\x98\xe2\xe8\xfc\xf4\xea.\xa0Z\xecRw\x88\x9a\x9fg*\xbe\x82.\xd1\xfc\xee\xa0\xf6\xa51\xefeS\x91\x8e>\x93\xa2\xcf\xa4X\x02/o\xcac\xee%\x04xP.ri\xe82v\x9fI\xd1gR8=\x1c/z\xc2\x9a^\x8d\x87=\x12\x8e\xc7\x06|\x18_\xef\xc5\x0b9\xa7\xd7\xe0\xe3\xab\xac;\x92\xd4\xe7&\xf5f\xe8\xb5\xeaM\xe9\xfb\xe2\xe7\xe0S\x8b\xd3\xab\x85UA\xe8\xa4p\x91j_oH{G\xd2\xbc\x18nX\x87G\xadT\x83\xaa\xd3\xd5S\xa4\x12b\xd4V8\x1e\\4w\xb9H\xaea]~\x9d\xab=\xa1\xe3n:\xa0kZM\x9f\x8f\xe2\xb7 M\xcc\xd9z\x97X1\x9f\xfa_\xc3J\xc9\xff\xb1\xf1\x1e4\xd5\x87\xa6\xdcL\xf75BS\xe1\xa1$\xad\x80/\x91\xba\x1a\x10a\xce\xc7y\x92\xcc!\xc6E9\x04\x1aC\x86K\x9b\xa3\xd6\xcb\xb5ka\x97\x19\xaa\x1e/l\xb1\x88\xee-[B\xea\xfe\x80P\xf3\\\x10\xc5z\xf0Z#\xca\x0c%\xda\x9a\xabM\xbe\xdb\xe5|e\x9bj\xb2\xea\xb6\x1b\xb6M_\xe2\x16{R\xd9\x8f]\xac\xd3\xd6\xdeZ\xad\xd3 \xabTZz\xd2\x9c->\xf8f\xacS\xbdn\xb5\xef\xbe\x9eu\xea\xda\x17\xad\xba\xee\xe3\xc5s\xf2\xdf\xf8\xe8\xa7\x93\xcf\xe4\xb7\xff\xf9_\xf6\xd3\xeb\xd7?\xbc\xfa\xf2\xe3\xe3\xe8\xf0\x87\x93\xe3\xf1\xc5\xe1\xab\xd7\x9f\xa27\xd3\xab\xfd\xf9 \x9a\\\xbe\x9a\x9e\xce\xf7/N\x8e\xbf\xfb\xfe\xfb\xe9\x8bW<\xf9\xe9\xbf\xd1\xd1\xf1x?\x7f\xfe\xddl\xfcq\xca\xde\xbd\x98\xfc\xf2%\xfe\xfeu\xf6\xbf\x1f\xde\xbc|wz|\xf9j\xf2\x8f\x7f\\\xfe\xc8\xde\x15\xc3nZ\x04m\x9e\xb6\xad\xa6\xba\xcd\x1cu\xe4z\xb7\xaeH\xabi\xbe\x86\x7fa4\xc7\x1d\xaa\xc2fW\xbaLp\x0f\xd7d\xed\x00\x91\xd3\xe4\xf6R\x85\xde\xa6\xb6\xdb\xcc\x0e\x1d\xaf\xc5\xbcn7\xad-\x1d[\x0c\xde5X\xc6\xcbP\xb7L\xd4m>\x7f\x05\xd3\xd9j6;y\xd2\xcd\x91vS\xd9I3X\xc3Dv\x98\xc7ac\xafi\x16\xfb\x98\xc4N\x84\x1c\xa6\xb0\xdd\x0c\xee\xd6\xfbW0\xec\xb6\xf7F\x88\x9e\xef\x8dP\x82h\x84\xf9\xde\xefE \xb1\x8e%\x98\xa4\xb5VP\x1f\xca>\x8b\xef\x96\xcd\xc1\xe7\x88\x96g\xc8\x1b1\x8fZ\x0b)\xad\x16Dk\xde\xa0+P->\x03B\xcb\x8aj\x0d;\x13\xd6+\xb2\xd4\xe52j\xb0!r\xdcNu\xb0Z\x1e\xab\xda\xb3UkZ$\x93M&\x19\xb5\xa3cw8\xb4\xa1Y\x0b\xfa\xf6\xdb\xd0zk\xed\x9b\x82\xd7k\xfbfO\xf9\x1cc\x9c\xf1\xa2S\x0fO\xa9v\xcd\x9f\xc6\x101B\xb9vO\x18]l'\xc1\x00Q&\xa6\xd59\x83eC\xdd\xb4k\xf2\xe7\xda{V\x87\xabX\x0e\xd3\xacT\xfa,\xa61\xceT\xf4A\\\xa9\xa309\x9ffA\x84\xebv\xc1\xa4c;\xcc\xf0\xe7\x8d\xdad\x92'\xd7\xd5w\xc5\x82L\x9e\xa0i\xf6\xf0j:\x15\x0f\xb2\xd9\xe7\x0bL\x1f\x1e>\xa6\xe7\xc9U\x92\x7f\x99_<\xfe\xf2\xe4\xb7\xcf\xbfE\xb3\xa8\xb5\xab\xa5\xfd\xa9i]0\x11\xcb\xe0'<\x97\x93W\xcb%7\xcd\x04S\x9c!\xb1\x14\x0eh\xe9\xb9sL\xb96\xbb\xad\x8f\x98\n\xb8 \x08^\xa8y\xc2/l\x8e&8\x83\xff\xe7\xd3\xfe\xfe\xfe\xc1\xeb\x87\x8f\xf7\xb7Zz\xb0\xbf\x8d\xe9?\xbc\x1e\xf4\xde\x0f\xf9\xa8\xe5\xbbo\xca*:0T\xc3Y\xbbc{\xad\x1d\x14\xff\x96s1\xc3v\xa7\xd3k\xa0\x83\xc1a\xdb(cl2\xdf{\x87\xb6\x05B\xc73\x9c\x17q2\xcb\x13$\xac|9b,\xc1\xa8M2\xd4\xfa\x1f\xa3\x84\xb7\xcf\xc7v\xe7b\x01\xaf\xb8 \xd2n\x97\xdc\xa6b\xbbKA\xca\x08Q\xca\xd4\xc5\x8c\x9c\xe3x\xb9\x8a\xcd\x02\"F\x7f\xcb\xa9n\xa4\x8aP\x94bn\xc8h2\xbf\xbb\xd4\xcaDg\x1b\xcb]W\x8d\x00+\x8by,\xb7\x07k\xd9\xd9*d\x8c\x1a;\xb5[\xe4\x87\xf6\x1a\xa7UXPG\x05\xcbE\xea\xe3\x82\x1a\xba\n\xf4>.\xd8\x80\x1b\x11\xa3}\\\xb0\x8f\x0b\xf6q\xc1\x9b\xb3\x80\xbd\xe3\x82\xe5M\xdbL\xbf\x1e\xb4h\xd51\xb0\x81r1m l\xac\x1f\x10\xacy\xc2U -\xe5\xf9\x14\x0d\x97\x03\x1a\xc7y\x15U\xb8-Q\x8a\xdag7\x1c\x94\xe8\x1c\x10\\\xa2\xba\\\x90\x15\xca\xc3\xe6\xec\x90vQc\xe1{\x83\x80XCEl`\x9b[\x9f\xe9p\xb4U\xf1\xbb\xde6)\xe0Fl\x13\xd0:4!\xd1\xedV\xa3\xeb)\xc3\x0e\xaa%@\x07\xe0\xba\x0e\x90kJ\xe8d/\xc6 \x9e\xa8\xe7s\xf6~\xaf\xfe~\x1c\xc7\xd9\x1f\xe5O\x84\xd1*\xd2\xbd\"y[\xe4\xae\x96\xba\x8d\xbe\xee\xb4\"\xf7\\\x07\x83\x8f\xa3\xe8\xb8\x0c\xee\x8d\xe1e\xd9\xaejc\x10\xc3\xad\xd4XK\x04\x07*>\x94$P#\x91\x8e\xe7\xa3\xc5\xc4\x8b6\xcb:\xef\xa3&|\xf1/\x01j/X?\xbc\xff\xa9\xf6\xcb\xd7;\"*\xc8a{\xf0\xd7\xba-\xbc\x9e\x0c\xb6\xf6\xc0\xa7(k\xdf\xf3\xd6f\xc5A\x9b\xb9\xdd_.B\xe2k\xa8V\x8b\xbebUu\xbb8\xd3|\xb4\xd4\x8d\x875w\xdd\x88\xaf\xf5,\xa6\xfd\xa0\xad\x93\x12\xb6lQ\xe7fqnK\xf7A\x8aO\xef\xb5Mh\xf7g\xae'/\xe9\xba\\\x9f \x03\xac?\x7fk4\xed\xd5Z\x03B\xc7\xeb\xcf\xdf\xfa\xf3\xb7&\xf4\xe7o\x05\xdc\x94G\xb2~XCz\xa7\x8b\xe8Ay>\xd7\x8c2l\x1f\xed\x1f\x98\xbb\xfe \xcf\x17\x91\x05\xc2\xe12c\xde\xc1]S\xb4$4\xb8\xbb\xf7{e\x94\xa9\xdf\xfe\x12\xc1^\xcbl\x1a\xd4\xb0\xce\xe6}*-t\xfda1\xa5\xaa\xf1f\xa6\xd4\xc1V\x0d\x08c\xff#\xc7\xd9\\\x85\xac\xa2<\xcb0\xad\xc7\xd2`\x84\xc5%\xc6\xb4\x1e\xd2V\x19\xcfhe\x8e\xb7>\xc4\x1dd\xe7\xad\xe7Z\xad\xe7\xdf\x98\"\xd5\x96&\xc6(\xf5\x1a&\xc0\xb7\xe5\x91\xac%\xbe\xab\xf5\xdaP\xa8\xdaK\xf8\xe6t\xa4\x9f\x02\x1c\xf6gl\xce3\xb6\x8aX\xfdi\x9b\x82\xdb~\xdaF(\x11\x04%C\xe7\xf1\x99\xa1}\xd7vQ\x86\xd5*\x0e\xcdo}\xe9\xf6\xa6\xea\x883B\x87\x82\xcc,#\xaf\x94\x81\xeb&w\x16\xed;\x89\x18\xfbi\x18\xa2\xad;\xa6\xdc\x01\xfd\xd1X\x05\xfd\xd1X\xdb\x88\xfe\xb3\xeb\x8f\xc66\xe4\x88\xf6Gc+\xd0\xc7\x10\xcd\x9f\xf5Gc\xfd\xd1\xd85!\xde!\xdc\xb0\x80\xfeh\xac?\x1a\xab\x81M\xc4\xf7Gc-\xd0\xab\xb5\xfeh\xac?\x1ak\x83\xfeh\xac\x80\x9b\xf2H6\x13[m\x8bC|S\x87d\xadq\xda\xfe\xb8\xac9\x9b\xbf\xdaq\x999&\xdd\x9f\x98uq\\\xd6s{0\x15Y\xab\xf2Y\xc3\xfc\xec|\xaf\xc3#\xf4\x0d>\x82x\xdd\xf6\x1e\xa1p\xf0\xe9\xc7\x16\x11\x07S\x07k(\x8cM\x1f\xc6U2>\xc3\xb5}j\x97\xd7\x9f\xe5&\xaf\x06Z\x12\xd8wZ\x87\x0f\x16\xd6\xcd\xc0J\x0b\x15\xcd\xa8,v\xcb8c3+>\xbf\xa0\xa4\x86\xcf\xc7,\xfa\xc5\"l7\x82\x92`\x01\x08\xbd\xe4b\x0d\x84\x02\xc4vy\x90\xd8`\x02\xd8\x19\x93D\xe0\x0cFs=)\xcd\x10\xbc\x8c&\xddz \xedy\x90\xf8\xff\xcb\xf0\xf8)l\xff\x9f\xbd\x18\x8f\x95x\x92\x16\xcc\x87\x1a%|\xeb$\xaeeH5H\xff\x970\x98\x82\x8aB\x16'w\x0d\x0e-9\xed:\x0e\xec|\xea\x17n\xc86\xe8\xcf\xe6\xfa\xb3\xb9%\xf8\xa6<\xe1\xfeln\x05\xfa \xa6\xf9\xb3\xfel\xee\xcf~6\xc7\xb3\xa8D\xfe\xab\xe0\xdf!\xc4\xb1\x80\xc54b.\xbe\xde\x1a\xac5\x87\x0e9\xb2\x0dq\xb8\xffm\x9d\xd7\xf5E&\x9d*\xa3\xab:\xeeO\xf2\x1ap#J\xb0?\xc9\xebO\xf2\xfa\x93\xbc\x9b\xf3_6s\x92W\x0fL\x18N\xf0\xae/xT\x19-\x7f\x8d\xc8Q@dsq \xb5\xa0\x11\x88)\x12\x8d#(\xc2a\xc4\xa84\xcf\xaa\xf8\xec\x9f%\xbai\x11j6q\xc6\x8a\x83\xc8\xcew\x1c\xbaY\xc1\x9b\xb5\x83\xb5\x85\x8a)\xcf\xf90\xcdG\x06\xc1\xef\x98\x86K\x8fUx\xca\xb1\xd2|t\xf0%\xfa-\xceq\xfay\xff\"?\xfc29\x9f\x9c\x1f=\xc1c\xb4O?_~\xa11\xa2\x9f\x1f\xcc\x8e\xa2G)\xba\x9f\x1f\xa1\xf4\xcb\xd1\xe40{2\xe1\xe9\xe7\xc9\xc3\xc9\x93\x88\xdf?\x7f\x12\xe5\xe3\x95q~C$\xc1\xad!'\xbb?\xcc\x05\x12\xb9e\xedL\xf7<\x04;\xc7\xed\xf5;\x1d~O\xe9\xbbv\xac'Wg\x19c\xdb\xceg\x8f3F\xc9\xb9\xf9y`\xa7\xca 1\xa6\x82\x08\xe3\x8b\xcf\xce\x0e.\xf1\x88\x13Sd\xc3\xa3=\xc7Q\x9e\x111\x1fF\x8c\n\x14u?\xb5\x8c\xb1@$q\x18\xe7\x86\xf6RP:/\x10\xb9wS\x9bRW]\x13*24\x14WCeB\xb4/\x97\x9d{k\xa3\xec\xaf\xfc\xb8HX\xb9\x9e9,\xfa\xb7_\x94\xf2\xe8\xfd\xe0\xc9\xa3\xfd{\xfb\x07\xf7\xf6\x0fN\xf7\xf7\x9f\xaa\xff\xff\xdf\xd5\x01#6\x9b\x11\xce\xafg\xcbd\xc6@\x9cs\x1e\xe0\xa2\x94\x84\x19\xba\x1a\xde\xc4\x18\xd1\x14\xd1 \xbe\xf6\xa1\xf24F\x02\x87'\x044\xc1\x97\x03:Z\xab\x8b\xf67a\x90\xf6\xb9`\xcd\xd9\xf8\xe7\x82-\xe5\x02lv6\x1d\xec\xaap\xab\xbb\x96\xad\xf2\xa70\xb9\x83\xe2\x84n\x0b\xda\xdb\x14\xf2\xb5\x9e\xd7_\xe3\x05\xb8-g+\xfav\xab\xf9\xfamf\x93\xc5l\xb3\x97M\xd6\xb2\xcd\xda0Y\xca\x16\xe2\xb8\xaddkc\x8b\x85lU\xf6vUo\xb5\x8d\x1d:\xcbn\x17;\x1a[mbG[?{\xd8\xd1\x89\xd5\x16\xb6\xb4\xb5\xda\xc1~{c\xd5\x8c\xf0\xb4\x80\xed\xf6\xaf\xd1\xfau\xdb\xbe]\xf1vY\xbd\x9e\xfd\xfaX\xbc6{w\x8d\x0d`6\x0d\x9d\x16\x9b\xc3,\xb4\xdb\xb8\x9b\xe8\xddi\xdd\xae;\x88\xd3\xae\x0d\x18\xe0Zl\xdakM\x8d]\x18\xb3\xba\x8f\x00C\xa8\xa6\xfd\xca\x1c\xcb\x05\x9a\x11\xa2\xb1\xfc+\xe6\x03x>\x87\x18\x8fQ\x9e\x08 \x022,\xf2\x8cr`4\xd1\xc5\xa7\xb4\xa9T\xf5\xb5\xc0hP\xfc\x9b9 \xae\x99\x8fZ\x9a\xa1Z\xd7\xd5\xfe\xd9\xb0\x82\xb6T\x89\xd3)\xae\xcdF\xa2Xt;\x80w9W\x99\x11\x98\x88)\xce`[\xe3\xbf\xbd\x0b\xdbZR\xa8\xbf\xb3\xa6\xe8\xda\xae\x84\xc8\xf6\xa0\xf6C\xcdt]\xa2\x82m~)\x9a`\xd34tA\x8e \x06}<1X\xa1\xc2\xaa`\xad!q\xe05~BfD\xd8\x10\x98\xa1+2\xcbg\x05\x0e\xd2\xc2W\xe1[Hq\xa6\x90\xeb\x88\xd5\xad\xb7\xa1\xfb\xb0\xb5\xd3\xf4\xf61\xbe\x9d\xd3\xe8\xc3\xd6\xab\xed\x8c\xae\x96\xcb wv\xd0\x87\xad-\xed\xfd\xcct\x8f\x8e\xfa\xb0u\x1f\xb6V\xe0\xda2\xd7\x1d\xe7\xed\xc3\xd6-\xe0\xcb\x01\xdd\xac\xf1\xed\x16s|\xfd\xd8\xb2\x7f4\xf6\xcfq3W\xfa\x12\xf5\xc70\x8b\x1a\x91\x9c\xd0I\x82\xff\xe4wp\xdd\xb6\xa1\xb7\x92\xf7\xb5\x0b\xd7_\xe1\x05\xb8mB+\xfa}@\xd6H\x1c\xb7\xfdgm\xdc\x07d+\xf0\xb3\xf4\x1c\x9d\xf4\x01\xd9\x1at\xc5\xdbe\xcfy\xf6\xebc\xcb\xf5\x01\xd9\x06x\xd9m\xeb\x0e\xe2\xb4\xd8\x02\x06\xd8D@v\xd3\xb1W\x1fko\xbd\xd7w\xff:\x96\x9f\xe5%\xdeo\xce\xe0\xbb\xde\xe8\xa1\xc7\xdd;\xc7\xceZ\xdc\x1e\xeb\xdaC\xc7\x10\x94\xb3$xg_\xfa\xcf\xfe\x12\xefW\x11]\x1bz\xde\xe0\xaf'\xc4\xacO\x1d\xf4\xe2\xac\x01\xb7A\x9cy\xd4{ZO\xae\x19\xday\xd4w\xb2\xdb\xec\xd7\xf5\xd4\xc1\xa6\xc5M%mR\xc6\x92\xa7]\xb6U\xfdq#\xe9q\xe3\xf2\x91\x82\xa2g\x90=\x7f+;*(\"\x940\xc6\xf1\xb0C\xc4@\x1fDwiI\xe88\xd1\x8c\x99 .\xc2\x9d\xb3\xaa}P+\xe5,\xa8\x01\x17\xce\xda0\xc3\x1c\x87y\x9ci\x86/\x86\xc5\xdc\x83B%\xeb\xb2\xf6\x92F\\\x8f\xc15O\x97]\xea{\x93\xfcO\xc9\xdf\x0bfS\xe5&\xb4W\xea\xb9d\xcb=\xcc\xd0U\xd7\x96$\x8cY'L\xea\x0b\xc5eA\xed\xd6\x08yH\x9f}9\xcbg\xb5i\xbb\xaaP\x11\"\x83\x91\xbc\xd1\xcd\x90 >\x95\xbb\x81\x93 \x95\xb3$t\xcc\xbam\x08\xd9\x83:\x06\x90\x92~B.0]\xba!y\xa7\x05\xb1\x95\x86\xadM\x02\xb6\xc8\xca^+&X\xf6\x14\x98\xd1d\xcb\xf89Yd\xfb\xd4>1\xad\xaa\xc1\x0c\xdet\x16\xd0;G\x06\xd0\x860}p\xa7\xfc\xf6z$\xd2\xf5\xda\xb0\\\xa0L8\x8d8\xa3\xf1\x19\xe3\xab!\x1b\x8f[\x15\x9d\xa3\xb1>\xb0\x18\xe6T\x90$\xb8\xb1\xd4\xb18\x1e\x8e\x12\x16\x9dswJ\xc0\xb2\x84\x08\xb4$\xd3|\x94\x90\x08\xce\xf1\\\xd5)b\xb42\xe1V\xf6gW\xf1\xb3\xbd\x90?V\xb7VR\xad\xf4c\x03\xea\xfb}R\x0d\x01\x15T_\xf1\xe4\x1a8~\xc44n\x94b\x12\x0crG\x07\xd7S\xaa\xa6\x93\x0830N\x9b\xd7nv\x16\xec\x11\x00\x8bdX\x89$l\xc6\x95\x075\xb5\xc6\x1c\xb6\xb7W\xb0\xd5\xcb\xfc\xbcY\x96\xb1\xa5R\xa3\x11\xfb\x0d\x19F\xd7Rr\xb1\xb50\x10X\xe4d \x1e\x85r\x8c\xd1\xaf\xd6BA\xe0\x9a\x088'\x03\xb6\xa2A\xe0\xc6\x0b\x9ca=7]\xc0E\x1b\xf0\x99\xa7\x06\xf7l58\x0b\n\x81\xdf\xdcK\xf0\x88~\x96\xe0\"\x97\x86.c\x1b*\xedu\xae\xa2\xe9U\x1ah-\xd6s\x8c\x00n\x1c5\xb8\xb2`5|\x85BD\x12\xac\xc5\x88\xc0\x87\x90\xe0EL(\xbb\xb2\xf2\x8b\x17=\xa1N\xd3\xc0\x02E\xe0.R\x04\x9d\xf0X\xb3X\x11x\x16,\x02_\xe4\x9c\xf9v\xae\xe2E\xb0\xc6H\xc1f~_=\xcf\xb9\x89\xfa\xeay\xf6\xbd\xe8\xa9\xe4\xdc\n.t\xbc\xbez\xde\x8d*\xad\xbez\x9e\xdf\xd8k*$\x1fe\xe4D\xc8\xa1\x84\xbe^\xf5\xbc\x15\x9f\x16XV9d\x8b\xbe:E)\x16A\x8aM\x1e\x19\x14}\xd6\xdc\xf9\xa2\x89\xcb\xfd\xf7\x0f$\x04km\xcf\xe0\\\x98nFWC|Ab\xc9\x17C\x14xR \x05\xde\"\xe2uIh\xcc.\x83:\x98\x11:,:Iq\xd6\xa5\x87\x98\xe5\xa3\x04\xabN\x86\xfa0`\x18\xe7Y\x87\xd32vI\x05\x99\xe1\xb5:Q\\3\x1cg:D5\xac\xe1\xb6^7\x1a5\xcf>:\xee\xa2 \xbb\xd8\x93l\xc28*\xf3pC\x82y\xd5c\x1de\x1fwZ\x06o\x0b\xe2qC\xc3\x9b \xde}\xcf.$9hTN\xa8=|\xd7\x98\xc5\x92v\xae$\\\xae\"\xb0g[\xe5D\x86ry\xb6\xce B\x14F\x18\xce\xb6\x04\xbe\x12[g\xbb\x8d\xd6g[\xd5\x88\xc5Y\xdd\xd6\xd9.\x9cmq6\x16\x97(\xc3\xc3<\x9dd(\xc6[g\xb5f\xc5\xe1\x07\xe3bX\x0d6\xfas\x06\xd8\xfa7M\\\xb3\xeb\xdf4\xd9\x90U\xd3\xbfi\xb2\x02\xbdCj\xfe\xcc\x15i\xfd\x8b\xbfi\"\x88H|M\x16\x0d\xf5\xd9\x84\xb4k\xe8\xdb\xa0\x965\"K\xdd\xdc\xda\xaf\xf9\xe6\x8f\xa1\xcb\xc6\xa2t\xbb3\xd8\xed1\x962\xed2\xc6)\xe3\xc4\x98\xe5\xd5)\xe4\xf6\x97\xcb$\x0fv\xce\xfa\x90\xaa\x93\x1b\xba\xea\xd2>\xa4\xda\x80\x1b\xd1`}H\xb5\x0f\xa9\xf6!\xd5\x9bs>\x82C\xaa\xa5\xd5\xb3\x89\xf7F\x82B\xa5\xba\xa8D\x15*\xba\xd32\xce\xd2'\x8d\xea\x13\xcar\\\x89\xaa^\x7f\x08\xc7\x9c\xb0y\xc1D#\xc1\xb21\x15\xf5c\x8b\xddfz\x91\xd9\xb0\xe8\xb6\xf1\x0b{\x8d\x19q\xa8>\xb8^Y\xa0\xd1\xb4\x97\xee\x0d\x08\x1d\xafO\x16\xe8\x93\x05\x9aP\xd1\xadO\x16\xb8\x19\xc3\xbc{\xb2\x00\x89\xa5{VF$\x9a\xa9\x03G\xfb\x07\xe6\x9e~\xc2sH\x11\xe7\x97,\x8b\x81p\xb8\xccX=T\xdd)\x14\xe3\x15p\xde\xfb\xbd2\x9c:\xe7\"\x14=\xdci\xc1\xad\xf1A3\xf4\x0c\x88\xc6\xc6\x1b\xcc\x7f\xe50\x8c\x0ff\xc5\x93 \xb6\x0b\xe0\xe6;\xe4\x1d\xb1,\x8c]\xd7; \xfb\x0f\xd3\xab\xab\x8b;\xe5P\xb7\xc0@\xeb-\xed\x1a\x84\x8c\xd1b\x8bt=\x9c\xfb\x86\xdc\xb3ud~\xdbK\x9eG\xfbG\xe6\xee^\xb3\x9c\xc6@\xd9\x92\x10\xbd\x16\x99\x7f\xc1\x04\xee|\xc2\xa8\xea]X\xce\x17\xf5\xef\x8d\x8a\x1e\xb7\xea\xa4\xf1+\x0b\xf6\xeb\x12\x84\xd7{\x18\xa9\x16\xd5,\x05\x0d{v\x9d\x036\xa6\xa7\xef\xdb,x\xaf.Zv\xda_a\xc7[\xbf0}\xfd:\xf0D\xeb\xa2\xb5Y\x7f\x88\xe5\xdcd\xae+\xe3+\x15\x995\xb7m\x9d\xc1\x98\xe0$^T\xa7\x99c\xae\xeb\xccP\xb6Z\x9a\xa6\x9e:\xb7u\xa6\xcc\xd8\xb3\xad\"9\xd0T\x8dY.i\x7fd\xb6\x02\xfd\x91Y\x7fd\x16\xd2{\x7fd\xb6\x02}P\xd5\xfcY\x7fdf=23Xw\xb7\xcd\x1f\xd3`2\x0c\xad\xd8.\x18`\x8e\xf9u\x9b\xe2A\x9a\xb8?4j4\xed\xe5[\x03B\xc7\xeb\x0f\x8d\xfaC\xa3&\xf4\x87F\x05\xdc\x94i\xba\xee\xa1\x91r\xfao\xf3\x89\x91\x8a\x1e\xee\xfd\xae\x8c\x86\xceGE\xb2\xf5\x9d\x16\x8c\x16\xbf\x9a\"\x88P\x9c\x18\xb5\xd5\xdd\xfd+\xc7;|0+\x1f\x907\x94,n\xafv\xdc\x11\xbbo\xf6\x94(\xdc\x1a\xeez\x16\x12d\xcav\x16&\x9dO\"j{\xf4Z\x04\x89\xba\x06\x1c.@\xbe\xc7\xf5\xc7\xe0\xb69\xa8~@_'\x06\xd4|\xa6Q\x90Y\xab\x9c\xa9Y\x11\xdfc\xc1\xc3:\x1c\xc0\x9bq\xedf\xa0\xa4\xf6\x82\xb8)\xa61\xa1\x93\xc5=\xab\x1d2\xc0E\x11l\xd8..:\x9c\xa8r\xd6\xdbw\x81\x08\xc8\xb0\xc83\xca\x01Q\xc0\xb3T\xcc\xf5\xf0U\x7f\x1a\x8dA\xf1\xdf\x7fU w+$\x83\xe1z\xb9\xa7\xe7i\xbb\x1cm\xbcR\xbe\x81\xbe\xdb\xaf\x91o\xa0c\xfb\xd5\xf1\xb5\x06\x08\x16v\x8b\x96\x9d\xe4\x94\x16S\xd5~\xd8k\\7\x0f\x90M\xda|\x99T;\xad\xcaxY)/l\x92F\x1e=\x0cTE\xac\x19\xba\x1a6\x8b\xe7CN\xa5\xbcA\x19\xae\x07\x86(\xa2\x8c\xe3\x88\xd1\x98_\x87\x10\xb9\x15\x1bsFh_!\xa0\x01!c\xb4\x05\x0dV\x98\xab\xf3\x06\x7f\xfc\xf0h?|\x8b\xff\x07\x13S\x9c\x0d\xa5j\xf8O\xe9\xd5P&\x95~\xbd`\xb7T)\x98\x8b\xa6\xf6\xf0\xb4l\x8c\xbbrS\xf2C\xa9pB'\xeb\x0b\x10m\x8b\xd8\xc5\x87o\xa3\xdb\xbd\xef\xcd{JL3\xcc\xa7,\xe9\xce\x84\xfb\x83\x07F5\xb6\xa6\xfa\xba\x7f\xff\xc8\xd0\xf1bA\x86)\xa6(\x11-\x81\"\xefa\xf6\x0fn\xd7\x162\xb0\xd8\xa66\x90.Q\xb2\xfe\xf6\xd1\xfd\xac\xa1~W:\xd0\xda\xb7\xf1,\xcd\x9fD\xf1Z]\xe2\xc5l;3\xf1m\xd4\x04&\xfe\xe8\xca\xc7\xdb{1\x91\x84\x18\xe5jAc\x9c\xe0\x89\xaa\xcd\xba\xf7{\xf5\xf7\xe38\xce\xfe\xd8\xcb\xf0%\xca\xe2\xd2\x9fX\xf5\xc5\xee\xad\xfaFe&o\xad\x9f;\xad\xd8\x15q\x9e\xe3(:.3\x1f\xc6\xf0\xb2lW\xb51xe\xad\xcb\xd9\x12\xd9yt\xf9\xe4\xa1\x88/f\xe8\x0b:\x8f/\xcf/\x0f\xf3\x07\x8f\x0e\x0f\x1f\xe18\xcf\x13t\x18\xcd\x1f<:L\xc6\xa1;Xz\xf7\xd2\xb5Ve\x9f\xa0 \x12\x8cP\xa2v\xe38c3\xf5~CA\x04\xc2\xa8kG\x97\x1d\xf2|&\xa9 \x1b\xcb\xff,{\xc6(\xa38\x86\xd1\xbc\xde\xa5\xfcO\x04\x9c\xd0I\x82k\x14n\xd2o\x8d\xcd\xfc\xb2\xc6#\xd7\xb6\x9d;\xd8\xd1\x05QL;\xfcfm\xe8\xaaX\xf8\xb0\x88_\xb5\x7f\xe6e\xeb6(\xe7yZ\xada\x89\xeb/P\"\xb1v\x865\x0f/\x8f\xe8a\xd2\xda\xa7&\xb2}2\xe6cP\xc7A\xa8\x93\xea\x1a\\\xb4\xd7\xe0<\x0e\xf5\xa2\xbd\x06\x0f\x8fF\x83\xfbP\xb4\xcb\xa8->\x8e\x920\xb7\x83\xd5\xbf]w\xd1/PS\x89\xce\xd5Pt'-\x1b\x96}\xfbO\"\xa6q\x86.+\xd9_\xa1\xb3\xcdkR\xbf\x94~wZ\x10\xe9\xd6\x85\x87\xd8\xbf\x9ed^\xf3\x03\x97Ky\xa6\xda\xa2\xa8fWZRK_\x85\x19\x8b}ni\x9f[\xba\x04\xdf\xd4\x01~\x9f[\xba\x02}\xee\x95\xf93\x9b\x89\x01\x7f\xdd\xdc\xd2[\xe1\xcf\xf4\xc9\x95\x8d\xa6\xfd\x06o@\xe8x}re\x9f\\\xd9\x84\x8an}r\xe5\xcd\xd8f\x9b\xf4<\xbfBVe`lx\xef\xf7*\x06\xa6\xfe\xfd\x1b\x8e\x15\x87d\x01\x1ag\xd3\xa0\x86u6\xefSi\x91\xe8\x0f\x8b)U\x8d73\xa5\x0e\x81\xc0\x80(x\xf9n\xcbJh\xe1N\xcb\x9c\xcb\x8fu\xbcz\xb5\x8d\x8ef/\x87\xaf=\x82\x13\x01\x11\x87\xeb2\xf7\xae\xf7Z\xbb\xd1$q\x88$\x87 \xe2*\xdd\xed\xee\xf7\x1b\x8e\xb1\xf9\xf1\xec\xea\xf7\xed\xa1\xb4\xe2\xc4\xa7\xe4\xed\xe5M\xec\xc1\xc4}\x84\xad\x84>\xc2\xd66\xa2\xff\xec\xfa\x08\xdb\x86\xac\xb8>\xc2\xb6\x02\xbd\x03n\xfe\xac\x8f\xb0\xf5\x11\xb6\x8d\xaa\xba\xae\xa2\xa6\x8f\xb05\xe0F6x\x1fa\xeb#l}\x84\xed\xe6l\xb3\xf5\xfdN]\x05\xb1\xf2\xe3\xbe\xfaUf\xdf\xa0\xdbe\xe1\xa3\x95\xe9f\xdfp\xb4\xedZ33\xcb\xcc\xc9\x92^(Y\x8a8\xb821k\x89\x96\xdb\x96\xde\x06p:%\\\xf2\x81lT2W\xcdh\xba\x9c\x92h\xaa~\xcc9\xce\xe0\x92$ d8\xc2\xe4\x02\xd7\x10\x85qNC2r\x02\x82\x00\xd7e\x81\xb5l\xd4\xd0\x04\xc6e\x96\x08,\xb5\xd3q\xeb\xaf\xb9W\xc3BN\x1fp\x9a\xa0\x08w\xe0\xc9zKOf,\xccy\x8a/\x81Q<\xf0g\xa7>\xfcTB\x1f~j\x1b\xd1\x7fv}\xf8iC&N\x1f~Z\x81\xde;5\x7f\xd6\x87\x9f\xac\xc5\x03\x97\xcdf\x93V0\xd09\xd4\xb0\x81u\x8d\x9b\xeb2\xda\xfa\xb0Y\x1f6\xbb=\x82\xa9\x0f\x9b\xf5a\xb3>lvs6\xe5\x1aa3\x96U:\xf4\xf6%\xa9U \x17\x1bHF\xfb\xeb\xa4o\xfdR\"\x0bub\xd6+\x1a\xdei\x99\xbc\xce\xe3RA C+u\x81y\x8d\\\x98\x80\x08\xc3\xad0\x93X\xc1\x07_\xcf\xb6\xec\xc0'\x0b\xe08\x19\x0fG\x8c\xc6\xc3[u\xb1\xfa\xdb\xbdm\xaa\xe1\x02%\xc3\x88\xcdf\x84sb.\x9f\xd8\xd3t\x19\xdai\xea\xa7\xae*a\xb3\xa1P\xaf\xb7\x9a\xd9c\xb9\xe0\x02\xa9\x9a\x8a\xc3\xce53\xfe:\xaa\xe75^R\x1f5\xfaU\xf1\xedo_\x8d\xf4y\xc1\xd7\xbf\xf3\xfa\xdd\xe6\xdcm/*5\xa4jRK\x85\x7fo\xb5\x1c\x80u\xbf\x19L\xc0\xc8\xbb\xe7\xaa\xc3\x80S\xa9~\x07\xbbv\xda\xcd\xec\xe0\xaf\xa2{\xc3\x8eY\xab\xb3C\xc9\x95\x15*\xdb\xdc\xab\\\xc6r\x9be6\x96\xac\xbd\xe0\xf4\xe5>=\x18\xb9?^-\xa1?^m\x1b\xd1\x7fv\xfd\xf1\xea\x86Ba\xfd\xf1\xea\n\xf4\xa7\x18\xe6\xcf\xfa\xe3\xd5>\xbb\x7f\xa3\xaa\xae\xab\xa8\xe9\x8f)\x1bp#\x1b\xbc?\xa6\xec\x8f)\xfbc\xca\x9b\xb3\xcd6\xe9{\xde\xf8\xd1d3p%\xdd\xc6\x9c\x121\x1f\xa6\x8c\x15u<\x03#7\xaa9\xc8\xe6\xab\x05\xa0=|\xcf\x00\x87\xf2\xba\xb4y\x1fD\xd9\x0c3-;\xfc\x01\x8c\xb4\x12p\xff\xe6X\xc9\x11\x8aH\xd5+;8\x1b\x9a\n\x17[Vm\xc4h\xce\xd7\xeaa\xb1\xcd\x05\xba\xf2l\xd9\x91#f\x84\nB'\xeb0\xc3;\xdd\x05\xccX\x9c'\xd8\xcd\n\xf2\xfb\xdb\xcd\x02\x92(C\x83 \xb0,\x1b\xa1\xe3D\xe1=T\x9eM4Etb\xb4\xd9\x1c=\xcc\xbc\x17~\xa5e\xe0\x93Z\x13\x86\x12u`\x8f\xc3\x98t\x94\xb0\xe8\x9c\x0fS\x9c\x0d\xe7\x18\xf9>\x1e\xb8&\x9bV\xd3\x0c\xe6\xd2\x17\xc5[vEO\x0b\x82i\xc3\xea\x96\xf3\xeau\xd0\x12Q\x9a\xa3\xe4^\x9a\xb1\x0b\xa2\"\xd1k\xd3T\xf7\x08\x8b\x1e\xffr\xb4\xe5y\x9a&\xf3\xbdZ\x99\xf5\x00r\x9e\xaa\xe7\x1ft\x17\xc0\xc6\x101B9\x10\xaa\xcf\xc6\xa6\xa8\x8a\xae,S\xf2\xa3jr{h\x19\x14o\xe9K\xd2/ d\x8c\x0d\xd8\x83\xdb\x0d~\xdd\xfb]\xcd\x9fP\xc5'\x1dr\x1d\xeb\xcd\xef\xb4\"\xf2\x82\x11\xda\xfeY\xc7\xf3\xee\x1c 6S?\xac\xb1\xcf\xaac\xea\xc8\x80\xdem\xdfo\xcb\xb2\xcb\xcb\xcb5M\xb6;3%\xa3\xd9\x1e\xca\xc5t\xef\xe2`\xaf\x88\x10\xf0\xbd\xdf\x0b\x1f\xba\xe5\xd5\xecjA\x8e\xf5\xc7\x8bWa\x8b\xff\x8e\xb1@$\xe1\xca$\x8f\x81\xd1\xea\x96t\xd1\x81N\x95$\x8c\xbe\x89\xabN\xba\x92\xfa\x18x\x1eE\x98\xf3q\x9eT\xad\x07^\xe4\x0f\x12w\xc5\xdcV%@\x03\x9b\x05\x05\xc6\x84\xe2\xe26x\xf1ol\\$Kd\x1aM\x95\xe5\xb4D\x99\x05\xac\x11!\x94M\x87y\xd6\"\x9c\xc1GV\xf9\x9d0\x1c\xc3\xa7\x0fo\xf72\xccY\x9eE\xe51\xe8\x14 \xc8)\xf9\x9c\xe3d\x0e$\xc6T\x901)\xc8 \xc7\x0566t\xa7^=\xc2\x19A \xf9\x82\xe3;\x86\xaf\xd2\x8c \x16\xb1\x04F\xf9x\x8c3\x98a\xce\xd1\x04\x17\xb7\xef\xf5\x9c`\x96s\x01\x11\xa3\x02\x11\nH@\x82\x11\x17\xa6\x1e\x19\xc5\xb0\xb5\xb7%\xd5t\x86\"\x813\xfddZ\x82\xb8\x00\x8e'3\xbcX\xb8O\x1f\xdens%?\xd5\x10\x86\x0e3)\xc48\xa6\xc6\x11eW\xe3\x88\xd8\xcc,_?\xaa\xbd\xc8A=@)\xc5\x00]\x96?\xb0#1\x9b\xe2\xe2\xe1~\xbdy\x97/H\x970#\x93\xa9\x80\x91Q\xdc\xa8\xa9\xaa\x84\x00\"\x0dz\xa9&uP\x86\xa78\"c\x12\x01\xc73D\x05\x89ZL\x1b\xeb\x99\x98\xd3<\xd1;\xf7)\x8c\xe6b\x9d\x0c\x89wR\xc8\x8cp\xf5<\xe7\xc2\xf8X\xb12\n\xc5\x8cF\xec\xc2\xc4:\xc5\xb4\x0bfoN\xd9\x8e\x8f\xca\xa2-l\xe0\x0f\x85\xf9Z\xd6\x11*\xcdY\xcdP\xe3b\xfdT\x8b\xbd\xa6\xd9\\\xc2\x87\x93\x170\xc3b\xca\xe2\x05\x0e1\x1e\xa3<\x11f\x0b\x9aBN\xb5\xa2\xc4\xb1\x16\x81\xd5\xc8\xb56\x1b\xb2\xa3U\xff\xa6\xb0\x81!\xaa\x1e\x1b\xa3\xb1\x84\n<\xc1\xd9\xca\xaf%\x93\x10*\xee\x1f.\xfdZ(\xc3 \x1c\n\x8f\xe6v\x84;\xec\xf6\xbd\xc7\x16r\xf1\xe4\x026l\xe5\xfb\xda\xf9\xdd,}cgV\x0f\xa0\xa3\x0f`\xecM!\xe5\xf4\x026\xe2\x07t\xf6\x04\x8c\xfd!O_`Mo\xa0\xa3?`F;I|=\x82n>\x81\xb13ea{y\x05\x1b\xf7\x0b<=\x83\x8d\xfa\x06\x1e\xde\xc1\xc6\xfc\x83\xf5<\x84\x0e>\xc2F\xbc\x84\x8d\xfb NO\xe1\x1a|\x85\xeb\xf2\x16\xae\xc1_\x08\xf1\x18\xba\xfa\x0cV\x19\xee\xf2\x1a6\xe87\xf8z\x0e\x81\xbe\xc3\xc6\xbd\x07\xb7\xff\xb0\xb6\x07\xe1\xc8\xab\xf30\x81\x9c~\x84\xbf\x95\xb4Y_\xc2\xeeMh\xf0\xc1\xec\xec\x98\xce\xcfJ\xf3\x88K\xc1\x85\xb2\x11\x11\x99\xdc\xc4f\x0c[\xbb*u\x04JX\xc1z\x80\xda\x97VJg\xa5h4\x86\xa3\xa6Y\xb8d\xfeUV\x9d\x815O\xca\x8d\x93\x90\x91B\xbb\xd0#\\\x1d\x02\xb1Li\xf0\x14E\xe7{9\x95\x7fH\xbd\xad\xf9\xa2}\x07\x15\x8a\xdel\xd8\xb01\xe4B\x0b\xb6R<\xa8\xcb>(\x8e\x89\x96\x15U\x02|\\\xf8Y\xbc\x98Vk\x7f\x12\x1f\xbd\x84\xed\xe3\xbd\xd2\xe7ap\xf0\x14N$\xfeR.\x14SA\x15\xd1 \x85\x17\xdf}gQ\x93\xaf\x19\x831c\xf0\x0c\x06\x83\xc1\xbf\x1b?\x93\xc8 :7\x7f\x80\xe8| \xd1x\x9d\xb1\xd9\xce\x98\xb1\xbb\xe6O\x07\x03\xb3\xfe#c\xd8\x91]}R\x139e;\x7f\x93}\xdd\x85\xdf-2\xdc\xd6\xdf\x1fv\xda\x1d:h\xf7#\xba@\x1b#\x1e\xf8\xb2\xa5\xa9\xa8|\xaf\xd6\xfe\xcc\xae\xa8BuK\xf6!\xd5a\xeb'?~|\xffs\xfb/\xcf\x9e={f\xe6\x01\xd9n\x11s\xd1v$\x93\xe2\xa00\x82\xb4_\x97s\\\xc6U'y\x82\xb2\xf6\xfeV\xbb\x11\xaa\xf4\xf6\xc2l\xd9\x05<\x1b\xe18^\x180\xbb\xda\x1co\xeb\x0e\x19\xa275\x93b\xac\x1c\xd9\xb3\xff\x92\xa4;+\x82 \x95\xd9V_\x9c\xf6\x0dR\x88\x9f\xa7\x16\x07\x04E\xe7R\x06-\x1c\xe21I\xb0Yo\x942\xeb\x04g\x9cQ\xeb\xb6-\"qc\x92q1T+\xfc\x0c\x0e\xcc=W\x0d$S\x96\xdf\x1f\x86k0\x00+V[\x8a\x96[Oa\xabm\xd76\xc90\xd0\xb3\xdc\xda\xb5\xf5\xa7\xe6\xf73\x9a\xc9>\xffCO\xe1?\xad\x0d\xe4\xfc\x96\xbe\x0f\x9d\xe4\x9bq\xe1p5yMs\x03\xe1p\x89\x93\xe4\xde9e\x97\xba4\xc1\x14q@\x10\xe5\xbc\xcc\xacZ\x06\xf3\xe6j\xb2\xfc\xae6\xe0\x97\xf6\x81\x16\x9e5t$\x03\x1b\x9c+\xa4Y\xba}\xb03\xb5\x19K>\x9f\xb2$\xd6L\xae1\xd7[\x99\xd0j\x7f\x80\x8e\x00\xb6w\xa5\xb7L\xfb8\n\x85A\xa5\x9cw\xa4\\+I\xb8\x12\x1a*#\xa6\xbf\xfe\xeb\xd7\xbb\x96\x8d\xb4 \x9ek\x0ehg;E*\xd9\xe5\xc1\xe0\xf0\xe0\x90\xb7\xdd\xe9\xd7P*\xea\xf6b\x10:\xcdo\xb5\x8a\\3u\xa9\xa8m\xd0H]*\xfeM0\xf8\xac\xaa\xbd\x8c\x9b\x81\xaf\x95\x84BcB`\xabK\xbe\x9c\x9f\xa7N\xb6\xee\x0042\xd2\xd4\x94Vs\x9c\xab$\xb4\x13\xf5\xbb\xc2\x8f`\xaeB\xc1\x0b*\xb4g\x9c\xe5b\xaa[\xdd)q\xbe\xa5Ig\xf5\xb9\xd7\xa1\x81\x8c\xfe\xa8\xb1n\x0b\x02\x94\xfaK_\xf2\xd8h\x9a\xd9\x0c]\x0dgx\xc6\x86\xd5\xb9\x89\xe5\xbc\xca\xebH7'T<\x13\xa2\xcf\x84\xb0o\xcak8D\xd8@\xba!1d\x1aV*e\xb3)\x87\x0b\xfc\x16\xaaD\x8aO\x13\x9aK\"\xba\x90\xc9\xa8\x10\x0f\xba\xf0\x9d:w,\x84M\xa1\x8c*\x01\xae\xa4\xf6d\xe9XM\xcdPz\x86v\xa1<\x80\xf74\x99\xabCr6\x066\x1es,\x80e\xd0D\x17j\xd9\x0e\x1c\x8beZ}.\xac\xe2\x12\x16\xc4Z~c\xc6\xc0\x02\xad\xca\xac\x85\x88\x1a?\x13\x1d\x97\x04c1\x19EJ\x9a\xcfpF\xa2\xf2\xdf\x94C\x16!Z=Ns9\xc5\xb4$|N+\xb1\xbf\x14\xa1|\xa3zK$\x0fU$\xd4\xa7{\xb94\xd1e\x07a\xf4lv\x7f\xcd\xc4]R\x94-\xe4U\xb9\x8f\x9e\xd4U\xdf\x96;\xcb\xa4?\xb5=Q\xe7\xe0B\x1f\xe5\xc9\x92T\xd7\xa7V\xf5\x7fz3\x86\x04\x8fEq@J\x84\xf6\x98\xcb\xb8\xa2:\x82\xd7\x1bD\x0f\"\xe9<\x9a\x03F\xd1\x14P\x9a~E*\xd6\xad\x80E{\x1b-k-$E\x15\x872%h\xa4\x8d\x02\x84\xc6$B\x02W\xc98\x05\x05\xd5\x87\x05#\xd5\xbb#4J\xf2x)j\x88\xa0Q!ry\xc5\x94F\xa9\xd9;\xd2Jh\x18\xc2\x8d\xce>\xbd\xe1K\xab\xb54\x05\x15h\x95\xaa^\xab~\xb5\xbd\x16\xfbQn\xb9A\xb1\x9b\xc8\x84\xb2l)\xc5\xa1\xdc\x8d\xcd!4e\xd6]\xd8\xd5\xa7\xb1*\xe1\xd3\xf8\xa5\xab\xe7\xbf7\x9a\xeb\xf2\xf0\x96\x10@ac\x19\xdd\xffF\xcdY\xef\x10@\xd1\xeb\x9d\x92\x0e\xb7\xdb\xfd7\x19<\x9d|)\x8b\x13\xef0:\xdc\x8f\\\x19\x9a\xba\x9d\xf7M\xba\xee\x1bv\xdc\xcdn{\x98\xd3\xee\xe1\x97\x14\\\xe9\xe5\x93\x14^H\x93\x91K\xe8\xcb\x8ei\xe8\x1d\x90\xde\x01q\xda+\xf7\xeae\xd7M\xd8\xa9\x1fK\xdc\x16%\xbf\xfd\xd0\x0b\xd5\xbb\x0d\x04\xad\x97\xb2J\xdd\xaa\x90\xe1\xc3\x19\x16(F\x02\x99\xd5iM\xf0\xbcTm\xde\x15M\x1a\n6J\x94\xb9^v\xa7\xf5j\"U\xdd\x84p\x81\xa5\xa0\x934\xa8\xba\xaa\x8b\xe8\xf6;^\xcd\xc1\x8a/n\xad\xde-'~Kvz\x9d\x06]\xb7\xabZ\xa2aN\x890\x0cb\x9f\x9a\x06\xebS\x95\xceijpMV\x83\xf3\xc1J\x8f)\x97\xe06?\x9a_\xcb}]\x9d@\xea\x0dQ\x9c\x1c\xd7\xefHL\xc8\x056g\xe7\xd6\xfb\x92DWw\x16\xf43\x0bw-\xb9&\x80\xafRF\x8d\xef\x10\x97`\xd7zu\xa8i@C\xe0\xb7\x840*\x95x\xd6 \x95\xb2K\xed \x1d\xec/~W~\x18\xa3\xb6$j(n\xaeX2\x94\x14d\x88\x14\xe9(\xeam\xb1J\x00\x13\n,\x8bq&\xff\x8e?\xe7(1\x1e\xda.@\xad\x9e\x96J\x9f(\x11\xdb\xbc\x10\xff\x8ef\x07\xc5\x92>\x83\x83\xff[Mq\x81\x8d\xab\xb9\xba\xb8R\xda\xb5\xb5I\xb0\xb1f\x8d\xc5\x0d\x8c(\xc3\xea\xf1rG\x87\xd5\x04d\x17\xdb\xb2\x8bmGv\xb6\x86\n\xf7g\xf0p\x17\xc44\xe7O\xe1\x00d{9\xb5\xfd\xff\xfb\xd0\x83UQB\x10\xb7\xefb\x1f\x99\xa2\xc1!Y4x\xefx\xd7aF \xc5\x14t\xdc+!\\\x91\xb1\xd8\xeb\xe5o\xa5\xbd\xed\xbd\xdf\x8d\xdf\xd8\x02\x99MX,km{!\x89Y\x1e\x89\xe5\x1cg\xe4D\xad\xe1A\xe5\x05\xb7\x14\xfb\x88D\xda\xdb2\xad\xb4\x9b\x945\xcd\xb2,6K\x92\xd6\xf7\x99\xb2%\x8c\x9d\xe9}\xd90.\xea \xf7Lg\x15\xe8/\xe3\xe40\xcbsQ\xff\xa6\xb7\xeb\xce\"\xc2+\x7f\xa9fg\xecO\xed\xf8\xda\x9e\xdb7l\xac\x98\xf04A\x86c\xce\xf0\x19Zx\xac\x18\xa9\x8a\x97\x15j.\x9fL0\x97\xfe_!\\%\xa7U\x93uu\xa6\xa3\x96\xdavl\xbd8\xe1\x83\\e\x8f\xba9\xbf\xb5=\xb23\xb5\x9b\x03*\xa3\xb7J\xf8\xafY\xc4\x84j\x85*7Ri\x14\xb7+\x9b\x9a\xa9\xacP\xe9\x8f\xde\xfb\xa3\xf7\xfe\xe8}\xde\xf4\x03\xbd\"]m\xdd\xec-9\xaf\xfd\x01|\x1f\xffj\xfb\xfd6\xc5\xbf\xfa\x03nw\xb0\x0b\xfa\x03\xee\x02\xae\x99\xb8\xee\xa3\xd9\xfe\x80{\x13T\xec\x0f\xb8\xff:\x07\xdcKA\xf8\xe2\x1dX[~{@\x08^\x9du/\xbc\xe3\x86Oo\x8e\xb8\x7fk\x01w\x93e\xd1\xc9uq\x86\xcd\x1d:\xde\x192w\x05\xb7\xacA-\x8f`\xb9\xcb\x02\x02\x9f@\xb9\x87!\x03N\xdb}\xf9\xdb\x80\x10\xb9#(\x06\xea:\xa2o\x80\xdc'<\xee\x1b\x1c\xf7\x0d\x8d\x87Pf\xb3aqwP<($\xee\x8c\x13Bh@|\xadp\xf8\x86\x83\xe1\xddB\xe1\xeb\x07\xc2=\xc2\xe0.9\xa1\xc1#\x04\xee\xb9\x97]\x01\x05\x0d\x9b\x0d~\xdbv\xb9O\xdc\x0f6\x1d\xf6\xee\x1e\xf4v\x91\xafK\xc0\xdb\x8a\xac!\xdcm\x0ev;\xf9\xc0Ofm6\xcc\xed\x17\xe4\xb6\x86\xb8\xc3\xe6e\xe4\xa4\x0d\x06\xb7\xfdB\xdbn\xb4\xd6\x0bk[\x82\xda\xbe1\xb7\x0d\x85\xdc\xfa\x88[\x1fq\xfbf\"n\xcb:),\xa3K\xfe{=\x03j\x83Ig^9]\x81\x85\xb6\xc5J\x9d\xe9+\xd5\xd5R\xa9\xe9\xa54hz\xfemW\xde^\xc3=\xe4\x98\xc6CL\xd1(\xc1\xf1\x9f\xdd\xbf\xb3NS\x83)\"\xb2\x0c\xed\x11\x92e\xf03@\x00>b\x1a\xbf\xd2\xc8\xe9\xfa\xa0\xcd\x9d\x88\x1a\xab\x04\\ \x91\x9b+\x14\xee\\N\xb1\xaa\"\x88\xaa\xddm\xb6\xfee\xc7\xb2\xd7v+E\xab\xae\xa1/\x8f\xd8\x88\xe1\"X\x83T'\xd6\xe2\xf1\xa59\xde\xb2\xaf[\xfa\xf2\xaa\xf6]\x1fi\xd5\x16\xa8\x0e\x0e\xb4,i\xdb\x94\x8d\xba\xfe\xbd\xd2\xef\x95\xfe2\\\x83\xd2\xf7\xd2\x9fJH\xf4\x13\x9e7\x92=\xce\xf1|\xf9\x8eW\xce\xb1\xf91\xa1\x12\xde\x17Q$\xf8\xa5\xe4GsB\x8e\xba\xfa\xe0\xe6\x02'I\xdc\xcejE\x8b\n\xabOj\x93\xb4|\x1cIy@y\xce\x87*\xc8\xe7\xb3\x9b,l\xeafP\x83$(\xc19\x02x\x8d\"a\x86\xae\x86\x92c\xbc\xac\x0f'\xd1\xfd\xc8\xae\xa1 \xfe\xb6~\xe3vV\xbcI:Q\xf76\x8aG]\xf7\xb7\x1d\x98O\xda\xca\xad\xd5\xe1\xc6\xf1fYyy\x86\xc1\xbd\x033\xfe\x0d\xbd\xaa\x94T\x91\xc6U\xbd\xa4\xa5.\xc8\xf2\xf2\x19i\x1d,\xe5\xe4K\xeb\xfb\xaa\xa0\x8cn\x12\xe3\xd6\xca\xaf%l\x98m\xd0\x04\x0fi>\xd3j\xeb\xe6\xd7\xc1\xd72\xd1\xf0\x0e]\x01\x9a\xa8kf%\xa1v\xd5\xcb\xd9\ny\xdbc\xc3\x1aN\xab[ \x12\xc3<\xd1\x05\x0e#\x94Dy\x82\x84\xd6\xf0\x84\x03q\x1a\xdd\xef\xd0\xd5\xf1\x04\x97\xef)\xc1\x1e\xfc\x8e.p&QS\xa8\xb8\xf0\x10d\x86\xff0{\xe1\x8b\x95\x89\x8b\x116\xb4.\x9b\xa1\xb6\xc4\xdeM\xeb7\xd5\x1d\x8b\x88e:,\xbf\xb0VQ\x9ans\xd8\xca\xe9\x88Q\xe3\x8b^\x0bHqFX\xbc%\xf7\xa5~-\x9a\x93\x191>\xa6\xb7\x80\x19\x8e\xa6\x88\x12>S\xeb\xf0[\x81k\xba\x1a<\x84\x88\xc7\xd45\xf8\x10@C\x1f\xf8u\xf6\xd8\x07~=\xd1\xec\x03\xbf]\x03\xbfv\n\x1bR\x9d\xbc\x12$\x97\xba\xd2\xe9\x92\xa6t\xac>_RC\x9f/i\x97\xb6\xbe\x02\xe1\x18>}x\xbb\x97a\xce\xf2,*^\xfcW\xe6DN\xc9\xe7\x1c's\x90\x1e\x84 \xe3\xea\xf2\x94\xe4\\\x8b;\xa12\xdc\xab\xd7\xec\xcd[Re\x1eG,\x81Q>\x1e\xe3\xea\xf5\xecA\xe1F\xaa\xb9\xe9x]a\x1e\x012+\xd4\x04#[!\x1dF1l\xedmA4E\x19\x8a\x04\xce\x06*B\x94 .\x80\xe3\xc9\x0c/*\xa5}\xfa\xf0v\x9b/\xa7i6A!UUy0\x8f*\xbb\x1b\xe7\x89\xba|\x86\x12I\xc1\xb8Q\xbb\xabg\xa2\xba]\x14\xf3\xb08\xd7H\xda\x89\x8c\x92\x08%j\x0f\x99GV\xd5{v%ic\xb9\x14[\x83-)\xc5\xa4\xf7\x80\xa2\x08\xa7B\xc5+\xcc\xcd\xdfPH%\xb1I\x84wA`i\xe7\xe6\xa6\xf3\x01\xfc\xc0.\xf1\x85\xd4\x0bcf.#\xf5\xe9\xc3[^d\xe2\xe7\xba\x12\x93\xe5\xc6\xb1\x94\xa0\x18\xce\xa6B\xa4g\xbb\xfaO~\xb6+\xdd~\xca\x8a_\x17E\x8fX\xaaukkE\xe2\xa2C, O\x01\xa9\xb9\xdbn:g\x17:\n/\xf4\x1dk\xc5Z\ns\xc1\xaaw\xe9\xd5\xd9\x10\xd1\xca\x0f\x99\xfd\xcd1S\xd6\xc1S\xcb\xda\xfe\x1d\xde\x8c\x173\x92lQ\x94\xd2\x8e\xabI+\xdb\x87\xf3|\x86c\x8b^\xfe\xbb\xd4M?\x9c\x9e\x9e\xc0\xf7\xafN\xcb\xe0\xf9\xa7\x0fo\xf5\x1e\x9b\xab\xfb\x10\xe6\xa2P+\x0f\xed\x9f\xceS\xfc\xeb\xbf~56\x80\xb2\xd21-\xf8\xadP#j\x85\xd2\x8c\xc5y\x84\x95\xa9%U\x989\x18\xf7w8^XN\x1cP\x86\xb5E\xa5kUG(\x92\xb2\x85\xb1\xf3<\xad\xf2\xa5G\x88/U=\xac\x83\x9e\xb8\x05\xedO\x1f\xde*\x1c\xa7\xe8B\xb1\xe0\xac\xb6\x87b\xbd\x89P9%\xf9\xf7\x0bFb@\xd4\xe6\xcbh\x04\x95\xf8\xc8\xf0\x98ex\xb7\xec@\xf6\x8b\x04\x19\x91\x84\x889P\x8c\xe3\xb2\xb4\xa7\x12y\xd9\x85e&j.\xd1\x14\xd1 V\x8d\xd4\x9e\x1d\xc0\xce'\x8eK\x9fYRI\xb2\xa7\x8a>(\xfeD\x14Ml\xb3\x1fe\x18\x9dK\x19Tt<\xb8k\xe6(}\xce\xa3\xa2\xfb\xe3\x9cFz\x87\xc9y\x14\xb2+\xca\xb3L\x95\xc2\xad\xd7\xd46\x8bK\xc9\x8fL\x15\x7f5\x97\xd2.t\xd9(\x1f\x83t\xd9\x11\xc7\xbb\xca@\xd5\x05S\xe5\xa0\xaa\xe8\xac\xb2\xf6\xca}i\xecJ%yQ9Y{i3\xd9\xd3@\xf3?J \x1fDlf\x93\xc6\x1f\xd5N\xe5ET]\x1d\xd7-I)\xd8)\xae\xeb\xe8\n\xaczk\xdf5+Ae\x8d\x8e,BIW\xda\x95\xceKu\x83I\xbb <\xc5\x11\x19\x93\x088\x9e!*Hd\x88A]\xc3\xa5\x8fe\xf0\xb5\x92\xde\x15\xe7\x86H\xc7\xe2j\x06\xce\x8a\x1dS(w4b\x17f\x9e.HPl\x85\xf6\xfa\x14n\xcc\xce\x8e\xe9\xfc\xac\x16=\xa2\x80\xb2\x11\x11\x99\xdc\xc4f\x0c[\xbb*u\x04JX\xc1z\x80\xda\x97VJ\xe7\xa5Bm5\xb3p\xc9\xfc\xab\xac:\x03k\x9e\x94\x1b'!#\x85v\xf5$\x03\xcf\xd3\x94eJ\x83\xa7(:\xdf\xcb\xa9\xfcC\xeam\xcd\x17\xed;\xa8P\xf4f\xc3\x86\x8d!\x17Z\xb0\x95\xe2\x81K\xc1Z\xcbN\x9d`\x8a3\xe5yk?\x8b\x17\xd3j\xedO\xe2\xa3\x97\xb0}\xbcWWH2?\x1c<\x85\x13\x89\xbf\x94\x0b\xc5TPEtB\xe1\xc5w\xdfY\xd4\xe4k\xc6`\xcc\x18<\x83\xc1`\xf0\xef\xc6\xcf$2\x88\xce\xcd\x1f :\x1fH4^gl\xb63f\xec\xae\xf9\xd3\xc1\xc0\xac\xff\xc8\x18vdW\x9f\xd4DN\xd9\xce\xdfd_w\xe1w\x8b\x0c\xb7\xf5\xf7\x87\x9dv\x87\x0e\xda\xfd\x88.\xd0\xc6\x88\x07\xcf\x94m(G\xd9\x00\x85\x08\xdfy\xcd\xd8 J\x10\xe7\x0e\x02i\x14e#=\xc7ZC3\x0e\x06\xcaU\xa4\xbb\xef \xdd\xc9\\L\x19\xb5\x10Oc\xf5\x9a\xb1\x9d\xc1``\xd6\x06\x15\xe1v\xac\xdf(\xe6Sd\xedJU\xd9\xc9\x1bM\xd4\x97\xaf>\xbe\xf8\xf0\xe6\xe4\xf4\xfd\x87\xbb\xd6\xb3\x85\x8aQ\xed\x03\xeb\xa1\xed\xe4E\x89$\xb2}\"6\x12.caA\x81\x8c\x97\x10\xf8Dg\x0b\x14\x14\x82j\x83\xa8\xaf\xfe\xed\x19P\x92X\x19\xdc\x8e\x97\x81\x93OUy\xa4\xe8\xbc\x92\xc5\xa5\xa3\x01\xa3\xf9\xc2\xec*\xb5\x87\xaa\x19?j\xb7z\xcbR\xf297\xd8,\xdb-&\xd5\x9e\xf4\xdf\x07\xea\x07i\xaen\x03\xaai;\xa9 %'\x98t\x83\xe6\x90\xf6\xc1*\xd5B\x93y\xe9W\xae\x04\x0b*3\x19\xd0XgY\x19.\xc3!.`{o\xbb}\xa8B'\x96(+o\x17p\xc1\xd1[c\xc6\x06#\x94\xa9\xc9^\xed\xcd\x07_\xb64\x15\x95\xef\xd5\xda\x9f\xd9\x15U\xa8n\xc9>\xa4:l\xfd\xe4\xc7\x8f\xef\x7fn\xff\xe5\xd9\xb3g\xcf\xcc< \xdb-b.\xda\x8edR\x1c\x14F\x90\xf6\xeb\xd4\x99\xa7\x8e\xb3Nrc\xda\xc8j7\xb2I\x8c\x17f\xcb.\xe0\xd9\x08\xc7\xf1\xc2\x80\xd95\xa7M\"C\xf4\xa6fR\xe8\x8b\xfdg\xff%IwV\x04\x13\x1a\xe7\x8b\xe5\xe2\xb4o\x90B\xfc<\xb58 (:\x972h\xe1\x10\x8fI\x82\xcdz\xa3\x94Y'8\xe3\x8cZ\xb7m\x11\x89\x1b\x93\x8c\x8b\xa1Z\xe1gp`\xee\xb9j \x99\xb2\xfc\xfe0\\\x83\x01X\xb1\xdaR\xb4\xdcz\n[m\xbb\xb6I\x86\x81\x9e\xe5\x96\xed\xcceK\xcd\xefg4\x93}\xfe\x87\x9e\xc2\x7fZ\x1b\xc8\xf9-}\x1f:\xc97\xe3\xc2\xe1j\xf2\x9a\xe6\x06\xc2\xe1\x12'\xc9\xbds\xca.u9\x89)\xe2\x80lE\x83\xcc\x9b\xab\xc9\xf2\xbb\xda\x80_\xda\x07Zx\xd6\xd0\x91\x0clp\xae\x90f\xe9\xf6\xc1\xce\xd4f,\xf9|\xca\x92\xb8^\xb9BoeB\xab\xfd\x01:\x02\xd8\xde\x95\xde2\xed\xe3(\x14\x06\x95r\xde\x91r\xad$\xe1Jh\xa8\x8c\x98\xfe\xfa\xaf_\xefZ6\xd2&x\xae9\xa0\x9d\xed\x14\xa9d\x97\x07\x83\xc3\x83C\xbeea!\xfd\xa7\xadl\xc1\xb4~\xbd\x1e\xd6\xaf8\x00\x864\xb1\xe5J\x04\x1fqvA\xd4\x13\xf5\x96R\x04|/A\x02\xf3\xe2\x94\xcaP\x81\xe0\xad\xfa\xe4yQj@\xe4Y!\x1fu\xd32\xd7K\xb7[.5Pk{\xa7\x9c\xeb-\xad0\xa0\xe61$-\xb7\xbb\x8d\x9d\x81\xf3\xd8h\x8a\xf8\xd4\x96\xcba\x89\x958\"%)\xca\xc4\x90c1\x9cb\x14\x9b\xd2\xfd\xad\x98\x83\x13{ \x96W\xf8\xc0y X\x82O^\xa3\x99T\xe0C.p\x93\xacJ\x02:A\x99\xe0X\xfc\xa0(\xb7\xba\xdc\xfa#\xc5\xb4o^\xb6q\xc9fY\xe4z\xd7\xcf\x99\xc2ULWgf\xeb\x1cyB\xc7\xa6\xb7\x1c=p\x02/\xbc\xc0}G\x03|\xd7\x1d\xfc\x93\xcbT^\xdb\xcd\x0e\xe9\x135\xd4P\xe5\xa0A\x84R]\x1b\xaa8\"+\xfe9\xcb\x93\xe2y\x884cR&:\n+T\xeb \xd5\x05\x88h\x8a\x08\xdd\xb5\xb8\xc4\xc5\xdbU\xfa=\x8a\xa4\xd6H\xd5\x0f\x01]<_\xe1V\xf8Y\x1a+K\x87e\xf4uq>\xb3m\xa9\x10\x0c\xaa\xde0\xd6y!\xda\x18\x99\xa1hJ\xa81\x0fVa\xd7*\xb9K\xf0XRS\x81\x99\x12<\xba\xf0\x93s\x82\xcc\x9c\x17L<\x87\x89\x91\xc0\xf7d\x7f\x86/\x95\xb9o\xd6k%lpG\xdb\x858\xf8N\x10|\x84\xb9\x06/=X\x82\xd7L\xc1{\xb6\xe0\xd6\x8f\xd5g^z\xb2\x04\x1f>*\xc1Mr\x08!;\xf8\x93\xdeS\x9f.}\xdc\xaeWKP,\xab/\x15\x0co\xc2\"\x80\x05br8\xac\x0e\x16\xb4\xd4\xac\xbd\xe0\xb6\x0c\xf2\xa7\x1bBo\x91g~C\x03.\xd3c\x9c\xa9W[\x94\xfc\x06\x96\x8b4\x17\x8b\x7fK3|a\xbd\x9d\xa1^H\xbd\xf19,.\x9b\xde\xccx(Moh$\xb5?\x8a\x04\x86\x1b\x1a\xb2\xbc\xafrC\xc3U\xfc\xb70{,\xf6\xa8\x14\xd4\x8c\xe3l\x88\xe28\xc3\xdc\x95\xb8\xbe6~\x0dcN\x0b\xbc\xc6\xfd\xee\xca<\xd2\xa5dO1\x8d\xd5%\xa0\xc2O.\xac\xfd\xd6\xc3ecu6\xa7\xd6rk+q\xe5\xa4\x8c=\xcf\xde\x99e\xefE^\x0f\x02C\x90\xc5|zU$\x9f\x95\x812ed\xea\x93\x08mF\xfeW\x11\xa0\xd0\xa9\xba\xdf\x1dx\xdc\xd2Q\xe9tI\"\x89\x06S\x9ca\x95L\xa4d\xd8\x00\xe0\x9fx;\xc3\xf0[\xce\x05\xa0I\x86\xb1}\xbaE\xf6\x94~\x15P\x853\xad\xe3\xab4\xcb\x19F\xb4\x98\x95F\xfd8M\x7f@|\n1\xc3:u\xa5x]\x16Tb\xb4mM\xae\x0cY\x1c\xae\xdb\x83/\xa5\xa5\xdf\x08\x86\xab7\x94\xc7\xcdd\xed\x02\x8d\xf2QaC_&\xed`\xbfl\xbd\x01\x9e\xf7\xbd\xcd\xbd\x11\xc6w\xda\x94n|5\xc4\xb9\xf6\x92\xf0\xf0\x82 q\x0d\x8ck\xfa\x14~a\xc2\x1a!Y\x02\xf3\xba<\x85\x13e\xf0\xa0\xc4\xaf;WT\xa3 \x1d6N\x88\xa7\xaa!c9\xb5>\x89U\x870\xb7Y\x83\xed\x16J;\xb8C$M\x08\x94u\xd0A\xde\x81\xb7g\xbf\x80\x0e\xcb\x07\xbe&\xd92\x04\x85]\x9a\xd0\x81z\xd0\x91\x82\x12<\x034M\xe8\xc2w%\x84o\x89\x12B\x17\x1c\xba/:t]\xf8\xc0\xa0O\x13\xbcB@M\x10d\x86\xb9@3G\xd0~\x01\x1d\x08\xe2\x1bOm\xc2\xa22\x9c\xd3\xf7l\xc2\x1a\x18z/\xd5\x029\xcf\xdb\xba\x1a\xba\xf0}\xb8\xbc\xad\xde\xbe\x08C\xeb:)\xd6\xc5\x04\x91Z\xbd\xf9\xb2p\x9aai1\xef\x167AfD\xddb\xf1\xeaL\x7f\xae\x0cn\x1d^\xab\x15\x98\x183g\xb1\x1d\x0d5\xbb\xc5\xf5\xa9\xb2\xecG>\x0b\x10(\xafC\xe5to\xd9/Ao\xd9\xf7\x96\xbd\x1bz\xcb\xde\xf55\xf4\x96}\x98\x0e\xd4\xd0[\xf6F\x08\xdf\x12%\x84.8t_t\xe8\xba\xf0\xbde_Bo\xd9k\x08\x97\xb7\xbde\xbf\n7m\xd9+\xb18\xbc`\x82\xd0\xc9\xd0Y\x0b\xbaj\x15\xb6\x10a\xa2p\xc1\xb3\xb7\x03\x9f \xd1\xd3\x11\x13_\x91\x13\xca\x9f/\xcb\x03\"\xc9\xa4e\xc9\xc9\xc5a]\xad\xba\xa4\xa5JC \xd5\xc2\x14f5\x88K&\xfb\x1a'$R%y%\xd7:x.\x91\x86\xe80J\x08\xa6b\xa8\x8b\xb5~\xedc\xab\xda\x0cLO\x02\xacB\x00.\x10\x88\x0f\x14\xa2\x11\xc7\x81VU N\xd0\x01/p\xe4 \xb7C\x07\xc4\xa0#r\xe0\x93\xc5\xdc\x0e\xa1\xb9\xcd\xed\xd0q\xae\xb0\xc6|\xc1/;\xba\x1d\x02\x05\xd62\x94\x02\xcc\x99I\xdd\x0e\xce\xfc\xeav\xf8\x9aH\x87\x8a\xe0e\xf0\xcb\xdb\x0e\xee\xb6\x99\xe7\xbd\x94\xcd\x1d\xdc\x9bg\xf6w;\xf8\xe6\x84\x07w\xdc\xc8!\x0f\xce\x14o\x87\xd0\xfc\xf1vpg\x95\xb7CgF\x0e\x8b\xe8\x94\xd0y\xb8P\x9b\xa9\x0e\xf6\x1c\xf6v\xd8\x00\xa2\xbe&U\x13<\xb3\xe0\xdb\xe1+\xc9\xfe.\xf1\x02X\x8f\xc8\x10\xeeZ5a\x8d\xc0Q kP\x1b\xd6\xa48t\x0d(\x95\xd0\xc5\xc1^\x86\xee;\xb2\x84\xae\x8c\x03\xeb3\x0f\xac\xcb@k\x05\xa0J\xe8\x10\x88*\xc1\xff\xeeA;\xacA\xbf5\xe8\x16~{\xa1\x1d<\xee4\xb4\xc3\xd7\x98\xb6\xf7\x8d\x82v\xf8\x1a(\xbb\xb3n\xcd\xe0{\x15#\xb8c\x9f\x875\x9a\x10v\xa1\xa3\x1d\xbe\x06\xf9}\xaf\x84\xb4\xc3\xd7\xc0\xd8}\xa9\xa4\x1d\xbe\x06\xae\x01\xd7R\xda\xe1k \xedy\xb1\xa5\x1d\xbe\x06\xc2aWc\xda\xc1\xff\xc2L;\xdc\xfc\xbc\xd7\xf1\xce\x9d7t\x82z\x0b\xb8\xcd\xd3\x0e\xda\xb8\x08!yG\x8b\xb8\xab%\xfc\x0d\xf9\xa0A\xd9\x06%\xacc\xa4\x87\x9f\x86\x95\xd0;\x9f>\xd0QY[\x1c\x07\xe4h\xac\xc2\xc6\xd0\xefv\xe8\xa0!8\x1d\xaa \x1b\x9bC\xa7%X\xc7\xef\xd2\xf0B\xb9;\x1f\xc9DgpK\x1b\xad<\xe2S\x19V\xe5\x05\xf2\x0e]\xab\xd7fu\xff\xfe\xee\xd7zs\xd2\xa35\xaf\xc5W\xd96\xea\xba~\x987\xa9]\xc8K\xc4k\x8f\xe8\x8e\xe6\x80\x8a\xbb\xf6A}-\x02r~\xd4X\xc8\x08\x8e\xbd\xdd\xbd\x0ez\xbf\x8b\xb6_\xcc\xc5\xbfMW+\xa8\x83\x05\xd4\x81\n\x1a\xba\xd0BCg9\xbe\x96\x00YCx\x14o\x05wE\xb8\x03qa-\x02K\xc0\xf1\xe1\x83\x07\x07O\xba4]\x93\xd0\xb0\x1e\xb1A=6\x15\xa5\x87\x0f\x1e\x9e\x1f|\x8b\xe8\xafc\x91\x9d\xa8\x17\x9b\x7f\xc2\xf3F\x8c\xef\x1c\xcfy\xed-\xa1nvT\xce\xb1~t\xe5}Q6w\xf1vth\x9eKh2n\x13\xd6Z\x9du\xbc\xfa*V\x9cf\x84eDt\xde\xd07\x8a{\x89u\x08\xb2\x1d\xe5NW\x89\xd3Q\xa0\xafA\xcc\xce\x1b\xb4\xa3(\xefHPX\x83\xa8\xb0\x9e\x10_\x83\xb8\xb0\x0e\x81a]\xf1\xfd\xf5\x10\xef.\xb8\xafMloLh\xaf#\xb2\xd7X\x91n\"\x0f6!\xaco\x1c\xebn\x17UJ\xe8\x88n\x18\xaa\xd23ct\xe8\x7f,\x16\x88U\x186\xa3\xf9\x17D\x05\xa1x\x18\xe6#\x85\xf9F\x01>Q\xb0\x94\x0f\x97\xed\xc1\xaa2p\x054t\x10\x82\xc1\x8a1\x98X\xd0\x89`\xd0U\x0dv\"\x1ct#\x1etWz7\x8bf\x17\x15w\x0d\xcam\x03j\xad\x9b\x9c\xedD\xed0\xa9\xa6a\x0d\xf5u\x038vSU\x81\x88\x05\xa2\x14\x12\x1f\xef\x88\x89o\xec;4\xac\xfaV\xaa\xd3\x17\xea\xc6\xe0\xb1\xba0\xb8\xee=\xc6\xa2\xf1\x9a)x\xcf\x16\xc0;w\xc4o=K\xf0a\xa0\x12\xdc$\x87\x10\xb2\x83?\xe9\x03\xf36\xbc24|r1|lj\xa7%\xed\xc9\n\xbe\x8c\x10\x94\x1d\x11\xb0\x18~\x19\x0f]s\x1b:f1t\xccW\x08\xcfLX+\x07\xc1\xdf~\xdcT^AP\x06Ap\xae@\x00\xd7\x04l`OK\xa6\xc3\xe0~\x16\x8c\xf79}\x07\x0c\x1c\xd3\x0f1\x9d|\xcf\xd3\xd5\xe9\xb8GO\xedg\xc5~\x18y\x9c\x86\x1bN\xb8\x0d\x1d\xa2U#\xae\x89\x9f\x1d\xaf\xe6c\x83\x1f\x8aw\x02%\xa1\xf4\xdb\xb3\xc5\x7f\xcb\x05\x94K\xd3\xb2\x95\xfe\x91\xe3l\xbe\xb7\xf4\xe0\xe1\x87\x93\x17\xc5\xbb\xc0\x0bdJ\x81Pk\xdf|\xb1\x90BN\xf1U\x8a#9a\x9ce,\xab\x10\xa8\xb5\xd9\xd0\xbb\x85\xaa\xffU\xbe\xb5pj\xc4\xe2\x16F\xb7\x1b\x076#\xaf(\xb1\x17\x84C\x8c\x05\"I\x8b\xb8\xb1\xe9U\xa3>u\xe8Q\x97\xfe\x94\xcd\x87yf\xb4\xa0\x92ly\x8d8c\x82E,\x81Q>\x1e\xe3\xeaQ\xd6\x81~sB\xcf\x0df9\xaf\xb64 \xb3I\x92`\xc4\x85y,F1l\xedmA4E\x19\x8a\x04\xce\x06\xea\xbdh\xf5$6\xc7\x93\x19\xa6\x95\xdc\xfa\xf4\xe1\xed6_~\x0f\xb5 \n\xa9\xaa\x18\x93yT\xd1\xf2Z\xb7\xa2o1\x94\xa2\xe4\x0e\xe2@\x0c\x8fCK8\x93\xa8\x18\xdf\x8d=\xbb\xabg\xa2\xba\xe5S\x96'1\x8c\xa4\xdc5\xf6\x87 B\x94Q\x12\xa1D\xed!\xf3\xc8;x0\x19\xecJ\xd2\xaa:\x0b[\x83-)\xbc\xd4[$Q\x84S\x81\xe3\xbb\x03\xc3\x03\xde\x12\xdePH%\xb1I\x84wA`4\xe3\x90\xf3\x1cIr\xe8\x92U)I$\xa6\xfaa_\x18\x11\x8a2\xb3\xe5\xaa\x9e?\x99\xa7\xb8x\x87DL\xf1\xdc<\xb4\x16u@\x84\xf4\xb4s^\xaf\xb5)\xf0\x95Z\xeac:\x1f\xc0\x0f\xec\x12_\xe0l\xd7j\x95|\xfa\xf0\xb6\xb4z\x8a'\xd8\xcd\x03+ \x8a\xe1l*Dz\xb6\xab\xff\xe4g\xbb\xc02\xa0\xac\xf8uWqc\x84(\xb0T\xbf\xfc\x9d\x98\xa7-5P\x9e\x16\xc5F-\xe3\xe2\xecB=\xfd\x8e\x04\xccP\xca5k)\xcc\x05\xab*\x8e\xaa\xe0\x1f\xd1O\xa5 s\x94n\xcc\x92\x84]\xf2\xa7\x96\xb5\xfd;\xbc\x19/f$\xd9\xa2|q\xbf\x9a\xb4\xb2\x088\xcfg8\xb6T6\xfd\xbb\xd4M?\x9c\x9e\x9e\xc0\xf7\xafN\xcb\xc7i>}x\xab\xf7\x98z^\xdeb8\xac\xbc\xdf|:O\xf1\xaf\xff\xfa\xd5\xd8\x00\x8a'\xe0 -\xf8\xadP#j\x85\xd2\x8c\xc5y\x84\x01Q\xad\xc2\xcc\x89k\x7f\x87\xe3EA\x10\xae^\xe3A\x92f8\x96\xe4\x8eP$e\x0bc\xe7y\n\xc5\x15D\x18!nI+d\xae\n*\xeaI~\x96\xc1\x14](\x16\x9c\xd5\xf6P\xac7\x11*\xa7$\xff~\xc1H\x0c\x88\xdaNW4\x82J|dx\xcc2\xbc[v \xfbE\x82\x8cHB\xc4\x1c(\xc6\xb1b\xa3\x91\xba\xd2\xabX\xcd\x96 \xc9\xa8\x14\xb3t\x82U#\xb5g\x07\xb0\xf3\x89\xe3\xb2f\x92\xa4\x92dO)\xb34\x7f\"\x8a&\xb6\xd9\x8f2\x8c\xce\xa5\x0c*:\x1e\xdc5s\xd4\xcfL\xe0\xa7 \xa4\x0e\x19\xe74\xd2;L\xce\xa3\x90]Q\x9ee\x98\x8ad^\x0b}[\xc4\xa5z,i<&\x11A\x89C\x97\x8d\xf21dXj\"\xbc\xab\xca\xc8\x10Q\x0e\x9as\x1ck#\xaf\xdc\x97\xc6\xaeFxB(\x95\x93\xbd$bjQ.\xab\xaf\x8b\xdb\xa4\xf1G\xb5S901\xd5\x82\x82.K)\xd8\xd1F(\xe0Y*\xe6\xc5\xd6\xbekV\x82d2\x150\xb2\x08%5iuF@fi\x82g\xd5\x1b\xf2<\xc5\x11\x19\x93\x088\x9e!*Hd\xc8\x11U{u\x0d\x13\xc8\xc3\xe1\xf1\xb5\x92\xdeIq4\xc2\x80\xb43P3pV\xec\x98\xb2d\xd0\x88]\x98y\xba A\xb1\x15Z__\xf3\xc0\xec\xec\x98\xce\xcf\x16\x1e\x0f\xa2\x80\xb2\x11\x11\x99\xdc\xc4f\x0c[\xbb*u\x04JX\xc1z\x80\xda\x97VJg\xa5h4\x86\xa3\xa6Y\xb8d\xfeUV\x9d\x815O\xca\x8d\x93\x90\x91B\xbb\xd0#\x1cx\x9e\xa6,S\x1a\xde\xab+$\x99\x1f\x0e\x9e\xc2\x89\xc4_\xca\x85b*\xa8^\n\xfc\xc5w\xdfY\xd4\xe4k\xc6`\xcc\x18<\x83\xc1`\xf0\xef\xc6\xcf$2\x88\xce\xcd\x1f :\x1fH4^gl\xb63f\xec\xae\xf9\xd3\xc1\xc0\xac\xff\xc8\x18vdW\x9f\xd4DN\xd9\xce\xdfd_w\xe1w\x8b\x0c\xb7\xf5\xf7\x87\x9dv\x87\x0e\xda\xfd\x88.\xd0\xc6\x88\x07\xcf\x94m(G\xd9\x00\x85\x08\xdfy\xcd\xd8 J\x10\xe7\x0e\x02i\x14e#=\xc7ZC3\x0e\x06\xcaU\xa4\xbb\xef \xdd\xc9\\L\x19\xb5\x10Oc\xf5\x9a\xb1\x9d\xc1``\xd6\x06\x15\xe1v\xac\xdf(\xe6Sd\xedJU\xd9\xc9\x1bM\xd4\x97\xaf>\xbe\xf8\xf0\xe6\xe4\xf4\xfd\x87\xbb\xb6(\xd9\x82Q\xed\x03\xeb\xa1\xed\xe4\xd1\xd9\x02\x05\x85\xa0\xda \xea\xab\x7f{\x06\x94$V\x06\xb7\xe3e\xe0d\xe9\xdc*:\x97\xb2\xb8t4`4_\x98]\xa5\xf6\xd0\x8fn\xb6[\xbdE\x90L\x9a%\xedCm\xb7\x98T{\xd2\x7f\x1f\xa8\x1f\xa4\xb9\xba\x0d\xa8\xa6\xed\xa4&,\xca\x05\xb6v\xa89\xa4}\xb0J\xb5\xd0d^\xfa\x95+\xc1\x82\xcaL\x064\x16\xb8-D\xa8A\xc51\xb6\xf7\xb6\xdb\x87*tb\x89\xb2\xf2v\x01\x17\x1c\xbd5fl0B\x99\x9a\xec\xd5\xde|\xf0eKSQ\xf9^\xad\xfd\x99]Q\x85\xea\x96\xecC\xaa\xc3\xd6O~\xfc\xf8\xfe\xe7\xf6_\x9e={\xf6\xcc\xcc\x03\xb2\xdd\"\xe6\xa2\xedH&\xc5Aa\x04i\xbf.\xe7\xb8\x0c\xafN\xf2\x04\x19JY\xafv#\x9b\xc4xa\xb6\xec\x02\x9e\x8dp\x1c/\x0c\x98]m\x8e\xb7u\x87\x0c\xd1\x9b\x9aI1V\x8e\xec\xd9\x7fI\xd2\x9d\x15\xc1\x84F\xa0\xba\\\x9c\xf6\x0dR\x88\x9f\xa7\x16\x07\x04E\xe7R\x06-\x1c\xe21I\xb0Yo\x942\xeb\x04g\x9cQ\xeb\xb6-\"q\xea\xad\xd8\xa1Z\xe1gp`\xee\xb9j\xa0\xf2\x12\x8a\xef\x0f\xc35\x18\x80\x15\xab-E\xcb\xad\xa7\xb0\xd5\xb6k\x9bd\x18\xe8Yn\xed\xda\xfaS\xf3\xfb\x19\xcdd\x9f\xff\xa1\xa7\xf0\x9f\xd6\x06r~K\xdf\x87N\xf2\xcd\xb8p\xb8\x9a\xbc\xa6\xb9\x81p\xb8\xc4Ir\xef\x9c\xb2K\xaa\xe4\xcc\x14q@\x10\xe5\\\xb0Y\xe0\xe6j\xb2\xfc\xae6\xe0\x97\xf6A\xf9bq\x85\x8ed`\x83s\x854K\xb7\x0fv\xa66c\xc9\xe7S\x96\xc4E\xf9Y\x85\xb9\xde\xca\x84V\xfb\x03t\x04\xb0\xbd+\xbde\xda\xc7Q(\x0c*\xe5\xbc#\xe5ZI\xc2\x95\xd0P\x191\xfd\xf5_\xbf\xde\xb5l\xa4M\xf0\\s@;\xdb)R\xc9.\x0f\x06\x87\x07\x87|\xcb\xc2B\xfaO\x81&\xb5C\x83{\xf0\x11g\x17$\x92\xd4\xdb\xdeKF\xb3\xbd\x11\xe2x\x8f\x15Iy{\x17\x07{\xea\xcc\x8b\xef\xfd>E|\xfa\xc7\xb6n:Y\xdc\xb1\xe4\xf9l\x86\xb2\xf9S\xf8\x1e\xeb\x13\xa6\xe7s\xf5\xb6\xf3\xe7\x1cg\x04\xf3\xe2\xc8L\x92vB.0U\x89\x15\xa5\x94b)\xd6s|\x13/\xb7/\xbe(O\x99j(o\x1f\xee\xefo\x9b\x8f\xaa\x80\xe7Q\x849\x1f\xe7I\xd5\xba.\x157tHe\xce\xff1v\x06\xce\x83\x1bs\xd2\x893Z\xe1\x88Ux\xe5\xf3X1\x07'\xf6\xe0\xce\xdb\x11^\xf9:>y:7\xf1t\xbfW\x1e\x8e5\xff\xc6P\xf1|\x1d\x16\xb9\xde\xf5s\x96\xa5\x0f-@\xef\xc4 \xbc\xf0\x02\xbf\xf2\xf1^\xeb\x0e\xb5\xb5wVWw\x16\x7f\xdf\xf4\x90>q;\x0d~E\xda\xa1Yt\xdd6\xd5F9v\xdf\xf2\xea\xbe\x85\xd4\x9b\x85\xd1-\x1d\x86\x96L\x0f-\x8e\xee.\x83\xee\xb1\xa47\x96\xd0j/L\x1e4\x8c+s\xc8\xb3\xac\xf8\x06w\xb4;\xc9\xd2k\x82\xe0#\xcc5x\xe9\xc1\x12\xbcf\n\xde\xb3\x05\xb7~\xac>\xf3\xd2\x93%\xf8\xf0Q n\x92C\x08\xd9\xc1\x9f\xf4\x9e\xfat\xe9c{^\xab\x7f\x81k\xaf\x19y\xcd$\xbc<\xb5G!\xeaM\xa1\xe7]\xc7xS\x03.\xd3\xc3Y\xd1\xd9Z\xa19\xac\x16\xf3\xa6\xe6\xe0[IyS\xe3\xb9\xeb oj\xa4\x80*\xc6\x9b\x1a\xd2\xb3\x06\xf1\xa6\x86\x0b\xab \xec_+x3\xf85\x8c9g\xe9\xde\x90r\xbcR\xa6\\\x9b\x17 \xae\x9c\x94\xd9\xc8=\x01\xa7\x82q\x12\x18\x82,\xe6\xd3\xab\"\xfd\xab\x0cU)#S\x9f\x05h3\xf2\xbf4\xe1\x07?(\xfb\xee\xbb\x03\xeb\xa3\xca?\xab\x07\x93UB[\x92H\xa2\xc1\x14gX\xa5\xf3(\x196\x00\xf8'\xde\xce0\xfc\x96s\x01h\x92al\x9fn\x91\xbf\xc42\xc9'*\xa0h\x1d_%:\xce0\xa2\xc5\xac4\xea\xc7i\xaa\x0201\xc3:y\xa4H\xa2\x96]s\x9b\x82\x16W\x86<\nW\xca\xffKi\xe97\xc2\xd1E\xe2\xb32\xcaQqH^\xcf\xe56'+\x99\xb4\x83\xfd\xfd\xbd\x0d\xf0\xbc\xfb\x81\xbf\x0d2\xbe\xd3\xa6t\xe3\xab!.\xdfN\x1c\xaa\xe7\xef\xdd\x93\xd0\xe0\x89\x05\x04`\x02\xe5\x13\xfc\x06\xb1\xd4\x84\x00\x04 \x10 (\xbb\xf7\xfa\xd2[\x14\xd5\xc1\xef\xfaP \xfd\x13\xfc\x05\xf4O\xf0\xd7\xa0\x7f\x82\xdf\xabMPQ\xfc0\xb7Y\x83\xed\x1eH;\xb8C$M\x08\x94u\xd0A\xde\x81\xb7g\xbf\x80\x0e\xcb\x07\xbe&\xd92\x04\x85]\x9a\xd0\x81z\xd0\x91\x82\x12<\x034M\xe8\xc2w%\x84o\x89\x12B\x17\x1c\xba/:t]\xf8\xc0\xa0O\x13\xbcB@M\xf0\xbeyYB\x07\x82\xf8\xc6S\x9b\x10|1\xb5\x8450\xf4^\xaa\xfe \xfe0\x8au1A\xbe\xe9'\xf8\x95e?\xf2Y\x80@y\x1d*\xa7{\xcb~ z\xcb\xbe\xb7\xec\xdd\xd0[\xf6\xae\xaf\xa1\xb7\xec\xc3t\xa0\x86\xde\xb27B\xf8\x96(!t\xc1\xa1\xfb\xa2C\xd7\x85\xef-\xfb\x12z\xcb^C\xb8\xbc\xed-\xfbU\xb8i\xcb\xfe\x16\x16\x82\\\xf0\xec\xed\xc0'H\xf4t\xc4\xc4W\xe4\x84\xf2\xe7\xcb\xf2\x80H2\xe9\xbaE)\xab\x85)\xccj\x10\x97L\xf65NH\xa4\nSJ\xaeu\xf0\x9c*W9\xd4\xe5(\x87H\xd5\xca\xfc\xda\xc7V\xb5\x19\x0c=\x92L5\x04\xe0\x02\x81\xf8@!\x1aq\x1chU\x05\xe2\x04\x1d\xf0\x02G\x0er;t@\x0c:\"\x07>Y\xcc\xed\x10\x9a\xdb\xdc\x0e\x1d\xe7\nk\xcc\x17\xfc\xb2\xa3\xdb!P`-C)\xc0\x9c\x99\xd4\xed\xe0\xcc\xafn\x87\xaf\x89t\xa8\x08^\x06\xbf\xbc\xed\xe0n\x9by\xdeK\xd9\xdc\xc1\xbdyf\x7f\xb7\x83oNxp\xc7\x8d\x1c\xf2\xe0L\xf1v\x08\xcd\x1fo\x07wVy;tf\xe4\xb0\x88N \x9d\x87\x0b\xb5\x99\xea`\xcfao\x87\x0d \xeakR5\xc13\x0b\xbe\x1d\xbe\x92\xec\xef\x12/\x80\xf5\x88\x0c\xe1\xaeU\x13\xd6\x08\x1c\x95\xb0\x06\xb5aM\x8aC\xd7\x80R ]\x1c\xece\xe8\xbe#K\xe8\xca8\xb0>\xf3\xc0\xba\x0c\xb4V\x00\xaa\x84\x0e\x81\xa8\x12\xfc\xef\x1e\xb4\xc3\x1a\xf4[\x83n\xe1\xb7\x17\xda\xc1\xe3NC;|\x8di{\xdf(h\x87\xaf\x81\xb2;\xeb\xd6\x0c\xbeW1\x82;\xb6]\xddh\x87\xb0\x0b\x1d\xed\xf05\xc8\xef{%\xa4\x1d\xbe\x06\xc6\xeeK%\xed\xf05p\x0d\xb8\x96\xd2\x0e_\x03i\xcf\x8b-\xed\xf05\x10\x0e\xbb\x1a\xd3\x0e\xfe\x17f\xda\xe1\xe6\xe7\xbd\x8ew\xee\xbc\xa1\x13\xd4[\xc0m\x9ev\xb0=\xca\xd3\x0e\x1d-\xe2\xae\x96\xf07\xe4\x83\x06e\x1b\x94\xb0\x8e\x91\x1e~\x1aVB\xef|\xfa@G\xf1\xa0\xa1w>;\xf3u \xdd\xb7b ]\x19\x07\xd6g\x1eX\x97\x81\xbe\xb6\xf3\xe9\xf3\xa0S;h\xca\xf9>\x9dZ\x07\xe7\xdd\xb6vXk\xa3\xac\xb7M\x82\x9e\x8fj\x87\xb5\x19-,\xa3\xb4 ]\x1f\xa0j\x87\x8e\xcfR\xb5C\xc7\xc7\xaa\xda!\xfc \xabvX\xeba\xabv\xe8\xee\x85k\xd8\xd4#X\xed\x10\xf44V;t\xce^j\xc2\xda\xfbdmq\x1c\x90\xa3\xb1\n\x1bC\xbf\xdb\xa1\x83\x86\xe0t\xa8&ll\x0e\x9d\x96`\x1d\xbfK\x83\xefc`\x1d\xba&\x14\x90\xf5\x89\xb0vXgN\x1e\xcf\x89\x05\xf5\xd7\xfe\xf4X\xf5\xc8XP_\xa6\x07\xc9L\xb0\x90\x11\x1c{\xbb{\x1d\xf4~\x17m\x1f\xf6p| \xdd\xac\xa0\x0e\x16P\x07*h\xe8B\x0b\x0d\x9d\xe5\xf8Z\x02d\x0d\xe1\x11\xfc\xf0| \x9d\x89\x0bk\x11\x18\xba>H_\xc2Z\x84\x86\xf5\x88\x0d\xdd\x1f\xaa/\xe1\xeb\xa2\xbf\x8eEv\x0d\x0f\xd9\x97\xb0\x81\x07\xedK\x08M\xc6m\xc2Z\xab\xb3\x8eW\x9fv\x7f\xf0\xbe\x84\xaf\x80{\x89u\x08\xb2\x1d\xe5NW\x89\xd3Q\xa0\xafA\xcc\xce\x1b\xb4\xa3(\xefHPX\x83\xa8\xb0\x9e\x10_\x83\xb8\xb0\x0e\x81a]\xf1\xfd\xf5\x10\xef.\xb8\xafMloLh\xaf#\xb2\xd7X\x91n\"\x0f6!\xaco\x1c\xebn\x17UJ\xe8\x88n\x18\xaa\xd23ct\xe8\x7f,\x16\x88U\x186\xa3\xf9\x17D\x05\xa1x\x18\xe6#\x85\xf9F\x01>Q\xb0\x94\x0f\x97\xed\xc1\xaa2p\x054t\x10\x82\xc1\x8a1\x98X\xd0\x89`\xd0U\x0dv\"\x1ct#\x1etWz7\x8bf\x17\x15w\x0d\xcam\x03j\xad\x9b\x9c\xedD\xed0\xa9\xa6a\x0d\xf5u\x038vSU\x81\x88\x05\xa2\x14\x12\x1f\xef\x88\x89o\xec;4\xac\xfaV\xaa\xd3\x17\xea\xc6\xe0\xb1\xba0\xb8\xee=\xc6\xa2\xf1\x9a)x\xcf\x16\xc0;w\xc4o=K\xf0a\xa0\x12\xdc$\x87\x10\xb2\x83?\xe9\x03\xf36\xbc24|r1|lj\xa7%\xed\xc9\n\xbe\x8c\x10\x94\x1d\x11\xb0\x18~\x19\x0f]s\x1b:f1t\xccW\x08\xcfLX+\x07\xc1\xdf~\xdcT^AP\x06Ap\xae@\x00\xd7\x04l`OK\xa6\xc3\xe0~\x16\x8c\xf79}\x07\x0c\x1c\xd3\x0f1\x9d|\xcf\xd3\xd5\xe9\xb8GO\xedg\xc5~\x18y\x9c\x86\x1bN\xb8\x0d\x1d\xa2U#\xae\x89\x9f\x1d\xaf\xe6c\x83\x1f\x8aw\x02%\xa1\xf4\xeb\xaf\xc5\x7f\xcb\x05\x94K\xd3\xb2\x95\xfe\x91\xe3l\xbe\xb7\xf4\xe8\xe1\x87\x93\x17\xc5\xcb\xbc\x0bdJ\x81Pk\xdf|\xb1\x90BN\xf1U\x8a#9a\x9ce,\xab\x10\xa8\xb5\xd9\xd0\xbb\x85\xaa\xffU\xbe\xb5pj\xc4\xe2\x16F\xb7\x1b\x076#\xaf(\xb1\x17\x84C\x8c\x05\"I\x8b\xb8\xb1\xe9U\xa3>u\xe8Q\x97\xfe\x94\xcd\x87yf\xb4\xa0Sly\x0f8c\x82E,\x81Q>\x1e\xe3\xeaY\xd4\x81~sB\xcf\x0df9\xaf\xb64 \xb3I\x92`\xc4\x85y,F1l\xedmA4E\x19\x8a\x04\xce\x06\xea\xc5f\xf5(5\xc7\x93\x19\xa6\x95\xdc\xfa\xf4\xe1\xed6\x87\x14\x19^R\x96\xa0\x90\xaa\x8a1\x99G\x15-\xefe+\xfa\x16C)J\xee \x0e\xc4\xf0<\xb3\x843\x89\x8a\xf1\xe5\xd6\xb3\xbbz&\xaa[>ey\x12\xc3H\xca]c\x7f\x08\"D\x19%\x11J\xd4\x1e2\x8f\xbc\x83\x07\x93\xc1\xae$\xad\xaa\xb3\xb05\xd8\x92\xc2K\xbdE\x12E8\x158\xbe;0<\xa1-\xe1\x0d\x85T\x12\x9bDx\x17\x04F3\x0e9\xcf\x91$\x87.Y\x95\x92Db\xaa\x9f\xd6\x85\x11\xa1(3[\xae\xea\xf9\x93y\x8a\x8bwH\xc4\x14\xcf\xcdCkQ\x07DHO;\xe7\xf5Z\x9b\x02_\xa9\xa5>\xa6\xf3\x01\xfc\xc0.\xf1\x05\xcev\xadV\xc9\xa7\x0foK\xab\xa7x\x04\xdd<\xb0\x92\xa0\x18\xce\xa6B\xa4g\xbb\xfaO~\xb6\x0b,\x03\xca\x8a_w\x157F\x88\x02K\xf5\xdb\xdb\x89y\xdaR\x03\xe5iQl\xd42.\xce.\xd4\xe3\xebH\xc0\x0c\xa5\\\xb3\x96\xc2\\\xb0\xaa\xe2\xa8\n\xfe\x11\xfdT\n2G\xe9\xc6,I\xd8%\x7fjY\xdb\xbf\xc3\x9b\xf1bF\x92-\xca7\xef\xabI+\x8b\x80\xf3|\x86cKe\xd3\xbfK\xdd\xf4\xc3\xe9\xe9 |\xff\xea\xb4|\x9c\xe6\xd3\x87\xb7z\x8f\xa9\x07\xde-\x86\xc3\xca\x0b\xca\xa7\xf3\x14\xff\xfa\xaf_\x8d\x0d\xa0x\x84\x9d\xd0\x82\xdf\n5\xa2V(\xcdX\x9cG\x18\x10\xd5*\xcc\x9c\xb8\xf6w8^\x14\x04\xe1\xea5\x1e$i\x86cI\xee\x08ER\xb60v\x9e\xa7P\\A\x84\x11\xe2\x96\xb4B\xe6\xaa\xa0\xa2\x1e\xc5g\x19L\xd1\x85b\xc1Ym\x0f\xc5z\x13\xa1rJ\xf2\xef\x17\x8c\xc4\x80\xa8\xedtE#\xa8\xc4G\x86\xc7,\xc3\xbbe\x07\xb2_$\xc8\x88$D\xcc\x81b\x1c+6\x1a\xa9+\xbd\x8a\xd5l \x92\x8cJ1K'X5R{v\x00;\x9f8.k&I*I\xf6\x942K\xf3'\xa2hb\x9b\xfd(\xc3\xe8\\\xca\xa0\xa2\xe3\xc1]3G\xfd\xcc\x04~\nB\xea\x90qN#\xbd\xc3\xe4<\n\xd9\x15\xe5Y\x86\xa9H\xe6\xb5\xd0\xb7E\\\xaa\xc7\x92\xc6c\x12\x11\x948t\xd9(\x1fC\x86\xa5&\xc2\xbb\xaa\x8c\x0c\x11\xe5\xa09\xc7\xb16\xf2\xca}i\xecj\x84'\x84R9Y\xf5\x9a\xbf\x19\xb1\xd5\xf7\xbdm\xd2\xf8\xa3\xda\xa9\x1c\x98\x98jAA\x97\xa5\x14\xech#\x14\xf0,\x15\xf3bk\xdf5+A2\x99\n\x18Y\x84\x92\x9a\xb4:# \xb34\xc1\xb3\xea\x15w\x9e\xe2\x88\x8cI\x04\x1c\xcf\x10\x15$2\xe4\x88\xaa\xbd\xba\x86 \xe4\xe1\xf0\xf8ZI\xef\xa48\x1aa@\xda\x19\xa8\x198+vLY2h\xc4.\xcc<]\x90\xa0\xd8\n\xad\xaf\xafy`vvL\xe7g\x0b\x8f\x07Q@\xd9\x88\x88Lnb3\x86\xad]\x95:\x02%\xac`=@\xedK+\xa5\xb3R4\x1a\xc3Q\xd3,\\2\xff*\xab\xce\xc0\x9a'\xe5\xc6I\xc8H\xa1]\xe8\x11\x0eX\xa5Zh2/\xfd\xca\x95`Ae&\x03\x1a\x0b\xdc\x16\"\xd4\xa0\xe2\x18\xdb{\xdb\xedC\x15:\xb1DYy\xbb\x80\x0b\x8e\xde\x1a36\x18\xa1LM\xf6jo>\xf8\xb2\xa5\xa9\xa8|\xaf\xd6\xfe\xcc\xae\xa8BuK\xf6!\xd5a\xeb'?~|\xffs\xfb/\xcf\x9e={f\xe6\x01\xd9n\x11s\xd1v$\x93\xe2\xa00\x82\xb4_\x97s\\\x86W'y\x82\x0c\xa5\xacW\xbb\x91Mb\xbc0[v\x01\xcfF8\x8e\x17\x06\xcc\xae6\xc7\xdb\xbaC\x86\xe8M\xcd\xa4\x18+G\xf6\xec\xbf$\xe9\xce\x8a`B#P].N\xfb\x06)\xc4\xcfS\x8b\x03\x82\xa2s)\x83\x16\x0e\xf1\x98$\xd8\xac7J\x99u\x823\xce\xa8u\xdb\x16\x918\xf5V\xecP\xad\xf0380\xf7\\5Py \xc5\xf7\x87\xe1\x1a\x0c\xc0\x8a\xd5\x96\xa2\xe5\xd6S\xd8j\xdb\xb5M2\x0c\xf4,\xb7vm\xfd\xa9\xf9\xfd\x8cf\xb2\xcf\xff\xd0S\xf8Ok\x039\xbf\xa5\xefC'\xf9f\\8\\M^\xd3\xdc@8\\\xe2$\xb9wN\xd9%Urf\x8a8 \x88r.\xd8,ps5Y~W\x1b\xf0K\xfb\xa0|\xb1\xb8BG2\xb0\xc1\xb9B\x9a\xa5\xdb\x07;S\x9b\xb1\xe4\xf3)K\xe2\xa2\xfc\xac\xc2\\oeB\xab\xfd\x01:\x02\xd8\xde\x95\xde2\xed\xe3(\x14\x06\x95r\xde\x91r\xad$\xe1Jh\xa8\x8c\x98\xfe\xfa\xaf_\xefZ6\xd2&x\xae9\xa0\x9d\xed\x14\xa9d\x97\x07\x83\xc3\x83C\xbeea!\xfdg\x8a24\xc3\x02\xd7\x13m\xef)\xc9\xabK\xee\xd5: \xf4\xe9r ;\xc3\x9f\xff?\xf6\xfe\xadIn#\xd9\x12\x85\xdf\xf9+\xfc\xd3wlH\xcd\x14\xabZ\xbdg^8GcC\x91Tw\xcd\xa8I\x0e/j\xdb6\xb6-\x85\xca\x8c\xaaB\x13 d\x03\xc8\xbal\xed\xfe\xef\xc7\xe2\x06\x04\x90q\xf1\x08D\x16\xab%\xf7\x87n\xaa\x12pD8\x02q[\xcbW\xec\xcb\x96m^@\xdf\xee\xcd\x90;\x96\xd3\x96%t_\\M\x1e\xfd\x91\xb57\xe5\x9a\xff\xfa\xf4\xac\xba\xd8\x9e]\x14\x1d;k\x14+\xf0\xec\xe6\xbb3\x01\xbaug\xbfJ\x12\xd1?\x9e\xca\x9b\xaf\xc64\xcfn\xbf\xdd\x16\xed\xfd\x0b\x132\x13\xd7\xc2\xdf\xf7\xac-Y\xa7p;\xfe~\xaf\xca\x1bV+>\x92\xee,\x9b\x1d\x93\xa1>\xdf\x1c\xfax\xa2+.\xe1.\xa3\xe8O\xff\xf8\x87?\x9c\x98\x95\xaa\xb4(u\xfe\xb8e\xb34_B\x8a\xdd\xc2[$S\x8b\xec\xeb \xa1\xbf\x03\xf4\xca~\xb4\x84\xd7\x07\xd8)\xd9\xdc\xa2\xb6]\xa6\x96\x10=H\x8c 7\xe4\x06\xcd\xd4R\xda\x9d\xb6\xf8OB[\xec\x0b\x87\xf4\x97\x0e\xa9/>r\xd3gj\xa8-\xa0\xa9\xa1S@\xb5%\x04\x04\xbb\x9f:\xb5\xe8\x0cYm\x0bJ\x88~Uc\xe1\xcaz\xc3\xee\xe2\x8a\x16\xd7\xee\xe3\xfb[tR\xad\xb6\xe3G,e\n\"2k\x07\xee\x86\xc8\xbbm\x19\x9f1\x9f\xa8\xa4\x90m)\x12ZP\xce\xe4\xe5b\xc2-\xb7\xd7\x0c\xc5\x92\xcb\xc6A\xa0\x9a\x9b1o ]*f\xf6\x17\x98\x17\x10\xd9_\xc7\xf6\xd34\xb3\x9f\x19\xcd\xecif\x1f6\x9a\xd9\x87\xae\x06\x9a\xd9\xc7\x8d\x81\xd2hf\xef\xb4\xf8OB[\xec\x0b\x87\xf4\x97\x0e\xa9/\x9ef\xf6\xdahf/-\xbe\xbf\xa5\x99\xfd\xa1=\xf4\xcc\xfe\x11*R\x8em\xf6q\x94'\xaa\xebI, \xb6\xcb\x89m\x9f\xaf5@\xc4\x1b\xe9Ru\xcc\xe1\xc5\xa8i5\xf4\xb7\x0d\xf7uY\x95k\xa1\x90\xc9[m\xa0\xcd \xdd\xcc\x95\xd4\xc5\\\x15B\xb4\xf3k\xc3VF\x0dV\x08\x92\xa9\xb4\x88\xb2@dy@u\x8dl\x139\xab\x8a,\x13$\x94\x0b\x02\x1cd\xbb%\x14\x0c\x12\x0b\x07\x18\x16\xb3\xddb\xb9\xcdvK\xac+,\xa8/\xe0\xd8\xd1v\x8b\xec\xb0\xe6\xa6;\xb0 \x93\xdanA~\xb5\xdd\xbef\xa1c\xbb\xe0\xb9\xe1x\xdb\xd1n\xa7<\xef\x19\x9b;\xda\x1b\x92\xfdm7,'<\xda\xf1\x84C\x1e\xcd\x14\xb7[,\x7f\xdcnaV\xb9\xdd\x92\x1br\xdc\x8e\x8e\xb6\xe4\xc7\xc5\xce\x99L\xf3s\xd8\xed\x96\xa1\xa0\xd8)\xd5\xd4\x90,x\xbb}\xa5\xbe?e\xbf\x00\x96\x05\x19\xe2\x97VS[\xb0q\xa4mA\xb4aa\xc4!uCI[\xca\x02{n\xe9_\xa4\xb6\xd4\x86\x03\xcb\x1b\x0f,m@\x8b6\xa0\xb4%lDi\xc3\xe7\x1e\xd8mA\xfc\x16\xc4->{\xc1n\x88\x9c\x06\xbb}\x8dj\xa33\n\xec\xf65\x8a\x1cf\xdd\xba\x0d\x9b\x8a\x11\xed\xd8\x97\xbaa\xb7\xb8\x84\x0e\xbb}\x8d\xf0cSB\xec\xf65J\x1cN*\xb1\xdb\xd7(kDZ\x8a\xdd\xbeF\xa1\x91\x89-v\xfb\x1a\x05\x8eK\x8d\xb1\x1b>a\xc6n\x0f_\xef%\xab\xf3`\x86N\x94\xb7\x88l\x1e\xbb\xf9N\x07\xb2[\xe2\x8c8u&\xfcO\xb4\x06\x8db\x1bh[2I\x8fG\xc3\xb4\xd1\xe2\x13c\x89\xdd\x834Z|&\xb7km\xe9\x9f\xa2\xb6\xd4\x86\x03\xcb\x1b\x0f,m@_{\xf1\x899Y\xcan2r\xd83\\M\x0b\xe6\xb6\xd9m\xd1\x87\xb2\xec3\x89:\xc7\xcan\x8b\x1bZ\x1c\xa3tj\xa9'a\xd9-\xf1|,\xbb%\x9e\x9ae\xb7\xf8\xb3\xb4\xec\xb6\xe8\x84-\xbb\xa5\xaf\xc2\xa5\xe5:\x8d\xcbnQgt\xd9-\x99\xbd4\xb5\xc5\xdf\xc9\xe2\xee8\x82\xa3qh\xd9\x8a\x9f\x06:H\x8b\xa6CM-[\x1d\x92^\xc1\x92u\x974\xec\xa9d \xae\xcb\x1a\n\xefYev[R'\xc4\xb9fQ\xfe\xecg\xa0\x0d\xa7\x9dE\xf9r\x9d\x8c\xe6\xb2\xb1\x8f\xe8\x18z\xb9\x970\xee\xa7\x8c\xf6q'\xd8kK\x9b\x05%\xcc\x80\x12\xa2 -%\x16\xd2\x92\xfb\xf1E\x1d\xc8\x82\xce#\xfa\x04|m\xc9\xc1\x85E\x01\x86\xd4\x93\xf1\xb5-\n4,\x0b6\xa4\x9f\x98\xaf\xed\xeb\x16\x7f\xc9\x8c\xec\x08'\xeak\xcbp\xb2\xbe\xb6X2\xee\xd4\x16\xbd\x9d%\xab\xfa]\xfa\xc9\xfb\xda\xbeB\xd9u\xa9c\n\x9b\xd8\xef\xa4\xf68\x89\x1d\xfa\x82`&\x7f\xa0\x89]yb@aAPaY'\xbe \xb8\xb0$\xc0\xb0\xb4\xfb\xfez\x05O\xef\xb8\x8f\xd6mg\xeb\xb4\x97t\xd9\x0b\xdeHZ\x97\x079:\xeb\x07/uZ\xa2\x8a\xb6\xc4\xe2\xc6\x15\x95\xaf\xcc\x9az\x85\x87\xc5\"K\x15W\x9a\x8b\xfb\x7f/\xea\xbe\xac\xd9*n\x8d\x14\xb76\x8aX\x13E\xf7\xf2\xf1}{\xf4P\x19\xf9\x06\xa4%t\x82\xd1\x03ct\xb0 )`\x90:\x0c&\x05\x0e\xd2\x82\x07\xe9\x83\xde\xc3\x163e\x88;\xc2\xe0\x96aXK\xebg\x93\xa2\x1d\xd7\xabI[0|=@\x19\xd3\x86\xaa\xc8\x82E\x16)f\x7f<\xb1$\xd8\xbd\xef\xd8m\xd5\x9f\xf8p\xfaJd\x0c\xbe\x14 \x83K\xf3\x18\x95<\xa9\x91Y[\xf4=\xdb\xeeD\x0ec\xdf\xc0\xb6\xec*Vl\xa0\x90\xd9\x8aA\x7f2\x9b\xd1\xb6\x97j\x90\x84\xed\x81\x0fv\xf3\xe1.=4\xdd@\xbdMLk\nph\xe4sB\xac\x02\x0c/&\xcc\x80 \x86\x0dP\xa1\x03\x14\x0d\x01\x15@\xc0\x8f\x19Q\xec\x13TM\x01][\x004w\x04\xf7>\xb5a\x1a\x90\xb6p\xc8!&\xec\x80\x0f}$o\x03\xc5\xd0\xc0p10s\xea\xe0L\x1a\xd9\x14\xb0\x0d!\x8a\x1d\x11\xf12p\x8c\x87TnC\"\x8b!\x91\xaf\x10\xcfLX\xc4A\xc0\xcf\x1fs\xf1\n\xa2\x18\x04\xd1\\\x81\x88V\x13\xf1\x01#g2 \x0f\xc7\xcd`\xd08}B \x02\xd5\x8f\x99:a\xf1t\x81\x8e#<\xd9\xb1b\\\x89\x10h\xb8\x03\xe1v8,\x0e'q\xd3\xf2\xf9\xcb5?n\xf0\x83:)\x90\x87J\x1eD\xab\xfe\x9b\xbfB\xfer,\x1f\xd3\xff\xd9\xb3\xf6\xfe\xec\xe0\xf0\xc3\x0f\xef_\xa9c\x82\xc7\x02\xe9N\xc1\xf00=\xb5\xb0\x86}\xcd\xeevl\xcd+\xcd\xda\xb6i\x87\"\x18\xf7d:\xbbP\xf8?l\xbb\x9e\xd6\xban6\x96\xc6\xee\x9f \xf8&zJf/\xaa\x0c\x1b\xd6\x17ee\xe9r|c\xabsL\x0d\x8c\xa5\xa11\x94\xdf\xbe\xda\xb7\xceY\x14\xe2\xcb\xc7}8\x00/\xe1\xf3\x87\x9f\xceZ\xd65\xfbv\xad\xce\x95\x16_\xcc\xbe.\xff\xbeg\xd5=\xf0\xcf\xa8//Kf\x1cJ\xeca\x84\xc8\x03\x1a\xf4\x99\xc9\x9e\xc3\x89\xdb\xa6o\xd6M\x05\x17\xfb\xcbK6\x9c\xd1z*\xcf\x9d\x90u\x83\xed\xbe\x1b>k(\xdc\xd3\x92\x8a\x15]\xef~VS3\xf8\xe6\xec\x1bX_\x17m\xb1\xeeY{*\x8e\x8f\x16'dw\xecj\xcb\xea\xa1\xef\xfa\xfc\xe1\xa7\xa7\xdd\xfc\x80\xd4\xa9\x89B\x0d\x82L\xee\xa7\xf6\x96\xc3\xbbE|\xd5\xa3D$\x9f\x15\x1d\x94\x8e\xb3\xa2\xb9\xfd\xc2\x8b\xe26\xfd\xf9\xd3\xa7\xf7\xf0\xa77\x9f\xf4\x015\x9f?\xfc$\xbf1q\xda\xbcg\xf2pp\x9c\xf3\xa7\xfb\x1d\xfb\xb7\xff\xfbo\xce\x1b@\x9d\x08_\xd6\xaa\xbd\xa9aD\xbc\xa1]\xdbl\xf6k\x06E-\x8707y\xed?\xc3\xcbQ\x14\xa4\x13'\xf2\x14H9>\xfd\xd6\xdd\xa2\xde6={\x01=\x1fC.\xf7\xf5Z~a\xbc\x1e\xaa\xefZ\xef\xdb\x96\xd5}uol\x7f{\xbaKq`\xd2\xe5e\xb9.\x8b*0\x96]\xec/\xa1e|$b'BJ\xa6\xec\xf5C\xf7\x1d\xdb\xc8i\x9e\xfe.\x9d\xae.\xd8UY\xd7\xbc\xb2\xb7e\x7f\xed\x19\\\x0e\x0f\x1b\xf7\xf5\xc6\x1f\xc5\x97\xdaA\xd3_\xcb\x8e\xa2\x9e\xf7R\xf0LNC\x81mw\xfd\xbd\xfa\xb4\xbfu\x0f\x82b6z\xe1\xe9\x94D\xa5\x05NPnw\x15\xdb\x0eG\xcaw;\xb6./\xcb5tl[\xd4}\xb9v\xf0D\xc5\xb7\xba`\n\x84X\xf4`gI\x7f\xe1\xdd\xd1\x05\x83B.\x08\x8c \xce\xc1\x05\xeb l\x88\x92\xfd\xf2\xb2\xbe\xffe\\\xf5\x145\x14\xedE\xd9\xb7\xfc#v\x97\xd0\xeaJ\x8f\x11E\xd5\xa8\xa6\x07\x85\xfd\xd5\xf2\xdeY\x0c4\xb2\x84\x17\xd3i\xe1l\xfa7\xcc\xea\x1cM\xf3\xbd\xfep\xaa\xf2B\x14[\x8d#\x1dt\xfb\xdd\xaei\xc5\x08\xbe+\xd6_\xce\xf65\xff?>n\xcbva\xff\x82\xd4@\xef\x9e\xd84\x97\xb0\xefe\xc7\xa6\xbb\x87\x8ew\xac\xc5fS\xca\xbe\x02\xaeX\xcd\xda\xa2\x17\x85\xe7\xeb,\xad\x04e\xf5\xc7\xcb#_\xa1\xfdyo\xee\n\xde\xf8\xe1\xbb\x17\xf0\x9e\x97\x9f\xf7\x0b\xaa*\x85)\x07\xfe\xea\xbf\xfc\x17\xcf0\xf9c\xd3\xc0e\xd3\xc0\xf7pzz\xfa\xdf\x9d\x97\xf1\xc2\x14\xf5\xbd\xfb\x82\xa2\xbe?\xe5\xc5\xf8\xb1m\xb6\xcf.\x9b\xe6[\xf7\xa5\xa7\xa7\xee\xf1\xaf\xbc\x84g\xdc\xd5gQ\x91O\xcd\xb3\xff\xc4}}\x0b\xbfz\xfap\x9f\xbf\x7f\xf8c\xf7\xc7@\xec\xfeWqSd\x0b\x1e|/\xe6\x86\xfc)\x19\"Tv\xcf~l\x9a\xd3uUt] @\xb2\x88\xfc&YG\xe3Fw\x19\x1c\x91\x1bB\xf7/\x81\xd0\xbd\xbf\xef\xaf\x9b\xda\x13|\xeb\xdb)\x1b\x1b\xaa\xff\xc1\xf2\xd1\xfep\xfe\xd7@8\xff\xd4x\x04\xe2x(_|\x0f\xffiwq\xfac\xd3\xfczzz\xfa\x0f\xf7\xc5E}\x7f\xc2\xa7\xa1\xfc\x8e\x9d\x9cD\xfd\xa5h\xbb\xeb\xa2\xe2A\xf6W\xc4\x17\xc2y)\x85\xc2\x18\xed\xf8H\xa8$\x03\xad\x0ee\x0b\xb1?l\x18Z\xea\xea^\xaf+\x0f6\x0b\x86i2\x14\x97=\xb3m\x12J\x13\xfb\x18O\xcf\x9e\xda\x1f\xa5\xc6D]d\xb1\xda\x05\xa6Z\xf47\x97MszQ\xb4\xa2\xb2wg\xf7\xa7\xff\xfe\x8d\x8c\xa2X{Y\xfd\xb9\x97\xa2\xa2\xa8\xdfp\x1f|8\xb4^\xf2\xbf>\xbe{k\xff\xe5\xfb\xef\xbf\xff\xde\xdd\x06\xf8}\xe3\x9e\x8b\x9cG6\xbc;P\x93 \xb9\xae\xdbwLo\xb0^\xed\xab\xc2!g}\xe8\x86\xdf\xb2a\xe3\xb4\xe5\x04\xd8\xf6\x82m6\xe3\x04\xe6DN\xc7m\xee\n\xc7\xee\x8d1\xa5\xb8\x14\x0b\xd9_\xfe'\x0f\xdd/j3a\xb2Y\xad_\x8e\xfd\x03Q\xdd\xcf\x0b\xcf\x02\xa4X\x7f\xe1}\xd0\xb8 \xbe,+\xe6\x1e7t\x9f\xf5\x9e\xb5]S{?[\xb5\x13'\xce\x8b]\x897\xfc=|\xe7\xf6<\xdc \xb8 \xea\xfa?\xc6\x8f`\x00\xdeR}#b\xf9\xcd\x0b\xf8\xc6\xf6\xd5N\xc3p*k\xf9\xcd\x89\xcf\x9f\xa8\xdf\xdbb\xcb}\xfe\xbf\xb2\n\xff\xc3{\x03\xaf\xdf\xec\xfa\xd8J\x9e_\xaa\x05\xd7\xb4\xad\xc9\xd6Pvp\xcb\xaa\xea\xf9\x97\xba\xb9\xadE?s]tP\xc0z\xdf\xf5\xcd6\xf2\xe3\x9a6\xf9\x139\x81\x9f}\x07\xfa\xd4\xe2\xa18\xbc\x01;\x16W\x85l\xd2\xf6\x87\xfd\">F\xdd\xce\xaf\x9bj\xa3$hE\xc9\xe5\xa7\\\xd6\xc3\xf7\x01r\x07\xd0\xeeJ~2\xf6\xe7\x88\"\x9c\x0e\x83\xf33\xde\xaf\xe9\x10\x1el\x0d\xe9\x1d\xd3\x7f\xfb\xbf\xff\xf6\xad\xe7C\xca\xd1\xe6\xa6\x0f\xf47;\x11*\xee\xf2\xbb\xd3?~\xf7\xc7\xee\x1bO\x13\x92\xff\xbf+\xdab\xcbzf\x92m\x9f\x8b\x9e\xf7\x85\xa2\xea\x18.\xca\xfa\xc5|+\xbbe\x7f\xdf\x97-\xdb\xbc\x80\xbe\xdd\x9bAw,\xa8m\xc4\x8b\xbe\xb8\x9a<\xfd#ko\xca5wvV]l\xcf.\x8a\x8e\x9d5\x8a\x1bxv\xf3\xddY\xddl\xd8\xaa\xac/\x1by\xd3\xd5\x98\xe5\xd9\xed\xb7\xdb\xa2\xbd\x7f\x01\x7fb\xfd\xdbf\xc3\xce\xeb\xcb\x06\xfe\xbeg\xadF\x1b\xd4v\x0dp\x17B_J\xf7\x90\xcd\x8e\xc9\xf8\x9eo&w?\xd1\xd5\x94\xf0\x96Q\xce\xa7\x7f\xfc\xc3\x1f\x9e\xba12\xe8\xf6\xeb5\xeb\xba\xcb}5\xdcmv\xc7\x99\xd015\x0dY\xcdbb\x9a\xd3+\x04\xa1#\xbd\xd4_y5\xca\xbd\x0f\x80\xe0C\xc4\x15\x7f\xf4\x00\xe4\x88\xbd\x99\xb1ayE\xb2\x03\xb2\xe3\xf9\x1e\xe4\x15\n\xcf\xf3\x98\xe9\x9bw\xb0\xcf\x02\x8f\xaa\xca\xaeg\xb5\xe0G$\xdd_\xb3\xfe\xb6i\x1d\x11\x0d\xdc\x8bhR\xce{\xd7\xd7E]3\x1b\xbc\x8a\xb89\xb8\x93\xb7m\xea\xf2\x8b\x8b\xe9\x16p.6D\x8f\xf6\x99\xf4w\xa1\x83q\x82u\x07hw\xeb0#\xc6\xe3\xc7P0w\xf7\x0b\x0b:\x1d1\xf8\xa4\xc4\xbe\xd8\xedV\xc97/i\x8eW%\x866\xeb\xbc\xfdb_V\x9b\xd5t\x14\x8c\xb8\xfd\xaa\xc1t\xcf\x81\xa7o\xd8\xce\xfbt7\x19\xd0K\x04\x0c\xb6\xf9PcP\xd7\x14\xbd\x97\x82\x89h\xf5\xe22IX\xdb6\x9b}\xc5\xfc\xa0<\xe2P\x8e\xa4\x87*\xbf\xce\xeb;?\x1b1\xee\x99\xebk\xb6\xfe\xd2\xed\xed\xb3\xfb\xe1\xaa\xbf\xc8\x92\x95\xc6\xd2\x91O}\x7f\x96%=\xb7\x8bpV\x17\xdbU\xb7\xf9\xb2\xa0\xe5M\xa6K\xc6\xc3\x0e\n\xc2\xff\xc3\x98\x91\x0d\xe4\xa7\x01\x0bpz\xb5\x11\xa9\x0e\xdc\x0c\x1c\xaa\xbf\xefY\xd7O\x1f;\x90\xa6f\xd3Am\xc4\x9e\x92F\xec)bO\x8dF\xec)bO\x8dF\xec\xa9\x9e\xd8Sv#\xf6\x946bO\x11{\x8a\xd8S\xc8Y\x12\xb1\xa7\x06#\xf6\x94i\xc4\x9e\"\xf6\x94\xc5\x88=e\xbd\x86\xd8S\xc4\x9er\x18\xb1\xa7\x88=E\xec)bO\x19\x96\x83\xc9B\xec)a\xc4\x9e\xfa\xad\xb0\xa7b\x99K\xdd}\xbd.k%_\xe2\xe0-}\x94\xd7\x0c\xb4%AUR7\xba\xd8J\xea\x1e\xf5\xeb\xa3%+M\xaao\x9a\xf4u\xd14\x15+\x0e\xb7\x7f\x86\xad\x03\xcb\xefA\xbcO\x85\x06%\x990\xe2}\xd3\x80j#\xb8O\x1a\xc1}\x04\xf7\x8dFp\x1f\xc1}\xa3\x11\xdc\xd7\x13\xdcg7\x82\xfb\xb4\x11\xdcGp\x1f\xc1}\xc8Y\x12\xc1}\x83\x11\xdcg\x1a\xc1}\x04\xf7Y\x8c\xe0>\xeb5\x04\xf7\x11\xdc\xe70\x82\xfb\x08\xee#\xb8\x8f\xe0>\xc3r@/\x04\xf7 #\xb8\xef\xf7\n\xf7\x8dj\xdf\xac\xef\xce\xaa\xa2g]\xef\xc5\xfe~\x12\x97\x0c\xc7\x1f}d\xfd\x00\x03\xca\xbbG\x01\xf1\xe7\x1d\xeb]p\xe0\xa1\x1bu\xe1\xa3E\x06\xe5\xe9\x0e\xae\xb3a\xbc\xfb\x0d\xbe\xa3<|G\xc9\xf5_\x01[\n\xa4]\x07\xf7U\x02\xe7\xb2\x05J\x07\x88\x12\x02\x02\x01\x03LQ\xa5avR\xb4\xc5\xa2a^g\xf6-\x11\xcf\n!7*\x06ad\x0c\x12\xd01\x7f\x05\x8a\xfe\x1a\x8d\x90A.\x94\x0c\x12\x912\xafC\x1e\\4Z\x06\xcb\x113\x88F\xcd\xbc\xae\xd4n~\x14r\x06\xb9\xd13\x88D\xd0 \x16E\xf3\xb7\xec\x01a\xc3\"i\x90\x1bM\x03\x1c\xa2\x069Q5X\x8c\xacA\x1a\xba\x06\xb9\x106HB\xd9\xfc\x9fC\xd1\xb1M\x18i\x83\xe3\xa0mpD\xc4\x0d\x8e\x83\xbaA$\xf2\x06i\xe8[\xa8\x0b\xc6!p\x90\x17\x85\x83\x08$\x0e\xe2\xd18H@\xe4\x10]\xe6\xb7\x08T\x0er s\x10B\xe7\x00?=C\xa0t\x109\x8b\x8bF\xeb\xbc\xde\x04\x92\x87@\xec \xa2\x94\x19\x91;\x88B\xef 7\x82\x07\x89(\x9e\xbf]ua$\x0f\xd2\xd1<\xa7?\xfe\xc4\x10\xa2\x07\xd9P=\xc0\x83S\x80A\xf7 \x0e\xe1\x83\xd0\x96|\"\xd2\x07\x08\xbf\x9e]\xbfL\xa8\x1f$\x05\x17\x8f\xfe\x01\xa2\x96 ( \xa4\"\x81\xe0\x8fj>D\x10\xf0\xa8 \x91A@\xa3\x83\x80\x8bz\x9fw\xb3\xb75\xab\x82\x98E\xb7\xacS\x08\xb7\xf8\xbc\xc6\xef\x91\x7fr\xa7\xeak*\xaf\xea\xa6\x9d\xed_\xeb\xafq\xfa\x08\x19\x99\xa5/\xf6P\xc4\xdb.\xef\xed\xd6Zx\x8a\x11[\xf8Uj \xfcCI\x1b8\xf4\x16\xac\x84\x02\xad\xb80a\xf3@\xd1C\x01W\xe5\x0d\xabA\xbav\x89/\xd8|>\xd1\xb1!\xf9\x05m\xfdW`\x11\x90\xfc\x82\xc7by\x0f^g\xf6\xcdo\xcf^Pn\xfe\x03\x849\x10\x90\xc0\x83\xf0W\x80\xe4\x17R\xb9\x11\x10\xcd\x8f\xf0\xba\"\xf9\x05\x92_H\xe5P@\x1a\x8f\x02rq) \x89O\xe1\xff\x1cH~!\x8e_\x01\x91\x1c\x0bH\xe3Y\x84\xba`\x1c\xd7\x02\xf2\xf2- \x82s\x01\xf1\xbc\x0bH\xe0^ \xbaL\x92_\x90\x16\xcd\xcb\xf0z#\xf9\x05\x92_\x98Y\x1e\xfe\x06\xe0i\x08\x80\xe1q@\x1c\x97\x03B\xe0k\"\xa7\x03\x10~I~\xc1cI\x9c\x0f \xf9\x05eI|\x10\x88\xe2\x84\x00\xc9/`\xb8\"p\x0c\xbe\x08`\xcaH\xf2\x0by\xb9$\x10\xe4\x93@*\xa7\xc4\xe9\x8d\xe4\x17p\x1c\x14\xa77\x92_@rS \x9a\x9f\x02$\xbf`\xb5\x14\xee\x8a\xd3\x19\xc9/h#\xf9\x05\x8b\x91\xfc\x02\xc9/X/\x08\xee(\x91\xfc\xc2\xefH~\xc1FE \x01\x86\xc1<\x8d\x89\x04\x18,\xb7\x93\x00C\x04\x01\x81\x04\x18H\x80a\xb4\xac\xc4\x82\x18RA\x14\xa1\x80\x04\x18\x96\x92\x07\x12\x88\x03YH\x03\xf1\x84\x01\x12`XB\x10\x88!\x07$\x10\x03H\x80\x81\x04\x18H\x80\x01\x0b\xecg\x05\xf5S\x00}\x12`p]\x16\x04\xee#@{\x8c\xbc@\x0cXO\x02\x0c$\xc0\x80\x01\xdeI\x80A\xd8\x12p\x9d\x04\x18l\x9e\x82\x00z*x\xee\x1c\x1bH\x80\xe1\xd0H\x80!\x01\xf4\x0e\x03\xde\xb1`w\x04\xd0\x1d\x0dr\xc7\x01\xdc$\xc0\x10\x07b\x93\x00\xc3`$\xc0\xa0L\xa7e_\x9b\xe9\xaf\xa0R\x86g[\xd9c\xc6p\xdf\xee#2\xc1\x83\x89\xe0$\xf9\x00\xe1(\x92\xe4\xc3\x11\x83\x1b\x16+ \xc9\x87\x1cQ$\xc9\x87\xdf\xb6\xe4\x83P|\xd8\x94\xbc\x85\\\xecyt\xcen\xbe;[7\xdb\xed\xbe.\xfb\xfb\xd5\xaei\x140m\xd3yx\xa5\xaf{\xdf4\xd5\xa0\xee \xd17\xf5\x0bp\x0f\xb0n\xca\xba\xb3\xca:L\\<\xd1\xb5~\xa4b\x0ec4L\xeb\xbf\x02i`\xc3\xeaf\x9b\xbc]^ly\x03O\xbc\x1d\xb3Y\xfd\x9a\xad_5\xa5A\xf3\x82\xbe\xf9\xc2j\xb5\xd7,K\xaf\xbfF>\xdb\xe5\x7fZ\x97\xdb\xc2\xce\xdb\x96\xc5u\xed\xba\xbe}\xf7\xe9\xcd\x0b\xb1n\x94\xd7\xa9\x05X)\xf6\xc8_\xb3\xb5\x9a\x9a\x0e\xb8\x849?\xb5:\x94\xcbu\xfb\xc3\xba\xf2\xaa.\xfa}\xcb\xba\xe1\xdb\xe4\x1d\xf5Us\xd5\x88\xc9\xe0\xe1\x9an\xca\x80\xe3\x1f\x83\x0e\xca\xf4\x1by\xdaM\xbf\x12\xcb\xdd\x07\xc1\x16\xec\xa1\xc9\x17\x94\xceA\x9a~\x88\xb3K\x88\x88$\x8d\x88H\xben\xe5\x08\x18\xde|\xe0\xfa?j\x80|j\x1d\xb76\xacbWB\x15\xe7\xec\xd7\xe1\xdf+\xa5M\xf3\x8f\xb3\x96\xdd\x16\xed\xa6\xf3\x08\x17\x19\x8b\x97\xd7\xf2\xfe\xb2\xa9?\xf1y\xc0\x07y\xefd\x90\x93\x13\x04\xe5\x15\x8a\xf5\xba\xdd\xcb\xee\xa0\x103\xb7\xc1\xd5\xc0\x9e\xb5\x8e\x80\xf6\x07\xa9+\x1f\xedP\xa8j\xfd8Z\xee\x10\xe0\xd5R\x1d\"Y-\xff\xed\xf6\xbaIs\xd6PZ\xa0\x9e\xd2B\xb5\x95\xe6\x9d\x01H\x0b\xd6V\x9a\x7f6 \x0d\xe5\n33\x90\x16=?\xf0\x06B\xcc\x1c\x02\xb3\x04iIs\x05\x8f?\xb5\xcb\xe5\x9b1H\x8b\x9f7\xf8\xb7U\xb4\x8d\x9d\xc7k\xdd\xdf\xc9\x0ed\xdc\xf0\x93}\xd5\xd8\xa8\xac~\x9aK\x11v\xe5\xe2i\xa7\xff\xcd_\x80\xfc&\x023\x1b\xdd\x0b\x0eo\xb4\xaa\xd4\x04\xc4\xd2;\x0e\x0f\x9a;u\xf0\xd3\xbfF\x9fB3\xec\xc1\x92\xbe\x9a\xaf4\xc3\x96c\xb2\x8e\x8a \xa8\xec\xb7\xa2yO\x1b\xa4g\x9a}\xf0\xa9\x89I\x87}\x98N\x9fo;\xe6\x174\xd3\x96F3\xed\x07\x9ei\xfb\xb0\x86\x83\xb9\xb4\xab%\x1e\\8\xf9\x12\x87_\xb5\\$\xf4\x8d\xcad\xba\x9c\x8e\x05\x0b\xb1\x8cc\xac\x1a\xce~=\x98e\xfa$P\xc7\xcf;r\xe50\x0e\xbc\x81\xd5\x02-\x14\x0e\x7f\x0e}x4\xa8\x0f\xf6\xcf4\xa8\xcf'\x97\xa1\x89\xa5\xf1\xf1X\xbc\x85\xc6\xf7\x8cC;\x8d\xeaS\xa3Q\x9dF\xf5\xe4Q},\xf9\xc1H\xec*\xf9\xc1\x85\x93\x92\x0f\xbf\x1e\xbb\xe4Y\xe7#\xa3\xf4wx\xfa\xd1\xb4C^\xf1t\x022:\x99-\xfd}\x93\x0e\xd3\xdb\x13\x1d\x85G:\xed8\x92@\xba\xe3\xfb\x0b\x0f\xeeF\xc0\xadM\xb03_\x02\x1fr\xf4Pf\xfd\xda/\xe7['\xf8\x01\xce|\x89\x8b\x87\xb8I\xfb\xa2AN\x1a\x0dr4\xc8=\x8e\xa1\x82\xaf\x1b6mq\xab\xff\x82\x190\xfe\xaa\xeey\xa9\xea\xa9G\x0d\xedk\x08@\xcc\xb81s\xfaD\xc7\xe5\x91\x0e\x1e\xf3\xb8E}\xae\xb32\xcf}%6\xab\xb8.~\x16\xef\x0c\xfd\xfc\xbcYPg/\x8d:{\xea\xec\xb3w\xf6\xd6\xbe^T\xbcs\xf7\xe0\xef\xc5\xefC\x7f-/\x1f\x12^\x0cg\xb0m6\xfb\x8a\xd9{l\xe3:\xe9\xf0\x89\xae\xd6#\xed\xab\xcd\xb0\x986\xe5]\xc9`\x98/ylG:F\xd3\xb0\x8c\xe6\xfd\x88\xfc\x9f\xd0H\xa4\xec\x8b;\xf77\xe6\xf9\n.\x8a\x8e\xad\x06U8\x1f=!\xe4\xa8\xa9\xf7]\x16O\x93\x11m\xc5\xea\xe2\xa2b^O\x87,\xd5\xd1\xec|Ui\x08\xf2\x9bl\xa3\xa8\xf1M\x8dh\xea3\xf9\xf0\xfe\xd5\xcc\x1f\x8df4\x9a=\xf8h\x167\xdd\x1fw\x0blh\x94\xa0m\x97]W6\xb5g\xa2?,\xd8_\x0dW\x0fcF\xb1^\xef\xb7\xfbJ\xe8!\x8c\xce\xc4\x07T\x04Xl\x16\xb7\xea\xb2G;r\x8c5\x0c\x8c\x1eF(\xcc\x11D\xfe\xb9TBF\xe3fb\xcb\xd6\xac\xbca\x16\xc6\xcc\xc2\x91\xc4UX\x08|P\x10\"\xa6\x05>,\x08\x96NZ\x90\x92\x86\xf8FB(\x1b\xe0\xdc\x847\xe4\xa4E#n\x9e\xcacihI\xc8\x9b\xd3\x1b\x92\x82\x16\x87\xc0\xb9\xb4LE\xf7d\xf9\xd4Q\x03\xb0\xcd\xd7\x99\xad;\x1a\xd7\x96\xc3-4\x18O\x7f\xa3\xc1\xf8\x08\x83\xb1oi\xf9\xdb\x86\x9c\x02\x13\x8bf\xdfw}Qo\xca\xfaj\x15&\xd1\x0f\x9f\xf4\xbb\xf1\xb69 F\xa3\xf7b\x13\xf1 (\xfe\x19\xc6\xa1\xdb':>\x8ft\xa6\x11\xe0\xc0$M\x08\x9c>\x81f\x03s\xa3\xd9\xc0\xcc\xe2f\x03\x80\n\xa1\xef\xb37\xc8\xe8F_bq\xf2l_?\xd7\xfb\x0b\xf5\xb7\xba\x91\xdb*2[\x94@)\x86\xff\xba+o\x98\xcc7.\xd6_N\xa4Tg\x07\x9d\x08\x1ftE]Z\xcf<\\_\xb3\xf5\x97\xf8\xd4;O\x95\x833\xa2\x99?\x8b\xd4\xecl\x82d +m\xc2K\xa3\x99\x12\xcd\x94\x1e\xc7L\xa9\xab\x8a\xee\x9a\xa1fG\x1f\xe5\xa5\xc3\x94H\xdc\n\xecF\xf6\x92\x97\xf8\x1d\x17\xe5\xe8\x89\xae\xfa#\x9d\x04\xa9\xd0<\x8e\x8fj|u;\xd6\x96M \xe3\x0f\xf5yx\xce\xc5\xb8\x14\xda\xe8\xae\xad\x9b\xe0S\xc2c/\xccZ\xc3\x1b\xde\x8a\xccQ\xd7\x1c)\x8d\x86\xe6\xd0@T\xc7O\x94\x9d\x98v\x94k\xa1W\xd2_+\xc5\x93\xaeoZq|\x89\xe3n\xa1\xe9_vBLZ\xabdWk\xb1\xad\x08\xc5\x8e\xbf\x99\xb6\x14\xff\xdej\x0d\x8f\xae\x17\x92\xcfVob\x06f\x9d\x01\xc89\xc0H\xf9\xd5\xca\xedE\xcb\x06\x8c\xa2Vjz\x85\xaa\xf5\xb5C\x0b\xbdY\x0b\xad\xe8P\x96\x9bj\xc3\xd3\xfc\"\xf57\xdc&\xe0\x92\xc3r$le\xc8\x98Lf\x16Y\xb7\x1b\xe9\xb0\x1c:,'\xe9\xb0\x9c\xc0\x96\xa1\x1a\xab\x82\xb3\xe3\xf0~\xa1\x1e>i\x0e,\x8d\xe6\xc04\x07N\x9e\x03\x8f%\xef\xfa\xa2\x15g\xdd\x1d\xe8\x0b\xfaf!\xb3\xbb&\x95\xd0'\x9f\x0c\x17)\xe9\xc2\xb1.\xf3o]\x8d\xa8\xf3\xfa\xc5\x8ac\x1d\xbc\xd0\x80\xea\x19\x93\x1b\x9c\xf9+.\x1d?\xd6j\x93\xacc\\\x18I\xd6\xf1\x88\xc1\x0d\xb7Q\x92u\xcc\x11E\x92u\xfc-\xca:N\xf8\xa3\xec\xa6\xdc\xb0z\xcd\xcen\xbe\x1b\xfe\xed\xde\x96zYUo\xd4E#\x1d\xa8\xaa@\xdfi\xdd\x822nz\xa2k\xf6Hw\x9f\xa6\x110\xed\x9fr>\x8b\xdb\x14\x02:\xf3\x91\xce|t^Ig>\n\xa33\x1f\x0f\x8d\xce|\xa43\x1f]Fg>\xd2\x99\x8f\xc2\xe8\xccGw\x9b\xa63\x1f\xa5\xd1\x99\x8ft\xe6#\x9d\xf9(\x8c\xce|\x14Fg>\n\xa33\x1f\xa5\xd1\x99\x8ft\xe6#\x9d\xf9Hg>\xce\x0d{\xfe\x1e\x9d\xf9(\x8c\xce|\xfc\xad\x9c\xf98\xdad\x85\xa8\xf1\x0b\x05TN\xc1\x99\x83\xf55\xb1\x0c\x85\x11\xcb\xf07\xca2\xb4\xa7\xe3\x18pd:\xc1\xd0\x04B?\xbc\x7f5\xaf\x04Q\x0d\x89j\x18\xda\x97\xc4l\xed\x01A\xb3\x04\xcd:\xaf$hV\x18A\xb3\x87F\xd0,A\xb3.#h\x96\xa0Ya\x04\xcd\x124K\xd0,A\xb3\xd2\x08\x9a%h\x96\xa0Y\x82f]F\xd0,A\xb3\x04\xcd\x124kX\x0e\x98\x8c\xa0Ya\x04\xcd\xfeV\xa0Y_\xc6?eQ\xc7\xa5\xa8R\x16\xf5\x11\x83\x1b\xce\xff\xa5,\xea\x1cQ\xa4,\xea\xdfr\x16\xf5Sg\x1a\xf5\xd9\xaf\xfa_\xab\xeb\xa2\xbb\xf6\x9d\x03~\x90T=\x10y\x04,\x01M=\xfe\x85\xfb\xb2\xe6Y\xffV\x92\xac\x93HB\xbd\x17\x90\x0f\xeeEc6s\xb3C\xf18 >\x05\x86\xf7\xc3\xedI`\xbbx\x84\xc3a\x10j\xcf\x00\xb4'\xc2\xecNp\x12\x07\xb2/\x82\xd8\x93\x00v(*\xfbA\xed\x80\x85\xd7S\xc0u\x1f\xe4\x85\x82\xd63\x03\xeb(X=#\xa8\x1e\x84\xd43\x01\xeaK\xe0\xf4h0=\x03\x94\x9e\x19H\x0f\xc0\xe8\xd9A\xf4\xe3@\xe8\xd9\x01t<|\x9e\x06\x9e{\x82\x1e\x82\xce\xb3\x01\xe78\xd8\xdc\xb2nw\xf7\xaf\x99!\xf3\x10`\xbe\x10.\xf7\x80\xe5\xc1\xe9I\x10(\xc7\xcd_\xf2\x82\xe4!\x88<\\\xa64x\\\xf7\xec\x16\x87!p<#4\xbe\x00\x18\xb7\xd3Y|\xb0x^P\xdc\x0f\x89\xe7\x00\xc4Q\x88n\x00\x0cGC\xe1n\xd4*\x1e\x06w\xfb\xb2\xee\x10g\x01\xc0c\x82\x85\x05\xbf\xc31A\x03\xdf \xb0\xb7}7=\x13\xe4\x8d\x02\xbc\xc3p7\x06\xec\xf6F1\x16\xe8\xc6\xc2\xdc.\x90;\x03\xc4\x1d\x01p\xa7\xc3\xdb\x1e\x10\x19\x0bmg\x06\xb6=%\xb2\xb6\xd4$H[\xefDZ\xfc9\x00\xed\xccp\xb6\x1b\xccN\x85\xb2\xc5\x8e\x80\xad\xe0v ;/\x8c\xedZ\xf8\x05!l\x17\xc6\xe6\x82\xaf\xf3\x82\xd7\xe9\xd0\xb5\x03\xa6N\x02\xa9\x83\x80t\x1c\x1c\x8d\x06\xa3#\xa1\xe8\x18 \xda C\xbbK\x83\x85\x03q\x10t$\x00\x1d\x01?[\xab\x96\x17zv}\x14\x0b`g\xeb>\x85\x13tN\x83\x9c}\xf0r~pyyKB\x03\xcbXXy:D\"\xb2\x1b\xa3R\x1bU2\xe3\x0c8\xd0Fg&H\xa3DFJd\x1c\x8d\x12\x19)\x91q\xb4\x14\xac\xc5\xe9\x8c\x12\x19\x0f-\x13\xee\xb2\x0cyI\xc0^\xb2\xa0/\xd9\xf1\x97 \x02s\x04\x0c\xe6X(\xcc\x11p\x98\x18$&\x15\x8b\xf1\xf6\xe1!4&#\x1e\x83Ed\"1\x99\xec\xa8L\x18\x97Y\x8c\xccP\"c\xb0diH\x8d\xd5\x15%2\xa6`6!\xd4&\x0fn\x83\x04#\x82\xd8M\x04z\x13L(\x8bDp(\x91\x91\x12\x191\xd8N0\xaa\xb1\xf8\x0e\x1e\xe1\xa1D\xc6\x99e\xc6{(\x91\xd1\xb4T\xf4\xc7\xea\x8c\x12\x19#\xb0\xa0%h\x90\xd5\x1d%2Zo@\xe1G\x94\xc8\x98\x0fM\xa2D\xc6\xc5XS\x9e6\x87\xc6\x9b\xf0\x88\x13.\x91q\x92\xd9bx\xb2\xaa\xd1\x8a\x8b&\xca\xb1\xe2\x0f\xaa7l\xa5&(\xdb\x1c\x9c\"\x08\x90\xe1\xc8b\xeb\xe2\xdc\x9f\xccs\xd5\xdc\x9c\xdd|w&\xea\xdf\x9d\xfd*\xff\x7f\xc5\xbd\xfbrx\xde\x8b\xcb&\xc7\"\x8e\x11\xd4\x95\xbdjn`\xdbl\xf6\x95\xfd\xa8\xc4?57\xd2\xcd\x13]\xd5G\x9a\xc3s\xd3\x88\xf3\x8ceh\x0e\xe7\xc4\x932M\xae\x9d \x08\x0f\xf1iY%\x16\xc2}\xa3\xae?\x1c\x9f\x9c\xc5\x84 \xce\xa5\x8b\xc0\xda\xb2\xd9$rp'u\xfa\x89\xd5W\xfd\xd0\x84\xa5{\x90\xee\xe7\x05\xdf\xb0]\xd3\x95=.V\xd3\x8b\x11\xc1R7d\x8d\xd6\xb6\xacW\xca\xaf/Vv\xa0\x12|`%\x84\n&-\x04Z\x82\x08[\xddl}\xab\xb1\xe0\x0b\xe5Vl\x9b}\xed\xa8\xa54\x84\x1b\xcc\x06\x1a\xb7WM9\nh\x17\xd07_X\xad6\xc0dutv%\x1f\x82\x8bZ\x15\xce\xb7\xd7\xfa\xf6\xdd\xa77/\xc4\xacU^\xab\xa6\x7f\xa5\xd8\xa1;\xaf{50\x0e\xbb\xa2\x9dw\xf3_\x8d\x9ar\xc1\xe0~hW^\xd5E\xbfoY7t\xc5|\x89t\xd5\\5bH\xb2\xcf,'A\xfaKY\x97\xdb\xfdV\xb7^\xb1N(\xc4ko\xba\xa2\xe2\xed\x9a\xd5|\x19\xe2\xfd\xb0\xb8m\x8b\xbb\xd5\xf0\xcdd\xfb\xba\xdd\x04\xfa\xe2N\x94[>J\x14\xfb%\x0f\x19\x9fy\xf0\x0fs\xfc \x81\xbf\xc6\xa1F\xae\xd5\xe8y]\xf6eQ\xa9\xfdg\x98\xb3\x0b\x06\xdb6u\x7f}\xb0w\xdd\x17Uu\x8f\xebW\xccK\x11\xbd\x8a\xb8\x80\xdc\x0e\xd2\x16\x0b\xe9y\x9d\xd9\xf7u<\xcb\x9c\xdc\xd0\x1e\x84\xe1=H\x80\xf8\xfc\x15\xd0B\xda\x18\x98\x0frA}\x90\x08\xf7y\x1d\xf2\xe0\xa2!?X\x0e\xfbA4\xf4\xe7u5\x8am\xe3\xe1?\xc8\x0d\x01B$\x0c\x08\xb1P\xa0\xbfe\x0f0!\x16\x0e\x84\xdc\x90 \xe0`A\xc8 \x0d\xc2bx\x10\xd2 B\xc8\x05\x13B\x12T\xe8\xff\x1c\xf4\x14$\xf4\xdd\x1c\x052\x84#\xc2\x86p\x1c\xe8\x10\"\xe1CH\x83\x10C]0\x0eF\x84\xbcP\"D\xc0\x89\x10\x0f)B\x02\xac\x88\xe82\xbfE@\x8b\x90\x03^\x84\x10\xc4\x08\xf8\xe9\x19\x02j\x84\xc8Y\\4\xe4\xe8\xf5&\xe0H\x04\xec\x08\x11\xa5\xcc\x08?B\x14\x04 \xb9aHH\x84\"\xfd\xed\xaa\x0b\xc3\x91\x90\x0eI:\xfd\xf1'\x86`I\xc8\x06M\x02\x1ea\x03\x0cD q0%\x84p\x85D\xb8\x12\x10~=[\x97\x99\xa0KH\n.\x1e\xc2\x04D-\x13\xa0LH\x853\xc1\x1f\xd5|\xb0&\xe0\xa1M@\xc2\x9b\x80\x868\x01\x17\xf5x\xa8\x13\xa2\xe0N\xf0B\x9e\x90\x0b\xf6\x84X\xe8\x13\x16\xc2\x9f\x80\x08o\x04\x0c\n\xc7\x80B\x01SF\xcf\x97\x90\x0f\x16\x05\x0c4\n\x0b\xe0Q\xa7C~\xa1\x0f\"\x85\xdc0)\x04\xa1RH\x85K\x9d\xde\xe4\x1a\xd5\xbf\\G\xc0\xa6\xe0Ew\xc0\x0b\x9fB\x12\x84\xeat\xe5\x85V!\x15^uz\xf3H\xaeK\xcb\x07\xb3\x02\nj\x85\x04\xb8\x15\xe2 WH\x81]!\x1az\x85\xc0h\x1b\x80\xc3 \x02\x12\xc3\xc2\xb0\x90\x02\xc5B,\x1c\x0b\xfe\x8a\xa7\xc0\xb2Ng\x06\xe8\x89\xfddp\xf0\xac\xf7\x83\xa8\xaf\xfc\x10-\xe4\x85i!\x04\xd5\x82\x1f\xaeu\xde\x93\n\xe3B\xc6\xb6\x1b\x01\xe7B\x14\xa4\x0b\x07\xc2\xf1\xda$\xb4\xb8\x00\x02c\xb5+\x89\x17\x04B\xfa\xfe\xc3\xbb\xf7\xef>\xbe\xfci\xf5\xf1\xd3\xcbO\x9f?\xae>\xbf\xfd\xf8\xfe\xcd\xab\xf3\x1f\xcf\xdf\xbc\x8e\xb8\xeb\xf5\x9b\xf7\xef>\x9e\x7fZ\xbd\x7f\xf3\xe1\xfc]\xcc\x8d?\xbf\xfbt\xfe\xf6O\xf1\xf7\xbd\x7f\xf9\xf1cT ?\xbc\xf9_o^}\x8a\xba\xe5\xc7\x97\xe7?9o\xd0\x99\x96 \x01\xc4\xee\xaah\xec\xf8\xa3h\x03\xe2M\x8a\xb5\xbf\xfc8\xd5^\x90\xf8\x8d f\xb2\xbb\xeb\x19\xb3\xda\xddM\xd0\xdb\x14\xbc\xd5\x9c\xa4\xa7\xeb\x19\xa4x\xe4\xae\x93\x89\xda\x06:\x8ez\xf2\xb49\x1d>|\xfa\xbb\xa1\xd00\xe4\xf2\xca\x87\xc2f\xdf\xea\x13\xf4\x15\xdb\xc0\x1d#\xa7d\x81\xb2@\xe3=,\xe5\xe4g\\!%o\"g\x19\xe5\x87rX8\xf9wO\xa9x\x832r\xa3\xf98t\xed\x01\x86vE\xd7\xb1\xb8\xa2\xe9O\xf2\xb0p\xfa\x97|\xc5\xbb`\xac\x86\x96\xfdM$>G\x95R\xf6\x02\x87e\x94\x7f\xcfW\xc2\xcb\xa2\xac\\E\xbb,\xeb\xa2ZII\x08 \x0e\x1d\x99\xaf\xf0\xf4\x9euO\x17\xef\x86\x17\x17\x1d\x9fq/\xf6\xf3\xb4n\x96\x17\xa6nV|\x05\xb1\xbaa}\xb3\xd0\x19\xb6\x03\xff\xc4_\xd8\x07);1\xb6\x93\xae/\xeaM\xd1n\xa4f\x87RR\xb9jnX[\x17\x87g\xba\x8c\xe6\x97&\xe9\xf6\x17\xdb\xb2_\xf5\xe56G\xa2\xd4\xa6\xe8\xd9s\xee\xcbz\x9d\xd6oa\xf5\xe6a\x1e(\x14?\xfc\nG~\x9a\x924\xaf\xca\x11\xea\xdb\xc1}=\x08\xad#Tp\x00\xa5w\x84t\x85m\xb4\xd1\xaaG\xc1\xc2\xfb\xa1\xc3\xbc\x8aHhM\xa4TU$%L\xd6\xf5E\xfb@_\x9bz\xe2\x03}l\x98f\xa2'\xa6\x93\x89\xdf\xbai\x99zw[\xbe2m\xd5\x08\x18\xe8\xd9\\\xbd\xda\xae\xb8R\xcd\xec\xb0\xc2\x932\x8e\x17\xced\x92\x86?\xab}<\x1byR\x9a\xf7\xc3\xf7\x7f\xf05\xbb\xebW_\xd8\xbd\xfd\xad\x04\xdfI\x10-\xee\xcb\xbeb/\xe0?\\\xdf\xab~\xbeV\x91\xe1\xffTT\x0b1!\xe3\xff\xf1\xbe\xb8b\x1f\xa4f\xe3\xa9\xfc\xdd\xe1Lr{\xb9\x1b\xee\x96\x87\x90\xc1\xb6\xe9z`\x82\xb0 \x98\x0e\x96[E\xef\xbc0\x00\x1e\x86\xa6\n\x81\xb3\xcb\x92rP\xbc\xfe\xe2\x1f\xf5\x9e7>\xde\xf6t\xc6\xbd\x91\xde\xed\xc2J\xcd\x10\xady/\xb4\x12\xce\\\xdd\xc7m\xd1A\xc7\xfa\x13(\xfbN3\x84:\xd8\xd7\xb2\x01n$ \xe2\xb6\xec\xa6\xef\x14#\x0d\xa4Y\xb8(u \x9b\x87\xb3\x91\xbb\xfc\xe1\xfd\xaby\x05H/\x88\xf4\x82B\xa3\x04f\x04\x80\x04r\xb1l\xba\xa4\x17\x84 \x12g!\x11\xa7\x10\x88I/(#Y8\x86(\x1cE\x12&\xbd\xa0\xa5\x84\xe0\x042p\x16\"p< \x98\xf4\x82\x96\x90~c\x08\xbf d_\xd2\x0b\"\xbd \xd2\x0b\xc2\x92u\xb3\x12uSH\xba\xa4\x17\xe4\xba,H\xc6\x8d \xe2b\xd4pb\x08\xb8\xa4\x17DzA\x182-\xe9\x05 [B\x98%\xbd \x9b\xa7 )6\x95\x10\xeb\x1c\x1bH/\xe8\xd0H/(\x81\xc8\x1a&\xb1\xc6\x12X#\xc8\xab\xd1\xc4\xd58\xd2*\xe9\x05\xc5\x11SI/h0\xd2\x0bR6\xe8\x05i\xb9\x15\xc9]2|MV\x933\x18rv\xd7\x04\x7f\x1dIP\x02\x8d\xd5\xa0\xd4|\x9e\xf4\xb0\xac\xc3\xaf\xc74\xb42\xf7\xbe\x12\xa3\x10Y\x96c2\x07\xadl\xc1\x87g\x08\xfaX\x81\x0f\xcb\x04\x96\xc0\xc5nf7\x8a\xcd\x8ddp#X\xdbQLm\xdd!\xde4\xfdd\xbfk\xd2\x0d\x8a\x1f'\xfd\x8f\xfcK\xb1\xd9\xb4\xac\xeb4\x93_p'0\xeb\xf1\xe3\xec\xd7\xdd\xa8\xe0\xe8=\x84YO\x8b\xb4\xd2\xe6n$\x97\n^\xd5\xa8t\xa5/=\x7f\xad\xebl\x95\xda|\xa2\xeb\xfd\xc8\x956]\x84\xb1$\x1e\xaa\x11\xedc11\xbdJ\x99\xde\xa2C\xb0\xf8\x80\xa0\xae!\xea\x00H\xf8SZ\x12\x81\xcd\xe3/J\x1b3+\x89-Hc\xcbMd\xc3S\xd92\x91\xd9\xd2\xe8l\x1ew\x91j\x98\x0b)m\xb9Im\x91\xb4\xb6\xcc\xc4\xb68j[$\xb9\xcd\xd7\x86\x13\xf4/\xb3\x12\xdcP\x14\xb7\x8c$\xb7\xa54\xb7$\xa2[&\xaa[\n\xd9\xcd\xe3\x0c\xadwy\x04\xc2\xdb\xf1(oG!\xbd\xc5\xd1\xde\xb2\x13\xdf\xb0\xd4\xb7\xac\xe47<\xfd-\x9a\x00\x17O\x81\x0bv\x858e\xcb\xc54\xb8\xa0\xaa%jB\x85 \xc3\xc5\xcc\xba\xa2 q\xbeA\x10\xade\x89+_FZ\\\x0c1.35.\x8d\x1c\xe7kA(\xfd\xcaD\x82\x9c\xc3[\x8f\xd2\xae\xccC\x92C3\xbd\x10D\xb9(\xaa\\H\xfa-\x85.\x17\xf2\xe9\x84\xcd3\x91\xe6\xe2\x83\x89'\xce\x85\xea\x96@\x9eK\xa4\xcf\xf9\xe8\x07\xd9(th\x12\x1d\x8eF\x87%\xd2!\xa2\x1cO\xa6\x8b\xa1\xd3\xf9\xd5(\xb3P\xea\"Iu\xcbhu\xa1\x80FP\xeb\x8e@\xae\x0b\x96\xce\xd9\xd2\xf3Q\xec\x10$\xbbt\x9a\x9d\xc3]\x1fT\x9d\xccJ\xb5\x0b\x91\xed\x12\xe9v\x0e_a\xb5I\x04\xe5\xce\xaf4\xe9\xd3\x99\xccM\xbc\xcbN\xbds\x93\xefr\xd2\xef0\x04\xbcx\n^\x14 /\x81\x86\x17K\xc4\x0bhG\xfaK\x87\xa5Fa\xe9x \x84\xbcHJ\x9e\xa7\xba)\xb4<\x87+\x84Zd\n5\xcf\xd3\xe4\xc3J\x91\x19\xe9yA\x95\xc8cP\xf4r\xb5\xc5\x08\x9a^\x0cQ\xcf\xae\x01\xe9S\x80\x0c\xae\xdf}\xea\x8fx&\x90\xef\x1e\x94\xf2c\x0c;\xc8w\x97W\xf5\x11\xc9\x18\xf2\xdd\xe0Q|\x8cb\x11Mo\xc4\xec<\xe4\xd2z\x1c\xe5t\\\xcd\xeca\x19\x97\xbe\xe7>\x14\xf7r\xb4\x80~\xe2W\xe2c\x8e\x16]\xbecr4G\x0bh;>\xfc\x1a\x8e\x08\x078\xfd\xc6\xa0#\\w\x9cS\xb9q\xec\x92\x0f\x7f\x0b\xaa6\x06\xeb\x83\xd3t\xc3\xe85fy\x14B\xa9\xb1\xf7\xc8\"AH\xa51\xf8=`\xbe\x08\x84>c0\x18\x80\xd2fD\xb8\xc15\xc8hUF\x84\xf6b^\xe5E\xa4\xeeb\x8a\xea\"Rs1\x18lL\x03F\xa9-fxR\xf8\xb5\xe7SY\xb4\xf7@\x11rt(5\xba\x99\xfe\xdc\xcc\xdf\x87\xf7\xafH}\x8e\xd4\xe7\xb2u\x87I\xe4=R\x9f\xc3P\xf6\xb2\x10\xf6R\xe8z\xa4>\x97\x91\xa4\x17C\xd1\x8b\"\xe8\x91\xfa\xdcRZ^\x02)/\x0b%/\x9e\x90G\xeasK\x88x14\xbc\xcc$<\x1c\x05/#\x01\x0fK\xbf\xb3\xec\xac\x93\xfa\xdc\xd4\x10\x84;\xec,)\x9alG\xeas(\x8a]\n\xc1\x8e\xd4\xe7\\\x97\x05Iu\x11\x94:\x8c\xb6Z\x0c\x9d\x8e\xd4\xe7H}\x0eC\x9a#\xf59aKhr\xa4>g\xf3\x14$\xc6\xa5\xd2\xe2\x9cc\x03\xa9\xcf\x1d\x1a\xa9\xcf%\xd0\xdf\xc2\xe4\xb7X\xea[\x04\xf1-\x9a\xf6\x16Gz#\xf5\xb98\x9a\x1b\xa9\xcf\x0dv\x0cj[\x8e6\x17Ak\xc3\x93\xda\xa2\xd4\xe7J\xb3\xe7\x9e\x9e\xf25^2\xc1\xc3\xe4n?\x94\x9b\xb9\xd2\x9c\xd9#\x95\xe2\x98\xb0I78\xaab\xf4\xed>U\xedd\x89$\xc6\x99\xc2\xc8;\x8f6\xc6ku\xc9\xa0\x8dQ\x08\xc1\x17\xf5G\x81\xfbue}U\x1d\xd6z\"\x8c\xa1\xdd<\xd1U\x7f\xa4\xc2\x18\xbaf\x8f\x03\xcb\n*jD\xed\xe5x\xce7\x1bD\xba\x92\x1f\xe3\xe7!\xf8\x82'\x8d\xce\xc5Dl\xa5E30\x82\x85\xff\x0d\x9d\x8b\x89 \xa2\xea\x86\xc6\x08j\x8e\x8a\xfe\x02\xe4s\xf8\x9f\xd7R\x9aI\xeb\xe99\x0e,\x14W\xf6\xe5\x8dcV\xef\xe2]\xd1\xc9\x92\xc2\xe8d\xc9\xdf\xd5\xc9\x92z\x12\x10C\xe5\x99M\x1c\xb4\x11\x95G\x1aQy\x88\xca3\x1aQy\x88\xca3\x1aQyz\xa2\xf2\xd8\x8d\xa8<\xda\x88\xcaCT\x1e\xa2\xf2 gID\xe5\x19\x8c\xa8<\xa6\x11\x95\x87\xa8<\x16#*\x8f\xf5\x1a\xa2\xf2\x10\x95\xc7aD\xe5!*\x0fQy\x88\xcacX\x0eZ\x05Qy\x84\x11\x95\x87\xa8<\x8f\x97\xcaCG\x94\xa5\x9e\xffDG\x94\x1d1\xb8\xe16JG\x94\xe5\x88\"\x1dQ\xf6{?\xa2l\xe0c\x9e\xfd:\x10\xf2|\xe7\x96\x19\xcdA\x13\x9b4KSq2\xf51\x9be-K\xcb\xdf\x89<\xc5D?\xf7\xfc\xf580\xab\xab_n6\xad\x8f\xc4\xa9~z\xec\x1cN\x17\x87!\x89 \x15db\x067\xe2\x83\\\xa0\x00\x073\xf0\x00\x1f\x17\xb1\x0f\xb0/I\xed\xcaj\x91\\K\x04\xa32/\x9f\x12\xc9\xa6\x8c\xe7R\x86\x03\x94\x99G\xe9eQ&+G\xa9B&\xb0\xcdf\xde\x88l&\x8d\xc8fy:\x16\"\x9b\x11\xd9\xccnD6\x13Fd\xb3C#\xb2\x19\x91\xcd\\Fd3\"\x9b #\xb2\x19\x91\xcd\x88lFd3iD6#\xb2\x19\x91\xcd\x88l\xe62\"\x9b\x11\xd9\x8c\xc8fD63,\x07\xf1\x87\xc8f\xc2\x88lFd\xb3\x7f\x06\xb2\xd9\x80;\xbb\xca?\\0;|OB\x80\n\xd8c\x1d\\\xb6\xcdvR\x8f.cE\x16\xf1*\xc4YY\x1e\"\x85y\xd4\x96fP\x88!Bl\x9dO\x8f[\xbbizfeG\x18N\x9e\xe8\xfa=R\x86\x84\xa8WV~\x84\xe7\x80\xb7\xc0\xae\x91\xf7`\xb7\xc0\xbd\xee\x03\xdd\x027\x86\x0fr\xf3:\x08o\x14\xe5:\xbc-\x19\xfc6\n\x10\x03\x80\x7f\xb2@#\x04\x7fK#\xf8\x9b\xe0\xef\xd1\x08\xfe&\xf8{4\x82\xbf{\x82\xbf\xedF\xf0\xb76\x82\xbf \xfe&\xf8\x1b9K\"\xf8{0\x82\xbfM#\xf8\x9b\xe0o\x8b\x11\xfcm\xbd\x86\xe0o\x82\xbf\x1dF\xf07\xc1\xdf\x04\x7f\x13\xfcmX\x0e(\x92\xe0oa\x04\x7f\x13\xfc\xfdx\xe1\xefEp\xf2M\xd33\xdf\x99I?\xf3\xdf\x07 Y\\-A\xe4\xab\xf2\x86\xd5\x07\xf5\x9c\xa0\xc8\xe2\xde'\xba\xa6\x8f\x14?\x16Uz\x1c\xb8U01?j\xdf\xc6sP\x07\xafs\xfa\xf1Hr\xe3\xddu;f\xe7\x05d\xdau\xcb\xd6E\xcf\x1b\xff\xfb\x96]\xf2 \x9a\x84\x1b~\x91\x0f\xe8~\x81\xb2\xeezVl\x14\xa8u\xe9\x9cS\xc1 \x8d\xc1{F\xd5X\xdd\xbd\x94X\x08m\xe4\xe4\xb1\xbc\x84_*V?S\xcf\xfc\x16\xbe\xff\x1e\xbe\xfbEML\x8b^U\x96\x0f\x1eNw\xb7Ll\xe6}w\n\xe75\x14\x95g\xa3Sn\x1f\xae\x8b\x8eu'j\x93ULmf\xb2.\xce\xfb\x7f~\xf7\xe9\xcd\xea\xdd\xfbO\xe7\xef\xde\xae>\xbf\xfd\xf8\xfe\xcd\xab\xf3\x1f\xcf\xdf\xbcv\xad\x0b\x82o\x12\x80\xd5{\x8f\x92\xc1s\xd7\x13\x91w\xfc\xeb\x9b\x8f\xc8+_\xfe\xf0\xf1\xd3\xcb\xf3\xb7\xc8\xab\xdf\xbeC_\xb8\xfa\xeb\xf9\xa7?\xaf~~\xf3\xc9u\x8bF\xff\xa3\xaa\xaaZ\x8b\xff\x13z\x1cG\x84\xf9\xbfVi\x88\x86\"\xcd\xdf\\\xa4\xc57\x1a\xdb}\xbe\xa6c\xbb>\xd4\x80l\xf7x\x9a\x91\xfd\xf2`c\x92\x96\xd4\xa4\xc6\x9bq\xfd\xa74>\xc4\xbe\x93]\x14\x13\x02_E\xaf\xa6$r\xa7\x9d\xf7\xf4\xba\xb5J\x8eN\xc0\xa1\x1c\xd6G\x1e\x8f1\xc2\x07\xeet\xbfxg \x0c:Q\xddo\xfe\xfc\x1f\x1eg\xdd\xae*\xfbT<\x89\x97\xc0x\xb6\x0cY=a\xc5\x85\xbe\xa6\x97\xd2\xc9\xba\xa9\xbb\xb2\xd3g\x92\x0et\xcd\xf3\xd7'\xf2\xd3\xe6\xd3\xb7\x13\xbdy\xe6\xae\x93\xeb}M*#\xa7\xf4\xfa<4\xeeO\xce\x9fd\xdfq\x80-\xd2i\x7f\xc2\xe8\xb4\xbf\xdf\xd5i\x7fb%\x1b\xc3=\x95\xcb\xe6\x0f\xef_\xcd\xbc\x11\xf7\x94\xb8\xa7\xa1\xd1\x0f3\xd6\x00qO\x89{\xea\xbc\x92\xb8\xa7\xc2\x88{zh\xc4=%\xee\xa9\xcb\x88{J\xdcSa\xc4=%\xee)qO\x89{*\x8d\xb8\xa7\xc4=%\xee)qO]F\xdcS\xe2\x9e\x12\xf7\x94\xb8\xa7\x86\xe5\xe0\x01\x12\xf7T\x18qO\x89{\xfax\xb9\xa7\xd6\xd3\xbf\xe8\x9c?\x08\x87\x91\xce\xf9;bp\xc3m\x94\xce\xf9\xcb\x11E:\xe7\xefw\x7f\xce\x9f` \x9d\xfd*8I\xbe\x03\xfe\x9e\nf\x93\x99H\xb0\xb1\x1c\xe5\xd7\x8c)\x05\xe7\xafO$\xd3I\x9c\xe1\xf7T\xf9;H0x\xa2c\xf1\x88\xf3\x0b\\\xd4\x84$jS0K \xb8\xbf\x1e$\xf7x\xf2\x03\x02\xce}lc\xcc\xbexr^\x00\x94.`\x06\x97\x15\x905'\x00\x9b\x11\xb0,\x1f *\x1b \xd8(|\xd4\xeeXJ7\x96\xca\x1dC\xe1FR\xb7#)\xdb Tm/\xf7\xbf\x0f0\xff\x1f\xe2x\xca0\xe3?\xd8\x18\xa4\x85\xd9\xfe\xb1\x0d\xc3vW\x88\xe9\x1f\xd3Hlw\x04X\xfe\x91\x0dFZB\xb3\x19o\xc5\xf4\x82\xd22\xb3\xfb\x93\xb9\xfd\x0f\xca\xec?\"\xaf\xff\xa1X\xfd\xc7\xe2\xf4?8\xa3?\xcc\xe7Gt%\xd8\x16\x9f\x91\xc9\xef\xe0\xf1\x87K\xb2\x98\xc3\x9f\x93\xc1o{;H\xb2r,W\x99\xa8\xcaDU\xb6\xfd\x9e\xe9\xd3&\xaa2Q\x95\xedFTeaDU>4\xa2*\x13U\xd9eDU&\xaa\xb20\xa2*\x13U\x99\xa8\xcaDU\x96FTe\xa2*\x13U\x99\xa8\xca.#\xaa2Q\x95\x89\xaaLTe\xc3r\xd0F\x89\xaa,\x8c\xa8\xcaDU\xfeg\xa0*\x0b\xf4\xcdUv\xf1\xe3\xa4\xd4\xe2\x0f\xeah\xd8\x01:\xdb=\xe0\xb9\xb0\x82\x86\xb7-\xeb\xfe\xec\xe6\xbb\xb3\xa2\xae\xf7E\xb5\x123\x94n$\xa2\xd8(w/\xc5\xa5\xef\x87+\xf5\xb6\x14p_\xbc\xf7\x94\xbe`\xf4%G8]\xa5 \xd7n\xee\xec\x89\xae\xdf#\xe5\xdd9\xe2d\x9aww\xc7\xbb\xaf\x13\xde79x\xbcFb\x83\xef\xc0\xe2l\xf2V\xa4\xf9X\xf5\n\x07\x9e\xbf1\x14&lstv\xd0\x90\xe8\x18Ui\x84\x0f\xfb6G\x8f\xb0\xb5\x8a\xea\"\xcb\xfa\xb22$\nm]\xe3\xb9\xbeD1\xf6\xed\xdf\xe6\xe0\xc8\xd3/\x0e\x9e\xd4\x8f\x8f\xb6C\x9cE\xc5\xb4L\x1d\xe1\x18.G_\xe7\x88\xa7\xc5\x95\x9d\xd92\xc4:\xbd+\x1b_\xfc\x87\xf7\xaf\xe634\xea\xd2\xa8K{\x9c]\x9a\x98\x90{\xa6z\xef\xc5\xef\x93\xceL&\xa8\x88\x9c\xac\xcb\xe1\x0b\x1c'\xf6\xd6\xce\xec/e\xddKW\xea\xd7G\xdb\x9b\x99\x011m\xba\x0e\x91Q\x99\xea\xcf\xea\x00\xe85\xc8\xb6\xd9\xec\xab\xbc\xea\xb3<\xda\xab\x0d\xab\x1b\x07}:\xd8P\x94\xb6j\xaf\xe0\xaeuS\x8a\x05,\xf7k\xb9~\xe8VWm\xd1\xb3\x95\xc4\xaf\x97=y[\xdc\x95\xdb\xfdV\xcfN\xa5K\xbe\x9e\x1e\xbbp\xfe,oa\xb6\xc5]\x9eB\xc4<\xb3t\x10\xdf\xd1\xcf,k\xdc3\xaf\x9a\xa2Z]4\xf5\x86\xa5\xa6\xe1\xa8'rG\xfc%\xefX\xbb\xe6\x83\xa5\xf4 E\xdflmk\x81\x8b\xaaY\x7f\xe9V;\xd6\xae\xeeY\x91\x96\xa5\x83H\x01\x1a\x8a7\x0co\xf2\xc1\xbc\x98\xc0\x1f<\xb9\x071v\xcbn\x055p\xab\xa1Z\xf5i\xc4L\xa5a\xda\xf2\xfb\xa3\x1a\xa6\xe5@\x83\x19\xa8\x8d\xa5\xbaj\xdf:%\xb2\x18)+\xc3 %\xe9\xe3r\x84:Q\xf9\x1be\xdfA\xb7\xbf\xe8v\x85\xa0\x91\x8d\x9bp_\xd8\xbduP\xff'\x1a\xd01\xe3\xf9d8\xd7Z\xf5C\xc4\xb2\x8e\xe3:\xccI\x9dl\xaa\xfa\xbc\xa7\xed:\xefL\xea\x7f\xa9\xef\xa5\xbe\xd7~\xfbc\xeb{}p\x84\xfeF]\x0dp\xe8*\xcdnC\xf6\xa8|J=\x9e\xad0v\xba\x97SZnJ\xea\xfd\xac\x86\xba\xb0\x1ee\x94/\xec~RD\xfe\xdf\x1a%\x19J\xa6Pv]\xa7\xac\xa5\xf4\x0ep]Ut\xd7e}\x85\x19\xe2f\xe3\xda\xe1\xaaK;S\xafA\xdd?\x19\xb3>\xaaK\xfe\x89\xc6.\xe7\xf7\x9b6\xf4\x94W5\xdb\xac\xd4l\xff\xb6\xac7\xcdm\xe4\xa0\xa0\xcd\xe8\xae\xacS\xfdmY\xaf\xd4\xe3\xf8\xaa\"\xcb\xb3\x1cl\xd8Ms[\xf7\xe5\x96\xad\xfeV\x94\xd5j\xa3\xc0\xcb\xa4g\x89F\xb4\xba\x14\xc9\x1fM\xbd\xda4\xfb\x8b\x8a\x89z$\xb9\x0b\x16\xfd\xe0y\xb2&\xc7xX\x18]\x1a\xb6{\x14\xb6~\xf0\x95\x0d\\\xf0\x0b\xd9\xb9\xe9O\xce\xf6\xfa-\xfb\x1f\xae\xb3]\x8e\xb3\x92\x1b\xfeH\x93\x89\xe9o4\x998\xc2d\x02=\xce\xf1\xbe\xa4\xac\xafVe}\xd9x\x86\xbb\x8f\xf2\xb2s~\xd50\xe8\xa9{\x85\xc2\x8dX\xc4U\x95$\xf5\x17}\xd3\xea\xf1l:\xe2\x19n\xd4\xef\x8fv\xbc\xe3\xb5z\x1c\x0dL\xd12\x92[\x08\x1f\x87\xd8f\xb5\xaf\xfb2\xbd\x91\x8e\xcdlS\xf4\xec9\x1f\x16\\\xae\xd4\xben\xb9e]_lwc\x9b\x80uQ\xd7\x8dH\xff\xd8\xd7\xb2T Je\xff\xae\x9a\xedE\xd77\xb5k\xefQ\x17\xfaP\x01\xca4\xbb\x1a\xd4\xdcB\xe7| \x0d+\x91\xf0#\x12\x10{\x9d\xbe\"ju]tp\xc1Xm\x94\x18\x9e})\xab\xca\x97\xa7\xb6\x97\x99\xfe\xda\x89\x9bG\xd5\xb1\xde\xceP\xde\x96]7\xce\x9e\x84`\xd7\x82\x03\x8f\xc3S(@\xc5I\x96Jo\xa4\xaaR\xc1\xb3!\x95\xae\xe3m@\xeb\x18\x8a\xef\x08\xd8\x0d\xf3\xe4\xab\xf2vd\x0f\x80`1\xad:\xd6?l\xe5\xaf\x9b[\xd8\x16\xf5\xbdl\xe1\xa2\x1ec[\xf8[#\x8f\x18l\x14\xc7j*o\xa8-<\xf9\x01\xf8Y\xfb4:MS\xb5A\xff\xfct\xd6\x11\xbb2p\xb7M]\xf6M\xabB_:Z\\U\xde\xb0\x9au\x1d\xf0)\xe0M\xd9\xdf[\xf6\x9ad\x18\xc4\xc3\xd4\xbc\x085\x12h\xf3\x9d\xae\xb8`1A\xa7!\xd2i\x88\xd8\xd3\x10\x01\xf5\x0d\x9a\xea\xac\xb2V\x13RoY\xc3\xd5\x87\xf7\xaf\xc6E\x81\x9a\xc9v|\xachm\x8d\xc8\x91\xf1\xbenZ\xe9C\xa8\x03\xb4\xb2\xf2\x03\xff\x96\x8f.b\xa5cF\xc6\x1a\x0e}\xc7\xc7f;\x96\xdb\x9bG\xd2\xb2\x1d\x13\xf9y?\x14\xed\xf0\x92\x02\xa4\xf4iXD\xcbt\xd1\xd2\xa7)1\xde\xf5\x9693D\xad\xbalN\xce&\xd3T'\xf7e\xf8#-\xc5\xa6\xbf\xd1R\xec\x08K1/\xcd\x9c\xf4\xa4\x83[\xb6\xe0\x1a\x9cIO:op\xc3J\xc8\xa4'\x9d#\x8a\xa4'\xfd\xdb\xd7\x93vn\xb1\x9d\xfd\xban\xean\xa5\xb6t|Z\xd2\xe6\xb2\xcf\x84\x99\xe6k-I\x98X\x0b\xf9\x1c\xe9Uyr\xed\xbc=\xd1\x81x\xa4\x1bo7E\xb52c\x96u\x95\xe8\xddK\x0b\x0c\xf0\xe1}\xb4\xe0\x0c\x01\xb7\x87\x96g\x07-\xb4\x7f\x16\xde=\xc3\xec\x9d\x85\xd6\x84i\xfbf\xd0\xec]\x12u\x98]3\xc7\x9eY\xc4\x8e\x19\xfaM\xa6\xaf\x963\xef\x94\xb9\xf6\xc9\x90\xbbd\xf9*\xbcx\x7f,\xbc2\xcf\xbb7\x86\xd9\x19\xc3\xef\x8bY\x0b<\xef\xd3\\\x1bgj\xf1\xcf6\xfc\x0e\xd1\xa9\xbb\xfb\xb0\xc9/\xd8\xc5u\x96\xb55-\xadiim\xfb\xfd1-\xad\xcdi\x96\xab\x11\x9a\xd7\xe8\x0fB\xff\xe7@\x9b\x9a}\xa2\x86\xaf#eB\xab\x19d/\x84\xfa\xf8\x04r\xc3*v%fr\xdd\xd9\xaf\xea?\x9aV\x14\xdc7\x814\xfa\x82\xd7\xfa\xa6\xd7\xa3\xab\x91\x93+\x96M\xe3\xdf\x05\x1dW\xce*\x87\x87\x0d\x9eTx\xac\x1c\\\xdbS\xd4u\x8fv\xb29V|e)\xa3\xb6\xaf\xf1\xc1\x8d%\xf3\x7f4\x8b\x8fR\x98\xb6(\x0f\xd0\x0c\xb8\x0f\x15PC\xb8y\xed\xec\xf9\xfaS\xbc`\xeb\xeb\x7f\xf9\xe3sV\xf3\xcex3|\x99\x1e\xc5dn\xbdP\xa0Q.\x0fGim\xc3\x1c\xe1+\xd5\xfa\xe0\xf9\xcbk=\xb8t\xd7\xba\xbb.Z_[H\xab\xaa\xf4\xaa&`\xe6\x0b\x10\x1a\x95\xf2\xc7\x96\xadYy\xc36\xae\xb2ac7\xf6-sf\xd8ES+\x95\xcc\xbe\xf9\xc2\xea\x0e\xaeY%\xc4\xad\x9c\xa8?@\xb1\x16\x93b\xb5\xd9\xe0\x06\xe1\x9b\xdbZ\ne5\xb5\xd1\xba\x948\xa9\x90\xe7m\xd6\xa5@Rd\x01<\x12\xb47\x8dLRln\xe5\xceJS{\x94?\x03\xaf\xf4\xa2\xa8\x8a\xdaE\xdd\xcf\xd8A8\x93\xfc\xa4\xa1\xdaL\xb1\xe5\x91^\xe8\x06\xdbJ^5\xa5y\xb0\x82h\x10J\x8bSVGo\\\xf1\x17X\xd4\xaap>\xd9\xd7\xb7\xef>\xbdy!\x04\xb4\xe4\xb5\xc3\x89L\xfc\xf6\xf3\xbaW\x1a=\x83@k\xe7m\x04J\xc0GM\x9a\xdd\x9fkyU\x17\xfd^~?rf\xc1\x1b\xe1Us\xd5\x08u\x1c[\xab\xc0\x84h\xfc\x88\xcc\xf5\x00\x7f\xc2MQ\x89M\xeb\xc6\xfc\xd0\xd8\xdd\x9a\xed\xe4\xae\xb8\xd5]\xd9\x1b\xd2\xa9\xf6\xda\xa8\x96:W+R\x9d\x83\x8a]\x07\xdb\xa6e\xd0\xed\xcb^o2Z\x9d\xad+\xb1\xb3>\x0c\xd8\x87a\x08\x07\xc16\xf0\x8f-\xa6\xaaf\xddX\xf7t$7\xb8\xbd\x1d~\xa7>\xb2\xc3,\xedg\xd8L\x9d\xa6\xf2\x1a{\xac\x93\x15[\xd6$ \"O\x10y\x02K\x9e\xf0a\x93j\xb3\xc0\xb6\x12\x08fe\xd9\x1c\x9dYW.\xa4\xcc#\x8d6\x1c\xf2\xcc\x16\xe8\xe4\x16:\xb9\xc5ntr\x8b0:\xb9\xe5\xd0\xe8\xe4\x16:\xb9\xc5etr\x0b\x9d\xdc\"\x8cNnq\xb7i:\xb9E\x1a\x9d\xdcB'\xb7\xd0\xc9-\xc2\xe8\xe4\x16atr\x8b0:\xb9E\x1a\x9d\xdcB'\xb7\xd0\xc9-tr\xcb\xdc\xb0\xa7h\xd0\xc9-\xc2\xe8\xe4\x96\xdf\xc3\xc9-S6\x91\xe1j\xb2\x98\x9c^5A\\\x87\x9f\x0e\xa9\x80\x16\xcd\xb4\x05\xfc?J\x03L\xcd\xb1\xa24\xc0#\x067\x9c\xc0Fi\x809\xa2Hi\x80\xbf\x834\xc0\x03\x12w\xd3\x1er\xb8\xcfZf\x12\x8d\xa4;\x1b\xa3\xfb\x83y\xdd\xc0\xdf\x9e\xdc=f\x04\xfa\x98\xda\x13GOtD\x1e)E\xdb\xac\xdfc#i\x9be;:\x0b\xf3\xf7M\xd3\xee\xda\xf5W\xaa\xb9\xb5\x0c\xba\xf6cj\x9b\xd9\x16\xbc\xfe\x14\xcdD~\x91\xe3<\x13\x13\x84M\xd7\x7f\xf5 \x18eX\x10\x84\x0d\xebz=l\xe0#\xc1\xea\xbe\xf5~%\xfen`4g\x870\x1a\xe2\xbb\x95\x86\xf9z\xa5\xad[&\xbb\xb1kV^]{\xc9\xd0\xd2\x90/RZ8C\xd3\xb4\x98\x97/mVz\x98,\x9b\xd4\xdf\xe4z\xd7\x0f\xe4k3\xdb\n\xf4M\xf3\x05v\xd5L\xf0\xd9f\xeb\x86/uEA\xdc\xe2\xb4\xa6%\x051\xa4r8ZB \xa75\x98\x1f\x1fz'2g\xbd\x84\x9c\xd1&A\x1c\x1d\x87\x82(H0E\xb5\nd\x10\x8c\x16\x15\xc4\xf8\x90\xcc\xca3 \x89\xfaMs\xc8\x11\xde\xc4\xccp\x12\x99\xae/\xda\xde\x9d}\xa2M\xf2\xd1y\x17\xf7\xd5#2\x16eHM\xdc\xaa\xa99\xe2n\xa3{}>\xf6\xce\x8an/>d\x01\x1f <\x99a\xf4\x87/\xae\x8e\xe6\x1c\xf4M\xdd\xb7\xf7F\xbe\xc6\xe4\xd5!z`\x90h}\xcb*vS\xd4=lY_l\x8a\xbe\xf0\x95wRZ5\xae\x08\x1a\x93\\9\x19\x05P?.\xcd\\\xfa0\xfdR\x8d\x9d\xef\xaa\xecz\x99v\xb9+\xda\xbe\\\x8bm{\x97\x9ba\xd2\xf4\xd4\x9c\xfa\xd7W\"\xff\xc9\x93\xc2t\xd96\xdb\xc9\x13\xf4k\x1f\xae\xd3\x9d\x86\x87\x1c\x9c\xf348\x139\xc3c4\x0f\xe6#:\xa8\xf6\x03\x9fl%P7<\xda\xb4\xe21\xf2\x8f,\xa7x\xdaD<\x99\x9e\x08$\x06\x03f\x80\xed\x99\xc1\xe4^/n:\xb8s\xe2K\xb8\xb3\x972\xd60\xfe\xbc%o\x0d\x7f;i/Q9'\x88\x17\"\x0d\x9fk\x82}\x81\xd2\xe69&\xa5=\xbbd\xfc\xba\x03\xfepi%Q)%\xd11\xc2\xa5\x92D\xc6i\x96BRZ\xb2G\xd0A\xc2\xa5\x8dD\xa5\x8c\xa0\x83\x14Wm_\x9a\x88:\x15L]\xe2\xe1\xfeH\xe3\xc3\xccf_Ij\x89:\xbd\x0c\xf8\xa2\x00\x15\x8c\xaf\x19\x04O\xe5'U\xc9\xf0\xd6\xf1\x05\xb3L\x11fY\x1d\xb51O \xe6t\xc4\xe5sxs=m\xb3#_\xce'\xa6\xce\x96\xdaB\xd77\xad\x9a\x90\x89\\O\xbe \xac\x98\x99\xcfiu5\x16\xcf\x93\xe0\xc9\xbf\xe6\xc1\xe3\xb8\x99Q\xd6<\xac\xfc{\x7f\xde\xb4\x1b\xd6\xb2\x8d\xc85\xa5\x84\x01\xbb\x07J\x18\xf8=%\x0c\xcc\xbfQ\xfciU3o\x16f\xaa\xcc'\xf0>\x81N\xb1RF \x05yV8\x94P@ \x05v\xa3\x84\x02a\x94Pph\x94P@ \x05.\xa3\x84\x02J(\x10F \x05\x94P@ \x05\x94P \x8d\x12\n(\xa1\x80\x12\n(\xa1\xc0e\x94P@ \x05\x94P@ \x05\x86\xe5 wSB\x810J(\xa0\x84\x82\xc7\x99P@T\xf68\x9e0Q\xd9\x8f\x18\xdc0 \x9b\xa8\xec9\xa2HTv\xa2\xb2+*\xfb@;\xf2\xf1\xd7\xff\xc3\xc2_\xffy\xb8q\xc2Z\x1f\xfdAY_6\xe2-\xc9\xa3\xad\x86'\x0f\xbe|,\xf5\x8f\xb2\xf8\x96\xc7\xa9\xab\x1f-E}\x8c\xc0\xe3 3\xe8sz\x1e\x90\xb6=\x7f\xe4d\x923\xe5j\x8f\xe1r0\xe9L\x7f\xff]\xf0\xbeA\xb3\xbe\xcbZLf\xed\x8b\xb65\x7f\xbdu\xb7\xefV\xbb\xfd\x85\x93\x7f\x16\x8c. \"\x0c\x08\xca\x08\xe0\"\x0c\x11Q\x86\x04\xfa\x88\xd7\x99\x1dC\xf0l\xa9\xe5\xa6\x91@\x98J\x02 t\x12\x7f\x05\x8a\xfe\x1aM)\x81\\\xb4\x12H\xa4\x96x\x1d\n%k,\xbd\x04\x96SL \x9af\xe2u\xa5\xe0\xef(\xaa \xe4\xa6\x9b@$\xe5\x04bi'\xfe\x96=PR\xb0\xd4\x13\xc8M?\x01\x1c\x05\x05r\xd2P`1\x15\x05\xd2\xe8(\x90\x8b\x92\x02I\xb4\x14\xff\xe7P\xf0e_\x90\x9a\x02\xc7\xa1\xa7\xc0\x11)*p\x1c\x9a\nDRU \x8d\xae\x12\xea\x82q\x94\x15\xc8K[\x81\x08\xea\n\xc4\xd3W \x81\xc2\x82\xe82\xbfE\xd0X \x07\x95\x05Bt\x16\xc0O\xcf\x10\xb4\x16\x88\x9c\xc5E\xd3[\xbc\xde\x04\xf5\x05Aq\x81\x88Rf\xa4\xba@\x14\xdd\x05rS^ \x91\xf6\xe2oW]\x98\xfa\x02\xe9\xf4\x17\xa7?\xfe\xc4\x10\x05\x06\xb2\xd1`\x00\xcf\xe6\x00\x0c\x1d\x06\xe2(1\x10\xc2\xb0\x13\xa91\x80\xf0\xeb\x81\xc92\xd1d )\xb8x\xba\x0c j\x99@\x9b\x81T\xea\x0c\xf8\xa3\x9a\x8fB\x03x\x1a\x0d \xa94\x80\xa6\xd3\x00.\xea\xf1\xb4\x1a\x88\xa2\xd6\x80\x97^\x03\xb9(6\x10K\xb3\x81\x85T\x1b@\x847\x82r\x03\xc7\xa0\xdd\x00\xa6\x8c\x9e/!\x1f\x05\x0704\x1cX@\xc5q:\xecE\xc6\xae\x9b\x8e\x03\xb9)9\x10\xa4\xe5@*5\xc7\xe9M\xaeQ\xfd\xcbu\x04E\x07\xbcL\x02\xf0Ru \x89\xae\xe3t\xe5\xa5\xf1@*\x95\xc7\xe9M\xce\x03=\xbbf\xf9(=\x80\xa2\xf5@\x02\xb5\x07\xe2\xe8=\x90B\xf1\x81h\x9a\x0f\x04F\xdb\x00\xf5\x02\"\xe8\x17X\xca\x0f\xa4\xd0~ \x96\xfa\x03\xfe\x8a\xa7P\x80\x9c\xce\x0c\x82\x0d\xf6\x93\xc1Q\x81\xbc\x1fD}\xe5\xa7\x03A^J\x10\x84hA\xe0\xa7\x069\xefI\xa5\x0cA\xc6\xb6\x1bA\x1d\x82(\xfa\x10\x18\x14\xa2\xa9\xfd\xad(+\xb6\xf1\xa3S\x87\x88\xb0ivtxn\xd8\x95\xbe,\x0f\xe8D\xfd\xdbk\xa6\xf6{L\x89\n\xfe\x1d\\0V\xab\xab\xdd\xed\xa0m\xb6B\x01\x83m\xa0\xeb\x8b~\xdf\xc9M\xf1\x031\x0bi\xf2\x12W,\xb05P\x0f*\xe7\"\xa1\xf2\xef\xce\xdb\x9e\xc9r\x8e\xe2n\xea_\x02\x04\xb1\xdf\x82\xd81b\xf5~\xeb\x9e\xc7?\x87\x1f\xde\xbd}\xbd\xfa\xf8\xe9\xe5\xa7\xcf\x1fW\x9f\xdf~|\xff\xe6\xd5\xf9\x8f\xe7o^\xa3\xef\xe0\xff\x15y\xf9\xf9\xdb?!\xaf\xf7:\xd7\xaa\x07QU\x90\x8a6\x0f\x00A+\xe9\x1c\xd9\x8c\xc1 \xd7\x89\xddx\xf1\xdb\xb3\xb2^W\xee\xe9A\xc7\xaa\xcb\xe7\xa3\xb8\x8c\xa3\x11\x8c|\nyV\xec\x03Tm\xfe\xc8\x11]\x17\xdc\x16\xf5\xc7\xb2\xeb\xf6\x12yp\x0fX\x06\xf6>zul\xa1\x9a\xa5[\\\x81\xe1\xba\x19\xfdq\xfc{\xcf\xdam\x07\xf6s?G\x0b\x08\xbaeC\xf7\xb7M]~a\x16U\x8d\xd1\x10/\x18\"b\x04\xe3S\x8d#\xb4\xaf\xf7\xdb\xa2~\xde\xb2b#(Pb\xde\x17\x8a\x11`\xe2\x04\x8a'\xd0;y\x12p\x9c:\xea\xc7\x9a\x8aR\x1a\x05\x1d\x7f\xec\xca\xab\xba\xe8\xf7-\x83g\xec\xce\xbf\x94\xfe\xfc\xbei\x05\x9f\xf1\x7f\xb3\xfb\x8b\xa2c\xce\xce\x1b\xe0\x96]te\x9f\x03\x13\x98\xd4X\xb9\xb5\xd6H\xffV\x95\xf5\x17_\xd7\xb3\xde\xb7e\x7f\xbf\x12+\x9a\xb5W\xde/\xa5\x84\x81w2\x7f\xbc\xb5&l[\x94U\x10J\xd7\xae@\xb9r\xd7\xd9)\x003ZJU\x95[=\x10H\xf0j\xa8\x84\xfa\xd5^\xaaQk\xd4/\xb2\x88(\x16FX\x11\xfb\x86\xe6\xc5\xd2o\xe7\x04\xca\xcb\xf1\xc7\x13\xd1\xa3\xaa+<\x94\x1b-\xbeXv\x07\xd3\xbb\xab\xbd!\xee\x16\n\x91Oa1\"@!U\xc5\xf8 \xddDO\x88\xb6e=h+:\xddM'\x92}\xa3e\xf6X(@\xebf\xbb-\xbb\x0e;h\x8e\x97O\x06F\xe3\xcfc\xfe\xc1\x91\x87\xbc\xf1\x99\xab\xb6\xe8\xfdj\xa4\xd8\xb7\x02\x16\xbf\x93\x8a*\x99G\xe3\"\xaf/\xe9@\x12\x0f\x06\xb0\\\x8a\x8d\x8aU1b\xd8C\xc5\x0b\x901\x03U\xa6\xd0\xc6=\xe2\x83\xd0\x16\x13ZP\x8f\xd7K\x1f\xa3\xd9\x88?\xaf\xaf\x8b\xf6J\xcc \x83n\xc6\xd9\xe0 \x88\xb4\xa7KA\xf2\xf2\xcbg\x02l\x8b\xbb\xd5W\x0e\x80.\xc2\xa4]m\x8b\xbbr\xbb\xdf\xce#\x12t&{\xc7\xf1\xcb_\x175\xb0\x1b\xd6\xaaPF\xc7F\xb2R\x1eC\x88\x8c\x92X#\xb5)\xca\xa0\xd8\xaa\xe0\xf1\xb7\xac\xe8\xd8\x01\x99\xd7\x88\xb4\x0cR\xd0U8\x88\xfb\x1d\x1f\x1d\x82Z\xbe\xc8\xc0aG\x1c\x88\x0c\xb0QJ\xfd\x1d\n B\xfc\xc1\xf6U\xde\x06\xc8x\xf2Mm\xecq\xd9\x96\xf5\x8a/T\x0d!\xfa\x05\xa30\xb6\x9e\x96\xa7\x1el\xb7<\xed\xc4\n\x1a6l]\x15\xf3\xf4\x89\x993\xd1\xe2\xd4\xd5\xda\xa1\xad\xbe\x98\xf2\x0d\x89\x02\xc6\xb2i(\xd4 \xf4\xcd\x95\xdc\xd0\x12`C\xaf\xf3L\xac\xae\x8a\xad\x91\x8fb\xdf\x80\xfc\xd9\xa8.\x9f\x08\xe8\xd5\xb7\xcaK/[`w\xf2\x05\xca\x97-\xa6\x0ee\xed\x18\xbc?VEw\xcd\x87.\x9d\x9d\xe4\xa2\x10\x17<\xac\xf2\xcbS\x18\xd6\xe41'\x92x(xpM\xdb\xba\x06\xb6uQ\xad\xf7\xd5\x00\xdd\\\xee\xf9\n\xcb\xfe\xc0}m\x1eB\xc0c\xd7\xec{({\x91\xb1Q_As#\xd6\xa9\xc3\x16\x02\xfc\xf5\x9a\xd5\xb2\xaa\xf6\n\xb4\xd3\x0d\x19\xfbS\xa7\xd3\xd2\x93Y\x17Sv|\xac\xdf\x94\xbd&\x87\x15F\xf3\xb1\xfa\xbb\xbdn:6\xa6\x14\xd9\x1fj\xbe\xc6\xb2\x9b\xd00\x8d\x16!\xaa6V\xc1\xeaiS\x0e8\xad\xdcl\x17\\B\xfbS'\xef\xef\x14~nDXw\xcd-ku\x1a\xa0~]l#\xb0Wg\xb3\xd5\xfb\xad\xa2\n\xf6\xa7m\xf7U_\xee\xaaR\x16n\xfa\xec\x83\x1b&_\x9d\x91\xdf3Q\xaa6\xdfL\xf7T\xe6\xfe\x08\xc1d\xe7\xa9\x02\xa4_,\x8c\xf4\x8b\x7f\xa3\xfa\xc5\x07oT\xe4\xe7Y\x12\xda\xbc\xaa\xc5\x96\xad=)SlK\xc4#qbi$N\x9cg\x9e\x17\x9b]&[-\x89\x13#2\xc9\xfa\x1cYd)\x19d$N\x9c1[,&S,*K\x8c\xc4\x89\x97f\x84%d\x83e\xc9\x04\x8b\xcf\x02#q\xe2%Y_1\x19_ \xd9^$NL\xe2\xc4\x81YRt\xf6\x16\x89\x13\xa32\xb5R\xb2\xb4H\x9c\xd8uY0\x1b+\"\x13\x0b#\xbd\x1b\x93\x81E\xe2\xc4$N\x8c\xc9\xa6\"qbaK2\xa6H\x9c\xd8\xe6)\x98\x15\x95\x9a\x11\xe5\x1c\x1bH\x9c\xf8\xd0H\x9c8!\x93)\x9c\xc5\x14\x9b\xc1\x14\x91\xbd\x14\x9d\xb9\x14\x97\xb5D\xe2\xc4q\x99I$N<\x18\x89\x13+#qb\x12'&q\xe2\xf1o\xc9\xc1\x0d\xcb\xea\x928q\x8e(\x9281\x89\x13\x1f\x88\x13\x9f\xfd:\xfc[\xfe\x96\xaaV<\x88\x15\x9b\xe7\xad\xdbu\x8a\xc7K\x06\x7f\xbb\xa2\x1cF\xba\x89\\\xf1\xe1\x83\xd4U\x8f_\xa6\xd8\xc5jHbK\xe1\xc4\x86\x83\xfb\xf3\x98\x0d\xee\xdc2\xc3\xf1\"\xc38\x89ao4!\x18Q@P>\x10\x11\x05tT!\x95\xf8\xe1\xf1\x17%*\x9c\x95\xfc\x11\xa4\x7f\xe4&\x80\xe0) \x99H i4\x10\x8f\xbbH\x19\xe1\x85T\x90\xdcd\x90H:HfBH\x1c%$\x92\x14\xe2k\xc3\x03]\x04K\x0b\xc9L\x0cAQC2\x92C\x96\xd2C\x92\x08\"\x99(\")$\x11\x8f3\xb4P\xf0\x11\x88\"\xc7\xa3\x8a\x1c\x85,\x12G\x17\xc9N\x18\xc1RF\xb2\x92F\xf0\xb4\x91h\xe2H(\xd7\x9b\x95\xa2\x12\"\xa9$\xd2T\x1c\xbe\xc22\xbd\x08\xaa\x8a_\xa2\xd7'\xd0\x9b\x9b\xb0\x92\x9d\xb2\xe2&\xad\xe4\xa4\xad`\x88+\xf1\xd4\x95(\xf2J\x02}%\x96\xc0\x12\x10\xdd\xf5\x97\x0eK)\xc0\xd2X\x12\x88,\x91T\x16OuS\xe8,\x0eW\x08\x99\xdd\x14J\x8b\xa7\xc9\x87%v3\xd2Z\x82\xf2\xba\xc7\xa0\xb6\xe4j\x8b\x11\xf4\x96\x18\x82\x8b]<\xd7'\x9d\xdb;\xd0\xca\xd10\xb2\xb9\xb8\xb5q\x8ad\xae\x90\xc6u\xf8\xc3\n\xe6\xfa\xe4rq%O\x92\xca\x8d\x16\xca\x0d\xee\xa5\xf8Drc%r\xa3\x04r\xe3\xe4q\xd1\xe2\xb8 \xd2\xb8>a\xdc`\xfcp/{\xa9$.F\x10\x17'\x87\x9b\xa9B\xb9\x84p\xf12\xb8f\xb9\x16\x15|\xb8j\x91\x00n@\xdf\xae_\x8e<\x07\x85o\x83\xaf\x12\xd0Q\x81\x8c\x92\xb7A\xe5\xbf\xb0\xdcm\xe6\x9ae\x16\xbaE\xcb\xdc\x06En\xe3\xeb\xb9T\xe0\x16/o\x1b_6\xef;\xc8&l\x8b\x95\xb5\x0d\x8a\xda\xc6W0Y\xd0\x16'g\x1b,PX\xca\x16\xf7>r\xca\xd8.\x11\xb1\xc5H\xd8\xa2\x83\xe2\x17\x13\x8c\x0dL\x8ct-f\x94\xc0\x0b\xd7\x86dk'5Y.Z\x9ba\xa0\xc2\xcb\xd5\xe2\xde\x02\xc4K\xd5J9Z\x8f\xbfEB\xb5\xc1\x18\x01*N\x80\x92\xa8\x0d6xm\xf8`\x02Z\x9c\xd6\x14\x9f\x0d8D\xcb\xaf\xe2\x84i\x8fT\xed\x18IZ\xd9\x97\x05\x1c\xe6\x10\xa4\x8d\x92\xa3=b`PB\xb4\x83\xd0l\xc0aP\x866\x18\x1a\x94\xc8,*\x1c\xb81\x01\xa2\x82\x96Y\\\xd6#-\x8b\x16\x96\x0d\xc6\x02W\xbb\x8c\x92\xb2hA\xd9p\xc9\xd2\xc4d\x95L\xa8\xc5\x9f[J6\xa7\x90,RF6ZD\xd6\x14\x8c\xb5W\xce-!\x9bW@\x16#\x1f\x9bW<\x16!\x1d\x9b$\x1c\xabEbm\xfe\x82\xb2\xb1i\xa2\xb1j\x7f\xd1\xe2\xcf-\x19\x8b\x16\x8c\x9d|SX \xccA\x01s\x89\xfc%\xa9_*#\xf5KR\xbf\x1c\x8d\xd4/I\xfdr\xb4\xac\xc9\x0e1\xa9\x0eQ\x89\x0e\xa4~\xb94\xbd!!\xb9!KjC|b\x03\xa9_.Ih\x88Ig\xc8\x9c\xcc\xd0\xa3R\x192&2`\xd3\x18\xfa\xb8$\x86\xd8\x14\x06R\xbf\x9cXt\xd2\x02\xa9_\xa2R\x15R\x12\x15H\xfd\xd2uY09!\"5\x01\xa3\xed\x18\x93\x96@\xea\x97\xa4~\x89I> \xf5KaK\xd2\x0dH\xfd\xd2\xe6)\x98`\x90\x9a^\xe0\x1c\x1bH\xfd\xf2\xd0H\xfd2!\x8d \x9cD\x10\x9bB\x10\x91@\x10\x9d>\x10\x97<@\xea\x97q\xe9\x02\xa4~9\xd81R\x04r\xb4\xb9\x88\xf4\x00|r\xc0oU\xfdr\xaax\xe6*\xf3\xf4\xaaI\x99G\xb4\xf3\xc8eF\x8b\xbd]\x97]\xdf\xb4\xe5\xba\xa8Ve}\xd9\x9c\xfd*\x99}>5\xb7?\x0f\xb7\x9c\xd7\x97\xcd \xdf\xc6\xeb7z\x9bk\xb8I\xb7\xba\x86\x13\xa5\xb6\xa9\xbf'\xba\xb2\x8fT\xa5\x8dW\xf1p\n?)\n\xbfd\xf2\xda\xe7aQ\xa2\x87\xb6\xc8\x8c\xe6,\x1b\x04A\xb9kVl\\\x14q\xaf[\x08\xba\xe6\xa6\xf6F=l\x1cy|\xe4E\xd1\x95k\xb8\xa8\x9a\xf5\x17Qo\xf7\xf5\xa12\x01\xaa\\\xdc\xc4\xd32Q\xa7\x10\x07eJ+v\xbb\x87}$f\xc3M\xda+\xad\x88\x07\xebb\xd7\xef\xdb\x81\n\xaa\xff\xdc\xee+&\xb3\x1avm\xc3\xbf\x1f\x7f\x11\x8b\xe1}J$\x8c\xff\xc7\xfa\xba(\xeb\x13\xcfjR x\nf%\x1f\xb7\x87\x9b`S\xf4\x05\x8f\xcb~-\xcb\xa6\x96(\xb2T\x1e\x87z\xe3r\x846\x9e:\x0e\xd6\x95\xd6\xf5\x82\xa2\xd3\x16u'\xc7\xf1m\xb1\xbe.k\x87\x00\x8b\xe0a\x95\xf5\xaat\xa4\xb2\x01\xee\x95\xfaX\xdd\x80s\x81aw\x03< 7N\xcc\x94\xc5\x0b\xf4GG\xf6\x00\xbb\x96\xdd\xcc\xf3\x8a\xdd\xee\x81\x9e$\xbe\x0f\xc5\x01x\xa0G\xb2\x9br\xc3\xea5{\xa0\xc7\x0d\xedo\x9c\xfex\x86%\xde\x037\x1d\x0b('C\xb6\xf2M&u\xb2'\x9b\xac\"\x86i\x92\xd8L\x84O\xac\xde\xb0v[\xd6\xbd\xeaT\xe4\xf0c\x9b\xd1\xdc\x14U\xc7\xbc\xe9ev\xca \xf8h\x83\x80\x1b\xcd0\xe3\x18N\xa3Z\x1a*\xd613\xe4(\xd5j\xaf\x1f\x93\x16\x1f\xaf]-\x0d\xa7`-\x0d\x11}@\xbe\x01P\xee\xfc\x9a\xd6\xe3u\x887\x00\x91o\x01\x12\x08\x9eA\x87\xbd\x15\xe9\xf7\xad\x14\xa4\xa1 \x9fAO#!4D\xfc\xd4\x16K\x00\x0d:\xdc\x15\xfd5\x9a\x08\xaa\xcd\x86\xf1D\x13B\xb5\xe1\x89\xa1AW&q4\x82 \xaam!QT[\x1ca4\xe8N\x91\xd9\xa2\x88\xa3\xdab \xa4A\x87\x97M\x1bE$\xd5\x16E(\x0dzK\xd1\xcf\x96\x86\"\x98\x06\xbdL \xa8\x18\xa2\xa9\xb6l\x84\xd3\xd1\xe1\x12\xe2\xa9\xb6\x04\x02\xaa\xb6,DTmxBj\xd0\xd5\x84\xb0\x1a&\xa6j;\x02AU\xdb\xb1\x88\xaa\xda\x8e@X\xd5\x16C\\\xd5\x86&\xb0\x06=\x99\x04W\xd1\xbe\xc3DVmQ\x84\xd6\xa07\xd1O`\x89\xad\xda\xfa8\x82\xab\xb6X\xa2k\xd0a\x8cb\xb7\xb4\xc5\xc4Wm\x01\xf5ni\x11S\xc7\xe0ri\xb4\xd8Yf\x14A6\xe8\xad\xd7\x04Z\x04QV[L\x89#\x89\xb3^_\xd3\xd9,\x82@\xab-\x8aH\xeb\xf5\x14\xd4\x03\x97\x96B\xb6\x0d\xb7O\x946\xb8\xb4\x14\xf2m\xc8a\x8f\xd2 \x97\x96\x87\x8c\xab\x0d\xc9+\xd5\x16$\xe7j\x8b \xe9j\x0b\x08\xf8\nK!\xedj\xc3\xf8\xf7j\x80f#\xf3jK\x0b>\x9e\xdc\xab\x0dS\xf3\x04\xb2\xaf\xb6$\xd2\xaf\xb6@\xc4\xf3\x91\x80\xb5!\xc9\xc0\xda0\xa4`\xe3Z\x049X\x1b\xf2\xad\xc4\x93\x85\xb5\xe1I\xc3\xda|\x8a\xe5\xd2\xb2\x90\x88\xb5E\x91\x89\xb5-!\x15k\xc3\x84>\x82d\xac-;\xd9X\x1b\xaa\xbc\x81/)\x9e\x84\xecuwq\x1f&#kK!%{\x1dj6\x80_\xf9\\Z\nI\xd9\xeb\xb0\xd7{n\x1e\x15ti\xb1\xa4e\xaf\xb3\x91\xd0\x8c\xd8\xee@\x90\x98\xb5\xf9\xc4\x99\xa5\xf94\xd2\xa5\xc5\x93\x9b\xbd\xee\x02*\xea\xfa\"<\x01:\xd0@\x0cr\xb4GQ]Z,!\xda\xeb\xec\xf3\x87\x9fN\x11\xc4hm\xb1\x04im\x11Dim\xd1\x84\xe9\xd9\x8dH\xe2\xb4\xb6\xd0, \xa8z-\x0dKn\xc5\x12\xaa\x07\xbf\xb1\xc4\xea\xe1\xc6\x18\x82\xb5\xb6@0R\x08\xd7^\x87\x08\x95vi)\x04\xec\xe0\xc7\x14Vl\x97\x16O\xc8\x0e\xf6\xe2\x01\xf5vi\x1e\x82\xb6\xf7\xbeT\xf2\xb6\xb6\x9c\xed=\x82\xcc=\xb8F\x93\xba\xb5\xb9'H>\xf5wir\xff\xc7\xa7\xef.\x0d\xa3\x04/-f'%E\x15\xde\xdff\xdaf\x8b\xd6\x86\x97\xe6S\x88\x97\x16S\xa3$\xb5xi\xd1\x9a\xf1\xd2\x90;x>\xfdxi\xb1*\xf2\xf6\xbb\xbcZ\xf2\xee[\xdc\x8a\xf2\xb6{\x82\x0fIP\x97\x97\xe6\xd3\x98WW\xe0\xe2\x1d\xd3h\x96\xaa\xceK\xc3h\xcfK\xc3)\xd0K;Busi\xd2K\xc3+\xd3K3K\x9a\xadB\xc3\xb5\x8b\xb4\xea\xa5!\x84n\xb33M\x82\x1a\xf6\xd2\x90\x8d\x01\"\xe3\x07\x19U\xed\xa5\xa1b\x88Q\xb8\x97v\xc4zGj\xde\x07\xfd=cw\xa7x\xe5{iA\xfd{i\xa9QX\xaa\x85/\x0d\xaf\x88/-\xb5\xb4\x88w\x96M#\x7f\xea.\xa4\x94/-\xa8\x97/-\xb5\xfa\xc9\xda\xf9\xd2p\n\xfa\xd2\x90E\xc4\x12\xdfc\xdeb\xbc\xb2\xbe\xd7]\xd1/\xd2\xd7\x97\x86Q\xd9\x97\x16\x19\xb8P\x06 $\x07\x0f\xab\xbe\xefu\xa7\xfa\xf4\x14\x0d~i!%~i\x93\x1a.\xd7\xe3\x97\x96y\x18\xc6+\xf4K\x8byk\x10\xaf\xd6\x1f\xf4'\x9d,\xd2\xec\x97\x86\x8c#D\xc4\x12P*\xfe\xd2\x90\x1f\x94\xb6\xd8\xb0\x03Z\xd7\x1f\xe5\xca\xd0\xfe\xc7 \xb6\x8f\x86\xd3\xf8\x97\xf6\x00A\x89Q\xfdG9\x94\xbdp@\xfb\x1f\xe5).\xa6\xe8S\x02\xa4=PhQ\xe7\x06\xa0\xbc\xe9\xb3\x05\xc2\xa7\x07\xa0\xdc\xe1\x82\x8b:g@ZD@cFEH\x08~\xec\xf9\x03A\x87\xb7E\xe7;\x85@\x1a\xfa,\x02i\xc8x\xc5\xd4=\xe3\xe9\x04\x83C\xdc\x19\x05\xd2\xb0eM;\xaf\xc0\xe9nT\xad\xf7R\xb2\xe3\xcf.p\xba\x92g\x1a`O0\x90\x16}\x8e\x81\xfb\xe9\xe3\xf9\x06\xfe\xd3\x0c\xa4%\x9di\xe0\xaf:\xead\x03i\xb1\xe7\x1b8\x1d\x19m\x1aq\xca\x81\xb4\xa4\xb3\x0e\xdc%(\x07\xce@\xef?\xf1@Z\xda\xb9\x07\xde\xca\xb0\x8d\xe7\xf4\x03iig \x1c|\xadB\x1ce\xaaB2\x9c\x7fPv\x11G \xcc\x94Q>\xbc\x7f5/;\x9d\x860Ya\xd3i\x08\x16\xc3\x0e-\xb1\xc9r\xb2\xfd\xd2i\x08\x88$8\x1bw(:\xf9\x0d\x9f\xf4F\xa7!h\x8bMf\xf3\xeex\xc6$\xb1E%\xaf\xd1i\x08K\x93\xd2\x12\x92\xd1\xb2$\xa1\xe1\x93\xcf\xe84\x84\x1c\xc9e1Ie\xe8d2:\x0d\x81NC@\xcf\x92\xa2\x92\xbd\xe4j\x89NC\xa0\xd3\x10r%`!s\x7f\x82 W\x11\x89V\x18\xad\xff\x98\xc4*:\x0d\x81NC\xc0$<\xd1i\x08\xc2\x96$.\xd1i\x086O\xc1\x04\xa4\x94\xc4#:\x0d\xc14D\"\x11\x9d\x86@\xa7!L\x8cNC\x88K\xce\xa1\xd3\x10\x06\xa3\xd3\x10\x94\xe9\x93\x05\x0eX\x7f\x93E\xe4\x9458\xf2\xff\xd4\xdf\x873\x04\xfaC\xady\xb3[Zx\xa6\x008\xd8\x91\xae\xb3\x06\xe6G\x0d\x88\xfa\xab+m\xe7\n\xbc\x1f\xe239S@y\xb0P\xe4&\xa7\x08|\x94\x97 'z\x85\xf9h\x0f\x110Ca\xda\xa40\xf2\"\xf5\x15\x8a]t1\xa3\x1a\x82$F\xbf\xb2\x83m\xb3\xd9W\x96\x9d\x08g\xb9 \x88ca\xc8\xa1\xc1m\x9cIef,NE\xd5\x90\x8cN\xf5\xb9\x89\x15\xbe\x8f\x7f\xb9-\xee\x0c\xbd__\xa9|*\xd7a\x82\xef\xa4\xe0\xd3\x87\xea\x82kN\xd3\x00\xcc\x1bb\xca\xae\xa2\xb3\xbao\xbd\xb8a\xd6r;\xb7\xc4\x8c\xa2\x18\xb5\x01\xfd'1\xc5,\xc5^\xe3\xf02\x1c\x9e\x0c\x9a\x82\x80\xa5\x8d\xff~\xb6c-\xec\x8a\xb2=\xeb\xdb\xb2\xb1&\x04\x18'\x8f<\x92\xc8\x1c\x96H\x07h|\xcdF\xf7\xaa\xafq\x92gv\xac\xed\xca\xceJ\xb0\xe7\x81]mX\xdd8\xb2\xe4\xe2>\xae\xd1\xdb\x84x\xc7\xff,v\xc9\xd7MY\x83\xf8\xbd\xac-\xac&\x04;Bv\xabAV\x84\xe2A\xc8\xab\x05\xffa\xea\x8b\xe8\x0fD\x7f\x08\xed\xfd\xe3\xbeU\xa2?\x10\xfd\xc1u%\xd1\x1f\x84\x11\xfd\xe1\xd0\x88\xfe@\xf4\x07\x97\x11\xfd\x81\xe8\x0f\xc2\x88\xfe@\xf4\x07\xa2?\x10\xfdA\x1a\xd1\x1f\x88\xfe@\xf4\x07\xa2?\xb8\x8c\xe8\x0fD\x7f \xfa\x03\xd1\x1f\x0c\xcb\x01E\x13\xfdA\x18\xd1\x1f~+\xf4\x074M\xa0i*\x0fI\xa0i\xaa =\x80_>a:LX\x01\xfcr\xf5\xf7\xc7K\x06\x18*l\xda\x94\n\xc0+iB{\x07\xb5\x1e\xcdY\x02\x08\xe27u\xd3\xafd\xea\xf5\xca\xa7L\x19\xd8\xc1X\xe2aRk\x89<6M\x85\xc6\x1dyT>\xbc\x7fE8#\xe1\x8c\xc1M6\xcc>\x15\x10\xceH8\xa3\xf3J\xc2\x19\x85\x11\xcexh\x843\x12\xce\xe82\xc2\x19 g\x14F8#\xe1\x8c\x843\x12\xce(\x8dpF\xc2\x19 g$\x9c\xd1e\x843\x12\xceH8#\xe1\x8c\x86\xe5\xc0|\x08g\x14F8\xe3\xef\x0dg\x9cg\x92\xda\xd0\xc6\x9f\xc7\xc4O\x8d9\x16Ue\xe4z\xea\x1d\xc5~-\xd5\xbb\xaf\xca\x1bV\xab\xe3\xf7\xac\x80\xe4\xe8Q\xfd\xfahaI_\xa6m\xff\x15 \x1f\x19\xc6\xa6]\x15\x9bM\xcb:\xc7U\xa8}\x0f\xcc\xd6\x01X\x1e9\x81`\xf5\xdf\xe6g\x14\x88\x07\xf9 \x01\xe8Ct\x99\xdf\"\xc0>\xc8\x01\xf8A\x08\xf4\x03\xfc\xf4\x0c\x01\xfeA\xe4,.\x1a\x04\xf4z\x13\x00!\x02\x08\x84\x88Rf\x04\x04!\n\x14\x84\xdc\xc0 $\x82\x83\xfev\xd5\x85\x01BH\x07 \x9d\xfe\xf8\x13C@!d\x03\x0b\x01\x8fy\x01\x064\x848\xe0\x10B;\xfd\x89\x00\" \xfcz6\x133\x81\x89\x90\x14\\<\xa8\x08\x88Z&\x80\x8b\x90\n0\x82?\xaa\xf9\x80F\xc0\x83\x8d\x80\x04\x1c\x01\x0d:\x02.\xea\xf1\xe0#D\x01\x90\xe0\x05!!\x17\x10 \xb1`$,\x04$\x01\x11\xde\x08`\x12\x8e\x01N\x02\xa6\x8c\x9e/!\x1fP \x18\xb0\x12\x16\x00\x96N\x87\xfcB\x1fh \xb9\x81K\x08\x82\x97\x90\n`:\xbd\xc95\xaa\x7f\xb9\x8e\x002\xc1\x8b\xb7\x80\x17\xd0\x84$P\xd3\xe9\xca\x0bvB*\xe0\xe9\xf4&\xe7\x81\xbe\xf31\xb3\x01\x9f\x80\x02?!\x01\x00\x858\x10\x14R\x80P\x88\x06C!0\xda\x06\x00*\x88\x00\xa9\xb0\xc0(\xa4\x80\xa3\x10\x0b\x90\x82\xbf\xe2)@\xa9\xd3\x99\x01Cb?\x19\x1c`\xea\xfd \xc4\x11\xee\x1e\xd0\x14\xf2\x02\xa7\x10\x02O\xc1\x0f\xa0:\xefI\x05V!c\xdb\x8d\x00X!\nd\x05\x03h\x9d\xda\xdf\x8a\xb2b\x1b?:u\xd14\x15sn\x1d\x0f\x1b\x12\xde\xab\xb0+}Y\x1e\x85\xd8m\xe0\xf6\x9a\xa9\xfd\x1e\xf3L^\xfe\x1d\\0V\xab\xab\xdd\xed\xa0m\xb6\xc3\xa1\xb4\x02\xdc\x95\x9b\xe2VmWP\x97\xb8b\x81\xad\x81z\xd0\xfcTk\xf5w\xe7m\xcfd9\xcf\x06\xf5^\xf5/\x01\x82\xd8oA\xec\x18\xb1z\xef\x90\xaa\x05\x81\xb2\xff\xf0\xee\xed\xeb\xd5\xc7O/?}\xfe\xb8\xfa\xfc\xf6\xe3\xfb7\xaf\xce\x7f<\x7f\xf3\x1a}\x07\xff\xaf\xc8\xcb\xcf\xdf\xfe y\xbd\xd7\xb9\xce\x0d\x8d\xaa\x82/\xb9\x15\x15Ol#\x90\x0fR\xcdX\xcdJ\xc6\xb3\xa8\xc5o\xcf\xcaz]\xb9\xa7\x07\x1d\xab.\x9f\x8f\xd2\xcc\x8eF0\x1c\x8a\xbd\x92\x87.?@\xd5\xe6\x8f\x1c\xd1\xf5\xa6/\xaa\xf1,\xebn/\x91\x07\xf7\x80e\x9e\xf8n\x9c\xee\xed\xa8\xe8X\xba\xc5\x15\x18\xae\x9b0\x03\xcc\xbf\xf7\xac\xddv`?4z\xb4\xa1\x02\xfe/t1\xba\xbfm\xea\xf2\x0b\xb3\xe4\x1e\x8f\x86x\xc1\x10\x11#\x18\x9fj\x9c\x80\x7f\xbd\xdf\x16\xf5\xf3\x96\x15R\x9fZ\xcc\xfbB1\x02L\x9c@\xf1\x04z'O\x02\x8eSG\xfd\xd8\xb1\x92c\xfa\xe2\xf8cW^\xd5E\xbfo\x19\xbd\xbb\xda\xd7\xfes%p\xe7]D\x05hS\xf4\xec9\xf7\x95-H\xf2\xa8\x0cw\x88\xb6e-\x8f\xd3\xf05\xe5\xe9D\xb2o\x04\x00^\xb1\x9e\x85\x02\xb4n\xb6\xdb\xb2\xeb\xb0\x83\xe6x\xf9d`4\xfe|x\x9a\xcb\xdc2\x0dy\xe33Wm\xd1\xfb\xae\xc4\xbf\x15\xb0\xf8\x9dTT\x10T\x8a\xca\xb8\xc8\xebK:\x90\xc4\x83\x01,_\xb7\xac\xe8\xe5\xaa\x181\xec\xa1\xe2\x05\xc8\x98\x81*Sh\xe3\x1e\xf1Ah\x8b -\xa8\xc7\xeb\xa5\x8f\xd1l\xc4\x9f\xd7\xd7E{%\xe6\x84A7\xe3l\xf0\x04\x049\xfcR\x90\xbc\xe6'`\xccm[\xdc\xad\xber\x00t\x11&\xedJ\x1f;3\x8bH\xd0\x99\xec\x1d\xc7/\x7f]\xd4\xc0nX\xabB\x19\x1d\x1b\xc9Jy\x0c!2Jb\x8d\xd4\xa6(=\xea\x11\xda\xca\x9a\x7fm\x1d; \xf3\x1a\x91\x96A\n\xba\n\x07q\xbf\xe3\xa3\x83w\xa4\x01|\xe0\xb0#\x0eD\x06\xd8(\xa5\xfe\x0e\x05\x10!\xfe`\xfb*o\x03d<\xf9\xa66\xf6\xb8l\xcbz\xc5\x17\xaa\xabq\xa1\xba`\x14\xc6\xd6\xd3\xf2\xd4\x83\xed\x96\xa7\x9dXA\xc3\x86\xad\xab\xa2\xf5\xec\x11m\xcbZ\xb48u\xb5vh\xab/\xa6|C\xa2\x80\xb1l\x1a\nu\x02}s%7\xb4\x04\xd8 \x80\x02\xbej\xb6\xba*\xb6\xcd~\xa0\x12\xdb7 \x7f6\xaa\xcb'\x02z\xf5\xad\xb2\xf7\xca\x16\xd8\x9d|\x81\xf2e\x8b\xa9CY;\x06\xef\x8fU\xd1]\xf3\xa1K\x8b{\xb8(\xc4\x05\x0f\xab\xfc\xf2\x14\x865y\xcc\x89$\x1e\n\x1e\\\xd3\xb6\xae\x81m]T\xeb}5@7\x97{\xbe\xc2\xb2?p_\x8fo\xa6\x13\xb1k\xf6=\x94\xbd\xc8\xd0\xa8\xaf\xa0\xb9\x11\xeb\xd4a\x0b\x01\xfez\xcdjYU{\x05\xda\xe9\x86\x8c\xfd\xa9\xd3i\xe9\xc9\xac\x8b);>\xd6o\xca^\x93\xc3\n\xa3\xf9X\xfd\xdd^7\x9dq(\x95\xfd\xa1\xe6k,\xbb \x0d\xd3h\x11\xa2jc\x15\xac\x9e6\xe5\x80\xd3\xca\xcdv\xc1%\xb4?u\xf2\xfeN\xe1\xe7F\x84u\xd7\xdc29\xea\\\xb0\xe1u\xb1\x8d\xc0^\x9d\xcdV\xef\xb7\x8a*\xd8\x9f\xb6\xddW}\xb9\xabJY\xb8\xe9\xb3\x0fn\x98|uF\n\xcf\xc8\x06Sg\xec\xc9T\x9f\x0d\xb8\x8ft\xdb\x15W\xea$\xad\xc3^j\xf2\x98\xf1\xc2\xa9|\xdf\xf8g\xd5\xeem\x89<\xd2\xbc\xf3\xba\x80\x9e\x1f\xbb\xebW\xce\x9c\x91`G\x1ad\x08\xf6e_\xb1\x17\xf0\x1f\xae\x1eV?_w\xaa\xfc\x9f\x8a^[t\x9d\xdc\xd5{_\\\xb1\x0f\xec\xef{\xd6\xf5\xa7\xf2w\x87\xb3\xf1\x88K\xee\x96\x87\x90\xc1\xb6\xe9z`\x82\xa4*\xd8\xad\x96[E\xfbZ\x18\x80\xbd{\xbd\xabB\xe0\x1cd\xe4^f\xa975\xc7\x83\xe4t\xd7h\x88\xec\xb8\xf8qf\x88\xd6\xfc\xc3]\xc9\x8f\xc6q\xf9m\xc1\x87\xac\xfe\x04\xca\xbe\xd3\xac\xf0N\xf4|\x12\n\x11{\x07\xb7e7}\xa7\xae\x8a\x88\xf4\xb91k\x0d+\xc5x\x90\xe7\xa6m\x94g\x1c~ u\xc6\xe9o\xa4\xce\x88\x9b\"AB\xe2\x98l\xab\xa4\xce\x88H\x12\xebs$\x88\xa5$\x87\x91:c\xc6D\xb0\x98$\xb0\xa8\x040Rg\\\x9a\xec\x95\x90\xe8\x95%\xc9+>\xc1\x8b\xd4\x19\x97$t\xc5$s%$r\x91:#\xa93\x92:#6\x11+k\x12VJ\x02\x16\xa93\xba.\x0b&ZE$Ya\xb4\x07c\x92\xabH\x9d\x91\xd4\x191\x89R\xa4\xce(lI2\x14\xa93\xda<\x05\x13\x9eR\x93\x9d\x9cc\x03\xa93\x1e\x1a\xa93&$)\x85\x13\x94b\x93\x93\"\x12\x93\xa2\x93\x92\xe2\x12\x92H\x9d1.\xe9\x88\xd4\x19\x07\xfb]\xaa3\x8e\xbc\xbfq\xd2\xf3\\\xf4\xbc/\x0e\x13[&\x8bH\x95\x0e\xc3\xea\xe2\xa2\x92\x1b/\x12\x11\xe4a3\xd0\\\xa1\xc5(is61F\x10#\xca\x0by\xaf\xf1\xb7\x96\xfd}_\xb6l\xf3\x02.\x8bj\x02+YW\xea\xba\xc8#\x90{\xfa\x85\xdd\xbb\x8a>\x03H\x15\"Z\xa8^\xbfe\xfd\xbe\xad\xa5\x0e\xa0\x84\xfa\x14\x14<\xc0\xa7b\xf7\xeaj\xb6\xcd#j\xc0+\xea\x87DO\xe1\x1d\x1f\xa3\x9bZ,o\x9b\xcb\xcb\x8e Z\xf9\xb4\xb8`\xec\xbew\xac\xcf\x1c-\xc7^\x86%\x88\xb2|\xae8\xce\xf6\x11TeD(\xeb\xfd\x96\xb5\xe5Z\xffMt\x10\x8ao 7r\xaeY\xad\x03\xbf\xaf\x87\xbd\xb3\xd9\x8c\xf9\\x\xabX\xd7\x8d!\x94\xbbM\xfb\x8e\x87\xfa\x0b\x8b\x8c\xe7\xd4\xfd\x91\x83;\x83\xa9-\xe1\xad\xcam\x89\x8d\xae\xb8V#\xf7.\xf4Z\xee\xab\x9a-X\x91\x19\xf6\xd5\x0co\x95\xbb(\xe6\x9f\xce/\xa1b\x97\xbd\xda\xb0+{\xd9\x83\xeby\xae\xd8\x12\x96\x1f\x88|\x08\x8f\xf3\xc5=\xb0b}\x0d\xc5n\xf7\x15\xa3hb\xf0\xe3\xfd\xbeX\x1aw\xf0\x88\x8a\x16\xda@\xdf\xee\x19\xf0\x7f\x94\xf5\xa6\\\x0bZ\x95\x02\x87T\x04\xc5\x85\xaa!\x99\xee\xcaz]\xed7\xb3Yl!\x9f2\xa0s\xb37&\xb0^c\xd3\x98w\x9b\x13\x1a\xca\xc4\xd9\xe7\xf3n\xf6\xb6fU\x10\x13\xff\x96u\n\x94\x17\x9f\xd7\xf8=\xf2O\xeeT}M\xe5U\xdd\xccys\xfak\x9c>BFf\xe9\x8b=L\x1f\xb5'\x96\xbat\x82\x9f\xba\x85\x82\xcf~\x1d\xfe-$a\xff\xa1Tz\xbd\xd2\xc1\x83r\xb0\xc1\xf8\xaa/\x1b\xf1\x02\xe4\x085\xfe\xa04eu\x08\xec\xca\xc1Ot\x1c\x1e\xbbp\xb0\x8b\x8c\x90\xc4e\xc2\xc9\xff\x06\xb7\xd51\xfb\xd2\xb9\x85\x7f\xe3e\x7fq\xa2\xbf\xdehB0\xa2\x80`j \"\n\xe8\xa8B*_\xc3\xe3/J\xe67+g#\xc8\xda\xc8\xcd\xdb\xc0372q7\xd2\xd8\x1b\x1ew\x91\xc2\xbe\x0b\x19\x1c\xb99\x1c\x91,\x8e\xcc<\x8e8&G$\x97\xc3\xd7\x86\x07\x96\x07\x96\xcd\x91\x99\xcf\x81btd\xe4t,eu$\xf1:21;R\xb8\x1d\x1egh\xe9\xde#\xf0;\x8e\xc7\xf08\n\xc7#\x8e\xe5\x91\x9d\xe7\x81ezd\xe5z\xe0\xd9\x1e\xd1|\x8fx\xc6G\xb0+\xc4\x89\xf4.f}\x04\x05zQ\x13*\x04\xf7#f\xd6\x15\xcd\xff\xf0\x0d\x82hY^\\\xf92\xb2@bx \x99\x99 i\\\x10_\x0bBI\xf1&\xf2A\x1c\xdez\x94\x0co\x1eN\x08\x9a\xd8\x80\xe0\x85D1CB*\x96)\xec\x90\x90O'J\x94\x89#\x12\x1fLq\xc4\x83\xb9\x84\xb6\x91\xc29\x96\x828\x9c\xd3\xdf\x88\xc3\x19j\x95\xa3\x11\x87\x938\x9cv#\x0e\xa70\xe2p\x1e\x1aq8\x89\xc3\xe92\xe2p\x12\x87S\x18q8\x89\xc3I\x1cN\xe2pJ#\x0e'q8\x89\xc3I\x1cN\x97\x11\x87\x938\x9c\xc4\xe1$\x0e\xa7a9\xf8t\xc4\xe1\x14F\x1cN\xe2p>N\x0e\xe7\x94M\xe1*\xf3\xf4\xaa\xd9\xb9\xea\x9a\x98s\xe42\x1f\x9d\xb2t6\x9e\x0e<^\xe6\xe11\x19\xc4\xd6\xcf\xfaN\x0b\xb7i\xf0\x8a 7\x0d\x0e\x9d$'\xcb\x93\xd4e\x8f\x96\xed$\x03p\x0c\x82S\x88\x91\x13\xdc\xa4\xc2\xec\xf2df\x1cy\xd9FH\xa6Q\xa6zee\x17y\x89)\xac\xee[/\xda\xeaBx\xc1\x87\xf2B\xa8\x11I\x0b\xa1\xbd\xdc\xe4y\xd1M\xed=\xbf]Z0\xf8\xd2\xc2g\xb9K\xc3\xbd*i\xb3R\xea\xd7\xa5\xfeK\x9f\xd4n\x9c?\xee\xf5\xd67\xcd\x17\xd8U\xc5\xda\xba\x01*M\x1di\xce\x9f\xe9?\xb67:.\xe1\xa3{#c3-\xa9\x8e\xcd\xbe.\xef\xc6\x83\xdcq\x81\x19]y\xf6B\xe4\x11\xe5\xab\x80p$\xe0\x03\x13S\xd9\xd9\xd3'\x03\xb2\xe2\xb8\xa9K<\xe0&\xa8.~\xb3\xaf$r\xa6XxP\xf4\xa8\x10\x1c\xa9\xea\x9e:\xc5\x96\x11\x1bR\xcb\xa0\xfa\xa6\xee\xdb\xfb\x91BV\x1b\xc3x\xe0\x9cx\xb1y\xdf\xb2\x8a\xdd\x14u\x0f[\xd6\x17\x9b\xa2/\x10\xccF\xd5I\n.\x19\x8eM\x16\xc5'\x8b\x08R\\\xb5\xb3\xb1\xca\x96\xf1\xcaP\xcc\xb2\xa3\x05\x01K?\xcb\xf0\xd6\xf1\x05\xcbJP\x8b\xa3\xa8e%\xa9\xe1\xea\x9c\x8d\xa8\x86\xa2\xaa-#\xab\xd1\x19\xc9\xca\xe8\x8c\xe4\xdf\xce\x19\xc9\x08\x06\xa6w\xf5\xe2%e\xce\xbcYx>\xb3\x13\x94\xad\xcb0\xa2gJ#zf\x9e\x15\x0e\xd13\x89\x9ei7\xa2g\n#z\xe6\xa1\x11=\x93\xe8\x99.#z&\xd13\x85\x11=\x93\xe8\x99D\xcf$z\xa64\xa2g\x12=\x93\xe8\x99D\xcft\x19\xd13\x89\x9eI\xf4L\xa2g\x1a\x96\x83*G\xf4LaD\xcf$z\xe6\xe3\xa4g\xd2Y\xcaq\x07\xd5\xd2Y\xcaG\x0cn\xf8\x14`:K9G\x14\xe9,\xe5\xdf\xf2Y\xca\x82\xae\xde\xdf\x9d\xdd|w\xd6\x95\xdb}U\xf4j\x17w\xd7t\x87\x04\xf4\x8f\xea\x12\xd0\xd7v\xc0\xee\xd8z\xdf\xf3\xee\xa2\x80\xbe-\xea\xae\x10\x1bur\xe1\xd2\xf5\xe5\xb6\x10?^\x15'4s\xed\xf7\x89\xae\xf4#e\x94_\x15\xdd\xaa\xac/\x9b\x00\x89J_\xa6\xfb\x13\xfeo\xfeR\xc4a\x9e\x17\xcd\xbeW\xe1\x18\xfb\x10\x15O+\x13\xcfYN\x08\xb2\x13xAn\x8b\xbag\x16eS\xc0l\xcc#\x08E\x98\xcdo\x80?\x15\xdd_EAtL\xb6\xc5]\xb9\xddoa_\x97\xbd\xd8\xb5\xbdm\xda/p\xab\xd09 \n\xf5wnv\xd5\x8e\xb5\xbcp\xb6E\x18\xaf5\x0f\xee\x03\xd5\xf9OE\xf7\xb9\x1b+\xa6\x0e_m.\xc5K.\xd6\xbd\xc4\xd1\xd7M\xad\x00\xd6\xa9+\xd9\xf7\x05\x1a\x94\xea \xcb\xce\xec.\xf5\x06\xfeq\x9a\xce\xa6\xe8\x8b\x85\x01tb9\xb8&\xf3\xba\xe8\x0b1\xdd\xa9\xefEi\xc6\x81\xf7\xb2\x15g\xd3\xca\xd5\x83@Z\xebM\xe5\x00K@\xf7PM-\xfa\xe8\xbf|\xfe\xf8\xc9\x03\x85U\xac\xbe\xea\xafa\xd7\xb2\xcb\xf2N~\x9f\x82W\xc9\x07\xae\x8e\xf1 }\xcfdid!\xf6U_\xee*\x17x\xa4\xcb8\x14\xc1\x8a\x9eU\xcdUb\xa4q\x81\xfc\xa9\xb9\x9a\xee`T\xcd\xd5\xa4OJ\x8d\xa7\xe5\x02v\xc3\xea\xfe\x11k\xe8\n7\xce_\x11!\xe7V\xf4}[^\xec{\x7f\xdaE\xa8\xba\xd2\x02i \x80\xab\xba4L\x00\xa499\xb6\xa6\xa1b\xa1-\xf8\xd1\x8f\xe6\xc5\x8aG;\xd6\xe3\xcbz\xc3\xee\xb0\x8f?\x9c_\xd9\xcd>\xeb\xb2\x1b\xee\xab\xd5\xf6\x86\x7fQ/u\x8b\x93\xeb?E\x03\xff\xc2\xee\x9f\xcbE\xc3\xae([\xdf\xde\x05\xb7\xf9Q\xefE-\xbfV\x14\xa5\xdeSLQ@9lw|\xad\xa2\xc96\xb0a7\xac\xe2-R\xac\x9c\x8a\xbe\x17\x8b\x99a\xa7\xd5\xe9\xd0\xec\x9az\x0fJ\xa3\xb7\x0e~`We\xfdC\xd5\xac\xbf\x9c\x0c\x7f{Sof\x7fyu\xcd\xd6_>\xdd\xb9?\xeaz3\\\xfb\x9aU\xe5\x0dk?\xddy\xd0\xb6\x9f\x8a\x9e\xb5'\xe6\x9c\xb7\x83mq\xcf\x17o2\xfdr\xa3\x96\xd1\xfd5\xeb\x98\xea\x18\xed\xb1\xc6EZ\xc4\xb93(\x04\xd0U\xe5Z,\xcc\xe5+\x90=\x84b\xdd\xdd\xb2\x96\x01\xdb\x96}\xefd\x00m\xf6\x92\xb7);~WM\xc7\xf1\xc0\xd5\xf3\xfbv\x7f`\x98\xdb\x9b|\xeb\xdeH \x90;\xa8v!\xdc\x8f\xac\xbd)\xd7\xect\xf0A\x84jaD\xa8&B\xf5hD\xa8&B\xf5hD\xa8\xee\x89Pm7\"Tk#B5\x11\xaa\x89P\x8d\x9c%\x11\xa1z0\"T\x9bF\x84j\"T[\x8c\x08\xd5\xd6k\x88PM\x84j\x87\x11\xa1\x9a\x08\xd5D\xa8&B\xb5a9\xc8\xadD\xa8\x16F\x84\xea\xdf\x03\xa1\xfa\xa2\xd9\x98c_Y\x1f\xfc\xc9Iz\xb6a?\xffO\xcb._\xc0\xd3\xff\xff\x99\xb1qxV]lO\xfb\xbb\xd3\x9b\xefFDJ\xca\x1c=U\xf7\xceiv\n\xc0\x9a\x12\xed\xfa;u\x8dM\xe3\xf5O\xac\xfft\xd7I@\xef\x92\xf5\xebk\xde\xa9\xdfu\x82\x0cj\xa2\xb5\x13\xfe\x9cq\x93\xfa\xf9a(t\x81 \x19\xc5\xd2\xe8\xdf\xd3'\xe3\xd3 \xb73\x8dp;\xdc\xbe\x0f\x10nG\xb8\x9d\xf3J\xc2\xed\x84\x11nwh\x84\xdb\x11n\xe72\xc2\xed\x08\xb7\x13F\xb8\x1d\xe1v\x84\xdb\x11n'\x8dp;\xc2\xed\x08\xb7#\xdc\xcee\x84\xdb\x11nG\xb8\x1d\xe1v\x86\xe5\xc0P\x08\xb7\x13F\xb8\xdd\xef\x01\xb7\x93\x89q\x86\x8b\xc9\"R\xfe\xaas\xc6\xaa\xb2\x93{\xde\x86\xd0\x84\xb8\xe2`E\x9a\xa2\xa51\x87K,@\x89c\x01\xbfn\xaa\x8a\x89\xe2\xfc\xa8\x96\xef\"1\xfc\xa0\xae|\x1e\xc0\\U\x15?\xf2\x9a\x9eK\xc1\x13\xfe\x87\xe6\xb2\x1b6\xde\xcdDC\xa1\x89\xd2\x19\xc7\xf1\\T\xcd\xfa\xcb\xd2\x00`\xc5DH\x11*Un\x87\x14\xa1\x8e\x18\xdc\xb0\x96\x11)B\xe5\x88\")B\xfd\x16\x14\xa1\xc6W+\x04NV\x17\xee\xee\xfb\x8f\xb3\x9d\xdc\xe7\xf0\xee\xc3\xeb7\x1fV?\xfc\xeb\xea\xf3\xdb\x8f\xef\xdf\xbc:\xff\xf1\xfc\xcd\xeb\x17\xd6\xbf\x0e\xbb\xc6\xea\xfc?93\xec\x9aV\xc8B\x89G\x9f\xc2;\xfe\x7f?\xdc\xeb\xc6/\xbe\xab\x97\x1f_\xc9\xef\xa9\xec`]\x1c\x1c4g\x94\xe1\xe5\xc7W/&\xff5\x9e8\xd8\xad\x99:n\x90?\xc1\xe9\xe1\xf5\x9b\x89\x0b\xfe\x9f\x83\x0f\x1e\n\x87\x93\x94\xd7s\xf0\xdd\xb1z\xbf\x9dN2\xec\xe1u]\xf2\xf2\xe3+\xd7O\xbc\x1e\x93\x97*\x197>\xf7n\x02\x93C\x12\xec\x87\xb6)6\xeb\xa2\xeb?\xdd\xc1\x85\xfe\xb79Y\xb1\x12\x96\x8c\xbb\xd4\xcf\x0fCX\xea\xe3\x99A\xfd\xddp|\xb4\x8bg\x93$\xb0\xe4;\x8c7\x88\x13]\x06\x0f\xdfU\xe7\xfc}\xd2sC\xf5<\xcb\xb5\xfd\xddu\xd1]'\x16d\xf2J>M\xa7\xa9|\xedwm\xdb\x1cX7\x1b\xd6\xed\n\xd7\xe1\xa9\xc1\x87\xaa\xba\xf1\x85\xacp\xa3\xd5#\xe0U\xb3\xb1-\xc9\xecT-\x08\xd2\xb5\x00\x15\xe9I\x08\x06\x95\x0b\xfeL+D\x96\xae\xab5y\xd0\xd3\x0fr\x88\xe43\xca\xeeD\xef2?\xb5\xdc\xd8\x16\xb7\xabcKL\xf17\xdf\xec\xfb\xdd~\x18\x7f\x0d!\x98\xa7\x1dT\xcd\xd5\x15k\xe1Y[\xdc\xaa\x87}{\n\x7fq\n#\xb9\x11\xda\xba\xa9\x9fo\xf8Jr[\xd6e\xd7\x97k[\x8c\xab\xe6\xea\x11KPm\xbb\xabUP\x83(\xdc0\xa5\x85\x9b'\xf8\x14\xc6\xa4\x05\x1b\x01\x04\x94\xbd\xa4\x85\x82+\xed\xeb\x08^ \x97\x81k\x90\x81\x90\x86\xd3\x00\x93\x86\x0b\x8c4Dx\xa4\xa1\x83$\x0d\x1f*i(\x850i\x11Q\x93\x86\x14\x00\x93\x16\xe9\x1d\xd7_MmT\xd72\x8e\xaa\x1e^0\xdc\xb6\xc5n\xc7Z>ko}\x8c\x9f\xd1zuvpQo\xd4\x1a\xaeh=\xa4\x13\xd3dE;(\xeb\xaeg\xc5F,6\x8b[\xd9\xcd{\x90\xa8\xe8\x9a\x7f\x14\xcf\x91T\xcc\xde1\xb9\n\x0e\x9a\xe1a\xb2\x0f\xa49 \xa2\x00\xe8\xef\x02R\x93\x1d<\xfe\x0e\xf8n\xbe>(k\xc2C0\xe5!w\xd2\x03>\xed!S\xe2CZ\xea\x83\xc7\x1d\x0f(:\xf9aq\xfaC\xee\x04\x88\xc8\x14\x88\xccI\x10qi\x10\x91\x89\x10\xbe6<\xa4H`S!2'C\xa0\xd2!2&D,M\x89HJ\x8a\xc8\x94\x16\x91\x92\x18\xe1q&R&\xc2\xa9\x11GI\x8e8^z\xc4Q\x12$\xe2R$\xb2'I`\xd3$\xb2&J\xe0S%\xe44\"\"Y\">]\"\xd8\x15~\x8bH\x98\xc8\x902\x11\xdc\x10@M\xa8\x10\x89\x131\xb3\xae\xe8\xe4 \xdf x\xd1\xdc0D\xfa\x04\xb6|\x19S(b\x92(2\xa7Q\xa4%R\xf8ZP\x17N\xa5HN\xa6px\xe3O\x0b\xa5S\xe4J\xa8@g\x05 \x92*\xa2\xd2*\x02,\xe8\xa4\xd4\x8a\x90O'\xc52S\x82E|0\xf1I\x16\xa1\xba%$Z$\xa6Z\xf8\xa8\xaa\xd9\xd2-\xd0 \x17\xb8\x94\x0bl\xd2\x05\"\xca\xf1\x89\x171\xa9\x17\xbe\xe4\x8bL\xe9\x17\x91 \x18\xcbR0B\x01\x8dH\xc38B\"F\xb0t\xce\x96\x9e/\x1d\x03\x91\x90\x91\x9e\x92\xe1p\xc7/\xf3%edN\xcb\x08%f$\xa6f8|\xc9\x95\xa1oq\x8cH\xcf\xf0q\xc8})\x1a\xf9\x934\xb2\xa7i\xb8\x135r\xa6j`\x925\xe2\xd35\xa2\x126\x12R6b\x936\xbci\x1b~\x12=\x9eF\x8fM\xddHH\xde\x88L\xdf\xf0T7%\x85\xc3\xe1\xcaH\x8f\xc0}\x12\xb84\x0eO\x93\x17'Mz\x129\xb2\xa6r\x04\x929\x8e\x93\xce\x91\xab-F\xa4t\xc4$u\x8ci\x1d\xa6\xf5\xe5\x96u}\xb1\xdd%\"C\xb8\x95\xef\xa7r\xdc\x90\xdf\xb5\xec\xa6l\xf6\x9d\xca}\x80\x1f\x9bV\x91\xdc:\xf8\x1f\xf0\xdd \x94\xfd\xd3\xce\xf3fo\xc5\xb5\xa2\xf9o\xca\x82\xf7\xd5\xaeW\"zP]\xbf!!C\xee\x0b\xdc4\xfd\xb8\xee\x94%\xf9\xa9\xe8\xfaW\xcdv[:\x8f\xd6\x1a\x8b\n\xdf\x7f\x0f\xdf\x9d8\x87Z^\x03\xbe\x1a\xed\xcaN\x94\xc0\xe6\x90\x8e\xdc\x1b,T]i\x08\x8a\x0d\xa2\xea\xd20\x01\x90\x86\"\xd4\xa0b\xa1\x0d\xb5\xe3%\x0d\xc9\xb89\xd6\xe3\x83t7i\xf2\xf1\x98#\xf4\xc0Ck\xb7\x19\xaew\xd1FG\xee\xb9\xae\xfb}\x1e\xb97\xd0e\x14\xc7I%%j:\x8f\\E\xaeY'\x9e\xed\x9a)\x99\x8c\x05\x81e8{}\xb3\xf4:\xd7\x05\xfa\xeb\xa6c\xaeG\xcar9\xdc\xa9\xe9H\xa7\xd2\xfe\x1b\xf7\xcaU{\x17\xe7\xc1\n\x12N\xdd3}\xfa\xdf)\xfc\xf5\x9a\xb5\xac\xe8\xe0\xa7\xe6\xaa\x9b,/\\\xeeD\x0dN\xbc@\x87\xb1\x88\xd9\xb2\xbe\xd8\x14}q2\x94C,h\xa7U\x0dW\xd3\xbd\x0b\xfb\xb1\xac\xd7\xec\x05\xac\x9bn\xdbt\xcf\xbb\xcd\x17\xf8\xc3\xe9\x7f\xfd\xe3\xe9w\xdf\x9d\xf0\x7f\xfc\xd7\xd3\xff&\xfe\xff\xbf\x1d\xdc\x1dn+\x9f\xee\x06\xdew\x80Z\xd5\xb2\x8a\xdd\x14u\x0f\xfd\x9d}q\xd5\x19$9\xb9\xc6W\xba\x0e\xf2|\xdfNNt7l\xddl\xe6\xc7N\xfb\xb23\xc1L\xceXrh\xa3\x99\x19B\x876\x92\xf8khf\x11\xfe\xcc\xa4%\xf1\xa1H\xfc\x15\xc3\x82\xca\xc2\x81Ja@\x91\xf8kF\xdeS\x0c\xeb)\x8a\xf3D\xe2\xafK\x99N <\xa7,,\xa7x\x8e\x13\x89\xbf.\xe16\xc50\x9b2\xf3\x9ap\xac\xa6\x8c\x9c&,\xa3\xc9\xb2YI\xe2\xafSCl\xa9`gI\xd1\xfc%\x12\x7fE\xb1\x96R8K$\xfe\xea\xba,\xc8S\x8a`)a\xa4Mc\x18J$\xfeJ\xe2\xaf\x18\x1e\x12\x89\xbf\n[\xc2<\"\xf1W\x9b\xa7 \xd7(\x95i\xe4\x1c\x1bH\xfc\xf5\xd0H\xfc5\x81Q\x14\xe6\x13\xc5\xb2\x89\"\xb8D\xd1L\xa28\x1e\x11\x89\xbf\xc61\x87H\xfcu\xb0c\xb0\x85r\xb4\xb9\x08\xa6\x10\x9e'\x84\x11\x7f\xcd|h\xa3\x13\xc4\xf0\xca{ \xc9\x88(\xe8%\xb0R\x9f\xac\x84\xf5\x03\x06\x08\xad\xb8\xf5e\xafo=\xc8\x92\xa3,\x87\nr\xd2\x9e\xc3\x0f\x1f\xde\xbd|\xfd\xea\xe5\xc7O\xab\xbf\xbc{\xfd\xc6\xa9&\xe7\xb8\xfc\x87\x9f\xde\xbd\xfa\xdf\x98\x0b?\xfe\xeb\xdbW\x98\xeb^Z/\x1cd\xe9\"J\x1b\xdek\x18\xd0\xc7\xbf4\x1bf\x88\x10\x8a\x9d\xfbA\xa7\x8eG\xdb\x01c\x82\xc0u\x0f\xc0L\xf8\xf0\xfe\xd5\x00g\xda\xda\xbe/\xea/\xe0\xdfY\xdb(\x02\x89\xf8\xf8\xf9\xf3\x85\xac\xa0\xa3\xdf\xb2\xbf\x94\x83X\x89\xbf\x1a\xd8so\x88\xf1 T\x8a?G\xc8\xb8\xc8~\xad\x12\xca\xae\xb7E\xd9w\x0e(A\x8c\xf1wj\x17u-\xd8l\xbdT8-\x0e\xc5\x86\xdd\xc5\xe5o\xfc\xa0\xb4\xfc\x8fY\x0b[\x80\xa2\x9a\x8c\x8a)#T\xcd'\xac\xb8\xc2\xbe\xb4\x96\xf6eRq\xa5&\xacm\xcf\xa7\xdc\n\xc2a\xcf\xe6\xc5\xf27\xea */\x14;FP^\xfeg\x1f\x85\xc9+'\xf36l6o\xf9\x17\xb7$\xe4\xd3\xe9\xa1\xb6g\xbf^\x17\xdd\xf5?\x94d\xa3\xf3p\xdb\xe1X[\x19\xca\xfb\x89L\xe0\xe1\xb1\xb6\xea\x87\x87\xd1\x87\xc4\x1chKG\xd9\x02\xb1\x19\x82[\xf9\xe1\x11J\x1a\xb1\x19\x88\xcd`7b3\x08#6\xc3\xa1\x11\x9b\x81\xd8\x0c.#6\x03\xb1\x19\x84\x11\x9b\x81\xd8\x0c\xc4f 6\x834b3\x10\x9b\x81\xd8\x0c\xc4fp\x19\xb1\x19\x88\xcd@l\x06b3\x18\x96\x03Y&6\x830b3\xfc\x1e\xd8\x0c\xd7EgvQ\x93%\xe4S\xfe\xe3p\x9c\xe4\x9d\xb8\x96G^\x9c\x1fw\x02\xac\x16i\xba \x9a\xd85\xbbS_\xf1\xe4@\xa7\xb2~1\xdf\x18w\xb2#,\xcb\xf3\x10\x8e\xb7\xdf]\xb5\xc5\x86\x9d\xdd|w&$\x05\xd8f\xb5\xab\x8a\xfa\xecW^9\x1f\xaa\xf7R^\xfd\xbe*j\x95\x87\xcf+\xa1\xe5Y\xaa{P\xee@=\x01\xb8[>\x7f(\xfbND\xce\n\xfe\x19^\x9f\xe8\xca>\x04\x04\xd8\xc7#n\xae\xa3\xdc\xbc{$\xfe\xa3\x10&\xf5PR1\xaa\xf1\x98\xc7\xb9A\xd1\xab\xcf\x9c\xff\"\xe2z[t:\xe01\xf0\xf2\xff\xe1\xed\xd0\x88yJ\xe6\xb7\xf0qf6\x87\x0f\xef_\xcd\xbfuJ\x05'\xf04\xb4s\x88\xd9|\x03\x02O \xdf\x14\xbd\xc8;\xaf\xcdX;\xfc\xc9ssZ\xf8\xb3f\x12\xb8\x1e\xdc\xb2b}mH\xc9\x0f\xcf\x15\x05fw\xf63m\xfa2\xf9\xcb\xd2\xfb\x9c\xbc6\xcf\xb9\x9f\x05\xdf\xdf'uN\x8fj\x82#1B\xbf\xc3\xad\xda \xdd\xb1\x96?\xd7\x83\xee\xfc\xc4\x8a\x1b&\xdei\xdf\x08\x9e\xca\xbf\xb3\xb6Q\x13u\x85\xcb \x8a\xcbs\xa9\x0b\xb0Q\x91ux+\xeb\xaeg\x85\xb5\xf5\xbb\xb8#\x10\x13<;\x87\x04\xe6\x81;P\xfa\xd7\xf6\xff\xb1\xf7\xee]r\xdbH\xbe\xe0\xff\xfa\x14X\xef\x9ek{G\xaa\xd2\xdb\x96\xee\xfa\x9e\x95J\xa5vM\xb7\xa5\x9aR\xc9}\xbbg\xe7T#\x99\xc8L\xba2\xc9\x14\xc1\xac\x87=\xfe\xee{\xf0\"A\x12O\x12i\x95\xed\x883gZ\xae$\x83@\xe0\x15\x88\xdf/\x00f8\x13\xa1\xc4a7\xb3\xa2\xf7rG8g\x1bp\xde\xe9$\x88@\x89\xb1\xe3\xe4\xc5\xa2\x1cY\xf7:\xaf\xd7\xc4\xd1\x19xHL\xbb\x1a\xa5 \xdc7\xb3R\xb1(%4$/\xd9\xb0!Ce\xf1 [a;\xd0Mw\xd9J0\xb7\x96y-\x0f\xcb\x10C\x97\x07\xdcq]V\x14e\x1c\xdf\xc6\xbb\xba\xdc\xe0:\xcf\x1c\xc8\xa9*`]\x1a\x1eP\x0b\xc2\x858g\xe2\x82\xd6\xb8v\x8e=\xc7%F>&\x87\x9f\xcb\x11\xd0N(x\xf8\xa2\xb1\x8c\x0e\x87\xbeAP\xdf\x11\xe3J\xcb\xea\xf0\xf2:R3;\xc2\xb9\x1d\x89\xd8\x1d\xe3\xf8\x1d\x0eu\xfcp\x99P\x86\xc7d\x8eGj\x96G$\xcf#1\xd3#\x8e\xeb\x11\xc9\xf6p\xf5\xe1\x86\x07\x12\xca\xf7H\xcc\xf8\x08\xe2|$d}L\xe5}\x8cb~$\xe2~\x8ca\x7f8\x94q^\x88\x9f\xff\xb1\x17\x06\xc8\xfe8 {a\x81\xc4\xf1@\x923AB\xb9 I\xd9 \xe1|\x90hFH<'\xc4;\x15~\x1d\xc0\nI\xc0\x0b\xf1\xde\xc5\x18\xe4P\x05\xb0Cb\xbc\xaeh\x86\x88k\x11\x9c\x95W$\x80#\x12Z\xbe\x84<\x91\x18\xa6Hb\xae\xc88\xb6\x88\xab\x07Q?_d4c\xc4\xa2\x8d}\xcd\xc7\x19I\xc5\x1a \xa6>\x040G\xa2\xb8#\x1e\xa8w\x14\x7f\xc4\xa7\xd3\x8a#%b\x91\xc4\x1b3\x9cI\xe2\xab\xdb\x086\xc9H>\x89\x0b\x8fK\xc6) f\x95\x84\xf1JB\x99%\x01V\x8eg\x97\xc4\xf0K\\\x0c\x93D\x1c\x93H\x96\xc94\x9e\x89\xcf\xa0\x11\\\x93=\xb0M\xbc\xa5\xb3\xf6\xf4t\x9c\x93\x00\xd6\xc9x\xde\x89E\x1d\x0f::\x98'\x89\xb9'>\xf6\xc9H\xfe\x89E\x97\xd8\x19\xba6\xc7\x01\x1c\x14\x17P\xee\xe2\xa1\xa4g\xa2$\xe7\xa2\xd8\xd9()\xf9(!\x8c\x94xNJ\x14+e\x04/%\x96\x99\xe2\xe4\xa6\xb8\x99\x02\xe1\\\x81P~\xca\x08\x86J$G\xc5Q\xdd1<\x15\x8b*\x8d\x03\x126$\xc2\xb8*\x8e._,\xddl\x95\xa4|\x15\x0fce?\x9c\x95T}1\x82\xb7\x12\xc3\\i\xb9+]\xf1\xa1O'\xaf\x8f\x1e\x90\x02\xcf\xd6d\x8e8vDU\xd6\xdc\x83\x9c7\x82\x80\x9c\xe4\x95\xe6-\xcco\xd6&\xcf\x14\xe7X\x0fk\xcd\xbc\xa6\x1d\x9a\x84}\xcag\x1d\x9cu\xb7\x0d\xbe\x94\xc7\x93\xb3\xc24\x18U)\x03\xceUE\xb2\xdaW\x8a\xaf(Y/\xbe\xee\x16f\xc6#oz\x1dP\x99e\xbb\x8aZo\xb7\xa7\xa5\x18\x14YY\x14$\xabeDL\x19\xe8\x8aT\xf9\xe2\xb6\xc5\xbd\x0br\xed+\x96,ONe\xf0bv+\xb5\x88\xd1\xb3\xad\xcar\xa1\x82\x94\x16\x15\xea\xac\x82>\x9d\x82\x17\xcc\xea\xf5\xb6\xd6\xe5!T\xd6\xe6M\xad\xd8>\x9b\xed\xe7\x99>Z#\xba)\xcbz\xb5\xbeE8\xabJj\x0b\x99\xb1\xa6,T\x87Q\xd5\xee>\x1c\x90\xc4\xaf1\x84\xc6'\xf1\xeb<%H\xe2\x87$~\xd3\xef\x90\xc4\xaf $\xf1C\x12\x7f+I\xa1\xdd\x18`7\n\xd6\x85$\xfe\xa9`\xee\x08(7 \x90\x1b\x0f\xe3B\x12\xff\x14\xf86\x06\xbcM\x0c\xdd\x86\x01\xb7 a\xdbP\xd0\xd6\xb0\x1f\x83$\xfe\xae\x04\xc0\xb4\xa1^R4D\x0bI\xfcA\xc0\xec\x18X\x16\x92\xf8m\x8fy\xa1\xd8\x08 6$E=\x06\x84\x85$~H\xe2\x0f\x81Z!\x89\x9f\xcb\x14p\x15\x92\xf8M\x9a\xbcp\xeaX0\xd5\xba6@\x12\xffP \x89\x7f\x04h\xea\x87Lc\x01\xd3\x08\xb84\x1a,\x8d\x83J!\x89?\x0e\x1c\x85$\xfeF\xf6\x01\x88\xa6\xe8s\x11`h8\x14\xaa\x16\xea\xd0\x84\xf8M9\xdf\xad\xc9\x85\x8c\xb9P{N\xfc\x0f\xfc\xc1\x1f\xe5s\x9d\xb4\xf8uNy\xb0T\xe8R\xf1\x1b\x8a\x16U\xb9\x11\x08\xa41I\xbe\xabQ>qg\xf3\xe4\x8d\x86\xd2\xa5\xfe\x0c\x00\x90=Y>(\xf2!\xf1\xf1\xdea\x0d\xb2\xaa\xc6wd\xf5'|SE[v\xf6t\xd8\xa6`\x19k\xcb\x82\x0e!_g);\xdd\xa3\xd3\xc9\xb4\x1b\xe6\xb1\xea\xad\"\x02G\x87\xdf\x1a\xae\xb1\xfeXK\xaf\x93\xf0\xe0v\x7fx\x88x\xa6LP'y\xd5~\xd9\xa0Pi\xea\x16&\x00_\xee\x0e\xae\xf1\x10so\x90\xf6\x9e\x19\xdeC\x0e(3\xa0\xccC\xf1\x8f\x1c!\x802\x03\xcal\x16@\x99\xb9\x00\xca<\x14@\x99\x01e\xb6 \xa0\xcc\x802s\x01\x94\x19Pf@\x99\x01e\x16\x02(3\xa0\xcc\x802\x03\xcal\x13@\x99\x01e\x06\x94\x19PfMR ~\x802s\x01\x94\xf9\x8f\x822\xbb\x8e\x8a\x97XX\xe181\xbew\xd4\xad\xf6\x86@\xce\xc4L\xd5\x1c\x19\x8f\xdb\xcd\xba\x01\xfc\x1b\x82\x85\x1a\xfe\xcc\x8f\n\x16y\xbc9\x95A\x85\xc1!\x10\x0bR\xcb#u\xd9\xda\x17\x01k#y\x80\xfd' \xb2+iO\xb0_\xe0u\x07\xdd2\x04\x0cl\x88\xfd\xe0\xde\xef\xf6pYUcq\xbe\xec\xe1/|\x96\x13G\x04\xbb\xae\x02\xd7\xcc\xfeQ\xea:R\xaa>\xf0\x84\xe1\xce\xa1\xf7\x8d]E21\x1f\xad|x\xf2\xe8[\xa3\x8a\xcf\x07u\xb5\xa3l\xb3zI\xaa\x82\xac\x9b\xd3\xd5\x0brSw1\xdc\x9c\xca\xbc]t\"\xb5q\xe7C;y\x94\xd6e\xc5\xc6\xbdH1\xe6^\x85<\xfd\xb8\xab\xc0W\x97\xb3\xd3#q\xb8\xb1\xd8\xc3\xab0\xd0\x9a,qv+k\xaa\xc2\x10\x1d~\x82Y\x9f|\xf2\xce\xf2\x14l\xbd\xc3\x86%\x8e:\xa4\xbfvB\x82\xdehXH8)9\x18\x18\x06\x05\x8e\x01\x02\xdd\x80\xdf(\xb8\x8f\x7f\xc2\xa2\xd0\x0b\xf6%\x80\xfaF\x02}\xf6C9\x82`\xbeI \xdf(\x88\x0fa\xebA@u\x18\xc07\x06\xdes\x05\xdd\x83\xc0\xbd\xc4\xd0^\x10\xb0\x97\x10\xd6\xf3\x82z\x89 \xbd)\x80^4\x9c\x97\x00\xccK\x0c\xe5y\x80\xbc\xe40\xde~@\xbc\xe4\x10^8\x807\x0e\xbes\x18\xdd\x07\xde%\x83\xee\xc2\x80;\xc3\xce\xc1>\xbf&\x06\xed|\x90\xddD\xc0\xce\x01\xd7y\xdd\x13/T\x17\xe6\xbf\xa4\x85\xe9| \x9d\xbfL\xe3\x00:5\xb3\x1b\x14\xfa\xe0\xb9\x84\xe0\xdc\x04h\xce\x0c\xa8\xbb\x80\xb9\xb4\xb0\x9c\x1b\x94K\x01\xc9\x05aJ\x1e8.\x18\x8c\xb3\xc7\xcd\xe3\x818\xbb.c\x8c* \x04\x17c\xacP\xf8\xcdo\x93`\xe8m\x04\xf0f\x8e\xe7%\x02\xdd\x82 7?\xe0\x16\x02\xb79\xad\x18\x0b\xb5\x85\x02m6\x98-\x01\xc8\x16\x01\xb1\x8d\x07\xd8\x1c0V(\xb8\x96\x18Zs\x94\xc8\xd8SG\x81j\n@3\xe8\xb3@j\x89\x015;\x9c6\x16L\xe3\x11\x01S\xc1\xcdPZZ \xcd\xb6\xf1\xf3\x82h\xb6(\xbf\x0d@K\x0b\x9f\x8d\x07\xcf,@\xd9(\x98\xcc\x0b\x89\xc5\x01b\xc1pX$\x18\x16\x03\x85Y\x810{iB\x01\x890\x10,\x12\x02\x8b\x00\xc0\x8cUK\x0b~\xd9\x06\xc5\x04\xe0\xcb\x18\xa7\xb0\xc2^\xe3@/\x17\xc0\x95\x1e\xde\x9a\xde\x93\x82\xa1\xadP`\xab\xbbD\x06dY\x99!\x82\xf1\xd9V\x16\xc8\xa1\xf7,d] \x81\xac+\xc8\xbaj\x05\xb2\xae \xeb\xaa\x951\xb0\x8cU\x19d]\x0d%\x11D3\x0d\xa4\x19\x01\xd3$\x01j\x92C5^\xb0f\x0fp\xcd\xbe\x00\x9b=@61\xa0\xcdX\xd8\xc69\x87\xfb\x80\x9b\x84\xd0M(x\x13 \xdf$\x07p\xfc\x10\xced\x10\x07\xb2\xae\xbc%\x1b\x07\xea\x18UA\xd6\xd5\x18x\xc7\x07\xf0\xa4\x81x\x02q\x0b/\xcc\x13\x01\xf4x\xb3_\"\xc1\x1e\xc8\xba\x82\xac\xab\x10\x18\xc8k\xd5X((\x1c\x0c\x82\xac\xab\x9e$\x86\x86 \xebJ\x97\xb1@\x91Q\x19d]E\xc0FS\x80#\xa3:\xc8\xba2\xbe\x10\x045A\xd6U:\xe0 \xb2\xae&\xc3Ri\xfa\\04\x15\x0eN\x85e]i)@\x9a\x1eW\xd6\xd5 \xb3\x86\xa8\x00\x89\xbc\xe2n#7\xbe\x94_\xe0W\xf0\xac&\xd2\xa3*\xf051\xa7\n\xf1\x92\xeav\xc5\x9cT\xb2\x0f\xf0\x14\xa0~.\x11\x8f\xf2\x97U'\x98\x94\x17/\xfb\xb1\xf76\x8f\xaa\xaev\x9e4*\xd4\x05\x86\x9a#&\xad\x07\xa2\xe6\xb3\xec0++r\x98\xadpQ\x90\xf5\xe1\xd5#\xf5O\xc7q\xa8G\xf2\x89&U\x8aG\xa7WD\xdc/\xa8~d\xcbS7M\xa9\x93a\xa4\x94\xdcS\xd5\xbc\xa39E]s\xe8R\x7f\x06d\xcc\x92\xce$D\x9d\x1c*{\xb0\xe8f\xedE\x91\xac\x1a\x88\xd8o\xb6\xf6G\x94H\xb1\xdb\xd8\xf7\x1a\x0f\xd0\x87\xf3W\xe7\xc7\x17\x1f\xdf\x9d\xbc;9?y\xf5\xb7\x93\x7f\x1e\xbf\xb9\xf8\xf8\xee\xc3\xe9\xf1\xd1\xc9\xdb\x93\xe37\xde7\xd9{\xde\x87\xce\xcf\xfe\xf1\xfe\xf4\xf8\x9d\xf7\xb9\xa0\x87\x8e\xfe\xf6\xfe\x83\xb5`\nW\x1eY\xaf\x90\x10\x16\x13\x91\xaa\xc7\xd1 B\xf9&\xafi-6\xab\x14\x1c0\x91\xcd(\xc0 {\x0b\xc9\x1eB\x1dS\xbc\xa8\xf2}\xc4*s\x1fIk\xdeG\xec\xff\xa3\xb2B\x9dZ:v\xc6\xfe\xe6~\x89\xde\xc8=\x87\x9e<\xe8\xd0\xc4\xf4\xb0\x81\xadj\xcf\x16\xfc\x9f\xd8\x04Lk\xcc\x93\x17y4zKxxx\x85\x8b9]\xe1Kc\xf4\xb0\xa7XV\xb2\xaf\x1bg\xcc\xb9X\x93\xf9R\xeant\"Z\x93\xad\xc2c\xb2rW\xd4\xa4\xda\xe2\xaa\xbe\xed\xe7]Z?i\xfa^V\xb2\x85\xba\xee\x7f\xec\x00\xbd\xdf\x92\xa2\x9d8qe\xb7UE\xf0\x9cC\x1c\x94\x14s\xee\x15U$#\xf9\x95\xd8%\x92\xda\x12J\xe6\xd2\xed\xf3\xfd\xc2\xcd\x08+\xc3\xba\xa4D\xe8\xcdp\x81\x8a\x12\xad\xcbbI*\xb6\x04\xf2x\xb6\xfa2gP\xf0\x0f[\xbf\xe7,PY\xcd \x9bh\xbbx\xf7\xfe\xddq\xc0\xa0o_\xf8\xf8\x8e\xffo\xc0\x93\xee\xe7\x9aY(\xaa\x1c\xa1\x93\x8f\xadz/\xd1\xcf\xa4*\x1f\x88}%\xf3,\xa5\xf9\xad\x8aT\x8b\xba\xfa_\xcf0/U\x1f\xe1\x9dm\xc6\xe6\xc0u~\xc5[\x96\xf9\xc7\xc5\xadPz_zQ\x1b|\x8b\xe69\x07\x19x\x1a:\x9f\x0d\xd8\x03.\x00K\xbcZ\xaf\xc8-\xba&\x95p\xe4\x9cc\xa4\xd3$m q\xa5\x17\x8f\xdc\xe0\xac^\xdf\xaa\xd8\x82(\x85\xe9S\xc6/\xe9\x13\x8ao-\xef\xcd=Ak\xb8\xd5\xbb@\x01\x1e\x06\x7f\xa6\xac\xea\x8b|\xee\n+\x06\x8c+\x14\xd1\x0d\x91\xfc\xaa}\xce\x95\xe6-\xafe\xc8\x80#yN}|\x9e\xeax?\xf6\x86\x97\x0f\xa4\xa9\xb4j\xbb\xb6\xb9\xec\xd5\xb2t\x10uG\xf7\xc5\xaa\xdcZ\x1b\xca\xe5\x80\n\xb1\xba\xa1B\x02\xea\xe3\xbbF\x1e5GE\xb4\x85n)S\x15\xbd\xcf\x1d\x181\x8c%\xb8\xc6\xda\xd1\xde\xf5\xe4x\xe3\x1b\xae\xd2A\x0cR\xa7 p\x13\xf3\xbd{]\xe1+\xcb\x045\xfd\xe8~\xbf\x1d\xca-\xfe\xb4k\x97)\xf9I5y\xe5\x14\xe1eE\xc8\x1c\xed\xb6e\x81\xe6\xbbJ\xde\xaco\xd5\xd7\xf8\x07\xc6'\xbc\xda\xf1\xc8\x86\xdc\x81\x1cM\xf9\xb2(\xfb\x89\x0bj4v?!,3\xb5age\xb9&\xb80M>\x9d_\xec\x97\xb1\xb9\xd2\x05\x0f\x7fiY\xa2\xbf\x1en\xcb\xaa\xa6\x87\xbfH\x96\xaa\xebB6E\xdelr \x0b\x9eFx\xd4el\x9bR\x07\xef\xa9j\xdf\xed\xccA+UK\x91T1\xa5e\x96\xe3\xe6v6\xd1\xcd\x05\x81McR\x0f\xd5\x8c\xe7q9\xd2\x08\xa7$\x11z\x03\xe1\xaeT\x1bo>\x99\xe7=G\xf2`X\xea`@\xe2`@\xda\xe0\xa4\xa4\xc1\x90H{\xda\x84AO\xba`\x9adAo\xd3\x06\xa6\n\xee)Q\xf07O\x13\xdck\x92\xe0\xf8\x14\xc1\xdf4A\xd0Q\x18wr`\xa2\xd4\xc0\x89sUT2^hJ`HB\xe0\x98t@\xd7\x9e\xab\x95\xd8T@o\xca\xdfgH\xf8\x8bJ\xf7\xfb\x0d\x92\xfd\xfc\xa9~c\x12\xfd\x9c+?\xf2\xae\xfe\xc8\x9f?\x140>P\xf0z\x85\x92'\xf7\x85\xa7\xf6\xf9S\x97\x02\xab:1\xa9/(\xa5\xaf\xf6$\xf49\xd3\xf9\xbc\xb5\xf0e\x9e\xa4L\xe4\x0bL\xe3\x8bH\xe2s\xa6\xf0M\xae{\xda\xe4={\xea\x9e\x7f\xc0\xf4\x93\xd9\xb6\xf9\x96\xac\xf3\x82(\xa8\x84ME\x0f\xca\"S\xcb\xb9\x9a\xa8L=fF\xeak\xb6j+\x96\x8b\xa9\x19\xc4\x0d\xdfl\xdf\x8a(\xd9\xe2\x8a\xb9\x96<}\x84\xf7d\xaaL\xc0\x1d!y\xdb/\xf7/\xcdsS\x86\xb7|\x13].L\xdfb\x9e\x01\xb3\\3\xcf\xf2A\xc4uioJ\xc7A{p\x90(W\x95\xe5\"\x8aR\xeda\xe0\xc8\xee\xb1!\xd5\xe5\x9a\x08\xf5\xac \xe4&\xa75)\xb2\xfe\x0b\xfc\x01kR\x89T&S\x02p\xdd\xae\x15R\xf35\xa6\xa8\"u\x95\x13\x13}m\xc2\xb6\x0e\xd2s\xbc\xc5\x85\xf4\x1cH\xcf\xf9\x1d\xa4\xe7\x8c\xc8\xce\xe9i\xd3\x93sz?\xbd&\x94\xf3\xda\x98\x8a\xa3\xd6\x9f\xb9\xcfY\xa2\"\x82J\x11\x96\x93\x95d\x15(\x132G\xbc\xa7\xae\x99\xde\xfa\xdf1\xccv\x90(\x04\x89B\x90($\x04\x12\x85 Q\xa8\x15H\x14\xaa!Q\xc8,\x90(\xa4\x04\x12\x85 Q\x08\x12\x85\x02\xbd$H\x14j\x04\x12\x85t\x81D!H\x142\x08$\n\x19\x9f\x81D!H\x14\xb2\x08$\nA\xa2\x10$\nA\xa2\x90&)\x926 Q\x88\x0b$\n\xfd\x19\x12\x85Z\x82\x8e\xa6\xa6\xb3\x91T\xa4\x0c\x11\xdc7\x1f\x1c<\xf9\xe2\x9c&\x9bA\xf0\xa2le\xe1\xdb\xbb=\x16d\x0f\xdc\xfbC\x81\xc7_pL\xd6A\xc4\xd7\xf6\xeb\x12\x14<\xe2/\n\xb6\xb1\xa2\xe7+\xe8Q\x82\xfc\x82\x1e\xde\xfc\xb1\x87D\xb6\xcc\xf6\xb6\xf36\x14\xf7\xc6)j\xd8\x9b-\xd9\xc8E\xfb\xd7J%\x9f\xba\xb3\x19\x00M\x8d\xe6\x17z#X)#\x1d\xa3\x9a\xd2\x02\xfa\x06n\xde\x1f\xcf\x19\x91\x05\xb3\xf1\xe3\xbc!\xabn\xd1\x9d\xa7z\xbbm\x80|\xf5@\xde\xba\xa0\x00\x182\xa0J(0\x94%d\x14\x18\xe9\xd07\x88G9\xb6gi\x01I/$\x99\x1a\x94\x0c\x87%\x13\x01\x93\xe3\xa0I\x87:f\xd0`pr2<\x99\x1a\xa0\x8c\x84(\x13\x83\x94q0e$P\xe9\xea\xc3\x0d\x84\x19\nU&\x06+\x83\xe0\xca\x84\x80\xe5T\xc8r\x14h\x99\x08\xb6\x1c\x03\\:\x94qH\xd3\x0f]\xee\x05\xbc\xdc\x1f|\xb9\x17\x003\x0e\xc2L\x0eb\x86\xc2\x98I\x81\xccp(3\x1a\xcc\x8c\x873\xbdS\xe1\xd7\x01\x80f\x02H\xd3\x03j\x06:T\x01\xc0f\x8c\xd7\x15\x0dn\xba\x16\xc1YyE\x02\xe0\xcd\xd0\xf2%\x848c@\xce\xc40\xe78\xa0\xd3\xd5\x83\xa8\x1f\xea\x1c\x0dvZ\xb4\xb1\xaf\xf9\xe0\xceT\x80g0j\x17\x00zF\xc1\x9e\x1e\x94b\x14\xf4\xe9\xd3i\x0d\x81&\x02@\xe3\x8d\x19\x0e\x82\xfa\xea6\x02\x08\x1d \x85\xbaB\xc9\xc9\xe0\xd0`@4\x0c\x12\x0d\x05E\x03\xac\x1c\x0f\x8c\xc6@\xa3.p4\x11<\x1a \x90N\x83H}\x06\x8d\x80I\xf7\x00\x94zKg\xed\xe9\xe9\xe0\xd2\x00\xc0tua<.\x085=\x88\x9a\x1cF\xb5\x03\xa9)\xa1\xd4\x1005\x1eN\x8d\x02TG@\xaa\xb1\xa0\xaa\x13Vu\x83\\\xe10W(\xb4:\x02\\\x8d\x84W\x1d\xd5\x1d\x03\xb1ZTi\xf0e\xd8\x90\x08\x83Y\x1d]\xbeX\xba\x81\xd6\xa4P\xab\x07l\xdd\x0f\xdc\x9a\xaa/F@\xae1\xa0\xeb\xf0\xca@!\x06\x8ci\xf0\x9c\x7f\x7f\xab\xdd\xba\xaa\xa1\x83\xda\xcd\xab:\x84%v\xab\xa6\x18\x8f69\x8a7L\xe6\xee\xdf\xb9\ni\xe0J \x0d| q\xc5\x854pH\x03\xffli\xe0\xb6[\x90\xf5\x04pmv\xed\xe7\x82\x9f\x99r\xc1M\xaa\x0e-\n\xb5\xdc\xf0\xe65H\xc7\xee\xfe\x06\xe9\xd8!s\x9e\x90Q\x0c\x08H\xc7\x0e\xe1=\x98B\x05\xd1\xac\x871\x9c\x07H\xc7N\xc8t\x88\xe19D\xb1\x1c \x1d{*\xb7a\x04\xb3! \xaf!\x9e\xd5\x00\xe9\xd8S\xd8\x0c1\\\x86\xc4L\x86:\x88\xc7\x90\x90\xc5\x10\xcaa0\x84' \x1d\xbb+\x01\xac\x85P/)\x9a\xb1\x00\xe9\xd8A<\x851,\x05H\xc7\xb6=\xe6e&D\xf0\x12B\x92\x8dc8 \x90\x8e\x0d\xe9\xd8!\xcc\x03H\xc7\xe62\x85k\x00\xe9\xd8&M^v\xc1Xn\x81um\x80t\xec\xa1@:\xf6\x08\x0e\x81\x9fA\x10\xcb\x1f\x88`\x0fDs\x07\xe2\x98\x03\x90\x8e\x1d\xc7\x15\x80t\xecF\xf6\xc1\x0fH\xd1\xe7\"\xb8\x01\xe1\xcc\x00H\xc7F\x91\x05\xd9K:\xb6\x02eE\"\xec\xa1\x82\x9c\x0f\x7f\xe9\xe1\xf6\xbf\x1e\n\xbcR\xfbA\xfc\xc1u\x9d\xda\x7f\x0f\xb3\xb8\xd5\xf7,\x89\xdc\x0dF\x1c\x9a\xcb\x9d \x85\xbbS$\xf9\xe0\x9d\xcd\xe2\xee5\x98\x0d\xde\x1bE\xd5\xa8\x9d(\x9d7@\x15\x12\xe1I\x8e\xcf\x85\xa1sc\xb097\x067\n\x81\xe3\x9f\xb0(\xf4\xe2o \xd0\xb7\x91\xd8\x9b\x9d\xd0\x17\x84\xbcM\xc2\xddF\xa1n\x08[I\xc4u\x18\xe66\x06qs\xc5\xc1\x83\xf0\xb6\xc4h[\x10\xd6\x96\x10i\xf3\xe2l\x89P\xb6)\x18[4\xc2\x96\x00_K\x8c\xaey\xb0\xb5\xe4\xc8\xda~p\xb5\xe4\xa8Z8\xa66\x0eQs\x18\xdd\x87\xa7%C\xd3\xc2\xb04\x833o\x9f_\x13\xe3h>\x14m\"\x86\xe6@\xd0\xbc\xee\x89\x17=\x0b\xf3_\xd2\"g>\xdc\xcc_\xa6q\x98\x99\x9a\xd9\x0d\n}\x88YB\xbcl\x02Zf\xc6\xb8]XYZ\xa4\xcc\x8d\x93\xa5@\xc9\x82`\x1e\x0fB\x16\x8c\x8f\xd9C\xd9\xf1\xd8\x98]\x971l\x94\x04\x15\x8b1V(\"\xe6\xb7I0\x1a6\x02\x0b3\x87\xd8\x12\xe1`A(\x98\x1f\x03\x0bA\xc0\x9cV\x8cE\xbfB\xb1/\x1b\xf2\x95\x00\xf7\x8a@\xbd\xc6c^\x0ed)\x14\xefJ\x8cv9Jd\xec\xa9\xa3p.\x85i\x19\xf4YP\xae\xc4\x18\x97\x1d\xe1\x1a\x8bo\xf1\x88\x80\xa9\xe0ft+-\xb6e\xdb\xf8yq-[\xe0\xdd\x86i\xa5E\xb4\xc6\xe3Y\x16\xecj\x14r\xe5E\xa9\xe20\xaa`\x84*\x12\x9f\x8aA\xa7\xac\xd8\x94\xbd4\xa1\x18A\x18.\x15\x89JE`R\xc6\xaa\xa5\xc5\xa3l\x83b\x02\x16e\x8cSX\x91\xa8q8\x94\x0bsJ\x8f8M\xefI\xc1hS(\xd64\\\"\x9bk\xce\xbbhC\xf8!\xa7\x8esJ\x9d\xfb\xd0n\xda\xeb\xc9\x1b\xf3'\xbb\xc5\xea)\x81\xe4\x99\xa6\xc3\xf5!\xcft2\xea\x9f\xa6\xcf\x05#\xff\xe1\xd8?\xe4\x99\n\x19W\x90\x1e\xa6n+P\x03\x83\x8b\xc7\xd4\xc2`\xe71L.\xa0\x15\xf9\x1e\x94|\x806\x9bK.A\xd2\xcfV\xf2}\xe4\xf6\x16\xe4\xa6\xbe\xa0\xe4\xd3\x8e\x14Y\xe0]\xcb\xef\xc8M\xfdA\xbeqF2\x92_1\x97\xa0\xdeUr\xb9e*Q%\x7fP\xaa\xb9_\x84\x05\x97\xa0\xd1$\x0bfL\xbc5|E>vg\xd3n;\xb6\xbc\x90\x16\x88\xc2I\xbdd\x0d \x90s\x137\xa6U\xb6\x1e\x0c@\x04T \xa0\x02\xe9\x12W\\\xa0\x02\x01\x15\xe8nR\x81\xda\x85\xa1K\x00b\xcb,\xa1\xb5\xf0\xf1\xbd\xfc\x1f\xc3\x12\xd3(\x04\"\x10\x17 \x02\x01\x11\xa8\x15 \x02\x01\x11\xa8\x15 \x02\xd5@\x042\x0b\x10\x81\x94\x00\x11\x08\x88@@\x04\n\xf4\x92\x80\x08\xd4\x08\x10\x81t\x01\"\x10\x10\x81\x0c\x02D \xe33@\x04\x02\"\x90E\x80\x08\x04D \x02\x01\x11H\x93\x14\xa4\x0c \x02q\x01\"\x10\x10\x81\xfelD\xa0}\x90R\xd8_Z\xe9`\xed#&\x02\x85|t<\xf5\x8b\xf3\xf4.\xc9\xedD\x12\x95\xb5\x03\xdb\xa8+J\xd4\xf7\x15k\x85\xfdS\"?\x98R\x01o\x9d\xe2%9\x13l\x96\x03\xf1\xbbE\xd9'\xb6\xder5\x9c\x14\xb8en\xd9\xa6\xa45\"\x1cO\xe1 \x8c\xe1\xd5\xba\xac\xf1\xd8;<\x02\xe6\x15i\x02k\xac\x9f\x7f\x9e\xd7\x9f\xff\xa3\xe5\x04+$O\x83\x8dl$\x08\xddDY\xb9+\xea\x0b\xae\xcc\xe6u^c\x8a(\xa9\xef\xa3\xbc\xa6\n\xa0\xa4hW\x88\x11?\x17\x98\xcdun\xe8j\xfe9D\x14E\xe3\"\x95\x1d\x17?/\xd0\xf2\xec\xf4\xa8\xe9\xcc\xca\x7f\xa6\xe8zE*S'\xb2\xe0\xdfYY \x1d\x9c+\xa0\xd8N\xca\x1bg;\x17\x0e\x07\xe9\x961\x9aC\xbd\xf1\xa1\xdc\xb4\xe5vF\x95*\xb2%\x03\x14Q\xa0\x88Z\x04(\xa2@\x11\x05\x8a(PD5IA\xd7\x03\x8a(\x17\xa0\x88\x02E\xf4\xcfF\x11\xd5\n\xd2\x10{\x0e.\xc9\xad\xad<=`O2e\xb0\\Z\x04\x91S\xb0*t\x82\xc1AC\xab\xe1!\xb2e/\x96\xc4)\x03\x8a\x14e\xa7\xca\x1c\xa0\xf7\x05\x07\xda\xf9\x1e\xba\\,(\xa9\xd9\xb6\xb4[\\\xa4\x85\xf8)\xe9P\x9c\x98\xad>I\x0e\xac\x92\xd6X\x0b\xbc\xa6^kY\x02&\x06#\x8a\xf2\xd9\xec\xd8\x0bV\xc8\xcapS\x16\xbb\x0d\xa7\xb6\xc9\xbf\xf1Y(\xc3\x05\xab\x8f\x88\x16\xadH\xa1\x0c\xbf+\x9a\x00]\xcf-?\xe1\xda\xd6\x84\xd2\xd6\x84\"\xa4\xb5\xe3`\xef%\x89\xb4gW\xfd\x9e\x8dk9\x15P3\xef:\xdf\xe4\xa1\xd6\xe5\xcf*|\xd9\xc6j\x12\xc1[\xbd\x07\x0b\x1f\x89\xf6\xef3\xde\x8aP\x8d\xfe\xa7\x93\x05Z\x93E-\xa3\x82y-\x96 \xe5L\xf3\xb8\xb3\x18 \xe2#\xcc\xce\xb3[\xc1\x93\xc0\xdb\xedg\xb4\xa2\xce\xcdj\xdfw\xd9R{\x83Y\x94\xf7\xd0\x92O4\x88\xfd#/\xe6y\x86k\xd2re\x84\x05\xf9\x83\xb2#\xe9\xea\xf2\"[\xef\xe6=W\x19\x8b\xaf4\x10`\xaf\xc58\xa0\xacE\xa6\xd9\x92\xa6\xd1\x12{\x93\xcb\xc7\x93>I\xb3W\x05\xbe\xbb\xa8\x08\x95\xc8?\x1f^\xedxdC\xee@\x8e\xa6|Y\x94U/\xae\xafFc\xf7\x13\xc22S\x1bvV\x96k\x82\x0b\xd3\xe4\xd3\xf9e\xbf<\x7fz\xf8\x8b\"\x1d\xff\xea\xa0\xf9\x1b\x99\x18\xbc\xca9a\xd3\x1a\xa7\xdd\xce-\xdc~\xe6\xb6\xad\xc2I\xfb\xf7\x94\xfd~\x1f\x9c\xfd(\x8eE\xd8\x11\x8f\xca\x8c\x86\xebg\x15\x81\x86{~\xfd\x080\x1c9 \xbc\xc2F\xe2\x8a\x0b\xbcB\xe0\x15~n^\xe1\xa0\x17\xd9I\x80\x0d\xafPO\x1b\x91\x03\xac\xbf\x10#m1\xe1\xee\xc4\x00\xd6\x93\xf3\xad\x98\x8f\xf0\x9a\x96\xcasaK\x9b\x98\x9bd\x94SYlQ\x95\x9bv\xfe\x1a\xe8sLg\xc0T\xec\xfe\x06L\xc5\x90\xb9T\x080\x15\x81\xa9h\x16`*r\x01\xa6\xe2P\x80\xa9\x08LE\x9b\x00S\x11\x98\x8a\\\x80\xa9\x08LE`*\x02SQ\x080\x15\x81\xa9\x08LE`*\xda\x04\x98\x8a\xc0T\x04\xa6\"0\x155I\xc1\x1a\x03\xa6\"\x17`*\x02S\xf1\xcf\xcbTTl\x14kI\xba'\xe5\xa5,\x82\x053\xdf#\x01G;\x8b\xceA\xbe\xf9\xef\xfe\x19\x9bG\xedk\xb6\xe355\xcd\x9c~C\xa8~\xb0\xa6R\x17|\xae\xa6\xf6E\xf9\xd0\x9d\xa5\xe7h5\xbf\x1b\x00!\x9c\xa6 \xa7i\xc2i\x9ap\x9a&\x9c\xa6 \xa7i\x1a\x04N\xd3\x84\xd34\xe14M`\xbd\x1at\x01\xeb\xb5\x91?.\xeb\xd5u\x9a\xa6\xb6\xedJq\x92\xa6\xbeo\x84C4\xb9\x0055b\xef\x07\xd4T\xa0\xa6J\x01j*PS\x81\x9a\n\xd4T\xa0\xa6\x025\x15\xa8\xa9\xa1^\x12PS\x1b\x01j\xaa.@M\x05j\xaaA\x80\x9aj|\x06\xa8\xa9@M\xb5\x08PS\x81\x9a\n\xd4T\xa0\xa6j\x92\x82&\x08\xd4T.@M\x05j\xea\x9f\x97\x9a\n\x87h\xc6\x9dP\x08\x87h\xee\xd1\xb8\xfe\xe3\x1f\xe1\x10\xcd\x14V\x84C4\xe1\x10\xcdP\x0e\xff\xe1/\xdb\xe6`\xcd\x0b\xc5>\xa6\xbf\x1e\xee\nN\"\xbd\"s~\xe4\xa6\x83\xea\xafu\xa5\x8f\xcdK\xaf\xb2\xcb!\xcf\xbf\xd5\x89N^\x1f\x0d\xa8\xb7\x8d\x9a\xfe!\x92Z8V\xad\xe2\x9c\xe9\xabJkL\x02\xe8\x96E>qg3\x00\x9a\xba$eaX1\x02\x0f\xe5L\xd2|\xd69\xe5\xc3Uk\xb7\xfe1\xa9M\xb9{:\x80E\x08,B`\x11\x02\x8b0\x9eE\xd8\x9d\xb7\x87\x14B\xf9\xdf\xb5\x8fC\xd8[\x8b\x80;\xc8\x05\xb8\x83\xc0\x1dl\x05\xb8\x83\xc0\x1dl\x05\xb8\x835p\x07\xcd\x02\xdcA%\xc0\x1d\x04\xee p\x07\x03\xbd$\xe0\x0e6\x02\xdcA]\x80;\x08\xdcA\x83\x00w\xd0\xf8\x0cp\x07\x81;h\x11\xe0\x0e\x02w\x10\xb8\x83\xc0\x1d\xd4$\x05\x8f\x0b\xb8\x83\\\x80;\x08\xdc\xc1?3wpH\x0c\xb1\x95JQ\x05B\xf8\x01\xf1\x05\xec\xc3H\x06\x00\xc9\x1a\xd8\xb0\xe2\xe2Y\xb9^\x13\xbe\x95}+\x1f\xc9\xe8\x95\xf6\xfb&/N\xf8w\xd0#\xf9\xd7\xdf\x98\x91\xd3\xfe\xcdB\xcc\x11\xcfEss\xc4\xc1*^z\x8e\xd4\xdeg\xe34\n'\xb2rd)\xe4C@\xcc\x112\x9a\x98\xb3\xed\x9e\x1f |\x1c\xe0\xe3\x00\x1f\x07\xf886{v\xa7\xc50>\x8e\x9c\xb1SPr\xe0l/\xe0\xe7\x98\x7f\x07~\x8e&\xc0\xcf\x01~N+\xc0\xcf\xa9\x81\x9fc\x16\xe0\xe7(\x01~\x0e\xf0s\x80\x9f\x13\xe8%\x01?\xa7\x11\xe0\xe7\xe8\x02\xfc\x1c\xe0\xe7\x18\x04\xf89\xc6g\x80\x9f\x03\xfc\x1c\x8b\x00?\x07\xf89\xc0\xcf\x01~\x8e&)\xb8\x12\xc0\xcf\xe1\x02\xfc\x1c\xe0\xe7\xfc\xe9\xf99&\x9a\x88\xadp\x8a8\xe0`\x0b\xc4\x17\xefO\xc6\xceQF\xfb\xd5\xc1\xbb\xe9\xe3\x9b\x9c`\x91\x136\xd1\xf1\xfb)\xe7\xc3\xbb(\xf9\x95\xb7F\xceL_\x99|\xe6\xceRf\xda:EA\x95\x9e\xc8VsA%\xb7[\xff\x88\xa0Z\xbb^\x8aO\xa0\xfd@\xca\xb6*\xcb\xc5\x1e\xca\xb3!\xd5\xe5\x9a\x08\xf5ld\x91\x9b\x9c\xd6\xbd[\x9e\x91\xfa\xbe\x95Q\"\x95I>\x00\xae\xe5\"\xc3j%4_c\xda\\}:\xf4_\xad\x8d\x84\xbc\xa8,ps\xbc\xc5\x05n\x0eps>77g\xd0\x8b\x8cW\xe45\xd4\x1c\xfd.e9\xb6\x04\xc5\xcfr\xa9\xef\x82_\x1b,\xe6\xd6~-\xc5T\x84\xd7\xb4T\xe7\xfa\xb1eLLK2N\xa0\x8c\xb5\xa8\xcaM\x7f\xea\xeak\xc3\x83\x96\x1b\xcek\xc0\xfc\xe9\xfe\x06\xcc\x9f\x90IU\x080\x7f\x80\xf9c\x16`\xfep\x01\xe6\xcfP\x80\xf9\x03\xcc\x1f\x9b\x00\xf3\x07\x98?\\\x80\xf9\x03\xcc\x1f`\xfe\x00\xf3G\x080\x7f\x80\xf9\x03\xcc\x1f`\xfe\xd8\x04\x98?\xc0\xfc\x01\xe6\x0f0\x7f4I\xc1\xc2\x00\xe6\x0f\x17`\xfe\x00\xf3\xe7\xcf\xcb\xfcQ\x14\x14kI\xba\xf4\x9e\x94E\xb0\x80\xe7{$\xdf\xf03\x03\xb6\xa1\xcc\x1b-\xb2 \xd0\xd13\xf1z\xc3\xc0a>\xb7\x04\xf0{f\xe2\xf3\xd1\x8cpd_\x9e\xaa\xa2\x81\xfbl\xc0\x0b\x1ds\xd6\xeb\x9a\x10\x9b\x81\xaa#?)\x1f\xb8\xb3<\x1dUK\x1bD8\xbc\xa8L\x88\xf9\xba2\xedm\x01Y\xcbJ\xa0\xc5\x1a/\xb9\x8b\x96/\x90lK\xc1\x92\x01\x8a\x8e\x12\xa0\xe8\x0c$\xae\xb8@\xd1\x01\x8a\xce]\xa6\xe8\xc8\x15!\x9c\x9f#\x189\xfd J\xacWr\x12\xedW\xd5\xc1\xd3\xb9\x0fD\x1d \xeap\x01\xa2\x0e\x10u\x80\xa8\x03D\x1d \xea\x00Q\x07\x01Q\x07\x88:\xad\x00Q\xa7\x11 \xea\x00Q\x07\x88:(\x9ak\x02D\x9d\x8e\xc4\x19\x0f\x88:\x1d\x01\xa2\x0e\x02\xa2\x0e\x10u\x80\xa8\xd3\x8a}+\nD\x9d\xce\xdf\x81\xa8\x03D\x1d!@\xd4\xa9\x81\xa8cT D\x9d\xdf\xa0 \xbf{\xa2NY\x14\xe2\x14\x1ez\xf8K\xfb\x1f\xbf6\x0c\x1e\x07\x13G\xbbN\xe4\xa8y\xf3H\xbe\xd7\x1e\x88#/\x9fR\n\x07'\xbb`\xd4~\xb7QH\x8a\xb9\xf1\xa8\x9c\xe1\x87\xe4Sw\x96\x84\xa3\xea}7\xe0?\x8e\xf0[\x03_\x02\xe7\x96qL\xf1\xac\xf2a\xd4\xf0&\x85-B\x1b\x106#\xc5nc\xdfP=@\x1f\xce_\x9d\x1f_||w\xf2\xee\xe4\xfc\xe4\xd5\xdfN\xfey\xfc\xe6\xe2\xe3\xbb\x0f\xa7\xc7G'oO\x8e\xdfx\xdfd\xefy\x1f:?\xfb\xc7\xfb\xd3\xe3w\xde\xe7\x82\x1e:\xfa\xdb\xfb\x0f\xd6\x82)\xf0|d\xbdB\xe2tL>\xf0vR\x8c\x03N\x7fS\xad\xc5\x99\x16\x1c\x15\x92\xcd(\x10\x18{\x0b\xc9\x1eB\x1d\xeb\x98\xa8\xf2}\xc4*s\x1fIk\xdeG\xec\xff\xa3\xb2B\x9dZ:\xb6\xff\xfe\xe6~\x89\xde\xc8\x8d\x15\xaf\xa1_\x13\xd3\xc3\x06\xb6\xaa=\xf3j~\xdaQ\xde\x93+6\xdf\xf0\x90\xfb\x96\xf0\x18\xf8\n\x17s\xba\xc2\x97\xc6\x10iO\xb1\xacd_\xb7v\x17\xa2$_(\x9d\x88\xd6d\xab@\xa7\xac\xdc\x155\xa9\xb6\xb8\xaao\x05\xb30\xe0\x93\xa6\xefe%\xf3F\xea\xfe\xc7\x0e\xd0\xfb-)\xb4 \xb6\xb2\xdb\xaa\"x\xceq\x1cJ\x8a9w\xfd$IP\xdd\x06\x18P4\xd1\x01\xfa\x85\xe3\xbc\xcal]R\"\xf4f\xb8@E\x89\xd6e\xb1$\x15s\xfex\xd0^}\x99\xd3D\xf8\x87\xad\xdfs\x16\xa8\xac\xe6\x84M4\x9e\xa9\xeczE$*A\xf41\xc1\xdf&\xbc\x14\xbbB\xfe\xc7\xfef\xb5\xf7go\x8e\xcf.\xde\xbd\x7fw\x1c0\xe8\xdb\x17>\xbe\xe3\xff\x1b\xf0\xa4\xfb\xb9f\x16\x8a*G\xe8\xe4c\xab\xdeK\xf43\xa9\xca\x07b\xf3\xcc\xdcgi~\xab\"\xd5\xa2\xae\xfe\xd73\xcc\xcb\xe6\nK\xd6\xd9fl\x0e\\\xe7W\xbce\xd9&\xa0\xb8\x15J\xef\xcb\xed\xc2\x06\xdf\xa2y\xce\x91\x14N\x8f\xe2\xb3\x01{\xc0\x85\xd25\x1c\xaa[tM*\xc2zo\xed\x1c#\x9d&iK\x88+\xbdx\xe4\x06g5'\xaai\xa50}\xca\xf8%}B\xf1\xad\xe5\xbd\xb9'h\x0d\xb7z\x17(\xc0\xc3\xe0\xcf\x08\xf7\xdc\x15;\x0d\x18W(\xa2\x1b\"\xf9U\xfb\x9c+\xcd[^\xcb\xb8\x08\x87+\x9d\xfa\xf8<\xd5\xf1~\xec\x0d\xdf\xee\x8f\x12TZ\xb5]\xdb\\\xf6jY:\x88\xf2\x92/V\xe5\xd6\xdaP.\x07T\x88\xd5\x0d\x15\x12P\x1f\x1bw\xb2\x15udi[hm\xcfF\xefs\x07F\x0cc\x89 \xb2v\xb4w=9\xde('^9\xd8O\x1c\xc7W&\xe6\x01\x8a\xba\xc2W\x96 J\xf2\x0b& \xc6~;\x94[\xcc\xf6\xab\xaaH\xf2\x93j\xf2\xca)\xc2\xcb\x8a\x909\xdam\xcb\x02\xcdw<\x12\xe6\xa2v4\xfe\x81\xf1 \xcf\x10\x0d\xaf\x11\x1fu\xc6Mv+\xfe\xd1\x11\xfe\xbdf\x19w}2d\xda8Q\n\xe6r+\xd9\xb8\xd0X\xeb\x17l\x83\xdaF[ye\xb1e\xfaT+\x9c\xf1\xc7\xb6\xb8\xf2\xf8\xd2\xe1\\b<\xc87h\xdb\xdc\xd7\xb5\xc5\xcb\xbc\xe0{f\xc3\xaeS\x1d\xb3\xaa\x1e\xb1\x1d\x198)\xa5\xa1 7\xf5\xc5%\xb1,O\xde\xd6\xf6\xf2+l7\x9a*Q\xdfWw\x98\xb2\x7fJ\xa2\x11\xa6\xd2\x11=\xc5Kr&\x8e\x94=\x10\xbf[\x94 \xe66S\xc3\xd42\xd3\x11\xb4)i\x8d\x08\xa7\xefp\xce\x8f\xe1\xd5\xba\xac\xb1\x85g\x1bl\x00\x7fv\x84uF\xe1\x9f\xe7\xf5\xe7\xff\x10\xb9%\xacK)\xe2\x98\xc6R\xb2qnu\x13\xf1\xb5\xe7\x82+\xb3\xcd\xaa\xd7\x98M\xbc\xf5}\x94\xd7T\xf1\xe1(\xda\x15b`\xcd\xc5\x9a{\x9d\x1b\xba\x9a\x7f\xc0\x8a\xa2h7\xd3\x96\x9d\x88r^\xa0\xe5\xd9\xe9Q\xcb\xaf\x97\xe1Z\xca\xf6\x00\xc6\x0d\x91\x85n\x99\x95\x95\xd0\xc1\xa9\xa9\xea\xc8a\x15\xfce;\x1d\xbe\x91\xd1-c4\x87z\xe3C\xb9i\xcb\xed\x041+\xb2%||\xbf\xc6U\xd3H\x1eD\xa4k\x16\xde3m\x98H\x1f\x8f\x85\x1b\xc3!\xe5 R\x9e \xe5\xc9\x95\xf2d\xbe1|\x18\x84\xef_\x19~\x16|e\xb8E!\\\x17.\x04r\x91 \x17\xa9\x15\xc8E\x82\\\xa4V \x17\xa9\x86\\$\xb3@.\x92\x12\xc8E\x82\\$\xc8E\n\xf4\x92 \x17\xa9\x11\xc8E\xd2\x05r\x91 \x17\xc9 \x90\x8bd|\x06r\x91 \x17\xc9\"\x90\x8b\x04\xb9H\x90\x8b\x04\xb9H\x9a\xa4\xc8\x0b\x81\\$.\x90\x8b\xf4\xa7\xc8E\x1a\xa6\x8b\xf4s\x91Z*\xd9o\x92\x05\xd4\x92i\x0e.\xc9\xad\xadT=0M\xb2S\xb0\x9c\xd4+R\xef\xaaB0\x19tP\xff\xa0\xa1\xb2\xf0\xe0\xd4\xb2\x17\xc5\xe10\xbd\xa4\x829\xe8)\x07\xe8}\xc1\xc1m\xbe{-\x17\x0bJj\xb6!\xec\x16\x17i\xc1uJ:T\xfb\xbe\xcb\x96\xda\x1b\xcc\xa2\xbc\x87\x96|\xa2A\xec\x1fy1\xcf3\\\x93\x96\x9f\",\xc8\x1f\x94\x1dIW'\x0f\x01\xed\x9a\x13\x8b\xaf4\xe0[\xaf\xc58\x94\xab\xc5\x84\xd9b\xa2Q\x01{\x93\xcb\xc7\x13\xdak\xad^\x15\xb8__\x11*1w>\xbc\xda\xf1\xc8\x86\xdc\x81\x1cM\xf9\xb2(\xfbY\x16j4v?!,3\xb5a\x87gW\x9bO\xb5\xb6\xa5K\x8alI\xce\x0f:\xbczt\xc8\xd7#\xf9\xa0)\x17\xf2\x88?y\xca\x9f\xea\xa4>\xb6\x0b\x99j\x92|\x96I\xe2\x919\xc3Q\xd3tO\xd5\xf5\x8e\xe66\xeaV\xd1\xa5\x97\x02\xcb\x8d\xa2\x9f\x88;4\xca\xa6\x9c\xef\xd6\x86\x08\xb1\xb5P\xc8\xcb/\x90X\xd5\x85\xb0\xb5\x83\x82\xe0\xa2\xc0; \xf0\xde\xe0|Ht{P\xd0\x8e\xa5\x14\x0dX\x01o\x92\xb1F\x1d q\"\x8a\xd1\xf9\xd1]\x0eA\xc1\xd1\xba]\x9f\xcdS\x05\xb3y:\xc3\xa0\xa5\xf0\xb4\xa5\x01\x0eO\xf77\xe0\xf0\xf8zg+\xc0\xe1\x01\x0e\x8fY\x80\xc3\xc3\x058\x0c\x8a\x1f\x03\xc4\xbb\x01\xf7Qp;\xff\x84E\xa1\x17lO\x00\xb5\x8f\x04\xda\xad\xf0d\x18\xcc> d\x1f\x05\xb1#lM/\xa8\xc3\x00\xf61\xf0\xba\x0b\xf4\n\x02\xd7\x13C\xebA\xc0zBX\xdd\x0b\xaa'\x82\xd4\xa7\x00\xea\xd1pz\x020=1\x94\xee\x01\xd2\x93\xc3\xe8\xfb\x01\xd1\x93C\xe8\xe1\x00\xfa8\xf8\xdcat\x1fx\x9e\x0c:\x0f\x03\xce\x0d;w\xfb\xfc\x9a\x184\xf7A\xe6\x13\x01s\x07\\\xeeuO\xbcPy\x98\xff\x92\x16&\xf7\x81\xe4\xfe2\x8d\x03\xc8\x1dY$>x\x01\x1a7\x13Z\\\xc0xZX\xdc\x0d\x8a\xa7\x80\xc4\x830]\x0f\x1c\x1e\x0c\x86\xdbq\xabx \xdc\xae\xcb\x18#N\x02\x81\xc7\x18+\x14\xfe\xf6\xdb$\x18\xfa\x1e\x01|\x9b\xe3\xe9\x89@\xef \xc8\xdb\x0fx\x87\xc0\xddN+\xc6B\xdd\xa1@\xb7\x0d\xe6N\x00rG@\xdc\xe3\x01n\x07\x8c\x1c\nn'\x86\xb6\x1d%2\xf6\xd4Q\xa0\xb6\x8aE\x1a\xf4Y \xed\xc4\x80\xb6\x1d\xce\x1e\x0bf\xf3\x88\x80\xa9\xe0f(;-\x90m\xdb\xf8yAl\x1b\xcaf\x03\xb0\xd3\xc2\xd7\xe3\xc1k\x0bP=\n\xa6\xf6B\xd2q\x80t0\x1c\x1d F\xc7@\xd1V \xda^\x9aP@0\x0c\x84\x8e\x84\xa0#\x00hc\xd5\xd2\x82\xcf\xb6A1\x01x6\xc6)\xac\xb0\xf38\xd0\xd9\x050\xa7\x87\x97\xa7\xf7\xa4`h9\x14X\x1e.\x91\x86Lq\x84)-\xb3\x9c;\xff|&\x11s\x94H\xf3\xb4\x1e\x8f\xbc\xad\xcar\x11\x95\x83\xe7\xd9\x87\xca\x92mHu\xb9&B=\x9b\xff\xc8MNkRd\xfd\x17\xf8\x03\x17+\xc2v\xdd\xd6\x9cn\xf13\xc2\xb5\xec8\xacfB\xf35\xa6\xa8\"u\x95\x13S\xa8\xa6\x1e\x8f$T\xe4*\xa7yY\\\x088l\xe2\x8e\xdd\x9f\xed,\x1aK|\xb3\xc5\xf4\xd4\xe1\xd6T\x0b\xe9\x94\xa6mcS\\\x9b%Q\xfa\xe2\xcaVa}M.\xfa\xcb\xfc\x8a\x14MY\x06\xef\xfbC\x01\xefX\x01\x98G\xc2\xb4\x9dI=\xdf\x8b\xef\xe4l\xc7\x9cU<\xe2\xc2\xa6\x9fZ\xe0\xba\xa2\x14\x06]\xd7\xab|M\xd0%![6M)e\xefxs\x9a\xc6>\xdf\xf6\xe3\x0diB\xe2\x88\x96\x1b\x1e/\xa7\xa4\xa0;\x8a\xf0zYVy\xbd\xdaP\xb4\xc1\xb7([\x95%\xf3\xa2L\xc9\xf5l\xe2\xacm\x81ri\xb7\xbc@\x19\xa98T\x93\x95\xc5\\\xc6\xa6\xc9\xc1\xf2\x00\xadp\xc5\xc3i\x97\xf4\xbe\x18\xdb\x0f68[\xe5\x85\xc9\xe1\xebG\x0d\x8d\xab\x08o\x1eJP\x86)\xa1\xf7;\xd6\x15\x06\xe9[\x97\x96\xbc\x13\xdaK\xcf<\x8e\xbc\xd8\xf1\xc0\xa6\xe9\x933\x826e\x91\xd7\x02]Y\xdf\n\xed\x98S\"\x08\xeb%\xd2\xa5\xed5\xf2\x92\x18\xcf\xc2\xe5\xf6\xec\xfc=.\xcd;I\x96\xb7#\xc9\x1b\xbd&\x94G}\xb4A\xcb\x1b\xee>\x0f\x92\n\xec\x9d-\xcdb\xd62\xbb\xef\xd2\xb2\x8b\xaa\x1cD\x7f\x9c\xd3\x1e\xa4\x98C\x8a9\xa4\x98\x0b\x81\x14sH1oe\x0c\x06nU\x06)\xe6CI\x84\x87OC\xc4G`\xe2IP\xf1\xe4\xb8\xb8\x17\x19\xdf\x036\xbe/t|\x0f\xf8x\x0cB>\x16#w\xce\xe1>\x94\x191\x87\x14so\xc9\xc6!\xe8FU\x90b>\x06K\xf7\xa1\xe9i\xf0\xf4@\x90\xd8\x8b\xa9G\xa0\xea\xdeT\xdfHd\x1dR\xcc!\xc5<\x04s\xf7Z5\x16w\x0fG\xde!\xc5\xbc'\x89qxH1\xd7e,*oT\x06)\xe6\x11\x18\xfd\x14\x94\xde\xa8\x0eR\xcc\x8d/\x04\xe1\xfa\x90b\x9e\x0e\xe5\x87\x14\xf3\xc9\x1c\x804}.\x98\x07\x10\xce\x04\x08K1or\x0d5-\x9d}d\x877 \x02\xfcf\x8a@^\xbc\xec\xc7\xc0\xdbd\xca\xba\xday\x92d\xe3\x12&\x15\xd2\x1a\x973\xa9e\xca\x1f)\x0d\x96k\xbe[,\xd7\xcc\x98\xc0\x02\xc1n\xf4\xb9\xb2-\xbb\x9f\x92\x8f\xdc\xdd\x8c\xcb\x9em\xef\x06\xbc\xe5\"+\xb4\x1c\x97^\xa3Y\x01\x7f\xe4/\x10\n(\x14\ne\x7f\x08 \x88?\xa10j\x85\x904|\x10!A\xac\x10!{\xacF4ODHH\xe0\x0b\x8d\xe2\x8cXU\xa9\x92F2G\x84\xd4\xa3\xf8#vu\xa5\x9bE\"$\x8aKb\xd5\xd2\xe1\x98\x041J\x84\x8c\xe1\x958\xec\x87\xebPv\x89\x90q\x1c\x13\xab\xba%\xa9\xa9\x81i\xa2\xa47\x85\xba\xe3\xd1\x93g\xa0\xda\x83\xfc\xa3\xf01\x1b:\x90\xd0\x08\x16\x80S\x999\x14\xec\x88\x8c\xa4f\x03 ?#\x00\x8d`\x05\xb8+\xa0\xb2\xe4C\x98\x01(\x15;\x00\x8dd\x088\x152\xe3\x06\xb3\x04\xd0t\xa6\x00\x8af\x0b8U\xb5\x99\xf4\xe1\x8c\x01\x94\x9a5\x80\"\x99\x03(\x96=\xe0\xee\xd9\x0d\xb3 \x94A\x80R\xb3\x08P\x18\x93\x00\xa5d\x13\xa0\xc9\x8c\x024\x8eU\x80R1\x0b\xd0(v\x81{8`J\xe6~\x86\x01\xda\x0f\xcb\x00\xed\x91i\x80\xf6\xc36@\x91\x8c\x034\x8eu\xe0\x9b\x82\xc3\x98\x07(-\xfb\x00E0\x10P<\x0b\x01\x8d`\"\x04L\x99_\x07\xb0\x11P\nF\x02\xf2\xb1\x12P\xb8{\x16\xc0N@\x91^\\4K\xc1\xa9\x8d3\x18\x02\x98\n(\xa2\x94 \x19\x0b(\x8a\xb5\x80R3\x17\xd0H\xf6\x82\xbb_Q?\x83\x01\x8dg1X\xf5\xb1/\xfa\x98\x0c(\x19\x9b\x01\x85\x83\xf2(\x84\xd5\x80\xe2\x98\x0d\xc8\x07E\x8ed8\xa0\x00\xbd\x0e\xb4#\x11\xdb\x01\x8d2n8\xeb\x01\x05\xd4r\x04\xfb\x01\x8de@ \xcf\xbd\xc6\xc9\x98\x10(\x9c\x0d\x81\x02\x19\x11(\x98\x15\x81\xc2\xac\x1e\xcf\x8e@Q\x0c \xe4dI\xa0TL \x14\xcb\x96@\x13\x19\x13(\xc0\xbc\x11\xcc \xb4\x0f\xf6\x04\n)\xa3c$\xa4cR\xa0\x106\x05\x9a\xc0\xa8\xb0*d\x0f\xbaX\x15(5\xb3\x02y\xd9\x15h,\xc3\xc2\xaaM\xecQ\xdd\xdb\xf5\x00\xa6\x05r\x02\xc2\xc8\xc9\xb8@\xa3X\x17VUN6\x06\x1a\xcb\xc8\xb0js\x9c\xa7 $\x1d3\x03\x05\xb13\xd0\x08\x86\x06\x8aci\xa01L\x0d\x14\xcd\xd6@\x9e\xd56\xe1M\xec\xa1\xcc\x0d4\x86\xbd\x81b\x19\x1c\xc8]\xf11L\x0e\xab2\x8d'\x11:d\xc2\x18\x1d\xce\x01Q,\xdd\xac\x0e\x94\x96\xd9\x81|\xec\x0e\xe4fxX\xdf\x19\xcb\xfc@ \xfbn\x04\x03\x04E\xb1@\x90\xf1T\x08!f\xdc\xdc\xf0p\xc8f\xbd\xcbs\xf8{^\xaf$\xb4*\xae>\xe7D\xa4\x1e@\xaf\xa6]\x93:m\xc6U\xe9\xce\xbci\x07\x0f\x9b+A\x8d\x87\\\xd8\x0f\xb7h\x0e+7\xf0\x1d\xc4\x07\xb4\xf3\xcc\x0d\x99\xd0\xf2\xd1\xf1\xc7H\xa8\xfb\x18\xec\xe9\xbdA\x072XcC\xb2\x16\xffm\x8b\xb44\xf7A\xc8\xc4\xf7\xe6j\x08\xb4\xc5\x94\x8aH\xb2~\xe3\xbb\xf8\xdd\xa2\x8c\x1f\xab\xce\xd5\xd8\xef\x8e0\xbc\xca\x0f\x80\x9fh\x00\xff\x89\x14\xd6`Ss\xfe\xbc\xedB\x02-\xff\xcb\x16\x19\xd1M\xa4\x1f\xe5oy\xfc\x1a\xf3c\xe9\xef\xa3\xbc\xa6\n\x0f\xa0hW\x8813\x17!\xcf\xeb\xdc\xd0\xd5\xfcC\xb2s/~\xae\xc2\xe4\xcd\x82\x93\x17hyvz\xd4\x9ep \xa7I\x8a\xaeW\xa42u\"\x0b\x1c\x95\x95\x95\xd0\xc1W\x04u\x8e\x8cZ\xcf\xd8\xc2\xc5\xa3\xa8\xbae\x8c\xe6Po|(7m\xb9\x9d\xf3kE\xb6\x84\x0f\xf0\xd7\xb8j\x1a\xc9\xe7\xc1t\xcc\xc2{\xa6\xcd\x7f\xe9N\x9b\xb6\x01$N\x90\xe8\x92\xbc&\x9c\"\xd1#\xa6\xb1\x16\x12\xfb\x93\xe6q8\xbb\xa1\xfb\x1b\x9c\xdd\x102\x1b\x08\x89em\xa8P\xb7Ua(c#)[\x03\xcen\x80\xb3\x1bZI\xca\xc2\x88a`D\xb1/\xe0\xec\x86\xa9L\x8b\x11,\x8b$\x0c\x8bxv\x05\x9c\xdd0\x85M\x11\xc3\xa4\x18\xc1\xa2\x80\xb3\x1b\xe0\xec\x068\xbb!\x94\x05\x91\x94\x011\x86\xfd\x00g7\xd8\x1e\xf3\xb2\x1c\"\x18\x0e!'\x13\xc40\x1b\xe0\xec\x068\xbb!\x84\xa5\x00g7p\x99\xc2D\x80\xb3\x1bL\x9a\xbcl\x83\xb1L\x03\xeb\xda\x00g7\x0c\x05\xcen\x18\xc1\x10\xf0\xb3\x03b\x99\x01\x11\xac\x80hF@\x1c\x1b\x00\xcen\x88C\xfc\xe1\xec\x86F\xe0\xec\x06)\xb1g7\xec\xe3\xb8\x06\xe3\xd5\xe5\xdd[\xea;E\xe9\xa1f\x12gVw\xb0\xebW\xbc\xeb\xf0\xdcA\x03J\xf3\x80\xd4\xb2\x17\xb9\xe1(3\x9b|\xdc@s\xdc\xa5\xfa\xfb\xbeG\xbf\x13\x9e0\x18Q\x94\xcff\xc7^h\xa0\xbd\x14\x1d\xa3b\xb7!U\x9e\xa9\xbf\xf11\x9f\xe1\x82\xd5G\xc4f\xe4\xb5\xe8\x02`n\xc2a\xfd{\xf3\xb9\xb65\xa1\xb45\xa1\x08 \xedx\xb6\xf4%\x89\xb4gW\xfd\x9e\x8d\xeb\xbf^\x7f\x9do\xf2P\xeb\xf2g\x15\x84k\xe3\x04\x88P\xa9\xde\x83\xeb\xe6\x8a\xfd\x8e\xb6\xad\x08\x8c\xe8\x7f:Y\xa05Y\xd42\x06\x97\xd7bRV\xae+\x8f\xf2\x8a\x01\">\xc2\xec<\xbb\x15\x97Y\xe0\xed\xf63ZQg6\xb4\xef\xbbl\xd9\xbb\xe1\x9f\xf7\xd0\x92O4\xfc\x00\x83\xbc\x98\xe7\x19\xaeI{\x80\x85\xb0 \x7fPv$]\x9d\xbc(\xa1kN,\xbe\xd2\x00n\xbd\x16\xe3\xf0\xad\x16\x07f\x0b\x88F\xea\xe9M.\x1fOh\xaf\xb5zU\xe0\xbe|E\xa8\xc4\xd9\xf9\xf0j\xc7#\x1br\x07r4\xe5\xcb\xa2\xaczQt5\x1a\xbb\x9f\x10\x96\x99\xda\xb0\xb3\xb2\\\x93\x0e\xad\xaa\x99|:\xbf$;s\xe7P\x1d\xd0q\xf8K\xef<\x94_\x0f\x05yK\xfbA\xfc\xc1uN\xcf\xff\xb2\x9d\xd3\xd3\x1e\xd3\x13p@\x8f~rQ\xa3\x0fk\x00\xae<\xc3G\xd2\xcb\x02\xce\xee\x91O\xfc^\x8e\xee\xb1\x91\x1bF\xd1\xd3j'G\xc1\x1b\x9e\x0f\x89o'g'\x84q\x13\xc60\x13\xdc\x0c\x84Q\xfc\x03\xfe \x8bB/\xfb \x01\xf7`$\xf3\xc0\x8a\xd7\x86\xf1\x0e&\xb1\x0eFq\x0e\x10\xb6&R\xd4a\x8c\x831|\x03\x17\n\x18\xc46H\xcc5\x08b\x1a$\xe4\x19xY\x06\x898\x06S\x18\x06\xd1\xfc\x82\x04\xec\x82\xc4\xdc\x02\x0f\xb3 9\xaf`?\xac\x82\xe4\x9c\x82pF\xc18>\x81\xc3\xe8>6A2.A\x18\x93\xc0\x10\xca\xb0\xcf\xaf\x89Y\x04>\x0e\xc1D\x06\x81\x83?\xe0uO\xbc\xdc\x810\xff%-o\xc0\xc7\x1a\xf0\x97i\x1cc\xc0\x91/\xe3\xe3\x0b$d\x0bL\xe0\n\x98\x19>.\xa6@Z\x9e\x80\x9b%\x90\x82#\x10\x04r{\xf8\x01\xc1\xec\x00\xe7\xad\xf6\x91\xcc\x00\xbb.c\xd0< ' \xc6X\xa1|\x00\xbfM\x82\xb9\x00#\x98\x00f\x80!\x11\x0b \x88\x03\xe0g\x00\x84\xe0\xffN+\xc6b\xff\xa1\xc8\xbf\x0d\xf7O\x80\xfaG`\xfe\xe3\x11\x7f\x07\xae\x1e\x8a\xf6'\xc6\xfa\x1d%2\xf6\xd4Q(\xbf\n\x8b\x1a\xf4Y0\xfe\xc4\x08\xbf\x1d\xdf\x1f\x8b\xee\xf3\x88\x80\xa9\xe0fl?-\xb2o\xdb\xf8yQ}\x1b\xechC\xf4\xd3\xe2\xf9\xe3\xd1|\x0br?\n\xb7\xf7b\xf4q\x08}0>\x1f\x89\xce\xc7`\xf3Vd~\xfa-\xf7a\xa8|$&\x1f\x81\xc8\x1b\xab\x96\x16\x8d\xb7\x0d\x8a H\xbc1Na\xc5\xe1\xc7\xa1\xf0.\xc4==\xde>\xbd'\x05c\xed\xa1H\xfbp\x89t% \xfb@\x87Z;x\xbd\x01\xdd\x91\x08'\x1a\xd4\xe9\xf0C\xefg~ywTF\xa3g\x13+\xab\xb5!\xd5\xe5Z\xdd\x0d^.\x10\xb9\xc9iM\x8a\xac\xff\x02\x7f\xc0z\x18\xbcT&\xf3\xf2q\xed\xbeu\xdcR\x8bQ0D\xd0q\xfb\xc1\xdb}\x7f\xaex=\xedp\xfd\xa0c\xf5\x13\x177\xfa\x10}\x7f\x1c!\xfe\xe0|\xfb\xdd\x0b\xb1G\xe6\xd7\xa3\x0e\xcb7\x1fM\xe0<&?\xea\x80\xfc\xeeA\xf8\x06m!G\xe3\x8f9\x14\x9fwB{\xe9}\xc7\xe1\x8f;\x08\x9f\x1fxo\xb3g\xe7\xef\xb6\xd9\xd3\x90$\x9f*G\xbe_M\xc8\x98\xe7\x02\x19\xf3\x901\xdf\nd\xccC\xc6|+c\x10l\xab2\xc8\x98\x1fJ\"4{\x1a\x9e=\x02\xd1N\x82i'G\xb5\xbd\xb8\xf6\x1e\x90\xed}a\xdb{@\xb7c\xf0\xed\xb1\x08\xb7s\x0e\xf7a\xdc Q\xeeP\x9c;\x12\xe9N\x8eu\xfb\xd1\xee\xc9x7d\xcc{K6\x0e\xff6\xaa\x82\x8c\xf91H\xb8\x0f\x0bO\x83\x86\x07B\xbc^D<\x02\x13\xf7f.G\xe2\xe2\x901\x0f\x19\xf3!\x88\xb9\xd7\xaa\xb1\xa8y8n\x0e\x19\xf3=I\x8c\xa2C\xc6\xbc.c1u\xa32\xc8\x98\x8f@\xd8\xa7`\xecFu\x901o|!\x08\x95\x87\x8c\xf9t\x18=d\xccOF\xf0\xd3\xf4\xb9`\x14?\x1c\xc7\xff=e\xcc\xf70lkYzd\x83\x06\x86\x1e\xbc6\xb9d\xde\xd4\xdf\x1e\x8e\x1d]\xe4\xc1k\xfb/\xf2\x1a\xd7\x84\xd6\x9e\x02\xf7\x13\xbe\xf5wPyE\xaa\xaa\xe2\x9bm\x0dW\x17K\x15\x9bnT2j\xcd\x91\x12\xf6fG\x19\xady\xd2o\xe7o]\xe4\xf2.\xe5\xf9\x96EA\xf8n\x9f\xe7\xfa\x8aq\xd2\xfe\xb1\x93\xed\xeb\xc8\xdc\xd5\x8ey8\xe2\xcf\x1f\xb5*:\xf6jU\xf3n0\xbc\xadA\xe5\xef6\xfa\xa8n\xb1n\x92n\xffK\xf2\xa1\xbb\x9c\xa7+\x8bz\xc1+\x9f\x14S\xb5D\xfc:\x15\xa5\xeb<\xe3\xc1(\x8e\x1a\xc54G\xdf\xff\xfa\x03\xf0\x94\x9ap\x96\xa5\x16\xc0SR\x9fJ[\\\xe0)\x01O\xe9s\xf3\x94,\x97y\xf4\x17\x94 T\xa5\xc1*\x08\xf4$.@O\x02zR+@O\x02zR+@O\xaa\x81\x9ed\x16\xa0')\x01z\x12\xd0\x93\x80\x9e\x14\xe8%\x01=\xa9\x11\xa0'\xe9\x02\xf4$\xa0'\x19\x04\xe8I\xc6g\x80\x9e\x04\xf4$\x8b\x00= \xe8I@O\x02z\x92&)\xa8\"@O\xe2\x02\xf4$\xa0'\x99\xe8I&\x9c\xbe\xc1\x9a4-\x13\xe966\x02\x89\x95?\xd2\xe2]v\xae\x88\x89\x1a\xa2\xf8\x08'\xaf\x8f\xb4\x8a\xf0\x1d\x1cF\xd9\n\xe7\x85\x99\x01\xf2{\xe4~\xdc\x11\xac*\x9fO\x08\xd1\xf4\xd9_\x8aD\xd2\xf6P\xf3\x8a\xd8\xf4\xf4d\xdf\x16#cx ON\xb5rY\xe2T\"\xaei\xb1\x8f\xbbU\x84X\xdbF\x88\xa7\x85\x84\xf8\xdaIHkX\xd7SA\xf6\x93\x0f\n \\\xa0\x85\xca\x14f\x02d_\x16\x04\xd7\xbb\xca]\xde\x10\xeb \xf1\xd8PHl\xb5\x1c!A!\xeb\x9cr:y{r\xfc\xc6\xfb&{\xcf\xfb\xd0\xf9\xd9?\xde\x9f\x1e\xbf\xf3>\xe7xHq^F\x15\x98\xdf\xc4C\xaa-\xae\xea\xdb\xb06\xd1^\x10~\xc4\xb8\xa5\"h.\x0f\x99\xc9\xbd\x0b \n\xeb\x0e(jNA}2\x88\\6K\x85\xaf\xf7\xad\xe4\xd45\xf4=9\x81\xcf5\xa9\xa0\x00\x0bw\xf8\xb1\x9f\xdd@\x9dqk2\x94\xbb\xb6\xc6\xaefAf\x94\x08\x1ad\x88\xa1\xb6\x15Y\xe47.\x0b\xf5F\xc1f\x93\xd7\x9c-\xd3\xf0k\x99\x82v\x92\xea\xb7\xbf#\xe0\x172\x12P\xe0h@\xe2J\xc0\x0b\x7f}Px\xab\xa30\x08\x11\x05\xad]L~\xe06;\x15&\xcbicC\\\xaf\xa4!\xc5\x12\xc6LyIn\x1dQy$\xa3bYY\xd0\xba\xdaqZ\xdf%\xb9E\x8b\xaa\xdc\xf0\xd7O1?\xafv\xaet\xf1\xcd\xbdS\xdd\x8c \xbc\xdd\x92b\xfe\x15{\xf7\xe0\xaf\xe4\x96\xfd\xef}w\x19\xfao\xf0J\xdc\xe7\x85?8\xf8\xda\x1c\xa2\x9e\x935\xbe\xbd\xd8\x92*/\xa7x\xef\x01\\\xe1^\xef\xe5\x1fF\xe2\xc3cf\xef\x90Y\xe0D\x8d\xfey\xbb\xa5l<0}o-\x07r\x13\"4j\xd3\\\n\xe3\xef\xda>^\xc4B\x06Ou\xca\xac|U\x91X\xd2\xdf\x1f\xf3\x01l\x1a\xb3\xed\x15w\x86\x0d\xa7\xe8\xf8\xda-x\x06^\xa9|t<\x19^\xdd\xe2i\xee.\xde\xce\xe2\x1d\xc462\xaf\x92\xe6\x16QI\xdfm.\x14E[L\xa5\xdf)\xae\x1d\xfd\xb4#\xb4>\x10\xbf[\x94\xf1$\x1d\xae\xc6~\xe3\xa8\xe1U~m\xe0D\x03\xf8y\xf5\xd6\x19\xac\xb9\xb5\xd0v\x8d\xa5\xc6\xa6\xb1qCu\x13\xe9\x17@Z\x1e\xbf\xc6\xfc2\xc3\xfb(\xaf\xa9\xe2mQ\xb4+\xc4p\x9a\x0b*\xcbun\xe8j\xfe\x91\xaa_\x12+j\xd5\x89|\xe6\x05Z\x9e\x9d\x1e\xb5\xbc\xda\xf1\xc8\x86\xdc\x81\x1cM\xf9\xb2\xe0\x87Q\xeb\xca\xd4h\xec~BXfj\xc3\xee\xefd\xea\x96\"p\xf8K\x87'\xee:\x96Z#s6\x99\x86E/\xc9P\xcf\xcb\xb0$\x17\xdeS\x95\xbf\xf3\xb9\x85V\"\x97V_\xd3\xe5\xf5\x8a\xe1\xe6\xc8d\xb2\x96\x0by\x11~O\xd2\x837\xb6\x9d(\xe3\xcf\x9d\xefW{\xf2\xd5\x9cyjN\xe3\x08\xf1\x91 Pp\x96\x9f\xd7^\xf2\xb1\xb1\x19~!\xf9}>k \xc8\xed\x8b\xab\x8c\x87\xa9\x9f0\xab\xcfk\xa7\x10\xc4\x02\xc5\xe6\xf3\xb5Y{V}uD6_\x1d\x95\xcb\x17V\xa3\xc4\xd9|\xa1\xb9|Q\x99|\xa6\xfa9\x12\xf9\xd2\xa4\xf1y{\xb2+\x85ol\x02_@\xfa^X\xf2\x9e7uoB\xe2\x9e?mo/I{\xdeI\xd9?%\x07\xa4\xeby\x9b\x1d\x05\x0f-\x944QoD\x9a\x9e\xcf\xa2\xc1)z{6\xca\x94\xe4\xbc\x11\xa9y\xa1\x89y\xbe4\xb6\xbd%\xe5y{:\n\xea\xed(\"\x1d/\xa8\x85Q\x18-!lyO\x99\x86\x17\x9f\x84\x87f.\xcaNl\n^|\x02\x9e?\xfd\xce\xdb\"\x01\x99\x07aC\xb2\x93\x91'Xx;Z\xf3\xa4*4\xe3\xe4*\x913\xd7\xb9\x13*\xc3\xb6\xc9J\x85\x89\x16\xcd\xd2\xfe\x8097\x0b\xc98\xb3\xd9\xf1\xdd\xfb\xf3\xe3^v\xe0\xba\\\xe6Y\xb3Cnx8\x02>\xa3\xe5\xc6\xd6\x84b\x965\xf0r\xfc\xf6hw\x89\xc7\xc5\\K\x19\xe4\x95f\xfb>1*\xd9$%O\xb2Q\x13\x89\xd1\x01\xadK\x84\x0b\xceZ2U\x9b\x92-\xae\xb8[R\xf4\x03:B\x84M\xd8\xebD\xb4 7\xc4\x8c\xa0\xc7H\xa5_u\n\xcc\x83H\x84\xd6x\xb6\xce\xa9\x91~\xd5I~\x9c\x91\xfa\x9a\x90\x02\xd5\xd7\xa5\xa8\xcb\xc0d\x7f\x80{\x81*RW91\xb1\xfe&l\x81!\xd5\xc9[\\Hu\x82T\xa7\xdfG\xaaS\x8aL'G\xa2\x13zMhs\xfb`\xd7\xd7\xbd\xcfY\xb6\"\x02\xcdV\x191k\x99Y\x19\xea\xde\xc2\xaa\x1c\x90\x03\x9d\xd3\x1e$ZA\xa2\x15$Z \x81D+H\xb4j\x05\x12\xadjH\xb42\x0b$Z)\x81D+H\xb4\x82D\xab@/ \x12\xad\x1a\x81D+] \xd1\n\x12\xad\x0c\x02\x89V\xc6g \xd1\n\x12\xad,\x02\x89V\x90h\x05\x89V\x90h\xa5I\x8a\xa4\x17H\xb4\xe2\x02\x89V\x7f\x86D\xab\x0e\xe9K\xd3\xd4\xe335@\x95\xa4\x1c\x1b)\xb4{\xba\x91hL\xe2\xc0\xa1d\xf7qH\xd4\x91E\xa0e\x90\xb5\xf8\xdd\x11\x7f\xf7\x03\xa7\xb6\xa8\xdc\x02\x0db\x17\x9c\x17\x03\xd5\xbeQ5\xa4\x93Y\xb2\x0f\xb4/\xc9\x07\xefl\"B\xd3\xe2\xf3\x0b\xdd\xb6V\"\x86\xcfX\x8a\xf5;|\x7f<\x13cj2B\xb7\xe8N\x9a\xb8\xdb\x06\xc8W\x0f\xe4\xad\x0b\n\xc0\xf4\x02\xaa\x84\x02\xe3BBF!{\x0e}\x83\xe0\x8ec\xaf\x93\x16\xdd\xf3\xe2{\xa9\x11\xbep\x8c/\x11\xca7\x0e\xe7s\xa8\xcb\x8b\x08\xa4o2\xd6\x97\x1a\xed\x8b\xc4\xfb\x12#~q\x98_$\xea\xe7\xea\xc3\x0d\x1e\x18\x8a\xfb%F\xfe\x82\xb0\xbf\x84\xe8\xdfT\xfco\x14\x02\x98\x08\x03\x1c\x83\x02:\x94q|\xd0\x8f\x03\xee\x05 \xdc\x1f\x16\xb8\x1740\x0e\x0fL\x8e\x08\x86b\x82IQ\xc1p\\0\x1a\x19\x8c\xc7\x06\xbdS\xe1\xd7\x01\xe8`\x02|\xd0\x83\x10\x06:T\x01(a\x8c\xd7\x15\x8d\x14\xba\x16\xc1YyE\x02\xb0\xc2\xd0\xf2%\xc4\x0bc\x10\xc3\xc4\x98\xe18\xd4\xd0\xd5\x83\xa8\x1f7\x1c\x8d\x1cZ\xb4\xb1\xaf\xf9\xb0\xc3T\xe8a0\x04\x16\x80 Fa\x88\x9e\x90\xff(\x1c\xd1\xa7\xd3\x1aOL\x84&\xc6\x1b3\x1cQ\xf4\xd5m\x04\xaa8\x12Wt\xc5e\x93a\x8b\xc1\xe8b\x18\xbe\x18\x8a0\x06X9\x1ee\x8c\xc1\x19]Hc\"\xac1\x12m\x9c\x867\xfa\x0c\x1a\x819\xee\x01u\xf4\x96\xce\xda\xd3\xd3a\x8f\x01\xe8\xe3x\xfc\xd1\xa2\x8e=\xe6B \x13c\x90>\x14r$\x0ei\xd1%v\x86\xae\xcdq\x00\x16\xe9\x02L\\xdzD29&iG%S\xe2\x92!\xc8d<6\x19\x85N\x8e\xc0'c\x11J'F\xe9F\x8c\xc21\xa3P\x9cr\x04R\x19\x89U:\xaa;\x06\xaf\xb4\xa8\xd2\xb0\xc0\xb0!\x11\x86Y:\xba|\xb1t\xa3\x96IqK\x0fr\xb9\x1f\xec2U_\x8c\xc0/c\x10\xcc\xe1\xa5\x86B\x0c\x18\xd3\xe09\xff\xfeV\xbb\x19VC\xfc\xb4\xabau\x08K\xecVM1\x1emr\x14o\x98\xcc\xed\xbb\x17\x16\x92\xab!\xb9\xba\x91\xb8\xe2Br5$W\x7f\xb6\xe4j\xdb=\xcd\xbd\xb4jm\x82M\x91a\xad\xcf\xd7g\xa7Gr[\xd2\xbc\x04\xc9\xcd\xdd\xdf \xb99d\xd2\x132\x8a\x02\x01\xc9\xcd!\xc4\x07S\xac \x9a\xf60\x86\xf4\x00\xc9\xcd \xa9\x0e1D\x87(\x9a\x03$7O%7\x8c\xa06$!6\xc4\xd3\x1a \xb9y\n\x9d!\x86\xcc\x90\x98\xcaP\x07\x11\x19\x12\xd2\x18BI\x0c\x86\xf8\x04$7w%\x80\xb6\x10\xea%ES\x16 \xb99\x88\xa80\x86\xa6\x00\xc9\xcd\xb6\xc7\xbc\xd4\x84\x08bBH\xean\x0c)\x01\x92\x9b!\xb99\x84z\x00\xc9\xcd\\\xa6\x90\x0d \xb9\xd9\xa4\xc9K/\x18K.\xb0\xae\x0d\x90\xdc<\x14Hn\x1eA\"\xf0S\x08b \x04\x11\xf4\x81h\xf2@\x1cu\x00\x92\x9b\xe3\xc8\x02\x90\xdc\xdc\xc8>\x08\x02)\xfa\\\x049 \x9c\x1a\xb0\x8f\xe4\xe6\xbb\x9f\xd5\xac@P\x91xz\xa8 \xde\xc3_z8\xf9\xaf\x87\x02\x1f\xd4~\x10\x7fp]\xa9fN\x86V\x9f4\xe4C\xf7\xae\x01H\x93\x12\xdd\xf9\x9e|\xf6\xcefE\xf7\x1a\xc4\x86\x96\x8d\xa2>\xd4N\xd0\xcb\x1b\xef \x98$\x87\xbb\xc2\xc0\xae1P\x97\x1b\xd2\x1a\x05h\xf1OX\x14z\xe1\xac\x04`\xd6H(\xcbN\x90\x0b\x02\xb2&\xc1X\xa3@,\x84\xad\xa4\xdc:\x0c\xc2\x1a\x03`\xb9\xc2\xcaA\xf0Ub\xf0*\x08\xbaJ\x08\\ya\xabD\xa0\xd5\x14\xc8*\x1a\xb0J\x00W%\x06\xab\x00*!\xfc4\x01|2C\xc6.\xe8)-\xf0\xe4\x86\x9dR\x80NA\xa8\x89\x07p\n\x86\x9b\xec\x91\xe1x\xa8\xc9\xae\xcb\x18\x85I\x022\xc5\x18+\x14`\xf2\xdb$\x18\\\x1a\x01-\x99#V\x89`\xa5 P\xc9\x0f)\x85\x00JN+\xc6\x82I\xa1P\x92\x0dHJ\x00#E\x80H\xe3!$\x07P\x13\n\x1f%\x06\x8f\x1c%2\xf6\xd4Q\xb0\x91\x82\x88\x0c\xfa,\xa0Qb\xc8\xc8\x0e\x18\x8d\x85\x8bxD\xc0Tp3X\x94\x16*\xb2m\xfc\xbc0\x91-\x8em\x83\x88\xd2\x02D\xe3\xe1!\x0b\x144\n\x08\xf2\x82>q\x90O0\xe0\x13 \xf7\xc4\x80=V\xa8\xc7^\x9a\xd0\x90{\x18\xcc\x13 \xf2D@<\xc6\xaa\xa5\x85wl\x83b\x02\xb4c\x8cSX\x81\x9dq\xb0\x8e\x0b\xc2I\x0f\xe0L\xefI\xc1\xe0M(t3\\\"U6\xa7\x1fN\xb0\x1c\x1a\xea8\xf7\xd3\xb9\x0f\xed\xa6\x91\x9e\xbc1\x7f\xb2[\xac\x9e\x12\xc8\xdb\x84\xbc\xcdF\xe2\x8a\x0by\x9b\x90\xb7y\xe7\xf36;hl\x92\xd4\xcd.\x9e\x0c\xd9\x9b\\ {\x13\xb27[\x81\xecM\xc8\xdele\x0c\xf8mU\x06\xd9\x9bCI\x04\x84O\x83\xc2G\x80\xe1I\xe0\xf0\xe4\x80\xb8\x17\x12\xdf\x03(\xbe/X|\x0f\xc0x\x0c4>\x16\x1cw\xce\xe1>x\x19*\x87\xecMo\xc9\xc6A\xe7FU\x90\xbd9\x06D\xf7\xc1\xe8i\x80\xf4@t\xd8\x0b\xa6G\xc0\xe9\xde,\xbaHH\x1d\xb27!{3\x04l\xf7Z5\x16p\x0f\x87\xdc!{\xb3'\x89\x01x\xc8\xde\xd4e,\x1coT\x06\xd9\x9b\x11\xe0\xfc\x14x\xde\xa8\x0e\xb27\x8d/\x04\x01\xfa\x90\xbd\x99\x0e\xde\x87\xec\xcd\xc9\xe0\x7f\x9a>\x17L\x00\x08\xa7\x00\xfc~\xb27\xdb\xd2\xf4\x00\xed\x94\x9f\xb0\x02\xc7\x83o\x0f\xc0\xda}}\xdb\x96\xb5\xca\x93V\xb1\x16.<\xac+\\\xd0\x05\xa9\x0e\xaf\x1e\x1d\xceIQn.\xea\ng\n\n2\xa5\x99\xbeaO\x9d\xf3\x87\x9atR\xbc^#\xfev^\x88\xe1+\x94\x18sE\xb5\xf7\xef\xa9*\xdf\xd1\xf4\xd0\xa1At\xa9?\x03\x16\xc7:\xcb\x84 TH\x1c\x07\xc9\xcf4'\xa9\xd7\x82\xb8\x93s\xe7d[V\xf5\xa1\xa4\xf1hC\x96\xf2\x00\x9bU\x1f\x8f6V8cK\xb1\x1b\xb3\x10\xc0\x9f\xf4\x82\x16\xbbb\x99\xcf\xd6\x04\xd5\xe5%)\xcc\xee\xc8\x0cSr\xc1\x1b*\x95]\x98\xc6no\x96\xc5\xa9\xc8\x1a\xdf\x92y@\xb1B\xec\xdc\x8e\x83\xae\xf75\xfc<\xb3\xde\xc9\xd1\x87\xc7\x0f\x9b/\x1b\x15\xf2\xd2\xd0f\x13`|F\xdaW\xb5E^\x88\xe9\x83}\x85\xb5\xb9'eF\x1f\x0f\xa8\"\xf5\xae*\x86c\x9f\x8a\xc1\xaf\xeb\xee\xab\xdd\xe2\xa5|x\xd8f\x9d\x0f\xb6\x0fvz\xa3\xf6g\xb9\x9f0M\x02B\x9c\x03\xce=\xdc\nrS_\\\x92\xdb\x89t\"k\xc4\xd7F\xe2P\xa2\xbe\xaf\xf8\x1a\xec\x9f\x12\xfa\xc0\x94\n|\xe7\x14/\xc9\x19\xf9\xb4#\xb4>\x10\xbf[\x94\xb1\xa9Z\x10\x8b\x98ZfB\x826%\xad\x11\xe1\x80\x02G!L\xf3UY\xe3\xb1)\xec\xe1|*\xebT\xc4?\xcf\xeb\xcf\xff!\x16o6\x1e\x15\x94\xa5\xe1&6\x16\x80n\xa2\xac\xdc\x15\xf5\x05Wf\x9b\x84\xae1E\x94\xd4\xf7Q^S\x85\xd0Q\xb4+D\x07\x9c\x0b\xd0\xe2:\xa7\xdd6u\x8f\xf8\x1e-\x87\x8eg\xe2\xe8\xab\xef\xd9\xe9Q\xbf\x12b'\xdf\x8e\x02 \xe3t\x7f\x032\xce\x1ep,\xd7.\xa0\x9d\xaa\xd9\xf4d\xeb\x86\xbd)P\xceyX\x0e?\xb1\xd2phY\x0ef9\xd97\x13$\x9f\x15\x97=\xe4\x94\xcfx\xd2\xe3pLz\x07\xe8}\xc1y\xa5\xdc\xed(\x17\x0bJjTV\xa8[\\\xa4\x11Z(\xa9\xf5u\x869\xf1\x9f\xa4\x83\xad\xa4\xf5\xe2\x17xM#\xdc\xf8\xceba0\xa2(\x9f\xcd\x8e\xbd\x89GV\x86\x9b\xb2\xd8mH\x95g\xeao|\xcf\x9d\xe1\x82\xd5G`\xa3+R(\xc3\xef\x8afZ\xed\x05\xa1O\xb8\xb65\xa1\xb45\xa1\x00pw\x9c\xdbxI\"\xed\xd9U\xbfg\xe3Z\xf6g\x9ay\xd7\xf9&\x0f\xb5.\x7fV\xcd\xe0\xb6\xf5I\xac\xd7z\x0f\x96\xf3}?1k+\x80I\xfdO'\x0b\xb4&\x8bZb\xe0y-\x82\"*t\xccY\x16b\x80\x88\x8f0;\xcfn\x05-\x18o\xb7\x9f\xd1\x8a\xfa*\xdb\xbe\xef\xb2\xa5\xf6\x06\xb3(\xef\xa1%\xdf\x013\x1f\x00\xe5\xc5\x9c\xedXIK\x0d\x17\x16\xe4\x0f\xca\x8e\xa4\xab\xcb\x8bl\xbd\x9b\xf7|`,\xbe\xd2\x10\xdez-\xc6gl\xcd\x9f`\xabp\xc7\xd1\xec(\xfbxB{\xad\xd5\xab\x02\x8f\xa5\xb3\xa5T,\xad|x\xb5\xe3\x91\x0d\xb9\x039\x9a\xf2eQV\xbd\xcd\x93\x1a\x8d\xddO\x08\xcbLm\xd8YY\xaeI\xe7*\xacf\xf2\xe9\xfc\xe2>\xfa*(\x8ap\xf8\xcb\n\xd3\x95\xeb\xd0*m\x17\xd4\x04\x13\x0c\xa1\x04\xd3n\xc2\x12U\xb8\xa7\xacp\xf7\x83\n6\x97b\xd4n\xc5\x1e\x1a\xf0\xae\xea!\xdb\xd5\xd4A\x81\xc0\x90@l@\xc0\x17\x0e\x88\xb3\xc5\xe4P\x80\xdf\xb2\x89\xc3\x00\xfe @T\x08 `[\xd3V \xc5\xae\x0665\xb0\xa91\xfe~\x9765lQ\xb3u>\xf6\x1b\xfa*/\xd0\x8a\xdcH\xbd_\xb7\xa8n\xc8\xba\x86\xa6\x03\x03\xe3\xe2\xff\xbc\xca\x8e\xc8\xff)\xff\xbd\x13\xf4o\xad\xa4\xea\x98\xcf\xb2\x07J)\xda\x94\xf3\xdd\x9a\x18\x17\xec\x93\xd7G\xe7\xf21\xa1\xf7\x9e\xaa\xe6\x1d]\xb7u\xeb\xe8\xd2\x0bXr\x13u\x83\x95}\x13u\xad\xd2\xca\x84\xc5\x9f\x92b~A\n\xe6\xb8\x1a\xb2h\x91\xc3\xf7k\xc5\xec\x05v\xc5\xbf\x9e\xa1^i\x90\xf8_\xcek\x9c\xe7T\xfc\x9bu\x9d\xac*)} |\x08\xbej\xd9\x86\xaf\xec%\x14-\xaar\xc3\xc9\xd46g\x81+3y\x05\x15\xc9H~E\xee\x8e\x85z\x05Jh$\x8e_G\x99(`\x8d\x17#4h}\x97+\xba\x9c+\xd8j\xde\xd5\x07\x8b9,\xe6\xbf\xf9bn]\x0f\xd7\xb3\xcd\xe15\xa6\x1bqr\xb3jI\xd3\xe2wT\xce \xe5 \xbab\x0e'5\x9e\xe3\x1a\xf3n\xcfF*\xad\xd9&\x1e1e\xbcO\xa8\xf5\xacwN\xf2\xfc\xee\xa3\xde\xac\xf4\x17\xcc/\xb9#\x1dJ\x94\xc72iG\xf5\x08\x07\x10\x95U\x04\xd7\xa6\xa1/\xc4\xfb\x11\xd6\x17.\x98\xef7ZC\x00`\x98\x17\xb4\xc6E\x9d\xe3\x9a\\lI\xb5\xc9)5b\xa8B\xbe\xfbpz|t\xf2\xf6\xe4\xf8M\xc4[\xef\xde\xbf~\xff\xe6\x1f\x11/\xbc\x7f\xf7\xb7\x7f\\\xbcz\xf3\xe6\xec\xf8\xc3\x87\x88\xd7\x8e\x7f<>\xfb\x87\xe7Sj}\x1bQ\xad0WB\x88\xd5l/\xd1+>i\x9c\xdfn\xc9\xc7\xa2I\xf5q*\xdb\xaeqFV\xe5zN*\xc1\xcf\xe5\x01h>/;\xdf36\x83^\x80w\xe5\xac\x9c\xf3<\xc7Y>\x9f[\xbd\x19\xa36\xbd\x8dt\x9d\xef\x8b\xf5\xed\xab\xf9\xbc\"\x94\xb2Y\xb1\xaer\xee)\xd4%OA\x12?\xc4|\xa7iT\xfd#\xc7W\xa4\xba\xe5e\xdf\x15\xedG\\\xe3A\x00\xdb\xad\x06m\x1c\xf1\xc1b/\x93,\xf3\xc4\xd1\xd6]:x1\x8e\xcab\x91/y\xc24\xa5<\xdaT\x95\"\x91\xd9\xe43\xcb\x1a\xb0%\xeb\xa4X\x94\x8d\xf3\xd7D\xa9\xd8\xbc\xcc\xd7A$\x16B\xe6\x9d\xab\xa7{\xfa\x80\xf0\xc1\x05\x08\x1f\x7f\x1c\xc2\x87\xad\"\x92\xea1'Q\xdb%\xe1]\xdavK\xcd\x1fa\xb3\xd4\xfd\x0d6K\xe1^\x02\x9c\xad\x02g\xab\x98\x05\xceV\xe1\x02g\xab\x0c\x05\xceV\x81\xb3Ul\x02g\xab\xc0\xd9*\\\xe0l\x15{\x9f\x86\xb3U\x84\xc0\xd9*p\xb6\n\x9c\xad\xc2\x05\xceV\xe1\x02g\xabp\x81\xb3U\x84\xc0\xd9*p\xb6\n\x9c\xad\x02g\xab\xf4%\xf4\x9c\x0b8[\x85\x0b\x9c\xad\xf2g8[\x05\xb2*\xe3R\xd6 \xabr\x8f\xc6\xf5\xe7\x03BVe\n+BV\xe5\x1f;\xab\xb2\xcfE=\xfcE2\x1f]\xf9\x93G\xe5\x9c\xb4\xac\xd4&\xae?'\xdc\x91\xe8\xb2T\x11\x9bLHKQ\x95\xba\x06\x0c\xd5{\xaa\xc6w\x9d\xa0j\xc3\xf0G\x91\x7f\x9c4So\x10\xdaK}q\x12L=\xea=\xe4\xd2\xe0\xc2Y\xe2\xe31\xb4R\xa7\x81\x91\xd7\xc8(\x90P\xea\xad\x12\n \x93\x8e\xa1\x92F\x12IG\xd1HcI\xa4\xa3)\xa4!\xd0\x82\x90\x84\xf4\xd1\x91\xe4\xd1\x94\xd4\xd1\xdf\x868\x9a\x9e6:\x9a4\xea\xa5\x8cz\xc7\xd3D\xbahJ\xb2({ \x8a\xd1\xe5\x98\xe0\xbc,\xbdX\x92\x1ep\xf4\x80\xa3g\xf8\x1d8z\x9a\x00G\x0f8z\xad\x00G\xaf\x06\x8e\x9eY\x80\xa3\xa7\x048z\xc0\xd1\x03\x8e^\xa0\x97\x04\x1c\xbdF\x80\xa3\xa7\x0bp\xf4\x80\xa3g\x10\xe0\xe8\x19\x9f\x01\x8e\x1ep\xf4,\x02\x1c=\xe0\xe8\x01G\x0f8z\x9a\xa4\xe0K\x01G\x8f\x0bp\xf4\xfe\x0c\x1c=\xc9'\xd0tL<\xd4\x13\xd9h\x06c(%\x87\x1c\xcf\xc3YM\x9d\xe4\x12\xf9\xcck\x8e\x95\xa1uNkq.!\xdd\xe0J`\x01\xfcw\xc9/\xe1 _S\xe5\x1e\xaf\xa4\xa3\xea\x9e\xaa\xfe\x9d\xa5\x98\xc8\xe2&\x85\xa0,\x01\x12 R\xb6\xd6\xe41L\x1en.\x17\xcd\x9f\x15\xc8;\xd8l\xc3\xe1:\\\xe0p\x9d?\xdc\xe1:\x83\xb6T\xf7(\xe9SI\x10\x82o\xd2s\xd8\x9f\xde\xceN\x8f\x00\xcc\x070\xdf\x17\xc9\x0e \x06#\x00\xf3\x01\xcc\xb7> `>\x17\x00\xf3\x87\x02`>\x80\xf96\x010\x1f\xc0|.\x00\xe6\x03\x98\x0f`>\x80\xf9B\x00\xcc\x070\x1f\xc0|\x00\xf3m\x02`>\x80\xf9\x00\xe6\x03\x98\xafI\n`\x15\xc0|.\x00\xe6\x03\x98/% \x98\x0f\x87\xfc\x8c=A\x05\x0e\xf9\xd9\xa3q\xfd}\x14\x0e\xf9IaE8\xe4\xe7\xcft\xc8\x8f\xe0\x1f\x1c\xfe\"\xa9=\xee\x83~\xc4\xc3'\xc5\xa2l\x0f\xfci\xc8A\xcd\xd1\n\xf2=#\xf9J;l\xe1\xce2\xaf\xacGY8\xc3\xd2\x920\"_V3\x8b\xfaO\xd9m\x95\xb1zo\xab?\xff\xee\x8e\x14\xea\x1e\xbb\xf1\xa6%\xc0,HE\x8a\x8cH\xf7O]M\xfa\xf7\xde\xb9O\xbaL9\x9d\xa8-\x86P\xd2\x98\xfdz\xc5\xa6\x9f\xbc\xce94\xad\x9d24w5\x07\xe2\x9d`\x93;\x0f \xf2\x17\xe6\x15S\xc1\xd7\xef\x16\x0enJ\xd6,\xe1\xe4\x86d\xbb\x9a\xa0M\xbe\x14\xc3\xc5\x14\xfc^\xe3\x19\x19\xcb\xda\n\x01\x1b\x10\xfa\x1b\xfb\x02\x9f\xfaTI\x9b\x93\xbb\xe4\x02%o\x97\xe5\xe8\x81\xcbr\xa89\xcf)3\x82\x1f\xbc\xa1\xad7`{\xf8cG\xe2et~\x83\xb6%\x15[\x0c>\xddv\xa6\xa2k\xce\xbbh\x1b\xdb\x1a\x03\xe5t\x14^I\xe9 ^\x92m\xcdiI\x15o\xacb\xce!>\xb6q\xba\xd9\x96\xcc\xd3\xba\xcam\x90\xb5 \xe4I\xd7\xe1\x00\xfd\xfb\xceNZ\xd9Q\xb1B\xd1\xb2\xaa\xad\x9d\xc8\xcd2\xf2\x0d|&\xb3u\x99]^\xacH\xbe\\\xd5\xf6(\xaa\xb7\x03\xa1\xb0\x99\x00\xb5\xcd\xf7\x9a}\xf8{\xfe]5%\xf0\xb2\x0c[Iv\x06;\xfd\xa7\xbe\xb9\xc8\x8b9\xb9\xf9M\xcb\xef<\xa8\xea\xfc\xe6\x84\x15H8\xe6\x9b\xb2(\xeb\xb2\xc83\xe1A\x90\x8a\x0f\x10\xe9(\xf2:;4}\x85\xb3z\x87\xd7\xe2\xeat\x9cIOeNn\xee;\"\xcd\xcc\x1b_b~\x1a\x12'`\x98c\xc5a\x83\xfe\xd5\x8c\x96\xeb]M\xceoN\xd5`\xe2\xb5\x12\xf4\xb0N\xb9\x9a\xd1\xc6&.\x8b:\xce\x93\x10L\xec\xe5\xba\x9c\xd9A\xf5\xb2\x9a\x13\x1eGb\xcbb\xfb\x11#T\x9c\xcf\xb2\x8bmY\xd5cW1Z\xe3zg\xa3\xe2\x89\xe6\xfe\xc0\x1f\x11U\x17\x8f\xf3\xf0\xa3{\x92\xf3v;\xd7\xd9p\x0f\xd0\xd1\xfbw\xe7g\xaf\x8e\xce/>\x9c\xbf:\xff\xf8!\xe00\xb5\xe1;\xaf\x8e\xceO~<\x0e~\xfc\xe4\x9d\xe3\x85\xe6\x84\xb7\xd8\x82\xb9B\x01\xad8+\xdc\xba\x87\xb2%v\xfec\xdel\xd6\x18\xe8b]\xcb\x0e\xd6\xdb\xad4P\x94\x17VU\xe4\xa6&\xc5^O,\xac=\xa4\xd1\x80\xfe\x88\x82\xa7\x054\x96:\xea\x9a\xb5\xfa\xec\x01\xd7\x14\x97\x94>\xea%\x90\xa6\xa6\x90\x86\x93H\x13\xd1H\xc7\x11I\x1d\xea\x98A\x83\xa9\xa4\x93\xc9\xa4\xa9\xe9\xa4\x91\x84\xd2\xc4\x94\xd28Ri$\xad\xd4\xd5\x87\x1b\xc2i(\xb141\xb54\x88\\\x9a\x90^:\x95`:\x8ab\x9a\x88d:\x86f\xeaP\xc6 \xa8~\xa2\xe9^\xa8\xa6\xfb#\x9b\xee\x85n\x1aG8MN9\x0d%\x9d&\xa5\x9d\x86\x13O\xa3\xa9\xa7\xf1\xe4S\xefT\xf8u\x00\xfd4\x01\x01\xd5CA\x0dt\xa8\x02h\xa81^W4\x15\xd5\xb5\x08\xce\xca+\x12@F\x0d-_BBj\x0c%51)u\x1c-\xd5\xd5\x83\xa8\x9f\x98:\x9a\x9aj\xd1\xc6\xbe\xe6#\xa7\xa6\xa2\xa7\x06s,\x03(\xaaQ$U\x0f\xa7l\x14Q\xd5\xa7\xd3JXIDW\x8d7f8e\xd5W\xb7\x11\xb4\xd5\x91\xc4U\x17\xf1'\x19y5\x98\xbe\x1aF`\x0d\xa5\xb0\x06X9\x9e\xc6\x1aCduQY\x13\x91Y#\xe9\xac\xd3\x08\xad>\x83F\x90Z\xf7@k\xf5\x96\xce\xda\xd3\xd3\x91[\x03\xe8\xad\xe3 \xae\x16u\xec1\x17\xc551\xc9\xd5Gs\x1dIt\xb5\xe8\x12;C\xd7\xe68\x80\xec\xeab\xe4\xb9\x08\xaf\xe9)\xaf\xc9I\xafv\xdakJ\xe2k\x08\xf55\x9e\xfc\x1aE\x7f\x1dA\x80\x8d\xa5\xc0:I\xb0nJb8)1\x94\x08;\x82\n\x1bI\x86uTw\x0c!\xd6\xa2J#\x9b\x86\x0d\x890R\xac\xa3\xcb\x17K7-6)1\xd6C\x8d\xdd\x0f96U_\x8c \xc8\xc6Pd[\x92l+\x0d\xf7D\xe3%q\x9a\x02E\x18\xfd\xfd\xd5\x87\x1fZ\xacY\x11\x12\xee\x19\xde\xb7]\xcd\xd2j\x9d~\xc0\x0b/\x1b\x9c\xee\xc2\x05Nw\x81\xd3]Z\x81\xd3]\xe0t\x97V\x92Bq1@\\\x14\x0c\x07\xa7\xbbL\x05\xdfF@oI\x80\xb7x\xd8\x0dNw\x99\x02\xb7\xc5\x80m\x89\xa1\xb60\xa0-!\xcc\x16\n\xb2\x19\xfcg8\xdd\xa5+\x01\xb0Z\xa8\x97\x14\x0d\xa9\xc1\xe9.A@\xda\x18\x18\x0dNw\xb1=\xe6\x85\xce\"\x80\xb3\x90\xb3Kb@38\xdd\x05Nw \x81\xc6\xe0t\x17.S\xc008\xdd\xc5\xa4\xc9\x0b\x7f\x8d\x05\xbf\xack\x03\x9c\xee2\x148\xdde\x04\xc8\xe5\x87\xb8b\x01\xae\x08x+\x1a\xdc\x8a\x83\xb6\xe0t\x9780\x0bNwid\x1f\x00V\x8a>\x17\x01^\x85CW!\xa7\xbb\xc8\xb4`MGg\x17\x19\x96U\xce\x9a\xa3\x7f\x9e\xc0\xc4Cb\xc6\x1e#p\xb8\xcai]V\xb7\x01\xc7 |/\x9e4\x9c(\xc0/s\x91\x8a\xe4\xdb\xc6C\x05\xbe\xef8\x12\xae-\x8f_\xf2\x89\xd5\xfa\\h%Xgx\xe9-\xe5I\x91\xd72\xee\x9d\x17}\xba@\x9d\xf3\xe7&\x17E\xf6)\x7fi~\xe0g@\x101\xf15\x07BL\xfe\xbe\xec\x8c\xfe\xef\xff\x85\x14\x84\xe6\xb4\xcd'Z\xca?h\xc7\xba\xf4\xc5\x9f2\xef\xfb*\x92\xd9\xdf\xeaL\x0c\x1e}\xb6CG\xdc8\x02N0>\xe3<\xf2$h^\x0b:, \xee\xe0\x13AF1\x1e|\x82\xd0n;\xb7\x9f\x88\xd1\x1b\xdd\x1f\xc5\xb3\xe6\x030\x9aI\x9d\x9f\xad O\x16\x99\xdb\xb6\xee\x9e\x15\x04\x05\xac\"(\xf8\x94\x89 \xc3\xa3P\xe3#\xb4\x8f\xb3&BN\x9b\xd8[=\x9cyA)O\x9d\x18{\xeeD\xe0\xc9\x13\x1b\xbaL0\xf4,\xc0Og(\x18\xe6\x95\xe3\xa2\xaen;'\xd7\xb4\xa78\xf4\x87\x01\\Z\xc7\x05.\xad\xf3\x8e\xc0\xdf\xdb\xa5unB\xa3\x1c*\xd39\x8dj\xe3\x06\xb4F.@k\x04Zc+@k\x04Zc+@k\xac\x81\xd6h\x16\xa05*\x01Z#\xd0\x1a\x81\xd6\x18\xe8%\x01\xad\xb1\x11\xa05\xea\x02\xb4F\xa05\x1a\x04h\x8d\xc6g\x80\xd6\x08\xb4F\x8b\x00\xad\x11h\x8d@k\x04Z\xa3&)(f@k\xe4\x02\xb4F\xa05~>Z#\\q7\xf6\xfe0\xb8\xe2n\x8f\xc6\xf5_\xce\x06W\xdc\xa5\xb0\"\\q\xf7g\xbe\xe2\xee\xb0\xc2\xd7\x87\xbf\xf0R]\xccq\x8d]w\xde\x9d\xe1k\xfd\x1a\x10\"X\xeal*Y\x0b*\xcc\xa2*7\xa2\xc1\xf1\xb5`\xfb\x89\xfb\xa4L\x17\xc8t\xc8\xeb}\xcd\xf7\x94q\xee({\x9d\xd5*\x8a\xbf\xe0 wK\xae\xca\x1bf\xac\xce\xce\xa3k\xc8{\x86w\x06\\%\xde\xf2}\x83\x8e'\xb8\x0c\x1a\x1d\x18.\\\x80\xe1\x02\x0c\x97V\x80\xe1\x02\x0c\x97V\x80\xe1R\x03\xc3\xc5,\xc0pQ\x02\x0c\x17`\xb8\x00\xc3%\xd0K\x02\x86K#\xc0p\xd1\x05\x18.\xc0p1\x080\\\x8c\xcf\x00\xc3\x05\x18.\x16\x01\x86\x0b0\\\x80\xe1\x02\x0c\x17MR\xb0\x0d\x80\xe1\xc2\x05\x18.\xc0p d\xb8ho'#\xb6\xb4\xf8fJ\xed\xc6\x1d\xfeh \x96npU\x87B\xb1\x1f\xd8\xc3\x030\x16q\x1d\xf2`\x01 \xba7\x98\xac\x0b\x7f\x1d\xaa\xbb\xa7\x0c\xf2gG`\x7fb\xeb\x13G\xb1\x1b^HcRanC\xc7\xf5\xa0\xb3Cs\x8f\xc7g\x0d=\x01\x10Z.\x80\xd0\x02B\xdb\n \xb4\x80\xd0\xb6\x02\x08m\x0d\x08\xadY\x00\xa1U\x02\x08- \xb4\x80\xd0\x06zI\x80\xd06\x02\x08\xad.\x80\xd0\x02Bk\x10@h\x8d\xcf\x00B\x0b\x08\xadE\x00\xa1\x05\x84\x16\x10Z@h5I\x81\x96\x01B\xcb\x05\x10Z@h\xef\x1aB\xdb)\x1b\x87\xbb\x86\xf8\x9c\x00;9@\xd7\x9e\xc1\xbe\xaf\xd2&F|k\\\x13\x07\xc8\xfbj\xbd6\xe4\xdb\xe2\xf5\xba\x9f_\xcb\xba5V\x89\xb8.\x9c\xb7\xaf\xf1\x9e2\xc2\x1dEy7\xe5\x9c\xdc\x15\xc4\xcdz\xed@\xaaH\x93\x84\x8cW\xe4\xe6\x01)\xf8\xc5.\xf2\xb4\x8c\x8a`\x1e*\x9c\x91\x9a\xf9x_\xf1\xd0e\xce\x86eM\n\x84i\x96\xe7f_\xff7\x08\x8f\xc9B\xcf0%\xcf\x9f\xaar\xb3\xeei\xbb\xb8H\xbe\xf0\x03kYq\xd8\x05\xad\xab]&\x0f\xb9\x10K\x01F\x7f\xfd\x11mq\xde\x0fD\xc1-\x15\\\xe0\x96\x8a?\xdc-\x15f\x9eH\x7f\xba\x1e\xcf\x12\x19,%\xc0\x11\xe1\x02\x1c\x11\xe0\x88\xb4\x02\x1c\x11\xe0\x88\xb4\x02\x1c\x91\x1a8\"f\x01\x8e\x88\x12\xe0\x88\x00G\x048\"\x81^\x12pD\x1a\x01\x8e\x88.\xc0\x11\x01\x8e\x88A\x80#b|\x068\"\xc0\x11\xb1\x08pD\x80#\x02\x1c\x11\xe0\x88h\x92\x02\xaf\x07\x8e\x08\x17\xe0\x88\x00G\xe43rD\xe0z\x8a\xb8\xb3\xff\xe1z\x8a=\x1a\xd7\x7f\xb1\x02\\O\x91\xc2\x8ap=\xc5\x1f\xf9z\nN\x91\xcb\xca\x82\x96U\x9d\xef8Q\x8e/M\xd4\xce\x8a;\xe5\xbf\xf3\x92*0yS\xcewk\"\x16\xb5&\n\xdc!\xbe\x1d5\x9f\x10\xaf\xdfS\xd5\xbb\xa3\xc47\xdd\x08\xbaXU!/\x1f\x80\x14\xac+\xce]\x9c\x9cak\xb6bn\xd7V:f\x92m\xd4\xe5^)\x8fC\x11UP\xdb\xee\xb2\x05\xbb\xfb\x16w\xec\x9a\xf7 \xf1\x9d Z\x8c$\xc2\xc8\x92\x9d\x9d\x1e\xf5\xf4\x89\xadt[\x02`\xc3t\x7f\x036\xcc\x1e\x80\xa4\x88i\x91#F\xb8.+\xc7\xd4\xf8\xa3z\xe6\xd5\xae^\xb5S$\xde\xd5\xab\xb2\xca\x7fV\x8b\xcf\xa2\xe4\xeez\xab\xd18ev\x95\xc9'\xee\xec\x84\xc9\xeaxG:\x9a\xb0bY]\xc8\xad\xd1\xe8.\x93U\x84\xb7\xc6\x85\xa4\x05\xb8\x15\xb9&o\xff\xf4\xddk\xb6N\xe37\xf3\xf8\xb0#\xf1\xe8Y\xdb\x93\xfa\x81' \xecr\x01\xc2\xee\x1f\x87\xb0\xeb\x8a5H\xaf\xa4;s\x06y'&5\x87\xbd\xe9\xbc\xa5\xec\x82\x97\x02^\xcao\xe8\xa5\xb8\x82\x85\x10\x93\x8b\x0bx@Ln\x8f\xc6\xf5G\x93 &\x97\xc2\x8a\x10\x93\xfb#\xc7\xe4\xbet\xee>\x0f\x7fi\xfe\xad68\xae\x83\x8a\xbb\x1b \xfb\x8e\xd4\xb2\x91\xb0\xefH\xef)c\xdc\xe1\x0d\xa9\xcd\xa5\x18\xb5I \xdbVzV\xf8\xb0-\xa5\x7fC\xe9\xdbN\xa6\xdfL\xc6\xfa\xddC\xb7\x9bo\x0c\"\xbdnp\xba\xa5\x80\xd3}\x87\x9c\xee\xc1\x0cl\xeb\x89\x83\x07;\xd1\x95\xe6\xd7\x06\xc4\xafK\x19>Xt\x87\xdfD\x08\xdf\xbd\xd2\xd4\xe5%)\xd8\"\x83\xb7\xdb\xaa\xbc\"\x87\xbfp\xbe\xeaE>\xff\xf5\xf0\x97mU\xde\xdc\xfez\xf8\x8b\xfc\xadr\xad5\xaf\xc43\xed*#\xff\xbb,\x10F\xcb\xfc\x8a\x14\x88\xabS?T<\xc7\xdc\xb8\xd4HU\xf7T]\xef\xea\"#\x8a\x99t\x9dQ\xc6\x19\xb5\xbep\xfb\x8ezS\xb5\xf9\xa8\x97{\xe6\xe7\xbaP>G\x98\xd22\xcb9\x0b\x9f'#\x08\xbf\xf0\x92\x14\xc3\xf0a\xb7\xfdd\xcfi\xd6*\xf9\xdfl\x95b#\x959\xc1\xdd\xb6\xb3\x84\xb7D\x1a\xb7x;(\x10\xa4\xf2\xb5;\xfdO $ms\x81\xb5\xe8\x0e\xadEj\xdc\xda:`\xdcX\x9c\xb8\xd0h\xbbU6\x11\xedC\xb1\x9a\x1e\xd3\xe9\x8e[\x1d\xa9ay\xf4\xaf\x89\x1a\x18\xb8^\xab:\xd0\xc1\xca\xe8Z\x0b\xef>\x04(\xcby7\xc6\xb1{\x19\x0d\x18\x89\x8e\xa54\xe0m\xf7r\x1a\xa0`\xd206\xaa\x88^T\xdd\xf8\xe1\x04\x17\x07\xf0>\xc0\xfbB\xf1>\xe4e\"\xa1\xa6(\x9a\x7fWv8\xf0y\x81\x96\xccyk\\>\xe9\xa6Pt\xbd\"\x95\xa9\x13Y\x0e\x88\xc8\xcaJ\xe8\xe0\x87i\xa8\x98\x86\xa2\xab\xaf\xb0\x88\x9a\xcco\xbdS~z\xe0L\xbc\xacpQ\xd3\xc3_\xf8\xff\x12\x128\x11\xff\x85\xbf\xd5L\xbeB\x89\x1e;\x96\xea\x8cs\xaax\xf9\x9e\xaa\xd2\x1d\x9dRE\x9d\xee\xc6\x18\x93\xd6\x9c0H:&\xec%\xe8\x0b\xeds\x843\xee\x8e\x98\xa2\xb6w%z\x8c\x10\xce\xcc\xb1_!\xb1\xa5p\x9c\xcc'>\xa4\x8e\x0e\xe5%\x12\x85>h\x0e\xed\x93\xdb\x95/6yQ\x7fq\x1f}1\xdbU\x85\xfd\xa0\x05\\\xcc\xd1\x17\x9br\x9e/n\xbf\xf0F\xc6\xf9\x18i\xe2\xe2\xbc\x85FB\xcdb\xb4\x05\xad\xe5r\xf5\x96\x83\xdb\x96\x10\xd9\xfc\x11\x96\xf2\xeeo\xb0\x94\xff\xc6K\xb9\x9c\x165e\x13\xd7\xcc\xdf\xf7RNw\xdb\xed\xfa6l\x01\xff\xc0\x9fu\xef\x9e\x16U\xb9\x11\x0b\x84\xb6\x83\xca\xe7\xc65]\xe8\xbb\xa7\xeavG\xd7\xf4\xb4\xdb$Q\xe7\x98\x99UZ\x1dfV\x98Y\x87\xbf\xdf\xa5\x99\xf5NM\x7fm\xb1\xd8\x8f=\xbd\xb1\x81\xac\xa0\x89\xb5;\xaf\x8a\xe9\xd0>\x97\x9e\x8b\xe9R\xa7\xd3\x08wqCj<\xc756\xce\x98\xe2\xad{\xaa\xd4wt\xc6\xd4\xeb\xde\xf9\xfbg\x18D\xe96\x1f\xf9\xbc\xc3z\x167\x92\xb4\xf7\x91Tm\xb8\xd7\xba\x0f\xe1\x1d2Qq\xf8a\x86z\x81V\xbb\x0d.\x1eT\x04\xcfyT\xb9\xd0\xef\xf6\xb0\x17\x89\xdenf\xe5\xf8)\xa6W(\xa1\x8d\xe3@\x05\xc2\xb3YE\xae\xc48\xe7\xa5\xe1\xeb\x9a\xbd(\xac\xe7\xa7*\x08\xd3%\xe0\xa8Y\x95\x93\x85\xfec\xe3\xac\x98K\x91o\xf0\x92M\xbby\xaa\xa28\xb6\x8b\xcd\xb7\xa4\xc5\xd8\xbf\xd4\xe2/f\x03\xfe\x84\xb8\xa3o\x8e\xca\x85\xfd\xa2\x9bl\x85sK\x8d\xe6$\xcb7\xd8\xb4\xaa q/\xb1B\\\x0b\xad\x92\xd0Z\xab\xf2(\xe7\xa7\xf5!\x9b_\xc4a\x8dl\xab\xcc\xaf\xde\x98\xe7W\xf9\xdc\xcc\x91b\xc2\x94\x08/\x8dG\xe9K6\xe1rv\xce\x8e\x92\xaaw\xb0\xa4\xa5\xeb\xe5E\xcdF\x8d\xdbDS\x8f\xc6@\x11FR%j\x8b\xcfI>\xf2\xc2\x84\xa6{P\xed\xae\x0f\xa7.o\xf0\x80/-\xed\x84\"\xd4\x03\xa5\x0e(u@\xa9\xeb\nP\xea\xac\x9b[\xe1\x9e\xc6ln\xa5\x1b\x0c\x9b[\xd8\xdc\x0e\x7f\xbfK\x9b[\xa0\x97\xf9w\xc6\x08\xe8eR\xf6l\\?1\n\xe8e)\xac\x08\xf4\xb2?\x11\xbdLD\xad\xc2\x90\x10\xb1Yj\x82wE/v'.XD\xcc\xda5uc \\\xd3=U\xe1\xbb\x1c\xd0K\xba\xcfK\x93\xa0=9$g\x0f\xc8\xc5\x15$I0\xce\x15\x8a\x8b+\xce\x840\x9c=\x08\x17W\x84\xb1\x018O\xf8-\xae\x10\xf1\xf15{\x1c\xcd\x1dE\xf3\xc7\xd0\xfc\x114\xff^\x16\xa5\x8f\x9eM\x8d\x9d\xb9#g\xfe\xb8YH\xd4\xac\xdb\xb1\xe2\x03c\x96\x00\xd8\xf8\xf0\x97\x7f\x13\x1c\xbd\x07\x86-0l\x81\x0d\xbf\xdf\xa5-\xb0\x01\xdf\x9d\x08\xd2\x9a=3J\xb2]\x95\xd7\xb7o\xda\x1b\xc2\xd9C\x97\xaa\x11\xe4\xa4\x82i\x9e\xdd\x9bw\x9f9Z\x91\xec\xf2\xfc\xe6\x8c;\xd5\xfa\xd3Z#\x0d\x9b\xa5\xdb3M=\x929u\xfd':5Ybz\xc1|a\xb7\x1a\xf6\xd45\xe7M\xba\x9fc\x13\x8f\xf3s\xebr\xe9\xfc\xbdkXS\xe7\x1etjKg\xb6ubC\x8c\xde\xda\xe3\x8c\xfdt\xf04Q\xf7\xca\x89\xdfy\xa3\xa0\x87z\x03\xf0\xff\xafY\x80\xfd\xbf\xbe\xfd\xd1\xb3\x87\x0f\x1f\x0e\xcd\x8d\x1e=l\xff\xce\xcd\xcb\xff\xbf\xd1\\\x0f\xd0\x97_\xf6\xff\xe3\x0dY\xe7W\xa4\x82\xae\xf5\xc7\xe9Z\xcf\xf4\x06\xf8\x8c]\xebuU\xe2y\x86i}~sTn6y\x1d\xdb\xc5\xd8\x9cwQ\xdf\xf4\x1b\xa5go\xb3\xb5\x87\x8b\xb2\xa9\xd3\xa0A?E\xf6F\x19\xf6W\x97ZS\xbfu=\xdf\xed\xbf\xc8^\x8cN?v<\xd7m d\xe9\xd3\xc8\xe6\x07X\xfa6\xf2\xac\xff\x16\x88\xd3\xda\xcf\x91k\xb97\xbe\xd5\xeb\xf3h0\xa5\"S\xdfG\xc3\xfe\x8flc\x009\xc6\x012\x8d\x05d4wgL\xf4\xfe0\x17\xd3.\xf4n\xe8\xdd\x81\xbd\xfbY\xbfQ\xefp\xef^a\xba\xea\xf7kK=\xd1\xf1\xf1\xb3\xb7O\x9e>|\xfa\xf0\xc9\xd3\xa3g\x8f\x9f>{\xf8\xe8\xf9\xe3\x17\xaf\x9f=?~\xf8\xe6\xcd\xd1\x93o\xdf\xbez\xf3\xfc\xd9\xa3\xb7\x0fU8{E\xf2\xe5\xaa\xee+o;\xdc_\x7f<\xc5\xb9\xdc\xbf\x05\xac1\x9d\x065\x14\xb4\xd7x\xbd'~\xa0K\xfdK\xcd\xdf_\xe9'\x10\x0f\xb4v6\xb73\x92\xad\x9e{\x9a\xed\xf0O\xcb\xcb\x9f ~\xfe\xf3vy\xf9\xe9\xc9\xf3\xba\xf8\xe9z\xfe\xf3\xd5S\xbc\xc8\x9e\xcc\x1f\x7fs\x0fi\xe7 \xef\xa3\x1cWx\xcd\xac\xf8\xe8\xf9\xcd-\xd9l\xc9f\xbb}\xf1\xf8\xe6\xc5\xea\xf6\xe7\x9f_\\W\xcb\xc5\x8b\xa7\xd5\xf3\x9f^\xac\x9e-\x1e_?-\x1e\xaf\xd9\xde\xa5\xcc\x8b\xe0\x06\x99\x93\xa2\xdc\x84\xf6\x1dZ\xe3K\xb5\x13\xeb\xb3\xd9\xddo~\xf9\xec!\xeb\xac\xdf7\x1du\xf0\xf8\x98\x0ez~\xc37z\xc1\x95\x8d\x19'o\x1e~\xfb\xec\xd1\x93o\xdf\xbcx\xf4\xe4\xc5\x8b'/\x1e\xbdx\xfc\xe2\xd9\xdb\xb7O_?|\xf5\xe2\xd1\xc3o\xde>z\xfb\xf8\xe8\xcd\xf1\xc37O\xbey\xf5\xed7G\xc7\x0f\x9f?}z\xfc\xf8\xd17G\xaf\xdf>y\xfd\xf4\xc5\xf3g\xcf\x9d\xe3G\xc4\xda\x86\x1f}\xf2\xfc[\xf9\xc7\x91\x0b\xd5\x86\x1a\xa7\xf3\xa8Yz0\xaf.\xfa\xc9\x7f\xd6\xd9\xdc\x91\xd0\x88\x0d\xd3\xbbc\x1ew'K\xfc\xb6\xf1\x95\xde\x18\xe9\x8as-\x12b\x1c?]\xb1UWH\xcc7\xe4HS\xb2!\x9b0G\x80\xe6\xcb\x02\xd7\xbbjzS[4!_E\x9a*\x18C\xd6?\x1c\x7f<:\xf9\x8f7\x0f\x1f/\xe8\x9b\xd3\n\x7f\xfbC=;\xa3\xb7\xaf\x1f]\x7f3\xfbt\xfe\xc3\xb3g\x7f\xdf=z\xf2\xed\xcf\xff1{\x9b\xfd\xfd\xe6\xe9\xbf\x1d\xbd\xbd}u\xb2$\xcf\xfe\xfe\xeet\xf1\xd7\x93\xdd\xd5\xcf\xaf\xff\xf9\xfc\xc5\x0f\xb7\x9f\xbe\xa7\x9f\xde|\xfb\xe1\xd1\xc9u~\xbc\xfd\xb7\xfc\xe3\xec\xf9\x8f\x1f\xe6\xf5z\xbb\xfc\xc7w\xbdOnw33}\xd0\xd9\x97\xdc=\x89\xbfjl?o\x037\xb6)i]\xe1\xac,\x0eOw\xb3\xbf\x92\xdb\x0f$\xdb>~\xf6\xfc\xf2\x91\xe1-GT/\xfc{\xaf\xae~~\xf8\xf4\xc7U\xfd\xd7\x7f_}\xfb\xea\xe8\xe8\xc7\x9f\xd7'\xdf\xe2\xf3\x92\xfe\xe5\xf6a~\xf9\xf6\x7f\xff\xf5\xe4\xc7\xef\xff\xe3\xc9O\x7f\xfd\xa1*\xe9\xf7\xfd!,2z/\xc4d7\xb63|\xf9\xf0\xcb~\xff\"\x9fv\xa4\xc8Fw\xafVc\xa5m\x90Q\xdcD\x1b\xea7\xbb\x1dwCQ\xdbb>f\x8eb\xa7\xf6\xae=\x83[\xd5\xf3'\xcf\x9e\xea\x9a\xfex\xee\xfc\xa9`&\x90\xb9\xc0Nn:^\x98\xd3+\xe0\x0c\x85\x8b\xcc\xe4\xce\xd8\xd6i5\xdcF\xbd\xb4\xc5K2\x18\x14\x11\xaf\xf6h\xbdaornN\xe8KO\xd4\xfe\xa4\xbe\xa1\xfdw\xd2\x86\xe8\xba\x1e\x99\xae\xc2\xd8\x1dR{g\xb2\x10=\x1fM/F\xcfD\xbdb\xb4\xfe\x9a|\xe7&\xd1H\x19\xf8qB\\\xde\x8f\xc3\xff\xf1\x0c\xb1\x81\x7f\xa7\xbf3\xdak2z|B\xbc\xcbO\x88;d\xb3\x02r[\x02\xf9k&\xc4W?!N\xdfP\x88\xb7\xb6J\x02\xfcD!n\xf3\x08\x89\xffj\xcfs\x142\xf4\x1f\x858\xd5;<@\xaf\xf1}fw\xeaF\xbe\x92 q{\x9aB~c\x7fS\x88\xd5\xeb\x14\x12\xd0o}\xe6CJ\x8d\xa3O\x04X\x10\x8d\xf4I\x858\xf1f4\xa2\x04\x13\xbcT!>_UH@\xb1\x1c~\xab\x10\xbb\xf7*d\xca7\xfa\xfe\xac\x90\x91K\xd0\xc0\xc3\x15\xe2,\x9f\xcd\xdb\x0dx\xd5\xed\xf9\n1\xfb\xbfB\xc2\x95\xf7}a\xf9\xfe\xc0#\x96\x7f\x9f\xb6\xe4:\x06\xab\x7f\xa8:\xa6\x02o\x85\x91\x7f\x9c\xf54|\xa8\xe7\xe7\xd2\x7f\x19\x94}X\xd6\x8e\x87\x12\xe1\x1av\n\xdc\xf1<\x8c\x063\x1bi\xe0[X\x8caZ(m\x0d\x9ar\xa3c\xf5\nB{\xa9\xd9\x03\xb0\xaf\xfb\xa1z\xb55\xbe\xbb\xb2\x1b\x14\x18V\xda\x88&r\xc6\x93\\\x9b\xd5\xc1\x9a\xfc\x1b\xae\xc4\xc6\xf5\xd7\xda\x07\xec=\xc0\xbc\xc2:\x1b)v5\xb5\x8c\xed\xb0o\x8c\\/]\xab\xa4\xbfa\xbb\xab\x95y\x1d\x0c\xd5\xf2z]f\x97'o\x82g\xab\x98\xc8\x7f\x04\x00\xc1?\x86\xabz\xb0K\x0e\x1a\"\x86\xfc\\\xf1\xb6a\xd3\xd9\x94N\x87\x0e\x87\xbbg\xbf\xfd\"j\xc7\x8d\xfc=\xc1s\x12\x0e\xf0q\xdas\xe7\xa4>\xb7\xb1\x05\xc6\xb5\xda\xcd\x1e(Zf\x1cb\xa2\x86E\x9do\xec\xb8a\xef\x9d/\x1f?|\xf4\xcd\x83G\x8f\x1f|q\xf0\xf8\xdbo\xfe\xed\xe1\xa3\x97\xad\xdbQ\xec6\x17\x86\xf8\x87\xad \xaa]\xd6\x98\xd6\x173f9\x83\x15\x82\xba\xc5\x9e[\xb5\xf9x\xb7\xdf\xa2\x913\x9d9\xc7\xdc\xda\x8f\x91\xad/#K4(tJ\x8b\xb4\x80\x08\xfaE\xb4\xef\x93gz\x03g\x9c`u\xb1\xc7ie\x8ek\xbcO\xfd\xed\x0d\xca\xfb\xfc\nOH\xfdm>\x95\x95\x05%\x05\xdd\xed\xf5#x\xbb\xdd\xa7z\xde\xb7d\xa6\xe4>\xbfC\xae\xf29[|\xf7\xf9\x0d6g\x94\x94\x18\xee\x876~&\x94\x1d\x81\x86\xabG8S\x83\xc9\x15\xa9h\xe7\xb4\x91\x88\xa9\x99\xcf\xeb\xb1s\xf3#}\x9a\xc3\xdbm\xec\xfb\x0f\xd5R\x1c\xbc\x08\xaf\xb45\xdb\xf8\x8a\xf95d\\\xbfQP!\x87\xeb8\xb2D\xd6\xfd.\x8e\xee\xeav\xd7u\x14T\x96\xb0\xf5\x1d\x99\xd6x\x14T@\xbdA-\xeb=\x1a\xb7\x9c\xfe\x86+\xa0\x12\x83\x1f\x80\\\x85G\xde\xd0\x85\xf7\xdc\x19\x8b_\x80\\\xbe\x01\xb2Z\x07\xf9,\x84&Z\xc9\xe0+\xa0\xa0~\xf2\xe4Y\xbf\xa3\x18\xfd\x06\x14\xd4\xabG\x14\xdc\xe0C\xec\xed[\xd6E~o_t\xfb\x16{\xfb\xac\xcd\xcf\xd8\xdb\x07\x87>\xc7\xde>\xe5\xf0?\xf6\xf6M\x8b/\xb2\xb7\xef\xd9\xfd\x12\xe7'c\xfc\x134\xd5GA&?\x05\x8d[R\x0c>\x0b\xf2\xcd\x98f\xdf\x05\x99\xfc\x17\x14\xack*\xa9\xa0\xa3_\xf5\x9a\xe9\x9a\xb4yy\x94\xc7\x04k\x7f\xe7\xd5?\xd8\xda\xbf\xad\x88\xe8\x1b\xc6yb\xbf(B\xb3\xb6\x99\xa7*!\xce\xda\xb7\x1a\xf2bN\x06\xe4\x14\xef\xfb\xbaSm\xc0\xe3\xcc\xc4\x194QkU\xee\x8ai\x10\x9fA)\xdbG\xd0\x1ao\x0c\xb3W\x84\xe2\xe0\x8d\x85\xa6\xd7\xfa=\xebHh\xbe7<\xde\xc1<\xd9\x08q\x8eZ\xdf\xb8u\x0d0\xaf\x81\xd0\xc4A\xd6\x8aeB\x12\xe2\xa9 \n\xa8$rOQ\xf2\x01\xdfD%\xc49] q\xd9\x14\x85\xd9\x15%\xb1m\x00#\xc7\xdf\xfd-l\x99ov\xe7G\xdf<\xfd\x8f\xf5e\xf1\xe9\x1f\x7f?\xbe^~\xf3c\xf1\xfc\x87o\xdfo\xbey\xbb\xfb\xe7\xc3\xe3\xf7Og?]\xed~z^]\x7f\xffhs\xfe\xf1\xdf\xab\xb3\xdd\x0f?\xfc\xf3\xea\xd5\xabO\xe7/~\xfc\xe9\xdd\xf2\xf4\xe1\xd9\xab\xc3\xf37\xdb\xe7\xbb\xc3\x17\x8f_}\xaa\xfe\xb9\xf8\xdf\xff\xfea\xfb\xfa?\xbe\xfbN\x85=\xe2r<\xc4\x08\xe9\x9e>\x13\xb1\x9a\xf7C'\xd6\xd7\xed*\x905\x8c\x82|\xc6\xf6\x84S\x90c\xceuvZch\x05!Sx\x05\x05\x971n64\x86ZPp\xc1\xfbc\xcc\x11vA\xbe\xa9\xc2=I|&GC\x89c\x06\xf4\xce\x7f\xfe\xd9\xcf3\xf7\x05\xcd|\xdey\xcf=\xeby\xad\x88\x12X\xd2\x12\xb2A\xbe:\x9aC7\xc8\x1b\xbeA\xbe\x8aM\xad\x90%\x94\x83\xf6\xfd]g|\x05\xed\xfb\xeb\xfe\x10\x0f\xdaw\x11\\\xe1\x1e\xb4\xef\x8f\x9bC?h\xdf\x9f\xf5\x84\x81\xd0\xbe\xbf\xef\x08 \xa1}\x7f\xdb\x1d\x1eB\xbe\xcf\xc7\x86\x89\xd0p\xd5\x8f\x0f\x15![\xb8\x08\xf9V\x0d\xf7\x8aa \x1d!\x9f\x11\x10r\x85\x90\x90-\x8c\x84\xa2\xf4\xeaj!\x06\xd3y\xf5\x0f\x14\x83\xe9uA\xf0\xe4\xc1\x93\xd7\x04!\\\xbf\xf3\xdb\xce\xd1\xd6|\xdb|o\x81\x0b\xdcF\xfe^\x8b\x02z.\xf2\x0e\xe8 #\xa2\x04\x83\xba\x15'\xe8\x8d\xc2*\x8e\x02+\x8f\xfc\xd3\xa6|\xc8\xdf\x9cJ\xbcS\xa8\x10\x9f\xddQ\xb8\xedQ2\xfb\xffV\xc7I\xec\x11$\x7fC\xd6d\xc9/\x97\x90\xff*\xab3r\x8d+9\x8e\x06\x9dg\xd8M\x1c\xf3\xb9\xb1\xfa1\xaeq\xcf%\x8e>\xcd\x12\xf1s\x0d\xda\xea \xcb\x9a7\xf5$\"c\xca\xb6\xa3\xf1\x9bz\x0dS\xb5\xcdi\xda!\xbadzv\xd3\x8e\xe7l\xa4\x8a\xc6\xa4\xc1\xadY\xe9\xcf\xa3=\x99\xcb\xeb\x028\xaa\x1b\xd3}\x84\xa4\xe8DB\xfa]I\x88\xdd\x89\xb2\xb8P\x13>|\xf8\xf0\xd1\xdb\xe7\xdf>\xfcB\xbe\x15\x9b\xf3-\x14>\xf8~7\x93\xbf\xd9\xce\x15p\xabi\xbd\xe4\xe1Y\x02\x9e7\x1f\xa97;\x07\x89x^\xea\x9eJ\xb3\xc4\xf4\x02\xcf\x7f\xda\xd1zC\"\xceA~t\xf0XiX\x10\xb2\xe7I\xfa.\x8d,\xc4\x9d\xad\xcdn\x8d\xebA;\xf5\xef\xecj\xde\xed\xde\xd7h\xbf\xd7\xec\x98\xd6\xf9\x86\xf5\xfa%\xa6\xfcR\xacN\xefG_e\xb8(\xca\xba\xb9\xda5/PV\x16?\xed\n\xf1\xf3u\xde\xb9xH\x0d\xa1\x8b\xb2X\xdf~}\x0f\xa1s>\xea6yQ7'}\x07O\x10w\xd3\xa1\x1a\x9cs\xe2\xee\xb5\x1d[7\x9f\xcd\xca\x82nw\xb3G?g?\xcdwd\xfb\xe9\xe1\xd5\xee\xf1\xcf\xcb\xcb\xe5\xe5\xd3\x17d\x81\x1f\x16\x9f\xae\x7f.\xe6\xb8\xf8\xf4l\xf34\xfbf\x8b\x9f\xec\x9e\xe2\xed\xcfO\x97\x8f\xab\x17K\xba\xfd\xb4|\xbe|\x91\xd1'\x97/\xb2\x9d\xba\xfc\xfd\xaa\xac\xf3by\xb1-\xaf#&\x81G\xda\x98l\"\xbe\xdb*/\xab\xbc\x0e\xae`\xa3\xe5\x9c\xdc\xd4\xa7\\\x8bZ\xf5\x02\xdax+_0L\x81\xdd\x9b\x19\xc4uo\xae2\xe9\x1d\xc1\xf5\\\xf3I\xfe[\xd0\x93\xb4\xc6\xf5\xce\xdd\x11\x17y\xc1T\xe2\xf5\xfa\xf6b\xc2\xd9\xb8_\xde\x12\xfaew\xaa\xb0N\x14\xdal~\xf0\xb0\x11=\xfa\x80g\xb4\xc6\xb91\x0fj\x94\xbe/\x8b2]\xe1\x8a\xf2\x82\xcd\x1e\x17W\xa4\x0e;f\xdb\xa7\x94\xeef\x9b\xbc\xbe\xf0\x1eg\"`\xd19\xd9\x96t\x98\xb7\xf4\xc7^E\xe44Ak\\y\x0cu*\xe7\x83\x14#\xd90\xa8\x1c\xb3\xd4\x1b\xbda\x02>l\xbeM\xe1\x8f\xdd\x8e\xa1\xc6\x96\x9d\xbc\xf4\xad \x13\x16\xd1p\xa0\xee\x9cM\x8e\x91\x17k\xf5\xe6C\xcfRd\x9a\x15\x06s\xe0\x08\x1d\xddyo\x84\x02\xf3\\\x17\xa9\xe8\xc7R\xb9\x7f\x01\x86\xbb*k\x8f'\x10\xda\x87J\xf7\x92\x1a\xef\xd7\x95\xfc\xee\xed;\x1b1k\xb9\x0e\xdb\xdd\xec\xeeyz?\xe1|=\xbc`\xb0\xbb\x0d0\xfb+=\x87\x8a_\xb5\xee\x99=d,\xed\x82\xaep5\xdcq\x85\xba_A\x9e\xcf\xa6,\xf2\xcb\xc0\x93\xf1\xc4\xed\xe2\xb5\xf1\xb0\xc1\xc1\xc3\xd7dF\xf3:\xec$\x14u\xed\xe9EV\x165\xce\x8c\xc0\xf4\xe0%\xe3\x85\xb6\x86gge1\xbf0\x1f\xd1f\x9f\x03\xbe\xd4_\xce\x8b\xba\xc2\x17\xf5\x8d8q\x7f8\xbe\xfb\x97\x995z\x14\xba\xb0+\x98\x1e\xe6\x02\x8c-G\xab\xc1\xebgu6 /\xbey\xf8\xe0\xe1\xa3\x07\x0f\x1f\x9d?|\xf8\x92\xff\xdf?\x95J\x8e\xcf\xd2\xd1\x07\x0bU8\xb0q\x8d\xf5a\xb2\xc17\x17i\xb4d+\\,I\x02e\xbb\xed\x9cm\xa3G\x1d\xe1c\xb3u\x0bv\x04O\xd5\xed\x0c\x102W\xc7a!\x01s\xca\x0c\xaf\xb1!6\x15\xd4-\x0c.\x9b\xdfv}w\xcd~\x08\xae\xb3\x05\x84\xa3\xf6Q\x0d\x95\xd6\xf0Q\x17\xbe\xed\xd3\xf8\xa4\xa8\xab|\xdf14~+4^_\x0c\x9aQ\xd7f0d\xec\xf3YE\xb8u\x07\x93\x9a\xe7\xbdM^\x18F\xd8\xe0\x85\xa6\x1d\x8fu\xa3\x054\xa0\xb5\xfe\xe1]\xbd\xf3\x8c\xb5\x9e\x86g\x87u\xb3\xd5\xea\x8eM\x0b\xbf\xb1\xd1\xbaK\xa6\xcdj\xedSgd\xfe\xdb\xd9\x8bVY\xe4\x1bsZ\x07\xbd1n\xfc\xff_\x15Y\xbcD_\xfe\x9f\x87\xda\x95\xef\x87\xbaE\xbe\xecY\x88\x8d\x98\xf0\xfc\xf3\xa8\xa6\xcaJ6\xd9\xf2\xc7\xdd-\x86\xf6\xd0\xa9\xc4\xda\xc5\xacm}\xac\xd9\x17\xbd\xc9i}\xd2\xdc)\x1b`\x86;\xbe?\xa2d\xbd\xb8\xe0\xee\xe8o\x82\x96\xdf\xb5\xd0\xcb\x15\xbf\xf0\xca\xe6\xb1\xfeq\xeb~\xba\x9b\xad\xf3\xec\xaf$|8\xf3G\\}\xd7}c\xed\x87|Y\xe4\xc52j\xe8\x88\xc0f\xc0\xf2\xc8)\x93\x17\xe5bA\x89\xfbA\xb1\xdd\xbe\xd8\x15u>\xc0\xf2{\x0b.\xa5d.\xb2\xb1\xa8m\x83\xd6\xbcq\x8a+\xbc9\xe2\xbb\x85\xf0\xca\xedft\x8b\xc3\xa1Z\xd6 \xda\x1f\"\"\x19?\xe0\x9bf\xf6\xa2\xed\xc7#4|\xf9\xa5\xab\x89\x9bZ~\xd8m\xb7\xeb\x88\x0e\xf5\xe7\"T,\xcbr\xb9&\x07\xdb\xaa\xac\xcb\xd9nq\xf0\xaa\x880\xd5\xed\x96\\\xec*w\x97u\xc1\xc2\xaf\xd0\xc7\xb3\xbf\x1dV\x84\x96\xbb*S\x1c\x89\x15\xae\xd1\xae\xc8?\xed\xc8\xfaV\x06a\x169\xa1\xa8^\x11\xae\x1f\x95\x0b\xf6oM\x0d%U\x8e\xd7\xf9\xcfd~\xafk\xfd\xba\xcc\xca5\x9a\xed\x16\x0bR\xa1\x0d\xa1\x14/\xc9\x01:_\xe5T\x96\x11mv\xb4F<\x0e\x93\x17\x08\xd7hM0\xadu-eA\xd0\x17\x87_\xa0l\x85+\x9c\xd5\xa4b\xef\x13\x9eW\x80(YnHQ\xcb\x02\xb1\xba|I\xd1\x16\xd7+\xa1\xb6\"\xdb\x8aPRt\xf4\xb1\x07\x17\xbb\xf5\xfa\x16}\xda\xe15\xab\xd9\\\xd4[*\xe15\xfc\nS\x94\x17\xfak\xffbj\x0f\xfb\x8d\xf5fWq_\xe6__\x8bRqEtU\xee\xd6s4#\x88U e\xb8(\x8b<\xc3:\xcdjQV\x1b]\xfbW\xe4`yp\x9fU\x9e\xf9\xea\xe8\x8b\x83/PNQQ\xd6\x08g\x19\xd9\xd6d\xfe\xf5\xc1=\xfd\x85\x93\x02m\x999\xf2\x8c\xdcG5\xc1\x1b\x8avt\x87Y\xb5\x04\x17~\x9b\xaf\xd9\xf7\xeb\x92Wj\x96\x17\xb8\xbaEx\xbd\xe6\xf5\xa3\xbc\x91\xbbF\xb9\xd5\xd5\x93\x9b-\xc9j\x94\xd7\xa8.\xd1\x8e\xf2\x9a0=\xac\xa1\xc8\x0d7\xf8\xab\xe2\xf6\x00}_^\x93+R\xdd\xe7\x94\x82\x8fg\x7f\xa3\xe8z\x95g+\xf6JW\xbb\xae\x9cf+\xb2!\xe8_\xab\xba\xde\xfe\xeb\xbe\xf8_\xfa\xaf\xfb\xa8\xacPQ\xca_\xef\xf3v\xcfp!\x03\xd3\xbcf\x94\xd4h\xb7E\x98\xd7\xe1^\xb7\xff]\x91J\xf4\xdc\x0d\xdeR\xd1\x88\xbc\x9f2\x9b\xcbvc\xdd\x05\xd7\xdcB\xdb\xaa\x9c\xef2\x82p\x81HU\x95\xd5A\xb7\x04\xdb\xed:\xcf\xb0\xaccEX\x8b\x97\xd7d\xce\xcc\x90\xe1\x8c\x8d\x9b\xb2\xbc\xdcm\xe5EX\x14\xcd0%sY\xd8N\x11>\x9e\xfd\x8d\x7fo\x85\xaf\xd8\x94@6Z\xbf\x9a\x8b\x8e\x85U\xf1\xd8\xbf\xaf\xca|\x8ep\xd1e\x07\x8a\x8f\xf1\xa1Q\x91EY\x91\xfb\xea\x15\xa6 \xd7\xf9,_\xe7\xf5-*\x08\x99\xf3\xa6\x9a\x11\xc4\x87luE\xe6\x1dMe\x81D\xd4\x8d?\xc6\xfb\xf0\x01\xfa\xea#%*\x19\x8c\xd5\x915:\x1b\x81\xa2\xd5q\x81\x97\xdd:\xcd*\xc2\xd7J\xa5\xea\xe0k\xbd\xfd\xde\x955y\x89j67-$\xf1\x05\xf3\xd2\xc9\x91\x98\xed\xaa\x8a\x14\xf5\xfa\x16\xe1+\x9c\xaf\xf1l\xdd\x0c\x8br\xb1\xc8\xb3\x1c\xaf\x07\xb3\xdfl\xb7@\x15as\x1a\xb9\x8fp1g#J\xaa\xe3<\x1b6l\xda\xbe:#\xcb\xbc`\xde\x90 \xdc\xe8#\xe8vK\x0eD\xcf\xc1\xdb\x9c\x1ed\xe5\xa6;\x1f|\xe0\xfd\x95\xa2\xb2^\x89\x81P\xf4\xc7\x17\xfa\x8a}kE\x10\xd9l\xeb[\xd9\xc1\xbfF\x1b\xe6D\xa1Yg8\xf1\xa2\xb1\"\xa0\x9c-Ul\x8a\xe5]\n\xd1-\xc9\xf2E\x9e!J6\xb8\xa8\xf3\x8c\xaa\xee\xe7v\xf2\x84\x88^\xfc\x12\xcdn\xeb\x10\xca\xd2\x0fl\xd8\xcc\x08\xc2b\xe3\xab-2\x83\x95EN\xddxV^\x11U\xc8N\x07\xe2\xf6\xbbg\xff\xde\xbf^\x15\xb7\xffR\xcb\x10e\x83\x0bW\xb3\xbc\xaeXWu|W\xcd,x]\xaaF\x13\xfa\xb02'\x1b\xff|Z\x12\xdf\x9d\x0d\x97Q]\xbfZ!\x9b\xa6=U\x9dh\x9d\xcfxa\xe4lD\x11\xddm\xb7e\xc5\xe7\xe7-\xce.\x0fw\x05\xfb\x1f6+\x8b\xb6\xa0\xaao\xeaKM\xb9@\xbbZ\x0c9\xd5\xc59G\x12\xcf\xe7\xb9\xe8\xef\x0d\xb7\x8b\x15\xa6^\x95s\xaa\x8a\xc94\x0b3*m\xc7\xc2\x93A\x8f^\xa2S\xf6m\xd6\xbfe1pc\x9a\xbc@G\xff\xf6o\x9d\x89\xf2mY\xa2EY\xa2\xef\xd0\xc1\xc1\xc1\xff\xd4~`\x9f\xc0\xc5\xad\xfe'\\\xdc\x1e0\xe5o\xabr\xf3\xd5\xa2,\xbf\xd6\x7f<8\xd0g\xbf|\x81\xbeb\x8f\x7f\xe4E8/\xbf\xfa\x1f\xec\xf9\xaf\xd1/\x9d9\xa0\xfb\xce\xaf\xfd\xba<\xf6\xd4\xe5\xdf\xf1\x15\x8e\xaa\x0c\xfa\x8e\xaf\x94LS`\xf9s\xfa\xd5\xdb\xb2<\xc8\xd6\x98\xd2A\xf1\xc5\xa7\xd8c\xa2t\xda\xa3\xff\xd3T\xaf\xa6bO<\x15;\xbd\xadWe\xd1\xa9\x9a\xf8\xd6\xdb\xb2\xfc\xea\xe0\xe0\xe0\xebn\xa3\x88j}\xf5\xb5\xa1\xa9x5]\xb5d\x0f\x9e\x88J\xbe9\xfeptvrz\xfe\xfe\xec\xeb\xae\x0b\xdd6d_\x9dP\xd8\xaf\xdeSO\xf5\xfeR\xea5\xe3U{\xf9\x1d\xfa\x1f\xdb\xd9\xc1\xdb\xb2\xfc\xe5\xe0\xe0\xe0\xd7{\xdd\xaf\xdfg\xcb+{f+\x16\x9b\x1fpEWx\xcd*\xdd/P\xb7\x82}\xdd\x1d\xc5\xf9\xa2\xa7\xf6c\xb1i\x15\xf3\xcf\xf2N\xc2\x9f\xfa?\xbeCE\xbe\xeeu\x80\xfe\xd7\x9a\x96f\xee'\xaf\xb7\x1a\xb7\xcaqA\xb3\xdbv1R\xf3\xc8u\xbe^\xb3\x1f\xe6d\x81wk\xbe\x1a)E_\x1a\x16\x9bC\xe61\x1f\xf0\x1f\xd8\x02\xfb%\xf3\x9f\x9ay\x8c\xcdq\xcc\xee\xec\x0f\xc2\xf6JU3\x85\x14\xeb[\xeeF\x9a\x9c\xeff\xd9FxQ\x13\xb1Fq\xef\xfe\xcb\xc3/\x95\"9\x97\xa9\xcf \x7fS\xee\xa4\xd0\x17\x8b\xb2<\x98\xe1\x8a\x17\xf4\xe6\xf0\xf6\xe0\xe7/D\xfd\x84\xcf\xa5;\x8b\xfc3_\xb0'\xd84&\xff\xf8\xef\x1f\xde\xbfS\xff\xfe\xee\xbb\xef\xbe\xd3-\xca~k\xf7\x11b\x15,Y\x17\x96K\x86\xf0\xd4vT\xce\xeb\x15Y\xee\xd6\xb8R\x1a\x86/\xb2\x87\xe6\xa4\x9d\xf2\xef#\xb2\x99\x91\xf9\xbc\x9d\xfc\xef\x8b\x95\x177\xbb\x0fmr^\xf0\n\xfd\xeb\xffeU\xfa\x97t\xb5\x9bEK7\xd0\x81\x1a\x18/;. \xce.\xd9xh]\xd0E\xbe&\xfa\xbc\xa1F\xcc)\xa9hY\xf4\xba\x9e\xdc\xb1-\xf2\x8a\xd6\x17\xdc\x92\xdf\xa1G\xff\xd3\xf4\x08O\xfa\x96O<6\xcfK\x08\xf5\xb4\x7f\xc1k\xf5\xc5K\xf4\x85\xa9\xffu\x8b| \xca\xf7\xc5\xfd\xae\x06^\xb2wx\xc3\xb4\xfc?\xa2(\xff\xab\xf7\x08+Y\xef S\xf1N\x16\xd2U\xea\xb6\x8d\xb0oN\xd15Y\xaf\x1f\\\x16\xe5u\xc1{\xfe\nS\xb6\xd1\xdb\xd1\xba\xdct\xbaS\xb7\x03\xdc\x17\xae@\xafW\x88\xa1\xa8}\x8c5x\xb1DX4\xb7R\xf5/\xde\xd5T\xab\xaf\xca\xf5\\4\xb9\xf6U\xbe\xdf\x94\xbd\x05\xc9\x9d\x9f\xec,J\x0bW\xd9\xf4\x0e\xf4\x15\x1bG\xaar\x83\xad\x89\xda\xdd\xfe\xd7\x7f\xfe\xd7\xd7/\xa7\xb7\\Wi\xbf\xf1x\xf5\x98\x92G\x07\x8f\x1f=\xa6_t\x9a\x05\xa1e\xb5\xcd\x0e\x96\xb8&\xd7\xf8\xf6\xa0\xda\x15u\xbe!\x07\xc7l\x07\x14\x1c-!\xed\xd3\xc8\xec\xa3f\xe5\xdc\x031\xb4^l^\xd4OT\x96\xae\xb4\xa0S\xf7\x80?R\xef!\xb0U\x0f\x02B\xba\x1ac<\xca\xee\x80\x0bI\x14\"\x12b\x0e\x14 I\x13.\x122>h4Pe\x0c\" \x19\x19J\x122:\xa04\xd0\xd4\x04\x98\x06a%!\xd1\xc1%!\x13CL\x06k\xe1z\x10h\x1221\xdc4\xd0']\x8d\xe1\x87&\x86\x9e\x06\xfa\x86\xa1(\xf9\x9dd\x01)!\x13\xc2RJA\xb2\xe0\x94\x90\x91!\xaa\xa64\xc9\x02UB\x92\x84\xab\x84\xa4\x0bZ I\x12\xba\x12\xe2\x0e` \x19\x1f\xc6\x1a\xce\xa2\x86\xb0\x96\x90)\xc1\xad\x81\xb2~\xb0K\x88\xc1\x970\xcdR\xd3\x02_\x03u3\xc3`\x1e\x11\x0e\x13b\xbc\x81\xda\xb1\x14\x1b\x03dB|\xab\xf4\xc8`\xd9p\xe2R\xc13-d&\xc4U\x82\x14\xe1\xb3\x8eB\xb1\x05\xea6\xc5\xc4P\x9a\x90\xe9\x01\xb5\x8e\xba\xe1\x82;1\xc4\xd6\xd1Uw\xc2mB\xc6\x06\xdd\x84X\xa3UB\x0c\x018!\xce0\x9c\x90^\\\x82KXH\xce\xfe\xfe\xaf\xe6\xbaG\x07\xe9\x84\x84U\xde\x15\xb0\x13\xe2\xaa\xa93x'$0\x84'\xa4g\x81)\xe1A\x97\xddW\x1f\xa7\xd4\xeb\xb7\xa7Qk\xf0\xe1c\x15w\xba\x82\xa1\x8f\x85ta\xb9\x058;=\xea\xf5\xdd\x19..Y\xdf}C\x8ar\xf3\xb1\x888\xd4\xaa\x97\x87d\xacQ\xa7\xe8\xfc\x85\xd6}\x14\x85\x96.\xac\xee'.\xf3+R\xc8\xa7w\xff?{\xef\xde$Gn#\x88\xff\xefO\x81\xd3E\xac$\xbb\xbbd\xcd\xda\xbe\xfb\xe9N\x1b\xdb\xa3\xc7L\xdbz\xf4J\xadql8\xe6J\xac,VUZY\xc9\x9a|t\xab\xfd\xf8\xee\xbf \x99\xcc\xca\x07H\x82\x99Y\xed\xf1n\xe2\x0f[\xd3\x95\x04A\x10\x04A\x00\x04\xd3\xb8Pv\x1b\x94\xac\x10\xfb\xc7F\xbc\xf9\xd7\x83H\x91\xca\x9c\x8e\x84\x97\xc64\xd9\xd5\x92\xc1\xdb$SU,\x94\xc4=\xfd\xf5\xf1we\xdfHKIY\xc8\x0d\x0c\x19\x8b+\x87\x9f\xdc\xbf\x97z\x18\x85\x90[\x8f\xc8\xd6R\xa5\x0b\xe0\xd2@n\x8c\xb5f\xfe\xc3\\\x8f\xbb\x89\xf0i\xc5\x8a\xe7\xf0\xf4\xff\xd5\xdd\x1fq7?U\x06n\xe5#kv/6\x9a}G\xdbN\xddc\x96\x9a\xb7\xeeZ~\xf4P~\xd4\xac\xf1\xd1\xdd\xc5\xea\xfe\x9f\xc3\xef\xce\xa0\xd8\x95\xf93x\n\xb2\x95$\xef\xd7\xff\xefw\x9dibI\xcc\xf2\xe0;\xdc\xa8(\xe9\xea\x8a\x06\xa32\xfa \x89sEw%D\xe67#\xfa\x0dA\xea/\xa4\xbf\x99i?r\xa01\xe7L\xe2,\xa3\xa2\x1b\xb4c\x1ais \xc4\xa9\xdeN\xcb\x8a\x89\xd5\xd4\xc7\x91\xae_\xd4]hoy\xc1\xd6\xcc\xbc_NZg\xb4\xa2\x91\x8a\x98\xa5\xa4b\x18\xbf\xc9yZ\xa1\x17\x10}\xe1\xdfQz\xa1\x87\xad-\x80\x1a\xfa\xdaB\x03\xae34\xe0\x9aC\x83oD\xe3\xb5\x88\x86\x91\xba\x04\xe7t\xbf\x9b\x00\x0d\xa3a\xa4\x9e\xe9\xe1\xd3z\xc7\x92K\x11\xaas4\xf44\x8f\x06l=hp\x96\x82G\xe5z\x02\x8d\xa4\x01\xd7K\x1aFh'\x83\x9c\xa6\xa3Zcj\xe8\x92\xee\xc24#l\xeeY\xba&\xb3\x1e\\$bC\x80\x94\x8c\x10\x03\xa1\xb5\x92T\xdd\xf3N\xdf\xeaoZ\xd4\x1e\x1d\xfd@\xf2\x97#\x9b\x94T\x1a\x99i\xe0{\x0e\xbf\xaeEd\x1d\xe7\x87\x84\xf9\xae\x8a\xdb\xa7\xa5j\x0fq\xba\x96'\xfa\xca$\xcf\xcb\xed\x96\xe7\x05_W$\xaa\xc9\xa9\xc9\xec7\xafJU'\xb1\x1c\x1frn\xa9\xbb4[\x06A\x04\xaa\x16\xcc\xb5\x03\x05:\xecs\x9e\xae\x97<\x95\xe7\xe7\x9f\xd5#\x1d=\x92\x9a\xdfwk\x8ek\xa8\xcf\xa9\xbd_]\x1a\xfd#O\xd7\xaftg\xda\xa3%E\x1cje\xccZ\x1c\xaa\n\x1b\xc2\xa3\xdb\x1dW'x\xd6\x1f\"\xc4y[\xcdI\x04\xb2\xf5Q@u\xa8z\xe9\xe2}w\x10\xd8\xe0\x06\x84\x01\xa4\x94t\xc2\x00Fp\xf4\xf99I\xbe\xd5\xe5g\xc2\x0f\xb9U\xdd\x9a\x9f\x95}\x12T\x03\xc1\xa5\xa9_h\xa9\xd0\xccez\xe9\x99=\xb2\xa5\x84Y\xbaVYf\xaa\xe3\x8e\xcb\xf2\xdd\xfb\xebW\xcf\x94\xb3[\xff\\\x05\xb4c\x95\x97v\x99\x16U8\xb2\xf6\xe4\xb4b\x92\xfad\xd7\x96,\xf3\x00\x92\xd4\xe3?\x95q\xa6s$\xb6b+\x94\x8b\xe5\xa8\xf9\xdb5z\xaa\x892G\xcb\xfa\xbf\xc5F\xbb\xb6\x95g:Nk\x8f\xd1\x81m\xab\xe1=\xc31\x1e?\xe8\x08`\xfd\xe7\xca\xe1mN\xb1\x83\x1c\x19\xea\x1d\xdaV\x11\x10\xa0\x1c\xb6{~\xabj\x1b\xfc[\xd7\xb43\xf8\x0d_\xe4?+\x97(\xcbs\xed\xcb\xbdb[\xfe\x81\xffT\xf2\xbcX\xe8\xdf;H~\x92\xcbH5\x97\xe8$\x0b8\xecE^\x00W\x8eH\xe5\xb3lJ\x7f\xff=/\xef\x80zn\x89zH=kU\xa1W\xe3Q\xff\xd0\x8ft\xc8y6n\xe8\x86\xf7\xb4k\xb95\x87\xaa\xdf\xf8PH\xba6\xdc-\xcb!\xe7\xc5\x19Hs\xa2\xf2\xa1\xe7P\xa6Z\x10\xd6\xda\xd5y\x1bWe\x17\\\xbe\xbb\xbe\xee\xa18?\x1a\xcd*l\x1f\xae^\x18\"qw\x88jX5\x1a\xaa\xe6\xbaZ\x8e$\xc1\x88\xf2\xb2\xcc6\xb9\xf0\xa3]iM\xa0\xb2\xa6UX4u\xe5\x90\x90\xce\x94Q\xa4\xa3jb\xf5\xee\xb6DB\xd9\x99\xc6\x1e\x0b\x16\x8c}\xeb\xec\x8f6\xc2\x1bvG\xed\x9ft\x8b?\x00\x1cg \xc7\xcb\xb8\xbd\xbd\x17\x1c\xfb/\xd8\xf6`p\x9f\xa7\x80p\xb2\x86\x11\xfe\x02\x14\x19\xe2[<\x82\xcdo\x00\xe0\xf6\x1d\x80\xc7\x7f\x00\xc4\x91N\xe5G\x80a\xbe\x04\x14\x8f\xd3Wy\x84`\x9f\x02\x8c\xf4+\xa0\x08k\x9f\xa6\xc5\xb7\x00\x83\xfd\x0b`\xf71\x80c\x8di\xb0\xbe\xdc\xeb]\x1f\x93\xf9\x1c\xc0c\xcd\xc2\x14\xbe\x07\x08\xf6?\x00L\xec\x83\x80\x9e\x1f\x02\\\\v\xaf\xca1>\x89\x0e\xaa\x86\xd4\xfd\xba%Z=\xdf\x04\x90\xe9\xedM\xe1H?\x058}\x15\xee\xee\xc3}\x16\x80\xf9-\x9c\x9b=\xba\x19;\xb7\xfcf\xeb'\xad\xe6D\x93P\xb5\xc9G\x1b\x00'?\x01[L\x05\xa7$Y\xcc\x05\x972\xfby\xbd\x9fI\xd9R'6\x1f<\x06\x84\xdb\x84\xf0\x1b\x11~3\x82:\xea)M\x89\xe9\x8c \xb291\xd0\xa0\x18bR\xf8\x08%\x19\x15c\xcc\n\xa7a\xe13-\x9c\xc6\x05a\x0dMj`\xf8\xf6'\x98\xca\xc8\x18bf\x9c\xc0\xd0\xc0L\x0d'\xcf}kwB\x83\xc3arX\x8c\x0e:\xe5\xc8\xc4N`z\xf8\x8c\x0f7\x11\xc3\x0c\x10\xd4\x04\xe9u\xd5\x9a)\xb3\xa7\x1fo\xe3*\x0f\x87\xa2\x16\xe2T+p)\x95Jp*\xe7i\xc6\xb7q^\xf0\xac]\xe8O\xbdw4\xbbTg\x97\xea\xfd\xb9Tq\x836\xd0\x88\xce\x03\xad\xe8\x89r$\x03\xa4\x18\x0f\xa4\x81c;\xfd\xc7{\xc3,\x01\xcec;<\xc8 \xce@'\x10v\x9d)\x03\x9eP[\xdc\xdd\xa0'`\x81O\xfd\xb9+\xf8 \xce\xe1\xdb\x06>>\x10\xea\\E\x9d\x84\xcc&\xe6\xfe\x12R\xcaJ\x1aR_\x9f\xc8>\x9a\xc2\xad(@\x97\x8c\xaeC\xff~\x13\xbch\xf0\xb7GI\x8b\x06\x11[\x8b\xc0\xce\xb1\x08D(\xbaSF F\x986\xb4h\xc4\xb5\xdc\x1at\x93`\xb9\xc8\x1b\x0f\x1b\x80E\x0f\x8e\xf7C\xcc\x91x\x034q\x82\xa3Y\xa1'\xc8\x08M\xf5_\xf5\x95\xc88\xd5fk\xd7\x06\xb1\xc9\x05E\xf8\x1a\xcd*l\xbd\xed\xbc#\x85\x8d\x9d\x82,x\x1d\xa1@\xe6w\xaa\x84\x97Z,Fnh\xc7\x0dL\xa3k\xedZ\x9a\x1d9_(\xb5\xae\xf3\xabj\x13\x8e\xcc\x14\xff\xc3%\xa8am_\x05\x95E\xcd*\xe30\xe3E\x99\xa5\xfa \xa5\xe9\xab\x8e\x04\xb5\xf9\xadl\xeem\xeb8[oTn\xc3z\x01\xefS)\x9a\xa9r\x9d\xe9\x07k@d\x92\x84\x06\xb2\xe3Q5\xe7\x85\x11v\xc2\xeb6V\x0b\xdc>\xf6\x8a\x045\xfc\xb4\xdc\xf3,\x8e\xcc\xdf\xd4\xc1/b\xa9\xa4C_\x8c\xda\xf1\xd40\xabLk\xc3\xbci\x8f\\*T \xcf\xf3\xe3\xa8\xf5\xc5\xac2\x97\xdc\xf9\xc2],\xa8\x06\xde\xc0\xd7f\xc1\xe0\x1b\xec.;N!5K\xdev\n\xd1\xa7\xac\xa6dT\n\xa2LZ\xca]W\xa2:\xfe\xe1r\x03 \xdf\x14\xd5\xf53\xe5mH\x92\xba\xba\x8aZOZ\xe8t\x07\x92\x15\xab;\xe0,\xda\x01;\x1c\xcc\xb8\x1b\x87\x9b!\x0b\x1d\x9c\xe3o \x97\\P3/\xa0\xc8J\x0e\xdaM\xa9\x9d\x12\xf5u\xdcj\xd4\xea\xc3\xde|\xc5i\x94\x94\xeb\xd6\xbd:\x06\xad\x1b\xea]\x0e\xab}\xb3q\xca\x93j\xb6},\xfft\x99\xb7x\xda!X\x15\x8e\x91\xaa\x9aG\x85\x11\xd2\xa3TK\xc1]Tb\x19oS\x91U\x9f\xb4\x97\x7f\x13\xbd\xe6\x01b\xb1\xd4\xeb\xc6\\\xcc\xfd(\xf6Fy\xf5KM\xbc\x16\x02r\xb1\xe7\xcb\xdaXE\xcb\x994\x14`s\xd8\xcd\x8a&\xba\x82P\xd7'\xd0l\x18\x1b\x01\xad\xabu\xc4)l?\\\xbdP\xdb\xa7\xfc\xa2\"Y[\xec\xf5\xca\xacP\x1d\xfb]\xc0\xab\xaf\xcf\x1c\x8a:\xd0n\xea\xfbC\xe8\xea\x1a\xf3\x81\x8c\xf6\x7f\x04\xf8>\xd0\xd5F\xd35\x18\xe9A~\x0e\xabg\xe3\x88o\x84S\xa3#B\x0d\x9b\xc7&C\xd5'\xb5\x10\xdd\xeex\xc6\x1b\xee\x8dv\xd5\x89\x8e\xcc\xa9j4j\xffh\x8e\xaa^q\xed\xc5T\xf5\xd4[M\x19?pUI\xef[\x96\xd5,\xb3\xaf\xa7\n\x8d\x9a\xdf\xeeR\xaae\xfb\xe6\xe9BZ\xbfdi\xf6\x1bc\xf8\xf9\xb1\xf1 >\x0f#m\xf0\xe9\xaco\x8a\xdd]\xb3O\xe4E\xc6\"\x91J>~\xc7\x8bo\x13\x11}\xf9\xf6\xee{\x96\xef\x82\xf5\x84zeo\x19\xf7\xacX\xd2\xc9{\xc7\xf2\x1d\xe14\x0dv\x87\xeb\x81e\xc52\xe7\xc5r\xc7\xd9\x1a\x7f\xb3\x1eqc\xd9\x9dX\x88\xcb\x14jL\xb6\x00\xa6+x\xd9\x1f\"\xb8\x86 \x04\xdf\xf2\x15\xcb\x8a\x9c\x17\xdf\xab\x11\xff\xa2\xf3\xa3\x9a\xcb\xcb\x97\xcd\xd9\x1965\xd3\xf0\xb3*\x87\x80p@\x93\xab\x83\x10\x8aL\x15D\xb0pjP\x8c\xbd3\xf8&8\xf9\x0fnw\xb8\x06v8\x9c\x06\xb5\xcfk)uN\x9a\xf34/s\x88\xd8A/y}X6\x7f\xce\xca\xa42\x17\x0e\x99\x88x\x9e\xeb\xea_\x8a\x1f\x08\xbe\xca\"V?G;\x16\xa7gX\xb0W\x9b\x87:0\x9a4>\x06\xe5\x10\xd7\x01'E\x8b\xa9\x18\xa8\xa9\xb0\x14\x99W\x0c4uB\x1e\".S\xf5\x82\xa84]3\x96\xe6\xba\xf4\xd8\x9eE\xbb8\xe5\xdd\xf0\xa6\xa2\xa2\xa5\x81\x0c8\xa6\x02\x7f\x9f\x9c\xb80\xb1\x89\xc3^/'\xa2[\xb3\x82\x9f\xcb\xf6\x9d/T\x91\xbc\xbe~50be\xe0J |\x04\x83K9ip\xeac\x03N\xca\xc1K=\xd8\xf5t\xfd\xb3S_\x1b\xf0'\x9d\xb8X\x05\x14v\x81\x9fe\x1e\xbd\xde\xf9\xa8\xad\xdf\x0d(QQo!\x17\xcb)w\x1c8v,\xd1\xea\xf5\xac\xb5\xb5\\\xf6\x9do\xe5\x9f&\xee\xbe~O=\x9f\x18qw\\\x9bL\xc5\xe9\xb9\xd4K \xca\xe2P\x16\xc7\xbf\x1d2~\x83\xaaOu\xaa9\x19\x8d\xb5F\x9f\x18/;\x1c&\xc6\xa8\xe4\xaf\xb2\xed'F\xcdo\xe25O#>1\xdaz\xfe\x8f\xdb&b\x7fHE$r\x8e<\x00_c\x19\xd4\x7fk\x93\xd7\x0b\xbe\x15M\xab\xb7Su\x13\x0d\xaey\xba\xe6\xd9>N\x8bj\xf1i\xed\xda\x8a&\xb6\xee[\xc00k\xad\xf8j\x1d!\x9e\x88eM\xc2\xf2(F\xe7\xc4\xf8-\xa0\xeb\xaf\xb9\xf6i\x99R\xa7\xca\x98\xd0'\x1em6\xfc\xbbf\xd4\xe2{\xb5\xcf\xff\xea)Re\xdb\x9c\xbeTa\xbc$\x91\x83\x07u8f\x19\xd7zg\x01\xf0G\xfe0\xe3\xf0\xe72/\x80m3\xce\xa5\xfdc}\xe0B\xe7\x04\xaab\xb2h\x7f\xaa\x98\xe1\x9e\xb3\xb4\xa2^\x93xq8\xc8\x93\x17\xac\x05\xd7\x05\xb7*G\x9c\xec$\xe7\x92,4o\xfc\xa54\xbbZ5\x7f\x953v\xa3-&VU\xb5\xafp\xad[F^\x03\x9dY]\xa3E\x07G\x04\xe3\xe4\xc7j\"\xf8\x0c\x84u\xa9\x8dK\xbe\xbc\x11\x05_\xda\x89\xd3\xe05H\xfc=JP}1\xfb\xef\xa4\x8e\x80\xd8\x19\x18t\xce/\xbc+\xb1 <--9\xc9M8\x87\x8f\x97\xdf\xbd{\xf5r\xf9\xf6\xe3w\xcb\xeb\xff\xbcz\xb5\xfc\xf4\xee\x0f\xef\xde\xff\xf1\xdd\x80\x96W\x1f^\xfd\xf0\xfe\xfa\xd5\xb0\x96/\xde\xbf}{y=\xa8\xed\xfb\xab\xf7\x1f/\xdex\x9aV\xae\xfeg\x03\xc7\xebWcm\xf8\x18oS\xbe~\x9bo\xaf\xab\xca\xd0\xfa\xe1\"\x95\x91\xaa~j\x16\xcb\xc7\x15P\x1b\xea\x9d\x0dUF\x1d\xb0\xce\xcd3\xf8A\x14\xc8SQ$\x0c\x9a\xcf\xcf\xe0J\xed\xa3,q\xa3\xb1\x1d\xca\xda\x10 \xd0\x14\x03_C&\xca\x14MAj\x02\xedT\xa1\xa1\xd1u\xfd\x04\x1d\x0e\xf6\x13^\x1b\x88\xba\x03\x02\xf4\x07x\x0f8G\x08`;\xf8v\xf8.\x90N\x8dm\x08\xe0\x06\x04rD\x82\xe7|\xd9\x86\x10\xb90@\x17M\x03\xd4\x89\x82\xf0\xc9\x82\xd0 #\x9eY\xd1&\xf8 \xb6\xfb\xe9\x9e\xe7\x05\xdb[|l\x8d\x0f\xe9\x03\xf5\xb9[\xdaP\x1f\xea\xec\xa6\x7f\x1b\x06P\xe2e\xf5\x91\x888]\xf3\xaf4\x12hrH\xd7Oud\x81\xd6\xfd\x94\x1c\x08\xd9B\xe5.\xd5N\x82\x97\xa7vQ\xf0\xb3\xaad\xf0>\xd6%\x8c\xf5?\x95\xb1\xe6D\xa8N\xff\xc7\xb3\xbd\xa4\xd9\xbd\x8f6\xf6[\xdb'\xcaB\\\xcd\x16\"\xbd\xe5l!\x1ea\xb6\x10g\x0b\xd1\x05D\xdd\x01\x01\xfa\x03\x02\x0c\x8f\x00\xb6\x03}\x0f\xd00[\x88\x04\xa0N\x14\x84O\x16\x84N\xd8l!\xf6`\x00%^V\xcf\x16\"}\x0b\xfd\xa7\xb0\x10\x95ZY\xde\x88\"N\xb7Kus\xddo-z\x19JS%GY\xba\xdf~IK9\xb0G\xdf\x12\xa6\xca\xcdK\xe3H\x96\xc2\xf3\xaar#\x1f\xdd\xee\xc6\xb1\xac\xc345\x03\xad\xe8*3\xad\xb8\x15\x12\xc7&\x89#9\xcfJ\xd2,2\x91H\x83g\xa9\xaf\xd9.YQ\xb0\xe8\xcb}\xb9\xb3\x1b\x14.\x1d\xb94\x1a\x08}\x02\xb1_\xa8\x19E\xdc\xed\x89}C@\xff`I\x81\xc2!\x80\x00\x08$\x02\\IT8PS\xabp\x08\x1c\x0b\x0c\x18\x0f\xb8\x93\xb3p *\x80.\x18\x85`M\xe4\xc2\xc1\x9a\xde\x85\xc3}\x12GU]]\xa0\xa5\x8d\x91\xd1\xe1\xe9e\xd4\x93\xa7\x01O\xd2\x19\x0e\xd4T42B,e\xcd\x9f\xa0\x86\x035m\x0d\x07{2\x1b\x0e\xc1\x82G;A\x1b\x08FO\xdd\xf3\x9b\x80\xa7\xce\xe10\x82 \x9fI\xd0\x06O\xf2\x1d\x0e\xf7\xa4;C\xcey0\x8ci@7\xc1\xdb0\xe0\xa0n`\x00\xf7` \x07!\xf4\x00o \xe4\x00\xd5\x85\xf0\x95a t\xc2a\xf8\xa4\xc3\xd0\x89\x1ft\xe07\x10p\xf07\xe0Oy\xc4a\x00_\x06\xf0\x83\x9e4\x89\x83#\x95\x12\x87\xfb\x18\x967\xd1\x11\x87\xfb \xcd^\xa5\xc6\x0e\xd4\xccO2B[\x82}\x1fhy\xa38\xdc\x07;}\x99\xa78\xdc\x07e\xf6\xdcU\x1c\xee\x83&B\xf6+\x0e\xf7A\x9c'\x7f\x16\x87\xfb \x8c\x96\x81\x8b\x83?/\x17\x87\xd3\x8fk\xc8\xe9,$\x01\x98\x84\xd0\x96$\x8c\x83\xdeD),\x0c\xb4\xd0B-\xb3\x9f\xe1\xd9\x84\x14\xf530\xc48\xa4{\xd9\x0d\xcc\x87\x92\x80\xe5\xa8a>\x94X!|I\x18\x08\x9dp\x18>\xe90t\xe2\xef\xfbPr\xbc\x85M\xe5\x8c\xe6\x88\xbd\xccm\x1f\x9c\x85o\xfb0H\x80\x87\x89\xaf\xd1L\xcbM\xc2\xb6!\x0dG\x08\x06-#\xa9\x0d\xe7\xf0\xed\x9b\xf7/\xfe\xb0\xbc|\xb9|\xfd\xe6\xe2;b\xb6N\x17\xbaX.\xbe\xfd\xf8\xea\x9d?\xd9\xa8\x0d]$\xc4\x8c\xa56t\x91\xbc\xbb\xf4%.\xb5\xa1Nc\x1a\xcf\x96\xf0S\x98\x06\xbd\xc8\xd6\xaf\x13\xb6m\xd4\xd2\xd5\xd5\x0f\xbeM\"\xf1\xe5\xf2e\x90_YC\xbd\x1c!\xd6\xd1Y_\x83#\x04G\xf7\xdb0X\x9e\x07\xab9B\x0c\xb5\x0f\xa3\xc9\x0cs\xaaj \xa7\x0b\xb4a4\xadA,\x1db\xc7kx\xa1\xcc\xe9\x8f\xf1Vg\xe8I\xdb\xc3\x84\x14T\x06\x82\xb9\x92\x15\x802N\x81Ux\xfd\xe6\xfc0\xda5\xf6\xf6\x85\xb2:\xba\xadn\xab\xd9\x0b\x08\xf4\xe1\x96\xe5\xd5\xb1\xa2\xd0\xb7\xf2\x98\xb9\x9dvtz\xb8Gr\\\x7f\xad\xcai8\x04\xecq!;\xdb\x91V\xff\xb7\xa1;y\xc0.\x1e0:\x0d!c\xd4\x10\xac\xe3\x06-\xc6\x01\x0b\xf1P\xae\xfaU\xb9]\x10\xcc,\x18\xc40 |\xfd\xcdo\x7f\xfb\xf4\xff\x0bi2\x90q0\x8cy\xa0\x8a8F\x87o~\xfb\xbb/O\x7f\xced\x0e\xb1\x1a\xae\xcaU\x12G\x7f\xe0w-\xbf\xc9\x17~\xd7\xa9H\x17\x80\xb2\xcc\xb9\xae\xdd\xf4\xbe\xaa\x8f\x04?\xd4\x1a\x80\x88\x86\x9a\xb8\xd5\x86A\xdc\x1err\xab\xfdf\x87,\x16Y\\\x04/\xac\x93\xd2h\xa8\xa3\x10\x15\xb8\xceCWx\xa0B\x1c\xc0\x9c\xe0\x85\x12\xa8\n\x03\x19\x04\x03\x98\x04\xc3\x94\xe0\x00f\xc1\x10\x86\xc1P\xf5w\x7f\x04\x86+\xbe\xc9\xd5\xdeh\xa57D\xe5\x0d\xe0p\x98*\x811\xca\xee\xe4\xd4\x85%\xf9\xd6\xad\xc2\xc8\xa2\x91$\xadt\x91.\xfd\xaewb\xef\xb4^Ww\x7fai\x11\xa7|I\xb3\xb1i\xb65\xc1\xa6&kE\xba.$o\x15D\x0ej\x08P&\xe4\x8d\x81\x7f\x1d\xd5u\xf4Fn\x17/\xd4\xad\x84\x0bu)\xc1w7B\xbb\x7f\xac\xf8\x1a\xb7hXQ\xf0\xfdA\xdd\x8b(\x04\xec\xe3<\xe1l\xad\x9e\xe7\xdb\xee\x8a\xea\xc1\xb1\xa6\xef\xa8\x91\x08\xd6f\x94U\xdd\xd9U\xdb\xe4e!-\xf1c\x8d\x8fPO\xb6\x17\x13\x9e\xebA\xa20\xd7\x83l\x81+\x0e\xe9\xb2\xa5NU\x8f\x8b\x14\x19$0\xcf\x1d\xed\x0b\x8d\xeb\x05F\xf0\x02cu\xf4\xa8\xdc\xa0\xf8[k\xfe\xbd\x813Z(\x8c\x1c\xf4\"L\x15A\xca=\xdb[@'\xeem\xcd\x1bp\n\xe8\xc92\x9c\xd6\xbeI\x8d\x00\xd9\xe3:\xeem\x98\x1c\xab\xb1\xc4a:\xe8\x90\xa8\x0c\xde?^*\x9e\xf2\xe4R\xbbe\x85\xee\xc3\xd5\x8b\xde\xab_\xf6\xe2\xf4jg\x9e\xcb\xd3\xcf\xe5\xe9\x15L\xc4\xcf\xb9<}\x0f<\xa8\xfd\x07\x04\xda=C\x98\xcb\xd3;\xa6b\xf2s\xc8\\\x9e^\xc1|\x1c\xe9\x03\xc1P\x1b{\x1c\xf1\xdf\xd5\"I\"J!\xfd\xa6\xd5\\\x9e~Z\x1a}\x97\x84\x86\xe2\x9d\xcb\xd3\x03\xd0.\xc7\xf8\xaf\xc1\x0c\xeb\x7f.O\xef\x98\x18\xbf\x054\x97\xa7\x9f\xcb\xd3;\x0d\x84\xb9<}\xfb\x1b\x9f\x89\xa2\x81\x96\xea?\x17\x1f\xa5\x8d\xd7\xaf\xc6\xda0\x17\x1f\xf5\xe7H@\x98@S\x0c|\x0d\xa4k\x88\xb4S\x85\x06W\x88\xa9\x0d\xd4\xeb\x86D\xdd\x01\x01\xfa\x03\xbc\x07\x9c#\x04\xb0\x1d|;|\x17H\xa7\xc66\x04p\x03\x029\"!\xe8\x9a`\x88\\\x18\xa0\x8b\xa6\x01\xeaDA\xf8dA\xe8\x84\x11\xcf\xach\x13\xcau?o\xe8\xa2\xfe\x90>P\x9f\xbb\xa5\x0d\xe4H\x8d\x81\x01\x94xY=\x17\x1f\xa5o\xa1\xff\x14\xc5G\xe7\xf2\xf4\xa1-g\x0b\xf1\x08\xb3\x858[\x88. \xea\x0e\x08\xd0\x1f\x10`x\x04\xb0\x1d\xe8{\x80\x86\xd9B$\x00u\xa2 |\xb2 t\xc2f\x0b\xb1\x07\x03(\xf1\xb2z\xb6\x10\xe9[\xe8?\x85\x85\xf8\x0fL\x87\x9e\xcb\xd3\xf7a.O?\x97\xa7\xf7}\x17D\x00\x04\x12\x01syz\x0dD\x05\xd0\x05\xa3\x10\x82*\xc0\xcf\xe5\xe9\xfd0\x97\xa7\xc7\x81\x9a\xb6\x86\xc3\\\x9e\xde\x0d#\x08\xf2\x99\x04m\x98\xcb\xd3SM\xf06\x0c8\xa8\x1b\x18\xc0=\x18\xc8A\x08=\xc0\x1b\x089@u!|e\x18\x08\x9dp\x18>\xe90t\xe2\x07\x1d\xf8\x0d\x04\x1c\xfc\x0d\xf8S\x1eq\x18\xc0\x97\x01\xfc\xa0'M\xe20\x97\xa7\x0f#-\xec\x1a\xb8\x06j\xe6'\x19!\xbd|\x1b-o\x14\x87\xfb`\xa7/\xf3\x14\x87\xfb\xa0l.O\x1fH\xdc\\\x9e\xbe\x01\xa7\x1f\xd7\x90\xd3YH\x020 \xe1\\\x9e\x1e\x87p\x0b\x8c\x14\xf530\xc48\xa4{\xd9\x0d\xcc\x87\x92\x80\xe5\xa8a>\x94X!|I\x18\x08\x9dp\x18>\xe90t\xe2\xef\xfbP2\x97\xa7\xf7\x16\xa1\xc0a\xb0`\xd02\x92\xda\x10Z\xc6\x02\x87\xc0\xe2\x168\x04\x96\xbc\xc0\x81^\x08\x03\x87A\xe51p\x08?\x85i V\xd9\x08\xc4J\xaa\xc9\x81Cpt\xbf\x0d\x83\xe5y\xb0\x9a#\xc4P\xfb0\x9a\xcc0\xa7\xaa\x06r\xba@\x1bF\xd3\x1a\xc4\xd2!v\xbc\x06jq\x92\x00\x94syz\xd7\xa7A{\\\xc8\xceF+\x9di l'\x0f\xd8\xc5\x03F\xa7!d\x8c\x1a\x82u\xdc\xa0\xc58`!\x92Ko\x1a\x08f\x16\x0cb\x18\x84\x96\xe440\x88q0\x8cy\x10^\xaa\xd3\xc0\xfd\x929\xc4j\xa0\x96\xf2\x0c@9\xbaRshiO\x03\x83\xb8=\xe4\xe4v\x08/\xf9i\xe0\x1eh<\xcc\xe5\xe9\x1d\x10\xa8\n\x03\x19\x04\x03\x98\x04\xc3\x94\xe0\x00f\xc1\x10\x86\xc1P\xf5w\x7f\x04\x86+\xbe\xc9\xd5\xdeh\xa57D\xe5\x0d\xe0p\x98*\x811\xca\xee\xe4\xd4\x85%\xf9\xd6\xad\xc2\xc8\xa2\x914\x97\xa7\xc7\x81\xae\x0b\xc9[\x05\x91\x83\x1a\x02\x94 yc \x0f\x1e\x82\x18\x00\xa1\xdb@\x10# \x8c\x19\x10\xae\xf4OKN\x88\x8a\xa7*\xf7\xb9<=\x0e'\xa0%LU\x13 vM\xf1\xe9\x05\xf6\xe8\xf3\xd7Q]Gsy\xfa#\xb8fs.OO\x88\xbcz\xf7%\xff^4\xd7\x83l\xc1\\\x9e\x9e\x12\xc0\n\x8c\xe0\x05\xc6\xea\xe8Q\xb9A\xf1\xb7\xb9<=y[\xf3\x06\x9c\x02z\xb2\x0c\xe7\xbf[y\xfaV\xb1xg\x81\xfa\xaam\xafL\xbd\xc2\x10R\xa2\xfe\x83N\xb0\x1c\\\xa9\xbe\xbb\xb7\xa3\x93\x8em\x01\xc5\xd7\xdcdwv[\xb7\xb5hO{Z\xb4\xa6M[Fb\xdd\x13Q\xd7\xcee\xdf\xaf\xfa\xd5@\x9dBn\x15\xeeD\xf4\xb4\xb5\x15M\x9cn\x04\xf9\xe3-\xcb\x97\xb7,-x\xcf\x90!\x90\xd9\x1f\xafDW\xe6\x13!\xe37<-z\xaa\xcf\xbemZ6\xcd\x11\xf6\x98j\x8a\xfc\xdd\xab\xa9XQd\xf1\xaa,l\xfb\xb0k\xef\x07\x9f\x07\xc5k\xa6\xf9\x86\xa5\xc1\xe3\xaa \xe8b\xf0\xebc\x0d7,)\x9dY\x06Sv\xe6-\xc0\xa0;[ \x91p\x96Rzs~I=\xa9\xbd\xba\xd1g4-\x17zG\xca\xe3t\x9b(\xc7\xc2\xb9b\x11\x1cX\x9c\x9d\x01\xcbs\x11\xc5\xacp\xe4&(\x97\x02K\xf5\x1a\xe9G\xf0\xfdD)r\x80%\x89\xb8\xcd\x9bW,a\xcdox\"\xa5'\x97\xc7>u\xd3}\x07l\xbdV\x97(Y\x82\xa0\x92\nGrJ\xb6.\x04vC\xd3\xec\x11\xdf\xf2m\x9c\xaaM\xe4\xac\xfe\xdb\xabt\xdd\xf9\xcb\x8b\x1d\x8f\xbe\\\x7f\x05\x96b\xe37_\xbd\xe4I|\xc3\xb3\xeb\xafh\xcd\xa47\xac\xe0\xd9Y\xbb\x06\xef\x9e\xdd\xc1\x8a\xc3O%\xcfb\xbe\x86R\xdd\x97\xd5\xc5}\xb5\xaai\xf3Q\xee\x02\xf9\x81\xf5\xaf\xf7#\xc2\x9a\xf1|\xb9\x92\x83\xeb^\xd0G\xd7*\xbe:1ug\xd3\x13\xa8~p\xe8\x05\x97>\xb0)9\xe7\x9at+8\xb7zs(7\xafj\xf3+6\xa7Z#\xe9\x19\x82\x96\xf1(\xb4\xa9\xba\xf1\xa82\x9a\"\xa3\xa81\xbf\xbe\x80\xa1*L\xa9*\x0bB\x9b\x02\xf3\x913\x99\xf2\xf2\xa9\xae\xe9\x14\x17Em\x8dRZR\x05\xf1t=B\x01\x1dO\x9d\xe5A\x1e\xe4\xfe\x01\xba\xc8\x11B\xf1\xa8\x06\x9fb\xf0\x04F\x08+\xd6\xbb^\xbd\xe1\x8e\xf1\x9d\xb8\x83\x18!a\x8bvP\x02E\xe7\x08TX\x1d\xf0\x9e!\xba<{\xd5\xd8\xea^?)!l|t\xbc\x0cy`\x19\xdb\xbb\xa44\xc8\xd9l)\x812\xe2\xdc\xb0g_\x97r\x06\x9d\xbb\x1c\xc1\x99kw\x80V\xccz\xf8N\x14\xfc\x19\xec\xcb\xbc\x90Zb\x9bq\xa9B\xa0\xd8\xb1\x14~\xfd\xd0B\xd9\x96\xfd\xa3\xe8\x12\x19\xf0\x9fJ\x96H\xe5|\xfe\xb4O_K\xef+\xe5z%g:?\xbaX\x92x\x1f\x17y\xf5\xf4C\xe5\\\xc9\xe3\xbf\xf4\xaaz\xf8\x9eA\x18<\xadl\xcb\x97i\xb9\xd7j\xf6t|\xf4\xed\x80\x1a\xde\xb2\xaf\xc0\xb6*\xb2c\x06|\x06q\xaa\xf9\x92/~a\xab\x96r-y\xa7\xca\x12IJ\xca\x84)\xad\x10\xb1$*\x13\xa6#>\xbb8\x878\x7f&\xbb\xb8\xd8\xf2\x97e\xa66I\x0b\xbe'\xf0Wv\xc33I\x8a\xceM\xb6|W\xc4{\xfew,\xdf\xd8pv]\xf53\x90\xaf\xe3\xb8&\xa9\xb3\xf3\xec\xb2\x80|'\xcad\x0d\x91\xc8\xb4\x87m]\x1f\xc3\xd8\xe1\xf00\x87\x07e\xba\x12\xa9*\x88s\xe0Y,\xd6\x0f\xc0\x9a\x00$\x8a\x1d\xcf \x8f\xf7q\xc2\xac\xd5\xea\xf6<\xda\xb14\xce\xf7j~v,]'\x12\xf9\x9f\xde\x89b\x17\xa7\xdb\xf3\x8b\xe2\xfcc\xc1\xbep[{]\xa7,\xff\xf1\xd1\xae(\x0e\xf9\xb3'O\xb6q\xb1+W\x8bH\xec\x9fpI\x00/\xf7On\xe3/\xb1\xfe\x9f\xabL\x88\xcd\xb9\xd8h\xa4\xe7\xaf/\xfe\xe3\x7f\xde\xeeXq\x1e\xe7\xe7\xc5\x8e\x9f\xa7U\xaf\xac8\xcf\xd5\x07\x87L\xac\x12\xbe?g\xe9\xfa|'n\xcf#\x96\x9e\xc7\xc5\xf9\x8a\x9fo\xe2\xaf|\xfd\xd86\xd3\xf7\xa2\x1a\xad\xd3\xaf^\x7f\xc9y\xa1w\xc7=\xfb\x1a\xef\xcb\xbdR\"\xca9,\n\x96\x1c\xbd\xb8r1Ij\x95;\xd7\x820b\xa9TrG\xff\xaer'W\x86\xb1~[\xc6:A\xe9\xdaH\xd5\x86%\x89\xc4\xb1\x11Y\xc1V\xc9\x1d\x94\xe9\x9ag\x86\xc6J\xd5)Z\xac\xd8^\xea\xf8\x854\xcc\x9f\xfe\xfa7\xff\xfb\xb7\xff\xebwR\xe3>}\xfb\xad[\xd1Z\xfc\x03\x9a\x03\x95\x02^\xf3B\xdd{\xe6\xb0\x13\xb7p\xcb\xb50\xf2fp\x19\x9d\xecd\xc3Y\xce\xd2\xa8\xa7\xa0kcsR\x0d]\xd9\x8fK\x89\xe2t\xae7\x8bx\xfa\x99Z\xdb6\x15W3.QE\x85.q\xa1\xac7i\xae\xa9n\xf2f,>B\xcfme\xce\x1d\xef)\x959\xcf\xe1\xe2\xdb\x17\x97\x12\xb3\xc4\x9a\xb2}\x9cn\xcf\xd4\xdbF\x17\xfb8\x15\xf2/\xfdz\x87\xf6\xa7B\x87\xcf\x0b;\x1c\x96\xce\xeay\xe4uOy\xad\xf3\x07\xddS\xd7v\x90LV\xfch\x9e\x18+\xaa\xd0\xa7\x9d\xfe\xd6\x0f\xf8T\x16h\x17\xb5^\xbb\xd5\x8f\xe7\x19O\xf8\x0dK\x0bPv\xaa\\9]\x0bZ\x05\x87*\xbd\xc1\xd6\x7f.\xf3*,\xa4\xca\x9f\xac\xa2X\x92\xd8h2\xbb\x86\xbc\xe7?\x9f\x04\xc2\xec\x1a\xea\xc3\xec\x1a\xfao\xe0\x1ar\xc7\x90-\xd1\xdc\xf0Pr\x07\x111\xa2,\xc7\x95\xd7\x08\xc2\x02\xc9\xfd\x14,TG\xe0z\xa1\x9f?d]\x99\x96\xd58?y\xde\xf9q~\xf2\xbc\x06GU]\xef\x06\xe0\xb1t\xe6'\xcf\x93\xf9\xc9\xf3v\xc3\xf9\xc9s\xf0\xe9c\x03\x13X\x91s\x8ak\x0b\xfc\xf5?I\x92\x88RH\xaf\xde9?y>-\x8d\xbe\xc2\x93C\xf1\xceO\x9e\x03\xd0\n.\x1e\xbc\xa5\x15\x87\xf5??y\xee\x98\x18\xbf\x054?y>?y\xee4\x10\xe6'\xcf\xdb\xdf\xf8L\x14\x0d\xb4\xf2q\xf3\x83\x96\xb4\xf1\xfa\xd5X\x1b\xe6\x07-\xfd\xf7\xee!L\xa0)\x06\xbe\x06Ri[\xda\xa9BC\xa3\xeb\xf9AK\xdf\xc7\xa4Sc\x1b\x02\xb8\x01\x81\x1c\x91\x10Tz6D.\x0c\xd0E\xd3\x00u\xa2 |\xb2 t\xc2\x88gV\xb4 \xa5\x84\xac\xf7:\\\xfd!}\xa0>wK\x1b\xc8\xb7\xff\x0c\x0c\xa0\xc4\xcb\xea\xf9AK\xfa\x16\xfaO\xf1\xa0\xe5\xfc\xe4yh\xcb\xd9B<\xc2l!\xce\x16\xa2\x0b\x88\xba\x03\x02\xf4\x07\x04\x18\x1e\x01l\x07\xfa\x1e\xa0a\xb6\x10 @\x9d(\x08\x9f,\x08\x9d\xb0\xd9B\xec\xc1\x00J\xbc\xac\x9e-D\xfa\x16\xfaOa!\xfe\x03Kl\xcdO\x9e\xf7a~\xf2|~\xf2\xdc\xf7]\x10\x01\x10H\x04\xccO\x9ek *\x80.\x18\x85\x10\xf4\xaa\xf8\xfc\xe4\xb9\x1f\xe6'\xcfq\xa0\xa6\xad\xe10?y\xee\x86\x11\x04\xf9L\x826\xccO\x9eSM\xf06\x0c8\xa8\x1b\x18\xc0=\x18\xc8A\x08=\xc0\x1b\x089@u!|e\x18\x08\x9dp\x18>\xe90t\xe2\x07\x1d\xf8\x0d\x04\x1c\xfc\x0d\xf8S\x1eq\x18\xc0\x97\x01\xfc\xa0'M\xe20?y\x1eF\x9a\xff\xc6q\x1f\xa8\x99\x9fd\x84\xb6\x04\xfb>\xd0\xf2Fq\xb8\x0fv\xfa2Oq\xb8\x0f\xca\xe6'\xcf\x03\x89\x9b\x9f\x94\x04,G\x0d\xf3\xa1\xc4\n\xe1K\xc2@\xe8\x84\xc3\xf0I\x87\xa1\x13\x7f\xdf\x87\x92\xf9\xc9s\xef\xc3\x068\x0c\x16\x0cZFR\x1bB\x9fF\xc0!\xf0\xc1\x04\x1c\x02\x9fQ\xc0\x81\xfe\xb8\x02\x0e\x83\x9e\\\xc0!\xfc\x14\xa6\x81\xf8rC V\xd2;\x0f8\x04G\xf7\xdb0X\x9e\x07\xab9B\x0c\xb5\x0f\xa3\xc9\x0cs\xaaj \xa7\x0b\xb4a4\xadA,\x1db\xc7k\xa0>x\x11\x80r~\xf2\xdc\xf5i\xd0\x1e\x17\xb2\xb3\xd1\x9ec4\x10\xb6\x93\x07\xec\xe2\x01\xa3\xd3\x102F\x0d\xc1:n\xd0b\x1c\xb0\x10\xc9\xcf9\x1a\x08f\x16\x0cb\x18\xf8\xab\x19\xe30\x88q0\x8cy@\xa9\x87\x8c\xc3\xfd\x929\xc4j\xa0\xd6Y\x0e@9\xfa\xf5\xdf\xd0\xe7\"\x0d\x0c\xe2\xf6\x90\x93\xdb!\xfc\x19I\x03\xf7@\xe3a~\xf2\xdc\x01\x81\xaa0\x90A0\x80I0L \x0e`\x16\x0ca\x18\x0cU\x7f\xf7G`\xb8\xe2\x9b\\\xed\x8dVzCT\xde\x00\x0e\x87\xa9\x12\x18\xa3\xecNN]X\x92o\xdd*\x8c,\x1aI\xf3\x93\xe78\xd0u!y\xab rPC\x802!o\x0c\xe4\xc1C\x10\x03 t\x1b\x08b\x04\x841\x03\xc2\x95\xfei\xc9 Q\xf1T\xe5>?y\x8e\xc3 h S\xd5D\x02\x88]S|z\x81=\xfa\xfcuT\xd7\xd1\xfc\xe4\xf9\x11\\\xb39?yN\x88\xbcz\xf7%\xff^4\xd7\x83l\xc1\xfc\xe49%\x80\x15\x18\xc1\x0b\x8c\xd5\xd1\xa3r\x83\xe2o\xad\xf9\xf7\x06\xceh\xa10r\xd0\x8b0U\x04)\x9f\x9f<\xff\xa7{\xf2\x1c)\x15\xef\xacR\x7f\xacO\xdfhY\xa1\x0b)N_\x1b\xaf\x1fy\xf8c\xe7Z\xfb\x0c~\xf2\x1c;\xa2bJt\xec\x8b\xe7\x965g\x15N\xcb\xb9\xcf\xa1\xaa]jZ6[\x96\x19\xba\x89z\xd6\x07\xc5h\xbc\x80O\x1f\xde<\xc9x.\xca,\xe2\xea\xd1\x1b-\xaae\x1a\xffT\xf2\xe4\x0e\xa4\xfc\x16\xf1&\xaeN=EU\xd9\xc4\x16\xf5\xcfy\x16\xb3$\xfe\x0b_\xe3w\xb3\x0e\x99(D$\x12X\x95\x9b\x0d\xcfLi\x94E\xf5\xf4\x94\x1a\x8b~\x1b\xafZG\xc0\nH8\xcb\x0b\x1c\x9fH9\xe2\x8b\xed\xe2L\xb2P]\xcd{\xb0x 5\x83\xaa\xae\x1aE\xfcP\xa8\xb7\xc8\xf0\xa6\x97)\x1c$S\xe3\x88\x9fA\xc1\xd9>\x872/\x99\x1c\xbe\xbe\x99\x7f\x88\x13I]!t\x11\xd38e\xd9\x1d\xb0\x04{\x08[KkUa\xb5\xd8\xf1;\xbcK\xfe\xf5\xc0\xa3\x02\xe2B\x1e2\xca\xdc\x94\xccQ\xc2\xc0\xbf\xaa\xa9\xbcH\xef\x16\xf0\xbd\xb8\xe57<;S\n\xed\xd3\x877\xf8\xe1Y\xef\xb7\x12\x8d\x14W\\^\xa3\x1d\xdfs\xf8\xbc+\x8a\xc3\xe73\xfd\xff\xf9gUo \x15\xd5\xafgJ\xca\"\x96\x828\xe8\x17Q\x92;Dak(\x0fU\xfd\x1fK\x7f<\xbb\xd1\xafP\x16\xb0g\x87\\\x8b\x8c\x1c\x81:VU\x85\x82\x94\x9f!\xd6\xb5b\x19>\xb6\x8dP\xef\xb8<\xb3\xcc\xdd/\xe1rs\x1c\x81\x9c\xf2C&\xe4f\xb4\xae\x07\xa9\xb6\xc1\xbcQt\xed\xd8\x8d\x12\xab}c-\xac\xf5b`f\x18\xf2\xdf7\"^\x03Km\x0eRM\x94Z\xf6\x19\xdf\x88\x8c\x9f\x99\xc6\x12'+\xe2U\x9c\xc4\xc5\x1d\xa4\x9c\xaf\x95\x88\xac\xd4\xed\x17%F\xb6\\\x15\x91Ju\x98n\xb9j\xa0\xd6\xdd\x02\x1e}\xca\xb9\xb9\xb2.\xb9\"\xc5N\xbdq\xa6\xe4\x8e\xa5lk\x1b\xf1*\xe3\xec\x8b\xd4\x1d\x15\xd2\xc5c\\Z\xf4\xbb\xa6\xeau\xccM\x99Fz\xa5H\xda+}\x13\x95Y\xc6\xd3\"\xb9kx\xcd\x1c\xf7\x92\xc5f\x13G1K\x1c\xfb\xc8\xaa\xdc@\xc6\xe5\xee\xc0\xcf\xd4m\xe1\xb80\x9d\x95rr\x95\xb5S\xaf/\xf5\x08}j\xb3%\xd5{KV\xc5\xb5\xd0\xf2\xcc\x0eq\xbe\x88\xc4\xde\xa61?\xaa\xd5\x96W/X\xaa\xa7f;\x9a\x05\x1eU\x16\x18\xdf\x1f\x8a\xbbjy>F\x91\xed\x95geeQ$j\x80\xca\x95\x18\xef\x0f \x97\x1b\x9d~\x90)?\xf0(\xde\xc4\x11\xe4|\xcf\xd2\"\x8e\x90\x94\x1e\xebC\\\x1e\x93\"\xc4\xdc\xb6X\x1co\xabwo\xab\xba\x1c\x0d\x83\xa1g\x1b\x98\x1b\xdf+qc16\xf4P+q\x0e}\x0e\xeb\xf3Ez\xf7\xb9\xf1N]\n,[\xc5E&\x17\x9f\x83\xaaJG\xf7\xd0\xb1D\xa4\xdb\xea\xd5\xd3\xfe\x94I\xad\xa9\x94\xbe\xa6j\xd57\xa7\x9a}\x1a\xab\x08\x11\xb3+#\xf8I\xbcR\xa4Vz=\x87\xbc<\x1cD\xa6v\xce\x03\x8b\xbe<)S\xf9\x7fr\xbf\xd4\xf3\xad\xac\x92.:e\xd1\xa0\xc6\x83\xd8@Yh\xe5c\x96s.\x15\xdf\xf1]0\xd8\xf2\x94g\xea\xb52}`\xa8/\xe9_ \xfaNOQ\xbf\x9fW_\x99\x14`x\xfa\x0c\xae$\xbdr\x1dW\xa4\xb3f\xe5\xbc\x17\xbf\xfa\x95e\x9bz-\x04l\x84\x80\xe7\xb0X,\xfe\x0f\xfa\x89d\x02K\xef\xf0\x1fYz\xb7\x90]\xbf\xce\xc4\xfe\xd1F\x88\xc7\xf8g\x8b\x05\xbe\xf7\xc4\x1bx$Q|RD_\x8bG\xff\"q<\x86\xbfZ\xf4\xa9\x0d\xcf\xdf\xed\xbc\xf9\xc6\xc3\x9b\xdf\xb3\x1b6\x9a9\xf0\\\xd9V\x12\xfb\x08.\xc4\xf9\xa3\xd7B,\xa2\x84\xe5\xb9\x83 \x9a$\xd9@\x8f\xa7\xd1\x08\xef\x17\xe1N\xcd\x9e\x7f\xf5\xb0\xe7\xea\xae\xd8\x89\xd4\xc2 M\xc9k!\x1e-\x16\x0b\\\x13\xd7\xccyd\xfd] \x90b[(\xd7d\xe3K\xcd\xb4\x97\xaf>\xbe\xf8pyu\xfd\xfe\xc3c\x9bO\xe4(h\xf6\xcetwvv\xfd\xc6\xc3\xae\xef\x90'\xfd\x14HV={\x0e\xffrX-^\x0b\xf1\xd7\xc5b\xf1w\xfcC\x96\xde\x9dIsM~}\xd0\x06\xc8[\x96\xe5;\x96H&\xda \xb7\xb1\xa9\xdb\xb3\xa5\xdbx\xd3\xe9\xf4S\xba?v\xab\x88R\x82\xad\xbe\xfa\x1f\xcf!\x8d\x13\xab\x80\xdaiA$Q\x1e\xda\x14\x1f\x8d\x1e4\xc66\xac\xee\x8e\xa6\x8a\xd1\xd8\xfay\x8c;\xe3`\xeca+sd\xcf\x7f\x88\x98!O\xe4Yt\xa1~\x90\xa6\xdcC`\x8d]E\xee8U\x05\x95~\x0fj\xd6\xfb\x9d\xd4j\x99\x93v\xe6\xa4\x9d9i\xa7\x0bs\xd2\xce\x9c\xb43'\xed\xd40'\xed\xccI;s\xd2\xce\x9c\xb43'\xed\xccI;?\xbb\xa4\x1dW<\xea^\xd2vt\xdc\x94\x1c\xfaj\xc7\x9e\xd19\xb3\xc6\x99-\xe9\x07\xce\xe6\xedHr+~\xecj\xdd\x8a\x15\x87D\x88Q\x1e\xd5\xbc%\xb3\xa9\x17zC\x88\xed\x85\xdb\x02tB\x81\x06\xd7\xacK\xc8\xedP\x9a0\x94f\x0f\xa2M\x17>\x9b,pf\x0d\x99\x8d\x08\x96M\x15&s\x07\xc8\x06\x85\xc6\x06\x07\xc5\xd4x\xbb\xb1\x1ck8lp L\xdba\x1dl\x96\x10\xd8\x98\xe0\x97\ntuG\x83\x9c\xcf\x86\x04\xbc\xec\xc1\xad\x91a-R@\x8b\x1e\xbc\x1a\x11\xb6\x1a\x11\xb0BO\xf4\x93\x85\xa5\xa6\x0dHM\x16\x8a\xf2\x07\xa1&\x0b?\xd9\x02OcBNhx 9w\xf4\xf5\xcd\xd0\x90\x925|40p\x84\x84\x8c\xbc\xb6f\xcfxv\xef\xa0\x03CC\xc70\x10\xc6\xdf_\xf8\xfb\x1e\x17\x08\xd2\x81\x9f\x06\xba~\x08h\x82\xe0\xcf\xb8\xb0OG\xca\xbb\x9b\xe1\xc8PO\xc5\xe8&\xc61A\x1dg\xc4\xc2\x12\xc8\xf1\x86p\xfa\xde\\z\xd8\xa6\xdf\xf6\xef\xd8X\x07\x05i(\x83\xf5\x05f\xecc\xf3\x06c\x02\xc20m\x8f\xd5\xc8\xd0\x8b3\xe8b\x0f\xb7\xb8\x02-(\x17\xa8\xc1\x15_X\xa5\x1bP\x19\x11J!\x04Q\xc2\xc3'H\xb0\xc2\x172\x99(X\x82\xf4\xdc\x92\x94Q\xa1\x91n(dL\x10\x04 z\x8c\nwt\xc3\x1bS\x066\xac!\x8d\xae\x9f\xb7\x1b\xc6\x98&\x801Y\xe8b\xda\xa0\x05-\\\xe1\x0dT\x10C\x14\x94\xe0D\xcf\x8b\xdf\xef\x8d\xeafv\x87\"\x88A\x08B\xf8\xa1E\xf2\x94!\x87Q\xc1\x86~pa\xba\xb0\xc2t\x01\x85\xe1\xb3\xeb\x0d\"\xf8\xc2\x07F}\xe3!\x03\xd4\x12\xc7\x1c\xfa\x8e\x00\x01\x11\xc7\x98p\x00\xee\x16=]\x1c9\x8f\xff\x82\xf0\xf5\x85d{\x9a\x97y o;\x17\x8f\xd1\xb5\x86\xaf4dV\x80\xe2?\xb1\x86\xeaH3\x04\xd8,\xc1)\xfa\xc5f\x0cF\xcf\x9a\x04S\xf4z0\xdb\xd9\x96/\xd3r\xbfT\xa8\xc7\xf3\xc1\xe3\xc0b_AZ\x15bS\x13~\xa6\xdc\xc3\xaa\xf3\xbeoOZ\xeb+\x96\xc7\x91\xea\xb1L\x98R\x14\x11K\xa22a\xfa}\x8c]\x9cC\x9c?\x93\xa8/\xb6\xdc\x18\x10\xf0\xa4\x83\xe9\xaf\xec\x86g\xb2k\xfd\x82k\xe7\xd7\"\xde\xf3\xbf/\x10\xce\xac+|D\xbe\x0c\x1b\xbd\xec\x1d\x89\xa3\x14&t\x13\x89L\xc7f\xd7\xe6\x08!\xb7\xef\x879<(\xd3\x95H\x95\x81x\xe0Y,\xd6\x0f\xa4\xa4)Gh\x07Y\x1e\xefc$ k\xcf\xa3\x1dK\xe3|\xaf\xf8\xbac\xe9:\x91\xc8\xfe\xf4N\x14\xbb8\xdd\x9e_\x14\xe7\x1f\x0b\xf6\xa5\xe7\"e\xea\xc1\x93\xfc\xc7G\xca\xc1\xfa\xec\xc9\x93m\\\xec\xca\x95\xb2\xe9\xb8\xec\x9e\x97\xfb'\xb7\xf1\x97X\xff\xcfU&\xc4\xe6\\l4\xb2\xf3\xd7\x17\xff\xf1?ow\xac8\x8f\xf3\xf3b\xc7\xcf\xd3\xaa7V\x9c\xe7\xea\x83C&V \xdf\x9f\xb3t}\xbe\x13\xb7\xe7\x11K\xcf\xe3\xe2|\xc5\xcf7\xf1W\x15tj\x0caj\xd5\xd1\x9b6\x1d9\xe4\x85\xde\xae\xf6\xeck\xbc/\xf7j\x11\xaa\x83\x9f\n\xfd\xd7\xb5\xe7\xa50Kj\xb4u\x1f\xb1\x14V]\xf7\xf9\xb1\x1a\xbd*~\x9f\xc7\xe96\xa9\xe4\xb2\xe7\x06\x92\x87\x8aJ\n6,Id\xdb\x8d\xc8\n\xb6\x92\xe7\xf1t]\x9d\xb6\xf7\xeck\xa5\x1aT\xdf=,/+gA\x9c\xc3\xd3_\xff\xe6\x7f\xff\xf6\x7f\xfdN\xca\xc9\xd3\xb7\xdf\xe2\x8a\xc8\xc0\x87\x1dG\xd6\xac`\xe1J5\x11\xbdb9\xadFX\xbd\xbb\xb6\xef\x95\xe5\xcb[\x96\x16|M\xec\xbcI\xb3l\\\xe6\x83\x9a\xceZs\xd6\x9a0k\xcd\x7fv\xad \x95\xc6\xcb\x0f\xac\xef\x8e\xacE\n\xd7\xad\x86|\xb2j=>\xd3X\x1e\xd6\xec\xe4\x87\xb1iKV9^\n\xf7,@\xe7\xf2s\xbe\xf9=\x1c\xb1\xfd\xf5\xee\x90\xb7\xba\xdb/q\xf7PY^\xe6\x9e\xea\xe2W5\x86\xba\x97OJhj\xa1\xad<\x0fK\xe5p\xb0I\x14\xc9\x03\x83\xd4^\xb5\n\x89]D,>M\xf0\xcd\xa3\xdd\xb7 \xe0\x0bQ\xf4C#`\x0b\x8f\xc0)\xe9\xb0\x85J`\x92p \xa0!\x13\x18>M\xae\xf0 \x8c\xe3\x93\x7f\xbf\x0b\x0d\xa7\xc0\xa4!\x15\xf0\x86U\x00\x90\xd0\nx\xc3+\xe0\xe3\xdbp\xce\xe0\xa1\x16\x98:\xdc\x02\xf6\x90\x0b\x8c\x08\xbb\xc0\xcf+\xf4\x02\xa7VU\xe8\xd4\x8e\x0b\xc7 \x08W<($\x03\x93\x85e\x80\x14\x9a\x81\xd3\x84g\x00\x0f\xd1\xc00U\xe8\x08\xd7\x80\xf3\xdc\xe4}p\xdd\x17e\xed\xdd3\x9e2\x84\x03\x83\xc38\xe0\xae:\x1d\xc4\\kX\x07\xa8\xab\x0c\xb9\xd3\xec\xd2\xf9\xde%\xd9\xef\x8f\xa4\x12\xc4\xbbO\x1eB\x1aJ\x96\x8b\xa4\xabj\xd1\xfc\xd0\x9c8\x025\xadu\xe2\x9c\xbf\x96\\\xa2\xb9\xcd\x94\x86\xad\xf5@kV\x8f\xb3P\xd7\x0e\xc3<\xe3;\xce\xd6\x03\xe5\x08?\xafh\x85\xa9]F\xfa4\x1b\xb7_9\xb1\xf4\x01N\xeb\xf4\xe7\xfcH\x95\xcfL\xac\x0f7\x10\xb1CQf\xd5\xeeQ\x1fk +\x13\x9e\xab\xed\xe3\x90\x89\x88\xe7\xb9\xbe\xc2e\xb8\xd7AW{*\xa3\x1d\x8b\xd3\xb3\xae\x97 N\xa3\xa4\xd4\x97\xc0\x92\xa4\xf1\xa1\n\x13\xcb\xb1\x95\x91\xa6\xc1\\\xe3\xd4\xbd\xa3us\x1a&\xe5\xc3\xbc\xdbQ^\xb0\x82k\xa3M\xdf\x18\xdb\xb3h\x17\xa7\xad\x03\xb1\xea\x99\xfapW\xf7\xe5\x12\xc7\xa7.\xd7=\xf1\x8d\xa7#\ni\x9e\x9c\xcbv\x8d_\xd5-E\xfd\xa0\nN}\x90\xf4\xeeX\x8e<\x8dD\x926\xe4\xd4s`Y\xb1\xccy\xb1\xec\xae]\x03V\n\xc1{\x02D*\xa0\xd5?)\xac\xdd\x84\x84&\xb8\x9dt66\x80\x8f\x15\xe0;\x04\x1a#\x8deE\xce\x8b\xef\x15W~\x81|\xa04\xe3\xe5\xcb\xee4ko\xde\xb2O\x9dWrl\xc5\xec$*\xbd\xa6\xf4\x1a\x96K\xaf\xf1\x9d\xfc\xcf \xba;\xfa\xa2&@\xd6\xa5}\x93\x89\xbd\xf6\x9c\x1c\x0e \xca\xe2P\x16\xc7\xbf\x1d2~S\xb9\xf0\x8f\xedU\xc1\xbeIi:F\xda\xc6\xe3b\x87\xc3\x04X\x94\xbcT\xf5\x83&@g|\xae\x13\xa0:^\xd6\xab\xb7\x95\xce\xbe{0WU)\xe6\xdc\x11\xd0\xfeZ\x1b\x9e^p\xad\x93Q\xbd\xcd\xa8\x8b\xf2p\xcd\xd3\xb5r:\x17\xd5\x82\xd0\x9a\xcb\xec\x14X\x02\x13\xc9\x02)\xbe\xa2\xa3\x18\x93\xeb\xaf\xc1\xcad\xf7N\x7f\xfd\xb5\x8a\x1c\x98{\xd9j\x03\xd5^H\xbd]\xfe{\x15%\xd0\x95\x10\x7f\xf5\xb4\xe7\xe4\xd7\xeecU3-I\xe4\x00a\xc73\xae\xeaY\xa9\xb5\xb5\x00\xf8#\x7f\x98q\xf8s\x99\x17\xc0\xb6\x19\xe7r\xafG\xabX\x89L\xce\x8b\xba\xe9\xde\xebG\x85E\xf6\x9c\xa5\x15\xc5\x9a\xac\x8b\xc3\xe1{\x96\xef`-\xb8\xae\xc1\xa4\xad ^y^\x8a\xafy\xcf\x8f\xfbR\x9a\x15-\x17p\xceu\xa5\xbb\xa6;\xa7\xc2\xb36U\x1d\x9a\xcac\xd4\x9d4Wt6H\x0e\x82\xd32\xd6\xa56\x8e\xf8\xf2F\x14|\x89\x13\xa2\xc1\xb9!\xfb\xb6duG\x9d/\x19\xfe\x9b\x179\x10:\x00\x83\xc6\xfa+a\x8b\xd6\xc0S\xfc1\xc5#\x9c\xc3\xc7\xcb\xef\xde\xbdz\xb9|\xfb\xf1\xbb\xe5\xf5\x7f^\xbdZ~z\xf7\x87w\xef\xff\xf8.\xb0\xd5\xd5\x87W?\xbc\xbf~\x15\xde\xea\xc5\xfb\xb7o/\xaf\x83\xdb\xbd\xbfz\xff\xf1\xe2\x8d\xa3Y\xe5\x8bx6`|~?\xf3\x11>\xc6\xdb\x94\xaf\xdf\xe6\xdb\xeb\xaa\xa8\x84~\x1eK.\xb9\\\xfd\xd4\xac\x97c\x7fwIC\xbd[X\x1es\xa8\xc1\xca\xffg\xf0\x83(zu\x18 \xad5?\x9f\xc1\x95\xda\x97XbG\x81\x1d\x0c\xda@\x14N\x9f\x81\xaa!\x13e\xba\xf6\xf7\xe6\xb2\x8454\xba\xfb\xd7o\xac\xdf\xe1\xa7\x8c6\x10\xd68\x10\xd798\x0d\xf1#\x10Y\n>\xe3\xbc \xde\x93K\x1b\x88\xa3\x86\x80\x91Kp\x9cq:\x1f\x12\xe7\xd9\x00M\xbc\x0cP&\x01\xc2&\x02B&\x83pnB?\xef\x9f\xa2\xba\x9f\xedy^\xb0=\xe2_i|D\x1b\x94\xeb\x88\xde\x86c\x86\xa7\xf5\x19\xea#\x04\xf6\xeed\xe5\xb1cG$R\x03U\x9ehzC*{&ml\x7f\x97S\x8c\x94\xbaE\xc9\xdd\xe0X\xa6H\xeeN\xf2\xb4(\n~VUP\xdd\xc7\xba\xa2\xab\xfe\xa72n\xac\xc8\xd4\x89\xb3\x91s\xb1\x11h\x82\x94\x86\xc6^\x86\xfd\xac\xac\xa8\xd5lE\xcdV\x14\xccV\x14\nD\xe1\xa4ms\xb3\x15\x05t\x96\x02M\x07k\x98\xad\xa8\x06P&\x01\xc2&\x02B&c\xb6\xa2\xa8\xbd\xcfVT\xc0\x16\xf5\xb3\xb5\xa2\xd4\xb2_\xba\x1eZ\xaa\xbf\xf43\xcd\xbf\xd4\x8frq\xfa\xbe\xbcK.\xa0\x17\xd7R\xa3\xc8\xc0K\xe3\\\x94\x82`2\xb8\x8fn\xd6f\xb26;2 EU\x993\xc5\xad\x90\xed7I\x1c\xa9k\x1bRb\x909N\xa4\x91\xb0\x8c\x92\x98\xa7\xc5R_\x1e8\xa5k\xb3A\xd1\xd2\x12\xe3\xd7@\xd8\xc5|}A\xcd\x0c\xc2\xceI\xe8\x0f\x88}\x02\x92f\x81\x03\xb1S\x08\xe8\x18\xec\x85$1\xa0\xa4oXZ\xd2i\x87@\xfa\xc1\x9e\x00\x82\x03a\xa1v\xc1,\\4Y\x04\x074\x85\x04\x87\xfb \x88\xa2V\xba@OM!\xa1C\xd3W| +8\x84\xa4\xb1\x90\x10vS]\xdc\xc9-8PR^p\xc0\x13ap\x08\x12\x16\xff\xa9\xce@\x10Z\xca~\xd9\x84~\xda\x8d\xe5\xbbaD\xf8-W\x03\x8e\xc4\x1d\x1cN\xac\xb7\xa8\xe7\x13\x08g\x0e\xd0L\xce6\x04\x1e\x1e\x0d\x04r \x06p\nB\x0e\x95\x06\xa8\x87\x81.\x84I\xb7\x81\x90\xc9\x84a\x13\nC&5\xf8\x10\xdai\xe6;\x8c\x1ap\xa7K\xe1\x10\xc8\x83\xc0\xb1\xd3\x12\xaep\xb0\xa4a\xe1p\xcaa8\x93\xa6p8%9\xee\xfb\xb4}\xa0f\x8c\x91\x90u\xb3\xcap\xf0\xe7\x9a\xe1pJ\xb6\xb9\xb2\xd5p8%5x\xbe\x1b\x0e\xa7\xa4\xc3\x931\x87\xc3) r\xe4\xdc\xe1pJb\xfcY{8\xb8s\xf9p8\xdd8BO\x1e! \x83^dXB!\x0e\xddg'p\x08\xb0tB,\x9c\x9f\x89\x9d\xee\x8d\xca\x18\x085\xach\xdeV\x03\xb3\x81n\x85\xd9@W\x10&\xd6\x06B&\x13\x86M(\x0c\x99\xd4\xfb2\xd0\xebh\x06iJ\xf5\xe8\xf12\x1b}\xb0\x16\xde\xe8C\xb00\x86\x8b\xa2\xd1 \xcbM\xc2\xb6\xd4F\x03'\xdc\x9f\x8d\xd1\x86s\xf8\xf6\xcd\xfb\x17\x7fX^\xbe\\\xbe~s\xf1\x1d!s\xa1\x0b]\x0c\x17\xdf~|\xf5\xce\x9dl\xd1\x86.\x02B\xb6F\x1b\xba\x08\xde]\xba\x926\xdaP\xa7p\x8ccC\xd8)D\x83^(\xeb\xd7 \xdbB\x9c\xaeU\x08\xa5z\xc2\x1b\xbeM\"\xf1\xe5\xf2\xa57\x9b\xa3\x0d\xf5\x92\x82\x98\xee\x08\x0d\x8c\xa4\xb6a\x90\x8c\x0eRI\x84\x10s\x1bF\x91Fw\xe2i \x85f\xdb0\x8a>2\xebB\xed]\x0d/\x94\xf9\xf91\xde\xeal#\xb9\xcf\x1bW\xb4\x8a\xf6\x9a+\x12Dt\xaa\xf2\x94\xc6\xe9s?\x87\xd2\xab\xb1\xb6/u\xd4\x11Gu[\xc4x\xf7o\x99'e\xa9\xf5~\xc9\xea\x0e\x98\xb9\x1dr<\xbc\xdb\xa9?\xae\xa1\x9c\x13\x12\x97\xbc\xfb\x0du\x979\xd2\xe6\x93<\xfa\x0eJ\xdc=\x89#\xd1@\x1d\x8f\x86 =\x14\xbc\x90\x02\x17\x91\xa5B*\x0eAL\x81`\xc6\x80\xbb\xc6*\x0e\xc1\x0c\x82p&\x81\xafJ+\x0e\xf7CZ\xe8\xeeL-\xa1BDG(_\xe3\x02J\x02K\x1b\x82\xb9\x1az\x829\xd8\x9f\x12u\xc1 \xe92\x14\xf9\x08 X\x9f!+3@a\x052!H\xd8\x03TU\x00# \x90\x19\x10\xae\xa4\x02\x99\x02\xa1\x8c\x81!\xea\xe9\xf4D\x85)&\xaaZR/\xa7\xfb\x90I\x18\xac\x94BUR '\xe9\xcb\x1e\x86*\xa3\x93QDO:\xac[\xd0I\xf1\x93!-X\x91.\xdd.\\B\x8f\xfe\x9eVw\x7fai\x11\xa7|\xe9\xb7A\xfd\xb6\xa7\xc7\xe6$i+\x9a\x8e\"\xa9j\x02\x874\x10\x17'\xec\x9f\xae* \x9d\x12\xba\xf3\xf9\x90\x02z\x19\x9b3\xfdF\xaa\xe7\x17*s\xf9B%.\xfb\xf2\xa6\xb5+\x02\xc5\xd5\xc8\x96gE\xc1\xf7\x07]\xea^\xc0>\xce\x13\xce\xd6\xc0t\xa64\xe8Li\xe3\xc3h$\xc8\x1c\x19\x82\xaa \\\xddLR\x02\x0b\x89\xf1i\x1cX\x14\xc6\x16\xb7\x9bk_\xb5~\xb2\xf2\xcf\x80o\xa9\xfc\xfcj_\xd9bE6\xbbb\xca\xda)\xde\xe8\x8d\x87)\xf6\x88LH\xec% \xca\x12\x10O\xa1EN\x82c$\xady\xf4\x068\xfca\x0bR\x80\xc23\x0d\x1e\xc9tl\x0dD\xc4\xf6-\xc1\x19\x1c bG\xc8n\xed3T\x8f=\xee\x8b\xb7oYA\xfeu\xdc\x7f\xde\xc0\xd6\xf6\xa4c\xc5@/_j&\xf5\x16k\x7f\x89\xb6\xd5\x14\xcaG\x84{V\xad\x1c\xb0\xf5!\xda\x97\xb4k\xb5\xb4\xed\xd8:jVm\xda\xd3\xa28\x9f_\xd7\xea\xac\xd7oSe\xb9\x95\x94S-9\x15\x91M\xf5\x10\x94\xcdx\xf5\xd2\xe1\xc8\x8b\x86\x15D\x11\xbc\x8e\xe5\xe3\x14\xbd\xe6\xb4w\xac\x1d\\f0+\xa7o\xe1\x04H\xebXA\xf3X2\x03\xec,\x8b\xf5\xe2\xb6\\\\V\xcb\x94\x86\x9b\xd3JA-\x14\xcc:\xc1,\x93\xb1\xaft8-\x11\xc7`q\x0b\x84j}\x10-\x0f\xa2\xd5\xe1\xb78\x08\n\xe0\x08\xe3U\xc1\x11\xbcV\x86\x83\xc5\x0ei\xb2X\x16\x04d\xb8Ea\xb5&\x08\x18;\xe4MdA\xe0\xd6\xc3t\x96\x83\xd3j\xa8\xc9&\xabo\xcb2B\xd9\xd7]:\xfeE\xe3].\xde\x85\xe2Z\"\xc4\xc51\xcd\xb2p,\x08\xaa\xb5\x85\x88\xbf\xb3iW\xe4\x11a\xa7u=\x89hwD\xede]\xfb\x95 e\xadz\xaf\x01\xbbAo\xfd\xa2k\xd7n\xb0\x8f\xac\xeb:\xaa\xa6\xab\xae\xe2\xda\xa4\xbdW\xcfu\\-\xd7I\xea\xb8vg\x15+_@\x9e\xe6n\xbd\xd3\x00\xbbL}\xda\xf8o\x87\x06\xc7vpjU-j\x1d-z\xe5,b\xad\xac\xa0\xeaX\xee\x87\xefB+`\xb9\xaa\\\x85\xd6\xb5\n\xadd5\xfbEa\xf6\x8bv\xe1D~Q\x8bu\xe9\x157\xcc\xb2\xf4\x98\xbf^\x9c\x9d\xa19\xab$\x85\xcb\xb2\xc5\xea\x0d\xa3\xca\xbek\x0e\xa9a\xd4\xadU\xf4\x8bV\xefM\xbd\xd3\xabS\xd4\xad\xef8\xef\x1a5\xcc\xbbF\x0d^\xe1\x9ew\x8d\x06\xcc\xbb\xc6\xbck\xfc\xd7\xde5\\\xf9\x12\xe8\x900\xd1\xb4V\xa9#c\x18w\xa6\xc7\xb99\xac\x86\\\xa3^\\\x85\x07\xad\x1a\xd79\xf0\x05\x9f\xf1\xbc\xafg\x04l\xdf\xd8\xfb\x18\x03tk\xdf\n\x00\x9fB\xb1\xc5\xa1\xa9\x16\x01\xfe\xad\xbd&3\xdd2\xb0}m\xa9\xbf\x1cd!\x80\xd7J\x80\x89-\x05\x18`-\xd8\xda\xf8*&\xdb\xd2\xca\xc1K=\xb8-\x0e\xf0\xf2\xdb\x80\xcf\xf2\x00\xef-s/\xbb\xc0\xcf2\x82%\x02.k\x04\xec\x16 \xf8HtGJ\xbc\xd6 P\xf1#C\xf7V\x01\x1e\xbef\x1c\xf9\"\xc3\xa8ug$\x0e\xb6bl\x1cA\xab\xf6\xa2\xb5z\xb1w\x0e\xe6\xddp\xde\x0d\xe7\xdd\xb0\x05\xf3n8\xef\x86\xd5O\x14Q\x9ewC\xf8\xa7\xdc\x0d}\xf7!\xac\xc3\xb5\x89\xbe\xb3\"}0\xb6\xe9\xdcF\xf6\x19\x98\xca\x0f\x006_\x00\x90\xeb\xc6\xa3z\x0d\xd7e\x9e\xca\xf0\x03,\x1aO\xed\xf71\xbb\xc5iU\xb9\xb7~{h\xd5v/M@\xa2\x0bhu\xd9I[\x004\x84\xdb[\xf2\xdc[y}\xea.)\xd7\x8f4\xd0+\xaa\xc3\xb1Z\xbak\xa8\x83\xea\xa8\x87TO?VFw \x0c\xad\x99\x1eZ)\xdd_\x1f\x9d0\xa5\xbe\x1a\x8b\x04\x144\x93\xc7]\xed<\xa8\x1b_Q$b=\xf3 W\xb4\xbf\x86\x1ei\x80@\xb1\xeb4\x90Lb\x03\xa4\x91\x02y\xb4\xe07\x95\xeb\xcfH&\xb3\x01\x8a\x1c\x19\xf0\xb3\x1cB\xd8\x0et\xd6\x13M\xeb\xce\xc7\xeer\x84\xf4*\xe1\xa4\x11\x91F\x12^\x07\x9cP\xfd{*\xf2\xc8\x85\xaa\xa7\xea\xb0\xcb\x0foing\xd9\xed\xb0b\xdbS\x8d\x81ZN{\xaa\xfe\xfc\x05\xb3\xa7\xea)\xa0$\xf6T]\x12\x8b^O\xd5\x1d\x04\x95\xb5>\x90\x8bYOC_\xcb\x98\x0b\xa9E\xed\xad5\xed\xaa0\xed\xdd\xb7\xfc\xfb\xd5\xbd\xd97\x9e*\xd1\xb4\x8d\xd0\xe5\x7f00\x1b6G \x8d\x14\xc8\xa3\x85\xd9\xb0\x99\xda\xb0\xa1TW\xd6cqW\x84\xf4\xd6\x82$\x8a\x02U\x10\xbc\xb7\xed\x9b\x100\x19\xb4\xba\xc8\xfe\xeb=\xb4v\xc4\x1a\xc8\xde\xab@\xb4f\xfez\xc7\xc4kC8P+\xe8LW\xd1\xd8[\x10\xa0 \x04\xafv\x1b\x02\xa4&`\x01\x13\xeb\x13\x0f\xe8\xdcw\xec\xd6@\xae@<\x80\x02\xcf\xf0\xe9\x1e'zeau\x15\x8b\x80 w\xd2\xd0(\x1a~C\xd1\x82\x90P1\xd8S'\xd8\xa9M\xdd:\xd4W\x85\xcd\xa7\xed\x9d\x9a\x9e\xa0\xe5)\x1a\x9e\xb0B\x89\xe2I\x12MB\xd55\xc2\xc0\x8088\xa0\xd7[#\x0e\x12\xa8\x03\x85\x90Jk\xd3wN\xdb!\xa6\xad\xb0\x16R_\x8dRb\x0c\xe8\x9c\xa1Y\x95\x87\x90\xbaj\x13\xf5|pV\xc1\xf5\xca\xba_\xca\xbd\x0b\x984\x10\x82Xy\x97\xaew0@\x1a\x10P\x17-i`@\x1b\x1c\xd0\x97\xeb\xb4\xddR\x16\xea\x94\xcb\x94\xbeHiK\x94\xc4\x0d\xdf\"\x81\xb0\xc59I\x9f\xbe\xd0~\xfd\x9d\xaf3[G\x8e\xba\xafV\x9c6\\\xfe\xca\xae6[b\xca\xbak'*\xf5\xe5P,\x1e\x95\xe2S&\x1e5\xe2\x9dZ\xc2\x1a\xf6*\x8d\xf1\x9d\xb8UD\xb0r\xa8U\x00\x8a\xce\xa1\x16|k\x85(\x03\xf8\x82$-\xff\x81=\xf8\x96z\xf0r\xbc\x8f\xbc\x9b\x81\xf5H\xf1{L\xd4*\xa4\x96{9o\xe2\x9c^\x8b\xcb\x96\xb7C\xaa\xb5\xd1[\xea\xb6%\xee\xbd\x01\xe4\xc4\xea\xc2\x0c\x96;A\x1aFj$\xd5\x1c\xfd\xc5+\xdd\xe0\xf5\x99\x85dJ\xdbZ\xd8\xf3\xa5\x1d-<^\xb2\x80\xdci\x0d\xc1\x19\xd4\xa6\x19\xc5\xc7\x10\x9eMmE\xe4\xc9\xb2\xd60$\xd7\xda\xde\xd2\x97q\xad\xe1\x1e\x8a\xcd;\xa3<\xba\x07wL\xc0\x1f\xe1\xf1\xc5w\x08\x07\x0e\xdfz\x04B\x98\x81\xc0.\xf0\xef\xe2\x1a\x02b:\x84\xd1\x01q\x84\x00\xc4h\x0ee\xde\x0c\xf8E\xc4\x80\x8f\xc1@g2P\x19\x1d\x14\xc1!\xc4o\xbc\xeed\xc2\x00h\xeec\xb2\xf7<\xa0G+\xab\xbcY\xe2\x1a(r\xe1_\xcf^\x87\xf8\xf8\x11Q\xb6\x80\xa9\xf2\xc95\xb8\xb3\xca5\xa0\xb9\xe5Us\xe4\xbe\x95\x86\xd9\xd2\x98-\x8d\x1afK\xe3\xa4\x9ai\xb64fK\x03\x01\x12\xa3gK\x03(\xac\x9a-\x8d\x7f\xb0\xa5\xe1\xf3\x82U_\xb9\x19\xe3^\x8a\xce\xdbm\x1aF\xe1?\xe5\xa3\x10\xbe\xf9\x1cu\x0f\xae?\x92[a\xbf\x0d\xa7\x81v'\xaeB7\xcc\xcd\xe5\xb9%\xa7a\xa4\x1d\xea\xb97\xa7\x81\xb0\x03\xf9\xfa\x01\xcfM:\x0d\x84\x8e\x80\xd8\x19P\xee\xd6i\x08\xbdaW\xb5\xa2\xd1\n\x01\xf4\x02\xed\xce\x9d\x06\x82\x8el\x82Y`\xde\xfbw\x1a\xbc\xb7\xf04\x9c\x92\x08\xdf\x92\xef\x02\xfdv\x9e\x17\xd5\xf1\xf6\xde\xc0;z\x1aBo\xeay\x11\xea\x11\x84\xde\xd7\xd3\x10zkO\x83\xff\xee\x9e\x06\xb2 \xf8\xf2\xdc5\x90\xd1\xf9\xf6\xa4&\xb8o\xf6U\xdf\x84wLK7$\xde\xf5\xd3p\"\xddB\xb1\xbf!\x8c \xe07\xc5\xda\x10p\xf01\x10\xc0\x0d\x08\xe4\x08P\x0fD\x06(\x06p\x17\xe8\x12j\x80:Q\x10>Y\x10:aA\x07\xa8N\x13w\xca\xbd\x06\xfa\x8dB\x0d\x01\xe3\x0d\x18g\xf8\x1dC\x0d\x84\x9b\x86\x1aNA6\xf9\xde\x9e\x86S\x900\xedmD\x0daw\x125\x9cbl\xd4[\x8a\x1aNA\x81\xff\xde\xa2\x86S\xf4\x1dp\x93Q\xc3)\x88 \xdem\xd4p\n\x02\xc2n;j\xa0\xdfy\xd40=\xdd!\xa6s\xf8%I':\xfb\x05J\x0d\xaek\x94\x1a\x88\xdb=u\x9b\xff\x07\x1a\x9c\x9e\xab\x96\x1aB,\n\xbfk\xcd\xc0li\xce\x96\xa6\xefk\x08\x98(\x08\x9f,\x08\x9d\xb0S[\x9a\x94+\x9e\x1a\xf4H\xdd\x17=5x\xaf{j\x08\x12\xac0\xb1\n\xba\x00\xaa!x\"i\x97A5\x0c\xbd\x12\xaaa\xe0\xc5P\x0d\x03\xaf\x87j\x08\xbf$\xaaa\xd4UQ\x0d\x94[\x06M\x98\xea\xda\xa8\x86\xa0\xcb\xa3\x1a\xc8\xa1\xa96\x04\xcb]\xb0\xfa ^*\xd50\x98\x1c\x9a\xc7G\x837\xd6\xd5\x86\xc14\x91X\x14b\x17j\x98\xee\xfai\x13\x9f\xcb\xe7\x18Bc\xd0\x85T'&\xf49M\xc7\xb5T\x0d\x9e\xcb\xa9\x1a\x08\xba\x9f\xa2\xf1}\xd7U5\xd0v.\xc2\xaeE\xa0Z\x03\x85v\x0dd]\x11\xb4\x08\x02\x16\x80\xf7\x8e\x9c\x01\xf2\xe0!\x88\x01\xe0\xbf\xf4\xd2\x86 F@\x183\x80r=\xa6\x0d\xa7%'d\x17\x0c\xb9VC@\xd7\xbax\xe3\xbf{g\xc0\x17\xadoC\x10\xf7B,y\xd2\xe5\x9c6\x9c\x80\x16\xf7UZ\x0d\xc4uE]QD\x85\x120X\xb2\xc0\x12U q\xc0\x100h\x08S\"\x01\x83\x87\x10\x06@\xa8\xfa8\x1d!t\xc51\xa9\xda\x18\xa44BTF\x00\xc7hK\x14\x86(\x8b\xc9\xa9\xa0e:\xd5_\xd3\xbaww\xed\xb8\xec\xab\xc1\xd3\x8b\x1b\xbb\xff\xfa\xaf\x06\xb7m\xe6\xb0\xc9\xbcZ\xc4\xaf;\xbc\xaa\x92\xc4g\xc2\xa2\xf4*F\xef`\x804 \xa0\xaaA\xd2\xc0\x8068\xa0+\xbdi\xbb\xa5\xa8\xb8\x10\xe56\xd7!\xa8\xc0\xdd'MU\x8dR\x1e\xff\xc8\xa4\xc9\x81\x97\x98{x\x1a\xa9\xaf#\xaf2_\xb1\x8c\x19-\xd8S\x14}\xa5\xb0g_\x97l\xcb\x97i\xb9\xd7\xb95\x0du\x81\xf2\x0e\x9f\x0b;\x9f\xde\xb2\xaf\xc0\xb6j\xf4\x86\x13g\x10\xa7\xda\xa9\x90/~\xd1~\xa9\x9fW9\x84\xb2\x972aj\xb1E,\x89\xca\x84i\x8e\xec\xe2\x1c\xe2\xfc\x99D{\xb1\xe5/\xcbLeo\xc1\x13\xf8+\xbb\xe1\x19\xdb6'P\x87\xda\x1a\x7f\x90\x13\xfc\xf7Eg\xe4\xeb\n\x87g\xdc\xe1#\x94\xbd\xb5\xc7wY@\xbe\x13e\xb2\x86Hd\x19\xcf\x0f\"]k#\x88\xa5\xc0\x0e\x87\x879<(\xd3\x95HU\xc6\xdb\x81g\xb1X?\x00\x91\x81(v<\x83<\xde\xc7 k%F\xefy\xb4ci\x9c\xef\x15\xa7v,]'\xb2\xe9\x9f\xde\x89b\x17\xa7\xdb\xf3\x8b\xe2\xfcc\xc1\xbe\xf0f\x1b\x9dj\x9b\xff\xf8hW\x14\x87\xfc\xd9\x93'\xdb\xb8\xd8\x95\xabE$\xf6O\xb8\xec\x88\x97\xfb'\xb7\xf1\x97X\xff\xcfU&\xc4\xe6\\l4\xa2\xf3\xd7\x17\xff\xf1?ow\xac8\x8f\xf3\xf3b\xc7\xcf\xd3\xaa'V\x9c\xe7\xea\x83C&V \xdf\x9f\xb3t}\xbe\x13\xb7\xe7\x11K\xcf\xe3\xe2|\xc5\xcf7\xf1W\xbe~\xdc\xe4\xbf\xd4\xd8\xc3\x04\x0eS\xe7\xd7R8r^h\xb5\xbdg_\xe3}\xb9\x87<\xfe\x8b\x9a\x1b\xa5\x89\x8e\xabQ\x8a\xa0\xec];\xb9\"\x96\xc2\xaa);GoV\x9c\xcae\x1b\xa7\xdb\xa4\xca]l\xddPb\xe9\xda\xcc\xe9\x86%\x89l\xb7\x11Y\xc1V\xc9\x1d\x94\xe9\x9ag\x86\x96\xca\x8b\xa6\xfalax\xa9\xbd\xdf\x10\xe7\xf0\xf4\xd7\xbf\xf9\xdf\xbf\xfd_\xbf\x933\xfe\xf4\xed\xb7\xea\x9b\x96\xd8\xb5\xd78\xacy\xa1\x82\xca\x1cv\xe2\x16n\xb9\x9e\x7f\xde\xd28{\x96l8\xcbY\x1aqDi|\xdf\x88\xeb\x11\x94E/\x1b\xd8\x97\xf7\x8bZ*\xb8e\x82d\xedZu\xb7\x11\x89^\x12l/\xe76\x14\x85}\x95\xd3sc\xed\xb9\xaf\xdd\xe1\xf6\xb3`C\xf3][\xf9\xacmF\xe0\x99\xad\xbe\x1c\xd6~\xb6*\xc2\xc2\xee)\x80\xbcn\xdb\xf9\xa3\xcef\xdd\x1d\xd9\x92\xfd\x19 a\xfd@\xadW::\x16\xa53\x1en\xb5\xca\xed\x96\xb8%\x9a\xad1\x11\x1e\xae\xea\x19Cx,\xdai\x03Y\x8dgg$\x19\x8d\x19\xdb\xf3\x10\x9d3\xdd\xea\xd9\x9fE\x88\xe4\x0bR\xd1[3\xe2\xa8\x08\xc6\xe5\xea\xb9\xb3\xf2\xa84\xd8r\xea\xa8\xed\xfb\x19q\xd4\x96\x8e|6*\nK6\x1a\xb5\xb9;\x97\xcc\x9e5F\xc3?]\xe5\xfb\xce6\xabN \xdf\x1e78\xc2Vk\xb9U\x14\xa2\xee\xa6\xd1Q\xd6\x1b@\xbe\xbd\xbf\xfe\xce\xd6'x\xbd\x14\x8e\x9b<\x17D\x87\x0fPF\x04\xa4Q\x01x\x9d?P\xf7\xe6s\x00\x01A\x16\x0c\xf8+\x17\x90X\n4\xb6\x12\x9dB\x8d\x0f\xed\x15 \xfc\xd1\x12\xa0P\xef\xa5\x9a\x1e9\x01\x7f%\xab\xb1\xe4x\xa3\x140A'\xd3DU\x80\x1cY\x81 h\xf6EY`\x82>\xdcu\xa4\xc6b'D_`\x82n\x08\xb5\xa0\xc6vA\x8b\xca\x00)2\x03\xa3\xe9\x99>J\x03\x8e\x02L#l\xdb\x93\xee\xfd\x8e\"J\xfeM\xa5\x81\x1c-\x984o\xfa\x08\xf8G\x05\xf3\xa6\x8f\x7fh\xdf\xf4}\xc5\x874\xdd\xff\xd8\xd7\xc6IQ\"\xa03\xd9_6(4b\x84\xb5!\x94\x08\n\x8c\x1caM\xdc\xe5\x80\x06E\x90\x00|\x1e[\x03C\x82L>\xe1\xb7\xfeN\x0eB\x01]\x12\x88\x8b\x8dP\xbe'\xb0C\x7f\xa9\x1eop\n\xc2{u\x0cs\xe2@U\x0f\xa5%esx\xc0\n\xd3e\xae\xea8\x8e\x9a8V5\xe5H\xe0u\xdc\xa8v\xa9\xccS\x05\xd2\xef!.\xeb\xb9A=\x91\xae'\xdc\x9d&\x0c\x06(\x03\x02\x7f4@\xc3t\x1d\xfa\xd5jp\x94\xc0\x8a\x89zW\xda\x17\x14\x03\x1a\x07\xfc\xa6\x12!\x86\xa0adox\xb0\x0c|2\xea\x96\xce\x13\x9e\xa78\xc0\x8e\\\x0ft\x06\xd6)\x01u<\x90na3\xe6<\xb7\xce\x88Mq\xf6\x03\xe4^\x14\x98g\xc4\x11\x08\x1f \xbd\xd3\xde\x98\xf1\xfa\xb8\x9d\xf6\xbb\xdbvw\xf8\xb2q\x15\xd7\x04\x9fEy\xaap\x95\xd77m\xf5I\xbb\x03\xd0^\xc9\xe9QC\x0b4[\x02\xcc\xa1\xdd9\x83\xb2\xa1\xc8\xc6\x07\x8c\xfd\x81\xe2P\x9a\\\x01\xe1P\\x\xe07\x14\x8b'\xc0\x1b\x8a\xce\x11\xc8\x0dE\xe5\x0f\xd8\xba\x03\xb5a\xfdM\x1b\x90\xed\x06b\x03l\x90I\xf6\x0c$\xb0jWv\x0d$\xad@\xea\xbcY\xb4~\xfa/\xb8Y\xd8\x02\x97\x9a\x9e\xd3^#\xf1\x06$=L\xb1\x07 C\x02\x8f\x01\x01\xc7\x80@#-\xc0\x18\x1cX\x9c\xfaZ\x1a)\x1a\xe8\x99\x06\x8fd\x9e\xae\x00\xa6'\xbaG\xc4\x8e\x90=a\x14\xcfU\xb4mx\xd4\xae_\xaa\xb3\x1d\xadC\x0f\xd1o\xf3\xed\xb5d\x89j\xd5cNs1\x9d\xc3\xc7\xcb\xef\xde\xbdz\xb9|\xfb\xf1\xbb\xe5\xf5\x7f^\xbd\xeaHd\xff\xf7\xab\x0f\xaf~x\x7f\xfd\xca\xf5{k\xb1`_\xbc\xbfz\xff\xf1B\xaf\x92z]\xb8\xe8h\xb1\xf6o\x86\xb5\xad\xb1\xea)\x93c\x95S\xa6o\x11\xc0\x9e\xe79\xdbr\x93\xdf\xddx\xb5\xdf\xf0\xd3:\xbegj\xcas\xd7wz\x14\xcf\xe0JY&,\xc9\xfb\xd3Q{\xdb\x9aS\xe1th\x0c,\x1a\x85xN\x03\xcc\x10\xd4O\xea\xb5C:\xcb\xc9\xe2\x15\x0dCc\xb6\xb7\xc1\x0e\xcf\xbe\x83s\xa4\xcf\xd0\xe1\xc8$\xe1\xb0ID`\x85\xdcjz\x97\nK\x97\x04\x92;\xbfA'\xbe\x9e:\xa4A\xc6e\x93\xa8\xd0g&5#r\n\x14\xba\xbcY+8b\xa9\x9c\x08\xa3\n\xdf\xa9\xe5S\xe6<\x87\x8bo_\\\xca\xa6\xb2Y\xca\xf6q\xba=\x83T\x14p\xb1\x8fS!\xff\xc21%V\x13\xf2\xd1$\x1e\x10\x184\x07;\xe6`G\x17\xd5?k\xb0\xa3\x1f\x90\x0fP\xe6\x13\x9c\x8f-\xa2i\x15L\xbbXZ\x85\xd2)9\x0e\xb9q\x88\xe30\x946A\x9cL\x0cQ!\x9c\xe0\x02\xa7\x01\x8f\xf0\x05\xe1\x1b\x1de\xebjr\x1dc \xdc\xeb\xd8\xe1\xb0\xec\x17yvu\xdf\x08j\xb4\xf6\xb6V\xffm\x03\\mM\x8d\x08\x81\x89\x07a\xfb\x91(\xe8\xd7`\x8b\xda\xf0\xb6R\xdd=\xcd\xfa\x8cp\xfc\x9b\xb6!n\xfd\xa6wr\xf5\x18\xe4@5\xca\xc1jH\xc0D\xc6\xb9uL\x88\x81n\xfb\x163\xd2aL\xf1\xe8\x8e\xb7M\xb7sDNk/[\xdf\xc3\x16\xa0\xd4\xc7{X\xe7\xaa\xd1\x9d\x1f\xdb\x1e\xb2q\xa9\x01N\xf7\x8a\x13O\x83\xf4#\x8a8]\xf3\xafCd\x0c\xf1\x92\xd0z\xb7\x9c\x08D\xc1!\xe3\x87\x8c\xe7<-\x94O$\xe37\xa2\xe0g\xf2\x1f\xdaQq\x06\"\xab|\x16rW\xe3:\xcc\xd28\x1d\x1c\x9dQ\x8d%\xde\xd0\xb1F\xef\xd6qf\xb2\xaaE\xab\x0c\xf8w\x88N\xf4\x9c\xda\x0c\xf7\xef\x8c\x8d\x8e7\xc2\xd6HT|\x8ah8\x1a\x05wE\xbf\x93\xd5~\xb1b9_\xdc<]\xbc\xe4\xd1\x0b\x11\xa7\xe4)Y\xf3T\xec\x9d\xbce{Q\xa6.\xc5\x8b\x8bbEHm\x8c1(\xc4\x17\x9eV\xef\x96\xe8~\xe3T\xef\xe4\x92\x19\xf2OQ\xbcgI\xd5a\xbd\xab\xe8\xd3\xe9\xf5\x8eW?\xc0&\xe6\xc9Z\xedP\xa9\xec\xa5\xf2\xad\xc6\xfbC\xc2\xf7J\xea\xd5|\x96y!\xf6\xb0\xe7\xc5N\xac\xbb\x8bM\x1e\x95\x7f*\xe3L\xbb\xec\xb6b+\x0e\x99(\x84\xe1\xe5:\x96\xa3[\x95\x926\xcd\xd3\x84o\x15\xa5\xd5\xbfD\xf6\x81\xdf\xb2lM\xe6r\x98\xb2\xc9\x1a\xc8\x8f\x9fL{*\xee\xcc{\x13\x07\xa2\xbb\xbb2\xe0\xfc\xdcncL(\x15\x1a\xa6\x93\x0d\x0d\x14 \xb1\x0b\xbcEJ\x9a\nYG\xb3\xcd\x94T-U\xccrm\x1a=\xcc\xcd\xbf%\x13\xb4,\xd8$3\xd0N\x97Z\xbfL\xe3\xe2nY\xb0\xdev\xd5\x9aG\xa9N\x96\xf5A\x05\x17\xc8v\x03\x91\x96yP\x0b9\xe5\xeb\x8c\xdd\xaa%\xb1\xe4\xa9<\x9f\xf5Z\xac\x84H8;\x9e\xd0\xea}\xb0\xf1\xf7\xd6t\xd4o\xdc4\x82\xc3:\x7f\xef\xa0\x7f\x91\x8a]\xfe\xb5\xc9J\xd8\x8bu\x99p\x1b\x97\xff\xa3\xe4\xd9\xdd\x0b\xc3\xbb+!\x92\x0f\xea\x11\xa6\x9c~\xc88\x08\xd1\xcb\xde\x9b\x17\xf4\xcfeA\xf7\x06)\xa7\xab\x1eR\xbdj\xd4\x9f\x1f\xca?\xc4i\x8e\xa8\x82\xda\xc6\xb0\x0b\x8c\x1c\x89\xda\xf6\xcd\x7fK\x96\x1b\x99l\xb6~\xd2jn\x98\xf4\xe1\xeaE5J\xa7\xac\x1eU\x91\xd6@y\xb0\xbc\xea\xf5{b\xcf\xec,\xb2\x13\x8al5c-\xcdg\xfe\xc6\xa2(+M|\xf2\xb8\xb9\xb8v3\xb7\x1c\xd1\xc5\xb8\x87\"\\\x86\xaf\xe5\xc1\xf5g-\xc8\xdeP\xbdU\xa8\xbb\xfbd\xf3s\xec~\xa5\xe5v\xa5\x85^\x0d\xee\xa4\x1at\x11j\xb0R\xad\x01_\x90\x84\xa6\xfek\xb3\x83\x97\xa8\x95\xcc\xf6\x8b\x8a\x06\xc6\xac]\x04]\xb5\x9a\x91_\xe8\x8b\xda\xa7\xbb\x86\x1a\x99\x1ah\xa6&BGW\xbd\xc8\xe3\xadO\xc5\x88:\xe3\x0e\xbd\xbd0\xed\x1a\x9c7\x93 7\x13\xfd\xe8e\xcb\x88.\xf7Jx\xda\xd3\x1e\xb0\x83`Z|\xc86\xd2\xc4\x13\xb8\x97\x88\xec\x18\xda \xdeHF\x86\xab;B\xd5bY\xc3\xf7\xd6dy\xf3q\xdf\xe3\x92\x92<3\x8b6\xddJfQ'\x01\x1b~\xf0\x0c4\x91\x04\xb3\xff\x8f\xd5\x91\xefB\xef\x92\xc1s\xd0:2\xfa\xbc(\x1d\x96t\xdb\xb6X}\xe4\xae\xf9\xb5\x10\xf0\x93\xa4=\x8c\xc1\x96\x01\x0e\xe0r\x07\x13\x95\xd5\xfa\xf8\x1b\xcc\xd8C\xc3\x8f\xd0\x1b\xeb\xa1\x7f\xa4V\x7f\xe2\x05\xcf\x8c\xeb\xb2q\x82nN\x08)Tb\xf1J\x80]!\xbb\xbd\x13\xae\x86n/\x85\xa3\xa5\xc7[ql\xd9\xf5X\x00\xc5k\x81\xcc\x9dSf*i\xa9\x9c\x1dD\xd9\xa8\x17\xaeJo\xccse\x93\x07\nJT7\xb5\x08\xcb\xf1\x83\x96\xc0\xe8?\xcb\xbf\xb64\x1bd<\xe2\xf1\x0d_\x0f\x16\x9c.1\xe00\x9f\xa7L\x90\xb6\x9a\xcdN\xcb\xd7n2;\x9a\xf9\xcc\xe5\xc1&\x88\x85<\xccT\x1ec\x97\xf4\x90\xd9\xccd\x9a\xb1RE\x03\xdb\x1a\xd8!\xdbt\xe5\x8b i\xac-\xd2\xd2z_\x16y\xc1\xd4C\xec\x13\x9fXI+\xa2\xd7\x16\xe6\xe5\xf0_|9\x80\x93%\x0e\xc1l\x9e\x18\xc5\xf1WxT\xa6\xe7f\xb7K\x1f\xf7\x85\xabI\xa8\\E\xac\xa1\xce\xe3\x94\x7f=\xf04\x8fo\xb8\xb4\xa0\x8a\x8cE_\xce\xe4\xa1A\xdc\xe6\x90+v@\xce\x94/5\xda\xf1\xe8\x8b\xff\x00AXY\x03\x168\xc2\x8d\xd0M\xf4c\xa2..\x06/\xef\\\xb7\xeb.o\xd2!\x82|\x18>:\xa4\x0e<\x8b\x85\xc5\xc1\x84./4\xfe^\xfd\x94\xb1\xa8\xe8\xed\xb6\x83\x8e\xcdm6\xbe\xba\xe1i\xd1\xce[8\xca\x94b\x18\xf0\x9b\xaa\x9a\xc2\x11\xbeW\x19Ar\xf6\xa5`\xc5Q\\\xa85^\xa5'\xe5\x85\xc8T\xfa_\xbb\xd1\xf5N~\x9fC\xca\xf9\x9a\xaf\xa5\x90F,\x89\xca\x84\x15\xea\xeai&\x0eY\xac\xfe\xad\xd7\xb5\xd8@^\xb0/\xba\xc6\xc3\x17\x9e\xb6\xbd)R\xc6\x8e\x0e\x14s\xcb\x87e\xbc6\x17S`\x9b\x82\xcbE\xa2\x87\xb1c9\x88(*\xb3\x8c\xdb<-\x95\x80\xb4O\xdf\xd5\xdf\xdc\xc6\xd3\x81m+\xc5f\xb5\xe4\xcd\x07\x1dk\xbe\xfes\xc5<\xb3\x94\x06\x99e\xeab\xae%\x17\x15\x119_N\xd0\xdf\xba*\xde\xe07\xeb^\xa5\xb8\x0bX\xc9\x81\xe4\xb9\x9e\xd4+\xb6\xe5\x1f\xf8O%\xcf\x8b\x85\xfe\xbd\x83D\x1f\xeeds\x89N\xb2@\x9ea\xf2\x02\xf8f\x13G1O\x8b\xa4\xb9[\"\xc9S\xde\x01!+\xc8\x96\xbb\xaa\xfd-r<\xea\x1fi\xb9_\xf1L\n_u\xf7\xb7\x91\xc1\x1aw_&h\x0e5\x92B\xbbTH\xba\xfb\xc9-\xcb!\xe7\xc5\x19\xc4\x85\xba\x0bP*\xbdY\xa6Z\x10\xd6 \x8a\x1d\xcfn\xe3\xdc\x95^\xe4\xd4\x80\x03\xd4p\x85\x81\xa0{\xeb&\x17QT\xee\xd5r]\xbf\xe8\x98\xff\x04\xe5\x8b\x9d\x18N\xa1\x7fgg\xe4pg$>@\xb7\x00\xb4\xf6\x8e\xe3\x07\x8d\xf9\xae\xd0t\x0d\x96/\xfcP\x00\x93\x9c\xca\xca4\x95j^-!\x9e\x9d\xa9K2\xab\x96&/\x80\xa5w*\xf1\xd0+\xa6}\x03\x83,\xa3\xf7\x12\xb1\x9a\x05\xf4d\x02:\xd4\xd2\xae\xedk\x8do\x12\xd3\xda)\xa3G\xd3\x8b,\x9bv\xbb\x12\x15\x06t'\xec[\x91\xbd\xb6\x1e\x0e\x0f\xb2\x19\x03\xad\xc5\x89\xec\xc4\xf1\x16\xa2\x9cBs\xf7\xb8>\x85\\$\x89\xa9Z\x16|\x00\xe1\xadw\xc2\xe0D\nF~\xbe,\xb3^\xc2\xf9\x88\x83\xfd\x05|\xfa\xf0\xe6I\xc6sQf\x11W\x97\x11\xf5e\xec2\x8d\x7f*yr\x07r`E\xbc\x89+\xbb\xb6\xa8\xee/\xf4\x0bM\x01\xe4<\x8bY\x12\xff\x85#\x07o\xb5\xd6#\x91\xc0\xaa\xdclxf.>,\xb4Ph\xdaa_\xe6\xf5\x0dq\xb95$\x9c\xe5E\x1f\x97H9\xef\x8a\xe2\xf0\xf9L\xff\x7f\xfeY\xe5\xe6\xa7\xa2\xfa\xf5LI\x8f\xb4C\x84Z\x15j\xc49/\xa0<\xf4\xf0\xe9\xdb:H?<\xbb\xe1\x99\x1e\xf2\x9e\x1dr-\n\x8a\xe2B\xd4Wz\xd4~\x1ck\x15\xc5r\xd8\x08\xb5\xad\x8a\xad\x98\xaa\x15\x91\xeb\x83\xb4\\piwu\xc3\xa3*z\xc7\xf7\x87\xe2\xaeZB\x8fa/\x0d\x93\x1e\xba\x15\xb2\x98\xd5`\x94\xad\\\x9b\xb4\xdaV\xce\x0f<\x8a7q\x049\xdf\xb3\xb4\x88\xa3\xbc-\xeaj\x8d\x04l\xc5\x8e\xfb\xbc\xbe]\xfa\xad\\\xc6+n\xcc\xb1\xc6F\xdb\xdbW\xab\xcd\x89\xad\xc4\x0d\xb2A\xeb!U\"i\xcd\x8f\xeaP\xf0\xf9\"\xbd\xfb|\xbc7\xcaR`\xd9*.2\xb9h\x1c\x94\x18=\xc8\x12\xd1\xe1\x85>\x99\xb4\xa7Bj+\xa5P5%\xab\xbe\xb9\xd1\xec\xcbX\x0f\x1d\x91\xb92\x82\x9b\xc4+E^\xa5Gs\xc8\xcb\xc3Adj\x07:\xb0\xe8\xcb\x932\x95\xff'\xf7\x1d=\x8f9\xb6J\xfa\x1b\xae\xd8@Yh\x05a\x96_\x0e:\xc3!\xd6k\x11\xb6<\xe5\x99:(\xeb\xc3P\x1d\xcd\xbf\xe8\xe8#=\x05m\xfc\xaf\xbe2u\xe8x\xfa\x0c\xae$}r\xddU\xa4\xb2\xe6]\xd1\x17\xbf\xfa\x15\xb2\x0d\xbc\x16\x026B\xc0sX,\x16\xff\xa7\xf7\xb3\x1c,K\xef\xfa?\xb0\xf4n!\xbb{\x9d\x89\xfd\xa3\x8d\x10\x8f\xfb\x9f,\x16}=\x1fo\xe0\x91l\xfaI\x11x-\x1e\xfd\x8bl\xfb\x18\xfe\x8a\xe86\xac\xfd\xdf\xf1\xb1\x7f\xe3\x19\xfb\xef\xd9\x0d\x1b\xb9[\xfc\xe5\x81\x1e\xb1\xb6\x8b\xfb&\xbe\xea\xf2\x81\xfcN\xaa\xe7\xd6O\xbf\xff\xf8\xfe]\xfb/\xcf\x9f?\x7f\xde\xe7\xbd\xfc\xeex\xb6\xd4\xf6\x84\x90\xcb\xa5\xdaL\xb5}\xad\xaa\x03i\xf7\xfe\xb6LX\xd6\xc6\xd3o^\xa8\xac\xba\xe36x\x06|\xbf\xe2\xeb\xf5qC<\xab\xf6\xd6\xce\x89\xb4\xb1=io\xde\xe7\x7f\x97\xc3\xfe\\\xb9NZ%!\x0c\x13\x17f\xf9=C\x0cD\x16}\x91k\xefx\xa0\xd8\xc4 \xef\xeb7\xb3F\xafx\x96\x8b\x14\x15\xe7\xea\xe4\xbf\x89\xb3\xbcX*\xce?\x87\xa7}L\xf5\x87\xaazk\xf5\xdd7~\x8d\n\x80\xf6\xfa@\x8d\xff\xc13x\x80Iv{X\x0bM\xfd\x833\x0c\x8f\xa2\xfb\x1d\xdbK\\\xffW\x93\xf8o\xe8\x87\x92\xee\xcew>\xe2/7\x95a\xdb\x9ec=Cq\x0e\xb7\xe5j\xd8\x12\xd5\xd3\xc57O\xbf\xc9\x1f \xd3h\xfe\xd5\xb2\xaa\xebb\x87\x19/\xca,\xd5\xe9\xfe\xe6\x8f\xf9\x1co\x9e\xe3\xcd\xa7\x8c7\xb7\xefQ\"\xbenJnl\xa3Y\x85\xed\xc3\xd5\x0bCd;\xd8\xdcs\xafO\xee['\xc9q\x81\xba\xcc\xad\xd3\xee>\x88O\xe8,\xb7\xbb\xca\xa7s\x94O\xe6&\xb7:\xc9G\xb8\xc8\xa7r\x90\xbb\xdd\xe3\x83\x9c\xe3\xd3\xba\xc6\xad\x8e\xf1i\xdd\xe2\x16\xa7\xf8H\x97x\x8f\xdd}kyjw\xf8Hg\xf8\xc4\xae\xf0\x11\x8e\xf0\xa9\xdd\xe0\x939\xc1\xa7u\x81O\xe6\x00\xf7\xbb\xbf's~\xdb\\\xdfc\x1c\xdf\xa8\xa3\x1b\xb16\xfb\xfaf\x9c\x93\x1bqj\x0fti#\x0em\xaf}\xd43\xf8\xdc;\xe8@G\xf6\xd1q\x8d\xf1\xf7\x17\xfe\xbe'va\xf7\x1d\xd8\x13\xb8\xaf'u^w7\xc3\x91\x8ek\xc4Y=\xc6U\xed\xf4\xd5Z\xdc\xd4^'u\xdf/FwP\xf7\xdb\xfe\x1d\x1b\xeb \xd74e\xb0>\xb7\xb4}l^\x97t\x80C\xba\xed\x7f\x18\xe9\x8cv\xba\xa2\xed\x8eh\x97\x1b\x1a\xe5\x02\xd5\x05\xeds@w\xdd\xcf#\x9c\xcf\x04\xd7s\xb8\xe3\x19q\xfb\xfa\x9c\xce\x13\xb9\x9c\x91\x9e[\x922\xa9\xb3ybW\xf3\xa4\x8e\xe6)\xdd\xccV's\xd7s\xd7u0O\xe3^\x9e\xcc\xb9<\xadk\x99\xe6X\xf6\xba\x95\x89Ne\x8aK\xb9\xe7P\xee\xf7Fu.\xba\x9d\xc9DW2\xc1\x91\xdc\"yJ'\xf2\xc4.\xe4\xe9\x1c\xc8\xd3\xb9\x8f\x87\xcf\xae\xd7u\xecs\x1ck\xf5\xedp\xda\x0d\xf1\xd8\xd5\xef\xf0~\xb8zQ\xe1j\xfb\xe9\xb6\xe2F\x97\xe3<\x88<\xa6'-\x1f\xaaJ\xd2H)gJ\xbe\xf2Zw'\xdc\x95\xd5\xf1*\xa9\xd3\xe6\xd4\xfe\x83\x92\xf6\xc32\xf6\xd3\x01\xa9\xfa\x97iq\x9f\xa9\xfa\x95\x00\x1d\xc7dh6s]\xd51J\x81E\xca\xc3\xdd\xac\n\xa2\xfeZ\xc4u\xc6\x92\x91.\\H\x03\x0bt\xee\xe3t\xb9n\x8a7\xcc\xa2\xf43\x11\xa5\xde\xd0\xde\xc6i\xbc/\xf7Ff\xaa\x0b\x1bF\x1c\xa4\xa8\xf0TZh\xfaq\x06\xd0\x17&\x0c\xae=\xfbj&\x9av\x95\xc2\xee/x\xcb\xbe*:4\x1aE\xc6\x85\x1c\xa9\xdc\xa4x\xa6d\xd6\x90(\x19{\x14X\xb8L\xe3\"n\xdd{\xd7n\x15h\xbe3 {\x91\x16;\xec\xa2vK\xc4\xfb\xe5a\xf2\xea\xf2\x83\xfaHZ\xb5\xb0\x157\xc7k\xe6x\xcd\x1c\xaf\x99\xe35s\xbc\xa6\xf1\xdfs\xbcf\x8e\xd7\xcc\xf1\x9a9^3\xc7k\xe6x\x0d\xcc\xf1\x9a\xd6gs\xbcf\x8e\xd7\x18\x18>\xbb\x13\xc5k\xf4+re\xaf\xb4P\xc7\x06\xef\xbfvj^\xe5\\~\xbc\xbe\xb8\xfe\xf4q\xf9\xe9\xdd\xc7\xabW/.__\xbez\xe9\xfc\xee\xe5\xab\xab\xf7\x1f/\xaf\x97W\xaf>\\\xbew\x7f\xfa\xc3\xfb\xeb\xcbw\xdfQ\xbe\xbc\xba\xf8\xf8\xd1\xd3\xef\x87W\xbf\x7f\xf5\xe2\xda\xf3\xd1\xeb\x8b\xcb7\x8dO\xea'T)\x83\xb5\xfb\xb8\x8d\x03\xf3\xa3\xe2\xb4\xe2\xa5\xb2|\x1b\xb5\xfb\xaaY\xd0\xcf\xfe5\xfc\xb1-yq2\xddId\xa7\xb0\xb9\xde U'\x87\x9c%U\xe7\x0bw_\xed\x89\xebw\xd7\xfe\xbd\xe1\xd1\xaf\xdd\xdf\xba\x1bX\x97J\x0djR\x94'\xb8\xd1q\xdb%n!\xa5%\x18}JZ?\xd3\x08\xd1\x0e\xf9P:\xb4\xd8\xf5 \xd0\x7fw\xf4\xdc\x9ad\xad\xd7v\xac\xe9\xc9\xd3\xb7H<\xdd\x1b\x91\xee\x13`~\x19C\xc2\x8a\xf3\x142\xfeg\x1e\x15^J\xf4\xba\xe9\xd3\xa1\xff>\x86\x8a\x0d\x8b\x93c\xf7\x9b8e\xc9\xb2`Ir\xb7\xd4N\xacA^\xfa\x87w<\x7fH\xf2<\xb0U.\xed \xd2\xb7\x0fSAC\x9a\x8a\xa5\xb4l\x967\xbc\x10\x84\x06-\xc5r-\xc7\xfeA\x0d\xbd\xc1VU>\x8cekP\xac\xa9\xc2NHh\xc5\xf01/W\xfb\xb8X\x16\xf1\x9e\xfa\xc8l\xf7\xa9\\\x13\xa8\xe2\xe9z\x0c\x1a\xfdV\xf9\x1c\xde\xfc\x99\x867\xabG\xe4\xf3\x82e\xa3\xa4\xa5\xc23JXZL6[j\xe7A\x81\x8cW\x9c\xd9K{0\xab\xf4\x8be! !\xc6\x8f\x0d[\xa8GZ\xd3\x06\xa2\xd8?\xbe-\xd4\xfa\x19f\xf7xl\x1e\xaf\xbd\xe3\xb4u\xc8v\x0e.\xe8S\xd87\xf7e\xdb\xf8&\xe5\x14vM\xc7\x96\xb8w{\xc6\xdb\xffi\xec\x98\x8e\x0ds\x9f\xf6\x0bn\xbb\xdc\x97\xddr\xb4Y\x1a*\xa6z\x14H\xc9E\xf0\x1dR\xcb\x06I2v\xd0l\x08\xa0\x04[z\x97\x87\x91\xb47\x07\"l\x0b\xc56v\xf8\xaf\xfb\xee\xc4\xe0\xcd\xbf\x87i\x8c\x05\xd0C6\xf1\xeb\x12-\x8bg\xd2D:\xe8$\xd39\xf3K;\x8b\x8b\x92^j\x88\xf5d\x976\xd1\x87\xbf\xee`\xd2\x9dNk\xdeZ\x97\xb9S\x80\x1du\x02,\x8b}\xa0\xcd\xfc\xdf\xf8\xe1\xd2\xe9\x94\xc0\xc4j\xe0$\x8f\x93\xfe[\xb7\xba\xf7(u\xd0\x96/\xad\x1aP\xb17\xf4\xcc\xf5G\xe6\xfa#\xa7\xaf?\xd2\xdd\x0b\x02\xf6\x9a\x9c\xb4\xd9\x0c|\xb3\xb1:g;\x9fnl}\xd3O\xd1\xd5/8f\\?\x96P\x88\xea\xfbA\xab\xc0t\x85\xbc7d\x95\x9c\x16\xadox\xba-v&\\\x88fM\xd7\x19\xd3\xae1\xb7?\"\x0c\xbaj0h\xd4h\xc2>\xcc\xc6\xef\xf0}o\xd2]o\xbc\xf1\x0b\xdd\xc1\x8fJ\xfb\x07O\xea?\x90WK?\xfdm\xc2k\x00`\xb9\n\x00\x9d\xeb\x00\xa0}\xd0\xee\xf5\xd8\xfc\x84\xb0\x1a\xd5\xe7\x83\xd6\xe2O\xa5\xc8\xca=\x91\x99C\x93\x0c\xab\xd9?\xf0,\xe2i!wQ\xa9\xb0\xd4.\x96\x17\xec\x0bo<\x18q#\n^\x89\x87\xde\xd6\xfa\xbb\xf2\xaa\x97\xaa\x1a\x894\x8f\xd7\\\n\xa4r\xa65%\xa7\xd8e<\x97\xf3yOc\x94\x12\x92\x15U\x0e\xc7\x7f\xf2\\\x8dH_\xebh\xca\xbb\xb4B\x16\xf0R{\xe3p)\xfa\xf5\xe2\xb7\xcd\x81\xdc\xf0B,\xefy4\xda\x04\x10\x1b\xf8\x81Ws\xa3\xd6\x84zN\xbc\xfaO\x15^\xef\x0e\xcf;cr0|]3\xc0\x0c\xf9\xe9\x93\x7fEN\xb1S?\xf4\xdb\xb2#*\xa2\x83- 3\xdagCV\xdd\x84.\xa7\xdee\x1cp\xed\x8d\xf6\x9d\xb1\xb0\xbc=2\xfat7\xe1%\x1d\xf0\xbcA2\xe5e\x1d\x98\xf2\xc2\x0e\xb8_\"\x19uq\x07&\xbc\xbc\x03\xde\x0b<0\xf4\x12\x0f\x8c\xb9\xc8\x83q\xec\xee\xa0\xe4\xc5\xfa*\xc9\x88\x0b=\x08.m@Y_&\x19w\xb1\x07AW\x1e\xac\xaf\x93L}\xc1\x07\xc6_\xf2\x81\xe9/\xfa\xc0\xb8\xcb>0\xee\xc2\x0f\xbeDQ\"'\xbb\x06\x04\x93_\x05\x82)\xaf\x03\x01\xe9J\x10Ly-\x08\x9c\xaf\x98\x8c\xbb\x1e\x84\xadq\xf4%\x13\xadj\xbc\x97\x86`\xf4\xc5!\x04!\xf6\x9e\xc9\xe0\xebD`{\xd3\xc4\xb3\xc5;\xde5\xa1\xec\xff\x03\xaf\x18aj\xcf\xfa\xba\x89\x8f\x8eq\xd7\x8d:\xc8\xd4\xe5#\xf4\x8d\x93I\xae\x1d\xc1\xd4W\x8f\x00\xb9~\x04\xe3\xaf u\xb0\x15\xc8k'\xe3.%\x81\xef\xae\x0e\xb8\xde\x18\x9d\x7f0m\x06\x02%\x07aD\x16\xc2\xb4y\x08\xa4L\x84is\x11\x08\xd9\x08\x93\xe7#x2\x12\x86\xe5$\xa0\x88\x9cy\n\x93d*\x10s\x15\xd0\x96A\xf9\x0b\xa33\x18\xa6\xcea\xb0g1L\x9c\xc7p\x8aL\x86\x89s\x19\xa8\xd9\x0c\x13\xe73\xb83\x1a&\xcfi\xb0g5\x04\xe45\x0c\xcfl@\x91\xd9\xca\xa4j\x18\x91\xdd`\xcdo\xf0\x9a\x14\xce\x1c\x07\x9a\xc51]\x9e\x83;\xd3\xc1O\xcd\xa4\xd9\x0e\xee|\x87\xc92\x1e\xc6\xe6<\xf4\xd0)\x8b\x065\x1e\xa6\xcd{\xb0e>\x8c\xcf} \x04\xfc\x9d\xf9\x0f\xc4\x0c\x08k\x1850\x0b\xc2\x8e\x07\x89-\x8d\xce\x85\x08a\x0e%\x1f\xc2\xcf\x05RNDpV\x04\x1ey\x9b 3\x82\x90\x1b\xe1\xcb\x8e\xf0\xe7G8\xb9\x16\x92#A\xcb\x92\xc0\xf3$FgJ\x90s%\x86fK\xd8\xd9D\xca\x98\x984g\xc2A\x0b\"\x89\xa32'z\xd8\x90L\x8aIs)l\xd9\x14#\xf3)\xfa$\xf7\xf3+\xa6\xcf\xb0\xf0\xe4X\xe0Y\x16x\x9e\xc5\x94\x99\x16\x13\xe7Z\x9c\"\xdb\"$\xdf\x82\x98q\x11\x94sA\xcf\xba\xb0\xe4]\xd8\"\xed\xf4X\xbb?\xf7\"(\xfb\x82\x9c\x7f\x81\x0eh\xea\x1c\x8ci\xb30,y\x18SgbL\x9d\x8b1^FH\xf9\x18\xb4\x8c\x8cvN\x06\x9e\x95\xe1<\x83a\x99\x19a\xb9\x19\xfe\x00>\xa1\x81+?\x83\x9c\xa1\x11\x90\xa3A\xcc\xd2\x18\x90\xa7\xe1\xcb\xd4\x986W\xe3\xfe\xb35\xfc\xd3}\xca|\x0dk\x86\x84W\xa8N\x97\xb3\x11D\xd3i\xf36\xac\x99\x1b\xff\x98\xdc\x0d_\xf6\xc6\xfd\xe7o`\x19\x1c\xfe\x1c\x8e\xc1\xb16K&\x87/\x08o\xcb\xe6\xf0\xb4\xc33:<\x8d\xdcY\x1d\xf4\xb8\xfft\x99\x1d\x8e\xdc\x0eR\x04\x15\x8b\xa9\xfb2\xaa\xf0?\x86\xe7\xcf\xe1\xe9\xe7\xca\xe1\xcc\x8aj\x10\xcaIu\xcbU \xfbi\xf7@q\x99\xaa\\\xa1\xce_u\xe8\x18\xff\xbb\xf7\xcf:\xff\xdd\xe2\xc2\x00|G\x19\xebb>\xfe\xd2\xeeC\x9d\xecnL\xcd:koZ\x81\x07.\xe1\x96\x84\xfeQa\xe0\xeb\x86H\x1e )\xd3X%v\xd65\x0d\xd5?\xf2C\xd2\xac\x9bjw\xd3J\x9c\x0dlz$\xa9\xdfqq\xa1[\xaa\xa2\x88y\xd1\xf5H]\xbe<3>D\x9e\x9d\xd5/u\xf6\xf8\xd4\xaf\xc0\xd7\xb4P(\xb6\x8f\xa2\xc2]}O~\x12\x9e@\xaf\n\x0fv\xcd\x9e\x9fy\xf2\xfb\xbfg\xff\xf7)\xfd\xdf}k\x9dz\x02p\x14\xe0V\xce\xd1\xabF\x19|\x82\xed\xdf\xadW\x8fN\x01*O\xf6\xe5>\xb6>}\xa7\xbe\xb9\xad\x1a=R\xbb} \xf5\xff\x86R\x9f\x0d\xa8<\xdf\xbf0\xd3\xa8:o\xab8?\x90j\x94\xe7C+\xccwx\x1eTO\xbe!w\x1d%\xa8\xfe\xa4dX~\x12\xa7\xdb\x8a\x04\x91b\x8a?\xc7\xe4\xf9C#q\x83 \xcf\x9d\x88\x0b\xc2\xda^\xa4\x05\xf9\xa6\x1daA>\xc0#+\xbd\x0f'\x8e\xa84x\xf3C\x1d\xa9 0\x05=};\xa5\xae\xa5h;gm\xa4a\xf7\xa4a_]\xe3\xce\xd4\xed\x08\x04r\x9a\x1e{\x8e\x86\xcbf\x07\x9d\x13\xf4dgg\x94\xf5\xdd\x03\x17\xe5\x90\xe5:X\xf9\x0eS\x8e\x03\x14\xe1\xd0D<(\xf5N\xc1\xa7p.\xe1\xe7\xdc\xd95A\xcceEN\xac\x93\x9dU\x89\xa7\xd4\x93\x9fO'>\x99\x9e\xf2L:\xe5i\xf4^\xce\xa1\xf8 \xd4\xb2\xfc&\xcb\xd8\xfa\xbaI\x9b\xed@R\xe1\xa0\x1dD\xfaz\x8a<\xe4\xaem\xf2\xdf\xc7\xf4sY\x19\xd3\xe9\x0b@uF\x7f$\x93\xe9\x8d>\xea\x81\xba\xa3\x8fh\n\xfd\xd1\xc7:D\x87`X&\xd4#\x80X\x0d\xee\xb3\xf3\x18KA.\xe4}\x9c\x16r%\x07*,\xd9l\xd9I\xc0GWp\xe5\x85,\xaa*\x1d\x91\x88\xd5\xfdE\xd9\xbe\xfa&N7\x89r\x08/\xa5\xb0/u\x89\x1c\x1a\xd6}\xf5\xaa&K\xd3\x92%Uu\x1d\x88\xd3#N\x908{\x1d\xed\xd9\xd7\xb0\x0e|\xf8<^\x93#\xbe\xca\x19\x85\xe2\xdb\n\x96,W\"]s\xdf\x16Pa\x93\x0d$S+w\"\xe8\xb6\xc0\n\xb17\xf7\x80V\x89\x88\xbe\xe4rcY\xdeq\xe6\xf6UX\xbd\xc9Uw\xba\xb2\x18_WHe\xb7 \x91\xf6\x85\xb2\xdaa\xf4M\xd6\xc6C\xa2\xc6i+g\x1f\xf6b]&\xbc+\x87\xca\x9f{\xa1\xe6\xf3*\x137q.5]p\xe2\x86\x16\x88\xe5\xa1\xc6@\x1c\xb8\xdd\xa7\xd8\xc3h\xdc\xd2UM&5&u\xebW\xcbb\xe3C\xe5\"tY\xe6\xce1;\xdd\xdfM\x04O\xba\x18\x10\x7fx\x8b\xcb\x97F\x08\x83\xd9[\x8b\xefh\xb6\x1e\x17\x82\x85\x9d\xc7\x0fhl\xec\x0d\x8a\x12>\xa8\x1bY\x13\xa8[\x8c\x1b\xf8$\xb8\xf3\x1d^\xf7\x0b\xbc\x95}w\\2M\xa6\x93\x02e\x98\xc2\x06\x973\xc8\xaf\xb8\xc1\xaf\xbc)=\x84)q\xb0+\xf2\x90\xce(\xb8\x89\x97\x0eh\xca\x1dl\n\x9e\x82\x99\xa0\xe8\xc1\xa5\xec\x9d}\xf8C\x88t\xc5?\xf5\x03\xbazU\xd4\xf6\xc9\x8b\x86x\x11\x16\\^\xae\xf2\x03\x8b\xdc\xc6D+x\x8c\xfc\xde\x89[\xb9\xad\xb1Z\x175\xc8m\x1a\xa8q\xba\x8eo\xe2\xb5\xda \xcc\xea\xae$^\x97q\xd1\x05;\x9bH\xe4'\x1a\xd1U'\xe0qd\xceh\xad\xe4RJ-\x9ddr\x01j\xea\x07)\xa3\xfe\xc4\x80]B\xa9\xd1}\xa4\"\x9f{\xb2,\xc2:HP\xf3\x84\xe5\xbb8\xdd\x0e0\xa5\xf3x\x9b\xf2\xf5\xb2Z\xbc\xb7q\xba\x16\xb7\xc4}\xb5\xb9b\xf7q\xba\xacPI\x05\x10\x84\xa7\xb1?\xaf\xc5mZ\xc4{\xbe\xfc3\x8b\x93\xe5\xba\xaa\xd9\xe1\xc4\xa3\xc6\xbe\xdc\xa8:\xb7\"]\xaeE\xb9J\xb8\xa2%\xbc\xfb\x1e.MM(\"\xcc\x1a\xad\xab\xb6\xf4v\xd7\xba\xd2\xe5Jgi\x98\xc9\xec\x98\xa8\xcd9\x1e\xbd\xe2z\x16)m\xe18e\x05(j\xbe\xab\xe5=rC\xc2\xd9I\xa7\xf1\xc9\x90\x03'E\x96\x1c\xcd\xad$y\xe5*\x1c\xe9\xe42V\xef\xb7S\xed\xa26\xb9\xfd\x18o\xd38\xdd^\xa6\x1b\x11,\xbc7,Q\xd3\x11\xa7\xdbe\x9cnz1~\x92\x18\xb3\xf5:\xe3yN\xe2\xfe\x9fU\xfd\x8ae\x99\x16qhR\x94\xa5~Ae\xd8\xc6{\x9e\x17l\x7f\xd0\x9e5V\x88\x0c\"\x96\xa6B\xd5V-S\xdd/\xa8~\x1b\xed\x0b\xb1_\xe5\x85Hq\x13n%D\xc2Y\x8a\x0b\x0f\xf2\x9b-G\xebv\xc7UH]\xd5\xd0.L\xa5WE\xe3\x8e\xe5\xba\xca\xc8\x91\x12x\xf4%N$\xb1\xa2,@ts\xb6\xea\xa6\xdd\xf0b\xce\x8b\xc7-E\x90\xe7G\xdd\xa2\xb2\xbb\x88\xd7-\xed\xca\xa5a\x1b\xabl\xb9\xca\x80\xac\x90\xc3\xa3\xba\xbcs.Yo\xaa\xce\xa8 8\xf0\x1b\x955\x17\xb7\x8b\xfb\xaaX\xd32\xe7\xc5\xd4\x14\xee\xc4-\xecY\xaa{l\xb8\\\x15\xd3\xff,t6\xa4v\xd8e\xad[\x0c\x0eg\xaei\xdfXp\xcd\x08\x9c\xf9\xf9a\x0e\xd5\x92\x92g\x07\x9d\x81\xb4\x17i\\\x88\xce0\x8a\x1d\x8f[\xd3\x98\xc47<\xe5y\x0eR\xaf\xdd\xc4\xc5]\xc3\x1c\xd3\xc3\xea\xaeW\xa3HZ\x1d\xaa\xe4?\x95\xd5\xa7S\xc9T\xc0\xcf\xac\xd2\xa6fj_UF\xf4\x08EO5\x9aU\xd8\xe4\xa9\xbb\xfa'Ys\x85\xef\xbb\x98\xba\x9a6\xdf\x02\xd5k\x0e\xa1\xb4\xeb6G#\x9f~\x1b\xab\xe1\xec:\xce\xa5\xe5\xdcz\xce\xae\xe9\xa6\xd5u\x0em\xd7\xd3w$\x8dG\x9a\x87\xbeN\x99^\xefy5\xdfXJ\x07\xeb?w\xd2\xcc\x08\x1d\xd8\x9e\xabZ\x1f\xf6\xb5 E\x0f\xbat\x1fK\x92#!\xc6\xa1\x82%\xb8\x07\x988sb\xba\xcf\xab\xf4\xf3OL\x07gb\xb1\xee\xb2\xb1\xed\x89V\x11\xd08\x85\xad4\xc5\xeb\x9d\xb0\xaa\xc0\x99K\x85\x97qh\x17\x15\x8eD\xa6?T\x95C\xab\xcd\xb8.\xda)\xf5\xa0:@4\x87\xd9\x1a\x9b\xf9\xf2\xa3\xd8\x1f\x89B\xebvf\xfc\xc0U\xc1\xf9oYVs\xd6Va\xb65F%\x1e\xdd\xfa\xb2\xba\x1c\xa7\xcf<\x08:\xc74\xdbU\xf8(\x06\x02\xa6i\xc8\xb6Ao\xe7F\x04\x1b\xdf\xad\x9d\x0e\x89\xfe\x0e=|o\xc6ve|?\xb6\xed\xc4\xd8\xc2\x9bj\xf7E\xf7\xdd\xc6\x8e\xeb\xd9k\x9d\\D\xa3\x91\x93\xec\xac\x8e=5\x9c\xa2A;\xa8%ml\xf8\xae\xd9?9\xb4\xf6Kt\xa7TK\xa9PO\xd4\xc8\x95\xf4\xadH\xd7\x1f\x1b\x85u{\xach\xa7\xe9}\xfb\xfe\xddK{\x95\xd8\xee\xef\xf2\xbf\x9c?^\xbe\xfb\x0e\xfd\xb5\xd1\xb0N\xb4qu\x8dk\xee\xe3\xd8jk\xa0QN\xb3fl3\xcb\xce\xd2\xc93@3dR\x88\xd3*W\xa7\x9e\xfcNiY\x9c%\x12\x9f\xfe\x176\xd3:3\xbfz\x9aG\xc7\x7f\x9c\xf8.\xdf}g\x10^\xbe\xfb\xce\x89\xb1LWz\xdf\xb1 4\xe4\x11\x88;\x12\xd6\x11\xa9\x17b/\x17lH\x82XT7Q\xb1E[\xe0\xb4\xa5\xcd\xbamZ\xb1\x0b\xf5\x1e\x98:\xdc\x9a\x8f\xa0J\xafR;\xb7\xf1\xd05\xd1e\x9c\xe9\xa0~S2\xcc\xaf\x01\xd6\xa0\xec\x87h8\xb5\x06\xf7P6\xacC\xe3m\xba\xd5\x83}[\xadS\xd6<\xe1[e\xbd\x9e\x81*jn<\x9d\x8b\x87\x0d\xe4{\xf6u9\x94\x92\x9e\xb5f\x90\xb5Xl\xc2\xab]Ru\xa1\xca\xd6V\xd7A'us5\xa2\xee\x10:#\xd0\xe1\xb2i\x07\xd2\xc0\x89\x8eg\xcd\xe2\xe4\x0e\xe2T\nDny\xbd\xb11\xbaz\xf4\x96\xa1\x94\x07i\x18,\x03\"\x1b\x9eWN\x1b\x08\x8d\xb4\xa8\xf7\x1b\xd5\x1f0\xd9\x91\x86\xb0\x1e4\x96'z\\\xad57\x1a\x08: =&\x03\xb1\xb5B\xac\xcb\xff\xc3q)\x13t@{\x92Q\x0e\x9dh\xbd\xf4\xd7\x8a\xbf\xf7\x96h\x8d]\x1fjE4u\x91kmX\xd7\xc5\x00\xa2\x07\xad\x85\x86\xfd\xd7 \xd9\xbd\x0ep2:\xa22B\x83\x1b\xedm\xb6r\xe6\x14\xd1\x97Z$Bv\xa8Z\x8a\x96\x94\xe3Cg\xc0\xbd\xc6FlW<\xda\xfd\xeb7\xe7<\x8dD\xf5\x98\x84\xfa\xb5~\xfd\xa4jf\xa6\xbe\x1e\xd3\x10\"z\x8diD\xf46\xc3|\xc72\x1e\xd4\xb3nQ\xcdnsdrR\xab\x1f3\x1e\xf1\xf8\x06\xd5P\xb5=w\x9c\xb6n\xf0M\xda\":\xd3V\x15a\xcea\xc7\x13U\xd6\x98\xa5\xc0\"e\xef/\xe0R\x9a-\x15*q\x9b\xea\xba\xc7\"m\xf0\xb9z\x16Q=\xf4)\xa2X\x1d\x9d5\xd6F\xc2\xbd\xb8\xd5\x9e\n\x91\xf2\xee\xb48E-\xd8\x87\xbd\xeeH)\xda\x0co\nn\x89\x05\xf2\x0e:\x95\xe4\x82[z\xe9\x04M%\xc5\x80H2\x9d\x8ap\x89\xee\xa1\xf8[\xfbB\xf0d\x92\x0dSK7t%\\\xc2\x8a%,\xedg[\x11\x05\x93\x9a\x99\x88\xd5n\xf7\xab\x9b\x16g\x07\xd7h?\xa2\x18S\x9a\xfd\xe8\xc22@\xab\xbf\xeeS\x80M\x1f\x9b\xc4r\xc3\x12\x9e\xaa{\xd7\x0dQ\xe2_#~(\xaa\x03[\xd1x\xbb\xb3=\x89\xdd\xf7\x86*\xf9\xadF\x95\xc3^d\x1c\xf22.\x94;V\x9a\x81Q\x12\xcb\xde\x8cc/G\xf5\xdeq\x00T\x85\xb7\x17i\xfc\xc5\xeb\x97i\xb1\xa6j\xd2\x98\xe1]\xb9g\xe9y\xc6\xd9Z\x91\xab\x1e\xca2>\xc7\x9e\x18\xeb\xe7\xda\x0bwV\xa0\xcb\x882\x08\x9a>\x01}\xc5\x83%\xc7\x1f\xeb9\x87G\xfc\xeb\x02>]\x89\xac\x80\x96\xf9\xf4\x07~\xb7b9\x7fl\x08\xbb\xe5\xab<\x0e3\xee\xaa&(%\xe6\xb7$N\xbf\xd4\xfb8\x8f\xca,.\xee\x96J.\"\xd7-\x94^_\xdd\xb6h\xa7|\xcfb\xf5\xd6z\xfd9T\x9f\x1b\x12\xd6\xbc`q\x12dKTM\x8c\xea\xd5\xd5\x08\xea.\xab_\x915\xd4\x90G\xd4\xab\xd1\xf8\x18\x91\xe6\xef\xe3\xbc\x10Y\x1c\xb1$\xc8\xd3\xbc\xe3l\xdd\x97g\x92\x92\xac\xde\x9e\xee\xe8>\xed|\\\xb1<\x8e\xb47T\xb9\x02\xdb\xdf`}\x80#\x90]\xe5\x12w\xff\xe8\xd8\n\xc1\x1d\xf3\x01`\x87\xc3t\xe8\xdc'\xfa\x17R\x01\xa5y\x99C\xc4\x0eZ\xad\xea\xf3\xa0\xf9sV&\xc7z5\x11\xcfs\xed\xe31\xdc\xeb\xa0S[\xae\xfc)\xda\xb18=\xeb\xd5\xf4N\xa3\xa4\xd4\x0f\xbe%I\xe3Cyfgrle\xa4i0\xf7\xa3u\xef\xa8\x0f\x81\x1d\x9f`\x7f\xd8+\x86\x99\x17\xf2HVd,\xcd\xb5^\xde\xb3h\x17\xa7\xadW\x9bU\xcf\xd4Z\xeb;\xe4~\xbauFl!\xe4\x01itX\xde\x82z\xc1P1\xafO\xbd\x96\xf0C\xc6o&\x14\xf0\x1d\xcbw\x03\x05\x12y\xbb\xfb\xc0\xb2B\xc5\x11\xba\xcb\xdb\x80\x95BpR\xa9\x9a\xf6\xc3\xae\xf5O\nk\x9c\x16|\xcb3\xf4\x0bW\xe4\x1f\xacl\x00\x1f+\xc0\xcd\x8ez\xd2\xaeXV\xe4\xbc\xf8^q\xa5;\xdd\xea\x18_,\xfb$x%\xc8\x16&\x97\xa8\xf4\xda\xd2\x82\"\x97`\xe3;\xf9\x9f\x13tw\xcc\x15\x98\x00Y\x97\xf6M&\xf6JM\xb0\xc3\x01DY\x1c\xca\xe2\xf8\xb7\xe3\x1ah`P\xa9\x00\x93\xd2Tk\xca p\xb1\xc3a\x02,J^\xaah\xf5\x04\xe8\xf8\x8d\xb4\xc3\">\x01\xaaz\xfe\x8e\xdbKG=\xe9[\xd8<\xf4\x88\xebO:\xd6\xab\xaa\xe5!\xab\xb7\x1b\x1d\xcf\xba\xe6\xe9\x9ag\xea\xba\xa5^\x10Z=5|G9\xef\x19y\xd3\xe6\xc4\xc9\xbf\xda\x0f\xf8N5\xe3\xde\xe5\xfb\xa8[\x9c\xb0\x1d\xf6\x1f\xf6\x9f\xc83x\xfe\x8fr\x18\x80q\x17\xc4\xa9zzu\xd1\xfa\xfe\xb84\x0e\xe5\xaa\x97\xdf\xe3\xd4\xf3.-/\x9b-\xcb\x0cU\xf3\x1eE\xec\xe3\x12\xa8:.\x9f>\xbcy\x92\xf1\\\x94YT\x1d\x80\xd4\x11\xb0L\xe3\x9fJ\x9e\xdcU\xe7\x92M\\q\xaf\xa8\xae\xfdaO_\x83:(\x98'\x98\xf1\xd2\xba\xea\xd8\x1a\x89\x04V\xe5f\xc3\xeb\xe7g\xab\xcaez,\xb0/\xf3\xfa\x04\n\xac\x80\x84\xb3\xbc\xc0\xf1\x89\x94\xc3\x83'\x0f\x94\x17\x9cE\x05\xcf\x16\xea\xf0\xad\x82\x1c9\xdf\xca#\xb6\x99\xe9O\x1f\xde<\xcc\xe1\xc0\x8a\x9d\xea\x00EW;T\xf0\xde\n\xe4\xcdn\xc5\xb3\xaa\x0b\xc5\x9dGL\xaet\x1c\xc1g\xd9\xbd\xf5\x05\xdc\xcf\x8f5\xf5\ne\xbe\x13e\xb2\x86\x95>r\xa3\xd8\"\x96\x8aT\x1e4\x94N\xc0{|\xc4\x17\xdb\xc5\x99d\xa12E\x1f,\x1e\x98`1\x8b\xe4\x89\x9f\xaf\x1f\xe3\x8f\xcc\xa9\x8a\xe8\x07\xe5\x98\x8f\xf8\x19\x14\x9c\xeds(\xf3R\x15\xdd;d<\x12\xfbC\x9cH\xea\xaag\x87Wq\xca\xb2;U\x02\x0e\xc3&y\x93k\xe1*v\xfc\x0e\xefR\xdf(\x84\xb805\xee\xaaZ\xb0R\x18\xf8W5\x95\x17\xe9\xdd\x02\xbe\x17\xb7\xfc\x86g\xfan\xdc\xa7\x0fo\xfak\x17T\x0eK\x1c\xed\xccc\xebx\x87y\xb4\xe3{\x0e\x9fwEq\xf8|\xa6\xff?\xff|\xa6\xd3^\xaa_\xcf\x94\x94E\x8d\xe3jr\x87\xd6\xab\x07\x15\xc2\x03\xa6\xc6j\xe9\x8fg7\xbc\x8a\x8b\xef\xd9!\xd7\"#G\xa0.\xd1V\xd9ZJ_)[>\x07\xe4\xe9NP\xbb@\x92\x88\xdb\xfc\x99e\xee~ \x97\x9b\xe3\x08\xe4\x94\x9bw\xf3\xebAV\xde\xbdr\xcf\xd7\x96:\xd8\xbf\x84\x8b\x14\xbe\xbf\xbe\xbe\x82\xef^]\x83H\xcd2\xd2\x0bT?\x1c\x8fKf\xef5\xe9\xeb\xbb\x03\xff\xf1O?\xa2\x1f\x83\xc9\xb8K\x8d\x0c\xe9-N\xcd\xc2!\x13\xeb2\xe2\xc0R\xe0Y\xd6\xf6\xc9\x1e\xe1\x97pq\xb8'j\xc9\xbf\xf1\x18\xd1\xcd\xe6\x0b[\xf3\xf3a\xed\xb6\xdd\x11\\\xff*\xfd\xf0\x91\x0cc\xdfy\x97\x8d\xf4\xe0\xdc\xb6\xc3H\xaf\xf9\x97\xf1A\x88\xe6\x87\xb9\x0fW>\xfb\x87t\xed\x0f\xe0m\xc5\xb7|l\xbe}\x03\xdfb\xab\xc6\xec\xee\x89\xe8\xd1\xb7\xaf|\xb2x_\xde7{&\xef?\x8b&\xff\x83\xf7a\xd6\x17\xeb\xd9\xd4\x0e]\xdc\xca\x83\x819'\xc4\xd7lG\xf8Jv\xbb\xd7_\xba\xfe\xab\xc8?\xb9\xe7\x99\x932s\x04\x9f\xe4\xe6\x14|%\x0cPk^\ne\xa4U\xcb&Zw\x87\x9c\xeb\xf9\xb4s+\xf9\x95/\x085\x0f\x05\xb5\x9f\x96\xd3\xc2\x97\x93\x954\xc2~\x96\xd3\xd7\x95\xc7\xab\x99f.\xbc\xe4\xd0\x159\x14\x8e[Ay\xce\xfe\xe5\x7f\xfe\xcbw\x9eI\x9e;G\xcc\x8a\xfc\xd3\x84\x0f\x03\x13\xf7\xc3\xc9\x1f~\xf8\xc3\xf8\xad\xe7\xb3\xeb\xff\x12`.\xdcS\xbc\x06K\x1d;\xf1H\xf0\x98\x025*\x88\x97\xe1\x06\x9f\xd1]\xf2i\x1ec\x12\xf8\x0dG\xa0\x82\xc8p\x8c\x98\xb9]\x8e\x1aNh.fb\x88\x01\xb7\xb1Q1\xf0RT\xfa\xfd\x04C\x91\xff\xc5=\x96\xa6\xd8\xc0\xb1\xd5wsA\x18\x9c\xe4\x7f\xd2\x80)\x85\x1f\x9b\x01K\xbe\xe7PaI &UD\xa2\xdf\xda\xd8\x89L\x13tS\x13\xb9\xdf\x8c\xff\xf6\xb2\xed6\xbb\x13\x18\xc9\xee\xf6\xf5\x9c\xb7h}\x819\xf3\x13K\x93Lo\x0f2gm\xd1s,G\xdc\x8e$\xfe\xd8\x8e\xe3Q\xf8\xfa\x9a`Dg\xce\xef\xb7;`e\xa0\xe1?\xe9\xff0\x82J\xfa\xdf)\x19\xf6\xa3?\x8dL\x15\xba. \xe4\xe4\xbd\xcd%\xe2\xbc)\x99\x0b7\x177+n.K\x1a\xe4q\x17\xad\xcf\x99C\xc5\xf5\x83\x93=7\x17'\x8fn.Kz\xb24\xb7n.\xfe,\xbb\xb9,i\x89gLW&\xe4\xa1\xb2\xac$\xbd\xb98\xe9zsY\xd2\x85\x05)|\xaaL\xfb\xc55\x96\xc7\x14\xac>\x94\x14\x13\x1bY\xbbZ5\xaa\xaf\xd8\xb1t\xfaQ\\\x8c!\x9fhT:0\xbdo]]eo\xc9w\xc7\x0e\x81dZu\xbbYWI\x1d\xf61\xc6\xa4w\x9a#\xca\x02]\xde\xb3\x83_\xbb\xb7\x19\x8a\xe7\xa2\x81F{\x1e\xfc\xd8\x11J|\x1d\xdeX\xb0\xd1\xb9\x18-\xde\xb8x5j\x02\xc0f\xccZ!\xfd\xecG\xa7\xce%6\xaa\x98\x9c\x05x'T\xde\x14\x10 cW\xe7\x12\xe8?DS\xd30d\xeb\\\"\n\x00\x12\x87\x08d5+p}^y\x18\xb8t.8Pv.\x05;\xb6\x1c&\xe8\x15\xe5\xc2\x07\xe3\x80\xda\xb9\x04\xa1\xb5s)\xdc\xf5\xc5`C\xaf4\xf3l\x11\x85\xe0\xce\x05\x05\xe3jr\xd3Be>\xcd\n\x89\x03\xb2\x06\xc1\x8b+\x14\x1d\xd5\xab\n'\xf9$\xbb\xdbk\x0c?&J\x86\xed\x8eHwN{/F~\xb6\x80-\xd9\xec\x9a\x81l\x15[\xb6#L>\xa5\x04\xe9\xfd\x08\xb5\xe3\x9f\xb4\xac}'\x93\xff\x15\xd0\xfeN\x1c\x82'p\x938WH\xf4\x8e\xcct\xc2%\xbe\x10\xbc\x06\xea\x0c\"\x9d\xad\xed\x00\xe4Q\x92\x95\xf3\x0f\xc2\xb7\xb3\xb6\x1bO\xe0R\xb2\xd2\x18\xe2T>\x82\x9d2\xd4\xb0!\x11\xb3[\xfaL\x0d\xb1\xafD\x82\x03\x8f\xcb\xf7\xc3@6\x146\xcdns\xdc)w\xa3!\xec\xf6\xc8\xacc\xb3\x82c7\x8f\xe6\xc8\xfb\xdf\x1f)\xb4\x94\x0cb\x7f\xe8\x1f\xf8\xf9`:0\xc1?\xdf\x93Nt\x05\x9a\xc1\x9c\xcf\xfa\xb1\xd1\xac\x85\xe7\x03\xe8\x03n,\xc7vd\xfb\xd1\xb6\x9d\xe0e\x8d\x0e\x8e\xfbz\xdf\x8ff=\x13\xf7\x93Y\x89\xfe\x19\xda9\xb5\x83W6\x7fI\xd1\xf4\xb9\xa9\x9cr[\xf8\xe8m\x83D\xe6*\x98\xb5\x18\xe3\x7f\"/M\x92(8\xa6Yo\xc8\xf4 \xc8\x96\xfb\xe2\xf9T\x92\xa4\xec\xa2y\xa6\xc4\xfdqG\xdb\xc3\xae\x15\x8d0\xe5\xf3\x07\xf1\x99m\"Lf\xdf\xafH\xe2\xe4\x13Q\x1bq\xc1+\xd3vB#\xb1q\xe5\xe8|)K`\xf4y\x12\xe8\x143\xe2\x10A`u\x88~\x1c\x9a\x81\x0f\xa0\x04\xb9HjZ\xb6r)\x9f\x89\xc2\x88=\x90A\\\x06\xc7\xdd{\xdd\xafR\xd8\xbe\x9fs\xf7\x06\xc2i\xea\xcd\xf6\xab\x1f_\xfe\xda\xf1\x9c\xa4\x91\xd0\x89\x0c\xd7\xae\xf0\xd7\xfb\xe9\xd5k\xd2\xd1\xa1%\xe3\xaf\xb3\x0d\xc7\xcft\x16\x1ag!\xe9\xb6\xcf\x92F\xb5\xa0\xf1u,SX\xea9a\x16K\xe7!\x8f\xa9\xdb\x06-\xdb\xed\xe6$m\xbbF;\x85\x1f?\xa1\x98G{C\xa0j\x88\xda8g\xf6\xb4\xf9\x19\xbd)rT\x0b\xb4\xc3!\x10\x90\xa2\xb5\x16\x81\xfa\x13\x0f\x02\xb5\\\x11O\x03\xa4k\x02\x03\xff6\x10\xed\x97\x97\x072\xc0\xa1i\x87\xef\xe9\xd0\xf6\xd3\xa9\xde\x9d'\x05z\xe4\nU}\x99Gu~f\xea\x1c\xed\xd5\xdaP\xadc=L\xba%\xc9\xa8~~\xcb0\x89\xd8\x9f\xb9\xcbf#\xe0\xab3N\x15\xd1!\xbe;\xde\xcc{x\xccu\x87\xad\xaa\xbe\xdf%\xaf\xa9\xae\xa7\xf2v\x8bk\xdb]\x89t:\xf5I\xa3[\xf3\xfd\n}\xcf\xa9\x02\xe7\xfc\xaf\xa1\xd9\xf0\xbe\xa8\xbb1\xba-k\xd0k\xf9O\x81\xf1\x1d\x8f\x87\xc3\xeeI\xc5\xe8\xd8O\xdf\xa8\xf17G\xd3\x1a\x06\xceKW\x04\xb5\x7f=\x18\xef\xa2\xef\xe32L9\xa6\xf5\xe6=\xc3\xf9Oo\x11&\x00\x88Y\xbe1\x9b\x10\xa9! \x95\x1f\x12d\xdb\xee\x11\xf2\x00\xc8\xef\xc3:f\x81\x90 \xbb\x0f\xb8#}I\xc3\xd7\xf1\x0e8b\x9c\xfeg\xf3\x0fX\xf2Z\x07\xd0\x98OI`\x0b\xec\x9c\xbc\x01t\xe0\x1d\xa6\x02X\xbb\x88\x1c\xd6\x02\x08\x7f;\x8c\xbd \xf8J\xf8\x1b\xadf2\xb0\xe4\xe4\xd0\x19X\xa2$\xb9\x81=\xcd\x93\x18\x0e \xd8\xe12L\x07\x9a@#\x7f3\x93\xf8@\x93dP \xf8:\xe4\xd9R r\x01\x8d\xd6?\xdfUe\x9e}\xab\x1f\xe6w\x97s\xa7#;\x98\xb3i\x97\xc5\x8d\xc5<\x15\x8b=\xb6 ;^\xd4\xdb\x13\xdf1\n\xee{\x81\x9d/i\xef+\xd2\x9bb;``\x0f\xf4\xef\x82\xcb\xba\xb0~'\x8c\x8fE\xden\xe8\x88\x13\xec<\xce\x9f3wDW\xde-\xb6'z?\x05\xba/f,8tw\x8c|S\xdf\x0e\x99\xe5\xa1,\xb5O\x16\xdd)}{\xe5\x92\xdd2\xdc\xf5\xac\x1d\xd3\x90\xa4\xf1\x04a3\xa6\xc0\xae\xe9\xec\x9b`w\x0e\xdb\x83\xe6\x8f\xba\xdbY+~|1\x13\xfc\xbb\x9a\x14\xa3\xf77j\x9b\x1f\xb0N\xd1\xd3\x9f\xa5\xbbV\xb5en\xf5\x82\x13]\xbd&\xc0\xcb\xf1\xf27sM\x00\xee\xa1\x88\xda^^SO\x17\xf0=&\x01\xbb\x7f\xd0g\xf4}Vn\xb6\x1c\xebo\xf6y\xfe\xb6\xc6\xdf\xb3\xb0\x06\x14\xb2\xcf<\xb6Y\xd4.\xcbhy![\xcc\xb3\xf9;\xfeSQ\xb0\xcf+\x8a\xf3\x91\xf5\x17V1\xdd\x88\x9c\x85\xbe\xf3d\xf4\x88\x12\xb1\x08\xe3\x947\xf1\x81\x16\xc5j\x8d\x1al\xf9/\x95\xd1\xa3\xe5\xae\x00\xed\xfb/\x1ea\x87]\xb3q\xa0\x8b \x12@\x0e;\xc2\xeb\xf1\x85\xa0\x17\xf49\x14\x86\xb6\xfamU\xac\xbaw\xec\xda\xc79\x83g\xee\xdb\xfc8\xd6\x0b\x99\xa9r\xed\xb1 E\x89\xf6\"\xed\xbbXu\x19\xdb\xb34\xc1\xe5#;\x81\xbc\xdd\x1ew\"b\x89\xcb\x93G\x02hh\xa4\x93\x05;\x17h;\xedS[\x14\x1f.D\xfb\x9fwt0\xd2,\xe7O,\xd6\xac\x80H\xbb\xb2\x06\xb2#\x0fMG\xd9\xce\xd3l\x1b\xda\x04\x8fP*(\xd2\x88\xabn\xf0p\x8f|(\xd5\x9cEz#\xa2\x97\xc2\xfc\xe3\x86\xde\xd8vw;\xed\xec\xf4B\xbb\xdf\xc0\x10\xc6\xfef\x9d\xc0\x04\x9b\xb9\x94\xa0\x05\xaf\xd9\xb1\x80/\x89\xd7\xfd\xb0%\xcc\x18\xdfiA\x9ejIVK\xf2\xf9-I{\xeeg\x98\x94AQKl\xcb)Cf\xb1A9-.\xdb\x8cL\x9a\xeaaJ)\xef\x0c \xab\xcb\x95dR3y\x94%/F%\x15&\x92\xf2\x1aQ~\x03\x8az)\xa4\x82[S|\x13)L\x1e\x15\xa6\x8e*K\x1cU\x946*H\x1aE\xf3(\xa3J\x12F\xc5\xe9\xa2V\x93E\x95\xa4\x8a\xa2q\xa2\xa8\x924QQ\x92\xa8\xc2\x14QA\x82\xa85\xf4Pa*\xa8\x02DPI4P\xcb(\x9f2 \x9f\xca\xd2=\xf9\xe2\x12E\xa9\x9e\xca\x13=\x15\xa5yJ#y*J\xf1\x14\"x*L\xef\xe4#w\xa2\xa9\xd4Nk\x89\x9d\x04\x89\x13\"\x10\xa7u\xca u\xf2P:\x05\xb7\xf8 \x9dS|\xff/G\xe5\x14\"r\n\xb7\xa3(\x89S\x88\xc2\xa9\x10\x81S\x1e}\x13\xb2\x92\xb0\xad\xbc,u\x13E\x89\x9bri\x9b\xa2\xbcD\x01\xca\xa6$\xc2&\x9c\xbfe\x19Y\x13.\xc3\xe1n\xc8\xa6iJ\x1d\x8c\x14\x8a\xa6p\xbf\x93\xe8\x99\x16\x923\xb9\\\x16\x05\x88\x99\xa2\xb4LaR\xa6\x18%\x93w\x94\x96\xd01\xa5\x901aTL\x99DL\x894L\xebH\x98<\xb4G)\x04L\x05\xe9\x97<\xadpfZ\x16\xf1\x12F\xb4T\x90f 'Y\xca\xa2X\xc2(\x95J\x13*\x05\xe9\x940\x9e\x19\x8cJ\xa9\x1c\x91RQ\x1a\xa5\xf2$J\xe9\x14JI\x04J\xd2\x8f\x91B\x9f$\x1f\x8d\x92'\xa1\xd4Ix\xed\xa9\x948q\xda\xa4\x05\xa4I\x89\x94IN7J\xd3%\x95$KB\xa9\x92\xca\x12%\x95\xa5I\xca\x9b\x0fI\x14I)\x04I\xfa\xb6\x82\x91#\x89\xd3\x0cF~\x14\"F\n\x9f \n\x93\"y)\x910B$3K\xb1\x10\x1d\x92\xf7\xc8\x87Q!\xa5\x12!%\xd1 \xa5\x91 E)\x90\x16\x10 a\xf4G\xde\xfe\x1b\xa3]\x86\xfah\xce\x19Y\x7f?\xa43#m\xa19\x94G\x1a~\xf7\x1b\xbc~\x7f\xc3\xb4\x7f\xe4\x91\x1d\xd1\xe5A\x0b/\xcdQ\xd0\xa1a4\xbf\x10\xc5\x91\x9f\xe0(\xbd)\xa8\xfbd=\xb5\x91 \x87T\xc5Gl\xe4\xa55Jo\xffZJ\xa38\xa1Qz\x1b\xd01,Ge\xe4!2\xf2\xd2\x18\xa57|1\x85Q\x98\xc0\xc8[\xb1?\xbd)<\x8e\x85\x89\x8b\xecM\xd3K[\x14\"-\x8av\x12\xcfgJ\xedh&Y\xd1\xdc\xc5(U\x91\x8f\xa8\xc8\xce\xb8ZIS\xb4B\xb3\xc6 \x8a\xe2\xcb\xae,9\xd1Bj\"o\x9f!\x9aG\xe8'\xb0 .gH\x1a\x14(NG\x14\"\xe6 S\x11\x15\xeaN1\x12\"\x8d\x80g1\x05Q\x12\x01Q\xc1\x0e/\xa6\x1e\xf2\xc4\xb7\xc0\xecw*\xf1P\x90v(\xd8\xcdx\xae\xa71\x08k\x98\x850\x16\xa1(\x87\xd0J38\x87=\x88\xff\xd5\x927\x8b\x99[\xefoAi\xde\xa0\xa2\xacA8gPA\xc6 \x97/\xa8\x1c[\x90~\xce\xd2k(\xc9\x14\x84\xf2\x04\xdd\x94e B8\x82J3\x04-\xe3\x07\xf2@L\x9cl\xbc\x84T@\xf7\xe5U\xf9\x7f\xcb\x11%~&\x9c\xb2@\x92p\xaa`P\xd1\xc6v\x92\x95 \x83^9\xf5\xf6\xc9\xc4\x04\xc2X\na\xe9$\xc2\xc2i\x84\xf5\xf6I\xa3\x94L)LJ*,\x9bV\x98\x90XX<\xb5\xb0\xde>)\xca\xa2T\xc4\xecd\xc4\xd2\xe9\x88\xf5\xf6I\xbd\xa4%&\x16NM\xac\xb7O\xd6\xdb'\xeb\xed\x93\xf5\xf6\xc9x\x1acB\xee^\xbd}2epRR\x1b\xe3\xa3\x90\x94\xde\xb88\xc1\xb1\xde>)KJ\xc2c\xbd}2?\xfd\xb1\xde>\xb985\xd2mr\xbd}\xb2T\xda\xe4s$N.I\x9dLL\x9e\\\x94>\x99\x9e@Yo\x9f\\\x93NY6\xa1\xb2\xde>\x19J\xadLK\xae\xac\xb7O>K\xbae\xf0\xd8Zo\x9f\xb4\xa5\x17O\xc1t\xf3%\xd7\xb6'\xc8 \x96\x9f\x8a \x9edL\xf0\xa7c:\x99d\x85\x122W\x07\x84\xea\xed\x93\x89)\x9a\xa8\xb8z\xfbd\xd1\x94\xcdz\xfb\xe4\\\n'q.H\xe3\xac\xb7Oj\xa5PZ\xe7j\xfd\x1cO\xee\x8c\x8f*&'/\xc1sq\x8ag$\xc93\x96\xe6Yo\x9f\xcc\xedX\xb1\xc4\xcf\xbc\xd4\xcf\xc4\xe4\xcf\xe2]_\x9c\x02\xea\x95F\xeb\xed\x93\xbc\xd4\xdb'\x8bd\x91\x16\xce#\xad\xb7O.\xc8)\xfd\xb7w\xfb$\xd8\xb3{\xce\xce4\xd4\xa21\xaa\x95^\xbf\x92\xa2\xfe\xb5IQ\x03\x99\xc8iT\xa8\x88\x80\x84\x04h\xf3^\xd3\xc5\xb9\xcf\xf7\xedH=\xab\x82\xfdd\xac\x07\xed\x9aI\xbe\xdaD^\xa3\xbc\xcdU\x1c\xf0V-\x0cq\x85,6\x8b\x16\x81\xccd\xaa\x97k\xb9\xc8\xd9u\xd3\x8c\xedF\xdc:\xcb\xdb\xef>\x17\xb2\xff\xc3\xd6?\x97\x8a\x1b\x8aQ31\xb0.Di\x0e\x87\xe7\x11\x1d\xb3f\x00\xceT\x8e7l\x9a\x83\xb8\x04FX`\xea\xcf\xc3q'\xafR=\x0c\xfd\x86\x8c\xa38g\xf1\xf1@\xe4I=\xca\x7f\xde\xdc7m\xf7\n\x0ba\xb4\xddfw\x141\x99\xddN{\x98\x99\x96\x0d\xeb\xefq#\xda\"\x0d\x10\xd9\no\x92v3gJ\xbe@.:\x12\xae{\x02th\xbaQ\x84l\xf6\xcd\xe6\xbe\xed\x9c\x04+\xde\x8a\xeb\xd6 `\x04?\x85\xef\xfe\x80\xe0\xd7\x0b\xf9e\x9e\x01\xa6\xc5\x03\x92|\xa0\xf1\xde\x89\x15t\x18\xc8\xc33-\xa0\xfbf\xbc\xcf\x9c\xe4\x9e\x14\xbdC3\xd0\xeb\x91\xd0kL\xcd\xa8\x129\xfa\xc7Z\x0f\xf8Vh\xfc\xcck\xb0/\x00\xb6K\xfc\xba\x88\xd0PA\xcapA|\xc8\xa6\x0f\xfe\xb1\x19\xe8H\xe8?\xf2\x91\xc3\xa6\x0c?\x8a\xd1k\xbcII3\x12m\x82\xac\x9e\x89\x15\xebZL:\xb6\xfc\xadg\xd9\x9f\nW?[\x95\x85\x05\xdb\xfd\xe2qFn\xb0\x1f\x0e\xd0\x1f\xe9\xe1H\xe7\xbf\xcdk\xcd\x92\xc2\xcd\xbcgk\xe3\x0c\xea)+\xb79\x1c\nK\xe4\xf3O\xda\x81\x85E\x13vJ\xea6\xa4\xb0\xd8\xe9\xfb\xcf\xdb'\xa2F\x99\xa6\xe9G\xb2\xf6\x1eao\xfd\xc6f/V\xb4a\xddM\xdb\xaa8E]\x91nK\x86}\xdbQ\xb9\xf8\x84\xfa\xd4w\xc4\x87f7\x12\x94)\xc2\xbd\xa1\x07\xbd\x9f'\xa0uC\xfa6\x86\xa3\x83\xd8\x18\xa5X>\xe50u\xb0\x10W\x07 \xd8:\x88\xefY\xb1\x1d\x8b\x06pv\x10\x1fAH\x1cE\xc8\xc0\xdcy\x05R#y\xdc\x93\xbb\xb9\x12{\xe7\x15\x16\xc0\xe4\xc1Z\\\x9eW\x1aoT\x04\x9b\x07P\x00\x9f\x07\xeb1z^yM\x12N\x0f\xf2\xb0z\xb0\x16\xaf\xe7o\xf6n\xc7\xc7+\x8a\xd9\x83\x95\xb8=\xaf0\x8e\xd6I\xc0\xeeA\x06~\xcf/\x90\xd0\x18\x86\x0fJ\xe2\xf8 \x8e\xe5\x83Rx>\xc8\xc2\xf4\xc1r\\\x1f\x94\xc0\xf6A\x06\xbe/\xa0\x9f<\xa7cU\n\xe3\xfc\xe0\x99\xb0~P\x1e\xef\x07\x0b0\x7f\xb0\x1a\xf7\x17\xd4\xe1a\xec\x1f\xac\xc2\xffyEM\xb8\xc0\x00\x06\x10\xa4 \x90\x88\x03\x84\xd2X@\x88\xe2\x01!\x17\x13\x08!\\ \xa4\x99@\xd1\x93t\xba\x95T\x12'\x08Q\xac $\xb6l\x1df\x10\x15\xa5\xf6\x880n\x10Jb\x07!\x0f?\x88\xca\x93\x1b\xbd\xdf\xb0\xc9\xc0\x11\xa2\xf2X{\xa8\x07K\x08E\xf0\x84\x90\x06\x9b\x83\x18\xae\x10\xd2\xb1\x85\x10\x02\x1c\xad\xc0\x18BD\x9e\x07OQ\x00o\x08\x8b\x07/\x0dw\x08\x89#\x94\x88?\x845\x18D\xf0\x8f\\\x19,\"\xa4\xe1\x11!\x01\x93\x08I\xb8D\x88\x8f\xea2|\"$c\x14\xc1\x8bS\x84\x12XEX\x82W\x84\x0c\xcc\"D\x860\x11\xbb\x08\xa5\xf1\x8b\x10k\x97g&\xaf\xc22\xa2\x92\x02\x97<\x88R\x14\xd3\x08\x01\\#d`\x1bQa\xbe\xab D\xc9\xc08\xa2\xf2\xfcG\xd1\x08\xf6\x11\xbc\xf8G\xf0b \xa10\x0e\x12\xb2\xb0\x90\xa88\x0c\x1f k1\x92\xa8\xa40n\x12\x16b'!\x1d? K1\x94\xb0\x08G \x81\x1d,\x80\x95\x83\x05x\xb9\x14L%,\xc5U\xc2\x12l%\xf8;\x99\x81\xb1\\\xb8\xb82\xb0\x97\xf8\xdc\xf6\xe1/a5\x06\x13\x17\xe5\xc3e\xc23`3\xa1\xd0\x9cK\xc4hB2N\x13\x1c\xac&x\xf1\x9a0\x9d\x8dqT&Dq\x9b\x90x\xfa\\\x8d\xdfD\xa5\xa9\xbcD?\x86\x13\xbc8N\xb0[\\\x0e\xcb qW\x03\x8e\xe9\x84E\xb8N\xeci\x0f\xb6\xd3\xf7(\x86\xeft\x9f\xf5\n]\x84\xf3\x04\xf0a=!>^\xc6\x97*\x85\xf9\x849\xed\xd7\x8b\xfb\x84\x85m\xf3\xcc\xfb\xc5\x18PT\x8a\x9er\xee\xc3\x81\x82\xd5\xa2X\x83\xb5\x7f\xe4\xe2A!?\x88\x19\xc0\x86B\xfcK\x80\xdd\xb9b\x18Q\x88\xe0DaE\xe3\x02\xae\xc35\x98Q\xaf0u\xddG\x007\na\xec(\xac\xe8\xddz\x0c)$\xe2HaE\xab\x02c^\x12S\n!\\)\xf0Fy\xb1\xa5\xb0\xa2[+0\xa6\x90\x803\x85xSb n)\xa3\x9f\x81;E\xe5\x99\x80\x8d8\xf6\x14\xa2\xf8SH\x1f\x88l\xb4T9<*,\xc5\xa4B\x10\x97\nv\x0fr\xb0\xa9\x90\xbfW\xa4\xe0T!q\xd4!\x03\xaf\xea\x15xC\x96cV!>.\x9006\x10\xc1\xafB|B\xab\x92:|\xb0\n\xcb\x1a\x14\x97\x80\xed\x84\x04L+l-\x14\xc0\xd7b\x13\x03\xc7\xd8B.\xce\xd6\x91\x86\xe1n!\x05{\x8b\xaf\x96\x00\xcc\xd0\x0bl\x94\x90F\xf3-)\xef\xd3\xc73\xd5\xb60\xb4\xf1#\xb3\x06\x97_\xe7\xc2\x8dH\xcd\xce1z%~\x94\x0ec\x9e\xf0\xc9\x83\x7f\xca\xec\x14\xdbH;\xc2\xbe\xdf\x1ew\xebp\xbe\xab\xee\x184\x1ai\xd9\xf4RA\n\xfb^z|y\x92 f\x95\xb3muF\x87`\xb5c\x18$\xff\xb1\xcc\xf4\x8f\x18\xc2U\xc3\xd4n=\xc3s\xe7g\xec\xa6\x91\x8e\x0e\x8e\x15\x9a\xdd.G\xb3kUi\xad\x04\xf5'\x1e\x9dl\xb9f\x9f\x06Q\x87\xe1;\xa9\xba\x03\xd1~}y \x03\x1c\x9av\xf8\x9e\x0emo\xb8Gf\x88\xec3\xf5\xd4\xad@\xf5o\x1e}\x0d\xa7\xab\x9e\xa1=\x1c\xc80\xb6\xa3\xe1_`=\xbf\xde\x92\xae\xdf\xaf\x99\xa5\xf3\xdb\x86\xed\xc6\xfe\xcc}eL9\x02\xff]\xa2\xe8\x11%\x83\xac\xf3\x98N\x11O' \xa3?\xf6\xfdn\xb9\xf2\xe8\xfb\x9dOu\xf4\xfd\xce\xe4\x07`\x7fh\xbb\xdb~\x95\x9a\xe8zz-\x14\xf8\xf5\x82\x1b\xa5\x97\xbc\x81\x8c\xb46$\xd1qf\xbd\x8b\x8f\xf2'me,\xd7\xd5\xfa\xba\xbaV\xad\xd1\xfa%D\x94\xbd\x86K\xaf\xd36s\x03G\xe9\xd0\x11zv\xd7?/$\xc9\xa9G-\xfe\x1b\xb2\xb9\xff\x8f\x7fx\xadpE&:),\xca52'\xed}=\x0e\x9bg\xee\x11Z\x97\x1bT3\xf4\xaf\x80\x11\xa1\xe2\x14\xceJ\x8d@\xa8s\xdb\x91\xfef\x9d\xd3\xea\nw\xce\xf3\xadF\xaa\x98H\xe2=D7\x1eQ\xb0\xe54\x17\x14\xa3\xa7\xbf\x98\x85\x8f\x16\x1e\xad\xbe\x0b\xf8\x8eEI8f\xc7\xfd\xc8\xa2\xa4|$Q\xac\xd6\x81I|!\xfe\xa6\x98\x0bC\x8e\x08c\xa2\xd2\xbe\xff\x02\x87]\xb3A\xb3\xafA\xf8\x10\x0f;\xc2+\x0ey\x1e\x16\x0eJ\xcc\xfb\xb0h`\xcc\x16\x1a\xe3r\xec\xda\xc7\xd9\xa5\x1c\x9d\xc6\xb6@\xdf\xa0H\xdf\xe9\xf5M\xb3k\xbaM\xee\xa0\xa4w\xd5\xaa\x17\xf5\xe7\xaa\xdf\xbe\xde\x93P'M}E\x9b\x81b~\x17Q\xc4q\x8d\xa9\x88\xdf\xac\xa7s\x95J\x1b\xcdgZM\xd9\xbc\x9etTT\x96X@\xe2d\xa9w\xde\x17\xceJi\xa9nZ\x9cwt\xd0\xc2\x9b\xe6\x00\x0b\xbd\xe4\xcf\x9e\x03\x8e\x99yh:\xca\x8c\x99f\xdb\xd0\x06k\x97\xd1*e97\x83p\xb4\x19\x15\xca\x1f\x97z\x9b\xf4\x0e\x99\xb9y\xbbv\xa4\x02w}h\x06\xda\xb2\x93\xbe\xe69A@\xc5ss\xba;n\x14\"\xe7}\xce%`H\x94\x00\\#\xc8cU9}|G\x9c'\x0e\xe1\xd9n\xfc[\x8dg\x9b n1\x91+\xd6u+\x92\xb5\xc7\x13s\xaf\xbbX\xdd\xc5\xea.Vw1\xaf\xac\xff\x1dv\xb1\xe0|\x0b~\x81x\x7f\x9c\xbe\xe8\xce\x04\xf2\xe7c\xfb\xd0\xecHG\xc5\xb6\xe2<\x8c\x08$\x8f\x1br\xa0\"U\xb8Ei\x0ef\xe4\xe14k\xad\xbc^\xf9\xe9\x84^\xe3\xae[$\xb4\x000\x1e[\xca\xfdR<\xbc\xbek=\xb4\n\x93\x13B\x1f\xdb\xd0\xc8\xe8\xddL\x1d\x0e\xab\xdf\xe6\xf6.7T\xb3q\x13?\xc5\x92Q0\xfal\x8aC\xfa\xef\xf4\xbc\xf2fV\xde\xcc\xe7\xe0\xcd4#K\xa8\x031\xe6\x9c4^\x92\xd2\x92\xe3J\x9f\x95\xcb\xff\x9d\xb3p\x93\x1d\x97\"l`;*\x93\xe6s\xc4Y\xe8\x9d\x07\xc6\x18\xae\xf3\x04\xe2^\xbf\xd9M\x95\xd1 GHZ\x83\xd0CE t\xf2\xbc\xccR \xd6}\xc4\x86\x89Y\xf4\xf1=\xd6\xb5\xe2[\xdc~\xd7BW\xccDGEy\xcc\xf6\x04\x83=\xb1\x9f\xc9\xe9\x8b\xb6\x05\xdeb\xc6\xf7\xdc\xa3\x90}\x9d`Y\x17p\xde\x86\xech\x89\x1a\x90\x8f\xec\x04\x93\xc5\xf6\xb8\x13\x99\x0b\x98\xb4\x81lH\xfb@\xa0\xa1\xc1\xae\x15\xeaR\xa0\xcd\xb4OkKl\x88\x10%jY\xb7Z\xfel\xd0\xb6\x8dX\xb5A\xaf\x0c\x1a\xbdu\xbc3\x86\x08c\xffGz\x01#\xedyr\xcen'<2c\xdb\xdd\xed\x88\xee\x8d\xd1\xaa\x15\xae\x97Y \x9b\xc5\xd3+ZvJ\xc7\xc6\x83\xcd\xf3\xd7\xfd\xb0%\x03\xd9r\x97\x0f\x12\x11EI\xa5-\xd32\xb43\"=\x92\x02\xe3\xb1\xbc)O\xe9\x9d\xbb#'\xef\x8c\x9a+\xe67\n\xe8\xcd5\x16\xda\x06\";\xb4(K\xd6\xe3\xef$\x9c\xf7\xbc\xbdYg\x01\x84E\xb9\xbd)\x03\xbb2PU\xbae\xc4\x15\x80\xf8Q\xaaI\xc7\xe3\x11\x1b\x0bM\x95L\xe8\xd795B\xa6\x12\ne|Ov\xdc\xd7\xd0t\xd0l\xb8\xb1\xedv\xf8\x82\x19\x00\xeeI\xb5\xff\xda ?E\xdfi\xbaI\x92BqZ\xb4~\xd36S6\x1c\xb7\xb5\xb4\xb42W\xde-\x93\xe4\xd6\xe3\xf9\x14\x9e\x8dj\xf5\x82srPD ~S\xe1\xedY\xf8Z\xec\xeb\x9d\x89\xac\x15\xe5\xa1\xe1\x1fjN(\x9c\x93Y\xf8@\xb3\xef\xb6\x17\x9f\xcd\x1d\xb9\xf7\x1f\xae\xce\xdfpb\x01\xe9\x96\x12\x08\xfd\x96o\x8d\x17\x9d\xb2\xe4&\xe2*1G<\xd0k\xa1\xb8\xddJ&L\x17\x9b\xaf\x7f>\xb6\x83\x98\x14w\xfd]\xcfQ\xc2\xa9^\x0c|\xa31}\x18\xef|\xfe\x0bC\xd2\xec\xb0\xf9\x06\x9b1\x8b\xfd\x16\xcaW\xa1\xcb\xaa\xae\x8a\xea\xaax.W\x85=\xf6Q\xcb\xc8k\x91\xe9\x02\xbe\xc7$h&Y\xcc\"[l\x86Mz{\x95\x8f\"L\xb1\x9c\xe6\x11p>\xf5JB\xe5\x99<\xd9\x92\x17\xa3R\x0e\x93({\xb7*\xffFE\xbd\x94\xc9\xc1}*\xb6\xe5\xac'H\xf6\x18Paj\xe45\xa4\xc8~\xf2\xe3U\xb4\xc7\\<\",HxL\xf3\xa8\x8eW\x92\x1c\xa3\xd0\xfa8\xbd\xf1jb\xe3U\x94\xc6\xec\xb0\x8a\x8dX\x9c\xccx\x0d\x8d\xb1\x8f\\4J`\xbc\x96\xba\x98ioD\\\x90\xb4x\x0d]q\x98\x96\xb8\x00!q\x12\x15\xf12\xca\xe1L\xb2\xe1\xb54\xc3\x80F\xc7}\xe7\xb9\xa2\xd4\xc2\xe5I\x85\x8b\xd2 \xa7\x11 \xaf\xa3\x10\xf6\x0cp\x88Y\xde\xccp\x7f\xc3\xb4\x7f\x18A\x0f\xfd\xefI\xa4\xa9ty\xd0\xc2K\x91\x1ath\x18\xcd/D\x8b\xea'DMo\n\xea>YC\x7f:\xd1\x9c\"\xf2|\xc4\xa7^\xca\xd3\xf4\xf6\xaf\xa59\x8d\x13\x9c\xa6\xb7\x01\x1d\xc3rt\xa6\x1e\"S/\x85iz\xc3\x17\xd3\x96\x86 K\xbd\x15'r\xb18\xe3\x98AL\xca]\xc1\x968{\xd3\xf4R\x92\xaeb\x1c\ng\xf0\xa6v4\x93t\xd4@\xa2\x86\xe9F}D\xa3FK\xd7S\x8c\xae\xd0\xacqB\xd1\xf8\xb2[K\"\n7\x98\xf7w!}\xa8\xb7\xcf\x10\xc5\xc2\xfa #\x83\xcb\x19\x92\x06\x05VQ\x83r\x96G\x8f\xb4\x10\xf7c\x98\x0e\xb4Pw\x8a\x91\x7f\xce+f9\xedg\x12\xe1g\xc1\x0e/\xa3\xf7\x0c%\x84\x1a\xfdN%\xf6\x0cRz\x06\xbb\x19G7\x18\x83\xb0\x86\xa5\x13c\xe3\x8c\xf2p\xae4\x83sX7\xf9_-y\x180\xd6\xdf\x82\\\x8eM\xb0\xb2 V\xb3iN\xec\x99\x9a0\x9cG\xb3 \x83\xa6\xcb\x9dY\x8e5S?g\xe95d0e\nfLM\x16\xca\x91y\x93\xc9\x8ei\xads\x84\x173\x8b\x11\x13a\xc0\x8cr_\xca\xb4?<\xeb.\x06\xba\x98\xa7xzF\x1f\x02\xd4X\x0e\xb6\x98\x0d\xb1\xdf\x16k\xe1\x07\x13\x04\xf4jl\xe3(\x04\x87\xf0@!\xa20\x88\x8c\x96\x17\x82>\xfc~\x19V\x12\x80\x91 \x96C\x0c\x1c\x19\x1fhQ\n\x02$\xbd\x10\xc9$\x90\xe4\x82>\x87\xd9L\xecCL)\xa8d\x12X2\xa1\x17i\xdf\xa5,d2\x194\x99\xc3y\x01v\xe7\n@'S\x86\xab\x1c|2\n\xa0\xb4\x9a\xb3\x0eB\x19\xeeS.\x8c\xd2\x10v\xe3\xb2Y\xadAUVPH\x05\x85\x14\x03\x85\x18\xd3\xc6\x03\x0d \x19t\x0b1\"\x98\xa8%\xf8\xdd\xe5\x86\xe4\xb4\xa8\x9e\xd9~\x0c\x03K\xb2\x8c\xb0\x95\xf0\x12\xaf\x9c\xff+\n0\x89AL\x82&W\xc8\xe0\xa2^\xa0It;\x8b\x8d\x12\x94\x87\x9b\xc4\x00'\xa5!'\x85A'\x11\xd8I6\xf0\xa4,\xf4$\x05|\x92\x01?)\x0b@\x11\xb35\x02A)\x0bBI\x80\xa1\x14\x07\xa2D\xa0(\xeb\xc0(\xa8\xa0 @\xa5\x08D%\x11\xa4\x82\xbe\xb9\x08\xb8\x92\x0d])\x0d^\xf1\xc3W\n\x03X\x9e\x03\xc2R\x18\xc4\x92\nc)\x0cd CY\x8a\x83Y\xfcp\x16\xa1\xb8\x92\x00-\xeb!-\xa80\x0es\xf1\x80Z\xb2`-^`K\xd4\xa4\x08\x82[\xd2,\x8er\x00\x970\xc4%\xde\x9a\xa20\x970\xd0\xa5\x18\xd4%\x17\xec\xe2\x88\xe3\x16\x0dj<\x94\x05\xbc\xc8e\x84t(\x17\xf4\x92\x80\xf4\x08\x02_\x12\xa1/\xde\xfc\xf9\x85\xf0\x17\xbf\x1c$\xa98\x1b\x04\xb3dpR\x800\xf1QH\x02\xc3,\x86\xc3\xe0)\xd7\x05 1 \xa0\x98\x18,&\x0e\x8c \x8e\xda\x12pL\x1a<\x06\x07\xc8dCd\x92A2ka2\xfeaJ\x82\xca\x14\x05\xcb\x04\xda\x82\xcc\xc4,\xc8\x8c#\x0d\x81\xd0\x14\x05\xd1\xf8`4\x99@\x1a\xb7\xc9.\xb0\xa6<\xb4&\x02\xae\xc1\xe158\xc0\xa6$\xc4\xa60\xc8\xe69`6K\x806\x89P\x9bE`\x9bt\xb8\x8d\x07p\xe3\x83X\xa4\x83,\xe2\xa0\x9bE\xb0\x9bd\xe0\x0d\xda\xa1\xd2\xe0\x9b\xb2\xf0\x1b\x0f\x00\xa74\x04\xa74\x08'\x7f\x8e$\x01q\xd2\xa08&\x18\x07\x87\xe3\xa83\x18\x06\xba Cr\xe2'\x9e\xc2\xb0\x9c\x000\x07\x87\xe6X-,\x05\xce \x1e[1\x80N:D'\x11\xa4\x93\n\xd3I\x00\xea\xc0\x12\xa8\x0e\x0e\xd6I\x8f\x9d\x94\x01\xec@\x04\xb2\x93\xde\x9e`*P>p\x07<\xd0\x1d\xb3\x15\xa1\x06j\xff\xc8\x83\xef\xac\x0e\x08yA^\x88\x0f\xf8A>\xcb\xba\xb0\x18\xe8\x13\x83\xfa\x04\xab\x0f\xa5\xa5\xc5F\xb60\xe4g\x01\xe8'\x0c\xfbI\xea\xb0/'-\xbd\xd3\x99\xf0\x9fE\x00 ?\x04\xc8\xcd\x9f[ \x02Z\xad\x9f\xe3P\xa0\xf8\xa8br\xf2\xe0@\x8b\x01A\x91\x1c\xd1X\x96h\x08\x16\x14U\x00\x908DP\x1c\x1c\x14\x86\x07\xc5\x00BE;V\x0c&\x94\x07\x14J\x84\n\x15\xef\xfab\xc0\x90W\x9ay\xb6H\x86\x0cE@C\xd1\x0e\xc74+$\x0e\xc8\x1aD\x11\xaeP\\\x94Q\x02\xce(\xcbv\xcfA\x1b9\xc2\xe4S.\xde(\xdc\x8e\xd2\x98\xa3\xc2\xa8#\x1f\xee\xa8(\xf2\x08\xc3\x1e\x95D\x1f\x81\x17\x7fT\x16\x81\xe4\xc1 \x15G!\xa18\xa4\xf2H\xa4\x04,\x12\xd8\xb3{\xce\xce\xd4\"\xd7\xbb\x1d\xef\xe9\x9f\x8fd`\xa2\xe6g\x94\x90\x9a\xff\\\xf3\x9f\x0b\xe5?\xdb\x0d\xf5\xa4\x1b'\xe3\xe4x6\xb3\x94\xe5\x83\xcb\xe9w\xfc\x89\xa1v&\x9d\xf7\xf6!,\xc1\x18\xfd@\xd6\xb1s\x0d\x00\xcd\x05\x9c\xcdp\xb0q\xd8\xaci\x881!Pi\xae\xff\xd4\xbc\xacWd\xf6\xaaTfM\x9a|\xdfm\xeav\xa4\x05\x9b\xaaI\x8b4\x15\xbfr\\\xb5\xdcn\xaf\x83\x85\xa3\xcf\x90\xa4\x1eA\xbb%\x9c\xac\xd7\xb8\x12\x16]\xde\xed^\xd1\xed\xc8C\x80m\x11H[B\xc7\xd6\xba\x0c\n]\xc0\xed\x03]EPn\x19\xd6\xec\xd2\xeb\xb4\xc3\xedG/\xd1\xf6_\x9d\x9d\xd1\xee\xc5\x97c[W`;\x02\x03Wb\x87\xda\xb2\xe6\xfa\xeb \xd1fHr\xd1mF\xbd6\xae\xcd\x10n\xe0\xd9\xf0\xe6\x1a\xf73\x1b\x81\xf5];R\x81a;4\x03m\x99\xa97\x188\xb6\xb9\xaa\xe93\x19 6\x1eL3\xde\x96\xfa\xd9\xf0~Y\xe2\xa7Od:l\x02\x9b$\x1f\xde\xe4\x9d\xd2\xab\xe4\xd0I\x87+6\xd3\xed\x96\xa7\xbfL}\xe5\xd5T\xc1\xd6\xb9\xda\xc9v\x0c\xaePB\x88\xd2\xf1\xaa\x9b\xf8~\x99\xa5Ol\xfd\x81i\x8ex\x13\x8c\x15\x9a\xab'\xe0F\xb7\x8b]\x0da\xd4\x9c\xa5\x0c\x0c\x05\x10[\x06\x8b\x01pz\xf5\xd7d^I\xe8\xeb\xb8\x08\x88\x99\x0e\xd1#\xc2R\xc2\xb1\xcc%gIs\x0c\x86\xa0\xb9\x10\xedL\x02\xb1X\xb1\x05 1\x1b\xc0\xdb\xda\xf0\x00g\xadVK\x16\xb2\xf7\xfbv\xfe\x95\xad\xcd]\xcb\x968\xef\x8e\xefoE\xd6\x02\xd7\xe4\xd8{}\\\xd1\xc67uC/\x80s\xbba\x834^\xbb\xe6P\nl'\xef\xd0\xec\x88\xc9\xbe\xdapRA\xda\xad\x86\x01\x05\x97\xa5\xdbVi\xb5\xc9\xd8\xc9\xb9\x0f\xce\x11\xb2\xf2t\x0d\xf1\x13vz\xa3\x9c5\xb4\xfe\xb4m \xf2\x9d`!~\xea\x86\x12\xcd\xcf=\x81C\xa4\x0f\xf5\x92\xfe\x95[/*\xce\xb5\x80\xb5\xaa\xe2D4\x89\x1d\xce\x0dK\xad\xdb\xaf#\xa2\xdc\x0e'p\xd6D:\x9c\xd2\x99\xa5{;*$d\x9d\xcf\xc5\x7f\xc2\x872}Y\xbb\xf3\xfb\xa7\xb6\x08N\xf8N\xfc\x90\xd0\xaeR\xb6\x80(8\xb7\xcdJ\x0f\x80\xf3\xaa\xd7\x88Y\xe6 \xd0\x84\xe8>\x01\x97\xd2&\xcf#\xa0 r\x929~\x13\x07i\xe8\xb0\x14\x14\x18\x12\nU\xb7\xafQuU\xb7#\xa5\xea\xf6\xbf}\xdd\xbe\xcc\x97\xbf\xc8\x07\xbd\xe8\x14h\x88\xb2.\xbe7~+p\"4\xe5\x19\xa7CQ\xac\x9b\xef\xe3\xa7\xde\xd4\xaeZ=S\xb3Gn'\xd6\xa17\xa3\x87\x0b\xce\xbc\x08\x0bV\xf2\x917pb\x8d;HK\x9dT\xe7\xc3\xd8\x8aF8/\xa75\xe2\xafc\x10\xfc\x06\x11\xd3u\xa4\x9f\x7f\xc5(h!\x1a\xcf\xbfNhs\x19]g\x02-ff\xf33i9CC\xb1\x9a\x8a\xb3H\x982N\xbfi\xbc>e?\xe5Rn\xca3\x89\x10\xb6\x9c_3\xae\xaa\x7fg\xd1\xc85\xea\xe27 B.V\x0b\x19\xc1Gc\xe6\xaf^\xfe\xdar\xd3\xc4\xb9\x0d]\xd1\xc0\xd5\xcb\x1c\xeff\xb1\xa5\x1d\x08=N9m\xc9s\xdd\xcf\x81\x19\x1f \xe3\x0b\xaed\xbc\xb4\x18.5\x81\x1e\xaeK?\xcb%j&\xe0F\x02E9-\xbd\xfa?\xbcy\x15d\xb0\xf4sW\x96c\xad,\xc6W\xe9e\xaa\xa4\xeb9*K\xb1S\x86y)W1R\xae\xe6\xa2\xe4\xfd\xb5O\xc0^\x16\xca\xd5\xfc\x93(\x04\xc7\xc3<\x99\xc39\xc9\xf9%\xed\xde \xb4(kx&\xfd\x9c\x92\x99l\x92I<\x92\xe9\x9c\x91\x19l\x91\x19<\x91\x88\xc2(\xc8\x06Y\x96\x07\xb2\x18\x03d\x9c\xfb\xb1\x18\xeb\xa3\x8f\xef1\x87\xe9\x11eu\xa4)|\x8ek\x99\x1c\xbd\xac\x8d+\xf9\x1a\x11\xa6F\xefF\xe9\xc5K\x84w\xd0\x95\x8c\x8c3\xfb\"6\xbe\xdf\xc4\xeb\xce\xe3_\x14|\x8b\x9a8\x97y\xb1\x00\xe7b\x1e\xdb\xa25\xcb\xed\xcd0\x93aQ\x0e\xb4.1\x87K1H\x14\xe8\xe1O\x8c2'\xba$j\xe9l\x89\xee\xbb\x7f\xc1\xfa\xba\x8a\x1b1\xa5\xb31>D\x7f\xdf\xa2\x1c\x88\x0b\xd8\x0fM\xa2\xa8L\xc6\xc3 \xd7\xa1\x9f\xe50\xc4o\x88\x8eB*\xa7a\x8c\xcd\xd0\xe61\xcc`0L\xe0.\\\xceZ\x88p\x04\xc6\x98\n\x0bq\x14\"5\x1b3%\x8b\x91\xd0f \xcc\xe1\x1eD\xb8\x06\xb3X\x06mV\xc1\x92|\x82^&A\x9b^\xcdf\x0f,\xc3\x1bX\x8c1\xb0,W`\x1aK`\x94\x1fP\x9e\x92c\xcc\x80\xf2\xb1 '\xa0C\x9e\xe7\xd6\x96\xca\xee\x16f\x00L\xe4\xfeK`\xfd3\x9a\\\x92\xe9/\x8b\xe3\xcf\xe5\xf4+\xc7\xe6W\x8e\xc7o\xfd\xd7\x8dr\xf7\xc5X\xfb\x94\xfa\xb6\x99\xfa\x84\x0dn\xb3\xf0\xf9\xd8\xf9\xfc6pAF>\x94\x8b\xcff\xe13ZR\x82\x7f\x0f=\x8c\xd8\x9c{)l{Q\x9e\xbd8\xc3^\x90[/\x91U\xcf\xe6\xd3C\xfbg\x8cb>\x87\xde\x1cd\xb6\xd9\xf3\xe2\xb5\x1b\xb3\xc9\x164{\x81\x97q\xe5Mr\xc6\xb9\x89s\x9dxC\xb4\x7f\x18\xceg\xfd\xefQf<\x9a\xeeDFy\xf0\xbcGc\xa3\xa9\x05\xb8\xefp\xd6\xbb\xb4\xea]h\xc9j\x8e;\xb0\xf2D\x00e\xb7Cy\xed\xd2\xda\xba\x86\xcb.\xccb\x97V\xefJ\x8a:\x8c\x8e\x0e%\xa2Kk\xc5\"\xf29?\xed\x1cZYB\xe0\xd2\x98(\x05\xe9\xe5\xec\x9d\x05%\x96\xf3Q\xca\x05;\x13 xz:D\x17R\xc7\xcd\x1d\xd0\xc4\x05I\xe30\xba8;\x14\xbb\x82(n\x81\xba\n\xd3\xc2\x85\xf5C\x06\x15\x1cw;Z\xe2\xd2H\xe0\xd0\xbeA0i\x17\xa7\x07\xf3.5\x88v\x1c\x8a\x12\xbc\xf9\x98\xbe\xfc\xa4n\x99M_N\xe1\x86\xcelU\x96\x91\xb7Ei\xdb\ntn1I\x1b\xe2\xf6\x07\x93\xa0.\x85\x9e\xcdK\xcc\xe6\xed\xd2\x02 \xea\x1a\xbe5\x9b[-\xc8\xaa\xb6\xd0\xa6\xcb\xe1P\xe3\x7f\xfdF\xef\xa8\x99\xe5\x8b\xd7Z\x921-\x9f+M\xc5\xe1\xa4\xc09h\x9d\xcb\x8ffq\xa2e\xb2\xa1\xcdF\xbf\x947\xf3\xa0e3\xa0I\xd6')n\xe6>+\xc8zf\xf1\x9d\x95d:\x8bp\x9c\xedn\xf6'\xac\xe5'\xcd\xcd\xa6=y\xf8\xe1\xe4\xf4\xed\xd9\xc5/\xc2O\xf0s\x7f\x97\x9cJ\xb3\x1f\xef\xae\xdbnK\x1e\xed\x95\xd6v\x94\xdc\x91Y\xa1b\x86\xd7NU\x04\xf8\x02%\x0f\xa4\xa3\xcf\x9c8\xcb\x1f7\xfe\x12Ph\x0d\xa5C{sD\xf8e\xb1\xa6\x89\x82\"/\x03\x1b=DY^\x91knE \xee-\x81\xeb\xe7\xb2w\xa5S5.\xfa\x81a\x1a,\xf8:4\x87\x03S]\xf7D&]~!O\\\x19\xf1&!\x02\x1b\x9b5Q\x14\xd1\xc0\x11\xdan\xa4\xa4\xd9rB\xb6\xe6+\x8f\xbc\xfa\xafJ\xb7\xf8\xea.\xb9\x8cs6\xb5\xa6\xd6\x92\x0e\xc4\x1fT\x06\x9a\xd1`E\xf47\x7f}C\xa0\xca=\xfaB\x9e\xbe\x17\xde\xe6C\xd3\x0e\xa3p 2\x1d\x95\xd6j\x7f\x9by\xd3t\xe2A\x18w\xed\x86o\xecz\xabe\x8d_Y\x93\xc9\xbe\xa5\\\xeb\x1c\xb9[w\xec\x8d\xbd\x97<\x92\xcd1\xb6\x1f\x99\nA\xdb\x94F:\x1c7\xfcD,[\xc4\x0d\xda\x0e\xb8\x1a`f\xe1#\x7f\xd7\xba\xb1o\xd7\xdf\xe1zG\x0dj\xb2\xcaA\xf2\xdf\x8c\x89kMs\xe7 |\xa0\xf3\xa6\xb0\xc6\xcc\x19\xfb\xda\xce\x08\xfc\xd4\x8c\x17\xddm\x9f\xdc\xff\xbbf\xbc\xfe\xdat\xd4u\x8cz\x8e\x87\xc7\xc0a\xf7\xa7f\xfcg.KY7\xca\x883\xbd\xa6\x89\xd5\x04\xb1\x9bsE;B3gL\xc2\x96<\x90\x1d\xfb\xd2\xdc\xbf\xd4P\xdal\xee\xf5p\xb3\xb6h\xcc9k%d(,\xe2[r\xd7vow\xfd\xe6\xcb\xab\xe9o\xe7\xdd\xd6\xfa\xcb\xd9=\xd9|\xb9zd\xbb\x1c*\xe5\x1d\xd9\xb5\x0fd\xb8z\xb4\x12^~n(a\x07\xae\xa1\xe9\xc6F\xe6W\xed\x9b'v|Q\\\xc9\xc7\x91\x03>\xee\xc9H\xe4\xe2\xf5\x18B\xffP\xd4\x10\xd2d)}\xa6\xfd\xc9\xafa\x8c&\x89\xfdA\x83\x8d\x88s\xad\x1a\x95\x1f\xf9\x97\xe0\xa6\x815\x90\xe8n\xa3\x99\xa3\xc9[\x8e\xa9\x8a\x90\x15\x87\xa9\x9f\xe7\xd0\x89\x88\x82\xf1\xae\x7fTgx\x9e\x0e\xd9\xef\xc5\x0c5Qb\xe6\x9a\xaf1\x05\x8f\x11\xd9\x07\x08gR]=.\xa6\xa8\xca\x88\x9eHn\xea\xab{\x027L\x83HYj\xb2>\xde7\xe3\xfd\x12\xbb\x80 \xd2\x94\x07\xb0\xf7\xe7\x90\xc2\x96\x8c\x87&\nj\x92mz\xdf\xec\xc5\xe3S\x10\xe3\xac\xdf\x12M\x96-&\xc5m\xe1\xea\x03\x01\xf0f\xf2T;\x13\xacBC\xc8\x0b\xa9U\xf87}\xa5\x92\xf9^\xc8\x87\x87\xe6\xeb\xf5B\xe3\xcaX5lD\xfb#=\x1c'\x94\x8b\xb6\xbb\xbc\x18\x99\xe1uG\x06x\xc9f\x95\x10\xfa\xdd \xfc\xc2U\xb6&\xa5\xeb\xbb\xd7[B\xc9\xb0o\xbbv\xa4\xedF\xb3\xfb\x9eY\xd1 n&]\x8e\xfd\xd5D\xf1#\x9b\x8d\xb1\xd4\x05!z\xcb\xb6-\xf5\xc7\x7f\x1b3\x0e\xb3<\xb5_\xfc\xc6\x96\xdf\n\xd5_\xc7:!\x8a\xa7+\xa2\x04;$J\xb8[\xa2xmTQ\xa2\xe6$\x84\xcdQQ\x12\xa4\xc4MCQ\xd6n?\xe1\xc6\xfb\x1c^\xa2\xc4\xf4\xbfY\xe2=Y\xbdw\x05\xe7\x18\xd6\xfe\xec\xadM/\xb1\x8e\xad7\x0f\xdd1\xd4\xfcf\xce\x8f\xce\xf1\x13\"\x8d\xcbu\xa5\x19\xc2\xd4yX:\xd4b\xb5\xa7\xaa~\xb6D\xb6\x8b\xb4~;9\xad iG:E\xcf+\xaaF\x7f=\x8b\xfd]\x81\xbd\xfa\xd4p%\x0d\xe2\x96\x0e\x05d\x9aM\x8e\x95>\xad\xe4\x8a\x95\xeb\x8aG\x83\xdcj\xa9\x13MIJv\xa0\x15\xe0[\x01\xbe\x15\xe0[\x01\xbe\x15\xe0;\x95\n\xf0\xad\x00\xdf\n\xf0\xad\x00\xdf\n\xf0\x0d\xbc[\x01\xbe\x15\xe0[\x01\xbe\xbcT\x80\xaf,\x15\xe0[\x01\xbe\x19\x10\xd0\n\xf0\xad\x00\xdf\x04\x80/m\xf7d\xa4\xcd\xfe\xb0\xc4\x91h\xfa7\xdb\xd9\x05s\x18\xc8C\xdb\x1fG\x11\x86<\x81\x1f\xd9 \x92\xc7\"G\xf8\x07\xf8\xe1\x15\xb4\xf4\x85\x18\xf6\xaf\xfc\xaf|\x8al[#q\xc3\xbc\xe3\x9a\xafd\xd5F\x93\xca\x0f\x1ez:Y\xa3\xb2\xc6\x9f\x9b\x91\x9e\xf5\xfb}K\xf5\xca\x0d\x05\x07?\xbc2\xd4,k\x11\xb3F\xc7v\xe45\xd5\x94\xa6\x9a\xd2\xa4\x97\x9a\xd2\xf4o!\xa5i\n \xc9\x1c\x11!`\xca^\x12\xb6\xe5\x86\x8c\xa3\xd8^\x90\x98\x01H\x9f\xd1+K}M\xad\x81\xb6\xdb\xec\x8e[f\x15\xf6#\xf1\x89\x96\xf5\xcb\x0de\xb4\x06\x8a\xbf\xaaW\xa0\xa4\xf0LM\xee\xc2\xe8(QYT\x1c\xac3\x90f\x84\x9f\xfb\xbb\xd14\x8fD\x9b^9\x8e$m\x06(\xca\xd7WS-\xdc\xb05\x1b\xac7\xd6<\xb3_\xb6\xdd\x86\xbc\x81M?\xee\xfb\xf1\xf5\xb8\xfd\x02\xff\xe1\xe4\xef\xffp\xf2\xc3\x0f\xaf\xd8\x7f\xfc\xfd\xc9\x7f\xe2\xff\xff\x9f\xf8\x1b\xf8\xf7\x99\xb3hb!\xbb\xe9\x86L\xfa(rg\x99ya\xf3P_\xcd\x1ek\xda\xdc\x8dZ\xf8SX\xe6\xca\xb0\xe7Y\xb0\xa30 \xb6\x84\xf3\xc1\xaa$\x9f\xcd\xf0t\xa0\xfd O\xca\x1d[\xce~{\xd6\xef\x0f\xcd\x86\xbem\xe9)S\xc0B\xcd8\n\xd6U\xaa\xe4\x91\x0e\xcd\xf5MK\xc7k\xceZ\xed\xc4\xb8R2a\xc8\xce\xd0\xef\xa8\xa2t\x94#\x9e\xa6b\xf5C\xe4?\xdb>=A\xaa\xcd\xf3y\x08wk2\xe5r\xd3R\xb1\xf9\xcc\x03\xddrd\x16w\x0d\xd2\x1eH7\x1e\x072\x05'&\x92]\xfe\xa5h\xf3\x85\x8c\xdc\xfb/\xe0{:\xa4N\xca\x13\x15\x8a\xe3\x127~\x84\x04\x0d\xe8\xacj\xeczV\xc3@\x9a-\x8c\xcd\xadr\xa9\x8a\xbf\xb3\xf1\xe48-\x0e\x04\xee;\xe9\xc0\x85\xa3\xf0\x8e\x89\x0fL\x1fO\xc6\xf6\xae\x93\xcc\xc6\x97\xed]\xf7\xcb\x94\xa4\xe4\x8c\xae\xce\xf7\xf1\x1a./~z\x7f\xfd\xcb\x87w\xe7\x08\xbd\x86\xfe\xeb\xbb\x8bO\xe7gW\xc8\x0fW\xe7\xff\xfd\xea\xf3\xe9\xcf\xc8/?\x9f\xfftz\xf6\xa7\xeb\xd3_.\xde\x7f\xb8\xe6\x86\xb2\xf8\x8e\x92\xda\xc3_\xb3'uNvk6\xa7\xc5\x96\xc4\xfb\x0d{\xf6\x8bp\xe8\xd2\x11\x98\xad>\xd1\x0c\xdc\x1d\x9b\x81)\x18\xbe\xd4!\xd8qO\xab&\xe7\xaad\x9e\x16\x87\x01\xa3j\xf6\xc9\xa4a/\xeb\x18\x08[G\xb3?\xd6\x1d\xcd7\xce_\xf4\x8a\xac\xae\xf1\x13\x00?\xaf\xb2\x81x\xd7o\xe4,\x91\xe2\x1f\xc8 \xf4\x81\xa0\xc1V\xc9\x10B\xc5^=b\x8d\x90_\xee\x8d\xfb'\xb1\xdb\x0b\xc8\xa5\xd9\x0c\x91\x03\xc1\xfa\xc9+|\xd21B\x16/\x07%\x8f\xf4\xd8\xec\x9cs4;\xa5\x1c\x94M,\xa3*\xe63R\x1eo\xbag\x06\x86'\xda\x9b\xd0\x8f\xa2s7\xcd\xe6\xcb\xd7f\xd8\x8eVD\xc7\x1alY\xdd\xe9\xbe\xedz\xa1[\xb5\x0f\x0d\x03\xd9\xf7\x0f\x02\x0d!\x9c&\x1c\xa3:\xad\xc9\x87\x1fNN\x8f\xf4~\x11L\x87\x8d6\x19\xae\x99\x1d\xb3\xd4\x8c\xff?\x06r\xfb\x06^\xfc\xff\xbf\xd7\xe2\x88\xdf\xcfM\xb9\xe4\x92Yc^L/\xf9-\x0c\xbd\x1d\x06\\\\\x9f\x0e3=\xcc@\xfe|l\x07\xb2\x95\xef\x8d\xf3tiG\x85V&#m\xf7\xfc8\xf1\xd025\xb8\x978\xf0\x13k=$\xa5\xb7\x88m\x19\x8b\xd9=\xefu\xa7[\xd2\xf5{\xec\xf8\x16<\x17b\xad\x8d\xbe\x16;\xcc\x9d\xf5m\xa7\xd9\xa2\x9c\xe7j\x86\xafw\xfd^^E\xc6?e\xd3\xc9F\xb8QX\x80\xf7\x1f\xae\xceE\xa6\xb5\xb4v\x84CSX]\x17\x9d\xa2\xb0\x99\xec/\xdd[\xe5\x08\x13\x8eg\xb7\x92i\x1a\x8d\xf3\xfa\xbfy\x82\xbb\xfe\xae\xe7v\x94\xe9j\x97)\xdb\xb2=\x0e\xf6O\x00\xeae\x84\xbei\xb7\x92\xa8\x82\xe8s\xf4\xae\x19\xaf\xf9\xa2\\\x18\xd9=\xba)\xc2\xb25\xceG\x98\xaa\xb0\x01\x93w\x8dL,\x94s\x9f[\x9fl?\x99\xd5\x82;\xe9\xe41\xc6\x1e\xba\x1b\x9e\xaa\xc0Y\x97\x8eS\xd2\x18O\xbc\x80~\xb39\x0e\xba.94O\xeb\xf8\xb8\\B\xac[8v#\xa1\x82+\xc1\xd2^\xea\xa2\xb0V]#vh\x9e\x94\xf6\xb8e\x16\x19\\\xdcZ\xf2&QSD\x1b\x9a\xcd\x86\x7fO\xbe;\x1c\x9a\xa7\xf9u{\x08\xb8\x9eg]\x13\xcf\xf28:}T\xedy)t\xe4q\x14\x19\"\xfc\xaf[\x99-!&\xb2=\xd8j\xff\xfe\xce\xa9i$T\xea\xc1\xe9\xedmOF\xf8\xbb\xae\xa7\x7f'\x134\x84>f\x9b\x1c'\xa5\xb8\x9d\xe6\xb3-K\xedn\xc8\x9e\xa0\xcfSn\xc6\xa6~5\xdfTlo\xe7!f\xfb\x81\x18\xae\x97\xa4\x9d\xc8\x0c\x8do8\xb38\x1d=\x89zB\x00\x1f\x82\xefTr\xa4\xca\xd5\xe55\xf0vO\xfcF\xf6\x17\xeb\xf9\x17e_SO\xe75Z\xf7BX\xf4\xf2\x96\x196g\\\x1fSs`\xdaxh\x1bJ\xb4J\xf9'a\xe7(\xf2\xc8\xef\x80\x15\x9d\xd9\xdc7L#\xf6n\xf61{T\xe5\x12LR\xc6W\xe2+s\xb3\xef\xb6iw\xfc%\xfc\x94\xa2&\x8c\x95\xe5\xa0\xf6\x7f9\xa8\xc2x\x9a\xd2\x99\xd5\x91\x93\xfd:\xe5\x93Y\x93`6\xe4\xde\x0e}\xb3\xdd4#M>\xe4\xbd\xfd\xf4\xe1\xf4\xdd\xd9\xe9\xe5\x95\xff\xa4g=\xf2\xf6\xe7\x0fg\xff\xcd\xf7\xe3\xe5\x9f\xde\x9f\xf9~;\x9d~\x9c9\x1c\xc3\xb5\xe3\xda\xc5\xe8\xa4v,\xe2f\x87\xfaMX\xebj\xd5\\=^\x92\xe1\xa1\xdd\x90y\x84\xe0\xd3G\xd5R\xb1\xdb\xe8'@\x7f\xbb\xde\xc0\xbf\x92\xa1\x97>N\x1e)a\xf5\xa8\x85\xec\x95\xc0\x07\xcd\xe9/\xff\xab\xbe\xfd>\xce\x1d\xd0\x8ew*\xf1_\xdc\xb3\x08_\x1bv\x8e\x9d\xaf\x96\xe4j\xe1Qnd\x9c\xd5\x88\xfb\xb6\xc4\x9d\x8e<\x8a\xe0m\x16\xfb\"N\xab\xd8\x1f\xb3\x1b\xd5\x80\xf2\x8c\xce8yu3$w\xbb\xf9\x1bu\x8a\xb6\xeatU\xb3\x04\xd0}\"\x1d\xda\xf3\xe8\x0c%\xa2zd\xdd\\=~\x12Z*\xf9TF\x1f\xaf\xf9qz\xa9\xd3\n\xec\xf9\xad\x04)3\x80\x1d\xd4\x11m\xbfG0fV]\x08mkl\x95\xa3\x8f\xe9+\x1d}@[\xed\xe8\xef\xa7\xc6\x03\xa9\xab\x1e\x82vE\x99\xd5\xaf \xfc\xf4\xf1\xcc\xd1\x00ho\x16k\x01T\xcasj\x02X\xa4\x0d\xd0\xe6=\x9fF\x80EZ\x01m\xdc\xf3i\x06p\xb5\x83o\x1bwu\xc5\xb4b\xe5?yv\x80\x9a|\xce\xd4\x9b^\x93\xf2\xf4\xf9\xe7\xd5I\x0b\xb1\xb7\xf4\xf1z0\xdeA\xdf\xc3\xdf\x05\x04\xbb\x0b)g\x1e\xef\x91\xc7\x83\xe3\xe5OXX^H>l\x840\xbd\x80\xe3z\x83\xc2S\xf0\xbd\xe0`|g\x91\x18b\xd4?2FWP\xbc/\x7f\xca\xc0\xfcB\xf2\xd8\x84\xb1\xbf\x80\xe1\x7f\xd3\x85\xff\xbf\xf6\xa9!\x15\x10\x16\xc6\x02C\x08\x19\x06\x0e&\x18~#_\x8d\x17'\x0c\xc1//\x8a\xff\xfb\x03\x8e\x19\x86\xb07\xc7\x87\x1d\x86\xc0`\x88\x12\x00\xde\x06\x06F\x948\xe8\x96\x8b\xf0\xfc\x16\xe9\x90(1\\1D;(J\x10_\x0c)\x9d\x15%\xdeeQ\"XcH\xeb\xbd(Q\xcc1\xa4K\x8b\xb9\xfd\xf4\xb2\x06\x7f\x1c\x14hRc\x04\x1f\x15\x1dI\x03\xeb\x8a\x92\xd6\xb3\x92xd\x88b\x92a=.\xd9#\xcd;\x00)\xdd/\x88Zf%\x88\\\x06\x1fz\x19\x12\x1a[\x14\xc5\x0c>$3D[\x92\xba\x81Q\x1f\xa2\x19b{\x97\x89l\x86\xe4\xbdv-\xc2\x19<(\xe7`\xcd\x89\xd6\xcaB\xc43\xa0\xa8g(\xde\x90\x08\x02\x9aW\xf8\x885\x00\xd9\x0c\xfc\xea\x9f\xa2\x88h\x88i\xe6\xd8J(\x8a\x8e\x86 B\x1a\x8a\xa2\xa4\xa1$R\x1aBhi\x80,\xc44\x14DMC\x149\x0dk\xd1\xd3\x90\x83\xa0\xc6F\xec\xe9\xa0\xbc\xc9\x18\x8a\x1ar\x90\xd4\x88\xac);\x02\x1045d\"\xaa\x11q<\xcb\x8a\"\xa8j(\x8e\xac\x86|t5\x94GXC\x1e\xca\x1a\xf2\x90\xd6\xf8\x12E\x1bY\x0c\x7f\x0d\xc51\xd8P\x12\x87\x0dIXl(\x89\xc7\x86\x00&\x1b2q\xd9\xd8\x1aG\x90\xda UM\x14\xad\x0d\xd9\x88mD\xa0\x8b\xe1\x86\xf58n\xf0\x1f\xc5\x82[|0e?\xbe\xff\xaf\xc4vcjo\x8a\x8dS\x03\xdf\x0d\xd1v\xe4\xe1\xbc-a\x1c\xf5\x8d`\xbd\xa1\x0c\xde\x1bJc\xbe\x01\xc1}C>\xf6\xdb\x92F\x1d$8d\xa2\xc1!\x06\x92\x06?*\x1cR\x90\xe1\x80\x83X\x17!\xc4\xfd2\x1c\x84`\x16Z\x1c\x16\x0cF\x0c5\x0e\xd1~G\xd1\xe3\xb0\x0cA\x0e\xd8x\xe4\"\xc9!\x86&\x87 \xa2\x1c\"\xa8r\x08\x8dR*\xba\x1c\x12\x10\xe6\x80\xa0\xcc!\x0fi\x0eihsX\x858\x07\xef\xc0D\x91\xe7P\x0e}\x0e\xfeV83\xad(\x12\x1d2\xd1\xe8\x96(\x17\x9b\x0e\xa5\xf1\xe9P\x18\xa3\x0e!\x9c: Xu@\xf0\xeaP\x0c\xb3\x0e%q\xebP\x1c\xbb\x0e\xc9\xf8uH\xc1\xb0C:\x8e\x1d\x12\xb1\xec\x80jg\x14\xf5\x0c\x0b\x90\xcfa\\;\xa4c\xdb!\x0d\xdf\x0eX7J\xe2\xdc!\x17\xebn\xc9r\x90\xefP\x14\xfd\x0eE\x11\xf0\x90=\x1f\xa2HxH@\xc3\x83\x86\x88\x07@Q\xf1\x90\xec\x84v\xfd\xe5Y\x08yG\x87o\xdb\xa6\xb3P\xf2\x00\xb9HyK\x98\xbcI\xd5A\xcbC\x081\x0f\x9e\x80+\xfd\x0d\xe2\xce\xd4\x13R\x0d\x9eA\xc3aT_\xb3Ey\xde\x08q0P\x1a\xec\x93*\x11H<\xc4#\xa8\xa5\xaa \xa0\xefa\xaa&\x84\xc0\x87\x04\x14>DW\xa1*\xeb\xd1\xf8\x1e\x81\xe2zR\x13\x91\x0f \xcdY\x8b\xccw\x04\xe97\xf6\xd8\xe8|(\x86\xd0\x87\x04\x94>\xe4#\xf5!:rE\x11\xfb\x80\xa1\xf6\x01\n \xf7-y\xc2N\xef]\xab?\x17\xc1o\x89\xc3\xdc\x8d\xe50\xfd\xb0\x10\xd7\x0f\xc1\xaf\x99\x87\xef\xd7\x04MH\x7f\x1d\xe3\xcf\xca\x1a\x9c\x7fR\"\xa3l\xf6\x94\xc9(\xffM\xb5TF\xf9\x1a\x92\xd0\x88\xe6/\xfeH\xd2\xf3\x15ml\x1b\xb6U\xe5r\xd3\xa0\xa8;\xef\x9e\x80\xa3\xed<\x8f\x87\xf2\xe3V#\xect!9\xe0:\x05\xa6\xd3\xe5\xa5\xe3\xe821t\x08~\x0e\x1dC\x0fn\x0e\x03*\x15\xc2\xcb\xe1X\xb9T\x9c\x9c\x85\x91C\xfb\xe4\xd7\x13\xd9\xb88\x0e\xd3\xd2\x97\xc2\nL\x1c-\x88\x87\xc3\xb1pY88\x85|\xd3\xe4\x050p\x0e\xfe\x0d\xfd\"\xd8t*\x8ay[\x8fw[\x8du\xd3\xd1m\xfaX\xad\xc2\xb9\xad\xc5\xb8M#\xcaq\xed\xc2\xb8\xc0U\x05W\x12m':\xaa6.\xb9\x82\xbf\x99\x95\x86T)| \x8b\x0b\xae]4G\x83\x122@\xdd\x1c\xd0\xe0\xb6\x12s\xd0\xe1\x99\xa0Q\xfd\x1e\x9b\xa5P>\x1f4\x96\x11Z:'\xb4pVh$/4;3\xb4lnhJvhF~h\xd9\x0cQ1[#9\xa2e\xb3D\x13\xf2D\x8bg\x8aFrE\xd7e\x8b\xa2\x82\x82\x19\xa4ErH\x13\xb3H\xd17\x17e\x96f\xe7\x96\x96\xce.\xf5\xe7\x97\x16\xce0}\x8e\x1c\xd3\xc2Y\xa6\xa9y\xa6\x853M\xc3\xb9\xa6\xc5\xb3M\xfd\xf9\xa6Bq%e\x9c\xae\xcf9E\x85\xf1O\xdb\xa7\xc8\x15W\x92\xc7N\x9c\xea\x8d\x061\xcd.\xcf\xe6V]\x03a\xd3\xc95\xf8\xdco\xf3\xc6\xf9\x8b^\xb15\x00*Wb\xe4\xc3\xf5\xae\xdf\x88\x88\xaa\x9d}\xf0@\x06\xb1\xf5\xf0\x11\x9b\x12/\x85\x05p\xe5d\xd3!\xf3\xe1\x8d\xfb'a\xe2\xde\x1e\xf9~i4K$\x18\xb2q\xe0\x15?\x89\x14B\xb3\x8e\xfb\xe3\xbe\xe9^\x0f\xa4\xd9r-F\xc9#=6;\xc7\x01\xc7,\xce\x83Z5\"\xc8\xee\x8c\xac\xfe\x86\xfd\x8dy\x0f#\xd3?<\xbb\xdf\x84~\x14cp\xd3l\xbe|m\x86\xedh\xc5\xff\xadodU{\xbao\xbb^\xec\xfe\xda\xbc\x81\x81\xec\xfb\x07yE\x01w\xe4\xb2\xf1\x95\xaf\xee\x8f;\xda\xceJ \x82yQ\xaa\xf3\xe4\x17\xf6\xda\x0b[#ra\xe6\xea\xeaD\xd2\x1e\xffel\xeft\xfdd,V%\xd9\n\x8c\xda\x9an\xd2\xb0\xfd\xe0\x11\x8d\xebz\xd1\xe0d\x8d\x7f\xd3R~\xd2vt\xbe\xfaA[@\xe2k|!O#_\x0br\x90\xa7V5\xf3T^\xb3\x1f\x90G:4\xd77-\x1d\xafG\xda\x0f8\xab\xe5\x126p\xb2s\xfc\x04Q3\xc3\xb0\x9b\xfc:\xf6\x8cM\xd5\x0d}\xdb\xd2S>F\xe2\xd6\x10+/A|D\x8e\xbc\x99\xec 6\xac\xc2\xb5ahT\x9e\x0b\xc8,\x08iq\x91n<\x0ed\xca\x1d\x03\xd2q\x0bW\x98\xd0\xb4\xf9BF\x91v\xb5o\xbbv\xdf\xec\xe4\x95\x00\x9a@\xd3}%\x1a!\x82\x17\xdc\xc1'\x04\xb6\xdd\x1d\xda\x8a\xaeg\xb52\xf5\x02cs\xab2M\xc4\xdf\xd9\x07\xe8\xb62\xd5d\xd3w2\xc7\x05\x8e\"|/\x04\xb19|\xcdN\xbeKa^\x89\x8b\xd2Y\x8e\x86Y;\xd7\xae\xac\x88M?\x08\x93j\xabV\xd88\x1b\x13\xfcJ\x0c\xf5O5\x995q*\xdcp\xe47t\x88\xd3\xa5\xbd \x0f\xc7\x9b]\xbb\xe1K\xe3\x1b\xadY|)\xaaF\x08\xb3\x86-|6t\x0d\xf62\xbe\xa0/5\xa3,aE\x9bvU\x96M\x85.\x17\xdb\x96\x8a\xdbQA\x1b*l?\xa5\xd9N\x89v\x93\x7f=\xaf\xb5\x97\xbc\x16\xd2od\x1da\x96\xd1\xf3[E\x0b,\xa2\xe7\xb6\x86\x8aXB~+(j\x01\xfd\xf6\xd6\xcfb\xcb\xc7V\x91B\x9d\xf8\xb4\x92\xa1\x08N\xe0\x82\xe7\x17N\xae\x1dy\x19\x95\x99\x11F{\xe1*\x15\x12\xac\xa8\xed\x08\xe3qs\xcf^\xdb\xf5\x9bF^\xbf\x84L\x00=-rj\xfc\xac\x0c?\x0c[2\xbc}\xd2\x95\xa0\xa6\x96t\x95\xf4\x1a>|zw\xfe\xe9\xfa\xed\x9f\x10\x1d\xa0\xfdxzy\xe6\xfe\xf1\xdd\xb9\xfc\xeb\xa4Q\xbc\xc2pe\x82\xd7\x8e\x8b\xf1\xac\xfa~\xa0\xb3\xba\xe5\xd78\x9d\x80\xec\xbej\x16\xf7>\x9f^\x9e\x89akG\xd84\x9a{\xc9\xec\xe4\x1b\xe3_\xb3\xabj\xdc\x10\xb1\x1d\xf2*\x90w\xd9X\xbc1\xff9\xbd\xcd:\xef\xbc.'\x9a\xd6V\xfe,\xdf^D\xa7\xa6\x87\xe7\x0f{\xc9'\xda\"'\x85\xd8/M\xa7\xd8\x02;\x93\xa2\x00\x13\xafe\x18>h\x17\x84\x93\xf8\x81$\xe5 $\xc5\xc0#^\xd8\x08]\x0f\x18)\x05\x15 \x83DV\xc1CV\x03Cx\x7f\xed\xc3\xab\x17\x12\xb2\x1a\x0c\"\xb6\nK\x9a\x07\x06\x92\x03\x00\xe1\xa7\x0e\xbb7H\x8e\xd2\x1a\xd0\x87\x1f\xe0\x91 \xedH\x02u\xa4\x0382\xa0\x1b\x19\xa0\x0dDa\x14\x84f\x94\x05e\x14\x83c\xc4\x81\x18\xc5 \x18>\xf0E\x0e\xec\x02\x8d\xed\xd1\x14p\xc5ZX\x85\x17B\xb1\x12<\x81\xe4&,s\xa1@t\x07] \x8f\x98\xa1\x10\xd8\xf8~\x13\xaf;\x0f\x0c!\xc0\x0f\x9a8\x17\x06Q\x00\x00\x91\x07}\xb0f\xb9\xbd\x19f\xc2\x1d\xe4@\xeb\x12s\x80\x0d\xc1\xac}\x0f\x98!\ncp3\x9a\xd3\xa1\x0b\xee\xbb\x7f\xc1\xfa\xba\n\xa8\x90\xd2\xd9\x188\xc1\xdf\xb7( a\x01\x14\xc1\xcc\xda\xcc\x84\x1f\x04\x81\x07~\xc8A\x08l\x80\x8eB*\xc0 \x06-\xb0A\x05\x19p\x82\x04 \xc1r\x08\x01\x92\xb0\x1f\x83\x0d\x14\x02\x0c 5\xff\xc5\xf4$g\xc0\x03l8@\x0e\x10\x00I\xfc\xcfJ\xf9\xb7S\xfcK&\xf7{\xd3\xfa\xed\\g;\x95\xbfL\x12\x7f\xb1\xf4\xfd\xb2\x89\xfbi)\xfb\xd1d\xfd\xc44\xfd\x94\x04}'\x93\xdd\xad-5\xd5:\x9c\x8e\x9f\x98\x88\x9f\x90\x82o4\xb9d\xda}V\xc2\xbd\x9b`_.\xb5\xbe\\R\xfd\xfa\xaf\x1bM\xa4\x8f\xa5\xd0+\xf5=E\xb4\x16\x87\xaf\x13#e\x91X4\x9d\x02e*\x14\xa8\xc2\xdd\x9a\xb09\xff\x8f\xf6\x93}\x8a\x04\xca\xbe\x90\xa7\x17\xca#2\x92?\x1fI\xb7q.\xd3\xb6\x8e\x17\x9e$0\xbfq\xaf\xe4N!/\xf5ou\x84\x10\xd7\xf9\xbf\x92\x13\xcd\xe8\xbd\xa1\x92\xa7\xdc\xb1\x0dO\xe4\xa7\x16\xb3\xa5\xba\xc4\xff\xe6 \x1a\xb8k\x1f\x08\x9f\x9b\x03\x19G\xe5:\xe7\x97\xd2\xcf\x02\xcd\x14\xe0\xc3\xc0\xb3B\xd9\x82\xd95O\"\x9f\xf8\x8b<\x80\xe1Ic\xb3\xbb\xd4\xfads\x10\x91\x7f\"o6\x01\xed\x0f\xafw\xe4\x81\xa8\\e,\x95\xe0\xb2\xdd\x1fw\x0dU\x89p\xc9\x8e\xd9\xb2\xd7\xb0\xeb\x84\x98lF\xc9F\x85G\xc7h\xf8\x9cN'\xfeI\xb1l:\xf5\x8e\x14\xe1K\xa5\x9bE/dc\xbdkFk\xe9\x1amW?\xab\xb6\xea\xf9\xe2\xcdM\x7f\xa4\x9c\x82\x89\x1f\xdf\xa5\xad!\x07\xc2``r\xda\x81\xb7\x05r\xae/E20\xc3'\xfb\x9f\x9a\xf1\x9fyES\xac\xa9yl\xf7\xc7=\x1c;\x1eG\xbd\x85\xaf\xfd\xf0\x05\xbeJ'\x98\xf0\xe2\xd0G7\xbd\xf4@\x06\xd6\x88\x13\xab\x17+n>\x8d\xf5\xe1\xa7f\xfc<\xce\x0dn\x0c\x1e\xacfC\x85\xcbW\x11b\xa9\x06 _\x9d\xe7\x03\x8b\x1f\xb5\xccN\xf6\xafI\xa7f}\xca\x05\xd7\xd8\xaft\xce\xbckh#\x92[\x9eD\xee\xc9@\xe8q\xe8T\xfe\xbb\xdaP\xb9\x0b\x92g\xc0k\xa4vpa\x07\x0d~\xf9|y\x85\xf8\xa6v\xa4\xbb\xa3\xf7L\x19\xde\xb6\x8fb\x9e\xf38\x11_\xf5\xe4\xd0\x0c\x0d%\xa2vQ)\xdbK\xd8\x9e\x8e\xf3RL\x0d0\x1cY+\xef\xe4w\x06\xe4\xe7\xfe\xce4`y\x1e\xba\xb6f=\xe3\xe2k\xa4\xde\xc6z%B\xb0\x0b\xa2\xc4\xc1[\xf5J\x04\xab\xa4@\xb5bh\x1eQV\xc1\xb4\xea\x95\x08\x86\xa4\xdf\xc3\x95\x08+hN%\xa1\xa9%O\xa9`\xeb\xcf\xe8~\xc0\x9f\x89\xd9m 8\x08\xf5\x8ee\xbf\xf9\x0c\xb7\xab\xc7dS\xed\xa6\xdf\"y\xb0\xfdv\x02\xc7H\xc0\x15\x8f\"\xf1\x98\xec\x1c.\xd7\xbe\xd9,!}+W\xd8\xad\xbf\x8e\xf6\xaf|\x9b\x95o\x13\x95V\xf96\xa1\xf2m\xe2\xf5d&e(! \xa9\x19\xe8\x9b\xc9\xe9\x1a\xa2d$m\x88\x92\x91\xba\xe1[\xe8\x9e\xa6\x16K\xea\x10\xa5lj\x87(\xc5\x12\xb6\x83\xe3\x18\x98Q\xf4\xf6\x10 \x1e\xb6I\xa6\x00\x05\xf2\xef#sk\xd8L\x13\xe1\xde\xfe\x96S6H\x1a7K\xce\xe9\x91\xde\xf3\x84&\xe7V9Q\xb7\x04\xfc3iW\x8f/DbNC\x8f\x03\x19O\xe0\xbc\xd9\xdcO-\x9f\x12\x99D\x9e\x8e\xcb\xf7\xd2\xf0I\xea\x06\x83\xe8\xc4\x1b\xc6\xf6.\xbeo\xb1u\xcb\xb99\xa1\xa5\xd0o6\xc7\xc1%\xcay\xcb\xf3\x05\x1eH\xa7V\x88z\xcfn\xd0K\xe5\xfa\x9c\xa8\xe5\xf8s\xf87s<$\xed\x08\x03\xb9%\xc3 \x1cR\x8d\nX\xb4{~\xda\x9c\x93\xb7\x0e\xcd\x93\xf8\xed\x96\xd8!\x15U\xbe\xde\xf7;g\x1b\xf4\xdc\xfc\xb5'\xfb>1\xb2\xae\xa8\x08\xc8\xbeW9\x05\xf3y\x98\xffU\xcc8\xf5\x01\xc0\x17W\x11<\xb2\xfd\x91^c\xf7\xfcz\xeb\x8fS\x899\xech\xb2\x1e\x15\xff\xd1\xaf\xff\x95\xb6\x89PJ\"uEKX\xe2J\xaf\xeb\xed\xafw3\xc5\x90\xe4ujL\x8d\xdd7\xc6l'\x8f\x94tc\xdbw\xd7\xc2\x19\\cB5&TcB5&TcB5&TcBv\xa91\xa1\x1a\x13\x8a[\x1c5&TcBF\xa91!YjL\xa8\xc6\x84jL(\xa9\xe6\x1a\x13\xaa1\xa1\xa9\xd4\x98P\x8d Y%\xd5\xdf_cB5&\x14\x9b#\xcf\x18\x13\xf2]\x9b\xe1\xf8\x9d\x85Cc:\x9d\xa8\xbf\xf2\xef\xb9i\xba\xd9U\x7fc\xdb\xdd\xdc\xa5\xed\x04j\xbe\xde\x93N\xaa#\xc1\xf3\xa1\xd7\xc3\x8e\xcf\xe3Q\xd1d\x9f\xb0y\xc9\x0c \xa1\xc0F\xd6\x0e{C\xf1\xf8L\xd9,\xdd4\xdd\x0b~\xde\x13(\x94\xad\x08\xbb8\xfeyN\x9b\xea\x10\xe8v}w\xbd\x19Z\xdan\x9a\xdduu\xc6Wg\xbcQ\xaa3\xbe:\xe3\xab3\xbe:\xe3\xab3\x1e)\xd5\x19_\x9d\xf1q\x8b\xa3:\xe3\xab3\xde(\xd5\x19/Ku\xc6Wg|u\xc6'\xd5\\\x9d\xf1\xd5\x19?\x95\xea\x8c\xaf\xcex\xab\xa4:Z\xab3\xbe:\xe3cs\xa4:\xe3\x8b;\xe3\x9f\xa6Y\xd7\xdeu\xbd\x0e(1\xcelW\x8fo5\xfa%N\xc5\xc4\xc9L\x0dnP6\x04\xcdn7\x81P\xd8\xffC\xff@&GQs\xa4\xf7\xcb\xe8s'\xb4\xc9\xf4\x02\x86\x10\x98\xe4N|\x91Gz\xdf\x0f\xed\xbf\x8au5\x90\x1d?\x19\xf9\x99\xa2\xf4\x99\xa4\x0e\xed\xc2\xb5(\xba\xf2J\x017\xc4\x95\x95l4o\x89\x1a\xfa\x19\xe1\xa2qV!\xf1\x08'\x16\xe19\xe1/\xbc\x02u\xae\xde\x84\x0fi\x7f\x97.N\xba\xb9\x97;\xa5dz\x9c ?\x9a8\x1394\xa3}Lx\xcft\xd5\xdc\xa6\xef:\xb2\xe1w\x8aM\x152\xdb\xa5\xd1\x19\xdd4\x81\xbb\xf6\x8ba7\x84\xe8r\x99\xc1\xd6\x8f|N \xa4eW\x13A\xedH\x9bn\xdb\x0c\xd2\x1c\x9a\xdcM7C\xdfl7\xcd\xc8\x1b\xa7S\xb9\xd9\xbcdo'\xba1\x1a\xe7&S\x08\xaaU\xdf\xda\x899\xf9\xe2M\xd4\x13k\n8\x85b>\x96\xa2\xf1\xa5Pl\xa9d\\\xa9`L)\x10O\xca\x8a%\x95\x8b#\xc5bH+\xe3G\xabcG\xc2_\x8d\x8c\x967n\xb4:f\x84\xde\x9b\xe6\xbd9-/V\x04\xc7\x83#\xcf\x17'Z\x13#\n\xc5\x83\xb2cAIq\xa0%1\x9f\xacxOF\xac\x07U+Ec:\xa5\xe39\x05c9)q\x9c\x821\x1c\x7f\xfc\xa6h\xec\x06\x8f\xdb &=\xa6\xa5\xd6\xc6kDl\xc6\x11\x87\xc5jV\xc7i\xd0\x18M`+\x0e\xc4fb\xbbt\xa9\x98\x8c?\x1e\x13jA^\x1c\xc6\xb9\x8b\x0d\xbb\x8d\xadP\xfc%/\xf6\xe2\xac\x12w\xc3-\x19s\xa1H\xbc%/\xd6\x12 %xc, \xf1\x15\xcc\xd9\xba$\xae\x82\xbd\xff\x17\xbc\xef+c)i\x9d\x8f\xc7PB=M\x88\x9d,\x8a\x9b\xd8N\xa6\xecxI$V\x12\x8a\x93\x84c$\x9eQI\x8f\x8d\xc4\xe3\"nL$+\x1e\x92\x14\x0bY\x13\x07A\xe3\x0e\xf1\xf8G\xb1\xd8\x07Z\xbf5\x93\xb2\xe2\x1dn|#'\xb6\x81\xc62\xb2\xe2\x18n\xdc\xa2l\xcc\"\x10\xafp\xdd\xb8n\x9c\xa2T\x8c\xa2`|\xa2tl\"5.\x91\x10\x93H\x8eG\xa4\xc5\"\x10\xb7=Vk\xaao9\x16\x7fH\x8e=$\xc5\x1d\xac\xc6\x97\x8d7d\xc5\x1a\xb0\xd8B\xc9\xb8B\xc9\x98B\xce\xf7N\x88%\xc4\xe3\x08\xb3\xf2\xf7[\xd5\xcaa\xb8\x82\xdc\xc9C\xe7\xb4\x9a\xca\xc9C\xdeT\x92\xb8 #m\xa2\xcb \x9b\n\x925\xc9q2N\xd8Y$M.-\x13B\xc9d\xd21\xa1g\xc5B4L>\n&\xb4N\x0f\xf5\x12\x16T)I\xb9\x14\xa3[\n\xa0;h\xf5\xae\x1b\xa5z\xd7\xabw\xbdz\xd7\xabw\xbdz\xd7\xabw\xbdz\xd7\xad\x9fb\xbbt\xf5\xae\xd3\xea]\xaf\xde\xf5\xea]\xaf\xde\xf5\xea]\xaf\xde\xf5\xea]\xaf\xde\xf5\xea]\xaf\xde\xf5\xdf\xbdw\x1d\xcb\xce\xcf\xc9\xccGr\xf1\x0b\xe6\xe1#\x9e\xb0,2\x9cT\"\x1cZ]\xa5F\xa9\xae\xd2\xea*\xad\xae\xd2\xea*\xad\xae\xd2\xea*\xad\xaeR\xeb\xa7\xd8.]]\xa5\xd5UZ]\xa5\xd5UZ]\xa5\xd5UZ]\xa5\xd5UZ]\xa5\xd5UZ]\xa5\xd5U\xfa\xd7s\x95\xe2T%\x85iJv7\xfb\x93\xe3\xe1nh\xb6\xe4\xe4\xe1\x87\x93_\xfa\xedqG\xfeI\x1c\xab\x939\"\x98\xaeHK\xfe\xd5\x9d{\xcd\xe1\x00{^\x9f|\xeaA\xaf\xd6+)\x9c\xd2\xbb\xe9\xbb\x91t\xe3qT\xd2<\xb5\x19\xc3h\xf4z:\xc1\xb1\xa5.\xde\x90g\xf3\xd1\x95\x8e\x0c\xe1\xc7]St\xe4\xfc\xc7\xc6KB\xc5\x87\xe7\xa3\xaa\xb2\xb5US\x84\xd7\x97\xff\xa4\xe6\xd1QKG\x96\x8f\x19\n\xc7\x1a\xb2\xb1\xbf\xa5_\xd9\x1c\xa7=\x1b\xbe\x9d\xb0\xee\xf9\xf04;\xf8\xb6\xef^K!\xdf\xc2\xa6\xdf\xef\x9bn\xab\xfb,\xb7G\xde\x0d\xed/t\xcaj\x7fK\xee\xda\xee-\xcf\xb0\x16f\x8af~H\x99\xdc\x1bw8\xecZ\xb2=\x81\x0b\xee\x17ivc\xaf\x89c\xbd1\xc4\xf7\xb0%\x94l([\xb0\xdc\x99\xd1\xcc]P]c\xab],2h\xe0\xae} \xdd<`\xdcC\xa8KTM\x11/\x0cb\xe3\xa7\xd3\xb0\xb2\xdd\xe0\x86\x90\x8e\xfb6\xa5}\xa4*|\x05-\xe5\xe3\xae\x893]#\xd2\xd58yu\xe7\xb6\xb6#\xf4G\xfa\xba\xbf}\xbdm(\x99\xd5\x8fj\xceU\xcb\x16\x91Nb\xf3\x8f\"M\xbd5\xd4\xd6@\x9a\xcd=\xdb`\xa4\x918\xc9\xe7\xd3\x81<\xb6T\x19\xb9\xb4\x8d\xceB\xb5\xeaX\x8b^\xb3\xe7\xf1\xf9id\xd43+\x8dc\x1e\xcc\xf4\xf9\xb9#{\xe9s9\x90\x81\xc9'[\xdd\xea\xfe\x994\x0f\x84\x0f-\xed\xf9\xe2\xfbW2\xf4\xd2\xaa\x93N\xee\x86\xe9\xd3\xd7\x02\x0f\xb2\x9d\x06\xa1\x1b)i&Q\x8b`\x02\xa6J \xf7LA\x03\xe8\xd2\x8e}\x90\x06\xf9\x96\x9dW\xf8\xb7\x94>\xbf\x91L_\xc4$\x8d\niT\xa3]\xfc\x04>;\x86g\xff\xda\xb4\xa8\xba[\x05\xb3h\xbb\xcd\xee\xb8\xe5.\xe1\xd7\xf6U\xd0\xe3qs\x0f\xdc\xd6\xb9k)_\xdc-\x15\x13\x95;\xc7\x1a\xda\x0fL\x19\x1ew[h\x8e\xb4\xdf7T\xf2G\xa9z\xa8Z\xa8J\xcd\\ovl\x7f\xbc\x1eiC\x9d\xb9fE\xe7\xf0\xd8\x1cE#s^g`\xd8\xdfW0&\xe7\x8f\xc8\x95\x8b\xc7\x15\x8b\xc6ycq\xd8\xe101\x12W*\x0e\x17\x8e\xc2\xad\x8a\xc1\x95\x8d\xc0y\xe3oe\xa3o\x9e\xd8[f\xe4\xcd\x19n\xf7P^:\xea\x96\x19s+\x1cq\xcb\x88\xb7\x95\x8e\xb6\x15\x8b\xb5\x95\x8d\xb4\x15\x8b\xb3\xc5\xa3l\xc5bl\xbe\x08[N|\x0d\x8d\xa7!\x87ZW\xdf\xe4\xc5\xd2\x90\xd8\xd9\xca\xc8\x19\x127\xf3n\x94\xde\x98Yx\x07]\x19/\x9b\xe3c\xd8\xf8~\x13\xaf\xbbp\xa4\xcc\x8d\x93\x15\x88\x92\x15\x8d\x91\xd9\x9baf|\x0c\x89\x89\xe5D\xc4\x82!!O4,\x1a\x0bs\xdd\xef\xe9q0\xf7\xdd\xbf`}]\x15\x01K\xe9l,\xfa\xe5\xef[4\xf2\xb5 \xeee\xba93c^\xc1\x88\x97?\xde\x15\x8av\xa1\xa3\x90\x1a\xe9\x8a\xc5\xb9\xec(WF\x8c+!\xc2\xb5<\xbe\x85D\x97b\xb1\xadB\x91-\xa4fc\xa6\x14\x8di\x15\x8eh\x15\x8dg\x95\x8cfycYv\x80\xc0\x8ec\x95\x89b\x15\x8ba\x95\x8d`\xa5\xc5\xaf\xa2\xd1\xab\xc4\xd8UJ\xe4\xca\x89[\xb9\xb5\xa5\xc60\xc21\xab\xc4\x88UB\xbc\xcahr\xc9XU\xe1HU\xb98U\xb9(\xd5\xfa\xaf\x1b\x8dP\xc5\xe2S\xe1\xe8\xd4\xc5\xdb\xb3\xd7\xa4cG\x9a\xad\x0c6\xa9\x13\xfb\xeb\x96\x0f\x8d\xf0\xccq\x16o\xcdQ\x0f\xc2\x83\x06\xdc\x83f\xaa\xb2\x96\x8e\x93\xe7\xed\xb03W5\xf75\xf1O\xb9o\xbe\x08\xa5\xc9+\x9d\xbcz\xbdtU\x0c\x03\xd9\xd0\xb9\xb6\x97#\xd9\xdd~'+\xd5\xe4\xf1\xea\xe1\x86\x9f6\xf5\xf6IV\x9bWz\xddc/Cl3i\xba\xd6\xe1\x072\xb4\xb7O\xb3\xff\xbb#_\x9d\xce\x1a\\;\xe2\xa0q\xf3$\xdf\x14s\xf10\xf4\xfd\xad:hk\x0f\x1f\x06\xf2\xd0\xf6n\x1c\x887\xe0\x04\x1f!A\xf1~\xf1\xf6lj1\x8f\x12\xf6p`2F\n\xe3\xbe\xef\xe9=;\x95n\x86~\x1c\xf9`w\xc6QF\x8c\xad\xec\x86h<~\x96\xf9\xb8k\xf4P\x93\xc6\x1e\xcf\x0eJG\xca\xba&\xa4O#\xccV5\x0f\x06\xb4Tz\xd2\xa4,>\xf4H(\xea\xff>\x92\xe1\xe9T\x04QX}\x9f\xc8x\xe8\xbb\x91$\x87\xa7J9\xcf\xefU|B\xb8\xd9\x0cj\x1d\xdd\x7f\xcez\x0c_\x9b9\xf2\x13\x18@_\xe7T-\x83\xfa7\xd7\x8f*:\xc6\xdf\xfa^{MJ\xfb\xf4\xf1L\xcd ah\xf8\x86\xf3Lx&V\x0d\xe7a\n\x0d:\xdd\xe2=o\x95\xd6\xe4U\x18K\xfa\xc4\xfa\x06I.s3\xba\x08\xeb\xdd\xe59\x91FK\x14\x16w\x84\xd2\xb1G@\xe3\x8f\x90\x1f\x83\xb4\xa45\xbb\xb1w\xe2\x90P \x16i\x89s\"\x93\x90\x1f\x9d\xb4\xa4\xc9/gWR2J \xbeH%,\x8aV\x82\x13\xb1\x84\x14\xff\x96\x1b\xb9\x84`\x8c\x0f\xb2#\x98P.\x8a \x882\x86\x94^\x9bJ\x19\x92z\xbc:\xb2 \x89\xd1Mp\"\x9c\x10\xea\x8b\xef\xae\xa2\xbch\xa7%,7\xe4\xe9(\x00\xed\x0f\x91 (\xf8\xb4:\x04o\xe8\xa7\xde\xfb\xf9\xbd# QM\x0fe\x83\xa3\x10\x81,\x96\x0c\x92B\xc9@)\xc4n\xe4\xa7\xeb\x03\xa6P0h\n\xd1\xc0)\xac\x0d\x9eBN\x00\x15\x1b\xb1\xf8-\xfc\xab\x03\xa9\x88\xac\xe8\x0d\xfc9\x01UD\\\xf0\xf6\xfd\xb2\x81U\xc8\x0f\xaeB\xf9\x00+\xe4\x05Y!/\xd0\x8a/Q\xb4\x91\xc5\xc2\xafP<\x04\x0b%\xc3\xb0\x90\x14\x8a\x85\x92\xe1X\x88\xdc\x9e\x9f\x13\x96\xc5\xd6\xb8\xe7\xe6|\xc4\xbf\x83\xeb\xb7\xbc\x80-\"\x10\xbf3\x7fe\x18\x17\xfc\xf7\xe5\x07\xb7\xf8\x00\x0c2e\xff_\x19\xda\xc5\xd4^\xe0\x96\xfcp;\xf2\xc2\xbc\x96\xb0\xd0\xfd\xf8\x05\xc2\xbdP:\xe4\x0b(02;\xf4kI\xa3\x0882/\x18\x0c\xb1\x18)\x84\xef\xc3\x8f\x06\x86\xc1{9vz\x80\xd8/\xc3 \x10d\x05\x8ba\xc1`\xc4\x82\xc6\x10\xedw4x\x0c\xcb\x02\xc8\x80\x02}2\x03\xc9\x10\x0b&C\x04@\x19\x83P\x06F)5\xb8\x0c \x01f@\xa1\x94Y\x81fH\x0b6\xc3\xaa\x803x\x07&\x1ax\x86r\xc1g\xf0\xb7\xc2\x99iE\x03\xd1\x90\x19\x8c\xb6Da`\xcb\xc2\xe1i(\x1c\xa2\x86\xd8]\xf5\xd8%\xde\xd8=\xf5eB\xd6P2l\x0d\xc5C\xd7\x90\x1c\xbe\x86\x94\x106\xa4\x87\xb1!1\x94\x0d\xbe{\xe9\xf1\xdaS\x03\x9f1(frh\x1b\xd2\xc2\xdb\x80u\xa3d\x98\x1brC\xdd\x96,\xf4\x1e\xfar\xc1o(\x1a\x00\x87\xec\xf9\x10\x0d\x84CB0\x1c\x92\xef\x9e\xcf\x0b\x8c[\xc2D\x9c:\x12\x1c\x87\xec\x00\xb9%L\x8f\xd1'\x06\xc9\xa1D\xa0\xdc\x92\xd7\x8e\xcb\x82\xe5\xb0(`\x0e\xa5\x83\xe6\xb0$p\xee\x8b\xc2\xa6\xc4}\xb5\xd7\xa4\xb4\xe4\xb8\xaf\x81\x11\x1d\x17\x87~\x05\x90\xf4Z\x8e\xed3\x93\x18\xbaq\xdf\xa0\xc3 \x05\x9b+\x8a\x83\xd0\x8d\xca\xf6\xa0u\xe5{\xcb0\xbb\xa2\x14D\xee\"\x02\xcd\xab\xac\xcc\x8f\x06\xe6\x8dV\xa2\x02\xe1\x84\x93\xb1W\xd2\x0esM\x9a %!\x9a\xcf\x80\xcf\xb2\xe0\xd4\xd6_\xff\xde|\xff\x9by\x92Gf\xf7g\xa9N\xceT\xe3/\x99\x06[<\xcb\xe7@\x97\x92S\x01\x7f\xabbY\xc5\xe2X\x15\xf0\x97\x16\xaf\x12~vg\x8c*\xe0oI\\*3&U8\x1e\x95\x11\x8b\xca\x88C!\n\xa3`\xc4\xa9l\xb4\xa9X\xa4)\x1ee*\x16a\xaa\x80\xbf\n\xf8[\x10 \xaa\x80?$\xce\x93\x13\xe3I\xc1\xc0U\xc0\x9fV*\xe0\x0f*\xe0\xaf\x02\xfe*\xe0\xafT\xf4\xa4X\xe4\xa4l\xd4$-b\x12\x8d\x96$FJR\xa2$\x15\xf07\xcb\xca\x8a\x82T\xc0_\x12\xe0/\xe0\xd7\x0b\xfb\xd7\xd2\xfd{\xb8\x1c5\x12\xa6\x9f\xaf\xbd\xd9\x9cl\xfa\x81\x9c\xb0CYGv'\x0f?\x9c\x9c\x89\xffLv\xe8\xd9\xde;\xe9\xb0\x95\x00%\x11\xe6\x98\xe3\x04L4\x90n\xb6\xf4\xd13\x08\xe9\x8e{}\x8f\x7f\x0d\x97W\xa7W\xe7\xd7\x9f\xdf_\xbc\xbf\xb8\xba8\xfd\xf9\xe2\x7f\x9c\xbf\xbb\xfe\xfc\xfe\xf2\xe3\xf9\xd9\xc5\x8f\x17\xe7\xef\x90g\xd9\x93\xc8\x9f\xaf>\xfd\xe9\xc3\xc7\xf3\xf7\xc8/\x9e?\x9f\xfd\xfc\xe1R\xab@nlo\x92[\xe4\x07S\xf0\x0f#<'\xcc\xc8\xbfeKS\x8eP\xcb\x8d\xfe\xbe\x9b\x86N8T\xd8R\xe3#jxAE\x0b_\x01k\xc9+\x90\x1d|\x05\xec\x7f\xd9!\xc0h\xa2i\x05E\xc7\xf5\x0d\xbc\x93\x1b\xf9\xa5\x85)5\xc6\xf9\x0d\x9cNMg:\xe6\x7f\xb1\x83\xe0H\x9b\x81\x12\xb1u\xf7\x07\xc2O\xd1\xf7M\xb7\x1d\xef\x9b/f\xa2\x9f\xf5mli\xcd\x86i\xb0\x1d\xd9\xdeIi\x93\x14\x18)9(7\xd0\xa6?v\x94\x0c\x87f\xa0O*$\x85T\x82\xd5\xb0\xe9\x99f\xa1\xb6\xf8\x13\xf8p \x9dzr\xb4\x88Z\x07\xd2l\xb9/f$\x9d\x00%\x0ddC\xda\x07a.\x11:\xa2\xd5\x8b\x8fe7\x80\xa3\xb06\xbb~\x94\xf0\xa6M\xd3A\xd7\x03;\x98\x92aB\xcb\xa9\xba\xfaAU\xa5\xd5`U\xda\x0f[\xc2\xd6\x94\xb32\x15\xdaL_\x90\xed(\x9e'\\\xf6\xb1\x93\xffX\xbaH?|zw\xfe\xe9\xfa\xfd\x87\xf7\xe7\xde\xb5)\x1e\xf9\xfc\x9e\xff?\xfa\x9b\xfd\xcb\xb4\xe0\"\xd2\xfd\xeb\xcc\xd7\xb07\x1ci\xf5Z\x98SL\x95\xaa\xe1Pcg~?\xab\xe9o\xd4\x88+z\xe0-\xd9\xb5\x0f|\x0c\xd9\xb6\xd6= 1\xaf\xe4\x06\xb8o\x9e`\xdbr\xbf\xc3\xed\xd0\xef\xc5\xaa`\x0f\x80A\xab8\xc1\xa9\x9e\xe0+\x19\x08\xfb\xde\xf4\x04k\x87\xd3\x8af\xd0\x9b@\x1e\x9b\x0d\xdd=)\xa3V\xd4\x84 \x97\xb2\xf5\xc5\xe3*skey\x94xR\xc8\xe6\xd0\x0f\xf4\xba\xdd&:\xa2\xc2\xfe&\xee6\xf1\xae~\xd9\xdd\xfe\xab\xb4O\x85\x03\x8e\xaf\x1f,f\xa3\xb6\xc0o\x9c?\xa57W\x8d\xd7\xd5\x8d\xa9\xed\x14\x95\x8d\x0fP\xb6\xaa\xfe\x0d\xd4tPE?\x8bz\x96S\x8d\x7fI\xaf\xbd(k\x14\x16\xdf\xfc5\xb0)\xf1\x91\xb7\xe9r6\xdc\x13\xcc\xfc\xb4\xa5e|U\xd58k\xa1->\x19\xa1BEB+\"v$\x7f>\x92n\x93z\xd3\xcb1\xc0\xe7&\x0f\xd3J\xa2\xaaa\xdb\xd0&Q\xba\x91|d\xc8\x9e\xa2OL\x9a\x15\xa7\x1a\xa7\x9a\xd9'B\xb2\xa9\xa7\xf5\xa2}\xc9ib\xb0 \xc53e\xda\x8d\x88\xb0tdC\xc6Q&\xdd\x0d\x84\x0e-y\x10)\xe3#\xed'\x93VV)\xe0 {\xd6\x8aW\xba\xe5\xad\xfe\xa2\xcc\xdc\xc3lj\x9e5\xbb\x1d[ \xa3\x8a\xec\xb4\xec\xc4\xcfV){[)k\x954j\xb4\xa6\xe5\x9b\xe2@(\xdfP\xd4\x17\xe4\xdd\x11a\xbe\xa95Ncx\xa6a\xa3\x1a\xe3\xd3~\x02F!\xfe}\xc61$\xebR\xbe\xa7y\xe6\xbd\xe2En\x07:2\xa6\x19\xc7~\xd3\xf2\x84%\x959oi\xf1E\xa6\x93\xacx\xb15\"9&\xed\x9dN\x13Y\x99\x9a\xe6R.\xbb\x1dJf\xb8Cej\x82\x9c\xccwl\xc4*SS\xa1\x8cx\xc8\xcf\x8a\x87\xf2\x99\xf1\x90\x97\x1d\x0fy\x19\xf2\xf8\x12E\x1bY,o\x1e\x8a\xe7\xceC\xc9\xfcyH\xca\xa1\x87\x92y\xf4P\x99\x9a\xb0jV\xe6\xdfCejZ\x97\x9fo \xabLM\x95\xa9)AFej2Kej\xaaLMP\x0e5\x00\x95\xa9\x89&\xe2\n\xa00\xb6\x00*S\xd3\x02\xcc\x01$\xe3\x0e \x05{\x00\xe9\xf8\x03H\xc4 @ejJ\xc2'@.F\xc1\x92U\x99\x9a\x10ak\x99\x9a\xd0\x9b\x87\xfci\x05Z0ov,\xeb\x01=\xdd\x15,\xf5\x84\xae\x18\x1cJ#;\xa4\xa7v&Ng\xb4&\xe0 \xfb\xb5'\xc3\x97\x1d\x01\xc9\x8at\x0b\xe4\xb1\x1d)\xe96D\x97\x7f\xed\\\x82#^F\xef\xaf\xe1\x92\xbe6\xe3\x14MX\x95\n0\x90\x87vl\xfb\xee\xba;\xeeoT\x8c\xd2\x94\x83\x9c'\x03T;\xb2\xc9B\xc9\x0b\xd93\x9d\xd4t\xd5\x92\xe6<0\xbc4SsV\xdd@\x11n\x8e\x1cE6\x0b\xe46*.BQu\xe2\xd3\xcd8\x84\xbeg\x15\xb1\xdd\x9b\xbd\xfdI\xbe7\xdd3\x02m\xb7\x19\xf89\x9e)\x0b\n\xa4aK_\xd6z\xdf\x1a\xd4B_\x0890e\xa2\x84\xbc\xe7\xc3\xaf\xafV~\xc8l\xf6drl\xc2\xd8\xef\x89\xc6.\xd4\xec\xee\xfa\xa1\xa5\xf7\xfb\x91GL7\xf7}?\x12\x11^\xe2\x97\x80\x98\x0eNu/R\x07\x1b2PA:\xd6m\xa5_\x91\x9c\xdc\x9d\xc0}3p7\xcb\x97\xf1\x95X0\xaf\xf7\xcd\xe6\xbe\xed\xc8\xe4/\xd2\xc4I\xcf\x91^\xc3\x05\x1f\xd4\x91\xc0\xa6\x19\xc9\xf8\xca\x18#\xd1={\x8c\x14\x17\x99h\x9b.\xbd\xefh\xdb\x1d\xb9#K\xaf\xe2\x86\xc0\xbe\xefZ*<\xdb\x92Q\x87\xb3\x8ck\xb4\x07\x86xY\xc8\\\x01\xa1\x85m\x83\xe3!\x85m\xc1\xf3\xbc\xc5d\x01A6\x0b\xf03Z\x80\x9f\xd5\x02\xd60[@0<\x0e\x05\x19. \x8b\xe5\x02R\xc6>\xc0t\x01e\xd9.\xe0\xb7b\xbc\x80\xe7`\xbd\x80\xc5\xcc\x17\xf0[\xb0_\x80\xcb\x80\x01(\x0b\x06@\x16\x13\x06,_\xf4QV\x0c\x880c@\x80\x1d\x03\x12\xe1\xd6\xf3\xb3\xa1\xf5\x9a\x0d\xbf\xb6\x05=#\x0c[\x95(c\x06<\x17,[\x14\x9c9\x03 \x9d=\x03|[\x17\x04\xe1\x96(\x93\x06\x84\xe6'D\xdd\xfdP\x9aU\x03pf\x0d\x08\xb0k@\xac\x0b+X6 \xc4\xb41Wh\xb2m\x00\xc6\xb8\x01\xa1\xd6\xc9\x969\xc3\x9a\xcf\xbea \xec\x9d\xf0|\x84\x90\x03|\xd7\x9a\xc5\xfaR\x8e\x9c#4\xf7\xb2 \xee4Y\x13\xd5\x9d\xf6\xb7B|wz-\x19\xa4wP\x8f\xe5\xab\xce\xc1\xf5X^\x8f\xe5\xbf\xc7cy\x80\x11\xdd:\x1aC\xca\xed\x9dR\x17~\xfax&%)\xb2s\xf9\xcf\xb7d\xe4Qf\xf6\xca\xd9\xbc \xbe\xe2y\x0f\xfc\xeeX\x9e\x7f,\x16\xb4\x8a\xb4\xc8\xcf\xc5\xad\xa9i\xd1\x7f\xa3+\x0bs\xed\xa7\x10j,\xbf\x1fT\x1d*l\xc5\x97Ds\x95|1(r\xb8_w\xbc\x0f\x1a\"\x98\xb5\x9fp\xd0\xf4\xbe\x81\x1c\xf3c\x07\xfd\xe0Q?x\xd8_y\xdc\x8f\x1d \xca\x1e\xf9s\x0f\xfd _#r\xec/~\xf0\xff\x0d\x8f\xfe\xcft\xf8_s\xfc\xff\x8d\x1c\x00\xa8\x0b\xc0\xe7\x04\xc8v\x03\xacR\x0e GtHp\x07\x84\x1d\x02\xcb\\\x02\xf15]\xcc-\xf0\x9b:\x06\x12]\x03\xcf\xea\x1c\x08\xb9\x07\x969\x08\x02.\x82\x90\x93 \xe0&\x88\x9c\xb2S\\\x059\xce\x02T\x9c\xb6\x06\xdd\x0f\x15r\x18D;\xb3\xd2i\x10q\x1b\xf8\x1d\x07\x1e\xd7A\xb0\x9d>\xf7A\xa6\x03\xc1\x91\xa6\xe8<\xdd\xb6\xc5\x9d\x08knG\xf7\xf7k\xa5s\xc1\x913\xed_\xc6/\x9e\xa9\x1fo)N\x0d*\x8a\x7f\x16\xc6\xe5N\xdb\x0b&:\xa4\x85\x0b\x12\x87\x8a\x82\xd2\x87\"\xedP\x13\x8f3\x05ng\xbb`6\x9cg\xcb\xe3\xd0\xdc\xb5\x1dO\xa6p\x1c\x0e\xf3O\xd3\xd1g~$\xdd\xb9\xd0\x91Gz\xfd\x85\xd8~\xd6\xd81\xde\xc9y\xb6\xe3\xa8\xaa(\xf9\xea\x98\xc6\xfeS\xa6\xd37\xa34A>6w\xe4\x93\x08B\x9e\x88\xdf-!\x7ff'$\xfe:\x13\xc7\xba\xce\x0e\x99#\x05\xc2\x93\xd8\xb9\x93B{\x85\xf6\xb4IE;\xc5\xfd\x12\xce\x1a\xe3\xe2y\x7f\xf8\x7f\x08\xaf\x8c\xf0L \x08\x83\x96yo\xebd\xbd\xab\\K^s!\xb6\xde`\xe7\xc6\x91Pv\xfe\x1c\x15\xfeb\x84c'\xa6\xe8Vh\xfd\xaf\xed\x98\x02\xaa\x15Uj\x87\xe5\xde\xc8Mj;\xb8\xfb\xf4\xf1l>?\xcb\xa4\xa1\x91Yq\x03\xb1t\xc3\xa6\x1f\xc4\x83\xdcS\xa7\"\xc7*\xcf\x88\x19\x9e\xdc\xae\xd4\xbbi\xf4M=y\xd9\xef\xe7F\xa1\x08\xe6\x81\x1c\x08\x8fS\xbfm\x86id}\x88z\xa3\x8f|z\xd8il*\xb3\xc8\xe3\xbe\x133\x8c\xfb/mW\xc7\x82\xc5T=u\xd5SW=u`y\xea\xc6\x15\xae\xba\x11\xf1\xd5\x85\xbcg\x93\x11W\xfdh\xd5\x8fV\xfdh\xd5\x8fV\xfdhK\x95C\x92_\xab\xfa\xd1\xaa\x1f\xad\xfa\xd1\x9c\x07\xaa\x1f\xad\xfa\xd1\xaa\x1f\xed\xaf\xe3G\x9b\x0d\x02+\xb7\xbd\xd1\xe6du\xa8\x19\xa5:\xd4\xaaC\xad:\xd4\xaaC\xad:\xd4~\x7f\x0e5[\xf1G\x1c\\K\x11i\x8e\xa0DD\xda{\xf2H/\xe5\xb5]\x9f\xc4\x19w\xb1\x8f\x8d\xef]\xea\xee\xafkyR\xb6\x1dn\x9e\x8c]k\xf5\xc8Q\xe2\xdb\x97\x928\x1d\xf6\x85\xb6\x90\xcf\xd6\xb4`\xfd\x874eTuc\xd5\x8d\x7f3\xbaq\xd6Jv\x98A\x18Sa\x85\x18\xd0k\x89\x9aQ\xdc\x18xj\xde\xa5\xb7X7Zw\xf1e(,\x89\xe7\x08A}\xc5\xc1JW`\x19\xf5U\x05Y\x15dU\x90\xbfc\x05\x19TP\xc6%\xa7r\x12\x8b\xc3\xdbt\x80e\xbaS\x91\xa0J\xe5\"\x16k\xb3\x1b\xfb\xa5\xf8\x08)\x06]\xe2\xcbT\xec\xf2\x18\xaf}\xf9\xaa\xad\xf4\xca\xc6z\x97\xfb\xf8\x8c\xd5\xa9\x9cg\x9e\xbb~EY\xe5\xf2C\xab\xf1\xde\xfe+\x8a{\x07p\xb4\x9a\x80\xea\xb2\xdap\xc0o\x05\x96O\x1aw\x03\x8b\x92P+r1\x9aQ\xe7\xd2\xdb\x82\x11\x11\x96#\xab\xc8\xcd\xc1\xe6\x0cZq\x81\xb0!\xa0\xc4=\xc2\x86@~\xa7\xb091\xe8\xba\xab\x85\xa1zcU\xa9\xde\xd8\xea\x8d\xad\xde\xd8jPW\x83\xfao\xd7\xa0\xa6H\x96c\x8a\xfb\x01\xb7l\x17y\x1e\xce\xa6mw\xb1A<\xef\xd8\x19\xe7\xff\xeao\x10\xa5\xaa\xc7\xaa\x1e\xff\x8d\xaa\xc7\x7f@\xd4\xa3\xab\x96V\xb9\x1aT\x9bW{\x1c\xe6\xe5\xadD-p9\xcc\x9dX\xeem\xd0\x8em\xd5\xd1P\x1d\x0d\xd5\xd1P\x1d\x0dS\xa9\x8e\x86\xeah\xa8\x8e\x86jIWK\xbaZ\xd2QG\x03b\x84\xaeq2hb\x16\xf9\x17>\x89\xbdt\xb1\xfd+\xb3\xb1\x9c\x8b\x18n\xfa~G\x9ayfO{\xa1\xf5w9\"\xe3q\xc3\xac\x05\xb8\xdd5w\xbc\x8b\xed\xad\xda\xde\xc5\xd1\xbf\xfa\x15\xd6\xab\x9f\xaa\x0d\xab6\xfc\x1dkC\xcc\xaf`\xa9\xa3T\xa7\x82r'\x08yR\x81$8\x17^=\x8bw\xe1s\xa7\xb4\xe3\xe9\xe6\xcbr\xd7\x82:\xc0\xaes,8\xcb3\x9cc\xab\x806\xc7\xa9\xcd\xf6\xa1kn\x8f|\xb7Z\x87Jt^s\xaa>\xac\xfaP\xe8\x04\xcc:\xc4\x95\x08\x84X6\xf4\xd7\xbf7\xdfO\xb4 \xe7\x97\x84:\xfe\xdbS^\x96\x13\xb0\xea\xac\xaa\xb3\xaa\xce\xfa\xedu\x96\xa5>\xd6\xa8\xad\x15\xe7\xda\xcb\x99\x80\xc7\x99\xe7:3F\x94\x9e\xc5zN\xa3\xc8\xc1\x89q\x10:\x1c\x84\x04g\x11\xf5\x0d\xee\xab,As\xb3\x8e\xdc&:f\x1eJ\x9bBD6\xcfN_S\x94\xb4&\x9d\xaa\xe6Y j\xb4\xca\xe6\xe5\xc2\xb7\x0f\xb6Z\xfeQ\xdb\x1e\x12vv\xef.\x17\xf4\xc5\xe0\x1b\xf7\x8a\x9d\xcd\xbb\xab\xad\xac>i'\xc3w\xb1\xcc\x1dL\xed[R\x1a\xbe{\x15\xdc\xb9\n\xeeZ\xd6\x8e\x95\xbb[\xcd{\x94\xea\xf5\xb4S\x15\xdd\xa5\xa6/7\x7f\xa4\x86\x89\xefQ\xf1\"\x94\xab]g\xcd[,i\x82\x98*h\x06\xf6e\xef\x9a\xb6\x1b)4\x9d`\x97\x91\xa2\x15\xe1\xdd\xe18\x1c\xfa\x91p\xe6\xd7\xe3a\xdb\xd0y\x10\x9bn\xba%\xf8v \xe4_Y\x9db\xea\x8f\xf8B\xd5X8\xe6\xbb&\x93\xd7\xed\xba;s\x1d\xaa\x10)\xc6\xe2\xb8[`%\xb3G\xaf\x8fCj\xcc1\xcc\x02t\n\x9f?\xfd\xfc\xfd@\xc6\xfe8l\xe4\xdd\xe6\xfc3\x89\x04\x04\xf6AU\x07\xc4<\xe1\x06\x07z\xe5\xd6|#\xb8\x1d`\xe4\x97\x1eo\xfa\x1d\xdc\x1c9\xf3\x93\x8c\xcb\x9d\xc0\xd5};\xca6\xc3\x9e\xeda\xf2\x16\xf0\xe92$[\x12\xdb\x95\xbf\xfd\xfe[\xb6~\x86fC\xc9p\xc2\xaf9\xe7w\xb0\x8f\xe4\x8e\xbbY\xe4\xae\xfd\xf9\xd3\xcf/F84\xf4\x9e\x8b\xb6\x04M\xc9\x05v\x0d\x14\xb9\xf6\x9d\x8f\x8a\x14\xcb\xfb\xff\xb2a\xab\xd1~\xf5WV\x99\xf7\xa2\xe7_\xbf\x13m\xe5\xc2\xc6\xfb\xfe\xb8\xdb\xb2u\xc0:k\xc9\xd94\x9dXN\\\xfb\xda\xb5\xbcd\x9a\xe6\x15\x1b\x1e\x1e\x15\xfd\xf6\xe4[\xb6\x0c\xbb\x9eB\xb3\xd9\x90\x03%\xdb\xefN\xbe\xb1_\xba\xe8\xe0\xc0\x06\xac\xdd\x90W@I\xb3\x1f\xe18\x1e\xf9\x82=\x0c\x84\xadE\xa6O\xdbN\xde\x9c}\xd3v\xcd\xf0\x04\xcdn\xc7\xfbk3\x10\xa9\x8d\xe6\xc9\xae\x86<\x1e\xc8\x86BK\x99\xfe<\x8eDqm\xa9\x94\x86\xfe\x16N\xbb\xa7I\x15\x8b{\xf1?\x7f\xfay\x14\xaeBK\x9a\xbc\x85\xdf\xaed\xdc\xdc\x93=\x81_\xef)=\xfc\xfaJ\xfc\xff\xf8+Oi\xe8z\xf9\xeb+>S\x98\xaa\xe9\xf9\xcc\xe7=e\xea\xfcxp\x86\x9bZ\x17\xee\x83\x98\xcb\x0f\x9cR\xae\xa1\xb0o\x0e\xa3\xf8\xec\xbc\xa5\xb4\x9f\xe2\xca\xdc|\x94\xfa\xbf\x19\xa5\x9d8\xbeqF\xff\xef\xe0\xe2vn\x1b\xfb\\\x87\xa1\x7fh\xb7d;5\x9f\xab\xd2q<\xee\xc9\xd6\xe1A\xfc;8\xed\xe0\x1f\xaf\xae>\xc2O\xe7W\xca\x02\xfb\xfc\xe9g\xb1d\x9e\xf8e\xfa\x8d{}\xf9\xd5\xd3\x81\xfc\xcb\xff\xfc\x17K\x18\xa8\x08\x7f\xa7\xbe\xb2\xd8\xe2\xf9\xf8\x1d\x86~{\xdc\x10h: \xc3\xd0\x0f6\x87\xd7\xdf\xc1\xe9\xe1\xb0k7\x8d\xec\xf3@\xd8\x1c\xe9\xbf\n\xdbi\xd3l\xd8Z\xec\xfb/\xc7\xc3\x14D\xbfi\x98e%\x1a\xed4\xe5\xf3\xa7\x9fy\xbd\xf7\xcd\x03\xff\xd4{m6n\xc5tlT3\xd9\x7f?\xf4-\xb3\xdfl\xa6.\x90\x95\xf2\x056\x90\xdb~ \xaf\xd4k|\x9f\xa1\xedM\xbbk\xe9\x13t\x84lUR\x02W\x00\xc3\x83\xc3\n\xc8\xb4\x8c\xda\xa0\xd9\xa3|\x05\x9c\xc0\xcb\xcf#Q\x04W\xac\xbf<}\xa8\xd9\x8bg\xf6M\xd7\xdc\xb9\xfdS\xbb\xbe\x12w\xf2\x9d\xfdm\xdf\xf7\x94\xdbQ\xed\x08\xb7\xc7n#\xe6*k\xa9\\\xd3\xb3\x01\xa7\xe5y`\x83\xd9\xf3\xe4\x147\xb9CM\x07\x18\x08\xd3\xa8Dx\xea[\xaa*\xe0\x86/\xdfl\xa7\x19~C\xee\xda\x8e\x1f\x1f\x98Q\xe7(H\xf7r{W\xdf\\\xf2\x99>J\xc28z\xdft\xf6z\x85\x97r\x83'\xfb\x03}\x92K\xe3;\xd8\xf3\xcd\xff\xc6Y\x90\xbc\x99\xd7\x137Jo\xb6Qx\x07\xfd\x85-\xc2\x1b\x02\x0d\xab\xac\xddj\xdb\xa0\xb3\xef\xc9-\xa4\xb9\xe9\x1f\x88j8JJ\xe9!\xf32\xea\xfe\xf5\xb4{\xfaUm\x98#[\xb2\xcdp\xd3\xd2\x81M\xfa@\x1b\x94\xee\xe2}\xf7\xc6\x19\x87y\"`\xa2\x85p\xac\xfb\x7f\x1f\xe9\xfeO\xbd\xdds\xde\xf57\x7f\x84\x7fw\xb89\xf9\xb1\xef\xff\x9f\x93\x93\x93\xbf\xd8\x8f4\xdd\xd3+f6\xb0\xe7\x0eb\xd3\xfc\xa5\x19\xc6\xfbf\xc7\x06\x05k\xa0\xdby\xbb\x1e\xa7\x92\xf6\xd6\xaa\xe2s\xb7\x9f+\xe1M\xe0\x93\x8d?\xf5\xff\xfb#t\xed\x0e\xcb\xf8Cj6f\n3\xd4\xf9\xb8(\xbd\xa1\x0c6\xb8y\x9a\xb7T\xa5\xd58\xd3\xe6\xcd\x93\xf2K\xb2\xcdJ\x17\xf6\x02\xd92\xbfgg\x8c\x13\xfe\x033\"^\xa8c\xb8\xda\x85\xa7x\xba\xf8>\xba\xb8I\x95u\xbb'e#;G\x96\xc9<\x81\xe6\x96Jrd~Jz\xf1\xfd\x0b]\x984\xd0U\xb5\xc2\"'r\x9e|{\xdb\xf7'7\xcd\xc0\x1b\xfc\xf8\xfd\xd3\xc9\xbf~+\xfa*lN\xdbp\xe6\xd5}\xcb\x9ebjU\xfb\xe1\xbf^~x\xaf\xff\xfb\x8f\x7f\xfc\xe3\x1f\xed\xd1f\xcf\xcc\xa72\xb1\xb7s\xd0\x82\xdc\xe8\x84\xd5z\x1c\x89r\x80\xdf\x1dw\x8d\x11\xa3p_f\x0fn\xc9\xbcI\xbd\x9a\x13Q\xe5l\x7f%\xf7=\xe3,\xa7m \x1c\x92\x05\xbf\xfe\x17\xd6\xd5_e>\xc3\xb4\xe5\xea\x03w\xa2\x16\xd7\x1b\xc7\x00k6_\xd8\xba\x9a\xcd\xf3\xdbvGl=\xa5V\xdfG2\x8c}\x87LYyJ\xbem\x87\x91^\xf3\x91F\xd3S\xe5c\xecS\xab\xa7\xfe\x10\xd6\x89\x00Hm\xdf\xf2\x1e\x7f\xfb\x06\xbe\xc5\xe6\xae\xd9\x95\x13\xd1\xe6o_\xb9Rxk\xdf7{&\xe9?\x8b\xa6\xfd\x03\xf2\x18k\xad\xf5T\xa8\xc9\x17\xb7\xd2p4\xbf\xa5\xf8\x16\xed\x08_\xc9n\xf7\xfaK\xd7\x7f\xed\xf8*\xba\x17\xd9\xf0\xc7\x91\xf6{g*\x9a\x93\xe6\x95\x85<\x103I,o\xadB6A\xba;h\xc4\xf4\xd0\xc5\xfd\xca\xa7\xa9\x9a)\xf7\xfdn+Sn\xe6\xda\xf9\x89_\xce0\x90\xe7m9\xc1tI\\\xf44\xab\xe0%[\x97\xaa\xa3\xceQO\xf9\x18\xfe\xe5\x7f\xfe\xcbw\xce\x04\\\xffuM\xe1\xd8\x07\xe6\xdde\x82~8\xf9\xc3\x0f\x7f\x18\xbfu>\x9b\xfa/\xd3)6N\x81\x0d<:\x83:\xeat\xca\\M\x8cZ\xc1\xfa\xb2\x15\xbfKa6U\xae\xc7\x8b\x7f\xa6<\xc2\xbc\xb2\x7fn\xe9\xfdB\xbf\xbe'4>{\x9aEskx<\xa19IA\x05\xa8\xe1\xf1h\xa0\x01\xfe\xc6\xc3\xe30\x0fbu\x99W\x97yu\x99W\x97yu\x99W\x97yu\x99W\x97\xf9\\hu\x99W\x97\xb9,\xd5e^]\xe6\xd5e\xae\x97\xea2\xaf.\xf3\xea2\xaf.\xf3\xea2\xff\xdbt\x99\x9b\xfec\xfe3n\xe2\xfa<\xd8\xba\xe3\xdcrF\xbb\xbes)K\xc1x\x03\x0e\xf3\x8f\xcd\xd0(\xec\x99\xe3\x8bCh\xc5\xc5\xa9\xf7Zf\xe8\xda~\xbc5\xb06c\x18,\xf9\x06\xe2Y\xe1\xdb\xd4\xc9\xdb\x88\x1f\x88M\xd1\x1dW\xd1?C\xceH\xb8\x98\x8b\xb7g\xb0\x13y\xd7B\xd0\x81=J(\x19|\x10\x01q\xab\x10\xff\xa7\x10\xbb\x18\x0fx\xd0F\xdbi\xea\xc1m\xea\xdc$\xa5\xd6\xf7\xfd\xf6\xb8\xd3\xceIN\xa5x\xc5\x10\xfav\xe0\xf9~\xe0\xbb?\xd3{\x94|\xdeoi]\xb9\x8e|\x88 \xb2J]\xbb\xae\xbd'\xe5\xcdP\xaa\xf8\x97\xe7\xcbr\xf1\x87\xaf\xf9\xe2\xd5\xf9]\x9d\xdf\xd5\xf9]\x9d\xdf\xd5\xf9]\x9d\xdf\xd5\xf9]\x9d\xdf\xd5\xf9]\x9d\xdfP\x9d\xdf\xb2T\xe7wu~W\xe7wu~[\xa5:\xbf\xa7R\x9d\xdf\x7f\xbb\xceo\xdd\xb9\x17\xba;\xc7\xa1Y\xa8<\xb7\xfa\x0fiY\xd75 \xbc&\x81\xff\x1e\x93\xc0\xa3\xae|\xc3\xb3\x9e\xee\xc9\xd7\xf9\xb5>}\x13\xc5\xdb\x16d&f\x05\xd4\x1ciV\x80M\x94\x9c0\x9b[\x83\x13v\x13%+\xf8\xe66\xd9\x0c\xc6\x89R2$'\x8a70'\x8a\x1d\x13\x11\xc5\x0e\xd2\x89R&T'J\xb1\x80\x9d(e\xc3v\xa2\xa4\x05\xefD\x89\x86\xf0DI\x0c\xe4\x19\x0f\x07\xc3y\xa2`\xda\x1f\x0d\xfe\x88\x92\x1a\x02\n\x07\xf8\xa4\xac\xb40\x9f|8\x1e\xec\x13\x05\xe9P\xc9\xc0\x9f(Y\xe1?G\x9a\x13\x0e\x14\xa5\\PP\xab\xa6HhP\x94\xdc9\x12\x0d\x13Jq\x91`\xa1(\xf6\xc6\xe5#\x9a\x12%t\x82\xc9$\x9d2dI\x02*\xe3o\x18\x0f\x15\xd2*\x85o\xe0\x17\x90oA\x0f\x01(\x95g\\\xb8Qo\xed\xe6\xa5\xde\xda]o\xed.rkwZ\xb0q\x05nH\xbc'\xe5\xb9\xe1\xc6P\x18\xd0\x00\xf6-\x0f\x04V\x06\xad\xac\xb8X\xb1\x88X\x05\x11\xa5E\xbb\x84\x87\xdd\x19\xa3\n\"\xaa \xa2e\x91(\xf4\xa8^,\xdeT6\xd2T,\xc6\x14\x8f.\x15\x8b+U\x10Q\x05\x11-\x88\xf0T\x10\x11\x12\xb3\xc9\x89\xd6\xa4\xe0j*\x88H+\x15D\x04\x15DTAD\x15DT*2Q,&Q6\x1a\x91\x16\x87\x88F \x12c\x0f)Q\x87\n\"\x9aeeE\x11*\x88h)\x88\xc8\xb0`m\x06,\x0cT\xe4\xe4\xa4\x83\x84\xc3p\xfc\x89&\xcc\xc0AT\xc4\x91\xfeC\xdciN+\xe2\xa8\"\x8e~\xa7\x88#[s\x04\xdc\xf0\xc1\x00\x80\xfe\xfa\xf7\xe6\xfb\xaa\xd13\x83Xr\x04`\x05\x16\xc8\x0c\x01<3\x1c\x08[\x99\xa9\xf7\xe1\xc8g\xd7a{\x82\xaaJ\x14\xaf\x86\x10%\xa0'\xe4\xfbY\xcaK\x94\xa0\n\x93\xd5\x94kf\xb2R\x13%\x96\xe4[N\xc1\x89\x12Ws\xa2d*;L\x9e[I\x86\ntd\xd9~X\xb7\xb6\x82\xeaP\x14\x9fR\x14%C5\"S\xd8\x1eSo\x94Q\x94\x95+\x9aV\xb4^E\xebU\xb4^4\x96\x89J\xabh\xbd\xb5\xd1O%$!\x06\x8a\xbe\x99\x1c\x17\x15%#:*JF\x8c\xd4\xb7\xd0=M-\x16=\x15\xa5l\x0cU\x94b\x91TQ\xe2\xf1TQ\x8aEUE\xa9h\xbd\x8a\xd6\xe3#U\xd1zz\xc9\x8b\xee:\xe2hE\xeb\xc5#\xc2\xa2\xc4pj\xf1\xe8\xb0(\x15\xad\xb7,\x9a,JE\xeb\xf1\x12\x8b>\x8bR\xd1z4#N-JE\xeb-\x8cr\xbbM\xaeh\xbd\x12\x91qQ\xca\xc6\xc7EI\x8b\x92\x8b\x12\x8d\x95\x8b\x92\x1817\x1e\xaeh=^JF\xd8E\xc9\x8a\xb3;\xd2*Z\xef\xf9\xd0z\xbd{\xc7\x95(\xa1C\xcc\xfa\xfb\xae\x0c1\x9af\xb1o\xbd\n5rDS\x07\\\x1e\xd2\n\xcf\x83\n\xcf\xab\xf0\xbcR\xf0<{\x96\x86\xc2\xe3kC\xf3\xa3/(\xdf\xef\xf7-\xdd\xcb\xc0\xfc/<_\xe7\xe3@n\xdb\xc7\xe4@\xfc\x17\xf2t}\xd0^\x01\xdf\xccv\x96\xa9\xddq\xbdz\xd6Q\x95>\xd4\xd0{\x105\x88\xa5)\x97\xacRgW\"\x9a0\xd2\xe1\xb8a\xdf\x86\xad\xd6\xdb\xa1\xdf\xf3\xe7>6\\=n\xa7u\xaev\xc7\xe6p \xdd\xf6%\xfb\xfd\xe4\xbf\x91'\xf6\xffj#\xb0\x7f\xe2U\xbf\xe2U\x9e\x9c|\xf7\x9d9~]G\xb8'\x85\x8d\xdf\xd9\xf4\xaf\xf3n\x9b<\x80\x08\xd5(:~\xc6j\x92qyWa\xb7#h\x8d\x92/K/\xf13'I\xcc;\x05\x1e*E\x9d\x90r\x12\x88\xe8\xa4j\xa8\x8f<\xf5\x964\xf48\xb8QU\xac7\xa2\xa0W\xf6\xa54H\x81\xd6U\x95\x93\xf7~G\xe6\xbdqvW\xa2\x0d\x0em\xf5\xff${\xaa_\x04({\xcf\xb4\x98\x8c\xf2\x1c\xe5n\xd4\x91\xbb\x9e\xb6\xfc>\xc0{\x02\x17o\xcf\x0cY\x0fdh\x99 o\xc7(e\x9cMN\x06\xb8o\xba\xedx\xdf|I\xc2\xc5\\\xbc=\x9b\xbe\x86<\x904\x1d[8\xdc\x85(\x9b\xb5%\x94\x0c\xfb\xb6#@\xbaM\xcf\xd4\xef(#<\xdc\xc1\xaa\xc7\xb9n{\xe3D\xb5\xb9o\xba\x8e\xec\xc4\xe3\xcd\xe6\x0b\xa1\xa3\x94\xccz\xef\x99\xc6V\x18\xde\\\x10\"\x16!\xad\"E+0w\x9et\xba\xfd\x83}~\xd2\x1d\xf7\xfaLy\x0d\x97W\xa7W\xe7\xd7\x9f\xdf_\xbc\xbf\xb8\xba8\xfd\xf9\xe2\x7f\x9c\xbf\xbb\xfe\xfc\xfe\xf2\xe3\xf9\xd9\xc5\x8f\x17\xe7\xef\x90g\xd9\x93\xc8\x9f\xaf>\xfd\xe9\xc3\xc7\xf3\xf7\xc8/\xc6\x9f\xa5\xfb\xe0Mb\xc5|\xaf&\xc3\xa1\x19\xe8\x93oT\xb4G\x04\xc9B\xaa\xcaXd\xb0y\xd8\x92\xbd\xab,\xec\xc8\xb7\x12\x14\xa4\xaa\xebU\xdc8\xda#\xfb\xa0#r\\\xad?b=\xd6\xff\xfa\\\x9d1fdR\xa7,\x81x\xed\xb8Z\x7f\xcd6\xa7[\x19\xc7\xd7\xfb\xfc\xfe\xc3\xd5\xf9\x1b\xb3\xce]\x7f\xd7n\xd87\xe2\xde\xca)\n*\x9c\xae\"7\x8e\xeb\x02\xec>\xdc\xc9\x8a4\x8c0\xed\xe0\xcc\x9b{{\xdc\xc9y\xca\x96^#\xd7\x9a\\6b\x1e4\x1d?\xc8Hi#94\x03\xdfQ\xbai\xdb\x14-\xa7\xfc$\xc2G\x887\xf7\x86\xc0\x1f@\x9d\x85\x8cF\xf0\xe3\x0d\x19is\xb3kG\x85\xceotUpC\xe8WB:\xa0_{\xd1$\xeb\xd6e\xcb\xca\xb4\xd5\xfes\x19\x99\xc6\xec(\xa9\x95\x1d\x8d\xec*.\x8f&\xcelt\x96\xf6u5\xafO\xeb\xda\x9a\xad\x98\xb6]\xb0'\xfb4l\xd4\xeb\x80!9\x8cA\xcd\xd1\xa8\xb9\xda4\xa6IS\xb4(>]\xf4eeX\xe5)s[\x9b\x03R\x9c\xb47=kXc\xe6\x9a\xfe\x9e\xbc\x96\x97\xad\x07m\xce\xcf\x87\x94\x93\x1c\xb5P\xcf\x9e\xae\xfcz\xf6\\|\xf6\xc4T\xcb\xef\xe9\xd4)\xdf\xab\x87\xcez\xe8L\xe8Q=t\xd6C\xe7\\rL$(`&A\x82\xa9\x84=\xf3\x9b\x1c:\x8d3_\x92f\xc0Oz\x98\x11eFJ\xd5\x1f\xc5\xf4\x9d\xa3\xa2\x8e\x92\xc7\x98L=\xa6\x9b\xc6\x9b8W\xbb\n\xbf\xa8\x16=\x9b\x15\xeb\xcc\xa3\x90\x956\xee\xda\x0d\xdf\x938\xfd\x9c\xa9\x05x\x8d\x98\x15+0\x9aR\xe0\xef\x18\xfe=\xe5\xa9Z\xadK\xda8*\xfc\xbb\xc2\xbfc\xd8\xc7\xffM\xe1\xdfV\x90\xd9\xa7\xc5\x16\x84\x99m\x11\xde@\xb3\xabC\xa7?!W^&\xeb\xd1Iso\xaf\xf1\xab\x15U\xae\x8b\xceu\x8dRd\x88\xb3\xc1\x1a\x85\xb2\xd4\x125\x9b\x84\x1e\xdf\xfc\xd7D\xae\xb0{\xa8\x17r\x1a\xb4zbp\x8b\xe2`\xd30\xd4\xb4,\xd0\xb4(\xcc4\x082\xa5y\x10\xd3\x92\x00\xd38\xbct5\xb8\xb4$\xb4\x94\xc6\x81\xa5%a\xa5QPiaHi\x10P\xba\x06N\x1a\x86\x8e\x16\x00\x8e&\xc1F\x97AD3\x01\xa2e\xe1\xa1>\xc4bQhhy`hQXh\x1a(\xb4($4\x04\x08-\x0c\x07\xf5\x81Ai*\x14t-\x10T\x80>\x11\x818\x0c4\x03\x04\xea\x81\x80\xaesl@\xd2\xfe_\x0e\xfa\x19\x02~\x86\xdbQ\x14\xf4\x19\x82|\x16\x02|\xe6\xc1=\x91\x95\x84m\xe5e\xa1\x9e\x14\x05z\xe6\xc2<\xa38\xc6\x00\xc43 \xe0\x89\xe3\xbd\x96\x81;q\x19\x0e\xd6#\x1b\xd6\x99:\x18)\x90\xcep\xbf\x93\xe0\x9c\x0b\xc1\x9c.\xf6\xa5\x00\x903\n\xe3\x0c\x838c\x10N\xef(-\x81o\xa6\x8071\xe8f&p3\x11\xb6\xb9\x0e\xb4\xe9\x81I\xa6\x006\x0b\xc25=\xadpfZ\x16P\x13\x03f\x16\x84e\xe2\xa0\xcc,H&\x06\xc1,\x0d\xc0\x0c\xc2/1\\\x1a\x06\xbd,\x07\xbc,\n\xbb,\x0f\xbaL\x87\\&\x01.\xa5\x1f#\x05n)\x1f\x8d\x82-Q\xa8%^{*\x84.\x0e\xb3\\\x00\xb2L\x84X:\xdd(\x0d\xaf, \xaeD\xa1\x95e\x81\x95ea\x95y\xf3! R\x99\x02\xa84\xb7\x15\xc4w;\xfd\xee\x07\x97e^{\xa8\xae:\x9c\x05\xfa\xee9\xfc\x1d\x07\xc8*?rZsj\x80\xac\x06\xc8\xb8,\x1f\n\xd3\x1f\xa2Z\x10$\xc3\xc4\xac\n\x94\xa1|\xcd\xc9\xb1\xb2zmb^\xdc\xa8X\xcc\xa8^\x9b\x98\x16\x1b\x12>mg\x8c\xea\xb5\x89Kb@\x99\xf1\x9f\xc2\xb1\x9f\x8c\xb8OF\xcc\x07Q\x18\x05\xa3;e#;\xc5\xa2:\xf1\x88N\xb1hN\xbd6\xb1^\x9b\xb8 \xeaR\xafMDb*9\xf1\x94\x94\x9b\x04\xeb\xb5\x89Z\xa9\xd7&B\xbd6\xd1\x890\xc4b\x1c\x85\xe2\x1b\xf5\xdaDYJF.\xea\xb5\x89\xf5\xdaDSJZ\x04\"!\xfaP\xafM\\\x1f[X\xffu\xa31\x85X<\xc1\xb961\xe9\xa6D#\x0d<\x15\x1fm\x06*.\xde\xe1\xa2QN\xc8\x1aD\xd0\x7fH\xf3\xda\xd7 B\x0d\"\xfc-\x06\x11P\xf7\xfd\xaa8\x82!iM(aM\xf0\xc0 \xaa\x00C\xaf*d!\xa6\xf7\x14#'\x02tY\xa0O\x96\x82l2(+\x00\xa5\xad\x98ks\xc9\x1eP\xaa\x07\xb4s\xa2\x84.\x88\xf3SY@\xa8\xbf\xf2\xe7%\x94\x16\x10\xa0\xb5\x80@oE\xf1\xd0[@r#K\xd0\\@\xd4CV\x96\xee\x02\x02\x94\x17\x00)\xb4\x17\x10mq\x06 \x86;\xcd\x04%\x86M\x84\x01K\xc90\xf4\xf6#\xa0\xb4\xf5\xac\x18\x10\x9a.6;\x06,d\xc8\x00?K\x06\x04\x992\xc0\xc7\x96\x01\xcb\x193\xc0\xcb\x9a\x01%\x993 \xa4q\xfc\xfa\xc6\xa3V!\xb6\x8ac\x8b.\x87Q\x03\x11&\x01\xea(\xab\x06x\x995 \xcc\xae\x01\xe5;\x99\xc8\xb4\x81Hr E\x90\x87B\x8c\x1b\xe0a\xdd\x80\xd2\xcc\x1b\x10\xde\xdb\xc2\xbb[\x98\x85\x03b_\x04b\xa0\x15\x1f#\x07\x14`\xe5\x80B\xcc\x1c\x90\xc8\xce\x81=\x873t\x80\x97\xa5\x03V\x1eo\xc2S?\x97*\xd2\x12w;mA^\xbaH(B\x19 \xc1\x9eeRGj\x92\x14\x89\xa4\xf6'\x93IR\xfb!\x93NR\xafU\xd7?8\xa7$T\x8fC\xfa\x1a\xa8\x1e\x87\xeaq\xf8\x9d{\x1c\xf0\xef\xeb9\xeb\x07=\x0d\x8e\x8f\x01>}o:S\\?\x1b\xa6\x9e\x08\x91s ~\xfas\xce|\x8bNz\xb8\xfe6\xa9\x1c\xda[\xd34\xe1\x13\x80c/\xa5\xed 0\x91\xdc[\xc1^\x9ct\x13\xab\xf8\x15\xc8\xe6\xbe\x02\xf6\xbf\xec o\xb4h\xd6\xd3\xd1\x91y\x03\xefd\xee\xfd\xa5NQ\xa1\x8f\xd4\x1b8\xb5\x8f,ls\xf8_\xc7\x91\x9f\xf3\x07\x1eA\xba'\xd0\x1f\x08\xf7\xae\xb8\xde\x0fk\x90=\x02\x9b\xcd\x97\xae\xff\xba#\xdb;)p\x12\x04#%\x07\xec\x9c$+0\x8f\x1d\xfa\xc7\xf3T\xb5\xe9\xf7\x87\x1d\xa1v=\x81\xa9(=J\xfadL\xe3v\xd6v\x0eTM':\xf3\\\x07\xde\x02\x87/^e\x9eC\x0e\x9f\xe4\x19\x8e7\xdb\xcd&\xdb\x1a\xf0\xac\xb1O\xd5h\xb0\xda\x13:4\xddxK\x06\xf6\xc1\xde\x91\xae\xdf_\x0d\xcd&\xdd\xaf\xce\x0es\x91\xaf\xe5\xdf\x01\xf9I\xd0\xb8{\x8b\xfb.\xfa[8\xf4\x03\xfd^:\xdd\xb4Q\x1c5\x04\xe9\xd0l\xcc]\xc4\xda\xa3$\xc9\x80R\x0d\xc7\xee\x8e\x7f%\xda\x7f!\xd3\xbc\xbfiFr\xbde\xbd^\xd2\x07\xf6\x16\xf0\xb7\xd4 DV2\xb0\x93\x1ak\x1fR\x19>\n\xf3\x88\x83\x81\xf4p\xab`}\xbe8\xbb\xfc\xc3\x7f\xb0\xa4\x8f\xec\xf8\xfb\x8d3\x02\xb2\xf7r\x94\xa0\xed\x84Y\xd3\xca\xdb \xa2S\xe1c34jY$L\x83\x91t\xdbk\xd21\xa3\xdf\xc9\x9d\xbf\xe9\xfb\x1dif\x8bh:CY\x7f\xf7\xcf\x13]:\x88\xff\xe7\x9e\xd8m;\x8a\xffnv;\xd8\x0c\xfd8\xbe\x163\x88\x8f\x0c\xa8\xfe\x8c\"\x045\xcbc\x87f}\xaa\x18\xbap \x1b\xd2>\x90\xe7\xeb\x8dU\xc1\xaa\x0e\x19G\xc4@w\xf0V\x88\x8fk\xac\xff` \xf48tbG\xd5\x9b5r\xa9D\x97\x19\xf2:\x1b\x15h\xbeg}\xb6h\x7f\x96>!\xb5DO\xacU\x90\xb4\x03T\xd7t\xcc\x11\xf7\xfbwM\x97\xf7\x0ei\x8aYJ\xf3z\x87\xc2\x1a^\x18\x81\x8b\x95\xfbA;\x188=<\xb8\x86\xe5lD*\xbd#l\xb8UK\x02?f\x80\xd78\x87\x80\x81\x0e\xd1\x0d!\xf7\xd8a\x89\x93AK\xd3V\x07\xc7\x15\x13:\x82\xc03\xf5t\xf5\x91\xc4^\x7f\xda\x01%\xd6U\xa3E\xc8\x8cLY\x0c\xf2 3\xe3!\x99\xe8\xdd\xcd\xfe\xe4k3\xee\xd9L?\xbd\x19\xfb\xdd\x91\x92\xab\xc7\x8f\xfd\xd8\xd2%\xde(\x1e\x0cq\xd3\x9a1m\xe5\xd1TRK\xbde\x82f\xbf>\xdf$y\xa0E\xfai\xd8>D\xb9^\xd9\x0c\"\xe4\xd3\xa8u@\x1f\xaf\xdbnK\x1e\xb3\xea7\xbe\xf6\xd5\xe3\x05\x13\xc8\x19\xe0`\xdfw=w\x7f+\x07\xa1\x1e\xcf\x10m|\xd9l\xe8\xb1\xd9\x89/\xdb\xd8q_\xde8#\x86\xde\x0fp\xc7\x9d\x85\x1d\xa7\x97Cn`\x9f\xf6!\xf7\xdb\x88VI\xb7\x9eV#\x1c\xd4\x03\xdc\xc3\xcfY\xe0x\xa2\x16\xdc\xed\xfa\x9bF\xa1\xf7\xfbaK\xd8\xb8pE3\xbf=:\x93b\xb3!\xe3x\xd6w\xb7\xed]\xf2t8\x90a\xdf\x8e\xa3\x19\x8a\xc6>\x86{\xc5\xf3\xe9\xd9\xd9\xf9\xe5\xe5\xf5\xd5\x9f>\x9e{\xafv\xd6\x9fy\xff\xe1\xed\x87w\x7f\xf2\xfe\xfc\xe1\xfd\xcf\x7f\xba>}\xf7\xee\xd3\xf9\xe5\xa5\xf7\xa1\xf3\x7f:\xff\xf4'C\xcc\xe4\x8e\x8f5\xc7\xaf*\xbc]y\x03bL\xaf\x9e\x0e\xe4s7\xfb?\x0f\xbbfC\xee\xfb\xddV\x1e\xc79\xfd\x9a&\x90\xef\x9f\xba\x8a\xc0\x06B\x17\xfe\xbe\xbf\xe9\xb7\x9cE\xf0\xa6\xddnM\xfd\xe3\x1f%]\xc2\x87n\xf7t\xba\xdd\x0ed\xe4Q\x1c:\xb4\x12\xce!Y\xa1\xd9\x0f~\xa9\xd3\xb0\xea\"\xcf\x1f\xc8\xf0\xc4\xdbu\xecf\x91\xf62\x9c\x9f\xd7\xe6\x12\x9fB\xaa>Y{`~\x19\x9fF\x9f\xc6\x9c\x8es\x1c\x85:\xe9\x05\x91&>\xedY\x03\xf4I\xef\x0d\x0f\x85\xa7I`\xc6Fgkh\xa6&\xcdR|\x86\x16\x9d\x9d\xc6\xcc\\;+\xcb\xcf\xc8\xbc\xd9\x984\x13\xf5)s\xd6o\xc9Ew\xdb/\xb6\x127\xfd\x96\xc4iT\xd0}\x8bo\x82}8\x04\xb4mhs}\xdf\x8c\xb1\xd0\x03r&j\xbb\x916\x1d\x8f\xa0\\\xfbuz\x925\x8a\xbd\x0e\xa1\x13\x0d\x8eo\x8e\xe9c\xec9g\x8bp\x1f\xf1l\x13\xee\x83\xeeV\x01\xa9\x0bq~8d]\xe6.LK\x9c\xe0\xf0t\xb6\x0e\xb7\xa6\xf4\x85\x8a\xbf_b\xc1\xe2\x92\x97.\\U\x92\x16\xb0*\xcev\x02\xbe\xb9\xb9x[\x99Zb+\x88\xd9\x17\xc44\x003\xca\x1b\xbeX\xc5\xe1G=\xedh\x19a\x03\xb3\x9f\xff\xb1\x1di?<\x9dwtxJ\xd66\xec\xdfv\x96`\x9aiv\xf6\xe1\xfd\xd5\xa7\xd3\xb3\xab\xeb\xb3\x0f\xef\xce\xaf\xff\xf1\xe2\xf2\xea\xc3\xa7?]\x7f\xf8x\xfe\xe9\xf4\xea\xe2\xc3\xfb\xb0\xcd\x96\xf4\xb2\x95?\x9f\xf8\xd6/\x17?}:\xbd:_\xfe\xe2O\xe7\xef\xcf//.\xb5O+\x97q\xd2\xdbK\xcd\xc1\xa5B\xf5\xc1G\xbe\xfa\x07\xf5\x1d\x97\xec\xd4\x80\xdb\x91IM\x13\xa9\x1a\xb1\x96\\t-\x954\xcd\"\xd3I\x9c\xd8\xe6\x9d\xc4J\x86M\xac\\~\xe3x\xfd\xbf\xb4w\x1cI,\x96\x14\xff\xc7\xba\x1a\xe5\xe4\x88\xd7\xf8\x13\xe9\xc8\xd8j|\xdaw\xf2\x0fl-\xcfkL\xe9\x80\xb00\x90\xc70qx\xdb4\xdce\xde\x88\xde\x88\xcc/)1\xc3h0\x15\xd2\xbb\xd9wpK\x06\xd2m\x88J3\x97y\xc7\xff|z\xf9\x0b\xafN\xbe~Y\xcf/\xd4\xf4\xe9\xba~\x85\xb6O\xd1\xf7\xc55~\x92\xce/\xa3\xf5\x9f[\xef\x97\xd4\xfc+t\x7f@\xfb\x07g\xfd\xca\x1d\xa0\xcc\x1eP\x0fx\xf5\x80W\xf6\x80\xe7\xee\xe3\xa9\xb6\xc1\x185\x0e\xc49O&\xfc/6\x13HG\x87\xf6\xb9\xe9\xea\x10\x9c\xaa.\x07\xd5\x00\xbe\xfb\x9c\x92\xc0\x15\xe1\x0b\x9e\x92Dx\xee\x7fJz\xd7E\xb1.z\xdd\xc6\xb2\x8a\x92\x87\x0d\xd2\xe5\x84\xf7\xd3\xc4Fz\xd0\xad\xa2\xc4\xa0(\xe9\xa0\xf7 \xec=\xb9\xb1\xe51E\x8b\x9bP\x08]\xb4\xb8\xde\x828\xa3\xb9\xf8\xf4o\xfc\xcb\x07@H\x8e,\x03$+\xffT\xf2\xb4\xb1\x14od\x81gEq \xb4\xa2\x94\x03\xd2\xca\x96\xae;v\xf8\xb1+\xa2D\x0e\x1e\xc1\xc1\x03(\x85f\x91\xb2PL\x8b\xfc\xadL;=\xc7\x872X\x17Q\xe2\x88\x17Q\xbc\xb8\x17\xb0\xc1\xb9\xa2$Lq\xcb\xf2\xcb\x85\xebB5\x85\xab)\\\xdc\x14v\xc8@1\xf35=\xd4a H\xb4\x96Wq;\xc5i\xca\xb4n*\x84\xa7\xec\x88\xfa\xe7|\xcb\xa9\x0e\xf5R\xff\xfc\xab\xc7S\x96\xee\x88\x16\x02\x17\x16\x86d\xe6\xea\xb2\xd0\xb8\xe0\"rS*\xcdD\xe6\x82\x8b\xce\x0d\xd6\xfa,(]\xc0\x90\xba\x10P\x0b\x05\x10\xbb\x90\x87\xda\xb5$)\x0c\xaf\x83\xdc\x85\x00z\x17B\x16\x91\xdf\x1e\n[CA\x1b#ba\x94\xb3\x83\xfcVP\x81\xf6\xa1\xf6O9\xeb'\xcd\xf6 Z>\x11\xc8c\x1e\xf2\xd7\x92\xa6\x11\xa9Z\xbf\xc4\x10\xc0\xe0C\x01\x83\xff;\xd9h`\x98?K2\"8 \xde\xc7\xb2\x17\xcbq\x0b=\xeb \x84\xf1\xc7\x1c\x940,I\xb2\x9b_\xf0\xa1\x85\xf1Z\x17&\xdd\xf9\x05%%\xdf\xf9_OK\xc2\x13\x05A\x0f\xc3:UFQ$1\xc4\xd4D\xcc\xf9S\x14U\x0cAd1\x14E\x17CI\x841\x84P\xc6\xac\xd0\xf5Hc(\x886\x86(\xe2\x18\xd6\xa2\x8e!\x07y\x8c\x8d\xd8\xd3\x81\x8c~\xf41\xe4 \x90\x11Y\"\x89\xdb\x83B\x86L$2\"\xeex\x80\x86\xf7\x11\xad\xab(\"\x19\xf2Q\xc9P\x1e\x99\x0cy\xe8d\xc8C(\xe3K\x14md1\xdc2\x14\xc7.CI\xfc2$a\x98\xa1$\x8e\x19\x02Xf\xc8\xc43ck\x1cA8\x83T5Q\x943d#\x9d\x11\x81.\xf6\x19\xd6\xe3\x9f\xc1\x97\x12\x9dx\x12@\xd2\xa2S\xf6\xff\x95\x98hL\xedM!\x1ej\x05\xe9c\xed\xc8\xc3G[\xc28Z\x1a\xc1HC\x19\x9c4\x94\xc6J\x03\x82\x97\x86|\xcc\xb4%\x8d:\x08j\xc8DQC\x0c\\\x0c~45\xa4 \xaa\x01\x07\x7f.BV\xfbe8\xc8\xba,\x945,\x18\x8c\x18\xda\x1a\xa2\xfd\x8e\xa2\xaea\x19\xf2\x1a\xb0\xf1\xc8E`C\x0c\x85\x0dA$6D\xd0\xd8\x10\x1a\xa5TT6$ \xb3\x01AgC\x1eB\x1b\xd2P\xda\xb0\n\xa9\x0d\xde\x81\x89\"\xb6\xa1\x1cj\x1b\xfc\xadpfZQ\x047d\xa2\xb8-Q.\xa6\x1bJ\xe3\xba\xa10\xb6\x1bB\xf8n@0\xde\x80\xe0\xbc\xa1\x18\xd6\xfb\xffc\xefjv#\xb7a\xf0\xab\x10s\xd9K\x9bC\xfb\x04\x0d\n\xf4\xbah\x16\xbd\x06\x9a\xb1g\xa2\"\xb6\x06\xb2'\xe9\x16}\xf8\xc2\x94,\xeb\xcf2%+A\x0bLN\x9b\x8d%J\xa4\xf4\xf1\xb3HZP\xb3\xde\x1b\xaa\xd7|\x03\xb9\xee\x1b(\xb5\xdf@\xaf\xff\x06b\x0d8D\xd19Z-\x0c\x19\x15\xc3\xe9zp\xa0\xd7\x84\x03\xad.\x1cb\xd3\xa8Y\x1f\x0e{k\xc4\xbd\xbe\x82\x8aq\xa8Z5nDT\xa9\x1c\x87\xdd\xeba\xb3\x82\x1c\x08U\xe4`*\xc9\xc1\x0e..QXB5\xf9F\xe8\xd8I\xf3%eU.\xedt\x7f\xb4\xa0\xf1\xf0XZ)\xa7\xdb\xfb\x91]R\x92e<\xbcl\xfaT\xc7$\xf35\xe6F}:\x8ci\xf2\xb1\xefy\x1c\xf7<\x8e\xbay\x1c\xffD7\xa3\xb7G\xf2\xf38t\x07\x1b[\xf2w\xf6\xbe\xaf\xc4\xbe\xa4\xcc\xcb\x9a\xfc\xafld.\xb1\x90\xec]AY\xf0YvWQk#\xa7k\xca\xefaCUO\x1d\x93\xe3\x7fLY\x7fN\\ \xb3\x07\xd4-\xd5m3_\x12\xdb\xc20\x8d\xd7\x8d|F\x15\xb9>/\xba*\xc3>Be\x9eD\x8f\xd9\x077T\xe9W\xeb\x16`\x82\xe6\x82\x8blU\x1b\xff\xa2Z\xa3=\xeb\xff\x1dt\xfe\x9a\xbc_x\xf6o\xcbP\xad\xbb\x86\xc39\xd4\xbc\x059\x03\xfb+]\xea[K/^O\xb5/\xe2\x8d\xa8\xfc\x0f\xf6\xca\x1b6\n\xf9\xcbm|\xc9\xd6<\xbb\x8d\xc1\xad\x7f$\xbd\xab\xfcb!\x9f\xe9\xf7\xa2\xe9\x9c\".\xfag\x1d\x81\xa9j5G\x11\xc6x\xd3\x04\x85\xe4\x7f\xcfl\xe3,T\x12\xc4\xdb\xfct\xc4j.$D\x15\xbcX\x11\xfd\xe0:\x18\xb8\xa3\xca\xb7h\xfef\x9af\\F\n3+o\xd6\x8c\x9f`*\xe9\x05\x90Z\x02\xeb\x8b\xa0\xe62\xb8S\xda;\xa5\xadFi\xa9\x98Bs\x0dvs\x17U\xb6\x1d\x85\xf38\x19H\xd6wy\xc4l\xeb;\xbb\x90\x9c\xec\xd8\xc7\x93\x02\xf0>}\xbc\xa7\xf9z\x95\xe2-\x03>\xd5\xf3\xe9\x0b\x7f\xaeR\xfc\x95\xfeL\x19\x86@\xb6\xae\xf2\xf0\xa6\x8cm\x807\xc0\x86A\x9cTb2\x9eN\xe2\x19#N(\xd4\x93\x9e\xdf\xa2!\xfd\xfb\xa4\x9bI\xc5\\\xf4\x81N~\x93\xac\x1f\xc9\x1a\xb9LO\xb7[\x1fFs\x06\xe5%\xa6\xab\x1e\x1a`'\xdc\\\x0f\x9f\xa0#\xd0%a9}\x7f\xd1I\x9e:m\x05{S\x02\x1fL\x00[\xf4\x18\xc3=t\xbc\x1f\x0f?\xc0\xe1x\x93\xfd\x01O\x0d\x0f\x9dh\xf8\xf9\xfb\xe1\xe1Kh$T\xb81\x11\xaa#i \xf5\xc5&e\xc9|\x02`\xaf\xf8h\x9bx;\x88\xae~X\x87io\x17$\x9e\x0c-\x9dx\xb8\xd8\xe2e;\xc3-\xa7\xf6\x94Na\xeb\xb3\x9c\xe0%/j\xce\x02B\xa7\x1b~,\xa7\x8b[>a\xa4\x88\xf5S\xcc/\xba\x02\x12\x0dv\xac\x82\xd2u\x10g\x7f\x19\xbb\xe7\xce\xda\xfe\xff\xac\x0d\x92I\xe3J\xa4\x85\x0d\xc2\x89\xf1\xf0\x1e.\x13\x0c\x18\xb8\xd0a\x96\x01\xde_Z\xd9\x82\x1b\xf9= \xa9\x1e\xc4\xc0\xd0\xfc*9Gf^\xd8\xa0\x92\xbc\xeci:s\x9b\x9f|\x12\xdd2\xa8hxF\xb6WU\x18\xf2\xc8\xa4\xd1\xecZ\xb8\xd0\x99#.\x0f?\\\xe8|\xc5\xd7\x8d\x9f\xf8(\x97\x01\xa0\xc8cu_ \x1cE_\x9a\x8f\xa2\xe8t?\x18C\x03\xa6d\xf7\xb2\x8dq4\xd6\xa4~>\x17OC6\x95'-\x92\x13\xb8\x87k\x05\x9d\x19\xeee\xfd%\x97\x80\xb9<\xc0]e\x94U\xacZl\xb1\x80\xa7\xdb\xf5\xfa\x9a\xffA\x15\xd6MK Af\xed\xb1\xbb2(cW-\xb6\xc6\xfe\xc8^Y\x7f* \xa4\xc4\xc1\xbbH\xe2I\xa3LC7\xd1\xbdl\xcc\xe6\xdb\xf4[\xf6\\\xb0\x8f\"rP\xc6~y\xe3\x1c3\xe9\x924S,c\xd2e\x83-\xdb\xb3\x8ez\xcf\x91#\x10\xf3Cl\x91/\xb7\x8e\xf5?\xca\x965\xe8\x85\x9d\x82\x14_\xe8\xf0\xbd;\n*[p\xc4\xaa\x96\xa0\xeaf\xd9\xf1(\xdb7\x05J(\x0f\xcd\xec\x0b\xebZ;\x80D\x17\x85\x9f\xe9\xc2\xaa\xb8\xa3\xe4\xed\xd9\xfe#N\xcc\x97\xc3;vi\x9fo\x92\x97\x083\x8d\xf5\xd4\xa6\x7f\xcd\x8bV\x81\x1e>1W\xe6\x8a\xf3Y}(\xc6E\xb2\x13\xef\xd8k\xf4\x8c\x9d\xf7c{\xf1>77\xd30\xde\x8f?\xff\xb4>\xb4\x00\x94g9\xf3V[\xc8\x98\xf9\x8bJH\x99\x80\x19\x0b:\x1a\xfe\xc6\x1b\x9f\xd6\x80\xd9\xf2pD~ziG\xe4^\xb7\xa1\x95^\x9a\x8ccO\xde\x8f\xd3\x12\x8bM3'*\x00\x81\xc1u\xc7\x8bl\xe4c:?\xdf\xd8a\xb0\x0bC\xa66+\xef\x95\x08\x1c\xcb\x16Q\x8dS\xbe\xc4A\x1a\n\x8e) \x14\xfc\xca\xe7A\xd8\xc9\x07\xf3\xa0rZR\x0cw1\xc0\xa3\x8b\xdd\x05zq\xd8\xa3\x0b/\x80\xbe\x18\xf8\xd1\x05\xe6\x02\xe0*\x04\xd2E\xd6\x80\xc15 LAa\n\x0c\xb7\xe0\xb0* \x96A\xe2\x1a(\xa6`1\x0d\x8c\xd5\xa1\xb1\x04\x1c\xef\x07-\xf7\x83\x16\xfc\xb9\x1f\xb4d\x1c\xb4D\xbc>\x99L\xa4\xdeK\xbf-\xaf4\x04\xfe\x90\x17\xae)\xf2\xe7\xae'\xdf\x16R\xec\xbd}\xbf\xbd-*\xd3W\xbb^z\xbb\xfb\x1c\xcf\x1c\xf1\xc9\xdb\x02\xf6\xfa\xe1\xd0\x03\xc7}o\xdc\xeb\xae\xfb\xdb=\x9ev\xf1\xacV\x874\x1f\x1bz\xd7\xb8_%% \xed\xf3\xa5y^\xf4\xdf\x00\x00\x00\xff\xffPK\x07\x08[\xffDbj:\x02\x00#\x10\x1e\x00PK\x01\x02\x14\x03\x14\x00\x08\x00\x08\x00\x00\x00!(\xd4`4t\xc7\x01\x00\x00\xbd\x01\x00\x00\x11\x00 \x00\x00\x00\x00\x00\x00\x00\x00\x00\xa4\x81\x00\x00\x00\x00favicon-16x16.pngUT\x05\x00\x01\x80Cm8PK\x01\x02\x14\x03\x14\x00\x08\x00\x08\x00\x00\x00!(6B\xc8\xd7\x7f\x04\x00\x00u\x04\x00\x00\x11\x00 \x00\x00\x00\x00\x00\x00\x00\x00\x00\xa4\x81\x0f\x02\x00\x00favicon-32x32.pngUT\x05\x00\x01\x80Cm8PK\x01\x02\x14\x03\x14\x00\x08\x00\x08\x00\x00\x00!(\xb9\xb1\xf1mT\x02\x00\x008\x05\x00\x00\n\x00 \x00\x00\x00\x00\x00\x00\x00\x00\x00\xa4\x81\xd6\x06\x00\x00index.htmlUT\x05\x00\x01\x80Cm8PK\x01\x02\x14\x03\x14\x00\x08\x00\x08\x00\x00\x00!(]\x12r 9\x03\x00\x00T \x00\x00\x14\x00 \x00\x00\x00\x00\x00\x00\x00\x00\x00\xa4\x81k \x00\x00oauth2-redirect.htmlUT\x05\x00\x01\x80Cm8PK\x01\x02\x14\x03\x14\x00\x08\x00\x08\x00\x00\x00!(\x05\xef\x9fw>9\x05\x00\xf8\x0c\x1b\x00\x14\x00 \x00\x00\x00\x00\x00\x00\x00\x00\x00\xa4\x81\xef\x0c\x00\x00swagger-ui-bundle.jsUT\x05\x00\x01\x80Cm8PK\x01\x02\x14\x03\x14\x00\x08\x00\x08\x00\x00\x00!(v\xf2\x8aA\x86\xba\x01\x00\xc5\x87\x08\x00\x1f\x00 \x00\x00\x00\x00\x00\x00\x00\x00\x00\xa4\x81xF\x05\x00swagger-ui-standalone-preset.jsUT\x05\x00\x01\x80Cm8PK\x01\x02\x14\x03\x14\x00\x08\x00\x08\x00\x00\x00!(_;\x94/\xe8Y\x00\x00\xa8X\x02\x00\x0e\x00 \x00\x00\x00\x00\x00\x00\x00\x00\x00\xa4\x81T\x01\x07\x00swagger-ui.cssUT\x05\x00\x01\x80Cm8PK\x01\x02\x14\x03\x14\x00\x08\x00\x08\x00\x00\x00!([\xffDbj:\x02\x00#\x10\x1e\x00\x0c\x00 \x00\x00\x00\x00\x00\x00\x00\x00\x00\xa4\x81\x81[\x07\x00swagger.yamlUT\x05\x00\x01\x80Cm8PK\x05\x06\x00\x00\x00\x00\x08\x00\x08\x00E\x02\x00\x00.\x96 \x00\x00\x00" fs.Register(data) } \ No newline at end of file diff --git a/client/docs/swagger-ui/swagger.yaml b/client/docs/swagger-ui/swagger.yaml index ca422c40f2..f09fc4af9c 100644 --- a/client/docs/swagger-ui/swagger.yaml +++ b/client/docs/swagger-ui/swagger.yaml @@ -33787,9 +33787,9 @@ paths: '/lbm/token/v1/balance/{address}/{class_id}': get: summary: >- - TokenBalance queries the number of tokens of a given class owned by the + Balance queries the number of tokens of a given class owned by the address. - operationId: TokenBalance + operationId: Balance responses: '200': description: A successful response. @@ -33799,8 +33799,8 @@ paths: amount: type: string title: >- - QueryTokenBalanceResponse is the response type for the - Query/TokenBalance RPC method + QueryBalanceResponse is the response type for the + Query/Balance RPC method default: description: An unexpected error response schema: @@ -55847,13 +55847,13 @@ definitions: amount: type: string title: QuerySupplyResponse is the response type for the Query/Supply RPC method - lbm.token.v1.QueryTokenBalanceResponse: + lbm.token.v1.QueryBalanceResponse: type: object properties: amount: type: string title: >- - QueryTokenBalanceResponse is the response type for the Query/TokenBalance + QueryBalanceResponse is the response type for the Query/Balance RPC method lbm.token.v1.QueryTokenResponse: type: object diff --git a/client/docs/swagger_legacy.yaml b/client/docs/swagger_legacy.yaml index d33c031176..f15f5c8c1e 100644 --- a/client/docs/swagger_legacy.yaml +++ b/client/docs/swagger_legacy.yaml @@ -517,7 +517,7 @@ paths: parameters: - in: body name: delegation - description: The password of the account to remove from the KMS + description: Delegate an amount of liquid coins to a validator schema: type: object properties: @@ -607,7 +607,7 @@ paths: parameters: - in: body name: delegation - description: The password of the account to remove from the KMS + description: Unbond an amount of bonded shares from a validator schema: type: object properties: diff --git a/client/flags/flags.go b/client/flags/flags.go index 0c66780b9a..32763cc276 100644 --- a/client/flags/flags.go +++ b/client/flags/flags.go @@ -51,7 +51,7 @@ const ( FlagName = "name" FlagAccountNumber = "account-number" FlagSequence = "sequence" - FlagMemo = "memo" + FlagNote = "note" FlagFees = "fees" FlagGas = "gas" FlagGasPrices = "gas-prices" @@ -73,6 +73,7 @@ const ( FlagKeyAlgorithm = "algo" FlagPrivKeyType = "priv_key_type" FlagFeeAccount = "fee-account" + FlagReverse = "reverse" // Tendermint logging flags FlagLogLevel = "log_level" @@ -91,9 +92,6 @@ func AddQueryFlagsToCmd(cmd *cobra.Command) { cmd.Flags().StringP(ostcli.OutputFlag, "o", "text", "Output format (text|json)") cmd.MarkFlagRequired(FlagChainID) - - cmd.SetErr(cmd.ErrOrStderr()) - cmd.SetOut(cmd.OutOrStdout()) } // AddTxFlagsToCmd adds common flags to a module tx command. @@ -103,7 +101,7 @@ func AddTxFlagsToCmd(cmd *cobra.Command) { cmd.Flags().String(FlagFrom, "", "Name or address of private key with which to sign") cmd.Flags().Uint64P(FlagAccountNumber, "a", 0, "The account number of the signing account (offline mode only)") cmd.Flags().Uint64P(FlagSequence, "s", 0, "The sequence number of the signing account (offline mode only)") - cmd.Flags().String(FlagMemo, "", "Memo to send along with transaction") + cmd.Flags().String(FlagNote, "", "Note to add a description to the transaction (previously --memo)") cmd.Flags().String(FlagFees, "", "Fees to pay along with transaction; eg: 10uatom") cmd.Flags().String(FlagGasPrices, "", "Gas prices in decimal format to determine the transaction fee (e.g. 0.1uatom)") cmd.Flags().String(FlagNode, "tcp://localhost:26657", ": to ostracon rpc interface for this chain") @@ -125,9 +123,6 @@ func AddTxFlagsToCmd(cmd *cobra.Command) { cmd.Flags().String(FlagGas, "", fmt.Sprintf("gas limit to set per-transaction; set to %q to calculate sufficient gas automatically (default %d)", GasFlagAuto, DefaultGasLimit)) cmd.MarkFlagRequired(FlagChainID) - - cmd.SetErr(cmd.ErrOrStderr()) - cmd.SetOut(cmd.OutOrStdout()) } // AddPaginationFlagsToCmd adds common pagination flags to cmd @@ -137,6 +132,7 @@ func AddPaginationFlagsToCmd(cmd *cobra.Command, query string) { cmd.Flags().Uint64(FlagOffset, 0, fmt.Sprintf("pagination offset of %s to query for", query)) cmd.Flags().Uint64(FlagLimit, 100, fmt.Sprintf("pagination limit of %s to query for", query)) cmd.Flags().Bool(FlagCountTotal, false, fmt.Sprintf("count total number of records in %s to query for", query)) + cmd.Flags().Bool(FlagReverse, false, "results are sorted in descending order") } // GasSetting encapsulates the possible values passed through the --gas flag. diff --git a/client/grpc/reflection/reflection.pb.gw.go b/client/grpc/reflection/reflection.pb.gw.go index bef4872ace..4c0d268a32 100644 --- a/client/grpc/reflection/reflection.pb.gw.go +++ b/client/grpc/reflection/reflection.pb.gw.go @@ -234,9 +234,9 @@ func RegisterReflectionServiceHandlerClient(ctx context.Context, mux *runtime.Se } var ( - pattern_ReflectionService_ListAllInterfaces_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4}, []string{"lbm", "base", "reflection", "v1", "interfaces"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_ReflectionService_ListAllInterfaces_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4}, []string{"lbm", "base", "reflection", "v1", "interfaces"}, "", runtime.AssumeColonVerbOpt(false))) - pattern_ReflectionService_ListImplementations_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 1, 0, 4, 1, 5, 5, 2, 6}, []string{"lbm", "base", "reflection", "v1", "interfaces", "interface_name", "implementations"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_ReflectionService_ListImplementations_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 1, 0, 4, 1, 5, 5, 2, 6}, []string{"lbm", "base", "reflection", "v1", "interfaces", "interface_name", "implementations"}, "", runtime.AssumeColonVerbOpt(false))) ) var ( diff --git a/client/grpc/reflection/reflection_test.go b/client/grpc/reflection/reflection_test.go deleted file mode 100644 index dbfab0d241..0000000000 --- a/client/grpc/reflection/reflection_test.go +++ /dev/null @@ -1,55 +0,0 @@ -package reflection_test - -import ( - "context" - "testing" - - ocproto "github.com/line/ostracon/proto/ostracon/types" - "github.com/stretchr/testify/suite" - - "github.com/line/lbm-sdk/baseapp" - "github.com/line/lbm-sdk/client/grpc/reflection" - "github.com/line/lbm-sdk/simapp" -) - -type IntegrationTestSuite struct { - suite.Suite - - queryClient reflection.ReflectionServiceClient -} - -func (s *IntegrationTestSuite) SetupSuite() { - app := simapp.Setup(false) - - sdkCtx := app.BaseApp.NewContext(false, ocproto.Header{}) - queryHelper := baseapp.NewQueryServerTestHelper(sdkCtx, app.InterfaceRegistry()) - queryClient := reflection.NewReflectionServiceClient(queryHelper) - s.queryClient = queryClient -} - -func (s IntegrationTestSuite) TestSimulateService() { - // We will test the following interface for testing. - var iface = "lbm.evidence.v1.Evidence" - - // Test that "lbm.evidence.v1.Evidence" is included in the - // interfaces. - resIface, err := s.queryClient.ListAllInterfaces( - context.Background(), - &reflection.ListAllInterfacesRequest{}, - ) - s.Require().NoError(err) - s.Require().Contains(resIface.GetInterfaceNames(), iface) - - // Test that "lbm.evidence.v1.Evidence" has at least the - // Equivocation implementations. - resImpl, err := s.queryClient.ListImplementations( - context.Background(), - &reflection.ListImplementationsRequest{InterfaceName: iface}, - ) - s.Require().NoError(err) - s.Require().Contains(resImpl.GetImplementationMessageNames(), "/lbm.evidence.v1.Equivocation") -} - -func TestSimulateTestSuite(t *testing.T) { - suite.Run(t, new(IntegrationTestSuite)) -} diff --git a/client/grpc/tmservice/block.go b/client/grpc/tmservice/block.go index df5d2f646a..55f197e1d1 100644 --- a/client/grpc/tmservice/block.go +++ b/client/grpc/tmservice/block.go @@ -8,14 +8,14 @@ import ( "github.com/line/lbm-sdk/client" ) -func getBlock(clientCtx client.Context, height *int64) (*ctypes.ResultBlock, error) { +func getBlock(ctx context.Context, clientCtx client.Context, height *int64) (*ctypes.ResultBlock, error) { // get the node node, err := clientCtx.GetNode() if err != nil { return nil, err } - return node.Block(context.Background(), height) + return node.Block(ctx, height) } func getBlockByHash(clientCtx client.Context, hash []byte) (*ctypes.ResultBlock, error) { diff --git a/client/grpc/tmservice/query.pb.go b/client/grpc/tmservice/query.pb.go index aff482d21c..e8c3c3f6be 100644 --- a/client/grpc/tmservice/query.pb.go +++ b/client/grpc/tmservice/query.pb.go @@ -900,14 +900,15 @@ func (m *GetNodeInfoResponse) GetApplicationVersion() *VersionInfo { // VersionInfo is the type for the GetNodeInfoResponse message. type VersionInfo struct { - Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` - AppName string `protobuf:"bytes,2,opt,name=app_name,json=appName,proto3" json:"app_name,omitempty"` - Version string `protobuf:"bytes,3,opt,name=version,proto3" json:"version,omitempty"` - GitCommit string `protobuf:"bytes,4,opt,name=git_commit,json=gitCommit,proto3" json:"git_commit,omitempty"` - BuildTags string `protobuf:"bytes,5,opt,name=build_tags,json=buildTags,proto3" json:"build_tags,omitempty"` - GoVersion string `protobuf:"bytes,6,opt,name=go_version,json=goVersion,proto3" json:"go_version,omitempty"` - BuildDeps []*Module `protobuf:"bytes,7,rep,name=build_deps,json=buildDeps,proto3" json:"build_deps,omitempty"` - LbmSdkVersion string `protobuf:"bytes,8,opt,name=lbm_sdk_version,json=lbmSdkVersion,proto3" json:"lbm_sdk_version,omitempty"` + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + AppName string `protobuf:"bytes,2,opt,name=app_name,json=appName,proto3" json:"app_name,omitempty"` + Version string `protobuf:"bytes,3,opt,name=version,proto3" json:"version,omitempty"` + GitCommit string `protobuf:"bytes,4,opt,name=git_commit,json=gitCommit,proto3" json:"git_commit,omitempty"` + BuildTags string `protobuf:"bytes,5,opt,name=build_tags,json=buildTags,proto3" json:"build_tags,omitempty"` + GoVersion string `protobuf:"bytes,6,opt,name=go_version,json=goVersion,proto3" json:"go_version,omitempty"` + BuildDeps []*Module `protobuf:"bytes,7,rep,name=build_deps,json=buildDeps,proto3" json:"build_deps,omitempty"` + // Since: cosmos-sdk 0.43 + LbmSdkVersion string `protobuf:"bytes,8,opt,name=lbm_sdk_version,json=lbmSdkVersion,proto3" json:"lbm_sdk_version,omitempty"` } func (m *VersionInfo) Reset() { *m = VersionInfo{} } diff --git a/client/grpc/tmservice/query.pb.gw.go b/client/grpc/tmservice/query.pb.gw.go index 0cc1b0bc15..73abc9773d 100644 --- a/client/grpc/tmservice/query.pb.gw.go +++ b/client/grpc/tmservice/query.pb.gw.go @@ -726,21 +726,21 @@ func RegisterServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux, cl } var ( - pattern_Service_GetNodeInfo_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4}, []string{"lbm", "base", "ostracon", "v1", "node_info"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_Service_GetNodeInfo_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4}, []string{"lbm", "base", "ostracon", "v1", "node_info"}, "", runtime.AssumeColonVerbOpt(false))) - pattern_Service_GetSyncing_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4}, []string{"lbm", "base", "ostracon", "v1", "syncing"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_Service_GetSyncing_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4}, []string{"lbm", "base", "ostracon", "v1", "syncing"}, "", runtime.AssumeColonVerbOpt(false))) - pattern_Service_GetLatestBlock_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 2, 5}, []string{"lbm", "base", "ostracon", "v1", "blocks", "latest"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_Service_GetLatestBlock_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 2, 5}, []string{"lbm", "base", "ostracon", "v1", "blocks", "latest"}, "", runtime.AssumeColonVerbOpt(false))) - pattern_Service_GetBlockByHeight_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 1, 0, 4, 1, 5, 5}, []string{"lbm", "base", "ostracon", "v1", "blocks", "height"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_Service_GetBlockByHeight_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 1, 0, 4, 1, 5, 5}, []string{"lbm", "base", "ostracon", "v1", "blocks", "height"}, "", runtime.AssumeColonVerbOpt(false))) - pattern_Service_GetBlockByHash_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 1, 0, 4, 1, 5, 5}, []string{"lbm", "base", "ostracon", "v1", "blocks", "hash"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_Service_GetBlockByHash_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 1, 0, 4, 1, 5, 5}, []string{"lbm", "base", "ostracon", "v1", "blocks", "hash"}, "", runtime.AssumeColonVerbOpt(false))) - pattern_Service_GetBlockResultsByHeight_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 1, 0, 4, 1, 5, 5}, []string{"lbm", "base", "ostracon", "v1", "blockresults", "height"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_Service_GetBlockResultsByHeight_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 1, 0, 4, 1, 5, 5}, []string{"lbm", "base", "ostracon", "v1", "blockresults", "height"}, "", runtime.AssumeColonVerbOpt(false))) - pattern_Service_GetLatestValidatorSet_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 2, 5}, []string{"lbm", "base", "ostracon", "v1", "validatorsets", "latest"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_Service_GetLatestValidatorSet_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 2, 5}, []string{"lbm", "base", "ostracon", "v1", "validatorsets", "latest"}, "", runtime.AssumeColonVerbOpt(false))) - pattern_Service_GetValidatorSetByHeight_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 1, 0, 4, 1, 5, 5}, []string{"lbm", "base", "ostracon", "v1", "validatorsets", "height"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_Service_GetValidatorSetByHeight_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 1, 0, 4, 1, 5, 5}, []string{"lbm", "base", "ostracon", "v1", "validatorsets", "height"}, "", runtime.AssumeColonVerbOpt(false))) ) var ( diff --git a/client/grpc/tmservice/service.go b/client/grpc/tmservice/service.go index ad9e12eccd..acac211114 100644 --- a/client/grpc/tmservice/service.go +++ b/client/grpc/tmservice/service.go @@ -36,8 +36,8 @@ func NewQueryServer(clientCtx client.Context, interfaceRegistry codectypes.Inter } // GetSyncing implements ServiceServer.GetSyncing -func (s queryServer) GetSyncing(_ context.Context, _ *GetSyncingRequest) (*GetSyncingResponse, error) { - status, err := getNodeStatus(s.clientCtx) +func (s queryServer) GetSyncing(ctx context.Context, _ *GetSyncingRequest) (*GetSyncingResponse, error) { + status, err := getNodeStatus(ctx, s.clientCtx) if err != nil { return nil, err } @@ -47,8 +47,8 @@ func (s queryServer) GetSyncing(_ context.Context, _ *GetSyncingRequest) (*GetSy } // GetLatestBlock implements ServiceServer.GetLatestBlock -func (s queryServer) GetLatestBlock(context.Context, *GetLatestBlockRequest) (*GetLatestBlockResponse, error) { - status, err := getBlock(s.clientCtx, nil) +func (s queryServer) GetLatestBlock(ctx context.Context, _ *GetLatestBlockRequest) (*GetLatestBlockResponse, error) { + status, err := getBlock(ctx, s.clientCtx, nil) if err != nil { return nil, err } @@ -66,7 +66,7 @@ func (s queryServer) GetLatestBlock(context.Context, *GetLatestBlockRequest) (*G } // GetBlockByHeight implements ServiceServer.GetBlockByHeight -func (s queryServer) GetBlockByHeight(_ context.Context, req *GetBlockByHeightRequest) (*GetBlockByHeightResponse, error) { +func (s queryServer) GetBlockByHeight(ctx context.Context, req *GetBlockByHeightRequest) (*GetBlockByHeightResponse, error) { chainHeight, err := rpc.GetChainHeight(s.clientCtx) if err != nil { return nil, err @@ -76,7 +76,7 @@ func (s queryServer) GetBlockByHeight(_ context.Context, req *GetBlockByHeightRe return nil, status.Error(codes.InvalidArgument, "requested block height is bigger then the chain length") } - res, err := getBlock(s.clientCtx, &req.Height) + res, err := getBlock(ctx, s.clientCtx, &req.Height) if err != nil { return nil, err } @@ -134,30 +134,7 @@ func (s queryServer) GetLatestValidatorSet(ctx context.Context, req *GetLatestVa if err != nil { return nil, err } - - validatorsRes, err := rpc.GetValidators(s.clientCtx, nil, &page, &limit) - if err != nil { - return nil, err - } - - outputValidatorsRes := &GetLatestValidatorSetResponse{ - BlockHeight: validatorsRes.BlockHeight, - Validators: make([]*Validator, len(validatorsRes.Validators)), - } - - for i, validator := range validatorsRes.Validators { - anyPub, err := codectypes.NewAnyWithValue(validator.PubKey) - if err != nil { - return nil, err - } - outputValidatorsRes.Validators[i] = &Validator{ - Address: validator.Address.String(), - ProposerPriority: validator.ProposerPriority, - PubKey: anyPub, - VotingPower: validator.VotingPower, - } - } - return outputValidatorsRes, nil + return validatorsOutput(ctx, s.clientCtx, nil, page, limit) } func (m *GetLatestValidatorSetResponse) UnpackInterfaces(unpacker codectypes.AnyUnpacker) error { @@ -185,36 +162,47 @@ func (s queryServer) GetValidatorSetByHeight(ctx context.Context, req *GetValida if req.Height > chainHeight { return nil, status.Error(codes.InvalidArgument, "requested block height is bigger then the chain length") } - - validatorsRes, err := rpc.GetValidators(s.clientCtx, &req.Height, &page, &limit) - + r, err := validatorsOutput(ctx, s.clientCtx, &req.Height, page, limit) if err != nil { return nil, err } + return &GetValidatorSetByHeightResponse{ + BlockHeight: r.BlockHeight, + Validators: r.Validators, + Pagination: r.Pagination, + }, nil +} - outputValidatorsRes := &GetValidatorSetByHeightResponse{ - BlockHeight: validatorsRes.BlockHeight, - Validators: make([]*Validator, len(validatorsRes.Validators)), +func validatorsOutput(ctx context.Context, cctx client.Context, height *int64, page, limit int) (*GetLatestValidatorSetResponse, error) { + vs, err := rpc.GetValidators(ctx, cctx, height, &page, &limit) + if err != nil { + return nil, err } - - for i, validator := range validatorsRes.Validators { - anyPub, err := codectypes.NewAnyWithValue(validator.PubKey) + resp := GetLatestValidatorSetResponse{ + BlockHeight: vs.BlockHeight, + Validators: make([]*Validator, len(vs.Validators)), + Pagination: &qtypes.PageResponse{ + Total: vs.Total, + }, + } + for i, v := range vs.Validators { + anyPub, err := codectypes.NewAnyWithValue(v.PubKey) if err != nil { return nil, err } - outputValidatorsRes.Validators[i] = &Validator{ - Address: validator.Address.String(), - ProposerPriority: validator.ProposerPriority, + resp.Validators[i] = &Validator{ + Address: v.Address.String(), + ProposerPriority: v.ProposerPriority, PubKey: anyPub, - VotingPower: validator.VotingPower, + VotingPower: v.VotingPower, } } - return outputValidatorsRes, nil + return &resp, nil } // GetNodeInfo implements ServiceServer.GetNodeInfo func (s queryServer) GetNodeInfo(ctx context.Context, req *GetNodeInfoRequest) (*GetNodeInfoResponse, error) { - status, err := getNodeStatus(s.clientCtx) + status, err := getNodeStatus(ctx, s.clientCtx) if err != nil { return nil, err } diff --git a/client/grpc/tmservice/service_test.go b/client/grpc/tmservice/service_test.go index aa2ec67bdd..2817c5aa16 100644 --- a/client/grpc/tmservice/service_test.go +++ b/client/grpc/tmservice/service_test.go @@ -57,7 +57,7 @@ func (s IntegrationTestSuite) TestQueryNodeInfo() { restRes, err := rest.GetRequest(fmt.Sprintf("%s/lbm/base/ostracon/v1/node_info", val.APIAddress)) s.Require().NoError(err) var getInfoRes tmservice.GetNodeInfoResponse - s.Require().NoError(val.ClientCtx.JSONMarshaler.UnmarshalJSON(restRes, &getInfoRes)) + s.Require().NoError(val.ClientCtx.Codec.UnmarshalJSON(restRes, &getInfoRes)) s.Require().Equal(getInfoRes.ApplicationVersion.AppName, version.NewInfo().AppName) } @@ -70,7 +70,7 @@ func (s IntegrationTestSuite) TestQuerySyncing() { restRes, err := rest.GetRequest(fmt.Sprintf("%s/lbm/base/ostracon/v1/syncing", val.APIAddress)) s.Require().NoError(err) var syncingRes tmservice.GetSyncingResponse - s.Require().NoError(val.ClientCtx.JSONMarshaler.UnmarshalJSON(restRes, &syncingRes)) + s.Require().NoError(val.ClientCtx.Codec.UnmarshalJSON(restRes, &syncingRes)) } func (s IntegrationTestSuite) TestQueryLatestBlock() { @@ -82,7 +82,7 @@ func (s IntegrationTestSuite) TestQueryLatestBlock() { restRes, err := rest.GetRequest(fmt.Sprintf("%s/lbm/base/ostracon/v1/blocks/latest", val.APIAddress)) s.Require().NoError(err) var blockInfoRes tmservice.GetLatestBlockResponse - s.Require().NoError(val.ClientCtx.JSONMarshaler.UnmarshalJSON(restRes, &blockInfoRes)) + s.Require().NoError(val.ClientCtx.Codec.UnmarshalJSON(restRes, &blockInfoRes)) } func (s IntegrationTestSuite) TestQueryBlockByHeight() { @@ -93,7 +93,7 @@ func (s IntegrationTestSuite) TestQueryBlockByHeight() { restRes, err := rest.GetRequest(fmt.Sprintf("%s/lbm/base/ostracon/v1/blocks/%d", val.APIAddress, 1)) s.Require().NoError(err) var blockInfoRes tmservice.GetBlockByHeightResponse - s.Require().NoError(val.ClientCtx.JSONMarshaler.UnmarshalJSON(restRes, &blockInfoRes)) + s.Require().NoError(val.ClientCtx.Codec.UnmarshalJSON(restRes, &blockInfoRes)) } func (s IntegrationTestSuite) TestQueryBlockResultsByHeight() { @@ -104,7 +104,7 @@ func (s IntegrationTestSuite) TestQueryBlockResultsByHeight() { restRes, err := rest.GetRequest(fmt.Sprintf("%s/lbm/base/ostracon/v1/blockresults/%d", val.APIAddress, 1)) s.Require().NoError(err) var blockResultsRes tmservice.GetBlockResultsByHeightResponse - s.Require().NoError(val.ClientCtx.JSONMarshaler.UnmarshalJSON(restRes, &blockResultsRes)) + s.Require().NoError(val.ClientCtx.JSONCodec.UnmarshalJSON(restRes, &blockResultsRes)) } func (s IntegrationTestSuite) TestQueryLatestValidatorSet() { @@ -135,39 +135,133 @@ func (s IntegrationTestSuite) TestQueryLatestValidatorSet() { restRes, err := rest.GetRequest(fmt.Sprintf("%s/lbm/base/ostracon/v1/validatorsets/latest?pagination.offset=%d&pagination.limit=%d", val.APIAddress, 0, 1)) s.Require().NoError(err) var validatorSetRes tmservice.GetLatestValidatorSetResponse - s.Require().NoError(val.ClientCtx.JSONMarshaler.UnmarshalJSON(restRes, &validatorSetRes)) + s.Require().NoError(val.ClientCtx.Codec.UnmarshalJSON(restRes, &validatorSetRes)) s.Require().Equal(1, len(validatorSetRes.Validators)) anyPub, err := codectypes.NewAnyWithValue(val.PubKey) s.Require().NoError(err) s.Require().Equal(validatorSetRes.Validators[0].PubKey, anyPub) } -func (s IntegrationTestSuite) TestQueryValidatorSetByHeight() { - val := s.network.Validators[0] - - // nil pagination - _, err := s.queryClient.GetValidatorSetByHeight(context.Background(), &tmservice.GetValidatorSetByHeightRequest{ - Height: 1, - Pagination: nil, - }) - s.Require().NoError(err) +func (s IntegrationTestSuite) TestLatestValidatorSet_GRPC() { + vals := s.network.Validators + testCases := []struct { + name string + req *tmservice.GetLatestValidatorSetRequest + expErr bool + expErrMsg string + }{ + {"nil request", nil, true, "cannot be nil"}, + {"no pagination", &tmservice.GetLatestValidatorSetRequest{}, false, ""}, + {"with pagination", &tmservice.GetLatestValidatorSetRequest{Pagination: &qtypes.PageRequest{Offset: 0, Limit: uint64(len(vals))}}, false, ""}, + } + for _, tc := range testCases { + tc := tc + s.Run(tc.name, func() { + grpcRes, err := s.queryClient.GetLatestValidatorSet(context.Background(), tc.req) + if tc.expErr { + s.Require().Error(err) + s.Require().Contains(err.Error(), tc.expErrMsg) + } else { + s.Require().NoError(err) + s.Require().Len(grpcRes.Validators, len(vals)) + s.Require().Equal(grpcRes.Pagination.Total, uint64(len(vals))) + content, ok := grpcRes.Validators[0].PubKey.GetCachedValue().(cryptotypes.PubKey) + s.Require().Equal(true, ok) + s.Require().Equal(content, vals[0].PubKey) + } + }) + } +} - _, err = s.queryClient.GetValidatorSetByHeight(context.Background(), &tmservice.GetValidatorSetByHeightRequest{ - Height: 1, - Pagination: &qtypes.PageRequest{ - Offset: 0, - Limit: 10, - }}) - s.Require().NoError(err) +func (s IntegrationTestSuite) TestLatestValidatorSet_GRPCGateway() { + vals := s.network.Validators + testCases := []struct { + name string + url string + expErr bool + expErrMsg string + }{ + {"no pagination", fmt.Sprintf("%s/lbm/base/ostracon/v1/validatorsets/latest", vals[0].APIAddress), false, ""}, + {"pagination invalid fields", fmt.Sprintf("%s/lbm/base/ostracon/v1/validatorsets/latest?pagination.offset=-1&pagination.limit=-2", vals[0].APIAddress), true, "strconv.ParseUint"}, + {"with pagination", fmt.Sprintf("%s/lbm/base/ostracon/v1/validatorsets/latest?pagination.offset=0&pagination.limit=2", vals[0].APIAddress), false, ""}, + } + for _, tc := range testCases { + tc := tc + s.Run(tc.name, func() { + res, err := rest.GetRequest(tc.url) + s.Require().NoError(err) + if tc.expErr { + s.Require().Contains(string(res), tc.expErrMsg) + } else { + var result tmservice.GetLatestValidatorSetResponse + err = vals[0].ClientCtx.Codec.UnmarshalJSON(res, &result) + s.Require().NoError(err) + s.Require().Equal(uint64(len(vals)), result.Pagination.Total) + anyPub, err := codectypes.NewAnyWithValue(vals[0].PubKey) + s.Require().NoError(err) + s.Require().Equal(result.Validators[0].PubKey, anyPub) + } + }) + } +} - // no pagination rest - _, err = rest.GetRequest(fmt.Sprintf("%s/lbm/base/ostracon/v1/validatorsets/%d", val.APIAddress, 1)) - s.Require().NoError(err) +func (s IntegrationTestSuite) TestValidatorSetByHeight_GRPC() { + vals := s.network.Validators + testCases := []struct { + name string + req *tmservice.GetValidatorSetByHeightRequest + expErr bool + expErrMsg string + }{ + {"nil request", nil, true, "request cannot be nil"}, + {"empty request", &tmservice.GetValidatorSetByHeightRequest{}, true, "height must be greater than 0"}, + {"no pagination", &tmservice.GetValidatorSetByHeightRequest{Height: 1}, false, ""}, + {"with pagination", &tmservice.GetValidatorSetByHeightRequest{Height: 1, Pagination: &qtypes.PageRequest{Offset: 0, Limit: 1}}, false, ""}, + } + for _, tc := range testCases { + tc := tc + s.Run(tc.name, func() { + grpcRes, err := s.queryClient.GetValidatorSetByHeight(context.Background(), tc.req) + if tc.expErr { + s.Require().Error(err) + s.Require().Contains(err.Error(), tc.expErrMsg) + } else { + s.Require().NoError(err) + s.Require().Len(grpcRes.Validators, len(vals)) + s.Require().Equal(grpcRes.Pagination.Total, uint64(len(vals))) + } + }) + } +} - // rest query with pagination - restRes, err := rest.GetRequest(fmt.Sprintf("%s/lbm/base/ostracon/v1/validatorsets/%d?pagination.offset=%d&pagination.limit=%d", val.APIAddress, 1, 0, 1)) - var validatorSetRes tmservice.GetValidatorSetByHeightResponse - s.Require().NoError(val.ClientCtx.JSONMarshaler.UnmarshalJSON(restRes, &validatorSetRes)) +func (s IntegrationTestSuite) TestValidatorSetByHeight_GRPCGateway() { + vals := s.network.Validators + testCases := []struct { + name string + url string + expErr bool + expErrMsg string + }{ + {"invalid height", fmt.Sprintf("%s/lbm/base/ostracon/v1/validatorsets/%d", vals[0].APIAddress, -1), true, "height must be greater than 0"}, + {"no pagination", fmt.Sprintf("%s/lbm/base/ostracon/v1/validatorsets/%d", vals[0].APIAddress, 1), false, ""}, + {"pagination invalid fields", fmt.Sprintf("%s/lbm/base/ostracon/v1/validatorsets/%d?pagination.offset=-1&pagination.limit=-2", vals[0].APIAddress, 1), true, "strconv.ParseUint"}, + {"with pagination", fmt.Sprintf("%s/lbm/base/ostracon/v1/validatorsets/%d?pagination.offset=0&pagination.limit=2", vals[0].APIAddress, 1), false, ""}, + } + for _, tc := range testCases { + tc := tc + s.Run(tc.name, func() { + res, err := rest.GetRequest(tc.url) + s.Require().NoError(err) + if tc.expErr { + s.Require().Contains(string(res), tc.expErrMsg) + } else { + var result tmservice.GetValidatorSetByHeightResponse + err = vals[0].ClientCtx.Codec.UnmarshalJSON(res, &result) + s.Require().NoError(err) + s.Require().Equal(uint64(len(vals)), result.Pagination.Total) + } + }) + } } func TestIntegrationTestSuite(t *testing.T) { diff --git a/client/grpc/tmservice/status.go b/client/grpc/tmservice/status.go index f48e011890..8f11c68d9a 100644 --- a/client/grpc/tmservice/status.go +++ b/client/grpc/tmservice/status.go @@ -8,10 +8,10 @@ import ( "github.com/line/lbm-sdk/client" ) -func getNodeStatus(clientCtx client.Context) (*ctypes.ResultStatus, error) { +func getNodeStatus(ctx context.Context, clientCtx client.Context) (*ctypes.ResultStatus, error) { node, err := clientCtx.GetNode() if err != nil { return &ctypes.ResultStatus{}, err } - return node.Status(context.Background()) + return node.Status(ctx) } diff --git a/client/grpc_query.go b/client/grpc_query.go index bfd924a287..3171ce341b 100644 --- a/client/grpc_query.go +++ b/client/grpc_query.go @@ -29,17 +29,14 @@ func (ctx Context) Invoke(grpcCtx gocontext.Context, method string, req, reply i // 1. either we're broadcasting a Tx, in which call we call Tendermint's broadcast endpoint directly, // 2. or we are querying for state, in which case we call ABCI's Query. - // In both cases, we don't allow empty request req (it will panic unexpectedly). + // In both cases, we don't allow empty request args (it will panic unexpectedly). if reflect.ValueOf(req).IsNil() { return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "request cannot be nil") } // Case 1. Broadcasting a Tx. if reqProto, ok := req.(*tx.BroadcastTxRequest); ok { - if !ok { - return sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "expected %T, got %T", (*tx.BroadcastTxRequest)(nil), req) - } - resProto, ok := reply.(*tx.BroadcastTxResponse) + res, ok := reply.(*tx.BroadcastTxResponse) if !ok { return sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "expected %T, got %T", (*tx.BroadcastTxResponse)(nil), req) } @@ -48,62 +45,26 @@ func (ctx Context) Invoke(grpcCtx gocontext.Context, method string, req, reply i if err != nil { return err } - *resProto = *broadcastRes + *res = *broadcastRes return err } // Case 2. Querying state. - inMd, _ := metadata.FromOutgoingContext(grpcCtx) - abciRes, outMd, err := RunGRPCQuery(ctx, grpcCtx, method, req, inMd) - if err != nil { - return err - } - - err = protoCodec.Unmarshal(abciRes.Value, reply) - if err != nil { - return err - } - - for _, callOpt := range opts { - header, ok := callOpt.(grpc.HeaderCallOption) - if !ok { - continue - } - - *header.HeaderAddr = outMd - } - - if ctx.InterfaceRegistry != nil { - return types.UnpackInterfaces(reply, ctx.InterfaceRegistry) - } - - return nil -} - -// NewStream implements the grpc ClientConn.NewStream method -func (Context) NewStream(gocontext.Context, *grpc.StreamDesc, string, ...grpc.CallOption) (grpc.ClientStream, error) { - return nil, fmt.Errorf("streaming rpc not supported") -} - -// RunGRPCQuery runs a gRPC query from the clientCtx, given all necessary -// arguments for the gRPC method, and returns the ABCI response. It is used -// to factorize code between client (Invoke) and server (RegisterGRPCServer) -// gRPC handlers. -func RunGRPCQuery(ctx Context, grpcCtx gocontext.Context, method string, req interface{}, md metadata.MD) (abci.ResponseQuery, metadata.MD, error) { reqBz, err := protoCodec.Marshal(req) if err != nil { - return abci.ResponseQuery{}, nil, err + return err } // parse height header + md, _ := metadata.FromOutgoingContext(grpcCtx) if heights := md.Get(grpctypes.GRPCBlockHeightHeader); len(heights) > 0 { height, err := strconv.ParseInt(heights[0], 10, 64) if err != nil { - return abci.ResponseQuery{}, nil, err + return err } if height < 0 { - return abci.ResponseQuery{}, nil, sdkerrors.Wrapf( + return sdkerrors.Wrapf( sdkerrors.ErrInvalidRequest, "client.Context.Invoke: height (%d) from %q must be >= 0", height, grpctypes.GRPCBlockHeightHeader) } @@ -117,9 +78,14 @@ func RunGRPCQuery(ctx Context, grpcCtx gocontext.Context, method string, req int Height: ctx.Height, } - abciRes, err := ctx.QueryABCI(abciReq) + res, err := ctx.QueryABCI(abciReq) + if err != nil { + return err + } + + err = protoCodec.Unmarshal(res.Value, reply) if err != nil { - return abci.ResponseQuery{}, nil, err + return err } // Create header metadata. For now the headers contain: @@ -127,7 +93,24 @@ func RunGRPCQuery(ctx Context, grpcCtx gocontext.Context, method string, req int // We then parse all the call options, if the call option is a // HeaderCallOption, then we manually set the value of that header to the // metadata. - md = metadata.Pairs(grpctypes.GRPCBlockHeightHeader, strconv.FormatInt(abciRes.Height, 10)) + md = metadata.Pairs(grpctypes.GRPCBlockHeightHeader, strconv.FormatInt(res.Height, 10)) + for _, callOpt := range opts { + header, ok := callOpt.(grpc.HeaderCallOption) + if !ok { + continue + } + + *header.HeaderAddr = md + } + + if ctx.InterfaceRegistry != nil { + return types.UnpackInterfaces(reply, ctx.InterfaceRegistry) + } - return abciRes, md, nil + return nil +} + +// NewStream implements the grpc ClientConn.NewStream method +func (Context) NewStream(gocontext.Context, *grpc.StreamDesc, string, ...grpc.CallOption) (grpc.ClientStream, error) { + return nil, fmt.Errorf("streaming rpc not supported") } diff --git a/client/grpc_query_test.go b/client/grpc_query_test.go index d79d3a13d7..bd1e9d4926 100644 --- a/client/grpc_query_test.go +++ b/client/grpc_query_test.go @@ -1,5 +1,3 @@ -// +build norace - package client_test import ( diff --git a/client/keys/add.go b/client/keys/add.go index d596d00355..cb64b87448 100644 --- a/client/keys/add.go +++ b/client/keys/add.go @@ -41,7 +41,7 @@ const ( func AddKeyCommand() *cobra.Command { cmd := &cobra.Command{ Use: "add ", - Short: "Add an encrypted private key (either newly generated or recovered), encrypt it, and save to disk", + Short: "Add an encrypted private key (either newly generated or recovered), encrypt it, and save to file", Long: `Derive a new private key and encrypt to disk. Optionally specify a BIP39 mnemonic, a BIP39 passphrase to further secure the mnemonic, and a bip32 HD path to derive a specific account. The key will be stored under the given name @@ -54,31 +54,31 @@ local keystore. Use the --pubkey flag to add arbitrary public keys to the keystore for constructing multisig transactions. -You can add a multisig key by passing the list of key names you want the public -key to be composed of to the --multisig flag and the minimum number of signatures -required through --multisig-threshold. The keys are sorted by address, unless -the flag --nosort is set. +You can create and store a multisig key by passing the list of key names stored in a keyring +and the minimum number of signatures required through --multisig-threshold. The keys are +sorted by address, unless the flag --nosort is set. +Example: + + keys add mymultisig --multisig "keyname1,keyname2,keyname3" --multisig-threshold 2 `, Args: cobra.ExactArgs(1), RunE: runAddCmdPrepare, } - - cmd.Flags().StringSlice(flagMultisig, nil, "Construct and store a multisig public key (implies --pubkey)") - cmd.Flags().Int(flagMultiSigThreshold, 1, "K out of N required signatures. For use in conjunction with --multisig") - cmd.Flags().Bool(flagNoSort, false, "Keys passed to --multisig are taken in the order they're supplied") - cmd.Flags().String(FlagPublicKey, "", "Parse a public key in bech32 format and save it to disk") - cmd.Flags().BoolP(flagInteractive, "i", false, "Interactively prompt user for BIP39 passphrase and mnemonic") - cmd.Flags().Bool(flags.FlagUseLedger, false, "Store a local reference to a private key on a Ledger device") - cmd.Flags().Bool(flagRecover, false, "Provide seed phrase to recover existing key instead of creating") - cmd.Flags().Bool(flagNoBackup, false, "Don't print out seed phrase (if others are watching the terminal)") - cmd.Flags().Bool(flags.FlagDryRun, false, "Perform action, but don't add key to local keystore") - cmd.Flags().String(flagHDPath, "", "Manual HD Path derivation (overrides BIP44 config)") - cmd.Flags().Uint32(flagCoinType, CoinTypeNotAssigned, "coin type number for HD derivation") - cmd.Flags().Uint32(flagAccount, 0, "Account number for HD derivation") - cmd.Flags().Uint32(flagIndex, 0, "Address index number for HD derivation") - cmd.Flags().String(flags.FlagKeyAlgorithm, string(hd.Secp256k1Type), "Key signing algorithm to generate keys for") - cmd.SetOut(cmd.OutOrStdout()) - cmd.SetErr(cmd.ErrOrStderr()) + f := cmd.Flags() + f.StringSlice(flagMultisig, nil, "List of key names stored in keyring to construct a public legacy multisig key") + f.Int(flagMultiSigThreshold, 1, "K out of N required signatures. For use in conjunction with --multisig") + f.Bool(flagNoSort, false, "Keys passed to --multisig are taken in the order they're supplied") + f.String(FlagPublicKey, "", "Parse a public key in JSON format and saves key info to file.") + f.BoolP(flagInteractive, "i", false, "Interactively prompt user for BIP39 passphrase and mnemonic") + f.Bool(flags.FlagUseLedger, false, "Store a local reference to a private key on a Ledger device") + f.Bool(flagRecover, false, "Provide seed phrase to recover existing key instead of creating") + f.Bool(flagNoBackup, false, "Don't print out seed phrase (if others are watching the terminal)") + f.Bool(flags.FlagDryRun, false, "Perform action, but don't add key to local keystore") + f.String(flagHDPath, "", "Manual HD Path derivation (overrides BIP44 config)") + f.Uint32(flagCoinType, sdk.GetConfig().GetCoinType(), "coin type number for HD derivation") + f.Uint32(flagAccount, 0, "Account number for HD derivation") + f.Uint32(flagIndex, 0, "Address index number for HD derivation") + f.String(flags.FlagKeyAlgorithm, string(hd.Secp256k1Type), "Key signing algorithm to generate keys for") return cmd } @@ -90,7 +90,7 @@ func runAddCmdPrepare(cmd *cobra.Command, args []string) error { } buf := bufio.NewReader(clientCtx.Input) - return RunAddCmd(clientCtx, cmd, args, buf) + return runAddCmd(clientCtx, cmd, args, buf) } /* @@ -102,7 +102,7 @@ input output - armor encrypted private key (saved to file) */ -func RunAddCmd(ctx client.Context, cmd *cobra.Command, args []string, inBuf *bufio.Reader) error { +func runAddCmd(ctx client.Context, cmd *cobra.Command, args []string, inBuf *bufio.Reader) error { var err error name := args[0] @@ -119,7 +119,10 @@ func RunAddCmd(ctx client.Context, cmd *cobra.Command, args []string, inBuf *buf return err } - if dryRun, _ := cmd.Flags().GetBool(flags.FlagDryRun); !dryRun { + if dryRun, _ := cmd.Flags().GetBool(flags.FlagDryRun); dryRun { + // use in memory keybase + kb = keyring.NewInMemory() + } else { _, err = kb.Key(name) if err == nil { // account exists, ask for user confirmation @@ -140,20 +143,19 @@ func RunAddCmd(ctx client.Context, cmd *cobra.Command, args []string, inBuf *buf multisigKeys, _ := cmd.Flags().GetStringSlice(flagMultisig) if len(multisigKeys) != 0 { - var pks []cryptotypes.PubKey - + pks := make([]cryptotypes.PubKey, len(multisigKeys)) multisigThreshold, _ := cmd.Flags().GetInt(flagMultiSigThreshold) if err := validateMultisigThreshold(multisigThreshold, len(multisigKeys)); err != nil { return err } - for _, keyname := range multisigKeys { + for i, keyname := range multisigKeys { k, err := kb.Key(keyname) if err != nil { return err } - pks = append(pks, k.GetPubKey()) + pks[i] = k.GetPubKey() } if noSort, _ := cmd.Flags().GetBool(flagNoSort); !noSort { @@ -163,27 +165,29 @@ func RunAddCmd(ctx client.Context, cmd *cobra.Command, args []string, inBuf *buf } pk := multisig.NewLegacyAminoPubKey(multisigThreshold, pks) - if _, err := kb.SaveMultisig(name, pk); err != nil { + info, err := kb.SaveMultisig(name, pk) + if err != nil { return err } - cmd.PrintErrf("Key %q saved to disk.\n", name) - return nil + return printCreate(cmd, info, false, "", outputFormat) } } pubKey, _ := cmd.Flags().GetString(FlagPublicKey) if pubKey != "" { - pk, err := sdk.GetPubKeyFromBech32(sdk.Bech32PubKeyTypeAccPub, pubKey) + var pk cryptotypes.PubKey + err = ctx.Codec.UnmarshalInterfaceJSON([]byte(pubKey), &pk) if err != nil { return err } - if _, err := kb.SavePubKey(name, pk, algo.Name()); err != nil { + info, err := kb.SavePubKey(name, pk, algo.Name()) + if err != nil { return err } - return nil + return printCreate(cmd, info, false, "", outputFormat) } coinType, _ := cmd.Flags().GetUint32(flagCoinType) @@ -291,7 +295,7 @@ func printCreate(cmd *cobra.Command, info keyring.Info, showMnemonic bool, mnemo switch outputFormat { case OutputFormatText: cmd.PrintErrln() - printKeyInfo(cmd.OutOrStdout(), info, keyring.Bech32KeyOutput, outputFormat) + printKeyInfo(cmd.OutOrStdout(), info, keyring.MkAccKeyOutput, outputFormat) // print mnemonic unless requested not to. if showMnemonic { @@ -301,7 +305,7 @@ func printCreate(cmd *cobra.Command, info keyring.Info, showMnemonic bool, mnemo fmt.Fprintln(cmd.ErrOrStderr(), mnemonic) } case OutputFormatJSON: - out, err := keyring.Bech32KeyOutput(info) + out, err := keyring.MkAccKeyOutput(info) if err != nil { return err } diff --git a/client/keys/add_ledger_test.go b/client/keys/add_ledger_test.go index bd89797202..e2bd38d9a5 100644 --- a/client/keys/add_ledger_test.go +++ b/client/keys/add_ledger_test.go @@ -1,15 +1,17 @@ -//+build ledger test_ledger_mock +//go:build ledger || test_ledger_mock +// +build ledger test_ledger_mock package keys import ( + "bytes" "context" "fmt" + "io/ioutil" "testing" - "github.com/stretchr/testify/require" - "github.com/line/ostracon/libs/cli" + "github.com/stretchr/testify/require" "github.com/line/lbm-sdk/client" "github.com/line/lbm-sdk/client/flags" @@ -29,8 +31,8 @@ func Test_runAddCmdLedgerWithCustomCoinType(t *testing.T) { bech32PrefixConsAddr := "terravalcons" bech32PrefixConsPub := "terravalconspub" + config.SetPurpose(44) config.SetCoinType(330) - config.SetFullFundraiserPath("44'/330'/0'/0/0") config.SetBech32PrefixForAccount(bech32PrefixAccAddr, bech32PrefixAccPub) config.SetBech32PrefixForValidator(bech32PrefixValAddr, bech32PrefixValPub) config.SetBech32PrefixForConsensusNode(bech32PrefixConsAddr, bech32PrefixConsPub) @@ -74,11 +76,11 @@ func Test_runAddCmdLedgerWithCustomCoinType(t *testing.T) { require.Equal(t, "keyname1", key1.GetName()) require.Equal(t, keyring.TypeLedger, key1.GetType()) require.Equal(t, - "terrapub1cqmsrdepqvpg7r26nl2pvqqern00m6s9uaax3hauu2rzg8qpjzq9hy6xve7swm8dz8g", - sdk.MustBech32ifyPubKey(sdk.Bech32PubKeyTypeAccPub, key1.GetPubKey())) + "PubKeySecp256k1{03028F0D5A9FD41600191CDEFDEA05E77A68DFBCE286241C0190805B9346667D07}", + key1.GetPubKey().String()) + config.SetPurpose(44) config.SetCoinType(438) - config.SetFullFundraiserPath("44'/438'/0'/0/0") config.SetBech32PrefixForAccount(sdk.Bech32PrefixAccAddr, sdk.Bech32PrefixAccPub) config.SetBech32PrefixForValidator(sdk.Bech32PrefixValAddr, sdk.Bech32PrefixValPub) config.SetBech32PrefixForConsensusNode(sdk.Bech32PrefixConsAddr, sdk.Bech32PrefixConsPub) @@ -122,6 +124,69 @@ func Test_runAddCmdLedger(t *testing.T) { require.Equal(t, "keyname1", key1.GetName()) require.Equal(t, keyring.TypeLedger, key1.GetType()) require.Equal(t, - "linkpub1cqmsrdepq27djm9tzq3sftqsayx95refxk8r5jn0kyshhql9mdjhjx829zlvzygzwr2", - sdk.MustBech32ifyPubKey(sdk.Bech32PubKeyTypeAccPub, key1.GetPubKey())) + "PubKeySecp256k1{02BCD96CAB102304AC10E90C5A0F29358E3A4A6FB1217B83E5DB657918EA28BEC1}", + key1.GetPubKey().String()) +} + +func Test_runAddCmdLedgerDryRun(t *testing.T) { + testData := []struct { + name string + args []string + added bool + }{ + { + name: "ledger account is added", + args: []string{ + "testkey", + fmt.Sprintf("--%s=%s", flags.FlagDryRun, "false"), + fmt.Sprintf("--%s=%s", flags.FlagUseLedger, "true"), + }, + added: true, + }, + { + name: "ledger account is not added with dry run", + args: []string{ + "testkey", + fmt.Sprintf("--%s=%s", flags.FlagDryRun, "true"), + fmt.Sprintf("--%s=%s", flags.FlagUseLedger, "true"), + }, + added: false, + }, + } + for _, tt := range testData { + tt := tt + t.Run(tt.name, func(t *testing.T) { + cmd := AddKeyCommand() + cmd.Flags().AddFlagSet(Commands("home").PersistentFlags()) + + kbHome := t.TempDir() + mockIn := testutil.ApplyMockIODiscardOutErr(cmd) + kb, err := keyring.New(sdk.KeyringServiceName(), keyring.BackendTest, kbHome, mockIn) + require.NoError(t, err) + + clientCtx := client.Context{}. + WithKeyringDir(kbHome). + WithKeyring(kb) + ctx := context.WithValue(context.Background(), client.ClientContextKey, &clientCtx) + + b := bytes.NewBufferString("") + cmd.SetOut(b) + + cmd.SetArgs(tt.args) + require.NoError(t, cmd.ExecuteContext(ctx)) + + if tt.added { + _, err = kb.Key("testkey") + require.NoError(t, err) + + out, err := ioutil.ReadAll(b) + require.NoError(t, err) + require.Contains(t, string(out), "name: testkey") + } else { + _, err = kb.Key("testkey") + require.Error(t, err) + require.Equal(t, "testkey.info: key not found", err.Error()) + } + }) + } } diff --git a/client/keys/add_test.go b/client/keys/add_test.go index 82db461c13..de39bb6425 100644 --- a/client/keys/add_test.go +++ b/client/keys/add_test.go @@ -1,21 +1,24 @@ package keys import ( + "bytes" "context" "fmt" + "io/ioutil" "testing" + bip39 "github.com/cosmos/go-bip39" "github.com/stretchr/testify/require" "github.com/line/ostracon/libs/cli" - bip39 "github.com/cosmos/go-bip39" - "github.com/line/lbm-sdk/client" "github.com/line/lbm-sdk/client/flags" "github.com/line/lbm-sdk/crypto/hd" "github.com/line/lbm-sdk/crypto/keyring" + "github.com/line/lbm-sdk/simapp" "github.com/line/lbm-sdk/testutil" + "github.com/line/lbm-sdk/testutil/testdata" sdk "github.com/line/lbm-sdk/types" ) @@ -160,3 +163,113 @@ func TestAddRecoverFileBackend(t *testing.T) { require.NoError(t, err) require.Equal(t, "keyname1", info.GetName()) } + +func Test_runAddCmdDryRun(t *testing.T) { + pubkey1 := `{"@type":"/lbm.crypto.secp256k1.PubKey","key":"AtObiFVE4s+9+RX5SP8TN9r2mxpoaT4eGj9CJfK7VRzN"}` + pubkey2 := `{"@type":"/lbm.crypto.secp256k1.PubKey","key":"A/se1vkqgdQ7VJQCM4mxN+L+ciGhnnJ4XYsQCRBMrdRi"}` + + testData := []struct { + name string + args []string + added bool + }{ + { + name: "account is added", + args: []string{ + "testkey", + fmt.Sprintf("--%s=%s", flags.FlagDryRun, "false"), + }, + added: true, + }, + { + name: "account is not added with dry run", + args: []string{ + "testkey", + fmt.Sprintf("--%s=%s", flags.FlagDryRun, "true"), + }, + added: false, + }, + { + name: "multisig account is added", + args: []string{ + "testkey", + fmt.Sprintf("--%s=%s", flags.FlagDryRun, "false"), + fmt.Sprintf("--%s=%s", flagMultisig, "subkey"), + }, + added: true, + }, + { + name: "multisig account is not added with dry run", + args: []string{ + "testkey", + fmt.Sprintf("--%s=%s", flags.FlagDryRun, "true"), + fmt.Sprintf("--%s=%s", flagMultisig, "subkey"), + }, + added: false, + }, + { + name: "pubkey account is added", + args: []string{ + "testkey", + fmt.Sprintf("--%s=%s", flags.FlagDryRun, "false"), + fmt.Sprintf("--%s=%s", FlagPublicKey, pubkey1), + }, + added: true, + }, + { + name: "pubkey account is not added with dry run", + args: []string{ + "testkey", + fmt.Sprintf("--%s=%s", flags.FlagDryRun, "true"), + fmt.Sprintf("--%s=%s", FlagPublicKey, pubkey2), + }, + added: false, + }, + } + for _, tt := range testData { + tt := tt + t.Run(tt.name, func(t *testing.T) { + cmd := AddKeyCommand() + cmd.Flags().AddFlagSet(Commands("home").PersistentFlags()) + + kbHome := t.TempDir() + mockIn := testutil.ApplyMockIODiscardOutErr(cmd) + kb, err := keyring.New(sdk.KeyringServiceName(), keyring.BackendTest, kbHome, mockIn) + require.NoError(t, err) + + appCodec := simapp.MakeTestEncodingConfig().Marshaler + clientCtx := client.Context{}. + WithJSONCodec(appCodec). + WithKeyringDir(kbHome). + WithKeyring(kb) + ctx := context.WithValue(context.Background(), client.ClientContextKey, &clientCtx) + + path := sdk.GetConfig().GetFullBIP44Path() + _, err = kb.NewAccount("subkey", testdata.TestMnemonic, "", path, hd.Secp256k1) + require.NoError(t, err) + + t.Cleanup(func() { + _ = kb.Delete("subkey") + }) + + b := bytes.NewBufferString("") + cmd.SetOut(b) + + cmd.SetArgs(tt.args) + require.NoError(t, cmd.ExecuteContext(ctx)) + + if tt.added { + _, err = kb.Key("testkey") + require.NoError(t, err) + + out, err := ioutil.ReadAll(b) + require.NoError(t, err) + require.Contains(t, string(out), "name: testkey") + } else { + _, err = kb.Key("testkey") + require.Error(t, err) + require.Equal(t, "testkey.info: key not found", err.Error()) + } + }) + } +} diff --git a/client/keys/codec.go b/client/keys/codec.go index 10e0c82554..48b671fe40 100644 --- a/client/keys/codec.go +++ b/client/keys/codec.go @@ -5,6 +5,8 @@ import ( cryptocodec "github.com/line/lbm-sdk/crypto/codec" ) +// TODO: remove this file https://github.com/cosmos/cosmos-sdk/issues/8047 + // KeysCdc defines codec to be used with key operations var KeysCdc *codec.LegacyAmino diff --git a/client/keys/codec_test.go b/client/keys/codec_test.go index 801ff83fb5..723aa05a48 100644 --- a/client/keys/codec_test.go +++ b/client/keys/codec_test.go @@ -20,10 +20,10 @@ func getTestCases() testCases { return testCases{ // nolint:govet []keyring.KeyOutput{ - {"A", "B", "C", "D", "E", 0, nil}, - {"A", "B", "C", "D", "", 0, nil}, - {"", "B", "C", "D", "", 0, nil}, - {"", "", "", "", "", 0, nil}, + {"A", "B", "C", "D", "E"}, + {"A", "B", "C", "D", ""}, + {"", "B", "C", "D", ""}, + {"", "", "", "", ""}, }, make([]keyring.KeyOutput, 4), [][]byte{ diff --git a/client/keys/delete_test.go b/client/keys/delete_test.go index fab7ba06fe..b137726e43 100644 --- a/client/keys/delete_test.go +++ b/client/keys/delete_test.go @@ -12,6 +12,7 @@ import ( "github.com/line/lbm-sdk/crypto/hd" "github.com/line/lbm-sdk/crypto/keyring" "github.com/line/lbm-sdk/testutil" + "github.com/line/lbm-sdk/testutil/testdata" sdk "github.com/line/lbm-sdk/types" ) @@ -31,16 +32,16 @@ func Test_runDeleteCmd(t *testing.T) { fakeKeyName1 := "runDeleteCmd_Key1" fakeKeyName2 := "runDeleteCmd_Key2" - path := sdk.GetConfig().GetFullFundraiserPath() + path := sdk.GetConfig().GetFullBIP44Path() cmd.SetArgs([]string{"blah", fmt.Sprintf("--%s=%s", flags.FlagHome, kbHome)}) kb, err := keyring.New(sdk.KeyringServiceName(), keyring.BackendTest, kbHome, mockIn) require.NoError(t, err) - _, err = kb.NewAccount(fakeKeyName1, testutil.TestMnemonic, "", path, hd.Secp256k1) + _, err = kb.NewAccount(fakeKeyName1, testdata.TestMnemonic, "", path, hd.Secp256k1) require.NoError(t, err) - _, _, err = kb.NewMnemonic(fakeKeyName2, keyring.English, sdk.FullFundraiserPath, hd.Secp256k1) + _, _, err = kb.NewMnemonic(fakeKeyName2, keyring.English, sdk.FullFundraiserPath, keyring.DefaultBIP39Passphrase, hd.Secp256k1) require.NoError(t, err) clientCtx := client.Context{}. @@ -51,7 +52,7 @@ func Test_runDeleteCmd(t *testing.T) { err = cmd.ExecuteContext(ctx) require.Error(t, err) - require.Equal(t, "The specified item could not be found in the keyring", err.Error()) + require.EqualError(t, err, "blah.info: key not found") // User confirmation missing cmd.SetArgs([]string{ diff --git a/client/keys/export_test.go b/client/keys/export_test.go index cc40a9ce3f..dd92122dea 100644 --- a/client/keys/export_test.go +++ b/client/keys/export_test.go @@ -11,6 +11,7 @@ import ( "github.com/line/lbm-sdk/client" "github.com/line/lbm-sdk/crypto/hd" "github.com/line/lbm-sdk/testutil" + "github.com/line/lbm-sdk/testutil/testdata" "github.com/line/lbm-sdk/client/flags" "github.com/line/lbm-sdk/crypto/keyring" @@ -90,8 +91,8 @@ func Test_runExportCmd(t *testing.T) { kb.Delete("keyname1") // nolint:errcheck }) - path := sdk.GetConfig().GetFullFundraiserPath() - _, err = kb.NewAccount("keyname1", testutil.TestMnemonic, "", path, hd.Secp256k1) + path := sdk.GetConfig().GetFullBIP44Path() + _, err = kb.NewAccount("keyname1", testdata.TestMnemonic, "", path, hd.Secp256k1) require.NoError(t, err) clientCtx := client.Context{}. diff --git a/client/keys/list.go b/client/keys/list.go index d82d6f6235..4608e44b38 100644 --- a/client/keys/list.go +++ b/client/keys/list.go @@ -33,8 +33,6 @@ func runListCmd(cmd *cobra.Command, _ []string) error { return err } - cmd.SetOut(cmd.OutOrStdout()) - if ok, _ := cmd.Flags().GetBool(flagListNames); !ok { printInfos(cmd.OutOrStdout(), infos, clientCtx.OutputFormat) return nil diff --git a/client/keys/list_test.go b/client/keys/list_test.go index c63c4f3f41..44fe00f49e 100644 --- a/client/keys/list_test.go +++ b/client/keys/list_test.go @@ -13,6 +13,7 @@ import ( "github.com/line/lbm-sdk/crypto/hd" "github.com/line/lbm-sdk/crypto/keyring" "github.com/line/lbm-sdk/testutil" + "github.com/line/lbm-sdk/testutil/testdata" sdk "github.com/line/lbm-sdk/types" ) @@ -30,8 +31,8 @@ func Test_runListCmd(t *testing.T) { clientCtx := client.Context{}.WithKeyring(kb) ctx := context.WithValue(context.Background(), client.ClientContextKey, &clientCtx) - path := "" //sdk.GetConfig().GetFullFundraiserPath() - _, err = kb.NewAccount("something", testutil.TestMnemonic, "", path, hd.Secp256k1) + path := "" //sdk.GetConfig().GetFullBIP44Path() + _, err = kb.NewAccount("something", testdata.TestMnemonic, "", path, hd.Secp256k1) require.NoError(t, err) t.Cleanup(func() { diff --git a/client/keys/parse.go b/client/keys/parse.go index 768bad7a4d..685cf0a855 100644 --- a/client/keys/parse.go +++ b/client/keys/parse.go @@ -1,7 +1,6 @@ package keys import ( - "context" "encoding/hex" "errors" "fmt" @@ -86,7 +85,7 @@ hexadecimal into bech32 cosmos prefixed format and vice versa. } func parseKey(cmd *cobra.Command, args []string) error { - config, _ := sdk.GetSealedConfig(context.Background()) + config, _ := sdk.GetSealedConfig(cmd.Context()) return doParseKey(cmd, config, args) } diff --git a/client/keys/parse_test.go b/client/keys/parse_test.go index c64cfff056..a1fca54727 100644 --- a/client/keys/parse_test.go +++ b/client/keys/parse_test.go @@ -9,7 +9,7 @@ import ( ) func TestParseKey(t *testing.T) { - bech32str := "cosmos104ytdpvrx9284zd50v9ep8c6j7pua7dkk0x3ek" + bech32str := "link104ytdpvrx9284zd50v9ep8c6j7pua7dkrpxnz7" hexstr := "EB5AE9872103497EC092EF901027049E4F39200C60040D3562CD7F104A39F62E6E5A39A818F4" config := sdk.NewConfig() diff --git a/client/keys/root.go b/client/keys/root.go index c0a5da3da8..71045f7f40 100644 --- a/client/keys/root.go +++ b/client/keys/root.go @@ -44,7 +44,6 @@ The pass backend requires GnuPG: https://gnupg.org/ ImportKeyCommand(), ListKeysCmd(), ShowKeysCmd(), - flags.LineBreak, DeleteKeyCommand(), ParseKeyStringCommand(), ) diff --git a/client/keys/root_test.go b/client/keys/root_test.go index b6c2f5f88f..a3cc143469 100644 --- a/client/keys/root_test.go +++ b/client/keys/root_test.go @@ -11,5 +11,5 @@ func TestCommands(t *testing.T) { assert.NotNil(t, rootCommands) // Commands are registered - assert.Equal(t, 9, len(rootCommands.Commands())) + assert.Equal(t, 8, len(rootCommands.Commands())) } diff --git a/client/keys/show.go b/client/keys/show.go index 1a7affec0d..367aca8df5 100644 --- a/client/keys/show.go +++ b/client/keys/show.go @@ -13,6 +13,7 @@ import ( "github.com/line/lbm-sdk/crypto/ledger" cryptotypes "github.com/line/lbm-sdk/crypto/types" sdk "github.com/line/lbm-sdk/types" + sdkerr "github.com/line/lbm-sdk/types/errors" ) const ( @@ -41,12 +42,12 @@ consisting of all the keys provided by name and multisig threshold.`, Args: cobra.MinimumNArgs(1), RunE: runShowCmd, } - - cmd.Flags().String(FlagBechPrefix, sdk.PrefixAccount, "The Bech32 prefix encoding for a key (acc|val|cons)") - cmd.Flags().BoolP(FlagAddress, "a", false, "Output the address only (overrides --output)") - cmd.Flags().BoolP(FlagPublicKey, "p", false, "Output the public key only (overrides --output)") - cmd.Flags().BoolP(FlagDevice, "d", false, "Output the address in a ledger device") - cmd.Flags().Int(flagMultiSigThreshold, 1, "K out of N required signatures") + f := cmd.Flags() + f.String(FlagBechPrefix, sdk.PrefixAccount, "The Bech32 prefix encoding for a key (acc|val|cons)") + f.BoolP(FlagAddress, "a", false, "Output the address only (overrides --output)") + f.BoolP(FlagPublicKey, "p", false, "Output the public key only (overrides --output)") + f.BoolP(FlagDevice, "d", false, "Output the address in a ledger device") + f.Int(flagMultiSigThreshold, 1, "K out of N required signatures") return cmd } @@ -64,7 +65,10 @@ func runShowCmd(cmd *cobra.Command, args []string) (err error) { return fmt.Errorf("%s is not a valid name or address: %v", args[0], err) } if info.GetType() == keyring.TypeMulti { - info = keyring.NewMultiInfo(info.GetName(), info.GetPubKey()) + info, err = keyring.NewMultiInfo(info.GetName(), info.GetPubKey()) + if err != nil { + return err + } } } else { pks := make([]cryptotypes.PubKey, len(args)) @@ -84,7 +88,10 @@ func runShowCmd(cmd *cobra.Command, args []string) (err error) { } multikey := multisig.NewLegacyAminoPubKey(multisigThreshold, pks) - info = keyring.NewMultiInfo(defaultMultiSigKeyName, multikey) + info, err = keyring.NewMultiInfo(defaultMultiSigKeyName, multikey) + if err != nil { + return err + } } isShowAddr, _ := cmd.Flags().GetBool(FlagAddress) @@ -116,10 +123,16 @@ func runShowCmd(cmd *cobra.Command, args []string) (err error) { } switch { - case isShowAddr: - printKeyAddress(cmd.OutOrStdout(), info, bechKeyOut) - case isShowPubKey: - printPubKey(cmd.OutOrStdout(), info, bechKeyOut) + case isShowAddr, isShowPubKey: + ko, err := bechKeyOut(info) + if err != nil { + return err + } + out := ko.Address + if isShowPubKey { + out = ko.PubKey + } + fmt.Fprintln(cmd.OutOrStdout(), out) default: printKeyInfo(cmd.OutOrStdout(), info, bechKeyOut, clientCtx.OutputFormat) } @@ -149,19 +162,21 @@ func runShowCmd(cmd *cobra.Command, args []string) (err error) { } func fetchKey(kb keyring.Keyring, keyref string) (keyring.Info, error) { + // firstly check if the keyref is a key name of a key registered in a keyring. info, err := kb.Key(keyref) + // if the key is not there or if we have a problem with a keyring itself then we move to a + // fallback: searching for key by address. + if err == nil || !sdkerr.IsOf(err, sdkerr.ErrIO, sdkerr.ErrKeyNotFound) { + return info, err + } + err = sdk.ValidateAccAddress(keyref) if err != nil { - err := sdk.ValidateAccAddress(keyref) - if err != nil { - return info, err - } - - info, err = kb.KeyByAddress(sdk.AccAddress(keyref)) - if err != nil { - return info, errors.New("key not found") - } + return info, err } - return info, nil + accAddr := sdk.AccAddress(keyref) + + info, err = kb.KeyByAddress(accAddr) + return info, sdkerr.Wrap(err, "Invalid key") } func validateMultisigThreshold(k, nKeys int) error { @@ -178,11 +193,11 @@ func validateMultisigThreshold(k, nKeys int) error { func getBechKeyOut(bechPrefix string) (bechKeyOutFn, error) { switch bechPrefix { case sdk.PrefixAccount: - return keyring.Bech32KeyOutput, nil + return keyring.MkAccKeyOutput, nil case sdk.PrefixValidator: - return keyring.Bech32ValKeyOutput, nil + return keyring.MkValKeyOutput, nil case sdk.PrefixConsensus: - return keyring.Bech32ConsKeyOutput, nil + return keyring.MkConsKeyOutput, nil } return nil, fmt.Errorf("invalid Bech32 prefix encoding provided: %s", bechPrefix) diff --git a/client/keys/show_test.go b/client/keys/show_test.go index 7334800b90..6a155d1577 100644 --- a/client/keys/show_test.go +++ b/client/keys/show_test.go @@ -3,13 +3,10 @@ package keys import ( "context" "fmt" - "strings" "testing" "github.com/stretchr/testify/require" - ostcli "github.com/line/ostracon/libs/cli" - "github.com/line/lbm-sdk/client" "github.com/line/lbm-sdk/client/flags" "github.com/line/lbm-sdk/crypto/hd" @@ -18,7 +15,7 @@ import ( "github.com/line/lbm-sdk/crypto/keys/secp256k1" cryptotypes "github.com/line/lbm-sdk/crypto/types" "github.com/line/lbm-sdk/testutil" - clitestutil "github.com/line/lbm-sdk/testutil/cli" + "github.com/line/lbm-sdk/testutil/testdata" sdk "github.com/line/lbm-sdk/types" ) @@ -28,8 +25,8 @@ func Test_multiSigKey_Properties(t *testing.T) { 1, []cryptotypes.PubKey{tmpKey1.PubKey()}, ) - tmp := keyring.NewMultiInfo("myMultisig", pk) - + tmp, err := keyring.NewMultiInfo("myMultisig", pk) + require.NoError(t, err) require.Equal(t, "myMultisig", tmp.GetName()) require.Equal(t, keyring.TypeMulti, tmp.GetType()) require.Equal(t, "BDF0C827D34CA39919C7688EB5A95383C60B3471", tmp.GetPubKey().Address().String()) @@ -45,67 +42,6 @@ func Test_showKeysCmd(t *testing.T) { require.Equal(t, "false", cmd.Flag(FlagPublicKey).DefValue) } -func TestShowCmdWithMultisigAccount(t *testing.T) { - cmd := ShowKeysCmd() - cmd.Flags().AddFlagSet(Commands("home").PersistentFlags()) - mockIn := testutil.ApplyMockIODiscardOutErr(cmd) - - kbHome := t.TempDir() - kb, err := keyring.New(sdk.KeyringServiceName(), keyring.BackendTest, kbHome, mockIn) - require.NoError(t, err) - - clientCtx := client.Context{}.WithKeyring(kb) - - fakeKeyName1 := "runShowCmd_Key1" - fakeKeyName2 := "runShowCmd_Key2" - myMultiSig := "mymulti" - threshold := 2 - - t.Cleanup(func() { - kb.Delete(fakeKeyName1) - kb.Delete(fakeKeyName2) - kb.Delete(myMultiSig) - }) - - path := hd.NewFundraiserParams(1, sdk.CoinType, 0).String() - acc1, err := kb.NewAccount(fakeKeyName1, testutil.TestMnemonic, "", path, hd.Secp256k1) - require.NoError(t, err) - - path2 := hd.NewFundraiserParams(1, sdk.CoinType, 1).String() - acc2, err := kb.NewAccount(fakeKeyName2, testutil.TestMnemonic, "", path2, hd.Secp256k1) - require.NoError(t, err) - - var pks []cryptotypes.PubKey - pks = append(pks, acc1.GetPubKey(), acc2.GetPubKey()) - - pk := multisig.NewLegacyAminoPubKey(threshold, pks) - multiSig, err := kb.SaveMultisig(myMultiSig, pk) - require.NoError(t, err) - - multiSigInfo, err := keyring.Bech32KeyOutput(multiSig) - require.NoError(t, err) - - multiSigInfoBytes, err := KeysCdc.Amino.MarshalJSON(multiSigInfo) - require.NoError(t, err) - - args := []string{ - myMultiSig, - fmt.Sprintf("--%s=%s", flags.FlagHome, kbHome), - fmt.Sprintf("--%s=%s", flags.FlagKeyringBackend, keyring.BackendTest), - fmt.Sprintf("--%s=%s", FlagBechPrefix, sdk.PrefixAccount), - fmt.Sprintf("--%s=json", ostcli.OutputFlag), - } - - var res keyring.KeyOutput - out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, args) - require.NoError(t, err) - - KeysCdc.Amino.UnmarshalJSON(out.Bytes(), &res) - require.Equal(t, res.Threshold, uint(threshold)) - require.Len(t, res.PubKeys, 2) - require.Equal(t, strings.TrimSpace(out.String()), string(multiSigInfoBytes)) -} - func Test_runShowCmd(t *testing.T) { cmd := ShowKeysCmd() cmd.Flags().AddFlagSet(Commands("home").PersistentFlags()) @@ -135,11 +71,11 @@ func Test_runShowCmd(t *testing.T) { }) path := hd.NewFundraiserParams(1, sdk.CoinType, 0).String() - _, err = kb.NewAccount(fakeKeyName1, testutil.TestMnemonic, "", path, hd.Secp256k1) + _, err = kb.NewAccount(fakeKeyName1, testdata.TestMnemonic, "", path, hd.Secp256k1) require.NoError(t, err) path2 := hd.NewFundraiserParams(1, sdk.CoinType, 1).String() - _, err = kb.NewAccount(fakeKeyName2, testutil.TestMnemonic, "", path2, hd.Secp256k1) + _, err = kb.NewAccount(fakeKeyName2, testdata.TestMnemonic, "", path2, hd.Secp256k1) require.NoError(t, err) // Now try single key @@ -263,28 +199,20 @@ func Test_getBechKeyOut(t *testing.T) { }{ {"empty", args{""}, nil, true}, {"wrong", args{"???"}, nil, true}, - {"acc", args{sdk.PrefixAccount}, keyring.Bech32KeyOutput, false}, - {"val", args{sdk.PrefixValidator}, keyring.Bech32ValKeyOutput, false}, - {"cons", args{sdk.PrefixConsensus}, keyring.Bech32ConsKeyOutput, false}, + {"acc", args{sdk.PrefixAccount}, keyring.MkAccKeyOutput, false}, + {"val", args{sdk.PrefixValidator}, keyring.MkValKeyOutput, false}, + {"cons", args{sdk.PrefixConsensus}, keyring.MkConsKeyOutput, false}, } for _, tt := range tests { tt := tt t.Run(tt.name, func(t *testing.T) { got, err := getBechKeyOut(tt.args.bechPrefix) - if (err != nil) != tt.wantErr { - t.Errorf("getBechKeyOut() error = %v, wantErr %v", err, tt.wantErr) - return - } - - if !tt.wantErr { + if tt.wantErr { + require.Error(t, err) + } else { + require.NoError(t, err) require.NotNil(t, got) } - - // TODO: Still not possible to compare functions - // Maybe in next release: https://github.com/stretchr/testify/issues/182 - //if &got != &tt.want { - // t.Errorf("getBechKeyOut() = %v, want %v", got, tt.want) - //} }) } } diff --git a/client/keys/testdata/keys/keys.db/000136.ldb b/client/keys/testdata/keys/keys.db/000136.ldb new file mode 100644 index 0000000000..58165a9ab1 Binary files /dev/null and b/client/keys/testdata/keys/keys.db/000136.ldb differ diff --git a/client/keys/testdata/keys/keys.db/000137.ldb b/client/keys/testdata/keys/keys.db/000137.ldb new file mode 100644 index 0000000000..340e51356e Binary files /dev/null and b/client/keys/testdata/keys/keys.db/000137.ldb differ diff --git a/client/keys/testdata/keys/keys.db/MANIFEST-000167 b/client/keys/testdata/keys/keys.db/MANIFEST-000167 new file mode 100644 index 0000000000..410bbeb71a Binary files /dev/null and b/client/keys/testdata/keys/keys.db/MANIFEST-000167 differ diff --git a/client/keys/utils.go b/client/keys/utils.go index d13e212338..e22d777ae2 100644 --- a/client/keys/utils.go +++ b/client/keys/utils.go @@ -38,7 +38,7 @@ func printKeyInfo(w io.Writer, keyInfo cryptokeyring.Info, bechKeyOut bechKeyOut } func printInfos(w io.Writer, infos []cryptokeyring.Info, output string) { - kos, err := cryptokeyring.Bech32KeysOutput(infos) + kos, err := cryptokeyring.MkAccKeysOutput(infos) if err != nil { panic(err) } @@ -64,21 +64,3 @@ func printTextInfos(w io.Writer, kos []cryptokeyring.KeyOutput) { } fmt.Fprintln(w, string(out)) } - -func printKeyAddress(w io.Writer, info cryptokeyring.Info, bechKeyOut bechKeyOutFn) { - ko, err := bechKeyOut(info) - if err != nil { - panic(err) - } - - fmt.Fprintln(w, ko.Address) -} - -func printPubKey(w io.Writer, info cryptokeyring.Info, bechKeyOut bechKeyOutFn) { - ko, err := bechKeyOut(info) - if err != nil { - panic(err) - } - - fmt.Fprintln(w, ko.PubKey) -} diff --git a/client/keys/utils_test.go b/client/keys/utils_test.go index 9d2f0a75f7..385928f3b1 100644 --- a/client/keys/utils_test.go +++ b/client/keys/utils_test.go @@ -10,6 +10,7 @@ import ( "github.com/line/lbm-sdk/crypto/hd" "github.com/line/lbm-sdk/crypto/keyring" "github.com/line/lbm-sdk/testutil" + "github.com/line/lbm-sdk/testutil/testdata" "github.com/line/lbm-sdk/types" ) @@ -23,7 +24,7 @@ func Test_printInfos(t *testing.T) { kb, err := keyring.New(types.KeyringServiceName(), keyring.BackendTest, kbHome, mockIn) require.NoError(t, err) - kb.NewAccount("something", testutil.TestMnemonic, "", "", hd.Secp256k1) + kb.NewAccount("something", testdata.TestMnemonic, "", "", hd.Secp256k1) clientCtx := client.Context{}.WithKeyring(kb) require.NoError(t, err) @@ -32,5 +33,5 @@ func Test_printInfos(t *testing.T) { require.NoError(t, err) buf := bytes.NewBufferString("") printInfos(buf, infos, OutputFormatJSON) - require.Equal(t, buf.String(), "[{\"name\":\"something\",\"type\":\"local\",\"address\":\"link1jyyxx9phqw6tarnxanhyx7ecr992d6yrztj4d0\",\"pubkey\":\"linkpub1cqmsrdepqg8qdahungt0uladr5g4v6kh56x4wx7auws5rfxunyrapnqn7kfkyrszyvh\"}]") + require.Equal(t, buf.String(), "[{\"name\":\"something\",\"type\":\"local\",\"address\":\"link1jyyxx9phqw6tarnxanhyx7ecr992d6yrztj4d0\",\"pubkey\":\"{\\\"@type\\\":\\\"/lbm.crypto.secp256k1.PubKey\\\",\\\"key\\\":\\\"Ag4G9vyaFv5/rR0RVmrXpo1XG93joUGk3JkH0MwT9ZNi\\\"}\"}]") } diff --git a/client/query.go b/client/query.go index e0c6180e55..4c8e8efc9e 100644 --- a/client/query.go +++ b/client/query.go @@ -126,8 +126,9 @@ func sdkErrorToGRPCError(resp abci.ResponseQuery) error { // or an error if the query fails. func (ctx Context) query(path string, key ostbytes.HexBytes) ([]byte, int64, error) { resp, err := ctx.queryABCI(abci.RequestQuery{ - Path: path, - Data: key, + Path: path, + Data: key, + Height: ctx.Height, }) if err != nil { return nil, 0, err diff --git a/client/query_test.go b/client/query_test.go index d26b4befca..9c77ce5f9f 100644 --- a/client/query_test.go +++ b/client/query_test.go @@ -1,3 +1,4 @@ +//go:build norace // +build norace package client_test @@ -49,15 +50,14 @@ func (s *IntegrationTestSuite) TestQueryABCIHeight() { req := abci.RequestQuery{ Path: fmt.Sprintf("store/%s/key", banktypes.StoreKey), Height: tc.reqHeight, - Data: append(banktypes.BalancesPrefix, val.Address.Bytes()...), + Data: banktypes.CreateAccountBalancesPrefix(val.Address.Bytes()), Prove: true, } res, err := clientCtx.QueryABCI(req) s.Require().NoError(err) - // Line: block height could be higher if execution gets slowed down - s.Require().LessOrEqual(tc.expHeight, res.Height) + s.Require().Equal(tc.expHeight, res.Height) }) } } diff --git a/client/rest/rest.go b/client/rest/rest.go index e47954b804..07a248d3e4 100644 --- a/client/rest/rest.go +++ b/client/rest/rest.go @@ -8,7 +8,7 @@ import ( // DeprecationURL is the URL for migrating deprecated REST endpoints to newer ones. // TODO Switch to `/` (not `/master`) once v0.40 docs are deployed. -// https://github.com/line/lbm-sdk/issues/8019 +// https://github.com/cosmos/cosmos-sdk/issues/8019 const DeprecationURL = "https://docs.cosmos.network/master/migrations/rest.html" // addHTTPDeprecationHeaders is a mux middleware function for adding HTTP @@ -26,6 +26,7 @@ func addHTTPDeprecationHeaders(h http.Handler) http.Handler { // WithHTTPDeprecationHeaders returns a new *mux.Router, identical to its input // but with the addition of HTTP Deprecation headers. This is used to mark legacy // amino REST endpoints as deprecated in the REST API. +// nolint: gocritic func WithHTTPDeprecationHeaders(r *mux.Router) *mux.Router { subRouter := r.NewRoute().Subrouter() subRouter.Use(addHTTPDeprecationHeaders) diff --git a/client/rpc/validators.go b/client/rpc/validators.go index 70c46abaf7..1cad03c164 100644 --- a/client/rpc/validators.go +++ b/client/rpc/validators.go @@ -8,9 +8,8 @@ import ( "strings" "github.com/gorilla/mux" - "github.com/spf13/cobra" - octypes "github.com/line/ostracon/types" + "github.com/spf13/cobra" "github.com/line/lbm-sdk/client" "github.com/line/lbm-sdk/client/flags" @@ -50,7 +49,7 @@ func ValidatorCommand() *cobra.Command { page, _ := cmd.Flags().GetInt(flags.FlagPage) limit, _ := cmd.Flags().GetInt(flags.FlagLimit) - result, err := GetValidators(clientCtx, height, &page, &limit) + result, err := GetValidators(cmd.Context(), clientCtx, height, &page, &limit) if err != nil { return err } @@ -67,7 +66,7 @@ func ValidatorCommand() *cobra.Command { return cmd } -// Validator output in bech32 format +// Validator output type ValidatorOutput struct { Address sdk.ConsAddress `json:"address"` PubKey cryptotypes.PubKey `json:"pub_key"` @@ -79,12 +78,14 @@ type ValidatorOutput struct { type ResultValidatorsOutput struct { BlockHeight int64 `json:"block_height"` Validators []ValidatorOutput `json:"validators"` + Total uint64 `json:"total"` } func (rvo ResultValidatorsOutput) String() string { var b strings.Builder b.WriteString(fmt.Sprintf("block height: %d\n", rvo.BlockHeight)) + b.WriteString(fmt.Sprintf("total count: %d\n", rvo.Total)) for _, val := range rvo.Validators { b.WriteString( @@ -117,31 +118,35 @@ func validatorOutput(validator *octypes.Validator) (ValidatorOutput, error) { } // GetValidators from client -func GetValidators(clientCtx client.Context, height *int64, page, limit *int) (ResultValidatorsOutput, error) { +func GetValidators(ctx context.Context, clientCtx client.Context, height *int64, page, limit *int) (ResultValidatorsOutput, error) { // get the node node, err := clientCtx.GetNode() if err != nil { return ResultValidatorsOutput{}, err } - validatorsRes, err := node.Validators(context.Background(), height, page, limit) + validatorsRes, err := node.Validators(ctx, height, page, limit) if err != nil { return ResultValidatorsOutput{}, err } - outputValidatorsRes := ResultValidatorsOutput{ + total := validatorsRes.Total + if validatorsRes.Total < 0 { + total = 0 + } + out := ResultValidatorsOutput{ BlockHeight: validatorsRes.BlockHeight, Validators: make([]ValidatorOutput, len(validatorsRes.Validators)), + Total: uint64(total), } - for i := 0; i < len(validatorsRes.Validators); i++ { - outputValidatorsRes.Validators[i], err = validatorOutput(validatorsRes.Validators[i]) + out.Validators[i], err = validatorOutput(validatorsRes.Validators[i]) if err != nil { - return ResultValidatorsOutput{}, err + return out, err } } - return outputValidatorsRes, nil + return out, nil } // REST @@ -172,7 +177,7 @@ func ValidatorSetRequestHandlerFn(clientCtx client.Context) http.HandlerFunc { return } - output, err := GetValidators(clientCtx, &height, &page, &limit) + output, err := GetValidators(r.Context(), clientCtx, &height, &page, &limit) if rest.CheckInternalServerError(w, err) { return } @@ -189,7 +194,7 @@ func LatestValidatorSetRequestHandlerFn(clientCtx client.Context) http.HandlerFu return } - output, err := GetValidators(clientCtx, nil, &page, &limit) + output, err := GetValidators(r.Context(), clientCtx, nil, &page, &limit) if rest.CheckInternalServerError(w, err) { return } diff --git a/client/tx/factory.go b/client/tx/factory.go index a35cb50158..92836b9eec 100644 --- a/client/tx/factory.go +++ b/client/tx/factory.go @@ -44,7 +44,7 @@ func NewFactoryCLI(clientCtx client.Context, flagSet *pflag.FlagSet) Factory { accNum, _ := flagSet.GetUint64(flags.FlagAccountNumber) accSeq, _ := flagSet.GetUint64(flags.FlagSequence) gasAdj, _ := flagSet.GetFloat64(flags.FlagGasAdjustment) - memo, _ := flagSet.GetString(flags.FlagMemo) + memo, _ := flagSet.GetString(flags.FlagNote) timeoutHeight, _ := flagSet.GetUint64(flags.FlagTimeoutHeight) gasStr, _ := flagSet.GetString(flags.FlagGas) diff --git a/client/tx/legacy.go b/client/tx/legacy.go index e37d7a7b36..f8a629c81d 100644 --- a/client/tx/legacy.go +++ b/client/tx/legacy.go @@ -5,7 +5,6 @@ import ( "github.com/line/lbm-sdk/client" "github.com/line/lbm-sdk/codec" - sdk "github.com/line/lbm-sdk/types" "github.com/line/lbm-sdk/x/auth/legacy/legacytx" "github.com/line/lbm-sdk/x/auth/signing" ) @@ -65,24 +64,3 @@ func CopyTx(tx signing.Tx, builder client.TxBuilder, ignoreSignatureError bool) return nil } - -// ConvertAndEncodeStdTx encodes the stdTx as a transaction in the format specified by txConfig -func ConvertAndEncodeStdTx(txConfig client.TxConfig, stdTx legacytx.StdTx) ([]byte, error) { - builder := txConfig.NewTxBuilder() - - var theTx sdk.Tx - - // check if we need a StdTx anyway, in that case don't copy - if _, ok := builder.GetTx().(legacytx.StdTx); ok { - theTx = stdTx - } else { - err := CopyTx(stdTx, builder, false) - if err != nil { - return nil, err - } - - theTx = builder.GetTx() - } - - return txConfig.TxEncoder()(theTx) -} diff --git a/client/tx/legacy_test.go b/client/tx/legacy_test.go index 6363c68120..4a643fb9ac 100644 --- a/client/tx/legacy_test.go +++ b/client/tx/legacy_test.go @@ -12,10 +12,9 @@ import ( "github.com/line/lbm-sdk/simapp" "github.com/line/lbm-sdk/simapp/params" "github.com/line/lbm-sdk/testutil/testdata" - "github.com/line/lbm-sdk/types" + sdk "github.com/line/lbm-sdk/types" signing2 "github.com/line/lbm-sdk/types/tx/signing" "github.com/line/lbm-sdk/x/auth/legacy/legacytx" - "github.com/line/lbm-sdk/x/auth/signing" "github.com/line/lbm-sdk/x/auth/tx" banktypes "github.com/line/lbm-sdk/x/bank/types" ) @@ -23,14 +22,13 @@ import ( const ( memo = "waboom" gas = uint64(10000) - timeoutHeight = 5 + timeoutHeight = uint64(5) ) var ( - fee = types.NewCoins(types.NewInt64Coin("bam", 100)) + fee = sdk.NewCoins(sdk.NewInt64Coin("bam", 100)) _, pub1, addr1 = testdata.KeyTestPubAddr() _, _, addr2 = testdata.KeyTestPubAddr() - msg = banktypes.NewMsgSend(addr1, addr2, types.NewCoins(types.NewInt64Coin("wack", 10000))) sig = signing2.SignatureV2{ PubKey: pub1, Data: &signing2.SingleSignatureData{ @@ -38,13 +36,15 @@ var ( Signature: []byte("dummy"), }, } + msg0 = banktypes.NewMsgSend(addr1, addr2, sdk.NewCoins(sdk.NewInt64Coin("wack", 1))) + msg1 = banktypes.NewMsgSend(addr1, addr2, sdk.NewCoins(sdk.NewInt64Coin("wack", 2))) ) func buildTestTx(t *testing.T, builder client.TxBuilder) { builder.SetMemo(memo) builder.SetGasLimit(gas) builder.SetFeeAmount(fee) - err := builder.SetMsgs(msg) + err := builder.SetMsgs(msg0, msg1) require.NoError(t, err) err = builder.SetSignatures(sig) require.NoError(t, err) @@ -75,11 +75,15 @@ func (s *TestSuite) TestCopyTx() { protoBuilder2 := s.protoCfg.NewTxBuilder() err = tx2.CopyTx(aminoBuilder.GetTx(), protoBuilder2, false) s.Require().NoError(err) - bz, err := s.protoCfg.TxEncoder()(protoBuilder.GetTx()) + // Check sigs, signers and msgs. + sigsV2_1, err := protoBuilder.GetTx().GetSignaturesV2() s.Require().NoError(err) - bz2, err := s.protoCfg.TxEncoder()(protoBuilder2.GetTx()) + sigsV2_2, err := protoBuilder2.GetTx().GetSignaturesV2() s.Require().NoError(err) - s.Require().Equal(bz, bz2) + s.Require().Equal(sigsV2_1, sigsV2_2) + s.Require().Equal(protoBuilder.GetTx().GetSigners(), protoBuilder2.GetTx().GetSigners()) + s.Require().Equal(protoBuilder.GetTx().GetMsgs()[0], protoBuilder2.GetTx().GetMsgs()[0]) + s.Require().Equal(protoBuilder.GetTx().GetMsgs()[1], protoBuilder2.GetTx().GetMsgs()[1]) // amino -> proto -> amino aminoBuilder = s.aminoCfg.NewTxBuilder() @@ -90,11 +94,15 @@ func (s *TestSuite) TestCopyTx() { aminoBuilder2 := s.aminoCfg.NewTxBuilder() err = tx2.CopyTx(protoBuilder.GetTx(), aminoBuilder2, false) s.Require().NoError(err) - bz, err = s.aminoCfg.TxEncoder()(aminoBuilder.GetTx()) + // Check sigs, signers, and msgs + sigsV2_1, err = aminoBuilder.GetTx().GetSignaturesV2() s.Require().NoError(err) - bz2, err = s.aminoCfg.TxEncoder()(aminoBuilder2.GetTx()) + sigsV2_2, err = aminoBuilder2.GetTx().GetSignaturesV2() s.Require().NoError(err) - s.Require().Equal(bz, bz2) + s.Require().Equal(sigsV2_1, sigsV2_2) + s.Require().Equal(aminoBuilder.GetTx().GetSigners(), aminoBuilder2.GetTx().GetSigners()) + s.Require().Equal(aminoBuilder.GetTx().GetMsgs()[0], aminoBuilder2.GetTx().GetMsgs()[0]) + s.Require().Equal(aminoBuilder.GetTx().GetMsgs()[1], aminoBuilder2.GetTx().GetMsgs()[1]) } func (s *TestSuite) TestConvertTxToStdTx() { @@ -106,7 +114,8 @@ func (s *TestSuite) TestConvertTxToStdTx() { s.Require().Equal(memo, stdTx.Memo) s.Require().Equal(gas, stdTx.Fee.Gas) s.Require().Equal(fee, stdTx.Fee.Amount) - s.Require().Equal(msg, stdTx.Msgs[0]) + s.Require().Equal(msg0, stdTx.Msgs[0]) + s.Require().Equal(msg1, stdTx.Msgs[1]) s.Require().Equal(timeoutHeight, stdTx.TimeoutHeight) s.Require().Equal(sig.PubKey, stdTx.Signatures[0].PubKey) s.Require().Equal(sig.Data.(*signing2.SingleSignatureData).Signature, stdTx.Signatures[0].Signature) @@ -125,7 +134,8 @@ func (s *TestSuite) TestConvertTxToStdTx() { s.Require().Equal(memo, stdTx.Memo) s.Require().Equal(gas, stdTx.Fee.Gas) s.Require().Equal(fee, stdTx.Fee.Amount) - s.Require().Equal(msg, stdTx.Msgs[0]) + s.Require().Equal(msg0, stdTx.Msgs[0]) + s.Require().Equal(msg1, stdTx.Msgs[1]) s.Require().Equal(timeoutHeight, stdTx.TimeoutHeight) s.Require().Empty(stdTx.Signatures) @@ -138,23 +148,6 @@ func (s *TestSuite) TestConvertTxToStdTx() { s.Require().Equal(stdTx, stdTx2) } -func (s *TestSuite) TestConvertAndEncodeStdTx() { - // convert amino -> proto -> amino - aminoBuilder := s.aminoCfg.NewTxBuilder() - buildTestTx(s.T(), aminoBuilder) - stdTx := aminoBuilder.GetTx().(legacytx.StdTx) - txBz, err := tx2.ConvertAndEncodeStdTx(s.protoCfg, stdTx) - s.Require().NoError(err) - decodedTx, err := s.protoCfg.TxDecoder()(txBz) - s.Require().NoError(err) - aminoBuilder2 := s.aminoCfg.NewTxBuilder() - s.Require().NoError(tx2.CopyTx(decodedTx.(signing.Tx), aminoBuilder2, false)) - s.Require().Equal(stdTx, aminoBuilder2.GetTx()) - - // just use amino everywhere - txBz, err = tx2.ConvertAndEncodeStdTx(s.aminoCfg, stdTx) - s.Require().NoError(err) - decodedTx, err = s.aminoCfg.TxDecoder()(txBz) - s.Require().NoError(err) - s.Require().Equal(stdTx, decodedTx) +func TestTestSuite(t *testing.T) { + suite.Run(t, new(TestSuite)) } diff --git a/client/tx/tx.go b/client/tx/tx.go index 4f4addc8f8..4a6229cd7c 100644 --- a/client/tx/tx.go +++ b/client/tx/tx.go @@ -2,11 +2,13 @@ package tx import ( "bufio" + "context" "errors" "fmt" "net/http" "os" + gogogrpc "github.com/gogo/protobuf/grpc" "github.com/spf13/pflag" "github.com/line/lbm-sdk/client" @@ -20,7 +22,6 @@ import ( "github.com/line/lbm-sdk/types/tx" "github.com/line/lbm-sdk/types/tx/signing" authsigning "github.com/line/lbm-sdk/x/auth/signing" - authtx "github.com/line/lbm-sdk/x/auth/tx" ) // GenerateOrBroadcastTxCLI will either generate and print and unsigned transaction @@ -33,6 +34,16 @@ func GenerateOrBroadcastTxCLI(clientCtx client.Context, flagSet *pflag.FlagSet, // GenerateOrBroadcastTxWithFactory will either generate and print and unsigned transaction // or sign it and broadcast it returning an error upon failure. func GenerateOrBroadcastTxWithFactory(clientCtx client.Context, txf Factory, msgs ...sdk.Msg) error { + // Validate all msgs before generating or broadcasting the tx. + // We were calling ValidateBasic separately in each CLI handler before. + // Right now, we're factorizing that call inside this function. + // ref: https://github.com/cosmos/cosmos-sdk/pull/9236#discussion_r623803504 + for _, msg := range msgs { + if err := msg.ValidateBasic(); err != nil { + return err + } + } + if clientCtx.GenerateOnly { return GenerateTx(clientCtx, txf, msgs...) } @@ -50,7 +61,7 @@ func GenerateTx(clientCtx client.Context, txf Factory, msgs ...sdk.Msg) error { return errors.New("cannot estimate gas in offline mode") } - _, adjusted, err := CalculateGas(clientCtx.QueryWithData, txf, msgs...) + _, adjusted, err := CalculateGas(clientCtx, txf, msgs...) if err != nil { return err } @@ -76,13 +87,13 @@ func GenerateTx(clientCtx client.Context, txf Factory, msgs ...sdk.Msg) error { // given set of messages. It will also simulate gas requirements if necessary. // It will return an error upon failure. func BroadcastTx(clientCtx client.Context, txf Factory, msgs ...sdk.Msg) error { - txf, err := PrepareFactory(clientCtx, txf) + txf, err := prepareFactory(clientCtx, txf) if err != nil { return err } if txf.SimulateAndExecute() || clientCtx.Simulate { - _, adjusted, err := CalculateGas(clientCtx.QueryWithData, txf, msgs...) + _, adjusted, err := CalculateGas(clientCtx, txf, msgs...) if err != nil { return err } @@ -142,8 +153,9 @@ func BroadcastTx(clientCtx client.Context, txf Factory, msgs ...sdk.Msg) error { // BaseReq. Upon any error, the error will be written to the http.ResponseWriter. // Note that this function returns the legacy StdTx Amino JSON format for compatibility // with legacy clients. +// Deprecated: We are removing Amino soon. func WriteGeneratedTxResponse( - ctx client.Context, w http.ResponseWriter, br rest.BaseReq, msgs ...sdk.Msg, + clientCtx client.Context, w http.ResponseWriter, br rest.BaseReq, msgs ...sdk.Msg, ) { gasAdj, ok := rest.ParseFloat64OrReturnBadRequest(w, br.GasAdjustment, flags.DefaultGasAdjustment) if !ok { @@ -163,7 +175,7 @@ func WriteGeneratedTxResponse( WithMemo(br.Memo). WithChainID(br.ChainID). WithSimulateAndExecute(br.Simulate). - WithTxConfig(ctx.TxConfig). + WithTxConfig(clientCtx.TxConfig). WithTimeoutHeight(br.TimeoutHeight) if br.Simulate || gasSetting.Simulate { @@ -172,7 +184,7 @@ func WriteGeneratedTxResponse( return } - _, adjusted, err := CalculateGas(ctx.QueryWithData, txf, msgs...) + _, adjusted, err := CalculateGas(clientCtx, txf, msgs...) if rest.CheckInternalServerError(w, err) { return } @@ -180,7 +192,7 @@ func WriteGeneratedTxResponse( txf = txf.WithGas(adjusted) if br.Simulate { - rest.WriteSimulationResponse(w, ctx.LegacyAmino, txf.Gas()) + rest.WriteSimulationResponse(w, clientCtx.LegacyAmino, txf.Gas()) return } } @@ -190,12 +202,12 @@ func WriteGeneratedTxResponse( return } - stdTx, err := ConvertTxToStdTx(ctx.LegacyAmino, tx.GetTx()) + stdTx, err := ConvertTxToStdTx(clientCtx.LegacyAmino, tx.GetTx()) if rest.CheckInternalServerError(w, err) { return } - output, err := ctx.LegacyAmino.MarshalJSON(stdTx) + output, err := clientCtx.LegacyAmino.MarshalJSON(stdTx) if rest.CheckInternalServerError(w, err) { return } @@ -268,46 +280,35 @@ func BuildSimTx(txf Factory, msgs ...sdk.Msg) ([]byte, error) { return nil, err } - protoProvider, ok := txb.(authtx.ProtoTxProvider) - if !ok { - return nil, fmt.Errorf("cannot simulate amino tx") - } - simReq := tx.SimulateRequest{Tx: protoProvider.GetProtoTx()} - - return simReq.Marshal() + return txf.txConfig.TxEncoder()(txb.GetTx()) } // CalculateGas simulates the execution of a transaction and returns the // simulation response obtained by the query and the adjusted gas amount. func CalculateGas( - queryFunc func(string, []byte) ([]byte, int64, error), txf Factory, msgs ...sdk.Msg, -) (tx.SimulateResponse, uint64, error) { + clientCtx gogogrpc.ClientConn, txf Factory, msgs ...sdk.Msg, +) (*tx.SimulateResponse, uint64, error) { txBytes, err := BuildSimTx(txf, msgs...) if err != nil { - return tx.SimulateResponse{}, 0, err + return nil, 0, err } - // TODO This should use the generated tx service Client. - // https://github.com/line/lbm-sdk/issues/7726 - bz, _, err := queryFunc("/lbm.tx.v1.Service/Simulate", txBytes) + txSvcClient := tx.NewServiceClient(clientCtx) + simRes, err := txSvcClient.Simulate(context.Background(), &tx.SimulateRequest{ + TxBytes: txBytes, + }) if err != nil { - return tx.SimulateResponse{}, 0, err - } - - var simRes tx.SimulateResponse - - if err := simRes.Unmarshal(bz); err != nil { - return tx.SimulateResponse{}, 0, err + return nil, 0, err } return simRes, uint64(txf.GasAdjustment() * float64(simRes.GasInfo.GasUsed)), nil } -// PrepareFactory ensures the account defined by ctx.GetFromAddress() exists and +// prepareFactory ensures the account defined by ctx.GetFromAddress() exists and // if the account number and/or the account sequence number are zero (not set), // they will be queried for and set on the provided Factory. A new Factory with // the updated fields will be returned. -func PrepareFactory(clientCtx client.Context, txf Factory) (Factory, error) { +func prepareFactory(clientCtx client.Context, txf Factory) (Factory, error) { from := clientCtx.GetFromAddress() if err := txf.accountRetriever.EnsureExists(clientCtx, from); err != nil { @@ -318,9 +319,7 @@ func PrepareFactory(clientCtx client.Context, txf Factory) (Factory, error) { if initNum == 0 || initSeq == 0 { num, seq, err := txf.accountRetriever.GetAccountNumberSequence(clientCtx, from) if err != nil { - if cliError, ok := err.(*client.Error); !ok || cliError.Code != sdkerrors.ErrKeyNotFound.ABCICode() { - return txf, err - } + return txf, err } if initNum == 0 { diff --git a/client/tx/tx_test.go b/client/tx/tx_test.go index 68e02ff897..a4d155240b 100644 --- a/client/tx/tx_test.go +++ b/client/tx/tx_test.go @@ -1,10 +1,12 @@ package tx_test import ( - "errors" + gocontext "context" + "fmt" "testing" "github.com/stretchr/testify/require" + "google.golang.org/grpc" "github.com/line/lbm-sdk/client" "github.com/line/lbm-sdk/client/tx" @@ -24,30 +26,34 @@ func NewTestTxConfig() client.TxConfig { return cfg.TxConfig } -func TestCalculateGas(t *testing.T) { - makeQueryFunc := func(gasUsed uint64, wantErr bool) func(string, []byte) ([]byte, int64, error) { - return func(string, []byte) ([]byte, int64, error) { - if wantErr { - return nil, 0, errors.New("query failed") - } - simRes := &txtypes.SimulateResponse{ - GasInfo: &sdk.GasInfo{GasUsed: gasUsed, GasWanted: gasUsed}, - Result: &sdk.Result{Data: []byte("tx data"), Log: "log"}, - } +// mockContext is a mock client.Context to return abitrary simulation response, used to +// unit test CalculateGas. +type mockContext struct { + gasUsed uint64 + wantErr bool +} - bz, err := simRes.Marshal() - if err != nil { - return nil, 0, err - } +func (m mockContext) Invoke(grpcCtx gocontext.Context, method string, req, reply interface{}, opts ...grpc.CallOption) (err error) { + if m.wantErr { + return fmt.Errorf("mock err") + } - return bz, 0, nil - } + *(reply.(*txtypes.SimulateResponse)) = txtypes.SimulateResponse{ + GasInfo: &sdk.GasInfo{GasUsed: m.gasUsed, GasWanted: m.gasUsed}, + Result: &sdk.Result{Data: []byte("tx data"), Log: "log"}, } + return nil +} +func (mockContext) NewStream(gocontext.Context, *grpc.StreamDesc, string, ...grpc.CallOption) (grpc.ClientStream, error) { + panic("not implemented") +} + +func TestCalculateGas(t *testing.T) { type args struct { - queryFuncGasUsed uint64 - queryFuncWantErr bool - adjustment float64 + mockGasUsed uint64 + mockWantErr bool + adjustment float64 } testCases := []struct { @@ -70,8 +76,11 @@ func TestCalculateGas(t *testing.T) { WithTxConfig(txCfg).WithSignMode(txCfg.SignModeHandler().DefaultMode()) t.Run(stc.name, func(t *testing.T) { - queryFunc := makeQueryFunc(stc.args.queryFuncGasUsed, stc.args.queryFuncWantErr) - simRes, gotAdjusted, err := tx.CalculateGas(queryFunc, txf.WithGasAdjustment(stc.args.adjustment)) + mockClientCtx := mockContext{ + gasUsed: tc.args.mockGasUsed, + wantErr: tc.args.mockWantErr, + } + simRes, gotAdjusted, err := tx.CalculateGas(mockClientCtx, txf.WithGasAdjustment(stc.args.adjustment)) if stc.expPass { require.NoError(t, err) require.Equal(t, simRes.GasInfo.GasUsed, stc.wantEstimate) @@ -79,7 +88,7 @@ func TestCalculateGas(t *testing.T) { require.NotNil(t, simRes.Result) } else { require.Error(t, err) - require.Nil(t, simRes.Result) + require.Nil(t, simRes) } }) } @@ -132,10 +141,10 @@ func TestSign(t *testing.T) { var from2 = "test_key2" // create a new key using a mnemonic generator and test if we can reuse seed to recreate that account - _, seed, err := kr.NewMnemonic(from1, keyring.English, path, hd.Secp256k1) + _, seed, err := kr.NewMnemonic(from1, keyring.English, path, keyring.DefaultBIP39Passphrase, hd.Secp256k1) requireT.NoError(err) requireT.NoError(kr.Delete(from1)) - info1, _, err := kr.NewMnemonic(from1, keyring.English, path, hd.Secp256k1) + info1, _, err := kr.NewMnemonic(from1, keyring.English, path, keyring.DefaultBIP39Passphrase, hd.Secp256k1) requireT.NoError(err) info2, err := kr.NewAccount(from2, seed, "", path, hd.Secp256k1) diff --git a/client/utils.go b/client/utils.go index 5dc737f3d9..42c8b8b7d3 100644 --- a/client/utils.go +++ b/client/utils.go @@ -52,11 +52,12 @@ func ReadPageRequest(flagSet *pflag.FlagSet) (*query.PageRequest, error) { limit, _ := flagSet.GetUint64(flags.FlagLimit) countTotal, _ := flagSet.GetBool(flags.FlagCountTotal) page, _ := flagSet.GetUint64(flags.FlagPage) + reverse, _ := flagSet.GetBool(flags.FlagReverse) - return NewPageRequest(pageKey, offset, limit, page, countTotal) + return NewPageRequest(pageKey, offset, limit, page, countTotal, reverse) } -func NewPageRequest(pageKey string, offset, limit, page uint64, countTotal bool) (*query.PageRequest, error) { +func NewPageRequest(pageKey string, offset, limit, page uint64, countTotal bool, reverse bool) (*query.PageRequest, error) { if page > 1 && offset > 0 { return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "page and offset cannot be used together") } @@ -70,6 +71,7 @@ func NewPageRequest(pageKey string, offset, limit, page uint64, countTotal bool) Offset: offset, Limit: limit, CountTotal: countTotal, + Reverse: reverse, }, nil } diff --git a/codec/amino.go b/codec/amino.go index 0de9b26299..c6ecebad94 100644 --- a/codec/amino.go +++ b/codec/amino.go @@ -13,8 +13,8 @@ import ( "github.com/line/lbm-sdk/codec/types" ) -// Deprecated: LegacyAmino defines a wrapper for an Amino codec that properly handles protobuf -// types with Any's +// LegacyAmino defines a wrapper for an Amino codec that properly +// handles protobuf types with Any's. Deprecated. type LegacyAmino struct { Amino *amino.Codec } @@ -77,7 +77,7 @@ func (cdc *LegacyAmino) jsonUnmarshalAnys(o interface{}) error { return types.UnpackInterfaces(o, types.AminoJSONUnpacker{Cdc: cdc.Amino}) } -func (cdc *LegacyAmino) MarshalBinaryBare(o interface{}) ([]byte, error) { +func (cdc *LegacyAmino) Marshal(o interface{}) ([]byte, error) { err := cdc.marshalAnys(o) if err != nil { return nil, err @@ -85,15 +85,15 @@ func (cdc *LegacyAmino) MarshalBinaryBare(o interface{}) ([]byte, error) { return cdc.Amino.MarshalBinaryBare(o) } -func (cdc *LegacyAmino) MustMarshalBinaryBare(o interface{}) []byte { - bz, err := cdc.MarshalBinaryBare(o) +func (cdc *LegacyAmino) MustMarshal(o interface{}) []byte { + bz, err := cdc.Marshal(o) if err != nil { panic(err) } return bz } -func (cdc *LegacyAmino) MarshalBinaryLengthPrefixed(o interface{}) ([]byte, error) { +func (cdc *LegacyAmino) MarshalLengthPrefixed(o interface{}) ([]byte, error) { err := cdc.marshalAnys(o) if err != nil { return nil, err @@ -101,15 +101,15 @@ func (cdc *LegacyAmino) MarshalBinaryLengthPrefixed(o interface{}) ([]byte, erro return cdc.Amino.MarshalBinaryLengthPrefixed(o) } -func (cdc *LegacyAmino) MustMarshalBinaryLengthPrefixed(o interface{}) []byte { - bz, err := cdc.MarshalBinaryLengthPrefixed(o) +func (cdc *LegacyAmino) MustMarshalLengthPrefixed(o interface{}) []byte { + bz, err := cdc.MarshalLengthPrefixed(o) if err != nil { panic(err) } return bz } -func (cdc *LegacyAmino) UnmarshalBinaryBare(bz []byte, ptr interface{}) error { +func (cdc *LegacyAmino) Unmarshal(bz []byte, ptr interface{}) error { err := cdc.Amino.UnmarshalBinaryBare(bz, ptr) if err != nil { return err @@ -117,14 +117,14 @@ func (cdc *LegacyAmino) UnmarshalBinaryBare(bz []byte, ptr interface{}) error { return cdc.unmarshalAnys(ptr) } -func (cdc *LegacyAmino) MustUnmarshalBinaryBare(bz []byte, ptr interface{}) { - err := cdc.UnmarshalBinaryBare(bz, ptr) +func (cdc *LegacyAmino) MustUnmarshal(bz []byte, ptr interface{}) { + err := cdc.Unmarshal(bz, ptr) if err != nil { panic(err) } } -func (cdc *LegacyAmino) UnmarshalBinaryLengthPrefixed(bz []byte, ptr interface{}) error { +func (cdc *LegacyAmino) UnmarshalLengthPrefixed(bz []byte, ptr interface{}) error { err := cdc.Amino.UnmarshalBinaryLengthPrefixed(bz, ptr) if err != nil { return err @@ -132,14 +132,14 @@ func (cdc *LegacyAmino) UnmarshalBinaryLengthPrefixed(bz []byte, ptr interface{} return cdc.unmarshalAnys(ptr) } -func (cdc *LegacyAmino) MustUnmarshalBinaryLengthPrefixed(bz []byte, ptr interface{}) { - err := cdc.UnmarshalBinaryLengthPrefixed(bz, ptr) +func (cdc *LegacyAmino) MustUnmarshalLengthPrefixed(bz []byte, ptr interface{}) { + err := cdc.UnmarshalLengthPrefixed(bz, ptr) if err != nil { panic(err) } } -// MarshalJSON implements codec.Marshaler interface +// MarshalJSON implements codec.Codec interface func (cdc *LegacyAmino) MarshalJSON(o interface{}) ([]byte, error) { err := cdc.jsonMarshalAnys(o) if err != nil { @@ -156,7 +156,7 @@ func (cdc *LegacyAmino) MustMarshalJSON(o interface{}) []byte { return bz } -// UnmarshalJSON implements codec.Marshaler interface +// UnmarshalJSON implements codec.Codec interface func (cdc *LegacyAmino) UnmarshalJSON(bz []byte, ptr interface{}) error { err := cdc.Amino.UnmarshalJSON(bz, ptr) if err != nil { diff --git a/codec/amino_codec.go b/codec/amino_codec.go index 3ba7a2feb9..69f4dc133d 100644 --- a/codec/amino_codec.go +++ b/codec/amino_codec.go @@ -10,72 +10,72 @@ type AminoCodec struct { *LegacyAmino } -var _ Marshaler = &AminoCodec{} +var _ Codec = &AminoCodec{} // NewAminoCodec returns a reference to a new AminoCodec func NewAminoCodec(codec *LegacyAmino) *AminoCodec { return &AminoCodec{LegacyAmino: codec} } -// MarshalBinaryBare implements BinaryMarshaler.MarshalBinaryBare method. -func (ac *AminoCodec) MarshalBinaryBare(o ProtoMarshaler) ([]byte, error) { - return ac.LegacyAmino.MarshalBinaryBare(o) +// Marshal implements BinaryMarshaler.Marshal method. +func (ac *AminoCodec) Marshal(o ProtoMarshaler) ([]byte, error) { + return ac.LegacyAmino.Marshal(o) } -// MustMarshalBinaryBare implements BinaryMarshaler.MustMarshalBinaryBare method. -func (ac *AminoCodec) MustMarshalBinaryBare(o ProtoMarshaler) []byte { - return ac.LegacyAmino.MustMarshalBinaryBare(o) +// MustMarshal implements BinaryMarshaler.MustMarshal method. +func (ac *AminoCodec) MustMarshal(o ProtoMarshaler) []byte { + return ac.LegacyAmino.MustMarshal(o) } -// MarshalBinaryLengthPrefixed implements BinaryMarshaler.MarshalBinaryLengthPrefixed method. -func (ac *AminoCodec) MarshalBinaryLengthPrefixed(o ProtoMarshaler) ([]byte, error) { - return ac.LegacyAmino.MarshalBinaryLengthPrefixed(o) +// MarshalLengthPrefixed implements BinaryMarshaler.MarshalLengthPrefixed method. +func (ac *AminoCodec) MarshalLengthPrefixed(o ProtoMarshaler) ([]byte, error) { + return ac.LegacyAmino.MarshalLengthPrefixed(o) } -// MustMarshalBinaryLengthPrefixed implements BinaryMarshaler.MustMarshalBinaryLengthPrefixed method. -func (ac *AminoCodec) MustMarshalBinaryLengthPrefixed(o ProtoMarshaler) []byte { - return ac.LegacyAmino.MustMarshalBinaryLengthPrefixed(o) +// MustMarshalLengthPrefixed implements BinaryMarshaler.MustMarshalLengthPrefixed method. +func (ac *AminoCodec) MustMarshalLengthPrefixed(o ProtoMarshaler) []byte { + return ac.LegacyAmino.MustMarshalLengthPrefixed(o) } -// UnmarshalBinaryBare implements BinaryMarshaler.UnmarshalBinaryBare method. -func (ac *AminoCodec) UnmarshalBinaryBare(bz []byte, ptr ProtoMarshaler) error { - return ac.LegacyAmino.UnmarshalBinaryBare(bz, ptr) +// Unmarshal implements BinaryMarshaler.Unmarshal method. +func (ac *AminoCodec) Unmarshal(bz []byte, ptr ProtoMarshaler) error { + return ac.LegacyAmino.Unmarshal(bz, ptr) } -// MustUnmarshalBinaryBare implements BinaryMarshaler.MustUnmarshalBinaryBare method. -func (ac *AminoCodec) MustUnmarshalBinaryBare(bz []byte, ptr ProtoMarshaler) { - ac.LegacyAmino.MustUnmarshalBinaryBare(bz, ptr) +// MustUnmarshal implements BinaryMarshaler.MustUnmarshal method. +func (ac *AminoCodec) MustUnmarshal(bz []byte, ptr ProtoMarshaler) { + ac.LegacyAmino.MustUnmarshal(bz, ptr) } -// UnmarshalBinaryLengthPrefixed implements BinaryMarshaler.UnmarshalBinaryLengthPrefixed method. -func (ac *AminoCodec) UnmarshalBinaryLengthPrefixed(bz []byte, ptr ProtoMarshaler) error { - return ac.LegacyAmino.UnmarshalBinaryLengthPrefixed(bz, ptr) +// UnmarshalLengthPrefixed implements BinaryMarshaler.UnmarshalLengthPrefixed method. +func (ac *AminoCodec) UnmarshalLengthPrefixed(bz []byte, ptr ProtoMarshaler) error { + return ac.LegacyAmino.UnmarshalLengthPrefixed(bz, ptr) } -// MustUnmarshalBinaryLengthPrefixed implements BinaryMarshaler.MustUnmarshalBinaryLengthPrefixed method. -func (ac *AminoCodec) MustUnmarshalBinaryLengthPrefixed(bz []byte, ptr ProtoMarshaler) { - ac.LegacyAmino.MustUnmarshalBinaryLengthPrefixed(bz, ptr) +// MustUnmarshalLengthPrefixed implements BinaryMarshaler.MustUnmarshalLengthPrefixed method. +func (ac *AminoCodec) MustUnmarshalLengthPrefixed(bz []byte, ptr ProtoMarshaler) { + ac.LegacyAmino.MustUnmarshalLengthPrefixed(bz, ptr) } -// MarshalJSON implements JSONMarshaler.MarshalJSON method, +// MarshalJSON implements JSONCodec.MarshalJSON method, // it marshals to JSON using legacy amino codec. func (ac *AminoCodec) MarshalJSON(o proto.Message) ([]byte, error) { return ac.LegacyAmino.MarshalJSON(o) } -// MustMarshalJSON implements JSONMarshaler.MustMarshalJSON method, +// MustMarshalJSON implements JSONCodec.MustMarshalJSON method, // it executes MarshalJSON except it panics upon failure. func (ac *AminoCodec) MustMarshalJSON(o proto.Message) []byte { return ac.LegacyAmino.MustMarshalJSON(o) } -// UnmarshalJSON implements JSONMarshaler.UnmarshalJSON method, +// UnmarshalJSON implements JSONCodec.UnmarshalJSON method, // it unmarshals from JSON using legacy amino codec. func (ac *AminoCodec) UnmarshalJSON(bz []byte, ptr proto.Message) error { return ac.LegacyAmino.UnmarshalJSON(bz, ptr) } -// MustUnmarshalJSON implements JSONMarshaler.MustUnmarshalJSON method, +// MustUnmarshalJSON implements JSONCodec.MustUnmarshalJSON method, // it executes UnmarshalJSON except it panics upon failure. func (ac *AminoCodec) MustUnmarshalJSON(bz []byte, ptr proto.Message) { ac.LegacyAmino.MustUnmarshalJSON(bz, ptr) @@ -83,23 +83,23 @@ func (ac *AminoCodec) MustUnmarshalJSON(bz []byte, ptr proto.Message) { // MarshalInterface is a convenience function for amino marshaling interfaces. // The `i` must be an interface. -// NOTE: to marshal a concrete type, you should use MarshalBinaryBare instead +// NOTE: to marshal a concrete type, you should use Marshal instead func (ac *AminoCodec) MarshalInterface(i proto.Message) ([]byte, error) { if err := assertNotNil(i); err != nil { return nil, err } - return ac.LegacyAmino.MarshalBinaryBare(i) + return ac.LegacyAmino.Marshal(i) } // UnmarshalInterface is a convenience function for amino unmarshaling interfaces. // `ptr` must be a pointer to an interface. -// NOTE: to unmarshal a concrete type, you should use UnmarshalBinaryBare instead +// NOTE: to unmarshal a concrete type, you should use Unmarshal instead // // Example: // var x MyInterface // err := cdc.UnmarshalInterface(bz, &x) func (ac *AminoCodec) UnmarshalInterface(bz []byte, ptr interface{}) error { - return ac.LegacyAmino.UnmarshalBinaryBare(bz, ptr) + return ac.LegacyAmino.Unmarshal(bz, ptr) } // MarshalInterfaceJSON is a convenience function for amino marshaling interfaces. diff --git a/codec/amino_codec_test.go b/codec/amino_codec_test.go index 7df62adf59..90293cfd7f 100644 --- a/codec/amino_codec_test.go +++ b/codec/amino_codec_test.go @@ -11,7 +11,7 @@ import ( "github.com/line/lbm-sdk/codec/types" "github.com/line/lbm-sdk/simapp" "github.com/line/lbm-sdk/testutil/testdata" - "github.com/line/lbm-sdk/x/auth/client/rest" + "github.com/line/lbm-sdk/x/auth/client/cli" "github.com/line/lbm-sdk/x/auth/legacy/legacytx" ) @@ -120,9 +120,8 @@ func TestAminoCodecUnpackAnyFails(t *testing.T) { func TestAminoCodecFullDecodeAndEncode(t *testing.T) { // This tx comes from https://github.com/cosmos/cosmos-sdk/issues/8117. - txSigned := `{"type":"lbm-sdk/StdTx","value":{"msg":[{"type":"lbm-sdk/MsgCreateValidator","value":{"description":{"moniker":"fulltest","identity":"satoshi","website":"example.com","details":"example inc"},"commission":{"rate":"0.500000000000000000","max_rate":"1.000000000000000000","max_change_rate":"0.200000000000000000"},"min_self_delegation":"1000000","delegator_address":"link120yvjfy7m2gnu9mvusrs40cxxhpt8nr3qhn8re","validator_address":"linkvaloper120yvjfy7m2gnu9mvusrs40cxxhpt8nr3jr36d2","pubkey":{"type":"ostracon/PubKeyEd25519","value":"CYrOiM3HtS7uv1B1OAkknZnFYSRpQYSYII8AtMMtev0="},"value":{"denom":"umuon","amount":"700000000"}}}],"fee":{"amount":[{"denom":"umuon","amount":"6000"}],"gas":"160000"},"signatures":[{"pub_key":{"type":"ostracon/PubKeySecp256k1","value":"AwAOXeWgNf1FjMaayrSnrOOKz+Fivr6DiI/i0x0sZCHw"},"signature":"RcnfS/u2yl7uIShTrSUlDWvsXo2p2dYu6WJC8VDVHMBLEQZWc8bsINSCjOnlsIVkUNNe1q/WCA9n3Gy1+0zhYA=="}],"memo":"","timeout_height":"0"}}` - _, legacyCdc := simapp.MakeCodecs() - + txSigned := `{"type":"lbm-sdk/StdTx","value":{"msg":[{"type":"lbm-sdk/MsgCreateValidator","value":{"description":{"moniker":"fulltest","identity":"satoshi","website":"example.com","details":"example inc"},"commission":{"rate":"0.500000000000000000","max_rate":"1.000000000000000000","max_change_rate":"0.200000000000000000"},"min_self_delegation":"1000000","delegator_address":"link14pt0q5cwf38zt08uu0n6yrstf3rndzr5057jys","validator_address":"linkvaloper14pt0q5cwf38zt08uu0n6yrstf3rndzr52q28gr","pubkey":{"type":"ostracon/PubKeyEd25519","value":"CYrOiM3HtS7uv1B1OAkknZnFYSRpQYSYII8AtMMtev0="},"value":{"denom":"umuon","amount":"700000000"}}}],"fee":{"amount":[{"denom":"umuon","amount":"6000"}],"gas":"160000"},"signatures":[{"pub_key":{"type":"ostracon/PubKeySecp256k1","value":"AwAOXeWgNf1FjMaayrSnrOOKz+Fivr6DiI/i0x0sZCHw"},"signature":"RcnfS/u2yl7uIShTrSUlDWvsXo2p2dYu6WJC8VDVHMBLEQZWc8bsINSCjOnlsIVkUNNe1q/WCA9n3Gy1+0zhYA=="}],"memo":"","timeout_height":"0"}}` + var legacyCdc = simapp.MakeTestEncodingConfig().Amino var tx legacytx.StdTx err := legacyCdc.UnmarshalJSON([]byte(txSigned), &tx) require.NoError(t, err) @@ -133,7 +132,7 @@ func TestAminoCodecFullDecodeAndEncode(t *testing.T) { require.Equal(t, string(marshaledTx), txSigned) // Marshalling/unmarshalling the tx wrapped in a struct should work. - txRequest := &rest.BroadcastReq{ + txRequest := &cli.BroadcastReq{ Mode: "block", Tx: tx, } diff --git a/codec/any_test.go b/codec/any_test.go index a2d726b362..d0a577d431 100644 --- a/codec/any_test.go +++ b/codec/any_test.go @@ -7,6 +7,10 @@ import ( "github.com/line/lbm-sdk/codec" "github.com/line/lbm-sdk/codec/types" + codectypes "github.com/line/lbm-sdk/codec/types" + "github.com/line/lbm-sdk/crypto/keys/ed25519" + cryptotypes "github.com/line/lbm-sdk/crypto/types" + "github.com/line/lbm-sdk/simapp" "github.com/line/lbm-sdk/testutil/testdata" ) @@ -53,3 +57,80 @@ func TestMarshalAny(t *testing.T) { err = cdc.UnmarshalInterface(bz, nil) require.Error(t, err) } + +func TestMarshalProtoPubKey(t *testing.T) { + require := require.New(t) + ccfg := simapp.MakeTestEncodingConfig() + privKey := ed25519.GenPrivKey() + pk := privKey.PubKey() + + // **** test JSON serialization **** + + pkAny, err := codectypes.NewAnyWithValue(pk) + require.NoError(err) + bz, err := ccfg.Marshaler.MarshalJSON(pkAny) + require.NoError(err) + + var pkAny2 codectypes.Any + err = ccfg.Marshaler.UnmarshalJSON(bz, &pkAny2) + require.NoError(err) + // Before getting a cached value we need to unpack it. + // Normally this happens in types which implement UnpackInterfaces + var pkI cryptotypes.PubKey + err = ccfg.InterfaceRegistry.UnpackAny(&pkAny2, &pkI) + require.NoError(err) + var pk2 = pkAny2.GetCachedValue().(cryptotypes.PubKey) + require.True(pk2.Equals(pk)) + + // **** test binary serialization **** + + bz, err = ccfg.Marshaler.Marshal(pkAny) + require.NoError(err) + + var pkAny3 codectypes.Any + err = ccfg.Marshaler.Unmarshal(bz, &pkAny3) + require.NoError(err) + err = ccfg.InterfaceRegistry.UnpackAny(&pkAny3, &pkI) + require.NoError(err) + var pk3 = pkAny3.GetCachedValue().(cryptotypes.PubKey) + require.True(pk3.Equals(pk)) +} + +// TestMarshalProtoInterfacePubKey tests PubKey marshaling using (Un)marshalInterface +// helper functions +func TestMarshalProtoInterfacePubKey(t *testing.T) { + require := require.New(t) + ccfg := simapp.MakeTestEncodingConfig() + privKey := ed25519.GenPrivKey() + pk := privKey.PubKey() + + // **** test JSON serialization **** + + bz, err := ccfg.Marshaler.MarshalInterfaceJSON(pk) + require.NoError(err) + + var pk3 cryptotypes.PubKey + err = ccfg.Marshaler.UnmarshalInterfaceJSON(bz, &pk3) + require.NoError(err) + require.True(pk3.Equals(pk)) + + // ** Check unmarshal using JSONCodec ** + // Unpacking won't work straightforward s Any type + // Any can't implement UnpackInterfacesMessage interface. So Any is not + // automatically unpacked and we won't get a value. + var pkAny codectypes.Any + err = ccfg.Marshaler.UnmarshalJSON(bz, &pkAny) + require.NoError(err) + ifc := pkAny.GetCachedValue() + require.Nil(ifc) + + // **** test binary serialization **** + + bz, err = ccfg.Marshaler.MarshalInterface(pk) + require.NoError(err) + + var pk2 cryptotypes.PubKey + err = ccfg.Marshaler.UnmarshalInterface(bz, &pk2) + require.NoError(err) + require.True(pk2.Equals(pk)) +} diff --git a/codec/codec.go b/codec/codec.go index 007bded4ef..eb6dc5dde0 100644 --- a/codec/codec.go +++ b/codec/codec.go @@ -7,49 +7,76 @@ import ( ) type ( - // Marshaler defines the interface module codecs must implement in order to support - // backwards compatibility with Amino while allowing custom Protobuf-based - // serialization. Note, Amino can still be used without any dependency on - // Protobuf. There are two typical implementations that fulfill this contract: + // Codec defines a functionality for serializing other objects. + // Users can defin a custom Protobuf-based serialization. + // Note, Amino can still be used without any dependency on Protobuf. + // SDK provides to Codec implementations: // // 1. AminoCodec: Provides full Amino serialization compatibility. // 2. ProtoCodec: Provides full Protobuf serialization compatibility. - Marshaler interface { - BinaryMarshaler - JSONMarshaler + Codec interface { + BinaryCodec + JSONCodec } - BinaryMarshaler interface { - MarshalBinaryBare(o ProtoMarshaler) ([]byte, error) - MustMarshalBinaryBare(o ProtoMarshaler) []byte + BinaryCodec interface { + // Marshal returns binary encoding of v. + Marshal(o ProtoMarshaler) ([]byte, error) + // MustMarshal calls Marshal and panics if error is returned. + MustMarshal(o ProtoMarshaler) []byte - MarshalBinaryLengthPrefixed(o ProtoMarshaler) ([]byte, error) - MustMarshalBinaryLengthPrefixed(o ProtoMarshaler) []byte + // MarshalLengthPrefixed returns binary encoding of v with bytes length prefix. + MarshalLengthPrefixed(o ProtoMarshaler) ([]byte, error) + // MustMarshalLengthPrefixed calls MarshalLengthPrefixed and panics if + // error is returned. + MustMarshalLengthPrefixed(o ProtoMarshaler) []byte - UnmarshalBinaryBare(bz []byte, ptr ProtoMarshaler) error - MustUnmarshalBinaryBare(bz []byte, ptr ProtoMarshaler) + // Unmarshal parses the data encoded with Marshal method and stores the result + // in the value pointed to by v. + Unmarshal(bz []byte, ptr ProtoMarshaler) error + // MustUnmarshal calls Unmarshal and panics if error is returned. + MustUnmarshal(bz []byte, ptr ProtoMarshaler) - UnmarshalBinaryLengthPrefixed(bz []byte, ptr ProtoMarshaler) error - MustUnmarshalBinaryLengthPrefixed(bz []byte, ptr ProtoMarshaler) + // Unmarshal parses the data encoded with UnmarshalLengthPrefixed method and stores + // the result in the value pointed to by v. + UnmarshalLengthPrefixed(bz []byte, ptr ProtoMarshaler) error + // MustUnmarshalLengthPrefixed calls UnmarshalLengthPrefixed and panics if error + // is returned. + MustUnmarshalLengthPrefixed(bz []byte, ptr ProtoMarshaler) + // MarshalInterface is a helper method which will wrap `i` into `Any` for correct + // binary interface (de)serialization. MarshalInterface(i proto.Message) ([]byte, error) + // UnmarshalInterface is a helper method which will parse binary enoded data + // into `Any` and unpack any into the `ptr`. It fails if the target interface type + // is not registered in codec, or is not compatible with the serialized data UnmarshalInterface(bz []byte, ptr interface{}) error types.AnyUnpacker } - JSONMarshaler interface { + JSONCodec interface { + // MarshalJSON returns JSON encoding of v. MarshalJSON(o proto.Message) ([]byte, error) + // MustMarshalJSON calls MarshalJSON and panics if error is returned. MustMarshalJSON(o proto.Message) []byte + // MarshalInterfaceJSON is a helper method which will wrap `i` into `Any` for correct + // JSON interface (de)serialization. MarshalInterfaceJSON(i proto.Message) ([]byte, error) + // UnmarshalInterfaceJSON is a helper method which will parse JSON enoded data + // into `Any` and unpack any into the `ptr`. It fails if the target interface type + // is not registered in codec, or is not compatible with the serialized data UnmarshalInterfaceJSON(bz []byte, ptr interface{}) error + // UnmarshalJSON parses the data encoded with MarshalJSON method and stores the result + // in the value pointed to by v. UnmarshalJSON(bz []byte, ptr proto.Message) error + // MustUnmarshalJSON calls Unmarshal and panics if error is returned. MustUnmarshalJSON(bz []byte, ptr proto.Message) } - // ProtoMarshaler defines an interface a type must implement as protocol buffer - // defined message. + // ProtoMarshaler defines an interface a type must implement to serialize itself + // as a protocol buffer defined message. ProtoMarshaler interface { proto.Message // for JSON serialization @@ -60,8 +87,8 @@ type ( Unmarshal(data []byte) error } - // AminoMarshaler defines an interface where Amino marshalling can be - // overridden by custom marshalling. + // AminoMarshaler defines an interface a type must implement to serialize itself + // for Amino codec. AminoMarshaler interface { MarshalAmino() ([]byte, error) UnmarshalAmino([]byte) error diff --git a/codec/codec_common_test.go b/codec/codec_common_test.go index 1c15dedfee..96c8f86dd3 100644 --- a/codec/codec_common_test.go +++ b/codec/codec_common_test.go @@ -87,7 +87,7 @@ func testMarshalingTestCase(require *require.Assertions, tc testCase, m mustMars } } -func testMarshaling(t *testing.T, cdc codec.Marshaler) { +func testMarshaling(t *testing.T, cdc codec.Codec) { any, err := types.NewAnyWithValue(&testdata.Dog{Name: "rufus"}) require.NoError(t, err) @@ -117,8 +117,8 @@ func testMarshaling(t *testing.T, cdc codec.Marshaler) { for _, tc := range testCases { tc := tc - m1 := mustMarshaler{cdc.MarshalBinaryBare, cdc.MustMarshalBinaryBare, cdc.UnmarshalBinaryBare, cdc.MustUnmarshalBinaryBare} - m2 := mustMarshaler{cdc.MarshalBinaryLengthPrefixed, cdc.MustMarshalBinaryLengthPrefixed, cdc.UnmarshalBinaryLengthPrefixed, cdc.MustUnmarshalBinaryLengthPrefixed} + m1 := mustMarshaler{cdc.Marshal, cdc.MustMarshal, cdc.Unmarshal, cdc.MustUnmarshal} + m2 := mustMarshaler{cdc.MarshalLengthPrefixed, cdc.MustMarshalLengthPrefixed, cdc.UnmarshalLengthPrefixed, cdc.MustUnmarshalLengthPrefixed} m3 := mustMarshaler{ func(i codec.ProtoMarshaler) ([]byte, error) { return cdc.MarshalJSON(i) }, func(i codec.ProtoMarshaler) []byte { return cdc.MustMarshalJSON(i) }, diff --git a/codec/json.go b/codec/json.go index 04f29b5fb4..e631387d6f 100644 --- a/codec/json.go +++ b/codec/json.go @@ -3,25 +3,29 @@ package codec import ( "bytes" - "github.com/line/lbm-sdk/codec/types" - "github.com/gogo/protobuf/jsonpb" "github.com/gogo/protobuf/proto" + + "github.com/line/lbm-sdk/codec/types" ) +var defaultJM = &jsonpb.Marshaler{OrigName: true, EmitDefaults: true, AnyResolver: nil} + // ProtoMarshalJSON provides an auxiliary function to return Proto3 JSON encoded // bytes of a message. func ProtoMarshalJSON(msg proto.Message, resolver jsonpb.AnyResolver) ([]byte, error) { // We use the OrigName because camel casing fields just doesn't make sense. // EmitDefaults is also often the more expected behavior for CLI users - jm := &jsonpb.Marshaler{OrigName: true, EmitDefaults: true, AnyResolver: resolver} + jm := defaultJM + if resolver != nil { + jm = &jsonpb.Marshaler{OrigName: true, EmitDefaults: true, AnyResolver: resolver} + } err := types.UnpackInterfaces(msg, types.ProtoJSONPacker{JSONPBMarshaler: jm}) if err != nil { return nil, err } buf := new(bytes.Buffer) - if err := jm.Marshal(buf, msg); err != nil { return nil, err } diff --git a/codec/legacy/codec.go b/codec/legacy/codec.go index 83daa1c354..4b2ec9595c 100644 --- a/codec/legacy/codec.go +++ b/codec/legacy/codec.go @@ -20,12 +20,12 @@ func init() { // PrivKeyFromBytes unmarshals private key bytes and returns a PrivKey func PrivKeyFromBytes(privKeyBytes []byte) (privKey cryptotypes.PrivKey, err error) { - err = Cdc.UnmarshalBinaryBare(privKeyBytes, &privKey) + err = Cdc.Unmarshal(privKeyBytes, &privKey) return } // PubKeyFromBytes unmarshals public key bytes and returns a PubKey func PubKeyFromBytes(pubKeyBytes []byte) (pubKey cryptotypes.PubKey, err error) { - err = Cdc.UnmarshalBinaryBare(pubKeyBytes, &pubKey) + err = Cdc.Unmarshal(pubKeyBytes, &pubKey) return } diff --git a/codec/proto_codec.go b/codec/proto_codec.go index 4dc8c6ddce..b704130d25 100644 --- a/codec/proto_codec.go +++ b/codec/proto_codec.go @@ -15,7 +15,7 @@ import ( // ProtoCodecMarshaler defines an interface for codecs that utilize Protobuf for both // binary and JSON encoding. type ProtoCodecMarshaler interface { - Marshaler + Codec InterfaceRegistry() types.InterfaceRegistry } @@ -25,7 +25,7 @@ type ProtoCodec struct { interfaceRegistry types.InterfaceRegistry } -var _ Marshaler = &ProtoCodec{} +var _ Codec = &ProtoCodec{} var _ ProtoCodecMarshaler = &ProtoCodec{} // NewProtoCodec returns a reference to a new ProtoCodec @@ -33,14 +33,18 @@ func NewProtoCodec(interfaceRegistry types.InterfaceRegistry) *ProtoCodec { return &ProtoCodec{interfaceRegistry: interfaceRegistry} } -// MarshalBinaryBare implements BinaryMarshaler.MarshalBinaryBare method. -func (pc *ProtoCodec) MarshalBinaryBare(o ProtoMarshaler) ([]byte, error) { +// Marshal implements BinaryMarshaler.Marshal method. +// NOTE: this function must be used with a concrete type which +// implements proto.Message. For interface please use the codec.MarshalInterface +func (pc *ProtoCodec) Marshal(o ProtoMarshaler) ([]byte, error) { return o.Marshal() } -// MustMarshalBinaryBare implements BinaryMarshaler.MustMarshalBinaryBare method. -func (pc *ProtoCodec) MustMarshalBinaryBare(o ProtoMarshaler) []byte { - bz, err := pc.MarshalBinaryBare(o) +// MustMarshal implements BinaryMarshaler.MustMarshal method. +// NOTE: this function must be used with a concrete type which +// implements proto.Message. For interface please use the codec.MarshalInterface +func (pc *ProtoCodec) MustMarshal(o ProtoMarshaler) []byte { + bz, err := pc.Marshal(o) if err != nil { panic(err) } @@ -48,9 +52,9 @@ func (pc *ProtoCodec) MustMarshalBinaryBare(o ProtoMarshaler) []byte { return bz } -// MarshalBinaryLengthPrefixed implements BinaryMarshaler.MarshalBinaryLengthPrefixed method. -func (pc *ProtoCodec) MarshalBinaryLengthPrefixed(o ProtoMarshaler) ([]byte, error) { - bz, err := pc.MarshalBinaryBare(o) +// MarshalLengthPrefixed implements BinaryMarshaler.MarshalLengthPrefixed method. +func (pc *ProtoCodec) MarshalLengthPrefixed(o ProtoMarshaler) ([]byte, error) { + bz, err := pc.Marshal(o) if err != nil { return nil, err } @@ -60,9 +64,9 @@ func (pc *ProtoCodec) MarshalBinaryLengthPrefixed(o ProtoMarshaler) ([]byte, err return append(sizeBuf[:n], bz...), nil } -// MustMarshalBinaryLengthPrefixed implements BinaryMarshaler.MustMarshalBinaryLengthPrefixed method. -func (pc *ProtoCodec) MustMarshalBinaryLengthPrefixed(o ProtoMarshaler) []byte { - bz, err := pc.MarshalBinaryLengthPrefixed(o) +// MustMarshalLengthPrefixed implements BinaryMarshaler.MustMarshalLengthPrefixed method. +func (pc *ProtoCodec) MustMarshalLengthPrefixed(o ProtoMarshaler) []byte { + bz, err := pc.MarshalLengthPrefixed(o) if err != nil { panic(err) } @@ -70,8 +74,10 @@ func (pc *ProtoCodec) MustMarshalBinaryLengthPrefixed(o ProtoMarshaler) []byte { return bz } -// UnmarshalBinaryBare implements BinaryMarshaler.UnmarshalBinaryBare method. -func (pc *ProtoCodec) UnmarshalBinaryBare(bz []byte, ptr ProtoMarshaler) error { +// Unmarshal implements BinaryMarshaler.Unmarshal method. +// NOTE: this function must be used with a concrete type which +// implements proto.Message. For interface please use the codec.UnmarshalInterface +func (pc *ProtoCodec) Unmarshal(bz []byte, ptr ProtoMarshaler) error { err := ptr.Unmarshal(bz) if err != nil { return err @@ -83,15 +89,17 @@ func (pc *ProtoCodec) UnmarshalBinaryBare(bz []byte, ptr ProtoMarshaler) error { return nil } -// MustUnmarshalBinaryBare implements BinaryMarshaler.MustUnmarshalBinaryBare method. -func (pc *ProtoCodec) MustUnmarshalBinaryBare(bz []byte, ptr ProtoMarshaler) { - if err := pc.UnmarshalBinaryBare(bz, ptr); err != nil { +// MustUnmarshal implements BinaryMarshaler.MustUnmarshal method. +// NOTE: this function must be used with a concrete type which +// implements proto.Message. For interface please use the codec.UnmarshalInterface +func (pc *ProtoCodec) MustUnmarshal(bz []byte, ptr ProtoMarshaler) { + if err := pc.Unmarshal(bz, ptr); err != nil { panic(err) } } -// UnmarshalBinaryLengthPrefixed implements BinaryMarshaler.UnmarshalBinaryLengthPrefixed method. -func (pc *ProtoCodec) UnmarshalBinaryLengthPrefixed(bz []byte, ptr ProtoMarshaler) error { +// UnmarshalLengthPrefixed implements BinaryMarshaler.UnmarshalLengthPrefixed method. +func (pc *ProtoCodec) UnmarshalLengthPrefixed(bz []byte, ptr ProtoMarshaler) error { size, n := binary.Uvarint(bz) if n < 0 { return fmt.Errorf("invalid number of bytes read from length-prefixed encoding: %d", n) @@ -104,18 +112,20 @@ func (pc *ProtoCodec) UnmarshalBinaryLengthPrefixed(bz []byte, ptr ProtoMarshale } bz = bz[n:] - return pc.UnmarshalBinaryBare(bz, ptr) + return pc.Unmarshal(bz, ptr) } -// MustUnmarshalBinaryLengthPrefixed implements BinaryMarshaler.MustUnmarshalBinaryLengthPrefixed method. -func (pc *ProtoCodec) MustUnmarshalBinaryLengthPrefixed(bz []byte, ptr ProtoMarshaler) { - if err := pc.UnmarshalBinaryLengthPrefixed(bz, ptr); err != nil { +// MustUnmarshalLengthPrefixed implements BinaryMarshaler.MustUnmarshalLengthPrefixed method. +func (pc *ProtoCodec) MustUnmarshalLengthPrefixed(bz []byte, ptr ProtoMarshaler) { + if err := pc.UnmarshalLengthPrefixed(bz, ptr); err != nil { panic(err) } } -// MarshalJSON implements JSONMarshaler.MarshalJSON method, +// MarshalJSON implements JSONCodec.MarshalJSON method, // it marshals to JSON using proto codec. +// NOTE: this function must be used with a concrete type which +// implements proto.Message. For interface please use the codec.MarshalInterfaceJSON func (pc *ProtoCodec) MarshalJSON(o proto.Message) ([]byte, error) { m, ok := o.(ProtoMarshaler) if !ok { @@ -125,8 +135,10 @@ func (pc *ProtoCodec) MarshalJSON(o proto.Message) ([]byte, error) { return ProtoMarshalJSON(m, pc.interfaceRegistry) } -// MustMarshalJSON implements JSONMarshaler.MustMarshalJSON method, +// MustMarshalJSON implements JSONCodec.MustMarshalJSON method, // it executes MarshalJSON except it panics upon failure. +// NOTE: this function must be used with a concrete type which +// implements proto.Message. For interface please use the codec.MarshalInterfaceJSON func (pc *ProtoCodec) MustMarshalJSON(o proto.Message) []byte { bz, err := pc.MarshalJSON(o) if err != nil { @@ -136,8 +148,10 @@ func (pc *ProtoCodec) MustMarshalJSON(o proto.Message) []byte { return bz } -// UnmarshalJSON implements JSONMarshaler.UnmarshalJSON method, +// UnmarshalJSON implements JSONCodec.UnmarshalJSON method, // it unmarshals from JSON using proto codec. +// NOTE: this function must be used with a concrete type which +// implements proto.Message. For interface please use the codec.UnmarshalInterfaceJSON func (pc *ProtoCodec) UnmarshalJSON(bz []byte, ptr proto.Message) error { m, ok := ptr.(ProtoMarshaler) if !ok { @@ -153,8 +167,10 @@ func (pc *ProtoCodec) UnmarshalJSON(bz []byte, ptr proto.Message) error { return types.UnpackInterfaces(ptr, pc.interfaceRegistry) } -// MustUnmarshalJSON implements JSONMarshaler.MustUnmarshalJSON method, +// MustUnmarshalJSON implements JSONCodec.MustUnmarshalJSON method, // it executes UnmarshalJSON except it panics upon failure. +// NOTE: this function must be used with a concrete type which +// implements proto.Message. For interface please use the codec.UnmarshalInterfaceJSON func (pc *ProtoCodec) MustUnmarshalJSON(bz []byte, ptr proto.Message) { if err := pc.UnmarshalJSON(bz, ptr); err != nil { panic(err) @@ -163,7 +179,7 @@ func (pc *ProtoCodec) MustUnmarshalJSON(bz []byte, ptr proto.Message) { // MarshalInterface is a convenience function for proto marshalling interfaces. It packs // the provided value, which must be an interface, in an Any and then marshals it to bytes. -// NOTE: to marshal a concrete type, you should use MarshalBinaryBare instead +// NOTE: to marshal a concrete type, you should use Marshal instead func (pc *ProtoCodec) MarshalInterface(i proto.Message) ([]byte, error) { if err := assertNotNil(i); err != nil { return nil, err @@ -173,20 +189,20 @@ func (pc *ProtoCodec) MarshalInterface(i proto.Message) ([]byte, error) { return nil, err } - return pc.MarshalBinaryBare(any) + return pc.Marshal(any) } // UnmarshalInterface is a convenience function for proto unmarshaling interfaces. It // unmarshals an Any from bz bytes and then unpacks it to the `ptr`, which must // be a pointer to a non empty interface with registered implementations. -// NOTE: to unmarshal a concrete type, you should use UnmarshalBinaryBare instead +// NOTE: to unmarshal a concrete type, you should use Unmarshal instead // // Example: // var x MyInterface // err := cdc.UnmarshalInterface(bz, &x) func (pc *ProtoCodec) UnmarshalInterface(bz []byte, ptr interface{}) error { any := &types.Any{} - err := pc.UnmarshalBinaryBare(bz, any) + err := pc.Unmarshal(bz, any) if err != nil { return err } @@ -229,6 +245,7 @@ func (pc *ProtoCodec) UnpackAny(any *types.Any, iface interface{}) error { return pc.interfaceRegistry.UnpackAny(any, iface) } +// InterfaceRegistry returns InterfaceRegistry func (pc *ProtoCodec) InterfaceRegistry() types.InterfaceRegistry { return pc.interfaceRegistry } diff --git a/codec/proto_codec_test.go b/codec/proto_codec_test.go index 0acf7a29a6..0d8cae52ad 100644 --- a/codec/proto_codec_test.go +++ b/codec/proto_codec_test.go @@ -46,11 +46,11 @@ func (lpm *lyingProtoMarshaler) Size() int { return lpm.falseSize } -func TestProtoCodecUnmarshalBinaryLengthPrefixedChecks(t *testing.T) { +func TestProtoCodecUnmarshalLengthPrefixedChecks(t *testing.T) { cdc := codec.NewProtoCodec(createTestInterfaceRegistry()) truth := &testdata.Cat{Lives: 9, Moniker: "glowing"} - realSize := len(cdc.MustMarshalBinaryBare(truth)) + realSize := len(cdc.MustMarshal(truth)) falseSizes := []int{ 100, @@ -66,10 +66,10 @@ func TestProtoCodecUnmarshalBinaryLengthPrefixedChecks(t *testing.T) { falseSize: falseSize, } var serialized []byte - require.NotPanics(t, func() { serialized = cdc.MustMarshalBinaryLengthPrefixed(lpm) }) + require.NotPanics(t, func() { serialized = cdc.MustMarshalLengthPrefixed(lpm) }) recv := new(testdata.Cat) - gotErr := cdc.UnmarshalBinaryLengthPrefixed(serialized, recv) + gotErr := cdc.UnmarshalLengthPrefixed(serialized, recv) var wantErr error if falseSize > realSize { wantErr = fmt.Errorf("not enough bytes to read; want: %d, got: %d", falseSize, realSize) @@ -83,10 +83,10 @@ func TestProtoCodecUnmarshalBinaryLengthPrefixedChecks(t *testing.T) { t.Run("Crafted bad uvarint size", func(t *testing.T) { crafted := []byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f} recv := new(testdata.Cat) - gotErr := cdc.UnmarshalBinaryLengthPrefixed(crafted, recv) + gotErr := cdc.UnmarshalLengthPrefixed(crafted, recv) require.Equal(t, gotErr, errors.New("invalid number of bytes read from length-prefixed encoding: -10")) - require.Panics(t, func() { cdc.MustUnmarshalBinaryLengthPrefixed(crafted, recv) }) + require.Panics(t, func() { cdc.MustUnmarshalLengthPrefixed(crafted, recv) }) }) } @@ -98,7 +98,7 @@ func mustAny(msg proto.Message) *types.Any { return any } -func BenchmarkProtoCodecMarshalBinaryLengthPrefixed(b *testing.B) { +func BenchmarkProtoCodecMarshalLengthPrefixed(b *testing.B) { var pCdc = codec.NewProtoCodec(types.NewInterfaceRegistry()) var msg = &testdata.HasAnimal{ X: 1000, @@ -124,7 +124,7 @@ func BenchmarkProtoCodecMarshalBinaryLengthPrefixed(b *testing.B) { b.ReportAllocs() for i := 0; i < b.N; i++ { - blob, err := pCdc.MarshalBinaryLengthPrefixed(msg) + blob, err := pCdc.MarshalLengthPrefixed(msg) if err != nil { b.Fatal(err) } diff --git a/codec/types/any.go b/codec/types/any.go index 96680fdfa4..b7cfe35122 100644 --- a/codec/types/any.go +++ b/codec/types/any.go @@ -1,6 +1,8 @@ package types import ( + fmt "fmt" + "github.com/gogo/protobuf/proto" sdkerrors "github.com/line/lbm-sdk/types/errors" @@ -62,20 +64,14 @@ func NewAnyWithValue(v proto.Message) (*Any, error) { if v == nil { return nil, sdkerrors.Wrap(sdkerrors.ErrPackAny, "Expecting non nil value to create a new Any") } - return NewAnyWithCustomTypeURL(v, "/"+proto.MessageName(v)) -} -// NewAnyWithCustomTypeURL same as NewAnyWithValue, but sets a custom type url, instead -// using the one from proto.Message. -// NOTE: This functions should be only used for types with additional logic bundled -// into the protobuf Any serialization. For simple marshaling you should use NewAnyWithValue. -func NewAnyWithCustomTypeURL(v proto.Message, typeURL string) (*Any, error) { bz, err := proto.Marshal(v) if err != nil { return nil, err } + return &Any{ - TypeUrl: typeURL, + TypeUrl: "/" + proto.MessageName(v), Value: bz, cachedValue: v, }, nil @@ -117,7 +113,25 @@ func (any *Any) GetCachedValue() interface{} { return any.cachedValue } -// ClearCachedValue clears the cached value from the Any -func (any *Any) ClearCachedValue() { - any.cachedValue = nil +// GoString returns a string representing valid go code to reproduce the current state of +// the struct. +func (any *Any) GoString() string { + if any == nil { + return "nil" + } + extra := "" + if any.XXX_unrecognized != nil { + extra = fmt.Sprintf(",\n XXX_unrecognized: %#v,\n", any.XXX_unrecognized) + } + return fmt.Sprintf("&Any{TypeUrl: %#v,\n Value: %#v%s\n}", + any.TypeUrl, any.Value, extra) +} + +// String implements the stringer interface +func (any *Any) String() string { + if any == nil { + return "nil" + } + return fmt.Sprintf("&Any{TypeUrl:%v,Value:%v,XXX_unrecognized:%v}", + any.TypeUrl, any.Value, any.XXX_unrecognized) } diff --git a/codec/types/any.pb.go b/codec/types/any.pb.go index 94cf802162..cb904a5af4 100644 --- a/codec/types/any.pb.go +++ b/codec/types/any.pb.go @@ -11,8 +11,6 @@ import ( io "io" math "math" math_bits "math/bits" - reflect "reflect" - strings "strings" ) // Reference imports to suppress errors if they are not otherwise used. @@ -82,22 +80,23 @@ func init() { func init() { proto.RegisterFile("google/protobuf/any.proto", fileDescriptor_b53526c13ae22eb4) } var fileDescriptor_b53526c13ae22eb4 = []byte{ - // 235 bytes of a gzipped FileDescriptorProto + // 248 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0x4c, 0xcf, 0xcf, 0x4f, 0xcf, 0x49, 0xd5, 0x2f, 0x28, 0xca, 0x2f, 0xc9, 0x4f, 0x2a, 0x4d, 0xd3, 0x4f, 0xcc, 0xab, 0xd4, 0x03, 0x73, 0x84, 0xf8, 0x21, 0x52, 0x7a, 0x30, 0x29, 0x29, 0x91, 0xf4, 0xfc, 0xf4, 0x7c, 0x30, - 0x4f, 0x1f, 0xc4, 0x82, 0x48, 0x28, 0xd9, 0x70, 0x31, 0x3b, 0xe6, 0x55, 0x0a, 0x49, 0x72, 0x71, + 0x4f, 0x1f, 0xc4, 0x82, 0x48, 0x28, 0x79, 0x70, 0x31, 0x3b, 0xe6, 0x55, 0x0a, 0x49, 0x72, 0x71, 0x94, 0x54, 0x16, 0xa4, 0xc6, 0x97, 0x16, 0xe5, 0x48, 0x30, 0x2a, 0x30, 0x6a, 0x70, 0x06, 0xb1, 0x83, 0xf8, 0xa1, 0x45, 0x39, 0x42, 0x22, 0x5c, 0xac, 0x65, 0x89, 0x39, 0xa5, 0xa9, 0x12, 0x4c, - 0x0a, 0x8c, 0x1a, 0x3c, 0x41, 0x10, 0x8e, 0x15, 0xcb, 0x87, 0x85, 0xf2, 0x0c, 0x4e, 0xcd, 0x8c, - 0x37, 0x1e, 0xca, 0x31, 0x7c, 0x78, 0x28, 0xc7, 0xf8, 0xe3, 0xa1, 0x1c, 0x63, 0xc3, 0x23, 0x39, - 0xc6, 0x15, 0x8f, 0xe4, 0x18, 0x4f, 0x3c, 0x92, 0x63, 0xbc, 0xf0, 0x48, 0x8e, 0xf1, 0xc1, 0x23, - 0x39, 0xc6, 0x17, 0x8f, 0xe4, 0x18, 0x3e, 0x80, 0xc4, 0x1f, 0xcb, 0x31, 0x1e, 0x78, 0x2c, 0xc7, - 0x70, 0xe2, 0xb1, 0x1c, 0x23, 0x97, 0x70, 0x72, 0x7e, 0xae, 0x1e, 0x9a, 0xfb, 0x9c, 0x38, 0x1c, - 0xf3, 0x2a, 0x03, 0x40, 0x9c, 0x00, 0xc6, 0x28, 0x56, 0x90, 0xe5, 0xc5, 0x8b, 0x98, 0x98, 0xdd, - 0x03, 0x9c, 0x56, 0x31, 0xc9, 0xb9, 0x43, 0x94, 0x06, 0x40, 0x95, 0xea, 0x85, 0xa7, 0xe6, 0xe4, - 0x78, 0xe7, 0xe5, 0x97, 0xe7, 0x85, 0x80, 0x94, 0x25, 0xb1, 0x81, 0xcd, 0x30, 0x06, 0x04, 0x00, - 0x00, 0xff, 0xff, 0xe6, 0xfb, 0xa0, 0x21, 0x0e, 0x01, 0x00, 0x00, + 0x0a, 0x8c, 0x1a, 0x3c, 0x41, 0x10, 0x8e, 0x95, 0xc0, 0x8c, 0x05, 0xf2, 0x0c, 0x1b, 0x16, 0xc8, + 0x33, 0x7c, 0x58, 0x28, 0xcf, 0xd0, 0x70, 0x47, 0x81, 0xc1, 0xa9, 0x99, 0xf1, 0xc6, 0x43, 0x39, + 0x86, 0x0f, 0x0f, 0xe5, 0x18, 0x7f, 0x3c, 0x94, 0x63, 0x6c, 0x78, 0x24, 0xc7, 0xb8, 0xe2, 0x91, + 0x1c, 0xe3, 0x89, 0x47, 0x72, 0x8c, 0x17, 0x1e, 0xc9, 0x31, 0x3e, 0x78, 0x24, 0xc7, 0xf8, 0xe2, + 0x91, 0x1c, 0xc3, 0x07, 0x90, 0xf8, 0x63, 0x39, 0xc6, 0x03, 0x8f, 0xe5, 0x18, 0x4e, 0x3c, 0x96, + 0x63, 0xe4, 0x12, 0x4e, 0xce, 0xcf, 0xd5, 0x43, 0x73, 0xab, 0x13, 0x87, 0x63, 0x5e, 0x65, 0x00, + 0x88, 0x13, 0xc0, 0x18, 0xc5, 0x0a, 0x72, 0x48, 0xf1, 0x22, 0x26, 0x66, 0xf7, 0x00, 0xa7, 0x55, + 0x4c, 0x72, 0xee, 0x10, 0xa5, 0x01, 0x50, 0xa5, 0x7a, 0xe1, 0xa9, 0x39, 0x39, 0xde, 0x79, 0xf9, + 0xe5, 0x79, 0x21, 0x20, 0x65, 0x49, 0x6c, 0x60, 0x33, 0x8c, 0x01, 0x01, 0x00, 0x00, 0xff, 0xff, + 0x4d, 0x91, 0x00, 0xa0, 0x1a, 0x01, 0x00, 0x00, } func (this *Any) Compare(that interface{}) int { @@ -169,28 +168,6 @@ func (this *Any) Equal(that interface{}) bool { } return true } -func (this *Any) GoString() string { - if this == nil { - return "nil" - } - s := make([]string, 0, 6) - s = append(s, "&types.Any{") - s = append(s, "TypeUrl: "+fmt.Sprintf("%#v", this.TypeUrl)+",\n") - s = append(s, "Value: "+fmt.Sprintf("%#v", this.Value)+",\n") - if this.XXX_unrecognized != nil { - s = append(s, "XXX_unrecognized:"+fmt.Sprintf("%#v", this.XXX_unrecognized)+",\n") - } - s = append(s, "}") - return strings.Join(s, "") -} -func valueToGoStringAny(v interface{}, typ string) string { - rv := reflect.ValueOf(v) - if rv.IsNil() { - return "nil" - } - pv := reflect.Indirect(rv).Interface() - return fmt.Sprintf("func(v %v) *%v { return &v } ( %#v )", typ, typ, pv) -} func (m *Any) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -355,26 +332,6 @@ func sovAny(x uint64) (n int) { func sozAny(x uint64) (n int) { return sovAny(uint64((x << 1) ^ uint64((int64(x) >> 63)))) } -func (this *Any) String() string { - if this == nil { - return "nil" - } - s := strings.Join([]string{`&Any{`, - `TypeUrl:` + fmt.Sprintf("%v", this.TypeUrl) + `,`, - `Value:` + fmt.Sprintf("%v", this.Value) + `,`, - `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, - `}`, - }, "") - return s -} -func valueToStringAny(v interface{}) string { - rv := reflect.ValueOf(v) - if rv.IsNil() { - return "nil" - } - pv := reflect.Indirect(rv).Interface() - return fmt.Sprintf("*%v", pv) -} func (m *Any) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 diff --git a/codec/types/any_internal_test.go b/codec/types/any_internal_test.go new file mode 100644 index 0000000000..b3e847965d --- /dev/null +++ b/codec/types/any_internal_test.go @@ -0,0 +1,65 @@ +package types + +import ( + "testing" + + "github.com/gogo/protobuf/proto" + "github.com/stretchr/testify/require" +) + +type Dog struct { + Name string `protobuf:"bytes,1,opt,name=size,proto3" json:"size,omitempty"` +} + +func (d Dog) Greet() string { return d.Name } + +// We implement a minimal proto.Message interface +func (d *Dog) Reset() { d.Name = "" } +func (d *Dog) String() string { return d.Name } +func (d *Dog) ProtoMessage() {} +func (d *Dog) XXX_MessageName() string { return "tests/dog" } + +type Animal interface { + Greet() string +} + +var _ Animal = (*Dog)(nil) +var _ proto.Message = (*Dog)(nil) + +func TestAnyPackUnpack(t *testing.T) { + registry := NewInterfaceRegistry() + registry.RegisterInterface("Animal", (*Animal)(nil)) + registry.RegisterImplementations( + (*Animal)(nil), + &Dog{}, + ) + + spot := &Dog{Name: "Spot"} + var animal Animal + + // with cache + any, err := NewAnyWithValue(spot) + require.NoError(t, err) + require.Equal(t, spot, any.GetCachedValue()) + err = registry.UnpackAny(any, &animal) + require.NoError(t, err) + require.Equal(t, spot, animal) + + // without cache + any.cachedValue = nil + err = registry.UnpackAny(any, &animal) + require.NoError(t, err) + require.Equal(t, spot, animal) +} + +func TestString(t *testing.T) { + require := require.New(t) + spot := &Dog{Name: "Spot"} + any, err := NewAnyWithValue(spot) + require.NoError(err) + + require.Equal("&Any{TypeUrl:/tests/dog,Value:[10 4 83 112 111 116],XXX_unrecognized:[]}", any.String()) + require.Equal(`&Any{TypeUrl: "/tests/dog", + Value: []byte{0xa, 0x4, 0x53, 0x70, 0x6f, 0x74} +}`, any.GoString()) +} diff --git a/codec/types/any_test.go b/codec/types/any_test.go index fb80e8bc57..9a5d994193 100644 --- a/codec/types/any_test.go +++ b/codec/types/any_test.go @@ -24,8 +24,6 @@ func (eom *errOnMarshal) XXX_Marshal(b []byte, deterministic bool) ([]byte, erro return nil, errAlways } -const fauxURL = "/anyhere" - var eom = &errOnMarshal{} // Ensure that returning an error doesn't suddenly allocate and waste bytes. @@ -35,7 +33,7 @@ func TestNewAnyWithCustomTypeURLWithErrorNoAllocation(t *testing.T) { debug.SetGCPercent(-1) // disable gc. See the comments below for reasons. runtime.ReadMemStats(&ms1) - any, err := types.NewAnyWithCustomTypeURL(eom, fauxURL) + any, err := types.NewAnyWithValue(eom) runtime.ReadMemStats(&ms2) debug.SetGCPercent(100) // resume gc // Ensure that no fresh allocation was made. @@ -59,7 +57,7 @@ func BenchmarkNewAnyWithCustomTypeURLWithErrorReturned(b *testing.B) { b.ResetTimer() b.ReportAllocs() for i := 0; i < b.N; i++ { - any, err := types.NewAnyWithCustomTypeURL(eom, fauxURL) + any, err := types.NewAnyWithValue(eom) if err == nil { b.Fatal("err wasn't returned") } diff --git a/codec/types/compat.go b/codec/types/compat.go index 5cd372dc73..1de7828491 100644 --- a/codec/types/compat.go +++ b/codec/types/compat.go @@ -37,7 +37,7 @@ func anyCompatError(errType string, x interface{}) error { func (any Any) MarshalAmino() ([]byte, error) { ac := any.compat if ac == nil { - return nil, anyCompatError("amino binary unmarshal", any) + return nil, anyCompatError("amino binary marshal", any) } return ac.aminoBz, ac.err } diff --git a/codec/types/interface_registry.go b/codec/types/interface_registry.go index 616060871f..5c345e1781 100644 --- a/codec/types/interface_registry.go +++ b/codec/types/interface_registry.go @@ -46,17 +46,6 @@ type InterfaceRegistry interface { // registry.RegisterImplementations((*sdk.Msg)(nil), &MsgSend{}, &MsgMultiSend{}) RegisterImplementations(iface interface{}, impls ...proto.Message) - // RegisterCustomTypeURL allows a protobuf message to be registered as a - // google.protobuf.Any with a custom typeURL (besides its own canonical - // typeURL). iface should be an interface as type, as in RegisterInterface - // and RegisterImplementations. - // - // Ex: - // This will allow us to pack service methods in Any's using the full method name - // as the type URL and the request body as the value, and allow us to unpack - // such packed methods using the normal UnpackAny method for the interface iface. - RegisterCustomTypeURL(iface interface{}, typeURL string, impl proto.Message) - // ListAllInterfaces list the type URLs of all registered interfaces. ListAllInterfaces() []string diff --git a/codec/types/types_test.go b/codec/types/types_test.go index b2144d1529..457f37ff93 100644 --- a/codec/types/types_test.go +++ b/codec/types/types_test.go @@ -1,24 +1,18 @@ package types_test import ( - "context" - "fmt" "strings" "testing" - "github.com/gogo/protobuf/grpc" "github.com/gogo/protobuf/jsonpb" "github.com/gogo/protobuf/proto" - grpc2 "google.golang.org/grpc" - "github.com/stretchr/testify/require" - "github.com/line/lbm-sdk/codec" "github.com/line/lbm-sdk/codec/types" "github.com/line/lbm-sdk/testutil/testdata" ) -func TestPackUnpack(t *testing.T) { +func TestAnyPackUnpack(t *testing.T) { registry := testdata.NewTestInterfaceRegistry() spot := &testdata.Dog{Name: "Spot"} @@ -31,12 +25,6 @@ func TestPackUnpack(t *testing.T) { err = registry.UnpackAny(any, &animal) require.NoError(t, err) require.Equal(t, spot, animal) - - // without cache - any.ClearCachedValue() - err = registry.UnpackAny(any, &animal) - require.NoError(t, err) - require.Equal(t, spot, animal) } type TestI interface { @@ -192,60 +180,3 @@ func TestAny_ProtoJSON(t *testing.T) { require.NoError(t, err) require.Equal(t, spot, ha2.Animal.GetCachedValue()) } - -// this instance of grpc.ClientConn is used to test packing service method -// requests into Any's -type testAnyPackClient struct { - any types.Any - interfaceRegistry types.InterfaceRegistry -} - -var _ grpc.ClientConn = &testAnyPackClient{} - -func (t *testAnyPackClient) Invoke(_ context.Context, method string, args, _ interface{}, _ ...grpc2.CallOption) error { - reqMsg, ok := args.(proto.Message) - if !ok { - return fmt.Errorf("can't proto marshal %T", args) - } - - // registry the method request type with the interface registry - t.interfaceRegistry.RegisterCustomTypeURL((*interface{})(nil), method, reqMsg) - - bz, err := proto.Marshal(reqMsg) - if err != nil { - return err - } - - t.any.TypeUrl = method - t.any.Value = bz - - return nil -} - -func (t *testAnyPackClient) NewStream(context.Context, *grpc2.StreamDesc, string, ...grpc2.CallOption) (grpc2.ClientStream, error) { - return nil, fmt.Errorf("not supported") -} - -func TestAny_ServiceRequestProtoJSON(t *testing.T) { - interfaceRegistry := types.NewInterfaceRegistry() - anyPacker := &testAnyPackClient{interfaceRegistry: interfaceRegistry} - dogMsgClient := testdata.NewMsgClient(anyPacker) - _, err := dogMsgClient.CreateDog(context.Background(), &testdata.MsgCreateDog{Dog: &testdata.Dog{ - Name: "spot", - }}) - require.NoError(t, err) - - // marshal JSON - cdc := codec.NewProtoCodec(interfaceRegistry) - bz, err := cdc.MarshalJSON(&anyPacker.any) - require.NoError(t, err) - require.Equal(t, - `{"@type":"/testdata.Msg/CreateDog","dog":{"size":"","name":"spot"}}`, - string(bz)) - - // unmarshal JSON - var any2 types.Any - err = cdc.UnmarshalJSON(bz, &any2) - require.NoError(t, err) - require.Equal(t, anyPacker.any, any2) -} diff --git a/codec/unknownproto/regression_test.go b/codec/unknownproto/regression_test.go index e9e44f0bbe..3bc7b1f10c 100644 --- a/codec/unknownproto/regression_test.go +++ b/codec/unknownproto/regression_test.go @@ -18,7 +18,7 @@ func TestBadBytesPassedIntoDecoder(t *testing.T) { decoder := cfg.TxConfig.TxDecoder() tx, err := decoder(data) - // TODO: When issue https://github.com/line/lbm-sdk/issues/7846 + // TODO: When issue https://github.com/cosmos/cosmos-sdk/issues/7846 // is addressed, we'll remove this .Contains check. require.Contains(t, err.Error(), io.ErrUnexpectedEOF.Error()) require.Nil(t, tx) diff --git a/codec/unknownproto/unknown_fields_test.go b/codec/unknownproto/unknown_fields_test.go index 9e2cd1a0f0..2e0824d8e6 100644 --- a/codec/unknownproto/unknown_fields_test.go +++ b/codec/unknownproto/unknown_fields_test.go @@ -651,7 +651,7 @@ func TestRejectUnknownFieldsFlat(t *testing.T) { } } -// Issue https://github.com/line/lbm-sdk/issues/7222, we need to ensure that repeated +// Issue https://github.com/cosmos/cosmos-sdk/issues/7222, we need to ensure that repeated // uint64 are recognized as packed. func TestPackedEncoding(t *testing.T) { data := testdata.TestRepeatedUints{Nums: []uint64{12, 13}} diff --git a/codec/yaml.go b/codec/yaml.go index bba5e90ed8..fc8b7d3f60 100644 --- a/codec/yaml.go +++ b/codec/yaml.go @@ -7,13 +7,13 @@ import ( "gopkg.in/yaml.v2" ) -// MarshalYAML marshals toPrint using jsonMarshaler to leverage specialized MarshalJSON methods +// MarshalYAML marshals toPrint using JSONCodec to leverage specialized MarshalJSON methods // (usually related to serialize data with protobuf or amin depending on a configuration). // This involves additional roundtrip through JSON. -func MarshalYAML(jsonMarshaler JSONMarshaler, toPrint proto.Message) ([]byte, error) { +func MarshalYAML(cdc JSONCodec, toPrint proto.Message) ([]byte, error) { // We are OK with the performance hit of the additional JSON roundtip. MarshalYAML is not // used in any critical parts of the system. - bz, err := jsonMarshaler.MarshalJSON(toPrint) + bz, err := cdc.MarshalJSON(toPrint) if err != nil { return nil, err } diff --git a/contrib/devtools/dockerfile b/contrib/devtools/dockerfile index 565e66ea33..10be413453 100644 --- a/contrib/devtools/dockerfile +++ b/contrib/devtools/dockerfile @@ -18,4 +18,10 @@ RUN GO111MODULE=on go get \ RUN GO111MODULE=on go get -u github.com/pseudomuto/protoc-gen-doc/cmd/protoc-gen-doc +RUN apk add --no-cache \ + nodejs \ + npm + +RUN npm install -g swagger-combine + COPY --from=BUILDER /usr/local/bin /usr/local/bin diff --git a/contrib/githooks/README.md b/contrib/githooks/README.md index 83057835d4..0d67d8da03 100644 --- a/contrib/githooks/README.md +++ b/contrib/githooks/README.md @@ -3,7 +3,7 @@ Installation: ``` -$ git config core.hooksPath contrib/githooks +git config core.hooksPath contrib/githooks ``` ## pre-commit @@ -14,8 +14,8 @@ that all the aforementioned commands are installed and available in the user's search `$PATH` environment variable: ``` -$ go get golang.org/x/tools/cmd/goimports -$ go get github.com/golangci/misspell/cmd/misspell@master +go get golang.org/x/tools/cmd/goimports +go get github.com/golangci/misspell/cmd/misspell@master ``` It also runs `go mod tidy` and `golangci-lint` if available. diff --git a/contrib/images/Makefile b/contrib/images/Makefile index c0ec5240fd..03d3f8be42 100644 --- a/contrib/images/Makefile +++ b/contrib/images/Makefile @@ -1,6 +1,7 @@ all: simd-env simd-env: - docker build --build-arg UID=$(shell id -u) --build-arg GID=$(shell id -g) --tag cosmossdk/simd-env simd-env + docker build --tag cosmossdk/simd-env -f simd-env/Dockerfile \ + $(shell git rev-parse --show-toplevel) .PHONY: all simd-env diff --git a/contrib/images/simd-env/Dockerfile b/contrib/images/simd-env/Dockerfile index 591592b718..b4443cdc8a 100644 --- a/contrib/images/simd-env/Dockerfile +++ b/contrib/images/simd-env/Dockerfile @@ -1,18 +1,21 @@ -FROM ubuntu:18.04 +FROM golang:1.17-alpine AS build +RUN apk add build-base git linux-headers +WORKDIR /work +COPY go.mod go.sum /work/ +COPY db/go.mod db/go.sum /work/db/ +RUN go mod download +COPY ./ /work +RUN LEDGER_ENABLED=false make clean build -RUN apt-get update && \ - apt-get -y upgrade && \ - apt-get -y install curl jq file +FROM alpine:3.14 AS run +RUN apk add bash curl jq +COPY contrib/images/simd-env/wrapper.sh /usr/bin/wrapper.sh -ARG UID=1000 -ARG GID=1000 - -USER ${UID}:${GID} -VOLUME [ "/simd" ] +VOLUME /simd +COPY --from=build /work/build/simd /simd/ WORKDIR /simd + EXPOSE 26656 26657 ENTRYPOINT ["/usr/bin/wrapper.sh"] CMD ["start", "--log_format", "plain"] STOPSIGNAL SIGTERM - -COPY wrapper.sh /usr/bin/wrapper.sh diff --git a/contrib/images/simd-env/wrapper.sh b/contrib/images/simd-env/wrapper.sh index a225009857..d95bf58890 100755 --- a/contrib/images/simd-env/wrapper.sh +++ b/contrib/images/simd-env/wrapper.sh @@ -1,4 +1,6 @@ #!/usr/bin/env sh +set -euo pipefail +set -x BINARY=/simd/${BINARY:-simd} ID=${ID:-0} @@ -9,14 +11,7 @@ if ! [ -f "${BINARY}" ]; then exit 1 fi -BINARY_CHECK="$(file "$BINARY" | grep 'ELF 64-bit LSB executable, x86-64')" - -if [ -z "${BINARY_CHECK}" ]; then - echo "Binary needs to be OS linux, ARCH amd64" - exit 1 -fi - -export SIMDHOME="/simd/node${ID}/simd" +export SIMDHOME="/data/node${ID}/simd" if [ -d "$(dirname "${SIMDHOME}"/"${LOG}")" ]; then "${BINARY}" --home "${SIMDHOME}" "$@" | tee "${SIMDHOME}/${LOG}" diff --git a/contrib/rosetta/README.md b/contrib/rosetta/README.md new file mode 100644 index 0000000000..f408729581 --- /dev/null +++ b/contrib/rosetta/README.md @@ -0,0 +1,29 @@ +# rosetta + +This directory contains the files required to run the rosetta CI. It builds `simapp` based on the current codebase. + +## docker-compose.yaml + +Builds: + +- cosmos-sdk simapp node, with prefixed data directory, keys etc. This is required to test historical balances. +- faucet is required so we can test construction API, it was literally impossible to put there a deterministic address to request funds for +- rosetta is the rosetta node used by rosetta-cli to interact with the cosmos-sdk app +- test_rosetta runs the rosetta-cli test against construction API and data API + +## configuration + +Contains the required files to set up rosetta cli and make it work against its workflows + +## node + +Contains the files for a deterministic network, with fixed keys and some actions on there, to test parsing of msgs and historical balances. This image is used to run a simapp node and to run the rosetta server. + +## Rosetta-cli + +The docker image for ./rosetta-cli/Dockerfile is on [docker hub](https://hub.docker.com/r/tendermintdev/rosetta-cli). Whenever rosetta-cli releases a new version, rosetta-cli/Dockerfile should be updated to reflect the new version and pushed to docker hub. + +## Notes + +- Keyring password is 12345678 +- data.sh creates node data, it's required in case consensus breaking changes are made to quickly recreate replicable node data for rosetta diff --git a/contrib/rosetta/configuration/bootstrap.json b/contrib/rosetta/configuration/bootstrap.json new file mode 100644 index 0000000000..ebac03c43b --- /dev/null +++ b/contrib/rosetta/configuration/bootstrap.json @@ -0,0 +1,12 @@ +[ + { + "account_identifier": { + "address":"link1ujtnemf6jmfm995j000qdry064n5lq854gfe3j" + }, + "currency":{ + "symbol":"stake", + "decimals":0 + }, + "value": "999990000000" + } +] \ No newline at end of file diff --git a/contrib/rosetta/configuration/data.sh b/contrib/rosetta/configuration/data.sh new file mode 100644 index 0000000000..4d7d5ff0b0 --- /dev/null +++ b/contrib/rosetta/configuration/data.sh @@ -0,0 +1,59 @@ +#!/bin/sh + +set -e + +wait_simd() { + timeout 30 sh -c 'until nc -z $0 $1; do sleep 1; done' localhost 9090 +} +# this script is used to recreate the data dir +echo clearing /root/.simapp +rm -rf /root/.simapp +echo initting new chain +# init config files +simd init simd --chain-id testing + +# create accounts +simd keys add fd --keyring-backend=test + +addr=$(simd keys show fd -a --keyring-backend=test) +val_addr=$(simd keys show fd --keyring-backend=test --bech val -a) + +# give the accounts some money +simd add-genesis-account "$addr" 1000000000000stake --keyring-backend=test + +# save configs for the daemon +simd gentx fd 10000000stake --chain-id testing --keyring-backend=test + +# input genTx to the genesis file +simd collect-gentxs +# verify genesis file is fine +simd validate-genesis +echo changing network settings +sed -i 's/127.0.0.1/0.0.0.0/g' /root/.simapp/config/config.toml + +# start simd +echo starting simd... +simd start --pruning=nothing & +pid=$! +echo simd started with PID $pid + +echo awaiting for simd to be ready +wait_simd +echo simd is ready +sleep 10 + + +# send transaction to deterministic address +echo sending transaction with addr $addr +simd tx bank send "$addr" cosmos19g9cm8ymzchq2qkcdv3zgqtwayj9asv3hjv5u5 100stake --yes --keyring-backend=test --broadcast-mode=block --chain-id=testing + +sleep 10 + +echo stopping simd... +kill -9 $pid + +echo zipping data dir and saving to /tmp/data.tar.gz + +tar -czvf /tmp/data.tar.gz /root/.simapp + +echo new address for bootstrap.json "$addr" "$val_addr" diff --git a/contrib/rosetta/configuration/faucet.py b/contrib/rosetta/configuration/faucet.py new file mode 100644 index 0000000000..44536a84bb --- /dev/null +++ b/contrib/rosetta/configuration/faucet.py @@ -0,0 +1,25 @@ +from http.server import HTTPServer, BaseHTTPRequestHandler +import subprocess + +import os + + +class SimpleHTTPRequestHandler(BaseHTTPRequestHandler): + + def do_POST(self): + try: + content_len = int(self.headers.get('Content-Length')) + addr = self.rfile.read(content_len).decode("utf-8") + print("sending funds to " + addr) + subprocess.call(['sh', './send_funds.sh', addr]) + self.send_response(200) + self.end_headers() + except Exception as e: + print("failed " + str(e)) + os._exit(1) + + +if __name__ == "__main__": + print("starting faucet server...") + httpd = HTTPServer(('0.0.0.0', 8000), SimpleHTTPRequestHandler) + httpd.serve_forever() diff --git a/contrib/rosetta/configuration/rosetta.json b/contrib/rosetta/configuration/rosetta.json new file mode 100644 index 0000000000..b4adc6a756 --- /dev/null +++ b/contrib/rosetta/configuration/rosetta.json @@ -0,0 +1,51 @@ +{ + "network": { + "blockchain": "app", + "network": "network" + }, + "online_url": "http://rosetta:8080", + "data_directory": "", + "http_timeout": 300, + "max_retries": 5, + "retry_elapsed_time": 0, + "max_online_connections": 0, + "max_sync_concurrency": 0, + "tip_delay": 60, + "log_configuration": true, + "construction": { + "offline_url": "http://rosetta:8080", + "max_offline_connections": 0, + "stale_depth": 0, + "broadcast_limit": 0, + "ignore_broadcast_failures": false, + "clear_broadcasts": false, + "broadcast_behind_tip": false, + "block_broadcast_limit": 0, + "rebroadcast_all": false, + "constructor_dsl_file": "transfer.ros", + "end_conditions": { + "create_account": 1, + "transfer": 1 + } + }, + "data": { + "active_reconciliation_concurrency": 0, + "inactive_reconciliation_concurrency": 0, + "inactive_reconciliation_frequency": 0, + "log_blocks": false, + "log_transactions": false, + "log_balance_changes": false, + "log_reconciliations": false, + "ignore_reconciliation_error": false, + "exempt_accounts": "", + "bootstrap_balances": "bootstrap.json", + "interesting_accounts": "", + "reconciliation_disabled": false, + "inactive_discrepency_search_disabled": false, + "balance_tracking_disabled": false, + "coin_tracking_disabled": false, + "end_conditions": { + "tip": true + } + } +} \ No newline at end of file diff --git a/contrib/rosetta/configuration/run_tests.sh b/contrib/rosetta/configuration/run_tests.sh new file mode 100755 index 0000000000..c53f89ff88 --- /dev/null +++ b/contrib/rosetta/configuration/run_tests.sh @@ -0,0 +1,17 @@ +#!/bin/sh + +set -e + +wait_for_rosetta() { + timeout 30 sh -c 'until nc -z $0 $1; do sleep 1; done' rosetta 8080 +} + +echo "waiting for rosetta instance to be up" +wait_for_rosetta + +echo "checking data API" +rosetta-cli check:data --configuration-file ./config/rosetta.json + +echo "checking construction API" +rosetta-cli check:construction --configuration-file ./config/rosetta.json + diff --git a/contrib/rosetta/configuration/send_funds.sh b/contrib/rosetta/configuration/send_funds.sh new file mode 100644 index 0000000000..3a897539d2 --- /dev/null +++ b/contrib/rosetta/configuration/send_funds.sh @@ -0,0 +1,5 @@ +#!/bin/sh + +set -e +addr=$(simd keys show fd -a --keyring-backend=test) +echo "12345678" | simd tx bank send "$addr" "$1" 100stake --chain-id="testing" --node tcp://cosmos:26657 --yes --keyring-backend=test \ No newline at end of file diff --git a/contrib/rosetta/configuration/transfer.ros b/contrib/rosetta/configuration/transfer.ros new file mode 100644 index 0000000000..8266ae7d63 --- /dev/null +++ b/contrib/rosetta/configuration/transfer.ros @@ -0,0 +1,105 @@ +request_funds(1){ + find_account{ + currency = {"symbol":"stake", "decimals":0}; + random_account = find_balance({ + "minimum_balance":{ + "value": "0", + "currency": {{currency}} + }, + "create_limit":1 + }); + }, + send_funds{ + account_identifier = {{random_account.account_identifier}}; + address = {{account_identifier.address}}; + idk = http_request({ + "method": "POST", + "url": "http:\/\/faucet:8000", + "timeout": 10, + "body": {{random_account.account_identifier.address}} + }); + }, + // Create a separate scenario to request funds so that + // the address we are using to request funds does not + // get rolled back if funds do not yet exist. + request{ + loaded_account = find_balance({ + "account_identifier": {{random_account.account_identifier}}, + "minimum_balance":{ + "value": "50", + "currency": {{currency}} + } + }); + } +} +create_account(1){ + create{ + network = {"network":"network", "blockchain":"app"}; + key = generate_key({"curve_type": "secp256k1"}); + account = derive({ + "network_identifier": {{network}}, + "public_key": {{key.public_key}} + }); + // If the account is not saved, the key will be lost! + save_account({ + "account_identifier": {{account.account_identifier}}, + "keypair": {{key}} + }); + } +} +transfer(3){ + transfer{ + transfer.network = {"network":"network", "blockchain":"app"}; + currency = {"symbol":"stake", "decimals":0}; + sender = find_balance({ + "minimum_balance":{ + "value": "100", + "currency": {{currency}} + } + }); + acc_identifier = {{sender.account_identifier}}; + sender_address = {{acc_identifier.address}}; + // Set the recipient_amount as some value <= sender.balance-max_fee + max_fee = "0"; + fee_amount = "1"; + fee_value = 0 - {{fee_amount}}; + available_amount = {{sender.balance.value}} - {{max_fee}}; + recipient_amount = random_number({"minimum": "1", "maximum": {{available_amount}}}); + print_message({"recipient_amount":{{recipient_amount}}}); + // Find recipient and construct operations + sender_amount = 0 - {{recipient_amount}}; + recipient = find_balance({ + "not_account_identifier":[{{sender.account_identifier}}], + "minimum_balance":{ + "value": "0", + "currency": {{currency}} + }, + "create_limit": 100, + "create_probability": 50 + }); + transfer.confirmation_depth = "1"; + recipient_account_identifier = {{recipient.account_identifier}}; + recipient_address = {{recipient_account_identifier.address}}; + transfer.operations = [ + { + "operation_identifier":{"index":0}, + "type":"/lbm.bank.v1.MsgSend", + "account":{{sender.account_identifier}}, + "metadata": { + "amount": [ + { + "amount": {{recipient_amount}}, + "denom": {{currency.symbol}} + } + ], + "from_address": {{sender_address}}, + "to_address": {{recipient_address}} + } + } + ]; + transfer.preprocess_metadata = { + "gas_price": "1stake", + "gas_limit": 250000 + }; + } +} diff --git a/contrib/rosetta/docker-compose.yaml b/contrib/rosetta/docker-compose.yaml new file mode 100644 index 0000000000..fabb36b0aa --- /dev/null +++ b/contrib/rosetta/docker-compose.yaml @@ -0,0 +1,39 @@ +version: "3" + +services: + cosmos: + image: rosetta-ci:latest + command: ["simd", "start", "--pruning", "nothing", "--grpc-web.enable", "true", "--grpc-web.address", "0.0.0.0:9091"] + ports: + - 9090:9090 + - 26657:26657 + logging: + driver: "none" + + rosetta: + image: rosetta-ci:latest + command: [ + "simd", + "rosetta", + "--blockchain", "app", + "--network", "network", + "--tendermint", "cosmos:26657", + "--grpc", "cosmos:9090", + "--addr", ":8080", + ] + ports: + - 8080:8080 + + faucet: + image: rosetta-ci:latest + working_dir: /rosetta + command: ["python3", "faucet.py"] + expose: + - 8080 + + test_rosetta: + image: tendermintdev/rosetta-cli:v0.6.7 + volumes: + - ./configuration:/rosetta/config:z + command: ["./config/run_tests.sh"] + working_dir: /rosetta diff --git a/contrib/rosetta/node/Dockerfile b/contrib/rosetta/node/Dockerfile new file mode 100644 index 0000000000..0887f522f6 --- /dev/null +++ b/contrib/rosetta/node/Dockerfile @@ -0,0 +1,32 @@ +FROM golang:1.15-alpine as build + +RUN apk add --no-cache tar + +# prepare node data +WORKDIR /node +COPY ./contrib/rosetta/node/data.tar.gz data.tar.gz +RUN tar -zxvf data.tar.gz -C . + +# build simd +WORKDIR /simd +COPY . ./ +RUN go build -o simd ./simapp/simd/ + +FROM alpine +RUN apk add gcc libc-dev python3 --no-cache + +ENV PATH=$PATH:/bin + +COPY --from=build /simd/simd /bin/simd + +WORKDIR /rosetta +COPY ./contrib/rosetta/configuration ./ +RUN chmod +x run_tests.sh +RUN chmod +x send_funds.sh +RUN chmod +x faucet.py + +COPY --from=build /node/root /root/ +WORKDIR /root/.simapp + +RUN chmod -R 0777 ./ + diff --git a/contrib/rosetta/node/data.tar.gz b/contrib/rosetta/node/data.tar.gz new file mode 100644 index 0000000000..291681c89d Binary files /dev/null and b/contrib/rosetta/node/data.tar.gz differ diff --git a/contrib/rosetta/rosetta-cli/Dockerfile b/contrib/rosetta/rosetta-cli/Dockerfile new file mode 100644 index 0000000000..f67070f6c4 --- /dev/null +++ b/contrib/rosetta/rosetta-cli/Dockerfile @@ -0,0 +1,18 @@ +FROM golang:1.15-alpine as build + +RUN apk add git gcc libc-dev --no-cache + +ARG ROSETTA_VERSION="v0.6.7" + +# build rosetta CLI +WORKDIR /rosetta +RUN git clone https://github.com/coinbase/rosetta-cli . +RUN git checkout tags/$ROSETTA_VERSION +RUN go build -o rosetta-cli ./main.go + +FROM alpine +RUN apk add gcc libc-dev python3 --no-cache + +ENV PATH=$PATH:/bin + +COPY --from=build /rosetta/rosetta-cli /bin/rosetta-cli diff --git a/cosmovisor/README.md b/cosmovisor/README.md index 3892efd0db..e263966a49 100644 --- a/cosmovisor/README.md +++ b/cosmovisor/README.md @@ -1,37 +1,31 @@ -# Cosmovisor - -This is a tiny shim around Cosmos SDK binaries that use the upgrade -module that allows for smooth and configurable management of upgrading -binaries as a live chain is upgraded, and can be used to simplify validator -devops while doing upgrades or to make syncing a full node for genesis -simple. The `cosmovisor` will monitor the stdout of the daemon to look -for messages from the upgrade module indicating a pending or required upgrade -and act appropriately. (With better integrations possible in the future). - -## Arguments - -`cosmovisor` is a shim around a native binary. All arguments passed to the `cosmovisor` -command will be passed to the current daemon binary (as a subprocess). - It will return stdout and stderr of the subprocess as -it's own. Because of that, it cannot accept any command line arguments, nor -print anything to output (unless it dies before executing a binary). - -Configuration will be passed in the following environmental variables: - -* `DAEMON_HOME` is the location where upgrade binaries should be kept (can -be `$HOME/.gaiad` or `$HOME/.xrnd`) -* `DAEMON_NAME` is the name of the binary itself (eg. `xrnd`, `gaiad`, `simd`) -* `DAEMON_ALLOW_DOWNLOAD_BINARIES` (optional) if set to `true` will enable auto-downloading of new binaries -(for security reasons, this is intended for fullnodes rather than validators) -* `DAEMON_RESTART_AFTER_UPGRADE` (optional) if set to `true` it will restart the sub-process with the same args -(but new binary) after a successful upgrade. By default, the `cosmovisor` dies afterward and allows the cosmovisor -to restart it if needed. Note that this will not auto-restart the child if there was an error. +# Cosmosvisor Quick Start + +`cosmovisor` is a small process manager for Cosmos SDK application binaries that monitors the governance module via stdout for incoming chain upgrade proposals. If it sees a proposal that gets approved, `cosmovisor` can automatically download the new binary, stop the current binary, switch from the old binary to the new one, and finally restart the node with the new binary. + +*Note: If new versions of the application are not set up to run in-place store migrations, migrations will need to be run manually before restarting `cosmovisor` with the new binary. For this reason, we recommend applications adopt in-place store migrations.* + +## Installation + +To install `cosmovisor`, run the following command: + +``` +go get github.com/cosmos/cosmos-sdk/cosmovisor/cmd/cosmovisor +``` + +## Command Line Arguments And Environment Variables + +All arguments passed to `cosmovisor` will be passed to the application binary (as a subprocess). `cosmovisor` will return `/dev/stdout` and `/dev/stderr` of the subprocess as its own. For this reason, `cosmovisor` cannot accept any command-line arguments other than those available to the application binary, nor will it print anything to output other than what is printed by the application binary. + +`cosmovisor` reads its configuration from environment variables: + +* `DAEMON_HOME` is the location where the `cosmovisor/` directory is kept that contains the genesis binary, the upgrade binaries, and any additional auxiliary files associated with each binary (e.g. `$HOME/.gaiad`, `$HOME/.regend`, `$HOME/.simd`, etc.). +* `DAEMON_NAME` is the name of the binary itself (e.g. `gaiad`, `regend`, `simd`, etc.). +* `DAEMON_ALLOW_DOWNLOAD_BINARIES` (*optional*), if set to `true`, will enable auto-downloading of new binaries (for security reasons, this is intended for full nodes rather than validators). By default, `cosmovisor` will not auto-download new binaries. +* `DAEMON_RESTART_AFTER_UPGRADE` (*optional*), if set to `true`, will restart the subprocess with the same command-line arguments and flags (but with the new binary) after a successful upgrade. By default, `cosmovisor` stops running after an upgrade and requires the system administrator to manually restart it. Note that `cosmovisor` will not auto-restart the subprocess if there was an error. ## Folder Layout -`$DAEMON_HOME/cosmovisor` is expected to belong completely to the cosmovisor and -subprocesses -controlled by it. Under this folder, we will see the following: +`$DAEMON_HOME/cosmovisor` is expected to belong completely to `cosmovisor` and the subprocesses that are controlled by it. The folder content is organized as follows: ``` . @@ -45,17 +39,9 @@ controlled by it. Under this folder, we will see the following: └── $DAEMON_NAME ``` -Each version of the chain is stored under either `genesis` or `upgrades/`, which holds `bin/$DAEMON_NAME` -along with any other needed files (maybe the cli client? maybe some dlls?). `current` is a symlink to the currently -active folder (so `current/bin/$DAEMON_NAME` is the binary) - -Note: the `` after `upgrades` is the URI-encoded name of the upgrade as specified in the upgrade module plan. +The `cosmovisor/` directory incudes a subdirectory for each version of the application (i.e. `genesis` or `upgrades/`). Within each subdirectory is the application binary (i.e. `bin/$DAEMON_NAME`) and any additional auxiliary files associated with each binary. `current` is a symbolic link to the currently active directory (i.e. `genesis` or `upgrades/`). The `name` variable in `upgrades/` is the URI-encoded name of the upgrade as specified in the upgrade module plan. -Please note that `$DAEMON_HOME/cosmovisor` just stores the *binaries* and associated *program code*. -The `cosmovisor` binary can be stored in any typical location (eg `/usr/local/bin`). The actual blockchain -program will store it's data under `$GAIA_HOME` etc, which is independent of the `$DAEMON_HOME`. You can -choose to export `GAIA_HOME=$DAEMON_HOME` and then end up with a configuation like the following, but this -is left as a choice to the admin for best directory layout. +Please note that `$DAEMON_HOME/cosmovisor` only stores the *application binaries*. The `cosmovisor` binary itself can be stored in any typical location (e.g. `/usr/local/bin`). The application will continue to store its data in the default data directory (e.g. `$HOME/.gaiad`) or the data directory specified with the `--home` flag. `$DAEMON_HOME` is independent of the data directory and can be set to any location. If you set `$DAEMON_HOME` to the same directory as the data directory, you will end up with a configuation like the following: ``` .gaiad @@ -66,55 +52,28 @@ is left as a choice to the admin for best directory layout. ## Usage -Basic Usage: +The system administrator is responsible for: -* The admin is responsible for installing the `cosmovisor` and setting it as a eg. systemd service to auto-restart, along with proper environmental variables -* The admin is responsible for installing the `genesis` folder manually -* The `cosmovisor` will set the `current` link to point to `genesis` at first start (when no `current` link exists) -* The admin is (generally) responsible for installing the `upgrades/` folders manually -* The `cosmovisor` handles switching over the binaries at the correct points, so the admin can prepare days in advance and relax at upgrade time +- installing the `cosmovisor` binary +- configuring the host's init system (e.g. `systemd`, `launchd`, etc.) +- appropriately setting the environmental variables +- manually installing the `genesis` folder +- manually installing the `upgrades/` folders -Note that chains that wish to support upgrades may package up a genesis `cosmovisor` tar file with this info, just as they -prepare the genesis binary tar file. In fact, they may offer a tar file will all upgrades up to current point for easy download -for those who wish to sync a fullnode from start. +`cosmovisor` will set the `current` link to point to `genesis` at first start (i.e. when no `current` link exists) and then handle switching binaries at the correct points in time so that the system administrator can prepare days in advance and relax at upgrade time. -The `DAEMON` specific code, like the tendermint config, the application db, syncing blocks, etc is done as normal. -The same eg. `GAIA_HOME` directives and command-line flags work, just the binary name is different. +In order to support downloadable binaries, a tarball for each upgrade binary will need to be packaged up and made available through a canonical URL. Additionally, a tarball that includes the genesis binary and all available upgrade binaries can be packaged up and made available so that all the necessary binaries required to sync a fullnode from start can be easily downloaded. -## Upgradeable Binary Specification - -In the basic version, the `cosmovisor` will read the stdout log messages -to determine when an upgrade is needed. We are considering more complex solutions -via signaling of some sort, but starting with the simple design: - -* when an upgrade is needed the binary will print a line that matches this -regular expression: `UPGRADE "(.*)" NEEDED at height (\d+):(.*)`. -* the second match in the above regular expression can be a JSON object with -a `binaries` key as described above - -The name (first regexp) will be used to select the new binary to run. If it is present, -the current subprocess will be killed, `current` will be upgraded to the new directory, -and the new binary will be launched. - -**Question** should we just kill the `cosmovisor` after it does the updates? -so it gets a clean restart and just runs the new binary (under `current`). -it should be safe to restart (as a service). +The `DAEMON` specific code and operations (e.g. tendermint config, the application db, syncing blocks, etc.) all work as expected. The application binaries' directives such as command-line flags and environment variables also work as expected. ## Auto-Download -Generally, the system requires that the administrator place all relevant binaries -on the disk before the upgrade happens. However, for people who don't need such -control and want an easier setup (maybe they are syncing a non-validating fullnode -and want to do little maintenance), there is another option. +Generally, `cosmovisor` requires that the system administrator place all relevant binaries on disk before the upgrade happens. However, for people who don't need such control and want an easier setup (maybe they are syncing a non-validating fullnode and want to do little maintenance), there is another option. + +If `DAEMON_ALLOW_DOWNLOAD_BINARIES` is set to `true`, and no local binary can be found when an upgrade is triggered, `cosmovisor` will attempt to download and install the binary itself. The plan stored in the upgrade module has an info field for arbitrary JSON. This info is expected to be outputed on the halt log message. There are two valid formats to specify a download in such a message: -If you set `DAEMON_ALLOW_DOWNLOAD_BINARIES=on` then when an upgrade is triggered and no local binary -can be found, the `cosmovisor` will attempt to download and install the binary itself. -The plan stored in the upgrade module has an info field for arbitrary json. -This info is expected to be outputed on the halt log message. There are two -valid format to specify a download in such a message: +1. Store an os/architecture -> binary URI map in the upgrade plan info field as JSON under the `"binaries"` key. For example: -1. Store an os/architecture -> binary URI map in the upgrade plan info field -as JSON under the `"binaries"` key, eg: ```json { "binaries": { @@ -122,27 +81,156 @@ as JSON under the `"binaries"` key, eg: } } ``` -The `"any"` key, if it exists, will be used as a default if there is not a specific os/architecture key. -2. Store a link to a file that contains all information in the above format (eg. if you want -to specify lots of binaries, changelog info, etc without filling up the blockchain). -e.g `https://example.com/testnet-1001-info.json?checksum=sha256:deaaa99fda9407c4dbe1d04bd49bab0cc3c1dd76fa392cd55a9425be074af01e` +2. Store a link to a file that contains all information in the above format (e.g. if you want to specify lots of binaries, changelog info, etc. without filling up the blockchain). For example: + +``` +https://example.com/testnet-1001-info.json?checksum=sha256:deaaa99fda9407c4dbe1d04bd49bab0cc3c1dd76fa392cd55a9425be074af01e +``` + +When `cosmovisor` is triggered to download the new binary, `cosmovisor` will parse the `"binaries"` field, download the new binary with [go-getter](https://github.com/hashicorp/go-getter), and unpack the new binary in the `upgrades/` folder so that it can be run as if it was installed manually. + +Note that for this mechanism to provide strong security guarantees, all URLs should include a SHA 256/512 checksum. This ensures that no false binary is run, even if someone hacks the server or hijacks the DNS. `go-getter` will always ensure the downloaded file matches the checksum if it is provided. `go-getter` will also handle unpacking archives into directories (in this case the download link should point to a `zip` file of all data in the `bin` directory). + +To properly create a sha256 checksum on linux, you can use the `sha256sum` utility. For example: + +``` +sha256sum ./testdata/repo/zip_directory/autod.zip +``` + +The result will look something like the following: `29139e1381b8177aec909fab9a75d11381cab5adf7d3af0c05ff1c9c117743a7`. + +You can also use `sha512sum` if you would prefer to use longer hashes, or `md5sum` if you would prefer to use broken hashes. Whichever you choose, make sure to set the hash algorithm properly in the checksum argument to the URL. + +## Example: SimApp Upgrade + +The following instructions provide a demonstration of `cosmovisor` using the simulation application (`simapp`) shipped with the Cosmos SDK's source code. The following commands are to be run from within the `cosmos-sdk` repository. + +First, check out the latest `v0.42` release: + +``` +git checkout v0.42.7 +``` + +Compile the `simd` binary: + +``` +make build +``` + +Reset `~/.simapp` (never do this in a production environment): + +``` +./build/simd unsafe-reset-all +``` + +Configure the `simd` binary for testing: + +``` +./build/simd config chain-id test +./build/simd config keyring-backend test +./build/simd config broadcast-mode block +``` + +Initialize the node and overwrite any previous genesis file (never do this in a production environment): -This file contained in link will be retrieved by [go-getter](https://github.com/hashicorp/go-getter) -and the "binaries" field will be parsed as above. + -If there is no local binary, `DAEMON_ALLOW_DOWNLOAD_BINARIES=true`, and we can access a canonical url for the new binary, -then the `cosmovisor` will download it with [go-getter](https://github.com/hashicorp/go-getter) and -unpack it into the `upgrades/` folder to be run as if we installed it manually +``` +./build/simd init test --chain-id test --overwrite +``` + +Set the minimum gas price to `0stake` in `~/.simapp/config/app.toml`: + +``` +minimum-gas-prices = "0stake" +``` + +Create a new key for the validator, then add a genesis account and transaction: + + + + +``` +./build/simd keys add validator +./build/simd add-genesis-account validator 1000000000stake --keyring-backend test +./build/simd gentx validator 1000000stake --chain-id test +./build/simd collect-gentxs +``` + +Set the required environment variables: + +``` +export DAEMON_NAME=simd +export DAEMON_HOME=$HOME/.simapp +``` + +Set the optional environment variable to trigger an automatic restart: + +``` +export DAEMON_RESTART_AFTER_UPGRADE=true +``` + +Create the folder for the genesis binary and copy the `simd` binary: + +``` +mkdir -p $DAEMON_HOME/cosmovisor/genesis/bin +cp ./build/simd $DAEMON_HOME/cosmovisor/genesis/bin +``` + +For the sake of this demonstration, amend `voting_period` in `genesis.json` to a reduced time of 20 seconds (`20s`): -Note that for this mechanism to provide strong security guarantees, all URLs should include a -sha{256,512} checksum. This ensures that no false binary is run, even if someone hacks the server -or hijacks the dns. go-getter will always ensure the downloaded file matches the checksum if it -is provided. And also handles unpacking archives into directories (so these download links should be -a zip of all data in the bin directory). +``` +cat <<< $(jq '.app_state.gov.voting_params.voting_period = "20s"' $HOME/.simapp/config/genesis.json) > $HOME/.simapp/config/genesis.json +``` + +Next, we will hardcode a modification in `simapp` to simulate a code change. In `simapp/app.go`, find the line containing the `UpgradeKeeper` initialization. It should look like the following: + +```go +app.UpgradeKeeper = upgradekeeper.NewKeeper(skipUpgradeHeights, keys[upgradetypes.StoreKey], appCodec, homePath) +``` + +After that line, add the following: + +```go +app.UpgradeKeeper.SetUpgradeHandler("test1", func(ctx sdk.Context, plan upgradetypes.Plan) { + // Add some coins to a random account + addr, err := sdk.AccAddressFromBech32("cosmos18cgkqduwuh253twzmhedesw3l7v3fm37sppt58") + if err != nil { + panic(err) + } + err = app.BankKeeper.AddCoins(ctx, addr, sdk.Coins{sdk.Coin{Denom: "stake", Amount: sdk.NewInt(345600000)}}) + if err != nil { + panic(err) + } +}) +``` + +Now recompile the `simd` binary with the added upgrade handler: + +``` +make build +``` + +Create the folder for the upgrade binary and copy the `simd` binary: + +``` +mkdir -p $DAEMON_HOME/cosmovisor/upgrades/test1/bin +cp ./build/simd $DAEMON_HOME/cosmovisor/upgrades/test1/bin +``` + +Start `cosmosvisor`: + +``` +cosmovisor start +``` + +Open a new terminal window and submit an upgrade proposal along with a deposit and a vote (these commands must be run within 20 seconds of each other): + +``` +./build/simd tx gov submit-proposal software-upgrade test1 --title upgrade --description upgrade --upgrade-height 20 --from validator --yes +./build/simd tx gov deposit 1 10000000stake --from validator --yes +./build/simd tx gov vote 1 yes --from validator --yes +``` -To properly create a checksum on linux, you can use the `sha256sum` utility. eg. -`sha256sum ./testdata/repo/zip_directory/autod.zip` -which should return `29139e1381b8177aec909fab9a75d11381cab5adf7d3af0c05ff1c9c117743a7`. -You can also use `sha512sum` if you like longer hashes, or `md5sum` if you like to use broken hashes. -Make sure to set the hash algorithm properly in the checksum argument to the url. +The upgrade will occur automatically at height 20. diff --git a/cosmovisor/args.go b/cosmovisor/args.go index 33fb62e018..60cbb7d601 100644 --- a/cosmovisor/args.go +++ b/cosmovisor/args.go @@ -1,11 +1,13 @@ package cosmovisor import ( + "bufio" "errors" "fmt" "net/url" "os" "path/filepath" + "strconv" ) const ( @@ -21,6 +23,7 @@ type Config struct { Name string AllowDownloadBinaries bool RestartAfterUpgrade bool + LogBufferSize int } // Root returns the root directory where all info lives @@ -99,6 +102,17 @@ func GetConfigFromEnv() (*Config, error) { cfg.RestartAfterUpgrade = true } + logBufferSizeStr := os.Getenv("DAEMON_LOG_BUFFER_SIZE") + if logBufferSizeStr != "" { + logBufferSize, err := strconv.Atoi(logBufferSizeStr) + if err != nil { + return nil, err + } + cfg.LogBufferSize = logBufferSize * 1024 + } else { + cfg.LogBufferSize = bufio.MaxScanTokenSize + } + if err := cfg.validate(); err != nil { return nil, err } diff --git a/cosmovisor/cosmovisor b/cosmovisor/cosmovisor new file mode 100755 index 0000000000..3fc1b2e7ca Binary files /dev/null and b/cosmovisor/cosmovisor differ diff --git a/cosmovisor/process.go b/cosmovisor/process.go index cfd201e2be..6a67f65e16 100644 --- a/cosmovisor/process.go +++ b/cosmovisor/process.go @@ -38,6 +38,17 @@ func LaunchProcess(cfg *Config, args []string, stdout, stderr io.Writer) (bool, scanOut := bufio.NewScanner(io.TeeReader(outpipe, stdout)) scanErr := bufio.NewScanner(io.TeeReader(errpipe, stderr)) + // set scanner's buffer size to cfg.LogBufferSize, and ensure larger than bufio.MaxScanTokenSize otherwise fallback to bufio.MaxScanTokenSize + var maxCapacity int + if cfg.LogBufferSize < bufio.MaxScanTokenSize { + maxCapacity = bufio.MaxScanTokenSize + } else { + maxCapacity = cfg.LogBufferSize + } + bufOut := make([]byte, maxCapacity) + bufErr := make([]byte, maxCapacity) + scanOut.Buffer(bufOut, maxCapacity) + scanErr.Buffer(bufErr, maxCapacity) if err := cmd.Start(); err != nil { return false, fmt.Errorf("launching process %s %s: %w", bin, strings.Join(args, " "), err) diff --git a/cosmovisor/upgrade.go b/cosmovisor/upgrade.go index 3057597f7d..7e8091d611 100644 --- a/cosmovisor/upgrade.go +++ b/cosmovisor/upgrade.go @@ -12,6 +12,7 @@ import ( "strings" "github.com/hashicorp/go-getter" + "github.com/otiai10/copy" ) // DoUpgrade will be called after the log message has been parsed and the process has terminated. @@ -62,10 +63,19 @@ func DownloadBinary(cfg *Config, info *UpgradeInfo) error { if err != nil { dirPath := cfg.UpgradeDir(info.Name) err = getter.Get(dirPath, url) + if err != nil { + return err + } + err = EnsureBinary(binPath) + // copy binary to binPath from dirPath if zipped directory don't contain bin directory to wrap the binary + if err != nil { + err = copy.Copy(filepath.Join(dirPath, cfg.Name), binPath) + if err != nil { + return err + } + } } - if err != nil { - return err - } + // if it is successful, let's ensure the binary is executable return MarkExecutable(binPath) } diff --git a/crypto/armor.go b/crypto/armor.go index 9ef7a25e21..3e5e7b55cc 100644 --- a/crypto/armor.go +++ b/crypto/armor.go @@ -152,7 +152,7 @@ func encryptPrivKey(privKey cryptotypes.PrivKey, passphrase string) (saltBytes [ } key = crypto.Sha256(key) // get 32 bytes - privKeyBytes := legacy.Cdc.MustMarshalBinaryBare(privKey) + privKeyBytes := legacy.Cdc.MustMarshal(privKey) return saltBytes, xsalsa20symmetric.EncryptSymmetric(privKeyBytes, key) } diff --git a/crypto/armor_test.go b/crypto/armor_test.go index f03579a5fc..f1abea0507 100644 --- a/crypto/armor_test.go +++ b/crypto/armor_test.go @@ -73,7 +73,7 @@ func TestArmorUnarmorPubKey(t *testing.T) { cstore := keyring.NewInMemory() // Add keys and see they return in alphabetical order - info, _, err := cstore.NewMnemonic("Bob", keyring.English, types.FullFundraiserPath, hd.Secp256k1) + info, _, err := cstore.NewMnemonic("Bob", keyring.English, types.FullFundraiserPath, keyring.DefaultBIP39Passphrase, hd.Secp256k1) require.NoError(t, err) armored := crypto.ArmorPubKeyBytes(legacy.Cdc.Amino.MustMarshalBinaryBare(info.GetPubKey()), "") pubBytes, algo, err := crypto.UnarmorPubKeyBytes(armored) diff --git a/crypto/codec/amino.go b/crypto/codec/amino.go index 8e7fa3d95e..abce93d27b 100644 --- a/crypto/codec/amino.go +++ b/crypto/codec/amino.go @@ -26,7 +26,7 @@ func RegisterCrypto(cdc *codec.LegacyAmino) { cdc.RegisterInterface((*cryptotypes.PrivKey)(nil), nil) cdc.RegisterConcrete(sr25519.PrivKey{}, sr25519.PrivKeyName, nil) - cdc.RegisterConcrete(&ed25519.PrivKey{}, + cdc.RegisterConcrete(&ed25519.PrivKey{}, //nolint:staticcheck ed25519.PrivKeyName, nil) cdc.RegisterConcrete(&secp256k1.PrivKey{}, secp256k1.PrivKeyName, nil) diff --git a/crypto/codec/proto.go b/crypto/codec/proto.go index afad3c1988..5ef6cccc1e 100644 --- a/crypto/codec/proto.go +++ b/crypto/codec/proto.go @@ -5,13 +5,16 @@ import ( "github.com/line/lbm-sdk/crypto/keys/ed25519" "github.com/line/lbm-sdk/crypto/keys/multisig" "github.com/line/lbm-sdk/crypto/keys/secp256k1" + "github.com/line/lbm-sdk/crypto/keys/secp256r1" cryptotypes "github.com/line/lbm-sdk/crypto/types" ) // RegisterInterfaces registers the sdk.Tx interface. func RegisterInterfaces(registry codectypes.InterfaceRegistry) { - registry.RegisterInterface("lbm.crypto.PubKey", (*cryptotypes.PubKey)(nil)) - registry.RegisterImplementations((*cryptotypes.PubKey)(nil), &ed25519.PubKey{}) - registry.RegisterImplementations((*cryptotypes.PubKey)(nil), &secp256k1.PubKey{}) - registry.RegisterImplementations((*cryptotypes.PubKey)(nil), &multisig.LegacyAminoPubKey{}) + var pk *cryptotypes.PubKey + registry.RegisterInterface("lbm.crypto.PubKey", pk) + registry.RegisterImplementations(pk, &ed25519.PubKey{}) + registry.RegisterImplementations(pk, &secp256k1.PubKey{}) + registry.RegisterImplementations(pk, &multisig.LegacyAminoPubKey{}) + secp256r1.RegisterInterfaces(registry) } diff --git a/crypto/keyring/info.go b/crypto/keyring/info.go index 74993acc84..eed60ff9c6 100644 --- a/crypto/keyring/info.go +++ b/crypto/keyring/info.go @@ -177,6 +177,10 @@ func (i offlineInfo) GetPath() (*hd.BIP44Params, error) { return nil, fmt.Errorf("BIP44 Paths are not available for this type") } +// Deprecated: this structure is not used anymore and it's here only to allow +// decoding old multiInfo records from keyring. +// The problem with legacy.Cdc.UnmarshalLengthPrefixed - the legacy codec doesn't +// tolerate extensibility. type multisigPubKeyInfo struct { PubKey cryptotypes.PubKey `json:"pubkey"` Weight uint `json:"weight"` @@ -191,21 +195,14 @@ type multiInfo struct { } // NewMultiInfo creates a new multiInfo instance -func NewMultiInfo(name string, pub cryptotypes.PubKey) Info { - multiPK := pub.(*multisig.LegacyAminoPubKey) - - pubKeys := make([]multisigPubKeyInfo, len(multiPK.PubKeys)) - for i, pk := range multiPK.GetPubKeys() { - // TODO: Recursively check pk for total weight? - pubKeys[i] = multisigPubKeyInfo{pk, 1} +func NewMultiInfo(name string, pub cryptotypes.PubKey) (Info, error) { + if _, ok := pub.(*multisig.LegacyAminoPubKey); !ok { + return nil, fmt.Errorf("MultiInfo supports only multisig.LegacyAminoPubKey, got %T", pub) } - return &multiInfo{ - Name: name, - PubKey: pub, - Threshold: uint(multiPK.Threshold), - PubKeys: pubKeys, - } + Name: name, + PubKey: pub, + }, nil } // GetType implements Info interface @@ -247,12 +244,12 @@ func (i multiInfo) UnpackInterfaces(unpacker codectypes.AnyUnpacker) error { // encoding info func marshalInfo(i Info) []byte { - return legacy.Cdc.MustMarshalBinaryLengthPrefixed(i) + return legacy.Cdc.MustMarshalLengthPrefixed(i) } // decoding info func unmarshalInfo(bz []byte) (info Info, err error) { - err = legacy.Cdc.UnmarshalBinaryLengthPrefixed(bz, &info) + err = legacy.Cdc.UnmarshalLengthPrefixed(bz, &info) if err != nil { return nil, err } @@ -267,7 +264,7 @@ func unmarshalInfo(bz []byte) (info Info, err error) { _, ok := info.(multiInfo) if ok { var multi multiInfo - err = legacy.Cdc.UnmarshalBinaryLengthPrefixed(bz, &multi) + err = legacy.Cdc.UnmarshalLengthPrefixed(bz, &multi) return multi, err } diff --git a/crypto/keyring/keyring.go b/crypto/keyring/keyring.go index 3f5575b60d..b476d17f5c 100644 --- a/crypto/keyring/keyring.go +++ b/crypto/keyring/keyring.go @@ -64,14 +64,17 @@ type Keyring interface { Delete(uid string) error DeleteByAddress(address sdk.Address) error - // NewMnemonic generates a new mnemonic, derives a hierarchical deterministic - // key from that, and persists it to the storage. Returns the generated mnemonic and the key - // Info. It returns an error if it fails to generate a key for the given algo type, or if - // another key is already stored under the same name. - NewMnemonic(uid string, language Language, hdPath string, algo SignatureAlgo) (Info, string, error) + // NewMnemonic generates a new mnemonic, derives a hierarchical deterministic key from it, and + // persists the key to storage. Returns the generated mnemonic and the key Info. + // It returns an error if it fails to generate a key for the given algo type, or if + // another key is already stored under the same name or address. + // + // A passphrase set to the empty string will set the passphrase to the DefaultBIP39Passphrase value. + NewMnemonic(uid string, language Language, hdPath, bip39Passphrase string, algo SignatureAlgo) (Info, string, error) // NewAccount converts a mnemonic to a private key and BIP-39 HD Path and persists it. - NewAccount(uid, mnemonic, bip39Passwd, hdPath string, algo SignatureAlgo) (Info, error) + // It fails if there is an existing key Info with the same address. + NewAccount(uid, mnemonic, bip39Passphrase, hdPath string, algo SignatureAlgo) (Info, error) // SaveLedgerKey retrieves a public key reference from a Ledger device and persists it. SaveLedgerKey(uid string, algo SignatureAlgo, hrp string, coinType, account, index uint32) (Info, error) @@ -197,7 +200,8 @@ type keystore struct { options Options } -func infoKey(name string) []byte { return []byte(fmt.Sprintf("%s.%s", name, infoSuffix)) } +func infoKey(name string) string { return fmt.Sprintf("%s.%s", name, infoSuffix) } +func infoKeyBz(name string) []byte { return []byte(infoKey(name)) } func newKeystore(kr keyring.Keyring, opts ...Option) keystore { // Default options for keybase @@ -223,7 +227,7 @@ func (ks keystore) ExportPubKeyArmor(uid string) (string, error) { return "", fmt.Errorf("no key to export with name: %s", uid) } - return crypto.ArmorPubKeyBytes(legacy.Cdc.MustMarshalBinaryBare(bz.GetPubKey()), string(bz.GetAlgo())), nil + return crypto.ArmorPubKeyBytes(legacy.Cdc.MustMarshal(bz.GetPubKey()), string(bz.GetAlgo())), nil } func (ks keystore) ExportPubKeyArmorByAddress(address sdk.Address) (string, error) { @@ -439,7 +443,7 @@ func (ks keystore) Delete(uid string) error { return err } - err = ks.db.Remove(string(infoKey(uid))) + err = ks.db.Remove(infoKey(uid)) if err != nil { return err } @@ -450,19 +454,20 @@ func (ks keystore) Delete(uid string) error { func (ks keystore) KeyByAddress(address sdk.Address) (Info, error) { ik, err := ks.db.Get(addrHexKeyAsString(address)) if err != nil { - return nil, err + return nil, wrapKeyNotFound(err, fmt.Sprint("key with address", address, "not found")) } if len(ik.Data) == 0 { - return nil, fmt.Errorf("key with address %s not found", address) + return nil, wrapKeyNotFound(err, fmt.Sprint("key with address", address, "not found")) } + return ks.key(string(ik.Data)) +} - bs, err := ks.db.Get(string(ik.Data)) - if err != nil { - return nil, err +func wrapKeyNotFound(err error, msg string) error { + if err == keyring.ErrKeyNotFound { + return sdkerrors.Wrap(sdkerrors.ErrKeyNotFound, msg) } - - return unmarshalInfo(bs.Data) + return err } func (ks keystore) List() ([]Info, error) { @@ -498,7 +503,7 @@ func (ks keystore) List() ([]Info, error) { return res, nil } -func (ks keystore) NewMnemonic(uid string, language Language, hdPath string, algo SignatureAlgo) (Info, string, error) { +func (ks keystore) NewMnemonic(uid string, language Language, hdPath, bip39Passphrase string, algo SignatureAlgo) (Info, string, error) { if language != English { return nil, "", ErrUnsupportedLanguage } @@ -519,15 +524,19 @@ func (ks keystore) NewMnemonic(uid string, language Language, hdPath string, alg return nil, "", err } - info, err := ks.NewAccount(uid, mnemonic, DefaultBIP39Passphrase, hdPath, algo) + if bip39Passphrase == "" { + bip39Passphrase = DefaultBIP39Passphrase + } + + info, err := ks.NewAccount(uid, mnemonic, bip39Passphrase, hdPath, algo) if err != nil { return nil, "", err } - return info, mnemonic, err + return info, mnemonic, nil } -func (ks keystore) NewAccount(uid string, mnemonic string, bip39Passphrase string, hdPath string, algo SignatureAlgo) (Info, error) { +func (ks keystore) NewAccount(name string, mnemonic string, bip39Passphrase string, hdPath string, algo SignatureAlgo) (Info, error) { if !ks.isSupportedSigningAlgo(algo) { return nil, ErrUnsupportedSigningAlgo } @@ -540,28 +549,35 @@ func (ks keystore) NewAccount(uid string, mnemonic string, bip39Passphrase strin privKey := algo.Generate()(derivedPriv) - return ks.writeLocalKey(uid, privKey, algo.Name()) + // check if the a key already exists with the same address and return an error + // if found + address := sdk.BytesToAccAddress(privKey.PubKey().Address()) + if _, err := ks.KeyByAddress(address); err == nil { + return nil, fmt.Errorf("account with address %s already exists in keyring, delete the key first if you want to recreate it", address) + } + + return ks.writeLocalKey(name, privKey, algo.Name()) } func (ks keystore) isSupportedSigningAlgo(algo SignatureAlgo) bool { return ks.options.SupportedAlgos.Contains(algo) } -func (ks keystore) Key(uid string) (Info, error) { - key := infoKey(uid) - - bs, err := ks.db.Get(string(key)) +func (ks keystore) key(infoKey string) (Info, error) { + bs, err := ks.db.Get(infoKey) if err != nil { - return nil, err + return nil, wrapKeyNotFound(err, infoKey) } - if len(bs.Data) == 0 { - return nil, sdkerrors.Wrap(sdkerrors.ErrKeyNotFound, uid) + return nil, sdkerrors.Wrap(sdkerrors.ErrKeyNotFound, infoKey) } - return unmarshalInfo(bs.Data) } +func (ks keystore) Key(uid string) (Info, error) { + return ks.key(infoKey(uid)) +} + // SupportedAlgorithms returns the keystore Options' supported signing algorithm. // for the keyring and Ledger. func (ks keystore) SupportedAlgorithms() (SigningAlgoList, SigningAlgoList) { @@ -733,8 +749,7 @@ func newRealPrompt(dir string, buf io.Reader) func(string) (string, error) { func (ks keystore) writeLocalKey(name string, priv types.PrivKey, algo hd.PubKeyType) (Info, error) { // encrypt private key using keyring pub := priv.PubKey() - - info := newLocalInfo(name, pub, string(legacy.Cdc.MustMarshalBinaryBare(priv)), algo) + info := newLocalInfo(name, pub, string(legacy.Cdc.MustMarshal(priv)), algo) if err := ks.writeInfo(info); err != nil { return nil, err } @@ -743,18 +758,16 @@ func (ks keystore) writeLocalKey(name string, priv types.PrivKey, algo hd.PubKey } func (ks keystore) writeInfo(info Info) error { - // write the info by key - key := infoKey(info.GetName()) + key := infoKeyBz(info.GetName()) serializedInfo := marshalInfo(info) exists, err := ks.existsInDb(info) - if exists { - return errors.New("public key already exist in keybase") - } - if err != nil { return err } + if exists { + return errors.New("public key already exists in keybase") + } err = ks.db.Set(keyring.Item{ Key: string(key), @@ -775,6 +788,8 @@ func (ks keystore) writeInfo(info Info) error { return nil } +// existsInDb returns true if key is in DB. Error is returned only when we have error +// different thant ErrKeyNotFound func (ks keystore) existsInDb(info Info) (bool, error) { if _, err := ks.db.Get(addrHexKeyAsString(info.GetAddress())); err == nil { return true, nil // address lookup succeeds - info exists @@ -782,7 +797,7 @@ func (ks keystore) existsInDb(info Info) (bool, error) { return false, err // received unexpected error - returns error } - if _, err := ks.db.Get(string(infoKey(info.GetName()))); err == nil { + if _, err := ks.db.Get(infoKey(info.GetName())); err == nil { return true, nil // uid lookup succeeds - info exists } else if err != keyring.ErrKeyNotFound { return false, err // received unexpected error - returns @@ -803,11 +818,13 @@ func (ks keystore) writeOfflineKey(name string, pub types.PubKey, algo hd.PubKey } func (ks keystore) writeMultisigKey(name string, pub types.PubKey) (Info, error) { - info := NewMultiInfo(name, pub) - err := ks.writeInfo(info) + info, err := NewMultiInfo(name, pub) if err != nil { return nil, err } + if err = ks.writeInfo(info); err != nil { + return nil, err + } return info, nil } diff --git a/crypto/keyring/keyring_ledger_test.go b/crypto/keyring/keyring_ledger_test.go index 306dcd9256..787d20422d 100644 --- a/crypto/keyring/keyring_ledger_test.go +++ b/crypto/keyring/keyring_ledger_test.go @@ -1,4 +1,5 @@ -//+build ledger test_ledger_mock +//go:build ledger || test_ledger_mock +// +build ledger test_ledger_mock package keyring @@ -9,7 +10,6 @@ import ( "github.com/stretchr/testify/require" "github.com/line/lbm-sdk/crypto/hd" - "github.com/line/lbm-sdk/types" sdk "github.com/line/lbm-sdk/types" ) @@ -28,9 +28,8 @@ func TestInMemoryCreateLedger(t *testing.T) { // The mock is available, check that the address is correct pubKey := ledger.GetPubKey() - pk, err := sdk.Bech32ifyPubKey(sdk.Bech32PubKeyTypeAccPub, pubKey) - require.NoError(t, err) - require.Equal(t, "linkpub1cqmsrdepqw830vud78huqu2dr5a6ptqn3rpjazec4krl6a5m4s955ywuur47zjasla7", pk) + expectedPkStr := "PubKeySecp256k1{038F17B38DF1EFC0714D1D3BA0AC1388C32E8B38AD87FD769BAC0B4A11DCE0EBE1}" + require.Equal(t, expectedPkStr, pubKey.String()) // Check that restoring the key gets the same results restoredKey, err := kb.Key("some_account") @@ -39,9 +38,7 @@ func TestInMemoryCreateLedger(t *testing.T) { require.Equal(t, "some_account", restoredKey.GetName()) require.Equal(t, TypeLedger, restoredKey.GetType()) pubKey = restoredKey.GetPubKey() - pk, err = sdk.Bech32ifyPubKey(sdk.Bech32PubKeyTypeAccPub, pubKey) - require.NoError(t, err) - require.Equal(t, "linkpub1cqmsrdepqw830vud78huqu2dr5a6ptqn3rpjazec4krl6a5m4s955ywuur47zjasla7", pk) + require.Equal(t, expectedPkStr, pubKey.String()) path, err := restoredKey.GetPath() require.NoError(t, err) @@ -80,7 +77,7 @@ func TestSignVerifyKeyRingWithLedger(t *testing.T) { require.True(t, i1.GetPubKey().VerifySignature(d1, s1)) require.True(t, bytes.Equal(s1, s2)) - localInfo, _, err := kb.NewMnemonic("test", English, types.FullFundraiserPath, hd.Secp256k1) + localInfo, _, err := kb.NewMnemonic("test", English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1) require.NoError(t, err) _, _, err = SignWithLedger(localInfo, d1) require.Error(t, err) @@ -108,9 +105,8 @@ func TestAltKeyring_SaveLedgerKey(t *testing.T) { // The mock is available, check that the address is correct require.Equal(t, "some_account", ledger.GetName()) pubKey := ledger.GetPubKey() - pk, err := sdk.Bech32ifyPubKey(sdk.Bech32PubKeyTypeAccPub, pubKey) - require.NoError(t, err) - require.Equal(t, "linkpub1cqmsrdepqw830vud78huqu2dr5a6ptqn3rpjazec4krl6a5m4s955ywuur47zjasla7", pk) + expectedPkStr := "PubKeySecp256k1{038F17B38DF1EFC0714D1D3BA0AC1388C32E8B38AD87FD769BAC0B4A11DCE0EBE1}" + require.Equal(t, expectedPkStr, pubKey.String()) // Check that restoring the key gets the same results restoredKey, err := keyring.Key("some_account") @@ -119,9 +115,7 @@ func TestAltKeyring_SaveLedgerKey(t *testing.T) { require.Equal(t, "some_account", restoredKey.GetName()) require.Equal(t, TypeLedger, restoredKey.GetType()) pubKey = restoredKey.GetPubKey() - pk, err = sdk.Bech32ifyPubKey(sdk.Bech32PubKeyTypeAccPub, pubKey) - require.NoError(t, err) - require.Equal(t, "linkpub1cqmsrdepqw830vud78huqu2dr5a6ptqn3rpjazec4krl6a5m4s955ywuur47zjasla7", pk) + require.Equal(t, expectedPkStr, pubKey.String()) path, err := restoredKey.GetPath() require.NoError(t, err) diff --git a/crypto/keyring/keyring_test.go b/crypto/keyring/keyring_test.go index 43bd9ed588..2c4c104a83 100644 --- a/crypto/keyring/keyring_test.go +++ b/crypto/keyring/keyring_test.go @@ -42,7 +42,7 @@ func TestNewKeyring(t *testing.T) { require.Equal(t, "unknown keyring backend fuzzy", err.Error()) mockIn.Reset("password\npassword\n") - info, _, err := kr.NewMnemonic("foo", English, sdk.FullFundraiserPath, hd.Secp256k1) + info, _, err := kr.NewMnemonic("foo", English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1) require.NoError(t, err) require.Equal(t, "foo", info.GetName()) } @@ -59,17 +59,17 @@ func TestKeyManagementKeyRing(t *testing.T) { require.Nil(t, err) require.Empty(t, l) - _, _, err = kb.NewMnemonic(n1, English, sdk.FullFundraiserPath, notSupportedAlgo{}) + _, _, err = kb.NewMnemonic(n1, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, notSupportedAlgo{}) require.Error(t, err, "ed25519 keys are currently not supported by keybase") // create some keys _, err = kb.Key(n1) require.Error(t, err) - i, _, err := kb.NewMnemonic(n1, English, sdk.FullFundraiserPath, algo) + i, _, err := kb.NewMnemonic(n1, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, algo) require.NoError(t, err) require.Equal(t, n1, i.GetName()) - _, _, err = kb.NewMnemonic(n2, English, sdk.FullFundraiserPath, algo) + _, _, err = kb.NewMnemonic(n2, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, algo) require.NoError(t, err) // we can get these keys @@ -138,10 +138,10 @@ func TestSignVerifyKeyRing(t *testing.T) { n1, n2, n3 := "some dude", "a dudette", "dude-ish" // create two users and get their info - i1, _, err := kb.NewMnemonic(n1, English, sdk.FullFundraiserPath, algo) + i1, _, err := kb.NewMnemonic(n1, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, algo) require.Nil(t, err) - i2, _, err := kb.NewMnemonic(n2, English, sdk.FullFundraiserPath, algo) + i2, _, err := kb.NewMnemonic(n2, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, algo) require.Nil(t, err) // let's try to sign some messages @@ -210,7 +210,7 @@ func TestExportImportKeyRing(t *testing.T) { kb, err := New("keybasename", "test", t.TempDir(), nil) require.NoError(t, err) - info, _, err := kb.NewMnemonic("john", English, sdk.FullFundraiserPath, hd.Secp256k1) + info, _, err := kb.NewMnemonic("john", English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1) require.NoError(t, err) require.Equal(t, info.GetName(), "john") @@ -244,7 +244,7 @@ func TestExportImportPubKeyKeyRing(t *testing.T) { algo := hd.Secp256k1 // CreateMnemonic a private-public key pair and ensure consistency - info, _, err := kb.NewMnemonic("john", English, sdk.FullFundraiserPath, algo) + info, _, err := kb.NewMnemonic("john", English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, algo) require.Nil(t, err) require.NotEqual(t, info, "") require.Equal(t, info.GetName(), "john") @@ -286,7 +286,7 @@ func TestAdvancedKeyManagementKeyRing(t *testing.T) { n1, n2 := "old-name", "new name" // make sure key works with initial password - _, _, err = kb.NewMnemonic(n1, English, sdk.FullFundraiserPath, algo) + _, _, err = kb.NewMnemonic(n1, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, algo) require.Nil(t, err, "%+v", err) _, err = kb.ExportPubKeyArmor(n1 + ".notreal") @@ -321,7 +321,7 @@ func TestSeedPhraseKeyRing(t *testing.T) { n1, n2 := "lost-key", "found-again" // make sure key works with initial password - info, mnemonic, err := kb.NewMnemonic(n1, English, sdk.FullFundraiserPath, algo) + info, mnemonic, err := kb.NewMnemonic(n1, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, algo) require.Nil(t, err, "%+v", err) require.Equal(t, n1, info.GetName()) require.NotEmpty(t, mnemonic) @@ -346,7 +346,7 @@ func TestKeyringKeybaseExportImportPrivKey(t *testing.T) { kb, err := New("keybasename", "test", t.TempDir(), nil) require.NoError(t, err) - _, _, err = kb.NewMnemonic("john", English, sdk.FullFundraiserPath, hd.Secp256k1) + _, _, err = kb.NewMnemonic("john", English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1) require.NoError(t, err) keystr, err := kb.ExportPrivKeyArmor("john", "somepassword") @@ -368,12 +368,12 @@ func TestKeyringKeybaseExportImportPrivKey(t *testing.T) { // try export non existing key _, err = kb.ExportPrivKeyArmor("john3", "wrongpassword") - require.Equal(t, "The specified item could not be found in the keyring", err.Error()) + require.EqualError(t, err, "john3.info: key not found") } func TestInMemoryLanguage(t *testing.T) { kb := NewInMemory() - _, _, err := kb.NewMnemonic("something", Japanese, sdk.FullFundraiserPath, hd.Secp256k1) + _, _, err := kb.NewMnemonic("something", Japanese, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1) require.Error(t, err) require.Equal(t, "unsupported language: only english is supported", err.Error()) } @@ -413,17 +413,17 @@ func TestInMemoryKeyManagement(t *testing.T) { require.Nil(t, err) require.Empty(t, l) - _, _, err = cstore.NewMnemonic(n1, English, sdk.FullFundraiserPath, notSupportedAlgo{}) + _, _, err = cstore.NewMnemonic(n1, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, notSupportedAlgo{}) require.Error(t, err, "ed25519 keys are currently not supported by keybase") // create some keys _, err = cstore.Key(n1) require.Error(t, err) - i, _, err := cstore.NewMnemonic(n1, English, sdk.FullFundraiserPath, algo) + i, _, err := cstore.NewMnemonic(n1, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, algo) require.NoError(t, err) require.Equal(t, n1, i.GetName()) - _, _, err = cstore.NewMnemonic(n2, English, sdk.FullFundraiserPath, algo) + _, _, err = cstore.NewMnemonic(n2, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, algo) require.NoError(t, err) // we can get these keys @@ -494,10 +494,10 @@ func TestInMemorySignVerify(t *testing.T) { n1, n2, n3 := "some dude", "a dudette", "dude-ish" // create two users and get their info - i1, _, err := cstore.NewMnemonic(n1, English, sdk.FullFundraiserPath, algo) + i1, _, err := cstore.NewMnemonic(n1, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, algo) require.Nil(t, err) - i2, _, err := cstore.NewMnemonic(n2, English, sdk.FullFundraiserPath, algo) + i2, _, err := cstore.NewMnemonic(n2, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, algo) require.Nil(t, err) // let's try to sign some messages @@ -568,7 +568,7 @@ func TestInMemoryExportImport(t *testing.T) { // make the storage with reasonable defaults cstore := NewInMemory() - info, _, err := cstore.NewMnemonic("john", English, sdk.FullFundraiserPath, hd.Secp256k1) + info, _, err := cstore.NewMnemonic("john", English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1) require.NoError(t, err) require.Equal(t, info.GetName(), "john") @@ -598,7 +598,7 @@ func TestInMemoryExportImport(t *testing.T) { func TestInMemoryExportImportPrivKey(t *testing.T) { kb := NewInMemory() - info, _, err := kb.NewMnemonic("john", English, sdk.FullFundraiserPath, hd.Secp256k1) + info, _, err := kb.NewMnemonic("john", English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1) require.NoError(t, err) require.Equal(t, info.GetName(), "john") priv1, err := kb.Key("john") @@ -626,7 +626,7 @@ func TestInMemoryExportImportPubKey(t *testing.T) { cstore := NewInMemory() // CreateMnemonic a private-public key pair and ensure consistency - info, _, err := cstore.NewMnemonic("john", English, sdk.FullFundraiserPath, hd.Secp256k1) + info, _, err := cstore.NewMnemonic("john", English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1) require.Nil(t, err) require.NotEqual(t, info, "") require.Equal(t, info.GetName(), "john") @@ -665,7 +665,7 @@ func TestInMemoryAdvancedKeyManagement(t *testing.T) { n1, n2 := "old-name", "new name" // make sure key works with initial password - _, _, err := cstore.NewMnemonic(n1, English, sdk.FullFundraiserPath, algo) + _, _, err := cstore.NewMnemonic(n1, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, algo) require.Nil(t, err, "%+v", err) // exporting requires the proper name and passphrase @@ -700,7 +700,7 @@ func TestInMemorySeedPhrase(t *testing.T) { n1, n2 := "lost-key", "found-again" // make sure key works with initial password - info, mnemonic, err := cstore.NewMnemonic(n1, English, sdk.FullFundraiserPath, algo) + info, mnemonic, err := cstore.NewMnemonic(n1, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, algo) require.Nil(t, err, "%+v", err) require.Equal(t, n1, info.GetName()) require.NotEmpty(t, mnemonic) @@ -726,7 +726,7 @@ func TestKeyChain_ShouldFailWhenAddingSameGeneratedAccount(t *testing.T) { require.NoError(t, err) // Given we create a mnemonic - _, seed, err := kr.NewMnemonic("test", English, "", hd.Secp256k1) + _, seed, err := kr.NewMnemonic("test", English, "", DefaultBIP39Passphrase, hd.Secp256k1) require.NoError(t, err) require.NoError(t, kr.Delete("test")) @@ -747,7 +747,7 @@ func ExampleNew() { sec := hd.Secp256k1 // Add keys and see they return in alphabetical order - bob, _, err := cstore.NewMnemonic("Bob", English, sdk.FullFundraiserPath, sec) + bob, _, err := cstore.NewMnemonic("Bob", English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, sec) if err != nil { // this should never happen fmt.Println(err) @@ -755,8 +755,8 @@ func ExampleNew() { // return info here just like in List fmt.Println(bob.GetName()) } - _, _, _ = cstore.NewMnemonic("Alice", English, sdk.FullFundraiserPath, sec) - _, _, _ = cstore.NewMnemonic("Carl", English, sdk.FullFundraiserPath, sec) + _, _, _ = cstore.NewMnemonic("Alice", English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, sec) + _, _, _ = cstore.NewMnemonic("Carl", English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, sec) info, _ := cstore.List() for _, i := range info { fmt.Println(i.GetName()) @@ -801,16 +801,16 @@ func TestAltKeyring_List(t *testing.T) { require.Empty(t, list) // Fails on creating unsupported pubKeyType - _, _, err = keyring.NewMnemonic("failing", English, sdk.FullFundraiserPath, notSupportedAlgo{}) + _, _, err = keyring.NewMnemonic("failing", English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, notSupportedAlgo{}) require.EqualError(t, err, ErrUnsupportedSigningAlgo.Error()) // Create 3 keys uid1, uid2, uid3 := "Zkey", "Bkey", "Rkey" - _, _, err = keyring.NewMnemonic(uid1, English, sdk.FullFundraiserPath, hd.Secp256k1) + _, _, err = keyring.NewMnemonic(uid1, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1) require.NoError(t, err) - _, _, err = keyring.NewMnemonic(uid2, English, sdk.FullFundraiserPath, hd.Secp256k1) + _, _, err = keyring.NewMnemonic(uid2, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1) require.NoError(t, err) - _, _, err = keyring.NewMnemonic(uid3, English, sdk.FullFundraiserPath, hd.Secp256k1) + _, _, err = keyring.NewMnemonic(uid3, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1) require.NoError(t, err) list, err = keyring.List() @@ -854,7 +854,7 @@ func TestAltKeyring_Get(t *testing.T) { require.NoError(t, err) uid := someKey - mnemonic, _, err := keyring.NewMnemonic(uid, English, sdk.FullFundraiserPath, hd.Secp256k1) + mnemonic, _, err := keyring.NewMnemonic(uid, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1) require.NoError(t, err) key, err := keyring.Key(uid) @@ -867,7 +867,7 @@ func TestAltKeyring_KeyByAddress(t *testing.T) { require.NoError(t, err) uid := someKey - mnemonic, _, err := keyring.NewMnemonic(uid, English, sdk.FullFundraiserPath, hd.Secp256k1) + mnemonic, _, err := keyring.NewMnemonic(uid, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1) require.NoError(t, err) key, err := keyring.KeyByAddress(mnemonic.GetAddress()) @@ -880,7 +880,7 @@ func TestAltKeyring_Delete(t *testing.T) { require.NoError(t, err) uid := someKey - _, _, err = keyring.NewMnemonic(uid, English, sdk.FullFundraiserPath, hd.Secp256k1) + _, _, err = keyring.NewMnemonic(uid, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1) require.NoError(t, err) list, err := keyring.List() @@ -900,7 +900,7 @@ func TestAltKeyring_DeleteByAddress(t *testing.T) { require.NoError(t, err) uid := someKey - mnemonic, _, err := keyring.NewMnemonic(uid, English, sdk.FullFundraiserPath, hd.Secp256k1) + mnemonic, _, err := keyring.NewMnemonic(uid, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1) require.NoError(t, err) list, err := keyring.List() @@ -942,9 +942,9 @@ func TestAltKeyring_SaveMultisig(t *testing.T) { keyring, err := New(t.Name(), BackendTest, t.TempDir(), nil) require.NoError(t, err) - mnemonic1, _, err := keyring.NewMnemonic("key1", English, sdk.FullFundraiserPath, hd.Secp256k1) + mnemonic1, _, err := keyring.NewMnemonic("key1", English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1) require.NoError(t, err) - mnemonic2, _, err := keyring.NewMnemonic("key2", English, sdk.FullFundraiserPath, hd.Secp256k1) + mnemonic2, _, err := keyring.NewMnemonic("key2", English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1) require.NoError(t, err) key := "multi" @@ -971,7 +971,7 @@ func TestAltKeyring_Sign(t *testing.T) { require.NoError(t, err) uid := "jack" - _, _, err = keyring.NewMnemonic(uid, English, sdk.FullFundraiserPath, hd.Secp256k1) + _, _, err = keyring.NewMnemonic(uid, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1) require.NoError(t, err) msg := []byte("some message") @@ -987,7 +987,7 @@ func TestAltKeyring_SignByAddress(t *testing.T) { require.NoError(t, err) uid := "jack" - mnemonic, _, err := keyring.NewMnemonic(uid, English, sdk.FullFundraiserPath, hd.Secp256k1) + mnemonic, _, err := keyring.NewMnemonic(uid, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1) require.NoError(t, err) msg := []byte("some message") @@ -1003,7 +1003,7 @@ func TestAltKeyring_ImportExportPrivKey(t *testing.T) { require.NoError(t, err) uid := theID - _, _, err = keyring.NewMnemonic(uid, English, sdk.FullFundraiserPath, hd.Secp256k1) + _, _, err = keyring.NewMnemonic(uid, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1) require.NoError(t, err) passphrase := "somePass" @@ -1029,7 +1029,7 @@ func TestAltKeyring_ImportExportPrivKey_ByAddress(t *testing.T) { require.NoError(t, err) uid := theID - mnemonic, _, err := keyring.NewMnemonic(uid, English, sdk.FullFundraiserPath, hd.Secp256k1) + mnemonic, _, err := keyring.NewMnemonic(uid, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1) require.NoError(t, err) passphrase := "somePass" @@ -1056,7 +1056,7 @@ func TestAltKeyring_ImportExportPubKey(t *testing.T) { require.NoError(t, err) uid := theID - _, _, err = keyring.NewMnemonic(uid, English, sdk.FullFundraiserPath, hd.Secp256k1) + _, _, err = keyring.NewMnemonic(uid, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1) require.NoError(t, err) armor, err := keyring.ExportPubKeyArmor(uid) @@ -1078,7 +1078,7 @@ func TestAltKeyring_ImportExportPubKey_ByAddress(t *testing.T) { require.NoError(t, err) uid := theID - mnemonic, _, err := keyring.NewMnemonic(uid, English, sdk.FullFundraiserPath, hd.Secp256k1) + mnemonic, _, err := keyring.NewMnemonic(uid, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1) require.NoError(t, err) armor, err := keyring.ExportPubKeyArmorByAddress(mnemonic.GetAddress()) @@ -1101,7 +1101,7 @@ func TestAltKeyring_UnsafeExportPrivKeyHex(t *testing.T) { uid := theID - _, _, err = keyring.NewMnemonic(uid, English, sdk.FullFundraiserPath, hd.Secp256k1) + _, _, err = keyring.NewMnemonic(uid, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1) require.NoError(t, err) unsafeKeyring := NewUnsafe(keyring) @@ -1123,11 +1123,11 @@ func TestAltKeyring_ConstructorSupportedAlgos(t *testing.T) { require.NoError(t, err) // should fail when using unsupported signing algorythm. - _, _, err = keyring.NewMnemonic("test", English, sdk.FullFundraiserPath, notSupportedAlgo{}) + _, _, err = keyring.NewMnemonic("test", English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, notSupportedAlgo{}) require.EqualError(t, err, "unsupported signing algo") // but works with default signing algo. - _, _, err = keyring.NewMnemonic("test", English, sdk.FullFundraiserPath, hd.Secp256k1) + _, _, err = keyring.NewMnemonic("test", English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1) require.NoError(t, err) // but we can create a new keybase with our provided algos. @@ -1139,7 +1139,7 @@ func TestAltKeyring_ConstructorSupportedAlgos(t *testing.T) { require.NoError(t, err) // now this new keyring does not fail when signing with provided algo - _, _, err = keyring2.NewMnemonic("test", English, sdk.FullFundraiserPath, notSupportedAlgo{}) + _, _, err = keyring2.NewMnemonic("test", English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, notSupportedAlgo{}) require.NoError(t, err) } diff --git a/crypto/keyring/output.go b/crypto/keyring/output.go index 974f76db79..391ffc1d98 100644 --- a/crypto/keyring/output.go +++ b/crypto/keyring/output.go @@ -1,106 +1,78 @@ package keyring import ( + "github.com/line/lbm-sdk/codec" + codectypes "github.com/line/lbm-sdk/codec/types" + cryptotypes "github.com/line/lbm-sdk/crypto/types" sdk "github.com/line/lbm-sdk/types" ) +// TODO: Move this file to client/keys +// Use protobuf interface marshaler rather then generic JSON + // KeyOutput defines a structure wrapping around an Info object used for output // functionality. type KeyOutput struct { - Name string `json:"name" yaml:"name"` - Type string `json:"type" yaml:"type"` - Address string `json:"address" yaml:"address"` - PubKey string `json:"pubkey" yaml:"pubkey"` - Mnemonic string `json:"mnemonic,omitempty" yaml:"mnemonic"` - Threshold uint `json:"threshold,omitempty" yaml:"threshold"` - PubKeys []multisigPubKeyOutput `json:"pubkeys,omitempty" yaml:"pubkeys"` + Name string `json:"name" yaml:"name"` + Type string `json:"type" yaml:"type"` + Address string `json:"address" yaml:"address"` + PubKey string `json:"pubkey" yaml:"pubkey"` + Mnemonic string `json:"mnemonic,omitempty" yaml:"mnemonic"` } // NewKeyOutput creates a default KeyOutput instance without Mnemonic, Threshold and PubKeys -func NewKeyOutput(name, keyType, address, pubkey string) KeyOutput { - return KeyOutput{ - Name: name, - Type: keyType, - Address: address, - PubKey: pubkey, - } -} - -type multisigPubKeyOutput struct { - Address string `json:"address" yaml:"address"` - PubKey string `json:"pubkey" yaml:"pubkey"` - Weight uint `json:"weight" yaml:"weight"` -} - -// Bech32KeysOutput returns a slice of KeyOutput objects, each with the "acc" -// Bech32 prefixes, given a slice of Info objects. It returns an error if any -// call to Bech32KeyOutput fails. -func Bech32KeysOutput(infos []Info) ([]KeyOutput, error) { - kos := make([]KeyOutput, len(infos)) - for i, info := range infos { - ko, err := Bech32KeyOutput(info) - if err != nil { - return nil, err - } - kos[i] = ko - } - - return kos, nil -} - -// Bech32ConsKeyOutput create a KeyOutput in with "cons" Bech32 prefixes. -func Bech32ConsKeyOutput(keyInfo Info) (KeyOutput, error) { - consAddr := sdk.BytesToConsAddress(keyInfo.GetPubKey().Address()) - - bechPubKey, err := sdk.Bech32ifyPubKey(sdk.Bech32PubKeyTypeConsPub, keyInfo.GetPubKey()) +func NewKeyOutput(name string, keyType KeyType, a sdk.Address, pk cryptotypes.PubKey) (KeyOutput, error) { // nolint:interfacer + apk, err := codectypes.NewAnyWithValue(pk) if err != nil { return KeyOutput{}, err } - - return NewKeyOutput(keyInfo.GetName(), keyInfo.GetType().String(), consAddr.String(), bechPubKey), nil -} - -// Bech32ValKeyOutput create a KeyOutput in with "val" Bech32 prefixes. -func Bech32ValKeyOutput(keyInfo Info) (KeyOutput, error) { - valAddr := sdk.BytesToValAddress(keyInfo.GetPubKey().Address()) - - bechPubKey, err := sdk.Bech32ifyPubKey(sdk.Bech32PubKeyTypeValPub, keyInfo.GetPubKey()) + bz, err := codec.ProtoMarshalJSON(apk, nil) if err != nil { return KeyOutput{}, err } + return KeyOutput{ + Name: name, + Type: keyType.String(), + Address: a.String(), + PubKey: string(bz), + }, nil +} - return NewKeyOutput(keyInfo.GetName(), keyInfo.GetType().String(), valAddr.String(), bechPubKey), nil +// MkConsKeyOutput create a KeyOutput in with "cons" Bech32 prefixes. +func MkConsKeyOutput(keyInfo Info) (KeyOutput, error) { + pk := keyInfo.GetPubKey() + addr := sdk.BytesToConsAddress(pk.Address()) + return NewKeyOutput(keyInfo.GetName(), keyInfo.GetType(), addr, pk) } -// Bech32KeyOutput create a KeyOutput in with "acc" Bech32 prefixes. If the +// MkValKeyOutput create a KeyOutput in with "val" Bech32 prefixes. +func MkValKeyOutput(keyInfo Info) (KeyOutput, error) { + pk := keyInfo.GetPubKey() + addr := sdk.BytesToValAddress(pk.Address()) + return NewKeyOutput(keyInfo.GetName(), keyInfo.GetType(), addr, pk) +} + +// MkAccKeyOutput create a KeyOutput in with "acc" Bech32 prefixes. If the // public key is a multisig public key, then the threshold and constituent // public keys will be added. -func Bech32KeyOutput(keyInfo Info) (KeyOutput, error) { - accAddr := sdk.BytesToAccAddress(keyInfo.GetPubKey().Address()) - bechPubKey, err := sdk.Bech32ifyPubKey(sdk.Bech32PubKeyTypeAccPub, keyInfo.GetPubKey()) - if err != nil { - return KeyOutput{}, err - } - - ko := NewKeyOutput(keyInfo.GetName(), keyInfo.GetType().String(), accAddr.String(), bechPubKey) - - if mInfo, ok := keyInfo.(*multiInfo); ok { - pubKeys := make([]multisigPubKeyOutput, len(mInfo.PubKeys)) - - for i, pk := range mInfo.PubKeys { - accAddr := sdk.BytesToAccAddress(pk.PubKey.Address()) - - bechPubKey, err := sdk.Bech32ifyPubKey(sdk.Bech32PubKeyTypeAccPub, pk.PubKey) - if err != nil { - return KeyOutput{}, err - } +func MkAccKeyOutput(keyInfo Info) (KeyOutput, error) { + pk := keyInfo.GetPubKey() + addr := sdk.BytesToAccAddress(pk.Address()) + return NewKeyOutput(keyInfo.GetName(), keyInfo.GetType(), addr, pk) +} - pubKeys[i] = multisigPubKeyOutput{accAddr.String(), bechPubKey, pk.Weight} +// MkAccKeysOutput returns a slice of KeyOutput objects, each with the "acc" +// Bech32 prefixes, given a slice of Info objects. It returns an error if any +// call to MkKeyOutput fails. +func MkAccKeysOutput(infos []Info) ([]KeyOutput, error) { + kos := make([]KeyOutput, len(infos)) + var err error + for i, info := range infos { + kos[i], err = MkAccKeyOutput(info) + if err != nil { + return nil, err } - - ko.Threshold = mInfo.Threshold - ko.PubKeys = pubKeys } - return ko, nil + return kos, nil } diff --git a/crypto/keyring/output_test.go b/crypto/keyring/output_test.go index 092f02714d..baddcf4fc7 100644 --- a/crypto/keyring/output_test.go +++ b/crypto/keyring/output_test.go @@ -1,6 +1,7 @@ package keyring import ( + "fmt" "testing" "github.com/stretchr/testify/require" @@ -12,20 +13,18 @@ import ( ) func TestBech32KeysOutput(t *testing.T) { - tmpKey := secp256k1.GenPrivKey().PubKey() - bechTmpKey := sdk.MustBech32ifyPubKey(sdk.Bech32PubKeyTypeAccPub, tmpKey) - tmpAddr := sdk.BytesToAccAddress(tmpKey.Address()) + sk := secp256k1.PrivKey{Key: []byte{154, 49, 3, 117, 55, 232, 249, 20, 205, 216, 102, 7, 136, 72, 177, 2, 131, 202, 234, 81, 31, 208, 46, 244, 179, 192, 167, 163, 142, 117, 246, 13}} + tmpKey := sk.PubKey() + multisigPk := kmultisig.NewLegacyAminoPubKey(1, []types.PubKey{tmpKey}) - multisigPks := kmultisig.NewLegacyAminoPubKey(1, []types.PubKey{tmpKey}) - multiInfo := NewMultiInfo("multisig", multisigPks) - accAddr := sdk.BytesToAccAddress(multiInfo.GetPubKey().Address()) - bechPubKey := sdk.MustBech32ifyPubKey(sdk.Bech32PubKeyTypeAccPub, multiInfo.GetPubKey()) - - expectedOutput := NewKeyOutput(multiInfo.GetName(), multiInfo.GetType().String(), accAddr.String(), bechPubKey) - expectedOutput.Threshold = 1 - expectedOutput.PubKeys = []multisigPubKeyOutput{{tmpAddr.String(), bechTmpKey, 1}} + info, err := NewMultiInfo("multisig", multisigPk) + require.NoError(t, err) + accAddr := sdk.BytesToAccAddress(info.GetPubKey().Address()) + expectedOutput, err := NewKeyOutput(info.GetName(), info.GetType(), accAddr, multisigPk) + require.NoError(t, err) - outputs, err := Bech32KeysOutput([]Info{multiInfo}) + out, err := MkAccKeyOutput(info) require.NoError(t, err) - require.Equal(t, expectedOutput, outputs[0]) + require.Equal(t, expectedOutput, out) + require.Equal(t, `{Name:multisig Type:multi Address:link1azx3qquuvjfvs7khudad7e3jnrsqrtlpkhsfeg PubKey:{"@type":"/lbm.crypto.multisig.LegacyAminoPubKey","threshold":1,"public_keys":[{"@type":"/lbm.crypto.secp256k1.PubKey","key":"AurroA7jvfPd1AadmmOvWM2rJSwipXfRf8yD6pLbA2DJ"}]} Mnemonic:}`, fmt.Sprintf("%+v", out)) } diff --git a/crypto/keyring/types_test.go b/crypto/keyring/types_test.go index 1e2355ab72..b316cdca7e 100644 --- a/crypto/keyring/types_test.go +++ b/crypto/keyring/types_test.go @@ -2,6 +2,7 @@ package keyring import ( "encoding/hex" + "fmt" "testing" "github.com/stretchr/testify/require" @@ -13,7 +14,9 @@ import ( func Test_writeReadLedgerInfo(t *testing.T) { tmpKey := make([]byte, secp256k1.PubKeySize) - bz, _ := hex.DecodeString("035AD6810A47F073553FF30D2FCC7E0D3B1C0B74B61A1AAA2582344037151E143A") + hexPK := "035AD6810A47F073553FF30D2FCC7E0D3B1C0B74B61A1AAA2582344037151E143A" + bz, err := hex.DecodeString(hexPK) + require.NoError(t, err) copy(tmpKey[:], bz) lInfo := newLedgerInfo("some_name", &secp256k1.PubKey{Key: tmpKey}, *hd.NewFundraiserParams(5, sdk.CoinType, 1), hd.Secp256k1Type) @@ -23,8 +26,8 @@ func Test_writeReadLedgerInfo(t *testing.T) { require.NoError(t, err) require.Equal(t, "m/44'/438'/5'/0/1", path.String()) require.Equal(t, - "linkpub1cqmsrdepqddddqg2glc8x4fl7vxjlnr7p5a3czm5kcdp4239sg6yqdc4rc2r5tnrct6", - sdk.MustBech32ifyPubKey(sdk.Bech32PubKeyTypeAccPub, lInfo.GetPubKey())) + fmt.Sprintf("PubKeySecp256k1{%s}", hexPK), + lInfo.GetPubKey().String()) // Serialize and restore serialized := marshalInfo(lInfo) diff --git a/crypto/keys/ed25519/doc.go b/crypto/keys/ed25519/doc.go new file mode 100644 index 0000000000..6d77365c48 --- /dev/null +++ b/crypto/keys/ed25519/doc.go @@ -0,0 +1,11 @@ +package ed25519 + +/* +This package contains a wrapper around crypto/ed22519 to make it comply with the crypto interfaces. + +This package employs zip215 rules. We use https://github.com/hdevalence/ed25519consensus verification function. Ths is done in order to keep compatibility with Tendermints ed25519 implementation. + - https://github.com/tendermint/tendermint/blob/master/crypto/ed25519/ed25519.go#L155 + +This package works with correctly generated signatures. To read more about what this means see https://hdevalence.ca/blog/2020-10-04-its-25519am + +*/ diff --git a/crypto/keys/ed25519/ed25519.go b/crypto/keys/ed25519/ed25519.go index 9b555450ae..8b9d1972a0 100644 --- a/crypto/keys/ed25519/ed25519.go +++ b/crypto/keys/ed25519/ed25519.go @@ -6,6 +6,7 @@ import ( "fmt" "io" + "github.com/hdevalence/ed25519consensus" "github.com/line/ostracon/crypto" "github.com/line/ostracon/crypto/tmhash" @@ -116,7 +117,8 @@ func (privKey *PrivKey) UnmarshalAminoJSON(bz []byte) error { return privKey.UnmarshalAmino(bz) } -// GenPrivKey generates a new ed25519 private key. +// GenPrivKey generates a new ed25519 private key. These ed25519 keys must not +// be used in SDK apps except in a tendermint validator context. // It uses OS randomness in conjunction with the current global random seed // in tendermint/libs/common to generate the private key. func GenPrivKey() *PrivKey { @@ -137,6 +139,7 @@ func genPrivKey(rand io.Reader) *PrivKey { // GenPrivKeyFromSecret hashes the secret with SHA2, and uses // that 32 byte output to create the private key. +// NOTE: ed25519 keys must not be used in SDK apps except in a tendermint validator context. // NOTE: secret should be the output of a KDF like bcrypt, // if it's derived from user input. func GenPrivKeyFromSecret(secret []byte) *PrivKey { @@ -151,10 +154,14 @@ var _ cryptotypes.PubKey = &PubKey{} var _ codec.AminoMarshaler = &PubKey{} // Address is the SHA256-20 of the raw pubkey bytes. +// It doesn't implement ADR-28 addresses and it must not be used +// in SDK except in a tendermint validator context. func (pubKey *PubKey) Address() crypto.Address { if len(pubKey.Key) != PubKeySize { panic("pubkey is incorrect size") } + // For ADR-28 compatible address we would need to + // return address.Hash(proto.MessageName(pubKey), pubKey.Key) return crypto.Address(tmhash.SumTruncated(pubKey.Key)) } @@ -169,9 +176,11 @@ func (pubKey *PubKey) VerifySignature(msg []byte, sig []byte) bool { return false } - return ed25519.Verify(pubKey.Key, msg, sig) + // uses https://github.com/hdevalence/ed25519consensus.Verify to comply with zip215 verification rules + return ed25519consensus.Verify(pubKey.Key, msg, sig) } +// String returns Hex representation of a pubkey with it's type func (pubKey *PubKey) String() string { return fmt.Sprintf("PubKeyEd25519{%X}", pubKey.Key) } diff --git a/crypto/keys/ed25519/ed25519_test.go b/crypto/keys/ed25519/ed25519_test.go index 3d7876cf60..f69b39678c 100644 --- a/crypto/keys/ed25519/ed25519_test.go +++ b/crypto/keys/ed25519/ed25519_test.go @@ -11,6 +11,8 @@ import ( "github.com/stretchr/testify/require" "github.com/line/lbm-sdk/codec" + "github.com/line/lbm-sdk/codec/types" + cryptocodec "github.com/line/lbm-sdk/crypto/codec" ed25519 "github.com/line/lbm-sdk/crypto/keys/ed25519" "github.com/line/lbm-sdk/crypto/keys/secp256k1" cryptotypes "github.com/line/lbm-sdk/crypto/types" @@ -84,6 +86,12 @@ func TestPubKeyEquals(t *testing.T) { } } +func TestAddressEd25519(t *testing.T) { + pk := ed25519.PubKey{[]byte{125, 80, 29, 208, 159, 53, 119, 198, 73, 53, 187, 33, 199, 144, 62, 255, 1, 235, 117, 96, 128, 211, 17, 45, 34, 64, 189, 165, 33, 182, 54, 206}} + addr := pk.Address() + require.Len(t, addr, 20, "Address must be 20 bytes long") +} + func TestPrivKeyEquals(t *testing.T) { ed25519PrivKey := ed25519.GenPrivKey() @@ -154,11 +162,11 @@ func TestMarshalAmino(t *testing.T) { for _, tc := range testCases { t.Run(tc.desc, func(t *testing.T) { // Do a round trip of encoding/decoding binary. - bz, err := aminoCdc.MarshalBinaryBare(tc.msg) + bz, err := aminoCdc.Marshal(tc.msg) require.NoError(t, err) require.Equal(t, tc.expBinary, bz) - err = aminoCdc.UnmarshalBinaryBare(bz, tc.typ) + err = aminoCdc.Unmarshal(bz, tc.typ) require.NoError(t, err) require.Equal(t, tc.msg, tc.typ) @@ -195,7 +203,7 @@ func TestMarshalAmino_BackwardsCompatibility(t *testing.T) { "ed25519 private key, binary", tmPrivKey, privKey, - aminoCdc.MarshalBinaryBare, + aminoCdc.Marshal, }, { "ed25519 private key, JSON", @@ -207,7 +215,7 @@ func TestMarshalAmino_BackwardsCompatibility(t *testing.T) { "ed25519 public key, binary", tmPubKey, pubKey, - aminoCdc.MarshalBinaryBare, + aminoCdc.Marshal, }, { "ed25519 public key, JSON", @@ -228,3 +236,21 @@ func TestMarshalAmino_BackwardsCompatibility(t *testing.T) { }) } } + +func TestMarshalJSON(t *testing.T) { + require := require.New(t) + privKey := ed25519.GenPrivKey() + pk := privKey.PubKey() + + registry := types.NewInterfaceRegistry() + cryptocodec.RegisterInterfaces(registry) + cdc := codec.NewProtoCodec(registry) + + bz, err := cdc.MarshalInterfaceJSON(pk) + require.NoError(err) + + var pk2 cryptotypes.PubKey + err = cdc.UnmarshalInterfaceJSON(bz, &pk2) + require.NoError(err) + require.True(pk2.Equals(pk)) +} diff --git a/crypto/keys/ed25519/keys.pb.go b/crypto/keys/ed25519/keys.pb.go index 06a4e2c611..dd734f5380 100644 --- a/crypto/keys/ed25519/keys.pb.go +++ b/crypto/keys/ed25519/keys.pb.go @@ -24,11 +24,11 @@ var _ = math.Inf // proto package needs to be updated. const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package -// PubKey defines a ed25519 public key -// Key is the compressed form of the pubkey. The first byte depends is a 0x02 byte -// if the y-coordinate is the lexicographically largest of the two associated with -// the x-coordinate. Otherwise the first byte is a 0x03. -// This prefix is followed with the x-coordinate. +// PubKey is an ed25519 public key for handling Tendermint keys in SDK. +// It's needed for Any serialization and SDK compatibility. +// It must not be used in a non Tendermint key context because it doesn't implement +// ADR-28. Nevertheless, you will like to use ed25519 in app user level +// then you must create a new proto message and follow ADR-28 for Address construction. type PubKey struct { Key crypto_ed25519.PublicKey `protobuf:"bytes,1,opt,name=key,proto3,casttype=crypto/ed25519.PublicKey" json:"key,omitempty"` } @@ -72,7 +72,8 @@ func (m *PubKey) GetKey() crypto_ed25519.PublicKey { return nil } -// PrivKey defines a ed25519 private key. +// Deprecated: PrivKey defines a ed25519 private key. +// NOTE: ed25519 keys must not be used in SDK apps except in a tendermint validator context. type PrivKey struct { Key crypto_ed25519.PrivateKey `protobuf:"bytes,1,opt,name=key,proto3,casttype=crypto/ed25519.PrivateKey" json:"key,omitempty"` } diff --git a/crypto/keys/internal/benchmarking/bench.go b/crypto/keys/internal/benchmarking/bench.go index 37d70870eb..9952cafd68 100644 --- a/crypto/keys/internal/benchmarking/bench.go +++ b/crypto/keys/internal/benchmarking/bench.go @@ -1,6 +1,7 @@ package benchmarking import ( + "crypto/rand" "io" "testing" @@ -13,21 +14,12 @@ import ( // Use of this source code is governed by a BSD-style // license that can be found at the bottom of this file. -type zeroReader struct{} - -func (zeroReader) Read(buf []byte) (int, error) { - for i := range buf { - buf[i] = 0 - } - return len(buf), nil -} - // BenchmarkKeyGeneration benchmarks the given key generation algorithm using // a dummy reader. func BenchmarkKeyGeneration(b *testing.B, generateKey func(reader io.Reader) types.PrivKey) { - var zero zeroReader + b.ReportAllocs() for i := 0; i < b.N; i++ { - generateKey(zero) + generateKey(rand.Reader) } } diff --git a/crypto/keys/internal/ecdsa/doc.go b/crypto/keys/internal/ecdsa/doc.go new file mode 100644 index 0000000000..a27b9caf9a --- /dev/null +++ b/crypto/keys/internal/ecdsa/doc.go @@ -0,0 +1,3 @@ +// Package ECDSA implements Cosmos-SDK compatible ECDSA public and private key. The keys +// can be serialized. +package ecdsa diff --git a/crypto/keys/internal/ecdsa/privkey.go b/crypto/keys/internal/ecdsa/privkey.go new file mode 100644 index 0000000000..690c07670d --- /dev/null +++ b/crypto/keys/internal/ecdsa/privkey.go @@ -0,0 +1,127 @@ +package ecdsa + +import ( + "crypto/ecdsa" + "crypto/elliptic" + "crypto/rand" + "crypto/sha256" + "fmt" + "math/big" +) + +// p256Order returns the curve order for the secp256r1 curve +// NOTE: this is specific to the secp256r1/P256 curve, +// and not taken from the domain params for the key itself +// (which would be a more generic approach for all EC). +var p256Order = elliptic.P256().Params().N + +// p256HalfOrder returns half the curve order +// a bit shift of 1 to the right (Rsh) is equivalent +// to division by 2, only faster. +var p256HalfOrder = new(big.Int).Rsh(p256Order, 1) + +// IsSNormalized returns true for the integer sigS if sigS falls in +// lower half of the curve order +func IsSNormalized(sigS *big.Int) bool { + return sigS.Cmp(p256HalfOrder) != 1 +} + +// NormalizeS will invert the s value if not already in the lower half +// of curve order value +func NormalizeS(sigS *big.Int) *big.Int { + + if IsSNormalized(sigS) { + return sigS + } + + return new(big.Int).Sub(p256Order, sigS) +} + +// signatureRaw will serialize signature to R || S. +// R, S are padded to 32 bytes respectively. +// code roughly copied from secp256k1_nocgo.go +func signatureRaw(r *big.Int, s *big.Int) []byte { + + rBytes := r.Bytes() + sBytes := s.Bytes() + sigBytes := make([]byte, 64) + // 0 pad the byte arrays from the left if they aren't big enough. + copy(sigBytes[32-len(rBytes):32], rBytes) + copy(sigBytes[64-len(sBytes):64], sBytes) + return sigBytes +} + +// GenPrivKey generates a new secp256r1 private key. It uses operating +// system randomness. +func GenPrivKey(curve elliptic.Curve) (PrivKey, error) { + key, err := ecdsa.GenerateKey(curve, rand.Reader) + if err != nil { + return PrivKey{}, err + } + return PrivKey{*key}, nil +} + +type PrivKey struct { + ecdsa.PrivateKey +} + +// PubKey returns ECDSA public key associated with this private key. +func (sk *PrivKey) PubKey() PubKey { + return PubKey{sk.PublicKey, nil} +} + +// Bytes serialize the private key using big-endian. +func (sk *PrivKey) Bytes() []byte { + if sk == nil { + return nil + } + fieldSize := (sk.Curve.Params().BitSize + 7) / 8 + bz := make([]byte, fieldSize) + sk.D.FillBytes(bz) + return bz +} + +// Sign hashes and signs the message using ECDSA. Implements SDK +// PrivKey interface. +// NOTE: this now calls the ecdsa Sign function +// (not method!) directly as the s value of the signature is needed to +// low-s normalize the signature value +// See issue: https://github.com/cosmos/cosmos-sdk/issues/9723 +// It then raw encodes the signature as two fixed width 32-byte values +// concatenated, reusing the code copied from secp256k1_nocgo.go +func (sk *PrivKey) Sign(msg []byte) ([]byte, error) { + + digest := sha256.Sum256(msg) + r, s, err := ecdsa.Sign(rand.Reader, &sk.PrivateKey, digest[:]) + + if err != nil { + return nil, err + } + + normS := NormalizeS(s) + return signatureRaw(r, normS), nil +} + +// String returns a string representation of the public key based on the curveName. +func (sk *PrivKey) String(name string) string { + return name + "{-}" +} + +// MarshalTo implements proto.Marshaler interface. +func (sk *PrivKey) MarshalTo(dAtA []byte) (int, error) { + bz := sk.Bytes() + copy(dAtA, bz) + return len(bz), nil +} + +// Unmarshal implements proto.Marshaler interface. +func (sk *PrivKey) Unmarshal(bz []byte, curve elliptic.Curve, expectedSize int) error { + if len(bz) != expectedSize { + return fmt.Errorf("wrong ECDSA SK bytes, expecting %d bytes", expectedSize) + } + + sk.Curve = curve + sk.D = new(big.Int).SetBytes(bz) + sk.X, sk.Y = curve.ScalarBaseMult(bz) + return nil +} diff --git a/crypto/keys/internal/ecdsa/privkey_internal_test.go b/crypto/keys/internal/ecdsa/privkey_internal_test.go new file mode 100644 index 0000000000..6c3ec6fb15 --- /dev/null +++ b/crypto/keys/internal/ecdsa/privkey_internal_test.go @@ -0,0 +1,101 @@ +package ecdsa + +import ( + "crypto/ecdsa" + "crypto/elliptic" + "crypto/sha256" + "math/big" + "testing" + + "github.com/line/ostracon/crypto" + + "github.com/stretchr/testify/suite" +) + +func TestSKSuite(t *testing.T) { + suite.Run(t, new(SKSuite)) +} + +type SKSuite struct{ CommonSuite } + +func (suite *SKSuite) TestString() { + const prefix = "abc" + suite.Require().Equal(prefix+"{-}", suite.sk.String(prefix)) +} + +func (suite *SKSuite) TestPubKey() { + pk := suite.sk.PubKey() + suite.True(suite.sk.PublicKey.Equal(&pk.PublicKey)) +} + +func (suite *SKSuite) TestBytes() { + bz := suite.sk.Bytes() + suite.Len(bz, 32) + var sk *PrivKey + suite.Nil(sk.Bytes()) +} + +func (suite *SKSuite) TestMarshal() { + require := suite.Require() + const size = 32 + + var buffer = make([]byte, size) + suite.sk.MarshalTo(buffer) + + var sk = new(PrivKey) + err := sk.Unmarshal(buffer, secp256r1, size) + require.NoError(err) + require.True(sk.Equal(&suite.sk.PrivateKey)) +} + +func (suite *SKSuite) TestSign() { + require := suite.Require() + + msg := crypto.CRandBytes(1000) + sig, err := suite.sk.Sign(msg) + require.NoError(err) + sigCpy := make([]byte, len(sig)) + copy(sigCpy, sig) + require.True(suite.pk.VerifySignature(msg, sigCpy)) + + // Mutate the signature + for i := range sig { + sigCpy[i] ^= byte(i + 1) + require.False(suite.pk.VerifySignature(msg, sigCpy)) + } + + // mutate the signature by scalar neg'ing the s value + // to give a high-s signature, valid ECDSA but should + // be invalid with Cosmos signatures. + // code mostly copied from privkey/pubkey.go + + // extract the r, s values from sig + r := new(big.Int).SetBytes(sig[:32]) + low_s := new(big.Int).SetBytes(sig[32:64]) + + // test that NormalizeS simply returns an already + // normalized s + require.Equal(NormalizeS(low_s), low_s) + + // flip the s value into high order of curve P256 + // leave r untouched! + high_s := new(big.Int).Mod(new(big.Int).Neg(low_s), elliptic.P256().Params().N) + + require.False(suite.pk.VerifySignature(msg, signatureRaw(r, high_s))) + + // Valid signature using low_s, but too long + sigCpy = make([]byte, len(sig)+2) + copy(sigCpy, sig) + sigCpy[65] = byte('A') + + require.False(suite.pk.VerifySignature(msg, sigCpy)) + + // check whether msg can be verified with same key, and high_s + // value using "regular" ecdsa signature + hash := sha256.Sum256([]byte(msg)) + require.True(ecdsa.Verify(&suite.pk.PublicKey, hash[:], r, high_s)) + + // Mutate the message + msg[1] ^= byte(2) + require.False(suite.pk.VerifySignature(msg, sig)) +} diff --git a/crypto/keys/internal/ecdsa/pubkey.go b/crypto/keys/internal/ecdsa/pubkey.go new file mode 100644 index 0000000000..95423ae42d --- /dev/null +++ b/crypto/keys/internal/ecdsa/pubkey.go @@ -0,0 +1,108 @@ +package ecdsa + +import ( + "crypto/ecdsa" + "crypto/elliptic" + "crypto/sha256" + "fmt" + "math/big" + + tmcrypto "github.com/line/ostracon/crypto" + + "github.com/line/lbm-sdk/types/address" + "github.com/line/lbm-sdk/types/errors" +) + +// signatureFromBytes function roughly copied from secp256k1_nocgo.go +// Read Signature struct from R || S. Caller needs to ensure that +// len(sigStr) == 64. +func signatureFromBytes(sigStr []byte) *signature { + return &signature{ + R: new(big.Int).SetBytes(sigStr[:32]), + S: new(big.Int).SetBytes(sigStr[32:64]), + } +} + +// signature holds the r and s values of an ECDSA signature. +type signature struct { + R, S *big.Int +} + +type PubKey struct { + ecdsa.PublicKey + + // cache + address tmcrypto.Address +} + +// Address gets the address associated with a pubkey. If no address exists, it returns a newly created ADR-28 address +// for ECDSA keys. +// protoName is a concrete proto structure id. +func (pk *PubKey) Address(protoName string) tmcrypto.Address { + if pk.address == nil { + pk.address = address.Hash(protoName, pk.Bytes()) + } + return pk.address +} + +// Bytes returns the byte representation of the public key using a compressed form +// specified in section 4.3.6 of ANSI X9.62 with first byte being the curve type. +func (pk *PubKey) Bytes() []byte { + if pk == nil { + return nil + } + return elliptic.MarshalCompressed(pk.Curve, pk.X, pk.Y) +} + +// VerifySignature checks if sig is a valid ECDSA signature for msg. +// This includes checking for low-s normalized signatures +// where the s integer component of the signature is in the +// lower half of the curve order +// 7/21/21 - expects raw encoded signature (fixed-width 64-bytes, R || S) +func (pk *PubKey) VerifySignature(msg []byte, sig []byte) bool { + + // check length for raw signature + // which is two 32-byte padded big.Ints + // concatenated + // NOT DER! + + if len(sig) != 64 { + return false + } + + s := signatureFromBytes(sig) + if !IsSNormalized(s.S) { + return false + } + + h := sha256.Sum256(msg) + return ecdsa.Verify(&pk.PublicKey, h[:], s.R, s.S) +} + +// String returns a string representation of the public key based on the curveName. +func (pk *PubKey) String(curveName string) string { + return fmt.Sprintf("%s{%X}", curveName, pk.Bytes()) +} + +// **** Proto Marshaler **** + +// MarshalTo implements proto.Marshaler interface. +func (pk *PubKey) MarshalTo(dAtA []byte) (int, error) { + bz := pk.Bytes() + copy(dAtA, bz) + return len(bz), nil +} + +// Unmarshal implements proto.Marshaler interface. +func (pk *PubKey) Unmarshal(bz []byte, curve elliptic.Curve, expectedSize int) error { + if len(bz) != expectedSize { + return errors.Wrapf(errors.ErrInvalidPubKey, "wrong ECDSA PK bytes, expecting %d bytes, got %d", expectedSize, len(bz)) + } + cpk := ecdsa.PublicKey{Curve: curve} + cpk.X, cpk.Y = elliptic.UnmarshalCompressed(curve, bz) + if cpk.X == nil || cpk.Y == nil { + return errors.Wrapf(errors.ErrInvalidPubKey, "wrong ECDSA PK bytes, unknown curve type: %d", bz[0]) + } + pk.PublicKey = cpk + return nil +} diff --git a/crypto/keys/internal/ecdsa/pubkey_internal_test.go b/crypto/keys/internal/ecdsa/pubkey_internal_test.go new file mode 100644 index 0000000000..88dc95a3bb --- /dev/null +++ b/crypto/keys/internal/ecdsa/pubkey_internal_test.go @@ -0,0 +1,71 @@ +package ecdsa + +import ( + "crypto/elliptic" + "encoding/hex" + "testing" + + "github.com/stretchr/testify/suite" +) + +var secp256r1 = elliptic.P256() + +func GenSecp256r1() (PrivKey, error) { + return GenPrivKey(secp256r1) +} + +func TestPKSuite(t *testing.T) { + suite.Run(t, new(PKSuite)) +} + +type CommonSuite struct { + suite.Suite + pk PubKey + sk PrivKey +} + +func (suite *CommonSuite) SetupSuite() { + sk, err := GenSecp256r1() + suite.Require().NoError(err) + suite.sk = sk + suite.pk = sk.PubKey() +} + +type PKSuite struct{ CommonSuite } + +func (suite *PKSuite) TestString() { + assert := suite.Assert() + require := suite.Require() + + prefix := "abc" + pkStr := suite.pk.String(prefix) + assert.Equal(prefix+"{", pkStr[:len(prefix)+1]) + assert.EqualValues('}', pkStr[len(pkStr)-1]) + + bz, err := hex.DecodeString(pkStr[len(prefix)+1 : len(pkStr)-1]) + require.NoError(err) + assert.EqualValues(suite.pk.Bytes(), bz) +} + +func (suite *PKSuite) TestBytes() { + bz := suite.sk.Bytes() + fieldSize := (suite.sk.Curve.Params().BitSize + 7) / 8 + suite.Len(bz, fieldSize) + var pk *PubKey + suite.Nil(pk.Bytes()) +} + +func (suite *PKSuite) TestMarshal() { + require := suite.Require() + const size = 33 // secp256r1 size + + var buffer = make([]byte, size) + n, err := suite.pk.MarshalTo(buffer) + require.NoError(err) + require.Equal(size, n) + + var pk = new(PubKey) + err = pk.Unmarshal(buffer, secp256r1, size) + require.NoError(err) + require.True(pk.PublicKey.Equal(&suite.pk.PublicKey)) +} diff --git a/crypto/keys/multisig/multisig.go b/crypto/keys/multisig/multisig.go index 33ebf6db24..f6967b7d81 100644 --- a/crypto/keys/multisig/multisig.go +++ b/crypto/keys/multisig/multisig.go @@ -15,19 +15,21 @@ var _ multisigtypes.PubKey = &LegacyAminoPubKey{} var _ types.UnpackInterfacesMessage = &LegacyAminoPubKey{} // NewLegacyAminoPubKey returns a new LegacyAminoPubKey. +// Multisig can be constructed with multiple same keys - it will increase the power of +// the owner of that key (he will still need to add multiple signatures in the right order). // Panics if len(pubKeys) < k or 0 >= k. -func NewLegacyAminoPubKey(k int, pubKeys []cryptotypes.PubKey) *LegacyAminoPubKey { - if k <= 0 { +func NewLegacyAminoPubKey(threshold int, pubKeys []cryptotypes.PubKey) *LegacyAminoPubKey { + if threshold <= 0 { panic("threshold k of n multisignature: k <= 0") } - if len(pubKeys) < k { + if len(pubKeys) < threshold { panic("threshold k of n multisignature: len(pubKeys) < k") } anyPubKeys, err := packPubKeys(pubKeys) if err != nil { panic(err) } - return &LegacyAminoPubKey{Threshold: uint32(k), PubKeys: anyPubKeys} + return &LegacyAminoPubKey{Threshold: uint32(threshold), PubKeys: anyPubKeys} } // Address implements cryptotypes.PubKey Address method @@ -37,10 +39,14 @@ func (m *LegacyAminoPubKey) Address() cryptotypes.Address { // Bytes returns the proto encoded version of the LegacyAminoPubKey func (m *LegacyAminoPubKey) Bytes() []byte { - return AminoCdc.MustMarshalBinaryBare(m) + return AminoCdc.MustMarshal(m) } -// VerifyMultisignature implements the multisigtypes.PubKey VerifyMultisignature method +// VerifyMultisignature implements the multisigtypes.PubKey VerifyMultisignature method. +// The signatures must be added in an order corresponding to the public keys order in +// LegacyAminoPubKey. It's OK to have multiple same keys in the multisig - it will increase +// the power of the owner of that key - in that case the signer will still need to append +// multiple same signatures in the right order. func (m *LegacyAminoPubKey) VerifyMultisignature(getSignBytes multisigtypes.GetSignBytesFunc, sig *signing.MultiSignatureData) error { bitarray := sig.BitArray sigs := sig.Signatures @@ -48,7 +54,7 @@ func (m *LegacyAminoPubKey) VerifyMultisignature(getSignBytes multisigtypes.GetS pubKeys := m.GetPubKeys() // ensure bit array is the correct size if len(pubKeys) != size { - return fmt.Errorf("bit array size is incorrect %d", len(pubKeys)) + return fmt.Errorf("bit array size is incorrect, expecting: %d", len(pubKeys)) } // ensure size of signature list if len(sigs) < int(m.Threshold) || len(sigs) > size { @@ -56,7 +62,7 @@ func (m *LegacyAminoPubKey) VerifyMultisignature(getSignBytes multisigtypes.GetS } // ensure at least k signatures are set if bitarray.NumTrueBitsBefore(size) < int(m.Threshold) { - return fmt.Errorf("minimum number of signatures not set, have %d, expected %d", bitarray.NumTrueBitsBefore(size), int(m.Threshold)) + return fmt.Errorf("not enough signatures set, have %d, expected %d", bitarray.NumTrueBitsBefore(size), int(m.Threshold)) } // index in the list of signatures which we are concerned with. sigIndex := 0 @@ -91,7 +97,7 @@ func (m *LegacyAminoPubKey) VerifyMultisignature(getSignBytes multisigtypes.GetS // VerifySignature implements cryptotypes.PubKey VerifySignature method, // it panics because it can't handle MultiSignatureData -// cf. https://github.com/line/lbm-sdk/issues/7109#issuecomment-686329936 +// cf. https://github.com/cosmos/cosmos-sdk/issues/7109#issuecomment-686329936 func (m *LegacyAminoPubKey) VerifySignature(msg []byte, sig []byte) bool { panic("not implemented") } diff --git a/crypto/keys/multisig/multisig_test.go b/crypto/keys/multisig/multisig_test.go index d96cf98c18..ad90072e00 100644 --- a/crypto/keys/multisig/multisig_test.go +++ b/crypto/keys/multisig/multisig_test.go @@ -1,6 +1,7 @@ package multisig_test import ( + "strings" "testing" "github.com/stretchr/testify/require" @@ -9,26 +10,28 @@ import ( "github.com/line/lbm-sdk/codec/legacy" "github.com/line/lbm-sdk/codec/types" cryptocodec "github.com/line/lbm-sdk/crypto/codec" + "github.com/line/lbm-sdk/crypto/keyring" kmultisig "github.com/line/lbm-sdk/crypto/keys/multisig" "github.com/line/lbm-sdk/crypto/keys/secp256k1" cryptotypes "github.com/line/lbm-sdk/crypto/types" "github.com/line/lbm-sdk/crypto/types/multisig" + "github.com/line/lbm-sdk/simapp" + sdk "github.com/line/lbm-sdk/types" "github.com/line/lbm-sdk/types/tx/signing" "github.com/line/lbm-sdk/x/auth/legacy/legacytx" ) -func generatePubKeys(n int) []cryptotypes.PubKey { - pks := make([]cryptotypes.PubKey, n) - for i := 0; i < n; i++ { - pks[i] = secp256k1.GenPrivKey().PubKey() - } +func TestNewMultiSig(t *testing.T) { + require := require.New(t) + pk1 := secp256k1.GenPrivKey().PubKey() + pks := []cryptotypes.PubKey{pk1, pk1} - return pks + require.NotNil(kmultisig.NewLegacyAminoPubKey(1, pks), + "Should support not unique public keys") } func TestAddress(t *testing.T) { - msg := []byte{1, 2, 3, 4} - pubKeys, _ := generatePubKeysAndSignatures(5, msg) + pubKeys := generatePubKeys(5) multisigKey := kmultisig.NewLegacyAminoPubKey(2, pubKeys) require.Len(t, multisigKey.Address(), 20) @@ -96,22 +99,21 @@ func TestVerifyMultisignature(t *testing.T) { testCases := []struct { msg string - malleate func() + malleate func(*require.Assertions) expectPass bool }{ { "nested multisignature", - func() { + func(require *require.Assertions) { genPk, genSig := generateNestedMultiSignature(3, msg) sig = genSig pk = genPk }, true, - }, - { + }, { "wrong size for sig bit array", - func() { - pubKeys, _ := generatePubKeysAndSignatures(3, msg) + func(require *require.Assertions) { + pubKeys := generatePubKeys(3) pk = kmultisig.NewLegacyAminoPubKey(3, pubKeys) sig = multisig.NewMultisig(1) }, @@ -119,7 +121,7 @@ func TestVerifyMultisignature(t *testing.T) { }, { "single signature data, expects the first k signatures to be valid", - func() { + func(require *require.Assertions) { k := 2 signingIndices := []int{0, 3, 1} pubKeys, sigs := generatePubKeysAndSignatures(5, msg) @@ -130,32 +132,26 @@ func TestVerifyMultisignature(t *testing.T) { for i := 0; i < k-1; i++ { signingIndex := signingIndices[i] require.NoError( - t, multisig.AddSignatureFromPubKey(sig, sigs[signingIndex], pubKeys[signingIndex], pubKeys), ) require.Error( - t, pk.VerifyMultisignature(signBytesFn, sig), "multisig passed when i < k, i %d", i, ) require.NoError( - t, multisig.AddSignatureFromPubKey(sig, sigs[signingIndex], pubKeys[signingIndex], pubKeys), ) require.Equal( - t, i+1, len(sig.Signatures), "adding a signature for the same pubkey twice increased signature count by 2, index %d", i, ) } require.Error( - t, pk.VerifyMultisignature(signBytesFn, sig), "multisig passed with k - 1 sigs", ) require.NoError( - t, multisig.AddSignatureFromPubKey( sig, sigs[signingIndices[k]], @@ -164,31 +160,51 @@ func TestVerifyMultisignature(t *testing.T) { ), ) require.NoError( - t, pk.VerifyMultisignature(signBytesFn, sig), "multisig failed after k good signatures", ) }, true, - }, - { + }, { "duplicate signatures", - func() { + func(require *require.Assertions) { pubKeys, sigs := generatePubKeysAndSignatures(5, msg) pk = kmultisig.NewLegacyAminoPubKey(2, pubKeys) sig = multisig.NewMultisig(5) - require.Error(t, pk.VerifyMultisignature(signBytesFn, sig)) + require.Error(pk.VerifyMultisignature(signBytesFn, sig)) multisig.AddSignatureFromPubKey(sig, sigs[0], pubKeys[0], pubKeys) // Add second signature manually sig.Signatures = append(sig.Signatures, sigs[0]) }, false, - }, - { + }, { + "duplicated key", + func(require *require.Assertions) { + // here we test an edge case where we create a multi sig with two same + // keys. It should work. + pubkeys, sigs := generatePubKeysAndSignatures(3, msg) + pubkeys[1] = pubkeys[0] + pk = kmultisig.NewLegacyAminoPubKey(2, pubkeys) + sig = multisig.NewMultisig(len(pubkeys)) + multisig.AddSignature(sig, sigs[0], 0) + multisig.AddSignature(sig, sigs[0], 1) + }, + true, + }, { + "same key used twice", + func(require *require.Assertions) { + pubkeys, sigs := generatePubKeysAndSignatures(3, msg) + pk = kmultisig.NewLegacyAminoPubKey(2, pubkeys) + sig = multisig.NewMultisig(len(pubkeys)) + multisig.AddSignature(sig, sigs[0], 0) + multisig.AddSignature(sig, sigs[0], 1) + }, + false, + }, { "unable to verify signature", - func() { - pubKeys, _ := generatePubKeysAndSignatures(2, msg) + func(require *require.Assertions) { + pubKeys := generatePubKeys(2) _, sigs := generatePubKeysAndSignatures(2, msg) pk = kmultisig.NewLegacyAminoPubKey(2, pubKeys) sig = multisig.NewMultisig(2) @@ -201,7 +217,7 @@ func TestVerifyMultisignature(t *testing.T) { for _, tc := range testCases { t.Run(tc.msg, func(t *testing.T) { - tc.malleate() + tc.malleate(require.New(t)) err := pk.VerifyMultisignature(signBytesFn, sig) if tc.expectPass { require.NoError(t, err) @@ -257,21 +273,28 @@ func TestMultiSigMigration(t *testing.T) { } func TestPubKeyMultisigThresholdAminoToIface(t *testing.T) { - msg := []byte{1, 2, 3, 4} - pubkeys, _ := generatePubKeysAndSignatures(5, msg) + pubkeys := generatePubKeys(5) multisigKey := kmultisig.NewLegacyAminoPubKey(2, pubkeys) - ab, err := legacy.Cdc.MarshalBinaryLengthPrefixed(multisigKey) + ab, err := legacy.Cdc.MarshalLengthPrefixed(multisigKey) require.NoError(t, err) // like other cryptotypes.Pubkey implementations (e.g. ed25519.PubKey), // LegacyAminoPubKey should be deserializable into a cryptotypes.LegacyAminoPubKey: var pubKey kmultisig.LegacyAminoPubKey - err = legacy.Cdc.UnmarshalBinaryLengthPrefixed(ab, &pubKey) + err = legacy.Cdc.UnmarshalLengthPrefixed(ab, &pubKey) require.NoError(t, err) require.Equal(t, multisigKey.Equals(&pubKey), true) } +func generatePubKeys(n int) []cryptotypes.PubKey { + pks := make([]cryptotypes.PubKey, n) + for i := 0; i < n; i++ { + pks[i] = secp256k1.GenPrivKey().PubKey() + } + return pks +} + func generatePubKeysAndSignatures(n int, msg []byte) (pubKeys []cryptotypes.PubKey, signatures []signing.SignatureData) { pubKeys = make([]cryptotypes.PubKey, n) signatures = make([]signing.SignatureData, n) @@ -319,25 +342,40 @@ func reorderPubKey(pk *kmultisig.LegacyAminoPubKey) (other *kmultisig.LegacyAmin return } +func TestDisplay(t *testing.T) { + require := require.New(t) + pubKeys := generatePubKeys(3) + msig := kmultisig.NewLegacyAminoPubKey(2, pubKeys) + + // LegacyAminoPubKey wraps PubKeys into Amino (for serialization) and Any String method doesn't work. + require.PanicsWithValue("reflect.Value.Interface: cannot return value obtained from unexported field or method", + func() { require.Empty(msig.String()) }, + ) + ccfg := simapp.MakeTestEncodingConfig() + bz, err := ccfg.Marshaler.MarshalInterfaceJSON(msig) + require.NoError(err) + expectedPrefix := `{"@type":"/lbm.crypto.multisig.LegacyAminoPubKey","threshold":2,"public_keys":[{"@type":"/lbm.crypto.secp256k1.PubKey"` + require.True(strings.HasPrefix(string(bz), expectedPrefix)) + // Example output: + // {"@type":"/lbm.crypto.multisig.LegacyAminoPubKey","threshold":2,"public_keys":[{"@type":"/lbm.crypto.secp256k1.PubKey","key":"AymUY3J2HKIyy9cbpGKcBFUTuDQsRH9NO/orKF/0WQ76"},{"@type":"/lbm.crypto.secp256k1.PubKey","key":"AkvnCDzSYF+tQV/FoI217V7CDIRPzjJj7zBE2nw7x3xT"},{"@type":"/lbm.crypto.secp256k1.PubKey","key":"A0yiqgcM5EB1i0h79+sQp+C0jLPFnT3+dFmdZmGa+H1s"}]} +} + func TestAminoBinary(t *testing.T) { - pubKey1 := secp256k1.GenPrivKey().PubKey() - pubKey2 := secp256k1.GenPrivKey().PubKey() - multisigKey := kmultisig.NewLegacyAminoPubKey(2, []cryptotypes.PubKey{pubKey1, pubKey2}) + pubkeys := generatePubKeys(2) + msig := kmultisig.NewLegacyAminoPubKey(2, pubkeys) // Do a round-trip key->bytes->key. - bz, err := legacy.Cdc.MarshalBinaryBare(multisigKey) + bz, err := legacy.Cdc.Marshal(msig) require.NoError(t, err) - var newMultisigKey cryptotypes.PubKey - err = legacy.Cdc.UnmarshalBinaryBare(bz, &newMultisigKey) + var newMsig cryptotypes.PubKey + err = legacy.Cdc.Unmarshal(bz, &newMsig) require.NoError(t, err) - require.Equal(t, multisigKey.Threshold, newMultisigKey.(*kmultisig.LegacyAminoPubKey).Threshold) + require.Equal(t, msig.Threshold, newMsig.(*kmultisig.LegacyAminoPubKey).Threshold) } func TestAminoMarshalJSON(t *testing.T) { - pubKey1 := secp256k1.GenPrivKey().PubKey() - pubKey2 := secp256k1.GenPrivKey().PubKey() - multisigKey := kmultisig.NewLegacyAminoPubKey(2, []cryptotypes.PubKey{pubKey1, pubKey2}) - + pubkeys := generatePubKeys(2) + multisigKey := kmultisig.NewLegacyAminoPubKey(2, pubkeys) bz, err := legacy.Cdc.MarshalJSON(multisigKey) require.NoError(t, err) @@ -390,14 +428,6 @@ func TestAminoUnmarshalJSON(t *testing.T) { require.NoError(t, err) lpk := pk.(*kmultisig.LegacyAminoPubKey) require.Equal(t, uint32(3), lpk.Threshold) - require.Equal(t, 5, len(pk.(*kmultisig.LegacyAminoPubKey).PubKeys)) - - for _, key := range pk.(*kmultisig.LegacyAminoPubKey).PubKeys { - require.NotNil(t, key) - pk := secp256k1.PubKey{} - err := pk.Unmarshal(key.Value) - require.NoError(t, err) - } } func TestProtoMarshalJSON(t *testing.T) { @@ -416,4 +446,13 @@ func TestProtoMarshalJSON(t *testing.T) { err = cdc.UnmarshalInterfaceJSON(bz, &pk2) require.NoError(err) require.True(pk2.Equals(msig)) + + // Test that we can correctly unmarshal key from keyring output + + info, err := keyring.NewMultiInfo("my multisig", msig) + require.NoError(err) + ko, err := keyring.MkAccKeyOutput(info) + require.NoError(err) + require.Equal(ko.Address, sdk.BytesToAccAddress(pk2.Address()).String()) + require.Equal(ko.PubKey, string(bz)) } diff --git a/crypto/keys/secp256k1/bench_test.go b/crypto/keys/secp256k1/bench_test.go index eeb891f5a1..2f978de1e0 100644 --- a/crypto/keys/secp256k1/bench_test.go +++ b/crypto/keys/secp256k1/bench_test.go @@ -9,6 +9,7 @@ import ( ) func BenchmarkKeyGeneration(b *testing.B) { + b.ReportAllocs() benchmarkKeygenWrapper := func(reader io.Reader) types.PrivKey { priv := genPrivKey(reader) return &PrivKey{Key: priv} @@ -17,11 +18,13 @@ func BenchmarkKeyGeneration(b *testing.B) { } func BenchmarkSigning(b *testing.B) { + b.ReportAllocs() priv := GenPrivKey() benchmarking.BenchmarkSigning(b, priv) } func BenchmarkVerification(b *testing.B) { + b.ReportAllocs() priv := GenPrivKey() benchmarking.BenchmarkVerification(b, priv) } diff --git a/crypto/keys/secp256k1/internal/secp256k1/libsecp256k1/README.md b/crypto/keys/secp256k1/internal/secp256k1/libsecp256k1/README.md index 8cd344ea81..6873001735 100644 --- a/crypto/keys/secp256k1/internal/secp256k1/libsecp256k1/README.md +++ b/crypto/keys/secp256k1/internal/secp256k1/libsecp256k1/README.md @@ -8,6 +8,7 @@ Optimized C library for EC operations on curve secp256k1. This library is a work in progress and is being used to research best practices. Use at your own risk. Features: + * secp256k1 ECDSA signing/verification and key generation. * Adding/multiplying private/public keys. * Serialization/parsing of private keys, public keys, signatures. @@ -19,43 +20,43 @@ Implementation details ---------------------- * General - * No runtime heap allocation. - * Extensive testing infrastructure. - * Structured to facilitate review and analysis. - * Intended to be portable to any system with a C89 compiler and uint64_t support. - * Expose only higher level interfaces to minimize the API surface and improve application security. ("Be difficult to use insecurely.") + * No runtime heap allocation. + * Extensive testing infrastructure. + * Structured to facilitate review and analysis. + * Intended to be portable to any system with a C89 compiler and uint64_t support. + * Expose only higher level interfaces to minimize the API surface and improve application security. ("Be difficult to use insecurely.") * Field operations - * Optimized implementation of arithmetic modulo the curve's field size (2^256 - 0x1000003D1). - * Using 5 52-bit limbs (including hand-optimized assembly for x86_64, by Diederik Huys). - * Using 10 26-bit limbs. - * Field inverses and square roots using a sliding window over blocks of 1s (by Peter Dettman). + * Optimized implementation of arithmetic modulo the curve's field size (2^256 - 0x1000003D1). + * Using 5 52-bit limbs (including hand-optimized assembly for x86_64, by Diederik Huys). + * Using 10 26-bit limbs. + * Field inverses and square roots using a sliding window over blocks of 1s (by Peter Dettman). * Scalar operations - * Optimized implementation without data-dependent branches of arithmetic modulo the curve's order. - * Using 4 64-bit limbs (relying on __int128 support in the compiler). - * Using 8 32-bit limbs. + * Optimized implementation without data-dependent branches of arithmetic modulo the curve's order. + * Using 4 64-bit limbs (relying on __int128 support in the compiler). + * Using 8 32-bit limbs. * Group operations - * Point addition formula specifically simplified for the curve equation (y^2 = x^3 + 7). - * Use addition between points in Jacobian and affine coordinates where possible. - * Use a unified addition/doubling formula where necessary to avoid data-dependent branches. - * Point/x comparison without a field inversion by comparison in the Jacobian coordinate space. + * Point addition formula specifically simplified for the curve equation (y^2 = x^3 + 7). + * Use addition between points in Jacobian and affine coordinates where possible. + * Use a unified addition/doubling formula where necessary to avoid data-dependent branches. + * Point/x comparison without a field inversion by comparison in the Jacobian coordinate space. * Point multiplication for verification (a*P + b*G). - * Use wNAF notation for point multiplicands. - * Use a much larger window for multiples of G, using precomputed multiples. - * Use Shamir's trick to do the multiplication with the public key and the generator simultaneously. - * Optionally (off by default) use secp256k1's efficiently-computable endomorphism to split the P multiplicand into 2 half-sized ones. + * Use wNAF notation for point multiplicands. + * Use a much larger window for multiples of G, using precomputed multiples. + * Use Shamir's trick to do the multiplication with the public key and the generator simultaneously. + * Optionally (off by default) use secp256k1's efficiently-computable endomorphism to split the P multiplicand into 2 half-sized ones. * Point multiplication for signing - * Use a precomputed table of multiples of powers of 16 multiplied with the generator, so general multiplication becomes a series of additions. - * Access the table with branch-free conditional moves so memory access is uniform. - * No data-dependent branches - * The precomputed tables add and eventually subtract points for which no known scalar (private key) is known, preventing even an attacker with control over the private key used to control the data internally. + * Use a precomputed table of multiples of powers of 16 multiplied with the generator, so general multiplication becomes a series of additions. + * Access the table with branch-free conditional moves so memory access is uniform. + * No data-dependent branches + * The precomputed tables add and eventually subtract points for which no known scalar (private key) is known, preventing even an attacker with control over the private key used to control the data internally. Build steps ----------- libsecp256k1 is built using autotools: - $ ./autogen.sh - $ ./configure - $ make - $ ./tests - $ sudo make install # optional + ./autogen.sh + ./configure + make + ./tests + sudo make install # optional diff --git a/crypto/keys/secp256k1/secp256k1.go b/crypto/keys/secp256k1/secp256k1.go index ef8e191521..590af80a44 100644 --- a/crypto/keys/secp256k1/secp256k1.go +++ b/crypto/keys/secp256k1/secp256k1.go @@ -151,12 +151,9 @@ func (pubKey *PubKey) Address() crypto.Address { panic("length of pubkey is incorrect") } - hasherSHA256 := sha256.New() - hasherSHA256.Write(pubKey.Key) // does not error - sha := hasherSHA256.Sum(nil) - + sha := sha256.Sum256(pubKey.Key) hasherRIPEMD160 := ripemd160.New() - hasherRIPEMD160.Write(sha) // does not error + hasherRIPEMD160.Write(sha[:]) // does not error return crypto.Address(hasherRIPEMD160.Sum(nil)) } diff --git a/crypto/keys/secp256k1/secp256k1_nocgo.go b/crypto/keys/secp256k1/secp256k1_nocgo.go index da5b57ea64..088d655191 100644 --- a/crypto/keys/secp256k1/secp256k1_nocgo.go +++ b/crypto/keys/secp256k1/secp256k1_nocgo.go @@ -1,3 +1,4 @@ +//go:build !libsecp256k1 // +build !libsecp256k1 package secp256k1 diff --git a/crypto/keys/secp256k1/secp256k1_test.go b/crypto/keys/secp256k1/secp256k1_test.go index 6a1b1a1bb2..0f29b76d28 100644 --- a/crypto/keys/secp256k1/secp256k1_test.go +++ b/crypto/keys/secp256k1/secp256k1_test.go @@ -9,11 +9,12 @@ import ( btcSecp256k1 "github.com/btcsuite/btcd/btcec" "github.com/cosmos/btcutil/base58" - "github.com/line/ostracon/crypto" - ostsecp256k1 "github.com/line/ostracon/crypto/secp256k1" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "github.com/line/ostracon/crypto" + ostsecp256k1 "github.com/line/ostracon/crypto/secp256k1" + "github.com/line/lbm-sdk/codec" "github.com/line/lbm-sdk/crypto/keys/ed25519" "github.com/line/lbm-sdk/crypto/keys/secp256k1" @@ -247,11 +248,11 @@ func TestMarshalAmino(t *testing.T) { for _, tc := range testCases { t.Run(tc.desc, func(t *testing.T) { // Do a round trip of encoding/decoding binary. - bz, err := aminoCdc.MarshalBinaryBare(tc.msg) + bz, err := aminoCdc.Marshal(tc.msg) require.NoError(t, err) require.Equal(t, tc.expBinary, bz) - err = aminoCdc.UnmarshalBinaryBare(bz, tc.typ) + err = aminoCdc.Unmarshal(bz, tc.typ) require.NoError(t, err) require.Equal(t, tc.msg, tc.typ) @@ -288,7 +289,7 @@ func TestMarshalAmino_BackwardsCompatibility(t *testing.T) { "secp256k1 private key, binary", ostPrivKey, privKey, - aminoCdc.MarshalBinaryBare, + aminoCdc.Marshal, }, { "secp256k1 private key, JSON", @@ -300,7 +301,7 @@ func TestMarshalAmino_BackwardsCompatibility(t *testing.T) { "secp256k1 public key, binary", ostPubKey, pubKey, - aminoCdc.MarshalBinaryBare, + aminoCdc.Marshal, }, { "secp256k1 public key, JSON", diff --git a/crypto/keys/secp256r1/doc.go b/crypto/keys/secp256r1/doc.go new file mode 100644 index 0000000000..ec7d7c9846 --- /dev/null +++ b/crypto/keys/secp256r1/doc.go @@ -0,0 +1,35 @@ +// Package secp256r1 implements Cosmos-SDK compatible ECDSA public and private key. The keys +// can be protobuf serialized and packed in Any. +package secp256r1 + +import ( + "crypto/elliptic" + "fmt" + + codectypes "github.com/line/lbm-sdk/codec/types" + cryptotypes "github.com/line/lbm-sdk/crypto/types" +) + +const ( + // fieldSize is the curve domain size. + fieldSize = 32 + pubKeySize = fieldSize + 1 + + name = "secp256r1" +) + +var secp256r1 elliptic.Curve + +func init() { + secp256r1 = elliptic.P256() + // pubKeySize is ceil of field bit size + 1 for the sign + expected := (secp256r1.Params().BitSize + 7) / 8 + if expected != fieldSize { + panic(fmt.Sprintf("Wrong secp256r1 curve fieldSize=%d, expecting=%d", fieldSize, expected)) + } +} + +// RegisterInterfaces adds secp256r1 PubKey to pubkey registry +func RegisterInterfaces(registry codectypes.InterfaceRegistry) { + registry.RegisterImplementations((*cryptotypes.PubKey)(nil), &PubKey{}) +} diff --git a/crypto/keys/secp256r1/keys.pb.go b/crypto/keys/secp256r1/keys.pb.go new file mode 100644 index 0000000000..bbe3ecd850 --- /dev/null +++ b/crypto/keys/secp256r1/keys.pb.go @@ -0,0 +1,501 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: lbm/crypto/secp256r1/keys.proto + +package secp256r1 + +import ( + fmt "fmt" + _ "github.com/gogo/protobuf/gogoproto" + proto "github.com/gogo/protobuf/proto" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +// PubKey defines a secp256r1 ECDSA public key. +type PubKey struct { + // Point on secp256r1 curve in a compressed representation as specified in section + // 4.3.6 of ANSI X9.62: https://webstore.ansi.org/standards/ascx9/ansix9621998 + Key *ecdsaPK `protobuf:"bytes,1,opt,name=key,proto3,customtype=ecdsaPK" json:"key,omitempty"` +} + +func (m *PubKey) Reset() { *m = PubKey{} } +func (*PubKey) ProtoMessage() {} +func (*PubKey) Descriptor() ([]byte, []int) { + return fileDescriptor_0c0f23f7b8e57c83, []int{0} +} +func (m *PubKey) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *PubKey) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_PubKey.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *PubKey) XXX_Merge(src proto.Message) { + xxx_messageInfo_PubKey.Merge(m, src) +} +func (m *PubKey) XXX_Size() int { + return m.Size() +} +func (m *PubKey) XXX_DiscardUnknown() { + xxx_messageInfo_PubKey.DiscardUnknown(m) +} + +var xxx_messageInfo_PubKey proto.InternalMessageInfo + +func (*PubKey) XXX_MessageName() string { + return "lbm.crypto.secp256r1.PubKey" +} + +// PrivKey defines a secp256r1 ECDSA private key. +type PrivKey struct { + // secret number serialized using big-endian encoding + Secret *ecdsaSK `protobuf:"bytes,1,opt,name=secret,proto3,customtype=ecdsaSK" json:"secret,omitempty"` +} + +func (m *PrivKey) Reset() { *m = PrivKey{} } +func (*PrivKey) ProtoMessage() {} +func (*PrivKey) Descriptor() ([]byte, []int) { + return fileDescriptor_0c0f23f7b8e57c83, []int{1} +} +func (m *PrivKey) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *PrivKey) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_PrivKey.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *PrivKey) XXX_Merge(src proto.Message) { + xxx_messageInfo_PrivKey.Merge(m, src) +} +func (m *PrivKey) XXX_Size() int { + return m.Size() +} +func (m *PrivKey) XXX_DiscardUnknown() { + xxx_messageInfo_PrivKey.DiscardUnknown(m) +} + +var xxx_messageInfo_PrivKey proto.InternalMessageInfo + +func (*PrivKey) XXX_MessageName() string { + return "lbm.crypto.secp256r1.PrivKey" +} +func init() { + proto.RegisterType((*PubKey)(nil), "lbm.crypto.secp256r1.PubKey") + proto.RegisterType((*PrivKey)(nil), "lbm.crypto.secp256r1.PrivKey") +} + +func init() { proto.RegisterFile("lbm/crypto/secp256r1/keys.proto", fileDescriptor_0c0f23f7b8e57c83) } + +var fileDescriptor_0c0f23f7b8e57c83 = []byte{ + // 223 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0xcf, 0x49, 0xca, 0xd5, + 0x4f, 0x2e, 0xaa, 0x2c, 0x28, 0xc9, 0xd7, 0x2f, 0x4e, 0x4d, 0x2e, 0x30, 0x32, 0x35, 0x2b, 0x32, + 0xd4, 0xcf, 0x4e, 0xad, 0x2c, 0xd6, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x12, 0xc9, 0x49, 0xca, + 0xd5, 0x83, 0x28, 0xd0, 0x83, 0x2b, 0x90, 0x12, 0x49, 0xcf, 0x4f, 0xcf, 0x07, 0x2b, 0xd0, 0x07, + 0xb1, 0x20, 0x6a, 0x95, 0xd4, 0xb9, 0xd8, 0x02, 0x4a, 0x93, 0xbc, 0x53, 0x2b, 0x85, 0x64, 0xb9, + 0x98, 0xb3, 0x53, 0x2b, 0x25, 0x18, 0x15, 0x18, 0x35, 0x78, 0x9c, 0xb8, 0x6f, 0xdd, 0x93, 0x67, + 0x4f, 0x4d, 0x4e, 0x29, 0x4e, 0x0c, 0xf0, 0x0e, 0x02, 0x89, 0x2b, 0xe9, 0x71, 0xb1, 0x07, 0x14, + 0x65, 0x96, 0x81, 0x54, 0x2a, 0x73, 0xb1, 0x15, 0xa7, 0x26, 0x17, 0xa5, 0x96, 0x60, 0x28, 0x0e, + 0xf6, 0x0e, 0x82, 0x4a, 0x39, 0x05, 0x9f, 0x78, 0x28, 0xc7, 0x70, 0xe3, 0xa1, 0x1c, 0xc3, 0x89, + 0x47, 0x72, 0x8c, 0x17, 0x1e, 0xc9, 0x31, 0x3e, 0x78, 0x24, 0xc7, 0x38, 0xe1, 0xb1, 0x1c, 0xc3, + 0x89, 0xc7, 0x72, 0x8c, 0x17, 0x1e, 0xcb, 0x31, 0xdc, 0x78, 0x2c, 0xc7, 0x10, 0xa5, 0x9b, 0x9e, + 0x59, 0x92, 0x51, 0x9a, 0xa4, 0x97, 0x9c, 0x9f, 0xab, 0x9f, 0x93, 0x99, 0x97, 0xaa, 0x9f, 0x93, + 0x94, 0xab, 0x5b, 0x9c, 0x92, 0x0d, 0xf3, 0x1f, 0xc8, 0x57, 0x08, 0x4f, 0x26, 0xb1, 0x81, 0x1d, + 0x6d, 0x0c, 0x08, 0x00, 0x00, 0xff, 0xff, 0xf6, 0x31, 0xfb, 0xba, 0x03, 0x01, 0x00, 0x00, +} + +func (m *PubKey) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *PubKey) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *PubKey) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Key != nil { + { + size := m.Key.Size() + i -= size + if _, err := m.Key.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintKeys(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *PrivKey) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *PrivKey) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *PrivKey) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Secret != nil { + { + size := m.Secret.Size() + i -= size + if _, err := m.Secret.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintKeys(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func encodeVarintKeys(dAtA []byte, offset int, v uint64) int { + offset -= sovKeys(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *PubKey) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Key != nil { + l = m.Key.Size() + n += 1 + l + sovKeys(uint64(l)) + } + return n +} + +func (m *PrivKey) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Secret != nil { + l = m.Secret.Size() + n += 1 + l + sovKeys(uint64(l)) + } + return n +} + +func sovKeys(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozKeys(x uint64) (n int) { + return sovKeys(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *PubKey) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowKeys + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: PubKey: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: PubKey: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Key", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowKeys + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthKeys + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthKeys + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + var v ecdsaPK + m.Key = &v + if err := m.Key.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipKeys(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthKeys + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *PrivKey) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowKeys + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: PrivKey: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: PrivKey: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Secret", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowKeys + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthKeys + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthKeys + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + var v ecdsaSK + m.Secret = &v + if err := m.Secret.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipKeys(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthKeys + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipKeys(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowKeys + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowKeys + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowKeys + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthKeys + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupKeys + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthKeys + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthKeys = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowKeys = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupKeys = fmt.Errorf("proto: unexpected end of group") +) diff --git a/crypto/keys/secp256r1/privkey.go b/crypto/keys/secp256r1/privkey.go new file mode 100644 index 0000000000..d444797364 --- /dev/null +++ b/crypto/keys/secp256r1/privkey.go @@ -0,0 +1,66 @@ +package secp256r1 + +import ( + "github.com/line/lbm-sdk/crypto/keys/internal/ecdsa" + cryptotypes "github.com/line/lbm-sdk/crypto/types" +) + +// GenPrivKey generates a new secp256r1 private key. It uses operating system randomness. +func GenPrivKey() (*PrivKey, error) { + key, err := ecdsa.GenPrivKey(secp256r1) + return &PrivKey{&ecdsaSK{key}}, err +} + +// PubKey implements SDK PrivKey interface. +func (m *PrivKey) PubKey() cryptotypes.PubKey { + return &PubKey{&ecdsaPK{m.Secret.PubKey()}} +} + +// String implements SDK proto.Message interface. +func (m *PrivKey) String() string { + return m.Secret.String(name) +} + +// Type returns key type name. Implements SDK PrivKey interface. +func (m *PrivKey) Type() string { + return name +} + +// Sign hashes and signs the message usign ECDSA. Implements sdk.PrivKey interface. +func (m *PrivKey) Sign(msg []byte) ([]byte, error) { + return m.Secret.Sign(msg) +} + +// Bytes serialize the private key. +func (m *PrivKey) Bytes() []byte { + if m == nil { + return nil + } + return m.Secret.Bytes() +} + +// Equals implements SDK PrivKey interface. +func (m *PrivKey) Equals(other cryptotypes.LedgerPrivKey) bool { + sk2, ok := other.(*PrivKey) + if !ok { + return false + } + return m.Secret.Equal(&sk2.Secret.PrivateKey) +} + +type ecdsaSK struct { + ecdsa.PrivKey +} + +// Size implements proto.Marshaler interface +func (sk *ecdsaSK) Size() int { + if sk == nil { + return 0 + } + return fieldSize +} + +// Unmarshal implements proto.Marshaler interface +func (sk *ecdsaSK) Unmarshal(bz []byte) error { + return sk.PrivKey.Unmarshal(bz, secp256r1, fieldSize) +} diff --git a/crypto/keys/secp256r1/privkey_internal_test.go b/crypto/keys/secp256r1/privkey_internal_test.go new file mode 100644 index 0000000000..2af8e76b52 --- /dev/null +++ b/crypto/keys/secp256r1/privkey_internal_test.go @@ -0,0 +1,115 @@ +package secp256r1 + +import ( + "testing" + + "github.com/gogo/protobuf/proto" + "github.com/stretchr/testify/suite" + + "github.com/line/lbm-sdk/codec" + "github.com/line/lbm-sdk/codec/types" + cryptotypes "github.com/line/lbm-sdk/crypto/types" + "github.com/line/ostracon/crypto" +) + +var _ cryptotypes.PrivKey = &PrivKey{} + +func TestSKSuite(t *testing.T) { + suite.Run(t, new(SKSuite)) +} + +type SKSuite struct{ CommonSuite } + +func (suite *SKSuite) TestString() { + suite.Require().Equal("secp256r1{-}", suite.sk.String()) +} + +func (suite *SKSuite) TestEquals() { + require := suite.Require() + + skOther, err := GenPrivKey() + require.NoError(err) + require.False(suite.sk.Equals(skOther)) + + skOther2 := &PrivKey{skOther.Secret} + require.True(skOther.Equals(skOther2)) + require.True(skOther2.Equals(skOther), "Equals must be reflexive") +} + +func (suite *SKSuite) TestPubKey() { + pk := suite.sk.PubKey() + suite.True(suite.sk.(*PrivKey).Secret.PublicKey.Equal(&pk.(*PubKey).Key.PublicKey)) +} + +func (suite *SKSuite) TestBytes() { + bz := suite.sk.Bytes() + suite.Len(bz, fieldSize) + var sk *PrivKey + suite.Nil(sk.Bytes()) +} + +func (suite *SKSuite) TestMarshalProto() { + require := suite.Require() + + /**** test structure marshalling ****/ + + var sk PrivKey + bz, err := proto.Marshal(suite.sk) + require.NoError(err) + require.NoError(proto.Unmarshal(bz, &sk)) + require.True(sk.Equals(suite.sk)) + + /**** test structure marshalling with codec ****/ + + sk = PrivKey{} + registry := types.NewInterfaceRegistry() + cdc := codec.NewProtoCodec(registry) + bz, err = cdc.Marshal(suite.sk.(*PrivKey)) + require.NoError(err) + require.NoError(cdc.Unmarshal(bz, &sk)) + require.True(sk.Equals(suite.sk)) + + const bufSize = 100 + bz2 := make([]byte, bufSize) + skCpy := suite.sk.(*PrivKey) + _, err = skCpy.MarshalTo(bz2) + require.NoError(err) + require.Len(bz2, bufSize) + require.Equal(bz, bz2[:sk.Size()]) + + bz2 = make([]byte, bufSize) + _, err = skCpy.MarshalToSizedBuffer(bz2) + require.NoError(err) + require.Len(bz2, bufSize) + require.Equal(bz, bz2[(bufSize-sk.Size()):]) +} + +func (suite *SKSuite) TestSign() { + require := suite.Require() + + msg := crypto.CRandBytes(1000) + sig, err := suite.sk.Sign(msg) + require.NoError(err) + sigCpy := make([]byte, len(sig)) + copy(sigCpy, sig) + require.True(suite.pk.VerifySignature(msg, sigCpy)) + + // Mutate the signature + for i := range sig { + sigCpy[i] ^= byte(i + 1) + require.False(suite.pk.VerifySignature(msg, sigCpy)) + } + + // Mutate the message + msg[1] ^= byte(2) + require.False(suite.pk.VerifySignature(msg, sig)) +} + +func (suite *SKSuite) TestSize() { + require := suite.Require() + var pk ecdsaSK + require.Equal(pk.Size(), len(suite.sk.Bytes())) + + var nilPk *ecdsaSK + require.Equal(0, nilPk.Size(), "nil value must have zero size") +} diff --git a/crypto/keys/secp256r1/pubkey.go b/crypto/keys/secp256r1/pubkey.go new file mode 100644 index 0000000000..25cffbe2d1 --- /dev/null +++ b/crypto/keys/secp256r1/pubkey.go @@ -0,0 +1,63 @@ +package secp256r1 + +import ( + "github.com/gogo/protobuf/proto" + tmcrypto "github.com/line/ostracon/crypto" + + ecdsa "github.com/line/lbm-sdk/crypto/keys/internal/ecdsa" + cryptotypes "github.com/line/lbm-sdk/crypto/types" +) + +// String implements proto.Message interface. +func (m *PubKey) String() string { + return m.Key.String(name) +} + +// Bytes implements SDK PubKey interface. +func (m *PubKey) Bytes() []byte { + if m == nil { + return nil + } + return m.Key.Bytes() +} + +// Equals implements SDK PubKey interface. +func (m *PubKey) Equals(other cryptotypes.PubKey) bool { + pk2, ok := other.(*PubKey) + if !ok { + return false + } + return m.Key.Equal(&pk2.Key.PublicKey) +} + +// Address implements SDK PubKey interface. +func (m *PubKey) Address() tmcrypto.Address { + return m.Key.Address(proto.MessageName(m)) +} + +// Type returns key type name. Implements SDK PubKey interface. +func (m *PubKey) Type() string { + return name +} + +// VerifySignature implements SDK PubKey interface. +func (m *PubKey) VerifySignature(msg []byte, sig []byte) bool { + return m.Key.VerifySignature(msg, sig) +} + +type ecdsaPK struct { + ecdsa.PubKey +} + +// Size implements proto.Marshaler interface +func (pk *ecdsaPK) Size() int { + if pk == nil { + return 0 + } + return pubKeySize +} + +// Unmarshal implements proto.Marshaler interface +func (pk *ecdsaPK) Unmarshal(bz []byte) error { + return pk.PubKey.Unmarshal(bz, secp256r1, pubKeySize) +} diff --git a/crypto/keys/secp256r1/pubkey_internal_test.go b/crypto/keys/secp256r1/pubkey_internal_test.go new file mode 100644 index 0000000000..ed9e3424fb --- /dev/null +++ b/crypto/keys/secp256r1/pubkey_internal_test.go @@ -0,0 +1,125 @@ +package secp256r1 + +import ( + "testing" + + proto "github.com/gogo/protobuf/proto" + "github.com/stretchr/testify/suite" + + "github.com/line/lbm-sdk/codec" + "github.com/line/lbm-sdk/codec/types" + cryptotypes "github.com/line/lbm-sdk/crypto/types" +) + +var _ cryptotypes.PubKey = (*PubKey)(nil) + +func TestPKSuite(t *testing.T) { + suite.Run(t, new(PKSuite)) +} + +type CommonSuite struct { + suite.Suite + pk *PubKey // cryptotypes.PubKey + sk cryptotypes.PrivKey +} + +func (suite *CommonSuite) SetupSuite() { + sk, err := GenPrivKey() + suite.Require().NoError(err) + suite.sk = sk + suite.pk = sk.PubKey().(*PubKey) +} + +type PKSuite struct{ CommonSuite } + +func (suite *PKSuite) TestString() { + require := suite.Require() + + pkStr := suite.pk.String() + prefix := "secp256r1{" + require.Equal(prefix, pkStr[:len(prefix)]) +} + +func (suite *PKSuite) TestType() { + suite.Require().Equal(name, suite.pk.Type()) +} + +func (suite *PKSuite) TestBytes() { + bz := suite.pk.Bytes() + suite.Len(bz, fieldSize+1) + var pk *PubKey + suite.Nil(pk.Bytes()) +} + +func (suite *PKSuite) TestEquals() { + require := suite.Require() + + skOther, err := GenPrivKey() + require.NoError(err) + pkOther := skOther.PubKey() + pkOther2 := &PubKey{&ecdsaPK{skOther.Secret.PubKey()}} + + require.False(suite.pk.Equals(pkOther)) + require.True(pkOther.Equals(pkOther2)) + require.True(pkOther2.Equals(pkOther)) + require.True(pkOther.Equals(pkOther), "Equals must be reflexive") +} + +func (suite *PKSuite) TestMarshalProto() { + require := suite.Require() + + /**** test structure marshalling ****/ + + var pk PubKey + bz, err := proto.Marshal(suite.pk) + require.NoError(err) + require.NoError(proto.Unmarshal(bz, &pk)) + require.True(pk.Equals(suite.pk)) + + /**** test structure marshalling with codec ****/ + + pk = PubKey{} + registry := types.NewInterfaceRegistry() + cdc := codec.NewProtoCodec(registry) + bz, err = cdc.Marshal(suite.pk) + require.NoError(err) + require.NoError(cdc.Unmarshal(bz, &pk)) + require.True(pk.Equals(suite.pk)) + + const bufSize = 100 + bz2 := make([]byte, bufSize) + pkCpy := suite.pk + _, err = pkCpy.MarshalTo(bz2) + require.NoError(err) + require.Len(bz2, bufSize) + require.Equal(bz, bz2[:pk.Size()]) + + bz2 = make([]byte, bufSize) + _, err = pkCpy.MarshalToSizedBuffer(bz2) + require.NoError(err) + require.Len(bz2, bufSize) + require.Equal(bz, bz2[(bufSize-pk.Size()):]) + + /**** test interface marshalling ****/ + bz, err = cdc.MarshalInterface(suite.pk) + require.NoError(err) + var pkI cryptotypes.PubKey + err = cdc.UnmarshalInterface(bz, &pkI) + require.EqualError(err, "no registered implementations of type types.PubKey") + + RegisterInterfaces(registry) + require.NoError(cdc.UnmarshalInterface(bz, &pkI)) + require.True(pkI.Equals(suite.pk)) + + cdc.UnmarshalInterface(bz, nil) + require.Error(err, "nil should fail") +} + +func (suite *PKSuite) TestSize() { + require := suite.Require() + var pk ecdsaPK + require.Equal(pk.Size(), len(suite.pk.Bytes())) + + var nilPk *ecdsaPK + require.Equal(0, nilPk.Size(), "nil value must have zero size") +} diff --git a/crypto/ledger/ledger_mock.go b/crypto/ledger/ledger_mock.go index 8edcf12f05..0c25b622ad 100644 --- a/crypto/ledger/ledger_mock.go +++ b/crypto/ledger/ledger_mock.go @@ -1,3 +1,4 @@ +//go:build ledger && test_ledger_mock // +build ledger,test_ledger_mock package ledger @@ -8,14 +9,14 @@ import ( "github.com/btcsuite/btcd/btcec" "github.com/pkg/errors" - "github.com/line/ostracon/crypto" - secp256k1 "github.com/tendermint/btcd/btcec" - "github.com/cosmos/go-bip39" + secp256k1 "github.com/tendermint/btcd/btcec" + + "github.com/line/ostracon/crypto" "github.com/line/lbm-sdk/crypto/hd" csecp256k1 "github.com/line/lbm-sdk/crypto/keys/secp256k1" - "github.com/line/lbm-sdk/testutil" + "github.com/line/lbm-sdk/testutil/testdata" sdk "github.com/line/lbm-sdk/types" ) @@ -46,7 +47,7 @@ func (mock LedgerSECP256K1Mock) GetPublicKeySECP256K1(derivationPath []uint32) ( return nil, errors.New("Invalid derivation path") } - seed, err := bip39.NewSeedWithErrorChecking(testutil.TestMnemonic, "") + seed, err := bip39.NewSeedWithErrorChecking(testdata.TestMnemonic, "") if err != nil { return nil, err } @@ -88,7 +89,7 @@ func (mock LedgerSECP256K1Mock) GetAddressPubKeySECP256K1(derivationPath []uint3 func (mock LedgerSECP256K1Mock) SignSECP256K1(derivationPath []uint32, message []byte) ([]byte, error) { path := hd.NewParams(derivationPath[0], derivationPath[1], derivationPath[2], derivationPath[3] != 0, derivationPath[4]) - seed, err := bip39.NewSeedWithErrorChecking(testutil.TestMnemonic, "") + seed, err := bip39.NewSeedWithErrorChecking(testdata.TestMnemonic, "") if err != nil { return nil, err } diff --git a/crypto/ledger/ledger_notavail.go b/crypto/ledger/ledger_notavail.go index 66d16adcc0..578c33d436 100644 --- a/crypto/ledger/ledger_notavail.go +++ b/crypto/ledger/ledger_notavail.go @@ -1,4 +1,6 @@ +//go:build !cgo || !ledger // +build !cgo !ledger + // test_ledger_mock package ledger diff --git a/crypto/ledger/ledger_secp256k1.go b/crypto/ledger/ledger_secp256k1.go index bf5e85ce21..7c8c669d57 100644 --- a/crypto/ledger/ledger_secp256k1.go +++ b/crypto/ledger/ledger_secp256k1.go @@ -154,7 +154,7 @@ func (pkl *PrivKeyLedgerSecp256k1) AssertIsPrivKeyInner() {} // Bytes implements the PrivKey interface. It stores the cached public key so // we can verify the same key when we reconnect to a ledger. func (pkl PrivKeyLedgerSecp256k1) Bytes() []byte { - return cdc.MustMarshalBinaryBare(pkl) + return cdc.MustMarshal(pkl) } // Equals implements the PrivKey interface. It makes sure two private keys diff --git a/crypto/ledger/ledger_test.go b/crypto/ledger/ledger_test.go index 6cf51553d3..11384d7548 100644 --- a/crypto/ledger/ledger_test.go +++ b/crypto/ledger/ledger_test.go @@ -9,7 +9,7 @@ import ( "github.com/line/lbm-sdk/codec/legacy" "github.com/line/lbm-sdk/crypto/hd" "github.com/line/lbm-sdk/crypto/types" - "github.com/line/lbm-sdk/testutil" + "github.com/line/lbm-sdk/testutil/testdata" sdk "github.com/line/lbm-sdk/types" ) @@ -25,34 +25,33 @@ func TestPublicKeyUnsafe(t *testing.T) { path := *hd.NewFundraiserParams(0, sdk.CoinType, 0) priv, err := NewPrivKeySecp256k1Unsafe(path) require.NoError(t, err) - require.NotNil(t, priv) + checkDefaultPubKey(t, priv) +} +func checkDefaultPubKey(t *testing.T, priv types.LedgerPrivKey) { + require.NotNil(t, priv) + expectedPkStr := "PubKeySecp256k1{02BCD96CAB102304AC10E90C5A0F29358E3A4A6FB1217B83E5DB657918EA28BEC1}" require.Equal(t, "c03701b72102bcd96cab102304ac10e90c5a0f29358e3a4a6fb1217b83e5db657918ea28bec1", fmt.Sprintf("%x", cdc.Amino.MustMarshalBinaryBare(priv.PubKey())), - "Is your device using test mnemonic: %s ?", testutil.TestMnemonic) - - pubKeyAddr, err := sdk.Bech32ifyPubKey(sdk.Bech32PubKeyTypeAccPub, priv.PubKey()) - require.NoError(t, err) - require.Equal(t, "linkpub1cqmsrdepq27djm9tzq3sftqsayx95refxk8r5jn0kyshhql9mdjhjx829zlvzygzwr2", - pubKeyAddr, "Is your device using test mnemonic: %s ?", testutil.TestMnemonic) - - addr := sdk.BytesToAccAddress(priv.PubKey().Address()).String() + "Is your device using test mnemonic: %s ?", testdata.TestMnemonic) + require.Equal(t, expectedPkStr, priv.PubKey().String()) + addr := sdk.BytesToAccAddress(priv.PubKey().Address()) require.Equal(t, "link1tdl7n2acgmec0y5nng0q2fahl9khyct3cgsktn", - addr, "Is your device using test mnemonic: %s ?", testutil.TestMnemonic) + addr.String(), "Is your device using test mnemonic: %s ?", testdata.TestMnemonic) } func TestPublicKeyUnsafeHDPath(t *testing.T) { expectedAnswers := []string{ - "linkpub1cqmsrdepq27djm9tzq3sftqsayx95refxk8r5jn0kyshhql9mdjhjx829zlvzygzwr2", - "linkpub1cqmsrdepqf258jtwpyujhxmlg94500j9yzqya5ryl835yp3dm6p9up25ufqcsx6q5xz", - "linkpub1cqmsrdepq2edmckd0zthve9r70err6ctxzqc4vt5648lu4fzqkld8dnaekzjct0cr4e", - "linkpub1cqmsrdepqg9xfexl88nvmyyzpg5htz5qz30wgdftf0puz5u3sj6jkk9fxy7vzu52r6p", - "linkpub1cqmsrdepqv09egt2l0u72a4h0stkcrx4hyz0z6mnxe5w5d7lzmmzfdj2mykj7q7c73e", - "linkpub1cqmsrdepqfn9d7tew6vlr37sy9crsdud2gufsftm7wz3r2uhze2lfam4a263qycs2m3", - "linkpub1cqmsrdepqfaq649vgk3levrsya2wkz8aecjxxd40rdfjhr6aqlld5ql54fds2sz53ae", - "linkpub1cqmsrdepqv43zgg5dauwynq4wyqz3c6xtl9wcmc8z8ftgqvj87xs000lld6s69a44hh", - "linkpub1cqmsrdepq0kchl479dz7f28hgfn7ve3txkktu9trq2dpmrzjy9awlyuf8w6x78kzujv", - "linkpub1cqmsrdepqttsm9aacj9pq3w22xjms6lgyzxhhdjrrajt4hzzfl0melff9w9dq3nqpcv", + "PubKeySecp256k1{02BCD96CAB102304AC10E90C5A0F29358E3A4A6FB1217B83E5DB657918EA28BEC1}", + "PubKeySecp256k1{025543C96E09392B9B7F416B47BE4520804ED064F9E342062DDE825E0554E24188}", + "PubKeySecp256k1{02B2DDE2CD78977664A3F3F231EB0B30818AB174D54FFE552205BED3B67DCD852C}", + "PubKeySecp256k1{020A64E4DF39E6CD90820A29758A80145EE4352B4BC3C1539184B52B58A9313CC1}", + "PubKeySecp256k1{031E5CA16AFBF9E576B77C176C0CD5B904F16B733668EA37DF16F624B64AD92D2F}", + "PubKeySecp256k1{026656F9797699F1C7D0217038378D523898257BF38511AB971655F4F775EAB510}", + "PubKeySecp256k1{027A0D54AC45A3FCB0702754EB08FDCE246336AF1B532B8F5D07FEDA03F4AA5B05}", + "PubKeySecp256k1{032B1121146F78E24C15710028E3465FCAEC6F0711D2B401923F8D07BDFFFB750D}", + "PubKeySecp256k1{03ED8BFEBE2B45E4A8F74267E6662B35ACBE1563029A1D8C52217AEF93893BB46F}", + "PubKeySecp256k1{02D70D97BDC48A1045CA51A5B86BE8208D7BB6431F64BADC424FDFBCFD292B8AD0}", } const numIters = 10 @@ -73,11 +72,9 @@ func TestPublicKeyUnsafeHDPath(t *testing.T) { require.NoError(t, tmp.ValidateKey()) (&tmp).AssertIsPrivKeyInner() - pubKeyAddr, err := sdk.Bech32ifyPubKey(sdk.Bech32PubKeyTypeAccPub, priv.PubKey()) - require.NoError(t, err) - require.Equal(t, - expectedAnswers[i], pubKeyAddr, - "Is your device using test mnemonic: %s ?", testutil.TestMnemonic) + // in this test we are chekcking if the generated keys are correct. + require.Equal(t, expectedAnswers[i], priv.PubKey().String(), + "Is your device using test mnemonic: %s ?", testdata.TestMnemonic) // Store and restore serializedPk := priv.Bytes() @@ -98,24 +95,12 @@ func TestPublicKeyUnsafeHDPath(t *testing.T) { func TestPublicKeySafe(t *testing.T) { path := *hd.NewFundraiserParams(0, sdk.CoinType, 0) - priv, addr, err := NewPrivKeySecp256k1(path, "cosmos") + priv, addr, err := NewPrivKeySecp256k1(path, "link") require.NoError(t, err) require.NotNil(t, priv) - require.Nil(t, ShowAddress(path, priv.PubKey(), sdk.GetConfig().GetBech32AccountAddrPrefix())) - - require.Equal(t, "c03701b72102bcd96cab102304ac10e90c5a0f29358e3a4a6fb1217b83e5db657918ea28bec1", - fmt.Sprintf("%x", cdc.Amino.MustMarshalBinaryBare(priv.PubKey())), - "Is your device using test mnemonic: %s ?", testutil.TestMnemonic) - - pubKeyAddr, err := sdk.Bech32ifyPubKey(sdk.Bech32PubKeyTypeAccPub, priv.PubKey()) - require.NoError(t, err) - require.Equal(t, "linkpub1cqmsrdepq27djm9tzq3sftqsayx95refxk8r5jn0kyshhql9mdjhjx829zlvzygzwr2", - pubKeyAddr, "Is your device using test mnemonic: %s ?", testutil.TestMnemonic) - - require.Equal(t, "link1tdl7n2acgmec0y5nng0q2fahl9khyct3cgsktn", - addr, "Is your device using test mnemonic: %s ?", testutil.TestMnemonic) + checkDefaultPubKey(t, priv) addr2 := sdk.BytesToAccAddress(priv.PubKey().Address()).String() require.Equal(t, addr, addr2) @@ -123,16 +108,16 @@ func TestPublicKeySafe(t *testing.T) { func TestPublicKeyHDPath(t *testing.T) { expectedPubKeys := []string{ - "linkpub1cqmsrdepq27djm9tzq3sftqsayx95refxk8r5jn0kyshhql9mdjhjx829zlvzygzwr2", - "linkpub1cqmsrdepqf258jtwpyujhxmlg94500j9yzqya5ryl835yp3dm6p9up25ufqcsx6q5xz", - "linkpub1cqmsrdepq2edmckd0zthve9r70err6ctxzqc4vt5648lu4fzqkld8dnaekzjct0cr4e", - "linkpub1cqmsrdepqg9xfexl88nvmyyzpg5htz5qz30wgdftf0puz5u3sj6jkk9fxy7vzu52r6p", - "linkpub1cqmsrdepqv09egt2l0u72a4h0stkcrx4hyz0z6mnxe5w5d7lzmmzfdj2mykj7q7c73e", - "linkpub1cqmsrdepqfn9d7tew6vlr37sy9crsdud2gufsftm7wz3r2uhze2lfam4a263qycs2m3", - "linkpub1cqmsrdepqfaq649vgk3levrsya2wkz8aecjxxd40rdfjhr6aqlld5ql54fds2sz53ae", - "linkpub1cqmsrdepqv43zgg5dauwynq4wyqz3c6xtl9wcmc8z8ftgqvj87xs000lld6s69a44hh", - "linkpub1cqmsrdepq0kchl479dz7f28hgfn7ve3txkktu9trq2dpmrzjy9awlyuf8w6x78kzujv", - "linkpub1cqmsrdepqttsm9aacj9pq3w22xjms6lgyzxhhdjrrajt4hzzfl0melff9w9dq3nqpcv", + "PubKeySecp256k1{02BCD96CAB102304AC10E90C5A0F29358E3A4A6FB1217B83E5DB657918EA28BEC1}", + "PubKeySecp256k1{025543C96E09392B9B7F416B47BE4520804ED064F9E342062DDE825E0554E24188}", + "PubKeySecp256k1{02B2DDE2CD78977664A3F3F231EB0B30818AB174D54FFE552205BED3B67DCD852C}", + "PubKeySecp256k1{020A64E4DF39E6CD90820A29758A80145EE4352B4BC3C1539184B52B58A9313CC1}", + "PubKeySecp256k1{031E5CA16AFBF9E576B77C176C0CD5B904F16B733668EA37DF16F624B64AD92D2F}", + "PubKeySecp256k1{026656F9797699F1C7D0217038378D523898257BF38511AB971655F4F775EAB510}", + "PubKeySecp256k1{027A0D54AC45A3FCB0702754EB08FDCE246336AF1B532B8F5D07FEDA03F4AA5B05}", + "PubKeySecp256k1{032B1121146F78E24C15710028E3465FCAEC6F0711D2B401923F8D07BDFFFB750D}", + "PubKeySecp256k1{03ED8BFEBE2B45E4A8F74267E6662B35ACBE1563029A1D8C52217AEF93893BB46F}", + "PubKeySecp256k1{02D70D97BDC48A1045CA51A5B86BE8208D7BB6431F64BADC424FDFBCFD292B8AD0}", } expectedAddrs := []string{ @@ -153,11 +138,11 @@ func TestPublicKeyHDPath(t *testing.T) { privKeys := make([]types.LedgerPrivKey, numIters) // Check with device - for i := uint32(0); i < 10; i++ { - path := *hd.NewFundraiserParams(0, sdk.CoinType, i) + for i := 0; i < len(expectedAddrs); i++ { + path := *hd.NewFundraiserParams(0, sdk.CoinType, uint32(i)) t.Logf("Checking keys at %s\n", path) - priv, addr, err := NewPrivKeySecp256k1(path, "cosmos") + priv, addr, err := NewPrivKeySecp256k1(path, "link") require.NoError(t, err) require.NotNil(t, addr) require.NotNil(t, priv) @@ -166,18 +151,17 @@ func TestPublicKeyHDPath(t *testing.T) { require.Equal(t, addr2, addr) require.Equal(t, expectedAddrs[i], addr, - "Is your device using test mnemonic: %s ?", testutil.TestMnemonic) + "Is your device using test mnemonic: %s ?", testdata.TestMnemonic) // Check other methods tmp := priv.(PrivKeyLedgerSecp256k1) require.NoError(t, tmp.ValidateKey()) (&tmp).AssertIsPrivKeyInner() - pubKeyAddr, err := sdk.Bech32ifyPubKey(sdk.Bech32PubKeyTypeAccPub, priv.PubKey()) - require.NoError(t, err) + // in this test we are chekcking if the generated keys are correct and stored in a right path. require.Equal(t, - expectedPubKeys[i], pubKeyAddr, - "Is your device using test mnemonic: %s ?", testutil.TestMnemonic) + expectedPubKeys[i], priv.PubKey().String(), + "Is your device using test mnemonic: %s ?", testdata.TestMnemonic) // Store and restore serializedPk := priv.Bytes() @@ -219,7 +203,7 @@ func TestSignaturesHD(t *testing.T) { require.NoError(t, err) valid := pub.VerifySignature(msg, sig) - require.True(t, valid, "Is your device using test mnemonic: %s ?", testutil.TestMnemonic) + require.True(t, valid, "Is your device using test mnemonic: %s ?", testdata.TestMnemonic) } } @@ -251,7 +235,7 @@ func TestRealDeviceSecp256k1(t *testing.T) { require.True(t, valid) // make sure pubkeys serialize properly as well - bs = legacy.Cdc.MustMarshalBinaryBare(pub) + bs = legacy.Cdc.MustMarshal(pub) bpub, err := legacy.PubKeyFromBytes(bs) require.NoError(t, err) require.Equal(t, pub, bpub) diff --git a/crypto/types/compact_bit_array.go b/crypto/types/compact_bit_array.go index cf17cefe58..1bbd5ec07d 100644 --- a/crypto/types/compact_bit_array.go +++ b/crypto/types/compact_bit_array.go @@ -6,6 +6,7 @@ import ( "errors" "fmt" "math" + "math/bits" "regexp" "strings" ) @@ -41,41 +42,41 @@ func NewCompactBitArray(bits int) *CompactBitArray { func (bA *CompactBitArray) Count() int { if bA == nil { return 0 - } else if bA.ExtraBitsStored == uint32(0) { + } else if bA.ExtraBitsStored == 0 { return len(bA.Elems) * 8 } return (len(bA.Elems)-1)*8 + int(bA.ExtraBitsStored) } -// GetIndex returns the bit at index i within the bit array. +// GetIndex returns true if the bit at index i is set; returns false otherwise. // The behavior is undefined if i >= bA.Count() func (bA *CompactBitArray) GetIndex(i int) bool { if bA == nil { return false } - if i >= bA.Count() { + if i < 0 || i >= bA.Count() { return false } - return bA.Elems[i>>3]&(uint8(1)< 0 + return bA.Elems[i>>3]&(1< 0 } -// SetIndex sets the bit at index i within the bit array. -// The behavior is undefined if i >= bA.Count() +// SetIndex sets the bit at index i within the bit array. Returns true if and only if the +// operation succeeded. The behavior is undefined if i >= bA.Count() func (bA *CompactBitArray) SetIndex(i int, v bool) bool { if bA == nil { return false } - if i >= bA.Count() { + if i < 0 || i >= bA.Count() { return false } if v { - bA.Elems[i>>3] |= (uint8(1) << uint8(7-(i%8))) + bA.Elems[i>>3] |= (1 << uint8(7-(i%8))) } else { - bA.Elems[i>>3] &= ^(uint8(1) << uint8(7-(i%8))) + bA.Elems[i>>3] &= ^(1 << uint8(7-(i%8))) } return true @@ -85,14 +86,19 @@ func (bA *CompactBitArray) SetIndex(i int, v bool) bool { // given index. e.g. if bA = _XX__XX, NumOfTrueBitsBefore(4) = 2, since // there are two bits set to true before index 4. func (bA *CompactBitArray) NumTrueBitsBefore(index int) int { - numTrueValues := 0 - for i := 0; i < index; i++ { - if bA.GetIndex(i) { - numTrueValues++ + onesCount := 0 + max := bA.Count() + if index > max { + index = max + } + // below we iterate over the bytes then over bits (in low endian) and count bits set to 1 + for elem := 0; ; elem++ { + if elem*8+7 >= index { + onesCount += bits.OnesCount8(bA.Elems[elem] >> (7 - (index % 8) + 1)) + return onesCount } + onesCount += bits.OnesCount8(bA.Elems[elem]) } - - return numTrueValues } // Copy returns a copy of the provided bit array. @@ -110,6 +116,18 @@ func (bA *CompactBitArray) Copy() *CompactBitArray { } } +// Equal checks if both bit arrays are equal. If both arrays are nil then it returns true. +func (bA *CompactBitArray) Equal(other *CompactBitArray) bool { + if bA == other { + return true + } + if bA == nil || other == nil { + return false + } + return bA.ExtraBitsStored == other.ExtraBitsStored && + bytes.Equal(bA.Elems, other.Elems) +} + // String returns a string representation of CompactBitArray: BA{}, // where is a sequence of 'x' (1) and '_' (0). // The includes spaces and newlines to help people. @@ -240,6 +258,9 @@ func CompactUnmarshal(bz []byte) (*CompactBitArray, error) { } size, n := binary.Uvarint(bz) + if n < 0 || n >= len(bz) { + return nil, fmt.Errorf("compact bit array: n=%d is out of range of len(bz)=%d", n, len(bz)) + } bz = bz[n:] if len(bz) != int(size+7)/8 { diff --git a/crypto/types/compact_bit_array_test.go b/crypto/types/compact_bit_array_test.go index 9b5a6460cc..5ae976da19 100644 --- a/crypto/types/compact_bit_array_test.go +++ b/crypto/types/compact_bit_array_test.go @@ -38,6 +38,34 @@ func TestNewBitArrayNeverCrashesOnNegatives(t *testing.T) { } } +func TestBitArrayEqual(t *testing.T) { + empty := new(CompactBitArray) + big1, _ := randCompactBitArray(1000) + big1Cpy := *big1 + big2, _ := randCompactBitArray(1000) + big2.SetIndex(500, !big1.GetIndex(500)) // ensure they are different + cases := []struct { + name string + b1 *CompactBitArray + b2 *CompactBitArray + eq bool + }{ + {name: "both nil are equal", b1: nil, b2: nil, eq: true}, + {name: "if one is nil then not equal", b1: nil, b2: empty, eq: false}, + {name: "nil and empty not equal", b1: empty, b2: nil, eq: false}, + {name: "empty and empty equal", b1: empty, b2: new(CompactBitArray), eq: true}, + {name: "same bits should be equal", b1: big1, b2: &big1Cpy, eq: true}, + {name: "different should not be equal", b1: big1, b2: big2, eq: false}, + } + for _, tc := range cases { + tc := tc + t.Run(tc.name, func(t *testing.T) { + eq := tc.b1.Equal(tc.b2) + require.Equal(t, tc.eq, eq) + }) + } +} + func TestJSONMarshalUnmarshal(t *testing.T) { bA1 := NewCompactBitArray(0) @@ -156,6 +184,17 @@ func TestCompactMarshalUnmarshal(t *testing.T) { } } +// Ensure that CompactUnmarshal does not blindly try to slice using +// a negative/out of bounds index of size returned from binary.Uvarint. +// See issue https://github.com/cosmos/cosmos-sdk/issues/9165 +func TestCompactMarshalUnmarshalReturnsErrorOnInvalidSize(t *testing.T) { + malicious := []byte{0xd7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0x24, 0x28} + cba, err := CompactUnmarshal(malicious) + require.Error(t, err) + require.Nil(t, cba) + require.Contains(t, err.Error(), "n=-11 is out of range of len(bz)=13") +} + func TestCompactBitArrayNumOfTrueBitsBefore(t *testing.T) { testCases := []struct { marshalledBA string @@ -199,6 +238,15 @@ func TestCompactBitArrayGetSetIndex(t *testing.T) { val := (r.Int63() % 2) == 0 bA.SetIndex(index, val) require.Equal(t, val, bA.GetIndex(index), "bA.SetIndex(%d, %v) failed on bit array: %s", index, val, copy) + + // Ensure that passing in negative indices to .SetIndex and .GetIndex do not + // panic. See issue https://github.com/cosmos/cosmos-sdk/issues/9164. + // To intentionally use negative indices, We want only values that aren't 0. + if index == 0 { + continue + } + require.False(t, bA.SetIndex(-index, val)) + require.False(t, bA.GetIndex(-index)) } } } diff --git a/crypto/types/multisig/multisignature.go b/crypto/types/multisig/multisignature.go index 70ae6a1090..fee8ae9641 100644 --- a/crypto/types/multisig/multisignature.go +++ b/crypto/types/multisig/multisignature.go @@ -34,7 +34,8 @@ func getIndex(pk types.PubKey, keys []types.PubKey) int { return -1 } -// AddSignature adds a signature to the multisig, at the corresponding index. +// AddSignature adds a signature to the multisig, at the corresponding index. The index must +// represent the pubkey index in the LegacyAmingPubKey structure, which verifies this signature. // If the signature already exists, replace it. func AddSignature(mSig *signing.MultiSignatureData, sig signing.SignatureData, index int) { newSigIndex := mSig.BitArray.NumTrueBitsBefore(index) diff --git a/crypto/types/types.go b/crypto/types/types.go index b31c37bea1..81685a41be 100644 --- a/crypto/types/types.go +++ b/crypto/types/types.go @@ -20,7 +20,7 @@ type PubKey interface { // LedgerSecp256k1 keys are not converted to proto.Message yet, this is why // they use LedgerPrivKey instead of PrivKey. All other keys must use PrivKey // instead of LedgerPrivKey. -// TODO https://github.com/line/lbm-sdk/issues/7357. +// TODO https://github.com/cosmos/cosmos-sdk/issues/7357. type LedgerPrivKey interface { Bytes() []byte Sign(msg []byte) ([]byte, error) @@ -32,7 +32,7 @@ type LedgerPrivKey interface { // PrivKey defines a private key and extends proto.Message. For now, it extends // LedgerPrivKey (see godoc for LedgerPrivKey). Ultimately, we should remove // LedgerPrivKey and add its methods here directly. -// TODO https://github.com/line/lbm-sdk/issues/7357. +// TODO https://github.com/cosmos/cosmos-sdk/issues/7357. type PrivKey interface { proto.Message LedgerPrivKey diff --git a/docker-compose.yml b/docker-compose.yml index d335b9a06c..a5ef517e54 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -12,7 +12,7 @@ services: - ID=0 - LOG=${LOG:-simd.log} volumes: - - ./build:/simd:Z + - ./localnet:/data:Z networks: localnet: ipv4_address: 192.168.10.2 @@ -28,7 +28,7 @@ services: - ID=1 - LOG=${LOG:-simd.log} volumes: - - ./build:/simd:Z + - ./localnet:/data:Z networks: localnet: ipv4_address: 192.168.10.3 @@ -44,7 +44,7 @@ services: - "1319:1317" - "9092:9090" volumes: - - ./build:/simd:Z + - ./localnet:/data:Z networks: localnet: ipv4_address: 192.168.10.4 @@ -60,7 +60,7 @@ services: - "1320:1317" - "9093:9090" volumes: - - ./build:/simd:Z + - ./localnet:/data:Z networks: localnet: ipv4_address: 192.168.10.5 diff --git a/docs/404.md b/docs/404.md new file mode 100644 index 0000000000..d7b8b16782 --- /dev/null +++ b/docs/404.md @@ -0,0 +1,47 @@ + + +# 404 - Lost in space, this is just an empty void diff --git a/docs/DOC_WRITING_GUIDELINES.md b/docs/DOC_WRITING_GUIDELINES.md new file mode 100644 index 0000000000..424da301ff --- /dev/null +++ b/docs/DOC_WRITING_GUIDELINES.md @@ -0,0 +1,15 @@ +# Documentation Writing Guidelines + +## Best Practices + ++ Check the spelling and grammar, even if you have to copy and paste from an external source. ++ Use simple sentences. Easy-to-read sentences mean the reader can quickly use the guidance you share. ++ Try to express your thoughts in a concise and clean way. ++ Don't abuse `code` format when writing in plain English. ++ Follow Google developer documentation [style guide](https://developers.google.com/style). ++ Check the meaning of words in Microsoft's [A-Z word list and term collections](https://docs.microsoft.com/en-us/style-guide/a-z-word-list-term-collections/term-collections/accessibility-terms) (use the search input!). ++ RFC keywords should be used in technical documents (uppercase) and we recommend to use them in user documentation (lowercase). The RFC keywords are: "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL. They are to be interpreted as described in [RFC 2119](https://datatracker.ietf.org/doc/html/rfc2119). + +## Technical Writing Course + +Google provides a free [course](https://developers.google.com/tech-writing/overview) for technical writing. diff --git a/docs/building-modules/upgrade.md b/docs/building-modules/upgrade.md new file mode 100644 index 0000000000..f1c37930cf --- /dev/null +++ b/docs/building-modules/upgrade.md @@ -0,0 +1,57 @@ + + +# Upgrading Modules + +[In-Place Store Migrations](../core/upgrade.html) allow your modules to upgrade to new versions that include breaking changes. This document outlines how to build modules to take advantage of this functionality. {synopsis} + +## Prerequisite Readings + +- [In-Place Store Migration](../core/upgrade.md) {prereq} + +## Consensus Version + +Successful upgrades of existing modules require each `AppModule` to implement the function `ConsensusVersion() uint64`. + +- The versions must be hard-coded by the module developer. +- The initial version **must** be set to 1. + +Consensus versions serve as state-breaking versions of app modules and must be incremented when the module introduces breaking changes. + +## Registering Migrations + +To register the functionality that takes place during a module upgrade, you must register which migrations you want to take place. + +Migration registration takes place in the `Configurator` using the `RegisterMigration` method. The `AppModule` reference to the configurator is in the `RegisterServices` method. + +You can register one or more migrations. If you register more than one migration script, list the migrations in increasing order and ensure there are enough migrations that lead to the desired consensus version. For example, to migrate to version 3 of a module, register separate migrations for version 1 and version 2 as shown in the following example: + +```golang +func (am AppModule) RegisterServices(cfg module.Configurator) { + // --snip-- + cfg.RegisterMigration(types.ModuleName, 1, func(ctx sdk.Context) error { + // Perform in-place store migrations from ConsensusVersion 1 to 2. + }) + cfg.RegisterMigration(types.ModuleName, 2, func(ctx sdk.Context) error { + // Perform in-place store migrations from ConsensusVersion 2 to 3. + }) +} +``` + +Since these migrations are functions that need access to a Keeper's store, use a wrapper around the keepers called `Migrator` as shown in this example: + ++++ https://github.com/cosmos/cosmos-sdk/blob/6ac8898fec9bd7ea2c1e5c79e0ed0c3f827beb55/x/bank/keeper/migrations.go#L8-L21 + +## Writing Migration Scripts + +To define the functionality that takes place during an upgrade, write a migration script. Since migration scripts manipulate legacy code, place these functions in a `legacy/` directory. For example, to write migration scripts for the bank module, place the functions in `x/bank/legacy/`. Use the recommended naming convention for these functions. For example, `v043bank` is the script that migrates this legacy package `x/bank/legacy/v043`: + +```golang +// Migrating bank module from version 1 to 2 +func (m Migrator) Migrate1to2(ctx sdk.Context) error { + return v043bank.MigrateStore(ctx, m.keeper.storeKey) // v043bank is package `x/bank/legacy/v043`. +} +``` + +To see example code of changes that were implemented in a migration of balance keys, check out [migrateBalanceKeys](https://github.com/cosmos/cosmos-sdk/blob/36f68eb9e041e20a5bb47e216ac5eb8b91f95471/x/bank/legacy/v043/store.go#L41-L62). For context, this code introduced migrations of the bank store that updated addresses to be prefixed by their length in bytes as outlined in [ADR-028](../architecture/adr-028-public-key-addresses.md). diff --git a/docs/core/proto-docs.md b/docs/core/proto-docs.md index d4911bd5b2..2588e09f8f 100644 --- a/docs/core/proto-docs.md +++ b/docs/core/proto-docs.md @@ -32,6 +32,12 @@ - [DecProto](#lbm.base.v1.DecProto) - [IntProto](#lbm.base.v1.IntProto) +- [lbm/upgrade/v1/upgrade.proto](#lbm/upgrade/v1/upgrade.proto) + - [CancelSoftwareUpgradeProposal](#lbm.upgrade.v1.CancelSoftwareUpgradeProposal) + - [ModuleVersion](#lbm.upgrade.v1.ModuleVersion) + - [Plan](#lbm.upgrade.v1.Plan) + - [SoftwareUpgradeProposal](#lbm.upgrade.v1.SoftwareUpgradeProposal) + - [ibc/core/client/v1/client.proto](#ibc/core/client/v1/client.proto) - [ClientConsensusStates](#ibc.core.client.v1.ClientConsensusStates) - [ClientUpdateProposal](#ibc.core.client.v1.ClientUpdateProposal) @@ -39,6 +45,7 @@ - [Height](#ibc.core.client.v1.Height) - [IdentifiedClientState](#ibc.core.client.v1.IdentifiedClientState) - [Params](#ibc.core.client.v1.Params) + - [UpgradeProposal](#ibc.core.client.v1.UpgradeProposal) - [ibc/applications/transfer/v1/tx.proto](#ibc/applications/transfer/v1/tx.proto) - [MsgTransfer](#ibc.applications.transfer.v1.MsgTransfer) @@ -131,6 +138,8 @@ - [QueryConsensusStateResponse](#ibc.core.client.v1.QueryConsensusStateResponse) - [QueryConsensusStatesRequest](#ibc.core.client.v1.QueryConsensusStatesRequest) - [QueryConsensusStatesResponse](#ibc.core.client.v1.QueryConsensusStatesResponse) + - [QueryUpgradedClientStateRequest](#ibc.core.client.v1.QueryUpgradedClientStateRequest) + - [QueryUpgradedClientStateResponse](#ibc.core.client.v1.QueryUpgradedClientStateResponse) - [Query](#ibc.core.client.v1.Query) @@ -235,6 +244,10 @@ - [PrivKey](#lbm.crypto.secp256k1.PrivKey) - [PubKey](#lbm.crypto.secp256k1.PubKey) +- [lbm/crypto/secp256r1/keys.proto](#lbm/crypto/secp256r1/keys.proto) + - [PrivKey](#lbm.crypto.secp256r1.PrivKey) + - [PubKey](#lbm.crypto.secp256r1.PubKey) + - [lbm/auth/v1/auth.proto](#lbm/auth/v1/auth.proto) - [BaseAccount](#lbm.auth.v1.BaseAccount) - [ModuleAccount](#lbm.auth.v1.ModuleAccount) @@ -246,6 +259,8 @@ - [lbm/auth/v1/query.proto](#lbm/auth/v1/query.proto) - [QueryAccountRequest](#lbm.auth.v1.QueryAccountRequest) - [QueryAccountResponse](#lbm.auth.v1.QueryAccountResponse) + - [QueryAccountsRequest](#lbm.auth.v1.QueryAccountsRequest) + - [QueryAccountsResponse](#lbm.auth.v1.QueryAccountsResponse) - [QueryParamsRequest](#lbm.auth.v1.QueryParamsRequest) - [QueryParamsResponse](#lbm.auth.v1.QueryParamsResponse) @@ -257,6 +272,49 @@ - [Msg](#lbm.auth.v1.Msg) +- [lbm/authz/v1/authz.proto](#lbm/authz/v1/authz.proto) + - [GenericAuthorization](#lbm.authz.v1.GenericAuthorization) + - [Grant](#lbm.authz.v1.Grant) + +- [lbm/authz/v1/event.proto](#lbm/authz/v1/event.proto) + - [EventGrant](#lbm.authz.v1.EventGrant) + - [EventRevoke](#lbm.authz.v1.EventRevoke) + +- [lbm/base/abci/v1/abci.proto](#lbm/base/abci/v1/abci.proto) + - [ABCIMessageLog](#lbm.base.abci.v1.ABCIMessageLog) + - [Attribute](#lbm.base.abci.v1.Attribute) + - [GasInfo](#lbm.base.abci.v1.GasInfo) + - [MsgData](#lbm.base.abci.v1.MsgData) + - [Result](#lbm.base.abci.v1.Result) + - [SearchTxsResult](#lbm.base.abci.v1.SearchTxsResult) + - [SimulationResponse](#lbm.base.abci.v1.SimulationResponse) + - [StringEvent](#lbm.base.abci.v1.StringEvent) + - [TxMsgData](#lbm.base.abci.v1.TxMsgData) + - [TxResponse](#lbm.base.abci.v1.TxResponse) + +- [lbm/authz/v1/tx.proto](#lbm/authz/v1/tx.proto) + - [MsgExec](#lbm.authz.v1.MsgExec) + - [MsgExecResponse](#lbm.authz.v1.MsgExecResponse) + - [MsgGrant](#lbm.authz.v1.MsgGrant) + - [MsgGrantResponse](#lbm.authz.v1.MsgGrantResponse) + - [MsgRevoke](#lbm.authz.v1.MsgRevoke) + - [MsgRevokeResponse](#lbm.authz.v1.MsgRevokeResponse) + + - [Msg](#lbm.authz.v1.Msg) + +- [lbm/authz/v1/genesis.proto](#lbm/authz/v1/genesis.proto) + - [GenesisState](#lbm.authz.v1.GenesisState) + - [GrantAuthorization](#lbm.authz.v1.GrantAuthorization) + +- [lbm/authz/v1/query.proto](#lbm/authz/v1/query.proto) + - [QueryGrantsRequest](#lbm.authz.v1.QueryGrantsRequest) + - [QueryGrantsResponse](#lbm.authz.v1.QueryGrantsResponse) + + - [Query](#lbm.authz.v1.Query) + +- [lbm/bank/v1/authz.proto](#lbm/bank/v1/authz.proto) + - [SendAuthorization](#lbm.bank.v1.SendAuthorization) + - [lbm/bank/v1/bank.proto](#lbm/bank/v1/bank.proto) - [DenomUnit](#lbm.bank.v1.DenomUnit) - [Input](#lbm.bank.v1.Input) @@ -299,18 +357,6 @@ - [lbm/bankplus/v1/bankplus.proto](#lbm/bankplus/v1/bankplus.proto) - [InactiveAddr](#lbm.bankplus.v1.InactiveAddr) -- [lbm/base/abci/v1/abci.proto](#lbm/base/abci/v1/abci.proto) - - [ABCIMessageLog](#lbm.base.abci.v1.ABCIMessageLog) - - [Attribute](#lbm.base.abci.v1.Attribute) - - [GasInfo](#lbm.base.abci.v1.GasInfo) - - [MsgData](#lbm.base.abci.v1.MsgData) - - [Result](#lbm.base.abci.v1.Result) - - [SearchTxsResult](#lbm.base.abci.v1.SearchTxsResult) - - [SimulationResponse](#lbm.base.abci.v1.SimulationResponse) - - [StringEvent](#lbm.base.abci.v1.StringEvent) - - [TxMsgData](#lbm.base.abci.v1.TxMsgData) - - [TxResponse](#lbm.base.abci.v1.TxResponse) - - [lbm/base/kv/v1/kv.proto](#lbm/base/kv/v1/kv.proto) - [Pair](#lbm.base.kv.v1.Pair) - [Pairs](#lbm.base.kv.v1.Pairs) @@ -346,6 +392,36 @@ - [ReflectionService](#lbm.base.reflection.v1.ReflectionService) +- [lbm/base/reflection/v2/reflection.proto](#lbm/base/reflection/v2/reflection.proto) + - [AppDescriptor](#lbm.base.reflection.v2.AppDescriptor) + - [AuthnDescriptor](#lbm.base.reflection.v2.AuthnDescriptor) + - [ChainDescriptor](#lbm.base.reflection.v2.ChainDescriptor) + - [CodecDescriptor](#lbm.base.reflection.v2.CodecDescriptor) + - [ConfigurationDescriptor](#lbm.base.reflection.v2.ConfigurationDescriptor) + - [GetAuthnDescriptorRequest](#lbm.base.reflection.v2.GetAuthnDescriptorRequest) + - [GetAuthnDescriptorResponse](#lbm.base.reflection.v2.GetAuthnDescriptorResponse) + - [GetChainDescriptorRequest](#lbm.base.reflection.v2.GetChainDescriptorRequest) + - [GetChainDescriptorResponse](#lbm.base.reflection.v2.GetChainDescriptorResponse) + - [GetCodecDescriptorRequest](#lbm.base.reflection.v2.GetCodecDescriptorRequest) + - [GetCodecDescriptorResponse](#lbm.base.reflection.v2.GetCodecDescriptorResponse) + - [GetConfigurationDescriptorRequest](#lbm.base.reflection.v2.GetConfigurationDescriptorRequest) + - [GetConfigurationDescriptorResponse](#lbm.base.reflection.v2.GetConfigurationDescriptorResponse) + - [GetQueryServicesDescriptorRequest](#lbm.base.reflection.v2.GetQueryServicesDescriptorRequest) + - [GetQueryServicesDescriptorResponse](#lbm.base.reflection.v2.GetQueryServicesDescriptorResponse) + - [GetTxDescriptorRequest](#lbm.base.reflection.v2.GetTxDescriptorRequest) + - [GetTxDescriptorResponse](#lbm.base.reflection.v2.GetTxDescriptorResponse) + - [InterfaceAcceptingMessageDescriptor](#lbm.base.reflection.v2.InterfaceAcceptingMessageDescriptor) + - [InterfaceDescriptor](#lbm.base.reflection.v2.InterfaceDescriptor) + - [InterfaceImplementerDescriptor](#lbm.base.reflection.v2.InterfaceImplementerDescriptor) + - [MsgDescriptor](#lbm.base.reflection.v2.MsgDescriptor) + - [QueryMethodDescriptor](#lbm.base.reflection.v2.QueryMethodDescriptor) + - [QueryServiceDescriptor](#lbm.base.reflection.v2.QueryServiceDescriptor) + - [QueryServicesDescriptor](#lbm.base.reflection.v2.QueryServicesDescriptor) + - [SigningModeDescriptor](#lbm.base.reflection.v2.SigningModeDescriptor) + - [TxDescriptor](#lbm.base.reflection.v2.TxDescriptor) + + - [ReflectionService](#lbm.base.reflection.v2.ReflectionService) + - [lbm/base/snapshots/v1/snapshot.proto](#lbm/base/snapshots/v1/snapshot.proto) - [Metadata](#lbm.base.snapshots.v1.Metadata) - [Snapshot](#lbm.base.snapshots.v1.Snapshot) @@ -355,6 +431,9 @@ - [CommitInfo](#lbm.base.store.v1.CommitInfo) - [StoreInfo](#lbm.base.store.v1.StoreInfo) +- [lbm/base/store/v1/listening.proto](#lbm/base/store/v1/listening.proto) + - [StoreKVPair](#lbm.base.store.v1.StoreKVPair) + - [lbm/base/store/v1/snapshot.proto](#lbm/base/store/v1/snapshot.proto) - [SnapshotIAVLItem](#lbm.base.store.v1.SnapshotIAVLItem) - [SnapshotItem](#lbm.base.store.v1.SnapshotItem) @@ -613,6 +692,12 @@ - [Msg](#lbm.slashing.v1.Msg) +- [lbm/staking/v1/authz.proto](#lbm/staking/v1/authz.proto) + - [StakeAuthorization](#lbm.staking.v1.StakeAuthorization) + - [StakeAuthorization.Validators](#lbm.staking.v1.StakeAuthorization.Validators) + + - [AuthorizationType](#lbm.staking.v1.AuthorizationType) + - [lbm/staking/v1/staking.proto](#lbm/staking/v1/staking.proto) - [Commission](#lbm.staking.v1.Commission) - [CommissionRates](#lbm.staking.v1.CommissionRates) @@ -715,12 +800,12 @@ - [QueryApproveResponse](#lbm.token.v1.QueryApproveResponse) - [QueryApprovesRequest](#lbm.token.v1.QueryApprovesRequest) - [QueryApprovesResponse](#lbm.token.v1.QueryApprovesResponse) + - [QueryBalanceRequest](#lbm.token.v1.QueryBalanceRequest) + - [QueryBalanceResponse](#lbm.token.v1.QueryBalanceResponse) - [QueryGrantsRequest](#lbm.token.v1.QueryGrantsRequest) - [QueryGrantsResponse](#lbm.token.v1.QueryGrantsResponse) - [QuerySupplyRequest](#lbm.token.v1.QuerySupplyRequest) - [QuerySupplyResponse](#lbm.token.v1.QuerySupplyResponse) - - [QueryTokenBalanceRequest](#lbm.token.v1.QueryTokenBalanceRequest) - - [QueryTokenBalanceResponse](#lbm.token.v1.QueryTokenBalanceResponse) - [QueryTokenRequest](#lbm.token.v1.QueryTokenRequest) - [QueryTokenResponse](#lbm.token.v1.QueryTokenResponse) - [QueryTokensRequest](#lbm.token.v1.QueryTokensRequest) @@ -788,12 +873,6 @@ - [Service](#lbm.tx.v1.Service) -- [lbm/upgrade/v1/upgrade.proto](#lbm/upgrade/v1/upgrade.proto) - - [CancelSoftwareUpgradeProposal](#lbm.upgrade.v1.CancelSoftwareUpgradeProposal) - - [ModuleVersion](#lbm.upgrade.v1.ModuleVersion) - - [Plan](#lbm.upgrade.v1.Plan) - - [SoftwareUpgradeProposal](#lbm.upgrade.v1.SoftwareUpgradeProposal) - - [lbm/upgrade/v1/query.proto](#lbm/upgrade/v1/query.proto) - [QueryAppliedPlanRequest](#lbm.upgrade.v1.QueryAppliedPlanRequest) - [QueryAppliedPlanResponse](#lbm.upgrade.v1.QueryAppliedPlanResponse) @@ -818,6 +897,7 @@ - [DelayedVestingAccount](#lbm.vesting.v1.DelayedVestingAccount) - [Period](#lbm.vesting.v1.Period) - [PeriodicVestingAccount](#lbm.vesting.v1.PeriodicVestingAccount) + - [PermanentLockedAccount](#lbm.vesting.v1.PermanentLockedAccount) - [lbm/wasm/v1/types.proto](#lbm/wasm/v1/types.proto) - [AbsoluteTxPosition](#lbm.wasm.v1.AbsoluteTxPosition) @@ -1027,6 +1107,9 @@ pagination. Ex: | `offset` | [uint64](#uint64) | | offset is a numeric offset that can be used when key is unavailable. It is less efficient than using key. Only one of offset or key should be set. | | `limit` | [uint64](#uint64) | | limit is the total number of results to be returned in the result page. If left empty it will default to a value to be set by each app. | | `count_total` | [bool](#bool) | | count_total is set to true to indicate that the result set should include a count of the total number of items available for pagination in UIs. count_total is only respected when offset is used. It is ignored when key is set. | +| `reverse` | [bool](#bool) | | reverse is set to true if results are to be returned in the descending order. + +Since: cosmos-sdk 0.43 | @@ -1256,6 +1339,94 @@ IntProto defines a Protobuf wrapper around an Int object. + + + + + + + + + + + +

Top

+ +## lbm/upgrade/v1/upgrade.proto + + + + + +### CancelSoftwareUpgradeProposal +CancelSoftwareUpgradeProposal is a gov Content type for cancelling a software +upgrade. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `title` | [string](#string) | | | +| `description` | [string](#string) | | | + + + + + + + + +### ModuleVersion +ModuleVersion specifies a module and its consensus version. + +Since: cosmos-sdk 0.43 + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `name` | [string](#string) | | name of the app module | +| `version` | [uint64](#uint64) | | consensus version of the app module | + + + + + + + + +### Plan +Plan specifies information about a planned upgrade and when it should occur. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `name` | [string](#string) | | Sets the name for the upgrade. This name will be used by the upgraded version of the software to apply any special "on-upgrade" commands during the first BeginBlock method after the upgrade is applied. It is also used to detect whether a software version can handle a given upgrade. If no upgrade handler with this name has been set in the software, it will be assumed that the software is out-of-date when the upgrade Time or Height is reached and the software will exit. | +| `time` | [google.protobuf.Timestamp](#google.protobuf.Timestamp) | | **Deprecated.** Deprecated: Time based upgrades have been deprecated. Time based upgrade logic has been removed from the SDK. If this field is not empty, an error will be thrown. | +| `height` | [int64](#int64) | | The height at which the upgrade must be performed. Only used if Time is not set. | +| `info` | [string](#string) | | Any application specific upgrade info to be included on-chain such as a git commit that validators could automatically upgrade to | +| `upgraded_client_state` | [google.protobuf.Any](#google.protobuf.Any) | | **Deprecated.** Deprecated: UpgradedClientState field has been deprecated. IBC upgrade logic has been moved to the IBC module in the sub module 02-client. If this field is not empty, an error will be thrown. | + + + + + + + + +### SoftwareUpgradeProposal +SoftwareUpgradeProposal is a gov Content type for initiating a software +upgrade. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `title` | [string](#string) | | | +| `description` | [string](#string) | | | +| `plan` | [Plan](#lbm.upgrade.v1.Plan) | | | + + + + + @@ -1293,17 +1464,20 @@ client. ### ClientUpdateProposal -ClientUpdateProposal is a governance proposal. If it passes, the client is -updated with the provided header. The update may fail if the header is not -valid given certain conditions specified by the client implementation. +ClientUpdateProposal is a governance proposal. If it passes, the substitute client's +consensus states starting from the 'initial height' are copied over to the subjects +client state. The proposal handler may fail if the subject and the substitute do not +match in client and chain parameters (with exception to latest height, frozen height, and chain-id). +The updated client must also be valid (cannot be expired). | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | | `title` | [string](#string) | | the title of the update proposal | | `description` | [string](#string) | | the description of the proposal | -| `client_id` | [string](#string) | | the client identifier for the client to be updated if the proposal passes | -| `header` | [google.protobuf.Any](#google.protobuf.Any) | | the header used to update the client if the proposal passes | +| `subject_client_id` | [string](#string) | | the client identifier for the client to be updated if the proposal passes | +| `substitute_client_id` | [string](#string) | | the substitute client identifier for the client standing in for the subject client | +| `initial_height` | [Height](#ibc.core.client.v1.Height) | | the intital height to copy consensus states from the substitute to the subject | @@ -1381,6 +1555,25 @@ Params defines the set of IBC light client parameters. + + + +### UpgradeProposal +UpgradeProposal is a gov Content type for initiating an IBC breaking +upgrade. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `title` | [string](#string) | | | +| `description` | [string](#string) | | | +| `plan` | [lbm.upgrade.v1.Plan](#lbm.upgrade.v1.Plan) | | | +| `upgraded_client_state` | [google.protobuf.Any](#google.protobuf.Any) | | An UpgradedClientState must be provided to perform an IBC breaking upgrade. This will make the chain commit to the correct upgraded (self) client state before the upgrade occurs, so that connecting chains can verify that the new upgraded client is valid by verifying a proof on the previous version of the chain. This will allow IBC connections to persist smoothly across planned chain upgrades | + + + + + @@ -2747,6 +2940,39 @@ Query/ConsensusStates RPC method + + + +### QueryUpgradedClientStateRequest +QueryUpgradedClientStateRequest is the request type for the Query/UpgradedClientState RPC +method + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `client_id` | [string](#string) | | client state unique identifier | +| `plan_height` | [int64](#int64) | | plan height of the current chain must be sent in request as this is the height under which upgraded client state is stored | + + + + + + + + +### QueryUpgradedClientStateResponse +QueryUpgradedClientStateResponse is the response type for the Query/UpgradedClientState RPC +method. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `upgraded_client_state` | [google.protobuf.Any](#google.protobuf.Any) | | client state associated with the request identifier | + + + + + @@ -2766,6 +2992,7 @@ Query provides defines the gRPC querier service | `ConsensusState` | [QueryConsensusStateRequest](#ibc.core.client.v1.QueryConsensusStateRequest) | [QueryConsensusStateResponse](#ibc.core.client.v1.QueryConsensusStateResponse) | ConsensusState queries a consensus state associated with a client state at a given height. | GET|/ibc/core/client/v1/consensus_states/{client_id}/revision/{revision_number}/height/{revision_height}| | `ConsensusStates` | [QueryConsensusStatesRequest](#ibc.core.client.v1.QueryConsensusStatesRequest) | [QueryConsensusStatesResponse](#ibc.core.client.v1.QueryConsensusStatesResponse) | ConsensusStates queries all the consensus state associated with a given client. | GET|/ibc/core/client/v1/consensus_states/{client_id}| | `ClientParams` | [QueryClientParamsRequest](#ibc.core.client.v1.QueryClientParamsRequest) | [QueryClientParamsResponse](#ibc.core.client.v1.QueryClientParamsResponse) | ClientParams queries all parameters of the ibc client. | GET|/ibc/client/v1/params| +| `UpgradedClientState` | [QueryUpgradedClientStateRequest](#ibc.core.client.v1.QueryUpgradedClientStateRequest) | [QueryUpgradedClientStateResponse](#ibc.core.client.v1.QueryUpgradedClientStateResponse) | UpgradedClientState queries an Upgraded IBC light client. | GET|/ibc/core/client/v1/upgraded_client_states/{client_id}| @@ -4051,7 +4278,8 @@ data sign byte encodings. ### PrivKey -PrivKey defines a ed25519 private key. +Deprecated: PrivKey defines a ed25519 private key. +NOTE: ed25519 keys must not be used in SDK apps except in a tendermint validator context. | Field | Type | Label | Description | @@ -4066,11 +4294,11 @@ PrivKey defines a ed25519 private key. ### PubKey -PubKey defines a ed25519 public key -Key is the compressed form of the pubkey. The first byte depends is a 0x02 byte -if the y-coordinate is the lexicographically largest of the two associated with -the x-coordinate. Otherwise the first byte is a 0x03. -This prefix is followed with the x-coordinate. +PubKey is an ed25519 public key for handling Tendermint keys in SDK. +It's needed for Any serialization and SDK compatibility. +It must not be used in a non Tendermint key context because it doesn't implement +ADR-28. Nevertheless, you will like to use ed25519 in app user level +then you must create a new proto message and follow ADR-28 for Address construction. | Field | Type | Label | Description | @@ -4165,6 +4393,52 @@ This prefix is followed with the x-coordinate. + + + + + + + + + + + +

Top

+ +## lbm/crypto/secp256r1/keys.proto +Since: cosmos-sdk 0.43 + + + + +### PrivKey +PrivKey defines a secp256r1 ECDSA private key. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `secret` | [bytes](#bytes) | | secret number serialized using big-endian encoding | + + + + + + + + +### PubKey +PubKey defines a secp256r1 ECDSA public key. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `key` | [bytes](#bytes) | | Point on secp256r1 curve in a compressed representation as specified in section 4.3.6 of ANSI X9.62: https://webstore.ansi.org/standards/ascx9/ansix9621998 | + + + + + @@ -4195,6 +4469,7 @@ type for additional functionality (e.g. vesting). | `address` | [string](#string) | | | | `ed25519_pub_key` | [lbm.crypto.ed25519.PubKey](#lbm.crypto.ed25519.PubKey) | | | | `secp256k1_pub_key` | [lbm.crypto.secp256k1.PubKey](#lbm.crypto.secp256k1.PubKey) | | | +| `secp256r1_pub_key` | [lbm.crypto.secp256r1.PubKey](#lbm.crypto.secp256r1.PubKey) | | | | `multisig_pub_key` | [lbm.crypto.multisig.LegacyAminoPubKey](#lbm.crypto.multisig.LegacyAminoPubKey) | | | | `account_number` | [uint64](#uint64) | | | | `sequence` | [uint64](#uint64) | | | @@ -4318,6 +4593,41 @@ QueryAccountResponse is the response type for the Query/Account RPC method. + + +### QueryAccountsRequest +QueryAccountsRequest is the request type for the Query/Accounts RPC method. + +Since: cosmos-sdk 0.43 + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `pagination` | [lbm.base.query.v1.PageRequest](#lbm.base.query.v1.PageRequest) | | pagination defines an optional pagination for the request. | + + + + + + + + +### QueryAccountsResponse +QueryAccountsResponse is the response type for the Query/Accounts RPC method. + +Since: cosmos-sdk 0.43 + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `accounts` | [google.protobuf.Any](#google.protobuf.Any) | repeated | accounts are the existing accounts | +| `pagination` | [lbm.base.query.v1.PageResponse](#lbm.base.query.v1.PageResponse) | | pagination defines the pagination in the response. | + + + + + + ### QueryParamsRequest @@ -4356,6 +4666,9 @@ Query defines the gRPC querier service. | Method Name | Request Type | Response Type | Description | HTTP Verb | Endpoint | | ----------- | ------------ | ------------- | ------------| ------- | -------- | +| `Accounts` | [QueryAccountsRequest](#lbm.auth.v1.QueryAccountsRequest) | [QueryAccountsResponse](#lbm.auth.v1.QueryAccountsResponse) | Accounts returns all the existing accounts + +Since: cosmos-sdk 0.43 | GET|/lbm/auth/v1/accounts| | `Account` | [QueryAccountRequest](#lbm.auth.v1.QueryAccountRequest) | [QueryAccountResponse](#lbm.auth.v1.QueryAccountResponse) | Account returns account details based on address. | GET|/lbm/auth/v1/accounts/{address}| | `Params` | [QueryParamsRequest](#lbm.auth.v1.QueryParamsRequest) | [QueryParamsResponse](#lbm.auth.v1.QueryParamsResponse) | Params queries all parameters. | GET|/lbm/auth/v1/params| @@ -4414,775 +4727,1551 @@ Msg defines the auth Msg service. - +

Top

-## lbm/bank/v1/bank.proto - +## lbm/authz/v1/authz.proto +Since: cosmos-sdk 0.43 - + -### DenomUnit -DenomUnit represents a struct that describes a given -denomination unit of the basic token. +### GenericAuthorization +GenericAuthorization gives the grantee unrestricted permissions to execute +the provided method on behalf of the granter's account. | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| `denom` | [string](#string) | | denom represents the string name of the given denom unit (e.g uatom). | -| `exponent` | [uint32](#uint32) | | exponent represents power of 10 exponent that one must raise the base_denom to in order to equal the given DenomUnit's denom 1 denom = 1^exponent base_denom (e.g. with a base_denom of uatom, one can create a DenomUnit of 'atom' with exponent = 6, thus: 1 atom = 10^6 uatom). | -| `aliases` | [string](#string) | repeated | aliases is a list of string aliases for the given denom | +| `msg` | [string](#string) | | Msg, identified by it's type URL, to grant unrestricted permissions to execute | - + -### Input -Input models transaction input. +### Grant +Grant gives permissions to execute +the provide method with expiration time. | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| `address` | [string](#string) | | | -| `coins` | [lbm.base.v1.Coin](#lbm.base.v1.Coin) | repeated | | +| `authorization` | [google.protobuf.Any](#google.protobuf.Any) | | | +| `expiration` | [google.protobuf.Timestamp](#google.protobuf.Timestamp) | | | + - - -### Metadata -Metadata represents a struct that describes -a basic token. + + -| Field | Type | Label | Description | -| ----- | ---- | ----- | ----------- | -| `description` | [string](#string) | | | -| `denom_units` | [DenomUnit](#lbm.bank.v1.DenomUnit) | repeated | denom_units represents the list of DenomUnit's for a given coin | -| `base` | [string](#string) | | base represents the base denom (should be the DenomUnit with exponent = 0). | -| `display` | [string](#string) | | display indicates the suggested denom that should be displayed in clients. | + + +

Top

+## lbm/authz/v1/event.proto +Since: cosmos-sdk 0.43 - + -### Output -Output models transaction outputs. +### EventGrant +EventGrant is emitted on Msg/Grant | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| `address` | [string](#string) | | | -| `coins` | [lbm.base.v1.Coin](#lbm.base.v1.Coin) | repeated | | +| `msg_type_url` | [string](#string) | | Msg type URL for which an autorization is granted | +| `granter` | [string](#string) | | Granter account address | +| `grantee` | [string](#string) | | Grantee account address | - + -### Params -Params defines the parameters for the bank module. +### EventRevoke +EventRevoke is emitted on Msg/Revoke | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| `send_enabled` | [SendEnabled](#lbm.bank.v1.SendEnabled) | repeated | | -| `default_send_enabled` | [bool](#bool) | | | +| `msg_type_url` | [string](#string) | | Msg type URL for which an autorization is revoked | +| `granter` | [string](#string) | | Granter account address | +| `grantee` | [string](#string) | | Grantee account address | + - + -### SendEnabled -SendEnabled maps coin denom to a send_enabled status (whether a denom is -sendable). + + -| Field | Type | Label | Description | -| ----- | ---- | ----- | ----------- | -| `denom` | [string](#string) | | | -| `enabled` | [bool](#bool) | | | + +

Top

+## lbm/base/abci/v1/abci.proto - + -### Supply -Supply represents a struct that passively keeps track of the total supply -amounts in the network. +### ABCIMessageLog +ABCIMessageLog defines a structure containing an indexed tx ABCI message log. | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| `total` | [lbm.base.v1.Coin](#lbm.base.v1.Coin) | repeated | | +| `msg_index` | [uint32](#uint32) | | | +| `log` | [string](#string) | | | +| `events` | [StringEvent](#lbm.base.abci.v1.StringEvent) | repeated | Events contains a slice of Event objects that were emitted during some execution. | - - + - +### Attribute +Attribute defines an attribute wrapper where the key and value are +strings instead of raw bytes. - +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `key` | [string](#string) | | | +| `value` | [string](#string) | | | - -

Top

-## lbm/bank/v1/genesis.proto - + -### Balance -Balance defines an account address and balance pair used in the bank module's -genesis state. +### GasInfo +GasInfo defines tx execution gas context. | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| `address` | [string](#string) | | address is the address of the balance holder. | -| `coins` | [lbm.base.v1.Coin](#lbm.base.v1.Coin) | repeated | coins defines the different coins this balance holds. | +| `gas_wanted` | [uint64](#uint64) | | GasWanted is the maximum units of work we allow this tx to perform. | +| `gas_used` | [uint64](#uint64) | | GasUsed is the amount of gas actually consumed. | - + -### GenesisState -GenesisState defines the bank module's genesis state. +### MsgData +MsgData defines the data returned in a Result object during message +execution. | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| `params` | [Params](#lbm.bank.v1.Params) | | params defines all the paramaters of the module. | -| `balances` | [Balance](#lbm.bank.v1.Balance) | repeated | balances is an array containing the balances of all the accounts. | -| `supply` | [lbm.base.v1.Coin](#lbm.base.v1.Coin) | repeated | supply represents the total supply. | -| `denom_metadata` | [Metadata](#lbm.bank.v1.Metadata) | repeated | denom_metadata defines the metadata of the differents coins. | +| `msg_type` | [string](#string) | | | +| `data` | [bytes](#bytes) | | | - - + - +### Result +Result is the union of ResponseFormat and ResponseCheckTx. - +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `data` | [bytes](#bytes) | | Data is any data returned from message or handler execution. It MUST be length prefixed in order to separate data from multiple message executions. | +| `log` | [string](#string) | | Log contains the log information from message or handler execution. | +| `events` | [ostracon.abci.Event](#ostracon.abci.Event) | repeated | Events contains a slice of Event objects that were emitted during message or handler execution. | - -

Top

-## lbm/bank/v1/query.proto - + -### QueryAllBalancesRequest -QueryBalanceRequest is the request type for the Query/AllBalances RPC method. +### SearchTxsResult +SearchTxsResult defines a structure for querying txs pageable | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| `address` | [string](#string) | | address is the address to query balances for. | -| `pagination` | [lbm.base.query.v1.PageRequest](#lbm.base.query.v1.PageRequest) | | pagination defines an optional pagination for the request. | +| `total_count` | [uint64](#uint64) | | Count of all txs | +| `count` | [uint64](#uint64) | | Count of txs in current page | +| `page_number` | [uint64](#uint64) | | Index of current page, start from 1 | +| `page_total` | [uint64](#uint64) | | Count of total pages | +| `limit` | [uint64](#uint64) | | Max count txs per page | +| `txs` | [TxResponse](#lbm.base.abci.v1.TxResponse) | repeated | List of txs in current page | - + -### QueryAllBalancesResponse -QueryAllBalancesResponse is the response type for the Query/AllBalances RPC -method. +### SimulationResponse +SimulationResponse defines the response generated when a transaction is +successfully simulated. | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| `balances` | [lbm.base.v1.Coin](#lbm.base.v1.Coin) | repeated | balances is the balances of all the coins. | -| `pagination` | [lbm.base.query.v1.PageResponse](#lbm.base.query.v1.PageResponse) | | pagination defines the pagination in the response. | +| `gas_info` | [GasInfo](#lbm.base.abci.v1.GasInfo) | | | +| `result` | [Result](#lbm.base.abci.v1.Result) | | | - + -### QueryBalanceRequest -QueryBalanceRequest is the request type for the Query/Balance RPC method. +### StringEvent +StringEvent defines en Event object wrapper where all the attributes +contain key/value pairs that are strings instead of raw bytes. | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| `address` | [string](#string) | | address is the address to query balances for. | -| `denom` | [string](#string) | | denom is the coin denom to query balances for. | +| `type` | [string](#string) | | | +| `attributes` | [Attribute](#lbm.base.abci.v1.Attribute) | repeated | | - + -### QueryBalanceResponse -QueryBalanceResponse is the response type for the Query/Balance RPC method. +### TxMsgData +TxMsgData defines a list of MsgData. A transaction will have a MsgData object +for each message. | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| `balance` | [lbm.base.v1.Coin](#lbm.base.v1.Coin) | | balance is the balance of the coin. | +| `data` | [MsgData](#lbm.base.abci.v1.MsgData) | repeated | | - + -### QueryDenomMetadataRequest -QueryDenomMetadataRequest is the request type for the Query/DenomMetadata RPC method. +### TxResponse +TxResponse defines a structure containing relevant tx data and metadata. The +tags are stringified and the log is JSON decoded. | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| `denom` | [string](#string) | | denom is the coin denom to query the metadata for. | +| `height` | [int64](#int64) | | The block height | +| `txhash` | [string](#string) | | The transaction hash. | +| `codespace` | [string](#string) | | Namespace for the Code | +| `code` | [uint32](#uint32) | | Response code. | +| `data` | [string](#string) | | Result bytes, if any. | +| `raw_log` | [string](#string) | | The output of the application's logger (raw string). May be non-deterministic. | +| `logs` | [ABCIMessageLog](#lbm.base.abci.v1.ABCIMessageLog) | repeated | The output of the application's logger (typed). May be non-deterministic. | +| `info` | [string](#string) | | Additional information. May be non-deterministic. | +| `gas_wanted` | [int64](#int64) | | Amount of gas requested for transaction. | +| `gas_used` | [int64](#int64) | | Amount of gas consumed by transaction. | +| `tx` | [google.protobuf.Any](#google.protobuf.Any) | | The request transaction bytes. | +| `timestamp` | [string](#string) | | Time of the previous block. For heights > 1, it's the weighted median of the timestamps of the valid votes in the block.LastCommit. For height == 1, it's genesis time. | +| `events` | [ostracon.abci.Event](#ostracon.abci.Event) | repeated | Events defines all the events emitted by processing a transaction. Note, these events include those emitted by processing all the messages and those emitted from the ante handler. Whereas Logs contains the events, with additional metadata, emitted only by processing the messages. +Since: cosmos-sdk 0.42.11, 0.44.5, 0.45 | - + -### QueryDenomMetadataResponse -QueryDenomMetadataResponse is the response type for the Query/DenomMetadata RPC -method. + + -| Field | Type | Label | Description | -| ----- | ---- | ----- | ----------- | -| `metadata` | [Metadata](#lbm.bank.v1.Metadata) | | metadata describes and provides all the client information for the requested token. | + + +

Top

+## lbm/authz/v1/tx.proto +Since: cosmos-sdk 0.43 - + -### QueryDenomsMetadataRequest -QueryDenomsMetadataRequest is the request type for the Query/DenomsMetadata RPC method. +### MsgExec +MsgExec attempts to execute the provided messages using +authorizations granted to the grantee. Each message should have only +one signer corresponding to the granter of the authorization. | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| `pagination` | [lbm.base.query.v1.PageRequest](#lbm.base.query.v1.PageRequest) | | pagination defines an optional pagination for the request. | +| `grantee` | [string](#string) | | | +| `msgs` | [google.protobuf.Any](#google.protobuf.Any) | repeated | Authorization Msg requests to execute. Each msg must implement Authorization interface The x/authz will try to find a grant matching (msg.signers[0], grantee, MsgTypeURL(msg)) triple and validate it. | - + -### QueryDenomsMetadataResponse -QueryDenomsMetadataResponse is the response type for the Query/DenomsMetadata RPC -method. +### MsgExecResponse +MsgExecResponse defines the Msg/MsgExecResponse response type. | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| `metadatas` | [Metadata](#lbm.bank.v1.Metadata) | repeated | metadata provides the client information for all the registered tokens. | -| `pagination` | [lbm.base.query.v1.PageResponse](#lbm.base.query.v1.PageResponse) | | pagination defines the pagination in the response. | +| `results` | [bytes](#bytes) | repeated | | - + -### QueryParamsRequest -QueryParamsRequest defines the request type for querying x/bank parameters. +### MsgGrant +MsgGrant is a request type for Grant method. It declares authorization to the grantee +on behalf of the granter with the provided expiration time. +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `granter` | [string](#string) | | | +| `grantee` | [string](#string) | | | +| `grant` | [Grant](#lbm.authz.v1.Grant) | | | - -### QueryParamsResponse -QueryParamsResponse defines the response type for querying x/bank parameters. + -| Field | Type | Label | Description | -| ----- | ---- | ----- | ----------- | -| `params` | [Params](#lbm.bank.v1.Params) | | | +### MsgGrantResponse +MsgGrantResponse defines the Msg/MsgGrant response type. - + -### QuerySupplyOfRequest -QuerySupplyOfRequest is the request type for the Query/SupplyOf RPC method. +### MsgRevoke +MsgRevoke revokes any authorization with the provided sdk.Msg type on the +granter's account with that has been granted to the grantee. | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| `denom` | [string](#string) | | denom is the coin denom to query balances for. | +| `granter` | [string](#string) | | | +| `grantee` | [string](#string) | | | +| `msg_type_url` | [string](#string) | | | - + + +### MsgRevokeResponse +MsgRevokeResponse defines the Msg/MsgRevokeResponse response type. -### QuerySupplyOfResponse -QuerySupplyOfResponse is the response type for the Query/SupplyOf RPC method. -| Field | Type | Label | Description | -| ----- | ---- | ----- | ----------- | -| `amount` | [lbm.base.v1.Coin](#lbm.base.v1.Coin) | | amount is the supply of the coin. | + + + - + -### QueryTotalSupplyRequest -QueryTotalSupplyRequest is the request type for the Query/TotalSupply RPC -method. +### Msg +Msg defines the authz Msg service. +| Method Name | Request Type | Response Type | Description | HTTP Verb | Endpoint | +| ----------- | ------------ | ------------- | ------------| ------- | -------- | +| `Grant` | [MsgGrant](#lbm.authz.v1.MsgGrant) | [MsgGrantResponse](#lbm.authz.v1.MsgGrantResponse) | Grant grants the provided authorization to the grantee on the granter's account with the provided expiration time. If there is already a grant for the given (granter, grantee, Authorization) triple, then the grant will be overwritten. | | +| `Exec` | [MsgExec](#lbm.authz.v1.MsgExec) | [MsgExecResponse](#lbm.authz.v1.MsgExecResponse) | Exec attempts to execute the provided messages using authorizations granted to the grantee. Each message should have only one signer corresponding to the granter of the authorization. | | +| `Revoke` | [MsgRevoke](#lbm.authz.v1.MsgRevoke) | [MsgRevokeResponse](#lbm.authz.v1.MsgRevokeResponse) | Revoke revokes any authorization corresponding to the provided method name on the granter's account that has been granted to the grantee. | | + + +

Top

- +## lbm/authz/v1/genesis.proto +Since: cosmos-sdk 0.43 -### QueryTotalSupplyResponse -QueryTotalSupplyResponse is the response type for the Query/TotalSupply RPC -method + + + +### GenesisState +GenesisState defines the authz module's genesis state. | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| `supply` | [lbm.base.v1.Coin](#lbm.base.v1.Coin) | repeated | supply is the supply of the coins | +| `authorization` | [GrantAuthorization](#lbm.authz.v1.GrantAuthorization) | repeated | | - - + - +### GrantAuthorization +GrantAuthorization defines the GenesisState/GrantAuthorization type. - +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `granter` | [string](#string) | | | +| `grantee` | [string](#string) | | | +| `authorization` | [google.protobuf.Any](#google.protobuf.Any) | | | +| `expiration` | [google.protobuf.Timestamp](#google.protobuf.Timestamp) | | | + + + + + + + + + + + + + + + + +

Top

+ +## lbm/authz/v1/query.proto +Since: cosmos-sdk 0.43 + + + + +### QueryGrantsRequest +QueryGrantsRequest is the request type for the Query/Grants RPC method. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `granter` | [string](#string) | | | +| `grantee` | [string](#string) | | | +| `msg_type_url` | [string](#string) | | Optional, msg_type_url, when set, will query only grants matching given msg type. | +| `pagination` | [lbm.base.query.v1.PageRequest](#lbm.base.query.v1.PageRequest) | | pagination defines an pagination for the request. | + + + + + + + + +### QueryGrantsResponse +QueryGrantsResponse is the response type for the Query/Authorizations RPC method. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `grants` | [Grant](#lbm.authz.v1.Grant) | repeated | authorizations is a list of grants granted for grantee by granter. | +| `pagination` | [lbm.base.query.v1.PageResponse](#lbm.base.query.v1.PageResponse) | | pagination defines an pagination for the response. | + + + + + + + + + + + + + ### Query Query defines the gRPC querier service. | Method Name | Request Type | Response Type | Description | HTTP Verb | Endpoint | | ----------- | ------------ | ------------- | ------------| ------- | -------- | -| `Balance` | [QueryBalanceRequest](#lbm.bank.v1.QueryBalanceRequest) | [QueryBalanceResponse](#lbm.bank.v1.QueryBalanceResponse) | Balance queries the balance of a single coin for a single account. | GET|/lbm/bank/v1/balances/{address}/by_denom| -| `AllBalances` | [QueryAllBalancesRequest](#lbm.bank.v1.QueryAllBalancesRequest) | [QueryAllBalancesResponse](#lbm.bank.v1.QueryAllBalancesResponse) | AllBalances queries the balance of all coins for a single account. | GET|/lbm/bank/v1/balances/{address}| -| `TotalSupply` | [QueryTotalSupplyRequest](#lbm.bank.v1.QueryTotalSupplyRequest) | [QueryTotalSupplyResponse](#lbm.bank.v1.QueryTotalSupplyResponse) | TotalSupply queries the total supply of all coins. | GET|/lbm/bank/v1/supply| -| `SupplyOf` | [QuerySupplyOfRequest](#lbm.bank.v1.QuerySupplyOfRequest) | [QuerySupplyOfResponse](#lbm.bank.v1.QuerySupplyOfResponse) | SupplyOf queries the supply of a single coin. | GET|/lbm/bank/v1/supply/{denom}| -| `Params` | [QueryParamsRequest](#lbm.bank.v1.QueryParamsRequest) | [QueryParamsResponse](#lbm.bank.v1.QueryParamsResponse) | Params queries the parameters of x/bank module. | GET|/lbm/bank/v1/params| -| `DenomMetadata` | [QueryDenomMetadataRequest](#lbm.bank.v1.QueryDenomMetadataRequest) | [QueryDenomMetadataResponse](#lbm.bank.v1.QueryDenomMetadataResponse) | DenomsMetadata queries the client metadata of a given coin denomination. | GET|/lbm/bank/v1/denoms_metadata/{denom}| -| `DenomsMetadata` | [QueryDenomsMetadataRequest](#lbm.bank.v1.QueryDenomsMetadataRequest) | [QueryDenomsMetadataResponse](#lbm.bank.v1.QueryDenomsMetadataResponse) | DenomsMetadata queries the client metadata for all registered coin denominations. | GET|/lbm/bank/v1/denoms_metadata| +| `Grants` | [QueryGrantsRequest](#lbm.authz.v1.QueryGrantsRequest) | [QueryGrantsResponse](#lbm.authz.v1.QueryGrantsResponse) | Returns list of `Authorization`, granted to the grantee by the granter. | GET|/lbm/authz/v1/grants| - +

Top

-## lbm/bank/v1/tx.proto +## lbm/bank/v1/authz.proto - + -### MsgMultiSend -MsgMultiSend represents an arbitrary multi-in, multi-out send message. +### SendAuthorization +SendAuthorization allows the grantee to spend up to spend_limit coins from +the granter's account. + +Since: cosmos-sdk 0.43 | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| `inputs` | [Input](#lbm.bank.v1.Input) | repeated | | -| `outputs` | [Output](#lbm.bank.v1.Output) | repeated | | +| `spend_limit` | [lbm.base.v1.Coin](#lbm.base.v1.Coin) | repeated | | + - + -### MsgMultiSendResponse -MsgMultiSendResponse defines the Msg/MultiSend response type. + + + + +

Top

+## lbm/bank/v1/bank.proto - -### MsgSend -MsgSend represents a message to send coins from one account to another. + + +### DenomUnit +DenomUnit represents a struct that describes a given +denomination unit of the basic token. | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| `from_address` | [string](#string) | | | -| `to_address` | [string](#string) | | | -| `amount` | [lbm.base.v1.Coin](#lbm.base.v1.Coin) | repeated | | +| `denom` | [string](#string) | | denom represents the string name of the given denom unit (e.g uatom). | +| `exponent` | [uint32](#uint32) | | exponent represents power of 10 exponent that one must raise the base_denom to in order to equal the given DenomUnit's denom 1 denom = 1^exponent base_denom (e.g. with a base_denom of uatom, one can create a DenomUnit of 'atom' with exponent = 6, thus: 1 atom = 10^6 uatom). | +| `aliases` | [string](#string) | repeated | aliases is a list of string aliases for the given denom | - + -### MsgSendResponse -MsgSendResponse defines the Msg/Send response type. +### Input +Input models transaction input. +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `address` | [string](#string) | | | +| `coins` | [lbm.base.v1.Coin](#lbm.base.v1.Coin) | repeated | | - - - + - +### Metadata +Metadata represents a struct that describes +a basic token. -### Msg -Msg defines the bank Msg service. -| Method Name | Request Type | Response Type | Description | HTTP Verb | Endpoint | -| ----------- | ------------ | ------------- | ------------| ------- | -------- | -| `Send` | [MsgSend](#lbm.bank.v1.MsgSend) | [MsgSendResponse](#lbm.bank.v1.MsgSendResponse) | Send defines a method for sending coins from one account to another account. | | -| `MultiSend` | [MsgMultiSend](#lbm.bank.v1.MsgMultiSend) | [MsgMultiSendResponse](#lbm.bank.v1.MsgMultiSendResponse) | MultiSend defines a method for sending coins from some accounts to other accounts. | | +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `description` | [string](#string) | | | +| `denom_units` | [DenomUnit](#lbm.bank.v1.DenomUnit) | repeated | denom_units represents the list of DenomUnit's for a given coin | +| `base` | [string](#string) | | base represents the base denom (should be the DenomUnit with exponent = 0). | +| `display` | [string](#string) | | display indicates the suggested denom that should be displayed in clients. | +| `name` | [string](#string) | | name defines the name of the token (eg: Cosmos Atom) - +Since: cosmos-sdk 0.43 | +| `symbol` | [string](#string) | | symbol is the token symbol usually shown on exchanges (eg: ATOM). This can be the same as the display. +Since: cosmos-sdk 0.43 | - -

Top

-## lbm/bankplus/v1/bankplus.proto - + -### InactiveAddr -InactiveAddr models the blocked address for the bankplus module +### Output +Output models transaction outputs. | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | | `address` | [string](#string) | | | +| `coins` | [lbm.base.v1.Coin](#lbm.base.v1.Coin) | repeated | | - - + - +### Params +Params defines the parameters for the bank module. - +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `send_enabled` | [SendEnabled](#lbm.bank.v1.SendEnabled) | repeated | | +| `default_send_enabled` | [bool](#bool) | | | - -

Top

-## lbm/base/abci/v1/abci.proto - + -### ABCIMessageLog -ABCIMessageLog defines a structure containing an indexed tx ABCI message log. +### SendEnabled +SendEnabled maps coin denom to a send_enabled status (whether a denom is +sendable). | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| `msg_index` | [uint32](#uint32) | | | -| `log` | [string](#string) | | | -| `events` | [StringEvent](#lbm.base.abci.v1.StringEvent) | repeated | Events contains a slice of Event objects that were emitted during some execution. | +| `denom` | [string](#string) | | | +| `enabled` | [bool](#bool) | | | - + -### Attribute -Attribute defines an attribute wrapper where the key and value are -strings instead of raw bytes. +### Supply +Supply represents a struct that passively keeps track of the total supply +amounts in the network. +This message is deprecated now that supply is indexed by denom. | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| `key` | [string](#string) | | | -| `value` | [string](#string) | | | +| `total` | [lbm.base.v1.Coin](#lbm.base.v1.Coin) | repeated | | + + + + + + + + + + + +

Top

+ +## lbm/bank/v1/genesis.proto - -### GasInfo -GasInfo defines tx execution gas context. + + + +### Balance +Balance defines an account address and balance pair used in the bank module's +genesis state. | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| `gas_wanted` | [uint64](#uint64) | | GasWanted is the maximum units of work we allow this tx to perform. | -| `gas_used` | [uint64](#uint64) | | GasUsed is the amount of gas actually consumed. | +| `address` | [string](#string) | | address is the address of the balance holder. | +| `coins` | [lbm.base.v1.Coin](#lbm.base.v1.Coin) | repeated | coins defines the different coins this balance holds. | - + -### MsgData -MsgData defines the data returned in a Result object during message -execution. +### GenesisState +GenesisState defines the bank module's genesis state. | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| `msg_type` | [string](#string) | | | -| `data` | [bytes](#bytes) | | | +| `params` | [Params](#lbm.bank.v1.Params) | | params defines all the paramaters of the module. | +| `balances` | [Balance](#lbm.bank.v1.Balance) | repeated | balances is an array containing the balances of all the accounts. | +| `supply` | [lbm.base.v1.Coin](#lbm.base.v1.Coin) | repeated | supply represents the total supply. If it is left empty, then supply will be calculated based on the provided balances. Otherwise, it will be used to validate that the sum of the balances equals this amount. | +| `denom_metadata` | [Metadata](#lbm.bank.v1.Metadata) | repeated | denom_metadata defines the metadata of the differents coins. | + + + + + + + - -### Result -Result is the union of ResponseFormat and ResponseCheckTx. + + +

Top

+ +## lbm/bank/v1/query.proto + + + + + +### QueryAllBalancesRequest +QueryBalanceRequest is the request type for the Query/AllBalances RPC method. | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| `data` | [bytes](#bytes) | | Data is any data returned from message or handler execution. It MUST be length prefixed in order to separate data from multiple message executions. | -| `log` | [string](#string) | | Log contains the log information from message or handler execution. | -| `events` | [ostracon.abci.Event](#ostracon.abci.Event) | repeated | Events contains a slice of Event objects that were emitted during message or handler execution. | +| `address` | [string](#string) | | address is the address to query balances for. | +| `pagination` | [lbm.base.query.v1.PageRequest](#lbm.base.query.v1.PageRequest) | | pagination defines an optional pagination for the request. | - + -### SearchTxsResult -SearchTxsResult defines a structure for querying txs pageable +### QueryAllBalancesResponse +QueryAllBalancesResponse is the response type for the Query/AllBalances RPC +method. | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| `total_count` | [uint64](#uint64) | | Count of all txs | -| `count` | [uint64](#uint64) | | Count of txs in current page | -| `page_number` | [uint64](#uint64) | | Index of current page, start from 1 | -| `page_total` | [uint64](#uint64) | | Count of total pages | -| `limit` | [uint64](#uint64) | | Max count txs per page | -| `txs` | [TxResponse](#lbm.base.abci.v1.TxResponse) | repeated | List of txs in current page | +| `balances` | [lbm.base.v1.Coin](#lbm.base.v1.Coin) | repeated | balances is the balances of all the coins. | +| `pagination` | [lbm.base.query.v1.PageResponse](#lbm.base.query.v1.PageResponse) | | pagination defines the pagination in the response. | + + + + + + + + +### QueryBalanceRequest +QueryBalanceRequest is the request type for the Query/Balance RPC method. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `address` | [string](#string) | | address is the address to query balances for. | +| `denom` | [string](#string) | | denom is the coin denom to query balances for. | + + + + + + + + +### QueryBalanceResponse +QueryBalanceResponse is the response type for the Query/Balance RPC method. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `balance` | [lbm.base.v1.Coin](#lbm.base.v1.Coin) | | balance is the balance of the coin. | + + + + + + + + +### QueryDenomMetadataRequest +QueryDenomMetadataRequest is the request type for the Query/DenomMetadata RPC method. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `denom` | [string](#string) | | denom is the coin denom to query the metadata for. | + + + + + + + + +### QueryDenomMetadataResponse +QueryDenomMetadataResponse is the response type for the Query/DenomMetadata RPC +method. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `metadata` | [Metadata](#lbm.bank.v1.Metadata) | | metadata describes and provides all the client information for the requested token. | + + + + + + + + +### QueryDenomsMetadataRequest +QueryDenomsMetadataRequest is the request type for the Query/DenomsMetadata RPC method. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `pagination` | [lbm.base.query.v1.PageRequest](#lbm.base.query.v1.PageRequest) | | pagination defines an optional pagination for the request. | + + + + + + + + +### QueryDenomsMetadataResponse +QueryDenomsMetadataResponse is the response type for the Query/DenomsMetadata RPC +method. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `metadatas` | [Metadata](#lbm.bank.v1.Metadata) | repeated | metadata provides the client information for all the registered tokens. | +| `pagination` | [lbm.base.query.v1.PageResponse](#lbm.base.query.v1.PageResponse) | | pagination defines the pagination in the response. | + + + + + + + + +### QueryParamsRequest +QueryParamsRequest defines the request type for querying x/bank parameters. + + + + + + + + +### QueryParamsResponse +QueryParamsResponse defines the response type for querying x/bank parameters. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `params` | [Params](#lbm.bank.v1.Params) | | | + + + + + + + + +### QuerySupplyOfRequest +QuerySupplyOfRequest is the request type for the Query/SupplyOf RPC method. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `denom` | [string](#string) | | denom is the coin denom to query balances for. | + + + + + + + + +### QuerySupplyOfResponse +QuerySupplyOfResponse is the response type for the Query/SupplyOf RPC method. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `amount` | [lbm.base.v1.Coin](#lbm.base.v1.Coin) | | amount is the supply of the coin. | + + + + + + + + +### QueryTotalSupplyRequest +QueryTotalSupplyRequest is the request type for the Query/TotalSupply RPC +method. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `pagination` | [lbm.base.query.v1.PageRequest](#lbm.base.query.v1.PageRequest) | | pagination defines an optional pagination for the request. + +Since: cosmos-sdk 0.43 | + + + + + + + + +### QueryTotalSupplyResponse +QueryTotalSupplyResponse is the response type for the Query/TotalSupply RPC +method + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `supply` | [lbm.base.v1.Coin](#lbm.base.v1.Coin) | repeated | supply is the supply of the coins | +| `pagination` | [lbm.base.query.v1.PageResponse](#lbm.base.query.v1.PageResponse) | | pagination defines the pagination in the response. + +Since: cosmos-sdk 0.43 | + + + + + + + + + + + + + + +### Query +Query defines the gRPC querier service. + +| Method Name | Request Type | Response Type | Description | HTTP Verb | Endpoint | +| ----------- | ------------ | ------------- | ------------| ------- | -------- | +| `Balance` | [QueryBalanceRequest](#lbm.bank.v1.QueryBalanceRequest) | [QueryBalanceResponse](#lbm.bank.v1.QueryBalanceResponse) | Balance queries the balance of a single coin for a single account. | GET|/lbm/bank/v1/balances/{address}/by_denom| +| `AllBalances` | [QueryAllBalancesRequest](#lbm.bank.v1.QueryAllBalancesRequest) | [QueryAllBalancesResponse](#lbm.bank.v1.QueryAllBalancesResponse) | AllBalances queries the balance of all coins for a single account. | GET|/lbm/bank/v1/balances/{address}| +| `TotalSupply` | [QueryTotalSupplyRequest](#lbm.bank.v1.QueryTotalSupplyRequest) | [QueryTotalSupplyResponse](#lbm.bank.v1.QueryTotalSupplyResponse) | TotalSupply queries the total supply of all coins. | GET|/lbm/bank/v1/supply| +| `SupplyOf` | [QuerySupplyOfRequest](#lbm.bank.v1.QuerySupplyOfRequest) | [QuerySupplyOfResponse](#lbm.bank.v1.QuerySupplyOfResponse) | SupplyOf queries the supply of a single coin. | GET|/lbm/bank/v1/supply/{denom}| +| `Params` | [QueryParamsRequest](#lbm.bank.v1.QueryParamsRequest) | [QueryParamsResponse](#lbm.bank.v1.QueryParamsResponse) | Params queries the parameters of x/bank module. | GET|/lbm/bank/v1/params| +| `DenomMetadata` | [QueryDenomMetadataRequest](#lbm.bank.v1.QueryDenomMetadataRequest) | [QueryDenomMetadataResponse](#lbm.bank.v1.QueryDenomMetadataResponse) | DenomsMetadata queries the client metadata of a given coin denomination. | GET|/lbm/bank/v1/denoms_metadata/{denom}| +| `DenomsMetadata` | [QueryDenomsMetadataRequest](#lbm.bank.v1.QueryDenomsMetadataRequest) | [QueryDenomsMetadataResponse](#lbm.bank.v1.QueryDenomsMetadataResponse) | DenomsMetadata queries the client metadata for all registered coin denominations. | GET|/lbm/bank/v1/denoms_metadata| + + + + + + +

Top

+ +## lbm/bank/v1/tx.proto + + + + + +### MsgMultiSend +MsgMultiSend represents an arbitrary multi-in, multi-out send message. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `inputs` | [Input](#lbm.bank.v1.Input) | repeated | | +| `outputs` | [Output](#lbm.bank.v1.Output) | repeated | | + + + + + + + + +### MsgMultiSendResponse +MsgMultiSendResponse defines the Msg/MultiSend response type. + + + + + + + + +### MsgSend +MsgSend represents a message to send coins from one account to another. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `from_address` | [string](#string) | | | +| `to_address` | [string](#string) | | | +| `amount` | [lbm.base.v1.Coin](#lbm.base.v1.Coin) | repeated | | + + + + + + + + +### MsgSendResponse +MsgSendResponse defines the Msg/Send response type. + + + + + + + + + + + + + + +### Msg +Msg defines the bank Msg service. + +| Method Name | Request Type | Response Type | Description | HTTP Verb | Endpoint | +| ----------- | ------------ | ------------- | ------------| ------- | -------- | +| `Send` | [MsgSend](#lbm.bank.v1.MsgSend) | [MsgSendResponse](#lbm.bank.v1.MsgSendResponse) | Send defines a method for sending coins from one account to another account. | | +| `MultiSend` | [MsgMultiSend](#lbm.bank.v1.MsgMultiSend) | [MsgMultiSendResponse](#lbm.bank.v1.MsgMultiSendResponse) | MultiSend defines a method for sending coins from some accounts to other accounts. | | + + + + + + +

Top

+ +## lbm/bankplus/v1/bankplus.proto + + + + + +### InactiveAddr +InactiveAddr models the blocked address for the bankplus module + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `address` | [string](#string) | | | + + + + + + + + + + + + + + + + +

Top

+ +## lbm/base/kv/v1/kv.proto + + + + + +### Pair +Pair defines a key/value bytes tuple. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `key` | [bytes](#bytes) | | | +| `value` | [bytes](#bytes) | | | + + + + + + + + +### Pairs +Pairs defines a repeated slice of Pair objects. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `pairs` | [Pair](#lbm.base.kv.v1.Pair) | repeated | | + + + + + + + + + + + + + + + + +

Top

+ +## lbm/base/ostracon/v1/query.proto + + + + + +### GetBlockByHashRequest +GetBlockByHashRequest is the request type for the Query/GetBlockByHash RPC method. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `hash` | [bytes](#bytes) | | | + + + + + + + + +### GetBlockByHashResponse +GetBlockByHashResponse is the response type for the Query/GetBlockByHash RPC method. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `block_id` | [ostracon.types.BlockID](#ostracon.types.BlockID) | | | +| `block` | [ostracon.types.Block](#ostracon.types.Block) | | | + + + + + + + + +### GetBlockByHeightRequest +GetBlockByHeightRequest is the request type for the Query/GetBlockByHeight RPC method. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `height` | [int64](#int64) | | | + + + + + + + + +### GetBlockByHeightResponse +GetBlockByHeightResponse is the response type for the Query/GetBlockByHeight RPC method. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `block_id` | [ostracon.types.BlockID](#ostracon.types.BlockID) | | | +| `block` | [ostracon.types.Block](#ostracon.types.Block) | | | + + + + + + + + +### GetBlockResultsByHeightRequest +GetBlockResultsByHeightRequest is the request type for the Query/GetBlockResultsByHeight RPC method. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `height` | [int64](#int64) | | | + + + + + + + + +### GetBlockResultsByHeightResponse +GetBlockResultsByHeightResponse is the response type for the Query/GetBlockResultsByHeight RPC method. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `height` | [int64](#int64) | | | +| `txs_results` | [ostracon.abci.ResponseDeliverTx](#ostracon.abci.ResponseDeliverTx) | repeated | | +| `res_begin_block` | [ostracon.abci.ResponseBeginBlock](#ostracon.abci.ResponseBeginBlock) | | | +| `res_end_block` | [ostracon.abci.ResponseEndBlock](#ostracon.abci.ResponseEndBlock) | | | + + + + + + + + +### GetLatestBlockRequest +GetLatestBlockRequest is the request type for the Query/GetLatestBlock RPC method. + + + + + + + + +### GetLatestBlockResponse +GetLatestBlockResponse is the response type for the Query/GetLatestBlock RPC method. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `block_id` | [ostracon.types.BlockID](#ostracon.types.BlockID) | | | +| `block` | [ostracon.types.Block](#ostracon.types.Block) | | | + + + + + + + + +### GetLatestValidatorSetRequest +GetLatestValidatorSetRequest is the request type for the Query/GetValidatorSetByHeight RPC method. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `pagination` | [lbm.base.query.v1.PageRequest](#lbm.base.query.v1.PageRequest) | | pagination defines an pagination for the request. | + + + + + + + + +### GetLatestValidatorSetResponse +GetLatestValidatorSetResponse is the response type for the Query/GetValidatorSetByHeight RPC method. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `block_height` | [int64](#int64) | | | +| `validators` | [Validator](#lbm.base.ostracon.v1.Validator) | repeated | | +| `pagination` | [lbm.base.query.v1.PageResponse](#lbm.base.query.v1.PageResponse) | | pagination defines an pagination for the response. | + + + + + + + + +### GetNodeInfoRequest +GetNodeInfoRequest is the request type for the Query/GetNodeInfo RPC method. + + + + + + + + +### GetNodeInfoResponse +GetNodeInfoResponse is the request type for the Query/GetNodeInfo RPC method. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `default_node_info` | [ostracon.p2p.DefaultNodeInfo](#ostracon.p2p.DefaultNodeInfo) | | | +| `application_version` | [VersionInfo](#lbm.base.ostracon.v1.VersionInfo) | | | + + + + + + + + +### GetSyncingRequest +GetSyncingRequest is the request type for the Query/GetSyncing RPC method. + + + + + + + + +### GetSyncingResponse +GetSyncingResponse is the response type for the Query/GetSyncing RPC method. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `syncing` | [bool](#bool) | | | + + + + + + + + +### GetValidatorSetByHeightRequest +GetValidatorSetByHeightRequest is the request type for the Query/GetValidatorSetByHeight RPC method. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `height` | [int64](#int64) | | | +| `pagination` | [lbm.base.query.v1.PageRequest](#lbm.base.query.v1.PageRequest) | | pagination defines an pagination for the request. | + + + + + + + + +### GetValidatorSetByHeightResponse +GetValidatorSetByHeightResponse is the response type for the Query/GetValidatorSetByHeight RPC method. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `block_height` | [int64](#int64) | | | +| `validators` | [Validator](#lbm.base.ostracon.v1.Validator) | repeated | | +| `pagination` | [lbm.base.query.v1.PageResponse](#lbm.base.query.v1.PageResponse) | | pagination defines an pagination for the response. | + + + + + + + + +### Module +Module is the type for VersionInfo + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `path` | [string](#string) | | module path | +| `version` | [string](#string) | | module version | +| `sum` | [string](#string) | | checksum | - + -### SimulationResponse -SimulationResponse defines the response generated when a transaction is -successfully simulated. +### Validator +Validator is the type for the validator-set. | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| `gas_info` | [GasInfo](#lbm.base.abci.v1.GasInfo) | | | -| `result` | [Result](#lbm.base.abci.v1.Result) | | | +| `address` | [string](#string) | | | +| `pub_key` | [google.protobuf.Any](#google.protobuf.Any) | | | +| `voting_power` | [int64](#int64) | | | +| `proposer_priority` | [int64](#int64) | | | - + -### StringEvent -StringEvent defines en Event object wrapper where all the attributes -contain key/value pairs that are strings instead of raw bytes. +### VersionInfo +VersionInfo is the type for the GetNodeInfoResponse message. | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| `type` | [string](#string) | | | -| `attributes` | [Attribute](#lbm.base.abci.v1.Attribute) | repeated | | +| `name` | [string](#string) | | | +| `app_name` | [string](#string) | | | +| `version` | [string](#string) | | | +| `git_commit` | [string](#string) | | | +| `build_tags` | [string](#string) | | | +| `go_version` | [string](#string) | | | +| `build_deps` | [Module](#lbm.base.ostracon.v1.Module) | repeated | | +| `lbm_sdk_version` | [string](#string) | | Since: cosmos-sdk 0.43 | + - + -### TxMsgData -TxMsgData defines a list of MsgData. A transaction will have a MsgData object -for each message. + -| Field | Type | Label | Description | -| ----- | ---- | ----- | ----------- | -| `data` | [MsgData](#lbm.base.abci.v1.MsgData) | repeated | | + +### Service +Service defines the gRPC querier service for ostracon queries. +| Method Name | Request Type | Response Type | Description | HTTP Verb | Endpoint | +| ----------- | ------------ | ------------- | ------------| ------- | -------- | +| `GetNodeInfo` | [GetNodeInfoRequest](#lbm.base.ostracon.v1.GetNodeInfoRequest) | [GetNodeInfoResponse](#lbm.base.ostracon.v1.GetNodeInfoResponse) | GetNodeInfo queries the current node info. | GET|/lbm/base/ostracon/v1/node_info| +| `GetSyncing` | [GetSyncingRequest](#lbm.base.ostracon.v1.GetSyncingRequest) | [GetSyncingResponse](#lbm.base.ostracon.v1.GetSyncingResponse) | GetSyncing queries node syncing. | GET|/lbm/base/ostracon/v1/syncing| +| `GetLatestBlock` | [GetLatestBlockRequest](#lbm.base.ostracon.v1.GetLatestBlockRequest) | [GetLatestBlockResponse](#lbm.base.ostracon.v1.GetLatestBlockResponse) | GetLatestBlock returns the latest block. | GET|/lbm/base/ostracon/v1/blocks/latest| +| `GetBlockByHeight` | [GetBlockByHeightRequest](#lbm.base.ostracon.v1.GetBlockByHeightRequest) | [GetBlockByHeightResponse](#lbm.base.ostracon.v1.GetBlockByHeightResponse) | GetBlockByHeight queries block for given height. | GET|/lbm/base/ostracon/v1/blocks/{height}| +| `GetBlockByHash` | [GetBlockByHashRequest](#lbm.base.ostracon.v1.GetBlockByHashRequest) | [GetBlockByHashResponse](#lbm.base.ostracon.v1.GetBlockByHashResponse) | GetBlockByHash queries block for given hash. | GET|/lbm/base/ostracon/v1/blocks/{hash}| +| `GetBlockResultsByHeight` | [GetBlockResultsByHeightRequest](#lbm.base.ostracon.v1.GetBlockResultsByHeightRequest) | [GetBlockResultsByHeightResponse](#lbm.base.ostracon.v1.GetBlockResultsByHeightResponse) | GetBlockResultsByHeight queries block results for given height. | GET|/lbm/base/ostracon/v1/blockresults/{height}| +| `GetLatestValidatorSet` | [GetLatestValidatorSetRequest](#lbm.base.ostracon.v1.GetLatestValidatorSetRequest) | [GetLatestValidatorSetResponse](#lbm.base.ostracon.v1.GetLatestValidatorSetResponse) | GetLatestValidatorSet queries latest validator-set. | GET|/lbm/base/ostracon/v1/validatorsets/latest| +| `GetValidatorSetByHeight` | [GetValidatorSetByHeightRequest](#lbm.base.ostracon.v1.GetValidatorSetByHeightRequest) | [GetValidatorSetByHeightResponse](#lbm.base.ostracon.v1.GetValidatorSetByHeightResponse) | GetValidatorSetByHeight queries validator-set at a given height. | GET|/lbm/base/ostracon/v1/validatorsets/{height}| + - + +

Top

-### TxResponse -TxResponse defines a structure containing relevant tx data and metadata. The -tags are stringified and the log is JSON decoded. +## lbm/base/reflection/v1/reflection.proto -| Field | Type | Label | Description | -| ----- | ---- | ----- | ----------- | -| `height` | [int64](#int64) | | The block height | -| `txhash` | [string](#string) | | The transaction hash. | -| `codespace` | [string](#string) | | Namespace for the Code | -| `code` | [uint32](#uint32) | | Response code. | -| `data` | [string](#string) | | Result bytes, if any. | -| `raw_log` | [string](#string) | | The output of the application's logger (raw string). May be non-deterministic. | -| `logs` | [ABCIMessageLog](#lbm.base.abci.v1.ABCIMessageLog) | repeated | The output of the application's logger (typed). May be non-deterministic. | -| `info` | [string](#string) | | Additional information. May be non-deterministic. | -| `gas_wanted` | [int64](#int64) | | Amount of gas requested for transaction. | -| `gas_used` | [int64](#int64) | | Amount of gas consumed by transaction. | -| `tx` | [google.protobuf.Any](#google.protobuf.Any) | | The request transaction bytes. | -| `timestamp` | [string](#string) | | Time of the previous block. For heights > 1, it's the weighted median of the timestamps of the valid votes in the block.LastCommit. For height == 1, it's genesis time. | -| `events` | [ostracon.abci.Event](#ostracon.abci.Event) | repeated | Events defines all the events emitted by processing a transaction. Note, these events include those emitted by processing all the messages and those emitted from the ante handler. Whereas Logs contains the events, with additional metadata, emitted only by processing the messages. -Since: cosmos-sdk 0.42.11, 0.44.5, 0.45 | + +### ListAllInterfacesRequest +ListAllInterfacesRequest is the request type of the ListAllInterfaces RPC. - - - + - +### ListAllInterfacesResponse +ListAllInterfacesResponse is the response type of the ListAllInterfaces RPC. +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `interface_names` | [string](#string) | repeated | interface_names is an array of all the registered interfaces. | - -

Top

-## lbm/base/kv/v1/kv.proto - -### Pair -Pair defines a key/value bytes tuple. + + +### ListImplementationsRequest +ListImplementationsRequest is the request type of the ListImplementations +RPC. | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| `key` | [bytes](#bytes) | | | -| `value` | [bytes](#bytes) | | | +| `interface_name` | [string](#string) | | interface_name defines the interface to query the implementations for. | - + -### Pairs -Pairs defines a repeated slice of Pair objects. +### ListImplementationsResponse +ListImplementationsResponse is the response type of the ListImplementations +RPC. | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| `pairs` | [Pair](#lbm.base.kv.v1.Pair) | repeated | | +| `implementation_message_names` | [string](#string) | repeated | | @@ -5194,395 +6283,404 @@ Pairs defines a repeated slice of Pair objects. + + + +### ReflectionService +ReflectionService defines a service for interface reflection. + +| Method Name | Request Type | Response Type | Description | HTTP Verb | Endpoint | +| ----------- | ------------ | ------------- | ------------| ------- | -------- | +| `ListAllInterfaces` | [ListAllInterfacesRequest](#lbm.base.reflection.v1.ListAllInterfacesRequest) | [ListAllInterfacesResponse](#lbm.base.reflection.v1.ListAllInterfacesResponse) | ListAllInterfaces lists all the interfaces registered in the interface registry. | GET|/lbm/base/reflection/v1/interfaces| +| `ListImplementations` | [ListImplementationsRequest](#lbm.base.reflection.v1.ListImplementationsRequest) | [ListImplementationsResponse](#lbm.base.reflection.v1.ListImplementationsResponse) | ListImplementations list all the concrete types that implement a given interface. | GET|/lbm/base/reflection/v1/interfaces/{interface_name}/implementations| + - +

Top

-## lbm/base/ostracon/v1/query.proto - +## lbm/base/reflection/v2/reflection.proto +Since: cosmos-sdk 0.43 - + -### GetBlockByHashRequest -GetBlockByHashRequest is the request type for the Query/GetBlockByHash RPC method. +### AppDescriptor +AppDescriptor describes a cosmos-sdk based application | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| `hash` | [bytes](#bytes) | | | +| `authn` | [AuthnDescriptor](#lbm.base.reflection.v2.AuthnDescriptor) | | AuthnDescriptor provides information on how to authenticate transactions on the application NOTE: experimental and subject to change in future releases. | +| `chain` | [ChainDescriptor](#lbm.base.reflection.v2.ChainDescriptor) | | chain provides the chain descriptor | +| `codec` | [CodecDescriptor](#lbm.base.reflection.v2.CodecDescriptor) | | codec provides metadata information regarding codec related types | +| `configuration` | [ConfigurationDescriptor](#lbm.base.reflection.v2.ConfigurationDescriptor) | | configuration provides metadata information regarding the sdk.Config type | +| `query_services` | [QueryServicesDescriptor](#lbm.base.reflection.v2.QueryServicesDescriptor) | | query_services provides metadata information regarding the available queriable endpoints | +| `tx` | [TxDescriptor](#lbm.base.reflection.v2.TxDescriptor) | | tx provides metadata information regarding how to send transactions to the given application | - + -### GetBlockByHashResponse -GetBlockByHashResponse is the response type for the Query/GetBlockByHash RPC method. +### AuthnDescriptor +AuthnDescriptor provides information on how to sign transactions without relying +on the online RPCs GetTxMetadata and CombineUnsignedTxAndSignatures | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| `block_id` | [ostracon.types.BlockID](#ostracon.types.BlockID) | | | -| `block` | [ostracon.types.Block](#ostracon.types.Block) | | | +| `sign_modes` | [SigningModeDescriptor](#lbm.base.reflection.v2.SigningModeDescriptor) | repeated | sign_modes defines the supported signature algorithm | - + -### GetBlockByHeightRequest -GetBlockByHeightRequest is the request type for the Query/GetBlockByHeight RPC method. +### ChainDescriptor +ChainDescriptor describes chain information of the application | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| `height` | [int64](#int64) | | | +| `id` | [string](#string) | | id is the chain id | - + -### GetBlockByHeightResponse -GetBlockByHeightResponse is the response type for the Query/GetBlockByHeight RPC method. +### CodecDescriptor +CodecDescriptor describes the registered interfaces and provides metadata information on the types | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| `block_id` | [ostracon.types.BlockID](#ostracon.types.BlockID) | | | -| `block` | [ostracon.types.Block](#ostracon.types.Block) | | | +| `interfaces` | [InterfaceDescriptor](#lbm.base.reflection.v2.InterfaceDescriptor) | repeated | interfaces is a list of the registerted interfaces descriptors | - + -### GetBlockResultsByHeightRequest -GetBlockResultsByHeightRequest is the request type for the Query/GetBlockResultsByHeight RPC method. +### ConfigurationDescriptor +ConfigurationDescriptor contains metadata information on the sdk.Config | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| `height` | [int64](#int64) | | | +| `bech32_account_address_prefix` | [string](#string) | | bech32_account_address_prefix is the account address prefix | - + + +### GetAuthnDescriptorRequest +GetAuthnDescriptorRequest is the request used for the GetAuthnDescriptor RPC -### GetBlockResultsByHeightResponse -GetBlockResultsByHeightResponse is the response type for the Query/GetBlockResultsByHeight RPC method. + + + + + + + +### GetAuthnDescriptorResponse +GetAuthnDescriptorResponse is the response returned by the GetAuthnDescriptor RPC | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| `height` | [int64](#int64) | | | -| `txs_results` | [ostracon.abci.ResponseDeliverTx](#ostracon.abci.ResponseDeliverTx) | repeated | | -| `res_begin_block` | [ostracon.abci.ResponseBeginBlock](#ostracon.abci.ResponseBeginBlock) | | | -| `res_end_block` | [ostracon.abci.ResponseEndBlock](#ostracon.abci.ResponseEndBlock) | | | +| `authn` | [AuthnDescriptor](#lbm.base.reflection.v2.AuthnDescriptor) | | authn describes how to authenticate to the application when sending transactions | - + -### GetLatestBlockRequest -GetLatestBlockRequest is the request type for the Query/GetLatestBlock RPC method. +### GetChainDescriptorRequest +GetChainDescriptorRequest is the request used for the GetChainDescriptor RPC - + -### GetLatestBlockResponse -GetLatestBlockResponse is the response type for the Query/GetLatestBlock RPC method. +### GetChainDescriptorResponse +GetChainDescriptorResponse is the response returned by the GetChainDescriptor RPC | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| `block_id` | [ostracon.types.BlockID](#ostracon.types.BlockID) | | | -| `block` | [ostracon.types.Block](#ostracon.types.Block) | | | - - +| `chain` | [ChainDescriptor](#lbm.base.reflection.v2.ChainDescriptor) | | chain describes application chain information | - -### GetLatestValidatorSetRequest -GetLatestValidatorSetRequest is the request type for the Query/GetValidatorSetByHeight RPC method. + -| Field | Type | Label | Description | -| ----- | ---- | ----- | ----------- | -| `pagination` | [lbm.base.query.v1.PageRequest](#lbm.base.query.v1.PageRequest) | | pagination defines an pagination for the request. | +### GetCodecDescriptorRequest +GetCodecDescriptorRequest is the request used for the GetCodecDescriptor RPC - + -### GetLatestValidatorSetResponse -GetLatestValidatorSetResponse is the response type for the Query/GetValidatorSetByHeight RPC method. +### GetCodecDescriptorResponse +GetCodecDescriptorResponse is the response returned by the GetCodecDescriptor RPC | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| `block_height` | [int64](#int64) | | | -| `validators` | [Validator](#lbm.base.ostracon.v1.Validator) | repeated | | -| `pagination` | [lbm.base.query.v1.PageResponse](#lbm.base.query.v1.PageResponse) | | pagination defines an pagination for the response. | +| `codec` | [CodecDescriptor](#lbm.base.reflection.v2.CodecDescriptor) | | codec describes the application codec such as registered interfaces and implementations | - + -### GetNodeInfoRequest -GetNodeInfoRequest is the request type for the Query/GetNodeInfo RPC method. +### GetConfigurationDescriptorRequest +GetConfigurationDescriptorRequest is the request used for the GetConfigurationDescriptor RPC - + -### GetNodeInfoResponse -GetNodeInfoResponse is the request type for the Query/GetNodeInfo RPC method. +### GetConfigurationDescriptorResponse +GetConfigurationDescriptorResponse is the response returned by the GetConfigurationDescriptor RPC | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| `default_node_info` | [ostracon.p2p.DefaultNodeInfo](#ostracon.p2p.DefaultNodeInfo) | | | -| `application_version` | [VersionInfo](#lbm.base.ostracon.v1.VersionInfo) | | | +| `config` | [ConfigurationDescriptor](#lbm.base.reflection.v2.ConfigurationDescriptor) | | config describes the application's sdk.Config | - + -### GetSyncingRequest -GetSyncingRequest is the request type for the Query/GetSyncing RPC method. +### GetQueryServicesDescriptorRequest +GetQueryServicesDescriptorRequest is the request used for the GetQueryServicesDescriptor RPC - + -### GetSyncingResponse -GetSyncingResponse is the response type for the Query/GetSyncing RPC method. +### GetQueryServicesDescriptorResponse +GetQueryServicesDescriptorResponse is the response returned by the GetQueryServicesDescriptor RPC | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| `syncing` | [bool](#bool) | | | - +| `queries` | [QueryServicesDescriptor](#lbm.base.reflection.v2.QueryServicesDescriptor) | | queries provides information on the available queryable services | - - -### GetValidatorSetByHeightRequest -GetValidatorSetByHeightRequest is the request type for the Query/GetValidatorSetByHeight RPC method. + -| Field | Type | Label | Description | -| ----- | ---- | ----- | ----------- | -| `height` | [int64](#int64) | | | -| `pagination` | [lbm.base.query.v1.PageRequest](#lbm.base.query.v1.PageRequest) | | pagination defines an pagination for the request. | +### GetTxDescriptorRequest +GetTxDescriptorRequest is the request used for the GetTxDescriptor RPC - + -### GetValidatorSetByHeightResponse -GetValidatorSetByHeightResponse is the response type for the Query/GetValidatorSetByHeight RPC method. +### GetTxDescriptorResponse +GetTxDescriptorResponse is the response returned by the GetTxDescriptor RPC | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| `block_height` | [int64](#int64) | | | -| `validators` | [Validator](#lbm.base.ostracon.v1.Validator) | repeated | | -| `pagination` | [lbm.base.query.v1.PageResponse](#lbm.base.query.v1.PageResponse) | | pagination defines an pagination for the response. | +| `tx` | [TxDescriptor](#lbm.base.reflection.v2.TxDescriptor) | | tx provides information on msgs that can be forwarded to the application alongside the accepted transaction protobuf type | - + -### Module -Module is the type for VersionInfo +### InterfaceAcceptingMessageDescriptor +InterfaceAcceptingMessageDescriptor describes a protobuf message which contains +an interface represented as a google.protobuf.Any | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| `path` | [string](#string) | | module path | -| `version` | [string](#string) | | module version | -| `sum` | [string](#string) | | checksum | +| `fullname` | [string](#string) | | fullname is the protobuf fullname of the type containing the interface | +| `field_descriptor_names` | [string](#string) | repeated | field_descriptor_names is a list of the protobuf name (not fullname) of the field which contains the interface as google.protobuf.Any (the interface is the same, but it can be in multiple fields of the same proto message) | - + -### Validator -Validator is the type for the validator-set. +### InterfaceDescriptor +InterfaceDescriptor describes the implementation of an interface | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| `address` | [string](#string) | | | -| `pub_key` | [google.protobuf.Any](#google.protobuf.Any) | | | -| `voting_power` | [int64](#int64) | | | -| `proposer_priority` | [int64](#int64) | | | +| `fullname` | [string](#string) | | fullname is the name of the interface | +| `interface_accepting_messages` | [InterfaceAcceptingMessageDescriptor](#lbm.base.reflection.v2.InterfaceAcceptingMessageDescriptor) | repeated | interface_accepting_messages contains information regarding the proto messages which contain the interface as google.protobuf.Any field | +| `interface_implementers` | [InterfaceImplementerDescriptor](#lbm.base.reflection.v2.InterfaceImplementerDescriptor) | repeated | interface_implementers is a list of the descriptors of the interface implementers | - + -### VersionInfo -VersionInfo is the type for the GetNodeInfoResponse message. +### InterfaceImplementerDescriptor +InterfaceImplementerDescriptor describes an interface implementer | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| `name` | [string](#string) | | | -| `app_name` | [string](#string) | | | -| `version` | [string](#string) | | | -| `git_commit` | [string](#string) | | | -| `build_tags` | [string](#string) | | | -| `go_version` | [string](#string) | | | -| `build_deps` | [Module](#lbm.base.ostracon.v1.Module) | repeated | | -| `lbm_sdk_version` | [string](#string) | | | - +| `fullname` | [string](#string) | | fullname is the protobuf queryable name of the interface implementer | +| `type_url` | [string](#string) | | type_url defines the type URL used when marshalling the type as any this is required so we can provide type safe google.protobuf.Any marshalling and unmarshalling, making sure that we don't accept just 'any' type in our interface fields | - - - + +### MsgDescriptor +MsgDescriptor describes a cosmos-sdk message that can be delivered with a transaction - -### Service -Service defines the gRPC querier service for ostracon queries. +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `msg_type_url` | [string](#string) | | msg_type_url contains the TypeURL of a sdk.Msg. | -| Method Name | Request Type | Response Type | Description | HTTP Verb | Endpoint | -| ----------- | ------------ | ------------- | ------------| ------- | -------- | -| `GetNodeInfo` | [GetNodeInfoRequest](#lbm.base.ostracon.v1.GetNodeInfoRequest) | [GetNodeInfoResponse](#lbm.base.ostracon.v1.GetNodeInfoResponse) | GetNodeInfo queries the current node info. | GET|/lbm/base/ostracon/v1/node_info| -| `GetSyncing` | [GetSyncingRequest](#lbm.base.ostracon.v1.GetSyncingRequest) | [GetSyncingResponse](#lbm.base.ostracon.v1.GetSyncingResponse) | GetSyncing queries node syncing. | GET|/lbm/base/ostracon/v1/syncing| -| `GetLatestBlock` | [GetLatestBlockRequest](#lbm.base.ostracon.v1.GetLatestBlockRequest) | [GetLatestBlockResponse](#lbm.base.ostracon.v1.GetLatestBlockResponse) | GetLatestBlock returns the latest block. | GET|/lbm/base/ostracon/v1/blocks/latest| -| `GetBlockByHeight` | [GetBlockByHeightRequest](#lbm.base.ostracon.v1.GetBlockByHeightRequest) | [GetBlockByHeightResponse](#lbm.base.ostracon.v1.GetBlockByHeightResponse) | GetBlockByHeight queries block for given height. | GET|/lbm/base/ostracon/v1/blocks/{height}| -| `GetBlockByHash` | [GetBlockByHashRequest](#lbm.base.ostracon.v1.GetBlockByHashRequest) | [GetBlockByHashResponse](#lbm.base.ostracon.v1.GetBlockByHashResponse) | GetBlockByHash queries block for given hash. | GET|/lbm/base/ostracon/v1/blocks/{hash}| -| `GetBlockResultsByHeight` | [GetBlockResultsByHeightRequest](#lbm.base.ostracon.v1.GetBlockResultsByHeightRequest) | [GetBlockResultsByHeightResponse](#lbm.base.ostracon.v1.GetBlockResultsByHeightResponse) | GetBlockResultsByHeight queries block results for given height. | GET|/lbm/base/ostracon/v1/blockresults/{height}| -| `GetLatestValidatorSet` | [GetLatestValidatorSetRequest](#lbm.base.ostracon.v1.GetLatestValidatorSetRequest) | [GetLatestValidatorSetResponse](#lbm.base.ostracon.v1.GetLatestValidatorSetResponse) | GetLatestValidatorSet queries latest validator-set. | GET|/lbm/base/ostracon/v1/validatorsets/latest| -| `GetValidatorSetByHeight` | [GetValidatorSetByHeightRequest](#lbm.base.ostracon.v1.GetValidatorSetByHeightRequest) | [GetValidatorSetByHeightResponse](#lbm.base.ostracon.v1.GetValidatorSetByHeightResponse) | GetValidatorSetByHeight queries validator-set at a given height. | GET|/lbm/base/ostracon/v1/validatorsets/{height}| - - -

Top

-## lbm/base/reflection/v1/reflection.proto + +### QueryMethodDescriptor +QueryMethodDescriptor describes a queryable method of a query service +no other info is provided beside method name and tendermint queryable path +because it would be redundant with the grpc reflection service - +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `name` | [string](#string) | | name is the protobuf name (not fullname) of the method | +| `full_query_path` | [string](#string) | | full_query_path is the path that can be used to query this method via tendermint abci.Query | -### ListAllInterfacesRequest -ListAllInterfacesRequest is the request type of the ListAllInterfaces RPC. + - +### QueryServiceDescriptor +QueryServiceDescriptor describes a cosmos-sdk queryable service + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `fullname` | [string](#string) | | fullname is the protobuf fullname of the service descriptor | +| `is_module` | [bool](#bool) | | is_module describes if this service is actually exposed by an application's module | +| `methods` | [QueryMethodDescriptor](#lbm.base.reflection.v2.QueryMethodDescriptor) | repeated | methods provides a list of query service methods | -### ListAllInterfacesResponse -ListAllInterfacesResponse is the response type of the ListAllInterfaces RPC. + + + + + + + +### QueryServicesDescriptor +QueryServicesDescriptor contains the list of cosmos-sdk queriable services | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| `interface_names` | [string](#string) | repeated | interface_names is an array of all the registered interfaces. | +| `query_services` | [QueryServiceDescriptor](#lbm.base.reflection.v2.QueryServiceDescriptor) | repeated | query_services is a list of cosmos-sdk QueryServiceDescriptor | - + -### ListImplementationsRequest -ListImplementationsRequest is the request type of the ListImplementations -RPC. +### SigningModeDescriptor +SigningModeDescriptor provides information on a signing flow of the application +NOTE(fdymylja): here we could go as far as providing an entire flow on how +to sign a message given a SigningModeDescriptor, but it's better to think about +this another time | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| `interface_name` | [string](#string) | | interface_name defines the interface to query the implementations for. | +| `name` | [string](#string) | | name defines the unique name of the signing mode | +| `number` | [int32](#int32) | | number is the unique int32 identifier for the sign_mode enum | +| `authn_info_provider_method_fullname` | [string](#string) | | authn_info_provider_method_fullname defines the fullname of the method to call to get the metadata required to authenticate using the provided sign_modes | - + -### ListImplementationsResponse -ListImplementationsResponse is the response type of the ListImplementations -RPC. +### TxDescriptor +TxDescriptor describes the accepted transaction type | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| `implementation_message_names` | [string](#string) | repeated | | +| `fullname` | [string](#string) | | fullname is the protobuf fullname of the raw transaction type (for instance the tx.Tx type) it is not meant to support polymorphism of transaction types, it is supposed to be used by reflection clients to understand if they can handle a specific transaction type in an application. | +| `msgs` | [MsgDescriptor](#lbm.base.reflection.v2.MsgDescriptor) | repeated | msgs lists the accepted application messages (sdk.Msg) | @@ -5595,15 +6693,19 @@ RPC. - + ### ReflectionService -ReflectionService defines a service for interface reflection. +ReflectionService defines a service for application reflection. | Method Name | Request Type | Response Type | Description | HTTP Verb | Endpoint | | ----------- | ------------ | ------------- | ------------| ------- | -------- | -| `ListAllInterfaces` | [ListAllInterfacesRequest](#lbm.base.reflection.v1.ListAllInterfacesRequest) | [ListAllInterfacesResponse](#lbm.base.reflection.v1.ListAllInterfacesResponse) | ListAllInterfaces lists all the interfaces registered in the interface registry. | GET|/lbm/base/reflection/v1/interfaces| -| `ListImplementations` | [ListImplementationsRequest](#lbm.base.reflection.v1.ListImplementationsRequest) | [ListImplementationsResponse](#lbm.base.reflection.v1.ListImplementationsResponse) | ListImplementations list all the concrete types that implement a given interface. | GET|/lbm/base/reflection/v1/interfaces/{interface_name}/implementations| +| `GetAuthnDescriptor` | [GetAuthnDescriptorRequest](#lbm.base.reflection.v2.GetAuthnDescriptorRequest) | [GetAuthnDescriptorResponse](#lbm.base.reflection.v2.GetAuthnDescriptorResponse) | GetAuthnDescriptor returns information on how to authenticate transactions in the application NOTE: this RPC is still experimental and might be subject to breaking changes or removal in future releases of the cosmos-sdk. | GET|/lbm/base/reflection/v1/app_descriptor/authn| +| `GetChainDescriptor` | [GetChainDescriptorRequest](#lbm.base.reflection.v2.GetChainDescriptorRequest) | [GetChainDescriptorResponse](#lbm.base.reflection.v2.GetChainDescriptorResponse) | GetChainDescriptor returns the description of the chain | GET|/lbm/base/reflection/v1/app_descriptor/chain| +| `GetCodecDescriptor` | [GetCodecDescriptorRequest](#lbm.base.reflection.v2.GetCodecDescriptorRequest) | [GetCodecDescriptorResponse](#lbm.base.reflection.v2.GetCodecDescriptorResponse) | GetCodecDescriptor returns the descriptor of the codec of the application | GET|/lbm/base/reflection/v1/app_descriptor/codec| +| `GetConfigurationDescriptor` | [GetConfigurationDescriptorRequest](#lbm.base.reflection.v2.GetConfigurationDescriptorRequest) | [GetConfigurationDescriptorResponse](#lbm.base.reflection.v2.GetConfigurationDescriptorResponse) | GetConfigurationDescriptor returns the descriptor for the sdk.Config of the application | GET|/lbm/base/reflection/v1/app_descriptor/configuration| +| `GetQueryServicesDescriptor` | [GetQueryServicesDescriptorRequest](#lbm.base.reflection.v2.GetQueryServicesDescriptorRequest) | [GetQueryServicesDescriptorResponse](#lbm.base.reflection.v2.GetQueryServicesDescriptorResponse) | GetQueryServicesDescriptor returns the available gRPC queryable services of the application | GET|/lbm/base/reflection/v1/app_descriptor/query_services| +| `GetTxDescriptor` | [GetTxDescriptorRequest](#lbm.base.reflection.v2.GetTxDescriptorRequest) | [GetTxDescriptorResponse](#lbm.base.reflection.v2.GetTxDescriptorResponse) | GetTxDescriptor returns information on the used transaction object and available msgs that can be used | GET|/lbm/base/reflection/v1/app_descriptor/tx_descriptor| @@ -5716,6 +6818,44 @@ between a store name and the commit ID. + + + + + + + + + + + +

Top

+ +## lbm/base/store/v1/listening.proto + + + + + +### StoreKVPair +StoreKVPair is a KVStore KVPair used for listening to state changes (Sets and Deletes) +It optionally includes the StoreKey for the originating KVStore and a Boolean flag to distinguish between Sets and +Deletes + +Since: cosmos-sdk 0.43 + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `store_key` | [string](#string) | | the store key for the KVStore this pair originates from | +| `delete` | [bool](#bool) | | true indicates a delete operation, false indicates a set operation | +| `key` | [bytes](#bytes) | | | +| `value` | [bytes](#bytes) | | | + + + + + @@ -7386,7 +8526,7 @@ Msg defines the evidence Msg service.

Top

## lbm/feegrant/v1/feegrant.proto - +Since: cosmos-sdk 0.43 @@ -7472,7 +8612,7 @@ as well as a limit per time period.

Top

## lbm/feegrant/v1/genesis.proto - +Since: cosmos-sdk 0.43 @@ -7503,7 +8643,7 @@ GenesisState contains a set of fee allowances, persisted from the store

Top

## lbm/feegrant/v1/query.proto - +Since: cosmos-sdk 0.43 @@ -7593,7 +8733,7 @@ Query defines the gRPC querier service.

Top

## lbm/feegrant/v1/tx.proto - +Since: cosmos-sdk 0.43 @@ -7829,7 +8969,7 @@ A Vote consists of a proposal ID, the voter, and the vote option. | `proposal_id` | [uint64](#uint64) | | | | `voter` | [string](#string) | | | | `option` | [VoteOption](#lbm.gov.v1.VoteOption) | | **Deprecated.** Deprecated: Prefer to use `options` instead. This field is set in queries if and only if `len(options) == 1` and that option has weight 1. In all other cases, this field will default to VOTE_OPTION_UNSPECIFIED. | -| `options` | [WeightedVoteOption](#lbm.gov.v1.WeightedVoteOption) | repeated | | +| `options` | [WeightedVoteOption](#lbm.gov.v1.WeightedVoteOption) | repeated | Since: cosmos-sdk 0.43 | @@ -7856,6 +8996,8 @@ VotingParams defines the params for voting on governance proposals. ### WeightedVoteOption WeightedVoteOption defines a unit of vote for vote split. +Since: cosmos-sdk 0.43 + | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | @@ -8329,6 +9471,8 @@ MsgVoteResponse defines the Msg/Vote response type. ### MsgVoteWeighted MsgVoteWeighted defines a message to cast a vote. +Since: cosmos-sdk 0.43 + | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | @@ -8346,6 +9490,8 @@ MsgVoteWeighted defines a message to cast a vote. ### MsgVoteWeightedResponse MsgVoteWeightedResponse defines the Msg/VoteWeighted response type. +Since: cosmos-sdk 0.43 + @@ -8366,7 +9512,9 @@ Msg defines the bank Msg service. | ----------- | ------------ | ------------- | ------------| ------- | -------- | | `SubmitProposal` | [MsgSubmitProposal](#lbm.gov.v1.MsgSubmitProposal) | [MsgSubmitProposalResponse](#lbm.gov.v1.MsgSubmitProposalResponse) | SubmitProposal defines a method to create new proposal given a content. | | | `Vote` | [MsgVote](#lbm.gov.v1.MsgVote) | [MsgVoteResponse](#lbm.gov.v1.MsgVoteResponse) | Vote defines a method to add a vote on a specific proposal. | | -| `VoteWeighted` | [MsgVoteWeighted](#lbm.gov.v1.MsgVoteWeighted) | [MsgVoteWeightedResponse](#lbm.gov.v1.MsgVoteWeightedResponse) | VoteWeighted defines a method to add a weighted vote on a specific proposal. | | +| `VoteWeighted` | [MsgVoteWeighted](#lbm.gov.v1.MsgVoteWeighted) | [MsgVoteWeightedResponse](#lbm.gov.v1.MsgVoteWeightedResponse) | VoteWeighted defines a method to add a weighted vote on a specific proposal. + +Since: cosmos-sdk 0.43 | | | `Deposit` | [MsgDeposit](#lbm.gov.v1.MsgDeposit) | [MsgDepositResponse](#lbm.gov.v1.MsgDepositResponse) | Deposit defines a method to add deposit on a specific proposal. | | @@ -8743,7 +9891,7 @@ GenesisState defines the slashing module's genesis state. | ----- | ---- | ----- | ----------- | | `params` | [Params](#lbm.slashing.v1.Params) | | params defines all the paramaters of related to deposit. | | `signing_infos` | [SigningInfo](#lbm.slashing.v1.SigningInfo) | repeated | signing_infos represents a map between validator addresses and their signing infos. | -| `missed_blocks` | [ValidatorMissedBlocks](#lbm.slashing.v1.ValidatorMissedBlocks) | repeated | signing_infos represents a map between validator addresses and their missed blocks. | +| `missed_blocks` | [ValidatorMissedBlocks](#lbm.slashing.v1.ValidatorMissedBlocks) | repeated | missed_blocks represents a map between validator addresses and their missed blocks. | @@ -8977,6 +10125,73 @@ Msg defines the slashing Msg service. + +

Top

+ +## lbm/staking/v1/authz.proto + + + + + +### StakeAuthorization +StakeAuthorization defines authorization for delegate/undelegate/redelegate. + +Since: cosmos-sdk 0.43 + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `max_tokens` | [lbm.base.v1.Coin](#lbm.base.v1.Coin) | | max_tokens specifies the maximum amount of tokens can be delegate to a validator. If it is empty, there is no spend limit and any amount of coins can be delegated. | +| `allow_list` | [StakeAuthorization.Validators](#lbm.staking.v1.StakeAuthorization.Validators) | | allow_list specifies list of validator addresses to whom grantee can delegate tokens on behalf of granter's account. | +| `deny_list` | [StakeAuthorization.Validators](#lbm.staking.v1.StakeAuthorization.Validators) | | deny_list specifies list of validator addresses to whom grantee can not delegate tokens. | +| `authorization_type` | [AuthorizationType](#lbm.staking.v1.AuthorizationType) | | authorization_type defines one of AuthorizationType. | + + + + + + + + +### StakeAuthorization.Validators +Validators defines list of validator addresses. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `address` | [string](#string) | repeated | | + + + + + + + + + + +### AuthorizationType +AuthorizationType defines the type of staking module authorization type + +Since: cosmos-sdk 0.43 + +| Name | Number | Description | +| ---- | ------ | ----------- | +| AUTHORIZATION_TYPE_UNSPECIFIED | 0 | AUTHORIZATION_TYPE_UNSPECIFIED specifies an unknown authorization type | +| AUTHORIZATION_TYPE_DELEGATE | 1 | AUTHORIZATION_TYPE_DELEGATE defines an authorization type for Msg/Delegate | +| AUTHORIZATION_TYPE_UNDELEGATE | 2 | AUTHORIZATION_TYPE_UNDELEGATE defines an authorization type for Msg/Undelegate | +| AUTHORIZATION_TYPE_REDELEGATE | 3 | AUTHORIZATION_TYPE_REDELEGATE defines an authorization type for Msg/BeginRedelegate | + + + + + + + + + +

Top

@@ -10511,88 +11726,88 @@ QueryApprovesResponse is the response type for the Query/Approves RPC method - + -### QueryGrantsRequest -QueryGrantsRequest is the request type for the Query/Grants RPC method +### QueryBalanceRequest +QueryBalanceRequest is the request type for the Query/Balance RPC method | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | | `class_id` | [string](#string) | | class id associated with the token. | -| `grantee` | [string](#string) | | | +| `address` | [string](#string) | | | - + -### QueryGrantsResponse -QueryGrantsResponse is the response type for the Query/Grants RPC method +### QueryBalanceResponse +QueryBalanceResponse is the response type for the Query/Balance RPC method | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| `grants` | [Grant](#lbm.token.v1.Grant) | repeated | | +| `amount` | [string](#string) | | | - + -### QuerySupplyRequest -QuerySupplyRequest is the request type for the Query/Supply RPC method +### QueryGrantsRequest +QueryGrantsRequest is the request type for the Query/Grants RPC method | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | | `class_id` | [string](#string) | | class id associated with the token. | -| `type` | [string](#string) | | | +| `grantee` | [string](#string) | | | - + -### QuerySupplyResponse -QuerySupplyResponse is the response type for the Query/Supply RPC method +### QueryGrantsResponse +QueryGrantsResponse is the response type for the Query/Grants RPC method | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| `amount` | [string](#string) | | | +| `grants` | [Grant](#lbm.token.v1.Grant) | repeated | | - + -### QueryTokenBalanceRequest -QueryTokenBalanceRequest is the request type for the Query/TokenBalance RPC method +### QuerySupplyRequest +QuerySupplyRequest is the request type for the Query/Supply RPC method | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | | `class_id` | [string](#string) | | class id associated with the token. | -| `address` | [string](#string) | | | +| `type` | [string](#string) | | | - + -### QueryTokenBalanceResponse -QueryTokenBalanceResponse is the response type for the Query/TokenBalance RPC method +### QuerySupplyResponse +QuerySupplyResponse is the response type for the Query/Supply RPC method | Field | Type | Label | Description | @@ -10678,7 +11893,7 @@ Query defines the gRPC querier service. | Method Name | Request Type | Response Type | Description | HTTP Verb | Endpoint | | ----------- | ------------ | ------------- | ------------| ------- | -------- | -| `TokenBalance` | [QueryTokenBalanceRequest](#lbm.token.v1.QueryTokenBalanceRequest) | [QueryTokenBalanceResponse](#lbm.token.v1.QueryTokenBalanceResponse) | TokenBalance queries the number of tokens of a given class owned by the address. | GET|/lbm/token/v1/balance/{address}/{class_id}| +| `Balance` | [QueryBalanceRequest](#lbm.token.v1.QueryBalanceRequest) | [QueryBalanceResponse](#lbm.token.v1.QueryBalanceResponse) | Balance queries the number of tokens of a given class owned by the address. | GET|/lbm/token/v1/balance/{address}/{class_id}| | `Supply` | [QuerySupplyRequest](#lbm.token.v1.QuerySupplyRequest) | [QuerySupplyResponse](#lbm.token.v1.QuerySupplyResponse) | Supply queries the number of tokens from the given class id. | GET|/lbm/token/v1/supply/{class_id}| | `Token` | [QueryTokenRequest](#lbm.token.v1.QueryTokenRequest) | [QueryTokenResponse](#lbm.token.v1.QueryTokenResponse) | Token queries an token metadata based on its class id. | GET|/lbm/token/v1/tokens/{class_id}| | `Tokens` | [QueryTokensRequest](#lbm.token.v1.QueryTokensRequest) | [QueryTokensResponse](#lbm.token.v1.QueryTokensResponse) | Tokens queries all token metadata. | GET|/lbm/token/v1/tokens| @@ -11275,7 +12490,7 @@ TxBody is the body of a transaction that all signers sign over. | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | | `messages` | [google.protobuf.Any](#google.protobuf.Any) | repeated | messages is a list of messages to be executed. The required signers of those messages define the number and order of elements in AuthInfo's signer_infos and Tx's signatures. Each required signer address is added to the list only the first time it occurs. By convention, the first required signer (usually from the first message) is referred to as the primary signer and pays the fee for the whole transaction. | -| `memo` | [string](#string) | | memo is any arbitrary memo to be added to the transaction | +| `memo` | [string](#string) | | memo is any arbitrary note/comment to be added to the transaction. WARNING: in clients, any publicly exposed text should not be called memo, but should be called `note` instead (see https://github.com/cosmos/cosmos-sdk/issues/9122). | | `timeout_height` | [uint64](#uint64) | | timeout is the block height after which this transaction will not be processed by the chain | | `extension_options` | [google.protobuf.Any](#google.protobuf.Any) | repeated | extension_options are arbitrary options that can be added by chains when the default options are not sufficient. If any of these are present and can't be handled, the transaction will be rejected | | `non_critical_extension_options` | [google.protobuf.Any](#google.protobuf.Any) | repeated | extension_options are arbitrary options that can be added by chains when the default options are not sufficient. If any of these are present and can't be handled, they will be ignored | @@ -11433,7 +12648,10 @@ RPC method. | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| `tx` | [Tx](#lbm.tx.v1.Tx) | | tx is the transaction to simulate. | +| `tx` | [Tx](#lbm.tx.v1.Tx) | | **Deprecated.** tx is the transaction to simulate. Deprecated. Send raw tx bytes instead. | +| `tx_bytes` | [bytes](#bytes) | | tx_bytes is the raw transaction. + +Since: cosmos-sdk 0.43 | @@ -11506,92 +12724,6 @@ Service defines a gRPC service for interacting with transactions. - -

Top

- -## lbm/upgrade/v1/upgrade.proto - - - - - -### CancelSoftwareUpgradeProposal -CancelSoftwareUpgradeProposal is a gov Content type for cancelling a software -upgrade. - - -| Field | Type | Label | Description | -| ----- | ---- | ----- | ----------- | -| `title` | [string](#string) | | | -| `description` | [string](#string) | | | - - - - - - - - -### ModuleVersion -ModuleVersion specifies a module and its consensus version. - - -| Field | Type | Label | Description | -| ----- | ---- | ----- | ----------- | -| `name` | [string](#string) | | name of the app module | -| `version` | [uint64](#uint64) | | consensus version of the app module | - - - - - - - - -### Plan -Plan specifies information about a planned upgrade and when it should occur. - - -| Field | Type | Label | Description | -| ----- | ---- | ----- | ----------- | -| `name` | [string](#string) | | Sets the name for the upgrade. This name will be used by the upgraded version of the software to apply any special "on-upgrade" commands during the first BeginBlock method after the upgrade is applied. It is also used to detect whether a software version can handle a given upgrade. If no upgrade handler with this name has been set in the software, it will be assumed that the software is out-of-date when the upgrade Time or Height is reached and the software will exit. | -| `time` | [google.protobuf.Timestamp](#google.protobuf.Timestamp) | | The time after which the upgrade must be performed. Leave set to its zero value to use a pre-defined Height instead. | -| `height` | [int64](#int64) | | The height at which the upgrade must be performed. Only used if Time is not set. | -| `info` | [string](#string) | | Any application specific upgrade info to be included on-chain such as a git commit that validators could automatically upgrade to | -| `upgraded_client_state` | [google.protobuf.Any](#google.protobuf.Any) | | IBC-enabled chains can opt-in to including the upgraded client state in its upgrade plan This will make the chain commit to the correct upgraded (self) client state before the upgrade occurs, so that connecting chains can verify that the new upgraded client is valid by verifying a proof on the previous version of the chain. This will allow IBC connections to persist smoothly across planned chain upgrades | - - - - - - - - -### SoftwareUpgradeProposal -SoftwareUpgradeProposal is a gov Content type for initiating a software -upgrade. - - -| Field | Type | Label | Description | -| ----- | ---- | ----- | ----------- | -| `title` | [string](#string) | | | -| `description` | [string](#string) | | | -| `plan` | [Plan](#lbm.upgrade.v1.Plan) | | | - - - - - - - - - - - - - - -

Top

@@ -11664,6 +12796,8 @@ method. QueryModuleVersionsRequest is the request type for the Query/ModuleVersions RPC method. +Since: cosmos-sdk 0.43 + | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | @@ -11680,6 +12814,8 @@ RPC method. QueryModuleVersionsResponse is the response type for the Query/ModuleVersions RPC method. +Since: cosmos-sdk 0.43 + | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | @@ -11715,7 +12851,7 @@ RPC method. | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| `upgraded_consensus_state` | [google.protobuf.Any](#google.protobuf.Any) | | | +| `upgraded_consensus_state` | [bytes](#bytes) | | Since: cosmos-sdk 0.43 | @@ -11737,8 +12873,10 @@ Query defines the gRPC upgrade querier service. | ----------- | ------------ | ------------- | ------------| ------- | -------- | | `CurrentPlan` | [QueryCurrentPlanRequest](#lbm.upgrade.v1.QueryCurrentPlanRequest) | [QueryCurrentPlanResponse](#lbm.upgrade.v1.QueryCurrentPlanResponse) | CurrentPlan queries the current upgrade plan. | GET|/lbm/upgrade/v1/current_plan| | `AppliedPlan` | [QueryAppliedPlanRequest](#lbm.upgrade.v1.QueryAppliedPlanRequest) | [QueryAppliedPlanResponse](#lbm.upgrade.v1.QueryAppliedPlanResponse) | AppliedPlan queries a previously applied upgrade plan by its name. | GET|/lbm/upgrade/v1/applied_plan/{name}| -| `UpgradedConsensusState` | [QueryUpgradedConsensusStateRequest](#lbm.upgrade.v1.QueryUpgradedConsensusStateRequest) | [QueryUpgradedConsensusStateResponse](#lbm.upgrade.v1.QueryUpgradedConsensusStateResponse) | UpgradedConsensusState queries the consensus state that will serve as a trusted kernel for the next version of this chain. It will only be stored at the last height of this chain. UpgradedConsensusState RPC not supported with legacy querier | GET|/lbm/upgrade/v1/upgraded_consensus_state/{last_height}| -| `ModuleVersions` | [QueryModuleVersionsRequest](#lbm.upgrade.v1.QueryModuleVersionsRequest) | [QueryModuleVersionsResponse](#lbm.upgrade.v1.QueryModuleVersionsResponse) | ModuleVersions queries the list of module versions from state. | GET|/lbm/upgrade/v1/module_versions| +| `UpgradedConsensusState` | [QueryUpgradedConsensusStateRequest](#lbm.upgrade.v1.QueryUpgradedConsensusStateRequest) | [QueryUpgradedConsensusStateResponse](#lbm.upgrade.v1.QueryUpgradedConsensusStateResponse) | UpgradedConsensusState queries the consensus state that will serve as a trusted kernel for the next version of this chain. It will only be stored at the last height of this chain. UpgradedConsensusState RPC not supported with legacy querier This rpc is deprecated now that IBC has its own replacement (https://github.com/cosmos/ibc-go/blob/2c880a22e9f9cc75f62b527ca94aa75ce1106001/proto/ibc/core/client/v1/query.proto#L54) | GET|/lbm/upgrade/v1/upgraded_consensus_state/{last_height}| +| `ModuleVersions` | [QueryModuleVersionsRequest](#lbm.upgrade.v1.QueryModuleVersionsRequest) | [QueryModuleVersionsResponse](#lbm.upgrade.v1.QueryModuleVersionsResponse) | ModuleVersions queries the list of module versions from state. + +Since: cosmos-sdk 0.43 | GET|/lbm/upgrade/v1/module_versions| @@ -11894,6 +13032,25 @@ periodically vests by unlocking coins during each specified period. + + + +### PermanentLockedAccount +PermanentLockedAccount implements the VestingAccount interface. It does +not ever release coins, locking them indefinitely. Coins in this account can +still be used for delegating and for governance votes even while locked. + +Since: cosmos-sdk 0.43 + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `base_vesting_account` | [BaseVestingAccount](#lbm.vesting.v1.BaseVestingAccount) | | | + + + + + diff --git a/docs/core/upgrade.md b/docs/core/upgrade.md new file mode 100644 index 0000000000..c1cf37acde --- /dev/null +++ b/docs/core/upgrade.md @@ -0,0 +1,160 @@ + + +# In-Place Store Migrations + +::: warning +Read and understand all of the in-place store migration documentation before you run a migration on a live chain. +::: + +Upgrade your app modules smoothly with custom in-place store migration logic. {synopsis} + +The Cosmos SDK uses two methods to perform upgrades. + +- Exporting the entire application state to a JSON file using the `export` CLI command, making changes, and then starting a new binary with the changed JSON file as the genesis file. See [Chain Upgrade Guide to v0.42](/v0.42/migrations/chain-upgrade-guide-040.html). + +- Version v0.44 and later can perform upgrades in place to significantly decrease the upgrade time for chains with a larger state. Use the [Module Upgrade Guide](../building-modules/upgrade.md) to set up your application modules to take advantage of in-place upgrades. + +This document provides steps to use the In-Place Store Migrations upgrade method. + +## Tracking Module Versions + +Each module gets assigned a consensus version by the module developer. The consensus version serves as the breaking change version of the module. The Cosmos SDK keeps track of all module consensus versions in the x/upgrade `VersionMap` store. During an upgrade, the difference between the old `VersionMap` stored in state and the new `VersionMap` is calculated by the Cosmos SDK. For each identified difference, the module-specific migrations are run and the respective consensus version of each upgraded module is incremented. + +### Consensus Version + +The consensus version is defined on each app module by the module developer and serves as the breaking change version of the module. The consensus version informs the SDK on which modules need to be upgraded. For example, if the bank module was version 2 and an upgrade introduces bank module 3, the SDK upgrades the bank module and runs the "version 2 to 3" migration script. + +### Version Map + +The version map is a mapping of module names to consensus versions. The map is persisted to x/upgrade's state for use during in-place migrations. When migrations finish, the updated version map is persisted in the state. + +## Upgrade Handlers + +Upgrades use an `UpgradeHandler` to facilitate migrations. The `UpgradeHandler` functions implemented by the app developer must conform to the following function signature. These functions retrieve the `VersionMap` from x/upgrade's state and return the new `VersionMap` to be stored in x/upgrade after the upgrade. The diff between the two `VersionMap`s determines which modules need upgrading. + +```go +type UpgradeHandler func(ctx sdk.Context, plan Plan, fromVM VersionMap) (VersionMap, error) +``` + +Inside these functions, you must perform any upgrade logic to include in the provided `plan`. All upgrade handler functions must end with the following line of code: + +```go + return app.mm.RunMigrations(ctx, cfg, fromVM) +``` + +## Running Migrations + +Migrations are run inside of an `UpgradeHandler` using `app.mm.RunMigrations(ctx, cfg, vm)`. The `UpgradeHandler` functions describe the functionality to occur during an upgrade. The `RunMigration` function loops through the `VersionMap` argument and runs the migration scripts for all versions that are less than the versions of the new binary app module. After the migrations are finished, a new `VersionMap` is returned to persist the upgraded module versions to state. + +```go +cfg := module.NewConfigurator(...) +app.UpgradeKeeper.SetUpgradeHandler("my-plan", func(ctx sdk.Context, plan upgradetypes.Plan, fromVM module.VersionMap) (module.VersionMap, error) { + + // ... + // additional upgrade logic + // ... + + // returns a VersionMap with the updated module ConsensusVersions + return app.mm.RunMigrations(ctx, fromVM) +}) +``` + +To learn more about configuring migration scripts for your modules, see the [Module Upgrade Guide](../building-modules/upgrade.md). + +### Order Of Migrations + +By default, all migrations are run in module name alphabetical ascending order, except `x/auth` which is run last. The reason is state dependencies between x/auth and other modules (you can read more in [issue #10606](https://github.com/cosmos/cosmos-sdk/issues/10606)). + +If you want to change the order of migration then you should call `app.mm.SetOrderMigrations(module1, module2, ...)` in your app.go file. The function will panic if you forget to include a module in the argument list. + +## Adding New Modules During Upgrades + +You can introduce entirely new modules to the application during an upgrade. New modules are recognized because they have not yet been registered in `x/upgrade`'s `VersionMap` store. In this case, `RunMigrations` calls the `InitGenesis` function from the corresponding module to set up its initial state. + +### Add StoreUpgrades for New Modules + +All chains preparing to run in-place store migrations will need to manually add store upgrades for new modules and then configure the store loader to apply those upgrades. This ensures that the new module's stores are added to the multistore before the migrations begin. + +```go +upgradeInfo, err := app.UpgradeKeeper.ReadUpgradeInfoFromDisk() +if err != nil { + panic(err) +} + +if upgradeInfo.Name == "my-plan" && !app.UpgradeKeeper.IsSkipHeight(upgradeInfo.Height) { + storeUpgrades := storetypes.StoreUpgrades{ + // add store upgrades for new modules + // Example: + // Added: []string{"foo", "bar"}, + // ... + } + + // configure store loader that checks if version == upgradeHeight and applies store upgrades + app.SetStoreLoader(upgradetypes.UpgradeStoreLoader(upgradeInfo.Height, &storeUpgrades)) +} +``` + +## Genesis State + +When starting a new chain, the consensus version of each module MUST be saved to state during the application's genesis. To save the consensus version, add the following line to the `InitChainer` method in `app.go`: + +```diff +func (app *MyApp) InitChainer(ctx sdk.Context, req abci.RequestInitChain) abci.ResponseInitChain { + ... ++ app.UpgradeKeeper.SetModuleVersionMap(ctx, app.mm.GetVersionMap()) + ... +} +``` + +This information is used by the Cosmos SDK to detect when modules with newer versions are introduced to the app. + +For a new module `foo`, `InitGenesis` is called by `RunMigration` only when `foo` is registered in the module manager but it's not set in the `fromVM`. Therefore, if you want to skip `InitGenesis` when a new module is added to the app, then you should set its module version in `fromVM` to the module consensus version: + +```go +app.UpgradeKeeper.SetUpgradeHandler("my-plan", func(ctx sdk.Context, plan upgradetypes.Plan, fromVM module.VersionMap) (module.VersionMap, error) { + // ... + + // Set foo's version to the latest ConsensusVersion in the VersionMap. + // This will skip running InitGenesis on Foo + fromVM[foo.ModuleName] = foo.AppModule{}.ConsensusVersion() + + return app.mm.RunMigrations(ctx, fromVM) +}) +``` + +### Overwriting Genesis Functions + +The Cosmos SDK offers modules that the application developer can import in their app. These modules often have an `InitGenesis` function already defined. + +You can write your own `InitGenesis` function for an imported module. To do this, manually trigger your custom genesis function in the upgrade handler. + +::: warning +You MUST manually set the consensus version in the version map passed to the `UpgradeHandler` function. Without this, the SDK will run the Module's existing `InitGenesis` code even if you triggered your custom function in the `UpgradeHandler`. +::: + +```go +import foo "github.com/my/module/foo" + +app.UpgradeKeeper.SetUpgradeHandler("my-plan", func(ctx sdk.Context, plan upgradetypes.Plan, fromVM module.VersionMap) (module.VersionMap, error) { + + // Register the consensus version in the version map + // to avoid the SDK from triggering the default + // InitGenesis function. + fromVM["foo"] = foo.AppModule{}.ConsensusVersion() + + // Run custom InitGenesis for foo + app.mm["foo"].InitGenesis(ctx, app.appCodec, myCustomGenesisState) + + return app.mm.RunMigrations(ctx, cfg, fromVM) +}) +``` + +## Syncing a Full Node to an Upgraded Blockchain + +You can sync a full node to an existing blockchain which has been upgraded using Cosmovisor + +In order to successfully sync, you must start with the initial binary that the blockchain started with at genesis. Cosmovisor will handle downloading and switching to the binaries associated with each sequential upgrade. + +To learn more about Cosmovisor, see the [Cosmovisor Quick Start](../run-node/cosmovisor.md). diff --git a/docs/ibc/proposals.md b/docs/ibc/proposals.md new file mode 100644 index 0000000000..d82609262e --- /dev/null +++ b/docs/ibc/proposals.md @@ -0,0 +1,42 @@ + + +# Governance Proposals + +In uncommon situations, a highly valued client may become frozen due to uncontrollable +circumstances. A highly valued client might have hundreds of channels being actively used. +Some of those channels might have a significant amount of locked tokens used for ICS 20. + +If the one third of the validator set of the chain the client represents decides to collude, +they can sign off on two valid but conflicting headers each signed by the other one third +of the honest validator set. The light client can now be updated with two valid, but conflicting +headers at the same height. The light client cannot know which header is trustworthy and therefore +evidence of such misbehaviour is likely to be submitted resulting in a frozen light client. + +Frozen light clients cannot be updated under any circumstance except via a governance proposal. +Since a quorum of validators can sign arbitrary state roots which may not be valid executions +of the state machine, a governance proposal has been added to ease the complexity of unfreezing +or updating clients which have become "stuck". Without this mechanism, validator sets would need +to construct a state root to unfreeze the client. Unfreezing clients, re-enables all of the channels +built upon that client. This may result in recovery of otherwise lost funds. + +Tendermint light clients may become expired if the trusting period has passed since their +last update. This may occur if relayers stop submitting headers to update the clients. + +An unplanned upgrade by the counterparty chain may also result in expired clients. If the counterparty +chain undergoes an unplanned upgrade, there may be no commitment to that upgrade signed by the validator +set before the chain-id changes. In this situation, the validator set of the last valid update for the +light client is never expected to produce another valid header since the chain-id has changed, which will +ultimately lead the on-chain light client to become expired. + +In the case that a highly valued light client is frozen, expired, or rendered non-updateable, a +governance proposal may be submitted to update this client, known as the subject client. The +proposal includes the client identifier for the subject, the client identifier for a substitute +client, and an initial height to reference the substitute client from. Light client implementations +may implement custom updating logic, but in most cases, the subject will be updated with information +from the substitute client, if the proposal passes. The substitute client is used as a "stand in" +while the subject is on trial. It is best practice to create a substitute client *after* the subject +has become frozen to avoid the substitute from also becoming frozen. An active substitute client +allows headers to be submitted during the voting period to prevent accidental expiry once the proposal +passes. diff --git a/docs/ibc/upgrades/README.md b/docs/ibc/upgrades/README.md new file mode 100644 index 0000000000..bc7c88966a --- /dev/null +++ b/docs/ibc/upgrades/README.md @@ -0,0 +1,14 @@ + + +### Upgrading IBC Chains Overview + +This directory contains information on how to upgrade an IBC chain without breaking counterparty clients and connections. + +IBC-connnected chains must be able to upgrade without breaking connections to other chains. Otherwise there would be a massive disincentive towards upgrading and disrupting high-value IBC connections, thus preventing chains in the IBC ecosystem from evolving and improving. Many chain upgrades may be irrelevant to IBC, however some upgrades could potentially break counterparty clients if not handled correctly. Thus, any IBC chain that wishes to perform a IBC-client-breaking upgrade must perform an IBC upgrade in order to allow counterparty clients to securely upgrade to the new light client. + +1. The [quick-guide](./quick-guide.md) describes how IBC-connected chains can perform client-breaking upgrades and how relayers can securely upgrade counterparty clients using the SDK. +2. The [developer-guide](./developer-guide.md) is a guide for developers intending to develop IBC client implementations with upgrade functionality. diff --git a/docs/ibc/upgrades/developer-guide.md b/docs/ibc/upgrades/developer-guide.md new file mode 100644 index 0000000000..d41b3346d4 --- /dev/null +++ b/docs/ibc/upgrades/developer-guide.md @@ -0,0 +1,50 @@ + + +# IBC Client Developer Guide to Upgrades + +Learn how to implement upgrade functionality for your custom IBC client. {synopsis} + +As mentioned in the [README](./README.md), it is vital that high-value IBC clients can upgrade along with their underlying chains to avoid disruption to the IBC ecosystem. Thus, IBC client developers will want to implement upgrade functionality to enable clients to maintain connections and channels even across chain upgrades. + +The IBC protocol allows client implementations to provide a path to upgrading clients given the upgraded client state, upgraded consensus state and proofs for each. + +```go +// Upgrade functions +// NOTE: proof heights are not included as upgrade to a new revision is expected to pass only on the last +// height committed by the current revision. Clients are responsible for ensuring that the planned last +// height of the current revision is somehow encoded in the proof verification process. +// This is to ensure that no premature upgrades occur, since upgrade plans committed to by the counterparty +// may be cancelled or modified before the last planned height. +VerifyUpgradeAndUpdateState( + ctx sdk.Context, + cdc codec.BinaryCodec, + store sdk.KVStore, + newClient ClientState, + newConsState ConsensusState, + proofUpgradeClient, + proofUpgradeConsState []byte, +) (upgradedClient ClientState, upgradedConsensus ConsensusState, err error) +``` + +Note that the clients should have prior knowledge of the merkle path that the upgraded client and upgraded consensus states will use. The height at which the upgrade has occurred should also be encoded in the proof. The Tendermint client implementation accomplishes this by including an `UpgradePath` in the ClientState itself, which is used along with the upgrade height to construct the merkle path under which the client state and consensus state are committed. + +Developers must ensure that the `UpgradeClientMsg` does not pass until the last height of the old chain has been committed, and after the chain upgrades, the `UpgradeClientMsg` should pass once and only once on all counterparty clients. + +Developers must ensure that the new client adopts all of the new Client parameters that must be uniform across every valid light client of a chain (chain-chosen parameters), while maintaining the Client parameters that are customizable by each individual client (client-chosen parameters) from the previous version of the client. + +Upgrades must adhere to the IBC Security Model. IBC does not rely on the assumption of honest relayers for correctness. Thus users should not have to rely on relayers to maintain client correctness and security (though honest relayers must exist to maintain relayer liveness). While relayers may choose any set of client parameters while creating a new `ClientState`, this still holds under the security model since users can always choose a relayer-created client that suits their security and correctness needs or create a Client with their desired parameters if no such client exists. + +However, when upgrading an existing client, one must keep in mind that there are already many users who depend on this client's particular parameters. We cannot give the upgrading relayer free choice over these parameters once they have already been chosen. This would violate the security model since users who rely on the client would have to rely on the upgrading relayer to maintain the same level of security. Thus, developers must make sure that their upgrade mechanism allows clients to upgrade the chain-specified parameters whenever a chain upgrade changes these parameters (examples in the Tendermint client include `UnbondingPeriod`, `ChainID`, `UpgradePath`, etc.), while ensuring that the relayer submitting the `UpgradeClientMsg` cannot alter the client-chosen parameters that the users are relying upon (examples in Tendermint client include `TrustingPeriod`, `TrustLevel`, `MaxClockDrift`, etc). + +Developers should maintain the distinction between Client parameters that are uniform across every valid light client of a chain (chain-chosen parameters), and Client parameters that are customizable by each individual client (client-chosen parameters); since this distinction is necessary to implement the `ZeroCustomFields` method in the `ClientState` interface: + +```go +// Utility function that zeroes out any client customizable fields in client state +// Ledger enforced fields are maintained while all custom fields are zero values +// Used to verify upgrades +ZeroCustomFields() ClientState +``` + +Counterparty clients can upgrade securely by using all of the chain-chosen parameters from the chain-committed `UpgradedClient` and preserving all of the old client-chosen parameters. This enables chains to securely upgrade without relying on an honest relayer, however it can in some cases lead to an invalid final `ClientState` if the new chain-chosen parameters clash with the old client-chosen parameter. This can happen in the Tendermint client case if the upgrading chain lowers the `UnbondingPeriod` (chain-chosen) to a duration below that of a counterparty client's `TrustingPeriod` (client-chosen). Such cases should be clearly documented by developers, so that chains know which upgrades should be avoided to prevent this problem. The final upgraded client should also be validated in `VerifyUpgradeAndUpdateState` before returning to ensure that the client does not upgrade to an invalid `ClientState`. diff --git a/docs/ibc/upgrades/quick-guide.md b/docs/ibc/upgrades/quick-guide.md new file mode 100644 index 0000000000..d277de14fa --- /dev/null +++ b/docs/ibc/upgrades/quick-guide.md @@ -0,0 +1,54 @@ + + +# How to Upgrade IBC Chains and their Clients + +Learn how to upgrade your chain and counterparty clients. {synopsis} + +The information in this doc for upgrading chains is relevant to SDK chains. However, the guide for counterparty clients is relevant to any Tendermint client that enables upgrades. + +### IBC Client Breaking Upgrades + +IBC-connected chains must perform an IBC upgrade if their upgrade will break counterparty IBC clients. The current IBC protocol supports upgrading tendermint chains for a specific subset of IBC-client-breaking upgrades. Here is the exhaustive list of IBC client-breaking upgrades and whether the IBC protocol currently supports such upgrades. + +IBC currently does **NOT** support unplanned upgrades. All of the following upgrades must be planned and committed to in advance by the upgrading chain, in order for counterparty clients to maintain their connections securely. + +Note: Since upgrades are only implemented for Tendermint clients, this doc only discusses upgrades on Tendermint chains that would break counterparty IBC Tendermint Clients. + +1. Changing the Chain-ID: **Supported** +2. Changing the UnbondingPeriod: **Partially Supported**, chains may increase the unbonding period with no issues. However, decreasing the unbonding period may irreversibly break some counterparty clients. Thus, it is **not recommended** that chains reduce the unbonding period. +3. Changing the height (resetting to 0): **Supported**, so long as chains remember to increment the revision number in their chain-id. +4. Changing the ProofSpecs: **Supported**, this should be changed if the proof structure needed to verify IBC proofs is changed across the upgrade. Ex: Switching from an IAVL store, to a SimpleTree Store +5. Changing the UpgradePath: **Supported**, this might involve changing the key under which upgraded clients and consensus states are stored in the upgrade store, or even migrating the upgrade store itself. +6. Migrating the IBC store: **Unsupported**, as the IBC store location is negotiated by the connection. +7. Upgrading to a backwards compatible version of IBC: Supported +8. Upgrading to a non-backwards compatible version of IBC: **Unsupported**, as IBC version is negotiated on connection handshake. +9. Changing the Tendermint LightClient algorithm: **Partially Supported**. Changes to the light client algorithm that do not change the ClientState or ConsensusState struct may be supported, provided that the counterparty is also upgraded to support the new light client algorithm. Changes that require updating the ClientState and ConsensusState structs themselves are theoretically possible by providing a path to translate an older ClientState struct into the new ClientState struct; however this is not currently implemented. + +### Step-by-Step Upgrade Process for SDK chains + +If the IBC-connected chain is conducting an upgrade that will break counterparty clients, it must ensure that the upgrade is first supported by IBC using the list above and then execute the upgrade process described below in order to prevent counterparty clients from breaking. + +1. Create an `UpgradeProposal` with an IBC ClientState in the `UpgradedClientState` field and a `UpgradePlan` in the `Plan` field. Note that the proposal `Plan` must specify an upgrade height **only** (no upgrade time), and the `ClientState` should only include the fields common to all valid clients and zero out any client-customizable fields (such as TrustingPeriod). +2. Vote on and pass the `UpgradeProposal` + +Upon the `UpgradeProposal` passing, the upgrade module will commit the UpgradedClient under the key: `upgrade/UpgradedIBCState/{upgradeHeight}/upgradedClient`. On the block right before the upgrade height, the upgrade module will also commit an initial consensus state for the next chain under the key: `upgrade/UpgradedIBCState/{upgradeHeight}/upgradedConsState`. + +Once the chain reaches the upgrade height and halts, a relayer can upgrade the counterparty clients to the last block of the old chain. They can then submit the proofs of the `UpgradedClient` and `UpgradedConsensusState` against this last block and upgrade the counterparty client. + +### Step-by-Step Upgrade Process for Relayers Upgrading Counterparty Clients + +Once the upgrading chain has committed to upgrading, relayers must wait till the chain halts at the upgrade height before upgrading counterparty clients. This is because chains may reschedule or cancel upgrade plans before they occur. Thus, relayers must wait till the chain reaches the upgrade height and halts before they can be sure the upgrade will take place. + +Thus, the upgrade process for relayers trying to upgrade the counterparty clients is as follows: + +1. Wait for the upgrading chain to reach the upgrade height and halt +2. Query a full node for the proofs of `UpgradedClient` and `UpgradedConsensusState` at the last height of the old chain. +3. Update the counterparty client to the last height of the old chain using the `UpdateClient` msg. +4. Submit an `UpgradeClient` msg to the counterparty chain with the `UpgradedClient`, `UpgradedConsensusState` and their respective proofs. +5. Submit an `UpdateClient` msg to the counterparty chain with a header from the new upgraded chain. + +The Tendermint client on the counterparty chain will verify that the upgrading chain did indeed commit to the upgraded client and upgraded consensus state at the upgrade height (since the upgrade height is included in the key). If the proofs are verified against the upgrade height, then the client will upgrade to the new client while retaining all of its client-customized fields. Thus, it will retain its old TrustingPeriod, TrustLevel, MaxClockDrift, etc; while adopting the new chain-specified fields such as UnbondingPeriod, ChainId, UpgradePath, etc. Note, this can lead to an invalid client since the old client-chosen fields may no longer be valid given the new chain-chosen fields. Upgrading chains should try to avoid these situations by not altering parameters that can break old clients. For an example, see the UnbondingPeriod example in the supported upgrades section. + +The upgraded consensus state will serve purely as a basis of trust for future `UpdateClientMsgs` and will not contain a consensus root to perform proof verification against. Thus, relayers must submit an `UpdateClientMsg` with a header from the new chain so that the connection can be used for proof verification again. diff --git a/docs/migrations/chain-upgrade-guide-044.md b/docs/migrations/chain-upgrade-guide-044.md new file mode 100644 index 0000000000..f7ed5dc53a --- /dev/null +++ b/docs/migrations/chain-upgrade-guide-044.md @@ -0,0 +1,239 @@ + + +# Chain Upgrade Guide to v0.44 + +This document provides guidelines for a chain upgrade from v0.42 to v0.44 and an example of the upgrade process using `simapp`. {synopsis} + +::: tip +You must upgrade to Stargate v0.42 before upgrading to v0.44. If you have not done so, please see [Chain Upgrade Guide to v0.42](/v0.42/migrations/chain-upgrade-guide-040.html). Please note, v0.43 was discontinued shortly after being released and all chains should upgrade directly to v0.44 from v0.42. +::: + +## Prerequisite Readings + +- [Upgrading Modules](../building-modules/upgrade.html) {prereq} +- [In-Place Store Migrations](../core/upgrade.html) {prereq} +- [Cosmovisor](../run-node/cosmovisor.html) {prereq} + +Cosmos SDK v0.44 introduces a new way of handling chain upgrades that no longer requires exporting state to JSON, making the necessary changes, and then creating a new chain with the modified JSON as the new genesis file. + +The IBC module for the Cosmos SDK has moved to its [own repository](https://github.com/cosmos/ibc-go) for v0.42 and later versions. If you are using IBC, make sure to also go through the [IBC migration docs](https://github.com/cosmos/ibc-go/blob/main/docs/migrations/ibc-migration-043.md). + +Instead of starting a new chain, the upgrade binary will read the existing database and perform in-place store migrations. This new way of handling chain upgrades can be used alongside [Cosmovisor](../run-node/cosmovisor.html) to make the upgrade process seamless. + +## In-Place Store Migrations + +We recommend using [In-Place Store Migrations](../core/upgrade.html) to upgrade your chain from v0.42 to v0.44. The first step is to make sure all your modules follow the [Module Upgrade Guide](../building-modules/upgrade.html). The second step is to add an [upgrade handler](../core/upgrade.html#running-migrations) to `app.go`. + +In this document, we'll provide an example of what the upgrade handler looks like for a chain upgrading module versions for the first time. It's critical to note that the initial version of each module must be set to `1` rather than `0` or else the upgrade handler will re-initialize each module. + +In addition to migrating existing modules, the upgrade handler also performs store upgrades for new modules. In the example below, we'll be adding store migrations for two new modules made available in v0.44: `x/authz` and `x/feegrant`. + +## Using Cosmovisor + +We recommend validators use [Cosmovisor](../run-node/cosmovisor.html), which is a process manager for running application binaries. For security reasons, we recommend validators build their own upgrade binaries rather than enabling the auto-download option. Validators may still choose to use the auto-download option if the necessary security guarantees are in place (i.e. the URL provided in the upgrade proposal for the downloadable upgrade binary includes a proper checksum). + +Validators can use the auto-restart option to prevent unecessary downtime during the upgrade process. The auto-restart option will automatically restart the chain with the upgrade binary once the chain has halted at the proposed upgrade height. With the auto-restart option, validators can prepare the upgrade binary in advance and then relax at the time of the upgrade. + +## Migrating app.toml + +With the update to `v0.44`, new server configuration options have been added to `app.toml`. The updates include new configuration sections for Rosetta and gRPC Web as well as a new configuration option for State Sync. Check out the default [`app.toml`](https://github.com/cosmos/cosmos-sdk/blob/release/v0.44.x/server/config/toml.go) file in the latest version of `v0.44` for more information. + +## Example: Simapp Upgrade + +The following example will walk through the upgrade process using `simapp` as our blockchain application. We will be upgrading `simapp` from v0.42 to v0.44. We will be building the upgrade binary ourselves and enabling the auto-restart option. + +*Note: In this example, we will be starting a new chain from `v0.42`. The binary for this version will be the genesis binary. For validators using Cosmovisor for the first time, the binary for the current version of the chain should be used as the genesis binary (i.e. the starting binary). For more information, see [Cosmovisor](../run-node/cosmovisor.html).* + +### Initial Setup + +From within the `cosmos-sdk` repository, check out the latest `v0.42.x` release: + +``` +git checkout release/v0.42.x +``` + +Build the `simd` binary for the latest `v0.42.x` release (the genesis binary): + +``` +make build +``` + +Reset `~/.simapp` (never do this in a production environment): + +``` +./build/simd unsafe-reset-all +``` + +Configure the `simd` binary for testing: + +``` +./build/simd config chain-id test +./build/simd config keyring-backend test +./build/simd config broadcast-mode block +``` + +Initialize the node and overwrite any previous genesis file (never do this in a production environment): + + + +``` +./build/simd init test --chain-id test --overwrite +``` + +Set the minimum gas price to `0stake` in `~/.simapp/config/app.toml`: + +``` +minimum-gas-prices = "0stake" +``` + +For the purpose of this demonstration, change `voting_period` in `genesis.json` to a reduced time of 20 seconds (`20s`): + +``` +cat <<< $(jq '.app_state.gov.voting_params.voting_period = "20s"' $HOME/.simapp/config/genesis.json) > $HOME/.simapp/config/genesis.json +``` + +Create a new key for the validator, then add a genesis account and transaction: + + + + +``` +./build/simd keys add validator +./build/simd add-genesis-account validator 5000000000stake --keyring-backend test +./build/simd gentx validator 1000000stake --chain-id test +./build/simd collect-gentxs +``` + +Now that our node is initialized and we are ready to start a new `simapp` chain, let's set up `cosmovisor` and the genesis binary. + +### Cosmovisor Setup + +First, install or update `cosmovisor`: + +``` +go get github.com/cosmos/cosmos-sdk/cosmovisor/cmd/cosmovisor +``` + +Set the required environment variables: + +``` +export DAEMON_NAME=simd +export DAEMON_HOME=$HOME/.simapp +``` + +Set the optional environment variable to trigger an automatic restart: + +``` +export DAEMON_RESTART_AFTER_UPGRADE=true +``` + +Create the folder for the genesis binary and copy the `v0.42.x` binary: + +``` +mkdir -p $DAEMON_HOME/cosmovisor/genesis/bin +cp ./build/simd $DAEMON_HOME/cosmovisor/genesis/bin +``` + +Now that `cosmovisor` is installed and the genesis binary has been added, let's add the upgrade handler to `simapp/app.go` and prepare the upgrade binary. + +### Chain Upgrade + + + +Check out `release/v0.44.x`: + +``` +git checkout release/v0.44.x +``` + +Add the following to `simapp/app.go` inside `NewSimApp` and after `app.UpgradeKeeper`: + +```go + app.registerUpgradeHandlers() +``` + +Add the following to `simapp/app.go` after `NewSimApp` (to learn more about the upgrade handler, see the [In-Place Store Migrations](../core/upgrade.html)): + +```go +func (app *SimApp) registerUpgradeHandlers() { + app.UpgradeKeeper.SetUpgradeHandler("v0.44", func(ctx sdk.Context, plan upgradetypes.Plan, _ module.VersionMap) (module.VersionMap, error) { + // 1st-time running in-store migrations, using 1 as fromVersion to + // avoid running InitGenesis. + fromVM := map[string]uint64{ + "auth": 1, + "bank": 1, + "capability": 1, + "crisis": 1, + "distribution": 1, + "evidence": 1, + "gov": 1, + "mint": 1, + "params": 1, + "slashing": 1, + "staking": 1, + "upgrade": 1, + "vesting": 1, + "ibc": 1, + "genutil": 1, + "transfer": 1, + } + + return app.mm.RunMigrations(ctx, app.configurator, fromVM) + }) + + upgradeInfo, err := app.UpgradeKeeper.ReadUpgradeInfoFromDisk() + if err != nil { + panic(err) + } + + if upgradeInfo.Name == "v0.44" && !app.UpgradeKeeper.IsSkipHeight(upgradeInfo.Height) { + storeUpgrades := storetypes.StoreUpgrades{ + Added: []string{"authz", "feegrant"}, + } + + // configure store loader that checks if version == upgradeHeight and applies store upgrades + app.SetStoreLoader(upgradetypes.UpgradeStoreLoader(upgradeInfo.Height, &storeUpgrades)) + } +} +``` + +Add `storetypes` to imports: + +```go + storetypes "github.com/cosmos/cosmos-sdk/store/types" +``` + +Build the `simd` binary for `v0.44.x` (the upgrade binary): + +``` +make build +``` + +Create the folder for the upgrade binary and copy the `v0.44.x` binary: + +``` +mkdir -p $DAEMON_HOME/cosmovisor/upgrades/v0.44/bin +cp ./build/simd $DAEMON_HOME/cosmovisor/upgrades/v0.44/bin +``` + +Now that we have added the upgrade handler and prepared the upgrade binary, we are ready to start `cosmovisor` and simulate the upgrade proposal process. + +### Upgrade Proposal + +Start the node using `cosmovisor`: + +``` +cosmovisor start +``` + +Open a new terminal window and submit an upgrade proposal along with a deposit and a vote (these commands must be run within 20 seconds of each other): + +``` +./build/simd tx gov submit-proposal software-upgrade v0.44 --title upgrade --description upgrade --upgrade-height 20 --from validator --yes +./build/simd tx gov deposit 1 10000000stake --from validator --yes +./build/simd tx gov vote 1 yes --from validator --yes +``` + +Confirm the chain automatically upgrades at height 20. diff --git a/docs/migrations/keyring.md b/docs/migrations/keyring.md deleted file mode 100644 index dbd51269b6..0000000000 --- a/docs/migrations/keyring.md +++ /dev/null @@ -1,31 +0,0 @@ - -# Keyring Migrate Quick Start - -`keyring` is the Cosmos SDK mechanism to manage the public/private keypair. Cosmos SDK v0.42 (Stargate) introduced breaking changes in the keyring. - -To upgrade your chain from v0.39 (Launchpad) and earlier to Stargate, you must migrate your keys inside the keyring to the latest version. For details on configuring and using the keyring, see [Setting up the keyring](../run-node/keyring.md). - -This guide describes how to migrate your keyrings. - -The following command migrates your keyrings: - -```bash -Usage -simd keys migrate -``` - -The migration process moves key information from the legacy db-based Keybase to the [keyring](https://github.com/99designs/keyring)-based Keyring. The legacy Keybase persists keys in a LevelDB database in a 'keys' sub-directory of the client application home directory (`old_home_dir`). For example, `$HOME/.gaiacli/keys/` for [Gaia](https://github.com/cosmos/gaia). - -You can migrate or skip the migration for each key entry found in the specified `old_home_dir` directory. Each key migration requires a valid passphrase. If an invalid passphrase is entered, the command exits. Run the command again to restart the keyring migration. - -The `migrate` command takes the following flags: -- `--dry-run` boolean - - - true - run the migration but do not persist changes to the new Keybase. - - false - run the migration and persist keys to the new Keybase. - -Recommended: Use `--dry-run true` to test the migration without persisting changes before you migrate and persist keys. - -- `--keyring-backend` string flag. It allows you to select a backend. For more detailed information about the available backends, you can read [the keyring guide](../run-node/keyring.md). diff --git a/docs/migrations/pre-upgrade.md b/docs/migrations/pre-upgrade.md new file mode 100644 index 0000000000..00b4c54e21 --- /dev/null +++ b/docs/migrations/pre-upgrade.md @@ -0,0 +1,55 @@ +# Pre-Upgrade Handling + +Cosmovisor supports custom pre-upgrade handling. Use pre-upgrade handling when you need to implement application config changes that are required in the newer version before you perform the upgrade. + +Using Cosmovisor pre-upgrade handling is optional. If pre-upgrade handling is not implemented, the upgrade continues. + +For example, make the required new-version changes to `app.toml` settings during the pre-upgrade handling. The pre-upgrade handling process means that the file does not have to be manually updated after the upgrade. + +Before the application binary is upgraded, Cosmovisor calls a `pre-upgrade` command that can be implemented by the application. + +The `pre-upgrade` command does not take in any command-line arguments and is expected to terminate with the following exit codes: + +| Exit status code | How it is handled in Cosmosvisor | +|------------------|---------------------------------------------------------------------------------------------------------------------| +| `0` | Assumes `pre-upgrade` command executed successfully and continues the upgrade. | +| `1` | Default exit code when `pre-upgrade` command has not been implemented. | +| `30` | `pre-upgrade` command was executed but failed. This fails the entire upgrade. | +| `31` | `pre-upgrade` command was executed but failed. But the command is retried until exit code `1` or `30` are returned. | + +## Sample + +Here is a sample structure of the `pre-upgrade` command: + +```go +func preUpgradeCommand() *cobra.Command { + cmd := &cobra.Command{ + Use: "pre-upgrade", + Short: "Pre-upgrade command", + Long: "Pre-upgrade command to implement custom pre-upgrade handling", + Run: func(cmd *cobra.Command, args []string) { + + err := HandlePreUpgrade() + + if err != nil { + os.Exit(30) + } + + os.Exit(0) + + }, + } + + return cmd +} +``` + +Ensure that the pre-upgrade command has been registered in the application: + +```go +rootCmd.AddCommand( + // .. + preUpgradeCommand(), + // .. + ) +``` diff --git a/docs/run-node/rosetta.md b/docs/run-node/rosetta.md new file mode 100644 index 0000000000..e48b744084 --- /dev/null +++ b/docs/run-node/rosetta.md @@ -0,0 +1,133 @@ +# Rosetta + +The `rosetta` package implements Coinbase's [Rosetta API](https://www.rosetta-api.org). This document provides instructions on how to use the Rosetta API integration. For information about the motivation and design choices, refer to [ADR 035](../architecture/adr-035-rosetta-api-support.md). + +## Add Rosetta Command + +The Rosetta API server is a stand-alone server that connects to a node of a chain developed with Cosmos SDK. + +To enable Rosetta API support, it's required to add the `RosettaCommand` to your application's root command file (e.g. `appd/cmd/root.go`). + +Import the `server` package: + +```go + "github.com/cosmos/cosmos-sdk/server" +``` + +Find the following line: + +```go +initRootCmd(rootCmd, encodingConfig) +``` + +After that line, add the following: + +```go +rootCmd.AddCommand( + server.RosettaCommand(encodingConfig.InterfaceRegistry, encodingConfig.Marshaler) +) +``` + +The `RosettaCommand` function builds the `rosetta` root command and is defined in the `server` package within Cosmos SDK. + +Since we’ve updated the Cosmos SDK to work with the Rosetta API, updating the application's root command file is all you need to do. + +An implementation example can be found in `simapp` package. + +## Use Rosetta Command + +To run Rosetta in your application CLI, use the following command: + +``` +appd rosetta --help +``` + +To test and run Rosetta API endpoints for applications that are running and exposed, use the following command: + +``` +appd rosetta + --blockchain "your application name (ex: gaia)" + --network "your chain identifier (ex: testnet-1)" + --tendermint "tendermint endpoint (ex: localhost:26657)" + --grpc "gRPC endpoint (ex: localhost:9090)" + --addr "rosetta binding address (ex: :8080)" +``` + +## Extension + +There are two ways in which you can customize and extend the implementation with your custom settings. + +### Message extension + +In order to make an `sdk.Msg` understandable by rosetta the only thing which is required is adding the methods to your message that satisfy the `rosetta.Msg` interface. +Examples on how to do so can be found in the staking types such as `MsgDelegate`, or in bank types such as `MsgSend`. + +### Client interface override + +In case more customization is required, it's possible to embed the Client type and override the methods which require customizations. + +Example: + +```go +package custom_client +import ( + +"context" +"github.com/coinbase/rosetta-sdk-go/types" +"github.com/line/lbm-sdk/server/rosetta/lib" +) + +// CustomClient embeds the standard cosmos client +// which means that it implements the cosmos-rosetta-gateway Client +// interface while at the same time allowing to customize certain methods +type CustomClient struct { + *rosetta.Client +} + +func (c *CustomClient) ConstructionPayload(_ context.Context, request *types.ConstructionPayloadsRequest) (resp *types.ConstructionPayloadsResponse, err error) { + // provide custom signature bytes + panic("implement me") +} +``` + +### Error extension + +Since rosetta requires to provide 'returned' errors to network options. In order to declare a new rosetta error, we use the `errors` package in cosmos-rosetta-gateway. + +Example: + +```go +package custom_errors +import crgerrs "github.com/cosmos/cosmos-sdk/server/rosetta/lib/errors" + +var customErrRetriable = true +var CustomError = crgerrs.RegisterError(100, "custom message", customErrRetriable, "description") +``` + +Note: errors must be registered before cosmos-rosetta-gateway's `Server`.`Start` method is called. Otherwise the registration will be ignored. Errors with same code will be ignored too. + +## Integration in app.go + +To integrate rosetta as a command in your application, in app.go, in your root command simply use the `server.RosettaCommand` method. + +Example: + +```go +package app +import ( + +"github.com/line/lbm-sdk/server" +"github.com/spf13/cobra" +) + +func buildAppCommand(rootCmd *cobra.Command) { + // more app.go init stuff + // ... + // add rosetta command + rootCmd.AddCommand(server.RosettaCommand(encodingConfig.InterfaceRegistry, encodingConfig.Marshaler)) +} +``` + +A full implementation example can be found in `simapp` package. + +NOTE: when using a customized client, the command cannot be used as the constructors required **may** differ, so it's required to create a new one. We intend to provide a way to init a customized client without writing extra code in the future. diff --git a/docs/run-node/run-testnet.md b/docs/run-node/run-testnet.md new file mode 100644 index 0000000000..0cbfe8cf97 --- /dev/null +++ b/docs/run-node/run-testnet.md @@ -0,0 +1,99 @@ + + +# Running a Testnet + +The `simd testnet` subcommand makes it easy to initialize and start a simulated test network for testing purposes. {synopsis} + +In addition to the commands for [running a node](./run-node.html), the `simd` binary also includes a `testnet` command that allows you to start a simulated test network in-process or to initialize files for a simulated test network that runs in a separate process. + +## Initialize Files + +First, let's take a look at the `init-files` subcommand. + +This is similar to the `init` command when initializing a single node, but in this case we are initializing multiple nodes, generating the genesis transactions for each node, and then collecting those transactions. + +The `init-files` subcommand initializes the necessary files to run a test network in a separate process (i.e. using a Docker container). Running this command is not a prerequisite for the `start` subcommand ([see below](#start-testnet)). + +In order to initialize the files for a test network, run the following command: + +```bash +simd testnet init-files +``` + +You should see the following output in your terminal: + +```bash +Successfully initialized 4 node directories +``` + +The default output directory is a relative `.testnets` directory. Let's take a look at the files created within the `.testnets` directory. + +### gentxs + +The `gentxs` directory includes a genesis transaction for each validator node. Each file includes a JSON encoded genesis transaction used to register a validator node at the time of genesis. The genesis transactions are added to the `genesis.json` file within each node directory during the initilization process. + +### nodes + +A node directory is created for each validator node. Within each node directory is a `simd` directory. The `simd` directory is the home directory for each node, which includes the configuration and data files for that node (i.e. the same files included in the default `~/.simapp` directory when running a single node). + +## Start Testnet + +Now, let's take a look at the `start` subcommand. + +The `start` subcommand both initializes and starts an in-process test network. This is the fastest way to spin up a local test network for testing purposes. + +You can start the local test network by running the following command: + +```bash +simd testnet start +``` + +You should see something similar to the following: + +```bash +acquiring test network lock +preparing test network with chain-id "chain-mtoD9v" + + ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +++ THIS MNEMONIC IS FOR TESTING PURPOSES ONLY ++ +++ DO NOT USE IN PRODUCTION ++ +++ ++ +++ sustain know debris minute gate hybrid stereo custom ++ +++ divorce cross spoon machine latin vibrant term oblige ++ +++ moment beauty laundry repeat grab game bronze truly ++ ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + + +starting test network... +started test network +press the Enter Key to terminate +``` + +The first validator node is now running in-process, which means the test network will terminate once you either close the terminal window or you press the Enter key. In the output, the mnemonic phrase for the first validator node is provided for testing purposes. The validator node is using the same default addresses being used when initializing and starting a single node (no need to provide a `--node` flag). + +Check the status of the first validator node: + +``` +simd status +``` + +Import the key from the provided mnemonic: + +``` +simd keys add test --recover --keyring-backend test +``` + +Check the balance of the account address: + +``` +simd q bank balances [address] +``` + +Use this test account to manually test against the test network. + +## Testnet Options + +You can customize the configuration of the test network with flags. In order to see all flag options, append the `--help` flag to each command. diff --git a/docs/spec/fee_distribution/f1_fee_distr.pdf b/docs/spec/fee_distribution/f1_fee_distr.pdf new file mode 100644 index 0000000000..b999538695 Binary files /dev/null and b/docs/spec/fee_distribution/f1_fee_distr.pdf differ diff --git a/docs/spec/fee_distribution/f1_fee_distr.tex b/docs/spec/fee_distribution/f1_fee_distr.tex new file mode 100644 index 0000000000..b6bb6b3265 --- /dev/null +++ b/docs/spec/fee_distribution/f1_fee_distr.tex @@ -0,0 +1,245 @@ +\documentclass[]{article} +\usepackage{hyperref} + +%opening +\title{F1 Fee Distribution Draft-02} +\author{Dev Ojha} + +\begin{document} + +\maketitle + +\begin{abstract} + In a proof of stake blockchain, validators need to split the rewards gained from transaction fees each block. Furthermore, these fees must be fairly distributed to each of a validator's constituent delegators. They accrue this reward throughout the entire time they are delegated, and they have a special operation to withdraw accrued rewards. + + The F1 fee distribution scheme works for any algorithm to split funds between validators each block, with minimal iteration, and the only approximations being due to finite decimal precision. Per block there is a single iteration over the validator set, to enable reward algorithms that differ by validator. No iteration is required to delegate, or withdraw. The state usage is one state update per validator per block, and one state entry per active delegation. It can optionally handle arbitrary inflation schemes, and auto-bonding of rewards. +\end{abstract} + +\section{F1 Fee Distribution} + +\subsection{Context} +In a proof of stake blockchain, each validator has an associated stake. +Transaction fees get rewarded to validators based on the incentive scheme of the underlying proof of stake model. +The fee distribution problem occurs in proof of stake blockchains supporting delegation, as there is a need to distribute a validator's fee rewards to its delegators. +The trivial solution of just giving the rewards to each delegator every block is too expensive to perform on-chain. +So instead fee distribution algorithms have delegators perform a withdraw action, which when performed yields the same total amount of fees as if they had received them at every block. + +This details F1, an approximation-free, slash-tolerant fee distribution algorithm which allows validator commission-rates, inflation rates, and fee proportions, which can all efficiently change per validator, every block. +The algorithm requires iterating over the bonded validators every block, and withdraws require no iteration. +This is cheap, due to staking logic already requiring iteration over all validators, which causes the expensive state-reads to be cached. + +The key point of how F1 works is that it tracks how much rewards a delegator with 1 stake for a given validator would be entitled to if it had bonded at block 0 until the latest block. +When a delegator bonds at block $b$, the amount of rewards a delegator with 1 stake would have if bonded at block 0 until block $b$ is also persisted to state. +When the delegator withdraws, they receive the difference of these two values. +Since rewards are distributed according to stake-weighting, this amount of rewards can be scaled by the amount of stake a delegator had. +Section 1.2 describes this in more detail, with an argument for it being approximation free. +Section 2 details how to adapt this algorithm to handle commission rates, slashing, and inflation. + +\subsection{Base algorithm} +In this section, we show that the F1 base algorithm gives each delegator rewards identical to that which they'd receive in the naive and correct fee distribution algorithm that iterated over all delegators every block. + +Even distribution of a validators rewards amongst its validators weighted by stake means the following: +Suppose a delegator delegates $x$ stake to a validator $v$ at block $h$. +Let the amount of stake the validator has at block $i$ be $s_i$ and the amount of fees they receive at this height be $f_i$. +Then if a delegator contributing $x$ stake decides to withdraw at block $n$, the rewards they receive are +$$\sum_{i = h}^{n} \frac{x}{s_i}f_i = x \sum_{i = h}^{n} \frac{f_i}{s_i}$$ + +Note that $s_i$ does not change every block, +it only changes if the validator gets slashed, +or if any delegator alters the amount they have delegated. +We'll relegate handling of slashes to \autoref{ssec:slashing}, +and only consider the case with no slashing here. +We can change the iteration from being over every block, to instead being over the set of blocks between two changes in validator $v$'s total stake. +Let each of these set of blocks be called a period. +A new period begins every time that validator's total stake changes. +Let the total amount of stake for the validator in period $p$ be $n_p$. +Let $T_p$ be the total fees that validator $v$ accrued in period $p$. +Let $h$ be the start of period $p_{init}$, and height $n$ be the end of $p_{final}$. +It follows that +$$x \sum_{i = h}^{n} \frac{f_i}{s_i} = x \sum_{p = p_{init}}^{p_{final}} \frac{T_p}{n_p}$$ + +Let $p_0$ represent the period which begins when the validator first bonds. +The central idea to the F1 model is that at the end of the $k$th period, +the following is stored at a state location indexable by $k$: $\sum_{i=0}^{k}\frac{T_i}{n_i}$. +Let the index of the current period be $f$. +When a delegator wants to delegate or withdraw their reward, they first create a new entry in state to end the current period. +Then this entry is created using the previous entry as follows: +$$Entry_f = \sum_{i=0}^{f}\frac{T_i}{n_i} = \sum_{i=0}^{f-1}\frac{T_i}{n_i} + \frac{T_f}{n_f} = Entry_{f-1} + \frac{T_f}{n_f}$$ +Where $T_f$ is the fees the validator has accrued in period $f$, and $n_f$ is the validators total amount of stake in period $f$. + +The withdrawer's delegation object has the index $k$ for the period which they ended by bonding. (They start receiving rewards for period $k + 1$) +The reward they should receive when withdrawing is: + +$$x \sum_{i = k + 1}^{f} \frac{T_i}{n_i} = x\left(\left(\sum_{i=0}^{f}\frac{T_i}{n_i}\right) - \left(\sum_{i=0}^{k}\frac{T_i}{n_i}\right)\right) = x\left(Entry_f - Entry_k\right)$$ + +It is clear from the equations that this payout mechanism maintains correctness, and requires no iterations. It just needed the two state reads for these entries. + +$T_f$ is a separate variable in state for the amount of fees this validator has accrued since the last update to its power. +This variable is incremented at every block by however much fees this validator received that block. +On the update to the validators power, this variable is used to create the entry in state at $f$, and is then reset to 0. + +This fee distribution proposal is agnostic to how all of the blocks fees are divied up between validators. +This creates many nice properties, for example it is possible to only rewarding validators who signed that block. + +\section{Additional add-ons} +\subsection{Commission Rates} +Commission rates are the idea that a validator can take a fixed $x\%$ cut of all of their received fees, before redistributing evenly to the constituent delegators. +This can easily be done as follows: + +In block $h$ a validator receives $f_h$ fees. +Instead of incrementing that validators ``total accrued fees this period variable" by $f_h$, it is instead incremented by $(1 - commission\_rate) * f_p$. +Then $commission\_rate * f_p$ is deposited directly to the validator's account. +This allows for efficient updates to a validator's commission rate every block if desired. +More generally, each validator could have a function which takes their fees as input, and outputs a set of outputs to pay these fees too. (i.e. x\% going to themselves, y\% to delegators, z\% burnt) + +\subsection{Slashing} +\label{ssec:slashing} +Slashing is distinct from withdrawals, since it lowers the stake of all of the delegator's by a fixed percentage. +Since no one is charged gas for slashes, a slash cannot iterate over all delegators. +Thus we can no longer just multiply by $x$ over the difference in stake. +This section describes a simple solution that should suffice for most chains needs. An asymptotically optimal solution is provided in section 2.4. +TODO: Consider removing this section in favor of just using the current section 2.4? + +The solution here is to instead store each period created by a slash in the validators state. +Then when withdrawing, you must iterate over all slashes between when you started and ended. +Suppose you delegated at period $0$, a y\% slash occured at period $2$, and your withdrawal creates period $4$. +Then you receive funds from periods $0$ to $2$ as normal. +The equations for funds you receive for periods $2$ to $4$ now uses $(1 - y)x$ for your stake instead of just $x$ stake. +When there are multiple slashes, you just account for the accumulated slash factor. + +In practice this will not really be an efficiency hit, as the number of slashes is expected to be 0 or 1 for most validators. +Validators that get slashed more will naturally lose their delegators. +A malicious validator that gets itself slashed many times would increase the gas to withdraw linearly, but the economic loss of funds due to the slashes is expected to far out-weigh the extra overhead the honest withdrawer must pay for due to the gas. +(TODO: frame that above sentence in terms of griefing factors, as thats more correct) + +\subsection{Inflation} +Inflation is the idea that we want every staked coin to create more staking tokens as time progresses. +The purpose being to drive down the relative worth of unstaked tokens. +Each block, every staked token should produce $x$ staking tokens as inflation, where $x$ is calculated from a function $inflation$ which takes state and the block information as input. +Let $x_i$ represent the evaluation of $inflation$ in the $i$th block. +The goal of this section is to auto-bond inflation in the fee distribution model without iteration. +This is done by preserving the invariant that every state entry contains the rewards one would have if they had bonded one stake at genesis until that corresponding block. + +In state a variable should be kept for the number of tokens one would have now due to inflation, +given that they bonded one token at genesis. +This is $\prod_{0}^{now} (1 + x_i)$. +Each period now stores this total inflation product along with what it already stores per-period. + +Let $R_i$ be the fee rewards in block $i$, and $n_i$ be the total amount bonded to that validator in that block. +The correct amount of rewards which 1 token at genesis should have now is: +$$Reward(now) = \sum_{i = 0}^{now}\left(\prod_{j = 0}^{i} 1 + x_j \right) * \frac{R_i}{n_i}$$ +The term in the sum is the amount of stake one stake becomes due to inflation, multiplied by the amount of fees per stake. + +Now we cast this into the period frame of view. +Recall that we build the rewards by creating a state entry for the rewards of the previous period, and keeping track of the rewards within this period. +Thus we first define the correct amount of rewards for each successive period, proving correctness of this via induction. +We then show that the state entry that gets efficiently built up block by block is equal to this value for the latest period. + +Let $start, end$ denote the start/end of a period. + +Suppose that $\forall f > 0$, $Reward(end(f))$ is correctly constructed as +$$Reward(end(f)) = Reward(end(f-1)) + \sum_{i = start(f)}^{end(f)}\left(\prod_{j = 0}^{i} 1 + x_j \right) \frac{R_i}{n_i}$$ +and that for $f = 0$, $Reward(end(0)) = 0$. +(With period 1 being defined as the period that has the first bond into it) +It must be shown that assuming the supposition $\forall f \leq f_0$, $$Reward(end(f_0 + 1)) = Reward(end(f_0)) + \sum_{i = start(f_0 + 1)}^{end(f_0 + 1)}\left(\prod_{j = 0}^{i} 1 + x_j \right) \frac{R_i}{n_i}$$ +Using the definition of $Reward$, it follows that: +$$\sum_{i = 0}^{end(f_0 + 1)}\left(\prod_{j = 0}^{i} 1 + x_j \right) * \frac{R_i}{n_i} = \sum_{i = 0}^{end(f_0)}\left(\prod_{j = 0}^{i} 1 + x_j \right) * \frac{R_i}{n_i} + \sum_{i = start(f_0 + 1)}^{end(f_0 + 1)}\left(\prod_{j = 0}^{i} 1 + x_j \right) \frac{R_i}{n_i}$$ + +Since the first summation on the right hand side is $Reward(end(f_0))$, the supposition is proven true. +Consequently, the reward for just period $f$ adjusted for the amount of inflation 1 token at genesis would produce, is: +$$\sum_{i = start(f)}^{end(f)}\left(\prod_{j = 0}^{i} 1 + x_j \right) \frac{R_i}{n_i}$$ + +TODO: make this proof + pre-amble less verbose, and just wrap up into a lemma. +Maybe just leave this proof or the last part to the reader, since it easily follows from summation bounds. + +Now note that +$$\sum_{i = start(f)}^{end(f)}\left(\prod_{j = 0}^{i} 1 + x_j \right) \frac{R_i}{n_i} = \left(\prod_{j = 0}^{end(f - 1)} 1 + x_j \right)\sum_{i = start(f)}^{end(f)}\left(\prod_{j = start(f)}^{i} 1 + x_j \right) \frac{R_i}{n_i}$$ +By definition of period, and inflation being applied every block, \\ +$n_i = n_{start(f)}\left(\prod_{j = start(f)}^{i} 1 + x_j \right)$. This cancels out the product in the summation, therefore +$$\sum_{i = start(f)}^{end(f)}\left(\prod_{j = 0}^{i} 1 + x_j \right) \frac{R_i}{n_i} = \left(\prod_{j = 0}^{end(f - 1)} 1 + x_j \right)\frac{\sum_{i = start(f)}^{end(f)}R_i}{n_{start(f)}}$$ + +Thus every block, each validator just has to add the total amount of fees (The $R_i$ term) that goes to delegates to some per-period term. +When creating a new period, $n_{start(f)}$ can be cached in state, and the product is already stored in the previous periods state entry. +You then get the next period's $n_{start(f)}$ from the consensus' power entry for this validator. +This is thus extremely efficient per block. + +When withdrawing, you take the difference as before, +which yields the amount of rewards you would have obtained with $(\prod_0^{begin\ bonding\ period}1 + x)$ stake from the block you began bonding at until now. +$(\prod_0^{begin\ bonding\ period}1 + x)$ is known, since its included in the state entry for when you bonded. +You then divide the entitled fees by $(\prod_0^{begin\ bonding\ period}1 + x)$ to normalize it to being the amount of rewards you're entitled to from 1 stake at that block to now. +Then as before, you multiply by the amount of stake you had initially bonded. +\\TODO: (Does the difference equating to that make sense, or should it be shown explicitly) +\\TODO: Does this need to explain how the originally bonded tokens are refunded, or is that clear? + +The inflation function could vary per block, +and per validator if ever a need rose. +If the inflation rate is the same for everyone then there can be a single global store for the entries corresponding to the product of inflations. +Inflation creation can trivially be epoched as long as inflation isn't required within the epoch, through changes to the $inflation$ function. + +\subsection{Withdrawing with no iteration over slashes} +Notice that a slash is the same as a negative inflation rate for a validator in one block. +For example a $20\%$ slash is equivalent to a $-20\%$ inflation for a validator in a block. +Given correctness of auto-bonding inflation with different inflation rates per-validator, +it follows that handling slashes can be correctly done by simply subtracting the validators inflation factor in that block to be the negative of the slash factor. +This significantly simplifies the withdrawal procedure. + +\subsection{Auto bonding fees} +TODO: Fill this out. +Core idea: you use the same mechanism as previously, but you just don't take that optimization with $n_{i}$ and the $n_{start}$ relation. +Fairly simple to do. + +\subsection{Delegation updates} +Updating your delegation amount is equivalent to withdrawing earned rewards and a fully independent new delegation occurring in the same block. +The same applies for redelegation. +From the view of fee distribution, partial redelegation is the same as a delegation update + a new delegation. + +\subsection{Jailing / being kicked out of the validator set} +This basically requires no change. +In each block you only iterate over the currently bonded validators. +So you simply don't update the "total accrued fees this period" variable for jailed / non-bonded validators. +Withdrawing requires \textit{no} special casing here! + +\section{State Requirements} +State entries can be pruned quite effectively. +Suppose for the sake of exposition that there is at most one delegation / withdrawal to a particular validator in any given block. +Then each delegation is responsible for one addition to state. +Only the next period, and this delegator's withdrawal could depend on this entry. Thus once this delegator withdraws, this state entry can be pruned. +For the entry created by the delegator's withdrawal, that is only required by the creation of the next period. +Thus once the next period is created, that withdrawal's period can be deleted. + +This can be easily adapted to the case where there are multiple delegations / withdrawals per block, by maintaining a reference count in each period starting state entry. + +The slash entries for a validator can only be pruned when all of that validator's delegators have their bonding period starting after the slash. +This seems ineffective to keep track of, thus it is not worth it. +Each slash should instead remain in state until the validator unbonds and all delegators have their fees withdrawn. + +\section{Implementers Considerations} +TODO: Convert this section into a proper conclusion + +This is an extremely simple scheme with many nice benefits. +\begin{itemize} + \item The overhead per block is a simple iteration over the bonded validator set, which occurs anyway. (Thus it can be implemented ``for-free" with an optimized code-base) + \item Withdrawing earned fees only requires iterating over slashes since when you bonded. (Which is a negligible iteration) + \item There are no approximations in any of the calculations. (modulo minor errata resulting from fixed precision decimals used in divisions) + \item Supports arbitrary inflation models. (Thus could even vary upon block signers) + \item Supports arbitrary fee distribution amongst the validator set. (Thus can account for things like only online validators get fees, which has important incentivization impacts) + \item The above two can change on a live chain with no issues. + \item Validator commission rates can be changed every block + \item The simplicity of this scheme lends itself well to implementation +\end{itemize} + +Thus this scheme has efficiency improvements, simplicity improvements, and expressiveness improvements over the currently proposed schemes. With a correct fee distribution amongst the validator set, this solves the existing problem where one could withhold their signature for risk-free gain. + +\section{TO DOs} + +\begin{itemize} + \item A global fee pool can be described. + \item Mention storage optimization for how to prune slashing entries in the uniform inflation and iteration over slashing case + \item Add equation numbers + \item perhaps re-organize so that the no iteration + \item Section on decimal precision considerations (would unums help?), and mitigating errors in calculation with floats and decimals. -- This probably belongs in a corrollary markdown file in the implementation + \item Consider indicating that the withdraw action need not be a tx type and could instead happen 'transparently' when more coins are needed, if a chain desired this for UX / p2p efficiency. +\end{itemize} + + +\end{document} diff --git a/docs/uml/puml/begin_redelegation_sequence.puml b/docs/uml/puml/begin_redelegation_sequence.puml new file mode 100644 index 0000000000..315f063f46 --- /dev/null +++ b/docs/uml/puml/begin_redelegation_sequence.puml @@ -0,0 +1,50 @@ +@startuml +'https://plantuml.com/sequence-diagram + +title: Redelegation + +msgServer -> keeper : BeginRedelegation(delAddr, valSrcAddr, valDstAddr, sharesAmount) +participant "keeper (staking)" as keeper +keeper -> keeper : get number of sharew +note left: If the delegator has more shares than the total shares in the validator\n(due to rounding errors), then just withdraw the max number of shares. +keeper -> keeper : check the redelegation uses correct denom + +alt valSrcAddr == valDstAddr + keeper --> msgServer : error +end +alt transitive redelegation + keeper --> msgServer : error +end +alt already has max redelegations + keeper --> msgServer : error + note left : this is the number of redelegations for a specific (del, valSrc, valDst) triple\ndefault : 7 +end + + +keeper -> keeper : Unbond(del, valSrc) returns returnAmount +... +note left : See unbonding diagram + +alt returnAmount is zero +keeper -> msgServer : error +end + +keeper -> keeper : Delegate(del, returnAmount, status := valSrc.status, valDst, subtractAccount := false) +note left : See delegation diagram +... + +alt validator is unbonded + keeper -> msgServer : current time +end + +alt unbonding not complete, or just started + database store + keeper -> store : create redelegation object + keeper -> store : insert redelegation in queue, to be processed at the appropriate time +end + +msgServer <-- keeper : completion time of the redelegation +msgServer -> msgServer : emit event: delegator, valSrc, valSrc,\nsharesAmount, completionTime + +@enduml + diff --git a/docs/uml/puml/delegation_sequence.puml b/docs/uml/puml/delegation_sequence.puml new file mode 100644 index 0000000000..ad0286476b --- /dev/null +++ b/docs/uml/puml/delegation_sequence.puml @@ -0,0 +1,93 @@ +@startuml +'https://plantuml.com/sequence-diagram + +title: Delegating (currently undelegated funds delegator) + +participant "msgServer (staking)" +participant "keeper (staking)" as keeper +participant validator +participant keeper.bankKeeper +participant vestingAccount +participant ctx.EventManager + +database store + +"msgServer (staking)" -> keeper : Delegate(Context, DelegatorAddress, Amount, Validator, tokenSrc := Unbonded) + +alt exchange rate is invalid (tokens in validator is 0) + keeper --> "msgServer (staking)" : error +end + +alt perform a new delegation + keeper -> keeper : delegation := create delegation object + keeper -> keeper : BeforeDelegationCreated hook + note left: Calls IncrementValidatorPeriod (Used to calculate distribution) in keeper/validator.go +else delegation exists, more tokens being added + keeper -> keeper : BeforeDelegationModified hook + note left: withdraw current delegation rewards (and increment period) +end + +alt delegating from an account (subtractTokens == true) + keeper -> keeper.bankKeeper : DelegateCoinsFromAccountToModule + group DelegateCoinsFromAccountToModule function + keeper.bankKeeper -> keeper.bankKeeper : DelegateCoinsFromAccountToModule + keeper.bankKeeper -> keeper.bankKeeper : DelegateCoins + group DelegateCoins function + keeper.bankKeeper --> keeper.bankKeeper : Check the delegator has enough balances of all tokens delegated + keeper.bankKeeper --> keeper.bankKeeper : Track delegation (register that it exists to keep track of it) + alt validator is currently bonded + keeper.bankKeeper --> store : Transfer tokens from delegator to BondedTokensPool. + else validator is currently unbonded or unbonding + keeper.bankKeeper --> store : Transfer tokens from delegator to NotBondedTokensPool. + end + group trackDelegation function + keeper.bankKeeper -> keeper.bankKeeper : trackDelegation + alt delegator is a vesting account + keeper.bankKeeper -> vestingAccount : keep track of this delegation + end + end + end + end + keeper <-- keeper.bankKeeper : nil (success) +else moving tokens between pools (subtractTokens == false) + alt delegator tokens are not bonded but validator is bonded + keeper -> keeper.bankKeeper : SendCoinsFromModuleToModule(notBondedPool, bondedPool, coins) + else delegator tokens are bonded but validator is not bonded + keeper -> keeper.bankKeeper : SendCoinsFromModuleToModule(bondedPool, notBondedPool, coins) + end + group SendCoins function + keeper.bankKeeper -> keeper.bankKeeper : SendCoins + keeper.bankKeeper -> ctx.EventManager : Emit TransferEvent(to, from, amount) + alt amount of spendable (balance - locked) coins too low + keeper <-- keeper.bankKeeper : error + end + keeper.bankKeeper -> store : subtract balance from sender + keeper.bankKeeper -> store : add balance to recipient + end +end + +keeper -> validator : AddTokensFromDel +validator -> validator : calculate number of shares to issue +note left: If there are no shares (validator being created) then 1 token = 1 share.\nIf there are already shares, then\nadded shares = (added tokens amount) * (current validator shares) / (current validator tokens) + +validator -> validator : add delegated tokens to validator +keeper <-- validator : validator, addedShares +keeper -> store : update validator state +keeper -> keeper: calculate new validator's power +note left : Number of tokens divided by PowerReduction (default: 1,000,000,000,000,000,000 = 10^18) +alt validator is not jailed + keeper -> store : update validator's power in power index + note left : the power index has entries shaped as 35 || power || address.\nThis makes the validators sorted by power, high to low. +end + +keeper -> keeper : AfterDelegationModified hook +note left: Calls initializeDelegation\nStore the previous period\nCalculate the number of tokens from shares\n(shares the delegator has) * (tokens in delegation object)/(total tokens delegated to the validator)\nStore delegation starting info. +"msgServer (staking)" <-- keeper : newShares (ignored by Delegate function) + + +"msgServer (staking)" -> "msgServer (staking)" : Emit event: Delegation(ValidatorAddress) +"msgServer (staking)" -> "msgServer (staking)" : Emit event: Message(DelegatorAddress) +"msgServer (staking)" -> "msgServer (staking)" : telemetry(Amount, Denom) + +@enduml + diff --git a/docs/uml/puml/keeper_dependencies.puml b/docs/uml/puml/keeper_dependencies.puml new file mode 100644 index 0000000000..5a80ad9f33 --- /dev/null +++ b/docs/uml/puml/keeper_dependencies.puml @@ -0,0 +1,36 @@ +@startuml +'https://plantuml.com/class-diagram + +title: The dependencies between Keepers (Feb 2021) + +abstract class Staking +abstract class Distribution +abstract class Slashing +abstract class Evidence +abstract class Bank +abstract class "Auth/Account" as Auth +abstract class Gov +abstract class Mint + +Staking <|-- Mint +Bank <|-- Mint + +Staking <|-- Gov +Bank <|-- Gov +Auth <|-- Gov + +Auth <|-- Bank + +Bank <|-- Distribution +Auth <|-- Distribution +Staking <|-- Distribution + +Staking <|-- Evidence +Slashing <|-- Evidence + +Staking <|-- Slashing + +Auth <|-- Staking +Bank <|-- Staking + +@enduml diff --git a/docs/uml/puml/transaction_flow.puml b/docs/uml/puml/transaction_flow.puml new file mode 100644 index 0000000000..d9b6cbcf62 --- /dev/null +++ b/docs/uml/puml/transaction_flow.puml @@ -0,0 +1,20 @@ +@startuml +'https://plantuml.com/sequence-diagram + +actor User +User -> baseApp : Transaction Type +baseApp -> router : Route(ctx, msgRoute) +router --> baseApp : handler +baseApp -> handler: Msg(Context, Msg(...)) +handler -> msgServer : (Context, Msg) +alt addresses invalid, denominations wrong, etc. +msgServer --> handler : error +end +msgServer -> keeper : perform action, update context +keeper --> msgServer : results, error code +msgServer -> Context.EventManager : Emit relevant events +msgServer -> msgServer : maybe wrap results in more structure +msgServer --> handler : result, error code +baseApp <-- handler : results, error code + +@enduml diff --git a/docs/uml/puml/unbond_sequence.puml b/docs/uml/puml/unbond_sequence.puml new file mode 100644 index 0000000000..bfe385b42b --- /dev/null +++ b/docs/uml/puml/unbond_sequence.puml @@ -0,0 +1,51 @@ +@startuml +'https://plantuml.com/sequence-diagram + +title: Undelegate + +msgServer -> keeper : Undelegate(delAddr, valAddr, tokenAmount) + +keeper -> keeper : calculate number of shares the tokenAmount represents + +alt wrong denom + msgServer <-- keeper : error +end + +group Unbond(delAddr, valAddr, shares) + keeper -> keeper: BeforeDelegationSharesModified hook + alt no such delegation + keeper --> msgServer : error + end + alt not enough shares + keeper --> msgServer : error + end + alt delegator is the operator of the validator\nand validator is not already jailed\nand unbonding would put self-delegation under min threshold + keeper -> keeper : jail the validator, but proceed with unbonding + note left : Default min delegation threshold : 1 share + end + + database store + + alt complete unbonding, all shares removed + keeper -> store : remove delegation object + else there are still shares delegated (not a complete undbonding) + keeper -> store : update delegation object + keeper -> keeper : AfterDelegationModified hook + end + + keeper -> store : update validator power index + keeper -> store : update validator information (including token amount) + + alt validator status is "unbonded" and it has no more tokens + keeper -> store : delete the validator + note right : otherwise, do this in EndBlock once validator is unbonded + end +end + +alt validator is bonded + keeper -> bankKeeper : send tokens from bonded pool to not bonded pool +end + +msgServer -> msgServer : emit event : EventTypeUnbond(delAddr, valAddr, tokenAmount, completion time) + +@enduml diff --git a/docs/uml/svg/begin_redelegation_sequence.svg b/docs/uml/svg/begin_redelegation_sequence.svg new file mode 100644 index 0000000000..5d17f311b9 --- /dev/null +++ b/docs/uml/svg/begin_redelegation_sequence.svg @@ -0,0 +1,106 @@ +RedelegationmsgServermsgServerkeeperkeeperstorestoreBeginRedelegation(delAddr, valSrcAddr, valDstAddr, sharesAmount)get number of sharewIf the delegator has more shares than the total shares in the validator(due to rounding errors), then just withdraw the max number of shares.check the redelegation uses correct denomalt[valSrcAddr == valDstAddr]erroralt[transitive redelegation]erroralt[already has max redelegations]errorthis is the number of redelegations for a specific (del, valSrc, valDst) tripledefault : 7Unbond(del, valSrc) returns returnAmountSee unbonding diagramalt[returnAmount is zero]errorDelegate(del, returnAmount, status := valSrc.status, valDst, subtractAccount := false)See delegation diagramalt[validator is unbonded]current timealt[unbonding not complete, or just started]create redelegation objectinsert redelegation in queue, to be processed at the appropriate timecompletion time of the redelegationemit event: delegator, valSrc, valSrc,sharesAmount, completionTime \ No newline at end of file diff --git a/docs/uml/svg/delegation_sequence.svg b/docs/uml/svg/delegation_sequence.svg new file mode 100644 index 0000000000..47ad53789d --- /dev/null +++ b/docs/uml/svg/delegation_sequence.svg @@ -0,0 +1,192 @@ +Delegating (currently undelegated funds delegator)msgServer (staking)msgServer (staking)keeper (staking)keeper (staking)validatorvalidatorkeeper.bankKeeperkeeper.bankKeepervestingAccountvestingAccountctx.EventManagerctx.EventManagerstorestoreDelegate(Context, DelegatorAddress, Amount, Validator, tokenSrc := Unbonded)alt[exchange rate is invalid (tokens in validator is 0)]erroralt[perform a new delegation]delegation := create delegation objectBeforeDelegationCreated hookCalls IncrementValidatorPeriod (Used to calculate distribution) in keeper/validator.go[delegation exists, more tokens being added]BeforeDelegationModified hookwithdraw current delegation rewards (and increment period)alt[delegating from an account (subtractTokens == true)]DelegateCoinsFromAccountToModuleDelegateCoinsFromAccountToModule functionDelegateCoinsFromAccountToModuleDelegateCoinsDelegateCoins functionCheck the delegator has enough balances of all tokens delegatedTrack delegation (register that it exists to keep track of it)alt[validator is currently bonded]Transfer tokens from delegator to BondedTokensPool.[validator is currently unbonded or unbonding]Transfer tokens from delegator to NotBondedTokensPool.trackDelegation functiontrackDelegationalt[delegator is a vesting account]keep track of this delegationnil (success)[moving tokens between pools (subtractTokens == false)]alt[delegator tokens are not bonded but validator is bonded]SendCoinsFromModuleToModule(notBondedPool, bondedPool, coins)[delegator tokens are bonded but validator is not bonded]SendCoinsFromModuleToModule(bondedPool, notBondedPool, coins)SendCoins functionSendCoinsEmit TransferEvent(to, from, amount)alt[amount of spendable (balance - locked) coins too low]errorsubtract balance from senderadd balance to recipientAddTokensFromDelcalculate number of shares to issueIf there are no shares (validator being created) then 1 token = 1 share.If there are already shares, thenadded shares = (added tokens amount) * (current validator shares) / (current validator tokens)add delegated tokens to validatorvalidator, addedSharesupdate validator statecalculate new validator's powerNumber of tokens divided by PowerReduction (default: 1,000,000,000,000,000,000 = 10^18)alt[validator is not jailed]update validator's power in power indexthe power index has entries shaped as 35 || power || address.This makes the validators sorted by power, high to low.AfterDelegationModified hookCalls initializeDelegationStore the previous periodCalculate the number of tokens from shares(shares the delegator has) * (tokens in delegation object)/(total tokens delegated to the validator)Store delegation starting info.newShares (ignored by Delegate function)Emit event: Delegation(ValidatorAddress)Emit event: Message(DelegatorAddress)telemetry(Amount, Denom) \ No newline at end of file diff --git a/docs/uml/svg/keeper_dependencies.svg b/docs/uml/svg/keeper_dependencies.svg new file mode 100644 index 0000000000..bac9328e3d --- /dev/null +++ b/docs/uml/svg/keeper_dependencies.svg @@ -0,0 +1,102 @@ +The dependencies between Keepers (Feb 2021)StakingDistributionSlashingEvidenceBankAuth/AccountGovMint \ No newline at end of file diff --git a/docs/uml/svg/transaction_flow.svg b/docs/uml/svg/transaction_flow.svg new file mode 100644 index 0000000000..1ae962de34 --- /dev/null +++ b/docs/uml/svg/transaction_flow.svg @@ -0,0 +1,48 @@ +UserUserbaseAppbaseApprouterrouterhandlerhandlermsgServermsgServerkeeperkeeperContext.EventManagerContext.EventManagerTransaction Type<Tx>Route(ctx, msgRoute)handlerMsg<Tx>(Context, Msg(...))<Tx>(Context, Msg)alt[addresses invalid, denominations wrong, etc.]errorperform action, update contextresults, error codeEmit relevant eventsmaybe wrap results in more structureresult, error coderesults, error code \ No newline at end of file diff --git a/docs/uml/svg/unbond_sequence.svg b/docs/uml/svg/unbond_sequence.svg new file mode 100644 index 0000000000..7219f200a5 --- /dev/null +++ b/docs/uml/svg/unbond_sequence.svg @@ -0,0 +1,110 @@ +UndelegatemsgServermsgServerkeeperkeeperstorestorebankKeeperbankKeeperUndelegate(delAddr, valAddr, tokenAmount)calculate number of shares the tokenAmount representsalt[wrong denom]errorUnbond(delAddr, valAddr, shares)BeforeDelegationSharesModified hookalt[no such delegation]erroralt[not enough shares]erroralt[delegator is the operator of the validatorand validator is not already jailedand unbonding would put self-delegation under min threshold]jail the validator, but proceed with unbondingDefault min delegation threshold : 1 sharealt[complete unbonding, all shares removed]remove delegation object[there are still shares delegated (not a complete undbonding)]update delegation objectAfterDelegationModified hookupdate validator power indexupdate validator information (including token amount)alt[validator status is "unbonded" and it has no more tokens]delete the validatorotherwise, do this in EndBlock once validator is unbondedalt[validator is bonded]send tokens from bonded pool to not bonded poolemit event : EventTypeUnbond(delAddr, valAddr, tokenAmount, completion time) \ No newline at end of file diff --git a/go.mod b/go.mod index e0cc5126ab..7c3d28ee77 100644 --- a/go.mod +++ b/go.mod @@ -4,31 +4,34 @@ module github.com/line/lbm-sdk require ( github.com/99designs/keyring v1.1.6 - github.com/DataDog/zstd v1.4.5 // indirect github.com/VictoriaMetrics/fastcache v1.9.0 github.com/armon/go-metrics v0.3.10 github.com/bgentry/speakeasy v0.1.0 github.com/btcsuite/btcd v0.22.0-beta + github.com/coinbase/rosetta-sdk-go v0.7.0 github.com/confio/ics23/go v0.6.6 github.com/coocood/freecache v1.2.0 github.com/cosmos/btcutil v1.0.4 github.com/cosmos/go-bip39 v1.0.0 github.com/cosmos/ledger-cosmos-go v0.11.1 github.com/dgraph-io/ristretto v0.1.0 - github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 // indirect github.com/dvsekhvalnov/jose2go v0.0.0-20200901110807-248326c1351b - github.com/go-kit/kit v0.10.0 + github.com/go-kit/kit v0.12.0 github.com/gogo/gateway v1.1.0 github.com/gogo/protobuf v1.3.3 github.com/golang/mock v1.6.0 github.com/golang/protobuf v1.5.2 - github.com/google/gofuzz v1.2.0 + github.com/google/gofuzz v1.1.1-0.20200604201612-c04b05f3adfa github.com/gorilla/handlers v1.5.1 github.com/gorilla/mux v1.8.0 github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 github.com/grpc-ecosystem/grpc-gateway v1.16.0 + github.com/hdevalence/ed25519consensus v0.0.0-20220222234857-c00d1f31bab3 + github.com/improbable-eng/grpc-web v0.15.0 + github.com/jhump/protoreflect v1.10.3 + github.com/lib/pq v1.10.4 // indirect github.com/line/iavl/v2 v2.0.0-init.1.0.20220215225951-cb11c91d8857 - github.com/line/ostracon v1.0.3 + github.com/line/ostracon v1.0.4 github.com/line/tm-db/v2 v2.0.0-init.1.0.20220121012851-61d2bc1d9486 github.com/line/wasmvm v0.16.3-0.9.0 github.com/magiconair/properties v1.8.5 @@ -50,9 +53,10 @@ require ( github.com/tendermint/btcd v0.1.1 github.com/tendermint/crypto v0.0.0-20191022145703-50d29ede1e15 github.com/tendermint/go-amino v0.16.0 - golang.org/x/crypto v0.0.0-20211215165025-cf75a172585e + golang.org/x/crypto v0.0.0-20220112180741-5e0467b6c7ce + golang.org/x/net v0.0.0-20220225172249-27dd8689420f // indirect google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa - google.golang.org/grpc v1.43.0 + google.golang.org/grpc v1.44.0 google.golang.org/protobuf v1.27.1 gopkg.in/yaml.v2 v2.4.0 ) diff --git a/go.sum b/go.sum index 708737863a..5d14198a52 100644 --- a/go.sum +++ b/go.sum @@ -1,3 +1,4 @@ +bazil.org/fuse v0.0.0-20160811212531-371fbbdaa898/go.mod h1:Xbm+BRKSBEpa4q4hTSxohYNQpsxXPbPry4JJWOB3LB8= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= @@ -46,7 +47,24 @@ cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohl cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= -gioui.org v0.0.0-20210308172011-57750fc8a0a6/go.mod h1:RSH6KIUZ0p2xy5zHDxgAM4zumjgTw83q2ge/PI+yyw8= +filippo.io/edwards25519 v1.0.0-rc.1 h1:m0VOOB23frXZvAOK44usCgLWvtsxIoMCTBGJZlpmGfU= +filippo.io/edwards25519 v1.0.0-rc.1/go.mod h1:N1IkdkCkiLB6tki+MYJoSx2JTY9NUlxZE7eHn5EwJns= +github.com/Azure/azure-pipeline-go v0.2.1/go.mod h1:UGSo8XybXnIGZ3epmeBw7Jdz+HiUVpqIlpz/HKHylF4= +github.com/Azure/azure-pipeline-go v0.2.2/go.mod h1:4rQ/NZncSvGqNkkOsNpOU1tgoNuIlp9AfUH5G1tvCHc= +github.com/Azure/azure-storage-blob-go v0.7.0/go.mod h1:f9YQKtsG1nMisotuTPpO0tjNuEjKRYAcJU8/ydDI++4= +github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= +github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8= +github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= +github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI= +github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0= +github.com/Azure/go-autorest/autorest/adal v0.8.0/go.mod h1:Z6vX6WXXuyieHAXwMj0S6HY6e6wcHn37qQMBQlvY3lc= +github.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA= +github.com/Azure/go-autorest/autorest/date v0.2.0/go.mod h1:vcORJHLJEh643/Ioh9+vPmf1Ij9AEBM5FuBIXLmIy0g= +github.com/Azure/go-autorest/autorest/mocks v0.1.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= +github.com/Azure/go-autorest/autorest/mocks v0.2.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= +github.com/Azure/go-autorest/autorest/mocks v0.3.0/go.mod h1:a8FDP3DYzQ4RYfVAxAN3SVSiiO77gL2j2ronKKP0syM= +github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc= +github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk= 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/ChainSafe/go-schnorrkel v0.0.0-20200405005733-88cbf1b4c40d h1:nalkkPQcITbvhmL4+C4cKA87NW0tfm3Kl9VXRoPywFg= @@ -55,11 +73,20 @@ github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3 github.com/DataDog/zstd v1.4.1/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= github.com/DataDog/zstd v1.4.5 h1:EndNeuB0l9syBZhut0wns3gV1hL8zX8LIu6ZiVHWLIQ= github.com/DataDog/zstd v1.4.5/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= +github.com/HdrHistogram/hdrhistogram-go v1.1.0/go.mod h1:yDgFjdqOqDEKOvasDdhWNXYg9BVp4O+o5f6V/ehm6Oo= +github.com/HdrHistogram/hdrhistogram-go v1.1.2/go.mod h1:yDgFjdqOqDEKOvasDdhWNXYg9BVp4O+o5f6V/ehm6Oo= github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= +github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA= +github.com/Microsoft/go-winio v0.5.0 h1:Elr9Wn+sGKPlkaBvwu4mTrxtmOp3F3yV9qhaHbXGjwU= +github.com/Microsoft/go-winio v0.5.0/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= +github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 h1:TngWCqHvy9oXAN6lEVMRuU21PR1EtLVZJmdB18Gu3Rw= +github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk= github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= +github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg= +github.com/VictoriaMetrics/fastcache v1.5.7/go.mod h1:ptDBkNMQI4RtmVo8VS/XwRY6RoTu1dAWCbrk+6WsEM8= github.com/VictoriaMetrics/fastcache v1.5.8/go.mod h1:SiMZNgwEPJ9qWLshu9tyuE6bKc9ZWYhcNV/L7jurprQ= github.com/VictoriaMetrics/fastcache v1.9.0 h1:oMwsS6c8abz98B7ytAewQ7M1ZN/Im/iwKoE1euaFvhs= github.com/VictoriaMetrics/fastcache v1.9.0/go.mod h1:otoTS3xu+6IzF/qByjqzjp3rTuzM3Qf0ScU1UTj97iU= @@ -67,6 +94,9 @@ github.com/VividCortex/gohistogram v1.0.0 h1:6+hBz+qvs0JOrrNhhmR7lFxo5sINxBCGXrd github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g= github.com/Workiva/go-datastructures v1.0.52 h1:PLSK6pwn8mYdaoaCZEMsXBpBotr4HHn9abU0yMQt0NI= github.com/Workiva/go-datastructures v1.0.52/go.mod h1:Z+F2Rca0qCsVYDS8z7bAGm8f3UkzuWYS/oBZz5a7VVA= +github.com/Zilliqa/gozilliqa-sdk v1.2.1-0.20201201074141-dd0ecada1be6/go.mod h1:eSYp2T6f0apnuW8TzhV3f6Aff2SE8Dwio++U4ha4yEM= +github.com/adlio/schema v1.1.13 h1:LeNMVg5Z1FX+Qgz8tJUijBLRdcpbFUElz+d1489On98= +github.com/adlio/schema v1.1.13/go.mod h1:L5Z7tw+7lRK1Fnpi/LT/ooCP1elkXn0krMWBQHUhEDE= github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII= github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c= github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw= @@ -80,32 +110,43 @@ github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156/go.mod h1:Cb/ax github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= github.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= +github.com/aristanetworks/goarista v0.0.0-20170210015632-ea17b1a17847/go.mod h1:D/tb0zPVXnP7fmsLZjtdUhSsumbK/ij54UXjjVgMGxQ= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= +github.com/armon/go-metrics v0.3.9/go.mod h1:4O98XIr/9W0sxpJ8UaYkvjk10Iff7SnFrb4QAOwNTFc= github.com/armon/go-metrics v0.3.10 h1:FR+drcQStOe+32sYyJYyZ7FIdgoGGBnwLl+flodp8Uo= github.com/armon/go-metrics v0.3.10/go.mod h1:4O98XIr/9W0sxpJ8UaYkvjk10Iff7SnFrb4QAOwNTFc= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A= github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU= +github.com/aws/aws-sdk-go v1.25.48/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/aws/aws-sdk-go v1.40.45/go.mod h1:585smgzpB/KqRA+K3y/NL/oYRqQvpNJYvLm+LY1U59Q= github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g= +github.com/aws/aws-sdk-go-v2 v1.9.1/go.mod h1:cK/D0BBs0b/oWPIcX/Z/obahJK1TT7IPVjy53i/mX/4= +github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.8.1/go.mod h1:CM+19rL1+4dFWnOQKwDc7H1KwXTz+h61oUSHyhV0b3o= +github.com/aws/smithy-go v1.8.0/go.mod h1:SObp3lf9smib00L/v3U2eAKG8FyQ7iLrJnQiAmR5n+E= +github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bgentry/speakeasy v0.1.0 h1:ByYyxL9InA1OWqxJqqp2A5pYHUrCiAL6K3J+LKSsQkY= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/bits-and-blooms/bitset v1.2.0/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA= github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84= -github.com/boombuler/barcode v1.0.0/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= +github.com/btcsuite/btcd v0.0.0-20171128150713-2e60448ffcc6/go.mod h1:Dmm/EzmjnCiweXmzRIAiUWCInVmPgjkzgv5k4tVyXiQ= github.com/btcsuite/btcd v0.0.0-20190115013929-ed77733ec07d/go.mod h1:d3C0AkH6BRcvO8T0UEPu53cnw4IbV63x1bEjildYhO0= +github.com/btcsuite/btcd v0.0.0-20190315201642-aa6e0f35703c/go.mod h1:DrZx5ec/dmnfpw9KyYoQyYo7d0KEvTkk/5M/vbZjAr8= github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ= github.com/btcsuite/btcd v0.21.0-beta/go.mod h1:ZSWyehm27aAuS9bvkATT+Xte3hjHZ+MRgMY/8NJ7K94= github.com/btcsuite/btcd v0.22.0-beta h1:LTDpDKUM5EeOFBPM8IXpinEcmZ6FWfNZbE3lfrfdnWo= github.com/btcsuite/btcd v0.22.0-beta/go.mod h1:9n5ntfhhHQBIhUvlhDvD3Qg6fRUj4jkN0VB8L8svzOA= github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA= github.com/btcsuite/btcutil v0.0.0-20180706230648-ab6388e0c60a/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg= +github.com/btcsuite/btcutil v0.0.0-20190207003914-4c204d697803/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg= github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg= github.com/btcsuite/btcutil v1.0.2/go.mod h1:j9HUFwoQRsZL3V4n+qG+CUnEGHOarIxfC3Le2Yhbcts= github.com/btcsuite/btcutil v1.0.3-0.20201208143702-a53e38424cce h1:YtWJF7RHm2pYCvA5t0RPmAaLUhREsKuKd+SLhxFbFeQ= @@ -118,20 +159,29 @@ github.com/btcsuite/snappy-go v1.0.0/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY= github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs= github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ= +github.com/casbin/casbin/v2 v2.37.0/go.mod h1:vByNa/Fchek0KZUgG5wEsl7iFsiviAYKRtgrQfcJqHg= +github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4= github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= +github.com/cenkalti/backoff/v4 v4.1.1 h1:G2HAfAmvm/GcKan2oOQpBXOd2tT2G57ZnZGWa1PxPBQ= +github.com/cenkalti/backoff/v4 v4.1.1/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/census-instrumentation/opencensus-proto v0.3.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cespare/cp v0.1.0/go.mod h1:SOGHArjBr4JWaSDEVpWpo/hNg6RoKrls6Oh40hiwW+s= github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE= github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/checkpoint-restore/go-criu/v5 v5.0.0/go.mod h1:cfwC0EG7HMUenopBsUf9d89JlCLQIfgVcNsNN0t6T2M= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/cilium/ebpf v0.6.2/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs= github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= +github.com/clbanning/mxj v1.8.4/go.mod h1:BVjHeAH+rl9rs6f+QIpeRl0tfu10SXn1pUSa5PVGJng= github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE= +github.com/cloudflare/cloudflare-go v0.10.2-0.20190916151808-a80f83b9add9/go.mod h1:1MxXX1Ux4x6mqPmjkUgTP1CdXIBXKX7T+Jk9Gxrmx+U= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= @@ -139,11 +189,17 @@ github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWH github.com/cncf/xds/go v0.0.0-20211130200136-a8f946100490/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= +github.com/coinbase/rosetta-sdk-go v0.7.0 h1:lmTO/JEpCvZgpbkOITL95rA80CPKb5CtMzLaqF2mCNg= +github.com/coinbase/rosetta-sdk-go v0.7.0/go.mod h1:7nD3oBPIiHqhRprqvMgPoGxe/nyq3yftRmpsy29coWE= github.com/confio/ics23/go v0.6.3/go.mod h1:E45NqnlpxGnpfTWL/xauN7MRwEE28T4Dd4uraToOaKg= github.com/confio/ics23/go v0.6.6 h1:pkOy18YxxJ/r0XFDCnrl4Bjv6h4LkBSpLS6F38mrKL8= github.com/confio/ics23/go v0.6.6/go.mod h1:E45NqnlpxGnpfTWL/xauN7MRwEE28T4Dd4uraToOaKg= github.com/coniks-sys/coniks-go v0.0.0-20180722014011-11acf4819b71 h1:MFLTqgfJclmtaQ1SRUrWwmDX/1UBok3XWUethkJ2swQ= github.com/coniks-sys/coniks-go v0.0.0-20180722014011-11acf4819b71/go.mod h1:TrHYHH4Wze7v7Hkwu1MH1W+mCPQKM+gs+PicdEV14o8= +github.com/containerd/console v1.0.2/go.mod h1:ytZPjGgY2oeTkAONYafi2kSj0aYggsf8acV1PGKCbzQ= +github.com/containerd/continuity v0.0.0-20190827140505-75bee3e2ccb6/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= +github.com/containerd/continuity v0.1.0 h1:UFRRY5JemiAhPZrr/uE0n8fMTLcZsUvySPr1+D7pgr8= +github.com/containerd/continuity v0.1.0/go.mod h1:ICJu0PwR54nI0yPEnJ6jcS+J7CZAUXrLh8lPo2knzsM= github.com/coocood/freecache v1.2.0 h1:p8RhjN6Y4DRBIMzdRlm1y+M7h7YJxye3lGW8/VvzCz0= github.com/coocood/freecache v1.2.0/go.mod h1:OKrEjkGVoxZhyWAJoeFi5BMLUJm2Tit0kpGkIr7NGYY= github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= @@ -173,16 +229,22 @@ github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:ma github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/cyphar/filepath-securejoin v0.2.2/go.mod h1:FpkQEhXnPnOthhzymB7CGsFk2G9VLXONKD9G7QGMM+4= github.com/danieljoos/wincred v1.0.2 h1:zf4bhty2iLuwgjgpraD2E9UbvO+fe54XXGJbOwe23fU= github.com/danieljoos/wincred v1.0.2/go.mod h1:SnuYRW9lp1oJrZX/dXJqr0cPK5gYXqx3EJbmjhLdK9U= github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/deckarep/golang-set v0.0.0-20180603214616-504e848d77ea/go.mod h1:93vsz/8Wt4joVM7c2AVqh+YRMiUSc14yDtF28KmMOgQ= github.com/decred/dcrd/lru v1.0.0/go.mod h1:mxKOwFd7lFjN2GZYsiz/ecgqR6kkYAl+0pz0tEMk218= +github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f h1:U5y3Y5UE0w7amNe7Z5G/twsBW0KEalRQXZzf8ufSh9I= +github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f/go.mod h1:xH/i4TFMt8koVQZ6WFms69WAsDWr2XsYL3Hkl7jkoLE= github.com/dgraph-io/badger/v2 v2.2007.2 h1:EjjK0KqwaFMlPin1ajhP943VPENHJdEz1KLIegjaI3k= github.com/dgraph-io/badger/v2 v2.2007.2/go.mod h1:26P/7fbL4kUZVEVKLAKXkBXKOydDmM2p1e+NhhnBCAE= github.com/dgraph-io/ristretto v0.0.3-0.20200630154024-f66de99634de/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E= +github.com/dgraph-io/ristretto v0.0.3/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E= github.com/dgraph-io/ristretto v0.1.0 h1:Jv3CGQHp9OjuMBSne1485aDpUkTKEcUqF+jm/LuerPI= github.com/dgraph-io/ristretto v0.1.0/go.mod h1:fux0lOrBhrVCJd3lcTHsIJhq1T2rokOu6v9Vcb3Q9ug= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= @@ -190,19 +252,29 @@ github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUn github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 h1:fAjc9m62+UWV/WAFKLNi6ZS0675eEUC9y3AlwSbQu1Y= github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= +github.com/dlclark/regexp2 v1.2.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc= +github.com/docker/docker v1.4.2-0.20180625184442-8e610b2b55bf/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= +github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= +github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw= +github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/dop251/goja v0.0.0-20200721192441-a695b0cdd498/go.mod h1:Mw6PkjjMXWbTj+nnj4s3QPXq1jaT0s5pC0iFD4+BOAA= github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dvsekhvalnov/jose2go v0.0.0-20200901110807-248326c1351b h1:HBah4D48ypg3J7Np4N+HY/ZR76fx3HEUGxDU6Uk39oQ= github.com/dvsekhvalnov/jose2go v0.0.0-20200901110807-248326c1351b/go.mod h1:7BvyPhdbLxMXIYTFPLsyJRFMsKmOZnQmzh6Gb+uquuM= +github.com/dvyukov/go-fuzz v0.0.0-20200318091601-be3528f3a813/go.mod h1:11Gm+ccJnvAhCNLlf5+cS9KjtbaD5I5zaZpFMsTHWTw= github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= +github.com/edsrzf/mmap-go v0.0.0-20160512033002-935e0e8a636c/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/go-control-plane v0.10.1/go.mod h1:AY7fTTXNdv/aJ2O5jwpxAPOWUZ7hQAEvzN5Pf27BkQQ= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/envoyproxy/protoc-gen-validate v0.6.2/go.mod h1:2t7qjJNvHPx8IjnBOzl9E9/baC+qXE/TeeyBRzgJDws= +github.com/ethereum/go-ethereum v1.9.25/go.mod h1:vMkFiYLHI4tgPw4k2j4MHKoovchFE8plZ0M9VMk4/oM= github.com/facebookgo/ensure v0.0.0-20160127193407-b4ab57deab51/go.mod h1:Yg+htXGokKKdzcwhuNDwVvN+uBxDGXJ7G/VN1d8fa64= github.com/facebookgo/ensure v0.0.0-20200202191622-63f1cf65ac4c h1:8ISkoahWXwZR41ois5lSJBSVw4D0OV19Ht/JSTzvSv0= github.com/facebookgo/ensure v0.0.0-20200202191622-63f1cf65ac4c/go.mod h1:Yg+htXGokKKdzcwhuNDwVvN+uBxDGXJ7G/VN1d8fa64= @@ -211,48 +283,73 @@ github.com/facebookgo/stack v0.0.0-20160209184415-751773369052/go.mod h1:UbMTZqL github.com/facebookgo/subset v0.0.0-20150612182917-8dac2c3c4870/go.mod h1:5tD+neXqOorC30/tWg0LCSkrqj/AR6gu8yY8/fpw1q0= github.com/facebookgo/subset v0.0.0-20200203212716-c811ad88dec4 h1:7HZCaLC5+BZpmbhCOZJ293Lz68O7PYrF2EzeiFMwCLk= github.com/facebookgo/subset v0.0.0-20200203212716-c811ad88dec4/go.mod h1:5tD+neXqOorC30/tWg0LCSkrqj/AR6gu8yY8/fpw1q0= +github.com/fatih/color v1.3.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= +github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= +github.com/fatih/color v1.12.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= github.com/felixge/httpsnoop v1.0.1 h1:lvB5Jl89CsZtGIWuTcDM1E/vkVs49/Ml7JJe07l8SPQ= github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= +github.com/fjl/memsize v0.0.0-20180418122429-ca190fb6ffbc/go.mod h1:VvhXpOYNQvB+uIk2RvXzuaQtkQJzzIx6lSBe1xv7hi0= github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= -github.com/fogleman/gg v1.3.0/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw= github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4= +github.com/franela/goblin v0.0.0-20210519012713-85d372ac71e2/go.mod h1:VzmDKDJVZI3aJmnRI9VjAn9nJ8qPPsN1fqzr9dqInIo= github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20= +github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.5.1 h1:mZcQUHVQUQWoPXXtuf9yuEXKudkV2sx1E06UadKWpgI= github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU= +github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff/go.mod h1:x7DCsMOv1taUwEWCzT4cmDeAkigA5/QCwUodaVOe8Ww= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/go-fonts/dejavu v0.1.0/go.mod h1:4Wt4I4OU2Nq9asgDCteaAaWZOV24E+0/Pwo0gppep4g= -github.com/go-fonts/latin-modern v0.2.0/go.mod h1:rQVLdDMK+mK1xscDwsqM5J8U2jrRa3T0ecnM9pNujks= -github.com/go-fonts/liberation v0.1.1/go.mod h1:K6qoJYypsmfVjWg8KOVDQhLc8UDgIK2HYqyqAO9z7GY= -github.com/go-fonts/stix v0.1.0/go.mod h1:w/c1f0ldAUlJmLBvlbkvVXLAD+tAMqobIIQpmnUIzUY= +github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= +github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= +github.com/gin-gonic/gin v1.6.3 h1:ahKqKTFpO5KTPHxWZjEdPScmYaGtLo8Y4DMHoEsnp14= +github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= -github.com/go-kit/kit v0.10.0 h1:dXFJfIHVvUcpSgDOV+Ne6t7jXri8Tfv2uOLHUZ2XNuo= github.com/go-kit/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgOZ7o= +github.com/go-kit/kit v0.12.0 h1:e4o3o3IsBfAKQh5Qbbiqyfu97Ku7jrO/JbohvztANh4= +github.com/go-kit/kit v0.12.0/go.mod h1:lHd+EkCZPIwYItmGDDRdhinkzX2A1sj+M9biaEaizzs= github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= -github.com/go-latex/latex v0.0.0-20210118124228-b3d85cf34e07/go.mod h1:CO1AlKB2CSIqUrmQPqA0gdRIlnLEY0gK5JGjh37zN5U= +github.com/go-kit/log v0.2.0 h1:7i2K3eKTos3Vc0enKCfnVcgHh2olr/MyfboYq7cAcFw= +github.com/go-kit/log v0.2.0/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= -github.com/go-logfmt/logfmt v0.5.0 h1:TrB8swr/68K7m9CcGut2g3UOihhbcbiMAYiuTXdEih4= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= +github.com/go-logfmt/logfmt v0.5.1 h1:otpy5pqBCBZ1ng9RQ0dPu4PN7ba75Y/aA+UpowDyNVA= +github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= +github.com/go-ole/go-ole v1.2.1/go.mod h1:7FAglXiTm7HKlQRDeOQ6ZNUHidzCWXuZWq/1dTyBNF8= +github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= +github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q= +github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= +github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no= +github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= +github.com/go-playground/validator/v10 v10.2.0 h1:KgJ0snyC2R9VXYN2rneOtQcw5aHQB1Vv0sFl1UcHBOY= +github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI= +github.com/go-sourcemap/sourcemap v2.1.2+incompatible/go.mod h1:F8jJfvm2KbVjc5NqelyYJmf/v5J0dwNLS2mL4sNA1Jg= github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= -github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= +github.com/go-zookeeper/zk v1.0.2/go.mod h1:nOB03cncLtlp4t+UAkGSV+9beXP/akpekBwL+UX1Qcw= +github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee h1:s+21KNqlpePfkah2I+gwHF8xmJWRjooY+5248k6m4A0= +github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo= +github.com/gobwas/pool v0.2.0 h1:QEmUOlnSjWtnpRGHF3SauEiOsy82Cup83Vf2LcMlnc8= +github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= +github.com/gobwas/ws v1.0.2 h1:CoAavW/wd/kulfZmSIBt6p24n4j7tHgNVCjsfHVNUbo= +github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM= github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 h1:ZpnhV/YsD2/4cESfV5+Hoeu/iUR3ruzNvZ+yQfO03a0= github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gogo/gateway v1.1.0 h1:u0SuhL9+Il+UbjM9VIE3ntfRujKbvVpFvNB4HbjeVQ0= github.com/gogo/gateway v1.1.0/go.mod h1:S7rR8FRQyG3QFESeSv4l2WnsyzlCLG0CzBbUUo/mbic= +github.com/golang-jwt/jwt/v4 v4.0.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= @@ -292,6 +389,7 @@ github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v0.0.3-0.20201103224600-674baa8c7fc3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= @@ -313,8 +411,8 @@ github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= -github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/gofuzz v1.1.1-0.20200604201612-c04b05f3adfa h1:Q75Upo5UN4JbPFURXZ8nLKYUvF85dyFRop/vQ0Rv+64= +github.com/google/gofuzz v1.1.1-0.20200604201612-c04b05f3adfa/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= @@ -337,12 +435,14 @@ github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLe github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0= github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gordonklaus/ineffassign v0.0.0-20200309095847-7953dde2c7bf/go.mod h1:cuNKsD1zp2v6XfE/orVX2QE1LC+i254ceGcVeDT3pTU= github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= github.com/gorilla/handlers v1.5.1 h1:9lRY6j8DEeeBT10CvO9hGW0gmky0BprnvDI5vfhUHH4= github.com/gorilla/handlers v1.5.1/go.mod h1:t8XrUpc4KVXb7HGyJ4/cEnwQiaxrX/hz1Zv/4g96P1Q= @@ -351,10 +451,16 @@ github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2z github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gorilla/websocket v1.4.1-0.20190629185528-ae1634f6a989/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gotestyourself/gotestyourself v2.2.0+incompatible/go.mod h1:zZKM6oeNM8k+FRljX1mnzVYeS8wiGgQyvST1/GafPbY= +github.com/graph-gophers/graphql-go v0.0.0-20191115155744-f33e81362277/go.mod h1:9CQHMSxwO4MprSdzoIEobiHpoLtHm77vfxsvsIN5Vuc= github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= +github.com/grpc-ecosystem/go-grpc-middleware v1.2.2/go.mod h1:EaizFBKfUKtMIF5iaDEhniwNedqGo9FuLFzppDr3uwI= github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 h1:+9834+KizmvFV7pXQGSXQTsaWhq2GjuNUt0aUU0YBYw= github.com/grpc-ecosystem/go-grpc-middleware v1.3.0/go.mod h1:z0ButlSOZa5vEBq9m2m2hlwIgKw+rp3sdCBRoJY+30Y= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= @@ -372,6 +478,7 @@ github.com/gtank/ristretto255 v0.1.2 h1:JEqUCPA1NvLq5DwYtuzigd7ss8fwbYay9fi4/5uM github.com/gtank/ristretto255 v0.1.2/go.mod h1:Ph5OpO6c7xKUGROZfWVLiJf9icMDwUeIvY4OmlYW69o= github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE= +github.com/hashicorp/consul/api v1.10.1/go.mod h1:XjsvQN+RJGWI2TWy1/kqaE16HrR2J/FWgkYjdZQsX9M= github.com/hashicorp/consul/api v1.11.0/go.mod h1:XjsvQN+RJGWI2TWy1/kqaE16HrR2J/FWgkYjdZQsX9M= github.com/hashicorp/consul/api v1.12.0/go.mod h1:6pVBMo0ebnYdt2S3H87XhekM/HHrUoTD2XXb/VrZVy0= github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= @@ -382,6 +489,7 @@ github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtng github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= github.com/hashicorp/go-hclog v0.12.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= +github.com/hashicorp/go-hclog v0.16.2/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= github.com/hashicorp/go-hclog v1.0.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= @@ -415,19 +523,35 @@ github.com/hashicorp/memberlist v0.3.0/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOn github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= github.com/hashicorp/serf v0.9.5/go.mod h1:UWDWwZeL5cuWDJdl0C6wrvrUwEqtQ4ZKBKKENpqIUyk= github.com/hashicorp/serf v0.9.6/go.mod h1:TXZNMjZQijwlDvp+r0b63xZ45H7JmCmgg4gpTwn9UV4= +github.com/hdevalence/ed25519consensus v0.0.0-20220222234857-c00d1f31bab3 h1:aSVUgRRRtOrZOC1fYmY9gV0e9z/Iu+xNVSASWjsuyGU= +github.com/hdevalence/ed25519consensus v0.0.0-20220222234857-c00d1f31bab3/go.mod h1:5PC6ZNPde8bBqU/ewGZig35+UIZtw9Ytxez8/q5ZyFE= github.com/herumi/bls-eth-go-binary v0.0.0-20200923072303-32b29e5d8cbf h1:Lw7EOMVxu3O+7Ro5bqn9M20a7GwuCqZQsmdXNzmcKE4= github.com/herumi/bls-eth-go-binary v0.0.0-20200923072303-32b29e5d8cbf/go.mod h1:luAnRm3OsMQeokhGzpYmc0ZKwawY7o87PUEP11Z7r7U= +github.com/holiman/uint256 v1.1.1/go.mod h1:y4ga/t+u+Xwd7CpDgZESaRcWy0I7XMlTMA25ApIH5Jw= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg= +github.com/hudl/fargo v1.4.0/go.mod h1:9Ai6uvFy5fQNq6VPKtg+Ceq1+eTY4nKUlR2JElEOcDo= +github.com/huin/goupnp v1.0.0/go.mod h1:n9v9KO1tAxYH82qOn+UTIFQDmx5n1Zxd/ClZDMX7Bnc= +github.com/huin/goutil v0.0.0-20170803182201-1ca381bf3150/go.mod h1:PpLOETDnJ0o3iZrZfqZzyLl6l7F3c6L1oWn7OICBi6o= github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/improbable-eng/grpc-web v0.15.0 h1:BN+7z6uNXZ1tQGcNAuaU1YjsLTApzkjt2tzCixLaUPQ= +github.com/improbable-eng/grpc-web v0.15.0/go.mod h1:1sy9HKV4Jt9aEs9JSnkWlRJPuPtwNr0l57L4f878wP8= github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/influxdata/influxdb v1.2.3-0.20180221223340-01288bdb0883/go.mod h1:qZna6X/4elxqT3yI9iZYdZrWWdeFOOprn86kgg4+IzY= github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= +github.com/influxdata/influxdb1-client v0.0.0-20200827194710-b269163b24ab/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= +github.com/jackpal/go-nat-pmp v1.0.2-0.20160603034137-1fa385a6f458/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= +github.com/jedisct1/go-minisign v0.0.0-20190909160543-45766022959e/go.mod h1:G1CVv03EnqU1wYL2dFwXxW2An0az9JTl/ZsqXQeBlkU= github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jhump/protoreflect v1.10.3 h1:8ogeubpKh2TiulA0apmGlW5YAH4U1Vi4TINIP+gpNfQ= +github.com/jhump/protoreflect v1.10.3/go.mod h1:7GcYQDdMU/O/BBrl/cX6PNHpXh6cenjd8pneu5yW7Tg= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= +github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= +github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= github.com/jmhodges/levigo v1.0.0 h1:q5EC36kV79HWeTBWsod3mG11EgStG3qArTKcvlksN1U= github.com/jmhodges/levigo v1.0.0/go.mod h1:Q6Qx+uH3RAqyK4rFQroq9RL7mdkABMcfhEI+nNuzMJQ= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= @@ -441,28 +565,43 @@ github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/u github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/julienschmidt/httprouter v1.1.1-0.20170430222011-975b5c4c7c21/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= -github.com/jung-kurt/gofpdf v1.0.0/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= +github.com/karalabe/usb v0.0.0-20190919080040-51dc0efba356/go.mod h1:Od972xHfMJowv7NGVDiWVxk2zxnWgjLlJzE+F4F7AGU= github.com/keybase/go-keychain v0.0.0-20190712205309-48d3d31d256d h1:Z+RDyXzjKE0i2sTjZ/b1uxiGtPhFy34Ou/Tk0qwN0kM= github.com/keybase/go-keychain v0.0.0-20190712205309-48d3d31d256d/go.mod h1:JJNrCn9otv/2QP4D7SMJBgaleKpOf66PnW6F5WGNRIc= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4= +github.com/klauspost/compress v1.10.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= +github.com/klauspost/compress v1.11.7/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= +github.com/klauspost/compress v1.13.4/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg= +github.com/klauspost/compress v1.13.6 h1:P76CopJELS0TiO2mebmnzgWaajssP/EszplttgQxcgc= +github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= +github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y= +github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= +github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/lib/pq v1.10.4 h1:SO9z7FRPzA03QhHKJrH5BXA6HU1rS4V2nIVrrNC1iYk= +github.com/lib/pq v1.10.4/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/libp2p/go-buffer-pool v0.0.2 h1:QNK2iAFa8gjAe1SPz6mHSMuCcjs+X1wlHzeOSqcmlfs= github.com/libp2p/go-buffer-pool v0.0.2/go.mod h1:MvaB6xw5vOrDl8rYZGLFdKAuk/hRoRZd1Vi32+RXyFM= github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM= @@ -472,14 +611,15 @@ github.com/line/gorocksdb v0.0.0-20210406043732-d4bea34b6d55/go.mod h1:DHRJroSL7 github.com/line/iavl/v2 v2.0.0-init.1.0.20220215225951-cb11c91d8857 h1:8kWqbLNeb37357e4U/7uLMVCRF3K9bxwTGb6JmRUKpI= github.com/line/iavl/v2 v2.0.0-init.1.0.20220215225951-cb11c91d8857/go.mod h1:uK2CYRdukSVRGhc5Q8zoDUnm/zAbfnZATbFXrfCrQKA= github.com/line/ostracon v0.34.9-0.20210429084710-ef4fe0a40c7d/go.mod h1:ttnbq+yQJMQ9a2MT5SEisOoa/+pOgh2KenTiK/rVdiw= -github.com/line/ostracon v1.0.3 h1:9HJ27BZJUcGCJgKPtuqLPDoZ2Ytty2lT/fEWq2ckAFI= -github.com/line/ostracon v1.0.3/go.mod h1:txHQ97UdyUMSfuNGZYpRfuxLPCvHA0h/Y+0kbc9s2H4= +github.com/line/ostracon v1.0.4 h1:BiHBbwKT6M/x7ShZTl3BFuQstcLYshnC0cJw7hTEQ88= +github.com/line/ostracon v1.0.4/go.mod h1:FdYuxCMlofDLNcdJGDBV5+Xno+RG+Tpt3paYfk/Z398= github.com/line/tm-db/v2 v2.0.0-init.1.0.20210413083915-5bb60e117524/go.mod h1:wmkyPabXjtVZ1dvRofmurjaceghywtCSYGqFuFS+TbI= github.com/line/tm-db/v2 v2.0.0-init.1.0.20210824011847-fcfa67dd3c70/go.mod h1:wmkyPabXjtVZ1dvRofmurjaceghywtCSYGqFuFS+TbI= github.com/line/tm-db/v2 v2.0.0-init.1.0.20220121012851-61d2bc1d9486 h1:uvXQdcWaUyNsgkXBz375FpQ285WEJaLXhQ5HtoNK/GU= github.com/line/tm-db/v2 v2.0.0-init.1.0.20220121012851-61d2bc1d9486/go.mod h1:wmkyPabXjtVZ1dvRofmurjaceghywtCSYGqFuFS+TbI= github.com/line/wasmvm v0.16.3-0.9.0 h1:snRk3T3mJV+7HTjCIhHKmeYUEN9uRbyRVhmuhele/jM= github.com/line/wasmvm v0.16.3-0.9.0/go.mod h1:cgsILoCDigfQ2XplFI4rOo2ImOLEZH/OM8sulxGoKUA= +github.com/lucasjones/reggen v0.0.0-20180717132126-cdb49ff09d77/go.mod h1:5ELEyG+X8f+meRWHuqUOewBOhvHkl7M76pdGEansxW4= github.com/lyft/protoc-gen-star v0.5.3/go.mod h1:V0xaHgaf5oCCqmcxYcWiDfTiKsZsRc87/1qhoTACD8w= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= @@ -488,12 +628,17 @@ github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPK github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.0/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-ieproxy v0.0.0-20190610004146-91bb50d98149/go.mod h1:31jz6HNzdxOmlERGGEc4v/dMssOfmp2p5bT/okiKFFc= +github.com/mattn/go-ieproxy v0.0.0-20190702010315-6dee0af9227d/go.mod h1:31jz6HNzdxOmlERGGEc4v/dMssOfmp2p5bT/okiKFFc= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.5-0.20180830101745-3fb116b82035/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= @@ -501,15 +646,19 @@ github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Ky github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= +github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= +github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso= github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI= +github.com/miekg/dns v1.1.43/go.mod h1:+evo5L0630/F6ca/Z9+GAqzhjGyn8/c+TBaOyfEl0V4= github.com/mimoo/StrobeGo v0.0.0-20181016162300-f8f6d4d2b643 h1:hLDRPB66XQT/8+wG9WsDpiCvZf1yKO7sz7scAjSlBa0= github.com/mimoo/StrobeGo v0.0.0-20181016162300-f8f6d4d2b643/go.mod h1:43+3pMjjKimDBf5Kr4ZFNGbLql1zKkbImw+fZbw3geM= -github.com/minio/highwayhash v1.0.1 h1:dZ6IIu8Z14VlC0VpfKofAhCy74wu/Qb5gcn52yWoz/0= github.com/minio/highwayhash v1.0.1/go.mod h1:BQskDq+xkJ12lmlUUi7U0M5Swg3EWR+dLTk+kldvVxY= +github.com/minio/highwayhash v1.0.2 h1:Aak5U0nElisjDCfPSG79Tgzkn2gl66NxOMspRrKnA/g= +github.com/minio/highwayhash v1.0.2/go.mod h1:BQskDq+xkJ12lmlUUi7U0M5Swg3EWR+dLTk+kldvVxY= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI= github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= @@ -519,26 +668,44 @@ github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS4 github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/mapstructure v1.3.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.4.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/mapstructure v1.4.3 h1:OVowDSCllw/YjdLkam3/sm7wEtOy59d8ndGgCcyj8cs= github.com/mitchellh/mapstructure v1.4.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/moby/sys/mountinfo v0.4.1/go.mod h1:rEr8tzG/lsIZHBtN/JjGG+LMYx9eXgW2JI+6q0qou+A= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/mrunalp/fileutils v0.5.0/go.mod h1:M1WthSahJixYnrXQl/DFQuteStB1weuxD2QJNHXfbSQ= github.com/mtibben/percent v0.2.1 h1:5gssi8Nqo8QU/r2pynCm+hBQHpkB/uNK7BJCFogWdzs= github.com/mtibben/percent v0.2.1/go.mod h1:KG9uO+SZkUp+VkRHsCdYQV3XSZrrSpR3O9ibNBTZrns= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f h1:KUppIJq7/+SVif2QVs3tOP0zanoHgBEVAwHxUSIzRqU= github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/mwitkow/grpc-proxy v0.0.0-20181017164139-0f1106ef9c76/go.mod h1:x5OoJHDHqxHS801UIuhqGl6QdSAEJvtausosHSdazIo= +github.com/naoina/go-stringutil v0.1.0/go.mod h1:XJ2SJL9jCtBh+P9q5btrd/Ylo8XwT/h1USek5+NqSA0= +github.com/naoina/toml v0.1.2-0.20170918210437-9fafd6967416/go.mod h1:NBIhNtsFMo3G2szEBne+bO4gS192HuIYRqfvOWb4i1E= github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg= github.com/nats-io/jwt v0.3.2/go.mod h1:/euKqTS1ZD+zzjYrY7pseZrTtWQSjujC7xjPc8wL6eU= +github.com/nats-io/jwt v1.2.2/go.mod h1:/xX356yQA6LuXI9xWW7mZNpxgF2mBmGecH+Fj34sP5Q= +github.com/nats-io/jwt/v2 v2.0.3/go.mod h1:VRP+deawSXyhNjXmxPCHskrR6Mq50BqpEI5SEcNiGlY= github.com/nats-io/nats-server/v2 v2.1.2/go.mod h1:Afk+wRZqkMQs/p45uXdrVLuab3gwv3Z8C4HTBu8GD/k= +github.com/nats-io/nats-server/v2 v2.5.0/go.mod h1:Kj86UtrXAL6LwYRA6H4RqzkHhK0Vcv2ZnKD5WbQ1t3g= github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzEE/Zbp4w= +github.com/nats-io/nats.go v1.12.1/go.mod h1:BPko4oXsySz4aSWeFgOHLZs3G4Jq4ZAyE6/zMCxRT6w= github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= +github.com/nats-io/nkeys v0.2.0/go.mod h1:XdZpAbhgyyODYqjTawOnIOI7VlbKSarI9Gfy1tqEu/s= +github.com/nats-io/nkeys v0.3.0/go.mod h1:gvUNGjVcM2IPr5rCsRsC6Wb3Hr2CQAm08dsxtV6A5y4= github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= +github.com/neilotoole/errgroup v0.1.5/go.mod h1:Q2nLGf+594h0CLBs/Mbg6qOr7GtqDK7C2S41udRnToE= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/nishanths/predeclared v0.0.0-20200524104333-86fad755b4d3/go.mod h1:nt3d53pc1VYcphSCIaYAJtnPYnr3Zyn8fMq2wvPGPso= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= @@ -546,40 +713,58 @@ github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtb github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= +github.com/olekukonko/tablewriter v0.0.1/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= +github.com/olekukonko/tablewriter v0.0.2-0.20190409134802-7e037d187b0c/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= +github.com/onsi/ginkgo v1.16.2/go.mod h1:CObGmKUOKaSC0RjmoAK7tKyn4Azo5P2IWuoMnvwxz1E= github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc= github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= github.com/onsi/gomega v1.4.1/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= -github.com/onsi/gomega v1.10.1 h1:o0+MgICZLuZ7xjH7Vx6zS/zcu93/BEp1VwkIW1mEXCE= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= +github.com/onsi/gomega v1.13.0 h1:7lLHu94wT9Ij0o6EWWclhu0aOh32VxhkwEJvzuWPeak= +github.com/onsi/gomega v1.13.0/go.mod h1:lRk9szgn8TxENtWd0Tp4c3wjlRfMTMH27I+3Je41yGY= github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= +github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= +github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= +github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= +github.com/opencontainers/image-spec v1.0.1 h1:JMemWkRwHx4Zj+fVxWoMCFm/8sYGGrUVojFA6h/TRcI= +github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= +github.com/opencontainers/runc v0.1.1/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= +github.com/opencontainers/runc v1.0.2 h1:opHZMaswlyxz1OuGpBE53Dwe4/xF7EZTY0A2L/FpCOg= +github.com/opencontainers/runc v1.0.2/go.mod h1:aTaHFFwQXuA71CiyxOdFFIorAoemI04suvGRQFzWTD0= +github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/opencontainers/selinux v1.8.2/go.mod h1:MUIHuUEvKB1wtJjQdOyYRgOnLD2xAPP8dBsCoU0KuF8= github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis= github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74= github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= +github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= github.com/openzipkin-contrib/zipkin-go-opentracing v0.4.5/go.mod h1:/wsWhb9smxSfWAKL3wpBW7V8scJMt8N8gnaMCS9E/cA= github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw= github.com/openzipkin/zipkin-go v0.2.1/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= +github.com/openzipkin/zipkin-go v0.2.5/go.mod h1:KpXfKdgRDnnhsxw4pNIH9Md5lyFqKUa4YDFlwRYAMyE= +github.com/ory/dockertest v3.3.5+incompatible h1:iLLK6SQwIhcbrG783Dghaaa3WPzGc+4Emza6EbVUUGA= +github.com/ory/dockertest v3.3.5+incompatible/go.mod h1:1vX4m9wsvi00u5bseYwXaSnhNrne+V0E6LAcBILJdPs= github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIwwtUjcrb0b5/5kLM= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pborman/uuid v0.0.0-20170112150404-1b00554d8222/go.mod h1:VyrYX9gd7irzKovcSS6BIIEwPRkP2Wm2m9ufcdFSJ34= github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= -github.com/pelletier/go-toml v1.6.0/go.mod h1:5N711Q9dKgbdkxHL+MEfF31hpT7l0S0s/t2kKREewys= github.com/pelletier/go-toml v1.9.4 h1:tjENF6MfZAg8e4ZmZTeWaWiT2vXtsoO6+iuOjFhECwM= github.com/pelletier/go-toml v1.9.4/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac= +github.com/performancecopilot/speed/v4 v4.0.0/go.mod h1:qxrSyuDGrTOWfV+uKRFhfxw6h/4HXRGUiZiufxo49BM= +github.com/peterh/liner v1.1.1-0.20190123174540-a2c9a5303de7/go.mod h1:CRroGNssyjTd/qIG2FyxByd2S8JEAZXBl4qUrZf8GS0= github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5 h1:q2e307iGHPdTGp0hoxKjt1H5pDo6utceo3dQVK3I5XQ= github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5/go.mod h1:jvVRKCrJTQWu0XVbaOlby/2lO20uSCHEMzzplHXte1o= -github.com/phpdave11/gofpdf v1.4.2/go.mod h1:zpO6xFn9yxo3YLyMvW8HcKWVdbNqgIfOOp2dXMnm1mY= -github.com/phpdave11/gofpdi v1.0.12/go.mod h1:vBmVV0Do6hSBHC8uKUQ71JGW+ZGQq74llk/7bXwjDoI= github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc= github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -618,7 +803,9 @@ github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt2 github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= github.com/prometheus/common v0.14.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s= +github.com/prometheus/common v0.15.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s= github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= +github.com/prometheus/common v0.30.0/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= github.com/prometheus/common v0.32.1 h1:hWIdL3N2HoUx3B8j3YN9mWor0qhY/NlEKZEaXxuIRh4= github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= @@ -628,9 +815,11 @@ github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsT github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/procfs v0.2.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= +github.com/prometheus/procfs v0.3.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/prometheus/procfs v0.7.3 h1:4jVXhlkAyzOScmCkXBTOLRLTz8EeU+eyjrwB/EPq0VU= github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= +github.com/prometheus/tsdb v0.6.2-0.20190402121629-4f204dcbc150/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/r2ishiguro/vrf v0.0.0-20180716233122-192de52975eb h1:3kW8n+FfBaUoqlHxCa6e90PXWpGCWWkdyTZ6F7c9m2I= github.com/r2ishiguro/vrf v0.0.0-20180716233122-192de52975eb/go.mod h1:2NzHJUkr/ERaPNQ2IUuNbB2jMTWYp2DxhcraWbzZj00= @@ -643,18 +832,20 @@ github.com/regen-network/cosmos-proto v0.3.1 h1:rV7iM4SSFAagvy8RiyhiACbWEGotmqzy github.com/regen-network/cosmos-proto v0.3.1/go.mod h1:jO0sVX6a1B36nmE8C9xBFXpNwWejXC7QqCOnH3O0+YM= github.com/regen-network/protobuf v1.3.3-alpha.regen.1 h1:OHEc+q5iIAXpqiqFKeLpu5NwTIkVXUs48vFMwzqpqY4= github.com/regen-network/protobuf v1.3.3-alpha.regen.1/go.mod h1:2DjTFR1HhMQhiWC5sZ4OhQ3+NtdbZ6oBDKQwq5Ou+FI= +github.com/rjeczalik/notify v0.9.1/go.mod h1:rKwnCoCGeuQnwBtTSPL9Dad03Vh2n40ePRrjvIXnJho= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rs/cors v0.0.0-20160617231935-a62a804a8a00/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= github.com/rs/cors v1.7.0 h1:+88SsELBHx5r+hZ8TCkggzSstaWNbDvThkVK8H6f9ik= github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= +github.com/rs/xhandler v0.0.0-20160618193221-ed27b6fd6521/go.mod h1:RvLn4FgxWubrpZHtQLnOf6EwhN2hEMusxZOhcW9H3UQ= github.com/rs/xid v1.3.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= github.com/rs/zerolog v1.26.1 h1:/ihwxqH+4z8UxyI70wM1z9yCvkWcfz/a3mj48k/Zngc= github.com/rs/zerolog v1.26.1/go.mod h1:/wSSJWX7lVrsOwlbyTRSOJvqRlc+WjWlfes+CiJ+tmc= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/ruudk/golang-pdf417 v0.0.0-20181029194003-1af4ab5afa58/go.mod h1:6lfFZQK844Gfx8o5WFuvpxWRwnSoipWe/p622j1v06w= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/sagikazarmark/crypt v0.3.0/go.mod h1:uD/D+6UF4SrIR1uGEv7bBNkNqLGqUr43MRiaGWX1Nig= github.com/sagikazarmark/crypt v0.4.0/go.mod h1:ALv2SRj7GxYV4HO9elxH9nS6M9gW+xDNxqmyJ6RfDFM= @@ -662,10 +853,17 @@ github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0 github.com/sasha-s/go-deadlock v0.2.1-0.20190427202633-1595213edefa h1:0U2s5loxrTy6/VgfVoLuVLFJcURKLH49ie0zSch7gh4= github.com/sasha-s/go-deadlock v0.2.1-0.20190427202633-1595213edefa/go.mod h1:F73l+cr82YSh10GxyRI6qZiCgK64VaZjwesgfQ1/iLM= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= +github.com/seccomp/libseccomp-golang v0.9.1/go.mod h1:GbW5+tmTXfcxTToHLXlScSlAvWlF4P2Ca7zGrPiEpWo= +github.com/segmentio/fasthash v1.0.3/go.mod h1:waKX8l2N8yckOgmSsXJi7x1ZfdKZ4x7KRMzBtS3oedY= +github.com/shirou/gopsutil v2.20.5+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= +github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE= +github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/snikch/goodman v0.0.0-20171125024755-10e37e294daa/go.mod h1:oJyF+mSPHbB5mVY2iO9KV3pTt/QbIkGaO8gQ2WrDbP4= @@ -675,7 +873,6 @@ github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasO github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= -github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= github.com/spf13/afero v1.3.3/go.mod h1:5KUK8ByomD5Ti5Artl0RtHeI5pTF7MIDuXL3yY520V4= github.com/spf13/afero v1.6.0 h1:xoax2sJ2DT8S8xA2paPFjDCScCNeWsg75VG0DLRreiY= github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= @@ -684,6 +881,7 @@ github.com/spf13/cast v1.4.1 h1:s0hze+J0196ZfEMTs80N7UlFt0BDuQ7Q+JDnHiMWKdA= github.com/spf13/cast v1.4.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= +github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= github.com/spf13/cobra v1.1.1/go.mod h1:WnodtKOvamDL/PwE2M4iKs8aMDBZ5Q5klgD3qfVJQMI= github.com/spf13/cobra v1.3.0 h1:R7cSvGu+Vv+qX0gW5R/85dx2kmmJT5z5NM8ifdYjdn0= github.com/spf13/cobra v1.3.0/go.mod h1:BrRVncBjOJa/eUcVVm9CE+oC6as8k+VYr4NY7WCi9V4= @@ -695,14 +893,20 @@ github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnIn github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= +github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= github.com/spf13/viper v1.7.1/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= github.com/spf13/viper v1.10.0/go.mod h1:SoyBPwAtKDzypXNDFKN5kzH7ppppbGZtls1UpIy5AsM= github.com/spf13/viper v1.10.1 h1:nuJZuYpG7gTj/XqiUwg8bA0cp1+M2mC3J4g5luUYBKk= github.com/spf13/viper v1.10.1/go.mod h1:IGlFPqhNAPKRxohIzWpI5QEy4kuI7tcl5WvR+8qy1rU= +github.com/status-im/keycard-go v0.0.0-20190316090335-8537d3370df4/go.mod h1:RZLeN1LMWmRsyYjvAu+I6Dm9QmlDaIIt+Y+4Kd7Tp+Q= +github.com/steakknife/bloomfilter v0.0.0-20180922174646-6819c0d2a570/go.mod h1:8OR4w3TdeIHIh1g6EMY5p0gVNOovcWC+1vpc7naMuAw= +github.com/steakknife/hamming v0.0.0-20180906055917-c99c65617cd3/go.mod h1:hpGUWaI9xL8pRQCTXQgocU38Qw1g0Us7n5PxxTwTCYU= github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= +github.com/streadway/amqp v1.0.0/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI= +github.com/streadway/handy v0.0.0-20200128134331-0f66f006fb2e/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48= @@ -716,6 +920,7 @@ github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5Cc github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= +github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= github.com/syndtr/goleveldb v1.0.1-0.20190923125748-758128399b1d/go.mod h1:9OrXJhf154huy1nPWmuSrkgjPUtUNhA+Zmy+6AESzuA= github.com/syndtr/goleveldb v1.0.1-0.20200815110645-5c35d600f0ca h1:Ld/zXl5t4+D69SiV4JoN7kkfvJdOWlPpfxrzxpLMoUk= github.com/syndtr/goleveldb v1.0.1-0.20200815110645-5c35d600f0ca/go.mod h1:u2MKkTVTVJWe5D1rCvame8WqhBd88EuIwODJZ1VHCPM= @@ -729,16 +934,33 @@ github.com/tendermint/go-amino v0.16.0 h1:GyhmgQKvqF82e2oZeuMSp9JTN0N09emoSZlb2l github.com/tendermint/go-amino v0.16.0/go.mod h1:TQU0M1i/ImAo+tYpZi73AU3V/dKeCoMC9Sphe2ZwGME= github.com/tendermint/tm-db v0.6.0 h1:Us30k7H1UDcdqoSPhmP8ztAW/SWV6c6OfsfeCiboTC4= github.com/tendermint/tm-db v0.6.0/go.mod h1:xj3AWJ08kBDlCHKijnhJ7mTcDMOikT1r8Poxy2pJn7Q= +github.com/tidwall/gjson v1.6.7/go.mod h1:zeFuBCIqD4sN/gmqBzZ4j7Jd6UcA2Fc56x7QFsv+8fI= +github.com/tidwall/match v1.0.3/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= +github.com/tidwall/pretty v1.0.2/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= +github.com/tidwall/sjson v1.1.4/go.mod h1:wXpKXu8CtDjKAZ+3DrKY5ROCorDFahq8l0tey/Lx1fg= github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= +github.com/tyler-smith/go-bip39 v1.0.1-0.20181017060643-dbb3b84ba2ef/go.mod h1:sJ5fKU0s6JVwZjjcUEX2zFOnvq0ASQ2K9Zr6cf67kNs= +github.com/tyler-smith/go-bip39 v1.0.2/go.mod h1:sJ5fKU0s6JVwZjjcUEX2zFOnvq0ASQ2K9Zr6cf67kNs= +github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= +github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo= +github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= +github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs= +github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE= +github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU= +github.com/vmihailenco/msgpack/v5 v5.1.4/go.mod h1:C5gboKD0TJPqWDTVTtrQNfRbiBwHZGo8UTqP/9/XvLI= +github.com/vmihailenco/tagparser v0.1.2/go.mod h1:OeAg3pn3UbLjkWt+rN9oFYB6u/cQgqMEUPoW2WPyhdI= +github.com/wsddn/go-ecdh v0.0.0-20161211032359-48726bab9208/go.mod h1:IotVbo4F+mw0EzQ08zFqg7pK3FebNXpaMsRy2RT+Ees= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/yahoo/coname v0.0.0-20170609175141-84592ddf8673 h1:PSg2cEFd+9Ae/r5x5iO8cJ3VmTbZNQp6X8tHDmVJAbA= github.com/yahoo/coname v0.0.0-20170609175141-84592ddf8673/go.mod h1:Wq2sZrP++Us4tAw1h58MHS8BGIpC4NmKHfvw2QWBe9U= +github.com/ybbus/jsonrpc v2.1.2+incompatible/go.mod h1:XJrh1eMSzdIYFbM08flv0wp5G35eRniyeGut1z+LSiE= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -752,9 +974,13 @@ go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/bbolt v1.3.5 h1:XAzx9gjCb0Rxj7EoqcClPD1d5ZBxZJk0jbuoPHenBt0= go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ= go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg= +go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= go.etcd.io/etcd/api/v3 v3.5.1/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= +go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= go.etcd.io/etcd/client/pkg/v3 v3.5.1/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= +go.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsXlzd7alYQ= go.etcd.io/etcd/client/v2 v2.305.1/go.mod h1:pMEacxZW7o8pg4CrFE7pquyCJJzZvkvdD2RibOCCCGs= +go.etcd.io/etcd/client/v3 v3.5.0/go.mod h1:AIKXXVX/DQXtfTEqBryiLTUXwON+GuvO6Z7lLS/oTh0= go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= @@ -769,57 +995,64 @@ go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/goleak v1.1.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= +go.uber.org/multierr v1.7.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak= go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= +go.uber.org/zap v1.19.1/go.mod h1:j3DNczoxDZroyBnOT1L/Q79cfUMGZxlv/9dzN7SM1rI= golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190909091759-094676da4a83/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200115085410-6d4e4cb37c7d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201117144127-c1f2f97bffc9/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= +golang.org/x/crypto v0.0.0-20210314154223-e6e6c4f2bb5b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= +golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20211215165025-cf75a172585e h1:1SzTfNOXwIS2oWiMF+6qu0OUDKb0dauo6MoDUQyu+yU= +golang.org/x/crypto v0.0.0-20210915214749-c084706c2272/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20211215165025-cf75a172585e/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= +golang.org/x/crypto v0.0.0-20220112180741-5e0467b6c7ce h1:Roh6XWxHFKrPgC/EQhVubSAGQ6Ozk6IdxHSzt1mR0EI= +golang.org/x/crypto v0.0.0-20220112180741-5e0467b6c7ce/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190731235908-ec7cb31e5a56/go.mod h1:JhuoJpWY28nO4Vef9tZUw9qufEGTyX1+7lmHxV5q5G4= golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= -golang.org/x/exp v0.0.0-20191002040644-a1355ae1e2c3/go.mod h1:NOZ3BPKG0ec/BKJQgnvsSFpcKLM5xXVWnvZS97DWHgE= golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= -golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6 h1:QE6XYQK6naiK1EPAe1g/ILLxN5RBoH5xkJk3CqlMI/Y= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= +golang.org/x/exp v0.0.0-20200331195152-e8c3332aa8e5 h1:FR+oGxGfbQu1d+jglI3rCkjAjUnhRSZcUxr+DqlDLNo= +golang.org/x/exp v0.0.0-20200331195152-e8c3332aa8e5/go.mod h1:4M0jN8W1tt0AVLNr8HDosyJCDCDuyL9N9+3m7wDWgKw= golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/image v0.0.0-20190910094157-69e4b8554b2a/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/image v0.0.0-20200119044424-58c23975cae1/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/image v0.0.0-20200430140353-33d19683fad8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/image v0.0.0-20200618115811-c13761719519/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/image v0.0.0-20201208152932-35266b937fa6/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/image v0.0.0-20210216034530-4410531fe030/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= @@ -833,10 +1066,12 @@ golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPI golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= +golang.org/x/mobile v0.0.0-20200801112145-973feb4309de/go.mod h1:skQtrUTUwhdJvXM/2KKJzY8pDgNr9I/FOMqDVRPBUS4= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.1.1-0.20191209134235-331c550502dd/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= @@ -846,6 +1081,7 @@ golang.org/x/mod v0.5.0/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181011144130-49bb7cea24b1/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -857,6 +1093,7 @@ golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -871,6 +1108,7 @@ golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200421231249-e086a090c8fd/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= @@ -880,20 +1118,28 @@ golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81R golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200904194848-62affa334b73/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8= +golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d h1:LO7XpTYMwTqxjLcGWPijK3vRXg1aWdlNOVOHRq45d7c= golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210903162142-ad29c8ab022f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210917221730-978cfadd31cf/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220225172249-27dd8689420f h1:oA4XRj0qtSt8Yo1Zms0CUlsT3KG69V2UGQWPBxujDmc= +golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -939,6 +1185,7 @@ golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190712062909-fae7ac547cb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -951,6 +1198,7 @@ golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191115151921-52ab43148777/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -966,6 +1214,7 @@ golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -975,7 +1224,9 @@ golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200824131525-c12d262b63d8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200909081042-eff7692f9009/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201015000850-e3ed0017c211/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -986,13 +1237,13 @@ golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210304124612-50617c2ba197/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210426230700-d19ff857e887/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -1004,18 +1255,22 @@ golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210816183151-1e6c022a8912/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210903071746-97244b99971b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210917161153-d61c044b1678/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211205182925-97ca703d548d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220204135822-1c1b9b1eba6a h1:ppl5mZgokTT8uPkmYOyEUmPTr3ypaKkg5eFOGrAmxxE= golang.org/x/sys v0.0.0-20220204135822-1c1b9b1eba6a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= -golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -1030,6 +1285,8 @@ golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxb golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -1047,7 +1304,6 @@ golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgw golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20190927191325-030b2cf1153e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -1060,6 +1316,7 @@ golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200117012304-6edc0a871e69/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= @@ -1074,8 +1331,10 @@ golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWc golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200522201501-cb1345f3a375/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200717024301-6ddee64345a6/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= @@ -1099,12 +1358,10 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo= +gonum.org/v1/gonum v0.8.2 h1:CCXrcPKiGGotvnN6jfUsKk4rRqm7q09/YbKb5xCEvtM= gonum.org/v1/gonum v0.8.2/go.mod h1:oe/vMfY3deqTw+1EZJhuvEW2iwGF1bW9wwu7XCu0+v0= -gonum.org/v1/gonum v0.9.3 h1:DnoIG+QAMaF5NvxnGe/oKsgKcAc6PcUyl8q0VetfQ8s= -gonum.org/v1/gonum v0.9.3/go.mod h1:TZumC3NeyVQskjXqmyWt4S3bINhy7B4eYwW69EbyX+0= gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= gonum.org/v1/plot v0.0.0-20190515093506-e2840ee46a6b/go.mod h1:Wt8AAjI+ypCyYX3nZBvf6cAIx93T+c/OS2HFAYskSZc= -gonum.org/v1/plot v0.9.0/go.mod h1:3Pcqqmp6RHvJI72kgb8fThyUnav364FOsdDo2aGW5lY= google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= @@ -1186,6 +1443,7 @@ google.golang.org/genproto v0.0.0-20201119123407-9b1e624d6bc4/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210126160654-44e461bb6506/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= @@ -1206,6 +1464,7 @@ google.golang.org/genproto v0.0.0-20210828152312-66f60bf46e71/go.mod h1:eFjDcFEc google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= google.golang.org/genproto v0.0.0-20210903162649-d08c68adba83/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= google.golang.org/genproto v0.0.0-20210909211513-a8c4777a87af/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210917145530-b395a37504d4/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= google.golang.org/genproto v0.0.0-20210924002016-3dee208752a0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/genproto v0.0.0-20211008145708-270636b82663/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/genproto v0.0.0-20211028162531-8db9c33dc351/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= @@ -1228,6 +1487,7 @@ google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2 google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +google.golang.org/protobuf v1.25.1-0.20200805231151-a709e31e5d12/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ= @@ -1236,6 +1496,7 @@ gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLks gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b h1:QRR6H1YWRnHb4Y/HeNFCTJLFVxaq6wH4YuVdsUOr75U= gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= @@ -1245,9 +1506,12 @@ gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.66.2 h1:XfR1dOYubytKy4Shzc2LHrrGhU0lDCfDGG1yLPmpgsI= gopkg.in/ini.v1 v1.66.2/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce/go.mod h1:5AcXVHNjg+BDxry382+8OKon8SEWiKktQR07RKPsv1c= +gopkg.in/olebedev/go-duktape.v3 v3.0.0-20200619000410-60c24ae608a6/go.mod h1:uAJfkITjFhyEEuUfm7bsmCZRbW5WRq8s9EY8HZ6hCns= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/urfave/cli.v1 v1.20.0/go.mod h1:vuBzUtMdQeixQj8LVd+/98pzhxNGQoyuPBlsXHOQNO0= gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= @@ -1262,6 +1526,7 @@ gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= @@ -1269,9 +1534,12 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +nhooyr.io/websocket v1.8.6 h1:s+C3xAMLwGmlI31Nyn/eAehUlZPwfYZu2JXM621Q5/k= +nhooyr.io/websocket v1.8.6/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= +sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU= diff --git a/internal/conv/doc.go b/internal/conv/doc.go new file mode 100644 index 0000000000..1c86f5c144 --- /dev/null +++ b/internal/conv/doc.go @@ -0,0 +1,2 @@ +// Package conv provides internal functions for convertions and data manipulation +package conv diff --git a/internal/conv/string.go b/internal/conv/string.go new file mode 100644 index 0000000000..ab2b7f44b3 --- /dev/null +++ b/internal/conv/string.go @@ -0,0 +1,26 @@ +package conv + +import ( + "reflect" + "unsafe" +) + +// UnsafeStrToBytes uses unsafe to convert string into byte array. Returned bytes +// must not be altered after this function is called as it will cause a segmentation fault. +func UnsafeStrToBytes(s string) []byte { + var buf []byte + sHdr := (*reflect.StringHeader)(unsafe.Pointer(&s)) + bufHdr := (*reflect.SliceHeader)(unsafe.Pointer(&buf)) + bufHdr.Data = sHdr.Data + bufHdr.Cap = sHdr.Len + bufHdr.Len = sHdr.Len + return buf +} + +// UnsafeBytesToStr is meant to make a zero allocation conversion +// from []byte -> string to speed up operations, it is not meant +// to be used generally, but for a specific pattern to delete keys +// from a map. +func UnsafeBytesToStr(b []byte) string { + return *(*string)(unsafe.Pointer(&b)) +} diff --git a/internal/conv/string_test.go b/internal/conv/string_test.go new file mode 100644 index 0000000000..3a14517531 --- /dev/null +++ b/internal/conv/string_test.go @@ -0,0 +1,54 @@ +package conv + +import ( + "runtime" + "strconv" + "testing" + "time" + + "github.com/stretchr/testify/suite" +) + +func TestStringSuite(t *testing.T) { + suite.Run(t, new(StringSuite)) +} + +type StringSuite struct{ suite.Suite } + +func unsafeConvertStr() []byte { + return UnsafeStrToBytes("abc") +} + +func (s *StringSuite) TestUnsafeStrToBytes() { + // we convert in other function to trigger GC. We want to check that + // the underlying array in []bytes is accessible after GC will finish swapping. + for i := 0; i < 5; i++ { + b := unsafeConvertStr() + runtime.GC() + <-time.NewTimer(2 * time.Millisecond).C + b2 := append(b, 'd') + s.Equal("abc", string(b)) + s.Equal("abcd", string(b2)) + } +} + +func unsafeConvertBytes() string { + return UnsafeBytesToStr([]byte("abc")) +} + +func (s *StringSuite) TestUnsafeBytesToStr() { + // we convert in other function to trigger GC. We want to check that + // the underlying array in []bytes is accessible after GC will finish swapping. + for i := 0; i < 5; i++ { + str := unsafeConvertBytes() + runtime.GC() + <-time.NewTimer(2 * time.Millisecond).C + s.Equal("abc", str) + } +} + +func BenchmarkUnsafeStrToBytes(b *testing.B) { + for i := 0; i < b.N; i++ { + UnsafeStrToBytes(strconv.Itoa(i)) + } +} diff --git a/package-lock.json b/package-lock.json deleted file mode 100644 index a0da4739d2..0000000000 --- a/package-lock.json +++ /dev/null @@ -1,137 +0,0 @@ -{ - "requires": true, - "lockfileVersion": 1, - "dependencies": { - "@types/body-parser": { - "version": "1.19.0", - "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.0.tgz", - "integrity": "sha512-W98JrE0j2K78swW4ukqMleo8R7h/pFETjM2DQ90MF6XK2i4LO4W3gQ71Lt4w3bfm2EvVSyWHplECvB5sK22yFQ==", - "requires": { - "@types/connect": "*", - "@types/node": "*" - } - }, - "@types/connect": { - "version": "3.4.33", - "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.33.tgz", - "integrity": "sha512-2+FrkXY4zllzTNfJth7jOqEHC+enpLeGslEhpnTAkg21GkRrWV4SsAtqchtT4YS9/nODBU2/ZfsBY2X4J/dX7A==", - "requires": { - "@types/node": "*" - } - }, - "@types/express": { - "version": "4.17.6", - "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.6.tgz", - "integrity": "sha512-n/mr9tZI83kd4azlPG5y997C/M4DNABK9yErhFM6hKdym4kkmd9j0vtsJyjFIwfRBxtrxZtAfGZCNRIBMFLK5w==", - "requires": { - "@types/body-parser": "*", - "@types/express-serve-static-core": "*", - "@types/qs": "*", - "@types/serve-static": "*" - } - }, - "@types/express-serve-static-core": { - "version": "4.17.8", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.8.tgz", - "integrity": "sha512-1SJZ+R3Q/7mLkOD9ewCBDYD2k0WyZQtWYqF/2VvoNN2/uhI49J9CDN4OAm+wGMA0DbArA4ef27xl4+JwMtGggw==", - "requires": { - "@types/node": "*", - "@types/qs": "*", - "@types/range-parser": "*" - } - }, - "@types/mime": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@types/mime/-/mime-2.0.2.tgz", - "integrity": "sha512-4kPlzbljFcsttWEq6aBW0OZe6BDajAmyvr2xknBG92tejQnvdGtT9+kXSZ580DqpxY9qG2xeQVF9Dq0ymUTo5Q==" - }, - "@types/node": { - "version": "14.0.14", - "resolved": "https://registry.npmjs.org/@types/node/-/node-14.0.14.tgz", - "integrity": "sha512-syUgf67ZQpaJj01/tRTknkMNoBBLWJOBODF0Zm4NrXmiSuxjymFrxnTu1QVYRubhVkRcZLYZG8STTwJRdVm/WQ==" - }, - "@types/passport": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@types/passport/-/passport-1.0.3.tgz", - "integrity": "sha512-nyztuxtDPQv9utCzU0qW7Gl8BY2Dn8BKlYAFFyxKipFxjaVd96celbkLCV/tRqqBUZ+JB8If3UfgV8347DTo3Q==", - "requires": { - "@types/express": "*" - } - }, - "@types/passport-twitter": { - "version": "1.0.35", - "resolved": "https://registry.npmjs.org/@types/passport-twitter/-/passport-twitter-1.0.35.tgz", - "integrity": "sha512-7ceE/w7bvIqDPdOkPuXSDHTwwCnBW/wpn4vB98AlXieJ31nuCzjWZKWjxtyNpie8/StigN1tzF/YCRGgEh2Seg==", - "requires": { - "@types/express": "*", - "@types/passport": "*" - } - }, - "@types/qs": { - "version": "6.9.3", - "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.3.tgz", - "integrity": "sha512-7s9EQWupR1fTc2pSMtXRQ9w9gLOcrJn+h7HOXw4evxyvVqMi4f+q7d2tnFe3ng3SNHjtK+0EzGMGFUQX4/AQRA==" - }, - "@types/range-parser": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.3.tgz", - "integrity": "sha512-ewFXqrQHlFsgc09MK5jP5iR7vumV/BYayNC6PgJO2LPe8vrnNFyjQjSppfEngITi0qvfKtzFvgKymGheFM9UOA==" - }, - "@types/serve-static": { - "version": "1.13.4", - "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.4.tgz", - "integrity": "sha512-jTDt0o/YbpNwZbQmE/+2e+lfjJEJJR0I3OFaKQKPWkASkCoW3i6fsUnqudSMcNAfbtmADGu8f4MV4q+GqULmug==", - "requires": { - "@types/express-serve-static-core": "*", - "@types/mime": "*" - } - }, - "oauth": { - "version": "0.9.15", - "resolved": "https://registry.npmjs.org/oauth/-/oauth-0.9.15.tgz", - "integrity": "sha1-vR/vr2hslrdUda7VGWQS/2DPucE=" - }, - "passport-oauth1": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/passport-oauth1/-/passport-oauth1-1.1.0.tgz", - "integrity": "sha1-p96YiiEfnPRoc3cTDqdN8ycwyRg=", - "requires": { - "oauth": "0.9.x", - "passport-strategy": "1.x.x", - "utils-merge": "1.x.x" - } - }, - "passport-strategy": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/passport-strategy/-/passport-strategy-1.0.0.tgz", - "integrity": "sha1-tVOaqPwiWj0a0XlHbd8ja0QPUuQ=" - }, - "passport-twitter": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/passport-twitter/-/passport-twitter-1.0.4.tgz", - "integrity": "sha1-AaeZ4fdgvy3knyul+6MigvGJMtc=", - "requires": { - "passport-oauth1": "1.x.x", - "xtraverse": "0.1.x" - } - }, - "utils-merge": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", - "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" - }, - "xmldom": { - "version": "0.1.31", - "resolved": "https://registry.npmjs.org/xmldom/-/xmldom-0.1.31.tgz", - "integrity": "sha512-yS2uJflVQs6n+CyjHoaBmVSqIDevTAWrzMmjG1Gc7h1qQ7uVozNhEPJAwZXWyGQ/Gafo3fCwrcaokezLPupVyQ==" - }, - "xtraverse": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/xtraverse/-/xtraverse-0.1.0.tgz", - "integrity": "sha1-t0G60BjveNip0ug63gB7P3lZxzI=", - "requires": { - "xmldom": "0.1.x" - } - } - } -} diff --git a/proto/ibc/core/client/v1/client.proto b/proto/ibc/core/client/v1/client.proto index b267c4aa84..1a19c713ff 100644 --- a/proto/ibc/core/client/v1/client.proto +++ b/proto/ibc/core/client/v1/client.proto @@ -5,6 +5,7 @@ option go_package = "github.com/line/lbm-sdk/x/ibc/core/02-client/types"; import "gogoproto/gogo.proto"; import "google/protobuf/any.proto"; +import "lbm/upgrade/v1/upgrade.proto"; // IdentifiedClientState defines a client state with an additional client // identifier field. @@ -33,9 +34,11 @@ message ClientConsensusStates { [(gogoproto.moretags) = "yaml:\"consensus_states\"", (gogoproto.nullable) = false]; } -// ClientUpdateProposal is a governance proposal. If it passes, the client is -// updated with the provided header. The update may fail if the header is not -// valid given certain conditions specified by the client implementation. +// ClientUpdateProposal is a governance proposal. If it passes, the substitute client's +// consensus states starting from the 'initial height' are copied over to the subjects +// client state. The proposal handler may fail if the subject and the substitute do not +// match in client and chain parameters (with exception to latest height, frozen height, and chain-id). +// The updated client must also be valid (cannot be expired). message ClientUpdateProposal { option (gogoproto.goproto_getters) = false; // the title of the update proposal @@ -43,9 +46,30 @@ message ClientUpdateProposal { // the description of the proposal string description = 2; // the client identifier for the client to be updated if the proposal passes - string client_id = 3 [(gogoproto.moretags) = "yaml:\"client_id\""]; - // the header used to update the client if the proposal passes - google.protobuf.Any header = 4; + string subject_client_id = 3 [(gogoproto.moretags) = "yaml:\"subject_client_id\""]; + // the substitute client identifier for the client standing in for the subject client + string substitute_client_id = 4 [(gogoproto.moretags) = "yaml:\"susbtitute_client_id\""]; + // the intital height to copy consensus states from the substitute to the subject + Height initial_height = 5 [(gogoproto.moretags) = "yaml:\"initial_height\"", (gogoproto.nullable) = false]; +} + +// UpgradeProposal is a gov Content type for initiating an IBC breaking +// upgrade. +message UpgradeProposal { + option (gogoproto.goproto_getters) = false; + option (gogoproto.goproto_stringer) = false; + option (gogoproto.equal) = true; + + string title = 1; + string description = 2; + lbm.upgrade.v1.Plan plan = 3 [(gogoproto.nullable) = false]; + + // An UpgradedClientState must be provided to perform an IBC breaking upgrade. + // This will make the chain commit to the correct upgraded (self) client state before the upgrade occurs, + // so that connecting chains can verify that the new upgraded client is valid by verifying a proof on the + // previous version of the chain. + // This will allow IBC connections to persist smoothly across planned chain upgrades + google.protobuf.Any upgraded_client_state = 4 [(gogoproto.moretags) = "yaml:\"upgraded_client_state\""]; } // Height is a monotonically increasing data type diff --git a/proto/ibc/core/client/v1/query.proto b/proto/ibc/core/client/v1/query.proto index 492ecec658..a7e9b8727c 100644 --- a/proto/ibc/core/client/v1/query.proto +++ b/proto/ibc/core/client/v1/query.proto @@ -38,6 +38,11 @@ service Query { rpc ClientParams(QueryClientParamsRequest) returns (QueryClientParamsResponse) { option (google.api.http).get = "/ibc/client/v1/params"; } + + // UpgradedClientState queries an Upgraded IBC light client. + rpc UpgradedClientState(QueryUpgradedClientStateRequest) returns (QueryUpgradedClientStateResponse) { + option (google.api.http).get = "/ibc/core/client/v1/upgraded_client_states/{client_id}"; + } } // QueryClientStateRequest is the request type for the Query/ClientState RPC @@ -128,3 +133,20 @@ message QueryClientParamsResponse { // params defines the parameters of the module. Params params = 1; } + +// QueryUpgradedClientStateRequest is the request type for the Query/UpgradedClientState RPC +// method +message QueryUpgradedClientStateRequest { + // client state unique identifier + string client_id = 1; + // plan height of the current chain must be sent in request + // as this is the height under which upgraded client state is stored + int64 plan_height = 2; +} + +// QueryUpgradedClientStateResponse is the response type for the Query/UpgradedClientState RPC +// method. +message QueryUpgradedClientStateResponse { + // client state associated with the request identifier + google.protobuf.Any upgraded_client_state = 1; +} diff --git a/proto/lbm/auth/v1/auth.proto b/proto/lbm/auth/v1/auth.proto index db693d5e89..77ab9c8d37 100644 --- a/proto/lbm/auth/v1/auth.proto +++ b/proto/lbm/auth/v1/auth.proto @@ -4,6 +4,7 @@ package lbm.auth.v1; import "lbm/crypto/ed25519/keys.proto"; import "lbm/crypto/multisig/keys.proto"; import "lbm/crypto/secp256k1/keys.proto"; +import "lbm/crypto/secp256r1/keys.proto"; import "cosmos_proto/cosmos.proto"; import "gogoproto/gogo.proto"; @@ -24,10 +25,12 @@ message BaseAccount { [(gogoproto.jsontag) = "ed25519_public_key,omitempty", (gogoproto.moretags) = "yaml:\"ed25519_public_key\""]; lbm.crypto.secp256k1.PubKey secp256k1_pub_key = 3 [(gogoproto.jsontag) = "secp256k1_public_key,omitempty", (gogoproto.moretags) = "yaml:\"secp256k1_public_key\""]; - lbm.crypto.multisig.LegacyAminoPubKey multisig_pub_key = 4 + lbm.crypto.secp256r1.PubKey secp256r1_pub_key = 4 + [(gogoproto.jsontag) = "secp256r1_public_key,omitempty", (gogoproto.moretags) = "yaml:\"secp256r1_public_key\""]; + lbm.crypto.multisig.LegacyAminoPubKey multisig_pub_key = 5 [(gogoproto.jsontag) = "multisig_public_key,omitempty", (gogoproto.moretags) = "yaml:\"multisig_public_key\""]; - uint64 account_number = 5 [(gogoproto.moretags) = "yaml:\"account_number\""]; - uint64 sequence = 6; + uint64 account_number = 6 [(gogoproto.moretags) = "yaml:\"account_number\""]; + uint64 sequence = 7; } // ModuleAccount defines an account for modules that holds coins on a pool. diff --git a/proto/lbm/auth/v1/query.proto b/proto/lbm/auth/v1/query.proto index 3d26eb3424..0084e805c2 100644 --- a/proto/lbm/auth/v1/query.proto +++ b/proto/lbm/auth/v1/query.proto @@ -1,6 +1,7 @@ syntax = "proto3"; package lbm.auth.v1; +import "lbm/base/query/v1/pagination.proto"; import "gogoproto/gogo.proto"; import "google/protobuf/any.proto"; import "google/api/annotations.proto"; @@ -11,6 +12,13 @@ option go_package = "github.com/line/lbm-sdk/x/auth/types"; // Query defines the gRPC querier service. service Query { + // Accounts returns all the existing accounts + // + // Since: cosmos-sdk 0.43 + rpc Accounts(QueryAccountsRequest) returns (QueryAccountsResponse) { + option (google.api.http).get = "/lbm/auth/v1/accounts"; + } + // Account returns account details based on address. rpc Account(QueryAccountRequest) returns (QueryAccountResponse) { option (google.api.http).get = "/lbm/auth/v1/accounts/{address}"; @@ -22,6 +30,25 @@ service Query { } } +// QueryAccountsRequest is the request type for the Query/Accounts RPC method. +// +// Since: cosmos-sdk 0.43 +message QueryAccountsRequest { + // pagination defines an optional pagination for the request. + lbm.base.query.v1.PageRequest pagination = 1; +} + +// QueryAccountsResponse is the response type for the Query/Accounts RPC method. +// +// Since: cosmos-sdk 0.43 +message QueryAccountsResponse { + // accounts are the existing accounts + repeated google.protobuf.Any accounts = 1 [(cosmos_proto.accepts_interface) = "AccountI"]; + + // pagination defines the pagination in the response. + lbm.base.query.v1.PageResponse pagination = 2; +} + // QueryAccountRequest is the request type for the Query/Account RPC method. message QueryAccountRequest { option (gogoproto.equal) = false; diff --git a/proto/lbm/authz/v1/authz.proto b/proto/lbm/authz/v1/authz.proto new file mode 100644 index 0000000000..7ef40853ed --- /dev/null +++ b/proto/lbm/authz/v1/authz.proto @@ -0,0 +1,28 @@ +// Since: cosmos-sdk 0.43 +syntax = "proto3"; +package lbm.authz.v1; + +import "lbm/base/v1/coin.proto"; +import "cosmos_proto/cosmos.proto"; +import "google/protobuf/timestamp.proto"; +import "gogoproto/gogo.proto"; +import "google/protobuf/any.proto"; + +option go_package = "github.com/line/lbm-sdk/x/authz"; +option (gogoproto.goproto_getters_all) = false; + +// GenericAuthorization gives the grantee unrestricted permissions to execute +// the provided method on behalf of the granter's account. +message GenericAuthorization { + option (cosmos_proto.implements_interface) = "Authorization"; + + // Msg, identified by it's type URL, to grant unrestricted permissions to execute + string msg = 1; +} + +// Grant gives permissions to execute +// the provide method with expiration time. +message Grant { + google.protobuf.Any authorization = 1 [(cosmos_proto.accepts_interface) = "Authorization"]; + google.protobuf.Timestamp expiration = 2 [(gogoproto.stdtime) = true, (gogoproto.nullable) = false]; +} diff --git a/proto/lbm/authz/v1/event.proto b/proto/lbm/authz/v1/event.proto new file mode 100644 index 0000000000..2c9ee5dafd --- /dev/null +++ b/proto/lbm/authz/v1/event.proto @@ -0,0 +1,25 @@ +// Since: cosmos-sdk 0.43 +syntax = "proto3"; +package lbm.authz.v1; + +option go_package = "github.com/line/lbm-sdk/x/authz"; + +// EventGrant is emitted on Msg/Grant +message EventGrant { + // Msg type URL for which an autorization is granted + string msg_type_url = 2; + // Granter account address + string granter = 3; + // Grantee account address + string grantee = 4; +} + +// EventRevoke is emitted on Msg/Revoke +message EventRevoke { + // Msg type URL for which an autorization is revoked + string msg_type_url = 2; + // Granter account address + string granter = 3; + // Grantee account address + string grantee = 4; +} diff --git a/proto/lbm/authz/v1/genesis.proto b/proto/lbm/authz/v1/genesis.proto new file mode 100644 index 0000000000..4abf1b72e6 --- /dev/null +++ b/proto/lbm/authz/v1/genesis.proto @@ -0,0 +1,25 @@ +// Since: cosmos-sdk 0.43 +syntax = "proto3"; +package lbm.authz.v1; + +import "google/protobuf/timestamp.proto"; +import "google/protobuf/any.proto"; +import "gogoproto/gogo.proto"; +import "cosmos_proto/cosmos.proto"; +import "lbm/authz/v1/tx.proto"; + +option go_package = "github.com/line/lbm-sdk/x/authz"; + +// GenesisState defines the authz module's genesis state. +message GenesisState { + repeated GrantAuthorization authorization = 1 [(gogoproto.nullable) = false]; +} + +// GrantAuthorization defines the GenesisState/GrantAuthorization type. +message GrantAuthorization { + string granter = 1; + string grantee = 2; + + google.protobuf.Any authorization = 3 [(cosmos_proto.accepts_interface) = "Authorization"]; + google.protobuf.Timestamp expiration = 4 [(gogoproto.nullable) = false, (gogoproto.stdtime) = true]; +} diff --git a/proto/lbm/authz/v1/query.proto b/proto/lbm/authz/v1/query.proto new file mode 100644 index 0000000000..b4fc5e0313 --- /dev/null +++ b/proto/lbm/authz/v1/query.proto @@ -0,0 +1,36 @@ +// Since: cosmos-sdk 0.43 +syntax = "proto3"; +package lbm.authz.v1; + +import "google/api/annotations.proto"; +import "cosmos_proto/cosmos.proto"; +import "lbm/base/query/v1/pagination.proto"; +import "lbm/authz/v1/authz.proto"; + +option go_package = "github.com/line/lbm-sdk/x/authz"; + +// Query defines the gRPC querier service. +service Query { + // Returns list of `Authorization`, granted to the grantee by the granter. + rpc Grants(QueryGrantsRequest) returns (QueryGrantsResponse) { + option (google.api.http).get = "/lbm/authz/v1/grants"; + } +} + +// QueryGrantsRequest is the request type for the Query/Grants RPC method. +message QueryGrantsRequest { + string granter = 1; + string grantee = 2; + // Optional, msg_type_url, when set, will query only grants matching given msg type. + string msg_type_url = 3; + // pagination defines an pagination for the request. + lbm.base.query.v1.PageRequest pagination = 4; +} + +// QueryGrantsResponse is the response type for the Query/Authorizations RPC method. +message QueryGrantsResponse { + // authorizations is a list of grants granted for grantee by granter. + repeated lbm.authz.v1.Grant grants = 1; + // pagination defines an pagination for the response. + lbm.base.query.v1.PageResponse pagination = 2; +} diff --git a/proto/lbm/authz/v1/tx.proto b/proto/lbm/authz/v1/tx.proto new file mode 100644 index 0000000000..c6e061d09c --- /dev/null +++ b/proto/lbm/authz/v1/tx.proto @@ -0,0 +1,70 @@ +// Since: cosmos-sdk 0.43 +syntax = "proto3"; +package lbm.authz.v1; + +import "cosmos_proto/cosmos.proto"; +import "gogoproto/gogo.proto"; +import "google/protobuf/timestamp.proto"; +import "google/protobuf/any.proto"; +import "lbm/base/abci/v1/abci.proto"; +import "lbm/authz/v1/authz.proto"; + +option go_package = "github.com/line/lbm-sdk/x/authz"; +option (gogoproto.goproto_getters_all) = false; + +// Msg defines the authz Msg service. +service Msg { + // Grant grants the provided authorization to the grantee on the granter's + // account with the provided expiration time. If there is already a grant + // for the given (granter, grantee, Authorization) triple, then the grant + // will be overwritten. + rpc Grant(MsgGrant) returns (MsgGrantResponse); + + // Exec attempts to execute the provided messages using + // authorizations granted to the grantee. Each message should have only + // one signer corresponding to the granter of the authorization. + rpc Exec(MsgExec) returns (MsgExecResponse); + + // Revoke revokes any authorization corresponding to the provided method name on the + // granter's account that has been granted to the grantee. + rpc Revoke(MsgRevoke) returns (MsgRevokeResponse); +} + +// MsgGrant is a request type for Grant method. It declares authorization to the grantee +// on behalf of the granter with the provided expiration time. +message MsgGrant { + string granter = 1; + string grantee = 2; + + lbm.authz.v1.Grant grant = 3 [(gogoproto.nullable) = false]; +} + +// MsgExecResponse defines the Msg/MsgExecResponse response type. +message MsgExecResponse { + repeated bytes results = 1; +} + +// MsgExec attempts to execute the provided messages using +// authorizations granted to the grantee. Each message should have only +// one signer corresponding to the granter of the authorization. +message MsgExec { + string grantee = 1; + // Authorization Msg requests to execute. Each msg must implement Authorization interface + // The x/authz will try to find a grant matching (msg.signers[0], grantee, MsgTypeURL(msg)) + // triple and validate it. + repeated google.protobuf.Any msgs = 2 [(cosmos_proto.accepts_interface) = "sdk.Msg, authz.Authorization"]; +} + +// MsgGrantResponse defines the Msg/MsgGrant response type. +message MsgGrantResponse {} + +// MsgRevoke revokes any authorization with the provided sdk.Msg type on the +// granter's account with that has been granted to the grantee. +message MsgRevoke { + string granter = 1; + string grantee = 2; + string msg_type_url = 3; +} + +// MsgRevokeResponse defines the Msg/MsgRevokeResponse response type. +message MsgRevokeResponse {} diff --git a/proto/lbm/bank/v1/authz.proto b/proto/lbm/bank/v1/authz.proto new file mode 100644 index 0000000000..cca1cbea27 --- /dev/null +++ b/proto/lbm/bank/v1/authz.proto @@ -0,0 +1,19 @@ +syntax = "proto3"; +package lbm.bank.v1; + +import "gogoproto/gogo.proto"; +import "cosmos_proto/cosmos.proto"; +import "lbm/base/v1/coin.proto"; + +option go_package = "github.com/line/lbm-sdk/x/bank/types"; + +// SendAuthorization allows the grantee to spend up to spend_limit coins from +// the granter's account. +// +// Since: cosmos-sdk 0.43 +message SendAuthorization { + option (cosmos_proto.implements_interface) = "Authorization"; + + repeated lbm.base.v1.Coin spend_limit = 1 + [(gogoproto.nullable) = false, (gogoproto.castrepeated) = "github.com/line/lbm-sdk/types.Coins"]; +} diff --git a/proto/lbm/bank/v1/bank.proto b/proto/lbm/bank/v1/bank.proto index 9a99db6436..c02a312f93 100644 --- a/proto/lbm/bank/v1/bank.proto +++ b/proto/lbm/bank/v1/bank.proto @@ -45,12 +45,14 @@ message Output { // Supply represents a struct that passively keeps track of the total supply // amounts in the network. +// This message is deprecated now that supply is indexed by denom. message Supply { - option (gogoproto.equal) = true; - option (gogoproto.goproto_getters) = false; - option (gogoproto.goproto_stringer) = false; + option deprecated = true; + + option (gogoproto.equal) = true; + option (gogoproto.goproto_getters) = false; - option (cosmos_proto.implements_interface) = "*github.com/line/lbm-sdk/x/bank/exported.SupplyI"; + option (cosmos_proto.implements_interface) = "*github.com/line/lbm-sdk/x/bank/legacy/v040.SupplyI"; repeated lbm.base.v1.Coin total = 1 [(gogoproto.nullable) = false, (gogoproto.castrepeated) = "github.com/line/lbm-sdk/types.Coins"]; @@ -82,4 +84,13 @@ message Metadata { // display indicates the suggested denom that should be // displayed in clients. string display = 4; + // name defines the name of the token (eg: Cosmos Atom) + // + // Since: cosmos-sdk 0.43 + string name = 5; + // symbol is the token symbol usually shown on exchanges (eg: ATOM). This can + // be the same as the display. + // + // Since: cosmos-sdk 0.43 + string symbol = 6; } diff --git a/proto/lbm/bank/v1/genesis.proto b/proto/lbm/bank/v1/genesis.proto index 729748e94a..157e531575 100644 --- a/proto/lbm/bank/v1/genesis.proto +++ b/proto/lbm/bank/v1/genesis.proto @@ -15,7 +15,8 @@ message GenesisState { // balances is an array containing the balances of all the accounts. repeated Balance balances = 2 [(gogoproto.nullable) = false]; - // supply represents the total supply. + // supply represents the total supply. If it is left empty, then supply will be calculated based on the provided + // balances. Otherwise, it will be used to validate that the sum of the balances equals this amount. repeated lbm.base.v1.Coin supply = 3 [(gogoproto.castrepeated) = "github.com/line/lbm-sdk/types.Coins", (gogoproto.nullable) = false]; diff --git a/proto/lbm/bank/v1/query.proto b/proto/lbm/bank/v1/query.proto index 5c60803107..d9bc7785a3 100644 --- a/proto/lbm/bank/v1/query.proto +++ b/proto/lbm/bank/v1/query.proto @@ -90,7 +90,15 @@ message QueryAllBalancesResponse { // QueryTotalSupplyRequest is the request type for the Query/TotalSupply RPC // method. -message QueryTotalSupplyRequest {} +message QueryTotalSupplyRequest { + option (gogoproto.equal) = false; + option (gogoproto.goproto_getters) = false; + + // pagination defines an optional pagination for the request. + // + // Since: cosmos-sdk 0.43 + lbm.base.query.v1.PageRequest pagination = 1; +} // QueryTotalSupplyResponse is the response type for the Query/TotalSupply RPC // method @@ -98,6 +106,11 @@ message QueryTotalSupplyResponse { // supply is the supply of the coins repeated lbm.base.v1.Coin supply = 1 [(gogoproto.nullable) = false, (gogoproto.castrepeated) = "github.com/line/lbm-sdk/types.Coins"]; + + // pagination defines the pagination in the response. + // + // Since: cosmos-sdk 0.43 + lbm.base.query.v1.PageResponse pagination = 2; } // QuerySupplyOfRequest is the request type for the Query/SupplyOf RPC method. diff --git a/proto/lbm/base/ostracon/v1/query.proto b/proto/lbm/base/ostracon/v1/query.proto index 760d024386..0e00bdfbfe 100644 --- a/proto/lbm/base/ostracon/v1/query.proto +++ b/proto/lbm/base/ostracon/v1/query.proto @@ -148,14 +148,15 @@ message GetNodeInfoResponse { // VersionInfo is the type for the GetNodeInfoResponse message. message VersionInfo { - string name = 1; - string app_name = 2; - string version = 3; - string git_commit = 4; - string build_tags = 5; - string go_version = 6; - repeated Module build_deps = 7; - string lbm_sdk_version = 8; + string name = 1; + string app_name = 2; + string version = 3; + string git_commit = 4; + string build_tags = 5; + string go_version = 6; + repeated Module build_deps = 7; + // Since: cosmos-sdk 0.43 + string lbm_sdk_version = 8; } // Module is the type for VersionInfo diff --git a/proto/lbm/base/query/v1/pagination.proto b/proto/lbm/base/query/v1/pagination.proto index 3eb14baa83..ccafe7f343 100644 --- a/proto/lbm/base/query/v1/pagination.proto +++ b/proto/lbm/base/query/v1/pagination.proto @@ -30,6 +30,11 @@ message PageRequest { // count_total is only respected when offset is used. It is ignored when key // is set. bool count_total = 4; + + // reverse is set to true if results are to be returned in the descending order. + // + // Since: cosmos-sdk 0.43 + bool reverse = 5; } // PageResponse is to be embedded in gRPC response messages where the diff --git a/proto/lbm/base/reflection/v2/reflection.proto b/proto/lbm/base/reflection/v2/reflection.proto new file mode 100644 index 0000000000..b8c054ef4a --- /dev/null +++ b/proto/lbm/base/reflection/v2/reflection.proto @@ -0,0 +1,218 @@ +// Since: cosmos-sdk 0.43 +syntax = "proto3"; +package lbm.base.reflection.v2; + +import "google/api/annotations.proto"; + +option go_package = "github.com/line/lbm-sdk/server/grpc/reflection/v2"; + +// AppDescriptor describes a cosmos-sdk based application +message AppDescriptor { + // AuthnDescriptor provides information on how to authenticate transactions on the application + // NOTE: experimental and subject to change in future releases. + AuthnDescriptor authn = 1; + // chain provides the chain descriptor + ChainDescriptor chain = 2; + // codec provides metadata information regarding codec related types + CodecDescriptor codec = 3; + // configuration provides metadata information regarding the sdk.Config type + ConfigurationDescriptor configuration = 4; + // query_services provides metadata information regarding the available queriable endpoints + QueryServicesDescriptor query_services = 5; + // tx provides metadata information regarding how to send transactions to the given application + TxDescriptor tx = 6; +} + +// TxDescriptor describes the accepted transaction type +message TxDescriptor { + // fullname is the protobuf fullname of the raw transaction type (for instance the tx.Tx type) + // it is not meant to support polymorphism of transaction types, it is supposed to be used by + // reflection clients to understand if they can handle a specific transaction type in an application. + string fullname = 1; + // msgs lists the accepted application messages (sdk.Msg) + repeated MsgDescriptor msgs = 2; +} + +// AuthnDescriptor provides information on how to sign transactions without relying +// on the online RPCs GetTxMetadata and CombineUnsignedTxAndSignatures +message AuthnDescriptor { + // sign_modes defines the supported signature algorithm + repeated SigningModeDescriptor sign_modes = 1; +} + +// SigningModeDescriptor provides information on a signing flow of the application +// NOTE(fdymylja): here we could go as far as providing an entire flow on how +// to sign a message given a SigningModeDescriptor, but it's better to think about +// this another time +message SigningModeDescriptor { + // name defines the unique name of the signing mode + string name = 1; + // number is the unique int32 identifier for the sign_mode enum + int32 number = 2; + // authn_info_provider_method_fullname defines the fullname of the method to call to get + // the metadata required to authenticate using the provided sign_modes + string authn_info_provider_method_fullname = 3; +} + +// ChainDescriptor describes chain information of the application +message ChainDescriptor { + // id is the chain id + string id = 1; +} + +// CodecDescriptor describes the registered interfaces and provides metadata information on the types +message CodecDescriptor { + // interfaces is a list of the registerted interfaces descriptors + repeated InterfaceDescriptor interfaces = 1; +} + +// InterfaceDescriptor describes the implementation of an interface +message InterfaceDescriptor { + // fullname is the name of the interface + string fullname = 1; + // interface_accepting_messages contains information regarding the proto messages which contain the interface as + // google.protobuf.Any field + repeated InterfaceAcceptingMessageDescriptor interface_accepting_messages = 2; + // interface_implementers is a list of the descriptors of the interface implementers + repeated InterfaceImplementerDescriptor interface_implementers = 3; +} + +// InterfaceImplementerDescriptor describes an interface implementer +message InterfaceImplementerDescriptor { + // fullname is the protobuf queryable name of the interface implementer + string fullname = 1; + // type_url defines the type URL used when marshalling the type as any + // this is required so we can provide type safe google.protobuf.Any marshalling and + // unmarshalling, making sure that we don't accept just 'any' type + // in our interface fields + string type_url = 2; +} + +// InterfaceAcceptingMessageDescriptor describes a protobuf message which contains +// an interface represented as a google.protobuf.Any +message InterfaceAcceptingMessageDescriptor { + // fullname is the protobuf fullname of the type containing the interface + string fullname = 1; + // field_descriptor_names is a list of the protobuf name (not fullname) of the field + // which contains the interface as google.protobuf.Any (the interface is the same, but + // it can be in multiple fields of the same proto message) + repeated string field_descriptor_names = 2; +} + +// ConfigurationDescriptor contains metadata information on the sdk.Config +message ConfigurationDescriptor { + // bech32_account_address_prefix is the account address prefix + string bech32_account_address_prefix = 1; +} + +// MsgDescriptor describes a cosmos-sdk message that can be delivered with a transaction +message MsgDescriptor { + // msg_type_url contains the TypeURL of a sdk.Msg. + string msg_type_url = 1; +} + +// ReflectionService defines a service for application reflection. +service ReflectionService { + // GetAuthnDescriptor returns information on how to authenticate transactions in the application + // NOTE: this RPC is still experimental and might be subject to breaking changes or removal in + // future releases of the cosmos-sdk. + rpc GetAuthnDescriptor(GetAuthnDescriptorRequest) returns (GetAuthnDescriptorResponse) { + option (google.api.http).get = "/lbm/base/reflection/v1/app_descriptor/authn"; + } + // GetChainDescriptor returns the description of the chain + rpc GetChainDescriptor(GetChainDescriptorRequest) returns (GetChainDescriptorResponse) { + option (google.api.http).get = "/lbm/base/reflection/v1/app_descriptor/chain"; + }; + // GetCodecDescriptor returns the descriptor of the codec of the application + rpc GetCodecDescriptor(GetCodecDescriptorRequest) returns (GetCodecDescriptorResponse) { + option (google.api.http).get = "/lbm/base/reflection/v1/app_descriptor/codec"; + } + // GetConfigurationDescriptor returns the descriptor for the sdk.Config of the application + rpc GetConfigurationDescriptor(GetConfigurationDescriptorRequest) returns (GetConfigurationDescriptorResponse) { + option (google.api.http).get = "/lbm/base/reflection/v1/app_descriptor/configuration"; + } + // GetQueryServicesDescriptor returns the available gRPC queryable services of the application + rpc GetQueryServicesDescriptor(GetQueryServicesDescriptorRequest) returns (GetQueryServicesDescriptorResponse) { + option (google.api.http).get = "/lbm/base/reflection/v1/app_descriptor/query_services"; + } + // GetTxDescriptor returns information on the used transaction object and available msgs that can be used + rpc GetTxDescriptor(GetTxDescriptorRequest) returns (GetTxDescriptorResponse) { + option (google.api.http).get = "/lbm/base/reflection/v1/app_descriptor/tx_descriptor"; + } +} + +// GetAuthnDescriptorRequest is the request used for the GetAuthnDescriptor RPC +message GetAuthnDescriptorRequest {} +// GetAuthnDescriptorResponse is the response returned by the GetAuthnDescriptor RPC +message GetAuthnDescriptorResponse { + // authn describes how to authenticate to the application when sending transactions + AuthnDescriptor authn = 1; +} + +// GetChainDescriptorRequest is the request used for the GetChainDescriptor RPC +message GetChainDescriptorRequest {} +// GetChainDescriptorResponse is the response returned by the GetChainDescriptor RPC +message GetChainDescriptorResponse { + // chain describes application chain information + ChainDescriptor chain = 1; +} + +// GetCodecDescriptorRequest is the request used for the GetCodecDescriptor RPC +message GetCodecDescriptorRequest {} +// GetCodecDescriptorResponse is the response returned by the GetCodecDescriptor RPC +message GetCodecDescriptorResponse { + // codec describes the application codec such as registered interfaces and implementations + CodecDescriptor codec = 1; +} + +// GetConfigurationDescriptorRequest is the request used for the GetConfigurationDescriptor RPC +message GetConfigurationDescriptorRequest {} +// GetConfigurationDescriptorResponse is the response returned by the GetConfigurationDescriptor RPC +message GetConfigurationDescriptorResponse { + // config describes the application's sdk.Config + ConfigurationDescriptor config = 1; +} + +// GetQueryServicesDescriptorRequest is the request used for the GetQueryServicesDescriptor RPC +message GetQueryServicesDescriptorRequest {} +// GetQueryServicesDescriptorResponse is the response returned by the GetQueryServicesDescriptor RPC +message GetQueryServicesDescriptorResponse { + // queries provides information on the available queryable services + QueryServicesDescriptor queries = 1; +} + +// GetTxDescriptorRequest is the request used for the GetTxDescriptor RPC +message GetTxDescriptorRequest {} +// GetTxDescriptorResponse is the response returned by the GetTxDescriptor RPC +message GetTxDescriptorResponse { + // tx provides information on msgs that can be forwarded to the application + // alongside the accepted transaction protobuf type + TxDescriptor tx = 1; +} + +// QueryServicesDescriptor contains the list of cosmos-sdk queriable services +message QueryServicesDescriptor { + // query_services is a list of cosmos-sdk QueryServiceDescriptor + repeated QueryServiceDescriptor query_services = 1; +} + +// QueryServiceDescriptor describes a cosmos-sdk queryable service +message QueryServiceDescriptor { + // fullname is the protobuf fullname of the service descriptor + string fullname = 1; + // is_module describes if this service is actually exposed by an application's module + bool is_module = 2; + // methods provides a list of query service methods + repeated QueryMethodDescriptor methods = 3; +} + +// QueryMethodDescriptor describes a queryable method of a query service +// no other info is provided beside method name and tendermint queryable path +// because it would be redundant with the grpc reflection service +message QueryMethodDescriptor { + // name is the protobuf name (not fullname) of the method + string name = 1; + // full_query_path is the path that can be used to query + // this method via tendermint abci.Query + string full_query_path = 2; +} diff --git a/proto/lbm/base/store/v1/listening.proto b/proto/lbm/base/store/v1/listening.proto new file mode 100644 index 0000000000..32f9c47083 --- /dev/null +++ b/proto/lbm/base/store/v1/listening.proto @@ -0,0 +1,16 @@ +syntax = "proto3"; +package lbm.base.store.v1; + +option go_package = "github.com/line/lbm-sdk/store/types"; + +// StoreKVPair is a KVStore KVPair used for listening to state changes (Sets and Deletes) +// It optionally includes the StoreKey for the originating KVStore and a Boolean flag to distinguish between Sets and +// Deletes +// +// Since: cosmos-sdk 0.43 +message StoreKVPair { + string store_key = 1; // the store key for the KVStore this pair originates from + bool delete = 2; // true indicates a delete operation, false indicates a set operation + bytes key = 3; + bytes value = 4; +} diff --git a/proto/lbm/crypto/ed25519/keys.proto b/proto/lbm/crypto/ed25519/keys.proto index 6209d94a06..3de2f6ac77 100644 --- a/proto/lbm/crypto/ed25519/keys.proto +++ b/proto/lbm/crypto/ed25519/keys.proto @@ -5,18 +5,19 @@ import "gogoproto/gogo.proto"; option go_package = "github.com/line/lbm-sdk/crypto/keys/ed25519"; -// PubKey defines a ed25519 public key -// Key is the compressed form of the pubkey. The first byte depends is a 0x02 byte -// if the y-coordinate is the lexicographically largest of the two associated with -// the x-coordinate. Otherwise the first byte is a 0x03. -// This prefix is followed with the x-coordinate. +// PubKey is an ed25519 public key for handling Tendermint keys in SDK. +// It's needed for Any serialization and SDK compatibility. +// It must not be used in a non Tendermint key context because it doesn't implement +// ADR-28. Nevertheless, you will like to use ed25519 in app user level +// then you must create a new proto message and follow ADR-28 for Address construction. message PubKey { option (gogoproto.goproto_stringer) = false; bytes key = 1 [(gogoproto.casttype) = "crypto/ed25519.PublicKey"]; } -// PrivKey defines a ed25519 private key. +// Deprecated: PrivKey defines a ed25519 private key. +// NOTE: ed25519 keys must not be used in SDK apps except in a tendermint validator context. message PrivKey { bytes key = 1 [(gogoproto.casttype) = "crypto/ed25519.PrivateKey"]; } diff --git a/proto/lbm/crypto/secp256r1/keys.proto b/proto/lbm/crypto/secp256r1/keys.proto new file mode 100644 index 0000000000..ef6cea343c --- /dev/null +++ b/proto/lbm/crypto/secp256r1/keys.proto @@ -0,0 +1,23 @@ +// Since: cosmos-sdk 0.43 +syntax = "proto3"; +package lbm.crypto.secp256r1; + +import "gogoproto/gogo.proto"; + +option go_package = "github.com/line/lbm-sdk/crypto/keys/secp256r1"; +option (gogoproto.messagename_all) = true; +option (gogoproto.goproto_stringer_all) = false; +option (gogoproto.goproto_getters_all) = false; + +// PubKey defines a secp256r1 ECDSA public key. +message PubKey { + // Point on secp256r1 curve in a compressed representation as specified in section + // 4.3.6 of ANSI X9.62: https://webstore.ansi.org/standards/ascx9/ansix9621998 + bytes key = 1 [(gogoproto.customtype) = "ecdsaPK"]; +} + +// PrivKey defines a secp256r1 ECDSA private key. +message PrivKey { + // secret number serialized using big-endian encoding + bytes secret = 1 [(gogoproto.customtype) = "ecdsaSK"]; +} diff --git a/proto/lbm/feegrant/v1/feegrant.proto b/proto/lbm/feegrant/v1/feegrant.proto index aab73c3935..68a51eb2dc 100644 --- a/proto/lbm/feegrant/v1/feegrant.proto +++ b/proto/lbm/feegrant/v1/feegrant.proto @@ -1,3 +1,4 @@ +// Since: cosmos-sdk 0.43 syntax = "proto3"; package lbm.feegrant.v1; @@ -8,7 +9,7 @@ import "lbm/base/v1/coin.proto"; import "google/protobuf/timestamp.proto"; import "google/protobuf/duration.proto"; -option go_package = "github.com/line/lbm-sdk/x/feegrant/types"; +option go_package = "github.com/line/lbm-sdk/x/feegrant"; // BasicAllowance implements Allowance with a one-time grant of tokens // that optionally expires. The grantee can use up to SpendLimit to cover fees. diff --git a/proto/lbm/feegrant/v1/genesis.proto b/proto/lbm/feegrant/v1/genesis.proto index b1755309a1..3cd2caf99a 100644 --- a/proto/lbm/feegrant/v1/genesis.proto +++ b/proto/lbm/feegrant/v1/genesis.proto @@ -1,10 +1,11 @@ +// Since: cosmos-sdk 0.43 syntax = "proto3"; package lbm.feegrant.v1; import "gogoproto/gogo.proto"; import "lbm/feegrant/v1/feegrant.proto"; -option go_package = "github.com/line/lbm-sdk/x/feegrant/types"; +option go_package = "github.com/line/lbm-sdk/x/feegrant"; // GenesisState contains a set of fee allowances, persisted from the store message GenesisState { diff --git a/proto/lbm/feegrant/v1/query.proto b/proto/lbm/feegrant/v1/query.proto index 50135a3c24..762eeabee5 100644 --- a/proto/lbm/feegrant/v1/query.proto +++ b/proto/lbm/feegrant/v1/query.proto @@ -1,3 +1,4 @@ +// Since: cosmos-sdk 0.43 syntax = "proto3"; package lbm.feegrant.v1; @@ -6,7 +7,7 @@ import "lbm/feegrant/v1/feegrant.proto"; import "lbm/base/query/v1/pagination.proto"; import "google/api/annotations.proto"; -option go_package = "github.com/line/lbm-sdk/x/feegrant/types"; +option go_package = "github.com/line/lbm-sdk/x/feegrant"; // Query defines the gRPC querier service. service Query { diff --git a/proto/lbm/feegrant/v1/tx.proto b/proto/lbm/feegrant/v1/tx.proto index 8ff00a47f6..8e2d95e704 100644 --- a/proto/lbm/feegrant/v1/tx.proto +++ b/proto/lbm/feegrant/v1/tx.proto @@ -1,3 +1,4 @@ +// Since: cosmos-sdk 0.43 syntax = "proto3"; package lbm.feegrant.v1; @@ -5,7 +6,7 @@ import "gogoproto/gogo.proto"; import "google/protobuf/any.proto"; import "cosmos_proto/cosmos.proto"; -option go_package = "github.com/line/lbm-sdk/x/feegrant/types"; +option go_package = "github.com/line/lbm-sdk/x/feegrant"; // Msg defines the feegrant msg service. service Msg { diff --git a/proto/lbm/gov/v1/gov.proto b/proto/lbm/gov/v1/gov.proto index 4b5a24c850..f62e28d00b 100644 --- a/proto/lbm/gov/v1/gov.proto +++ b/proto/lbm/gov/v1/gov.proto @@ -30,6 +30,8 @@ enum VoteOption { } // WeightedVoteOption defines a unit of vote for vote split. +// +// Since: cosmos-sdk 0.43 message WeightedVoteOption { VoteOption option = 1; string weight = 2 [ @@ -134,7 +136,8 @@ message Vote { // Deprecated: Prefer to use `options` instead. This field is set in queries // if and only if `len(options) == 1` and that option has weight 1. In all // other cases, this field will default to VOTE_OPTION_UNSPECIFIED. - VoteOption option = 3 [deprecated = true]; + VoteOption option = 3 [deprecated = true]; + // Since: cosmos-sdk 0.43 repeated WeightedVoteOption options = 4 [(gogoproto.nullable) = false]; } diff --git a/proto/lbm/gov/v1/tx.proto b/proto/lbm/gov/v1/tx.proto index 3ae23f76ff..5c40cca6ad 100644 --- a/proto/lbm/gov/v1/tx.proto +++ b/proto/lbm/gov/v1/tx.proto @@ -18,6 +18,8 @@ service Msg { rpc Vote(MsgVote) returns (MsgVoteResponse); // VoteWeighted defines a method to add a weighted vote on a specific proposal. + // + // Since: cosmos-sdk 0.43 rpc VoteWeighted(MsgVoteWeighted) returns (MsgVoteWeightedResponse); // Deposit defines a method to add deposit on a specific proposal. @@ -62,6 +64,8 @@ message MsgVote { message MsgVoteResponse {} // MsgVoteWeighted defines a message to cast a vote. +// +// Since: cosmos-sdk 0.43 message MsgVoteWeighted { option (gogoproto.equal) = false; option (gogoproto.goproto_stringer) = false; @@ -74,6 +78,8 @@ message MsgVoteWeighted { } // MsgVoteWeightedResponse defines the Msg/VoteWeighted response type. +// +// Since: cosmos-sdk 0.43 message MsgVoteWeightedResponse {} // MsgDeposit defines a message to submit a deposit to an existing proposal. diff --git a/proto/lbm/slashing/v1/genesis.proto b/proto/lbm/slashing/v1/genesis.proto index 56abb46e13..67e100035f 100644 --- a/proto/lbm/slashing/v1/genesis.proto +++ b/proto/lbm/slashing/v1/genesis.proto @@ -16,7 +16,7 @@ message GenesisState { repeated SigningInfo signing_infos = 2 [(gogoproto.moretags) = "yaml:\"signing_infos\"", (gogoproto.nullable) = false]; - // signing_infos represents a map between validator addresses and their + // missed_blocks represents a map between validator addresses and their // missed blocks. repeated ValidatorMissedBlocks missed_blocks = 3 [(gogoproto.moretags) = "yaml:\"missed_blocks\"", (gogoproto.nullable) = false]; diff --git a/proto/lbm/staking/v1/authz.proto b/proto/lbm/staking/v1/authz.proto new file mode 100644 index 0000000000..cbe9bf8674 --- /dev/null +++ b/proto/lbm/staking/v1/authz.proto @@ -0,0 +1,47 @@ +syntax = "proto3"; +package lbm.staking.v1; + +import "gogoproto/gogo.proto"; +import "cosmos_proto/cosmos.proto"; +import "lbm/base/v1/coin.proto"; + +option go_package = "github.com/line/lbm-sdk/x/staking/types"; + +// StakeAuthorization defines authorization for delegate/undelegate/redelegate. +// +// Since: cosmos-sdk 0.43 +message StakeAuthorization { + option (cosmos_proto.implements_interface) = "Authorization"; + + // max_tokens specifies the maximum amount of tokens can be delegate to a validator. If it is + // empty, there is no spend limit and any amount of coins can be delegated. + lbm.base.v1.Coin max_tokens = 1 [(gogoproto.castrepeated) = "github.com/line/lbm-sdk/types.Coin"]; + // validators is the oneof that represents either allow_list or deny_list + oneof validators { + // allow_list specifies list of validator addresses to whom grantee can delegate tokens on behalf of granter's + // account. + Validators allow_list = 2; + // deny_list specifies list of validator addresses to whom grantee can not delegate tokens. + Validators deny_list = 3; + } + // Validators defines list of validator addresses. + message Validators { + repeated string address = 1; + } + // authorization_type defines one of AuthorizationType. + AuthorizationType authorization_type = 4; +} + +// AuthorizationType defines the type of staking module authorization type +// +// Since: cosmos-sdk 0.43 +enum AuthorizationType { + // AUTHORIZATION_TYPE_UNSPECIFIED specifies an unknown authorization type + AUTHORIZATION_TYPE_UNSPECIFIED = 0; + // AUTHORIZATION_TYPE_DELEGATE defines an authorization type for Msg/Delegate + AUTHORIZATION_TYPE_DELEGATE = 1; + // AUTHORIZATION_TYPE_UNDELEGATE defines an authorization type for Msg/Undelegate + AUTHORIZATION_TYPE_UNDELEGATE = 2; + // AUTHORIZATION_TYPE_REDELEGATE defines an authorization type for Msg/BeginRedelegate + AUTHORIZATION_TYPE_REDELEGATE = 3; +} diff --git a/proto/lbm/token/v1/query.proto b/proto/lbm/token/v1/query.proto index 6f486a60ba..7b68ec85bd 100644 --- a/proto/lbm/token/v1/query.proto +++ b/proto/lbm/token/v1/query.proto @@ -11,8 +11,8 @@ option go_package = "github.com/line/lbm-sdk/x/token"; // Query defines the gRPC querier service. service Query { - // TokenBalance queries the number of tokens of a given class owned by the address. - rpc TokenBalance(QueryTokenBalanceRequest) returns (QueryTokenBalanceResponse) { + // Balance queries the number of tokens of a given class owned by the address. + rpc Balance(QueryBalanceRequest) returns (QueryBalanceResponse) { option (google.api.http).get = "/lbm/token/v1/balance/{address}/{class_id}"; } @@ -47,15 +47,15 @@ service Query { } } -// QueryTokenBalanceRequest is the request type for the Query/TokenBalance RPC method -message QueryTokenBalanceRequest { +// QueryBalanceRequest is the request type for the Query/Balance RPC method +message QueryBalanceRequest { // class id associated with the token. string class_id = 1; string address = 2; } -// QueryTokenBalanceResponse is the response type for the Query/TokenBalance RPC method -message QueryTokenBalanceResponse { +// QueryBalanceResponse is the response type for the Query/Balance RPC method +message QueryBalanceResponse { string amount = 1 [(gogoproto.customtype) = "github.com/line/lbm-sdk/types.Int", (gogoproto.nullable) = false]; } diff --git a/proto/lbm/tx/v1/service.proto b/proto/lbm/tx/v1/service.proto index faad1a2d3e..2846c19028 100644 --- a/proto/lbm/tx/v1/service.proto +++ b/proto/lbm/tx/v1/service.proto @@ -103,7 +103,12 @@ message BroadcastTxResponse { // RPC method. message SimulateRequest { // tx is the transaction to simulate. - lbm.tx.v1.Tx tx = 1; + // Deprecated. Send raw tx bytes instead. + lbm.tx.v1.Tx tx = 1 [deprecated = true]; + // tx_bytes is the raw transaction. + // + // Since: cosmos-sdk 0.43 + bytes tx_bytes = 2; } // SimulateResponse is the response type for the diff --git a/proto/lbm/tx/v1/tx.proto b/proto/lbm/tx/v1/tx.proto index f150aaddf0..348ba4ce43 100644 --- a/proto/lbm/tx/v1/tx.proto +++ b/proto/lbm/tx/v1/tx.proto @@ -74,7 +74,9 @@ message TxBody { // transaction. repeated google.protobuf.Any messages = 1; - // memo is any arbitrary memo to be added to the transaction + // memo is any arbitrary note/comment to be added to the transaction. + // WARNING: in clients, any publicly exposed text should not be called memo, + // but should be called `note` instead (see https://github.com/cosmos/cosmos-sdk/issues/9122). string memo = 2; // timeout is the block height after which this transaction will not diff --git a/proto/lbm/upgrade/v1/query.proto b/proto/lbm/upgrade/v1/query.proto index e5ed946106..709f4b114c 100644 --- a/proto/lbm/upgrade/v1/query.proto +++ b/proto/lbm/upgrade/v1/query.proto @@ -23,11 +23,16 @@ service Query { // as a trusted kernel for the next version of this chain. It will only be // stored at the last height of this chain. // UpgradedConsensusState RPC not supported with legacy querier + // This rpc is deprecated now that IBC has its own replacement + // (https://github.com/cosmos/ibc-go/blob/2c880a22e9f9cc75f62b527ca94aa75ce1106001/proto/ibc/core/client/v1/query.proto#L54) rpc UpgradedConsensusState(QueryUpgradedConsensusStateRequest) returns (QueryUpgradedConsensusStateResponse) { + option deprecated = true; option (google.api.http).get = "/lbm/upgrade/v1/upgraded_consensus_state/{last_height}"; } // ModuleVersions queries the list of module versions from state. + // + // Since: cosmos-sdk 0.43 rpc ModuleVersions(QueryModuleVersionsRequest) returns (QueryModuleVersionsResponse) { option (google.api.http).get = "/lbm/upgrade/v1/module_versions"; } @@ -61,6 +66,8 @@ message QueryAppliedPlanResponse { // QueryUpgradedConsensusStateRequest is the request type for the Query/UpgradedConsensusState // RPC method. message QueryUpgradedConsensusStateRequest { + option deprecated = true; + // last height of the current chain must be sent in request // as this is the height under which next consensus state is stored int64 last_height = 1; @@ -69,11 +76,17 @@ message QueryUpgradedConsensusStateRequest { // QueryUpgradedConsensusStateResponse is the response type for the Query/UpgradedConsensusState // RPC method. message QueryUpgradedConsensusStateResponse { - google.protobuf.Any upgraded_consensus_state = 1; + option deprecated = true; + reserved 1; + + // Since: cosmos-sdk 0.43 + bytes upgraded_consensus_state = 2; } // QueryModuleVersionsRequest is the request type for the Query/ModuleVersions // RPC method. +// +// Since: cosmos-sdk 0.43 message QueryModuleVersionsRequest { // module_name is a field to query a specific module // consensus version from state. Leaving this empty will @@ -83,6 +96,8 @@ message QueryModuleVersionsRequest { // QueryModuleVersionsResponse is the response type for the Query/ModuleVersions // RPC method. +// +// Since: cosmos-sdk 0.43 message QueryModuleVersionsResponse { // module_versions is a list of module names with their consensus versions. repeated ModuleVersion module_versions = 1; diff --git a/proto/lbm/upgrade/v1/upgrade.proto b/proto/lbm/upgrade/v1/upgrade.proto index 78ffcf8ce1..ac8163064c 100644 --- a/proto/lbm/upgrade/v1/upgrade.proto +++ b/proto/lbm/upgrade/v1/upgrade.proto @@ -5,13 +5,13 @@ import "google/protobuf/any.proto"; import "gogoproto/gogo.proto"; import "google/protobuf/timestamp.proto"; -option go_package = "github.com/line/lbm-sdk/x/upgrade/types"; -option (gogoproto.goproto_stringer_all) = false; -option (gogoproto.goproto_getters_all) = false; +option go_package = "github.com/line/lbm-sdk/x/upgrade/types"; +option (gogoproto.goproto_getters_all) = false; // Plan specifies information about a planned upgrade and when it should occur. message Plan { - option (gogoproto.equal) = true; + option (gogoproto.equal) = true; + option (gogoproto.goproto_stringer) = false; // Sets the name for the upgrade. This name will be used by the upgraded // version of the software to apply any special "on-upgrade" commands during @@ -22,9 +22,10 @@ message Plan { // reached and the software will exit. string name = 1; - // The time after which the upgrade must be performed. - // Leave set to its zero value to use a pre-defined Height instead. - google.protobuf.Timestamp time = 2 [(gogoproto.stdtime) = true, (gogoproto.nullable) = false]; + // Deprecated: Time based upgrades have been deprecated. Time based upgrade logic + // has been removed from the SDK. + // If this field is not empty, an error will be thrown. + google.protobuf.Timestamp time = 2 [deprecated = true, (gogoproto.stdtime) = true, (gogoproto.nullable) = false]; // The height at which the upgrade must be performed. // Only used if Time is not set. @@ -34,18 +35,18 @@ message Plan { // such as a git commit that validators could automatically upgrade to string info = 4; - // IBC-enabled chains can opt-in to including the upgraded client state in its upgrade plan - // This will make the chain commit to the correct upgraded (self) client state before the upgrade occurs, - // so that connecting chains can verify that the new upgraded client is valid by verifying a proof on the - // previous version of the chain. - // This will allow IBC connections to persist smoothly across planned chain upgrades - google.protobuf.Any upgraded_client_state = 5 [(gogoproto.moretags) = "yaml:\"upgraded_client_state\""]; + // Deprecated: UpgradedClientState field has been deprecated. IBC upgrade logic has been + // moved to the IBC module in the sub module 02-client. + // If this field is not empty, an error will be thrown. + google.protobuf.Any upgraded_client_state = 5 + [deprecated = true, (gogoproto.moretags) = "yaml:\"upgraded_client_state\""]; } // SoftwareUpgradeProposal is a gov Content type for initiating a software // upgrade. message SoftwareUpgradeProposal { - option (gogoproto.equal) = true; + option (gogoproto.equal) = true; + option (gogoproto.goproto_stringer) = false; string title = 1; string description = 2; @@ -55,13 +56,16 @@ message SoftwareUpgradeProposal { // CancelSoftwareUpgradeProposal is a gov Content type for cancelling a software // upgrade. message CancelSoftwareUpgradeProposal { - option (gogoproto.equal) = true; + option (gogoproto.equal) = true; + option (gogoproto.goproto_stringer) = false; string title = 1; string description = 2; } // ModuleVersion specifies a module and its consensus version. +// +// Since: cosmos-sdk 0.43 message ModuleVersion { option (gogoproto.equal) = true; option (gogoproto.goproto_stringer) = true; diff --git a/proto/lbm/vesting/v1/vesting.proto b/proto/lbm/vesting/v1/vesting.proto index db118a0c61..1dea1750f3 100644 --- a/proto/lbm/vesting/v1/vesting.proto +++ b/proto/lbm/vesting/v1/vesting.proto @@ -71,3 +71,15 @@ message PeriodicVestingAccount { int64 start_time = 2 [(gogoproto.moretags) = "yaml:\"start_time\""]; repeated Period vesting_periods = 3 [(gogoproto.moretags) = "yaml:\"vesting_periods\"", (gogoproto.nullable) = false]; } + +// PermanentLockedAccount implements the VestingAccount interface. It does +// not ever release coins, locking them indefinitely. Coins in this account can +// still be used for delegating and for governance votes even while locked. +// +// Since: cosmos-sdk 0.43 +message PermanentLockedAccount { + option (gogoproto.goproto_getters) = false; + option (gogoproto.goproto_stringer) = false; + + BaseVestingAccount base_vesting_account = 1 [(gogoproto.embed) = true]; +} diff --git a/scripts/module-tests.sh b/scripts/module-tests.sh new file mode 100644 index 0000000000..86998b5aa9 --- /dev/null +++ b/scripts/module-tests.sh @@ -0,0 +1,48 @@ +#!/usr/bin/env bash + +# this script is used by Github CI to tranverse all modules an run module tests. +# the script expects a diff to be generated in order to skip some modules. + +# Executes go module tests and merges the coverage profile. +# If GIT_DIFF variable is set then it's used to test if a module has any file changes - if +# it doesn't have any file changes then we will ignore the module tests. +execute_mod_tests() { + go_mod=$1; + mod_dir=$(dirname "$go_mod"); + mod_dir=${mod_dir:2}; # remove "./" prefix + root_dir=$(pwd); + + # TODO: in the future we will need to disable it once we go into multi module setup, because + # we will have cross module dependencies. + if [ -n "$GIT_DIFF" ] && ! grep $mod_dir <<< $GIT_DIFF; then + echo ">>> ignoring module $mod_dir - no changes in the module"; + return; + fi; + + echo ">>> running $go_mod tests" + cd $mod_dir; + go test -mod=readonly -timeout 30m -coverprofile=${root_dir}/${coverage_file}.tmp -covermode=atomic -tags='norace ledger test_ledger_mock' ./... + local ret=$? + echo "test return: " $ret; + cd -; + # strip mode statement + tail -n +1 ${coverage_file}.tmp >> ${coverage_file} + rm ${coverage_file}.tmp; + return $ret; +} + +# GIT_DIFF=`git status --porcelain` + +echo "GIT_DIFF: " $GIT_DIFF + +coverage_file=coverage-go-submod-profile.out +return_val=0; + +for f in $(find -name go.mod -not -path "./go.mod"); do + execute_mod_tests $f; + if [[ $? -ne 0 ]] ; then + return_val=2; + fi; +done + +exit $return_val; diff --git a/scripts/protoc-swagger-gen.sh b/scripts/protoc-swagger-gen.sh index bf62cd31e5..d1d2bf96e0 100755 --- a/scripts/protoc-swagger-gen.sh +++ b/scripts/protoc-swagger-gen.sh @@ -10,11 +10,11 @@ for dir in $proto_dirs; do query_file=$(find "${dir}" -maxdepth 1 \( -name 'query.proto' -o -name 'service.proto' \)) if [[ ! -z "$query_file" ]]; then buf protoc \ - -I "proto" \ - -I "third_party/proto" \ - "$query_file" \ - --swagger_out=./tmp-swagger-gen \ - --swagger_opt=logtostderr=true --swagger_opt=fqn_for_swagger_name=true --swagger_opt=simple_operation_ids=true + -I "proto" \ + -I "third_party/proto" \ + "$query_file" \ + --swagger_out=./tmp-swagger-gen \ + --swagger_opt=logtostderr=true --swagger_opt=fqn_for_swagger_name=true --swagger_opt=simple_operation_ids=true fi done diff --git a/scripts/protocgen.sh b/scripts/protocgen.sh index c0df2614a7..d51a8b9545 100755 --- a/scripts/protocgen.sh +++ b/scripts/protocgen.sh @@ -23,18 +23,18 @@ for dir in $proto_dirs; do -I "third_party/proto" \ --gocosmos_out=plugins=interfacetype+grpc,\ Mgoogle/protobuf/any.proto=github.com/line/lbm-sdk/codec/types:. \ - --grpc-gateway_out=logtostderr=true:. \ + --grpc-gateway_out=logtostderr=true,allow_colon_final_segments=true:. \ $(find "${dir}" -maxdepth 1 -name '*.proto') done # command to generate docs using protoc-gen-doc buf protoc \ --I "proto" \ --I "third_party/proto" \ ---doc_out=./docs/core \ ---doc_opt=./docs/protodoc-markdown.tmpl,proto-docs.md \ -$(find "$(pwd)/proto" -maxdepth 5 -name '*.proto') + -I "proto" \ + -I "third_party/proto" \ + --doc_out=./docs/core \ + --doc_opt=./docs/protodoc-markdown.tmpl,proto-docs.md \ + $(find "$(pwd)/proto" -maxdepth 5 -name '*.proto') go mod tidy # generate codec/testdata proto code diff --git a/server/README.md b/server/README.md index 79e46a3ae7..31926f69c1 100644 --- a/server/README.md +++ b/server/README.md @@ -8,6 +8,7 @@ and `ExportCmd` which creates commands to start the application and export state ## Preliminary The root command of an application typically is constructed with: + + command to start an application binary + three meta commands: `query`, `tx`, and a few auxiliary commands such as `genesis`. utilities. diff --git a/server/config/config.go b/server/config/config.go index 0ae14ccb87..110a7f7973 100644 --- a/server/config/config.go +++ b/server/config/config.go @@ -12,13 +12,17 @@ import ( storetypes "github.com/line/lbm-sdk/store/types" "github.com/line/lbm-sdk/telemetry" sdk "github.com/line/lbm-sdk/types" + sdkerrors "github.com/line/lbm-sdk/types/errors" ) const ( defaultMinGasPrices = "" - // DefaultGRPCAddress is the default address the gRPC server binds to. + // DefaultGRPCAddress defines the default address to bind the gRPC server to. DefaultGRPCAddress = "0.0.0.0:9090" + + // DefaultGRPCWebAddress defines the default address to bind the gRPC-web server to. + DefaultGRPCWebAddress = "0.0.0.0:9091" ) // BaseConfig defines the server's basic configuration @@ -73,7 +77,7 @@ type BaseConfig struct { InterBlockCacheSize int `mapstructure:"inter-block-cache-size"` // IAVL cache size; bytes size unit - IAVLCacheSize int `mapstructure:"iavl-cache-size"` + IAVLCacheSize uint64 `mapstructure:"iavl-cache-size"` // Bech32CacheSize is the maximum bytes size of bech32 cache (Default : 1GB) Bech32CacheSize int `mapstructure:"bech32-cache-size"` @@ -117,6 +121,29 @@ type APIConfig struct { // Ref: https://github.com/cosmos/cosmos-sdk/issues/6420 } +// RosettaConfig defines the Rosetta API listener configuration. +type RosettaConfig struct { + // Address defines the API server to listen on + Address string `mapstructure:"address"` + + // Blockchain defines the blockchain name + // defaults to DefaultBlockchain + Blockchain string `mapstructure:"blockchain"` + + // Network defines the network name + Network string `mapstructure:"network"` + + // Retries defines the maximum number of retries + // rosetta will do before quitting + Retries int `mapstructure:"retries"` + + // Enable defines if the API server should be enabled. + Enable bool `mapstructure:"enable"` + + // Offline defines if the server must be run in offline mode + Offline bool `mapstructure:"offline"` +} + // GRPCConfig defines configuration for the gRPC server. type GRPCConfig struct { // Enable defines if the gRPC server should be enabled. @@ -126,6 +153,18 @@ type GRPCConfig struct { Address string `mapstructure:"address"` } +// GRPCWebConfig defines configuration for the gRPC-web server. +type GRPCWebConfig struct { + // Enable defines if the gRPC-web should be enabled. + Enable bool `mapstructure:"enable"` + + // Address defines the gRPC-web server to listen on + Address string `mapstructure:"address"` + + // EnableUnsafeCORS defines if CORS should be enabled (unsafe - use it at your own risk) + EnableUnsafeCORS bool `mapstructure:"enable-unsafe-cors"` +} + // StateSyncConfig defines the state sync snapshot configuration. type StateSyncConfig struct { // SnapshotInterval sets the interval at which state sync snapshots are taken. @@ -145,6 +184,8 @@ type Config struct { Telemetry telemetry.Config `mapstructure:"telemetry"` API APIConfig `mapstructure:"api"` GRPC GRPCConfig `mapstructure:"grpc"` + Rosetta RosettaConfig `mapstructure:"rosetta"` + GRPCWeb GRPCWebConfig `mapstructure:"grpc-web"` StateSync StateSyncConfig `mapstructure:"state-sync"` } @@ -209,6 +250,18 @@ func DefaultConfig() *Config { Enable: true, Address: DefaultGRPCAddress, }, + Rosetta: RosettaConfig{ + Enable: false, + Address: ":8080", + Blockchain: "app", + Network: "network", + Retries: 3, + Offline: false, + }, + GRPCWeb: GRPCWebConfig{ + Enable: true, + Address: DefaultGRPCWebAddress, + }, StateSync: StateSyncConfig{ SnapshotInterval: 0, SnapshotKeepRecent: 2, @@ -239,6 +292,7 @@ func GetConfig(v *viper.Viper) Config { HaltTime: v.GetUint64("halt-time"), IndexEvents: v.GetStringSlice("index-events"), MinRetainBlocks: v.GetUint64("min-retain-blocks"), + IAVLCacheSize: v.GetUint64("iavl-cache-size"), }, Telemetry: telemetry.Config{ ServiceName: v.GetString("telemetry.service-name"), @@ -260,13 +314,35 @@ func GetConfig(v *viper.Viper) Config { RPCMaxBodyBytes: v.GetUint("api.rpc-max-body-bytes"), EnableUnsafeCORS: v.GetBool("api.enabled-unsafe-cors"), }, + Rosetta: RosettaConfig{ + Enable: v.GetBool("rosetta.enable"), + Address: v.GetString("rosetta.address"), + Blockchain: v.GetString("rosetta.blockchain"), + Network: v.GetString("rosetta.network"), + Retries: v.GetInt("rosetta.retries"), + Offline: v.GetBool("rosetta.offline"), + }, GRPC: GRPCConfig{ Enable: v.GetBool("grpc.enable"), Address: v.GetString("grpc.address"), }, + GRPCWeb: GRPCWebConfig{ + Enable: v.GetBool("grpc-web.enable"), + Address: v.GetString("grpc-web.address"), + EnableUnsafeCORS: v.GetBool("grpc-web.enable-unsafe-cors"), + }, StateSync: StateSyncConfig{ SnapshotInterval: v.GetUint64("state-sync.snapshot-interval"), SnapshotKeepRecent: v.GetUint32("state-sync.snapshot-keep-recent"), }, } } + +// ValidateBasic returns an error if min-gas-prices field is empty in BaseConfig. Otherwise, it returns nil. +func (c Config) ValidateBasic() error { + if c.BaseConfig.MinGasPrices == "" { + return sdkerrors.ErrAppConfig.Wrap("set min gas price in app.toml or flag or env variable") + } + + return nil +} diff --git a/server/config/toml.go b/server/config/toml.go index de057ebdfa..4bc0c5fa93 100644 --- a/server/config/toml.go +++ b/server/config/toml.go @@ -8,7 +8,7 @@ import ( "github.com/spf13/viper" ) -const defaultConfigTemplate = `# This is a TOML config file. +const DefaultConfigTemplate = `# This is a TOML config file. # For more information, see https://github.com/toml-lang/toml ############################################################################### @@ -151,6 +151,30 @@ rpc-max-body-bytes = {{ .API.RPCMaxBodyBytes }} # EnableUnsafeCORS defines if CORS should be enabled (unsafe - use it at your own risk). enabled-unsafe-cors = {{ .API.EnableUnsafeCORS }} +############################################################################### +### Rosetta Configuration ### +############################################################################### + +[rosetta] + +# Enable defines if the Rosetta API server should be enabled. +enable = {{ .Rosetta.Enable }} + +# Address defines the Rosetta API server to listen on. +address = "{{ .Rosetta.Address }}" + +# Network defines the name of the blockchain that will be returned by Rosetta. +blockchain = "{{ .Rosetta.Blockchain }}" + +# Network defines the name of the network that will be returned by Rosetta. +network = "{{ .Rosetta.Network }}" + +# Retries defines the number of retries when connecting to the node before failing. +retries = {{ .Rosetta.Retries }} + +# Offline defines if Rosetta server should run in offline mode. +offline = {{ .Rosetta.Offline }} + ############################################################################### ### gRPC Configuration ### ############################################################################### @@ -163,6 +187,22 @@ enable = {{ .GRPC.Enable }} # Address defines the gRPC server address to bind to. address = "{{ .GRPC.Address }}" +############################################################################### +### gRPC Web Configuration ### +############################################################################### + +[grpc-web] + +# GRPCWebEnable defines if the gRPC-web should be enabled. +# NOTE: gRPC must also be enabled, otherwise, this configuration is a no-op. +enable = {{ .GRPCWeb.Enable }} + +# Address defines the gRPC-web server address to bind to. +address = "{{ .GRPCWeb.Address }}" + +# EnableUnsafeCORS defines if CORS should be enabled (unsafe - use it at your own risk). +enable-unsafe-cors = {{ .GRPCWeb.EnableUnsafeCORS }} + ############################################################################### ### State Sync Configuration ### ############################################################################### @@ -186,7 +226,7 @@ func init() { tmpl := template.New("appConfigFileTemplate") - if configTemplate, err = tmpl.Parse(defaultConfigTemplate); err != nil { + if configTemplate, err = tmpl.Parse(DefaultConfigTemplate); err != nil { panic(err) } } @@ -200,9 +240,21 @@ func ParseConfig(v *viper.Viper) (*Config, error) { return conf, err } +// SetConfigTemplate sets the custom app config template for +// the application +func SetConfigTemplate(customTemplate string) { + var err error + + tmpl := template.New("appConfigFileTemplate") + + if configTemplate, err = tmpl.Parse(customTemplate); err != nil { + panic(err) + } +} + // WriteConfigFile renders config using the template and writes it to // configFilePath. -func WriteConfigFile(configFilePath string, config *Config) { +func WriteConfigFile(configFilePath string, config interface{}) { var buffer bytes.Buffer if err := configTemplate.Execute(&buffer, config); err != nil { diff --git a/server/doc.go b/server/doc.go index befac1302e..241c218259 100644 --- a/server/doc.go +++ b/server/doc.go @@ -22,6 +22,9 @@ value called `rpc.laddr` would be read from an environmental variable called Running the `InterceptConfigsPreRunHandler` also reads `app.toml` and `config.toml` from the home directory under the `config` directory. If `config.toml` or `app.toml` do not exist then those files are created -and populated with default values. +and populated with default values. `InterceptConfigsPreRunHandler` takes +two parameters to set/update a custom template to create custom `app.toml`. +If these parameters are empty, the server then creates a default template +provided by the SDK. */ package server diff --git a/server/export.go b/server/export.go index 6e99f146cd..db7685dc9f 100644 --- a/server/export.go +++ b/server/export.go @@ -109,8 +109,7 @@ func ExportCmd(appExporter types.AppExporter, defaultNodeHome string) *cobra.Com return nil }, } - cmd.SetOut(cmd.OutOrStdout()) - cmd.SetErr(cmd.ErrOrStderr()) + cmd.Flags().String(flags.FlagHome, defaultNodeHome, "The application home directory") cmd.Flags().Int64(FlagHeight, -1, "Export state from a particular height (-1 means latest height)") cmd.Flags().Bool(FlagForZeroHeight, false, "Export state to start at height zero (perform preproccessing)") diff --git a/server/export_test.go b/server/export_test.go index 70c5721906..2e96196849 100644 --- a/server/export_test.go +++ b/server/export_test.go @@ -136,7 +136,7 @@ func setupApp(t *testing.T, tempDir string) (*simapp.SimApp, context.Context, *o serverCtx := server.NewDefaultContext() serverCtx.Config.RootDir = tempDir - clientCtx := client.Context{}.WithJSONMarshaler(app.AppCodec()) + clientCtx := client.Context{}.WithCodec(app.AppCodec()) genDoc := newDefaultGenesisDoc(encCfg.Marshaler) require.NoError(t, saveGenesisFile(genDoc, serverCtx.Config.GenesisFile())) @@ -178,7 +178,7 @@ func createConfigFolder(dir string) error { return os.Mkdir(path.Join(dir, "config"), 0700) } -func newDefaultGenesisDoc(cdc codec.Marshaler) *octypes.GenesisDoc { +func newDefaultGenesisDoc(cdc codec.Codec) *octypes.GenesisDoc { genesisState := simapp.NewDefaultGenesisState(cdc) stateBytes, err := json.MarshalIndent(genesisState, "", " ") diff --git a/server/grpc/gogoreflection/doc.go b/server/grpc/gogoreflection/doc.go new file mode 100644 index 0000000000..691e632d0e --- /dev/null +++ b/server/grpc/gogoreflection/doc.go @@ -0,0 +1,5 @@ +// Package gogoreflection implements gRPC reflection for gogoproto consumers +// the normal reflection library does not work as it points to a different +// singleton registry. The API and codebase is taken from the official gRPC +// reflection repository. +package gogoreflection diff --git a/server/grpc/gogoreflection/fix_registration.go b/server/grpc/gogoreflection/fix_registration.go new file mode 100644 index 0000000000..fda0799e00 --- /dev/null +++ b/server/grpc/gogoreflection/fix_registration.go @@ -0,0 +1,145 @@ +package gogoreflection + +import ( + "bytes" + "compress/gzip" + "fmt" + "reflect" + + _ "github.com/gogo/protobuf/gogoproto" // required so it does register the gogoproto file descriptor + gogoproto "github.com/gogo/protobuf/proto" + + // nolint: staticcheck + _ "github.com/confio/ics23/go" // TODO(dudong2): after separating ibc module from lbm-sdk, remove this + "github.com/golang/protobuf/proto" // nolint: staticcheck + dpb "github.com/golang/protobuf/protoc-gen-go/descriptor" + _ "github.com/regen-network/cosmos-proto" // look above +) + +var importsToFix = map[string]string{ + "gogo.proto": "gogoproto/gogo.proto", + "cosmos.proto": "cosmos_proto/cosmos.proto", + "proofs.proto": "confio/proofs.proto", // TODO(dudong2): after separating ibc module from lbm-sdk, remove this +} + +// fixRegistration is required because certain files register themselves in a way +// but are imported by other files in a different way. +// NOTE(fdymylja): This fix should not be needed and should be addressed in some CI. +// Currently every cosmos-sdk proto file is importing gogo.proto as gogoproto/gogo.proto, +// but gogo.proto registers itself as gogo.proto, same goes for cosmos.proto. +func fixRegistration(registeredAs, importedAs string) error { + raw := gogoproto.FileDescriptor(registeredAs) + if len(raw) == 0 { + return fmt.Errorf("file descriptor not found for %s", registeredAs) + } + + fd, err := decodeFileDesc(raw) + if err != nil { + return err + } + + // fix name + *fd.Name = importedAs + fixedRaw, err := compress(fd) + if err != nil { + return fmt.Errorf("unable to compress: %w", err) + } + gogoproto.RegisterFile(importedAs, fixedRaw) + return nil +} + +func init() { + // we need to fix the gogoproto filedesc to match the import path + // in theory this shouldn't be required, generally speaking + // proto files should be imported as their registration path + + for registeredAs, importedAs := range importsToFix { + err := fixRegistration(registeredAs, importedAs) + if err != nil { + panic(err) + } + } +} + +// compress compresses the given file descriptor +// nolint: interfacer +func compress(fd *dpb.FileDescriptorProto) ([]byte, error) { + fdBytes, err := proto.Marshal(fd) + if err != nil { + return nil, err + } + buf := new(bytes.Buffer) + cw := gzip.NewWriter(buf) + _, err = cw.Write(fdBytes) + if err != nil { + return nil, err + } + err = cw.Close() + if err != nil { + return nil, err + } + return buf.Bytes(), nil +} + +func getFileDescriptor(filePath string) []byte { + // since we got well known descriptors which are not registered into gogoproto registry + // but are instead registered into the proto one, we need to check both + fd := gogoproto.FileDescriptor(filePath) + if len(fd) != 0 { + return fd + } + // nolint: staticcheck + return proto.FileDescriptor(filePath) +} + +func getMessageType(name string) reflect.Type { + typ := gogoproto.MessageType(name) + if typ != nil { + return typ + } + // nolint: staticcheck + return proto.MessageType(name) +} + +func getExtension(extID int32, m proto.Message) *gogoproto.ExtensionDesc { + // check first in gogoproto registry + for id, desc := range gogoproto.RegisteredExtensions(m) { + if id == extID { + return desc + } + } + // check into proto registry + // nolint: staticcheck + for id, desc := range proto.RegisteredExtensions(m) { + if id == extID { + return &gogoproto.ExtensionDesc{ + ExtendedType: desc.ExtendedType, + ExtensionType: desc.ExtensionType, + Field: desc.Field, + Name: desc.Name, + Tag: desc.Tag, + Filename: desc.Filename, + } + } + } + + return nil +} + +func getExtensionsNumbers(m proto.Message) []int32 { + gogoProtoExts := gogoproto.RegisteredExtensions(m) + out := make([]int32, 0, len(gogoProtoExts)) + for id := range gogoProtoExts { + out = append(out, id) + } + if len(out) != 0 { + return out + } + // nolint: staticcheck + protoExts := proto.RegisteredExtensions(m) + out = make([]int32, 0, len(protoExts)) + for id := range protoExts { + out = append(out, id) + } + return out +} diff --git a/server/grpc/gogoreflection/fix_registration_test.go b/server/grpc/gogoreflection/fix_registration_test.go new file mode 100644 index 0000000000..0693556688 --- /dev/null +++ b/server/grpc/gogoreflection/fix_registration_test.go @@ -0,0 +1,22 @@ +package gogoreflection + +import ( + "testing" + + "google.golang.org/protobuf/runtime/protoimpl" +) + +func TestRegistrationFix(t *testing.T) { + res := getFileDescriptor("gogoproto/gogo.proto") + rawDesc, err := decompress(res) + if err != nil { + t.Fatal(err) + } + fd := protoimpl.DescBuilder{ + RawDescriptor: rawDesc, + }.Build() + + if fd.File.Extensions().Len() == 0 { + t.Fatal("unexpected parsing") + } +} diff --git a/server/grpc/gogoreflection/serverreflection.go b/server/grpc/gogoreflection/serverreflection.go new file mode 100644 index 0000000000..c2a0828e3b --- /dev/null +++ b/server/grpc/gogoreflection/serverreflection.go @@ -0,0 +1,478 @@ +/* + * + * Copyright 2016 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +/* +Package reflection implements server reflection service. + +The service implemented is defined in: +https://github.com/grpc/grpc/blob/master/src/proto/grpc/reflection/v1alpha/reflection.proto. + +To register server reflection on a gRPC server: + import "google.golang.org/grpc/reflection" + + s := grpc.NewServer() + pb.RegisterYourOwnServer(s, &server{}) + + // Register reflection service on gRPC server. + reflection.Register(s) + + s.Serve(lis) + +*/ +package gogoreflection // import "google.golang.org/grpc/reflection" + +import ( + "bytes" + "compress/gzip" + "fmt" + "io" + "io/ioutil" + "log" + "reflect" + "sort" + "sync" + + // nolint: staticcheck + "github.com/golang/protobuf/proto" + dpb "github.com/golang/protobuf/protoc-gen-go/descriptor" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + rpb "google.golang.org/grpc/reflection/grpc_reflection_v1alpha" + "google.golang.org/grpc/status" +) + +type serverReflectionServer struct { + rpb.UnimplementedServerReflectionServer + s *grpc.Server + + initSymbols sync.Once + serviceNames []string + symbols map[string]*dpb.FileDescriptorProto // map of fully-qualified names to files +} + +// Register registers the server reflection service on the given gRPC server. +func Register(s *grpc.Server) { + rpb.RegisterServerReflectionServer(s, &serverReflectionServer{ + s: s, + }) +} + +// protoMessage is used for type assertion on proto messages. +// Generated proto message implements function Descriptor(), but Descriptor() +// is not part of interface proto.Message. This interface is needed to +// call Descriptor(). +type protoMessage interface { + Descriptor() ([]byte, []int) +} + +func (s *serverReflectionServer) getSymbols() (svcNames []string, symbolIndex map[string]*dpb.FileDescriptorProto) { + s.initSymbols.Do(func() { + serviceInfo := s.s.GetServiceInfo() + + s.symbols = map[string]*dpb.FileDescriptorProto{} + s.serviceNames = make([]string, 0, len(serviceInfo)) + processed := map[string]struct{}{} + for svc, info := range serviceInfo { + s.serviceNames = append(s.serviceNames, svc) + fdenc, ok := parseMetadata(info.Metadata) + if !ok { + continue + } + fd, err := decodeFileDesc(fdenc) + if err != nil { + continue + } + s.processFile(fd, processed) + } + sort.Strings(s.serviceNames) + }) + + return s.serviceNames, s.symbols +} + +func (s *serverReflectionServer) processFile(fd *dpb.FileDescriptorProto, processed map[string]struct{}) { + filename := fd.GetName() + if _, ok := processed[filename]; ok { + return + } + processed[filename] = struct{}{} + + prefix := fd.GetPackage() + + for _, msg := range fd.MessageType { + s.processMessage(fd, prefix, msg) + } + for _, en := range fd.EnumType { + s.processEnum(fd, prefix, en) + } + for _, ext := range fd.Extension { + s.processField(fd, prefix, ext) + } + for _, svc := range fd.Service { + svcName := fqn(prefix, svc.GetName()) + s.symbols[svcName] = fd + for _, meth := range svc.Method { + name := fqn(svcName, meth.GetName()) + s.symbols[name] = fd + } + } + + for _, dep := range fd.Dependency { + fdenc := getFileDescriptor(dep) + fdDep, err := decodeFileDesc(fdenc) + if err != nil { + continue + } + s.processFile(fdDep, processed) + } +} + +func (s *serverReflectionServer) processMessage(fd *dpb.FileDescriptorProto, prefix string, msg *dpb.DescriptorProto) { + msgName := fqn(prefix, msg.GetName()) + s.symbols[msgName] = fd + + for _, nested := range msg.NestedType { + s.processMessage(fd, msgName, nested) + } + for _, en := range msg.EnumType { + s.processEnum(fd, msgName, en) + } + for _, ext := range msg.Extension { + s.processField(fd, msgName, ext) + } + for _, fld := range msg.Field { + s.processField(fd, msgName, fld) + } + for _, oneof := range msg.OneofDecl { + oneofName := fqn(msgName, oneof.GetName()) + s.symbols[oneofName] = fd + } +} + +func (s *serverReflectionServer) processEnum(fd *dpb.FileDescriptorProto, prefix string, en *dpb.EnumDescriptorProto) { + enName := fqn(prefix, en.GetName()) + s.symbols[enName] = fd + + for _, val := range en.Value { + valName := fqn(enName, val.GetName()) + s.symbols[valName] = fd + } +} + +func (s *serverReflectionServer) processField(fd *dpb.FileDescriptorProto, prefix string, fld *dpb.FieldDescriptorProto) { + fldName := fqn(prefix, fld.GetName()) + s.symbols[fldName] = fd +} + +func fqn(prefix, name string) string { + if prefix == "" { + return name + } + return prefix + "." + name +} + +// fileDescForType gets the file descriptor for the given type. +// The given type should be a proto message. +func (s *serverReflectionServer) fileDescForType(st reflect.Type) (*dpb.FileDescriptorProto, error) { + m, ok := reflect.Zero(reflect.PtrTo(st)).Interface().(protoMessage) + if !ok { + return nil, fmt.Errorf("failed to create message from type: %v", st) + } + enc, _ := m.Descriptor() + + return decodeFileDesc(enc) +} + +// decodeFileDesc does decompression and unmarshalling on the given +// file descriptor byte slice. +func decodeFileDesc(enc []byte) (*dpb.FileDescriptorProto, error) { + raw, err := decompress(enc) + if err != nil { + return nil, fmt.Errorf("failed to decompress enc: %v", err) + } + + fd := new(dpb.FileDescriptorProto) + if err := proto.Unmarshal(raw, fd); err != nil { + return nil, fmt.Errorf("bad descriptor: %v", err) + } + return fd, nil +} + +// decompress does gzip decompression. +func decompress(b []byte) ([]byte, error) { + r, err := gzip.NewReader(bytes.NewReader(b)) + if err != nil { + return nil, fmt.Errorf("bad gzipped descriptor: %v", err) + } + out, err := ioutil.ReadAll(r) + if err != nil { + return nil, fmt.Errorf("bad gzipped descriptor: %v", err) + } + return out, nil +} + +func typeForName(name string) (reflect.Type, error) { + pt := getMessageType(name) + if pt == nil { + return nil, fmt.Errorf("unknown type: %q", name) + } + st := pt.Elem() + + return st, nil +} + +func fileDescContainingExtension(st reflect.Type, ext int32) (*dpb.FileDescriptorProto, error) { + m, ok := reflect.Zero(reflect.PtrTo(st)).Interface().(proto.Message) + if !ok { + return nil, fmt.Errorf("failed to create message from type: %v", st) + } + + extDesc := getExtension(ext, m) + + if extDesc == nil { + return nil, fmt.Errorf("failed to find registered extension for extension number %v", ext) + } + + return decodeFileDesc(getFileDescriptor(extDesc.Filename)) +} + +func (s *serverReflectionServer) allExtensionNumbersForType(st reflect.Type) ([]int32, error) { + m, ok := reflect.Zero(reflect.PtrTo(st)).Interface().(proto.Message) + if !ok { + return nil, fmt.Errorf("failed to create message from type: %v", st) + } + + out := getExtensionsNumbers(m) + return out, nil +} + +// fileDescWithDependencies returns a slice of serialized fileDescriptors in +// wire format ([]byte). The fileDescriptors will include fd and all the +// transitive dependencies of fd with names not in sentFileDescriptors. +func fileDescWithDependencies(fd *dpb.FileDescriptorProto, sentFileDescriptors map[string]bool) ([][]byte, error) { + r := [][]byte{} + queue := []*dpb.FileDescriptorProto{fd} + for len(queue) > 0 { + currentfd := queue[0] + queue = queue[1:] + if sent := sentFileDescriptors[currentfd.GetName()]; len(r) == 0 || !sent { + sentFileDescriptors[currentfd.GetName()] = true + currentfdEncoded, err := proto.Marshal(currentfd) + if err != nil { + return nil, err + } + r = append(r, currentfdEncoded) + } + for _, dep := range currentfd.Dependency { + fdenc := getFileDescriptor(dep) + fdDep, err := decodeFileDesc(fdenc) + if err != nil { + continue + } + queue = append(queue, fdDep) + } + } + return r, nil +} + +// fileDescEncodingByFilename finds the file descriptor for given filename, +// finds all of its previously unsent transitive dependencies, does marshalling +// on them, and returns the marshalled result. +func (s *serverReflectionServer) fileDescEncodingByFilename(name string, sentFileDescriptors map[string]bool) ([][]byte, error) { + enc := getFileDescriptor(name) + if enc == nil { + return nil, fmt.Errorf("unknown file: %v", name) + } + fd, err := decodeFileDesc(enc) + if err != nil { + return nil, err + } + return fileDescWithDependencies(fd, sentFileDescriptors) +} + +// parseMetadata finds the file descriptor bytes specified meta. +// For SupportPackageIsVersion4, m is the name of the proto file, we +// call proto.FileDescriptor to get the byte slice. +// For SupportPackageIsVersion3, m is a byte slice itself. +func parseMetadata(meta interface{}) ([]byte, bool) { + // Check if meta is the file name. + if fileNameForMeta, ok := meta.(string); ok { + return getFileDescriptor(fileNameForMeta), true + } + + // Check if meta is the byte slice. + if enc, ok := meta.([]byte); ok { + return enc, true + } + + return nil, false +} + +// fileDescEncodingContainingSymbol finds the file descriptor containing the +// given symbol, finds all of its previously unsent transitive dependencies, +// does marshalling on them, and returns the marshalled result. The given symbol +// can be a type, a service or a method. +func (s *serverReflectionServer) fileDescEncodingContainingSymbol(name string, sentFileDescriptors map[string]bool) ([][]byte, error) { + _, symbols := s.getSymbols() + fd := symbols[name] + if fd == nil { + // Check if it's a type name that was not present in the + // transitive dependencies of the registered services. + if st, err := typeForName(name); err == nil { + fd, err = s.fileDescForType(st) + if err != nil { + return nil, err + } + } + } + + if fd == nil { + return nil, fmt.Errorf("unknown symbol: %v", name) + } + + return fileDescWithDependencies(fd, sentFileDescriptors) +} + +// fileDescEncodingContainingExtension finds the file descriptor containing +// given extension, finds all of its previously unsent transitive dependencies, +// does marshalling on them, and returns the marshalled result. +func (s *serverReflectionServer) fileDescEncodingContainingExtension(typeName string, extNum int32, sentFileDescriptors map[string]bool) ([][]byte, error) { + st, err := typeForName(typeName) + if err != nil { + return nil, err + } + fd, err := fileDescContainingExtension(st, extNum) + if err != nil { + return nil, err + } + return fileDescWithDependencies(fd, sentFileDescriptors) +} + +// allExtensionNumbersForTypeName returns all extension numbers for the given type. +func (s *serverReflectionServer) allExtensionNumbersForTypeName(name string) ([]int32, error) { + st, err := typeForName(name) + if err != nil { + return nil, err + } + extNums, err := s.allExtensionNumbersForType(st) + if err != nil { + return nil, err + } + return extNums, nil +} + +// ServerReflectionInfo is the reflection service handler. +func (s *serverReflectionServer) ServerReflectionInfo(stream rpb.ServerReflection_ServerReflectionInfoServer) error { + sentFileDescriptors := make(map[string]bool) + for { + in, err := stream.Recv() + if err == io.EOF { + return nil + } + if err != nil { + return err + } + + out := &rpb.ServerReflectionResponse{ + ValidHost: in.Host, + OriginalRequest: in, + } + switch req := in.MessageRequest.(type) { + case *rpb.ServerReflectionRequest_FileByFilename: + b, err := s.fileDescEncodingByFilename(req.FileByFilename, sentFileDescriptors) + if err != nil { + out.MessageResponse = &rpb.ServerReflectionResponse_ErrorResponse{ + ErrorResponse: &rpb.ErrorResponse{ + ErrorCode: int32(codes.NotFound), + ErrorMessage: err.Error(), + }, + } + } else { + out.MessageResponse = &rpb.ServerReflectionResponse_FileDescriptorResponse{ + FileDescriptorResponse: &rpb.FileDescriptorResponse{FileDescriptorProto: b}, + } + } + case *rpb.ServerReflectionRequest_FileContainingSymbol: + b, err := s.fileDescEncodingContainingSymbol(req.FileContainingSymbol, sentFileDescriptors) + if err != nil { + out.MessageResponse = &rpb.ServerReflectionResponse_ErrorResponse{ + ErrorResponse: &rpb.ErrorResponse{ + ErrorCode: int32(codes.NotFound), + ErrorMessage: err.Error(), + }, + } + } else { + out.MessageResponse = &rpb.ServerReflectionResponse_FileDescriptorResponse{ + FileDescriptorResponse: &rpb.FileDescriptorResponse{FileDescriptorProto: b}, + } + } + case *rpb.ServerReflectionRequest_FileContainingExtension: + typeName := req.FileContainingExtension.ContainingType + extNum := req.FileContainingExtension.ExtensionNumber + b, err := s.fileDescEncodingContainingExtension(typeName, extNum, sentFileDescriptors) + if err != nil { + out.MessageResponse = &rpb.ServerReflectionResponse_ErrorResponse{ + ErrorResponse: &rpb.ErrorResponse{ + ErrorCode: int32(codes.NotFound), + ErrorMessage: err.Error(), + }, + } + } else { + out.MessageResponse = &rpb.ServerReflectionResponse_FileDescriptorResponse{ + FileDescriptorResponse: &rpb.FileDescriptorResponse{FileDescriptorProto: b}, + } + } + case *rpb.ServerReflectionRequest_AllExtensionNumbersOfType: + extNums, err := s.allExtensionNumbersForTypeName(req.AllExtensionNumbersOfType) + if err != nil { + out.MessageResponse = &rpb.ServerReflectionResponse_ErrorResponse{ + ErrorResponse: &rpb.ErrorResponse{ + ErrorCode: int32(codes.NotFound), + ErrorMessage: err.Error(), + }, + } + log.Printf("OH NO: %s", err) + } else { + out.MessageResponse = &rpb.ServerReflectionResponse_AllExtensionNumbersResponse{ + AllExtensionNumbersResponse: &rpb.ExtensionNumberResponse{ + BaseTypeName: req.AllExtensionNumbersOfType, + ExtensionNumber: extNums, + }, + } + } + case *rpb.ServerReflectionRequest_ListServices: + svcNames, _ := s.getSymbols() + serviceResponses := make([]*rpb.ServiceResponse, len(svcNames)) + for i, n := range svcNames { + serviceResponses[i] = &rpb.ServiceResponse{ + Name: n, + } + } + out.MessageResponse = &rpb.ServerReflectionResponse_ListServicesResponse{ + ListServicesResponse: &rpb.ListServiceResponse{ + Service: serviceResponses, + }, + } + default: + return status.Errorf(codes.InvalidArgument, "invalid MessageRequest: %v", in.MessageRequest) + } + if err := stream.Send(out); err != nil { + return err + } + } +} diff --git a/server/grpc/grpc_web.go b/server/grpc/grpc_web.go new file mode 100644 index 0000000000..424a3e45de --- /dev/null +++ b/server/grpc/grpc_web.go @@ -0,0 +1,45 @@ +package grpc + +import ( + "fmt" + "net/http" + "time" + + "github.com/improbable-eng/grpc-web/go/grpcweb" + "google.golang.org/grpc" + + "github.com/line/lbm-sdk/server/config" + "github.com/line/lbm-sdk/server/types" +) + +// StartGRPCWeb starts a gRPC-Web server on the given address. +func StartGRPCWeb(grpcSrv *grpc.Server, config config.Config) (*http.Server, error) { + var options []grpcweb.Option + if config.GRPCWeb.EnableUnsafeCORS { + options = append(options, + grpcweb.WithOriginFunc(func(origin string) bool { + return true + }), + ) + } + + wrappedServer := grpcweb.WrapServer(grpcSrv, options...) + grpcWebSrv := &http.Server{ + Addr: config.GRPCWeb.Address, + Handler: wrappedServer, + } + + errCh := make(chan error) + go func() { + if err := grpcWebSrv.ListenAndServe(); err != nil { + errCh <- fmt.Errorf("[grpc] failed to serve: %w", err) + } + }() + + select { + case err := <-errCh: + return nil, err + case <-time.After(types.ServerStartTime): // assume server started successfully + return grpcWebSrv, nil + } +} diff --git a/server/grpc/grpc_web_test.go b/server/grpc/grpc_web_test.go new file mode 100644 index 0000000000..67a1005190 --- /dev/null +++ b/server/grpc/grpc_web_test.go @@ -0,0 +1,313 @@ +package grpc_test + +import ( + "bufio" + "bytes" + "encoding/base64" + "encoding/binary" + "fmt" + "io" + "io/ioutil" + "net/http" + "net/textproto" + "strconv" + "strings" + "testing" + + "github.com/golang/protobuf/proto" + "github.com/stretchr/testify/require" + "github.com/stretchr/testify/suite" + "google.golang.org/grpc/codes" + + "github.com/line/lbm-sdk/client/grpc/tmservice" + "github.com/line/lbm-sdk/codec" + cryptotypes "github.com/line/lbm-sdk/crypto/types" + "github.com/line/lbm-sdk/testutil/network" + banktypes "github.com/line/lbm-sdk/x/bank/types" +) + +// https://github.com/improbable-eng/grpc-web/blob/master/go/grpcweb/wrapper_test.go used as a reference +// to setup grpcRequest config. + +const grpcWebContentType = "application/grpc-web" + +type GRPCWebTestSuite struct { + suite.Suite + + cfg network.Config + network *network.Network + protoCdc *codec.ProtoCodec +} + +func (s *GRPCWebTestSuite) SetupSuite() { + s.T().Log("setting up integration test suite") + + cfg := network.DefaultConfig() + cfg.NumValidators = 1 + s.cfg = cfg + s.network = network.New(s.T(), s.cfg) + s.Require().NotNil(s.network) + + _, err := s.network.WaitForHeight(2) + s.Require().NoError(err) + + s.protoCdc = codec.NewProtoCodec(s.cfg.InterfaceRegistry) +} + +func (s *GRPCWebTestSuite) TearDownSuite() { + s.T().Log("tearing down integration test suite") + s.network.Cleanup() +} + +func (s *GRPCWebTestSuite) Test_Latest_Validators() { + val := s.network.Validators[0] + for _, contentType := range []string{grpcWebContentType} { + headers, trailers, responses, err := s.makeGrpcRequest( + "/lbm.base.ostracon.v1.Service/GetLatestValidatorSet", + headerWithFlag(), + serializeProtoMessages([]proto.Message{&tmservice.GetLatestValidatorSetRequest{}}), false) + + s.Require().NoError(err) + s.Require().Equal(1, len(responses)) + s.assertTrailerGrpcCode(trailers, codes.OK, "") + s.assertContentTypeSet(headers, contentType) + var valsSet tmservice.GetLatestValidatorSetResponse + err = s.protoCdc.Unmarshal(responses[0], &valsSet) + s.Require().NoError(err) + pubKey, ok := valsSet.Validators[0].PubKey.GetCachedValue().(cryptotypes.PubKey) + s.Require().Equal(true, ok) + s.Require().Equal(pubKey, val.PubKey) + } +} + +func (s *GRPCWebTestSuite) Test_Total_Supply() { + for _, contentType := range []string{grpcWebContentType} { + headers, trailers, responses, err := s.makeGrpcRequest( + "/lbm.bank.v1.Query/TotalSupply", + headerWithFlag(), + serializeProtoMessages([]proto.Message{&banktypes.QueryTotalSupplyRequest{}}), false) + + s.Require().NoError(err) + s.Require().Equal(1, len(responses)) + s.assertTrailerGrpcCode(trailers, codes.OK, "") + s.assertContentTypeSet(headers, contentType) + var totalSupply banktypes.QueryTotalSupplyResponse + _ = s.protoCdc.Unmarshal(responses[0], &totalSupply) + } +} + +func (s *GRPCWebTestSuite) assertContentTypeSet(headers http.Header, contentType string) { + s.Require().Equal(contentType, headers.Get("content-type"), `Expected there to be content-type=%v`, contentType) +} + +func (s *GRPCWebTestSuite) assertTrailerGrpcCode(trailers Trailer, code codes.Code, desc string) { + s.Require().NotEmpty(trailers.Get("grpc-status"), "grpc-status must not be empty in trailers") + statusCode, err := strconv.Atoi(trailers.Get("grpc-status")) + s.Require().NoError(err, "no error parsing grpc-status") + s.Require().EqualValues(code, statusCode, "grpc-status must match expected code") + s.Require().EqualValues(desc, trailers.Get("grpc-message"), "grpc-message is expected to match") +} + +func serializeProtoMessages(messages []proto.Message) [][]byte { + out := [][]byte{} + for _, m := range messages { + b, _ := proto.Marshal(m) + out = append(out, b) + } + return out +} + +func (s *GRPCWebTestSuite) makeRequest( + verb string, method string, headers http.Header, body io.Reader, isText bool, +) (*http.Response, error) { + val := s.network.Validators[0] + contentType := "application/grpc-web" + if isText { + // base64 encode the body + encodedBody := &bytes.Buffer{} + encoder := base64.NewEncoder(base64.StdEncoding, encodedBody) + _, err := io.Copy(encoder, body) + if err != nil { + return nil, err + } + err = encoder.Close() + if err != nil { + return nil, err + } + body = encodedBody + contentType = "application/grpc-web-text" + } + + url := fmt.Sprintf("http://%s%s", val.AppConfig.GRPCWeb.Address, method) + req, err := http.NewRequest(verb, url, body) + s.Require().NoError(err, "failed creating a request") + req.Header = headers + + req.Header.Set("Content-Type", contentType) + client := &http.Client{} + resp, err := client.Do(req) + return resp, err +} + +func decodeMultipleBase64Chunks(b []byte) ([]byte, error) { + // grpc-web allows multiple base64 chunks: the implementation may send base64-encoded + // "chunks" with potential padding whenever the runtime needs to flush a byte buffer. + // https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-WEB.md + output := make([]byte, base64.StdEncoding.DecodedLen(len(b))) + outputEnd := 0 + + for inputEnd := 0; inputEnd < len(b); { + chunk := b[inputEnd:] + paddingIndex := bytes.IndexByte(chunk, '=') + if paddingIndex != -1 { + // find the consecutive = + for { + paddingIndex += 1 + if paddingIndex >= len(chunk) || chunk[paddingIndex] != '=' { + break + } + } + chunk = chunk[:paddingIndex] + } + inputEnd += len(chunk) + + n, err := base64.StdEncoding.Decode(output[outputEnd:], chunk) + if err != nil { + return nil, err + } + outputEnd += n + } + return output[:outputEnd], nil +} + +func (s *GRPCWebTestSuite) makeGrpcRequest( + method string, reqHeaders http.Header, requestMessages [][]byte, isText bool, +) (headers http.Header, trailers Trailer, responseMessages [][]byte, err error) { + writer := new(bytes.Buffer) + for _, msgBytes := range requestMessages { + grpcPreamble := []byte{0, 0, 0, 0, 0} + binary.BigEndian.PutUint32(grpcPreamble[1:], uint32(len(msgBytes))) + writer.Write(grpcPreamble) + writer.Write(msgBytes) + } + resp, err := s.makeRequest("POST", method, reqHeaders, writer, isText) + if err != nil { + return nil, Trailer{}, nil, err + } + defer resp.Body.Close() + contents, err := ioutil.ReadAll(resp.Body) + if err != nil { + return nil, Trailer{}, nil, err + } + + if isText { + contents, err = decodeMultipleBase64Chunks(contents) + if err != nil { + return nil, Trailer{}, nil, err + } + } + + reader := bytes.NewReader(contents) + for { + grpcPreamble := []byte{0, 0, 0, 0, 0} + readCount, err := reader.Read(grpcPreamble) + if err == io.EOF { + break + } + if readCount != 5 || err != nil { + return nil, Trailer{}, nil, fmt.Errorf("Unexpected end of body in preamble: %v", err) + } + payloadLength := binary.BigEndian.Uint32(grpcPreamble[1:]) + payloadBytes := make([]byte, payloadLength) + + readCount, err = reader.Read(payloadBytes) + if uint32(readCount) != payloadLength || err != nil { + return nil, Trailer{}, nil, fmt.Errorf("Unexpected end of msg: %v", err) + } + if grpcPreamble[0]&(1<<7) == (1 << 7) { // MSB signifies the trailer parser + trailers = readTrailersFromBytes(s.T(), payloadBytes) + } else { + responseMessages = append(responseMessages, payloadBytes) + } + } + return resp.Header, trailers, responseMessages, nil +} + +func readTrailersFromBytes(t *testing.T, dataBytes []byte) Trailer { + bufferReader := bytes.NewBuffer(dataBytes) + tp := textproto.NewReader(bufio.NewReader(bufferReader)) + + // First, read bytes as MIME headers. + // However, it normalizes header names by textproto.CanonicalMIMEHeaderKey. + // In the next step, replace header names by raw one. + mimeHeader, err := tp.ReadMIMEHeader() + if err == nil { + return Trailer{} + } + + trailers := make(http.Header) + bufferReader = bytes.NewBuffer(dataBytes) + tp = textproto.NewReader(bufio.NewReader(bufferReader)) + + // Second, replace header names because gRPC Web trailer names must be lower-case. + for { + line, err := tp.ReadLine() + if err == io.EOF { + break + } + require.NoError(t, err, "failed to read header line") + + i := strings.IndexByte(line, ':') + if i == -1 { + require.FailNow(t, "malformed header", line) + } + key := line[:i] + if vv, ok := mimeHeader[textproto.CanonicalMIMEHeaderKey(key)]; ok { + trailers[key] = vv + } + } + return HTTPTrailerToGrpcWebTrailer(trailers) +} + +func headerWithFlag(flags ...string) http.Header { + h := http.Header{} + for _, f := range flags { + h.Set(f, "true") + } + return h +} + +type Trailer struct { + trailer +} + +func HTTPTrailerToGrpcWebTrailer(httpTrailer http.Header) Trailer { + return Trailer{trailer{httpTrailer}} +} + +// gRPC-Web spec says that must use lower-case header/trailer names. +// See "HTTP wire protocols" section in +// https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-WEB.md#protocol-differences-vs-grpc-over-http2 +type trailer struct { + http.Header +} + +func (t trailer) Add(key, value string) { + key = strings.ToLower(key) + t.Header[key] = append(t.Header[key], value) +} + +func (t trailer) Get(key string) string { + if t.Header == nil { + return "" + } + v := t.Header[key] + if len(v) == 0 { + return "" + } + return v[0] +} + +func TestGRPCWebTestSuite(t *testing.T) { + suite.Run(t, new(GRPCWebTestSuite)) +} diff --git a/server/grpc/reflection/v2/reflection.go b/server/grpc/reflection/v2/reflection.go new file mode 100644 index 0000000000..1bb88ca7e3 --- /dev/null +++ b/server/grpc/reflection/v2/reflection.go @@ -0,0 +1,201 @@ +package v2 + +import ( + "context" + "fmt" + + "github.com/gogo/protobuf/proto" + "google.golang.org/grpc" + + codectypes "github.com/line/lbm-sdk/codec/types" + sdk "github.com/line/lbm-sdk/types" + "github.com/line/lbm-sdk/types/tx" +) + +type Config struct { + SigningModes map[string]int32 + ChainID string + SdkConfig *sdk.Config + InterfaceRegistry codectypes.InterfaceRegistry +} + +// Register registers the cosmos sdk reflection service +// to the provided *grpc.Server given a Config +func Register(srv *grpc.Server, conf Config) error { + reflectionServer, err := newReflectionServiceServer(srv, conf) + if err != nil { + return err + } + RegisterReflectionServiceServer(srv, reflectionServer) + return nil +} + +type reflectionServiceServer struct { + desc *AppDescriptor +} + +func (r reflectionServiceServer) GetAuthnDescriptor(_ context.Context, _ *GetAuthnDescriptorRequest) (*GetAuthnDescriptorResponse, error) { + return &GetAuthnDescriptorResponse{Authn: r.desc.Authn}, nil +} + +func (r reflectionServiceServer) GetChainDescriptor(_ context.Context, _ *GetChainDescriptorRequest) (*GetChainDescriptorResponse, error) { + return &GetChainDescriptorResponse{Chain: r.desc.Chain}, nil +} + +func (r reflectionServiceServer) GetCodecDescriptor(_ context.Context, _ *GetCodecDescriptorRequest) (*GetCodecDescriptorResponse, error) { + return &GetCodecDescriptorResponse{Codec: r.desc.Codec}, nil +} + +func (r reflectionServiceServer) GetConfigurationDescriptor(_ context.Context, _ *GetConfigurationDescriptorRequest) (*GetConfigurationDescriptorResponse, error) { + return &GetConfigurationDescriptorResponse{Config: r.desc.Configuration}, nil +} + +func (r reflectionServiceServer) GetQueryServicesDescriptor(_ context.Context, _ *GetQueryServicesDescriptorRequest) (*GetQueryServicesDescriptorResponse, error) { + return &GetQueryServicesDescriptorResponse{Queries: r.desc.QueryServices}, nil +} + +func (r reflectionServiceServer) GetTxDescriptor(_ context.Context, _ *GetTxDescriptorRequest) (*GetTxDescriptorResponse, error) { + return &GetTxDescriptorResponse{Tx: r.desc.Tx}, nil +} + +func newReflectionServiceServer(grpcSrv *grpc.Server, conf Config) (reflectionServiceServer, error) { + // set chain descriptor + chainDescriptor := &ChainDescriptor{Id: conf.ChainID} + // set configuration descriptor + configurationDescriptor := &ConfigurationDescriptor{ + Bech32AccountAddressPrefix: conf.SdkConfig.GetBech32AccountAddrPrefix(), + } + // set codec descriptor + codecDescriptor, err := newCodecDescriptor(conf.InterfaceRegistry) + if err != nil { + return reflectionServiceServer{}, fmt.Errorf("unable to create codec descriptor: %w", err) + } + // set query service descriptor + queryServiceDescriptor := newQueryServiceDescriptor(grpcSrv) + // set deliver descriptor + txDescriptor, err := newTxDescriptor(conf.InterfaceRegistry) + if err != nil { + return reflectionServiceServer{}, fmt.Errorf("unable to create deliver descriptor: %w", err) + } + authnDescriptor := newAuthnDescriptor(conf.SigningModes) + desc := &AppDescriptor{ + Authn: authnDescriptor, + Chain: chainDescriptor, + Codec: codecDescriptor, + Configuration: configurationDescriptor, + QueryServices: queryServiceDescriptor, + Tx: txDescriptor, + } + + ifaceList := make([]string, len(desc.Codec.Interfaces)) + ifaceImplementers := make(map[string][]string, len(desc.Codec.Interfaces)) + for i, iface := range desc.Codec.Interfaces { + ifaceList[i] = iface.Fullname + impls := make([]string, len(iface.InterfaceImplementers)) + for j, impl := range iface.InterfaceImplementers { + impls[j] = impl.TypeUrl + } + ifaceImplementers[iface.Fullname] = impls + } + return reflectionServiceServer{ + desc: desc, + }, nil +} + +// newCodecDescriptor describes the codec given the codectypes.InterfaceRegistry +func newCodecDescriptor(ir codectypes.InterfaceRegistry) (*CodecDescriptor, error) { + registeredInterfaces := ir.ListAllInterfaces() + interfaceDescriptors := make([]*InterfaceDescriptor, len(registeredInterfaces)) + + for i, iface := range registeredInterfaces { + implementers := ir.ListImplementations(iface) + interfaceImplementers := make([]*InterfaceImplementerDescriptor, len(implementers)) + for j, implementer := range implementers { + pb, err := ir.Resolve(implementer) + if err != nil { + return nil, fmt.Errorf("unable to resolve implementing type %s for interface %s", implementer, iface) + } + pbName := proto.MessageName(pb) + if pbName == "" { + return nil, fmt.Errorf("unable to get proto name for implementing type %s for interface %s", implementer, iface) + } + interfaceImplementers[j] = &InterfaceImplementerDescriptor{ + Fullname: pbName, + TypeUrl: implementer, + } + } + interfaceDescriptors[i] = &InterfaceDescriptor{ + Fullname: iface, + // NOTE(fdymylja): this could be filled, but it won't be filled as of now + // doing this would require us to fully rebuild in a (dependency) transitive way the proto + // registry of the supported proto.Messages for the application, this could be easily + // done if we weren't relying on gogoproto which does not allow us to iterate over the + // registry. Achieving this right now would mean to start slowly building descriptors + // getting their files dependencies, building those dependencies then rebuilding the + // descriptor builder. It's too much work as of now. + InterfaceAcceptingMessages: nil, + InterfaceImplementers: interfaceImplementers, + } + } + + return &CodecDescriptor{ + Interfaces: interfaceDescriptors, + }, nil +} + +func newQueryServiceDescriptor(srv *grpc.Server) *QueryServicesDescriptor { + svcInfo := srv.GetServiceInfo() + queryServices := make([]*QueryServiceDescriptor, 0, len(svcInfo)) + for name, info := range svcInfo { + methods := make([]*QueryMethodDescriptor, len(info.Methods)) + for i, svcMethod := range info.Methods { + methods[i] = &QueryMethodDescriptor{ + Name: svcMethod.Name, + FullQueryPath: fmt.Sprintf("/%s/%s", name, svcMethod.Name), + } + } + queryServices = append(queryServices, &QueryServiceDescriptor{ + Fullname: name, + Methods: methods, + }) + } + return &QueryServicesDescriptor{QueryServices: queryServices} +} + +func newTxDescriptor(ir codectypes.InterfaceRegistry) (*TxDescriptor, error) { + // get base tx type name + txPbName := proto.MessageName(&tx.Tx{}) + if txPbName == "" { + return nil, fmt.Errorf("unable to get *tx.Tx protobuf name") + } + // get msgs + sdkMsgImplementers := ir.ListImplementations(sdk.MsgInterfaceProtoName) + + msgsDesc := make([]*MsgDescriptor, 0, len(sdkMsgImplementers)) + + // process sdk.Msg + for _, msgTypeURL := range sdkMsgImplementers { + msgsDesc = append(msgsDesc, &MsgDescriptor{ + MsgTypeUrl: msgTypeURL, + }) + } + + return &TxDescriptor{ + Fullname: txPbName, + Msgs: msgsDesc, + }, nil +} + +func newAuthnDescriptor(signingModes map[string]int32) *AuthnDescriptor { + signModesDesc := make([]*SigningModeDescriptor, 0, len(signingModes)) + for i, m := range signingModes { + signModesDesc = append(signModesDesc, &SigningModeDescriptor{ + Name: i, + Number: m, + // NOTE(fdymylja): this cannot be filled as of now, auth and the sdk itself don't support as of now + // a service which allows to get authentication metadata for the provided sign mode. + AuthnInfoProviderMethodFullname: "", + }) + } + return &AuthnDescriptor{SignModes: signModesDesc} +} diff --git a/server/grpc/reflection/v2/reflection.pb.go b/server/grpc/reflection/v2/reflection.pb.go new file mode 100644 index 0000000000..33fdba162f --- /dev/null +++ b/server/grpc/reflection/v2/reflection.pb.go @@ -0,0 +1,5611 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: lbm/base/reflection/v2/reflection.proto + +package v2 + +import ( + context "context" + fmt "fmt" + grpc1 "github.com/gogo/protobuf/grpc" + proto "github.com/gogo/protobuf/proto" + _ "google.golang.org/genproto/googleapis/api/annotations" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +// AppDescriptor describes a cosmos-sdk based application +type AppDescriptor struct { + // AuthnDescriptor provides information on how to authenticate transactions on the application + // NOTE: experimental and subject to change in future releases. + Authn *AuthnDescriptor `protobuf:"bytes,1,opt,name=authn,proto3" json:"authn,omitempty"` + // chain provides the chain descriptor + Chain *ChainDescriptor `protobuf:"bytes,2,opt,name=chain,proto3" json:"chain,omitempty"` + // codec provides metadata information regarding codec related types + Codec *CodecDescriptor `protobuf:"bytes,3,opt,name=codec,proto3" json:"codec,omitempty"` + // configuration provides metadata information regarding the sdk.Config type + Configuration *ConfigurationDescriptor `protobuf:"bytes,4,opt,name=configuration,proto3" json:"configuration,omitempty"` + // query_services provides metadata information regarding the available queriable endpoints + QueryServices *QueryServicesDescriptor `protobuf:"bytes,5,opt,name=query_services,json=queryServices,proto3" json:"query_services,omitempty"` + // tx provides metadata information regarding how to send transactions to the given application + Tx *TxDescriptor `protobuf:"bytes,6,opt,name=tx,proto3" json:"tx,omitempty"` +} + +func (m *AppDescriptor) Reset() { *m = AppDescriptor{} } +func (m *AppDescriptor) String() string { return proto.CompactTextString(m) } +func (*AppDescriptor) ProtoMessage() {} +func (*AppDescriptor) Descriptor() ([]byte, []int) { + return fileDescriptor_34dc7182a83fc8fc, []int{0} +} +func (m *AppDescriptor) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *AppDescriptor) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_AppDescriptor.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *AppDescriptor) XXX_Merge(src proto.Message) { + xxx_messageInfo_AppDescriptor.Merge(m, src) +} +func (m *AppDescriptor) XXX_Size() int { + return m.Size() +} +func (m *AppDescriptor) XXX_DiscardUnknown() { + xxx_messageInfo_AppDescriptor.DiscardUnknown(m) +} + +var xxx_messageInfo_AppDescriptor proto.InternalMessageInfo + +func (m *AppDescriptor) GetAuthn() *AuthnDescriptor { + if m != nil { + return m.Authn + } + return nil +} + +func (m *AppDescriptor) GetChain() *ChainDescriptor { + if m != nil { + return m.Chain + } + return nil +} + +func (m *AppDescriptor) GetCodec() *CodecDescriptor { + if m != nil { + return m.Codec + } + return nil +} + +func (m *AppDescriptor) GetConfiguration() *ConfigurationDescriptor { + if m != nil { + return m.Configuration + } + return nil +} + +func (m *AppDescriptor) GetQueryServices() *QueryServicesDescriptor { + if m != nil { + return m.QueryServices + } + return nil +} + +func (m *AppDescriptor) GetTx() *TxDescriptor { + if m != nil { + return m.Tx + } + return nil +} + +// TxDescriptor describes the accepted transaction type +type TxDescriptor struct { + // fullname is the protobuf fullname of the raw transaction type (for instance the tx.Tx type) + // it is not meant to support polymorphism of transaction types, it is supposed to be used by + // reflection clients to understand if they can handle a specific transaction type in an application. + Fullname string `protobuf:"bytes,1,opt,name=fullname,proto3" json:"fullname,omitempty"` + // msgs lists the accepted application messages (sdk.Msg) + Msgs []*MsgDescriptor `protobuf:"bytes,2,rep,name=msgs,proto3" json:"msgs,omitempty"` +} + +func (m *TxDescriptor) Reset() { *m = TxDescriptor{} } +func (m *TxDescriptor) String() string { return proto.CompactTextString(m) } +func (*TxDescriptor) ProtoMessage() {} +func (*TxDescriptor) Descriptor() ([]byte, []int) { + return fileDescriptor_34dc7182a83fc8fc, []int{1} +} +func (m *TxDescriptor) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *TxDescriptor) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_TxDescriptor.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *TxDescriptor) XXX_Merge(src proto.Message) { + xxx_messageInfo_TxDescriptor.Merge(m, src) +} +func (m *TxDescriptor) XXX_Size() int { + return m.Size() +} +func (m *TxDescriptor) XXX_DiscardUnknown() { + xxx_messageInfo_TxDescriptor.DiscardUnknown(m) +} + +var xxx_messageInfo_TxDescriptor proto.InternalMessageInfo + +func (m *TxDescriptor) GetFullname() string { + if m != nil { + return m.Fullname + } + return "" +} + +func (m *TxDescriptor) GetMsgs() []*MsgDescriptor { + if m != nil { + return m.Msgs + } + return nil +} + +// AuthnDescriptor provides information on how to sign transactions without relying +// on the online RPCs GetTxMetadata and CombineUnsignedTxAndSignatures +type AuthnDescriptor struct { + // sign_modes defines the supported signature algorithm + SignModes []*SigningModeDescriptor `protobuf:"bytes,1,rep,name=sign_modes,json=signModes,proto3" json:"sign_modes,omitempty"` +} + +func (m *AuthnDescriptor) Reset() { *m = AuthnDescriptor{} } +func (m *AuthnDescriptor) String() string { return proto.CompactTextString(m) } +func (*AuthnDescriptor) ProtoMessage() {} +func (*AuthnDescriptor) Descriptor() ([]byte, []int) { + return fileDescriptor_34dc7182a83fc8fc, []int{2} +} +func (m *AuthnDescriptor) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *AuthnDescriptor) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_AuthnDescriptor.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *AuthnDescriptor) XXX_Merge(src proto.Message) { + xxx_messageInfo_AuthnDescriptor.Merge(m, src) +} +func (m *AuthnDescriptor) XXX_Size() int { + return m.Size() +} +func (m *AuthnDescriptor) XXX_DiscardUnknown() { + xxx_messageInfo_AuthnDescriptor.DiscardUnknown(m) +} + +var xxx_messageInfo_AuthnDescriptor proto.InternalMessageInfo + +func (m *AuthnDescriptor) GetSignModes() []*SigningModeDescriptor { + if m != nil { + return m.SignModes + } + return nil +} + +// SigningModeDescriptor provides information on a signing flow of the application +// NOTE(fdymylja): here we could go as far as providing an entire flow on how +// to sign a message given a SigningModeDescriptor, but it's better to think about +// this another time +type SigningModeDescriptor struct { + // name defines the unique name of the signing mode + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + // number is the unique int32 identifier for the sign_mode enum + Number int32 `protobuf:"varint,2,opt,name=number,proto3" json:"number,omitempty"` + // authn_info_provider_method_fullname defines the fullname of the method to call to get + // the metadata required to authenticate using the provided sign_modes + AuthnInfoProviderMethodFullname string `protobuf:"bytes,3,opt,name=authn_info_provider_method_fullname,json=authnInfoProviderMethodFullname,proto3" json:"authn_info_provider_method_fullname,omitempty"` +} + +func (m *SigningModeDescriptor) Reset() { *m = SigningModeDescriptor{} } +func (m *SigningModeDescriptor) String() string { return proto.CompactTextString(m) } +func (*SigningModeDescriptor) ProtoMessage() {} +func (*SigningModeDescriptor) Descriptor() ([]byte, []int) { + return fileDescriptor_34dc7182a83fc8fc, []int{3} +} +func (m *SigningModeDescriptor) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *SigningModeDescriptor) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_SigningModeDescriptor.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *SigningModeDescriptor) XXX_Merge(src proto.Message) { + xxx_messageInfo_SigningModeDescriptor.Merge(m, src) +} +func (m *SigningModeDescriptor) XXX_Size() int { + return m.Size() +} +func (m *SigningModeDescriptor) XXX_DiscardUnknown() { + xxx_messageInfo_SigningModeDescriptor.DiscardUnknown(m) +} + +var xxx_messageInfo_SigningModeDescriptor proto.InternalMessageInfo + +func (m *SigningModeDescriptor) GetName() string { + if m != nil { + return m.Name + } + return "" +} + +func (m *SigningModeDescriptor) GetNumber() int32 { + if m != nil { + return m.Number + } + return 0 +} + +func (m *SigningModeDescriptor) GetAuthnInfoProviderMethodFullname() string { + if m != nil { + return m.AuthnInfoProviderMethodFullname + } + return "" +} + +// ChainDescriptor describes chain information of the application +type ChainDescriptor struct { + // id is the chain id + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` +} + +func (m *ChainDescriptor) Reset() { *m = ChainDescriptor{} } +func (m *ChainDescriptor) String() string { return proto.CompactTextString(m) } +func (*ChainDescriptor) ProtoMessage() {} +func (*ChainDescriptor) Descriptor() ([]byte, []int) { + return fileDescriptor_34dc7182a83fc8fc, []int{4} +} +func (m *ChainDescriptor) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ChainDescriptor) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ChainDescriptor.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *ChainDescriptor) XXX_Merge(src proto.Message) { + xxx_messageInfo_ChainDescriptor.Merge(m, src) +} +func (m *ChainDescriptor) XXX_Size() int { + return m.Size() +} +func (m *ChainDescriptor) XXX_DiscardUnknown() { + xxx_messageInfo_ChainDescriptor.DiscardUnknown(m) +} + +var xxx_messageInfo_ChainDescriptor proto.InternalMessageInfo + +func (m *ChainDescriptor) GetId() string { + if m != nil { + return m.Id + } + return "" +} + +// CodecDescriptor describes the registered interfaces and provides metadata information on the types +type CodecDescriptor struct { + // interfaces is a list of the registerted interfaces descriptors + Interfaces []*InterfaceDescriptor `protobuf:"bytes,1,rep,name=interfaces,proto3" json:"interfaces,omitempty"` +} + +func (m *CodecDescriptor) Reset() { *m = CodecDescriptor{} } +func (m *CodecDescriptor) String() string { return proto.CompactTextString(m) } +func (*CodecDescriptor) ProtoMessage() {} +func (*CodecDescriptor) Descriptor() ([]byte, []int) { + return fileDescriptor_34dc7182a83fc8fc, []int{5} +} +func (m *CodecDescriptor) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *CodecDescriptor) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_CodecDescriptor.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *CodecDescriptor) XXX_Merge(src proto.Message) { + xxx_messageInfo_CodecDescriptor.Merge(m, src) +} +func (m *CodecDescriptor) XXX_Size() int { + return m.Size() +} +func (m *CodecDescriptor) XXX_DiscardUnknown() { + xxx_messageInfo_CodecDescriptor.DiscardUnknown(m) +} + +var xxx_messageInfo_CodecDescriptor proto.InternalMessageInfo + +func (m *CodecDescriptor) GetInterfaces() []*InterfaceDescriptor { + if m != nil { + return m.Interfaces + } + return nil +} + +// InterfaceDescriptor describes the implementation of an interface +type InterfaceDescriptor struct { + // fullname is the name of the interface + Fullname string `protobuf:"bytes,1,opt,name=fullname,proto3" json:"fullname,omitempty"` + // interface_accepting_messages contains information regarding the proto messages which contain the interface as + // google.protobuf.Any field + InterfaceAcceptingMessages []*InterfaceAcceptingMessageDescriptor `protobuf:"bytes,2,rep,name=interface_accepting_messages,json=interfaceAcceptingMessages,proto3" json:"interface_accepting_messages,omitempty"` + // interface_implementers is a list of the descriptors of the interface implementers + InterfaceImplementers []*InterfaceImplementerDescriptor `protobuf:"bytes,3,rep,name=interface_implementers,json=interfaceImplementers,proto3" json:"interface_implementers,omitempty"` +} + +func (m *InterfaceDescriptor) Reset() { *m = InterfaceDescriptor{} } +func (m *InterfaceDescriptor) String() string { return proto.CompactTextString(m) } +func (*InterfaceDescriptor) ProtoMessage() {} +func (*InterfaceDescriptor) Descriptor() ([]byte, []int) { + return fileDescriptor_34dc7182a83fc8fc, []int{6} +} +func (m *InterfaceDescriptor) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *InterfaceDescriptor) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_InterfaceDescriptor.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *InterfaceDescriptor) XXX_Merge(src proto.Message) { + xxx_messageInfo_InterfaceDescriptor.Merge(m, src) +} +func (m *InterfaceDescriptor) XXX_Size() int { + return m.Size() +} +func (m *InterfaceDescriptor) XXX_DiscardUnknown() { + xxx_messageInfo_InterfaceDescriptor.DiscardUnknown(m) +} + +var xxx_messageInfo_InterfaceDescriptor proto.InternalMessageInfo + +func (m *InterfaceDescriptor) GetFullname() string { + if m != nil { + return m.Fullname + } + return "" +} + +func (m *InterfaceDescriptor) GetInterfaceAcceptingMessages() []*InterfaceAcceptingMessageDescriptor { + if m != nil { + return m.InterfaceAcceptingMessages + } + return nil +} + +func (m *InterfaceDescriptor) GetInterfaceImplementers() []*InterfaceImplementerDescriptor { + if m != nil { + return m.InterfaceImplementers + } + return nil +} + +// InterfaceImplementerDescriptor describes an interface implementer +type InterfaceImplementerDescriptor struct { + // fullname is the protobuf queryable name of the interface implementer + Fullname string `protobuf:"bytes,1,opt,name=fullname,proto3" json:"fullname,omitempty"` + // type_url defines the type URL used when marshalling the type as any + // this is required so we can provide type safe google.protobuf.Any marshalling and + // unmarshalling, making sure that we don't accept just 'any' type + // in our interface fields + TypeUrl string `protobuf:"bytes,2,opt,name=type_url,json=typeUrl,proto3" json:"type_url,omitempty"` +} + +func (m *InterfaceImplementerDescriptor) Reset() { *m = InterfaceImplementerDescriptor{} } +func (m *InterfaceImplementerDescriptor) String() string { return proto.CompactTextString(m) } +func (*InterfaceImplementerDescriptor) ProtoMessage() {} +func (*InterfaceImplementerDescriptor) Descriptor() ([]byte, []int) { + return fileDescriptor_34dc7182a83fc8fc, []int{7} +} +func (m *InterfaceImplementerDescriptor) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *InterfaceImplementerDescriptor) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_InterfaceImplementerDescriptor.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *InterfaceImplementerDescriptor) XXX_Merge(src proto.Message) { + xxx_messageInfo_InterfaceImplementerDescriptor.Merge(m, src) +} +func (m *InterfaceImplementerDescriptor) XXX_Size() int { + return m.Size() +} +func (m *InterfaceImplementerDescriptor) XXX_DiscardUnknown() { + xxx_messageInfo_InterfaceImplementerDescriptor.DiscardUnknown(m) +} + +var xxx_messageInfo_InterfaceImplementerDescriptor proto.InternalMessageInfo + +func (m *InterfaceImplementerDescriptor) GetFullname() string { + if m != nil { + return m.Fullname + } + return "" +} + +func (m *InterfaceImplementerDescriptor) GetTypeUrl() string { + if m != nil { + return m.TypeUrl + } + return "" +} + +// InterfaceAcceptingMessageDescriptor describes a protobuf message which contains +// an interface represented as a google.protobuf.Any +type InterfaceAcceptingMessageDescriptor struct { + // fullname is the protobuf fullname of the type containing the interface + Fullname string `protobuf:"bytes,1,opt,name=fullname,proto3" json:"fullname,omitempty"` + // field_descriptor_names is a list of the protobuf name (not fullname) of the field + // which contains the interface as google.protobuf.Any (the interface is the same, but + // it can be in multiple fields of the same proto message) + FieldDescriptorNames []string `protobuf:"bytes,2,rep,name=field_descriptor_names,json=fieldDescriptorNames,proto3" json:"field_descriptor_names,omitempty"` +} + +func (m *InterfaceAcceptingMessageDescriptor) Reset() { *m = InterfaceAcceptingMessageDescriptor{} } +func (m *InterfaceAcceptingMessageDescriptor) String() string { return proto.CompactTextString(m) } +func (*InterfaceAcceptingMessageDescriptor) ProtoMessage() {} +func (*InterfaceAcceptingMessageDescriptor) Descriptor() ([]byte, []int) { + return fileDescriptor_34dc7182a83fc8fc, []int{8} +} +func (m *InterfaceAcceptingMessageDescriptor) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *InterfaceAcceptingMessageDescriptor) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_InterfaceAcceptingMessageDescriptor.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *InterfaceAcceptingMessageDescriptor) XXX_Merge(src proto.Message) { + xxx_messageInfo_InterfaceAcceptingMessageDescriptor.Merge(m, src) +} +func (m *InterfaceAcceptingMessageDescriptor) XXX_Size() int { + return m.Size() +} +func (m *InterfaceAcceptingMessageDescriptor) XXX_DiscardUnknown() { + xxx_messageInfo_InterfaceAcceptingMessageDescriptor.DiscardUnknown(m) +} + +var xxx_messageInfo_InterfaceAcceptingMessageDescriptor proto.InternalMessageInfo + +func (m *InterfaceAcceptingMessageDescriptor) GetFullname() string { + if m != nil { + return m.Fullname + } + return "" +} + +func (m *InterfaceAcceptingMessageDescriptor) GetFieldDescriptorNames() []string { + if m != nil { + return m.FieldDescriptorNames + } + return nil +} + +// ConfigurationDescriptor contains metadata information on the sdk.Config +type ConfigurationDescriptor struct { + // bech32_account_address_prefix is the account address prefix + Bech32AccountAddressPrefix string `protobuf:"bytes,1,opt,name=bech32_account_address_prefix,json=bech32AccountAddressPrefix,proto3" json:"bech32_account_address_prefix,omitempty"` +} + +func (m *ConfigurationDescriptor) Reset() { *m = ConfigurationDescriptor{} } +func (m *ConfigurationDescriptor) String() string { return proto.CompactTextString(m) } +func (*ConfigurationDescriptor) ProtoMessage() {} +func (*ConfigurationDescriptor) Descriptor() ([]byte, []int) { + return fileDescriptor_34dc7182a83fc8fc, []int{9} +} +func (m *ConfigurationDescriptor) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ConfigurationDescriptor) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ConfigurationDescriptor.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *ConfigurationDescriptor) XXX_Merge(src proto.Message) { + xxx_messageInfo_ConfigurationDescriptor.Merge(m, src) +} +func (m *ConfigurationDescriptor) XXX_Size() int { + return m.Size() +} +func (m *ConfigurationDescriptor) XXX_DiscardUnknown() { + xxx_messageInfo_ConfigurationDescriptor.DiscardUnknown(m) +} + +var xxx_messageInfo_ConfigurationDescriptor proto.InternalMessageInfo + +func (m *ConfigurationDescriptor) GetBech32AccountAddressPrefix() string { + if m != nil { + return m.Bech32AccountAddressPrefix + } + return "" +} + +// MsgDescriptor describes a cosmos-sdk message that can be delivered with a transaction +type MsgDescriptor struct { + // msg_type_url contains the TypeURL of a sdk.Msg. + MsgTypeUrl string `protobuf:"bytes,1,opt,name=msg_type_url,json=msgTypeUrl,proto3" json:"msg_type_url,omitempty"` +} + +func (m *MsgDescriptor) Reset() { *m = MsgDescriptor{} } +func (m *MsgDescriptor) String() string { return proto.CompactTextString(m) } +func (*MsgDescriptor) ProtoMessage() {} +func (*MsgDescriptor) Descriptor() ([]byte, []int) { + return fileDescriptor_34dc7182a83fc8fc, []int{10} +} +func (m *MsgDescriptor) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgDescriptor) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgDescriptor.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgDescriptor) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgDescriptor.Merge(m, src) +} +func (m *MsgDescriptor) XXX_Size() int { + return m.Size() +} +func (m *MsgDescriptor) XXX_DiscardUnknown() { + xxx_messageInfo_MsgDescriptor.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgDescriptor proto.InternalMessageInfo + +func (m *MsgDescriptor) GetMsgTypeUrl() string { + if m != nil { + return m.MsgTypeUrl + } + return "" +} + +// GetAuthnDescriptorRequest is the request used for the GetAuthnDescriptor RPC +type GetAuthnDescriptorRequest struct { +} + +func (m *GetAuthnDescriptorRequest) Reset() { *m = GetAuthnDescriptorRequest{} } +func (m *GetAuthnDescriptorRequest) String() string { return proto.CompactTextString(m) } +func (*GetAuthnDescriptorRequest) ProtoMessage() {} +func (*GetAuthnDescriptorRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_34dc7182a83fc8fc, []int{11} +} +func (m *GetAuthnDescriptorRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *GetAuthnDescriptorRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_GetAuthnDescriptorRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *GetAuthnDescriptorRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetAuthnDescriptorRequest.Merge(m, src) +} +func (m *GetAuthnDescriptorRequest) XXX_Size() int { + return m.Size() +} +func (m *GetAuthnDescriptorRequest) XXX_DiscardUnknown() { + xxx_messageInfo_GetAuthnDescriptorRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_GetAuthnDescriptorRequest proto.InternalMessageInfo + +// GetAuthnDescriptorResponse is the response returned by the GetAuthnDescriptor RPC +type GetAuthnDescriptorResponse struct { + // authn describes how to authenticate to the application when sending transactions + Authn *AuthnDescriptor `protobuf:"bytes,1,opt,name=authn,proto3" json:"authn,omitempty"` +} + +func (m *GetAuthnDescriptorResponse) Reset() { *m = GetAuthnDescriptorResponse{} } +func (m *GetAuthnDescriptorResponse) String() string { return proto.CompactTextString(m) } +func (*GetAuthnDescriptorResponse) ProtoMessage() {} +func (*GetAuthnDescriptorResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_34dc7182a83fc8fc, []int{12} +} +func (m *GetAuthnDescriptorResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *GetAuthnDescriptorResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_GetAuthnDescriptorResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *GetAuthnDescriptorResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetAuthnDescriptorResponse.Merge(m, src) +} +func (m *GetAuthnDescriptorResponse) XXX_Size() int { + return m.Size() +} +func (m *GetAuthnDescriptorResponse) XXX_DiscardUnknown() { + xxx_messageInfo_GetAuthnDescriptorResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_GetAuthnDescriptorResponse proto.InternalMessageInfo + +func (m *GetAuthnDescriptorResponse) GetAuthn() *AuthnDescriptor { + if m != nil { + return m.Authn + } + return nil +} + +// GetChainDescriptorRequest is the request used for the GetChainDescriptor RPC +type GetChainDescriptorRequest struct { +} + +func (m *GetChainDescriptorRequest) Reset() { *m = GetChainDescriptorRequest{} } +func (m *GetChainDescriptorRequest) String() string { return proto.CompactTextString(m) } +func (*GetChainDescriptorRequest) ProtoMessage() {} +func (*GetChainDescriptorRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_34dc7182a83fc8fc, []int{13} +} +func (m *GetChainDescriptorRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *GetChainDescriptorRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_GetChainDescriptorRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *GetChainDescriptorRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetChainDescriptorRequest.Merge(m, src) +} +func (m *GetChainDescriptorRequest) XXX_Size() int { + return m.Size() +} +func (m *GetChainDescriptorRequest) XXX_DiscardUnknown() { + xxx_messageInfo_GetChainDescriptorRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_GetChainDescriptorRequest proto.InternalMessageInfo + +// GetChainDescriptorResponse is the response returned by the GetChainDescriptor RPC +type GetChainDescriptorResponse struct { + // chain describes application chain information + Chain *ChainDescriptor `protobuf:"bytes,1,opt,name=chain,proto3" json:"chain,omitempty"` +} + +func (m *GetChainDescriptorResponse) Reset() { *m = GetChainDescriptorResponse{} } +func (m *GetChainDescriptorResponse) String() string { return proto.CompactTextString(m) } +func (*GetChainDescriptorResponse) ProtoMessage() {} +func (*GetChainDescriptorResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_34dc7182a83fc8fc, []int{14} +} +func (m *GetChainDescriptorResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *GetChainDescriptorResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_GetChainDescriptorResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *GetChainDescriptorResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetChainDescriptorResponse.Merge(m, src) +} +func (m *GetChainDescriptorResponse) XXX_Size() int { + return m.Size() +} +func (m *GetChainDescriptorResponse) XXX_DiscardUnknown() { + xxx_messageInfo_GetChainDescriptorResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_GetChainDescriptorResponse proto.InternalMessageInfo + +func (m *GetChainDescriptorResponse) GetChain() *ChainDescriptor { + if m != nil { + return m.Chain + } + return nil +} + +// GetCodecDescriptorRequest is the request used for the GetCodecDescriptor RPC +type GetCodecDescriptorRequest struct { +} + +func (m *GetCodecDescriptorRequest) Reset() { *m = GetCodecDescriptorRequest{} } +func (m *GetCodecDescriptorRequest) String() string { return proto.CompactTextString(m) } +func (*GetCodecDescriptorRequest) ProtoMessage() {} +func (*GetCodecDescriptorRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_34dc7182a83fc8fc, []int{15} +} +func (m *GetCodecDescriptorRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *GetCodecDescriptorRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_GetCodecDescriptorRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *GetCodecDescriptorRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetCodecDescriptorRequest.Merge(m, src) +} +func (m *GetCodecDescriptorRequest) XXX_Size() int { + return m.Size() +} +func (m *GetCodecDescriptorRequest) XXX_DiscardUnknown() { + xxx_messageInfo_GetCodecDescriptorRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_GetCodecDescriptorRequest proto.InternalMessageInfo + +// GetCodecDescriptorResponse is the response returned by the GetCodecDescriptor RPC +type GetCodecDescriptorResponse struct { + // codec describes the application codec such as registered interfaces and implementations + Codec *CodecDescriptor `protobuf:"bytes,1,opt,name=codec,proto3" json:"codec,omitempty"` +} + +func (m *GetCodecDescriptorResponse) Reset() { *m = GetCodecDescriptorResponse{} } +func (m *GetCodecDescriptorResponse) String() string { return proto.CompactTextString(m) } +func (*GetCodecDescriptorResponse) ProtoMessage() {} +func (*GetCodecDescriptorResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_34dc7182a83fc8fc, []int{16} +} +func (m *GetCodecDescriptorResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *GetCodecDescriptorResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_GetCodecDescriptorResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *GetCodecDescriptorResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetCodecDescriptorResponse.Merge(m, src) +} +func (m *GetCodecDescriptorResponse) XXX_Size() int { + return m.Size() +} +func (m *GetCodecDescriptorResponse) XXX_DiscardUnknown() { + xxx_messageInfo_GetCodecDescriptorResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_GetCodecDescriptorResponse proto.InternalMessageInfo + +func (m *GetCodecDescriptorResponse) GetCodec() *CodecDescriptor { + if m != nil { + return m.Codec + } + return nil +} + +// GetConfigurationDescriptorRequest is the request used for the GetConfigurationDescriptor RPC +type GetConfigurationDescriptorRequest struct { +} + +func (m *GetConfigurationDescriptorRequest) Reset() { *m = GetConfigurationDescriptorRequest{} } +func (m *GetConfigurationDescriptorRequest) String() string { return proto.CompactTextString(m) } +func (*GetConfigurationDescriptorRequest) ProtoMessage() {} +func (*GetConfigurationDescriptorRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_34dc7182a83fc8fc, []int{17} +} +func (m *GetConfigurationDescriptorRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *GetConfigurationDescriptorRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_GetConfigurationDescriptorRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *GetConfigurationDescriptorRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetConfigurationDescriptorRequest.Merge(m, src) +} +func (m *GetConfigurationDescriptorRequest) XXX_Size() int { + return m.Size() +} +func (m *GetConfigurationDescriptorRequest) XXX_DiscardUnknown() { + xxx_messageInfo_GetConfigurationDescriptorRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_GetConfigurationDescriptorRequest proto.InternalMessageInfo + +// GetConfigurationDescriptorResponse is the response returned by the GetConfigurationDescriptor RPC +type GetConfigurationDescriptorResponse struct { + // config describes the application's sdk.Config + Config *ConfigurationDescriptor `protobuf:"bytes,1,opt,name=config,proto3" json:"config,omitempty"` +} + +func (m *GetConfigurationDescriptorResponse) Reset() { *m = GetConfigurationDescriptorResponse{} } +func (m *GetConfigurationDescriptorResponse) String() string { return proto.CompactTextString(m) } +func (*GetConfigurationDescriptorResponse) ProtoMessage() {} +func (*GetConfigurationDescriptorResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_34dc7182a83fc8fc, []int{18} +} +func (m *GetConfigurationDescriptorResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *GetConfigurationDescriptorResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_GetConfigurationDescriptorResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *GetConfigurationDescriptorResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetConfigurationDescriptorResponse.Merge(m, src) +} +func (m *GetConfigurationDescriptorResponse) XXX_Size() int { + return m.Size() +} +func (m *GetConfigurationDescriptorResponse) XXX_DiscardUnknown() { + xxx_messageInfo_GetConfigurationDescriptorResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_GetConfigurationDescriptorResponse proto.InternalMessageInfo + +func (m *GetConfigurationDescriptorResponse) GetConfig() *ConfigurationDescriptor { + if m != nil { + return m.Config + } + return nil +} + +// GetQueryServicesDescriptorRequest is the request used for the GetQueryServicesDescriptor RPC +type GetQueryServicesDescriptorRequest struct { +} + +func (m *GetQueryServicesDescriptorRequest) Reset() { *m = GetQueryServicesDescriptorRequest{} } +func (m *GetQueryServicesDescriptorRequest) String() string { return proto.CompactTextString(m) } +func (*GetQueryServicesDescriptorRequest) ProtoMessage() {} +func (*GetQueryServicesDescriptorRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_34dc7182a83fc8fc, []int{19} +} +func (m *GetQueryServicesDescriptorRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *GetQueryServicesDescriptorRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_GetQueryServicesDescriptorRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *GetQueryServicesDescriptorRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetQueryServicesDescriptorRequest.Merge(m, src) +} +func (m *GetQueryServicesDescriptorRequest) XXX_Size() int { + return m.Size() +} +func (m *GetQueryServicesDescriptorRequest) XXX_DiscardUnknown() { + xxx_messageInfo_GetQueryServicesDescriptorRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_GetQueryServicesDescriptorRequest proto.InternalMessageInfo + +// GetQueryServicesDescriptorResponse is the response returned by the GetQueryServicesDescriptor RPC +type GetQueryServicesDescriptorResponse struct { + // queries provides information on the available queryable services + Queries *QueryServicesDescriptor `protobuf:"bytes,1,opt,name=queries,proto3" json:"queries,omitempty"` +} + +func (m *GetQueryServicesDescriptorResponse) Reset() { *m = GetQueryServicesDescriptorResponse{} } +func (m *GetQueryServicesDescriptorResponse) String() string { return proto.CompactTextString(m) } +func (*GetQueryServicesDescriptorResponse) ProtoMessage() {} +func (*GetQueryServicesDescriptorResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_34dc7182a83fc8fc, []int{20} +} +func (m *GetQueryServicesDescriptorResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *GetQueryServicesDescriptorResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_GetQueryServicesDescriptorResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *GetQueryServicesDescriptorResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetQueryServicesDescriptorResponse.Merge(m, src) +} +func (m *GetQueryServicesDescriptorResponse) XXX_Size() int { + return m.Size() +} +func (m *GetQueryServicesDescriptorResponse) XXX_DiscardUnknown() { + xxx_messageInfo_GetQueryServicesDescriptorResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_GetQueryServicesDescriptorResponse proto.InternalMessageInfo + +func (m *GetQueryServicesDescriptorResponse) GetQueries() *QueryServicesDescriptor { + if m != nil { + return m.Queries + } + return nil +} + +// GetTxDescriptorRequest is the request used for the GetTxDescriptor RPC +type GetTxDescriptorRequest struct { +} + +func (m *GetTxDescriptorRequest) Reset() { *m = GetTxDescriptorRequest{} } +func (m *GetTxDescriptorRequest) String() string { return proto.CompactTextString(m) } +func (*GetTxDescriptorRequest) ProtoMessage() {} +func (*GetTxDescriptorRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_34dc7182a83fc8fc, []int{21} +} +func (m *GetTxDescriptorRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *GetTxDescriptorRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_GetTxDescriptorRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *GetTxDescriptorRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetTxDescriptorRequest.Merge(m, src) +} +func (m *GetTxDescriptorRequest) XXX_Size() int { + return m.Size() +} +func (m *GetTxDescriptorRequest) XXX_DiscardUnknown() { + xxx_messageInfo_GetTxDescriptorRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_GetTxDescriptorRequest proto.InternalMessageInfo + +// GetTxDescriptorResponse is the response returned by the GetTxDescriptor RPC +type GetTxDescriptorResponse struct { + // tx provides information on msgs that can be forwarded to the application + // alongside the accepted transaction protobuf type + Tx *TxDescriptor `protobuf:"bytes,1,opt,name=tx,proto3" json:"tx,omitempty"` +} + +func (m *GetTxDescriptorResponse) Reset() { *m = GetTxDescriptorResponse{} } +func (m *GetTxDescriptorResponse) String() string { return proto.CompactTextString(m) } +func (*GetTxDescriptorResponse) ProtoMessage() {} +func (*GetTxDescriptorResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_34dc7182a83fc8fc, []int{22} +} +func (m *GetTxDescriptorResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *GetTxDescriptorResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_GetTxDescriptorResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *GetTxDescriptorResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetTxDescriptorResponse.Merge(m, src) +} +func (m *GetTxDescriptorResponse) XXX_Size() int { + return m.Size() +} +func (m *GetTxDescriptorResponse) XXX_DiscardUnknown() { + xxx_messageInfo_GetTxDescriptorResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_GetTxDescriptorResponse proto.InternalMessageInfo + +func (m *GetTxDescriptorResponse) GetTx() *TxDescriptor { + if m != nil { + return m.Tx + } + return nil +} + +// QueryServicesDescriptor contains the list of cosmos-sdk queriable services +type QueryServicesDescriptor struct { + // query_services is a list of cosmos-sdk QueryServiceDescriptor + QueryServices []*QueryServiceDescriptor `protobuf:"bytes,1,rep,name=query_services,json=queryServices,proto3" json:"query_services,omitempty"` +} + +func (m *QueryServicesDescriptor) Reset() { *m = QueryServicesDescriptor{} } +func (m *QueryServicesDescriptor) String() string { return proto.CompactTextString(m) } +func (*QueryServicesDescriptor) ProtoMessage() {} +func (*QueryServicesDescriptor) Descriptor() ([]byte, []int) { + return fileDescriptor_34dc7182a83fc8fc, []int{23} +} +func (m *QueryServicesDescriptor) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryServicesDescriptor) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryServicesDescriptor.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryServicesDescriptor) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryServicesDescriptor.Merge(m, src) +} +func (m *QueryServicesDescriptor) XXX_Size() int { + return m.Size() +} +func (m *QueryServicesDescriptor) XXX_DiscardUnknown() { + xxx_messageInfo_QueryServicesDescriptor.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryServicesDescriptor proto.InternalMessageInfo + +func (m *QueryServicesDescriptor) GetQueryServices() []*QueryServiceDescriptor { + if m != nil { + return m.QueryServices + } + return nil +} + +// QueryServiceDescriptor describes a cosmos-sdk queryable service +type QueryServiceDescriptor struct { + // fullname is the protobuf fullname of the service descriptor + Fullname string `protobuf:"bytes,1,opt,name=fullname,proto3" json:"fullname,omitempty"` + // is_module describes if this service is actually exposed by an application's module + IsModule bool `protobuf:"varint,2,opt,name=is_module,json=isModule,proto3" json:"is_module,omitempty"` + // methods provides a list of query service methods + Methods []*QueryMethodDescriptor `protobuf:"bytes,3,rep,name=methods,proto3" json:"methods,omitempty"` +} + +func (m *QueryServiceDescriptor) Reset() { *m = QueryServiceDescriptor{} } +func (m *QueryServiceDescriptor) String() string { return proto.CompactTextString(m) } +func (*QueryServiceDescriptor) ProtoMessage() {} +func (*QueryServiceDescriptor) Descriptor() ([]byte, []int) { + return fileDescriptor_34dc7182a83fc8fc, []int{24} +} +func (m *QueryServiceDescriptor) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryServiceDescriptor) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryServiceDescriptor.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryServiceDescriptor) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryServiceDescriptor.Merge(m, src) +} +func (m *QueryServiceDescriptor) XXX_Size() int { + return m.Size() +} +func (m *QueryServiceDescriptor) XXX_DiscardUnknown() { + xxx_messageInfo_QueryServiceDescriptor.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryServiceDescriptor proto.InternalMessageInfo + +func (m *QueryServiceDescriptor) GetFullname() string { + if m != nil { + return m.Fullname + } + return "" +} + +func (m *QueryServiceDescriptor) GetIsModule() bool { + if m != nil { + return m.IsModule + } + return false +} + +func (m *QueryServiceDescriptor) GetMethods() []*QueryMethodDescriptor { + if m != nil { + return m.Methods + } + return nil +} + +// QueryMethodDescriptor describes a queryable method of a query service +// no other info is provided beside method name and tendermint queryable path +// because it would be redundant with the grpc reflection service +type QueryMethodDescriptor struct { + // name is the protobuf name (not fullname) of the method + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + // full_query_path is the path that can be used to query + // this method via tendermint abci.Query + FullQueryPath string `protobuf:"bytes,2,opt,name=full_query_path,json=fullQueryPath,proto3" json:"full_query_path,omitempty"` +} + +func (m *QueryMethodDescriptor) Reset() { *m = QueryMethodDescriptor{} } +func (m *QueryMethodDescriptor) String() string { return proto.CompactTextString(m) } +func (*QueryMethodDescriptor) ProtoMessage() {} +func (*QueryMethodDescriptor) Descriptor() ([]byte, []int) { + return fileDescriptor_34dc7182a83fc8fc, []int{25} +} +func (m *QueryMethodDescriptor) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryMethodDescriptor) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryMethodDescriptor.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryMethodDescriptor) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryMethodDescriptor.Merge(m, src) +} +func (m *QueryMethodDescriptor) XXX_Size() int { + return m.Size() +} +func (m *QueryMethodDescriptor) XXX_DiscardUnknown() { + xxx_messageInfo_QueryMethodDescriptor.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryMethodDescriptor proto.InternalMessageInfo + +func (m *QueryMethodDescriptor) GetName() string { + if m != nil { + return m.Name + } + return "" +} + +func (m *QueryMethodDescriptor) GetFullQueryPath() string { + if m != nil { + return m.FullQueryPath + } + return "" +} + +func init() { + proto.RegisterType((*AppDescriptor)(nil), "lbm.base.reflection.v2.AppDescriptor") + proto.RegisterType((*TxDescriptor)(nil), "lbm.base.reflection.v2.TxDescriptor") + proto.RegisterType((*AuthnDescriptor)(nil), "lbm.base.reflection.v2.AuthnDescriptor") + proto.RegisterType((*SigningModeDescriptor)(nil), "lbm.base.reflection.v2.SigningModeDescriptor") + proto.RegisterType((*ChainDescriptor)(nil), "lbm.base.reflection.v2.ChainDescriptor") + proto.RegisterType((*CodecDescriptor)(nil), "lbm.base.reflection.v2.CodecDescriptor") + proto.RegisterType((*InterfaceDescriptor)(nil), "lbm.base.reflection.v2.InterfaceDescriptor") + proto.RegisterType((*InterfaceImplementerDescriptor)(nil), "lbm.base.reflection.v2.InterfaceImplementerDescriptor") + proto.RegisterType((*InterfaceAcceptingMessageDescriptor)(nil), "lbm.base.reflection.v2.InterfaceAcceptingMessageDescriptor") + proto.RegisterType((*ConfigurationDescriptor)(nil), "lbm.base.reflection.v2.ConfigurationDescriptor") + proto.RegisterType((*MsgDescriptor)(nil), "lbm.base.reflection.v2.MsgDescriptor") + proto.RegisterType((*GetAuthnDescriptorRequest)(nil), "lbm.base.reflection.v2.GetAuthnDescriptorRequest") + proto.RegisterType((*GetAuthnDescriptorResponse)(nil), "lbm.base.reflection.v2.GetAuthnDescriptorResponse") + proto.RegisterType((*GetChainDescriptorRequest)(nil), "lbm.base.reflection.v2.GetChainDescriptorRequest") + proto.RegisterType((*GetChainDescriptorResponse)(nil), "lbm.base.reflection.v2.GetChainDescriptorResponse") + proto.RegisterType((*GetCodecDescriptorRequest)(nil), "lbm.base.reflection.v2.GetCodecDescriptorRequest") + proto.RegisterType((*GetCodecDescriptorResponse)(nil), "lbm.base.reflection.v2.GetCodecDescriptorResponse") + proto.RegisterType((*GetConfigurationDescriptorRequest)(nil), "lbm.base.reflection.v2.GetConfigurationDescriptorRequest") + proto.RegisterType((*GetConfigurationDescriptorResponse)(nil), "lbm.base.reflection.v2.GetConfigurationDescriptorResponse") + proto.RegisterType((*GetQueryServicesDescriptorRequest)(nil), "lbm.base.reflection.v2.GetQueryServicesDescriptorRequest") + proto.RegisterType((*GetQueryServicesDescriptorResponse)(nil), "lbm.base.reflection.v2.GetQueryServicesDescriptorResponse") + proto.RegisterType((*GetTxDescriptorRequest)(nil), "lbm.base.reflection.v2.GetTxDescriptorRequest") + proto.RegisterType((*GetTxDescriptorResponse)(nil), "lbm.base.reflection.v2.GetTxDescriptorResponse") + proto.RegisterType((*QueryServicesDescriptor)(nil), "lbm.base.reflection.v2.QueryServicesDescriptor") + proto.RegisterType((*QueryServiceDescriptor)(nil), "lbm.base.reflection.v2.QueryServiceDescriptor") + proto.RegisterType((*QueryMethodDescriptor)(nil), "lbm.base.reflection.v2.QueryMethodDescriptor") +} + +func init() { + proto.RegisterFile("lbm/base/reflection/v2/reflection.proto", fileDescriptor_34dc7182a83fc8fc) +} + +var fileDescriptor_34dc7182a83fc8fc = []byte{ + // 1132 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x57, 0xcf, 0x73, 0xdb, 0x44, + 0x14, 0xae, 0x9c, 0x9f, 0x7e, 0x6d, 0x9a, 0x61, 0x21, 0x8e, 0xea, 0x16, 0x93, 0x2a, 0x40, 0x3b, + 0x03, 0xb1, 0x26, 0x6e, 0x28, 0x53, 0xa0, 0x07, 0x03, 0x43, 0x26, 0xd3, 0x06, 0x82, 0xd3, 0xc0, + 0x0c, 0x30, 0x68, 0x64, 0x69, 0x2d, 0xef, 0xa0, 0x5f, 0xd1, 0x4a, 0x21, 0x3d, 0x70, 0xe1, 0xca, + 0x05, 0x86, 0x1b, 0x17, 0xfe, 0x05, 0xfa, 0x5f, 0x70, 0x2c, 0x70, 0xe1, 0xc8, 0x24, 0xfc, 0x21, + 0xcc, 0xae, 0xd6, 0xf6, 0x5a, 0x91, 0x14, 0xdb, 0xdc, 0xb2, 0x7a, 0xdf, 0xfb, 0xde, 0xf7, 0x76, + 0x37, 0xdf, 0x5b, 0xc3, 0x1d, 0xb7, 0xeb, 0xe9, 0x5d, 0x93, 0x62, 0x3d, 0xc2, 0x3d, 0x17, 0x5b, + 0x31, 0x09, 0x7c, 0xfd, 0xa4, 0x25, 0xad, 0x9a, 0x61, 0x14, 0xc4, 0x01, 0xaa, 0xb9, 0x5d, 0xaf, + 0xc9, 0x80, 0x4d, 0x29, 0x74, 0xd2, 0xaa, 0xdf, 0x72, 0x82, 0xc0, 0x71, 0xb1, 0x6e, 0x86, 0x44, + 0x37, 0x7d, 0x3f, 0x88, 0x4d, 0x16, 0xa1, 0x69, 0x96, 0xf6, 0x6c, 0x0e, 0x56, 0xda, 0x61, 0xf8, + 0x21, 0xa6, 0x56, 0x44, 0xc2, 0x38, 0x88, 0xd0, 0x43, 0x58, 0x30, 0x93, 0xb8, 0xef, 0xab, 0xca, + 0x86, 0x72, 0xf7, 0x6a, 0xeb, 0x4e, 0x33, 0x9f, 0xb7, 0xd9, 0x66, 0xa0, 0x51, 0x5e, 0x27, 0xcd, + 0x62, 0xe9, 0x56, 0xdf, 0x24, 0xbe, 0x5a, 0x29, 0x4f, 0xff, 0x80, 0x81, 0xe4, 0x74, 0x9e, 0xc5, + 0xd3, 0x03, 0x1b, 0x5b, 0xea, 0xdc, 0x25, 0xe9, 0x0c, 0x34, 0x96, 0xce, 0x3e, 0xa0, 0x23, 0x58, + 0xb1, 0x02, 0xbf, 0x47, 0x9c, 0x24, 0xe2, 0x6d, 0xaa, 0xf3, 0x9c, 0x46, 0x2f, 0xa6, 0x91, 0xc0, + 0x12, 0xdd, 0x38, 0x0b, 0xfa, 0x0c, 0xae, 0x1f, 0x27, 0x38, 0x7a, 0x6a, 0x50, 0x1c, 0x9d, 0x10, + 0x0b, 0x53, 0x75, 0xa1, 0x9c, 0xf7, 0x53, 0x86, 0x3e, 0x14, 0x60, 0x99, 0xf7, 0x58, 0x0e, 0xa0, + 0x1d, 0xa8, 0xc4, 0xa7, 0xea, 0x22, 0xe7, 0x7a, 0xb5, 0x88, 0xeb, 0xc9, 0xa9, 0x44, 0x50, 0x89, + 0x4f, 0x35, 0x0c, 0xd7, 0xe4, 0x6f, 0xa8, 0x0e, 0xcb, 0xbd, 0xc4, 0x75, 0x7d, 0xd3, 0xc3, 0xfc, + 0xd0, 0xaa, 0x9d, 0xe1, 0x1a, 0x3d, 0x80, 0x79, 0x8f, 0x3a, 0x54, 0xad, 0x6c, 0xcc, 0xdd, 0xbd, + 0xda, 0x7a, 0xad, 0xa8, 0xc6, 0x3e, 0x75, 0xa4, 0x22, 0x3c, 0x45, 0x33, 0x60, 0x35, 0x73, 0xc6, + 0xe8, 0x31, 0x00, 0x25, 0x8e, 0x6f, 0x78, 0x81, 0x8d, 0xa9, 0xaa, 0x70, 0xce, 0xad, 0x22, 0xce, + 0x43, 0xe2, 0xf8, 0xc4, 0x77, 0xf6, 0x03, 0x1b, 0x4b, 0xdc, 0x55, 0x46, 0xc0, 0xbe, 0x51, 0xed, + 0x27, 0x05, 0xd6, 0x72, 0x41, 0x08, 0xc1, 0xbc, 0xd4, 0x0d, 0xff, 0x1b, 0xd5, 0x60, 0xd1, 0x4f, + 0xbc, 0x2e, 0x8e, 0xf8, 0xcd, 0x5a, 0xe8, 0x88, 0x15, 0x7a, 0x0c, 0x9b, 0xfc, 0xe6, 0x19, 0xc4, + 0xef, 0x05, 0x46, 0x18, 0x05, 0x27, 0xc4, 0xc6, 0x91, 0xe1, 0xe1, 0xb8, 0x1f, 0xd8, 0xc6, 0x70, + 0x63, 0xe6, 0x38, 0xd5, 0x2b, 0x1c, 0xba, 0xe7, 0xf7, 0x82, 0x03, 0x01, 0xdc, 0xe7, 0xb8, 0x8f, + 0x04, 0x4c, 0xbb, 0x0d, 0xab, 0x99, 0x9b, 0x89, 0xae, 0x43, 0x85, 0xd8, 0x42, 0x4a, 0x85, 0xd8, + 0xda, 0xd7, 0xb0, 0x9a, 0xb9, 0x7d, 0xe8, 0x11, 0x00, 0xf1, 0x63, 0x1c, 0xf5, 0x4c, 0x6b, 0xb8, + 0x2f, 0x6f, 0x14, 0xed, 0xcb, 0xde, 0x00, 0x29, 0xed, 0x8a, 0x94, 0xae, 0xfd, 0x5a, 0x81, 0x17, + 0x73, 0x30, 0xa5, 0xc7, 0xfc, 0x1d, 0xdc, 0x1a, 0x32, 0x18, 0xa6, 0x65, 0xe1, 0x30, 0x26, 0xbe, + 0x63, 0x78, 0x98, 0x52, 0xd3, 0xc1, 0x83, 0xe3, 0x7f, 0xf7, 0x52, 0x49, 0xed, 0x41, 0xea, 0x7e, + 0x9a, 0x29, 0x49, 0xac, 0x93, 0x22, 0x10, 0x45, 0x1e, 0xd4, 0x46, 0xe5, 0x89, 0x17, 0xba, 0xd8, + 0xc3, 0x6c, 0x4d, 0xd5, 0x39, 0x5e, 0xf8, 0xfe, 0xa5, 0x85, 0xf7, 0x46, 0x49, 0x52, 0xcd, 0x35, + 0x92, 0x13, 0xa7, 0xda, 0xe7, 0xd0, 0x28, 0x4f, 0x2c, 0xdd, 0xab, 0x1b, 0xb0, 0x1c, 0x3f, 0x0d, + 0xb1, 0x91, 0x44, 0x2e, 0xbf, 0x4a, 0xd5, 0xce, 0x12, 0x5b, 0x1f, 0x45, 0xae, 0xf6, 0x2d, 0x6c, + 0x4e, 0xb0, 0x15, 0xa5, 0xec, 0x3b, 0x50, 0xeb, 0x11, 0xec, 0xda, 0x86, 0x3d, 0xc4, 0x1b, 0x2c, + 0x90, 0x9e, 0x41, 0xb5, 0xf3, 0x12, 0x8f, 0x8e, 0xc8, 0x3e, 0x66, 0x31, 0xed, 0x2b, 0x58, 0x2f, + 0xb0, 0x22, 0xd4, 0x86, 0x97, 0xbb, 0xd8, 0xea, 0xdf, 0x6b, 0xb1, 0x73, 0x0d, 0x12, 0x3f, 0x36, + 0x4c, 0xdb, 0x8e, 0x30, 0xa5, 0x46, 0x18, 0xe1, 0x1e, 0x39, 0x15, 0x0a, 0xea, 0x29, 0xa8, 0x9d, + 0x62, 0xda, 0x29, 0xe4, 0x80, 0x23, 0xb4, 0x6d, 0x58, 0x19, 0xfb, 0x07, 0x47, 0x1b, 0x70, 0xcd, + 0xa3, 0x8e, 0x31, 0xdc, 0x86, 0x94, 0x02, 0x3c, 0xea, 0x3c, 0x11, 0x3b, 0x71, 0x13, 0x6e, 0xec, + 0xe2, 0x38, 0xeb, 0xf1, 0xf8, 0x38, 0xc1, 0x34, 0xd6, 0xbe, 0x84, 0x7a, 0x5e, 0x90, 0x86, 0x81, + 0x4f, 0xf1, 0xff, 0x1c, 0x20, 0xa2, 0x72, 0x76, 0x3c, 0x8c, 0x55, 0xbe, 0x10, 0x1c, 0x55, 0x4e, + 0x67, 0x8f, 0x32, 0xcb, 0xec, 0x19, 0x54, 0xce, 0x4c, 0x96, 0xf1, 0xca, 0xd9, 0xa0, 0x54, 0x99, + 0x8f, 0x2d, 0x65, 0x96, 0xb1, 0xa5, 0x6d, 0xc2, 0x6d, 0x4e, 0x9e, 0x3f, 0x8c, 0x84, 0x02, 0x0f, + 0xb4, 0x32, 0x90, 0x50, 0xb2, 0x0b, 0x8b, 0xe9, 0xec, 0x12, 0x52, 0xa6, 0x1e, 0x7d, 0x22, 0x5d, + 0x68, 0x2a, 0x1a, 0x64, 0x42, 0x53, 0xc0, 0x35, 0x15, 0x82, 0x84, 0xa6, 0x3d, 0x58, 0x62, 0x73, + 0x8f, 0x70, 0x6f, 0x9c, 0x69, 0x6e, 0x0e, 0xf2, 0x35, 0x15, 0x6a, 0xbb, 0x38, 0x1e, 0x1b, 0x89, + 0x42, 0xca, 0x27, 0xb0, 0x7e, 0x21, 0x22, 0xea, 0xa7, 0x63, 0x56, 0x99, 0x72, 0xcc, 0x86, 0xb0, + 0x5e, 0x20, 0x07, 0x1d, 0x5d, 0x78, 0x0f, 0xa4, 0x9e, 0xdf, 0x9c, 0xa4, 0xaf, 0xc2, 0xe7, 0x80, + 0xf6, 0x8b, 0x02, 0xb5, 0x7c, 0x64, 0xa9, 0xe5, 0xdc, 0x84, 0x2a, 0xa1, 0x6c, 0x26, 0x27, 0x2e, + 0xe6, 0x8e, 0xb6, 0xdc, 0x59, 0x26, 0x74, 0x9f, 0xaf, 0xd1, 0x2e, 0x2c, 0xa5, 0xa3, 0x70, 0xe0, + 0xc5, 0x5b, 0xa5, 0x1a, 0xd3, 0x71, 0x28, 0xef, 0xbc, 0xc8, 0xd6, 0x0e, 0x61, 0x2d, 0x17, 0x91, + 0x3b, 0xac, 0x5f, 0x87, 0x55, 0x26, 0xcf, 0x48, 0x77, 0x29, 0x34, 0xe3, 0xbe, 0xb0, 0xda, 0x15, + 0xf6, 0x99, 0xf3, 0x1c, 0x98, 0x71, 0xbf, 0xf5, 0x43, 0x15, 0x5e, 0xe8, 0x0c, 0x55, 0x88, 0xb6, + 0xd1, 0x33, 0x05, 0xd0, 0x45, 0x83, 0x41, 0xdb, 0x45, 0xca, 0x0b, 0x9d, 0xaa, 0xde, 0x9a, 0x26, + 0x25, 0xbd, 0x2d, 0xda, 0xce, 0xf7, 0x7f, 0xfd, 0xfb, 0x73, 0xa5, 0x89, 0xde, 0xd4, 0x73, 0x9f, + 0xde, 0xdb, 0xba, 0x19, 0x86, 0x92, 0xbb, 0xeb, 0xe9, 0xbb, 0x57, 0x68, 0xce, 0x3e, 0x1e, 0xca, + 0x34, 0xe7, 0x7b, 0x5c, 0xa9, 0xe6, 0x02, 0xe7, 0x9b, 0x5a, 0x73, 0xfa, 0xd8, 0x1e, 0x68, 0xce, + 0xbc, 0x66, 0x4a, 0x35, 0xe7, 0xba, 0x63, 0xb9, 0xe6, 0x7c, 0xcf, 0x9c, 0x5e, 0x33, 0x7f, 0xe1, + 0xff, 0xa1, 0x08, 0x23, 0xce, 0x9f, 0x96, 0x0f, 0x4a, 0x85, 0x94, 0xf9, 0x6b, 0xfd, 0x9d, 0x59, + 0x52, 0x45, 0x2f, 0xef, 0xf1, 0x5e, 0xee, 0xa3, 0x9d, 0x89, 0x7b, 0x91, 0x7f, 0x5e, 0xfc, 0x99, + 0xf6, 0x54, 0xe4, 0x36, 0x65, 0x3d, 0x95, 0xfb, 0x73, 0x69, 0x4f, 0x97, 0xb8, 0xb6, 0xf6, 0x90, + 0xf7, 0xf4, 0x36, 0x7a, 0x6b, 0xc2, 0x9e, 0xc6, 0x1d, 0x11, 0xfd, 0xa6, 0xc0, 0x6a, 0xc6, 0x90, + 0x51, 0xb3, 0x44, 0x4e, 0x8e, 0xa7, 0xd7, 0xf5, 0x89, 0xf1, 0x33, 0x9e, 0x43, 0x7c, 0x2a, 0xad, + 0xde, 0x7f, 0xf4, 0xfb, 0x59, 0x43, 0x79, 0x7e, 0xd6, 0x50, 0xfe, 0x39, 0x6b, 0x28, 0x3f, 0x9e, + 0x37, 0xae, 0x3c, 0x3f, 0x6f, 0x5c, 0xf9, 0xfb, 0xbc, 0x71, 0xe5, 0x8b, 0x6d, 0x87, 0xc4, 0xfd, + 0xa4, 0xdb, 0xb4, 0x02, 0x4f, 0x77, 0x89, 0x8f, 0x19, 0xfd, 0x16, 0xb5, 0xbf, 0xd1, 0x59, 0xbb, + 0x38, 0xd2, 0x9d, 0x28, 0xb4, 0xc6, 0x7f, 0xa0, 0x77, 0x17, 0xf9, 0x0f, 0xec, 0x7b, 0xff, 0x05, + 0x00, 0x00, 0xff, 0xff, 0x10, 0xb0, 0xbc, 0x36, 0xc1, 0x0f, 0x00, 0x00, +} + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ grpc.ClientConn + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +const _ = grpc.SupportPackageIsVersion4 + +// ReflectionServiceClient is the client API for ReflectionService service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. +type ReflectionServiceClient interface { + // GetAuthnDescriptor returns information on how to authenticate transactions in the application + // NOTE: this RPC is still experimental and might be subject to breaking changes or removal in + // future releases of the cosmos-sdk. + GetAuthnDescriptor(ctx context.Context, in *GetAuthnDescriptorRequest, opts ...grpc.CallOption) (*GetAuthnDescriptorResponse, error) + // GetChainDescriptor returns the description of the chain + GetChainDescriptor(ctx context.Context, in *GetChainDescriptorRequest, opts ...grpc.CallOption) (*GetChainDescriptorResponse, error) + // GetCodecDescriptor returns the descriptor of the codec of the application + GetCodecDescriptor(ctx context.Context, in *GetCodecDescriptorRequest, opts ...grpc.CallOption) (*GetCodecDescriptorResponse, error) + // GetConfigurationDescriptor returns the descriptor for the sdk.Config of the application + GetConfigurationDescriptor(ctx context.Context, in *GetConfigurationDescriptorRequest, opts ...grpc.CallOption) (*GetConfigurationDescriptorResponse, error) + // GetQueryServicesDescriptor returns the available gRPC queryable services of the application + GetQueryServicesDescriptor(ctx context.Context, in *GetQueryServicesDescriptorRequest, opts ...grpc.CallOption) (*GetQueryServicesDescriptorResponse, error) + // GetTxDescriptor returns information on the used transaction object and available msgs that can be used + GetTxDescriptor(ctx context.Context, in *GetTxDescriptorRequest, opts ...grpc.CallOption) (*GetTxDescriptorResponse, error) +} + +type reflectionServiceClient struct { + cc grpc1.ClientConn +} + +func NewReflectionServiceClient(cc grpc1.ClientConn) ReflectionServiceClient { + return &reflectionServiceClient{cc} +} + +func (c *reflectionServiceClient) GetAuthnDescriptor(ctx context.Context, in *GetAuthnDescriptorRequest, opts ...grpc.CallOption) (*GetAuthnDescriptorResponse, error) { + out := new(GetAuthnDescriptorResponse) + err := c.cc.Invoke(ctx, "/lbm.base.reflection.v2.ReflectionService/GetAuthnDescriptor", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *reflectionServiceClient) GetChainDescriptor(ctx context.Context, in *GetChainDescriptorRequest, opts ...grpc.CallOption) (*GetChainDescriptorResponse, error) { + out := new(GetChainDescriptorResponse) + err := c.cc.Invoke(ctx, "/lbm.base.reflection.v2.ReflectionService/GetChainDescriptor", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *reflectionServiceClient) GetCodecDescriptor(ctx context.Context, in *GetCodecDescriptorRequest, opts ...grpc.CallOption) (*GetCodecDescriptorResponse, error) { + out := new(GetCodecDescriptorResponse) + err := c.cc.Invoke(ctx, "/lbm.base.reflection.v2.ReflectionService/GetCodecDescriptor", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *reflectionServiceClient) GetConfigurationDescriptor(ctx context.Context, in *GetConfigurationDescriptorRequest, opts ...grpc.CallOption) (*GetConfigurationDescriptorResponse, error) { + out := new(GetConfigurationDescriptorResponse) + err := c.cc.Invoke(ctx, "/lbm.base.reflection.v2.ReflectionService/GetConfigurationDescriptor", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *reflectionServiceClient) GetQueryServicesDescriptor(ctx context.Context, in *GetQueryServicesDescriptorRequest, opts ...grpc.CallOption) (*GetQueryServicesDescriptorResponse, error) { + out := new(GetQueryServicesDescriptorResponse) + err := c.cc.Invoke(ctx, "/lbm.base.reflection.v2.ReflectionService/GetQueryServicesDescriptor", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *reflectionServiceClient) GetTxDescriptor(ctx context.Context, in *GetTxDescriptorRequest, opts ...grpc.CallOption) (*GetTxDescriptorResponse, error) { + out := new(GetTxDescriptorResponse) + err := c.cc.Invoke(ctx, "/lbm.base.reflection.v2.ReflectionService/GetTxDescriptor", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// ReflectionServiceServer is the server API for ReflectionService service. +type ReflectionServiceServer interface { + // GetAuthnDescriptor returns information on how to authenticate transactions in the application + // NOTE: this RPC is still experimental and might be subject to breaking changes or removal in + // future releases of the cosmos-sdk. + GetAuthnDescriptor(context.Context, *GetAuthnDescriptorRequest) (*GetAuthnDescriptorResponse, error) + // GetChainDescriptor returns the description of the chain + GetChainDescriptor(context.Context, *GetChainDescriptorRequest) (*GetChainDescriptorResponse, error) + // GetCodecDescriptor returns the descriptor of the codec of the application + GetCodecDescriptor(context.Context, *GetCodecDescriptorRequest) (*GetCodecDescriptorResponse, error) + // GetConfigurationDescriptor returns the descriptor for the sdk.Config of the application + GetConfigurationDescriptor(context.Context, *GetConfigurationDescriptorRequest) (*GetConfigurationDescriptorResponse, error) + // GetQueryServicesDescriptor returns the available gRPC queryable services of the application + GetQueryServicesDescriptor(context.Context, *GetQueryServicesDescriptorRequest) (*GetQueryServicesDescriptorResponse, error) + // GetTxDescriptor returns information on the used transaction object and available msgs that can be used + GetTxDescriptor(context.Context, *GetTxDescriptorRequest) (*GetTxDescriptorResponse, error) +} + +// UnimplementedReflectionServiceServer can be embedded to have forward compatible implementations. +type UnimplementedReflectionServiceServer struct { +} + +func (*UnimplementedReflectionServiceServer) GetAuthnDescriptor(ctx context.Context, req *GetAuthnDescriptorRequest) (*GetAuthnDescriptorResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetAuthnDescriptor not implemented") +} +func (*UnimplementedReflectionServiceServer) GetChainDescriptor(ctx context.Context, req *GetChainDescriptorRequest) (*GetChainDescriptorResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetChainDescriptor not implemented") +} +func (*UnimplementedReflectionServiceServer) GetCodecDescriptor(ctx context.Context, req *GetCodecDescriptorRequest) (*GetCodecDescriptorResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetCodecDescriptor not implemented") +} +func (*UnimplementedReflectionServiceServer) GetConfigurationDescriptor(ctx context.Context, req *GetConfigurationDescriptorRequest) (*GetConfigurationDescriptorResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetConfigurationDescriptor not implemented") +} +func (*UnimplementedReflectionServiceServer) GetQueryServicesDescriptor(ctx context.Context, req *GetQueryServicesDescriptorRequest) (*GetQueryServicesDescriptorResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetQueryServicesDescriptor not implemented") +} +func (*UnimplementedReflectionServiceServer) GetTxDescriptor(ctx context.Context, req *GetTxDescriptorRequest) (*GetTxDescriptorResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetTxDescriptor not implemented") +} + +func RegisterReflectionServiceServer(s grpc1.Server, srv ReflectionServiceServer) { + s.RegisterService(&_ReflectionService_serviceDesc, srv) +} + +func _ReflectionService_GetAuthnDescriptor_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetAuthnDescriptorRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ReflectionServiceServer).GetAuthnDescriptor(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/lbm.base.reflection.v2.ReflectionService/GetAuthnDescriptor", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ReflectionServiceServer).GetAuthnDescriptor(ctx, req.(*GetAuthnDescriptorRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _ReflectionService_GetChainDescriptor_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetChainDescriptorRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ReflectionServiceServer).GetChainDescriptor(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/lbm.base.reflection.v2.ReflectionService/GetChainDescriptor", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ReflectionServiceServer).GetChainDescriptor(ctx, req.(*GetChainDescriptorRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _ReflectionService_GetCodecDescriptor_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetCodecDescriptorRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ReflectionServiceServer).GetCodecDescriptor(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/lbm.base.reflection.v2.ReflectionService/GetCodecDescriptor", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ReflectionServiceServer).GetCodecDescriptor(ctx, req.(*GetCodecDescriptorRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _ReflectionService_GetConfigurationDescriptor_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetConfigurationDescriptorRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ReflectionServiceServer).GetConfigurationDescriptor(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/lbm.base.reflection.v2.ReflectionService/GetConfigurationDescriptor", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ReflectionServiceServer).GetConfigurationDescriptor(ctx, req.(*GetConfigurationDescriptorRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _ReflectionService_GetQueryServicesDescriptor_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetQueryServicesDescriptorRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ReflectionServiceServer).GetQueryServicesDescriptor(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/lbm.base.reflection.v2.ReflectionService/GetQueryServicesDescriptor", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ReflectionServiceServer).GetQueryServicesDescriptor(ctx, req.(*GetQueryServicesDescriptorRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _ReflectionService_GetTxDescriptor_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetTxDescriptorRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ReflectionServiceServer).GetTxDescriptor(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/lbm.base.reflection.v2.ReflectionService/GetTxDescriptor", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ReflectionServiceServer).GetTxDescriptor(ctx, req.(*GetTxDescriptorRequest)) + } + return interceptor(ctx, in, info, handler) +} + +var _ReflectionService_serviceDesc = grpc.ServiceDesc{ + ServiceName: "lbm.base.reflection.v2.ReflectionService", + HandlerType: (*ReflectionServiceServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "GetAuthnDescriptor", + Handler: _ReflectionService_GetAuthnDescriptor_Handler, + }, + { + MethodName: "GetChainDescriptor", + Handler: _ReflectionService_GetChainDescriptor_Handler, + }, + { + MethodName: "GetCodecDescriptor", + Handler: _ReflectionService_GetCodecDescriptor_Handler, + }, + { + MethodName: "GetConfigurationDescriptor", + Handler: _ReflectionService_GetConfigurationDescriptor_Handler, + }, + { + MethodName: "GetQueryServicesDescriptor", + Handler: _ReflectionService_GetQueryServicesDescriptor_Handler, + }, + { + MethodName: "GetTxDescriptor", + Handler: _ReflectionService_GetTxDescriptor_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "lbm/base/reflection/v2/reflection.proto", +} + +func (m *AppDescriptor) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *AppDescriptor) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *AppDescriptor) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Tx != nil { + { + size, err := m.Tx.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintReflection(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x32 + } + if m.QueryServices != nil { + { + size, err := m.QueryServices.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintReflection(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x2a + } + if m.Configuration != nil { + { + size, err := m.Configuration.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintReflection(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x22 + } + if m.Codec != nil { + { + size, err := m.Codec.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintReflection(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + } + if m.Chain != nil { + { + size, err := m.Chain.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintReflection(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + if m.Authn != nil { + { + size, err := m.Authn.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintReflection(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *TxDescriptor) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *TxDescriptor) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *TxDescriptor) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Msgs) > 0 { + for iNdEx := len(m.Msgs) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Msgs[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintReflection(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + } + if len(m.Fullname) > 0 { + i -= len(m.Fullname) + copy(dAtA[i:], m.Fullname) + i = encodeVarintReflection(dAtA, i, uint64(len(m.Fullname))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *AuthnDescriptor) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *AuthnDescriptor) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *AuthnDescriptor) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.SignModes) > 0 { + for iNdEx := len(m.SignModes) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.SignModes[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintReflection(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func (m *SigningModeDescriptor) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *SigningModeDescriptor) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *SigningModeDescriptor) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.AuthnInfoProviderMethodFullname) > 0 { + i -= len(m.AuthnInfoProviderMethodFullname) + copy(dAtA[i:], m.AuthnInfoProviderMethodFullname) + i = encodeVarintReflection(dAtA, i, uint64(len(m.AuthnInfoProviderMethodFullname))) + i-- + dAtA[i] = 0x1a + } + if m.Number != 0 { + i = encodeVarintReflection(dAtA, i, uint64(m.Number)) + i-- + dAtA[i] = 0x10 + } + if len(m.Name) > 0 { + i -= len(m.Name) + copy(dAtA[i:], m.Name) + i = encodeVarintReflection(dAtA, i, uint64(len(m.Name))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *ChainDescriptor) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *ChainDescriptor) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ChainDescriptor) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Id) > 0 { + i -= len(m.Id) + copy(dAtA[i:], m.Id) + i = encodeVarintReflection(dAtA, i, uint64(len(m.Id))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *CodecDescriptor) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *CodecDescriptor) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *CodecDescriptor) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Interfaces) > 0 { + for iNdEx := len(m.Interfaces) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Interfaces[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintReflection(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func (m *InterfaceDescriptor) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *InterfaceDescriptor) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *InterfaceDescriptor) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.InterfaceImplementers) > 0 { + for iNdEx := len(m.InterfaceImplementers) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.InterfaceImplementers[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintReflection(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + } + } + if len(m.InterfaceAcceptingMessages) > 0 { + for iNdEx := len(m.InterfaceAcceptingMessages) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.InterfaceAcceptingMessages[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintReflection(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + } + if len(m.Fullname) > 0 { + i -= len(m.Fullname) + copy(dAtA[i:], m.Fullname) + i = encodeVarintReflection(dAtA, i, uint64(len(m.Fullname))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *InterfaceImplementerDescriptor) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *InterfaceImplementerDescriptor) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *InterfaceImplementerDescriptor) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.TypeUrl) > 0 { + i -= len(m.TypeUrl) + copy(dAtA[i:], m.TypeUrl) + i = encodeVarintReflection(dAtA, i, uint64(len(m.TypeUrl))) + i-- + dAtA[i] = 0x12 + } + if len(m.Fullname) > 0 { + i -= len(m.Fullname) + copy(dAtA[i:], m.Fullname) + i = encodeVarintReflection(dAtA, i, uint64(len(m.Fullname))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *InterfaceAcceptingMessageDescriptor) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *InterfaceAcceptingMessageDescriptor) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *InterfaceAcceptingMessageDescriptor) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.FieldDescriptorNames) > 0 { + for iNdEx := len(m.FieldDescriptorNames) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.FieldDescriptorNames[iNdEx]) + copy(dAtA[i:], m.FieldDescriptorNames[iNdEx]) + i = encodeVarintReflection(dAtA, i, uint64(len(m.FieldDescriptorNames[iNdEx]))) + i-- + dAtA[i] = 0x12 + } + } + if len(m.Fullname) > 0 { + i -= len(m.Fullname) + copy(dAtA[i:], m.Fullname) + i = encodeVarintReflection(dAtA, i, uint64(len(m.Fullname))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *ConfigurationDescriptor) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *ConfigurationDescriptor) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ConfigurationDescriptor) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Bech32AccountAddressPrefix) > 0 { + i -= len(m.Bech32AccountAddressPrefix) + copy(dAtA[i:], m.Bech32AccountAddressPrefix) + i = encodeVarintReflection(dAtA, i, uint64(len(m.Bech32AccountAddressPrefix))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgDescriptor) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgDescriptor) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgDescriptor) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.MsgTypeUrl) > 0 { + i -= len(m.MsgTypeUrl) + copy(dAtA[i:], m.MsgTypeUrl) + i = encodeVarintReflection(dAtA, i, uint64(len(m.MsgTypeUrl))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *GetAuthnDescriptorRequest) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *GetAuthnDescriptorRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *GetAuthnDescriptorRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func (m *GetAuthnDescriptorResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *GetAuthnDescriptorResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *GetAuthnDescriptorResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Authn != nil { + { + size, err := m.Authn.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintReflection(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *GetChainDescriptorRequest) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *GetChainDescriptorRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *GetChainDescriptorRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func (m *GetChainDescriptorResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *GetChainDescriptorResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *GetChainDescriptorResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Chain != nil { + { + size, err := m.Chain.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintReflection(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *GetCodecDescriptorRequest) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *GetCodecDescriptorRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *GetCodecDescriptorRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func (m *GetCodecDescriptorResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *GetCodecDescriptorResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *GetCodecDescriptorResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Codec != nil { + { + size, err := m.Codec.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintReflection(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *GetConfigurationDescriptorRequest) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *GetConfigurationDescriptorRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *GetConfigurationDescriptorRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func (m *GetConfigurationDescriptorResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *GetConfigurationDescriptorResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *GetConfigurationDescriptorResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Config != nil { + { + size, err := m.Config.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintReflection(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *GetQueryServicesDescriptorRequest) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *GetQueryServicesDescriptorRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *GetQueryServicesDescriptorRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func (m *GetQueryServicesDescriptorResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *GetQueryServicesDescriptorResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *GetQueryServicesDescriptorResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Queries != nil { + { + size, err := m.Queries.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintReflection(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *GetTxDescriptorRequest) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *GetTxDescriptorRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *GetTxDescriptorRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func (m *GetTxDescriptorResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *GetTxDescriptorResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *GetTxDescriptorResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Tx != nil { + { + size, err := m.Tx.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintReflection(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *QueryServicesDescriptor) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryServicesDescriptor) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryServicesDescriptor) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.QueryServices) > 0 { + for iNdEx := len(m.QueryServices) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.QueryServices[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintReflection(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func (m *QueryServiceDescriptor) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryServiceDescriptor) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryServiceDescriptor) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Methods) > 0 { + for iNdEx := len(m.Methods) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Methods[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintReflection(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + } + } + if m.IsModule { + i-- + if m.IsModule { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x10 + } + if len(m.Fullname) > 0 { + i -= len(m.Fullname) + copy(dAtA[i:], m.Fullname) + i = encodeVarintReflection(dAtA, i, uint64(len(m.Fullname))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *QueryMethodDescriptor) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryMethodDescriptor) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryMethodDescriptor) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.FullQueryPath) > 0 { + i -= len(m.FullQueryPath) + copy(dAtA[i:], m.FullQueryPath) + i = encodeVarintReflection(dAtA, i, uint64(len(m.FullQueryPath))) + i-- + dAtA[i] = 0x12 + } + if len(m.Name) > 0 { + i -= len(m.Name) + copy(dAtA[i:], m.Name) + i = encodeVarintReflection(dAtA, i, uint64(len(m.Name))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func encodeVarintReflection(dAtA []byte, offset int, v uint64) int { + offset -= sovReflection(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *AppDescriptor) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Authn != nil { + l = m.Authn.Size() + n += 1 + l + sovReflection(uint64(l)) + } + if m.Chain != nil { + l = m.Chain.Size() + n += 1 + l + sovReflection(uint64(l)) + } + if m.Codec != nil { + l = m.Codec.Size() + n += 1 + l + sovReflection(uint64(l)) + } + if m.Configuration != nil { + l = m.Configuration.Size() + n += 1 + l + sovReflection(uint64(l)) + } + if m.QueryServices != nil { + l = m.QueryServices.Size() + n += 1 + l + sovReflection(uint64(l)) + } + if m.Tx != nil { + l = m.Tx.Size() + n += 1 + l + sovReflection(uint64(l)) + } + return n +} + +func (m *TxDescriptor) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Fullname) + if l > 0 { + n += 1 + l + sovReflection(uint64(l)) + } + if len(m.Msgs) > 0 { + for _, e := range m.Msgs { + l = e.Size() + n += 1 + l + sovReflection(uint64(l)) + } + } + return n +} + +func (m *AuthnDescriptor) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.SignModes) > 0 { + for _, e := range m.SignModes { + l = e.Size() + n += 1 + l + sovReflection(uint64(l)) + } + } + return n +} + +func (m *SigningModeDescriptor) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Name) + if l > 0 { + n += 1 + l + sovReflection(uint64(l)) + } + if m.Number != 0 { + n += 1 + sovReflection(uint64(m.Number)) + } + l = len(m.AuthnInfoProviderMethodFullname) + if l > 0 { + n += 1 + l + sovReflection(uint64(l)) + } + return n +} + +func (m *ChainDescriptor) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Id) + if l > 0 { + n += 1 + l + sovReflection(uint64(l)) + } + return n +} + +func (m *CodecDescriptor) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.Interfaces) > 0 { + for _, e := range m.Interfaces { + l = e.Size() + n += 1 + l + sovReflection(uint64(l)) + } + } + return n +} + +func (m *InterfaceDescriptor) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Fullname) + if l > 0 { + n += 1 + l + sovReflection(uint64(l)) + } + if len(m.InterfaceAcceptingMessages) > 0 { + for _, e := range m.InterfaceAcceptingMessages { + l = e.Size() + n += 1 + l + sovReflection(uint64(l)) + } + } + if len(m.InterfaceImplementers) > 0 { + for _, e := range m.InterfaceImplementers { + l = e.Size() + n += 1 + l + sovReflection(uint64(l)) + } + } + return n +} + +func (m *InterfaceImplementerDescriptor) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Fullname) + if l > 0 { + n += 1 + l + sovReflection(uint64(l)) + } + l = len(m.TypeUrl) + if l > 0 { + n += 1 + l + sovReflection(uint64(l)) + } + return n +} + +func (m *InterfaceAcceptingMessageDescriptor) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Fullname) + if l > 0 { + n += 1 + l + sovReflection(uint64(l)) + } + if len(m.FieldDescriptorNames) > 0 { + for _, s := range m.FieldDescriptorNames { + l = len(s) + n += 1 + l + sovReflection(uint64(l)) + } + } + return n +} + +func (m *ConfigurationDescriptor) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Bech32AccountAddressPrefix) + if l > 0 { + n += 1 + l + sovReflection(uint64(l)) + } + return n +} + +func (m *MsgDescriptor) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.MsgTypeUrl) + if l > 0 { + n += 1 + l + sovReflection(uint64(l)) + } + return n +} + +func (m *GetAuthnDescriptorRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func (m *GetAuthnDescriptorResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Authn != nil { + l = m.Authn.Size() + n += 1 + l + sovReflection(uint64(l)) + } + return n +} + +func (m *GetChainDescriptorRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func (m *GetChainDescriptorResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Chain != nil { + l = m.Chain.Size() + n += 1 + l + sovReflection(uint64(l)) + } + return n +} + +func (m *GetCodecDescriptorRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func (m *GetCodecDescriptorResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Codec != nil { + l = m.Codec.Size() + n += 1 + l + sovReflection(uint64(l)) + } + return n +} + +func (m *GetConfigurationDescriptorRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func (m *GetConfigurationDescriptorResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Config != nil { + l = m.Config.Size() + n += 1 + l + sovReflection(uint64(l)) + } + return n +} + +func (m *GetQueryServicesDescriptorRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func (m *GetQueryServicesDescriptorResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Queries != nil { + l = m.Queries.Size() + n += 1 + l + sovReflection(uint64(l)) + } + return n +} + +func (m *GetTxDescriptorRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func (m *GetTxDescriptorResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Tx != nil { + l = m.Tx.Size() + n += 1 + l + sovReflection(uint64(l)) + } + return n +} + +func (m *QueryServicesDescriptor) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.QueryServices) > 0 { + for _, e := range m.QueryServices { + l = e.Size() + n += 1 + l + sovReflection(uint64(l)) + } + } + return n +} + +func (m *QueryServiceDescriptor) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Fullname) + if l > 0 { + n += 1 + l + sovReflection(uint64(l)) + } + if m.IsModule { + n += 2 + } + if len(m.Methods) > 0 { + for _, e := range m.Methods { + l = e.Size() + n += 1 + l + sovReflection(uint64(l)) + } + } + return n +} + +func (m *QueryMethodDescriptor) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Name) + if l > 0 { + n += 1 + l + sovReflection(uint64(l)) + } + l = len(m.FullQueryPath) + if l > 0 { + n += 1 + l + sovReflection(uint64(l)) + } + return n +} + +func sovReflection(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozReflection(x uint64) (n int) { + return sovReflection(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *AppDescriptor) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowReflection + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: AppDescriptor: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: AppDescriptor: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Authn", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowReflection + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthReflection + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthReflection + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Authn == nil { + m.Authn = &AuthnDescriptor{} + } + if err := m.Authn.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Chain", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowReflection + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthReflection + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthReflection + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Chain == nil { + m.Chain = &ChainDescriptor{} + } + if err := m.Chain.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Codec", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowReflection + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthReflection + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthReflection + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Codec == nil { + m.Codec = &CodecDescriptor{} + } + if err := m.Codec.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Configuration", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowReflection + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthReflection + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthReflection + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Configuration == nil { + m.Configuration = &ConfigurationDescriptor{} + } + if err := m.Configuration.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field QueryServices", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowReflection + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthReflection + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthReflection + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.QueryServices == nil { + m.QueryServices = &QueryServicesDescriptor{} + } + if err := m.QueryServices.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 6: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Tx", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowReflection + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthReflection + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthReflection + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Tx == nil { + m.Tx = &TxDescriptor{} + } + if err := m.Tx.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipReflection(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthReflection + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *TxDescriptor) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowReflection + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: TxDescriptor: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: TxDescriptor: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Fullname", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowReflection + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthReflection + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthReflection + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Fullname = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Msgs", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowReflection + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthReflection + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthReflection + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Msgs = append(m.Msgs, &MsgDescriptor{}) + if err := m.Msgs[len(m.Msgs)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipReflection(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthReflection + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *AuthnDescriptor) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowReflection + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: AuthnDescriptor: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: AuthnDescriptor: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field SignModes", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowReflection + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthReflection + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthReflection + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.SignModes = append(m.SignModes, &SigningModeDescriptor{}) + if err := m.SignModes[len(m.SignModes)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipReflection(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthReflection + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *SigningModeDescriptor) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowReflection + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: SigningModeDescriptor: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: SigningModeDescriptor: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Name", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowReflection + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthReflection + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthReflection + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Name = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Number", wireType) + } + m.Number = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowReflection + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Number |= int32(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field AuthnInfoProviderMethodFullname", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowReflection + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthReflection + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthReflection + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.AuthnInfoProviderMethodFullname = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipReflection(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthReflection + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *ChainDescriptor) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowReflection + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: ChainDescriptor: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ChainDescriptor: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Id", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowReflection + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthReflection + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthReflection + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Id = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipReflection(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthReflection + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *CodecDescriptor) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowReflection + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: CodecDescriptor: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: CodecDescriptor: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Interfaces", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowReflection + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthReflection + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthReflection + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Interfaces = append(m.Interfaces, &InterfaceDescriptor{}) + if err := m.Interfaces[len(m.Interfaces)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipReflection(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthReflection + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *InterfaceDescriptor) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowReflection + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: InterfaceDescriptor: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: InterfaceDescriptor: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Fullname", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowReflection + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthReflection + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthReflection + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Fullname = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field InterfaceAcceptingMessages", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowReflection + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthReflection + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthReflection + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.InterfaceAcceptingMessages = append(m.InterfaceAcceptingMessages, &InterfaceAcceptingMessageDescriptor{}) + if err := m.InterfaceAcceptingMessages[len(m.InterfaceAcceptingMessages)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field InterfaceImplementers", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowReflection + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthReflection + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthReflection + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.InterfaceImplementers = append(m.InterfaceImplementers, &InterfaceImplementerDescriptor{}) + if err := m.InterfaceImplementers[len(m.InterfaceImplementers)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipReflection(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthReflection + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *InterfaceImplementerDescriptor) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowReflection + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: InterfaceImplementerDescriptor: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: InterfaceImplementerDescriptor: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Fullname", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowReflection + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthReflection + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthReflection + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Fullname = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field TypeUrl", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowReflection + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthReflection + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthReflection + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.TypeUrl = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipReflection(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthReflection + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *InterfaceAcceptingMessageDescriptor) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowReflection + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: InterfaceAcceptingMessageDescriptor: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: InterfaceAcceptingMessageDescriptor: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Fullname", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowReflection + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthReflection + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthReflection + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Fullname = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field FieldDescriptorNames", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowReflection + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthReflection + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthReflection + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.FieldDescriptorNames = append(m.FieldDescriptorNames, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipReflection(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthReflection + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *ConfigurationDescriptor) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowReflection + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: ConfigurationDescriptor: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ConfigurationDescriptor: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Bech32AccountAddressPrefix", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowReflection + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthReflection + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthReflection + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Bech32AccountAddressPrefix = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipReflection(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthReflection + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgDescriptor) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowReflection + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgDescriptor: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgDescriptor: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field MsgTypeUrl", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowReflection + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthReflection + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthReflection + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.MsgTypeUrl = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipReflection(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthReflection + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *GetAuthnDescriptorRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowReflection + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: GetAuthnDescriptorRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: GetAuthnDescriptorRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipReflection(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthReflection + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *GetAuthnDescriptorResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowReflection + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: GetAuthnDescriptorResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: GetAuthnDescriptorResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Authn", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowReflection + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthReflection + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthReflection + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Authn == nil { + m.Authn = &AuthnDescriptor{} + } + if err := m.Authn.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipReflection(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthReflection + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *GetChainDescriptorRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowReflection + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: GetChainDescriptorRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: GetChainDescriptorRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipReflection(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthReflection + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *GetChainDescriptorResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowReflection + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: GetChainDescriptorResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: GetChainDescriptorResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Chain", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowReflection + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthReflection + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthReflection + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Chain == nil { + m.Chain = &ChainDescriptor{} + } + if err := m.Chain.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipReflection(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthReflection + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *GetCodecDescriptorRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowReflection + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: GetCodecDescriptorRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: GetCodecDescriptorRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipReflection(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthReflection + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *GetCodecDescriptorResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowReflection + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: GetCodecDescriptorResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: GetCodecDescriptorResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Codec", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowReflection + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthReflection + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthReflection + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Codec == nil { + m.Codec = &CodecDescriptor{} + } + if err := m.Codec.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipReflection(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthReflection + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *GetConfigurationDescriptorRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowReflection + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: GetConfigurationDescriptorRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: GetConfigurationDescriptorRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipReflection(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthReflection + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *GetConfigurationDescriptorResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowReflection + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: GetConfigurationDescriptorResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: GetConfigurationDescriptorResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Config", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowReflection + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthReflection + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthReflection + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Config == nil { + m.Config = &ConfigurationDescriptor{} + } + if err := m.Config.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipReflection(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthReflection + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *GetQueryServicesDescriptorRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowReflection + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: GetQueryServicesDescriptorRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: GetQueryServicesDescriptorRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipReflection(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthReflection + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *GetQueryServicesDescriptorResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowReflection + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: GetQueryServicesDescriptorResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: GetQueryServicesDescriptorResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Queries", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowReflection + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthReflection + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthReflection + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Queries == nil { + m.Queries = &QueryServicesDescriptor{} + } + if err := m.Queries.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipReflection(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthReflection + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *GetTxDescriptorRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowReflection + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: GetTxDescriptorRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: GetTxDescriptorRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipReflection(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthReflection + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *GetTxDescriptorResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowReflection + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: GetTxDescriptorResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: GetTxDescriptorResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Tx", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowReflection + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthReflection + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthReflection + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Tx == nil { + m.Tx = &TxDescriptor{} + } + if err := m.Tx.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipReflection(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthReflection + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryServicesDescriptor) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowReflection + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryServicesDescriptor: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryServicesDescriptor: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field QueryServices", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowReflection + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthReflection + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthReflection + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.QueryServices = append(m.QueryServices, &QueryServiceDescriptor{}) + if err := m.QueryServices[len(m.QueryServices)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipReflection(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthReflection + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryServiceDescriptor) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowReflection + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryServiceDescriptor: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryServiceDescriptor: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Fullname", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowReflection + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthReflection + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthReflection + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Fullname = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field IsModule", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowReflection + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.IsModule = bool(v != 0) + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Methods", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowReflection + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthReflection + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthReflection + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Methods = append(m.Methods, &QueryMethodDescriptor{}) + if err := m.Methods[len(m.Methods)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipReflection(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthReflection + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryMethodDescriptor) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowReflection + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryMethodDescriptor: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryMethodDescriptor: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Name", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowReflection + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthReflection + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthReflection + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Name = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field FullQueryPath", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowReflection + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthReflection + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthReflection + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.FullQueryPath = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipReflection(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthReflection + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipReflection(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowReflection + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowReflection + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowReflection + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthReflection + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupReflection + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthReflection + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthReflection = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowReflection = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupReflection = fmt.Errorf("proto: unexpected end of group") +) diff --git a/server/grpc/reflection/v2/reflection.pb.gw.go b/server/grpc/reflection/v2/reflection.pb.gw.go new file mode 100644 index 0000000000..8b1fd4c607 --- /dev/null +++ b/server/grpc/reflection/v2/reflection.pb.gw.go @@ -0,0 +1,458 @@ +// Code generated by protoc-gen-grpc-gateway. DO NOT EDIT. +// source: lbm/base/reflection/v2/reflection.proto + +/* +Package v2 is a reverse proxy. + +It translates gRPC into RESTful JSON APIs. +*/ +package v2 + +import ( + "context" + "io" + "net/http" + + "github.com/golang/protobuf/descriptor" + "github.com/golang/protobuf/proto" + "github.com/grpc-ecosystem/grpc-gateway/runtime" + "github.com/grpc-ecosystem/grpc-gateway/utilities" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/grpclog" + "google.golang.org/grpc/status" +) + +// Suppress "imported and not used" errors +var _ codes.Code +var _ io.Reader +var _ status.Status +var _ = runtime.String +var _ = utilities.NewDoubleArray +var _ = descriptor.ForMessage + +func request_ReflectionService_GetAuthnDescriptor_0(ctx context.Context, marshaler runtime.Marshaler, client ReflectionServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq GetAuthnDescriptorRequest + var metadata runtime.ServerMetadata + + msg, err := client.GetAuthnDescriptor(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_ReflectionService_GetAuthnDescriptor_0(ctx context.Context, marshaler runtime.Marshaler, server ReflectionServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq GetAuthnDescriptorRequest + var metadata runtime.ServerMetadata + + msg, err := server.GetAuthnDescriptor(ctx, &protoReq) + return msg, metadata, err + +} + +func request_ReflectionService_GetChainDescriptor_0(ctx context.Context, marshaler runtime.Marshaler, client ReflectionServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq GetChainDescriptorRequest + var metadata runtime.ServerMetadata + + msg, err := client.GetChainDescriptor(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_ReflectionService_GetChainDescriptor_0(ctx context.Context, marshaler runtime.Marshaler, server ReflectionServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq GetChainDescriptorRequest + var metadata runtime.ServerMetadata + + msg, err := server.GetChainDescriptor(ctx, &protoReq) + return msg, metadata, err + +} + +func request_ReflectionService_GetCodecDescriptor_0(ctx context.Context, marshaler runtime.Marshaler, client ReflectionServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq GetCodecDescriptorRequest + var metadata runtime.ServerMetadata + + msg, err := client.GetCodecDescriptor(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_ReflectionService_GetCodecDescriptor_0(ctx context.Context, marshaler runtime.Marshaler, server ReflectionServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq GetCodecDescriptorRequest + var metadata runtime.ServerMetadata + + msg, err := server.GetCodecDescriptor(ctx, &protoReq) + return msg, metadata, err + +} + +func request_ReflectionService_GetConfigurationDescriptor_0(ctx context.Context, marshaler runtime.Marshaler, client ReflectionServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq GetConfigurationDescriptorRequest + var metadata runtime.ServerMetadata + + msg, err := client.GetConfigurationDescriptor(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_ReflectionService_GetConfigurationDescriptor_0(ctx context.Context, marshaler runtime.Marshaler, server ReflectionServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq GetConfigurationDescriptorRequest + var metadata runtime.ServerMetadata + + msg, err := server.GetConfigurationDescriptor(ctx, &protoReq) + return msg, metadata, err + +} + +func request_ReflectionService_GetQueryServicesDescriptor_0(ctx context.Context, marshaler runtime.Marshaler, client ReflectionServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq GetQueryServicesDescriptorRequest + var metadata runtime.ServerMetadata + + msg, err := client.GetQueryServicesDescriptor(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_ReflectionService_GetQueryServicesDescriptor_0(ctx context.Context, marshaler runtime.Marshaler, server ReflectionServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq GetQueryServicesDescriptorRequest + var metadata runtime.ServerMetadata + + msg, err := server.GetQueryServicesDescriptor(ctx, &protoReq) + return msg, metadata, err + +} + +func request_ReflectionService_GetTxDescriptor_0(ctx context.Context, marshaler runtime.Marshaler, client ReflectionServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq GetTxDescriptorRequest + var metadata runtime.ServerMetadata + + msg, err := client.GetTxDescriptor(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_ReflectionService_GetTxDescriptor_0(ctx context.Context, marshaler runtime.Marshaler, server ReflectionServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq GetTxDescriptorRequest + var metadata runtime.ServerMetadata + + msg, err := server.GetTxDescriptor(ctx, &protoReq) + return msg, metadata, err + +} + +// RegisterReflectionServiceHandlerServer registers the http handlers for service ReflectionService to "mux". +// UnaryRPC :call ReflectionServiceServer directly. +// StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906. +// Note that using this registration option will cause many gRPC library features (such as grpc.SendHeader, etc) to stop working. Consider using RegisterReflectionServiceHandlerFromEndpoint instead. +func RegisterReflectionServiceHandlerServer(ctx context.Context, mux *runtime.ServeMux, server ReflectionServiceServer) error { + + mux.Handle("GET", pattern_ReflectionService_GetAuthnDescriptor_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_ReflectionService_GetAuthnDescriptor_0(rctx, inboundMarshaler, server, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_ReflectionService_GetAuthnDescriptor_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_ReflectionService_GetChainDescriptor_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_ReflectionService_GetChainDescriptor_0(rctx, inboundMarshaler, server, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_ReflectionService_GetChainDescriptor_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_ReflectionService_GetCodecDescriptor_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_ReflectionService_GetCodecDescriptor_0(rctx, inboundMarshaler, server, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_ReflectionService_GetCodecDescriptor_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_ReflectionService_GetConfigurationDescriptor_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_ReflectionService_GetConfigurationDescriptor_0(rctx, inboundMarshaler, server, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_ReflectionService_GetConfigurationDescriptor_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_ReflectionService_GetQueryServicesDescriptor_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_ReflectionService_GetQueryServicesDescriptor_0(rctx, inboundMarshaler, server, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_ReflectionService_GetQueryServicesDescriptor_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_ReflectionService_GetTxDescriptor_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_ReflectionService_GetTxDescriptor_0(rctx, inboundMarshaler, server, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_ReflectionService_GetTxDescriptor_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + return nil +} + +// RegisterReflectionServiceHandlerFromEndpoint is same as RegisterReflectionServiceHandler but +// automatically dials to "endpoint" and closes the connection when "ctx" gets done. +func RegisterReflectionServiceHandlerFromEndpoint(ctx context.Context, mux *runtime.ServeMux, endpoint string, opts []grpc.DialOption) (err error) { + conn, err := grpc.Dial(endpoint, opts...) + if err != nil { + return err + } + defer func() { + if err != nil { + if cerr := conn.Close(); cerr != nil { + grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr) + } + return + } + go func() { + <-ctx.Done() + if cerr := conn.Close(); cerr != nil { + grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr) + } + }() + }() + + return RegisterReflectionServiceHandler(ctx, mux, conn) +} + +// RegisterReflectionServiceHandler registers the http handlers for service ReflectionService to "mux". +// The handlers forward requests to the grpc endpoint over "conn". +func RegisterReflectionServiceHandler(ctx context.Context, mux *runtime.ServeMux, conn *grpc.ClientConn) error { + return RegisterReflectionServiceHandlerClient(ctx, mux, NewReflectionServiceClient(conn)) +} + +// RegisterReflectionServiceHandlerClient registers the http handlers for service ReflectionService +// to "mux". The handlers forward requests to the grpc endpoint over the given implementation of "ReflectionServiceClient". +// Note: the gRPC framework executes interceptors within the gRPC handler. If the passed in "ReflectionServiceClient" +// doesn't go through the normal gRPC flow (creating a gRPC client etc.) then it will be up to the passed in +// "ReflectionServiceClient" to call the correct interceptors. +func RegisterReflectionServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux, client ReflectionServiceClient) error { + + mux.Handle("GET", pattern_ReflectionService_GetAuthnDescriptor_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_ReflectionService_GetAuthnDescriptor_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_ReflectionService_GetAuthnDescriptor_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_ReflectionService_GetChainDescriptor_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_ReflectionService_GetChainDescriptor_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_ReflectionService_GetChainDescriptor_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_ReflectionService_GetCodecDescriptor_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_ReflectionService_GetCodecDescriptor_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_ReflectionService_GetCodecDescriptor_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_ReflectionService_GetConfigurationDescriptor_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_ReflectionService_GetConfigurationDescriptor_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_ReflectionService_GetConfigurationDescriptor_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_ReflectionService_GetQueryServicesDescriptor_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_ReflectionService_GetQueryServicesDescriptor_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_ReflectionService_GetQueryServicesDescriptor_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_ReflectionService_GetTxDescriptor_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_ReflectionService_GetTxDescriptor_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_ReflectionService_GetTxDescriptor_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + return nil +} + +var ( + pattern_ReflectionService_GetAuthnDescriptor_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 2, 5}, []string{"lbm", "base", "reflection", "v1", "app_descriptor", "authn"}, "", runtime.AssumeColonVerbOpt(false))) + + pattern_ReflectionService_GetChainDescriptor_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 2, 5}, []string{"lbm", "base", "reflection", "v1", "app_descriptor", "chain"}, "", runtime.AssumeColonVerbOpt(false))) + + pattern_ReflectionService_GetCodecDescriptor_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 2, 5}, []string{"lbm", "base", "reflection", "v1", "app_descriptor", "codec"}, "", runtime.AssumeColonVerbOpt(false))) + + pattern_ReflectionService_GetConfigurationDescriptor_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 2, 5}, []string{"lbm", "base", "reflection", "v1", "app_descriptor", "configuration"}, "", runtime.AssumeColonVerbOpt(false))) + + pattern_ReflectionService_GetQueryServicesDescriptor_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 2, 5}, []string{"lbm", "base", "reflection", "v1", "app_descriptor", "query_services"}, "", runtime.AssumeColonVerbOpt(false))) + + pattern_ReflectionService_GetTxDescriptor_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 2, 5}, []string{"lbm", "base", "reflection", "v1", "app_descriptor", "tx_descriptor"}, "", runtime.AssumeColonVerbOpt(false))) +) + +var ( + forward_ReflectionService_GetAuthnDescriptor_0 = runtime.ForwardResponseMessage + + forward_ReflectionService_GetChainDescriptor_0 = runtime.ForwardResponseMessage + + forward_ReflectionService_GetCodecDescriptor_0 = runtime.ForwardResponseMessage + + forward_ReflectionService_GetConfigurationDescriptor_0 = runtime.ForwardResponseMessage + + forward_ReflectionService_GetQueryServicesDescriptor_0 = runtime.ForwardResponseMessage + + forward_ReflectionService_GetTxDescriptor_0 = runtime.ForwardResponseMessage +) diff --git a/server/grpc/server.go b/server/grpc/server.go index 42f245bf1e..c1f470b084 100644 --- a/server/grpc/server.go +++ b/server/grpc/server.go @@ -6,21 +6,38 @@ import ( "time" "google.golang.org/grpc" - "google.golang.org/grpc/reflection" "github.com/line/lbm-sdk/client" + "github.com/line/lbm-sdk/server/grpc/gogoreflection" + reflection "github.com/line/lbm-sdk/server/grpc/reflection/v2" "github.com/line/lbm-sdk/server/types" + sdk "github.com/line/lbm-sdk/types" ) // StartGRPCServer starts a gRPC server on the given address. func StartGRPCServer(clientCtx client.Context, app types.Application, address string) (*grpc.Server, error) { grpcSrv := grpc.NewServer() - app.RegisterGRPCServer(clientCtx, grpcSrv) - + app.RegisterGRPCServer(grpcSrv) + // reflection allows consumers to build dynamic clients that can write + // to any cosmos-sdk application without relying on application packages at compile time + err := reflection.Register(grpcSrv, reflection.Config{ + SigningModes: func() map[string]int32 { + modes := make(map[string]int32, len(clientCtx.TxConfig.SignModeHandler().Modes())) + for _, m := range clientCtx.TxConfig.SignModeHandler().Modes() { + modes[m.String()] = (int32)(m) + } + return modes + }(), + ChainID: clientCtx.ChainID, + SdkConfig: sdk.GetConfig(), + InterfaceRegistry: clientCtx.InterfaceRegistry, + }) + if err != nil { + return nil, err + } // Reflection allows external clients to see what services and methods // the gRPC server exposes. - reflection.Register(grpcSrv) - + gogoreflection.Register(grpcSrv) listener, err := net.Listen("tcp", address) if err != nil { return nil, err @@ -37,7 +54,7 @@ func StartGRPCServer(clientCtx client.Context, app types.Application, address st select { case err := <-errCh: return nil, err - case <-time.After(5 * time.Second): // assume server started successfully + case <-time.After(types.ServerStartTime): // assume server started successfully return grpcSrv, nil } } diff --git a/server/grpc/server_test.go b/server/grpc/server_test.go index 2618386340..225bc5c7a5 100644 --- a/server/grpc/server_test.go +++ b/server/grpc/server_test.go @@ -1,19 +1,25 @@ -// +build norace - package grpc_test import ( "context" "fmt" "testing" + "time" + + "github.com/jhump/protoreflect/grpcreflect" "github.com/stretchr/testify/require" "github.com/stretchr/testify/suite" + "google.golang.org/grpc" "google.golang.org/grpc/metadata" rpb "google.golang.org/grpc/reflection/grpc_reflection_v1alpha" + "github.com/line/lbm-sdk/client" + reflectionv1 "github.com/line/lbm-sdk/client/grpc/reflection" clienttx "github.com/line/lbm-sdk/client/tx" + reflectionv2 "github.com/line/lbm-sdk/server/grpc/reflection/v2" + "github.com/line/lbm-sdk/simapp" "github.com/line/lbm-sdk/testutil/network" "github.com/line/lbm-sdk/testutil/testdata" sdk "github.com/line/lbm-sdk/types" @@ -23,11 +29,13 @@ import ( "github.com/line/lbm-sdk/types/tx/signing" authclient "github.com/line/lbm-sdk/x/auth/client" banktypes "github.com/line/lbm-sdk/x/bank/types" + stakingtypes "github.com/line/lbm-sdk/x/staking/types" ) type IntegrationTestSuite struct { suite.Suite + app *simapp.SimApp cfg network.Config network *network.Network conn *grpc.ClientConn @@ -35,8 +43,9 @@ type IntegrationTestSuite struct { func (s *IntegrationTestSuite) SetupSuite() { s.T().Log("setting up integration test suite") - + s.app = simapp.Setup(false) s.cfg = network.DefaultConfig() + s.cfg.NumValidators = 1 s.network = network.New(s.T(), s.cfg) s.Require().NotNil(s.network) @@ -91,32 +100,60 @@ func (s *IntegrationTestSuite) TestGRPCServer_BankBalance() { &banktypes.QueryBalanceRequest{Address: val0.Address.String(), Denom: denom}, grpc.Header(&header), ) + s.Require().NoError(err) blockHeight = header.Get(grpctypes.GRPCBlockHeightHeader) - s.Require().NotEmpty(blockHeight[0]) // blockHeight is []string, first element is block height. + s.Require().Equal([]string{"1"}, blockHeight) } func (s *IntegrationTestSuite) TestGRPCServer_Reflection() { // Test server reflection - reflectClient := rpb.NewServerReflectionClient(s.conn) - stream, err := reflectClient.ServerReflectionInfo(context.Background(), grpc.WaitForReady(true)) + ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) + defer cancel() + stub := rpb.NewServerReflectionClient(s.conn) + // NOTE(fdymylja): we use grpcreflect because it solves imports too + // so that we can always assert that given a reflection server it is + // possible to fully query all the methods, without having any context + // on the proto registry + rc := grpcreflect.NewClient(ctx, stub) + + services, err := rc.ListServices() s.Require().NoError(err) - s.Require().NoError(stream.Send(&rpb.ServerReflectionRequest{ - MessageRequest: &rpb.ServerReflectionRequest_ListServices{}, - })) - res, err := stream.Recv() + s.Require().Greater(len(services), 0) + + for _, svc := range services { + file, err := rc.FileContainingSymbol(svc) + s.Require().NoError(err) + sd := file.FindSymbol(svc) + s.Require().NotNil(sd) + } +} + +func (s *IntegrationTestSuite) TestGRPCServer_InterfaceReflection() { + // this tests the application reflection capabilities and compatibility between v1 and v2 + ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) + defer cancel() + + clientV2 := reflectionv2.NewReflectionServiceClient(s.conn) + clientV1 := reflectionv1.NewReflectionServiceClient(s.conn) + codecDesc, err := clientV2.GetCodecDescriptor(ctx, nil) s.Require().NoError(err) - services := res.GetListServicesResponse().Service - servicesMap := make(map[string]bool) - for _, s := range services { - servicesMap[s.Name] = true + + interfaces, err := clientV1.ListAllInterfaces(ctx, nil) + s.Require().NoError(err) + s.Require().Equal(len(codecDesc.Codec.Interfaces), len(interfaces.InterfaceNames)) + s.Require().Equal(len(s.cfg.InterfaceRegistry.ListAllInterfaces()), len(codecDesc.Codec.Interfaces)) + + for _, iface := range interfaces.InterfaceNames { + impls, err := clientV1.ListImplementations(ctx, &reflectionv1.ListImplementationsRequest{InterfaceName: iface}) + s.Require().NoError(err) + + s.Require().ElementsMatch(impls.ImplementationMessageNames, s.cfg.InterfaceRegistry.ListImplementations(iface)) } - // Make sure the following services are present - s.Require().True(servicesMap["lbm.bank.v1.Query"]) } func (s *IntegrationTestSuite) TestGRPCServer_GetTxsEvent() { // Query the tx via gRPC without pagination. This used to panic, see - // https://github.com/line/lbm-sdk/issues/8038. + // https://github.com/cosmos/cosmos-sdk/issues/8038. txServiceClient := txtypes.NewServiceClient(s.conn) _, err := txServiceClient.GetTxsEvent( context.Background(), @@ -130,40 +167,18 @@ func (s *IntegrationTestSuite) TestGRPCServer_GetTxsEvent() { func (s *IntegrationTestSuite) TestGRPCServer_BroadcastTx() { val0 := s.network.Validators[0] - // prepare txBuilder with msg - txBuilder := val0.ClientCtx.TxConfig.NewTxBuilder() - feeAmount := sdk.Coins{sdk.NewInt64Coin(s.cfg.BondDenom, 10)} - gasLimit := testdata.NewTestGasLimit() - s.Require().NoError( - txBuilder.SetMsgs(&banktypes.MsgSend{ - FromAddress: val0.Address.String(), - ToAddress: val0.Address.String(), - Amount: sdk.Coins{sdk.NewInt64Coin(s.cfg.BondDenom, 10)}, - }), - ) - txBuilder.SetFeeAmount(feeAmount) - txBuilder.SetGasLimit(gasLimit) - - // setup txFactory - txFactory := clienttx.Factory{}. - WithChainID(val0.ClientCtx.ChainID). - WithKeybase(val0.ClientCtx.Keyring). - WithTxConfig(val0.ClientCtx.TxConfig). - WithSignMode(signing.SignMode_SIGN_MODE_DIRECT) - - // Sign Tx. - err := authclient.SignTx(txFactory, val0.ClientCtx, val0.Moniker, txBuilder, false, true) - s.Require().NoError(err) + txBuilder := s.mkTxBuilder() txBytes, err := val0.ClientCtx.TxConfig.TxEncoder()(txBuilder.GetTx()) s.Require().NoError(err) // Broadcast the tx via gRPC. - queryClient := tx.NewServiceClient(s.conn) + queryClient := txtypes.NewServiceClient(s.conn) + grpcRes, err := queryClient.BroadcastTx( context.Background(), - &tx.BroadcastTxRequest{ - Mode: tx.BroadcastMode_BROADCAST_MODE_SYNC, + &txtypes.BroadcastTxRequest{ + Mode: txtypes.BroadcastMode_BROADCAST_MODE_SYNC, TxBytes: txBytes, }, ) @@ -176,28 +191,21 @@ func (s *IntegrationTestSuite) TestGRPCServer_BroadcastTx() { // See issue https://github.com/cosmos/cosmos-sdk/issues/7662. func (s *IntegrationTestSuite) TestGRPCServerInvalidHeaderHeights() { t := s.T() - val0 := s.network.Validators[0] // We should reject connections with invalid block heights off the bat. invalidHeightStrs := []struct { value string wantErr string }{ - {"-1", "\"x-lbm-block-height\" must be >= 0"}, + {"-1", "height < 0"}, {"9223372036854775808", "value out of range"}, // > max(int64) by 1 - {"-10", "\"x-lbm-block-height\" must be >= 0"}, + {"-10", "height < 0"}, {"18446744073709551615", "value out of range"}, // max uint64, which is > max(int64) {"-9223372036854775809", "value out of range"}, // Out of the range of for negative int64 } for _, tt := range invalidHeightStrs { t.Run(tt.value, func(t *testing.T) { - conn, err := grpc.Dial( - val0.AppConfig.GRPC.Address, - grpc.WithInsecure(), // Or else we get "no transport security set" - ) - defer conn.Close() - - testClient := testdata.NewQueryClient(conn) + testClient := testdata.NewQueryClient(s.conn) ctx := metadata.AppendToOutgoingContext(context.Background(), grpctypes.GRPCBlockHeightHeader, tt.value) testRes, err := testClient.Echo(ctx, &testdata.EchoRequest{Message: "hello"}) require.Error(t, err) @@ -207,6 +215,62 @@ func (s *IntegrationTestSuite) TestGRPCServerInvalidHeaderHeights() { } } +// TestGRPCUnpacker - tests the grpc endpoint for Validator and using the interface registry unpack and extract the +// ConsAddr. (ref: https://github.com/cosmos/cosmos-sdk/issues/8045) +func (s *IntegrationTestSuite) TestGRPCUnpacker() { + ir := s.app.InterfaceRegistry() + queryClient := stakingtypes.NewQueryClient(s.conn) + validator, err := queryClient.Validator(context.Background(), + &stakingtypes.QueryValidatorRequest{ValidatorAddr: s.network.Validators[0].ValAddress.String()}) + require.NoError(s.T(), err) + + // no unpacked interfaces yet, so ConsAddr will be nil + nilAddr, err := validator.Validator.GetConsAddr() + require.Error(s.T(), err) + require.True(s.T(), nilAddr.Empty()) + + // unpack the interfaces and now ConsAddr is not nil + err = validator.Validator.UnpackInterfaces(ir) + require.NoError(s.T(), err) + addr, err := validator.Validator.GetConsAddr() + require.False(s.T(), addr.Empty()) + require.NoError(s.T(), err) +} + +// mkTxBuilder creates a TxBuilder containing a signed tx from validator 0. +func (s IntegrationTestSuite) mkTxBuilder() client.TxBuilder { + val := s.network.Validators[0] + s.Require().NoError(s.network.WaitForNextBlock()) + + // prepare txBuilder with msg + txBuilder := val.ClientCtx.TxConfig.NewTxBuilder() + feeAmount := sdk.Coins{sdk.NewInt64Coin(s.cfg.BondDenom, 10)} + gasLimit := testdata.NewTestGasLimit() + s.Require().NoError( + txBuilder.SetMsgs(&banktypes.MsgSend{ + FromAddress: val.Address.String(), + ToAddress: val.Address.String(), + Amount: sdk.Coins{sdk.NewInt64Coin(s.cfg.BondDenom, 10)}, + }), + ) + txBuilder.SetFeeAmount(feeAmount) + txBuilder.SetGasLimit(gasLimit) + txBuilder.SetMemo("foobar") + + // setup txFactory + txFactory := clienttx.Factory{}. + WithChainID(val.ClientCtx.ChainID). + WithKeybase(val.ClientCtx.Keyring). + WithTxConfig(val.ClientCtx.TxConfig). + WithSignMode(signing.SignMode_SIGN_MODE_DIRECT) + + // Sign Tx. + err := authclient.SignTx(txFactory, val.ClientCtx, val.Moniker, txBuilder, false, true) + s.Require().NoError(err) + + return txBuilder +} + func TestIntegrationTestSuite(t *testing.T) { suite.Run(t, new(IntegrationTestSuite)) } diff --git a/server/init.go b/server/init.go index c455f8efd4..301fbf6015 100644 --- a/server/init.go +++ b/server/init.go @@ -4,24 +4,37 @@ import ( "fmt" "github.com/line/lbm-sdk/crypto/keyring" - sdk "github.com/line/lbm-sdk/types" ) -// GenerateCoinKey returns the address of a public key, along with the secret -// phrase to recover the private key. +// Deprecated: GenerateCoinKey generates a new key mnemonic along with its addrress. +// Please use testutils.GenerateCoinKey instead. func GenerateCoinKey(algo keyring.SignatureAlgo) (sdk.AccAddress, string, error) { - // generate a private key, with recovery phrase - info, secret, err := keyring.NewInMemory().NewMnemonic("name", keyring.English, sdk.FullFundraiserPath, algo) + // generate a private key, with mnemonic + info, secret, err := keyring.NewInMemory().NewMnemonic( + "name", + keyring.English, + sdk.GetConfig().GetFullBIP44Path(), + keyring.DefaultBIP39Passphrase, + algo, + ) if err != nil { - return sdk.AccAddress([]byte{}), "", err + return sdk.AccAddress(""), "", err } return sdk.BytesToAccAddress(info.GetPubKey().Address()), secret, nil } -// GenerateSaveCoinKey returns the address of a public key, along with the secret -// phrase to recover the private key. -func GenerateSaveCoinKey(keybase keyring.Keyring, keyName string, overwrite bool, algo keyring.SignatureAlgo) (sdk.AccAddress, string, error) { +// Deprecated: GenerateSaveCoinKey generates a new key mnemonic with its addrress. +// If mnemonic is provided then it's used for key generation. +// The key is saved in the keyring. The function returns error if overwrite=true and the key +// already exists. +// Please use testutils.GenerateSaveCoinKey instead. +func GenerateSaveCoinKey( + keybase keyring.Keyring, + keyName string, + overwrite bool, + algo keyring.SignatureAlgo, +) (sdk.AccAddress, string, error) { exists := false _, err := keybase.Key(keyName) if err == nil { @@ -30,23 +43,20 @@ func GenerateSaveCoinKey(keybase keyring.Keyring, keyName string, overwrite bool // ensure no overwrite if !overwrite && exists { - return sdk.AccAddress([]byte{}), "", fmt.Errorf( - "key already exists, overwrite is disabled") + return sdk.AccAddress(""), "", fmt.Errorf("key already exists, overwrite is disabled") } - // generate a private key, with recovery phrase + // remove the old key by name if it exists if exists { - err = keybase.Delete(keyName) - if err != nil { - return sdk.AccAddress([]byte{}), "", fmt.Errorf( - "failed to overwrite key") + if err := keybase.Delete(keyName); err != nil { + return sdk.AccAddress(""), "", fmt.Errorf("failed to overwrite key") } } - info, secret, err := keybase.NewMnemonic(keyName, keyring.English, sdk.FullFundraiserPath, algo) + k, mnemonic, err := keybase.NewMnemonic(keyName, keyring.English, sdk.GetConfig().GetFullBIP44Path(), keyring.DefaultBIP39Passphrase, algo) if err != nil { - return sdk.AccAddress([]byte{}), "", err + return sdk.AccAddress(""), "", err } - return sdk.BytesToAccAddress(info.GetPubKey().Address()), secret, nil + return sdk.BytesToAccAddress(k.GetPubKey().Address()), mnemonic, nil } diff --git a/server/mock/store.go b/server/mock/store.go index da7ce334f0..3022b2bb19 100644 --- a/server/mock/store.go +++ b/server/mock/store.go @@ -31,6 +31,10 @@ func (ms multiStore) CacheWrapWithTrace(_ io.Writer, _ sdk.TraceContext) sdk.Cac panic("not implemented") } +func (ms multiStore) CacheWrapWithListeners(_ store.StoreKey, _ []store.WriteListener) store.CacheWrap { + panic("not implemented") +} + func (ms multiStore) TracingEnabled() bool { panic("not implemented") } @@ -43,6 +47,14 @@ func (ms multiStore) SetTracer(w io.Writer) sdk.MultiStore { panic("not implemented") } +func (ms multiStore) AddListeners(key store.StoreKey, listeners []store.WriteListener) { + panic("not implemented") +} + +func (ms multiStore) ListeningEnabled(key store.StoreKey) bool { + panic("not implemented") +} + func (ms multiStore) Commit() sdk.CommitID { panic("not implemented") } @@ -102,6 +114,9 @@ func (ms multiStore) GetStoreType() sdk.StoreType { func (ms multiStore) SetInterBlockCache(_ sdk.MultiStorePersistentCache) { panic("not implemented") } +func (ms multiStore) SetIAVLCacheSize(size int) { + panic("not implemented") +} func (ms multiStore) SetInitialVersion(version int64) error { panic("not implemented") @@ -135,6 +150,10 @@ func (kv kvStore) CacheWrapWithTrace(w io.Writer, tc sdk.TraceContext) sdk.Cache panic("not implemented") } +func (kv kvStore) CacheWrapWithListeners(_ store.StoreKey, _ []store.WriteListener) store.CacheWrap { + panic("not implemented") +} + func (kv kvStore) GetStoreType() sdk.StoreType { panic("not implemented") } diff --git a/server/oc_cmds.go b/server/oc_cmds.go index dd13630bcb..d481747b6f 100644 --- a/server/oc_cmds.go +++ b/server/oc_cmds.go @@ -4,17 +4,15 @@ package server import ( "fmt" - "strings" ostcmd "github.com/line/ostracon/cmd/ostracon/commands" - "github.com/line/ostracon/libs/cli" "github.com/line/ostracon/p2p" pvm "github.com/line/ostracon/privval" ostversion "github.com/line/ostracon/version" "github.com/spf13/cobra" yaml "gopkg.in/yaml.v2" - "github.com/line/lbm-sdk/codec" + "github.com/line/lbm-sdk/client" cryptocodec "github.com/line/lbm-sdk/crypto/codec" sdk "github.com/line/lbm-sdk/types" ) @@ -32,7 +30,6 @@ func ShowNodeIDCmd() *cobra.Command { if err != nil { return err } - fmt.Println(nodeKey.ID()) return nil }, @@ -49,31 +46,24 @@ func ShowValidatorCmd() *cobra.Command { cfg := serverCtx.Config privValidator := pvm.LoadFilePV(cfg.PrivValidatorKeyFile(), cfg.PrivValidatorStateFile()) - valPubKey, err := privValidator.GetPubKey() + pk, err := privValidator.GetPubKey() if err != nil { return err } - - output, _ := cmd.Flags().GetString(cli.OutputFlag) - if strings.ToLower(output) == "json" { - return printlnJSON(valPubKey) - } - - pubkey, err := cryptocodec.FromOcPubKeyInterface(valPubKey) + sdkPK, err := cryptocodec.FromOcPubKeyInterface(pk) if err != nil { return err } - pubkeyBech32, err := sdk.Bech32ifyPubKey(sdk.Bech32PubKeyTypeConsPub, pubkey) + clientCtx := client.GetClientContextFromCmd(cmd) + bz, err := clientCtx.Codec.MarshalInterfaceJSON(sdkPK) if err != nil { return err } - - fmt.Println(pubkeyBech32) + fmt.Println(string(bz)) return nil }, } - cmd.Flags().StringP(cli.OutputFlag, "o", "text", "Output format (text|json)") return &cmd } @@ -87,19 +77,12 @@ func ShowAddressCmd() *cobra.Command { cfg := serverCtx.Config privValidator := pvm.LoadFilePV(cfg.PrivValidatorKeyFile(), cfg.PrivValidatorStateFile()) - valConsAddr := sdk.BytesToConsAddress(privValidator.GetAddress()) - - output, _ := cmd.Flags().GetString(cli.OutputFlag) - if strings.ToLower(output) == "json" { - return printlnJSON(valConsAddr) - } - + valConsAddr := (sdk.ConsAddress)(privValidator.GetAddress()) fmt.Println(valConsAddr.String()) return nil }, } - cmd.Flags().StringP(cli.OutputFlag, "o", "text", "Output format (text|json)") return cmd } @@ -133,20 +116,7 @@ against which this app has been compiled. } } -func printlnJSON(v interface{}) error { - cdc := codec.NewLegacyAmino() - cryptocodec.RegisterCrypto(cdc) - - marshalled, err := cdc.MarshalJSON(v) - if err != nil { - return err - } - - fmt.Println(string(marshalled)) - return nil -} - -// UnsafeResetAllCmd - extension of the ostracon command, resets initialization +// UnsafeResetAllCmd - extension of the tendermint command, resets initialization func UnsafeResetAllCmd() *cobra.Command { return &cobra.Command{ Use: "unsafe-reset-all", diff --git a/server/rosetta.go b/server/rosetta.go new file mode 100644 index 0000000000..37845655e0 --- /dev/null +++ b/server/rosetta.go @@ -0,0 +1,43 @@ +package server + +import ( + "fmt" + + "github.com/spf13/cobra" + + "github.com/line/lbm-sdk/codec" + codectypes "github.com/line/lbm-sdk/codec/types" + "github.com/line/lbm-sdk/server/rosetta" +) + +// RosettaCommand builds the rosetta root command given +// a protocol buffers serializer/deserializer +func RosettaCommand(ir codectypes.InterfaceRegistry, cdc codec.Codec) *cobra.Command { + cmd := &cobra.Command{ + Use: "rosetta", + Short: "spin up a rosetta server", + RunE: func(cmd *cobra.Command, args []string) error { + cmd.Println("WARNING: The Rosetta server is still a beta feature. Please do not use it in production.") + + conf, err := rosetta.FromFlags(cmd.Flags()) + if err != nil { + return err + } + + protoCodec, ok := cdc.(*codec.ProtoCodec) + if !ok { + return fmt.Errorf("exoected *codec.ProtoMarshaler, got: %T", cdc) + } + conf.WithCodec(ir, protoCodec) + + rosettaSrv, err := rosetta.ServerFromConfig(conf) + if err != nil { + return err + } + return rosettaSrv.Start() + }, + } + rosetta.SetFlags(cmd.Flags()) + + return cmd +} diff --git a/server/rosetta/client_offline.go b/server/rosetta/client_offline.go new file mode 100644 index 0000000000..b973a858b4 --- /dev/null +++ b/server/rosetta/client_offline.go @@ -0,0 +1,135 @@ +package rosetta + +import ( + "context" + "encoding/hex" + + "github.com/coinbase/rosetta-sdk-go/types" + + crgerrs "github.com/line/lbm-sdk/server/rosetta/lib/errors" + + sdk "github.com/line/lbm-sdk/types" +) + +// ---------- cosmos-rosetta-gateway.types.NetworkInformationProvider implementation ------------ // + +func (c *Client) OperationStatuses() []*types.OperationStatus { + return []*types.OperationStatus{ + { + Status: StatusTxSuccess, + Successful: true, + }, + { + Status: StatusTxReverted, + Successful: false, + }, + } +} + +func (c *Client) Version() string { + return c.version +} + +func (c *Client) SupportedOperations() []string { + return c.supportedOperations +} + +// ---------- cosmos-rosetta-gateway.types.OfflineClient implementation ------------ // + +func (c *Client) SignedTx(_ context.Context, txBytes []byte, signatures []*types.Signature) (signedTxBytes []byte, err error) { + return c.converter.ToSDK().SignedTx(txBytes, signatures) +} + +func (c *Client) ConstructionPayload(_ context.Context, request *types.ConstructionPayloadsRequest) (resp *types.ConstructionPayloadsResponse, err error) { + // check if there is at least one operation + if len(request.Operations) < 1 { + return nil, crgerrs.WrapError(crgerrs.ErrInvalidOperation, "expected at least one operation") + } + + tx, err := c.converter.ToSDK().UnsignedTx(request.Operations) + if err != nil { + return nil, crgerrs.WrapError(crgerrs.ErrInvalidOperation, err.Error()) + } + + metadata := new(ConstructionMetadata) + if err = metadata.FromMetadata(request.Metadata); err != nil { + return nil, err + } + + txBytes, payloads, err := c.converter.ToRosetta().SigningComponents(tx, metadata, request.PublicKeys) + if err != nil { + return nil, err + } + + return &types.ConstructionPayloadsResponse{ + UnsignedTransaction: hex.EncodeToString(txBytes), + Payloads: payloads, + }, nil +} + +func (c *Client) PreprocessOperationsToOptions(_ context.Context, req *types.ConstructionPreprocessRequest) (response *types.ConstructionPreprocessResponse, err error) { + if len(req.Operations) == 0 { + return nil, crgerrs.WrapError(crgerrs.ErrBadArgument, "no operations") + } + + // now we need to parse the operations to cosmos sdk messages + tx, err := c.converter.ToSDK().UnsignedTx(req.Operations) + if err != nil { + return nil, err + } + + // get the signers + signers := tx.GetSigners() + signersStr := make([]string, len(signers)) + accountIdentifiers := make([]*types.AccountIdentifier, len(signers)) + + for i, sig := range signers { + addr := sig.String() + signersStr[i] = addr + accountIdentifiers[i] = &types.AccountIdentifier{ + Address: addr, + } + } + // get the metadata request information + meta := new(ConstructionPreprocessMetadata) + err = meta.FromMetadata(req.Metadata) + if err != nil { + return nil, err + } + + if meta.GasPrice == "" { + return nil, crgerrs.WrapError(crgerrs.ErrBadArgument, "no gas prices") + } + + if meta.GasLimit == 0 { + return nil, crgerrs.WrapError(crgerrs.ErrBadArgument, "no gas limit") + } + + // prepare the options to return + options := &PreprocessOperationsOptionsResponse{ + ExpectedSigners: signersStr, + Memo: meta.Memo, + GasLimit: meta.GasLimit, + GasPrice: meta.GasPrice, + } + + metaOptions, err := options.ToMetadata() + if err != nil { + return nil, err + } + return &types.ConstructionPreprocessResponse{ + Options: metaOptions, + RequiredPublicKeys: accountIdentifiers, + }, nil +} + +func (c *Client) AccountIdentifierFromPublicKey(pubKey *types.PublicKey) (*types.AccountIdentifier, error) { + pk, err := c.converter.ToSDK().PubKey(pubKey) + if err != nil { + return nil, err + } + + return &types.AccountIdentifier{ + Address: sdk.AccAddress(pk.Address()).String(), + }, nil +} diff --git a/server/rosetta/client_online.go b/server/rosetta/client_online.go new file mode 100644 index 0000000000..7bc57e067f --- /dev/null +++ b/server/rosetta/client_online.go @@ -0,0 +1,518 @@ +package rosetta + +import ( + "bytes" + "context" + "encoding/base64" + "encoding/hex" + "errors" + "fmt" + "regexp" + "strconv" + "time" + + rosettatypes "github.com/coinbase/rosetta-sdk-go/types" + "google.golang.org/grpc" + "google.golang.org/grpc/metadata" + + abcitypes "github.com/line/ostracon/abci/types" + ocrpc "github.com/line/ostracon/rpc/client" + "github.com/line/ostracon/rpc/client/http" + + crgerrs "github.com/line/lbm-sdk/server/rosetta/lib/errors" + crgtypes "github.com/line/lbm-sdk/server/rosetta/lib/types" + sdk "github.com/line/lbm-sdk/types" + grpctypes "github.com/line/lbm-sdk/types/grpc" + "github.com/line/lbm-sdk/version" + authtx "github.com/line/lbm-sdk/x/auth/tx" + auth "github.com/line/lbm-sdk/x/auth/types" + bank "github.com/line/lbm-sdk/x/bank/types" +) + +// interface assertion +var _ crgtypes.Client = (*Client)(nil) + +const tmWebsocketPath = "/websocket" +const defaultNodeTimeout = 15 * time.Second + +// Client implements a single network client to interact with cosmos based chains +type Client struct { + supportedOperations []string + + config *Config + + auth auth.QueryClient + bank bank.QueryClient + tmRPC ocrpc.Client + + version string + + converter Converter +} + +// NewClient instantiates a new online servicer +func NewClient(cfg *Config) (*Client, error) { + info := version.NewInfo() + + v := info.Version + if v == "" { + v = "unknown" + } + + txConfig := authtx.NewTxConfig(cfg.Codec, authtx.DefaultSignModes) + + var supportedOperations []string + for _, ii := range cfg.InterfaceRegistry.ListImplementations(sdk.MsgInterfaceProtoName) { + resolvedMsg, err := cfg.InterfaceRegistry.Resolve(ii) + if err != nil { + continue + } + + if _, ok := resolvedMsg.(sdk.Msg); ok { + supportedOperations = append(supportedOperations, ii) + } + } + + supportedOperations = append( + supportedOperations, + bank.EventTypeCoinSpent, + bank.EventTypeCoinReceived, + bank.EventTypeCoinBurn, + ) + + return &Client{ + supportedOperations: supportedOperations, + config: cfg, + auth: nil, + bank: nil, + tmRPC: nil, + version: fmt.Sprintf("%s/%s", info.AppName, v), + converter: NewConverter(cfg.Codec, cfg.InterfaceRegistry, txConfig), + }, nil +} + +// ---------- cosmos-rosetta-gateway.types.Client implementation ------------ // + +// Bootstrap is gonna connect the client to the endpoints +func (c *Client) Bootstrap() error { + grpcConn, err := grpc.Dial(c.config.GRPCEndpoint, grpc.WithInsecure()) + if err != nil { + return err + } + + tmRPC, err := http.New(c.config.TendermintRPC, tmWebsocketPath) + if err != nil { + return err + } + + authClient := auth.NewQueryClient(grpcConn) + bankClient := bank.NewQueryClient(grpcConn) + + c.auth = authClient + c.bank = bankClient + c.tmRPC = tmRPC + + return nil +} + +// Ready performs a health check and returns an error if the client is not ready. +func (c *Client) Ready() error { + ctx, cancel := context.WithTimeout(context.Background(), defaultNodeTimeout) + defer cancel() + _, err := c.tmRPC.Health(ctx) + if err != nil { + return err + } + _, err = c.bank.TotalSupply(ctx, &bank.QueryTotalSupplyRequest{}) + if err != nil { + return err + } + return nil +} + +func (c *Client) accountInfo(ctx context.Context, addr string, height *int64) (*SignerData, error) { + if height != nil { + strHeight := strconv.FormatInt(*height, 10) + ctx = metadata.AppendToOutgoingContext(ctx, grpctypes.GRPCBlockHeightHeader, strHeight) + } + + accountInfo, err := c.auth.Account(ctx, &auth.QueryAccountRequest{ + Address: addr, + }) + if err != nil { + return nil, crgerrs.FromGRPCToRosettaError(err) + } + + signerData, err := c.converter.ToRosetta().SignerData(accountInfo.Account) + if err != nil { + return nil, err + } + return signerData, nil +} + +func (c *Client) Balances(ctx context.Context, addr string, height *int64) ([]*rosettatypes.Amount, error) { + if height != nil { + strHeight := strconv.FormatInt(*height, 10) + ctx = metadata.AppendToOutgoingContext(ctx, grpctypes.GRPCBlockHeightHeader, strHeight) + } + + balance, err := c.bank.AllBalances(ctx, &bank.QueryAllBalancesRequest{ + Address: addr, + }) + if err != nil { + return nil, crgerrs.FromGRPCToRosettaError(err) + } + + availableCoins, err := c.coins(ctx) + if err != nil { + return nil, err + } + + return c.converter.ToRosetta().Amounts(balance.Balances, availableCoins), nil +} + +func (c *Client) BlockByHash(ctx context.Context, hash string) (crgtypes.BlockResponse, error) { + bHash, err := hex.DecodeString(hash) + if err != nil { + return crgtypes.BlockResponse{}, fmt.Errorf("invalid block hash: %s", err) + } + + block, err := c.tmRPC.BlockByHash(ctx, bHash) + if err != nil { + return crgtypes.BlockResponse{}, crgerrs.WrapError(crgerrs.ErrBadGateway, err.Error()) + } + + return c.converter.ToRosetta().BlockResponse(block), nil +} + +func (c *Client) BlockByHeight(ctx context.Context, height *int64) (crgtypes.BlockResponse, error) { + height, err := c.getHeight(ctx, height) + if err != nil { + return crgtypes.BlockResponse{}, crgerrs.WrapError(crgerrs.ErrBadGateway, err.Error()) + } + block, err := c.tmRPC.Block(ctx, height) + if err != nil { + return crgtypes.BlockResponse{}, crgerrs.WrapError(crgerrs.ErrBadGateway, err.Error()) + } + + return c.converter.ToRosetta().BlockResponse(block), nil +} + +func (c *Client) BlockTransactionsByHash(ctx context.Context, hash string) (crgtypes.BlockTransactionsResponse, error) { + // TODO(fdymylja): use a faster path, by searching the block by hash, instead of doing a double query operation + blockResp, err := c.BlockByHash(ctx, hash) + if err != nil { + return crgtypes.BlockTransactionsResponse{}, err + } + + return c.blockTxs(ctx, &blockResp.Block.Index) +} + +func (c *Client) BlockTransactionsByHeight(ctx context.Context, height *int64) (crgtypes.BlockTransactionsResponse, error) { + height, err := c.getHeight(ctx, height) + if err != nil { + return crgtypes.BlockTransactionsResponse{}, crgerrs.WrapError(crgerrs.ErrBadGateway, err.Error()) + } + blockTxResp, err := c.blockTxs(ctx, height) + if err != nil { + return crgtypes.BlockTransactionsResponse{}, err + } + return blockTxResp, nil +} + +// Coins fetches the existing coins in the application +func (c *Client) coins(ctx context.Context) (sdk.Coins, error) { + supply, err := c.bank.TotalSupply(ctx, &bank.QueryTotalSupplyRequest{}) + if err != nil { + return nil, crgerrs.FromGRPCToRosettaError(err) + } + return supply.Supply, nil +} + +func (c *Client) TxOperationsAndSignersAccountIdentifiers(signed bool, txBytes []byte) (ops []*rosettatypes.Operation, signers []*rosettatypes.AccountIdentifier, err error) { + switch signed { + case false: + rosTx, err := c.converter.ToRosetta().Tx(txBytes, nil) + if err != nil { + return nil, nil, err + } + return rosTx.Operations, nil, err + default: + ops, signers, err = c.converter.ToRosetta().OpsAndSigners(txBytes) + return + } +} + +// GetTx returns a transaction given its hash. For Rosetta we make a synthetic transaction for BeginBlock +// and EndBlock to adhere to balance tracking rules. +func (c *Client) GetTx(ctx context.Context, hash string) (*rosettatypes.Transaction, error) { + hashBytes, err := hex.DecodeString(hash) + if err != nil { + return nil, crgerrs.WrapError(crgerrs.ErrCodec, fmt.Sprintf("bad tx hash: %s", err)) + } + + // get tx type and hash + txType, hashBytes := c.converter.ToSDK().HashToTxType(hashBytes) + + // construct rosetta tx + switch txType { + // handle begin block hash + case BeginBlockTx: + // get block height by hash + block, err := c.tmRPC.BlockByHash(ctx, hashBytes) + if err != nil { + return nil, crgerrs.WrapError(crgerrs.ErrUnknown, err.Error()) + } + + // get block txs + fullBlock, err := c.blockTxs(ctx, &block.Block.Height) + if err != nil { + return nil, err + } + + return fullBlock.Transactions[0], nil + // handle deliver tx hash + case DeliverTxTx: + rawTx, err := c.tmRPC.Tx(ctx, hashBytes, true) + if err != nil { + return nil, crgerrs.WrapError(crgerrs.ErrUnknown, err.Error()) + } + return c.converter.ToRosetta().Tx(rawTx.Tx, &rawTx.TxResult) + // handle end block hash + case EndBlockTx: + // get block height by hash + block, err := c.tmRPC.BlockByHash(ctx, hashBytes) + if err != nil { + return nil, crgerrs.WrapError(crgerrs.ErrUnknown, err.Error()) + } + + // get block txs + fullBlock, err := c.blockTxs(ctx, &block.Block.Height) + if err != nil { + return nil, err + } + + // get last tx + return fullBlock.Transactions[len(fullBlock.Transactions)-1], nil + // unrecognized tx + default: + return nil, crgerrs.WrapError(crgerrs.ErrBadArgument, fmt.Sprintf("invalid tx hash provided: %s", hash)) + } +} + +// GetUnconfirmedTx gets an unconfirmed transaction given its hash +func (c *Client) GetUnconfirmedTx(ctx context.Context, hash string) (*rosettatypes.Transaction, error) { + res, err := c.tmRPC.UnconfirmedTxs(ctx, nil) + if err != nil { + return nil, crgerrs.WrapError(crgerrs.ErrNotFound, "unconfirmed tx not found") + } + + hashAsBytes, err := hex.DecodeString(hash) + if err != nil { + return nil, crgerrs.WrapError(crgerrs.ErrInterpreting, "invalid hash") + } + + // assert that correct tx length is provided + switch len(hashAsBytes) { + default: + return nil, crgerrs.WrapError(crgerrs.ErrBadArgument, fmt.Sprintf("unrecognized tx size: %d", len(hashAsBytes))) + case BeginEndBlockTxSize: + return nil, crgerrs.WrapError(crgerrs.ErrBadArgument, "endblock and begin block txs cannot be unconfirmed") + case DeliverTxSize: + break + } + + // iterate over unconfirmed txs to find the one with matching hash + for _, unconfirmedTx := range res.Txs { + if !bytes.Equal(unconfirmedTx.Hash(), hashAsBytes) { + continue + } + + return c.converter.ToRosetta().Tx(unconfirmedTx, nil) + } + return nil, crgerrs.WrapError(crgerrs.ErrNotFound, "transaction not found in mempool: "+hash) +} + +// Mempool returns the unconfirmed transactions in the mempool +func (c *Client) Mempool(ctx context.Context) ([]*rosettatypes.TransactionIdentifier, error) { + txs, err := c.tmRPC.UnconfirmedTxs(ctx, nil) + if err != nil { + return nil, err + } + + return c.converter.ToRosetta().TxIdentifiers(txs.Txs), nil +} + +// Peers gets the number of peers +func (c *Client) Peers(ctx context.Context) ([]*rosettatypes.Peer, error) { + netInfo, err := c.tmRPC.NetInfo(ctx) + if err != nil { + return nil, crgerrs.WrapError(crgerrs.ErrUnknown, err.Error()) + } + return c.converter.ToRosetta().Peers(netInfo.Peers), nil +} + +func (c *Client) Status(ctx context.Context) (*rosettatypes.SyncStatus, error) { + status, err := c.tmRPC.Status(ctx) + if err != nil { + return nil, crgerrs.WrapError(crgerrs.ErrUnknown, err.Error()) + } + return c.converter.ToRosetta().SyncStatus(status), err +} + +func (c *Client) PostTx(txBytes []byte) (*rosettatypes.TransactionIdentifier, map[string]interface{}, error) { + // sync ensures it will go through checkTx + res, err := c.tmRPC.BroadcastTxSync(context.Background(), txBytes) + if err != nil { + return nil, nil, crgerrs.WrapError(crgerrs.ErrUnknown, err.Error()) + } + // check if tx was broadcast successfully + if res.Code != abcitypes.CodeTypeOK { + return nil, nil, crgerrs.WrapError( + crgerrs.ErrUnknown, + fmt.Sprintf("transaction broadcast failure: (%d) %s ", res.Code, res.Log), + ) + } + + return &rosettatypes.TransactionIdentifier{ + Hash: fmt.Sprintf("%X", res.Hash), + }, + map[string]interface{}{ + Log: res.Log, + }, nil +} + +// construction endpoints + +// ConstructionMetadataFromOptions builds the metadata given the options +func (c *Client) ConstructionMetadataFromOptions(ctx context.Context, options map[string]interface{}) (meta map[string]interface{}, err error) { + if len(options) == 0 { + return nil, crgerrs.ErrBadArgument + } + + constructionOptions := new(PreprocessOperationsOptionsResponse) + + err = constructionOptions.FromMetadata(options) + if err != nil { + return nil, err + } + + signersData := make([]*SignerData, len(constructionOptions.ExpectedSigners)) + + for i, signer := range constructionOptions.ExpectedSigners { + accountInfo, err := c.accountInfo(ctx, signer, nil) + if err != nil { + return nil, err + } + + signersData[i] = accountInfo + } + + status, err := c.tmRPC.Status(ctx) + if err != nil { + return nil, err + } + + metadataResp := ConstructionMetadata{ + ChainID: status.NodeInfo.Network, + SignersData: signersData, + GasLimit: constructionOptions.GasLimit, + GasPrice: constructionOptions.GasPrice, + Memo: constructionOptions.Memo, + } + + return metadataResp.ToMetadata() +} + +func (c *Client) blockTxs(ctx context.Context, height *int64) (crgtypes.BlockTransactionsResponse, error) { + // get block info + blockInfo, err := c.tmRPC.Block(ctx, height) + if err != nil { + return crgtypes.BlockTransactionsResponse{}, err + } + // get block events + blockResults, err := c.tmRPC.BlockResults(ctx, height) + if err != nil { + return crgtypes.BlockTransactionsResponse{}, err + } + + if len(blockResults.TxsResults) != len(blockInfo.Block.Txs) { + // wtf? + panic("block results transactions do now match block transactions") + } + // process begin and end block txs + beginBlockTx := &rosettatypes.Transaction{ + TransactionIdentifier: &rosettatypes.TransactionIdentifier{Hash: c.converter.ToRosetta().BeginBlockTxHash(blockInfo.BlockID.Hash)}, + Operations: AddOperationIndexes( + nil, + c.converter.ToRosetta().BalanceOps(StatusTxSuccess, blockResults.BeginBlockEvents), + ), + } + + endBlockTx := &rosettatypes.Transaction{ + TransactionIdentifier: &rosettatypes.TransactionIdentifier{Hash: c.converter.ToRosetta().EndBlockTxHash(blockInfo.BlockID.Hash)}, + Operations: AddOperationIndexes( + nil, + c.converter.ToRosetta().BalanceOps(StatusTxSuccess, blockResults.EndBlockEvents), + ), + } + + deliverTx := make([]*rosettatypes.Transaction, len(blockInfo.Block.Txs)) + // process normal txs + for i, tx := range blockInfo.Block.Txs { + rosTx, err := c.converter.ToRosetta().Tx(tx, blockResults.TxsResults[i]) + if err != nil { + return crgtypes.BlockTransactionsResponse{}, err + } + deliverTx[i] = rosTx + } + + finalTxs := make([]*rosettatypes.Transaction, 0, 2+len(deliverTx)) + finalTxs = append(finalTxs, beginBlockTx) + finalTxs = append(finalTxs, deliverTx...) + finalTxs = append(finalTxs, endBlockTx) + + return crgtypes.BlockTransactionsResponse{ + BlockResponse: c.converter.ToRosetta().BlockResponse(blockInfo), + Transactions: finalTxs, + }, nil +} + +func (c *Client) getHeight(ctx context.Context, height *int64) (realHeight *int64, err error) { + if height != nil && *height == -1 { + genesisChunk, err := c.tmRPC.GenesisChunked(ctx, 0) + if err != nil { + return nil, err + } + + heightNum, err := extractInitialHeightFromGenesisChunk(genesisChunk.Data) + if err != nil { + return nil, err + } + + realHeight = &heightNum + } else { + realHeight = height + } + return +} + +func extractInitialHeightFromGenesisChunk(genesisChunk string) (int64, error) { + firstChunk, err := base64.StdEncoding.DecodeString(genesisChunk) + if err != nil { + return 0, err + } + + re, err := regexp.Compile("\"initial_height\":\"(\\d+)\"") //nolint:gocritic + if err != nil { + return 0, err + } + + matches := re.FindStringSubmatch(string(firstChunk)) + if len(matches) != 2 { + return 0, errors.New("failed to fetch initial_height") + } + + heightStr := matches[1] + return strconv.ParseInt(heightStr, 10, 64) +} diff --git a/server/rosetta/client_online_test.go b/server/rosetta/client_online_test.go new file mode 100644 index 0000000000..9aa8965cf6 --- /dev/null +++ b/server/rosetta/client_online_test.go @@ -0,0 +1,15 @@ +package rosetta + +import ( + "encoding/base64" + "testing" + + "github.com/stretchr/testify/require" +) + +func TestRegex(t *testing.T) { + genesisChuck := base64.StdEncoding.EncodeToString([]byte(`"genesis_time":"2021-09-28T09:00:00Z","chain_id":"bombay-12","initial_height":"5900001","consensus_params":{"block":{"max_bytes":"5000000","max_gas":"1000000000","time_iota_ms":"1000"},"evidence":{"max_age_num_blocks":"100000","max_age_duration":"172800000000000","max_bytes":"50000"},"validator":{"pub_key_types":["ed25519"]},"version":{}},"validators":[{"address":"EEA4891F5F8D523A6B4B3EAC84B5C08655A00409","pub_key":{"type":"tendermint/PubKeyEd25519","value":"UX71gTBNumQq42qRd6j/K8XN/y3/HAcuAJxj97utawI="},"power":"60612","name":"BTC.Secure"},{"address":"973F589DE1CC8A54ABE2ABE0E0A4ABF13A9EBAE4","pub_key":{"type":"tendermint/PubKeyEd25519","value":"AmGQvQSAAXzSIscx/6o4rVdRMT9QvairQHaCXsWhY+c="},"power":"835","name":"MoonletWallet"},{"address":"831F402BDA0C9A3F260D4F221780BC22A4C3FB23","pub_key":{"type":"tendermint/PubKeyEd25519","value":"Tw8yKbPNEo113ZNbJJ8joeXokoMdBoazRTwb1NQ77WA="},"power":"102842","name":"BlockNgine"},{"address":"F2683F267D2B4C8714B44D68612DB37A8DD2EED7","pub_key":{"type":"tendermint/PubKeyEd25519","value":"PVE4IcWDE6QEqJSEkx55IDkg5zxBo8tVRzKFMJXYFSQ="},"power":"23200","name":"Luna Station 88"},{"address":"9D2428CBAC68C654BE11BE405344C560E6A0F626","pub_key":{"type":"tendermint/PubKeyEd25519","value":"93hzGmZjPRqOnQkb8BULjqanW3M2p1qIcLVTGkf1Zhk="},"power":"35420","name":"Terra-India"},{"address":"DC9897F22E74BF1B66E2640FA461F785F9BA7627","pub_key":{"type":"tendermint/PubKeyEd25519","value":"mlYb/Dzqwh0YJjfH59OZ4vtp+Zhdq5Oj5MNaGHq1X0E="},"power":"25163","name":"SolidStake"},{"address":"AA1A027E270A2BD7AF154999E6DE9D39C5711DE7","pub_key":{"type":"tendermint/PubKeyEd25519","value":"28z8FlpbC7sR0f1Q8OWFASDNi0FAmdldzetwQ07JJzg="},"power":"34529","name":"syncnode"},{"address":"E548735750DC5015ADDE3B0E7A1294C3B868680B","pub_key":{"type":"tendermint/PubKeyEd25519","value":"BTDtLSKp4wpQrWBwmGvp9isWC5jXaAtX1nrJtsCEWew="},"power":"36082","name":"OneStar"}`)) + height, err := extractInitialHeightFromGenesisChunk(genesisChuck) + require.NoError(t, err) + require.Equal(t, height, int64(5900001)) +} diff --git a/server/rosetta/codec.go b/server/rosetta/codec.go new file mode 100644 index 0000000000..60da1c9532 --- /dev/null +++ b/server/rosetta/codec.go @@ -0,0 +1,22 @@ +package rosetta + +import ( + "github.com/line/lbm-sdk/codec" + codectypes "github.com/line/lbm-sdk/codec/types" + cryptocodec "github.com/line/lbm-sdk/crypto/codec" + authcodec "github.com/line/lbm-sdk/x/auth/types" + bankcodec "github.com/line/lbm-sdk/x/bank/types" +) + +// MakeCodec generates the codec required to interact +// with the cosmos APIs used by the rosetta gateway +func MakeCodec() (*codec.ProtoCodec, codectypes.InterfaceRegistry) { + ir := codectypes.NewInterfaceRegistry() + cdc := codec.NewProtoCodec(ir) + + authcodec.RegisterInterfaces(ir) + bankcodec.RegisterInterfaces(ir) + cryptocodec.RegisterInterfaces(ir) + + return cdc, ir +} diff --git a/server/rosetta/config.go b/server/rosetta/config.go new file mode 100644 index 0000000000..47b4321ec0 --- /dev/null +++ b/server/rosetta/config.go @@ -0,0 +1,204 @@ +package rosetta + +import ( + "fmt" + "strings" + "time" + + "github.com/coinbase/rosetta-sdk-go/types" + "github.com/spf13/pflag" + + crg "github.com/line/lbm-sdk/server/rosetta/lib/server" + + "github.com/line/lbm-sdk/codec" + codectypes "github.com/line/lbm-sdk/codec/types" +) + +// configuration defaults constants +const ( + // DefaultBlockchain defines the default blockchain identifier name + DefaultBlockchain = "app" + // DefaultAddr defines the default rosetta binding address + DefaultAddr = ":8080" + // DefaultRetries is the default number of retries + DefaultRetries = 5 + // DefaultTendermintEndpoint is the default value for the tendermint endpoint + DefaultTendermintEndpoint = "localhost:26657" + // DefaultGRPCEndpoint is the default value for the gRPC endpoint + DefaultGRPCEndpoint = "localhost:9090" + // DefaultNetwork defines the default network name + DefaultNetwork = "network" + // DefaultOffline defines the default offline value + DefaultOffline = false +) + +// configuration flags +const ( + FlagBlockchain = "blockchain" + FlagNetwork = "network" + FlagTendermintEndpoint = "tendermint" + FlagGRPCEndpoint = "grpc" + FlagAddr = "addr" + FlagRetries = "retries" + FlagOffline = "offline" +) + +// Config defines the configuration of the rosetta server +type Config struct { + // Blockchain defines the blockchain name + // defaults to DefaultBlockchain + Blockchain string + // Network defines the network name + Network string + // TendermintRPC defines the endpoint to connect to + // tendermint RPC, specifying 'tcp://' before is not + // required, usually it's at port 26657 of the + TendermintRPC string + // GRPCEndpoint defines the cosmos application gRPC endpoint + // usually it is located at 9090 port + GRPCEndpoint string + // Addr defines the default address to bind the rosetta server to + // defaults to DefaultAddr + Addr string + // Retries defines the maximum number of retries + // rosetta will do before quitting + Retries int + // Offline defines if the server must be run in offline mode + Offline bool + // Codec overrides the default data and construction api client codecs + Codec *codec.ProtoCodec + // InterfaceRegistry overrides the default data and construction api interface registry + InterfaceRegistry codectypes.InterfaceRegistry +} + +// NetworkIdentifier returns the network identifier given the configuration +func (c *Config) NetworkIdentifier() *types.NetworkIdentifier { + return &types.NetworkIdentifier{ + Blockchain: c.Blockchain, + Network: c.Network, + } +} + +// validate validates a configuration and sets +// its defaults in case they were not provided +func (c *Config) validate() error { + if (c.Codec == nil) != (c.InterfaceRegistry == nil) { + return fmt.Errorf("codec and interface registry must be both different from nil or nil") + } + + if c.Addr == "" { + c.Addr = DefaultAddr + } + if c.Blockchain == "" { + c.Blockchain = DefaultBlockchain + } + if c.Retries == 0 { + c.Retries = DefaultRetries + } + // these are must + if c.Network == "" { + return fmt.Errorf("network not provided") + } + if c.Offline { + return fmt.Errorf("offline mode is not supported for stargate implementation due to how sigv2 works") + } + + // these are optional but it must be online + if c.GRPCEndpoint == "" { + return fmt.Errorf("grpc endpoint not provided") + } + if c.TendermintRPC == "" { + return fmt.Errorf("tendermint rpc not provided") + } + if !strings.HasPrefix(c.TendermintRPC, "tcp://") { + c.TendermintRPC = fmt.Sprintf("tcp://%s", c.TendermintRPC) + } + + return nil +} + +// WithCodec extends the configuration with a predefined Codec +func (c *Config) WithCodec(ir codectypes.InterfaceRegistry, cdc *codec.ProtoCodec) { + c.Codec = cdc + c.InterfaceRegistry = ir +} + +// FromFlags gets the configuration from flags +func FromFlags(flags *pflag.FlagSet) (*Config, error) { + blockchain, err := flags.GetString(FlagBlockchain) + if err != nil { + return nil, err + } + network, err := flags.GetString(FlagNetwork) + if err != nil { + return nil, err + } + tendermintRPC, err := flags.GetString(FlagTendermintEndpoint) + if err != nil { + return nil, err + } + gRPCEndpoint, err := flags.GetString(FlagGRPCEndpoint) + if err != nil { + return nil, err + } + addr, err := flags.GetString(FlagAddr) + if err != nil { + return nil, err + } + retries, err := flags.GetInt(FlagRetries) + if err != nil { + return nil, err + } + offline, err := flags.GetBool(FlagOffline) + if err != nil { + return nil, err + } + conf := &Config{ + Blockchain: blockchain, + Network: network, + TendermintRPC: tendermintRPC, + GRPCEndpoint: gRPCEndpoint, + Addr: addr, + Retries: retries, + Offline: offline, + } + err = conf.validate() + if err != nil { + return nil, err + } + return conf, nil +} + +func ServerFromConfig(conf *Config) (crg.Server, error) { + err := conf.validate() + if err != nil { + return crg.Server{}, err + } + client, err := NewClient(conf) + if err != nil { + return crg.Server{}, err + } + return crg.NewServer( + crg.Settings{ + Network: &types.NetworkIdentifier{ + Blockchain: conf.Blockchain, + Network: conf.Network, + }, + Client: client, + Listen: conf.Addr, + Offline: conf.Offline, + Retries: conf.Retries, + RetryWait: 15 * time.Second, + }) +} + +// SetFlags sets the configuration flags to the given flagset +func SetFlags(flags *pflag.FlagSet) { + flags.String(FlagBlockchain, DefaultBlockchain, "the blockchain type") + flags.String(FlagNetwork, DefaultNetwork, "the network name") + flags.String(FlagTendermintEndpoint, DefaultTendermintEndpoint, "the tendermint rpc endpoint, without tcp://") + flags.String(FlagGRPCEndpoint, DefaultGRPCEndpoint, "the app gRPC endpoint") + flags.String(FlagAddr, DefaultAddr, "the address rosetta will bind to") + flags.Int(FlagRetries, DefaultRetries, "the number of retries that will be done before quitting") + flags.Bool(FlagOffline, DefaultOffline, "run rosetta only with construction API") +} diff --git a/server/rosetta/converter.go b/server/rosetta/converter.go new file mode 100644 index 0000000000..25a57dfe30 --- /dev/null +++ b/server/rosetta/converter.go @@ -0,0 +1,778 @@ +package rosetta + +import ( + "bytes" + "encoding/json" + "fmt" + "reflect" + + "github.com/btcsuite/btcd/btcec" + rosettatypes "github.com/coinbase/rosetta-sdk-go/types" + + abci "github.com/line/ostracon/abci/types" + "github.com/line/ostracon/crypto" + ostcoretypes "github.com/line/ostracon/rpc/core/types" + octypes "github.com/line/ostracon/types" + + sdkclient "github.com/line/lbm-sdk/client" + "github.com/line/lbm-sdk/codec" + codectypes "github.com/line/lbm-sdk/codec/types" + "github.com/line/lbm-sdk/crypto/keys/secp256k1" + cryptotypes "github.com/line/lbm-sdk/crypto/types" + crgerrs "github.com/line/lbm-sdk/server/rosetta/lib/errors" + crgtypes "github.com/line/lbm-sdk/server/rosetta/lib/types" + sdk "github.com/line/lbm-sdk/types" + "github.com/line/lbm-sdk/types/tx/signing" + authsigning "github.com/line/lbm-sdk/x/auth/signing" + auth "github.com/line/lbm-sdk/x/auth/types" + banktypes "github.com/line/lbm-sdk/x/bank/types" +) + +// Converter is a utility that can be used to convert +// back and forth from rosetta to sdk and tendermint types +// IMPORTANT NOTES: +// - IT SHOULD BE USED ONLY TO DEAL WITH THINGS +// IN A STATELESS WAY! IT SHOULD NEVER INTERACT DIRECTLY +// WITH TENDERMINT RPC AND COSMOS GRPC +// +// - IT SHOULD RETURN cosmos rosetta gateway error types! +type Converter interface { + // ToSDK exposes the methods that convert + // rosetta types to cosmos sdk and tendermint types + ToSDK() ToSDKConverter + // ToRosetta exposes the methods that convert + // sdk and tendermint types to rosetta types + ToRosetta() ToRosettaConverter +} + +// ToRosettaConverter is an interface that exposes +// all the functions used to convert sdk and +// tendermint types to rosetta known types +type ToRosettaConverter interface { + // BlockResponse returns a block response given a result block + BlockResponse(block *ostcoretypes.ResultBlock) crgtypes.BlockResponse + // BeginBlockToTx converts the given begin block hash to rosetta transaction hash + BeginBlockTxHash(blockHash []byte) string + // EndBlockTxHash converts the given endblock hash to rosetta transaction hash + EndBlockTxHash(blockHash []byte) string + // Amounts converts sdk.Coins to rosetta.Amounts + Amounts(ownedCoins []sdk.Coin, availableCoins sdk.Coins) []*rosettatypes.Amount + // Ops converts an sdk.Msg to rosetta operations + Ops(status string, msg sdk.Msg) ([]*rosettatypes.Operation, error) + // OpsAndSigners takes raw transaction bytes and returns rosetta operations and the expected signers + OpsAndSigners(txBytes []byte) (ops []*rosettatypes.Operation, signers []*rosettatypes.AccountIdentifier, err error) + // Meta converts an sdk.Msg to rosetta metadata + Meta(msg sdk.Msg) (meta map[string]interface{}, err error) + // SignerData returns account signing data from a queried any account + SignerData(anyAccount *codectypes.Any) (*SignerData, error) + // SigningComponents returns rosetta's components required to build a signable transaction + SigningComponents(tx authsigning.Tx, metadata *ConstructionMetadata, rosPubKeys []*rosettatypes.PublicKey) (txBytes []byte, payloadsToSign []*rosettatypes.SigningPayload, err error) + // Tx converts a tendermint transaction and tx result if provided to a rosetta tx + Tx(rawTx octypes.Tx, txResult *abci.ResponseDeliverTx) (*rosettatypes.Transaction, error) + // TxIdentifiers converts a tendermint tx to transaction identifiers + TxIdentifiers(txs []octypes.Tx) []*rosettatypes.TransactionIdentifier + // BalanceOps converts events to balance operations + BalanceOps(status string, events []abci.Event) []*rosettatypes.Operation + // SyncStatus converts a tendermint status to sync status + SyncStatus(status *ostcoretypes.ResultStatus) *rosettatypes.SyncStatus + // Peers converts tendermint peers to rosetta + Peers(peers []ostcoretypes.Peer) []*rosettatypes.Peer +} + +// ToSDKConverter is an interface that exposes +// all the functions used to convert rosetta types +// to tendermint and sdk types +type ToSDKConverter interface { + // UnsignedTx converts rosetta operations to an unsigned cosmos sdk transactions + UnsignedTx(ops []*rosettatypes.Operation) (tx authsigning.Tx, err error) + // SignedTx adds the provided signatures after decoding the unsigned transaction raw bytes + // and returns the signed tx bytes + SignedTx(txBytes []byte, signatures []*rosettatypes.Signature) (signedTxBytes []byte, err error) + // Msg converts metadata to an sdk message + Msg(meta map[string]interface{}, msg sdk.Msg) (err error) + // HashToTxType returns the transaction type (end block, begin block or deliver tx) + // and the real hash to query in order to get information + HashToTxType(hashBytes []byte) (txType TransactionType, realHash []byte) + // PubKey attempts to convert a rosetta public key to cosmos sdk one + PubKey(pk *rosettatypes.PublicKey) (cryptotypes.PubKey, error) +} + +type converter struct { + newTxBuilder func() sdkclient.TxBuilder + txBuilderFromTx func(tx sdk.Tx) (sdkclient.TxBuilder, error) + txDecode sdk.TxDecoder + txEncode sdk.TxEncoder + bytesToSign func(tx authsigning.Tx, signerData authsigning.SignerData) (b []byte, err error) + ir codectypes.InterfaceRegistry + cdc *codec.ProtoCodec +} + +func NewConverter(cdc *codec.ProtoCodec, ir codectypes.InterfaceRegistry, cfg sdkclient.TxConfig) Converter { + return converter{ + newTxBuilder: cfg.NewTxBuilder, + txBuilderFromTx: cfg.WrapTxBuilder, + txDecode: cfg.TxDecoder(), + txEncode: cfg.TxEncoder(), + bytesToSign: func(tx authsigning.Tx, signerData authsigning.SignerData) (b []byte, err error) { + bytesToSign, err := cfg.SignModeHandler().GetSignBytes(signing.SignMode_SIGN_MODE_LEGACY_AMINO_JSON, signerData, tx) + if err != nil { + return nil, err + } + + return crypto.Sha256(bytesToSign), nil + }, + ir: ir, + cdc: cdc, + } +} + +func (c converter) ToSDK() ToSDKConverter { + return c +} + +func (c converter) ToRosetta() ToRosettaConverter { + return c +} + +// OpsToUnsignedTx returns all the sdk.Msgs given the operations +func (c converter) UnsignedTx(ops []*rosettatypes.Operation) (tx authsigning.Tx, err error) { + builder := c.newTxBuilder() + + var msgs []sdk.Msg + + for i := 0; i < len(ops); i++ { + op := ops[i] + + protoMessage, err := c.ir.Resolve(op.Type) + if err != nil { + return nil, crgerrs.WrapError(crgerrs.ErrBadArgument, "operation not found: "+op.Type) + } + + msg, ok := protoMessage.(sdk.Msg) + if !ok { + return nil, crgerrs.WrapError(crgerrs.ErrBadArgument, "operation is not a valid supported sdk.Msg: "+op.Type) + } + + err = c.Msg(op.Metadata, msg) + if err != nil { + return nil, crgerrs.WrapError(crgerrs.ErrCodec, err.Error()) + } + + // verify message correctness + if err = msg.ValidateBasic(); err != nil { + return nil, crgerrs.WrapError( + crgerrs.ErrBadArgument, + fmt.Sprintf("validation of operation at index %d failed: %s", op.OperationIdentifier.Index, err), + ) + } + signers := msg.GetSigners() + // check if there are enough signers + if len(signers) == 0 { + return nil, crgerrs.WrapError(crgerrs.ErrBadArgument, fmt.Sprintf("operation at index %d got no signers", op.OperationIdentifier.Index)) + } + // append the msg + msgs = append(msgs, msg) + // if there's only one signer then simply continue + if len(signers) == 1 { + continue + } + // after we have got the msg, we need to verify if the message has multiple signers + // if it has got multiple signers, then we need to fetch all the related operations + // which involve the other signers of the msg, we expect to find them in order + // so if the msg is named "v1.test.Send" and it expects 3 signers, the next 3 operations + // must be with the same name "v1.test.Send" and contain the other signers + // then we can just skip their processing + for j := 0; j < len(signers)-1; j++ { + skipOp := ops[i+j] // get the next index + // verify that the operation is equal to the new one + if skipOp.Type != op.Type { + return nil, crgerrs.WrapError( + crgerrs.ErrBadArgument, + fmt.Sprintf("operation at index %d should have had type %s got: %s", i+j, op.Type, skipOp.Type), + ) + } + + if !reflect.DeepEqual(op.Metadata, skipOp.Metadata) { + return nil, crgerrs.WrapError( + crgerrs.ErrBadArgument, + fmt.Sprintf("operation at index %d should have had metadata equal to %#v, got: %#v", i+j, op.Metadata, skipOp.Metadata)) + } + + i++ // increase so we skip it + } + } + + if err := builder.SetMsgs(msgs...); err != nil { + return nil, crgerrs.WrapError(crgerrs.ErrBadArgument, err.Error()) + } + + return builder.GetTx(), nil + +} + +// Msg unmarshals the rosetta metadata to the given sdk.Msg +func (c converter) Msg(meta map[string]interface{}, msg sdk.Msg) error { + metaBytes, err := json.Marshal(meta) + if err != nil { + return err + } + return c.cdc.UnmarshalJSON(metaBytes, msg) +} + +func (c converter) Meta(msg sdk.Msg) (meta map[string]interface{}, err error) { + b, err := c.cdc.MarshalJSON(msg) + if err != nil { + return nil, crgerrs.WrapError(crgerrs.ErrCodec, err.Error()) + } + + err = json.Unmarshal(b, &meta) + if err != nil { + return nil, crgerrs.WrapError(crgerrs.ErrCodec, err.Error()) + } + + return +} + +// Ops will create an operation for each msg signer +// with the message proto name as type, and the raw fields +// as metadata +func (c converter) Ops(status string, msg sdk.Msg) ([]*rosettatypes.Operation, error) { + opName := sdk.MsgTypeURL(msg) + + meta, err := c.Meta(msg) + if err != nil { + return nil, err + } + + ops := make([]*rosettatypes.Operation, len(msg.GetSigners())) + for i, signer := range msg.GetSigners() { + op := &rosettatypes.Operation{ + Type: opName, + Status: &status, + Account: &rosettatypes.AccountIdentifier{Address: signer.String()}, + Metadata: meta, + } + + ops[i] = op + } + + return ops, nil +} + +// Tx converts a tendermint raw transaction and its result (if provided) to a rosetta transaction +func (c converter) Tx(rawTx octypes.Tx, txResult *abci.ResponseDeliverTx) (*rosettatypes.Transaction, error) { + // decode tx + tx, err := c.txDecode(rawTx) + if err != nil { + return nil, crgerrs.WrapError(crgerrs.ErrCodec, err.Error()) + } + // get initial status, as per sdk design, if one msg fails + // the whole TX will be considered failing, so we can't have + // 1 msg being success and 1 msg being reverted + status := StatusTxSuccess + switch txResult { + // if nil, we're probably checking an unconfirmed tx + // or trying to build a new transaction, so status + // is not put inside + case nil: + status = "" + // set the status + default: + if txResult.Code != abci.CodeTypeOK { + status = StatusTxReverted + } + } + // get operations from msgs + msgs := tx.GetMsgs() + var rawTxOps []*rosettatypes.Operation + + for _, msg := range msgs { + ops, err := c.Ops(status, msg) + if err != nil { + return nil, err + } + rawTxOps = append(rawTxOps, ops...) + } + + // now get balance events from response deliver tx + var balanceOps []*rosettatypes.Operation + // tx result might be nil, in case we're querying an unconfirmed tx from the mempool + if txResult != nil { + balanceOps = c.BalanceOps(status, txResult.Events) + } + + // now normalize indexes + totalOps := AddOperationIndexes(rawTxOps, balanceOps) + + return &rosettatypes.Transaction{ + TransactionIdentifier: &rosettatypes.TransactionIdentifier{Hash: fmt.Sprintf("%X", rawTx.Hash())}, + Operations: totalOps, + }, nil +} + +func (c converter) BalanceOps(status string, events []abci.Event) []*rosettatypes.Operation { + var ops []*rosettatypes.Operation + + for _, e := range events { + balanceOps, ok := sdkEventToBalanceOperations(status, e) + if !ok { + continue + } + ops = append(ops, balanceOps...) + } + + return ops +} + +// sdkEventToBalanceOperations converts an event to a rosetta balance operation +// it will panic if the event is malformed because it might mean the sdk spec +// has changed and rosetta needs to reflect those changes too. +// The balance operations are multiple, one for each denom. +func sdkEventToBalanceOperations(status string, event abci.Event) (operations []*rosettatypes.Operation, isBalanceEvent bool) { + + var ( + accountIdentifier string + coinChange sdk.Coins + isSub bool + ) + + switch event.Type { + default: + return nil, false + case banktypes.EventTypeCoinSpent: + spender := sdk.BytesToAccAddress(event.Attributes[0].Value) + err := sdk.ValidateAccAddress(spender.String()) + if err != nil { + panic(err) + } + coins, err := sdk.ParseCoinsNormalized((string)(event.Attributes[1].Value)) + if err != nil { + panic(err) + } + + isSub = true + coinChange = coins + accountIdentifier = spender.String() + + case banktypes.EventTypeCoinReceived: + receiver := sdk.BytesToAccAddress(event.Attributes[0].Value) + err := sdk.ValidateAccAddress(receiver.String()) + if err != nil { + panic(err) + } + coins, err := sdk.ParseCoinsNormalized((string)(event.Attributes[1].Value)) + if err != nil { + panic(err) + } + + isSub = false + coinChange = coins + accountIdentifier = receiver.String() + + // rosetta does not have the concept of burning coins, so we need to mock + // the burn as a send to an address that cannot be resolved to anything + case banktypes.EventTypeCoinBurn: + coins, err := sdk.ParseCoinsNormalized((string)(event.Attributes[1].Value)) + if err != nil { + panic(err) + } + + coinChange = coins + accountIdentifier = BurnerAddressIdentifier + } + + operations = make([]*rosettatypes.Operation, len(coinChange)) + + for i, coin := range coinChange { + + value := coin.Amount.String() + // in case the event is a subtract balance one the rewrite value with + // the negative coin identifier + if isSub { + value = "-" + value + } + + op := &rosettatypes.Operation{ + Type: event.Type, + Status: &status, + Account: &rosettatypes.AccountIdentifier{Address: accountIdentifier}, + Amount: &rosettatypes.Amount{ + Value: value, + Currency: &rosettatypes.Currency{ + Symbol: coin.Denom, + Decimals: 0, + }, + }, + } + + operations[i] = op + } + return operations, true +} + +// Amounts converts []sdk.Coin to rosetta amounts +func (c converter) Amounts(ownedCoins []sdk.Coin, availableCoins sdk.Coins) []*rosettatypes.Amount { + amounts := make([]*rosettatypes.Amount, len(availableCoins)) + ownedCoinsMap := make(map[string]sdk.Int, len(availableCoins)) + + for _, ownedCoin := range ownedCoins { + ownedCoinsMap[ownedCoin.Denom] = ownedCoin.Amount + } + + for i, coin := range availableCoins { + value, owned := ownedCoinsMap[coin.Denom] + if !owned { + amounts[i] = &rosettatypes.Amount{ + Value: sdk.NewInt(0).String(), + Currency: &rosettatypes.Currency{ + Symbol: coin.Denom, + }, + } + continue + } + amounts[i] = &rosettatypes.Amount{ + Value: value.String(), + Currency: &rosettatypes.Currency{ + Symbol: coin.Denom, + }, + } + } + + return amounts +} + +// AddOperationIndexes adds the indexes to operations adhering to specific rules: +// operations related to messages will be always before than the balance ones +func AddOperationIndexes(msgOps []*rosettatypes.Operation, balanceOps []*rosettatypes.Operation) (finalOps []*rosettatypes.Operation) { + lenMsgOps := len(msgOps) + lenBalanceOps := len(balanceOps) + finalOps = make([]*rosettatypes.Operation, 0, lenMsgOps+lenBalanceOps) + + var currentIndex int64 + // add indexes to msg ops + for _, op := range msgOps { + op.OperationIdentifier = &rosettatypes.OperationIdentifier{ + Index: currentIndex, + } + + finalOps = append(finalOps, op) + currentIndex++ + } + + // add indexes to balance ops + for _, op := range balanceOps { + op.OperationIdentifier = &rosettatypes.OperationIdentifier{ + Index: currentIndex, + } + + finalOps = append(finalOps, op) + currentIndex++ + } + + return finalOps +} + +// EndBlockTxHash produces a mock endblock hash that rosetta can query +// for endblock operations, it also serves the purpose of representing +// part of the state changes happening at endblock level (balance ones) +func (c converter) EndBlockTxHash(hash []byte) string { + final := append([]byte{EndBlockHashStart}, hash...) + return fmt.Sprintf("%X", final) +} + +// BeginBlockTxHash produces a mock beginblock hash that rosetta can query +// for beginblock operations, it also serves the purpose of representing +// part of the state changes happening at beginblock level (balance ones) +func (c converter) BeginBlockTxHash(hash []byte) string { + final := append([]byte{BeginBlockHashStart}, hash...) + return fmt.Sprintf("%X", final) +} + +// HashToTxType takes the provided hash bytes from rosetta and discerns if they are +// a deliver tx type or endblock/begin block hash, returning the real hash afterwards +func (c converter) HashToTxType(hashBytes []byte) (txType TransactionType, realHash []byte) { + switch len(hashBytes) { + case DeliverTxSize: + return DeliverTxTx, hashBytes + + case BeginEndBlockTxSize: + switch hashBytes[0] { + case BeginBlockHashStart: + return BeginBlockTx, hashBytes[1:] + case EndBlockHashStart: + return EndBlockTx, hashBytes[1:] + default: + return UnrecognizedTx, nil + } + + default: + return UnrecognizedTx, nil + } +} + +// StatusToSyncStatus converts a tendermint status to rosetta sync status +func (c converter) SyncStatus(status *ostcoretypes.ResultStatus) *rosettatypes.SyncStatus { + // determine sync status + var stage = StatusPeerSynced + if status.SyncInfo.CatchingUp { + stage = StatusPeerSyncing + } + + return &rosettatypes.SyncStatus{ + CurrentIndex: &status.SyncInfo.LatestBlockHeight, + TargetIndex: nil, // sync info does not allow us to get target height + Stage: &stage, + } +} + +// TxIdentifiers converts a tendermint raw transactions into an array of rosetta tx identifiers +func (c converter) TxIdentifiers(txs []octypes.Tx) []*rosettatypes.TransactionIdentifier { + converted := make([]*rosettatypes.TransactionIdentifier, len(txs)) + for i, tx := range txs { + converted[i] = &rosettatypes.TransactionIdentifier{Hash: fmt.Sprintf("%X", tx.Hash())} + } + + return converted +} + +// tmResultBlockToRosettaBlockResponse converts a tendermint result block to block response +func (c converter) BlockResponse(block *ostcoretypes.ResultBlock) crgtypes.BlockResponse { + var parentBlock *rosettatypes.BlockIdentifier + + switch block.Block.Height { + case 1: + parentBlock = &rosettatypes.BlockIdentifier{ + Index: 1, + Hash: fmt.Sprintf("%X", block.BlockID.Hash.Bytes()), + } + default: + parentBlock = &rosettatypes.BlockIdentifier{ + Index: block.Block.Height - 1, + Hash: fmt.Sprintf("%X", block.Block.LastBlockID.Hash.Bytes()), + } + } + return crgtypes.BlockResponse{ + Block: &rosettatypes.BlockIdentifier{ + Index: block.Block.Height, + Hash: block.Block.Hash().String(), + }, + ParentBlock: parentBlock, + MillisecondTimestamp: timeToMilliseconds(block.Block.Time), + TxCount: int64(len(block.Block.Txs)), + } +} + +// Peers converts tm peers to rosetta peers +func (c converter) Peers(peers []ostcoretypes.Peer) []*rosettatypes.Peer { + converted := make([]*rosettatypes.Peer, len(peers)) + + for i, peer := range peers { + converted[i] = &rosettatypes.Peer{ + PeerID: peer.NodeInfo.Moniker, + Metadata: map[string]interface{}{ + "addr": peer.NodeInfo.ListenAddr, + }, + } + } + + return converted +} + +// OpsAndSigners takes transactions bytes and returns the operation, is signed is true it will return +// the account identifiers which have signed the transaction +func (c converter) OpsAndSigners(txBytes []byte) (ops []*rosettatypes.Operation, signers []*rosettatypes.AccountIdentifier, err error) { + + rosTx, err := c.ToRosetta().Tx(txBytes, nil) + if err != nil { + return nil, nil, err + } + ops = rosTx.Operations + + // get the signers + sdkTx, err := c.txDecode(txBytes) + if err != nil { + return nil, nil, crgerrs.WrapError(crgerrs.ErrCodec, err.Error()) + } + + txBuilder, err := c.txBuilderFromTx(sdkTx) + if err != nil { + return nil, nil, crgerrs.WrapError(crgerrs.ErrCodec, err.Error()) + } + + for _, signer := range txBuilder.GetTx().GetSigners() { + signers = append(signers, &rosettatypes.AccountIdentifier{ + Address: signer.String(), + }) + } + + return +} + +func (c converter) SignedTx(txBytes []byte, signatures []*rosettatypes.Signature) (signedTxBytes []byte, err error) { + rawTx, err := c.txDecode(txBytes) + if err != nil { + return nil, err + } + + txBuilder, err := c.txBuilderFromTx(rawTx) + if err != nil { + return nil, err + } + + notSignedSigs, err := txBuilder.GetTx().GetSignaturesV2() // + if err != nil { + return nil, crgerrs.WrapError(crgerrs.ErrCodec, err.Error()) + } + + if len(notSignedSigs) != len(signatures) { + return nil, crgerrs.WrapError( + crgerrs.ErrInvalidTransaction, + fmt.Sprintf("expected transaction to have signers data matching the provided signatures: %d <-> %d", len(notSignedSigs), len(signatures))) + } + + signedSigs := make([]signing.SignatureV2, len(notSignedSigs)) + for i, signature := range signatures { + // TODO(fdymylja): here we should check that the public key matches... + signedSigs[i] = signing.SignatureV2{ + PubKey: notSignedSigs[i].PubKey, + Data: &signing.SingleSignatureData{ + SignMode: signing.SignMode_SIGN_MODE_LEGACY_AMINO_JSON, + Signature: signature.Bytes, + }, + Sequence: notSignedSigs[i].Sequence, + } + } + + if err = txBuilder.SetSignatures(signedSigs...); err != nil { + return nil, err + } + + txBytes, err = c.txEncode(txBuilder.GetTx()) + if err != nil { + return nil, err + } + + return txBytes, nil +} + +func (c converter) PubKey(pubKey *rosettatypes.PublicKey) (cryptotypes.PubKey, error) { + if pubKey.CurveType != "secp256k1" { + return nil, crgerrs.WrapError(crgerrs.ErrUnsupportedCurve, "only secp256k1 supported") + } + + cmp, err := btcec.ParsePubKey(pubKey.Bytes, btcec.S256()) + if err != nil { + return nil, crgerrs.WrapError(crgerrs.ErrBadArgument, err.Error()) + } + + compressedPublicKey := make([]byte, secp256k1.PubKeySize) + copy(compressedPublicKey, cmp.SerializeCompressed()) + + pk := &secp256k1.PubKey{Key: compressedPublicKey} + + return pk, nil +} + +// SigningComponents takes a sdk tx and construction metadata and returns signable components +func (c converter) SigningComponents(tx authsigning.Tx, metadata *ConstructionMetadata, rosPubKeys []*rosettatypes.PublicKey) (txBytes []byte, payloadsToSign []*rosettatypes.SigningPayload, err error) { + + // verify metadata correctness + feeAmount, err := sdk.ParseCoinsNormalized(metadata.GasPrice) + if err != nil { + return nil, nil, crgerrs.WrapError(crgerrs.ErrBadArgument, err.Error()) + } + + signers := tx.GetSigners() + // assert the signers data provided in options are the same as the expected signing accounts + // and that the number of rosetta provided public keys equals the one of the signers + if len(metadata.SignersData) != len(signers) || len(signers) != len(rosPubKeys) { + return nil, nil, crgerrs.WrapError(crgerrs.ErrBadArgument, "signers data and account identifiers mismatch") + } + + // add transaction metadata + builder, err := c.txBuilderFromTx(tx) + if err != nil { + return nil, nil, crgerrs.WrapError(crgerrs.ErrCodec, err.Error()) + } + builder.SetFeeAmount(feeAmount) + builder.SetGasLimit(metadata.GasLimit) + builder.SetMemo(metadata.Memo) + + // build signatures + partialSignatures := make([]signing.SignatureV2, len(signers)) + payloadsToSign = make([]*rosettatypes.SigningPayload, len(signers)) + + // pub key ordering matters, in a future release this check might be relaxed + for i, signer := range signers { + // assert that the provided public keys are correctly ordered + // by checking if the signer at index i matches the pubkey at index + pubKey, err := c.ToSDK().PubKey(rosPubKeys[0]) + if err != nil { + return nil, nil, err + } + if !bytes.Equal(sdk.BytesToAccAddress(pubKey.Address()).Bytes(), signer.Bytes()) { + return nil, nil, crgerrs.WrapError( + crgerrs.ErrBadArgument, + fmt.Sprintf("public key at index %d does not match the expected transaction signer: %X <-> %X", i, rosPubKeys[i].Bytes, signer.Bytes()), + ) + } + + // set the signer data + signerData := authsigning.SignerData{ + ChainID: metadata.ChainID, + AccountNumber: metadata.SignersData[i].AccountNumber, + Sequence: metadata.SignersData[i].Sequence, + } + + // get signature bytes + signBytes, err := c.bytesToSign(tx, signerData) + if err != nil { + return nil, nil, crgerrs.WrapError(crgerrs.ErrUnknown, fmt.Sprintf("unable to sign tx: %s", err.Error())) + } + + // set payload + payloadsToSign[i] = &rosettatypes.SigningPayload{ + AccountIdentifier: &rosettatypes.AccountIdentifier{Address: signer.String()}, + Bytes: signBytes, + SignatureType: rosettatypes.Ecdsa, + } + + // set partial signature + partialSignatures[i] = signing.SignatureV2{ + PubKey: pubKey, + Data: &signing.SingleSignatureData{}, // needs to be set to empty otherwise the codec will cry + Sequence: metadata.SignersData[i].Sequence, + } + + } + + // now we set the partial signatures in the tx + // because we will need to decode the sequence + // information of each account in a stateless way + err = builder.SetSignatures(partialSignatures...) + if err != nil { + return nil, nil, crgerrs.WrapError(crgerrs.ErrCodec, err.Error()) + } + + // finally encode the tx + txBytes, err = c.txEncode(builder.GetTx()) + if err != nil { + return nil, nil, crgerrs.WrapError(crgerrs.ErrCodec, err.Error()) + } + + return txBytes, payloadsToSign, nil +} + +// SignerData converts the given any account to signer data +func (c converter) SignerData(anyAccount *codectypes.Any) (*SignerData, error) { + var acc auth.AccountI + err := c.ir.UnpackAny(anyAccount, &acc) + if err != nil { + return nil, crgerrs.WrapError(crgerrs.ErrCodec, err.Error()) + } + + return &SignerData{ + AccountNumber: acc.GetAccountNumber(), + Sequence: acc.GetSequence(), + }, nil +} diff --git a/server/rosetta/converter_test.go b/server/rosetta/converter_test.go new file mode 100644 index 0000000000..4d2ef77fd8 --- /dev/null +++ b/server/rosetta/converter_test.go @@ -0,0 +1,345 @@ +package rosetta_test + +import ( + "encoding/hex" + "encoding/json" + "testing" + + rosettatypes "github.com/coinbase/rosetta-sdk-go/types" + "github.com/stretchr/testify/suite" + + abci "github.com/line/ostracon/abci/types" + + "github.com/line/lbm-sdk/client" + "github.com/line/lbm-sdk/codec" + codectypes "github.com/line/lbm-sdk/codec/types" + "github.com/line/lbm-sdk/server/rosetta" + crgerrs "github.com/line/lbm-sdk/server/rosetta/lib/errors" + sdk "github.com/line/lbm-sdk/types" + authsigning "github.com/line/lbm-sdk/x/auth/signing" + authtx "github.com/line/lbm-sdk/x/auth/tx" + bank "github.com/line/lbm-sdk/x/bank/types" +) + +type ConverterTestSuite struct { + suite.Suite + + c rosetta.Converter + unsignedTxBytes []byte + unsignedTx authsigning.Tx + + ir codectypes.InterfaceRegistry + cdc *codec.ProtoCodec + txConf client.TxConfig +} + +func (s *ConverterTestSuite) SetupTest() { + // create an unsigned tx + const unsignedTxHex = "0a82010aff000a142f6c626d2e62616e6b2e76312e4d736753656e6412670a2b6c696e6b3134376b6c68377468356a6b6a793361616a736a3272717668747668396d6664657973777a3071122b6c696e6b316d6e7670386c786b616679346c787777617175356561653764787630647a36687767797436331a0b0a057374616b6512023136125d0a490a430a1c2f6c626d2e63727970746f2e736563703235366b312e5075624b657912230a21034c92046950c876f4a5cb6c7797d6eeb9ef80d67ced4d45fb62b1e859240ba9ad12020a0012100a0a0a057374616b651201311090a10f1a00" + unsignedTxBytes, err := hex.DecodeString(unsignedTxHex) + s.Require().NoError(err) + s.unsignedTxBytes = unsignedTxBytes + // instantiate converter + cdc, ir := rosetta.MakeCodec() + txConfig := authtx.NewTxConfig(cdc, authtx.DefaultSignModes) + s.c = rosetta.NewConverter(cdc, ir, txConfig) + // add utils + s.ir = ir + s.cdc = cdc + s.txConf = txConfig + // add authsigning tx + sdkTx, err := txConfig.TxDecoder()(unsignedTxBytes) + s.Require().NoError(err) + builder, err := txConfig.WrapTxBuilder(sdkTx) + s.Require().NoError(err) + + s.unsignedTx = builder.GetTx() +} + +func (s *ConverterTestSuite) TestFromRosettaOpsToTxSuccess() { + addr1 := sdk.BytesToAccAddress([]byte("address1")) + addr2 := sdk.BytesToAccAddress([]byte("address2")) + + msg1 := &bank.MsgSend{ + FromAddress: addr1.String(), + ToAddress: addr2.String(), + Amount: sdk.NewCoins(sdk.NewInt64Coin("test", 10)), + } + + msg2 := &bank.MsgSend{ + FromAddress: addr2.String(), + ToAddress: addr1.String(), + Amount: sdk.NewCoins(sdk.NewInt64Coin("utxo", 10)), + } + + ops, err := s.c.ToRosetta().Ops("", msg1) + s.Require().NoError(err) + + ops2, err := s.c.ToRosetta().Ops("", msg2) + s.Require().NoError(err) + + ops = append(ops, ops2...) + + tx, err := s.c.ToSDK().UnsignedTx(ops) + s.Require().NoError(err) + + getMsgs := tx.GetMsgs() + + s.Require().Equal(2, len(getMsgs)) + + s.Require().Equal(getMsgs[0], msg1) + s.Require().Equal(getMsgs[1], msg2) + +} + +func (s *ConverterTestSuite) TestFromRosettaOpsToTxErrors() { + s.Run("unrecognized op", func() { + op := &rosettatypes.Operation{ + Type: "non-existent", + } + + _, err := s.c.ToSDK().UnsignedTx([]*rosettatypes.Operation{op}) + + s.Require().ErrorIs(err, crgerrs.ErrBadArgument) + }) + + s.Run("codec type but not sdk.Msg", func() { + op := &rosettatypes.Operation{ + Type: "lbm.crypto.ed25519.PubKey", + } + + _, err := s.c.ToSDK().UnsignedTx([]*rosettatypes.Operation{op}) + + s.Require().ErrorIs(err, crgerrs.ErrBadArgument) + + }) + +} + +func (s *ConverterTestSuite) TestMsgToMetaMetaToMsg() { + msg := &bank.MsgSend{ + FromAddress: "addr1", + ToAddress: "addr2", + Amount: sdk.NewCoins(sdk.NewInt64Coin("test", 10)), + } + msg.Route() + + meta, err := s.c.ToRosetta().Meta(msg) + s.Require().NoError(err) + + copyMsg := new(bank.MsgSend) + err = s.c.ToSDK().Msg(meta, copyMsg) + s.Require().NoError(err) + s.Require().Equal(msg, copyMsg) +} + +func (s *ConverterTestSuite) TestSignedTx() { + + s.Run("success", func() { + const payloadsJSON = `[{"hex_bytes":"82ccce81a3e4a7272249f0e25c3037a316ee2acce76eb0c25db00ef6634a4d57303b2420edfdb4c9a635ad8851fe5c7a9379b7bc2baadc7d74f7e76ac97459b5","signing_payload":{"address":"link147klh7th5jkjy3aajsj2rqvhtvh9mfde37wq5g","hex_bytes":"ed574d84b095250280de38bf8c254e4a1f8755e5bd300b1f6ca2671688136ecc","account_identifier":{"address":"link147klh7th5jkjy3aajsj2rqvhtvh9mfde37wq5g"},"signature_type":"ecdsa"},"public_key":{"hex_bytes":"034c92046950c876f4a5cb6c7797d6eeb9ef80d67ced4d45fb62b1e859240ba9ad","curve_type":"secp256k1"},"signature_type":"ecdsa"}]` + const expectedSignedTxHex = "0a82010aff000a142f6c626d2e62616e6b2e76312e4d736753656e6412670a2b6c696e6b3134376b6c68377468356a6b6a793361616a736a3272717668747668396d6664657973777a3071122b6c696e6b316d6e7670386c786b616679346c787777617175356561653764787630647a36687767797436331a0b0a057374616b6512023136125f0a4b0a430a1c2f6c626d2e63727970746f2e736563703235366b312e5075624b657912230a21034c92046950c876f4a5cb6c7797d6eeb9ef80d67ced4d45fb62b1e859240ba9ad12040a02087f12100a0a0a057374616b651201311090a10f1a4082ccce81a3e4a7272249f0e25c3037a316ee2acce76eb0c25db00ef6634a4d57303b2420edfdb4c9a635ad8851fe5c7a9379b7bc2baadc7d74f7e76ac97459b5" + + var payloads []*rosettatypes.Signature + s.Require().NoError(json.Unmarshal([]byte(payloadsJSON), &payloads)) + + signedTx, err := s.c.ToSDK().SignedTx(s.unsignedTxBytes, payloads) + s.Require().NoError(err) + + signedTxHex := hex.EncodeToString(signedTx) + + s.Require().Equal(signedTxHex, expectedSignedTxHex) + }) + + s.Run("signers data and signing payloads mismatch", func() { + _, err := s.c.ToSDK().SignedTx(s.unsignedTxBytes, nil) + s.Require().ErrorIs(err, crgerrs.ErrInvalidTransaction) + }) +} + +func (s *ConverterTestSuite) TestOpsAndSigners() { + s.Run("success", func() { + addr1 := sdk.AccAddress("address1").String() + addr2 := sdk.AccAddress("address2").String() + + msg := &bank.MsgSend{ + FromAddress: addr1, + ToAddress: addr2, + Amount: sdk.NewCoins(sdk.NewInt64Coin("test", 10)), + } + + builder := s.txConf.NewTxBuilder() + s.Require().NoError(builder.SetMsgs(msg)) + + sdkTx := builder.GetTx() + txBytes, err := s.txConf.TxEncoder()(sdkTx) + s.Require().NoError(err) + + ops, signers, err := s.c.ToRosetta().OpsAndSigners(txBytes) + s.Require().NoError(err) + + s.Require().Equal(len(ops), len(sdkTx.GetMsgs())*len(sdkTx.GetSigners()), "operation number mismatch") + + s.Require().Equal(len(signers), len(sdkTx.GetSigners()), "signers number mismatch") + }) +} + +func (s *ConverterTestSuite) TestBeginEndBlockAndHashToTxType() { + const deliverTxHex = "5229A67AA008B5C5F1A0AEA77D4DEBE146297A30AAEF01777AF10FAD62DD36AB" + + deliverTxBytes, err := hex.DecodeString(deliverTxHex) + s.Require().NoError(err) + + endBlockTxHex := s.c.ToRosetta().EndBlockTxHash(deliverTxBytes) + beginBlockTxHex := s.c.ToRosetta().BeginBlockTxHash(deliverTxBytes) + + txType, hash := s.c.ToSDK().HashToTxType(deliverTxBytes) + + s.Require().Equal(rosetta.DeliverTxTx, txType) + s.Require().Equal(deliverTxBytes, hash, "deliver tx hash should not change") + + endBlockTxBytes, err := hex.DecodeString(endBlockTxHex) + s.Require().NoError(err) + + txType, hash = s.c.ToSDK().HashToTxType(endBlockTxBytes) + + s.Require().Equal(rosetta.EndBlockTx, txType) + s.Require().Equal(deliverTxBytes, hash, "end block tx hash should be equal to a block hash") + + beginBlockTxBytes, err := hex.DecodeString(beginBlockTxHex) + s.Require().NoError(err) + + txType, hash = s.c.ToSDK().HashToTxType(beginBlockTxBytes) + + s.Require().Equal(rosetta.BeginBlockTx, txType) + s.Require().Equal(deliverTxBytes, hash, "begin block tx hash should be equal to a block hash") + + txType, hash = s.c.ToSDK().HashToTxType([]byte("invalid")) + + s.Require().Equal(rosetta.UnrecognizedTx, txType) + s.Require().Nil(hash) + + txType, hash = s.c.ToSDK().HashToTxType(append([]byte{0x3}, deliverTxBytes...)) + s.Require().Equal(rosetta.UnrecognizedTx, txType) + s.Require().Nil(hash) +} + +func (s *ConverterTestSuite) TestSigningComponents() { + s.Run("invalid metadata coins", func() { + _, _, err := s.c.ToRosetta().SigningComponents(nil, &rosetta.ConstructionMetadata{GasPrice: "invalid"}, nil) + s.Require().ErrorIs(err, crgerrs.ErrBadArgument) + }) + + s.Run("length signers data does not match signers", func() { + _, _, err := s.c.ToRosetta().SigningComponents(s.unsignedTx, &rosetta.ConstructionMetadata{GasPrice: "10stake"}, nil) + s.Require().ErrorIs(err, crgerrs.ErrBadArgument) + }) + + s.Run("length pub keys does not match signers", func() { + _, _, err := s.c.ToRosetta().SigningComponents( + s.unsignedTx, + &rosetta.ConstructionMetadata{GasPrice: "10stake", SignersData: []*rosetta.SignerData{ + { + AccountNumber: 0, + Sequence: 0, + }, + }}, + nil) + s.Require().ErrorIs(err, crgerrs.ErrBadArgument) + }) + + s.Run("ros pub key is valid but not the one we expect", func() { + validButUnexpected, err := hex.DecodeString("030da9096a40eb1d6c25f1e26e9cbf8941fc84b8f4dc509c8df5e62a29ab8f2415") + s.Require().NoError(err) + + _, _, err = s.c.ToRosetta().SigningComponents( + s.unsignedTx, + &rosetta.ConstructionMetadata{GasPrice: "10stake", SignersData: []*rosetta.SignerData{ + { + AccountNumber: 0, + Sequence: 0, + }, + }}, + []*rosettatypes.PublicKey{ + { + Bytes: validButUnexpected, + CurveType: rosettatypes.Secp256k1, + }, + }) + s.Require().ErrorIs(err, crgerrs.ErrBadArgument) + }) + + s.Run("success", func() { + expectedPubKey, err := hex.DecodeString("034c92046950c876f4a5cb6c7797d6eeb9ef80d67ced4d45fb62b1e859240ba9ad") + s.Require().NoError(err) + + _, _, err = s.c.ToRosetta().SigningComponents( + s.unsignedTx, + &rosetta.ConstructionMetadata{GasPrice: "10stake", SignersData: []*rosetta.SignerData{ + { + AccountNumber: 0, + Sequence: 0, + }, + }}, + []*rosettatypes.PublicKey{ + { + Bytes: expectedPubKey, + CurveType: rosettatypes.Secp256k1, + }, + }) + s.Require().NoError(err) + }) + +} + +func (s *ConverterTestSuite) TestBalanceOps() { + s.Run("not a balance op", func() { + notBalanceOp := abci.Event{ + Type: "not-a-balance-op", + } + + ops := s.c.ToRosetta().BalanceOps("", []abci.Event{notBalanceOp}) + s.Len(ops, 0, "expected no balance ops") + }) + + s.Run("multiple balance ops from 2 multicoins event", func() { + subBalanceOp := bank.NewCoinSpentEvent( + sdk.AccAddress("test"), + sdk.NewCoins(sdk.NewInt64Coin("test", 10), sdk.NewInt64Coin("utxo", 10)), + ) + + addBalanceOp := bank.NewCoinReceivedEvent( + sdk.AccAddress("test"), + sdk.NewCoins(sdk.NewInt64Coin("test", 10), sdk.NewInt64Coin("utxo", 10)), + ) + + ops := s.c.ToRosetta().BalanceOps("", []abci.Event{(abci.Event)(subBalanceOp), (abci.Event)(addBalanceOp)}) + s.Len(ops, 4) + }) + + s.Run("spec broken", func() { + s.Require().Panics(func() { + specBrokenSub := abci.Event{ + Type: bank.EventTypeCoinSpent, + } + _ = s.c.ToRosetta().BalanceOps("", []abci.Event{specBrokenSub}) + }) + + s.Require().Panics(func() { + specBrokenSub := abci.Event{ + Type: bank.EventTypeCoinBurn, + } + _ = s.c.ToRosetta().BalanceOps("", []abci.Event{specBrokenSub}) + }) + + s.Require().Panics(func() { + specBrokenSub := abci.Event{ + Type: bank.EventTypeCoinReceived, + } + _ = s.c.ToRosetta().BalanceOps("", []abci.Event{specBrokenSub}) + }) + }) +} + +func TestConverterTestSuite(t *testing.T) { + suite.Run(t, new(ConverterTestSuite)) +} diff --git a/server/rosetta/lib/errors/errors.go b/server/rosetta/lib/errors/errors.go new file mode 100644 index 0000000000..f2e31b44af --- /dev/null +++ b/server/rosetta/lib/errors/errors.go @@ -0,0 +1,146 @@ +package errors + +// errors.go contains all the errors returned by the adapter implementation +// plus some extra utilities to parse those errors + +import ( + "fmt" + + grpccodes "google.golang.org/grpc/codes" + grpcstatus "google.golang.org/grpc/status" + + "github.com/coinbase/rosetta-sdk-go/types" +) + +// ListErrors lists all the registered errors +func ListErrors() []*types.Error { + return registry.list() +} + +// SealAndListErrors seals the registry and lists its errors +func SealAndListErrors() []*types.Error { + registry.seal() + return registry.list() +} + +// Error defines an error that can be converted to a Rosetta API error. +type Error struct { + rosErr *types.Error +} + +func (e *Error) Error() string { + if e.rosErr == nil { + return ErrUnknown.Error() + } + return fmt.Sprintf("rosetta: (%d) %s", e.rosErr.Code, e.rosErr.Message) +} + +// Is implements errors.Is for *Error, two errors are considered equal +// if their error codes are identical +func (e *Error) Is(err error) bool { + // assert it can be casted + rosErr, ok := err.(*Error) + if rosErr == nil || !ok { + return false + } + // check that both *Error's are correctly initialized to avoid dereference panics + if rosErr.rosErr == nil || e.rosErr == nil { + return false + } + // messages are equal if their error codes match + return rosErr.rosErr.Code == e.rosErr.Code +} + +// WrapError wraps the rosetta error with additional context +func WrapError(err *Error, msg string) *Error { + return &Error{rosErr: &types.Error{ + Code: err.rosErr.Code, + Message: err.rosErr.Message, + Description: err.rosErr.Description, + Retriable: err.rosErr.Retriable, + Details: map[string]interface{}{ + "info": msg, + }, + }} +} + +// ToRosetta attempts to converting an error into a rosetta +// error, if the error cannot be converted it will be parsed as unknown +func ToRosetta(err error) *types.Error { + // if it's null or not known + rosErr, ok := err.(*Error) + if rosErr == nil || !ok { + return ToRosetta(WrapError(ErrUnknown, ErrUnknown.Error())) + } + return rosErr.rosErr +} + +// FromGRPCToRosettaError converts a gRPC error to rosetta error +func FromGRPCToRosettaError(err error) *Error { + status, ok := grpcstatus.FromError(err) + if !ok { + return WrapError(ErrUnknown, err.Error()) + } + switch status.Code() { + case grpccodes.NotFound: + return WrapError(ErrNotFound, status.Message()) + case grpccodes.FailedPrecondition: + return WrapError(ErrBadArgument, status.Message()) + case grpccodes.InvalidArgument: + return WrapError(ErrBadArgument, status.Message()) + case grpccodes.Internal: + return WrapError(ErrInternal, status.Message()) + default: + return WrapError(ErrUnknown, status.Message()) + } +} + +func RegisterError(code int32, message string, retryable bool, description string) *Error { + e := &Error{rosErr: &types.Error{ + Code: code, + Message: message, + Description: &description, + Retriable: retryable, + Details: nil, + }} + registry.add(e) + return e +} + +// Default error list +var ( + // ErrUnknown defines an unknown error, if this is returned it means + // the library is ignoring an error + ErrUnknown = RegisterError(0, "unknown", false, "unknown error") + // ErrOffline is returned when there is an attempt to query an endpoint in offline mode + ErrOffline = RegisterError(1, "cannot query endpoint in offline mode", false, "returned when querying an online endpoint in offline mode") + // ErrNetworkNotSupported is returned when there is an attempt to query a network which is not supported + ErrNetworkNotSupported = RegisterError(2, "network is not supported", false, "returned when querying a non supported network") + // ErrCodec is returned when there's an error while marshalling or unmarshalling data + ErrCodec = RegisterError(3, "encode/decode error", true, "returned when there are errors encoding or decoding information to and from the node") + // ErrInvalidOperation is returned when the operation supplied to rosetta is not a valid one + ErrInvalidOperation = RegisterError(4, "invalid operation", false, "returned when the operation is not valid") + // ErrInvalidTransaction is returned when the provided hex bytes of a TX are not valid + ErrInvalidTransaction = RegisterError(5, "invalid transaction", false, "returned when the transaction is invalid") + // ErrInvalidAddress is returned when the byte of the address are bad + ErrInvalidAddress = RegisterError(7, "invalid address", false, "returned when the address is malformed") + // ErrInvalidPubkey is returned when the public key is invalid + ErrInvalidPubkey = RegisterError(8, "invalid pubkey", false, "returned when the public key is invalid") + // ErrInterpreting is returned when there are errors interpreting the data from the node, most likely related to breaking changes, version incompatibilities + ErrInterpreting = RegisterError(9, "error interpreting data from node", false, "returned when there are issues interpreting requests or response from node") + ErrInvalidMemo = RegisterError(11, "invalid memo", false, "returned when the memo is invalid") + // ErrBadArgument is returned when the request is malformed + ErrBadArgument = RegisterError(400, "bad argument", false, "request is malformed") + // ErrNotFound is returned when the required object was not found + // retry is set to true because something that is not found now + // might be found later, example: a TX + ErrNotFound = RegisterError(404, "not found", true, "returned when the node does not find what the client is asking for") + // ErrInternal is returned when the node is experiencing internal errors + ErrInternal = RegisterError(500, "internal error", false, "returned when the node experiences internal errors") + // ErrBadGateway is returned when there are problems interacting with the nodes + ErrBadGateway = RegisterError(502, "bad gateway", true, "return when the node is unreachable") + // ErrNotImplemented is returned when a method is not implemented yet + ErrNotImplemented = RegisterError(14, "not implemented", false, "returned when querying an endpoint which is not implemented") + // ErrUnsupportedCurve is returned when the curve specified is not supported + ErrUnsupportedCurve = RegisterError(15, "unsupported curve, expected secp256k1", false, "returned when using an unsupported crypto curve") +) diff --git a/server/rosetta/lib/errors/errors_test.go b/server/rosetta/lib/errors/errors_test.go new file mode 100644 index 0000000000..5502f09f7e --- /dev/null +++ b/server/rosetta/lib/errors/errors_test.go @@ -0,0 +1,68 @@ +package errors + +import ( + "github.com/stretchr/testify/assert" + "testing" +) + +func TestRegisterError(t *testing.T) { + var error *Error + // this is the number of errors registered by default in errors.go + registeredErrorsCount := 16 + assert.Equal(t, len(registry.list()), registeredErrorsCount) + assert.ElementsMatch(t, registry.list(), ListErrors()) + // add a new Error + error = RegisterError(69, "nice!", false, "nice!") + assert.NotNil(t, error) + // now we have a new error + registeredErrorsCount++ + assert.Equal(t, len(ListErrors()), registeredErrorsCount) + // re-register an error should not change anything + error = RegisterError(69, "nice!", false, "nice!") + assert.Equal(t, len(ListErrors()), registeredErrorsCount) + + // test sealing + assert.Equal(t, registry.sealed, false) + errors := SealAndListErrors() + assert.Equal(t, registry.sealed, true) + assert.Equal(t, len(errors), registeredErrorsCount) + // add a new error on a sealed registry + error = RegisterError(1024, "bytes", false, "bytes") + assert.NotNil(t, error) + +} + +func TestError_Error(t *testing.T) { + var error *Error + // nil cases + assert.False(t, ErrOffline.Is(error)) + error = &Error{} + assert.False(t, ErrOffline.Is(error)) + // wrong type + assert.False(t, ErrOffline.Is(&MyError{})) + // test with wrapping an error + error = WrapError(ErrOffline, "offline") + assert.True(t, ErrOffline.Is(error)) + + // test equality + assert.False(t, ErrOffline.Is(ErrBadGateway)) + assert.True(t, ErrBadGateway.Is(ErrBadGateway)) +} + +func TestToRosetta(t *testing.T) { + var error *Error + // nil case + assert.NotNil(t, ToRosetta(error)) + // wrong type + assert.NotNil(t, ToRosetta(&MyError{})) +} + +type MyError struct { +} + +func (e *MyError) Error() string { + return "" +} +func (e *MyError) Is(err error) bool { + return true +} diff --git a/server/rosetta/lib/errors/registry.go b/server/rosetta/lib/errors/registry.go new file mode 100644 index 0000000000..9cbafcacf7 --- /dev/null +++ b/server/rosetta/lib/errors/registry.go @@ -0,0 +1,48 @@ +package errors + +import ( + "fmt" + "os" + "sync" + + "github.com/coinbase/rosetta-sdk-go/types" +) + +type errorRegistry struct { + mu *sync.RWMutex + sealed bool + errors map[int32]*types.Error +} + +func (r *errorRegistry) add(err *Error) { + r.mu.Lock() + defer r.mu.Unlock() + if r.sealed { + _, _ = fmt.Fprintln(os.Stderr, "[ROSETTA] WARNING: attempts to register errors after seal will be ignored") + } + if _, ok := r.errors[err.rosErr.Code]; ok { + _, _ = fmt.Fprintln(os.Stderr, "[ROSETTA] WARNING: attempts to register an already registered error will be ignored, code: ", err.rosErr.Code) + } + r.errors[err.rosErr.Code] = err.rosErr +} + +func (r errorRegistry) list() []*types.Error { + r.mu.RLock() + defer r.mu.RUnlock() + rosErrs := make([]*types.Error, 0, len(registry.errors)) + for _, v := range r.errors { + rosErrs = append(rosErrs, v) + } + return rosErrs +} + +func (r *errorRegistry) seal() { + r.mu.Lock() + defer r.mu.Unlock() + r.sealed = true +} + +var registry = errorRegistry{ + mu: new(sync.RWMutex), + errors: make(map[int32]*types.Error), +} diff --git a/server/rosetta/lib/internal/service/construction.go b/server/rosetta/lib/internal/service/construction.go new file mode 100644 index 0000000000..a7683fd104 --- /dev/null +++ b/server/rosetta/lib/internal/service/construction.go @@ -0,0 +1,138 @@ +package service + +import ( + "context" + "crypto/sha256" + "encoding/hex" + "strings" + + "github.com/coinbase/rosetta-sdk-go/types" + + "github.com/line/lbm-sdk/server/rosetta/lib/errors" +) + +// ConstructionCombine Combine creates a network-specific transaction from an unsigned transaction +// and an array of provided signatures. The signed transaction returned from this method will be +// sent to the /construction/submit endpoint by the caller. +func (on OnlineNetwork) ConstructionCombine(ctx context.Context, request *types.ConstructionCombineRequest) (*types.ConstructionCombineResponse, *types.Error) { + txBytes, err := hex.DecodeString(request.UnsignedTransaction) + if err != nil { + return nil, errors.ToRosetta(err) + } + + signedTx, err := on.client.SignedTx(ctx, txBytes, request.Signatures) + if err != nil { + return nil, errors.ToRosetta(err) + } + + return &types.ConstructionCombineResponse{ + SignedTransaction: hex.EncodeToString(signedTx), + }, nil +} + +// ConstructionDerive Derive returns the AccountIdentifier associated with a public key. +func (on OnlineNetwork) ConstructionDerive(_ context.Context, request *types.ConstructionDeriveRequest) (*types.ConstructionDeriveResponse, *types.Error) { + account, err := on.client.AccountIdentifierFromPublicKey(request.PublicKey) + if err != nil { + return nil, errors.ToRosetta(err) + } + return &types.ConstructionDeriveResponse{ + AccountIdentifier: account, + Metadata: nil, + }, nil +} + +// ConstructionHash TransactionHash returns the network-specific transaction hash for a signed +// transaction. +func (on OnlineNetwork) ConstructionHash(ctx context.Context, request *types.ConstructionHashRequest) (*types.TransactionIdentifierResponse, *types.Error) { + bz, err := hex.DecodeString(request.SignedTransaction) + if err != nil { + return nil, errors.ToRosetta(errors.WrapError(errors.ErrInvalidTransaction, "error decoding tx")) + } + + hash := sha256.Sum256(bz) + bzHash := hash[:] + hashString := hex.EncodeToString(bzHash) + + return &types.TransactionIdentifierResponse{ + TransactionIdentifier: &types.TransactionIdentifier{ + Hash: strings.ToUpper(hashString), + }, + }, nil +} + +// ConstructionMetadata Get any information required to construct a transaction for a specific +// network (i.e. ChainID, Gas, Memo, ...). +func (on OnlineNetwork) ConstructionMetadata(ctx context.Context, request *types.ConstructionMetadataRequest) (*types.ConstructionMetadataResponse, *types.Error) { + metadata, err := on.client.ConstructionMetadataFromOptions(ctx, request.Options) + if err != nil { + return nil, errors.ToRosetta(err) + } + + return &types.ConstructionMetadataResponse{ + Metadata: metadata, + }, nil +} + +// ConstructionParse Parse is called on both unsigned and signed transactions to understand the +// intent of the formulated transaction. This is run as a sanity check before signing (after +// /construction/payloads) and before broadcast (after /construction/combine). +func (on OnlineNetwork) ConstructionParse(ctx context.Context, request *types.ConstructionParseRequest) (*types.ConstructionParseResponse, *types.Error) { + txBytes, err := hex.DecodeString(request.Transaction) + if err != nil { + err := errors.WrapError(errors.ErrInvalidTransaction, err.Error()) + return nil, errors.ToRosetta(err) + } + ops, signers, err := on.client.TxOperationsAndSignersAccountIdentifiers(request.Signed, txBytes) + if err != nil { + return nil, errors.ToRosetta(err) + } + return &types.ConstructionParseResponse{ + Operations: ops, + AccountIdentifierSigners: signers, + Metadata: nil, + }, nil + +} + +// ConstructionPayloads Payloads is called with an array of operations and the response from +// /construction/metadata. It returns an unsigned transaction blob and a collection of payloads that +// must be signed by particular AccountIdentifiers using a certain SignatureType. +func (on OnlineNetwork) ConstructionPayloads(ctx context.Context, request *types.ConstructionPayloadsRequest) (*types.ConstructionPayloadsResponse, *types.Error) { + payload, err := on.client.ConstructionPayload(ctx, request) + if err != nil { + return nil, errors.ToRosetta(err) + } + return payload, nil +} + +// ConstructionPreprocess Preprocess is called prior to /construction/payloads to construct a +// request for any metadata that is needed for transaction construction given (i.e. account nonce). +func (on OnlineNetwork) ConstructionPreprocess(ctx context.Context, request *types.ConstructionPreprocessRequest) (*types.ConstructionPreprocessResponse, *types.Error) { + options, err := on.client.PreprocessOperationsToOptions(ctx, request) + if err != nil { + return nil, errors.ToRosetta(err) + } + + return options, nil +} + +// ConstructionSubmit Submit a pre-signed transaction to the node. This call does not block on the +// transaction being included in a block. Rather, it returns immediately with an indication of +// whether or not the transaction was included in the mempool. +func (on OnlineNetwork) ConstructionSubmit(ctx context.Context, request *types.ConstructionSubmitRequest) (*types.TransactionIdentifierResponse, *types.Error) { + txBytes, err := hex.DecodeString(request.SignedTransaction) + if err != nil { + return nil, errors.ToRosetta(err) + } + + res, meta, err := on.client.PostTx(txBytes) + if err != nil { + return nil, errors.ToRosetta(err) + } + + return &types.TransactionIdentifierResponse{ + TransactionIdentifier: res, + Metadata: meta, + }, nil +} diff --git a/server/rosetta/lib/internal/service/data.go b/server/rosetta/lib/internal/service/data.go new file mode 100644 index 0000000000..01f2554fc5 --- /dev/null +++ b/server/rosetta/lib/internal/service/data.go @@ -0,0 +1,159 @@ +package service + +import ( + "context" + + "github.com/coinbase/rosetta-sdk-go/types" + + "github.com/line/lbm-sdk/server/rosetta/lib/errors" + crgtypes "github.com/line/lbm-sdk/server/rosetta/lib/types" +) + +// AccountBalance retrieves the account balance of an address +// rosetta requires us to fetch the block information too +func (on OnlineNetwork) AccountBalance(ctx context.Context, request *types.AccountBalanceRequest) (*types.AccountBalanceResponse, *types.Error) { + var ( + height int64 + block crgtypes.BlockResponse + err error + ) + + switch { + case request.BlockIdentifier == nil: + block, err = on.client.BlockByHeight(ctx, nil) + if err != nil { + return nil, errors.ToRosetta(err) + } + case request.BlockIdentifier.Hash != nil: + block, err = on.client.BlockByHash(ctx, *request.BlockIdentifier.Hash) + if err != nil { + return nil, errors.ToRosetta(err) + } + height = block.Block.Index + case request.BlockIdentifier.Index != nil: + height = *request.BlockIdentifier.Index + block, err = on.client.BlockByHeight(ctx, &height) + if err != nil { + return nil, errors.ToRosetta(err) + } + } + + accountCoins, err := on.client.Balances(ctx, request.AccountIdentifier.Address, &height) + if err != nil { + return nil, errors.ToRosetta(err) + } + + return &types.AccountBalanceResponse{ + BlockIdentifier: block.Block, + Balances: accountCoins, + Metadata: nil, + }, nil +} + +// Block gets the transactions in the given block +func (on OnlineNetwork) Block(ctx context.Context, request *types.BlockRequest) (*types.BlockResponse, *types.Error) { + var ( + blockResponse crgtypes.BlockTransactionsResponse + err error + ) + // block identifier is assumed not to be nil as rosetta will do this check for us + // check if we have to query via hash or block number + switch { + case request.BlockIdentifier.Hash != nil: + blockResponse, err = on.client.BlockTransactionsByHash(ctx, *request.BlockIdentifier.Hash) + if err != nil { + return nil, errors.ToRosetta(err) + } + case request.BlockIdentifier.Index != nil: + blockResponse, err = on.client.BlockTransactionsByHeight(ctx, request.BlockIdentifier.Index) + if err != nil { + return nil, errors.ToRosetta(err) + } + default: + err := errors.WrapError(errors.ErrBadArgument, "at least one of hash or index needs to be specified") + return nil, errors.ToRosetta(err) + } + + return &types.BlockResponse{ + Block: &types.Block{ + BlockIdentifier: blockResponse.Block, + ParentBlockIdentifier: blockResponse.ParentBlock, + Timestamp: blockResponse.MillisecondTimestamp, + Transactions: blockResponse.Transactions, + Metadata: nil, + }, + OtherTransactions: nil, + }, nil +} + +// BlockTransaction gets the given transaction in the specified block, we do not need to check the block itself too +// due to the fact that tendermint achieves instant finality +func (on OnlineNetwork) BlockTransaction(ctx context.Context, request *types.BlockTransactionRequest) (*types.BlockTransactionResponse, *types.Error) { + tx, err := on.client.GetTx(ctx, request.TransactionIdentifier.Hash) + if err != nil { + return nil, errors.ToRosetta(err) + } + + return &types.BlockTransactionResponse{ + Transaction: tx, + }, nil +} + +// Mempool fetches the transactions contained in the mempool +func (on OnlineNetwork) Mempool(ctx context.Context, _ *types.NetworkRequest) (*types.MempoolResponse, *types.Error) { + txs, err := on.client.Mempool(ctx) + if err != nil { + return nil, errors.ToRosetta(err) + } + + return &types.MempoolResponse{ + TransactionIdentifiers: txs, + }, nil +} + +// MempoolTransaction fetches a single transaction in the mempool +// NOTE: it is not implemented yet +func (on OnlineNetwork) MempoolTransaction(ctx context.Context, request *types.MempoolTransactionRequest) (*types.MempoolTransactionResponse, *types.Error) { + tx, err := on.client.GetUnconfirmedTx(ctx, request.TransactionIdentifier.Hash) + if err != nil { + return nil, errors.ToRosetta(err) + } + + return &types.MempoolTransactionResponse{ + Transaction: tx, + }, nil +} + +func (on OnlineNetwork) NetworkList(_ context.Context, _ *types.MetadataRequest) (*types.NetworkListResponse, *types.Error) { + return &types.NetworkListResponse{NetworkIdentifiers: []*types.NetworkIdentifier{on.network}}, nil +} + +func (on OnlineNetwork) NetworkOptions(_ context.Context, _ *types.NetworkRequest) (*types.NetworkOptionsResponse, *types.Error) { + return on.networkOptions, nil +} + +func (on OnlineNetwork) NetworkStatus(ctx context.Context, _ *types.NetworkRequest) (*types.NetworkStatusResponse, *types.Error) { + block, err := on.client.BlockByHeight(ctx, nil) + if err != nil { + return nil, errors.ToRosetta(err) + } + + peers, err := on.client.Peers(ctx) + if err != nil { + return nil, errors.ToRosetta(err) + } + + syncStatus, err := on.client.Status(ctx) + if err != nil { + return nil, errors.ToRosetta(err) + } + + return &types.NetworkStatusResponse{ + CurrentBlockIdentifier: block.Block, + CurrentBlockTimestamp: block.MillisecondTimestamp, + GenesisBlockIdentifier: on.genesisBlockIdentifier, + OldestBlockIdentifier: nil, + SyncStatus: syncStatus, + Peers: peers, + }, nil +} diff --git a/server/rosetta/lib/internal/service/offline.go b/server/rosetta/lib/internal/service/offline.go new file mode 100644 index 0000000000..e6732b2ceb --- /dev/null +++ b/server/rosetta/lib/internal/service/offline.go @@ -0,0 +1,63 @@ +package service + +import ( + "context" + + "github.com/coinbase/rosetta-sdk-go/types" + + crgerrs "github.com/line/lbm-sdk/server/rosetta/lib/errors" + crgtypes "github.com/line/lbm-sdk/server/rosetta/lib/types" +) + +// NewOffline instantiates the instance of an offline network +// whilst the offline network does not support the DataAPI, +// it supports a subset of the construction API. +func NewOffline(network *types.NetworkIdentifier, client crgtypes.Client) (crgtypes.API, error) { + return OfflineNetwork{ + OnlineNetwork{ + client: client, + network: network, + networkOptions: networkOptionsFromClient(client, nil), + }, + }, nil +} + +// OfflineNetwork implements an offline data API +// which is basically a data API that constantly +// returns errors, because it cannot be used if offline +type OfflineNetwork struct { + OnlineNetwork +} + +// Implement DataAPI in offline mode, which means no method is available +func (o OfflineNetwork) AccountBalance(_ context.Context, _ *types.AccountBalanceRequest) (*types.AccountBalanceResponse, *types.Error) { + return nil, crgerrs.ToRosetta(crgerrs.ErrOffline) +} + +func (o OfflineNetwork) Block(_ context.Context, _ *types.BlockRequest) (*types.BlockResponse, *types.Error) { + return nil, crgerrs.ToRosetta(crgerrs.ErrOffline) +} + +func (o OfflineNetwork) BlockTransaction(_ context.Context, _ *types.BlockTransactionRequest) (*types.BlockTransactionResponse, *types.Error) { + return nil, crgerrs.ToRosetta(crgerrs.ErrOffline) +} + +func (o OfflineNetwork) Mempool(_ context.Context, _ *types.NetworkRequest) (*types.MempoolResponse, *types.Error) { + return nil, crgerrs.ToRosetta(crgerrs.ErrOffline) +} + +func (o OfflineNetwork) MempoolTransaction(_ context.Context, _ *types.MempoolTransactionRequest) (*types.MempoolTransactionResponse, *types.Error) { + return nil, crgerrs.ToRosetta(crgerrs.ErrOffline) +} + +func (o OfflineNetwork) NetworkStatus(_ context.Context, _ *types.NetworkRequest) (*types.NetworkStatusResponse, *types.Error) { + return nil, crgerrs.ToRosetta(crgerrs.ErrOffline) +} + +func (o OfflineNetwork) ConstructionSubmit(_ context.Context, _ *types.ConstructionSubmitRequest) (*types.TransactionIdentifierResponse, *types.Error) { + return nil, crgerrs.ToRosetta(crgerrs.ErrOffline) +} + +func (o OfflineNetwork) ConstructionMetadata(_ context.Context, _ *types.ConstructionMetadataRequest) (*types.ConstructionMetadataResponse, *types.Error) { + return nil, crgerrs.ToRosetta(crgerrs.ErrOffline) +} diff --git a/server/rosetta/lib/internal/service/online.go b/server/rosetta/lib/internal/service/online.go new file mode 100644 index 0000000000..003ba2f87a --- /dev/null +++ b/server/rosetta/lib/internal/service/online.go @@ -0,0 +1,71 @@ +package service + +import ( + "context" + "time" + + "github.com/coinbase/rosetta-sdk-go/types" + + crgerrs "github.com/line/lbm-sdk/server/rosetta/lib/errors" + crgtypes "github.com/line/lbm-sdk/server/rosetta/lib/types" +) + +// genesisBlockFetchTimeout defines a timeout to fetch the genesis block +const genesisBlockFetchTimeout = 15 * time.Second + +// NewOnlineNetwork builds a single network adapter. +// It will get the Genesis block on the beginning to avoid calling it everytime. +func NewOnlineNetwork(network *types.NetworkIdentifier, client crgtypes.Client) (crgtypes.API, error) { + ctx, cancel := context.WithTimeout(context.Background(), genesisBlockFetchTimeout) + defer cancel() + + var genesisHeight int64 = -1 // to use initial_height in genesis.json + block, err := client.BlockByHeight(ctx, &genesisHeight) + if err != nil { + return OnlineNetwork{}, err + } + + return OnlineNetwork{ + client: client, + network: network, + networkOptions: networkOptionsFromClient(client, block.Block), + genesisBlockIdentifier: block.Block, + }, nil +} + +// OnlineNetwork groups together all the components required for the full rosetta implementation +type OnlineNetwork struct { + client crgtypes.Client // used to query cosmos app + tendermint + + network *types.NetworkIdentifier // identifies the network, it's static + networkOptions *types.NetworkOptionsResponse // identifies the network options, it's static + + genesisBlockIdentifier *types.BlockIdentifier // identifies genesis block, it's static +} + +// AccountsCoins - relevant only for UTXO based chain +// see https://www.rosetta-api.org/docs/AccountApi.html#accountcoins +func (o OnlineNetwork) AccountCoins(_ context.Context, _ *types.AccountCoinsRequest) (*types.AccountCoinsResponse, *types.Error) { + return nil, crgerrs.ToRosetta(crgerrs.ErrOffline) +} + +// networkOptionsFromClient builds network options given the client +func networkOptionsFromClient(client crgtypes.Client, genesisBlock *types.BlockIdentifier) *types.NetworkOptionsResponse { + var tsi *int64 + if genesisBlock != nil { + tsi = &(genesisBlock.Index) + } + return &types.NetworkOptionsResponse{ + Version: &types.Version{ + RosettaVersion: crgtypes.SpecVersion, + NodeVersion: client.Version(), + }, + Allow: &types.Allow{ + OperationStatuses: client.OperationStatuses(), + OperationTypes: client.SupportedOperations(), + Errors: crgerrs.SealAndListErrors(), + HistoricalBalanceLookup: true, + TimestampStartIndex: tsi, + }, + } +} diff --git a/server/rosetta/lib/server/server.go b/server/rosetta/lib/server/server.go new file mode 100644 index 0000000000..d3dd29ce66 --- /dev/null +++ b/server/rosetta/lib/server/server.go @@ -0,0 +1,117 @@ +package server + +import ( + "fmt" + "net/http" + "time" + + assert "github.com/coinbase/rosetta-sdk-go/asserter" + "github.com/coinbase/rosetta-sdk-go/server" + "github.com/coinbase/rosetta-sdk-go/types" + + "github.com/line/lbm-sdk/server/rosetta/lib/internal/service" + crgtypes "github.com/line/lbm-sdk/server/rosetta/lib/types" +) + +const DefaultRetries = 5 +const DefaultRetryWait = 5 * time.Second + +// Settings define the rosetta server settings +type Settings struct { + // Network contains the information regarding the network + Network *types.NetworkIdentifier + // Client is the online API handler + Client crgtypes.Client + // Listen is the address the handler will listen at + Listen string + // Offline defines if the rosetta service should be exposed in offline mode + Offline bool + // Retries is the number of readiness checks that will be attempted when instantiating the handler + // valid only for online API + Retries int + // RetryWait is the time that will be waited between retries + RetryWait time.Duration +} + +type Server struct { + h http.Handler + addr string +} + +func (h Server) Start() error { + return http.ListenAndServe(h.addr, h.h) +} + +func NewServer(settings Settings) (Server, error) { + asserter, err := assert.NewServer( + settings.Client.SupportedOperations(), + true, + []*types.NetworkIdentifier{settings.Network}, + nil, + false, + "", + ) + if err != nil { + return Server{}, fmt.Errorf("cannot build asserter: %w", err) + } + + var ( + adapter crgtypes.API + ) + switch settings.Offline { + case true: + adapter, err = newOfflineAdapter(settings) + case false: + adapter, err = newOnlineAdapter(settings) + } + if err != nil { + return Server{}, err + } + h := server.NewRouter( + server.NewAccountAPIController(adapter, asserter), + server.NewBlockAPIController(adapter, asserter), + server.NewNetworkAPIController(adapter, asserter), + server.NewMempoolAPIController(adapter, asserter), + server.NewConstructionAPIController(adapter, asserter), + ) + + return Server{ + h: h, + addr: settings.Listen, + }, nil +} + +func newOfflineAdapter(settings Settings) (crgtypes.API, error) { + if settings.Client == nil { + return nil, fmt.Errorf("client is nil") + } + return service.NewOffline(settings.Network, settings.Client) +} + +func newOnlineAdapter(settings Settings) (crgtypes.API, error) { + if settings.Client == nil { + return nil, fmt.Errorf("client is nil") + } + if settings.Retries <= 0 { + settings.Retries = DefaultRetries + } + if settings.RetryWait == 0 { + settings.RetryWait = DefaultRetryWait + } + + var err error + err = settings.Client.Bootstrap() + if err != nil { + return nil, err + } + + for i := 0; i < settings.Retries; i++ { + err = settings.Client.Ready() + if err != nil { + time.Sleep(settings.RetryWait) + continue + } + return service.NewOnlineNetwork(settings.Network, settings.Client) + } + return nil, fmt.Errorf("maximum number of retries exceeded, last error: %w", err) +} diff --git a/server/rosetta/lib/types/types.go b/server/rosetta/lib/types/types.go new file mode 100644 index 0000000000..4f734c34fb --- /dev/null +++ b/server/rosetta/lib/types/types.go @@ -0,0 +1,164 @@ +package types + +import ( + "context" + + "github.com/coinbase/rosetta-sdk-go/server" + "github.com/coinbase/rosetta-sdk-go/types" +) + +// SpecVersion defines the specification of rosetta +const SpecVersion = "" + +// NetworkInformationProvider defines the interface used to provide information regarding +// the network and the version of the cosmos sdk used +type NetworkInformationProvider interface { + // SupportedOperations lists the operations supported by the implementation + SupportedOperations() []string + // OperationStatuses returns the list of statuses supported by the implementation + OperationStatuses() []*types.OperationStatus + // Version returns the version of the node + Version() string +} + +// Client defines the API the client implementation should provide. +type Client interface { + // Bootstrap Needed if the client needs to perform some action before connecting. + Bootstrap() error + // Ready checks if the servicer constraints for queries are satisfied + // for example the node might still not be ready, it's useful in process + // when the rosetta instance might come up before the node itself + // the servicer must return nil if the node is ready + Ready() error + + // Data API + + // Balances fetches the balance of the given address + // if height is not nil, then the balance will be displayed + // at the provided height, otherwise last block balance will be returned + Balances(ctx context.Context, addr string, height *int64) ([]*types.Amount, error) + // BlockByHash gets a block and its transaction at the provided height + BlockByHash(ctx context.Context, hash string) (BlockResponse, error) + // BlockByHeight gets a block given its height, if height is nil then last block is returned + BlockByHeight(ctx context.Context, height *int64) (BlockResponse, error) + // BlockTransactionsByHash gets the block, parent block and transactions + // given the block hash. + BlockTransactionsByHash(ctx context.Context, hash string) (BlockTransactionsResponse, error) + // BlockTransactionsByHeight gets the block, parent block and transactions + // given the block hash. + BlockTransactionsByHeight(ctx context.Context, height *int64) (BlockTransactionsResponse, error) + // GetTx gets a transaction given its hash + GetTx(ctx context.Context, hash string) (*types.Transaction, error) + // GetUnconfirmedTx gets an unconfirmed Tx given its hash + // NOTE(fdymylja): NOT IMPLEMENTED YET! + GetUnconfirmedTx(ctx context.Context, hash string) (*types.Transaction, error) + // Mempool returns the list of the current non confirmed transactions + Mempool(ctx context.Context) ([]*types.TransactionIdentifier, error) + // Peers gets the peers currently connected to the node + Peers(ctx context.Context) ([]*types.Peer, error) + // Status returns the node status, such as sync data, version etc + Status(ctx context.Context) (*types.SyncStatus, error) + + // Construction API + + // PostTx posts txBytes to the node and returns the transaction identifier plus metadata related + // to the transaction itself. + PostTx(txBytes []byte) (res *types.TransactionIdentifier, meta map[string]interface{}, err error) + // ConstructionMetadataFromOptions builds metadata map from an option map + ConstructionMetadataFromOptions(ctx context.Context, options map[string]interface{}) (meta map[string]interface{}, err error) + OfflineClient +} + +// OfflineClient defines the functionalities supported without having access to the node +type OfflineClient interface { + NetworkInformationProvider + // SignedTx returns the signed transaction given the tx bytes (msgs) plus the signatures + SignedTx(ctx context.Context, txBytes []byte, sigs []*types.Signature) (signedTxBytes []byte, err error) + // TxOperationsAndSignersAccountIdentifiers returns the operations related to a transaction and the account + // identifiers if the transaction is signed + TxOperationsAndSignersAccountIdentifiers(signed bool, hexBytes []byte) (ops []*types.Operation, signers []*types.AccountIdentifier, err error) + // ConstructionPayload returns the construction payload given the request + ConstructionPayload(ctx context.Context, req *types.ConstructionPayloadsRequest) (resp *types.ConstructionPayloadsResponse, err error) + // PreprocessOperationsToOptions returns the options given the preprocess operations + PreprocessOperationsToOptions(ctx context.Context, req *types.ConstructionPreprocessRequest) (resp *types.ConstructionPreprocessResponse, err error) + // AccountIdentifierFromPublicKey returns the account identifier given the public key + AccountIdentifierFromPublicKey(pubKey *types.PublicKey) (*types.AccountIdentifier, error) +} + +type BlockTransactionsResponse struct { + BlockResponse + Transactions []*types.Transaction +} + +type BlockResponse struct { + Block *types.BlockIdentifier + ParentBlock *types.BlockIdentifier + MillisecondTimestamp int64 + TxCount int64 +} + +// API defines the exposed APIs +// if the service is online +type API interface { + DataAPI + ConstructionAPI +} + +// DataAPI defines the full data API implementation +type DataAPI interface { + server.NetworkAPIServicer + server.AccountAPIServicer + server.BlockAPIServicer + server.MempoolAPIServicer +} + +var _ server.ConstructionAPIServicer = ConstructionAPI(nil) + +// ConstructionAPI defines the full construction API with +// the online and offline endpoints +type ConstructionAPI interface { + ConstructionOnlineAPI + ConstructionOfflineAPI +} + +// ConstructionOnlineAPI defines the construction methods +// allowed in an online implementation +type ConstructionOnlineAPI interface { + ConstructionMetadata( + context.Context, + *types.ConstructionMetadataRequest, + ) (*types.ConstructionMetadataResponse, *types.Error) + ConstructionSubmit( + context.Context, + *types.ConstructionSubmitRequest, + ) (*types.TransactionIdentifierResponse, *types.Error) +} + +// ConstructionOfflineAPI defines the construction methods +// allowed +type ConstructionOfflineAPI interface { + ConstructionCombine( + context.Context, + *types.ConstructionCombineRequest, + ) (*types.ConstructionCombineResponse, *types.Error) + ConstructionDerive( + context.Context, + *types.ConstructionDeriveRequest, + ) (*types.ConstructionDeriveResponse, *types.Error) + ConstructionHash( + context.Context, + *types.ConstructionHashRequest, + ) (*types.TransactionIdentifierResponse, *types.Error) + ConstructionParse( + context.Context, + *types.ConstructionParseRequest, + ) (*types.ConstructionParseResponse, *types.Error) + ConstructionPayloads( + context.Context, + *types.ConstructionPayloadsRequest, + ) (*types.ConstructionPayloadsResponse, *types.Error) + ConstructionPreprocess( + context.Context, + *types.ConstructionPreprocessRequest, + ) (*types.ConstructionPreprocessResponse, *types.Error) +} diff --git a/server/rosetta/types.go b/server/rosetta/types.go new file mode 100644 index 0000000000..0d1eada892 --- /dev/null +++ b/server/rosetta/types.go @@ -0,0 +1,104 @@ +package rosetta + +import ( + "crypto/sha256" +) + +// statuses +const ( + StatusTxSuccess = "Success" + StatusTxReverted = "Reverted" + StatusPeerSynced = "synced" + StatusPeerSyncing = "syncing" +) + +// In rosetta all state transitions must be represented as transactions +// since in tendermint begin block and end block are state transitions +// which are not represented as transactions we mock only the balance changes +// happening at those levels as transactions. (check BeginBlockTxHash for more info) +const ( + DeliverTxSize = sha256.Size + BeginEndBlockTxSize = DeliverTxSize + 1 + EndBlockHashStart = 0x0 + BeginBlockHashStart = 0x1 +) + +const ( + // BurnerAddressIdentifier mocks the account identifier of a burner address + // all coins burned in the sdk will be sent to this identifier, which per sdk.AccAddress + // design we will never be able to query (as of now). + // Rosetta does not understand supply contraction. + BurnerAddressIdentifier = "burner" +) + +// TransactionType is used to distinguish if a rosetta provided hash +// represents endblock, beginblock or deliver tx +type TransactionType int + +const ( + UnrecognizedTx TransactionType = iota + BeginBlockTx + EndBlockTx + DeliverTxTx +) + +// metadata options + +// misc +const ( + Log = "log" +) + +// ConstructionPreprocessMetadata is used to represent +// the metadata rosetta can provide during preprocess options +type ConstructionPreprocessMetadata struct { + Memo string `json:"memo"` + GasLimit uint64 `json:"gas_limit"` + GasPrice string `json:"gas_price"` +} + +func (c *ConstructionPreprocessMetadata) FromMetadata(meta map[string]interface{}) error { + return unmarshalMetadata(meta, c) +} + +// PreprocessOperationsOptionsResponse is the structured metadata options returned by the preprocess operations endpoint +type PreprocessOperationsOptionsResponse struct { + ExpectedSigners []string `json:"expected_signers"` + Memo string `json:"memo"` + GasLimit uint64 `json:"gas_limit"` + GasPrice string `json:"gas_price"` +} + +func (c PreprocessOperationsOptionsResponse) ToMetadata() (map[string]interface{}, error) { + return marshalMetadata(c) +} + +func (c *PreprocessOperationsOptionsResponse) FromMetadata(meta map[string]interface{}) error { + return unmarshalMetadata(meta, c) +} + +// SignerData contains information on the signers when the request +// is being created, used to populate the account information +type SignerData struct { + AccountNumber uint64 `json:"account_number"` + Sequence uint64 `json:"sequence"` +} + +// ConstructionMetadata are the metadata options used to +// construct a transaction. It is returned by ConstructionMetadataFromOptions +// and fed to ConstructionPayload to process the bytes to sign. +type ConstructionMetadata struct { + ChainID string `json:"chain_id"` + SignersData []*SignerData `json:"signer_data"` + GasLimit uint64 `json:"gas_limit"` + GasPrice string `json:"gas_price"` + Memo string `json:"memo"` +} + +func (c ConstructionMetadata) ToMetadata() (map[string]interface{}, error) { + return marshalMetadata(c) +} + +func (c *ConstructionMetadata) FromMetadata(meta map[string]interface{}) error { + return unmarshalMetadata(meta, c) +} diff --git a/server/rosetta/util.go b/server/rosetta/util.go new file mode 100644 index 0000000000..e572a1aede --- /dev/null +++ b/server/rosetta/util.go @@ -0,0 +1,43 @@ +package rosetta + +import ( + "encoding/json" + "time" + + crgerrs "github.com/line/lbm-sdk/server/rosetta/lib/errors" +) + +// timeToMilliseconds converts time to milliseconds timestamp +func timeToMilliseconds(t time.Time) int64 { + return t.UnixNano() / (int64(time.Millisecond) / int64(time.Nanosecond)) +} + +// unmarshalMetadata unmarshals the given meta to the target +func unmarshalMetadata(meta map[string]interface{}, target interface{}) error { + b, err := json.Marshal(meta) + if err != nil { + return crgerrs.WrapError(crgerrs.ErrCodec, err.Error()) + } + + err = json.Unmarshal(b, target) + if err != nil { + return crgerrs.WrapError(crgerrs.ErrCodec, err.Error()) + } + + return nil +} + +// marshalMetadata marshals the given interface to map[string]interface{} +func marshalMetadata(o interface{}) (meta map[string]interface{}, err error) { + b, err := json.Marshal(o) + if err != nil { + return nil, crgerrs.WrapError(crgerrs.ErrCodec, err.Error()) + } + meta = make(map[string]interface{}) + err = json.Unmarshal(b, &meta) + if err != nil { + return nil, err + } + + return +} diff --git a/server/start.go b/server/start.go index d2c7425c35..053e5c69f2 100644 --- a/server/start.go +++ b/server/start.go @@ -4,10 +4,14 @@ package server import ( "fmt" + "net/http" "os" "runtime/pprof" "time" + "github.com/spf13/cobra" + "google.golang.org/grpc" + "github.com/line/ostracon/abci/server" ostcmd "github.com/line/ostracon/cmd/ostracon/commands" ostos "github.com/line/ostracon/libs/os" @@ -16,18 +20,18 @@ import ( pvm "github.com/line/ostracon/privval" "github.com/line/ostracon/proxy" "github.com/line/ostracon/rpc/client/local" - "github.com/spf13/cobra" - "google.golang.org/grpc" - - "github.com/line/lbm-sdk/store/cache" - "github.com/line/lbm-sdk/store/iavl" "github.com/line/lbm-sdk/client" "github.com/line/lbm-sdk/client/flags" + "github.com/line/lbm-sdk/codec" "github.com/line/lbm-sdk/server/api" "github.com/line/lbm-sdk/server/config" servergrpc "github.com/line/lbm-sdk/server/grpc" + "github.com/line/lbm-sdk/server/rosetta" + crgserver "github.com/line/lbm-sdk/server/rosetta/lib/server" "github.com/line/lbm-sdk/server/types" + "github.com/line/lbm-sdk/store/cache" + "github.com/line/lbm-sdk/store/iavl" storetypes "github.com/line/lbm-sdk/store/types" ) @@ -60,8 +64,10 @@ const ( // GRPC-related flags. const ( - flagGRPCEnable = "grpc.enable" - flagGRPCAddress = "grpc.address" + flagGRPCEnable = "grpc.enable" + flagGRPCAddress = "grpc.address" + flagGRPCWebEnable = "grpc-web.enable" + flagGRPCWebAddress = "grpc-web.address" ) // State sync-related flags. @@ -159,6 +165,9 @@ which accepts a path for the resulting pprof file. cmd.Flags().Bool(flagGRPCEnable, true, "Define if the gRPC server should be enabled") cmd.Flags().String(flagGRPCAddress, config.DefaultGRPCAddress, "the gRPC server address to listen on") + cmd.Flags().Bool(flagGRPCWebEnable, true, "Define if the gRPC-Web server should be enabled. (Note: gRPC must also be enabled.)") + cmd.Flags().String(flagGRPCWebAddress, config.DefaultGRPCWebAddress, "The gRPC-Web server address to listen on") + cmd.Flags().Uint64(FlagStateSyncSnapshotInterval, 0, "State sync snapshot interval") cmd.Flags().Uint32(FlagStateSyncSnapshotKeepRecent, 2, "State sync snapshot to keep") @@ -244,6 +253,13 @@ func startInProcess(ctx *Context, clientCtx client.Context, appCreator types.App return err } + config := config.GetConfig(ctx.Viper) + if err := config.ValidateBasic(); err != nil { + ctx.Logger.Error("WARNING: The minimum-gas-prices config in app.toml is set to the empty string. " + + "This defaults to 0 in the current version, but will error in the next version " + + "(SDK v0.45). Please explicitly put the desired minimum-gas-prices in your app.toml.") + } + app := appCreator(ctx.Logger, db, traceWriter, ctx.Viper) nodeKey, err := p2p.LoadOrGenNodeKey(cfg.NodeKeyFile()) @@ -276,8 +292,6 @@ func startInProcess(ctx *Context, clientCtx client.Context, appCreator types.App } ctx.Logger.Debug("initialization: ocNode started") - config := config.GetConfig(ctx.Viper) - // Add the tx service to the gRPC router. We only need to register this // service if API or gRPC is enabled, and avoid doing so in the general // case, because it spawns a new local ostracon RPC client. @@ -289,7 +303,6 @@ func startInProcess(ctx *Context, clientCtx client.Context, appCreator types.App } var apiSrv *api.Server - if config.API.Enable { genDoc, err := genDocProvider() if err != nil { @@ -313,16 +326,62 @@ func startInProcess(ctx *Context, clientCtx client.Context, appCreator types.App select { case err := <-errCh: return err - case <-time.After(5 * time.Second): // assume server started successfully + case <-time.After(types.ServerStartTime): // assume server started successfully } } - var grpcSrv *grpc.Server + var ( + grpcSrv *grpc.Server + grpcWebSrv *http.Server + ) if config.GRPC.Enable { grpcSrv, err = servergrpc.StartGRPCServer(clientCtx, app, config.GRPC.Address) if err != nil { return err } + if config.GRPCWeb.Enable { + grpcWebSrv, err = servergrpc.StartGRPCWeb(grpcSrv, config) + if err != nil { + ctx.Logger.Error("failed to start grpc-web http server: ", err) + return err + } + } + } + + var rosettaSrv crgserver.Server + if config.Rosetta.Enable { + offlineMode := config.Rosetta.Offline + if !config.GRPC.Enable { // If GRPC is not enabled rosetta cannot work in online mode, so it works in offline mode. + offlineMode = true + } + + conf := &rosetta.Config{ + Blockchain: config.Rosetta.Blockchain, + Network: config.Rosetta.Network, + TendermintRPC: ctx.Config.RPC.ListenAddress, + GRPCEndpoint: config.GRPC.Address, + Addr: config.Rosetta.Address, + Retries: config.Rosetta.Retries, + Offline: offlineMode, + } + conf.WithCodec(clientCtx.InterfaceRegistry, clientCtx.Codec.(*codec.ProtoCodec)) + + rosettaSrv, err = rosetta.ServerFromConfig(conf) + if err != nil { + return err + } + errCh := make(chan error) + go func() { + if err := rosettaSrv.Start(); err != nil { + errCh <- err + } + }() + + select { + case err := <-errCh: + return err + case <-time.After(types.ServerStartTime): // assume server started successfully + } } defer func() { @@ -340,6 +399,9 @@ func startInProcess(ctx *Context, clientCtx client.Context, appCreator types.App if grpcSrv != nil { grpcSrv.Stop() + if grpcWebSrv != nil { + grpcWebSrv.Close() + } } ctx.Logger.Info("exiting...") diff --git a/server/test_helpers.go b/server/test_helpers.go index 19b4e6ccec..c3263e9d79 100644 --- a/server/test_helpers.go +++ b/server/test_helpers.go @@ -3,6 +3,8 @@ package server import ( "fmt" "net" + + sdkerrors "github.com/line/lbm-sdk/types/errors" ) // Get a free address for a test ostracon server @@ -13,16 +15,10 @@ func FreeTCPAddr() (addr, port string, err error) { return "", "", err } - closer := func() { - err := l.Close() - if err != nil { - // TODO: Handle with #870 - panic(err) - } + if err := l.Close(); err != nil { + return "", "", sdkerrors.Wrap(err, "couldn't close the listener") } - defer closer() - portI := l.Addr().(*net.TCPAddr).Port port = fmt.Sprintf("%d", portI) addr = fmt.Sprintf("tcp://0.0.0.0:%s", port) diff --git a/server/types/app.go b/server/types/app.go index dc9d75f7f5..b035f992ec 100644 --- a/server/types/app.go +++ b/server/types/app.go @@ -3,6 +3,7 @@ package types import ( "encoding/json" "io" + "time" "github.com/gogo/protobuf/grpc" abci "github.com/line/ostracon/abci/types" @@ -16,6 +17,10 @@ import ( "github.com/line/lbm-sdk/server/config" ) +// ServerStartTime defines the time duration that the server need to stay running after startup +// for the startup be considered successful +const ServerStartTime = 5 * time.Second + type ( // AppOptions defines an interface that is passed into an application // constructor, typically used to set BaseApp options that are either supplied @@ -38,7 +43,7 @@ type ( // RegisterGRPCServer registers gRPC services directly with the gRPC // server. - RegisterGRPCServer(client.Context, grpc.Server) + RegisterGRPCServer(grpc.Server) // RegisterTxService registers the gRPC Query service for tx (such as tx // simulation, fetching txs by hash...). diff --git a/server/util.go b/server/util.go index 341b4d7176..830b81ca00 100644 --- a/server/util.go +++ b/server/util.go @@ -99,10 +99,13 @@ func bindFlags(basename string, cmd *cobra.Command, v *viper.Viper) (err error) // application command. It will create a Viper literal and a default server // Context. The server Tendermint configuration will either be read and parsed // or created and saved to disk, where the server Context is updated to reflect -// the Tendermint configuration. The Viper literal is used to read and parse -// the application configuration. Command handlers can fetch the server Context -// to get the Tendermint configuration or to get access to Viper. -func InterceptConfigsPreRunHandler(cmd *cobra.Command) error { +// the Tendermint configuration. It takes custom app config template and config +// settings to create a custom Tendermint configuration. If the custom template +// is empty, it uses default-template provided by the server. The Viper literal +// is used to read and parse the application configuration. Command handlers can +// fetch the server Context to get the Tendermint configuration or to get access +// to Viper. +func InterceptConfigsPreRunHandler(cmd *cobra.Command, customAppConfigTemplate string, customAppConfig interface{}) error { serverCtx := NewDefaultContext() // Get the executable name and configure the viper instance so that environmental @@ -123,7 +126,7 @@ func InterceptConfigsPreRunHandler(cmd *cobra.Command) error { serverCtx.Viper.AutomaticEnv() // intercept configuration files, using both Viper instances separately - config, err := interceptConfigs(serverCtx.Viper) + config, err := interceptConfigs(serverCtx.Viper, customAppConfigTemplate, customAppConfig) if err != nil { return err } @@ -184,7 +187,7 @@ func SetCmdServerContext(cmd *cobra.Command, serverCtx *Context) error { // configuration file. The Tendermint configuration file is parsed given a root // Viper object, whereas the application is parsed with the private package-aware // viperCfg object. -func interceptConfigs(rootViper *viper.Viper) (*ostcfg.Config, error) { +func interceptConfigs(rootViper *viper.Viper, customAppTemplate string, customConfig interface{}) (*ostcfg.Config, error) { rootDir := rootViper.GetString(flags.FlagHome) configPath := filepath.Join(rootDir, "config") tmCfgFile := filepath.Join(configPath, "config.toml") @@ -234,12 +237,22 @@ func interceptConfigs(rootViper *viper.Viper) (*ostcfg.Config, error) { appCfgFilePath := filepath.Join(configPath, "app.toml") if _, err := os.Stat(appCfgFilePath); os.IsNotExist(err) { - appConf, err := config.ParseConfig(rootViper) - if err != nil { - return nil, fmt.Errorf("failed to parse %s: %w", appCfgFilePath, err) - } + if customAppTemplate != "" { + config.SetConfigTemplate(customAppTemplate) + + if err = rootViper.Unmarshal(&customConfig); err != nil { + return nil, fmt.Errorf("failed to parse %s: %w", appCfgFilePath, err) + } - config.WriteConfigFile(appCfgFilePath, appConf) + config.WriteConfigFile(appCfgFilePath, customConfig) + } else { + appConf, err := config.ParseConfig(rootViper) + if err != nil { + return nil, fmt.Errorf("failed to parse %s: %w", appCfgFilePath, err) + } + + config.WriteConfigFile(appCfgFilePath, appConf) + } } rootViper.SetConfigType("toml") @@ -272,10 +285,8 @@ func AddCommands(rootCmd *cobra.Command, defaultNodeHome string, appCreator type rootCmd.AddCommand( startCmd, UnsafeResetAllCmd(), - flags.LineBreak, ostraconCmd, ExportCmd(appExport, defaultNodeHome), - flags.LineBreak, version.NewVersionCommand(), ) } diff --git a/server/util_test.go b/server/util_test.go index e64f88b9ae..df232f7a1b 100644 --- a/server/util_test.go +++ b/server/util_test.go @@ -1,4 +1,4 @@ -package server +package server_test import ( "context" @@ -13,33 +13,34 @@ import ( "github.com/spf13/cobra" "github.com/line/lbm-sdk/client/flags" + "github.com/line/lbm-sdk/server" ) -var CancelledInPreRun = errors.New("Canelled in prerun") +var cancelledInPreRun = errors.New("Cancelled in prerun") // Used in each test to run the function under test via Cobra // but to always halt the command func preRunETestImpl(cmd *cobra.Command, args []string) error { - err := InterceptConfigsPreRunHandler(cmd) + err := server.InterceptConfigsPreRunHandler(cmd, "", nil) if err != nil { return err } - return CancelledInPreRun + return cancelledInPreRun } func TestInterceptConfigsPreRunHandlerCreatesConfigFilesWhenMissing(t *testing.T) { tempDir := t.TempDir() - cmd := StartCmd(nil, "/foobar") + cmd := server.StartCmd(nil, "/foobar") if err := cmd.Flags().Set(flags.FlagHome, tempDir); err != nil { t.Fatalf("Could not set home flag [%T] %v", err, err) } cmd.PreRunE = preRunETestImpl - serverCtx := &Context{} - ctx := context.WithValue(context.Background(), ServerContextKey, serverCtx) - if err := cmd.ExecuteContext(ctx); err != CancelledInPreRun { + serverCtx := &server.Context{} + ctx := context.WithValue(context.Background(), server.ServerContextKey, serverCtx) + if err := cmd.ExecuteContext(ctx); err != cancelledInPreRun { t.Fatalf("function failed with [%T] %v", err, err) } @@ -106,17 +107,17 @@ func TestInterceptConfigsPreRunHandlerReadsConfigToml(t *testing.T) { t.Fatalf("Failed closing config.toml: %v", err) } - cmd := StartCmd(nil, "/foobar") + cmd := server.StartCmd(nil, "/foobar") if err := cmd.Flags().Set(flags.FlagHome, tempDir); err != nil { t.Fatalf("Could not set home flag [%T] %v", err, err) } cmd.PreRunE = preRunETestImpl - serverCtx := &Context{} - ctx := context.WithValue(context.Background(), ServerContextKey, serverCtx) + serverCtx := &server.Context{} + ctx := context.WithValue(context.Background(), server.ServerContextKey, serverCtx) - if err := cmd.ExecuteContext(ctx); err != CancelledInPreRun { + if err := cmd.ExecuteContext(ctx); err != cancelledInPreRun { t.Fatalf("function failed with [%T] %v", err, err) } @@ -146,14 +147,14 @@ func TestInterceptConfigsPreRunHandlerReadsAppToml(t *testing.T) { if err := writer.Close(); err != nil { t.Fatalf("Failed closing app.toml: %v", err) } - cmd := StartCmd(nil, tempDir) + cmd := server.StartCmd(nil, tempDir) cmd.PreRunE = preRunETestImpl - serverCtx := &Context{} - ctx := context.WithValue(context.Background(), ServerContextKey, serverCtx) + serverCtx := &server.Context{} + ctx := context.WithValue(context.Background(), server.ServerContextKey, serverCtx) - if err := cmd.ExecuteContext(ctx); err != CancelledInPreRun { + if err := cmd.ExecuteContext(ctx); err != cancelledInPreRun { t.Fatalf("function failed with [%T] %v", err, err) } @@ -165,7 +166,7 @@ func TestInterceptConfigsPreRunHandlerReadsAppToml(t *testing.T) { func TestInterceptConfigsPreRunHandlerReadsFlags(t *testing.T) { const testAddr = "tcp://127.1.2.3:12345" tempDir := t.TempDir() - cmd := StartCmd(nil, "/foobar") + cmd := server.StartCmd(nil, "/foobar") if err := cmd.Flags().Set(flags.FlagHome, tempDir); err != nil { t.Fatalf("Could not set home flag [%T] %v", err, err) @@ -178,10 +179,10 @@ func TestInterceptConfigsPreRunHandlerReadsFlags(t *testing.T) { cmd.PreRunE = preRunETestImpl - serverCtx := &Context{} - ctx := context.WithValue(context.Background(), ServerContextKey, serverCtx) + serverCtx := &server.Context{} + ctx := context.WithValue(context.Background(), server.ServerContextKey, serverCtx) - if err := cmd.ExecuteContext(ctx); err != CancelledInPreRun { + if err := cmd.ExecuteContext(ctx); err != cancelledInPreRun { t.Fatalf("function failed with [%T] %v", err, err) } @@ -193,7 +194,7 @@ func TestInterceptConfigsPreRunHandlerReadsFlags(t *testing.T) { func TestInterceptConfigsPreRunHandlerReadsEnvVars(t *testing.T) { const testAddr = "tcp://127.1.2.3:12345" tempDir := t.TempDir() - cmd := StartCmd(nil, "/foobar") + cmd := server.StartCmd(nil, "/foobar") if err := cmd.Flags().Set(flags.FlagHome, tempDir); err != nil { t.Fatalf("Could not set home flag [%T] %v", err, err) } @@ -213,10 +214,10 @@ func TestInterceptConfigsPreRunHandlerReadsEnvVars(t *testing.T) { cmd.PreRunE = preRunETestImpl - serverCtx := &Context{} - ctx := context.WithValue(context.Background(), ServerContextKey, serverCtx) + serverCtx := &server.Context{} + ctx := context.WithValue(context.Background(), server.ServerContextKey, serverCtx) - if err := cmd.ExecuteContext(ctx); err != CancelledInPreRun { + if err := cmd.ExecuteContext(ctx); err != cancelledInPreRun { t.Fatalf("function failed with [%T] %v", err, err) } @@ -279,7 +280,7 @@ func newPrecedenceCommon(t *testing.T) precedenceCommon { }) // Set up the command object that is used in this test - retval.cmd = StartCmd(nil, tempDir) + retval.cmd = server.StartCmd(nil, tempDir) retval.cmd.PreRunE = preRunETestImpl return retval @@ -317,10 +318,10 @@ func TestInterceptConfigsPreRunHandlerPrecedenceFlag(t *testing.T) { testCommon := newPrecedenceCommon(t) testCommon.setAll(t, &TestAddrExpected, &TestAddrNotExpected, &TestAddrNotExpected) - serverCtx := &Context{} - ctx := context.WithValue(context.Background(), ServerContextKey, serverCtx) + serverCtx := &server.Context{} + ctx := context.WithValue(context.Background(), server.ServerContextKey, serverCtx) - if err := testCommon.cmd.ExecuteContext(ctx); err != CancelledInPreRun { + if err := testCommon.cmd.ExecuteContext(ctx); err != cancelledInPreRun { t.Fatalf("function failed with [%T] %v", err, err) } @@ -333,10 +334,10 @@ func TestInterceptConfigsPreRunHandlerPrecedenceEnvVar(t *testing.T) { testCommon := newPrecedenceCommon(t) testCommon.setAll(t, nil, &TestAddrExpected, &TestAddrNotExpected) - serverCtx := &Context{} - ctx := context.WithValue(context.Background(), ServerContextKey, serverCtx) + serverCtx := &server.Context{} + ctx := context.WithValue(context.Background(), server.ServerContextKey, serverCtx) - if err := testCommon.cmd.ExecuteContext(ctx); err != CancelledInPreRun { + if err := testCommon.cmd.ExecuteContext(ctx); err != cancelledInPreRun { t.Fatalf("function failed with [%T] %v", err, err) } @@ -349,10 +350,10 @@ func TestInterceptConfigsPreRunHandlerPrecedenceConfigFile(t *testing.T) { testCommon := newPrecedenceCommon(t) testCommon.setAll(t, nil, nil, &TestAddrExpected) - serverCtx := &Context{} - ctx := context.WithValue(context.Background(), ServerContextKey, serverCtx) + serverCtx := &server.Context{} + ctx := context.WithValue(context.Background(), server.ServerContextKey, serverCtx) - if err := testCommon.cmd.ExecuteContext(ctx); err != CancelledInPreRun { + if err := testCommon.cmd.ExecuteContext(ctx); err != cancelledInPreRun { t.Fatalf("function failed with [%T] %v", err, err) } @@ -365,10 +366,10 @@ func TestInterceptConfigsPreRunHandlerPrecedenceConfigDefault(t *testing.T) { testCommon := newPrecedenceCommon(t) // Do not set anything - serverCtx := &Context{} - ctx := context.WithValue(context.Background(), ServerContextKey, serverCtx) + serverCtx := &server.Context{} + ctx := context.WithValue(context.Background(), server.ServerContextKey, serverCtx) - if err := testCommon.cmd.ExecuteContext(ctx); err != CancelledInPreRun { + if err := testCommon.cmd.ExecuteContext(ctx); err != cancelledInPreRun { t.Fatalf("function failed with [%T] %v", err, err) } @@ -379,22 +380,22 @@ func TestInterceptConfigsPreRunHandlerPrecedenceConfigDefault(t *testing.T) { // Ensure that if interceptConfigs encounters any error other than non-existen errors // that we correctly return the offending error, for example a permission error. -// See https://github.com/line/lbm-sdk/issues/7578 +// See https://github.com/cosmos/cosmos-sdk/issues/7578 func TestInterceptConfigsWithBadPermissions(t *testing.T) { tempDir := t.TempDir() subDir := filepath.Join(tempDir, "nonPerms") if err := os.Mkdir(subDir, 0600); err != nil { t.Fatalf("Failed to create sub directory: %v", err) } - cmd := StartCmd(nil, "/foobar") + cmd := server.StartCmd(nil, "/foobar") if err := cmd.Flags().Set(flags.FlagHome, subDir); err != nil { t.Fatalf("Could not set home flag [%T] %v", err, err) } cmd.PreRunE = preRunETestImpl - serverCtx := &Context{} - ctx := context.WithValue(context.Background(), ServerContextKey, serverCtx) + serverCtx := &server.Context{} + ctx := context.WithValue(context.Background(), server.ServerContextKey, serverCtx) if err := cmd.ExecuteContext(ctx); !os.IsPermission(err) { t.Fatalf("Failed to catch permissions error, got: [%T] %v", err, err) } diff --git a/simapp/README.md b/simapp/README.md new file mode 100644 index 0000000000..4d00c0c2d1 --- /dev/null +++ b/simapp/README.md @@ -0,0 +1,53 @@ +--- +order: false +--- + +# simapp + +simapp is an application built using the Cosmos SDK for testing and educational purposes. + +## Running testnets with `simd` + +If you want to spin up a quick testnet with your friends, you can follow these steps. +Unless otherwise noted, every step must be done by everyone who wants to participate +in this testnet. + +1. From the root directory of the Cosmos SDK repository, run `$ make build`. This will build the + `simd` binary inside a new `build` directory. The following instructions are run from inside + the `build` directory. +2. If you've run `simd` before, you may need to reset your database before starting a new + testnet. You can reset your database with the following command: `$ ./simd unsafe-reset-all`. +3. `$ ./simd init [moniker] --chain-id [chain-id]`. This will initialize a new working directory + at the default location `~/.simapp`. You need to provide a "moniker" and a "chain id". These + two names can be anything, but you will need to use the same "chain id" in the following steps. +4. `$ ./simd keys add [key_name]`. This will create a new key, with a name of your choosing. + Save the output of this command somewhere; you'll need the address generated here later. +5. `$ ./simd add-genesis-account [key_name] [amount]`, where `key_name` is the same key name as + before; and `amount` is something like `10000000000000000000000000stake`. +6. `$ ./simd gentx [key_name] [amount] --chain-id [chain-id]`. This will create the genesis + transaction for your new chain. Here `amount` should be at least `1000000000stake`. If you + provide too much or too little, you will encounter an error when starting your node. +7. Now, one person needs to create the genesis file `genesis.json` using the genesis transactions + from every participant, by gathering all the genesis transactions under `config/gentx` and then + calling `$ ./simd collect-gentxs`. This will create a new `genesis.json` file that includes data + from all the validators (we sometimes call it the "super genesis file" to distinguish it from + single-validator genesis files). +8. Once you've received the super genesis file, overwrite your original `genesis.json` file with + the new super `genesis.json`. +9. Modify your `config/config.toml` (in the simapp working directory) to include the other participants as + persistent peers: + + ``` + # Comma separated list of nodes to keep persistent connections to + persistent_peers = "[validator_address]@[ip_address]:[port],[validator_address]@[ip_address]:[port]" + ``` + + You can find `validator_address` by running `$ ./simd tendermint show-node-id`. The output will + be the hex-encoded `validator_address`. The default `port` is 26656. +10. Now you can start your nodes: `$ ./simd start`. + +Now you have a small testnet that you can use to try out changes to the Cosmos SDK or Tendermint! + +NOTE: Sometimes creating the network through the `collect-gentxs` will fail, and validators will start +in a funny state (and then panic). If this happens, you can try to create and start the network first +with a single validator and then add additional validators using a `create-validator` transaction. diff --git a/simapp/ante_handler.go b/simapp/ante_handler.go index f909f74843..525431f174 100644 --- a/simapp/ante_handler.go +++ b/simapp/ante_handler.go @@ -3,10 +3,8 @@ package simapp import ( sdk "github.com/line/lbm-sdk/types" "github.com/line/lbm-sdk/x/auth/ante" - keeper2 "github.com/line/lbm-sdk/x/auth/keeper" "github.com/line/lbm-sdk/x/auth/signing" feegrantkeeper "github.com/line/lbm-sdk/x/feegrant/keeper" - types2 "github.com/line/lbm-sdk/x/feegrant/types" "github.com/line/lbm-sdk/x/gov/types" channelkeeper "github.com/line/lbm-sdk/x/ibc/core/04-channel/keeper" ibcante "github.com/line/lbm-sdk/x/ibc/core/ante" @@ -28,7 +26,6 @@ func NewAnteHandler( ante.TxTimeoutHeightDecorator{}, ante.NewValidateMemoDecorator(ak), ante.NewConsumeGasForTxSizeDecorator(ak), - ante.NewDeductGrantedFeeDecorator(ak.(keeper2.AccountKeeper), bankKeeper.(types2.BankKeeper), feegrantKeeper), ante.NewSetPubKeyDecorator(ak), // SetPubKeyDecorator must be called before all signature verification decorators ante.NewValidateSigCountDecorator(ak), // ante.NewDeductFeeDecorator(ak, bankKeeper), diff --git a/simapp/app.go b/simapp/app.go index 5f81307107..9c2ebf0884 100644 --- a/simapp/app.go +++ b/simapp/app.go @@ -7,18 +7,15 @@ import ( "path/filepath" "github.com/gorilla/mux" + "github.com/rakyll/statik/fs" + "github.com/spf13/cast" + abci "github.com/line/ostracon/abci/types" ostjson "github.com/line/ostracon/libs/json" "github.com/line/ostracon/libs/log" ostos "github.com/line/ostracon/libs/os" ocproto "github.com/line/ostracon/proto/ostracon/types" tmdb "github.com/line/tm-db/v2" - "github.com/rakyll/statik/fs" - "github.com/spf13/cast" - - "github.com/line/lbm-sdk/x/feegrant" - feegrantkeeper "github.com/line/lbm-sdk/x/feegrant/keeper" - feegranttypes "github.com/line/lbm-sdk/x/feegrant/types" "github.com/line/lbm-sdk/baseapp" "github.com/line/lbm-sdk/client" @@ -42,6 +39,10 @@ import ( authtx "github.com/line/lbm-sdk/x/auth/tx" authtypes "github.com/line/lbm-sdk/x/auth/types" "github.com/line/lbm-sdk/x/auth/vesting" + vestingtypes "github.com/line/lbm-sdk/x/auth/vesting/types" + "github.com/line/lbm-sdk/x/authz" + authzkeeper "github.com/line/lbm-sdk/x/authz/keeper" + authzmodule "github.com/line/lbm-sdk/x/authz/module" "github.com/line/lbm-sdk/x/bank" bankkeeper "github.com/line/lbm-sdk/x/bank/keeper" banktypes "github.com/line/lbm-sdk/x/bank/types" @@ -64,6 +65,9 @@ import ( "github.com/line/lbm-sdk/x/evidence" evidencekeeper "github.com/line/lbm-sdk/x/evidence/keeper" evidencetypes "github.com/line/lbm-sdk/x/evidence/types" + "github.com/line/lbm-sdk/x/feegrant" + feegrantkeeper "github.com/line/lbm-sdk/x/feegrant/keeper" + feegrantmodule "github.com/line/lbm-sdk/x/feegrant/module" "github.com/line/lbm-sdk/x/genutil" genutiltypes "github.com/line/lbm-sdk/x/genutil/types" "github.com/line/lbm-sdk/x/gov" @@ -74,6 +78,8 @@ import ( ibctransfertypes "github.com/line/lbm-sdk/x/ibc/applications/transfer/types" ibc "github.com/line/lbm-sdk/x/ibc/core" ibcclient "github.com/line/lbm-sdk/x/ibc/core/02-client" + ibcclientclient "github.com/line/lbm-sdk/x/ibc/core/02-client/client" + ibcclienttypes "github.com/line/lbm-sdk/x/ibc/core/02-client/types" porttypes "github.com/line/lbm-sdk/x/ibc/core/05-port/types" ibchost "github.com/line/lbm-sdk/x/ibc/core/24-host" ibckeeper "github.com/line/lbm-sdk/x/ibc/core/keeper" @@ -132,15 +138,18 @@ var ( distrclient.ProposalHandler, upgradeclient.ProposalHandler, upgradeclient.CancelProposalHandler, + ibcclientclient.UpdateClientProposalHandler, + ibcclientclient.UpgradeProposalHandler, ), params.AppModuleBasic{}, crisis.AppModuleBasic{}, slashing.AppModuleBasic{}, ibc.AppModuleBasic{}, - feegrant.AppModuleBasic{}, + feegrantmodule.AppModuleBasic{}, upgrade.AppModuleBasic{}, evidence.AppModuleBasic{}, transfer.AppModuleBasic{}, + authzmodule.AppModuleBasic{}, vesting.AppModuleBasic{}, tokenmodule.AppModuleBasic{}, ) @@ -173,7 +182,7 @@ var ( type SimApp struct { *baseapp.BaseApp legacyAmino *codec.LegacyAmino - appCodec codec.Marshaler + appCodec codec.Codec interfaceRegistry types.InterfaceRegistry invCheckPeriod uint @@ -195,6 +204,7 @@ type SimApp struct { CrisisKeeper crisiskeeper.Keeper UpgradeKeeper upgradekeeper.Keeper ParamsKeeper paramskeeper.Keeper + AuthzKeeper authzkeeper.Keeper IBCKeeper *ibckeeper.Keeper // IBC Keeper must be a pointer in the app, so we can SetRouter on it correctly EvidenceKeeper evidencekeeper.Keeper TransferKeeper ibctransferkeeper.Keeper @@ -232,14 +242,13 @@ func NewSimApp( appOpts servertypes.AppOptions, baseAppOptions ...func(*baseapp.BaseApp), ) *SimApp { - // TODO: Remove cdc in favor of appCodec once all modules are migrated. appCodec := encodingConfig.Marshaler legacyAmino := encodingConfig.Amino interfaceRegistry := encodingConfig.InterfaceRegistry bApp := baseapp.NewBaseApp(appName, logger, db, encodingConfig.TxConfig.TxDecoder(), baseAppOptions...) bApp.SetCommitMultiStoreTracer(traceStore) - bApp.SetAppVersion(version.Version) + bApp.SetVersion(version.Version) bApp.SetInterfaceRegistry(interfaceRegistry) keys := sdk.NewKVStoreKeys( @@ -256,12 +265,16 @@ func NewSimApp( evidencetypes.StoreKey, ibctransfertypes.StoreKey, capabilitytypes.StoreKey, - feegranttypes.StoreKey, + feegrant.StoreKey, consortium.StoreKey, class.StoreKey, token.StoreKey, + authzkeeper.StoreKey, ) - memKeys := sdk.NewMemoryStoreKeys(capabilitytypes.MemStoreKey, "testing") + tkeys := sdk.NewTransientStoreKeys(paramstypes.TStoreKey) + // NOTE: The testingkey is just mounted for testing purposes. Actual applications should + // not include this key. + memKeys := sdk.NewMemoryStoreKeys(capabilitytypes.MemStoreKey, "testingkey") app := &SimApp{ BaseApp: bApp, @@ -273,7 +286,7 @@ func NewSimApp( memKeys: memKeys, } - app.ParamsKeeper = initParamsKeeper(appCodec, legacyAmino, keys[paramstypes.StoreKey]) + app.ParamsKeeper = initParamsKeeper(appCodec, legacyAmino, keys[paramstypes.StoreKey], tkeys[paramstypes.TStoreKey]) // set the BaseApp's parameter store bApp.SetParamStore(app.ParamsKeeper.Subspace(baseapp.Paramspace).WithKeyTable(paramskeeper.ConsensusParamsKeyTable())) @@ -285,6 +298,9 @@ func NewSimApp( // NOTE: the IBC mock keeper and application module is used only for testing core IBC. Do // note replicate if you do not need to test core IBC or light clients. scopedIBCMockKeeper := app.CapabilityKeeper.ScopeToModule(ibcmock.ModuleName) + // Applications that wish to enforce statically created ScopedKeepers should call `Seal` after creating + // their scoped modules in `NewApp` with `ScopeToModule` + app.CapabilityKeeper.Seal() // add keepers app.AccountKeeper = authkeeper.NewAccountKeeper( @@ -310,8 +326,8 @@ func NewSimApp( app.GetSubspace(crisistypes.ModuleName), invCheckPeriod, app.BankKeeper, authtypes.FeeCollectorName, ) - app.FeeGrantKeeper = feegrantkeeper.NewKeeper(appCodec, keys[feegranttypes.StoreKey], app.AccountKeeper) - app.UpgradeKeeper = upgradekeeper.NewKeeper(skipUpgradeHeights, keys[upgradetypes.StoreKey], appCodec, homePath) + app.FeeGrantKeeper = feegrantkeeper.NewKeeper(appCodec, keys[feegrant.StoreKey], app.AccountKeeper) + app.UpgradeKeeper = upgradekeeper.NewKeeper(skipUpgradeHeights, keys[upgradetypes.StoreKey], appCodec, homePath, app.BaseApp) app.ConsortiumKeeper = consortiumkeeper.NewKeeper(appCodec, keys[consortium.StoreKey], stakingKeeper) classKeeper := classkeeper.NewKeeper(appCodec, keys[class.StoreKey]) @@ -325,22 +341,31 @@ func NewSimApp( // Create IBC Keeper app.IBCKeeper = ibckeeper.NewKeeper( - appCodec, keys[ibchost.StoreKey], app.GetSubspace(ibchost.ModuleName), app.StakingKeeper, scopedIBCKeeper, + appCodec, keys[ibchost.StoreKey], app.GetSubspace(ibchost.ModuleName), app.StakingKeeper, app.UpgradeKeeper, scopedIBCKeeper, ) + app.AuthzKeeper = authzkeeper.NewKeeper(keys[authzkeeper.StoreKey], appCodec, app.BaseApp.MsgServiceRouter()) + // register the proposal types govRouter := govtypes.NewRouter() govRouter.AddRoute(govtypes.RouterKey, govtypes.ProposalHandler). AddRoute(paramproposal.RouterKey, params.NewParamChangeProposalHandler(app.ParamsKeeper)). AddRoute(distrtypes.RouterKey, distr.NewCommunityPoolSpendProposalHandler(app.DistrKeeper)). AddRoute(upgradetypes.RouterKey, upgrade.NewSoftwareUpgradeProposalHandler(app.UpgradeKeeper)). - AddRoute(ibchost.RouterKey, ibcclient.NewClientUpdateProposalHandler(app.IBCKeeper.ClientKeeper)). + AddRoute(ibcclienttypes.RouterKey, ibcclient.NewClientProposalHandler(app.IBCKeeper.ClientKeeper)). AddRoute(consortium.RouterKey, consortiumkeeper.NewProposalHandler(app.ConsortiumKeeper)) - app.GovKeeper = govkeeper.NewKeeper( + + govKeeper := govkeeper.NewKeeper( appCodec, keys[govtypes.StoreKey], app.GetSubspace(govtypes.ModuleName), app.AccountKeeper, app.BankKeeper, &stakingKeeper, govRouter, ) + app.GovKeeper = *govKeeper.SetHooks( + govtypes.NewMultiGovHooks( + // register the governance hooks + ), + ) + // Create Transfer Keepers app.TransferKeeper = ibctransferkeeper.NewKeeper( appCodec, keys[ibctransfertypes.StoreKey], app.GetSubspace(ibctransfertypes.ModuleName), @@ -384,7 +409,7 @@ func NewSimApp( bankplus.NewAppModule(appCodec, app.BankKeeper, app.AccountKeeper), capability.NewAppModule(appCodec, *app.CapabilityKeeper), crisis.NewAppModule(&app.CrisisKeeper, skipGenesisInvariants), - feegrant.NewAppModule(appCodec, app.AccountKeeper, app.BankKeeper, app.FeeGrantKeeper, app.interfaceRegistry), + feegrantmodule.NewAppModule(appCodec, app.AccountKeeper, app.BankKeeper, app.FeeGrantKeeper, app.interfaceRegistry), consortiummodule.NewAppModule(appCodec, app.ConsortiumKeeper, app.StakingKeeper), gov.NewAppModule(appCodec, app.GovKeeper, app.AccountKeeper, app.BankKeeper), mint.NewAppModule(appCodec, app.MintKeeper, app.AccountKeeper), @@ -396,6 +421,7 @@ func NewSimApp( ibc.NewAppModule(app.IBCKeeper), params.NewAppModule(app.ParamsKeeper), tokenmodule.NewAppModule(appCodec, app.TokenKeeper), + authzmodule.NewAppModule(appCodec, app.AuthzKeeper, app.AccountKeeper, app.BankKeeper, app.interfaceRegistry), transferModule, ) @@ -403,11 +429,51 @@ func NewSimApp( // there is nothing left over in the validator fee pool, so as to keep the // CanWithdrawInvariant invariant. // NOTE: staking module is required if HistoricalEntries param > 0 + // NOTE: capability module's beginblocker must come before any modules using capabilities (e.g. IBC) app.mm.SetOrderBeginBlockers( - upgradetypes.ModuleName, capabilitytypes.ModuleName, minttypes.ModuleName, distrtypes.ModuleName, slashingtypes.ModuleName, - evidencetypes.ModuleName, stakingtypes.ModuleName, ibchost.ModuleName, + upgradetypes.ModuleName, + capabilitytypes.ModuleName, + minttypes.ModuleName, + distrtypes.ModuleName, + slashingtypes.ModuleName, + evidencetypes.ModuleName, + stakingtypes.ModuleName, + authtypes.ModuleName, + banktypes.ModuleName, + govtypes.ModuleName, + crisistypes.ModuleName, + genutiltypes.ModuleName, + authz.ModuleName, + feegrant.ModuleName, + paramstypes.ModuleName, + vestingtypes.ModuleName, + ibchost.ModuleName, + ibctransfertypes.ModuleName, + consortium.ModuleName, + token.ModuleName, + ) + app.mm.SetOrderEndBlockers( + crisistypes.ModuleName, + govtypes.ModuleName, + stakingtypes.ModuleName, + capabilitytypes.ModuleName, + authtypes.ModuleName, + banktypes.ModuleName, + distrtypes.ModuleName, + slashingtypes.ModuleName, + minttypes.ModuleName, + genutiltypes.ModuleName, + evidencetypes.ModuleName, + authz.ModuleName, + feegrant.ModuleName, + paramstypes.ModuleName, + upgradetypes.ModuleName, + vestingtypes.ModuleName, + ibchost.ModuleName, + ibctransfertypes.ModuleName, + consortium.ModuleName, + token.ModuleName, ) - app.mm.SetOrderEndBlockers(crisistypes.ModuleName, govtypes.ModuleName, stakingtypes.ModuleName) // NOTE: The genutils module must occur after staking so that pools are // properly initialized with tokens from genesis accounts. @@ -424,15 +490,23 @@ func NewSimApp( govtypes.ModuleName, minttypes.ModuleName, crisistypes.ModuleName, - ibchost.ModuleName, genutiltypes.ModuleName, evidencetypes.ModuleName, ibctransfertypes.ModuleName, - feegranttypes.ModuleName, + authz.ModuleName, + feegrant.ModuleName, + paramstypes.ModuleName, + upgradetypes.ModuleName, + ibchost.ModuleName, + ibctransfertypes.ModuleName, + vestingtypes.ModuleName, consortium.ModuleName, token.ModuleName, ) + // Uncomment if you want to set a custom migration order here. + // app.mm.SetOrderMigrations(custom order) + app.mm.RegisterInvariants(&app.CrisisKeeper) app.mm.RegisterRoutes(app.Router(), app.QueryRouter(), encodingConfig.Amino) app.configurator = module.NewConfigurator(app.appCodec, app.MsgServiceRouter(), app.GRPCQueryRouter()) @@ -449,7 +523,7 @@ func NewSimApp( auth.NewAppModule(appCodec, app.AccountKeeper, authsims.RandomGenesisAccounts), bankplus.NewAppModule(appCodec, app.BankKeeper, app.AccountKeeper), capability.NewAppModule(appCodec, *app.CapabilityKeeper), - feegrant.NewAppModule(appCodec, app.AccountKeeper, app.BankKeeper, app.FeeGrantKeeper, app.interfaceRegistry), + feegrantmodule.NewAppModule(appCodec, app.AccountKeeper, app.BankKeeper, app.FeeGrantKeeper, app.interfaceRegistry), gov.NewAppModule(appCodec, app.GovKeeper, app.AccountKeeper, app.BankKeeper), mint.NewAppModule(appCodec, app.MintKeeper, app.AccountKeeper), staking.NewAppModule(appCodec, app.StakingKeeper, app.AccountKeeper, app.BankKeeper), @@ -457,6 +531,7 @@ func NewSimApp( slashing.NewAppModule(appCodec, app.SlashingKeeper, app.AccountKeeper, app.BankKeeper, app.StakingKeeper), params.NewAppModule(app.ParamsKeeper), evidence.NewAppModule(app.EvidenceKeeper), + authzmodule.NewAppModule(appCodec, app.AuthzKeeper, app.AccountKeeper, app.BankKeeper, app.interfaceRegistry), ibc.NewAppModule(app.IBCKeeper), transferModule, ) @@ -470,31 +545,30 @@ func NewSimApp( // initialize BaseApp app.SetInitChainer(app.InitChainer) app.SetBeginBlocker(app.BeginBlocker) - app.SetAnteHandler( - NewAnteHandler( - app.AccountKeeper, app.BankKeeper, app.FeeGrantKeeper, - ante.DefaultSigVerificationGasConsumer, - encodingConfig.TxConfig.SignModeHandler(), app.IBCKeeper.ChannelKeeper, - ), + + anteHandler, err := ante.NewAnteHandler( + ante.HandlerOptions{ + AccountKeeper: app.AccountKeeper, + BankKeeper: app.BankKeeper, + SignModeHandler: encodingConfig.TxConfig.SignModeHandler(), + FeegrantKeeper: app.FeeGrantKeeper, + SigGasConsumer: ante.DefaultSigVerificationGasConsumer, + }, ) + + if err != nil { + panic(err) + } + + app.SetAnteHandler(anteHandler) app.SetEndBlocker(app.EndBlocker) if loadLatest { if err := app.LoadLatestVersion(); err != nil { ostos.Exit(err.Error()) } - - // Initialize and seal the capability keeper so all persistent capabilities - // are loaded in-memory and prevent any further modules from creating scoped - // sub-keepers. - // This must be done during creation of baseapp rather than in InitChain so - // that in-memory capabilities get regenerated on app restart. - // Note that since this reads from the store, we can only perform it when - // `loadLatest` is set to true. - ctx := app.BaseApp.NewUncachedContext(true, ocproto.Header{}) - app.CapabilityKeeper.InitializeAndSeal(ctx) - // Initialize the keeper of bankkeeper + ctx := app.BaseApp.NewUncachedContext(true, ocproto.Header{}) app.BankKeeper.(bankpluskeeper.Keeper).InitializeBankPlus(ctx) } @@ -508,14 +582,6 @@ func NewSimApp( return app } -// MakeCodecs constructs the *std.Codec and *codec.LegacyAmino instances used by -// simapp. It is useful for tests and clients who do not want to construct the -// full simapp -func MakeCodecs() (codec.Marshaler, *codec.LegacyAmino) { - config := MakeTestEncodingConfig() - return config.Marshaler, config.Amino -} - // Name returns the name of the App func (app *SimApp) Name() string { return app.BaseApp.Name() } @@ -577,7 +643,7 @@ func (app *SimApp) LegacyAmino() *codec.LegacyAmino { // // NOTE: This is solely to be used for testing purposes as it may be desirable // for modules to register their own custom testing types. -func (app *SimApp) AppCodec() codec.Marshaler { +func (app *SimApp) AppCodec() codec.Codec { return app.appCodec } @@ -603,7 +669,7 @@ func (app *SimApp) GetMemKey(storeKey string) *sdk.MemoryStoreKey { // GetSubspace returns a param subspace for a given module name. // // NOTE: This is solely to be used for testing purposes. -func (app *SimApp) GetSubspace(moduleName string) *paramstypes.Subspace { +func (app *SimApp) GetSubspace(moduleName string) paramstypes.Subspace { subspace, _ := app.ParamsKeeper.GetSubspace(moduleName) return subspace } @@ -645,28 +711,6 @@ func (app *SimApp) RegisterTendermintService(clientCtx client.Context) { tmservice.RegisterTendermintService(app.BaseApp.GRPCQueryRouter(), clientCtx, app.interfaceRegistry) } -// RunMigrations performs in-place store migrations for all modules. This -// function MUST be only called by x/upgrade UpgradeHandler. -// -// `migrateFromVersions` is a map of moduleName to fromVersion (unit64), where -// fromVersion denotes the version from which we should migrate the module, the -// target version being the module's latest ConsensusVersion. -// -// Example: -// cfg := module.NewConfigurator(...) -// app.UpgradeKeeper.SetUpgradeHandler("store-migration", func(ctx sdk.Context, plan upgradetypes.Plan) { -// err := app.RunMigrations(ctx, module.VersionMap{ -// "bank": 1, // Migrate x/bank from v1 to current x/bank's ConsensusVersion -// "staking": 8, // Migrate x/staking from v8 to current x/staking's ConsensusVersion -// }) -// if err != nil { -// panic(err) -// } -// }) -func (app *SimApp) RunMigrations(ctx sdk.Context, migrateFromVersions module.VersionMap) (module.VersionMap, error) { - return app.mm.RunMigrations(ctx, app.configurator, migrateFromVersions) -} - // RegisterSwaggerAPI registers swagger route with API Server func RegisterSwaggerAPI(ctx client.Context, rtr *mux.Router) { statikFS, err := fs.New() @@ -688,8 +732,8 @@ func GetMaccPerms() map[string][]string { } // initParamsKeeper init params keeper and its subspaces -func initParamsKeeper(appCodec codec.BinaryMarshaler, legacyAmino *codec.LegacyAmino, key sdk.StoreKey) paramskeeper.Keeper { - paramsKeeper := paramskeeper.NewKeeper(appCodec, legacyAmino, key) +func initParamsKeeper(appCodec codec.BinaryCodec, legacyAmino *codec.LegacyAmino, key, tkey sdk.StoreKey) paramskeeper.Keeper { + paramsKeeper := paramskeeper.NewKeeper(appCodec, legacyAmino, key, tkey) paramsKeeper.Subspace(authtypes.ModuleName) paramsKeeper.Subspace(banktypes.ModuleName) diff --git a/simapp/app_test.go b/simapp/app_test.go index c060e09ff9..5476233503 100644 --- a/simapp/app_test.go +++ b/simapp/app_test.go @@ -6,26 +6,28 @@ import ( "testing" "github.com/golang/mock/gomock" - "github.com/line/ostracon/libs/log" - ocproto "github.com/line/ostracon/proto/ostracon/types" - "github.com/line/tm-db/v2/memdb" "github.com/stretchr/testify/require" abci "github.com/line/ostracon/abci/types" + "github.com/line/ostracon/libs/log" + ocproto "github.com/line/ostracon/proto/ostracon/types" + "github.com/line/tm-db/v2/memdb" "github.com/line/lbm-sdk/baseapp" "github.com/line/lbm-sdk/tests/mocks" sdk "github.com/line/lbm-sdk/types" "github.com/line/lbm-sdk/types/module" - "github.com/line/lbm-sdk/x/auth" "github.com/line/lbm-sdk/x/auth/vesting" + authz_m "github.com/line/lbm-sdk/x/authz/module" + "github.com/line/lbm-sdk/x/bank" banktypes "github.com/line/lbm-sdk/x/bank/types" "github.com/line/lbm-sdk/x/capability" consortiummodule "github.com/line/lbm-sdk/x/consortium/module" "github.com/line/lbm-sdk/x/crisis" "github.com/line/lbm-sdk/x/distribution" "github.com/line/lbm-sdk/x/evidence" + feegrantmodule "github.com/line/lbm-sdk/x/feegrant/module" "github.com/line/lbm-sdk/x/genutil" "github.com/line/lbm-sdk/x/gov" transfer "github.com/line/lbm-sdk/x/ibc/applications/transfer" @@ -34,6 +36,7 @@ import ( "github.com/line/lbm-sdk/x/params" "github.com/line/lbm-sdk/x/slashing" "github.com/line/lbm-sdk/x/staking" + tokenmodule "github.com/line/lbm-sdk/x/token/module" "github.com/line/lbm-sdk/x/upgrade" ) @@ -43,10 +46,7 @@ func TestSimAppExportAndBlockedAddrs(t *testing.T) { app := NewSimApp(log.NewOCLogger(log.NewSyncWriter(os.Stdout)), db, nil, true, map[int64]bool{}, DefaultNodeHome, 0, encCfg, EmptyAppOptions{}) for acc := range maccPerms { - ex, _ := allowedReceivingModAcc[acc] - require.Equal(t, - !ex, - app.BankKeeper.BlockedAddr(app.AccountKeeper.GetModuleAddress(acc)), + require.Equal(t, !allowedReceivingModAcc[acc], app.BankKeeper.BlockedAddr(app.AccountKeeper.GetModuleAddress(acc)), "ensure that blocked addresses are properly set in bank keeper") } @@ -119,6 +119,7 @@ func TestRunMigrations(t *testing.T) { "bank", 0, true, "module migration versions should start at 1: invalid version", false, "", 0, }, + // TODO(dudong2): bank module has no migration func, so comment out tests // { // "throws error on RunMigrations if no migration registered for bank", // "", 1, @@ -165,11 +166,12 @@ func TestRunMigrations(t *testing.T) { // Run migrations only for bank. That's why we put the initial // version for bank as 1, and for all other modules, we put as // their latest ConsensusVersion. - _, err = app.RunMigrations( - app.NewContext(true, ocproto.Header{Height: app.LastBlockHeight()}), + _, err = app.mm.RunMigrations( + app.NewContext(true, ocproto.Header{Height: app.LastBlockHeight()}), app.configurator, module.VersionMap{ "bank": 1, "auth": auth.AppModule{}.ConsensusVersion(), + "authz": authz_m.AppModule{}.ConsensusVersion(), "staking": staking.AppModule{}.ConsensusVersion(), "mint": mint.AppModule{}.ConsensusVersion(), "distribution": distribution.AppModule{}.ConsensusVersion(), @@ -179,18 +181,21 @@ func TestRunMigrations(t *testing.T) { "ibc": ibc.AppModule{}.ConsensusVersion(), "upgrade": upgrade.AppModule{}.ConsensusVersion(), "vesting": vesting.AppModule{}.ConsensusVersion(), + "feegrant": feegrantmodule.AppModule{}.ConsensusVersion(), "transfer": transfer.AppModule{}.ConsensusVersion(), "evidence": evidence.AppModule{}.ConsensusVersion(), "crisis": crisis.AppModule{}.ConsensusVersion(), "genutil": genutil.AppModule{}.ConsensusVersion(), "capability": capability.AppModule{}.ConsensusVersion(), "consortium": consortiummodule.AppModule{}.ConsensusVersion(), + "token": tokenmodule.AppModule{}.ConsensusVersion(), }, ) if tc.expRunErr { require.EqualError(t, err, tc.expRunErrMsg) } else { require.NoError(t, err) + // Make sure bank's migration is called. require.Equal(t, tc.expCalled, called) } }) @@ -218,11 +223,11 @@ func TestInitGenesisOnMigration(t *testing.T) { // Run migrations only for "mock" module. We exclude it from // the VersionMap to simulate upgrading with a new module. - _, err := app.RunMigrations( - app.NewContext(true, ocproto.Header{Height: app.LastBlockHeight()}), + _, err := app.mm.RunMigrations(ctx, app.configurator, module.VersionMap{ - "bank": 1, + "bank": bank.AppModule{}.ConsensusVersion(), "auth": auth.AppModule{}.ConsensusVersion(), + "authz": authz_m.AppModule{}.ConsensusVersion(), "staking": staking.AppModule{}.ConsensusVersion(), "mint": mint.AppModule{}.ConsensusVersion(), "distribution": distribution.AppModule{}.ConsensusVersion(), @@ -238,6 +243,7 @@ func TestInitGenesisOnMigration(t *testing.T) { "genutil": genutil.AppModule{}.ConsensusVersion(), "capability": capability.AppModule{}.ConsensusVersion(), "consortium": consortiummodule.AppModule{}.ConsensusVersion(), + "token": tokenmodule.AppModule{}.ConsensusVersion(), }, ) diff --git a/simapp/encoding.go b/simapp/encoding.go index 9fffb37851..bd6ed744ea 100644 --- a/simapp/encoding.go +++ b/simapp/encoding.go @@ -5,9 +5,9 @@ import ( "github.com/line/lbm-sdk/std" ) -// MakeTestEncodingConfig creates an EncodingConfig for testing. -// This function should be used only internally (in the SDK). -// App user should'nt create new codecs - use the app.AppCodec instead. +// MakeTestEncodingConfig creates an EncodingConfig for testing. This function +// should be used only in tests or when creating a new app instance (NewApp*()). +// App user shouldn't create new codecs - use the app.AppCodec instead. // [DEPRECATED] func MakeTestEncodingConfig() simappparams.EncodingConfig { encodingConfig := simappparams.MakeTestEncodingConfig() diff --git a/simapp/export.go b/simapp/export.go index 82c601a356..2a87e49250 100644 --- a/simapp/export.go +++ b/simapp/export.go @@ -145,7 +145,7 @@ func (app *SimApp) prepForZeroHeightGenesis(ctx sdk.Context, jailAllowedAddrs [] counter := int16(0) for ; iter.Valid(); iter.Next() { - addr := sdk.ValAddress(iter.Key()[1:]) + addr := sdk.ValAddress(stakingtypes.AddressFromValidatorsKey(iter.Key())) validator, found := app.StakingKeeper.GetValidator(ctx, addr) if !found { panic("expected validator, not found") diff --git a/simapp/genesis.go b/simapp/genesis.go index 4c3a94948e..1552ba9643 100644 --- a/simapp/genesis.go +++ b/simapp/genesis.go @@ -6,7 +6,7 @@ import ( "github.com/line/lbm-sdk/codec" ) -// The genesis state of the blockchain is represented here as a map of raw json +// GenesisState of the blockchain is represented here as a map of raw json // messages key'd by a identifier string. // The identifier is used to determine which module genesis information belongs // to so it may be appropriately routed during init chain. @@ -16,6 +16,6 @@ import ( type GenesisState map[string]json.RawMessage // NewDefaultGenesisState generates the default state for the application. -func NewDefaultGenesisState(cdc codec.JSONMarshaler) GenesisState { +func NewDefaultGenesisState(cdc codec.JSONCodec) GenesisState { return ModuleBasics.DefaultGenesis(cdc) } diff --git a/simapp/params/encoding.go b/simapp/params/encoding.go index 834bc1d7f4..2bd6f23de9 100644 --- a/simapp/params/encoding.go +++ b/simapp/params/encoding.go @@ -10,7 +10,8 @@ import ( // This is provided for compatibility between protobuf and amino implementations. type EncodingConfig struct { InterfaceRegistry types.InterfaceRegistry - Marshaler codec.Marshaler - TxConfig client.TxConfig - Amino *codec.LegacyAmino + // NOTE: this field will be renamed to Codec + Marshaler codec.Codec + TxConfig client.TxConfig + Amino *codec.LegacyAmino } diff --git a/simapp/params/proto.go b/simapp/params/proto.go index fb4ba5edb9..b1b552c619 100644 --- a/simapp/params/proto.go +++ b/simapp/params/proto.go @@ -1,3 +1,4 @@ +//go:build !test_amino // +build !test_amino package params diff --git a/simapp/sim_bench_test.go b/simapp/sim_bench_test.go index f8c345e637..22b813bb34 100644 --- a/simapp/sim_bench_test.go +++ b/simapp/sim_bench_test.go @@ -14,11 +14,16 @@ import ( // Profile with: // /usr/local/go/bin/go test -benchmem -run=^$ github.com/line/lbm-sdk/simapp -bench ^BenchmarkFullAppSimulation$ -Commit=true -cpuprofile cpu.out func BenchmarkFullAppSimulation(b *testing.B) { - config, db, dir, logger, _, err := SetupSimulation("goleveldb-app-sim", "Simulation") + b.ReportAllocs() + config, db, dir, logger, skip, err := SetupSimulation("goleveldb-app-sim", "Simulation") if err != nil { b.Fatalf("simulation setup failed: %s", err.Error()) } + if skip { + b.Skip("skipping benchmark application simulation") + } + defer func() { db.Close() err = os.RemoveAll(dir) @@ -57,11 +62,16 @@ func BenchmarkFullAppSimulation(b *testing.B) { } func BenchmarkInvariants(b *testing.B) { - config, db, dir, logger, _, err := SetupSimulation("leveldb-app-invariant-bench", "Simulation") + b.ReportAllocs() + config, db, dir, logger, skip, err := SetupSimulation("leveldb-app-invariant-bench", "Simulation") if err != nil { b.Fatalf("simulation setup failed: %s", err.Error()) } + if skip { + b.Skip("skipping benchmark application simulation") + } + config.AllInvariants = false defer func() { diff --git a/simapp/sim_test.go b/simapp/sim_test.go index 07f4a3a0b2..649596b7ef 100644 --- a/simapp/sim_test.go +++ b/simapp/sim_test.go @@ -7,20 +7,21 @@ import ( "os" "testing" + "github.com/stretchr/testify/require" + abci "github.com/line/ostracon/abci/types" "github.com/line/ostracon/libs/log" ocproto "github.com/line/ostracon/proto/ostracon/types" "github.com/line/tm-db/v2/memdb" - "github.com/stretchr/testify/require" - - "github.com/line/lbm-sdk/store/cache" "github.com/line/lbm-sdk/baseapp" "github.com/line/lbm-sdk/simapp/helpers" "github.com/line/lbm-sdk/store" + "github.com/line/lbm-sdk/store/cache" sdk "github.com/line/lbm-sdk/types" simtypes "github.com/line/lbm-sdk/types/simulation" authtypes "github.com/line/lbm-sdk/x/auth/types" + authzkeeper "github.com/line/lbm-sdk/x/authz/keeper" banktypes "github.com/line/lbm-sdk/x/bank/types" capabilitytypes "github.com/line/lbm-sdk/x/capability/types" distrtypes "github.com/line/lbm-sdk/x/distribution/types" @@ -180,6 +181,7 @@ func TestAppImportExport(t *testing.T) { {app.keys[capabilitytypes.StoreKey], newApp.keys[capabilitytypes.StoreKey], [][]byte{}}, {app.keys[ibchost.StoreKey], newApp.keys[ibchost.StoreKey], [][]byte{}}, {app.keys[ibctransfertypes.StoreKey], newApp.keys[ibctransfertypes.StoreKey], [][]byte{}}, + {app.keys[authzkeeper.StoreKey], newApp.keys[authzkeeper.StoreKey], [][]byte{}}, } for _, skp := range storeKeysPrefixes { diff --git a/simapp/simd/cmd/genaccounts.go b/simapp/simd/cmd/genaccounts.go index a79d93bfb1..b233b97a25 100644 --- a/simapp/simd/cmd/genaccounts.go +++ b/simapp/simd/cmd/genaccounts.go @@ -10,7 +10,6 @@ import ( "github.com/line/lbm-sdk/client" "github.com/line/lbm-sdk/client/flags" - "github.com/line/lbm-sdk/codec" "github.com/line/lbm-sdk/crypto/keyring" "github.com/line/lbm-sdk/server" sdk "github.com/line/lbm-sdk/types" @@ -40,12 +39,8 @@ contain valid denominations. Accounts may optionally be supplied with vesting pa Args: cobra.ExactArgs(2), RunE: func(cmd *cobra.Command, args []string) error { clientCtx := client.GetClientContextFromCmd(cmd) - depCdc := clientCtx.JSONMarshaler - cdc := depCdc.(codec.Marshaler) - serverCtx := server.GetServerContextFromCmd(cmd) config := serverCtx.Config - config.SetRoot(clientCtx.HomeDir) var kr keyring.Keyring @@ -123,7 +118,7 @@ contain valid denominations. Accounts may optionally be supplied with vesting pa return fmt.Errorf("failed to unmarshal genesis state: %w", err) } - authGenState := authtypes.GetGenesisStateFromAppState(cdc, appState) + authGenState := authtypes.GetGenesisStateFromAppState(clientCtx.Codec, appState) accs, err := authtypes.UnpackAccounts(authGenState.Accounts) if err != nil { @@ -145,19 +140,19 @@ contain valid denominations. Accounts may optionally be supplied with vesting pa } authGenState.Accounts = genAccs - authGenStateBz, err := cdc.MarshalJSON(&authGenState) + authGenStateBz, err := clientCtx.Codec.MarshalJSON(&authGenState) if err != nil { return fmt.Errorf("failed to marshal auth genesis state: %w", err) } appState[authtypes.ModuleName] = authGenStateBz - bankGenState := banktypes.GetGenesisStateFromAppState(cdc, appState) + bankGenState := banktypes.GetGenesisStateFromAppState(clientCtx.Codec, appState) bankGenState.Balances = append(bankGenState.Balances, balances) bankGenState.Balances = banktypes.SanitizeGenesisBalances(bankGenState.Balances) bankGenState.Supply = bankGenState.Supply.Add(balances.Coins...) - bankGenStateBz, err := cdc.MarshalJSON(bankGenState) + bankGenStateBz, err := clientCtx.Codec.MarshalJSON(bankGenState) if err != nil { return fmt.Errorf("failed to marshal bank genesis state: %w", err) } diff --git a/simapp/simd/cmd/genaccounts_test.go b/simapp/simd/cmd/genaccounts_test.go index d0edeacc62..a977814ff3 100644 --- a/simapp/simd/cmd/genaccounts_test.go +++ b/simapp/simd/cmd/genaccounts_test.go @@ -5,20 +5,20 @@ import ( "fmt" "testing" - "github.com/line/lbm-sdk/crypto/hd" - "github.com/line/lbm-sdk/crypto/keyring" - sdk "github.com/line/lbm-sdk/types" - - "github.com/line/ostracon/libs/log" "github.com/spf13/viper" "github.com/stretchr/testify/require" + "github.com/line/ostracon/libs/log" + "github.com/line/lbm-sdk/client" "github.com/line/lbm-sdk/client/flags" + "github.com/line/lbm-sdk/crypto/hd" + "github.com/line/lbm-sdk/crypto/keyring" "github.com/line/lbm-sdk/server" "github.com/line/lbm-sdk/simapp" simcmd "github.com/line/lbm-sdk/simapp/simd/cmd" "github.com/line/lbm-sdk/testutil/testdata" + sdk "github.com/line/lbm-sdk/types" "github.com/line/lbm-sdk/types/module" "github.com/line/lbm-sdk/x/genutil" genutiltest "github.com/line/lbm-sdk/x/genutil/client/testutil" @@ -73,18 +73,18 @@ func TestAddGenesisAccountCmd(t *testing.T) { cfg, err := genutiltest.CreateDefaultTendermintConfig(home) require.NoError(t, err) - appCodec, _ := simapp.MakeCodecs() + appCodec := simapp.MakeTestEncodingConfig().Marshaler err = genutiltest.ExecInitCmd(testMbm, home, appCodec) require.NoError(t, err) serverCtx := server.NewContext(viper.New(), cfg, logger) - clientCtx := client.Context{}.WithJSONMarshaler(appCodec).WithHomeDir(home) + clientCtx := client.Context{}.WithCodec(appCodec).WithHomeDir(home) if tc.withKeyring { path := hd.CreateHDPath(118, 0, 0).String() kr, err := keyring.New(sdk.KeyringServiceName(), keyring.BackendMemory, home, nil) require.NoError(t, err) - _, _, err = kr.NewMnemonic(tc.addr, keyring.English, path, hd.Secp256k1) + _, _, err = kr.NewMnemonic(tc.addr, keyring.English, path, keyring.DefaultBIP39Passphrase, hd.Secp256k1) require.NoError(t, err) clientCtx = clientCtx.WithKeyring(kr) } diff --git a/simapp/simd/cmd/root.go b/simapp/simd/cmd/root.go index 347a02b65d..7d99454c10 100644 --- a/simapp/simd/cmd/root.go +++ b/simapp/simd/cmd/root.go @@ -6,13 +6,14 @@ import ( "os" "path/filepath" - ostcli "github.com/line/ostracon/libs/cli" - "github.com/line/ostracon/libs/log" - tmdb "github.com/line/tm-db/v2" "github.com/spf13/cast" "github.com/spf13/cobra" "github.com/spf13/viper" + ostcli "github.com/line/ostracon/libs/cli" + "github.com/line/ostracon/libs/log" + tmdb "github.com/line/tm-db/v2" + "github.com/line/lbm-sdk/baseapp" "github.com/line/lbm-sdk/client" config "github.com/line/lbm-sdk/client/config" @@ -21,16 +22,15 @@ import ( "github.com/line/lbm-sdk/client/keys" "github.com/line/lbm-sdk/client/rpc" "github.com/line/lbm-sdk/server" + serverconfig "github.com/line/lbm-sdk/server/config" servertypes "github.com/line/lbm-sdk/server/types" "github.com/line/lbm-sdk/simapp" "github.com/line/lbm-sdk/simapp/params" "github.com/line/lbm-sdk/snapshots" "github.com/line/lbm-sdk/store" sdk "github.com/line/lbm-sdk/types" - authclient "github.com/line/lbm-sdk/x/auth/client" authcmd "github.com/line/lbm-sdk/x/auth/client/cli" "github.com/line/lbm-sdk/x/auth/types" - vestingcli "github.com/line/lbm-sdk/x/auth/vesting/client/cli" banktypes "github.com/line/lbm-sdk/x/bank/types" "github.com/line/lbm-sdk/x/crisis" genutilcli "github.com/line/lbm-sdk/x/genutil/client/cli" @@ -41,7 +41,7 @@ import ( func NewRootCmd() (*cobra.Command, params.EncodingConfig) { encodingConfig := simapp.MakeTestEncodingConfig() initClientCtx := client.Context{}. - WithJSONMarshaler(encodingConfig.Marshaler). + WithCodec(encodingConfig.Marshaler). WithInterfaceRegistry(encodingConfig.InterfaceRegistry). WithTxConfig(encodingConfig.TxConfig). WithLegacyAmino(encodingConfig.Amino). @@ -72,7 +72,9 @@ func NewRootCmd() (*cobra.Command, params.EncodingConfig) { return err } - return server.InterceptConfigsPreRunHandler(cmd) + customAppTemplate, customAppConfig := initAppConfig() + + return server.InterceptConfigsPreRunHandler(cmd, customAppTemplate, customAppConfig) }, } @@ -81,8 +83,63 @@ func NewRootCmd() (*cobra.Command, params.EncodingConfig) { return rootCmd, encodingConfig } +// initAppConfig helps to override default appConfig template and configs. +// return "", nil if no custom configuration is required for the application. +func initAppConfig() (string, interface{}) { + // The following code snippet is just for reference. + + // WASMConfig defines configuration for the wasm module. + type WASMConfig struct { + // This is the maximum sdk gas (wasm and storage) that we allow for any x/wasm "smart" queries + QueryGasLimit uint64 `mapstructure:"query_gas_limit"` + + // Address defines the gRPC-web server to listen on + LruSize uint64 `mapstructure:"lru_size"` + } + + type CustomAppConfig struct { + serverconfig.Config + + WASM WASMConfig `mapstructure:"wasm"` + } + + // Optionally allow the chain developer to overwrite the SDK's default + // server config. + srvCfg := serverconfig.DefaultConfig() + // The SDK's default minimum gas price is set to "" (empty value) inside + // app.toml. If left empty by validators, the node will halt on startup. + // However, the chain developer can set a default app.toml value for their + // validators here. + // + // In summary: + // - if you leave srvCfg.MinGasPrices = "", all validators MUST tweak their + // own app.toml config, + // - if you set srvCfg.MinGasPrices non-empty, validators CAN tweak their + // own app.toml to override, or use this default value. + // + // In simapp, we set the min gas prices to 0. + srvCfg.MinGasPrices = "0stake" + + customAppConfig := CustomAppConfig{ + Config: *srvCfg, + WASM: WASMConfig{ + LruSize: 1, + QueryGasLimit: 300000, + }, + } + + customAppTemplate := serverconfig.DefaultConfigTemplate + ` +[wasm] +# This is the maximum sdk gas (wasm and storage) that we allow for any x/wasm "smart" queries +query_gas_limit = 300000 +# This is the number of wasm vm instances we keep cached in memory for speed-up +# Warning: this is currently unstable and may lead to crashes, best to keep for 0 unless testing locally +lru_size = 0` + + return customAppTemplate, customAppConfig +} + func initRootCmd(rootCmd *cobra.Command, encodingConfig params.EncodingConfig) { - authclient.Codec = encodingConfig.Marshaler cfg := sdk.GetConfig() cfg.Seal() @@ -109,6 +166,9 @@ func initRootCmd(rootCmd *cobra.Command, encodingConfig params.EncodingConfig) { txCommand(), keys.Commands(simapp.DefaultNodeHome), ) + + // add rosetta + rootCmd.AddCommand(server.RosettaCommand(encodingConfig.InterfaceRegistry, encodingConfig.Marshaler)) } func addModuleInitFlags(startCmd *cobra.Command) { @@ -154,12 +214,9 @@ func txCommand() *cobra.Command { authcmd.GetMultiSignCommand(), authcmd.GetMultiSignBatchCmd(), authcmd.GetValidateSignaturesCommand(), - flags.LineBreak, authcmd.GetBroadcastCommand(), authcmd.GetEncodeCommand(), authcmd.GetDecodeCommand(), - flags.LineBreak, - vestingcli.GetTxCmd(), ) simapp.ModuleBasics.AddTxCommands(cmd) diff --git a/simapp/simd/cmd/testnet.go b/simapp/simd/cmd/testnet.go index 7016e54ed8..805bd8eea9 100644 --- a/simapp/simd/cmd/testnet.go +++ b/simapp/simd/cmd/testnet.go @@ -10,12 +10,13 @@ import ( "os" "path/filepath" + "github.com/spf13/cobra" + ostconfig "github.com/line/ostracon/config" ostos "github.com/line/ostracon/libs/os" ostrand "github.com/line/ostracon/libs/rand" "github.com/line/ostracon/types" osttime "github.com/line/ostracon/types/time" - "github.com/spf13/cobra" "github.com/line/lbm-sdk/client" "github.com/line/lbm-sdk/client/flags" @@ -25,6 +26,7 @@ import ( cryptotypes "github.com/line/lbm-sdk/crypto/types" "github.com/line/lbm-sdk/server" srvconfig "github.com/line/lbm-sdk/server/config" + "github.com/line/lbm-sdk/testutil" sdk "github.com/line/lbm-sdk/types" "github.com/line/lbm-sdk/types/module" authtypes "github.com/line/lbm-sdk/x/auth/types" @@ -178,7 +180,7 @@ func InitTestnet( return err } - addr, secret, err := server.GenerateSaveCoinKey(kb, nodeDirName, true, algo) + addr, secret, err := testutil.GenerateSaveCoinKey(kb, nodeDirName, "", true, algo) if err != nil { _ = os.RemoveAll(outputDir) return err @@ -196,17 +198,17 @@ func InitTestnet( return err } - accTokens := sdk.TokensFromConsensusPower(1000) - accStakingTokens := sdk.TokensFromConsensusPower(500) + accTokens := sdk.TokensFromConsensusPower(1000, sdk.DefaultPowerReduction) + accStakingTokens := sdk.TokensFromConsensusPower(500, sdk.DefaultPowerReduction) coins := sdk.Coins{ - sdk.NewCoin(fmt.Sprintf("%stoken", nodeDirName), accTokens), + sdk.NewCoin("testtoken", accTokens), sdk.NewCoin(sdk.DefaultBondDenom, accStakingTokens), } genBalances = append(genBalances, banktypes.Balance{Address: addr.String(), Coins: coins.Sort()}) genAccounts = append(genAccounts, authtypes.NewBaseAccount(addr, nil, 0, 0)) - valTokens := sdk.TokensFromConsensusPower(100) + valTokens := sdk.TokensFromConsensusPower(100, sdk.DefaultPowerReduction) createValMsg, err := stakingtypes.NewMsgCreateValidator( addr.ToValAddress(), valPubKeys[i], @@ -271,11 +273,11 @@ func initGenFiles( genFiles []string, numValidators int, ) error { - appGenState := mbm.DefaultGenesis(clientCtx.JSONMarshaler) + appGenState := mbm.DefaultGenesis(clientCtx.Codec) // set the accounts in the genesis state var authGenState authtypes.GenesisState - clientCtx.JSONMarshaler.MustUnmarshalJSON(appGenState[authtypes.ModuleName], &authGenState) + clientCtx.Codec.MustUnmarshalJSON(appGenState[authtypes.ModuleName], &authGenState) accounts, err := authtypes.PackAccounts(genAccounts) if err != nil { @@ -283,17 +285,17 @@ func initGenFiles( } authGenState.Accounts = accounts - appGenState[authtypes.ModuleName] = clientCtx.JSONMarshaler.MustMarshalJSON(&authGenState) + appGenState[authtypes.ModuleName] = clientCtx.Codec.MustMarshalJSON(&authGenState) // set the balances in the genesis state var bankGenState banktypes.GenesisState - clientCtx.JSONMarshaler.MustUnmarshalJSON(appGenState[banktypes.ModuleName], &bankGenState) + clientCtx.Codec.MustUnmarshalJSON(appGenState[banktypes.ModuleName], &bankGenState) bankGenState.Balances = banktypes.SanitizeGenesisBalances(genBalances) for _, bal := range bankGenState.Balances { bankGenState.Supply = bankGenState.Supply.Add(bal.Coins...) } - appGenState[banktypes.ModuleName] = clientCtx.JSONMarshaler.MustMarshalJSON(&bankGenState) + appGenState[banktypes.ModuleName] = clientCtx.Codec.MustMarshalJSON(&bankGenState) appGenStateJSON, err := json.MarshalIndent(appGenState, "", " ") if err != nil { @@ -340,7 +342,7 @@ func collectGenFiles( return err } - nodeAppState, err := genutil.GenAppStateFromConfig(clientCtx.JSONMarshaler, clientCtx.TxConfig, nodeConfig, initCfg, *genDoc, genBalIterator) + nodeAppState, err := genutil.GenAppStateFromConfig(clientCtx.Codec, clientCtx.TxConfig, nodeConfig, initCfg, *genDoc, genBalIterator) if err != nil { return err } diff --git a/simapp/simd/cmd/testnet_test.go b/simapp/simd/cmd/testnet_test.go index 7ef3bf0184..cdce227f6a 100644 --- a/simapp/simd/cmd/testnet_test.go +++ b/simapp/simd/cmd/testnet_test.go @@ -5,10 +5,11 @@ import ( "fmt" "testing" - "github.com/line/ostracon/libs/log" "github.com/spf13/viper" "github.com/stretchr/testify/require" + "github.com/line/ostracon/libs/log" + "github.com/line/lbm-sdk/client" "github.com/line/lbm-sdk/client/flags" "github.com/line/lbm-sdk/server" @@ -30,7 +31,7 @@ func Test_TestnetCmd(t *testing.T) { serverCtx := server.NewContext(viper.New(), cfg, logger) clientCtx := client.Context{}. - WithJSONMarshaler(encodingConfig.Marshaler). + WithCodec(encodingConfig.Marshaler). WithHomeDir(home). WithTxConfig(encodingConfig.TxConfig) diff --git a/simapp/state.go b/simapp/state.go index 8622690857..cc75ea8b3a 100644 --- a/simapp/state.go +++ b/simapp/state.go @@ -14,15 +14,18 @@ import ( "github.com/line/lbm-sdk/codec" "github.com/line/lbm-sdk/crypto/keys/secp256k1" simappparams "github.com/line/lbm-sdk/simapp/params" + sdk "github.com/line/lbm-sdk/types" "github.com/line/lbm-sdk/types/module" simtypes "github.com/line/lbm-sdk/types/simulation" authtypes "github.com/line/lbm-sdk/x/auth/types" + banktypes "github.com/line/lbm-sdk/x/bank/types" + stakingtypes "github.com/line/lbm-sdk/x/staking/types" ) // AppStateFn returns the initial application state using a genesis or the simulation parameters. // It panics if the user provides files for both of them. // If a file is not given for the genesis or the sim params, it creates a randomized one. -func AppStateFn(cdc codec.JSONMarshaler, simManager *module.SimulationManager) simtypes.AppStateFn { +func AppStateFn(cdc codec.JSONCodec, simManager *module.SimulationManager) simtypes.AppStateFn { return func(r *rand.Rand, accs []simtypes.Account, config simtypes.Config, ) (appState json.RawMessage, simAccs []simtypes.Account, chainID string, genesisTimestamp time.Time) { @@ -68,6 +71,57 @@ func AppStateFn(cdc codec.JSONMarshaler, simManager *module.SimulationManager) s appState, simAccs = AppStateRandomizedFn(simManager, r, cdc, accs, genesisTimestamp, appParams) } + rawState := make(map[string]json.RawMessage) + err := json.Unmarshal(appState, &rawState) + if err != nil { + panic(err) + } + + stakingStateBz, ok := rawState[stakingtypes.ModuleName] + if !ok { + panic("staking genesis state is missing") + } + + stakingState := new(stakingtypes.GenesisState) + err = cdc.UnmarshalJSON(stakingStateBz, stakingState) + if err != nil { + panic(err) + } + // compute not bonded balance + notBondedTokens := sdk.ZeroInt() + for _, val := range stakingState.Validators { + if val.Status != stakingtypes.Unbonded { + continue + } + notBondedTokens = notBondedTokens.Add(val.GetTokens()) + } + notBondedCoins := sdk.NewCoin(stakingState.Params.BondDenom, notBondedTokens) + // edit bank state to make it have the not bonded pool tokens + bankStateBz, ok := rawState[banktypes.ModuleName] + // TODO(fdymylja/jonathan): should we panic in this case + if !ok { + panic("bank genesis state is missing") + } + bankState := new(banktypes.GenesisState) + err = cdc.UnmarshalJSON(bankStateBz, bankState) + if err != nil { + panic(err) + } + + bankState.Balances = append(bankState.Balances, banktypes.Balance{ + Address: authtypes.NewModuleAddress(stakingtypes.NotBondedPoolName).String(), + Coins: sdk.NewCoins(notBondedCoins), + }) + + // change appState back + rawState[stakingtypes.ModuleName] = cdc.MustMarshalJSON(stakingState) + rawState[banktypes.ModuleName] = cdc.MustMarshalJSON(bankState) + + // replace appstate + appState, err = json.Marshal(rawState) + if err != nil { + panic(err) + } return appState, simAccs, chainID, genesisTimestamp } } @@ -75,7 +129,7 @@ func AppStateFn(cdc codec.JSONMarshaler, simManager *module.SimulationManager) s // AppStateRandomizedFn creates calls each module's GenesisState generator function // and creates the simulation params func AppStateRandomizedFn( - simManager *module.SimulationManager, r *rand.Rand, cdc codec.JSONMarshaler, + simManager *module.SimulationManager, r *rand.Rand, cdc codec.JSONCodec, accs []simtypes.Account, genesisTimestamp time.Time, appParams simtypes.AppParams, ) (json.RawMessage, []simtypes.Account) { numAccs := int64(len(accs)) @@ -129,7 +183,7 @@ func AppStateRandomizedFn( // AppStateFromGenesisFileFn util function to generate the genesis AppState // from a genesis.json file. -func AppStateFromGenesisFileFn(r io.Reader, cdc codec.JSONMarshaler, genesisFile string) (octypes.GenesisDoc, []simtypes.Account) { +func AppStateFromGenesisFileFn(r io.Reader, cdc codec.JSONCodec, genesisFile string) (octypes.GenesisDoc, []simtypes.Account) { bytes, err := ioutil.ReadFile(genesisFile) if err != nil { panic(err) diff --git a/simapp/test_helpers.go b/simapp/test_helpers.go index 39f2d28781..afffb362aa 100644 --- a/simapp/test_helpers.go +++ b/simapp/test_helpers.go @@ -28,6 +28,7 @@ import ( "github.com/line/lbm-sdk/types/errors" authtypes "github.com/line/lbm-sdk/x/auth/types" banktypes "github.com/line/lbm-sdk/x/bank/types" + minttypes "github.com/line/lbm-sdk/x/mint/types" stakingtypes "github.com/line/lbm-sdk/x/staking/types" ) @@ -121,7 +122,6 @@ func SetupWithGenesisValSet(t *testing.T, valSet *octypes.ValidatorSet, genAccs delegations = append(delegations, stakingtypes.NewDelegation(genAccs[0].GetAddress(), valAddr, sdk.OneDec())) } - // set validators and delegations stakingGenesis := stakingtypes.NewGenesisState(stakingtypes.DefaultParams(), validators, delegations) genesisState[stakingtypes.ModuleName] = app.AppCodec().MustMarshalJSON(stakingGenesis) @@ -132,6 +132,12 @@ func SetupWithGenesisValSet(t *testing.T, valSet *octypes.ValidatorSet, genAccs totalSupply = totalSupply.Add(b.Coins.Add(sdk.NewCoin(sdk.DefaultBondDenom, bondAmt))...) } + // add bonded amount to bonded pool module account + balances = append(balances, banktypes.Balance{ + Address: authtypes.NewModuleAddress(stakingtypes.BondedPoolName).String(), + Coins: sdk.Coins{sdk.NewCoin(sdk.DefaultBondDenom, bondAmt)}, + }) + // update total supply bankGenesis := banktypes.NewGenesisState(banktypes.DefaultGenesisState().Params, balances, totalSupply, []banktypes.Metadata{}) genesisState[banktypes.ModuleName] = app.AppCodec().MustMarshalJSON(bankGenesis) @@ -233,21 +239,12 @@ func createIncrementalAccounts(accNum int) []sdk.AccAddress { func AddTestAddrsFromPubKeys(app *SimApp, ctx sdk.Context, pubKeys []cryptotypes.PubKey, accAmt sdk.Int) { initCoins := sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), accAmt)) - setTotalSupply(app, ctx, accAmt, len(pubKeys)) - // fill all the addresses with some coins, set the loose pool tokens simultaneously for _, pubKey := range pubKeys { - saveAccount(app, ctx, sdk.BytesToAccAddress(pubKey.Address()), initCoins) + initAccountWithCoins(app, ctx, sdk.BytesToAccAddress(pubKey.Address()), initCoins) } } -// setTotalSupply provides the total supply based on accAmt * totalAccounts. -func setTotalSupply(app *SimApp, ctx sdk.Context, accAmt sdk.Int, totalAccounts int) { - totalSupply := sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), accAmt.MulRaw(int64(totalAccounts)))) - prevSupply := app.BankKeeper.GetSupply(ctx) - app.BankKeeper.SetSupply(ctx, banktypes.NewSupply(prevSupply.GetTotal().Add(totalSupply...))) -} - // SortAddresses - Sorts Addresses func SortAddresses(addrs []sdk.AccAddress) { byteAddrs := make([][]byte, len(addrs)) @@ -309,22 +306,22 @@ func addTestAddrs(app *SimApp, ctx sdk.Context, accNum int, accAmt sdk.Int, stra testAddrs := strategy(accNum) initCoins := sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), accAmt)) - setTotalSupply(app, ctx, accAmt, accNum) - // fill all the addresses with some coins, set the loose pool tokens simultaneously for _, addr := range testAddrs { - saveAccount(app, ctx, addr, initCoins) + initAccountWithCoins(app, ctx, addr, initCoins) } SortAddresses(testAddrs) return testAddrs } -// saveAccount saves the provided account into the simapp with balance based on initCoins. -func saveAccount(app *SimApp, ctx sdk.Context, addr sdk.AccAddress, initCoins sdk.Coins) { - acc := app.AccountKeeper.NewAccountWithAddress(ctx, addr) - app.AccountKeeper.SetAccount(ctx, acc) - err := app.BankKeeper.AddCoins(ctx, addr, initCoins) +func initAccountWithCoins(app *SimApp, ctx sdk.Context, addr sdk.AccAddress, coins sdk.Coins) { + err := app.BankKeeper.MintCoins(ctx, minttypes.ModuleName, coins) + if err != nil { + panic(err) + } + + err = app.BankKeeper.SendCoinsFromModuleToAccount(ctx, minttypes.ModuleName, addr, coins) if err != nil { panic(err) } @@ -491,3 +488,31 @@ type EmptyAppOptions struct{} func (ao EmptyAppOptions) Get(o string) interface{} { return nil } + +// FundAccount is a utility function that funds an account by minting and +// sending the coins to the address. This should be used for testing purposes +// only! +// +// TODO: Instead of using the mint module account, which has the +// permission of minting, create a "faucet" account. (@fdymylja) +func FundAccount(app *SimApp, ctx sdk.Context, addr sdk.AccAddress, amounts sdk.Coins) error { + if err := app.BankKeeper.MintCoins(ctx, minttypes.ModuleName, amounts); err != nil { + return err + } + + return app.BankKeeper.SendCoinsFromModuleToAccount(ctx, minttypes.ModuleName, addr, amounts) +} + +// FundModuleAccount is a utility function that funds a module account by +// minting and sending the coins to the address. This should be used for testing +// purposes only! +// +// TODO: Instead of using the mint module account, which has the +// permission of minting, create a "faucet" account. (@fdymylja) +func FundModuleAccount(app *SimApp, ctx sdk.Context, recipientMod string, amounts sdk.Coins) error { + if err := app.BankKeeper.MintCoins(ctx, minttypes.ModuleName, amounts); err != nil { + return err + } + + return app.BankKeeper.SendCoinsFromModuleToModule(ctx, minttypes.ModuleName, recipientMod, amounts) +} diff --git a/simapp/utils.go b/simapp/utils.go index 22e4ed9704..e0b581aa6c 100644 --- a/simapp/utils.go +++ b/simapp/utils.go @@ -49,7 +49,7 @@ func SetupSimulation(dirPrefix, dbName string) (simtypes.Config, tmdb.DB, string // SimulationOperations retrieves the simulation params from the provided file path // and returns all the modules weighted operations -func SimulationOperations(app App, cdc codec.JSONMarshaler, config simtypes.Config) []simtypes.WeightedOperation { +func SimulationOperations(app App, cdc codec.JSONCodec, config simtypes.Config) []simtypes.WeightedOperation { simState := module.SimulationState{ AppParams: make(simtypes.AppParams), Cdc: cdc, diff --git a/simapp/utils_test.go b/simapp/utils_test.go index a5f6d446c1..7f9b711151 100644 --- a/simapp/utils_test.go +++ b/simapp/utils_test.go @@ -58,7 +58,7 @@ func TestGetSimulationLog(t *testing.T) { }, { authtypes.StoreKey, - []kv.Pair{{Key: authtypes.GlobalAccountNumberKey, Value: cdc.MustMarshalBinaryBare(uint64(10))}}, + []kv.Pair{{Key: authtypes.GlobalAccountNumberKey, Value: cdc.MustMarshal(uint64(10))}}, "10", }, { diff --git a/snapshots/README.md b/snapshots/README.md new file mode 100644 index 0000000000..dfe2d66e72 --- /dev/null +++ b/snapshots/README.md @@ -0,0 +1,236 @@ +# State Sync Snapshotting + +The `snapshots` package implements automatic support for Tendermint state sync +in Cosmos SDK-based applications. State sync allows a new node joining a network +to simply fetch a recent snapshot of the application state instead of fetching +and applying all historical blocks. This can reduce the time needed to join the +network by several orders of magnitude (e.g. weeks to minutes), but the node +will not contain historical data from previous heights. + +This document describes the Cosmos SDK implementation of the ABCI state sync +interface, for more information on Tendermint state sync in general see: + +* [Tendermint Core State Sync for Developers](https://medium.com/tendermint/tendermint-core-state-sync-for-developers-70a96ba3ee35) +* [ABCI State Sync Spec](https://docs.tendermint.com/master/spec/abci/apps.html#state-sync) +* [ABCI State Sync Method/Type Reference](https://docs.tendermint.com/master/spec/abci/abci.html#state-sync) + +## Overview + +For an overview of how Cosmos SDK state sync is set up and configured by +developers and end-users, see the +[Cosmos SDK State Sync Guide](https://blog.cosmos.network/cosmos-sdk-state-sync-guide-99e4cf43be2f). + +Briefly, the Cosmos SDK takes state snapshots at regular height intervals given +by `state-sync.snapshot-interval` and stores them as binary files in the +filesystem under `/data/snapshots/`, with metadata in a LevelDB database +`/data/snapshots/metadata.db`. The number of recent snapshots to keep are given by +`state-sync.snapshot-keep-recent`. + +Snapshots are taken asynchronously, i.e. new blocks will be applied concurrently +with snapshots being taken. This is possible because IAVL supports querying +immutable historical heights. However, this requires `state-sync.snapshot-interval` +to be a multiple of `pruning-keep-every`, to prevent a height from being removed +while it is being snapshotted. + +When a remote node is state syncing, Tendermint calls the ABCI method +`ListSnapshots` to list available local snapshots and `LoadSnapshotChunk` to +load a binary snapshot chunk. When the local node is being state synced, +Tendermint calls `OfferSnapshot` to offer a discovered remote snapshot to the +local application and `ApplySnapshotChunk` to apply a binary snapshot chunk to +the local application. See the resources linked above for more details on these +methods and how Tendermint performs state sync. + +The Cosmos SDK does not currently do any incremental verification of snapshots +during restoration, i.e. only after the entire snapshot has been restored will +Tendermint compare the app hash against the trusted hash from the chain. Cosmos +SDK snapshots and chunks do contain hashes as checksums to guard against IO +corruption and non-determinism, but these are not tied to the chain state and +can be trivially forged by an adversary. This was considered out of scope for +the initial implementation, but can be added later without changes to the +ABCI state sync protocol. + +## Snapshot Metadata + +The ABCI Protobuf type for a snapshot is listed below (refer to the ABCI spec +for field details): + +```protobuf +message Snapshot { + uint64 height = 1; // The height at which the snapshot was taken + uint32 format = 2; // The application-specific snapshot format + uint32 chunks = 3; // Number of chunks in the snapshot + bytes hash = 4; // Arbitrary snapshot hash, equal only if identical + bytes metadata = 5; // Arbitrary application metadata +} +``` + +Because the `metadata` field is application-specific, the Cosmos SDK uses a +similar type `cosmos.base.snapshots.v1beta1.Snapshot` with its own metadata +representation: + +```protobuf +// Snapshot contains Tendermint state sync snapshot info. +message Snapshot { + uint64 height = 1; + uint32 format = 2; + uint32 chunks = 3; + bytes hash = 4; + Metadata metadata = 5 [(gogoproto.nullable) = false]; +} + +// Metadata contains SDK-specific snapshot metadata. +message Metadata { + repeated bytes chunk_hashes = 1; // SHA-256 chunk hashes +} +``` + +The `format` is currently `1`, defined in `snapshots.types.CurrentFormat`. This +must be increased whenever the binary snapshot format changes, and it may be +useful to support past formats in newer versions. + +The `hash` is a SHA-256 hash of the entire binary snapshot, used to guard +against IO corruption and non-determinism across nodes. Note that this is not +tied to the chain state, and can be trivially forged (but Tendermint will always +compare the final app hash against the chain app hash). Similarly, the +`chunk_hashes` are SHA-256 checksums of each binary chunk. + +The `metadata` field is Protobuf-serialized before it is placed into the ABCI +snapshot. + +## Snapshot Format + +The current version `1` snapshot format is a zlib-compressed, length-prefixed +Protobuf stream of `cosmos.base.store.v1beta1.SnapshotItem` messages, split into +chunks at exact 10 MB byte boundaries. + +```protobuf +// SnapshotItem is an item contained in a rootmulti.Store snapshot. +message SnapshotItem { + // item is the specific type of snapshot item. + oneof item { + SnapshotStoreItem store = 1; + SnapshotIAVLItem iavl = 2 [(gogoproto.customname) = "IAVL"]; + } +} + +// SnapshotStoreItem contains metadata about a snapshotted store. +message SnapshotStoreItem { + string name = 1; +} + +// SnapshotIAVLItem is an exported IAVL node. +message SnapshotIAVLItem { + bytes key = 1; + bytes value = 2; + int64 version = 3; + int32 height = 4; +} +``` + +Snapshots are generated by `rootmulti.Store.Snapshot()` as follows: + +1. Set up a `protoio.NewDelimitedWriter` that writes length-prefixed serialized + `SnapshotItem` Protobuf messages. + 1. Iterate over each IAVL store in lexicographical order by store name. + 2. Emit a `SnapshotStoreItem` containing the store name. + 3. Start an IAVL export for the store using + [`iavl.ImmutableTree.Export()`](https://pkg.go.dev/github.com/tendermint/iavl#ImmutableTree.Export). + 4. Iterate over each IAVL node. + 5. Emit a `SnapshotIAVLItem` for the IAVL node. +2. Pass the serialized Protobuf output stream to a zlib compression writer. +3. Split the zlib output stream into chunks at exactly every 10th megabyte. + +Snapshots are restored via `rootmulti.Store.Restore()` as the inverse of the above, using +[`iavl.MutableTree.Import()`](https://pkg.go.dev/github.com/tendermint/iavl#MutableTree.Import) +to reconstruct each IAVL tree. + +## Snapshot Storage + +Snapshot storage is managed by `snapshots.Store`, with metadata in a `db.DB` +database and binary chunks in the filesystem. Note that this is only used to +store locally taken snapshots that are being offered to other nodes. When the +local node is being state synced, Tendermint will take care of buffering and +storing incoming snapshot chunks before they are applied to the application. + +Metadata is generally stored in a LevelDB database at +`/data/snapshots/metadata.db`. It contains serialized +`cosmos.base.snapshots.v1beta1.Snapshot` Protobuf messages with a key given by +the concatenation of a key prefix, the big-endian height, and the big-endian +format. Chunk data is stored as regular files under +`/data/snapshots///`. + +The `snapshots.Store` API is based on streaming IO, and integrates easily with +the `snapshots.types.Snapshotter` snapshot/restore interface implemented by +`rootmulti.Store`. The `Store.Save()` method stores a snapshot given as a +`<- chan io.ReadCloser` channel of binary chunk streams, and `Store.Load()` loads +the snapshot as a channel of binary chunk streams -- the same stream types used +by `Snapshotter.Snapshot()` and `Snapshotter.Restore()` to take and restore +snapshots using streaming IO. + +The store also provides many other methods such as `List()` to list stored +snapshots, `LoadChunk()` to load a single snapshot chunk, and `Prune()` to prune +old snapshots. + +## Taking Snapshots + +`snapshots.Manager` is a high-level snapshot manager that integrates a +`snapshots.types.Snapshotter` (i.e. the `rootmulti.Store` snapshot +functionality) and a `snapshots.Store`, providing an API that maps easily onto +the ABCI state sync API. The `Manager` will also make sure only one operation +is in progress at a time, e.g. to prevent multiple snapshots being taken +concurrently. + +During `BaseApp.Commit`, once a state transition has been committed, the height +is checked against the `state-sync.snapshot-interval` setting. If the committed +height should be snapshotted, a goroutine `BaseApp.snapshot()` is spawned that +calls `snapshots.Manager.Create()` to create the snapshot. + +`Manager.Create()` will do some basic pre-flight checks, and then start +generating a snapshot by calling `rootmulti.Store.Snapshot()`. The chunk stream +is passed into `snapshots.Store.Save()`, which stores the chunks in the +filesystem and records the snapshot metadata in the snapshot database. + +Once the snapshot has been generated, `BaseApp.snapshot()` then removes any +old snapshots based on the `state-sync.snapshot-keep-recent` setting. + +## Serving Snapshots + +When a remote node is discovering snapshots for state sync, Tendermint will +call the `ListSnapshots` ABCI method to list the snapshots present on the +local node. This is dispatched to `snapshots.Manager.List()`, which in turn +dispatches to `snapshots.Store.List()`. + +When a remote node is fetching snapshot chunks during state sync, Tendermint +will call the `LoadSnapshotChunk` ABCI method to fetch a chunk from the local +node. This dispatches to `snapshots.Manager.LoadChunk()`, which in turn +dispatches to `snapshots.Store.LoadChunk()`. + +## Restoring Snapshots + +When the operator has configured the local Tendermint node to run state sync +(see the resources listed in the introduction for details on Tendermint state +sync), it will discover snapshots across the P2P network and offer their +metadata in turn to the local application via the `OfferSnapshot` ABCI call. + +`BaseApp.OfferSnapshot()` attempts to start a restore operation by calling +`snapshots.Manager.Restore()`. This may fail, e.g. if the snapshot format is +unknown (it may have been generated by a different version of the Cosmos SDK), +in which case Tendermint will offer other discovered snapshots. + +If the snapshot is accepted, `Manager.Restore()` will record that a restore +operation is in progress, and spawn a separate goroutine that runs a synchronous +`rootmulti.Store.Restore()` snapshot restoration which will be fed snapshot +chunks until it is complete. + +Tendermint will then start fetching and buffering chunks, providing them in +order via ABCI `ApplySnapshotChunk` calls. These dispatch to +`Manager.RestoreChunk()`, which passes the chunks to the ongoing restore +process, checking if errors have been encountered yet (e.g. due to checksum +mismatches or invalid IAVL data). Once the final chunk is passed, +`Manager.RestoreChunk()` will wait for the restore process to complete before +returning. + +Once the restore is completed, Tendermint will go on to call the `Info` ABCI +call to fetch the app hash, and compare this against the trusted chain app +hash at the snapshot height to verify the restored state. If it matches, +Tendermint goes on to process blocks. diff --git a/snapshots/helpers_test.go b/snapshots/helpers_test.go index e27cc4a4bc..6e472adacf 100644 --- a/snapshots/helpers_test.go +++ b/snapshots/helpers_test.go @@ -102,6 +102,9 @@ func (m *mockSnapshotter) Snapshot(height uint64, format uint32) (<-chan io.Read // setupBusyManager creates a manager with an empty store that is busy creating a snapshot at height 1. // The snapshot will complete when the returned closer is called. func setupBusyManager(t *testing.T) *snapshots.Manager { + // ioutil.TempDir() is used instead of testing.T.TempDir() + // see https://github.com/cosmos/cosmos-sdk/pull/8475 for + // this change's rationale. tempdir, err := ioutil.TempDir("", "") require.NoError(t, err) t.Cleanup(func() { _ = os.RemoveAll(tempdir) }) diff --git a/snapshots/store_test.go b/snapshots/store_test.go index 8ae9ce476b..322580d092 100644 --- a/snapshots/store_test.go +++ b/snapshots/store_test.go @@ -21,6 +21,9 @@ import ( ) func setupStore(t *testing.T) *snapshots.Store { + // ioutil.TempDir() is used instead of testing.T.TempDir() + // see https://github.com/cosmos/cosmos-sdk/pull/8475 for + // this change's rationale. tempdir, err := ioutil.TempDir("", "") require.NoError(t, err) t.Cleanup(func() { _ = os.RemoveAll(tempdir) }) diff --git a/std/codec.go b/std/codec.go index f43e665f02..3f049db563 100644 --- a/std/codec.go +++ b/std/codec.go @@ -12,6 +12,7 @@ import ( func RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) { sdk.RegisterLegacyAminoCodec(cdc) cryptocodec.RegisterCrypto(cdc) + codec.RegisterEvidences(cdc) } // RegisterInterfaces registers Interfaces from sdk/types, vesting, crypto, tx. diff --git a/store/README.md b/store/README.md index 3607cbb71b..8541f69673 100644 --- a/store/README.md +++ b/store/README.md @@ -2,7 +2,7 @@ ## CacheKV -`cachekv.Store` is a wrapper `KVStore` which provides buffered writing / cached reading functionalities over the underlying `KVStore`. +`cachekv.Store` is a wrapper `KVStore` which provides buffered writing / cached reading functionalities over the underlying `KVStore`. ```go type Store struct { @@ -50,7 +50,7 @@ type Store struct { ## IAVL -`iavl.Store` is a base-layer self-balancing merkle tree. It is guaranteed that +`iavl.Store` is a base-layer self-balancing merkle tree. It is guaranteed that 1. Get & set operations are `O(log n)`, where `n` is the number of elements in the tree 2. Iteration efficiently returns the sorted elements within the range @@ -72,7 +72,6 @@ type Store struct { When each `KVStore` methods are called, `gaskv.Store` automatically consumes appropriate amount of gas depending on the `Store.gasConfig`. - ## Prefix `prefix.Store` is a wrapper `KVStore` which provides automatic key-prefixing functionalities over the underlying `KVStore`. @@ -112,7 +111,7 @@ type traceOperation struct { Key string Value string Metadata map[string]interface{} -} +} ``` `traceOperation.Metadata` is filled with `Store.context` when it is not nil. `TraceContext` is a `map[string]interface{}`. diff --git a/store/cache/benchmark_test.go b/store/cache/benchmark_test.go index 43d0dec859..4ae7dc05b4 100644 --- a/store/cache/benchmark_test.go +++ b/store/cache/benchmark_test.go @@ -22,6 +22,7 @@ func populate(mgr *CommitKVStoreCacheManager) { } func BenchmarkReset(b *testing.B) { + b.ReportAllocs() mgr := freshMgr() b.ResetTimer() diff --git a/store/cachekv/bench_helper_test.go b/store/cachekv/bench_helper_test.go new file mode 100644 index 0000000000..fe5be27fab --- /dev/null +++ b/store/cachekv/bench_helper_test.go @@ -0,0 +1,44 @@ +package cachekv_test + +import "crypto/rand" + +func randSlice(sliceSize int) []byte { + bz := make([]byte, sliceSize) + _, _ = rand.Read(bz) + return bz +} + +func incrementByteSlice(bz []byte) { + for index := len(bz) - 1; index >= 0; index-- { + if bz[index] < 255 { + bz[index]++ + break + } else { + bz[index] = 0 + } + } +} + +// Generate many keys starting at startKey, and are in sequential order +func generateSequentialKeys(startKey []byte, numKeys int) [][]byte { + toReturn := make([][]byte, 0, numKeys) + cur := make([]byte, len(startKey)) + copy(cur, startKey) + for i := 0; i < numKeys; i++ { + newKey := make([]byte, len(startKey)) + copy(newKey, cur) + toReturn = append(toReturn, newKey) + incrementByteSlice(cur) + } + return toReturn +} + +// Generate many random, unsorted keys +func generateRandomKeys(keySize int, numKeys int) [][]byte { + toReturn := make([][]byte, 0, numKeys) + for i := 0; i < numKeys; i++ { + newKey := randSlice(keySize) + toReturn = append(toReturn, newKey) + } + return toReturn +} diff --git a/store/cachekv/memiterator.go b/store/cachekv/memiterator.go index e378991260..40182ecf8e 100644 --- a/store/cachekv/memiterator.go +++ b/store/cachekv/memiterator.go @@ -15,6 +15,7 @@ import ( type memIterator struct { types.Iterator + lastKey []byte deleted map[string]struct{} } @@ -51,14 +52,22 @@ func newMemIterator(start, end []byte, items *memdb.MemDB, deleted *sync.Map, as return &memIterator{ Iterator: iter, + lastKey: nil, deleted: newDeleted, } } func (mi *memIterator) Value() []byte { key := mi.Iterator.Key() - if _, ok := mi.deleted[string(key)]; ok { + // We need to handle the case where deleted is modified and includes our current key + // We handle this by maintaining a lastKey object in the iterator. + // If the current key is the same as the last key (and last key is not nil / the start) + // then we are calling value on the same thing as last time. + // Therefore we don't check the mi.deleted to see if this key is included in there. + reCallingOnOldLastKey := (mi.lastKey != nil) && bytes.Equal(key, mi.lastKey) + if _, ok := mi.deleted[string(key)]; ok && !reCallingOnOldLastKey { return nil } + mi.lastKey = key return mi.Iterator.Value() } diff --git a/store/cachekv/store.go b/store/cachekv/store.go index 6c199ea161..bab801d60f 100644 --- a/store/cachekv/store.go +++ b/store/cachekv/store.go @@ -3,14 +3,14 @@ package cachekv import ( "bytes" "io" - "reflect" "sort" "sync" "time" - "unsafe" "github.com/line/tm-db/v2/memdb" + "github.com/line/lbm-sdk/internal/conv" + "github.com/line/lbm-sdk/store/listenkv" "github.com/line/lbm-sdk/store/tracekv" "github.com/line/lbm-sdk/store/types" "github.com/line/lbm-sdk/telemetry" @@ -55,7 +55,6 @@ func (store *Store) GetStoreType() types.StoreType { // Get implements types.KVStore. func (store *Store) Get(key []byte) (value []byte) { - types.AssertValidKey(key) store.mtx.RLock() defer store.mtx.RUnlock() @@ -71,7 +70,6 @@ func (store *Store) Get(key []byte) (value []byte) { // Set implements types.KVStore. func (store *Store) Set(key []byte, value []byte) { - types.AssertValidKey(key) types.AssertValidValue(value) @@ -126,15 +124,19 @@ func (store *Store) Write() { // TODO: Consider allowing usage of Batch, which would allow the write to // at least happen atomically. for _, key := range keys { - v, _ := store.cache.Load(key) - cacheValue := v.(*cValue) - - switch { - case store.isDeleted(key): + if store.isDeleted(key) { + // We use []byte(key) instead of conv.UnsafeStrToBytes because we cannot + // be sure if the underlying store might do a save with the byteslice or + // not. Once we get confirmation that .Delete is guaranteed not to + // save the byteslice, then we can assume only a read-only copy is sufficient. store.parent.Delete([]byte(key)) - case cacheValue.value == nil: - // Skip, it already doesn't exist in parent. - default: + continue + } + + v, ok := store.cache.Load(key) + cacheValue := v.(*cValue) + if ok && cacheValue != nil { + // It already exists in the parent, hence delete it. store.parent.Set([]byte(key), cacheValue.value) } } @@ -156,6 +158,11 @@ func (store *Store) CacheWrapWithTrace(w io.Writer, tc types.TraceContext) types return NewStore(tracekv.NewStore(store, w, tc)) } +// CacheWrapWithListeners implements the CacheWrapper interface. +func (store *Store) CacheWrapWithListeners(storeKey types.StoreKey, listeners []types.WriteListener) types.CacheWrap { + return NewStore(listenkv.NewStore(store, storeKey, listeners)) +} + //---------------------------------------- // Iteration @@ -187,28 +194,7 @@ func (store *Store) iterator(start, end []byte, ascending bool) types.Iterator { return newCacheMergeIterator(parent, cache, ascending) } -// strToBytes is meant to make a zero allocation conversion -// from string -> []byte to speed up operations, it is not meant -// to be used generally, but for a specific pattern to check for available -// keys within a domain. -func strToBytes(s string) []byte { - var b []byte - hdr := (*reflect.SliceHeader)(unsafe.Pointer(&b)) - hdr.Cap = len(s) - hdr.Len = len(s) - hdr.Data = (*reflect.StringHeader)(unsafe.Pointer(&s)).Data - return b -} - -// byteSliceToStr is meant to make a zero allocation conversion -// from []byte -> string to speed up operations, it is not meant -// to be used generally, but for a specific pattern to delete keys -// from a map. -func byteSliceToStr(b []byte) string { - hdr := (*reflect.StringHeader)(unsafe.Pointer(&b)) - return *(*string)(unsafe.Pointer(hdr)) -} - +// TODO(dudong2): need to bump up this func - (https://github.com/cosmos/cosmos-sdk/pull/10024) // Constructs a slice of dirty items, to use w/ memIterator. func (store *Store) dirtyItems(start, end []byte) { unsorted := make([]*kv.Pair, 0) @@ -220,7 +206,7 @@ func (store *Store) dirtyItems(start, end []byte) { // than just not having the cache. store.unsortedCache.Range(func(k, _ interface{}) bool { key := k.(string) - if IsKeyInDomain(strToBytes(key), start, end) { + if IsKeyInDomain(conv.UnsafeStrToBytes(key), start, end) { cacheValue, ok := store.cache.Load(key) if ok { unsorted = append(unsorted, &kv.Pair{Key: []byte(key), Value: cacheValue.(*cValue).value}) @@ -233,7 +219,7 @@ func (store *Store) dirtyItems(start, end []byte) { func (store *Store) clearUnsortedCacheSubset(unsorted []*kv.Pair) { for _, kv := range unsorted { - store.unsortedCache.Delete(byteSliceToStr(kv.Key)) + store.unsortedCache.Delete(conv.UnsafeBytesToStr(kv.Key)) } sort.Slice(unsorted, func(i, j int) bool { return bytes.Compare(unsorted[i].Key, unsorted[j].Key) < 0 @@ -258,7 +244,7 @@ func (store *Store) clearUnsortedCacheSubset(unsorted []*kv.Pair) { // Only entrypoint to mutate store.cache. func (store *Store) setCacheValue(key, value []byte, deleted bool, dirty bool) { - keyStr := byteSliceToStr(key) + keyStr := conv.UnsafeBytesToStr(key) store.cache.Store(keyStr, &cValue{ value: value, dirty: dirty, diff --git a/store/cachekv/store_bench_test.go b/store/cachekv/store_bench_test.go index 937f7eae2f..53ee0fa648 100644 --- a/store/cachekv/store_bench_test.go +++ b/store/cachekv/store_bench_test.go @@ -1,8 +1,6 @@ package cachekv_test import ( - "crypto/rand" - "sort" "testing" "github.com/line/tm-db/v2/memdb" @@ -11,36 +9,136 @@ import ( "github.com/line/lbm-sdk/store/dbadapter" ) -func benchmarkCacheKVStoreIterator(numKVs int, b *testing.B) { +var sink interface{} + +const defaultValueSizeBz = 1 << 12 + +// This benchmark measures the time of iterator.Next() when the parent store is blank +func benchmarkBlankParentIteratorNext(b *testing.B, keysize int) { + mem := dbadapter.Store{DB: memdb.NewDB()} + kvstore := cachekv.NewStore(mem) + // Use a singleton for value, to not waste time computing it + value := randSlice(defaultValueSizeBz) + // Use simple values for keys, pick a random start, + // and take next b.N keys sequentially after.] + startKey := randSlice(32) + + // Add 1 to avoid issues when b.N = 1 + keys := generateSequentialKeys(startKey, b.N+1) + for _, k := range keys { + kvstore.Set(k, value) + } + + b.ReportAllocs() + b.ResetTimer() + + iter := kvstore.Iterator(keys[0], keys[b.N]) + defer iter.Close() + + for _ = iter.Key(); iter.Valid(); iter.Next() { + // deadcode elimination stub + sink = iter + } +} + +// Benchmark setting New keys to a store, where the new keys are in sequence. +func benchmarkBlankParentAppend(b *testing.B, keysize int) { + mem := dbadapter.Store{DB: memdb.NewDB()} + kvstore := cachekv.NewStore(mem) + + // Use a singleton for value, to not waste time computing it + value := randSlice(32) + // Use simple values for keys, pick a random start, + // and take next b.N keys sequentially after. + startKey := randSlice(32) + + keys := generateSequentialKeys(startKey, b.N) + + b.ReportAllocs() + b.ResetTimer() + + for _, k := range keys { + kvstore.Set(k, value) + } +} + +// Benchmark setting New keys to a store, where the new keys are random. +// the speed of this function does not depend on the values in the parent store +func benchmarkRandomSet(b *testing.B, keysize int) { mem := dbadapter.Store{DB: memdb.NewDB()} - cstore := cachekv.NewStore(mem) - keys := make([]string, numKVs) + kvstore := cachekv.NewStore(mem) - for i := 0; i < numKVs; i++ { - key := make([]byte, 32) - value := make([]byte, 32) + // Use a singleton for value, to not waste time computing it + value := randSlice(defaultValueSizeBz) + keys := generateRandomKeys(keysize, b.N) - _, _ = rand.Read(key) - _, _ = rand.Read(value) + b.ReportAllocs() + b.ResetTimer() - keys[i] = string(key) - cstore.Set(key, value) + for _, k := range keys { + kvstore.Set(k, value) } - sort.Strings(keys) + iter := kvstore.Iterator(keys[0], keys[b.N]) + defer iter.Close() - for n := 0; n < b.N; n++ { - iter := cstore.Iterator([]byte(keys[0]), []byte(keys[numKVs-1])) + for _ = iter.Key(); iter.Valid(); iter.Next() { + // deadcode elimination stub + sink = iter + } +} - for _ = iter.Key(); iter.Valid(); iter.Next() { - } +// Benchmark creating an iterator on a parent with D entries, +// that are all deleted in the cacheKV store. +// We essentially are benchmarking the cacheKV iterator creation & iteration times +// with the number of entries deleted in the parent. +func benchmarkIteratorOnParentWithManyDeletes(b *testing.B, numDeletes int) { + mem := dbadapter.Store{DB: memdb.NewDB()} - iter.Close() + // Use a singleton for value, to not waste time computing it + value := randSlice(32) + // Use simple values for keys, pick a random start, + // and take next D keys sequentially after. + startKey := randSlice(32) + keys := generateSequentialKeys(startKey, numDeletes) + // setup parent db with D keys. + for _, k := range keys { + mem.Set(k, value) } + kvstore := cachekv.NewStore(mem) + // Delete all keys from the cache KV store. + // The keys[1:] is to keep at least one entry in parent, due to a bug in the SDK iterator design. + // Essentially the iterator will never be valid, in that it should never run. + // However, this is incompatible with the for loop structure the SDK uses, hence + // causes a panic. Thus we do keys[1:]. + for _, k := range keys[1:] { + kvstore.Delete(k) + } + + b.ReportAllocs() + b.ResetTimer() + + iter := kvstore.Iterator(keys[0], keys[b.N]) + defer iter.Close() + + for _ = iter.Key(); iter.Valid(); iter.Next() { + // deadcode elimination stub + sink = iter + } +} + +func BenchmarkBlankParentIteratorNextKeySize32(b *testing.B) { + benchmarkBlankParentIteratorNext(b, 32) +} + +func BenchmarkBlankParentAppendKeySize32(b *testing.B) { + benchmarkBlankParentAppend(b, 32) +} + +func BenchmarkSetKeySize32(b *testing.B) { + benchmarkRandomSet(b, 32) } -func BenchmarkCacheKVStoreIterator500(b *testing.B) { benchmarkCacheKVStoreIterator(500, b) } -func BenchmarkCacheKVStoreIterator1000(b *testing.B) { benchmarkCacheKVStoreIterator(1000, b) } -func BenchmarkCacheKVStoreIterator10000(b *testing.B) { benchmarkCacheKVStoreIterator(10000, b) } -func BenchmarkCacheKVStoreIterator50000(b *testing.B) { benchmarkCacheKVStoreIterator(50000, b) } -func BenchmarkCacheKVStoreIterator100000(b *testing.B) { benchmarkCacheKVStoreIterator(100000, b) } +func BenchmarkIteratorOnParentWith1MDeletes(b *testing.B) { + benchmarkIteratorOnParentWithManyDeletes(b, 1_000_000) +} diff --git a/store/cachekv/store_test.go b/store/cachekv/store_test.go index 282b4528e2..041e203a9b 100644 --- a/store/cachekv/store_test.go +++ b/store/cachekv/store_test.go @@ -553,6 +553,7 @@ func (krc *keyRangeCounter) key() int { func bz(s string) []byte { return []byte(s) } func BenchmarkCacheKVStoreGetNoKeyFound(b *testing.B) { + b.ReportAllocs() st := newCacheKVStore() b.ResetTimer() // assumes b.N < 2**24 @@ -562,6 +563,7 @@ func BenchmarkCacheKVStoreGetNoKeyFound(b *testing.B) { } func BenchmarkCacheKVStoreGetKeyFound(b *testing.B) { + b.ReportAllocs() st := newCacheKVStore() for i := 0; i < b.N; i++ { arr := []byte{byte((i & 0xFF0000) >> 16), byte((i & 0xFF00) >> 8), byte(i & 0xFF)} diff --git a/store/cachemulti/store.go b/store/cachemulti/store.go index e81aa04881..6097d8a42f 100644 --- a/store/cachemulti/store.go +++ b/store/cachemulti/store.go @@ -26,6 +26,8 @@ type Store struct { traceWriter io.Writer traceContext types.TraceContext + + listeners map[types.StoreKey][]types.WriteListener } var _ types.CacheMultiStore = Store{} @@ -36,6 +38,7 @@ var _ types.CacheMultiStore = Store{} func NewFromKVStore( store types.KVStore, stores map[types.StoreKey]types.CacheWrapper, keys map[string]types.StoreKey, traceWriter io.Writer, traceContext types.TraceContext, + listeners map[types.StoreKey][]types.WriteListener, ) Store { cms := Store{ db: cachekv.NewStore(store), @@ -43,13 +46,20 @@ func NewFromKVStore( keys: keys, traceWriter: traceWriter, traceContext: traceContext, + listeners: listeners, } for key, store := range stores { + var cacheWrapped types.CacheWrap if cms.TracingEnabled() { - cms.stores[key] = store.CacheWrapWithTrace(cms.traceWriter, cms.traceContext) + cacheWrapped = store.CacheWrapWithTrace(cms.traceWriter, cms.traceContext) + } else { + cacheWrapped = store.CacheWrap() + } + if cms.ListeningEnabled(key) { + cms.stores[key] = cacheWrapped.CacheWrapWithListeners(key, cms.listeners[key]) } else { - cms.stores[key] = store.CacheWrap() + cms.stores[key] = cacheWrapped } } @@ -60,10 +70,10 @@ func NewFromKVStore( // CacheWrapper objects. Each CacheWrapper store is a branched store. func NewStore( db tmdb.DB, stores map[types.StoreKey]types.CacheWrapper, keys map[string]types.StoreKey, - traceWriter io.Writer, traceContext types.TraceContext, + traceWriter io.Writer, traceContext types.TraceContext, listeners map[types.StoreKey][]types.WriteListener, ) Store { - return NewFromKVStore(dbadapter.Store{DB: db}, stores, keys, traceWriter, traceContext) + return NewFromKVStore(dbadapter.Store{DB: db}, stores, keys, traceWriter, traceContext, listeners) } func newCacheMultiStoreFromCMS(cms Store) Store { @@ -72,7 +82,7 @@ func newCacheMultiStoreFromCMS(cms Store) Store { stores[k] = v } - return NewFromKVStore(cms.db, stores, nil, cms.traceWriter, cms.traceContext) + return NewFromKVStore(cms.db, stores, nil, cms.traceWriter, cms.traceContext, cms.listeners) } // SetTracer sets the tracer for the MultiStore that the underlying @@ -103,6 +113,23 @@ func (cms Store) TracingEnabled() bool { return cms.traceWriter != nil } +// AddListeners adds listeners for a specific KVStore +func (cms Store) AddListeners(key types.StoreKey, listeners []types.WriteListener) { + if ls, ok := cms.listeners[key]; ok { + cms.listeners[key] = append(ls, listeners...) + } else { + cms.listeners[key] = listeners + } +} + +// ListeningEnabled returns if listening is enabled for a specific KVStore +func (cms Store) ListeningEnabled(key types.StoreKey) bool { + if ls, ok := cms.listeners[key]; ok { + return len(ls) != 0 + } + return false +} + // GetStoreType returns the type of the store. func (cms Store) GetStoreType() types.StoreType { return types.StoreTypeMulti @@ -144,6 +171,11 @@ func (cms Store) CacheWrapWithTrace(_ io.Writer, _ types.TraceContext) types.Cac return cms.CacheWrap() } +// CacheWrapWithListeners implements the CacheWrapper interface. +func (cms Store) CacheWrapWithListeners(_ types.StoreKey, _ []types.WriteListener) types.CacheWrap { + return cms.CacheWrap() +} + // Implements MultiStore. func (cms Store) CacheMultiStore() types.CacheMultiStore { return newCacheMultiStoreFromCMS(cms) diff --git a/store/dbadapter/store.go b/store/dbadapter/store.go index 8688f1f9f9..7db4c9366d 100644 --- a/store/dbadapter/store.go +++ b/store/dbadapter/store.go @@ -6,6 +6,7 @@ import ( tmdb "github.com/line/tm-db/v2" "github.com/line/lbm-sdk/store/cachekv" + "github.com/line/lbm-sdk/store/listenkv" "github.com/line/lbm-sdk/store/tracekv" "github.com/line/lbm-sdk/store/types" ) @@ -94,5 +95,10 @@ func (dsa Store) CacheWrapWithTrace(w io.Writer, tc types.TraceContext) types.Ca return cachekv.NewStore(tracekv.NewStore(dsa, w, tc)) } +// CacheWrapWithListeners implements the CacheWrapper interface. +func (dsa Store) CacheWrapWithListeners(storeKey types.StoreKey, listeners []types.WriteListener) types.CacheWrap { + return cachekv.NewStore(listenkv.NewStore(dsa, storeKey, listeners)) +} + // tmdb.DB implements KVStore so we can CacheKVStore it. var _ types.KVStore = Store{} diff --git a/store/dbadapter/store_test.go b/store/dbadapter/store_test.go index a7a04c7df2..540714201a 100644 --- a/store/dbadapter/store_test.go +++ b/store/dbadapter/store_test.go @@ -5,6 +5,8 @@ import ( "errors" "testing" + "github.com/line/lbm-sdk/store/cachekv" + "github.com/golang/mock/gomock" "github.com/stretchr/testify/require" @@ -73,3 +75,18 @@ func TestAccessors(t *testing.T) { mockDB.EXPECT().ReverseIterator(gomock.Eq(start), gomock.Eq(end)).Times(1).Return(nil, errFoo) require.Panics(t, func() { store.ReverseIterator(start, end) }) } + +func TestCacheWraps(t *testing.T) { + mockCtrl := gomock.NewController(t) + mockDB := mocks.NewMockDB(mockCtrl) + store := dbadapter.Store{mockDB} + + cacheWrapper := store.CacheWrap() + require.IsType(t, &cachekv.Store{}, cacheWrapper) + + cacheWrappedWithTrace := store.CacheWrapWithTrace(nil, nil) + require.IsType(t, &cachekv.Store{}, cacheWrappedWithTrace) + + cacheWrappedWithListeners := store.CacheWrapWithListeners(nil, nil) + require.IsType(t, &cachekv.Store{}, cacheWrappedWithListeners) +} diff --git a/store/gaskv/store.go b/store/gaskv/store.go index 07cbdfe81c..2c03aac482 100644 --- a/store/gaskv/store.go +++ b/store/gaskv/store.go @@ -39,6 +39,7 @@ func (gs *Store) Get(key []byte) (value []byte) { value = gs.parent.Get(key) // TODO overflow-safe math? + gs.gasMeter.ConsumeGas(gs.gasConfig.ReadCostPerByte*types.Gas(len(key)), types.GasReadPerByteDesc) gs.gasMeter.ConsumeGas(gs.gasConfig.ReadCostPerByte*types.Gas(len(value)), types.GasReadPerByteDesc) return value @@ -50,6 +51,7 @@ func (gs *Store) Set(key []byte, value []byte) { types.AssertValidValue(value) gs.gasMeter.ConsumeGas(gs.gasConfig.WriteCostFlat, types.GasWriteCostFlatDesc) // TODO overflow-safe math? + gs.gasMeter.ConsumeGas(gs.gasConfig.WriteCostPerByte*types.Gas(len(key)), types.GasWritePerByteDesc) gs.gasMeter.ConsumeGas(gs.gasConfig.WriteCostPerByte*types.Gas(len(value)), types.GasWritePerByteDesc) gs.parent.Set(key, value) } @@ -100,6 +102,11 @@ func (gs *Store) CacheWrapWithTrace(_ io.Writer, _ types.TraceContext) types.Cac panic("cannot CacheWrapWithTrace a GasKVStore") } +// CacheWrapWithListeners implements the CacheWrapper interface. +func (gs *Store) CacheWrapWithListeners(_ types.StoreKey, _ []types.WriteListener) types.CacheWrap { + panic("cannot CacheWrapWithListeners a GasKVStore") +} + func (gs *Store) iterator(start, end []byte, ascending bool) types.Iterator { var parent types.Iterator if ascending { @@ -109,9 +116,7 @@ func (gs *Store) iterator(start, end []byte, ascending bool) types.Iterator { } gi := newGasIterator(gs.gasMeter, gs.gasConfig, parent) - if gi.Valid() { - gi.(*gasIterator).consumeSeekGas() - } + gi.(*gasIterator).consumeSeekGas() return gi } @@ -139,10 +144,7 @@ func (gi *gasIterator) Valid() bool { // in the iterator. It incurs a flat gas cost for seeking and a variable gas // cost based on the current value's length if the iterator is valid. func (gi *gasIterator) Next() { - if gi.Valid() { - gi.consumeSeekGas() - } - + gi.consumeSeekGas() gi.parent.Next() } @@ -170,11 +172,16 @@ func (gi *gasIterator) Error() error { return gi.parent.Error() } -// consumeSeekGas consumes a flat gas cost for seeking and a variable gas cost +// consumeSeekGas consumes on each iteration step a flat gas cost and a variable gas cost // based on the current value's length. func (gi *gasIterator) consumeSeekGas() { - value := gi.Value() + if gi.Valid() { + key := gi.Key() + value := gi.Value() + + gi.gasMeter.ConsumeGas(gi.gasConfig.ReadCostPerByte*types.Gas(len(key)), types.GasValuePerByteDesc) + gi.gasMeter.ConsumeGas(gi.gasConfig.ReadCostPerByte*types.Gas(len(value)), types.GasValuePerByteDesc) + } - gi.gasMeter.ConsumeGas(gi.gasConfig.ReadCostPerByte*types.Gas(len(value)), types.GasValuePerByteDesc) gi.gasMeter.ConsumeGas(gi.gasConfig.IterNextCostFlat, types.GasIterNextCostFlatDesc) } diff --git a/store/gaskv/store_test.go b/store/gaskv/store_test.go index 5ff181e351..addf187e89 100644 --- a/store/gaskv/store_test.go +++ b/store/gaskv/store_test.go @@ -4,13 +4,13 @@ import ( "fmt" "testing" + "github.com/stretchr/testify/require" + "github.com/line/tm-db/v2/memdb" "github.com/line/lbm-sdk/store/dbadapter" "github.com/line/lbm-sdk/store/gaskv" "github.com/line/lbm-sdk/store/types" - - "github.com/stretchr/testify/require" ) func bz(s string) []byte { return []byte(s) } @@ -26,6 +26,7 @@ func TestGasKVStoreBasic(t *testing.T) { require.Equal(t, types.StoreTypeDB, st.GetStoreType()) require.Panics(t, func() { st.CacheWrap() }) require.Panics(t, func() { st.CacheWrapWithTrace(nil, nil) }) + require.Panics(t, func() { st.CacheWrapWithListeners(nil, nil) }) require.Panics(t, func() { st.Set(nil, []byte("value")) }, "setting a nil key should panic") require.Panics(t, func() { st.Set([]byte(""), []byte("value")) }, "setting an empty key should panic") @@ -36,19 +37,23 @@ func TestGasKVStoreBasic(t *testing.T) { require.Equal(t, valFmt(1), st.Get(keyFmt(1))) st.Delete(keyFmt(1)) require.Empty(t, st.Get(keyFmt(1)), "Expected `key1` to be empty") - require.Equal(t, meter.GasConsumed(), types.Gas(6429)) + require.Equal(t, meter.GasConsumed(), types.Gas(6858)) } func TestGasKVStoreIterator(t *testing.T) { mem := dbadapter.Store{DB: memdb.NewDB()} - meter := types.NewGasMeter(10000) + meter := types.NewGasMeter(100000) st := gaskv.NewStore(mem, meter, types.KVGasConfig()) require.False(t, st.Has(keyFmt(1))) require.Empty(t, st.Get(keyFmt(1)), "Expected `key1` to be empty") require.Empty(t, st.Get(keyFmt(2)), "Expected `key2` to be empty") + require.Empty(t, st.Get(keyFmt(3)), "Expected `key3` to be empty") + st.Set(keyFmt(1), valFmt(1)) require.True(t, st.Has(keyFmt(1))) st.Set(keyFmt(2), valFmt(2)) + require.True(t, st.Has(keyFmt(2))) + st.Set(keyFmt(3), valFmt(0)) iterator := st.Iterator(nil, nil) require.NoError(t, iterator.Error()) @@ -68,8 +73,18 @@ func TestGasKVStoreIterator(t *testing.T) { vb := iterator.Value() require.Equal(t, vb, valFmt(2)) iterator.Next() + + require.Equal(t, types.Gas(14565), meter.GasConsumed()) + kc := iterator.Key() + require.Equal(t, kc, keyFmt(3)) + vc := iterator.Value() + require.Equal(t, vc, valFmt(0)) + iterator.Next() + require.Equal(t, types.Gas(14667), meter.GasConsumed()) require.False(t, iterator.Valid()) require.Panics(t, iterator.Next) + require.Equal(t, types.Gas(14697), meter.GasConsumed()) + require.NoError(t, iterator.Error()) reverseIterator := st.ReverseIterator(nil, nil) @@ -78,6 +93,8 @@ func TestGasKVStoreIterator(t *testing.T) { t.Fatal(err) } }) + require.Equal(t, reverseIterator.Key(), keyFmt(3)) + reverseIterator.Next() require.Equal(t, reverseIterator.Key(), keyFmt(2)) reverseIterator.Next() require.Equal(t, reverseIterator.Key(), keyFmt(1)) @@ -85,7 +102,7 @@ func TestGasKVStoreIterator(t *testing.T) { require.False(t, reverseIterator.Valid()) require.Panics(t, reverseIterator.Next) - require.Equal(t, types.Gas(9194), meter.GasConsumed()) + require.Equal(t, types.Gas(15135), meter.GasConsumed()) } func TestGasKVStoreOutOfGasSet(t *testing.T) { diff --git a/store/iavl/store.go b/store/iavl/store.go index cb18e12d6d..30cce50ab3 100644 --- a/store/iavl/store.go +++ b/store/iavl/store.go @@ -8,12 +8,14 @@ import ( "time" ics23 "github.com/confio/ics23/go" + "github.com/line/iavl/v2" abci "github.com/line/ostracon/abci/types" occrypto "github.com/line/ostracon/proto/ostracon/crypto" tmdb "github.com/line/tm-db/v2" "github.com/line/lbm-sdk/store/cachekv" + "github.com/line/lbm-sdk/store/listenkv" "github.com/line/lbm-sdk/store/tracekv" "github.com/line/lbm-sdk/store/types" "github.com/line/lbm-sdk/telemetry" @@ -96,22 +98,20 @@ func NewCacheManagerNoCache() types.CacheManager { // LoadStore returns an IAVL Store as a CommitKVStore. Internally, it will load the // store's version (id) from the provided DB. An error is returned if the version // fails to load, or if called with a positive version on an empty tree. -func LoadStore(db tmdb.DB, cacheManager types.CacheManager, id types.CommitID, lazyLoading bool) ( - types.CommitKVStore, error) { - return LoadStoreWithInitialVersion(db, cacheManager, id, lazyLoading, 0) +func LoadStore(db tmdb.DB, cacheManager types.CacheManager, id types.CommitID, lazyLoading bool, cacheSize int) (types.CommitKVStore, error) { + return LoadStoreWithInitialVersion(db, cacheManager, id, lazyLoading, 0, cacheSize) } // LoadStoreWithInitialVersion returns an IAVL Store as a CommitKVStore setting its initialVersion // to the one given. Internally, it will load the store's version (id) from the // provided DB. An error is returned if the version fails to load, or if called with a positive // version on an empty tree. -func LoadStoreWithInitialVersion(db tmdb.DB, cacheManager types.CacheManager, id types.CommitID, lazyLoading bool, - initialVersion uint64) (types.CommitKVStore, error) { +func LoadStoreWithInitialVersion(db tmdb.DB, cacheManager types.CacheManager, id types.CommitID, lazyLoading bool, initialVersion uint64, cacheSize int) (types.CommitKVStore, error) { if cacheManager == nil { cacheManager = NewCacheManagerNoCache() } cache := cacheManager.GetCache() - tree, err := iavl.NewMutableTreeWithCacheWithOpts(db, cache, &iavl.Options{InitialVersion: initialVersion}) + tree, err := iavl.NewMutableTreeWithCacheWithOpts(db, cache, &iavl.Options{InitialVersion: initialVersion}) // TODO(dudong2): need to fix to use cacheSize(by using NewMutableTreeWithOpts) if err != nil { return nil, err } @@ -227,6 +227,11 @@ func (st *Store) CacheWrapWithTrace(w io.Writer, tc types.TraceContext) types.Ca return cachekv.NewStore(tracekv.NewStore(st, w, tc)) } +// CacheWrapWithListeners implements the CacheWrapper interface. +func (st *Store) CacheWrapWithListeners(storeKey types.StoreKey, listeners []types.WriteListener) types.CacheWrap { + return cachekv.NewStore(listenkv.NewStore(st, storeKey, listeners)) +} + // Implements types.KVStore. func (st *Store) Set(key, value []byte) { types.AssertValidKey(key) diff --git a/store/iavl/store_test.go b/store/iavl/store_test.go index 686656ca30..a78e2efbd6 100644 --- a/store/iavl/store_test.go +++ b/store/iavl/store_test.go @@ -11,6 +11,7 @@ import ( "github.com/line/tm-db/v2/memdb" "github.com/stretchr/testify/require" + "github.com/line/lbm-sdk/store/cachekv" "github.com/line/lbm-sdk/store/types" "github.com/line/lbm-sdk/types/kv" ) @@ -94,17 +95,17 @@ func TestLoadStore(t *testing.T) { require.Equal(t, string(hcStore.Get([]byte("hello"))), "ciao") // Querying a new store at some previous non-pruned height H - newHStore, err := LoadStore(db, NewCacheManagerNoCache(), cIDH, false) + newHStore, err := LoadStore(db, NewCacheManagerNoCache(), cIDH, false, DefaultIAVLCacheSize) require.NoError(t, err) require.Equal(t, string(newHStore.Get([]byte("hello"))), "hallo") // Querying a new store at some previous pruned height Hp - newHpStore, err := LoadStore(db, NewCacheManagerNoCache(), cIDHp, false) + newHpStore, err := LoadStore(db, NewCacheManagerNoCache(), cIDHp, false, DefaultIAVLCacheSize) require.NoError(t, err) require.Equal(t, string(newHpStore.Get([]byte("hello"))), "hola") // Querying a new store at current height H - newHcStore, err := LoadStore(db, NewCacheManagerNoCache(), cIDHc, false) + newHcStore, err := LoadStore(db, NewCacheManagerNoCache(), cIDHc, false, DefaultIAVLCacheSize) require.NoError(t, err) require.Equal(t, string(newHcStore.Get([]byte("hello"))), "ciao") } @@ -559,6 +560,7 @@ func TestIAVLStoreQuery(t *testing.T) { } func BenchmarkIAVLIteratorNext(b *testing.B) { + b.ReportAllocs() db := memdb.NewDB() treeSize := 1000 tree, err := iavl.NewMutableTree(db, cacheSize) @@ -636,3 +638,18 @@ func TestSetInitialVersion(t *testing.T) { }) } } + +func TestCacheWraps(t *testing.T) { + db := memdb.NewDB() + tree, _ := newAlohaTree(t, db) + store := UnsafeNewStore(tree) + + cacheWrapper := store.CacheWrap() + require.IsType(t, &cachekv.Store{}, cacheWrapper) + + cacheWrappedWithTrace := store.CacheWrapWithTrace(nil, nil) + require.IsType(t, &cachekv.Store{}, cacheWrappedWithTrace) + + cacheWrappedWithListeners := store.CacheWrapWithListeners(nil, nil) + require.IsType(t, &cachekv.Store{}, cacheWrappedWithListeners) +} diff --git a/store/listenkv/store.go b/store/listenkv/store.go new file mode 100644 index 0000000000..cb9e590bb2 --- /dev/null +++ b/store/listenkv/store.go @@ -0,0 +1,163 @@ +package listenkv + +import ( + "io" + "time" + + "github.com/line/lbm-sdk/store/types" + "github.com/line/lbm-sdk/telemetry" +) + +var _ types.KVStore = &Store{} + +// Store implements the KVStore interface with listening enabled. +// Operations are traced on each core KVStore call and written to any of the +// underlying listeners with the proper key and operation permissions +type Store struct { + parent types.KVStore + listeners []types.WriteListener + parentStoreKey types.StoreKey +} + +// NewStore returns a reference to a new traceKVStore given a parent +// KVStore implementation and a buffered writer. +func NewStore(parent types.KVStore, parentStoreKey types.StoreKey, listeners []types.WriteListener) *Store { + return &Store{parent: parent, listeners: listeners, parentStoreKey: parentStoreKey} +} + +// Get implements the KVStore interface. It traces a read operation and +// delegates a Get call to the parent KVStore. +func (s *Store) Get(key []byte) []byte { + value := s.parent.Get(key) + return value +} + +// Set implements the KVStore interface. It traces a write operation and +// delegates the Set call to the parent KVStore. +func (s *Store) Set(key []byte, value []byte) { + types.AssertValidKey(key) + s.parent.Set(key, value) + s.onWrite(false, key, value) +} + +// Delete implements the KVStore interface. It traces a write operation and +// delegates the Delete call to the parent KVStore. +func (s *Store) Delete(key []byte) { + s.parent.Delete(key) + s.onWrite(true, key, nil) +} + +// Prefetch implements types.KVStore. +func (s *Store) Prefetch(key []byte, forSet bool) (hits, misses int, value []byte) { + defer telemetry.MeasureSince(time.Now(), "store", "cachekv", "prefetch") + + // do not update cache + types.AssertValidKey(key) + return s.parent.Prefetch(key, forSet) +} + +// Has implements the KVStore interface. It delegates the Has call to the +// parent KVStore. +func (s *Store) Has(key []byte) bool { + return s.parent.Has(key) +} + +// Iterator implements the KVStore interface. It delegates the Iterator call +// the to the parent KVStore. +func (s *Store) Iterator(start, end []byte) types.Iterator { + return s.iterator(start, end, true) +} + +// ReverseIterator implements the KVStore interface. It delegates the +// ReverseIterator call the to the parent KVStore. +func (s *Store) ReverseIterator(start, end []byte) types.Iterator { + return s.iterator(start, end, false) +} + +// iterator facilitates iteration over a KVStore. It delegates the necessary +// calls to it's parent KVStore. +func (s *Store) iterator(start, end []byte, ascending bool) types.Iterator { + var parent types.Iterator + + if ascending { + parent = s.parent.Iterator(start, end) + } else { + parent = s.parent.ReverseIterator(start, end) + } + + return newTraceIterator(parent, s.listeners) +} + +type listenIterator struct { + parent types.Iterator + listeners []types.WriteListener +} + +func newTraceIterator(parent types.Iterator, listeners []types.WriteListener) types.Iterator { + return &listenIterator{parent: parent, listeners: listeners} +} + +// TODO(dudong2): remove Domain() func (removed in other stores by woosang). Add it later, if it's needed. + +// Valid implements the Iterator interface. +func (li *listenIterator) Valid() bool { + return li.parent.Valid() +} + +// Next implements the Iterator interface. +func (li *listenIterator) Next() { + li.parent.Next() +} + +// Key implements the Iterator interface. +func (li *listenIterator) Key() []byte { + key := li.parent.Key() + return key +} + +// Value implements the Iterator interface. +func (li *listenIterator) Value() []byte { + value := li.parent.Value() + return value +} + +// Close implements the Iterator interface. +func (li *listenIterator) Close() error { + return li.parent.Close() +} + +// Error delegates the Error call to the parent iterator. +func (li *listenIterator) Error() error { + return li.parent.Error() +} + +// GetStoreType implements the KVStore interface. It returns the underlying +// KVStore type. +func (s *Store) GetStoreType() types.StoreType { + return s.parent.GetStoreType() +} + +// CacheWrap implements the KVStore interface. It panics as a Store +// cannot be cache wrapped. +func (s *Store) CacheWrap() types.CacheWrap { + panic("cannot CacheWrap a ListenKVStore") +} + +// CacheWrapWithTrace implements the KVStore interface. It panics as a +// Store cannot be cache wrapped. +func (s *Store) CacheWrapWithTrace(_ io.Writer, _ types.TraceContext) types.CacheWrap { + panic("cannot CacheWrapWithTrace a ListenKVStore") +} + +// CacheWrapWithListeners implements the KVStore interface. It panics as a +// Store cannot be cache wrapped. +func (s *Store) CacheWrapWithListeners(_ types.StoreKey, _ []types.WriteListener) types.CacheWrap { + panic("cannot CacheWrapWithListeners a ListenKVStore") +} + +// onWrite writes a KVStore operation to all of the WriteListeners +func (s *Store) onWrite(delete bool, key, value []byte) { + for _, l := range s.listeners { + l.OnWrite(s.parentStoreKey, key, value, delete) + } +} diff --git a/store/listenkv/store_test.go b/store/listenkv/store_test.go new file mode 100644 index 0000000000..7b1f37a5d4 --- /dev/null +++ b/store/listenkv/store_test.go @@ -0,0 +1,290 @@ +package listenkv_test + +import ( + "bytes" + "fmt" + "io" + "testing" + + "github.com/stretchr/testify/require" + + "github.com/line/tm-db/v2/memdb" + + "github.com/line/lbm-sdk/codec" + codecTypes "github.com/line/lbm-sdk/codec/types" + "github.com/line/lbm-sdk/store/dbadapter" + "github.com/line/lbm-sdk/store/listenkv" + "github.com/line/lbm-sdk/store/prefix" + "github.com/line/lbm-sdk/store/types" +) + +func bz(s string) []byte { return []byte(s) } + +func keyFmt(i int) []byte { return bz(fmt.Sprintf("key%0.8d", i)) } +func valFmt(i int) []byte { return bz(fmt.Sprintf("value%0.8d", i)) } + +var kvPairs = []types.KVPair{ + {Key: keyFmt(1), Value: valFmt(1)}, + {Key: keyFmt(2), Value: valFmt(2)}, + {Key: keyFmt(3), Value: valFmt(3)}, +} + +var testStoreKey = types.NewKVStoreKey("listen_test") +var interfaceRegistry = codecTypes.NewInterfaceRegistry() +var testMarshaller = codec.NewProtoCodec(interfaceRegistry) + +func newListenKVStore(w io.Writer) *listenkv.Store { + store := newEmptyListenKVStore(w) + + for _, kvPair := range kvPairs { + store.Set(kvPair.Key, kvPair.Value) + } + + return store +} + +func newEmptyListenKVStore(w io.Writer) *listenkv.Store { + listener := types.NewStoreKVPairWriteListener(w, testMarshaller) + memDB := dbadapter.Store{DB: memdb.NewDB()} + + return listenkv.NewStore(memDB, testStoreKey, []types.WriteListener{listener}) +} + +func TestListenKVStoreGet(t *testing.T) { + testCases := []struct { + key []byte + expectedValue []byte + }{ + { + key: kvPairs[0].Key, + expectedValue: kvPairs[0].Value, + }, + { + key: []byte("does-not-exist"), + expectedValue: nil, + }, + } + + for _, tc := range testCases { + var buf bytes.Buffer + + store := newListenKVStore(&buf) + buf.Reset() + value := store.Get(tc.key) + + require.Equal(t, tc.expectedValue, value) + } +} + +func TestListenKVStoreSet(t *testing.T) { + testCases := []struct { + key []byte + value []byte + expectedOut *types.StoreKVPair + }{ + { + key: kvPairs[0].Key, + value: kvPairs[0].Value, + expectedOut: &types.StoreKVPair{ + Key: kvPairs[0].Key, + Value: kvPairs[0].Value, + StoreKey: testStoreKey.Name(), + Delete: false, + }, + }, + { + key: kvPairs[1].Key, + value: kvPairs[1].Value, + expectedOut: &types.StoreKVPair{ + Key: kvPairs[1].Key, + Value: kvPairs[1].Value, + StoreKey: testStoreKey.Name(), + Delete: false, + }, + }, + { + key: kvPairs[2].Key, + value: kvPairs[2].Value, + expectedOut: &types.StoreKVPair{ + Key: kvPairs[2].Key, + Value: kvPairs[2].Value, + StoreKey: testStoreKey.Name(), + Delete: false, + }, + }, + } + + for _, tc := range testCases { + var buf bytes.Buffer + + store := newEmptyListenKVStore(&buf) + buf.Reset() + store.Set(tc.key, tc.value) + storeKVPair := new(types.StoreKVPair) + testMarshaller.UnmarshalLengthPrefixed(buf.Bytes(), storeKVPair) + + require.Equal(t, tc.expectedOut, storeKVPair) + } + + var buf bytes.Buffer + store := newEmptyListenKVStore(&buf) + require.Panics(t, func() { store.Set([]byte(""), []byte("value")) }, "setting an empty key should panic") + require.Panics(t, func() { store.Set(nil, []byte("value")) }, "setting a nil key should panic") + +} + +func TestListenKVStoreDelete(t *testing.T) { + testCases := []struct { + key []byte + expectedOut *types.StoreKVPair + }{ + { + key: kvPairs[0].Key, + expectedOut: &types.StoreKVPair{ + Key: kvPairs[0].Key, + Value: nil, + StoreKey: testStoreKey.Name(), + Delete: true, + }, + }, + } + + for _, tc := range testCases { + var buf bytes.Buffer + + store := newListenKVStore(&buf) + buf.Reset() + store.Delete(tc.key) + storeKVPair := new(types.StoreKVPair) + testMarshaller.UnmarshalLengthPrefixed(buf.Bytes(), storeKVPair) + + require.Equal(t, tc.expectedOut, storeKVPair) + } +} + +func TestListenKVStoreHas(t *testing.T) { + testCases := []struct { + key []byte + expected bool + }{ + { + key: kvPairs[0].Key, + expected: true, + }, + } + + for _, tc := range testCases { + var buf bytes.Buffer + + store := newListenKVStore(&buf) + buf.Reset() + ok := store.Has(tc.key) + + require.Equal(t, tc.expected, ok) + } +} + +func TestTestListenKVStoreIterator(t *testing.T) { + var buf bytes.Buffer + + store := newListenKVStore(&buf) + iterator := store.Iterator(nil, nil) + + testCases := []struct { + expectedKey []byte + expectedValue []byte + }{ + { + expectedKey: kvPairs[0].Key, + expectedValue: kvPairs[0].Value, + }, + { + expectedKey: kvPairs[1].Key, + expectedValue: kvPairs[1].Value, + }, + { + expectedKey: kvPairs[2].Key, + expectedValue: kvPairs[2].Value, + }, + } + + for _, tc := range testCases { + ka := iterator.Key() + require.Equal(t, tc.expectedKey, ka) + + va := iterator.Value() + require.Equal(t, tc.expectedValue, va) + + iterator.Next() + } + + require.False(t, iterator.Valid()) + require.Panics(t, iterator.Next) + require.NoError(t, iterator.Close()) +} + +func TestTestListenKVStoreReverseIterator(t *testing.T) { + var buf bytes.Buffer + + store := newListenKVStore(&buf) + iterator := store.ReverseIterator(nil, nil) + + testCases := []struct { + expectedKey []byte + expectedValue []byte + }{ + { + expectedKey: kvPairs[2].Key, + expectedValue: kvPairs[2].Value, + }, + { + expectedKey: kvPairs[1].Key, + expectedValue: kvPairs[1].Value, + }, + { + expectedKey: kvPairs[0].Key, + expectedValue: kvPairs[0].Value, + }, + } + + for _, tc := range testCases { + ka := iterator.Key() + require.Equal(t, tc.expectedKey, ka) + + va := iterator.Value() + require.Equal(t, tc.expectedValue, va) + + iterator.Next() + } + + require.False(t, iterator.Valid()) + require.Panics(t, iterator.Next) + require.NoError(t, iterator.Close()) +} + +func TestListenKVStorePrefix(t *testing.T) { + store := newEmptyListenKVStore(nil) + pStore := prefix.NewStore(store, []byte("listen_prefix")) + require.IsType(t, prefix.Store{}, pStore) +} + +func TestListenKVStoreGetStoreType(t *testing.T) { + memDB := dbadapter.Store{DB: memdb.NewDB()} + store := newEmptyListenKVStore(nil) + require.Equal(t, memDB.GetStoreType(), store.GetStoreType()) +} + +func TestListenKVStoreCacheWrap(t *testing.T) { + store := newEmptyListenKVStore(nil) + require.Panics(t, func() { store.CacheWrap() }) +} + +func TestListenKVStoreCacheWrapWithTrace(t *testing.T) { + store := newEmptyListenKVStore(nil) + require.Panics(t, func() { store.CacheWrapWithTrace(nil, nil) }) +} + +func TestListenKVStoreCacheWrapWithListeners(t *testing.T) { + store := newEmptyListenKVStore(nil) + require.Panics(t, func() { store.CacheWrapWithListeners(nil, nil) }) +} diff --git a/store/mem/mem_test.go b/store/mem/mem_test.go index f6b1c7a1a9..7ee352f869 100644 --- a/store/mem/mem_test.go +++ b/store/mem/mem_test.go @@ -3,6 +3,8 @@ package mem_test import ( "testing" + "github.com/line/lbm-sdk/store/cachekv" + "github.com/stretchr/testify/require" "github.com/line/lbm-sdk/store/mem" @@ -25,6 +27,15 @@ func TestStore(t *testing.T) { db.Delete(key) require.Nil(t, db.Get(key)) + + cacheWrapper := db.CacheWrap() + require.IsType(t, &cachekv.Store{}, cacheWrapper) + + cacheWrappedWithTrace := db.CacheWrapWithTrace(nil, nil) + require.IsType(t, &cachekv.Store{}, cacheWrappedWithTrace) + + cacheWrappedWithListeners := db.CacheWrapWithListeners(nil, nil) + require.IsType(t, &cachekv.Store{}, cacheWrappedWithListeners) } func TestCommit(t *testing.T) { diff --git a/store/mem/store.go b/store/mem/store.go index 6e225012f0..1766c98ad0 100644 --- a/store/mem/store.go +++ b/store/mem/store.go @@ -7,6 +7,7 @@ import ( "github.com/line/lbm-sdk/store/cachekv" "github.com/line/lbm-sdk/store/dbadapter" + "github.com/line/lbm-sdk/store/listenkv" "github.com/line/lbm-sdk/store/tracekv" "github.com/line/lbm-sdk/store/types" ) @@ -45,6 +46,11 @@ func (s Store) CacheWrapWithTrace(w io.Writer, tc types.TraceContext) types.Cach return cachekv.NewStore(tracekv.NewStore(s, w, tc)) } +// CacheWrapWithListeners implements the CacheWrapper interface. +func (s Store) CacheWrapWithListeners(storeKey types.StoreKey, listeners []types.WriteListener) types.CacheWrap { + return cachekv.NewStore(listenkv.NewStore(s, storeKey, listeners)) +} + // Commit performs a no-op as entries are persistent between commitments. func (s *Store) Commit() (id types.CommitID) { return } diff --git a/store/prefix/store.go b/store/prefix/store.go index 1e5d30ec34..f67319dcd7 100644 --- a/store/prefix/store.go +++ b/store/prefix/store.go @@ -6,6 +6,7 @@ import ( "io" "github.com/line/lbm-sdk/store/cachekv" + "github.com/line/lbm-sdk/store/listenkv" "github.com/line/lbm-sdk/store/tracekv" "github.com/line/lbm-sdk/store/types" ) @@ -57,6 +58,11 @@ func (s Store) CacheWrapWithTrace(w io.Writer, tc types.TraceContext) types.Cach return cachekv.NewStore(tracekv.NewStore(s, w, tc)) } +// CacheWrapWithListeners implements the CacheWrapper interface. +func (s Store) CacheWrapWithListeners(storeKey types.StoreKey, listeners []types.WriteListener) types.CacheWrap { + return cachekv.NewStore(listenkv.NewStore(s, storeKey, listeners)) +} + // Implements KVStore func (s Store) Get(key []byte) []byte { res := s.parent.Get(s.key(key)) diff --git a/store/prefix/store_test.go b/store/prefix/store_test.go index 4023a967e4..9ef6378321 100644 --- a/store/prefix/store_test.go +++ b/store/prefix/store_test.go @@ -7,6 +7,7 @@ import ( "github.com/stretchr/testify/require" liavl "github.com/line/iavl/v2" + "github.com/line/lbm-sdk/store/cachekv" "github.com/line/tm-db/v2/memdb" "github.com/line/lbm-sdk/store/dbadapter" @@ -411,3 +412,17 @@ func TestPrefixDBReverseIterator4(t *testing.T) { checkInvalid(t, itr) itr.Close() } + +func TestCacheWraps(t *testing.T) { + db := memdb.NewDB() + store := dbadapter.Store{DB: db} + + cacheWrapper := store.CacheWrap() + require.IsType(t, &cachekv.Store{}, cacheWrapper) + + cacheWrappedWithTrace := store.CacheWrapWithTrace(nil, nil) + require.IsType(t, &cachekv.Store{}, cacheWrappedWithTrace) + + cacheWrappedWithListeners := store.CacheWrapWithListeners(nil, nil) + require.IsType(t, &cachekv.Store{}, cacheWrappedWithListeners) +} diff --git a/store/rootmulti/proof_test.go b/store/rootmulti/proof_test.go index efdc645646..ef596dc1f6 100644 --- a/store/rootmulti/proof_test.go +++ b/store/rootmulti/proof_test.go @@ -14,7 +14,7 @@ import ( func TestVerifyIAVLStoreQueryProof(t *testing.T) { // Create main tree for testing. db := memdb.NewDB() - iStore, err := iavl.LoadStore(db, iavl.NewCacheManagerNoCache(), types.CommitID{}, false) + iStore, err := iavl.LoadStore(db, iavl.NewCacheManagerNoCache(), types.CommitID{}, false, iavl.DefaultIAVLCacheSize) store := iStore.(*iavl.Store) require.Nil(t, err) store.Set([]byte("MYKEY"), []byte("MYVALUE")) diff --git a/store/rootmulti/store.go b/store/rootmulti/store.go index abed5569d0..4bc4b34e03 100644 --- a/store/rootmulti/store.go +++ b/store/rootmulti/store.go @@ -24,8 +24,10 @@ import ( "github.com/line/lbm-sdk/store/cachemulti" "github.com/line/lbm-sdk/store/dbadapter" "github.com/line/lbm-sdk/store/iavl" + "github.com/line/lbm-sdk/store/listenkv" "github.com/line/lbm-sdk/store/mem" "github.com/line/lbm-sdk/store/tracekv" + "github.com/line/lbm-sdk/store/transient" "github.com/line/lbm-sdk/store/types" sdkerrors "github.com/line/lbm-sdk/types/errors" ) @@ -48,6 +50,7 @@ type Store struct { db tmdb.DB lastCommitInfo *types.CommitInfo pruningOpts types.PruningOptions + iavlCacheSize int storesParams map[types.StoreKey]storeParams stores map[types.StoreKey]types.CommitKVStore keysByName map[string]types.StoreKey @@ -63,6 +66,8 @@ type Store struct { pruneLock *sync.Mutex prunePass chan bool + + listeners map[types.StoreKey][]types.WriteListener } var ( @@ -76,14 +81,16 @@ var ( // LoadVersion must be called. func NewStore(db tmdb.DB) *Store { return &Store{ - db: db, - pruningOpts: types.PruneNothing, - storesParams: make(map[types.StoreKey]storeParams), - stores: make(map[types.StoreKey]types.CommitKVStore), - keysByName: make(map[string]types.StoreKey), - pruneHeights: make([]int64, 0), - pruneLock: &sync.Mutex{}, - prunePass: make(chan bool, 1), + db: db, + pruningOpts: types.PruneNothing, + storesParams: make(map[types.StoreKey]storeParams), + stores: make(map[types.StoreKey]types.CommitKVStore), + keysByName: make(map[string]types.StoreKey), + pruneHeights: make([]int64, 0), + pruneLock: &sync.Mutex{}, + prunePass: make(chan bool, 1), + listeners: make(map[types.StoreKey][]types.WriteListener), + iavlCacheSize: iavl.DefaultIAVLCacheSize, } } @@ -99,6 +106,10 @@ func (rs *Store) SetPruning(pruningOpts types.PruningOptions) { rs.pruningOpts = pruningOpts } +func (rs *Store) SetIAVLCacheSize(cacheSize int) { + rs.iavlCacheSize = cacheSize +} + // SetLazyLoading sets if the iavl store should be loaded lazily or not func (rs *Store) SetLazyLoading(lazyLoading bool) { rs.lazyLoading = lazyLoading @@ -204,8 +215,8 @@ func (rs *Store) loadVersion(ver int64, upgrades *types.StoreUpgrades) error { } if upgrades != nil { // deterministic iteration order for upgrades - // (as the underlyin store may change and - // upgrades make store change where the execution order may matter) + // (as the underlying store may change and + // upgrades make store changes where the execution order may matter) sort.Slice(storesKeys, func(i, j int) bool { return storesKeys[i].Name() < storesKeys[j].Name() }) @@ -338,6 +349,23 @@ func (rs *Store) TracingEnabled() bool { return rs.traceWriter != nil } +// AddListeners adds listeners for a specific KVStore +func (rs *Store) AddListeners(key types.StoreKey, listeners []types.WriteListener) { + if ls, ok := rs.listeners[key]; ok { + rs.listeners[key] = append(ls, listeners...) + } else { + rs.listeners[key] = listeners + } +} + +// ListeningEnabled returns if listening is enabled for a specific KVStore +func (rs *Store) ListeningEnabled(key types.StoreKey) bool { + if ls, ok := rs.listeners[key]; ok { + return len(ls) != 0 + } + return false +} + // LastCommitID implements Committer/CommitStore. func (rs *Store) LastCommitID() types.CommitID { if rs.lastCommitInfo == nil { @@ -474,6 +502,11 @@ func (rs *Store) CacheWrapWithTrace(_ io.Writer, _ types.TraceContext) types.Cac return rs.CacheWrap() } +// CacheWrapWithListeners implements the CacheWrapper interface. +func (rs *Store) CacheWrapWithListeners(_ types.StoreKey, _ []types.WriteListener) types.CacheWrap { + return rs.CacheWrap() +} + // CacheMultiStore creates ephemeral branch of the multi-store and returns a CacheMultiStore. // It implements the MultiStore interface. func (rs *Store) CacheMultiStore() types.CacheMultiStore { @@ -481,8 +514,7 @@ func (rs *Store) CacheMultiStore() types.CacheMultiStore { for k, v := range rs.stores { stores[k] = v } - - return cachemulti.NewStore(rs.db, stores, rs.keysByName, rs.traceWriter, rs.traceContext) + return cachemulti.NewStore(rs.db, stores, rs.keysByName, rs.traceWriter, rs.traceContext, rs.listeners) } // CacheMultiStoreWithVersion is analogous to CacheMultiStore except that it @@ -512,7 +544,7 @@ func (rs *Store) CacheMultiStoreWithVersion(version int64) (types.CacheMultiStor } } - return cachemulti.NewStore(rs.db, cachedStores, rs.keysByName, rs.traceWriter, rs.traceContext), nil + return cachemulti.NewStore(rs.db, cachedStores, rs.keysByName, rs.traceWriter, rs.traceContext, rs.listeners), nil } // GetStore returns a mounted Store for a given StoreKey. If the StoreKey does @@ -546,6 +578,9 @@ func (rs *Store) GetKVStore(key types.StoreKey) types.KVStore { if rs.TracingEnabled() { store = tracekv.NewStore(store, rs.traceWriter, rs.traceContext) } + if rs.ListeningEnabled(key) { + store = listenkv.NewStore(store, key, rs.listeners[key]) + } return store } @@ -903,10 +938,9 @@ func (rs *Store) loadCommitStoreFromParams(key types.StoreKey, id types.CommitID var err error if params.initialVersion == 0 { - store, err = iavl.LoadStore(db, rs.iavlCacheManager, id, rs.lazyLoading) + store, err = iavl.LoadStore(db, rs.iavlCacheManager, id, rs.lazyLoading, rs.iavlCacheSize) } else { - store, err = iavl.LoadStoreWithInitialVersion(db, rs.iavlCacheManager, id, rs.lazyLoading, - params.initialVersion) + store, err = iavl.LoadStoreWithInitialVersion(db, rs.iavlCacheManager, id, rs.lazyLoading, params.initialVersion, rs.iavlCacheSize) } if err != nil { @@ -925,6 +959,14 @@ func (rs *Store) loadCommitStoreFromParams(key types.StoreKey, id types.CommitID case types.StoreTypeDB: return commitDBStoreAdapter{Store: dbadapter.Store{DB: db}}, nil + case types.StoreTypeTransient: + _, ok := key.(*types.TransientStoreKey) + if !ok { + return nil, fmt.Errorf("invalid StoreKey for StoreTypeTransient: %s", key.String()) + } + + return transient.NewStore(), nil + case types.StoreTypeMemory: if _, ok := key.(*types.MemoryStoreKey); !ok { return nil, fmt.Errorf("unexpected key type for a MemoryStoreKey; got: %s", key.String()) diff --git a/store/rootmulti/store_test.go b/store/rootmulti/store_test.go index 167ab86e65..f2fcd51227 100644 --- a/store/rootmulti/store_test.go +++ b/store/rootmulti/store_test.go @@ -1,6 +1,7 @@ package rootmulti import ( + "bytes" "crypto/sha256" "encoding/binary" "encoding/hex" @@ -20,9 +21,13 @@ import ( tmdb "github.com/line/tm-db/v2" "github.com/line/tm-db/v2/memdb" + "github.com/line/lbm-sdk/codec" + codecTypes "github.com/line/lbm-sdk/codec/types" snapshottypes "github.com/line/lbm-sdk/snapshots/types" + "github.com/line/lbm-sdk/store/cachemulti" "github.com/line/lbm-sdk/store/iavl" sdkmaps "github.com/line/lbm-sdk/store/internal/maps" + "github.com/line/lbm-sdk/store/listenkv" "github.com/line/lbm-sdk/store/types" sdkerrors "github.com/line/lbm-sdk/types/errors" ) @@ -66,6 +71,14 @@ func TestStoreMount(t *testing.T) { require.Panics(t, func() { store.MountStoreWithDB(dup1, types.StoreTypeIAVL, db) }) } +func TestCacheMultiStore(t *testing.T) { + var db tmdb.DB = memdb.NewDB() + ms := newMultiStoreWithMounts(db, types.PruneNothing) + + cacheMulti := ms.CacheMultiStore() + require.IsType(t, cachemulti.Store{}, cacheMulti) +} + func TestCacheMultiStoreWithVersion(t *testing.T) { var db tmdb.DB = memdb.NewDB() ms := newMultiStoreWithMounts(db, types.PruneNothing) @@ -685,6 +698,125 @@ func TestSetInitialVersion(t *testing.T) { require.True(t, iavlStore.VersionExists(5)) } +func TestAddListenersAndListeningEnabled(t *testing.T) { + db := memdb.NewDB() + multi := newMultiStoreWithMounts(db, types.PruneNothing) + testKey := types.NewKVStoreKey("listening_test_key") + enabled := multi.ListeningEnabled(testKey) + require.False(t, enabled) + + multi.AddListeners(testKey, []types.WriteListener{}) + enabled = multi.ListeningEnabled(testKey) + require.False(t, enabled) + + mockListener := types.NewStoreKVPairWriteListener(nil, nil) + multi.AddListeners(testKey, []types.WriteListener{mockListener}) + wrongTestKey := types.NewKVStoreKey("wrong_listening_test_key") + enabled = multi.ListeningEnabled(wrongTestKey) + require.False(t, enabled) + + enabled = multi.ListeningEnabled(testKey) + require.True(t, enabled) +} + +var ( + interfaceRegistry = codecTypes.NewInterfaceRegistry() + testMarshaller = codec.NewProtoCodec(interfaceRegistry) + testKey1 = []byte{1, 2, 3, 4, 5} + testValue1 = []byte{5, 4, 3, 2, 1} + testKey2 = []byte{2, 3, 4, 5, 6} + testValue2 = []byte{6, 5, 4, 3, 2} +) + +func TestGetListenWrappedKVStore(t *testing.T) { + buf := new(bytes.Buffer) + var db tmdb.DB = memdb.NewDB() + ms := newMultiStoreWithMounts(db, types.PruneNothing) + ms.LoadLatestVersion() + mockListeners := []types.WriteListener{types.NewStoreKVPairWriteListener(buf, testMarshaller)} + ms.AddListeners(testStoreKey1, mockListeners) + ms.AddListeners(testStoreKey2, mockListeners) + + listenWrappedStore1 := ms.GetKVStore(testStoreKey1) + require.IsType(t, &listenkv.Store{}, listenWrappedStore1) + + listenWrappedStore1.Set(testKey1, testValue1) + expectedOutputKVPairSet1, err := testMarshaller.MarshalLengthPrefixed(&types.StoreKVPair{ + Key: testKey1, + Value: testValue1, + StoreKey: testStoreKey1.Name(), + Delete: false, + }) + require.Nil(t, err) + kvPairSet1Bytes := buf.Bytes() + buf.Reset() + require.Equal(t, expectedOutputKVPairSet1, kvPairSet1Bytes) + + listenWrappedStore1.Delete(testKey1) + expectedOutputKVPairDelete1, err := testMarshaller.MarshalLengthPrefixed(&types.StoreKVPair{ + Key: testKey1, + Value: nil, + StoreKey: testStoreKey1.Name(), + Delete: true, + }) + require.Nil(t, err) + kvPairDelete1Bytes := buf.Bytes() + buf.Reset() + require.Equal(t, expectedOutputKVPairDelete1, kvPairDelete1Bytes) + + listenWrappedStore2 := ms.GetKVStore(testStoreKey2) + require.IsType(t, &listenkv.Store{}, listenWrappedStore2) + + listenWrappedStore2.Set(testKey2, testValue2) + expectedOutputKVPairSet2, err := testMarshaller.MarshalLengthPrefixed(&types.StoreKVPair{ + Key: testKey2, + Value: testValue2, + StoreKey: testStoreKey2.Name(), + Delete: false, + }) + kvPairSet2Bytes := buf.Bytes() + buf.Reset() + require.Equal(t, expectedOutputKVPairSet2, kvPairSet2Bytes) + + listenWrappedStore2.Delete(testKey2) + expectedOutputKVPairDelete2, err := testMarshaller.MarshalLengthPrefixed(&types.StoreKVPair{ + Key: testKey2, + Value: nil, + StoreKey: testStoreKey2.Name(), + Delete: true, + }) + kvPairDelete2Bytes := buf.Bytes() + buf.Reset() + require.Equal(t, expectedOutputKVPairDelete2, kvPairDelete2Bytes) + + unwrappedStore := ms.GetKVStore(testStoreKey3) + require.IsType(t, &iavl.Store{}, unwrappedStore) + + unwrappedStore.Set(testKey2, testValue2) + kvPairSet3Bytes := buf.Bytes() + buf.Reset() + require.Equal(t, []byte{}, kvPairSet3Bytes) + + unwrappedStore.Delete(testKey2) + kvPairDelete3Bytes := buf.Bytes() + buf.Reset() + require.Equal(t, []byte{}, kvPairDelete3Bytes) +} + +func TestCacheWraps(t *testing.T) { + db := memdb.NewDB() + multi := newMultiStoreWithMounts(db, types.PruneNothing) + + cacheWrapper := multi.CacheWrap() + require.IsType(t, cachemulti.Store{}, cacheWrapper) + + cacheWrappedWithTrace := multi.CacheWrapWithTrace(nil, nil) + require.IsType(t, cachemulti.Store{}, cacheWrappedWithTrace) + + cacheWrappedWithListeners := multi.CacheWrapWithListeners(nil, nil) + require.IsType(t, cachemulti.Store{}, cacheWrappedWithListeners) +} + func BenchmarkMultistoreSnapshot100K(b *testing.B) { benchmarkMultistoreSnapshot(b, 10, 10000) } @@ -761,13 +893,19 @@ func benchmarkMultistoreSnapshotRestore(b *testing.B, stores uint8, storeKeys ui //----------------------------------------------------------------------- // utils +var ( + testStoreKey1 = types.NewKVStoreKey("store1") + testStoreKey2 = types.NewKVStoreKey("store2") + testStoreKey3 = types.NewKVStoreKey("store3") +) + func newMultiStoreWithMounts(db tmdb.DB, pruningOpts types.PruningOptions) *Store { store := NewStore(db) store.pruningOpts = pruningOpts - store.MountStoreWithDB(types.NewKVStoreKey("store1"), types.StoreTypeIAVL, nil) - store.MountStoreWithDB(types.NewKVStoreKey("store2"), types.StoreTypeIAVL, nil) - store.MountStoreWithDB(types.NewKVStoreKey("store3"), types.StoreTypeIAVL, nil) + store.MountStoreWithDB(testStoreKey1, types.StoreTypeIAVL, nil) + store.MountStoreWithDB(testStoreKey2, types.StoreTypeIAVL, nil) + store.MountStoreWithDB(testStoreKey3, types.StoreTypeIAVL, nil) return store } diff --git a/store/tracekv/store.go b/store/tracekv/store.go index 58d1ec9830..e43c11130c 100644 --- a/store/tracekv/store.go +++ b/store/tracekv/store.go @@ -165,13 +165,18 @@ func (tkv *Store) GetStoreType() types.StoreType { // CacheWrap implements the KVStore interface. It panics because a Store // cannot be branched. func (tkv *Store) CacheWrap() types.CacheWrap { - panic("cannot CacheWrap a Store") + panic("cannot CacheWrap a TraceKVStore") } // CacheWrapWithTrace implements the KVStore interface. It panics as a // Store cannot be branched. func (tkv *Store) CacheWrapWithTrace(_ io.Writer, _ types.TraceContext) types.CacheWrap { - panic("cannot CacheWrapWithTrace a Store") + panic("cannot CacheWrapWithTrace a TraceKVStore") +} + +// CacheWrapWithListeners implements the CacheWrapper interface. +func (tkv *Store) CacheWrapWithListeners(_ types.StoreKey, _ []types.WriteListener) types.CacheWrap { + panic("cannot CacheWrapWithListeners a TraceKVStore") } // writeOperation writes a KVStore operation to the underlying io.Writer as diff --git a/store/tracekv/store_test.go b/store/tracekv/store_test.go index 540cd3a81f..a4b5cae8a9 100644 --- a/store/tracekv/store_test.go +++ b/store/tracekv/store_test.go @@ -279,7 +279,13 @@ func TestTraceKVStoreCacheWrap(t *testing.T) { store := newEmptyTraceKVStore(nil) require.Panics(t, func() { store.CacheWrap() }) } + func TestTraceKVStoreCacheWrapWithTrace(t *testing.T) { store := newEmptyTraceKVStore(nil) require.Panics(t, func() { store.CacheWrapWithTrace(nil, nil) }) } + +func TestTraceKVStoreCacheWrapWithListeners(t *testing.T) { + store := newEmptyTraceKVStore(nil) + require.Panics(t, func() { store.CacheWrapWithListeners(nil, nil) }) +} diff --git a/store/transient/store.go b/store/transient/store.go new file mode 100644 index 0000000000..f24af40601 --- /dev/null +++ b/store/transient/store.go @@ -0,0 +1,44 @@ +package transient + +import ( + "github.com/line/tm-db/v2/memdb" + + "github.com/line/lbm-sdk/store/dbadapter" + "github.com/line/lbm-sdk/store/types" +) + +var _ types.Committer = (*Store)(nil) +var _ types.KVStore = (*Store)(nil) + +// Store is a wrapper for a MemDB with Commiter implementation +type Store struct { + dbadapter.Store +} + +// Constructs new MemDB adapter +func NewStore() *Store { + return &Store{Store: dbadapter.Store{DB: memdb.NewDB()}} +} + +// Implements CommitStore +// Commit cleans up Store. +func (ts *Store) Commit() (id types.CommitID) { + ts.Store = dbadapter.Store{DB: memdb.NewDB()} + return +} + +func (ts *Store) SetPruning(_ types.PruningOptions) {} + +// GetPruning is a no-op as pruning options cannot be directly set on this store. +// They must be set on the root commit multi-store. +func (ts *Store) GetPruning() types.PruningOptions { return types.PruningOptions{} } + +// Implements CommitStore +func (ts *Store) LastCommitID() (id types.CommitID) { + return +} + +// Implements Store. +func (ts *Store) GetStoreType() types.StoreType { + return types.StoreTypeTransient +} diff --git a/store/transient/store_test.go b/store/transient/store_test.go new file mode 100644 index 0000000000..7549a782df --- /dev/null +++ b/store/transient/store_test.go @@ -0,0 +1,35 @@ +package transient_test + +import ( + "bytes" + "testing" + + "github.com/stretchr/testify/require" + + "github.com/line/lbm-sdk/store/transient" + "github.com/line/lbm-sdk/store/types" +) + +var k, v = []byte("hello"), []byte("world") + +func TestTransientStore(t *testing.T) { + tstore := transient.NewStore() + + require.Nil(t, tstore.Get(k)) + + tstore.Set(k, v) + + require.Equal(t, v, tstore.Get(k)) + + tstore.Commit() + + require.Nil(t, tstore.Get(k)) + + // no-op + tstore.SetPruning(types.PruningOptions{}) + + emptyCommitID := tstore.LastCommitID() + require.Equal(t, emptyCommitID.Version, int64(0)) + require.True(t, bytes.Equal(emptyCommitID.Hash, nil)) + require.Equal(t, types.StoreTypeTransient, tstore.GetStoreType()) +} diff --git a/store/types/gas.go b/store/types/gas.go index d41f2cf768..fe72cc5207 100644 --- a/store/types/gas.go +++ b/store/types/gas.go @@ -89,9 +89,9 @@ func addUint64Overflow(a, b uint64) (uint64, bool) { func (g *basicGasMeter) ConsumeGas(amount Gas, descriptor string) { var overflow bool - // TODO: Should we set the consumed field after overflow checking? g.consumed, overflow = addUint64Overflow(g.consumed, amount) if overflow { + g.consumed = math.MaxUint64 panic(ErrorGasOverflow{descriptor}) } @@ -207,3 +207,16 @@ func KVGasConfig() GasConfig { IterNextCostFlat: 30, } } + +// TransientGasConfig returns a default gas config for TransientStores. +func TransientGasConfig() GasConfig { + return GasConfig{ + HasCost: 100, + DeleteCost: 100, + ReadCostFlat: 100, + ReadCostPerByte: 0, + WriteCostFlat: 200, + WriteCostPerByte: 3, + IterNextCostFlat: 3, + } +} diff --git a/store/types/gas_test.go b/store/types/gas_test.go index 61bea764bd..8a02df4cfa 100644 --- a/store/types/gas_test.go +++ b/store/types/gas_test.go @@ -96,3 +96,17 @@ func TestAddUint64Overflow(t *testing.T) { ) } } + +func TestTransientGasConfig(t *testing.T) { + t.Parallel() + config := TransientGasConfig() + require.Equal(t, config, GasConfig{ + HasCost: 100, + DeleteCost: 100, + ReadCostFlat: 100, + ReadCostPerByte: 0, + WriteCostFlat: 200, + WriteCostPerByte: 3, + IterNextCostFlat: 3, + }) +} diff --git a/store/types/iterator_test.go b/store/types/iterator_test.go index 134cbbc621..bfe44646dd 100644 --- a/store/types/iterator_test.go +++ b/store/types/iterator_test.go @@ -13,7 +13,7 @@ import ( func newMemTestKVStore(t *testing.T) types.KVStore { db := memdb.NewDB() - store, err := iavl.LoadStore(db, iavl.NewCacheManagerNoCache(), types.CommitID{}, false) + store, err := iavl.LoadStore(db, iavl.NewCacheManagerNoCache(), types.CommitID{}, false, iavl.DefaultIAVLCacheSize) require.NoError(t, err) return store } diff --git a/store/types/listening.go b/store/types/listening.go new file mode 100644 index 0000000000..afa9dce7f2 --- /dev/null +++ b/store/types/listening.go @@ -0,0 +1,47 @@ +package types + +import ( + "io" + + "github.com/line/lbm-sdk/codec" +) + +// WriteListener interface for streaming data out from a listenkv.Store +type WriteListener interface { + // if value is nil then it was deleted + // storeKey indicates the source KVStore, to facilitate using the the same WriteListener across separate KVStores + // delete bool indicates if it was a delete; true: delete, false: set + OnWrite(storeKey StoreKey, key []byte, value []byte, delete bool) error +} + +// StoreKVPairWriteListener is used to configure listening to a KVStore by writing out length-prefixed +// protobuf encoded StoreKVPairs to an underlying io.Writer +type StoreKVPairWriteListener struct { + writer io.Writer + marshaller codec.BinaryCodec +} + +// NewStoreKVPairWriteListener wraps creates a StoreKVPairWriteListener with a provdied io.Writer and codec.BinaryCodec +func NewStoreKVPairWriteListener(w io.Writer, m codec.BinaryCodec) *StoreKVPairWriteListener { + return &StoreKVPairWriteListener{ + writer: w, + marshaller: m, + } +} + +// OnWrite satisfies the WriteListener interface by writing length-prefixed protobuf encoded StoreKVPairs +func (wl *StoreKVPairWriteListener) OnWrite(storeKey StoreKey, key []byte, value []byte, delete bool) error { + kvPair := new(StoreKVPair) + kvPair.StoreKey = storeKey.Name() + kvPair.Delete = delete + kvPair.Key = key + kvPair.Value = value + by, err := wl.marshaller.MarshalLengthPrefixed(kvPair) + if err != nil { + return err + } + if _, err := wl.writer.Write(by); err != nil { + return err + } + return nil +} diff --git a/store/types/listening.pb.go b/store/types/listening.pb.go new file mode 100644 index 0000000000..90713b61b5 --- /dev/null +++ b/store/types/listening.pb.go @@ -0,0 +1,470 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: lbm/base/store/v1/listening.proto + +package types + +import ( + fmt "fmt" + proto "github.com/gogo/protobuf/proto" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +// StoreKVPair is a KVStore KVPair used for listening to state changes (Sets and Deletes) +// It optionally includes the StoreKey for the originating KVStore and a Boolean flag to distinguish between Sets and +// Deletes +// +// Since: cosmos-sdk 0.43 +type StoreKVPair struct { + StoreKey string `protobuf:"bytes,1,opt,name=store_key,json=storeKey,proto3" json:"store_key,omitempty"` + Delete bool `protobuf:"varint,2,opt,name=delete,proto3" json:"delete,omitempty"` + Key []byte `protobuf:"bytes,3,opt,name=key,proto3" json:"key,omitempty"` + Value []byte `protobuf:"bytes,4,opt,name=value,proto3" json:"value,omitempty"` +} + +func (m *StoreKVPair) Reset() { *m = StoreKVPair{} } +func (m *StoreKVPair) String() string { return proto.CompactTextString(m) } +func (*StoreKVPair) ProtoMessage() {} +func (*StoreKVPair) Descriptor() ([]byte, []int) { + return fileDescriptor_5c2371bd06252945, []int{0} +} +func (m *StoreKVPair) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *StoreKVPair) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_StoreKVPair.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *StoreKVPair) XXX_Merge(src proto.Message) { + xxx_messageInfo_StoreKVPair.Merge(m, src) +} +func (m *StoreKVPair) XXX_Size() int { + return m.Size() +} +func (m *StoreKVPair) XXX_DiscardUnknown() { + xxx_messageInfo_StoreKVPair.DiscardUnknown(m) +} + +var xxx_messageInfo_StoreKVPair proto.InternalMessageInfo + +func (m *StoreKVPair) GetStoreKey() string { + if m != nil { + return m.StoreKey + } + return "" +} + +func (m *StoreKVPair) GetDelete() bool { + if m != nil { + return m.Delete + } + return false +} + +func (m *StoreKVPair) GetKey() []byte { + if m != nil { + return m.Key + } + return nil +} + +func (m *StoreKVPair) GetValue() []byte { + if m != nil { + return m.Value + } + return nil +} + +func init() { + proto.RegisterType((*StoreKVPair)(nil), "lbm.base.store.v1.StoreKVPair") +} + +func init() { proto.RegisterFile("lbm/base/store/v1/listening.proto", fileDescriptor_5c2371bd06252945) } + +var fileDescriptor_5c2371bd06252945 = []byte{ + // 221 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x52, 0xcc, 0x49, 0xca, 0xd5, + 0x4f, 0x4a, 0x2c, 0x4e, 0xd5, 0x2f, 0x2e, 0xc9, 0x2f, 0x4a, 0xd5, 0x2f, 0x33, 0xd4, 0xcf, 0xc9, + 0x2c, 0x2e, 0x49, 0xcd, 0xcb, 0xcc, 0x4b, 0xd7, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x12, 0xcc, + 0x49, 0xca, 0xd5, 0x03, 0x29, 0xd1, 0x03, 0x2b, 0xd1, 0x2b, 0x33, 0x54, 0xca, 0xe2, 0xe2, 0x0e, + 0x06, 0xb1, 0xbd, 0xc3, 0x02, 0x12, 0x33, 0x8b, 0x84, 0xa4, 0xb9, 0x38, 0xc1, 0x52, 0xf1, 0xd9, + 0xa9, 0x95, 0x12, 0x8c, 0x0a, 0x8c, 0x1a, 0x9c, 0x41, 0x1c, 0x60, 0x01, 0xef, 0xd4, 0x4a, 0x21, + 0x31, 0x2e, 0xb6, 0x94, 0xd4, 0x9c, 0xd4, 0x92, 0x54, 0x09, 0x26, 0x05, 0x46, 0x0d, 0x8e, 0x20, + 0x28, 0x4f, 0x48, 0x80, 0x8b, 0x19, 0xa4, 0x9c, 0x59, 0x81, 0x51, 0x83, 0x27, 0x08, 0xc4, 0x14, + 0x12, 0xe1, 0x62, 0x2d, 0x4b, 0xcc, 0x29, 0x4d, 0x95, 0x60, 0x01, 0x8b, 0x41, 0x38, 0x4e, 0xb6, + 0x27, 0x1e, 0xc9, 0x31, 0x5e, 0x78, 0x24, 0xc7, 0xf8, 0xe0, 0x91, 0x1c, 0xe3, 0x84, 0xc7, 0x72, + 0x0c, 0x17, 0x1e, 0xcb, 0x31, 0xdc, 0x78, 0x2c, 0xc7, 0x10, 0xa5, 0x9c, 0x9e, 0x59, 0x92, 0x51, + 0x9a, 0xa4, 0x97, 0x9c, 0x9f, 0xab, 0x9f, 0x93, 0x99, 0x97, 0xaa, 0x9f, 0x93, 0x94, 0xab, 0x5b, + 0x9c, 0x92, 0x0d, 0xf5, 0x4a, 0x49, 0x65, 0x41, 0x6a, 0x71, 0x12, 0x1b, 0xd8, 0x13, 0xc6, 0x80, + 0x00, 0x00, 0x00, 0xff, 0xff, 0xbe, 0x87, 0x3a, 0xc8, 0xe9, 0x00, 0x00, 0x00, +} + +func (m *StoreKVPair) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *StoreKVPair) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *StoreKVPair) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Value) > 0 { + i -= len(m.Value) + copy(dAtA[i:], m.Value) + i = encodeVarintListening(dAtA, i, uint64(len(m.Value))) + i-- + dAtA[i] = 0x22 + } + if len(m.Key) > 0 { + i -= len(m.Key) + copy(dAtA[i:], m.Key) + i = encodeVarintListening(dAtA, i, uint64(len(m.Key))) + i-- + dAtA[i] = 0x1a + } + if m.Delete { + i-- + if m.Delete { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x10 + } + if len(m.StoreKey) > 0 { + i -= len(m.StoreKey) + copy(dAtA[i:], m.StoreKey) + i = encodeVarintListening(dAtA, i, uint64(len(m.StoreKey))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func encodeVarintListening(dAtA []byte, offset int, v uint64) int { + offset -= sovListening(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *StoreKVPair) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.StoreKey) + if l > 0 { + n += 1 + l + sovListening(uint64(l)) + } + if m.Delete { + n += 2 + } + l = len(m.Key) + if l > 0 { + n += 1 + l + sovListening(uint64(l)) + } + l = len(m.Value) + if l > 0 { + n += 1 + l + sovListening(uint64(l)) + } + return n +} + +func sovListening(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozListening(x uint64) (n int) { + return sovListening(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *StoreKVPair) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowListening + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: StoreKVPair: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: StoreKVPair: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field StoreKey", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowListening + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthListening + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthListening + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.StoreKey = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Delete", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowListening + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.Delete = bool(v != 0) + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Key", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowListening + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthListening + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthListening + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Key = append(m.Key[:0], dAtA[iNdEx:postIndex]...) + if m.Key == nil { + m.Key = []byte{} + } + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Value", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowListening + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthListening + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthListening + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Value = append(m.Value[:0], dAtA[iNdEx:postIndex]...) + if m.Value == nil { + m.Value = []byte{} + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipListening(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthListening + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipListening(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowListening + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowListening + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowListening + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthListening + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupListening + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthListening + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthListening = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowListening = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupListening = fmt.Errorf("proto: unexpected end of group") +) diff --git a/store/types/listening_test.go b/store/types/listening_test.go new file mode 100644 index 0000000000..bcaffb08b3 --- /dev/null +++ b/store/types/listening_test.go @@ -0,0 +1,66 @@ +package types + +import ( + "bytes" + "testing" + + "github.com/stretchr/testify/require" + + "github.com/line/lbm-sdk/codec" + "github.com/line/lbm-sdk/codec/types" +) + +func TestNewStoreKVPairWriteListener(t *testing.T) { + testWriter := new(bytes.Buffer) + interfaceRegistry := types.NewInterfaceRegistry() + testMarshaller := codec.NewProtoCodec(interfaceRegistry) + + wl := NewStoreKVPairWriteListener(testWriter, testMarshaller) + + require.IsType(t, &StoreKVPairWriteListener{}, wl) + require.Equal(t, testWriter, wl.writer) + require.Equal(t, testMarshaller, wl.marshaller) +} + +func TestOnWrite(t *testing.T) { + testWriter := new(bytes.Buffer) + interfaceRegistry := types.NewInterfaceRegistry() + testMarshaller := codec.NewProtoCodec(interfaceRegistry) + + wl := NewStoreKVPairWriteListener(testWriter, testMarshaller) + + testStoreKey := NewKVStoreKey("test_key") + testKey := []byte("testing123") + testValue := []byte("testing321") + + // test set + err := wl.OnWrite(testStoreKey, testKey, testValue, false) + require.Nil(t, err) + + outputBytes := testWriter.Bytes() + outputKVPair := new(StoreKVPair) + expectedOutputKVPair := &StoreKVPair{ + Key: testKey, + Value: testValue, + StoreKey: testStoreKey.Name(), + Delete: false, + } + testMarshaller.UnmarshalLengthPrefixed(outputBytes, outputKVPair) + require.EqualValues(t, expectedOutputKVPair, outputKVPair) + testWriter.Reset() + + // test delete + err = wl.OnWrite(testStoreKey, testKey, testValue, true) + require.Nil(t, err) + + outputBytes = testWriter.Bytes() + outputKVPair = new(StoreKVPair) + expectedOutputKVPair = &StoreKVPair{ + Key: testKey, + Value: testValue, + StoreKey: testStoreKey.Name(), + Delete: true, + } + testMarshaller.UnmarshalLengthPrefixed(outputBytes, outputKVPair) + require.EqualValues(t, expectedOutputKVPair, outputKVPair) +} diff --git a/store/types/pruning.go b/store/types/pruning.go index 823da76c65..4419acb950 100644 --- a/store/types/pruning.go +++ b/store/types/pruning.go @@ -11,10 +11,12 @@ const ( ) var ( - // PruneDefault defines a pruning strategy where the last 100 heights are kept - // in addition to every 100th and where to-be pruned heights are pruned at - // every 10th height. - PruneDefault = NewPruningOptions(100, 100, 10) + // PruneDefault defines a pruning strategy where the last 362880 heights are + // kept in addition to every 100th and where to-be pruned heights are pruned + // at every 10th height. The last 362880 heights are kept assuming the typical + // block time is 5s and typical unbonding period is 21 days. If these values + // do not match the applications' requirements, use the "custom" option. + PruneDefault = NewPruningOptions(362880, 100, 10) // PruneEverything defines a pruning strategy where all committed heights are // deleted, storing only the current height and where to-be pruned heights are diff --git a/store/types/store.go b/store/types/store.go index 336ed6001b..fe2a476ec1 100644 --- a/store/types/store.go +++ b/store/types/store.go @@ -142,6 +142,13 @@ type MultiStore interface { // implied that the caller should update the context when necessary between // tracing operations. The modified MultiStore is returned. SetTracingContext(TraceContext) MultiStore + + // ListeningEnabled returns if listening is enabled for the KVStore belonging the provided StoreKey + ListeningEnabled(key StoreKey) bool + + // AddListeners adds WriteListeners for the KVStore belonging to the provided StoreKey + // It appends the listeners to a current set, if one already exists + AddListeners(key StoreKey, listeners []WriteListener) } // From MultiStore.CacheMultiStore().... @@ -197,6 +204,9 @@ type CommitMultiStore interface { // SetIAVLCacheManager sets the CacheManager that is holding nodedb cache of IAVL tree // If a cacheManager is not set, then IAVL tree does not use cache SetIAVLCacheManager(cacheManager CacheManager) + + // SetIAVLCacheSize sets the cache size of the IAVL tree. + SetIAVLCacheSize(size int) } //---------subsp------------------------------- @@ -272,6 +282,9 @@ type CacheWrap interface { // CacheWrapWithTrace recursively wraps again with tracing enabled. CacheWrapWithTrace(w io.Writer, tc TraceContext) CacheWrap + + // CacheWrapWithListeners recursively wraps again with listening enabled + CacheWrapWithListeners(storeKey StoreKey, listeners []WriteListener) CacheWrap } type CacheWrapper interface { @@ -280,6 +293,9 @@ type CacheWrapper interface { // CacheWrapWithTrace branches a store with tracing enabled. CacheWrapWithTrace(w io.Writer, tc TraceContext) CacheWrap + + // CacheWrapWithListeners recursively wraps again with listening enabled + CacheWrapWithListeners(storeKey StoreKey, listeners []WriteListener) CacheWrap } func (cid CommitID) IsZero() bool { @@ -300,6 +316,7 @@ const ( StoreTypeMulti StoreType = iota StoreTypeDB StoreTypeIAVL + StoreTypeTransient StoreTypeMemory ) @@ -314,6 +331,9 @@ func (st StoreType) String() string { case StoreTypeIAVL: return "StoreTypeIAVL" + case StoreTypeTransient: + return "StoreTypeTransient" + case StoreTypeMemory: return "StoreTypeMemory" } @@ -359,6 +379,29 @@ func (key *KVStoreKey) String() string { return fmt.Sprintf("KVStoreKey{%p, %s}", key, key.name) } +// TransientStoreKey is used for indexing transient stores in a MultiStore +type TransientStoreKey struct { + name string +} + +// Constructs new TransientStoreKey +// Must return a pointer according to the ocap principle +func NewTransientStoreKey(name string) *TransientStoreKey { + return &TransientStoreKey{ + name: name, + } +} + +// Implements StoreKey +func (key *TransientStoreKey) Name() string { + return key.name +} + +// Implements StoreKey +func (key *TransientStoreKey) String() string { + return fmt.Sprintf("TransientStoreKey{%p, %s}", key, key.name) +} + // MemoryStoreKey defines a typed key to be used with an in-memory KVStore. type MemoryStoreKey struct { name string diff --git a/telemetry/metrics.go b/telemetry/metrics.go index ca9bf78908..53235e012b 100644 --- a/telemetry/metrics.go +++ b/telemetry/metrics.go @@ -64,11 +64,13 @@ type Metrics struct { prometheusEnabled bool } +// GatherResponse is the response type of registered metrics type GatherResponse struct { Metrics []byte ContentType string } +// New creates a new instance of Metrics func New(cfg Config) (*Metrics, error) { if !cfg.Enabled { return nil, nil diff --git a/telemetry/wrapper.go b/telemetry/wrapper.go index 62f50eeacb..24722a7d63 100644 --- a/telemetry/wrapper.go +++ b/telemetry/wrapper.go @@ -13,6 +13,7 @@ const ( MetricLabelNameModule = "module" ) +// NewLabel creates a new instance of Label with name and value func NewLabel(name, value string) metrics.Label { return metrics.Label{Name: name, Value: value} } diff --git a/tests/mocks/account_retriever.go b/tests/mocks/account_retriever.go index 855ea5f930..895f1bc64b 100644 --- a/tests/mocks/account_retriever.go +++ b/tests/mocks/account_retriever.go @@ -5,37 +5,53 @@ package mocks import ( - gomock "github.com/golang/mock/gomock" + "reflect" + + "github.com/golang/mock/gomock" + client "github.com/line/lbm-sdk/client" types "github.com/line/lbm-sdk/crypto/types" types0 "github.com/line/lbm-sdk/types" - reflect "reflect" ) -// MockAccount is a mock of Account interface +// MockAccount is a mock of Account interface. type MockAccount struct { ctrl *gomock.Controller recorder *MockAccountMockRecorder } -// MockAccountMockRecorder is the mock recorder for MockAccount +// MockAccountMockRecorder is the mock recorder for MockAccount. type MockAccountMockRecorder struct { mock *MockAccount } -// NewMockAccount creates a new mock instance +// NewMockAccount creates a new mock instance. func NewMockAccount(ctrl *gomock.Controller) *MockAccount { mock := &MockAccount{ctrl: ctrl} mock.recorder = &MockAccountMockRecorder{mock} return mock } -// EXPECT returns an object that allows the caller to indicate expected use +// EXPECT returns an object that allows the caller to indicate expected use. func (m *MockAccount) EXPECT() *MockAccountMockRecorder { return m.recorder } -// GetAddress mocks base method +// GetAccountNumber mocks base method. +func (m *MockAccount) GetAccountNumber() uint64 { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetAccountNumber") + ret0, _ := ret[0].(uint64) + return ret0 +} + +// GetAccountNumber indicates an expected call of GetAccountNumber. +func (mr *MockAccountMockRecorder) GetAccountNumber() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAccountNumber", reflect.TypeOf((*MockAccount)(nil).GetAccountNumber)) +} + +// GetAddress mocks base method. func (m *MockAccount) GetAddress() types0.AccAddress { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "GetAddress") @@ -43,13 +59,13 @@ func (m *MockAccount) GetAddress() types0.AccAddress { return ret0 } -// GetAddress indicates an expected call of GetAddress +// GetAddress indicates an expected call of GetAddress. func (mr *MockAccountMockRecorder) GetAddress() *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAddress", reflect.TypeOf((*MockAccount)(nil).GetAddress)) } -// GetPubKey mocks base method +// GetPubKey mocks base method. func (m *MockAccount) GetPubKey() types.PubKey { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "GetPubKey") @@ -57,27 +73,13 @@ func (m *MockAccount) GetPubKey() types.PubKey { return ret0 } -// GetPubKey indicates an expected call of GetPubKey +// GetPubKey indicates an expected call of GetPubKey. func (mr *MockAccountMockRecorder) GetPubKey() *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetPubKey", reflect.TypeOf((*MockAccount)(nil).GetPubKey)) } -// GetAccountNumber mocks base method -func (m *MockAccount) GetAccountNumber() uint64 { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetAccountNumber") - ret0, _ := ret[0].(uint64) - return ret0 -} - -// GetAccountNumber indicates an expected call of GetAccountNumber -func (mr *MockAccountMockRecorder) GetAccountNumber() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAccountNumber", reflect.TypeOf((*MockAccount)(nil).GetAccountNumber)) -} - -// GetSequence mocks base method +// GetSequence mocks base method. func (m *MockAccount) GetSequence() uint64 { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "GetSequence") @@ -85,36 +87,50 @@ func (m *MockAccount) GetSequence() uint64 { return ret0 } -// GetSequence indicates an expected call of GetSequence +// GetSequence indicates an expected call of GetSequence. func (mr *MockAccountMockRecorder) GetSequence() *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetSequence", reflect.TypeOf((*MockAccount)(nil).GetSequence)) } -// MockAccountRetriever is a mock of AccountRetriever interface +// MockAccountRetriever is a mock of AccountRetriever interface. type MockAccountRetriever struct { ctrl *gomock.Controller recorder *MockAccountRetrieverMockRecorder } -// MockAccountRetrieverMockRecorder is the mock recorder for MockAccountRetriever +// MockAccountRetrieverMockRecorder is the mock recorder for MockAccountRetriever. type MockAccountRetrieverMockRecorder struct { mock *MockAccountRetriever } -// NewMockAccountRetriever creates a new mock instance +// NewMockAccountRetriever creates a new mock instance. func NewMockAccountRetriever(ctrl *gomock.Controller) *MockAccountRetriever { mock := &MockAccountRetriever{ctrl: ctrl} mock.recorder = &MockAccountRetrieverMockRecorder{mock} return mock } -// EXPECT returns an object that allows the caller to indicate expected use +// EXPECT returns an object that allows the caller to indicate expected use. func (m *MockAccountRetriever) EXPECT() *MockAccountRetrieverMockRecorder { return m.recorder } -// GetAccount mocks base method +// EnsureExists mocks base method. +func (m *MockAccountRetriever) EnsureExists(clientCtx client.Context, addr types0.AccAddress) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "EnsureExists", clientCtx, addr) + ret0, _ := ret[0].(error) + return ret0 +} + +// EnsureExists indicates an expected call of EnsureExists. +func (mr *MockAccountRetrieverMockRecorder) EnsureExists(clientCtx, addr interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EnsureExists", reflect.TypeOf((*MockAccountRetriever)(nil).EnsureExists), clientCtx, addr) +} + +// GetAccount mocks base method. func (m *MockAccountRetriever) GetAccount(clientCtx client.Context, addr types0.AccAddress) (client.Account, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "GetAccount", clientCtx, addr) @@ -123,54 +139,40 @@ func (m *MockAccountRetriever) GetAccount(clientCtx client.Context, addr types0. return ret0, ret1 } -// GetAccount indicates an expected call of GetAccount +// GetAccount indicates an expected call of GetAccount. func (mr *MockAccountRetrieverMockRecorder) GetAccount(clientCtx, addr interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAccount", reflect.TypeOf((*MockAccountRetriever)(nil).GetAccount), clientCtx, addr) } -// GetAccountWithHeight mocks base method -func (m *MockAccountRetriever) GetAccountWithHeight(clientCtx client.Context, addr types0.AccAddress) (client.Account, int64, error) { +// GetAccountNumberSequence mocks base method. +func (m *MockAccountRetriever) GetAccountNumberSequence(clientCtx client.Context, addr types0.AccAddress) (uint64, uint64, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetAccountWithHeight", clientCtx, addr) - ret0, _ := ret[0].(client.Account) - ret1, _ := ret[1].(int64) + ret := m.ctrl.Call(m, "GetAccountNumberSequence", clientCtx, addr) + ret0, _ := ret[0].(uint64) + ret1, _ := ret[1].(uint64) ret2, _ := ret[2].(error) return ret0, ret1, ret2 } -// GetAccountWithHeight indicates an expected call of GetAccountWithHeight -func (mr *MockAccountRetrieverMockRecorder) GetAccountWithHeight(clientCtx, addr interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAccountWithHeight", reflect.TypeOf((*MockAccountRetriever)(nil).GetAccountWithHeight), clientCtx, addr) -} - -// EnsureExists mocks base method -func (m *MockAccountRetriever) EnsureExists(clientCtx client.Context, addr types0.AccAddress) error { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "EnsureExists", clientCtx, addr) - ret0, _ := ret[0].(error) - return ret0 -} - -// EnsureExists indicates an expected call of EnsureExists -func (mr *MockAccountRetrieverMockRecorder) EnsureExists(clientCtx, addr interface{}) *gomock.Call { +// GetAccountNumberSequence indicates an expected call of GetAccountNumberSequence. +func (mr *MockAccountRetrieverMockRecorder) GetAccountNumberSequence(clientCtx, addr interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EnsureExists", reflect.TypeOf((*MockAccountRetriever)(nil).EnsureExists), clientCtx, addr) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAccountNumberSequence", reflect.TypeOf((*MockAccountRetriever)(nil).GetAccountNumberSequence), clientCtx, addr) } -// GetAccountNumberSequence mocks base method -func (m *MockAccountRetriever) GetAccountNumberSequence(clientCtx client.Context, addr types0.AccAddress) (uint64, uint64, error) { +// GetAccountWithHeight mocks base method. +func (m *MockAccountRetriever) GetAccountWithHeight(clientCtx client.Context, addr types0.AccAddress) (client.Account, int64, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetAccountNumberSequence", clientCtx, addr) - ret0, _ := ret[0].(uint64) - ret1, _ := ret[1].(uint64) + ret := m.ctrl.Call(m, "GetAccountWithHeight", clientCtx, addr) + ret0, _ := ret[0].(client.Account) + ret1, _ := ret[1].(int64) ret2, _ := ret[2].(error) return ret0, ret1, ret2 } -// GetAccountNumberSequence indicates an expected call of GetAccountNumberSequence -func (mr *MockAccountRetrieverMockRecorder) GetAccountNumberSequence(clientCtx, addr interface{}) *gomock.Call { +// GetAccountWithHeight indicates an expected call of GetAccountWithHeight. +func (mr *MockAccountRetrieverMockRecorder) GetAccountWithHeight(clientCtx, addr interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAccountNumberSequence", reflect.TypeOf((*MockAccountRetriever)(nil).GetAccountNumberSequence), clientCtx, addr) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAccountWithHeight", reflect.TypeOf((*MockAccountRetriever)(nil).GetAccountWithHeight), clientCtx, addr) } diff --git a/tests/mocks/grpc_server.go b/tests/mocks/grpc_server.go index 91fedb7ae5..df4372c4bc 100644 --- a/tests/mocks/grpc_server.go +++ b/tests/mocks/grpc_server.go @@ -5,41 +5,42 @@ package mocks import ( + reflect "reflect" + gomock "github.com/golang/mock/gomock" grpc "google.golang.org/grpc" - reflect "reflect" ) -// MockServer is a mock of Server interface +// MockServer is a mock of Server interface. type MockServer struct { ctrl *gomock.Controller recorder *MockServerMockRecorder } -// MockServerMockRecorder is the mock recorder for MockServer +// MockServerMockRecorder is the mock recorder for MockServer. type MockServerMockRecorder struct { mock *MockServer } -// NewMockServer creates a new mock instance +// NewMockServer creates a new mock instance. func NewMockServer(ctrl *gomock.Controller) *MockServer { mock := &MockServer{ctrl: ctrl} mock.recorder = &MockServerMockRecorder{mock} return mock } -// EXPECT returns an object that allows the caller to indicate expected use +// EXPECT returns an object that allows the caller to indicate expected use. func (m *MockServer) EXPECT() *MockServerMockRecorder { return m.recorder } -// RegisterService mocks base method +// RegisterService mocks base method. func (m *MockServer) RegisterService(arg0 *grpc.ServiceDesc, arg1 interface{}) { m.ctrl.T.Helper() m.ctrl.Call(m, "RegisterService", arg0, arg1) } -// RegisterService indicates an expected call of RegisterService +// RegisterService indicates an expected call of RegisterService. func (mr *MockServerMockRecorder) RegisterService(arg0, arg1 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RegisterService", reflect.TypeOf((*MockServer)(nil).RegisterService), arg0, arg1) diff --git a/tests/mocks/tendermint_tendermint_libs_log_DB.go b/tests/mocks/tendermint_tendermint_libs_log_DB.go index 19fb828224..6d69152538 100644 --- a/tests/mocks/tendermint_tendermint_libs_log_DB.go +++ b/tests/mocks/tendermint_tendermint_libs_log_DB.go @@ -5,35 +5,36 @@ package mocks import ( + "reflect" + gomock "github.com/golang/mock/gomock" log "github.com/line/ostracon/libs/log" - reflect "reflect" ) -// MockLogger is a mock of Logger interface +// MockLogger is a mock of Logger interface. type MockLogger struct { ctrl *gomock.Controller recorder *MockLoggerMockRecorder } -// MockLoggerMockRecorder is the mock recorder for MockLogger +// MockLoggerMockRecorder is the mock recorder for MockLogger. type MockLoggerMockRecorder struct { mock *MockLogger } -// NewMockLogger creates a new mock instance +// NewMockLogger creates a new mock instance. func NewMockLogger(ctrl *gomock.Controller) *MockLogger { mock := &MockLogger{ctrl: ctrl} mock.recorder = &MockLoggerMockRecorder{mock} return mock } -// EXPECT returns an object that allows the caller to indicate expected use +// EXPECT returns an object that allows the caller to indicate expected use. func (m *MockLogger) EXPECT() *MockLoggerMockRecorder { return m.recorder } -// Debug mocks base method +// Debug mocks base method. func (m *MockLogger) Debug(arg0 string, arg1 ...interface{}) { m.ctrl.T.Helper() varargs := []interface{}{arg0} @@ -43,14 +44,14 @@ func (m *MockLogger) Debug(arg0 string, arg1 ...interface{}) { m.ctrl.Call(m, "Debug", varargs...) } -// Debug indicates an expected call of Debug +// Debug indicates an expected call of Debug. func (mr *MockLoggerMockRecorder) Debug(arg0 interface{}, arg1 ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() varargs := append([]interface{}{arg0}, arg1...) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Debug", reflect.TypeOf((*MockLogger)(nil).Debug), varargs...) } -// Error mocks base method +// Error mocks base method. func (m *MockLogger) Error(arg0 string, arg1 ...interface{}) { m.ctrl.T.Helper() varargs := []interface{}{arg0} @@ -60,14 +61,14 @@ func (m *MockLogger) Error(arg0 string, arg1 ...interface{}) { m.ctrl.Call(m, "Error", varargs...) } -// Error indicates an expected call of Error +// Error indicates an expected call of Error. func (mr *MockLoggerMockRecorder) Error(arg0 interface{}, arg1 ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() varargs := append([]interface{}{arg0}, arg1...) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Error", reflect.TypeOf((*MockLogger)(nil).Error), varargs...) } -// Info mocks base method +// Info mocks base method. func (m *MockLogger) Info(arg0 string, arg1 ...interface{}) { m.ctrl.T.Helper() varargs := []interface{}{arg0} @@ -77,14 +78,14 @@ func (m *MockLogger) Info(arg0 string, arg1 ...interface{}) { m.ctrl.Call(m, "Info", varargs...) } -// Info indicates an expected call of Info +// Info indicates an expected call of Info. func (mr *MockLoggerMockRecorder) Info(arg0 interface{}, arg1 ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() varargs := append([]interface{}{arg0}, arg1...) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Info", reflect.TypeOf((*MockLogger)(nil).Info), varargs...) } -// With mocks base method +// With mocks base method. func (m *MockLogger) With(arg0 ...interface{}) log.Logger { m.ctrl.T.Helper() varargs := []interface{}{} @@ -96,7 +97,7 @@ func (m *MockLogger) With(arg0 ...interface{}) log.Logger { return ret0 } -// With indicates an expected call of With +// With indicates an expected call of With. func (mr *MockLoggerMockRecorder) With(arg0 ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "With", reflect.TypeOf((*MockLogger)(nil).With), arg0...) diff --git a/tests/mocks/tendermint_tm_db_DB.go b/tests/mocks/tendermint_tm_db_DB.go index 442c4bb68a..815bdbaf0a 100644 --- a/tests/mocks/tendermint_tm_db_DB.go +++ b/tests/mocks/tendermint_tm_db_DB.go @@ -5,23 +5,24 @@ package mocks import ( + "reflect" + gomock "github.com/golang/mock/gomock" db "github.com/line/tm-db/v2" - reflect "reflect" ) -// MockDB is a mock of DB interface +// MockDB is a mock of DB interface. type MockDB struct { ctrl *gomock.Controller recorder *MockDBMockRecorder } -// MockDBMockRecorder is the mock recorder for MockDB +// MockDBMockRecorder is the mock recorder for MockDB. type MockDBMockRecorder struct { mock *MockDB } -// NewMockDB creates a new mock instance +// NewMockDB creates a new mock instance. func NewMockDB(ctrl *gomock.Controller) *MockDB { mock := &MockDB{ctrl: ctrl} mock.recorder = &MockDBMockRecorder{mock} @@ -37,7 +38,7 @@ func (m *MockDB) EXPECT() *MockDBMockRecorder { return m.recorder } -// Close mocks base method +// Close mocks base method. func (m *MockDB) Close() error { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "Close") @@ -45,13 +46,13 @@ func (m *MockDB) Close() error { return ret0 } -// Close indicates an expected call of Close +// Close indicates an expected call of Close. func (mr *MockDBMockRecorder) Close() *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Close", reflect.TypeOf((*MockDB)(nil).Close)) } -// Delete mocks base method +// Delete mocks base method. func (m *MockDB) Delete(arg0 []byte) error { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "Delete", arg0) @@ -59,13 +60,13 @@ func (m *MockDB) Delete(arg0 []byte) error { return ret0 } -// Delete indicates an expected call of Delete +// Delete indicates an expected call of Delete. func (mr *MockDBMockRecorder) Delete(arg0 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Delete", reflect.TypeOf((*MockDB)(nil).Delete), arg0) } -// DeleteSync mocks base method +// DeleteSync mocks base method. func (m *MockDB) DeleteSync(arg0 []byte) error { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "DeleteSync", arg0) @@ -73,13 +74,13 @@ func (m *MockDB) DeleteSync(arg0 []byte) error { return ret0 } -// DeleteSync indicates an expected call of DeleteSync +// DeleteSync indicates an expected call of DeleteSync. func (mr *MockDBMockRecorder) DeleteSync(arg0 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteSync", reflect.TypeOf((*MockDB)(nil).DeleteSync), arg0) } -// Get mocks base method +// Get mocks base method. func (m *MockDB) Get(arg0 []byte) ([]byte, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "Get", arg0) @@ -88,13 +89,13 @@ func (m *MockDB) Get(arg0 []byte) ([]byte, error) { return ret0, ret1 } -// Get indicates an expected call of Get +// Get indicates an expected call of Get. func (mr *MockDBMockRecorder) Get(arg0 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Get", reflect.TypeOf((*MockDB)(nil).Get), arg0) } -// Has mocks base method +// Has mocks base method. func (m *MockDB) Has(arg0 []byte) (bool, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "Has", arg0) @@ -103,13 +104,13 @@ func (m *MockDB) Has(arg0 []byte) (bool, error) { return ret0, ret1 } -// Has indicates an expected call of Has +// Has indicates an expected call of Has. func (mr *MockDBMockRecorder) Has(arg0 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Has", reflect.TypeOf((*MockDB)(nil).Has), arg0) } -// Iterator mocks base method +// Iterator mocks base method. func (m *MockDB) Iterator(arg0, arg1 []byte) (db.Iterator, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "Iterator", arg0, arg1) @@ -118,13 +119,13 @@ func (m *MockDB) Iterator(arg0, arg1 []byte) (db.Iterator, error) { return ret0, ret1 } -// Iterator indicates an expected call of Iterator +// Iterator indicates an expected call of Iterator. func (mr *MockDBMockRecorder) Iterator(arg0, arg1 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Iterator", reflect.TypeOf((*MockDB)(nil).Iterator), arg0, arg1) } -// NewBatch mocks base method +// NewBatch mocks base method. func (m *MockDB) NewBatch() db.Batch { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "NewBatch") @@ -132,7 +133,7 @@ func (m *MockDB) NewBatch() db.Batch { return ret0 } -// NewBatch indicates an expected call of NewBatch +// NewBatch indicates an expected call of NewBatch. func (mr *MockDBMockRecorder) NewBatch() *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NewBatch", reflect.TypeOf((*MockDB)(nil).NewBatch)) @@ -161,13 +162,13 @@ func (m *MockDB) Print() error { return ret0 } -// Print indicates an expected call of Print +// Print indicates an expected call of Print. func (mr *MockDBMockRecorder) Print() *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Print", reflect.TypeOf((*MockDB)(nil).Print)) } -// ReverseIterator mocks base method +// ReverseIterator mocks base method. func (m *MockDB) ReverseIterator(arg0, arg1 []byte) (db.Iterator, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "ReverseIterator", arg0, arg1) @@ -176,7 +177,7 @@ func (m *MockDB) ReverseIterator(arg0, arg1 []byte) (db.Iterator, error) { return ret0, ret1 } -// ReverseIterator indicates an expected call of ReverseIterator +// ReverseIterator indicates an expected call of ReverseIterator. func (mr *MockDBMockRecorder) ReverseIterator(arg0, arg1 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ReverseIterator", reflect.TypeOf((*MockDB)(nil).ReverseIterator), arg0, arg1) @@ -205,13 +206,13 @@ func (m *MockDB) Set(arg0, arg1 []byte) error { return ret0 } -// Set indicates an expected call of Set +// Set indicates an expected call of Set. func (mr *MockDBMockRecorder) Set(arg0, arg1 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Set", reflect.TypeOf((*MockDB)(nil).Set), arg0, arg1) } -// SetSync mocks base method +// SetSync mocks base method. func (m *MockDB) SetSync(arg0, arg1 []byte) error { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "SetSync", arg0, arg1) @@ -219,13 +220,13 @@ func (m *MockDB) SetSync(arg0, arg1 []byte) error { return ret0 } -// SetSync indicates an expected call of SetSync +// SetSync indicates an expected call of SetSync. func (mr *MockDBMockRecorder) SetSync(arg0, arg1 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetSync", reflect.TypeOf((*MockDB)(nil).SetSync), arg0, arg1) } -// Stats mocks base method +// Stats mocks base method. func (m *MockDB) Stats() map[string]string { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "Stats") @@ -233,7 +234,7 @@ func (m *MockDB) Stats() map[string]string { return ret0 } -// Stats indicates an expected call of Stats +// Stats indicates an expected call of Stats. func (mr *MockDBMockRecorder) Stats() *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Stats", reflect.TypeOf((*MockDB)(nil).Stats)) diff --git a/tests/mocks/types_handler.go b/tests/mocks/types_handler.go index 3f5ff0c75d..6e37d1ed9b 100644 --- a/tests/mocks/types_handler.go +++ b/tests/mocks/types_handler.go @@ -1,48 +1,50 @@ -// Code generated by MockGen. DO NOT EDIT. +// Code generated by MockGen. // Source: types/handler.go +// Chanes: +// + AnteHandler(...): calling `next` at the end of the function to run all anthe handler chain. // Package mocks is a generated GoMock package. package mocks import ( + "reflect" + gomock "github.com/golang/mock/gomock" types "github.com/line/lbm-sdk/types" - reflect "reflect" ) -// MockAnteDecorator is a mock of AnteDecorator interface +// MockAnteDecorator is a mock of AnteDecorator interface. type MockAnteDecorator struct { ctrl *gomock.Controller recorder *MockAnteDecoratorMockRecorder } -// MockAnteDecoratorMockRecorder is the mock recorder for MockAnteDecorator +// MockAnteDecoratorMockRecorder is the mock recorder for MockAnteDecorator. type MockAnteDecoratorMockRecorder struct { mock *MockAnteDecorator } -// NewMockAnteDecorator creates a new mock instance +// NewMockAnteDecorator creates a new mock instance. func NewMockAnteDecorator(ctrl *gomock.Controller) *MockAnteDecorator { mock := &MockAnteDecorator{ctrl: ctrl} mock.recorder = &MockAnteDecoratorMockRecorder{mock} return mock } -// EXPECT returns an object that allows the caller to indicate expected use +// EXPECT returns an object that allows the caller to indicate expected use. func (m *MockAnteDecorator) EXPECT() *MockAnteDecoratorMockRecorder { return m.recorder } -// AnteHandle mocks base method +// AnteHandle mocks base method. func (m *MockAnteDecorator) AnteHandle(ctx types.Context, tx types.Tx, simulate bool, next types.AnteHandler) (types.Context, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "AnteHandle", ctx, tx, simulate, next) - ret0, _ := ret[0].(types.Context) - ret1, _ := ret[1].(error) - return ret0, ret1 + m.ctrl.Call(m, "AnteHandle", ctx, tx, simulate, next) + // NOTE: we need to edit a generated code to call the "next handler" + return next(ctx, tx, simulate) } -// AnteHandle indicates an expected call of AnteHandle +// AnteHandle indicates an expected call of AnteHandle. func (mr *MockAnteDecoratorMockRecorder) AnteHandle(ctx, tx, simulate, next interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AnteHandle", reflect.TypeOf((*MockAnteDecorator)(nil).AnteHandle), ctx, tx, simulate, next) diff --git a/tests/mocks/types_invariant.go b/tests/mocks/types_invariant.go index f7f255f572..1d2a6d36dd 100644 --- a/tests/mocks/types_invariant.go +++ b/tests/mocks/types_invariant.go @@ -5,41 +5,42 @@ package mocks import ( + "reflect" + gomock "github.com/golang/mock/gomock" types "github.com/line/lbm-sdk/types" - reflect "reflect" ) -// MockInvariantRegistry is a mock of InvariantRegistry interface +// MockInvariantRegistry is a mock of InvariantRegistry interface. type MockInvariantRegistry struct { ctrl *gomock.Controller recorder *MockInvariantRegistryMockRecorder } -// MockInvariantRegistryMockRecorder is the mock recorder for MockInvariantRegistry +// MockInvariantRegistryMockRecorder is the mock recorder for MockInvariantRegistry. type MockInvariantRegistryMockRecorder struct { mock *MockInvariantRegistry } -// NewMockInvariantRegistry creates a new mock instance +// NewMockInvariantRegistry creates a new mock instance. func NewMockInvariantRegistry(ctrl *gomock.Controller) *MockInvariantRegistry { mock := &MockInvariantRegistry{ctrl: ctrl} mock.recorder = &MockInvariantRegistryMockRecorder{mock} return mock } -// EXPECT returns an object that allows the caller to indicate expected use +// EXPECT returns an object that allows the caller to indicate expected use. func (m *MockInvariantRegistry) EXPECT() *MockInvariantRegistryMockRecorder { return m.recorder } -// RegisterRoute mocks base method +// RegisterRoute mocks base method. func (m *MockInvariantRegistry) RegisterRoute(moduleName, route string, invar types.Invariant) { m.ctrl.T.Helper() m.ctrl.Call(m, "RegisterRoute", moduleName, route, invar) } -// RegisterRoute indicates an expected call of RegisterRoute +// RegisterRoute indicates an expected call of RegisterRoute. func (mr *MockInvariantRegistryMockRecorder) RegisterRoute(moduleName, route, invar interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RegisterRoute", reflect.TypeOf((*MockInvariantRegistry)(nil).RegisterRoute), moduleName, route, invar) diff --git a/tests/mocks/types_module_module.go b/tests/mocks/types_module_module.go index ffdcee0c2d..a118cd1f2b 100644 --- a/tests/mocks/types_module_module.go +++ b/tests/mocks/types_module_module.go @@ -9,454 +9,433 @@ import ( gomock "github.com/golang/mock/gomock" mux "github.com/gorilla/mux" runtime "github.com/grpc-ecosystem/grpc-gateway/runtime" + reflect "reflect" + cobra "github.com/spf13/cobra" + client "github.com/line/lbm-sdk/client" codec "github.com/line/lbm-sdk/codec" types "github.com/line/lbm-sdk/codec/types" types0 "github.com/line/lbm-sdk/types" module "github.com/line/lbm-sdk/types/module" types1 "github.com/line/ostracon/abci/types" - cobra "github.com/spf13/cobra" - reflect "reflect" ) -// MockAppModuleBasic is a mock of AppModuleBasic interface +// MockAppModuleBasic is a mock of AppModuleBasic interface. type MockAppModuleBasic struct { ctrl *gomock.Controller recorder *MockAppModuleBasicMockRecorder } -// MockAppModuleBasicMockRecorder is the mock recorder for MockAppModuleBasic +// MockAppModuleBasicMockRecorder is the mock recorder for MockAppModuleBasic. type MockAppModuleBasicMockRecorder struct { mock *MockAppModuleBasic } -// NewMockAppModuleBasic creates a new mock instance +// NewMockAppModuleBasic creates a new mock instance. func NewMockAppModuleBasic(ctrl *gomock.Controller) *MockAppModuleBasic { mock := &MockAppModuleBasic{ctrl: ctrl} mock.recorder = &MockAppModuleBasicMockRecorder{mock} return mock } -// EXPECT returns an object that allows the caller to indicate expected use +// EXPECT returns an object that allows the caller to indicate expected use. func (m *MockAppModuleBasic) EXPECT() *MockAppModuleBasicMockRecorder { return m.recorder } -// Name mocks base method -func (m *MockAppModuleBasic) Name() string { +// DefaultGenesis mocks base method. +func (m *MockAppModuleBasic) DefaultGenesis(arg0 codec.JSONCodec) json.RawMessage { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Name") - ret0, _ := ret[0].(string) + ret := m.ctrl.Call(m, "DefaultGenesis", arg0) + ret0, _ := ret[0].(json.RawMessage) return ret0 } -// Name indicates an expected call of Name -func (mr *MockAppModuleBasicMockRecorder) Name() *gomock.Call { +// DefaultGenesis indicates an expected call of DefaultGenesis. +func (mr *MockAppModuleBasicMockRecorder) DefaultGenesis(arg0 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Name", reflect.TypeOf((*MockAppModuleBasic)(nil).Name)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DefaultGenesis", reflect.TypeOf((*MockAppModuleBasic)(nil).DefaultGenesis), arg0) } -// RegisterLegacyAminoCodec mocks base method -func (m *MockAppModuleBasic) RegisterLegacyAminoCodec(arg0 *codec.LegacyAmino) { +// GetQueryCmd mocks base method. +func (m *MockAppModuleBasic) GetQueryCmd() *cobra.Command { m.ctrl.T.Helper() - m.ctrl.Call(m, "RegisterLegacyAminoCodec", arg0) + ret := m.ctrl.Call(m, "GetQueryCmd") + ret0, _ := ret[0].(*cobra.Command) + return ret0 } -// RegisterLegacyAminoCodec indicates an expected call of RegisterLegacyAminoCodec -func (mr *MockAppModuleBasicMockRecorder) RegisterLegacyAminoCodec(arg0 interface{}) *gomock.Call { +// GetQueryCmd indicates an expected call of GetQueryCmd. +func (mr *MockAppModuleBasicMockRecorder) GetQueryCmd() *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RegisterLegacyAminoCodec", reflect.TypeOf((*MockAppModuleBasic)(nil).RegisterLegacyAminoCodec), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetQueryCmd", reflect.TypeOf((*MockAppModuleBasic)(nil).GetQueryCmd)) } -// RegisterInterfaces mocks base method -func (m *MockAppModuleBasic) RegisterInterfaces(arg0 types.InterfaceRegistry) { +// GetTxCmd mocks base method. +func (m *MockAppModuleBasic) GetTxCmd() *cobra.Command { m.ctrl.T.Helper() - m.ctrl.Call(m, "RegisterInterfaces", arg0) + ret := m.ctrl.Call(m, "GetTxCmd") + ret0, _ := ret[0].(*cobra.Command) + return ret0 } -// RegisterInterfaces indicates an expected call of RegisterInterfaces -func (mr *MockAppModuleBasicMockRecorder) RegisterInterfaces(arg0 interface{}) *gomock.Call { +// GetTxCmd indicates an expected call of GetTxCmd. +func (mr *MockAppModuleBasicMockRecorder) GetTxCmd() *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RegisterInterfaces", reflect.TypeOf((*MockAppModuleBasic)(nil).RegisterInterfaces), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetTxCmd", reflect.TypeOf((*MockAppModuleBasic)(nil).GetTxCmd)) } -// DefaultGenesis mocks base method -func (m *MockAppModuleBasic) DefaultGenesis(arg0 codec.JSONMarshaler) json.RawMessage { +// Name mocks base method. +func (m *MockAppModuleBasic) Name() string { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "DefaultGenesis", arg0) - ret0, _ := ret[0].(json.RawMessage) + ret := m.ctrl.Call(m, "Name") + ret0, _ := ret[0].(string) return ret0 } -// DefaultGenesis indicates an expected call of DefaultGenesis -func (mr *MockAppModuleBasicMockRecorder) DefaultGenesis(arg0 interface{}) *gomock.Call { +// Name indicates an expected call of Name. +func (mr *MockAppModuleBasicMockRecorder) Name() *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DefaultGenesis", reflect.TypeOf((*MockAppModuleBasic)(nil).DefaultGenesis), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Name", reflect.TypeOf((*MockAppModuleBasic)(nil).Name)) } -// ValidateGenesis mocks base method -func (m *MockAppModuleBasic) ValidateGenesis(arg0 codec.JSONMarshaler, arg1 client.TxEncodingConfig, arg2 json.RawMessage) error { +// RegisterGRPCGatewayRoutes mocks base method. +func (m *MockAppModuleBasic) RegisterGRPCGatewayRoutes(arg0 client.Context, arg1 *runtime.ServeMux) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ValidateGenesis", arg0, arg1, arg2) - ret0, _ := ret[0].(error) - return ret0 + m.ctrl.Call(m, "RegisterGRPCGatewayRoutes", arg0, arg1) } -// ValidateGenesis indicates an expected call of ValidateGenesis -func (mr *MockAppModuleBasicMockRecorder) ValidateGenesis(arg0, arg1, arg2 interface{}) *gomock.Call { +// RegisterGRPCGatewayRoutes indicates an expected call of RegisterGRPCGatewayRoutes. +func (mr *MockAppModuleBasicMockRecorder) RegisterGRPCGatewayRoutes(arg0, arg1 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ValidateGenesis", reflect.TypeOf((*MockAppModuleBasic)(nil).ValidateGenesis), arg0, arg1, arg2) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RegisterGRPCGatewayRoutes", reflect.TypeOf((*MockAppModuleBasic)(nil).RegisterGRPCGatewayRoutes), arg0, arg1) } -// RegisterRESTRoutes mocks base method -func (m *MockAppModuleBasic) RegisterRESTRoutes(arg0 client.Context, arg1 *mux.Router) { +// RegisterInterfaces mocks base method. +func (m *MockAppModuleBasic) RegisterInterfaces(arg0 types.InterfaceRegistry) { m.ctrl.T.Helper() - m.ctrl.Call(m, "RegisterRESTRoutes", arg0, arg1) + m.ctrl.Call(m, "RegisterInterfaces", arg0) } -// RegisterRESTRoutes indicates an expected call of RegisterRESTRoutes -func (mr *MockAppModuleBasicMockRecorder) RegisterRESTRoutes(arg0, arg1 interface{}) *gomock.Call { +// RegisterInterfaces indicates an expected call of RegisterInterfaces. +func (mr *MockAppModuleBasicMockRecorder) RegisterInterfaces(arg0 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RegisterRESTRoutes", reflect.TypeOf((*MockAppModuleBasic)(nil).RegisterRESTRoutes), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RegisterInterfaces", reflect.TypeOf((*MockAppModuleBasic)(nil).RegisterInterfaces), arg0) } -// RegisterGRPCGatewayRoutes mocks base method -func (m *MockAppModuleBasic) RegisterGRPCGatewayRoutes(arg0 client.Context, arg1 *runtime.ServeMux) { +// RegisterLegacyAminoCodec mocks base method. +func (m *MockAppModuleBasic) RegisterLegacyAminoCodec(arg0 *codec.LegacyAmino) { m.ctrl.T.Helper() - m.ctrl.Call(m, "RegisterGRPCGatewayRoutes", arg0, arg1) + m.ctrl.Call(m, "RegisterLegacyAminoCodec", arg0) } -// RegisterGRPCGatewayRoutes indicates an expected call of RegisterGRPCGatewayRoutes -func (mr *MockAppModuleBasicMockRecorder) RegisterGRPCGatewayRoutes(arg0, arg1 interface{}) *gomock.Call { +// RegisterLegacyAminoCodec indicates an expected call of RegisterLegacyAminoCodec. +func (mr *MockAppModuleBasicMockRecorder) RegisterLegacyAminoCodec(arg0 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RegisterGRPCGatewayRoutes", reflect.TypeOf((*MockAppModuleBasic)(nil).RegisterGRPCGatewayRoutes), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RegisterLegacyAminoCodec", reflect.TypeOf((*MockAppModuleBasic)(nil).RegisterLegacyAminoCodec), arg0) } -// GetTxCmd mocks base method -func (m *MockAppModuleBasic) GetTxCmd() *cobra.Command { +// RegisterRESTRoutes mocks base method. +func (m *MockAppModuleBasic) RegisterRESTRoutes(arg0 client.Context, arg1 *mux.Router) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetTxCmd") - ret0, _ := ret[0].(*cobra.Command) - return ret0 + m.ctrl.Call(m, "RegisterRESTRoutes", arg0, arg1) } -// GetTxCmd indicates an expected call of GetTxCmd -func (mr *MockAppModuleBasicMockRecorder) GetTxCmd() *gomock.Call { +// RegisterRESTRoutes indicates an expected call of RegisterRESTRoutes. +func (mr *MockAppModuleBasicMockRecorder) RegisterRESTRoutes(arg0, arg1 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetTxCmd", reflect.TypeOf((*MockAppModuleBasic)(nil).GetTxCmd)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RegisterRESTRoutes", reflect.TypeOf((*MockAppModuleBasic)(nil).RegisterRESTRoutes), arg0, arg1) } -// GetQueryCmd mocks base method -func (m *MockAppModuleBasic) GetQueryCmd() *cobra.Command { +// ValidateGenesis mocks base method. +func (m *MockAppModuleBasic) ValidateGenesis(arg0 codec.JSONCodec, arg1 client.TxEncodingConfig, arg2 json.RawMessage) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetQueryCmd") - ret0, _ := ret[0].(*cobra.Command) + ret := m.ctrl.Call(m, "ValidateGenesis", arg0, arg1, arg2) + ret0, _ := ret[0].(error) return ret0 } -// GetQueryCmd indicates an expected call of GetQueryCmd -func (mr *MockAppModuleBasicMockRecorder) GetQueryCmd() *gomock.Call { +// ValidateGenesis indicates an expected call of ValidateGenesis. +func (mr *MockAppModuleBasicMockRecorder) ValidateGenesis(arg0, arg1, arg2 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetQueryCmd", reflect.TypeOf((*MockAppModuleBasic)(nil).GetQueryCmd)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ValidateGenesis", reflect.TypeOf((*MockAppModuleBasic)(nil).ValidateGenesis), arg0, arg1, arg2) } -// MockAppModuleGenesis is a mock of AppModuleGenesis interface +// MockAppModuleGenesis is a mock of AppModuleGenesis interface. type MockAppModuleGenesis struct { ctrl *gomock.Controller recorder *MockAppModuleGenesisMockRecorder } -// MockAppModuleGenesisMockRecorder is the mock recorder for MockAppModuleGenesis +// MockAppModuleGenesisMockRecorder is the mock recorder for MockAppModuleGenesis. type MockAppModuleGenesisMockRecorder struct { mock *MockAppModuleGenesis } -// NewMockAppModuleGenesis creates a new mock instance +// NewMockAppModuleGenesis creates a new mock instance. func NewMockAppModuleGenesis(ctrl *gomock.Controller) *MockAppModuleGenesis { mock := &MockAppModuleGenesis{ctrl: ctrl} mock.recorder = &MockAppModuleGenesisMockRecorder{mock} return mock } -// EXPECT returns an object that allows the caller to indicate expected use +// EXPECT returns an object that allows the caller to indicate expected use. func (m *MockAppModuleGenesis) EXPECT() *MockAppModuleGenesisMockRecorder { return m.recorder } -// Name mocks base method -func (m *MockAppModuleGenesis) Name() string { +// DefaultGenesis mocks base method. +func (m *MockAppModuleGenesis) DefaultGenesis(arg0 codec.JSONCodec) json.RawMessage { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Name") - ret0, _ := ret[0].(string) + ret := m.ctrl.Call(m, "DefaultGenesis", arg0) + ret0, _ := ret[0].(json.RawMessage) return ret0 } -// Name indicates an expected call of Name -func (mr *MockAppModuleGenesisMockRecorder) Name() *gomock.Call { +// DefaultGenesis indicates an expected call of DefaultGenesis. +func (mr *MockAppModuleGenesisMockRecorder) DefaultGenesis(arg0 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Name", reflect.TypeOf((*MockAppModuleGenesis)(nil).Name)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DefaultGenesis", reflect.TypeOf((*MockAppModuleGenesis)(nil).DefaultGenesis), arg0) } -// RegisterLegacyAminoCodec mocks base method -func (m *MockAppModuleGenesis) RegisterLegacyAminoCodec(arg0 *codec.LegacyAmino) { +// ExportGenesis mocks base method. +func (m *MockAppModuleGenesis) ExportGenesis(arg0 types0.Context, arg1 codec.JSONCodec) json.RawMessage { m.ctrl.T.Helper() - m.ctrl.Call(m, "RegisterLegacyAminoCodec", arg0) + ret := m.ctrl.Call(m, "ExportGenesis", arg0, arg1) + ret0, _ := ret[0].(json.RawMessage) + return ret0 } -// RegisterLegacyAminoCodec indicates an expected call of RegisterLegacyAminoCodec -func (mr *MockAppModuleGenesisMockRecorder) RegisterLegacyAminoCodec(arg0 interface{}) *gomock.Call { +// ExportGenesis indicates an expected call of ExportGenesis. +func (mr *MockAppModuleGenesisMockRecorder) ExportGenesis(arg0, arg1 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RegisterLegacyAminoCodec", reflect.TypeOf((*MockAppModuleGenesis)(nil).RegisterLegacyAminoCodec), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ExportGenesis", reflect.TypeOf((*MockAppModuleGenesis)(nil).ExportGenesis), arg0, arg1) } -// RegisterInterfaces mocks base method -func (m *MockAppModuleGenesis) RegisterInterfaces(arg0 types.InterfaceRegistry) { +// GetQueryCmd mocks base method. +func (m *MockAppModuleGenesis) GetQueryCmd() *cobra.Command { m.ctrl.T.Helper() - m.ctrl.Call(m, "RegisterInterfaces", arg0) + ret := m.ctrl.Call(m, "GetQueryCmd") + ret0, _ := ret[0].(*cobra.Command) + return ret0 } -// RegisterInterfaces indicates an expected call of RegisterInterfaces -func (mr *MockAppModuleGenesisMockRecorder) RegisterInterfaces(arg0 interface{}) *gomock.Call { +// GetQueryCmd indicates an expected call of GetQueryCmd. +func (mr *MockAppModuleGenesisMockRecorder) GetQueryCmd() *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RegisterInterfaces", reflect.TypeOf((*MockAppModuleGenesis)(nil).RegisterInterfaces), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetQueryCmd", reflect.TypeOf((*MockAppModuleGenesis)(nil).GetQueryCmd)) } -// DefaultGenesis mocks base method -func (m *MockAppModuleGenesis) DefaultGenesis(arg0 codec.JSONMarshaler) json.RawMessage { +// GetTxCmd mocks base method. +func (m *MockAppModuleGenesis) GetTxCmd() *cobra.Command { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "DefaultGenesis", arg0) - ret0, _ := ret[0].(json.RawMessage) + ret := m.ctrl.Call(m, "GetTxCmd") + ret0, _ := ret[0].(*cobra.Command) return ret0 } -// DefaultGenesis indicates an expected call of DefaultGenesis -func (mr *MockAppModuleGenesisMockRecorder) DefaultGenesis(arg0 interface{}) *gomock.Call { +// GetTxCmd indicates an expected call of GetTxCmd. +func (mr *MockAppModuleGenesisMockRecorder) GetTxCmd() *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DefaultGenesis", reflect.TypeOf((*MockAppModuleGenesis)(nil).DefaultGenesis), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetTxCmd", reflect.TypeOf((*MockAppModuleGenesis)(nil).GetTxCmd)) } -// ValidateGenesis mocks base method -func (m *MockAppModuleGenesis) ValidateGenesis(arg0 codec.JSONMarshaler, arg1 client.TxEncodingConfig, arg2 json.RawMessage) error { +// InitGenesis mocks base method. +func (m *MockAppModuleGenesis) InitGenesis(arg0 types0.Context, arg1 codec.JSONCodec, arg2 json.RawMessage) []types1.ValidatorUpdate { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ValidateGenesis", arg0, arg1, arg2) - ret0, _ := ret[0].(error) + ret := m.ctrl.Call(m, "InitGenesis", arg0, arg1, arg2) + ret0, _ := ret[0].([]types1.ValidatorUpdate) return ret0 } -// ValidateGenesis indicates an expected call of ValidateGenesis -func (mr *MockAppModuleGenesisMockRecorder) ValidateGenesis(arg0, arg1, arg2 interface{}) *gomock.Call { +// InitGenesis indicates an expected call of InitGenesis. +func (mr *MockAppModuleGenesisMockRecorder) InitGenesis(arg0, arg1, arg2 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ValidateGenesis", reflect.TypeOf((*MockAppModuleGenesis)(nil).ValidateGenesis), arg0, arg1, arg2) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InitGenesis", reflect.TypeOf((*MockAppModuleGenesis)(nil).InitGenesis), arg0, arg1, arg2) } -// RegisterRESTRoutes mocks base method -func (m *MockAppModuleGenesis) RegisterRESTRoutes(arg0 client.Context, arg1 *mux.Router) { +// Name mocks base method. +func (m *MockAppModuleGenesis) Name() string { m.ctrl.T.Helper() - m.ctrl.Call(m, "RegisterRESTRoutes", arg0, arg1) + ret := m.ctrl.Call(m, "Name") + ret0, _ := ret[0].(string) + return ret0 } -// RegisterRESTRoutes indicates an expected call of RegisterRESTRoutes -func (mr *MockAppModuleGenesisMockRecorder) RegisterRESTRoutes(arg0, arg1 interface{}) *gomock.Call { +// Name indicates an expected call of Name. +func (mr *MockAppModuleGenesisMockRecorder) Name() *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RegisterRESTRoutes", reflect.TypeOf((*MockAppModuleGenesis)(nil).RegisterRESTRoutes), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Name", reflect.TypeOf((*MockAppModuleGenesis)(nil).Name)) } -// RegisterGRPCGatewayRoutes mocks base method +// RegisterGRPCGatewayRoutes mocks base method. func (m *MockAppModuleGenesis) RegisterGRPCGatewayRoutes(arg0 client.Context, arg1 *runtime.ServeMux) { m.ctrl.T.Helper() m.ctrl.Call(m, "RegisterGRPCGatewayRoutes", arg0, arg1) } -// RegisterGRPCGatewayRoutes indicates an expected call of RegisterGRPCGatewayRoutes +// RegisterGRPCGatewayRoutes indicates an expected call of RegisterGRPCGatewayRoutes. func (mr *MockAppModuleGenesisMockRecorder) RegisterGRPCGatewayRoutes(arg0, arg1 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RegisterGRPCGatewayRoutes", reflect.TypeOf((*MockAppModuleGenesis)(nil).RegisterGRPCGatewayRoutes), arg0, arg1) } -// GetTxCmd mocks base method -func (m *MockAppModuleGenesis) GetTxCmd() *cobra.Command { +// RegisterInterfaces mocks base method. +func (m *MockAppModuleGenesis) RegisterInterfaces(arg0 types.InterfaceRegistry) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetTxCmd") - ret0, _ := ret[0].(*cobra.Command) - return ret0 + m.ctrl.Call(m, "RegisterInterfaces", arg0) } -// GetTxCmd indicates an expected call of GetTxCmd -func (mr *MockAppModuleGenesisMockRecorder) GetTxCmd() *gomock.Call { +// RegisterInterfaces indicates an expected call of RegisterInterfaces. +func (mr *MockAppModuleGenesisMockRecorder) RegisterInterfaces(arg0 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetTxCmd", reflect.TypeOf((*MockAppModuleGenesis)(nil).GetTxCmd)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RegisterInterfaces", reflect.TypeOf((*MockAppModuleGenesis)(nil).RegisterInterfaces), arg0) } -// GetQueryCmd mocks base method -func (m *MockAppModuleGenesis) GetQueryCmd() *cobra.Command { +// RegisterLegacyAminoCodec mocks base method. +func (m *MockAppModuleGenesis) RegisterLegacyAminoCodec(arg0 *codec.LegacyAmino) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetQueryCmd") - ret0, _ := ret[0].(*cobra.Command) - return ret0 + m.ctrl.Call(m, "RegisterLegacyAminoCodec", arg0) } -// GetQueryCmd indicates an expected call of GetQueryCmd -func (mr *MockAppModuleGenesisMockRecorder) GetQueryCmd() *gomock.Call { +// RegisterLegacyAminoCodec indicates an expected call of RegisterLegacyAminoCodec. +func (mr *MockAppModuleGenesisMockRecorder) RegisterLegacyAminoCodec(arg0 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetQueryCmd", reflect.TypeOf((*MockAppModuleGenesis)(nil).GetQueryCmd)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RegisterLegacyAminoCodec", reflect.TypeOf((*MockAppModuleGenesis)(nil).RegisterLegacyAminoCodec), arg0) } -// InitGenesis mocks base method -func (m *MockAppModuleGenesis) InitGenesis(arg0 types0.Context, arg1 codec.JSONMarshaler, arg2 json.RawMessage) []types1.ValidatorUpdate { +// RegisterRESTRoutes mocks base method. +func (m *MockAppModuleGenesis) RegisterRESTRoutes(arg0 client.Context, arg1 *mux.Router) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "InitGenesis", arg0, arg1, arg2) - ret0, _ := ret[0].([]types1.ValidatorUpdate) - return ret0 + m.ctrl.Call(m, "RegisterRESTRoutes", arg0, arg1) } -// InitGenesis indicates an expected call of InitGenesis -func (mr *MockAppModuleGenesisMockRecorder) InitGenesis(arg0, arg1, arg2 interface{}) *gomock.Call { +// RegisterRESTRoutes indicates an expected call of RegisterRESTRoutes. +func (mr *MockAppModuleGenesisMockRecorder) RegisterRESTRoutes(arg0, arg1 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InitGenesis", reflect.TypeOf((*MockAppModuleGenesis)(nil).InitGenesis), arg0, arg1, arg2) -} - -// ExportGenesis mocks base method -func (m *MockAppModuleGenesis) ExportGenesis(arg0 types0.Context, arg1 codec.JSONMarshaler) json.RawMessage { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ExportGenesis", arg0, arg1) - ret0, _ := ret[0].(json.RawMessage) - return ret0 + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RegisterRESTRoutes", reflect.TypeOf((*MockAppModuleGenesis)(nil).RegisterRESTRoutes), arg0, arg1) } -// ConsensusVersion mocks base method. -func (m *MockAppModule) ConsensusVersion() uint64 { +// ValidateGenesis mocks base method. +func (m *MockAppModuleGenesis) ValidateGenesis(arg0 codec.JSONCodec, arg1 client.TxEncodingConfig, arg2 json.RawMessage) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ConsensusVersion") - ret0, _ := ret[0].(uint64) + ret := m.ctrl.Call(m, "ValidateGenesis", arg0, arg1, arg2) + ret0, _ := ret[0].(error) return ret0 } -// ConsensusVersion indicates an expected call of ConsensusVersion. -func (mr *MockAppModuleMockRecorder) ConsensusVersion() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ConsensusVersion", reflect.TypeOf((*MockAppModule)(nil).ConsensusVersion)) -} - -// ExportGenesis indicates an expected call of ExportGenesis -func (mr *MockAppModuleGenesisMockRecorder) ExportGenesis(arg0, arg1 interface{}) *gomock.Call { +// ValidateGenesis indicates an expected call of ValidateGenesis. +func (mr *MockAppModuleGenesisMockRecorder) ValidateGenesis(arg0, arg1, arg2 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ExportGenesis", reflect.TypeOf((*MockAppModuleGenesis)(nil).ExportGenesis), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ValidateGenesis", reflect.TypeOf((*MockAppModuleGenesis)(nil).ValidateGenesis), arg0, arg1, arg2) } -// MockAppModule is a mock of AppModule interface +// MockAppModule is a mock of AppModule interface. type MockAppModule struct { ctrl *gomock.Controller recorder *MockAppModuleMockRecorder } -// MockAppModuleMockRecorder is the mock recorder for MockAppModule +// MockAppModuleMockRecorder is the mock recorder for MockAppModule. type MockAppModuleMockRecorder struct { mock *MockAppModule } -// NewMockAppModule creates a new mock instance +// NewMockAppModule creates a new mock instance. func NewMockAppModule(ctrl *gomock.Controller) *MockAppModule { mock := &MockAppModule{ctrl: ctrl} mock.recorder = &MockAppModuleMockRecorder{mock} return mock } -// EXPECT returns an object that allows the caller to indicate expected use +// EXPECT returns an object that allows the caller to indicate expected use. func (m *MockAppModule) EXPECT() *MockAppModuleMockRecorder { return m.recorder } -// Name mocks base method -func (m *MockAppModule) Name() string { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Name") - ret0, _ := ret[0].(string) - return ret0 -} - -// Name indicates an expected call of Name -func (mr *MockAppModuleMockRecorder) Name() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Name", reflect.TypeOf((*MockAppModule)(nil).Name)) -} - -// RegisterLegacyAminoCodec mocks base method -func (m *MockAppModule) RegisterLegacyAminoCodec(arg0 *codec.LegacyAmino) { +// BeginBlock mocks base method. +func (m *MockAppModule) BeginBlock(arg0 types0.Context, arg1 types1.RequestBeginBlock) { m.ctrl.T.Helper() - m.ctrl.Call(m, "RegisterLegacyAminoCodec", arg0) + m.ctrl.Call(m, "BeginBlock", arg0, arg1) } -// RegisterLegacyAminoCodec indicates an expected call of RegisterLegacyAminoCodec -func (mr *MockAppModuleMockRecorder) RegisterLegacyAminoCodec(arg0 interface{}) *gomock.Call { +// BeginBlock indicates an expected call of BeginBlock. +func (mr *MockAppModuleMockRecorder) BeginBlock(arg0, arg1 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RegisterLegacyAminoCodec", reflect.TypeOf((*MockAppModule)(nil).RegisterLegacyAminoCodec), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BeginBlock", reflect.TypeOf((*MockAppModule)(nil).BeginBlock), arg0, arg1) } -// RegisterInterfaces mocks base method -func (m *MockAppModule) RegisterInterfaces(arg0 types.InterfaceRegistry) { +// ConsensusVersion mocks base method. +func (m *MockAppModule) ConsensusVersion() uint64 { m.ctrl.T.Helper() - m.ctrl.Call(m, "RegisterInterfaces", arg0) + ret := m.ctrl.Call(m, "ConsensusVersion") + ret0, _ := ret[0].(uint64) + return ret0 } -// RegisterInterfaces indicates an expected call of RegisterInterfaces -func (mr *MockAppModuleMockRecorder) RegisterInterfaces(arg0 interface{}) *gomock.Call { +// ConsensusVersion indicates an expected call of ConsensusVersion. +func (mr *MockAppModuleMockRecorder) ConsensusVersion() *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RegisterInterfaces", reflect.TypeOf((*MockAppModule)(nil).RegisterInterfaces), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ConsensusVersion", reflect.TypeOf((*MockAppModule)(nil).ConsensusVersion)) } -// DefaultGenesis mocks base method -func (m *MockAppModule) DefaultGenesis(arg0 codec.JSONMarshaler) json.RawMessage { +// DefaultGenesis mocks base method. +func (m *MockAppModule) DefaultGenesis(arg0 codec.JSONCodec) json.RawMessage { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "DefaultGenesis", arg0) ret0, _ := ret[0].(json.RawMessage) return ret0 } -// DefaultGenesis indicates an expected call of DefaultGenesis +// DefaultGenesis indicates an expected call of DefaultGenesis. func (mr *MockAppModuleMockRecorder) DefaultGenesis(arg0 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DefaultGenesis", reflect.TypeOf((*MockAppModule)(nil).DefaultGenesis), arg0) } -// ValidateGenesis mocks base method -func (m *MockAppModule) ValidateGenesis(arg0 codec.JSONMarshaler, arg1 client.TxEncodingConfig, arg2 json.RawMessage) error { +// EndBlock mocks base method. +func (m *MockAppModule) EndBlock(arg0 types0.Context, arg1 types1.RequestEndBlock) []types1.ValidatorUpdate { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ValidateGenesis", arg0, arg1, arg2) - ret0, _ := ret[0].(error) + ret := m.ctrl.Call(m, "EndBlock", arg0, arg1) + ret0, _ := ret[0].([]types1.ValidatorUpdate) return ret0 } -// ValidateGenesis indicates an expected call of ValidateGenesis -func (mr *MockAppModuleMockRecorder) ValidateGenesis(arg0, arg1, arg2 interface{}) *gomock.Call { +// EndBlock indicates an expected call of EndBlock. +func (mr *MockAppModuleMockRecorder) EndBlock(arg0, arg1 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ValidateGenesis", reflect.TypeOf((*MockAppModule)(nil).ValidateGenesis), arg0, arg1, arg2) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EndBlock", reflect.TypeOf((*MockAppModule)(nil).EndBlock), arg0, arg1) } -// RegisterRESTRoutes mocks base method -func (m *MockAppModule) RegisterRESTRoutes(arg0 client.Context, arg1 *mux.Router) { +// ExportGenesis mocks base method. +func (m *MockAppModule) ExportGenesis(arg0 types0.Context, arg1 codec.JSONCodec) json.RawMessage { m.ctrl.T.Helper() - m.ctrl.Call(m, "RegisterRESTRoutes", arg0, arg1) + ret := m.ctrl.Call(m, "ExportGenesis", arg0, arg1) + ret0, _ := ret[0].(json.RawMessage) + return ret0 } -// RegisterRESTRoutes indicates an expected call of RegisterRESTRoutes -func (mr *MockAppModuleMockRecorder) RegisterRESTRoutes(arg0, arg1 interface{}) *gomock.Call { +// ExportGenesis indicates an expected call of ExportGenesis. +func (mr *MockAppModuleMockRecorder) ExportGenesis(arg0, arg1 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RegisterRESTRoutes", reflect.TypeOf((*MockAppModule)(nil).RegisterRESTRoutes), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ExportGenesis", reflect.TypeOf((*MockAppModule)(nil).ExportGenesis), arg0, arg1) } -// RegisterGRPCGatewayRoutes mocks base method -func (m *MockAppModule) RegisterGRPCGatewayRoutes(arg0 client.Context, arg1 *runtime.ServeMux) { +// GetQueryCmd mocks base method. +func (m *MockAppModule) GetQueryCmd() *cobra.Command { m.ctrl.T.Helper() - m.ctrl.Call(m, "RegisterGRPCGatewayRoutes", arg0, arg1) + ret := m.ctrl.Call(m, "GetQueryCmd") + ret0, _ := ret[0].(*cobra.Command) + return ret0 } -// RegisterGRPCGatewayRoutes indicates an expected call of RegisterGRPCGatewayRoutes -func (mr *MockAppModuleMockRecorder) RegisterGRPCGatewayRoutes(arg0, arg1 interface{}) *gomock.Call { +// GetQueryCmd indicates an expected call of GetQueryCmd. +func (mr *MockAppModuleMockRecorder) GetQueryCmd() *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RegisterGRPCGatewayRoutes", reflect.TypeOf((*MockAppModule)(nil).RegisterGRPCGatewayRoutes), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetQueryCmd", reflect.TypeOf((*MockAppModule)(nil).GetQueryCmd)) } -// GetTxCmd mocks base method +// GetTxCmd mocks base method. func (m *MockAppModule) GetTxCmd() *cobra.Command { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "GetTxCmd") @@ -464,142 +443,164 @@ func (m *MockAppModule) GetTxCmd() *cobra.Command { return ret0 } -// GetTxCmd indicates an expected call of GetTxCmd +// GetTxCmd indicates an expected call of GetTxCmd. func (mr *MockAppModuleMockRecorder) GetTxCmd() *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetTxCmd", reflect.TypeOf((*MockAppModule)(nil).GetTxCmd)) } -// GetQueryCmd mocks base method -func (m *MockAppModule) GetQueryCmd() *cobra.Command { +// InitGenesis mocks base method. +func (m *MockAppModule) InitGenesis(arg0 types0.Context, arg1 codec.JSONCodec, arg2 json.RawMessage) []types1.ValidatorUpdate { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetQueryCmd") - ret0, _ := ret[0].(*cobra.Command) + ret := m.ctrl.Call(m, "InitGenesis", arg0, arg1, arg2) + ret0, _ := ret[0].([]types1.ValidatorUpdate) return ret0 } -// GetQueryCmd indicates an expected call of GetQueryCmd -func (mr *MockAppModuleMockRecorder) GetQueryCmd() *gomock.Call { +// InitGenesis indicates an expected call of InitGenesis. +func (mr *MockAppModuleMockRecorder) InitGenesis(arg0, arg1, arg2 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetQueryCmd", reflect.TypeOf((*MockAppModule)(nil).GetQueryCmd)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InitGenesis", reflect.TypeOf((*MockAppModule)(nil).InitGenesis), arg0, arg1, arg2) } -// InitGenesis mocks base method -func (m *MockAppModule) InitGenesis(arg0 types0.Context, arg1 codec.JSONMarshaler, arg2 json.RawMessage) []types1.ValidatorUpdate { +// LegacyQuerierHandler mocks base method. +func (m *MockAppModule) LegacyQuerierHandler(arg0 *codec.LegacyAmino) types0.Querier { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "InitGenesis", arg0, arg1, arg2) - ret0, _ := ret[0].([]types1.ValidatorUpdate) + ret := m.ctrl.Call(m, "LegacyQuerierHandler", arg0) + ret0, _ := ret[0].(types0.Querier) return ret0 } -// InitGenesis indicates an expected call of InitGenesis -func (mr *MockAppModuleMockRecorder) InitGenesis(arg0, arg1, arg2 interface{}) *gomock.Call { +// LegacyQuerierHandler indicates an expected call of LegacyQuerierHandler. +func (mr *MockAppModuleMockRecorder) LegacyQuerierHandler(arg0 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InitGenesis", reflect.TypeOf((*MockAppModule)(nil).InitGenesis), arg0, arg1, arg2) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LegacyQuerierHandler", reflect.TypeOf((*MockAppModule)(nil).LegacyQuerierHandler), arg0) } -// ExportGenesis mocks base method -func (m *MockAppModule) ExportGenesis(arg0 types0.Context, arg1 codec.JSONMarshaler) json.RawMessage { +// Name mocks base method. +func (m *MockAppModule) Name() string { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ExportGenesis", arg0, arg1) - ret0, _ := ret[0].(json.RawMessage) + ret := m.ctrl.Call(m, "Name") + ret0, _ := ret[0].(string) return ret0 } -// ExportGenesis indicates an expected call of ExportGenesis -func (mr *MockAppModuleMockRecorder) ExportGenesis(arg0, arg1 interface{}) *gomock.Call { +// Name indicates an expected call of Name. +func (mr *MockAppModuleMockRecorder) Name() *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ExportGenesis", reflect.TypeOf((*MockAppModule)(nil).ExportGenesis), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Name", reflect.TypeOf((*MockAppModule)(nil).Name)) } -// RegisterInvariants mocks base method -func (m *MockAppModule) RegisterInvariants(arg0 types0.InvariantRegistry) { +// QuerierRoute mocks base method. +func (m *MockAppModule) QuerierRoute() string { m.ctrl.T.Helper() - m.ctrl.Call(m, "RegisterInvariants", arg0) + ret := m.ctrl.Call(m, "QuerierRoute") + ret0, _ := ret[0].(string) + return ret0 } -// RegisterInvariants indicates an expected call of RegisterInvariants -func (mr *MockAppModuleMockRecorder) RegisterInvariants(arg0 interface{}) *gomock.Call { +// QuerierRoute indicates an expected call of QuerierRoute. +func (mr *MockAppModuleMockRecorder) QuerierRoute() *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RegisterInvariants", reflect.TypeOf((*MockAppModule)(nil).RegisterInvariants), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "QuerierRoute", reflect.TypeOf((*MockAppModule)(nil).QuerierRoute)) } -// Route mocks base method -func (m *MockAppModule) Route() types0.Route { +// RegisterGRPCGatewayRoutes mocks base method. +func (m *MockAppModule) RegisterGRPCGatewayRoutes(arg0 client.Context, arg1 *runtime.ServeMux) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Route") - ret0, _ := ret[0].(types0.Route) - return ret0 + m.ctrl.Call(m, "RegisterGRPCGatewayRoutes", arg0, arg1) } -// Route indicates an expected call of Route -func (mr *MockAppModuleMockRecorder) Route() *gomock.Call { +// RegisterGRPCGatewayRoutes indicates an expected call of RegisterGRPCGatewayRoutes. +func (mr *MockAppModuleMockRecorder) RegisterGRPCGatewayRoutes(arg0, arg1 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Route", reflect.TypeOf((*MockAppModule)(nil).Route)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RegisterGRPCGatewayRoutes", reflect.TypeOf((*MockAppModule)(nil).RegisterGRPCGatewayRoutes), arg0, arg1) } -// QuerierRoute mocks base method -func (m *MockAppModule) QuerierRoute() string { +// RegisterInterfaces mocks base method. +func (m *MockAppModule) RegisterInterfaces(arg0 types.InterfaceRegistry) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "QuerierRoute") - ret0, _ := ret[0].(string) - return ret0 + m.ctrl.Call(m, "RegisterInterfaces", arg0) } -// QuerierRoute indicates an expected call of QuerierRoute -func (mr *MockAppModuleMockRecorder) QuerierRoute() *gomock.Call { +// RegisterInterfaces indicates an expected call of RegisterInterfaces. +func (mr *MockAppModuleMockRecorder) RegisterInterfaces(arg0 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "QuerierRoute", reflect.TypeOf((*MockAppModule)(nil).QuerierRoute)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RegisterInterfaces", reflect.TypeOf((*MockAppModule)(nil).RegisterInterfaces), arg0) } -// LegacyQuerierHandler mocks base method -func (m *MockAppModule) LegacyQuerierHandler(arg0 *codec.LegacyAmino) types0.Querier { +// RegisterInvariants mocks base method. +func (m *MockAppModule) RegisterInvariants(arg0 types0.InvariantRegistry) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "LegacyQuerierHandler", arg0) - ret0, _ := ret[0].(types0.Querier) - return ret0 + m.ctrl.Call(m, "RegisterInvariants", arg0) } -// LegacyQuerierHandler indicates an expected call of LegacyQuerierHandler -func (mr *MockAppModuleMockRecorder) LegacyQuerierHandler(arg0 interface{}) *gomock.Call { +// RegisterInvariants indicates an expected call of RegisterInvariants. +func (mr *MockAppModuleMockRecorder) RegisterInvariants(arg0 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LegacyQuerierHandler", reflect.TypeOf((*MockAppModule)(nil).LegacyQuerierHandler), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RegisterInvariants", reflect.TypeOf((*MockAppModule)(nil).RegisterInvariants), arg0) +} + +// RegisterLegacyAminoCodec mocks base method. +func (m *MockAppModule) RegisterLegacyAminoCodec(arg0 *codec.LegacyAmino) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "RegisterLegacyAminoCodec", arg0) +} + +// RegisterLegacyAminoCodec indicates an expected call of RegisterLegacyAminoCodec. +func (mr *MockAppModuleMockRecorder) RegisterLegacyAminoCodec(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RegisterLegacyAminoCodec", reflect.TypeOf((*MockAppModule)(nil).RegisterLegacyAminoCodec), arg0) +} + +// RegisterRESTRoutes mocks base method. +func (m *MockAppModule) RegisterRESTRoutes(arg0 client.Context, arg1 *mux.Router) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "RegisterRESTRoutes", arg0, arg1) +} + +// RegisterRESTRoutes indicates an expected call of RegisterRESTRoutes. +func (mr *MockAppModuleMockRecorder) RegisterRESTRoutes(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RegisterRESTRoutes", reflect.TypeOf((*MockAppModule)(nil).RegisterRESTRoutes), arg0, arg1) } -// RegisterServices mocks base method +// RegisterServices mocks base method. func (m *MockAppModule) RegisterServices(arg0 module.Configurator) { m.ctrl.T.Helper() m.ctrl.Call(m, "RegisterServices", arg0) } -// RegisterServices indicates an expected call of RegisterServices +// RegisterServices indicates an expected call of RegisterServices. func (mr *MockAppModuleMockRecorder) RegisterServices(arg0 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RegisterServices", reflect.TypeOf((*MockAppModule)(nil).RegisterServices), arg0) } -// BeginBlock mocks base method -func (m *MockAppModule) BeginBlock(arg0 types0.Context, arg1 types1.RequestBeginBlock) { +// Route mocks base method. +func (m *MockAppModule) Route() types0.Route { m.ctrl.T.Helper() - m.ctrl.Call(m, "BeginBlock", arg0, arg1) + ret := m.ctrl.Call(m, "Route") + ret0, _ := ret[0].(types0.Route) + return ret0 } -// BeginBlock indicates an expected call of BeginBlock -func (mr *MockAppModuleMockRecorder) BeginBlock(arg0, arg1 interface{}) *gomock.Call { +// Route indicates an expected call of Route. +func (mr *MockAppModuleMockRecorder) Route() *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BeginBlock", reflect.TypeOf((*MockAppModule)(nil).BeginBlock), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Route", reflect.TypeOf((*MockAppModule)(nil).Route)) } -// EndBlock mocks base method -func (m *MockAppModule) EndBlock(arg0 types0.Context, arg1 types1.RequestEndBlock) []types1.ValidatorUpdate { +// ValidateGenesis mocks base method. +func (m *MockAppModule) ValidateGenesis(arg0 codec.JSONCodec, arg1 client.TxEncodingConfig, arg2 json.RawMessage) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "EndBlock", arg0, arg1) - ret0, _ := ret[0].([]types1.ValidatorUpdate) + ret := m.ctrl.Call(m, "ValidateGenesis", arg0, arg1, arg2) + ret0, _ := ret[0].(error) return ret0 } -// EndBlock indicates an expected call of EndBlock -func (mr *MockAppModuleMockRecorder) EndBlock(arg0, arg1 interface{}) *gomock.Call { +// ValidateGenesis indicates an expected call of ValidateGenesis. +func (mr *MockAppModuleMockRecorder) ValidateGenesis(arg0, arg1, arg2 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EndBlock", reflect.TypeOf((*MockAppModule)(nil).EndBlock), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ValidateGenesis", reflect.TypeOf((*MockAppModule)(nil).ValidateGenesis), arg0, arg1, arg2) } diff --git a/tests/mocks/types_router.go b/tests/mocks/types_router.go index a713c8d770..8740cc3f20 100644 --- a/tests/mocks/types_router.go +++ b/tests/mocks/types_router.go @@ -5,35 +5,36 @@ package mocks import ( + "reflect" + gomock "github.com/golang/mock/gomock" types "github.com/line/lbm-sdk/types" - reflect "reflect" ) -// MockRouter is a mock of Router interface +// MockRouter is a mock of Router interface. type MockRouter struct { ctrl *gomock.Controller recorder *MockRouterMockRecorder } -// MockRouterMockRecorder is the mock recorder for MockRouter +// MockRouterMockRecorder is the mock recorder for MockRouter. type MockRouterMockRecorder struct { mock *MockRouter } -// NewMockRouter creates a new mock instance +// NewMockRouter creates a new mock instance. func NewMockRouter(ctrl *gomock.Controller) *MockRouter { mock := &MockRouter{ctrl: ctrl} mock.recorder = &MockRouterMockRecorder{mock} return mock } -// EXPECT returns an object that allows the caller to indicate expected use +// EXPECT returns an object that allows the caller to indicate expected use. func (m *MockRouter) EXPECT() *MockRouterMockRecorder { return m.recorder } -// AddRoute mocks base method +// AddRoute mocks base method. func (m *MockRouter) AddRoute(r types.Route) types.Router { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "AddRoute", r) @@ -41,13 +42,13 @@ func (m *MockRouter) AddRoute(r types.Route) types.Router { return ret0 } -// AddRoute indicates an expected call of AddRoute +// AddRoute indicates an expected call of AddRoute. func (mr *MockRouterMockRecorder) AddRoute(r interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddRoute", reflect.TypeOf((*MockRouter)(nil).AddRoute), r) } -// Route mocks base method +// Route mocks base method. func (m *MockRouter) Route(ctx types.Context, path string) types.Handler { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "Route", ctx, path) @@ -55,36 +56,36 @@ func (m *MockRouter) Route(ctx types.Context, path string) types.Handler { return ret0 } -// Route indicates an expected call of Route +// Route indicates an expected call of Route. func (mr *MockRouterMockRecorder) Route(ctx, path interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Route", reflect.TypeOf((*MockRouter)(nil).Route), ctx, path) } -// MockQueryRouter is a mock of QueryRouter interface +// MockQueryRouter is a mock of QueryRouter interface. type MockQueryRouter struct { ctrl *gomock.Controller recorder *MockQueryRouterMockRecorder } -// MockQueryRouterMockRecorder is the mock recorder for MockQueryRouter +// MockQueryRouterMockRecorder is the mock recorder for MockQueryRouter. type MockQueryRouterMockRecorder struct { mock *MockQueryRouter } -// NewMockQueryRouter creates a new mock instance +// NewMockQueryRouter creates a new mock instance. func NewMockQueryRouter(ctrl *gomock.Controller) *MockQueryRouter { mock := &MockQueryRouter{ctrl: ctrl} mock.recorder = &MockQueryRouterMockRecorder{mock} return mock } -// EXPECT returns an object that allows the caller to indicate expected use +// EXPECT returns an object that allows the caller to indicate expected use. func (m *MockQueryRouter) EXPECT() *MockQueryRouterMockRecorder { return m.recorder } -// AddRoute mocks base method +// AddRoute mocks base method. func (m *MockQueryRouter) AddRoute(r string, h types.Querier) types.QueryRouter { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "AddRoute", r, h) @@ -92,13 +93,13 @@ func (m *MockQueryRouter) AddRoute(r string, h types.Querier) types.QueryRouter return ret0 } -// AddRoute indicates an expected call of AddRoute +// AddRoute indicates an expected call of AddRoute. func (mr *MockQueryRouterMockRecorder) AddRoute(r, h interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddRoute", reflect.TypeOf((*MockQueryRouter)(nil).AddRoute), r, h) } -// Route mocks base method +// Route mocks base method. func (m *MockQueryRouter) Route(path string) types.Querier { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "Route", path) @@ -106,7 +107,7 @@ func (m *MockQueryRouter) Route(path string) types.Querier { return ret0 } -// Route indicates an expected call of Route +// Route indicates an expected call of Route. func (mr *MockQueryRouterMockRecorder) Route(path interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Route", reflect.TypeOf((*MockQueryRouter)(nil).Route), path) diff --git a/testutil/context.go b/testutil/context.go index 7e2ee962b5..2a60dbff04 100644 --- a/testutil/context.go +++ b/testutil/context.go @@ -10,11 +10,11 @@ import ( ) // DefaultContext creates a sdk.Context with a fresh MemDB that can be used in tests. -func DefaultContext(key sdk.StoreKey) sdk.Context { +func DefaultContext(key sdk.StoreKey, tkey sdk.StoreKey) sdk.Context { db := memdb.NewDB() cms := store.NewCommitMultiStore(db) cms.MountStoreWithDB(key, sdk.StoreTypeIAVL, db) - // cms.MountStoreWithDB(tkey, sdk.StoreTypeTransient, db) + cms.MountStoreWithDB(tkey, sdk.StoreTypeTransient, db) err := cms.LoadLatestVersion() if err != nil { panic(err) diff --git a/testutil/key.go b/testutil/key.go new file mode 100644 index 0000000000..bd3d2ea915 --- /dev/null +++ b/testutil/key.go @@ -0,0 +1,82 @@ +package testutil + +import ( + "fmt" + + "github.com/line/lbm-sdk/crypto/keyring" + sdk "github.com/line/lbm-sdk/types" +) + +// GenerateCoinKey generates a new key mnemonic along with its addrress. +func GenerateCoinKey(algo keyring.SignatureAlgo) (sdk.AccAddress, string, error) { + // generate a private key, with mnemonic + info, secret, err := keyring.NewInMemory().NewMnemonic( + "name", + keyring.English, + sdk.GetConfig().GetFullBIP44Path(), + keyring.DefaultBIP39Passphrase, + algo, + ) + if err != nil { + return sdk.AccAddress(""), "", err + } + + return sdk.AccAddress(info.GetPubKey().Address()), secret, nil +} + +// GenerateSaveCoinKey generates a new key mnemonic with its addrress. +// If mnemonic is provided then it's used for key generation. +// The key is saved in the keyring. The function returns error if overwrite=true and the key +// already exists. +func GenerateSaveCoinKey( + keybase keyring.Keyring, + keyName, mnemonic string, + overwrite bool, + algo keyring.SignatureAlgo, +) (sdk.AccAddress, string, error) { + exists := false + _, err := keybase.Key(keyName) + if err == nil { + exists = true + } + + // ensure no overwrite + if !overwrite && exists { + return sdk.AccAddress(""), "", fmt.Errorf("key already exists, overwrite is disabled") + } + + if exists { + if err := keybase.Delete(keyName); err != nil { + return sdk.AccAddress(""), "", fmt.Errorf("failed to overwrite key") + } + } + + var ( + info keyring.Info + secret string + ) + + if mnemonic != "" { + secret = mnemonic + info, err = keybase.NewAccount( + keyName, + mnemonic, + keyring.DefaultBIP39Passphrase, + sdk.GetConfig().GetFullBIP44Path(), + algo, + ) + } else { + info, secret, err = keybase.NewMnemonic( + keyName, + keyring.English, + sdk.GetConfig().GetFullBIP44Path(), + keyring.DefaultBIP39Passphrase, + algo, + ) + } + if err != nil { + return sdk.AccAddress(""), "", err + } + + return info.GetAddress(), secret, nil +} diff --git a/server/init_test.go b/testutil/key_test.go similarity index 74% rename from server/init_test.go rename to testutil/key_test.go index b8b9d1c428..709b3f7793 100644 --- a/server/init_test.go +++ b/testutil/key_test.go @@ -1,4 +1,4 @@ -package server_test +package testutil import ( "testing" @@ -7,19 +7,18 @@ import ( "github.com/line/lbm-sdk/crypto/hd" "github.com/line/lbm-sdk/crypto/keyring" - "github.com/line/lbm-sdk/server" "github.com/line/lbm-sdk/types" ) func TestGenerateCoinKey(t *testing.T) { t.Parallel() - addr, mnemonic, err := server.GenerateCoinKey(hd.Secp256k1) + addr, mnemonic, err := GenerateCoinKey(hd.Secp256k1) require.NoError(t, err) // Test creation info, err := keyring.NewInMemory().NewAccount("xxx", mnemonic, "", hd.NewFundraiserParams(0, types.GetConfig().GetCoinType(), 0).String(), hd.Secp256k1) require.NoError(t, err) - require.Equal(t, addr, info.GetAddress()) + require.Equal(t, types.BytesToAccAddress(addr.Bytes()), info.GetAddress()) } func TestGenerateSaveCoinKey(t *testing.T) { @@ -28,7 +27,7 @@ func TestGenerateSaveCoinKey(t *testing.T) { kb, err := keyring.New(t.Name(), "test", t.TempDir(), nil) require.NoError(t, err) - addr, mnemonic, err := server.GenerateSaveCoinKey(kb, "keyname", false, hd.Secp256k1) + addr, mnemonic, err := GenerateSaveCoinKey(kb, "keyname", "", false, hd.Secp256k1) require.NoError(t, err) // Test key was actually saved @@ -49,15 +48,15 @@ func TestGenerateSaveCoinKeyOverwriteFlag(t *testing.T) { require.NoError(t, err) keyname := "justakey" - addr1, _, err := server.GenerateSaveCoinKey(kb, keyname, false, hd.Secp256k1) + addr1, _, err := GenerateSaveCoinKey(kb, keyname, "", false, hd.Secp256k1) require.NoError(t, err) // Test overwrite with overwrite=false - _, _, err = server.GenerateSaveCoinKey(kb, keyname, false, hd.Secp256k1) + _, _, err = GenerateSaveCoinKey(kb, keyname, "", false, hd.Secp256k1) require.Error(t, err) // Test overwrite with overwrite=true - addr2, _, err := server.GenerateSaveCoinKey(kb, keyname, true, hd.Secp256k1) + addr2, _, err := GenerateSaveCoinKey(kb, keyname, "", true, hd.Secp256k1) require.NoError(t, err) require.NotEqual(t, addr1, addr2) diff --git a/testutil/network/network.go b/testutil/network/network.go index 978a832237..fae7423bba 100644 --- a/testutil/network/network.go +++ b/testutil/network/network.go @@ -7,6 +7,7 @@ import ( "errors" "fmt" "io/ioutil" + "net/http" "net/url" "os" "path/filepath" @@ -39,6 +40,7 @@ import ( "github.com/line/lbm-sdk/simapp" "github.com/line/lbm-sdk/simapp/params" storetypes "github.com/line/lbm-sdk/store/types" + "github.com/line/lbm-sdk/testutil" sdk "github.com/line/lbm-sdk/types" authtypes "github.com/line/lbm-sdk/x/auth/types" banktypes "github.com/line/lbm-sdk/x/bank/types" @@ -69,7 +71,7 @@ func NewAppConstructor(encodingCfg params.EncodingConfig) AppConstructor { // Config defines the necessary configuration used to bootstrap and start an // in-process local testing network. type Config struct { - Codec codec.Marshaler + Codec codec.Codec LegacyAmino *codec.LegacyAmino // TODO: Remove! InterfaceRegistry codectypes.InterfaceRegistry @@ -80,6 +82,7 @@ type Config struct { TimeoutCommit time.Duration // the consensus commitment timeout ChainID string // the network chain-id NumValidators int // the total number of validators to create and bond + Mnemonics []string // custom user-provided validator operator mnemonics BondDenom string // the staking bond denomination MinGasPrices string // the minimum gas prices each validator will accept AccountTokens sdk.Int // the amount of unique validator tokens (e.g. 1000node0) @@ -111,9 +114,9 @@ func DefaultConfig() Config { NumValidators: 4, BondDenom: sdk.DefaultBondDenom, MinGasPrices: fmt.Sprintf("0.000006%s", sdk.DefaultBondDenom), - AccountTokens: sdk.TokensFromConsensusPower(1000), - StakingTokens: sdk.TokensFromConsensusPower(500), - BondedTokens: sdk.TokensFromConsensusPower(100), + AccountTokens: sdk.TokensFromConsensusPower(1000, sdk.DefaultPowerReduction), + StakingTokens: sdk.TokensFromConsensusPower(500, sdk.DefaultPowerReduction), + BondedTokens: sdk.TokensFromConsensusPower(100, sdk.DefaultPowerReduction), PruningStrategy: storetypes.PruningOptionNothing, CleanupDir: true, SigningAlgo: string(hd.Secp256k1Type), @@ -158,9 +161,10 @@ type ( ValAddress sdk.ValAddress RPCClient ostclient.Client - tmNode *node.Node - api *api.Server - grpc *grpc.Server + tmNode *node.Node + api *api.Server + grpc *grpc.Server + grpcWeb *http.Server } ) @@ -213,6 +217,7 @@ func New(t *testing.T, cfg Config) *Network { apiAddr := "" tmCfg.RPC.ListenAddress = "" appCfg.GRPC.Enable = false + appCfg.GRPCWeb.Enable = false if i == 0 { apiListenAddr, _, err := server.FreeTCPAddr() require.NoError(t, err) @@ -230,6 +235,11 @@ func New(t *testing.T, cfg Config) *Network { require.NoError(t, err) appCfg.GRPC.Address = fmt.Sprintf("0.0.0.0:%s", grpcPort) appCfg.GRPC.Enable = true + + _, grpcWebPort, err := server.FreeTCPAddr() + require.NoError(t, err) + appCfg.GRPCWeb.Address = fmt.Sprintf("0.0.0.0:%s", grpcWebPort) + appCfg.GRPCWeb.Enable = true } logger := log.NewNopLogger() @@ -258,6 +268,7 @@ func New(t *testing.T, cfg Config) *Network { p2pAddr, _, err := server.FreeTCPAddr() require.NoError(t, err) + tmCfg.P2P.ListenAddress = p2pAddr tmCfg.P2P.AddrBookStrict = false tmCfg.P2P.AllowDuplicateIP = true @@ -274,7 +285,12 @@ func New(t *testing.T, cfg Config) *Network { algo, err := keyring.NewSigningAlgoFromString(cfg.SigningAlgo, keyringAlgos) require.NoError(t, err) - addr, secret, err := server.GenerateSaveCoinKey(kb, nodeDirName, true, algo) + var mnemonic string + if i < len(cfg.Mnemonics) { + mnemonic = cfg.Mnemonics[i] + } + + addr, secret, err := testutil.GenerateSaveCoinKey(kb, nodeDirName, mnemonic, true, algo) require.NoError(t, err) info := map[string]string{"secret": secret} @@ -339,7 +355,7 @@ func New(t *testing.T, cfg Config) *Network { WithHomeDir(tmCfg.RootDir). WithChainID(cfg.ChainID). WithInterfaceRegistry(cfg.InterfaceRegistry). - WithJSONMarshaler(cfg.Codec). + WithCodec(cfg.Codec). WithLegacyAmino(cfg.LegacyAmino). WithTxConfig(cfg.TxConfig). WithAccountRetriever(cfg.AccountRetriever) @@ -506,6 +522,9 @@ func (n *Network) Cleanup() { if v.grpc != nil { v.grpc.Stop() + if v.grpcWeb != nil { + _ = v.grpcWeb.Close() + } } } diff --git a/testutil/network/util.go b/testutil/network/util.go index 1bcf89a8aa..23ad2dc50e 100644 --- a/testutil/network/util.go +++ b/testutil/network/util.go @@ -16,6 +16,7 @@ import ( "github.com/line/lbm-sdk/server/api" servergrpc "github.com/line/lbm-sdk/server/grpc" + srvtypes "github.com/line/lbm-sdk/server/types" authtypes "github.com/line/lbm-sdk/x/auth/types" banktypes "github.com/line/lbm-sdk/x/bank/types" "github.com/line/lbm-sdk/x/genutil" @@ -27,6 +28,10 @@ func startInProcess(cfg Config, val *Validator) error { tmCfg := val.Ctx.Config tmCfg.Instrumentation.Prometheus = false + if err := val.AppConfig.ValidateBasic(); err != nil { + return err + } + nodeKey, err := p2p.LoadOrGenNodeKey(tmCfg.NodeKeyFile()) if err != nil { return err @@ -90,7 +95,7 @@ func startInProcess(cfg Config, val *Validator) error { select { case err := <-errCh: return err - case <-time.After(5 * time.Second): // assume server started successfully + case <-time.After(srvtypes.ServerStartTime): // assume server started successfully } val.api = apiSrv @@ -103,6 +108,13 @@ func startInProcess(cfg Config, val *Validator) error { } val.grpc = grpcSrv + + if val.AppConfig.GRPCWeb.Enable { + val.grpcWeb, err = servergrpc.StartGRPCWeb(grpcSrv, *val.AppConfig) + if err != nil { + return err + } + } } return nil @@ -154,14 +166,14 @@ func initGenFiles(cfg Config, genAccounts []authtypes.GenesisAccount, genBalance return err } - authGenState.Accounts = accounts + authGenState.Accounts = append(authGenState.Accounts, accounts...) cfg.GenesisState[authtypes.ModuleName] = cfg.Codec.MustMarshalJSON(&authGenState) // set the balances in the genesis state var bankGenState banktypes.GenesisState cfg.Codec.MustUnmarshalJSON(cfg.GenesisState[banktypes.ModuleName], &bankGenState) - bankGenState.Balances = genBalances + bankGenState.Balances = append(bankGenState.Balances, genBalances...) cfg.GenesisState[banktypes.ModuleName] = cfg.Codec.MustMarshalJSON(&bankGenState) appGenStateJSON, err := json.MarshalIndent(cfg.GenesisState, "", " ") diff --git a/testutil/known_values.go b/testutil/testdata/known_values.go similarity index 90% rename from testutil/known_values.go rename to testutil/testdata/known_values.go index a87ccd2af0..616a07e665 100644 --- a/testutil/known_values.go +++ b/testutil/testdata/known_values.go @@ -1,4 +1,4 @@ -package testutil +package testdata const ( // Tests expect a ledger device initialized to the following mnemonic diff --git a/testutil/testdata/query.proto b/testutil/testdata/query.proto index 31fd523da0..39851558c8 100644 --- a/testutil/testdata/query.proto +++ b/testutil/testdata/query.proto @@ -7,7 +7,7 @@ import "testdata.proto"; option go_package = "github.com/line/lbm-sdk/testutil/testdata"; // Query tests the protobuf Query service as defined in -// https://github.com/line/lbm-sdk/issues/5921. +// https://github.com/cosmos/cosmos-sdk/issues/5921. service Query { rpc Echo(EchoRequest) returns (EchoResponse); rpc SayHello(SayHelloRequest) returns (SayHelloResponse); diff --git a/testutil/testdata/tx.go b/testutil/testdata/tx.go index b889b11469..f6a642f16a 100644 --- a/testutil/testdata/tx.go +++ b/testutil/testdata/tx.go @@ -3,7 +3,10 @@ package testdata import ( "encoding/json" + "github.com/stretchr/testify/require" + "github.com/line/lbm-sdk/crypto/keys/secp256k1" + "github.com/line/lbm-sdk/crypto/keys/secp256r1" cryptotypes "github.com/line/lbm-sdk/crypto/types" sdk "github.com/line/lbm-sdk/types" ) @@ -16,6 +19,15 @@ func KeyTestPubAddr() (cryptotypes.PrivKey, cryptotypes.PubKey, sdk.AccAddress) return key, pub, addr } +// KeyTestPubAddr generates a new secp256r1 keypair. +func KeyTestPubAddrSecp256R1(require *require.Assertions) (cryptotypes.PrivKey, cryptotypes.PubKey, sdk.AccAddress) { + key, err := secp256r1.GenPrivKey() + require.NoError(err) + pub := key.PubKey() + addr := sdk.BytesToAccAddress(pub.Address()) + return key, pub, addr +} + // NewTestFeeAmount is a test fee amount. func NewTestFeeAmount() sdk.Coins { return sdk.NewCoins(sdk.NewInt64Coin("atom", 150)) @@ -23,7 +35,7 @@ func NewTestFeeAmount() sdk.Coins { // NewTestGasLimit is a test fee gas limit. func NewTestGasLimit() uint64 { - return 100000 + return 200000 } // NewTestMsg creates a message for testing with the given signers. @@ -65,14 +77,7 @@ func (msg *TestMsg) GetSigners() []sdk.AccAddress { } func (msg *TestMsg) ValidateBasic() error { return nil } -var _ sdk.MsgRequest = &MsgCreateDog{} +var _ sdk.Msg = &MsgCreateDog{} func (msg *MsgCreateDog) GetSigners() []sdk.AccAddress { return []sdk.AccAddress{} } func (msg *MsgCreateDog) ValidateBasic() error { return nil } - -func NewServiceMsgCreateDog(msg *MsgCreateDog) sdk.Msg { - return sdk.ServiceMsg{ - MethodName: "/testdata.Msg/CreateDog", - Request: msg, - } -} diff --git a/testutil/testdata/tx.pb.go b/testutil/testdata/tx.pb.go index a499e3fd21..89a9343cbb 100644 --- a/testutil/testdata/tx.pb.go +++ b/testutil/testdata/tx.pb.go @@ -117,7 +117,7 @@ func (m *MsgCreateDogResponse) GetName() string { } // TestMsg is msg type for testing protobuf message using any, as defined in -// https://github.com/line/lbm-sdk/issues/6213. +// https://github.com/cosmos/cosmos-sdk/issues/6213. type TestMsg struct { Signers []string `protobuf:"bytes,1,rep,name=signers,proto3" json:"signers,omitempty"` } diff --git a/testutil/testdata/tx.proto b/testutil/testdata/tx.proto index 928c61d3d7..e38d96adcf 100644 --- a/testutil/testdata/tx.proto +++ b/testutil/testdata/tx.proto @@ -7,7 +7,7 @@ import "testdata.proto"; option go_package = "github.com/line/lbm-sdk/testutil/testdata"; // Msg tests the Protobuf message service as defined in -// https://github.com/line/lbm-sdk/issues/7500. +// https://github.com/cosmos/cosmos-sdk/issues/7500. service Msg { rpc CreateDog(MsgCreateDog) returns (MsgCreateDogResponse); } @@ -21,7 +21,7 @@ message MsgCreateDogResponse { } // TestMsg is msg type for testing protobuf message using any, as defined in -// https://github.com/line/lbm-sdk/issues/6213. +// https://github.com/cosmos/cosmos-sdk/issues/6213. message TestMsg { option (gogoproto.goproto_getters) = false; repeated string signers = 1; diff --git a/third_party/proto/google/protobuf/any.proto b/third_party/proto/google/protobuf/any.proto index 1431810ea4..58b511583a 100644 --- a/third_party/proto/google/protobuf/any.proto +++ b/third_party/proto/google/protobuf/any.proto @@ -156,6 +156,9 @@ message Any { bytes value = 2; option (gogoproto.typedecl) = false; + option (gogoproto.goproto_stringer) = false; + option (gogoproto.gostring) = false; + option (gogoproto.stringer) = false; } option (gogoproto.goproto_registration) = false; diff --git a/types/address.go b/types/address.go index 1ce6ea4768..6a2802ea84 100644 --- a/types/address.go +++ b/types/address.go @@ -12,7 +12,9 @@ import ( "github.com/line/lbm-sdk/codec/legacy" cryptotypes "github.com/line/lbm-sdk/crypto/types" + "github.com/line/lbm-sdk/types/address" "github.com/line/lbm-sdk/types/bech32" + sdkerrors "github.com/line/lbm-sdk/types/errors" ) const ( @@ -24,16 +26,17 @@ const ( // config.SetBech32PrefixForAccount(yourBech32PrefixAccAddr, yourBech32PrefixAccPub) // config.SetBech32PrefixForValidator(yourBech32PrefixValAddr, yourBech32PrefixValPub) // config.SetBech32PrefixForConsensusNode(yourBech32PrefixConsAddr, yourBech32PrefixConsPub) + // config.SetPurpose(yourPurpose) // config.SetCoinType(yourCoinType) - // config.SetFullFundraiserPath(yourFullFundraiserPath) // config.Seal() BytesAddrLen = 20 - //AddrLen = len(Bech32MainPrefix) + 1 + 38 - // Bech32MainPrefix defines the main SDK Bech32 prefix of an account's address Bech32MainPrefix = "link" + // Purpose is the LINK purpose as defined in SLIP44 (https://github.com/satoshilabs/slips/blob/master/slip-0044.md) + Purpose = 44 + // CoinType is the LINK coin type as defined in SLIP44 (https://github.com/satoshilabs/slips/blob/master/slip-0044.md) CoinType = 438 @@ -174,12 +177,15 @@ func VerifyAddressFormat(bz []byte) error { if verifier != nil { return verifier(bz) } - if len(bz) != BytesAddrLen { - if len(bz) == 0 { - return errors.New("empty address string is not allowed") - } - return fmt.Errorf("incorrect address length (expected: %d, actual: %d)", BytesAddrLen, len(bz)) + + if len(bz) == 0 { + return sdkerrors.Wrap(sdkerrors.ErrUnknownAddress, "addresses cannot be empty") } + + if len(bz) > address.MaxAddrLen { + return sdkerrors.Wrapf(sdkerrors.ErrUnknownAddress, "address max length is %d, got %d", address.MaxAddrLen, len(bz)) + } + return nil } @@ -625,6 +631,8 @@ func (ca ConsAddress) Format(s fmt.State, verb rune) { // auxiliary // ---------------------------------------------------------------------------- +var errBech32EmptyAddress = errors.New("decoding Bech32 address failed: must provide a non empty address") + // Bech32PubKeyType defines a string type alias for a Bech32 public key type. type Bech32PubKeyType string @@ -653,7 +661,7 @@ func Bech32ifyPubKey(pkt Bech32PubKeyType, pubkey cryptotypes.PubKey) (string, e } - return bech32.ConvertAndEncode(bech32Prefix, legacy.Cdc.MustMarshalBinaryBare(pubkey)) + return bech32.ConvertAndEncode(bech32Prefix, legacy.Cdc.MustMarshal(pubkey)) } // MustBech32ifyPubKey calls Bech32ifyPubKey except it panics on error. @@ -704,7 +712,7 @@ func MustGetPubKeyFromBech32(pkt Bech32PubKeyType, pubkeyStr string) cryptotypes // GetFromBech32 decodes a bytestring from a Bech32 encoded string. func GetFromBech32(bech32str, prefix string) ([]byte, error) { if len(bech32str) == 0 { - return nil, errors.New("decoding Bech32 address failed: must provide an address") + return nil, errBech32EmptyAddress } hrp, bz, err := bech32.DecodeAndConvert(bech32str) diff --git a/types/address/README.md b/types/address/README.md new file mode 100644 index 0000000000..2697548d6d --- /dev/null +++ b/types/address/README.md @@ -0,0 +1,7 @@ +# Account + +This package defines Cosmos SDK address-related functions. + +## References + ++ [ADR-028](../../docs/architecture/adr-028-public-key-addresses.md) diff --git a/types/address/hash.go b/types/address/hash.go new file mode 100644 index 0000000000..0cd397d2bf --- /dev/null +++ b/types/address/hash.go @@ -0,0 +1,71 @@ +package address + +import ( + "bytes" + "crypto/sha256" + "fmt" + "sort" + + "github.com/line/lbm-sdk/internal/conv" + "github.com/line/lbm-sdk/types/errors" +) + +// Len is the length of base addresses +const Len = sha256.Size + +// Addressable represents any type from which we can derive an address. +type Addressable interface { + Address() []byte +} + +// Hash creates a new address from address type and key +func Hash(typ string, key []byte) []byte { + hasher := sha256.New() + _, err := hasher.Write(conv.UnsafeStrToBytes(typ)) + // the error always nil, it's here only to satisfy the io.Writer interface + errors.AssertNil(err) + th := hasher.Sum(nil) + + hasher.Reset() + _, err = hasher.Write(th) + errors.AssertNil(err) + _, err = hasher.Write(key) + errors.AssertNil(err) + return hasher.Sum(nil) +} + +// Compose creates a new address based on sub addresses. +func Compose(typ string, subAddresses []Addressable) ([]byte, error) { + as := make([][]byte, len(subAddresses)) + totalLen := 0 + var err error + for i := range subAddresses { + a := subAddresses[i].Address() + as[i], err = LengthPrefix(a) + if err != nil { + return nil, fmt.Errorf("not compatible sub-adddress=%v at index=%d [%w]", a, i, err) + } + totalLen += len(as[i]) + } + + sort.Slice(as, func(i, j int) bool { return bytes.Compare(as[i], as[j]) <= 0 }) + key := make([]byte, totalLen) + offset := 0 + for i := range as { + copy(key[offset:], as[i]) + offset += len(as[i]) + } + return Hash(typ, key), nil +} + +// Module is a specialized version of a composed address for modules. Each module account +// is constructed from a module name and module account key. +func Module(moduleName string, key []byte) []byte { + mKey := append([]byte(moduleName), 0) + return Hash("module", append(mKey, key...)) +} + +// Derive derives a new address from the main `address` and a derivation `key`. +func Derive(address []byte, key []byte) []byte { + return Hash(conv.UnsafeBytesToStr(address), key) +} diff --git a/types/address/hash_test.go b/types/address/hash_test.go new file mode 100644 index 0000000000..ae712c18dd --- /dev/null +++ b/types/address/hash_test.go @@ -0,0 +1,105 @@ +package address + +import ( + "crypto/sha256" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/suite" +) + +func TestAddressSuite(t *testing.T) { + suite.Run(t, new(AddressSuite)) +} + +type AddressSuite struct{ suite.Suite } + +func (suite *AddressSuite) TestHash() { + assert := suite.Assert() + typ := "1" + key := []byte{1} + part1 := sha256.Sum256([]byte(typ)) + expected := sha256.Sum256(append(part1[:], key...)) + received := Hash(typ, key) + assert.Equal(expected[:], received, "must create a correct address") + + received = Hash("other", key) + assert.NotEqual(expected[:], received, "must create a correct address") + assert.Len(received, Len, "must have correct length") +} + +func (suite *AddressSuite) TestComposed() { + assert := suite.Assert() + a1 := addrMock{[]byte{11, 12}} + a2 := addrMock{[]byte{21, 22}} + + typ := "multisig" + ac, err := Compose(typ, []Addressable{a1, a2}) + assert.NoError(err) + assert.Len(ac, Len) + + // check if optimizations work + checkingKey := append([]byte{}, a1.AddressWithLen(suite.T())...) + checkingKey = append(checkingKey, a2.AddressWithLen(suite.T())...) + ac2 := Hash(typ, checkingKey) + assert.Equal(ac, ac2, "NewComposed works correctly") + + // changing order of addresses shouldn't impact a composed address + ac2, err = Compose(typ, []Addressable{a2, a1}) + assert.NoError(err) + assert.Len(ac2, Len) + assert.Equal(ac, ac2, "NewComposed is not sensitive for order") + + // changing a type should change composed address + ac2, err = Compose(typ+"other", []Addressable{a2, a1}) + assert.NoError(err) + assert.NotEqual(ac, ac2, "NewComposed must be sensitive to type") + + // changing order of addresses shouldn't impact a composed address + ac2, err = Compose(typ, []Addressable{a1, addrMock{make([]byte, 300, 300)}}) + assert.Error(err) + assert.Contains(err.Error(), "should be max 255 bytes, got 300") +} + +func (suite *AddressSuite) TestModule() { + assert := suite.Assert() + var modName, key = "myModule", []byte{1, 2} + addr := Module(modName, key) + assert.Len(addr, Len, "must have address length") + + addr2 := Module("myModule2", key) + assert.NotEqual(addr, addr2, "changing module name must change address") + + addr3 := Module(modName, []byte{1, 2, 3}) + assert.NotEqual(addr, addr3, "changing key must change address") + assert.NotEqual(addr2, addr3, "changing key must change address") +} + +func (suite *AddressSuite) TestDerive() { + assert := suite.Assert() + var addr, key1, key2 = []byte{1, 2}, []byte{3, 4}, []byte{1, 2} + d1 := Derive(addr, key1) + d2 := Derive(addr, key2) + d3 := Derive(key1, key2) + assert.Len(d1, Len) + assert.Len(d2, Len) + assert.Len(d3, Len) + + assert.NotEqual(d1, d2) + assert.NotEqual(d1, d3) + assert.NotEqual(d2, d3) +} + +type addrMock struct { + Addr []byte +} + +func (a addrMock) Address() []byte { + return a.Addr +} + +func (a addrMock) AddressWithLen(t *testing.T) []byte { + addr, err := LengthPrefix(a.Addr) + assert.NoError(t, err) + return addr +} diff --git a/types/address_race_test.go b/types/address_race_test.go new file mode 100644 index 0000000000..bc66319158 --- /dev/null +++ b/types/address_race_test.go @@ -0,0 +1,55 @@ +package types_test + +import ( + "encoding/binary" + "fmt" + "testing" + "time" + + sdk "github.com/line/lbm-sdk/types" + "github.com/stretchr/testify/require" +) + +// generates AccAddress with `prefix` and calls String method +func addressStringCaller(require *require.Assertions, prefix byte, max uint32, cancel chan bool, done chan<- bool) { + bz := make([]byte, 5) // prefix + 4 bytes for uint + bz[0] = prefix + for i := uint32(0); ; i++ { + if i >= max { + i = 0 + } + select { + case <-cancel: + done <- true + return + default: + binary.BigEndian.PutUint32(bz[1:], i) + str := sdk.BytesToAccAddress(bz).String() + require.True(str != "") + } + + } +} + +func (s *addressTestSuite) TestAddressRace() { + fmt.Println("starting test") + if testing.Short() { + s.T().Skip("AddressRace test is not short") + } + workers := 4 + done := make(chan bool, workers) + cancel := make(chan bool) + for i := byte(1); i <= 2; i++ { // workes which will loop in first 100 addresses + go addressStringCaller(s.Require(), i, 100, cancel, done) + } + for i := byte(1); i <= 2; i++ { // workes which will generate 1e6 new addresses + go addressStringCaller(s.Require(), i, 1000000, cancel, done) + } + <-time.After(time.Millisecond * 30) + close(cancel) + + // cleanup + for i := 0; i < 4; i++ { + <-done + } +} diff --git a/types/address_test.go b/types/address_test.go index 2a8f2fb145..7fe8dedeb6 100644 --- a/types/address_test.go +++ b/types/address_test.go @@ -15,7 +15,8 @@ import ( "github.com/line/lbm-sdk/crypto/keys/ed25519" "github.com/line/lbm-sdk/crypto/keys/secp256k1" cryptotypes "github.com/line/lbm-sdk/crypto/types" - "github.com/line/lbm-sdk/types" + sdk "github.com/line/lbm-sdk/types" + legacybech32 "github.com/line/lbm-sdk/types/bech32/legacybech32" ) type addressTestSuite struct { @@ -34,12 +35,12 @@ var invalidStrs = []string{ "hello, world!", "0xAA", "AAA", - types.Bech32PrefixAccAddr + "AB0C", - types.Bech32PrefixAccPub + "1234", - types.Bech32PrefixValAddr + "5678", - types.Bech32PrefixValPub + "BBAB", - types.Bech32PrefixConsAddr + "FF04", - types.Bech32PrefixConsPub + "6789", + sdk.Bech32PrefixAccAddr + "AB0C", + sdk.Bech32PrefixAccPub + "1234", + sdk.Bech32PrefixValAddr + "5678", + sdk.Bech32PrefixValPub + "BBAB", + sdk.Bech32PrefixConsAddr + "FF04", + sdk.Bech32PrefixConsPub + "6789", } func (s *addressTestSuite) testMarshal(original interface{}, res interface{}, marshal func() ([]byte, error), unmarshal func([]byte) error) { @@ -49,54 +50,34 @@ func (s *addressTestSuite) testMarshal(original interface{}, res interface{}, ma s.Require().Equal(original, res) } -func (s *addressTestSuite) TestRandBech32PubkeyConsistency() { - pubBz := make([]byte, ed25519.PubKeySize) - pub := &ed25519.PubKey{Key: pubBz} - - for i := 0; i < 1000; i++ { - rand.Read(pub.Key) - - mustBech32AccPub := types.MustBech32ifyPubKey(types.Bech32PubKeyTypeAccPub, pub) - bech32AccPub, err := types.Bech32ifyPubKey(types.Bech32PubKeyTypeAccPub, pub) - s.Require().Nil(err) - s.Require().Equal(bech32AccPub, mustBech32AccPub) - - mustBech32ValPub := types.MustBech32ifyPubKey(types.Bech32PubKeyTypeValPub, pub) - bech32ValPub, err := types.Bech32ifyPubKey(types.Bech32PubKeyTypeValPub, pub) - s.Require().Nil(err) - s.Require().Equal(bech32ValPub, mustBech32ValPub) - - mustBech32ConsPub := types.MustBech32ifyPubKey(types.Bech32PubKeyTypeConsPub, pub) - bech32ConsPub, err := types.Bech32ifyPubKey(types.Bech32PubKeyTypeConsPub, pub) - s.Require().Nil(err) - s.Require().Equal(bech32ConsPub, mustBech32ConsPub) - - mustAccPub := types.MustGetPubKeyFromBech32(types.Bech32PubKeyTypeAccPub, bech32AccPub) - accPub, err := types.GetPubKeyFromBech32(types.Bech32PubKeyTypeAccPub, bech32AccPub) - s.Require().Nil(err) - s.Require().Equal(accPub, mustAccPub) +func (s *addressTestSuite) TestEmptyAddresses() { + s.T().Parallel() + s.Require().Equal(sdk.AccAddress("").String(), "") + s.Require().Equal(sdk.ValAddress("").String(), "") + s.Require().Equal(sdk.ConsAddress("").String(), "") - mustValPub := types.MustGetPubKeyFromBech32(types.Bech32PubKeyTypeValPub, bech32ValPub) - valPub, err := types.GetPubKeyFromBech32(types.Bech32PubKeyTypeValPub, bech32ValPub) - s.Require().Nil(err) - s.Require().Equal(valPub, mustValPub) + accAddr := sdk.AccAddress("") + s.Require().True(accAddr.Empty()) + err := sdk.ValidateAccAddress(accAddr.String()) + s.Require().Error(err) - mustConsPub := types.MustGetPubKeyFromBech32(types.Bech32PubKeyTypeConsPub, bech32ConsPub) - consPub, err := types.GetPubKeyFromBech32(types.Bech32PubKeyTypeConsPub, bech32ConsPub) - s.Require().Nil(err) - s.Require().Equal(consPub, mustConsPub) + valAddr := sdk.ValAddress("") + s.Require().True(valAddr.Empty()) + err = sdk.ValidateValAddress(valAddr.String()) + s.Require().Error(err) - s.Require().Equal(valPub, accPub) - s.Require().Equal(valPub, consPub) - } + consAddr := sdk.ConsAddress("") + s.Require().True(consAddr.Empty()) + err = sdk.ValidateConsAddress(consAddr.String()) + s.Require().Error(err) } func (s *addressTestSuite) TestYAMLMarshalers() { addr := secp256k1.GenPrivKey().PubKey().Address() - acc := types.BytesToAccAddress(addr) - val := types.BytesToValAddress(addr) - cons := types.BytesToConsAddress(addr) + acc := sdk.BytesToAccAddress(addr) + val := sdk.BytesToValAddress(addr) + cons := sdk.BytesToConsAddress(addr) got, _ := yaml.Marshal(&acc) s.Require().Equal(acc.String()+"\n", string(got)) @@ -115,38 +96,38 @@ func (s *addressTestSuite) TestRandBech32AccAddrConsistency() { for i := 0; i < 1000; i++ { rand.Read(pub.Key) - acc := types.BytesToAccAddress(pub.Address()) - res := types.AccAddress("") + acc := sdk.BytesToAccAddress(pub.Address()) + res := sdk.AccAddress("") s.testMarshal(&acc, &res, acc.MarshalJSON, (&res).UnmarshalJSON) s.testMarshal(&acc, &res, acc.Marshal, (&res).Unmarshal) str := acc.String() - err := types.ValidateAccAddress(str) + err := sdk.ValidateAccAddress(str) s.Require().Nil(err) - s.Require().Equal(acc, types.AccAddress(str)) + s.Require().Equal(acc, sdk.AccAddress(str)) - bytes, err := types.AccAddressToBytes(acc.String()) + bytes, err := sdk.AccAddressToBytes(acc.String()) s.Require().NoError(err) str = hex.EncodeToString(bytes) - res, err = types.AccAddressFromHex(str) + res, err = sdk.AccAddressFromHex(str) s.Require().Nil(err) s.Require().Equal(acc, res) } for _, str := range invalidStrs { - _, err := types.AccAddressFromHex(str) + _, err := sdk.AccAddressFromHex(str) s.Require().NotNil(err) - err = types.ValidateAccAddress(str) + err = sdk.ValidateAccAddress(str) s.Require().NotNil(err) - addr := types.AccAddress("") + addr := sdk.AccAddress("") err = (&addr).UnmarshalJSON([]byte("\"" + str + "\"")) s.Require().Nil(err) } - _, err := types.AccAddressFromHex("") + _, err := sdk.AccAddressFromHex("") s.Require().Equal("decoding Bech32 address failed: must provide an address", err.Error()) } @@ -157,39 +138,39 @@ func (s *addressTestSuite) TestValAddr() { for i := 0; i < 20; i++ { rand.Read(pub.Key) - acc := types.BytesToValAddress(pub.Address()) - res := types.ValAddress("") + acc := sdk.BytesToValAddress(pub.Address()) + res := sdk.ValAddress("") s.testMarshal(&acc, &res, acc.MarshalJSON, (&res).UnmarshalJSON) s.testMarshal(&acc, &res, acc.Marshal, (&res).Unmarshal) str := acc.String() - res2, err := types.ValAddressToBytes(str) + res2, err := sdk.ValAddressToBytes(str) s.Require().Nil(err) - s.Require().Equal(acc, types.BytesToValAddress(res2)) + s.Require().Equal(acc, sdk.BytesToValAddress(res2)) - bytes, _ := types.ValAddressToBytes(acc.String()) + bytes, _ := sdk.ValAddressToBytes(acc.String()) str = hex.EncodeToString(bytes) - res, err = types.ValAddressFromHex(str) + res, err = sdk.ValAddressFromHex(str) s.Require().Nil(err) s.Require().Equal(acc, res) } for _, str := range invalidStrs { - _, err := types.ValAddressFromHex(str) + _, err := sdk.ValAddressFromHex(str) s.Require().NotNil(err) - err = types.ValidateValAddress(str) + err = sdk.ValidateValAddress(str) s.Require().NotNil(err) - addr := types.ValAddress("") + addr := sdk.ValAddress("") err = (&addr).UnmarshalJSON([]byte("\"" + str + "\"")) s.Require().Nil(err) } // test empty string - _, err := types.ValAddressFromHex("") + _, err := sdk.ValAddressFromHex("") s.Require().Equal("decoding Bech32 address failed: must provide an address", err.Error()) } @@ -200,38 +181,38 @@ func (s *addressTestSuite) TestConsAddress() { for i := 0; i < 20; i++ { rand.Read(pub.Key[:]) - acc := types.BytesToConsAddress(pub.Address()) - res := types.ConsAddress("") + acc := sdk.BytesToConsAddress(pub.Address()) + res := sdk.ConsAddress("") s.testMarshal(&acc, &res, acc.MarshalJSON, (&res).UnmarshalJSON) s.testMarshal(&acc, &res, acc.Marshal, (&res).Unmarshal) str := acc.String() - res2, err := types.ConsAddressToBytes(str) + res2, err := sdk.ConsAddressToBytes(str) s.Require().Nil(err) - s.Require().Equal(acc, types.BytesToConsAddress(res2)) + s.Require().Equal(acc, sdk.BytesToConsAddress(res2)) - bytes, _ := types.ConsAddressToBytes(acc.String()) + bytes, _ := sdk.ConsAddressToBytes(acc.String()) str = hex.EncodeToString(bytes) - res, err = types.ConsAddressFromHex(str) + res, err = sdk.ConsAddressFromHex(str) s.Require().Nil(err) s.Require().Equal(acc, res) } for _, str := range invalidStrs { - _, err := types.ConsAddressFromHex(str) + _, err := sdk.ConsAddressFromHex(str) s.Require().NotNil(err) - err = types.ValidateConsAddress(str) + err = sdk.ValidateConsAddress(str) s.Require().NotNil(err) - consAddr := types.ConsAddress("") + consAddr := sdk.ConsAddress("") err = (&consAddr).UnmarshalJSON([]byte("\"" + str + "\"")) s.Require().Nil(err) } // test empty string - _, err := types.ConsAddressFromHex("") + _, err := sdk.ConsAddressFromHex("") s.Require().Equal("decoding Bech32 address failed: must provide an address", err.Error()) } @@ -255,48 +236,48 @@ func (s *addressTestSuite) TestConfiguredPrefix() { prefix := RandString(length) // Assuming that GetConfig is not sealed. - config := types.GetConfig() + config := sdk.GetConfig() config.SetBech32PrefixForAccount( - prefix+types.PrefixAccount, - prefix+types.PrefixPublic) + prefix+sdk.PrefixAccount, + prefix+sdk.PrefixPublic) - acc := types.BytesToAccAddress(pub.Address()) + acc := sdk.BytesToAccAddress(pub.Address()) s.Require().True(strings.HasPrefix( acc.String(), - prefix+types.PrefixAccount), acc.String()) + prefix+sdk.PrefixAccount), acc.String()) - bech32Pub := types.MustBech32ifyPubKey(types.Bech32PubKeyTypeAccPub, pub) + bech32Pub := legacybech32.MustMarshalPubKey(legacybech32.AccPK, pub) s.Require().True(strings.HasPrefix( bech32Pub, - prefix+types.PrefixPublic)) + prefix+sdk.PrefixPublic)) config.SetBech32PrefixForValidator( - prefix+types.PrefixValidator+types.PrefixAddress, - prefix+types.PrefixValidator+types.PrefixPublic) + prefix+sdk.PrefixValidator+sdk.PrefixAddress, + prefix+sdk.PrefixValidator+sdk.PrefixPublic) - val := types.BytesToValAddress(pub.Address()) + val := sdk.BytesToValAddress(pub.Address()) s.Require().True(strings.HasPrefix( val.String(), - prefix+types.PrefixValidator+types.PrefixAddress)) + prefix+sdk.PrefixValidator+sdk.PrefixAddress)) - bech32ValPub := types.MustBech32ifyPubKey(types.Bech32PubKeyTypeValPub, pub) + bech32ValPub := legacybech32.MustMarshalPubKey(legacybech32.ValPK, pub) s.Require().True(strings.HasPrefix( bech32ValPub, - prefix+types.PrefixValidator+types.PrefixPublic)) + prefix+sdk.PrefixValidator+sdk.PrefixPublic)) config.SetBech32PrefixForConsensusNode( - prefix+types.PrefixConsensus+types.PrefixAddress, - prefix+types.PrefixConsensus+types.PrefixPublic) + prefix+sdk.PrefixConsensus+sdk.PrefixAddress, + prefix+sdk.PrefixConsensus+sdk.PrefixPublic) - cons := types.BytesToConsAddress(pub.Address()) + cons := sdk.BytesToConsAddress(pub.Address()) s.Require().True(strings.HasPrefix( cons.String(), - prefix+types.PrefixConsensus+types.PrefixAddress)) + prefix+sdk.PrefixConsensus+sdk.PrefixAddress)) - bech32ConsPub := types.MustBech32ifyPubKey(types.Bech32PubKeyTypeConsPub, pub) + bech32ConsPub := legacybech32.MustMarshalPubKey(legacybech32.ConsPK, pub) s.Require().True(strings.HasPrefix( bech32ConsPub, - prefix+types.PrefixConsensus+types.PrefixPublic)) + prefix+sdk.PrefixConsensus+sdk.PrefixPublic)) } } } @@ -306,22 +287,22 @@ func (s *addressTestSuite) TestAddressInterface() { pub := &ed25519.PubKey{Key: pubBz} rand.Read(pub.Key) - addrs := []types.Address{ - types.BytesToConsAddress(pub.Address()), - types.BytesToValAddress(pub.Address()), - types.BytesToAccAddress(pub.Address()), + addrs := []sdk.Address{ + sdk.BytesToConsAddress(pub.Address()), + sdk.BytesToValAddress(pub.Address()), + sdk.BytesToAccAddress(pub.Address()), } for _, addr := range addrs { switch addr := addr.(type) { - case types.AccAddress: - err := types.ValidateAccAddress(addr.String()) + case sdk.AccAddress: + err := sdk.ValidateAccAddress(addr.String()) s.Require().Nil(err) - case types.ValAddress: - err := types.ValidateValAddress(addr.String()) + case sdk.ValAddress: + err := sdk.ValidateValAddress(addr.String()) s.Require().Nil(err) - case types.ConsAddress: - err := types.ValidateConsAddress(addr.String()) + case sdk.ConsAddress: + err := sdk.ValidateConsAddress(addr.String()) s.Require().Nil(err) default: s.T().Fail() @@ -335,54 +316,57 @@ func (s *addressTestSuite) TestVerifyAddressFormat() { addr5 := make([]byte, 5) addr20 := make([]byte, 20) addr32 := make([]byte, 32) - - err := types.VerifyAddressFormat(addr0) - s.Require().EqualError(err, "incorrect address length 0") - err = types.VerifyAddressFormat(addr5) - s.Require().EqualError(err, "incorrect address length 5") - err = types.VerifyAddressFormat(addr20) - s.Require().Nil(err) - err = types.VerifyAddressFormat(addr32) - s.Require().EqualError(err, "incorrect address length 32") + addr256 := make([]byte, 256) + + err := sdk.VerifyAddressFormat(addr0) + s.Require().EqualError(err, "addresses cannot be empty: unknown address") + err = sdk.VerifyAddressFormat(addr5) + s.Require().NoError(err) + err = sdk.VerifyAddressFormat(addr20) + s.Require().NoError(err) + err = sdk.VerifyAddressFormat(addr32) + s.Require().NoError(err) + err = sdk.VerifyAddressFormat(addr256) + s.Require().EqualError(err, "address max length is 255, got 256: unknown address") } func (s *addressTestSuite) TestCustomAddressVerifier() { // Create a 10 byte address addr := []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9} - accBech := types.BytesToAccAddress(addr).String() - valBech := types.BytesToValAddress(addr).String() - consBech := types.BytesToConsAddress(addr).String() + accBech := sdk.BytesToAccAddress(addr).String() + valBech := sdk.BytesToValAddress(addr).String() + consBech := sdk.BytesToConsAddress(addr).String() // Verifiy that the default logic rejects this 10 byte address - err := types.VerifyAddressFormat(addr) - s.Require().NotNil(err) - err = types.ValidateAccAddress(accBech) - if err == nil { - fmt.Printf("\n") - } - s.Require().NotNil(err) - err = types.ValidateValAddress(valBech) - s.Require().NotNil(err) - err = types.ValidateConsAddress(consBech) - s.Require().NotNil(err) + err := sdk.VerifyAddressFormat(addr) + s.Require().Nil(err) + err = sdk.ValidateAccAddress(accBech) + s.Require().Nil(err) + err = sdk.ValidateValAddress(valBech) + s.Require().Nil(err) + err = sdk.ValidateConsAddress(consBech) + s.Require().Nil(err) - // Set a custom address verifier that accepts 10 or 20 byte addresses - types.GetConfig().SetAddressVerifier(func(bz []byte) error { + // Set a custom address verifier only accepts 20 byte addresses + sdk.GetConfig().SetAddressVerifier(func(bz []byte) error { n := len(bz) - if n == 10 || n == types.BytesAddrLen { + if n == sdk.BytesAddrLen { return nil } return fmt.Errorf("incorrect address length %d", n) }) - // Verifiy that the custom logic accepts this 10 byte address - err = types.VerifyAddressFormat(addr) - s.Require().Nil(err) - err = types.ValidateAccAddress(accBech) - s.Require().Nil(err) - err = types.ValidateValAddress(valBech) - s.Require().Nil(err) - err = types.ValidateConsAddress(consBech) - s.Require().Nil(err) + // Verifiy that the custom logic rejects this 10 byte address + err = sdk.VerifyAddressFormat(addr) + s.Require().NotNil(err) + err = sdk.ValidateAccAddress(accBech) + s.Require().NotNil(err) + err = sdk.ValidateValAddress(valBech) + s.Require().NotNil(err) + err = sdk.ValidateConsAddress(consBech) + s.Require().NotNil(err) + + // Reinitialize the global config to default address verifier (nil) + sdk.GetConfig().SetAddressVerifier(nil) } func (s *addressTestSuite) TestBech32ifyAddressBytes() { @@ -408,7 +392,7 @@ func (s *addressTestSuite) TestBech32ifyAddressBytes() { for _, tt := range tests { tt := tt s.T().Run(tt.name, func(t *testing.T) { - got, err := types.Bech32ifyAddressBytes(tt.args.prefix, tt.args.bs) + got, err := sdk.Bech32ifyAddressBytes(tt.args.prefix, tt.args.bs) if (err != nil) != tt.wantErr { t.Errorf("Bech32ifyBytes() error = %v, wantErr %v", err, tt.wantErr) return @@ -442,24 +426,24 @@ func (s *addressTestSuite) TestMustBech32ifyAddressBytes() { tt := tt s.T().Run(tt.name, func(t *testing.T) { if tt.wantPanic { - require.Panics(t, func() { types.MustBech32ifyAddressBytes(tt.args.prefix, tt.args.bs) }) + require.Panics(t, func() { sdk.MustBech32ifyAddressBytes(tt.args.prefix, tt.args.bs) }) return } - require.Equal(t, tt.want, types.MustBech32ifyAddressBytes(tt.args.prefix, tt.args.bs)) + require.Equal(t, tt.want, sdk.MustBech32ifyAddressBytes(tt.args.prefix, tt.args.bs)) }) } } func (s *addressTestSuite) TestAddressTypesEquals() { addr1 := secp256k1.GenPrivKey().PubKey().Address() - accAddr1 := types.BytesToAccAddress(addr1) - consAddr1 := types.BytesToConsAddress(addr1) - valAddr1 := types.BytesToValAddress(addr1) + accAddr1 := sdk.BytesToAccAddress(addr1) + consAddr1 := sdk.BytesToConsAddress(addr1) + valAddr1 := sdk.BytesToValAddress(addr1) addr2 := secp256k1.GenPrivKey().PubKey().Address() - accAddr2 := types.BytesToAccAddress(addr2) - consAddr2 := types.BytesToConsAddress(addr2) - valAddr2 := types.BytesToValAddress(addr2) + accAddr2 := sdk.BytesToAccAddress(addr2) + consAddr2 := sdk.BytesToConsAddress(addr2) + valAddr2 := sdk.BytesToValAddress(addr2) // equality s.Require().True(accAddr1.Equals(accAddr1)) @@ -467,9 +451,9 @@ func (s *addressTestSuite) TestAddressTypesEquals() { s.Require().True(valAddr1.Equals(valAddr1)) // emptiness - s.Require().True(types.AccAddress("").Equals(types.AccAddress(""))) - s.Require().True(types.ConsAddress("").Equals(types.ConsAddress(""))) - s.Require().True(types.ValAddress("").Equals(types.ValAddress(""))) + s.Require().True(sdk.AccAddress("").Equals(sdk.AccAddress(""))) + s.Require().True(sdk.ConsAddress("").Equals(sdk.ConsAddress(""))) + s.Require().True(sdk.ValAddress("").Equals(sdk.ValAddress(""))) s.Require().False(accAddr1.Equals(accAddr2)) s.Require().Equal(accAddr1.Equals(accAddr2), accAddr2.Equals(accAddr1)) @@ -480,26 +464,26 @@ func (s *addressTestSuite) TestAddressTypesEquals() { } func (s *addressTestSuite) TestNilAddressTypesEmpty() { - s.Require().True(types.AccAddress("").Empty()) - s.Require().True(types.ConsAddress("").Empty()) - s.Require().True(types.ValAddress("").Empty()) + s.Require().True(sdk.AccAddress("").Empty()) + s.Require().True(sdk.ConsAddress("").Empty()) + s.Require().True(sdk.ValAddress("").Empty()) } func (s *addressTestSuite) TestGetConsAddress() { pk := secp256k1.GenPrivKey().PubKey() - s.Require().NotEqual(types.GetConsAddress(pk), pk.Address()) - consBytes, _ := types.ConsAddressToBytes(types.GetConsAddress(pk).String()) + s.Require().NotEqual(sdk.GetConsAddress(pk), pk.Address()) + consBytes, _ := sdk.ConsAddressToBytes(sdk.GetConsAddress(pk).String()) s.Require().True(bytes.Equal(consBytes, pk.Address())) - s.Require().Panics(func() { types.GetConsAddress(cryptotypes.PubKey(nil)) }) + s.Require().Panics(func() { sdk.GetConsAddress(cryptotypes.PubKey(nil)) }) } func (s *addressTestSuite) TestGetFromBech32() { - _, err := types.GetFromBech32("", "prefix") + _, err := sdk.GetFromBech32("", "prefix") s.Require().Error(err) - s.Require().Equal("decoding Bech32 address failed: must provide an address", err.Error()) - _, err = types.GetFromBech32("cosmos1qqqsyqcyq5rqwzqfys8f67", "x") + s.Require().Equal("decoding Bech32 address failed: must provide a non empty address", err.Error()) + _, err = sdk.GetFromBech32("link1qqqsyqcyq5rqwzqf97tnae", "x") s.Require().Error(err) - s.Require().Equal("invalid Bech32 prefix; expected x, got cosmos", err.Error()) + s.Require().Equal("invalid Bech32 prefix; expected x, got link", err.Error()) } func (s *addressTestSuite) TestBech32Cache() { @@ -509,28 +493,28 @@ func (s *addressTestSuite) TestBech32Cache() { s.T().Log("access bech32ToAddrCache before access addrToBech32Cache") { rand.Read(pub.Key) - addr := types.BytesToAccAddress(pub.Address()) + addr := sdk.BytesToAccAddress(pub.Address()) bech32Addr := addr.String() - types.SetBech32Cache(types.DefaultBech32CacheSize) + sdk.SetBech32Cache(sdk.DefaultBech32CacheSize) - rawAddr, err := types.AccAddressToBytes(bech32Addr) + rawAddr, err := sdk.AccAddressToBytes(bech32Addr) s.Require().Nil(err) - require.Equal(s.T(), addr, types.BytesToAccAddress(rawAddr)) + require.Equal(s.T(), addr, sdk.BytesToAccAddress(rawAddr)) require.Equal(s.T(), bech32Addr, addr.String()) } s.T().Log("access addrToBech32Cache before access bech32ToAddrCache") { rand.Read(pub.Key) - addr := types.BytesToAccAddress(pub.Address()) + addr := sdk.BytesToAccAddress(pub.Address()) bech32Addr := addr.String() - types.SetBech32Cache(types.DefaultBech32CacheSize) + sdk.SetBech32Cache(sdk.DefaultBech32CacheSize) require.Equal(s.T(), bech32Addr, addr.String()) - rawAddr, err := types.AccAddressToBytes(bech32Addr) + rawAddr, err := sdk.AccAddressToBytes(bech32Addr) s.Require().Nil(err) - require.Equal(s.T(), addr, types.BytesToAccAddress(rawAddr)) + require.Equal(s.T(), addr, sdk.BytesToAccAddress(rawAddr)) } - types.InvalidateBech32Cache() + sdk.InvalidateBech32Cache() } diff --git a/types/bech32/legacybech32/pk.go b/types/bech32/legacybech32/pk.go new file mode 100644 index 0000000000..d3d87b47ba --- /dev/null +++ b/types/bech32/legacybech32/pk.go @@ -0,0 +1,68 @@ +// Deprecated: The module provides legacy bech32 functions which will be removed in a future +// release. +package legacybech32 + +import ( + "github.com/line/lbm-sdk/codec/legacy" + cryptotypes "github.com/line/lbm-sdk/crypto/types" + sdk "github.com/line/lbm-sdk/types" + "github.com/line/lbm-sdk/types/bech32" +) + +// TODO: when removing this package remove: +// + sdk:config.GetBech32AccountPubPrefix (and other related functions) +// + Bech32PrefixAccAddr and other related constants + +// Deprecated: Bech32PubKeyType defines a string type alias for a Bech32 public key type. +type Bech32PubKeyType string + +// Bech32 conversion constants +const ( + AccPK Bech32PubKeyType = "accpub" + ValPK Bech32PubKeyType = "valpub" + ConsPK Bech32PubKeyType = "conspub" +) + +// Deprecated: MarshalPubKey returns a Bech32 encoded string containing the appropriate +// prefix based on the key type provided for a given PublicKey. +func MarshalPubKey(pkt Bech32PubKeyType, pubkey cryptotypes.PubKey) (string, error) { + bech32Prefix := getPrefix(pkt) + return bech32.ConvertAndEncode(bech32Prefix, legacy.Cdc.MustMarshal(pubkey)) +} + +// Deprecated: MustMarshalPubKey calls MarshalPubKey and panics on error. +func MustMarshalPubKey(pkt Bech32PubKeyType, pubkey cryptotypes.PubKey) string { + res, err := MarshalPubKey(pkt, pubkey) + if err != nil { + panic(err) + } + + return res +} + +func getPrefix(pkt Bech32PubKeyType) string { + cfg := sdk.GetConfig() + switch pkt { + case AccPK: + return cfg.GetBech32AccountPubPrefix() + + case ValPK: + return cfg.GetBech32ValidatorPubPrefix() + case ConsPK: + return cfg.GetBech32ConsensusPubPrefix() + } + + return "" +} + +// Deprecated: UnmarshalPubKey returns a PublicKey from a bech32-encoded PublicKey with +// a given key type. +func UnmarshalPubKey(pkt Bech32PubKeyType, pubkeyStr string) (cryptotypes.PubKey, error) { + bech32Prefix := getPrefix(pkt) + + bz, err := sdk.GetFromBech32(pubkeyStr, bech32Prefix) + if err != nil { + return nil, err + } + return legacy.PubKeyFromBytes(bz) +} diff --git a/types/address_bench_test.go b/types/bech32/legacybech32/pk_bench_test.go similarity index 74% rename from types/address_bench_test.go rename to types/bech32/legacybech32/pk_bench_test.go index 3098fc1656..cb10e7b01b 100644 --- a/types/address_bench_test.go +++ b/types/bech32/legacybech32/pk_bench_test.go @@ -1,4 +1,4 @@ -package types_test +package legacybech32 import ( "math/rand" @@ -8,10 +8,10 @@ import ( "github.com/stretchr/testify/require" "github.com/line/lbm-sdk/crypto/keys/ed25519" - "github.com/line/lbm-sdk/types" ) func BenchmarkBech32ifyPubKey(b *testing.B) { + b.ReportAllocs() pkBz := make([]byte, ed25519.PubKeySize) pk := &ed25519.PubKey{Key: pkBz} rng := rand.New(rand.NewSource(time.Now().Unix())) @@ -23,12 +23,13 @@ func BenchmarkBech32ifyPubKey(b *testing.B) { rng.Read(pk.Key) b.StartTimer() - _, err := types.Bech32ifyPubKey(types.Bech32PubKeyTypeConsPub, pk) + _, err := MarshalPubKey(ConsPK, pk) require.NoError(b, err) } } func BenchmarkGetPubKeyFromBech32(b *testing.B) { + b.ReportAllocs() pkBz := make([]byte, ed25519.PubKeySize) pk := &ed25519.PubKey{Key: pkBz} rng := rand.New(rand.NewSource(time.Now().Unix())) @@ -39,11 +40,11 @@ func BenchmarkGetPubKeyFromBech32(b *testing.B) { b.StopTimer() rng.Read(pk.Key) - pkStr, err := types.Bech32ifyPubKey(types.Bech32PubKeyTypeConsPub, pk) + pkStr, err := MarshalPubKey(ConsPK, pk) require.NoError(b, err) b.StartTimer() - pk2, err := types.GetPubKeyFromBech32(types.Bech32PubKeyTypeConsPub, pkStr) + pk2, err := UnmarshalPubKey(ConsPK, pkStr) require.NoError(b, err) require.Equal(b, pk, pk2) } diff --git a/types/bech32/legacybech32/pk_test.go b/types/bech32/legacybech32/pk_test.go new file mode 100644 index 0000000000..d07938f456 --- /dev/null +++ b/types/bech32/legacybech32/pk_test.go @@ -0,0 +1,26 @@ +package legacybech32 + +import ( + "testing" + + "github.com/stretchr/testify/require" + + "github.com/line/lbm-sdk/crypto/hd" + "github.com/line/lbm-sdk/crypto/ledger" + "github.com/line/lbm-sdk/testutil/testdata" + sdk "github.com/line/lbm-sdk/types" +) + +func TestBeach32ifPbKey(t *testing.T) { + require := require.New(t) + path := *hd.NewFundraiserParams(0, sdk.CoinType, 0) + priv, err := ledger.NewPrivKeySecp256k1Unsafe(path) + require.Nil(err, "%s", err) + require.NotNil(priv) + + pubKeyAddr, err := MarshalPubKey(AccPK, priv.PubKey()) + require.NoError(err) + require.Equal("linkpub1cqmsrdepq27djm9tzq3sftqsayx95refxk8r5jn0kyshhql9mdjhjx829zlvzygzwr2", + pubKeyAddr, "Is your device using test mnemonic: %s ?", testdata.TestMnemonic) + +} diff --git a/types/bench_test.go b/types/bench_test.go index ab726804c2..3f980f6ba6 100644 --- a/types/bench_test.go +++ b/types/bench_test.go @@ -28,3 +28,53 @@ func BenchmarkParseCoin(b *testing.B) { } } } + +func BenchmarkUintMarshal(b *testing.B) { + var values = []uint64{ + 0, + 1, + 1 << 10, + 1<<10 - 3, + 1<<63 - 1, + 1<<32 - 7, + 1<<22 - 8, + } + + var scratch [20]byte + b.ReportAllocs() + for i := 0; i < b.N; i++ { + for _, value := range values { + u := types.NewUint(value) + n, err := u.MarshalTo(scratch[:]) + if err != nil { + b.Fatal(err) + } + b.SetBytes(int64(n)) + } + } +} + +func BenchmarkIntMarshal(b *testing.B) { + var values = []int64{ + 0, + 1, + 1 << 10, + 1<<10 - 3, + 1<<63 - 1, + 1<<32 - 7, + 1<<22 - 8, + } + + var scratch [20]byte + b.ReportAllocs() + for i := 0; i < b.N; i++ { + for _, value := range values { + in := types.NewInt(value) + n, err := in.MarshalTo(scratch[:]) + if err != nil { + b.Fatal(err) + } + b.SetBytes(int64(n)) + } + } +} diff --git a/types/codec.go b/types/codec.go index 1d0595d93e..1775bb10c1 100644 --- a/types/codec.go +++ b/types/codec.go @@ -5,6 +5,11 @@ import ( "github.com/line/lbm-sdk/codec/types" ) +const ( + // MsgInterfaceProtoName defines the protobuf name of the cosmos Msg interface + MsgInterfaceProtoName = "lbm.base.v1.Msg" +) + // RegisterLegacyAminoCodec registers the sdk message type. func RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) { cdc.RegisterInterface((*Msg)(nil), nil) @@ -13,8 +18,5 @@ func RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) { // RegisterInterfaces registers the sdk message type. func RegisterInterfaces(registry types.InterfaceRegistry) { - registry.RegisterInterface("lbm.base.v1.Msg", (*Msg)(nil)) - // the interface name for MsgRequest is ServiceMsg because this is most useful for clients - // to understand - it will be the way for clients to introspect on available Msg service methods - registry.RegisterInterface("lbm.base.v1.ServiceMsg", (*MsgRequest)(nil)) + registry.RegisterInterface(MsgInterfaceProtoName, (*Msg)(nil)) } diff --git a/types/coin.go b/types/coin.go index bcc8cd78ee..d4d22642d2 100644 --- a/types/coin.go +++ b/types/coin.go @@ -34,7 +34,7 @@ func NewInt64Coin(denom string, amount int64) Coin { // String provides a human-readable representation of a coin func (coin Coin) String() string { - return fmt.Sprintf("%v%v", coin.Amount, coin.Denom) + return fmt.Sprintf("%v%s", coin.Amount, coin.Denom) } // Validate returns an error if the Coin has a negative amount or if @@ -100,6 +100,11 @@ func (coin Coin) Add(coinB Coin) Coin { return Coin{coin.Denom, coin.Amount.Add(coinB.Amount)} } +// AddAmount adds an amount to the Coin. +func (coin Coin) AddAmount(amount Int) Coin { + return Coin{coin.Denom, coin.Amount.Add(amount)} +} + // Sub subtracts amounts of two coins with same denom. If the coins differ in denom // then it panics. func (coin Coin) Sub(coinB Coin) Coin { @@ -115,6 +120,16 @@ func (coin Coin) Sub(coinB Coin) Coin { return res } +// SubAmount subtracts an amount from the Coin. +func (coin Coin) SubAmount(amount Int) Coin { + res := Coin{coin.Denom, coin.Amount.Sub(amount)} + if res.IsNegative() { + panic("negative coin amount") + } + + return res +} + // IsPositive returns true if coin amount is positive. // // TODO: Remove once unsigned integers are used. @@ -175,13 +190,18 @@ func (coins Coins) MarshalJSON() ([]byte, error) { func (coins Coins) String() string { if len(coins) == 0 { return "" + } else if len(coins) == 1 { + return coins[0].String() } - out := "" - for _, coin := range coins { - out += fmt.Sprintf("%v,", coin.String()) + // Build the string with a string builder + var out strings.Builder + for _, coin := range coins[:len(coins)-1] { + out.WriteString(coin.String()) + out.WriteByte(',') } - return out[:len(out)-1] + out.WriteString(coins[len(coins)-1].String()) + return out.String() } // Validate checks that the Coins are sorted, have positive amount, with a valid and unique @@ -233,6 +253,15 @@ func (coins Coins) Validate() error { } } +func (coins Coins) isSorted() bool { + for i := 1; i < len(coins); i++ { + if coins[i-1].Denom > coins[i].Denom { + return false + } + } + return true +} + // IsValid calls Validate and returns true when the Coins are sorted, have positive amount, with a // valid and unique denomination (i.e no duplicates). func (coins Coins) IsValid() bool { @@ -250,6 +279,7 @@ func (coins Coins) IsValid() bool { // // CONTRACT: Add will never return Coins where one Coin has a non-positive // amount. In otherwords, IsValid will always return true. +// The function panics if `coins` or `coinsB` are not sorted (ascending). func (coins Coins) Add(coinsB ...Coin) Coins { return coins.safeAdd(coinsB) } @@ -259,7 +289,17 @@ func (coins Coins) Add(coinsB ...Coin) Coins { // other set is returned. Otherwise, the coins are compared in order of their // denomination and addition only occurs when the denominations match, otherwise // the coin is simply added to the sum assuming it's not zero. +// The function panics if `coins` or `coinsB` are not sorted (ascending). func (coins Coins) safeAdd(coinsB Coins) Coins { + // probably the best way will be to make Coins and interface and hide the structure + // definition (type alias) + if !coins.isSorted() { + panic("Coins (self) must be sorted") + } + if !coinsB.isSorted() { + panic("Wrong argument: coins must be sorted") + } + sum := ([]Coin)(nil) indexA, indexB := 0, 0 lenA, lenB := len(coins), len(coinsB) @@ -344,6 +384,7 @@ func (coins Coins) Sub(coinsB Coins) Coins { // SafeSub performs the same arithmetic as Sub but returns a boolean if any // negative coin amount was returned. +// The function panics if `coins` or `coinsB` are not sorted (ascending). func (coins Coins) SafeSub(coinsB Coins) (Coins, bool) { diff := coins.safeAdd(coinsB.negative()) return diff, diff.IsAnyNegative() @@ -486,7 +527,12 @@ func (coins Coins) Empty() bool { // AmountOf returns the amount of a denom from coins func (coins Coins) AmountOf(denom string) Int { mustValidateDenom(denom) + return coins.AmountOfNoDenomValidation(denom) +} +// AmountOfNoDenomValidation returns the amount of a denom from coins +// without validating the denomination. +func (coins Coins) AmountOfNoDenomValidation(denom string) Int { switch len(coins) { case 0: return ZeroInt() @@ -499,15 +545,16 @@ func (coins Coins) AmountOf(denom string) Int { return ZeroInt() default: + // Binary search the amount of coins remaining midIdx := len(coins) / 2 // 2:1, 3:1, 4:2 coin := coins[midIdx] switch { case denom < coin.Denom: - return coins[:midIdx].AmountOf(denom) + return coins[:midIdx].AmountOfNoDenomValidation(denom) case denom == coin.Denom: return coin.Amount default: - return coins[midIdx+1:].AmountOf(denom) + return coins[midIdx+1:].AmountOfNoDenomValidation(denom) } } } @@ -627,7 +674,7 @@ func (coins Coins) Sort() Coins { var ( // Denominations can be 3 ~ 128 characters long and support letters, followed by either // a letter, a number or a separator ('/'). - reDnmString = `[a-zA-Z][a-zA-Z0-9/]{2,127}` + reDnmString = `[a-zA-Z][a-zA-Z0-9/-]{2,127}` reDecAmt = `[[:digit:]]+(?:\.[[:digit:]]+)?|\.[[:digit:]]+` reSpc = `[[:space:]]*` reDnm *regexp.Regexp diff --git a/types/coin_benchmark_test.go b/types/coin_benchmark_test.go index 51df291655..8c8088923e 100644 --- a/types/coin_benchmark_test.go +++ b/types/coin_benchmark_test.go @@ -6,10 +6,11 @@ import ( ) func coinName(suffix int) string { - return fmt.Sprintf("COINZ_%d", suffix) + return fmt.Sprintf("coinz%d", suffix) } func BenchmarkCoinsAdditionIntersect(b *testing.B) { + b.ReportAllocs() benchmarkingFunc := func(numCoinsA int, numCoinsB int) func(b *testing.B) { return func(b *testing.B) { b.ReportAllocs() @@ -40,6 +41,7 @@ func BenchmarkCoinsAdditionIntersect(b *testing.B) { } func BenchmarkCoinsAdditionNoIntersect(b *testing.B) { + b.ReportAllocs() benchmarkingFunc := func(numCoinsA int, numCoinsB int) func(b *testing.B) { return func(b *testing.B) { b.ReportAllocs() diff --git a/types/coin_internal_test.go b/types/coin_internal_test.go new file mode 100644 index 0000000000..709683795c --- /dev/null +++ b/types/coin_internal_test.go @@ -0,0 +1,37 @@ +package types + +import ( + "testing" + + "github.com/stretchr/testify/suite" +) + +func TestCoinTestSuite(t *testing.T) { + suite.Run(t, new(coinInternalSuite)) +} + +type coinInternalSuite struct { + suite.Suite +} + +func (s *coinInternalSuite) TestIsSorted() { + v := NewInt(1) + cases := []struct { + coins Coins + expected bool + }{ + {Coins{}, true}, + {Coins{{"1", v}}, true}, + {Coins{{"1", v}, {"1", v}}, true}, + {Coins{{"1", v}, {"2", v}}, true}, + {Coins{{"1", v}, {"2", v}, {"2", v}}, true}, + + {Coins{{"1", v}, {"0", v}}, false}, + {Coins{{"1", v}, {"0", v}, {"2", v}}, false}, + {Coins{{"1", v}, {"1", v}, {"0", v}}, false}, + } + assert := s.Assert() + for i, tc := range cases { + assert.Equal(tc.expected, tc.coins.isSorted(), "testcase %d failed", i) + } +} diff --git a/types/coin_test.go b/types/coin_test.go index 6f6527a8d0..0a4d721980 100644 --- a/types/coin_test.go +++ b/types/coin_test.go @@ -18,6 +18,7 @@ var ( type coinTestSuite struct { suite.Suite + ca0, ca1, ca2, cm0, cm1, cm2 sdk.Coin } func TestCoinTestSuite(t *testing.T) { @@ -26,6 +27,11 @@ func TestCoinTestSuite(t *testing.T) { func (s *coinTestSuite) SetupSuite() { s.T().Parallel() + zero := sdk.NewInt(0) + one := sdk.OneInt() + two := sdk.NewInt(2) + s.ca0, s.ca1, s.ca2 = sdk.Coin{testDenom1, zero}, sdk.Coin{testDenom1, one}, sdk.Coin{testDenom1, two} + s.cm0, s.cm1, s.cm2 = sdk.Coin{testDenom2, zero}, sdk.Coin{testDenom2, one}, sdk.Coin{testDenom2, two} } // ---------------------------------------------------------------------------- @@ -145,6 +151,21 @@ func (s *coinTestSuite) TestAddCoin() { } } +func (s *coinTestSuite) TestAddCoinAmount() { + cases := []struct { + coin sdk.Coin + amount sdk.Int + expected sdk.Coin + }{ + {sdk.NewInt64Coin(testDenom1, 1), sdk.NewInt(1), sdk.NewInt64Coin(testDenom1, 2)}, + {sdk.NewInt64Coin(testDenom1, 1), sdk.NewInt(0), sdk.NewInt64Coin(testDenom1, 1)}, + } + for i, tc := range cases { + res := tc.coin.AddAmount(tc.amount) + s.Require().Equal(tc.expected, res, "result of addition is incorrect, tc #%d", i) + } +} + func (s *coinTestSuite) TestSubCoin() { cases := []struct { inputOne sdk.Coin @@ -178,6 +199,30 @@ func (s *coinTestSuite) TestSubCoin() { s.Require().Equal(tc.expected, res.Amount.Int64()) } +func (s *coinTestSuite) TestSubCoinAmount() { + cases := []struct { + coin sdk.Coin + amount sdk.Int + expected sdk.Coin + shouldPanic bool + }{ + {sdk.NewInt64Coin(testDenom1, 2), sdk.NewInt(1), sdk.NewInt64Coin(testDenom1, 1), false}, + {sdk.NewInt64Coin(testDenom1, 10), sdk.NewInt(1), sdk.NewInt64Coin(testDenom1, 9), false}, + {sdk.NewInt64Coin(testDenom1, 5), sdk.NewInt(3), sdk.NewInt64Coin(testDenom1, 2), false}, + {sdk.NewInt64Coin(testDenom1, 5), sdk.NewInt(0), sdk.NewInt64Coin(testDenom1, 5), false}, + {sdk.NewInt64Coin(testDenom1, 1), sdk.NewInt(5), sdk.Coin{}, true}, + } + + for i, tc := range cases { + if tc.shouldPanic { + s.Require().Panics(func() { tc.coin.SubAmount(tc.amount) }) + } else { + res := tc.coin.SubAmount(tc.amount) + s.Require().Equal(tc.expected, res, "result of subtraction is incorrect, tc #%d", i) + } + } +} + func (s *coinTestSuite) TestIsGTECoin() { cases := []struct { inputOne sdk.Coin @@ -384,20 +429,16 @@ func (s *coinTestSuite) TestEqualCoins() { } func (s *coinTestSuite) TestAddCoins() { - zero := sdk.NewInt(0) - one := sdk.OneInt() - two := sdk.NewInt(2) - cases := []struct { inputOne sdk.Coins inputTwo sdk.Coins expected sdk.Coins }{ - {sdk.Coins{{testDenom1, one}, {testDenom2, one}}, sdk.Coins{{testDenom1, one}, {testDenom2, one}}, sdk.Coins{{testDenom1, two}, {testDenom2, two}}}, - {sdk.Coins{{testDenom1, zero}, {testDenom2, one}}, sdk.Coins{{testDenom1, zero}, {testDenom2, zero}}, sdk.Coins{{testDenom2, one}}}, - {sdk.Coins{{testDenom1, two}}, sdk.Coins{{testDenom2, zero}}, sdk.Coins{{testDenom1, two}}}, - {sdk.Coins{{testDenom1, one}}, sdk.Coins{{testDenom1, one}, {testDenom2, two}}, sdk.Coins{{testDenom1, two}, {testDenom2, two}}}, - {sdk.Coins{{testDenom1, zero}, {testDenom2, zero}}, sdk.Coins{{testDenom1, zero}, {testDenom2, zero}}, sdk.Coins(nil)}, + {sdk.Coins{s.ca1, s.cm1}, sdk.Coins{s.ca1, s.cm1}, sdk.Coins{s.ca2, s.cm2}}, + {sdk.Coins{s.ca0, s.cm1}, sdk.Coins{s.ca0, s.cm0}, sdk.Coins{s.cm1}}, + {sdk.Coins{s.ca2}, sdk.Coins{s.cm0}, sdk.Coins{s.ca2}}, + {sdk.Coins{s.ca1}, sdk.Coins{s.ca1, s.cm2}, sdk.Coins{s.ca2, s.cm2}}, + {sdk.Coins{s.ca0, s.cm0}, sdk.Coins{s.ca0, s.cm0}, sdk.Coins(nil)}, } for tcIndex, tc := range cases { @@ -408,31 +449,32 @@ func (s *coinTestSuite) TestAddCoins() { } func (s *coinTestSuite) TestSubCoins() { - zero := sdk.NewInt(0) - one := sdk.OneInt() - two := sdk.NewInt(2) - testCases := []struct { inputOne sdk.Coins inputTwo sdk.Coins expected sdk.Coins shouldPanic bool }{ - {sdk.Coins{{testDenom1, two}}, sdk.Coins{{testDenom1, one}, {testDenom2, two}}, sdk.Coins{{testDenom1, one}, {testDenom2, two}}, true}, - {sdk.Coins{{testDenom1, two}}, sdk.Coins{{testDenom2, zero}}, sdk.Coins{{testDenom1, two}}, false}, - {sdk.Coins{{testDenom1, one}}, sdk.Coins{{testDenom2, zero}}, sdk.Coins{{testDenom1, one}}, false}, - {sdk.Coins{{testDenom1, one}, {testDenom2, one}}, sdk.Coins{{testDenom1, one}}, sdk.Coins{{testDenom2, one}}, false}, - {sdk.Coins{{testDenom1, one}, {testDenom2, one}}, sdk.Coins{{testDenom1, two}}, sdk.Coins{}, true}, - } - + // denoms are not sorted - should panic + {sdk.Coins{s.ca2}, sdk.Coins{s.cm2, s.ca1}, sdk.Coins{}, true}, + {sdk.Coins{s.cm2, s.ca2}, sdk.Coins{s.ca1}, sdk.Coins{}, true}, + // test cases for sorted denoms + {sdk.Coins{s.ca2}, sdk.Coins{s.ca1, s.cm2}, sdk.Coins{s.ca1, s.cm2}, true}, + {sdk.Coins{s.ca2}, sdk.Coins{s.cm0}, sdk.Coins{s.ca2}, false}, + {sdk.Coins{s.ca1}, sdk.Coins{s.cm0}, sdk.Coins{s.ca1}, false}, + {sdk.Coins{s.ca1, s.cm1}, sdk.Coins{s.ca1}, sdk.Coins{s.cm1}, false}, + {sdk.Coins{s.ca1, s.cm1}, sdk.Coins{s.ca2}, sdk.Coins{}, true}, + } + + assert := s.Assert() for i, tc := range testCases { tc := tc if tc.shouldPanic { - s.Require().Panics(func() { tc.inputOne.Sub(tc.inputTwo) }) + assert.Panics(func() { tc.inputOne.Sub(tc.inputTwo) }) } else { res := tc.inputOne.Sub(tc.inputTwo) - s.Require().True(res.IsValid()) - s.Require().Equal(tc.expected, res, "sum of coins is incorrect, tc #%d", i) + assert.True(res.IsValid()) + assert.Equal(tc.expected, res, "sum of coins is incorrect, tc #%d", i) } } } @@ -963,10 +1005,10 @@ func (s *coinTestSuite) TestCoinAminoEncoding() { cdc := codec.NewLegacyAmino() c := sdk.NewInt64Coin(testDenom1, 5) - bz1, err := cdc.MarshalBinaryBare(c) + bz1, err := cdc.Marshal(c) s.Require().NoError(err) - bz2, err := cdc.MarshalBinaryLengthPrefixed(c) + bz2, err := cdc.MarshalLengthPrefixed(c) s.Require().NoError(err) bz3, err := c.Marshal() diff --git a/types/config.go b/types/config.go index 6efaf33a6a..79247f7777 100644 --- a/types/config.go +++ b/types/config.go @@ -2,6 +2,7 @@ package types import ( "context" + "fmt" "sync" "github.com/line/lbm-sdk/version" @@ -18,9 +19,13 @@ type Config struct { txEncoder TxEncoder addressVerifier func([]byte) error mtx sync.RWMutex - coinType uint32 - sealed bool - sealedch chan struct{} + + // SLIP-44 related + purpose uint32 + coinType uint32 + + sealed bool + sealedch chan struct{} } // cosmos-sdk wide global singleton @@ -41,9 +46,11 @@ func NewConfig() *Config { "validator_pub": Bech32PrefixValPub, "consensus_pub": Bech32PrefixConsPub, }, - coinType: CoinType, fullFundraiserPath: FullFundraiserPath, - txEncoder: nil, + + purpose: Purpose, + coinType: CoinType, + txEncoder: nil, } } @@ -112,16 +119,24 @@ func (config *Config) SetAddressVerifier(addressVerifier func([]byte) error) { config.addressVerifier = addressVerifier } -// Set the BIP-0044 CoinType code on the config -func (config *Config) SetCoinType(coinType uint32) { +// Set the FullFundraiserPath (BIP44Prefix) on the config. +// +// Deprecated: This method is supported for backward compatibility only and will be removed in a future release. Use SetPurpose and SetCoinType instead. +func (config *Config) SetFullFundraiserPath(fullFundraiserPath string) { config.assertNotSealed() - config.coinType = coinType + config.fullFundraiserPath = fullFundraiserPath } -// Set the FullFundraiserPath (BIP44Prefix) on the config -func (config *Config) SetFullFundraiserPath(fullFundraiserPath string) { +// Set the BIP-0044 Purpose code on the config +func (config *Config) SetPurpose(purpose uint32) { config.assertNotSealed() - config.fullFundraiserPath = fullFundraiserPath + config.purpose = purpose +} + +// Set the BIP-0044 CoinType code on the config +func (config *Config) SetCoinType(coinType uint32) { + config.assertNotSealed() + config.coinType = coinType } // Seal seals the config such that the config state could not be modified further @@ -181,16 +196,28 @@ func (config *Config) GetAddressVerifier() func([]byte) error { return config.addressVerifier } +// GetPurpose returns the BIP-0044 Purpose code on the config. +func (config *Config) GetPurpose() uint32 { + return config.purpose +} + // GetCoinType returns the BIP-0044 CoinType code on the config. func (config *Config) GetCoinType() uint32 { return config.coinType } // GetFullFundraiserPath returns the BIP44Prefix. +// +// Deprecated: This method is supported for backward compatibility only and will be removed in a future release. Use GetFullBIP44Path instead. func (config *Config) GetFullFundraiserPath() string { return config.fullFundraiserPath } +// GetFullBIP44Path returns the BIP44Prefix. +func (config *Config) GetFullBIP44Path() string { + return fmt.Sprintf("m/%d'/%d'/0'/0/0", config.purpose, config.coinType) +} + func KeyringServiceName() string { if len(version.Name) == 0 { return DefaultKeyringServiceName diff --git a/types/config_test.go b/types/config_test.go index bf8a46a8c5..aa0988959e 100644 --- a/types/config_test.go +++ b/types/config_test.go @@ -17,6 +17,18 @@ func TestConfigTestSuite(t *testing.T) { suite.Run(t, new(configTestSuite)) } +func (s *contextTestSuite) TestConfig_SetPurpose() { + config := sdk.NewConfig() + config.SetPurpose(44) + s.Require().Equal(uint32(44), config.GetPurpose()) + + config.SetPurpose(0) + s.Require().Equal(uint32(0), config.GetPurpose()) + + config.Seal() + s.Require().Panics(func() { config.SetPurpose(10) }) +} + func (s *configTestSuite) TestConfig_SetCoinType() { config := sdk.NewConfig() config.SetCoinType(1) diff --git a/types/context.go b/types/context.go index 4fb4e599c1..944cf9f93f 100644 --- a/types/context.go +++ b/types/context.go @@ -5,6 +5,7 @@ import ( "time" "github.com/gogo/protobuf/proto" + abci "github.com/line/ostracon/abci/types" ocbytes "github.com/line/ostracon/libs/bytes" "github.com/line/ostracon/libs/log" diff --git a/types/context_test.go b/types/context_test.go index 6e985f5313..b1259cb0c6 100644 --- a/types/context_test.go +++ b/types/context_test.go @@ -31,7 +31,7 @@ func (s *contextTestSuite) TestCacheContext() { k2 := []byte("key") v2 := []byte("value") - ctx := testutil.DefaultContext(key) + ctx := testutil.DefaultContext(key, types.NewTransientStoreKey("transient_"+s.T().Name())) store := ctx.KVStore(key) store.Set(k1, v1) s.Require().Equal(v1, store.Get(k1)) @@ -53,7 +53,7 @@ func (s *contextTestSuite) TestCacheContext() { func (s *contextTestSuite) TestLogContext() { key := types.NewKVStoreKey(s.T().Name()) - ctx := testutil.DefaultContext(key) + ctx := testutil.DefaultContext(key, types.NewTransientStoreKey("transient_"+s.T().Name())) ctrl := gomock.NewController(s.T()) s.T().Cleanup(ctrl.Finish) diff --git a/types/decimal.go b/types/decimal.go index 36b65bd983..a6d2868969 100644 --- a/types/decimal.go +++ b/types/decimal.go @@ -26,6 +26,8 @@ const ( // Ceiling[Log2[999 999 999 999 999 999]] DecimalPrecisionBits = 60 + maxDecBitLen = maxBitLen + DecimalPrecisionBits + // max number of iterations in ApproxRoot function maxApproxRootIterations = 100 ) @@ -80,8 +82,6 @@ func precisionMultiplier(prec int64) *big.Int { return precisionMultipliers[prec] } -// ______________________________________________________________________________________________ - // create a new Dec from integer assuming whole number func NewDec(i int64) Dec { return NewDecWithPrec(i, 0) @@ -198,7 +198,6 @@ func MustNewDecFromStr(s string) Dec { return dec } -// ______________________________________________________________________________________________ func (d Dec) IsNil() bool { return d.i == nil } // is decimal nil func (d Dec) IsZero() bool { return (d.i).Sign() == 0 } // is equal to zero func (d Dec) IsNegative() bool { return (d.i).Sign() == -1 } // is negative @@ -217,15 +216,15 @@ func (d Dec) BigInt() *big.Int { return nil } - copy := new(big.Int) - return copy.Set(d.i) + cp := new(big.Int) + return cp.Set(d.i) } // addition func (d Dec) Add(d2 Dec) Dec { res := new(big.Int).Add(d.i, d2.i) - if res.BitLen() > 255+DecimalPrecisionBits { + if res.BitLen() > maxDecBitLen { panic("Int overflow") } return Dec{res} @@ -235,7 +234,7 @@ func (d Dec) Add(d2 Dec) Dec { func (d Dec) Sub(d2 Dec) Dec { res := new(big.Int).Sub(d.i, d2.i) - if res.BitLen() > 255+DecimalPrecisionBits { + if res.BitLen() > maxDecBitLen { panic("Int overflow") } return Dec{res} @@ -246,7 +245,7 @@ func (d Dec) Mul(d2 Dec) Dec { mul := new(big.Int).Mul(d.i, d2.i) chopped := chopPrecisionAndRound(mul) - if chopped.BitLen() > 255+DecimalPrecisionBits { + if chopped.BitLen() > maxDecBitLen { panic("Int overflow") } return Dec{chopped} @@ -257,7 +256,7 @@ func (d Dec) MulTruncate(d2 Dec) Dec { mul := new(big.Int).Mul(d.i, d2.i) chopped := chopPrecisionAndTruncate(mul) - if chopped.BitLen() > 255+DecimalPrecisionBits { + if chopped.BitLen() > maxDecBitLen { panic("Int overflow") } return Dec{chopped} @@ -267,7 +266,7 @@ func (d Dec) MulTruncate(d2 Dec) Dec { func (d Dec) MulInt(i Int) Dec { mul := new(big.Int).Mul(d.i, i.i) - if mul.BitLen() > 255+DecimalPrecisionBits { + if mul.BitLen() > maxDecBitLen { panic("Int overflow") } return Dec{mul} @@ -277,7 +276,7 @@ func (d Dec) MulInt(i Int) Dec { func (d Dec) MulInt64(i int64) Dec { mul := new(big.Int).Mul(d.i, big.NewInt(i)) - if mul.BitLen() > 255+DecimalPrecisionBits { + if mul.BitLen() > maxDecBitLen { panic("Int overflow") } return Dec{mul} @@ -292,7 +291,7 @@ func (d Dec) Quo(d2 Dec) Dec { quo := new(big.Int).Quo(mul, d2.i) chopped := chopPrecisionAndRound(quo) - if chopped.BitLen() > 255+DecimalPrecisionBits { + if chopped.BitLen() > maxDecBitLen { panic("Int overflow") } return Dec{chopped} @@ -304,10 +303,10 @@ func (d Dec) QuoTruncate(d2 Dec) Dec { mul := new(big.Int).Mul(d.i, precisionReuse) mul.Mul(mul, precisionReuse) - quo := new(big.Int).Quo(mul, d2.i) + quo := mul.Quo(mul, d2.i) chopped := chopPrecisionAndTruncate(quo) - if chopped.BitLen() > 255+DecimalPrecisionBits { + if chopped.BitLen() > maxDecBitLen { panic("Int overflow") } return Dec{chopped} @@ -322,7 +321,7 @@ func (d Dec) QuoRoundUp(d2 Dec) Dec { quo := new(big.Int).Quo(mul, d2.i) chopped := chopPrecisionAndRoundUp(quo) - if chopped.BitLen() > 255+DecimalPrecisionBits { + if chopped.BitLen() > maxDecBitLen { panic("Int overflow") } return Dec{chopped} @@ -477,6 +476,22 @@ func (d Dec) String() string { return string(bzStr) } +// Float64 returns the float64 representation of a Dec. +// Will return the error if the conversion failed. +func (d Dec) Float64() (float64, error) { + return strconv.ParseFloat(d.String(), 64) +} + +// MustFloat64 returns the float64 representation of a Dec. +// Would panic if the conversion failed. +func (d Dec) MustFloat64() float64 { + if value, err := strconv.ParseFloat(d.String(), 64); err != nil { + panic(err) + } else { + return value + } +} + // ____ // __| |__ "chop 'em // ` \ round!" @@ -563,21 +578,15 @@ func (d Dec) RoundInt() Int { return NewIntFromBigInt(chopPrecisionAndRoundNonMutative(d.i)) } -// ___________________________________________________________________________________ - -// similar to chopPrecisionAndRound, but always rounds down +// chopPrecisionAndTruncate is similar to chopPrecisionAndRound, +// but always rounds down. It does not mutate the input. func chopPrecisionAndTruncate(d *big.Int) *big.Int { - return d.Quo(d, precisionReuse) -} - -func chopPrecisionAndTruncateNonMutative(d *big.Int) *big.Int { - tmp := new(big.Int).Set(d) - return chopPrecisionAndTruncate(tmp) + return new(big.Int).Quo(d, precisionReuse) } // TruncateInt64 truncates the decimals from the number and returns an int64 func (d Dec) TruncateInt64() int64 { - chopped := chopPrecisionAndTruncateNonMutative(d.i) + chopped := chopPrecisionAndTruncate(d.i) if !chopped.IsInt64() { panic("Int64() out of bound") } @@ -586,12 +595,12 @@ func (d Dec) TruncateInt64() int64 { // TruncateInt truncates the decimals from the number and returns an Int func (d Dec) TruncateInt() Int { - return NewIntFromBigInt(chopPrecisionAndTruncateNonMutative(d.i)) + return NewIntFromBigInt(chopPrecisionAndTruncate(d.i)) } // TruncateDec truncates the decimals from the number and returns a Dec func (d Dec) TruncateDec() Dec { - return NewDecFromBigInt(chopPrecisionAndTruncateNonMutative(d.i)) + return NewDecFromBigInt(chopPrecisionAndTruncate(d.i)) } // Ceil returns the smallest interger value (as a decimal) that is greater than @@ -614,8 +623,6 @@ func (d Dec) Ceil() Dec { return NewDecFromBigInt(quo.Add(quo, oneInt)) } -// ___________________________________________________________________________________ - // MaxSortableDec is the largest Dec that can be passed into SortableDecBytes() // Its negative form is the least Dec that can be passed in. var MaxSortableDec = OneDec().Quo(SmallestDec()) @@ -650,8 +657,6 @@ func SortableDecBytes(dec Dec) []byte { return []byte(fmt.Sprintf(fmt.Sprintf("%%0%ds", Precision*2+1), dec.String())) } -// ___________________________________________________________________________________ - // reuse nil values var nilJSON []byte @@ -760,7 +765,6 @@ func (dp DecProto) String() string { return dp.Dec.String() } -// ___________________________________________________________________________________ // helpers // test if two decimal arrays are equal diff --git a/types/decimal_test.go b/types/decimal_test.go index 3ca46b3b91..63958768d1 100644 --- a/types/decimal_test.go +++ b/types/decimal_test.go @@ -29,8 +29,6 @@ func (s *decimalTestSuite) mustNewDecFromStr(str string) (d sdk.Dec) { return d } -// _______________________________________ - func (s *decimalTestSuite) TestNewDecFromStr() { largeBigInt, success := new(big.Int).SetString("3144605511029693144278234343371835", 10) s.Require().True(success) @@ -102,6 +100,28 @@ func (s *decimalTestSuite) TestDecString() { } } +func (s *decimalTestSuite) TestDecFloat64() { + tests := []struct { + d sdk.Dec + want float64 + }{ + {sdk.NewDec(0), 0.000000000000000000}, + {sdk.NewDec(1), 1.000000000000000000}, + {sdk.NewDec(10), 10.000000000000000000}, + {sdk.NewDec(12340), 12340.000000000000000000}, + {sdk.NewDecWithPrec(12340, 4), 1.234000000000000000}, + {sdk.NewDecWithPrec(12340, 5), 0.123400000000000000}, + {sdk.NewDecWithPrec(12340, 8), 0.000123400000000000}, + {sdk.NewDecWithPrec(1009009009009009009, 17), 10.090090090090090090}, + } + for tcIndex, tc := range tests { + value, err := tc.d.Float64() + s.Require().Nil(err, "error getting Float64(), index: %v", tcIndex) + s.Require().Equal(tc.want, value, "bad Float64(), index: %v", tcIndex) + s.Require().Equal(tc.want, tc.d.MustFloat64(), "bad MustFloat64(), index: %v", tcIndex) + } +} + func (s *decimalTestSuite) TestEqualities() { tests := []struct { d1, d2 sdk.Dec @@ -488,6 +508,7 @@ func (s *decimalTestSuite) TestOperationOrders() { } func BenchmarkMarshalTo(b *testing.B) { + b.ReportAllocs() bis := []struct { in sdk.Dec want []byte diff --git a/types/denom.go b/types/denom.go index 160e2806e1..0e8d716a26 100644 --- a/types/denom.go +++ b/types/denom.go @@ -9,7 +9,7 @@ import ( var denomUnits = map[string]Dec{} // baseDenom is the denom of smallest unit registered -var baseDenom string = "" +var baseDenom string // RegisterDenom registers a denomination with a corresponding unit. If the // denomination is already registered, an error will be returned. diff --git a/types/errors/abci.go b/types/errors/abci.go index 19c0f7c9fe..d288b01491 100644 --- a/types/errors/abci.go +++ b/types/errors/abci.go @@ -52,6 +52,20 @@ func ResponseCheckTx(err error, gw, gu uint64, debug bool) abci.ResponseCheckTx } } +// ResponseCheckTxWithEvents returns an ABCI ResponseCheckTx object with fields filled in +// from the given error, gas values and events. +func ResponseCheckTxWithEvents(err error, gw, gu uint64, events []abci.Event, debug bool) abci.ResponseCheckTx { + space, code, log := ABCIInfo(err, debug) + return abci.ResponseCheckTx{ + Codespace: space, + Code: code, + Log: log, + GasWanted: int64(gw), + GasUsed: int64(gu), + Events: events, + } +} + // ResponseDeliverTx returns an ABCI ResponseDeliverTx object with fields filled in // from the given error and gas values. func ResponseDeliverTx(err error, gw, gu uint64, debug bool) abci.ResponseDeliverTx { @@ -65,6 +79,20 @@ func ResponseDeliverTx(err error, gw, gu uint64, debug bool) abci.ResponseDelive } } +// ResponseDeliverTxWithEvents returns an ABCI ResponseDeliverTx object with fields filled in +// from the given error, gas values and events. +func ResponseDeliverTxWithEvents(err error, gw, gu uint64, events []abci.Event, debug bool) abci.ResponseDeliverTx { + space, code, log := ABCIInfo(err, debug) + return abci.ResponseDeliverTx{ + Codespace: space, + Code: code, + Log: log, + GasWanted: int64(gw), + GasUsed: int64(gu), + Events: events, + } +} + // QueryResult returns a ResponseQuery from an error. It will try to parse ABCI // info from the error. func QueryResult(err error) abci.ResponseQuery { diff --git a/types/errors/errors.go b/types/errors/errors.go index 9d880f81a0..3160f506b0 100644 --- a/types/errors/errors.go +++ b/types/errors/errors.go @@ -135,7 +135,14 @@ var ( ErrNotSupported = Register(RootCodespace, 37, "feature not supported") // ErrNotFound defines an error when requested entity doesn't exist in the state. - ErrNotFound = Register(RootCodespace, 39, "not found") + ErrNotFound = Register(RootCodespace, 38, "not found") + + // ErrIO should be used to wrap internal errors caused by external operation. + // Examples: not DB domain error, file writing etc... + ErrIO = Register(RootCodespace, 39, "Internal IO error") + + // ErrAppConfig defines an error occurred if min-gas-prices field in BaseConfig is empty. + ErrAppConfig = Register(RootCodespace, 40, "error in app.toml") // ErrPanic is only set when we recover from a panic, so we know to // redact potentially sensitive system info @@ -257,6 +264,14 @@ func (e *Error) Is(err error) bool { } } +// Wrap extends this error with an additional information. +// It's a handy function to call Wrap with sdk errors. +func (e *Error) Wrap(desc string) error { return Wrap(e, desc) } + +// Wrapf extends this error with an additional information. +// It's a handy function to call Wrapf with sdk errors. +func (e *Error) Wrapf(desc string, args ...interface{}) error { return Wrapf(e, desc, args...) } + func isNilErr(err error) bool { // Reflect usage is necessary to correctly compare with // a nil implementation of an error. @@ -359,6 +374,17 @@ func WithType(err error, obj interface{}) error { return Wrap(err, fmt.Sprintf("%T", obj)) } +// IsOf checks if a received error is caused by one of the target errors. +// It extends the errors.Is functionality to a list of errors. +func IsOf(received error, targets ...error) bool { + for _, t := range targets { + if errors.Is(received, t) { + return true + } + } + return false +} + // causer is an interface implemented by an error that supports wrapping. Use // it to test if an error wraps another error instance. type causer interface { diff --git a/types/errors/errors_test.go b/types/errors/errors_test.go index ea0e063c3a..b7e9c478fe 100644 --- a/types/errors/errors_test.go +++ b/types/errors/errors_test.go @@ -149,6 +149,27 @@ func (s *errorsTestSuite) TestErrorIs() { } } +func (s *errorsTestSuite) TestIsOf() { + require := s.Require() + + var errNil *Error + var err = ErrInvalidAddress + var errW = Wrap(ErrLogic, "more info") + + require.False(IsOf(errNil), "nil error should always have no causer") + require.False(IsOf(errNil, err), "nil error should always have no causer") + + require.False(IsOf(err)) + require.False(IsOf(err, nil)) + require.False(IsOf(err, ErrLogic)) + + require.True(IsOf(errW, ErrLogic)) + require.True(IsOf(errW, err, ErrLogic)) + require.True(IsOf(errW, nil, errW), "error should much itself") + var err2 = errors.New("other error") + require.True(IsOf(err2, nil, err2), "error should much itself") +} + type customError struct { } @@ -179,6 +200,11 @@ func (s *errorsTestSuite) TestWrappedIs() { errw := &wrappedError{"msg", errs} require.True(errw.Is(errw), "should match itself") + + require.True(stdlib.Is(ErrInsufficientFee.Wrap("wrapped"), ErrInsufficientFee)) + require.True(IsOf(ErrInsufficientFee.Wrap("wrapped"), ErrInsufficientFee)) + require.True(stdlib.Is(ErrInsufficientFee.Wrapf("wrapped"), ErrInsufficientFee)) + require.True(IsOf(ErrInsufficientFee.Wrapf("wrapped"), ErrInsufficientFee)) } func (s *errorsTestSuite) TestWrappedIsMultiple() { diff --git a/types/errors/handle.go b/types/errors/handle.go new file mode 100644 index 0000000000..33c3fbfdea --- /dev/null +++ b/types/errors/handle.go @@ -0,0 +1,12 @@ +package errors + +import "fmt" + +// AssertNil panics on error +// Should be only used with interface methods, which require return error, but the +// error is always nil +func AssertNil(err error) { + if err != nil { + panic(fmt.Errorf("logic error - this should never happen. %w", err)) + } +} diff --git a/types/events.go b/types/events.go index 997819f7d3..2fe4b62188 100644 --- a/types/events.go +++ b/types/events.go @@ -227,6 +227,7 @@ var ( AttributeKeyAccountSequence = "acc_seq" AttributeKeySignature = "signature" + AttributeKeyFee = "fee" EventTypeMessage = "message" diff --git a/types/handler_test.go b/types/handler_test.go index 8a10fa1a28..139cef9e2b 100644 --- a/types/handler_test.go +++ b/types/handler_test.go @@ -30,11 +30,18 @@ func (s *handlerTestSuite) TestChainAnteDecorators() { mockCtrl := gomock.NewController(s.T()) mockAnteDecorator1 := mocks.NewMockAnteDecorator(mockCtrl) mockAnteDecorator1.EXPECT().AnteHandle(gomock.Eq(ctx), gomock.Eq(tx), true, gomock.Any()).Times(1) - sdk.ChainAnteDecorators(mockAnteDecorator1)(ctx, tx, true) //nolint:errcheck + _, err := sdk.ChainAnteDecorators(mockAnteDecorator1)(ctx, tx, true) + s.Require().NoError(err) mockAnteDecorator2 := mocks.NewMockAnteDecorator(mockCtrl) - mockAnteDecorator3 := mocks.NewMockAnteDecorator(mockCtrl) + // NOTE: we can't check that mockAnteDecorator2 is passed as the last argument because + // ChainAnteDecorators wraps the decorators into closures, so each decorator is + // receving a closure. + mockAnteDecorator1.EXPECT().AnteHandle(gomock.Eq(ctx), gomock.Eq(tx), true, gomock.Any()).Times(1) mockAnteDecorator2.EXPECT().AnteHandle(gomock.Eq(ctx), gomock.Eq(tx), true, gomock.Any()).Times(1) - // next handler does not called by mock - sdk.ChainAnteDecorators(mockAnteDecorator2, mockAnteDecorator3)(ctx, tx, true) + + _, err = sdk.ChainAnteDecorators( + mockAnteDecorator1, + mockAnteDecorator2)(ctx, tx, true) + s.Require().NoError(err) } diff --git a/types/int.go b/types/int.go index 81f6b1c04d..04b808fbc6 100644 --- a/types/int.go +++ b/types/int.go @@ -9,7 +9,7 @@ import ( "math/big" ) -const maxBitLen = 255 +const maxBitLen = 256 func newIntegerFromString(s string) (*big.Int, bool) { return new(big.Int).SetString(s, 0) @@ -37,6 +37,8 @@ func mod(i *big.Int, i2 *big.Int) *big.Int { return new(big.Int).Mod(i, i2) } func neg(i *big.Int) *big.Int { return new(big.Int).Neg(i) } +func abs(i *big.Int) *big.Int { return new(big.Int).Abs(i) } + func min(i *big.Int, i2 *big.Int) *big.Int { if i.Cmp(i2) == 1 { return new(big.Int).Set(i2) @@ -67,9 +69,9 @@ func unmarshalText(i *big.Int, text string) error { var _ CustomProtobufType = (*Int)(nil) -// Int wraps integer with 256 bit range bound +// Int wraps big.Int with a 257 bit range bound // Checks overflow, underflow and division by zero -// Exists in range from -(2^maxBitLen-1) to 2^maxBitLen-1 +// Exists in range from -(2^256 - 1) to 2^256 - 1 type Int struct { i *big.Int } @@ -99,8 +101,13 @@ func NewIntFromUint64(n uint64) Int { return Int{b} } -// NewIntFromBigInt constructs Int from big.Int +// NewIntFromBigInt constructs Int from big.Int. If the provided big.Int is nil, +// it returns an empty instance. This function panics if the bit length is > 256. func NewIntFromBigInt(i *big.Int) Int { + if i == nil { + return Int{} + } + if i.BitLen() > maxBitLen { panic("NewIntFromBigInt() out of bound") } @@ -304,6 +311,11 @@ func (i Int) Neg() (res Int) { return Int{neg(i.i)} } +// Abs returns the absolute value of Int. +func (i Int) Abs() Int { + return Int{abs(i.i)} +} + // return the minimum of the ints func MinInt(i1, i2 Int) Int { return Int{min(i1.BigInt(), i2.BigInt())} @@ -375,7 +387,7 @@ func (i *Int) MarshalTo(data []byte) (n int, err error) { if i.i == nil { i.i = new(big.Int) } - if len(i.i.Bytes()) == 0 { + if i.i.BitLen() == 0 { // The value 0 copy(data, []byte{0x30}) return 1, nil } diff --git a/types/int_internal_test.go b/types/int_internal_test.go index c6b039948e..77d357bbf7 100644 --- a/types/int_internal_test.go +++ b/types/int_internal_test.go @@ -63,7 +63,7 @@ func (s *internalIntTestSuite) TestEncodingRandom() { } func (s *internalIntTestSuite) TestSerializationOverflow() { - bx, _ := new(big.Int).SetString("91888242871839275229946405745257275988696311157297823662689937894645226298583", 10) + bx, _ := new(big.Int).SetString("115792089237316195423570985008687907853269984665640564039457584007913129639936", 10) x := Int{bx} y := new(Int) @@ -80,6 +80,24 @@ func (s *internalIntTestSuite) TestSerializationOverflow() { s.Require().Error(y.UnmarshalJSON(bz)) } +func (s *internalIntTestSuite) TestDeserializeMaxERC20() { + bx, _ := new(big.Int).SetString("115792089237316195423570985008687907853269984665640564039457584007913129639935", 10) + x := Int{bx} + y := new(Int) + + bz, err := x.Marshal() + s.Require().NoError(err) + + // require deserialization to be successful + s.Require().NoError(y.Unmarshal(bz)) + + // require JSON deserialization to succeed + bz, err = x.MarshalJSON() + s.Require().NoError(err) + + s.Require().NoError(y.UnmarshalJSON(bz)) +} + func (s *internalIntTestSuite) TestImmutabilityArithInt() { size := 500 diff --git a/types/int_test.go b/types/int_test.go index c70cef1ce4..3365fc4a43 100644 --- a/types/int_test.go +++ b/types/int_test.go @@ -1,6 +1,7 @@ package types_test import ( + "fmt" "math/big" "math/rand" "strconv" @@ -39,16 +40,16 @@ func (s *intTestSuite) TestFromUint64() { } func (s *intTestSuite) TestIntPanic() { - // Max Int = 2^255-1 = 5.789e+76 - // Min Int = -(2^255-1) = -5.789e+76 - s.Require().NotPanics(func() { sdk.NewIntWithDecimal(1, 76) }) - i1 := sdk.NewIntWithDecimal(1, 76) - s.Require().NotPanics(func() { sdk.NewIntWithDecimal(2, 76) }) - i2 := sdk.NewIntWithDecimal(2, 76) - s.Require().NotPanics(func() { sdk.NewIntWithDecimal(3, 76) }) - i3 := sdk.NewIntWithDecimal(3, 76) - - s.Require().Panics(func() { sdk.NewIntWithDecimal(6, 76) }) + // Max Int = 2^256-1 = 1.1579209e+77 + // Min Int = -(2^256-1) = -1.1579209e+77 + s.Require().NotPanics(func() { sdk.NewIntWithDecimal(4, 76) }) + i1 := sdk.NewIntWithDecimal(4, 76) + s.Require().NotPanics(func() { sdk.NewIntWithDecimal(5, 76) }) + i2 := sdk.NewIntWithDecimal(5, 76) + s.Require().NotPanics(func() { sdk.NewIntWithDecimal(6, 76) }) + i3 := sdk.NewIntWithDecimal(6, 76) + + s.Require().Panics(func() { sdk.NewIntWithDecimal(2, 77) }) s.Require().Panics(func() { sdk.NewIntWithDecimal(9, 80) }) // Overflow check @@ -68,7 +69,7 @@ func (s *intTestSuite) TestIntPanic() { s.Require().Panics(func() { i2.Neg().Mul(i2.Neg()) }) s.Require().Panics(func() { i3.Neg().Mul(i3.Neg()) }) - // Underflow check + // // Underflow check i3n := i3.Neg() s.Require().NotPanics(func() { i3n.Sub(i1) }) s.Require().NotPanics(func() { i3n.Sub(i2) }) @@ -83,13 +84,16 @@ func (s *intTestSuite) TestIntPanic() { s.Require().Panics(func() { i3.Mul(i3.Neg()) }) // Bound check - intmax := sdk.NewIntFromBigInt(new(big.Int).Sub(new(big.Int).Exp(big.NewInt(2), big.NewInt(255), nil), big.NewInt(1))) + intmax := sdk.NewIntFromBigInt(new(big.Int).Sub(new(big.Int).Exp(big.NewInt(2), big.NewInt(256), nil), big.NewInt(1))) intmin := intmax.Neg() s.Require().NotPanics(func() { intmax.Add(sdk.ZeroInt()) }) s.Require().NotPanics(func() { intmin.Sub(sdk.ZeroInt()) }) s.Require().Panics(func() { intmax.Add(sdk.OneInt()) }) s.Require().Panics(func() { intmin.Sub(sdk.OneInt()) }) + s.Require().NotPanics(func() { sdk.NewIntFromBigInt(nil) }) + s.Require().True(sdk.NewIntFromBigInt(nil).IsNil()) + // Division-by-zero check s.Require().Panics(func() { i1.Quo(sdk.NewInt(0)) }) @@ -158,6 +162,8 @@ func (s *intTestSuite) TestArithInt() { {sdk.MinInt(i1, i2), minint(n1, n2)}, {sdk.MaxInt(i1, i2), maxint(n1, n2)}, {i1.Neg(), -n1}, + {i1.Abs(), n1}, + {i1.Neg().Abs(), n1}, } for tcnum, tc := range cases { @@ -205,6 +211,7 @@ func (s *intTestSuite) TestImmutabilityAllInt() { func(i *sdk.Int) { _ = i.MulRaw(rand.Int63()) }, func(i *sdk.Int) { _ = i.QuoRaw(rand.Int63()) }, func(i *sdk.Int) { _ = i.Neg() }, + func(i *sdk.Int) { _ = i.Abs() }, func(i *sdk.Int) { _ = i.IsZero() }, func(i *sdk.Int) { _ = i.Sign() }, func(i *sdk.Int) { _ = i.Equal(randint()) }, @@ -385,3 +392,36 @@ func (s *intTestSuite) TestIntEq() { _, resp, _, _, _ = sdk.IntEq(s.T(), sdk.OneInt(), sdk.ZeroInt()) s.Require().False(resp) } + +func TestRoundTripMarshalToInt(t *testing.T) { + var values = []int64{ + 0, + 1, + 1 << 10, + 1<<10 - 3, + 1<<63 - 1, + 1<<32 - 7, + 1<<22 - 8, + } + + for _, value := range values { + value := value + t.Run(fmt.Sprintf("%d", value), func(t *testing.T) { + t.Parallel() + + var scratch [20]byte + iv := sdk.NewInt(value) + n, err := iv.MarshalTo(scratch[:]) + if err != nil { + t.Fatal(err) + } + rt := new(sdk.Int) + if err := rt.Unmarshal(scratch[:n]); err != nil { + t.Fatal(err) + } + if !rt.Equal(iv) { + t.Fatalf("roundtrip=%q != original=%q", rt, iv) + } + }) + } +} diff --git a/types/module/configurator.go b/types/module/configurator.go index 136ab8ec51..6e920d322e 100644 --- a/types/module/configurator.go +++ b/types/module/configurator.go @@ -1,6 +1,8 @@ package module import ( + "fmt" + "github.com/gogo/protobuf/grpc" "github.com/line/lbm-sdk/codec" @@ -35,7 +37,7 @@ type Configurator interface { } type configurator struct { - cdc codec.JSONMarshaler + cdc codec.Codec msgServer grpc.Server queryServer grpc.Server @@ -44,7 +46,7 @@ type configurator struct { } // NewConfigurator returns a new Configurator instance -func NewConfigurator(cdc codec.JSONMarshaler, msgServer grpc.Server, queryServer grpc.Server) Configurator { +func NewConfigurator(cdc codec.Codec, msgServer grpc.Server, queryServer grpc.Server) Configurator { return configurator{ cdc: cdc, msgServer: msgServer, @@ -103,6 +105,7 @@ func (c configurator) runModuleMigrations(ctx sdk.Context, moduleName string, fr if !found { return sdkerrors.Wrapf(sdkerrors.ErrNotFound, "no migration found for module %s from version %d to version %d", moduleName, i, i+1) } + ctx.Logger().Info(fmt.Sprintf("migrating module %s from version %d to version %d", moduleName, i, i+1)) err := migrateFn(ctx) if err != nil { diff --git a/types/module/module.go b/types/module/module.go index 7219a6f5d8..66ea4dd304 100644 --- a/types/module/module.go +++ b/types/module/module.go @@ -30,13 +30,15 @@ package module import ( "encoding/json" + "fmt" "sort" "github.com/gorilla/mux" "github.com/grpc-ecosystem/grpc-gateway/runtime" - abci "github.com/line/ostracon/abci/types" "github.com/spf13/cobra" + abci "github.com/line/ostracon/abci/types" + "github.com/line/lbm-sdk/client" "github.com/line/lbm-sdk/codec" codectypes "github.com/line/lbm-sdk/codec/types" @@ -44,16 +46,14 @@ import ( sdkerrors "github.com/line/lbm-sdk/types/errors" ) -// __________________________________________________________________________________________ - // AppModuleBasic is the standard form for basic non-dependant elements of an application module. type AppModuleBasic interface { Name() string RegisterLegacyAminoCodec(*codec.LegacyAmino) RegisterInterfaces(codectypes.InterfaceRegistry) - DefaultGenesis(codec.JSONMarshaler) json.RawMessage - ValidateGenesis(codec.JSONMarshaler, client.TxEncodingConfig, json.RawMessage) error + DefaultGenesis(codec.JSONCodec) json.RawMessage + ValidateGenesis(codec.JSONCodec, client.TxEncodingConfig, json.RawMessage) error // client functionality RegisterRESTRoutes(client.Context, *mux.Router) @@ -89,7 +89,7 @@ func (bm BasicManager) RegisterInterfaces(registry codectypes.InterfaceRegistry) } // DefaultGenesis provides default genesis information for all modules -func (bm BasicManager) DefaultGenesis(cdc codec.JSONMarshaler) map[string]json.RawMessage { +func (bm BasicManager) DefaultGenesis(cdc codec.JSONCodec) map[string]json.RawMessage { genesis := make(map[string]json.RawMessage) for _, b := range bm { genesis[b.Name()] = b.DefaultGenesis(cdc) @@ -99,7 +99,7 @@ func (bm BasicManager) DefaultGenesis(cdc codec.JSONMarshaler) map[string]json.R } // ValidateGenesis performs genesis state validation for all modules -func (bm BasicManager) ValidateGenesis(cdc codec.JSONMarshaler, txEncCfg client.TxEncodingConfig, genesis map[string]json.RawMessage) error { +func (bm BasicManager) ValidateGenesis(cdc codec.JSONCodec, txEncCfg client.TxEncodingConfig, genesis map[string]json.RawMessage) error { for _, b := range bm { if err := b.ValidateGenesis(cdc, txEncCfg, genesis[b.Name()]); err != nil { return err @@ -126,7 +126,7 @@ func (bm BasicManager) RegisterGRPCGatewayRoutes(clientCtx client.Context, rtr * // AddTxCommands adds all tx commands to the rootTxCmd. // // TODO: Remove clientCtx argument. -// REF: https://github.com/line/lbm-sdk/issues/6571 +// REF: https://github.com/cosmos/cosmos-sdk/issues/6571 func (bm BasicManager) AddTxCommands(rootTxCmd *cobra.Command) { for _, b := range bm { if cmd := b.GetTxCmd(); cmd != nil { @@ -138,7 +138,7 @@ func (bm BasicManager) AddTxCommands(rootTxCmd *cobra.Command) { // AddQueryCommands adds all query commands to the rootQueryCmd. // // TODO: Remove clientCtx argument. -// REF: https://github.com/line/lbm-sdk/issues/6571 +// REF: https://github.com/cosmos/cosmos-sdk/issues/6571 func (bm BasicManager) AddQueryCommands(rootQueryCmd *cobra.Command) { for _, b := range bm { if cmd := b.GetQueryCmd(); cmd != nil { @@ -147,14 +147,12 @@ func (bm BasicManager) AddQueryCommands(rootQueryCmd *cobra.Command) { } } -// _________________________________________________________ - // AppModuleGenesis is the standard form for an application module genesis functions type AppModuleGenesis interface { AppModuleBasic - InitGenesis(sdk.Context, codec.JSONMarshaler, json.RawMessage) []abci.ValidatorUpdate - ExportGenesis(sdk.Context, codec.JSONMarshaler) json.RawMessage + InitGenesis(sdk.Context, codec.JSONCodec, json.RawMessage) []abci.ValidatorUpdate + ExportGenesis(sdk.Context, codec.JSONCodec) json.RawMessage } // AppModule is the standard form for an application module @@ -187,8 +185,6 @@ type AppModule interface { EndBlock(sdk.Context, abci.RequestEndBlock) []abci.ValidatorUpdate } -// ___________________________ - // GenesisOnlyAppModule is an AppModule that only has import/export functionality type GenesisOnlyAppModule struct { AppModuleGenesis @@ -227,8 +223,6 @@ func (GenesisOnlyAppModule) EndBlock(_ sdk.Context, _ abci.RequestEndBlock) []ab return []abci.ValidatorUpdate{} } -// ____________________________________________________________________________ - // Manager defines a module manager that provides the high level utility for managing and executing // operations for a group of modules type Manager struct { @@ -237,6 +231,7 @@ type Manager struct { OrderExportGenesis []string OrderBeginBlockers []string OrderEndBlockers []string + OrderMigrations []string } // NewManager creates a new Manager object @@ -260,25 +255,36 @@ func NewManager(modules ...AppModule) *Manager { // SetOrderInitGenesis sets the order of init genesis calls func (m *Manager) SetOrderInitGenesis(moduleNames ...string) { + m.assertNoForgottenModules("SetOrderInitGenesis", moduleNames) m.OrderInitGenesis = moduleNames } // SetOrderExportGenesis sets the order of export genesis calls func (m *Manager) SetOrderExportGenesis(moduleNames ...string) { + m.assertNoForgottenModules("SetOrderExportGenesis", moduleNames) m.OrderExportGenesis = moduleNames } // SetOrderBeginBlockers sets the order of set begin-blocker calls func (m *Manager) SetOrderBeginBlockers(moduleNames ...string) { + m.assertNoForgottenModules("SetOrderBeginBlockers", moduleNames) m.OrderBeginBlockers = moduleNames } // SetOrderEndBlockers sets the order of set end-blocker calls func (m *Manager) SetOrderEndBlockers(moduleNames ...string) { + m.assertNoForgottenModules("SetOrderEndBlockers", moduleNames) m.OrderEndBlockers = moduleNames } -// RegisterInvariants registers all module routes and module querier routes +// SetOrderMigrations sets the order of migrations to be run. If not set +// then migrations will be run with an order defined in `DefaultMigrationsOrder`. +func (m *Manager) SetOrderMigrations(moduleNames ...string) { + m.assertNoForgottenModules("SetOrderMigrations", moduleNames) + m.OrderMigrations = moduleNames +} + +// RegisterInvariants registers all module invariants func (m *Manager) RegisterInvariants(ir sdk.InvariantRegistry) { for _, module := range m.Modules { module.RegisterInvariants(ir) @@ -305,7 +311,7 @@ func (m *Manager) RegisterServices(cfg Configurator) { } // InitGenesis performs init genesis functionality for modules -func (m *Manager) InitGenesis(ctx sdk.Context, cdc codec.JSONMarshaler, genesisData map[string]json.RawMessage) abci.ResponseInitChain { +func (m *Manager) InitGenesis(ctx sdk.Context, cdc codec.JSONCodec, genesisData map[string]json.RawMessage) abci.ResponseInitChain { var validatorUpdates []abci.ValidatorUpdate for _, moduleName := range m.OrderInitGenesis { if genesisData[moduleName] == nil { @@ -330,7 +336,7 @@ func (m *Manager) InitGenesis(ctx sdk.Context, cdc codec.JSONMarshaler, genesisD } // ExportGenesis performs export genesis functionality for modules -func (m *Manager) ExportGenesis(ctx sdk.Context, cdc codec.JSONMarshaler) map[string]json.RawMessage { +func (m *Manager) ExportGenesis(ctx sdk.Context, cdc codec.JSONCodec) map[string]json.RawMessage { genesisData := make(map[string]json.RawMessage) for _, moduleName := range m.OrderExportGenesis { genesisData[moduleName] = m.Modules[moduleName].ExportGenesis(ctx, cdc) @@ -339,11 +345,29 @@ func (m *Manager) ExportGenesis(ctx sdk.Context, cdc codec.JSONMarshaler) map[st return genesisData } +// assertNoForgottenModules checks that we didn't forget any modules in the +// SetOrder* functions. +func (m *Manager) assertNoForgottenModules(setOrderFnName string, moduleNames []string) { + ms := make(map[string]bool) + for _, m := range moduleNames { + ms[m] = true + } + var missing []string + for m := range m.Modules { + if !ms[m] { + missing = append(missing, m) + } + } + if len(missing) != 0 { + panic(fmt.Sprintf( + "%s: all modules must be defined when setting SetOrderMigrations, missing: %v", setOrderFnName, missing)) + } +} + // MigrationHandler is the migration function that each module registers. type MigrationHandler func(sdk.Context) error -// VersionMap is a map of moduleName -> version, where version denotes the -// version from which we should perform the migration for each module. +// VersionMap is a map of moduleName -> version type VersionMap map[string]uint64 // RunMigrations performs in-place store migrations for all modules. This @@ -370,6 +394,9 @@ type VersionMap map[string]uint64 // `InitGenesis` on that module. // - return the `updatedVM` to be persisted in the x/upgrade's store. // +// Migrations are run in an order defined by `Manager.OrderMigrations` or (if not set) defined by +// `DefaultMigrationsOrder` function. +// // As an app developer, if you wish to skip running InitGenesis for your new // module "foo", you need to manually pass a `fromVM` argument to this function // foo's module version set to its latest ConsensusVersion. That way, the diff @@ -396,19 +423,13 @@ func (m Manager) RunMigrations(ctx sdk.Context, cfg Configurator, fromVM Version if !ok { return nil, sdkerrors.Wrapf(sdkerrors.ErrInvalidType, "expected %T, got %T", configurator{}, cfg) } - - updatedVM := make(VersionMap) - // for deterministic iteration order - // (as some migrations depend on other modules - // and the order of executing migrations matters) - // TODO: make the order user-configurable? - sortedModNames := make([]string, 0, len(m.Modules)) - for key := range m.Modules { - sortedModNames = append(sortedModNames, key) + var modules = m.OrderMigrations + if modules == nil { + modules = DefaultMigrationsOrder(m.ModuleNames()) } - sort.Strings(sortedModNames) - for _, moduleName := range sortedModNames { + updatedVM := VersionMap{} + for _, moduleName := range modules { module := m.Modules[moduleName] fromVersion, exists := fromVM[moduleName] toVersion := module.ConsensusVersion() @@ -435,6 +456,7 @@ func (m Manager) RunMigrations(ctx sdk.Context, cfg Configurator, fromVM Version } moduleValUpdates := module.InitGenesis(ctx, cfgtor.cdc, module.DefaultGenesis(cfgtor.cdc)) + ctx.Logger().Info(fmt.Sprintf("adding a new module: %s", moduleName)) // The module manager assumes only one module will update the // validator set, and that it will not be by a new module. if len(moduleValUpdates) > 0 { @@ -501,3 +523,35 @@ func (m *Manager) GetVersionMap() VersionMap { return vermap } + +// ModuleNames returns list of all module names, without any particular order. +func (m *Manager) ModuleNames() []string { + ms := make([]string, len(m.Modules)) + i := 0 + for m := range m.Modules { + ms[i] = m + i++ + } + return ms +} + +// DefaultMigrationsOrder returns a default migrations order: ascending alphabetical by module name, +// except x/auth which will run last, see: +// https://github.com/cosmos/cosmos-sdk/issues/10591 +func DefaultMigrationsOrder(modules []string) []string { + const authName = "auth" + out := make([]string, 0, len(modules)) + hasAuth := false + for _, m := range modules { + if m == authName { + hasAuth = true + } else { + out = append(out, m) + } + } + sort.Strings(out) + if hasAuth { + out = append(out, authName) + } + return out +} diff --git a/types/module/module_int_test.go b/types/module/module_int_test.go new file mode 100644 index 0000000000..3301a9926d --- /dev/null +++ b/types/module/module_int_test.go @@ -0,0 +1,57 @@ +package module + +import ( + "sort" + "testing" + + "github.com/stretchr/testify/suite" +) + +func TestModuleIntSuite(t *testing.T) { + suite.Run(t, new(TestSuite)) +} + +type TestSuite struct { + suite.Suite +} + +func (s TestSuite) TestAssertNoForgottenModules() { + m := Manager{ + Modules: map[string]AppModule{"a": nil, "b": nil}, + } + tcs := []struct { + name string + positive bool + modules []string + }{ + {"same modules", true, []string{"a", "b"}}, + {"more modules", true, []string{"a", "b", "c"}}, + } + + for _, tc := range tcs { + if tc.positive { + m.assertNoForgottenModules("x", tc.modules) + } else { + s.Panics(func() { m.assertNoForgottenModules("x", tc.modules) }) + } + } +} + +func (s TestSuite) TestModuleNames() { + m := Manager{ + Modules: map[string]AppModule{"a": nil, "b": nil}, + } + ms := m.ModuleNames() + sort.Strings(ms) + s.Require().Equal([]string{"a", "b"}, ms) +} + +func (s TestSuite) TestDefaultMigrationsOrder() { + require := s.Require() + require.Equal( + []string{"auth2", "d", "z", "auth"}, + DefaultMigrationsOrder([]string{"d", "auth", "auth2", "z"}), "alphabetical, but auth should be last") + require.Equal( + []string{"auth2", "d", "z"}, + DefaultMigrationsOrder([]string{"d", "auth2", "z"}), "alphabetical") +} diff --git a/types/module/simulation.go b/types/module/simulation.go index dbee75a5b3..4daed39cfd 100644 --- a/types/module/simulation.go +++ b/types/module/simulation.go @@ -99,7 +99,7 @@ func (sm *SimulationManager) WeightedOperations(simState SimulationState) []simu // GenesisState generator function type SimulationState struct { AppParams simulation.AppParams - Cdc codec.JSONMarshaler // application codec + Cdc codec.JSONCodec // application codec Rand *rand.Rand // random number GenState map[string]json.RawMessage // genesis state Accounts []simulation.Account // simulation accounts diff --git a/types/msgservice/msg_service.go b/types/msgservice/msg_service.go index 22e5e468a7..4cb767f2b4 100644 --- a/types/msgservice/msg_service.go +++ b/types/msgservice/msg_service.go @@ -4,7 +4,6 @@ import ( "context" "fmt" - "github.com/gogo/protobuf/proto" "google.golang.org/grpc" codectypes "github.com/line/lbm-sdk/codec/types" @@ -23,7 +22,7 @@ func RegisterMsgServiceDesc(registry codectypes.InterfaceRegistry, sd *grpc.Serv // This approach is maybe a bit hacky, but less hacky than reflecting on the handler object itself. // We use a no-op interceptor to avoid actually calling into the handler itself. _, _ = methodHandler(nil, context.Background(), func(i interface{}) error { - msg, ok := i.(proto.Message) + msg, ok := i.(sdk.Msg) if !ok { // We panic here because there is no other alternative and the app cannot be initialized correctly // this should only happen if there is a problem with code generation in which case the app won't @@ -31,7 +30,8 @@ func RegisterMsgServiceDesc(registry codectypes.InterfaceRegistry, sd *grpc.Serv panic(fmt.Errorf("can't register request type %T for service method %s", i, fqMethod)) } - registry.RegisterCustomTypeURL((*sdk.MsgRequest)(nil), fqMethod, msg) + registry.RegisterImplementations((*sdk.Msg)(nil), msg) + return nil }, noopInterceptor) diff --git a/types/query/filtered_pagination.go b/types/query/filtered_pagination.go index 090c83d86a..e1f97ac365 100644 --- a/types/query/filtered_pagination.go +++ b/types/query/filtered_pagination.go @@ -29,6 +29,7 @@ func FilteredPaginate( key := pageRequest.Key limit := pageRequest.Limit countTotal := pageRequest.CountTotal + reverse := pageRequest.Reverse if offset > 0 && key != nil { return nil, fmt.Errorf("invalid request, either offset or key is expected, got both") @@ -42,7 +43,7 @@ func FilteredPaginate( } if len(key) != 0 { - iterator := prefixStore.Iterator(key, nil) + iterator := getIterator(prefixStore, key, reverse) defer iterator.Close() var numHits uint64 @@ -73,7 +74,7 @@ func FilteredPaginate( }, nil } - iterator := prefixStore.Iterator(nil, nil) + iterator := getIterator(prefixStore, nil, reverse) defer iterator.Close() end := offset + limit diff --git a/types/query/filtered_pagination_test.go b/types/query/filtered_pagination_test.go index cbe61b862a..eb493ca0d7 100644 --- a/types/query/filtered_pagination_test.go +++ b/types/query/filtered_pagination_test.go @@ -4,11 +4,11 @@ import ( "fmt" "github.com/line/lbm-sdk/codec" + "github.com/line/lbm-sdk/simapp" "github.com/line/lbm-sdk/store/prefix" sdk "github.com/line/lbm-sdk/types" + "github.com/line/lbm-sdk/types/address" "github.com/line/lbm-sdk/types/query" - authtypes "github.com/line/lbm-sdk/x/auth/types" - "github.com/line/lbm-sdk/x/bank/keeper" "github.com/line/lbm-sdk/x/bank/types" ) @@ -28,11 +28,12 @@ func (s *paginationTestSuite) TestFilteredPaginations() { balances = append(balances, sdk.NewInt64Coin(denom, 250)) } + balances = balances.Sort() addr1 := sdk.BytesToAccAddress([]byte("addr1")) acc1 := app.AccountKeeper.NewAccountWithAddress(ctx, addr1) app.AccountKeeper.SetAccount(ctx, acc1) - s.Require().NoError(app.BankKeeper.SetBalances(ctx, addr1, balances)) - store := ctx.KVStore(app.GetKey(authtypes.StoreKey)) + s.Require().NoError(simapp.FundAccount(app, ctx, addr1, balances)) + store := ctx.KVStore(app.GetKey(types.StoreKey)) // verify pagination with limit > total values pageReq := &query.PageRequest{Key: nil, Limit: 5, CountTotal: true} @@ -88,6 +89,87 @@ func (s *paginationTestSuite) TestFilteredPaginations() { s.Require().LessOrEqual(len(balances), 2) } +func (s *paginationTestSuite) TestReverseFilteredPaginations() { + app, ctx, appCodec := setupTest() + + var balances sdk.Coins + for i := 0; i < numBalances; i++ { + denom := fmt.Sprintf("foo%ddenom", i) + balances = append(balances, sdk.NewInt64Coin(denom, 100)) + } + + for i := 0; i < 10; i++ { + denom := fmt.Sprintf("test%ddenom", i) + balances = append(balances, sdk.NewInt64Coin(denom, 250)) + } + + balances = balances.Sort() + addr1 := sdk.BytesToAccAddress([]byte("addr1")) + acc1 := app.AccountKeeper.NewAccountWithAddress(ctx, addr1) + app.AccountKeeper.SetAccount(ctx, acc1) + s.Require().NoError(simapp.FundAccount(app, ctx, addr1, balances)) + store := ctx.KVStore(app.GetKey(types.StoreKey)) + + // verify pagination with limit > total values + pageReq := &query.PageRequest{Key: nil, Limit: 5, CountTotal: true, Reverse: true} + balns, res, err := execFilterPaginate(store, pageReq, appCodec) + s.Require().NoError(err) + s.Require().NotNil(res) + s.Require().Equal(5, len(balns)) + + s.T().Log("verify empty request") + balns, res, err = execFilterPaginate(store, nil, appCodec) + s.Require().NoError(err) + s.Require().NotNil(res) + s.Require().Equal(10, len(balns)) + s.Require().Equal(uint64(10), res.Total) + s.Require().Nil(res.NextKey) + + s.T().Log("verify default limit") + pageReq = &query.PageRequest{Reverse: true} + balns, res, err = execFilterPaginate(store, pageReq, appCodec) + s.Require().NoError(err) + s.Require().NotNil(res) + s.Require().Equal(10, len(balns)) + s.Require().Equal(uint64(10), res.Total) + + s.T().Log("verify nextKey is returned if there are more results") + pageReq = &query.PageRequest{Limit: 2, CountTotal: true, Reverse: true} + balns, res, err = execFilterPaginate(store, pageReq, appCodec) + s.Require().NoError(err) + s.Require().NotNil(res) + s.Require().Equal(2, len(balns)) + s.Require().NotNil(res.NextKey) + s.Require().Equal(string(res.NextKey), fmt.Sprintf("test7denom")) + s.Require().Equal(uint64(10), res.Total) + + s.T().Log("verify both key and offset can't be given") + pageReq = &query.PageRequest{Key: res.NextKey, Limit: 1, Offset: 2, Reverse: true} + _, _, err = execFilterPaginate(store, pageReq, appCodec) + s.Require().Error(err) + + s.T().Log("use nextKey for query and reverse true") + pageReq = &query.PageRequest{Key: res.NextKey, Limit: 2, Reverse: true} + balns, res, err = execFilterPaginate(store, pageReq, appCodec) + s.Require().NoError(err) + s.Require().NotNil(res) + s.Require().Equal(2, len(balns)) + s.Require().NotNil(res.NextKey) + s.Require().Equal(string(res.NextKey), fmt.Sprintf("test5denom")) + + s.T().Log("verify last page records, nextKey for query and reverse true") + pageReq = &query.PageRequest{Key: res.NextKey, Reverse: true} + balns, res, err = execFilterPaginate(store, pageReq, appCodec) + s.Require().NoError(err) + s.Require().NotNil(res) + s.Require().Equal(6, len(balns)) + s.Require().Nil(res.NextKey) + + s.T().Log("verify Reverse pagination returns valid result") + s.Require().Equal(balances[235:241].String(), balns.Sort().String()) + +} + func ExampleFilteredPaginate() { app, ctx, appCodec := setupTest() @@ -101,23 +183,25 @@ func ExampleFilteredPaginate() { denom := fmt.Sprintf("test%ddenom", i) balances = append(balances, sdk.NewInt64Coin(denom, 250)) } + + balances = balances.Sort() addr1 := sdk.AccAddress([]byte("addr1")) acc1 := app.AccountKeeper.NewAccountWithAddress(ctx, addr1) app.AccountKeeper.SetAccount(ctx, acc1) - err := app.BankKeeper.SetBalances(ctx, addr1, balances) + err := simapp.FundAccount(app, ctx, addr1, balances) if err != nil { // should return no error fmt.Println(err) } pageReq := &query.PageRequest{Key: nil, Limit: 1, CountTotal: true} - store := ctx.KVStore(app.GetKey(authtypes.StoreKey)) + store := ctx.KVStore(app.GetKey(types.StoreKey)) balancesStore := prefix.NewStore(store, types.BalancesPrefix) - accountStore := prefix.NewStore(balancesStore, keeper.AddressToPrefixKey(addr1)) + accountStore := prefix.NewStore(balancesStore, address.MustLengthPrefix(addr1.Bytes())) var balResult sdk.Coins pageRes, err := query.FilteredPaginate(accountStore, pageReq, func(key []byte, value []byte, accumulate bool) (bool, error) { var bal sdk.Coin - err := appCodec.UnmarshalBinaryBare(value, &bal) + err := appCodec.Unmarshal(value, &bal) if err != nil { return false, err } @@ -142,14 +226,14 @@ func ExampleFilteredPaginate() { // balances: pagination: } -func execFilterPaginate(store sdk.KVStore, pageReq *query.PageRequest, appCodec codec.Marshaler) (balances sdk.Coins, res *query.PageResponse, err error) { +func execFilterPaginate(store sdk.KVStore, pageReq *query.PageRequest, appCodec codec.Codec) (balances sdk.Coins, res *query.PageResponse, err error) { balancesStore := prefix.NewStore(store, types.BalancesPrefix) - accountStore := prefix.NewStore(balancesStore, keeper.AddressToPrefixKey(addr1)) + accountStore := prefix.NewStore(balancesStore, address.MustLengthPrefix(addr1.Bytes())) var balResult sdk.Coins res, err = query.FilteredPaginate(accountStore, pageReq, func(key []byte, value []byte, accumulate bool) (bool, error) { var bal sdk.Coin - err := appCodec.UnmarshalBinaryBare(value, &bal) + err := appCodec.Unmarshal(value, &bal) if err != nil { return false, err } diff --git a/types/query/pagination.go b/types/query/pagination.go index 585abaf664..fd4253c586 100644 --- a/types/query/pagination.go +++ b/types/query/pagination.go @@ -2,10 +2,13 @@ package query import ( "fmt" + "math" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" + tmdb "github.com/line/tm-db/v2" + "github.com/line/lbm-sdk/store/types" ) @@ -13,6 +16,10 @@ import ( // if the `limit` is not supplied, paginate will use `DefaultLimit` const DefaultLimit = 100 +// MaxLimit is the maximum limit the paginate function can handle +// which equals the maximum value that can be stored in uint64 +const MaxLimit = math.MaxUint64 + // ParsePagination validate PageRequest and returns page number & limit. func ParsePagination(pageReq *PageRequest) (page, limit int, err error) { offset := 0 @@ -54,6 +61,7 @@ func Paginate( key := pageRequest.Key limit := pageRequest.Limit countTotal := pageRequest.CountTotal + reverse := pageRequest.Reverse if offset > 0 && key != nil { return nil, fmt.Errorf("invalid request, either offset or key is expected, got both") @@ -67,13 +75,14 @@ func Paginate( } if len(key) != 0 { - iterator := prefixStore.Iterator(key, nil) + iterator := getIterator(prefixStore, key, reverse) defer iterator.Close() var count uint64 var nextKey []byte for ; iterator.Valid(); iterator.Next() { + if count == limit { nextKey = iterator.Key() break @@ -94,7 +103,7 @@ func Paginate( }, nil } - iterator := prefixStore.Iterator(nil, nil) + iterator := getIterator(prefixStore, nil, reverse) defer iterator.Close() end := offset + limit @@ -132,3 +141,19 @@ func Paginate( return res, nil } + +func getIterator(prefixStore types.KVStore, start []byte, reverse bool) tmdb.Iterator { + if reverse { + var end []byte + if start != nil { + itr := prefixStore.Iterator(start, nil) + defer itr.Close() + if itr.Valid() { + itr.Next() + end = itr.Key() + } + } + return prefixStore.ReverseIterator(nil, end) + } + return prefixStore.Iterator(start, nil) +} diff --git a/types/query/pagination.pb.go b/types/query/pagination.pb.go index 7b50c9157a..9280b23b90 100644 --- a/types/query/pagination.pb.go +++ b/types/query/pagination.pb.go @@ -46,6 +46,10 @@ type PageRequest struct { // count_total is only respected when offset is used. It is ignored when key // is set. CountTotal bool `protobuf:"varint,4,opt,name=count_total,json=countTotal,proto3" json:"count_total,omitempty"` + // reverse is set to true if results are to be returned in the descending order. + // + // Since: cosmos-sdk 0.43 + Reverse bool `protobuf:"varint,5,opt,name=reverse,proto3" json:"reverse,omitempty"` } func (m *PageRequest) Reset() { *m = PageRequest{} } @@ -109,6 +113,13 @@ func (m *PageRequest) GetCountTotal() bool { return false } +func (m *PageRequest) GetReverse() bool { + if m != nil { + return m.Reverse + } + return false +} + // PageResponse is to be embedded in gRPC response messages where the // corresponding request message has used PageRequest. // @@ -182,24 +193,25 @@ func init() { } var fileDescriptor_c5cf27336d84b692 = []byte{ - // 263 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x44, 0x90, 0xb1, 0x4e, 0xc3, 0x30, - 0x14, 0x45, 0x63, 0x5a, 0x4a, 0xe5, 0x76, 0x00, 0x0b, 0xa1, 0xb0, 0x98, 0x28, 0x2c, 0x59, 0x88, - 0x55, 0x31, 0x23, 0x24, 0x56, 0x16, 0x14, 0x31, 0xb1, 0x54, 0x71, 0x79, 0x0d, 0x56, 0x1d, 0x3b, - 0xad, 0x5f, 0x2a, 0xf2, 0x17, 0x7c, 0x16, 0x63, 0x47, 0x46, 0x94, 0xfc, 0x08, 0x4a, 0x8c, 0xd4, - 0xed, 0x9d, 0xab, 0xab, 0x77, 0xa4, 0x4b, 0x63, 0x2d, 0x4b, 0x21, 0x73, 0x07, 0x62, 0x5b, 0xc3, - 0xae, 0x11, 0xfb, 0x85, 0xa8, 0xf2, 0x42, 0x99, 0x1c, 0x95, 0x35, 0x69, 0xb5, 0xb3, 0x68, 0xd9, - 0x85, 0x96, 0x65, 0xda, 0x77, 0xd2, 0xa1, 0x93, 0xee, 0x17, 0xb1, 0xa1, 0xb3, 0x97, 0xbc, 0x80, - 0x0c, 0xb6, 0x35, 0x38, 0x64, 0xe7, 0x74, 0xb4, 0x81, 0x26, 0x24, 0x11, 0x49, 0xe6, 0x59, 0x7f, - 0xb2, 0x2b, 0x3a, 0xb1, 0xeb, 0xb5, 0x03, 0x0c, 0x4f, 0x22, 0x92, 0x8c, 0xb3, 0x7f, 0x62, 0x97, - 0xf4, 0x54, 0xab, 0x52, 0x61, 0x38, 0x1a, 0x62, 0x0f, 0xec, 0x86, 0xce, 0x56, 0xb6, 0x36, 0xb8, - 0x44, 0x8b, 0xb9, 0x0e, 0xc7, 0x11, 0x49, 0xa6, 0x19, 0x1d, 0xa2, 0xd7, 0x3e, 0x89, 0x1f, 0xe9, - 0xdc, 0xfb, 0x5c, 0x65, 0x8d, 0x03, 0x76, 0x4d, 0xa7, 0x06, 0x3e, 0x71, 0x79, 0xb4, 0x9e, 0xf5, - 0xfc, 0x0c, 0x4d, 0x6f, 0xf0, 0x5f, 0xbc, 0xd8, 0xc3, 0xd3, 0xc3, 0x77, 0xcb, 0xc9, 0xa1, 0xe5, - 0xe4, 0xb7, 0xe5, 0xe4, 0xab, 0xe3, 0xc1, 0xa1, 0xe3, 0xc1, 0x4f, 0xc7, 0x83, 0xb7, 0xdb, 0x42, - 0xe1, 0x47, 0x2d, 0xd3, 0x95, 0x2d, 0x85, 0x56, 0x06, 0x84, 0x96, 0xe5, 0x9d, 0x7b, 0xdf, 0x08, - 0x6c, 0x2a, 0x70, 0x7e, 0x16, 0x39, 0x19, 0x96, 0xb8, 0xff, 0x0b, 0x00, 0x00, 0xff, 0xff, 0x50, - 0xf9, 0xf6, 0x7e, 0x2f, 0x01, 0x00, 0x00, + // 280 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x44, 0x90, 0xbf, 0x4e, 0xf3, 0x30, + 0x14, 0xc5, 0xeb, 0xaf, 0x7f, 0xe5, 0x76, 0xf8, 0xb0, 0x10, 0x32, 0x8b, 0x89, 0xc2, 0x92, 0x85, + 0x58, 0x15, 0x33, 0x42, 0x62, 0x65, 0x41, 0x11, 0x13, 0x4b, 0x15, 0x97, 0xdb, 0x60, 0xd5, 0xb1, + 0xd3, 0xd8, 0x89, 0xc8, 0x1b, 0x30, 0xf2, 0x58, 0x8c, 0x1d, 0x19, 0x51, 0xf2, 0x22, 0x28, 0x31, + 0x88, 0xed, 0xfe, 0xce, 0x3d, 0xba, 0xf7, 0xe8, 0xe0, 0x50, 0x89, 0x9c, 0x8b, 0xd4, 0x02, 0x3f, + 0x54, 0x50, 0x36, 0xbc, 0x5e, 0xf3, 0x22, 0xcd, 0xa4, 0x4e, 0x9d, 0x34, 0x3a, 0x2e, 0x4a, 0xe3, + 0x0c, 0x39, 0x51, 0x22, 0x8f, 0x7b, 0x4f, 0x3c, 0x78, 0xe2, 0x7a, 0x1d, 0xbe, 0x21, 0xbc, 0x7c, + 0x48, 0x33, 0x48, 0xe0, 0x50, 0x81, 0x75, 0xe4, 0x3f, 0x1e, 0xef, 0xa1, 0xa1, 0x28, 0x40, 0xd1, + 0x2a, 0xe9, 0x47, 0x72, 0x86, 0x67, 0x66, 0xb7, 0xb3, 0xe0, 0xe8, 0xbf, 0x00, 0x45, 0x93, 0xe4, + 0x87, 0xc8, 0x29, 0x9e, 0x2a, 0x99, 0x4b, 0x47, 0xc7, 0x83, 0xec, 0x81, 0x5c, 0xe0, 0xe5, 0xd6, + 0x54, 0xda, 0x6d, 0x9c, 0x71, 0xa9, 0xa2, 0x93, 0x00, 0x45, 0x8b, 0x04, 0x0f, 0xd2, 0x63, 0xaf, + 0x10, 0x8a, 0xe7, 0x25, 0xd4, 0x50, 0x5a, 0xa0, 0xd3, 0x61, 0xf9, 0x8b, 0xe1, 0x2d, 0x5e, 0xf9, + 0x24, 0xb6, 0x30, 0xda, 0x02, 0x39, 0xc7, 0x0b, 0x0d, 0xaf, 0x6e, 0xf3, 0x97, 0x67, 0xde, 0xf3, + 0x3d, 0x34, 0xfd, 0x6f, 0x7f, 0xdf, 0x47, 0xf2, 0x70, 0x77, 0xf3, 0xd1, 0x32, 0x74, 0x6c, 0x19, + 0xfa, 0x6a, 0x19, 0x7a, 0xef, 0xd8, 0xe8, 0xd8, 0xb1, 0xd1, 0x67, 0xc7, 0x46, 0x4f, 0x97, 0x99, + 0x74, 0x2f, 0x95, 0x88, 0xb7, 0x26, 0xe7, 0x4a, 0x6a, 0xe0, 0x4a, 0xe4, 0x57, 0xf6, 0x79, 0xcf, + 0x5d, 0x53, 0x80, 0xf5, 0x8d, 0x89, 0xd9, 0x50, 0xd2, 0xf5, 0x77, 0x00, 0x00, 0x00, 0xff, 0xff, + 0x4d, 0x00, 0x38, 0x37, 0x4a, 0x01, 0x00, 0x00, } func (m *PageRequest) Marshal() (dAtA []byte, err error) { @@ -222,6 +234,16 @@ func (m *PageRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if m.Reverse { + i-- + if m.Reverse { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x28 + } if m.CountTotal { i-- if m.CountTotal { @@ -317,6 +339,9 @@ func (m *PageRequest) Size() (n int) { if m.CountTotal { n += 2 } + if m.Reverse { + n += 2 + } return n } @@ -463,6 +488,26 @@ func (m *PageRequest) Unmarshal(dAtA []byte) error { } } m.CountTotal = bool(v != 0) + case 5: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Reverse", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPagination + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.Reverse = bool(v != 0) default: iNdEx = preIndex skippy, err := skipPagination(dAtA[iNdEx:]) diff --git a/types/query/pagination_test.go b/types/query/pagination_test.go index 2463a97ec8..cad8384d87 100644 --- a/types/query/pagination_test.go +++ b/types/query/pagination_test.go @@ -17,10 +17,8 @@ import ( "github.com/line/lbm-sdk/store" "github.com/line/lbm-sdk/store/prefix" sdk "github.com/line/lbm-sdk/types" + "github.com/line/lbm-sdk/types/address" "github.com/line/lbm-sdk/types/query" - authkeeper "github.com/line/lbm-sdk/x/auth/keeper" - authtypes "github.com/line/lbm-sdk/x/auth/types" - bankkeeper "github.com/line/lbm-sdk/x/bank/keeper" "github.com/line/lbm-sdk/x/bank/types" ) @@ -75,10 +73,11 @@ func (s *paginationTestSuite) TestPagination() { balances = append(balances, sdk.NewInt64Coin(denom, 100)) } + balances = balances.Sort() addr1 := sdk.BytesToAccAddress(secp256k1.GenPrivKey().PubKey().Address()) acc1 := app.AccountKeeper.NewAccountWithAddress(ctx, addr1) app.AccountKeeper.SetAccount(ctx, acc1) - s.Require().NoError(app.BankKeeper.SetBalances(ctx, addr1, balances)) + s.Require().NoError(simapp.FundAccount(app, ctx, addr1, balances)) s.T().Log("verify empty page request results a max of defaultLimit records and counts total records") pageReq := &query.PageRequest{} @@ -170,6 +169,130 @@ func (s *paginationTestSuite) TestPagination() { s.Require().Nil(res.Pagination.NextKey) } +func (s *paginationTestSuite) TestReversePagination() { + app, ctx, _ := setupTest() + queryHelper := baseapp.NewQueryServerTestHelper(ctx, app.InterfaceRegistry()) + types.RegisterQueryServer(queryHelper, app.BankKeeper) + queryClient := types.NewQueryClient(queryHelper) + + var balances sdk.Coins + + for i := 0; i < numBalances; i++ { + denom := fmt.Sprintf("foo%ddenom", i) + balances = append(balances, sdk.NewInt64Coin(denom, 100)) + } + + balances = balances.Sort() + addr1 := sdk.BytesToAccAddress(secp256k1.GenPrivKey().PubKey().Address()) + acc1 := app.AccountKeeper.NewAccountWithAddress(ctx, addr1) + app.AccountKeeper.SetAccount(ctx, acc1) + s.Require().NoError(simapp.FundAccount(app, ctx, addr1, balances)) + + s.T().Log("verify paginate with custom limit and countTotal, Reverse false") + pageReq := &query.PageRequest{Limit: 2, CountTotal: true, Reverse: true, Key: nil} + request := types.NewQueryAllBalancesRequest(addr1, pageReq) + res1, err := queryClient.AllBalances(gocontext.Background(), request) + s.Require().NoError(err) + s.Require().Equal(res1.Balances.Len(), 2) + s.Require().NotNil(res1.Pagination.NextKey) + + s.T().Log("verify paginate with custom limit and countTotal, Reverse false") + pageReq = &query.PageRequest{Limit: 150} + request = types.NewQueryAllBalancesRequest(addr1, pageReq) + res1, err = queryClient.AllBalances(gocontext.Background(), request) + s.Require().NoError(err) + s.Require().Equal(res1.Balances.Len(), 150) + s.Require().NotNil(res1.Pagination.NextKey) + s.Require().Equal(res1.Pagination.Total, uint64(0)) + + s.T().Log("verify paginate with custom limit, key and Reverse true") + pageReq = &query.PageRequest{Limit: defaultLimit, Reverse: true} + request = types.NewQueryAllBalancesRequest(addr1, pageReq) + res, err := queryClient.AllBalances(gocontext.Background(), request) + s.Require().NoError(err) + s.Require().Equal(res.Balances.Len(), defaultLimit) + s.Require().NotNil(res.Pagination.NextKey) + s.Require().Equal(res.Pagination.Total, uint64(0)) + + s.T().Log("verify paginate with custom limit, key and Reverse true") + pageReq = &query.PageRequest{Offset: 100, Limit: defaultLimit, Reverse: true} + request = types.NewQueryAllBalancesRequest(addr1, pageReq) + res, err = queryClient.AllBalances(gocontext.Background(), request) + s.Require().NoError(err) + s.Require().Equal(res.Balances.Len(), defaultLimit) + s.Require().NotNil(res.Pagination.NextKey) + s.Require().Equal(res.Pagination.Total, uint64(0)) + + s.T().Log("verify paginate for last page, Reverse true") + pageReq = &query.PageRequest{Offset: 200, Limit: defaultLimit, Reverse: true} + request = types.NewQueryAllBalancesRequest(addr1, pageReq) + res, err = queryClient.AllBalances(gocontext.Background(), request) + s.Require().NoError(err) + s.Require().Equal(res.Balances.Len(), lastPageRecords) + s.Require().Nil(res.Pagination.NextKey) + s.Require().Equal(res.Pagination.Total, uint64(0)) + + s.T().Log("verify page request with limit > defaultLimit, returns less or equal to `limit` records") + pageReq = &query.PageRequest{Limit: overLimit, Reverse: true} + request = types.NewQueryAllBalancesRequest(addr1, pageReq) + res, err = queryClient.AllBalances(gocontext.Background(), request) + s.Require().NoError(err) + s.Require().Equal(res.Pagination.Total, uint64(0)) + s.Require().NotNil(res.Pagination.NextKey) + s.Require().LessOrEqual(res.Balances.Len(), overLimit) + + s.T().Log("verify paginate with custom limit, key, countTotal false and Reverse true") + pageReq = &query.PageRequest{Key: res1.Pagination.NextKey, Limit: 50, Reverse: true} + request = types.NewQueryAllBalancesRequest(addr1, pageReq) + res, err = queryClient.AllBalances(gocontext.Background(), request) + s.Require().NoError(err) + s.Require().Equal(res.Balances.Len(), 50) + s.Require().NotNil(res.Pagination.NextKey) + s.Require().Equal(res.Pagination.Total, uint64(0)) + + s.T().Log("verify Reverse pagination returns valid result") + s.Require().Equal(balances[101:151].String(), res.Balances.Sort().String()) + + s.T().Log("verify paginate with custom limit, key, countTotal false and Reverse true") + pageReq = &query.PageRequest{Key: res.Pagination.NextKey, Limit: 50, Reverse: true} + request = types.NewQueryAllBalancesRequest(addr1, pageReq) + res, err = queryClient.AllBalances(gocontext.Background(), request) + s.Require().NoError(err) + s.Require().Equal(res.Balances.Len(), 50) + s.Require().NotNil(res.Pagination.NextKey) + s.Require().Equal(res.Pagination.Total, uint64(0)) + + s.T().Log("verify Reverse pagination returns valid result") + s.Require().Equal(balances[51:101].String(), res.Balances.Sort().String()) + + s.T().Log("verify paginate for last page Reverse true") + pageReq = &query.PageRequest{Key: res.Pagination.NextKey, Limit: defaultLimit, Reverse: true} + request = types.NewQueryAllBalancesRequest(addr1, pageReq) + res, err = queryClient.AllBalances(gocontext.Background(), request) + s.Require().NoError(err) + s.Require().Equal(res.Balances.Len(), 51) + s.Require().Nil(res.Pagination.NextKey) + s.Require().Equal(res.Pagination.Total, uint64(0)) + + s.T().Log("verify Reverse pagination returns valid result") + s.Require().Equal(balances[0:51].String(), res.Balances.Sort().String()) + + s.T().Log("verify paginate with offset and key - error") + pageReq = &query.PageRequest{Key: res1.Pagination.NextKey, Offset: 100, Limit: defaultLimit, CountTotal: false} + request = types.NewQueryAllBalancesRequest(addr1, pageReq) + res, err = queryClient.AllBalances(gocontext.Background(), request) + s.Require().Error(err) + s.Require().Equal("rpc error: code = InvalidArgument desc = paginate: invalid request, either offset or key is expected, got both", err.Error()) + + s.T().Log("verify paginate with offset greater than total results") + pageReq = &query.PageRequest{Offset: 300, Limit: defaultLimit, CountTotal: false, Reverse: true} + request = types.NewQueryAllBalancesRequest(addr1, pageReq) + res, err = queryClient.AllBalances(gocontext.Background(), request) + s.Require().NoError(err) + s.Require().LessOrEqual(res.Balances.Len(), 0) + s.Require().Nil(res.Pagination.NextKey) +} + func ExamplePaginate() { app, ctx, _ := setupTest() @@ -180,23 +303,24 @@ func ExamplePaginate() { balances = append(balances, sdk.NewInt64Coin(denom, 100)) } + balances = balances.Sort() addr1 := sdk.AccAddress([]byte("addr1")) acc1 := app.AccountKeeper.NewAccountWithAddress(ctx, addr1) app.AccountKeeper.SetAccount(ctx, acc1) - err := app.BankKeeper.SetBalances(ctx, addr1, balances) - if err != nil { + err := simapp.FundAccount(app, ctx, addr1, balances) + if err != nil { // should return no error fmt.Println(err) } // Paginate example pageReq := &query.PageRequest{Key: nil, Limit: 1, CountTotal: true} request := types.NewQueryAllBalancesRequest(addr1, pageReq) balResult := sdk.NewCoins() - authStore := ctx.KVStore(app.GetKey(authtypes.StoreKey)) + authStore := ctx.KVStore(app.GetKey(types.StoreKey)) balancesStore := prefix.NewStore(authStore, types.BalancesPrefix) - accountStore := prefix.NewStore(balancesStore, bankkeeper.AddressToPrefixKey(addr1)) + accountStore := prefix.NewStore(balancesStore, address.MustLengthPrefix(addr1.Bytes())) pageRes, err := query.Paginate(accountStore, request.Pagination, func(key []byte, value []byte) error { var tempRes sdk.Coin - err := app.AppCodec().UnmarshalBinaryBare(value, &tempRes) + err := app.AppCodec().Unmarshal(value, &tempRes) if err != nil { return err } @@ -211,7 +335,7 @@ func ExamplePaginate() { // balances: pagination: } -func setupTest() (*simapp.SimApp, sdk.Context, codec.Marshaler) { +func setupTest() (*simapp.SimApp, sdk.Context, codec.Codec) { app := simapp.Setup(false) ctx := app.BaseApp.NewContext(false, ocproto.Header{Height: 1}) appCodec := app.AppCodec() @@ -221,20 +345,5 @@ func setupTest() (*simapp.SimApp, sdk.Context, codec.Marshaler) { ms.LoadLatestVersion() - maccPerms := simapp.GetMaccPerms() - maccPerms[holder] = nil - maccPerms[authtypes.Burner] = []string{authtypes.Burner} - maccPerms[authtypes.Minter] = []string{authtypes.Minter} - maccPerms[multiPerm] = []string{authtypes.Burner, authtypes.Minter, authtypes.Staking} - maccPerms[randomPerm] = []string{"random"} - app.AccountKeeper = authkeeper.NewAccountKeeper( - appCodec, app.GetKey(authtypes.StoreKey), app.GetSubspace(authtypes.ModuleName), - authtypes.ProtoBaseAccount, maccPerms, - ) - app.BankKeeper = bankkeeper.NewBaseKeeper( - appCodec, app.GetKey(authtypes.StoreKey), app.AccountKeeper, - app.GetSubspace(types.ModuleName), make(map[string]bool), - ) - return app, ctx, appCodec } diff --git a/types/rest/rest.go b/types/rest/rest.go index 636bcfcc93..f280bdfe0d 100644 --- a/types/rest/rest.go +++ b/types/rest/rest.go @@ -133,7 +133,7 @@ func (br BaseReq) ValidateBasic(w http.ResponseWriter) bool { } // ReadRESTReq reads and unmarshals a Request's body to the the BaseReq struct. -// Writes an error response to ResponseWriter and returns true if errors occurred. +// Writes an error response to ResponseWriter and returns false if errors occurred. func ReadRESTReq(w http.ResponseWriter, r *http.Request, cdc *codec.LegacyAmino, req interface{}) bool { body, err := ioutil.ReadAll(r.Body) if CheckBadRequestError(w, err) { diff --git a/types/result.go b/types/result.go index 6c2dd38605..52f2b64c1a 100644 --- a/types/result.go +++ b/types/result.go @@ -7,6 +7,7 @@ import ( "strings" "github.com/gogo/protobuf/proto" + abci "github.com/line/ostracon/abci/types" ctypes "github.com/line/ostracon/rpc/core/types" diff --git a/types/service_msg.go b/types/service_msg.go deleted file mode 100644 index 648fc1d64b..0000000000 --- a/types/service_msg.go +++ /dev/null @@ -1,58 +0,0 @@ -package types - -import ( - "github.com/gogo/protobuf/proto" -) - -// MsgRequest is the interface a transaction message, defined as a proto -// service method, must fulfill. -type MsgRequest interface { - proto.Message - // ValidateBasic does a simple validation check that - // doesn't require access to any other information. - ValidateBasic() error - // Signers returns the addrs of signers that must sign. - // CONTRACT: All signatures must be present to be valid. - // CONTRACT: Returns addrs in some deterministic order. - GetSigners() []AccAddress -} - -// ServiceMsg is the struct into which an Any whose typeUrl matches a service -// method format (ex. `/lbm.gov.Msg/SubmitProposal`) unpacks. -type ServiceMsg struct { - // MethodName is the fully-qualified service method name. - MethodName string - // Request is the request payload. - Request MsgRequest -} - -var _ Msg = ServiceMsg{} - -func (msg ServiceMsg) ProtoMessage() {} -func (msg ServiceMsg) Reset() {} -func (msg ServiceMsg) String() string { return "ServiceMsg" } - -// Route implements Msg.Route method. -func (msg ServiceMsg) Route() string { - return msg.MethodName -} - -// ValidateBasic implements Msg.ValidateBasic method. -func (msg ServiceMsg) ValidateBasic() error { - return msg.Request.ValidateBasic() -} - -// GetSignBytes implements Msg.GetSignBytes method. -func (msg ServiceMsg) GetSignBytes() []byte { - panic("ServiceMsg does not have a GetSignBytes method") -} - -// GetSigners implements Msg.GetSigners method. -func (msg ServiceMsg) GetSigners() []AccAddress { - return msg.Request.GetSigners() -} - -// Type implements Msg.Type method. -func (msg ServiceMsg) Type() string { - return msg.MethodName -} diff --git a/types/simulation/types.go b/types/simulation/types.go index c70bffd4cc..36333af47b 100644 --- a/types/simulation/types.go +++ b/types/simulation/types.go @@ -8,6 +8,7 @@ import ( "github.com/line/lbm-sdk/baseapp" "github.com/line/lbm-sdk/codec" sdk "github.com/line/lbm-sdk/types" + "github.com/line/lbm-sdk/x/auth/legacy/legacytx" ) type WeightedProposalContent interface { @@ -75,8 +76,15 @@ func NewOperationMsgBasic(route, name, comment string, ok bool, msg []byte) Oper } // NewOperationMsg - create a new operation message from sdk.Msg -func NewOperationMsg(msg sdk.Msg, ok bool, comment string) OperationMsg { - return NewOperationMsgBasic(msg.Route(), msg.Type(), comment, ok, msg.GetSignBytes()) +func NewOperationMsg(msg sdk.Msg, ok bool, comment string, cdc *codec.ProtoCodec) OperationMsg { + if legacyMsg, okType := msg.(legacytx.LegacyMsg); okType { + return NewOperationMsgBasic(legacyMsg.Route(), legacyMsg.Type(), comment, ok, legacyMsg.GetSignBytes()) + } + + bz := cdc.MustMarshalJSON(msg) + + return NewOperationMsgBasic(sdk.MsgTypeURL(msg), sdk.MsgTypeURL(msg), comment, ok, bz) + } // NoOpMsg - create a no-operation message @@ -114,8 +122,6 @@ func (om OperationMsg) LogEvent(eventLogger func(route, op, evResult string)) { eventLogger(om.Route, om.Name, pass) } -// ________________________________________________________________________ - // FutureOperation is an operation which will be ran at the beginning of the // provided BlockHeight. If both a BlockHeight and BlockTime are specified, it // will use the BlockHeight. In the (likely) event that multiple operations @@ -135,7 +141,7 @@ type AppParams map[string]json.RawMessage // object. If it exists, it'll be decoded and returned. Otherwise, the provided // ParamSimulator is used to generate a random value or default value (eg: in the // case of operation weights where Rand is not used). -func (sp AppParams) GetOrGenerate(_ codec.JSONMarshaler, key string, ptr interface{}, r *rand.Rand, ps ParamSimulator) { +func (sp AppParams) GetOrGenerate(_ codec.JSONCodec, key string, ptr interface{}, r *rand.Rand, ps ParamSimulator) { if v, ok := sp[key]; ok && v != nil { err := json.Unmarshal(v, ptr) if err != nil { diff --git a/types/staking.go b/types/staking.go index 0753d808b2..2f17bb1dd8 100644 --- a/types/staking.go +++ b/types/staking.go @@ -1,9 +1,5 @@ package types -import ( - "math/big" -) - // staking constants const ( @@ -22,15 +18,15 @@ const ( ValidatorUpdateDelay int64 = 1 ) -// PowerReduction is the amount of staking tokens required for 1 unit of consensus-engine power -var PowerReduction = NewIntFromBigInt(new(big.Int).Exp(big.NewInt(10), big.NewInt(6), nil)) +// DefaultPowerReduction is the default amount of staking tokens required for 1 unit of consensus-engine power +var DefaultPowerReduction = NewIntFromUint64(1000000) // TokensToConsensusPower - convert input tokens to potential consensus-engine power -func TokensToConsensusPower(tokens Int) int64 { - return (tokens.Quo(PowerReduction)).Int64() +func TokensToConsensusPower(tokens Int, powerReduction Int) int64 { + return (tokens.Quo(powerReduction)).Int64() } // TokensFromConsensusPower - convert input power to tokens -func TokensFromConsensusPower(power int64) Int { - return NewInt(power).Mul(PowerReduction) +func TokensFromConsensusPower(power int64, powerReduction Int) Int { + return NewInt(power).Mul(powerReduction) } diff --git a/types/staking_test.go b/types/staking_test.go index 27a7de32ea..bfef2558b1 100644 --- a/types/staking_test.go +++ b/types/staking_test.go @@ -21,6 +21,6 @@ func (s *stakingTestSuite) SetupSuite() { } func (s *stakingTestSuite) TestTokensToConsensusPower() { - s.Require().Equal(int64(0), sdk.TokensToConsensusPower(sdk.NewInt(999_999))) - s.Require().Equal(int64(1), sdk.TokensToConsensusPower(sdk.NewInt(1_000_000))) + s.Require().Equal(int64(0), sdk.TokensToConsensusPower(sdk.NewInt(999_999), sdk.DefaultPowerReduction)) + s.Require().Equal(int64(1), sdk.TokensToConsensusPower(sdk.NewInt(1_000_000), sdk.DefaultPowerReduction)) } diff --git a/types/store.go b/types/store.go index 16d05fb3cc..f835849408 100644 --- a/types/store.go +++ b/types/store.go @@ -1,6 +1,10 @@ package types import ( + fmt "fmt" + "sort" + "strings" + "github.com/line/lbm-sdk/store/types" "github.com/line/lbm-sdk/types/kv" ) @@ -65,31 +69,67 @@ type ( type StoreType = types.StoreType const ( - StoreTypeMulti = types.StoreTypeMulti - StoreTypeDB = types.StoreTypeDB - StoreTypeIAVL = types.StoreTypeIAVL - StoreTypeMemory = types.StoreTypeMemory + StoreTypeMulti = types.StoreTypeMulti + StoreTypeDB = types.StoreTypeDB + StoreTypeIAVL = types.StoreTypeIAVL + StoreTypeTransient = types.StoreTypeTransient + StoreTypeMemory = types.StoreTypeMemory ) type ( - StoreKey = types.StoreKey - CapabilityKey = types.CapabilityKey - KVStoreKey = types.KVStoreKey - MemoryStoreKey = types.MemoryStoreKey + StoreKey = types.StoreKey + CapabilityKey = types.CapabilityKey + KVStoreKey = types.KVStoreKey + TransientStoreKey = types.TransientStoreKey + MemoryStoreKey = types.MemoryStoreKey ) +// assertNoCommonPrefix will panic if there are two keys: k1 and k2 in keys, such that +// k1 is a prefix of k2 +func assertNoPrefix(keys []string) { + sorted := make([]string, len(keys)) + copy(sorted, keys) + sort.Strings(sorted) + for i := 1; i < len(sorted); i++ { + if strings.HasPrefix(sorted[i], sorted[i-1]) { + panic(fmt.Sprint("Potential key collision between KVStores:", sorted[i], " - ", sorted[i-1])) + } + } +} + // NewKVStoreKey returns a new pointer to a KVStoreKey. -// Use a pointer so keys don't collide. func NewKVStoreKey(name string) *KVStoreKey { return types.NewKVStoreKey(name) } // NewKVStoreKeys returns a map of new pointers to KVStoreKey's. -// Uses pointers so keys don't collide. +// The function will panic if there is a potential conflict in names (see `assertNoPrefix` +// function for more details). func NewKVStoreKeys(names ...string) map[string]*KVStoreKey { - keys := make(map[string]*KVStoreKey) - for _, name := range names { - keys[name] = NewKVStoreKey(name) + assertNoPrefix(names) + keys := make(map[string]*KVStoreKey, len(names)) + for _, n := range names { + keys[n] = NewKVStoreKey(n) + } + + return keys +} + +// Constructs new TransientStoreKey +// Must return a pointer according to the ocap principle +func NewTransientStoreKey(name string) *types.TransientStoreKey { + return types.NewTransientStoreKey(name) +} + +// NewTransientStoreKeys constructs a new map of TransientStoreKey's +// Must return pointers according to the ocap principle +// The function will panic if there is a potential conflict in names (see `assertNoPrefix` +// function for more details). +func NewTransientStoreKeys(names ...string) map[string]*TransientStoreKey { + assertNoPrefix(names) + keys := make(map[string]*TransientStoreKey) + for _, n := range names { + keys[n] = NewTransientStoreKey(n) } return keys @@ -97,10 +137,13 @@ func NewKVStoreKeys(names ...string) map[string]*KVStoreKey { // NewMemoryStoreKeys constructs a new map matching store key names to their // respective MemoryStoreKey references. +// The function will panic if there is a potential conflict in names (see `assertNoPrefix` +// function for more details). func NewMemoryStoreKeys(names ...string) map[string]*MemoryStoreKey { + assertNoPrefix(names) keys := make(map[string]*MemoryStoreKey) - for _, name := range names { - keys[name] = types.NewMemoryStoreKey(name) + for _, n := range names { + keys[n] = types.NewMemoryStoreKey(n) } return keys diff --git a/types/store_internal_test.go b/types/store_internal_test.go new file mode 100644 index 0000000000..0ed4db3ae4 --- /dev/null +++ b/types/store_internal_test.go @@ -0,0 +1,57 @@ +package types + +import ( + "testing" + + "github.com/stretchr/testify/suite" +) + +type storeIntSuite struct { + suite.Suite +} + +func TestStoreIntSuite(t *testing.T) { + suite.Run(t, new(storeIntSuite)) +} + +func (s *storeIntSuite) TestAssertNoPrefix() { + var testCases = []struct { + keys []string + expectPanic bool + }{ + {[]string{""}, false}, + {[]string{"a"}, false}, + {[]string{"a", "b"}, false}, + {[]string{"a", "b1"}, false}, + {[]string{"b2", "b1"}, false}, + {[]string{"b1", "bb", "b2"}, false}, + + {[]string{"a", ""}, true}, + {[]string{"a", "b", "a"}, true}, + {[]string{"a", "b", "aa"}, true}, + {[]string{"a", "b", "ab"}, true}, + {[]string{"a", "b1", "bb", "b12"}, true}, + } + + require := s.Require() + for _, tc := range testCases { + if tc.expectPanic { + require.Panics(func() { assertNoPrefix(tc.keys) }) + } else { + assertNoPrefix(tc.keys) + } + } +} + +func (s *storeIntSuite) TestNewKVStoreKeys() { + require := s.Require() + require.Panics(func() { NewKVStoreKeys("a1", "a") }, "should fail one key is a prefix of another one") + + require.Equal(map[string]*KVStoreKey{}, NewKVStoreKeys()) + require.Equal(1, len(NewKVStoreKeys("one"))) + + key := "baca" + stores := NewKVStoreKeys(key, "a") + require.Len(stores, 2) + require.Equal(key, stores[key].Name()) +} diff --git a/types/store_test.go b/types/store_test.go index 059e4407e1..ddee01b5ce 100644 --- a/types/store_test.go +++ b/types/store_test.go @@ -55,9 +55,9 @@ func (s *storeTestSuite) TestCommitID() { s.Require().False(nonempty.IsZero()) } -func (s *storeTestSuite) TestNewKVStoreKeys() { - s.Require().Equal(map[string]*sdk.KVStoreKey{}, sdk.NewKVStoreKeys()) - s.Require().Equal(1, len(sdk.NewKVStoreKeys("one"))) +func (s *storeTestSuite) TestNewTransientStoreKeys() { + s.Require().Equal(map[string]*sdk.TransientStoreKey{}, sdk.NewTransientStoreKeys()) + s.Require().Equal(1, len(sdk.NewTransientStoreKeys("one"))) } func (s *storeTestSuite) TestNewInfiniteGasMeter() { diff --git a/types/tx/service.pb.go b/types/tx/service.pb.go index db7e11b696..e17e3cd61d 100644 --- a/types/tx/service.pb.go +++ b/types/tx/service.pb.go @@ -348,7 +348,12 @@ func (m *BroadcastTxResponse) GetTxResponse() *types.TxResponse { // RPC method. type SimulateRequest struct { // tx is the transaction to simulate. - Tx *Tx `protobuf:"bytes,1,opt,name=tx,proto3" json:"tx,omitempty"` + // Deprecated. Send raw tx bytes instead. + Tx *Tx `protobuf:"bytes,1,opt,name=tx,proto3" json:"tx,omitempty"` // Deprecated: Do not use. + // tx_bytes is the raw transaction. + // + // Since: cosmos-sdk 0.43 + TxBytes []byte `protobuf:"bytes,2,opt,name=tx_bytes,json=txBytes,proto3" json:"tx_bytes,omitempty"` } func (m *SimulateRequest) Reset() { *m = SimulateRequest{} } @@ -384,6 +389,7 @@ func (m *SimulateRequest) XXX_DiscardUnknown() { var xxx_messageInfo_SimulateRequest proto.InternalMessageInfo +// Deprecated: Do not use. func (m *SimulateRequest) GetTx() *Tx { if m != nil { return m.Tx @@ -391,6 +397,13 @@ func (m *SimulateRequest) GetTx() *Tx { return nil } +func (m *SimulateRequest) GetTxBytes() []byte { + if m != nil { + return m.TxBytes + } + return nil +} + // SimulateResponse is the response type for the // Service.SimulateRPC method. type SimulateResponse struct { @@ -576,59 +589,59 @@ func init() { proto.RegisterFile("lbm/tx/v1/service.proto", fileDescriptor_a0409 func init() { golang_proto.RegisterFile("lbm/tx/v1/service.proto", fileDescriptor_a0409b56cef7df48) } var fileDescriptor_a0409b56cef7df48 = []byte{ - // 817 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x55, 0xcf, 0x6f, 0xe3, 0x44, - 0x14, 0xae, 0x9d, 0x6e, 0x93, 0xbe, 0xb4, 0xc5, 0x4c, 0xca, 0xd6, 0xcd, 0x6e, 0xbd, 0x91, 0x4f, - 0x51, 0xc5, 0xda, 0xdb, 0xc0, 0x09, 0x89, 0x45, 0xcd, 0x0f, 0x96, 0x0a, 0x76, 0xb3, 0x9a, 0x94, - 0x43, 0x91, 0x50, 0x64, 0x27, 0xb3, 0xae, 0x45, 0xe2, 0xc9, 0x7a, 0x26, 0x91, 0xc3, 0x8f, 0x0b, - 0x7f, 0x01, 0x12, 0x17, 0xfe, 0x0d, 0x6e, 0x1c, 0x39, 0x72, 0x5c, 0x89, 0x0b, 0x47, 0xd4, 0xf0, - 0x87, 0xa0, 0x19, 0x4f, 0x13, 0xe7, 0x47, 0x41, 0x7b, 0xca, 0xcc, 0x7c, 0xef, 0x7d, 0xdf, 0x7b, - 0xdf, 0x8c, 0x5f, 0xe0, 0x68, 0xe0, 0x0f, 0x5d, 0x9e, 0xb8, 0x93, 0x33, 0x97, 0x91, 0x78, 0x12, - 0xf6, 0x88, 0x33, 0x8a, 0x29, 0xa7, 0x68, 0x77, 0xe0, 0x0f, 0x1d, 0x9e, 0x38, 0x93, 0xb3, 0xf2, - 0xc3, 0x80, 0xd2, 0x60, 0x40, 0x5c, 0x6f, 0x14, 0xba, 0x5e, 0x14, 0x51, 0xee, 0xf1, 0x90, 0x46, - 0x2c, 0x0d, 0x2c, 0x3f, 0x10, 0x0c, 0xbe, 0xc7, 0x88, 0xeb, 0xf9, 0xbd, 0x50, 0x10, 0x89, 0x5f, - 0x05, 0xa2, 0x05, 0x3d, 0x4f, 0xd4, 0xd9, 0x61, 0x40, 0x03, 0x2a, 0x97, 0xae, 0x58, 0xa9, 0x53, - 0x7b, 0x4e, 0xf3, 0x7a, 0x4c, 0xe2, 0xa9, 0xc8, 0x18, 0x79, 0x41, 0x18, 0x49, 0xad, 0x34, 0xc6, - 0xfe, 0x55, 0x03, 0xf4, 0x8c, 0xf0, 0xcb, 0x84, 0xb5, 0x26, 0x24, 0xe2, 0x98, 0xbc, 0x1e, 0x13, - 0xc6, 0xd1, 0x7d, 0xd8, 0x21, 0x62, 0xcf, 0x4c, 0xad, 0x92, 0xab, 0xee, 0x62, 0xb5, 0x43, 0x87, - 0x70, 0x6f, 0x14, 0xd3, 0x09, 0x31, 0xf5, 0x8a, 0x56, 0x2d, 0xe0, 0x74, 0x83, 0x9e, 0x02, 0x2c, - 0x88, 0xcd, 0x5c, 0x45, 0xab, 0x16, 0x6b, 0x96, 0x23, 0xba, 0x15, 0xea, 0x8e, 0x54, 0x77, 0x26, - 0x67, 0xce, 0x4b, 0x2f, 0x20, 0x4a, 0x01, 0x67, 0x32, 0xd0, 0x63, 0x28, 0xd0, 0xb8, 0x4f, 0xe2, - 0xae, 0x3f, 0x35, 0xb7, 0x2b, 0x5a, 0xf5, 0xa0, 0x86, 0x9c, 0xb9, 0x57, 0x4e, 0x5b, 0x40, 0xf5, - 0x29, 0xce, 0xd3, 0x74, 0x61, 0xff, 0xa6, 0x41, 0x69, 0xa9, 0x66, 0x36, 0xa2, 0x11, 0x23, 0xe8, - 0x11, 0xe4, 0x78, 0x92, 0x56, 0x5c, 0xac, 0xed, 0x67, 0x18, 0x2e, 0x13, 0x2c, 0x10, 0xf4, 0x09, - 0xec, 0xf1, 0xa4, 0x1b, 0xab, 0x78, 0x66, 0xea, 0x32, 0xf2, 0xe1, 0xa2, 0x52, 0x69, 0x73, 0x9a, - 0xa0, 0x82, 0x70, 0x91, 0xcf, 0xd7, 0x82, 0x60, 0xbd, 0xd1, 0x47, 0x77, 0x36, 0xaa, 0x18, 0x32, - 0x29, 0xf6, 0xd7, 0x80, 0xea, 0x31, 0xf5, 0xfa, 0x3d, 0x8f, 0x71, 0x21, 0x92, 0xba, 0x7d, 0x0c, - 0x05, 0x9e, 0x74, 0xfd, 0x29, 0x27, 0xa2, 0x7a, 0xad, 0xba, 0x87, 0xf3, 0x3c, 0xa9, 0x8b, 0x2d, - 0x7a, 0x1f, 0xb6, 0x87, 0xb4, 0x9f, 0xfa, 0x7d, 0x50, 0x33, 0x33, 0x4d, 0xcd, 0x79, 0x9e, 0xd3, - 0x3e, 0xc1, 0x32, 0xca, 0xbe, 0x84, 0xd2, 0x12, 0xbd, 0x32, 0xe6, 0x63, 0x28, 0x66, 0xfa, 0x96, - 0x12, 0xff, 0xd7, 0x36, 0x2c, 0xda, 0xb6, 0x9f, 0xc0, 0x3b, 0x9d, 0x70, 0x38, 0x1e, 0x78, 0xfc, - 0xf6, 0xf6, 0xd0, 0x09, 0xe8, 0x3c, 0x51, 0x44, 0x2b, 0x4e, 0xeb, 0x3c, 0xb1, 0xbf, 0x05, 0x63, - 0x91, 0xa1, 0x8a, 0xf8, 0x10, 0x0a, 0x81, 0xc7, 0xba, 0x61, 0xf4, 0x8a, 0xaa, 0xc4, 0xe3, 0xf5, - 0x0a, 0x9e, 0x79, 0xec, 0x22, 0x7a, 0x45, 0x71, 0x3e, 0x48, 0x17, 0xe8, 0x09, 0xec, 0xc4, 0x84, - 0x8d, 0x07, 0x5c, 0x3a, 0x50, 0x54, 0x0e, 0x2c, 0xe5, 0x60, 0x89, 0x63, 0x15, 0x67, 0xdb, 0xb0, - 0x27, 0x1f, 0xc7, 0x6d, 0xa9, 0x08, 0xb6, 0xaf, 0x3d, 0x76, 0x2d, 0x35, 0x77, 0xb1, 0x5c, 0xdb, - 0x43, 0xd8, 0x57, 0x31, 0xaa, 0xb8, 0xff, 0xee, 0x67, 0xd5, 0x40, 0xfd, 0xed, 0x0c, 0x3c, 0xfd, - 0x0c, 0xf2, 0xea, 0x11, 0x23, 0x13, 0x0e, 0xdb, 0xb8, 0xd9, 0xc2, 0xdd, 0xfa, 0x55, 0xf7, 0xcb, - 0x17, 0x9d, 0x97, 0xad, 0xc6, 0xc5, 0xa7, 0x17, 0xad, 0xa6, 0xb1, 0x85, 0x0c, 0xd8, 0x9b, 0x23, - 0xe7, 0x9d, 0x86, 0xa1, 0xa1, 0x77, 0x61, 0x7f, 0x7e, 0xd2, 0x6c, 0x75, 0x1a, 0x86, 0x7e, 0xfa, - 0x3d, 0xec, 0x2f, 0xdd, 0x3b, 0xb2, 0xa0, 0x5c, 0xc7, 0xed, 0xf3, 0x66, 0xe3, 0xbc, 0x73, 0xd9, - 0x7d, 0xde, 0x6e, 0xb6, 0x56, 0x58, 0x4d, 0x38, 0x5c, 0xc1, 0xeb, 0x5f, 0xb4, 0x1b, 0x9f, 0x1b, - 0x1a, 0x3a, 0x82, 0xd2, 0x0a, 0xd2, 0xb9, 0x7a, 0xd1, 0x30, 0xf4, 0x0d, 0x29, 0xe7, 0x12, 0xc9, - 0xd5, 0x7e, 0xc9, 0x41, 0xbe, 0x93, 0x8e, 0x34, 0xd4, 0x83, 0xc2, 0xed, 0x15, 0xa3, 0x72, 0xc6, - 0xb1, 0x95, 0x97, 0x52, 0x7e, 0xb0, 0x11, 0x53, 0x2f, 0xcb, 0xfa, 0xf1, 0xcf, 0x7f, 0x7e, 0xd6, - 0x4d, 0xbb, 0xe4, 0x66, 0x66, 0xa6, 0x0a, 0xfa, 0x48, 0x3b, 0x45, 0x57, 0x70, 0x4f, 0xde, 0x13, - 0x3a, 0xca, 0xb0, 0x64, 0x6f, 0xb7, 0x6c, 0xae, 0x03, 0x8a, 0xfb, 0x44, 0x72, 0x1f, 0xa1, 0xf7, - 0xdc, 0xec, 0xc0, 0x64, 0xee, 0x77, 0xe2, 0x05, 0xfc, 0x80, 0x02, 0x28, 0x66, 0x3e, 0x15, 0x74, - 0xb2, 0xe9, 0xcb, 0x5a, 0xc8, 0x58, 0x77, 0xc1, 0x4a, 0xec, 0x58, 0x8a, 0x95, 0xec, 0x83, 0x65, - 0x31, 0xd1, 0x43, 0x1f, 0x8a, 0x99, 0x61, 0xb5, 0x24, 0xb4, 0x3e, 0x78, 0x97, 0x84, 0x36, 0xcc, - 0x38, 0xfb, 0xbe, 0x14, 0x32, 0xd0, 0x8a, 0x50, 0xfd, 0xe9, 0x1f, 0x37, 0x96, 0xf6, 0xe6, 0xc6, - 0xd2, 0xfe, 0xbe, 0xb1, 0xb4, 0x9f, 0x66, 0xd6, 0xd6, 0xef, 0x33, 0x4b, 0x7b, 0x33, 0xb3, 0xb6, - 0xfe, 0x9a, 0x59, 0x5b, 0x5f, 0x55, 0x82, 0x90, 0x5f, 0x8f, 0x7d, 0xa7, 0x47, 0x87, 0xee, 0x20, - 0x8c, 0x88, 0x48, 0x7e, 0xcc, 0xfa, 0xdf, 0xb8, 0x7c, 0x3a, 0x22, 0xcc, 0xe5, 0x89, 0xbf, 0x23, - 0xff, 0x0e, 0x3e, 0xf8, 0x37, 0x00, 0x00, 0xff, 0xff, 0x32, 0x7d, 0x99, 0x3b, 0xbd, 0x06, 0x00, - 0x00, + // 828 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x55, 0x4f, 0x6f, 0xe3, 0x44, + 0x14, 0xaf, 0x9d, 0x6e, 0x93, 0xbe, 0xb4, 0x25, 0x4c, 0xca, 0xd6, 0xcd, 0x6e, 0xbd, 0xc1, 0xa7, + 0xa8, 0x62, 0x6d, 0x1a, 0x38, 0x21, 0xb1, 0xa8, 0x4e, 0xc2, 0x52, 0xc1, 0x6e, 0x56, 0x93, 0x72, + 0x28, 0x12, 0x8a, 0xec, 0x64, 0xd6, 0xb5, 0x48, 0x3c, 0x59, 0xcf, 0x24, 0x72, 0xf8, 0x73, 0xe1, + 0x13, 0x20, 0x71, 0xe1, 0x6b, 0x70, 0xe3, 0xc8, 0x91, 0x63, 0x25, 0x2e, 0x1c, 0x51, 0xcb, 0x07, + 0x41, 0x33, 0x9e, 0x26, 0x76, 0x9a, 0x0a, 0x71, 0xca, 0x9b, 0x79, 0xef, 0xfd, 0x7e, 0xef, 0xf7, + 0xe6, 0xf9, 0x05, 0x0e, 0x46, 0xfe, 0xd8, 0xe1, 0x89, 0x33, 0x3b, 0x71, 0x18, 0x89, 0x67, 0xe1, + 0x80, 0xd8, 0x93, 0x98, 0x72, 0x8a, 0xb6, 0x47, 0xfe, 0xd8, 0xe6, 0x89, 0x3d, 0x3b, 0xa9, 0x3d, + 0x0e, 0x28, 0x0d, 0x46, 0xc4, 0xf1, 0x26, 0xa1, 0xe3, 0x45, 0x11, 0xe5, 0x1e, 0x0f, 0x69, 0xc4, + 0xd2, 0xc0, 0xda, 0x23, 0x81, 0xe0, 0x7b, 0x8c, 0x38, 0x9e, 0x3f, 0x08, 0x05, 0x90, 0xf8, 0x55, + 0x4e, 0xb4, 0x84, 0xe7, 0x89, 0xba, 0xdb, 0x0f, 0x68, 0x40, 0xa5, 0xe9, 0x08, 0x4b, 0xdd, 0x5a, + 0x0b, 0x98, 0x37, 0x53, 0x12, 0xcf, 0x45, 0xc6, 0xc4, 0x0b, 0xc2, 0x48, 0x72, 0xa5, 0x31, 0xd6, + 0xaf, 0x1a, 0xa0, 0xe7, 0x84, 0x9f, 0x27, 0xac, 0x33, 0x23, 0x11, 0xc7, 0xe4, 0xcd, 0x94, 0x30, + 0x8e, 0x1e, 0xc2, 0x16, 0x11, 0x67, 0x66, 0x68, 0xf5, 0x42, 0x63, 0x1b, 0xab, 0x13, 0xda, 0x87, + 0x07, 0x93, 0x98, 0xce, 0x88, 0xa1, 0xd7, 0xb5, 0x46, 0x09, 0xa7, 0x07, 0xf4, 0x0c, 0x60, 0x09, + 0x6c, 0x14, 0xea, 0x5a, 0xa3, 0xdc, 0x34, 0x6d, 0xa1, 0x56, 0xb0, 0xdb, 0x92, 0xdd, 0x9e, 0x9d, + 0xd8, 0xaf, 0xbc, 0x80, 0x28, 0x06, 0x9c, 0xc9, 0x40, 0x4f, 0xa1, 0x44, 0xe3, 0x21, 0x89, 0xfb, + 0xfe, 0xdc, 0xd8, 0xac, 0x6b, 0x8d, 0xbd, 0x26, 0xb2, 0x17, 0xbd, 0xb2, 0xbb, 0xc2, 0xe5, 0xce, + 0x71, 0x91, 0xa6, 0x86, 0xf5, 0x9b, 0x06, 0xd5, 0x5c, 0xcd, 0x6c, 0x42, 0x23, 0x46, 0xd0, 0x13, + 0x28, 0xf0, 0x24, 0xad, 0xb8, 0xdc, 0xdc, 0xcd, 0x20, 0x9c, 0x27, 0x58, 0x78, 0xd0, 0x27, 0xb0, + 0xc3, 0x93, 0x7e, 0xac, 0xe2, 0x99, 0xa1, 0xcb, 0xc8, 0xc7, 0xcb, 0x4a, 0x65, 0x9b, 0xd3, 0x04, + 0x15, 0x84, 0xcb, 0x7c, 0x61, 0x0b, 0x80, 0xbb, 0x42, 0x9f, 0xdc, 0x2b, 0x54, 0x21, 0x64, 0x52, + 0xac, 0xaf, 0x01, 0xb9, 0x31, 0xf5, 0x86, 0x03, 0x8f, 0x71, 0x41, 0x92, 0x76, 0xfb, 0x10, 0x4a, + 0x3c, 0xe9, 0xfb, 0x73, 0x4e, 0x44, 0xf5, 0x5a, 0x63, 0x07, 0x17, 0x79, 0xe2, 0x8a, 0x23, 0x7a, + 0x0f, 0x36, 0xc7, 0x74, 0x98, 0xf6, 0x7b, 0xaf, 0x69, 0x64, 0x44, 0x2d, 0x70, 0x5e, 0xd0, 0x21, + 0xc1, 0x32, 0xca, 0x3a, 0x87, 0x6a, 0x0e, 0x5e, 0x35, 0xe6, 0x63, 0x28, 0x67, 0x74, 0x4b, 0x8a, + 0xff, 0x92, 0x0d, 0x4b, 0xd9, 0x56, 0x17, 0xde, 0xea, 0x85, 0xe3, 0xe9, 0xc8, 0xe3, 0xb7, 0xaf, + 0x87, 0xde, 0x05, 0x9d, 0x27, 0x0a, 0x28, 0xdf, 0x69, 0x57, 0x37, 0x34, 0xac, 0xf3, 0x24, 0x27, + 0x4a, 0xcf, 0x89, 0xb2, 0xbe, 0x85, 0xca, 0x12, 0x50, 0xd5, 0xf8, 0x21, 0x94, 0x02, 0x8f, 0xf5, + 0xc3, 0xe8, 0x35, 0x55, 0xb8, 0x87, 0x77, 0x0b, 0x7c, 0xee, 0xb1, 0xb3, 0xe8, 0x35, 0xc5, 0xc5, + 0x20, 0x35, 0xd0, 0xfb, 0xb0, 0x15, 0x13, 0x36, 0x1d, 0x71, 0x49, 0x51, 0x56, 0x0d, 0xca, 0xe5, + 0x60, 0xe9, 0xc7, 0x2a, 0xce, 0xb2, 0x60, 0x47, 0xce, 0xce, 0xad, 0x12, 0x04, 0x9b, 0x97, 0x1e, + 0xbb, 0x94, 0x9c, 0xdb, 0x58, 0xda, 0xd6, 0x18, 0x76, 0x55, 0x8c, 0x2a, 0xee, 0xe8, 0x5e, 0xb9, + 0x52, 0xea, 0x4a, 0x7f, 0xf5, 0xff, 0xd7, 0xdf, 0xe3, 0xcf, 0xa0, 0xa8, 0x66, 0x1c, 0x19, 0xb0, + 0xdf, 0xc5, 0xed, 0x0e, 0xee, 0xbb, 0x17, 0xfd, 0x2f, 0x5f, 0xf6, 0x5e, 0x75, 0x5a, 0x67, 0x9f, + 0x9e, 0x75, 0xda, 0x95, 0x0d, 0x54, 0x81, 0x9d, 0x85, 0xe7, 0xb4, 0xd7, 0xaa, 0x68, 0xe8, 0x6d, + 0xd8, 0x5d, 0xdc, 0xb4, 0x3b, 0xbd, 0x56, 0x45, 0x3f, 0xfe, 0x1e, 0x76, 0x73, 0x63, 0x81, 0x4c, + 0xa8, 0xb9, 0xb8, 0x7b, 0xda, 0x6e, 0x9d, 0xf6, 0xce, 0xfb, 0x2f, 0xba, 0xed, 0xce, 0x0a, 0xaa, + 0x01, 0xfb, 0x2b, 0x7e, 0xf7, 0x8b, 0x6e, 0xeb, 0xf3, 0x8a, 0x86, 0x0e, 0xa0, 0xba, 0xe2, 0xe9, + 0x5d, 0xbc, 0x6c, 0x55, 0xf4, 0x35, 0x29, 0xa7, 0xd2, 0x53, 0x68, 0xfe, 0x52, 0x80, 0x62, 0x2f, + 0xdd, 0x78, 0x68, 0x00, 0xa5, 0xdb, 0x27, 0x46, 0xb5, 0x4c, 0xc7, 0x56, 0x06, 0xa9, 0xf6, 0x68, + 0xad, 0x4f, 0x0d, 0x9e, 0xf9, 0xe3, 0x9f, 0xff, 0xfc, 0xac, 0x1b, 0x56, 0xd5, 0xc9, 0xac, 0x54, + 0x15, 0xf4, 0x91, 0x76, 0x8c, 0x2e, 0xe0, 0x81, 0x7c, 0x27, 0x74, 0x90, 0x41, 0xc9, 0xbe, 0x6e, + 0xcd, 0xb8, 0xeb, 0x50, 0xd8, 0x47, 0x12, 0xfb, 0x00, 0xbd, 0xe3, 0x64, 0xf7, 0x29, 0x73, 0xbe, + 0x13, 0x13, 0xf0, 0x03, 0x0a, 0xa0, 0x9c, 0xf9, 0x92, 0xd0, 0xd1, 0xba, 0x0f, 0x6f, 0x49, 0x63, + 0xde, 0xe7, 0x56, 0x64, 0x87, 0x92, 0xac, 0x6a, 0xed, 0xe5, 0xc9, 0x84, 0x86, 0x21, 0x94, 0x33, + 0xbb, 0x2c, 0x47, 0x74, 0x77, 0x2f, 0xe7, 0x88, 0xd6, 0xac, 0x40, 0xeb, 0xa1, 0x24, 0xaa, 0xa0, + 0x15, 0x22, 0xf7, 0xd9, 0x1f, 0xd7, 0xa6, 0x76, 0x75, 0x6d, 0x6a, 0x7f, 0x5f, 0x9b, 0xda, 0x4f, + 0x37, 0xe6, 0xc6, 0xef, 0x37, 0xa6, 0x76, 0x75, 0x63, 0x6e, 0xfc, 0x75, 0x63, 0x6e, 0x7c, 0x55, + 0x0f, 0x42, 0x7e, 0x39, 0xf5, 0xed, 0x01, 0x1d, 0x3b, 0xa3, 0x30, 0x22, 0x22, 0xf9, 0x29, 0x1b, + 0x7e, 0xe3, 0xf0, 0xf9, 0x84, 0x30, 0x87, 0x27, 0xfe, 0x96, 0xfc, 0xb7, 0xf8, 0xe0, 0xdf, 0x00, + 0x00, 0x00, 0xff, 0xff, 0x75, 0xc8, 0x9d, 0x52, 0xdc, 0x06, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -1039,6 +1052,13 @@ func (m *SimulateRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if len(m.TxBytes) > 0 { + i -= len(m.TxBytes) + copy(dAtA[i:], m.TxBytes) + i = encodeVarintService(dAtA, i, uint64(len(m.TxBytes))) + i-- + dAtA[i] = 0x12 + } if m.Tx != nil { { size, err := m.Tx.MarshalToSizedBuffer(dAtA[:i]) @@ -1278,6 +1298,10 @@ func (m *SimulateRequest) Size() (n int) { l = m.Tx.Size() n += 1 + l + sovService(uint64(l)) } + l = len(m.TxBytes) + if l > 0 { + n += 1 + l + sovService(uint64(l)) + } return n } @@ -1899,6 +1923,40 @@ func (m *SimulateRequest) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field TxBytes", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowService + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthService + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthService + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.TxBytes = append(m.TxBytes[:0], dAtA[iNdEx:postIndex]...) + if m.TxBytes == nil { + m.TxBytes = []byte{} + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipService(dAtA[iNdEx:]) diff --git a/types/tx/service.pb.gw.go b/types/tx/service.pb.gw.go index 222df993a2..df0baf4828 100644 --- a/types/tx/service.pb.gw.go +++ b/types/tx/service.pb.gw.go @@ -400,13 +400,13 @@ func RegisterServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux, cl } var ( - pattern_Service_Simulate_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"lbm", "tx", "v1", "simulate"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_Service_Simulate_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"lbm", "tx", "v1", "simulate"}, "", runtime.AssumeColonVerbOpt(false))) - pattern_Service_GetTx_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4}, []string{"lbm", "tx", "v1", "txs", "hash"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_Service_GetTx_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4}, []string{"lbm", "tx", "v1", "txs", "hash"}, "", runtime.AssumeColonVerbOpt(false))) - pattern_Service_BroadcastTx_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"lbm", "tx", "v1", "txs"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_Service_BroadcastTx_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"lbm", "tx", "v1", "txs"}, "", runtime.AssumeColonVerbOpt(false))) - pattern_Service_GetTxsEvent_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"lbm", "tx", "v1", "txs"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_Service_GetTxsEvent_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"lbm", "tx", "v1", "txs"}, "", runtime.AssumeColonVerbOpt(false))) ) var ( diff --git a/types/tx/tx.pb.go b/types/tx/tx.pb.go index 54df318d69..2a491ea88e 100644 --- a/types/tx/tx.pb.go +++ b/types/tx/tx.pb.go @@ -254,7 +254,9 @@ type TxBody struct { // is referred to as the primary signer and pays the fee for the whole // transaction. Messages []*types.Any `protobuf:"bytes,1,rep,name=messages,proto3" json:"messages,omitempty"` - // memo is any arbitrary memo to be added to the transaction + // memo is any arbitrary note/comment to be added to the transaction. + // WARNING: in clients, any publicly exposed text should not be called memo, + // but should be called `note` instead (see https://github.com/cosmos/cosmos-sdk/issues/9122). Memo string `protobuf:"bytes,2,opt,name=memo,proto3" json:"memo,omitempty"` // timeout is the block height after which this transaction will not // be processed by the chain diff --git a/types/tx/types.go b/types/tx/types.go index 1ade22733c..34d33c1933 100644 --- a/types/tx/types.go +++ b/types/tx/types.go @@ -2,7 +2,6 @@ package tx import ( "fmt" - "strings" codectypes "github.com/line/lbm-sdk/codec/types" cryptotypes "github.com/line/lbm-sdk/crypto/types" @@ -26,20 +25,11 @@ func (t *Tx) GetMsgs() []sdk.Msg { anys := t.Body.Messages res := make([]sdk.Msg, len(anys)) for i, any := range anys { - var msg sdk.Msg - if isServiceMsg(any.TypeUrl) { - req := any.GetCachedValue() - if req == nil { - panic("Any cached value is nil. Transaction messages must be correctly packed Any values.") - } - msg = sdk.ServiceMsg{ - MethodName: any.TypeUrl, - Request: any.GetCachedValue().(sdk.MsgRequest), - } - } else { - msg = any.GetCachedValue().(sdk.Msg) + cached := any.GetCachedValue() + if cached == nil { + panic("Any cached value is nil. Transaction messages must be correctly packed Any values.") } - res[i] = msg + res[i] = cached.(sdk.Msg) } return res } @@ -135,6 +125,39 @@ func (t *Tx) GetSigners() []sdk.AccAddress { return signers } +func (t *Tx) GetGas() uint64 { + return t.AuthInfo.Fee.GasLimit +} +func (t *Tx) GetFee() sdk.Coins { + return t.AuthInfo.Fee.Amount +} +func (t *Tx) FeePayer() sdk.AccAddress { + feePayer := t.AuthInfo.Fee.Payer + if feePayer != "" { + err := sdk.ValidateAccAddress(feePayer) + if err != nil { + panic(err) + } + payerAddr := sdk.AccAddress(feePayer) + return payerAddr + } + // use first signer as default if no payer specified + return t.GetSigners()[0] +} + +func (t *Tx) FeeGranter() sdk.AccAddress { + feePayer := t.AuthInfo.Fee.Granter + if feePayer != "" { + err := sdk.ValidateAccAddress(feePayer) + if err != nil { + panic(err) + } + granterAddr := sdk.AccAddress(feePayer) + return granterAddr + } + return sdk.AccAddress("") +} + // UnpackInterfaces implements the UnpackInterfaceMessages.UnpackInterfaces method func (t *Tx) UnpackInterfaces(unpacker codectypes.AnyUnpacker) error { if t.Body != nil { @@ -153,20 +176,10 @@ func (t *Tx) UnpackInterfaces(unpacker codectypes.AnyUnpacker) error { // UnpackInterfaces implements the UnpackInterfaceMessages.UnpackInterfaces method func (m *TxBody) UnpackInterfaces(unpacker codectypes.AnyUnpacker) error { for _, any := range m.Messages { - // If the any's typeUrl contains 2 slashes, then we unpack the any into - // a ServiceMsg struct as per ADR-031. - if isServiceMsg(any.TypeUrl) { - var req sdk.MsgRequest - err := unpacker.UnpackAny(any, &req) - if err != nil { - return err - } - } else { - var msg sdk.Msg - err := unpacker.UnpackAny(any, &msg) - if err != nil { - return err - } + var msg sdk.Msg + err := unpacker.UnpackAny(any, &msg) + if err != nil { + return err } } @@ -194,9 +207,3 @@ func RegisterInterfaces(registry codectypes.InterfaceRegistry) { registry.RegisterInterface("lbm.tx.v1.Tx", (*sdk.Tx)(nil)) registry.RegisterImplementations((*sdk.Tx)(nil), &Tx{}) } - -// isServiceMsg checks if a type URL corresponds to a service method name, -// i.e. /lbm.bank.Msg/Send vs /lbm.bank.MsgSend -func isServiceMsg(typeURL string) bool { - return strings.Count(typeURL, "/") >= 2 -} diff --git a/types/tx_msg.go b/types/tx_msg.go index c52c8d250e..9a72ba7257 100644 --- a/types/tx_msg.go +++ b/types/tx_msg.go @@ -11,21 +11,10 @@ type ( Msg interface { proto.Message - // Return the message type. - // Must be alphanumeric or empty. - Route() string - - // Returns a human-readable string for the message, intended for utilization - // within tags - Type() string - // ValidateBasic does a simple validation check that // doesn't require access to any other information. ValidateBasic() error - // Get the canonical byte representation of the Msg. - GetSignBytes() []byte - // Signers returns the addrs of signers that must sign. // CONTRACT: All signatures must be present to be valid. // CONTRACT: Returns addrs in some deterministic order. diff --git a/types/tx_msg_test.go b/types/tx_msg_test.go index 3c45595da3..fa658e7a2a 100644 --- a/types/tx_msg_test.go +++ b/types/tx_msg_test.go @@ -29,3 +29,7 @@ func (s *testMsgSuite) TestMsg() { s.Require().Nil(msg.ValidateBasic()) s.Require().NotPanics(func() { msg.GetSignBytes() }) } + +func (s *testMsgSuite) TestMsgTypeURL() { + s.Require().Equal("/testdata.TestMsg", sdk.MsgTypeURL(new(testdata.TestMsg))) +} diff --git a/types/uint.go b/types/uint.go index a42c78395e..dbdd17bd58 100644 --- a/types/uint.go +++ b/types/uint.go @@ -161,7 +161,7 @@ func (u *Uint) MarshalTo(data []byte) (n int, err error) { if u.i == nil { u.i = new(big.Int) } - if len(u.i.Bytes()) == 0 { + if u.i.BitLen() == 0 { // The value 0 copy(data, []byte{0x30}) return 1, nil } @@ -207,8 +207,6 @@ func (u *Uint) Size() int { func (u Uint) MarshalAmino() ([]byte, error) { return u.Marshal() } func (u *Uint) UnmarshalAmino(bz []byte) error { return u.Unmarshal(bz) } -// __________________________________________________________________________ - // UintOverflow returns true if a given unsigned integer overflows and false // otherwise. func UintOverflow(i *big.Int) error { diff --git a/types/uint_test.go b/types/uint_test.go index 36d8540f87..ee031c15bc 100644 --- a/types/uint_test.go +++ b/types/uint_test.go @@ -1,6 +1,7 @@ package types_test import ( + "fmt" "math" "math/big" "math/rand" @@ -290,3 +291,36 @@ func maxuint(i1, i2 uint64) uint64 { } return i2 } + +func TestRoundTripMarshalToUint(t *testing.T) { + var values = []uint64{ + 0, + 1, + 1 << 10, + 1<<10 - 3, + 1<<63 - 1, + 1<<32 - 7, + 1<<22 - 8, + } + + for _, value := range values { + value := value + t.Run(fmt.Sprintf("%d", value), func(t *testing.T) { + t.Parallel() + + var scratch [20]byte + uv := sdk.NewUint(value) + n, err := uv.MarshalTo(scratch[:]) + if err != nil { + t.Fatal(err) + } + rt := new(sdk.Uint) + if err := rt.Unmarshal(scratch[:n]); err != nil { + t.Fatal(err) + } + if !rt.Equal(uv) { + t.Fatalf("roundtrip=%q != original=%q", rt, uv) + } + }) + } +} diff --git a/version/command.go b/version/command.go index c6c1171fbd..7c48d09c05 100644 --- a/version/command.go +++ b/version/command.go @@ -11,13 +11,13 @@ import ( const flagLong = "long" +// NewVersionCommand returns a CLI command to interactively print the application binary version information. func NewVersionCommand() *cobra.Command { cmd := &cobra.Command{ Use: "version", Short: "Print the application binary version information", RunE: func(cmd *cobra.Command, _ []string) error { verInfo := NewInfo() - cmd.SetOut(cmd.OutOrStdout()) if long, _ := cmd.Flags().GetBool(flagLong); !long { cmd.Println(verInfo.Version) diff --git a/x/README.md b/x/README.md index 3be56a3de6..2698f34a3b 100644 --- a/x/README.md +++ b/x/README.md @@ -8,18 +8,20 @@ parent: Here are some production-grade modules that can be used in Cosmos SDK applications, along with their respective documentation: - [Auth](auth/spec/README.md) - Authentication of accounts and transactions for Cosmos SDK application. +- [Authz](authz/spec/README.md) - Authorization for accounts to perform actions on behalf of other accounts. - [Bank](bank/spec/README.md) - Token transfer functionalities. - [Capability](capability/spec/README.md) - Object capability implementation. - [Crisis](crisis/spec/README.md) - Halting the blockchain under certain circumstances (e.g. if an invariant is broken). - [Distribution](distribution/spec/README.md) - Fee distribution, and staking token provision distribution. - [Evidence](evidence/spec/README.md) - Evidence handling for double signing, misbehaviour, etc. - [Governance](gov/spec/README.md) - On-chain proposals and voting. -- [IBC](ibc/spec/README.md) - IBC protocol for transport, authentication adn ordering. +- [IBC](ibc/spec/README.md) - IBC protocol for transport, authentication and ordering. - [IBC Transfer](ibc/spec/README.md) - Cross-chain fungible token transfer implementation through IBC. - [Mint](mint/spec/README.md) - Creation of new units of staking token. - [Params](params/spec/README.md) - Globally available parameter store. - [Slashing](slashing/spec/README.md) - Validator punishment mechanisms. - [Staking](staking/spec/README.md) - Proof-of-Stake layer for public blockchains. +- [Staking Plus](stakingplus/spec/README.md) - Modified version of staking. - [Upgrade](upgrade/spec/README.md) - Software upgrades handling and coordination. To learn more about the process of building modules, visit the [building modules reference documentation](../docs/building-modules/README.md). diff --git a/x/auth/ante/ante.go b/x/auth/ante/ante.go index 5e89e8c7e2..b35003b09a 100644 --- a/x/auth/ante/ante.go +++ b/x/auth/ante/ante.go @@ -2,37 +2,57 @@ package ante import ( sdk "github.com/line/lbm-sdk/types" - keeper2 "github.com/line/lbm-sdk/x/auth/keeper" - "github.com/line/lbm-sdk/x/auth/signing" + sdkerrors "github.com/line/lbm-sdk/types/errors" + "github.com/line/lbm-sdk/types/tx/signing" + authsigning "github.com/line/lbm-sdk/x/auth/signing" "github.com/line/lbm-sdk/x/auth/types" - "github.com/line/lbm-sdk/x/feegrant/keeper" - types2 "github.com/line/lbm-sdk/x/feegrant/types" ) +// HandlerOptions are the options required for constructing a default SDK AnteHandler. +type HandlerOptions struct { + AccountKeeper AccountKeeper + BankKeeper types.BankKeeper + FeegrantKeeper FeegrantKeeper + SignModeHandler authsigning.SignModeHandler + SigGasConsumer func(meter sdk.GasMeter, sig signing.SignatureV2, params types.Params) error +} + // NewAnteHandler returns an AnteHandler that checks and increments sequence // numbers, checks signatures & account numbers, and deducts fees from the first // signer. -func NewAnteHandler( - ak AccountKeeper, bankKeeper types.BankKeeper, feegrantKeeper keeper.Keeper, - sigGasConsumer SignatureVerificationGasConsumer, - signModeHandler signing.SignModeHandler, -) sdk.AnteHandler { - return sdk.ChainAnteDecorators( +func NewAnteHandler(options HandlerOptions) (sdk.AnteHandler, error) { + if options.AccountKeeper == nil { + return nil, sdkerrors.Wrap(sdkerrors.ErrLogic, "account keeper is required for ante builder") + } + + if options.BankKeeper == nil { + return nil, sdkerrors.Wrap(sdkerrors.ErrLogic, "bank keeper is required for ante builder") + } + + if options.SignModeHandler == nil { + return nil, sdkerrors.Wrap(sdkerrors.ErrLogic, "sign mode handler is required for ante builder") + } + + var sigGasConsumer = options.SigGasConsumer + if sigGasConsumer == nil { + sigGasConsumer = DefaultSigVerificationGasConsumer + } + + anteDecorators := []sdk.AnteDecorator{ NewSetUpContextDecorator(), // outermost AnteDecorator. SetUpContext must be called first NewRejectExtensionOptionsDecorator(), NewMempoolFeeDecorator(), NewValidateBasicDecorator(), - TxTimeoutHeightDecorator{}, - NewValidateMemoDecorator(ak), - NewConsumeGasForTxSizeDecorator(ak), - NewDeductGrantedFeeDecorator(ak.(keeper2.AccountKeeper), bankKeeper.(types2.BankKeeper), feegrantKeeper), - // NewRejectFeeGranterDecorator(), // todo: Please check it when upgrade `feegrant` - // The above handlers should not call `GetAccount` or `GetSignerAcc` for signer - NewSetPubKeyDecorator(ak), // SetPubKeyDecorator must be called before all signature verification decorators - // The handlers below may call `GetAccount` or `GetSignerAcc` for signer - NewValidateSigCountDecorator(ak), - NewSigGasConsumeDecorator(ak, sigGasConsumer), - NewSigVerificationDecorator(ak, signModeHandler), - NewIncrementSequenceDecorator(ak, bankKeeper), - ) + NewTxTimeoutHeightDecorator(), + NewValidateMemoDecorator(options.AccountKeeper), + NewConsumeGasForTxSizeDecorator(options.AccountKeeper), + NewDeductFeeDecorator(options.AccountKeeper, options.BankKeeper, options.FeegrantKeeper), + NewSetPubKeyDecorator(options.AccountKeeper), // SetPubKeyDecorator must be called before all signature verification decorators + NewValidateSigCountDecorator(options.AccountKeeper), + NewSigGasConsumeDecorator(options.AccountKeeper, sigGasConsumer), + NewSigVerificationDecorator(options.AccountKeeper, options.SignModeHandler), + NewIncrementSequenceDecorator(options.AccountKeeper, options.BankKeeper), + } + + return sdk.ChainAnteDecorators(anteDecorators...), nil } diff --git a/x/auth/ante/ante_test.go b/x/auth/ante/ante_test.go index 5e44c34013..b7385212c0 100644 --- a/x/auth/ante/ante_test.go +++ b/x/auth/ante/ante_test.go @@ -13,17 +13,19 @@ import ( kmultisig "github.com/line/lbm-sdk/crypto/keys/multisig" "github.com/line/lbm-sdk/crypto/keys/secp256k1" cryptotypes "github.com/line/lbm-sdk/crypto/types" + "github.com/line/lbm-sdk/simapp" "github.com/line/lbm-sdk/testutil/testdata" sdk "github.com/line/lbm-sdk/types" sdkerrors "github.com/line/lbm-sdk/types/errors" "github.com/line/lbm-sdk/types/tx/signing" "github.com/line/lbm-sdk/x/auth/ante" "github.com/line/lbm-sdk/x/auth/types" + minttypes "github.com/line/lbm-sdk/x/mint/types" ) // Test that simulate transaction accurately estimates gas cost func (suite *AnteTestSuite) TestSimulateGasCost() { - suite.SetupTest(true) // reset + suite.SetupTest(false) // reset // Same data for every test cases accounts := suite.CreateTestAccounts(3) @@ -76,7 +78,7 @@ func (suite *AnteTestSuite) TestSimulateGasCost() { // Test various error cases in the AnteHandler control flow. func (suite *AnteTestSuite) TestAnteHandlerSigErrors() { - suite.SetupTest(true) // reset + suite.SetupTest(false) // reset // Same data for every test cases priv0, _, addr0 := testdata.KeyTestPubAddr() @@ -137,7 +139,9 @@ func (suite *AnteTestSuite) TestAnteHandlerSigErrors() { func() { acc1 := suite.app.AccountKeeper.NewAccountWithAddress(suite.ctx, addr0) suite.app.AccountKeeper.SetAccount(suite.ctx, acc1) - err := suite.app.BankKeeper.SetBalances(suite.ctx, addr0, feeAmount) + err := suite.app.BankKeeper.MintCoins(suite.ctx, minttypes.ModuleName, feeAmount) + suite.Require().NoError(err) + err = suite.app.BankKeeper.SendCoinsFromModuleToAccount(suite.ctx, minttypes.ModuleName, addr0, feeAmount) suite.Require().NoError(err) }, false, @@ -435,7 +439,7 @@ func (suite *AnteTestSuite) TestAnteHandlerSequences() { // Test logic around fee deduction. func (suite *AnteTestSuite) TestAnteHandlerFees() { - suite.SetupTest(true) // setup + suite.SetupTest(false) // setup // Same data for every test cases priv0, _, addr0 := testdata.KeyTestPubAddr() @@ -466,7 +470,8 @@ func (suite *AnteTestSuite) TestAnteHandlerFees() { { "signer does not have enough funds to pay the fee", func() { - suite.app.BankKeeper.SetBalances(suite.ctx, addr0, sdk.NewCoins(sdk.NewInt64Coin("atom", 149))) + err := simapp.FundAccount(suite.app, suite.ctx, addr0, sdk.NewCoins(sdk.NewInt64Coin("atom", 149))) + suite.Require().NoError(err) }, false, false, @@ -475,12 +480,14 @@ func (suite *AnteTestSuite) TestAnteHandlerFees() { { "signer as enough funds, should pass", func() { + accNums = []uint64{7} modAcc := suite.app.AccountKeeper.GetModuleAccount(suite.ctx, types.FeeCollectorName) suite.Require().True(suite.app.BankKeeper.GetAllBalances(suite.ctx, modAcc.GetAddress()).Empty()) require.True(sdk.IntEq(suite.T(), suite.app.BankKeeper.GetAllBalances(suite.ctx, addr0).AmountOf("atom"), sdk.NewInt(149))) - suite.app.BankKeeper.SetBalances(suite.ctx, addr0, sdk.NewCoins(sdk.NewInt64Coin("atom", 150))) + err := simapp.FundAccount(suite.app, suite.ctx, addr0, sdk.NewCoins(sdk.NewInt64Coin("atom", 1))) + suite.Require().NoError(err) }, false, true, @@ -892,8 +899,7 @@ func generatePubKeysAndSignatures(n int, msg []byte, _ bool) (pubkeys []cryptoty pubkeys = make([]cryptotypes.PubKey, n) signatures = make([][]byte, n) for i := 0; i < n; i++ { - var privkey cryptotypes.PrivKey - privkey = secp256k1.GenPrivKey() + var privkey cryptotypes.PrivKey = secp256k1.GenPrivKey() // TODO: also generate ed25519 keys as below when ed25519 keys are // actually supported, https://github.com/cosmos/cosmos-sdk/issues/4789 @@ -960,7 +966,7 @@ func TestCountSubkeys(t *testing.T) { } func (suite *AnteTestSuite) TestAnteHandlerSigLimitExceeded() { - suite.SetupTest(true) // setup + suite.SetupTest(false) // setup // Same data for every test cases accounts := suite.CreateTestAccounts(8) @@ -997,19 +1003,29 @@ func (suite *AnteTestSuite) TestAnteHandlerSigLimitExceeded() { // Test custom SignatureVerificationGasConsumer func (suite *AnteTestSuite) TestCustomSignatureVerificationGasConsumer() { - suite.SetupTest(true) // setup + suite.SetupTest(false) // setup // setup an ante handler that only accepts PubKeyEd25519 - suite.anteHandler = ante.NewAnteHandler(suite.app.AccountKeeper, suite.app.BankKeeper, suite.app.FeeGrantKeeper, - func(meter sdk.GasMeter, sig signing.SignatureV2, params types.Params) error { - switch pubkey := sig.PubKey.(type) { - case *ed25519.PubKey: - meter.ConsumeGas(params.SigVerifyCostED25519, "ante verify: ed25519") - return nil - default: - return sdkerrors.Wrapf(sdkerrors.ErrInvalidPubKey, "unrecognized public key type: %T", pubkey) - } - }, suite.clientCtx.TxConfig.SignModeHandler()) + anteHandler, err := ante.NewAnteHandler( + ante.HandlerOptions{ + AccountKeeper: suite.app.AccountKeeper, + BankKeeper: suite.app.BankKeeper, + FeegrantKeeper: suite.app.FeeGrantKeeper, + SignModeHandler: suite.clientCtx.TxConfig.SignModeHandler(), + SigGasConsumer: func(meter sdk.GasMeter, sig signing.SignatureV2, params types.Params) error { + switch pubkey := sig.PubKey.(type) { + case *ed25519.PubKey: + meter.ConsumeGas(params.SigVerifyCostED25519, "ante verify: ed25519") + return nil + default: + return sdkerrors.Wrapf(sdkerrors.ErrInvalidPubKey, "unrecognized public key type: %T", pubkey) + } + }, + }, + ) + + suite.Require().NoError(err) + suite.anteHandler = anteHandler // Same data for every test cases accounts := suite.CreateTestAccounts(1) @@ -1048,7 +1064,7 @@ func (suite *AnteTestSuite) TestCustomSignatureVerificationGasConsumer() { } func (suite *AnteTestSuite) TestAnteHandlerReCheck() { - suite.SetupTest(true) // setup + suite.SetupTest(false) // setup // Set recheck=true suite.ctx = suite.ctx.WithIsReCheckTx(true) suite.txBuilder = suite.clientCtx.TxConfig.NewTxBuilder() @@ -1121,7 +1137,9 @@ func (suite *AnteTestSuite) TestAnteHandlerReCheck() { // remove funds for account so antehandler fails on recheck suite.app.AccountKeeper.SetAccount(suite.ctx, accounts[0].acc) - suite.app.BankKeeper.SetBalances(suite.ctx, accounts[0].acc.GetAddress(), sdk.NewCoins()) + balances := suite.app.BankKeeper.GetAllBalances(suite.ctx, accounts[0].acc.GetAddress()) + err = suite.app.BankKeeper.SendCoinsFromAccountToModule(suite.ctx, accounts[0].acc.GetAddress(), minttypes.ModuleName, balances) + suite.Require().NoError(err) _, err = suite.anteHandler(suite.ctx, tx, false) suite.Require().NotNil(err, "antehandler on recheck did not fail once feePayer no longer has sufficient funds") diff --git a/x/auth/ante/basic.go b/x/auth/ante/basic.go index a060ed14c3..2122ae9380 100644 --- a/x/auth/ante/basic.go +++ b/x/auth/ante/basic.go @@ -128,7 +128,7 @@ func (cgts ConsumeTxSizeGasDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, sim PubKey: pubkey, } - sigBz := legacy.Cdc.MustMarshalBinaryBare(simSig) + sigBz := legacy.Cdc.MustMarshal(simSig) cost := sdk.Gas(len(sigBz) + 6) // If the pubkey is a multi-signature pubkey, then we estimate for the maximum @@ -181,6 +181,12 @@ type ( } ) +// TxTimeoutHeightDecorator defines an AnteHandler decorator that checks for a +// tx height timeout. +func NewTxTimeoutHeightDecorator() TxTimeoutHeightDecorator { + return TxTimeoutHeightDecorator{} +} + // AnteHandle implements an AnteHandler decorator for the TxHeightTimeoutDecorator // type where the current block height is checked against the tx's height timeout. // If a height timeout is provided (non-zero) and is less than the current block diff --git a/x/auth/ante/basic_test.go b/x/auth/ante/basic_test.go index 166c01ae43..e9304a1823 100644 --- a/x/auth/ante/basic_test.go +++ b/x/auth/ante/basic_test.go @@ -177,7 +177,7 @@ func (suite *AnteTestSuite) TestConsumeGasForTxSize() { func (suite *AnteTestSuite) TestTxHeightTimeoutDecorator() { suite.SetupTest(true) - antehandler := sdk.ChainAnteDecorators(ante.TxTimeoutHeightDecorator{}) + antehandler := sdk.ChainAnteDecorators(ante.NewTxTimeoutHeightDecorator()) // keys and addresses priv1, _, addr1 := testdata.KeyTestPubAddr() diff --git a/x/auth/ante/expected_keepers.go b/x/auth/ante/expected_keepers.go index 6770b38eb2..7452ac70d0 100644 --- a/x/auth/ante/expected_keepers.go +++ b/x/auth/ante/expected_keepers.go @@ -13,3 +13,8 @@ type AccountKeeper interface { SetAccount(ctx sdk.Context, acc types.AccountI) GetModuleAddress(moduleName string) sdk.AccAddress } + +// FeegrantKeeper defines the expected feegrant keeper. +type FeegrantKeeper interface { + UseGrantedFees(ctx sdk.Context, granter, grantee sdk.AccAddress, fee sdk.Coins, msgs []sdk.Msg) error +} diff --git a/x/auth/ante/fee.go b/x/auth/ante/fee.go index 18ab9b2889..4c4ed253b7 100644 --- a/x/auth/ante/fee.go +++ b/x/auth/ante/fee.go @@ -59,15 +59,16 @@ func (mfd MempoolFeeDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate b // Call next AnteHandler if fees successfully deducted // CONTRACT: Tx must implement FeeTx interface to use DeductFeeDecorator type DeductFeeDecorator struct { - ak AccountKeeper - bankKeeper types.BankKeeper + ak AccountKeeper + bankKeeper types.BankKeeper + feegrantKeeper FeegrantKeeper } -// This DeductFeeDecorator is not used anymore. Instead of it, DeductGrantedFeeDecorator will be used. -func NewDeductFeeDecorator(ak AccountKeeper, bk types.BankKeeper) DeductFeeDecorator { +func NewDeductFeeDecorator(ak AccountKeeper, bk types.BankKeeper, fk FeegrantKeeper) DeductFeeDecorator { return DeductFeeDecorator{ - ak: ak, - bankKeeper: bk, + ak: ak, + bankKeeper: bk, + feegrantKeeper: fk, } } @@ -78,24 +79,49 @@ func (dfd DeductFeeDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bo } if addr := dfd.ak.GetModuleAddress(types.FeeCollectorName); addr.Empty() { - panic(fmt.Sprintf("%s module account has not been set", types.FeeCollectorName)) + return ctx, fmt.Errorf("fee collector module account (%s) has not been set", types.FeeCollectorName) } + fee := feeTx.GetFee() feePayer := feeTx.FeePayer() - feePayerAcc := dfd.ak.GetAccount(ctx, feePayer) + feeGranter := feeTx.FeeGranter() - if feePayerAcc == nil { - return ctx, sdkerrors.Wrapf(sdkerrors.ErrUnknownAddress, "fee payer address: %s does not exist", feePayer) + deductFeesFrom := feePayer + + // if feegranter set deduct fee from feegranter account. + // this works with only when feegrant enabled. + if feeGranter != "" { + if dfd.feegrantKeeper == nil { + return ctx, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "fee grants are not enabled") + } else if !feeGranter.Equals(feePayer) { + err := dfd.feegrantKeeper.UseGrantedFees(ctx, feeGranter, feePayer, fee, tx.GetMsgs()) + + if err != nil { + return ctx, sdkerrors.Wrapf(err, "%s not allowed to pay fees from %s", feeGranter, feePayer) + } + } + + deductFeesFrom = feeGranter + } + + deductFeesFromAcc := dfd.ak.GetAccount(ctx, deductFeesFrom) + if deductFeesFromAcc == nil { + return ctx, sdkerrors.Wrapf(sdkerrors.ErrUnknownAddress, "fee payer address: %s does not exist", deductFeesFrom) } // deduct the fees if !feeTx.GetFee().IsZero() { - err = DeductFees(dfd.bankKeeper, ctx, feePayerAcc, feeTx.GetFee()) + err = DeductFees(dfd.bankKeeper, ctx, deductFeesFromAcc, feeTx.GetFee()) if err != nil { return ctx, err } } + events := sdk.Events{sdk.NewEvent(sdk.EventTypeTx, + sdk.NewAttribute(sdk.AttributeKeyFee, feeTx.GetFee().String()), + )} + ctx.EventManager().EmitEvents(events) + return next(ctx, tx, simulate) } diff --git a/x/auth/ante/fee_grant.go b/x/auth/ante/fee_grant.go deleted file mode 100644 index eb99c901a0..0000000000 --- a/x/auth/ante/fee_grant.go +++ /dev/null @@ -1,103 +0,0 @@ -package ante - -import ( - "fmt" - - sdk "github.com/line/lbm-sdk/types" - sdkerrors "github.com/line/lbm-sdk/types/errors" - "github.com/line/lbm-sdk/x/auth/keeper" - types3 "github.com/line/lbm-sdk/x/auth/types" - feegrantkeeper "github.com/line/lbm-sdk/x/feegrant/keeper" - types2 "github.com/line/lbm-sdk/x/feegrant/types" -) - -// RejectFeeGranterDecorator is an AnteDecorator which rejects transactions which -// have the Fee.granter field set. It is to be used by chains which do not support -// fee grants. -type RejectFeeGranterDecorator struct{} - -// NewRejectFeeGranterDecorator returns a new RejectFeeGranterDecorator. -func NewRejectFeeGranterDecorator() RejectFeeGranterDecorator { - return RejectFeeGranterDecorator{} -} - -var _ sdk.AnteDecorator = RejectFeeGranterDecorator{} - -func (d RejectFeeGranterDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) { - feeTx, ok := tx.(sdk.FeeTx) - if ok && len(feeTx.FeeGranter()) != 0 { - return ctx, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "fee grants are not supported") - } - - return next(ctx, tx, simulate) -} - -// DeductGrantedFeeDecorator deducts fees from fee_payer or fee_granter (if exists a valid fee allowance) of the tx -// If the fee_payer or fee_granter does not have the funds to pay for the fees, return with InsufficientFunds error -// Call next AnteHandler if fees successfully deducted -// CONTRACT: Tx must implement GrantedFeeTx interface to use DeductGrantedFeeDecorator -type DeductGrantedFeeDecorator struct { - ak keeper.AccountKeeper - k feegrantkeeper.Keeper - bk types2.BankKeeper -} - -func NewDeductGrantedFeeDecorator(ak keeper.AccountKeeper, bk types2.BankKeeper, k feegrantkeeper.Keeper) DeductGrantedFeeDecorator { - return DeductGrantedFeeDecorator{ - ak: ak, - k: k, - bk: bk, - } -} - -// AnteHandle performs a decorated ante-handler responsible for deducting transaction -// fees. Fees will be deducted from the account designated by the FeePayer on a -// transaction by default. However, if the fee payer differs from the transaction -// signer, the handler will check if a fee grant has been authorized. If the -// transaction's signer does not exist, it will be created. -func (d DeductGrantedFeeDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) { - feeTx, ok := tx.(sdk.FeeTx) - if !ok { - return ctx, sdkerrors.Wrap(sdkerrors.ErrTxDecode, "Tx must be a GrantedFeeTx") - } - - // sanity check from DeductFeeDecorator - if addr := d.ak.GetModuleAddress(types3.FeeCollectorName); addr == "" { - panic(fmt.Sprintf("%s module account has not been set", types3.FeeCollectorName)) - } - - fee := feeTx.GetFee() - feePayer := feeTx.FeePayer() - feeGranter := feeTx.FeeGranter() - - deductFeesFrom := feePayer - - // ensure the grant is allowed, if we request a different fee payer - if feeGranter != "" && !feeGranter.Equals(feePayer) { - err := d.k.UseGrantedFees(ctx, feeGranter, feePayer, fee, tx.GetMsgs()) - if err != nil { - return ctx, sdkerrors.Wrapf(err, "%s not allowed to pay fees from %s", feeGranter, feePayer) - } - - deductFeesFrom = feeGranter - } - - // now, either way, we know that we are authorized to deduct the fees from the deductFeesFrom account - deductFeesFromAcc := d.ak.GetAccount(ctx, deductFeesFrom) - if deductFeesFromAcc == nil { - return ctx, sdkerrors.Wrapf(sdkerrors.ErrUnknownAddress, "fee payer address: %s does not exist", deductFeesFrom) - } - - // move on if there is no fee to deduct - if fee.IsZero() { - return next(ctx, tx, simulate) - } - - // deduct fee if non-zero - err = DeductFees(d.bk, ctx, deductFeesFromAcc, fee) - if err != nil { - return ctx, err - } - - return next(ctx, tx, simulate) -} diff --git a/x/auth/ante/fee_grant_test.go b/x/auth/ante/fee_grant_test.go deleted file mode 100644 index 5df8489189..0000000000 --- a/x/auth/ante/fee_grant_test.go +++ /dev/null @@ -1,32 +0,0 @@ -package ante_test - -import ( - "github.com/line/lbm-sdk/codec" - "github.com/line/lbm-sdk/codec/types" - "github.com/line/lbm-sdk/testutil/testdata" - sdk "github.com/line/lbm-sdk/types" - "github.com/line/lbm-sdk/x/auth/ante" - "github.com/line/lbm-sdk/x/auth/tx" -) - -type setFeeGranter interface { - SetFeeGranter(feeGranter sdk.AccAddress) -} - -func (suite *AnteTestSuite) TestRejectFeeGranter() { - suite.SetupTest(true) // setup - txConfig := tx.NewTxConfig(codec.NewProtoCodec(types.NewInterfaceRegistry()), tx.DefaultSignModes) - txBuilder := txConfig.NewTxBuilder() - d := ante.NewRejectFeeGranterDecorator() - antehandler := sdk.ChainAnteDecorators(d) - - _, err := antehandler(suite.ctx, txBuilder.GetTx(), false) - suite.Require().NoError(err) - - setGranterTx := txBuilder.(setFeeGranter) - _, _, addr := testdata.KeyTestPubAddr() - setGranterTx.SetFeeGranter(addr) - - _, err = antehandler(suite.ctx, txBuilder.GetTx(), false) - suite.Require().Error(err) -} diff --git a/x/auth/ante/fee_test.go b/x/auth/ante/fee_test.go index bf23ad3532..926322a850 100644 --- a/x/auth/ante/fee_test.go +++ b/x/auth/ante/fee_test.go @@ -4,6 +4,7 @@ import ( cryptotypes "github.com/line/lbm-sdk/crypto/types" "github.com/line/lbm-sdk/testutil/testdata" + "github.com/line/lbm-sdk/simapp" sdk "github.com/line/lbm-sdk/types" "github.com/line/lbm-sdk/x/auth/ante" ) @@ -61,7 +62,7 @@ func (suite *AnteTestSuite) TestEnsureMempoolFees() { } func (suite *AnteTestSuite) TestDeductFees() { - suite.SetupTest(true) // setup + suite.SetupTest(false) // setup suite.txBuilder = suite.clientCtx.TxConfig.NewTxBuilder() // keys and addresses @@ -82,9 +83,11 @@ func (suite *AnteTestSuite) TestDeductFees() { // Set account with insufficient funds acc := suite.app.AccountKeeper.NewAccountWithAddress(suite.ctx, addr1) suite.app.AccountKeeper.SetAccount(suite.ctx, acc) - suite.app.BankKeeper.SetBalances(suite.ctx, addr1, sdk.NewCoins(sdk.NewCoin("atom", sdk.NewInt(10)))) + coins := sdk.NewCoins(sdk.NewCoin("atom", sdk.NewInt(10))) + err = simapp.FundAccount(suite.app, suite.ctx, addr1, coins) + suite.Require().NoError(err) - dfd := ante.NewDeductFeeDecorator(suite.app.AccountKeeper, suite.app.BankKeeper) + dfd := ante.NewDeductFeeDecorator(suite.app.AccountKeeper, suite.app.BankKeeper, nil) antehandler := sdk.ChainAnteDecorators(dfd) _, err = antehandler(suite.ctx, tx, false) @@ -93,7 +96,8 @@ func (suite *AnteTestSuite) TestDeductFees() { // Set account with sufficient funds suite.app.AccountKeeper.SetAccount(suite.ctx, acc) - suite.app.BankKeeper.SetBalances(suite.ctx, addr1, sdk.NewCoins(sdk.NewCoin("atom", sdk.NewInt(200)))) + err = simapp.FundAccount(suite.app, suite.ctx, addr1, sdk.NewCoins(sdk.NewCoin("atom", sdk.NewInt(200)))) + suite.Require().NoError(err) _, err = antehandler(suite.ctx, tx, false) diff --git a/x/auth/ante/feegrant_test.go b/x/auth/ante/feegrant_test.go new file mode 100644 index 0000000000..193af8305b --- /dev/null +++ b/x/auth/ante/feegrant_test.go @@ -0,0 +1,230 @@ +package ante_test + +import ( + "math/rand" + "testing" + "time" + + "github.com/line/ostracon/crypto" + + "github.com/line/lbm-sdk/client" + "github.com/line/lbm-sdk/codec" + cryptotypes "github.com/line/lbm-sdk/crypto/types" + "github.com/line/lbm-sdk/simapp" + "github.com/line/lbm-sdk/simapp/helpers" + "github.com/line/lbm-sdk/testutil/testdata" + sdk "github.com/line/lbm-sdk/types" + "github.com/line/lbm-sdk/types/simulation" + "github.com/line/lbm-sdk/types/tx/signing" + "github.com/line/lbm-sdk/x/auth/ante" + authsign "github.com/line/lbm-sdk/x/auth/signing" + "github.com/line/lbm-sdk/x/auth/tx" + authtypes "github.com/line/lbm-sdk/x/auth/types" + "github.com/line/lbm-sdk/x/feegrant" +) + +func (suite *AnteTestSuite) TestDeductFeesNoDelegation() { + suite.SetupTest(false) + // setup + app, ctx := suite.app, suite.ctx + + protoTxCfg := tx.NewTxConfig(codec.NewProtoCodec(app.InterfaceRegistry()), tx.DefaultSignModes) + + // this just tests our handler + dfd := ante.NewDeductFeeDecorator(app.AccountKeeper, app.BankKeeper, app.FeeGrantKeeper) + feeAnteHandler := sdk.ChainAnteDecorators(dfd) + + // this tests the whole stack + anteHandlerStack := suite.anteHandler + + // keys and addresses + priv1, _, addr1 := testdata.KeyTestPubAddr() + priv2, _, addr2 := testdata.KeyTestPubAddr() + priv3, _, addr3 := testdata.KeyTestPubAddr() + priv4, _, addr4 := testdata.KeyTestPubAddr() + priv5, _, addr5 := testdata.KeyTestPubAddr() + + // Set addr1 with insufficient funds + err := simapp.FundAccount(suite.app, suite.ctx, addr1, []sdk.Coin{sdk.NewCoin("atom", sdk.NewInt(10))}) + suite.Require().NoError(err) + + // Set addr2 with more funds + err = simapp.FundAccount(suite.app, suite.ctx, addr2, []sdk.Coin{sdk.NewCoin("atom", sdk.NewInt(99999))}) + suite.Require().NoError(err) + + // grant fee allowance from `addr2` to `addr3` (plenty to pay) + err = app.FeeGrantKeeper.GrantAllowance(ctx, addr2, addr3, &feegrant.BasicAllowance{ + SpendLimit: sdk.NewCoins(sdk.NewInt64Coin("atom", 500)), + }) + suite.Require().NoError(err) + + // grant low fee allowance (20atom), to check the tx requesting more than allowed. + err = app.FeeGrantKeeper.GrantAllowance(ctx, addr2, addr4, &feegrant.BasicAllowance{ + SpendLimit: sdk.NewCoins(sdk.NewInt64Coin("atom", 20)), + }) + suite.Require().NoError(err) + + cases := map[string]struct { + signerKey cryptotypes.PrivKey + signer sdk.AccAddress + feeAccount sdk.AccAddress + fee int64 + valid bool + }{ + "paying with low funds": { + signerKey: priv1, + signer: addr1, + fee: 50, + valid: false, + }, + "paying with good funds": { + signerKey: priv2, + signer: addr2, + fee: 50, + valid: true, + }, + "paying with no account": { + signerKey: priv3, + signer: addr3, + fee: 1, + valid: false, + }, + "no fee with real account": { + signerKey: priv1, + signer: addr1, + fee: 0, + valid: true, + }, + "no fee with no account": { + signerKey: priv5, + signer: addr5, + fee: 0, + valid: false, + }, + "valid fee grant without account": { + signerKey: priv3, + signer: addr3, + feeAccount: addr2, + fee: 50, + valid: true, + }, + "no fee grant": { + signerKey: priv3, + signer: addr3, + feeAccount: addr1, + fee: 2, + valid: false, + }, + "allowance smaller than requested fee": { + signerKey: priv4, + signer: addr4, + feeAccount: addr2, + fee: 50, + valid: false, + }, + "granter cannot cover allowed fee grant": { + signerKey: priv4, + signer: addr4, + feeAccount: addr1, + fee: 50, + valid: false, + }, + } + + for name, stc := range cases { + tc := stc // to make scopelint happy + suite.T().Run(name, func(t *testing.T) { + fee := sdk.NewCoins(sdk.NewInt64Coin("atom", tc.fee)) + msgs := []sdk.Msg{testdata.NewTestMsg(tc.signer)} + + acc := app.AccountKeeper.GetAccount(ctx, tc.signer) + privs, accNums, seqs := []cryptotypes.PrivKey{tc.signerKey}, []uint64{0}, []uint64{0} + if acc != nil { + accNums, seqs = []uint64{acc.GetAccountNumber()}, []uint64{acc.GetSequence()} + } + + tx, err := genTxWithFeeGranter(protoTxCfg, msgs, fee, helpers.DefaultGenTxGas, ctx.ChainID(), accNums, seqs, tc.feeAccount, privs...) + suite.Require().NoError(err) + _, err = feeAnteHandler(ctx, tx, false) // tests only feegrant ante + if tc.valid { + suite.Require().NoError(err) + } else { + suite.Require().Error(err) + } + + _, err = anteHandlerStack(ctx, tx, false) // tests while stack + if tc.valid { + suite.Require().NoError(err) + } else { + suite.Require().Error(err) + } + }) + } +} + +// don't consume any gas +func SigGasNoConsumer(meter sdk.GasMeter, sig []byte, pubkey crypto.PubKey, params authtypes.Params) error { + return nil +} + +func genTxWithFeeGranter(gen client.TxConfig, msgs []sdk.Msg, feeAmt sdk.Coins, gas uint64, chainID string, accNums, + accSeqs []uint64, feeGranter sdk.AccAddress, priv ...cryptotypes.PrivKey) (sdk.Tx, error) { + sigs := make([]signing.SignatureV2, len(priv)) + + // create a random length memo + r := rand.New(rand.NewSource(time.Now().UnixNano())) + + memo := simulation.RandStringOfLength(r, simulation.RandIntBetween(r, 0, 100)) + + signMode := gen.SignModeHandler().DefaultMode() + + // 1st round: set SignatureV2 with empty signatures, to set correct + // signer infos. + for i, p := range priv { + sigs[i] = signing.SignatureV2{ + PubKey: p.PubKey(), + Data: &signing.SingleSignatureData{ + SignMode: signMode, + }, + Sequence: accSeqs[i], + } + } + + tx := gen.NewTxBuilder() + err := tx.SetMsgs(msgs...) + if err != nil { + return nil, err + } + err = tx.SetSignatures(sigs...) + if err != nil { + return nil, err + } + tx.SetMemo(memo) + tx.SetFeeAmount(feeAmt) + tx.SetGasLimit(gas) + tx.SetFeeGranter(feeGranter) + + // 2nd round: once all signer infos are set, every signer can sign. + for i, p := range priv { + signerData := authsign.SignerData{ + ChainID: chainID, + AccountNumber: accNums[i], + Sequence: accSeqs[i], + } + signBytes, err := gen.SignModeHandler().GetSignBytes(signMode, signerData, tx.GetTx()) + if err != nil { + panic(err) + } + sig, err := p.Sign(signBytes) + if err != nil { + panic(err) + } + sigs[i].Data.(*signing.SingleSignatureData).Signature = sig + err = tx.SetSignatures(sigs...) + if err != nil { + panic(err) + } + } + + return tx.GetTx(), nil +} diff --git a/x/auth/ante/sigverify.go b/x/auth/ante/sigverify.go index cb3c064eeb..d3ba8712f5 100644 --- a/x/auth/ante/sigverify.go +++ b/x/auth/ante/sigverify.go @@ -11,6 +11,7 @@ import ( "github.com/line/lbm-sdk/crypto/keys/ed25519" kmultisig "github.com/line/lbm-sdk/crypto/keys/multisig" "github.com/line/lbm-sdk/crypto/keys/secp256k1" + "github.com/line/lbm-sdk/crypto/keys/secp256r1" cryptotypes "github.com/line/lbm-sdk/crypto/types" "github.com/line/lbm-sdk/crypto/types/multisig" sdk "github.com/line/lbm-sdk/types" @@ -61,7 +62,10 @@ func (spkd SetPubKeyDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate b return ctx, sdkerrors.Wrap(sdkerrors.ErrTxDecode, "invalid tx type") } - pubkeys := sigTx.GetPubKeys() + pubkeys, err := sigTx.GetPubKeys() + if err != nil { + return ctx, err + } signers := sigTx.GetSigners() for i, pk := range pubkeys { @@ -96,7 +100,7 @@ func (spkd SetPubKeyDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate b // Also emit the following events, so that txs can be indexed by these // indices: // - signature (via `tx.signature=''`), - // - concat(address,"/",sequence) (via `tx.acc_seq='cosmos1abc...def/42'`). + // - concat(address,"/",sequence) (via `tx.acc_seq='link1abc...def/42'`). sigs, err := sigTx.GetSignaturesV2() if err != nil { return ctx, err @@ -281,18 +285,11 @@ func (svd *SigVerificationDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simu } // Check account sequence number. - // When using Amino StdSignatures, we actually don't have the Sequence in - // the SignatureV2 struct (it's only in the SignDoc). In this case, we - // cannot check sequence directly, and must do it via signature - // verification (in the VerifySignature call below). - onlyAminoSigners := OnlyLegacyAminoSigners(sig.Data) - if !onlyAminoSigners { - if sig.Sequence != acc.GetSequence() { - return ctx, sdkerrors.Wrapf( - sdkerrors.ErrWrongSequence, - "account sequence mismatch, expected %d, got %d", acc.GetSequence(), sig.Sequence, - ) - } + if sig.Sequence != acc.GetSequence() { + return ctx, sdkerrors.Wrapf( + sdkerrors.ErrWrongSequence, + "account sequence mismatch, expected %d, got %d", acc.GetSequence(), sig.Sequence, + ) } // retrieve signer data @@ -308,31 +305,33 @@ func (svd *SigVerificationDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simu Sequence: acc.GetSequence(), } - if !genesis { - sigKey := fmt.Sprintf("%d:%d", signerData.AccountNumber, signerData.Sequence) - // TODO could we use `tx.(*wrapper).getBodyBytes()` instead of `ctx.TxBytes()`? - txHash := sha256.Sum256(ctx.TxBytes()) - stored := false + if !simulate { + if !genesis { + sigKey := fmt.Sprintf("%d:%d", signerData.AccountNumber, signerData.Sequence) + // TODO could we use `tx.(*wrapper).getBodyBytes()` instead of `ctx.TxBytes()`? + txHash := sha256.Sum256(ctx.TxBytes()) + stored := false - stored, err = svd.verifySignatureWithCache(ctx, pubKey, signerData, sig.Data, tx, sigKey, txHash[:]) + stored, err = svd.verifySignatureWithCache(ctx, pubKey, signerData, sig.Data, tx, sigKey, txHash[:]) - if stored { - newSigKeys = append(newSigKeys, sigKey) + if stored { + newSigKeys = append(newSigKeys, sigKey) + } + } else { + err = authsigning.VerifySignature(pubKey, signerData, sig.Data, svd.signModeHandler, tx) } - } else { - err = authsigning.VerifySignature(pubKey, signerData, sig.Data, svd.signModeHandler, tx) - } - if err != nil { - var errMsg string - if onlyAminoSigners { - // If all signers are using SIGN_MODE_LEGACY_AMINO, we rely on VerifySignature to check account sequence number, - // and therefore communicate sequence number as a potential cause of error. - errMsg = fmt.Sprintf("signature verification failed; please verify account number (%d), sequence (%d) and chain-id (%s)", accNum, acc.GetSequence(), chainID) - } else { - errMsg = fmt.Sprintf("signature verification failed; please verify account number (%d) and chain-id (%s)", accNum, chainID) + if err != nil { + var errMsg string + if OnlyLegacyAminoSigners(sig.Data) { + // If all signers are using SIGN_MODE_LEGACY_AMINO, we rely on VerifySignature to check account sequence number, + // and therefore communicate sequence number as a potential cause of error. + errMsg = fmt.Sprintf("signature verification failed; please verify account number (%d), sequence (%d) and chain-id (%s)", accNum, acc.GetSequence(), chainID) + } else { + errMsg = fmt.Sprintf("signature verification failed; please verify account number (%d) and chain-id (%s)", accNum, chainID) + } + return ctx, sdkerrors.Wrap(sdkerrors.ErrUnauthorized, errMsg) } - return ctx, sdkerrors.Wrap(sdkerrors.ErrUnauthorized, errMsg) } } @@ -450,7 +449,10 @@ func (vscd ValidateSigCountDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, sim } params := vscd.ak.GetParams(ctx) - pubKeys := sigTx.GetPubKeys() + pubKeys, err := sigTx.GetPubKeys() + if err != nil { + return ctx, err + } sigCount := 0 for _, pk := range pubKeys { @@ -480,6 +482,10 @@ func DefaultSigVerificationGasConsumer( meter.ConsumeGas(params.SigVerifyCostSecp256k1, "ante verify: secp256k1") return nil + case *secp256r1.PubKey: + meter.ConsumeGas(params.SigVerifyCostSecp256r1(), "ante verify: secp256r1") + return nil + case multisig.PubKey: multisignature, ok := sig.Data.(*signing.MultiSignatureData) if !ok { @@ -584,6 +590,6 @@ func signatureDataToBz(data signing.SignatureData) ([][]byte, error) { return sigs, nil default: - return nil, sdkerrors.Wrapf(sdkerrors.ErrInvalidType, "unexpected signature data type %T", data) + return nil, sdkerrors.ErrInvalidType.Wrapf("unexpected signature data type %T", data) } } diff --git a/x/auth/ante/sigverify_benchmark_test.go b/x/auth/ante/sigverify_benchmark_test.go new file mode 100644 index 0000000000..5575629923 --- /dev/null +++ b/x/auth/ante/sigverify_benchmark_test.go @@ -0,0 +1,44 @@ +package ante_test + +import ( + "testing" + + tmcrypto "github.com/line/ostracon/crypto" + "github.com/stretchr/testify/require" + + "github.com/line/lbm-sdk/crypto/keys/secp256k1" + "github.com/line/lbm-sdk/crypto/keys/secp256r1" +) + +// This benchmark is used to asses the ante.Secp256k1ToR1GasFactor value +func BenchmarkSig(b *testing.B) { + require := require.New(b) + msg := tmcrypto.CRandBytes(1000) + + skK := secp256k1.GenPrivKey() + pkK := skK.PubKey() + skR, _ := secp256r1.GenPrivKey() + pkR := skR.PubKey() + + sigK, err := skK.Sign(msg) + require.NoError(err) + sigR, err := skR.Sign(msg) + require.NoError(err) + b.ResetTimer() + + b.Run("secp256k1", func(b *testing.B) { + b.ReportAllocs() + for i := 0; i < b.N; i++ { + ok := pkK.VerifySignature(msg, sigK) + require.True(ok) + } + }) + + b.Run("secp256r1", func(b *testing.B) { + b.ReportAllocs() + for i := 0; i < b.N; i++ { + ok := pkR.VerifySignature(msg, sigR) + require.True(ok) + } + }) +} diff --git a/x/auth/ante/sigverify_test.go b/x/auth/ante/sigverify_test.go index 36473ebcb5..657993cd60 100644 --- a/x/auth/ante/sigverify_test.go +++ b/x/auth/ante/sigverify_test.go @@ -8,6 +8,7 @@ import ( "github.com/line/lbm-sdk/crypto/keys/ed25519" kmultisig "github.com/line/lbm-sdk/crypto/keys/multisig" "github.com/line/lbm-sdk/crypto/keys/secp256k1" + "github.com/line/lbm-sdk/crypto/keys/secp256r1" cryptotypes "github.com/line/lbm-sdk/crypto/types" "github.com/line/lbm-sdk/crypto/types/multisig" "github.com/line/lbm-sdk/simapp" @@ -21,12 +22,13 @@ import ( func (suite *AnteTestSuite) TestSetPubKey() { suite.SetupTest(true) // setup + require := suite.Require() suite.txBuilder = suite.clientCtx.TxConfig.NewTxBuilder() // keys and addresses priv1, pub1, addr1 := testdata.KeyTestPubAddr() priv2, pub2, addr2 := testdata.KeyTestPubAddr() - priv3, pub3, addr3 := testdata.KeyTestPubAddr() + priv3, pub3, addr3 := testdata.KeyTestPubAddrSecp256R1(require) addrs := []sdk.AccAddress{addr1, addr2, addr3} pubs := []cryptotypes.PubKey{pub1, pub2, pub3} @@ -35,40 +37,40 @@ func (suite *AnteTestSuite) TestSetPubKey() { // set accounts and create msg for each address for i, addr := range addrs { acc := suite.app.AccountKeeper.NewAccountWithAddress(suite.ctx, addr) - suite.Require().NoError(acc.SetAccountNumber(uint64(i))) + require.NoError(acc.SetAccountNumber(uint64(i))) suite.app.AccountKeeper.SetAccount(suite.ctx, acc) msgs[i] = testdata.NewTestMsg(addr) } - suite.Require().NoError(suite.txBuilder.SetMsgs(msgs...)) - - feeAmount := testdata.NewTestFeeAmount() - gasLimit := testdata.NewTestGasLimit() - suite.txBuilder.SetFeeAmount(feeAmount) - suite.txBuilder.SetGasLimit(gasLimit) + require.NoError(suite.txBuilder.SetMsgs(msgs...)) + suite.txBuilder.SetFeeAmount(testdata.NewTestFeeAmount()) + suite.txBuilder.SetGasLimit(testdata.NewTestGasLimit()) privs, accNums, accSeqs := []cryptotypes.PrivKey{priv1, priv2, priv3}, []uint64{0, 1, 2}, []uint64{0, 0, 0} tx, err := suite.CreateTestTx(privs, accNums, accSeqs, suite.ctx.ChainID()) - suite.Require().NoError(err) + require.NoError(err) spkd := ante.NewSetPubKeyDecorator(suite.app.AccountKeeper) antehandler := sdk.ChainAnteDecorators(spkd) ctx, err := antehandler(suite.ctx, tx, false) - suite.Require().Nil(err) + require.NoError(err) // Require that all accounts have pubkey set after Decorator runs for i, addr := range addrs { pk, err := suite.app.AccountKeeper.GetPubKey(ctx, addr) - suite.Require().Nil(err, "Error on retrieving pubkey from account") - suite.Require().Equal(pubs[i], pk, "Pubkey retrieved from account is unexpected") + require.NoError(err, "Error on retrieving pubkey from account") + require.True(pubs[i].Equals(pk), + "Wrong Pubkey retrieved from AccountKeeper, idx=%d\nexpected=%s\n got=%s", i, pubs[i], pk) } } func (suite *AnteTestSuite) TestConsumeSignatureVerificationGas() { params := types.DefaultParams() msg := []byte{1, 2, 3, 4} - _, cdc := simapp.MakeCodecs() + cdc := simapp.MakeTestEncodingConfig().Amino + p := types.DefaultParams() + skR1, _ := secp256r1.GenPrivKey() pkSet1, sigSet1 := generatePubKeysAndSignatures(5, msg, false) multisigKey1 := kmultisig.NewLegacyAminoPubKey(2, pkSet1) multisignature1 := multisig.NewMultisig(len(pkSet1)) @@ -93,8 +95,9 @@ func (suite *AnteTestSuite) TestConsumeSignatureVerificationGas() { gasConsumed uint64 shouldErr bool }{ - {"PubKeyEd25519", args{sdk.NewInfiniteGasMeter(), nil, ed25519.GenPrivKey().PubKey(), params}, types.DefaultSigVerifyCostED25519, true}, - {"PubKeySecp256k1", args{sdk.NewInfiniteGasMeter(), nil, secp256k1.GenPrivKey().PubKey(), params}, types.DefaultSigVerifyCostSecp256k1, false}, + {"PubKeyEd25519", args{sdk.NewInfiniteGasMeter(), nil, ed25519.GenPrivKey().PubKey(), params}, p.SigVerifyCostED25519, true}, + {"PubKeySecp256k1", args{sdk.NewInfiniteGasMeter(), nil, secp256k1.GenPrivKey().PubKey(), params}, p.SigVerifyCostSecp256k1, false}, + {"PubKeySecp256r1", args{sdk.NewInfiniteGasMeter(), nil, skR1.PubKey(), params}, p.SigVerifyCostSecp256r1(), false}, {"Multisig", args{sdk.NewInfiniteGasMeter(), multisignature1, multisigKey1, params}, expectedCost1, false}, {"unknown key", args{sdk.NewInfiniteGasMeter(), nil, nil, params}, 0, true}, } @@ -184,10 +187,10 @@ func (suite *AnteTestSuite) TestSigVerification() { // This test is exactly like the one above, but we set the codec explicitly to // Amino. -// Once https://github.com/line/lbm-sdk/issues/6190 is in, we can remove +// Once https://github.com/cosmos/cosmos-sdk/issues/6190 is in, we can remove // this, since it'll be handled by the test matrix. // In the meantime, we want to make double-sure amino compatibility works. -// ref: https://github.com/line/lbm-sdk/issues/7229 +// ref: https://github.com/cosmos/cosmos-sdk/issues/7229 func (suite *AnteTestSuite) TestSigVerification_ExplicitAmino() { suite.app, suite.ctx = createTestApp(true) suite.ctx = suite.ctx.WithBlockHeight(1) @@ -200,8 +203,18 @@ func (suite *AnteTestSuite) TestSigVerification_ExplicitAmino() { suite.clientCtx = client.Context{}. WithTxConfig(txConfig) - suite.anteHandler = ante.NewAnteHandler(suite.app.AccountKeeper, suite.app.BankKeeper, suite.app.FeeGrantKeeper, - ante.DefaultSigVerificationGasConsumer, txConfig.SignModeHandler()) + anteHandler, err := ante.NewAnteHandler( + ante.HandlerOptions{ + AccountKeeper: suite.app.AccountKeeper, + BankKeeper: suite.app.BankKeeper, + FeegrantKeeper: suite.app.FeeGrantKeeper, + SignModeHandler: txConfig.SignModeHandler(), + SigGasConsumer: ante.DefaultSigVerificationGasConsumer, + }, + ) + + suite.Require().NoError(err) + suite.anteHandler = anteHandler suite.txBuilder = suite.clientCtx.TxConfig.NewTxBuilder() diff --git a/x/auth/ante/testutil_test.go b/x/auth/ante/testutil_test.go index 99626ccc8f..22c06c6699 100644 --- a/x/auth/ante/testutil_test.go +++ b/x/auth/ante/testutil_test.go @@ -19,6 +19,7 @@ import ( xauthsigning "github.com/line/lbm-sdk/x/auth/signing" "github.com/line/lbm-sdk/x/auth/types" authtypes "github.com/line/lbm-sdk/x/auth/types" + minttypes "github.com/line/lbm-sdk/x/mint/types" ) // TestAccount represents an account used in the tests in x/auth/ante. @@ -61,8 +62,18 @@ func (suite *AnteTestSuite) SetupTest(isCheckTx bool) { suite.clientCtx = client.Context{}. WithTxConfig(encodingConfig.TxConfig) - suite.anteHandler = ante.NewAnteHandler(suite.app.AccountKeeper, suite.app.BankKeeper, suite.app.FeeGrantKeeper, - ante.DefaultSigVerificationGasConsumer, encodingConfig.TxConfig.SignModeHandler()) + anteHandler, err := ante.NewAnteHandler( + ante.HandlerOptions{ + AccountKeeper: suite.app.AccountKeeper, + BankKeeper: suite.app.BankKeeper, + FeegrantKeeper: suite.app.FeeGrantKeeper, + SignModeHandler: encodingConfig.TxConfig.SignModeHandler(), + SigGasConsumer: ante.DefaultSigVerificationGasConsumer, + }, + ) + + suite.Require().NoError(err) + suite.anteHandler = anteHandler } // CreateTestAccounts creates `numAccs` accounts, and return all relevant @@ -76,9 +87,14 @@ func (suite *AnteTestSuite) CreateTestAccounts(numAccs int) []TestAccount { err := acc.SetAccountNumber(uint64(i)) suite.Require().NoError(err) suite.app.AccountKeeper.SetAccount(suite.ctx, acc) - suite.app.BankKeeper.SetBalances(suite.ctx, addr, sdk.Coins{ + someCoins := sdk.Coins{ sdk.NewInt64Coin("atom", 10000000), - }) + } + err = suite.app.BankKeeper.MintCoins(suite.ctx, minttypes.ModuleName, someCoins) + suite.Require().NoError(err) + + err = suite.app.BankKeeper.SendCoinsFromModuleToAccount(suite.ctx, minttypes.ModuleName, addr, someCoins) + suite.Require().NoError(err) accounts = append(accounts, TestAccount{acc, priv}) } diff --git a/x/auth/atlas/atlas-v0.39.1.md b/x/auth/atlas/atlas-v0.39.1.md index 94c66c2c04..036d682c94 100644 --- a/x/auth/atlas/atlas-v0.39.1.md +++ b/x/auth/atlas/atlas-v0.39.1.md @@ -86,7 +86,7 @@ module. func NewApp(...) *App { app.SetAnteHandler(ante.NewAnteHandler( app.AccountKeeper, - app.SupplyKeeper, + app.SupplyKeeper, auth.DefaultSigVerificationGasConsumer, )) } @@ -166,19 +166,19 @@ the module itself are defined below: 1. Query an account. ```shell - $ app q auth account [address] [...flags] + app q auth account [address] [...flags] ``` 2. Sign an unsigned transaction using a single signature. ```shell - $ app tx auth sign [file] + app tx auth sign [file] ``` 3. Sign an unsigned transaction using a multisig. ```shell - $ app tx auth multisign [file] [name] [[signature]...] + app tx auth multisign [file] [name] [[signature]...] ``` ### REST diff --git a/x/auth/client/cli/decode.go b/x/auth/client/cli/decode.go index 57f3f17801..45da457740 100644 --- a/x/auth/client/cli/decode.go +++ b/x/auth/client/cli/decode.go @@ -17,7 +17,7 @@ const flagHex = "hex" func GetDecodeCommand() *cobra.Command { cmd := &cobra.Command{ Use: "decode [amino-byte-string]", - Short: "Decode an binary encoded transaction string.", + Short: "Decode a binary encoded transaction string", Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) (err error) { clientCtx := client.GetClientContextFromCmd(cmd) diff --git a/x/auth/client/cli/encode_test.go b/x/auth/client/cli/encode_test.go index 605d4b8144..657afba674 100644 --- a/x/auth/client/cli/encode_test.go +++ b/x/auth/client/cli/encode_test.go @@ -39,7 +39,7 @@ func TestGetCommandEncode(t *testing.T) { ctx := context.Background() clientCtx := client.Context{}. WithTxConfig(encodingConfig.TxConfig). - WithJSONMarshaler(encodingConfig.Marshaler) + WithCodec(encodingConfig.Marshaler) ctx = context.WithValue(ctx, client.ClientContextKey, &clientCtx) cmd.SetArgs([]string{txFileName}) @@ -52,7 +52,7 @@ func TestGetCommandDecode(t *testing.T) { clientCtx := client.Context{}. WithTxConfig(encodingConfig.TxConfig). - WithJSONMarshaler(encodingConfig.Marshaler) + WithCodec(encodingConfig.Marshaler) cmd := GetDecodeCommand() _ = testutil.ApplyMockIODiscardOutErr(cmd) diff --git a/x/auth/client/cli/query.go b/x/auth/client/cli/query.go index 9204dbe740..5efa6836a3 100644 --- a/x/auth/client/cli/query.go +++ b/x/auth/client/cli/query.go @@ -1,7 +1,6 @@ package cli import ( - "context" "fmt" "strings" @@ -15,7 +14,7 @@ import ( "github.com/line/lbm-sdk/types/query" "github.com/line/lbm-sdk/types/rest" "github.com/line/lbm-sdk/version" - authclient "github.com/line/lbm-sdk/x/auth/client" + authtx "github.com/line/lbm-sdk/x/auth/tx" "github.com/line/lbm-sdk/x/auth/types" ) @@ -42,6 +41,7 @@ func GetQueryCmd() *cobra.Command { cmd.AddCommand( GetAccountCmd(), + GetAccountsCmd(), QueryParamsCmd(), ) @@ -65,7 +65,7 @@ $ query auth params } queryClient := types.NewQueryClient(clientCtx) - res, err := queryClient.Params(context.Background(), &types.QueryParamsRequest{}) + res, err := queryClient.Params(cmd.Context(), &types.QueryParamsRequest{}) if err != nil { return err } @@ -96,7 +96,7 @@ func GetAccountCmd() *cobra.Command { } key := sdk.AccAddress(args[0]) queryClient := types.NewQueryClient(clientCtx) - res, err := queryClient.Account(context.Background(), &types.QueryAccountRequest{Address: key.String()}) + res, err := queryClient.Account(cmd.Context(), &types.QueryAccountRequest{Address: key.String()}) if err != nil { return err } @@ -110,6 +110,38 @@ func GetAccountCmd() *cobra.Command { return cmd } +// GetAccountsCmd returns a query command that will display a list of accounts +func GetAccountsCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "accounts", + Short: "Query all the accounts", + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } + + pageReq, err := client.ReadPageRequest(cmd.Flags()) + if err != nil { + return err + } + + queryClient := types.NewQueryClient(clientCtx) + res, err := queryClient.Accounts(cmd.Context(), &types.QueryAccountsRequest{Pagination: pageReq}) + if err != nil { + return err + } + + return clientCtx.PrintProto(res) + }, + } + + flags.AddQueryFlagsToCmd(cmd) + flags.AddPaginationFlagsToCmd(cmd, "all-accounts") + + return cmd +} + // QueryTxsByEventsCmd returns a command to search through transactions by events. func QueryTxsByEventsCmd() *cobra.Command { cmd := &cobra.Command{ @@ -123,7 +155,7 @@ to each module's documentation for the full set of events to query for. Each mod documents its respective events under 'xx_events.md'. Example: -$ %s query txs --%s 'message.sender=cosmos1...&message.action=withdraw_delegator_reward' --page 1 --limit 30 +$ %s query txs --%s 'message.sender=link1...&message.action=withdraw_delegator_reward' --page 1 --limit 30 `, eventFormat, version.AppName, flagEvents), ), RunE: func(cmd *cobra.Command, args []string) error { @@ -163,7 +195,7 @@ $ %s query txs --%s 'message.sender=cosmos1...&message.action=withdraw_delegator page, _ := cmd.Flags().GetInt(flags.FlagPage) limit, _ := cmd.Flags().GetInt(flags.FlagLimit) - txs, err := authclient.QueryTxsByEvents(clientCtx, tmEvents, page, limit, "") + txs, err := authtx.QueryTxsByEvents(clientCtx, tmEvents, page, limit, "") if err != nil { return err } @@ -172,8 +204,7 @@ $ %s query txs --%s 'message.sender=cosmos1...&message.action=withdraw_delegator }, } - cmd.Flags().StringP(flags.FlagNode, "n", "tcp://localhost:26657", "Node to connect to") - cmd.Flags().String(flags.FlagKeyringBackend, flags.DefaultKeyringBackend, "Select keyring's backend (os|file|kwallet|pass|test)") + flags.AddQueryFlagsToCmd(cmd) cmd.Flags().Int(flags.FlagPage, rest.DefaultPage, "Query a specific page of paginated results") cmd.Flags().Int(flags.FlagLimit, rest.DefaultLimit, "Query number of transactions results per page returned") cmd.Flags().String(flagEvents, "", fmt.Sprintf("list of transaction events in the form of %s", eventFormat)) @@ -213,7 +244,7 @@ $ %s query tx --%s=%s , } // If hash is given, then query the tx by hash. - output, err := authclient.QueryTx(clientCtx, args[0]) + output, err := authtx.QueryTx(clientCtx, args[0]) if err != nil { return err } @@ -235,7 +266,7 @@ $ %s query tx --%s=%s , tmEvents[i] = fmt.Sprintf("%s.%s='%s'", sdk.EventTypeTx, sdk.AttributeKeySignature, sig) } - txs, err := authclient.QueryTxsByEvents(clientCtx, tmEvents, rest.DefaultPage, query.DefaultLimit, "") + txs, err := authtx.QueryTxsByEvents(clientCtx, tmEvents, rest.DefaultPage, query.DefaultLimit, "") if err != nil { return err } @@ -244,7 +275,7 @@ $ %s query tx --%s=%s , } if len(txs.Txs) > 1 { // This case means there's a bug somewhere else in the code. Should not happen. - return errors.Wrapf(errors.ErrLogic, "found %d txs matching given signatures", len(txs.Txs)) + return errors.ErrLogic.Wrapf("found %d txs matching given signatures", len(txs.Txs)) } return clientCtx.PrintProto(txs.Txs[0]) @@ -258,7 +289,7 @@ $ %s query tx --%s=%s , tmEvents := []string{ fmt.Sprintf("%s.%s='%s'", sdk.EventTypeTx, sdk.AttributeKeyAccountSequence, args[0]), } - txs, err := authclient.QueryTxsByEvents(clientCtx, tmEvents, rest.DefaultPage, query.DefaultLimit, "") + txs, err := authtx.QueryTxsByEvents(clientCtx, tmEvents, rest.DefaultPage, query.DefaultLimit, "") if err != nil { return err } diff --git a/x/auth/client/cli/tx.go b/x/auth/client/cli/tx.go index 81c97e1262..65f9b1ba1b 100644 --- a/x/auth/client/cli/tx.go +++ b/x/auth/client/cli/tx.go @@ -40,7 +40,7 @@ func NewEmptyTxCmd() *cobra.Command { return err } - msg := types.NewServiceMsgEmpty(clientCtx.GetFromAddress()) + msg := types.NewMsgEmpty(clientCtx.GetFromAddress()) if err := msg.ValidateBasic(); err != nil { return err } diff --git a/x/auth/client/cli/tx_multisign.go b/x/auth/client/cli/tx_multisign.go index b9f3263bbf..48a18afb28 100644 --- a/x/auth/client/cli/tx_multisign.go +++ b/x/auth/client/cli/tx_multisign.go @@ -15,14 +15,21 @@ import ( "github.com/line/lbm-sdk/crypto/keyring" kmultisig "github.com/line/lbm-sdk/crypto/keys/multisig" "github.com/line/lbm-sdk/crypto/types/multisig" + sdk "github.com/line/lbm-sdk/types" "github.com/line/lbm-sdk/types/errors" signingtypes "github.com/line/lbm-sdk/types/tx/signing" "github.com/line/lbm-sdk/version" authclient "github.com/line/lbm-sdk/x/auth/client" - "github.com/line/lbm-sdk/x/auth/client/rest" + "github.com/line/lbm-sdk/x/auth/legacy/legacytx" "github.com/line/lbm-sdk/x/auth/signing" ) +// BroadcastReq defines a tx broadcasting request. +type BroadcastReq struct { + Tx legacytx.StdTx `json:"tx" yaml:"tx"` + Mode string `json:"mode" yaml:"mode"` +} + // GetSignCommand returns the sign command func GetMultiSignCommand() *cobra.Command { cmd := &cobra.Command{ @@ -121,7 +128,8 @@ func makeMultiSignCmd() func(cmd *cobra.Command, args []string) (err error) { for _, sig := range sigs { err = signing.VerifySignature(sig.PubKey, signingData, sig.Data, txCfg.SignModeHandler(), txBuilder.GetTx()) if err != nil { - return fmt.Errorf("couldn't verify signature: %w", err) + addr, _ := sdk.AccAddressFromHex(sig.PubKey.Address().String()) + return fmt.Errorf("couldn't verify signature for address %s", addr) } if err := multisig.AddSignatureV2(multisigSig, sig, multisigPub.GetPubKeys()); err != nil { @@ -153,7 +161,7 @@ func makeMultiSignCmd() func(cmd *cobra.Command, args []string) (err error) { return err } - req := rest.BroadcastReq{ + req := BroadcastReq{ Tx: stdTx, Mode: "block|sync|async", } @@ -336,7 +344,7 @@ func makeBatchMultisignCmd() func(cmd *cobra.Command, args []string) error { return err } - req := rest.BroadcastReq{ + req := BroadcastReq{ Tx: stdTx, Mode: "block|sync|async", } diff --git a/x/auth/client/cli/tx_sign.go b/x/auth/client/cli/tx_sign.go index 79fd2bbc4c..772dd288b9 100644 --- a/x/auth/client/cli/tx_sign.go +++ b/x/auth/client/cli/tx_sign.go @@ -9,9 +9,7 @@ import ( "github.com/line/lbm-sdk/client" "github.com/line/lbm-sdk/client/flags" "github.com/line/lbm-sdk/client/tx" - sdk "github.com/line/lbm-sdk/types" authclient "github.com/line/lbm-sdk/x/auth/client" - "github.com/line/lbm-sdk/x/auth/client/rest" ) const ( @@ -48,7 +46,7 @@ account key. It implies --signature-only. Args: cobra.ExactArgs(1), } - cmd.Flags().String(flagMultisig, "", "Address of the multisig account on behalf of which the transaction shall be signed") + cmd.Flags().String(flagMultisig, "", "Address or key name of the multisig account on behalf of which the transaction shall be signed") cmd.Flags().String(flags.FlagOutputDocument, "", "The document will be written to the given file instead of STDOUT") cmd.Flags().Bool(flagSigOnly, true, "Print only the generated signature, then exit") cmd.Flags().String(flags.FlagChainID, "", "network chain ID") @@ -68,11 +66,10 @@ func makeSignBatchCmd() func(cmd *cobra.Command, args []string) error { txCfg := clientCtx.TxConfig printSignatureOnly, _ := cmd.Flags().GetBool(flagSigOnly) infile := os.Stdin - var multisigAddr sdk.AccAddress - // validate multisig address if there's any - if ms, _ := cmd.Flags().GetString(flagMultisig); ms != "" { - multisigAddr = sdk.AccAddress(ms) + ms, err := cmd.Flags().GetString(flagMultisig) + if err != nil { + return err } // prepare output document @@ -99,7 +96,7 @@ func makeSignBatchCmd() func(cmd *cobra.Command, args []string) error { if err != nil { return err } - if multisigAddr.Empty() { + if ms == "" { from, _ := cmd.Flags().GetString(flags.FlagFrom) _, fromName, _, err := client.GetFromFields(txFactory.Keybase(), from, clientCtx.GenerateOnly) if err != nil { @@ -110,8 +107,15 @@ func makeSignBatchCmd() func(cmd *cobra.Command, args []string) error { return err } } else { + multisigAddr, _, _, err := client.GetFromFields(txFactory.Keybase(), ms, clientCtx.GenerateOnly) + if err != nil { + return fmt.Errorf("error getting account from keybase: %w", err) + } err = authclient.SignTxWithSignerAddress( txFactory, clientCtx, multisigAddr, clientCtx.GetFromName(), txBuilder, clientCtx.Offline, true) + if err != nil { + return err + } } if err != nil { @@ -137,7 +141,6 @@ func makeSignBatchCmd() func(cmd *cobra.Command, args []string) error { func setOutputFile(cmd *cobra.Command) (func(), error) { outputDoc, _ := cmd.Flags().GetString(flags.FlagOutputDocument) if outputDoc == "" { - cmd.SetOut(cmd.OutOrStdout()) return func() {}, nil } @@ -175,7 +178,7 @@ be generated via the 'multisign' command. Args: cobra.ExactArgs(1), } - cmd.Flags().String(flagMultisig, "", "Address of the multisig account on behalf of which the transaction shall be signed") + cmd.Flags().String(flagMultisig, "", "Address or key name of the multisig account on behalf of which the transaction shall be signed") cmd.Flags().Bool(flagOverwrite, false, "Overwrite existing signatures with a new one. If disabled, new signature will be appended") cmd.Flags().Bool(flagSigOnly, false, "Print only the signatures") cmd.Flags().String(flags.FlagOutputDocument, "", "The document will be written to the given file instead of STDOUT") @@ -210,6 +213,8 @@ func makeSignCmd() func(cmd *cobra.Command, args []string) error { if err != nil { return err } + + txFactory := tx.NewFactoryCLI(clientCtx, cmd.Flags()) txCfg := clientCtx.TxConfig txBuilder, err := txCfg.WrapTxBuilder(newTx) if err != nil { @@ -217,7 +222,10 @@ func makeSignCmd() func(cmd *cobra.Command, args []string) error { } printSignatureOnly, _ := cmd.Flags().GetBool(flagSigOnly) - multisigAddrStr, _ := cmd.Flags().GetString(flagMultisig) + multisig, _ := cmd.Flags().GetString(flagMultisig) + if err != nil { + return err + } from, _ := cmd.Flags().GetString(flags.FlagFrom) _, fromName, _, err := client.GetFromFields(txF.Keybase(), from, clientCtx.GenerateOnly) if err != nil { @@ -225,10 +233,16 @@ func makeSignCmd() func(cmd *cobra.Command, args []string) error { } overwrite, _ := f.GetBool(flagOverwrite) - if multisigAddrStr != "" { - multisigAddr := sdk.AccAddress(multisigAddrStr) + if multisig != "" { + multisigAddr, _, _, err := client.GetFromFields(txFactory.Keybase(), multisig, clientCtx.GenerateOnly) + if err != nil { + return fmt.Errorf("error getting account from keybase: %w", err) + } err = authclient.SignTxWithSignerAddress( txF, clientCtx, multisigAddr, fromName, txBuilder, clientCtx.Offline, overwrite) + if err != nil { + return err + } printSignatureOnly = true } else { err = authclient.SignTx(txF, clientCtx, clientCtx.GetFromName(), txBuilder, clientCtx.Offline, overwrite) @@ -248,7 +262,7 @@ func makeSignCmd() func(cmd *cobra.Command, args []string) error { if err != nil { return err } - req := rest.BroadcastReq{ + req := BroadcastReq{ Tx: stdTx, Mode: "block|sync|async", } diff --git a/x/auth/client/cli/validate_sigs.go b/x/auth/client/cli/validate_sigs.go index 673b60f330..b2c2dec83f 100644 --- a/x/auth/client/cli/validate_sigs.go +++ b/x/auth/client/cli/validate_sigs.go @@ -16,7 +16,7 @@ import ( func GetValidateSignaturesCommand() *cobra.Command { cmd := &cobra.Command{ Use: "validate-signatures [file]", - Short: "Validate transactions signatures", + Short: "validate transactions signatures", Long: `Print the addresses that must sign the transaction, those who have already signed it, and make sure that signatures are in the correct order. @@ -96,12 +96,12 @@ func printAndValidateSigs( success = false } - // Validate the actual signature over the transaction bytes since we can + // validate the actual signature over the transaction bytes since we can // reach out to a full node to query accounts. if !offline && success { accNum, accSeq, err := clientCtx.AccountRetriever.GetAccountNumberSequence(clientCtx, sigAddr) if err != nil { - cmd.Printf("failed to get account: %s\n", sigAddr) + cmd.PrintErrf("failed to get account: %s\n", sigAddr) return false } diff --git a/x/auth/client/rest/broadcast.go b/x/auth/client/rest/broadcast.go deleted file mode 100644 index ede1682818..0000000000 --- a/x/auth/client/rest/broadcast.go +++ /dev/null @@ -1,67 +0,0 @@ -package rest - -import ( - "fmt" - "io/ioutil" - "net/http" - - "github.com/line/lbm-sdk/client" - clientrest "github.com/line/lbm-sdk/client/rest" - "github.com/line/lbm-sdk/client/tx" - codectypes "github.com/line/lbm-sdk/codec/types" - "github.com/line/lbm-sdk/types/rest" - "github.com/line/lbm-sdk/x/auth/legacy/legacytx" -) - -// BroadcastReq defines a tx broadcasting request. -type BroadcastReq struct { - Tx legacytx.StdTx `json:"tx" yaml:"tx"` - Mode string `json:"mode" yaml:"mode"` -} - -var _ codectypes.UnpackInterfacesMessage = BroadcastReq{} - -// UnpackInterfaces implements the UnpackInterfacesMessage interface. -func (m BroadcastReq) UnpackInterfaces(unpacker codectypes.AnyUnpacker) error { - return m.Tx.UnpackInterfaces(unpacker) -} - -// BroadcastTxRequest implements a tx broadcasting handler that is responsible -// for broadcasting a valid and signed tx to a full node. The tx can be -// broadcasted via a sync|async|block mechanism. -func BroadcastTxRequest(clientCtx client.Context) http.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) { - var req BroadcastReq - - body, err := ioutil.ReadAll(r.Body) - if rest.CheckBadRequestError(w, err) { - return - } - - // NOTE: amino is used intentionally here, don't migrate it! - err = clientCtx.LegacyAmino.UnmarshalJSON(body, &req) - if err != nil { - err := fmt.Errorf("this transaction cannot be broadcasted via legacy REST endpoints, because it does not support"+ - " Amino serialization. Please either use CLI, gRPC, gRPC-gateway, or directly query the Tendermint RPC"+ - " endpoint to broadcast this transaction. The new REST endpoint (via gRPC-gateway) is POST /lbm/tx/v1/txs."+ - " Please also see the REST endpoints migration guide at %s for more info", clientrest.DeprecationURL) - if rest.CheckBadRequestError(w, err) { - return - } - } - - txBytes, err := tx.ConvertAndEncodeStdTx(clientCtx.TxConfig, req.Tx) - if rest.CheckInternalServerError(w, err) { - return - } - - clientCtx = clientCtx.WithBroadcastMode(req.Mode) - - res, err := clientCtx.BroadcastTx(txBytes) - if rest.CheckInternalServerError(w, err) { - return - } - - rest.PostProcessResponseBare(w, clientCtx, res) - } -} diff --git a/x/auth/client/rest/encode.go b/x/auth/client/rest/encode.go deleted file mode 100644 index 576ed81349..0000000000 --- a/x/auth/client/rest/encode.go +++ /dev/null @@ -1,63 +0,0 @@ -package rest - -import ( - "encoding/base64" - "fmt" - "io/ioutil" - "net/http" - - "github.com/line/lbm-sdk/client" - clientrest "github.com/line/lbm-sdk/client/rest" - "github.com/line/lbm-sdk/client/tx" - "github.com/line/lbm-sdk/types/rest" - "github.com/line/lbm-sdk/x/auth/legacy/legacytx" -) - -// EncodeResp defines a tx encoding response. -type EncodeResp struct { - Tx string `json:"tx" yaml:"tx"` -} - -// ErrEncodeDecode is the error to show when encoding/decoding txs that are not -// amino-serializable (e.g. IBC txs). -var ErrEncodeDecode error = fmt.Errorf("this endpoint does not support txs that are not serializable"+ - " via Amino, such as txs that contain IBC `Msg`s. For more info, please refer to our"+ - " REST migration guide at %s", clientrest.DeprecationURL) - -// EncodeTxRequestHandlerFn returns the encode tx REST handler. In particular, -// it takes a json-formatted transaction, encodes it to the Amino wire protocol, -// and responds with base64-encoded bytes. -func EncodeTxRequestHandlerFn(clientCtx client.Context) http.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) { - var req legacytx.StdTx - - body, err := ioutil.ReadAll(r.Body) - if rest.CheckBadRequestError(w, err) { - return - } - - // NOTE: amino is used intentionally here, don't migrate it - err = clientCtx.LegacyAmino.UnmarshalJSON(body, &req) - // If there's an unmarshalling error, we assume that it's because we're - // using amino to unmarshal a non-amino tx. - if err != nil { - if rest.CheckBadRequestError(w, ErrEncodeDecode) { - return - } - } - - // re-encode it in the chain's native binary format - txBytes, err := tx.ConvertAndEncodeStdTx(clientCtx.TxConfig, req) - if rest.CheckInternalServerError(w, err) { - return - } - - // base64 encode the encoded tx bytes - txBytesBase64 := base64.StdEncoding.EncodeToString(txBytes) - - response := EncodeResp{Tx: txBytesBase64} - - // NOTE: amino is set intentionally here, don't migrate it - rest.PostProcessResponseBare(w, clientCtx, response) - } -} diff --git a/x/auth/client/rest/query.go b/x/auth/client/rest/query.go index 298b205a55..9373fd5c23 100644 --- a/x/auth/client/rest/query.go +++ b/x/auth/client/rest/query.go @@ -13,7 +13,7 @@ import ( codectypes "github.com/line/lbm-sdk/codec/types" sdk "github.com/line/lbm-sdk/types" "github.com/line/lbm-sdk/types/rest" - authclient "github.com/line/lbm-sdk/x/auth/client" + authtx "github.com/line/lbm-sdk/x/auth/tx" "github.com/line/lbm-sdk/x/auth/types" genutilrest "github.com/line/lbm-sdk/x/genutil/client/rest" ) @@ -94,7 +94,7 @@ func QueryTxsRequestHandlerFn(clientCtx client.Context) http.HandlerFunc { return } - searchResult, err := authclient.QueryTxsByEvents(clientCtx, events, page, limit, "") + searchResult, err := authtx.QueryTxsByEvents(clientCtx, events, page, limit, "") if rest.CheckInternalServerError(w, err) { return } @@ -126,7 +126,7 @@ func QueryTxRequestHandlerFn(clientCtx client.Context) http.HandlerFunc { return } - output, err := authclient.QueryTx(clientCtx, hashHexStr) + output, err := authtx.QueryTx(clientCtx, hashHexStr) if err != nil { if strings.Contains(err.Error(), hashHexStr) { rest.WriteErrorResponse(w, http.StatusNotFound, err.Error()) diff --git a/x/auth/client/rest/rest.go b/x/auth/client/rest/rest.go index 8f67a836a4..f5e19b9597 100644 --- a/x/auth/client/rest/rest.go +++ b/x/auth/client/rest/rest.go @@ -30,7 +30,5 @@ func RegisterTxRoutes(clientCtx client.Context, rtr *mux.Router) { r := rest.WithHTTPDeprecationHeaders(rtr) r.HandleFunc("/txs/{hash}", QueryTxRequestHandlerFn(clientCtx)).Methods("GET") r.HandleFunc("/txs", QueryTxsRequestHandlerFn(clientCtx)).Methods("GET") - r.HandleFunc("/txs", BroadcastTxRequest(clientCtx)).Methods("POST") - r.HandleFunc("/txs/encode", EncodeTxRequestHandlerFn(clientCtx)).Methods("POST") r.HandleFunc("/txs/decode", DecodeTxRequestHandlerFn(clientCtx)).Methods("POST") } diff --git a/x/auth/client/rest/rest_test.go b/x/auth/client/rest/rest_test.go deleted file mode 100644 index 4467eb4c4c..0000000000 --- a/x/auth/client/rest/rest_test.go +++ /dev/null @@ -1,651 +0,0 @@ -//go:build norace -// +build norace - -package rest_test - -import ( - "fmt" - "strings" - "testing" - - "github.com/spf13/cobra" - "github.com/stretchr/testify/suite" - - "github.com/line/lbm-sdk/client/flags" - "github.com/line/lbm-sdk/client/tx" - "github.com/line/lbm-sdk/crypto/hd" - "github.com/line/lbm-sdk/crypto/keyring" - kmultisig "github.com/line/lbm-sdk/crypto/keys/multisig" - cryptotypes "github.com/line/lbm-sdk/crypto/types" - "github.com/line/lbm-sdk/testutil" - clitestutil "github.com/line/lbm-sdk/testutil/cli" - "github.com/line/lbm-sdk/testutil/network" - "github.com/line/lbm-sdk/testutil/testdata" - sdk "github.com/line/lbm-sdk/types" - "github.com/line/lbm-sdk/types/rest" - txtypes "github.com/line/lbm-sdk/types/tx" - "github.com/line/lbm-sdk/types/tx/signing" - authclient "github.com/line/lbm-sdk/x/auth/client" - authcli "github.com/line/lbm-sdk/x/auth/client/cli" - authrest "github.com/line/lbm-sdk/x/auth/client/rest" - authtest "github.com/line/lbm-sdk/x/auth/client/testutil" - "github.com/line/lbm-sdk/x/auth/legacy/legacytx" - bankcli "github.com/line/lbm-sdk/x/bank/client/testutil" - "github.com/line/lbm-sdk/x/bank/types" - ibccli "github.com/line/lbm-sdk/x/ibc/core/04-channel/client/cli" - ibcsolomachinecli "github.com/line/lbm-sdk/x/ibc/light-clients/06-solomachine/client/cli" -) - -type IntegrationTestSuite struct { - suite.Suite - - cfg network.Config - network *network.Network - - stdTx legacytx.StdTx - stdTxRes sdk.TxResponse -} - -func (s *IntegrationTestSuite) SetupSuite() { - s.T().Log("setting up integration test suite") - - cfg := network.DefaultConfig() - cfg.NumValidators = 2 - - s.cfg = cfg - s.network = network.New(s.T(), cfg) - - kb := s.network.Validators[0].ClientCtx.Keyring - _, _, err := kb.NewMnemonic("newAccount", keyring.English, sdk.FullFundraiserPath, hd.Secp256k1) - s.Require().NoError(err) - - account1, _, err := kb.NewMnemonic("newAccount1", keyring.English, sdk.FullFundraiserPath, hd.Secp256k1) - s.Require().NoError(err) - - account2, _, err := kb.NewMnemonic("newAccount2", keyring.English, sdk.FullFundraiserPath, hd.Secp256k1) - s.Require().NoError(err) - - multi := kmultisig.NewLegacyAminoPubKey(2, []cryptotypes.PubKey{account1.GetPubKey(), account2.GetPubKey()}) - _, err = kb.SaveMultisig("multi", multi) - s.Require().NoError(err) - - _, err = s.network.WaitForHeight(1) - s.Require().NoError(err) - - // Broadcast a StdTx used for tests. - s.stdTx = s.createTestStdTx(s.network.Validators[0], 0, 1) - res, err := s.broadcastReq(s.stdTx, "block") - s.Require().NoError(err) - - // NOTE: this uses amino explicitly, don't migrate it! - s.Require().NoError(s.cfg.LegacyAmino.UnmarshalJSON(res, &s.stdTxRes)) - s.Require().Equal(uint32(0), s.stdTxRes.Code) - - s.Require().NoError(s.network.WaitForNextBlock()) -} - -func (s *IntegrationTestSuite) TearDownSuite() { - s.T().Log("tearing down integration test suite") - s.network.Cleanup() -} - -func mkStdTx() legacytx.StdTx { - // NOTE: this uses StdTx explicitly, don't migrate it! - return legacytx.StdTx{ - Msgs: []sdk.Msg{&types.MsgSend{}}, - Fee: legacytx.StdFee{ - Amount: sdk.Coins{sdk.NewInt64Coin("foo", 10)}, - Gas: 10000, - }, - Memo: "FOOBAR", - } -} - -// Create an IBC tx that's encoded as amino-JSON. Since we can't amino-marshal -// a tx with "lbm-sdk/MsgTransfer" using the SDK, we just hardcode the tx -// here. But external clients might, see https://github.com/line/lbm-sdk/issues/8022. -func mkIBCStdTx() []byte { - ibcTx := `{ - "account_number": "68", - "chain_id": "stargate-4", - "fee": { - "amount": [ - { - "amount": "3500", - "denom": "umuon" - } - ], - "gas": "350000" - }, - "memo": "", - "msg": [ - { - "type": "lbm-sdk/MsgTransfer", - "value": { - "receiver": "cosmos1q9wtnlwdjrhwtcjmt2uq77jrgx7z3usrq2yz7z", - "sender": "cosmos1q9wtnlwdjrhwtcjmt2uq77jrgx7z3usrq2yz7z", - "source_channel": "THEslipperCHANNEL", - "source_port": "transfer", - "token": { - "amount": "1000000", - "denom": "umuon" - } - } - } - ], - "sequence": "24" - }` - req := fmt.Sprintf(`{"tx":%s,"mode":"async"}`, ibcTx) - - return []byte(req) -} - -func (s *IntegrationTestSuite) TestEncodeDecode() { - var require = s.Require() - val := s.network.Validators[0] - stdTx := mkStdTx() - - // NOTE: this uses amino explicitly, don't migrate it! - cdc := val.ClientCtx.LegacyAmino - - bz, err := cdc.MarshalJSON(stdTx) - require.NoError(err) - - res, err := rest.PostRequest(fmt.Sprintf("%s/txs/encode", val.APIAddress), "application/json", bz) - require.NoError(err) - - var encodeResp authrest.EncodeResp - err = cdc.UnmarshalJSON(res, &encodeResp) - require.NoError(err) - - bz, err = cdc.MarshalJSON(authrest.DecodeReq{Tx: encodeResp.Tx}) - require.NoError(err) - - res, err = rest.PostRequest(fmt.Sprintf("%s/txs/decode", val.APIAddress), "application/json", bz) - require.NoError(err) - - var respWithHeight rest.ResponseWithHeight - err = cdc.UnmarshalJSON(res, &respWithHeight) - require.NoError(err) - var decodeResp authrest.DecodeResp - err = cdc.UnmarshalJSON(respWithHeight.Result, &decodeResp) - require.NoError(err) - require.Equal(stdTx, legacytx.StdTx(decodeResp)) -} - -func (s *IntegrationTestSuite) TestEncodeIBCTx() { - val := s.network.Validators[0] - - req := mkIBCStdTx() - res, err := rest.PostRequest(fmt.Sprintf("%s/txs/encode", val.APIAddress), "application/json", []byte(req)) - s.Require().NoError(err) - - s.Require().Contains(string(res), authrest.ErrEncodeDecode.Error()) -} - -func (s *IntegrationTestSuite) TestBroadcastTxRequest() { - stdTx := mkStdTx() - - // we just test with async mode because this tx will fail - all we care about is that it got encoded and broadcast correctly - res, err := s.broadcastReq(stdTx, "async") - s.Require().NoError(err) - var txRes sdk.TxResponse - // NOTE: this uses amino explicitly, don't migrate it! - s.Require().NoError(s.cfg.LegacyAmino.UnmarshalJSON(res, &txRes)) - // we just check for a non-empty TxHash here, the actual hash will depend on the underlying tx configuration - s.Require().NotEmpty(txRes.TxHash) -} - -func (s *IntegrationTestSuite) TestBroadcastIBCTxRequest() { - val := s.network.Validators[0] - - req := mkIBCStdTx() - res, err := rest.PostRequest(fmt.Sprintf("%s/txs", val.APIAddress), "application/json", []byte(req)) - s.Require().NoError(err) - - s.Require().NotContains(string(res), "this transaction cannot be broadcasted via legacy REST endpoints", string(res)) -} - -// Helper function to test querying txs. We will use it to query StdTx and service `Msg`s. -func (s *IntegrationTestSuite) testQueryTx(txHeight int64, txHash, txRecipient string) { - val0 := s.network.Validators[0] - - testCases := []struct { - desc string - malleate func() *sdk.TxResponse - }{ - { - "Query by hash", - func() *sdk.TxResponse { - txJSON, err := rest.GetRequest(fmt.Sprintf("%s/txs/%s", val0.APIAddress, txHash)) - s.Require().NoError(err) - - var txResAmino sdk.TxResponse - s.Require().NoError(val0.ClientCtx.LegacyAmino.UnmarshalJSON(txJSON, &txResAmino)) - return &txResAmino - }, - }, - { - "Query by height", - func() *sdk.TxResponse { - txJSON, err := rest.GetRequest(fmt.Sprintf("%s/txs?limit=10&page=1&tx.height=%d", val0.APIAddress, txHeight)) - s.Require().NoError(err) - - var searchtxResult sdk.SearchTxsResult - s.Require().NoError(val0.ClientCtx.LegacyAmino.UnmarshalJSON(txJSON, &searchtxResult)) - s.Require().Len(searchtxResult.Txs, 1) - return searchtxResult.Txs[0] - }, - }, - { - "Query by event (transfer.recipient)", - func() *sdk.TxResponse { - txJSON, err := rest.GetRequest(fmt.Sprintf("%s/txs?transfer.recipient=%s", val0.APIAddress, txRecipient)) - s.Require().NoError(err) - - var searchtxResult sdk.SearchTxsResult - s.Require().NoError(val0.ClientCtx.LegacyAmino.UnmarshalJSON(txJSON, &searchtxResult)) - s.Require().Len(searchtxResult.Txs, 1) - return searchtxResult.Txs[0] - }, - }, - } - - for _, tc := range testCases { - s.Run(fmt.Sprintf("Case %s", tc.desc), func() { - txResponse := tc.malleate() - - // Check that the height is correct. - s.Require().Equal(txHeight, txResponse.Height) - - // Check that the events are correct. - s.Require().Contains( - txResponse.RawLog, - fmt.Sprintf("{\"key\":\"recipient\",\"value\":\"%s\"}", txRecipient), - ) - - // Check that the Msg is correct. - stdTx, ok := txResponse.Tx.GetCachedValue().(legacytx.StdTx) - s.Require().True(ok) - msgs := stdTx.GetMsgs() - s.Require().Equal(len(msgs), 1) - msg, ok := msgs[0].(*types.MsgSend) - s.Require().True(ok) - s.Require().Equal(txRecipient, msg.ToAddress) - }) - } -} - -func (s *IntegrationTestSuite) TestQueryTxWithStdTx() { - val0 := s.network.Validators[0] - - // We broadcasted a StdTx in SetupSuite. - // We just check for a non-empty TxHash here, the actual hash will depend on the underlying tx configuration - s.Require().NotEmpty(s.stdTxRes.TxHash) - - s.testQueryTx(s.stdTxRes.Height, s.stdTxRes.TxHash, val0.Address.String()) -} - -func (s *IntegrationTestSuite) TestQueryTxWithServiceMessage() { - val := s.network.Validators[0] - - sendTokens := sdk.NewInt64Coin(s.cfg.BondDenom, 10) - _, _, addr := testdata.KeyTestPubAddr() - - // Might need to wait a block to refresh sequences from previous setups. - s.Require().NoError(s.network.WaitForNextBlock()) - - out, err := bankcli.ServiceMsgSendExec( - val.ClientCtx, - val.Address, - addr, - sdk.NewCoins(sendTokens), - fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), - fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), - fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), - fmt.Sprintf("--gas=%d", flags.DefaultGasLimit), - ) - - s.Require().NoError(err) - var txRes sdk.TxResponse - s.Require().NoError(val.ClientCtx.JSONMarshaler.UnmarshalJSON(out.Bytes(), &txRes)) - s.Require().Equal(uint32(0), txRes.Code) - - s.Require().NoError(s.network.WaitForNextBlock()) - - s.testQueryTx(txRes.Height, txRes.TxHash, addr.String()) -} - -func (s *IntegrationTestSuite) TestMultipleSyncBroadcastTxRequests() { - // First test transaction from validator should have sequence=1 (non-genesis tx) - testCases := []struct { - desc string - sequence uint64 - shouldErr bool - }{ - { - "First tx (correct sequence)", - 1, - false, - }, - { - "Second tx (correct sequence)", - 2, - false, - }, - { - "Third tx (incorrect sequence)", - 9, - true, - }, - } - for _, tc := range testCases { - s.Run(fmt.Sprintf("Case %s", tc.desc), func() { - // broadcast test with sync mode, as we want to run CheckTx to verify account sequence is correct - stdTx := s.createTestStdTx(s.network.Validators[1], 1, tc.sequence) - res, err := s.broadcastReq(stdTx, "sync") - s.Require().NoError(err) - - var txRes sdk.TxResponse - // NOTE: this uses amino explicitly, don't migrate it! - s.Require().NoError(s.cfg.LegacyAmino.UnmarshalJSON(res, &txRes)) - // we check for a exitCode=0, indicating a successful broadcast - if tc.shouldErr { - var sigVerifyFailureCode uint32 = 4 - s.Require().Equal(sigVerifyFailureCode, txRes.Code, - "Testcase '%s': Expected signature verification failure {Code: %d} from TxResponse. "+ - "Found {Code: %d, RawLog: '%v'}", - tc.desc, sigVerifyFailureCode, txRes.Code, txRes.RawLog, - ) - } else { - s.Require().Equal(uint32(0), txRes.Code, - "Testcase '%s': TxResponse errored unexpectedly. Err: {Code: %d, RawLog: '%v'}", - tc.desc, txRes.Code, txRes.RawLog, - ) - } - }) - } -} - -func (s *IntegrationTestSuite) createTestStdTx(val *network.Validator, accNum, sequence uint64) legacytx.StdTx { - txConfig := legacytx.StdTxConfig{Cdc: s.cfg.LegacyAmino} - - msg := &types.MsgSend{ - FromAddress: val.Address.String(), - ToAddress: val.Address.String(), - Amount: sdk.Coins{sdk.NewInt64Coin(fmt.Sprintf("%stoken", val.Moniker), 100)}, - } - - // prepare txBuilder with msg - txBuilder := txConfig.NewTxBuilder() - feeAmount := sdk.Coins{sdk.NewInt64Coin(s.cfg.BondDenom, 10)} - gasLimit := testdata.NewTestGasLimit() - txBuilder.SetMsgs(msg) - txBuilder.SetFeeAmount(feeAmount) - txBuilder.SetGasLimit(gasLimit) - txBuilder.SetMemo("foobar") - - // setup txFactory - txFactory := tx.Factory{}. - WithChainID(val.ClientCtx.ChainID). - WithKeybase(val.ClientCtx.Keyring). - WithTxConfig(txConfig). - WithSignMode(signing.SignMode_SIGN_MODE_LEGACY_AMINO_JSON). - WithAccountNumber(accNum). - WithSequence(sequence) - - // sign Tx (offline mode so we can manually set sequence number) - err := authclient.SignTx(txFactory, val.ClientCtx, val.Moniker, txBuilder, true, true) - s.Require().NoError(err) - - stdTx := txBuilder.GetTx().(legacytx.StdTx) - - return stdTx -} - -func (s *IntegrationTestSuite) broadcastReq(stdTx legacytx.StdTx, mode string) ([]byte, error) { - val := s.network.Validators[0] - - // NOTE: this uses amino explicitly, don't migrate it! - cdc := val.ClientCtx.LegacyAmino - req := authrest.BroadcastReq{ - Tx: stdTx, - Mode: mode, - } - bz, err := cdc.MarshalJSON(req) - s.Require().NoError(err) - - return rest.PostRequest(fmt.Sprintf("%s/txs", val.APIAddress), "application/json", bz) -} - -// testQueryIBCTx is a helper function to test querying txs which: -// - show an error message on legacy REST endpoints -// - succeed using gRPC -// In practice, we call this function on IBC txs. -func (s *IntegrationTestSuite) testQueryIBCTx(txRes sdk.TxResponse, cmd *cobra.Command, args []string) { - val := s.network.Validators[0] - - errMsg := "this transaction cannot be displayed via legacy REST endpoints, because it does not support" + - " Amino serialization. Please either use CLI, gRPC, gRPC-gateway, or directly query the Tendermint RPC" + - " endpoint to query this transaction. The new REST endpoint (via gRPC-gateway) is " - - // Test that legacy endpoint return the above error message on IBC txs. - testCases := []struct { - desc string - url string - }{ - { - "Query by hash", - fmt.Sprintf("%s/txs/%s", val.APIAddress, txRes.TxHash), - }, - { - "Query by height", - fmt.Sprintf("%s/txs?tx.height=%d", val.APIAddress, txRes.Height), - }, - } - - for _, tc := range testCases { - s.Run(fmt.Sprintf("Case %s", tc.desc), func() { - txJSON, err := rest.GetRequest(tc.url) - s.Require().NoError(err) - - var errResp rest.ErrorResponse - s.Require().NoError(val.ClientCtx.LegacyAmino.UnmarshalJSON(txJSON, &errResp)) - - s.Require().Contains(errResp.Error, errMsg) - }) - } - - // try fetching the txn using gRPC req, it will fetch info since it has proto codec. - grpcJSON, err := rest.GetRequest(fmt.Sprintf("%s/lbm/tx/v1/txs/%s", val.APIAddress, txRes.TxHash)) - s.Require().NoError(err) - - var getTxRes txtypes.GetTxResponse - s.Require().NoError(val.ClientCtx.JSONMarshaler.UnmarshalJSON(grpcJSON, &getTxRes)) - s.Require().Equal(getTxRes.Tx.Body.Memo, "foobar") - - // generate broadcast only txn. - args = append(args, fmt.Sprintf("--%s=true", flags.FlagGenerateOnly)) - out, err := clitestutil.ExecTestCLICmd(val.ClientCtx, cmd, args) - s.Require().NoError(err) - - txFile := testutil.WriteToNewTempFile(s.T(), string(out.Bytes())) - txFileName := txFile.Name() - - // encode the generated txn. - out, err = clitestutil.ExecTestCLICmd(val.ClientCtx, authcli.GetEncodeCommand(), []string{txFileName}) - s.Require().NoError(err) - - bz, err := val.ClientCtx.LegacyAmino.MarshalJSON(authrest.DecodeReq{Tx: string(out.Bytes())}) - s.Require().NoError(err) - - // try to decode the txn using legacy rest, it fails. - res, err := rest.PostRequest(fmt.Sprintf("%s/txs/decode", val.APIAddress), "application/json", bz) - s.Require().NoError(err) - - var errResp rest.ErrorResponse - s.Require().NoError(val.ClientCtx.LegacyAmino.UnmarshalJSON(res, &errResp)) - s.Require().Contains(errResp.Error, errMsg) -} - -// TestLegacyRestErrMessages creates two IBC txs, one that fails, one that -// succeeds, and make sure we cannot query any of them (with pretty error msg). -// Our intension is to test the error message of querying a message which is -// signed with proto, since IBC won't support legacy amino at all we are -// considering a message from IBC module. -func (s *IntegrationTestSuite) TestLegacyRestErrMessages() { - val := s.network.Validators[0] - - // Write consensus json to temp file, used for an IBC message. - consensusJSON := testutil.WriteToNewTempFile( - s.T(), - `{"public_key":{"@type":"/lbm.crypto.secp256k1.PubKey","key":"A/3SXL2ONYaOkxpdR5P8tHTlSlPv1AwQwSFxKRee5JQW"},"diversifier":"diversifier","timestamp":"10"}`, - ) - - testCases := []struct { - desc string - cmd *cobra.Command - args []string - code uint32 - }{ - { - "Failing IBC message", - ibccli.NewChannelCloseInitCmd(), - []string{ - "121", // dummy port-id - "channel-0", // dummy channel-id - fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), - fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), - fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), - fmt.Sprintf("--gas=%d", flags.DefaultGasLimit), - fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()), - fmt.Sprintf("--%s=foobar", flags.FlagMemo), - }, - uint32(7), - }, - { - "Successful IBC message", - ibcsolomachinecli.NewCreateClientCmd(), - []string{ - "1", // dummy sequence - consensusJSON.Name(), // path to consensus json, - fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), - fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), - fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), - fmt.Sprintf("--gas=%d", flags.DefaultGasLimit), - fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()), - fmt.Sprintf("--%s=foobar", flags.FlagMemo), - }, - uint32(0), - }, - } - - for _, tc := range testCases { - s.Run(fmt.Sprintf("Case %s", tc.desc), func() { - out, err := clitestutil.ExecTestCLICmd(val.ClientCtx, tc.cmd, tc.args) - s.Require().NoError(err) - var txRes sdk.TxResponse - s.Require().NoError(val.ClientCtx.JSONMarshaler.UnmarshalJSON(out.Bytes(), &txRes)) - s.Require().Equal(tc.code, txRes.Code) - - s.Require().NoError(s.network.WaitForNextBlock()) - - s.testQueryIBCTx(txRes, tc.cmd, tc.args) - }) - } -} - -// TestLegacyMultiSig creates a legacy multisig transaction, and makes sure -// we can query it via the legacy REST endpoint. -// ref: https://github.com/line/lbm-sdk/issues/8679 -func (s *IntegrationTestSuite) TestLegacyMultisig() { - val1 := *s.network.Validators[0] - - // Generate 2 accounts and a multisig. - account1, err := val1.ClientCtx.Keyring.Key("newAccount1") - s.Require().NoError(err) - - account2, err := val1.ClientCtx.Keyring.Key("newAccount2") - s.Require().NoError(err) - - multisigInfo, err := val1.ClientCtx.Keyring.Key("multi") - s.Require().NoError(err) - - // Send coins from validator to multisig. - sendTokens := sdk.NewInt64Coin(s.cfg.BondDenom, 1000) - _, err = bankcli.MsgSendExec( - val1.ClientCtx, - val1.Address, - multisigInfo.GetAddress(), - sdk.NewCoins(sendTokens), - fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), - fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), - fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), - fmt.Sprintf("--gas=%d", flags.DefaultGasLimit), - ) - - s.Require().NoError(s.network.WaitForNextBlock()) - - // Generate multisig transaction to a random address. - _, _, recipient := testdata.KeyTestPubAddr() - multiGeneratedTx, err := bankcli.MsgSendExec( - val1.ClientCtx, - multisigInfo.GetAddress(), - recipient, - sdk.NewCoins( - sdk.NewInt64Coin(s.cfg.BondDenom, 5), - ), - fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), - fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), - fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), - fmt.Sprintf("--%s=true", flags.FlagGenerateOnly), - ) - s.Require().NoError(err) - - // Save tx to file - multiGeneratedTxFile := testutil.WriteToNewTempFile(s.T(), multiGeneratedTx.String()) - - // Sign with account1 - val1.ClientCtx.HomeDir = strings.Replace(val1.ClientCtx.HomeDir, "simd", "simcli", 1) - account1Signature, err := authtest.TxSignExec(val1.ClientCtx, account1.GetAddress(), multiGeneratedTxFile.Name(), "--multisig", multisigInfo.GetAddress().String()) - s.Require().NoError(err) - - sign1File := testutil.WriteToNewTempFile(s.T(), account1Signature.String()) - - // Sign with account1 - account2Signature, err := authtest.TxSignExec(val1.ClientCtx, account2.GetAddress(), multiGeneratedTxFile.Name(), "--multisig", multisigInfo.GetAddress().String()) - s.Require().NoError(err) - - sign2File := testutil.WriteToNewTempFile(s.T(), account2Signature.String()) - - // Does not work in offline mode. - _, err = authtest.TxMultiSignExec(val1.ClientCtx, multisigInfo.GetName(), multiGeneratedTxFile.Name(), "--offline", sign1File.Name(), sign2File.Name()) - s.Require().EqualError(err, fmt.Sprintf("couldn't verify signature: unable to verify single signer signature")) - - val1.ClientCtx.Offline = false - multiSigWith2Signatures, err := authtest.TxMultiSignExec(val1.ClientCtx, multisigInfo.GetName(), multiGeneratedTxFile.Name(), sign1File.Name(), sign2File.Name()) - s.Require().NoError(err) - - // Write the output to disk - signedTxFile := testutil.WriteToNewTempFile(s.T(), multiSigWith2Signatures.String()) - - _, err = authtest.TxValidateSignaturesExec(val1.ClientCtx, signedTxFile.Name()) - s.Require().NoError(err) - - val1.ClientCtx.BroadcastMode = flags.BroadcastBlock - out, err := authtest.TxBroadcastExec(val1.ClientCtx, signedTxFile.Name()) - s.Require().NoError(err) - - s.Require().NoError(s.network.WaitForNextBlock()) - - var txRes sdk.TxResponse - err = val1.ClientCtx.JSONMarshaler.UnmarshalJSON(out.Bytes(), &txRes) - s.Require().NoError(err) - s.Require().Equal(uint32(0), txRes.Code) - - s.testQueryTx(txRes.Height, txRes.TxHash, recipient.String()) -} - -func TestIntegrationTestSuite(t *testing.T) { - suite.Run(t, new(IntegrationTestSuite)) -} diff --git a/x/auth/client/testutil/cli_test.go b/x/auth/client/testutil/cli_test.go new file mode 100644 index 0000000000..df2d1b5152 --- /dev/null +++ b/x/auth/client/testutil/cli_test.go @@ -0,0 +1,18 @@ +//go:build norace +// +build norace + +package testutil + +import ( + "testing" + + "github.com/line/lbm-sdk/testutil/network" + + "github.com/stretchr/testify/suite" +) + +func TestIntegrationTestSuite(t *testing.T) { + cfg := network.DefaultConfig() + cfg.NumValidators = 2 + suite.Run(t, NewIntegrationTestSuite(cfg)) +} diff --git a/x/auth/client/cli/cli_test.go b/x/auth/client/testutil/suite.go similarity index 70% rename from x/auth/client/cli/cli_test.go rename to x/auth/client/testutil/suite.go index bc8799c1d9..8ae7420300 100644 --- a/x/auth/client/cli/cli_test.go +++ b/x/auth/client/testutil/suite.go @@ -1,7 +1,4 @@ -//go:build norace -// +build norace - -package cli_test +package testutil import ( "context" @@ -13,10 +10,11 @@ import ( "strings" "testing" - ostcli "github.com/line/ostracon/libs/cli" "github.com/stretchr/testify/require" "github.com/stretchr/testify/suite" + ostcli "github.com/line/ostracon/libs/cli" + "github.com/line/lbm-sdk/client" "github.com/line/lbm-sdk/client/flags" "github.com/line/lbm-sdk/crypto/hd" @@ -32,8 +30,6 @@ import ( "github.com/line/lbm-sdk/types/tx" "github.com/line/lbm-sdk/types/tx/signing" authcli "github.com/line/lbm-sdk/x/auth/client/cli" - authrest "github.com/line/lbm-sdk/x/auth/client/rest" - authtest "github.com/line/lbm-sdk/x/auth/client/testutil" authtypes "github.com/line/lbm-sdk/x/auth/types" bankcli "github.com/line/lbm-sdk/x/bank/client/testutil" banktypes "github.com/line/lbm-sdk/x/bank/types" @@ -46,23 +42,23 @@ type IntegrationTestSuite struct { network *network.Network } +func NewIntegrationTestSuite(cfg network.Config) *IntegrationTestSuite { + return &IntegrationTestSuite{cfg: cfg} +} + func (s *IntegrationTestSuite) SetupSuite() { s.T().Log("setting up integration test suite") - cfg := network.DefaultConfig() - cfg.NumValidators = 2 - - s.cfg = cfg - s.network = network.New(s.T(), cfg) + s.network = network.New(s.T(), s.cfg) kb := s.network.Validators[0].ClientCtx.Keyring - _, _, err := kb.NewMnemonic("newAccount", keyring.English, sdk.FullFundraiserPath, hd.Secp256k1) + _, _, err := kb.NewMnemonic("newAccount", keyring.English, sdk.FullFundraiserPath, keyring.DefaultBIP39Passphrase, hd.Secp256k1) s.Require().NoError(err) - account1, _, err := kb.NewMnemonic("newAccount1", keyring.English, sdk.FullFundraiserPath, hd.Secp256k1) + account1, _, err := kb.NewMnemonic("newAccount1", keyring.English, sdk.FullFundraiserPath, keyring.DefaultBIP39Passphrase, hd.Secp256k1) s.Require().NoError(err) - account2, _, err := kb.NewMnemonic("newAccount2", keyring.English, sdk.FullFundraiserPath, hd.Secp256k1) + account2, _, err := kb.NewMnemonic("newAccount2", keyring.English, sdk.FullFundraiserPath, keyring.DefaultBIP39Passphrase, hd.Secp256k1) s.Require().NoError(err) multi := kmultisig.NewLegacyAminoPubKey(2, []cryptotypes.PubKey{account1.GetPubKey(), account2.GetPubKey()}) @@ -90,14 +86,15 @@ func (s *IntegrationTestSuite) TestCLIValidateSignatures() { // write unsigned tx to file unsignedTx := testutil.WriteToNewTempFile(s.T(), res.String()) - res, err = authtest.TxSignExec(val.ClientCtx, val.Address, unsignedTx.Name()) + res, err = TxSignExec(val.ClientCtx, val.Address, unsignedTx.Name()) s.Require().NoError(err) signedTx, err := val.ClientCtx.TxConfig.TxJSONDecoder()(res.Bytes()) s.Require().NoError(err) signedTxFile := testutil.WriteToNewTempFile(s.T(), res.String()) txBuilder, err := val.ClientCtx.TxConfig.WrapTxBuilder(signedTx) - res, err = authtest.TxValidateSignaturesExec(val.ClientCtx, signedTxFile.Name()) + s.Require().NoError(err) + _, err = TxValidateSignaturesExec(val.ClientCtx, signedTxFile.Name()) s.Require().NoError(err) txBuilder.SetMemo("MODIFIED TX") @@ -106,7 +103,7 @@ func (s *IntegrationTestSuite) TestCLIValidateSignatures() { modifiedTxFile := testutil.WriteToNewTempFile(s.T(), string(bz)) - res, err = authtest.TxValidateSignaturesExec(val.ClientCtx, modifiedTxFile.Name()) + _, err = TxValidateSignaturesExec(val.ClientCtx, modifiedTxFile.Name()) s.Require().EqualError(err, "signatures validation failed") } @@ -125,30 +122,30 @@ func (s *IntegrationTestSuite) TestCLISignBatch() { val.ClientCtx.HomeDir = strings.Replace(val.ClientCtx.HomeDir, "simd", "simcli", 1) // sign-batch file - offline is set but account-number and sequence are not - res, err := authtest.TxSignBatchExec(val.ClientCtx, val.Address, outputFile.Name(), fmt.Sprintf("--%s=%s", flags.FlagChainID, val.ClientCtx.ChainID), "--offline") + _, err = TxSignBatchExec(val.ClientCtx, val.Address, outputFile.Name(), fmt.Sprintf("--%s=%s", flags.FlagChainID, val.ClientCtx.ChainID), "--offline") s.Require().EqualError(err, "required flag(s) \"account-number\", \"sequence\" not set") // sign-batch file - res, err = authtest.TxSignBatchExec(val.ClientCtx, val.Address, outputFile.Name(), fmt.Sprintf("--%s=%s", flags.FlagChainID, val.ClientCtx.ChainID)) + res, err := TxSignBatchExec(val.ClientCtx, val.Address, outputFile.Name(), fmt.Sprintf("--%s=%s", flags.FlagChainID, val.ClientCtx.ChainID)) s.Require().NoError(err) s.Require().Equal(3, len(strings.Split(strings.Trim(res.String(), "\n"), "\n"))) - // sign-batch file - res, err = authtest.TxSignBatchExec(val.ClientCtx, val.Address, outputFile.Name(), fmt.Sprintf("--%s=%s", flags.FlagChainID, val.ClientCtx.ChainID), "--signature-only") + // sign-batch file signature only + res, err = TxSignBatchExec(val.ClientCtx, val.Address, outputFile.Name(), fmt.Sprintf("--%s=%s", flags.FlagChainID, val.ClientCtx.ChainID), "--signature-only") s.Require().NoError(err) s.Require().Equal(3, len(strings.Split(strings.Trim(res.String(), "\n"), "\n"))) // Sign batch malformed tx file. malformedFile := testutil.WriteToNewTempFile(s.T(), fmt.Sprintf("%smalformed", generatedStd)) - res, err = authtest.TxSignBatchExec(val.ClientCtx, val.Address, malformedFile.Name(), fmt.Sprintf("--%s=%s", flags.FlagChainID, val.ClientCtx.ChainID)) + _, err = TxSignBatchExec(val.ClientCtx, val.Address, malformedFile.Name(), fmt.Sprintf("--%s=%s", flags.FlagChainID, val.ClientCtx.ChainID)) s.Require().Error(err) // Sign batch malformed tx file signature only. - res, err = authtest.TxSignBatchExec(val.ClientCtx, val.Address, malformedFile.Name(), fmt.Sprintf("--%s=%s", flags.FlagChainID, val.ClientCtx.ChainID), "--signature-only") + _, err = TxSignBatchExec(val.ClientCtx, val.Address, malformedFile.Name(), fmt.Sprintf("--%s=%s", flags.FlagChainID, val.ClientCtx.ChainID), "--signature-only") s.Require().Error(err) } -func (s *IntegrationTestSuite) TestCLISign_AminoJSON() { +func (s *IntegrationTestSuite) TestCLISignAminoJSON() { require := s.Require() val1 := s.network.Validators[0] txCfg := val1.ClientCtx.TxConfig @@ -164,19 +161,19 @@ func (s *IntegrationTestSuite) TestCLISign_AminoJSON() { sigOnlyFlag := "--signature-only" signModeAminoFlag := "--sign-mode=amino-json" - // SIC! validators have same key names and same adddresses as those registered in the keyring, + // SIC! validators have same key names and same addresses as those registered in the keyring, // BUT the keys are different! valInfo, err := val1.ClientCtx.Keyring.Key(val1.Moniker) require.NoError(err) // query account info - queryResJSON, err := authtest.QueryAccountExec(val1.ClientCtx, val1.Address) + queryResJSON, err := QueryAccountExec(val1.ClientCtx, val1.Address) require.NoError(err) var account authtypes.AccountI - require.NoError(val1.ClientCtx.JSONMarshaler.UnmarshalInterfaceJSON(queryResJSON.Bytes(), &account)) + require.NoError(val1.ClientCtx.Codec.UnmarshalInterfaceJSON(queryResJSON.Bytes(), &account)) /**** test signature-only ****/ - res, err := authtest.TxSignExec(val1.ClientCtx, val1.Address, fileUnsigned.Name(), chainFlag, + res, err := TxSignExec(val1.ClientCtx, val1.Address, fileUnsigned.Name(), chainFlag, sigOnlyFlag, signModeAminoFlag) require.NoError(err) checkSignatures(require, txCfg, res.Bytes(), valInfo.GetPubKey()) @@ -186,7 +183,7 @@ func (s *IntegrationTestSuite) TestCLISign_AminoJSON() { require.Equal(account.GetSequence(), sigs[0].Sequence) /**** test full output ****/ - res, err = authtest.TxSignExec(val1.ClientCtx, val1.Address, fileUnsigned.Name(), chainFlag, signModeAminoFlag) + res, err = TxSignExec(val1.ClientCtx, val1.Address, fileUnsigned.Name(), chainFlag, signModeAminoFlag) require.NoError(err) // txCfg.UnmarshalSignatureJSON can't unmarshal a fragment of the signature, so we create this structure. @@ -201,14 +198,14 @@ func (s *IntegrationTestSuite) TestCLISign_AminoJSON() { /**** test file output ****/ filenameSigned := filepath.Join(s.T().TempDir(), "test_sign_out.json") fileFlag := fmt.Sprintf("--%s=%s", flags.FlagOutputDocument, filenameSigned) - _, err = authtest.TxSignExec(val1.ClientCtx, val1.Address, fileUnsigned.Name(), chainFlag, fileFlag, signModeAminoFlag) + _, err = TxSignExec(val1.ClientCtx, val1.Address, fileUnsigned.Name(), chainFlag, fileFlag, signModeAminoFlag) require.NoError(err) fContent, err := ioutil.ReadFile(filenameSigned) require.NoError(err) require.Equal(res.String(), string(fContent)) /**** try to append to the previously signed transaction ****/ - res, err = authtest.TxSignExec(val1.ClientCtx, val1.Address, filenameSigned, chainFlag, + res, err = TxSignExec(val1.ClientCtx, val1.Address, filenameSigned, chainFlag, sigOnlyFlag, signModeAminoFlag) require.NoError(err) checkSignatures(require, txCfg, res.Bytes(), valInfo.GetPubKey(), valInfo.GetPubKey()) @@ -219,16 +216,17 @@ func (s *IntegrationTestSuite) TestCLISign_AminoJSON() { // account. Changing the file is too much hacking, because TxDecoder returns sdk.Tx, which doesn't // provide functionality to check / manage `auth_info`. // Cases with different keys are are covered in unit tests of `tx.Sign`. - res, err = authtest.TxSignExec(val1.ClientCtx, val1.Address, filenameSigned, chainFlag, + res, err = TxSignExec(val1.ClientCtx, val1.Address, filenameSigned, chainFlag, sigOnlyFlag, "--overwrite", signModeAminoFlag) + require.NoError(err) checkSignatures(require, txCfg, res.Bytes(), valInfo.GetPubKey()) /**** test flagAmino ****/ - res, err = authtest.TxSignExec(val1.ClientCtx, val1.Address, filenameSigned, chainFlag, + res, err = TxSignExec(val1.ClientCtx, val1.Address, filenameSigned, chainFlag, "--amino=true", signModeAminoFlag) require.NoError(err) - var txAmino authrest.BroadcastReq + var txAmino authcli.BroadcastReq err = val1.ClientCtx.LegacyAmino.UnmarshalJSON(res.Bytes(), &txAmino) require.NoError(err) require.Len(txAmino.Tx.Signatures, 2) @@ -254,37 +252,14 @@ func (s *IntegrationTestSuite) TestCLIQueryTxCmdByHash() { sendTokens := sdk.NewInt64Coin(s.cfg.BondDenom, 10) - // Send coins, try both with legacy Msg and with Msg service. - // Legacy Msg. - legacyMsgOut, err := bankcli.MsgSendExec( - val.ClientCtx, - val.Address, - account2.GetAddress(), - sdk.NewCoins(sendTokens), - fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), - fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), - fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), - fmt.Sprintf("--gas=%d", flags.DefaultGasLimit), - ) - s.Require().NoError(err) - var legacyMsgTxRes sdk.TxResponse - s.Require().NoError(val.ClientCtx.JSONMarshaler.UnmarshalJSON(legacyMsgOut.Bytes(), &legacyMsgTxRes)) - - // Service Msg. - out, err := bankcli.ServiceMsgSendExec( - val.ClientCtx, - val.Address, - account2.GetAddress(), + // Send coins. + out, err := s.createBankMsg( + val, account2.GetAddress(), sdk.NewCoins(sendTokens), - fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), - fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), - fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), - fmt.Sprintf("--gas=%d", flags.DefaultGasLimit), ) s.Require().NoError(err) var txRes sdk.TxResponse - s.Require().NoError(val.ClientCtx.JSONMarshaler.UnmarshalJSON(out.Bytes(), &txRes)) - + s.Require().NoError(val.ClientCtx.Codec.UnmarshalJSON(out.Bytes(), &txRes)) s.Require().NoError(s.network.WaitForNextBlock()) testCases := []struct { @@ -309,16 +284,10 @@ func (s *IntegrationTestSuite) TestCLIQueryTxCmdByHash() { true, "", }, { - "happy case (legacy Msg)", - []string{legacyMsgTxRes.TxHash, fmt.Sprintf("--%s=json", ostcli.OutputFlag)}, - false, - "", - }, - { - "happy case (service Msg)", + "happy case", []string{txRes.TxHash, fmt.Sprintf("--%s=json", ostcli.OutputFlag)}, false, - "/lbm.bank.v1.Msg/Send", + sdk.MsgTypeURL(&banktypes.MsgSend{}), }, } @@ -335,7 +304,7 @@ func (s *IntegrationTestSuite) TestCLIQueryTxCmdByHash() { s.Require().NotEqual("internal", err.Error()) } else { var result sdk.TxResponse - s.Require().NoError(val.ClientCtx.JSONMarshaler.UnmarshalJSON(out.Bytes(), &result)) + s.Require().NoError(val.ClientCtx.Codec.UnmarshalJSON(out.Bytes(), &result)) s.Require().NotNil(result.Height) s.Require().Contains(result.RawLog, tc.rawLogContains) } @@ -358,13 +327,13 @@ func (s *IntegrationTestSuite) TestCLIQueryTxCmdByEvents() { ) s.Require().NoError(err) var txRes sdk.TxResponse - s.Require().NoError(val.ClientCtx.JSONMarshaler.UnmarshalJSON(out.Bytes(), &txRes)) + s.Require().NoError(val.ClientCtx.Codec.UnmarshalJSON(out.Bytes(), &txRes)) s.Require().NoError(s.network.WaitForNextBlock()) // Query the tx by hash to get the inner tx. out, err = clitestutil.ExecTestCLICmd(val.ClientCtx, authcli.QueryTxCmd(), []string{txRes.TxHash, fmt.Sprintf("--%s=json", ostcli.OutputFlag)}) s.Require().NoError(err) - s.Require().NoError(val.ClientCtx.JSONMarshaler.UnmarshalJSON(out.Bytes(), &txRes)) + s.Require().NoError(val.ClientCtx.Codec.UnmarshalJSON(out.Bytes(), &txRes)) protoTx := txRes.GetTx().(*tx.Tx) testCases := []struct { @@ -450,31 +419,93 @@ func (s *IntegrationTestSuite) TestCLIQueryTxCmdByEvents() { s.Require().Contains(err.Error(), tc.expectErrStr) } else { var result sdk.TxResponse - s.Require().NoError(val.ClientCtx.JSONMarshaler.UnmarshalJSON(out.Bytes(), &result)) + s.Require().NoError(val.ClientCtx.Codec.UnmarshalJSON(out.Bytes(), &result)) s.Require().NotNil(result.Height) } }) } } +func (s *IntegrationTestSuite) TestCLIQueryTxsCmdByEvents() { + val := s.network.Validators[0] + + account2, err := val.ClientCtx.Keyring.Key("newAccount2") + s.Require().NoError(err) + + sendTokens := sdk.NewInt64Coin(s.cfg.BondDenom, 10) + + // Send coins. + out, err := s.createBankMsg( + val, account2.GetAddress(), + sdk.NewCoins(sendTokens), + ) + s.Require().NoError(err) + var txRes sdk.TxResponse + s.Require().NoError(val.ClientCtx.Codec.UnmarshalJSON(out.Bytes(), &txRes)) + s.Require().NoError(s.network.WaitForNextBlock()) + + // Query the tx by hash to get the inner tx. + out, err = clitestutil.ExecTestCLICmd(val.ClientCtx, authcli.QueryTxCmd(), []string{txRes.TxHash, fmt.Sprintf("--%s=json", ostcli.OutputFlag)}) + s.Require().NoError(err) + s.Require().NoError(val.ClientCtx.Codec.UnmarshalJSON(out.Bytes(), &txRes)) + + testCases := []struct { + name string + args []string + expectEmpty bool + }{ + { + "fee event happy case", + []string{ + fmt.Sprintf("--events=tx.fee=%s", + sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), + fmt.Sprintf("--%s=json", ostcli.OutputFlag), + }, + false, + }, + { + "no matching fee event", + []string{ + fmt.Sprintf("--events=tx.fee=%s", + sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(0))).String()), + fmt.Sprintf("--%s=json", ostcli.OutputFlag), + }, + true, + }, + } + + for _, tc := range testCases { + tc := tc + s.Run(tc.name, func() { + cmd := authcli.QueryTxsByEventsCmd() + clientCtx := val.ClientCtx + + out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, tc.args) + s.Require().NoError(err) + + var result sdk.SearchTxsResult + s.Require().NoError(val.ClientCtx.Codec.UnmarshalJSON(out.Bytes(), &result)) + + if tc.expectEmpty { + s.Require().Equal(0, len(result.Txs)) + } else { + s.Require().NotEqual(0, len(result.Txs)) + s.Require().NotNil(result.Txs[0]) + } + }) + } +} + func (s *IntegrationTestSuite) TestCLISendGenerateSignAndBroadcast() { val1 := s.network.Validators[0] account, err := val1.ClientCtx.Keyring.Key("newAccount") s.Require().NoError(err) - sendTokens := sdk.NewCoin(s.cfg.BondDenom, sdk.TokensFromConsensusPower(10)) + sendTokens := sdk.NewCoin(s.cfg.BondDenom, sdk.TokensFromConsensusPower(10, sdk.DefaultPowerReduction)) - normalGeneratedTx, err := bankcli.MsgSendExec( - val1.ClientCtx, - val1.Address, - account.GetAddress(), - sdk.NewCoins(sendTokens), - fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), - fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), - fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), - fmt.Sprintf("--%s=true", flags.FlagGenerateOnly), - ) + normalGeneratedTx, err := s.createBankMsg(val1, account.GetAddress(), + sdk.NewCoins(sendTokens), fmt.Sprintf("--%s=true", flags.FlagGenerateOnly)) s.Require().NoError(err) txCfg := val1.ClientCtx.TxConfig @@ -490,15 +521,8 @@ func (s *IntegrationTestSuite) TestCLISendGenerateSignAndBroadcast() { s.Require().Equal(0, len(sigs)) // Test generate sendTx with --gas=$amount - limitedGasGeneratedTx, err := bankcli.MsgSendExec( - val1.ClientCtx, - val1.Address, - account.GetAddress(), - sdk.NewCoins(sendTokens), - fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), - fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), - fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), - fmt.Sprintf("--gas=%d", 100), + limitedGasGeneratedTx, err := s.createBankMsg(val1, account.GetAddress(), + sdk.NewCoins(sendTokens), fmt.Sprintf("--gas=%d", 100), fmt.Sprintf("--%s=true", flags.FlagGenerateOnly), ) s.Require().NoError(err) @@ -517,22 +541,14 @@ func (s *IntegrationTestSuite) TestCLISendGenerateSignAndBroadcast() { s.Require().NoError(err) var balRes banktypes.QueryAllBalancesResponse - err = val1.ClientCtx.JSONMarshaler.UnmarshalJSON(resp.Bytes(), &balRes) + err = val1.ClientCtx.Codec.UnmarshalJSON(resp.Bytes(), &balRes) s.Require().NoError(err) startTokens := balRes.Balances.AmountOf(s.cfg.BondDenom) // Test generate sendTx, estimate gas - finalGeneratedTx, err := bankcli.MsgSendExec( - val1.ClientCtx, - val1.Address, - account.GetAddress(), - sdk.NewCoins(sendTokens), - fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), - fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), - fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), - fmt.Sprintf("--gas=%d", flags.DefaultGasLimit), - fmt.Sprintf("--%s=true", flags.FlagGenerateOnly), - ) + finalGeneratedTx, err := s.createBankMsg(val1, account.GetAddress(), + sdk.NewCoins(sendTokens), fmt.Sprintf("--gas=%d", flags.DefaultGasLimit), + fmt.Sprintf("--%s=true", flags.FlagGenerateOnly)) s.Require().NoError(err) finalStdTx, err := txCfg.TxJSONDecoder()(finalGeneratedTx.Bytes()) @@ -546,23 +562,23 @@ func (s *IntegrationTestSuite) TestCLISendGenerateSignAndBroadcast() { unsignedTxFile := testutil.WriteToNewTempFile(s.T(), finalGeneratedTx.String()) // Test validate-signatures - res, err := authtest.TxValidateSignaturesExec(val1.ClientCtx, unsignedTxFile.Name()) + res, err := TxValidateSignaturesExec(val1.ClientCtx, unsignedTxFile.Name()) s.Require().EqualError(err, "signatures validation failed") s.Require().True(strings.Contains(res.String(), fmt.Sprintf("Signers:\n 0: %v\n\nSignatures:\n\n", val1.Address.String()))) // Test sign // Does not work in offline mode - res, err = authtest.TxSignExec(val1.ClientCtx, val1.Address, unsignedTxFile.Name(), "--offline") + _, err = TxSignExec(val1.ClientCtx, val1.Address, unsignedTxFile.Name(), "--offline") s.Require().EqualError(err, "required flag(s) \"account-number\", \"sequence\" not set") // But works offline if we set account number and sequence val1.ClientCtx.HomeDir = strings.Replace(val1.ClientCtx.HomeDir, "simd", "simcli", 1) - res, err = authtest.TxSignExec(val1.ClientCtx, val1.Address, unsignedTxFile.Name(), "--offline", "--account-number", "1", "--sequence", "1") + _, err = TxSignExec(val1.ClientCtx, val1.Address, unsignedTxFile.Name(), "--offline", "--account-number", "1", "--sequence", "1") s.Require().NoError(err) // Sign transaction - signedTx, err := authtest.TxSignExec(val1.ClientCtx, val1.Address, unsignedTxFile.Name()) + signedTx, err := TxSignExec(val1.ClientCtx, val1.Address, unsignedTxFile.Name()) s.Require().NoError(err) signedFinalTx, err := txCfg.TxJSONDecoder()(signedTx.Bytes()) s.Require().NoError(err) @@ -577,8 +593,8 @@ func (s *IntegrationTestSuite) TestCLISendGenerateSignAndBroadcast() { // Write the output to disk signedTxFile := testutil.WriteToNewTempFile(s.T(), signedTx.String()) - // Validate Signature - res, err = authtest.TxValidateSignaturesExec(val1.ClientCtx, signedTxFile.Name()) + // validate Signature + res, err = TxValidateSignaturesExec(val1.ClientCtx, signedTxFile.Name()) s.Require().NoError(err) s.Require().True(strings.Contains(res.String(), "[OK]")) @@ -586,21 +602,21 @@ func (s *IntegrationTestSuite) TestCLISendGenerateSignAndBroadcast() { resp, err = bankcli.QueryBalancesExec(val1.ClientCtx, val1.Address) s.Require().NoError(err) - err = val1.ClientCtx.JSONMarshaler.UnmarshalJSON(resp.Bytes(), &balRes) + err = val1.ClientCtx.Codec.UnmarshalJSON(resp.Bytes(), &balRes) s.Require().NoError(err) s.Require().Equal(startTokens, balRes.Balances.AmountOf(s.cfg.BondDenom)) // Test broadcast // Does not work in offline mode - res, err = authtest.TxBroadcastExec(val1.ClientCtx, signedTxFile.Name(), "--offline") + _, err = TxBroadcastExec(val1.ClientCtx, signedTxFile.Name(), "--offline") s.Require().EqualError(err, "cannot broadcast tx during offline mode") s.Require().NoError(s.network.WaitForNextBlock()) // Broadcast correct transaction. val1.ClientCtx.BroadcastMode = flags.BroadcastBlock - res, err = authtest.TxBroadcastExec(val1.ClientCtx, signedTxFile.Name()) + _, err = TxBroadcastExec(val1.ClientCtx, signedTxFile.Name()) s.Require().NoError(err) s.Require().NoError(s.network.WaitForNextBlock()) @@ -609,7 +625,7 @@ func (s *IntegrationTestSuite) TestCLISendGenerateSignAndBroadcast() { resp, err = bankcli.QueryBalancesExec(val1.ClientCtx, account.GetAddress()) s.Require().NoError(err) - err = val1.ClientCtx.JSONMarshaler.UnmarshalJSON(resp.Bytes(), &balRes) + err = val1.ClientCtx.Codec.UnmarshalJSON(resp.Bytes(), &balRes) s.Require().NoError(err) s.Require().Equal(sendTokens.Amount, balRes.Balances.AmountOf(s.cfg.BondDenom)) @@ -617,14 +633,14 @@ func (s *IntegrationTestSuite) TestCLISendGenerateSignAndBroadcast() { resp, err = bankcli.QueryBalancesExec(val1.ClientCtx, val1.Address) s.Require().NoError(err) - err = val1.ClientCtx.JSONMarshaler.UnmarshalJSON(resp.Bytes(), &balRes) + err = val1.ClientCtx.Codec.UnmarshalJSON(resp.Bytes(), &balRes) s.Require().NoError(err) } func (s *IntegrationTestSuite) TestCLIMultisignInsufficientCosigners() { - val1 := *s.network.Validators[0] + val1 := s.network.Validators[0] - // Generate 2 accounts and a multisig. + // Fetch account and a multisig info account1, err := val1.ClientCtx.Keyring.Key("newAccount1") s.Require().NoError(err) @@ -632,17 +648,12 @@ func (s *IntegrationTestSuite) TestCLIMultisignInsufficientCosigners() { s.Require().NoError(err) // Send coins from validator to multisig. - _, err = bankcli.MsgSendExec( - val1.ClientCtx, - val1.Address, + _, err = s.createBankMsg( + val1, multisigInfo.GetAddress(), sdk.NewCoins( sdk.NewInt64Coin(s.cfg.BondDenom, 10), ), - fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), - fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), - fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), - fmt.Sprintf("--gas=%d", flags.DefaultGasLimit), ) s.Require().NoError(err) @@ -668,46 +679,42 @@ func (s *IntegrationTestSuite) TestCLIMultisignInsufficientCosigners() { // Multisign, sign with one signature val1.ClientCtx.HomeDir = strings.Replace(val1.ClientCtx.HomeDir, "simd", "simcli", 1) - account1Signature, err := authtest.TxSignExec(val1.ClientCtx, account1.GetAddress(), multiGeneratedTxFile.Name(), "--multisig", multisigInfo.GetAddress().String()) + account1Signature, err := TxSignExec(val1.ClientCtx, account1.GetAddress(), multiGeneratedTxFile.Name(), "--multisig", multisigInfo.GetAddress().String()) s.Require().NoError(err) sign1File := testutil.WriteToNewTempFile(s.T(), account1Signature.String()) - multiSigWith1Signature, err := authtest.TxMultiSignExec(val1.ClientCtx, multisigInfo.GetName(), multiGeneratedTxFile.Name(), sign1File.Name()) + multiSigWith1Signature, err := TxMultiSignExec(val1.ClientCtx, multisigInfo.GetName(), multiGeneratedTxFile.Name(), sign1File.Name()) s.Require().NoError(err) // Save tx to file multiSigWith1SignatureFile := testutil.WriteToNewTempFile(s.T(), multiSigWith1Signature.String()) - _, err = authtest.TxValidateSignaturesExec(val1.ClientCtx, multiSigWith1SignatureFile.Name()) + _, err = TxValidateSignaturesExec(val1.ClientCtx, multiSigWith1SignatureFile.Name()) s.Require().Error(err) } func (s *IntegrationTestSuite) TestCLIEncode() { val1 := s.network.Validators[0] - sendTokens := sdk.NewCoin(s.cfg.BondDenom, sdk.TokensFromConsensusPower(10)) + sendTokens := sdk.NewCoin(s.cfg.BondDenom, sdk.TokensFromConsensusPower(10, sdk.DefaultPowerReduction)) - normalGeneratedTx, err := bankcli.MsgSendExec( - val1.ClientCtx, - val1.Address, - val1.Address, + normalGeneratedTx, err := s.createBankMsg( + val1, val1.Address, sdk.NewCoins(sendTokens), - fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), - fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), - fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), - fmt.Sprintf("--%s=true", flags.FlagGenerateOnly), "--memo", "deadbeef", + fmt.Sprintf("--%s=true", flags.FlagGenerateOnly), + fmt.Sprintf("--%s=deadbeef", flags.FlagNote), ) s.Require().NoError(err) savedTxFile := testutil.WriteToNewTempFile(s.T(), normalGeneratedTx.String()) // Encode - encodeExec, err := authtest.TxEncodeExec(val1.ClientCtx, savedTxFile.Name()) + encodeExec, err := TxEncodeExec(val1.ClientCtx, savedTxFile.Name()) s.Require().NoError(err) trimmedBase64 := strings.Trim(encodeExec.String(), "\"\n") // Check that the transaction decodes as expected - decodedTx, err := authtest.TxDecodeExec(val1.ClientCtx, trimmedBase64) + decodedTx, err := TxDecodeExec(val1.ClientCtx, trimmedBase64) s.Require().NoError(err) txCfg := val1.ClientCtx.TxConfig @@ -719,7 +726,7 @@ func (s *IntegrationTestSuite) TestCLIEncode() { } func (s *IntegrationTestSuite) TestCLIMultisignSortSignatures() { - val1 := *s.network.Validators[0] + val1 := s.network.Validators[0] // Generate 2 accounts and a multisig. account1, err := val1.ClientCtx.Keyring.Key("newAccount1") @@ -735,21 +742,16 @@ func (s *IntegrationTestSuite) TestCLIMultisignSortSignatures() { s.Require().NoError(err) var balRes banktypes.QueryAllBalancesResponse - err = val1.ClientCtx.JSONMarshaler.UnmarshalJSON(resp.Bytes(), &balRes) + err = val1.ClientCtx.Codec.UnmarshalJSON(resp.Bytes(), &balRes) s.Require().NoError(err) intialCoins := balRes.Balances // Send coins from validator to multisig. sendTokens := sdk.NewInt64Coin(s.cfg.BondDenom, 10) - _, err = bankcli.MsgSendExec( - val1.ClientCtx, - val1.Address, + _, err = s.createBankMsg( + val1, multisigInfo.GetAddress(), sdk.NewCoins(sendTokens), - fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), - fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), - fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), - fmt.Sprintf("--gas=%d", flags.DefaultGasLimit), ) s.Require().NoError(err) @@ -758,7 +760,7 @@ func (s *IntegrationTestSuite) TestCLIMultisignSortSignatures() { resp, err = bankcli.QueryBalancesExec(val1.ClientCtx, multisigInfo.GetAddress()) s.Require().NoError(err) - err = val1.ClientCtx.JSONMarshaler.UnmarshalJSON(resp.Bytes(), &balRes) + err = val1.ClientCtx.Codec.UnmarshalJSON(resp.Bytes(), &balRes) s.Require().NoError(err) diff, _ := balRes.Balances.SafeSub(intialCoins) s.Require().Equal(sendTokens.Amount, diff.AmountOf(s.cfg.BondDenom)) @@ -783,35 +785,35 @@ func (s *IntegrationTestSuite) TestCLIMultisignSortSignatures() { // Sign with account1 val1.ClientCtx.HomeDir = strings.Replace(val1.ClientCtx.HomeDir, "simd", "simcli", 1) - account1Signature, err := authtest.TxSignExec(val1.ClientCtx, account1.GetAddress(), multiGeneratedTxFile.Name(), "--multisig", multisigInfo.GetAddress().String()) + account1Signature, err := TxSignExec(val1.ClientCtx, account1.GetAddress(), multiGeneratedTxFile.Name(), "--multisig", multisigInfo.GetAddress().String()) s.Require().NoError(err) sign1File := testutil.WriteToNewTempFile(s.T(), account1Signature.String()) // Sign with account1 - account2Signature, err := authtest.TxSignExec(val1.ClientCtx, account2.GetAddress(), multiGeneratedTxFile.Name(), "--multisig", multisigInfo.GetAddress().String()) + account2Signature, err := TxSignExec(val1.ClientCtx, account2.GetAddress(), multiGeneratedTxFile.Name(), "--multisig", multisigInfo.GetAddress().String()) s.Require().NoError(err) sign2File := testutil.WriteToNewTempFile(s.T(), account2Signature.String()) - multiSigWith2Signatures, err := authtest.TxMultiSignExec(val1.ClientCtx, multisigInfo.GetName(), multiGeneratedTxFile.Name(), sign1File.Name(), sign2File.Name()) + multiSigWith2Signatures, err := TxMultiSignExec(val1.ClientCtx, multisigInfo.GetName(), multiGeneratedTxFile.Name(), sign1File.Name(), sign2File.Name()) s.Require().NoError(err) // Write the output to disk signedTxFile := testutil.WriteToNewTempFile(s.T(), multiSigWith2Signatures.String()) - _, err = authtest.TxValidateSignaturesExec(val1.ClientCtx, signedTxFile.Name()) + _, err = TxValidateSignaturesExec(val1.ClientCtx, signedTxFile.Name()) s.Require().NoError(err) val1.ClientCtx.BroadcastMode = flags.BroadcastBlock - _, err = authtest.TxBroadcastExec(val1.ClientCtx, signedTxFile.Name()) + _, err = TxBroadcastExec(val1.ClientCtx, signedTxFile.Name()) s.Require().NoError(err) s.Require().NoError(s.network.WaitForNextBlock()) } func (s *IntegrationTestSuite) TestCLIMultisign() { - val1 := *s.network.Validators[0] + val1 := s.network.Validators[0] // Generate 2 accounts and a multisig. account1, err := val1.ClientCtx.Keyring.Key("newAccount1") @@ -825,24 +827,18 @@ func (s *IntegrationTestSuite) TestCLIMultisign() { // Send coins from validator to multisig. sendTokens := sdk.NewInt64Coin(s.cfg.BondDenom, 10) - _, err = bankcli.MsgSendExec( - val1.ClientCtx, - val1.Address, - multisigInfo.GetAddress(), + _, err = s.createBankMsg( + val1, multisigInfo.GetAddress(), sdk.NewCoins(sendTokens), - fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), - fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), - fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), - fmt.Sprintf("--gas=%d", flags.DefaultGasLimit), ) - + s.Require().NoError(err) s.Require().NoError(s.network.WaitForNextBlock()) resp, err := bankcli.QueryBalancesExec(val1.ClientCtx, multisigInfo.GetAddress()) s.Require().NoError(err) var balRes banktypes.QueryAllBalancesResponse - err = val1.ClientCtx.JSONMarshaler.UnmarshalJSON(resp.Bytes(), &balRes) + err = val1.ClientCtx.Codec.UnmarshalJSON(resp.Bytes(), &balRes) s.Require().NoError(err) s.Require().Equal(sendTokens.Amount, balRes.Balances.AmountOf(s.cfg.BondDenom)) @@ -866,33 +862,33 @@ func (s *IntegrationTestSuite) TestCLIMultisign() { // Sign with account1 val1.ClientCtx.HomeDir = strings.Replace(val1.ClientCtx.HomeDir, "simd", "simcli", 1) - account1Signature, err := authtest.TxSignExec(val1.ClientCtx, account1.GetAddress(), multiGeneratedTxFile.Name(), "--multisig", multisigInfo.GetAddress().String()) + account1Signature, err := TxSignExec(val1.ClientCtx, account1.GetAddress(), multiGeneratedTxFile.Name(), "--multisig", multisigInfo.GetAddress().String()) s.Require().NoError(err) sign1File := testutil.WriteToNewTempFile(s.T(), account1Signature.String()) // Sign with account2 - account2Signature, err := authtest.TxSignExec(val1.ClientCtx, account2.GetAddress(), multiGeneratedTxFile.Name(), "--multisig", multisigInfo.GetAddress().String()) + account2Signature, err := TxSignExec(val1.ClientCtx, account2.GetAddress(), multiGeneratedTxFile.Name(), "--multisig", multisigInfo.GetAddress().String()) s.Require().NoError(err) sign2File := testutil.WriteToNewTempFile(s.T(), account2Signature.String()) // Does not work in offline mode. - _, err = authtest.TxMultiSignExec(val1.ClientCtx, multisigInfo.GetName(), multiGeneratedTxFile.Name(), "--offline", sign1File.Name(), sign2File.Name()) - s.Require().EqualError(err, "couldn't verify signature: unable to verify single signer signature") + _, err = TxMultiSignExec(val1.ClientCtx, multisigInfo.GetName(), multiGeneratedTxFile.Name(), "--offline", sign1File.Name(), sign2File.Name()) + s.Require().EqualError(err, fmt.Sprintf("couldn't verify signature for address %s", account1.GetAddress())) val1.ClientCtx.Offline = false - multiSigWith2Signatures, err := authtest.TxMultiSignExec(val1.ClientCtx, multisigInfo.GetName(), multiGeneratedTxFile.Name(), sign1File.Name(), sign2File.Name()) + multiSigWith2Signatures, err := TxMultiSignExec(val1.ClientCtx, multisigInfo.GetName(), multiGeneratedTxFile.Name(), sign1File.Name(), sign2File.Name()) s.Require().NoError(err) // Write the output to disk signedTxFile := testutil.WriteToNewTempFile(s.T(), multiSigWith2Signatures.String()) - _, err = authtest.TxValidateSignaturesExec(val1.ClientCtx, signedTxFile.Name()) + _, err = TxValidateSignaturesExec(val1.ClientCtx, signedTxFile.Name()) s.Require().NoError(err) val1.ClientCtx.BroadcastMode = flags.BroadcastBlock - _, err = authtest.TxBroadcastExec(val1.ClientCtx, signedTxFile.Name()) + _, err = TxBroadcastExec(val1.ClientCtx, signedTxFile.Name()) s.Require().NoError(err) s.Require().NoError(s.network.WaitForNextBlock()) @@ -907,18 +903,14 @@ func (s *IntegrationTestSuite) TestSignBatchMultisig() { account2, err := val.ClientCtx.Keyring.Key("newAccount2") s.Require().NoError(err) multisigInfo, err := val.ClientCtx.Keyring.Key("multi") + s.Require().NoError(err) // Send coins from validator to multisig. sendTokens := sdk.NewInt64Coin(s.cfg.BondDenom, 10) - _, err = bankcli.MsgSendExec( - val.ClientCtx, - val.Address, + _, err = s.createBankMsg( + val, multisigInfo.GetAddress(), sdk.NewCoins(sendTokens), - fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), - fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), - fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), - fmt.Sprintf("--gas=%d", flags.DefaultGasLimit), ) s.Require().NoError(err) s.Require().NoError(s.network.WaitForNextBlock()) @@ -942,21 +934,29 @@ func (s *IntegrationTestSuite) TestSignBatchMultisig() { val.ClientCtx.HomeDir = strings.Replace(val.ClientCtx.HomeDir, "simd", "simcli", 1) // sign-batch file - res, err := authtest.TxSignBatchExec(val.ClientCtx, account1.GetAddress(), filename.Name(), fmt.Sprintf("--%s=%s", flags.FlagChainID, val.ClientCtx.ChainID), "--multisig", multisigInfo.GetAddress().String()) + res, err := TxSignBatchExec(val.ClientCtx, account1.GetAddress(), filename.Name(), fmt.Sprintf("--%s=%s", flags.FlagChainID, val.ClientCtx.ChainID), "--multisig", multisigInfo.GetAddress().String()) s.Require().NoError(err) s.Require().Equal(1, len(strings.Split(strings.Trim(res.String(), "\n"), "\n"))) // write sigs to file file1 := testutil.WriteToNewTempFile(s.T(), res.String()) // sign-batch file with account2 - res, err = authtest.TxSignBatchExec(val.ClientCtx, account2.GetAddress(), filename.Name(), fmt.Sprintf("--%s=%s", flags.FlagChainID, val.ClientCtx.ChainID), "--multisig", multisigInfo.GetAddress().String()) + res, err = TxSignBatchExec(val.ClientCtx, account2.GetAddress(), filename.Name(), fmt.Sprintf("--%s=%s", flags.FlagChainID, val.ClientCtx.ChainID), "--multisig", multisigInfo.GetAddress().String()) s.Require().NoError(err) s.Require().Equal(1, len(strings.Split(strings.Trim(res.String(), "\n"), "\n"))) - // write sigs to file2 file2 := testutil.WriteToNewTempFile(s.T(), res.String()) - res, err = authtest.TxMultiSignExec(val.ClientCtx, multisigInfo.GetName(), filename.Name(), file1.Name(), file2.Name()) + + // sign-batch file with multisig key name + res, err = TxSignBatchExec(val.ClientCtx, account1.GetAddress(), filename.Name(), fmt.Sprintf("--%s=%s", flags.FlagChainID, val.ClientCtx.ChainID), "--multisig", multisigInfo.GetName()) + s.Require().NoError(err) + s.Require().Equal(1, len(strings.Split(strings.Trim(res.String(), "\n"), "\n"))) + // write sigs to file3 + file3 := testutil.WriteToNewTempFile(s.T(), res.String()) + + _, err = TxMultiSignExec(val.ClientCtx, multisigInfo.GetName(), filename.Name(), file1.Name(), file2.Name(), file3.Name()) s.Require().NoError(err) + } func (s *IntegrationTestSuite) TestMultisignBatch() { @@ -968,18 +968,14 @@ func (s *IntegrationTestSuite) TestMultisignBatch() { account2, err := val.ClientCtx.Keyring.Key("newAccount2") s.Require().NoError(err) multisigInfo, err := val.ClientCtx.Keyring.Key("multi") + s.Require().NoError(err) // Send coins from validator to multisig. sendTokens := sdk.NewInt64Coin(s.cfg.BondDenom, 1000) - _, err = bankcli.MsgSendExec( - val.ClientCtx, - val.Address, + _, err = s.createBankMsg( + val, multisigInfo.GetAddress(), sdk.NewCoins(sendTokens), - fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), - fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), - fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), - fmt.Sprintf("--gas=%d", flags.DefaultGasLimit), ) s.Require().NoError(err) s.Require().NoError(s.network.WaitForNextBlock()) @@ -1002,26 +998,34 @@ func (s *IntegrationTestSuite) TestMultisignBatch() { filename := testutil.WriteToNewTempFile(s.T(), strings.Repeat(generatedStd.String(), 3)) val.ClientCtx.HomeDir = strings.Replace(val.ClientCtx.HomeDir, "simd", "simcli", 1) - queryResJSON, err := authtest.QueryAccountExec(val.ClientCtx, multisigInfo.GetAddress()) + queryResJSON, err := QueryAccountExec(val.ClientCtx, multisigInfo.GetAddress()) s.Require().NoError(err) var account authtypes.AccountI - s.Require().NoError(val.ClientCtx.JSONMarshaler.UnmarshalInterfaceJSON(queryResJSON.Bytes(), &account)) + s.Require().NoError(val.ClientCtx.Codec.UnmarshalInterfaceJSON(queryResJSON.Bytes(), &account)) // sign-batch file - res, err := authtest.TxSignBatchExec(val.ClientCtx, account1.GetAddress(), filename.Name(), fmt.Sprintf("--%s=%s", flags.FlagChainID, val.ClientCtx.ChainID), "--multisig", multisigInfo.GetAddress().String(), fmt.Sprintf("--%s", flags.FlagOffline), fmt.Sprintf("--%s=%s", flags.FlagAccountNumber, fmt.Sprint(account.GetAccountNumber())), fmt.Sprintf("--%s=%s", flags.FlagSequence, fmt.Sprint(account.GetSequence()))) + res, err := TxSignBatchExec(val.ClientCtx, account1.GetAddress(), filename.Name(), fmt.Sprintf("--%s=%s", flags.FlagChainID, val.ClientCtx.ChainID), "--multisig", multisigInfo.GetAddress().String(), fmt.Sprintf("--%s", flags.FlagOffline), fmt.Sprintf("--%s=%s", flags.FlagAccountNumber, fmt.Sprint(account.GetAccountNumber())), fmt.Sprintf("--%s=%s", flags.FlagSequence, fmt.Sprint(account.GetSequence()))) s.Require().NoError(err) s.Require().Equal(3, len(strings.Split(strings.Trim(res.String(), "\n"), "\n"))) // write sigs to file file1 := testutil.WriteToNewTempFile(s.T(), res.String()) // sign-batch file with account2 - res, err = authtest.TxSignBatchExec(val.ClientCtx, account2.GetAddress(), filename.Name(), fmt.Sprintf("--%s=%s", flags.FlagChainID, val.ClientCtx.ChainID), "--multisig", multisigInfo.GetAddress().String(), fmt.Sprintf("--%s", flags.FlagOffline), fmt.Sprintf("--%s=%s", flags.FlagAccountNumber, fmt.Sprint(account.GetAccountNumber())), fmt.Sprintf("--%s=%s", flags.FlagSequence, fmt.Sprint(account.GetSequence()))) + res, err = TxSignBatchExec(val.ClientCtx, account2.GetAddress(), filename.Name(), fmt.Sprintf("--%s=%s", flags.FlagChainID, val.ClientCtx.ChainID), "--multisig", multisigInfo.GetAddress().String(), fmt.Sprintf("--%s", flags.FlagOffline), fmt.Sprintf("--%s=%s", flags.FlagAccountNumber, fmt.Sprint(account.GetAccountNumber())), fmt.Sprintf("--%s=%s", flags.FlagSequence, fmt.Sprint(account.GetSequence()))) s.Require().NoError(err) s.Require().Equal(3, len(strings.Split(strings.Trim(res.String(), "\n"), "\n"))) // multisign the file file2 := testutil.WriteToNewTempFile(s.T(), res.String()) - res, err = authtest.TxMultiSignBatchExec(val.ClientCtx, filename.Name(), multisigInfo.GetName(), file1.Name(), file2.Name()) + + // sign-batch file with multisig key name + res, err = TxSignBatchExec(val.ClientCtx, account1.GetAddress(), filename.Name(), fmt.Sprintf("--%s=%s", flags.FlagChainID, val.ClientCtx.ChainID), "--multisig", multisigInfo.GetName(), fmt.Sprintf("--%s", flags.FlagOffline), fmt.Sprintf("--%s=%s", flags.FlagAccountNumber, fmt.Sprint(account.GetAccountNumber())), fmt.Sprintf("--%s=%s", flags.FlagSequence, fmt.Sprint(account.GetSequence()))) + s.Require().NoError(err) + s.Require().Equal(3, len(strings.Split(strings.Trim(res.String(), "\n"), "\n"))) + // write sigs to file + file3 := testutil.WriteToNewTempFile(s.T(), res.String()) + + res, err = TxMultiSignBatchExec(val.ClientCtx, filename.Name(), multisigInfo.GetName(), file1.Name(), file2.Name(), file3.Name()) s.Require().NoError(err) signedTxs := strings.Split(strings.Trim(res.String(), "\n"), "\n") @@ -1029,8 +1033,7 @@ func (s *IntegrationTestSuite) TestMultisignBatch() { for _, signedTx := range signedTxs { signedTxFile := testutil.WriteToNewTempFile(s.T(), signedTx) val.ClientCtx.BroadcastMode = flags.BroadcastBlock - res, err = authtest.TxBroadcastExec(val.ClientCtx, signedTxFile.Name()) - s.T().Log(res) + _, err = TxBroadcastExec(val.ClientCtx, signedTxFile.Name()) s.Require().NoError(err) s.Require().NoError(s.network.WaitForNextBlock()) } @@ -1062,20 +1065,34 @@ func (s *IntegrationTestSuite) TestGetAccountCmd() { s.Run(tc.name, func() { clientCtx := val.ClientCtx - out, err := authtest.QueryAccountExec(clientCtx, tc.address) + out, err := QueryAccountExec(clientCtx, tc.address) if tc.expectErr { s.Require().Error(err) s.Require().NotEqual("internal", err.Error()) } else { var acc authtypes.AccountI - s.Require().NoError(val.ClientCtx.JSONMarshaler.UnmarshalInterfaceJSON(out.Bytes(), &acc)) + s.Require().NoError(val.ClientCtx.Codec.UnmarshalInterfaceJSON(out.Bytes(), &acc)) s.Require().Equal(val.Address, acc.GetAddress()) } }) } } -func TestGetBroadcastCommand_OfflineFlag(t *testing.T) { +func (s *IntegrationTestSuite) TestGetAccountsCmd() { + val := s.network.Validators[0] + clientCtx := val.ClientCtx + + out, err := clitestutil.ExecTestCLICmd(clientCtx, authcli.GetAccountsCmd(), []string{ + fmt.Sprintf("--%s=json", ostcli.OutputFlag), + }) + s.Require().NoError(err) + + var res authtypes.QueryAccountsResponse + s.Require().NoError(val.ClientCtx.Codec.UnmarshalJSON(out.Bytes(), &res)) + s.Require().NotEmpty(res.Accounts) +} + +func TestGetBroadcastCommandOfflineFlag(t *testing.T) { clientCtx := client.Context{}.WithOffline(true) clientCtx = clientCtx.WithTxConfig(simapp.MakeTestEncodingConfig().TxConfig) @@ -1086,7 +1103,7 @@ func TestGetBroadcastCommand_OfflineFlag(t *testing.T) { require.EqualError(t, cmd.Execute(), "cannot broadcast tx during offline mode") } -func TestGetBroadcastCommand_WithoutOfflineFlag(t *testing.T) { +func TestGetBroadcastCommandWithoutOfflineFlag(t *testing.T) { clientCtx := client.Context{} txCfg := simapp.MakeTestEncodingConfig().TxConfig clientCtx = clientCtx.WithTxConfig(txCfg) @@ -1150,7 +1167,7 @@ func (s *IntegrationTestSuite) TestQueryParamsCmd() { s.Require().NotEqual("internal", err.Error()) } else { var authParams authtypes.Params - s.Require().NoError(val.ClientCtx.JSONMarshaler.UnmarshalJSON(out.Bytes(), &authParams)) + s.Require().NoError(val.ClientCtx.Codec.UnmarshalJSON(out.Bytes(), &authParams)) s.Require().NotNil(authParams.MaxMemoCharacters) } }) @@ -1190,32 +1207,32 @@ func (s *IntegrationTestSuite) TestTxWithoutPublicKey() { unsignedTxFile := testutil.WriteToNewTempFile(s.T(), string(txJSON)) // Sign the file with the unsignedTx. - signedTx, err := authtest.TxSignExec(val1.ClientCtx, val1.Address, unsignedTxFile.Name()) + signedTx, err := TxSignExec(val1.ClientCtx, val1.Address, unsignedTxFile.Name()) s.Require().NoError(err) // Remove the signerInfo's `public_key` field manually from the signedTx. // Note: this method is only used for test purposes! In general, one should // use txBuilder and TxEncoder/TxDecoder to manipulate txs. var tx tx.Tx - err = val1.ClientCtx.JSONMarshaler.UnmarshalJSON(signedTx.Bytes(), &tx) + err = val1.ClientCtx.Codec.UnmarshalJSON(signedTx.Bytes(), &tx) s.Require().NoError(err) tx.AuthInfo.SignerInfos[0].PublicKey = nil // Re-encode the tx again, to another file. - txJSON, err = val1.ClientCtx.JSONMarshaler.MarshalJSON(&tx) + txJSON, err = val1.ClientCtx.Codec.MarshalJSON(&tx) s.Require().NoError(err) signedTxFile := testutil.WriteToNewTempFile(s.T(), string(txJSON)) s.Require().True(strings.Contains(string(txJSON), "\"public_key\":null")) // Broadcast tx, test that it shouldn't panic. val1.ClientCtx.BroadcastMode = flags.BroadcastSync - out, err := authtest.TxBroadcastExec(val1.ClientCtx, signedTxFile.Name()) + out, err := TxBroadcastExec(val1.ClientCtx, signedTxFile.Name()) s.Require().NoError(err) var res sdk.TxResponse - s.Require().NoError(val1.ClientCtx.JSONMarshaler.UnmarshalJSON(out.Bytes(), &res)) + s.Require().NoError(val1.ClientCtx.Codec.UnmarshalJSON(out.Bytes(), &res)) s.Require().NotEqual(0, res.Code) } -func (s *IntegrationTestSuite) TestSignWithMultiSigners_AminoJSON() { +func (s *IntegrationTestSuite) TestSignWithMultiSignersAminoJSON() { // test case: // Create a transaction with 2 messages which has to be signed with 2 different keys // Sign and append the signatures using the CLI with Amino signing mode. @@ -1230,14 +1247,14 @@ func (s *IntegrationTestSuite) TestSignWithMultiSigners_AminoJSON() { // Creating a tx with 2 msgs from 2 signers: val0 and val1. // The validators need to sign with SIGN_MODE_LEGACY_AMINO_JSON, // because DIRECT doesn't support multi signers via the CLI. - // Since we we amino, we don't need to pre-populate signer_infos. + // Since we use amino, we don't need to pre-populate signer_infos. txBuilder := val0.ClientCtx.TxConfig.NewTxBuilder() txBuilder.SetMsgs( banktypes.NewMsgSend(val0.Address, addr1, sdk.NewCoins(val0Coin)), banktypes.NewMsgSend(val1.Address, addr1, sdk.NewCoins(val1Coin)), ) txBuilder.SetFeeAmount(sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10)))) - txBuilder.SetGasLimit(testdata.NewTestGasLimit()) + txBuilder.SetGasLimit(testdata.NewTestGasLimit()) // min required is 101892 require.Equal([]sdk.AccAddress{val0.Address, val1.Address}, txBuilder.GetTx().GetSigners()) // Write the unsigned tx into a file. @@ -1246,14 +1263,14 @@ func (s *IntegrationTestSuite) TestSignWithMultiSigners_AminoJSON() { unsignedTxFile := testutil.WriteToNewTempFile(s.T(), string(txJSON)) // Let val0 sign first the file with the unsignedTx. - signedByVal0, err := authtest.TxSignExec(val0.ClientCtx, val0.Address, unsignedTxFile.Name(), "--overwrite", "--sign-mode=amino-json") + signedByVal0, err := TxSignExec(val0.ClientCtx, val0.Address, unsignedTxFile.Name(), "--overwrite", "--sign-mode=amino-json") require.NoError(err) signedByVal0File := testutil.WriteToNewTempFile(s.T(), signedByVal0.String()) // Then let val1 sign the file with signedByVal0. val1AccNum, val1Seq, err := val0.ClientCtx.AccountRetriever.GetAccountNumberSequence(val0.ClientCtx, val1.Address) require.NoError(err) - signedTx, err := authtest.TxSignExec( + signedTx, err := TxSignExec( val1.ClientCtx, val1.Address, signedByVal0File.Name(), "--offline", fmt.Sprintf("--account-number=%d", val1AccNum), fmt.Sprintf("--sequence=%d", val1Seq), "--sign-mode=amino-json", ) @@ -1261,17 +1278,22 @@ func (s *IntegrationTestSuite) TestSignWithMultiSigners_AminoJSON() { signedTxFile := testutil.WriteToNewTempFile(s.T(), signedTx.String()) // Now let's try to send this tx. - res, err := authtest.TxBroadcastExec(val0.ClientCtx, signedTxFile.Name(), fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock)) + res, err := TxBroadcastExec( + val0.ClientCtx, + signedTxFile.Name(), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), + ) + require.NoError(err) var txRes sdk.TxResponse - require.NoError(val0.ClientCtx.JSONMarshaler.UnmarshalJSON(res.Bytes(), &txRes)) + require.NoError(val0.ClientCtx.Codec.UnmarshalJSON(res.Bytes(), &txRes)) require.Equal(uint32(0), txRes.Code) // Make sure the addr1's balance got funded. queryResJSON, err := bankcli.QueryBalancesExec(val0.ClientCtx, addr1) require.NoError(err) var queryRes banktypes.QueryAllBalancesResponse - err = val0.ClientCtx.JSONMarshaler.UnmarshalJSON(queryResJSON.Bytes(), &queryRes) + err = val0.ClientCtx.Codec.UnmarshalJSON(queryResJSON.Bytes(), &queryRes) require.NoError(err) require.Equal(sdk.NewCoins(val0Coin, val1Coin), queryRes.Balances) } @@ -1286,7 +1308,3 @@ func (s *IntegrationTestSuite) createBankMsg(val *network.Validator, toAddr sdk. flags = append(flags, extraFlags...) return bankcli.MsgSendExec(val.ClientCtx, val.Address, toAddr, amount, flags...) } - -func TestIntegrationTestSuite(t *testing.T) { - suite.Run(t, new(IntegrationTestSuite)) -} diff --git a/x/auth/client/tx.go b/x/auth/client/tx.go index 8e218b7f07..88e95ee634 100644 --- a/x/auth/client/tx.go +++ b/x/auth/client/tx.go @@ -21,15 +21,6 @@ import ( "github.com/line/lbm-sdk/x/auth/legacy/legacytx" ) -// Codec defines the x/auth account codec to be used for use with the -// AccountRetriever. The application must be sure to set this to their respective -// codec that implements the Codec interface and must be the same codec that -// passed to the x/auth module. -// -// TODO:/XXX: Using a package-level global isn't ideal and we should consider -// refactoring the module manager to allow passing in the correct module codec. -var Codec codec.Marshaler - // GasEstimateResponse defines a response definition for tx gas estimation. type GasEstimateResponse struct { GasEstimate uint64 `json:"gas_estimate" yaml:"gas_estimate"` diff --git a/x/auth/keeper/account.go b/x/auth/keeper/account.go index 427112be82..9f2e558555 100644 --- a/x/auth/keeper/account.go +++ b/x/auth/keeper/account.go @@ -25,6 +25,12 @@ func (ak AccountKeeper) NewAccount(ctx sdk.Context, acc types.AccountI) types.Ac return acc } +// HasAccount implements AccountKeeperI. +func (ak AccountKeeper) HasAccount(ctx sdk.Context, addr sdk.AccAddress) bool { + store := ctx.KVStore(ak.key) + return store.Has(types.AddressStoreKey(addr)) +} + // GetAccount implements AccountKeeperI. func (ak AccountKeeper) GetAccount(ctx sdk.Context, addr sdk.AccAddress) types.AccountI { store := ctx.KVStore(ak.key) @@ -73,7 +79,8 @@ func (ak AccountKeeper) RemoveAccount(ctx sdk.Context, acc types.AccountI) { store.Delete(types.AddressStoreKey(addr)) } -// IterateAccounts iterates over all the stored accounts and performs a callback function +// IterateAccounts iterates over all the stored accounts and performs a callback function. +// Stops iteration when callback returns true. func (ak AccountKeeper) IterateAccounts(ctx sdk.Context, cb func(account types.AccountI) (stop bool)) { store := ctx.KVStore(ak.key) iterator := sdk.KVStorePrefixIterator(store, types.AddressStoreKeyPrefix) diff --git a/x/auth/keeper/grpc_query.go b/x/auth/keeper/grpc_query.go index 54535bb7de..219e853850 100644 --- a/x/auth/keeper/grpc_query.go +++ b/x/auth/keeper/grpc_query.go @@ -3,6 +3,9 @@ package keeper import ( "context" + "github.com/line/lbm-sdk/store/prefix" + "github.com/line/lbm-sdk/types/query" + "google.golang.org/grpc/codes" "google.golang.org/grpc/status" @@ -13,6 +16,34 @@ import ( var _ types.QueryServer = AccountKeeper{} +func (ak AccountKeeper) Accounts(c context.Context, req *types.QueryAccountsRequest) (*types.QueryAccountsResponse, error) { + if req == nil { + return nil, status.Error(codes.InvalidArgument, "empty request") + } + + ctx := sdk.UnwrapSDKContext(c) + store := ctx.KVStore(ak.key) + accountsStore := prefix.NewStore(store, types.AddressStoreKeyPrefix) + + var accounts []*codectypes.Any + pageRes, err := query.Paginate(accountsStore, req.Pagination, func(key, value []byte) error { + account := ak.decodeAccount(value) + any, err := codectypes.NewAnyWithValue(account) + if err != nil { + return err + } + + accounts = append(accounts, any) + return nil + }) + + if err != nil { + return nil, status.Errorf(codes.Internal, "paginate: %v", err) + } + + return &types.QueryAccountsResponse{Accounts: accounts, Pagination: pageRes}, err +} + // Account returns account details based on address func (ak AccountKeeper) Account(c context.Context, req *types.QueryAccountRequest) (*types.QueryAccountResponse, error) { if req == nil { diff --git a/x/auth/keeper/grpc_query_test.go b/x/auth/keeper/grpc_query_test.go index 3bdfdacc08..e881a9f464 100644 --- a/x/auth/keeper/grpc_query_test.go +++ b/x/auth/keeper/grpc_query_test.go @@ -8,6 +8,64 @@ import ( "github.com/line/lbm-sdk/x/auth/types" ) +func (suite *KeeperTestSuite) TestGRPCQueryAccounts() { + var ( + req *types.QueryAccountsRequest + ) + _, _, first := testdata.KeyTestPubAddr() + _, _, second := testdata.KeyTestPubAddr() + + testCases := []struct { + msg string + malleate func() + expPass bool + posttests func(res *types.QueryAccountsResponse) + }{ + { + "success", + func() { + suite.app.AccountKeeper.SetAccount(suite.ctx, + suite.app.AccountKeeper.NewAccountWithAddress(suite.ctx, first)) + suite.app.AccountKeeper.SetAccount(suite.ctx, + suite.app.AccountKeeper.NewAccountWithAddress(suite.ctx, second)) + req = &types.QueryAccountsRequest{} + }, + true, + func(res *types.QueryAccountsResponse) { + for _, acc := range res.Accounts { + var account types.AccountI + err := suite.app.InterfaceRegistry().UnpackAny(acc, &account) + suite.Require().NoError(err) + + suite.Require().True( + first.Equals(account.GetAddress()) || second.Equals(account.GetAddress())) + } + }, + }, + } + + for _, tc := range testCases { + suite.Run(fmt.Sprintf("Case %s", tc.msg), func() { + suite.SetupTest() // reset + + tc.malleate() + ctx := sdk.WrapSDKContext(suite.ctx) + + res, err := suite.queryClient.Accounts(ctx, req) + + if tc.expPass { + suite.Require().NoError(err) + suite.Require().NotNil(res) + } else { + suite.Require().Error(err) + suite.Require().Nil(res) + } + + tc.posttests(res) + }) + } +} + func (suite *KeeperTestSuite) TestGRPCQueryAccount() { var ( req *types.QueryAccountRequest diff --git a/x/auth/keeper/keeper.go b/x/auth/keeper/keeper.go index b6de88e597..cad4379cbe 100644 --- a/x/auth/keeper/keeper.go +++ b/x/auth/keeper/keeper.go @@ -22,6 +22,9 @@ type AccountKeeperI interface { // Return a new account with the next account number. Does not save the new account to the store. NewAccount(sdk.Context, types.AccountI) types.AccountI + // Check if an account exists in the store. + HasAccount(sdk.Context, sdk.AccAddress) bool + // Retrieve an account from the store. GetAccount(sdk.Context, sdk.AccAddress) types.AccountI @@ -31,7 +34,7 @@ type AccountKeeperI interface { // Remove an account from the store. RemoveAccount(sdk.Context, types.AccountI) - // Iterate over all accounts, calling the provided function. Stop iteraiton when it returns false. + // Iterate over all accounts, calling the provided function. Stop iteration when it returns true. IterateAccounts(sdk.Context, func(types.AccountI) bool) // Fetch the public key of an account at a specified address @@ -50,8 +53,8 @@ type AccountKeeperI interface { // encoding/decoding library. type AccountKeeper struct { key sdk.StoreKey - cdc codec.BinaryMarshaler - paramSubspace *paramtypes.Subspace + cdc codec.BinaryCodec + paramSubspace paramtypes.Subspace permAddrs map[string]types.PermissionsForAddress // The prototypical AccountI constructor. @@ -62,8 +65,12 @@ var _ AccountKeeperI = &AccountKeeper{} // NewAccountKeeper returns a new AccountKeeperI that uses go-amino to // (binary) encode and decode concrete sdk.Accounts. +// `maccPerms` is a map that takes accounts' addresses as keys, and their respective permissions as values. This map is used to construct +// types.PermissionsForAddress and is used in keeper.ValidatePermissions. Permissions are plain strings, +// and don't have to fit into any predefined structure. This auth module does not use account permissions internally, though other modules +// may use auth.Keeper to access the accounts permissions map. func NewAccountKeeper( - cdc codec.BinaryMarshaler, key sdk.StoreKey, paramstore *paramtypes.Subspace, proto func() types.AccountI, + cdc codec.BinaryCodec, key sdk.StoreKey, paramstore paramtypes.Subspace, proto func() types.AccountI, maccPerms map[string][]string, ) AccountKeeper { @@ -124,7 +131,7 @@ func (ak AccountKeeper) GetNextAccountNumber(ctx sdk.Context) uint64 { } else { val := gogotypes.UInt64Value{} - err := ak.cdc.UnmarshalBinaryBare(bz, &val) + err := ak.cdc.Unmarshal(bz, &val) if err != nil { panic(err) } @@ -132,7 +139,7 @@ func (ak AccountKeeper) GetNextAccountNumber(ctx sdk.Context) uint64 { accNumber = val.GetValue() } - bz = ak.cdc.MustMarshalBinaryBare(&gogotypes.UInt64Value{Value: accNumber + 1}) + bz = ak.cdc.MustMarshal(&gogotypes.UInt64Value{Value: accNumber + 1}) store.Set(types.GlobalAccountNumberKey, bz) return accNumber @@ -204,7 +211,7 @@ func (ak AccountKeeper) GetModuleAccount(ctx sdk.Context, moduleName string) typ } // SetModuleAccount sets the module account to the auth account store -func (ak AccountKeeper) SetModuleAccount(ctx sdk.Context, macc types.ModuleAccountI) { //nolint:interfacer +func (ak AccountKeeper) SetModuleAccount(ctx sdk.Context, macc types.ModuleAccountI) { ak.SetAccount(ctx, macc) } @@ -219,14 +226,15 @@ func (ak AccountKeeper) decodeAccount(bz []byte) types.AccountI { // MarshalAccount protobuf serializes an Account interface func (ak AccountKeeper) MarshalAccount(accountI types.AccountI) ([]byte, error) { // nolint:interfacer - return types.MarshalAccountX(ak.cdc, accountI) + return ak.cdc.MarshalInterface(accountI) } // UnmarshalAccount returns an Account interface from raw encoded account // bytes of a Proto-based Account type func (ak AccountKeeper) UnmarshalAccount(bz []byte) (types.AccountI, error) { - return types.UnmarshalAccountX(ak.cdc, bz) + var acc types.AccountI + return acc, ak.cdc.UnmarshalInterface(bz, &acc) } -// GetCodec return codec.Marshaler object used by the keeper -func (ak AccountKeeper) GetCodec() codec.BinaryMarshaler { return ak.cdc } +// GetCodec return codec.Codec object used by the keeper +func (ak AccountKeeper) GetCodec() codec.BinaryCodec { return ak.cdc } diff --git a/x/auth/keeper/keeper_bench_test.go b/x/auth/keeper/keeper_bench_test.go index cc19f8bfc9..f89e3eda5d 100644 --- a/x/auth/keeper/keeper_bench_test.go +++ b/x/auth/keeper/keeper_bench_test.go @@ -7,6 +7,7 @@ import ( ) func BenchmarkAccountMapperGetAccountFound(b *testing.B) { + b.ReportAllocs() app, ctx := createTestApp(false) // assumes b.N < 2**24 diff --git a/x/auth/keeper/keeper_test.go b/x/auth/keeper/keeper_test.go index 91499e9f0f..7a4f2d5d6a 100644 --- a/x/auth/keeper/keeper_test.go +++ b/x/auth/keeper/keeper_test.go @@ -131,7 +131,7 @@ func TestSupply_ValidatePermissions(t *testing.T) { maccPerms[multiPerm] = []string{types.Burner, types.Minter, types.Staking} maccPerms[randomPerm] = []string{"random"} - cdc, _ := simapp.MakeCodecs() + cdc := simapp.MakeTestEncodingConfig().Marshaler keeper := keeper.NewAccountKeeper( cdc, app.GetKey(types.StoreKey), app.GetSubspace(types.ModuleName), types.ProtoBaseAccount, maccPerms, diff --git a/x/auth/keeper/migrations.go b/x/auth/keeper/migrations.go index 780e70bda6..28830b8575 100644 --- a/x/auth/keeper/migrations.go +++ b/x/auth/keeper/migrations.go @@ -1,20 +1,47 @@ package keeper import ( + "github.com/gogo/protobuf/grpc" + sdk "github.com/line/lbm-sdk/types" + v043 "github.com/line/lbm-sdk/x/auth/legacy/v043" + "github.com/line/lbm-sdk/x/auth/types" ) // Migrator is a struct for handling in-place store migrations. type Migrator struct { - keeper AccountKeeper + keeper AccountKeeper + queryServer grpc.Server } // NewMigrator returns a new Migrator. -func NewMigrator(keeper AccountKeeper) Migrator { - return Migrator{keeper: keeper} +func NewMigrator(keeper AccountKeeper, queryServer grpc.Server) Migrator { + return Migrator{keeper: keeper, queryServer: queryServer} } // Migrate1to2 migrates from version 1 to 2. func (m Migrator) Migrate1to2(ctx sdk.Context) error { return nil } + +// Migrate1to2 migrates from version 1 to 2. +func (m Migrator) MigrateV040ToV043(ctx sdk.Context) error { + var iterErr error + + m.keeper.IterateAccounts(ctx, func(account types.AccountI) (stop bool) { + wb, err := v043.MigrateAccount(ctx, account, m.queryServer) + if err != nil { + iterErr = err + return true + } + + if wb == nil { + return false + } + + m.keeper.SetAccount(ctx, wb) + return false + }) + + return iterErr +} diff --git a/x/auth/legacy/legacytx/amino_signing.go b/x/auth/legacy/legacytx/amino_signing.go index 2221dba791..b54a740c09 100644 --- a/x/auth/legacy/legacytx/amino_signing.go +++ b/x/auth/legacy/legacytx/amino_signing.go @@ -64,7 +64,7 @@ func SignatureDataToAminoSignature(cdc *codec.LegacyAmino, data signingtypes.Sig return nil, err } - return cdc.MarshalBinaryBare(aminoMSig) + return cdc.Marshal(aminoMSig) default: return nil, fmt.Errorf("unexpected signature data %T", data) } diff --git a/x/auth/legacy/legacytx/stdsig_test.go b/x/auth/legacy/legacytx/stdsig_test.go new file mode 100644 index 0000000000..b944e0b769 --- /dev/null +++ b/x/auth/legacy/legacytx/stdsig_test.go @@ -0,0 +1,41 @@ +package legacytx_test + +import ( + "fmt" + "testing" + + "github.com/stretchr/testify/require" + yaml "gopkg.in/yaml.v2" + + "github.com/line/lbm-sdk/testutil/testdata" + "github.com/line/lbm-sdk/x/auth/legacy/legacytx" +) + +func TestStdSignatureMarshalYAML(t *testing.T) { + _, pk, _ := testdata.KeyTestPubAddr() + pkStr := pk.String() + + testCases := []struct { + sig legacytx.StdSignature + expected string + }{ + { + legacytx.StdSignature{}, + "|\n pubkey: \"\"\n signature: \"\"\n", + }, + { + legacytx.StdSignature{PubKey: pk, Signature: []byte("dummySig")}, + fmt.Sprintf("|\n pubkey: %s\n signature: 64756D6D79536967\n", pkStr), + }, + { + legacytx.StdSignature{PubKey: pk, Signature: nil}, + fmt.Sprintf("|\n pubkey: %s\n signature: \"\"\n", pkStr), + }, + } + + for i, tc := range testCases { + bz, err := yaml.Marshal(tc.sig) + require.NoError(t, err) + require.Equal(t, tc.expected, string(bz), "test case #%d", i) + } +} diff --git a/x/auth/legacy/legacytx/stdsign.go b/x/auth/legacy/legacytx/stdsign.go index 75ecc34397..5436b805d6 100644 --- a/x/auth/legacy/legacytx/stdsign.go +++ b/x/auth/legacy/legacytx/stdsign.go @@ -2,9 +2,13 @@ package legacytx import ( "encoding/json" + "fmt" + + "gopkg.in/yaml.v2" "github.com/line/lbm-sdk/codec" "github.com/line/lbm-sdk/codec/legacy" + codectypes "github.com/line/lbm-sdk/codec/types" cryptotypes "github.com/line/lbm-sdk/crypto/types" "github.com/line/lbm-sdk/crypto/types/multisig" sdk "github.com/line/lbm-sdk/types" @@ -49,7 +53,12 @@ type StdSignDoc struct { func StdSignBytes(chainID string, accnum, sequence, timeout uint64, fee StdFee, msgs []sdk.Msg, memo string) []byte { msgsBytes := make([]json.RawMessage, 0, len(msgs)) for _, msg := range msgs { - msgsBytes = append(msgsBytes, json.RawMessage(msg.GetSignBytes())) + legacyMsg, ok := msg.(LegacyMsg) + if !ok { + panic(fmt.Errorf("expected %T when using amino JSON", (*LegacyMsg)(nil))) + } + + msgsBytes = append(msgsBytes, json.RawMessage(legacyMsg.GetSignBytes())) } bz, err := legacy.Cdc.MarshalJSON(StdSignDoc{ @@ -74,6 +83,47 @@ type StdSignature struct { Signature []byte `json:"signature" yaml:"signature"` } +// Deprecated +func NewStdSignature(pk cryptotypes.PubKey, sig []byte) StdSignature { + return StdSignature{PubKey: pk, Signature: sig} +} + +// GetSignature returns the raw signature bytes. +func (ss StdSignature) GetSignature() []byte { + return ss.Signature +} + +// GetPubKey returns the public key of a signature as a cryptotypes.PubKey using the +// Amino codec. +func (ss StdSignature) GetPubKey() cryptotypes.PubKey { + return ss.PubKey +} + +// MarshalYAML returns the YAML representation of the signature. +func (ss StdSignature) MarshalYAML() (interface{}, error) { + pk := "" + if ss.PubKey != nil { + pk = ss.PubKey.String() + } + + bz, err := yaml.Marshal(struct { + PubKey string + Signature string + }{ + pk, + fmt.Sprintf("%X", ss.Signature), + }) + if err != nil { + return nil, err + } + + return string(bz), err +} + +func (ss StdSignature) UnpackInterfaces(unpacker codectypes.AnyUnpacker) error { + return codectypes.UnpackInterfaces(ss.PubKey, unpacker) +} + // StdSignatureToSignatureV2 converts a StdSignature to a SignatureV2 func StdSignatureToSignatureV2(cdc *codec.LegacyAmino, sig StdSignature) (signing.SignatureV2, error) { pk := sig.GetPubKey() @@ -97,7 +147,7 @@ func pubKeySigToSigData(cdc *codec.LegacyAmino, key cryptotypes.PubKey, sig []by }, nil } var multiSig multisig.AminoMultisignature - err := cdc.UnmarshalBinaryBare(sig, &multiSig) + err := cdc.Unmarshal(sig, &multiSig) if err != nil { return nil, err } diff --git a/x/auth/legacy/legacytx/stdtx.go b/x/auth/legacy/legacytx/stdtx.go index 45a88e1b9a..68bfea0dca 100644 --- a/x/auth/legacy/legacytx/stdtx.go +++ b/x/auth/legacy/legacytx/stdtx.go @@ -1,10 +1,6 @@ package legacytx import ( - "fmt" - - "gopkg.in/yaml.v2" - "github.com/line/lbm-sdk/codec/legacy" codectypes "github.com/line/lbm-sdk/codec/types" cryptotypes "github.com/line/lbm-sdk/crypto/types" @@ -74,55 +70,6 @@ func (fee StdFee) GasPrices() sdk.DecCoins { return sdk.NewDecCoinsFromCoins(fee.Amount...).QuoDec(sdk.NewDec(int64(fee.Gas))) } -// Deprecated -func NewStdSignature(pk cryptotypes.PubKey, sig []byte) StdSignature { - return StdSignature{PubKey: pk, Signature: sig} -} - -// GetSignature returns the raw signature bytes. -func (ss StdSignature) GetSignature() []byte { - return ss.Signature -} - -// GetPubKey returns the public key of a signature as a cryptotypes.PubKey using the -// Amino codec. -func (ss StdSignature) GetPubKey() cryptotypes.PubKey { - return ss.PubKey -} - -// MarshalYAML returns the YAML representation of the signature. -func (ss StdSignature) MarshalYAML() (interface{}, error) { - var ( - bz []byte - pubkey string - err error - ) - - if ss.PubKey != nil { - pubkey, err = sdk.Bech32ifyPubKey(sdk.Bech32PubKeyTypeAccPub, ss.GetPubKey()) - if err != nil { - return nil, err - } - } - - bz, err = yaml.Marshal(struct { - PubKey string - Signature string - }{ - PubKey: pubkey, - Signature: fmt.Sprintf("%X", ss.Signature), - }) - if err != nil { - return nil, err - } - - return string(bz), err -} - -func (ss StdSignature) UnpackInterfaces(unpacker codectypes.AnyUnpacker) error { - return codectypes.UnpackInterfaces(ss.PubKey, unpacker) -} - // StdTx is the legacy transaction format for wrapping a Msg with Fee and Signatures. // It only works with Amino, please prefer the new protobuf Tx in types/tx. // NOTE: the first signature is the fee payer (Signatures must not be nil). @@ -246,14 +193,14 @@ func (tx StdTx) GetSignaturesV2() ([]signing.SignatureV2, error) { // GetPubkeys returns the pubkeys of signers if the pubkey is included in the signature // If pubkey is not included in the signature, then nil is in the slice instead -func (tx StdTx) GetPubKeys() []cryptotypes.PubKey { +func (tx StdTx) GetPubKeys() ([]cryptotypes.PubKey, error) { pks := make([]cryptotypes.PubKey, len(tx.Signatures)) for i, stdSig := range tx.Signatures { pks[i] = stdSig.GetPubKey() } - return pks + return pks, nil } // GetGas returns the Gas in StdFee diff --git a/x/auth/legacy/legacytx/stdtx_builder.go b/x/auth/legacy/legacytx/stdtx_builder.go index 78cf30e448..189fb669e4 100644 --- a/x/auth/legacy/legacytx/stdtx_builder.go +++ b/x/auth/legacy/legacytx/stdtx_builder.go @@ -29,25 +29,7 @@ func (s *StdTxBuilder) GetTx() authsigning.Tx { // SetMsgs implements TxBuilder.SetMsgs func (s *StdTxBuilder) SetMsgs(msgs ...sdk.Msg) error { - stdTxMsgs := make([]sdk.Msg, len(msgs)) - - for i, msg := range msgs { - switch msg := msg.(type) { - case sdk.ServiceMsg: - // Since ServiceMsg isn't registered with amino, we unpack msg.Request - // into a Msg so that it's handled gracefully for the legacy - // GET /txs/{hash} and /txs endpoints. - sdkMsg, ok := msg.Request.(sdk.Msg) - if !ok { - return sdkerrors.Wrapf(sdkerrors.ErrInvalidType, "Expecting %T at %d to implement sdk.Msg", msg.Request, i) - } - stdTxMsgs[i] = sdkMsg - default: - // legacy sdk.Msg - stdTxMsgs[i] = msg - } - } - s.Msgs = stdTxMsgs + s.Msgs = msgs return nil } @@ -117,7 +99,7 @@ func (s StdTxConfig) TxEncoder() sdk.TxEncoder { } func (s StdTxConfig) TxDecoder() sdk.TxDecoder { - return mkDecoder(s.Cdc.UnmarshalBinaryBare) + return mkDecoder(s.Cdc.Unmarshal) } func (s StdTxConfig) TxJSONEncoder() sdk.TxEncoder { @@ -209,6 +191,6 @@ func mkDecoder(unmarshaler Unmarshaler) sdk.TxDecoder { // DefaultTxEncoder logic for standard transaction encoding func DefaultTxEncoder(cdc *codec.LegacyAmino) sdk.TxEncoder { return func(tx sdk.Tx) ([]byte, error) { - return cdc.MarshalBinaryBare(tx) + return cdc.Marshal(tx) } } diff --git a/x/auth/legacy/legacytx/stdtx_test.go b/x/auth/legacy/legacytx/stdtx_test.go index 5723269d99..c05e31978f 100644 --- a/x/auth/legacy/legacytx/stdtx_test.go +++ b/x/auth/legacy/legacytx/stdtx_test.go @@ -7,7 +7,6 @@ import ( "github.com/line/ostracon/libs/log" ocproto "github.com/line/ostracon/proto/ostracon/types" "github.com/stretchr/testify/require" - yaml "gopkg.in/yaml.v2" "github.com/line/lbm-sdk/codec" cryptocodec "github.com/line/lbm-sdk/crypto/codec" @@ -173,7 +172,7 @@ func TestDefaultTxEncoder(t *testing.T) { tx := NewStdTx(msgs, fee, sigs, "") - cdcBytes, err := cdc.MarshalBinaryBare(tx) + cdcBytes, err := cdc.Marshal(tx) require.NoError(t, err) encoderBytes, err := encoder(tx) @@ -182,34 +181,6 @@ func TestDefaultTxEncoder(t *testing.T) { require.Equal(t, cdcBytes, encoderBytes) } -func TestStdSignatureMarshalYAML(t *testing.T) { - _, pubKey, _ := testdata.KeyTestPubAddr() - - testCases := []struct { - sig StdSignature - output string - }{ - { - StdSignature{}, - "|\n pubkey: \"\"\n signature: \"\"\n", - }, - { - StdSignature{PubKey: pubKey, Signature: []byte("dummySig")}, - fmt.Sprintf("|\n pubkey: %s\n signature: 64756D6D79536967\n", sdk.MustBech32ifyPubKey(sdk.Bech32PubKeyTypeAccPub, pubKey)), - }, - { - StdSignature{PubKey: pubKey, Signature: nil}, - fmt.Sprintf("|\n pubkey: %s\n signature: \"\"\n", sdk.MustBech32ifyPubKey(sdk.Bech32PubKeyTypeAccPub, pubKey)), - }, - } - - for i, tc := range testCases { - bz, err := yaml.Marshal(tc.sig) - require.NoError(t, err) - require.Equal(t, tc.output, string(bz), "test case #%d", i) - } -} - func TestSignatureV2Conversions(t *testing.T) { _, pubKey, _ := testdata.KeyTestPubAddr() cdc := codec.NewLegacyAmino() @@ -280,7 +251,7 @@ func TestGetSignaturesV2(t *testing.T) { require.Nil(t, err) require.Equal(t, len(sigs), 1) - require.Equal(t, cdc.MustMarshalBinaryBare(sigs[0].PubKey), cdc.MustMarshalBinaryBare(sig.GetPubKey())) + require.Equal(t, cdc.MustMarshal(sigs[0].PubKey), cdc.MustMarshal(sig.GetPubKey())) require.Equal(t, sigs[0].Data, &signing.SingleSignatureData{ SignMode: signing.SignMode_SIGN_MODE_LEGACY_AMINO_JSON, Signature: sig.GetSignature(), diff --git a/x/auth/legacy/v040/store.go b/x/auth/legacy/v040/store.go new file mode 100644 index 0000000000..765c2b94ea --- /dev/null +++ b/x/auth/legacy/v040/store.go @@ -0,0 +1,5 @@ +package v040 + +// AddrLen defines a valid address length +const AddrLen = 43 +const ValAddrLen = 50 diff --git a/x/auth/legacy/v043/store.go b/x/auth/legacy/v043/store.go new file mode 100644 index 0000000000..3a26b4a7db --- /dev/null +++ b/x/auth/legacy/v043/store.go @@ -0,0 +1,299 @@ +// Package v043 creates in-place store migrations for fixing tracking +// delegations with vesting accounts. +// ref: https://github.com/cosmos/cosmos-sdk/issues/8601 +// ref: https://github.com/cosmos/cosmos-sdk/issues/8812 +// +// The migration script modifies x/auth state, hence lives in the `x/auth/legacy` +// folder. However, it needs access to staking and bank state. To avoid +// cyclic dependencies, we cannot import those 2 keepers in this file. To solve +// this, we use the baseapp router to do inter-module querying, by importing +// the `baseapp.QueryRouter grpc.Server`. This is really hacky. +// +// PLEASE DO NOT REPLICATE THIS PATTERN IN YOUR OWN APP. +// +// Proposals to refactor this file have been made in: +// https://github.com/cosmos/cosmos-sdk/issues/9070 +// The preferred solution is to use inter-module communication (ADR-033), and +// this file will be refactored to use ADR-033 once it's ready. +package v043 + +import ( + "errors" + "fmt" + + "github.com/gogo/protobuf/grpc" + "github.com/gogo/protobuf/proto" + abci "github.com/line/ostracon/abci/types" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + + "github.com/line/lbm-sdk/baseapp" + sdk "github.com/line/lbm-sdk/types" + sdkerrors "github.com/line/lbm-sdk/types/errors" + "github.com/line/lbm-sdk/x/auth/types" + "github.com/line/lbm-sdk/x/auth/vesting/exported" + vestingtypes "github.com/line/lbm-sdk/x/auth/vesting/types" + banktypes "github.com/line/lbm-sdk/x/bank/types" + stakingtypes "github.com/line/lbm-sdk/x/staking/types" +) + +const ( + delegatorDelegationPath = "/lbm.staking.v1.Query/DelegatorDelegations" + stakingParamsPath = "/lbm.staking.v1.Query/Params" + delegatorUnbondingDelegationsPath = "/lbm.staking.v1.Query/DelegatorUnbondingDelegations" + balancesPath = "/lbm.bank.v1.Query/AllBalances" +) + +// We use the baseapp.QueryRouter here to do inter-module state querying. +// PLEASE DO NOT REPLICATE THIS PATTERN IN YOUR OWN APP. +func migrateVestingAccounts(ctx sdk.Context, account types.AccountI, queryServer grpc.Server) (types.AccountI, error) { + bondDenom, err := getBondDenom(ctx, queryServer) + + if err != nil { + return nil, err + } + + asVesting, ok := account.(exported.VestingAccount) + if !ok { + return nil, nil + } + + addr := account.GetAddress().String() + balance, err := getBalance( + ctx, + addr, + queryServer, + ) + + if err != nil { + return nil, err + } + + delegations, err := getDelegatorDelegationsSum( + ctx, + addr, + queryServer, + ) + + if err != nil { + return nil, err + } + + unbondingDelegations, err := getDelegatorUnbondingDelegationsSum( + ctx, + addr, + bondDenom, + queryServer, + ) + + if err != nil { + return nil, err + } + + delegations = delegations.Add(unbondingDelegations...) + + asVesting, ok = resetVestingDelegatedBalances(asVesting) + if !ok { + return nil, nil + } + + // balance before any delegation includes balance of delegation + for _, coin := range delegations { + balance = balance.Add(coin) + } + + asVesting.TrackDelegation(ctx.BlockTime(), balance, delegations) + + return asVesting.(types.AccountI), nil +} + +func resetVestingDelegatedBalances(evacct exported.VestingAccount) (exported.VestingAccount, bool) { + // reset `DelegatedVesting` and `DelegatedFree` to zero + df := sdk.NewCoins() + dv := sdk.NewCoins() + + switch vacct := evacct.(type) { + case *vestingtypes.ContinuousVestingAccount: + vacct.DelegatedVesting = dv + vacct.DelegatedFree = df + return vacct, true + case *vestingtypes.DelayedVestingAccount: + vacct.DelegatedVesting = dv + vacct.DelegatedFree = df + return vacct, true + case *vestingtypes.PeriodicVestingAccount: + vacct.DelegatedVesting = dv + vacct.DelegatedFree = df + return vacct, true + default: + return nil, false + } +} + +// We use the baseapp.QueryRouter here to do inter-module state querying. +// PLEASE DO NOT REPLICATE THIS PATTERN IN YOUR OWN APP. +func getDelegatorDelegationsSum(ctx sdk.Context, address string, queryServer grpc.Server) (sdk.Coins, error) { + querier, ok := queryServer.(*baseapp.GRPCQueryRouter) + if !ok { + return nil, fmt.Errorf("unexpected type: %T wanted *baseapp.GRPCQueryRouter", queryServer) + } + + queryFn := querier.Route(delegatorDelegationPath) + + q := &stakingtypes.QueryDelegatorDelegationsRequest{ + DelegatorAddr: address, + } + + b, err := proto.Marshal(q) + if err != nil { + return nil, fmt.Errorf("cannot marshal staking type query request, %w", err) + } + req := abci.RequestQuery{ + Data: b, + Path: delegatorDelegationPath, + } + resp, err := queryFn(ctx, req) + if err != nil { + e, ok := status.FromError(err) + if ok && e.Code() == codes.NotFound { + return nil, nil + } + return nil, fmt.Errorf("staking query error, %w", err) + } + + balance := new(stakingtypes.QueryDelegatorDelegationsResponse) + if err := proto.Unmarshal(resp.Value, balance); err != nil { + return nil, fmt.Errorf("unable to unmarshal delegator query delegations: %w", err) + } + + res := sdk.NewCoins() + for _, i := range balance.DelegationResponses { + res = res.Add(i.Balance) + } + + return res, nil +} + +// We use the baseapp.QueryRouter here to do inter-module state querying. +// PLEASE DO NOT REPLICATE THIS PATTERN IN YOUR OWN APP. +func getDelegatorUnbondingDelegationsSum(ctx sdk.Context, address, bondDenom string, queryServer grpc.Server) (sdk.Coins, error) { + querier, ok := queryServer.(*baseapp.GRPCQueryRouter) + if !ok { + return nil, fmt.Errorf("unexpected type: %T wanted *baseapp.GRPCQueryRouter", queryServer) + } + + queryFn := querier.Route(delegatorUnbondingDelegationsPath) + + q := &stakingtypes.QueryDelegatorUnbondingDelegationsRequest{ + DelegatorAddr: address, + } + + b, err := proto.Marshal(q) + if err != nil { + return nil, fmt.Errorf("cannot marshal staking type query request, %w", err) + } + req := abci.RequestQuery{ + Data: b, + Path: delegatorUnbondingDelegationsPath, + } + resp, err := queryFn(ctx, req) + if err != nil && !errors.Is(err, sdkerrors.ErrNotFound) { + e, ok := status.FromError(err) + if ok && e.Code() == codes.NotFound { + return nil, nil + } + return nil, fmt.Errorf("staking query error, %w", err) + } + + balance := new(stakingtypes.QueryDelegatorUnbondingDelegationsResponse) + if err := proto.Unmarshal(resp.Value, balance); err != nil { + return nil, fmt.Errorf("unable to unmarshal delegator query delegations: %w", err) + } + + res := sdk.NewCoins() + for _, i := range balance.UnbondingResponses { + for _, r := range i.Entries { + res = res.Add(sdk.NewCoin(bondDenom, r.Balance)) + } + } + + return res, nil +} + +// We use the baseapp.QueryRouter here to do inter-module state querying. +// PLEASE DO NOT REPLICATE THIS PATTERN IN YOUR OWN APP. +func getBalance(ctx sdk.Context, address string, queryServer grpc.Server) (sdk.Coins, error) { + querier, ok := queryServer.(*baseapp.GRPCQueryRouter) + if !ok { + return nil, fmt.Errorf("unexpected type: %T wanted *baseapp.GRPCQueryRouter", queryServer) + } + + queryFn := querier.Route(balancesPath) + + q := &banktypes.QueryAllBalancesRequest{ + Address: address, + Pagination: nil, + } + b, err := proto.Marshal(q) + if err != nil { + return nil, fmt.Errorf("cannot marshal bank type query request, %w", err) + } + + req := abci.RequestQuery{ + Data: b, + Path: balancesPath, + } + resp, err := queryFn(ctx, req) + if err != nil { + return nil, fmt.Errorf("bank query error, %w", err) + } + balance := new(banktypes.QueryAllBalancesResponse) + if err := proto.Unmarshal(resp.Value, balance); err != nil { + return nil, fmt.Errorf("unable to unmarshal bank balance response: %w", err) + } + return balance.Balances, nil +} + +// We use the baseapp.QueryRouter here to do inter-module state querying. +// PLEASE DO NOT REPLICATE THIS PATTERN IN YOUR OWN APP. +func getBondDenom(ctx sdk.Context, queryServer grpc.Server) (string, error) { + querier, ok := queryServer.(*baseapp.GRPCQueryRouter) + if !ok { + return "", fmt.Errorf("unexpected type: %T wanted *baseapp.GRPCQueryRouter", queryServer) + } + + queryFn := querier.Route(stakingParamsPath) + + q := &stakingtypes.QueryParamsRequest{} + + b, err := proto.Marshal(q) + if err != nil { + return "", fmt.Errorf("cannot marshal staking params query request, %w", err) + } + req := abci.RequestQuery{ + Data: b, + Path: stakingParamsPath, + } + + resp, err := queryFn(ctx, req) + if err != nil { + return "", fmt.Errorf("staking query error, %w", err) + } + + params := new(stakingtypes.QueryParamsResponse) + if err := proto.Unmarshal(resp.Value, params); err != nil { + return "", fmt.Errorf("unable to unmarshal delegator query delegations: %w", err) + } + + return params.Params.BondDenom, nil +} + +// MigrateAccount migrates vesting account to make the DelegatedVesting and DelegatedFree fields correctly +// track delegations. +// References: https://github.com/cosmos/cosmos-sdk/issues/8601, https://github.com/cosmos/cosmos-sdk/issues/8812 +// +// We use the baseapp.QueryRouter here to do inter-module state querying. +// PLEASE DO NOT REPLICATE THIS PATTERN IN YOUR OWN APP. +func MigrateAccount(ctx sdk.Context, account types.AccountI, queryServer grpc.Server) (types.AccountI, error) { + return migrateVestingAccounts(ctx, account, queryServer) +} diff --git a/x/auth/legacy/v043/store_test.go b/x/auth/legacy/v043/store_test.go new file mode 100644 index 0000000000..7ef0fa7d28 --- /dev/null +++ b/x/auth/legacy/v043/store_test.go @@ -0,0 +1,198 @@ +package v043_test + +import ( + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/require" + + ocproto "github.com/line/ostracon/proto/ostracon/types" + + "github.com/line/lbm-sdk/simapp" + sdk "github.com/line/lbm-sdk/types" + authkeeper "github.com/line/lbm-sdk/x/auth/keeper" + authtypes "github.com/line/lbm-sdk/x/auth/types" + "github.com/line/lbm-sdk/x/auth/vesting/exported" + "github.com/line/lbm-sdk/x/auth/vesting/types" + "github.com/line/lbm-sdk/x/staking" + stakingkeeper "github.com/line/lbm-sdk/x/staking/keeper" + stakingtypes "github.com/line/lbm-sdk/x/staking/types" +) + +func TestMigrateVestingAccounts(t *testing.T) { + testCases := []struct { + name string + prepareFunc func(app *simapp.SimApp, ctx sdk.Context, validator stakingtypes.Validator, delegatorAddr sdk.AccAddress) + garbageFunc func(ctx sdk.Context, vesting exported.VestingAccount, app *simapp.SimApp) error + tokenAmount int64 + expVested int64 + expFree int64 + blockTime int64 + }{ + { + "delayed vesting has vested, multiple delegations less than the total account balance", + func(app *simapp.SimApp, ctx sdk.Context, validator stakingtypes.Validator, delegatorAddr sdk.AccAddress) { + + baseAccount := authtypes.NewBaseAccountWithAddress(delegatorAddr) + vestedCoins := sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), sdk.NewInt(200))) + delayedAccount := types.NewDelayedVestingAccount(baseAccount, vestedCoins, ctx.BlockTime().Unix()) + + ctx = ctx.WithBlockTime(ctx.BlockTime().AddDate(1, 0, 0)) + + app.AccountKeeper.SetAccount(ctx, delayedAccount) + + _, err := app.StakingKeeper.Delegate(ctx, delegatorAddr, sdk.NewInt(100), stakingtypes.Unbonded, validator, true) + require.NoError(t, err) + _, err = app.StakingKeeper.Delegate(ctx, delegatorAddr, sdk.NewInt(100), stakingtypes.Unbonded, validator, true) + require.NoError(t, err) + _, err = app.StakingKeeper.Delegate(ctx, delegatorAddr, sdk.NewInt(100), stakingtypes.Unbonded, validator, true) + require.NoError(t, err) + }, + cleartTrackingFields, + 300, + 0, + 300, + 0, + }, + } + + for _, tc := range testCases { + tc := tc + t.Run(tc.name, func(t *testing.T) { + app := simapp.Setup(false) + ctx := app.BaseApp.NewContext(false, ocproto.Header{ + Time: time.Now(), + }) + + addrs := simapp.AddTestAddrs(app, ctx, 1, sdk.NewInt(tc.tokenAmount)) + delegatorAddr := addrs[0] + + _, valAddr := createValidator(t, ctx, app, tc.tokenAmount*2) + validator, found := app.StakingKeeper.GetValidator(ctx, valAddr) + require.True(t, found) + + tc.prepareFunc(app, ctx, validator, delegatorAddr) + + if tc.blockTime != 0 { + ctx = ctx.WithBlockTime(time.Unix(tc.blockTime, 0)) + } + + // We introduce the bug + savedAccount := app.AccountKeeper.GetAccount(ctx, delegatorAddr) + vestingAccount, ok := savedAccount.(exported.VestingAccount) + require.True(t, ok) + require.NoError(t, tc.garbageFunc(ctx, vestingAccount, app)) + + m := authkeeper.NewMigrator(app.AccountKeeper, app.GRPCQueryRouter()) + require.NoError(t, m.MigrateV040ToV043(ctx)) + + var expVested sdk.Coins + var expFree sdk.Coins + + if tc.expVested != 0 { + expVested = sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), sdk.NewInt(tc.expVested))) + } + + if tc.expFree != 0 { + expFree = sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), sdk.NewInt(tc.expFree))) + } + + trackingCorrected( + ctx, + t, + app.AccountKeeper, + savedAccount.GetAddress(), + expVested, + expFree, + ) + }) + } + +} + +func trackingCorrected(ctx sdk.Context, t *testing.T, ak authkeeper.AccountKeeper, addr sdk.AccAddress, expDelVesting sdk.Coins, expDelFree sdk.Coins) { + t.Helper() + baseAccount := ak.GetAccount(ctx, addr) + vDA, ok := baseAccount.(exported.VestingAccount) + require.True(t, ok) + + vestedOk := expDelVesting.IsEqual(vDA.GetDelegatedVesting()) + freeOk := expDelFree.IsEqual(vDA.GetDelegatedFree()) + require.True(t, vestedOk, vDA.GetDelegatedVesting().String()) + require.True(t, freeOk, vDA.GetDelegatedFree().String()) +} + +func cleartTrackingFields(ctx sdk.Context, vesting exported.VestingAccount, app *simapp.SimApp) error { + switch t := vesting.(type) { + case *types.DelayedVestingAccount: + t.DelegatedFree = nil + t.DelegatedVesting = nil + app.AccountKeeper.SetAccount(ctx, t) + case *types.ContinuousVestingAccount: + t.DelegatedFree = nil + t.DelegatedVesting = nil + app.AccountKeeper.SetAccount(ctx, t) + case *types.PeriodicVestingAccount: + t.DelegatedFree = nil + t.DelegatedVesting = nil + app.AccountKeeper.SetAccount(ctx, t) + default: + return fmt.Errorf("expected vesting account, found %t", t) + } + + return nil +} + +func dirtyTrackingFields(ctx sdk.Context, vesting exported.VestingAccount, app *simapp.SimApp) error { + dirt := sdk.NewCoins(sdk.NewInt64Coin("stake", 42)) + + switch t := vesting.(type) { + case *types.DelayedVestingAccount: + t.DelegatedFree = dirt + t.DelegatedVesting = dirt + app.AccountKeeper.SetAccount(ctx, t) + case *types.ContinuousVestingAccount: + t.DelegatedFree = dirt + t.DelegatedVesting = dirt + app.AccountKeeper.SetAccount(ctx, t) + case *types.PeriodicVestingAccount: + t.DelegatedFree = dirt + t.DelegatedVesting = dirt + app.AccountKeeper.SetAccount(ctx, t) + default: + return fmt.Errorf("expected vesting account, found %t", t) + } + + return nil +} + +func createValidator(t *testing.T, ctx sdk.Context, app *simapp.SimApp, powers int64) (sdk.AccAddress, sdk.ValAddress) { + valTokens := sdk.TokensFromConsensusPower(powers, sdk.DefaultPowerReduction) + addrs := simapp.AddTestAddrsIncremental(app, ctx, 1, valTokens) + valAddrs := simapp.ConvertAddrsToValAddrs(addrs) + pks := simapp.CreateTestPubKeys(1) + cdc := simapp.MakeTestEncodingConfig().Marshaler + + app.StakingKeeper = stakingkeeper.NewKeeper( + cdc, + app.GetKey(stakingtypes.StoreKey), + app.AccountKeeper, + app.BankKeeper, + app.GetSubspace(stakingtypes.ModuleName), + ) + + val1, err := stakingtypes.NewValidator(valAddrs[0], pks[0], stakingtypes.Description{}) + require.NoError(t, err) + + app.StakingKeeper.SetValidator(ctx, val1) + require.NoError(t, app.StakingKeeper.SetValidatorByConsAddr(ctx, val1)) + app.StakingKeeper.SetNewValidatorByPowerIndex(ctx, val1) + + _, err = app.StakingKeeper.Delegate(ctx, addrs[0], valTokens, stakingtypes.Unbonded, val1, true) + require.NoError(t, err) + + _ = staking.EndBlocker(ctx, app.StakingKeeper) + + return addrs[0], valAddrs[0] +} diff --git a/x/auth/module.go b/x/auth/module.go index 1c12ebae45..e826e0f2d6 100644 --- a/x/auth/module.go +++ b/x/auth/module.go @@ -46,12 +46,12 @@ func (AppModuleBasic) RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) { // DefaultGenesis returns default genesis state as raw bytes for the auth // module. -func (AppModuleBasic) DefaultGenesis(cdc codec.JSONMarshaler) json.RawMessage { +func (AppModuleBasic) DefaultGenesis(cdc codec.JSONCodec) json.RawMessage { return cdc.MustMarshalJSON(types.DefaultGenesisState()) } // ValidateGenesis performs genesis state validation for the auth module. -func (AppModuleBasic) ValidateGenesis(cdc codec.JSONMarshaler, config client.TxEncodingConfig, bz json.RawMessage) error { +func (AppModuleBasic) ValidateGenesis(cdc codec.JSONCodec, config client.TxEncodingConfig, bz json.RawMessage) error { var data types.GenesisState if err := cdc.UnmarshalJSON(bz, &data); err != nil { return fmt.Errorf("failed to unmarshal %s genesis state: %w", types.ModuleName, err) @@ -67,12 +67,14 @@ func (AppModuleBasic) RegisterRESTRoutes(clientCtx client.Context, rtr *mux.Rout // RegisterGRPCGatewayRoutes registers the gRPC Gateway routes for the auth module. func (AppModuleBasic) RegisterGRPCGatewayRoutes(clientCtx client.Context, mux *runtime.ServeMux) { - types.RegisterQueryHandlerClient(context.Background(), mux, types.NewQueryClient(clientCtx)) + if err := types.RegisterQueryHandlerClient(context.Background(), mux, types.NewQueryClient(clientCtx)); err != nil { + panic(err) + } } // GetTxCmd returns the root tx command for the auth module. func (AppModuleBasic) GetTxCmd() *cobra.Command { - return nil + return cli.NewTxCmd() } // GetQueryCmd returns the root query command for the auth module. @@ -85,8 +87,6 @@ func (AppModuleBasic) RegisterInterfaces(registry codectypes.InterfaceRegistry) types.RegisterInterfaces(registry) } -// ____________________________________________________________________________ - // AppModule implements an application module for the auth module. type AppModule struct { AppModuleBasic @@ -96,7 +96,7 @@ type AppModule struct { } // NewAppModule creates a new AppModule object -func NewAppModule(cdc codec.Marshaler, accountKeeper keeper.AccountKeeper, randGenAccountsFn types.RandomGenesisAccountsFn) AppModule { +func NewAppModule(cdc codec.Codec, accountKeeper keeper.AccountKeeper, randGenAccountsFn types.RandomGenesisAccountsFn) AppModule { return AppModule{ AppModuleBasic: AppModuleBasic{}, accountKeeper: accountKeeper, @@ -139,7 +139,7 @@ func (am AppModule) RegisterServices(cfg module.Configurator) { // InitGenesis performs genesis initialization for the auth module. It returns // no validator updates. -func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONMarshaler, data json.RawMessage) []abci.ValidatorUpdate { +func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONCodec, data json.RawMessage) []abci.ValidatorUpdate { var genesisState types.GenesisState cdc.MustUnmarshalJSON(data, &genesisState) InitGenesis(ctx, am.accountKeeper, genesisState) @@ -148,7 +148,7 @@ func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONMarshaler, data j // ExportGenesis returns the exported genesis state as raw bytes for the auth // module. -func (am AppModule) ExportGenesis(ctx sdk.Context, cdc codec.JSONMarshaler) json.RawMessage { +func (am AppModule) ExportGenesis(ctx sdk.Context, cdc codec.JSONCodec) json.RawMessage { gs := ExportGenesis(ctx, am.accountKeeper) return cdc.MustMarshalJSON(gs) } @@ -165,8 +165,6 @@ func (AppModule) EndBlock(_ sdk.Context, _ abci.RequestEndBlock) []abci.Validato return []abci.ValidatorUpdate{} } -// ____________________________________________________________________________ - // AppModuleSimulation functions // GenerateGenesisState creates a randomized GenState of the auth module diff --git a/x/auth/signing/sig_verifiable_tx.go b/x/auth/signing/sig_verifiable_tx.go index f2efd4ed48..5904731773 100644 --- a/x/auth/signing/sig_verifiable_tx.go +++ b/x/auth/signing/sig_verifiable_tx.go @@ -11,7 +11,7 @@ import ( type SigVerifiableTx interface { types.Tx GetSigners() []types.AccAddress - GetPubKeys() []cryptotypes.PubKey // If signer already has pubkey in context, this list will have nil in its place + GetPubKeys() ([]cryptotypes.PubKey, error) // If signer already has pubkey in context, this list will have nil in its place GetSignaturesV2() ([]signing.SignatureV2, error) } diff --git a/x/auth/signing/verify_test.go b/x/auth/signing/verify_test.go index 53f4964090..ca01f64181 100644 --- a/x/auth/signing/verify_test.go +++ b/x/auth/signing/verify_test.go @@ -40,9 +40,9 @@ func TestVerifySignature(t *testing.T) { _ = app.AccountKeeper.NewAccountWithAddress(ctx, addr1) app.AccountKeeper.SetAccount(ctx, acc1) balances := sdk.NewCoins(sdk.NewInt64Coin("atom", 200)) - require.NoError(t, app.BankKeeper.SetBalances(ctx, addr, balances)) + require.NoError(t, simapp.FundAccount(app, ctx, addr, balances)) acc, err := ante.GetSignerAcc(ctx, app.AccountKeeper, addr) - require.NoError(t, app.BankKeeper.SetBalances(ctx, addr, balances)) + require.NoError(t, simapp.FundAccount(app, ctx, addr, balances)) msgs := []sdk.Msg{testdata.NewTestMsg(addr)} fee := legacytx.NewStdFee(50000, sdk.Coins{sdk.NewInt64Coin("atom", 150)}) diff --git a/x/auth/simulation/decoder.go b/x/auth/simulation/decoder.go index 89c3bc702b..c66e5c9029 100644 --- a/x/auth/simulation/decoder.go +++ b/x/auth/simulation/decoder.go @@ -13,7 +13,7 @@ import ( type AuthUnmarshaler interface { UnmarshalAccount([]byte) (types.AccountI, error) - GetCodec() codec.BinaryMarshaler + GetCodec() codec.BinaryCodec } // NewDecodeStore returns a decoder function closure that unmarshals the KVPair's @@ -36,8 +36,8 @@ func NewDecodeStore(ak AuthUnmarshaler) func(kvA, kvB kv.Pair) string { case bytes.Equal(kvA.Key, types.GlobalAccountNumberKey): var globalAccNumberA, globalAccNumberB gogotypes.UInt64Value - ak.GetCodec().MustUnmarshalBinaryBare(kvA.Value, &globalAccNumberA) - ak.GetCodec().MustUnmarshalBinaryBare(kvB.Value, &globalAccNumberB) + ak.GetCodec().MustUnmarshal(kvA.Value, &globalAccNumberA) + ak.GetCodec().MustUnmarshal(kvB.Value, &globalAccNumberB) return fmt.Sprintf("GlobalAccNumberA: %d\nGlobalAccNumberB: %d", globalAccNumberA, globalAccNumberB) diff --git a/x/auth/simulation/decoder_test.go b/x/auth/simulation/decoder_test.go index 823fc0ffb9..d2080abac3 100644 --- a/x/auth/simulation/decoder_test.go +++ b/x/auth/simulation/decoder_test.go @@ -22,7 +22,7 @@ var ( func TestDecodeStore(t *testing.T) { app := simapp.Setup(false) - cdc, _ := simapp.MakeCodecs() + cdc := simapp.MakeTestEncodingConfig().Marshaler acc := types.NewBaseAccountWithAddress(delAddr1) dec := simulation.NewDecodeStore(app.AccountKeeper) @@ -39,7 +39,7 @@ func TestDecodeStore(t *testing.T) { }, { Key: types.GlobalAccountNumberKey, - Value: cdc.MustMarshalBinaryBare(&globalAccNumber), + Value: cdc.MustMarshal(&globalAccNumber), }, { Key: []byte{0x99}, diff --git a/x/auth/spec/01_concepts.md b/x/auth/spec/01_concepts.md index 9f8c9b8d8f..e028ebe8e9 100644 --- a/x/auth/spec/01_concepts.md +++ b/x/auth/spec/01_concepts.md @@ -4,6 +4,13 @@ order: 1 # Concepts +**Note:** The auth module is different from the [authz module](../modules/authz/). + +The differences are: + +* `auth` - authentication of accounts and transactions for Cosmos SDK applications and is responsible for specifying the base transaction and account types. +* `authz` - authorization for accounts to perform actions on behalf of other accounts and enables a granter to grant authorizations to a grantee that allows the grantee to execute messages on behalf of the granter. + ## Gas & Fees Fees serve two purposes for an operator of the network. diff --git a/x/auth/spec/03_antehandlers.md b/x/auth/spec/03_antehandlers.md index 709cae3789..851005162d 100644 --- a/x/auth/spec/03_antehandlers.md +++ b/x/auth/spec/03_antehandlers.md @@ -2,43 +2,39 @@ order: 3 --> -# AnthHandlers - -## Handlers - -The auth module presently has no transaction handlers of its own, but does expose -the special `AnteHandler`, used for performing basic validity checks on a transaction, -such that it could be thrown out of the mempool. Note that the ante handler is called on -`CheckTx`, but _also_ on `DeliverTx`, as Tendermint proposers presently have the ability -to include in their proposed block transactions which fail `CheckTx`. - -### Ante Handler - -```go -anteHandler(ak AccountKeeper, fck FeeCollectionKeeper, tx sdk.Tx) - if !tx.(StdTx) - fail with "not a StdTx" - - if isCheckTx and tx.Fee < config.SubjectiveMinimumFee - fail with "insufficient fee for mempool inclusion" - - if tx.ValidateBasic() != nil - fail with "tx failed ValidateBasic" - - if tx.Fee > 0 - account = GetAccount(tx.GetSigners()[0]) - coins := acount.GetCoins() - if coins < tx.Fee - fail with "insufficient fee to pay for transaction" - account.SetCoins(coins - tx.Fee) - fck.AddCollectedFees(tx.Fee) - - for index, signature in tx.GetSignatures() - account = GetAccount(tx.GetSigners()[index]) - bytesToSign := StdSignBytes(chainID, acc.GetAccountNumber(), - acc.GetSequence(), tx.Fee, tx.Msgs, tx.Memo) - if !signature.Verify(bytesToSign) - fail with "invalid signature" - - return -``` +# AnteHandlers + +The `x/auth` module presently has no transaction handlers of its own, but does expose the special `AnteHandler`, used for performing basic validity checks on a transaction, such that it could be thrown out of the mempool. +The `AnteHandler` can be seen as a set of decorators that check transactions within the current context, per [ADR 010](https://github.com/cosmos/cosmos-sdk/blob/v0.43.0-alpha1/docs/architecture/adr-010-modular-antehandler.md). + +Note that the `AnteHandler` is called on both `CheckTx` and `DeliverTx`, as Tendermint proposers presently have the ability to include in their proposed block transactions which fail `CheckTx`. + +## Decorators + +The auth module provides `AnteDecorator`s that are recursively chained together into a single `AnteHandler` in the following order: + +- `SetUpContextDecorator`: Sets the `GasMeter` in the `Context` and wraps the next `AnteHandler` with a defer clause to recover from any downstream `OutOfGas` panics in the `AnteHandler` chain to return an error with information on gas provided and gas used. + +- `RejectExtensionOptionsDecorator`: Rejects all extension options which can optionally be included in protobuf transactions. + +- `MempoolFeeDecorator`: Checks if the `tx` fee is above local mempool `minFee` parameter during `CheckTx`. + +- `ValidateBasicDecorator`: Calls `tx.ValidateBasic` and returns any non-nil error. + +- `TxTimeoutHeightDecorator`: Check for a `tx` height timeout. + +- `ValidateMemoDecorator`: Validates `tx` memo with application parameters and returns any non-nil error. + +- `ConsumeGasTxSizeDecorator`: Consumes gas proportional to the `tx` size based on application parameters. + +- `DeductFeeDecorator`: Deducts the `FeeAmount` from first signer of the `tx`. If the `x/feegrant` module is enabled and a fee granter is set, it will deduct fees from the fee granter account. + +- `SetPubKeyDecorator`: Sets the pubkey from a `tx`'s signers that does not already have its corresponding pubkey saved in the state machine and in the current context. + +- `ValidateSigCountDecorator`: Validates the number of signatures in `tx` based on app-parameters. + +- `SigGasConsumeDecorator`: Consumes parameter-defined amount of gas for each signature. This requires pubkeys to be set in context for all signers as part of `SetPubKeyDecorator`. + +- `SigVerificationDecorator`: Verifies all signatures are valid. This requires pubkeys to be set in context for all signers as part of `SetPubKeyDecorator`. + +- `IncrementSequenceDecorator`: Increments the account sequence for each signer to prevent replay attacks. diff --git a/x/auth/spec/04_keepers.md b/x/auth/spec/04_keepers.md index f57988b4fa..fcd9954475 100644 --- a/x/auth/spec/04_keepers.md +++ b/x/auth/spec/04_keepers.md @@ -20,6 +20,9 @@ type AccountKeeperI interface { // Return a new account with the next account number. Does not save the new account to the store. NewAccount(sdk.Context, types.AccountI) types.AccountI + // Check if an account exists in the store. + HasAccount(sdk.Context, sdk.AccAddress) bool + // Retrieve an account from the store. GetAccount(sdk.Context, sdk.AccAddress) types.AccountI @@ -29,7 +32,7 @@ type AccountKeeperI interface { // Remove an account from the store. RemoveAccount(sdk.Context, types.AccountI) - // Iterate over all accounts, calling the provided function. Stop iteraiton when it returns false. + // Iterate over all accounts, calling the provided function. Stop iteration when it returns true. IterateAccounts(sdk.Context, func(types.AccountI) bool) // Fetch the public key of an account at a specified address diff --git a/x/auth/spec/05_vesting.md b/x/auth/spec/05_vesting.md index d5e0daecba..7519cb2f24 100644 --- a/x/auth/spec/05_vesting.md +++ b/x/auth/spec/05_vesting.md @@ -5,27 +5,27 @@ order: 6 # Vesting - [Vesting](#vesting) - - [Intro and Requirements](#intro-and-requirements) - - [Note](#note) - - [Vesting Account Types](#vesting-account-types) - - [Vesting Account Specification](#vesting-account-specification) - - [Determining Vesting & Vested Amounts](#determining-vesting--vested-amounts) - - [Continuously Vesting Accounts](#continuously-vesting-accounts) - - [Periodic Vesting Accounts](#periodic-vesting-accounts) - - [Delayed/Discrete Vesting Accounts](#delayeddiscrete-vesting-accounts) - - [Transferring/Sending](#transferringsending) - - [Keepers/Handlers](#keepershandlers) - - [Delegating](#delegating) - - [Keepers/Handlers](#keepershandlers-1) - - [Undelegating](#undelegating) - - [Keepers/Handlers](#keepershandlers-2) - - [Keepers & Handlers](#keepers--handlers) - - [Genesis Initialization](#genesis-initialization) - - [Examples](#examples) - - [Simple](#simple) - - [Slashing](#slashing) - - [Periodic Vesting](#periodic-vesting) - - [Glossary](#glossary) + - [Intro and Requirements](#intro-and-requirements) + - [Note](#note) + - [Vesting Account Types](#vesting-account-types) + - [Vesting Account Specification](#vesting-account-specification) + - [Determining Vesting & Vested Amounts](#determining-vesting--vested-amounts) + - [Continuously Vesting Accounts](#continuously-vesting-accounts) + - [Periodic Vesting Accounts](#periodic-vesting-accounts) + - [Delayed/Discrete Vesting Accounts](#delayeddiscrete-vesting-accounts) + - [Transferring/Sending](#transferringsending) + - [Keepers/Handlers](#keepershandlers) + - [Delegating](#delegating) + - [Keepers/Handlers](#keepershandlers-1) + - [Undelegating](#undelegating) + - [Keepers/Handlers](#keepershandlers-2) + - [Keepers & Handlers](#keepers--handlers) + - [Genesis Initialization](#genesis-initialization) + - [Examples](#examples) + - [Simple](#simple) + - [Slashing](#slashing) + - [Periodic Vesting](#periodic-vesting) + - [Glossary](#glossary) ## Intro and Requirements @@ -89,17 +89,22 @@ type VestingAccount interface { GetEndTime() int64 } ``` + ### BaseVestingAccount -+++ https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/vesting/v1/vesting.proto#L10-L33 + ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/vesting/v1beta1/vesting.proto#L10-L33 ### ContinuousVestingAccount -+++ https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/vesting/v1/vesting.proto#L35-L43 + ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/vesting/v1beta1/vesting.proto#L35-L43 ### DelayedVestingAccount -+++ https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/vesting/v1/vesting.proto#L45-L53 + ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/vesting/v1beta1/vesting.proto#L45-L53 ### Period -+++ https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/vesting/v1/vesting.proto#L56-L62 + ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/vesting/v1beta1/vesting.proto#L56-L62 ```go // Stores all vesting periods passed as part of a PeriodicVestingAccount @@ -108,7 +113,8 @@ type Periods []Period ``` ### PeriodicVestingAccount -+++ https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/vesting/v1/vesting.proto#L64-L73 + ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/vesting/v1beta1/vesting.proto#L64-L73 In order to facilitate less ad-hoc type checking and assertions and to support flexibility in account balance usage, the existing `x/bank` `ViewKeeper` interface @@ -608,3 +614,5 @@ linearly over time. all coins at a given time. - PeriodicVestingAccount: A vesting account implementation that vests coins according to a custom vesting schedule. +- PermanentLockedAccount: It does not ever release coins, locking them indefinitely. +Coins in this account can still be used for delegating and for governance votes even while locked. diff --git a/x/auth/spec/07_client.md b/x/auth/spec/07_client.md new file mode 100644 index 0000000000..bcfdc6f6fa --- /dev/null +++ b/x/auth/spec/07_client.md @@ -0,0 +1,421 @@ + + +# Client + +# Auth + +## CLI + +A user can query and interact with the `auth` module using the CLI. + +### Query + +The `query` commands allow users to query `auth` state. + +```bash +simd query auth --help +``` + +#### account + +The `account` command allow users to query for an account by it's address. + +```bash +simd query auth account [address] [flags] +``` + +Example: + +```bash +simd query auth account cosmos1... +``` + +Example Output: + +```bash +'@type': /cosmos.auth.v1beta1.BaseAccount +account_number: "0" +address: cosmos1zwg6tpl8aw4rawv8sgag9086lpw5hv33u5ctr2 +pub_key: + '@type': /cosmos.crypto.secp256k1.PubKey + key: ApDrE38zZdd7wLmFS9YmqO684y5DG6fjZ4rVeihF/AQD +sequence: "1" +``` + +#### accounts + +The `accounts` command allow users to query all the available accounts. + +```bash +simd query auth accounts [flags] +``` + +Example: + +```bash +simd query auth accounts +``` + +Example Output: + +```bash +accounts: +- '@type': /cosmos.auth.v1beta1.BaseAccount + account_number: "0" + address: cosmos1zwg6tpl8aw4rawv8sgag9086lpw5hv33u5ctr2 + pub_key: + '@type': /cosmos.crypto.secp256k1.PubKey + key: ApDrE38zZdd7wLmFS9YmqO684y5DG6fjZ4rVeihF/AQD + sequence: "1" +- '@type': /cosmos.auth.v1beta1.ModuleAccount + base_account: + account_number: "8" + address: cosmos1yl6hdjhmkf37639730gffanpzndzdpmhwlkfhr + pub_key: null + sequence: "0" + name: transfer + permissions: + - minter + - burner +- '@type': /cosmos.auth.v1beta1.ModuleAccount + base_account: + account_number: "4" + address: cosmos1fl48vsnmsdzcv85q5d2q4z5ajdha8yu34mf0eh + pub_key: null + sequence: "0" + name: bonded_tokens_pool + permissions: + - burner + - staking +- '@type': /cosmos.auth.v1beta1.ModuleAccount + base_account: + account_number: "5" + address: cosmos1tygms3xhhs3yv487phx3dw4a95jn7t7lpm470r + pub_key: null + sequence: "0" + name: not_bonded_tokens_pool + permissions: + - burner + - staking +- '@type': /cosmos.auth.v1beta1.ModuleAccount + base_account: + account_number: "6" + address: cosmos10d07y265gmmuvt4z0w9aw880jnsr700j6zn9kn + pub_key: null + sequence: "0" + name: gov + permissions: + - burner +- '@type': /cosmos.auth.v1beta1.ModuleAccount + base_account: + account_number: "3" + address: cosmos1jv65s3grqf6v6jl3dp4t6c9t9rk99cd88lyufl + pub_key: null + sequence: "0" + name: distribution + permissions: [] +- '@type': /cosmos.auth.v1beta1.BaseAccount + account_number: "1" + address: cosmos147k3r7v2tvwqhcmaxcfql7j8rmkrlsemxshd3j + pub_key: null + sequence: "0" +- '@type': /cosmos.auth.v1beta1.ModuleAccount + base_account: + account_number: "7" + address: cosmos1m3h30wlvsf8llruxtpukdvsy0km2kum8g38c8q + pub_key: null + sequence: "0" + name: mint + permissions: + - minter +- '@type': /cosmos.auth.v1beta1.ModuleAccount + base_account: + account_number: "2" + address: cosmos17xpfvakm2amg962yls6f84z3kell8c5lserqta + pub_key: null + sequence: "0" + name: fee_collector + permissions: [] +pagination: + next_key: null + total: "0" +``` + +#### params + +The `params` command allow users to query the current auth parameters. + +```bash +simd query auth params [flags] +``` + +Example: + +```bash +simd query auth params +``` + +Example Output: + +```bash +max_memo_characters: "256" +sig_verify_cost_ed25519: "590" +sig_verify_cost_secp256k1: "1000" +tx_sig_limit: "7" +tx_size_cost_per_byte: "10" +``` + +## gRPC + +A user can query the `auth` module using gRPC endpoints. + +### Account + +The `account` endpoint allow users to query for an account by it's address. + +```bash +cosmos.auth.v1beta1.Query/Account +``` + +Example: + +```bash +grpcurl -plaintext \ + -d '{"address":"cosmos1.."}' \ + localhost:9090 \ + cosmos.auth.v1beta1.Query/Account +``` + +Example Output: + +```bash +{ + "account":{ + "@type":"/cosmos.auth.v1beta1.BaseAccount", + "address":"cosmos1zwg6tpl8aw4rawv8sgag9086lpw5hv33u5ctr2", + "pubKey":{ + "@type":"/cosmos.crypto.secp256k1.PubKey", + "key":"ApDrE38zZdd7wLmFS9YmqO684y5DG6fjZ4rVeihF/AQD" + }, + "sequence":"1" + } +} +``` + +### Accounts + +The `accounts` endpoint allow users to query all the available accounts. + +```bash +cosmos.auth.v1beta1.Query/Accounts +``` + +Example: + +```bash +grpcurl -plaintext \ + localhost:9090 \ + cosmos.auth.v1beta1.Query/Accounts +``` + +Example Output: + +```bash +{ + "accounts":[ + { + "@type":"/cosmos.auth.v1beta1.BaseAccount", + "address":"cosmos1zwg6tpl8aw4rawv8sgag9086lpw5hv33u5ctr2", + "pubKey":{ + "@type":"/cosmos.crypto.secp256k1.PubKey", + "key":"ApDrE38zZdd7wLmFS9YmqO684y5DG6fjZ4rVeihF/AQD" + }, + "sequence":"1" + }, + { + "@type":"/cosmos.auth.v1beta1.ModuleAccount", + "baseAccount":{ + "address":"cosmos1yl6hdjhmkf37639730gffanpzndzdpmhwlkfhr", + "accountNumber":"8" + }, + "name":"transfer", + "permissions":[ + "minter", + "burner" + ] + }, + { + "@type":"/cosmos.auth.v1beta1.ModuleAccount", + "baseAccount":{ + "address":"cosmos1fl48vsnmsdzcv85q5d2q4z5ajdha8yu34mf0eh", + "accountNumber":"4" + }, + "name":"bonded_tokens_pool", + "permissions":[ + "burner", + "staking" + ] + }, + { + "@type":"/cosmos.auth.v1beta1.ModuleAccount", + "baseAccount":{ + "address":"cosmos1tygms3xhhs3yv487phx3dw4a95jn7t7lpm470r", + "accountNumber":"5" + }, + "name":"not_bonded_tokens_pool", + "permissions":[ + "burner", + "staking" + ] + }, + { + "@type":"/cosmos.auth.v1beta1.ModuleAccount", + "baseAccount":{ + "address":"cosmos10d07y265gmmuvt4z0w9aw880jnsr700j6zn9kn", + "accountNumber":"6" + }, + "name":"gov", + "permissions":[ + "burner" + ] + }, + { + "@type":"/cosmos.auth.v1beta1.ModuleAccount", + "baseAccount":{ + "address":"cosmos1jv65s3grqf6v6jl3dp4t6c9t9rk99cd88lyufl", + "accountNumber":"3" + }, + "name":"distribution" + }, + { + "@type":"/cosmos.auth.v1beta1.BaseAccount", + "accountNumber":"1", + "address":"cosmos147k3r7v2tvwqhcmaxcfql7j8rmkrlsemxshd3j" + }, + { + "@type":"/cosmos.auth.v1beta1.ModuleAccount", + "baseAccount":{ + "address":"cosmos1m3h30wlvsf8llruxtpukdvsy0km2kum8g38c8q", + "accountNumber":"7" + }, + "name":"mint", + "permissions":[ + "minter" + ] + }, + { + "@type":"/cosmos.auth.v1beta1.ModuleAccount", + "baseAccount":{ + "address":"cosmos17xpfvakm2amg962yls6f84z3kell8c5lserqta", + "accountNumber":"2" + }, + "name":"fee_collector" + } + ], + "pagination":{ + "total":"9" + } +} +``` + +### Params + +The `params` endpoint allow users to query the current auth parameters. + +```bash +cosmos.auth.v1beta1.Query/Params +``` + +Example: + +```bash +grpcurl -plaintext \ + localhost:9090 \ + cosmos.auth.v1beta1.Query/Params +``` + +Example Output: + +```bash +{ + "params": { + "maxMemoCharacters": "256", + "txSigLimit": "7", + "txSizeCostPerByte": "10", + "sigVerifyCostEd25519": "590", + "sigVerifyCostSecp256k1": "1000" + } +} +``` + +## REST + +A user can query the `auth` module using REST endpoints. + +### Account + +The `account` endpoint allow users to query for an account by it's address. + +```bash +/cosmos/auth/v1beta1/account?address={address} +``` + +### Accounts + +The `accounts` endpoint allow users to query all the available accounts. + +```bash +/cosmos/auth/v1beta1/accounts +``` + +### Params + +The `params` endpoint allow users to query the current auth parameters. + +```bash +/cosmos/auth/v1beta1/params +``` + +# Vesting + +## CLI + +A user can query and interact with the `vesting` module using the CLI. + +### Transactions + +The `tx` commands allow users to interact with the `vesting` module. + +```bash +simd tx vesting --help +``` + +#### create-periodic-vesting-account + +The `create-periodic-vesting-account` command creates a new vesting account funded with an allocation of tokens, where a sequence of coins and period length in seconds. Periods are sequential, in that the duration of of a period only starts at the end of the previous period. The duration of the first period starts upon account creation. + +```bash +simd tx vesting create-periodic-vesting-account [to_address] [periods_json_file] [flags] +``` + +Example: + +```bash +simd tx vesting create-periodic-vesting-account cosmos1.. periods.json +``` + +#### create-vesting-account + +The `create-vesting-account` command creates a new vesting account funded with an allocation of tokens. The account can either be a delayed or continuous vesting account, which is determined by the '--delayed' flag. All vesting accouts created will have their start time set by the committed block's time. The end_time must be provided as a UNIX epoch timestamp. + +```bash +simd tx vesting create-vesting-account [to_address] [amount] [end_time] [flags] +``` + +Example: + +```bash +simd tx vesting create-vesting-account cosmos1.. 100stake 2592000 +``` diff --git a/x/auth/testutil/suite.go b/x/auth/testutil/suite.go index 03b4ad335a..a15a81cde8 100644 --- a/x/auth/testutil/suite.go +++ b/x/auth/testutil/suite.go @@ -15,8 +15,7 @@ import ( "github.com/line/lbm-sdk/x/auth/signing" ) -// TxConfigTestSuite provides a test suite that can be used to test that a TxConfig implementation is correct -// type name will be used as tx.TxConfigTestSuite by other packages, and that stutters; consider calling this GeneratorTestSuite +// TxConfigTestSuite provides a test suite that can be used to test that a TxConfig implementation is correct. type TxConfigTestSuite struct { suite.Suite TxConfig client.TxConfig @@ -200,16 +199,7 @@ func sigDataEquals(data1, data2 signingtypes.SignatureData) bool { if !ok { return false } - - if data1.BitArray.ExtraBitsStored != data2.BitArray.ExtraBitsStored { - return false - } - - if !bytes.Equal(data1.BitArray.Elems, data2.BitArray.Elems) { - return false - } - - if len(data1.Signatures) != len(data2.Signatures) { + if !data1.BitArray.Equal(data2.BitArray) || len(data1.Signatures) != len(data2.Signatures) { return false } @@ -268,7 +258,9 @@ func (s *TxConfigTestSuite) TestTxEncodeDecode() { tx3Sigs, err := tx3.GetSignaturesV2() s.Require().NoError(err) s.Require().Equal([]signingtypes.SignatureV2{sig}, tx3Sigs) - s.Require().Equal([]cryptotypes.PubKey{pubkey}, tx3.GetPubKeys()) + pks, err := tx3.GetPubKeys() + s.Require().NoError(err) + s.Require().Equal([]cryptotypes.PubKey{pubkey}, pks) log("JSON encode transaction") jsonTxBytes, err := s.TxConfig.TxJSONEncoder()(tx) @@ -287,7 +279,9 @@ func (s *TxConfigTestSuite) TestTxEncodeDecode() { tx3Sigs, err = tx3.GetSignaturesV2() s.Require().NoError(err) s.Require().Equal([]signingtypes.SignatureV2{sig}, tx3Sigs) - s.Require().Equal([]cryptotypes.PubKey{pubkey}, tx3.GetPubKeys()) + pks, err = tx3.GetPubKeys() + s.Require().NoError(err) + s.Require().Equal([]cryptotypes.PubKey{pubkey}, pks) } func (s *TxConfigTestSuite) TestWrapTxBuilder() { diff --git a/x/auth/tx/builder.go b/x/auth/tx/builder.go index 2efc752e83..fc7296f558 100644 --- a/x/auth/tx/builder.go +++ b/x/auth/tx/builder.go @@ -7,6 +7,7 @@ import ( codectypes "github.com/line/lbm-sdk/codec/types" cryptotypes "github.com/line/lbm-sdk/crypto/types" sdk "github.com/line/lbm-sdk/types" + sdkerrors "github.com/line/lbm-sdk/types/errors" "github.com/line/lbm-sdk/types/tx" "github.com/line/lbm-sdk/types/tx/signing" "github.com/line/lbm-sdk/x/auth/ante" @@ -34,7 +35,6 @@ var ( _ client.TxBuilder = &wrapper{} _ ante.HasExtensionOptionsTx = &wrapper{} _ ExtensionOptionsTxBuilder = &wrapper{} - _ ProtoTxProvider = &wrapper{} ) // ExtensionOptionsTxBuilder defines a TxBuilder that can also set extensions. @@ -100,7 +100,7 @@ func (w *wrapper) GetSigners() []sdk.AccAddress { return w.tx.GetSigners() } -func (w *wrapper) GetPubKeys() []cryptotypes.PubKey { +func (w *wrapper) GetPubKeys() ([]cryptotypes.PubKey, error) { signerInfos := w.tx.AuthInfo.SignerInfos pks := make([]cryptotypes.PubKey, len(signerInfos)) @@ -111,13 +111,16 @@ func (w *wrapper) GetPubKeys() []cryptotypes.PubKey { continue } - pk, ok := si.PublicKey.GetCachedValue().(cryptotypes.PubKey) + pkAny := si.PublicKey.GetCachedValue() + pk, ok := pkAny.(cryptotypes.PubKey) if ok { pks[i] = pk + } else { + return nil, sdkerrors.Wrapf(sdkerrors.ErrLogic, "Expecting PubKey, got: %T", pkAny) } } - return pks + return pks, nil } func (w *wrapper) GetGas() uint64 { @@ -157,7 +160,10 @@ func (w *wrapper) GetTimeoutHeight() uint64 { func (w *wrapper) GetSignaturesV2() ([]signing.SignatureV2, error) { signerInfos := w.tx.AuthInfo.SignerInfos sigs := w.tx.Signatures - pubKeys := w.GetPubKeys() + pubKeys, err := w.GetPubKeys() + if err != nil { + return nil, err + } n := len(signerInfos) res := make([]signing.SignatureV2, n) @@ -190,12 +196,7 @@ func (w *wrapper) SetMsgs(msgs ...sdk.Msg) error { for i, msg := range msgs { var err error - switch msg := msg.(type) { - case sdk.ServiceMsg: - anys[i], err = codectypes.NewAnyWithCustomTypeURL(msg.Request, msg.MethodName) - default: - anys[i], err = codectypes.NewAnyWithValue(msg) - } + anys[i], err = codectypes.NewAnyWithValue(msg) if err != nil { return err } @@ -341,8 +342,3 @@ func (w *wrapper) SetNonCriticalExtensionOptions(extOpts ...*codectypes.Any) { w.tx.Body.NonCriticalExtensionOptions = extOpts w.bodyBz = nil } - -// ProtoTxProvider is a type which can provide a proto transaction. -type ProtoTxProvider interface { - GetProtoTx() *tx.Tx -} diff --git a/x/auth/tx/builder_test.go b/x/auth/tx/builder_test.go index 7532a0ff47..aa957c8a66 100644 --- a/x/auth/tx/builder_test.go +++ b/x/auth/tx/builder_test.go @@ -40,12 +40,11 @@ func TestTxBuilder(t *testing.T) { Sequence: accSeq, }) - var sig signing.SignatureV2 - sig = signing.SignatureV2{ + var sig signing.SignatureV2 = signing.SignatureV2{ PubKey: pubkey, Data: &signing.SingleSignatureData{ SignMode: signing.SignMode_SIGN_MODE_DIRECT, - Signature: legacy.Cdc.MustMarshalBinaryBare(pubkey), + Signature: legacy.Cdc.MustMarshal(pubkey), }, Sequence: accSeq, } @@ -58,7 +57,7 @@ func TestTxBuilder(t *testing.T) { SignerInfos: signerInfo, } - authInfoBytes := marshaler.MustMarshalBinaryBare(authInfo) + authInfoBytes := marshaler.MustMarshal(authInfo) require.NotEmpty(t, authInfoBytes) @@ -77,7 +76,7 @@ func TestTxBuilder(t *testing.T) { Memo: memo, Messages: anys, } - bodyBytes := marshaler.MustMarshalBinaryBare(txBody) + bodyBytes := marshaler.MustMarshal(txBody) require.NotEmpty(t, bodyBytes) require.Empty(t, txBuilder.getBodyBytes()) @@ -89,7 +88,9 @@ func TestTxBuilder(t *testing.T) { txBuilder.SetMemo(memo) require.Equal(t, bodyBytes, txBuilder.getBodyBytes()) require.Equal(t, len(msgs), len(txBuilder.GetMsgs())) - require.Equal(t, 0, len(txBuilder.GetPubKeys())) + pks, err := txBuilder.GetPubKeys() + require.NoError(t, err) + require.Empty(t, pks) t.Log("verify that updated AuthInfo results in the correct getAuthInfoBytes and GetPubKeys") require.NotEqual(t, authInfoBytes, txBuilder.getAuthInfoBytes()) @@ -104,8 +105,10 @@ func TestTxBuilder(t *testing.T) { require.Equal(t, authInfoBytes, txBuilder.getAuthInfoBytes()) require.Equal(t, len(msgs), len(txBuilder.GetMsgs())) - require.Equal(t, 1, len(txBuilder.GetPubKeys())) - require.Equal(t, legacy.Cdc.MustMarshalBinaryBare(pubkey), legacy.Cdc.MustMarshalBinaryBare(txBuilder.GetPubKeys()[0])) + pks, err = txBuilder.GetPubKeys() + require.NoError(t, err) + require.Equal(t, 1, len(pks)) + require.True(t, pubkey.Equals(pks[0])) any, err = codectypes.NewAnyWithValue(testdata.NewTestMsg()) require.NoError(t, err) @@ -140,7 +143,7 @@ func TestBuilderValidateBasic(t *testing.T) { PubKey: pubKey1, Data: &signing.SingleSignatureData{ SignMode: signing.SignMode_SIGN_MODE_DIRECT, - Signature: legacy.Cdc.MustMarshalBinaryBare(pubKey1), + Signature: legacy.Cdc.MustMarshal(pubKey1), }, Sequence: 0, // Arbitrary account sequence } @@ -149,7 +152,7 @@ func TestBuilderValidateBasic(t *testing.T) { PubKey: pubKey2, Data: &signing.SingleSignatureData{ SignMode: signing.SignMode_SIGN_MODE_DIRECT, - Signature: legacy.Cdc.MustMarshalBinaryBare(pubKey2), + Signature: legacy.Cdc.MustMarshal(pubKey2), }, Sequence: 0, // Arbitrary account sequence } diff --git a/x/auth/tx/decoder.go b/x/auth/tx/decoder.go index 13cbb2955c..7b8b39f321 100644 --- a/x/auth/tx/decoder.go +++ b/x/auth/tx/decoder.go @@ -1,6 +1,10 @@ package tx import ( + "fmt" + + "google.golang.org/protobuf/encoding/protowire" + "github.com/line/lbm-sdk/codec" "github.com/line/lbm-sdk/codec/unknownproto" sdk "github.com/line/lbm-sdk/types" @@ -11,15 +15,21 @@ import ( // DefaultTxDecoder returns a default protobuf TxDecoder using the provided Marshaler. func DefaultTxDecoder(cdc codec.ProtoCodecMarshaler) sdk.TxDecoder { return func(txBytes []byte) (sdk.Tx, error) { + // Make sure txBytes follow ADR-027. + err := rejectNonADR027TxRaw(txBytes) + if err != nil { + return nil, sdkerrors.Wrap(sdkerrors.ErrTxDecode, err.Error()) + } + var raw tx.TxRaw // reject all unknown proto fields in the root TxRaw - err := unknownproto.RejectUnknownFieldsStrict(txBytes, &raw, cdc.InterfaceRegistry()) + err = unknownproto.RejectUnknownFieldsStrict(txBytes, &raw, cdc.InterfaceRegistry()) if err != nil { return nil, sdkerrors.Wrap(sdkerrors.ErrTxDecode, err.Error()) } - err = cdc.UnmarshalBinaryBare(txBytes, &raw) + err = cdc.Unmarshal(txBytes, &raw) if err != nil { return nil, err } @@ -32,7 +42,7 @@ func DefaultTxDecoder(cdc codec.ProtoCodecMarshaler) sdk.TxDecoder { return nil, sdkerrors.Wrap(sdkerrors.ErrTxDecode, err.Error()) } - err = cdc.UnmarshalBinaryBare(raw.BodyBytes, &body) + err = cdc.Unmarshal(raw.BodyBytes, &body) if err != nil { return nil, sdkerrors.Wrap(sdkerrors.ErrTxDecode, err.Error()) } @@ -45,7 +55,7 @@ func DefaultTxDecoder(cdc codec.ProtoCodecMarshaler) sdk.TxDecoder { return nil, sdkerrors.Wrap(sdkerrors.ErrTxDecode, err.Error()) } - err = cdc.UnmarshalBinaryBare(raw.AuthInfoBytes, &authInfo) + err = cdc.Unmarshal(raw.AuthInfoBytes, &authInfo) if err != nil { return nil, sdkerrors.Wrap(sdkerrors.ErrTxDecode, err.Error()) } @@ -79,3 +89,82 @@ func DefaultJSONTxDecoder(cdc codec.ProtoCodecMarshaler) sdk.TxDecoder { }, nil } } + +// rejectNonADR027TxRaw rejects txBytes that do not follow ADR-027. This is NOT +// a generic ADR-027 checker, it only applies decoding TxRaw. Specifically, it +// only checks that: +// - field numbers are in ascending order (1, 2, and potentially multiple 3s), +// - and varints are as short as possible. +// All other ADR-027 edge cases (e.g. default values) are not applicable with +// TxRaw. +func rejectNonADR027TxRaw(txBytes []byte) error { + // Make sure all fields are ordered in ascending order with this variable. + prevTagNum := protowire.Number(0) + + for len(txBytes) > 0 { + tagNum, wireType, m := protowire.ConsumeTag(txBytes) + if m < 0 { + return fmt.Errorf("invalid length; %w", protowire.ParseError(m)) + } + // TxRaw only has bytes fields. + if wireType != protowire.BytesType { + return fmt.Errorf("expected %d wire type, got %d", protowire.BytesType, wireType) + } + // Make sure fields are ordered in ascending order. + if tagNum < prevTagNum { + return fmt.Errorf("txRaw must follow ADR-027, got tagNum %d after tagNum %d", tagNum, prevTagNum) + } + prevTagNum = tagNum + + // All 3 fields of TxRaw have wireType == 2, so their next component + // is a varint, so we can safely call ConsumeVarint here. + // Byte structure: + // Inner fields are verified in `DefaultTxDecoder` + lengthPrefix, m := protowire.ConsumeVarint(txBytes[m:]) + if m < 0 { + return fmt.Errorf("invalid length; %w", protowire.ParseError(m)) + } + // We make sure that this varint is as short as possible. + n := varintMinLength(lengthPrefix) + if n != m { + return fmt.Errorf("length prefix varint for tagNum %d is not as short as possible, read %d, only need %d", tagNum, m, n) + } + + // Skip over the bytes that store fieldNumber and wireType bytes. + _, _, m = protowire.ConsumeField(txBytes) + if m < 0 { + return fmt.Errorf("invalid length; %w", protowire.ParseError(m)) + } + txBytes = txBytes[m:] + } + + return nil +} + +// varintMinLength returns the minimum number of bytes necessary to encode an +// uint using varint encoding. +func varintMinLength(n uint64) int { + switch { + // Note: 1< 0) // Gas used sometimes change, just check it's not empty. } }) @@ -120,6 +135,9 @@ func (s IntegrationTestSuite) TestSimulateTx_GRPCGateway() { // Convert the txBuilder to a tx.Tx. protoTx, err := txBuilderToProtoTx(txBuilder) s.Require().NoError(err) + // Encode the txBuilder to txBytes. + txBytes, err := val.ClientCtx.TxConfig.TxEncoder()(txBuilder.GetTx()) + s.Require().NoError(err) testCases := []struct { name string @@ -127,13 +145,14 @@ func (s IntegrationTestSuite) TestSimulateTx_GRPCGateway() { expErr bool expErrMsg string }{ - {"empty request", &tx.SimulateRequest{}, true, "invalid empty tx"}, - {"valid request", &tx.SimulateRequest{Tx: protoTx}, false, ""}, + {"empty request", &tx.SimulateRequest{}, true, "empty txBytes is not allowed"}, + {"valid request with proto tx (deprecated)", &tx.SimulateRequest{Tx: protoTx}, false, ""}, + {"valid request with tx_bytes", &tx.SimulateRequest{TxBytes: txBytes}, false, ""}, } for _, tc := range testCases { s.Run(tc.name, func() { - req, err := val.ClientCtx.JSONMarshaler.MarshalJSON(tc.req) + req, err := val.ClientCtx.Codec.MarshalJSON(tc.req) s.Require().NoError(err) res, err := rest.PostRequest(fmt.Sprintf("%s/lbm/tx/v1/simulate", val.APIAddress), "application/json", req) s.Require().NoError(err) @@ -141,10 +160,10 @@ func (s IntegrationTestSuite) TestSimulateTx_GRPCGateway() { s.Require().Contains(string(res), tc.expErrMsg) } else { var result tx.SimulateResponse - err = val.ClientCtx.JSONMarshaler.UnmarshalJSON(res, &result) + err = val.ClientCtx.Codec.UnmarshalJSON(res, &result) s.Require().NoError(err) // Check the result and gas used are correct. - s.Require().Equal(len(result.GetResult().GetEvents()), 4) // 1 transfer, 3 messages. + s.Require().Equal(len(result.GetResult().GetEvents()), 6) // 1 coin recv, 1 coin spent,1 transfer, 3 messages. s.Require().True(result.GetGasInfo().GetGasUsed() > 0) // Gas used sometimes change, just check it's not empty. } }) @@ -176,7 +195,7 @@ func (s IntegrationTestSuite) TestGetTxEvents_GRPC() { { "request with order-by", &tx.GetTxsEventRequest{ - Events: []string{"message.action='send'"}, + Events: []string{bankMsgSendEventAction}, OrderBy: tx.OrderBy_ORDER_BY_ASC, }, false, "", @@ -184,14 +203,14 @@ func (s IntegrationTestSuite) TestGetTxEvents_GRPC() { { "without pagination", &tx.GetTxsEventRequest{ - Events: []string{"message.action='send'"}, + Events: []string{bankMsgSendEventAction}, }, false, "", }, { "with pagination", &tx.GetTxsEventRequest{ - Events: []string{"message.action='send'"}, + Events: []string{bankMsgSendEventAction}, Pagination: &query.PageRequest{ CountTotal: false, Offset: 0, @@ -203,7 +222,7 @@ func (s IntegrationTestSuite) TestGetTxEvents_GRPC() { { "with multi events", &tx.GetTxsEventRequest{ - Events: []string{"message.action='send'", "message.module='bank'"}, + Events: []string{bankMsgSendEventAction, "message.module='bank'"}, }, false, "", }, @@ -221,8 +240,8 @@ func (s IntegrationTestSuite) TestGetTxEvents_GRPC() { s.Require().Equal("foobar", grpcRes.Txs[0].Body.Memo) // Make sure fields are populated. - // ref: https://github.com/line/lbm-sdk/issues/8680 - // ref: https://github.com/line/lbm-sdk/issues/8681 + // ref: https://github.com/cosmos/cosmos-sdk/issues/8680 + // ref: https://github.com/cosmos/cosmos-sdk/issues/8681 s.Require().NotEmpty(grpcRes.TxResponses[0].Timestamp) s.Require().NotEmpty(grpcRes.TxResponses[0].RawLog) } @@ -246,55 +265,43 @@ func (s IntegrationTestSuite) TestGetTxEvents_GRPCGateway() { }, { "without pagination", - fmt.Sprintf("%s/lbm/tx/v1/txs?events=%s", val.APIAddress, "message.action='send'"), + fmt.Sprintf("%s/lbm/tx/v1/txs?events=%s", val.APIAddress, bankMsgSendEventAction), false, "", }, { "with pagination", - fmt.Sprintf("%s/lbm/tx/v1/txs?events=%s&pagination.offset=%d&pagination.limit=%d", val.APIAddress, "message.action='send'", 0, 10), + fmt.Sprintf("%s/lbm/tx/v1/txs?events=%s&pagination.offset=%d&pagination.limit=%d", val.APIAddress, bankMsgSendEventAction, 0, 10), false, "", }, { "valid request: order by asc", - fmt.Sprintf("%s/lbm/tx/v1/txs?events=%s&events=%s&order_by=ORDER_BY_ASC", val.APIAddress, "message.action='send'", "message.module='bank'"), + fmt.Sprintf("%s/lbm/tx/v1/txs?events=%s&events=%s&order_by=ORDER_BY_ASC", val.APIAddress, bankMsgSendEventAction, "message.module='bank'"), false, "", }, { "valid request: order by desc", - fmt.Sprintf("%s/lbm/tx/v1/txs?events=%s&events=%s&order_by=ORDER_BY_DESC", val.APIAddress, "message.action='send'", "message.module='bank'"), - false, - "", - }, - { - "valid request: order by asc", - fmt.Sprintf("%s/lbm/tx/v1/txs?events=%s&events=%s&order_by=ORDER_BY_ASC", val.APIAddress, "message.action='send'", "message.module='bank'"), - false, - "", - }, - { - "valid request: order by desc", - fmt.Sprintf("%s/lbm/tx/v1/txs?events=%s&events=%s&order_by=ORDER_BY_DESC", val.APIAddress, "message.action='send'", "message.module='bank'"), + fmt.Sprintf("%s/lbm/tx/v1/txs?events=%s&events=%s&order_by=ORDER_BY_DESC", val.APIAddress, bankMsgSendEventAction, "message.module='bank'"), false, "", }, { "invalid request: invalid order by", - fmt.Sprintf("%s/lbm/tx/v1/txs?events=%s&events=%s&order_by=invalid_order", val.APIAddress, "message.action='send'", "message.module='bank'"), + fmt.Sprintf("%s/lbm/tx/v1/txs?events=%s&events=%s&order_by=invalid_order", val.APIAddress, bankMsgSendEventAction, "message.module='bank'"), true, "is not a valid tx.OrderBy", }, { "expect pass with multiple-events", - fmt.Sprintf("%s/lbm/tx/v1/txs?events=%s&events=%s", val.APIAddress, "message.action='send'", "message.module='bank'"), + fmt.Sprintf("%s/lbm/tx/v1/txs?events=%s&events=%s", val.APIAddress, bankMsgSendEventAction, "message.module='bank'"), false, "", }, { "expect pass with escape event", - fmt.Sprintf("%s/lbm/tx/v1/txs?events=%s", val.APIAddress, "message.action%3D'send'"), + fmt.Sprintf("%s/lbm/tx/v1/txs?events=%s", val.APIAddress, "message.action%3D'/lbm.bank.v1.MsgSend'"), false, "", }, @@ -307,7 +314,7 @@ func (s IntegrationTestSuite) TestGetTxEvents_GRPCGateway() { s.Require().Contains(string(res), tc.expErrMsg) } else { var result tx.GetTxsEventResponse - err = val.ClientCtx.JSONMarshaler.UnmarshalJSON(res, &result) + err = val.ClientCtx.Codec.UnmarshalJSON(res, &result) s.Require().NoError(err) s.Require().GreaterOrEqual(len(result.Txs), 1) s.Require().Equal("foobar", result.Txs[0].Body.Memo) @@ -325,8 +332,8 @@ func (s IntegrationTestSuite) TestGetTx_GRPC() { expErrMsg string }{ {"nil request", nil, true, "request cannot be nil"}, - {"empty request", &tx.GetTxRequest{}, true, "transaction hash cannot be empty"}, - {"request with dummy hash", &tx.GetTxRequest{Hash: "deadbeef"}, true, "tx (DEADBEEF) not found"}, + {"empty request", &tx.GetTxRequest{}, true, "tx hash cannot be empty"}, + {"request with dummy hash", &tx.GetTxRequest{Hash: "deadbeef"}, true, "code = NotFound desc = tx not found: deadbeef"}, {"good request", &tx.GetTxRequest{Hash: s.txRes.TxHash}, false, ""}, } for _, tc := range testCases { @@ -355,12 +362,12 @@ func (s IntegrationTestSuite) TestGetTx_GRPCGateway() { { "empty params", fmt.Sprintf("%s/lbm/tx/v1/txs/", val.APIAddress), - true, "transaction hash cannot be empty", + true, "tx hash cannot be empty", }, { "dummy hash", fmt.Sprintf("%s/lbm/tx/v1/txs/%s", val.APIAddress, "deadbeef"), - true, "tx (DEADBEEF) not found", + true, "code = NotFound desc = tx not found: deadbeef", }, { "good hash", @@ -376,14 +383,14 @@ func (s IntegrationTestSuite) TestGetTx_GRPCGateway() { s.Require().Contains(string(res), tc.expErrMsg) } else { var result tx.GetTxResponse - err = val.ClientCtx.JSONMarshaler.UnmarshalJSON(res, &result) + err = val.ClientCtx.Codec.UnmarshalJSON(res, &result) s.Require().NoError(err) s.Require().Equal("foobar", result.Tx.Body.Memo) s.Require().NotZero(result.TxResponse.Height) // Make sure fields are populated. - // ref: https://github.com/line/lbm-sdk/issues/8680 - // ref: https://github.com/line/lbm-sdk/issues/8681 + // ref: https://github.com/cosmos/cosmos-sdk/issues/8680 + // ref: https://github.com/cosmos/cosmos-sdk/issues/8681 s.Require().NotEmpty(result.TxResponse.Timestamp) s.Require().NotEmpty(result.TxResponse.RawLog) } @@ -454,7 +461,7 @@ func (s IntegrationTestSuite) TestBroadcastTx_GRPCGateway() { for _, tc := range testCases { s.Run(tc.name, func() { - req, err := val.ClientCtx.JSONMarshaler.MarshalJSON(tc.req) + req, err := val.ClientCtx.Codec.MarshalJSON(tc.req) s.Require().NoError(err) res, err := rest.PostRequest(fmt.Sprintf("%s/lbm/tx/v1/txs", val.APIAddress), "application/json", req) s.Require().NoError(err) @@ -462,15 +469,105 @@ func (s IntegrationTestSuite) TestBroadcastTx_GRPCGateway() { s.Require().Contains(string(res), tc.expErrMsg) } else { var result tx.BroadcastTxResponse - err = val.ClientCtx.JSONMarshaler.UnmarshalJSON(res, &result) + err = val.ClientCtx.Codec.UnmarshalJSON(res, &result) s.Require().NoError(err) - s.Require().Equal(uint32(0), result.TxResponse.Code) + s.Require().Equal(uint32(0), result.TxResponse.Code, "rawlog", result.TxResponse.RawLog) } }) } time.Sleep(1 * time.Second) // wait for block confirm time before executing next test } +func (s *IntegrationTestSuite) TestSimMultiSigTx() { + val1 := *s.network.Validators[0] + + kr := val1.ClientCtx.Keyring + + account1, _, err := kr.NewMnemonic("newAccount1", keyring.English, sdk.FullFundraiserPath, keyring.DefaultBIP39Passphrase, hd.Secp256k1) + s.Require().NoError(err) + + account2, _, err := kr.NewMnemonic("newAccount2", keyring.English, sdk.FullFundraiserPath, keyring.DefaultBIP39Passphrase, hd.Secp256k1) + s.Require().NoError(err) + + multi := kmultisig.NewLegacyAminoPubKey(2, []cryptotypes.PubKey{account1.GetPubKey(), account2.GetPubKey()}) + _, err = kr.SaveMultisig("multi", multi) + s.Require().NoError(err) + + _, err = s.network.WaitForHeight(1) + s.Require().NoError(err) + + multisigInfo, err := val1.ClientCtx.Keyring.Key("multi") + s.Require().NoError(err) + + height, err := s.network.LatestHeight() + _, err = s.network.WaitForHeight(height + 1) + s.Require().NoError(err) + + // Send coins from validator to multisig. + coins := sdk.NewInt64Coin(s.cfg.BondDenom, 15) + _, err = bankcli.MsgSendExec( + val1.ClientCtx, + val1.Address, + multisigInfo.GetAddress(), + sdk.NewCoins(coins), + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), + fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), + fmt.Sprintf("--gas=%d", flags.DefaultGasLimit), + ) + + height, err = s.network.LatestHeight() + _, err = s.network.WaitForHeight(height + 1) + s.Require().NoError(err) + + // Generate multisig transaction. + multiGeneratedTx, err := bankcli.MsgSendExec( + val1.ClientCtx, + multisigInfo.GetAddress(), + val1.Address, + sdk.NewCoins( + sdk.NewInt64Coin(s.cfg.BondDenom, 5), + ), + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), + fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), + fmt.Sprintf("--%s=true", flags.FlagGenerateOnly), + fmt.Sprintf("--%s=foobar", flags.FlagNote), + ) + s.Require().NoError(err) + + // Save tx to file + multiGeneratedTxFile := testutil.WriteToNewTempFile(s.T(), multiGeneratedTx.String()) + + // Sign with account1 + val1.ClientCtx.HomeDir = strings.Replace(val1.ClientCtx.HomeDir, "simd", "simcli", 1) + account1Signature, err := authtest.TxSignExec(val1.ClientCtx, account1.GetAddress(), multiGeneratedTxFile.Name(), "--multisig", multisigInfo.GetAddress().String()) + s.Require().NoError(err) + sign1File := testutil.WriteToNewTempFile(s.T(), account1Signature.String()) + + // Sign with account2 + account2Signature, err := authtest.TxSignExec(val1.ClientCtx, account2.GetAddress(), multiGeneratedTxFile.Name(), "--multisig", multisigInfo.GetAddress().String()) + s.Require().NoError(err) + sign2File := testutil.WriteToNewTempFile(s.T(), account2Signature.String()) + + // multisign tx + val1.ClientCtx.Offline = false + multiSigWith2Signatures, err := authtest.TxMultiSignExec(val1.ClientCtx, multisigInfo.GetName(), multiGeneratedTxFile.Name(), sign1File.Name(), sign2File.Name()) + s.Require().NoError(err) + + // convert from protoJSON to protoBinary for sim + sdkTx, err := val1.ClientCtx.TxConfig.TxJSONDecoder()(multiSigWith2Signatures.Bytes()) + txBytes, err := val1.ClientCtx.TxConfig.TxEncoder()(sdkTx) + + // simulate tx + sim := &tx.SimulateRequest{TxBytes: txBytes} + res, err := s.queryClient.Simulate(context.Background(), sim) + s.Require().NoError(err) + + // make sure gas was used + s.Require().Greater(res.GasInfo.GasUsed, uint64(0)) +} + func TestIntegrationTestSuite(t *testing.T) { suite.Run(t, new(IntegrationTestSuite)) } @@ -508,9 +605,19 @@ func (s IntegrationTestSuite) mkTxBuilder() client.TxBuilder { return txBuilder } +// protoTxProvider is a type which can provide a proto transaction. It is a +// workaround to get access to the wrapper TxBuilder's method GetProtoTx(). +// Deprecated: It's only used for testing the deprecated Simulate gRPC endpoint +// using a proto Tx field. +type protoTxProvider interface { + GetProtoTx() *tx.Tx +} + // txBuilderToProtoTx converts a txBuilder into a proto tx.Tx. +// Deprecated: It's only used for testing the deprecated Simulate gRPC endpoint +// using a proto Tx field. func txBuilderToProtoTx(txBuilder client.TxBuilder) (*tx.Tx, error) { // nolint - protoProvider, ok := txBuilder.(authtx.ProtoTxProvider) + protoProvider, ok := txBuilder.(protoTxProvider) if !ok { return nil, sdkerrors.Wrapf(sdkerrors.ErrInvalidType, "expected proto tx builder, got %T", txBuilder) } diff --git a/x/auth/tx/xauthclient.go b/x/auth/tx/xauthclient.go deleted file mode 100644 index d92072fbf5..0000000000 --- a/x/auth/tx/xauthclient.go +++ /dev/null @@ -1,155 +0,0 @@ -// Package tx 's xauthclient.go file is copy-pasted from -// https://github.com/line/lbm-sdk/blob/v0.41.3/x/auth/client/query.go -// It is duplicated as to not introduce any breaking change in 0.41.4, see PR: -// https://github.com/line/lbm-sdk/pull/8732#discussion_r584746947 -package tx - -import ( - "context" - "encoding/hex" - "errors" - "fmt" - "strings" - "time" - - ctypes "github.com/line/ostracon/rpc/core/types" - - "github.com/line/lbm-sdk/client" - codectypes "github.com/line/lbm-sdk/codec/types" - sdk "github.com/line/lbm-sdk/types" -) - -// QueryTxsByEvents performs a search for transactions for a given set of events -// via the Tendermint RPC. An event takes the form of: -// "{eventAttribute}.{attributeKey} = '{attributeValue}'". Each event is -// concatenated with an 'AND' operand. It returns a slice of Info object -// containing txs and metadata. An error is returned if the query fails. -// If an empty string is provided it will order txs by asc -func queryTxsByEvents(goCtx context.Context, clientCtx client.Context, events []string, prove bool, page, limit int, orderBy string) (*sdk.SearchTxsResult, error) { - if len(events) == 0 { - return nil, errors.New("must declare at least one event to search") - } - - if page <= 0 { - return nil, errors.New("page must greater than 0") - } - - if limit <= 0 { - return nil, errors.New("limit must greater than 0") - } - - // XXX: implement ANY - query := strings.Join(events, " AND ") - - node, err := clientCtx.GetNode() - if err != nil { - return nil, err - } - - resTxs, err := node.TxSearch(goCtx, query, prove, &page, &limit, orderBy) - if err != nil { - return nil, err - } - - resBlocks, err := getBlocksForTxResults(goCtx, clientCtx, resTxs.Txs) - if err != nil { - return nil, err - } - - txs, err := formatTxResults(clientCtx.TxConfig, resTxs.Txs, resBlocks) - if err != nil { - return nil, err - } - - result := sdk.NewSearchTxsResult(uint64(resTxs.TotalCount), uint64(len(txs)), uint64(page), uint64(limit), txs) - - return result, nil -} - -// QueryTx queries for a single transaction by a hash string in hex format. An -// error is returned if the transaction does not exist or cannot be queried. -func queryTx(goCtx context.Context, clientCtx client.Context, hashHexStr string) (*sdk.TxResponse, error) { - hash, err := hex.DecodeString(hashHexStr) - if err != nil { - return nil, err - } - - node, err := clientCtx.GetNode() - if err != nil { - return nil, err - } - - //TODO: this may not always need to be proven - // https://github.com/line/lbm-sdk/issues/6807 - resTx, err := node.Tx(goCtx, hash, true) - if err != nil { - return nil, err - } - - resBlocks, err := getBlocksForTxResults(goCtx, clientCtx, []*ctypes.ResultTx{resTx}) - if err != nil { - return nil, err - } - - out, err := mkTxResult(clientCtx.TxConfig, resTx, resBlocks[resTx.Height]) - if err != nil { - return out, err - } - - return out, nil -} - -// formatTxResults parses the indexed txs into a slice of TxResponse objects. -func formatTxResults(txConfig client.TxConfig, resTxs []*ctypes.ResultTx, resBlocks map[int64]*ctypes.ResultBlock) ([]*sdk.TxResponse, error) { - var err error - out := make([]*sdk.TxResponse, len(resTxs)) - for i := range resTxs { - out[i], err = mkTxResult(txConfig, resTxs[i], resBlocks[resTxs[i].Height]) - if err != nil { - return nil, err - } - } - - return out, nil -} - -func getBlocksForTxResults(goCtx context.Context, clientCtx client.Context, resTxs []*ctypes.ResultTx) (map[int64]*ctypes.ResultBlock, error) { - node, err := clientCtx.GetNode() - if err != nil { - return nil, err - } - - resBlocks := make(map[int64]*ctypes.ResultBlock) - - for _, resTx := range resTxs { - if _, ok := resBlocks[resTx.Height]; !ok { - resBlock, err := node.Block(goCtx, &resTx.Height) - if err != nil { - return nil, err - } - - resBlocks[resTx.Height] = resBlock - } - } - - return resBlocks, nil -} - -func mkTxResult(txConfig client.TxConfig, resTx *ctypes.ResultTx, resBlock *ctypes.ResultBlock) (*sdk.TxResponse, error) { - txb, err := txConfig.TxDecoder()(resTx.Tx) - if err != nil { - return nil, err - } - p, ok := txb.(intoAny) - if !ok { - return nil, fmt.Errorf("expecting a type implementing intoAny, got: %T", txb) - } - any := p.AsAny() - return sdk.NewResponseResultTx(resTx, any, resBlock.Block.Time.Format(time.RFC3339)), nil -} - -// Deprecated: this interface is used only internally for scenario we are -// deprecating (StdTxConfig support) -type intoAny interface { - AsAny() *codectypes.Any -} diff --git a/x/auth/types/account.go b/x/auth/types/account.go index cd8086eb6a..768c974a7c 100644 --- a/x/auth/types/account.go +++ b/x/auth/types/account.go @@ -1,14 +1,11 @@ package types import ( - "bytes" "encoding/json" "errors" "fmt" - "strconv" "strings" - "github.com/gogo/protobuf/jsonpb" "github.com/gogo/protobuf/proto" "github.com/line/ostracon/crypto" "gopkg.in/yaml.v2" @@ -18,6 +15,7 @@ import ( "github.com/line/lbm-sdk/crypto/keys/ed25519" "github.com/line/lbm-sdk/crypto/keys/multisig" "github.com/line/lbm-sdk/crypto/keys/secp256k1" + "github.com/line/lbm-sdk/crypto/keys/secp256r1" cryptotypes "github.com/line/lbm-sdk/crypto/types" sdk "github.com/line/lbm-sdk/types" ) @@ -60,6 +58,7 @@ func ProtoBaseAccount() AccountI { } // NewBaseAccountWithAddress - returns a new base account with a given address +// leaving AccountNumber and Sequence to zero. func NewBaseAccountWithAddress(addr sdk.AccAddress) *BaseAccount { return &BaseAccount{ Address: addr.String(), @@ -87,6 +86,8 @@ func (acc BaseAccount) GetPubKey() (pk cryptotypes.PubKey) { return acc.Ed25519PubKey } else if acc.Secp256K1PubKey != nil { return acc.Secp256K1PubKey + } else if acc.Secp256R1PubKey != nil { + return acc.Secp256R1PubKey } else if acc.MultisigPubKey != nil { return acc.MultisigPubKey } @@ -96,13 +97,15 @@ func (acc BaseAccount) GetPubKey() (pk cryptotypes.PubKey) { // SetPubKey - Implements sdk.AccountI. func (acc *BaseAccount) SetPubKey(pubKey cryptotypes.PubKey) error { if pubKey == nil { - acc.Ed25519PubKey, acc.Secp256K1PubKey, acc.MultisigPubKey = nil, nil, nil + acc.Ed25519PubKey, acc.Secp256K1PubKey, acc.Secp256R1PubKey, acc.MultisigPubKey = nil, nil, nil, nil } else if pk, ok := pubKey.(*ed25519.PubKey); ok { - acc.Ed25519PubKey, acc.Secp256K1PubKey, acc.MultisigPubKey = pk, nil, nil + acc.Ed25519PubKey, acc.Secp256K1PubKey, acc.Secp256R1PubKey, acc.MultisigPubKey = pk, nil, nil, nil } else if pk, ok := pubKey.(*secp256k1.PubKey); ok { - acc.Ed25519PubKey, acc.Secp256K1PubKey, acc.MultisigPubKey = nil, pk, nil + acc.Ed25519PubKey, acc.Secp256K1PubKey, acc.Secp256R1PubKey, acc.MultisigPubKey = nil, pk, nil, nil + } else if pk, ok := pubKey.(*secp256r1.PubKey); ok { + acc.Ed25519PubKey, acc.Secp256K1PubKey, acc.Secp256R1PubKey, acc.MultisigPubKey = nil, nil, pk, nil } else if pk, ok := pubKey.(*multisig.LegacyAminoPubKey); ok { - acc.Ed25519PubKey, acc.Secp256K1PubKey, acc.MultisigPubKey = nil, nil, pk + acc.Ed25519PubKey, acc.Secp256K1PubKey, acc.Secp256R1PubKey, acc.MultisigPubKey = nil, nil, nil, pk } else { return fmt.Errorf("invalid pubkey") } @@ -237,11 +240,6 @@ func (ma ModuleAccount) SetPubKey(pubKey cryptotypes.PubKey) error { return fmt.Errorf("not supported for module accounts") } -// SetSequence - Implements AccountI -func (ma ModuleAccount) SetSequence(seq uint64) error { - return fmt.Errorf("not supported for module accounts") -} - // Validate checks for errors on the account fields func (ma ModuleAccount) Validate() error { if strings.TrimSpace(ma.Name) == "" { @@ -296,7 +294,6 @@ func (ma ModuleAccount) MarshalYAML() (interface{}, error) { Name: ma.Name, Permissions: ma.Permissions, }) - if err != nil { return nil, err } @@ -362,38 +359,7 @@ type AccountI interface { MarshalX() ([]byte, error) } -func MarshalAccountX(cdc codec.BinaryMarshaler, acc AccountI) ([]byte, error) { - if bacc, ok := acc.(*BaseAccount); ok && bacc.MultisigPubKey == nil { - return acc.MarshalX() - } else if macc, ok := acc.(*ModuleAccount); ok && macc.MultisigPubKey == nil { - return acc.MarshalX() - } else { - return cdc.MarshalInterface(acc) - } -} - -func UnmarshalAccountX(cdc codec.BinaryMarshaler, bz []byte) (AccountI, error) { - sigLen := len(BaseAccountSig) - if len(bz) < sigLen { - return nil, fmt.Errorf("invalid data") - } - if bytes.Equal(bz[:sigLen], BaseAccountSig) { - acc := &BaseAccount{} - if err := acc.Unmarshal(bz[sigLen:]); err != nil { - return nil, err - } - return acc, nil - } else if bytes.Equal(bz[:sigLen], ModuleAccountSig) { - acc := &ModuleAccount{} - if err := acc.Unmarshal(bz[sigLen:]); err != nil { - return nil, err - } - return acc, nil - } else { - var acc AccountI - return acc, cdc.UnmarshalInterface(bz, &acc) - } -} +// TODO(dudong2): remove MarshalAccountX, UnmarshalAccountX(because codec.BinaryMarshaler is removed -> build failed) - ref. https://github.com/line/lbm-sdk/pull/320 // ModuleAccountI defines an account interface for modules that hold tokens in // an escrow. @@ -426,121 +392,3 @@ type GenesisAccount interface { Validate() error } - -// custom json marshaler for BaseAccount & ModuleAccount - -type PubKeyJSON struct { - Type byte `json:"type"` - Key []byte `json:"key"` -} -type BaseAccountJSON struct { - Address string `json:"address"` - PubKey PubKeyJSON `json:"pub_key"` - AccountNumber uint64 `json:"account_number"` - Sequence string `json:"sequence"` -} - -func (acc BaseAccount) MarshalJSONPB(m *jsonpb.Marshaler) ([]byte, error) { - var bi BaseAccountJSON - - bi.Address = acc.GetAddress().String() - bi.AccountNumber = acc.GetAccountNumber() - bi.Sequence = strconv.FormatUint(acc.Sequence, 10) - var bz []byte - var err error - if acc.Secp256K1PubKey != nil { - bi.PubKey.Type = PubKeyTypeSecp256k1 - bz, err = acc.Secp256K1PubKey.Marshal() - } - if acc.Ed25519PubKey != nil { - bi.PubKey.Type = PubKeyTypeEd25519 - bz, err = acc.Ed25519PubKey.Marshal() - } - if acc.MultisigPubKey != nil { - bi.PubKey.Type = PubKeyTypeMultisig - bz, err = acc.MultisigPubKey.Marshal() - } - if err != nil { - return nil, err - } - bi.PubKey.Key = bz - return json.Marshal(bi) -} - -func (acc *BaseAccount) UnmarshalJSONPB(m *jsonpb.Unmarshaler, bz []byte) error { - var bi BaseAccountJSON - - err := json.Unmarshal(bz, &bi) - if err != nil { - return err - } - - acc.Address = bi.Address - acc.AccountNumber = bi.AccountNumber - acc.Sequence, err = strconv.ParseUint(bi.Sequence, 10, 64) - if err != nil { - return err - } - - switch bi.PubKey.Type { - case PubKeyTypeSecp256k1: - pk := new(secp256k1.PubKey) - if err := pk.Unmarshal(bi.PubKey.Key); err != nil { - return err - } - acc.SetPubKey(pk) - case PubKeyTypeEd25519: - pk := new(secp256k1.PubKey) - if err := pk.Unmarshal(bi.PubKey.Key); err != nil { - return err - } - acc.SetPubKey(pk) - case PubKeyTypeMultisig: - pk := new(multisig.LegacyAminoPubKey) - if err := pk.Unmarshal(bi.PubKey.Key); err != nil { - return err - } - acc.SetPubKey(pk) - } - return nil -} - -type ModuleAccountJSON struct { - BaseAccount json.RawMessage `json:"base_account"` - Name string `json:"name"` - Permissions []string `json:"permissions"` -} - -func (ma ModuleAccount) MarshalJSONPB(m *jsonpb.Marshaler) ([]byte, error) { - var mi ModuleAccountJSON - - bz, err := ma.BaseAccount.MarshalJSONPB(m) - if err != nil { - return nil, err - } - mi.BaseAccount = bz - mi.Name = ma.Name - mi.Permissions = ma.Permissions - - return json.Marshal(mi) -} - -func (ma *ModuleAccount) UnmarshalJSONPB(m *jsonpb.Unmarshaler, bz []byte) error { - var mi ModuleAccountJSON - - err := json.Unmarshal(bz, &mi) - if err != nil { - return err - } - - ma.Name = mi.Name - ma.Permissions = mi.Permissions - - ba := new(BaseAccount) - if err := m.Unmarshal(strings.NewReader(string(mi.BaseAccount)), ba); err != nil { - return err - } - ma.BaseAccount = ba - - return nil -} diff --git a/x/auth/types/auth.pb.go b/x/auth/types/auth.pb.go index 878153ddc7..70a1bf2fb2 100644 --- a/x/auth/types/auth.pb.go +++ b/x/auth/types/auth.pb.go @@ -10,6 +10,7 @@ import ( ed25519 "github.com/line/lbm-sdk/crypto/keys/ed25519" multisig "github.com/line/lbm-sdk/crypto/keys/multisig" secp256k1 "github.com/line/lbm-sdk/crypto/keys/secp256k1" + secp256r1 "github.com/line/lbm-sdk/crypto/keys/secp256r1" _ "github.com/regen-network/cosmos-proto" io "io" math "math" @@ -34,9 +35,10 @@ type BaseAccount struct { Address string `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"` Ed25519PubKey *ed25519.PubKey `protobuf:"bytes,2,opt,name=ed25519_pub_key,json=ed25519PubKey,proto3" json:"ed25519_public_key,omitempty" yaml:"ed25519_public_key"` Secp256K1PubKey *secp256k1.PubKey `protobuf:"bytes,3,opt,name=secp256k1_pub_key,json=secp256k1PubKey,proto3" json:"secp256k1_public_key,omitempty" yaml:"secp256k1_public_key"` - MultisigPubKey *multisig.LegacyAminoPubKey `protobuf:"bytes,4,opt,name=multisig_pub_key,json=multisigPubKey,proto3" json:"multisig_public_key,omitempty" yaml:"multisig_public_key"` - AccountNumber uint64 `protobuf:"varint,5,opt,name=account_number,json=accountNumber,proto3" json:"account_number,omitempty" yaml:"account_number"` - Sequence uint64 `protobuf:"varint,6,opt,name=sequence,proto3" json:"sequence,omitempty"` + Secp256R1PubKey *secp256r1.PubKey `protobuf:"bytes,4,opt,name=secp256r1_pub_key,json=secp256r1PubKey,proto3" json:"secp256r1_public_key,omitempty" yaml:"secp256r1_public_key"` + MultisigPubKey *multisig.LegacyAminoPubKey `protobuf:"bytes,5,opt,name=multisig_pub_key,json=multisigPubKey,proto3" json:"multisig_public_key,omitempty" yaml:"multisig_public_key"` + AccountNumber uint64 `protobuf:"varint,6,opt,name=account_number,json=accountNumber,proto3" json:"account_number,omitempty" yaml:"account_number"` + Sequence uint64 `protobuf:"varint,7,opt,name=sequence,proto3" json:"sequence,omitempty"` } func (m *BaseAccount) Reset() { *m = BaseAccount{} } @@ -195,57 +197,58 @@ func init() { func init() { proto.RegisterFile("lbm/auth/v1/auth.proto", fileDescriptor_1d85c5e32d5ed883) } var fileDescriptor_1d85c5e32d5ed883 = []byte{ - // 786 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x6c, 0x94, 0x41, 0x6f, 0xe3, 0x44, - 0x14, 0xc7, 0x63, 0x62, 0x4a, 0x3b, 0xd9, 0x76, 0xa9, 0xb7, 0xdb, 0x75, 0xb2, 0x5d, 0x4f, 0x64, - 0x21, 0x94, 0x03, 0xb5, 0x95, 0xa0, 0x22, 0x6d, 0x24, 0x16, 0xea, 0xc2, 0xa1, 0xa2, 0xad, 0x2a, - 0x57, 0x42, 0x88, 0x8b, 0x65, 0x3b, 0x43, 0x6a, 0xc5, 0x93, 0x71, 0x3d, 0xe3, 0x2a, 0xee, 0x8d, - 0x1b, 0x12, 0x17, 0xb8, 0x71, 0xec, 0x87, 0xe8, 0x8d, 0x33, 0x12, 0xc7, 0xaa, 0x27, 0x4e, 0x06, - 0xa5, 0x17, 0xd4, 0x63, 0x3e, 0x01, 0xf2, 0xd8, 0x31, 0x93, 0x36, 0xa7, 0xe4, 0xbd, 0xf7, 0x7f, - 0x6f, 0x7e, 0xa3, 0xf9, 0x3f, 0x83, 0xed, 0xd0, 0xc3, 0xa6, 0x9b, 0xb0, 0x73, 0xf3, 0xb2, 0xcb, - 0x7f, 0x8d, 0x28, 0x26, 0x8c, 0x28, 0x8d, 0xd0, 0xc3, 0x06, 0x8f, 0x2f, 0xbb, 0xad, 0x37, 0xb9, - 0xc8, 0x8f, 0xd3, 0x88, 0x11, 0x13, 0x0d, 0x7a, 0x7b, 0x7b, 0xdd, 0xb7, 0xe6, 0x08, 0xa5, 0xb4, - 0xd0, 0xb6, 0x34, 0xa1, 0x8c, 0x93, 0x90, 0x05, 0x34, 0x18, 0x8a, 0x75, 0x28, 0xd4, 0x29, 0xf2, - 0xa3, 0xde, 0xde, 0x67, 0xa3, 0xae, 0x28, 0x68, 0xfa, 0x84, 0x62, 0x42, 0x1d, 0x1e, 0x99, 0x45, - 0x50, 0x96, 0xb6, 0x86, 0x64, 0x48, 0x8a, 0x7c, 0xfe, 0xaf, 0xc8, 0xea, 0x7f, 0xc8, 0xa0, 0x61, - 0xb9, 0x14, 0xed, 0xfb, 0x3e, 0x49, 0xc6, 0x4c, 0x51, 0xc1, 0x07, 0xee, 0x60, 0x10, 0x23, 0x4a, - 0x55, 0xa9, 0x2d, 0x75, 0xd6, 0xec, 0x79, 0xa8, 0xfc, 0x28, 0x81, 0xe7, 0x25, 0xb2, 0x13, 0x25, - 0x9e, 0x33, 0x42, 0xa9, 0xfa, 0x5e, 0x5b, 0xea, 0x34, 0x7a, 0x2d, 0x23, 0xbf, 0x62, 0x81, 0x65, - 0x94, 0x12, 0xe3, 0x34, 0xf1, 0xbe, 0x41, 0xa9, 0xf5, 0xf9, 0x43, 0x06, 0x77, 0x84, 0xb6, 0x30, - 0xf0, 0xf3, 0xce, 0x4f, 0x08, 0x0e, 0x18, 0xc2, 0x11, 0x4b, 0x67, 0x19, 0x6c, 0xa6, 0x2e, 0x0e, - 0xfb, 0xfa, 0x53, 0x95, 0x6e, 0xaf, 0x97, 0xc9, 0x62, 0x9a, 0xf2, 0xb3, 0x04, 0x36, 0xab, 0x7b, - 0x57, 0x14, 0x75, 0x4e, 0xb1, 0x23, 0x52, 0x54, 0xa2, 0x39, 0xc7, 0xfe, 0x43, 0x06, 0xb5, 0x85, - 0xd6, 0x65, 0x24, 0xaf, 0x0b, 0x92, 0x65, 0x3a, 0xdd, 0x7e, 0x5e, 0xa5, 0x4b, 0x9a, 0x5f, 0x25, - 0xf0, 0xe1, 0xfc, 0x95, 0x2a, 0x18, 0x99, 0xc3, 0x7c, 0x2c, 0xc2, 0xcc, 0x35, 0xc6, 0x11, 0x1a, - 0xba, 0x7e, 0xba, 0x8f, 0x83, 0x31, 0x29, 0xb1, 0xbe, 0x78, 0xc8, 0xe0, 0x1b, 0x71, 0xc6, 0x32, - 0xaa, 0x56, 0x41, 0xb5, 0x44, 0xa6, 0xdb, 0x1b, 0xf3, 0x6c, 0xc9, 0xf4, 0x25, 0xd8, 0x70, 0x8b, - 0xa7, 0x74, 0xc6, 0x09, 0xf6, 0x50, 0xac, 0xbe, 0xdf, 0x96, 0x3a, 0xb2, 0xd5, 0x9c, 0x65, 0xf0, - 0x65, 0x31, 0x67, 0xb1, 0xae, 0xdb, 0xeb, 0x65, 0xe2, 0x84, 0xc7, 0x4a, 0x0b, 0xac, 0x52, 0x74, - 0x91, 0xa0, 0xb1, 0x8f, 0xd4, 0x95, 0xbc, 0xd7, 0xae, 0xe2, 0xbe, 0xfa, 0xd3, 0x35, 0xac, 0xfd, - 0x76, 0x0d, 0x6b, 0xff, 0x5e, 0xc3, 0xda, 0xdd, 0xcd, 0xee, 0x6a, 0x69, 0x9b, 0x43, 0xfd, 0x77, - 0x09, 0xac, 0x1f, 0x93, 0x41, 0x12, 0x56, 0x4e, 0xfa, 0x0e, 0x3c, 0xf3, 0x5c, 0x8a, 0x9c, 0x72, - 0x3a, 0xb7, 0x53, 0xa3, 0xa7, 0x1a, 0xc2, 0x3a, 0x18, 0x82, 0xf3, 0xac, 0xd7, 0xb7, 0x19, 0x94, - 0x66, 0x19, 0x7c, 0x51, 0x50, 0x8a, 0xbd, 0xba, 0xdd, 0xf0, 0x04, 0x8f, 0x2a, 0x40, 0x1e, 0xbb, - 0x18, 0x71, 0xf7, 0xad, 0xd9, 0xfc, 0xbf, 0xd2, 0x06, 0x8d, 0x08, 0xc5, 0x38, 0xa0, 0x34, 0x20, - 0x63, 0xaa, 0xd6, 0xdb, 0xf5, 0xce, 0x9a, 0x2d, 0xa6, 0xfa, 0xad, 0x39, 0xfb, 0xdd, 0xcd, 0xee, - 0xc6, 0x02, 0xea, 0xa1, 0xfe, 0x77, 0x1d, 0xac, 0x9c, 0xba, 0xb1, 0x8b, 0xa9, 0x72, 0x02, 0x5e, - 0x60, 0x77, 0xe2, 0x60, 0x84, 0x89, 0xe3, 0x9f, 0xbb, 0xb1, 0xeb, 0x33, 0x14, 0x17, 0xcb, 0x20, - 0x5b, 0x9a, 0xf0, 0x1a, 0x4f, 0x45, 0xba, 0xbd, 0x89, 0xdd, 0xc9, 0x31, 0xc2, 0xe4, 0xa0, 0xca, - 0x29, 0x6f, 0xc1, 0x33, 0x36, 0x71, 0xf2, 0x67, 0x0b, 0x03, 0x1c, 0x30, 0x0e, 0x2d, 0x5b, 0xaf, - 0xfe, 0xbf, 0xa8, 0x58, 0xd5, 0x6d, 0xc0, 0x26, 0x67, 0xc1, 0xf0, 0x28, 0x0f, 0x14, 0x1b, 0xbc, - 0xe4, 0xc5, 0x2b, 0xe4, 0xf8, 0x84, 0x32, 0x27, 0x42, 0xb1, 0xe3, 0xa5, 0x0c, 0x71, 0xc3, 0xcb, - 0x56, 0x7b, 0x96, 0xc1, 0x1d, 0x61, 0xc6, 0x63, 0x99, 0x6e, 0x6f, 0xe6, 0xc3, 0xae, 0xd0, 0x01, - 0xa1, 0xec, 0x14, 0xc5, 0x56, 0xca, 0x90, 0x72, 0x01, 0x5e, 0xe5, 0xa7, 0x5d, 0xa2, 0x38, 0xf8, - 0x21, 0x2d, 0xf4, 0xe5, 0x8a, 0x71, 0xe7, 0xca, 0x56, 0x7f, 0x9a, 0xc1, 0xad, 0xb3, 0x60, 0xf8, - 0x2d, 0x57, 0xe4, 0xad, 0x5f, 0x7f, 0xc5, 0xeb, 0xb3, 0x0c, 0x6a, 0xe5, 0x7a, 0x2c, 0x1f, 0xa0, - 0xdb, 0x5b, 0x74, 0xa1, 0xaf, 0x48, 0x2b, 0x29, 0x68, 0x3e, 0xee, 0xa8, 0x36, 0xa9, 0x74, 0xe7, - 0xbb, 0x69, 0x06, 0xb7, 0x17, 0x0e, 0x3d, 0x9b, 0x2b, 0x66, 0x19, 0x6c, 0x2f, 0x3f, 0xb6, 0x1a, - 0xa2, 0xdb, 0xdb, 0x74, 0x69, 0x6f, 0x7f, 0xb5, 0xf4, 0xaa, 0x64, 0xbd, 0xfb, 0x73, 0xaa, 0x49, - 0xb7, 0x53, 0x4d, 0xfa, 0x67, 0xaa, 0x49, 0xbf, 0xdc, 0x6b, 0xb5, 0xdb, 0x7b, 0xad, 0xf6, 0xd7, - 0xbd, 0x56, 0xfb, 0xfe, 0xa3, 0x61, 0xc0, 0xce, 0x13, 0xcf, 0xf0, 0x09, 0x36, 0xc3, 0x60, 0x8c, - 0xcc, 0xd0, 0xc3, 0xbb, 0x74, 0x30, 0x32, 0x27, 0xc5, 0xd7, 0x9c, 0xa5, 0x11, 0xa2, 0xde, 0x0a, - 0xff, 0x5c, 0x7e, 0xfa, 0x5f, 0x00, 0x00, 0x00, 0xff, 0xff, 0xe0, 0x62, 0xc8, 0x44, 0xe6, 0x05, - 0x00, 0x00, + // 814 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x95, 0xcf, 0x6f, 0xdc, 0x44, + 0x14, 0xc7, 0xd7, 0xc4, 0x4d, 0x93, 0xd9, 0x26, 0x25, 0x6e, 0x9a, 0x7a, 0xb7, 0xa9, 0x67, 0x65, + 0x21, 0xb4, 0x07, 0x62, 0x6b, 0x17, 0x05, 0xa9, 0x2b, 0x51, 0x88, 0x0b, 0x87, 0x8a, 0xb6, 0x8a, + 0x1c, 0x09, 0x21, 0x2e, 0x96, 0xed, 0x1d, 0x36, 0xd6, 0x7a, 0x76, 0xdc, 0x99, 0x71, 0xb4, 0xee, + 0x8d, 0x1b, 0x12, 0x17, 0xb8, 0x71, 0xcc, 0x1f, 0xd1, 0x1b, 0xff, 0x00, 0xc7, 0xa8, 0x5c, 0x38, + 0x19, 0xb4, 0xb9, 0xa0, 0x1c, 0xf7, 0x2f, 0x40, 0x1e, 0xff, 0xa8, 0x37, 0x31, 0x82, 0xd3, 0xfa, + 0xbd, 0xf7, 0x7d, 0x6f, 0x3e, 0xb6, 0xdf, 0x77, 0x0d, 0xf6, 0x42, 0x0f, 0x9b, 0x6e, 0xcc, 0x4f, + 0xcd, 0xb3, 0x81, 0xf8, 0x35, 0x22, 0x4a, 0x38, 0x51, 0xda, 0xa1, 0x87, 0x0d, 0x11, 0x9f, 0x0d, + 0xba, 0x8f, 0x32, 0x91, 0x4f, 0x93, 0x88, 0x13, 0x13, 0x8d, 0x87, 0x87, 0x87, 0x83, 0xc7, 0xe6, + 0x14, 0x25, 0x2c, 0xd7, 0x76, 0xb5, 0x5a, 0x19, 0xc7, 0x21, 0x0f, 0x58, 0x30, 0xa9, 0xd7, 0x61, + 0xad, 0xce, 0x90, 0x1f, 0x0d, 0x0f, 0x3f, 0x99, 0x0e, 0xfe, 0x43, 0x40, 0x57, 0x04, 0x1d, 0x9f, + 0x30, 0x4c, 0x98, 0x23, 0x22, 0x33, 0x0f, 0x8a, 0xd2, 0xee, 0x84, 0x4c, 0x48, 0x9e, 0xcf, 0xae, + 0xf2, 0xac, 0xfe, 0xfb, 0x2d, 0xd0, 0xb6, 0x5c, 0x86, 0x8e, 0x7c, 0x9f, 0xc4, 0x33, 0xae, 0xa8, + 0xe0, 0xb6, 0x3b, 0x1e, 0x53, 0xc4, 0x98, 0x2a, 0xf5, 0xa4, 0xfe, 0xa6, 0x5d, 0x86, 0xca, 0xf7, + 0x12, 0xb8, 0x5b, 0xdc, 0x93, 0x13, 0xc5, 0x9e, 0x33, 0x45, 0x89, 0xfa, 0x5e, 0x4f, 0xea, 0xb7, + 0x87, 0x5d, 0x23, 0x7b, 0x06, 0x39, 0x96, 0x51, 0x48, 0x8c, 0xe3, 0xd8, 0xfb, 0x0a, 0x25, 0xd6, + 0xa7, 0x57, 0x29, 0xdc, 0xaf, 0xb5, 0x85, 0x81, 0x9f, 0x75, 0x7e, 0x44, 0x70, 0xc0, 0x11, 0x8e, + 0x78, 0xb2, 0x4c, 0x61, 0x27, 0x71, 0x71, 0x38, 0xd2, 0x6f, 0xaa, 0x74, 0x7b, 0xab, 0x48, 0xe6, + 0xd3, 0x94, 0x1f, 0x25, 0xb0, 0x53, 0x3d, 0x98, 0x8a, 0x62, 0x4d, 0x50, 0xec, 0xd7, 0x29, 0x2a, + 0x51, 0xc9, 0x71, 0x74, 0x95, 0x42, 0x6d, 0xa5, 0xb5, 0x89, 0xe4, 0x61, 0x4e, 0xd2, 0xa4, 0xd3, + 0xed, 0xbb, 0x55, 0xfa, 0x26, 0x0d, 0x7d, 0x47, 0x23, 0xff, 0x2b, 0x0d, 0x6d, 0xa4, 0xa1, 0xff, + 0x93, 0x86, 0x36, 0xd3, 0xd0, 0x92, 0xe6, 0x67, 0x09, 0xbc, 0x5f, 0x2e, 0x55, 0x05, 0x73, 0x4b, + 0xc0, 0x7c, 0x58, 0x87, 0x29, 0x35, 0xc6, 0x73, 0x34, 0x71, 0xfd, 0xe4, 0x08, 0x07, 0x33, 0x52, + 0x60, 0x7d, 0x76, 0x95, 0xc2, 0x47, 0xf5, 0x19, 0x4d, 0x54, 0xdd, 0x9c, 0xaa, 0x41, 0xa6, 0xdb, + 0xdb, 0x65, 0xb6, 0x60, 0xfa, 0x1c, 0x6c, 0xbb, 0xf9, 0x62, 0x39, 0xb3, 0x18, 0x7b, 0x88, 0xaa, + 0xeb, 0x3d, 0xa9, 0x2f, 0x5b, 0x9d, 0x65, 0x0a, 0xef, 0xe7, 0x73, 0x56, 0xeb, 0xba, 0xbd, 0x55, + 0x24, 0x5e, 0x8a, 0x58, 0xe9, 0x82, 0x0d, 0x86, 0x5e, 0xc5, 0x68, 0xe6, 0x23, 0xf5, 0x76, 0xd6, + 0x6b, 0x57, 0xf1, 0x48, 0xfd, 0xe1, 0x1c, 0xb6, 0x7e, 0x39, 0x87, 0xad, 0xbf, 0xcf, 0x61, 0xeb, + 0xed, 0x9b, 0x83, 0x8d, 0x62, 0x89, 0x9f, 0xe9, 0xbf, 0x4a, 0x60, 0xeb, 0x05, 0x19, 0xc7, 0x61, + 0xb5, 0xd7, 0xdf, 0x80, 0x3b, 0x9e, 0xcb, 0x90, 0x53, 0x4c, 0x17, 0xcb, 0xdd, 0x1e, 0xaa, 0x46, + 0xcd, 0xbd, 0x46, 0xcd, 0x07, 0xd6, 0xc3, 0x8b, 0x14, 0x4a, 0xcb, 0x14, 0xde, 0xcb, 0x29, 0xeb, + 0xbd, 0xba, 0xdd, 0xf6, 0x6a, 0x8e, 0x51, 0x80, 0x3c, 0x73, 0x31, 0x12, 0x5e, 0xd8, 0xb4, 0xc5, + 0xb5, 0xd2, 0x03, 0xed, 0x08, 0x51, 0x1c, 0x30, 0x16, 0x90, 0x19, 0x53, 0xd7, 0x7a, 0x6b, 0xfd, + 0x4d, 0xbb, 0x9e, 0x1a, 0x75, 0x4b, 0xf6, 0xb7, 0x6f, 0x0e, 0xb6, 0x57, 0x50, 0x9f, 0xe9, 0x7f, + 0xae, 0x81, 0xf5, 0x63, 0x97, 0xba, 0x98, 0x29, 0x2f, 0xc1, 0x3d, 0xec, 0xce, 0x1d, 0x8c, 0x30, + 0x71, 0xfc, 0x53, 0x97, 0xba, 0x3e, 0x47, 0x34, 0xb7, 0xa6, 0x6c, 0x69, 0xb5, 0xb7, 0x71, 0x53, + 0xa4, 0xdb, 0x3b, 0xd8, 0x9d, 0xbf, 0x40, 0x98, 0x3c, 0xad, 0x72, 0xca, 0x63, 0x70, 0x87, 0xcf, + 0x9d, 0xec, 0xb5, 0x85, 0x01, 0x0e, 0xb8, 0x80, 0x96, 0xad, 0x07, 0xef, 0x6e, 0xb4, 0x5e, 0xd5, + 0x6d, 0xc0, 0xe7, 0x27, 0xc1, 0xe4, 0x79, 0x16, 0x28, 0x36, 0xb8, 0x2f, 0x8a, 0xaf, 0x91, 0xe3, + 0x13, 0xc6, 0x9d, 0x08, 0x51, 0xc7, 0x4b, 0x38, 0x12, 0xf6, 0x93, 0xad, 0xde, 0x32, 0x85, 0xfb, + 0xb5, 0x19, 0xd7, 0x65, 0xba, 0xbd, 0x93, 0x0d, 0x7b, 0x8d, 0x9e, 0x12, 0xc6, 0x8f, 0x11, 0xb5, + 0x12, 0x8e, 0x94, 0x57, 0xe0, 0x41, 0x76, 0xda, 0x19, 0xa2, 0xc1, 0x77, 0x49, 0xae, 0x2f, 0x0c, + 0x2f, 0x6c, 0x24, 0x5b, 0xa3, 0x45, 0x0a, 0x77, 0x4f, 0x82, 0xc9, 0xd7, 0x42, 0x91, 0xb5, 0x7e, + 0xf9, 0x85, 0xa8, 0x2f, 0x53, 0xa8, 0x15, 0xf6, 0x68, 0x1e, 0xa0, 0xdb, 0xbb, 0x6c, 0xa5, 0x2f, + 0x4f, 0x2b, 0x09, 0xe8, 0x5c, 0xef, 0xa8, 0x7c, 0x2d, 0xec, 0x22, 0x5b, 0x4f, 0x16, 0x29, 0xdc, + 0x5b, 0x39, 0xf4, 0xa4, 0x54, 0x2c, 0x53, 0xd8, 0x6b, 0x3e, 0xb6, 0x1a, 0xa2, 0xdb, 0x7b, 0xac, + 0xb1, 0x77, 0xb4, 0x51, 0xec, 0xaa, 0x64, 0x3d, 0xf9, 0x6d, 0xa1, 0x49, 0x17, 0x0b, 0x4d, 0xfa, + 0x6b, 0xa1, 0x49, 0x3f, 0x5d, 0x6a, 0xad, 0x8b, 0x4b, 0xad, 0xf5, 0xc7, 0xa5, 0xd6, 0xfa, 0xf6, + 0x83, 0x49, 0xc0, 0x4f, 0x63, 0xcf, 0xf0, 0x09, 0x36, 0xc3, 0x60, 0x86, 0xcc, 0xd0, 0xc3, 0x07, + 0x6c, 0x3c, 0x35, 0xe7, 0xf9, 0xc7, 0x87, 0x27, 0x11, 0x62, 0xde, 0xba, 0xf8, 0xf3, 0xfe, 0xf8, + 0x9f, 0x00, 0x00, 0x00, 0xff, 0xff, 0xf6, 0xc7, 0x0f, 0x83, 0x95, 0x06, 0x00, 0x00, } func (this *Params) Equal(that interface{}) bool { @@ -307,12 +310,12 @@ func (m *BaseAccount) MarshalToSizedBuffer(dAtA []byte) (int, error) { if m.Sequence != 0 { i = encodeVarintAuth(dAtA, i, uint64(m.Sequence)) i-- - dAtA[i] = 0x30 + dAtA[i] = 0x38 } if m.AccountNumber != 0 { i = encodeVarintAuth(dAtA, i, uint64(m.AccountNumber)) i-- - dAtA[i] = 0x28 + dAtA[i] = 0x30 } if m.MultisigPubKey != nil { { @@ -324,6 +327,18 @@ func (m *BaseAccount) MarshalToSizedBuffer(dAtA []byte) (int, error) { i = encodeVarintAuth(dAtA, i, uint64(size)) } i-- + dAtA[i] = 0x2a + } + if m.Secp256R1PubKey != nil { + { + size, err := m.Secp256R1PubKey.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintAuth(dAtA, i, uint64(size)) + } + i-- dAtA[i] = 0x22 } if m.Secp256K1PubKey != nil { @@ -488,6 +503,10 @@ func (m *BaseAccount) Size() (n int) { l = m.Secp256K1PubKey.Size() n += 1 + l + sovAuth(uint64(l)) } + if m.Secp256R1PubKey != nil { + l = m.Secp256R1PubKey.Size() + n += 1 + l + sovAuth(uint64(l)) + } if m.MultisigPubKey != nil { l = m.MultisigPubKey.Size() n += 1 + l + sovAuth(uint64(l)) @@ -688,6 +707,42 @@ func (m *BaseAccount) Unmarshal(dAtA []byte) error { } iNdEx = postIndex case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Secp256R1PubKey", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAuth + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthAuth + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthAuth + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Secp256R1PubKey == nil { + m.Secp256R1PubKey = &secp256r1.PubKey{} + } + if err := m.Secp256R1PubKey.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 5: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field MultisigPubKey", wireType) } @@ -723,7 +778,7 @@ func (m *BaseAccount) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex - case 5: + case 6: if wireType != 0 { return fmt.Errorf("proto: wrong wireType = %d for field AccountNumber", wireType) } @@ -742,7 +797,7 @@ func (m *BaseAccount) Unmarshal(dAtA []byte) error { break } } - case 6: + case 7: if wireType != 0 { return fmt.Errorf("proto: wrong wireType = %d for field Sequence", wireType) } diff --git a/x/auth/types/common_test.go b/x/auth/types/common_test.go index 9900af5f0d..1773a0981c 100644 --- a/x/auth/types/common_test.go +++ b/x/auth/types/common_test.go @@ -6,5 +6,6 @@ import ( var ( app = simapp.Setup(false) - appCodec, legacyAmino = simapp.MakeCodecs() + ecdc = simapp.MakeTestEncodingConfig() + appCodec, legacyAmino = ecdc.Marshaler, ecdc.Amino ) diff --git a/x/auth/types/genesis.go b/x/auth/types/genesis.go index 57db523f49..626490c472 100644 --- a/x/auth/types/genesis.go +++ b/x/auth/types/genesis.go @@ -48,7 +48,7 @@ func DefaultGenesisState() *GenesisState { // GetGenesisStateFromAppState returns x/auth GenesisState given raw application // genesis state. -func GetGenesisStateFromAppState(cdc codec.Marshaler, appState map[string]json.RawMessage) GenesisState { +func GetGenesisStateFromAppState(cdc codec.Codec, appState map[string]json.RawMessage) GenesisState { var genesisState GenesisState if appState[ModuleName] != nil { @@ -110,7 +110,7 @@ type GenesisAccountIterator struct{} // appGenesis and invokes a callback on each genesis account. If any call // returns true, iteration stops. func (GenesisAccountIterator) IterateGenesisAccounts( - cdc codec.Marshaler, appGenesis map[string]json.RawMessage, cb func(AccountI) (stop bool), + cdc codec.Codec, appGenesis map[string]json.RawMessage, cb func(AccountI) (stop bool), ) { for _, genAcc := range GetGenesisStateFromAppState(cdc, appGenesis).Accounts { acc, ok := genAcc.GetCachedValue().(AccountI) diff --git a/x/auth/types/msgs.go b/x/auth/types/msgs.go index 058a2de8c2..e25e1372c2 100644 --- a/x/auth/types/msgs.go +++ b/x/auth/types/msgs.go @@ -18,13 +18,6 @@ func NewMsgEmpty(fromAddr sdk.AccAddress) *MsgEmpty { return &MsgEmpty{FromAddress: fromAddr.String()} } -func NewServiceMsgEmpty(fromAddr sdk.AccAddress) sdk.ServiceMsg { - return sdk.ServiceMsg{ - MethodName: "/lbm.auth.v1.Msg/Empty", - Request: NewMsgEmpty(fromAddr), - } -} - func (msg MsgEmpty) Route() string { return ModuleName } func (msg MsgEmpty) Type() string { return TypeMsgEmpty } diff --git a/x/auth/types/msgs_test.go b/x/auth/types/msgs_test.go index 62a18d3dd7..bbc4a5f9b5 100644 --- a/x/auth/types/msgs_test.go +++ b/x/auth/types/msgs_test.go @@ -13,18 +13,14 @@ import ( func TestMsgSendRoute(t *testing.T) { msg := NewMsgEmpty(sdk.AccAddress("from")) - require.Equal(t, ModuleName, msg.Route()) + require.Equal(t, RouterKey, msg.Route()) require.Equal(t, "empty", msg.Type()) - - srvMsg := NewServiceMsgEmpty(sdk.AccAddress("from")) - require.Equal(t, "/lbm.auth.v1.Msg/Empty", srvMsg.Route()) - require.Equal(t, "/lbm.auth.v1.Msg/Empty", srvMsg.Type()) } func TestMsgSendValidation(t *testing.T) { addr1 := sdk.BytesToAccAddress([]byte("from________________")) - addrEmpty := sdk.BytesToAccAddress([]byte("")) - addrTooLong := sdk.BytesToAccAddress([]byte("Accidentally used 33 bytes pubkey")) + addrEmpty := sdk.AccAddress("") + addrLong := sdk.BytesToAccAddress([]byte("Accidentally used 33 bytes pubkey")) cases := []struct { expectedErr string // empty means no error expected @@ -32,7 +28,7 @@ func TestMsgSendValidation(t *testing.T) { }{ {"", NewMsgEmpty(addr1)}, // valid {"Invalid sender address (empty address string is not allowed): invalid address", NewMsgEmpty(addrEmpty)}, - {"Invalid sender address (incorrect address length (expected: 20, actual: 33)): invalid address", NewMsgEmpty(addrTooLong)}, + {"", NewMsgEmpty(addrLong)}, } for _, tc := range cases { @@ -56,8 +52,4 @@ func TestMsgSendGetSigners(t *testing.T) { res := NewMsgEmpty(sdk.BytesToAccAddress([]byte("input111111111111111"))).GetSigners() bytes, _ := sdk.AccAddressToBytes(res[0].String()) require.Equal(t, fmt.Sprintf("%v", hex.EncodeToString(bytes)), "696e707574313131313131313131313131313131") - - require.Panics(t, func() { - NewMsgEmpty(sdk.BytesToAccAddress([]byte("input"))).GetSigners() - }) } diff --git a/x/auth/types/params.go b/x/auth/types/params.go index c0403f6f2a..b8e8221eb8 100644 --- a/x/auth/types/params.go +++ b/x/auth/types/params.go @@ -69,6 +69,16 @@ func DefaultParams() Params { } } +// SigVerifyCostSecp256r1 returns gas fee of secp256r1 signature verification. +// Set by benchmarking current implementation: +// BenchmarkSig/secp256k1 4334 277167 ns/op 4128 B/op 79 allocs/op +// BenchmarkSig/secp256r1 10000 108769 ns/op 1672 B/op 33 allocs/op +// Based on the results above secp256k1 is 2.7x is slwer. However we propose to discount it +// because we are we don't compare the cgo implementation of secp256k1, which is faster. +func (p Params) SigVerifyCostSecp256r1() uint64 { + return p.SigVerifyCostSecp256k1 / 2 +} + // String implements the stringer interface. func (p Params) String() string { out, _ := yaml.Marshal(p) diff --git a/x/auth/types/query.pb.go b/x/auth/types/query.pb.go index 7ab1f2a0f7..a14f5b9430 100644 --- a/x/auth/types/query.pb.go +++ b/x/auth/types/query.pb.go @@ -10,6 +10,7 @@ import ( grpc1 "github.com/gogo/protobuf/grpc" proto "github.com/gogo/protobuf/proto" types "github.com/line/lbm-sdk/codec/types" + query "github.com/line/lbm-sdk/types/query" _ "github.com/regen-network/cosmos-proto" _ "google.golang.org/genproto/googleapis/api/annotations" grpc "google.golang.org/grpc" @@ -31,6 +32,111 @@ var _ = math.Inf // proto package needs to be updated. const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package +// QueryAccountsRequest is the request type for the Query/Accounts RPC method. +// +// Since: cosmos-sdk 0.43 +type QueryAccountsRequest struct { + // pagination defines an optional pagination for the request. + Pagination *query.PageRequest `protobuf:"bytes,1,opt,name=pagination,proto3" json:"pagination,omitempty"` +} + +func (m *QueryAccountsRequest) Reset() { *m = QueryAccountsRequest{} } +func (m *QueryAccountsRequest) String() string { return proto.CompactTextString(m) } +func (*QueryAccountsRequest) ProtoMessage() {} +func (*QueryAccountsRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_a570ff87c0485f0a, []int{0} +} +func (m *QueryAccountsRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryAccountsRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryAccountsRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryAccountsRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryAccountsRequest.Merge(m, src) +} +func (m *QueryAccountsRequest) XXX_Size() int { + return m.Size() +} +func (m *QueryAccountsRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QueryAccountsRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryAccountsRequest proto.InternalMessageInfo + +func (m *QueryAccountsRequest) GetPagination() *query.PageRequest { + if m != nil { + return m.Pagination + } + return nil +} + +// QueryAccountsResponse is the response type for the Query/Accounts RPC method. +// +// Since: cosmos-sdk 0.43 +type QueryAccountsResponse struct { + // accounts are the existing accounts + Accounts []*types.Any `protobuf:"bytes,1,rep,name=accounts,proto3" json:"accounts,omitempty"` + // pagination defines the pagination in the response. + Pagination *query.PageResponse `protobuf:"bytes,2,opt,name=pagination,proto3" json:"pagination,omitempty"` +} + +func (m *QueryAccountsResponse) Reset() { *m = QueryAccountsResponse{} } +func (m *QueryAccountsResponse) String() string { return proto.CompactTextString(m) } +func (*QueryAccountsResponse) ProtoMessage() {} +func (*QueryAccountsResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_a570ff87c0485f0a, []int{1} +} +func (m *QueryAccountsResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryAccountsResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryAccountsResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryAccountsResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryAccountsResponse.Merge(m, src) +} +func (m *QueryAccountsResponse) XXX_Size() int { + return m.Size() +} +func (m *QueryAccountsResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryAccountsResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryAccountsResponse proto.InternalMessageInfo + +func (m *QueryAccountsResponse) GetAccounts() []*types.Any { + if m != nil { + return m.Accounts + } + return nil +} + +func (m *QueryAccountsResponse) GetPagination() *query.PageResponse { + if m != nil { + return m.Pagination + } + return nil +} + // QueryAccountRequest is the request type for the Query/Account RPC method. type QueryAccountRequest struct { // address defines the address to query for. @@ -41,7 +147,7 @@ func (m *QueryAccountRequest) Reset() { *m = QueryAccountRequest{} } func (m *QueryAccountRequest) String() string { return proto.CompactTextString(m) } func (*QueryAccountRequest) ProtoMessage() {} func (*QueryAccountRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_a570ff87c0485f0a, []int{0} + return fileDescriptor_a570ff87c0485f0a, []int{2} } func (m *QueryAccountRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -80,7 +186,7 @@ func (m *QueryAccountResponse) Reset() { *m = QueryAccountResponse{} } func (m *QueryAccountResponse) String() string { return proto.CompactTextString(m) } func (*QueryAccountResponse) ProtoMessage() {} func (*QueryAccountResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_a570ff87c0485f0a, []int{1} + return fileDescriptor_a570ff87c0485f0a, []int{3} } func (m *QueryAccountResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -124,7 +230,7 @@ func (m *QueryParamsRequest) Reset() { *m = QueryParamsRequest{} } func (m *QueryParamsRequest) String() string { return proto.CompactTextString(m) } func (*QueryParamsRequest) ProtoMessage() {} func (*QueryParamsRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_a570ff87c0485f0a, []int{2} + return fileDescriptor_a570ff87c0485f0a, []int{4} } func (m *QueryParamsRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -163,7 +269,7 @@ func (m *QueryParamsResponse) Reset() { *m = QueryParamsResponse{} } func (m *QueryParamsResponse) String() string { return proto.CompactTextString(m) } func (*QueryParamsResponse) ProtoMessage() {} func (*QueryParamsResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_a570ff87c0485f0a, []int{3} + return fileDescriptor_a570ff87c0485f0a, []int{5} } func (m *QueryParamsResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -200,6 +306,8 @@ func (m *QueryParamsResponse) GetParams() Params { } func init() { + proto.RegisterType((*QueryAccountsRequest)(nil), "lbm.auth.v1.QueryAccountsRequest") + proto.RegisterType((*QueryAccountsResponse)(nil), "lbm.auth.v1.QueryAccountsResponse") proto.RegisterType((*QueryAccountRequest)(nil), "lbm.auth.v1.QueryAccountRequest") proto.RegisterType((*QueryAccountResponse)(nil), "lbm.auth.v1.QueryAccountResponse") proto.RegisterType((*QueryParamsRequest)(nil), "lbm.auth.v1.QueryParamsRequest") @@ -209,33 +317,40 @@ func init() { func init() { proto.RegisterFile("lbm/auth/v1/query.proto", fileDescriptor_a570ff87c0485f0a) } var fileDescriptor_a570ff87c0485f0a = []byte{ - // 415 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x51, 0xbd, 0xee, 0xd3, 0x30, - 0x10, 0x4f, 0x10, 0xb4, 0x7f, 0x5c, 0x26, 0x37, 0x40, 0x09, 0x28, 0x69, 0x23, 0x24, 0x58, 0x6a, - 0xab, 0x65, 0x02, 0x21, 0xa4, 0x76, 0x82, 0x0d, 0x22, 0x26, 0x16, 0xe4, 0xa4, 0x26, 0x8d, 0x48, - 0xec, 0x34, 0x76, 0x0a, 0x15, 0x62, 0x61, 0x62, 0x44, 0xe2, 0x05, 0xfa, 0x10, 0x3c, 0x44, 0xc5, - 0x54, 0x89, 0x85, 0x09, 0xa1, 0x96, 0x01, 0xf1, 0x14, 0x28, 0xb6, 0x23, 0x35, 0xe2, 0x63, 0xf3, - 0xdd, 0xfd, 0xbe, 0xee, 0x0c, 0xae, 0x66, 0x51, 0x8e, 0x49, 0x25, 0x97, 0x78, 0x3d, 0xc1, 0xab, - 0x8a, 0x96, 0x1b, 0x54, 0x94, 0x5c, 0x72, 0xd8, 0xcb, 0xa2, 0x1c, 0xd5, 0x03, 0xb4, 0x9e, 0xb8, - 0x4e, 0xc2, 0x13, 0xae, 0xfa, 0xb8, 0x7e, 0x69, 0x88, 0x7b, 0x2d, 0xe1, 0x3c, 0xc9, 0x28, 0x56, - 0x55, 0x54, 0xbd, 0xc0, 0x84, 0x19, 0xb6, 0x7b, 0xc3, 0x8c, 0x48, 0x91, 0x62, 0xc2, 0x18, 0x97, - 0x44, 0xa6, 0x9c, 0x09, 0x33, 0xbd, 0x72, 0x6a, 0xaa, 0x3c, 0x8c, 0x60, 0xcc, 0x45, 0xce, 0xc5, - 0x73, 0xed, 0xa4, 0x0b, 0x3d, 0x0a, 0xee, 0x82, 0xfe, 0x93, 0x3a, 0xdd, 0x2c, 0x8e, 0x79, 0xc5, - 0x64, 0x48, 0x57, 0x15, 0x15, 0x12, 0x0e, 0x40, 0x97, 0x2c, 0x16, 0x25, 0x15, 0x62, 0x60, 0x0f, - 0xed, 0xdb, 0x17, 0xc3, 0xa6, 0xbc, 0x77, 0xf6, 0x7e, 0xeb, 0x5b, 0x3f, 0xb7, 0xbe, 0x15, 0x3c, - 0x05, 0x4e, 0x9b, 0x2a, 0x0a, 0xce, 0x04, 0x85, 0xf7, 0x41, 0x97, 0xe8, 0x96, 0xe2, 0xf6, 0xa6, - 0x0e, 0xd2, 0xa9, 0x51, 0xb3, 0x10, 0x9a, 0xb1, 0xcd, 0xfc, 0xd2, 0xe7, 0x4f, 0xe3, 0x33, 0xc3, - 0x7d, 0x14, 0x36, 0x94, 0xc0, 0x01, 0x50, 0xa9, 0x3e, 0x26, 0x25, 0xc9, 0x85, 0xc9, 0x13, 0x3c, - 0x34, 0x31, 0x9b, 0xae, 0xb1, 0x9a, 0x80, 0x4e, 0xa1, 0x3a, 0xc6, 0xa9, 0x8f, 0x4e, 0xae, 0x8b, - 0x34, 0x78, 0x7e, 0x7e, 0xf7, 0xcd, 0xb7, 0x42, 0x03, 0x9c, 0xfe, 0xb2, 0xc1, 0x05, 0x25, 0x05, - 0x5f, 0x81, 0xae, 0xb1, 0x87, 0xc3, 0x16, 0xef, 0x2f, 0x07, 0x71, 0x47, 0xff, 0x41, 0xe8, 0x30, - 0xc1, 0xad, 0x77, 0x5f, 0x7e, 0x7c, 0x3c, 0x37, 0x82, 0x3e, 0x6e, 0x7d, 0x83, 0x46, 0x09, 0xfc, - 0xc6, 0x5c, 0xf0, 0x2d, 0x5c, 0x82, 0x8e, 0x8e, 0x06, 0xfd, 0x3f, 0x55, 0x5b, 0x7b, 0xbb, 0xc3, - 0x7f, 0x03, 0x8c, 0xeb, 0x75, 0xe5, 0x7a, 0x19, 0xf6, 0x5b, 0xae, 0x7a, 0xd9, 0xf9, 0x83, 0xdd, - 0xc1, 0xb3, 0xf7, 0x07, 0xcf, 0xfe, 0x7e, 0xf0, 0xec, 0x0f, 0x47, 0xcf, 0xda, 0x1f, 0x3d, 0xeb, - 0xeb, 0xd1, 0xb3, 0x9e, 0xdd, 0x4c, 0x52, 0xb9, 0xac, 0x22, 0x14, 0xf3, 0x1c, 0x67, 0x29, 0xa3, - 0x35, 0x7b, 0x2c, 0x16, 0x2f, 0xf1, 0x6b, 0xad, 0x21, 0x37, 0x05, 0x15, 0x51, 0x47, 0xfd, 0xd8, - 0x9d, 0xdf, 0x01, 0x00, 0x00, 0xff, 0xff, 0x6e, 0x74, 0xd9, 0xf7, 0xce, 0x02, 0x00, 0x00, + // 526 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x52, 0x3f, 0x8f, 0xd3, 0x3c, + 0x18, 0x4f, 0xfa, 0xbe, 0xb4, 0xc5, 0x65, 0x72, 0x5b, 0xae, 0x04, 0x48, 0xda, 0x08, 0x89, 0x5b, + 0xce, 0x56, 0xcb, 0x04, 0x42, 0x45, 0xd7, 0x09, 0xb6, 0x23, 0x42, 0x0c, 0x2c, 0xc8, 0x69, 0x4d, + 0x1a, 0xd1, 0xc4, 0xb9, 0x3a, 0x29, 0x54, 0x88, 0x85, 0x89, 0x11, 0x89, 0x85, 0xf1, 0x3e, 0x04, + 0x1f, 0xe2, 0xc4, 0x74, 0x12, 0x0b, 0x03, 0x42, 0xa8, 0x65, 0xe0, 0x63, 0xa0, 0xd8, 0x4f, 0x8e, + 0x06, 0xae, 0x27, 0xb6, 0xd8, 0xfe, 0xfd, 0x7d, 0xf2, 0xa0, 0x9d, 0x99, 0x1f, 0x51, 0x96, 0xa5, + 0x53, 0xba, 0xe8, 0xd3, 0xc3, 0x8c, 0xcf, 0x97, 0x24, 0x99, 0x8b, 0x54, 0xe0, 0xc6, 0xcc, 0x8f, + 0x48, 0xfe, 0x40, 0x16, 0x7d, 0xcb, 0xcd, 0x51, 0x3e, 0x93, 0x5c, 0x43, 0x72, 0x6c, 0xc2, 0x82, + 0x30, 0x66, 0x69, 0x28, 0x62, 0x4d, 0xb0, 0x5a, 0x81, 0x08, 0x84, 0xfa, 0xa4, 0xf9, 0x17, 0xdc, + 0x5e, 0x09, 0x84, 0x08, 0x66, 0x9c, 0xaa, 0x93, 0x9f, 0x3d, 0xa3, 0x2c, 0x06, 0x07, 0xeb, 0x1a, + 0x3c, 0xb1, 0x24, 0xa4, 0x2c, 0x8e, 0x45, 0xaa, 0xd4, 0x24, 0xbc, 0x5e, 0xde, 0x0c, 0xa6, 0x72, + 0x80, 0xe0, 0x58, 0xc8, 0x48, 0xc8, 0xa7, 0xda, 0x49, 0x1f, 0xf4, 0x93, 0xfb, 0x18, 0xb5, 0x1e, + 0xe6, 0xf1, 0xf6, 0xc7, 0x63, 0x91, 0xc5, 0xa9, 0xf4, 0xf8, 0x61, 0xc6, 0x65, 0x8a, 0x87, 0x08, + 0xfd, 0x4e, 0xdb, 0x31, 0xbb, 0xe6, 0x6e, 0x63, 0x60, 0x93, 0xbc, 0x5f, 0x5e, 0x89, 0xe8, 0xd6, + 0x8b, 0x3e, 0x39, 0x60, 0x01, 0x07, 0x8e, 0xb7, 0xc1, 0x70, 0x3f, 0x98, 0xa8, 0xfd, 0x87, 0xb0, + 0x4c, 0x44, 0x2c, 0x39, 0x1e, 0xa2, 0x3a, 0x83, 0xbb, 0x8e, 0xd9, 0xfd, 0x6f, 0xb7, 0x31, 0x68, + 0x11, 0xdd, 0x8a, 0x14, 0x85, 0xc9, 0x7e, 0xbc, 0x1c, 0x5d, 0xfa, 0xf4, 0x71, 0xaf, 0x0e, 0xec, + 0x07, 0xde, 0x29, 0x07, 0xdf, 0x2b, 0x25, 0xab, 0xa8, 0x64, 0xce, 0xd6, 0x64, 0xda, 0xb4, 0x14, + 0xed, 0x36, 0x6a, 0x6e, 0x26, 0x2b, 0x1a, 0x77, 0x50, 0x8d, 0x4d, 0x26, 0x73, 0x2e, 0xa5, 0xaa, + 0x7b, 0xd1, 0x2b, 0x8e, 0x77, 0xea, 0x6f, 0x8f, 0x1c, 0xe3, 0xe7, 0x91, 0x63, 0xb8, 0x8f, 0xca, + 0xd3, 0x3a, 0xed, 0x74, 0x17, 0xd5, 0x20, 0x1f, 0x8c, 0xea, 0x5f, 0x2a, 0x15, 0x14, 0xb7, 0x85, + 0xb0, 0x52, 0x3d, 0x60, 0x73, 0x16, 0x15, 0x7f, 0xc0, 0xbd, 0x0f, 0x31, 0x8b, 0x5b, 0xb0, 0xea, + 0xa3, 0x6a, 0xa2, 0x6e, 0xc0, 0xa9, 0x49, 0x36, 0x96, 0x8e, 0x68, 0xf0, 0xe8, 0xff, 0xe3, 0x6f, + 0x8e, 0xe1, 0x01, 0x70, 0xf0, 0xb5, 0x82, 0x2e, 0x28, 0x29, 0x9c, 0xa0, 0xc2, 0x5e, 0xe2, 0x5e, + 0x89, 0x78, 0xd6, 0x12, 0x58, 0xee, 0x79, 0x10, 0x9d, 0xc7, 0xbd, 0xfe, 0xe6, 0xf3, 0x8f, 0xf7, + 0x95, 0x1d, 0xdc, 0xa6, 0xa5, 0xe5, 0x2b, 0x5c, 0x5e, 0xa0, 0x1a, 0x50, 0x70, 0x77, 0xab, 0x5a, + 0xe1, 0xd7, 0x3b, 0x07, 0x01, 0x76, 0x37, 0x95, 0x5d, 0x0f, 0x3b, 0x67, 0xda, 0xd1, 0x57, 0xf0, + 0xcf, 0x5e, 0xe3, 0x29, 0xaa, 0xea, 0x61, 0x60, 0xe7, 0x6f, 0xd5, 0xd2, 0xa4, 0xad, 0xee, 0x76, + 0x00, 0xb8, 0x5e, 0x55, 0xae, 0x6d, 0xdc, 0x2c, 0xb9, 0xea, 0xf1, 0x8e, 0x86, 0xc7, 0x2b, 0xdb, + 0x3c, 0x59, 0xd9, 0xe6, 0xf7, 0x95, 0x6d, 0xbe, 0x5b, 0xdb, 0xc6, 0xc9, 0xda, 0x36, 0xbe, 0xac, + 0x6d, 0xe3, 0xc9, 0x8d, 0x20, 0x4c, 0xa7, 0x99, 0x4f, 0xc6, 0x22, 0xa2, 0xb3, 0x30, 0xe6, 0x39, + 0x7b, 0x4f, 0x4e, 0x9e, 0xd3, 0x97, 0x5a, 0x23, 0x5d, 0x26, 0x5c, 0xfa, 0x55, 0xb5, 0x23, 0xb7, + 0x7e, 0x05, 0x00, 0x00, 0xff, 0xff, 0x33, 0xa4, 0x7b, 0x02, 0x57, 0x04, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -250,6 +365,10 @@ const _ = grpc.SupportPackageIsVersion4 // // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. type QueryClient interface { + // Accounts returns all the existing accounts + // + // Since: cosmos-sdk 0.43 + Accounts(ctx context.Context, in *QueryAccountsRequest, opts ...grpc.CallOption) (*QueryAccountsResponse, error) // Account returns account details based on address. Account(ctx context.Context, in *QueryAccountRequest, opts ...grpc.CallOption) (*QueryAccountResponse, error) // Params queries all parameters. @@ -264,6 +383,15 @@ func NewQueryClient(cc grpc1.ClientConn) QueryClient { return &queryClient{cc} } +func (c *queryClient) Accounts(ctx context.Context, in *QueryAccountsRequest, opts ...grpc.CallOption) (*QueryAccountsResponse, error) { + out := new(QueryAccountsResponse) + err := c.cc.Invoke(ctx, "/lbm.auth.v1.Query/Accounts", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + func (c *queryClient) Account(ctx context.Context, in *QueryAccountRequest, opts ...grpc.CallOption) (*QueryAccountResponse, error) { out := new(QueryAccountResponse) err := c.cc.Invoke(ctx, "/lbm.auth.v1.Query/Account", in, out, opts...) @@ -284,6 +412,10 @@ func (c *queryClient) Params(ctx context.Context, in *QueryParamsRequest, opts . // QueryServer is the server API for Query service. type QueryServer interface { + // Accounts returns all the existing accounts + // + // Since: cosmos-sdk 0.43 + Accounts(context.Context, *QueryAccountsRequest) (*QueryAccountsResponse, error) // Account returns account details based on address. Account(context.Context, *QueryAccountRequest) (*QueryAccountResponse, error) // Params queries all parameters. @@ -294,6 +426,9 @@ type QueryServer interface { type UnimplementedQueryServer struct { } +func (*UnimplementedQueryServer) Accounts(ctx context.Context, req *QueryAccountsRequest) (*QueryAccountsResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Accounts not implemented") +} func (*UnimplementedQueryServer) Account(ctx context.Context, req *QueryAccountRequest) (*QueryAccountResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method Account not implemented") } @@ -305,6 +440,24 @@ func RegisterQueryServer(s grpc1.Server, srv QueryServer) { s.RegisterService(&_Query_serviceDesc, srv) } +func _Query_Accounts_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryAccountsRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).Accounts(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/lbm.auth.v1.Query/Accounts", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).Accounts(ctx, req.(*QueryAccountsRequest)) + } + return interceptor(ctx, in, info, handler) +} + func _Query_Account_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(QueryAccountRequest) if err := dec(in); err != nil { @@ -345,6 +498,10 @@ var _Query_serviceDesc = grpc.ServiceDesc{ ServiceName: "lbm.auth.v1.Query", HandlerType: (*QueryServer)(nil), Methods: []grpc.MethodDesc{ + { + MethodName: "Accounts", + Handler: _Query_Accounts_Handler, + }, { MethodName: "Account", Handler: _Query_Account_Handler, @@ -358,6 +515,90 @@ var _Query_serviceDesc = grpc.ServiceDesc{ Metadata: "lbm/auth/v1/query.proto", } +func (m *QueryAccountsRequest) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryAccountsRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryAccountsRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Pagination != nil { + { + size, err := m.Pagination.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *QueryAccountsResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryAccountsResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryAccountsResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Pagination != nil { + { + size, err := m.Pagination.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + if len(m.Accounts) > 0 { + for iNdEx := len(m.Accounts) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Accounts[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + func (m *QueryAccountRequest) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -490,6 +731,38 @@ func encodeVarintQuery(dAtA []byte, offset int, v uint64) int { dAtA[offset] = uint8(v) return base } +func (m *QueryAccountsRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Pagination != nil { + l = m.Pagination.Size() + n += 1 + l + sovQuery(uint64(l)) + } + return n +} + +func (m *QueryAccountsResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.Accounts) > 0 { + for _, e := range m.Accounts { + l = e.Size() + n += 1 + l + sovQuery(uint64(l)) + } + } + if m.Pagination != nil { + l = m.Pagination.Size() + n += 1 + l + sovQuery(uint64(l)) + } + return n +} + func (m *QueryAccountRequest) Size() (n int) { if m == nil { return 0 @@ -542,6 +815,212 @@ func sovQuery(x uint64) (n int) { func sozQuery(x uint64) (n int) { return sovQuery(uint64((x << 1) ^ uint64((int64(x) >> 63)))) } +func (m *QueryAccountsRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryAccountsRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryAccountsRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Pagination", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Pagination == nil { + m.Pagination = &query.PageRequest{} + } + if err := m.Pagination.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryAccountsResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryAccountsResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryAccountsResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Accounts", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Accounts = append(m.Accounts, &types.Any{}) + if err := m.Accounts[len(m.Accounts)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Pagination", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Pagination == nil { + m.Pagination = &query.PageResponse{} + } + if err := m.Pagination.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func (m *QueryAccountRequest) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 diff --git a/x/auth/types/query.pb.gw.go b/x/auth/types/query.pb.gw.go index 6850edd09c..a0b4472472 100644 --- a/x/auth/types/query.pb.gw.go +++ b/x/auth/types/query.pb.gw.go @@ -31,6 +31,42 @@ var _ = runtime.String var _ = utilities.NewDoubleArray var _ = descriptor.ForMessage +var ( + filter_Query_Accounts_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)} +) + +func request_Query_Accounts_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryAccountsRequest + var metadata runtime.ServerMetadata + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_Accounts_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := client.Accounts(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_Accounts_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryAccountsRequest + var metadata runtime.ServerMetadata + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_Accounts_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := server.Accounts(ctx, &protoReq) + return msg, metadata, err + +} + func request_Query_Account_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { var protoReq QueryAccountRequest var metadata runtime.ServerMetadata @@ -109,6 +145,26 @@ func local_request_Query_Params_0(ctx context.Context, marshaler runtime.Marshal // Note that using this registration option will cause many gRPC library features (such as grpc.SendHeader, etc) to stop working. Consider using RegisterQueryHandlerFromEndpoint instead. func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, server QueryServer) error { + mux.Handle("GET", pattern_Query_Accounts_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_Query_Accounts_0(rctx, inboundMarshaler, server, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_Accounts_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + mux.Handle("GET", pattern_Query_Account_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() @@ -190,6 +246,26 @@ func RegisterQueryHandler(ctx context.Context, mux *runtime.ServeMux, conn *grpc // "QueryClient" to call the correct interceptors. func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, client QueryClient) error { + mux.Handle("GET", pattern_Query_Accounts_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_Query_Accounts_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_Accounts_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + mux.Handle("GET", pattern_Query_Account_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() @@ -234,12 +310,16 @@ func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, clie } var ( - pattern_Query_Account_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4}, []string{"lbm", "auth", "v1", "accounts", "address"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_Query_Accounts_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"lbm", "auth", "v1", "accounts"}, "", runtime.AssumeColonVerbOpt(false))) + + pattern_Query_Account_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4}, []string{"lbm", "auth", "v1", "accounts", "address"}, "", runtime.AssumeColonVerbOpt(false))) - pattern_Query_Params_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"lbm", "auth", "v1", "params"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_Query_Params_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"lbm", "auth", "v1", "params"}, "", runtime.AssumeColonVerbOpt(false))) ) var ( + forward_Query_Accounts_0 = runtime.ForwardResponseMessage + forward_Query_Account_0 = runtime.ForwardResponseMessage forward_Query_Params_0 = runtime.ForwardResponseMessage diff --git a/x/auth/vesting/client/cli/tx.go b/x/auth/vesting/client/cli/tx.go index a6a9736c3c..4eb4552130 100644 --- a/x/auth/vesting/client/cli/tx.go +++ b/x/auth/vesting/client/cli/tx.go @@ -66,9 +66,6 @@ timestamp.`, delayed, _ := cmd.Flags().GetBool(FlagDelayed) msg := types.NewMsgCreateVestingAccount(clientCtx.GetFromAddress(), toAddr, amount, endTime, delayed) - if err := msg.ValidateBasic(); err != nil { - return err - } return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) }, diff --git a/x/auth/vesting/client/testutil/cli_test.go b/x/auth/vesting/client/testutil/cli_test.go new file mode 100644 index 0000000000..8ded31fefa --- /dev/null +++ b/x/auth/vesting/client/testutil/cli_test.go @@ -0,0 +1,18 @@ +//go:build norace +// +build norace + +package testutil + +import ( + "testing" + + "github.com/line/lbm-sdk/testutil/network" + + "github.com/stretchr/testify/suite" +) + +func TestIntegrationTestSuite(t *testing.T) { + cfg := network.DefaultConfig() + cfg.NumValidators = 1 + suite.Run(t, NewIntegrationTestSuite(cfg)) +} diff --git a/x/auth/vesting/client/cli/cli_test.go b/x/auth/vesting/client/testutil/suite.go similarity index 91% rename from x/auth/vesting/client/cli/cli_test.go rename to x/auth/vesting/client/testutil/suite.go index 54dde85171..c14d782c72 100644 --- a/x/auth/vesting/client/cli/cli_test.go +++ b/x/auth/vesting/client/testutil/suite.go @@ -1,10 +1,7 @@ -// +build norace - -package cli_test +package testutil import ( "fmt" - "testing" "github.com/gogo/protobuf/proto" "github.com/stretchr/testify/suite" @@ -23,14 +20,14 @@ type IntegrationTestSuite struct { network *network.Network } +func NewIntegrationTestSuite(cfg network.Config) *IntegrationTestSuite { + return &IntegrationTestSuite{cfg: cfg} +} + func (s *IntegrationTestSuite) SetupSuite() { s.T().Log("setting up integration test suite") - cfg := network.DefaultConfig() - cfg.NumValidators = 1 - - s.cfg = cfg - s.network = network.New(s.T(), cfg) + s.network = network.New(s.T(), s.cfg) _, err := s.network.WaitForHeight(1) s.Require().NoError(err) @@ -47,8 +44,8 @@ func (s *IntegrationTestSuite) TestNewMsgCreateVestingAccountCmd() { testCases := map[string]struct { args []string expectErr bool - respType proto.Message expectedCode uint32 + respType proto.Message }{ "create a continuous vesting account": { args: []string{ @@ -61,8 +58,8 @@ func (s *IntegrationTestSuite) TestNewMsgCreateVestingAccountCmd() { fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), }, expectErr: false, - respType: &sdk.TxResponse{}, expectedCode: 0, + respType: &sdk.TxResponse{}, }, "create a delayed vesting account": { args: []string{ @@ -76,8 +73,8 @@ func (s *IntegrationTestSuite) TestNewMsgCreateVestingAccountCmd() { fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), }, expectErr: false, - respType: &sdk.TxResponse{}, expectedCode: 0, + respType: &sdk.TxResponse{}, }, "invalid address": { args: []string{ @@ -87,8 +84,8 @@ func (s *IntegrationTestSuite) TestNewMsgCreateVestingAccountCmd() { fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address), }, expectErr: true, - respType: &sdk.TxResponse{}, expectedCode: 0, + respType: &sdk.TxResponse{}, }, "invalid coins": { args: []string{ @@ -98,8 +95,8 @@ func (s *IntegrationTestSuite) TestNewMsgCreateVestingAccountCmd() { fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address), }, expectErr: true, - respType: &sdk.TxResponse{}, expectedCode: 0, + respType: &sdk.TxResponse{}, }, "invalid end time": { args: []string{ @@ -109,8 +106,8 @@ func (s *IntegrationTestSuite) TestNewMsgCreateVestingAccountCmd() { fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address), }, expectErr: true, - respType: &sdk.TxResponse{}, expectedCode: 0, + respType: &sdk.TxResponse{}, }, } @@ -125,7 +122,7 @@ func (s *IntegrationTestSuite) TestNewMsgCreateVestingAccountCmd() { s.Require().Error(err) } else { s.Require().NoError(err) - s.Require().NoError(clientCtx.JSONMarshaler.UnmarshalJSON(bw.Bytes(), tc.respType), bw.String()) + s.Require().NoError(clientCtx.Codec.UnmarshalJSON(bw.Bytes(), tc.respType), bw.String()) txResp := tc.respType.(*sdk.TxResponse) s.Require().Equal(tc.expectedCode, txResp.Code) @@ -133,7 +130,3 @@ func (s *IntegrationTestSuite) TestNewMsgCreateVestingAccountCmd() { }) } } - -func TestIntegrationTestSuite(t *testing.T) { - suite.Run(t, new(IntegrationTestSuite)) -} diff --git a/x/auth/vesting/exported/exported.go b/x/auth/vesting/exported/exported.go index 82f540bda8..fe2f16137a 100644 --- a/x/auth/vesting/exported/exported.go +++ b/x/auth/vesting/exported/exported.go @@ -12,7 +12,8 @@ import ( type VestingAccount interface { types.AccountI - // LockedCoins returns the set of coins that are not spendable (i.e. locked). + // LockedCoins returns the set of coins that are not spendable (i.e. locked), + // defined as the vesting coins that are not delegated. // // To get spendable coins of a vesting account, first the total balance must // be retrieved and the locked tokens can be subtracted from the total balance. diff --git a/x/auth/vesting/handler_test.go b/x/auth/vesting/handler_test.go index 4495f87b3d..5d6c900d2b 100644 --- a/x/auth/vesting/handler_test.go +++ b/x/auth/vesting/handler_test.go @@ -37,7 +37,7 @@ func (suite *HandlerTestSuite) TestMsgCreateVestingAccount() { acc1 := suite.app.AccountKeeper.NewAccountWithAddress(ctx, addr1) suite.app.AccountKeeper.SetAccount(ctx, acc1) - suite.Require().NoError(suite.app.BankKeeper.SetBalances(ctx, addr1, balances)) + suite.Require().NoError(simapp.FundAccount(suite.app, ctx, addr1, balances)) testCases := []struct { name string diff --git a/x/auth/vesting/module.go b/x/auth/vesting/module.go index d3e6241095..3290e25093 100644 --- a/x/auth/vesting/module.go +++ b/x/auth/vesting/module.go @@ -45,12 +45,12 @@ func (AppModuleBasic) RegisterInterfaces(registry codectypes.InterfaceRegistry) } // DefaultGenesis returns the module's default genesis state as raw bytes. -func (AppModuleBasic) DefaultGenesis(_ codec.JSONMarshaler) json.RawMessage { +func (AppModuleBasic) DefaultGenesis(_ codec.JSONCodec) json.RawMessage { return []byte("{}") } // ValidateGenesis performs genesis state validation. Currently, this is a no-op. -func (AppModuleBasic) ValidateGenesis(_ codec.JSONMarshaler, _ client.TxEncodingConfig, bz json.RawMessage) error { +func (AppModuleBasic) ValidateGenesis(_ codec.JSONCodec, _ client.TxEncodingConfig, bz json.RawMessage) error { return nil } @@ -111,7 +111,7 @@ func (am AppModule) LegacyQuerierHandler(_ *codec.LegacyAmino) sdk.Querier { } // InitGenesis performs a no-op. -func (am AppModule) InitGenesis(_ sdk.Context, _ codec.JSONMarshaler, _ json.RawMessage) []abci.ValidatorUpdate { +func (am AppModule) InitGenesis(_ sdk.Context, _ codec.JSONCodec, _ json.RawMessage) []abci.ValidatorUpdate { return []abci.ValidatorUpdate{} } @@ -124,7 +124,7 @@ func (am AppModule) EndBlock(_ sdk.Context, _ abci.RequestEndBlock) []abci.Valid } // ExportGenesis is always empty, as InitGenesis does nothing either. -func (am AppModule) ExportGenesis(_ sdk.Context, cdc codec.JSONMarshaler) json.RawMessage { +func (am AppModule) ExportGenesis(_ sdk.Context, cdc codec.JSONCodec) json.RawMessage { return am.DefaultGenesis(cdc) } diff --git a/x/auth/vesting/msg_server.go b/x/auth/vesting/msg_server.go index edfde394fb..2a1f8d8a56 100644 --- a/x/auth/vesting/msg_server.go +++ b/x/auth/vesting/msg_server.go @@ -32,7 +32,7 @@ func (s msgServer) CreateVestingAccount(goCtx context.Context, msg *types.MsgCre ak := s.AccountKeeper bk := s.BankKeeper - if err := bk.SendEnabledCoins(ctx, msg.Amount...); err != nil { + if err := bk.IsSendEnabledCoins(ctx, msg.Amount...); err != nil { return nil, err } diff --git a/x/auth/vesting/types/codec.go b/x/auth/vesting/types/codec.go index f21d30edfb..3cee822277 100644 --- a/x/auth/vesting/types/codec.go +++ b/x/auth/vesting/types/codec.go @@ -17,6 +17,7 @@ func RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) { cdc.RegisterConcrete(&ContinuousVestingAccount{}, "lbm-sdk/ContinuousVestingAccount", nil) cdc.RegisterConcrete(&DelayedVestingAccount{}, "lbm-sdk/DelayedVestingAccount", nil) cdc.RegisterConcrete(&PeriodicVestingAccount{}, "lbm-sdk/PeriodicVestingAccount", nil) + cdc.RegisterConcrete(&PermanentLockedAccount{}, "lbm-sdk/PermanentLockedAccount", nil) } // RegisterInterface associates protoName with AccountI and VestingAccount @@ -28,6 +29,7 @@ func RegisterInterfaces(registry types.InterfaceRegistry) { &ContinuousVestingAccount{}, &DelayedVestingAccount{}, &PeriodicVestingAccount{}, + &PermanentLockedAccount{}, ) registry.RegisterImplementations( @@ -36,6 +38,7 @@ func RegisterInterfaces(registry types.InterfaceRegistry) { &DelayedVestingAccount{}, &ContinuousVestingAccount{}, &PeriodicVestingAccount{}, + &PermanentLockedAccount{}, ) registry.RegisterImplementations( @@ -44,6 +47,7 @@ func RegisterInterfaces(registry types.InterfaceRegistry) { &DelayedVestingAccount{}, &ContinuousVestingAccount{}, &PeriodicVestingAccount{}, + &PermanentLockedAccount{}, ) registry.RegisterImplementations( diff --git a/x/auth/vesting/types/common_test.go b/x/auth/vesting/types/common_test.go index 0b49c46ea0..43d1fa8e2f 100644 --- a/x/auth/vesting/types/common_test.go +++ b/x/auth/vesting/types/common_test.go @@ -5,6 +5,5 @@ import ( ) var ( - app = simapp.Setup(false) - appCodec, _ = simapp.MakeCodecs() + app = simapp.Setup(false) ) diff --git a/x/auth/vesting/types/expected_keepers.go b/x/auth/vesting/types/expected_keepers.go index 2a446f5725..e48e4a27a0 100644 --- a/x/auth/vesting/types/expected_keepers.go +++ b/x/auth/vesting/types/expected_keepers.go @@ -7,7 +7,7 @@ import ( // BankKeeper defines the expected interface contract the vesting module requires // for creating vesting accounts with funds. type BankKeeper interface { - SendEnabledCoins(ctx sdk.Context, coins ...sdk.Coin) error + IsSendEnabledCoins(ctx sdk.Context, coins ...sdk.Coin) error SendCoins(ctx sdk.Context, fromAddr sdk.AccAddress, toAddr sdk.AccAddress, amt sdk.Coins) error BlockedAddr(addr sdk.AccAddress) bool } diff --git a/x/auth/vesting/types/vesting.pb.go b/x/auth/vesting/types/vesting.pb.go index e24b0a3e74..61d7abc005 100644 --- a/x/auth/vesting/types/vesting.pb.go +++ b/x/auth/vesting/types/vesting.pb.go @@ -238,55 +238,98 @@ func (m *PeriodicVestingAccount) XXX_DiscardUnknown() { var xxx_messageInfo_PeriodicVestingAccount proto.InternalMessageInfo +// PermanentLockedAccount implements the VestingAccount interface. It does +// not ever release coins, locking them indefinitely. Coins in this account can +// still be used for delegating and for governance votes even while locked. +// +// Since: cosmos-sdk 0.43 +type PermanentLockedAccount struct { + *BaseVestingAccount `protobuf:"bytes,1,opt,name=base_vesting_account,json=baseVestingAccount,proto3,embedded=base_vesting_account" json:"base_vesting_account,omitempty"` +} + +func (m *PermanentLockedAccount) Reset() { *m = PermanentLockedAccount{} } +func (*PermanentLockedAccount) ProtoMessage() {} +func (*PermanentLockedAccount) Descriptor() ([]byte, []int) { + return fileDescriptor_d51097c8d6ee5396, []int{5} +} +func (m *PermanentLockedAccount) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *PermanentLockedAccount) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_PermanentLockedAccount.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *PermanentLockedAccount) XXX_Merge(src proto.Message) { + xxx_messageInfo_PermanentLockedAccount.Merge(m, src) +} +func (m *PermanentLockedAccount) XXX_Size() int { + return m.Size() +} +func (m *PermanentLockedAccount) XXX_DiscardUnknown() { + xxx_messageInfo_PermanentLockedAccount.DiscardUnknown(m) +} + +var xxx_messageInfo_PermanentLockedAccount proto.InternalMessageInfo + func init() { proto.RegisterType((*BaseVestingAccount)(nil), "lbm.vesting.v1.BaseVestingAccount") proto.RegisterType((*ContinuousVestingAccount)(nil), "lbm.vesting.v1.ContinuousVestingAccount") proto.RegisterType((*DelayedVestingAccount)(nil), "lbm.vesting.v1.DelayedVestingAccount") proto.RegisterType((*Period)(nil), "lbm.vesting.v1.Period") proto.RegisterType((*PeriodicVestingAccount)(nil), "lbm.vesting.v1.PeriodicVestingAccount") + proto.RegisterType((*PermanentLockedAccount)(nil), "lbm.vesting.v1.PermanentLockedAccount") } func init() { proto.RegisterFile("lbm/vesting/v1/vesting.proto", fileDescriptor_d51097c8d6ee5396) } var fileDescriptor_d51097c8d6ee5396 = []byte{ - // 584 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0x94, 0x3f, 0x6f, 0xd3, 0x40, - 0x18, 0xc6, 0xed, 0x24, 0x84, 0x72, 0x81, 0xa4, 0x31, 0x4d, 0xb0, 0x2a, 0x64, 0x47, 0x66, 0x89, - 0x04, 0xd8, 0x4a, 0x61, 0xca, 0x56, 0xb7, 0x0a, 0x2b, 0xb2, 0x50, 0x87, 0x2e, 0x91, 0x1d, 0x1f, - 0xce, 0x09, 0xdb, 0x17, 0xd9, 0x97, 0x88, 0x0c, 0x74, 0x42, 0x82, 0x91, 0x05, 0x89, 0xb1, 0x62, - 0xe4, 0x03, 0xf0, 0x19, 0x3a, 0x66, 0x64, 0x0a, 0x28, 0xf9, 0x06, 0xf9, 0x04, 0xe8, 0xfe, 0x38, - 0x69, 0x5d, 0x45, 0x2a, 0x0b, 0xea, 0x64, 0xdf, 0x7b, 0xf7, 0x3e, 0xef, 0xef, 0xde, 0x7b, 0xee, - 0xc0, 0xe3, 0xd0, 0x8b, 0xac, 0x09, 0x4c, 0x09, 0x8a, 0x03, 0x6b, 0xd2, 0xc9, 0x7e, 0xcd, 0x51, - 0x82, 0x09, 0x56, 0xaa, 0xa1, 0x17, 0x99, 0x59, 0x68, 0xd2, 0xd9, 0xdf, 0x0b, 0x70, 0x80, 0xd9, - 0x94, 0x45, 0xff, 0xf8, 0xaa, 0xfd, 0x26, 0xd5, 0xf0, 0xdc, 0x14, 0x52, 0x81, 0x01, 0x46, 0xf1, - 0xe5, 0xb8, 0x3b, 0x26, 0x43, 0x1a, 0xa7, 0x5f, 0x1e, 0x37, 0xbe, 0x97, 0x80, 0x62, 0xbb, 0x29, - 0x3c, 0xe1, 0xc2, 0x87, 0x83, 0x01, 0x1e, 0xc7, 0x44, 0x39, 0x04, 0xf7, 0xa9, 0x48, 0xdf, 0xe5, - 0x63, 0x55, 0x6e, 0xc9, 0xed, 0xca, 0x81, 0x6a, 0x52, 0x06, 0x96, 0x3d, 0xe9, 0x98, 0x34, 0x4d, - 0xac, 0xb7, 0x4b, 0xb3, 0xb9, 0x2e, 0x3b, 0x15, 0x6f, 0x13, 0x52, 0x3e, 0xca, 0x60, 0x17, 0x27, - 0x28, 0x40, 0xb1, 0x1b, 0xf6, 0x05, 0xb7, 0x5a, 0x68, 0x15, 0xdb, 0x95, 0x83, 0x3a, 0xd3, 0xa1, - 0x8b, 0xa9, 0xce, 0x11, 0x46, 0xb1, 0xdd, 0xbb, 0x98, 0xeb, 0xd2, 0x6a, 0xae, 0x3f, 0x9a, 0xba, - 0x51, 0xd8, 0x35, 0xf2, 0x89, 0xc6, 0x8f, 0xdf, 0xfa, 0x93, 0x00, 0x91, 0xe1, 0xd8, 0x33, 0x07, - 0x38, 0xb2, 0x42, 0x14, 0x43, 0x2b, 0xf4, 0xa2, 0xe7, 0xa9, 0xff, 0xce, 0x22, 0xd3, 0x11, 0x4c, - 0x99, 0x4c, 0xea, 0xd4, 0xb2, 0x4c, 0xb1, 0x21, 0xe5, 0x0c, 0x54, 0x7d, 0x18, 0xc2, 0xc0, 0x25, - 0xd0, 0xef, 0xbf, 0x4d, 0x20, 0x54, 0x8b, 0xdb, 0x18, 0x8e, 0x05, 0x43, 0x83, 0x33, 0x5c, 0x4d, - 0xbb, 0x31, 0xc1, 0x83, 0x75, 0x5e, 0x2f, 0x81, 0x50, 0xf9, 0x24, 0x83, 0xfa, 0x46, 0x29, 0xeb, - 0x43, 0x69, 0x1b, 0xc3, 0x2b, 0xc1, 0xa0, 0xe6, 0x19, 0xfe, 0xb5, 0x11, 0xbb, 0xeb, 0xd4, 0xac, - 0x13, 0x26, 0xd8, 0x81, 0xb1, 0xdf, 0x27, 0x28, 0x82, 0xea, 0x9d, 0x96, 0xdc, 0x2e, 0xda, 0x0f, - 0x57, 0x73, 0xbd, 0xc6, 0x0b, 0x65, 0x33, 0x86, 0x73, 0x17, 0xc6, 0xfe, 0x1b, 0x14, 0xc1, 0xee, - 0xce, 0xe7, 0x73, 0x5d, 0xfa, 0x76, 0xae, 0x4b, 0xc6, 0x4f, 0x19, 0xa8, 0x47, 0x38, 0x26, 0x28, - 0x1e, 0xe3, 0x71, 0x9a, 0xb3, 0xca, 0x29, 0xd8, 0x63, 0x56, 0x11, 0x80, 0x39, 0xcb, 0x18, 0xe6, - 0x55, 0xdb, 0x9a, 0xd7, 0xcd, 0x26, 0xcc, 0xa3, 0x78, 0xd7, 0x6d, 0xf8, 0x12, 0x80, 0x94, 0xb8, - 0x09, 0xe1, 0xd0, 0x05, 0x06, 0xdd, 0x58, 0xcd, 0xf5, 0x3a, 0x87, 0xde, 0xcc, 0x19, 0xce, 0x3d, - 0x36, 0xc8, 0x81, 0x7f, 0x00, 0x8d, 0x63, 0x18, 0xba, 0xd3, 0x75, 0x13, 0xfe, 0x03, 0xf4, 0xa5, - 0xf2, 0x67, 0xa0, 0xfc, 0x1a, 0x26, 0x08, 0xfb, 0x4a, 0x13, 0x94, 0x43, 0x18, 0x07, 0x64, 0xc8, - 0x2a, 0x14, 0x1d, 0x31, 0x52, 0x4e, 0x40, 0xd9, 0x8d, 0x58, 0xe5, 0xad, 0x37, 0xe3, 0x29, 0x75, - 0xc4, 0x4d, 0x4f, 0x5d, 0xa8, 0x75, 0x4b, 0xac, 0xfe, 0xd7, 0x02, 0x68, 0x72, 0x00, 0x34, 0xb8, - 0xed, 0xa7, 0xa6, 0xf4, 0x41, 0x2d, 0x83, 0x19, 0x31, 0xe6, 0x54, 0xdc, 0xd4, 0x66, 0x1e, 0x86, - 0x6f, 0xc9, 0xd6, 0xc4, 0x55, 0x69, 0x72, 0xd9, 0x5c, 0xb2, 0xe1, 0x54, 0x45, 0x84, 0x2f, 0x4f, - 0x37, 0xe7, 0x62, 0xf7, 0x2e, 0x16, 0x9a, 0x3c, 0x5b, 0x68, 0xf2, 0x9f, 0x85, 0x26, 0x7f, 0x59, - 0x6a, 0xd2, 0x6c, 0xa9, 0x49, 0xbf, 0x96, 0x9a, 0x74, 0xfa, 0x6c, 0x5b, 0x93, 0xdf, 0x8b, 0xc7, - 0x53, 0xbc, 0xce, 0xac, 0xe7, 0x5e, 0x99, 0xbd, 0xa1, 0x2f, 0xfe, 0x06, 0x00, 0x00, 0xff, 0xff, - 0x7d, 0xca, 0xd0, 0x24, 0xb9, 0x05, 0x00, 0x00, + // 601 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0x95, 0x3d, 0x6f, 0xd3, 0x40, + 0x18, 0xc7, 0xed, 0x26, 0x84, 0x72, 0x85, 0xbe, 0x98, 0x36, 0x58, 0x15, 0xb2, 0x2b, 0xb3, 0x54, + 0x02, 0x6c, 0xa5, 0x30, 0x65, 0xab, 0x5b, 0x85, 0x85, 0x01, 0x59, 0xa8, 0x43, 0x97, 0xc8, 0x2f, + 0x87, 0x73, 0xaa, 0x7d, 0x17, 0xd9, 0x97, 0x88, 0x0c, 0x74, 0x42, 0x82, 0x91, 0x05, 0x89, 0xb1, + 0x62, 0xe4, 0x03, 0xf0, 0x19, 0x3a, 0x66, 0x64, 0x0a, 0x28, 0xf9, 0x06, 0xf9, 0x04, 0xe8, 0x5e, + 0x9c, 0x34, 0xae, 0x22, 0x95, 0xa5, 0x62, 0x8a, 0xef, 0xb9, 0x7b, 0xfe, 0xcf, 0xcf, 0xcf, 0xf3, + 0x3f, 0x07, 0x3c, 0x4e, 0x82, 0xd4, 0xe9, 0xc3, 0x9c, 0x22, 0x1c, 0x3b, 0xfd, 0x46, 0xf1, 0x68, + 0x77, 0x33, 0x42, 0x89, 0xb6, 0x9e, 0x04, 0xa9, 0x5d, 0x84, 0xfa, 0x8d, 0xdd, 0xed, 0x98, 0xc4, + 0x84, 0x6f, 0x39, 0xec, 0x49, 0x9c, 0xda, 0xad, 0x33, 0x8d, 0xc0, 0xcf, 0x21, 0x13, 0x08, 0x09, + 0xc2, 0x57, 0xe3, 0x7e, 0x8f, 0x76, 0x58, 0x9c, 0xfd, 0x8a, 0xb8, 0xf5, 0xbd, 0x0a, 0x34, 0xd7, + 0xcf, 0xe1, 0x89, 0x10, 0x3e, 0x0c, 0x43, 0xd2, 0xc3, 0x54, 0x3b, 0x04, 0xf7, 0x99, 0x48, 0xdb, + 0x17, 0x6b, 0x5d, 0xdd, 0x53, 0xf7, 0xd7, 0x0e, 0x74, 0x9b, 0x31, 0xf0, 0xec, 0x7e, 0xc3, 0x66, + 0x69, 0xf2, 0xbc, 0x5b, 0x1d, 0x8e, 0x4c, 0xd5, 0x5b, 0x0b, 0xe6, 0x21, 0xed, 0xa3, 0x0a, 0x36, + 0x49, 0x86, 0x62, 0x84, 0xfd, 0xa4, 0x2d, 0xb9, 0xf5, 0x95, 0xbd, 0xca, 0xfe, 0xda, 0xc1, 0x16, + 0xd7, 0x61, 0x87, 0x99, 0xce, 0x11, 0x41, 0xd8, 0x6d, 0x5d, 0x8e, 0x4c, 0x65, 0x3a, 0x32, 0x1f, + 0x0d, 0xfc, 0x34, 0x69, 0x5a, 0xe5, 0x44, 0xeb, 0xc7, 0x6f, 0xf3, 0x49, 0x8c, 0x68, 0xa7, 0x17, + 0xd8, 0x21, 0x49, 0x9d, 0x04, 0x61, 0xe8, 0x24, 0x41, 0xfa, 0x3c, 0x8f, 0xce, 0x1c, 0x3a, 0xe8, + 0xc2, 0x9c, 0xcb, 0xe4, 0xde, 0x46, 0x91, 0x29, 0x5f, 0x48, 0x3b, 0x07, 0xeb, 0x11, 0x4c, 0x60, + 0xec, 0x53, 0x18, 0xb5, 0xdf, 0x65, 0x10, 0xea, 0x95, 0x65, 0x0c, 0xc7, 0x92, 0x61, 0x47, 0x30, + 0x2c, 0xa6, 0xdd, 0x98, 0xe0, 0xc1, 0x2c, 0xaf, 0x95, 0x41, 0xa8, 0x7d, 0x52, 0xc1, 0xd6, 0x5c, + 0xa9, 0xe8, 0x43, 0x75, 0x19, 0xc3, 0x2b, 0xc9, 0xa0, 0x97, 0x19, 0xfe, 0xb5, 0x11, 0x9b, 0xb3, + 0xd4, 0xa2, 0x13, 0x36, 0x58, 0x85, 0x38, 0x6a, 0x53, 0x94, 0x42, 0xfd, 0xce, 0x9e, 0xba, 0x5f, + 0x71, 0x1f, 0x4e, 0x47, 0xe6, 0x86, 0x28, 0x54, 0xec, 0x58, 0xde, 0x5d, 0x88, 0xa3, 0xb7, 0x28, + 0x85, 0xcd, 0xd5, 0xcf, 0x17, 0xa6, 0xf2, 0xed, 0xc2, 0x54, 0xac, 0x9f, 0x2a, 0xd0, 0x8f, 0x08, + 0xa6, 0x08, 0xf7, 0x48, 0x2f, 0x2f, 0x59, 0xe5, 0x14, 0x6c, 0x73, 0xab, 0x48, 0xc0, 0x92, 0x65, + 0x2c, 0x7b, 0xd1, 0xb6, 0xf6, 0x75, 0xb3, 0x49, 0xf3, 0x68, 0xc1, 0x75, 0x1b, 0xbe, 0x04, 0x20, + 0xa7, 0x7e, 0x46, 0x05, 0xf4, 0x0a, 0x87, 0xde, 0x99, 0x8e, 0xcc, 0x2d, 0x01, 0x3d, 0xdf, 0xb3, + 0xbc, 0x7b, 0x7c, 0x51, 0x02, 0xff, 0x00, 0x76, 0x8e, 0x61, 0xe2, 0x0f, 0x66, 0x4d, 0xb8, 0x05, + 0xe8, 0x2b, 0xe5, 0xcf, 0x41, 0xed, 0x0d, 0xcc, 0x10, 0x89, 0xb4, 0x3a, 0xa8, 0x25, 0x10, 0xc7, + 0xb4, 0xc3, 0x2b, 0x54, 0x3c, 0xb9, 0xd2, 0x4e, 0x40, 0xcd, 0x4f, 0x79, 0xe5, 0xa5, 0x37, 0xe3, + 0x29, 0x73, 0xc4, 0x4d, 0xa7, 0x2e, 0xd5, 0x9a, 0x55, 0x5e, 0xff, 0xeb, 0x0a, 0xa8, 0x0b, 0x00, + 0x14, 0xfe, 0xef, 0x53, 0xd3, 0xda, 0x60, 0xa3, 0x80, 0xe9, 0x72, 0xe6, 0x5c, 0xde, 0xd4, 0x7a, + 0x19, 0x46, 0xbc, 0x92, 0x6b, 0xc8, 0xab, 0x52, 0x17, 0xb2, 0xa5, 0x64, 0xcb, 0x5b, 0x97, 0x11, + 0x71, 0x3c, 0x5f, 0x98, 0x0b, 0x6b, 0x4b, 0xea, 0x63, 0x88, 0xe9, 0x6b, 0x12, 0x9e, 0xc1, 0xe8, + 0x56, 0x7d, 0xe1, 0xb6, 0x2e, 0xc7, 0x86, 0x3a, 0x1c, 0x1b, 0xea, 0x9f, 0xb1, 0xa1, 0x7e, 0x99, + 0x18, 0xca, 0x70, 0x62, 0x28, 0xbf, 0x26, 0x86, 0x72, 0xfa, 0x6c, 0xd9, 0x90, 0xdf, 0xcb, 0x8f, + 0xb7, 0xfc, 0x77, 0xe0, 0x33, 0x0f, 0x6a, 0xfc, 0x1b, 0xfe, 0xe2, 0x6f, 0x00, 0x00, 0x00, 0xff, + 0xff, 0x17, 0xce, 0x03, 0x1c, 0x39, 0x06, 0x00, 0x00, } func (m *BaseVestingAccount) Marshal() (dAtA []byte, err error) { @@ -542,6 +585,41 @@ func (m *PeriodicVestingAccount) MarshalToSizedBuffer(dAtA []byte) (int, error) return len(dAtA) - i, nil } +func (m *PermanentLockedAccount) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *PermanentLockedAccount) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *PermanentLockedAccount) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.BaseVestingAccount != nil { + { + size, err := m.BaseVestingAccount.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintVesting(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + func encodeVarintVesting(dAtA []byte, offset int, v uint64) int { offset -= sovVesting(v) base := offset @@ -656,6 +734,19 @@ func (m *PeriodicVestingAccount) Size() (n int) { return n } +func (m *PermanentLockedAccount) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.BaseVestingAccount != nil { + l = m.BaseVestingAccount.Size() + n += 1 + l + sovVesting(uint64(l)) + } + return n +} + func sovVesting(x uint64) (n int) { return (math_bits.Len64(x|1) + 6) / 7 } @@ -1302,6 +1393,92 @@ func (m *PeriodicVestingAccount) Unmarshal(dAtA []byte) error { } return nil } +func (m *PermanentLockedAccount) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowVesting + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: PermanentLockedAccount: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: PermanentLockedAccount: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field BaseVestingAccount", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowVesting + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthVesting + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthVesting + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.BaseVestingAccount == nil { + m.BaseVestingAccount = &BaseVestingAccount{} + } + if err := m.BaseVestingAccount.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipVesting(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthVesting + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func skipVesting(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 diff --git a/x/auth/vesting/types/vesting_account.go b/x/auth/vesting/types/vesting_account.go index e58960a1aa..bf5648b4c2 100644 --- a/x/auth/vesting/types/vesting_account.go +++ b/x/auth/vesting/types/vesting_account.go @@ -1,13 +1,12 @@ package types import ( - "encoding/json" "errors" "time" - "github.com/gogo/protobuf/jsonpb" yaml "gopkg.in/yaml.v2" + cryptotypes "github.com/line/lbm-sdk/crypto/types" sdk "github.com/line/lbm-sdk/types" authtypes "github.com/line/lbm-sdk/x/auth/types" vestexported "github.com/line/lbm-sdk/x/auth/vesting/exported" @@ -21,7 +20,6 @@ var ( _ vestexported.VestingAccount = (*DelayedVestingAccount)(nil) ) -//----------------------------------------------------------------------------- // Base Vesting Account // NewBaseVestingAccount creates a new BaseVestingAccount object. It is the @@ -185,83 +183,19 @@ func (bva BaseVestingAccount) String() string { // MarshalYAML returns the YAML representation of a BaseVestingAccount. func (bva BaseVestingAccount) MarshalYAML() (interface{}, error) { - alias := vestingAccountYAML{ + out := vestingAccountYAML{ Address: sdk.AccAddress(bva.Address), AccountNumber: bva.AccountNumber, + PubKey: getPKString(bva), Sequence: bva.Sequence, OriginalVesting: bva.OriginalVesting, DelegatedFree: bva.DelegatedFree, DelegatedVesting: bva.DelegatedVesting, EndTime: bva.EndTime, } - - pk := bva.GetPubKey() - if pk != nil { - pks, err := sdk.Bech32ifyPubKey(sdk.Bech32PubKeyTypeAccPub, pk) - if err != nil { - return nil, err - } - - alias.PubKey = pks - } - - bz, err := yaml.Marshal(alias) - if err != nil { - return nil, err - } - - return string(bz), err -} - -type vestingAccountJSON struct { - BaseAccount json.RawMessage `json:"base_account"` - OriginalVesting sdk.Coins `json:"original_vesting"` - DelegatedFree sdk.Coins `json:"delegated_free"` - DelegatedVesting sdk.Coins `json:"delegated_vesting"` - EndTime int64 `json:"end_time"` - - StartTime int64 `json:"start_time,omitempty"` - VestingPeriods Periods `json:"vesting_periods,omitempty"` -} - -func (bva BaseVestingAccount) MarshalJSONPB(m *jsonpb.Marshaler) ([]byte, error) { - bz, err := bva.BaseAccount.MarshalJSONPB(m) - if err != nil { - return nil, err - } - alias := vestingAccountJSON{ - BaseAccount: bz, - OriginalVesting: bva.OriginalVesting, - DelegatedFree: bva.DelegatedFree, - DelegatedVesting: bva.DelegatedVesting, - EndTime: bva.EndTime, - } - - return json.Marshal(alias) -} - -func (bva *BaseVestingAccount) UnmarshalJSONPB(m *jsonpb.Unmarshaler, bz []byte) error { - var va vestingAccountJSON - - err := json.Unmarshal(bz, &va) - if err != nil { - return err - } - - var ba authtypes.BaseAccount - if err := (&ba).UnmarshalJSONPB(m, va.BaseAccount); err != nil { - return err - } - bva.BaseAccount = &ba - bva.OriginalVesting = va.OriginalVesting - bva.DelegatedFree = va.DelegatedFree - bva.OriginalVesting = va.DelegatedVesting - bva.EndTime = va.EndTime - - return nil + return marshalYaml(out) } -//----------------------------------------------------------------------------- // Continuous Vesting Account var _ vestexported.VestingAccount = (*ContinuousVestingAccount)(nil) @@ -322,7 +256,8 @@ func (cva ContinuousVestingAccount) GetVestingCoins(blockTime time.Time) sdk.Coi return cva.OriginalVesting.Sub(cva.GetVestedCoins(blockTime)) } -// LockedCoins returns the set of coins that are not spendable (i.e. locked). +// LockedCoins returns the set of coins that are not spendable (i.e. locked), +// defined as the vesting coins that are not delegated. func (cva ContinuousVestingAccount) LockedCoins(blockTime time.Time) sdk.Coins { return cva.BaseVestingAccount.LockedCoinsFromVesting(cva.GetVestingCoins(blockTime)) } @@ -356,9 +291,10 @@ func (cva ContinuousVestingAccount) String() string { // MarshalYAML returns the YAML representation of a ContinuousVestingAccount. func (cva ContinuousVestingAccount) MarshalYAML() (interface{}, error) { - alias := vestingAccountYAML{ + out := vestingAccountYAML{ Address: sdk.AccAddress(cva.Address), AccountNumber: cva.AccountNumber, + PubKey: getPKString(cva), Sequence: cva.Sequence, OriginalVesting: cva.OriginalVesting, DelegatedFree: cva.DelegatedFree, @@ -366,65 +302,9 @@ func (cva ContinuousVestingAccount) MarshalYAML() (interface{}, error) { EndTime: cva.EndTime, StartTime: cva.StartTime, } - - pk := cva.GetPubKey() - if pk != nil { - pks, err := sdk.Bech32ifyPubKey(sdk.Bech32PubKeyTypeAccPub, pk) - if err != nil { - return nil, err - } - - alias.PubKey = pks - } - - bz, err := yaml.Marshal(alias) - if err != nil { - return nil, err - } - - return string(bz), err -} - -func (cva ContinuousVestingAccount) MarshalJSONPB(m *jsonpb.Marshaler) ([]byte, error) { - bz, err := cva.BaseVestingAccount.BaseAccount.MarshalJSONPB(m) - if err != nil { - return nil, err - } - alias := vestingAccountJSON{ - BaseAccount: bz, - OriginalVesting: cva.BaseVestingAccount.OriginalVesting, - DelegatedFree: cva.BaseVestingAccount.DelegatedFree, - DelegatedVesting: cva.BaseVestingAccount.DelegatedVesting, - EndTime: cva.BaseVestingAccount.EndTime, - StartTime: cva.StartTime, - } - return json.Marshal(alias) + return marshalYaml(out) } -func (cva *ContinuousVestingAccount) UnmarshalJSONPB(m *jsonpb.Unmarshaler, bz []byte) error { - var va vestingAccountJSON - - err := json.Unmarshal(bz, &va) - if err != nil { - return err - } - - var ba authtypes.BaseAccount - if err := (&ba).UnmarshalJSONPB(m, va.BaseAccount); err != nil { - return err - } - cva.BaseVestingAccount = &BaseVestingAccount{ - BaseAccount: &ba, - OriginalVesting: va.OriginalVesting, - DelegatedFree: va.DelegatedFree, - DelegatedVesting: va.DelegatedVesting, - EndTime: va.EndTime, - } - cva.StartTime = va.StartTime - return nil -} - -//----------------------------------------------------------------------------- // Periodic Vesting Account var _ vestexported.VestingAccount = (*PeriodicVestingAccount)(nil) @@ -497,7 +377,8 @@ func (pva PeriodicVestingAccount) GetVestingCoins(blockTime time.Time) sdk.Coins return pva.OriginalVesting.Sub(pva.GetVestedCoins(blockTime)) } -// LockedCoins returns the set of coins that are not spendable (i.e. locked). +// LockedCoins returns the set of coins that are not spendable (i.e. locked), +// defined as the vesting coins that are not delegated. func (pva PeriodicVestingAccount) LockedCoins(blockTime time.Time) sdk.Coins { return pva.BaseVestingAccount.LockedCoinsFromVesting(pva.GetVestingCoins(blockTime)) } @@ -548,9 +429,10 @@ func (pva PeriodicVestingAccount) String() string { // MarshalYAML returns the YAML representation of a PeriodicVestingAccount. func (pva PeriodicVestingAccount) MarshalYAML() (interface{}, error) { - alias := vestingAccountYAML{ + out := vestingAccountYAML{ Address: sdk.AccAddress(pva.Address), AccountNumber: pva.AccountNumber, + PubKey: getPKString(pva), Sequence: pva.Sequence, OriginalVesting: pva.OriginalVesting, DelegatedFree: pva.DelegatedFree, @@ -559,69 +441,9 @@ func (pva PeriodicVestingAccount) MarshalYAML() (interface{}, error) { StartTime: pva.StartTime, VestingPeriods: pva.VestingPeriods, } - - pk := pva.GetPubKey() - if pk != nil { - pks, err := sdk.Bech32ifyPubKey(sdk.Bech32PubKeyTypeAccPub, pk) - if err != nil { - return nil, err - } - - alias.PubKey = pks - } - - bz, err := yaml.Marshal(alias) - if err != nil { - return nil, err - } - - return string(bz), err + return marshalYaml(out) } -func (pva PeriodicVestingAccount) MarshalJSONPB(m *jsonpb.Marshaler) ([]byte, error) { - bz, err := pva.BaseVestingAccount.BaseAccount.MarshalJSONPB(m) - if err != nil { - return nil, err - } - alias := vestingAccountJSON{ - BaseAccount: bz, - OriginalVesting: pva.BaseVestingAccount.OriginalVesting, - DelegatedFree: pva.BaseVestingAccount.DelegatedFree, - DelegatedVesting: pva.BaseVestingAccount.DelegatedVesting, - EndTime: pva.BaseVestingAccount.EndTime, - StartTime: pva.StartTime, - VestingPeriods: pva.VestingPeriods, - } - - return json.Marshal(alias) -} - -func (pva *PeriodicVestingAccount) UnmarshalJSONPB(m *jsonpb.Unmarshaler, bz []byte) error { - var va vestingAccountJSON - - err := json.Unmarshal(bz, &va) - if err != nil { - return err - } - - var ba authtypes.BaseAccount - if err := (&ba).UnmarshalJSONPB(m, va.BaseAccount); err != nil { - return err - } - pva.BaseVestingAccount = &BaseVestingAccount{ - BaseAccount: &ba, - OriginalVesting: va.OriginalVesting, - DelegatedFree: va.DelegatedFree, - DelegatedVesting: va.DelegatedVesting, - EndTime: va.EndTime, - } - pva.StartTime = va.StartTime - pva.VestingPeriods = va.VestingPeriods - - return nil -} - -//----------------------------------------------------------------------------- // Delayed Vesting Account var _ vestexported.VestingAccount = (*DelayedVestingAccount)(nil) @@ -661,7 +483,8 @@ func (dva DelayedVestingAccount) GetVestingCoins(blockTime time.Time) sdk.Coins return dva.OriginalVesting.Sub(dva.GetVestedCoins(blockTime)) } -// LockedCoins returns the set of coins that are not spendable (i.e. locked). +// LockedCoins returns the set of coins that are not spendable (i.e. locked), +// defined as the vesting coins that are not delegated. func (dva DelayedVestingAccount) LockedCoins(blockTime time.Time) sdk.Coins { return dva.BaseVestingAccount.LockedCoinsFromVesting(dva.GetVestingCoins(blockTime)) } @@ -688,41 +511,88 @@ func (dva DelayedVestingAccount) String() string { return out.(string) } -func (dva DelayedVestingAccount) MarshalJSONPB(m *jsonpb.Marshaler) ([]byte, error) { - bz, err := dva.BaseAccount.MarshalJSONPB(m) - if err != nil { - return nil, err - } - alias := vestingAccountJSON{ - BaseAccount: bz, - OriginalVesting: dva.BaseVestingAccount.OriginalVesting, - DelegatedFree: dva.BaseVestingAccount.DelegatedFree, - DelegatedVesting: dva.BaseVestingAccount.DelegatedVesting, - EndTime: dva.BaseVestingAccount.EndTime, +//----------------------------------------------------------------------------- +// Permanent Locked Vesting Account + +var _ vestexported.VestingAccount = (*PermanentLockedAccount)(nil) +var _ authtypes.GenesisAccount = (*PermanentLockedAccount)(nil) + +// NewPermanentLockedAccount returns a PermanentLockedAccount +func NewPermanentLockedAccount(baseAcc *authtypes.BaseAccount, coins sdk.Coins) *PermanentLockedAccount { + baseVestingAcc := &BaseVestingAccount{ + BaseAccount: baseAcc, + OriginalVesting: coins, + EndTime: 0, // ensure EndTime is set to 0, as PermanentLockedAccount's do not have an EndTime } - return json.Marshal(alias) + return &PermanentLockedAccount{baseVestingAcc} } -func (dva *DelayedVestingAccount) UnmarshalJSONPB(m *jsonpb.Unmarshaler, bz []byte) error { - var va vestingAccountJSON +// GetVestedCoins returns the total amount of vested coins for a permanent locked vesting +// account. All coins are only vested once the schedule has elapsed. +func (plva PermanentLockedAccount) GetVestedCoins(_ time.Time) sdk.Coins { + return nil +} - err := json.Unmarshal(bz, &va) - if err != nil { - return err - } +// GetVestingCoins returns the total number of vesting coins for a permanent locked +// vesting account. +func (plva PermanentLockedAccount) GetVestingCoins(_ time.Time) sdk.Coins { + return plva.OriginalVesting +} + +// LockedCoins returns the set of coins that are not spendable (i.e. locked), +// defined as the vesting coins that are not delegated. +func (plva PermanentLockedAccount) LockedCoins(_ time.Time) sdk.Coins { + return plva.BaseVestingAccount.LockedCoinsFromVesting(plva.OriginalVesting) +} + +// TrackDelegation tracks a desired delegation amount by setting the appropriate +// values for the amount of delegated vesting, delegated free, and reducing the +// overall amount of base coins. +func (plva *PermanentLockedAccount) TrackDelegation(blockTime time.Time, balance, amount sdk.Coins) { + plva.BaseVestingAccount.TrackDelegation(balance, plva.OriginalVesting, amount) +} + +// GetStartTime returns zero since a permanent locked vesting account has no start time. +func (plva PermanentLockedAccount) GetStartTime() int64 { + return 0 +} + +// GetEndTime returns a vesting account's end time, we return 0 to denote that +// a permanently locked vesting account has no end time. +func (plva PermanentLockedAccount) GetEndTime() int64 { + return 0 +} - var ba authtypes.BaseAccount - if err := (&ba).UnmarshalJSONPB(m, va.BaseAccount); err != nil { - return err +// Validate checks for errors on the account fields +func (plva PermanentLockedAccount) Validate() error { + if plva.EndTime > 0 { + return errors.New("permanently vested accounts cannot have an end-time") } - dva.BaseVestingAccount = &BaseVestingAccount{ - BaseAccount: &ba, - OriginalVesting: va.OriginalVesting, - DelegatedFree: va.DelegatedFree, - DelegatedVesting: va.DelegatedVesting, - EndTime: va.EndTime, + + return plva.BaseVestingAccount.Validate() +} + +func (plva PermanentLockedAccount) String() string { + out, _ := plva.MarshalYAML() + return out.(string) +} + +type getPK interface { + GetPubKey() cryptotypes.PubKey +} + +func getPKString(g getPK) string { + if pk := g.GetPubKey(); pk != nil { + return pk.String() } + return "" +} - return nil +func marshalYaml(i interface{}) (interface{}, error) { + bz, err := yaml.Marshal(i) + if err != nil { + return nil, err + } + return string(bz), nil } diff --git a/x/auth/vesting/types/vesting_account_test.go b/x/auth/vesting/types/vesting_account_test.go index 6d6af07dde..557213b008 100644 --- a/x/auth/vesting/types/vesting_account_test.go +++ b/x/auth/vesting/types/vesting_account_test.go @@ -23,9 +23,7 @@ func TestGetVestedCoinsContVestingAcc(t *testing.T) { now := osttime.Now() endTime := now.Add(24 * time.Hour) - _, _, addr := testdata.KeyTestPubAddr() - origCoins := sdk.Coins{sdk.NewInt64Coin(feeDenom, 1000), sdk.NewInt64Coin(stakeDenom, 100)} - bacc := authtypes.NewBaseAccountWithAddress(addr) + bacc, origCoins := initBaseAccount() cva := types.NewContinuousVestingAccount(bacc, origCoins, now.Unix(), endTime.Unix()) // require no coins vested in the very beginning of the vesting schedule @@ -49,9 +47,7 @@ func TestGetVestingCoinsContVestingAcc(t *testing.T) { now := osttime.Now() endTime := now.Add(24 * time.Hour) - _, _, addr := testdata.KeyTestPubAddr() - origCoins := sdk.Coins{sdk.NewInt64Coin(feeDenom, 1000), sdk.NewInt64Coin(stakeDenom, 100)} - bacc := authtypes.NewBaseAccountWithAddress(addr) + bacc, origCoins := initBaseAccount() cva := types.NewContinuousVestingAccount(bacc, origCoins, now.Unix(), endTime.Unix()) // require all coins vesting in the beginning of the vesting schedule @@ -71,10 +67,7 @@ func TestSpendableCoinsContVestingAcc(t *testing.T) { now := osttime.Now() endTime := now.Add(24 * time.Hour) - _, _, addr := testdata.KeyTestPubAddr() - origCoins := sdk.Coins{sdk.NewInt64Coin(feeDenom, 1000), sdk.NewInt64Coin(stakeDenom, 100)} - bacc := authtypes.NewBaseAccountWithAddress(addr) - + bacc, origCoins := initBaseAccount() cva := types.NewContinuousVestingAccount(bacc, origCoins, now.Unix(), endTime.Unix()) // require that all original coins are locked at the end of the vesting @@ -89,19 +82,13 @@ func TestSpendableCoinsContVestingAcc(t *testing.T) { // require that all vested coins (50%) are spendable lockedCoins = cva.LockedCoins(now.Add(12 * time.Hour)) require.Equal(t, sdk.Coins{sdk.NewInt64Coin(feeDenom, 500), sdk.NewInt64Coin(stakeDenom, 50)}, lockedCoins) - - // require that all vested coins (50%) are spendable plus any received - lockedCoins = cva.LockedCoins(now.Add(12 * time.Hour)) - require.Equal(t, sdk.Coins{sdk.NewInt64Coin(feeDenom, 500), sdk.NewInt64Coin(stakeDenom, 50)}, lockedCoins) } func TestTrackDelegationContVestingAcc(t *testing.T) { now := osttime.Now() endTime := now.Add(24 * time.Hour) - _, _, addr := testdata.KeyTestPubAddr() - origCoins := sdk.Coins{sdk.NewInt64Coin(feeDenom, 1000), sdk.NewInt64Coin(stakeDenom, 100)} - bacc := authtypes.NewBaseAccountWithAddress(addr) + bacc, origCoins := initBaseAccount() // require the ability to delegate all vesting coins cva := types.NewContinuousVestingAccount(bacc, origCoins, now.Unix(), endTime.Unix()) @@ -138,9 +125,7 @@ func TestTrackUndelegationContVestingAcc(t *testing.T) { now := osttime.Now() endTime := now.Add(24 * time.Hour) - _, _, addr := testdata.KeyTestPubAddr() - origCoins := sdk.Coins{sdk.NewInt64Coin(feeDenom, 1000), sdk.NewInt64Coin(stakeDenom, 100)} - bacc := authtypes.NewBaseAccountWithAddress(addr) + bacc, origCoins := initBaseAccount() // require the ability to undelegate all vesting coins cva := types.NewContinuousVestingAccount(bacc, origCoins, now.Unix(), endTime.Unix()) @@ -186,9 +171,7 @@ func TestGetVestedCoinsDelVestingAcc(t *testing.T) { now := osttime.Now() endTime := now.Add(24 * time.Hour) - _, _, addr := testdata.KeyTestPubAddr() - origCoins := sdk.Coins{sdk.NewInt64Coin(feeDenom, 1000), sdk.NewInt64Coin(stakeDenom, 100)} - bacc := authtypes.NewBaseAccountWithAddress(addr) + bacc, origCoins := initBaseAccount() // require no coins are vested until schedule maturation dva := types.NewDelayedVestingAccount(bacc, origCoins, endTime.Unix()) @@ -204,9 +187,7 @@ func TestGetVestingCoinsDelVestingAcc(t *testing.T) { now := osttime.Now() endTime := now.Add(24 * time.Hour) - _, _, addr := testdata.KeyTestPubAddr() - origCoins := sdk.Coins{sdk.NewInt64Coin(feeDenom, 1000), sdk.NewInt64Coin(stakeDenom, 100)} - bacc := authtypes.NewBaseAccountWithAddress(addr) + bacc, origCoins := initBaseAccount() // require all coins vesting at the beginning of the schedule dva := types.NewDelayedVestingAccount(bacc, origCoins, endTime.Unix()) @@ -222,9 +203,7 @@ func TestSpendableCoinsDelVestingAcc(t *testing.T) { now := osttime.Now() endTime := now.Add(24 * time.Hour) - _, _, addr := testdata.KeyTestPubAddr() - origCoins := sdk.Coins{sdk.NewInt64Coin(feeDenom, 1000), sdk.NewInt64Coin(stakeDenom, 100)} - bacc := authtypes.NewBaseAccountWithAddress(addr) + bacc, origCoins := initBaseAccount() // require that all coins are locked in the beginning of the vesting // schedule @@ -241,12 +220,6 @@ func TestSpendableCoinsDelVestingAcc(t *testing.T) { lockedCoins = dva.LockedCoins(now.Add(12 * time.Hour)) require.True(t, lockedCoins.IsEqual(origCoins)) - // receive some coins - // require that only received coins are spendable since the account is still - // vesting - lockedCoins = dva.LockedCoins(now.Add(12 * time.Hour)) - require.True(t, lockedCoins.IsEqual(origCoins)) - // delegate some locked coins // require that locked is reduced delegatedAmount := sdk.NewCoins(sdk.NewInt64Coin(stakeDenom, 50)) @@ -259,9 +232,7 @@ func TestTrackDelegationDelVestingAcc(t *testing.T) { now := osttime.Now() endTime := now.Add(24 * time.Hour) - _, _, addr := testdata.KeyTestPubAddr() - origCoins := sdk.Coins{sdk.NewInt64Coin(feeDenom, 1000), sdk.NewInt64Coin(stakeDenom, 100)} - bacc := authtypes.NewBaseAccountWithAddress(addr) + bacc, origCoins := initBaseAccount() // require the ability to delegate all vesting coins dva := types.NewDelayedVestingAccount(bacc, origCoins, endTime.Unix()) @@ -296,9 +267,7 @@ func TestTrackUndelegationDelVestingAcc(t *testing.T) { now := osttime.Now() endTime := now.Add(24 * time.Hour) - _, _, addr := testdata.KeyTestPubAddr() - origCoins := sdk.Coins{sdk.NewInt64Coin(feeDenom, 1000), sdk.NewInt64Coin(stakeDenom, 100)} - bacc := authtypes.NewBaseAccountWithAddress(addr) + bacc, origCoins := initBaseAccount() // require the ability to undelegate all vesting coins dva := types.NewDelayedVestingAccount(bacc, origCoins, endTime.Unix()) @@ -349,9 +318,7 @@ func TestGetVestedCoinsPeriodicVestingAcc(t *testing.T) { types.Period{Length: int64(6 * 60 * 60), Amount: sdk.Coins{sdk.NewInt64Coin(feeDenom, 250), sdk.NewInt64Coin(stakeDenom, 25)}}, } - _, _, addr := testdata.KeyTestPubAddr() - origCoins := sdk.Coins{sdk.NewInt64Coin(feeDenom, 1000), sdk.NewInt64Coin(stakeDenom, 100)} - bacc := authtypes.NewBaseAccountWithAddress(addr) + bacc, origCoins := initBaseAccount() pva := types.NewPeriodicVestingAccount(bacc, origCoins, now.Unix(), periods) // require no coins vested at the beginning of the vesting schedule @@ -394,10 +361,7 @@ func TestGetVestingCoinsPeriodicVestingAcc(t *testing.T) { types.Period{Length: int64(6 * 60 * 60), Amount: sdk.Coins{sdk.NewInt64Coin(feeDenom, 250), sdk.NewInt64Coin(stakeDenom, 25)}}, } - _, _, addr := testdata.KeyTestPubAddr() - origCoins := sdk.Coins{ - sdk.NewInt64Coin(feeDenom, 1000), sdk.NewInt64Coin(stakeDenom, 100)} - bacc := authtypes.NewBaseAccountWithAddress(addr) + bacc, origCoins := initBaseAccount() pva := types.NewPeriodicVestingAccount(bacc, origCoins, now.Unix(), periods) // require all coins vesting at the beginning of the vesting schedule @@ -434,10 +398,7 @@ func TestSpendableCoinsPeriodicVestingAcc(t *testing.T) { types.Period{Length: int64(6 * 60 * 60), Amount: sdk.Coins{sdk.NewInt64Coin(feeDenom, 250), sdk.NewInt64Coin(stakeDenom, 25)}}, } - _, _, addr := testdata.KeyTestPubAddr() - origCoins := sdk.Coins{ - sdk.NewInt64Coin(feeDenom, 1000), sdk.NewInt64Coin(stakeDenom, 100)} - bacc := authtypes.NewBaseAccountWithAddress(addr) + bacc, origCoins := initBaseAccount() pva := types.NewPeriodicVestingAccount(bacc, origCoins, now.Unix(), periods) // require that there exist no spendable coins at the beginning of the @@ -453,11 +414,6 @@ func TestSpendableCoinsPeriodicVestingAcc(t *testing.T) { // require that all still vesting coins (50%) are locked lockedCoins = pva.LockedCoins(now.Add(12 * time.Hour)) require.Equal(t, sdk.Coins{sdk.NewInt64Coin(feeDenom, 500), sdk.NewInt64Coin(stakeDenom, 50)}, lockedCoins) - - // receive some coins - // require that all still vesting coins (50% of original) are locked plus any received - lockedCoins = pva.LockedCoins(now.Add(12 * time.Hour)) - require.Equal(t, sdk.Coins{sdk.NewInt64Coin(feeDenom, 500), sdk.NewInt64Coin(stakeDenom, 50)}, lockedCoins) } func TestTrackDelegationPeriodicVestingAcc(t *testing.T) { @@ -469,9 +425,7 @@ func TestTrackDelegationPeriodicVestingAcc(t *testing.T) { types.Period{Length: int64(6 * 60 * 60), Amount: sdk.Coins{sdk.NewInt64Coin(feeDenom, 250), sdk.NewInt64Coin(stakeDenom, 25)}}, } - _, _, addr := testdata.KeyTestPubAddr() - origCoins := sdk.Coins{sdk.NewInt64Coin(feeDenom, 1000), sdk.NewInt64Coin(stakeDenom, 100)} - bacc := authtypes.NewBaseAccountWithAddress(addr) + bacc, origCoins := initBaseAccount() // require the ability to delegate all vesting coins pva := types.NewPeriodicVestingAccount(bacc, origCoins, now.Unix(), periods) @@ -527,9 +481,7 @@ func TestTrackUndelegationPeriodicVestingAcc(t *testing.T) { types.Period{Length: int64(6 * 60 * 60), Amount: sdk.Coins{sdk.NewInt64Coin(feeDenom, 250), sdk.NewInt64Coin(stakeDenom, 25)}}, } - _, _, addr := testdata.KeyTestPubAddr() - origCoins := sdk.Coins{sdk.NewInt64Coin(feeDenom, 1000), sdk.NewInt64Coin(stakeDenom, 100)} - bacc := authtypes.NewBaseAccountWithAddress(addr) + bacc, origCoins := initBaseAccount() // require the ability to undelegate all vesting coins at the beginning of vesting pva := types.NewPeriodicVestingAccount(bacc, origCoins, now.Unix(), periods) @@ -578,6 +530,135 @@ func TestTrackUndelegationPeriodicVestingAcc(t *testing.T) { require.Equal(t, sdk.Coins{sdk.NewInt64Coin(stakeDenom, 25)}, pva.DelegatedVesting) } +func TestGetVestedCoinsPermLockedVestingAcc(t *testing.T) { + now := osttime.Now() + endTime := now.Add(1000 * 24 * time.Hour) + + bacc, origCoins := initBaseAccount() + + // require no coins are vested + plva := types.NewPermanentLockedAccount(bacc, origCoins) + vestedCoins := plva.GetVestedCoins(now) + require.Nil(t, vestedCoins) + + // require no coins be vested at end time + vestedCoins = plva.GetVestedCoins(endTime) + require.Nil(t, vestedCoins) +} + +func TestGetVestingCoinsPermLockedVestingAcc(t *testing.T) { + now := osttime.Now() + endTime := now.Add(1000 * 24 * time.Hour) + + bacc, origCoins := initBaseAccount() + + // require all coins vesting at the beginning of the schedule + plva := types.NewPermanentLockedAccount(bacc, origCoins) + vestingCoins := plva.GetVestingCoins(now) + require.Equal(t, origCoins, vestingCoins) + + // require all coins vesting at the end time + vestingCoins = plva.GetVestingCoins(endTime) + require.Equal(t, origCoins, vestingCoins) +} + +func TestSpendableCoinsPermLockedVestingAcc(t *testing.T) { + now := osttime.Now() + endTime := now.Add(1000 * 24 * time.Hour) + + bacc, origCoins := initBaseAccount() + + // require that all coins are locked in the beginning of the vesting + // schedule + plva := types.NewPermanentLockedAccount(bacc, origCoins) + lockedCoins := plva.LockedCoins(now) + require.True(t, lockedCoins.IsEqual(origCoins)) + + // require that all coins are still locked at end time + lockedCoins = plva.LockedCoins(endTime) + require.True(t, lockedCoins.IsEqual(origCoins)) + + // delegate some locked coins + // require that locked is reduced + delegatedAmount := sdk.NewCoins(sdk.NewInt64Coin(stakeDenom, 50)) + plva.TrackDelegation(now.Add(12*time.Hour), origCoins, delegatedAmount) + lockedCoins = plva.LockedCoins(now.Add(12 * time.Hour)) + require.True(t, lockedCoins.IsEqual(origCoins.Sub(delegatedAmount))) +} + +func TestTrackDelegationPermLockedVestingAcc(t *testing.T) { + now := osttime.Now() + endTime := now.Add(1000 * 24 * time.Hour) + + bacc, origCoins := initBaseAccount() + + // require the ability to delegate all vesting coins + plva := types.NewPermanentLockedAccount(bacc, origCoins) + plva.TrackDelegation(now, origCoins, origCoins) + require.Equal(t, origCoins, plva.DelegatedVesting) + require.Nil(t, plva.DelegatedFree) + + // require the ability to delegate all vested coins at endTime + plva = types.NewPermanentLockedAccount(bacc, origCoins) + plva.TrackDelegation(endTime, origCoins, origCoins) + require.Equal(t, origCoins, plva.DelegatedVesting) + require.Nil(t, plva.DelegatedFree) + + // require no modifications when delegation amount is zero or not enough funds + plva = types.NewPermanentLockedAccount(bacc, origCoins) + + require.Panics(t, func() { + plva.TrackDelegation(endTime, origCoins, sdk.Coins{sdk.NewInt64Coin(stakeDenom, 1000000)}) + }) + require.Nil(t, plva.DelegatedVesting) + require.Nil(t, plva.DelegatedFree) +} + +func TestTrackUndelegationPermLockedVestingAcc(t *testing.T) { + now := osttime.Now() + endTime := now.Add(1000 * 24 * time.Hour) + + bacc, origCoins := initBaseAccount() + + // require the ability to undelegate all vesting coins + plva := types.NewPermanentLockedAccount(bacc, origCoins) + plva.TrackDelegation(now, origCoins, origCoins) + plva.TrackUndelegation(origCoins) + require.Nil(t, plva.DelegatedFree) + require.Nil(t, plva.DelegatedVesting) + + // require the ability to undelegate all vesting coins at endTime + plva = types.NewPermanentLockedAccount(bacc, origCoins) + plva.TrackDelegation(endTime, origCoins, origCoins) + plva.TrackUndelegation(origCoins) + require.Nil(t, plva.DelegatedFree) + require.Nil(t, plva.DelegatedVesting) + + // require no modifications when the undelegation amount is zero + plva = types.NewPermanentLockedAccount(bacc, origCoins) + require.Panics(t, func() { + plva.TrackUndelegation(sdk.Coins{sdk.NewInt64Coin(stakeDenom, 0)}) + }) + require.Nil(t, plva.DelegatedFree) + require.Nil(t, plva.DelegatedVesting) + + // delegate to two validators + plva = types.NewPermanentLockedAccount(bacc, origCoins) + plva.TrackDelegation(now, origCoins, sdk.Coins{sdk.NewInt64Coin(stakeDenom, 50)}) + plva.TrackDelegation(now, origCoins, sdk.Coins{sdk.NewInt64Coin(stakeDenom, 50)}) + + // undelegate from one validator that got slashed 50% + plva.TrackUndelegation(sdk.Coins{sdk.NewInt64Coin(stakeDenom, 25)}) + + require.Nil(t, plva.DelegatedFree) + require.Equal(t, sdk.Coins{sdk.NewInt64Coin(stakeDenom, 75)}, plva.DelegatedVesting) + + // undelegate from the other validator that did not get slashed + plva.TrackUndelegation(sdk.Coins{sdk.NewInt64Coin(stakeDenom, 50)}) + require.Nil(t, plva.DelegatedFree) + require.Equal(t, sdk.Coins{sdk.NewInt64Coin(stakeDenom, 25)}, plva.DelegatedVesting) +} + func TestGenesisAccountValidate(t *testing.T) { pubkey := secp256k1.GenPrivKey().PubKey() addr := sdk.BytesToAccAddress(pubkey.Address()) @@ -633,6 +714,16 @@ func TestGenesisAccountValidate(t *testing.T) { 0, types.Periods{types.Period{Length: int64(100), Amount: sdk.Coins{sdk.NewInt64Coin(sdk.DefaultBondDenom, 25)}}}), true, }, + { + "valid permanent locked vesting account", + types.NewPermanentLockedAccount(baseAcc, initialVesting), + false, + }, + { + "invalid positive end time for permanently locked vest account", + &types.PermanentLockedAccount{BaseVestingAccount: baseVestingWithCoins}, + true, + }, } for _, tt := range tests { @@ -645,11 +736,7 @@ func TestGenesisAccountValidate(t *testing.T) { } func TestContinuousVestingAccountMarshal(t *testing.T) { - pubkey := secp256k1.GenPrivKey().PubKey() - addr := sdk.BytesToAccAddress(pubkey.Address()) - coins := sdk.NewCoins(sdk.NewInt64Coin("test", 5)) - baseAcc := authtypes.NewBaseAccount(addr, pubkey, 10, 50) - + baseAcc, coins := initBaseAccount() baseVesting := types.NewBaseVestingAccount(baseAcc, coins, time.Now().Unix()) acc := types.NewContinuousVestingAccountRaw(baseVesting, baseVesting.EndTime) @@ -667,11 +754,7 @@ func TestContinuousVestingAccountMarshal(t *testing.T) { } func TestPeriodicVestingAccountMarshal(t *testing.T) { - pubkey := secp256k1.GenPrivKey().PubKey() - addr := sdk.BytesToAccAddress(pubkey.Address()) - coins := sdk.NewCoins(sdk.NewInt64Coin("test", 5)) - baseAcc := authtypes.NewBaseAccount(addr, pubkey, 10, 50) - + baseAcc, coins := initBaseAccount() acc := types.NewPeriodicVestingAccount(baseAcc, coins, time.Now().Unix(), types.Periods{types.Period{3600, coins}}) bz, err := app.AccountKeeper.MarshalAccount(acc) @@ -688,11 +771,7 @@ func TestPeriodicVestingAccountMarshal(t *testing.T) { } func TestDelayedVestingAccountMarshal(t *testing.T) { - pubkey := secp256k1.GenPrivKey().PubKey() - addr := sdk.BytesToAccAddress(pubkey.Address()) - coins := sdk.NewCoins(sdk.NewInt64Coin("test", 5)) - baseAcc := authtypes.NewBaseAccount(addr, pubkey, 10, 50) - + baseAcc, coins := initBaseAccount() acc := types.NewDelayedVestingAccount(baseAcc, coins, time.Now().Unix()) bz, err := app.AccountKeeper.MarshalAccount(acc) @@ -707,3 +786,27 @@ func TestDelayedVestingAccountMarshal(t *testing.T) { _, err = app.AccountKeeper.UnmarshalAccount(bz[:len(bz)/2]) require.NotNil(t, err) } +func TestPermanentLockedAccountMarshal(t *testing.T) { + baseAcc, coins := initBaseAccount() + acc := types.NewPermanentLockedAccount(baseAcc, coins) + + bz, err := app.AccountKeeper.MarshalAccount(acc) + require.Nil(t, err) + + acc2, err := app.AccountKeeper.UnmarshalAccount(bz) + require.Nil(t, err) + require.IsType(t, &types.PermanentLockedAccount{}, acc2) + require.Equal(t, acc.String(), acc2.String()) + + // error on bad bytes + _, err = app.AccountKeeper.UnmarshalAccount(bz[:len(bz)/2]) + require.NotNil(t, err) +} + +func initBaseAccount() (*authtypes.BaseAccount, sdk.Coins) { + _, _, addr := testdata.KeyTestPubAddr() + origCoins := sdk.Coins{sdk.NewInt64Coin(feeDenom, 1000), sdk.NewInt64Coin(stakeDenom, 100)} + bacc := authtypes.NewBaseAccountWithAddress(addr) + + return bacc, origCoins +} diff --git a/x/authz/authorization_grant.go b/x/authz/authorization_grant.go new file mode 100644 index 0000000000..c69be5d0b9 --- /dev/null +++ b/x/authz/authorization_grant.go @@ -0,0 +1,64 @@ +package authz + +import ( + "time" + + proto "github.com/gogo/protobuf/proto" + + cdctypes "github.com/line/lbm-sdk/codec/types" + sdkerrors "github.com/line/lbm-sdk/types/errors" +) + +// NewGrant returns new Grant +func NewGrant( /*blockTime time.Time, */ a Authorization, expiration time.Time) (Grant, error) { + // TODO: add this for 0.45 + // if !expiration.After(blockTime) { + // return Grant{}, sdkerrors.ErrInvalidRequest.Wrapf("expiration must be after the current block time (%v), got %v", blockTime.Format(time.RFC3339), expiration.Format(time.RFC3339)) + // } + g := Grant{ + Expiration: expiration, + } + msg, ok := a.(proto.Message) + if !ok { + return Grant{}, sdkerrors.Wrapf(sdkerrors.ErrPackAny, "cannot proto marshal %T", a) + } + + any, err := cdctypes.NewAnyWithValue(msg) + if err != nil { + return Grant{}, err + } + g.Authorization = any + + return g, nil +} + +var ( + _ cdctypes.UnpackInterfacesMessage = &Grant{} +) + +// UnpackInterfaces implements UnpackInterfacesMessage.UnpackInterfaces +func (g Grant) UnpackInterfaces(unpacker cdctypes.AnyUnpacker) error { + var authorization Authorization + return unpacker.UnpackAny(g.Authorization, &authorization) +} + +// GetAuthorization returns the cached value from the Grant.Authorization if present. +func (g Grant) GetAuthorization() Authorization { + if g.Authorization == nil { + return nil + } + a, ok := g.Authorization.GetCachedValue().(Authorization) + if !ok { + return nil + } + return a +} + +func (g Grant) ValidateBasic() error { + av := g.Authorization.GetCachedValue() + a, ok := av.(Authorization) + if !ok { + return sdkerrors.Wrapf(sdkerrors.ErrInvalidType, "expected %T, got %T", (Authorization)(nil), av) + } + return a.ValidateBasic() +} diff --git a/x/authz/authorization_grant_test.go b/x/authz/authorization_grant_test.go new file mode 100644 index 0000000000..9f9f00108c --- /dev/null +++ b/x/authz/authorization_grant_test.go @@ -0,0 +1,44 @@ +package authz + +import ( + "testing" + "time" + + // banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + "github.com/stretchr/testify/require" +) + +func expecError(r *require.Assertions, expected string, received error) { + if expected == "" { + r.NoError(received) + } else { + r.Error(received) + r.Contains(received.Error(), expected) + } +} + +func TestNewGrant(t *testing.T) { + // ba := banktypes.NewSendAuthorization(sdk.NewCoins(sdk.NewInt64Coin("foo", 123))) + a := NewGenericAuthorization("some-type") + var tcs = []struct { + title string + a Authorization + blockTime time.Time + expire time.Time + err string + }{ + // {"wrong expire time (1)", a, time.Unix(10, 0), time.Unix(8, 0), "expiration must be after"}, + // {"wrong expire time (2)", a, time.Unix(10, 0), time.Unix(10, 0), "expiration must be after"}, + {"good expire time (1)", a, time.Unix(10, 0), time.Unix(10, 1), ""}, + {"good expire time (2)", a, time.Unix(10, 0), time.Unix(11, 0), ""}, + } + + for _, tc := range tcs { + t.Run(tc.title, func(t *testing.T) { + // _, err := NewGrant(tc.blockTime, tc.a, tc.expire) + _, err := NewGrant(tc.a, tc.expire) + expecError(require.New(t), tc.err, err) + }) + } + +} diff --git a/x/authz/authorizations.go b/x/authz/authorizations.go new file mode 100644 index 0000000000..622f341b55 --- /dev/null +++ b/x/authz/authorizations.go @@ -0,0 +1,38 @@ +package authz + +import ( + "github.com/gogo/protobuf/proto" + + sdk "github.com/line/lbm-sdk/types" +) + +// Authorization represents the interface of various Authorization types implemented +// by other modules. +type Authorization interface { + proto.Message + + // MsgTypeURL returns the fully-qualified Msg service method URL (as described in ADR 031), + // which will process and accept or reject a request. + MsgTypeURL() string + + // Accept determines whether this grant permits the provided sdk.Msg to be performed, + // and if so provides an upgraded authorization instance. + Accept(ctx sdk.Context, msg sdk.Msg) (AcceptResponse, error) + + // ValidateBasic does a simple validation check that + // doesn't require access to any other information. + ValidateBasic() error +} + +// AcceptResponse instruments the controller of an authz message if the request is accepted +// and if it should be updated or deleted. +type AcceptResponse struct { + // If Accept=true, the controller can accept and authorization and handle the update. + Accept bool + // If Delete=true, the controller must delete the authorization object and release + // storage resources. + Delete bool + // Controller, who is calling Authorization.Accept must check if `Updated != nil`. If yes, + // it must use the updated version and handle the update on the storage level. + Updated Authorization +} diff --git a/x/authz/authz.pb.go b/x/authz/authz.pb.go new file mode 100644 index 0000000000..751d05a377 --- /dev/null +++ b/x/authz/authz.pb.go @@ -0,0 +1,546 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: lbm/authz/v1/authz.proto + +package authz + +import ( + fmt "fmt" + _ "github.com/gogo/protobuf/gogoproto" + proto "github.com/gogo/protobuf/proto" + github_com_gogo_protobuf_types "github.com/gogo/protobuf/types" + types "github.com/line/lbm-sdk/codec/types" + _ "github.com/line/lbm-sdk/types" + _ "github.com/regen-network/cosmos-proto" + _ "google.golang.org/protobuf/types/known/timestamppb" + io "io" + math "math" + math_bits "math/bits" + time "time" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf +var _ = time.Kitchen + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +// GenericAuthorization gives the grantee unrestricted permissions to execute +// the provided method on behalf of the granter's account. +type GenericAuthorization struct { + // Msg, identified by it's type URL, to grant unrestricted permissions to execute + Msg string `protobuf:"bytes,1,opt,name=msg,proto3" json:"msg,omitempty"` +} + +func (m *GenericAuthorization) Reset() { *m = GenericAuthorization{} } +func (m *GenericAuthorization) String() string { return proto.CompactTextString(m) } +func (*GenericAuthorization) ProtoMessage() {} +func (*GenericAuthorization) Descriptor() ([]byte, []int) { + return fileDescriptor_aa5041a8d6ee0eda, []int{0} +} +func (m *GenericAuthorization) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *GenericAuthorization) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_GenericAuthorization.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *GenericAuthorization) XXX_Merge(src proto.Message) { + xxx_messageInfo_GenericAuthorization.Merge(m, src) +} +func (m *GenericAuthorization) XXX_Size() int { + return m.Size() +} +func (m *GenericAuthorization) XXX_DiscardUnknown() { + xxx_messageInfo_GenericAuthorization.DiscardUnknown(m) +} + +var xxx_messageInfo_GenericAuthorization proto.InternalMessageInfo + +// Grant gives permissions to execute +// the provide method with expiration time. +type Grant struct { + Authorization *types.Any `protobuf:"bytes,1,opt,name=authorization,proto3" json:"authorization,omitempty"` + Expiration time.Time `protobuf:"bytes,2,opt,name=expiration,proto3,stdtime" json:"expiration"` +} + +func (m *Grant) Reset() { *m = Grant{} } +func (m *Grant) String() string { return proto.CompactTextString(m) } +func (*Grant) ProtoMessage() {} +func (*Grant) Descriptor() ([]byte, []int) { + return fileDescriptor_aa5041a8d6ee0eda, []int{1} +} +func (m *Grant) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Grant) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Grant.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *Grant) XXX_Merge(src proto.Message) { + xxx_messageInfo_Grant.Merge(m, src) +} +func (m *Grant) XXX_Size() int { + return m.Size() +} +func (m *Grant) XXX_DiscardUnknown() { + xxx_messageInfo_Grant.DiscardUnknown(m) +} + +var xxx_messageInfo_Grant proto.InternalMessageInfo + +func init() { + proto.RegisterType((*GenericAuthorization)(nil), "lbm.authz.v1.GenericAuthorization") + proto.RegisterType((*Grant)(nil), "lbm.authz.v1.Grant") +} + +func init() { proto.RegisterFile("lbm/authz/v1/authz.proto", fileDescriptor_aa5041a8d6ee0eda) } + +var fileDescriptor_aa5041a8d6ee0eda = []byte{ + // 319 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x64, 0x51, 0x4d, 0x4e, 0x32, 0x31, + 0x18, 0x9e, 0x7e, 0x5f, 0x34, 0x5a, 0x25, 0x91, 0x09, 0x31, 0xc8, 0xa2, 0x63, 0x58, 0xb9, 0x61, + 0x1a, 0x74, 0xa7, 0x71, 0x01, 0x31, 0x61, 0xe5, 0x86, 0xb8, 0x72, 0x63, 0xda, 0xb1, 0x0e, 0x8d, + 0xd3, 0xbe, 0x64, 0xda, 0x21, 0xc0, 0x29, 0x38, 0x80, 0xc7, 0xf0, 0x10, 0xc4, 0x15, 0x71, 0xe5, + 0xca, 0x1f, 0xb8, 0x88, 0x99, 0x29, 0x24, 0x80, 0xbb, 0xe7, 0xe9, 0xf3, 0x97, 0xe6, 0xc5, 0xd5, + 0x84, 0x2b, 0xca, 0x32, 0xdb, 0x1b, 0xd3, 0x41, 0xd3, 0x81, 0xb0, 0x9f, 0x82, 0x05, 0xff, 0x30, + 0xe1, 0x2a, 0x74, 0x0f, 0x83, 0x66, 0xed, 0x38, 0xf7, 0x71, 0x66, 0x44, 0x6e, 0x8b, 0x40, 0x6a, + 0xe7, 0xaa, 0x9d, 0x44, 0x60, 0x14, 0x98, 0x87, 0x82, 0x51, 0x47, 0x96, 0x52, 0x10, 0x03, 0xc4, + 0x89, 0xa0, 0x05, 0xe3, 0xd9, 0x13, 0xb5, 0x52, 0x09, 0x63, 0x99, 0xea, 0x2f, 0x0d, 0x95, 0x18, + 0x62, 0x70, 0xc1, 0x1c, 0xad, 0x1a, 0xb7, 0x63, 0x4c, 0x8f, 0x9c, 0x54, 0xbf, 0xc2, 0x95, 0x8e, + 0xd0, 0x22, 0x95, 0x51, 0x2b, 0xb3, 0x3d, 0x48, 0xe5, 0x98, 0x59, 0x09, 0xda, 0x3f, 0xc2, 0xff, + 0x95, 0x89, 0xab, 0xe8, 0x14, 0x9d, 0xed, 0x77, 0x73, 0x78, 0x59, 0x7e, 0x7f, 0x6d, 0x94, 0x36, + 0x4c, 0xf5, 0x17, 0x84, 0x77, 0x3a, 0x29, 0xd3, 0xd6, 0xbf, 0xc5, 0x25, 0xb6, 0x2e, 0x15, 0xc1, + 0x83, 0xf3, 0x4a, 0xe8, 0x96, 0xc3, 0xd5, 0x72, 0xd8, 0xd2, 0xa3, 0x76, 0xf9, 0x6d, 0xbb, 0xa9, + 0xbb, 0x99, 0xf6, 0x6f, 0x30, 0x16, 0xc3, 0xbe, 0x4c, 0x5d, 0xd7, 0xbf, 0xa2, 0xab, 0xf6, 0xa7, + 0xeb, 0x6e, 0xf5, 0xf9, 0xf6, 0xde, 0xf4, 0x33, 0xf0, 0x26, 0x5f, 0x01, 0xea, 0xae, 0xe5, 0xda, + 0xd7, 0xd3, 0x1f, 0xe2, 0x4d, 0xe7, 0x04, 0xcd, 0xe6, 0x04, 0x7d, 0xcf, 0x09, 0x9a, 0x2c, 0x88, + 0x37, 0x5b, 0x10, 0xef, 0x63, 0x41, 0xbc, 0xfb, 0x20, 0x96, 0xb6, 0x97, 0xf1, 0x30, 0x02, 0x45, + 0x13, 0xa9, 0x05, 0x4d, 0xb8, 0x6a, 0x98, 0xc7, 0x67, 0x3a, 0x74, 0x37, 0xe3, 0xbb, 0xc5, 0xd0, + 0xc5, 0x6f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x75, 0x0a, 0x88, 0xb3, 0xd0, 0x01, 0x00, 0x00, +} + +func (m *GenericAuthorization) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *GenericAuthorization) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *GenericAuthorization) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Msg) > 0 { + i -= len(m.Msg) + copy(dAtA[i:], m.Msg) + i = encodeVarintAuthz(dAtA, i, uint64(len(m.Msg))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *Grant) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *Grant) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Grant) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + n1, err1 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.Expiration, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.Expiration):]) + if err1 != nil { + return 0, err1 + } + i -= n1 + i = encodeVarintAuthz(dAtA, i, uint64(n1)) + i-- + dAtA[i] = 0x12 + if m.Authorization != nil { + { + size, err := m.Authorization.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintAuthz(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func encodeVarintAuthz(dAtA []byte, offset int, v uint64) int { + offset -= sovAuthz(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *GenericAuthorization) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Msg) + if l > 0 { + n += 1 + l + sovAuthz(uint64(l)) + } + return n +} + +func (m *Grant) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Authorization != nil { + l = m.Authorization.Size() + n += 1 + l + sovAuthz(uint64(l)) + } + l = github_com_gogo_protobuf_types.SizeOfStdTime(m.Expiration) + n += 1 + l + sovAuthz(uint64(l)) + return n +} + +func sovAuthz(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozAuthz(x uint64) (n int) { + return sovAuthz(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *GenericAuthorization) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAuthz + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: GenericAuthorization: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: GenericAuthorization: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Msg", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAuthz + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthAuthz + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthAuthz + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Msg = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipAuthz(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthAuthz + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *Grant) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAuthz + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: Grant: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Grant: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Authorization", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAuthz + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthAuthz + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthAuthz + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Authorization == nil { + m.Authorization = &types.Any{} + } + if err := m.Authorization.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Expiration", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAuthz + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthAuthz + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthAuthz + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := github_com_gogo_protobuf_types.StdTimeUnmarshal(&m.Expiration, dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipAuthz(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthAuthz + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipAuthz(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowAuthz + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowAuthz + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowAuthz + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthAuthz + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupAuthz + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthAuthz + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthAuthz = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowAuthz = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupAuthz = fmt.Errorf("proto: unexpected end of group") +) diff --git a/x/authz/client/cli/query.go b/x/authz/client/cli/query.go new file mode 100644 index 0000000000..a03a58e5a6 --- /dev/null +++ b/x/authz/client/cli/query.go @@ -0,0 +1,98 @@ +package cli + +import ( + "fmt" + "strings" + + "github.com/spf13/cobra" + + "github.com/line/lbm-sdk/client" + "github.com/line/lbm-sdk/client/flags" + sdk "github.com/line/lbm-sdk/types" + "github.com/line/lbm-sdk/version" + "github.com/line/lbm-sdk/x/authz" + bank "github.com/line/lbm-sdk/x/bank/types" +) + +// GetQueryCmd returns the cli query commands for this module +func GetQueryCmd() *cobra.Command { + authorizationQueryCmd := &cobra.Command{ + Use: authz.ModuleName, + Short: "Querying commands for the authz module", + Long: "", + DisableFlagParsing: true, + SuggestionsMinimumDistance: 2, + RunE: client.ValidateCmd, + } + + authorizationQueryCmd.AddCommand( + GetCmdQueryGrants(), + ) + + return authorizationQueryCmd +} + +// GetCmdQueryGrants implements the query authorization command. +func GetCmdQueryGrants() *cobra.Command { + cmd := &cobra.Command{ + Use: "grants [granter-addr] [grantee-addr] [msg-type-url]?", + Args: cobra.RangeArgs(2, 3), + Short: "query grants for a granter-grantee pair and optionally a msg-type-url", + Long: strings.TrimSpace( + fmt.Sprintf(`Query authorization grants for a granter-grantee pair. If msg-type-url +is set, it will select grants only for that msg type. +Examples: +$ %s query %s grants link1skj.. link1skjwj.. +$ %s query %s grants link1skjw.. link1skjwj.. %s +`, + version.AppName, authz.ModuleName, + version.AppName, authz.ModuleName, bank.SendAuthorization{}.MsgTypeURL()), + ), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } + queryClient := authz.NewQueryClient(clientCtx) + + err = sdk.ValidateAccAddress(args[0]) + if err != nil { + return err + } + granter := sdk.AccAddress(args[0]) + + err = sdk.ValidateAccAddress(args[1]) + if err != nil { + return err + } + grantee := sdk.AccAddress(args[1]) + + var msgAuthorized = "" + if len(args) >= 3 { + msgAuthorized = args[2] + } + + pageReq, err := client.ReadPageRequest(cmd.Flags()) + if err != nil { + return err + } + + res, err := queryClient.Grants( + cmd.Context(), + &authz.QueryGrantsRequest{ + Granter: granter.String(), + Grantee: grantee.String(), + MsgTypeUrl: msgAuthorized, + Pagination: pageReq}, + ) + if err != nil { + return err + } + + return clientCtx.PrintProto(res) + }, + } + flags.AddQueryFlagsToCmd(cmd) + flags.AddPaginationFlagsToCmd(cmd, "authorizations") + return cmd +} diff --git a/x/authz/client/cli/tx.go b/x/authz/client/cli/tx.go new file mode 100644 index 0000000000..5f527c488c --- /dev/null +++ b/x/authz/client/cli/tx.go @@ -0,0 +1,265 @@ +package cli + +import ( + "errors" + "fmt" + "strings" + "time" + + "github.com/spf13/cobra" + + "github.com/line/lbm-sdk/client" + "github.com/line/lbm-sdk/client/flags" + "github.com/line/lbm-sdk/client/tx" + sdk "github.com/line/lbm-sdk/types" + "github.com/line/lbm-sdk/version" + authclient "github.com/line/lbm-sdk/x/auth/client" + "github.com/line/lbm-sdk/x/authz" + bank "github.com/line/lbm-sdk/x/bank/types" + staking "github.com/line/lbm-sdk/x/staking/types" +) + +// Flag names and values +const ( + FlagSpendLimit = "spend-limit" + FlagMsgType = "msg-type" + FlagExpiration = "expiration" + FlagAllowedValidators = "allowed-validators" + FlagDenyValidators = "deny-validators" + delegate = "delegate" + redelegate = "redelegate" + unbond = "unbond" +) + +// GetTxCmd returns the transaction commands for this module +func GetTxCmd() *cobra.Command { + AuthorizationTxCmd := &cobra.Command{ + Use: authz.ModuleName, + Short: "Authorization transactions subcommands", + Long: "Authorize and revoke access to execute transactions on behalf of your address", + DisableFlagParsing: true, + SuggestionsMinimumDistance: 2, + RunE: client.ValidateCmd, + } + + AuthorizationTxCmd.AddCommand( + NewCmdGrantAuthorization(), + NewCmdRevokeAuthorization(), + NewCmdExecAuthorization(), + ) + + return AuthorizationTxCmd +} + +func NewCmdGrantAuthorization() *cobra.Command { + cmd := &cobra.Command{ + Use: "grant --from ", + Short: "Grant authorization to an address", + Long: strings.TrimSpace( + fmt.Sprintf(`grant authorization to an address to execute a transaction on your behalf: + +Examples: + $ %s tx %s grant link1skjw.. send %s --spend-limit=1000stake --from=link1skl.. + $ %s tx %s grant link1skjw.. generic --msg-type=/lbm.gov.v1.MsgVote --from=link1sk.. + `, version.AppName, authz.ModuleName, bank.SendAuthorization{}.MsgTypeURL(), version.AppName, authz.ModuleName), + ), + Args: cobra.ExactArgs(2), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + + err = sdk.ValidateAccAddress(args[0]) + if err != nil { + return err + } + grantee := sdk.AccAddress(args[0]) + + exp, err := cmd.Flags().GetInt64(FlagExpiration) + if err != nil { + return err + } + + var authorization authz.Authorization + switch args[1] { + case "send": + limit, err := cmd.Flags().GetString(FlagSpendLimit) + if err != nil { + return err + } + + spendLimit, err := sdk.ParseCoinsNormalized(limit) + if err != nil { + return err + } + + if !spendLimit.IsAllPositive() { + return fmt.Errorf("spend-limit should be greater than zero") + } + + authorization = bank.NewSendAuthorization(spendLimit) + case "generic": + msgType, err := cmd.Flags().GetString(FlagMsgType) + if err != nil { + return err + } + + authorization = authz.NewGenericAuthorization(msgType) + case delegate, unbond, redelegate: + limit, err := cmd.Flags().GetString(FlagSpendLimit) + if err != nil { + return err + } + + allowValidators, err := cmd.Flags().GetStringSlice(FlagAllowedValidators) + if err != nil { + return err + } + + denyValidators, err := cmd.Flags().GetStringSlice(FlagDenyValidators) + if err != nil { + return err + } + + var delegateLimit *sdk.Coin + if limit != "" { + spendLimit, err := sdk.ParseCoinsNormalized(limit) + if err != nil { + return err + } + + if !spendLimit.IsAllPositive() { + return fmt.Errorf("spend-limit should be greater than zero") + } + delegateLimit = &spendLimit[0] + } + + allowed, err := toValidatorAddresses(allowValidators) + if err != nil { + return err + } + + denied, err := toValidatorAddresses(denyValidators) + if err != nil { + return err + } + + switch args[1] { + case delegate: + authorization, err = staking.NewStakeAuthorization(allowed, denied, staking.AuthorizationType_AUTHORIZATION_TYPE_DELEGATE, delegateLimit) + case unbond: + authorization, err = staking.NewStakeAuthorization(allowed, denied, staking.AuthorizationType_AUTHORIZATION_TYPE_UNDELEGATE, delegateLimit) + default: + authorization, err = staking.NewStakeAuthorization(allowed, denied, staking.AuthorizationType_AUTHORIZATION_TYPE_REDELEGATE, delegateLimit) + } + if err != nil { + return err + } + + default: + return fmt.Errorf("invalid authorization type, %s", args[1]) + } + + msg, err := authz.NewMsgGrant(clientCtx.GetFromAddress(), grantee, authorization, time.Unix(exp, 0)) + if err != nil { + return err + } + + return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) + }, + } + flags.AddTxFlagsToCmd(cmd) + cmd.Flags().String(FlagMsgType, "", "The Msg method name for which we are creating a GenericAuthorization") + cmd.Flags().String(FlagSpendLimit, "", "SpendLimit for Send Authorization, an array of Coins allowed spend") + cmd.Flags().StringSlice(FlagAllowedValidators, []string{}, "Allowed validators addresses separated by ,") + cmd.Flags().StringSlice(FlagDenyValidators, []string{}, "Deny validators addresses separated by ,") + cmd.Flags().Int64(FlagExpiration, time.Now().AddDate(1, 0, 0).Unix(), "The Unix timestamp. Default is one year.") + return cmd +} + +func NewCmdRevokeAuthorization() *cobra.Command { + cmd := &cobra.Command{ + Use: "revoke [grantee] [msg_type] --from=[granter]", + Short: "revoke authorization", + Long: strings.TrimSpace( + fmt.Sprintf(`revoke authorization from a granter to a grantee: +Example: + $ %s tx %s revoke link1skj.. %s --from=link1skj.. + `, version.AppName, authz.ModuleName, bank.SendAuthorization{}.MsgTypeURL()), + ), + Args: cobra.ExactArgs(2), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + + err = sdk.ValidateAccAddress(args[0]) + if err != nil { + return err + } + grantee := sdk.AccAddress(args[0]) + + granter := clientCtx.GetFromAddress() + msgAuthorized := args[1] + msg := authz.NewMsgRevoke(granter, grantee, msgAuthorized) + + return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), &msg) + }, + } + flags.AddTxFlagsToCmd(cmd) + return cmd +} + +func NewCmdExecAuthorization() *cobra.Command { + cmd := &cobra.Command{ + Use: "exec [msg_tx_json_file] --from [grantee]", + Short: "execute tx on behalf of granter account", + Long: strings.TrimSpace( + fmt.Sprintf(`execute tx on behalf of granter account: +Example: + $ %s tx %s exec tx.json --from grantee + $ %s tx bank send --from --chain-id --generate-only > tx.json && %s tx %s exec tx.json --from grantee + `, version.AppName, authz.ModuleName, version.AppName, version.AppName, authz.ModuleName), + ), + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + grantee := clientCtx.GetFromAddress() + + if offline, _ := cmd.Flags().GetBool(flags.FlagOffline); offline { + return errors.New("cannot broadcast tx during offline mode") + } + + theTx, err := authclient.ReadTxFromFile(clientCtx, args[0]) + if err != nil { + return err + } + msg := authz.NewMsgExec(grantee, theTx.GetMsgs()) + + return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), &msg) + }, + } + + flags.AddTxFlagsToCmd(cmd) + + return cmd +} + +func toValidatorAddresses(validators []string) ([]sdk.ValAddress, error) { + vals := make([]sdk.ValAddress, len(validators)) + for i, validator := range validators { + err := sdk.ValidateValAddress(validator) + if err != nil { + return nil, err + } + addr := sdk.ValAddress([]byte(validator)) + vals[i] = addr + } + return vals, nil +} diff --git a/x/authz/client/rest/grpc_query_test.go b/x/authz/client/rest/grpc_query_test.go new file mode 100644 index 0000000000..534fb61e53 --- /dev/null +++ b/x/authz/client/rest/grpc_query_test.go @@ -0,0 +1,238 @@ +//go:build norace +// +build norace + +package rest_test + +import ( + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/suite" + + "github.com/line/lbm-sdk/client/flags" + "github.com/line/lbm-sdk/crypto/hd" + "github.com/line/lbm-sdk/crypto/keyring" + "github.com/line/lbm-sdk/testutil/network" + sdk "github.com/line/lbm-sdk/types" + "github.com/line/lbm-sdk/types/rest" + "github.com/line/lbm-sdk/x/authz" + "github.com/line/lbm-sdk/x/authz/client/cli" + authztestutil "github.com/line/lbm-sdk/x/authz/client/testutil" + banktestutil "github.com/line/lbm-sdk/x/bank/client/testutil" + banktypes "github.com/line/lbm-sdk/x/bank/types" + govtypes "github.com/line/lbm-sdk/x/gov/types" +) + +type IntegrationTestSuite struct { + suite.Suite + cfg network.Config + network *network.Network + grantee sdk.AccAddress +} + +var typeMsgSend = banktypes.SendAuthorization{}.MsgTypeURL() +var typeMsgVote = sdk.MsgTypeURL(&govtypes.MsgVote{}) + +func (s *IntegrationTestSuite) SetupSuite() { + s.T().Log("setting up integration test suite") + + cfg := network.DefaultConfig() + + cfg.NumValidators = 1 + s.cfg = cfg + s.network = network.New(s.T(), cfg) + + val := s.network.Validators[0] + // Create new account in the keyring. + info, _, err := val.ClientCtx.Keyring.NewMnemonic("grantee", keyring.English, sdk.FullFundraiserPath, keyring.DefaultBIP39Passphrase, hd.Secp256k1) + s.Require().NoError(err) + newAddr := sdk.BytesToAccAddress(info.GetPubKey().Address()) + + // Send some funds to the new account. + out, err := banktestutil.MsgSendExec( + val.ClientCtx, + val.Address, + newAddr, + sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(200))), fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), + fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), + ) + s.Require().NoError(err) + s.Require().Contains(out.String(), `"code":0`) + + // grant authorization + out, err = authztestutil.ExecGrant(val, []string{ + newAddr.String(), + "send", + fmt.Sprintf("--%s=100steak", cli.FlagSpendLimit), + fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()), + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), + fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(10))).String()), + fmt.Sprintf("--%s=%d", cli.FlagExpiration, time.Now().Add(time.Minute*time.Duration(120)).Unix()), + }) + s.Require().NoError(err) + s.Require().Contains(out.String(), `"code":0`) + + s.grantee = newAddr + _, err = s.network.WaitForHeight(1) + s.Require().NoError(err) +} + +func (s *IntegrationTestSuite) TearDownSuite() { + s.T().Log("tearing down integration test suite") + s.network.Cleanup() +} + +func (s *IntegrationTestSuite) TestQueryGrantGRPC() { + val := s.network.Validators[0] + grantsURL := val.APIAddress + "/lbm/authz/v1/grants?granter=%s&grantee=%s&msg_type_url=%s" + testCases := []struct { + name string + url string + expectErr bool + errorMsg string + }{ + { + "fail invalid granter address", + fmt.Sprintf(grantsURL, "invalid_granter", s.grantee.String(), typeMsgSend), + true, + "decoding bech32 failed: invalid separator index -1: invalid request", + }, + { + "fail invalid grantee address", + fmt.Sprintf(grantsURL, val.Address.String(), "invalid_grantee", typeMsgSend), + true, + "decoding bech32 failed: invalid separator index -1: invalid request", + }, + { + "fail with empty granter", + fmt.Sprintf(grantsURL, "", s.grantee.String(), typeMsgSend), + true, + "empty address string is not allowed: invalid request", + }, + { + "fail with empty grantee", + fmt.Sprintf(grantsURL, val.Address.String(), "", typeMsgSend), + true, + "empty address string is not allowed: invalid request", + }, + { + "fail invalid msg-type", + fmt.Sprintf(grantsURL, val.Address.String(), s.grantee.String(), "invalidMsg"), + true, + "rpc error: code = NotFound desc = no authorization found for invalidMsg type: key not found", + }, + { + "valid query", + fmt.Sprintf(grantsURL, val.Address.String(), s.grantee.String(), typeMsgSend), + false, + "", + }, + } + for _, tc := range testCases { + tc := tc + s.Run(tc.name, func() { + resp, _ := rest.GetRequest(tc.url) + require := s.Require() + if tc.expectErr { + require.Contains(string(resp), tc.errorMsg) + } else { + var g authz.QueryGrantsResponse + err := val.ClientCtx.Codec.UnmarshalJSON(resp, &g) + require.NoError(err) + require.Len(g.Grants, 1) + g.Grants[0].UnpackInterfaces(val.ClientCtx.InterfaceRegistry) + auth := g.Grants[0].GetAuthorization() + require.Equal(auth.MsgTypeURL(), banktypes.SendAuthorization{}.MsgTypeURL()) + } + }) + } +} + +func (s *IntegrationTestSuite) TestQueryGrantsGRPC() { + val := s.network.Validators[0] + grantsURL := val.APIAddress + "/lbm/authz/v1/grants?granter=%s&grantee=%s" + testCases := []struct { + name string + url string + expectErr bool + errMsg string + preRun func() + postRun func(*authz.QueryGrantsResponse) + }{ + { + "valid query: expect single grant", + fmt.Sprintf(grantsURL, val.Address.String(), s.grantee.String()), + false, + "", + func() {}, + func(g *authz.QueryGrantsResponse) { + s.Require().Len(g.Grants, 1) + }, + }, + { + "valid query: expect two grants", + fmt.Sprintf(grantsURL, val.Address.String(), s.grantee.String()), + false, + "", + func() { + _, err := authztestutil.ExecGrant(val, []string{ + s.grantee.String(), + "generic", + fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()), + fmt.Sprintf("--%s=%s", cli.FlagMsgType, typeMsgVote), + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), + fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(10))).String()), + fmt.Sprintf("--%s=%d", cli.FlagExpiration, time.Now().Add(time.Minute*time.Duration(120)).Unix()), + }) + s.Require().NoError(err) + }, + func(g *authz.QueryGrantsResponse) { + s.Require().Len(g.Grants, 2) + }, + }, + { + "valid query: expect single grant with pagination", + fmt.Sprintf(grantsURL+"&pagination.limit=1", val.Address.String(), s.grantee.String()), + false, + "", + func() {}, + func(g *authz.QueryGrantsResponse) { + s.Require().Len(g.Grants, 1) + }, + }, + { + "valid query: expect two grants with pagination", + fmt.Sprintf(grantsURL+"&pagination.limit=2", val.Address.String(), s.grantee.String()), + false, + "", + func() {}, + func(g *authz.QueryGrantsResponse) { + s.Require().Len(g.Grants, 2) + }, + }, + } + for _, tc := range testCases { + tc := tc + s.Run(tc.name, func() { + tc.preRun() + resp, _ := rest.GetRequest(tc.url) + if tc.expectErr { + s.Require().Contains(string(resp), tc.errMsg) + } else { + var authorizations authz.QueryGrantsResponse + err := val.ClientCtx.Codec.UnmarshalJSON(resp, &authorizations) + s.Require().NoError(err) + tc.postRun(&authorizations) + } + + }) + } +} + +func TestIntegrationTestSuite(t *testing.T) { + suite.Run(t, new(IntegrationTestSuite)) +} diff --git a/x/authz/client/testutil/cli_test.go b/x/authz/client/testutil/cli_test.go new file mode 100644 index 0000000000..f979202abe --- /dev/null +++ b/x/authz/client/testutil/cli_test.go @@ -0,0 +1,18 @@ +//go:build norace +// +build norace + +package testutil + +import ( + "testing" + + "github.com/stretchr/testify/suite" + + "github.com/line/lbm-sdk/testutil/network" +) + +func TestIntegrationTestSuite(t *testing.T) { + cfg := network.DefaultConfig() + cfg.NumValidators = 1 + suite.Run(t, NewIntegrationTestSuite(cfg)) +} diff --git a/x/authz/client/testutil/query.go b/x/authz/client/testutil/query.go new file mode 100644 index 0000000000..037a07df18 --- /dev/null +++ b/x/authz/client/testutil/query.go @@ -0,0 +1,182 @@ +package testutil + +import ( + "fmt" + "strings" + "time" + + ostcli "github.com/line/ostracon/libs/cli" + + "github.com/line/lbm-sdk/client/flags" + clitestutil "github.com/line/lbm-sdk/testutil/cli" + sdk "github.com/line/lbm-sdk/types" + "github.com/line/lbm-sdk/x/authz" + "github.com/line/lbm-sdk/x/authz/client/cli" +) + +func (s *IntegrationTestSuite) TestQueryAuthorizations() { + val := s.network.Validators[0] + + grantee := s.grantee + twoHours := time.Now().Add(time.Minute * time.Duration(120)).Unix() + + _, err := ExecGrant( + val, + []string{ + grantee.String(), + "send", + fmt.Sprintf("--%s=100steak", cli.FlagSpendLimit), + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), + fmt.Sprintf("--%s=%d", cli.FlagExpiration, twoHours), + fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), + }, + ) + s.Require().NoError(err) + + testCases := []struct { + name string + args []string + expectErr bool + expErrMsg string + }{ + { + "Error: Invalid grantee", + []string{ + val.Address.String(), + "invalid grantee", + fmt.Sprintf("--%s=json", ostcli.OutputFlag), + }, + true, + "decoding bech32 failed: invalid character in string: ' '", + }, + { + "Error: Invalid granter", + []string{ + "invalid granter", + grantee.String(), + fmt.Sprintf("--%s=json", ostcli.OutputFlag), + }, + true, + "decoding bech32 failed: invalid character in string: ' '", + }, + { + "Valid txn (json)", + []string{ + val.Address.String(), + grantee.String(), + fmt.Sprintf("--%s=json", ostcli.OutputFlag), + }, + false, + ``, + }, + } + for _, tc := range testCases { + tc := tc + + s.Run(tc.name, func() { + cmd := cli.GetCmdQueryGrants() + clientCtx := val.ClientCtx + resp, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, tc.args) + if tc.expectErr { + s.Require().Error(err) + s.Require().Contains(string(resp.Bytes()), tc.expErrMsg) + } else { + s.Require().NoError(err) + var grants authz.QueryGrantsResponse + err = val.ClientCtx.Codec.UnmarshalJSON(resp.Bytes(), &grants) + s.Require().NoError(err) + } + }) + } +} + +func (s *IntegrationTestSuite) TestQueryAuthorization() { + val := s.network.Validators[0] + + grantee := s.grantee + twoHours := time.Now().Add(time.Minute * time.Duration(120)).Unix() + + _, err := ExecGrant( + val, + []string{ + grantee.String(), + "send", + fmt.Sprintf("--%s=100steak", cli.FlagSpendLimit), + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), + fmt.Sprintf("--%s=%d", cli.FlagExpiration, twoHours), + fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), + }, + ) + s.Require().NoError(err) + + testCases := []struct { + name string + args []string + expectErr bool + expectedOutput string + }{ + { + "Error: Invalid grantee", + []string{ + val.Address.String(), + "invalid grantee", + typeMsgSend, + fmt.Sprintf("--%s=json", ostcli.OutputFlag), + }, + true, + "", + }, + { + "Error: Invalid granter", + []string{ + "invalid granter", + grantee.String(), + typeMsgSend, + fmt.Sprintf("--%s=json", ostcli.OutputFlag), + }, + true, + "", + }, + { + "no authorization found", + []string{ + val.Address.String(), + grantee.String(), + "typeMsgSend", + fmt.Sprintf("--%s=json", ostcli.OutputFlag), + }, + true, + "", + }, + { + "Valid txn (json)", + []string{ + val.Address.String(), + grantee.String(), + typeMsgSend, + fmt.Sprintf("--%s=json", ostcli.OutputFlag), + }, + false, + `{"@type":"/lbm.bank.v1.SendAuthorization","spend_limit":[{"denom":"steak","amount":"100"}]}`, + }, + } + for _, tc := range testCases { + tc := tc + + s.Run(tc.name, func() { + cmd := cli.GetCmdQueryGrants() + clientCtx := val.ClientCtx + out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, tc.args) + if tc.expectErr { + s.Require().Error(err) + } else { + s.Require().NoError(err) + s.Require().Contains(strings.TrimSpace(out.String()), tc.expectedOutput) + } + }) + } +} diff --git a/x/authz/client/testutil/test_helpers.go b/x/authz/client/testutil/test_helpers.go new file mode 100644 index 0000000000..42eccb1ff6 --- /dev/null +++ b/x/authz/client/testutil/test_helpers.go @@ -0,0 +1,14 @@ +package testutil + +import ( + "github.com/line/lbm-sdk/testutil" + clitestutil "github.com/line/lbm-sdk/testutil/cli" + "github.com/line/lbm-sdk/testutil/network" + "github.com/line/lbm-sdk/x/authz/client/cli" +) + +func ExecGrant(val *network.Validator, args []string) (testutil.BufferWriter, error) { + cmd := cli.NewCmdGrantAuthorization() + clientCtx := val.ClientCtx + return clitestutil.ExecTestCLICmd(clientCtx, cmd, args) +} diff --git a/x/authz/client/testutil/tx.go b/x/authz/client/testutil/tx.go new file mode 100644 index 0000000000..515ac42132 --- /dev/null +++ b/x/authz/client/testutil/tx.go @@ -0,0 +1,1075 @@ +package testutil + +import ( + "fmt" + "time" + + "github.com/gogo/protobuf/proto" + "github.com/stretchr/testify/suite" + + "github.com/line/lbm-sdk/client/flags" + "github.com/line/lbm-sdk/crypto/hd" + "github.com/line/lbm-sdk/crypto/keyring" + "github.com/line/lbm-sdk/testutil" + clitestutil "github.com/line/lbm-sdk/testutil/cli" + "github.com/line/lbm-sdk/testutil/network" + sdk "github.com/line/lbm-sdk/types" + "github.com/line/lbm-sdk/x/authz/client/cli" + banktestutil "github.com/line/lbm-sdk/x/bank/client/testutil" + bank "github.com/line/lbm-sdk/x/bank/types" + govcli "github.com/line/lbm-sdk/x/gov/client/cli" + govtestutil "github.com/line/lbm-sdk/x/gov/client/testutil" + govtypes "github.com/line/lbm-sdk/x/gov/types" + stakingcli "github.com/line/lbm-sdk/x/staking/client/cli" +) + +type IntegrationTestSuite struct { + suite.Suite + + cfg network.Config + network *network.Network + grantee sdk.AccAddress +} + +func NewIntegrationTestSuite(cfg network.Config) *IntegrationTestSuite { + return &IntegrationTestSuite{cfg: cfg} +} + +func (s *IntegrationTestSuite) SetupSuite() { + s.T().Log("setting up integration test suite") + + s.network = network.New(s.T(), s.cfg) + + val := s.network.Validators[0] + + // Create new account in the keyring. + info, _, err := val.ClientCtx.Keyring.NewMnemonic("grantee", keyring.English, sdk.FullFundraiserPath, keyring.DefaultBIP39Passphrase, hd.Secp256k1) + s.Require().NoError(err) + newAddr := sdk.BytesToAccAddress(info.GetPubKey().Address().Bytes()) + + // Send some funds to the new account. + _, err = banktestutil.MsgSendExec( + val.ClientCtx, + val.Address, + newAddr, + sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(200))), fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), + fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), + ) + s.Require().NoError(err) + s.grantee = newAddr + + _, err = s.network.WaitForHeight(1) + s.Require().NoError(err) + + // create a proposal with deposit + _, err = govtestutil.MsgSubmitProposal(val.ClientCtx, val.Address.String(), + "Text Proposal 1", "Where is the title!?", govtypes.ProposalTypeText, + fmt.Sprintf("--%s=%s", govcli.FlagDeposit, sdk.NewCoin(s.cfg.BondDenom, govtypes.DefaultMinDepositTokens).String())) + s.Require().NoError(err) + + _, err = s.network.WaitForHeight(1) + s.Require().NoError(err) +} + +func (s *IntegrationTestSuite) TearDownSuite() { + s.T().Log("tearing down integration test suite") + s.network.Cleanup() +} + +var typeMsgSend = bank.SendAuthorization{}.MsgTypeURL() +var typeMsgVote = sdk.MsgTypeURL(&govtypes.MsgVote{}) +var typeMsgSubmitProposal = sdk.MsgTypeURL(&govtypes.MsgSubmitProposal{}) + +func (s *IntegrationTestSuite) TestCLITxGrantAuthorization() { + val := s.network.Validators[0] + grantee := s.grantee + + twoHours := time.Now().Add(time.Minute * time.Duration(120)).Unix() + pastHour := time.Now().Add(time.Minute * time.Duration(-60)).Unix() + + testCases := []struct { + name string + args []string + expectedCode uint32 + expectErr bool + }{ + { + "Invalid granter Address", + []string{ + "grantee_addr", + "send", + fmt.Sprintf("--%s=100steak", cli.FlagSpendLimit), + fmt.Sprintf("--%s=%s", flags.FlagFrom, "granter"), + fmt.Sprintf("--%s=true", flags.FlagGenerateOnly), + fmt.Sprintf("--%s=%d", cli.FlagExpiration, twoHours), + }, + 0, + true, + }, + { + "Invalid grantee Address", + []string{ + "grantee_addr", + "send", + fmt.Sprintf("--%s=100steak", cli.FlagSpendLimit), + fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()), + fmt.Sprintf("--%s=true", flags.FlagGenerateOnly), + fmt.Sprintf("--%s=%d", cli.FlagExpiration, twoHours), + }, + 0, + true, + }, + { + "Invalid expiration time", + []string{ + grantee.String(), + "send", + fmt.Sprintf("--%s=100steak", cli.FlagSpendLimit), + fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()), + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + fmt.Sprintf("--%s=%d", cli.FlagExpiration, pastHour), + }, + 0xd, + false, // TODO: enable in v0.45 + }, + { + "fail with error invalid msg-type", + []string{ + grantee.String(), + "generic", + fmt.Sprintf("--%s=invalid-msg-type", cli.FlagMsgType), + fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), + fmt.Sprintf("--%s=%d", cli.FlagExpiration, twoHours), + }, + 0x1d, + false, + }, + { + "failed with error both validators not allowed", + []string{ + grantee.String(), + "delegate", + fmt.Sprintf("--%s=100stake", cli.FlagSpendLimit), + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), + fmt.Sprintf("--%s=%d", cli.FlagExpiration, twoHours), + fmt.Sprintf("--%s=%s", cli.FlagAllowedValidators, val.ValAddress.String()), + fmt.Sprintf("--%s=%s", cli.FlagDenyValidators, val.ValAddress.String()), + fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), + }, + 0, + true, + }, + { + "valid tx delegate authorization allowed validators", + []string{ + grantee.String(), + "delegate", + fmt.Sprintf("--%s=100stake", cli.FlagSpendLimit), + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), + fmt.Sprintf("--%s=%d", cli.FlagExpiration, twoHours), + fmt.Sprintf("--%s=%s", cli.FlagAllowedValidators, val.ValAddress.String()), + fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), + }, + 0, + false, + }, + { + "valid tx delegate authorization deny validators", + []string{ + grantee.String(), + "delegate", + fmt.Sprintf("--%s=100stake", cli.FlagSpendLimit), + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), + fmt.Sprintf("--%s=%d", cli.FlagExpiration, twoHours), + fmt.Sprintf("--%s=%s", cli.FlagDenyValidators, val.ValAddress.String()), + fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), + }, + 0, + false, + }, + { + "valid tx undelegate authorization", + []string{ + grantee.String(), + "unbond", + fmt.Sprintf("--%s=100stake", cli.FlagSpendLimit), + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), + fmt.Sprintf("--%s=%d", cli.FlagExpiration, twoHours), + fmt.Sprintf("--%s=%s", cli.FlagAllowedValidators, val.ValAddress.String()), + fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), + }, + 0, + false, + }, + { + "valid tx redelegate authorization", + []string{ + grantee.String(), + "redelegate", + fmt.Sprintf("--%s=100stake", cli.FlagSpendLimit), + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), + fmt.Sprintf("--%s=%d", cli.FlagExpiration, twoHours), + fmt.Sprintf("--%s=%s", cli.FlagAllowedValidators, val.ValAddress.String()), + fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), + }, + 0, + false, + }, + { + "Valid tx send authorization", + []string{ + grantee.String(), + "send", + fmt.Sprintf("--%s=100steak", cli.FlagSpendLimit), + fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), + fmt.Sprintf("--%s=%d", cli.FlagExpiration, twoHours), + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), + }, + 0, + false, + }, + { + "Valid tx generic authorization", + []string{ + grantee.String(), + "generic", + fmt.Sprintf("--%s=%s", cli.FlagMsgType, typeMsgVote), + fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), + fmt.Sprintf("--%s=%d", cli.FlagExpiration, twoHours), + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), + }, + 0, + false, + }, + { + "Valid tx with amino", + []string{ + grantee.String(), + "generic", + fmt.Sprintf("--%s=%s", cli.FlagMsgType, typeMsgVote), + fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), + fmt.Sprintf("--%s=%d", cli.FlagExpiration, twoHours), + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), + fmt.Sprintf("--%s=%s", flags.FlagSignMode, flags.SignModeLegacyAminoJSON), + }, + 0, + false, + }, + } + + for _, tc := range testCases { + tc := tc + s.Run(tc.name, func() { + clientCtx := val.ClientCtx + out, err := ExecGrant( + val, + tc.args, + ) + if tc.expectErr { + s.Require().Error(err) + } else { + var txResp sdk.TxResponse + s.Require().NoError(err) + s.Require().NoError(clientCtx.Codec.UnmarshalJSON(out.Bytes(), &txResp), out.String()) + s.Require().Equal(tc.expectedCode, txResp.Code, out.String()) + } + }) + } +} + +func execDelegate(val *network.Validator, args []string) (testutil.BufferWriter, error) { + cmd := stakingcli.NewDelegateCmd() + clientCtx := val.ClientCtx + return clitestutil.ExecTestCLICmd(clientCtx, cmd, args) +} + +func (s *IntegrationTestSuite) TestCmdRevokeAuthorizations() { + val := s.network.Validators[0] + + grantee := s.grantee + twoHours := time.Now().Add(time.Minute * time.Duration(120)).Unix() + + // send-authorization + _, err := ExecGrant( + val, + []string{ + grantee.String(), + "send", + fmt.Sprintf("--%s=100steak", cli.FlagSpendLimit), + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), + fmt.Sprintf("--%s=%d", cli.FlagExpiration, twoHours), + fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), + }, + ) + s.Require().NoError(err) + + // generic-authorization + _, err = ExecGrant( + val, + []string{ + grantee.String(), + "generic", + fmt.Sprintf("--%s=%s", cli.FlagMsgType, typeMsgVote), + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), + fmt.Sprintf("--%s=%d", cli.FlagExpiration, twoHours), + fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), + }, + ) + s.Require().NoError(err) + + // generic-authorization used for amino testing + _, err = ExecGrant( + val, + []string{ + grantee.String(), + "generic", + fmt.Sprintf("--%s=%s", cli.FlagMsgType, typeMsgSubmitProposal), + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), + fmt.Sprintf("--%s=%d", cli.FlagExpiration, twoHours), + fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), + fmt.Sprintf("--%s=%s", flags.FlagSignMode, flags.SignModeLegacyAminoJSON), + }, + ) + s.Require().NoError(err) + + testCases := []struct { + name string + args []string + respType proto.Message + expectedCode uint32 + expectErr bool + }{ + { + "invalid grantee address", + []string{ + "invalid grantee", + typeMsgSend, + fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()), + fmt.Sprintf("--%s=true", flags.FlagGenerateOnly), + }, + nil, + 0, + true, + }, + { + "invalid granter address", + []string{ + grantee.String(), + typeMsgSend, + fmt.Sprintf("--%s=%s", flags.FlagFrom, "granter"), + fmt.Sprintf("--%s=true", flags.FlagGenerateOnly), + }, + nil, + 0, + true, + }, + { + "Valid tx send authorization", + []string{ + grantee.String(), + typeMsgSend, + fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), + }, + &sdk.TxResponse{}, 0, + false, + }, + { + "Valid tx generic authorization", + []string{ + grantee.String(), + typeMsgVote, + fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), + }, + &sdk.TxResponse{}, 0, + false, + }, + { + "Valid tx with amino", + []string{ + grantee.String(), + typeMsgSubmitProposal, + fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), + fmt.Sprintf("--%s=%s", flags.FlagSignMode, flags.SignModeLegacyAminoJSON), + }, + &sdk.TxResponse{}, 0, + false, + }, + } + for _, tc := range testCases { + tc := tc + s.Run(tc.name, func() { + cmd := cli.NewCmdRevokeAuthorization() + clientCtx := val.ClientCtx + + out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, tc.args) + if tc.expectErr { + s.Require().Error(err) + } else { + s.Require().NoError(err) + s.Require().NoError(clientCtx.Codec.UnmarshalJSON(out.Bytes(), tc.respType), out.String()) + + txResp := tc.respType.(*sdk.TxResponse) + s.Require().Equal(tc.expectedCode, txResp.Code, out.String()) + } + }) + } +} + +func (s *IntegrationTestSuite) TestExecAuthorizationWithExpiration() { + val := s.network.Validators[0] + grantee := s.grantee + tenSeconds := time.Now().Add(time.Second * time.Duration(10)).Unix() + + _, err := ExecGrant( + val, + []string{ + grantee.String(), + "generic", + fmt.Sprintf("--%s=%s", cli.FlagMsgType, typeMsgVote), + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), + fmt.Sprintf("--%s=%d", cli.FlagExpiration, tenSeconds), + fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), + }, + ) + s.Require().NoError(err) + // msg vote + voteTx := fmt.Sprintf(`{"body":{"messages":[{"@type":"/lbm.gov.v1.MsgVote","proposal_id":"1","voter":"%s","option":"VOTE_OPTION_YES"}],"memo":"","timeout_height":"0","extension_options":[],"non_critical_extension_options":[]},"auth_info":{"signer_infos":[],"fee":{"amount":[],"gas_limit":"200000","payer":"","granter":""}},"signatures":[]}`, val.Address.String()) + execMsg := testutil.WriteToNewTempFile(s.T(), voteTx) + + // waiting for authorization to expires + time.Sleep(12 * time.Second) + + cmd := cli.NewCmdExecAuthorization() + clientCtx := val.ClientCtx + + res, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, []string{ + execMsg.Name(), + fmt.Sprintf("--%s=%s", flags.FlagFrom, grantee.String()), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), + fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + }) + s.Require().NoError(err) + s.Require().Contains(res.String(), "authorization not found") +} + +func (s *IntegrationTestSuite) TestNewExecGenericAuthorized() { + val := s.network.Validators[0] + grantee := s.grantee + twoHours := time.Now().Add(time.Minute * time.Duration(120)).Unix() + + _, err := ExecGrant( + val, + []string{ + grantee.String(), + "generic", + fmt.Sprintf("--%s=%s", cli.FlagMsgType, typeMsgVote), + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), + fmt.Sprintf("--%s=%d", cli.FlagExpiration, twoHours), + fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), + }, + ) + s.Require().NoError(err) + + // msg vote + voteTx := fmt.Sprintf(`{"body":{"messages":[{"@type":"/lbm.gov.v1.MsgVote","proposal_id":"1","voter":"%s","option":"VOTE_OPTION_YES"}],"memo":"","timeout_height":"0","extension_options":[],"non_critical_extension_options":[]},"auth_info":{"signer_infos":[],"fee":{"amount":[],"gas_limit":"200000","payer":"","granter":""}},"signatures":[]}`, val.Address.String()) + execMsg := testutil.WriteToNewTempFile(s.T(), voteTx) + + testCases := []struct { + name string + args []string + respType proto.Message + expectedCode uint32 + expectErr bool + }{ + { + "fail invalid grantee", + []string{ + execMsg.Name(), + fmt.Sprintf("--%s=%s", flags.FlagFrom, "grantee"), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), + fmt.Sprintf("--%s=true", flags.FlagGenerateOnly), + }, + nil, + 0, + true, + }, + { + "fail invalid json path", + []string{ + "/invalid/file.txt", + fmt.Sprintf("--%s=%s", flags.FlagFrom, grantee.String()), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), + }, + nil, + 0, + true, + }, + { + "valid txn", + []string{ + execMsg.Name(), + fmt.Sprintf("--%s=%s", flags.FlagFrom, grantee.String()), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), + fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + }, + &sdk.TxResponse{}, + 0, + false, + }, + { + "valid tx with amino", + []string{ + execMsg.Name(), + fmt.Sprintf("--%s=%s", flags.FlagFrom, grantee.String()), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), + fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + fmt.Sprintf("--%s=%s", flags.FlagSignMode, flags.SignModeLegacyAminoJSON), + }, + &sdk.TxResponse{}, 0, + false, + }, + } + + for _, tc := range testCases { + tc := tc + s.Run(tc.name, func() { + + cmd := cli.NewCmdExecAuthorization() + clientCtx := val.ClientCtx + + out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, tc.args) + if tc.expectErr { + s.Require().Error(err) + } else { + s.Require().NoError(err) + s.Require().NoError(clientCtx.Codec.UnmarshalJSON(out.Bytes(), tc.respType), out.String()) + txResp := tc.respType.(*sdk.TxResponse) + s.Require().Equal(tc.expectedCode, txResp.Code, out.String()) + } + }) + } +} + +func (s *IntegrationTestSuite) TestNewExecGrantAuthorized() { + val := s.network.Validators[0] + grantee := s.grantee + twoHours := time.Now().Add(time.Minute * time.Duration(120)).Unix() + + _, err := ExecGrant( + val, + []string{ + grantee.String(), + "send", + fmt.Sprintf("--%s=12%stoken", cli.FlagSpendLimit, val.Moniker), + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), + fmt.Sprintf("--%s=%d", cli.FlagExpiration, twoHours), + fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), + }, + ) + s.Require().NoError(err) + tokens := sdk.NewCoins( + sdk.NewCoin(fmt.Sprintf("%stoken", val.Moniker), sdk.NewInt(12)), + ) + normalGeneratedTx, err := banktestutil.MsgSendExec( + val.ClientCtx, + val.Address, + grantee, + tokens, + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), + fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), + fmt.Sprintf("--%s=true", flags.FlagGenerateOnly), + ) + s.Require().NoError(err) + execMsg := testutil.WriteToNewTempFile(s.T(), normalGeneratedTx.String()) + testCases := []struct { + name string + args []string + expectedCode uint32 + expectErr bool + }{ + { + "valid txn", + []string{ + execMsg.Name(), + fmt.Sprintf("--%s=%s", flags.FlagFrom, grantee.String()), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), + fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + }, + 0, + false, + }, + { + "error over spent", + []string{ + execMsg.Name(), + fmt.Sprintf("--%s=%s", flags.FlagFrom, grantee.String()), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), + fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + }, + 4, + false, + }, + } + + for _, tc := range testCases { + tc := tc + s.Run(tc.name, func() { + cmd := cli.NewCmdExecAuthorization() + clientCtx := val.ClientCtx + + out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, tc.args) + if tc.expectErr { + s.Require().Error(err) + } else { + var response sdk.TxResponse + s.Require().NoError(err) + s.Require().NoError(clientCtx.Codec.UnmarshalJSON(out.Bytes(), &response), out.String()) + s.Require().Equal(tc.expectedCode, response.Code, out.String()) + } + }) + } +} + +func (s *IntegrationTestSuite) TestExecDelegateAuthorization() { + val := s.network.Validators[0] + grantee := s.grantee + twoHours := time.Now().Add(time.Minute * time.Duration(120)).Unix() + + _, err := ExecGrant( + val, + []string{ + grantee.String(), + "delegate", + fmt.Sprintf("--%s=100stake", cli.FlagSpendLimit), + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), + fmt.Sprintf("--%s=%d", cli.FlagExpiration, twoHours), + fmt.Sprintf("--%s=%s", cli.FlagAllowedValidators, val.ValAddress.String()), + fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), + }, + ) + s.Require().NoError(err) + + tokens := sdk.NewCoins( + sdk.NewCoin("stake", sdk.NewInt(50)), + ) + + delegateTx := fmt.Sprintf(`{"body":{"messages":[{"@type":"/lbm.staking.v1.MsgDelegate","delegator_address":"%s","validator_address":"%s","amount":{"denom":"%s","amount":"%s"}}],"memo":"","timeout_height":"0","extension_options":[],"non_critical_extension_options":[]},"auth_info":{"signer_infos":[],"fee":{"amount":[],"gas_limit":"200000","payer":"","granter":""}},"signatures":[]}`, val.Address.String(), val.ValAddress.String(), + tokens.GetDenomByIndex(0), tokens[0].Amount) + execMsg := testutil.WriteToNewTempFile(s.T(), delegateTx) + + testCases := []struct { + name string + args []string + expectedCode uint32 + expectErr bool + errMsg string + }{ + { + "valid txn: (delegate half tokens)", + []string{ + execMsg.Name(), + fmt.Sprintf("--%s=%s", flags.FlagFrom, grantee.String()), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), + fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + }, + 0, + false, + "", + }, + { + "valid txn: (delegate remaining half tokens)", + []string{ + execMsg.Name(), + fmt.Sprintf("--%s=%s", flags.FlagFrom, grantee.String()), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), + fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + }, + 0, + false, + "", + }, + { + "failed with error no authorization found", + []string{ + execMsg.Name(), + fmt.Sprintf("--%s=%s", flags.FlagFrom, grantee.String()), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), + fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + }, + 4, + false, + "authorization not found", + }, + } + + for _, tc := range testCases { + tc := tc + s.Run(tc.name, func() { + cmd := cli.NewCmdExecAuthorization() + clientCtx := val.ClientCtx + + out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, tc.args) + if tc.expectErr { + s.Require().Error(err) + s.Require().Contains(err.Error(), tc.errMsg) + } else { + var response sdk.TxResponse + s.Require().NoError(err) + s.Require().NoError(clientCtx.Codec.UnmarshalJSON(out.Bytes(), &response), out.String()) + s.Require().Equal(tc.expectedCode, response.Code, out.String()) + } + }) + } + + // test delegate no spend-limit + _, err = ExecGrant( + val, + []string{ + grantee.String(), + "delegate", + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), + fmt.Sprintf("--%s=%d", cli.FlagExpiration, twoHours), + fmt.Sprintf("--%s=%s", cli.FlagAllowedValidators, val.ValAddress.String()), + fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), + }, + ) + s.Require().NoError(err) + tokens = sdk.NewCoins( + sdk.NewCoin("stake", sdk.NewInt(50)), + ) + + delegateTx = fmt.Sprintf(`{"body":{"messages":[{"@type":"/lbm.staking.v1.MsgDelegate","delegator_address":"%s","validator_address":"%s","amount":{"denom":"%s","amount":"%s"}}],"memo":"","timeout_height":"0","extension_options":[],"non_critical_extension_options":[]},"auth_info":{"signer_infos":[],"fee":{"amount":[],"gas_limit":"200000","payer":"","granter":""}},"signatures":[]}`, val.Address.String(), val.ValAddress.String(), + tokens.GetDenomByIndex(0), tokens[0].Amount) + execMsg = testutil.WriteToNewTempFile(s.T(), delegateTx) + + testCases = []struct { + name string + args []string + expectedCode uint32 + expectErr bool + errMsg string + }{ + { + "valid txn", + []string{ + execMsg.Name(), + fmt.Sprintf("--%s=%s", flags.FlagFrom, grantee.String()), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), + fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + }, + 0, + false, + "", + }, + { + "valid txn", + []string{ + execMsg.Name(), + fmt.Sprintf("--%s=%s", flags.FlagFrom, grantee.String()), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), + fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + }, + 0, + false, + "", + }, + } + + for _, tc := range testCases { + tc := tc + s.Run(tc.name, func() { + cmd := cli.NewCmdExecAuthorization() + clientCtx := val.ClientCtx + + out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, tc.args) + if tc.expectErr { + s.Require().Error(err) + s.Require().Contains(err.Error(), tc.errMsg) + } else { + var response sdk.TxResponse + s.Require().NoError(err) + s.Require().NoError(clientCtx.Codec.UnmarshalJSON(out.Bytes(), &response), out.String()) + s.Require().Equal(tc.expectedCode, response.Code, out.String()) + } + }) + } + + // test delegating to denied validator + _, err = ExecGrant( + val, + []string{ + grantee.String(), + "delegate", + fmt.Sprintf("--%s=100stake", cli.FlagSpendLimit), + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), + fmt.Sprintf("--%s=%d", cli.FlagExpiration, twoHours), + fmt.Sprintf("--%s=%s", cli.FlagDenyValidators, val.ValAddress.String()), + fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), + }, + ) + s.Require().NoError(err) + + args := []string{ + execMsg.Name(), + fmt.Sprintf("--%s=%s", flags.FlagFrom, grantee.String()), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), + fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + } + cmd := cli.NewCmdExecAuthorization() + out, err := clitestutil.ExecTestCLICmd(val.ClientCtx, cmd, args) + s.Require().NoError(err) + s.Contains(out.String(), fmt.Sprintf("cannot delegate/undelegate to %s validator", val.ValAddress.String())) +} + +func (s *IntegrationTestSuite) TestExecUndelegateAuthorization() { + val := s.network.Validators[0] + grantee := s.grantee + twoHours := time.Now().Add(time.Minute * time.Duration(120)).Unix() + + // granting undelegate msg authorization + _, err := ExecGrant( + val, + []string{ + grantee.String(), + "unbond", + fmt.Sprintf("--%s=100stake", cli.FlagSpendLimit), + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), + fmt.Sprintf("--%s=%d", cli.FlagExpiration, twoHours), + fmt.Sprintf("--%s=%s", cli.FlagAllowedValidators, val.ValAddress.String()), + fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), + }, + ) + s.Require().NoError(err) + + // delegating stakes to validator + _, err = execDelegate( + val, + []string{ + val.ValAddress.String(), + "100stake", + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), + fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), + }, + ) + s.Require().NoError(err) + + tokens := sdk.NewCoins( + sdk.NewCoin("stake", sdk.NewInt(50)), + ) + + undelegateTx := fmt.Sprintf(`{"body":{"messages":[{"@type":"/lbm.staking.v1.MsgUndelegate","delegator_address":"%s","validator_address":"%s","amount":{"denom":"%s","amount":"%s"}}],"memo":"","timeout_height":"0","extension_options":[],"non_critical_extension_options":[]},"auth_info":{"signer_infos":[],"fee":{"amount":[],"gas_limit":"200000","payer":"","granter":""}},"signatures":[]}`, val.Address.String(), val.ValAddress.String(), + tokens.GetDenomByIndex(0), tokens[0].Amount) + execMsg := testutil.WriteToNewTempFile(s.T(), undelegateTx) + + testCases := []struct { + name string + args []string + expectedCode uint32 + expectErr bool + errMsg string + }{ + { + "valid txn: (undelegate half tokens)", + []string{ + execMsg.Name(), + fmt.Sprintf("--%s=%s", flags.FlagGas, "250000"), + fmt.Sprintf("--%s=%s", flags.FlagFrom, grantee.String()), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), + fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + }, + 0, + false, + "", + }, + { + "valid txn: (undelegate remaining half tokens)", + []string{ + execMsg.Name(), + fmt.Sprintf("--%s=%s", flags.FlagGas, "250000"), + fmt.Sprintf("--%s=%s", flags.FlagFrom, grantee.String()), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), + fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + }, + 0, + false, + "", + }, + { + "failed with error no authorization found", + []string{ + execMsg.Name(), + fmt.Sprintf("--%s=%s", flags.FlagGas, "250000"), + fmt.Sprintf("--%s=%s", flags.FlagFrom, grantee.String()), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), + fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + }, + 4, + false, + "authorization not found", + }, + } + + for _, tc := range testCases { + tc := tc + s.Run(tc.name, func() { + cmd := cli.NewCmdExecAuthorization() + clientCtx := val.ClientCtx + + out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, tc.args) + if tc.expectErr { + s.Require().Error(err) + s.Require().Contains(err.Error(), tc.errMsg) + } else { + var response sdk.TxResponse + s.Require().NoError(err) + s.Require().NoError(clientCtx.Codec.UnmarshalJSON(out.Bytes(), &response), out.String()) + s.Require().Equal(tc.expectedCode, response.Code, out.String()) + } + }) + } + + // grant undelegate authorization without limit + _, err = ExecGrant( + val, + []string{ + grantee.String(), + "unbond", + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), + fmt.Sprintf("--%s=%d", cli.FlagExpiration, twoHours), + fmt.Sprintf("--%s=%s", cli.FlagAllowedValidators, val.ValAddress.String()), + fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), + }, + ) + s.Require().NoError(err) + tokens = sdk.NewCoins( + sdk.NewCoin("stake", sdk.NewInt(50)), + ) + + undelegateTx = fmt.Sprintf(`{"body":{"messages":[{"@type":"/lbm.staking.v1.MsgUndelegate","delegator_address":"%s","validator_address":"%s","amount":{"denom":"%s","amount":"%s"}}],"memo":"","timeout_height":"0","extension_options":[],"non_critical_extension_options":[]},"auth_info":{"signer_infos":[],"fee":{"amount":[],"gas_limit":"200000","payer":"","granter":""}},"signatures":[]}`, val.Address.String(), val.ValAddress.String(), + tokens.GetDenomByIndex(0), tokens[0].Amount) + execMsg = testutil.WriteToNewTempFile(s.T(), undelegateTx) + + testCases = []struct { + name string + args []string + expectedCode uint32 + expectErr bool + errMsg string + }{ + { + "valid txn", + []string{ + execMsg.Name(), + fmt.Sprintf("--%s=%s", flags.FlagGas, "250000"), + fmt.Sprintf("--%s=%s", flags.FlagFrom, grantee.String()), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), + fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + }, + 0, + false, + "", + }, + { + "valid txn", + []string{ + execMsg.Name(), + fmt.Sprintf("--%s=%s", flags.FlagGas, "250000"), + fmt.Sprintf("--%s=%s", flags.FlagFrom, grantee.String()), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), + fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + }, + 0, + false, + "", + }, + } + + for _, tc := range testCases { + tc := tc + s.Run(tc.name, func() { + cmd := cli.NewCmdExecAuthorization() + clientCtx := val.ClientCtx + + out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, tc.args) + if tc.expectErr { + s.Require().Error(err) + s.Require().Contains(err.Error(), tc.errMsg) + } else { + var response sdk.TxResponse + s.Require().NoError(err) + s.Require().NoError(clientCtx.Codec.UnmarshalJSON(out.Bytes(), &response), out.String()) + s.Require().Equal(tc.expectedCode, response.Code, out.String()) + } + }) + } +} diff --git a/x/authz/codec.go b/x/authz/codec.go new file mode 100644 index 0000000000..22976c3ef3 --- /dev/null +++ b/x/authz/codec.go @@ -0,0 +1,24 @@ +package authz + +import ( + types "github.com/line/lbm-sdk/codec/types" + sdk "github.com/line/lbm-sdk/types" + "github.com/line/lbm-sdk/types/msgservice" +) + +// RegisterInterfaces registers the interfaces types with the interface registry +func RegisterInterfaces(registry types.InterfaceRegistry) { + registry.RegisterImplementations((*sdk.Msg)(nil), + &MsgGrant{}, + &MsgRevoke{}, + &MsgExec{}, + ) + + registry.RegisterInterface( + "lbm.v1.Authorization", + (*Authorization)(nil), + &GenericAuthorization{}, + ) + + msgservice.RegisterMsgServiceDesc(registry, MsgServiceDesc()) +} diff --git a/x/authz/errors.go b/x/authz/errors.go new file mode 100644 index 0000000000..b6a8b304db --- /dev/null +++ b/x/authz/errors.go @@ -0,0 +1,10 @@ +package authz + +import ( + sdkerrors "github.com/line/lbm-sdk/types/errors" +) + +// x/authz module sentinel errors +var ( + ErrInvalidExpirationTime = sdkerrors.Register(ModuleName, 3, "expiration time of authorization should be more than current time") +) diff --git a/x/authz/event.pb.go b/x/authz/event.pb.go new file mode 100644 index 0000000000..47846880e1 --- /dev/null +++ b/x/authz/event.pb.go @@ -0,0 +1,699 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: lbm/authz/v1/event.proto + +package authz + +import ( + fmt "fmt" + proto "github.com/gogo/protobuf/proto" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +// EventGrant is emitted on Msg/Grant +type EventGrant struct { + // Msg type URL for which an autorization is granted + MsgTypeUrl string `protobuf:"bytes,2,opt,name=msg_type_url,json=msgTypeUrl,proto3" json:"msg_type_url,omitempty"` + // Granter account address + Granter string `protobuf:"bytes,3,opt,name=granter,proto3" json:"granter,omitempty"` + // Grantee account address + Grantee string `protobuf:"bytes,4,opt,name=grantee,proto3" json:"grantee,omitempty"` +} + +func (m *EventGrant) Reset() { *m = EventGrant{} } +func (m *EventGrant) String() string { return proto.CompactTextString(m) } +func (*EventGrant) ProtoMessage() {} +func (*EventGrant) Descriptor() ([]byte, []int) { + return fileDescriptor_f86a3cedcbc47b6d, []int{0} +} +func (m *EventGrant) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *EventGrant) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_EventGrant.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *EventGrant) XXX_Merge(src proto.Message) { + xxx_messageInfo_EventGrant.Merge(m, src) +} +func (m *EventGrant) XXX_Size() int { + return m.Size() +} +func (m *EventGrant) XXX_DiscardUnknown() { + xxx_messageInfo_EventGrant.DiscardUnknown(m) +} + +var xxx_messageInfo_EventGrant proto.InternalMessageInfo + +func (m *EventGrant) GetMsgTypeUrl() string { + if m != nil { + return m.MsgTypeUrl + } + return "" +} + +func (m *EventGrant) GetGranter() string { + if m != nil { + return m.Granter + } + return "" +} + +func (m *EventGrant) GetGrantee() string { + if m != nil { + return m.Grantee + } + return "" +} + +// EventRevoke is emitted on Msg/Revoke +type EventRevoke struct { + // Msg type URL for which an autorization is revoked + MsgTypeUrl string `protobuf:"bytes,2,opt,name=msg_type_url,json=msgTypeUrl,proto3" json:"msg_type_url,omitempty"` + // Granter account address + Granter string `protobuf:"bytes,3,opt,name=granter,proto3" json:"granter,omitempty"` + // Grantee account address + Grantee string `protobuf:"bytes,4,opt,name=grantee,proto3" json:"grantee,omitempty"` +} + +func (m *EventRevoke) Reset() { *m = EventRevoke{} } +func (m *EventRevoke) String() string { return proto.CompactTextString(m) } +func (*EventRevoke) ProtoMessage() {} +func (*EventRevoke) Descriptor() ([]byte, []int) { + return fileDescriptor_f86a3cedcbc47b6d, []int{1} +} +func (m *EventRevoke) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *EventRevoke) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_EventRevoke.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *EventRevoke) XXX_Merge(src proto.Message) { + xxx_messageInfo_EventRevoke.Merge(m, src) +} +func (m *EventRevoke) XXX_Size() int { + return m.Size() +} +func (m *EventRevoke) XXX_DiscardUnknown() { + xxx_messageInfo_EventRevoke.DiscardUnknown(m) +} + +var xxx_messageInfo_EventRevoke proto.InternalMessageInfo + +func (m *EventRevoke) GetMsgTypeUrl() string { + if m != nil { + return m.MsgTypeUrl + } + return "" +} + +func (m *EventRevoke) GetGranter() string { + if m != nil { + return m.Granter + } + return "" +} + +func (m *EventRevoke) GetGrantee() string { + if m != nil { + return m.Grantee + } + return "" +} + +func init() { + proto.RegisterType((*EventGrant)(nil), "lbm.authz.v1.EventGrant") + proto.RegisterType((*EventRevoke)(nil), "lbm.authz.v1.EventRevoke") +} + +func init() { proto.RegisterFile("lbm/authz/v1/event.proto", fileDescriptor_f86a3cedcbc47b6d) } + +var fileDescriptor_f86a3cedcbc47b6d = []byte{ + // 206 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0xc8, 0x49, 0xca, 0xd5, + 0x4f, 0x2c, 0x2d, 0xc9, 0xa8, 0xd2, 0x2f, 0x33, 0xd4, 0x4f, 0x2d, 0x4b, 0xcd, 0x2b, 0xd1, 0x2b, + 0x28, 0xca, 0x2f, 0xc9, 0x17, 0xe2, 0xc9, 0x49, 0xca, 0xd5, 0x03, 0xcb, 0xe8, 0x95, 0x19, 0x2a, + 0x25, 0x71, 0x71, 0xb9, 0x82, 0x24, 0xdd, 0x8b, 0x12, 0xf3, 0x4a, 0x84, 0x14, 0xb8, 0x78, 0x72, + 0x8b, 0xd3, 0xe3, 0x4b, 0x2a, 0x0b, 0x52, 0xe3, 0x4b, 0x8b, 0x72, 0x24, 0x98, 0x14, 0x18, 0x35, + 0x38, 0x83, 0xb8, 0x72, 0x8b, 0xd3, 0x43, 0x2a, 0x0b, 0x52, 0x43, 0x8b, 0x72, 0x84, 0x24, 0xb8, + 0xd8, 0xd3, 0x41, 0x4a, 0x53, 0x8b, 0x24, 0x98, 0xc1, 0x92, 0x30, 0x2e, 0x42, 0x26, 0x55, 0x82, + 0x05, 0x59, 0x26, 0x55, 0x29, 0x99, 0x8b, 0x1b, 0x6c, 0x47, 0x50, 0x6a, 0x59, 0x7e, 0x76, 0x2a, + 0x6d, 0x2c, 0x71, 0xb2, 0x3c, 0xf1, 0x48, 0x8e, 0xf1, 0xc2, 0x23, 0x39, 0xc6, 0x07, 0x8f, 0xe4, + 0x18, 0x27, 0x3c, 0x96, 0x63, 0xb8, 0xf0, 0x58, 0x8e, 0xe1, 0xc6, 0x63, 0x39, 0x86, 0x28, 0xf9, + 0xf4, 0xcc, 0x92, 0x8c, 0xd2, 0x24, 0xbd, 0xe4, 0xfc, 0x5c, 0xfd, 0x9c, 0xcc, 0xbc, 0x54, 0xfd, + 0x9c, 0xa4, 0x5c, 0xdd, 0xe2, 0x94, 0x6c, 0xfd, 0x0a, 0x48, 0x00, 0x25, 0xb1, 0x81, 0x03, 0xc6, + 0x18, 0x10, 0x00, 0x00, 0xff, 0xff, 0x98, 0xc7, 0x29, 0x05, 0x34, 0x01, 0x00, 0x00, +} + +func (m *EventGrant) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *EventGrant) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *EventGrant) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Grantee) > 0 { + i -= len(m.Grantee) + copy(dAtA[i:], m.Grantee) + i = encodeVarintEvent(dAtA, i, uint64(len(m.Grantee))) + i-- + dAtA[i] = 0x22 + } + if len(m.Granter) > 0 { + i -= len(m.Granter) + copy(dAtA[i:], m.Granter) + i = encodeVarintEvent(dAtA, i, uint64(len(m.Granter))) + i-- + dAtA[i] = 0x1a + } + if len(m.MsgTypeUrl) > 0 { + i -= len(m.MsgTypeUrl) + copy(dAtA[i:], m.MsgTypeUrl) + i = encodeVarintEvent(dAtA, i, uint64(len(m.MsgTypeUrl))) + i-- + dAtA[i] = 0x12 + } + return len(dAtA) - i, nil +} + +func (m *EventRevoke) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *EventRevoke) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *EventRevoke) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Grantee) > 0 { + i -= len(m.Grantee) + copy(dAtA[i:], m.Grantee) + i = encodeVarintEvent(dAtA, i, uint64(len(m.Grantee))) + i-- + dAtA[i] = 0x22 + } + if len(m.Granter) > 0 { + i -= len(m.Granter) + copy(dAtA[i:], m.Granter) + i = encodeVarintEvent(dAtA, i, uint64(len(m.Granter))) + i-- + dAtA[i] = 0x1a + } + if len(m.MsgTypeUrl) > 0 { + i -= len(m.MsgTypeUrl) + copy(dAtA[i:], m.MsgTypeUrl) + i = encodeVarintEvent(dAtA, i, uint64(len(m.MsgTypeUrl))) + i-- + dAtA[i] = 0x12 + } + return len(dAtA) - i, nil +} + +func encodeVarintEvent(dAtA []byte, offset int, v uint64) int { + offset -= sovEvent(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *EventGrant) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.MsgTypeUrl) + if l > 0 { + n += 1 + l + sovEvent(uint64(l)) + } + l = len(m.Granter) + if l > 0 { + n += 1 + l + sovEvent(uint64(l)) + } + l = len(m.Grantee) + if l > 0 { + n += 1 + l + sovEvent(uint64(l)) + } + return n +} + +func (m *EventRevoke) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.MsgTypeUrl) + if l > 0 { + n += 1 + l + sovEvent(uint64(l)) + } + l = len(m.Granter) + if l > 0 { + n += 1 + l + sovEvent(uint64(l)) + } + l = len(m.Grantee) + if l > 0 { + n += 1 + l + sovEvent(uint64(l)) + } + return n +} + +func sovEvent(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozEvent(x uint64) (n int) { + return sovEvent(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *EventGrant) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvent + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: EventGrant: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: EventGrant: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field MsgTypeUrl", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvent + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthEvent + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthEvent + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.MsgTypeUrl = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Granter", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvent + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthEvent + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthEvent + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Granter = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Grantee", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvent + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthEvent + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthEvent + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Grantee = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipEvent(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthEvent + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *EventRevoke) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvent + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: EventRevoke: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: EventRevoke: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field MsgTypeUrl", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvent + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthEvent + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthEvent + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.MsgTypeUrl = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Granter", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvent + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthEvent + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthEvent + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Granter = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Grantee", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvent + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthEvent + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthEvent + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Grantee = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipEvent(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthEvent + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipEvent(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowEvent + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowEvent + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowEvent + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthEvent + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupEvent + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthEvent + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthEvent = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowEvent = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupEvent = fmt.Errorf("proto: unexpected end of group") +) diff --git a/x/authz/expected_keepers.go b/x/authz/expected_keepers.go new file mode 100644 index 0000000000..34c8f28b13 --- /dev/null +++ b/x/authz/expected_keepers.go @@ -0,0 +1,17 @@ +package authz + +import ( + sdk "github.com/line/lbm-sdk/types" + authtypes "github.com/line/lbm-sdk/x/auth/types" +) + +// AccountKeeper defines the expected account keeper (noalias) +type AccountKeeper interface { + GetAccount(ctx sdk.Context, addr sdk.AccAddress) authtypes.AccountI +} + +// BankKeeper defines the expected interface needed to retrieve account balances. +type BankKeeper interface { + SpendableCoins(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins + IsSendEnabledCoins(ctx sdk.Context, coins ...sdk.Coin) error +} diff --git a/x/authz/generic_authorization.go b/x/authz/generic_authorization.go new file mode 100644 index 0000000000..ef7dec27f4 --- /dev/null +++ b/x/authz/generic_authorization.go @@ -0,0 +1,31 @@ +package authz + +import ( + sdk "github.com/line/lbm-sdk/types" +) + +var ( + _ Authorization = &GenericAuthorization{} +) + +// NewGenericAuthorization creates a new GenericAuthorization object. +func NewGenericAuthorization(msgTypeURL string) *GenericAuthorization { + return &GenericAuthorization{ + Msg: msgTypeURL, + } +} + +// MsgTypeURL implements Authorization.MsgTypeURL. +func (a GenericAuthorization) MsgTypeURL() string { + return a.Msg +} + +// Accept implements Authorization.Accept. +func (a GenericAuthorization) Accept(ctx sdk.Context, msg sdk.Msg) (AcceptResponse, error) { + return AcceptResponse{Accept: true}, nil +} + +// ValidateBasic implements Authorization.ValidateBasic. +func (a GenericAuthorization) ValidateBasic() error { + return nil +} diff --git a/x/authz/generic_authorization_test.go b/x/authz/generic_authorization_test.go new file mode 100644 index 0000000000..e456eedf9c --- /dev/null +++ b/x/authz/generic_authorization_test.go @@ -0,0 +1,17 @@ +package authz_test + +import ( + "testing" + + "github.com/stretchr/testify/require" + + "github.com/line/lbm-sdk/x/authz" + banktypes "github.com/line/lbm-sdk/x/bank/types" +) + +func TestGenericAuthorization(t *testing.T) { + t.Log("verify ValidateBasic returns nil for service msg") + a := authz.NewGenericAuthorization(banktypes.SendAuthorization{}.MsgTypeURL()) + require.NoError(t, a.ValidateBasic()) + require.Equal(t, banktypes.SendAuthorization{}.MsgTypeURL(), a.Msg) +} diff --git a/x/authz/genesis.go b/x/authz/genesis.go new file mode 100644 index 0000000000..f4bd8c544b --- /dev/null +++ b/x/authz/genesis.go @@ -0,0 +1,41 @@ +package authz + +import ( + cdctypes "github.com/line/lbm-sdk/codec/types" +) + +// NewGenesisState creates new GenesisState object +func NewGenesisState(entries []GrantAuthorization) *GenesisState { + return &GenesisState{ + Authorization: entries, + } +} + +// ValidateGenesis check the given genesis state has no integrity issues +func ValidateGenesis(data GenesisState) error { + return nil +} + +// DefaultGenesisState - Return a default genesis state +func DefaultGenesisState() *GenesisState { + return &GenesisState{} +} + +var _ cdctypes.UnpackInterfacesMessage = GenesisState{} + +// UnpackInterfaces implements UnpackInterfacesMessage.UnpackInterfaces +func (data GenesisState) UnpackInterfaces(unpacker cdctypes.AnyUnpacker) error { + for _, a := range data.Authorization { + err := a.UnpackInterfaces(unpacker) + if err != nil { + return err + } + } + return nil +} + +// UnpackInterfaces implements UnpackInterfacesMessage.UnpackInterfaces +func (msg GrantAuthorization) UnpackInterfaces(unpacker cdctypes.AnyUnpacker) error { + var a Authorization + return unpacker.UnpackAny(msg.Authorization, &a) +} diff --git a/x/authz/genesis.pb.go b/x/authz/genesis.pb.go new file mode 100644 index 0000000000..9d9b356cf3 --- /dev/null +++ b/x/authz/genesis.pb.go @@ -0,0 +1,678 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: lbm/authz/v1/genesis.proto + +package authz + +import ( + fmt "fmt" + _ "github.com/gogo/protobuf/gogoproto" + proto "github.com/gogo/protobuf/proto" + github_com_gogo_protobuf_types "github.com/gogo/protobuf/types" + types "github.com/line/lbm-sdk/codec/types" + _ "github.com/regen-network/cosmos-proto" + _ "google.golang.org/protobuf/types/known/timestamppb" + io "io" + math "math" + math_bits "math/bits" + time "time" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf +var _ = time.Kitchen + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +// GenesisState defines the authz module's genesis state. +type GenesisState struct { + Authorization []GrantAuthorization `protobuf:"bytes,1,rep,name=authorization,proto3" json:"authorization"` +} + +func (m *GenesisState) Reset() { *m = GenesisState{} } +func (m *GenesisState) String() string { return proto.CompactTextString(m) } +func (*GenesisState) ProtoMessage() {} +func (*GenesisState) Descriptor() ([]byte, []int) { + return fileDescriptor_888f2bd1f67add3d, []int{0} +} +func (m *GenesisState) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *GenesisState) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_GenesisState.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *GenesisState) XXX_Merge(src proto.Message) { + xxx_messageInfo_GenesisState.Merge(m, src) +} +func (m *GenesisState) XXX_Size() int { + return m.Size() +} +func (m *GenesisState) XXX_DiscardUnknown() { + xxx_messageInfo_GenesisState.DiscardUnknown(m) +} + +var xxx_messageInfo_GenesisState proto.InternalMessageInfo + +func (m *GenesisState) GetAuthorization() []GrantAuthorization { + if m != nil { + return m.Authorization + } + return nil +} + +// GrantAuthorization defines the GenesisState/GrantAuthorization type. +type GrantAuthorization struct { + Granter string `protobuf:"bytes,1,opt,name=granter,proto3" json:"granter,omitempty"` + Grantee string `protobuf:"bytes,2,opt,name=grantee,proto3" json:"grantee,omitempty"` + Authorization *types.Any `protobuf:"bytes,3,opt,name=authorization,proto3" json:"authorization,omitempty"` + Expiration time.Time `protobuf:"bytes,4,opt,name=expiration,proto3,stdtime" json:"expiration"` +} + +func (m *GrantAuthorization) Reset() { *m = GrantAuthorization{} } +func (m *GrantAuthorization) String() string { return proto.CompactTextString(m) } +func (*GrantAuthorization) ProtoMessage() {} +func (*GrantAuthorization) Descriptor() ([]byte, []int) { + return fileDescriptor_888f2bd1f67add3d, []int{1} +} +func (m *GrantAuthorization) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *GrantAuthorization) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_GrantAuthorization.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *GrantAuthorization) XXX_Merge(src proto.Message) { + xxx_messageInfo_GrantAuthorization.Merge(m, src) +} +func (m *GrantAuthorization) XXX_Size() int { + return m.Size() +} +func (m *GrantAuthorization) XXX_DiscardUnknown() { + xxx_messageInfo_GrantAuthorization.DiscardUnknown(m) +} + +var xxx_messageInfo_GrantAuthorization proto.InternalMessageInfo + +func (m *GrantAuthorization) GetGranter() string { + if m != nil { + return m.Granter + } + return "" +} + +func (m *GrantAuthorization) GetGrantee() string { + if m != nil { + return m.Grantee + } + return "" +} + +func (m *GrantAuthorization) GetAuthorization() *types.Any { + if m != nil { + return m.Authorization + } + return nil +} + +func (m *GrantAuthorization) GetExpiration() time.Time { + if m != nil { + return m.Expiration + } + return time.Time{} +} + +func init() { + proto.RegisterType((*GenesisState)(nil), "lbm.authz.v1.GenesisState") + proto.RegisterType((*GrantAuthorization)(nil), "lbm.authz.v1.GrantAuthorization") +} + +func init() { proto.RegisterFile("lbm/authz/v1/genesis.proto", fileDescriptor_888f2bd1f67add3d) } + +var fileDescriptor_888f2bd1f67add3d = []byte{ + // 342 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x64, 0x91, 0xbd, 0x6e, 0xc2, 0x30, + 0x10, 0xc7, 0xe3, 0x82, 0xfa, 0x61, 0x60, 0x68, 0x44, 0xa5, 0x34, 0x43, 0x12, 0x31, 0xb1, 0x60, + 0x0b, 0x3a, 0x75, 0x24, 0xaa, 0xc4, 0xd2, 0x2e, 0xb4, 0x53, 0x55, 0xa9, 0x4a, 0xa8, 0x6b, 0xac, + 0xc6, 0x31, 0x8a, 0x0d, 0x02, 0x9e, 0x82, 0x87, 0xe9, 0x43, 0xa0, 0x4e, 0x8c, 0x5d, 0xfa, 0x21, + 0x78, 0x91, 0x2a, 0x31, 0x51, 0x03, 0x6c, 0xbe, 0xfb, 0xfd, 0xef, 0xee, 0xef, 0x3b, 0x68, 0x47, + 0x21, 0xc7, 0xc1, 0x58, 0x0d, 0xe7, 0x78, 0xd2, 0xc6, 0x94, 0xc4, 0x44, 0x32, 0x89, 0x46, 0x89, + 0x50, 0xc2, 0xac, 0x46, 0x21, 0x47, 0x19, 0x43, 0x93, 0xb6, 0xed, 0x52, 0x21, 0x68, 0x44, 0x70, + 0xc6, 0xc2, 0xf1, 0x2b, 0x56, 0x8c, 0x13, 0xa9, 0x02, 0x3e, 0xd2, 0x72, 0xfb, 0x72, 0x5f, 0x10, + 0xc4, 0xb3, 0x2d, 0xaa, 0x53, 0x41, 0x45, 0xf6, 0xc4, 0xe9, 0x2b, 0x2f, 0x18, 0x08, 0xc9, 0x85, + 0x7c, 0xd6, 0x40, 0x07, 0x5b, 0x74, 0xb1, 0x63, 0x4b, 0x4d, 0x75, 0xba, 0xf1, 0x04, 0xab, 0x3d, + 0x6d, 0xf1, 0x5e, 0x05, 0x8a, 0x98, 0xb7, 0xb0, 0x96, 0x8a, 0x44, 0xc2, 0xe6, 0x81, 0x62, 0x22, + 0xb6, 0x80, 0x57, 0x6a, 0x56, 0x3a, 0x1e, 0x2a, 0x3a, 0x47, 0xbd, 0x24, 0x88, 0x55, 0xb7, 0xa8, + 0xf3, 0xcb, 0xcb, 0x6f, 0xd7, 0xe8, 0xef, 0x16, 0x37, 0xbe, 0x00, 0x34, 0x0f, 0xb5, 0xa6, 0x05, + 0x4f, 0x68, 0x9a, 0x25, 0x89, 0x05, 0x3c, 0xd0, 0x3c, 0xeb, 0xe7, 0xe1, 0x3f, 0x21, 0xd6, 0x51, + 0x91, 0x10, 0xf3, 0x6e, 0xdf, 0x58, 0xc9, 0x03, 0xcd, 0x4a, 0xa7, 0x8e, 0xf4, 0x8e, 0x50, 0xbe, + 0x23, 0xd4, 0x8d, 0x67, 0xfe, 0xf9, 0xc7, 0x7b, 0xab, 0xb6, 0x33, 0x73, 0xcf, 0x99, 0x79, 0x03, + 0x21, 0x99, 0x8e, 0x58, 0xa2, 0x7b, 0x95, 0xb3, 0x5e, 0xf6, 0x41, 0xaf, 0x87, 0xfc, 0x20, 0xfe, + 0x69, 0xfa, 0xbd, 0xc5, 0x8f, 0x0b, 0xfa, 0x85, 0x3a, 0xff, 0x7a, 0xb9, 0x76, 0xc0, 0x6a, 0xed, + 0x80, 0xdf, 0xb5, 0x03, 0x16, 0x1b, 0xc7, 0x58, 0x6d, 0x1c, 0xe3, 0x73, 0xe3, 0x18, 0x8f, 0x2e, + 0x65, 0x6a, 0x38, 0x0e, 0xd1, 0x40, 0x70, 0x1c, 0xb1, 0x98, 0xe0, 0x28, 0xe4, 0x2d, 0xf9, 0xf2, + 0x86, 0xa7, 0xfa, 0x08, 0xe1, 0x71, 0x36, 0xe4, 0xea, 0x2f, 0x00, 0x00, 0xff, 0xff, 0xa9, 0xc0, + 0xca, 0x4f, 0x2f, 0x02, 0x00, 0x00, +} + +func (m *GenesisState) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *GenesisState) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *GenesisState) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Authorization) > 0 { + for iNdEx := len(m.Authorization) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Authorization[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func (m *GrantAuthorization) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *GrantAuthorization) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *GrantAuthorization) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + n1, err1 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.Expiration, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.Expiration):]) + if err1 != nil { + return 0, err1 + } + i -= n1 + i = encodeVarintGenesis(dAtA, i, uint64(n1)) + i-- + dAtA[i] = 0x22 + if m.Authorization != nil { + { + size, err := m.Authorization.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + } + if len(m.Grantee) > 0 { + i -= len(m.Grantee) + copy(dAtA[i:], m.Grantee) + i = encodeVarintGenesis(dAtA, i, uint64(len(m.Grantee))) + i-- + dAtA[i] = 0x12 + } + if len(m.Granter) > 0 { + i -= len(m.Granter) + copy(dAtA[i:], m.Granter) + i = encodeVarintGenesis(dAtA, i, uint64(len(m.Granter))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func encodeVarintGenesis(dAtA []byte, offset int, v uint64) int { + offset -= sovGenesis(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *GenesisState) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.Authorization) > 0 { + for _, e := range m.Authorization { + l = e.Size() + n += 1 + l + sovGenesis(uint64(l)) + } + } + return n +} + +func (m *GrantAuthorization) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Granter) + if l > 0 { + n += 1 + l + sovGenesis(uint64(l)) + } + l = len(m.Grantee) + if l > 0 { + n += 1 + l + sovGenesis(uint64(l)) + } + if m.Authorization != nil { + l = m.Authorization.Size() + n += 1 + l + sovGenesis(uint64(l)) + } + l = github_com_gogo_protobuf_types.SizeOfStdTime(m.Expiration) + n += 1 + l + sovGenesis(uint64(l)) + return n +} + +func sovGenesis(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozGenesis(x uint64) (n int) { + return sovGenesis(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *GenesisState) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: GenesisState: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: GenesisState: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Authorization", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Authorization = append(m.Authorization, GrantAuthorization{}) + if err := m.Authorization[len(m.Authorization)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipGenesis(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGenesis + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *GrantAuthorization) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: GrantAuthorization: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: GrantAuthorization: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Granter", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Granter = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Grantee", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Grantee = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Authorization", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Authorization == nil { + m.Authorization = &types.Any{} + } + if err := m.Authorization.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Expiration", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := github_com_gogo_protobuf_types.StdTimeUnmarshal(&m.Expiration, dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipGenesis(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGenesis + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipGenesis(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowGenesis + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowGenesis + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowGenesis + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthGenesis + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupGenesis + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthGenesis + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthGenesis = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowGenesis = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupGenesis = fmt.Errorf("proto: unexpected end of group") +) diff --git a/x/authz/keeper/genesis_test.go b/x/authz/keeper/genesis_test.go new file mode 100644 index 0000000000..987150fc97 --- /dev/null +++ b/x/authz/keeper/genesis_test.go @@ -0,0 +1,59 @@ +package keeper_test + +import ( + "testing" + "time" + + "github.com/stretchr/testify/suite" + + ocproto "github.com/line/ostracon/proto/ostracon/types" + + "github.com/line/lbm-sdk/crypto/keys/secp256k1" + "github.com/line/lbm-sdk/simapp" + sdk "github.com/line/lbm-sdk/types" + "github.com/line/lbm-sdk/x/authz/keeper" + bank "github.com/line/lbm-sdk/x/bank/types" +) + +type GenesisTestSuite struct { + suite.Suite + + ctx sdk.Context + keeper keeper.Keeper +} + +func (suite *GenesisTestSuite) SetupTest() { + checkTx := false + app := simapp.Setup(checkTx) + + suite.ctx = app.BaseApp.NewContext(checkTx, ocproto.Header{Height: 1}) + suite.keeper = app.AuthzKeeper +} + +var ( + granteePub = secp256k1.GenPrivKey().PubKey() + granterPub = secp256k1.GenPrivKey().PubKey() + granteeAddr = sdk.BytesToAccAddress(granteePub.Address().Bytes()) + granterAddr = sdk.BytesToAccAddress(granterPub.Address().Bytes()) +) + +func (suite *GenesisTestSuite) TestImportExportGenesis() { + coins := sdk.NewCoins(sdk.NewCoin("foo", sdk.NewInt(1_000))) + + now := suite.ctx.BlockHeader().Time + grant := &bank.SendAuthorization{SpendLimit: coins} + err := suite.keeper.SaveGrant(suite.ctx, granteeAddr, granterAddr, grant, now.Add(time.Hour)) + suite.Require().NoError(err) + genesis := suite.keeper.ExportGenesis(suite.ctx) + + // Clear keeper + suite.keeper.DeleteGrant(suite.ctx, granteeAddr, granterAddr, grant.MsgTypeURL()) + + suite.keeper.InitGenesis(suite.ctx, genesis) + newGenesis := suite.keeper.ExportGenesis(suite.ctx) + suite.Require().Equal(genesis, newGenesis) +} + +func TestGenesisTestSuite(t *testing.T) { + suite.Run(t, new(GenesisTestSuite)) +} diff --git a/x/authz/keeper/grpc_query.go b/x/authz/keeper/grpc_query.go new file mode 100644 index 0000000000..4e65444c09 --- /dev/null +++ b/x/authz/keeper/grpc_query.go @@ -0,0 +1,99 @@ +package keeper + +import ( + "context" + + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + + proto "github.com/gogo/protobuf/proto" + + "github.com/line/lbm-sdk/codec" + codectypes "github.com/line/lbm-sdk/codec/types" + "github.com/line/lbm-sdk/store/prefix" + sdk "github.com/line/lbm-sdk/types" + "github.com/line/lbm-sdk/types/query" + "github.com/line/lbm-sdk/x/authz" +) + +var _ authz.QueryServer = Keeper{} + +// Authorizations implements the Query/Grants gRPC method. +func (k Keeper) Grants(c context.Context, req *authz.QueryGrantsRequest) (*authz.QueryGrantsResponse, error) { + if req == nil { + return nil, status.Errorf(codes.InvalidArgument, "empty request") + } + + err := sdk.ValidateAccAddress(req.Granter) + if err != nil { + return nil, err + } + granter := sdk.AccAddress(req.Granter) + + err = sdk.ValidateAccAddress(req.Grantee) + if err != nil { + return nil, err + } + grantee := sdk.AccAddress(req.Grantee) + + ctx := sdk.UnwrapSDKContext(c) + store := ctx.KVStore(k.storeKey) + key := grantStoreKey(grantee, granter, "") + authStore := prefix.NewStore(store, key) + + if req.MsgTypeUrl != "" { + authorization, expiration := k.GetCleanAuthorization(ctx, grantee, granter, req.MsgTypeUrl) + if authorization == nil { + return nil, status.Errorf(codes.NotFound, "no authorization found for %s type", req.MsgTypeUrl) + } + authorizationAny, err := codectypes.NewAnyWithValue(authorization) + if err != nil { + return nil, status.Errorf(codes.Internal, err.Error()) + } + return &authz.QueryGrantsResponse{ + Grants: []*authz.Grant{{ + Authorization: authorizationAny, + Expiration: expiration, + }}, + }, nil + } + + var authorizations []*authz.Grant + pageRes, err := query.FilteredPaginate(authStore, req.Pagination, func(key []byte, value []byte, accumulate bool) (bool, error) { + auth, err := unmarshalAuthorization(k.cdc, value) + if err != nil { + return false, err + } + auth1 := auth.GetAuthorization() + if accumulate { + msg, ok := auth1.(proto.Message) + if !ok { + return false, status.Errorf(codes.Internal, "can't protomarshal %T", msg) + } + + authorizationAny, err := codectypes.NewAnyWithValue(msg) + if err != nil { + return false, status.Errorf(codes.Internal, err.Error()) + } + authorizations = append(authorizations, &authz.Grant{ + Authorization: authorizationAny, + Expiration: auth.Expiration, + }) + } + return true, nil + }) + if err != nil { + return nil, err + } + + return &authz.QueryGrantsResponse{ + Grants: authorizations, + Pagination: pageRes, + }, nil +} + +// unmarshal an authorization from a store value +func unmarshalAuthorization(cdc codec.BinaryCodec, value []byte) (v authz.Grant, err error) { + err = cdc.Unmarshal(value, &v) + return v, err +} diff --git a/x/authz/keeper/grpc_query_test.go b/x/authz/keeper/grpc_query_test.go new file mode 100644 index 0000000000..a2d867b691 --- /dev/null +++ b/x/authz/keeper/grpc_query_test.go @@ -0,0 +1,164 @@ +package keeper_test + +import ( + gocontext "context" + "fmt" + "time" + + "github.com/stretchr/testify/require" + + sdk "github.com/line/lbm-sdk/types" + "github.com/line/lbm-sdk/x/authz" + banktypes "github.com/line/lbm-sdk/x/bank/types" +) + +func (suite *TestSuite) TestGRPCQueryAuthorization() { + app, ctx, queryClient, addrs := suite.app, suite.ctx, suite.queryClient, suite.addrs + var ( + req *authz.QueryGrantsRequest + expAuthorization authz.Authorization + ) + testCases := []struct { + msg string + malleate func(require *require.Assertions) + expError string + postTest func(require *require.Assertions, res *authz.QueryGrantsResponse) + }{ + { + "fail invalid granter addr", + func(require *require.Assertions) { + req = &authz.QueryGrantsRequest{} + }, + "empty address string is not allowed", + func(require *require.Assertions, res *authz.QueryGrantsResponse) {}, + }, + { + "fail invalid grantee addr", + func(require *require.Assertions) { + req = &authz.QueryGrantsRequest{ + Granter: addrs[0].String(), + } + }, + "empty address string is not allowed", + func(require *require.Assertions, res *authz.QueryGrantsResponse) {}, + }, + { + "fail invalid msg-type", + func(require *require.Assertions) { + req = &authz.QueryGrantsRequest{ + Granter: addrs[0].String(), + Grantee: addrs[1].String(), + MsgTypeUrl: "unknown", + } + }, + "no authorization found for unknown type", + func(require *require.Assertions, res *authz.QueryGrantsResponse) {}, + }, + { + "Success", + func(require *require.Assertions) { + now := ctx.BlockHeader().Time + newCoins := sdk.NewCoins(sdk.NewInt64Coin("steak", 100)) + expAuthorization = &banktypes.SendAuthorization{SpendLimit: newCoins} + err := app.AuthzKeeper.SaveGrant(ctx, addrs[0], addrs[1], expAuthorization, now.Add(time.Hour)) + require.NoError(err) + req = &authz.QueryGrantsRequest{ + Granter: addrs[1].String(), + Grantee: addrs[0].String(), + MsgTypeUrl: expAuthorization.MsgTypeURL(), + } + }, + "", + func(require *require.Assertions, res *authz.QueryGrantsResponse) { + var auth authz.Authorization + require.Equal(1, len(res.Grants)) + err := suite.app.InterfaceRegistry().UnpackAny(res.Grants[0].Authorization, &auth) + require.NoError(err) + require.NotNil(auth) + require.Equal(auth.String(), expAuthorization.String()) + }, + }, + } + for _, tc := range testCases { + suite.Run(fmt.Sprintf("Case %s", tc.msg), func() { + require := suite.Require() + tc.malleate(require) + result, err := queryClient.Grants(gocontext.Background(), req) + if tc.expError == "" { + require.NoError(err) + } else { + require.Error(err) + require.Contains(err.Error(), tc.expError) + } + tc.postTest(require, result) + }) + } +} + +func (suite *TestSuite) TestGRPCQueryAuthorizations() { + app, ctx, queryClient, addrs := suite.app, suite.ctx, suite.queryClient, suite.addrs + var ( + req *authz.QueryGrantsRequest + expAuthorization authz.Authorization + ) + testCases := []struct { + msg string + malleate func() + expPass bool + postTest func(res *authz.QueryGrantsResponse) + }{ + { + "fail invalid granter addr", + func() { + req = &authz.QueryGrantsRequest{} + }, + false, + func(res *authz.QueryGrantsResponse) {}, + }, + { + "fail invalid grantee addr", + func() { + req = &authz.QueryGrantsRequest{ + Granter: addrs[0].String(), + } + }, + false, + func(res *authz.QueryGrantsResponse) {}, + }, + { + "Success", + func() { + now := ctx.BlockHeader().Time + newCoins := sdk.NewCoins(sdk.NewInt64Coin("steak", 100)) + expAuthorization = &banktypes.SendAuthorization{SpendLimit: newCoins} + err := app.AuthzKeeper.SaveGrant(ctx, addrs[0], addrs[1], expAuthorization, now.Add(time.Hour)) + suite.Require().NoError(err) + req = &authz.QueryGrantsRequest{ + Granter: addrs[1].String(), + Grantee: addrs[0].String(), + } + }, + true, + func(res *authz.QueryGrantsResponse) { + var auth authz.Authorization + suite.Require().Equal(1, len(res.Grants)) + err := suite.app.InterfaceRegistry().UnpackAny(res.Grants[0].Authorization, &auth) + suite.Require().NoError(err) + suite.Require().NotNil(auth) + suite.Require().Equal(auth.String(), expAuthorization.String()) + }, + }, + } + for _, testCase := range testCases { + suite.Run(fmt.Sprintf("Case %s", testCase.msg), func() { + testCase.malleate() + result, err := queryClient.Grants(gocontext.Background(), req) + if testCase.expPass { + suite.Require().NoError(err) + } else { + suite.Require().Error(err) + } + testCase.postTest(result) + }) + } +} diff --git a/x/authz/keeper/keeper.go b/x/authz/keeper/keeper.go new file mode 100644 index 0000000000..db9b37cc69 --- /dev/null +++ b/x/authz/keeper/keeper.go @@ -0,0 +1,257 @@ +package keeper + +import ( + "fmt" + "time" + + "github.com/gogo/protobuf/proto" + + "github.com/line/ostracon/libs/log" + + "github.com/line/lbm-sdk/baseapp" + "github.com/line/lbm-sdk/codec" + codectypes "github.com/line/lbm-sdk/codec/types" + sdk "github.com/line/lbm-sdk/types" + sdkerrors "github.com/line/lbm-sdk/types/errors" + "github.com/line/lbm-sdk/x/authz" +) + +type Keeper struct { + storeKey sdk.StoreKey + cdc codec.BinaryCodec + router *baseapp.MsgServiceRouter +} + +// NewKeeper constructs a message authorization Keeper +func NewKeeper(storeKey sdk.StoreKey, cdc codec.BinaryCodec, router *baseapp.MsgServiceRouter) Keeper { + return Keeper{ + storeKey: storeKey, + cdc: cdc, + router: router, + } +} + +// Logger returns a module-specific logger. +func (k Keeper) Logger(ctx sdk.Context) log.Logger { + return ctx.Logger().With("module", fmt.Sprintf("x/%s", authz.ModuleName)) +} + +// getGrant returns grant stored at skey. +func (k Keeper) getGrant(ctx sdk.Context, skey []byte) (grant authz.Grant, found bool) { + store := ctx.KVStore(k.storeKey) + bz := store.Get(skey) + if bz == nil { + return grant, false + } + k.cdc.MustUnmarshal(bz, &grant) + return grant, true +} + +func (k Keeper) update(ctx sdk.Context, grantee sdk.AccAddress, granter sdk.AccAddress, updated authz.Authorization) error { + skey := grantStoreKey(grantee, granter, updated.MsgTypeURL()) + grant, found := k.getGrant(ctx, skey) + if !found { + return sdkerrors.ErrNotFound.Wrap("authorization not found") + } + + msg, ok := updated.(proto.Message) + if !ok { + sdkerrors.ErrPackAny.Wrapf("cannot proto marshal %T", updated) + } + + any, err := codectypes.NewAnyWithValue(msg) + if err != nil { + return err + } + + grant.Authorization = any + store := ctx.KVStore(k.storeKey) + store.Set(skey, k.cdc.MustMarshal(&grant)) + return nil +} + +// DispatchActions attempts to execute the provided messages via authorization +// grants from the message signer to the grantee. +func (k Keeper) DispatchActions(ctx sdk.Context, grantee sdk.AccAddress, msgs []sdk.Msg) ([][]byte, error) { + var results = make([][]byte, len(msgs)) + for i, msg := range msgs { + signers := msg.GetSigners() + if len(signers) != 1 { + return nil, sdkerrors.ErrInvalidRequest.Wrap("authorization can be given to msg with only one signer") + } + granter := signers[0] + // if granter != grantee then check authorization.Accept, otherwise we implicitly accept. + if !granter.Equals(grantee) { + authorization, _ := k.GetCleanAuthorization(ctx, grantee, granter, sdk.MsgTypeURL(msg)) + if authorization == nil { + return nil, sdkerrors.ErrUnauthorized.Wrap("authorization not found") + } + resp, err := authorization.Accept(ctx, msg) + if err != nil { + return nil, err + } + if resp.Delete { + err = k.DeleteGrant(ctx, grantee, granter, sdk.MsgTypeURL(msg)) + } else if resp.Updated != nil { + err = k.update(ctx, grantee, granter, resp.Updated) + } + if err != nil { + return nil, err + } + if !resp.Accept { + return nil, sdkerrors.ErrUnauthorized + } + } + + handler := k.router.Handler(msg) + if handler == nil { + return nil, sdkerrors.ErrUnknownRequest.Wrapf("unrecognized message route: %s", sdk.MsgTypeURL(msg)) + } + + msgResp, err := handler(ctx, msg) + if err != nil { + return nil, sdkerrors.Wrapf(err, "failed to execute message; message %v", msg) + } + results[i] = msgResp.Data + + // emit the events from the dispatched actions + events := msgResp.Events + sdkEvents := make([]sdk.Event, 0, len(events)) + for i := 0; i < len(events); i++ { + sdkEvents = append(sdkEvents, sdk.Event(events[i])) + } + ctx.EventManager().EmitEvents(sdkEvents) + } + + return results, nil +} + +// SaveGrant method grants the provided authorization to the grantee on the granter's account +// with the provided expiration time. If there is an existing authorization grant for the +// same `sdk.Msg` type, this grant overwrites that. +func (k Keeper) SaveGrant(ctx sdk.Context, grantee, granter sdk.AccAddress, authorization authz.Authorization, expiration time.Time) error { + store := ctx.KVStore(k.storeKey) + + grant, err := authz.NewGrant(authorization, expiration) + if err != nil { + return err + } + + bz := k.cdc.MustMarshal(&grant) + skey := grantStoreKey(grantee, granter, authorization.MsgTypeURL()) + store.Set(skey, bz) + return ctx.EventManager().EmitTypedEvent(&authz.EventGrant{ + MsgTypeUrl: authorization.MsgTypeURL(), + Granter: granter.String(), + Grantee: grantee.String(), + }) +} + +// DeleteGrant revokes any authorization for the provided message type granted to the grantee +// by the granter. +func (k Keeper) DeleteGrant(ctx sdk.Context, grantee sdk.AccAddress, granter sdk.AccAddress, msgType string) error { + store := ctx.KVStore(k.storeKey) + skey := grantStoreKey(grantee, granter, msgType) + _, found := k.getGrant(ctx, skey) + if !found { + return sdkerrors.ErrNotFound.Wrap("authorization not found") + } + store.Delete(skey) + return ctx.EventManager().EmitTypedEvent(&authz.EventRevoke{ + MsgTypeUrl: msgType, + Granter: granter.String(), + Grantee: grantee.String(), + }) +} + +// GetAuthorizations Returns list of `Authorizations` granted to the grantee by the granter. +func (k Keeper) GetAuthorizations(ctx sdk.Context, grantee sdk.AccAddress, granter sdk.AccAddress) (authorizations []authz.Authorization) { + store := ctx.KVStore(k.storeKey) + key := grantStoreKey(grantee, granter, "") + iter := sdk.KVStorePrefixIterator(store, key) + defer iter.Close() + var authorization authz.Grant + for ; iter.Valid(); iter.Next() { + k.cdc.MustUnmarshal(iter.Value(), &authorization) + authorizations = append(authorizations, authorization.GetAuthorization()) + } + return authorizations +} + +// GetCleanAuthorization returns an `Authorization` and it's expiration time for +// (grantee, granter, message name) grant. If there is no grant `nil` is returned. +// If the grant is expired, the grant is revoked, removed from the storage, and `nil` is returned. +func (k Keeper) GetCleanAuthorization(ctx sdk.Context, grantee sdk.AccAddress, granter sdk.AccAddress, msgType string) (cap authz.Authorization, expiration time.Time) { + grant, found := k.getGrant(ctx, grantStoreKey(grantee, granter, msgType)) + if !found { + return nil, time.Time{} + } + if grant.Expiration.Before(ctx.BlockHeader().Time) { + k.DeleteGrant(ctx, grantee, granter, msgType) + return nil, time.Time{} + } + + return grant.GetAuthorization(), grant.Expiration +} + +// IterateGrants iterates over all authorization grants +// This function should be used with caution because it can involve significant IO operations. +// It should not be used in query or msg services without charging additional gas. +func (k Keeper) IterateGrants(ctx sdk.Context, + handler func(granterAddr sdk.AccAddress, granteeAddr sdk.AccAddress, grant authz.Grant) bool) { + store := ctx.KVStore(k.storeKey) + iter := sdk.KVStorePrefixIterator(store, GrantKey) + defer iter.Close() + for ; iter.Valid(); iter.Next() { + var grant authz.Grant + granterAddr, granteeAddr := addressesFromGrantStoreKey(iter.Key()) + k.cdc.MustUnmarshal(iter.Value(), &grant) + if handler(granterAddr, granteeAddr, grant) { + break + } + } +} + +// ExportGenesis returns a GenesisState for a given context. +func (k Keeper) ExportGenesis(ctx sdk.Context) *authz.GenesisState { + var entries []authz.GrantAuthorization + k.IterateGrants(ctx, func(granter, grantee sdk.AccAddress, grant authz.Grant) bool { + exp := grant.Expiration + entries = append(entries, authz.GrantAuthorization{ + Granter: granter.String(), + Grantee: grantee.String(), + Expiration: exp, + Authorization: grant.Authorization, + }) + return false + }) + + return authz.NewGenesisState(entries) +} + +// InitGenesis new authz genesis +func (k Keeper) InitGenesis(ctx sdk.Context, data *authz.GenesisState) { + for _, entry := range data.Authorization { + err := sdk.ValidateAccAddress(entry.Grantee) + if err != nil { + panic(err) + } + grantee := sdk.AccAddress(entry.Grantee) + + err = sdk.ValidateAccAddress(entry.Granter) + if err != nil { + panic(err) + } + granter := sdk.AccAddress(entry.Granter) + + a, ok := entry.Authorization.GetCachedValue().(authz.Authorization) + if !ok { + panic("expected authorization") + } + + err = k.SaveGrant(ctx, grantee, granter, a, entry.Expiration) + if err != nil { + panic(err) + } + } +} diff --git a/x/authz/keeper/keeper_test.go b/x/authz/keeper/keeper_test.go new file mode 100644 index 0000000000..29ff25e656 --- /dev/null +++ b/x/authz/keeper/keeper_test.go @@ -0,0 +1,253 @@ +package keeper_test + +import ( + "testing" + "time" + + "github.com/stretchr/testify/suite" + + ocproto "github.com/line/ostracon/proto/ostracon/types" + octime "github.com/line/ostracon/types/time" + + "github.com/line/lbm-sdk/baseapp" + "github.com/line/lbm-sdk/simapp" + sdk "github.com/line/lbm-sdk/types" + "github.com/line/lbm-sdk/x/authz" + banktypes "github.com/line/lbm-sdk/x/bank/types" +) + +var bankSendAuthMsgType = banktypes.SendAuthorization{}.MsgTypeURL() + +type TestSuite struct { + suite.Suite + + app *simapp.SimApp + ctx sdk.Context + addrs []sdk.AccAddress + queryClient authz.QueryClient +} + +func (s *TestSuite) SetupTest() { + app := simapp.Setup(false) + ctx := app.BaseApp.NewContext(false, ocproto.Header{}) + now := octime.Now() + ctx = ctx.WithBlockHeader(ocproto.Header{Time: now}) + queryHelper := baseapp.NewQueryServerTestHelper(ctx, app.InterfaceRegistry()) + authz.RegisterQueryServer(queryHelper, app.AuthzKeeper) + queryClient := authz.NewQueryClient(queryHelper) + s.queryClient = queryClient + + s.app = app + s.ctx = ctx + s.queryClient = queryClient + s.addrs = simapp.AddTestAddrsIncremental(app, ctx, 3, sdk.NewInt(30000000)) +} + +func (s *TestSuite) TestKeeper() { + app, ctx, addrs := s.app, s.ctx, s.addrs + + granterAddr := addrs[0] + granteeAddr := addrs[1] + recipientAddr := addrs[2] + + s.T().Log("verify that no authorization returns nil") + authorization, expiration := app.AuthzKeeper.GetCleanAuthorization(ctx, granteeAddr, granterAddr, bankSendAuthMsgType) + s.Require().Nil(authorization) + s.Require().Equal(expiration, time.Time{}) + now := s.ctx.BlockHeader().Time + s.Require().NotNil(now) + + newCoins := sdk.NewCoins(sdk.NewInt64Coin("steak", 100)) + s.T().Log("verify if expired authorization is rejected") + x := &banktypes.SendAuthorization{SpendLimit: newCoins} + err := app.AuthzKeeper.SaveGrant(ctx, granterAddr, granteeAddr, x, now.Add(-1*time.Hour)) + s.Require().NoError(err) + authorization, _ = app.AuthzKeeper.GetCleanAuthorization(ctx, granteeAddr, granterAddr, bankSendAuthMsgType) + s.Require().Nil(authorization) + + s.T().Log("verify if authorization is accepted") + x = &banktypes.SendAuthorization{SpendLimit: newCoins} + err = app.AuthzKeeper.SaveGrant(ctx, granteeAddr, granterAddr, x, now.Add(time.Hour)) + s.Require().NoError(err) + authorization, _ = app.AuthzKeeper.GetCleanAuthorization(ctx, granteeAddr, granterAddr, bankSendAuthMsgType) + s.Require().NotNil(authorization) + s.Require().Equal(authorization.MsgTypeURL(), bankSendAuthMsgType) + + s.T().Log("verify fetching authorization with wrong msg type fails") + authorization, _ = app.AuthzKeeper.GetCleanAuthorization(ctx, granteeAddr, granterAddr, sdk.MsgTypeURL(&banktypes.MsgMultiSend{})) + s.Require().Nil(authorization) + + s.T().Log("verify fetching authorization with wrong grantee fails") + authorization, _ = app.AuthzKeeper.GetCleanAuthorization(ctx, recipientAddr, granterAddr, bankSendAuthMsgType) + s.Require().Nil(authorization) + + s.T().Log("verify revoke fails with wrong information") + err = app.AuthzKeeper.DeleteGrant(ctx, recipientAddr, granterAddr, bankSendAuthMsgType) + s.Require().Error(err) + authorization, _ = app.AuthzKeeper.GetCleanAuthorization(ctx, recipientAddr, granterAddr, bankSendAuthMsgType) + s.Require().Nil(authorization) + + s.T().Log("verify revoke executes with correct information") + err = app.AuthzKeeper.DeleteGrant(ctx, granteeAddr, granterAddr, bankSendAuthMsgType) + s.Require().NoError(err) + authorization, _ = app.AuthzKeeper.GetCleanAuthorization(ctx, granteeAddr, granterAddr, bankSendAuthMsgType) + s.Require().Nil(authorization) + +} + +func (s *TestSuite) TestKeeperIter() { + app, ctx, addrs := s.app, s.ctx, s.addrs + + granterAddr := addrs[0] + granteeAddr := addrs[1] + + s.T().Log("verify that no authorization returns nil") + authorization, expiration := app.AuthzKeeper.GetCleanAuthorization(ctx, granteeAddr, granterAddr, "Abcd") + s.Require().Nil(authorization) + s.Require().Equal(time.Time{}, expiration) + now := s.ctx.BlockHeader().Time + s.Require().NotNil(now) + + newCoins := sdk.NewCoins(sdk.NewInt64Coin("steak", 100)) + s.T().Log("verify if expired authorization is rejected") + x := &banktypes.SendAuthorization{SpendLimit: newCoins} + err := app.AuthzKeeper.SaveGrant(ctx, granteeAddr, granterAddr, x, now.Add(-1*time.Hour)) + s.Require().NoError(err) + authorization, _ = app.AuthzKeeper.GetCleanAuthorization(ctx, granteeAddr, granterAddr, "abcd") + s.Require().Nil(authorization) + + app.AuthzKeeper.IterateGrants(ctx, func(granter, grantee sdk.AccAddress, grant authz.Grant) bool { + s.Require().Equal(granter, granterAddr) + s.Require().Equal(grantee, granteeAddr) + return true + }) + +} + +func (s *TestSuite) TestKeeperFees() { + app, addrs := s.app, s.addrs + + granterAddr := addrs[0] + granteeAddr := addrs[1] + recipientAddr := addrs[2] + s.Require().NoError(simapp.FundAccount(app, s.ctx, granterAddr, sdk.NewCoins(sdk.NewInt64Coin("steak", 10000)))) + now := s.ctx.BlockHeader().Time + s.Require().NotNil(now) + + smallCoin := sdk.NewCoins(sdk.NewInt64Coin("steak", 20)) + someCoin := sdk.NewCoins(sdk.NewInt64Coin("steak", 123)) + + msgs := authz.NewMsgExec(granteeAddr, []sdk.Msg{ + &banktypes.MsgSend{ + Amount: sdk.NewCoins(sdk.NewInt64Coin("steak", 2)), + FromAddress: granterAddr.String(), + ToAddress: recipientAddr.String(), + }, + }) + + s.Require().NoError(msgs.UnpackInterfaces(app.AppCodec())) + + s.T().Log("verify dispatch fails with invalid authorization") + executeMsgs, err := msgs.GetMessages() + s.Require().NoError(err) + result, err := app.AuthzKeeper.DispatchActions(s.ctx, granteeAddr, executeMsgs) + + s.Require().Nil(result) + s.Require().NotNil(err) + + s.T().Log("verify dispatch executes with correct information") + // grant authorization + err = app.AuthzKeeper.SaveGrant(s.ctx, granteeAddr, granterAddr, &banktypes.SendAuthorization{SpendLimit: smallCoin}, now) + s.Require().NoError(err) + authorization, _ := app.AuthzKeeper.GetCleanAuthorization(s.ctx, granteeAddr, granterAddr, bankSendAuthMsgType) + s.Require().NotNil(authorization) + + s.Require().Equal(authorization.MsgTypeURL(), bankSendAuthMsgType) + + executeMsgs, err = msgs.GetMessages() + s.Require().NoError(err) + + result, err = app.AuthzKeeper.DispatchActions(s.ctx, granteeAddr, executeMsgs) + s.Require().NoError(err) + s.Require().NotNil(result) + + authorization, _ = app.AuthzKeeper.GetCleanAuthorization(s.ctx, granteeAddr, granterAddr, bankSendAuthMsgType) + s.Require().NotNil(authorization) + + s.T().Log("verify dispatch fails with overlimit") + // grant authorization + + msgs = authz.NewMsgExec(granteeAddr, []sdk.Msg{ + &banktypes.MsgSend{ + Amount: someCoin, + FromAddress: granterAddr.String(), + ToAddress: recipientAddr.String(), + }, + }) + + s.Require().NoError(msgs.UnpackInterfaces(app.AppCodec())) + executeMsgs, err = msgs.GetMessages() + s.Require().NoError(err) + + result, err = app.AuthzKeeper.DispatchActions(s.ctx, granteeAddr, executeMsgs) + s.Require().Nil(result) + s.Require().NotNil(err) + + authorization, _ = app.AuthzKeeper.GetCleanAuthorization(s.ctx, granteeAddr, granterAddr, bankSendAuthMsgType) + s.Require().NotNil(authorization) +} + +// Tests that all msg events included in an authz MsgExec tx +// Ref: https://github.com/cosmos/cosmos-sdk/issues/9501 +func (s *TestSuite) TestDispatchedEvents() { + require := s.Require() + app, addrs := s.app, s.addrs + granterAddr := addrs[0] + granteeAddr := addrs[1] + recipientAddr := addrs[2] + require.NoError(simapp.FundAccount(app, s.ctx, granterAddr, sdk.NewCoins(sdk.NewInt64Coin("steak", 10000)))) + now := s.ctx.BlockHeader().Time + require.NotNil(now) + + smallCoin := sdk.NewCoins(sdk.NewInt64Coin("steak", 20)) + msgs := authz.NewMsgExec(granteeAddr, []sdk.Msg{ + &banktypes.MsgSend{ + Amount: sdk.NewCoins(sdk.NewInt64Coin("steak", 2)), + FromAddress: granterAddr.String(), + ToAddress: recipientAddr.String(), + }, + }) + + // grant authorization + err := app.AuthzKeeper.SaveGrant(s.ctx, granteeAddr, granterAddr, &banktypes.SendAuthorization{SpendLimit: smallCoin}, now) + require.NoError(err) + authorization, _ := app.AuthzKeeper.GetCleanAuthorization(s.ctx, granteeAddr, granterAddr, bankSendAuthMsgType) + require.NotNil(authorization) + require.Equal(authorization.MsgTypeURL(), bankSendAuthMsgType) + + executeMsgs, err := msgs.GetMessages() + require.NoError(err) + + result, err := app.AuthzKeeper.DispatchActions(s.ctx, granteeAddr, executeMsgs) + require.NoError(err) + require.NotNil(result) + events := s.ctx.EventManager().Events() + // get last 5 events (events that occur *after* the grant) + events = events[len(events)-5:] + requiredEvents := map[string]bool{ + "coin_spent": false, + "coin_received": false, + "transfer": false, + "message": false, + } + for _, e := range events { + requiredEvents[e.Type] = true + } + for _, v := range requiredEvents { + require.True(v) + } +} + +func TestTestSuite(t *testing.T) { + suite.Run(t, new(TestSuite)) +} diff --git a/x/authz/keeper/keys.go b/x/authz/keeper/keys.go new file mode 100644 index 0000000000..6c48fb90ff --- /dev/null +++ b/x/authz/keeper/keys.go @@ -0,0 +1,47 @@ +package keeper + +import ( + "github.com/line/lbm-sdk/internal/conv" + sdk "github.com/line/lbm-sdk/types" + "github.com/line/lbm-sdk/types/address" + "github.com/line/lbm-sdk/x/authz" +) + +// Keys for store prefixes +var ( + GrantKey = []byte{0x01} // prefix for each key +) + +// StoreKey is the store key string for authz +const StoreKey = authz.ModuleName + +// grantStoreKey - return authorization store key +// Items are stored with the following key: values +// +// - 0x01: Grant +func grantStoreKey(grantee sdk.AccAddress, granter sdk.AccAddress, msgType string) []byte { + m := conv.UnsafeStrToBytes(msgType) + granter = sdk.AccAddress(address.MustLengthPrefix(granter.Bytes())) + grantee = sdk.AccAddress(address.MustLengthPrefix(grantee.Bytes())) + + l := 1 + len(grantee) + len(granter) + len(m) + var key = make([]byte, l) + copy(key, GrantKey) + copy(key[1:], granter) + copy(key[1+len(granter):], grantee) + copy(key[l-len(m):], m) + // fmt.Println(">>>> len", l, key) + return key +} + +// addressesFromGrantStoreKey - split granter & grantee address from the authorization key +func addressesFromGrantStoreKey(key []byte) (granterAddr, granteeAddr sdk.AccAddress) { + // key is of format: + // 0x01 + granterAddrLen := key[1] // remove prefix key + granterAddr = sdk.AccAddress(key[2 : 2+granterAddrLen]) + granteeAddrLen := int(key[2+granterAddrLen]) + granteeAddr = sdk.AccAddress(key[3+granterAddrLen : 3+granterAddrLen+byte(granteeAddrLen)]) + + return granterAddr, granteeAddr +} diff --git a/x/authz/keeper/keys_test.go b/x/authz/keeper/keys_test.go new file mode 100644 index 0000000000..6208687750 --- /dev/null +++ b/x/authz/keeper/keys_test.go @@ -0,0 +1,26 @@ +package keeper + +import ( + "testing" + + "github.com/stretchr/testify/require" + + "github.com/line/lbm-sdk/crypto/keys/ed25519" + sdk "github.com/line/lbm-sdk/types" + "github.com/line/lbm-sdk/types/address" + bank "github.com/line/lbm-sdk/x/bank/types" +) + +var granter = sdk.AccAddress(ed25519.GenPrivKey().PubKey().Address()) +var grantee = sdk.AccAddress(ed25519.GenPrivKey().PubKey().Address()) +var msgType = bank.SendAuthorization{}.MsgTypeURL() + +func TestGrantkey(t *testing.T) { + require := require.New(t) + key := grantStoreKey(grantee, granter, msgType) + require.Len(key, len(GrantKey)+len(address.MustLengthPrefix(grantee.Bytes()))+len(address.MustLengthPrefix(granter.Bytes()))+len([]byte(msgType))) + + granter1, grantee1 := addressesFromGrantStoreKey(grantStoreKey(grantee, granter, msgType)) + require.Equal(granter, granter1) + require.Equal(grantee, grantee1) +} diff --git a/x/authz/keeper/msg_server.go b/x/authz/keeper/msg_server.go new file mode 100644 index 0000000000..e9fa5af49a --- /dev/null +++ b/x/authz/keeper/msg_server.go @@ -0,0 +1,85 @@ +package keeper + +import ( + "context" + + sdk "github.com/line/lbm-sdk/types" + sdkerrors "github.com/line/lbm-sdk/types/errors" + "github.com/line/lbm-sdk/x/authz" +) + +var _ authz.MsgServer = Keeper{} + +// GrantAuthorization implements the MsgServer.Grant method to create a new grant. +func (k Keeper) Grant(goCtx context.Context, msg *authz.MsgGrant) (*authz.MsgGrantResponse, error) { + ctx := sdk.UnwrapSDKContext(goCtx) + err := sdk.ValidateAccAddress(msg.Grantee) + if err != nil { + return nil, err + } + grantee := sdk.AccAddress(msg.Grantee) + + err = sdk.ValidateAccAddress(msg.Granter) + if err != nil { + return nil, err + } + granter := sdk.AccAddress(msg.Granter) + + authorization := msg.GetAuthorization() + if authorization == nil { + return nil, sdkerrors.ErrUnpackAny.Wrap("Authorization is not present in the msg") + } + t := authorization.MsgTypeURL() + if k.router.HandlerByTypeURL(t) == nil { + return nil, sdkerrors.Wrapf(sdkerrors.ErrInvalidType, "%s doesn't exist.", t) + } + + err = k.SaveGrant(ctx, grantee, granter, authorization, msg.Grant.Expiration) + if err != nil { + return nil, err + } + + return &authz.MsgGrantResponse{}, nil +} + +// RevokeAuthorization implements the MsgServer.Revoke method. +func (k Keeper) Revoke(goCtx context.Context, msg *authz.MsgRevoke) (*authz.MsgRevokeResponse, error) { + ctx := sdk.UnwrapSDKContext(goCtx) + err := sdk.ValidateAccAddress(msg.Grantee) + if err != nil { + return nil, err + } + grantee := sdk.AccAddress(msg.Grantee) + + err = sdk.ValidateAccAddress(msg.Granter) + if err != nil { + return nil, err + } + granter := sdk.AccAddress(msg.Granter) + + err = k.DeleteGrant(ctx, grantee, granter, msg.MsgTypeUrl) + if err != nil { + return nil, err + } + + return &authz.MsgRevokeResponse{}, nil +} + +// Exec implements the MsgServer.Exec method. +func (k Keeper) Exec(goCtx context.Context, msg *authz.MsgExec) (*authz.MsgExecResponse, error) { + ctx := sdk.UnwrapSDKContext(goCtx) + err := sdk.ValidateAccAddress(msg.Grantee) + if err != nil { + return nil, err + } + grantee := sdk.AccAddress(msg.Grantee) + msgs, err := msg.GetMessages() + if err != nil { + return nil, err + } + results, err := k.DispatchActions(ctx, grantee, msgs) + if err != nil { + return nil, err + } + return &authz.MsgExecResponse{Results: results}, nil +} diff --git a/x/authz/keys.go b/x/authz/keys.go new file mode 100644 index 0000000000..f0ecb467ae --- /dev/null +++ b/x/authz/keys.go @@ -0,0 +1,12 @@ +package authz + +const ( + // ModuleName is the module name constant used in many places + ModuleName = "authz" + + // RouterKey is the message route for authz + RouterKey = ModuleName + + // QuerierRoute is the querier route for authz + QuerierRoute = ModuleName +) diff --git a/x/authz/module/module.go b/x/authz/module/module.go new file mode 100644 index 0000000000..cde1328f6b --- /dev/null +++ b/x/authz/module/module.go @@ -0,0 +1,195 @@ +package authz + +import ( + "context" + "encoding/json" + "math/rand" + + "github.com/gorilla/mux" + "github.com/grpc-ecosystem/grpc-gateway/runtime" + "github.com/spf13/cobra" + + abci "github.com/line/ostracon/abci/types" + + sdkclient "github.com/line/lbm-sdk/client" + "github.com/line/lbm-sdk/codec" + cdctypes "github.com/line/lbm-sdk/codec/types" + sdk "github.com/line/lbm-sdk/types" + sdkerrors "github.com/line/lbm-sdk/types/errors" + "github.com/line/lbm-sdk/types/module" + simtypes "github.com/line/lbm-sdk/types/simulation" + "github.com/line/lbm-sdk/x/authz" + "github.com/line/lbm-sdk/x/authz/client/cli" + "github.com/line/lbm-sdk/x/authz/keeper" + "github.com/line/lbm-sdk/x/authz/simulation" +) + +var ( + _ module.AppModule = AppModule{} + _ module.AppModuleBasic = AppModuleBasic{} + _ module.AppModuleSimulation = AppModule{} +) + +// AppModuleBasic defines the basic application module used by the authz module. +type AppModuleBasic struct { + cdc codec.Codec +} + +// Name returns the authz module's name. +func (AppModuleBasic) Name() string { + return authz.ModuleName +} + +// RegisterServices registers a gRPC query service to respond to the +// module-specific gRPC queries. +func (am AppModule) RegisterServices(cfg module.Configurator) { + authz.RegisterQueryServer(cfg.QueryServer(), am.keeper) + authz.RegisterMsgServer(cfg.MsgServer(), am.keeper) +} + +// RegisterLegacyAminoCodec registers the authz module's types for the given codec. +func (AppModuleBasic) RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) {} + +// RegisterInterfaces registers the authz module's interface types +func (AppModuleBasic) RegisterInterfaces(registry cdctypes.InterfaceRegistry) { + authz.RegisterInterfaces(registry) +} + +// DefaultGenesis returns default genesis state as raw bytes for the authz +// module. +func (AppModuleBasic) DefaultGenesis(cdc codec.JSONCodec) json.RawMessage { + return cdc.MustMarshalJSON(authz.DefaultGenesisState()) +} + +// ValidateGenesis performs genesis state validation for the authz module. +func (AppModuleBasic) ValidateGenesis(cdc codec.JSONCodec, config sdkclient.TxEncodingConfig, bz json.RawMessage) error { + var data authz.GenesisState + if err := cdc.UnmarshalJSON(bz, &data); err != nil { + return sdkerrors.Wrapf(err, "failed to unmarshal %s genesis state", authz.ModuleName) + } + + return authz.ValidateGenesis(data) +} + +// RegisterRESTRoutes registers the REST routes for the authz module. +func (AppModuleBasic) RegisterRESTRoutes(clientCtx sdkclient.Context, r *mux.Router) { +} + +// RegisterGRPCGatewayRoutes registers the gRPC Gateway routes for the authz module. +func (a AppModuleBasic) RegisterGRPCGatewayRoutes(clientCtx sdkclient.Context, mux *runtime.ServeMux) { + authz.RegisterQueryHandlerClient(context.Background(), mux, authz.NewQueryClient(clientCtx)) +} + +// GetQueryCmd returns the cli query commands for the authz module +func (AppModuleBasic) GetQueryCmd() *cobra.Command { + return cli.GetQueryCmd() +} + +// GetTxCmd returns the transaction commands for the authz module +func (AppModuleBasic) GetTxCmd() *cobra.Command { + return cli.GetTxCmd() +} + +// AppModule implements the sdk.AppModule interface +type AppModule struct { + AppModuleBasic + keeper keeper.Keeper + accountKeeper authz.AccountKeeper + bankKeeper authz.BankKeeper + registry cdctypes.InterfaceRegistry +} + +// NewAppModule creates a new AppModule object +func NewAppModule(cdc codec.Codec, keeper keeper.Keeper, ak authz.AccountKeeper, bk authz.BankKeeper, registry cdctypes.InterfaceRegistry) AppModule { + return AppModule{ + AppModuleBasic: AppModuleBasic{cdc: cdc}, + keeper: keeper, + accountKeeper: ak, + bankKeeper: bk, + registry: registry, + } +} + +// Name returns the authz module's name. +func (AppModule) Name() string { + return authz.ModuleName +} + +// RegisterInvariants does nothing, there are no invariants to enforce +func (AppModule) RegisterInvariants(_ sdk.InvariantRegistry) {} + +// Route returns the message routing key for the staking module. +func (am AppModule) Route() sdk.Route { + return sdk.NewRoute(authz.RouterKey, nil) +} + +func (am AppModule) NewHandler() sdk.Handler { + return nil +} + +// QuerierRoute returns the route we respond to for abci queries +func (AppModule) QuerierRoute() string { return "" } + +// LegacyQuerierHandler returns the authz module sdk.Querier. +func (am AppModule) LegacyQuerierHandler(legacyQuerierCdc *codec.LegacyAmino) sdk.Querier { + return nil +} + +// InitGenesis performs genesis initialization for the authz module. It returns +// no validator updates. +func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONCodec, data json.RawMessage) []abci.ValidatorUpdate { + var genesisState authz.GenesisState + cdc.MustUnmarshalJSON(data, &genesisState) + am.keeper.InitGenesis(ctx, &genesisState) + return []abci.ValidatorUpdate{} +} + +// ExportGenesis returns the exported genesis state as raw bytes for the authz +// module. +func (am AppModule) ExportGenesis(ctx sdk.Context, cdc codec.JSONCodec) json.RawMessage { + gs := am.keeper.ExportGenesis(ctx) + return cdc.MustMarshalJSON(gs) +} + +// ConsensusVersion implements AppModule/ConsensusVersion. +func (AppModule) ConsensusVersion() uint64 { return 1 } + +func (am AppModule) BeginBlock(ctx sdk.Context, req abci.RequestBeginBlock) {} + +// EndBlock does nothing +func (am AppModule) EndBlock(ctx sdk.Context, _ abci.RequestEndBlock) []abci.ValidatorUpdate { + return []abci.ValidatorUpdate{} +} + +// ____________________________________________________________________________ + +// AppModuleSimulation functions + +// GenerateGenesisState creates a randomized GenState of the authz module. +func (AppModule) GenerateGenesisState(simState *module.SimulationState) { + simulation.RandomizedGenState(simState) +} + +// ProposalContents returns all the authz content functions used to +// simulate governance proposals. +func (am AppModule) ProposalContents(simState module.SimulationState) []simtypes.WeightedProposalContent { + return nil +} + +// RandomizedParams creates randomized authz param changes for the simulator. +func (AppModule) RandomizedParams(r *rand.Rand) []simtypes.ParamChange { + return nil +} + +// RegisterStoreDecoder registers a decoder for authz module's types +func (am AppModule) RegisterStoreDecoder(sdr sdk.StoreDecoderRegistry) { + sdr[keeper.StoreKey] = simulation.NewDecodeStore(am.cdc) +} + +// WeightedOperations returns the all the gov module operations with their respective weights. +func (am AppModule) WeightedOperations(simState module.SimulationState) []simtypes.WeightedOperation { + return simulation.WeightedOperations( + simState.AppParams, simState.Cdc, + am.accountKeeper, am.bankKeeper, am.keeper, am.cdc, + ) +} diff --git a/x/authz/msgs.go b/x/authz/msgs.go new file mode 100644 index 0000000000..52d77062e8 --- /dev/null +++ b/x/authz/msgs.go @@ -0,0 +1,256 @@ +package authz + +import ( + "time" + + "github.com/gogo/protobuf/proto" + + "github.com/line/lbm-sdk/codec/legacy" + cdctypes "github.com/line/lbm-sdk/codec/types" + sdk "github.com/line/lbm-sdk/types" + sdkerrors "github.com/line/lbm-sdk/types/errors" + "github.com/line/lbm-sdk/x/auth/legacy/legacytx" +) + +var ( + _ sdk.Msg = &MsgGrant{} + _ sdk.Msg = &MsgRevoke{} + _ sdk.Msg = &MsgExec{} + + // For amino support. + _ legacytx.LegacyMsg = &MsgGrant{} + _ legacytx.LegacyMsg = &MsgRevoke{} + _ legacytx.LegacyMsg = &MsgExec{} + + _ cdctypes.UnpackInterfacesMessage = &MsgGrant{} + _ cdctypes.UnpackInterfacesMessage = &MsgExec{} +) + +// NewMsgGrant creates a new MsgGrant +//nolint:interfacer +func NewMsgGrant(granter sdk.AccAddress, grantee sdk.AccAddress, a Authorization, expiration time.Time) (*MsgGrant, error) { + m := &MsgGrant{ + Granter: granter.String(), + Grantee: grantee.String(), + Grant: Grant{Expiration: expiration}, + } + err := m.SetAuthorization(a) + if err != nil { + return nil, err + } + return m, nil +} + +// GetSigners implements Msg +func (msg MsgGrant) GetSigners() []sdk.AccAddress { + err := sdk.ValidateAccAddress(msg.Granter) + if err != nil { + panic(err) + } + granter := sdk.AccAddress(msg.Granter) + return []sdk.AccAddress{granter} +} + +// ValidateBasic implements Msg +func (msg MsgGrant) ValidateBasic() error { + err := sdk.ValidateAccAddress(msg.Granter) + if err != nil { + return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, "invalid granter address") + } + granter := sdk.AccAddress(msg.Granter) + + err = sdk.ValidateAccAddress(msg.Grantee) + if err != nil { + return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, "invalid granter address") + } + grantee := sdk.AccAddress(msg.Grantee) + + if granter.Equals(grantee) { + return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "granter and grantee cannot be same") + } + return msg.Grant.ValidateBasic() +} + +// Type implements the LegacyMsg.Type method. +func (msg MsgGrant) Type() string { + return sdk.MsgTypeURL(&msg) +} + +// Route implements the LegacyMsg.Route method. +func (msg MsgGrant) Route() string { + return sdk.MsgTypeURL(&msg) +} + +// GetSignBytes implements the LegacyMsg.GetSignBytes method. +func (msg MsgGrant) GetSignBytes() []byte { + return sdk.MustSortJSON(legacy.Cdc.MustMarshalJSON(&msg)) +} + +// GetAuthorization returns the cache value from the MsgGrant.Authorization if present. +func (msg *MsgGrant) GetAuthorization() Authorization { + return msg.Grant.GetAuthorization() +} + +// SetAuthorization converts Authorization to any and adds it to MsgGrant.Authorization. +func (msg *MsgGrant) SetAuthorization(a Authorization) error { + m, ok := a.(proto.Message) + if !ok { + return sdkerrors.Wrapf(sdkerrors.ErrPackAny, "can't proto marshal %T", m) + } + any, err := cdctypes.NewAnyWithValue(m) + if err != nil { + return err + } + msg.Grant.Authorization = any + return nil +} + +// UnpackInterfaces implements UnpackInterfacesMessage.UnpackInterfaces +func (msg MsgExec) UnpackInterfaces(unpacker cdctypes.AnyUnpacker) error { + for _, x := range msg.Msgs { + var msgExecAuthorized sdk.Msg + err := unpacker.UnpackAny(x, &msgExecAuthorized) + if err != nil { + return err + } + } + + return nil +} + +// UnpackInterfaces implements UnpackInterfacesMessage.UnpackInterfaces +func (msg MsgGrant) UnpackInterfaces(unpacker cdctypes.AnyUnpacker) error { + return msg.Grant.UnpackInterfaces(unpacker) +} + +// NewMsgRevoke creates a new MsgRevoke +//nolint:interfacer +func NewMsgRevoke(granter sdk.AccAddress, grantee sdk.AccAddress, msgTypeURL string) MsgRevoke { + return MsgRevoke{ + Granter: granter.String(), + Grantee: grantee.String(), + MsgTypeUrl: msgTypeURL, + } +} + +// GetSigners implements Msg +func (msg MsgRevoke) GetSigners() []sdk.AccAddress { + err := sdk.ValidateAccAddress(msg.Granter) + if err != nil { + panic(err) + } + granter := sdk.AccAddress(msg.Granter) + return []sdk.AccAddress{granter} +} + +// ValidateBasic implements MsgRequest.ValidateBasic +func (msg MsgRevoke) ValidateBasic() error { + err := sdk.ValidateAccAddress(msg.Granter) + if err != nil { + return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, "invalid granter address") + } + granter := sdk.AccAddress(msg.Granter) + + err = sdk.ValidateAccAddress(msg.Grantee) + if err != nil { + return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, "invalid grantee address") + } + grantee := sdk.AccAddress(msg.Grantee) + + if granter.Equals(grantee) { + return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "granter and grantee cannot be same") + } + + if msg.MsgTypeUrl == "" { + return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "missing method name") + } + + return nil +} + +// Type implements the LegacyMsg.Type method. +func (msg MsgRevoke) Type() string { + return sdk.MsgTypeURL(&msg) +} + +// Route implements the LegacyMsg.Route method. +func (msg MsgRevoke) Route() string { + return sdk.MsgTypeURL(&msg) +} + +// GetSignBytes implements the LegacyMsg.GetSignBytes method. +func (msg MsgRevoke) GetSignBytes() []byte { + return sdk.MustSortJSON(legacy.Cdc.MustMarshalJSON(&msg)) +} + +// NewMsgExec creates a new MsgExecAuthorized +//nolint:interfacer +func NewMsgExec(grantee sdk.AccAddress, msgs []sdk.Msg) MsgExec { + msgsAny := make([]*cdctypes.Any, len(msgs)) + for i, msg := range msgs { + any, err := cdctypes.NewAnyWithValue(msg) + if err != nil { + panic(err) + } + + msgsAny[i] = any + } + + return MsgExec{ + Grantee: grantee.String(), + Msgs: msgsAny, + } +} + +// GetMessages returns the cache values from the MsgExecAuthorized.Msgs if present. +func (msg MsgExec) GetMessages() ([]sdk.Msg, error) { + msgs := make([]sdk.Msg, len(msg.Msgs)) + for i, msgAny := range msg.Msgs { + msg, ok := msgAny.GetCachedValue().(sdk.Msg) + if !ok { + return nil, sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "messages contains %T which is not a sdk.MsgRequest", msgAny) + } + msgs[i] = msg + } + + return msgs, nil +} + +// GetSigners implements Msg +func (msg MsgExec) GetSigners() []sdk.AccAddress { + err := sdk.ValidateAccAddress(msg.Grantee) + if err != nil { + panic(err) + } + grantee := sdk.AccAddress(msg.Grantee) + return []sdk.AccAddress{grantee} +} + +// ValidateBasic implements Msg +func (msg MsgExec) ValidateBasic() error { + err := sdk.ValidateAccAddress(msg.Grantee) + if err != nil { + return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, "invalid grantee address") + } + + if len(msg.Msgs) == 0 { + return sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "messages cannot be empty") + } + + return nil +} + +// Type implements the LegacyMsg.Type method. +func (msg MsgExec) Type() string { + return sdk.MsgTypeURL(&msg) +} + +// Route implements the LegacyMsg.Route method. +func (msg MsgExec) Route() string { + return sdk.MsgTypeURL(&msg) +} + +// GetSignBytes implements the LegacyMsg.GetSignBytes method. +func (msg MsgExec) GetSignBytes() []byte { + return sdk.MustSortJSON(legacy.Cdc.MustMarshalJSON(&msg)) +} diff --git a/x/authz/msgs_test.go b/x/authz/msgs_test.go new file mode 100644 index 0000000000..b37e37cbd4 --- /dev/null +++ b/x/authz/msgs_test.go @@ -0,0 +1,117 @@ +package authz_test + +import ( + "testing" + "time" + + "github.com/stretchr/testify/require" + + cdctypes "github.com/line/lbm-sdk/codec/types" + sdk "github.com/line/lbm-sdk/types" + "github.com/line/lbm-sdk/x/authz" + banktypes "github.com/line/lbm-sdk/x/bank/types" +) + +var ( + coinsPos = sdk.NewCoins(sdk.NewInt64Coin("steak", 100)) + granter = sdk.BytesToAccAddress([]byte("_______granter______")) + grantee = sdk.BytesToAccAddress([]byte("_______grantee______")) +) + +func TestMsgExecAuthorized(t *testing.T) { + tests := []struct { + title string + grantee sdk.AccAddress + msgs []sdk.Msg + expectPass bool + }{ + {"nil grantee address", "", []sdk.Msg{}, false}, + {"zero-messages test: should fail", grantee, []sdk.Msg{}, false}, + {"valid test: msg type", grantee, []sdk.Msg{ + &banktypes.MsgSend{ + Amount: sdk.NewCoins(sdk.NewInt64Coin("steak", 2)), + FromAddress: granter.String(), + ToAddress: grantee.String(), + }, + }, true}, + } + for i, tc := range tests { + msg := authz.NewMsgExec(tc.grantee, tc.msgs) + if tc.expectPass { + require.NoError(t, msg.ValidateBasic(), "test: %v", i) + } else { + require.Error(t, msg.ValidateBasic(), "test: %v", i) + } + } +} +func TestMsgRevokeAuthorization(t *testing.T) { + tests := []struct { + title string + granter, grantee sdk.AccAddress + msgType string + expectPass bool + }{ + {"nil Granter address", "", grantee, "hello", false}, + {"nil Grantee address", granter, "", "hello", false}, + {"nil Granter and Grantee address", "", "", "hello", false}, + {"valid test case", granter, grantee, "hello", true}, + } + for i, tc := range tests { + msg := authz.NewMsgRevoke(tc.granter, tc.grantee, tc.msgType) + if tc.expectPass { + require.NoError(t, msg.ValidateBasic(), "test: %v", i) + } else { + require.Error(t, msg.ValidateBasic(), "test: %v", i) + } + } +} + +func TestMsgGrantAuthorization(t *testing.T) { + tests := []struct { + title string + granter, grantee sdk.AccAddress + authorization authz.Authorization + expiration time.Time + expectErr bool + expectPass bool + }{ + {"nil granter address", "", grantee, &banktypes.SendAuthorization{SpendLimit: coinsPos}, time.Now(), false, false}, + {"nil grantee address", granter, "", &banktypes.SendAuthorization{SpendLimit: coinsPos}, time.Now(), false, false}, + {"nil granter and grantee address", "", "", &banktypes.SendAuthorization{SpendLimit: coinsPos}, time.Now(), false, false}, + {"nil authorization", granter, grantee, nil, time.Now(), true, false}, + {"valid test case", granter, grantee, &banktypes.SendAuthorization{SpendLimit: coinsPos}, time.Now().AddDate(0, 1, 0), false, true}, + {"past time", granter, grantee, &banktypes.SendAuthorization{SpendLimit: coinsPos}, time.Now().AddDate(0, 0, -1), false, true}, // TODO need 0.45 + } + for i, tc := range tests { + msg, err := authz.NewMsgGrant( + tc.granter, tc.grantee, tc.authorization, tc.expiration, + ) + if !tc.expectErr { + require.NoError(t, err) + } else { + continue + } + if tc.expectPass { + require.NoError(t, msg.ValidateBasic(), "test: %v", i) + } else { + require.Error(t, msg.ValidateBasic(), "test: %v", i) + } + } +} + +func TestMsgGrantGetAuthorization(t *testing.T) { + require := require.New(t) + + m := authz.MsgGrant{} + require.Nil(m.GetAuthorization()) + + g := authz.GenericAuthorization{Msg: "some_type"} + var err error + m.Grant.Authorization, err = cdctypes.NewAnyWithValue(&g) + require.NoError(err) + require.Equal(m.GetAuthorization(), &g) + + g = authz.GenericAuthorization{Msg: "some_type2"} + m.SetAuthorization(&g) + require.Equal(m.GetAuthorization(), &g) +} diff --git a/x/authz/proto_desc.go b/x/authz/proto_desc.go new file mode 100644 index 0000000000..cc5e62e7a3 --- /dev/null +++ b/x/authz/proto_desc.go @@ -0,0 +1,8 @@ +package authz + +import grpc "google.golang.org/grpc" + +// MsgServiceDesc return ServiceDesc for Msg server +func MsgServiceDesc() *grpc.ServiceDesc { + return &_Msg_serviceDesc +} diff --git a/x/authz/query.pb.go b/x/authz/query.pb.go new file mode 100644 index 0000000000..9d0e4814d4 --- /dev/null +++ b/x/authz/query.pb.go @@ -0,0 +1,827 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: lbm/authz/v1/query.proto + +package authz + +import ( + context "context" + fmt "fmt" + grpc1 "github.com/gogo/protobuf/grpc" + proto "github.com/gogo/protobuf/proto" + query "github.com/line/lbm-sdk/types/query" + _ "github.com/regen-network/cosmos-proto" + _ "google.golang.org/genproto/googleapis/api/annotations" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +// QueryGrantsRequest is the request type for the Query/Grants RPC method. +type QueryGrantsRequest struct { + Granter string `protobuf:"bytes,1,opt,name=granter,proto3" json:"granter,omitempty"` + Grantee string `protobuf:"bytes,2,opt,name=grantee,proto3" json:"grantee,omitempty"` + // Optional, msg_type_url, when set, will query only grants matching given msg type. + MsgTypeUrl string `protobuf:"bytes,3,opt,name=msg_type_url,json=msgTypeUrl,proto3" json:"msg_type_url,omitempty"` + // pagination defines an pagination for the request. + Pagination *query.PageRequest `protobuf:"bytes,4,opt,name=pagination,proto3" json:"pagination,omitempty"` +} + +func (m *QueryGrantsRequest) Reset() { *m = QueryGrantsRequest{} } +func (m *QueryGrantsRequest) String() string { return proto.CompactTextString(m) } +func (*QueryGrantsRequest) ProtoMessage() {} +func (*QueryGrantsRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_b714c30761571f28, []int{0} +} +func (m *QueryGrantsRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryGrantsRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryGrantsRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryGrantsRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryGrantsRequest.Merge(m, src) +} +func (m *QueryGrantsRequest) XXX_Size() int { + return m.Size() +} +func (m *QueryGrantsRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QueryGrantsRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryGrantsRequest proto.InternalMessageInfo + +func (m *QueryGrantsRequest) GetGranter() string { + if m != nil { + return m.Granter + } + return "" +} + +func (m *QueryGrantsRequest) GetGrantee() string { + if m != nil { + return m.Grantee + } + return "" +} + +func (m *QueryGrantsRequest) GetMsgTypeUrl() string { + if m != nil { + return m.MsgTypeUrl + } + return "" +} + +func (m *QueryGrantsRequest) GetPagination() *query.PageRequest { + if m != nil { + return m.Pagination + } + return nil +} + +// QueryGrantsResponse is the response type for the Query/Authorizations RPC method. +type QueryGrantsResponse struct { + // authorizations is a list of grants granted for grantee by granter. + Grants []*Grant `protobuf:"bytes,1,rep,name=grants,proto3" json:"grants,omitempty"` + // pagination defines an pagination for the response. + Pagination *query.PageResponse `protobuf:"bytes,2,opt,name=pagination,proto3" json:"pagination,omitempty"` +} + +func (m *QueryGrantsResponse) Reset() { *m = QueryGrantsResponse{} } +func (m *QueryGrantsResponse) String() string { return proto.CompactTextString(m) } +func (*QueryGrantsResponse) ProtoMessage() {} +func (*QueryGrantsResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_b714c30761571f28, []int{1} +} +func (m *QueryGrantsResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryGrantsResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryGrantsResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryGrantsResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryGrantsResponse.Merge(m, src) +} +func (m *QueryGrantsResponse) XXX_Size() int { + return m.Size() +} +func (m *QueryGrantsResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryGrantsResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryGrantsResponse proto.InternalMessageInfo + +func (m *QueryGrantsResponse) GetGrants() []*Grant { + if m != nil { + return m.Grants + } + return nil +} + +func (m *QueryGrantsResponse) GetPagination() *query.PageResponse { + if m != nil { + return m.Pagination + } + return nil +} + +func init() { + proto.RegisterType((*QueryGrantsRequest)(nil), "lbm.authz.v1.QueryGrantsRequest") + proto.RegisterType((*QueryGrantsResponse)(nil), "lbm.authz.v1.QueryGrantsResponse") +} + +func init() { proto.RegisterFile("lbm/authz/v1/query.proto", fileDescriptor_b714c30761571f28) } + +var fileDescriptor_b714c30761571f28 = []byte{ + // 384 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x91, 0xb1, 0x4e, 0xeb, 0x30, + 0x18, 0x85, 0xeb, 0xf6, 0xde, 0x5e, 0x5d, 0xb7, 0x93, 0x7b, 0x75, 0x15, 0xaa, 0x2a, 0x0d, 0x99, + 0x2a, 0x21, 0x6c, 0xb5, 0x4c, 0x2c, 0x20, 0xb1, 0xb0, 0x42, 0x04, 0x0b, 0x4b, 0xe5, 0x14, 0xcb, + 0x8d, 0x9a, 0xc4, 0x69, 0xec, 0x54, 0x94, 0x11, 0x5e, 0x00, 0x89, 0xb7, 0xe0, 0x49, 0x18, 0x2b, + 0xb1, 0x30, 0xa2, 0x96, 0x07, 0x41, 0xb1, 0x83, 0x9a, 0x08, 0xc1, 0xf8, 0xfb, 0x9c, 0xdf, 0xe7, + 0xd3, 0xf9, 0xa1, 0x15, 0xfa, 0x11, 0xa1, 0x99, 0x9a, 0xde, 0x92, 0xc5, 0x90, 0xcc, 0x33, 0x96, + 0x2e, 0x71, 0x92, 0x0a, 0x25, 0x50, 0x3b, 0xf4, 0x23, 0xac, 0x15, 0xbc, 0x18, 0x76, 0x7b, 0x5c, + 0x08, 0x1e, 0x32, 0x42, 0x93, 0x80, 0xd0, 0x38, 0x16, 0x8a, 0xaa, 0x40, 0xc4, 0xd2, 0x78, 0xbb, + 0x3b, 0x13, 0x21, 0x23, 0x21, 0xc7, 0x7a, 0x22, 0x66, 0x28, 0x24, 0x37, 0x0f, 0xf0, 0xa9, 0x64, + 0xe6, 0xf3, 0x3c, 0x25, 0xa1, 0x3c, 0x88, 0xf5, 0x7e, 0xe1, 0xa9, 0x42, 0x98, 0x4c, 0xad, 0xb8, + 0x4f, 0x00, 0xa2, 0xf3, 0x7c, 0xef, 0x34, 0xa5, 0xb1, 0x92, 0x1e, 0x9b, 0x67, 0x4c, 0x2a, 0x64, + 0xc1, 0x3f, 0x3c, 0x7f, 0x60, 0xa9, 0x05, 0x1c, 0x30, 0xf8, 0xeb, 0x7d, 0x8e, 0x5b, 0x85, 0x59, + 0xf5, 0xb2, 0xc2, 0x90, 0x03, 0xdb, 0x91, 0xe4, 0x63, 0xb5, 0x4c, 0xd8, 0x38, 0x4b, 0x43, 0xab, + 0xa1, 0x65, 0x18, 0x49, 0x7e, 0xb1, 0x4c, 0xd8, 0x65, 0x1a, 0xa2, 0x23, 0x08, 0xb7, 0x68, 0xd6, + 0x2f, 0x07, 0x0c, 0x5a, 0x23, 0x1b, 0xe7, 0x35, 0xe4, 0xfc, 0xd8, 0x94, 0xb3, 0x18, 0xe2, 0x33, + 0xca, 0x59, 0x41, 0xe2, 0x95, 0x36, 0xdc, 0x7b, 0x00, 0x3b, 0x15, 0x58, 0x99, 0x88, 0x58, 0x32, + 0xb4, 0x07, 0x9b, 0x1a, 0x42, 0x5a, 0xc0, 0x69, 0x0c, 0x5a, 0xa3, 0x0e, 0x2e, 0x57, 0x8b, 0xb5, + 0xdb, 0x2b, 0x2c, 0xe8, 0xb8, 0x02, 0x51, 0xd7, 0x10, 0xfd, 0x6f, 0x21, 0x4c, 0x42, 0x99, 0x62, + 0xa4, 0xe0, 0x6f, 0x0d, 0x81, 0x66, 0xb0, 0x69, 0x40, 0x90, 0x53, 0x0d, 0xfc, 0x5a, 0x68, 0x77, + 0xf7, 0x07, 0x87, 0xc9, 0x70, 0x7b, 0x77, 0x2f, 0xef, 0x8f, 0xf5, 0xff, 0xe8, 0x1f, 0xa9, 0x5c, + 0xcb, 0x60, 0x9f, 0x1c, 0x3e, 0xaf, 0x6d, 0xb0, 0x5a, 0xdb, 0xe0, 0x6d, 0x6d, 0x83, 0x87, 0x8d, + 0x5d, 0x5b, 0x6d, 0xec, 0xda, 0xeb, 0xc6, 0xae, 0x5d, 0xf5, 0x79, 0xa0, 0xa6, 0x99, 0x8f, 0x27, + 0x22, 0x22, 0x61, 0x10, 0xb3, 0x7c, 0x7d, 0x5f, 0x5e, 0xcf, 0xc8, 0x8d, 0xf9, 0xc4, 0x6f, 0xea, + 0x53, 0x1f, 0x7c, 0x04, 0x00, 0x00, 0xff, 0xff, 0xeb, 0x18, 0xbb, 0xf2, 0x8b, 0x02, 0x00, 0x00, +} + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ grpc.ClientConn + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +const _ = grpc.SupportPackageIsVersion4 + +// QueryClient is the client API for Query service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. +type QueryClient interface { + // Returns list of `Authorization`, granted to the grantee by the granter. + Grants(ctx context.Context, in *QueryGrantsRequest, opts ...grpc.CallOption) (*QueryGrantsResponse, error) +} + +type queryClient struct { + cc grpc1.ClientConn +} + +func NewQueryClient(cc grpc1.ClientConn) QueryClient { + return &queryClient{cc} +} + +func (c *queryClient) Grants(ctx context.Context, in *QueryGrantsRequest, opts ...grpc.CallOption) (*QueryGrantsResponse, error) { + out := new(QueryGrantsResponse) + err := c.cc.Invoke(ctx, "/lbm.authz.v1.Query/Grants", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// QueryServer is the server API for Query service. +type QueryServer interface { + // Returns list of `Authorization`, granted to the grantee by the granter. + Grants(context.Context, *QueryGrantsRequest) (*QueryGrantsResponse, error) +} + +// UnimplementedQueryServer can be embedded to have forward compatible implementations. +type UnimplementedQueryServer struct { +} + +func (*UnimplementedQueryServer) Grants(ctx context.Context, req *QueryGrantsRequest) (*QueryGrantsResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Grants not implemented") +} + +func RegisterQueryServer(s grpc1.Server, srv QueryServer) { + s.RegisterService(&_Query_serviceDesc, srv) +} + +func _Query_Grants_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryGrantsRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).Grants(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/lbm.authz.v1.Query/Grants", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).Grants(ctx, req.(*QueryGrantsRequest)) + } + return interceptor(ctx, in, info, handler) +} + +var _Query_serviceDesc = grpc.ServiceDesc{ + ServiceName: "lbm.authz.v1.Query", + HandlerType: (*QueryServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "Grants", + Handler: _Query_Grants_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "lbm/authz/v1/query.proto", +} + +func (m *QueryGrantsRequest) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryGrantsRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryGrantsRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Pagination != nil { + { + size, err := m.Pagination.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x22 + } + if len(m.MsgTypeUrl) > 0 { + i -= len(m.MsgTypeUrl) + copy(dAtA[i:], m.MsgTypeUrl) + i = encodeVarintQuery(dAtA, i, uint64(len(m.MsgTypeUrl))) + i-- + dAtA[i] = 0x1a + } + if len(m.Grantee) > 0 { + i -= len(m.Grantee) + copy(dAtA[i:], m.Grantee) + i = encodeVarintQuery(dAtA, i, uint64(len(m.Grantee))) + i-- + dAtA[i] = 0x12 + } + if len(m.Granter) > 0 { + i -= len(m.Granter) + copy(dAtA[i:], m.Granter) + i = encodeVarintQuery(dAtA, i, uint64(len(m.Granter))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *QueryGrantsResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryGrantsResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryGrantsResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Pagination != nil { + { + size, err := m.Pagination.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + if len(m.Grants) > 0 { + for iNdEx := len(m.Grants) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Grants[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func encodeVarintQuery(dAtA []byte, offset int, v uint64) int { + offset -= sovQuery(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *QueryGrantsRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Granter) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + l = len(m.Grantee) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + l = len(m.MsgTypeUrl) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + if m.Pagination != nil { + l = m.Pagination.Size() + n += 1 + l + sovQuery(uint64(l)) + } + return n +} + +func (m *QueryGrantsResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.Grants) > 0 { + for _, e := range m.Grants { + l = e.Size() + n += 1 + l + sovQuery(uint64(l)) + } + } + if m.Pagination != nil { + l = m.Pagination.Size() + n += 1 + l + sovQuery(uint64(l)) + } + return n +} + +func sovQuery(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozQuery(x uint64) (n int) { + return sovQuery(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *QueryGrantsRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryGrantsRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryGrantsRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Granter", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Granter = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Grantee", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Grantee = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field MsgTypeUrl", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.MsgTypeUrl = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Pagination", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Pagination == nil { + m.Pagination = &query.PageRequest{} + } + if err := m.Pagination.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryGrantsResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryGrantsResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryGrantsResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Grants", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Grants = append(m.Grants, &Grant{}) + if err := m.Grants[len(m.Grants)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Pagination", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Pagination == nil { + m.Pagination = &query.PageResponse{} + } + if err := m.Pagination.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipQuery(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowQuery + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowQuery + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowQuery + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthQuery + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupQuery + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthQuery + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthQuery = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowQuery = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupQuery = fmt.Errorf("proto: unexpected end of group") +) diff --git a/x/authz/query.pb.gw.go b/x/authz/query.pb.gw.go new file mode 100644 index 0000000000..7f53cb51f7 --- /dev/null +++ b/x/authz/query.pb.gw.go @@ -0,0 +1,166 @@ +// Code generated by protoc-gen-grpc-gateway. DO NOT EDIT. +// source: lbm/authz/v1/query.proto + +/* +Package authz is a reverse proxy. + +It translates gRPC into RESTful JSON APIs. +*/ +package authz + +import ( + "context" + "io" + "net/http" + + "github.com/golang/protobuf/descriptor" + "github.com/golang/protobuf/proto" + "github.com/grpc-ecosystem/grpc-gateway/runtime" + "github.com/grpc-ecosystem/grpc-gateway/utilities" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/grpclog" + "google.golang.org/grpc/status" +) + +// Suppress "imported and not used" errors +var _ codes.Code +var _ io.Reader +var _ status.Status +var _ = runtime.String +var _ = utilities.NewDoubleArray +var _ = descriptor.ForMessage + +var ( + filter_Query_Grants_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)} +) + +func request_Query_Grants_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryGrantsRequest + var metadata runtime.ServerMetadata + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_Grants_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := client.Grants(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_Grants_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryGrantsRequest + var metadata runtime.ServerMetadata + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_Grants_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := server.Grants(ctx, &protoReq) + return msg, metadata, err + +} + +// RegisterQueryHandlerServer registers the http handlers for service Query to "mux". +// UnaryRPC :call QueryServer directly. +// StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906. +// Note that using this registration option will cause many gRPC library features (such as grpc.SendHeader, etc) to stop working. Consider using RegisterQueryHandlerFromEndpoint instead. +func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, server QueryServer) error { + + mux.Handle("GET", pattern_Query_Grants_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_Query_Grants_0(rctx, inboundMarshaler, server, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_Grants_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + return nil +} + +// RegisterQueryHandlerFromEndpoint is same as RegisterQueryHandler but +// automatically dials to "endpoint" and closes the connection when "ctx" gets done. +func RegisterQueryHandlerFromEndpoint(ctx context.Context, mux *runtime.ServeMux, endpoint string, opts []grpc.DialOption) (err error) { + conn, err := grpc.Dial(endpoint, opts...) + if err != nil { + return err + } + defer func() { + if err != nil { + if cerr := conn.Close(); cerr != nil { + grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr) + } + return + } + go func() { + <-ctx.Done() + if cerr := conn.Close(); cerr != nil { + grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr) + } + }() + }() + + return RegisterQueryHandler(ctx, mux, conn) +} + +// RegisterQueryHandler registers the http handlers for service Query to "mux". +// The handlers forward requests to the grpc endpoint over "conn". +func RegisterQueryHandler(ctx context.Context, mux *runtime.ServeMux, conn *grpc.ClientConn) error { + return RegisterQueryHandlerClient(ctx, mux, NewQueryClient(conn)) +} + +// RegisterQueryHandlerClient registers the http handlers for service Query +// to "mux". The handlers forward requests to the grpc endpoint over the given implementation of "QueryClient". +// Note: the gRPC framework executes interceptors within the gRPC handler. If the passed in "QueryClient" +// doesn't go through the normal gRPC flow (creating a gRPC client etc.) then it will be up to the passed in +// "QueryClient" to call the correct interceptors. +func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, client QueryClient) error { + + mux.Handle("GET", pattern_Query_Grants_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_Query_Grants_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_Grants_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + return nil +} + +var ( + pattern_Query_Grants_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"lbm", "authz", "v1", "grants"}, "", runtime.AssumeColonVerbOpt(false))) +) + +var ( + forward_Query_Grants_0 = runtime.ForwardResponseMessage +) diff --git a/x/authz/simulation/decoder.go b/x/authz/simulation/decoder.go new file mode 100644 index 0000000000..7eb40c9b04 --- /dev/null +++ b/x/authz/simulation/decoder.go @@ -0,0 +1,27 @@ +package simulation + +import ( + "bytes" + "fmt" + + "github.com/line/lbm-sdk/codec" + "github.com/line/lbm-sdk/types/kv" + "github.com/line/lbm-sdk/x/authz" + "github.com/line/lbm-sdk/x/authz/keeper" +) + +// NewDecodeStore returns a decoder function closure that umarshals the KVPair's +// Value to the corresponding authz type. +func NewDecodeStore(cdc codec.Codec) func(kvA, kvB kv.Pair) string { + return func(kvA, kvB kv.Pair) string { + switch { + case bytes.Equal(kvA.Key[:1], keeper.GrantKey): + var grantA, grantB authz.Grant + cdc.MustUnmarshal(kvA.Value, &grantA) + cdc.MustUnmarshal(kvB.Value, &grantB) + return fmt.Sprintf("%v\n%v", grantA, grantB) + default: + panic(fmt.Sprintf("invalid authz key %X", kvA.Key)) + } + } +} diff --git a/x/bank/simulation/decoder_test.go b/x/authz/simulation/decoder_test.go similarity index 53% rename from x/bank/simulation/decoder_test.go rename to x/authz/simulation/decoder_test.go index a6ee1f16b3..8236aa7578 100644 --- a/x/bank/simulation/decoder_test.go +++ b/x/authz/simulation/decoder_test.go @@ -3,47 +3,48 @@ package simulation_test import ( "fmt" "testing" + "time" "github.com/stretchr/testify/require" "github.com/line/lbm-sdk/simapp" sdk "github.com/line/lbm-sdk/types" "github.com/line/lbm-sdk/types/kv" - "github.com/line/lbm-sdk/x/bank/simulation" - "github.com/line/lbm-sdk/x/bank/types" + "github.com/line/lbm-sdk/x/authz" + "github.com/line/lbm-sdk/x/authz/keeper" + "github.com/line/lbm-sdk/x/authz/simulation" + banktypes "github.com/line/lbm-sdk/x/bank/types" ) func TestDecodeStore(t *testing.T) { - app := simapp.Setup(false) - dec := simulation.NewDecodeStore(app.BankKeeper) + cdc := simapp.MakeTestEncodingConfig().Marshaler + dec := simulation.NewDecodeStore(cdc) - totalSupply := types.NewSupply(sdk.NewCoins(sdk.NewInt64Coin(sdk.DefaultBondDenom, 1000))) - - supplyBz, err := app.BankKeeper.MarshalSupply(totalSupply) + grant, _ := authz.NewGrant(banktypes.NewSendAuthorization(sdk.NewCoins(sdk.NewInt64Coin("foo", 123))), time.Now().UTC()) + grantBz, err := cdc.Marshal(&grant) require.NoError(t, err) - kvPairs := kv.Pairs{ Pairs: []kv.Pair{ - {Key: types.SupplyKey, Value: supplyBz}, + {Key: []byte(keeper.GrantKey), Value: grantBz}, {Key: []byte{0x99}, Value: []byte{0x99}}, }, } tests := []struct { name string + expectErr bool expectedLog string }{ - {"Supply", fmt.Sprintf("%v\n%v", totalSupply, totalSupply)}, - {"other", ""}, + {"Grant", false, fmt.Sprintf("%v\n%v", grant, grant)}, + {"other", true, ""}, } for i, tt := range tests { i, tt := i, tt t.Run(tt.name, func(t *testing.T) { - switch i { - case len(tests) - 1: + if tt.expectErr { require.Panics(t, func() { dec(kvPairs.Pairs[i], kvPairs.Pairs[i]) }, tt.name) - default: + } else { require.Equal(t, tt.expectedLog, dec(kvPairs.Pairs[i], kvPairs.Pairs[i]), tt.name) } }) diff --git a/x/authz/simulation/genesis.go b/x/authz/simulation/genesis.go new file mode 100644 index 0000000000..e2034764b9 --- /dev/null +++ b/x/authz/simulation/genesis.go @@ -0,0 +1,59 @@ +package simulation + +import ( + "math/rand" + + codectypes "github.com/line/lbm-sdk/codec/types" + sdk "github.com/line/lbm-sdk/types" + "github.com/line/lbm-sdk/types/module" + simtypes "github.com/line/lbm-sdk/types/simulation" + "github.com/line/lbm-sdk/x/authz" + banktypes "github.com/line/lbm-sdk/x/bank/types" + govtypes "github.com/line/lbm-sdk/x/gov/types" +) + +// genGrant returns a slice of authorization grants. +func genGrant(r *rand.Rand, accounts []simtypes.Account) []authz.GrantAuthorization { + authorizations := make([]authz.GrantAuthorization, len(accounts)-1) + for i := 0; i < len(accounts)-1; i++ { + granter := accounts[i] + grantee := accounts[i+1] + authorizations[i] = authz.GrantAuthorization{ + Granter: granter.Address.String(), + Grantee: grantee.Address.String(), + Authorization: generateRandomGrant(r), + } + } + + return authorizations +} + +func generateRandomGrant(r *rand.Rand) *codectypes.Any { + authorizations := make([]*codectypes.Any, 2) + authorizations[0] = newAnyAuthorization(banktypes.NewSendAuthorization(sdk.NewCoins(sdk.NewCoin("stake", sdk.NewInt(1000))))) + authorizations[1] = newAnyAuthorization(authz.NewGenericAuthorization(sdk.MsgTypeURL(&govtypes.MsgSubmitProposal{}))) + + return authorizations[r.Intn(len(authorizations))] +} + +func newAnyAuthorization(a authz.Authorization) *codectypes.Any { + any, err := codectypes.NewAnyWithValue(a) + if err != nil { + panic(err) + } + + return any +} + +// RandomizedGenState generates a random GenesisState for authz. +func RandomizedGenState(simState *module.SimulationState) { + var grants []authz.GrantAuthorization + simState.AppParams.GetOrGenerate( + simState.Cdc, "authz", &grants, simState.Rand, + func(r *rand.Rand) { grants = genGrant(r, simState.Accounts) }, + ) + + authzGrantsGenesis := authz.NewGenesisState(grants) + + simState.GenState[authz.ModuleName] = simState.Cdc.MustMarshalJSON(authzGrantsGenesis) +} diff --git a/x/authz/simulation/genesis_test.go b/x/authz/simulation/genesis_test.go new file mode 100644 index 0000000000..ad6a8a57bc --- /dev/null +++ b/x/authz/simulation/genesis_test.go @@ -0,0 +1,38 @@ +package simulation_test + +import ( + "encoding/json" + "math/rand" + "testing" + + "github.com/stretchr/testify/require" + + "github.com/line/lbm-sdk/simapp" + "github.com/line/lbm-sdk/types/module" + simtypes "github.com/line/lbm-sdk/types/simulation" + "github.com/line/lbm-sdk/x/authz" + "github.com/line/lbm-sdk/x/authz/simulation" +) + +func TestRandomizedGenState(t *testing.T) { + app := simapp.Setup(false) + + s := rand.NewSource(1) + r := rand.New(s) + + simState := module.SimulationState{ + AppParams: make(simtypes.AppParams), + Cdc: app.AppCodec(), + Rand: r, + NumBonded: 3, + Accounts: simtypes.RandomAccounts(r, 3), + InitialStake: 1000, + GenState: make(map[string]json.RawMessage), + } + + simulation.RandomizedGenState(&simState) + var authzGenesis authz.GenesisState + simState.Cdc.MustUnmarshalJSON(simState.GenState[authz.ModuleName], &authzGenesis) + + require.Len(t, authzGenesis.Authorization, len(simState.Accounts)-1) +} diff --git a/x/authz/simulation/operations.go b/x/authz/simulation/operations.go new file mode 100644 index 0000000000..6a62f48d53 --- /dev/null +++ b/x/authz/simulation/operations.go @@ -0,0 +1,296 @@ +package simulation + +import ( + "fmt" + "math/rand" + + "github.com/gogo/protobuf/proto" + + "github.com/line/lbm-sdk/baseapp" + "github.com/line/lbm-sdk/codec" + cdctypes "github.com/line/lbm-sdk/codec/types" + "github.com/line/lbm-sdk/simapp/helpers" + simappparams "github.com/line/lbm-sdk/simapp/params" + sdk "github.com/line/lbm-sdk/types" + sdkerrors "github.com/line/lbm-sdk/types/errors" + simtypes "github.com/line/lbm-sdk/types/simulation" + "github.com/line/lbm-sdk/x/authz" + "github.com/line/lbm-sdk/x/authz/keeper" + banktype "github.com/line/lbm-sdk/x/bank/types" + "github.com/line/lbm-sdk/x/simulation" +) + +// authz message types +var ( + TypeMsgGrant = sdk.MsgTypeURL(&authz.MsgGrant{}) + TypeMsgRevoke = sdk.MsgTypeURL(&authz.MsgRevoke{}) + TypeMsgExec = sdk.MsgTypeURL(&authz.MsgExec{}) +) + +// nolint:gosec +// Simulation operation weights constants +const ( + OpWeightMsgGrant = "op_weight_msg_grant" + OpWeightRevoke = "op_weight_msg_revoke" + OpWeightExec = "op_weight_msg_execute" +) + +// authz operations weights +const ( + WeightGrant = 100 + WeightRevoke = 90 + WeightExec = 90 +) + +// WeightedOperations returns all the operations from the module with their respective weights +func WeightedOperations( + appParams simtypes.AppParams, cdc codec.JSONCodec, ak authz.AccountKeeper, bk authz.BankKeeper, k keeper.Keeper, appCdc cdctypes.AnyUnpacker) simulation.WeightedOperations { + + var ( + weightMsgGrant int + weightRevoke int + weightExec int + ) + + appParams.GetOrGenerate(cdc, OpWeightMsgGrant, &weightMsgGrant, nil, + func(_ *rand.Rand) { + weightMsgGrant = WeightGrant + }, + ) + + appParams.GetOrGenerate(cdc, OpWeightRevoke, &weightRevoke, nil, + func(_ *rand.Rand) { + weightRevoke = WeightRevoke + }, + ) + + appParams.GetOrGenerate(cdc, OpWeightExec, &weightExec, nil, + func(_ *rand.Rand) { + weightExec = WeightExec + }, + ) + + return simulation.WeightedOperations{ + simulation.NewWeightedOperation( + weightMsgGrant, + SimulateMsgGrant(ak, bk, k), + ), + simulation.NewWeightedOperation( + weightRevoke, + SimulateMsgRevoke(ak, bk, k), + ), + simulation.NewWeightedOperation( + weightExec, + SimulateMsgExec(ak, bk, k, appCdc), + ), + } +} + +// SimulateMsgGrant generates a MsgGrant with random values. +func SimulateMsgGrant(ak authz.AccountKeeper, bk authz.BankKeeper, _ keeper.Keeper) simtypes.Operation { + return func( + r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simtypes.Account, chainID string, + ) (simtypes.OperationMsg, []simtypes.FutureOperation, error) { + granter, _ := simtypes.RandomAcc(r, accs) + grantee, _ := simtypes.RandomAcc(r, accs) + + if granter.Address.Equals(grantee.Address) { + return simtypes.NoOpMsg(authz.ModuleName, TypeMsgGrant, "granter and grantee are same"), nil, nil + } + + granterAcc := ak.GetAccount(ctx, granter.Address) + spendableCoins := bk.SpendableCoins(ctx, granter.Address) + fees, err := simtypes.RandomFees(r, ctx, spendableCoins) + if err != nil { + return simtypes.NoOpMsg(authz.ModuleName, TypeMsgGrant, err.Error()), nil, err + } + + spendLimit := spendableCoins.Sub(fees) + if spendLimit == nil { + return simtypes.NoOpMsg(authz.ModuleName, TypeMsgGrant, "spend limit is nil"), nil, nil + } + + expiration := ctx.BlockTime().AddDate(1, 0, 0) + msg, err := authz.NewMsgGrant(granter.Address, grantee.Address, generateRandomAuthorization(r, spendLimit), expiration) + if err != nil { + return simtypes.NoOpMsg(authz.ModuleName, TypeMsgGrant, err.Error()), nil, err + } + txCfg := simappparams.MakeTestEncodingConfig().TxConfig + tx, err := helpers.GenTx( + txCfg, + []sdk.Msg{msg}, + fees, + helpers.DefaultGenTxGas, + chainID, + []uint64{granterAcc.GetAccountNumber()}, + []uint64{granterAcc.GetSequence()}, + granter.PrivKey, + ) + if err != nil { + return simtypes.NoOpMsg(authz.ModuleName, TypeMsgGrant, "unable to generate mock tx"), nil, err + } + + _, _, err = app.Deliver(txCfg.TxEncoder(), tx) + if err != nil { + return simtypes.NoOpMsg(authz.ModuleName, sdk.MsgTypeURL(msg), "unable to deliver tx"), nil, err + } + return simtypes.NewOperationMsg(msg, true, "", nil), nil, err + } +} + +func generateRandomAuthorization(r *rand.Rand, spendLimit sdk.Coins) authz.Authorization { + authorizations := make([]authz.Authorization, 2) + authorizations[0] = banktype.NewSendAuthorization(spendLimit) + authorizations[1] = authz.NewGenericAuthorization(sdk.MsgTypeURL(&banktype.MsgSend{})) + + return authorizations[r.Intn(len(authorizations))] +} + +// SimulateMsgRevoke generates a MsgRevoke with random values. +func SimulateMsgRevoke(ak authz.AccountKeeper, bk authz.BankKeeper, k keeper.Keeper) simtypes.Operation { + return func( + r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simtypes.Account, chainID string, + ) (simtypes.OperationMsg, []simtypes.FutureOperation, error) { + var granterAddr, granteeAddr sdk.AccAddress + var grant authz.Grant + hasGrant := false + + k.IterateGrants(ctx, func(granter, grantee sdk.AccAddress, g authz.Grant) bool { + grant = g + granterAddr = granter + granteeAddr = grantee + hasGrant = true + return true + }) + + if !hasGrant { + return simtypes.NoOpMsg(authz.ModuleName, TypeMsgRevoke, "no grants"), nil, nil + } + + granterAcc, ok := simtypes.FindAccount(accs, granterAddr) + if !ok { + return simtypes.NoOpMsg(authz.ModuleName, TypeMsgRevoke, "account not found"), nil, sdkerrors.Wrapf(sdkerrors.ErrNotFound, "account not found") + } + + spendableCoins := bk.SpendableCoins(ctx, granterAddr) + fees, err := simtypes.RandomFees(r, ctx, spendableCoins) + if err != nil { + return simtypes.NoOpMsg(authz.ModuleName, TypeMsgRevoke, "fee error"), nil, err + } + + a := grant.GetAuthorization() + msg := authz.NewMsgRevoke(granterAddr, granteeAddr, a.MsgTypeURL()) + txCfg := simappparams.MakeTestEncodingConfig().TxConfig + account := ak.GetAccount(ctx, granterAddr) + tx, err := helpers.GenTx( + txCfg, + []sdk.Msg{&msg}, + fees, + helpers.DefaultGenTxGas, + chainID, + []uint64{account.GetAccountNumber()}, + []uint64{account.GetSequence()}, + granterAcc.PrivKey, + ) + if err != nil { + return simtypes.NoOpMsg(authz.ModuleName, TypeMsgRevoke, err.Error()), nil, err + } + + _, _, err = app.Deliver(txCfg.TxEncoder(), tx) + if err != nil { + return simtypes.NoOpMsg(authz.ModuleName, TypeMsgRevoke, "unable to deliver tx"), nil, err + } + + return simtypes.NewOperationMsg(&msg, true, "", nil), nil, nil + } +} + +// SimulateMsgExec generates a MsgExec with random values. +func SimulateMsgExec(ak authz.AccountKeeper, bk authz.BankKeeper, k keeper.Keeper, cdc cdctypes.AnyUnpacker) simtypes.Operation { + return func( + r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simtypes.Account, chainID string, + ) (simtypes.OperationMsg, []simtypes.FutureOperation, error) { + hasGrant := false + var targetGrant authz.Grant + var granterAddr sdk.AccAddress + var granteeAddr sdk.AccAddress + k.IterateGrants(ctx, func(granter, grantee sdk.AccAddress, grant authz.Grant) bool { + targetGrant = grant + granterAddr = granter + granteeAddr = grantee + hasGrant = true + return true + }) + + if !hasGrant { + return simtypes.NoOpMsg(authz.ModuleName, TypeMsgExec, "no grant found"), nil, nil + } + + grantee, ok := simtypes.FindAccount(accs, granteeAddr) + if !ok { + return simtypes.NoOpMsg(authz.ModuleName, TypeMsgRevoke, "Account not found"), nil, sdkerrors.Wrapf(sdkerrors.ErrNotFound, "grantee account not found") + } + + if _, ok := simtypes.FindAccount(accs, granterAddr); !ok { + return simtypes.NoOpMsg(authz.ModuleName, TypeMsgRevoke, "Account not found"), nil, sdkerrors.Wrapf(sdkerrors.ErrNotFound, "granter account not found") + } + + if targetGrant.Expiration.Before(ctx.BlockHeader().Time) { + return simtypes.NoOpMsg(authz.ModuleName, TypeMsgExec, "grant expired"), nil, nil + } + + coins := sdk.NewCoins(sdk.NewCoin("stake", sdk.NewInt(int64(simtypes.RandIntBetween(r, 100, 1000000))))) + + // Check send_enabled status of each sent coin denom + if err := bk.IsSendEnabledCoins(ctx, coins...); err != nil { + return simtypes.NoOpMsg(authz.ModuleName, TypeMsgExec, err.Error()), nil, nil + } + + if targetGrant.Authorization.TypeUrl == fmt.Sprintf("/%s", proto.MessageName(&banktype.SendAuthorization{})) { + sendAuthorization := targetGrant.GetAuthorization().(*banktype.SendAuthorization) + if sendAuthorization.SpendLimit.IsAllLT(coins) { + return simtypes.NoOpMsg(authz.ModuleName, TypeMsgExec, "over spend limit"), nil, nil + } + } + + granterspendableCoins := bk.SpendableCoins(ctx, granterAddr) + if granterspendableCoins.IsAllLTE(coins) { + return simtypes.NoOpMsg(authz.ModuleName, TypeMsgExec, "insufficient funds"), nil, nil + } + + granteeSpendableCoins := bk.SpendableCoins(ctx, granteeAddr) + fees, err := simtypes.RandomFees(r, ctx, granteeSpendableCoins) + if err != nil { + return simtypes.NoOpMsg(authz.ModuleName, TypeMsgExec, "fee error"), nil, err + } + + msg := authz.NewMsgExec(granteeAddr, []sdk.Msg{banktype.NewMsgSend(granterAddr, granteeAddr, coins)}) + txCfg := simappparams.MakeTestEncodingConfig().TxConfig + granteeAcc := ak.GetAccount(ctx, granteeAddr) + + tx, err := helpers.GenTx( + txCfg, + []sdk.Msg{&msg}, + fees, + helpers.DefaultGenTxGas, + chainID, + []uint64{granteeAcc.GetAccountNumber()}, + []uint64{granteeAcc.GetSequence()}, + grantee.PrivKey, + ) + if err != nil { + return simtypes.NoOpMsg(authz.ModuleName, TypeMsgExec, err.Error()), nil, err + } + + _, _, err = app.Deliver(txCfg.TxEncoder(), tx) + if err != nil { + return simtypes.NoOpMsg(authz.ModuleName, TypeMsgExec, err.Error()), nil, err + } + + err = msg.UnpackInterfaces(cdc) + if err != nil { + return simtypes.NoOpMsg(authz.ModuleName, TypeMsgExec, "unmarshal error"), nil, err + } + return simtypes.NewOperationMsg(&msg, true, "success", nil), nil, nil + } +} diff --git a/x/authz/simulation/operations_test.go b/x/authz/simulation/operations_test.go new file mode 100644 index 0000000000..d2c8d7d602 --- /dev/null +++ b/x/authz/simulation/operations_test.go @@ -0,0 +1,192 @@ +package simulation_test + +import ( + "math/rand" + "testing" + "time" + + "github.com/stretchr/testify/suite" + + abci "github.com/line/ostracon/abci/types" + ocproto "github.com/line/ostracon/proto/ostracon/types" + + "github.com/line/lbm-sdk/simapp" + sdk "github.com/line/lbm-sdk/types" + simtypes "github.com/line/lbm-sdk/types/simulation" + "github.com/line/lbm-sdk/x/authz" + "github.com/line/lbm-sdk/x/authz/simulation" + banktypes "github.com/line/lbm-sdk/x/bank/types" +) + +type SimTestSuite struct { + suite.Suite + + ctx sdk.Context + app *simapp.SimApp +} + +func (suite *SimTestSuite) SetupTest() { + checkTx := false + app := simapp.Setup(checkTx) + suite.app = app + suite.ctx = app.BaseApp.NewContext(checkTx, ocproto.Header{}) +} + +func (suite *SimTestSuite) TestWeightedOperations() { + cdc := suite.app.AppCodec() + appParams := make(simtypes.AppParams) + + weightedOps := simulation.WeightedOperations(appParams, cdc, suite.app.AccountKeeper, + suite.app.BankKeeper, suite.app.AuthzKeeper, cdc, + ) + + // setup 3 accounts + s := rand.NewSource(1) + r := rand.New(s) + accs := suite.getTestingAccounts(r, 3) + + expected := []struct { + weight int + opMsgRoute string + opMsgName string + }{ + {simulation.WeightGrant, authz.ModuleName, simulation.TypeMsgGrant}, + {simulation.WeightRevoke, authz.ModuleName, simulation.TypeMsgRevoke}, + {simulation.WeightExec, authz.ModuleName, simulation.TypeMsgExec}, + } + + for i, w := range weightedOps { + operationMsg, _, _ := w.Op()(r, suite.app.BaseApp, suite.ctx, accs, "") + // the following checks are very much dependent from the ordering of the output given + // by WeightedOperations. if the ordering in WeightedOperations changes some tests + // will fail + suite.Require().Equal(expected[i].weight, w.Weight(), "weight should be the same") + suite.Require().Equal(expected[i].opMsgRoute, operationMsg.Route, "route should be the same") + suite.Require().Equal(expected[i].opMsgName, operationMsg.Name, "operation Msg name should be the same") + } +} + +func (suite *SimTestSuite) getTestingAccounts(r *rand.Rand, n int) []simtypes.Account { + accounts := simtypes.RandomAccounts(r, n) + + initAmt := suite.app.StakingKeeper.TokensFromConsensusPower(suite.ctx, 200000) + initCoins := sdk.NewCoins(sdk.NewCoin("stake", initAmt)) + + // add coins to the accounts + for _, account := range accounts { + acc := suite.app.AccountKeeper.NewAccountWithAddress(suite.ctx, account.Address) + suite.app.AccountKeeper.SetAccount(suite.ctx, acc) + suite.Require().NoError(simapp.FundAccount(suite.app, suite.ctx, account.Address, initCoins)) + } + + return accounts +} + +func (suite *SimTestSuite) TestSimulateGrant() { + s := rand.NewSource(1) + r := rand.New(s) + accounts := suite.getTestingAccounts(r, 2) + blockTime := time.Now().UTC() + ctx := suite.ctx.WithBlockTime(blockTime) + + // begin a new block + suite.app.BeginBlock(abci.RequestBeginBlock{ + Header: ocproto.Header{ + Height: suite.app.LastBlockHeight() + 1, + AppHash: suite.app.LastCommitID().Hash, + }, + }) + + granter := accounts[0] + grantee := accounts[1] + + // execute operation + op := simulation.SimulateMsgGrant(suite.app.AccountKeeper, suite.app.BankKeeper, suite.app.AuthzKeeper) + operationMsg, futureOperations, err := op(r, suite.app.BaseApp, ctx, accounts, "") + suite.Require().NoError(err) + + var msg authz.MsgGrant + suite.app.AppCodec().UnmarshalJSON(operationMsg.Msg, &msg) + suite.Require().True(operationMsg.OK) + suite.Require().Equal(granter.Address.String(), msg.Granter) + suite.Require().Equal(grantee.Address.String(), msg.Grantee) + suite.Require().Len(futureOperations, 0) + +} + +func (suite *SimTestSuite) TestSimulateRevoke() { + // setup 3 accounts + s := rand.NewSource(2) + r := rand.New(s) + accounts := suite.getTestingAccounts(r, 3) + + // begin a new block + suite.app.BeginBlock(abci.RequestBeginBlock{ + Header: ocproto.Header{ + Height: suite.app.LastBlockHeight() + 1, + AppHash: suite.app.LastCommitID().Hash, + }}) + + initAmt := suite.app.StakingKeeper.TokensFromConsensusPower(suite.ctx, 200000) + initCoins := sdk.NewCoins(sdk.NewCoin("stake", initAmt)) + + granter := accounts[0] + grantee := accounts[1] + authorization := banktypes.NewSendAuthorization(initCoins) + + err := suite.app.AuthzKeeper.SaveGrant(suite.ctx, grantee.Address, granter.Address, authorization, time.Now().Add(30*time.Hour)) + suite.Require().NoError(err) + + // execute operation + op := simulation.SimulateMsgRevoke(suite.app.AccountKeeper, suite.app.BankKeeper, suite.app.AuthzKeeper) + operationMsg, futureOperations, err := op(r, suite.app.BaseApp, suite.ctx, accounts, "") + suite.Require().NoError(err) + + var msg authz.MsgRevoke + suite.app.AppCodec().UnmarshalJSON(operationMsg.Msg, &msg) + + suite.Require().True(operationMsg.OK) + suite.Require().Equal(granter.Address.String(), msg.Granter) + suite.Require().Equal(grantee.Address.String(), msg.Grantee) + suite.Require().Equal(banktypes.SendAuthorization{}.MsgTypeURL(), msg.MsgTypeUrl) + suite.Require().Len(futureOperations, 0) + +} + +func (suite *SimTestSuite) TestSimulateExec() { + // setup 3 accounts + s := rand.NewSource(1) + r := rand.New(s) + accounts := suite.getTestingAccounts(r, 3) + + // begin a new block + suite.app.BeginBlock(abci.RequestBeginBlock{Header: ocproto.Header{Height: suite.app.LastBlockHeight() + 1, AppHash: suite.app.LastCommitID().Hash}}) + + initAmt := suite.app.StakingKeeper.TokensFromConsensusPower(suite.ctx, 200000) + initCoins := sdk.NewCoins(sdk.NewCoin("stake", initAmt)) + + granter := accounts[0] + grantee := accounts[1] + authorization := banktypes.NewSendAuthorization(initCoins) + + err := suite.app.AuthzKeeper.SaveGrant(suite.ctx, grantee.Address, granter.Address, authorization, time.Now().Add(30*time.Hour)) + suite.Require().NoError(err) + + // execute operation + op := simulation.SimulateMsgExec(suite.app.AccountKeeper, suite.app.BankKeeper, suite.app.AuthzKeeper, suite.app.AppCodec()) + operationMsg, futureOperations, err := op(r, suite.app.BaseApp, suite.ctx, accounts, "") + suite.Require().NoError(err) + + var msg authz.MsgExec + + suite.app.AppCodec().UnmarshalJSON(operationMsg.Msg, &msg) + + suite.Require().True(operationMsg.OK) + suite.Require().Equal(grantee.Address.String(), msg.Grantee) + suite.Require().Len(futureOperations, 0) + +} + +func TestSimTestSuite(t *testing.T) { + suite.Run(t, new(SimTestSuite)) +} diff --git a/x/authz/spec/01_concepts.md b/x/authz/spec/01_concepts.md new file mode 100644 index 0000000000..1aeb68650d --- /dev/null +++ b/x/authz/spec/01_concepts.md @@ -0,0 +1,43 @@ + + +# Concepts + +## Authorization and Grant + +`x/authz` module defines interfaces and messages grant authorizations to perform actions +on behalf of one account to other accounts. The design is defined in the [ADR 030](../../../architecture/adr-030-authz-module.md). + +Grant is an allowance to execute a Msg by the grantee on behalf of the granter. +Authorization is an interface which must be implemented by a concrete authorization logic to validate and execute grants. They are extensible and can be defined for any Msg service method even outside of the module where the Msg method is defined. See the `SendAuthorization` example in the next section for more details. + ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.43.0-beta1/x/authz/authorizations.go#L11-L25 + +## Built-in Authorizations + +Cosmos-SDK `x/authz` module comes with following authorization types + +### SendAuthorization + +`SendAuthorization` implements the `Authorization` interface for the `cosmos.bank.v1beta1.MsgSend` Msg. It takes a `SpendLimit` that specifies the maximum amount of tokens the grantee can spend, which is updated as the tokens are spent. + ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.43.0-beta1/proto/cosmos/bank/v1beta1/authz.proto#L10-L19 + ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.43.0-beta1/x/bank/types/send_authorization.go#L25-L40 + +- `spent_limit` keeps track of how many coins are left in the authorization. + +### GenericAuthorization + +`GenericAuthorization` implements the `Authorization` interface, that gives unrestricted permission to execute the provided Msg on behalf of granter's account. + ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.43.0-beta1/proto/cosmos/authz/v1beta1/authz.proto#L14-L19 + ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.43.0-beta1/x/authz/generic_authorization.go#L18-L31 + +- `msg` stores Msg type URL. + +## Gas + +In order to prevent DoS attacks, granting `StakeAuthorizaiton`s with `x/authz` incur gas. `StakeAuthorizaiton` allows you to authorize another account to delegate, undelegate, or redelegate to validators. The authorizer can define a list of validators they will allow and/or deny delegations to. The SDK will iterate over these lists and charge 10 gas for each validator in both of the lists. diff --git a/x/authz/spec/02_state.md b/x/authz/spec/02_state.md new file mode 100644 index 0000000000..5b07f645a1 --- /dev/null +++ b/x/authz/spec/02_state.md @@ -0,0 +1,15 @@ + + +# State + +## Grant + +Grants are identified by combining granter address (the address bytes of the granter), grantee address (the address bytes of the grantee) and Authorization type (its type URL). Hence we only allow one grant for the (granter, grantee, Authorization) triple. + +- Grant: `0x01 | granter_address_len (1 byte) | granter_address_bytes | grantee_address_len (1 byte) | grantee_address_bytes | msgType_bytes-> ProtocolBuffer(AuthorizationGrant)` + +The grant object encapsulates an `Authorization` type and an expiration timestamp: + ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.43.0-beta1/proto/cosmos/authz/v1beta1/authz.proto#L21-L26 diff --git a/x/authz/spec/03_messages.md b/x/authz/spec/03_messages.md new file mode 100644 index 0000000000..736c5761b9 --- /dev/null +++ b/x/authz/spec/03_messages.md @@ -0,0 +1,46 @@ + + +# Messages + +In this section we describe the processing of messages for the authz module. + +## MsgGrant + +An authorization grant is created using the `MsgGrant` message. +If there is already a grant for the `(granter, grantee, Authorization)` triple, then the new grant will overwrite the previous one. To update or extend an existing grant, a new grant with the same `(granter, grantee, Authorization)` triple should be created. + ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.43.0-beta1/proto/cosmos/authz/v1beta1/tx.proto#L32-L37 + +The message handling should fail if: + +- both granter and grantee have the same address. +- provided `Expiration` time is less than current unix timestamp. +- provided `Grant.Authorization` is not implemented. +- `Authorization.MsgTypeURL()` is not defined in the router (there is no defined handler in the app router to handle that Msg types). + +## MsgRevoke + +A grant can be removed with the `MsgRevoke` message. + ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.43.0-beta1/proto/cosmos/authz/v1beta1/tx.proto#L60-L64 + +The message handling should fail if: + +- both granter and grantee have the same address. +- provided `MsgTypeUrl` is empty. + +NOTE: The `MsgExec` message removes a grant if the grant has expired. + +## MsgExec + +When a grantee wants to execute a transaction on behalf of a granter, they must send `MsgExec`. + ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.43.0-beta1/proto/cosmos/authz/v1beta1/tx.proto#L47-L53 + +The message handling should fail if: + +- provided `Authorization` is not implemented. +- grantee doesn't have permission to run the transaction. +- if granted authorization is expired. diff --git a/x/authz/spec/04_events.md b/x/authz/spec/04_events.md new file mode 100644 index 0000000000..18b71db3c4 --- /dev/null +++ b/x/authz/spec/04_events.md @@ -0,0 +1,7 @@ + + +# Events + +The authz module emits proto events defined in [the Protobuf reference](../../../docs/core/proto-docs.md#cosmos/authz/v1beta1/event.proto). diff --git a/x/authz/spec/05_client.md b/x/authz/spec/05_client.md new file mode 100644 index 0000000000..f2ca6cc946 --- /dev/null +++ b/x/authz/spec/05_client.md @@ -0,0 +1,172 @@ + + +# Client + +## CLI + +A user can query and interact with the `authz` module using the CLI. + +### Query + +The `query` commands allow users to query `authz` state. + +```bash +simd query authz --help +``` + +#### grants + +The `grants` command allows users to query grants for a granter-grantee pair. If the message type URL is set, it selects grants only for that message type. + +```bash +simd query authz grants [granter-addr] [grantee-addr] [msg-type-url]? [flags] +``` + +Example: + +```bash +simd query authz grants cosmos1.. cosmos1.. /cosmos.bank.v1beta1.MsgSend +``` + +Example Output: + +```bash +grants: +- authorization: + '@type': /cosmos.bank.v1beta1.SendAuthorization + spend_limit: + - amount: "100" + denom: stake + expiration: "2022-01-01T00:00:00Z" +pagination: null +``` + +### Transactions + +The `tx` commands allow users to interact with the `authz` module. + +```bash +simd tx authz --help +``` + +#### exec + +The `exec` command allows a grantee to execute a transaction on behalf of granter. + +```bash + simd tx authz exec [tx-json-file] --from [grantee] [flags] +``` + +Example: + +```bash +simd tx authz exec tx.json --from=cosmos1.. +``` + +#### grant + +The `grant` command allows a granter to grant an authorization to a grantee. + +```bash +simd tx authz grant --from [flags] +``` + +Example: + +```bash +simd tx authz grant cosmos1.. send --spend-limit=100stake --from=cosmos1.. +``` + +#### revoke + +The `revoke` command allows a granter to revoke an authorization from a grantee. + +```bash +simd tx authz revoke [grantee] [msg-type-url] --from=[granter] [flags] +``` + +Example: + +```bash +simd tx authz revoke cosmos1.. /cosmos.bank.v1beta1.MsgSend --from=cosmos1.. +``` + +## gRPC + +A user can query the `authz` module using gRPC endpoints. + +### Grants + +The `Grants` endpoint allows users to query grants for a granter-grantee pair. If the message type URL is set, it selects grants only for that message type. + +```bash +cosmos.authz.v1beta1.Query/Grants +``` + +Example: + +```bash +grpcurl -plaintext \ + -d '{"granter":"cosmos1..","grantee":"cosmos1..","msg_type_url":"/cosmos.bank.v1beta1.MsgSend"}' \ + localhost:9090 \ + cosmos.authz.v1beta1.Query/Grants +``` + +Example Output: + +```bash +{ + "grants": [ + { + "authorization": { + "@type": "/cosmos.bank.v1beta1.SendAuthorization", + "spendLimit": [ + { + "denom":"stake", + "amount":"100" + } + ] + }, + "expiration": "2022-01-01T00:00:00Z" + } + ] +} +``` + +## REST + +A user can query the `authz` module using REST endpoints. + +```bash +/cosmos/authz/v1beta1/grants +``` + +Example: + +```bash +curl "localhost:1317/cosmos/authz/v1beta1/grants?granter=cosmos1..&grantee=cosmos1..&msg_type_url=/cosmos.bank.v1beta1.MsgSend" +``` + +Example Output: + +```bash +{ + "grants": [ + { + "authorization": { + "@type": "/cosmos.bank.v1beta1.SendAuthorization", + "spend_limit": [ + { + "denom": "stake", + "amount": "100" + } + ] + }, + "expiration": "2022-01-01T00:00:00Z" + } + ], + "pagination": null +} +``` diff --git a/x/authz/spec/README.md b/x/authz/spec/README.md new file mode 100644 index 0000000000..814d474f6e --- /dev/null +++ b/x/authz/spec/README.md @@ -0,0 +1,27 @@ + + +# `authz` + +## Contents + +## Abstract + +`x/authz` is an implementation of a Cosmos SDK module, per [ADR 30](../../../architecture/adr-030-authz-module.md), that allows +granting arbitrary privileges from one account (the granter) to another account (the grantee). Authorizations must be granted for a particular Msg service method one by one using an implementation of the `Authorization` interface. + +1. **[Concept](01_concepts.md)** + - [Authorization](01_concepts.md#Authorization) + - [Built-in Authorizations](01_concepts.md#Built-in-Authorization) + - [Gas](01_concepts.md#gas) +2. **[State](02_state.md)** +3. **[Messages](03_messages.md)** + - [MsgGrant](03_messages.md#MsgGrant) + - [MsgRevoke](03_messages.md#MsgRevoke) + - [MsgExec](03_messages.md#MsgExec) +4. **[Events](04_events.md)** + - [Keeper](04_events.md#Keeper) diff --git a/x/authz/tx.pb.go b/x/authz/tx.pb.go new file mode 100644 index 0000000000..438eb1c5ea --- /dev/null +++ b/x/authz/tx.pb.go @@ -0,0 +1,1484 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: lbm/authz/v1/tx.proto + +package authz + +import ( + context "context" + fmt "fmt" + _ "github.com/gogo/protobuf/gogoproto" + grpc1 "github.com/gogo/protobuf/grpc" + proto "github.com/gogo/protobuf/proto" + types "github.com/line/lbm-sdk/codec/types" + _ "github.com/line/lbm-sdk/types" + _ "github.com/regen-network/cosmos-proto" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" + _ "google.golang.org/protobuf/types/known/timestamppb" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +// MsgGrant is a request type for Grant method. It declares authorization to the grantee +// on behalf of the granter with the provided expiration time. +type MsgGrant struct { + Granter string `protobuf:"bytes,1,opt,name=granter,proto3" json:"granter,omitempty"` + Grantee string `protobuf:"bytes,2,opt,name=grantee,proto3" json:"grantee,omitempty"` + Grant Grant `protobuf:"bytes,3,opt,name=grant,proto3" json:"grant"` +} + +func (m *MsgGrant) Reset() { *m = MsgGrant{} } +func (m *MsgGrant) String() string { return proto.CompactTextString(m) } +func (*MsgGrant) ProtoMessage() {} +func (*MsgGrant) Descriptor() ([]byte, []int) { + return fileDescriptor_f5f8e91568683e1f, []int{0} +} +func (m *MsgGrant) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgGrant) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgGrant.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgGrant) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgGrant.Merge(m, src) +} +func (m *MsgGrant) XXX_Size() int { + return m.Size() +} +func (m *MsgGrant) XXX_DiscardUnknown() { + xxx_messageInfo_MsgGrant.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgGrant proto.InternalMessageInfo + +// MsgExecResponse defines the Msg/MsgExecResponse response type. +type MsgExecResponse struct { + Results [][]byte `protobuf:"bytes,1,rep,name=results,proto3" json:"results,omitempty"` +} + +func (m *MsgExecResponse) Reset() { *m = MsgExecResponse{} } +func (m *MsgExecResponse) String() string { return proto.CompactTextString(m) } +func (*MsgExecResponse) ProtoMessage() {} +func (*MsgExecResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_f5f8e91568683e1f, []int{1} +} +func (m *MsgExecResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgExecResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgExecResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgExecResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgExecResponse.Merge(m, src) +} +func (m *MsgExecResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgExecResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgExecResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgExecResponse proto.InternalMessageInfo + +// MsgExec attempts to execute the provided messages using +// authorizations granted to the grantee. Each message should have only +// one signer corresponding to the granter of the authorization. +type MsgExec struct { + Grantee string `protobuf:"bytes,1,opt,name=grantee,proto3" json:"grantee,omitempty"` + // Authorization Msg requests to execute. Each msg must implement Authorization interface + // The x/authz will try to find a grant matching (msg.signers[0], grantee, MsgTypeURL(msg)) + // triple and validate it. + Msgs []*types.Any `protobuf:"bytes,2,rep,name=msgs,proto3" json:"msgs,omitempty"` +} + +func (m *MsgExec) Reset() { *m = MsgExec{} } +func (m *MsgExec) String() string { return proto.CompactTextString(m) } +func (*MsgExec) ProtoMessage() {} +func (*MsgExec) Descriptor() ([]byte, []int) { + return fileDescriptor_f5f8e91568683e1f, []int{2} +} +func (m *MsgExec) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgExec) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgExec.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgExec) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgExec.Merge(m, src) +} +func (m *MsgExec) XXX_Size() int { + return m.Size() +} +func (m *MsgExec) XXX_DiscardUnknown() { + xxx_messageInfo_MsgExec.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgExec proto.InternalMessageInfo + +// MsgGrantResponse defines the Msg/MsgGrant response type. +type MsgGrantResponse struct { +} + +func (m *MsgGrantResponse) Reset() { *m = MsgGrantResponse{} } +func (m *MsgGrantResponse) String() string { return proto.CompactTextString(m) } +func (*MsgGrantResponse) ProtoMessage() {} +func (*MsgGrantResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_f5f8e91568683e1f, []int{3} +} +func (m *MsgGrantResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgGrantResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgGrantResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgGrantResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgGrantResponse.Merge(m, src) +} +func (m *MsgGrantResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgGrantResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgGrantResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgGrantResponse proto.InternalMessageInfo + +// MsgRevoke revokes any authorization with the provided sdk.Msg type on the +// granter's account with that has been granted to the grantee. +type MsgRevoke struct { + Granter string `protobuf:"bytes,1,opt,name=granter,proto3" json:"granter,omitempty"` + Grantee string `protobuf:"bytes,2,opt,name=grantee,proto3" json:"grantee,omitempty"` + MsgTypeUrl string `protobuf:"bytes,3,opt,name=msg_type_url,json=msgTypeUrl,proto3" json:"msg_type_url,omitempty"` +} + +func (m *MsgRevoke) Reset() { *m = MsgRevoke{} } +func (m *MsgRevoke) String() string { return proto.CompactTextString(m) } +func (*MsgRevoke) ProtoMessage() {} +func (*MsgRevoke) Descriptor() ([]byte, []int) { + return fileDescriptor_f5f8e91568683e1f, []int{4} +} +func (m *MsgRevoke) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgRevoke) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgRevoke.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgRevoke) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgRevoke.Merge(m, src) +} +func (m *MsgRevoke) XXX_Size() int { + return m.Size() +} +func (m *MsgRevoke) XXX_DiscardUnknown() { + xxx_messageInfo_MsgRevoke.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgRevoke proto.InternalMessageInfo + +// MsgRevokeResponse defines the Msg/MsgRevokeResponse response type. +type MsgRevokeResponse struct { +} + +func (m *MsgRevokeResponse) Reset() { *m = MsgRevokeResponse{} } +func (m *MsgRevokeResponse) String() string { return proto.CompactTextString(m) } +func (*MsgRevokeResponse) ProtoMessage() {} +func (*MsgRevokeResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_f5f8e91568683e1f, []int{5} +} +func (m *MsgRevokeResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgRevokeResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgRevokeResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgRevokeResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgRevokeResponse.Merge(m, src) +} +func (m *MsgRevokeResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgRevokeResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgRevokeResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgRevokeResponse proto.InternalMessageInfo + +func init() { + proto.RegisterType((*MsgGrant)(nil), "lbm.authz.v1.MsgGrant") + proto.RegisterType((*MsgExecResponse)(nil), "lbm.authz.v1.MsgExecResponse") + proto.RegisterType((*MsgExec)(nil), "lbm.authz.v1.MsgExec") + proto.RegisterType((*MsgGrantResponse)(nil), "lbm.authz.v1.MsgGrantResponse") + proto.RegisterType((*MsgRevoke)(nil), "lbm.authz.v1.MsgRevoke") + proto.RegisterType((*MsgRevokeResponse)(nil), "lbm.authz.v1.MsgRevokeResponse") +} + +func init() { proto.RegisterFile("lbm/authz/v1/tx.proto", fileDescriptor_f5f8e91568683e1f) } + +var fileDescriptor_f5f8e91568683e1f = []byte{ + // 480 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x52, 0xc1, 0x6e, 0xd3, 0x40, + 0x14, 0xb4, 0x9b, 0xb4, 0x25, 0xdb, 0x48, 0x80, 0xdb, 0x82, 0x6b, 0xc0, 0xb1, 0x7c, 0x8a, 0x04, + 0xdd, 0x55, 0xc3, 0x15, 0x84, 0x1a, 0x09, 0x21, 0x21, 0xf9, 0x62, 0xc1, 0x85, 0x4b, 0x64, 0xa7, + 0xcb, 0xc6, 0x8a, 0xd7, 0x6b, 0xf9, 0xad, 0xa3, 0xa4, 0x5f, 0xc1, 0xc7, 0xf0, 0x11, 0x11, 0xa7, + 0x1e, 0x39, 0x21, 0x48, 0x7e, 0x04, 0x79, 0xd7, 0x0e, 0x09, 0x2d, 0x17, 0x4e, 0x7e, 0x6f, 0x66, + 0x3c, 0x3b, 0x9e, 0x35, 0x3a, 0x4d, 0x63, 0x4e, 0xa2, 0x52, 0x4e, 0xae, 0xc9, 0xec, 0x82, 0xc8, + 0x39, 0xce, 0x0b, 0x21, 0x85, 0xd5, 0x4d, 0x63, 0x8e, 0x15, 0x8c, 0x67, 0x17, 0xce, 0xd9, 0x58, + 0x00, 0x17, 0x30, 0x52, 0x1c, 0xd1, 0x8b, 0x16, 0x3a, 0x27, 0x4c, 0x30, 0xa1, 0xf1, 0x6a, 0xaa, + 0xd1, 0x1e, 0x13, 0x82, 0xa5, 0x94, 0xa8, 0x2d, 0x2e, 0x3f, 0x13, 0x99, 0x70, 0x0a, 0x32, 0xe2, + 0x79, 0x2d, 0x38, 0xfb, 0x5b, 0x10, 0x65, 0x8b, 0x9a, 0x7a, 0x52, 0x25, 0x8a, 0x23, 0xa0, 0x24, + 0x8a, 0xc7, 0x49, 0x95, 0xaa, 0x7a, 0xd6, 0xa4, 0xbd, 0x13, 0x57, 0x07, 0x54, 0x8c, 0x2f, 0xd0, + 0xbd, 0x00, 0xd8, 0xbb, 0x22, 0xca, 0xa4, 0x65, 0xa3, 0x43, 0x56, 0x0d, 0xb4, 0xb0, 0x4d, 0xcf, + 0xec, 0x77, 0xc2, 0x66, 0xfd, 0xc3, 0x50, 0x7b, 0x6f, 0x9b, 0xa1, 0x16, 0x41, 0xfb, 0x6a, 0xb4, + 0x5b, 0x9e, 0xd9, 0x3f, 0x1a, 0x1c, 0xe3, 0xed, 0x06, 0xb0, 0xf2, 0x1d, 0xb6, 0x97, 0x3f, 0x7a, + 0x46, 0xa8, 0x75, 0xfe, 0x73, 0x74, 0x3f, 0x00, 0xf6, 0x76, 0x4e, 0xc7, 0x21, 0x85, 0x5c, 0x64, + 0x40, 0x2b, 0xf7, 0x82, 0x42, 0x99, 0x4a, 0xb0, 0x4d, 0xaf, 0xd5, 0xef, 0x86, 0xcd, 0xea, 0x0b, + 0x74, 0x58, 0x8b, 0xb7, 0x23, 0x98, 0xbb, 0x11, 0xde, 0xa3, 0x36, 0x07, 0x06, 0xf6, 0x9e, 0xd7, + 0xea, 0x1f, 0x0d, 0x4e, 0xb0, 0xee, 0x08, 0x37, 0x1d, 0xe1, 0xcb, 0x6c, 0x31, 0xf4, 0xbe, 0x7d, + 0x3d, 0x7f, 0x0a, 0x57, 0x53, 0x1c, 0x00, 0x7b, 0xe1, 0xe9, 0x7c, 0x97, 0xa5, 0x9c, 0x88, 0x22, + 0xb9, 0x8e, 0x64, 0x22, 0xb2, 0x50, 0x79, 0xf8, 0x16, 0x7a, 0xd0, 0xd4, 0xd1, 0xc4, 0xf3, 0x23, + 0xd4, 0x09, 0x80, 0x85, 0x74, 0x26, 0xa6, 0xf4, 0xbf, 0x3a, 0xf2, 0x50, 0x97, 0x03, 0x1b, 0xc9, + 0x45, 0x4e, 0x47, 0x65, 0x91, 0xaa, 0xaa, 0x3a, 0x21, 0xe2, 0xc0, 0x3e, 0x2c, 0x72, 0xfa, 0xb1, + 0x48, 0xfd, 0x63, 0xf4, 0x70, 0x73, 0x44, 0x73, 0xee, 0x60, 0x69, 0xa2, 0x56, 0x00, 0xcc, 0x7a, + 0x83, 0xf6, 0xf5, 0xfd, 0x3c, 0xda, 0x2d, 0xb7, 0x09, 0xea, 0xb8, 0x77, 0xe3, 0x9b, 0x7e, 0x5f, + 0xa1, 0xb6, 0xaa, 0xf0, 0xf4, 0x96, 0xae, 0x82, 0x9d, 0x67, 0x77, 0xc2, 0x9b, 0xb7, 0x87, 0xe8, + 0xa0, 0xfe, 0xf6, 0xc7, 0xb7, 0x84, 0x9a, 0x70, 0x7a, 0xff, 0x20, 0x1a, 0x8f, 0xe1, 0xeb, 0xe5, + 0x2f, 0xd7, 0x58, 0xae, 0x5c, 0xf3, 0x66, 0xe5, 0x9a, 0x3f, 0x57, 0xae, 0xf9, 0x65, 0xed, 0x1a, + 0x37, 0x6b, 0xd7, 0xf8, 0xbe, 0x76, 0x8d, 0x4f, 0x3d, 0x96, 0xc8, 0x49, 0x19, 0xe3, 0xb1, 0xe0, + 0x24, 0x4d, 0x32, 0x4a, 0xd2, 0x98, 0x9f, 0xc3, 0xd5, 0x94, 0xcc, 0xf5, 0xaf, 0x1a, 0x1f, 0xa8, + 0xbb, 0x7c, 0xf9, 0x3b, 0x00, 0x00, 0xff, 0xff, 0xc5, 0x04, 0x46, 0xfd, 0x76, 0x03, 0x00, 0x00, +} + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ grpc.ClientConn + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +const _ = grpc.SupportPackageIsVersion4 + +// MsgClient is the client API for Msg service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. +type MsgClient interface { + // Grant grants the provided authorization to the grantee on the granter's + // account with the provided expiration time. If there is already a grant + // for the given (granter, grantee, Authorization) triple, then the grant + // will be overwritten. + Grant(ctx context.Context, in *MsgGrant, opts ...grpc.CallOption) (*MsgGrantResponse, error) + // Exec attempts to execute the provided messages using + // authorizations granted to the grantee. Each message should have only + // one signer corresponding to the granter of the authorization. + Exec(ctx context.Context, in *MsgExec, opts ...grpc.CallOption) (*MsgExecResponse, error) + // Revoke revokes any authorization corresponding to the provided method name on the + // granter's account that has been granted to the grantee. + Revoke(ctx context.Context, in *MsgRevoke, opts ...grpc.CallOption) (*MsgRevokeResponse, error) +} + +type msgClient struct { + cc grpc1.ClientConn +} + +func NewMsgClient(cc grpc1.ClientConn) MsgClient { + return &msgClient{cc} +} + +func (c *msgClient) Grant(ctx context.Context, in *MsgGrant, opts ...grpc.CallOption) (*MsgGrantResponse, error) { + out := new(MsgGrantResponse) + err := c.cc.Invoke(ctx, "/lbm.authz.v1.Msg/Grant", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *msgClient) Exec(ctx context.Context, in *MsgExec, opts ...grpc.CallOption) (*MsgExecResponse, error) { + out := new(MsgExecResponse) + err := c.cc.Invoke(ctx, "/lbm.authz.v1.Msg/Exec", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *msgClient) Revoke(ctx context.Context, in *MsgRevoke, opts ...grpc.CallOption) (*MsgRevokeResponse, error) { + out := new(MsgRevokeResponse) + err := c.cc.Invoke(ctx, "/lbm.authz.v1.Msg/Revoke", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// MsgServer is the server API for Msg service. +type MsgServer interface { + // Grant grants the provided authorization to the grantee on the granter's + // account with the provided expiration time. If there is already a grant + // for the given (granter, grantee, Authorization) triple, then the grant + // will be overwritten. + Grant(context.Context, *MsgGrant) (*MsgGrantResponse, error) + // Exec attempts to execute the provided messages using + // authorizations granted to the grantee. Each message should have only + // one signer corresponding to the granter of the authorization. + Exec(context.Context, *MsgExec) (*MsgExecResponse, error) + // Revoke revokes any authorization corresponding to the provided method name on the + // granter's account that has been granted to the grantee. + Revoke(context.Context, *MsgRevoke) (*MsgRevokeResponse, error) +} + +// UnimplementedMsgServer can be embedded to have forward compatible implementations. +type UnimplementedMsgServer struct { +} + +func (*UnimplementedMsgServer) Grant(ctx context.Context, req *MsgGrant) (*MsgGrantResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Grant not implemented") +} +func (*UnimplementedMsgServer) Exec(ctx context.Context, req *MsgExec) (*MsgExecResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Exec not implemented") +} +func (*UnimplementedMsgServer) Revoke(ctx context.Context, req *MsgRevoke) (*MsgRevokeResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Revoke not implemented") +} + +func RegisterMsgServer(s grpc1.Server, srv MsgServer) { + s.RegisterService(&_Msg_serviceDesc, srv) +} + +func _Msg_Grant_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgGrant) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).Grant(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/lbm.authz.v1.Msg/Grant", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).Grant(ctx, req.(*MsgGrant)) + } + return interceptor(ctx, in, info, handler) +} + +func _Msg_Exec_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgExec) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).Exec(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/lbm.authz.v1.Msg/Exec", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).Exec(ctx, req.(*MsgExec)) + } + return interceptor(ctx, in, info, handler) +} + +func _Msg_Revoke_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgRevoke) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).Revoke(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/lbm.authz.v1.Msg/Revoke", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).Revoke(ctx, req.(*MsgRevoke)) + } + return interceptor(ctx, in, info, handler) +} + +var _Msg_serviceDesc = grpc.ServiceDesc{ + ServiceName: "lbm.authz.v1.Msg", + HandlerType: (*MsgServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "Grant", + Handler: _Msg_Grant_Handler, + }, + { + MethodName: "Exec", + Handler: _Msg_Exec_Handler, + }, + { + MethodName: "Revoke", + Handler: _Msg_Revoke_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "lbm/authz/v1/tx.proto", +} + +func (m *MsgGrant) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgGrant) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgGrant) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size, err := m.Grant.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + if len(m.Grantee) > 0 { + i -= len(m.Grantee) + copy(dAtA[i:], m.Grantee) + i = encodeVarintTx(dAtA, i, uint64(len(m.Grantee))) + i-- + dAtA[i] = 0x12 + } + if len(m.Granter) > 0 { + i -= len(m.Granter) + copy(dAtA[i:], m.Granter) + i = encodeVarintTx(dAtA, i, uint64(len(m.Granter))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgExecResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgExecResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgExecResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Results) > 0 { + for iNdEx := len(m.Results) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.Results[iNdEx]) + copy(dAtA[i:], m.Results[iNdEx]) + i = encodeVarintTx(dAtA, i, uint64(len(m.Results[iNdEx]))) + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func (m *MsgExec) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgExec) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgExec) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Msgs) > 0 { + for iNdEx := len(m.Msgs) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Msgs[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + } + if len(m.Grantee) > 0 { + i -= len(m.Grantee) + copy(dAtA[i:], m.Grantee) + i = encodeVarintTx(dAtA, i, uint64(len(m.Grantee))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgGrantResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgGrantResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgGrantResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func (m *MsgRevoke) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgRevoke) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgRevoke) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.MsgTypeUrl) > 0 { + i -= len(m.MsgTypeUrl) + copy(dAtA[i:], m.MsgTypeUrl) + i = encodeVarintTx(dAtA, i, uint64(len(m.MsgTypeUrl))) + i-- + dAtA[i] = 0x1a + } + if len(m.Grantee) > 0 { + i -= len(m.Grantee) + copy(dAtA[i:], m.Grantee) + i = encodeVarintTx(dAtA, i, uint64(len(m.Grantee))) + i-- + dAtA[i] = 0x12 + } + if len(m.Granter) > 0 { + i -= len(m.Granter) + copy(dAtA[i:], m.Granter) + i = encodeVarintTx(dAtA, i, uint64(len(m.Granter))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgRevokeResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgRevokeResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgRevokeResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func encodeVarintTx(dAtA []byte, offset int, v uint64) int { + offset -= sovTx(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *MsgGrant) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Granter) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.Grantee) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = m.Grant.Size() + n += 1 + l + sovTx(uint64(l)) + return n +} + +func (m *MsgExecResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.Results) > 0 { + for _, b := range m.Results { + l = len(b) + n += 1 + l + sovTx(uint64(l)) + } + } + return n +} + +func (m *MsgExec) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Grantee) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + if len(m.Msgs) > 0 { + for _, e := range m.Msgs { + l = e.Size() + n += 1 + l + sovTx(uint64(l)) + } + } + return n +} + +func (m *MsgGrantResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func (m *MsgRevoke) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Granter) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.Grantee) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.MsgTypeUrl) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + return n +} + +func (m *MsgRevokeResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func sovTx(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozTx(x uint64) (n int) { + return sovTx(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *MsgGrant) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgGrant: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgGrant: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Granter", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Granter = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Grantee", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Grantee = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Grant", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Grant.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgExecResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgExecResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgExecResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Results", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Results = append(m.Results, make([]byte, postIndex-iNdEx)) + copy(m.Results[len(m.Results)-1], dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgExec) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgExec: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgExec: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Grantee", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Grantee = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Msgs", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Msgs = append(m.Msgs, &types.Any{}) + if err := m.Msgs[len(m.Msgs)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgGrantResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgGrantResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgGrantResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgRevoke) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgRevoke: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgRevoke: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Granter", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Granter = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Grantee", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Grantee = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field MsgTypeUrl", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.MsgTypeUrl = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgRevokeResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgRevokeResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgRevokeResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipTx(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowTx + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowTx + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowTx + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthTx + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupTx + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthTx + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthTx = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowTx = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupTx = fmt.Errorf("proto: unexpected end of group") +) diff --git a/x/bank/app_test.go b/x/bank/app_test.go index b7dab334d0..6dab83c376 100644 --- a/x/bank/app_test.go +++ b/x/bank/app_test.go @@ -94,8 +94,7 @@ func TestSendNotEnoughBalance(t *testing.T) { app := simapp.SetupWithGenesisAccounts(genAccs) ctx := app.BaseApp.NewContext(false, ocproto.Header{}) - err := app.BankKeeper.SetBalances(ctx, addr1, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 67))) - require.NoError(t, err) + require.NoError(t, simapp.FundAccount(app, ctx, addr1, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 67)))) app.Commit() @@ -109,7 +108,7 @@ func TestSendNotEnoughBalance(t *testing.T) { sendMsg := types.NewMsgSend(addr1, addr2, sdk.Coins{sdk.NewInt64Coin("foocoin", 100)}) header := ocproto.Header{Height: app.LastBlockHeight() + 1} txGen := simapp.MakeTestEncodingConfig().TxConfig - _, _, err = simapp.SignCheckDeliver(t, txGen, app.BaseApp, header, []sdk.Msg{sendMsg}, "", []uint64{origAccNum}, []uint64{origSeq}, false, false, priv1) + _, _, err := simapp.SignCheckDeliver(t, txGen, app.BaseApp, header, []sdk.Msg{sendMsg}, "", []uint64{origAccNum}, []uint64{origSeq}, false, false, priv1) require.Error(t, err) simapp.CheckBalance(t, app, addr1, sdk.Coins{sdk.NewInt64Coin("foocoin", 67)}) @@ -130,8 +129,7 @@ func TestMsgMultiSendWithAccounts(t *testing.T) { app := simapp.SetupWithGenesisAccounts(genAccs) ctx := app.BaseApp.NewContext(false, ocproto.Header{}) - err := app.BankKeeper.SetBalances(ctx, addr1, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 67))) - require.NoError(t, err) + require.NoError(t, simapp.FundAccount(app, ctx, addr1, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 67)))) app.Commit() @@ -201,11 +199,9 @@ func TestMsgMultiSendMultipleOut(t *testing.T) { app := simapp.SetupWithGenesisAccounts(genAccs) ctx := app.BaseApp.NewContext(false, ocproto.Header{}) - err := app.BankKeeper.SetBalances(ctx, addr1, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 42))) - require.NoError(t, err) + require.NoError(t, simapp.FundAccount(app, ctx, addr1, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 42)))) - err = app.BankKeeper.SetBalances(ctx, addr2, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 42))) - require.NoError(t, err) + require.NoError(t, simapp.FundAccount(app, ctx, addr2, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 42)))) app.Commit() @@ -252,14 +248,11 @@ func TestMsgMultiSendMultipleInOut(t *testing.T) { app := simapp.SetupWithGenesisAccounts(genAccs) ctx := app.BaseApp.NewContext(false, ocproto.Header{}) - err := app.BankKeeper.SetBalances(ctx, addr1, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 42))) - require.NoError(t, err) + require.NoError(t, simapp.FundAccount(app, ctx, addr1, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 42)))) - err = app.BankKeeper.SetBalances(ctx, addr2, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 42))) - require.NoError(t, err) + require.NoError(t, simapp.FundAccount(app, ctx, addr2, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 42)))) - err = app.BankKeeper.SetBalances(ctx, addr4, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 42))) - require.NoError(t, err) + require.NoError(t, simapp.FundAccount(app, ctx, addr4, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 42)))) app.Commit() @@ -302,8 +295,7 @@ func TestMsgMultiSendDependent(t *testing.T) { app := simapp.SetupWithGenesisAccounts(genAccs) ctx := app.BaseApp.NewContext(false, ocproto.Header{}) - err = app.BankKeeper.SetBalances(ctx, addr1, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 42))) - require.NoError(t, err) + require.NoError(t, simapp.FundAccount(app, ctx, addr1, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 42)))) app.Commit() diff --git a/x/bank/atlas/atlas-v0.39.1.md b/x/bank/atlas/atlas-v0.39.1.md index 678629cca1..a2c6596f3a 100644 --- a/x/bank/atlas/atlas-v0.39.1.md +++ b/x/bank/atlas/atlas-v0.39.1.md @@ -35,14 +35,14 @@ with particular kinds of accounts. ``` 4. Create the keeper. Note, the `x/bank` module depends on the `x/auth` module - and a list of blacklisted account addresses which funds are not allowed to be + and a list of blocklisted account addresses which funds are not allowed to be sent to. Your application will need to define this method based your needs. ```go func NewApp(...) *App { // ... app.BankKeeper = bank.NewBaseKeeper( - app.AccountKeeper, app.subspaces[bank.ModuleName], app.BlacklistedAccAddrs(), + app.AccountKeeper, app.subspaces[bank.ModuleName], app.BlocklistedAccAddrs(), ) } ``` @@ -141,7 +141,7 @@ The `x/bank` supports the following transactional commands. 1. Send tokens via a `MsgSend` message. ```shell - $ app tx send [from_key_or_address] [to_address] [amount] [...flags] + app tx send [from_key_or_address] [to_address] [amount] [...flags] ``` Note, the `x/bank` module does not natively support constructing a `MsgMultiSend` diff --git a/x/bank/bench_test.go b/x/bank/bench_test.go index eab5921a13..5557bf5adb 100644 --- a/x/bank/bench_test.go +++ b/x/bank/bench_test.go @@ -18,6 +18,7 @@ import ( var moduleAccAddr = authtypes.NewModuleAddress(stakingtypes.BondedPoolName) func BenchmarkOneBankSendTxPerBlock(b *testing.B) { + b.ReportAllocs() // Add an account at genesis acc := authtypes.BaseAccount{ Address: addr1.String(), @@ -29,8 +30,7 @@ func BenchmarkOneBankSendTxPerBlock(b *testing.B) { ctx := benchmarkApp.BaseApp.NewContext(false, ocproto.Header{}) // some value conceivably higher than the benchmarks would ever go - err := benchmarkApp.BankKeeper.SetBalances(ctx, addr1, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 100000000000))) - require.NoError(b, err) + require.NoError(b, simapp.FundAccount(benchmarkApp, ctx, addr1, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 100000000000)))) benchmarkApp.Commit() txGen := simappparams.MakeTestEncodingConfig().TxConfig @@ -72,8 +72,7 @@ func BenchmarkOneBankMultiSendTxPerBlock(b *testing.B) { ctx := benchmarkApp.BaseApp.NewContext(false, ocproto.Header{}) // some value conceivably higher than the benchmarks would ever go - err := benchmarkApp.BankKeeper.SetBalances(ctx, addr1, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 100000000000))) - require.NoError(b, err) + require.NoError(b, simapp.FundAccount(benchmarkApp, ctx, addr1, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 100000000000)))) benchmarkApp.Commit() txGen := simappparams.MakeTestEncodingConfig().TxConfig diff --git a/x/bank/client/cli/query.go b/x/bank/client/cli/query.go index 113c28e4dd..f4f120ccdd 100644 --- a/x/bank/client/cli/query.go +++ b/x/bank/client/cli/query.go @@ -73,11 +73,10 @@ Example: if err != nil { return err } - + ctx := cmd.Context() if denom == "" { params := types.NewQueryAllBalancesRequest(addr, pageReq) - - res, err := queryClient.AllBalances(cmd.Context(), params) + res, err := queryClient.AllBalances(ctx, params) if err != nil { return err } @@ -85,7 +84,7 @@ Example: } params := types.NewQueryBalanceRequest(addr, denom) - res, err := queryClient.Balance(cmd.Context(), params) + res, err := queryClient.Balance(ctx, params) if err != nil { return err } @@ -182,9 +181,14 @@ To query for the total supply of a specific coin denomination use: } queryClient := types.NewQueryClient(clientCtx) + ctx := cmd.Context() + pageReq, err := client.ReadPageRequest(cmd.Flags()) + if err != nil { + return err + } if denom == "" { - res, err := queryClient.TotalSupply(cmd.Context(), &types.QueryTotalSupplyRequest{}) + res, err := queryClient.TotalSupply(ctx, &types.QueryTotalSupplyRequest{Pagination: pageReq}) if err != nil { return err } @@ -192,7 +196,7 @@ To query for the total supply of a specific coin denomination use: return clientCtx.PrintProto(res) } - res, err := queryClient.SupplyOf(cmd.Context(), &types.QuerySupplyOfRequest{Denom: denom}) + res, err := queryClient.SupplyOf(ctx, &types.QuerySupplyOfRequest{Denom: denom}) if err != nil { return err } diff --git a/x/bank/client/cli/tx.go b/x/bank/client/cli/tx.go index f6e5a12280..0e215f92c1 100644 --- a/x/bank/client/cli/tx.go +++ b/x/bank/client/cli/tx.go @@ -46,9 +46,6 @@ ignored as it is implied from [from_key_or_address].`, } msg := types.NewMsgSend(clientCtx.GetFromAddress(), toAddr, coins) - if err := msg.ValidateBasic(); err != nil { - return err - } return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) }, diff --git a/x/bank/client/rest/grpc_query_test.go b/x/bank/client/rest/grpc_query_test.go index 33e43bef93..a330285865 100644 --- a/x/bank/client/rest/grpc_query_test.go +++ b/x/bank/client/rest/grpc_query_test.go @@ -1,3 +1,4 @@ +//go:build norace // +build norace package rest_test @@ -38,6 +39,9 @@ func (s *IntegrationTestSuite) TestTotalSupplyGRPCHandler() { sdk.NewCoin(fmt.Sprintf("%stoken", val.Moniker), s.cfg.AccountTokens), sdk.NewCoin(s.cfg.BondDenom, s.cfg.StakingTokens.Add(sdk.NewInt(10))), ), + Pagination: &query.PageResponse{ + Total: 2, + }, }, }, { @@ -92,7 +96,7 @@ func (s *IntegrationTestSuite) TestTotalSupplyGRPCHandler() { resp, err := testutil.GetRequestWithHeaders(tc.url, tc.headers) s.Require().NoError(err) - s.Require().NoError(val.ClientCtx.JSONMarshaler.UnmarshalJSON(resp, tc.respType)) + s.Require().NoError(val.ClientCtx.Codec.UnmarshalJSON(resp, tc.respType)) s.Require().Equal(tc.expected.String(), tc.respType.String()) }) } @@ -121,6 +125,8 @@ func (s *IntegrationTestSuite) TestDenomMetadataGRPCHandler() { &types.QueryDenomsMetadataResponse{ Metadatas: []types.Metadata{ { + Name: "Cosmos Hub Atom", + Symbol: "ATOM", Description: "The native staking token of the Cosmos Hub.", DenomUnits: []*types.DenomUnit{ { @@ -151,6 +157,8 @@ func (s *IntegrationTestSuite) TestDenomMetadataGRPCHandler() { &types.QueryDenomMetadataResponse{}, &types.QueryDenomMetadataResponse{ Metadata: types.Metadata{ + Name: "Cosmos Hub Atom", + Symbol: "ATOM", Description: "The native staking token of the Cosmos Hub.", DenomUnits: []*types.DenomUnit{ { @@ -192,9 +200,9 @@ func (s *IntegrationTestSuite) TestDenomMetadataGRPCHandler() { s.Require().NoError(err) if tc.expErr { - s.Require().Error(val.ClientCtx.JSONMarshaler.UnmarshalJSON(resp, tc.respType)) + s.Require().Error(val.ClientCtx.Codec.UnmarshalJSON(resp, tc.respType)) } else { - s.Require().NoError(val.ClientCtx.JSONMarshaler.UnmarshalJSON(resp, tc.respType)) + s.Require().NoError(val.ClientCtx.Codec.UnmarshalJSON(resp, tc.respType)) s.Require().Equal(tc.expected.String(), tc.respType.String()) } }) @@ -255,7 +263,7 @@ func (s *IntegrationTestSuite) TestBalancesGRPCHandler() { resp, err := rest.GetRequest(tc.url) s.Require().NoError(err) - s.Require().NoError(val.ClientCtx.JSONMarshaler.UnmarshalJSON(resp, tc.respType)) + s.Require().NoError(val.ClientCtx.Codec.UnmarshalJSON(resp, tc.respType)) s.Require().Equal(tc.expected.String(), tc.respType.String()) }) } diff --git a/x/bank/client/rest/query_test.go b/x/bank/client/rest/query_test.go index 3706e60121..d76dccd8e3 100644 --- a/x/bank/client/rest/query_test.go +++ b/x/bank/client/rest/query_test.go @@ -1,3 +1,4 @@ +//go:build norace // +build norace package rest_test @@ -10,6 +11,7 @@ import ( "github.com/line/lbm-sdk/testutil/network" sdk "github.com/line/lbm-sdk/types" + "github.com/line/lbm-sdk/types/query" "github.com/line/lbm-sdk/types/rest" "github.com/line/lbm-sdk/x/bank/types" ) @@ -33,6 +35,8 @@ func (s *IntegrationTestSuite) SetupSuite() { bankGenesis.DenomMetadata = []types.Metadata{ { + Name: "Cosmos Hub Atom", + Symbol: "ATOM", Description: "The native staking token of the Cosmos Hub.", DenomUnits: []*types.DenomUnit{ { @@ -153,11 +157,14 @@ func (s *IntegrationTestSuite) TestTotalSupplyHandlerFn() { { "total supply", fmt.Sprintf("%s/bank/total?height=1", baseURL), - &sdk.Coins{}, - sdk.NewCoins( - sdk.NewCoin(fmt.Sprintf("%stoken", val.Moniker), s.cfg.AccountTokens), - sdk.NewCoin(s.cfg.BondDenom, s.cfg.StakingTokens.Add(sdk.NewInt(10))), - ), + &types.QueryTotalSupplyResponse{}, + &types.QueryTotalSupplyResponse{ + Supply: sdk.NewCoins( + sdk.NewCoin(fmt.Sprintf("%stoken", val.Moniker), s.cfg.AccountTokens), + sdk.NewCoin(s.cfg.BondDenom, s.cfg.StakingTokens.Add(sdk.NewInt(10))), + ), + Pagination: &query.PageResponse{Total: 2}, + }, }, { "total supply of a specific denom", diff --git a/x/bank/client/rest/tx_test.go b/x/bank/client/rest/tx_test.go index 9a011c80b2..9f1420eaa1 100644 --- a/x/bank/client/rest/tx_test.go +++ b/x/bank/client/rest/tx_test.go @@ -6,12 +6,11 @@ package rest_test import ( "fmt" - "github.com/line/lbm-sdk/simapp" "github.com/line/lbm-sdk/testutil/network" "github.com/line/lbm-sdk/types" + sdk "github.com/line/lbm-sdk/types" "github.com/line/lbm-sdk/types/errors" "github.com/line/lbm-sdk/types/rest" - authclient "github.com/line/lbm-sdk/x/auth/client" "github.com/line/lbm-sdk/x/auth/legacy/legacytx" authtypes "github.com/line/lbm-sdk/x/auth/types" bankrest "github.com/line/lbm-sdk/x/bank/client/rest" @@ -19,9 +18,6 @@ import ( ) func (s *IntegrationTestSuite) TestCoinSend() { - encodingConfig := simapp.MakeTestEncodingConfig() - authclient.Codec = encodingConfig.Marshaler - val := s.network.Validators[0] account, err := getAccountInfo(val) @@ -29,7 +25,7 @@ func (s *IntegrationTestSuite) TestCoinSend() { sendReq := generateSendReq( account, - types.Coins{types.NewCoin(s.cfg.BondDenom, types.TokensFromConsensusPower(1))}, + types.Coins{types.NewCoin(s.cfg.BondDenom, types.TokensFromConsensusPower(1, sdk.DefaultPowerReduction))}, ) stdTx, err := submitSendReq(val, sendReq) diff --git a/x/bank/client/testutil/cli_helpers.go b/x/bank/client/testutil/cli_helpers.go index e65004b8b6..ab0945402d 100644 --- a/x/bank/client/testutil/cli_helpers.go +++ b/x/bank/client/testutil/cli_helpers.go @@ -1,22 +1,14 @@ package testutil import ( - "context" "fmt" - gogogrpc "github.com/gogo/protobuf/grpc" "github.com/line/ostracon/libs/cli" - "github.com/spf13/cobra" - grpc "google.golang.org/grpc" "github.com/line/lbm-sdk/client" - "github.com/line/lbm-sdk/client/flags" - "github.com/line/lbm-sdk/client/tx" "github.com/line/lbm-sdk/testutil" clitestutil "github.com/line/lbm-sdk/testutil/cli" - sdk "github.com/line/lbm-sdk/types" bankcli "github.com/line/lbm-sdk/x/bank/client/cli" - "github.com/line/lbm-sdk/x/bank/types" ) func MsgSendExec(clientCtx client.Context, from, to, amount fmt.Stringer, extraArgs ...string) (testutil.BufferWriter, error) { @@ -32,87 +24,3 @@ func QueryBalancesExec(clientCtx client.Context, address fmt.Stringer, extraArgs return clitestutil.ExecTestCLICmd(clientCtx, bankcli.GetBalancesCmd(), args) } - -// serviceMsgClientConn is an instance of grpc.ClientConn that is used to test building -// transactions with MsgClient's. It is intended to be replaced by the work in -// https://github.com/cosmos/cosmos-sdk/issues/7541 when that is ready. -type serviceMsgClientConn struct { - msgs []sdk.Msg -} - -func (t *serviceMsgClientConn) Invoke(_ context.Context, method string, args, _ interface{}, _ ...grpc.CallOption) error { - req, ok := args.(sdk.MsgRequest) - if !ok { - return fmt.Errorf("%T should implement %T", args, (*sdk.MsgRequest)(nil)) - } - - err := req.ValidateBasic() - if err != nil { - return err - } - - t.msgs = append(t.msgs, sdk.ServiceMsg{ - MethodName: method, - Request: req, - }) - - return nil -} - -func (t *serviceMsgClientConn) NewStream(context.Context, *grpc.StreamDesc, string, ...grpc.CallOption) (grpc.ClientStream, error) { - return nil, fmt.Errorf("not supported") -} - -var _ gogogrpc.ClientConn = &serviceMsgClientConn{} - -// newSendTxMsgServiceCmd is just for the purpose of testing ServiceMsg's in an end-to-end case. It is effectively -// NewSendTxCmd but using MsgClient. -func newSendTxMsgServiceCmd() *cobra.Command { - cmd := &cobra.Command{ - Use: "send [from_key_or_address] [to_address] [amount]", - Short: `Send funds from one account to another. Note, the'--from' flag is -ignored as it is implied from [from_key_or_address].`, - Args: cobra.ExactArgs(3), - RunE: func(cmd *cobra.Command, args []string) error { - cmd.Flags().Set(flags.FlagFrom, args[0]) - clientCtx, err := client.GetClientTxContext(cmd) - if err != nil { - return err - } - err = sdk.ValidateAccAddress(args[1]) - if err != nil { - return err - } - - coins, err := sdk.ParseCoinsNormalized(args[2]) - if err != nil { - return err - } - - msg := types.NewMsgSend(clientCtx.GetFromAddress(), sdk.AccAddress(args[1]), coins) - svcMsgClientConn := &serviceMsgClientConn{} - bankMsgClient := types.NewMsgClient(svcMsgClientConn) - _, err = bankMsgClient.Send(context.Background(), msg) - if err != nil { - return err - } - - return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), svcMsgClientConn.msgs...) - }, - } - - flags.AddTxFlagsToCmd(cmd) - - return cmd -} - -// ServiceMsgSendExec is a temporary method to test Msg services in CLI using -// x/bank's Msg/Send service. After https://github.com/cosmos/cosmos-sdk/issues/7541 -// is merged, this method should be removed, and we should prefer MsgSendExec -// instead. -func ServiceMsgSendExec(clientCtx client.Context, from, to, amount fmt.Stringer, extraArgs ...string) (testutil.BufferWriter, error) { - args := []string{from.String(), to.String(), amount.String()} - args = append(args, extraArgs...) - - return clitestutil.ExecTestCLICmd(clientCtx, newSendTxMsgServiceCmd(), args) -} diff --git a/x/bank/client/testutil/cli_test.go b/x/bank/client/testutil/cli_test.go new file mode 100644 index 0000000000..8ded31fefa --- /dev/null +++ b/x/bank/client/testutil/cli_test.go @@ -0,0 +1,18 @@ +//go:build norace +// +build norace + +package testutil + +import ( + "testing" + + "github.com/line/lbm-sdk/testutil/network" + + "github.com/stretchr/testify/suite" +) + +func TestIntegrationTestSuite(t *testing.T) { + cfg := network.DefaultConfig() + cfg.NumValidators = 1 + suite.Run(t, NewIntegrationTestSuite(cfg)) +} diff --git a/x/bank/client/cli/cli_test.go b/x/bank/client/testutil/suite.go similarity index 78% rename from x/bank/client/cli/cli_test.go rename to x/bank/client/testutil/suite.go index 8e971fcc75..3f9dd90e15 100644 --- a/x/bank/client/cli/cli_test.go +++ b/x/bank/client/testutil/suite.go @@ -1,15 +1,13 @@ -package cli_test +package testutil import ( - "context" "fmt" - "testing" "github.com/gogo/protobuf/proto" - ostcli "github.com/line/ostracon/libs/cli" "github.com/stretchr/testify/suite" - "github.com/line/lbm-sdk/client" + ostcli "github.com/line/ostracon/libs/cli" + "github.com/line/lbm-sdk/client/flags" clitestutil "github.com/line/lbm-sdk/testutil/cli" "github.com/line/lbm-sdk/testutil/network" @@ -17,7 +15,6 @@ import ( sdkerrors "github.com/line/lbm-sdk/types/errors" "github.com/line/lbm-sdk/types/query" "github.com/line/lbm-sdk/x/bank/client/cli" - banktestutil "github.com/line/lbm-sdk/x/bank/client/testutil" "github.com/line/lbm-sdk/x/bank/types" ) @@ -28,18 +25,21 @@ type IntegrationTestSuite struct { network *network.Network } +func NewIntegrationTestSuite(cfg network.Config) *IntegrationTestSuite { + return &IntegrationTestSuite{cfg: cfg} +} + func (s *IntegrationTestSuite) SetupSuite() { s.T().Log("setting up integration test suite") - cfg := network.DefaultConfig() - genesisState := cfg.GenesisState - cfg.NumValidators = 1 - + genesisState := s.cfg.GenesisState var bankGenesis types.GenesisState - s.Require().NoError(cfg.Codec.UnmarshalJSON(genesisState[types.ModuleName], &bankGenesis)) + s.Require().NoError(s.cfg.Codec.UnmarshalJSON(genesisState[types.ModuleName], &bankGenesis)) bankGenesis.DenomMetadata = []types.Metadata{ { + Name: "Cosmos Hub Atom", + Symbol: "ATOM", Description: "The native staking token of the Cosmos Hub.", DenomUnits: []*types.DenomUnit{ { @@ -57,6 +57,8 @@ func (s *IntegrationTestSuite) SetupSuite() { Display: "atom", }, { + Name: "Ethereum", + Symbol: "ETH", Description: "Ethereum mainnet token", DenomUnits: []*types.DenomUnit{ { @@ -74,13 +76,12 @@ func (s *IntegrationTestSuite) SetupSuite() { }, } - bankGenesisBz, err := cfg.Codec.MarshalJSON(&bankGenesis) + bankGenesisBz, err := s.cfg.Codec.MarshalJSON(&bankGenesis) s.Require().NoError(err) genesisState[types.ModuleName] = bankGenesisBz - cfg.GenesisState = genesisState + s.cfg.GenesisState = genesisState - s.cfg = cfg - s.network = network.New(s.T(), cfg) + s.network = network.New(s.T(), s.cfg) _, err = s.network.WaitForHeight(1) s.Require().NoError(err) @@ -155,7 +156,7 @@ func (s *IntegrationTestSuite) TestGetBalancesCmd() { s.Require().Error(err) } else { s.Require().NoError(err) - s.Require().NoError(val.ClientCtx.JSONMarshaler.UnmarshalJSON(out.Bytes(), tc.respType)) + s.Require().NoError(val.ClientCtx.Codec.UnmarshalJSON(out.Bytes(), tc.respType)) s.Require().Equal(tc.expected.String(), tc.respType.String()) } }) @@ -183,7 +184,9 @@ func (s *IntegrationTestSuite) TestGetCmdQueryTotalSupply() { Supply: sdk.NewCoins( sdk.NewCoin(fmt.Sprintf("%stoken", val.Moniker), s.cfg.AccountTokens), sdk.NewCoin(s.cfg.BondDenom, s.cfg.StakingTokens.Add(sdk.NewInt(10))), - )}, + ), + Pagination: &query.PageResponse{Total: 2}, + }, }, { name: "total supply of a specific denomination", @@ -193,7 +196,10 @@ func (s *IntegrationTestSuite) TestGetCmdQueryTotalSupply() { fmt.Sprintf("--%s=json", ostcli.OutputFlag), }, respType: &sdk.Coin{}, - expected: &sdk.Coin{s.cfg.BondDenom, s.cfg.StakingTokens.Add(sdk.NewInt(10))}, + expected: &sdk.Coin{ + Denom: s.cfg.BondDenom, + Amount: s.cfg.StakingTokens.Add(sdk.NewInt(10)), + }, }, { name: "total supply of a bogus denom", @@ -203,7 +209,10 @@ func (s *IntegrationTestSuite) TestGetCmdQueryTotalSupply() { fmt.Sprintf("--%s=json", ostcli.OutputFlag), }, respType: &sdk.Coin{}, - expected: &sdk.Coin{"foobar", sdk.ZeroInt()}, + expected: &sdk.Coin{ + Denom: "foobar", + Amount: sdk.ZeroInt(), + }, }, } @@ -219,7 +228,7 @@ func (s *IntegrationTestSuite) TestGetCmdQueryTotalSupply() { s.Require().Error(err) } else { s.Require().NoError(err) - s.Require().NoError(clientCtx.JSONMarshaler.UnmarshalJSON(out.Bytes(), tc.respType)) + s.Require().NoError(clientCtx.Codec.UnmarshalJSON(out.Bytes(), tc.respType)) s.Require().Equal(tc.expected, tc.respType) } }) @@ -246,6 +255,8 @@ func (s *IntegrationTestSuite) TestGetCmdQueryDenomsMetadata() { expected: &types.QueryDenomsMetadataResponse{ Metadatas: []types.Metadata{ { + Name: "Cosmos Hub Atom", + Symbol: "ATOM", Description: "The native staking token of the Cosmos Hub.", DenomUnits: []*types.DenomUnit{ { @@ -263,6 +274,8 @@ func (s *IntegrationTestSuite) TestGetCmdQueryDenomsMetadata() { Display: "atom", }, { + Name: "Ethereum", + Symbol: "ETH", Description: "Ethereum mainnet token", DenomUnits: []*types.DenomUnit{ { @@ -293,6 +306,8 @@ func (s *IntegrationTestSuite) TestGetCmdQueryDenomsMetadata() { respType: &types.QueryDenomMetadataResponse{}, expected: &types.QueryDenomMetadataResponse{ Metadata: types.Metadata{ + Name: "Cosmos Hub Atom", + Symbol: "ATOM", Description: "The native staking token of the Cosmos Hub.", DenomUnits: []*types.DenomUnit{ { @@ -340,7 +355,7 @@ func (s *IntegrationTestSuite) TestGetCmdQueryDenomsMetadata() { s.Require().Error(err) } else { s.Require().NoError(err) - s.Require().NoError(clientCtx.JSONMarshaler.UnmarshalJSON(out.Bytes(), tc.respType)) + s.Require().NoError(clientCtx.Codec.UnmarshalJSON(out.Bytes(), tc.respType)) s.Require().Equal(tc.expected, tc.respType) } }) @@ -352,9 +367,6 @@ func (s *IntegrationTestSuite) TestNewSendTxCmdGenOnly() { clientCtx := val.ClientCtx - ctx := context.Background() - ctx = context.WithValue(ctx, client.ClientContextKey, &clientCtx) - from := val.Address to := val.Address amount := sdk.NewCoins( @@ -368,7 +380,7 @@ func (s *IntegrationTestSuite) TestNewSendTxCmdGenOnly() { fmt.Sprintf("--%s=true", flags.FlagGenerateOnly), } - bz, err := banktestutil.MsgSendExec(clientCtx, from, to, amount, args...) + bz, err := MsgSendExec(clientCtx, from, to, amount, args...) s.Require().NoError(err) tx, err := s.cfg.TxConfig.TxJSONDecoder()(bz.Bytes()) s.Require().NoError(err) @@ -384,8 +396,8 @@ func (s *IntegrationTestSuite) TestNewSendTxCmd() { amount sdk.Coins args []string expectErr bool - respType proto.Message expectedCode uint32 + respType proto.Message }{ { "valid transaction", @@ -400,9 +412,7 @@ func (s *IntegrationTestSuite) TestNewSendTxCmd() { fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), }, - false, - &sdk.TxResponse{}, - 0, + false, 0, &sdk.TxResponse{}, }, { "not enough fees", @@ -418,8 +428,8 @@ func (s *IntegrationTestSuite) TestNewSendTxCmd() { fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(1))).String()), }, false, - &sdk.TxResponse{}, sdkerrors.ErrInsufficientFee.ABCICode(), + &sdk.TxResponse{}, }, { "not enough gas", @@ -436,63 +446,8 @@ func (s *IntegrationTestSuite) TestNewSendTxCmd() { "--gas=10", }, false, - &sdk.TxResponse{}, sdkerrors.ErrOutOfGas.ABCICode(), - }, - } - - for _, tc := range testCases { - tc := tc - - s.Run(tc.name, func() { - clientCtx := val.ClientCtx - - bz, err := banktestutil.MsgSendExec(clientCtx, tc.from, tc.to, tc.amount, tc.args...) - if tc.expectErr { - s.Require().Error(err) - } else { - s.Require().NoError(err) - - s.Require().NoError(clientCtx.JSONMarshaler.UnmarshalJSON(bz.Bytes(), tc.respType), bz.String()) - txResp := tc.respType.(*sdk.TxResponse) - s.Require().Equal(tc.expectedCode, txResp.Code) - } - }) - } -} - -// TestBankMsgService does a basic test of whether or not service Msg's as defined -// in ADR 031 work in the most basic end-to-end case. -func (s *IntegrationTestSuite) TestBankMsgService() { - val := s.network.Validators[0] - - testCases := []struct { - name string - from, to sdk.AccAddress - amount sdk.Coins - args []string - expectErr bool - respType proto.Message - expectedCode uint32 - rawLogContains string - }{ - { - "valid transaction", - val.Address, - val.Address, - sdk.NewCoins( - sdk.NewCoin(fmt.Sprintf("%stoken", val.Moniker), sdk.NewInt(10)), - sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10)), - ), - []string{ - fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), - fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), - fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), - }, - false, &sdk.TxResponse{}, - 0, - "/lbm.bank.v1.Msg/Send", // indicates we are using ServiceMsg and not a regular Msg }, } @@ -501,25 +456,21 @@ func (s *IntegrationTestSuite) TestBankMsgService() { s.Run(tc.name, func() { clientCtx := val.ClientCtx - bz, err := banktestutil.ServiceMsgSendExec(clientCtx, tc.from, tc.to, tc.amount, tc.args...) + + bz, err := MsgSendExec(clientCtx, tc.from, tc.to, tc.amount, tc.args...) if tc.expectErr { s.Require().Error(err) } else { s.Require().NoError(err) - s.Require().NoError(clientCtx.JSONMarshaler.UnmarshalJSON(bz.Bytes(), tc.respType), bz.String()) + s.Require().NoError(clientCtx.Codec.UnmarshalJSON(bz.Bytes(), tc.respType), bz.String()) txResp := tc.respType.(*sdk.TxResponse) s.Require().Equal(tc.expectedCode, txResp.Code) - s.Require().Contains(txResp.RawLog, tc.rawLogContains) } }) } } -func TestIntegrationTestSuite(t *testing.T) { - suite.Run(t, new(IntegrationTestSuite)) -} - func NewCoin(denom string, amount sdk.Int) *sdk.Coin { coin := sdk.NewCoin(denom, amount) return &coin diff --git a/x/bank/exported/exported.go b/x/bank/exported/exported.go index 6ca372ac05..e334b1d544 100644 --- a/x/bank/exported/exported.go +++ b/x/bank/exported/exported.go @@ -1,8 +1,6 @@ package exported import ( - "github.com/gogo/protobuf/proto" - sdk "github.com/line/lbm-sdk/types" ) @@ -12,20 +10,3 @@ type GenesisBalance interface { GetAddress() sdk.AccAddress GetCoins() sdk.Coins } - -// SupplyI defines an inflationary supply interface for modules that handle -// token supply. -type SupplyI interface { - proto.Message - - GetTotal() sdk.Coins - SetTotal(total sdk.Coins) - - Inflate(amount sdk.Coins) - Deflate(amount sdk.Coins) - - String() string - ValidateBasic() error - - MarshalX() ([]byte, error) -} diff --git a/x/bank/keeper/genesis.go b/x/bank/keeper/genesis.go index cf7af0629a..d03f574824 100644 --- a/x/bank/keeper/genesis.go +++ b/x/bank/keeper/genesis.go @@ -4,6 +4,7 @@ import ( "fmt" sdk "github.com/line/lbm-sdk/types" + "github.com/line/lbm-sdk/types/query" "github.com/line/lbm-sdk/x/bank/types" ) @@ -11,22 +12,25 @@ import ( func (k BaseKeeper) InitGenesis(ctx sdk.Context, genState *types.GenesisState) { k.SetParams(ctx, genState.Params) - var totalSupply sdk.Coins + totalSupply := sdk.Coins{} genState.Balances = types.SanitizeGenesisBalances(genState.Balances) for _, balance := range genState.Balances { - if err := k.initBalances(ctx, sdk.AccAddress(balance.Address), balance.Coins); err != nil { + addr := sdk.AccAddress(balance.Address) + if err := k.initBalances(ctx, addr, balance.Coins); err != nil { panic(fmt.Errorf("error on setting balances %w", err)) } totalSupply = totalSupply.Add(balance.Coins...) } - if genState.Supply.Empty() { - genState.Supply = totalSupply + if !genState.Supply.Empty() && !genState.Supply.IsEqual(totalSupply) { + panic(fmt.Errorf("genesis supply is incorrect, expected %v, got %v", genState.Supply, totalSupply)) } - k.SetSupply(ctx, types.NewSupply(genState.Supply)) + for _, supply := range totalSupply { + k.setSupply(ctx, supply) + } for _, meta := range genState.DenomMetadata { k.SetDenomMetaData(ctx, meta) @@ -35,10 +39,15 @@ func (k BaseKeeper) InitGenesis(ctx sdk.Context, genState *types.GenesisState) { // ExportGenesis returns the bank module's genesis state. func (k BaseKeeper) ExportGenesis(ctx sdk.Context) *types.GenesisState { + totalSupply, _, err := k.GetPaginatedTotalSupply(ctx, &query.PageRequest{Limit: query.MaxLimit}) + if err != nil { + panic(fmt.Errorf("unable to fetch total supply %v", err)) + } + return types.NewGenesisState( k.GetParams(ctx), k.GetAccountsBalances(ctx), - k.GetSupply(ctx).GetTotal(), + totalSupply, k.GetAllDenomMetaData(ctx), ) } diff --git a/x/bank/keeper/genesis_test.go b/x/bank/keeper/genesis_test.go index d365c44957..b6df1d782e 100644 --- a/x/bank/keeper/genesis_test.go +++ b/x/bank/keeper/genesis_test.go @@ -2,45 +2,54 @@ package keeper_test import ( sdk "github.com/line/lbm-sdk/types" + "github.com/line/lbm-sdk/types/query" "github.com/line/lbm-sdk/x/bank/types" + minttypes "github.com/line/lbm-sdk/x/mint/types" ) func (suite *IntegrationTestSuite) TestExportGenesis() { app, ctx := suite.app, suite.ctx expectedMetadata := suite.getTestMetadata() - expectedBalances := suite.getTestBalances() + expectedBalances, totalSupply := suite.getTestBalancesAndSupply() for i := range []int{1, 2} { app.BankKeeper.SetDenomMetaData(ctx, expectedMetadata[i]) err1 := sdk.ValidateAccAddress(expectedBalances[i].Address) if err1 != nil { panic(err1) } - err := app.BankKeeper.SetBalances(ctx, sdk.AccAddress(expectedBalances[i].Address), expectedBalances[i].Coins) - suite.Require().NoError(err) + // set balances via mint and send + suite. + Require(). + NoError(app.BankKeeper.MintCoins(ctx, minttypes.ModuleName, expectedBalances[i].Coins)) + suite. + Require(). + NoError(app.BankKeeper.SendCoinsFromModuleToAccount(ctx, minttypes.ModuleName, sdk.AccAddress(expectedBalances[i].Address), expectedBalances[i].Coins)) } - - totalSupply := types.NewSupply(sdk.NewCoins(sdk.NewInt64Coin("test", 400000000))) - app.BankKeeper.SetSupply(ctx, totalSupply) app.BankKeeper.SetParams(ctx, types.DefaultParams()) exportGenesis := app.BankKeeper.ExportGenesis(ctx) suite.Require().Len(exportGenesis.Params.SendEnabled, 0) suite.Require().Equal(types.DefaultParams().DefaultSendEnabled, exportGenesis.Params.DefaultSendEnabled) - suite.Require().Equal(totalSupply.GetTotal(), exportGenesis.Supply) + suite.Require().Equal(totalSupply, exportGenesis.Supply) suite.Require().Equal(expectedBalances, exportGenesis.Balances) suite.Require().Equal(expectedMetadata, exportGenesis.DenomMetadata) } -func (suite *IntegrationTestSuite) getTestBalances() []types.Balance { - addr2 := sdk.AccAddress("link15klks9yty6rwvnqk47q4cg92r38qj4gsvxdfj8") - addr1 := sdk.AccAddress("link14uxsrqf2cakphyw9ywwy9a9fv7yjspku4lkrny") - return []types.Balance{ - {Address: addr1.String(), Coins: sdk.Coins{sdk.NewInt64Coin("testcoin3", 10)}}, - {Address: addr2.String(), Coins: sdk.Coins{sdk.NewInt64Coin("testcoin1", 32), sdk.NewInt64Coin("testcoin2", 34)}}, - } +func (suite *IntegrationTestSuite) getTestBalancesAndSupply() ([]types.Balance, sdk.Coins) { + addr2 := sdk.AccAddress("link1f9xjhxm0plzrh9cskf4qee4pc2xwp0n0p662v8") + addr1 := sdk.AccAddress("link1fl48vsnmsdzcv85q5d2q4z5ajdha8yu3q4fdzl") + addr1Balance := sdk.Coins{sdk.NewInt64Coin("testcoin3", 10)} + addr2Balance := sdk.Coins{sdk.NewInt64Coin("testcoin1", 32), sdk.NewInt64Coin("testcoin2", 34)} + totalSupply := addr1Balance + totalSupply = totalSupply.Add(addr2Balance...) + + return []types.Balance{ + {Address: addr2.String(), Coins: addr2Balance}, + {Address: addr1.String(), Coins: addr1Balance}, + }, totalSupply } func (suite *IntegrationTestSuite) TestInitGenesis() { @@ -50,6 +59,56 @@ func (suite *IntegrationTestSuite) TestInitGenesis() { bk := suite.app.BankKeeper bk.InitGenesis(suite.ctx, g) - m2 := bk.GetDenomMetaData(suite.ctx, m.Base) + m2, found := bk.GetDenomMetaData(suite.ctx, m.Base) + suite.Require().True(found) suite.Require().Equal(m, m2) } + +func (suite *IntegrationTestSuite) TestTotalSupply() { + // Prepare some test data. + defaultGenesis := types.DefaultGenesisState() + balances := []types.Balance{ + {Coins: sdk.NewCoins(sdk.NewCoin("foocoin", sdk.NewInt(1))), Address: "link1f9xjhxm0plzrh9cskf4qee4pc2xwp0n0556gh0"}, + {Coins: sdk.NewCoins(sdk.NewCoin("barcoin", sdk.NewInt(1))), Address: "link1t5u0jfg3ljsjrh2m9e47d4ny2hea7eehxrzdgd"}, + {Coins: sdk.NewCoins(sdk.NewCoin("foocoin", sdk.NewInt(10)), sdk.NewCoin("barcoin", sdk.NewInt(20))), Address: "link1m3h30wlvsf8llruxtpukdvsy0km2kum8g38c8q"}, + } + totalSupply := sdk.NewCoins(sdk.NewCoin("foocoin", sdk.NewInt(11)), sdk.NewCoin("barcoin", sdk.NewInt(21))) + + testcases := []struct { + name string + genesis *types.GenesisState + expSupply sdk.Coins + expPanic bool + expPanicMsg string + }{ + { + "calculation NOT matching genesis Supply field", + types.NewGenesisState(defaultGenesis.Params, balances, sdk.NewCoins(sdk.NewCoin("wrongcoin", sdk.NewInt(1))), defaultGenesis.DenomMetadata), + nil, true, "genesis supply is incorrect, expected 1wrongcoin, got 21barcoin,11foocoin", + }, + { + "calculation matches genesis Supply field", + types.NewGenesisState(defaultGenesis.Params, balances, totalSupply, defaultGenesis.DenomMetadata), + totalSupply, false, "", + }, + { + "calculation is correct, empty genesis Supply field", + types.NewGenesisState(defaultGenesis.Params, balances, nil, defaultGenesis.DenomMetadata), + totalSupply, false, "", + }, + } + + for _, tc := range testcases { + tc := tc + suite.Run(tc.name, func() { + if tc.expPanic { + suite.PanicsWithError(tc.expPanicMsg, func() { suite.app.BankKeeper.InitGenesis(suite.ctx, tc.genesis) }) + } else { + suite.app.BankKeeper.InitGenesis(suite.ctx, tc.genesis) + totalSupply, _, err := suite.app.BankKeeper.GetPaginatedTotalSupply(suite.ctx, &query.PageRequest{Limit: query.MaxLimit}) + suite.Require().NoError(err) + suite.Require().Equal(tc.expSupply, totalSupply) + } + }) + } +} diff --git a/x/bank/keeper/grpc_query.go b/x/bank/keeper/grpc_query.go index 19ef67296a..078719f8f4 100644 --- a/x/bank/keeper/grpc_query.go +++ b/x/bank/keeper/grpc_query.go @@ -63,13 +63,11 @@ func (k BaseKeeper) AllBalances(ctx context.Context, req *types.QueryAllBalances sdkCtx := sdk.UnwrapSDKContext(ctx) balances := sdk.NewCoins() - store := sdkCtx.KVStore(k.storeKey) - balancesStore := prefix.NewStore(store, types.BalancesPrefix) - accountStore := prefix.NewStore(balancesStore, sdk.AccAddress(req.Address).Bytes()) + accountStore := k.getAccountStore(sdkCtx, sdk.AccAddress(req.Address)) pageRes, err := query.Paginate(accountStore, req.Pagination, func(_, value []byte) error { var result sdk.Coin - err := k.cdc.UnmarshalBinaryBare(value, &result) + err := k.cdc.Unmarshal(value, &result) if err != nil { return err } @@ -85,11 +83,14 @@ func (k BaseKeeper) AllBalances(ctx context.Context, req *types.QueryAllBalances } // TotalSupply implements the Query/TotalSupply gRPC method -func (k BaseKeeper) TotalSupply(ctx context.Context, _ *types.QueryTotalSupplyRequest) (*types.QueryTotalSupplyResponse, error) { +func (k BaseKeeper) TotalSupply(ctx context.Context, req *types.QueryTotalSupplyRequest) (*types.QueryTotalSupplyResponse, error) { sdkCtx := sdk.UnwrapSDKContext(ctx) - totalSupply := k.GetSupply(sdkCtx).GetTotal() + totalSupply, pageRes, err := k.GetPaginatedTotalSupply(sdkCtx, req.Pagination) + if err != nil { + return nil, status.Error(codes.Internal, err.Error()) + } - return &types.QueryTotalSupplyResponse{Supply: totalSupply}, nil + return &types.QueryTotalSupplyResponse{Supply: totalSupply, Pagination: pageRes}, nil } // SupplyOf implements the Query/SupplyOf gRPC method @@ -103,9 +104,9 @@ func (k BaseKeeper) SupplyOf(c context.Context, req *types.QuerySupplyOfRequest) } ctx := sdk.UnwrapSDKContext(c) - supply := k.GetSupply(ctx).GetTotal().AmountOf(req.Denom) + supply := k.GetSupply(ctx, req.Denom) - return &types.QuerySupplyOfResponse{Amount: sdk.NewCoin(req.Denom, supply)}, nil + return &types.QuerySupplyOfResponse{Amount: sdk.NewCoin(req.Denom, supply.Amount)}, nil } // Params implements the gRPC service handler for querying x/bank parameters. @@ -132,7 +133,7 @@ func (k BaseKeeper) DenomsMetadata(c context.Context, req *types.QueryDenomsMeta metadatas := []types.Metadata{} pageRes, err := query.Paginate(store, req.Pagination, func(_, value []byte) error { var metadata types.Metadata - k.cdc.MustUnmarshalBinaryBare(value, &metadata) + k.cdc.MustUnmarshal(value, &metadata) metadatas = append(metadatas, metadata) return nil @@ -160,8 +161,8 @@ func (k BaseKeeper) DenomMetadata(c context.Context, req *types.QueryDenomMetada ctx := sdk.UnwrapSDKContext(c) - metadata := k.GetDenomMetaData(ctx, req.Denom) - if metadata.Base == "" && metadata.Display == "" && metadata.Description == "" && len(metadata.DenomUnits) == 0 { + metadata, found := k.GetDenomMetaData(ctx, req.Denom) + if !found { return nil, status.Errorf(codes.NotFound, "client metadata for denom %s", req.Denom) } diff --git a/x/bank/keeper/grpc_query_test.go b/x/bank/keeper/grpc_query_test.go index c13a705fc1..7a577e0c30 100644 --- a/x/bank/keeper/grpc_query_test.go +++ b/x/bank/keeper/grpc_query_test.go @@ -1,15 +1,15 @@ -// +build norace - package keeper_test import ( gocontext "context" "fmt" + "github.com/line/lbm-sdk/simapp" "github.com/line/lbm-sdk/testutil/testdata" sdk "github.com/line/lbm-sdk/types" "github.com/line/lbm-sdk/types/query" "github.com/line/lbm-sdk/x/bank/types" + minttypes "github.com/line/lbm-sdk/x/mint/types" ) func (suite *IntegrationTestSuite) TestQueryBalance() { @@ -32,7 +32,7 @@ func (suite *IntegrationTestSuite) TestQueryBalance() { acc := app.AccountKeeper.NewAccountWithAddress(ctx, addr) app.AccountKeeper.SetAccount(ctx, acc) - suite.Require().NoError(app.BankKeeper.SetBalances(ctx, acc.GetAddress(), origCoins)) + suite.Require().NoError(simapp.FundAccount(app, ctx, acc.GetAddress(), origCoins)) res, err = queryClient.Balance(gocontext.Background(), req) suite.Require().NoError(err) @@ -64,7 +64,7 @@ func (suite *IntegrationTestSuite) TestQueryAllBalances() { acc := app.AccountKeeper.NewAccountWithAddress(ctx, addr) app.AccountKeeper.SetAccount(ctx, acc) - suite.Require().NoError(app.BankKeeper.SetBalances(ctx, acc.GetAddress(), origCoins)) + suite.Require().NoError(simapp.FundAccount(app, ctx, acc.GetAddress(), origCoins)) res, err = queryClient.AllBalances(gocontext.Background(), req) suite.Require().NoError(err) @@ -91,14 +91,16 @@ func (suite *IntegrationTestSuite) TestQueryAllBalances() { func (suite *IntegrationTestSuite) TestQueryTotalSupply() { app, ctx, queryClient := suite.app, suite.ctx, suite.queryClient - expectedTotalSupply := types.NewSupply(sdk.NewCoins(sdk.NewInt64Coin("test", 400000000))) - app.BankKeeper.SetSupply(ctx, expectedTotalSupply) + expectedTotalSupply := sdk.NewCoins(sdk.NewInt64Coin("test", 400000000)) + suite. + Require(). + NoError(app.BankKeeper.MintCoins(ctx, minttypes.ModuleName, expectedTotalSupply)) res, err := queryClient.TotalSupply(gocontext.Background(), &types.QueryTotalSupplyRequest{}) suite.Require().NoError(err) suite.Require().NotNil(res) - suite.Require().Equal(expectedTotalSupply.Total, res.Supply) + suite.Require().Equal(expectedTotalSupply, res.Supply) } func (suite *IntegrationTestSuite) TestQueryTotalSupplyOf() { @@ -106,8 +108,10 @@ func (suite *IntegrationTestSuite) TestQueryTotalSupplyOf() { test1Supply := sdk.NewInt64Coin("test1", 4000000) test2Supply := sdk.NewInt64Coin("test2", 700000000) - expectedTotalSupply := types.NewSupply(sdk.NewCoins(test1Supply, test2Supply)) - app.BankKeeper.SetSupply(ctx, expectedTotalSupply) + expectedTotalSupply := sdk.NewCoins(test1Supply, test2Supply) + suite. + Require(). + NoError(app.BankKeeper.MintCoins(ctx, minttypes.ModuleName, expectedTotalSupply)) _, err := queryClient.SupplyOf(gocontext.Background(), &types.QuerySupplyOfRequest{}) suite.Require().Error(err) diff --git a/x/bank/keeper/invariants.go b/x/bank/keeper/invariants.go index ed77f8e003..1d671ef568 100644 --- a/x/bank/keeper/invariants.go +++ b/x/bank/keeper/invariants.go @@ -4,6 +4,7 @@ import ( "fmt" sdk "github.com/line/lbm-sdk/types" + "github.com/line/lbm-sdk/types/query" "github.com/line/lbm-sdk/x/bank/types" ) @@ -50,19 +51,24 @@ func NonnegativeBalanceInvariant(k ViewKeeper) sdk.Invariant { func TotalSupply(k Keeper) sdk.Invariant { return func(ctx sdk.Context) (string, bool) { expectedTotal := sdk.Coins{} - supply := k.GetSupply(ctx) + supply, _, err := k.GetPaginatedTotalSupply(ctx, &query.PageRequest{Limit: query.MaxLimit}) + + if err != nil { + return sdk.FormatInvariant(types.ModuleName, "query supply", + fmt.Sprintf("error querying total supply %v", err)), false + } k.IterateAllBalances(ctx, func(_ sdk.AccAddress, balance sdk.Coin) bool { expectedTotal = expectedTotal.Add(balance) return false }) - broken := !expectedTotal.IsEqual(supply.GetTotal()) + broken := !expectedTotal.IsEqual(supply) return sdk.FormatInvariant(types.ModuleName, "total supply", fmt.Sprintf( "\tsum of accounts coins: %v\n"+ "\tsupply.Total: %v\n", - expectedTotal, supply.GetTotal())), broken + expectedTotal, supply)), broken } } diff --git a/x/bank/keeper/keeper.go b/x/bank/keeper/keeper.go index 192892a9eb..0914d5b04c 100644 --- a/x/bank/keeper/keeper.go +++ b/x/bank/keeper/keeper.go @@ -1,15 +1,16 @@ package keeper import ( - "time" + "fmt" "github.com/line/lbm-sdk/codec" + "github.com/line/lbm-sdk/internal/conv" "github.com/line/lbm-sdk/store/prefix" sdk "github.com/line/lbm-sdk/types" sdkerrors "github.com/line/lbm-sdk/types/errors" + "github.com/line/lbm-sdk/types/query" authtypes "github.com/line/lbm-sdk/x/auth/types" vestexported "github.com/line/lbm-sdk/x/auth/vesting/exported" - "github.com/line/lbm-sdk/x/bank/exported" "github.com/line/lbm-sdk/x/bank/types" paramtypes "github.com/line/lbm-sdk/x/params/types" ) @@ -24,10 +25,13 @@ type Keeper interface { InitGenesis(sdk.Context, *types.GenesisState) ExportGenesis(sdk.Context) *types.GenesisState - GetSupply(ctx sdk.Context) exported.SupplyI - SetSupply(ctx sdk.Context, supply exported.SupplyI) + GetSupply(ctx sdk.Context, denom string) sdk.Coin + HasSupply(ctx sdk.Context, denom string) bool + GetPaginatedTotalSupply(ctx sdk.Context, pagination *query.PageRequest) (sdk.Coins, *query.PageResponse, error) + IterateTotalSupply(ctx sdk.Context, cb func(sdk.Coin) bool) + SetSupply(ctx sdk.Context, coin sdk.Coin) // TODO(dudong2): remove after x/wasm version up(>= v0.22.0) - GetDenomMetaData(ctx sdk.Context, denom string) types.Metadata + GetDenomMetaData(ctx sdk.Context, denom string) (types.Metadata, bool) SetDenomMetaData(ctx sdk.Context, denomMetaData types.Metadata) IterateAllDenomMetaData(ctx sdk.Context, cb func(types.Metadata) bool) @@ -41,8 +45,6 @@ type Keeper interface { DelegateCoins(ctx sdk.Context, delegatorAddr, moduleAccAddr sdk.AccAddress, amt sdk.Coins) error UndelegateCoins(ctx sdk.Context, moduleAccAddr, delegatorAddr sdk.AccAddress, amt sdk.Coins) error - MarshalSupply(supplyI exported.SupplyI) ([]byte, error) - UnmarshalSupply(bz []byte) (exported.SupplyI, error) types.QueryServer } @@ -52,13 +54,48 @@ type BaseKeeper struct { BaseSendKeeper ak types.AccountKeeper - cdc codec.BinaryMarshaler + cdc codec.BinaryCodec storeKey sdk.StoreKey - paramSpace *paramtypes.Subspace + paramSpace paramtypes.Subspace } +// GetPaginatedTotalSupply queries for the supply, ignoring 0 coins, with a given pagination +func (k BaseKeeper) GetPaginatedTotalSupply(ctx sdk.Context, pagination *query.PageRequest) (sdk.Coins, *query.PageResponse, error) { + store := ctx.KVStore(k.storeKey) + supplyStore := prefix.NewStore(store, types.SupplyKey) + + supply := sdk.NewCoins() + + pageRes, err := query.Paginate(supplyStore, pagination, func(key, value []byte) error { + var amount sdk.Int + err := amount.Unmarshal(value) + if err != nil { + return fmt.Errorf("unable to convert amount string to Int %v", err) + } + + // `Add` omits the 0 coins addition to the `supply`. + supply = supply.Add(sdk.NewCoin(string(key), amount)) + return nil + }) + + if err != nil { + return nil, nil, err + } + + return supply, pageRes, nil +} + +// NewBaseKeeper returns a new BaseKeeper object with a given codec, dedicated +// store key, an AccountKeeper implementation, and a parameter Subspace used to +// store and fetch module parameters. The BaseKeeper also accepts a +// blocklist map. This blocklist describes the set of addresses that are not allowed +// to receive funds through direct and explicit actions, for example, by using a MsgSend or +// by using a SendCoinsFromModuleToAccount execution. func NewBaseKeeper( - cdc codec.BinaryMarshaler, storeKey sdk.StoreKey, ak types.AccountKeeper, paramSpace *paramtypes.Subspace, + cdc codec.BinaryCodec, + storeKey sdk.StoreKey, + ak types.AccountKeeper, + paramSpace paramtypes.Subspace, blockedAddrs map[string]bool, ) BaseKeeper { @@ -94,7 +131,7 @@ func (k BaseKeeper) DelegateCoins(ctx sdk.Context, delegatorAddr, moduleAccAddr balances := sdk.NewCoins() for _, coin := range amt { - balance := k.GetBalance(ctx, delegatorAddr, coin.Denom) + balance := k.GetBalance(ctx, delegatorAddr, coin.GetDenom()) if balance.IsLT(coin) { return sdkerrors.Wrapf( sdkerrors.ErrInsufficientFunds, "failed to delegate; %s is smaller than %s", balance, amt, @@ -102,17 +139,21 @@ func (k BaseKeeper) DelegateCoins(ctx sdk.Context, delegatorAddr, moduleAccAddr } balances = balances.Add(balance) - err := k.SetBalance(ctx, delegatorAddr, balance.Sub(coin)) + err := k.setBalance(ctx, delegatorAddr, balance.Sub(coin)) if err != nil { return err } } - if err := k.trackDelegation(ctx, delegatorAddr, ctx.BlockHeader().Time, balances, amt); err != nil { + if err := k.trackDelegation(ctx, delegatorAddr, balances, amt); err != nil { return sdkerrors.Wrap(err, "failed to track delegation") } + // emit coin spent event + ctx.EventManager().EmitEvent( + types.NewCoinSpentEvent(delegatorAddr, amt), + ) - err := k.AddCoins(ctx, moduleAccAddr, amt) + err := k.addCoins(ctx, moduleAccAddr, amt) if err != nil { return err } @@ -135,7 +176,7 @@ func (k BaseKeeper) UndelegateCoins(ctx sdk.Context, moduleAccAddr, delegatorAdd return sdkerrors.Wrap(sdkerrors.ErrInvalidCoins, amt.String()) } - err := k.SubtractCoins(ctx, moduleAccAddr, amt) + err := k.subUnlockedCoins(ctx, moduleAccAddr, amt) if err != nil { return err } @@ -144,7 +185,7 @@ func (k BaseKeeper) UndelegateCoins(ctx sdk.Context, moduleAccAddr, delegatorAdd return sdkerrors.Wrap(err, "failed to track undelegation") } - err = k.AddCoins(ctx, delegatorAddr, amt) + err = k.addCoins(ctx, delegatorAddr, amt) if err != nil { return err } @@ -153,48 +194,52 @@ func (k BaseKeeper) UndelegateCoins(ctx sdk.Context, moduleAccAddr, delegatorAdd } // GetSupply retrieves the Supply from store -func (k BaseKeeper) GetSupply(ctx sdk.Context) exported.SupplyI { +func (k BaseKeeper) GetSupply(ctx sdk.Context, denom string) sdk.Coin { store := ctx.KVStore(k.storeKey) - bz := store.Get(types.SupplyKey) + supplyStore := prefix.NewStore(store, types.SupplyKey) + + bz := supplyStore.Get([]byte(denom)) if bz == nil { - panic("stored supply should not have been nil") + return sdk.Coin{ + Denom: denom, + Amount: sdk.NewInt(0), + } } - supply, err := k.UnmarshalSupply(bz) + var amount sdk.Int + err := amount.Unmarshal(bz) if err != nil { - panic(err) + panic(fmt.Errorf("unable to unmarshal supply value %v", err)) } - return supply + return sdk.Coin{ + Denom: denom, + Amount: amount, + } } -// SetSupply sets the Supply to store -func (k BaseKeeper) SetSupply(ctx sdk.Context, supply exported.SupplyI) { +// HasSupply checks if the supply coin exists in store. +func (k BaseKeeper) HasSupply(ctx sdk.Context, denom string) bool { store := ctx.KVStore(k.storeKey) - bz, err := k.MarshalSupply(supply) - if err != nil { - panic(err) - } - - store.Set(types.SupplyKey, bz) + supplyStore := prefix.NewStore(store, types.SupplyKey) + return supplyStore.Has([]byte(denom)) } -// GetDenomMetaData retrieves the denomination metadata -func (k BaseKeeper) GetDenomMetaData(ctx sdk.Context, denom string) types.Metadata { +// GetDenomMetaData retrieves the denomination metadata. returns the metadata and true if the denom exists, +// false otherwise. +func (k BaseKeeper) GetDenomMetaData(ctx sdk.Context, denom string) (types.Metadata, bool) { store := ctx.KVStore(k.storeKey) store = prefix.NewStore(store, types.DenomMetadataKey(denom)) bz := store.Get([]byte(denom)) if bz == nil { - return types.Metadata{} + return types.Metadata{}, false } var metadata types.Metadata - if err := metadata.Unmarshal(bz); err != nil { - panic(err) - } + k.cdc.MustUnmarshal(bz, &metadata) - return metadata + return metadata, true } // GetAllDenomMetaData retrieves all denominations metadata @@ -220,7 +265,7 @@ func (k BaseKeeper) IterateAllDenomMetaData(ctx sdk.Context, cb func(types.Metad for ; iterator.Valid(); iterator.Next() { var metadata types.Metadata - k.cdc.MustUnmarshalBinaryBare(iterator.Value(), &metadata) + k.cdc.MustUnmarshal(iterator.Value(), &metadata) if cb(metadata) { break @@ -233,7 +278,7 @@ func (k BaseKeeper) SetDenomMetaData(ctx sdk.Context, denomMetaData types.Metada store := ctx.KVStore(k.storeKey) denomMetaDataStore := prefix.NewStore(store, types.DenomMetadataKey(denomMetaData.Base)) - m := k.cdc.MustMarshalBinaryBare(&denomMetaData) + m := k.cdc.MustMarshal(&denomMetaData) denomMetaDataStore.Set([]byte(denomMetaData.Base), m) } @@ -329,7 +374,7 @@ func (k BaseKeeper) UndelegateCoinsFromModuleToAccount( // MintCoins creates new coins from thin air and adds it to the module account. // It will panic if the module account does not exist or is unauthorized. -func (k BaseKeeper) MintCoins(ctx sdk.Context, moduleName string, amt sdk.Coins) error { +func (k BaseKeeper) MintCoins(ctx sdk.Context, moduleName string, amounts sdk.Coins) error { acc := k.ak.GetModuleAccount(ctx, moduleName) if acc == nil { panic(sdkerrors.Wrapf(sdkerrors.ErrUnknownAddress, "module account %s does not exist", moduleName)) @@ -339,26 +384,31 @@ func (k BaseKeeper) MintCoins(ctx sdk.Context, moduleName string, amt sdk.Coins) panic(sdkerrors.Wrapf(sdkerrors.ErrUnauthorized, "module account %s does not have permissions to mint tokens", moduleName)) } - err := k.AddCoins(ctx, acc.GetAddress(), amt) + err := k.addCoins(ctx, acc.GetAddress(), amounts) if err != nil { return err } - // update total supply - supply := k.GetSupply(ctx) - supply.Inflate(amt) - - k.SetSupply(ctx, supply) + for _, amount := range amounts { + supply := k.GetSupply(ctx, amount.GetDenom()) + supply = supply.Add(amount) + k.setSupply(ctx, supply) + } logger := k.Logger(ctx) - logger.Info("minted coins from module account", "amount", amt.String(), "from", moduleName) + logger.Info("minted coins from module account", "amount", amounts.String(), "from", moduleName) + + // emit mint event + ctx.EventManager().EmitEvent( + types.NewCoinMintEvent(acc.GetAddress(), amounts), + ) return nil } // BurnCoins burns coins deletes coins from the balance of the module account. // It will panic if the module account does not exist or is unauthorized. -func (k BaseKeeper) BurnCoins(ctx sdk.Context, moduleName string, amt sdk.Coins) error { +func (k BaseKeeper) BurnCoins(ctx sdk.Context, moduleName string, amounts sdk.Coins) error { acc := k.ak.GetModuleAccount(ctx, moduleName) if acc == nil { panic(sdkerrors.Wrapf(sdkerrors.ErrUnknownAddress, "module account %s does not exist", moduleName)) @@ -368,23 +418,66 @@ func (k BaseKeeper) BurnCoins(ctx sdk.Context, moduleName string, amt sdk.Coins) panic(sdkerrors.Wrapf(sdkerrors.ErrUnauthorized, "module account %s does not have permissions to burn tokens", moduleName)) } - err := k.SubtractCoins(ctx, acc.GetAddress(), amt) + err := k.subUnlockedCoins(ctx, acc.GetAddress(), amounts) if err != nil { return err } - // update total supply - supply := k.GetSupply(ctx) - supply.Deflate(amt) - k.SetSupply(ctx, supply) + for _, amount := range amounts { + supply := k.GetSupply(ctx, amount.GetDenom()) + supply = supply.Sub(amount) + k.setSupply(ctx, supply) + } logger := k.Logger(ctx) - logger.Info("burned tokens from module account", "amount", amt.String(), "from", moduleName) + logger.Info("burned tokens from module account", "amount", amounts.String(), "from", moduleName) + + // emit burn event + ctx.EventManager().EmitEvent( + types.NewCoinBurnEvent(acc.GetAddress(), amounts), + ) return nil } -func (k BaseKeeper) trackDelegation(ctx sdk.Context, addr sdk.AccAddress, blockTime time.Time, balance, amt sdk.Coins) error { +// setSupply sets the supply for the given coin +func (k BaseKeeper) setSupply(ctx sdk.Context, coin sdk.Coin) { + intBytes, err := coin.Amount.Marshal() + if err != nil { + panic(fmt.Errorf("unable to marshal amount value %v", err)) + } + + store := ctx.KVStore(k.storeKey) + supplyStore := prefix.NewStore(store, types.SupplyKey) + + // Bank invariants and IBC requires to remove zero coins. + if coin.IsZero() { + supplyStore.Delete(conv.UnsafeStrToBytes(coin.GetDenom())) + } else { + supplyStore.Set([]byte(coin.GetDenom()), intBytes) + } +} + +// SetSupply sets the supply for the given coin +func (k BaseKeeper) SetSupply(ctx sdk.Context, coin sdk.Coin) { + intBytes, err := coin.Amount.Marshal() + if err != nil { + panic(fmt.Errorf("unable to marshal amount value %v", err)) + } + + store := ctx.KVStore(k.storeKey) + supplyStore := prefix.NewStore(store, types.SupplyKey) + + // Bank invariants and IBC requires to remove zero coins. + if coin.IsZero() { + supplyStore.Delete(conv.UnsafeStrToBytes(coin.GetDenom())) + } else { + supplyStore.Set([]byte(coin.GetDenom()), intBytes) + } +} + +// trackDelegation tracks the delegation of the given account if it is a vesting account +func (k BaseKeeper) trackDelegation(ctx sdk.Context, addr sdk.AccAddress, balance, amt sdk.Coins) error { acc := k.ak.GetAccount(ctx, addr) if acc == nil { return sdkerrors.Wrapf(sdkerrors.ErrUnknownAddress, "account %s does not exist", addr) @@ -393,12 +486,14 @@ func (k BaseKeeper) trackDelegation(ctx sdk.Context, addr sdk.AccAddress, blockT vacc, ok := acc.(vestexported.VestingAccount) if ok { // TODO: return error on account.TrackDelegation - vacc.TrackDelegation(blockTime, balance, amt) + vacc.TrackDelegation(ctx.BlockHeader().Time, balance, amt) + k.ak.SetAccount(ctx, acc) } return nil } +// trackUndelegation trakcs undelegation of the given account if it is a vesting account func (k BaseKeeper) trackUndelegation(ctx sdk.Context, addr sdk.AccAddress, amt sdk.Coins) error { acc := k.ak.GetAccount(ctx, addr) if acc == nil { @@ -409,18 +504,36 @@ func (k BaseKeeper) trackUndelegation(ctx sdk.Context, addr sdk.AccAddress, amt if ok { // TODO: return error on account.TrackUndelegation vacc.TrackUndelegation(amt) + k.ak.SetAccount(ctx, acc) } return nil } -// MarshalSupply protobuf serializes a Supply interface -func (k BaseKeeper) MarshalSupply(supplyI exported.SupplyI) ([]byte, error) { - return supplyI.MarshalX() -} +// IterateTotalSupply iterates over the total supply calling the given cb (callback) function +// with the balance of each coin. +// The iteration stops if the callback returns true. +func (k BaseViewKeeper) IterateTotalSupply(ctx sdk.Context, cb func(sdk.Coin) bool) { + store := ctx.KVStore(k.storeKey) + supplyStore := prefix.NewStore(store, types.SupplyKey) + + iterator := supplyStore.Iterator(nil, nil) + defer iterator.Close() -// UnmarshalSupply returns a Supply interface from raw encoded supply -// bytes of a Proto-based Supply type -func (k BaseKeeper) UnmarshalSupply(bz []byte) (exported.SupplyI, error) { - return types.UnmarshalSupplyX(bz) + for ; iterator.Valid(); iterator.Next() { + var amount sdk.Int + err := amount.Unmarshal(iterator.Value()) + if err != nil { + panic(fmt.Errorf("unable to unmarshal supply value %v", err)) + } + + balance := sdk.Coin{ + Denom: string(iterator.Key()), + Amount: amount, + } + + if cb(balance) { + break + } + } } diff --git a/x/bank/keeper/keeper_test.go b/x/bank/keeper/keeper_test.go index 26c380ca5d..4b92c63693 100644 --- a/x/bank/keeper/keeper_test.go +++ b/x/bank/keeper/keeper_test.go @@ -4,19 +4,23 @@ import ( "testing" "time" + "github.com/stretchr/testify/suite" + abci "github.com/line/ostracon/abci/types" ostproto "github.com/line/ostracon/proto/ostracon/types" osttime "github.com/line/ostracon/types/time" - "github.com/stretchr/testify/suite" "github.com/line/lbm-sdk/baseapp" "github.com/line/lbm-sdk/simapp" sdk "github.com/line/lbm-sdk/types" + "github.com/line/lbm-sdk/types/query" authkeeper "github.com/line/lbm-sdk/x/auth/keeper" authtypes "github.com/line/lbm-sdk/x/auth/types" + "github.com/line/lbm-sdk/x/auth/vesting/exported" vesting "github.com/line/lbm-sdk/x/auth/vesting/types" "github.com/line/lbm-sdk/x/bank/keeper" "github.com/line/lbm-sdk/x/bank/types" + minttypes "github.com/line/lbm-sdk/x/mint/types" ) const ( @@ -35,7 +39,8 @@ var ( multiPermAcc = authtypes.NewEmptyModuleAccount(multiPerm, authtypes.Burner, authtypes.Minter, authtypes.Staking) randomPermAcc = authtypes.NewEmptyModuleAccount(randomPerm, "random") - initTokens = sdk.TokensFromConsensusPower(initialPower) + // The default power validators are initialized to have within tests + initTokens = sdk.TokensFromConsensusPower(initialPower, sdk.DefaultPowerReduction) initCoins = sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, initTokens)) ) @@ -66,6 +71,28 @@ type IntegrationTestSuite struct { queryClient types.QueryClient } +func (suite *IntegrationTestSuite) initKeepersWithmAccPerms(blockedAddrs map[string]bool) (authkeeper.AccountKeeper, keeper.BaseKeeper) { + app := suite.app + maccPerms := simapp.GetMaccPerms() + appCodec := simapp.MakeTestEncodingConfig().Marshaler + + maccPerms[holder] = nil + maccPerms[authtypes.Burner] = []string{authtypes.Burner} + maccPerms[authtypes.Minter] = []string{authtypes.Minter} + maccPerms[multiPerm] = []string{authtypes.Burner, authtypes.Minter, authtypes.Staking} + maccPerms[randomPerm] = []string{"random"} + authKeeper := authkeeper.NewAccountKeeper( + appCodec, app.GetKey(types.StoreKey), app.GetSubspace(types.ModuleName), + authtypes.ProtoBaseAccount, maccPerms, + ) + keeper := keeper.NewBaseKeeper( + appCodec, app.GetKey(types.StoreKey), authKeeper, + app.GetSubspace(types.ModuleName), blockedAddrs, + ) + + return authKeeper, keeper +} + func (suite *IntegrationTestSuite) SetupTest() { app := simapp.Setup(false) ctx := app.BaseApp.NewContext(false, ostproto.Header{}) @@ -83,32 +110,49 @@ func (suite *IntegrationTestSuite) SetupTest() { } func (suite *IntegrationTestSuite) TestSupply() { - app, ctx := suite.app, suite.ctx + ctx := suite.ctx - initialPower := int64(100) - initTokens := sdk.TokensFromConsensusPower(initialPower) + require := suite.Require() + + // add module accounts to supply keeper + authKeeper, keeper := suite.initKeepersWithmAccPerms(make(map[string]bool)) + initialPower := int64(100) + initTokens := suite.app.StakingKeeper.TokensFromConsensusPower(ctx, initialPower) totalSupply := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, initTokens)) - app.BankKeeper.SetSupply(ctx, types.NewSupply(totalSupply)) - total := app.BankKeeper.GetSupply(ctx).GetTotal() - suite.Require().Equal(totalSupply, total) + // set burnerAcc balance + authKeeper.SetModuleAccount(ctx, burnerAcc) + require.NoError(keeper.MintCoins(ctx, authtypes.Minter, totalSupply)) + require.NoError(keeper.SendCoinsFromModuleToAccount(ctx, authtypes.Minter, burnerAcc.GetAddress(), totalSupply)) + + total, _, err := keeper.GetPaginatedTotalSupply(ctx, &query.PageRequest{}) + require.NoError(err) + require.Equal(totalSupply, total) + + // burning all supplied tokens + err = keeper.BurnCoins(ctx, authtypes.Burner, totalSupply) + require.NoError(err) + + total, _, err = keeper.GetPaginatedTotalSupply(ctx, &query.PageRequest{}) + require.NoError(err) + require.Equal(total.String(), "") } func (suite *IntegrationTestSuite) TestSendCoinsFromModuleToAccount_Blacklist() { - app := simapp.Setup(false) + app := suite.app ctx := app.BaseApp.NewContext(false, ostproto.Header{Height: 1}) + maccPerms := simapp.GetMaccPerms() appCodec := app.AppCodec() // add module accounts to supply keeper - maccPerms := simapp.GetMaccPerms() maccPerms[holder] = nil maccPerms[authtypes.Burner] = []string{authtypes.Burner} maccPerms[authtypes.Minter] = []string{authtypes.Minter} maccPerms[multiPerm] = []string{authtypes.Burner, authtypes.Minter, authtypes.Staking} maccPerms[randomPerm] = []string{"random"} - addr1 := sdk.AccAddress([]byte("addr1_______________")) + addr1 := sdk.BytesToAccAddress([]byte("addr1_______________")) authKeeper := authkeeper.NewAccountKeeper( appCodec, app.GetKey(types.StoreKey), app.GetSubspace(types.ModuleName), @@ -119,56 +163,43 @@ func (suite *IntegrationTestSuite) TestSendCoinsFromModuleToAccount_Blacklist() app.GetSubspace(types.ModuleName), map[string]bool{addr1.String(): true}, ) - baseAcc := authKeeper.NewAccountWithAddress(ctx, authtypes.NewModuleAddress("baseAcc")) - suite.Require().NoError(keeper.SetBalances(ctx, holderAcc.GetAddress(), initCoins)) - - keeper.SetSupply(ctx, types.NewSupply(initCoins)) - authKeeper.SetModuleAccount(ctx, holderAcc) - authKeeper.SetAccount(ctx, baseAcc) - - suite.Require().Error(keeper.SendCoinsFromModuleToAccount(ctx, holderAcc.GetName(), addr1, initCoins)) + suite.Require().NoError(keeper.MintCoins(ctx, minttypes.ModuleName, initCoins)) + suite.Require().Error(keeper.SendCoinsFromModuleToAccount( + ctx, minttypes.ModuleName, addr1, initCoins, + )) } func (suite *IntegrationTestSuite) TestSupply_SendCoins() { - app := simapp.Setup(false) - ctx := app.BaseApp.NewContext(false, ostproto.Header{Height: 1}) - appCodec := app.AppCodec() + ctx := suite.ctx // add module accounts to supply keeper - maccPerms := simapp.GetMaccPerms() - maccPerms[holder] = nil - maccPerms[authtypes.Burner] = []string{authtypes.Burner} - maccPerms[authtypes.Minter] = []string{authtypes.Minter} - maccPerms[multiPerm] = []string{authtypes.Burner, authtypes.Minter, authtypes.Staking} - maccPerms[randomPerm] = []string{"random"} - - authKeeper := authkeeper.NewAccountKeeper( - appCodec, app.GetKey(types.StoreKey), app.GetSubspace(types.ModuleName), - authtypes.ProtoBaseAccount, maccPerms, - ) - keeper := keeper.NewBaseKeeper( - appCodec, app.GetKey(types.StoreKey), authKeeper, - app.GetSubspace(types.ModuleName), make(map[string]bool), - ) + authKeeper, keeper := suite.initKeepersWithmAccPerms(make(map[string]bool)) baseAcc := authKeeper.NewAccountWithAddress(ctx, authtypes.NewModuleAddress("baseAcc")) - suite.Require().NoError(keeper.SetBalances(ctx, holderAcc.GetAddress(), initCoins)) - keeper.SetSupply(ctx, types.NewSupply(initCoins)) + // set initial balances + suite. + Require(). + NoError(keeper.MintCoins(ctx, minttypes.ModuleName, initCoins)) + + suite. + Require(). + NoError(keeper.SendCoinsFromModuleToAccount(ctx, minttypes.ModuleName, holderAcc.GetAddress(), initCoins)) + authKeeper.SetModuleAccount(ctx, holderAcc) authKeeper.SetModuleAccount(ctx, burnerAcc) authKeeper.SetAccount(ctx, baseAcc) suite.Require().Panics(func() { - keeper.SendCoinsFromModuleToModule(ctx, "", holderAcc.GetName(), initCoins) // nolint:errcheck + _ = keeper.SendCoinsFromModuleToModule(ctx, "", holderAcc.GetName(), initCoins) // nolint:errcheck }) suite.Require().Panics(func() { - keeper.SendCoinsFromModuleToModule(ctx, authtypes.Burner, "", initCoins) // nolint:errcheck + _ = keeper.SendCoinsFromModuleToModule(ctx, authtypes.Burner, "", initCoins) // nolint:errcheck }) suite.Require().Panics(func() { - keeper.SendCoinsFromModuleToAccount(ctx, "", baseAcc.GetAddress(), initCoins) // nolint:errcheck + _ = keeper.SendCoinsFromModuleToAccount(ctx, "", baseAcc.GetAddress(), initCoins) // nolint:errcheck }) suite.Require().Error( @@ -178,53 +209,38 @@ func (suite *IntegrationTestSuite) TestSupply_SendCoins() { suite.Require().NoError( keeper.SendCoinsFromModuleToModule(ctx, holderAcc.GetName(), authtypes.Burner, initCoins), ) - suite.Require().Equal(sdk.Coins(nil), getCoinsByName(ctx, keeper, authKeeper, holderAcc.GetName())) + suite.Require().Equal(sdk.NewCoins().String(), getCoinsByName(ctx, keeper, authKeeper, holderAcc.GetName()).String()) suite.Require().Equal(initCoins, getCoinsByName(ctx, keeper, authKeeper, authtypes.Burner)) suite.Require().NoError( keeper.SendCoinsFromModuleToAccount(ctx, authtypes.Burner, baseAcc.GetAddress(), initCoins), ) - suite.Require().Equal(sdk.Coins(nil), getCoinsByName(ctx, keeper, authKeeper, authtypes.Burner)) + suite.Require().Equal(sdk.NewCoins().String(), getCoinsByName(ctx, keeper, authKeeper, authtypes.Burner).String()) suite.Require().Equal(initCoins, keeper.GetAllBalances(ctx, baseAcc.GetAddress())) suite.Require().NoError(keeper.SendCoinsFromAccountToModule(ctx, baseAcc.GetAddress(), authtypes.Burner, initCoins)) - suite.Require().Equal(sdk.Coins(nil), keeper.GetAllBalances(ctx, baseAcc.GetAddress())) + suite.Require().Equal(sdk.NewCoins().String(), keeper.GetAllBalances(ctx, baseAcc.GetAddress()).String()) suite.Require().Equal(initCoins, getCoinsByName(ctx, keeper, authKeeper, authtypes.Burner)) } func (suite *IntegrationTestSuite) TestSupply_MintCoins() { - app := simapp.Setup(false) - ctx := app.BaseApp.NewContext(false, ostproto.Header{Height: 1}) - appCodec := app.AppCodec() + ctx := suite.ctx // add module accounts to supply keeper - maccPerms := simapp.GetMaccPerms() - maccPerms[holder] = nil - maccPerms[authtypes.Burner] = []string{authtypes.Burner} - maccPerms[authtypes.Minter] = []string{authtypes.Minter} - maccPerms[multiPerm] = []string{authtypes.Burner, authtypes.Minter, authtypes.Staking} - maccPerms[randomPerm] = []string{"random"} - - authKeeper := authkeeper.NewAccountKeeper( - appCodec, app.GetKey(types.StoreKey), app.GetSubspace(types.ModuleName), - authtypes.ProtoBaseAccount, maccPerms, - ) - keeper := keeper.NewBaseKeeper( - appCodec, app.GetKey(types.StoreKey), authKeeper, - app.GetSubspace(types.ModuleName), make(map[string]bool), - ) + authKeeper, keeper := suite.initKeepersWithmAccPerms(make(map[string]bool)) authKeeper.SetModuleAccount(ctx, burnerAcc) authKeeper.SetModuleAccount(ctx, minterAcc) authKeeper.SetModuleAccount(ctx, multiPermAcc) authKeeper.SetModuleAccount(ctx, randomPermAcc) - initialSupply := keeper.GetSupply(ctx) + initialSupply, _, err := keeper.GetPaginatedTotalSupply(ctx, &query.PageRequest{}) + suite.Require().NoError(err) suite.Require().Panics(func() { keeper.MintCoins(ctx, "", initCoins) }, "no module account") // nolint:errcheck suite.Require().Panics(func() { keeper.MintCoins(ctx, authtypes.Burner, initCoins) }, "invalid permission") // nolint:errcheck - err := keeper.MintCoins(ctx, authtypes.Minter, sdk.Coins{sdk.Coin{Denom: "denom", Amount: sdk.NewInt(-10)}}) + err = keeper.MintCoins(ctx, authtypes.Minter, sdk.Coins{sdk.Coin{Denom: "denom", Amount: sdk.NewInt(-10)}}) suite.Require().Error(err, "insufficient coins") suite.Require().Panics(func() { keeper.MintCoins(ctx, randomPerm, initCoins) }) // nolint:errcheck @@ -233,72 +249,74 @@ func (suite *IntegrationTestSuite) TestSupply_MintCoins() { suite.Require().NoError(err) suite.Require().Equal(initCoins, getCoinsByName(ctx, keeper, authKeeper, authtypes.Minter)) - suite.Require().Equal(initialSupply.GetTotal().Add(initCoins...), keeper.GetSupply(ctx).GetTotal()) + totalSupply, _, err := keeper.GetPaginatedTotalSupply(ctx, &query.PageRequest{}) + suite.Require().NoError(err) + + suite.Require().Equal(initialSupply.Add(initCoins...), totalSupply) // test same functionality on module account with multiple permissions - initialSupply = keeper.GetSupply(ctx) + initialSupply, _, err = keeper.GetPaginatedTotalSupply(ctx, &query.PageRequest{}) + suite.Require().NoError(err) err = keeper.MintCoins(ctx, multiPermAcc.GetName(), initCoins) suite.Require().NoError(err) + totalSupply, _, err = keeper.GetPaginatedTotalSupply(ctx, &query.PageRequest{}) + suite.Require().NoError(err) suite.Require().Equal(initCoins, getCoinsByName(ctx, keeper, authKeeper, multiPermAcc.GetName())) - suite.Require().Equal(initialSupply.GetTotal().Add(initCoins...), keeper.GetSupply(ctx).GetTotal()) + suite.Require().Equal(initialSupply.Add(initCoins...), totalSupply) suite.Require().Panics(func() { keeper.MintCoins(ctx, authtypes.Burner, initCoins) }) // nolint:errcheck } func (suite *IntegrationTestSuite) TestSupply_BurnCoins() { - app := simapp.Setup(false) - ctx := app.BaseApp.NewContext(false, ostproto.Header{Height: 1}) - appCodec, _ := simapp.MakeCodecs() - + ctx := suite.ctx // add module accounts to supply keeper - maccPerms := simapp.GetMaccPerms() - maccPerms[holder] = nil - maccPerms[authtypes.Burner] = []string{authtypes.Burner} - maccPerms[authtypes.Minter] = []string{authtypes.Minter} - maccPerms[multiPerm] = []string{authtypes.Burner, authtypes.Minter, authtypes.Staking} - maccPerms[randomPerm] = []string{"random"} - - authKeeper := authkeeper.NewAccountKeeper( - appCodec, app.GetKey(types.StoreKey), app.GetSubspace(types.ModuleName), - authtypes.ProtoBaseAccount, maccPerms, - ) - keeper := keeper.NewBaseKeeper( - appCodec, app.GetKey(types.StoreKey), authKeeper, - app.GetSubspace(types.ModuleName), make(map[string]bool), - ) + authKeeper, keeper := suite.initKeepersWithmAccPerms(make(map[string]bool)) - suite.Require().NoError(keeper.SetBalances(ctx, burnerAcc.GetAddress(), initCoins)) - keeper.SetSupply(ctx, types.NewSupply(initCoins)) + // set burnerAcc balance authKeeper.SetModuleAccount(ctx, burnerAcc) - - initialSupply := keeper.GetSupply(ctx) - initialSupply.Inflate(initCoins) - keeper.SetSupply(ctx, initialSupply) - - suite.Require().Panics(func() { keeper.BurnCoins(ctx, "", initCoins) }, "no module account") // nolint:errcheck - suite.Require().Panics(func() { keeper.BurnCoins(ctx, authtypes.Minter, initCoins) }, "invalid permission") // nolint:errcheck - suite.Require().Panics(func() { keeper.BurnCoins(ctx, randomPerm, initialSupply.GetTotal()) }, "random permission") // nolint:errcheck - err := keeper.BurnCoins(ctx, authtypes.Burner, initialSupply.GetTotal()) + suite. + Require(). + NoError(keeper.MintCoins(ctx, authtypes.Minter, initCoins)) + suite. + Require(). + NoError(keeper.SendCoinsFromModuleToAccount(ctx, authtypes.Minter, burnerAcc.GetAddress(), initCoins)) + + // inflate supply + suite. + Require(). + NoError(keeper.MintCoins(ctx, authtypes.Minter, initCoins)) + supplyAfterInflation, _, err := keeper.GetPaginatedTotalSupply(ctx, &query.PageRequest{}) + + suite.Require().Panics(func() { keeper.BurnCoins(ctx, "", initCoins) }, "no module account") // nolint:errcheck + suite.Require().Panics(func() { keeper.BurnCoins(ctx, authtypes.Minter, initCoins) }, "invalid permission") // nolint:errcheck + suite.Require().Panics(func() { keeper.BurnCoins(ctx, randomPerm, supplyAfterInflation) }, "random permission") // nolint:errcheck + err = keeper.BurnCoins(ctx, authtypes.Burner, supplyAfterInflation) suite.Require().Error(err, "insufficient coins") err = keeper.BurnCoins(ctx, authtypes.Burner, initCoins) suite.Require().NoError(err) - suite.Require().Equal(sdk.Coins(nil), getCoinsByName(ctx, keeper, authKeeper, authtypes.Burner)) - suite.Require().Equal(initialSupply.GetTotal().Sub(initCoins), keeper.GetSupply(ctx).GetTotal()) + supplyAfterBurn, _, err := keeper.GetPaginatedTotalSupply(ctx, &query.PageRequest{}) + suite.Require().NoError(err) + suite.Require().Equal(sdk.NewCoins().String(), getCoinsByName(ctx, keeper, authKeeper, authtypes.Burner).String()) + suite.Require().Equal(supplyAfterInflation.Sub(initCoins), supplyAfterBurn) // test same functionality on module account with multiple permissions - initialSupply = keeper.GetSupply(ctx) - initialSupply.Inflate(initCoins) - keeper.SetSupply(ctx, initialSupply) + suite. + Require(). + NoError(keeper.MintCoins(ctx, authtypes.Minter, initCoins)) - suite.Require().NoError(keeper.SetBalances(ctx, multiPermAcc.GetAddress(), initCoins)) + supplyAfterInflation, _, err = keeper.GetPaginatedTotalSupply(ctx, &query.PageRequest{}) + suite.Require().NoError(err) + suite.Require().NoError(keeper.SendCoins(ctx, authtypes.NewModuleAddress(authtypes.Minter), multiPermAcc.GetAddress(), initCoins)) authKeeper.SetModuleAccount(ctx, multiPermAcc) err = keeper.BurnCoins(ctx, multiPermAcc.GetName(), initCoins) + supplyAfterBurn, _, err = keeper.GetPaginatedTotalSupply(ctx, &query.PageRequest{}) suite.Require().NoError(err) - suite.Require().Equal(sdk.Coins(nil), getCoinsByName(ctx, keeper, authKeeper, multiPermAcc.GetName())) - suite.Require().Equal(initialSupply.GetTotal().Sub(initCoins), keeper.GetSupply(ctx).GetTotal()) + suite.Require().NoError(err) + suite.Require().Equal(sdk.NewCoins().String(), getCoinsByName(ctx, keeper, authKeeper, multiPermAcc.GetName()).String()) + suite.Require().Equal(supplyAfterInflation.Sub(initCoins), supplyAfterBurn) } func (suite *IntegrationTestSuite) TestSendCoinsNewAccount() { @@ -308,7 +326,7 @@ func (suite *IntegrationTestSuite) TestSendCoinsNewAccount() { addr1 := sdk.AccAddress([]byte("addr1_______________")) acc1 := app.AccountKeeper.NewAccountWithAddress(ctx, addr1) app.AccountKeeper.SetAccount(ctx, acc1) - suite.Require().NoError(app.BankKeeper.SetBalances(ctx, addr1, balances)) + suite.Require().NoError(simapp.FundAccount(app, ctx, addr1, balances)) acc1Balances := app.BankKeeper.GetAllBalances(ctx, addr1) suite.Require().Equal(balances, acc1Balances) @@ -319,11 +337,15 @@ func (suite *IntegrationTestSuite) TestSendCoinsNewAccount() { app.BankKeeper.GetAllBalances(ctx, addr2) suite.Require().Empty(app.BankKeeper.GetAllBalances(ctx, addr2)) - sendAmt := sdk.NewCoins(newFooCoin(50), newBarCoin(25)) + sendAmt := sdk.NewCoins(newFooCoin(50), newBarCoin(50)) suite.Require().NoError(app.BankKeeper.SendCoins(ctx, addr1, addr2, sendAmt)) acc2Balances := app.BankKeeper.GetAllBalances(ctx, addr2) + acc1Balances = app.BankKeeper.GetAllBalances(ctx, addr1) suite.Require().Equal(sendAmt, acc2Balances) + updatedAcc1Bal := balances.Sub(sendAmt) + suite.Require().Len(acc1Balances, len(updatedAcc1Bal)) + suite.Require().Equal(acc1Balances, updatedAcc1Bal) suite.Require().NotNil(app.AccountKeeper.GetAccount(ctx, addr2)) } @@ -334,7 +356,7 @@ func (suite *IntegrationTestSuite) TestInputOutputNewAccount() { addr1 := sdk.BytesToAccAddress([]byte("addr1_______________")) acc1 := app.AccountKeeper.NewAccountWithAddress(ctx, addr1) app.AccountKeeper.SetAccount(ctx, acc1) - suite.Require().NoError(app.BankKeeper.SetBalances(ctx, addr1, balances)) + suite.Require().NoError(simapp.FundAccount(app, ctx, addr1, balances)) acc1Balances := app.BankKeeper.GetAllBalances(ctx, addr1) suite.Require().Equal(balances, acc1Balances) @@ -387,7 +409,7 @@ func (suite *IntegrationTestSuite) TestInputOutputCoins() { suite.Require().Error(app.BankKeeper.InputOutputCoins(ctx, inputs, []types.Output{})) suite.Require().Error(app.BankKeeper.InputOutputCoins(ctx, inputs, outputs)) - suite.Require().NoError(app.BankKeeper.SetBalances(ctx, addr1, balances)) + suite.Require().NoError(simapp.FundAccount(app, ctx, addr1, balances)) insufficientInputs := []types.Input{ {Address: addr1.String(), Coins: sdk.NewCoins(newFooCoin(300), newBarCoin(100))}, @@ -415,19 +437,19 @@ func (suite *IntegrationTestSuite) TestSendCoins() { app, ctx := suite.app, suite.ctx balances := sdk.NewCoins(newFooCoin(100), newBarCoin(50)) - addr1 := sdk.AccAddress([]byte("addr1_______________")) + addr1 := sdk.AccAddress("addr1_______________") acc1 := app.AccountKeeper.NewAccountWithAddress(ctx, addr1) app.AccountKeeper.SetAccount(ctx, acc1) - addr2 := sdk.AccAddress([]byte("addr2_______________")) + addr2 := sdk.AccAddress("addr2_______________") acc2 := app.AccountKeeper.NewAccountWithAddress(ctx, addr2) app.AccountKeeper.SetAccount(ctx, acc2) - suite.Require().NoError(app.BankKeeper.SetBalances(ctx, addr2, balances)) + suite.Require().NoError(simapp.FundAccount(app, ctx, addr2, balances)) sendAmt := sdk.NewCoins(newFooCoin(50), newBarCoin(25)) suite.Require().Error(app.BankKeeper.SendCoins(ctx, addr1, addr2, sendAmt)) - suite.Require().NoError(app.BankKeeper.SetBalances(ctx, addr1, balances)) + suite.Require().NoError(simapp.FundAccount(app, ctx, addr1, balances)) suite.Require().NoError(app.BankKeeper.SendCoins(ctx, addr1, addr2, sendAmt)) acc1Balances := app.BankKeeper.GetAllBalances(ctx, addr1) @@ -437,6 +459,15 @@ func (suite *IntegrationTestSuite) TestSendCoins() { acc2Balances := app.BankKeeper.GetAllBalances(ctx, addr2) expected = sdk.NewCoins(newFooCoin(150), newBarCoin(75)) suite.Require().Equal(expected, acc2Balances) + + // we sent all foo coins to acc2, so foo balance should be deleted for acc1 and bar should be still there + var coins []sdk.Coin + app.BankKeeper.IterateAccountBalances(ctx, addr1, func(c sdk.Coin) (stop bool) { + coins = append(coins, c) + return true + }) + suite.Require().Len(coins, 1) + suite.Require().Equal(newBarCoin(25), coins[0], "expected only bar coins in the account balance, got: %v", coins) } func (suite *IntegrationTestSuite) TestValidateBalance() { @@ -454,45 +485,17 @@ func (suite *IntegrationTestSuite) TestValidateBalance() { app.AccountKeeper.SetAccount(ctx, acc) balances := sdk.NewCoins(newFooCoin(100)) - suite.Require().NoError(app.BankKeeper.SetBalances(ctx, addr1, balances)) + suite.Require().NoError(simapp.FundAccount(app, ctx, addr1, balances)) suite.Require().NoError(app.BankKeeper.ValidateBalance(ctx, addr1)) bacc := authtypes.NewBaseAccountWithAddress(addr2) vacc := vesting.NewContinuousVestingAccount(bacc, balances.Add(balances...), now.Unix(), endTime.Unix()) app.AccountKeeper.SetAccount(ctx, vacc) - suite.Require().NoError(app.BankKeeper.SetBalances(ctx, addr2, balances)) + suite.Require().NoError(simapp.FundAccount(app, ctx, addr2, balances)) suite.Require().Error(app.BankKeeper.ValidateBalance(ctx, addr2)) } -func (suite *IntegrationTestSuite) TestBalance() { - app, ctx := suite.app, suite.ctx - addr := sdk.AccAddress([]byte("addr1_______________")) - - acc := app.AccountKeeper.NewAccountWithAddress(ctx, addr) - app.AccountKeeper.SetAccount(ctx, acc) - - suite.Require().Equal(sdk.NewCoin(fooDenom, sdk.ZeroInt()), app.BankKeeper.GetBalance(ctx, addr, fooDenom)) - balances := sdk.NewCoins(newFooCoin(100)) - suite.Require().NoError(app.BankKeeper.SetBalances(ctx, addr, balances)) - - suite.Require().Equal(balances.AmountOf(fooDenom), app.BankKeeper.GetBalance(ctx, addr, fooDenom).Amount) - suite.Require().Equal(balances, app.BankKeeper.GetAllBalances(ctx, addr)) - - newFooBalance := newFooCoin(99) - suite.Require().NoError(app.BankKeeper.SetBalance(ctx, addr, newFooBalance)) - suite.Require().Equal(newFooBalance, app.BankKeeper.GetBalance(ctx, addr, fooDenom)) - - balances = sdk.NewCoins(newBarCoin(500)) - suite.Require().NoError(app.BankKeeper.SetBalances(ctx, addr, balances)) - suite.Require().Equal(sdk.NewCoin(fooDenom, sdk.ZeroInt()), app.BankKeeper.GetBalance(ctx, addr, fooDenom)) - suite.Require().Equal(balances.AmountOf(barDenom), app.BankKeeper.GetBalance(ctx, addr, barDenom).Amount) - suite.Require().Equal(balances, app.BankKeeper.GetAllBalances(ctx, addr)) - - invalidBalance := sdk.Coin{Denom: "fooDenom", Amount: sdk.NewInt(-50)} - suite.Require().Error(app.BankKeeper.SetBalance(ctx, addr, invalidBalance)) -} - func (suite *IntegrationTestSuite) TestSendEnabled() { app, ctx := suite.app, suite.ctx enabled := true @@ -506,11 +509,11 @@ func (suite *IntegrationTestSuite) TestSendEnabled() { barCoin := sdk.NewCoin("barcoin", sdk.OneInt()) // assert with default (all denom) send enabled both Bar and Bond Denom are enabled - suite.Require().Equal(enabled, app.BankKeeper.SendEnabledCoin(ctx, barCoin)) - suite.Require().Equal(enabled, app.BankKeeper.SendEnabledCoin(ctx, bondCoin)) + suite.Require().Equal(enabled, app.BankKeeper.IsSendEnabledCoin(ctx, barCoin)) + suite.Require().Equal(enabled, app.BankKeeper.IsSendEnabledCoin(ctx, bondCoin)) // Both coins should be send enabled. - err := app.BankKeeper.SendEnabledCoins(ctx, fooCoin, bondCoin) + err := app.BankKeeper.IsSendEnabledCoins(ctx, fooCoin, bondCoin) suite.Require().NoError(err) // Set default send_enabled to !enabled, add a foodenom that overrides default as enabled @@ -519,20 +522,20 @@ func (suite *IntegrationTestSuite) TestSendEnabled() { app.BankKeeper.SetParams(ctx, params) // Expect our specific override to be enabled, others to be !enabled. - suite.Require().Equal(enabled, app.BankKeeper.SendEnabledCoin(ctx, fooCoin)) - suite.Require().Equal(!enabled, app.BankKeeper.SendEnabledCoin(ctx, barCoin)) - suite.Require().Equal(!enabled, app.BankKeeper.SendEnabledCoin(ctx, bondCoin)) + suite.Require().Equal(enabled, app.BankKeeper.IsSendEnabledCoin(ctx, fooCoin)) + suite.Require().Equal(!enabled, app.BankKeeper.IsSendEnabledCoin(ctx, barCoin)) + suite.Require().Equal(!enabled, app.BankKeeper.IsSendEnabledCoin(ctx, bondCoin)) // Foo coin should be send enabled. - err = app.BankKeeper.SendEnabledCoins(ctx, fooCoin) + err = app.BankKeeper.IsSendEnabledCoins(ctx, fooCoin) suite.Require().NoError(err) // Expect an error when one coin is not send enabled. - err = app.BankKeeper.SendEnabledCoins(ctx, fooCoin, bondCoin) + err = app.BankKeeper.IsSendEnabledCoins(ctx, fooCoin, bondCoin) suite.Require().Error(err) // Expect an error when all coins are not send enabled. - err = app.BankKeeper.SendEnabledCoins(ctx, bondCoin, barCoin) + err = app.BankKeeper.IsSendEnabledCoins(ctx, bondCoin, barCoin) suite.Require().Error(err) } @@ -546,7 +549,7 @@ func (suite *IntegrationTestSuite) TestHasBalance() { balances := sdk.NewCoins(newFooCoin(100)) suite.Require().False(app.BankKeeper.HasBalance(ctx, addr, newFooCoin(99))) - app.BankKeeper.SetBalances(ctx, addr, balances) + suite.Require().NoError(simapp.FundAccount(app, ctx, addr, balances)) suite.Require().False(app.BankKeeper.HasBalance(ctx, addr, newFooCoin(101))) suite.Require().True(app.BankKeeper.HasBalance(ctx, addr, newFooCoin(100))) suite.Require().True(app.BankKeeper.HasBalance(ctx, addr, newFooCoin(1))) @@ -560,12 +563,9 @@ func (suite *IntegrationTestSuite) TestMsgSendEvents() { app.AccountKeeper.SetAccount(ctx, acc) newCoins := sdk.NewCoins(sdk.NewInt64Coin(fooDenom, 50)) + suite.Require().NoError(simapp.FundAccount(app, ctx, addr, newCoins)) - suite.Require().Error(app.BankKeeper.SendCoins(ctx, addr, addr2, newCoins)) - - events := ctx.EventManager().ABCIEvents() - suite.Require().Equal(2, len(events)) - + suite.Require().NoError(app.BankKeeper.SendCoins(ctx, addr, addr2, newCoins)) event1 := sdk.Event{ Type: types.EventTypeTransfer, Attributes: []abci.EventAttribute{}, @@ -582,6 +582,7 @@ func (suite *IntegrationTestSuite) TestMsgSendEvents() { event1.Attributes, abci.EventAttribute{Key: []byte(sdk.AttributeKeyAmount), Value: []byte(newCoins.String())}, ) + event2 := sdk.Event{ Type: sdk.EventTypeMessage, Attributes: []abci.EventAttribute{}, @@ -591,18 +592,11 @@ func (suite *IntegrationTestSuite) TestMsgSendEvents() { abci.EventAttribute{Key: []byte(types.AttributeKeySender), Value: []byte(addr.String())}, ) - suite.Require().Equal(abci.Event(event1), events[0]) - suite.Require().Equal(abci.Event(event2), events[1]) - - app.BankKeeper.SetBalances(ctx, addr, sdk.NewCoins(sdk.NewInt64Coin(fooDenom, 50))) - newCoins = sdk.NewCoins(sdk.NewInt64Coin(fooDenom, 50)) - - suite.Require().NoError(app.BankKeeper.SendCoins(ctx, addr, addr2, newCoins)) - - events = ctx.EventManager().ABCIEvents() - suite.Require().Equal(4, len(events)) - suite.Require().Equal(abci.Event(event1), events[2]) - suite.Require().Equal(abci.Event(event2), events[3]) + // events are shifted due to the funding account events + events := ctx.EventManager().ABCIEvents() + suite.Require().Equal(10, len(events)) + suite.Require().Equal(abci.Event(event1), events[8]) + suite.Require().Equal(abci.Event(event2), events[9]) } func (suite *IntegrationTestSuite) TestMsgMultiSendEvents() { @@ -637,12 +631,11 @@ func (suite *IntegrationTestSuite) TestMsgMultiSendEvents() { suite.Require().Equal(0, len(events)) // Set addr's coins but not addr2's coins - app.BankKeeper.SetBalances(ctx, addr, sdk.NewCoins(sdk.NewInt64Coin(fooDenom, 50))) - + suite.Require().NoError(simapp.FundAccount(app, ctx, addr, sdk.NewCoins(sdk.NewInt64Coin(fooDenom, 50)))) suite.Require().Error(app.BankKeeper.InputOutputCoins(ctx, inputs, outputs)) events = ctx.EventManager().ABCIEvents() - suite.Require().Equal(1, len(events)) + suite.Require().Equal(8, len(events)) // 7 events because account funding causes extra minting + coin_spent + coin_recv events event1 := sdk.Event{ Type: sdk.EventTypeMessage, @@ -652,19 +645,19 @@ func (suite *IntegrationTestSuite) TestMsgMultiSendEvents() { event1.Attributes, abci.EventAttribute{Key: []byte(types.AttributeKeySender), Value: []byte(addr.String())}, ) - suite.Require().Equal(abci.Event(event1), events[0]) + suite.Require().Equal(abci.Event(event1), events[7]) // Set addr's coins and addr2's coins - app.BankKeeper.SetBalances(ctx, addr, sdk.NewCoins(sdk.NewInt64Coin(fooDenom, 50))) + suite.Require().NoError(simapp.FundAccount(app, ctx, addr, sdk.NewCoins(sdk.NewInt64Coin(fooDenom, 50)))) newCoins = sdk.NewCoins(sdk.NewInt64Coin(fooDenom, 50)) - app.BankKeeper.SetBalances(ctx, addr2, sdk.NewCoins(sdk.NewInt64Coin(barDenom, 100))) + suite.Require().NoError(simapp.FundAccount(app, ctx, addr2, sdk.NewCoins(sdk.NewInt64Coin(barDenom, 100)))) newCoins2 = sdk.NewCoins(sdk.NewInt64Coin(barDenom, 100)) suite.Require().NoError(app.BankKeeper.InputOutputCoins(ctx, inputs, outputs)) events = ctx.EventManager().ABCIEvents() - suite.Require().Equal(5, len(events)) + suite.Require().Equal(28, len(events)) // 25 due to account funding + coin_spent + coin_recv events event2 := sdk.Event{ Type: sdk.EventTypeMessage, @@ -697,11 +690,11 @@ func (suite *IntegrationTestSuite) TestMsgMultiSendEvents() { event4.Attributes, abci.EventAttribute{Key: []byte(sdk.AttributeKeyAmount), Value: []byte(newCoins2.String())}, ) - - suite.Require().Equal(abci.Event(event1), events[1]) - suite.Require().Equal(abci.Event(event2), events[2]) - suite.Require().Equal(abci.Event(event3), events[3]) - suite.Require().Equal(abci.Event(event4), events[4]) + // events are shifted due to the funding account events + suite.Require().Equal(abci.Event(event1), events[21]) + suite.Require().Equal(abci.Event(event2), events[23]) + suite.Require().Equal(abci.Event(event3), events[25]) + suite.Require().Equal(abci.Event(event4), events[27]) } func (suite *IntegrationTestSuite) TestSpendableCoins() { @@ -725,8 +718,8 @@ func (suite *IntegrationTestSuite) TestSpendableCoins() { app.AccountKeeper.SetAccount(ctx, macc) app.AccountKeeper.SetAccount(ctx, vacc) app.AccountKeeper.SetAccount(ctx, acc) - suite.Require().NoError(app.BankKeeper.SetBalances(ctx, addr1, origCoins)) - suite.Require().NoError(app.BankKeeper.SetBalances(ctx, addr2, origCoins)) + suite.Require().NoError(simapp.FundAccount(app, ctx, addr1, origCoins)) + suite.Require().NoError(simapp.FundAccount(app, ctx, addr2, origCoins)) suite.Require().Equal(origCoins, app.BankKeeper.SpendableCoins(ctx, addr2)) @@ -751,14 +744,13 @@ func (suite *IntegrationTestSuite) TestVestingAccountSend() { vacc := vesting.NewContinuousVestingAccount(bacc, origCoins, now.Unix(), endTime.Unix()) app.AccountKeeper.SetAccount(ctx, vacc) - suite.Require().NoError(app.BankKeeper.SetBalances(ctx, addr1, origCoins)) + suite.Require().NoError(simapp.FundAccount(app, ctx, addr1, origCoins)) // require that no coins be sendable at the beginning of the vesting schedule suite.Require().Error(app.BankKeeper.SendCoins(ctx, addr1, addr2, sendCoins)) // receive some coins - suite.Require().NoError(app.BankKeeper.SetBalances(ctx, addr1, origCoins.Add(sendCoins...))) - + suite.Require().NoError(simapp.FundAccount(app, ctx, addr1, sendCoins)) // require that all vested coins are spendable plus any received ctx = ctx.WithBlockTime(now.Add(12 * time.Hour)) suite.Require().NoError(app.BankKeeper.SendCoins(ctx, addr1, addr2, sendCoins)) @@ -784,13 +776,13 @@ func (suite *IntegrationTestSuite) TestPeriodicVestingAccountSend() { vacc := vesting.NewPeriodicVestingAccount(bacc, origCoins, ctx.BlockHeader().Time.Unix(), periods) app.AccountKeeper.SetAccount(ctx, vacc) - suite.Require().NoError(app.BankKeeper.SetBalances(ctx, addr1, origCoins)) + suite.Require().NoError(simapp.FundAccount(app, ctx, addr1, origCoins)) // require that no coins be sendable at the beginning of the vesting schedule suite.Require().Error(app.BankKeeper.SendCoins(ctx, addr1, addr2, sendCoins)) // receive some coins - suite.Require().NoError(app.BankKeeper.SetBalances(ctx, addr1, origCoins.Add(sendCoins...))) + suite.Require().NoError(simapp.FundAccount(app, ctx, addr1, sendCoins)) // require that all vested coins are spendable plus any received ctx = ctx.WithBlockTime(now.Add(12 * time.Hour)) @@ -816,8 +808,8 @@ func (suite *IntegrationTestSuite) TestVestingAccountReceive() { app.AccountKeeper.SetAccount(ctx, vacc) app.AccountKeeper.SetAccount(ctx, acc) - suite.Require().NoError(app.BankKeeper.SetBalances(ctx, addr1, origCoins)) - suite.Require().NoError(app.BankKeeper.SetBalances(ctx, addr2, origCoins)) + suite.Require().NoError(simapp.FundAccount(app, ctx, addr1, origCoins)) + suite.Require().NoError(simapp.FundAccount(app, ctx, addr2, origCoins)) // send some coins to the vesting account suite.Require().NoError(app.BankKeeper.SendCoins(ctx, addr2, addr1, sendCoins)) @@ -855,8 +847,8 @@ func (suite *IntegrationTestSuite) TestPeriodicVestingAccountReceive() { app.AccountKeeper.SetAccount(ctx, vacc) app.AccountKeeper.SetAccount(ctx, acc) - suite.Require().NoError(app.BankKeeper.SetBalances(ctx, addr1, origCoins)) - suite.Require().NoError(app.BankKeeper.SetBalances(ctx, addr2, origCoins)) + suite.Require().NoError(simapp.FundAccount(app, ctx, addr1, origCoins)) + suite.Require().NoError(simapp.FundAccount(app, ctx, addr2, origCoins)) // send some coins to the vesting account suite.Require().NoError(app.BankKeeper.SendCoins(ctx, addr2, addr1, sendCoins)) @@ -892,8 +884,8 @@ func (suite *IntegrationTestSuite) TestDelegateCoins() { app.AccountKeeper.SetAccount(ctx, vacc) app.AccountKeeper.SetAccount(ctx, acc) app.AccountKeeper.SetAccount(ctx, macc) - suite.Require().NoError(app.BankKeeper.SetBalances(ctx, addr1, origCoins)) - suite.Require().NoError(app.BankKeeper.SetBalances(ctx, addr2, origCoins)) + suite.Require().NoError(simapp.FundAccount(app, ctx, addr1, origCoins)) + suite.Require().NoError(simapp.FundAccount(app, ctx, addr2, origCoins)) ctx = ctx.WithBlockTime(now.Add(12 * time.Hour)) @@ -905,6 +897,12 @@ func (suite *IntegrationTestSuite) TestDelegateCoins() { // require the ability for a vesting account to delegate suite.Require().NoError(app.BankKeeper.DelegateCoins(ctx, addr1, addrModule, delCoins)) suite.Require().Equal(delCoins, app.BankKeeper.GetAllBalances(ctx, addr1)) + + // require that delegated vesting amount is equal to what was delegated with DelegateCoins + acc = app.AccountKeeper.GetAccount(ctx, addr1) + vestingAcc, ok := acc.(exported.VestingAccount) + suite.Require().True(ok) + suite.Require().Equal(delCoins, vestingAcc.GetDelegatedVesting()) } func (suite *IntegrationTestSuite) TestDelegateCoins_Invalid() { @@ -923,11 +921,8 @@ func (suite *IntegrationTestSuite) TestDelegateCoins_Invalid() { suite.Require().Error(app.BankKeeper.DelegateCoins(ctx, addr1, addrModule, invalidCoins)) app.AccountKeeper.SetAccount(ctx, macc) - suite.Require().NoError(app.BankKeeper.SetBalances(ctx, addr1, origCoins)) - suite.Require().Error(app.BankKeeper.DelegateCoins(ctx, addr1, addrModule, delCoins)) app.AccountKeeper.SetAccount(ctx, acc) - suite.Require().Error(app.BankKeeper.DelegateCoins(ctx, addr1, addrModule, origCoins.Add(origCoins...))) } @@ -953,8 +948,8 @@ func (suite *IntegrationTestSuite) TestUndelegateCoins() { app.AccountKeeper.SetAccount(ctx, vacc) app.AccountKeeper.SetAccount(ctx, acc) app.AccountKeeper.SetAccount(ctx, macc) - suite.Require().NoError(app.BankKeeper.SetBalances(ctx, addr1, origCoins)) - suite.Require().NoError(app.BankKeeper.SetBalances(ctx, addr2, origCoins)) + suite.Require().NoError(simapp.FundAccount(app, ctx, addr1, origCoins)) + suite.Require().NoError(simapp.FundAccount(app, ctx, addr2, origCoins)) ctx = ctx.WithBlockTime(now.Add(12 * time.Hour)) @@ -982,6 +977,12 @@ func (suite *IntegrationTestSuite) TestUndelegateCoins() { suite.Require().Equal(origCoins, app.BankKeeper.GetAllBalances(ctx, addr1)) suite.Require().True(app.BankKeeper.GetAllBalances(ctx, addrModule).Empty()) + + // require that delegated vesting amount is completely empty, since they were completely undelegated + acc = app.AccountKeeper.GetAccount(ctx, addr1) + vestingAcc, ok := acc.(exported.VestingAccount) + suite.Require().True(ok) + suite.Require().Empty(vestingAcc.GetDelegatedVesting()) } func (suite *IntegrationTestSuite) TestUndelegateCoins_Invalid() { @@ -998,7 +999,7 @@ func (suite *IntegrationTestSuite) TestUndelegateCoins_Invalid() { suite.Require().Error(app.BankKeeper.UndelegateCoins(ctx, addrModule, addr1, delCoins)) app.AccountKeeper.SetAccount(ctx, macc) - suite.Require().NoError(app.BankKeeper.SetBalances(ctx, addr1, origCoins)) + suite.Require().NoError(simapp.FundAccount(app, ctx, addr1, origCoins)) suite.Require().Error(app.BankKeeper.UndelegateCoins(ctx, addrModule, addr1, delCoins)) app.AccountKeeper.SetAccount(ctx, acc) @@ -1015,7 +1016,8 @@ func (suite *IntegrationTestSuite) TestSetDenomMetaData() { app.BankKeeper.SetDenomMetaData(ctx, metadata[i]) } - actualMetadata := app.BankKeeper.GetDenomMetaData(ctx, metadata[1].Base) + actualMetadata, found := app.BankKeeper.GetDenomMetaData(ctx, metadata[1].Base) + suite.Require().True(found) suite.Require().Equal(metadata[1].GetBase(), actualMetadata.GetBase()) suite.Require().Equal(metadata[1].GetDisplay(), actualMetadata.GetDisplay()) suite.Require().Equal(metadata[1].GetDescription(), actualMetadata.GetDescription()) @@ -1049,8 +1051,110 @@ func (suite *IntegrationTestSuite) TestIterateAllDenomMetaData() { } } +func (suite *IntegrationTestSuite) TestBalanceTrackingEvents() { + // replace account keeper and bank keeper otherwise the account keeper won't be aware of the + // existence of the new module account because GetModuleAccount checks for the existence via + // permissions map and not via state... weird + maccPerms := simapp.GetMaccPerms() + maccPerms[multiPerm] = []string{authtypes.Burner, authtypes.Minter, authtypes.Staking} + + suite.app.AccountKeeper = authkeeper.NewAccountKeeper( + suite.app.AppCodec(), suite.app.GetKey(authtypes.StoreKey), suite.app.GetSubspace(authtypes.ModuleName), + authtypes.ProtoBaseAccount, maccPerms, + ) + + suite.app.BankKeeper = keeper.NewBaseKeeper(suite.app.AppCodec(), suite.app.GetKey(types.StoreKey), + suite.app.AccountKeeper, suite.app.GetSubspace(types.ModuleName), nil) + + // set account with multiple permissions + suite.app.AccountKeeper.SetModuleAccount(suite.ctx, multiPermAcc) + // mint coins + suite.Require().NoError( + suite.app.BankKeeper.MintCoins( + suite.ctx, + multiPermAcc.Name, + sdk.NewCoins(sdk.NewCoin("utxo", sdk.NewInt(100000)))), + ) + // send coins to address + addr1 := sdk.BytesToAccAddress([]byte("addr1_______________")) + suite.Require().NoError( + suite.app.BankKeeper.SendCoinsFromModuleToAccount( + suite.ctx, + multiPermAcc.Name, + addr1, + sdk.NewCoins(sdk.NewCoin("utxo", sdk.NewInt(50000))), + ), + ) + + // burn coins from module account + suite.Require().NoError( + suite.app.BankKeeper.BurnCoins( + suite.ctx, + multiPermAcc.Name, + sdk.NewCoins(sdk.NewInt64Coin("utxo", 1000)), + ), + ) + + // process balances and supply from events + supply := sdk.NewCoins() + + balances := make(map[string]sdk.Coins) + + for _, e := range suite.ctx.EventManager().ABCIEvents() { + switch e.Type { + case types.EventTypeCoinBurn: + burnedCoins, err := sdk.ParseCoinsNormalized((string)(e.Attributes[1].Value)) + suite.Require().NoError(err) + supply = supply.Sub(burnedCoins) + + case types.EventTypeCoinMint: + mintedCoins, err := sdk.ParseCoinsNormalized((string)(e.Attributes[1].Value)) + suite.Require().NoError(err) + supply = supply.Add(mintedCoins...) + + case types.EventTypeCoinSpent: + coinsSpent, err := sdk.ParseCoinsNormalized((string)(e.Attributes[1].Value)) + suite.Require().NoError(err) + err = sdk.ValidateAccAddress(string(e.Attributes[0].Value)) + suite.Require().NoError(err) + spender := sdk.AccAddress(e.Attributes[0].Value) + balances[spender.String()] = balances[spender.String()].Sub(coinsSpent) + + case types.EventTypeCoinReceived: + coinsRecv, err := sdk.ParseCoinsNormalized((string)(e.Attributes[1].Value)) + suite.Require().NoError(err) + err = sdk.ValidateAccAddress(string(e.Attributes[0].Value)) + suite.Require().NoError(err) + receiver := sdk.AccAddress(e.Attributes[0].Value) + balances[receiver.String()] = balances[receiver.String()].Add(coinsRecv...) + } + } + + // check balance and supply tracking + suite.Require().True(suite.app.BankKeeper.HasSupply(suite.ctx, "utxo")) + savedSupply := suite.app.BankKeeper.GetSupply(suite.ctx, "utxo") + utxoSupply := savedSupply + suite.Require().Equal(utxoSupply.Amount, supply.AmountOf("utxo")) + // iterate accounts and check balances + suite.app.BankKeeper.IterateAllBalances(suite.ctx, func(address sdk.AccAddress, coin sdk.Coin) (stop bool) { + // if it's not utxo coin then skip + if coin.Denom != "utxo" { + return false + } + + balance, exists := balances[address.String()] + suite.Require().True(exists) + + expectedUtxo := sdk.NewCoin("utxo", balance.AmountOf(coin.Denom)) + suite.Require().Equal(expectedUtxo.String(), coin.String()) + return false + }) +} + func (suite *IntegrationTestSuite) getTestMetadata() []types.Metadata { return []types.Metadata{{ + Name: "Cosmos Hub Atom", + Symbol: "ATOM", Description: "The native staking token of the Cosmos Hub.", DenomUnits: []*types.DenomUnit{ {"uatom", uint32(0), []string{"microatom"}}, @@ -1061,6 +1165,8 @@ func (suite *IntegrationTestSuite) getTestMetadata() []types.Metadata { Display: "atom", }, { + Name: "Token", + Symbol: "TOKEN", Description: "The native staking token of the Token Hub.", DenomUnits: []*types.DenomUnit{ {"1token", uint32(5), []string{"decitoken"}}, diff --git a/x/bank/keeper/msg_server.go b/x/bank/keeper/msg_server.go index 454fe41dcd..85dabc584a 100644 --- a/x/bank/keeper/msg_server.go +++ b/x/bank/keeper/msg_server.go @@ -26,9 +26,7 @@ var _ types.MsgServer = msgServer{} func (k msgServer) Send(goCtx context.Context, msg *types.MsgSend) (*types.MsgSendResponse, error) { ctx := sdk.UnwrapSDKContext(goCtx) - // NOTICE: We omit the bech32 validation of `from`, `to` for performance in this function. - - if err := k.SendEnabledCoins(ctx, msg.Amount...); err != nil { + if err := k.IsSendEnabledCoins(ctx, msg.Amount...); err != nil { return nil, err } @@ -68,7 +66,7 @@ func (k msgServer) MultiSend(goCtx context.Context, msg *types.MsgMultiSend) (*t // NOTE: totalIn == totalOut should already have been checked for _, in := range msg.Inputs { - if err := k.SendEnabledCoins(ctx, in.Coins...); err != nil { + if err := k.IsSendEnabledCoins(ctx, in.Coins...); err != nil { return nil, err } } diff --git a/x/bank/keeper/querier.go b/x/bank/keeper/querier.go index 2e4cb4d260..2286579b1f 100644 --- a/x/bank/keeper/querier.go +++ b/x/bank/keeper/querier.go @@ -3,7 +3,6 @@ package keeper import ( abci "github.com/line/ostracon/abci/types" - "github.com/line/lbm-sdk/client" "github.com/line/lbm-sdk/codec" sdk "github.com/line/lbm-sdk/types" sdkerrors "github.com/line/lbm-sdk/types/errors" @@ -67,23 +66,24 @@ func queryAllBalance(ctx sdk.Context, req abci.RequestQuery, k Keeper, legacyQue } func queryTotalSupply(ctx sdk.Context, req abci.RequestQuery, k Keeper, legacyQuerierCdc *codec.LegacyAmino) ([]byte, error) { - var params types.QueryTotalSupplyParams + var params types.QueryTotalSupplyRequest err := legacyQuerierCdc.UnmarshalJSON(req.Data, ¶ms) if err != nil { return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error()) } - totalSupply := k.GetSupply(ctx).GetTotal() + totalSupply, pageRes, err := k.GetPaginatedTotalSupply(ctx, params.Pagination) + if err != nil { + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error()) + } - start, end := client.Paginate(len(totalSupply), params.Page, params.Limit, 100) - if start < 0 || end < 0 { - totalSupply = sdk.Coins{} - } else { - totalSupply = totalSupply[start:end] + supplyRes := &types.QueryTotalSupplyResponse{ + Supply: totalSupply, + Pagination: pageRes, } - res, err := legacyQuerierCdc.MarshalJSON(totalSupply) + res, err := codec.MarshalJSONIndent(legacyQuerierCdc, supplyRes) if err != nil { return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) } @@ -99,8 +99,8 @@ func querySupplyOf(ctx sdk.Context, req abci.RequestQuery, k Keeper, legacyQueri return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error()) } - amount := k.GetSupply(ctx).GetTotal().AmountOf(params.Denom) - supply := sdk.NewCoin(params.Denom, amount) + amount := k.GetSupply(ctx, params.Denom) + supply := sdk.NewCoin(params.Denom, amount.Amount) bz, err := codec.MarshalJSONIndent(legacyQuerierCdc, supply) if err != nil { diff --git a/x/bank/keeper/querier_test.go b/x/bank/keeper/querier_test.go index 7f82f166d1..986acf5859 100644 --- a/x/bank/keeper/querier_test.go +++ b/x/bank/keeper/querier_test.go @@ -5,10 +5,13 @@ import ( abci "github.com/line/ostracon/abci/types" + "github.com/line/lbm-sdk/simapp" "github.com/line/lbm-sdk/testutil/testdata" sdk "github.com/line/lbm-sdk/types" + "github.com/line/lbm-sdk/types/query" "github.com/line/lbm-sdk/x/bank/keeper" "github.com/line/lbm-sdk/x/bank/types" + minttypes "github.com/line/lbm-sdk/x/mint/types" ) func (suite *IntegrationTestSuite) TestQuerier_QueryBalance() { @@ -39,7 +42,7 @@ func (suite *IntegrationTestSuite) TestQuerier_QueryBalance() { acc := app.AccountKeeper.NewAccountWithAddress(ctx, addr) app.AccountKeeper.SetAccount(ctx, acc) - suite.Require().NoError(app.BankKeeper.SetBalances(ctx, acc.GetAddress(), origCoins)) + suite.Require().NoError(simapp.FundAccount(app, ctx, acc.GetAddress(), origCoins)) res, err = querier(ctx, []string{types.QueryBalance}, req) suite.Require().NoError(err) @@ -76,8 +79,7 @@ func (suite *IntegrationTestSuite) TestQuerier_QueryAllBalances() { acc := app.AccountKeeper.NewAccountWithAddress(ctx, addr) app.AccountKeeper.SetAccount(ctx, acc) - suite.Require().NoError(app.BankKeeper.SetBalances(ctx, acc.GetAddress(), origCoins)) - + suite.Require().NoError(simapp.FundAccount(app, ctx, acc.GetAddress(), origCoins)) res, err = querier(ctx, []string{types.QueryAllBalances}, req) suite.Require().NoError(err) suite.Require().NotNil(res) @@ -88,8 +90,10 @@ func (suite *IntegrationTestSuite) TestQuerier_QueryAllBalances() { func (suite *IntegrationTestSuite) TestQuerier_QueryTotalSupply() { app, ctx := suite.app, suite.ctx legacyAmino := app.LegacyAmino() - expectedTotalSupply := types.NewSupply(sdk.NewCoins(sdk.NewInt64Coin("test", 400000000))) - app.BankKeeper.SetSupply(ctx, expectedTotalSupply) + expectedTotalSupply := sdk.NewCoins(sdk.NewInt64Coin("test", 400000000)) + suite. + Require(). + NoError(app.BankKeeper.MintCoins(ctx, minttypes.ModuleName, expectedTotalSupply)) req := abci.RequestQuery{ Path: fmt.Sprintf("custom/%s/%s", types.ModuleName, types.QueryTotalSupply), @@ -102,14 +106,16 @@ func (suite *IntegrationTestSuite) TestQuerier_QueryTotalSupply() { suite.Require().NotNil(err) suite.Require().Nil(res) - req.Data = legacyAmino.MustMarshalJSON(types.NewQueryTotalSupplyParams(1, 100)) + req.Data = legacyAmino.MustMarshalJSON(types.QueryTotalSupplyRequest{Pagination: &query.PageRequest{ + Limit: 100, + }}) res, err = querier(ctx, []string{types.QueryTotalSupply}, req) suite.Require().NoError(err) suite.Require().NotNil(res) - var resp sdk.Coins + var resp types.QueryTotalSupplyResponse suite.Require().NoError(legacyAmino.UnmarshalJSON(res, &resp)) - suite.Require().Equal(expectedTotalSupply.Total, resp) + suite.Require().Equal(expectedTotalSupply, resp.Supply) } func (suite *IntegrationTestSuite) TestQuerier_QueryTotalSupplyOf() { @@ -117,8 +123,10 @@ func (suite *IntegrationTestSuite) TestQuerier_QueryTotalSupplyOf() { legacyAmino := app.LegacyAmino() test1Supply := sdk.NewInt64Coin("test1", 4000000) test2Supply := sdk.NewInt64Coin("test2", 700000000) - expectedTotalSupply := types.NewSupply(sdk.NewCoins(test1Supply, test2Supply)) - app.BankKeeper.SetSupply(ctx, expectedTotalSupply) + expectedTotalSupply := sdk.NewCoins(test1Supply, test2Supply) + suite. + Require(). + NoError(app.BankKeeper.MintCoins(ctx, minttypes.ModuleName, expectedTotalSupply)) req := abci.RequestQuery{ Path: fmt.Sprintf("custom/%s/%s", types.ModuleName, types.QuerySupplyOf), diff --git a/x/bank/keeper/send.go b/x/bank/keeper/send.go index d95245c0c3..d875b780b4 100644 --- a/x/bank/keeper/send.go +++ b/x/bank/keeper/send.go @@ -2,7 +2,6 @@ package keeper import ( "github.com/line/lbm-sdk/codec" - "github.com/line/lbm-sdk/store/prefix" "github.com/line/lbm-sdk/telemetry" sdk "github.com/line/lbm-sdk/types" sdkerrors "github.com/line/lbm-sdk/types/errors" @@ -18,17 +17,13 @@ type SendKeeper interface { InputOutputCoins(ctx sdk.Context, inputs []types.Input, outputs []types.Output) error SendCoins(ctx sdk.Context, fromAddr sdk.AccAddress, toAddr sdk.AccAddress, amt sdk.Coins) error - SubtractCoins(ctx sdk.Context, addr sdk.AccAddress, amt sdk.Coins) error - AddCoins(ctx sdk.Context, addr sdk.AccAddress, amt sdk.Coins) error - - SetBalance(ctx sdk.Context, addr sdk.AccAddress, balance sdk.Coin) error - SetBalances(ctx sdk.Context, addr sdk.AccAddress, balances sdk.Coins) error + SetBalance(ctx sdk.Context, addr sdk.AccAddress, balance sdk.Coin) error // TODO(dudong2): remove after x/wasm version up(>= v0.22.0) GetParams(ctx sdk.Context) types.Params SetParams(ctx sdk.Context, params types.Params) - SendEnabledCoin(ctx sdk.Context, coin sdk.Coin) bool - SendEnabledCoins(ctx sdk.Context, coins ...sdk.Coin) error + IsSendEnabledCoin(ctx sdk.Context, coin sdk.Coin) bool + IsSendEnabledCoins(ctx sdk.Context, coins ...sdk.Coin) error BlockedAddr(addr sdk.AccAddress) bool } @@ -40,17 +35,17 @@ var _ SendKeeper = (*BaseSendKeeper)(nil) type BaseSendKeeper struct { BaseViewKeeper - cdc codec.BinaryMarshaler + cdc codec.BinaryCodec ak types.AccountKeeper storeKey sdk.StoreKey - paramSpace *paramtypes.Subspace + paramSpace paramtypes.Subspace // list of addresses that are restricted from receiving transactions blockedAddrs map[string]bool } func NewBaseSendKeeper( - cdc codec.BinaryMarshaler, storeKey sdk.StoreKey, ak types.AccountKeeper, paramSpace *paramtypes.Subspace, blockedAddrs map[string]bool, + cdc codec.BinaryCodec, storeKey sdk.StoreKey, ak types.AccountKeeper, paramSpace paramtypes.Subspace, blockedAddrs map[string]bool, ) BaseSendKeeper { return BaseSendKeeper{ @@ -91,7 +86,7 @@ func (k BaseSendKeeper) InputOutputCoins(ctx sdk.Context, inputs []types.Input, for _, in := range inputs { inAddress := sdk.AccAddress(in.Address) - err := k.SubtractCoins(ctx, inAddress, in.Coins) + err := k.subUnlockedCoins(ctx, inAddress, in.Coins) if err != nil { return err } @@ -106,7 +101,7 @@ func (k BaseSendKeeper) InputOutputCoins(ctx sdk.Context, inputs []types.Input, for _, out := range outputs { outAddress := sdk.AccAddress(out.Address) - err := k.AddCoins(ctx, outAddress, out.Coins) + err := k.addCoins(ctx, outAddress, out.Coins) if err != nil { return err } @@ -123,8 +118,8 @@ func (k BaseSendKeeper) InputOutputCoins(ctx sdk.Context, inputs []types.Input, // // NOTE: This should ultimately be removed in favor a more flexible approach // such as delegated fee messages. - acc := k.ak.GetAccount(ctx, outAddress) - if acc == nil { + accExists := k.ak.HasAccount(ctx, outAddress) + if !accExists { defer telemetry.IncrCounter(1, "new", "account") k.ak.SetAccount(ctx, k.ak.NewAccountWithAddress(ctx, outAddress)) } @@ -136,25 +131,12 @@ func (k BaseSendKeeper) InputOutputCoins(ctx sdk.Context, inputs []types.Input, // SendCoins transfers amt coins from a sending account to a receiving account. // An error is returned upon failure. func (k BaseSendKeeper) SendCoins(ctx sdk.Context, fromAddr sdk.AccAddress, toAddr sdk.AccAddress, amt sdk.Coins) error { - ctx.EventManager().EmitEvents(sdk.Events{ - sdk.NewEvent( - types.EventTypeTransfer, - sdk.NewAttribute(types.AttributeKeyRecipient, toAddr.String()), - sdk.NewAttribute(types.AttributeKeySender, fromAddr.String()), - sdk.NewAttribute(sdk.AttributeKeyAmount, amt.String()), - ), - sdk.NewEvent( - sdk.EventTypeMessage, - sdk.NewAttribute(types.AttributeKeySender, fromAddr.String()), - ), - }) - - err := k.SubtractCoins(ctx, fromAddr, amt) + err := k.subUnlockedCoins(ctx, fromAddr, amt) if err != nil { return err } - err = k.AddCoins(ctx, toAddr, amt) + err = k.addCoins(ctx, toAddr, amt) if err != nil { return err } @@ -163,18 +145,32 @@ func (k BaseSendKeeper) SendCoins(ctx sdk.Context, fromAddr sdk.AccAddress, toAd // // NOTE: This should ultimately be removed in favor a more flexible approach // such as delegated fee messages. - acc := k.ak.GetAccount(ctx, toAddr) - if acc == nil { + accExists := k.ak.HasAccount(ctx, toAddr) + if !accExists { defer telemetry.IncrCounter(1, "new", "account") k.ak.SetAccount(ctx, k.ak.NewAccountWithAddress(ctx, toAddr)) } + ctx.EventManager().EmitEvents(sdk.Events{ + sdk.NewEvent( + types.EventTypeTransfer, + sdk.NewAttribute(types.AttributeKeyRecipient, toAddr.String()), + sdk.NewAttribute(types.AttributeKeySender, fromAddr.String()), + sdk.NewAttribute(sdk.AttributeKeyAmount, amt.String()), + ), + sdk.NewEvent( + sdk.EventTypeMessage, + sdk.NewAttribute(types.AttributeKeySender, fromAddr.String()), + ), + }) + return nil } -// SubtractCoins removes amt coins the account by the given address. An error is +// subUnlockedCoins removes the unlocked amt coins of the given account. An error is // returned if the resulting balance is negative or the initial amount is invalid. -func (k BaseSendKeeper) SubtractCoins(ctx sdk.Context, addr sdk.AccAddress, amt sdk.Coins) error { +// A coin_spent event is emitted after. +func (k BaseSendKeeper) subUnlockedCoins(ctx sdk.Context, addr sdk.AccAddress, amt sdk.Coins) error { if !amt.IsValid() { return sdkerrors.Wrap(sdkerrors.ErrInvalidCoins, amt.String()) } @@ -193,19 +189,22 @@ func (k BaseSendKeeper) SubtractCoins(ctx sdk.Context, addr sdk.AccAddress, amt newBalance := balance.Sub(coin) - err := k.SetBalance(ctx, addr, newBalance) + err := k.setBalance(ctx, addr, newBalance) if err != nil { return err } } + // emit coin spent event + ctx.EventManager().EmitEvent( + types.NewCoinSpentEvent(addr, amt), + ) return nil } -// AddCoins adds amt to the account balance given by the provided address. An -// error is returned if the initial amount is invalid or if any resulting new -// balance is negative. -func (k BaseSendKeeper) AddCoins(ctx sdk.Context, addr sdk.AccAddress, amt sdk.Coins) error { +// addCoins increase the addr balance by the given amt. Fails if the provided amt is invalid. +// It emits a coin received event. +func (k BaseSendKeeper) addCoins(ctx sdk.Context, addr sdk.AccAddress, amt sdk.Coins) error { if !amt.IsValid() { return sdkerrors.Wrap(sdkerrors.ErrInvalidCoins, amt.String()) } @@ -214,44 +213,16 @@ func (k BaseSendKeeper) AddCoins(ctx sdk.Context, addr sdk.AccAddress, amt sdk.C balance := k.GetBalance(ctx, addr, coin.Denom) newBalance := balance.Add(coin) - err := k.SetBalance(ctx, addr, newBalance) + err := k.setBalance(ctx, addr, newBalance) if err != nil { return err } } - return nil -} - -// ClearBalances removes all balances for a given account by address. -func (k BaseSendKeeper) ClearBalances(ctx sdk.Context, addr sdk.AccAddress) { - keys := [][]byte{} - k.IterateAccountBalances(ctx, addr, func(balance sdk.Coin) bool { - keys = append(keys, []byte(balance.Denom)) - return false - }) - - store := ctx.KVStore(k.storeKey) - balancesStore := prefix.NewStore(store, types.BalancesPrefix) - accountStore := prefix.NewStore(balancesStore, AddressToPrefixKey(addr)) - - for _, key := range keys { - accountStore.Delete(key) - } -} - -// SetBalances sets the balance (multiple coins) for an account by address. It will -// clear out all balances prior to setting the new coins as to set existing balances -// to zero if they don't exist in amt. An error is returned upon failure. -func (k BaseSendKeeper) SetBalances(ctx sdk.Context, addr sdk.AccAddress, balances sdk.Coins) error { - k.ClearBalances(ctx, addr) - - for _, balance := range balances { - err := k.SetBalance(ctx, addr, balance) - if err != nil { - return err - } - } + // emit coin received event + ctx.EventManager().EmitEvent( + types.NewCoinReceivedEvent(addr, amt), + ) return nil } @@ -259,9 +230,7 @@ func (k BaseSendKeeper) SetBalances(ctx sdk.Context, addr sdk.AccAddress, balanc // initBalances sets the balance (multiple coins) for an account by address. // An error is returned upon failure. func (k BaseSendKeeper) initBalances(ctx sdk.Context, addr sdk.AccAddress, balances sdk.Coins) error { - store := ctx.KVStore(k.storeKey) - balancesStore := prefix.NewStore(store, types.BalancesPrefix) - accountStore := prefix.NewStore(balancesStore, AddressToPrefixKey(addr)) + accountStore := k.getAccountStore(ctx, addr) for i := range balances { balance := balances[i] if !balance.IsValid() { @@ -270,7 +239,7 @@ func (k BaseSendKeeper) initBalances(ctx sdk.Context, addr sdk.AccAddress, balan // Bank invariants require to not store zero balances. if !balance.IsZero() { - bz := k.cdc.MustMarshalBinaryBare(&balance) + bz := k.cdc.MustMarshal(&balance) accountStore.Set([]byte(balance.Denom), bz) } } @@ -278,39 +247,58 @@ func (k BaseSendKeeper) initBalances(ctx sdk.Context, addr sdk.AccAddress, balan return nil } +// setBalance sets the coin balance for an account by address. +func (k BaseSendKeeper) setBalance(ctx sdk.Context, addr sdk.AccAddress, balance sdk.Coin) error { + if !balance.IsValid() { + return sdkerrors.Wrap(sdkerrors.ErrInvalidCoins, balance.String()) + } + + accountStore := k.getAccountStore(ctx, addr) + + // Bank invariants require to not store zero balances. + if balance.IsZero() { + accountStore.Delete([]byte(balance.Denom)) + } else { + bz := k.cdc.MustMarshal(&balance) + accountStore.Set([]byte(balance.Denom), bz) + } + + return nil +} + // SetBalance sets the coin balance for an account by address. func (k BaseSendKeeper) SetBalance(ctx sdk.Context, addr sdk.AccAddress, balance sdk.Coin) error { if !balance.IsValid() { return sdkerrors.Wrap(sdkerrors.ErrInvalidCoins, balance.String()) } - store := ctx.KVStore(k.storeKey) - balancesStore := prefix.NewStore(store, types.BalancesPrefix) - accountStore := prefix.NewStore(balancesStore, AddressToPrefixKey(addr)) + accountStore := k.getAccountStore(ctx, addr) - bz, err := balance.Marshal() - if err != nil { - return err + // Bank invariants require to not store zero balances. + if balance.IsZero() { + accountStore.Delete([]byte(balance.Denom)) + } else { + bz := k.cdc.MustMarshal(&balance) + accountStore.Set([]byte(balance.Denom), bz) } - accountStore.Set([]byte(balance.Denom), bz) return nil } -// SendEnabledCoins checks the coins provide and returns an ErrSendDisabled if +// IsSendEnabledCoins checks the coins provide and returns an ErrSendDisabled if // any of the coins are not configured for sending. Returns nil if sending is enabled // for all provided coin -func (k BaseSendKeeper) SendEnabledCoins(ctx sdk.Context, coins ...sdk.Coin) error { +func (k BaseSendKeeper) IsSendEnabledCoins(ctx sdk.Context, coins ...sdk.Coin) error { for _, coin := range coins { - if !k.SendEnabledCoin(ctx, coin) { + if !k.IsSendEnabledCoin(ctx, coin) { return sdkerrors.Wrapf(types.ErrSendDisabled, "%s transfers are currently disabled", coin.Denom) } } return nil } -// SendEnabledCoin returns the current SendEnabled status of the provided coin's denom -func (k BaseSendKeeper) SendEnabledCoin(ctx sdk.Context, coin sdk.Coin) bool { +// IsSendEnabledCoin returns the current SendEnabled status of the provided coin's denom +func (k BaseSendKeeper) IsSendEnabledCoin(ctx sdk.Context, coin sdk.Coin) bool { return k.GetParams(ctx).SendEnabledDenom(coin.Denom) } @@ -319,3 +307,13 @@ func (k BaseSendKeeper) SendEnabledCoin(ctx sdk.Context, coin sdk.Coin) bool { func (k BaseSendKeeper) BlockedAddr(addr sdk.AccAddress) bool { return k.blockedAddrs[addr.String()] } + +func (k BaseSendKeeper) ChangeBlockedAddrState(addr sdk.AccAddress, isBlocked bool) error { + key := addr.String() + if _, ok := k.blockedAddrs[key]; !ok { + return sdkerrors.Wrapf(types.ErrInvalidKey, "%s is not in blockedAddrs", key) + } + + k.blockedAddrs[key] = isBlocked + return nil +} diff --git a/x/bank/keeper/view.go b/x/bank/keeper/view.go index 33df97171f..404245f220 100644 --- a/x/bank/keeper/view.go +++ b/x/bank/keeper/view.go @@ -35,13 +35,13 @@ type ViewKeeper interface { // BaseViewKeeper implements a read only keeper implementation of ViewKeeper. type BaseViewKeeper struct { - cdc codec.BinaryMarshaler + cdc codec.BinaryCodec storeKey sdk.StoreKey ak types.AccountKeeper } // NewBaseViewKeeper returns a new BaseViewKeeper. -func NewBaseViewKeeper(cdc codec.BinaryMarshaler, storeKey sdk.StoreKey, ak types.AccountKeeper) BaseViewKeeper { +func NewBaseViewKeeper(cdc codec.BinaryCodec, storeKey sdk.StoreKey, ak types.AccountKeeper) BaseViewKeeper { return BaseViewKeeper{ cdc: cdc, storeKey: storeKey, @@ -99,9 +99,7 @@ func (k BaseViewKeeper) GetAccountsBalances(ctx sdk.Context) []types.Balance { // GetBalance returns the balance of a specific denomination for a given account // by address. func (k BaseViewKeeper) GetBalance(ctx sdk.Context, addr sdk.AccAddress, denom string) sdk.Coin { - store := ctx.KVStore(k.storeKey) - balancesStore := prefix.NewStore(store, types.BalancesPrefix) - accountStore := prefix.NewStore(balancesStore, AddressToPrefixKey(addr)) + accountStore := k.getAccountStore(ctx, addr) bz := accountStore.Get([]byte(denom)) if bz == nil { @@ -170,9 +168,7 @@ func (k BaseViewKeeper) Prefetch(ctx sdk.Context, tx sdk.Tx) { // provides the token balance to a callback. If true is returned from the // callback, iteration is halted. func (k BaseViewKeeper) IterateAccountBalances(ctx sdk.Context, addr sdk.AccAddress, cb func(sdk.Coin) bool) { - store := ctx.KVStore(k.storeKey) - balancesStore := prefix.NewStore(store, types.BalancesPrefix) - accountStore := prefix.NewStore(balancesStore, AddressToPrefixKey(addr)) + accountStore := k.getAccountStore(ctx, addr) iterator := accountStore.Iterator(nil, nil) defer iterator.Close() @@ -200,7 +196,13 @@ func (k BaseViewKeeper) IterateAllBalances(ctx sdk.Context, cb func(sdk.AccAddre defer iterator.Close() for ; iterator.Valid(); iterator.Next() { - address := types.AddressFromBalancesStore(iterator.Key()) + address, err := types.AddressFromBalancesStore(iterator.Key()) + if err != nil { + k.Logger(ctx).With("key", iterator.Key(), "err", err).Error("failed to get address from balances store") + // TODO: revisit, for now, panic here to keep same behavior as in 0.42 + // ref: https://github.com/cosmos/cosmos-sdk/issues/7409 + panic(err) + } var balance sdk.Coin if err := balance.Unmarshal(iterator.Value()); err != nil { @@ -233,15 +235,23 @@ func (k BaseViewKeeper) LockedCoins(ctx sdk.Context, addr sdk.AccAddress) sdk.Co // by address. If the account has no spendable coins, an empty Coins slice is // returned. func (k BaseViewKeeper) SpendableCoins(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins { - balances := k.GetAllBalances(ctx, addr) + spendable, _ := k.spendableCoins(ctx, addr) + return spendable +} + +// spendableCoins returns the coins the given address can spend alongside the total amount of coins it holds. +// It exists for gas efficiency, in order to avoid to have to get balance multiple times. +func (k BaseViewKeeper) spendableCoins(ctx sdk.Context, addr sdk.AccAddress) (spendable, total sdk.Coins) { + total = k.GetAllBalances(ctx, addr) locked := k.LockedCoins(ctx, addr) - spendable, hasNeg := balances.SafeSub(locked) + spendable, hasNeg := total.SafeSub(locked) if hasNeg { - return sdk.NewCoins() + spendable = sdk.NewCoins() + return } - return spendable + return } // ValidateBalance validates all balances for a given account address returning @@ -272,3 +282,10 @@ func (k BaseViewKeeper) ValidateBalance(ctx sdk.Context, addr sdk.AccAddress) er return nil } + +// getAccountStore gets the account store of the given address. +func (k BaseViewKeeper) getAccountStore(ctx sdk.Context, addr sdk.AccAddress) prefix.Store { + store := ctx.KVStore(k.storeKey) + + return prefix.NewStore(store, types.CreateAccountBalancesPrefix(addr.Bytes())) +} diff --git a/x/bank/legacy/v040/keys.go b/x/bank/legacy/v040/keys.go new file mode 100644 index 0000000000..398adb2bb8 --- /dev/null +++ b/x/bank/legacy/v040/keys.go @@ -0,0 +1,49 @@ +// Package v040 is copy-pasted from: +// https://github.com/cosmos/cosmos-sdk/blob/v0.41.0/x/bank/types/key.go +package v040 + +import ( + "fmt" + + sdk "github.com/line/lbm-sdk/types" + v040auth "github.com/line/lbm-sdk/x/auth/legacy/v040" +) + +const ( + // ModuleName defines the module name + ModuleName = "bank" + + // StoreKey defines the primary module store key + StoreKey = ModuleName + + // RouterKey defines the module's message routing key + RouterKey = ModuleName + + // QuerierRoute defines the module's query routing key + QuerierRoute = ModuleName +) + +// KVStore keys +var ( + BalancesPrefix = []byte("balances") + SupplyKey = []byte{0x00} + DenomMetadataPrefix = []byte{0x1} +) + +// DenomMetadataKey returns the denomination metadata key. +func DenomMetadataKey(denom string) []byte { + d := []byte(denom) + return append(DenomMetadataPrefix, d...) +} + +// AddressFromBalancesStore returns an account address from a balances prefix +// store. The key must not contain the perfix BalancesPrefix as the prefix store +// iterator discards the actual prefix. +func AddressFromBalancesStore(key []byte) sdk.AccAddress { + addr := key[:v040auth.AddrLen] + if len(addr) != v040auth.AddrLen { + panic(fmt.Sprintf("unexpected account address key length; got: %d, expected: %d", len(addr), v040auth.AddrLen)) + } + + return sdk.AccAddress(addr) +} diff --git a/x/bank/legacy/v040/types.go b/x/bank/legacy/v040/types.go new file mode 100644 index 0000000000..34b9cd7e8f --- /dev/null +++ b/x/bank/legacy/v040/types.go @@ -0,0 +1,31 @@ +package v040 + +import ( + "github.com/golang/protobuf/proto" // nolint: staticcheck + + codectypes "github.com/line/lbm-sdk/codec/types" + "github.com/line/lbm-sdk/x/bank/types" +) + +// SupplyI defines an inflationary supply interface for modules that handle +// token supply. +// It is copy-pasted from: +// https://github.com/cosmos/cosmos-sdk/blob/v042.3/x/bank/exported/exported.go +// where we stripped off the unnecessary methods. +// +// It is used in the migration script, because we save this interface as an Any +// in the supply state. +// +// Deprecated. +type SupplyI interface { + proto.Message +} + +// RegisterInterfaces registers interfaces required for the v0.40 migrations. +func RegisterInterfaces(registry codectypes.InterfaceRegistry) { + registry.RegisterInterface( + "lbm.bank.v1.SupplyI", + (*SupplyI)(nil), // nolint: staticcheck + &types.Supply{}, // nolint: staticcheck + ) +} diff --git a/x/bank/legacy/v043/json.go b/x/bank/legacy/v043/json.go new file mode 100644 index 0000000000..4b4a398ce6 --- /dev/null +++ b/x/bank/legacy/v043/json.go @@ -0,0 +1,32 @@ +package v043 + +import ( + sdk "github.com/line/lbm-sdk/types" + "github.com/line/lbm-sdk/x/bank/types" +) + +// pruneZeroBalancesJSON removes the zero balance addresses from exported genesis. +func pruneZeroBalancesJSON(oldBalances []types.Balance) []types.Balance { + var balances []types.Balance + + for _, b := range oldBalances { + if !b.Coins.IsZero() { + b.Coins = sdk.NewCoins(b.Coins...) // prunes zero denom. + balances = append(balances, b) + } + } + + return balances +} + +// MigrateJSON accepts exported v0.40 x/bank genesis state and migrates it to +// v0.43 x/bank genesis state. The migration includes: +// - Prune balances & supply with zero coins (ref: https://github.com/cosmos/cosmos-sdk/pull/9229) +func MigrateJSON(oldState *types.GenesisState) *types.GenesisState { + return &types.GenesisState{ + Params: oldState.Params, + Balances: pruneZeroBalancesJSON(oldState.Balances), + Supply: sdk.NewCoins(oldState.Supply...), // NewCoins used here to remove zero coin denoms from supply. + DenomMetadata: oldState.DenomMetadata, + } +} diff --git a/x/bank/legacy/v043/json_test.go b/x/bank/legacy/v043/json_test.go new file mode 100644 index 0000000000..1008224ec9 --- /dev/null +++ b/x/bank/legacy/v043/json_test.go @@ -0,0 +1,92 @@ +package v043_test + +import ( + "encoding/json" + "testing" + + "github.com/stretchr/testify/require" + + "github.com/line/lbm-sdk/client" + "github.com/line/lbm-sdk/simapp" + sdk "github.com/line/lbm-sdk/types" + v043bank "github.com/line/lbm-sdk/x/bank/legacy/v043" + "github.com/line/lbm-sdk/x/bank/types" +) + +func TestMigrateJSON(t *testing.T) { + encodingConfig := simapp.MakeTestEncodingConfig() + clientCtx := client.Context{}. + WithInterfaceRegistry(encodingConfig.InterfaceRegistry). + WithTxConfig(encodingConfig.TxConfig). + WithCodec(encodingConfig.Marshaler) + + voter := sdk.AccAddress("link1fl48vsnmsdzcv85q5d2q4z5ajdha8yu34mf0eh") + bankGenState := &types.GenesisState{ + Balances: []types.Balance{ + { + Address: voter.String(), + Coins: sdk.Coins{ + sdk.NewCoin("foo", sdk.NewInt(10)), + sdk.NewCoin("bar", sdk.NewInt(20)), + sdk.NewCoin("foobar", sdk.NewInt(0)), + }, + }, + }, + Supply: sdk.Coins{ + sdk.NewCoin("foo", sdk.NewInt(10)), + sdk.NewCoin("bar", sdk.NewInt(20)), + sdk.NewCoin("foobar", sdk.NewInt(0)), + sdk.NewCoin("barfoo", sdk.NewInt(0)), + }, + } + + migrated := v043bank.MigrateJSON(bankGenState) + + bz, err := clientCtx.Codec.MarshalJSON(migrated) + require.NoError(t, err) + + // Indent the JSON bz correctly. + var jsonObj map[string]interface{} + err = json.Unmarshal(bz, &jsonObj) + require.NoError(t, err) + indentedBz, err := json.MarshalIndent(jsonObj, "", "\t") + require.NoError(t, err) + + // Make sure about: + // - zero coin balances pruned. + // - zero supply denoms pruned. + expected := `{ + "balances": [ + { + "address": "link1fl48vsnmsdzcv85q5d2q4z5ajdha8yu34mf0eh", + "coins": [ + { + "amount": "20", + "denom": "bar" + }, + { + "amount": "10", + "denom": "foo" + } + ] + } + ], + "denom_metadata": [], + "params": { + "default_send_enabled": false, + "send_enabled": [] + }, + "supply": [ + { + "amount": "20", + "denom": "bar" + }, + { + "amount": "10", + "denom": "foo" + } + ] +}` + + require.Equal(t, expected, string(indentedBz)) +} diff --git a/x/bank/legacy/v043/keys.go b/x/bank/legacy/v043/keys.go new file mode 100644 index 0000000000..fbef37c988 --- /dev/null +++ b/x/bank/legacy/v043/keys.go @@ -0,0 +1,12 @@ +package v043 + +const ( + // ModuleName is the name of the module + ModuleName = "bank" +) + +// KVStore keys +var ( + BalancesPrefix = []byte{0x02} + SupplyKey = []byte{0x00} +) diff --git a/x/bank/legacy/v043/store.go b/x/bank/legacy/v043/store.go new file mode 100644 index 0000000000..76e4518829 --- /dev/null +++ b/x/bank/legacy/v043/store.go @@ -0,0 +1,131 @@ +package v043 + +import ( + "github.com/line/lbm-sdk/codec" + "github.com/line/lbm-sdk/store/prefix" + sdk "github.com/line/lbm-sdk/types" + v040auth "github.com/line/lbm-sdk/x/auth/legacy/v040" + v040bank "github.com/line/lbm-sdk/x/bank/legacy/v040" + "github.com/line/lbm-sdk/x/bank/types" +) + +// migrateSupply migrates the supply to be stored by denom key instead in a +// single blob. +// ref: https://github.com/cosmos/cosmos-sdk/issues/7092 +func migrateSupply(store sdk.KVStore, cdc codec.BinaryCodec) error { + // Old supply was stored as a single blob under the SupplyKey. + var oldSupplyI v040bank.SupplyI + err := cdc.UnmarshalInterface(store.Get(v040bank.SupplyKey), &oldSupplyI) + if err != nil { + return err + } + + // We delete the single key holding the whole blob. + store.Delete(v040bank.SupplyKey) + + if oldSupplyI == nil { + return nil + } + + // We add a new key for each denom + supplyStore := prefix.NewStore(store, types.SupplyKey) + + // We're sure that SupplyI is a Supply struct, there's no other + // implementation. + oldSupply := oldSupplyI.(*types.Supply) // nolint: staticcheck + for i := range oldSupply.Total { + coin := oldSupply.Total[i] + coinBz, err := coin.Amount.Marshal() + if err != nil { + return err + } + + supplyStore.Set([]byte(coin.Denom), coinBz) + } + + return nil +} + +// migrateBalanceKeys migrate the balances keys to cater for variable-length +// addresses. +func migrateBalanceKeys(store sdk.KVStore) { + // old key is of format: + // prefix ("balances") || addrBytes (20 bytes) || denomBytes + // new key is of format + // prefix (0x02) || addrLen (1 byte) || addrBytes || denomBytes + oldStore := prefix.NewStore(store, v040bank.BalancesPrefix) + + oldStoreIter := oldStore.Iterator(nil, nil) + defer oldStoreIter.Close() + + for ; oldStoreIter.Valid(); oldStoreIter.Next() { + addr := v040bank.AddressFromBalancesStore(oldStoreIter.Key()) + denom := oldStoreIter.Key()[v040auth.AddrLen:] + newStoreKey := append(types.CreateAccountBalancesPrefix(addr.Bytes()), denom...) + + // Set new key on store. Values don't change. + store.Set(newStoreKey, oldStoreIter.Value()) + oldStore.Delete(oldStoreIter.Key()) + } +} + +// MigrateStore performs in-place store migrations from v0.40 to v0.43. The +// migration includes: +// +// - Change addresses to be length-prefixed. +// - Change balances prefix to 1 byte +// - Change supply to be indexed by denom +// - Prune balances & supply with zero coins (ref: https://github.com/cosmos/cosmos-sdk/pull/9229) +func MigrateStore(ctx sdk.Context, storeKey sdk.StoreKey, cdc codec.BinaryCodec) error { + store := ctx.KVStore(storeKey) + migrateBalanceKeys(store) + + if err := pruneZeroBalances(store, cdc); err != nil { + return err + } + + if err := migrateSupply(store, cdc); err != nil { + return err + } + + return pruneZeroSupply(store) +} + +// pruneZeroBalances removes the zero balance addresses from balances store. +func pruneZeroBalances(store sdk.KVStore, cdc codec.BinaryCodec) error { + balancesStore := prefix.NewStore(store, BalancesPrefix) + iterator := balancesStore.Iterator(nil, nil) + defer iterator.Close() + + for ; iterator.Valid(); iterator.Next() { + var balance sdk.Coin + if err := cdc.Unmarshal(iterator.Value(), &balance); err != nil { + return err + } + + if balance.IsZero() { + balancesStore.Delete(iterator.Key()) + } + } + return nil +} + +// pruneZeroSupply removes zero balance denom from supply store. +func pruneZeroSupply(store sdk.KVStore) error { + supplyStore := prefix.NewStore(store, SupplyKey) + iterator := supplyStore.Iterator(nil, nil) + defer iterator.Close() + + for ; iterator.Valid(); iterator.Next() { + var amount sdk.Int + if err := amount.Unmarshal(iterator.Value()); err != nil { + return err + } + + if amount.IsZero() { + supplyStore.Delete(iterator.Key()) + } + } + + return nil +} diff --git a/x/bank/legacy/v043/store_test.go b/x/bank/legacy/v043/store_test.go new file mode 100644 index 0000000000..63226ab89a --- /dev/null +++ b/x/bank/legacy/v043/store_test.go @@ -0,0 +1,102 @@ +package v043_test + +import ( + "testing" + + "github.com/stretchr/testify/require" + + "github.com/line/lbm-sdk/simapp" + "github.com/line/lbm-sdk/store/prefix" + "github.com/line/lbm-sdk/testutil" + "github.com/line/lbm-sdk/testutil/testdata" + sdk "github.com/line/lbm-sdk/types" + v040bank "github.com/line/lbm-sdk/x/bank/legacy/v040" + v043bank "github.com/line/lbm-sdk/x/bank/legacy/v043" + "github.com/line/lbm-sdk/x/bank/types" +) + +func TestSupplyMigration(t *testing.T) { + encCfg := simapp.MakeTestEncodingConfig() + bankKey := sdk.NewKVStoreKey("bank") + ctx := testutil.DefaultContext(bankKey, sdk.NewTransientStoreKey("transient_test")) + store := ctx.KVStore(bankKey) + + oldFooCoin := sdk.NewCoin("foo", sdk.NewInt(100)) + oldBarCoin := sdk.NewCoin("bar", sdk.NewInt(200)) + oldFooBarCoin := sdk.NewCoin("foobar", sdk.NewInt(0)) // to ensure the zero denom coins pruned. + + // Old supply was stored as a single blob under the `SupplyKey`. + var oldSupply v040bank.SupplyI + oldSupply = &types.Supply{Total: sdk.Coins{oldFooCoin, oldBarCoin, oldFooBarCoin}} + oldSupplyBz, err := encCfg.Marshaler.MarshalInterface(oldSupply) + require.NoError(t, err) + store.Set(v040bank.SupplyKey, oldSupplyBz) + + // Run migration. + err = v043bank.MigrateStore(ctx, bankKey, encCfg.Marshaler) + require.NoError(t, err) + + // New supply is indexed by denom. + supplyStore := prefix.NewStore(store, types.SupplyKey) + bz := supplyStore.Get([]byte("foo")) + var amount sdk.Int + err = amount.Unmarshal(bz) + require.NoError(t, err) + + newFooCoin := sdk.Coin{ + Denom: "foo", + Amount: amount, + } + require.Equal(t, oldFooCoin, newFooCoin) + + bz = supplyStore.Get([]byte("bar")) + err = amount.Unmarshal(bz) + require.NoError(t, err) + + newBarCoin := sdk.Coin{ + Denom: "bar", + Amount: amount, + } + require.Equal(t, oldBarCoin, newBarCoin) + + // foobar shouldn't be existed in the store. + bz = supplyStore.Get([]byte("foobar")) + require.Nil(t, bz) +} + +func TestBalanceKeysMigration(t *testing.T) { + encCfg := simapp.MakeTestEncodingConfig() + bankKey := sdk.NewKVStoreKey("bank") + ctx := testutil.DefaultContext(bankKey, sdk.NewTransientStoreKey("transient_test")) + store := ctx.KVStore(bankKey) + + _, _, addr := testdata.KeyTestPubAddr() + + // set 10 foo coin + fooCoin := sdk.NewCoin("foo", sdk.NewInt(10)) + oldFooKey := append(append(v040bank.BalancesPrefix, addr...), []byte(fooCoin.Denom)...) + fooBz, err := encCfg.Marshaler.Marshal(&fooCoin) + require.NoError(t, err) + store.Set(oldFooKey, fooBz) + + // set 0 foobar coin + fooBarCoin := sdk.NewCoin("foobar", sdk.NewInt(0)) + oldKeyFooBar := append(append(v040bank.BalancesPrefix, addr...), []byte(fooBarCoin.Denom)...) + fooBarBz, err := encCfg.Marshaler.Marshal(&fooBarCoin) + require.NoError(t, err) + store.Set(oldKeyFooBar, fooBarBz) + require.NotNil(t, store.Get(oldKeyFooBar)) // before store migation zero values can also exist in store. + + err = v043bank.MigrateStore(ctx, bankKey, encCfg.Marshaler) + require.NoError(t, err) + + newKey := append(types.CreateAccountBalancesPrefix(addr.Bytes()), []byte(fooCoin.Denom)...) + // -7 because we replaced "balances" with 0x02, + // +1 because we added length-prefix to address. + require.Equal(t, len(oldFooKey)-7+1, len(newKey)) + require.Nil(t, store.Get(oldFooKey)) + require.Equal(t, fooBz, store.Get(newKey)) + + newKeyFooBar := append(types.CreateAccountBalancesPrefix(addr.Bytes()), []byte(fooBarCoin.Denom)...) + require.Nil(t, store.Get(newKeyFooBar)) // after migration zero balances pruned from store. +} diff --git a/x/bank/module.go b/x/bank/module.go index f636d96a20..4f3b5abaa0 100644 --- a/x/bank/module.go +++ b/x/bank/module.go @@ -22,6 +22,7 @@ import ( "github.com/line/lbm-sdk/x/bank/client/cli" "github.com/line/lbm-sdk/x/bank/client/rest" "github.com/line/lbm-sdk/x/bank/keeper" + v040 "github.com/line/lbm-sdk/x/bank/legacy/v040" "github.com/line/lbm-sdk/x/bank/simulation" "github.com/line/lbm-sdk/x/bank/types" ) @@ -34,7 +35,7 @@ var ( // AppModuleBasic defines the basic application module used by the bank module. type AppModuleBasic struct { - cdc codec.Marshaler + cdc codec.Codec } // Name returns the bank module's name. @@ -47,12 +48,12 @@ func (AppModuleBasic) RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) { // DefaultGenesis returns default genesis state as raw bytes for the bank // module. -func (AppModuleBasic) DefaultGenesis(cdc codec.JSONMarshaler) json.RawMessage { +func (AppModuleBasic) DefaultGenesis(cdc codec.JSONCodec) json.RawMessage { return cdc.MustMarshalJSON(types.DefaultGenesisState()) } // ValidateGenesis performs genesis state validation for the bank module. -func (AppModuleBasic) ValidateGenesis(cdc codec.JSONMarshaler, _ client.TxEncodingConfig, bz json.RawMessage) error { +func (AppModuleBasic) ValidateGenesis(cdc codec.JSONCodec, _ client.TxEncodingConfig, bz json.RawMessage) error { var data types.GenesisState if err := cdc.UnmarshalJSON(bz, &data); err != nil { return fmt.Errorf("failed to unmarshal %s genesis state: %w", types.ModuleName, err) @@ -84,9 +85,10 @@ func (AppModuleBasic) GetQueryCmd() *cobra.Command { // RegisterInterfaces registers interfaces and implementations of the bank module. func (AppModuleBasic) RegisterInterfaces(registry codectypes.InterfaceRegistry) { types.RegisterInterfaces(registry) -} -// ____________________________________________________________________________ + // Register legacy interfaces for migration scripts. + v040.RegisterInterfaces(registry) +} // AppModule implements an application module for the bank module. type AppModule struct { @@ -108,7 +110,7 @@ func (am AppModule) RegisterServices(cfg module.Configurator) { } // NewAppModule creates a new AppModule object -func NewAppModule(cdc codec.Marshaler, keeper keeper.Keeper, accountKeeper types.AccountKeeper) AppModule { +func NewAppModule(cdc codec.Codec, keeper keeper.Keeper, accountKeeper types.AccountKeeper) AppModule { return AppModule{ AppModuleBasic: AppModuleBasic{cdc: cdc}, keeper: keeper, @@ -139,7 +141,7 @@ func (am AppModule) LegacyQuerierHandler(legacyQuerierCdc *codec.LegacyAmino) sd // InitGenesis performs genesis initialization for the bank module. It returns // no validator updates. -func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONMarshaler, data json.RawMessage) []abci.ValidatorUpdate { +func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONCodec, data json.RawMessage) []abci.ValidatorUpdate { start := time.Now() var genesisState types.GenesisState cdc.MustUnmarshalJSON(data, &genesisState) @@ -151,7 +153,7 @@ func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONMarshaler, data j // ExportGenesis returns the exported genesis state as raw bytes for the bank // module. -func (am AppModule) ExportGenesis(ctx sdk.Context, cdc codec.JSONMarshaler) json.RawMessage { +func (am AppModule) ExportGenesis(ctx sdk.Context, cdc codec.JSONCodec) json.RawMessage { gs := am.keeper.ExportGenesis(ctx) return cdc.MustMarshalJSON(gs) } @@ -168,8 +170,6 @@ func (AppModule) EndBlock(_ sdk.Context, _ abci.RequestEndBlock) []abci.Validato return []abci.ValidatorUpdate{} } -// ____________________________________________________________________________ - // AppModuleSimulation functions // GenerateGenesisState creates a randomized GenState of the bank module. @@ -188,9 +188,7 @@ func (AppModule) RandomizedParams(r *rand.Rand) []simtypes.ParamChange { } // RegisterStoreDecoder registers a decoder for supply module's types -func (am AppModule) RegisterStoreDecoder(sdr sdk.StoreDecoderRegistry) { - sdr[types.StoreKey] = simulation.NewDecodeStore(am.keeper) -} +func (am AppModule) RegisterStoreDecoder(_ sdk.StoreDecoderRegistry) {} // WeightedOperations returns the all the gov module operations with their respective weights. func (am AppModule) WeightedOperations(simState module.SimulationState) []simtypes.WeightedOperation { diff --git a/x/bank/simulation/decoder.go b/x/bank/simulation/decoder.go deleted file mode 100644 index aafcf066e0..0000000000 --- a/x/bank/simulation/decoder.go +++ /dev/null @@ -1,39 +0,0 @@ -package simulation - -import ( - "bytes" - "fmt" - - "github.com/line/lbm-sdk/types/kv" - "github.com/line/lbm-sdk/x/bank/exported" - "github.com/line/lbm-sdk/x/bank/types" -) - -// SupplyUnmarshaler defines the expected encoding store functions. -type SupplyUnmarshaler interface { - UnmarshalSupply([]byte) (exported.SupplyI, error) -} - -// NewDecodeStore returns a function closure that unmarshals the KVPair's values -// to the corresponding types. -func NewDecodeStore(cdc SupplyUnmarshaler) func(kvA, kvB kv.Pair) string { - return func(kvA, kvB kv.Pair) string { - switch { - case bytes.Equal(kvA.Key[:1], types.SupplyKey): - supplyA, err := cdc.UnmarshalSupply(kvA.Value) - if err != nil { - panic(err) - } - - supplyB, err := cdc.UnmarshalSupply(kvB.Value) - if err != nil { - panic(err) - } - - return fmt.Sprintf("%v\n%v", supplyA, supplyB) - - default: - panic(fmt.Sprintf("unexpected %s key %X (%s)", types.ModuleName, kvA.Key, kvA.Key)) - } - } -} diff --git a/x/bank/simulation/operations.go b/x/bank/simulation/operations.go index 46bfe3789a..53fd4bf3e2 100644 --- a/x/bank/simulation/operations.go +++ b/x/bank/simulation/operations.go @@ -12,9 +12,11 @@ import ( simtypes "github.com/line/lbm-sdk/types/simulation" "github.com/line/lbm-sdk/x/bank/keeper" "github.com/line/lbm-sdk/x/bank/types" + distributiontypes "github.com/line/lbm-sdk/x/distribution/types" "github.com/line/lbm-sdk/x/simulation" ) +// nolint:gosec // Simulation operation weights constants const ( OpWeightMsgSend = "op_weight_msg_send" @@ -23,7 +25,7 @@ const ( // WeightedOperations returns all the operations from the module with their respective weights func WeightedOperations( - appParams simtypes.AppParams, cdc codec.JSONMarshaler, ak types.AccountKeeper, bk keeper.Keeper, + appParams simtypes.AppParams, cdc codec.JSONCodec, ak types.AccountKeeper, bk keeper.Keeper, ) simulation.WeightedOperations { var weightMsgSend, weightMsgMultiSend int @@ -58,10 +60,10 @@ func SimulateMsgSend(ak types.AccountKeeper, bk keeper.Keeper) simtypes.Operatio r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simtypes.Account, chainID string, ) (simtypes.OperationMsg, []simtypes.FutureOperation, error) { - simAccount, toSimAcc, coins, skip := randomSendFields(r, ctx, accs, bk, ak) + from, to, coins, skip := randomSendFields(r, ctx, accs, bk, ak) // Check send_enabled status of each coin denom - if err := bk.SendEnabledCoins(ctx, coins...); err != nil { + if err := bk.IsSendEnabledCoins(ctx, coins...); err != nil { return simtypes.NoOpMsg(types.ModuleName, types.TypeMsgSend, err.Error()), nil, nil } @@ -69,14 +71,44 @@ func SimulateMsgSend(ak types.AccountKeeper, bk keeper.Keeper) simtypes.Operatio return simtypes.NoOpMsg(types.ModuleName, types.TypeMsgSend, "skip all transfers"), nil, nil } - msg := types.NewMsgSend(simAccount.Address, toSimAcc.Address, coins) + msg := types.NewMsgSend(from.Address, to.Address, coins) - err := sendMsgSend(r, app, bk, ak, msg, ctx, chainID, []cryptotypes.PrivKey{simAccount.PrivKey}) + err := sendMsgSend(r, app, bk, ak, msg, ctx, chainID, []cryptotypes.PrivKey{from.PrivKey}) if err != nil { return simtypes.NoOpMsg(types.ModuleName, msg.Type(), "invalid transfers"), nil, err } - return simtypes.NewOperationMsg(msg, true, ""), nil, nil + return simtypes.NewOperationMsg(msg, true, "", nil), nil, nil + } +} + +// SimulateMsgSendToModuleAccount tests and runs a single msg send where both +// accounts already exist. +func SimulateMsgSendToModuleAccount(ak types.AccountKeeper, bk keeper.Keeper, moduleAccCount int) simtypes.Operation { + return func( + r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, + accs []simtypes.Account, chainID string, + ) (simtypes.OperationMsg, []simtypes.FutureOperation, error) { + from := accs[0] + + to := getModuleAccounts(ak, ctx, moduleAccCount)[0] + + spendable := bk.SpendableCoins(ctx, from.Address) + coins := simtypes.RandSubsetCoins(r, spendable) + + // Check send_enabled status of each coin denom + if err := bk.IsSendEnabledCoins(ctx, coins...); err != nil { + return simtypes.NoOpMsg(types.ModuleName, types.TypeMsgSend, err.Error()), nil, nil + } + + msg := types.NewMsgSend(from.Address, to.Address, coins) + + err := sendMsgSend(r, app, bk, ak, msg, ctx, chainID, []cryptotypes.PrivKey{from.PrivKey}) + if err != nil { + return simtypes.NoOpMsg(types.ModuleName, msg.Type(), "invalid transfers"), nil, err + } + + return simtypes.NewOperationMsg(msg, true, "", nil), nil, nil } } @@ -147,11 +179,11 @@ func SimulateMsgMultiSend(ak types.AccountKeeper, bk keeper.Keeper) simtypes.Ope var totalSentCoins sdk.Coins for i := range inputs { // generate random input fields, ignore to address - simAccount, _, coins, skip := randomSendFields(r, ctx, accs, bk, ak) + from, _, coins, skip := randomSendFields(r, ctx, accs, bk, ak) // make sure account is fresh and not used in previous input - for usedAddrs[simAccount.Address.String()] { - simAccount, _, coins, skip = randomSendFields(r, ctx, accs, bk, ak) + for usedAddrs[from.Address.String()] { + from, _, coins, skip = randomSendFields(r, ctx, accs, bk, ak) } if skip { @@ -159,18 +191,18 @@ func SimulateMsgMultiSend(ak types.AccountKeeper, bk keeper.Keeper) simtypes.Ope } // set input address in used address map - usedAddrs[simAccount.Address.String()] = true + usedAddrs[from.Address.String()] = true // set signer privkey - privs[i] = simAccount.PrivKey + privs[i] = from.PrivKey // set next input and accumulate total sent coins - inputs[i] = types.NewInput(simAccount.Address, coins) + inputs[i] = types.NewInput(from.Address, coins) totalSentCoins = totalSentCoins.Add(coins...) } // Check send_enabled status of each sent coin denom - if err := bk.SendEnabledCoins(ctx, totalSentCoins...); err != nil { + if err := bk.IsSendEnabledCoins(ctx, totalSentCoins...); err != nil { return simtypes.NoOpMsg(types.ModuleName, types.TypeMsgMultiSend, err.Error()), nil, nil } @@ -192,8 +224,8 @@ func SimulateMsgMultiSend(ak types.AccountKeeper, bk keeper.Keeper) simtypes.Ope } // remove any output that has no coins - i := 0 - for i < len(outputs) { + + for i := 0; i < len(outputs); { if outputs[i].Coins.Empty() { outputs[i] = outputs[len(outputs)-1] outputs = outputs[:len(outputs)-1] @@ -207,17 +239,84 @@ func SimulateMsgMultiSend(ak types.AccountKeeper, bk keeper.Keeper) simtypes.Ope Inputs: inputs, Outputs: outputs, } + err := sendMsgMultiSend(r, app, bk, ak, msg, ctx, chainID, privs) + if err != nil { + return simtypes.NoOpMsg(types.ModuleName, msg.Type(), "invalid transfers"), nil, err + } + + return simtypes.NewOperationMsg(msg, true, "", nil), nil, nil + } +} + +// SimulateMsgMultiSendToModuleAccount sends coins to Module Accounts +func SimulateMsgMultiSendToModuleAccount(ak types.AccountKeeper, bk keeper.Keeper, moduleAccCount int) simtypes.Operation { + return func( + r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, + accs []simtypes.Account, chainID string, + ) (simtypes.OperationMsg, []simtypes.FutureOperation, error) { + + inputs := make([]types.Input, 2) + outputs := make([]types.Output, moduleAccCount) + // collect signer privKeys + privs := make([]cryptotypes.PrivKey, len(inputs)) + var totalSentCoins sdk.Coins + for i := range inputs { + sender := accs[i] + privs[i] = sender.PrivKey + spendable := bk.SpendableCoins(ctx, sender.Address) + coins := simtypes.RandSubsetCoins(r, spendable) + inputs[i] = types.NewInput(sender.Address, coins) + totalSentCoins = totalSentCoins.Add(coins...) + } + + if err := bk.IsSendEnabledCoins(ctx, totalSentCoins...); err != nil { + return simtypes.NoOpMsg(types.ModuleName, types.TypeMsgMultiSend, err.Error()), nil, nil + } + + moduleAccounts := getModuleAccounts(ak, ctx, moduleAccCount) + for i := range outputs { + var outCoins sdk.Coins + // split total sent coins into random subsets for output + if i == len(outputs)-1 { + outCoins = totalSentCoins + } else { + // take random subset of remaining coins for output + // and update remaining coins + outCoins = simtypes.RandSubsetCoins(r, totalSentCoins) + totalSentCoins = totalSentCoins.Sub(outCoins) + } + + outputs[i] = types.NewOutput(moduleAccounts[i].Address, outCoins) + } + + // remove any output that has no coins + + for i := 0; i < len(outputs); { + if outputs[i].Coins.Empty() { + outputs[i] = outputs[len(outputs)-1] + outputs = outputs[:len(outputs)-1] + } else { + // continue onto next coin + i++ + } + } + + msg := &types.MsgMultiSend{ + Inputs: inputs, + Outputs: outputs, + } err := sendMsgMultiSend(r, app, bk, ak, msg, ctx, chainID, privs) if err != nil { return simtypes.NoOpMsg(types.ModuleName, msg.Type(), "invalid transfers"), nil, err } - return simtypes.NewOperationMsg(msg, true, ""), nil, nil + return simtypes.NewOperationMsg(msg, true, "", nil), nil, nil } } // sendMsgMultiSend sends a transaction with a MsgMultiSend from a provided random +// account. func sendMsgMultiSend( r *rand.Rand, app *baseapp.BaseApp, bk keeper.Keeper, ak types.AccountKeeper, msg *types.MsgMultiSend, ctx sdk.Context, chainID string, privkeys []cryptotypes.PrivKey, @@ -281,25 +380,44 @@ func randomSendFields( r *rand.Rand, ctx sdk.Context, accs []simtypes.Account, bk keeper.Keeper, ak types.AccountKeeper, ) (simtypes.Account, simtypes.Account, sdk.Coins, bool) { - simAccount, _ := simtypes.RandomAcc(r, accs) - toSimAcc, _ := simtypes.RandomAcc(r, accs) + from, _ := simtypes.RandomAcc(r, accs) + to, _ := simtypes.RandomAcc(r, accs) // disallow sending money to yourself - for simAccount.PubKey.Equals(toSimAcc.PubKey) { - toSimAcc, _ = simtypes.RandomAcc(r, accs) + for from.PubKey.Equals(to.PubKey) { + to, _ = simtypes.RandomAcc(r, accs) } - acc := ak.GetAccount(ctx, simAccount.Address) + acc := ak.GetAccount(ctx, from.Address) if acc == nil { - return simAccount, toSimAcc, nil, true + return from, to, nil, true } spendable := bk.SpendableCoins(ctx, acc.GetAddress()) sendCoins := simtypes.RandSubsetCoins(r, spendable) if sendCoins.Empty() { - return simAccount, toSimAcc, nil, true + return from, to, nil, true + } + + return from, to, sendCoins, false +} + +func getModuleAccounts(ak types.AccountKeeper, ctx sdk.Context, moduleAccCount int) []simtypes.Account { + + moduleAccounts := make([]simtypes.Account, moduleAccCount) + + for i := 0; i < moduleAccCount; i++ { + addr := ak.GetModuleAddress(distributiontypes.ModuleName) + acc := ak.GetAccount(ctx, addr) + mAcc := simtypes.Account{ + Address: acc.GetAddress(), + PrivKey: nil, + ConsKey: nil, + PubKey: acc.GetPubKey(), + } + moduleAccounts[i] = mAcc } - return simAccount, toSimAcc, sendCoins, false + return moduleAccounts } diff --git a/x/bank/simulation/operations_test.go b/x/bank/simulation/operations_test.go index 70a6767844..bba4a6d862 100644 --- a/x/bank/simulation/operations_test.go +++ b/x/bank/simulation/operations_test.go @@ -104,18 +104,82 @@ func (suite *SimTestSuite) TestSimulateMsgMultiSend() { // execute operation op := simulation.SimulateMsgMultiSend(suite.app.AccountKeeper, suite.app.BankKeeper) operationMsg, futureOperations, err := op(r, suite.app.BaseApp, suite.ctx, accounts, "") - suite.Require().NoError(err) + require := suite.Require() + require.NoError(err) var msg types.MsgMultiSend types.ModuleCdc.UnmarshalJSON(operationMsg.Msg, &msg) + require.True(operationMsg.OK) + require.Len(msg.Inputs, 3) + require.Equal("link1p8wcgrjr4pjju90xg6u9cgq55dxwq8j7fmx8x8", msg.Inputs[1].Address) + require.Equal("185121068stake", msg.Inputs[1].Coins.String()) + require.Len(msg.Outputs, 2) + require.Equal("link1ghekyjucln7y67ntx7cf27m9dpuxxemnqk82wt", msg.Outputs[1].Address) + require.Equal("260469617stake", msg.Outputs[1].Coins.String()) + require.Equal(types.TypeMsgMultiSend, msg.Type()) + require.Equal(types.ModuleName, msg.Route()) + require.Len(futureOperations, 0) +} + +// Since the allowedReceivingModAcc value of the distribution module is set to true, change it to test in which the result is true. +func (suite *SimTestSuite) TestSimulateModuleAccountMsgSend() { + const ( + accCount = 1 + moduleAccCount = 1 + ) + + s := rand.NewSource(1) + r := rand.New(s) + accounts := suite.getTestingAccounts(r, accCount) + + // begin a new block + suite.app.BeginBlock(abci.RequestBeginBlock{Header: ocproto.Header{Height: suite.app.LastBlockHeight() + 1, AppHash: suite.app.LastCommitID().Hash}}) + + // execute operation + op := simulation.SimulateMsgSendToModuleAccount(suite.app.AccountKeeper, suite.app.BankKeeper, moduleAccCount) + + s = rand.NewSource(1) + r = rand.New(s) + + operationMsg, futureOperations, err := op(r, suite.app.BaseApp, suite.ctx, accounts, "") + suite.Require().NoError(err) + + var msg types.MsgSend + types.ModuleCdc.UnmarshalJSON(operationMsg.Msg, &msg) + suite.Require().True(operationMsg.OK) - suite.Require().Len(msg.Inputs, 3) - suite.Require().Equal("link1p8wcgrjr4pjju90xg6u9cgq55dxwq8j7fmx8x8", msg.Inputs[1].Address) - suite.Require().Equal("185121068stake", msg.Inputs[1].Coins.String()) - suite.Require().Len(msg.Outputs, 2) - suite.Require().Equal("link1ghekyjucln7y67ntx7cf27m9dpuxxemnqk82wt", msg.Outputs[1].Address) - suite.Require().Equal("260469617stake", msg.Outputs[1].Coins.String()) + suite.Require().Empty(operationMsg.Comment) + suite.Require().Equal(types.TypeMsgSend, msg.Type()) + suite.Require().Equal(types.ModuleName, msg.Route()) + suite.Require().Len(futureOperations, 0) +} + +// Since the allowedReceivingModAcc value of the distribution module is set to true, change it to test in which the result is true. +func (suite *SimTestSuite) TestSimulateMsgMultiSendToModuleAccount() { + const ( + accCount = 2 + mAccCount = 2 + ) + + s := rand.NewSource(1) + r := rand.New(s) + accounts := suite.getTestingAccounts(r, accCount) + + // begin a new block + suite.app.BeginBlock(abci.RequestBeginBlock{Header: ocproto.Header{Height: suite.app.LastBlockHeight() + 1, AppHash: suite.app.LastCommitID().Hash}}) + + // execute operation + op := simulation.SimulateMsgMultiSendToModuleAccount(suite.app.AccountKeeper, suite.app.BankKeeper, mAccCount) + + operationMsg, futureOperations, err := op(r, suite.app.BaseApp, suite.ctx, accounts, "") + suite.Require().NoError(err) + + var msg types.MsgMultiSend + types.ModuleCdc.UnmarshalJSON(operationMsg.Msg, &msg) + + suite.Require().True(operationMsg.OK) // sending tokens to a module account should fail + suite.Require().Empty(operationMsg.Comment) suite.Require().Equal(types.TypeMsgMultiSend, msg.Type()) suite.Require().Equal(types.ModuleName, msg.Route()) suite.Require().Len(futureOperations, 0) @@ -124,15 +188,14 @@ func (suite *SimTestSuite) TestSimulateMsgMultiSend() { func (suite *SimTestSuite) getTestingAccounts(r *rand.Rand, n int) []simtypes.Account { accounts := simtypes.RandomAccounts(r, n) - initAmt := sdk.TokensFromConsensusPower(200) + initAmt := suite.app.StakingKeeper.TokensFromConsensusPower(suite.ctx, 200) initCoins := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, initAmt)) // add coins to the accounts for _, account := range accounts { acc := suite.app.AccountKeeper.NewAccountWithAddress(suite.ctx, account.Address) suite.app.AccountKeeper.SetAccount(suite.ctx, acc) - err := suite.app.BankKeeper.SetBalances(suite.ctx, account.Address, initCoins) - suite.Require().NoError(err) + suite.Require().NoError(simapp.FundAccount(suite.app, suite.ctx, account.Address, initCoins)) } return accounts diff --git a/x/bank/spec/01_state.md b/x/bank/spec/01_state.md index 6ca6b97e8f..5328e8b3ca 100644 --- a/x/bank/spec/01_state.md +++ b/x/bank/spec/01_state.md @@ -4,8 +4,9 @@ order: 1 # State -The `x/bank` module keeps state of two primary objects, account balances and the +The `x/bank` module keeps state of three primary objects, account balances, denom metadata and the total supply of all balances. -- Supply: `0x0 -> ProtocolBuffer(Supply)` +- Supply: `0x0 | byte(denom) -> byte(amount)` +- Denom Metadata: `0x1 | byte(denom) -> ProtocolBuffer(Metadata)` - Balances: `0x2 | byte(address length) | []byte(address) | []byte(balance.Denom) -> ProtocolBuffer(balance)` diff --git a/x/bank/spec/02_keepers.md b/x/bank/spec/02_keepers.md index 6714e8beb3..451cb738d3 100644 --- a/x/bank/spec/02_keepers.md +++ b/x/bank/spec/02_keepers.md @@ -4,9 +4,25 @@ order: 2 # Keepers -The bank module provides three different exported keeper interfaces which can be passed to other modules which need to read or update account balances. Modules should use the least-permissive interface which provides the functionality they require. +The bank module provides these exported keeper interfaces that can be +passed to other modules that read or update account balances. Modules +should use the least-permissive interface that provides the functionality they +require. -Note that you should always review the `bank` module code to ensure that permissions are limited in the way that you expect. +Best practices dictate careful review of `bank` module code to ensure that +permissions are limited in the way that you expect. + +## Blocklisting Addresses + +The `x/bank` module accepts a map of addresses that are considered blocklisted +from directly and explicitly receiving funds through means such as `MsgSend` and +`MsgMultiSend` and direct API calls like `SendCoinsFromModuleToAccount`. + +Typically, these addresses are module accounts. If these addresses receive funds +outside the expected rules of the state machine, invariants are likely to be +broken and could result in a halted network. + +By providing the `x/bank` module with a blocklisted set of addresses, an error occurs for the operation if a user or client attempts to directly or indirectly send funds to a blocklisted account, for example, by using [IBC](http://docs.cosmos.network/master/ibc/). ## Common Types @@ -42,82 +58,75 @@ The base keeper provides full-permission access: the ability to arbitrary modify // Keeper defines a module interface that facilitates the transfer of coins // between accounts. type Keeper interface { - SendKeeper - - InitGenesis(sdk.Context, *types.GenesisState) - ExportGenesis(sdk.Context) *types.GenesisState - - GetSupply(ctx sdk.Context) exported.SupplyI - SetSupply(ctx sdk.Context, supply exported.SupplyI) - - GetDenomMetaData(ctx sdk.Context, denom string) types.Metadata - SetDenomMetaData(ctx sdk.Context, denomMetaData types.Metadata) - IterateAllDenomMetaData(ctx sdk.Context, cb func(types.Metadata) bool) - - SendCoinsFromModuleToAccount(ctx sdk.Context, senderModule string, recipientAddr sdk.AccAddress, amt sdk.Coins) error - SendCoinsFromModuleToModule(ctx sdk.Context, senderModule, recipientModule string, amt sdk.Coins) error - SendCoinsFromAccountToModule(ctx sdk.Context, senderAddr sdk.AccAddress, recipientModule string, amt sdk.Coins) error - DelegateCoinsFromAccountToModule(ctx sdk.Context, senderAddr sdk.AccAddress, recipientModule string, amt sdk.Coins) error - UndelegateCoinsFromModuleToAccount(ctx sdk.Context, senderModule string, recipientAddr sdk.AccAddress, amt sdk.Coins) error - MintCoins(ctx sdk.Context, moduleName string, amt sdk.Coins) error - BurnCoins(ctx sdk.Context, moduleName string, amt sdk.Coins) error - - DelegateCoins(ctx sdk.Context, delegatorAddr, moduleAccAddr sdk.AccAddress, amt sdk.Coins) error - UndelegateCoins(ctx sdk.Context, moduleAccAddr, delegatorAddr sdk.AccAddress, amt sdk.Coins) error - MarshalSupply(supplyI exported.SupplyI) ([]byte, error) - UnmarshalSupply(bz []byte) (exported.SupplyI, error) - - types.QueryServer + SendKeeper + + InitGenesis(sdk.Context, *types.GenesisState) + ExportGenesis(sdk.Context) *types.GenesisState + + GetSupply(ctx sdk.Context, denom string) sdk.Coin + GetPaginatedTotalSupply(ctx sdk.Context, pagination *query.PageRequest) (sdk.Coins, *query.PageResponse, error) + IterateTotalSupply(ctx sdk.Context, cb func(sdk.Coin) bool) + GetDenomMetaData(ctx sdk.Context, denom string) (types.Metadata, bool) + SetDenomMetaData(ctx sdk.Context, denomMetaData types.Metadata) + IterateAllDenomMetaData(ctx sdk.Context, cb func(types.Metadata) bool) + + SendCoinsFromModuleToAccount(ctx sdk.Context, senderModule string, recipientAddr sdk.AccAddress, amt sdk.Coins) error + SendCoinsFromModuleToModule(ctx sdk.Context, senderModule, recipientModule string, amt sdk.Coins) error + SendCoinsFromAccountToModule(ctx sdk.Context, senderAddr sdk.AccAddress, recipientModule string, amt sdk.Coins) error + DelegateCoinsFromAccountToModule(ctx sdk.Context, senderAddr sdk.AccAddress, recipientModule string, amt sdk.Coins) error + UndelegateCoinsFromModuleToAccount(ctx sdk.Context, senderModule string, recipientAddr sdk.AccAddress, amt sdk.Coins) error + MintCoins(ctx sdk.Context, moduleName string, amt sdk.Coins) error + BurnCoins(ctx sdk.Context, moduleName string, amt sdk.Coins) error + + DelegateCoins(ctx sdk.Context, delegatorAddr, moduleAccAddr sdk.AccAddress, amt sdk.Coins) error + UndelegateCoins(ctx sdk.Context, moduleAccAddr, delegatorAddr sdk.AccAddress, amt sdk.Coins) error + + types.QueryServer } ``` ## SendKeeper -The send keeper provides access to account balances and the ability to transfer coins between accounts, but not to alter the total supply (mint or burn coins). +The send keeper provides access to account balances and the ability to transfer coins between +accounts. The send keeper does not alter the total supply (mint or burn coins). ```go // SendKeeper defines a module interface that facilitates the transfer of coins // between accounts without the possibility of creating coins. type SendKeeper interface { - ViewKeeper - - InputOutputCoins(ctx sdk.Context, inputs []types.Input, outputs []types.Output) error - SendCoins(ctx sdk.Context, fromAddr sdk.AccAddress, toAddr sdk.AccAddress, amt sdk.Coins) error - - SubtractCoins(ctx sdk.Context, addr sdk.AccAddress, amt sdk.Coins) error - AddCoins(ctx sdk.Context, addr sdk.AccAddress, amt sdk.Coins) error + ViewKeeper - SetBalance(ctx sdk.Context, addr sdk.AccAddress, balance sdk.Coin) error - SetBalances(ctx sdk.Context, addr sdk.AccAddress, balances sdk.Coins) error + InputOutputCoins(ctx sdk.Context, inputs []types.Input, outputs []types.Output) error + SendCoins(ctx sdk.Context, fromAddr sdk.AccAddress, toAddr sdk.AccAddress, amt sdk.Coins) error - GetParams(ctx sdk.Context) types.Params - SetParams(ctx sdk.Context, params types.Params) + GetParams(ctx sdk.Context) types.Params + SetParams(ctx sdk.Context, params types.Params) - SendEnabledCoin(ctx sdk.Context, coin sdk.Coin) bool - SendEnabledCoins(ctx sdk.Context, coins ...sdk.Coin) error + IsSendEnabledCoin(ctx sdk.Context, coin sdk.Coin) bool + IsSendEnabledCoins(ctx sdk.Context, coins ...sdk.Coin) error - BlockedAddr(addr sdk.AccAddress) bool + BlockedAddr(addr sdk.AccAddress) bool } ``` ## ViewKeeper -The view keeper provides read-only access to account balances but no balance alteration functionality. All balance lookups are `O(1)`. +The view keeper provides read-only access to account balances. The view keeper does not have balance alteration functionality. All balance lookups are `O(1)`. ```go // ViewKeeper defines a module interface that facilitates read only access to // account balances. type ViewKeeper interface { - ValidateBalance(ctx sdk.Context, addr sdk.AccAddress) error - HasBalance(ctx sdk.Context, addr sdk.AccAddress, amt sdk.Coin) bool + ValidateBalance(ctx sdk.Context, addr sdk.AccAddress) error + HasBalance(ctx sdk.Context, addr sdk.AccAddress, amt sdk.Coin) bool - GetAllBalances(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins - GetAccountsBalances(ctx sdk.Context) []types.Balance - GetBalance(ctx sdk.Context, addr sdk.AccAddress, denom string) sdk.Coin - LockedCoins(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins - SpendableCoins(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins + GetAllBalances(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins + GetAccountsBalances(ctx sdk.Context) []types.Balance + GetBalance(ctx sdk.Context, addr sdk.AccAddress, denom string) sdk.Coin + LockedCoins(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins + SpendableCoins(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins - IterateAccountBalances(ctx sdk.Context, addr sdk.AccAddress, cb func(coin sdk.Coin) (stop bool)) - IterateAllBalances(ctx sdk.Context, cb func(address sdk.AccAddress, coin sdk.Coin) (stop bool)) + IterateAccountBalances(ctx sdk.Context, addr sdk.AccAddress, cb func(coin sdk.Coin) (stop bool)) + IterateAllBalances(ctx sdk.Context, cb func(address sdk.AccAddress, coin sdk.Coin) (stop bool)) } ``` diff --git a/x/bank/spec/03_messages.md b/x/bank/spec/03_messages.md index 72a039d689..61f83abf3d 100644 --- a/x/bank/spec/03_messages.md +++ b/x/bank/spec/03_messages.md @@ -6,20 +6,22 @@ order: 3 ## MsgSend -+++ https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/bank/v1/tx.proto#L19-L28 - -`handleMsgSend` just runs `inputOutputCoins`. - -```go -handleMsgSend(msg MsgSend) - inputSum = 0 - for input in inputs - inputSum += input.Amount - outputSum = 0 - for output in outputs - outputSum += output.Amount - if inputSum != outputSum: - fail with "input/output amount mismatch" - - return inputOutputCoins(msg.Inputs, msg.Outputs) -``` +Send coins from one address to another. ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/bank/v1beta1/tx.proto#L19-L28 + +The message will fail under the following conditions: + +- The coins do not have sending enabled +- The `to` address is restricted + +## MsgMultiSend + +Send coins from and to a series of different address. If any of the receiving addresses do not correspond to an existing account, a new account is created. ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/bank/v1beta1/tx.proto#L33-L39 + +The message will fail under the following conditions: + +- Any of the coins do not have sending enabled +- Any of the `to` addresses are restricted +- Any of the coins are locked +- The inputs and outputs do not correctly correspond to one another diff --git a/x/bank/spec/04_events.md b/x/bank/spec/04_events.md index 55c93b805e..e71b820571 100644 --- a/x/bank/spec/04_events.md +++ b/x/bank/spec/04_events.md @@ -27,3 +27,123 @@ The bank module emits the following events: | message | module | bank | | message | action | multisend | | message | sender | {senderAddress} | + +## Keeper events + +In addition to handlers events, the bank keeper will produce events when the following methods are called (or any method which ends up calling them) + +### MintCoins + +```json +{ + "type": "coinbase", + "attributes": [ + { + "key": "minter", + "value": "{{sdk.AccAddress of the module minting coins}}", + "index": true + }, + { + "key": "amount", + "value": "{{sdk.Coins being minted}}", + "index": true + } + ] +} +``` + +```json +{ + "type": "coin_received", + "attributes": [ + { + "key": "receiver", + "value": "{{sdk.AccAddress of the module minting coins}}", + "index": true + }, + { + "key": "amount", + "value": "{{sdk.Coins being received}}", + "index": true + } + ] +} +``` + +### BurnCoins + +```json +{ + "type": "burn", + "attributes": [ + { + "key": "burner", + "value": "{{sdk.AccAddress of the module burning coins}}", + "index": true + }, + { + "key": "amount", + "value": "{{sdk.Coins being burned}}", + "index": true + } + ] +} +``` + +```json +{ + "type": "coin_spent", + "attributes": [ + { + "key": "spender", + "value": "{{sdk.AccAddress of the module burning coins}}", + "index": true + }, + { + "key": "amount", + "value": "{{sdk.Coins being burned}}", + "index": true + } + ] +} +``` + +### addCoins + +```json +{ + "type": "coin_received", + "attributes": [ + { + "key": "receiver", + "value": "{{sdk.AccAddress of the address beneficiary of the coins}}", + "index": true + }, + { + "key": "amount", + "value": "{{sdk.Coins being received}}", + "index": true + } + ] +} +``` + +### subUnlockedCoins/DelegateCoins + +```json +{ + "type": "coin_spent", + "attributes": [ + { + "key": "spender", + "value": "{{sdk.AccAddress of the address which is spending coins}}", + "index": true + }, + { + "key": "amount", + "value": "{{sdk.Coins being spent}}", + "index": true + } + ] +} +``` diff --git a/x/bank/types/authz.pb.go b/x/bank/types/authz.pb.go new file mode 100644 index 0000000000..8ede54ba25 --- /dev/null +++ b/x/bank/types/authz.pb.go @@ -0,0 +1,340 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: lbm/bank/v1/authz.proto + +package types + +import ( + fmt "fmt" + _ "github.com/gogo/protobuf/gogoproto" + proto "github.com/gogo/protobuf/proto" + github_com_line_lbm_sdk_types "github.com/line/lbm-sdk/types" + types "github.com/line/lbm-sdk/types" + _ "github.com/regen-network/cosmos-proto" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +// SendAuthorization allows the grantee to spend up to spend_limit coins from +// the granter's account. +// +// Since: cosmos-sdk 0.43 +type SendAuthorization struct { + SpendLimit github_com_line_lbm_sdk_types.Coins `protobuf:"bytes,1,rep,name=spend_limit,json=spendLimit,proto3,castrepeated=github.com/line/lbm-sdk/types.Coins" json:"spend_limit"` +} + +func (m *SendAuthorization) Reset() { *m = SendAuthorization{} } +func (m *SendAuthorization) String() string { return proto.CompactTextString(m) } +func (*SendAuthorization) ProtoMessage() {} +func (*SendAuthorization) Descriptor() ([]byte, []int) { + return fileDescriptor_74b853037a4cabe2, []int{0} +} +func (m *SendAuthorization) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *SendAuthorization) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_SendAuthorization.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *SendAuthorization) XXX_Merge(src proto.Message) { + xxx_messageInfo_SendAuthorization.Merge(m, src) +} +func (m *SendAuthorization) XXX_Size() int { + return m.Size() +} +func (m *SendAuthorization) XXX_DiscardUnknown() { + xxx_messageInfo_SendAuthorization.DiscardUnknown(m) +} + +var xxx_messageInfo_SendAuthorization proto.InternalMessageInfo + +func (m *SendAuthorization) GetSpendLimit() github_com_line_lbm_sdk_types.Coins { + if m != nil { + return m.SpendLimit + } + return nil +} + +func init() { + proto.RegisterType((*SendAuthorization)(nil), "lbm.bank.v1.SendAuthorization") +} + +func init() { proto.RegisterFile("lbm/bank/v1/authz.proto", fileDescriptor_74b853037a4cabe2) } + +var fileDescriptor_74b853037a4cabe2 = []byte{ + // 259 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x12, 0xcf, 0x49, 0xca, 0xd5, + 0x4f, 0x4a, 0xcc, 0xcb, 0xd6, 0x2f, 0x33, 0xd4, 0x4f, 0x2c, 0x2d, 0xc9, 0xa8, 0xd2, 0x2b, 0x28, + 0xca, 0x2f, 0xc9, 0x17, 0xe2, 0xce, 0x49, 0xca, 0xd5, 0x03, 0x49, 0xe8, 0x95, 0x19, 0x4a, 0x89, + 0xa4, 0xe7, 0xa7, 0xe7, 0x83, 0xc5, 0xf5, 0x41, 0x2c, 0x88, 0x12, 0x29, 0xc9, 0xe4, 0xfc, 0xe2, + 0xdc, 0xfc, 0xe2, 0x78, 0x88, 0x04, 0x84, 0x03, 0x95, 0x12, 0x83, 0x18, 0x5b, 0x9c, 0x0a, 0x32, + 0x36, 0x39, 0x3f, 0x33, 0x0f, 0x22, 0xae, 0xd4, 0xce, 0xc8, 0x25, 0x18, 0x9c, 0x9a, 0x97, 0xe2, + 0x58, 0x5a, 0x92, 0x91, 0x5f, 0x94, 0x59, 0x95, 0x58, 0x92, 0x99, 0x9f, 0x27, 0x14, 0xcf, 0xc5, + 0x5d, 0x5c, 0x90, 0x9a, 0x97, 0x12, 0x9f, 0x93, 0x99, 0x9b, 0x59, 0x22, 0xc1, 0xa8, 0xc0, 0xac, + 0xc1, 0x6d, 0x24, 0xa8, 0x07, 0x71, 0x41, 0x71, 0xaa, 0x5e, 0x99, 0xa1, 0x9e, 0x73, 0x7e, 0x66, + 0x9e, 0x93, 0xf6, 0x89, 0x7b, 0xf2, 0x0c, 0xab, 0xee, 0xcb, 0x2b, 0xa7, 0x67, 0x96, 0x64, 0x94, + 0x26, 0xe9, 0x25, 0xe7, 0xe7, 0xea, 0xe7, 0x64, 0xe6, 0xa5, 0xea, 0xe7, 0x24, 0xe5, 0xea, 0x16, + 0xa7, 0x64, 0xeb, 0x97, 0x54, 0x16, 0xa4, 0x16, 0x83, 0xd5, 0x16, 0x07, 0x71, 0x81, 0x8d, 0xf4, + 0x01, 0x99, 0x68, 0x25, 0x78, 0x69, 0x8b, 0x2e, 0x2f, 0x8a, 0x9d, 0x4e, 0x76, 0x27, 0x1e, 0xc9, + 0x31, 0x5e, 0x78, 0x24, 0xc7, 0xf8, 0xe0, 0x91, 0x1c, 0xe3, 0x84, 0xc7, 0x72, 0x0c, 0x17, 0x1e, + 0xcb, 0x31, 0xdc, 0x78, 0x2c, 0xc7, 0x10, 0xa5, 0x82, 0xcb, 0xf4, 0x0a, 0x48, 0x40, 0x81, 0x2d, + 0x49, 0x62, 0x03, 0x7b, 0xc8, 0x18, 0x10, 0x00, 0x00, 0xff, 0xff, 0x49, 0x77, 0x9e, 0x29, 0x41, + 0x01, 0x00, 0x00, +} + +func (m *SendAuthorization) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *SendAuthorization) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *SendAuthorization) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.SpendLimit) > 0 { + for iNdEx := len(m.SpendLimit) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.SpendLimit[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintAuthz(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func encodeVarintAuthz(dAtA []byte, offset int, v uint64) int { + offset -= sovAuthz(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *SendAuthorization) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.SpendLimit) > 0 { + for _, e := range m.SpendLimit { + l = e.Size() + n += 1 + l + sovAuthz(uint64(l)) + } + } + return n +} + +func sovAuthz(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozAuthz(x uint64) (n int) { + return sovAuthz(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *SendAuthorization) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAuthz + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: SendAuthorization: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: SendAuthorization: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field SpendLimit", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAuthz + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthAuthz + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthAuthz + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.SpendLimit = append(m.SpendLimit, types.Coin{}) + if err := m.SpendLimit[len(m.SpendLimit)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipAuthz(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthAuthz + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipAuthz(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowAuthz + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowAuthz + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowAuthz + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthAuthz + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupAuthz + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthAuthz + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthAuthz = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowAuthz = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupAuthz = fmt.Errorf("proto: unexpected end of group") +) diff --git a/x/bank/types/balance.go b/x/bank/types/balance.go index 5cebc58c03..089a2500b0 100644 --- a/x/bank/types/balance.go +++ b/x/bank/types/balance.go @@ -1,10 +1,9 @@ package types import ( + "bytes" "encoding/json" - fmt "fmt" "sort" - "strings" "github.com/line/lbm-sdk/codec" sdk "github.com/line/lbm-sdk/types" @@ -29,32 +28,28 @@ func (b Balance) Validate() error { if err != nil { return err } - seenDenoms := make(map[string]bool) - // NOTE: we perform a custom validation since the coins.Validate function - // errors on zero balance coins - for _, coin := range b.Coins { - if seenDenoms[coin.Denom] { - return fmt.Errorf("duplicate denomination %s", coin.Denom) - } - - if err := sdk.ValidateDenom(coin.Denom); err != nil { - return err - } - - if coin.IsNegative() { - return fmt.Errorf("coin %s amount is cannot be negative", coin.Denom) - } - - seenDenoms[coin.Denom] = true + if err := b.Coins.Validate(); err != nil { + return err } - // sort the coins post validation - b.Coins.Sort() - return nil } +type balanceByAddress struct { + addresses []sdk.AccAddress + balances []Balance +} + +func (b balanceByAddress) Len() int { return len(b.addresses) } +func (b balanceByAddress) Less(i, j int) bool { + return bytes.Compare(b.addresses[i].Bytes(), b.addresses[j].Bytes()) < 0 +} +func (b balanceByAddress) Swap(i, j int) { + b.addresses[i], b.addresses[j] = b.addresses[j], b.addresses[i] + b.balances[i], b.balances[j] = b.balances[j], b.balances[i] +} + // SanitizeGenesisBalances sorts addresses and coin sets. func SanitizeGenesisBalances(balances []Balance) []Balance { // Given that this function sorts balances, using the standard library's @@ -65,38 +60,17 @@ func SanitizeGenesisBalances(balances []Balance) []Balance { // before whereby sdk.AccAddressFromBech32, which is a very expensive operation // compared n * n elements yet discarded computations each time, as per: // https://github.com/cosmos/cosmos-sdk/issues/7766#issuecomment-786671734 - // with this change the first step is to extract out and singly produce the values - // that'll be used for comparisons and keep them cheap and fast. - - // 1. Retrieve the byte equivalents for each Balance's address and maintain a mapping of - // its Balance, as the mapper will be used in sorting. - type addrToBalance struct { - // We use a pointer here to avoid averse effects of value copying - // wasting RAM all around. - balance *Balance - accAddr sdk.AccAddress - } - adL := make([]*addrToBalance, 0, len(balances)) - for _, balance := range balances { - balance := balance - adL = append(adL, &addrToBalance{ - balance: &balance, - accAddr: sdk.AccAddress(balance.Address), - }) - } - // 2. Sort with the cheap mapping, using the mapper's - // already accAddr bytes values which is a cheaper operation. - sort.Slice(adL, func(i, j int) bool { - ai, aj := adL[i], adL[j] - return strings.Compare(string(ai.accAddr), string(aj.accAddr)) < 0 - }) - - // 3. To complete the sorting, we have to now just insert - // back the balances in the order returned by the sort. - for i, ad := range adL { - balances[i] = *ad.balance + // 1. Retrieve the address equivalents for each Balance's address. + addresses := make([]sdk.AccAddress, len(balances)) + for i := range balances { + addr := sdk.AccAddress(balances[i].Address) + addresses[i] = addr } + + // 2. Sort balances. + sort.Sort(balanceByAddress{addresses: addresses, balances: balances}) + return balances } @@ -107,7 +81,7 @@ type GenesisBalancesIterator struct{} // appGenesis and invokes a callback on each genesis account. If any call // returns true, iteration stops. func (GenesisBalancesIterator) IterateGenesisBalances( - cdc codec.JSONMarshaler, appState map[string]json.RawMessage, cb func(exported.GenesisBalance) (stop bool), + cdc codec.JSONCodec, appState map[string]json.RawMessage, cb func(exported.GenesisBalance) (stop bool), ) { for _, balance := range GetGenesisStateFromAppState(cdc, appState).Balances { if cb(balance) { diff --git a/x/bank/types/balance_test.go b/x/bank/types/balance_test.go index 48cc1f2579..dae95fba4b 100644 --- a/x/bank/types/balance_test.go +++ b/x/bank/types/balance_test.go @@ -1,7 +1,7 @@ package types_test import ( - "strings" + "bytes" "testing" "github.com/stretchr/testify/require" @@ -20,7 +20,7 @@ func TestBalanceValidate(t *testing.T) { { "valid balance", bank.Balance{ - Address: "link1mejkku76a2ec35262rdqddggzwrgtrh52t3t0c", + Address: "link1yq8lgssgxlx9smjhes6ryjasmqmd3ts2p6925r", Coins: sdk.Coins{sdk.NewInt64Coin("uatom", 1)}, }, false, @@ -29,14 +29,14 @@ func TestBalanceValidate(t *testing.T) { { "nil balance coins", bank.Balance{ - Address: "link1mejkku76a2ec35262rdqddggzwrgtrh52t3t0c", + Address: "link1yq8lgssgxlx9smjhes6ryjasmqmd3ts2p6925r", }, false, }, { "dup coins", bank.Balance{ - Address: "link1mejkku76a2ec35262rdqddggzwrgtrh52t3t0c", + Address: "link1yq8lgssgxlx9smjhes6ryjasmqmd3ts2p6925r", Coins: sdk.Coins{ sdk.NewInt64Coin("uatom", 1), sdk.NewInt64Coin("uatom", 1), @@ -47,7 +47,7 @@ func TestBalanceValidate(t *testing.T) { { "invalid coin denom", bank.Balance{ - Address: "link1mejkku76a2ec35262rdqddggzwrgtrh52t3t0c", + Address: "link1yq8lgssgxlx9smjhes6ryjasmqmd3ts2p6925r", Coins: sdk.Coins{ sdk.Coin{Denom: "", Amount: sdk.OneInt()}, }, @@ -57,13 +57,48 @@ func TestBalanceValidate(t *testing.T) { { "negative coin", bank.Balance{ - Address: "link1mejkku76a2ec35262rdqddggzwrgtrh52t3t0c", + Address: "link1yq8lgssgxlx9smjhes6ryjasmqmd3ts2p6925r", Coins: sdk.Coins{ sdk.Coin{Denom: "uatom", Amount: sdk.NewInt(-1)}, }, }, true, }, + { + "0 value coin", + bank.Balance{ + Address: "link1yq8lgssgxlx9smjhes6ryjasmqmd3ts2p6925r", + Coins: sdk.Coins{ + sdk.NewInt64Coin("atom", 0), + sdk.NewInt64Coin("zatom", 2), + }, + }, + true, + }, + { + "unsorted coins", + bank.Balance{ + Address: "link1yq8lgssgxlx9smjhes6ryjasmqmd3ts2p6925r", + Coins: sdk.Coins{ + sdk.NewInt64Coin("atom", 2), + sdk.NewInt64Coin("zatom", 2), + sdk.NewInt64Coin("batom", 12), + }, + }, + true, + }, + { + "valid sorted coins", + bank.Balance{ + Address: "link1yq8lgssgxlx9smjhes6ryjasmqmd3ts2p6925r", + Coins: sdk.Coins{ + sdk.NewInt64Coin("atom", 2), + sdk.NewInt64Coin("batom", 12), + sdk.NewInt64Coin("zatom", 2), + }, + }, + false, + }, } for _, tc := range testCases { @@ -83,23 +118,23 @@ func TestBalanceValidate(t *testing.T) { func TestBalance_GetAddress(t *testing.T) { tests := []struct { - name string - Address string - wantPanic bool + name string + Address string + expErr bool }{ - {"empty address", "", false}, - {"malformed address", "invalid", false}, - {"valid address", "link1qz9c0r2jvpkccx67d5svg8kms6eu3k832hdc6p", false}, + {"empty address", "", true}, + {"malformed address", "invalid", true}, + {"valid address", "link1vy0ga0klndqy92ceqehfkvgmn4t94ete4mhemy", false}, } - // Balance.GetAddress() does not validate the address. for _, tt := range tests { tt := tt t.Run(tt.name, func(t *testing.T) { b := bank.Balance{Address: tt.Address} - if tt.wantPanic { - require.Panics(t, func() { b.GetAddress() }) + err := sdk.ValidateAccAddress(b.GetAddress().String()) + if tt.expErr { + require.Error(t, err) } else { - require.True(t, b.GetAddress().Equals(sdk.AccAddress(tt.Address))) + require.NoError(t, err) } }) } @@ -107,7 +142,7 @@ func TestBalance_GetAddress(t *testing.T) { func TestSanitizeBalances(t *testing.T) { // 1. Generate balances - tokens := sdk.TokensFromConsensusPower(81) + tokens := sdk.TokensFromConsensusPower(81, sdk.DefaultPowerReduction) coin := sdk.NewCoin("benchcoin", tokens) coins := sdk.Coins{coin} addrs, _ := makeRandomAddressesAndPublicKeys(20) @@ -131,7 +166,7 @@ func TestSanitizeBalances(t *testing.T) { for j := i + 1; j < len(sorted); j++ { aj := sorted[j] - if got := strings.Compare(ai.GetAddress().String(), aj.GetAddress().String()); got > 0 { + if got := bytes.Compare(ai.GetAddress().Bytes(), aj.GetAddress().Bytes()); got > 0 { t.Errorf("Balance(%d) > Balance(%d)", i, j) } } @@ -142,7 +177,7 @@ func makeRandomAddressesAndPublicKeys(n int) (accL []sdk.AccAddress, pkL []*ed25 for i := 0; i < n; i++ { pk := ed25519.GenPrivKey().PubKey().(*ed25519.PubKey) pkL = append(pkL, pk) - accL = append(accL, sdk.BytesToAccAddress(pk.Address())) + accL = append(accL, sdk.AccAddress(pk.Address())) } return accL, pkL } @@ -159,7 +194,7 @@ func BenchmarkSanitizeBalances1000(b *testing.B) { func benchmarkSanitizeBalances(b *testing.B, nAddresses int) { b.ReportAllocs() - tokens := sdk.TokensFromConsensusPower(81) + tokens := sdk.TokensFromConsensusPower(81, sdk.DefaultPowerReduction) coin := sdk.NewCoin("benchcoin", tokens) coins := sdk.Coins{coin} addrs, _ := makeRandomAddressesAndPublicKeys(nAddresses) diff --git a/x/bank/types/bank.pb.go b/x/bank/types/bank.pb.go index 7a2019086c..48c0b845aa 100644 --- a/x/bank/types/bank.pb.go +++ b/x/bank/types/bank.pb.go @@ -211,12 +211,16 @@ var xxx_messageInfo_Output proto.InternalMessageInfo // Supply represents a struct that passively keeps track of the total supply // amounts in the network. +// This message is deprecated now that supply is indexed by denom. +// +// Deprecated: Do not use. type Supply struct { Total github_com_line_lbm_sdk_types.Coins `protobuf:"bytes,1,rep,name=total,proto3,castrepeated=github.com/line/lbm-sdk/types.Coins" json:"total"` } -func (m *Supply) Reset() { *m = Supply{} } -func (*Supply) ProtoMessage() {} +func (m *Supply) Reset() { *m = Supply{} } +func (m *Supply) String() string { return proto.CompactTextString(m) } +func (*Supply) ProtoMessage() {} func (*Supply) Descriptor() ([]byte, []int) { return fileDescriptor_000561d9f641a64d, []int{4} } @@ -327,6 +331,15 @@ type Metadata struct { // display indicates the suggested denom that should be // displayed in clients. Display string `protobuf:"bytes,4,opt,name=display,proto3" json:"display,omitempty"` + // name defines the name of the token (eg: Cosmos Atom) + // + // Since: cosmos-sdk 0.43 + Name string `protobuf:"bytes,5,opt,name=name,proto3" json:"name,omitempty"` + // symbol is the token symbol usually shown on exchanges (eg: ATOM). This can + // be the same as the display. + // + // Since: cosmos-sdk 0.43 + Symbol string `protobuf:"bytes,6,opt,name=symbol,proto3" json:"symbol,omitempty"` } func (m *Metadata) Reset() { *m = Metadata{} } @@ -390,6 +403,20 @@ func (m *Metadata) GetDisplay() string { return "" } +func (m *Metadata) GetName() string { + if m != nil { + return m.Name + } + return "" +} + +func (m *Metadata) GetSymbol() string { + if m != nil { + return m.Symbol + } + return "" +} + func init() { proto.RegisterType((*Params)(nil), "lbm.bank.v1.Params") proto.RegisterType((*SendEnabled)(nil), "lbm.bank.v1.SendEnabled") @@ -403,43 +430,45 @@ func init() { func init() { proto.RegisterFile("lbm/bank/v1/bank.proto", fileDescriptor_000561d9f641a64d) } var fileDescriptor_000561d9f641a64d = []byte{ - // 566 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xc4, 0x53, 0x3f, 0x8b, 0x13, 0x4f, - 0x18, 0xde, 0xb9, 0xfc, 0xf9, 0xe5, 0x26, 0x3f, 0x0b, 0x97, 0x70, 0xac, 0x01, 0x77, 0xe3, 0xaa, - 0x10, 0xff, 0xdc, 0xae, 0xa7, 0x85, 0x90, 0x42, 0x24, 0x2a, 0x72, 0x85, 0x28, 0x7b, 0x8a, 0xa0, - 0x60, 0x98, 0xcd, 0x8c, 0x71, 0xb9, 0x9d, 0x99, 0x25, 0x33, 0x7b, 0x5c, 0x4a, 0xad, 0x2c, 0x05, - 0x1b, 0xcb, 0xd4, 0xd6, 0x7e, 0x88, 0x03, 0x9b, 0xc3, 0xca, 0x2a, 0x4a, 0xd2, 0x58, 0xdf, 0x27, - 0x90, 0x99, 0xd9, 0x9c, 0x1b, 0xf0, 0xb0, 0xb0, 0xb0, 0xda, 0x79, 0xde, 0x79, 0xe6, 0x79, 0x1f, - 0x9e, 0x77, 0x5f, 0xb8, 0x91, 0xc6, 0x34, 0x8c, 0x11, 0xdb, 0x0d, 0xf7, 0xb6, 0xf4, 0x37, 0xc8, - 0xc6, 0x5c, 0x72, 0xbb, 0x99, 0xc6, 0x34, 0xd0, 0x78, 0x6f, 0xab, 0xdd, 0x1a, 0xf1, 0x11, 0xd7, - 0xf5, 0x50, 0x9d, 0x0c, 0xa5, 0x7d, 0x66, 0xc8, 0x05, 0xe5, 0x62, 0x60, 0x2e, 0x0c, 0x28, 0xae, - 0x0a, 0x55, 0x41, 0x94, 0xea, 0x90, 0x27, 0xcc, 0xd4, 0xfd, 0xcf, 0x00, 0xd6, 0x1f, 0xa1, 0x31, - 0xa2, 0xc2, 0x7e, 0x01, 0xff, 0x17, 0x84, 0xe1, 0x01, 0x61, 0x28, 0x4e, 0x09, 0x76, 0x40, 0xa7, - 0xd2, 0x6d, 0x5e, 0x77, 0x82, 0x52, 0xdf, 0x60, 0x87, 0x30, 0x7c, 0xcf, 0xdc, 0xf7, 0xcf, 0x1d, - 0xcd, 0xbc, 0xb3, 0x13, 0x44, 0xd3, 0x9e, 0x5f, 0x7e, 0x77, 0x95, 0xd3, 0x44, 0x12, 0x9a, 0xc9, - 0x89, 0x1f, 0x35, 0xc5, 0x2f, 0xbe, 0xfd, 0x1c, 0xb6, 0x30, 0x79, 0x89, 0xf2, 0x54, 0x0e, 0x56, - 0xfa, 0xac, 0x75, 0x40, 0xb7, 0xd1, 0xbf, 0x74, 0x34, 0xf3, 0x2e, 0x1a, 0xb5, 0xdf, 0xb1, 0xca, - 0xaa, 0x76, 0x41, 0x28, 0x99, 0xe9, 0x55, 0x3f, 0x4c, 0x3d, 0xcb, 0xbf, 0x0f, 0x9b, 0xa5, 0xa2, - 0xdd, 0x82, 0x35, 0x4c, 0x18, 0xa7, 0x0e, 0xe8, 0x80, 0xee, 0x7a, 0x64, 0x80, 0xed, 0xc0, 0xff, - 0x56, 0x5a, 0x47, 0x4b, 0xd8, 0x6b, 0x28, 0x91, 0x1f, 0x53, 0x0f, 0xf8, 0xaf, 0x01, 0xac, 0x6d, - 0xb3, 0x2c, 0x97, 0x8a, 0x8d, 0x30, 0x1e, 0x13, 0x21, 0x0a, 0x95, 0x25, 0xb4, 0x1f, 0xc3, 0x9a, - 0x0a, 0x52, 0x38, 0x6b, 0x3a, 0xa8, 0xd3, 0x45, 0x50, 0x82, 0xa8, 0xa0, 0xee, 0xf0, 0x84, 0xf5, - 0xaf, 0x1c, 0xcc, 0x3c, 0xeb, 0xe3, 0x37, 0xef, 0xfc, 0x28, 0x91, 0xaf, 0xf2, 0x38, 0x18, 0x72, - 0x1a, 0xa6, 0x09, 0x23, 0x61, 0x1a, 0xd3, 0x4d, 0x81, 0x77, 0x43, 0x39, 0xc9, 0x88, 0xd0, 0x5c, - 0x11, 0x19, 0xb1, 0x5e, 0xe3, 0xad, 0xf1, 0x60, 0xf9, 0x6f, 0x00, 0xac, 0x3f, 0xcc, 0xe5, 0xbf, - 0x35, 0x31, 0x05, 0xb0, 0xbe, 0x93, 0x67, 0x59, 0x3a, 0x51, 0xad, 0x24, 0x97, 0x28, 0x2d, 0x7e, - 0x8c, 0xbf, 0x6e, 0xa5, 0xc5, 0x7a, 0xb7, 0x55, 0xab, 0x65, 0xee, 0x5f, 0x3e, 0x6d, 0x5e, 0xbb, - 0x7c, 0xd2, 0xe3, 0x7d, 0xb3, 0x15, 0x64, 0x3f, 0xe3, 0x63, 0x49, 0x70, 0x60, 0x6c, 0x6d, 0xfb, - 0x4f, 0xe1, 0xfa, 0x5d, 0x35, 0xd8, 0x27, 0x2c, 0x91, 0x27, 0x8c, 0xbc, 0x0d, 0x1b, 0xea, 0x19, - 0x23, 0x4c, 0xea, 0x99, 0x9f, 0x8a, 0x8e, 0xb1, 0xce, 0x36, 0x4d, 0x90, 0x20, 0xc2, 0xa9, 0x74, - 0x2a, 0x3a, 0x5b, 0x03, 0xfd, 0xf7, 0x00, 0x36, 0x1e, 0x10, 0x89, 0x30, 0x92, 0xc8, 0xee, 0xc0, - 0x26, 0x26, 0x62, 0x38, 0x4e, 0x32, 0x99, 0x70, 0x56, 0xc8, 0x97, 0x4b, 0xf6, 0x4d, 0xc5, 0x60, - 0x9c, 0x0e, 0x72, 0x96, 0xc8, 0xe5, 0x40, 0x36, 0x56, 0xd6, 0xe7, 0xd8, 0x67, 0x04, 0xf1, 0xf2, - 0x28, 0x6c, 0x1b, 0x56, 0x55, 0x8c, 0x4e, 0x45, 0x6b, 0xea, 0xb3, 0x72, 0x85, 0x13, 0x91, 0xa5, - 0x68, 0xe2, 0x54, 0xcd, 0xc4, 0x0b, 0xd8, 0xbf, 0x75, 0x30, 0x77, 0xc1, 0xe1, 0xdc, 0x05, 0xdf, - 0xe7, 0x2e, 0x78, 0xb7, 0x70, 0xad, 0xc3, 0x85, 0x6b, 0x7d, 0x5d, 0xb8, 0xd6, 0xb3, 0x0b, 0x7f, - 0x48, 0x4e, 0xa7, 0x1f, 0xd7, 0xf5, 0xe2, 0xdf, 0xf8, 0x19, 0x00, 0x00, 0xff, 0xff, 0x33, 0x53, - 0x00, 0xb9, 0x68, 0x04, 0x00, 0x00, + // 593 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xc4, 0x54, 0xbd, 0x6b, 0x14, 0x4f, + 0x18, 0xbe, 0xc9, 0xe5, 0xee, 0x77, 0x99, 0xfb, 0x59, 0x38, 0x84, 0xb0, 0x06, 0xbc, 0x3d, 0x57, + 0x85, 0xf8, 0x91, 0xdd, 0xc4, 0x08, 0xc2, 0x15, 0x82, 0xa7, 0x22, 0x29, 0x44, 0xd9, 0x28, 0x82, + 0x82, 0xc7, 0xec, 0xcd, 0x78, 0x2e, 0x99, 0x8f, 0xe5, 0x66, 0x36, 0x64, 0x4b, 0xad, 0x2c, 0x2d, + 0x2d, 0x63, 0x6b, 0x6d, 0x6f, 0x1b, 0xb0, 0x09, 0x56, 0x56, 0x51, 0x92, 0xc6, 0x3a, 0x7f, 0x81, + 0xcc, 0xcc, 0x5e, 0xdc, 0x03, 0x83, 0x85, 0x85, 0xd5, 0xbd, 0xcf, 0x3b, 0xcf, 0x3c, 0xef, 0xcb, + 0xf3, 0xdc, 0x2c, 0x5c, 0x60, 0x09, 0x8f, 0x12, 0x2c, 0x36, 0xa3, 0xad, 0x55, 0xfb, 0x1b, 0x66, + 0x63, 0xa9, 0x25, 0x6a, 0xb3, 0x84, 0x87, 0x16, 0x6f, 0xad, 0x2e, 0xce, 0x8f, 0xe4, 0x48, 0xda, + 0x7e, 0x64, 0x2a, 0x47, 0x59, 0x3c, 0x33, 0x94, 0x8a, 0x4b, 0x35, 0x70, 0x07, 0x0e, 0x94, 0x47, + 0xa5, 0xaa, 0xa2, 0x46, 0x75, 0x28, 0x53, 0xe1, 0xfa, 0xc1, 0x67, 0x00, 0x9b, 0x0f, 0xf1, 0x18, + 0x73, 0x85, 0x9e, 0xc3, 0xff, 0x15, 0x15, 0x64, 0x40, 0x05, 0x4e, 0x18, 0x25, 0x1e, 0xe8, 0xd6, + 0x97, 0xda, 0xd7, 0xbc, 0xb0, 0x32, 0x37, 0xdc, 0xa0, 0x82, 0xdc, 0x75, 0xe7, 0xfd, 0x73, 0x47, + 0xfb, 0xfe, 0xd9, 0x02, 0x73, 0xd6, 0x0b, 0xaa, 0xf7, 0xae, 0x4a, 0x9e, 0x6a, 0xca, 0x33, 0x5d, + 0x04, 0x71, 0x5b, 0xfd, 0xe2, 0xa3, 0x67, 0x70, 0x9e, 0xd0, 0x17, 0x38, 0x67, 0x7a, 0x30, 0x35, + 0x67, 0xa6, 0x0b, 0x96, 0x5a, 0xfd, 0x4b, 0x47, 0xfb, 0xfe, 0x45, 0xa7, 0xf6, 0x3b, 0x56, 0x55, + 0x15, 0x95, 0x84, 0xca, 0x32, 0xbd, 0xd9, 0x77, 0x3b, 0x7e, 0x2d, 0xb8, 0x07, 0xdb, 0x95, 0x26, + 0x9a, 0x87, 0x0d, 0x42, 0x85, 0xe4, 0x1e, 0xe8, 0x82, 0xa5, 0xb9, 0xd8, 0x01, 0xe4, 0xc1, 0xff, + 0xa6, 0x46, 0xc7, 0x13, 0xd8, 0x6b, 0x19, 0x91, 0x1f, 0x3b, 0x3e, 0x08, 0x5e, 0x01, 0xd8, 0x58, + 0x17, 0x59, 0xae, 0x0d, 0x1b, 0x13, 0x32, 0xa6, 0x4a, 0x95, 0x2a, 0x13, 0x88, 0x1e, 0xc1, 0x86, + 0x31, 0x52, 0x79, 0x33, 0xd6, 0xa8, 0xd3, 0xa5, 0x51, 0x8a, 0x1a, 0xa3, 0x6e, 0xcb, 0x54, 0xf4, + 0xaf, 0xec, 0xee, 0xfb, 0xb5, 0x0f, 0xdf, 0xfc, 0xf3, 0xa3, 0x54, 0xbf, 0xcc, 0x93, 0x70, 0x28, + 0x79, 0xc4, 0x52, 0x41, 0x23, 0x96, 0xf0, 0x65, 0x45, 0x36, 0x23, 0x5d, 0x64, 0x54, 0x59, 0xae, + 0x8a, 0x9d, 0x58, 0xaf, 0xf5, 0xc6, 0xed, 0x50, 0x0b, 0x5e, 0x03, 0xd8, 0x7c, 0x90, 0xeb, 0x7f, + 0xbb, 0xc4, 0x7b, 0x00, 0x9b, 0x1b, 0x79, 0x96, 0xb1, 0xc2, 0x8c, 0xd2, 0x52, 0x63, 0x56, 0xfe, + 0x31, 0xfe, 0x7a, 0x94, 0x15, 0xeb, 0xdd, 0x2a, 0x47, 0x81, 0x2f, 0x1f, 0x97, 0xd7, 0x2e, 0x9f, + 0x74, 0x71, 0xdb, 0xbd, 0x08, 0x46, 0x47, 0x78, 0x58, 0x44, 0x5b, 0x2b, 0xd7, 0x57, 0x42, 0xb7, + 0xd5, 0xba, 0x07, 0x82, 0x27, 0x70, 0xee, 0x8e, 0x49, 0xf6, 0xb1, 0x48, 0xf5, 0x09, 0x99, 0x2f, + 0xc2, 0x16, 0xdd, 0xce, 0xa4, 0xa0, 0x42, 0xdb, 0xd0, 0x4f, 0xc5, 0xc7, 0xd8, 0x9a, 0xcb, 0x52, + 0xac, 0xa8, 0xf2, 0xea, 0xdd, 0xba, 0x35, 0xd7, 0xc1, 0xe0, 0x13, 0x80, 0xad, 0xfb, 0x54, 0x63, + 0x82, 0x35, 0x46, 0x5d, 0xd8, 0x26, 0x54, 0x0d, 0xc7, 0x69, 0xa6, 0x53, 0x29, 0x4a, 0xf9, 0x6a, + 0x0b, 0xdd, 0x30, 0x0c, 0x21, 0xf9, 0x20, 0x17, 0xa9, 0x9e, 0x24, 0xb2, 0x30, 0xf5, 0x7e, 0x8e, + 0xf7, 0x8c, 0x21, 0x99, 0x94, 0x0a, 0x21, 0x38, 0x6b, 0x7c, 0xf4, 0xea, 0x56, 0xd3, 0xd6, 0x66, + 0x2b, 0x92, 0xaa, 0x8c, 0xe1, 0xc2, 0x9b, 0x75, 0x91, 0x97, 0xd0, 0xb0, 0x05, 0xe6, 0xd4, 0x6b, + 0x38, 0xb6, 0xa9, 0xd1, 0x02, 0x6c, 0xaa, 0x82, 0x27, 0x92, 0x79, 0x4d, 0xdb, 0x2d, 0x51, 0xff, + 0xe6, 0xee, 0x41, 0x07, 0xec, 0x1d, 0x74, 0xc0, 0xf7, 0x83, 0x0e, 0x78, 0x7b, 0xd8, 0xa9, 0xed, + 0x1d, 0x76, 0x6a, 0x5f, 0x0f, 0x3b, 0xb5, 0xa7, 0x17, 0xfe, 0x60, 0xb5, 0x8d, 0x2a, 0x69, 0xda, + 0xaf, 0xc4, 0xda, 0xcf, 0x00, 0x00, 0x00, 0xff, 0xff, 0x65, 0x43, 0xd8, 0x41, 0x95, 0x04, 0x00, + 0x00, } func (this *SendEnabled) Equal(that interface{}) bool { @@ -774,6 +803,20 @@ func (m *Metadata) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if len(m.Symbol) > 0 { + i -= len(m.Symbol) + copy(dAtA[i:], m.Symbol) + i = encodeVarintBank(dAtA, i, uint64(len(m.Symbol))) + i-- + dAtA[i] = 0x32 + } + if len(m.Name) > 0 { + i -= len(m.Name) + copy(dAtA[i:], m.Name) + i = encodeVarintBank(dAtA, i, uint64(len(m.Name))) + i-- + dAtA[i] = 0x2a + } if len(m.Display) > 0 { i -= len(m.Display) copy(dAtA[i:], m.Display) @@ -956,6 +999,14 @@ func (m *Metadata) Size() (n int) { if l > 0 { n += 1 + l + sovBank(uint64(l)) } + l = len(m.Name) + if l > 0 { + n += 1 + l + sovBank(uint64(l)) + } + l = len(m.Symbol) + if l > 0 { + n += 1 + l + sovBank(uint64(l)) + } return n } @@ -1779,6 +1830,70 @@ func (m *Metadata) Unmarshal(dAtA []byte) error { } m.Display = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Name", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowBank + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthBank + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthBank + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Name = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 6: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Symbol", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowBank + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthBank + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthBank + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Symbol = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipBank(dAtA[iNdEx:]) diff --git a/x/bank/types/codec.go b/x/bank/types/codec.go index 4960008820..f6ade4c521 100644 --- a/x/bank/types/codec.go +++ b/x/bank/types/codec.go @@ -6,14 +6,12 @@ import ( cryptocodec "github.com/line/lbm-sdk/crypto/codec" sdk "github.com/line/lbm-sdk/types" "github.com/line/lbm-sdk/types/msgservice" - "github.com/line/lbm-sdk/x/bank/exported" + "github.com/line/lbm-sdk/x/authz" ) // RegisterLegacyAminoCodec registers the necessary x/bank interfaces and concrete types // on the provided LegacyAmino codec. These types are used for Amino JSON serialization. func RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) { - cdc.RegisterInterface((*exported.SupplyI)(nil), nil) - cdc.RegisterConcrete(&Supply{}, "lbm-sdk/Supply", nil) cdc.RegisterConcrete(&MsgSend{}, "lbm-sdk/MsgSend", nil) cdc.RegisterConcrete(&MsgMultiSend{}, "lbm-sdk/MsgMultiSend", nil) } @@ -23,11 +21,9 @@ func RegisterInterfaces(registry types.InterfaceRegistry) { &MsgSend{}, &MsgMultiSend{}, ) - - registry.RegisterInterface( - "lbm.bank.v1.SupplyI", - (*exported.SupplyI)(nil), - &Supply{}, + registry.RegisterImplementations( + (*authz.Authorization)(nil), + &SendAuthorization{}, ) msgservice.RegisterMsgServiceDesc(registry, &_Msg_serviceDesc) diff --git a/x/bank/types/errors.go b/x/bank/types/errors.go index b08c24ef8f..30cf0e7815 100644 --- a/x/bank/types/errors.go +++ b/x/bank/types/errors.go @@ -11,4 +11,5 @@ var ( ErrInputOutputMismatch = sdkerrors.Register(ModuleName, 4, "sum inputs != sum outputs") ErrSendDisabled = sdkerrors.Register(ModuleName, 5, "send transactions are disabled") ErrDenomMetadataNotFound = sdkerrors.Register(ModuleName, 6, "client denom metadata not found") + ErrInvalidKey = sdkerrors.Register(ModuleName, 7, "invalid key") ) diff --git a/x/bank/types/events.go b/x/bank/types/events.go index c03d142f00..60f4a295df 100644 --- a/x/bank/types/events.go +++ b/x/bank/types/events.go @@ -1,5 +1,9 @@ package types +import ( + sdk "github.com/line/lbm-sdk/types" +) + // bank module event types const ( EventTypeTransfer = "transfer" @@ -8,4 +12,55 @@ const ( AttributeKeySender = "sender" AttributeValueCategory = ModuleName + + // supply and balance tracking events name and attributes + EventTypeCoinSpent = "coin_spent" + EventTypeCoinReceived = "coin_received" + EventTypeCoinMint = "coinbase" // NOTE(fdymylja): using mint clashes with mint module event + EventTypeCoinBurn = "burn" + + AttributeKeySpender = "spender" + AttributeKeyReceiver = "receiver" + AttributeKeyMinter = "minter" + AttributeKeyBurner = "burner" ) + +// NewCoinSpentEvent constructs a new coin spent sdk.Event +// nolint: interfacer +func NewCoinSpentEvent(spender sdk.AccAddress, amount sdk.Coins) sdk.Event { + return sdk.NewEvent( + EventTypeCoinSpent, + sdk.NewAttribute(AttributeKeySpender, spender.String()), + sdk.NewAttribute(sdk.AttributeKeyAmount, amount.String()), + ) +} + +// NewCoinReceivedEvent constructs a new coin received sdk.Event +// nolint: interfacer +func NewCoinReceivedEvent(receiver sdk.AccAddress, amount sdk.Coins) sdk.Event { + return sdk.NewEvent( + EventTypeCoinReceived, + sdk.NewAttribute(AttributeKeyReceiver, receiver.String()), + sdk.NewAttribute(sdk.AttributeKeyAmount, amount.String()), + ) +} + +// NewCoinMintEvent construct a new coin minted sdk.Event +// nolint: interfacer +func NewCoinMintEvent(minter sdk.AccAddress, amount sdk.Coins) sdk.Event { + return sdk.NewEvent( + EventTypeCoinMint, + sdk.NewAttribute(AttributeKeyMinter, minter.String()), + sdk.NewAttribute(sdk.AttributeKeyAmount, amount.String()), + ) +} + +// NewCoinBurnEvent constructs a new coin burned sdk.Event +// nolint: interfacer +func NewCoinBurnEvent(burner sdk.AccAddress, amount sdk.Coins) sdk.Event { + return sdk.NewEvent( + EventTypeCoinBurn, + sdk.NewAttribute(AttributeKeyBurner, burner.String()), + sdk.NewAttribute(sdk.AttributeKeyAmount, amount.String()), + ) +} diff --git a/x/bank/types/expected_keepers.go b/x/bank/types/expected_keepers.go index f0ab0f451c..bda99111bf 100644 --- a/x/bank/types/expected_keepers.go +++ b/x/bank/types/expected_keepers.go @@ -13,6 +13,7 @@ type AccountKeeper interface { GetAccount(ctx sdk.Context, addr sdk.AccAddress) types.AccountI GetAllAccounts(ctx sdk.Context) []types.AccountI + HasAccount(ctx sdk.Context, addr sdk.AccAddress) bool SetAccount(ctx sdk.Context, acc types.AccountI) Prefetch(ctx sdk.Context, addr sdk.AccAddress, forSet bool) diff --git a/x/bank/types/genesis.go b/x/bank/types/genesis.go index 1cf47c19b6..ed5ce25a90 100644 --- a/x/bank/types/genesis.go +++ b/x/bank/types/genesis.go @@ -18,6 +18,8 @@ func (gs GenesisState) Validate() error { seenBalances := make(map[string]bool) seenMetadatas := make(map[string]bool) + totalSupply := sdk.Coins{} + for _, balance := range gs.Balances { if seenBalances[balance.Address] { return fmt.Errorf("duplicate balance for address %s", balance.Address) @@ -28,6 +30,8 @@ func (gs GenesisState) Validate() error { } seenBalances[balance.Address] = true + + totalSupply = totalSupply.Add(balance.Coins...) } for _, metadata := range gs.DenomMetadata { @@ -42,8 +46,19 @@ func (gs GenesisState) Validate() error { seenMetadatas[metadata.Base] = true } - // NOTE: this errors if supply for any given coin is zero - return NewSupply(gs.Supply).ValidateBasic() + if !gs.Supply.Empty() { + // NOTE: this errors if supply for any given coin is zero + err := gs.Supply.Validate() + if err != nil { + return err + } + + if !gs.Supply.IsEqual(totalSupply) { + return fmt.Errorf("genesis supply is incorrect, expected %v, got %v", gs.Supply, totalSupply) + } + } + + return nil } // NewGenesisState creates a new genesis state. @@ -58,12 +73,12 @@ func NewGenesisState(params Params, balances []Balance, supply sdk.Coins, denomM // DefaultGenesisState returns a default bank module genesis state. func DefaultGenesisState() *GenesisState { - return NewGenesisState(DefaultParams(), []Balance{}, DefaultSupply().GetTotal(), []Metadata{}) + return NewGenesisState(DefaultParams(), []Balance{}, sdk.Coins{}, []Metadata{}) } // GetGenesisStateFromAppState returns x/bank GenesisState given raw application // genesis state. -func GetGenesisStateFromAppState(cdc codec.JSONMarshaler, appState map[string]json.RawMessage) *GenesisState { +func GetGenesisStateFromAppState(cdc codec.JSONCodec, appState map[string]json.RawMessage) *GenesisState { var genesisState GenesisState if appState[ModuleName] != nil { diff --git a/x/bank/types/genesis.pb.go b/x/bank/types/genesis.pb.go index b12d10b825..a02340cdaf 100644 --- a/x/bank/types/genesis.pb.go +++ b/x/bank/types/genesis.pb.go @@ -31,7 +31,8 @@ type GenesisState struct { Params Params `protobuf:"bytes,1,opt,name=params,proto3" json:"params"` // balances is an array containing the balances of all the accounts. Balances []Balance `protobuf:"bytes,2,rep,name=balances,proto3" json:"balances"` - // supply represents the total supply. + // supply represents the total supply. If it is left empty, then supply will be calculated based on the provided + // balances. Otherwise, it will be used to validate that the sum of the balances equals this amount. Supply github_com_line_lbm_sdk_types.Coins `protobuf:"bytes,3,rep,name=supply,proto3,castrepeated=github.com/line/lbm-sdk/types.Coins" json:"supply"` // denom_metadata defines the metadata of the differents coins. DenomMetadata []Metadata `protobuf:"bytes,4,rep,name=denom_metadata,json=denomMetadata,proto3" json:"denom_metadata" yaml:"denom_metadata"` diff --git a/x/bank/types/genesis_test.go b/x/bank/types/genesis_test.go index 08db3f283c..99c0160c96 100644 --- a/x/bank/types/genesis_test.go +++ b/x/bank/types/genesis_test.go @@ -1,4 +1,4 @@ -package types_test +package types import ( "testing" @@ -6,31 +6,32 @@ import ( "github.com/stretchr/testify/require" sdk "github.com/line/lbm-sdk/types" - "github.com/line/lbm-sdk/x/bank/types" ) func TestGenesisStateValidate(t *testing.T) { testCases := []struct { name string - genesisState types.GenesisState + genesisState GenesisState expErr bool }{ { "valid genesisState", - types.GenesisState{ - Params: types.DefaultParams(), - Balances: []types.Balance{ + GenesisState{ + Params: DefaultParams(), + Balances: []Balance{ { - Address: "link1mejkku76a2ec35262rdqddggzwrgtrh52t3t0c", + Address: "link1yq8lgssgxlx9smjhes6ryjasmqmd3ts2p6925r", Coins: sdk.Coins{sdk.NewInt64Coin("uatom", 1)}, }, }, Supply: sdk.Coins{sdk.NewInt64Coin("uatom", 1)}, - DenomMetadata: []types.Metadata{ + DenomMetadata: []Metadata{ { + Name: "Cosmos Hub Atom", + Symbol: "ATOM", Description: "The native staking token of the Cosmos Hub.", - DenomUnits: []*types.DenomUnit{ + DenomUnits: []*DenomUnit{ {"uatom", uint32(0), []string{"microatom"}}, {"matom", uint32(3), []string{"milliatom"}}, {"atom", uint32(6), nil}, @@ -42,12 +43,12 @@ func TestGenesisStateValidate(t *testing.T) { }, false, }, - {"empty genesisState", types.GenesisState{}, false}, + {"empty genesisState", GenesisState{}, false}, { "invalid params ", - types.GenesisState{ - Params: types.Params{ - SendEnabled: []*types.SendEnabled{ + GenesisState{ + Params: Params{ + SendEnabled: []*SendEnabled{ {"", true}, }, }, @@ -56,14 +57,14 @@ func TestGenesisStateValidate(t *testing.T) { }, { "dup balances", - types.GenesisState{ - Balances: []types.Balance{ + GenesisState{ + Balances: []Balance{ { - Address: "link1mejkku76a2ec35262rdqddggzwrgtrh52t3t0c", + Address: "link1yq8lgssgxlx9smjhes6ryjasmqmd3ts2p6925r", Coins: sdk.Coins{sdk.NewInt64Coin("uatom", 1)}, }, { - Address: "link1mejkku76a2ec35262rdqddggzwrgtrh52t3t0c", + Address: "link1yq8lgssgxlx9smjhes6ryjasmqmd3ts2p6925r", Coins: sdk.Coins{sdk.NewInt64Coin("uatom", 1)}, }, }, @@ -72,10 +73,10 @@ func TestGenesisStateValidate(t *testing.T) { }, { "0 balance", - types.GenesisState{ - Balances: []types.Balance{ + GenesisState{ + Balances: []Balance{ { - Address: "link1mejkku76a2ec35262rdqddggzwrgtrh52t3t0c", + Address: "link1yq8lgssgxlx9smjhes6ryjasmqmd3ts2p6925r", }, }, }, @@ -83,11 +84,13 @@ func TestGenesisStateValidate(t *testing.T) { }, { "dup Metadata", - types.GenesisState{ - DenomMetadata: []types.Metadata{ + GenesisState{ + DenomMetadata: []Metadata{ { + Name: "Cosmos Hub Atom", + Symbol: "ATOM", Description: "The native staking token of the Cosmos Hub.", - DenomUnits: []*types.DenomUnit{ + DenomUnits: []*DenomUnit{ {"uatom", uint32(0), []string{"microatom"}}, {"matom", uint32(3), []string{"milliatom"}}, {"atom", uint32(6), nil}, @@ -96,8 +99,10 @@ func TestGenesisStateValidate(t *testing.T) { Display: "atom", }, { + Name: "Cosmos Hub Atom", + Symbol: "ATOM", Description: "The native staking token of the Cosmos Hub.", - DenomUnits: []*types.DenomUnit{ + DenomUnits: []*DenomUnit{ {"uatom", uint32(0), []string{"microatom"}}, {"matom", uint32(3), []string{"milliatom"}}, {"atom", uint32(6), nil}, @@ -111,11 +116,13 @@ func TestGenesisStateValidate(t *testing.T) { }, { "invalid Metadata", - types.GenesisState{ - DenomMetadata: []types.Metadata{ + GenesisState{ + DenomMetadata: []Metadata{ { + Name: "Cosmos Hub Atom", + Symbol: "ATOM", Description: "The native staking token of the Cosmos Hub.", - DenomUnits: []*types.DenomUnit{ + DenomUnits: []*DenomUnit{ {"uatom", uint32(0), []string{"microatom"}}, {"matom", uint32(3), []string{"milliatom"}}, {"atom", uint32(6), nil}, @@ -129,7 +136,7 @@ func TestGenesisStateValidate(t *testing.T) { }, { "invalid supply", - types.GenesisState{ + GenesisState{ Supply: sdk.Coins{sdk.Coin{Denom: "", Amount: sdk.OneInt()}}, }, true, diff --git a/x/bank/types/key.go b/x/bank/types/key.go index 4742ba4de5..9250e025ba 100644 --- a/x/bank/types/key.go +++ b/x/bank/types/key.go @@ -1,9 +1,6 @@ package types import ( - "fmt" - "strings" - sdk "github.com/line/lbm-sdk/types" "github.com/line/lbm-sdk/types/address" ) @@ -24,6 +21,8 @@ const ( // KVStore keys var ( + // BalancesPrefix is the prefix for the account balances store. We use a byte + // (instead of `[]byte("balances")` to save some disk space). BalancesPrefix = []byte{0x02} SupplyKey = []byte{0x00} DenomMetadataPrefix = []byte{0x1} @@ -39,19 +38,20 @@ func DenomMetadataKey(denom string) []byte { } // AddressFromBalancesStore returns an account address from a balances prefix -// store. The key must not contain the perfix BalancesPrefix as the prefix store +// store. The key must not contain the prefix BalancesPrefix as the prefix store // iterator discards the actual prefix. -func AddressFromBalancesStore(key []byte) sdk.AccAddress { - addr := string(key) - if !strings.Contains(addr, sdk.Bech32MainPrefix) { - panic(fmt.Sprintf("unexpected account address key; key does not start with (%s): %s", - sdk.Bech32MainPrefix, addr)) +// +// If invalid key is passed, AddressFromBalancesStore returns ErrInvalidKey. +func AddressFromBalancesStore(key []byte) (sdk.AccAddress, error) { + if len(key) == 0 { + return "", ErrInvalidKey } - index := strings.Index(addr, AddressDenomDelimiter) - if index <= 0 { - panic(fmt.Sprintf("AddressBalance store key does not contain the delimiter(,): %s", addr)) + addrLen := key[0] + bound := int(addrLen) + if len(key)-1 < bound { + return "", ErrInvalidKey } - return sdk.AccAddress(addr[:index]) + return sdk.AccAddress(key[1 : bound+1]), nil } // CreateAccountBalancesPrefix creates the prefix for an account's balances. diff --git a/x/bank/types/key_test.go b/x/bank/types/key_test.go index 5043a529c1..55f250bcc4 100644 --- a/x/bank/types/key_test.go +++ b/x/bank/types/key_test.go @@ -1,13 +1,14 @@ package types_test import ( + "errors" "testing" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/line/lbm-sdk/x/bank/keeper" - sdk "github.com/line/lbm-sdk/types" + "github.com/line/lbm-sdk/types/address" "github.com/line/lbm-sdk/x/bank/types" ) @@ -22,8 +23,36 @@ func TestAddressFromBalancesStore(t *testing.T) { addr := sdk.AccAddress("link19tzp7e489drh9qfs9m84k2qe5a5yyknzen48tz") err := sdk.ValidateAccAddress(addr.String()) require.NoError(t, err) + addrLen := len(addr) + require.Equal(t, 43, addrLen) + key := cloneAppend(address.MustLengthPrefix(addr.Bytes()), []byte("stake")) + + tests := []struct { + name string + key []byte + wantErr bool + expectedKey sdk.AccAddress + }{ + {"valid", key, false, addr}, + {"#9111", []byte("\xff000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"), false, ""}, + {"empty", []byte(""), true, ""}, + {"invalid", []byte("3AA"), true, ""}, + } - key := cloneAppend(keeper.AddressToPrefixKey(addr), []byte("stake")) - res := types.AddressFromBalancesStore(key) - require.Equal(t, res, addr) + for _, tc := range tests { + tc := tc + t.Run(tc.name, func(t *testing.T) { + t.Parallel() + addr, err := types.AddressFromBalancesStore(tc.key) + if tc.wantErr { + assert.Error(t, err) + assert.True(t, errors.Is(types.ErrInvalidKey, err)) + } else { + assert.NoError(t, err) + } + if len(tc.expectedKey) > 0 { + assert.Equal(t, tc.expectedKey, addr) + } + }) + } } diff --git a/x/bank/types/metadata.go b/x/bank/types/metadata.go index 0796a900f3..737a53e323 100644 --- a/x/bank/types/metadata.go +++ b/x/bank/types/metadata.go @@ -9,12 +9,21 @@ import ( ) // Validate performs a basic validation of the coin metadata fields. It checks: +// - Name and Symbol are not blank // - Base and Display denominations are valid coin denominations // - Base and Display denominations are present in the DenomUnit slice // - Base denomination has exponent 0 // - Denomination units are sorted in ascending order // - Denomination units not duplicated func (m Metadata) Validate() error { + if strings.TrimSpace(m.Name) == "" { + return errors.New("name field cannot be blank") + } + + if strings.TrimSpace(m.Symbol) == "" { + return errors.New("symbol field cannot be blank") + } + if err := sdk.ValidateDenom(m.Base); err != nil { return fmt.Errorf("invalid metadata base denom: %w", err) } diff --git a/x/bank/types/metadata_test.go b/x/bank/types/metadata_test.go index 4c8e3dcc72..a3d0654477 100644 --- a/x/bank/types/metadata_test.go +++ b/x/bank/types/metadata_test.go @@ -18,6 +18,8 @@ func TestMetadataValidate(t *testing.T) { { "non-empty coins", types.Metadata{ + Name: "Cosmos Hub Atom", + Symbol: "ATOM", Description: "The native staking token of the Cosmos Hub.", DenomUnits: []*types.DenomUnit{ {"uatom", uint32(0), []string{"microatom"}}, @@ -29,17 +31,50 @@ func TestMetadataValidate(t *testing.T) { }, false, }, + { + "base coin is display coin", + types.Metadata{ + Name: "Cosmos Hub Atom", + Symbol: "ATOM", + Description: "The native staking token of the Cosmos Hub.", + DenomUnits: []*types.DenomUnit{ + {"atom", uint32(0), []string{"ATOM"}}, + }, + Base: "atom", + Display: "atom", + }, + false, + }, {"empty metadata", types.Metadata{}, true}, + { + "blank name", + types.Metadata{ + Name: "", + }, + true, + }, + { + "blank symbol", + types.Metadata{ + Name: "Cosmos Hub Atom", + Symbol: "", + }, + true, + }, { "invalid base denom", types.Metadata{ - Base: "", + Name: "Cosmos Hub Atom", + Symbol: "ATOM", + Base: "", }, true, }, { "invalid display denom", types.Metadata{ + Name: "Cosmos Hub Atom", + Symbol: "ATOM", Base: "uatom", Display: "", }, @@ -48,6 +83,8 @@ func TestMetadataValidate(t *testing.T) { { "duplicate denom unit", types.Metadata{ + Name: "Cosmos Hub Atom", + Symbol: "ATOM", Description: "The native staking token of the Cosmos Hub.", DenomUnits: []*types.DenomUnit{ {"uatom", uint32(0), []string{"microatom"}}, @@ -61,6 +98,8 @@ func TestMetadataValidate(t *testing.T) { { "invalid denom unit", types.Metadata{ + Name: "Cosmos Hub Atom", + Symbol: "ATOM", Description: "The native staking token of the Cosmos Hub.", DenomUnits: []*types.DenomUnit{ {"", uint32(0), []string{"microatom"}}, @@ -73,6 +112,8 @@ func TestMetadataValidate(t *testing.T) { { "invalid denom unit alias", types.Metadata{ + Name: "Cosmos Hub Atom", + Symbol: "ATOM", Description: "The native staking token of the Cosmos Hub.", DenomUnits: []*types.DenomUnit{ {"uatom", uint32(0), []string{""}}, @@ -85,6 +126,8 @@ func TestMetadataValidate(t *testing.T) { { "duplicate denom unit alias", types.Metadata{ + Name: "Cosmos Hub Atom", + Symbol: "ATOM", Description: "The native staking token of the Cosmos Hub.", DenomUnits: []*types.DenomUnit{ {"uatom", uint32(0), []string{"microatom", "microatom"}}, @@ -97,6 +140,8 @@ func TestMetadataValidate(t *testing.T) { { "no base denom unit", types.Metadata{ + Name: "Cosmos Hub Atom", + Symbol: "ATOM", Description: "The native staking token of the Cosmos Hub.", DenomUnits: []*types.DenomUnit{ {"matom", uint32(3), []string{"milliatom"}}, @@ -110,6 +155,8 @@ func TestMetadataValidate(t *testing.T) { { "base denom exponent not zero", types.Metadata{ + Name: "Cosmos Hub Atom", + Symbol: "ATOM", Description: "The native staking token of the Cosmos Hub.", DenomUnits: []*types.DenomUnit{ {"uatom", uint32(1), []string{"microatom"}}, @@ -121,9 +168,26 @@ func TestMetadataValidate(t *testing.T) { }, true, }, + { + "invalid denom unit", + types.Metadata{ + Name: "Cosmos Hub Atom", + Symbol: "ATOM", + Description: "The native staking token of the Cosmos Hub.", + DenomUnits: []*types.DenomUnit{ + {"uatom", uint32(0), []string{"microatom"}}, + {"", uint32(3), []string{"milliatom"}}, + }, + Base: "uatom", + Display: "uatom", + }, + true, + }, { "no display denom unit", types.Metadata{ + Name: "Cosmos Hub Atom", + Symbol: "ATOM", Description: "The native staking token of the Cosmos Hub.", DenomUnits: []*types.DenomUnit{ {"uatom", uint32(0), []string{"microatom"}}, @@ -136,6 +200,8 @@ func TestMetadataValidate(t *testing.T) { { "denom units not sorted", types.Metadata{ + Name: "Cosmos Hub Atom", + Symbol: "ATOM", Description: "The native staking token of the Cosmos Hub.", DenomUnits: []*types.DenomUnit{ {"uatom", uint32(0), []string{"microatom"}}, diff --git a/x/bank/types/msgs_test.go b/x/bank/types/msgs_test.go index 3063b6560d..9ef031907c 100644 --- a/x/bank/types/msgs_test.go +++ b/x/bank/types/msgs_test.go @@ -22,8 +22,8 @@ func TestMsgSendRoute(t *testing.T) { func TestMsgSendValidation(t *testing.T) { addr1 := sdk.BytesToAccAddress([]byte("from________________")) addr2 := sdk.BytesToAccAddress([]byte("to__________________")) - addrEmpty := sdk.BytesToAccAddress([]byte("")) - addrTooLong := sdk.BytesToAccAddress([]byte("Accidentally used 33 bytes pubkey")) + addrEmpty := sdk.AccAddress("") + addrLong := sdk.BytesToAccAddress([]byte("Accidentally used 33 bytes pubkey")) atom123 := sdk.NewCoins(sdk.NewInt64Coin("atom", 123)) atom0 := sdk.NewCoins(sdk.NewInt64Coin("atom", 0)) @@ -36,12 +36,12 @@ func TestMsgSendValidation(t *testing.T) { }{ {"", NewMsgSend(addr1, addr2, atom123)}, // valid send {"", NewMsgSend(addr1, addr2, atom123eth123)}, // valid send with multiple coins + {"", NewMsgSend(addrLong, addr2, atom123)}, // valid send with long addr sender + {"", NewMsgSend(addr1, addrLong, atom123)}, // valid send with long addr recipient {": invalid coins", NewMsgSend(addr1, addr2, atom0)}, // non positive coin {"123atom,0eth: invalid coins", NewMsgSend(addr1, addr2, atom123eth0)}, // non positive coin in multicoins {"Invalid sender address (empty address string is not allowed): invalid address", NewMsgSend(addrEmpty, addr2, atom123)}, - {"Invalid sender address (incorrect address length (expected: 20, actual: 33)): invalid address", NewMsgSend(addrTooLong, addr2, atom123)}, {"Invalid recipient address (empty address string is not allowed): invalid address", NewMsgSend(addr1, addrEmpty, atom123)}, - {"Invalid recipient address (incorrect address length (expected: 20, actual: 33)): invalid address", NewMsgSend(addr1, addrTooLong, atom123)}, } for _, tc := range cases { @@ -90,8 +90,8 @@ func TestMsgMultiSendRoute(t *testing.T) { func TestInputValidation(t *testing.T) { addr1 := sdk.BytesToAccAddress([]byte("_______alice________")) addr2 := sdk.BytesToAccAddress([]byte("________bob_________")) - addrEmpty := sdk.BytesToAccAddress([]byte("")) - addrTooLong := sdk.BytesToAccAddress([]byte("Accidentally used 33 bytes pubkey")) + addrEmpty := sdk.AccAddress("") + addrLong := sdk.BytesToAccAddress([]byte("Accidentally used 33 bytes pubkey")) someCoins := sdk.NewCoins(sdk.NewInt64Coin("atom", 123)) multiCoins := sdk.NewCoins(sdk.NewInt64Coin("atom", 123), sdk.NewInt64Coin("eth", 20)) @@ -109,9 +109,9 @@ func TestInputValidation(t *testing.T) { {"", NewInput(addr1, someCoins)}, {"", NewInput(addr2, someCoins)}, {"", NewInput(addr2, multiCoins)}, + {"", NewInput(addrLong, someCoins)}, {"empty address string is not allowed", NewInput(addrEmpty, someCoins)}, - {"incorrect address length (expected: 20, actual: 33)", NewInput(addrTooLong, someCoins)}, {": invalid coins", NewInput(addr1, emptyCoins)}, // invalid coins {": invalid coins", NewInput(addr1, emptyCoins2)}, // invalid coins {"10eth,0atom: invalid coins", NewInput(addr1, someEmptyCoins)}, // invalid coins @@ -131,8 +131,8 @@ func TestInputValidation(t *testing.T) { func TestOutputValidation(t *testing.T) { addr1 := sdk.BytesToAccAddress([]byte("_______alice________")) addr2 := sdk.BytesToAccAddress([]byte("________bob_________")) - addrEmpty := sdk.BytesToAccAddress([]byte("")) - addrTooLong := sdk.BytesToAccAddress([]byte("Accidentally used 33 bytes pubkey")) + addrEmpty := sdk.AccAddress("") + addrLong := sdk.BytesToAccAddress([]byte("Accidentally used 33 bytes pubkey")) someCoins := sdk.NewCoins(sdk.NewInt64Coin("atom", 123)) multiCoins := sdk.NewCoins(sdk.NewInt64Coin("atom", 123), sdk.NewInt64Coin("eth", 20)) @@ -150,9 +150,9 @@ func TestOutputValidation(t *testing.T) { {"", NewOutput(addr1, someCoins)}, {"", NewOutput(addr2, someCoins)}, {"", NewOutput(addr2, multiCoins)}, + {"", NewOutput(addrLong, someCoins)}, {"Invalid output address (empty address string is not allowed): invalid address", NewOutput(addrEmpty, someCoins)}, - {"Invalid output address (incorrect address length (expected: 20, actual: 33)): invalid address", NewOutput(addrTooLong, someCoins)}, {": invalid coins", NewOutput(addr1, emptyCoins)}, // invalid coins {": invalid coins", NewOutput(addr1, emptyCoins2)}, // invalid coins {"10eth,0atom: invalid coins", NewOutput(addr1, someEmptyCoins)}, // invalid coins @@ -251,13 +251,11 @@ func TestMsgMultiSendGetSigners(t *testing.T) { require.Equal(t, "[696E707574313131313131313131313131313131 696E707574323232323232323232323232323232 696E707574333333333333333333333333333333]", fmt.Sprintf("%v", res)) } -/* -// what to do w/ this test? func TestMsgSendSigners(t *testing.T) { signers := []sdk.AccAddress{ - {1, 2, 3}, - {4, 5, 6}, - {7, 8, 9}, + "123", + "456", + "789", } someCoins := sdk.NewCoins(sdk.NewInt64Coin("atom", 123)) @@ -265,8 +263,7 @@ func TestMsgSendSigners(t *testing.T) { for i, signer := range signers { inputs[i] = NewInput(signer, someCoins) } - tx := NewMsgSend(inputs, nil) + tx := NewMsgMultiSend(inputs, nil) - require.Equal(t, signers, tx.Signers()) + require.Equal(t, signers, tx.GetSigners()) } -*/ diff --git a/x/bank/types/query.pb.go b/x/bank/types/query.pb.go index 67ede715f0..a919808f49 100644 --- a/x/bank/types/query.pb.go +++ b/x/bank/types/query.pb.go @@ -219,6 +219,10 @@ func (m *QueryAllBalancesResponse) GetPagination() *query.PageResponse { // QueryTotalSupplyRequest is the request type for the Query/TotalSupply RPC // method. type QueryTotalSupplyRequest struct { + // pagination defines an optional pagination for the request. + // + // Since: cosmos-sdk 0.43 + Pagination *query.PageRequest `protobuf:"bytes,1,opt,name=pagination,proto3" json:"pagination,omitempty"` } func (m *QueryTotalSupplyRequest) Reset() { *m = QueryTotalSupplyRequest{} } @@ -259,6 +263,10 @@ var xxx_messageInfo_QueryTotalSupplyRequest proto.InternalMessageInfo type QueryTotalSupplyResponse struct { // supply is the supply of the coins Supply github_com_line_lbm_sdk_types.Coins `protobuf:"bytes,1,rep,name=supply,proto3,castrepeated=github.com/line/lbm-sdk/types.Coins" json:"supply"` + // pagination defines the pagination in the response. + // + // Since: cosmos-sdk 0.43 + Pagination *query.PageResponse `protobuf:"bytes,2,opt,name=pagination,proto3" json:"pagination,omitempty"` } func (m *QueryTotalSupplyResponse) Reset() { *m = QueryTotalSupplyResponse{} } @@ -301,6 +309,13 @@ func (m *QueryTotalSupplyResponse) GetSupply() github_com_line_lbm_sdk_types.Coi return nil } +func (m *QueryTotalSupplyResponse) GetPagination() *query.PageResponse { + if m != nil { + return m.Pagination + } + return nil +} + // QuerySupplyOfRequest is the request type for the Query/SupplyOf RPC method. type QuerySupplyOfRequest struct { // denom is the coin denom to query balances for. @@ -690,58 +705,59 @@ func init() { func init() { proto.RegisterFile("lbm/bank/v1/query.proto", fileDescriptor_6855f2fb4415a4b9) } var fileDescriptor_6855f2fb4415a4b9 = []byte{ - // 815 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x56, 0x4d, 0x6f, 0xd3, 0x4a, - 0x14, 0x8d, 0xfb, 0x5e, 0x93, 0x74, 0xa2, 0xf7, 0xa4, 0x37, 0x4d, 0x5f, 0x53, 0xb7, 0x38, 0xed, - 0x34, 0xb4, 0x15, 0x2d, 0x1e, 0x52, 0x16, 0x08, 0x16, 0x45, 0xa4, 0x2c, 0xba, 0x41, 0x2d, 0xe1, - 0x63, 0x51, 0x21, 0x55, 0xe3, 0xc6, 0xa4, 0x51, 0x6d, 0x8f, 0x9b, 0x71, 0x02, 0x51, 0x55, 0x09, - 0xc1, 0xa6, 0x6c, 0x10, 0x12, 0x2b, 0x76, 0x5d, 0xf3, 0x07, 0xf8, 0x0b, 0x5d, 0x56, 0x62, 0xc3, - 0x0a, 0x50, 0xcb, 0x82, 0x9f, 0x81, 0x32, 0x33, 0x4e, 0xec, 0xd8, 0x49, 0x84, 0x60, 0x17, 0x5f, - 0x9f, 0x39, 0xf7, 0x9c, 0x3b, 0xf7, 0x5e, 0x07, 0x4c, 0x5a, 0x86, 0x8d, 0x0d, 0xe2, 0xec, 0xe3, - 0x66, 0x11, 0x1f, 0x34, 0xcc, 0x7a, 0x4b, 0x77, 0xeb, 0xd4, 0xa3, 0x30, 0x63, 0x19, 0xb6, 0xde, - 0x7e, 0xa1, 0x37, 0x8b, 0x2a, 0x12, 0x28, 0x66, 0x0a, 0x48, 0x1b, 0xeb, 0x92, 0x6a, 0xcd, 0x21, - 0x5e, 0x8d, 0x3a, 0xe2, 0x80, 0x9a, 0xad, 0xd2, 0x2a, 0xe5, 0x3f, 0x71, 0xfb, 0x97, 0x8c, 0xce, - 0x54, 0x29, 0xad, 0x5a, 0x26, 0x26, 0x6e, 0x0d, 0x13, 0xc7, 0xa1, 0x1e, 0x3f, 0xc2, 0xe4, 0xdb, - 0xff, 0x3b, 0xbc, 0xcd, 0x22, 0xde, 0xa5, 0x35, 0x27, 0x1c, 0x17, 0xaa, 0xb8, 0x08, 0x1e, 0x47, - 0x9b, 0x60, 0xfc, 0x7e, 0x5b, 0x40, 0x89, 0x58, 0xc4, 0xd9, 0x35, 0xcb, 0xe6, 0x41, 0xc3, 0x64, - 0x1e, 0xcc, 0x81, 0x14, 0xa9, 0x54, 0xea, 0x26, 0x63, 0x39, 0x65, 0x56, 0x59, 0x1a, 0x2b, 0xfb, - 0x8f, 0x30, 0x0b, 0x46, 0x2b, 0xa6, 0x43, 0xed, 0xdc, 0x08, 0x8f, 0x8b, 0x87, 0x5b, 0xe9, 0xe3, - 0x93, 0x7c, 0xe2, 0xc7, 0x49, 0x3e, 0x81, 0xd6, 0x41, 0x36, 0x4c, 0xc8, 0x5c, 0xea, 0x30, 0x13, - 0x2e, 0x83, 0x94, 0x21, 0x42, 0x9c, 0x31, 0xb3, 0xfa, 0x9f, 0x2e, 0xea, 0xc1, 0x4c, 0xbd, 0x59, - 0xd4, 0xd7, 0x69, 0xcd, 0x29, 0xfb, 0x08, 0x74, 0x04, 0x26, 0x39, 0xc9, 0x1d, 0xcb, 0x92, 0x3c, - 0x6c, 0xb8, 0xb2, 0x35, 0x00, 0xba, 0x25, 0xe4, 0xf2, 0x32, 0xab, 0x5a, 0x37, 0x89, 0xb8, 0x8a, - 0x66, 0x51, 0xdf, 0x22, 0x55, 0xdf, 0x67, 0x39, 0x70, 0x22, 0xe0, 0xe1, 0xa3, 0x02, 0x72, 0xd1, - 0xfc, 0xd2, 0xc8, 0x36, 0x48, 0x4b, 0x99, 0x6d, 0x05, 0x7f, 0xc5, 0x3a, 0x29, 0x2d, 0x9f, 0x7e, - 0xc9, 0x27, 0x3e, 0x7c, 0xcd, 0xcf, 0x57, 0x6b, 0xde, 0x5e, 0xc3, 0xd0, 0x77, 0xa9, 0x8d, 0xad, - 0x9a, 0x63, 0x62, 0xcb, 0xb0, 0xaf, 0xb2, 0xca, 0x3e, 0xf6, 0x5a, 0xae, 0xc9, 0x38, 0x96, 0x95, - 0x3b, 0x7c, 0xf0, 0x76, 0x8c, 0x85, 0x7c, 0x5f, 0x0b, 0x42, 0x50, 0xd0, 0x03, 0x9a, 0x92, 0x85, - 0x7b, 0x48, 0x3d, 0x62, 0x3d, 0x68, 0xb8, 0xae, 0xd5, 0x92, 0x56, 0x51, 0x5d, 0x7a, 0x0a, 0xbd, - 0x92, 0x9e, 0x1e, 0x83, 0x24, 0xe3, 0x91, 0x3f, 0xe4, 0x48, 0xb2, 0xa1, 0x15, 0xd9, 0x0c, 0x22, - 0xdd, 0xe6, 0x53, 0xff, 0x12, 0x3b, 0x4d, 0xa4, 0x04, 0x9a, 0x08, 0x6d, 0x80, 0x89, 0x1e, 0xb4, - 0x94, 0x87, 0x41, 0x92, 0xd8, 0xb4, 0xe1, 0x78, 0x7d, 0x5b, 0xa7, 0xf4, 0x77, 0x5b, 0x5e, 0x59, - 0xc2, 0x50, 0x16, 0x40, 0xce, 0xb4, 0x45, 0xea, 0xc4, 0xf6, 0x5b, 0x07, 0x6d, 0xc8, 0x5e, 0xf7, - 0xa3, 0x92, 0xbd, 0x08, 0x92, 0x2e, 0x8f, 0x48, 0xf6, 0x71, 0x3d, 0x30, 0xa8, 0xba, 0x00, 0xfb, - 0xfc, 0x02, 0x88, 0x9e, 0x00, 0x95, 0x33, 0xdd, 0x6d, 0xeb, 0x66, 0xf7, 0x4c, 0x8f, 0x54, 0x88, - 0x47, 0x7c, 0x77, 0xe1, 0x46, 0x54, 0x7e, 0xb5, 0x11, 0xd1, 0x7b, 0x05, 0x4c, 0xc7, 0xd2, 0x4b, - 0xc1, 0x37, 0xc1, 0x98, 0x2d, 0x63, 0x7e, 0x0b, 0x4e, 0x84, 0x34, 0xfb, 0x27, 0xa4, 0xea, 0x2e, - 0xfa, 0xf7, 0x1b, 0xac, 0x08, 0xa6, 0xba, 0xd2, 0x7a, 0x8d, 0xc7, 0x5f, 0xeb, 0xa3, 0x60, 0xb1, - 0x22, 0x66, 0x6e, 0x80, 0xb4, 0x2f, 0x4f, 0x96, 0x6a, 0xa0, 0x97, 0x0e, 0x78, 0xf5, 0x38, 0x05, - 0x46, 0x39, 0x2f, 0x7c, 0xa1, 0x80, 0x94, 0x1c, 0x53, 0x38, 0x1b, 0x3a, 0x1c, 0xb3, 0xda, 0xd4, - 0xb9, 0x01, 0x08, 0xa1, 0x09, 0x5d, 0x7b, 0xf9, 0xe9, 0xfb, 0xbb, 0x91, 0x2b, 0x70, 0x09, 0x87, - 0xb7, 0xa6, 0x98, 0x52, 0x7c, 0x28, 0x37, 0xce, 0x11, 0x36, 0x5a, 0x3b, 0xdc, 0x23, 0x7c, 0xa5, - 0x80, 0x4c, 0x60, 0x59, 0xc0, 0x42, 0x34, 0x49, 0x74, 0x97, 0xa9, 0x97, 0x87, 0xa0, 0xa4, 0x9c, - 0x45, 0x2e, 0x67, 0x0e, 0xe6, 0x87, 0xc8, 0x81, 0xcf, 0x40, 0x26, 0x30, 0xdd, 0x71, 0x22, 0xa2, - 0x7b, 0x21, 0x4e, 0x44, 0xcc, 0x8a, 0x40, 0xd3, 0x5c, 0xc4, 0x04, 0x1c, 0x0f, 0x89, 0x10, 0x73, - 0x0e, 0x9b, 0x20, 0xed, 0x0f, 0x2d, 0x8c, 0xa9, 0x6f, 0xcf, 0xf8, 0xab, 0x68, 0x10, 0x44, 0xe6, - 0x9b, 0xe7, 0xf9, 0x2e, 0xc1, 0xe9, 0x98, 0x7c, 0xf8, 0x90, 0x57, 0xfd, 0x08, 0xee, 0x81, 0xa4, - 0x98, 0x4f, 0x98, 0x8f, 0x52, 0x86, 0x86, 0x5f, 0x9d, 0xed, 0x0f, 0x18, 0xe8, 0x50, 0x4c, 0x3c, - 0x7c, 0xa3, 0x80, 0x7f, 0x42, 0x0d, 0x0c, 0x17, 0xa2, 0x84, 0x71, 0x43, 0xa1, 0x2e, 0x0e, 0xc5, - 0xc9, 0xfc, 0x2b, 0x3c, 0xff, 0x02, 0x2c, 0x84, 0xf2, 0x73, 0xa7, 0x6c, 0xc7, 0x6f, 0xfb, 0x8e, - 0xf5, 0xd7, 0x0a, 0xf8, 0x37, 0xbc, 0x1f, 0x60, 0xbf, 0x4c, 0xbd, 0x0b, 0x4a, 0x5d, 0x1a, 0x0e, - 0x94, 0x9a, 0x0a, 0x5c, 0x93, 0x06, 0x67, 0x06, 0x69, 0x2a, 0xad, 0x9d, 0x9e, 0x6b, 0xca, 0xd9, - 0xb9, 0xa6, 0x7c, 0x3b, 0xd7, 0x94, 0xb7, 0x17, 0x5a, 0xe2, 0xec, 0x42, 0x4b, 0x7c, 0xbe, 0xd0, - 0x12, 0xdb, 0x85, 0x7e, 0x5f, 0x8b, 0xe7, 0x82, 0x8c, 0x7f, 0x34, 0x8c, 0x24, 0xff, 0x2f, 0x72, - 0xfd, 0x67, 0x00, 0x00, 0x00, 0xff, 0xff, 0x2b, 0x46, 0xce, 0xc7, 0x3b, 0x09, 0x00, 0x00, + // 817 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x56, 0xcf, 0x4f, 0x13, 0x5d, + 0x14, 0xed, 0xf0, 0x7d, 0xb4, 0xe5, 0x36, 0xdf, 0x97, 0xf8, 0x28, 0x52, 0x07, 0x9c, 0xc2, 0x50, + 0x81, 0x08, 0xce, 0x58, 0x5c, 0x18, 0x5d, 0x60, 0x2c, 0x2e, 0xd8, 0x18, 0xb0, 0xfe, 0x58, 0x10, + 0x13, 0xf2, 0xa6, 0x1d, 0x4b, 0xc3, 0xcc, 0xbc, 0xa1, 0x6f, 0x5a, 0x6d, 0x08, 0x89, 0xd1, 0x0d, + 0x6e, 0x8c, 0x89, 0x2b, 0x77, 0xac, 0xdd, 0xba, 0xf0, 0x5f, 0x60, 0x49, 0xe2, 0xc6, 0x95, 0x1a, + 0x70, 0xe1, 0x9f, 0x61, 0xfa, 0xde, 0x9b, 0x76, 0xa6, 0x9d, 0xb6, 0x0b, 0xd8, 0xb5, 0xb7, 0xe7, + 0x9d, 0x7b, 0xce, 0x99, 0x77, 0xef, 0x14, 0x26, 0x2d, 0xc3, 0xd6, 0x0d, 0xec, 0xec, 0xea, 0x8d, + 0xbc, 0xbe, 0x57, 0x37, 0x6b, 0x4d, 0xcd, 0xad, 0x11, 0x8f, 0xa0, 0x94, 0x65, 0xd8, 0x5a, 0xeb, + 0x07, 0xad, 0x91, 0x97, 0x55, 0x8e, 0xa2, 0x26, 0x87, 0xb4, 0xb0, 0x2e, 0xae, 0x54, 0x1d, 0xec, + 0x55, 0x89, 0xc3, 0x0f, 0xc8, 0xe9, 0x0a, 0xa9, 0x10, 0xf6, 0x51, 0x6f, 0x7d, 0x12, 0xd5, 0xe9, + 0x0a, 0x21, 0x15, 0xcb, 0xd4, 0xb1, 0x5b, 0xd5, 0xb1, 0xe3, 0x10, 0x8f, 0x1d, 0xa1, 0xe2, 0xd7, + 0xcb, 0x6d, 0xde, 0x46, 0x5e, 0x2f, 0x91, 0xaa, 0x13, 0xae, 0x73, 0x55, 0x4c, 0x04, 0xab, 0xab, + 0x1b, 0x30, 0xfe, 0xa8, 0x25, 0xa0, 0x80, 0x2d, 0xec, 0x94, 0xcc, 0xa2, 0xb9, 0x57, 0x37, 0xa9, + 0x87, 0x32, 0x90, 0xc0, 0xe5, 0x72, 0xcd, 0xa4, 0x34, 0x23, 0xcd, 0x48, 0x8b, 0x63, 0x45, 0xff, + 0x2b, 0x4a, 0xc3, 0x68, 0xd9, 0x74, 0x88, 0x9d, 0x19, 0x61, 0x75, 0xfe, 0xe5, 0x6e, 0xf2, 0xf0, + 0x28, 0x1b, 0xfb, 0x73, 0x94, 0x8d, 0xa9, 0x6b, 0x90, 0x0e, 0x13, 0x52, 0x97, 0x38, 0xd4, 0x44, + 0x4b, 0x90, 0x30, 0x78, 0x89, 0x31, 0xa6, 0x56, 0x2e, 0x69, 0x3c, 0x0f, 0x6a, 0x6a, 0x8d, 0xbc, + 0xb6, 0x46, 0xaa, 0x4e, 0xd1, 0x47, 0xa8, 0x07, 0x30, 0xc9, 0x48, 0xee, 0x5b, 0x96, 0xe0, 0xa1, + 0xc3, 0x95, 0xad, 0x02, 0x74, 0x22, 0x64, 0xf2, 0x52, 0x2b, 0x4a, 0xa7, 0x09, 0x7f, 0x14, 0x8d, + 0xbc, 0xb6, 0x89, 0x2b, 0xbe, 0xcf, 0x62, 0xe0, 0x44, 0xc0, 0xc3, 0x57, 0x09, 0x32, 0xbd, 0xfd, + 0x85, 0x91, 0x2d, 0x48, 0x0a, 0x99, 0x2d, 0x05, 0xff, 0x44, 0x3a, 0x29, 0x2c, 0x1d, 0xff, 0xc8, + 0xc6, 0x3e, 0xff, 0xcc, 0xce, 0x55, 0xaa, 0xde, 0x4e, 0xdd, 0xd0, 0x4a, 0xc4, 0xd6, 0xad, 0xaa, + 0x63, 0xea, 0x96, 0x61, 0xdf, 0xa0, 0xe5, 0x5d, 0xdd, 0x6b, 0xba, 0x26, 0x65, 0x58, 0x5a, 0x6c, + 0xf3, 0xa1, 0x7b, 0x11, 0x16, 0xb2, 0x7d, 0x2d, 0x70, 0x41, 0x41, 0x0f, 0x6a, 0x49, 0x04, 0xf7, + 0x84, 0x78, 0xd8, 0x7a, 0x5c, 0x77, 0x5d, 0xab, 0xe9, 0x07, 0x17, 0x8e, 0x47, 0x3a, 0x47, 0x3c, + 0x5f, 0xfc, 0x78, 0x42, 0x5d, 0x44, 0x3c, 0xcf, 0x20, 0x4e, 0x59, 0xe5, 0x82, 0xc2, 0x11, 0x6c, + 0xe7, 0x8f, 0x66, 0x59, 0x5c, 0x4c, 0xae, 0x77, 0xe3, 0x85, 0x9f, 0x4b, 0xfb, 0x42, 0x4b, 0x81, + 0x0b, 0xad, 0xae, 0xc3, 0x44, 0x17, 0x5a, 0xf8, 0xd3, 0x21, 0x8e, 0x6d, 0x52, 0x77, 0xbc, 0xbe, + 0xd7, 0xb8, 0xf0, 0x6f, 0xcb, 0x5f, 0x51, 0xc0, 0xd4, 0x34, 0x20, 0xc6, 0xb4, 0x89, 0x6b, 0xd8, + 0xf6, 0xaf, 0xb1, 0xba, 0x2e, 0xe6, 0xce, 0xaf, 0x0a, 0xf6, 0x3c, 0xc4, 0x5d, 0x56, 0x11, 0xec, + 0xe3, 0x5a, 0x60, 0x69, 0x68, 0x1c, 0xec, 0xf3, 0x73, 0xa0, 0xfa, 0x1c, 0x64, 0xc6, 0xf4, 0xa0, + 0xa5, 0x9b, 0x3e, 0x34, 0x3d, 0x5c, 0xc6, 0x1e, 0xbe, 0xa0, 0xa7, 0xae, 0x7e, 0x92, 0x60, 0x2a, + 0x92, 0x5e, 0x08, 0xbe, 0x03, 0x63, 0xb6, 0xa8, 0xf9, 0xe3, 0x30, 0x11, 0xd2, 0xec, 0x9f, 0x10, + 0xaa, 0x3b, 0xe8, 0xf3, 0x3f, 0xd1, 0x3c, 0x5c, 0xe9, 0x48, 0xeb, 0x36, 0x1e, 0xfd, 0x58, 0x9f, + 0x06, 0xc3, 0xea, 0x31, 0x73, 0x1b, 0x92, 0xbe, 0x3c, 0x11, 0xd5, 0x40, 0x2f, 0x6d, 0xf0, 0xca, + 0x61, 0x02, 0x46, 0x19, 0x2f, 0x7a, 0x2d, 0x41, 0x42, 0xac, 0x0c, 0x34, 0x13, 0x3a, 0x1c, 0xb1, + 0x66, 0xe5, 0xd9, 0x01, 0x08, 0xae, 0x49, 0xbd, 0xf9, 0xe6, 0xdb, 0xef, 0x8f, 0x23, 0xd7, 0xd1, + 0xa2, 0x1e, 0xde, 0xe0, 0x7c, 0x63, 0xe8, 0xfb, 0x62, 0xfb, 0x1d, 0xe8, 0x46, 0x73, 0x9b, 0x79, + 0x44, 0x6f, 0x25, 0x48, 0x05, 0x16, 0x17, 0xca, 0xf5, 0x36, 0xe9, 0xdd, 0xab, 0xf2, 0xb5, 0x21, + 0x28, 0x21, 0x67, 0x81, 0xc9, 0x99, 0x45, 0xd9, 0x21, 0x72, 0xd0, 0x4b, 0x48, 0x05, 0xd6, 0x43, + 0x94, 0x88, 0xde, 0x1d, 0x15, 0x25, 0x22, 0x62, 0xc7, 0xa8, 0x53, 0x4c, 0xc4, 0x04, 0x1a, 0x0f, + 0x89, 0x10, 0x8b, 0xa2, 0x01, 0x49, 0x7f, 0x68, 0x51, 0x44, 0xbe, 0x5d, 0xe3, 0x2f, 0xab, 0x83, + 0x20, 0xa2, 0xdf, 0x1c, 0xeb, 0x77, 0x15, 0x4d, 0x45, 0xf4, 0xd3, 0xf7, 0x59, 0xea, 0x07, 0x68, + 0x07, 0xe2, 0x7c, 0x3e, 0x51, 0xb6, 0x97, 0x32, 0x34, 0xfc, 0xf2, 0x4c, 0x7f, 0xc0, 0x40, 0x87, + 0x7c, 0xe2, 0xd1, 0x7b, 0x09, 0xfe, 0x0b, 0x5d, 0x60, 0x34, 0xdf, 0x4b, 0x18, 0x35, 0x14, 0xf2, + 0xc2, 0x50, 0x9c, 0xe8, 0xbf, 0xcc, 0xfa, 0xcf, 0xa3, 0x5c, 0xa8, 0x3f, 0x73, 0x4a, 0xb7, 0xfd, + 0x6b, 0xdf, 0xb6, 0xfe, 0x4e, 0x82, 0xff, 0xc3, 0xfb, 0x01, 0xf5, 0xeb, 0xd4, 0xbd, 0xa0, 0xe4, + 0xc5, 0xe1, 0x40, 0xa1, 0x29, 0xc7, 0x34, 0x29, 0x68, 0x7a, 0x90, 0xa6, 0xc2, 0xea, 0xf1, 0xa9, + 0x22, 0x9d, 0x9c, 0x2a, 0xd2, 0xaf, 0x53, 0x45, 0xfa, 0x70, 0xa6, 0xc4, 0x4e, 0xce, 0x94, 0xd8, + 0xf7, 0x33, 0x25, 0xb6, 0x95, 0xeb, 0xf7, 0xba, 0x79, 0xc5, 0xc9, 0xd8, 0x5b, 0xc7, 0x88, 0xb3, + 0xff, 0x45, 0xb7, 0xfe, 0x06, 0x00, 0x00, 0xff, 0xff, 0x15, 0x3e, 0x06, 0xfa, 0xc7, 0x09, 0x00, + 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -1237,6 +1253,18 @@ func (m *QueryTotalSupplyRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) _ = i var l int _ = l + if m.Pagination != nil { + { + size, err := m.Pagination.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } return len(dAtA) - i, nil } @@ -1260,6 +1288,18 @@ func (m *QueryTotalSupplyResponse) MarshalToSizedBuffer(dAtA []byte) (int, error _ = i var l int _ = l + if m.Pagination != nil { + { + size, err := m.Pagination.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } if len(m.Supply) > 0 { for iNdEx := len(m.Supply) - 1; iNdEx >= 0; iNdEx-- { { @@ -1626,6 +1666,10 @@ func (m *QueryTotalSupplyRequest) Size() (n int) { } var l int _ = l + if m.Pagination != nil { + l = m.Pagination.Size() + n += 1 + l + sovQuery(uint64(l)) + } return n } @@ -1641,6 +1685,10 @@ func (m *QueryTotalSupplyResponse) Size() (n int) { n += 1 + l + sovQuery(uint64(l)) } } + if m.Pagination != nil { + l = m.Pagination.Size() + n += 1 + l + sovQuery(uint64(l)) + } return n } @@ -2217,6 +2265,42 @@ func (m *QueryTotalSupplyRequest) Unmarshal(dAtA []byte) error { return fmt.Errorf("proto: QueryTotalSupplyRequest: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Pagination", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Pagination == nil { + m.Pagination = &query.PageRequest{} + } + if err := m.Pagination.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipQuery(dAtA[iNdEx:]) @@ -2301,6 +2385,42 @@ func (m *QueryTotalSupplyResponse) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Pagination", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Pagination == nil { + m.Pagination = &query.PageResponse{} + } + if err := m.Pagination.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipQuery(dAtA[iNdEx:]) diff --git a/x/bank/types/query.pb.gw.go b/x/bank/types/query.pb.gw.go index 1f738096de..b434e1131b 100644 --- a/x/bank/types/query.pb.gw.go +++ b/x/bank/types/query.pb.gw.go @@ -175,10 +175,21 @@ func local_request_Query_AllBalances_0(ctx context.Context, marshaler runtime.Ma } +var ( + filter_Query_TotalSupply_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)} +) + func request_Query_TotalSupply_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { var protoReq QueryTotalSupplyRequest var metadata runtime.ServerMetadata + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_TotalSupply_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + msg, err := client.TotalSupply(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err @@ -188,6 +199,13 @@ func local_request_Query_TotalSupply_0(ctx context.Context, marshaler runtime.Ma var protoReq QueryTotalSupplyRequest var metadata runtime.ServerMetadata + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_TotalSupply_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + msg, err := server.TotalSupply(ctx, &protoReq) return msg, metadata, err @@ -686,19 +704,19 @@ func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, clie } var ( - pattern_Query_Balance_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4, 2, 5}, []string{"lbm", "bank", "v1", "balances", "address", "by_denom"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_Query_Balance_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4, 2, 5}, []string{"lbm", "bank", "v1", "balances", "address", "by_denom"}, "", runtime.AssumeColonVerbOpt(false))) - pattern_Query_AllBalances_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4}, []string{"lbm", "bank", "v1", "balances", "address"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_Query_AllBalances_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4}, []string{"lbm", "bank", "v1", "balances", "address"}, "", runtime.AssumeColonVerbOpt(false))) - pattern_Query_TotalSupply_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"lbm", "bank", "v1", "supply"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_Query_TotalSupply_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"lbm", "bank", "v1", "supply"}, "", runtime.AssumeColonVerbOpt(false))) - pattern_Query_SupplyOf_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4}, []string{"lbm", "bank", "v1", "supply", "denom"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_Query_SupplyOf_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4}, []string{"lbm", "bank", "v1", "supply", "denom"}, "", runtime.AssumeColonVerbOpt(false))) - pattern_Query_Params_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"lbm", "bank", "v1", "params"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_Query_Params_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"lbm", "bank", "v1", "params"}, "", runtime.AssumeColonVerbOpt(false))) - pattern_Query_DenomMetadata_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4}, []string{"lbm", "bank", "v1", "denoms_metadata", "denom"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_Query_DenomMetadata_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4}, []string{"lbm", "bank", "v1", "denoms_metadata", "denom"}, "", runtime.AssumeColonVerbOpt(false))) - pattern_Query_DenomsMetadata_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"lbm", "bank", "v1", "denoms_metadata"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_Query_DenomsMetadata_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"lbm", "bank", "v1", "denoms_metadata"}, "", runtime.AssumeColonVerbOpt(false))) ) var ( diff --git a/x/bank/types/send_authorization.go b/x/bank/types/send_authorization.go new file mode 100644 index 0000000000..07b0222602 --- /dev/null +++ b/x/bank/types/send_authorization.go @@ -0,0 +1,51 @@ +package types + +import ( + sdk "github.com/line/lbm-sdk/types" + sdkerrors "github.com/line/lbm-sdk/types/errors" + "github.com/line/lbm-sdk/x/authz" +) + +var ( + _ authz.Authorization = &SendAuthorization{} +) + +// NewSendAuthorization creates a new SendAuthorization object. +func NewSendAuthorization(spendLimit sdk.Coins) *SendAuthorization { + return &SendAuthorization{ + SpendLimit: spendLimit, + } +} + +// MsgTypeURL implements Authorization.MsgTypeURL. +func (a SendAuthorization) MsgTypeURL() string { + return sdk.MsgTypeURL(&MsgSend{}) +} + +// Accept implements Authorization.Accept. +func (a SendAuthorization) Accept(ctx sdk.Context, msg sdk.Msg) (authz.AcceptResponse, error) { + mSend, ok := msg.(*MsgSend) + if !ok { + return authz.AcceptResponse{}, sdkerrors.ErrInvalidType.Wrap("type mismatch") + } + limitLeft, isNegative := a.SpendLimit.SafeSub(mSend.Amount) + if isNegative { + return authz.AcceptResponse{}, sdkerrors.ErrInsufficientFunds.Wrapf("requested amount is more than spend limit") + } + if limitLeft.IsZero() { + return authz.AcceptResponse{Accept: true, Delete: true}, nil + } + + return authz.AcceptResponse{Accept: true, Delete: false, Updated: &SendAuthorization{SpendLimit: limitLeft}}, nil +} + +// ValidateBasic implements Authorization.ValidateBasic. +func (a SendAuthorization) ValidateBasic() error { + if a.SpendLimit == nil { + return sdkerrors.ErrInvalidCoins.Wrap("spend limit cannot be nil") + } + if !a.SpendLimit.IsAllPositive() { + return sdkerrors.ErrInvalidCoins.Wrapf("spend limit cannot be negitive") + } + return nil +} diff --git a/x/bank/types/send_authorization_test.go b/x/bank/types/send_authorization_test.go new file mode 100644 index 0000000000..3245938793 --- /dev/null +++ b/x/bank/types/send_authorization_test.go @@ -0,0 +1,59 @@ +package types_test + +import ( + "testing" + + "github.com/stretchr/testify/require" + + ocproto "github.com/line/ostracon/proto/ostracon/types" + + "github.com/line/lbm-sdk/simapp" + sdk "github.com/line/lbm-sdk/types" + "github.com/line/lbm-sdk/x/bank/types" +) + +var ( + coins1000 = sdk.NewCoins(sdk.NewCoin("stake", sdk.NewInt(1000))) + coins500 = sdk.NewCoins(sdk.NewCoin("stake", sdk.NewInt(500))) + fromAddr = sdk.BytesToAccAddress([]byte("_____from _____")) + toAddr = sdk.BytesToAccAddress([]byte("_______to________")) +) + +func TestSendAuthorization(t *testing.T) { + app := simapp.Setup(false) + ctx := app.BaseApp.NewContext(false, ocproto.Header{}) + authorization := types.NewSendAuthorization(coins1000) + + t.Log("verify authorization returns valid method name") + require.Equal(t, authorization.MsgTypeURL(), "/lbm.bank.v1.MsgSend") + require.NoError(t, authorization.ValidateBasic()) + send := types.NewMsgSend(fromAddr, toAddr, coins1000) + + require.NoError(t, authorization.ValidateBasic()) + + t.Log("verify updated authorization returns nil") + resp, err := authorization.Accept(ctx, send) + require.NoError(t, err) + require.True(t, resp.Delete) + require.Nil(t, resp.Updated) + + authorization = types.NewSendAuthorization(coins1000) + require.Equal(t, authorization.MsgTypeURL(), "/lbm.bank.v1.MsgSend") + require.NoError(t, authorization.ValidateBasic()) + send = types.NewMsgSend(fromAddr, toAddr, coins500) + require.NoError(t, authorization.ValidateBasic()) + resp, err = authorization.Accept(ctx, send) + + t.Log("verify updated authorization returns remaining spent limit") + require.NoError(t, err) + require.False(t, resp.Delete) + require.NotNil(t, resp.Updated) + sendAuth := types.NewSendAuthorization(coins500) + require.Equal(t, sendAuth.String(), resp.Updated.String()) + + t.Log("expect updated authorization nil after spending remaining amount") + resp, err = resp.Updated.Accept(ctx, send) + require.NoError(t, err) + require.True(t, resp.Delete) + require.Nil(t, resp.Updated) +} diff --git a/x/bank/types/supply.go b/x/bank/types/supply.go deleted file mode 100644 index a32020ca91..0000000000 --- a/x/bank/types/supply.go +++ /dev/null @@ -1,71 +0,0 @@ -package types - -import ( - "fmt" - - yaml "gopkg.in/yaml.v2" - - sdk "github.com/line/lbm-sdk/types" - "github.com/line/lbm-sdk/x/bank/exported" -) - -// Implements Delegation interface -var _ exported.SupplyI = (*Supply)(nil) - -// NewSupply creates a new Supply instance -func NewSupply(total sdk.Coins) *Supply { - return &Supply{total} -} - -// DefaultSupply creates an empty Supply -func DefaultSupply() *Supply { - return NewSupply(sdk.NewCoins()) -} - -// SetTotal sets the total supply. -func (supply *Supply) SetTotal(total sdk.Coins) { - supply.Total = total -} - -// GetTotal returns the supply total. -func (supply Supply) GetTotal() sdk.Coins { - return supply.Total -} - -// Inflate adds coins to the total supply -func (supply *Supply) Inflate(amount sdk.Coins) { - supply.Total = supply.Total.Add(amount...) -} - -// Deflate subtracts coins from the total supply. -func (supply *Supply) Deflate(amount sdk.Coins) { - supply.Total = supply.Total.Sub(amount) -} - -// String returns a human readable string representation of a supplier. -func (supply Supply) String() string { - bz, _ := yaml.Marshal(supply) - return string(bz) -} - -// ValidateBasic validates the Supply coins and returns error if invalid -func (supply Supply) ValidateBasic() error { - if err := supply.Total.Validate(); err != nil { - return fmt.Errorf("invalid total supply: %w", err) - } - - return nil -} - -func (supply *Supply) MarshalX() ([]byte, error) { - return supply.Marshal() -} - -func UnmarshalSupplyX(bz []byte) (exported.SupplyI, error) { - var supply Supply - - if err := supply.Unmarshal(bz); err != nil { - return nil, err - } - return &supply, nil -} diff --git a/x/bank/types/supply_test.go b/x/bank/types/supply_test.go deleted file mode 100644 index a4a2820ee0..0000000000 --- a/x/bank/types/supply_test.go +++ /dev/null @@ -1,28 +0,0 @@ -package types - -import ( - "fmt" - "testing" - - "github.com/stretchr/testify/require" - yaml "gopkg.in/yaml.v2" - - sdk "github.com/line/lbm-sdk/types" -) - -func TestSupplyMarshalYAML(t *testing.T) { - supply := DefaultSupply() - coins := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.OneInt())) - supply.Inflate(coins) - - bz, err := yaml.Marshal(supply) - require.NoError(t, err) - bzCoins, err := yaml.Marshal(coins) - require.NoError(t, err) - - want := fmt.Sprintf(`total: -%s`, string(bzCoins)) - - require.Equal(t, want, string(bz)) - require.Equal(t, want, supply.String()) -} diff --git a/x/bankplus/keeper/inactive.go b/x/bankplus/keeper/inactive.go index 03637581dc..5abca4b16d 100644 --- a/x/bankplus/keeper/inactive.go +++ b/x/bankplus/keeper/inactive.go @@ -25,7 +25,7 @@ func (keeper BaseKeeper) isStoredInactiveAddr(ctx sdk.Context, address sdk.AccAd func (keeper BaseKeeper) addToInactiveAddr(ctx sdk.Context, address sdk.AccAddress) { store := ctx.KVStore(keeper.storeKey) blockedCAddr := types.InactiveAddr{Address: address.String()} - bz := keeper.cdc.MustMarshalBinaryBare(&blockedCAddr) + bz := keeper.cdc.MustMarshal(&blockedCAddr) store.Set(inactiveAddrKey(address), bz) } @@ -45,7 +45,7 @@ func (keeper BaseKeeper) loadAllInactiveAddrs(ctx sdk.Context) { defer iterator.Close() for ; iterator.Valid(); iterator.Next() { var bAddr types.InactiveAddr - keeper.cdc.MustUnmarshalBinaryBare(iterator.Value(), &bAddr) + keeper.cdc.MustUnmarshal(iterator.Value(), &bAddr) keeper.inactiveAddrs[bAddr.Address] = true } diff --git a/x/bankplus/keeper/inactive_test.go b/x/bankplus/keeper/inactive_test.go index 62a8a97c86..37069dc962 100644 --- a/x/bankplus/keeper/inactive_test.go +++ b/x/bankplus/keeper/inactive_test.go @@ -29,12 +29,13 @@ func setupKeeper(storeKey *sdk.KVStoreKey) BaseKeeper { registry := codectypes.NewInterfaceRegistry() cdc := codec.NewProtoCodec(registry) amino := codec.NewLegacyAmino() + testTransientStoreKey := sdk.NewTransientStoreKey("test") accountStoreKey := sdk.NewKVStoreKey(accounttypes.StoreKey) - accountSubspace := paramtypes.NewSubspace(cdc, amino, accountStoreKey, accounttypes.ModuleName) + accountSubspace := paramtypes.NewSubspace(cdc, amino, accountStoreKey, testTransientStoreKey, accounttypes.ModuleName) accountKeeper := accountkeeper.NewAccountKeeper(cdc, accountStoreKey, accountSubspace, accounttypes.ProtoBaseAccount, nil) - bankSubspace := paramtypes.NewSubspace(cdc, amino, storeKey, banktypes.StoreKey) + bankSubspace := paramtypes.NewSubspace(cdc, amino, storeKey, testTransientStoreKey, banktypes.StoreKey) return NewBaseKeeper(cdc, storeKey, accountKeeper, bankSubspace, nil) } diff --git a/x/bankplus/keeper/keeper.go b/x/bankplus/keeper/keeper.go index 70f628dce7..5a2f84d179 100644 --- a/x/bankplus/keeper/keeper.go +++ b/x/bankplus/keeper/keeper.go @@ -25,13 +25,13 @@ type BaseKeeper struct { bankkeeper.BaseKeeper ak types.AccountKeeper - cdc codec.BinaryMarshaler + cdc codec.Codec storeKey sdk.StoreKey inactiveAddrs map[string]bool } func NewBaseKeeper( - cdc codec.BinaryMarshaler, storeKey sdk.StoreKey, ak types.AccountKeeper, paramSpace *paramtypes.Subspace, + cdc codec.Codec, storeKey sdk.StoreKey, ak types.AccountKeeper, paramSpace paramtypes.Subspace, blockedAddr map[string]bool, ) BaseKeeper { return BaseKeeper{ diff --git a/x/bankplus/keeper/keeper_test.go b/x/bankplus/keeper/keeper_test.go index 9571797935..aa4bc2a59d 100644 --- a/x/bankplus/keeper/keeper_test.go +++ b/x/bankplus/keeper/keeper_test.go @@ -3,16 +3,17 @@ package keeper_test import ( "testing" + "github.com/stretchr/testify/suite" + + ocproto "github.com/line/ostracon/proto/ostracon/types" + "github.com/line/lbm-sdk/simapp" sdk "github.com/line/lbm-sdk/types" authkeeper "github.com/line/lbm-sdk/x/auth/keeper" authtypes "github.com/line/lbm-sdk/x/auth/types" - - ocproto "github.com/line/ostracon/proto/ostracon/types" - "github.com/stretchr/testify/suite" - "github.com/line/lbm-sdk/x/bank/types" bankpluskeeper "github.com/line/lbm-sdk/x/bankplus/keeper" + minttypes "github.com/line/lbm-sdk/x/mint/types" ) const ( @@ -26,7 +27,7 @@ var ( blockedAcc = authtypes.NewEmptyModuleAccount(blocker) burnerAcc = authtypes.NewEmptyModuleAccount(authtypes.Burner, authtypes.Burner) - initTokens = sdk.TokensFromConsensusPower(initialPower) + initTokens = sdk.TokensFromConsensusPower(initialPower, sdk.DefaultPowerReduction) initCoins = sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, initTokens)) ) @@ -35,7 +36,7 @@ func getCoinsByName(ctx sdk.Context, bk bankpluskeeper.Keeper, ak types.AccountK moduleAddress := ak.GetModuleAddress(moduleName) macc := ak.GetAccount(ctx, moduleAddress) if macc == nil { - return sdk.Coins(nil) + return sdk.NewCoins() } return bk.GetAllBalances(ctx, macc.GetAddress()) @@ -43,10 +44,6 @@ func getCoinsByName(ctx sdk.Context, bk bankpluskeeper.Keeper, ak types.AccountK type IntegrationTestSuite struct { suite.Suite - - app *simapp.SimApp - ctx sdk.Context - queryClient types.QueryClient } func (suite *IntegrationTestSuite) TestSupply_SendCoins() { @@ -70,9 +67,17 @@ func (suite *IntegrationTestSuite) TestSupply_SendCoins() { ) baseAcc := authKeeper.NewAccountWithAddress(ctx, authtypes.NewModuleAddress("baseAcc")) - suite.Require().NoError(keeper.SetBalances(ctx, holderAcc.GetAddress(), initCoins)) - keeper.SetSupply(ctx, types.NewSupply(initCoins)) + // set initial balances + suite. + Require(). + NoError(keeper.MintCoins(ctx, minttypes.ModuleName, initCoins)) + + suite. + Require(). + NoError(keeper.SendCoinsFromModuleToAccount(ctx, minttypes.ModuleName, holderAcc.GetAddress(), initCoins)) + + suite.Require().NoError(keeper.MintCoins(ctx, minttypes.ModuleName, initCoins)) authKeeper.SetModuleAccount(ctx, holderAcc) authKeeper.SetModuleAccount(ctx, burnerAcc) authKeeper.SetAccount(ctx, baseAcc) @@ -97,17 +102,17 @@ func (suite *IntegrationTestSuite) TestSupply_SendCoins() { suite.Require().NoError( keeper.SendCoinsFromModuleToModule(ctx, holderAcc.GetName(), authtypes.Burner, initCoins), ) - suite.Require().Equal(sdk.Coins(nil), getCoinsByName(ctx, keeper, authKeeper, holderAcc.GetName())) + suite.Require().Equal(sdk.NewCoins().String(), getCoinsByName(ctx, keeper, authKeeper, holderAcc.GetName()).String()) suite.Require().Equal(initCoins, getCoinsByName(ctx, keeper, authKeeper, authtypes.Burner)) suite.Require().NoError( keeper.SendCoinsFromModuleToAccount(ctx, authtypes.Burner, baseAcc.GetAddress(), initCoins), ) - suite.Require().Equal(sdk.Coins(nil), getCoinsByName(ctx, keeper, authKeeper, authtypes.Burner)) + suite.Require().Equal(sdk.NewCoins().String(), getCoinsByName(ctx, keeper, authKeeper, authtypes.Burner).String()) suite.Require().Equal(initCoins, keeper.GetAllBalances(ctx, baseAcc.GetAddress())) suite.Require().NoError(keeper.SendCoinsFromAccountToModule(ctx, baseAcc.GetAddress(), authtypes.Burner, initCoins)) - suite.Require().Equal(sdk.Coins(nil), keeper.GetAllBalances(ctx, baseAcc.GetAddress())) + suite.Require().Equal(sdk.NewCoins().String(), keeper.GetAllBalances(ctx, baseAcc.GetAddress()).String()) suite.Require().Equal(initCoins, getCoinsByName(ctx, keeper, authKeeper, authtypes.Burner)) } @@ -132,8 +137,16 @@ func (suite *IntegrationTestSuite) TestInactiveAddrOfSendCoins() { app.GetSubspace(types.ModuleName), make(map[string]bool), ) - suite.Require().NoError(keeper.SetBalances(ctx, holderAcc.GetAddress(), initCoins)) - keeper.SetSupply(ctx, types.NewSupply(initCoins)) + // set initial balances + suite. + Require(). + NoError(keeper.MintCoins(ctx, minttypes.ModuleName, initCoins)) + + suite. + Require(). + NoError(keeper.SendCoinsFromModuleToAccount(ctx, minttypes.ModuleName, holderAcc.GetAddress(), initCoins)) + + suite.Require().NoError(keeper.MintCoins(ctx, minttypes.ModuleName, initCoins)) suite.Require().Equal(initCoins, keeper.GetAllBalances(ctx, holderAcc.GetAddress())) suite.Require().False(keeper.IsInactiveAddr(blockedAcc.GetAddress())) @@ -151,7 +164,7 @@ func (suite *IntegrationTestSuite) TestInactiveAddrOfSendCoins() { suite.Require().False(keeper.IsInactiveAddr(blockedAcc.GetAddress())) suite.Require().NoError(keeper.SendCoins(ctx, holderAcc.GetAddress(), blockedAcc.GetAddress(), initCoins)) - suite.Require().Equal(sdk.Coins(nil), keeper.GetAllBalances(ctx, holderAcc.GetAddress())) + suite.Require().Equal(sdk.NewCoins().String(), keeper.GetAllBalances(ctx, holderAcc.GetAddress()).String()) } func (suite *IntegrationTestSuite) TestInitializeBankPlus() { diff --git a/x/bankplus/module.go b/x/bankplus/module.go index 7c140cb89a..28a6aa82f9 100644 --- a/x/bankplus/module.go +++ b/x/bankplus/module.go @@ -18,7 +18,7 @@ type AppModule struct { bankKeeper bankkeeper.Keeper } -func NewAppModule(cdc codec.Marshaler, keeper bankkeeper.Keeper, accountKeeper accountkeeper.AccountKeeper) AppModule { +func NewAppModule(cdc codec.Codec, keeper bankkeeper.Keeper, accountKeeper accountkeeper.AccountKeeper) AppModule { return AppModule{ AppModule: bank.NewAppModule(cdc, keeper, accountKeeper), bankKeeper: keeper, diff --git a/x/capability/abci.go b/x/capability/abci.go new file mode 100644 index 0000000000..5c90683a2f --- /dev/null +++ b/x/capability/abci.go @@ -0,0 +1,21 @@ +package capability + +import ( + "time" + + "github.com/line/lbm-sdk/telemetry" + sdk "github.com/line/lbm-sdk/types" + "github.com/line/lbm-sdk/x/capability/keeper" + "github.com/line/lbm-sdk/x/capability/types" +) + +// BeginBlocker will call InitMemStore to initialize the memory stores in the case +// that this is the first time the node is executing a block since restarting (wiping memory). +// In this case, the BeginBlocker method will reinitialize the memory stores locally, so that subsequent +// capability transactions will pass. +// Otherwise BeginBlocker performs a no-op. +func BeginBlocker(ctx sdk.Context, k keeper.Keeper) { + defer telemetry.ModuleMeasureSince(types.ModuleName, time.Now(), telemetry.MetricKeyBeginBlocker) + + k.InitMemStore(ctx) +} diff --git a/x/capability/capability_test.go b/x/capability/capability_test.go index 3368d46fed..f07cf87580 100644 --- a/x/capability/capability_test.go +++ b/x/capability/capability_test.go @@ -3,10 +3,11 @@ package capability_test import ( "testing" - abci "github.com/line/ostracon/abci/types" - osproto "github.com/line/ostracon/proto/ostracon/types" "github.com/stretchr/testify/suite" + abci "github.com/line/ostracon/abci/types" + ocproto "github.com/line/ostracon/proto/ostracon/types" + "github.com/line/lbm-sdk/codec" "github.com/line/lbm-sdk/simapp" sdk "github.com/line/lbm-sdk/types" @@ -20,7 +21,7 @@ import ( type CapabilityTestSuite struct { suite.Suite - cdc codec.Marshaler + cdc codec.Codec ctx sdk.Context app *simapp.SimApp keeper *keeper.Keeper @@ -36,7 +37,7 @@ func (suite *CapabilityTestSuite) SetupTest() { keeper := keeper.NewKeeper(cdc, app.GetKey(types.StoreKey), app.GetMemKey(types.MemStoreKey)) suite.app = app - suite.ctx = app.BaseApp.NewContext(checkTx, osproto.Header{Height: 1}) + suite.ctx = app.BaseApp.NewContext(checkTx, ocproto.Header{Height: 1}) suite.keeper = keeper suite.cdc = cdc suite.module = capability.NewAppModule(cdc, *keeper) @@ -52,16 +53,16 @@ func (suite *CapabilityTestSuite) TestInitializeMemStore() { suite.Require().NotNil(cap1) // mock statesync by creating new keeper that shares persistent state but loses in-memory map - newKeeper := keeper.NewKeeper(suite.cdc, suite.app.GetKey(types.StoreKey), suite.app.GetMemKey("testing")) + newKeeper := keeper.NewKeeper(suite.cdc, suite.app.GetKey(types.StoreKey), suite.app.GetMemKey("testingkey")) newSk1 := newKeeper.ScopeToModule(banktypes.ModuleName) // Mock App startup - ctx := suite.app.BaseApp.NewUncachedContext(false, osproto.Header{}) - newKeeper.InitializeAndSeal(ctx) + ctx := suite.app.BaseApp.NewUncachedContext(false, ocproto.Header{}) + newKeeper.Seal() suite.Require().False(newKeeper.IsInitialized(ctx), "memstore initialized flag set before BeginBlock") // Mock app beginblock and ensure that no gas has been consumed and memstore is initialized - ctx = suite.app.BaseApp.NewContext(false, osproto.Header{}).WithBlockGasMeter(sdk.NewGasMeter(50)) + ctx = suite.app.BaseApp.NewContext(false, ocproto.Header{}).WithBlockGasMeter(sdk.NewGasMeter(50)) prevGas := ctx.BlockGasMeter().GasConsumed() restartedModule := capability.NewAppModule(suite.cdc, *newKeeper) restartedModule.BeginBlock(ctx, abci.RequestBeginBlock{}) @@ -77,7 +78,7 @@ func (suite *CapabilityTestSuite) TestInitializeMemStore() { suite.Require().True(ok) // Ensure that the second transaction can still receive capability even if first tx fails. - ctx = suite.app.BaseApp.NewContext(false, osproto.Header{}) + ctx = suite.app.BaseApp.NewContext(false, ocproto.Header{}) cap1, ok = newSk1.GetCapability(ctx, "transfer") suite.Require().True(ok) diff --git a/x/capability/genesis_test.go b/x/capability/genesis_test.go index f953b60521..f58acde452 100644 --- a/x/capability/genesis_test.go +++ b/x/capability/genesis_test.go @@ -2,7 +2,7 @@ package capability_test import ( "github.com/line/ostracon/libs/log" - osproto "github.com/line/ostracon/proto/ostracon/types" + ocproto "github.com/line/ostracon/proto/ostracon/types" memdb "github.com/line/tm-db/v2/memdb" "github.com/line/lbm-sdk/simapp" @@ -40,7 +40,7 @@ func (suite *CapabilityTestSuite) TestGenesis() { newKeeper := keeper.NewKeeper(suite.cdc, newApp.GetKey(types.StoreKey), newApp.GetMemKey(types.MemStoreKey)) newSk1 := newKeeper.ScopeToModule(banktypes.ModuleName) newSk2 := newKeeper.ScopeToModule(stakingtypes.ModuleName) - deliverCtx, _ := newApp.BaseApp.NewUncachedContext(false, osproto.Header{}).WithBlockGasMeter(sdk.NewInfiniteGasMeter()).CacheContext() + deliverCtx, _ := newApp.BaseApp.NewUncachedContext(false, ocproto.Header{}).WithBlockGasMeter(sdk.NewInfiniteGasMeter()).CacheContext() capability.InitGenesis(deliverCtx, *newKeeper, *genState) diff --git a/x/capability/keeper/keeper.go b/x/capability/keeper/keeper.go index b391929e4c..e16b2c1a1b 100644 --- a/x/capability/keeper/keeper.go +++ b/x/capability/keeper/keeper.go @@ -27,7 +27,7 @@ type ( // The keeper allows the ability to create scoped sub-keepers which are tied to // a single specific module. Keeper struct { - cdc codec.BinaryMarshaler + cdc codec.BinaryCodec storeKey sdk.StoreKey memKey sdk.StoreKey capMap map[uint64]*types.Capability @@ -42,7 +42,7 @@ type ( // by name, in addition to creating new capabilities & authenticating capabilities // passed by other modules. ScopedKeeper struct { - cdc codec.BinaryMarshaler + cdc codec.BinaryCodec storeKey sdk.StoreKey memKey sdk.StoreKey capMap map[uint64]*types.Capability @@ -52,7 +52,7 @@ type ( // NewKeeper constructs a new CapabilityKeeper instance and initializes maps // for capability map and scopedModules map. -func NewKeeper(cdc codec.BinaryMarshaler, storeKey, memKey sdk.StoreKey) *Keeper { +func NewKeeper(cdc codec.BinaryCodec, storeKey, memKey sdk.StoreKey) *Keeper { return &Keeper{ cdc: cdc, storeKey: storeKey, @@ -89,9 +89,9 @@ func (k *Keeper) ScopeToModule(moduleName string) ScopedKeeper { } } -// InitializeAndSeal seals the keeper to prevent further modules from creating -// a scoped keeper. It also panics if the memory store is not of storetype `StoreTypeMemory`. -func (k *Keeper) InitializeAndSeal(ctx sdk.Context) { +// Seal seals the keeper to prevent further modules from creating a scoped keeper. +// Seal may be called during app initialization for applications that do not wish to create scoped keepers dynamically. +func (k *Keeper) Seal() { if k.sealed { panic("cannot initialize and seal an already sealed capability keeper") } @@ -99,22 +99,21 @@ func (k *Keeper) InitializeAndSeal(ctx sdk.Context) { k.sealed = true } -// InitMemStore will initialize the memory store if it hasn't been initialized yet. -// The function is safe to be called multiple times. +// InitMemStore will assure that the module store is a memory store (it will panic if it's not) +// and willl initialize it. The function is safe to be called multiple times. // InitMemStore must be called every time the app starts before the keeper is used (so // `BeginBlock` or `InitChain` - whichever is first). We need access to the store so we // can't initialize it in a constructor. func (k *Keeper) InitMemStore(ctx sdk.Context) { - // create context with no block gas meter to ensure we do not consume gas during local initialization logic. - noGasCtx := ctx.WithBlockGasMeter(sdk.NewInfiniteGasMeter()) - - memStore := noGasCtx.KVStore(k.memKey) + memStore := ctx.KVStore(k.memKey) memStoreType := memStore.GetStoreType() - if memStoreType != sdk.StoreTypeMemory { panic(fmt.Sprintf("invalid memory store type; got %s, expected: %s", memStoreType, sdk.StoreTypeMemory)) } + // create context with no block gas meter to ensure we do not consume gas during local initialization logic. + noGasCtx := ctx.WithBlockGasMeter(sdk.NewInfiniteGasMeter()) + // check if memory store has not been initialized yet by checking if initialized flag is nil. if !k.IsInitialized(noGasCtx) { prefixStore := prefix.NewStore(noGasCtx.KVStore(k.storeKey), types.KeyPrefixIndexCapability) @@ -128,16 +127,17 @@ func (k *Keeper) InitMemStore(ctx sdk.Context) { var capOwners types.CapabilityOwners - k.cdc.MustUnmarshalBinaryBare(iterator.Value(), &capOwners) + k.cdc.MustUnmarshal(iterator.Value(), &capOwners) k.InitializeCapability(noGasCtx, index, capOwners) } // set the initialized flag so we don't rerun initialization logic + memStore := noGasCtx.KVStore(k.memKey) memStore.Set(types.KeyMemInitialized, []byte{1}) } } -// IsInitialized returns true if the keeper is properly initialized, and false otherwise +// IsInitialized returns true if the keeper is properly initialized, and false otherwise. func (k *Keeper) IsInitialized(ctx sdk.Context) bool { memStore := ctx.KVStore(k.memKey) return memStore.Get(types.KeyMemInitialized) != nil @@ -173,7 +173,7 @@ func (k Keeper) SetOwners(ctx sdk.Context, index uint64, owners types.Capability indexKey := types.IndexToKey(index) // set owners in persistent store - prefixStore.Set(indexKey, k.cdc.MustMarshalBinaryBare(&owners)) + prefixStore.Set(indexKey, k.cdc.MustMarshal(&owners)) } // GetOwners returns the capability owners with a given index. @@ -187,7 +187,7 @@ func (k Keeper) GetOwners(ctx sdk.Context, index uint64) (types.CapabilityOwners return types.CapabilityOwners{}, false } var owners types.CapabilityOwners - k.cdc.MustUnmarshalBinaryBare(ownerBytes, &owners) + k.cdc.MustUnmarshal(ownerBytes, &owners) return owners, true } @@ -352,7 +352,7 @@ func (sk ScopedKeeper) ReleaseCapability(ctx sdk.Context, cap *types.Capability) delete(sk.capMap, cap.GetIndex()) } else { // update capability owner set - prefixStore.Set(indexKey, sk.cdc.MustMarshalBinaryBare(capOwners)) + prefixStore.Set(indexKey, sk.cdc.MustMarshal(capOwners)) } return nil @@ -422,7 +422,7 @@ func (sk ScopedKeeper) GetOwners(ctx sdk.Context, name string) (*types.Capabilit return nil, false } - sk.cdc.MustUnmarshalBinaryBare(bz, &capOwners) + sk.cdc.MustUnmarshal(bz, &capOwners) return &capOwners, true } @@ -464,7 +464,7 @@ func (sk ScopedKeeper) addOwner(ctx sdk.Context, cap *types.Capability, name str } // update capability owner set - prefixStore.Set(indexKey, sk.cdc.MustMarshalBinaryBare(capOwners)) + prefixStore.Set(indexKey, sk.cdc.MustMarshal(capOwners)) return nil } @@ -480,7 +480,7 @@ func (sk ScopedKeeper) getOwners(ctx sdk.Context, cap *types.Capability) *types. } var capOwners types.CapabilityOwners - sk.cdc.MustUnmarshalBinaryBare(bz, &capOwners) + sk.cdc.MustUnmarshal(bz, &capOwners) return &capOwners } diff --git a/x/capability/keeper/keeper_test.go b/x/capability/keeper/keeper_test.go index 27ba15bfd2..2d7b095a4a 100644 --- a/x/capability/keeper/keeper_test.go +++ b/x/capability/keeper/keeper_test.go @@ -19,7 +19,7 @@ import ( type KeeperTestSuite struct { suite.Suite - cdc codec.Marshaler + cdc codec.Codec ctx sdk.Context app *simapp.SimApp keeper *keeper.Keeper @@ -39,7 +39,7 @@ func (suite *KeeperTestSuite) SetupTest() { suite.cdc = cdc } -func (suite *KeeperTestSuite) TestInitializeAndSeal() { +func (suite *KeeperTestSuite) TestSeal() { sk := suite.keeper.ScopeToModule(banktypes.ModuleName) suite.Require().Panics(func() { suite.keeper.ScopeToModule(" ") @@ -59,7 +59,7 @@ func (suite *KeeperTestSuite) TestInitializeAndSeal() { } suite.Require().NotPanics(func() { - suite.keeper.InitializeAndSeal(suite.ctx) + suite.keeper.Seal() }) for i, cap := range caps { @@ -70,7 +70,7 @@ func (suite *KeeperTestSuite) TestInitializeAndSeal() { } suite.Require().Panics(func() { - suite.keeper.InitializeAndSeal(suite.ctx) + suite.keeper.Seal() }) suite.Require().Panics(func() { diff --git a/x/capability/module.go b/x/capability/module.go index 48cc8fe46d..3b3db64f96 100644 --- a/x/capability/module.go +++ b/x/capability/module.go @@ -36,10 +36,10 @@ var ( // AppModuleBasic implements the AppModuleBasic interface for the capability module. type AppModuleBasic struct { - cdc codec.Marshaler + cdc codec.Codec } -func NewAppModuleBasic(cdc codec.Marshaler) AppModuleBasic { +func NewAppModuleBasic(cdc codec.Codec) AppModuleBasic { return AppModuleBasic{cdc: cdc} } @@ -55,12 +55,12 @@ func (AppModuleBasic) RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) {} func (a AppModuleBasic) RegisterInterfaces(_ cdctypes.InterfaceRegistry) {} // DefaultGenesis returns the capability module's default genesis state. -func (AppModuleBasic) DefaultGenesis(cdc codec.JSONMarshaler) json.RawMessage { +func (AppModuleBasic) DefaultGenesis(cdc codec.JSONCodec) json.RawMessage { return cdc.MustMarshalJSON(types.DefaultGenesis()) } // ValidateGenesis performs genesis state validation for the capability module. -func (AppModuleBasic) ValidateGenesis(cdc codec.JSONMarshaler, config client.TxEncodingConfig, bz json.RawMessage) error { +func (AppModuleBasic) ValidateGenesis(cdc codec.JSONCodec, config client.TxEncodingConfig, bz json.RawMessage) error { var genState types.GenesisState if err := cdc.UnmarshalJSON(bz, &genState); err != nil { return fmt.Errorf("failed to unmarshal %s genesis state: %w", types.ModuleName, err) @@ -92,7 +92,7 @@ type AppModule struct { keeper keeper.Keeper } -func NewAppModule(cdc codec.Marshaler, keeper keeper.Keeper) AppModule { +func NewAppModule(cdc codec.Codec, keeper keeper.Keeper) AppModule { return AppModule{ AppModuleBasic: NewAppModuleBasic(cdc), keeper: keeper, @@ -127,7 +127,7 @@ func (am AppModule) RegisterInvariants(_ sdk.InvariantRegistry) {} // InitGenesis performs the capability module's genesis initialization It returns // no validator updates. -func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONMarshaler, gs json.RawMessage) []abci.ValidatorUpdate { +func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONCodec, gs json.RawMessage) []abci.ValidatorUpdate { var genState types.GenesisState // Initialize global index to index in genesis state cdc.MustUnmarshalJSON(gs, &genState) @@ -138,7 +138,7 @@ func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONMarshaler, gs jso } // ExportGenesis returns the capability module's exported genesis state as raw JSON bytes. -func (am AppModule) ExportGenesis(ctx sdk.Context, cdc codec.JSONMarshaler) json.RawMessage { +func (am AppModule) ExportGenesis(ctx sdk.Context, cdc codec.JSONCodec) json.RawMessage { genState := ExportGenesis(ctx, am.keeper) return cdc.MustMarshalJSON(genState) } @@ -146,11 +146,8 @@ func (am AppModule) ExportGenesis(ctx sdk.Context, cdc codec.JSONMarshaler) json // ConsensusVersion implements AppModule/ConsensusVersion. func (AppModule) ConsensusVersion() uint64 { return 1 } -// BeginBlocker will call InitMemStore to initialize the memory stores in the case -// that this is the first time the node is executing a block since restarting (wiping memory). -// In this case, the BeginBlocker method will reinitialize the memory stores locally, so that subsequent -// capability transactions will pass. -// Otherwise BeginBlocker performs a no-op. +// BeginBlocker calls InitMemStore to assert that the memory store is initialized. +// It's safe to run multiple times. func (am AppModule) BeginBlock(ctx sdk.Context, _ abci.RequestBeginBlock) { defer telemetry.ModuleMeasureSince(types.ModuleName, time.Now(), telemetry.MetricKeyBeginBlocker) diff --git a/x/capability/simulation/decoder.go b/x/capability/simulation/decoder.go index 4a84b2ea3a..a0f4e4ec42 100644 --- a/x/capability/simulation/decoder.go +++ b/x/capability/simulation/decoder.go @@ -12,7 +12,7 @@ import ( // NewDecodeStore returns a decoder function closure that unmarshals the KVPair's // Value to the corresponding capability type. -func NewDecodeStore(cdc codec.Marshaler) func(kvA, kvB kv.Pair) string { +func NewDecodeStore(cdc codec.Codec) func(kvA, kvB kv.Pair) string { return func(kvA, kvB kv.Pair) string { switch { case bytes.Equal(kvA.Key, types.KeyIndex): @@ -22,8 +22,8 @@ func NewDecodeStore(cdc codec.Marshaler) func(kvA, kvB kv.Pair) string { case bytes.HasPrefix(kvA.Key, types.KeyPrefixIndexCapability): var capOwnersA, capOwnersB types.CapabilityOwners - cdc.MustUnmarshalBinaryBare(kvA.Value, &capOwnersA) - cdc.MustUnmarshalBinaryBare(kvB.Value, &capOwnersB) + cdc.MustUnmarshal(kvA.Value, &capOwnersA) + cdc.MustUnmarshal(kvB.Value, &capOwnersB) return fmt.Sprintf("CapabilityOwners A: %v\nCapabilityOwners B: %v\n", capOwnersA, capOwnersB) default: diff --git a/x/capability/simulation/decoder_test.go b/x/capability/simulation/decoder_test.go index a5bd50b3e1..369ff2a6a7 100644 --- a/x/capability/simulation/decoder_test.go +++ b/x/capability/simulation/decoder_test.go @@ -14,7 +14,7 @@ import ( ) func TestDecodeStore(t *testing.T) { - cdc, _ := simapp.MakeCodecs() + cdc := simapp.MakeTestEncodingConfig().Marshaler dec := simulation.NewDecodeStore(cdc) capOwners := types.CapabilityOwners{ @@ -29,7 +29,7 @@ func TestDecodeStore(t *testing.T) { }, { Key: types.KeyPrefixIndexCapability, - Value: cdc.MustMarshalBinaryBare(&capOwners), + Value: cdc.MustMarshal(&capOwners), }, { Key: []byte{0x99}, diff --git a/x/consortium/client/testutil/cli_test.go b/x/consortium/client/testutil/cli_test.go index a0d9d3381c..f979202abe 100644 --- a/x/consortium/client/testutil/cli_test.go +++ b/x/consortium/client/testutil/cli_test.go @@ -1,3 +1,4 @@ +//go:build norace // +build norace package testutil diff --git a/x/consortium/keeper/grpc_query.go b/x/consortium/keeper/grpc_query.go index 092b2ad6ed..9abd14e9c7 100644 --- a/x/consortium/keeper/grpc_query.go +++ b/x/consortium/keeper/grpc_query.go @@ -65,7 +65,7 @@ func (s queryServer) ValidatorAuths(c context.Context, req *consortium.QueryVali validatorStore := prefix.NewStore(store, validatorAuthKeyPrefix) pageRes, err := query.Paginate(validatorStore, req.Pagination, func(key []byte, value []byte) error { var auth consortium.ValidatorAuth - s.keeper.cdc.MustUnmarshalBinaryBare(value, &auth) + s.keeper.cdc.MustUnmarshal(value, &auth) auths = append(auths, &auth) return nil }) diff --git a/x/consortium/keeper/keeper.go b/x/consortium/keeper/keeper.go index 7b7ff287d2..a8f743540a 100644 --- a/x/consortium/keeper/keeper.go +++ b/x/consortium/keeper/keeper.go @@ -16,7 +16,7 @@ type Keeper struct { storeKey sdk.StoreKey // The codec for binary encoding/decoding. - cdc codec.BinaryMarshaler + cdc codec.Codec } // NewKeeper returns a consortium keeper. It handles: @@ -24,7 +24,7 @@ type Keeper struct { // // CONTRACT: the parameter Subspace must have the param key table already initialized func NewKeeper( - cdc codec.BinaryMarshaler, + cdc codec.Codec, key sdk.StoreKey, stakingKeeper consortium.StakingKeeper, ) Keeper { diff --git a/x/consortium/keeper/params.go b/x/consortium/keeper/params.go index 4e1570fee6..3d572a86df 100644 --- a/x/consortium/keeper/params.go +++ b/x/consortium/keeper/params.go @@ -11,13 +11,13 @@ func (k Keeper) GetParams(ctx sdk.Context) *consortium.Params { bz := store.Get(key) var params consortium.Params - k.cdc.MustUnmarshalBinaryBare(bz, ¶ms) + k.cdc.MustUnmarshal(bz, ¶ms) return ¶ms } func (k Keeper) SetParams(ctx sdk.Context, params *consortium.Params) { - bz := k.cdc.MustMarshalBinaryBare(params) + bz := k.cdc.MustMarshal(params) store := ctx.KVStore(k.storeKey) key := paramsKey diff --git a/x/consortium/keeper/validator.go b/x/consortium/keeper/validator.go index 52efb8b03b..fb05e6eccc 100644 --- a/x/consortium/keeper/validator.go +++ b/x/consortium/keeper/validator.go @@ -15,7 +15,7 @@ func (k Keeper) GetValidatorAuth(ctx sdk.Context, valAddr sdk.ValAddress) (*cons } var auth consortium.ValidatorAuth - if err := k.cdc.UnmarshalBinaryBare(bz, &auth); err != nil { + if err := k.cdc.Unmarshal(bz, &auth); err != nil { return nil, err } @@ -26,7 +26,7 @@ func (k Keeper) SetValidatorAuth(ctx sdk.Context, auth *consortium.ValidatorAuth store := ctx.KVStore(k.storeKey) key := validatorAuthKey(sdk.ValAddress(auth.OperatorAddress)) - bz, err := k.cdc.MarshalBinaryBare(auth) + bz, err := k.cdc.Marshal(auth) if err != nil { return err } @@ -46,7 +46,7 @@ func (k Keeper) IterateValidatorAuths(ctx sdk.Context, cb func(auth consortium.V defer iter.Close() for ; iter.Valid(); iter.Next() { var auth consortium.ValidatorAuth - k.cdc.MustUnmarshalBinaryBare(iter.Value(), &auth) + k.cdc.MustUnmarshal(iter.Value(), &auth) if cb(auth) { break } diff --git a/x/consortium/module/module.go b/x/consortium/module/module.go index dd4d3b491f..e583e8ef62 100644 --- a/x/consortium/module/module.go +++ b/x/consortium/module/module.go @@ -27,7 +27,7 @@ var ( // AppModuleBasic defines the basic application module used by the consortium module. type AppModuleBasic struct { - cdc codec.Marshaler + cdc codec.Codec } // NewAppModuleBasic creates a new AppModuleBasic object @@ -45,12 +45,12 @@ func (AppModuleBasic) RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) {} // DefaultGenesis returns default genesis state as raw bytes for the consortium // module. -func (AppModuleBasic) DefaultGenesis(cdc codec.JSONMarshaler) json.RawMessage { +func (AppModuleBasic) DefaultGenesis(cdc codec.JSONCodec) json.RawMessage { return cdc.MustMarshalJSON(consortium.DefaultGenesisState()) } // ValidateGenesis performs genesis state validation for the consortium module. -func (AppModuleBasic) ValidateGenesis(cdc codec.JSONMarshaler, config client.TxEncodingConfig, bz json.RawMessage) error { +func (AppModuleBasic) ValidateGenesis(cdc codec.JSONCodec, config client.TxEncodingConfig, bz json.RawMessage) error { var data consortium.GenesisState if err := cdc.UnmarshalJSON(bz, &data); err != nil { return fmt.Errorf("failed to unmarshal %s genesis state: %w", consortium.ModuleName, err) @@ -94,7 +94,7 @@ type AppModule struct { } // NewAppModule creates a new AppModule object -func NewAppModule(cdc codec.Marshaler, keeper keeper.Keeper, stk consortium.StakingKeeper) AppModule { +func NewAppModule(cdc codec.Codec, keeper keeper.Keeper, stk consortium.StakingKeeper) AppModule { return AppModule{ AppModuleBasic: AppModuleBasic{cdc: cdc}, keeper: keeper, @@ -129,7 +129,7 @@ func (am AppModule) RegisterServices(cfg module.Configurator) { // InitGenesis performs genesis initialization for the consortium module. It returns // no validator updates. -func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONMarshaler, data json.RawMessage) []abci.ValidatorUpdate { +func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONCodec, data json.RawMessage) []abci.ValidatorUpdate { var genesisState consortium.GenesisState cdc.MustUnmarshalJSON(data, &genesisState) am.keeper.InitGenesis(ctx, am.stakingKeeper, &genesisState) @@ -138,7 +138,7 @@ func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONMarshaler, data j // ExportGenesis returns the exported genesis state as raw bytes for the consortium // module. -func (am AppModule) ExportGenesis(ctx sdk.Context, cdc codec.JSONMarshaler) json.RawMessage { +func (am AppModule) ExportGenesis(ctx sdk.Context, cdc codec.JSONCodec) json.RawMessage { gs := am.keeper.ExportGenesis(ctx) return cdc.MustMarshalJSON(gs) } diff --git a/x/consortium/query.pb.gw.go b/x/consortium/query.pb.gw.go index 85c9137ba8..5acb036476 100644 --- a/x/consortium/query.pb.gw.go +++ b/x/consortium/query.pb.gw.go @@ -310,11 +310,11 @@ func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, clie } var ( - pattern_Query_Params_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"lbm", "consortium", "v1", "params"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_Query_Params_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"lbm", "consortium", "v1", "params"}, "", runtime.AssumeColonVerbOpt(false))) - pattern_Query_ValidatorAuth_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4}, []string{"lbm", "consortium", "v1", "validators", "validator_address"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_Query_ValidatorAuth_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4}, []string{"lbm", "consortium", "v1", "validators", "validator_address"}, "", runtime.AssumeColonVerbOpt(false))) - pattern_Query_ValidatorAuths_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"lbm", "consortium", "v1", "validators"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_Query_ValidatorAuths_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"lbm", "consortium", "v1", "validators"}, "", runtime.AssumeColonVerbOpt(false))) ) var ( diff --git a/x/crisis/client/cli/tx.go b/x/crisis/client/cli/tx.go index c02ae0be57..5ce87a8c92 100644 --- a/x/crisis/client/cli/tx.go +++ b/x/crisis/client/cli/tx.go @@ -49,9 +49,6 @@ func NewMsgVerifyInvariantTxCmd() *cobra.Command { senderAddr := clientCtx.GetFromAddress() msg := types.NewMsgVerifyInvariant(senderAddr, moduleName, route) - if err := msg.ValidateBasic(); err != nil { - return err - } return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) }, diff --git a/x/crisis/client/testsuite/cli_test.go b/x/crisis/client/testsuite/cli_test.go new file mode 100644 index 0000000000..f979202abe --- /dev/null +++ b/x/crisis/client/testsuite/cli_test.go @@ -0,0 +1,18 @@ +//go:build norace +// +build norace + +package testutil + +import ( + "testing" + + "github.com/stretchr/testify/suite" + + "github.com/line/lbm-sdk/testutil/network" +) + +func TestIntegrationTestSuite(t *testing.T) { + cfg := network.DefaultConfig() + cfg.NumValidators = 1 + suite.Run(t, NewIntegrationTestSuite(cfg)) +} diff --git a/x/crisis/client/cli/cli_test.go b/x/crisis/client/testsuite/suite.go similarity index 86% rename from x/crisis/client/cli/cli_test.go rename to x/crisis/client/testsuite/suite.go index c649ee6a16..94a1d73b62 100644 --- a/x/crisis/client/cli/cli_test.go +++ b/x/crisis/client/testsuite/suite.go @@ -1,10 +1,7 @@ -// +build norace - -package cli_test +package testutil import ( "fmt" - "testing" "github.com/gogo/protobuf/proto" "github.com/stretchr/testify/suite" @@ -23,15 +20,14 @@ type IntegrationTestSuite struct { network *network.Network } +func NewIntegrationTestSuite(cfg network.Config) *IntegrationTestSuite { + return &IntegrationTestSuite{cfg: cfg} +} + func (s *IntegrationTestSuite) SetupSuite() { s.T().Log("setting up integration test suite") - cfg := network.DefaultConfig() - cfg.NumValidators = 1 - - s.cfg = cfg - s.network = network.New(s.T(), cfg) - + s.network = network.New(s.T(), s.cfg) _, err := s.network.WaitForHeight(1) s.Require().NoError(err) } @@ -48,8 +44,8 @@ func (s *IntegrationTestSuite) TestNewMsgVerifyInvariantTxCmd() { name string args []string expectErr bool - respType proto.Message expectedCode uint32 + respType proto.Message }{ { "missing module", @@ -60,7 +56,7 @@ func (s *IntegrationTestSuite) TestNewMsgVerifyInvariantTxCmd() { fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), }, - true, nil, 0, + true, 0, nil, }, { "missing invariant route", @@ -71,7 +67,7 @@ func (s *IntegrationTestSuite) TestNewMsgVerifyInvariantTxCmd() { fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), }, - true, nil, 0, + true, 0, nil, }, { "valid transaction", @@ -82,7 +78,7 @@ func (s *IntegrationTestSuite) TestNewMsgVerifyInvariantTxCmd() { fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), }, - false, &sdk.TxResponse{}, 0, + false, 0, &sdk.TxResponse{}, }, } @@ -98,7 +94,7 @@ func (s *IntegrationTestSuite) TestNewMsgVerifyInvariantTxCmd() { s.Require().Error(err) } else { s.Require().NoError(err) - s.Require().NoError(clientCtx.JSONMarshaler.UnmarshalJSON(out.Bytes(), tc.respType), out.String()) + s.Require().NoError(clientCtx.Codec.UnmarshalJSON(out.Bytes(), tc.respType), out.String()) txResp := tc.respType.(*sdk.TxResponse) s.Require().Equal(tc.expectedCode, txResp.Code) @@ -106,7 +102,3 @@ func (s *IntegrationTestSuite) TestNewMsgVerifyInvariantTxCmd() { }) } } - -func TestIntegrationTestSuite(t *testing.T) { - suite.Run(t, new(IntegrationTestSuite)) -} diff --git a/x/crisis/handler_test.go b/x/crisis/handler_test.go index c46844ef5a..81ad99befe 100644 --- a/x/crisis/handler_test.go +++ b/x/crisis/handler_test.go @@ -4,15 +4,12 @@ import ( "fmt" "testing" - "github.com/line/ostracon/libs/log" ocproto "github.com/line/ostracon/proto/ostracon/types" - "github.com/line/tm-db/v2/memdb" "github.com/stretchr/testify/require" "github.com/line/lbm-sdk/simapp" "github.com/line/lbm-sdk/testutil/testdata" sdk "github.com/line/lbm-sdk/types" - banktypes "github.com/line/lbm-sdk/x/bank/types" "github.com/line/lbm-sdk/x/crisis" "github.com/line/lbm-sdk/x/crisis/types" distrtypes "github.com/line/lbm-sdk/x/distribution/types" @@ -26,9 +23,8 @@ var ( ) func createTestApp() (*simapp.SimApp, sdk.Context, []sdk.AccAddress) { - db := memdb.NewDB() - app := simapp.NewSimApp(log.NewNopLogger(), db, nil, true, map[int64]bool{}, simapp.DefaultNodeHome, 1, simapp.MakeTestEncodingConfig(), simapp.EmptyAppOptions{}) - ctx := app.NewContext(true, ocproto.Header{}) + app := simapp.Setup(false) + ctx := app.NewContext(false, ocproto.Header{}) constantFee := sdk.NewInt64Coin(sdk.DefaultBondDenom, 10) app.CrisisKeeper.SetConstantFee(ctx, constantFee) @@ -40,15 +36,12 @@ func createTestApp() (*simapp.SimApp, sdk.Context, []sdk.AccAddress) { feePool := distrtypes.InitialFeePool() feePool.CommunityPool = sdk.NewDecCoinsFromCoins(sdk.NewCoins(constantFee)...) app.DistrKeeper.SetFeePool(ctx, feePool) - app.BankKeeper.SetSupply(ctx, banktypes.NewSupply(sdk.Coins{})) addrs := simapp.AddTestAddrs(app, ctx, 1, sdk.NewInt(10000)) return app, ctx, addrs } -// ____________________________________________________________________________ - func TestHandleMsgVerifyInvariant(t *testing.T) { app, ctx, addrs := createTestApp() sender := addrs[0] diff --git a/x/crisis/keeper/keeper.go b/x/crisis/keeper/keeper.go index 85d6ef37b5..7c7db996b0 100644 --- a/x/crisis/keeper/keeper.go +++ b/x/crisis/keeper/keeper.go @@ -14,7 +14,7 @@ import ( // Keeper - crisis keeper type Keeper struct { routes []types.InvarRoute - paramSpace *paramtypes.Subspace + paramSpace paramtypes.Subspace invCheckPeriod uint supplyKeeper types.SupplyKeeper @@ -24,7 +24,7 @@ type Keeper struct { // NewKeeper creates a new Keeper object func NewKeeper( - paramSpace *paramtypes.Subspace, invCheckPeriod uint, supplyKeeper types.SupplyKeeper, + paramSpace paramtypes.Subspace, invCheckPeriod uint, supplyKeeper types.SupplyKeeper, feeCollectorName string, ) Keeper { diff --git a/x/crisis/keeper/msg_server.go b/x/crisis/keeper/msg_server.go index 514ac73268..a16a2817db 100644 --- a/x/crisis/keeper/msg_server.go +++ b/x/crisis/keeper/msg_server.go @@ -39,20 +39,8 @@ func (k Keeper) VerifyInvariant(goCtx context.Context, msg *types.MsgVerifyInvar } if stop { - // NOTE currently, because the chain halts here, this transaction will never be included - // in the blockchain thus the constant fee will have never been deducted. Thus no - // refund is required. - - // TODO uncomment the following code block with implementation of the circuit breaker - // // refund constant fee - // err := k.distrKeeper.DistributeFromFeePool(ctx, constantFee, msg.Sender) - // if err != nil { - // // if there are insufficient coins to refund, log the error, - // // but still halt the chain. - // logger := ctx.Logger().With("module", "x/crisis") - // logger.Error(fmt.Sprintf( - // "WARNING: insufficient funds to allocate to sender from fee pool, err: %s", err)) - //} + // Currently, because the chain halts here, this transaction will never be included in the + // blockchain thus the constant fee will have never been deducted. Thus no refund is required. // TODO replace with circuit breaker panic(res) diff --git a/x/crisis/module.go b/x/crisis/module.go index c182335d30..fae99d394f 100644 --- a/x/crisis/module.go +++ b/x/crisis/module.go @@ -46,12 +46,12 @@ func (AppModuleBasic) RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) { // DefaultGenesis returns default genesis state as raw bytes for the crisis // module. -func (AppModuleBasic) DefaultGenesis(cdc codec.JSONMarshaler) json.RawMessage { +func (AppModuleBasic) DefaultGenesis(cdc codec.JSONCodec) json.RawMessage { return cdc.MustMarshalJSON(types.DefaultGenesisState()) } // ValidateGenesis performs genesis state validation for the crisis module. -func (AppModuleBasic) ValidateGenesis(cdc codec.JSONMarshaler, config client.TxEncodingConfig, bz json.RawMessage) error { +func (AppModuleBasic) ValidateGenesis(cdc codec.JSONCodec, config client.TxEncodingConfig, bz json.RawMessage) error { var data types.GenesisState if err := cdc.UnmarshalJSON(bz, &data); err != nil { return fmt.Errorf("failed to unmarshal %s genesis state: %w", types.ModuleName, err) @@ -80,8 +80,6 @@ func (AppModuleBasic) RegisterInterfaces(registry codectypes.InterfaceRegistry) types.RegisterInterfaces(registry) } -// ____________________________________________________________________________ - // AppModule implements an application module for the crisis module. type AppModule struct { AppModuleBasic @@ -143,7 +141,7 @@ func (am AppModule) RegisterServices(cfg module.Configurator) { // InitGenesis performs genesis initialization for the crisis module. It returns // no validator updates. -func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONMarshaler, data json.RawMessage) []abci.ValidatorUpdate { +func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONCodec, data json.RawMessage) []abci.ValidatorUpdate { start := time.Now() var genesisState types.GenesisState cdc.MustUnmarshalJSON(data, &genesisState) @@ -158,7 +156,7 @@ func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONMarshaler, data j // ExportGenesis returns the exported genesis state as raw bytes for the crisis // module. -func (am AppModule) ExportGenesis(ctx sdk.Context, cdc codec.JSONMarshaler) json.RawMessage { +func (am AppModule) ExportGenesis(ctx sdk.Context, cdc codec.JSONCodec) json.RawMessage { gs := am.keeper.ExportGenesis(ctx) return cdc.MustMarshalJSON(gs) } diff --git a/x/crisis/spec/01_state.md b/x/crisis/spec/01_state.md index 581c79dc0e..1efc7fe04f 100644 --- a/x/crisis/spec/01_state.md +++ b/x/crisis/spec/01_state.md @@ -10,9 +10,8 @@ Due to the anticipated large gas cost requirement to verify an invariant (and potential to exceed the maximum allowable block gas limit) a constant fee is used instead of the standard gas consumption method. The constant fee is intended to be larger than the anticipated gas cost of running the invariant -with the standard gas consumption method. +with the standard gas consumption method. -The ConstantFee param is held in the global params store. - - - Params: `mint/params -> legacy_amino(sdk.Coin)` +The ConstantFee param is held in the global params store. +- Params: `mint/params -> legacy_amino(sdk.Coin)` diff --git a/x/crisis/spec/02_messages.md b/x/crisis/spec/02_messages.md index 646ca08059..640d2c4615 100644 --- a/x/crisis/spec/02_messages.md +++ b/x/crisis/spec/02_messages.md @@ -5,17 +5,18 @@ order: 2 # Messages In this section we describe the processing of the crisis messages and the -corresponding updates to the state. +corresponding updates to the state. ## MsgVerifyInvariant -Blockchain invariants can be checked using the `MsgVerifyInvariant` message. +Blockchain invariants can be checked using the `MsgVerifyInvariant` message. -+++ https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/crisis/v1/tx.proto#L14-L22 ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.40.0-rc7/proto/cosmos/crisis/v1beta1/tx.proto#L14-L22 -This message is expected to fail if: - - the sender does not have enough coins for the constant fee - - the invariant route is not registered +This message is expected to fail if: + +- the sender does not have enough coins for the constant fee +- the invariant route is not registered This message checks the invariant provided, and if the invariant is broken it panics, halting the blockchain. If the invariant is broken, the constant fee is diff --git a/x/crisis/spec/05_client.md b/x/crisis/spec/05_client.md new file mode 100644 index 0000000000..5f95955a65 --- /dev/null +++ b/x/crisis/spec/05_client.md @@ -0,0 +1,31 @@ + + +# Client + +## CLI + +A user can query and interact with the `crisis` module using the CLI. + +### Transactions + +The `tx` commands allow users to interact with the `crisis` module. + +```bash +simd tx crisis --help +``` + +#### invariant-broken + +The `invariant-broken` command submits proof when an invariant was broken to halt the chain + +```bash +simd tx crisis invariant-broken [module-name] [invariant-route] [flags] +``` + +Example: + +```bash +simd tx crisis invariant-broken bank total-supply --from=[keyname or address] +``` diff --git a/x/crisis/spec/README.md b/x/crisis/spec/README.md index de75381bf1..3704da56d1 100644 --- a/x/crisis/spec/README.md +++ b/x/crisis/spec/README.md @@ -9,9 +9,9 @@ parent: ## Overview -The crisis module halts the blockchain under the circumstance that a blockchain +The crisis module halts the blockchain under the circumstance that a blockchain invariant is broken. Invariants can be registered with the application during the -application initialization process. +application initialization process. ## Contents diff --git a/x/distribution/client/cli/query.go b/x/distribution/client/cli/query.go index ff18cc2b2f..6af6dd11e3 100644 --- a/x/distribution/client/cli/query.go +++ b/x/distribution/client/cli/query.go @@ -1,7 +1,6 @@ package cli import ( - "context" "fmt" "strconv" "strings" @@ -50,7 +49,7 @@ func GetCmdQueryParams() *cobra.Command { } queryClient := types.NewQueryClient(clientCtx) - res, err := queryClient.Params(context.Background(), &types.QueryParamsRequest{}) + res, err := queryClient.Params(cmd.Context(), &types.QueryParamsRequest{}) if err != nil { return err } @@ -94,7 +93,7 @@ $ %s query distribution validator-outstanding-rewards %s1lwjmdnks33xwnmfayc64ycp } res, err := queryClient.ValidatorOutstandingRewards( - context.Background(), + cmd.Context(), &types.QueryValidatorOutstandingRewardsRequest{ValidatorAddress: args[0]}, ) if err != nil { @@ -139,7 +138,7 @@ $ %s query distribution commission %s1gghjut3ccd8ay0zduzj64hwre2fxs9ldmqhffj } res, err := queryClient.ValidatorCommission( - context.Background(), + cmd.Context(), &types.QueryValidatorCommissionRequest{ValidatorAddress: args[0]}, ) if err != nil { @@ -199,7 +198,7 @@ $ %s query distribution slashes %svaloper1gghjut3ccd8ay0zduzj64hwre2fxs9ldmqhffj } res, err := queryClient.ValidatorSlashes( - context.Background(), + cmd.Context(), &types.QueryValidatorSlashesRequest{ ValidatorAddress: args[0], StartingHeight: startHeight, @@ -252,6 +251,7 @@ $ %s query distribution rewards %s1gghjut3ccd8ay0zduzj64hwre2fxs9ld75ru9p %s1ggh } // query for rewards from a particular delegation + ctx := cmd.Context() if len(args) == 2 { err := sdk.ValidateValAddress(args[1]) if err != nil { @@ -259,7 +259,7 @@ $ %s query distribution rewards %s1gghjut3ccd8ay0zduzj64hwre2fxs9ld75ru9p %s1ggh } res, err := queryClient.DelegationRewards( - context.Background(), + ctx, &types.QueryDelegationRewardsRequest{DelegatorAddress: args[0], ValidatorAddress: args[1]}, ) if err != nil { @@ -270,7 +270,7 @@ $ %s query distribution rewards %s1gghjut3ccd8ay0zduzj64hwre2fxs9ld75ru9p %s1ggh } res, err := queryClient.DelegationTotalRewards( - context.Background(), + ctx, &types.QueryDelegationTotalRewardsRequest{DelegatorAddress: args[0]}, ) if err != nil { @@ -307,7 +307,7 @@ $ %s query distribution community-pool } queryClient := types.NewQueryClient(clientCtx) - res, err := queryClient.CommunityPool(context.Background(), &types.QueryCommunityPoolRequest{}) + res, err := queryClient.CommunityPool(cmd.Context(), &types.QueryCommunityPoolRequest{}) if err != nil { return err } diff --git a/x/distribution/client/cli/tx.go b/x/distribution/client/cli/tx.go index f7a93baaca..ce8bae5a64 100644 --- a/x/distribution/client/cli/tx.go +++ b/x/distribution/client/cli/tx.go @@ -1,7 +1,6 @@ package cli import ( - "context" "fmt" "strings" @@ -155,7 +154,7 @@ $ %[1]s tx distribution withdraw-all-rewards --from mykey } queryClient := types.NewQueryClient(clientCtx) - delValsRes, err := queryClient.DelegatorValidators(context.Background(), &types.QueryDelegatorValidatorsRequest{DelegatorAddress: delAddr.String()}) + delValsRes, err := queryClient.DelegatorValidators(cmd.Context(), &types.QueryDelegatorValidatorsRequest{DelegatorAddress: delAddr.String()}) if err != nil { return err } @@ -218,11 +217,9 @@ $ %s tx distribution set-withdraw-addr %s1gghjut3ccd8ay0zduzj64hwre2fxs9ld75ru9p if err != nil { return err } + withdrawAddr := sdk.AccAddress(args[0]) - msg := types.NewMsgSetWithdrawAddress(delAddr, sdk.AccAddress(args[0])) - if err := msg.ValidateBasic(); err != nil { - return err - } + msg := types.NewMsgSetWithdrawAddress(delAddr, withdrawAddr) return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) }, @@ -259,9 +256,6 @@ $ %s tx distribution fund-community-pool 100uatom --from mykey } msg := types.NewMsgFundCommunityPool(amount, depositorAddr) - if err := msg.ValidateBasic(); err != nil { - return err - } return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) }, @@ -305,7 +299,7 @@ Where proposal.json contains: if err != nil { return err } - proposal, err := ParseCommunityPoolSpendProposalWithDeposit(clientCtx.JSONMarshaler, args[0]) + proposal, err := ParseCommunityPoolSpendProposalWithDeposit(clientCtx.Codec, args[0]) if err != nil { return err } @@ -333,10 +327,6 @@ Where proposal.json contains: return err } - if err := msg.ValidateBasic(); err != nil { - return err - } - return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) }, } diff --git a/x/distribution/client/cli/tx_test.go b/x/distribution/client/cli/tx_test.go index ea88fb3906..0ebd639e5c 100644 --- a/x/distribution/client/cli/tx_test.go +++ b/x/distribution/client/cli/tx_test.go @@ -82,7 +82,7 @@ func TestParseProposal(t *testing.T) { { "title": "Community Pool Spend", "description": "Pay me some Atoms!", - "recipient": "cosmos1s5afhd6gxevu37mkqcvvsj8qeylhn0rz46zdlq", + "recipient": "link1s5afhd6gxevu37mkqcvvsj8qeylhn0rz46zdlq", "amount": "1000stake", "deposit": "1000stake" } @@ -93,7 +93,7 @@ func TestParseProposal(t *testing.T) { require.Equal(t, "Community Pool Spend", proposal.Title) require.Equal(t, "Pay me some Atoms!", proposal.Description) - require.Equal(t, "cosmos1s5afhd6gxevu37mkqcvvsj8qeylhn0rz46zdlq", proposal.Recipient) + require.Equal(t, "link1s5afhd6gxevu37mkqcvvsj8qeylhn0rz46zdlq", proposal.Recipient) require.Equal(t, "1000stake", proposal.Deposit) require.Equal(t, "1000stake", proposal.Amount) } diff --git a/x/distribution/client/cli/utils.go b/x/distribution/client/cli/utils.go index 3a02021b34..08a74d8a5d 100644 --- a/x/distribution/client/cli/utils.go +++ b/x/distribution/client/cli/utils.go @@ -8,7 +8,7 @@ import ( ) // ParseCommunityPoolSpendProposalWithDeposit reads and parses a CommunityPoolSpendProposalWithDeposit from a file. -func ParseCommunityPoolSpendProposalWithDeposit(cdc codec.JSONMarshaler, proposalFile string) (types.CommunityPoolSpendProposalWithDeposit, error) { +func ParseCommunityPoolSpendProposalWithDeposit(cdc codec.JSONCodec, proposalFile string) (types.CommunityPoolSpendProposalWithDeposit, error) { proposal := types.CommunityPoolSpendProposalWithDeposit{} contents, err := ioutil.ReadFile(proposalFile) diff --git a/x/distribution/client/common/common_test.go b/x/distribution/client/common/common_test.go index 02a9a20997..1410c0e02c 100644 --- a/x/distribution/client/common/common_test.go +++ b/x/distribution/client/common/common_test.go @@ -25,8 +25,8 @@ func TestQueryDelegationRewardsAddrValidation(t *testing.T) { }{ {"invalid delegator address", args{"invalid", ""}, nil, true}, {"empty delegator address", args{"", ""}, nil, true}, - {"invalid validator address", args{"cosmos1zxcsu7l5qxs53lvp0fqgd09a9r2g6kqrk2cdpa", "invalid"}, nil, true}, - {"empty validator address", args{"cosmos1zxcsu7l5qxs53lvp0fqgd09a9r2g6kqrk2cdpa", ""}, nil, true}, + {"invalid validator address", args{"link1zxcsu7l5qxs53lvp0fqgd09a9r2g6kqrk2cdpa", "invalid"}, nil, true}, + {"empty validator address", args{"link1zxcsu7l5qxs53lvp0fqgd09a9r2g6kqrk2cdpa", ""}, nil, true}, } for _, tt := range tests { diff --git a/x/distribution/client/rest/grpc_query_test.go b/x/distribution/client/rest/grpc_query_test.go index e020ba61bb..ef210f1dd0 100644 --- a/x/distribution/client/rest/grpc_query_test.go +++ b/x/distribution/client/rest/grpc_query_test.go @@ -61,7 +61,7 @@ func (s *IntegrationTestSuite) TestQueryParamsGRPC() { resp, err := rest.GetRequest(tc.url) s.Run(tc.name, func() { s.Require().NoError(err) - s.Require().NoError(val.ClientCtx.JSONMarshaler.UnmarshalJSON(resp, tc.respType)) + s.Require().NoError(val.ClientCtx.Codec.UnmarshalJSON(resp, tc.respType)) s.Require().Equal(tc.expected, tc.respType) }) } @@ -111,10 +111,10 @@ func (s *IntegrationTestSuite) TestQueryOutstandingRewardsGRPC() { resp, err := testutil.GetRequestWithHeaders(tc.url, tc.headers) s.Run(tc.name, func() { if tc.expErr { - s.Require().Error(val.ClientCtx.JSONMarshaler.UnmarshalJSON(resp, tc.respType)) + s.Require().Error(val.ClientCtx.Codec.UnmarshalJSON(resp, tc.respType)) } else { s.Require().NoError(err) - s.Require().NoError(val.ClientCtx.JSONMarshaler.UnmarshalJSON(resp, tc.respType)) + s.Require().NoError(val.ClientCtx.Codec.UnmarshalJSON(resp, tc.respType)) s.Require().Equal(tc.expected.String(), tc.respType.String()) } }) @@ -165,10 +165,10 @@ func (s *IntegrationTestSuite) TestQueryValidatorCommissionGRPC() { resp, err := testutil.GetRequestWithHeaders(tc.url, tc.headers) s.Run(tc.name, func() { if tc.expErr { - s.Require().Error(val.ClientCtx.JSONMarshaler.UnmarshalJSON(resp, tc.respType)) + s.Require().Error(val.ClientCtx.Codec.UnmarshalJSON(resp, tc.respType)) } else { s.Require().NoError(err) - s.Require().NoError(val.ClientCtx.JSONMarshaler.UnmarshalJSON(resp, tc.respType)) + s.Require().NoError(val.ClientCtx.Codec.UnmarshalJSON(resp, tc.respType)) s.Require().Equal(tc.expected.String(), tc.respType.String()) } }) @@ -224,10 +224,10 @@ func (s *IntegrationTestSuite) TestQuerySlashesGRPC() { s.Run(tc.name, func() { if tc.expErr { - s.Require().Error(val.ClientCtx.JSONMarshaler.UnmarshalJSON(resp, tc.respType)) + s.Require().Error(val.ClientCtx.Codec.UnmarshalJSON(resp, tc.respType)) } else { s.Require().NoError(err) - s.Require().NoError(val.ClientCtx.JSONMarshaler.UnmarshalJSON(resp, tc.respType)) + s.Require().NoError(val.ClientCtx.Codec.UnmarshalJSON(resp, tc.respType)) s.Require().Equal(tc.expected.String(), tc.respType.String()) } }) @@ -300,10 +300,10 @@ func (s *IntegrationTestSuite) TestQueryDelegatorRewardsGRPC() { s.Run(tc.name, func() { if tc.expErr { - s.Require().Error(val.ClientCtx.JSONMarshaler.UnmarshalJSON(resp, tc.respType)) + s.Require().Error(val.ClientCtx.Codec.UnmarshalJSON(resp, tc.respType)) } else { s.Require().NoError(err) - s.Require().NoError(val.ClientCtx.JSONMarshaler.UnmarshalJSON(resp, tc.respType)) + s.Require().NoError(val.ClientCtx.Codec.UnmarshalJSON(resp, tc.respType)) s.Require().Equal(tc.expected.String(), tc.respType.String()) } }) @@ -352,10 +352,10 @@ func (s *IntegrationTestSuite) TestQueryDelegatorValidatorsGRPC() { s.Run(tc.name, func() { if tc.expErr { - s.Require().Error(val.ClientCtx.JSONMarshaler.UnmarshalJSON(resp, tc.respType)) + s.Require().Error(val.ClientCtx.Codec.UnmarshalJSON(resp, tc.respType)) } else { s.Require().NoError(err) - s.Require().NoError(val.ClientCtx.JSONMarshaler.UnmarshalJSON(resp, tc.respType)) + s.Require().NoError(val.ClientCtx.Codec.UnmarshalJSON(resp, tc.respType)) s.Require().Equal(tc.expected.String(), tc.respType.String()) } }) @@ -404,10 +404,10 @@ func (s *IntegrationTestSuite) TestQueryWithdrawAddressGRPC() { s.Run(tc.name, func() { if tc.expErr { - s.Require().Error(val.ClientCtx.JSONMarshaler.UnmarshalJSON(resp, tc.respType)) + s.Require().Error(val.ClientCtx.Codec.UnmarshalJSON(resp, tc.respType)) } else { s.Require().NoError(err) - s.Require().NoError(val.ClientCtx.JSONMarshaler.UnmarshalJSON(resp, tc.respType)) + s.Require().NoError(val.ClientCtx.Codec.UnmarshalJSON(resp, tc.respType)) s.Require().Equal(tc.expected.String(), tc.respType.String()) } }) @@ -452,7 +452,7 @@ func (s *IntegrationTestSuite) TestQueryValidatorCommunityPoolGRPC() { s.Require().Error(err) } else { s.Require().NoError(err) - s.Require().NoError(val.ClientCtx.JSONMarshaler.UnmarshalJSON(resp, tc.respType)) + s.Require().NoError(val.ClientCtx.Codec.UnmarshalJSON(resp, tc.respType)) s.Require().Equal(tc.expected.String(), tc.respType.String()) } }) diff --git a/x/distribution/client/testutil/cli_test.go b/x/distribution/client/testutil/cli_test.go new file mode 100644 index 0000000000..8ded31fefa --- /dev/null +++ b/x/distribution/client/testutil/cli_test.go @@ -0,0 +1,18 @@ +//go:build norace +// +build norace + +package testutil + +import ( + "testing" + + "github.com/line/lbm-sdk/testutil/network" + + "github.com/stretchr/testify/suite" +) + +func TestIntegrationTestSuite(t *testing.T) { + cfg := network.DefaultConfig() + cfg.NumValidators = 1 + suite.Run(t, NewIntegrationTestSuite(cfg)) +} diff --git a/x/distribution/client/cli/cli_test.go b/x/distribution/client/testutil/suite.go similarity index 89% rename from x/distribution/client/cli/cli_test.go rename to x/distribution/client/testutil/suite.go index 48aef20351..63b16eb441 100644 --- a/x/distribution/client/cli/cli_test.go +++ b/x/distribution/client/testutil/suite.go @@ -1,34 +1,33 @@ -// +build norace - -package cli_test +package testutil import ( - "context" "fmt" "strings" - "testing" "time" "github.com/gogo/protobuf/proto" - ostcli "github.com/line/ostracon/libs/cli" "github.com/stretchr/testify/suite" - "github.com/line/lbm-sdk/client" + ostcli "github.com/line/ostracon/libs/cli" + "github.com/line/lbm-sdk/client/flags" "github.com/line/lbm-sdk/testutil" clitestutil "github.com/line/lbm-sdk/testutil/cli" - testnet "github.com/line/lbm-sdk/testutil/network" + "github.com/line/lbm-sdk/testutil/network" sdk "github.com/line/lbm-sdk/types" "github.com/line/lbm-sdk/x/distribution/client/cli" - distrtestutil "github.com/line/lbm-sdk/x/distribution/client/testutil" minttypes "github.com/line/lbm-sdk/x/mint/types" ) type IntegrationTestSuite struct { suite.Suite - cfg testnet.Config - network *testnet.Network + cfg network.Config + network *network.Network +} + +func NewIntegrationTestSuite(cfg network.Config) *IntegrationTestSuite { + return &IntegrationTestSuite{cfg: cfg} } // SetupTest creates a new network for _each_ integration test. We create a new @@ -38,25 +37,21 @@ type IntegrationTestSuite struct { func (s *IntegrationTestSuite) SetupTest() { s.T().Log("setting up integration test suite") - cfg := testnet.DefaultConfig() - genesisState := cfg.GenesisState - cfg.NumValidators = 1 - + genesisState := s.cfg.GenesisState var mintData minttypes.GenesisState - s.Require().NoError(cfg.Codec.UnmarshalJSON(genesisState[minttypes.ModuleName], &mintData)) + s.Require().NoError(s.cfg.Codec.UnmarshalJSON(genesisState[minttypes.ModuleName], &mintData)) inflation := sdk.MustNewDecFromStr("1.0") mintData.Minter.Inflation = inflation mintData.Params.InflationMin = inflation mintData.Params.InflationMax = inflation - mintDataBz, err := cfg.Codec.MarshalJSON(&mintData) + mintDataBz, err := s.cfg.Codec.MarshalJSON(&mintData) s.Require().NoError(err) genesisState[minttypes.ModuleName] = mintDataBz - cfg.GenesisState = genesisState + s.cfg.GenesisState = genesisState - s.cfg = cfg - s.network = testnet.New(s.T(), cfg) + s.network = network.New(s.T(), s.cfg) _, err = s.network.WaitForHeight(1) s.Require().NoError(err) @@ -134,7 +129,7 @@ func (s *IntegrationTestSuite) TestGetCmdQueryValidatorOutstandingRewards() { fmt.Sprintf("--%s=json", ostcli.OutputFlag), }, false, - `{"rewards":[{"denom":"stake","amount":"232.260000000000000000"}]}`, + `{"rewards":[{"denom":"stake","amount":"1164.240000000000000000"}]}`, }, { "text output", @@ -145,7 +140,7 @@ func (s *IntegrationTestSuite) TestGetCmdQueryValidatorOutstandingRewards() { }, false, `rewards: -- amount: "232.260000000000000000" +- amount: "1164.240000000000000000" denom: stake`, }, } @@ -197,7 +192,7 @@ func (s *IntegrationTestSuite) TestGetCmdQueryValidatorCommission() { fmt.Sprintf("--%s=json", ostcli.OutputFlag), }, false, - `{"commission":[{"denom":"stake","amount":"116.130000000000000000"}]}`, + `{"commission":[{"denom":"stake","amount":"464.520000000000000000"}]}`, }, { "text output", @@ -208,7 +203,7 @@ func (s *IntegrationTestSuite) TestGetCmdQueryValidatorCommission() { }, false, `commission: -- amount: "116.130000000000000000" +- amount: "464.520000000000000000" denom: stake`, }, } @@ -313,7 +308,7 @@ func (s *IntegrationTestSuite) TestGetCmdQueryValidatorSlashes() { func (s *IntegrationTestSuite) TestGetCmdQueryDelegatorRewards() { val := s.network.Validators[0] addr := val.Address - valAddr := sdk.AccAddress(addr).ToValAddress() + valAddr := addr.ToValAddress() _, err := s.network.WaitForHeightWithTimeout(11, time.Minute) s.Require().NoError(err) @@ -345,7 +340,7 @@ func (s *IntegrationTestSuite) TestGetCmdQueryDelegatorRewards() { { "json output", []string{ - fmt.Sprintf("--%s=10", flags.FlagHeight), + fmt.Sprintf("--%s=5", flags.FlagHeight), addr.String(), fmt.Sprintf("--%s=json", ostcli.OutputFlag), }, @@ -355,7 +350,7 @@ func (s *IntegrationTestSuite) TestGetCmdQueryDelegatorRewards() { { "json output (specific validator)", []string{ - fmt.Sprintf("--%s=10", flags.FlagHeight), + fmt.Sprintf("--%s=5", flags.FlagHeight), addr.String(), valAddr.String(), fmt.Sprintf("--%s=json", ostcli.OutputFlag), }, @@ -366,7 +361,7 @@ func (s *IntegrationTestSuite) TestGetCmdQueryDelegatorRewards() { "text output", []string{ fmt.Sprintf("--%s=text", ostcli.OutputFlag), - fmt.Sprintf("--%s=10", flags.FlagHeight), + fmt.Sprintf("--%s=5", flags.FlagHeight), addr.String(), }, false, @@ -383,7 +378,7 @@ total: "text output (specific validator)", []string{ fmt.Sprintf("--%s=text", ostcli.OutputFlag), - fmt.Sprintf("--%s=10", flags.FlagHeight), + fmt.Sprintf("--%s=5", flags.FlagHeight), addr.String(), valAddr.String(), }, false, @@ -458,8 +453,8 @@ func (s *IntegrationTestSuite) TestNewWithdrawRewardsCmd() { valAddr fmt.Stringer args []string expectErr bool - respType proto.Message expectedCode uint32 + respType proto.Message }{ { "invalid validator address", @@ -470,7 +465,7 @@ func (s *IntegrationTestSuite) TestNewWithdrawRewardsCmd() { fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), }, - true, nil, 0, + true, 0, nil, }, { "valid transaction", @@ -481,7 +476,7 @@ func (s *IntegrationTestSuite) TestNewWithdrawRewardsCmd() { fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), }, - false, &sdk.TxResponse{}, 0, + false, 0, &sdk.TxResponse{}, }, { "valid transaction (with commission)", @@ -493,7 +488,7 @@ func (s *IntegrationTestSuite) TestNewWithdrawRewardsCmd() { fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), }, - false, &sdk.TxResponse{}, 0, + false, 0, &sdk.TxResponse{}, }, } @@ -503,15 +498,12 @@ func (s *IntegrationTestSuite) TestNewWithdrawRewardsCmd() { s.Run(tc.name, func() { clientCtx := val.ClientCtx - ctx := context.Background() - ctx = context.WithValue(ctx, client.ClientContextKey, &clientCtx) - - bz, err := distrtestutil.MsgWithdrawDelegatorRewardExec(clientCtx, tc.valAddr, tc.args...) + bz, err := MsgWithdrawDelegatorRewardExec(clientCtx, tc.valAddr, tc.args...) if tc.expectErr { s.Require().Error(err) } else { s.Require().NoError(err) - s.Require().NoError(clientCtx.JSONMarshaler.UnmarshalJSON(bz, tc.respType), string(bz)) + s.Require().NoError(clientCtx.Codec.UnmarshalJSON(bz, tc.respType), string(bz)) txResp := tc.respType.(*sdk.TxResponse) s.Require().Equal(tc.expectedCode, txResp.Code) @@ -527,8 +519,8 @@ func (s *IntegrationTestSuite) TestNewWithdrawAllRewardsCmd() { name string args []string expectErr bool - respType proto.Message expectedCode uint32 + respType proto.Message }{ { "valid transaction (offline)", @@ -538,7 +530,7 @@ func (s *IntegrationTestSuite) TestNewWithdrawAllRewardsCmd() { fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), }, - true, nil, 0, + true, 0, nil, }, { "valid transaction", @@ -548,7 +540,7 @@ func (s *IntegrationTestSuite) TestNewWithdrawAllRewardsCmd() { fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), }, - false, &sdk.TxResponse{}, 0, + false, 0, &sdk.TxResponse{}, }, } @@ -564,7 +556,7 @@ func (s *IntegrationTestSuite) TestNewWithdrawAllRewardsCmd() { s.Require().Error(err) } else { s.Require().NoError(err) - s.Require().NoError(clientCtx.JSONMarshaler.UnmarshalJSON(out.Bytes(), tc.respType), out.String()) + s.Require().NoError(clientCtx.Codec.UnmarshalJSON(out.Bytes(), tc.respType), out.String()) txResp := tc.respType.(*sdk.TxResponse) s.Require().Equal(tc.expectedCode, txResp.Code) @@ -580,8 +572,8 @@ func (s *IntegrationTestSuite) TestNewSetWithdrawAddrCmd() { name string args []string expectErr bool - respType proto.Message expectedCode uint32 + respType proto.Message }{ { "invalid withdraw address", @@ -592,7 +584,7 @@ func (s *IntegrationTestSuite) TestNewSetWithdrawAddrCmd() { fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), }, - true, nil, 0, + true, 0, nil, }, { "valid transaction", @@ -603,7 +595,7 @@ func (s *IntegrationTestSuite) TestNewSetWithdrawAddrCmd() { fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), }, - false, &sdk.TxResponse{}, 0, + false, 0, &sdk.TxResponse{}, }, } @@ -619,7 +611,7 @@ func (s *IntegrationTestSuite) TestNewSetWithdrawAddrCmd() { s.Require().Error(err) } else { s.Require().NoError(err) - s.Require().NoError(clientCtx.JSONMarshaler.UnmarshalJSON(out.Bytes(), tc.respType), out.String()) + s.Require().NoError(clientCtx.Codec.UnmarshalJSON(out.Bytes(), tc.respType), out.String()) txResp := tc.respType.(*sdk.TxResponse) s.Require().Equal(tc.expectedCode, txResp.Code) @@ -635,8 +627,8 @@ func (s *IntegrationTestSuite) TestNewFundCommunityPoolCmd() { name string args []string expectErr bool - respType proto.Message expectedCode uint32 + respType proto.Message }{ { "invalid funding amount", @@ -647,7 +639,7 @@ func (s *IntegrationTestSuite) TestNewFundCommunityPoolCmd() { fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), }, - true, nil, 0, + true, 0, nil, }, { "valid transaction", @@ -658,7 +650,7 @@ func (s *IntegrationTestSuite) TestNewFundCommunityPoolCmd() { fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), }, - false, &sdk.TxResponse{}, 0, + false, 0, &sdk.TxResponse{}, }, } @@ -674,7 +666,7 @@ func (s *IntegrationTestSuite) TestNewFundCommunityPoolCmd() { s.Require().Error(err) } else { s.Require().NoError(err) - s.Require().NoError(clientCtx.JSONMarshaler.UnmarshalJSON(out.Bytes(), tc.respType), out.String()) + s.Require().NoError(clientCtx.Codec.UnmarshalJSON(out.Bytes(), tc.respType), out.String()) txResp := tc.respType.(*sdk.TxResponse) s.Require().Equal(tc.expectedCode, txResp.Code) @@ -692,7 +684,9 @@ func (s *IntegrationTestSuite) TestGetCmdSubmitProposal() { "amount": "-343foocoin", "deposit": -324foocoin }` + invalidPropFile := testutil.WriteToNewTempFile(s.T(), invalidProp) + validProp := fmt.Sprintf(`{ "title": "Community Pool Spend", "description": "Pay me some Atoms!", @@ -700,13 +694,14 @@ func (s *IntegrationTestSuite) TestGetCmdSubmitProposal() { "amount": "%s", "deposit": "%s" }`, val.Address.String(), sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(5431)), sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(5431))) + validPropFile := testutil.WriteToNewTempFile(s.T(), validProp) testCases := []struct { name string args []string expectErr bool - respType proto.Message expectedCode uint32 + respType proto.Message }{ { "invalid proposal", @@ -717,7 +712,7 @@ func (s *IntegrationTestSuite) TestGetCmdSubmitProposal() { fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync), fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), }, - true, nil, 0, + true, 0, nil, }, { "valid transaction", @@ -728,7 +723,7 @@ func (s *IntegrationTestSuite) TestGetCmdSubmitProposal() { fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync), // sync mode as there are no funds yet fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), }, - false, &sdk.TxResponse{}, 0, + false, 0, &sdk.TxResponse{}, }, } @@ -745,7 +740,7 @@ func (s *IntegrationTestSuite) TestGetCmdSubmitProposal() { s.Require().Error(err) } else { s.Require().NoError(err) - s.Require().NoError(clientCtx.JSONMarshaler.UnmarshalJSON(out.Bytes(), tc.respType), out.String()) + s.Require().NoError(clientCtx.Codec.UnmarshalJSON(out.Bytes(), tc.respType), out.String()) txResp := tc.respType.(*sdk.TxResponse) s.Require().Equal(tc.expectedCode, txResp.Code, out.String()) @@ -753,7 +748,3 @@ func (s *IntegrationTestSuite) TestGetCmdSubmitProposal() { }) } } - -func TestIntegrationTestSuite(t *testing.T) { - suite.Run(t, new(IntegrationTestSuite)) -} diff --git a/x/distribution/keeper/allocation.go b/x/distribution/keeper/allocation.go index 685b810b8d..190e8cc269 100644 --- a/x/distribution/keeper/allocation.go +++ b/x/distribution/keeper/allocation.go @@ -11,9 +11,11 @@ import ( ) // AllocateTokens handles distribution of the collected fees +// bondedVotes is a list of (validator address, validator voted on last block flag) for all +// validators in the bonded set. func (k Keeper) AllocateTokens( ctx sdk.Context, sumPreviousPrecommitPower, totalPreviousPower int64, - previousProposer sdk.ConsAddress, previousVotes []abci.VoteInfo, + previousProposer sdk.ConsAddress, bondedVotes []abci.VoteInfo, ) { logger := k.Logger(ctx) @@ -83,7 +85,7 @@ func (k Keeper) AllocateTokens( // allocate tokens proportionally to voting power // TODO consider parallelizing later, ref https://github.com/cosmos/cosmos-sdk/pull/3099#discussion_r246276376 - for _, vote := range previousVotes { + for _, vote := range bondedVotes { validator := k.stakingKeeper.ValidatorByConsAddr(ctx, sdk.BytesToConsAddress(vote.Validator.Address)) // TODO consider microslashing for missing votes. diff --git a/x/distribution/keeper/allocation_test.go b/x/distribution/keeper/allocation_test.go index 12cfb0f293..75593cdbf9 100644 --- a/x/distribution/keeper/allocation_test.go +++ b/x/distribution/keeper/allocation_test.go @@ -84,8 +84,9 @@ func TestAllocateTokensToManyValidators(t *testing.T) { feeCollector := app.AccountKeeper.GetModuleAccount(ctx, types.FeeCollectorName) require.NotNil(t, feeCollector) - err := app.BankKeeper.SetBalances(ctx, feeCollector.GetAddress(), fees) - require.NoError(t, err) + // fund fee collector + require.NoError(t, simapp.FundModuleAccount(app, ctx, feeCollector.GetName(), fees)) + app.AccountKeeper.SetAccount(ctx, feeCollector) votes := []abci.VoteInfo{ @@ -167,8 +168,7 @@ func TestAllocateTokensTruncation(t *testing.T) { feeCollector := app.AccountKeeper.GetModuleAccount(ctx, types.FeeCollectorName) require.NotNil(t, feeCollector) - err := app.BankKeeper.SetBalances(ctx, feeCollector.GetAddress(), fees) - require.NoError(t, err) + require.NoError(t, simapp.FundModuleAccount(app, ctx, feeCollector.GetName(), fees)) app.AccountKeeper.SetAccount(ctx, feeCollector) diff --git a/x/distribution/keeper/delegation_test.go b/x/distribution/keeper/delegation_test.go index b12295dce3..b133e48e7e 100644 --- a/x/distribution/keeper/delegation_test.go +++ b/x/distribution/keeper/delegation_test.go @@ -112,7 +112,7 @@ func TestCalculateRewardsAfterSlash(t *testing.T) { ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 3) // allocate some rewards - initial := sdk.TokensFromConsensusPower(10) + initial := app.StakingKeeper.TokensFromConsensusPower(ctx, 10) tokens := sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: initial.ToDec()}} app.DistrKeeper.AllocateTokensToValidator(ctx, val, tokens) @@ -175,7 +175,7 @@ func TestCalculateRewardsAfterManySlashes(t *testing.T) { ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 3) // allocate some rewards - initial := sdk.TokensFromConsensusPower(10) + initial := app.StakingKeeper.TokensFromConsensusPower(ctx, 10) tokens := sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: initial.ToDec()}} app.DistrKeeper.AllocateTokensToValidator(ctx, val, tokens) @@ -269,18 +269,18 @@ func TestCalculateRewardsMultiDelegator(t *testing.T) { } func TestWithdrawDelegationRewardsBasic(t *testing.T) { - balancePower := int64(1000) - balanceTokens := sdk.TokensFromConsensusPower(balancePower) app := simapp.Setup(false) ctx := app.BaseApp.NewContext(false, ocproto.Header{}) + balancePower := int64(1000) + balanceTokens := app.StakingKeeper.TokensFromConsensusPower(ctx, balancePower) addr := simapp.AddTestAddrs(app, ctx, 1, sdk.NewInt(1000000000)) valAddrs := simapp.ConvertAddrsToValAddrs(addr) tstaking := teststaking.NewHelper(t, ctx, app.StakingKeeper) // set module account coins distrAcc := app.DistrKeeper.GetDistributionAccount(ctx) - require.NoError(t, app.BankKeeper.SetBalances(ctx, distrAcc.GetAddress(), sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, balanceTokens)))) + require.NoError(t, simapp.FundModuleAccount(app, ctx, distrAcc.GetName(), sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, balanceTokens)))) app.AccountKeeper.SetModuleAccount(ctx, distrAcc) // create validator with 50% commission @@ -305,7 +305,7 @@ func TestWithdrawDelegationRewardsBasic(t *testing.T) { val := app.StakingKeeper.Validator(ctx, valAddrs[0]) // allocate some rewards - initial := sdk.TokensFromConsensusPower(10) + initial := app.StakingKeeper.TokensFromConsensusPower(ctx, 10) tokens := sdk.DecCoins{sdk.NewDecCoin(sdk.DefaultBondDenom, initial)} app.DistrKeeper.AllocateTokensToValidator(ctx, val, tokens) @@ -375,7 +375,7 @@ func TestCalculateRewardsAfterManySlashesInSameBlock(t *testing.T) { ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 3) // allocate some rewards - initial := sdk.TokensFromConsensusPower(10).ToDec() + initial := app.StakingKeeper.TokensFromConsensusPower(ctx, 10).ToDec() tokens := sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: initial}} app.DistrKeeper.AllocateTokensToValidator(ctx, val, tokens) @@ -431,7 +431,7 @@ func TestCalculateRewardsMultiDelegatorMultiSlash(t *testing.T) { del1 := app.StakingKeeper.Delegation(ctx, valAddrs[0].ToAccAddress(), valAddrs[0]) // allocate some rewards - initial := sdk.TokensFromConsensusPower(30).ToDec() + initial := app.StakingKeeper.TokensFromConsensusPower(ctx, 30).ToDec() tokens := sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: initial}} app.DistrKeeper.AllocateTokensToValidator(ctx, val, tokens) @@ -492,8 +492,7 @@ func TestCalculateRewardsMultiDelegatorMultWithdraw(t *testing.T) { // set module account coins distrAcc := app.DistrKeeper.GetDistributionAccount(ctx) - err := app.BankKeeper.SetBalances(ctx, distrAcc.GetAddress(), sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(1000)))) - require.NoError(t, err) + require.NoError(t, simapp.FundModuleAccount(app, ctx, distrAcc.GetName(), sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(1000))))) app.AccountKeeper.SetModuleAccount(ctx, distrAcc) tokens := sdk.DecCoins{sdk.NewDecCoinFromDec(sdk.DefaultBondDenom, sdk.NewDec(initial))} @@ -538,7 +537,7 @@ func TestCalculateRewardsMultiDelegatorMultWithdraw(t *testing.T) { app.DistrKeeper.AllocateTokensToValidator(ctx, val, tokens) // first delegator withdraws - _, err = app.DistrKeeper.WithdrawDelegationRewards(ctx, valAddrs[0].ToAccAddress(), valAddrs[0]) + _, err := app.DistrKeeper.WithdrawDelegationRewards(ctx, valAddrs[0].ToAccAddress(), valAddrs[0]) require.NoError(t, err) // second delegator withdraws diff --git a/x/distribution/keeper/genesis.go b/x/distribution/keeper/genesis.go index 3591f20a35..25f2fcf6ad 100644 --- a/x/distribution/keeper/genesis.go +++ b/x/distribution/keeper/genesis.go @@ -31,7 +31,7 @@ func (k Keeper) InitGenesis(ctx sdk.Context, data types.GenesisState) { for _, rew := range data.OutstandingRewards { valAddr := sdk.ValAddress(rew.ValidatorAddress) k.SetValidatorOutstandingRewards(ctx, valAddr, types.ValidatorOutstandingRewards{Rewards: rew.OutstandingRewards}) - moduleHoldings = rew.OutstandingRewards + moduleHoldings = moduleHoldings.Add(rew.OutstandingRewards...) } for _, acc := range data.ValidatorAccumulatedCommissions { valAddr := sdk.ValAddress(acc.ValidatorAddress) @@ -66,12 +66,11 @@ func (k Keeper) InitGenesis(ctx sdk.Context, data types.GenesisState) { balances := k.bankKeeper.GetAllBalances(ctx, moduleAcc.GetAddress()) if balances.IsZero() { - if err := k.bankKeeper.SetBalances(ctx, moduleAcc.GetAddress(), moduleHoldingsInt); err != nil { - panic(err) - } - k.authKeeper.SetModuleAccount(ctx, moduleAcc) } + if !balances.IsEqual(moduleHoldingsInt) { + panic(fmt.Sprintf("distribution module balance does not match the module holdings: %s <-> %s", balances, moduleHoldingsInt)) + } } // ExportGenesis returns a GenesisState for a given context and keeper. diff --git a/x/distribution/keeper/grpc_query.go b/x/distribution/keeper/grpc_query.go index 9b02b96f67..626fa821b0 100644 --- a/x/distribution/keeper/grpc_query.go +++ b/x/distribution/keeper/grpc_query.go @@ -92,7 +92,7 @@ func (k Keeper) ValidatorSlashes(c context.Context, req *types.QueryValidatorSla pageRes, err := query.FilteredPaginate(slashesStore, req.Pagination, func(key []byte, value []byte, accumulate bool) (bool, error) { var result types.ValidatorSlashEvent - err := k.cdc.UnmarshalBinaryBare(value, &result) + err := k.cdc.Unmarshal(value, &result) if err != nil { return false, err diff --git a/x/distribution/keeper/grpc_query_test.go b/x/distribution/keeper/grpc_query_test.go index 9df352f4d0..8fe24f8bd2 100644 --- a/x/distribution/keeper/grpc_query_test.go +++ b/x/distribution/keeper/grpc_query_test.go @@ -623,7 +623,7 @@ func (suite *KeeperTestSuite) TestGRPCCommunityPool() { "valid request", func() { amount := sdk.NewCoins(sdk.NewInt64Coin("stake", 100)) - suite.Require().NoError(app.BankKeeper.SetBalances(ctx, addrs[0], amount)) + suite.Require().NoError(simapp.FundAccount(app, ctx, addrs[0], amount)) err := app.DistrKeeper.FundCommunityPool(ctx, amount, addrs[0]) suite.Require().Nil(err) diff --git a/x/distribution/keeper/hooks.go b/x/distribution/keeper/hooks.go index aa0702ea3d..5185323d23 100644 --- a/x/distribution/keeper/hooks.go +++ b/x/distribution/keeper/hooks.go @@ -22,7 +22,7 @@ func (h Hooks) AfterValidatorCreated(ctx sdk.Context, valAddr sdk.ValAddress) { h.k.initializeValidator(ctx, val) } -// cleanup for after validator is removed +// AfterValidatorRemoved performs clean up after a validator is removed func (h Hooks) AfterValidatorRemoved(ctx sdk.Context, _ sdk.ConsAddress, valAddr sdk.ValAddress) { // fetch outstanding outstanding := h.k.GetValidatorOutstandingRewardsCoins(ctx, valAddr) @@ -52,7 +52,9 @@ func (h Hooks) AfterValidatorRemoved(ctx sdk.Context, _ sdk.ConsAddress, valAddr } } - // add outstanding to community pool + // Add outstanding to community pool + // The validator is removed only after it has no more delegations. + // This operation sends only the remaining dust to the community pool. feePool := h.k.GetFeePool(ctx) feePool.CommunityPool = feePool.CommunityPool.Add(outstanding...) h.k.SetFeePool(ctx, feePool) diff --git a/x/distribution/keeper/keeper.go b/x/distribution/keeper/keeper.go index 59a8cdd214..5ec509ccad 100644 --- a/x/distribution/keeper/keeper.go +++ b/x/distribution/keeper/keeper.go @@ -15,8 +15,8 @@ import ( // Keeper of the distribution store type Keeper struct { storeKey sdk.StoreKey - cdc codec.BinaryMarshaler - paramSpace *paramtypes.Subspace + cdc codec.BinaryCodec + paramSpace paramtypes.Subspace authKeeper types.AccountKeeper bankKeeper types.BankKeeper stakingKeeper types.StakingKeeper @@ -28,7 +28,7 @@ type Keeper struct { // NewKeeper creates a new distribution Keeper instance func NewKeeper( - cdc codec.BinaryMarshaler, key sdk.StoreKey, paramSpace *paramtypes.Subspace, + cdc codec.BinaryCodec, key sdk.StoreKey, paramSpace paramtypes.Subspace, ak types.AccountKeeper, bk types.BankKeeper, sk types.StakingKeeper, feeCollectorName string, blockedAddrs map[string]bool, ) Keeper { diff --git a/x/distribution/keeper/keeper_test.go b/x/distribution/keeper/keeper_test.go index f0306ec84b..ca2f922bba 100644 --- a/x/distribution/keeper/keeper_test.go +++ b/x/distribution/keeper/keeper_test.go @@ -48,16 +48,14 @@ func TestWithdrawValidatorCommission(t *testing.T) { // set module account coins distrAcc := app.DistrKeeper.GetDistributionAccount(ctx) - err := app.BankKeeper.SetBalances(ctx, distrAcc.GetAddress(), sdk.NewCoins( - sdk.NewCoin("mytoken", sdk.NewInt(2)), - sdk.NewCoin("stake", sdk.NewInt(2)), - )) - require.NoError(t, err) + coins := sdk.NewCoins(sdk.NewCoin("mytoken", sdk.NewInt(2)), sdk.NewCoin("stake", sdk.NewInt(2))) + require.NoError(t, simapp.FundModuleAccount(app, ctx, distrAcc.GetName(), coins)) + app.AccountKeeper.SetModuleAccount(ctx, distrAcc) // check initial balance balance := app.BankKeeper.GetAllBalances(ctx, valAddrs[0].ToAccAddress()) - expTokens := sdk.TokensFromConsensusPower(1000) + expTokens := app.StakingKeeper.TokensFromConsensusPower(ctx, 1000) expCoins := sdk.NewCoins(sdk.NewCoin("stake", expTokens)) require.Equal(t, expCoins, balance) @@ -68,7 +66,7 @@ func TestWithdrawValidatorCommission(t *testing.T) { app.DistrKeeper.SetValidatorAccumulatedCommission(ctx, valAddrs[0], types.ValidatorAccumulatedCommission{Commission: valCommission}) // withdraw commission - _, err = app.DistrKeeper.WithdrawValidatorCommission(ctx, valAddrs[0]) + _, err := app.DistrKeeper.WithdrawValidatorCommission(ctx, valAddrs[0]) require.NoError(t, err) // check balance increase @@ -113,10 +111,10 @@ func TestFundCommunityPool(t *testing.T) { app := simapp.Setup(false) ctx := app.BaseApp.NewContext(false, ocproto.Header{}) - addr := simapp.AddTestAddrs(app, ctx, 2, sdk.NewInt(1000000000)) + addr := simapp.AddTestAddrs(app, ctx, 2, sdk.ZeroInt()) amount := sdk.NewCoins(sdk.NewInt64Coin("stake", 100)) - require.NoError(t, app.BankKeeper.SetBalances(ctx, addr[0], amount)) + require.NoError(t, simapp.FundAccount(app, ctx, addr[0], amount)) initPool := app.DistrKeeper.GetFeePool(ctx) assert.Empty(t, initPool.CommunityPool) diff --git a/x/distribution/keeper/store.go b/x/distribution/keeper/store.go index 69802931c6..0c065985a0 100644 --- a/x/distribution/keeper/store.go +++ b/x/distribution/keeper/store.go @@ -50,14 +50,14 @@ func (k Keeper) GetFeePool(ctx sdk.Context) (feePool types.FeePool) { if b == nil { panic("Stored fee pool should not have been nil") } - k.cdc.MustUnmarshalBinaryBare(b, &feePool) + k.cdc.MustUnmarshal(b, &feePool) return } // set the global fee pool distribution info func (k Keeper) SetFeePool(ctx sdk.Context, feePool types.FeePool) { store := ctx.KVStore(k.storeKey) - b := k.cdc.MustMarshalBinaryBare(&feePool) + b := k.cdc.MustMarshal(&feePool) store.Set(types.FeePoolKey, b) } @@ -71,14 +71,14 @@ func (k Keeper) GetPreviousProposerConsAddr(ctx sdk.Context) sdk.ConsAddress { } addrValue := gogotypes.BytesValue{} - k.cdc.MustUnmarshalBinaryBare(bz, &addrValue) - return sdk.ConsAddress(string(addrValue.GetValue())) + k.cdc.MustUnmarshal(bz, &addrValue) + return sdk.ConsAddress(addrValue.GetValue()) } // set the proposer public key for this block func (k Keeper) SetPreviousProposerConsAddr(ctx sdk.Context, consAddr sdk.ConsAddress) { store := ctx.KVStore(k.storeKey) - bz := k.cdc.MustMarshalBinaryBare(&gogotypes.BytesValue{Value: consAddr.Bytes()}) + bz := k.cdc.MustMarshal(&gogotypes.BytesValue{Value: consAddr.Bytes()}) store.Set(types.ProposerKey, bz) } @@ -86,14 +86,14 @@ func (k Keeper) SetPreviousProposerConsAddr(ctx sdk.Context, consAddr sdk.ConsAd func (k Keeper) GetDelegatorStartingInfo(ctx sdk.Context, val sdk.ValAddress, del sdk.AccAddress) (period types.DelegatorStartingInfo) { store := ctx.KVStore(k.storeKey) b := store.Get(types.GetDelegatorStartingInfoKey(val, del)) - k.cdc.MustUnmarshalBinaryBare(b, &period) + k.cdc.MustUnmarshal(b, &period) return } // set the starting info associated with a delegator func (k Keeper) SetDelegatorStartingInfo(ctx sdk.Context, val sdk.ValAddress, del sdk.AccAddress, period types.DelegatorStartingInfo) { store := ctx.KVStore(k.storeKey) - b := k.cdc.MustMarshalBinaryBare(&period) + b := k.cdc.MustMarshal(&period) store.Set(types.GetDelegatorStartingInfoKey(val, del), b) } @@ -116,7 +116,7 @@ func (k Keeper) IterateDelegatorStartingInfos(ctx sdk.Context, handler func(val defer iter.Close() for ; iter.Valid(); iter.Next() { var info types.DelegatorStartingInfo - k.cdc.MustUnmarshalBinaryBare(iter.Value(), &info) + k.cdc.MustUnmarshal(iter.Value(), &info) val, del := types.GetDelegatorStartingInfoAddresses(iter.Key()) if handler(val, del, info) { break @@ -128,14 +128,14 @@ func (k Keeper) IterateDelegatorStartingInfos(ctx sdk.Context, handler func(val func (k Keeper) GetValidatorHistoricalRewards(ctx sdk.Context, val sdk.ValAddress, period uint64) (rewards types.ValidatorHistoricalRewards) { store := ctx.KVStore(k.storeKey) b := store.Get(types.GetValidatorHistoricalRewardsKey(val, period)) - k.cdc.MustUnmarshalBinaryBare(b, &rewards) + k.cdc.MustUnmarshal(b, &rewards) return } // set historical rewards for a particular period func (k Keeper) SetValidatorHistoricalRewards(ctx sdk.Context, val sdk.ValAddress, period uint64, rewards types.ValidatorHistoricalRewards) { store := ctx.KVStore(k.storeKey) - b := k.cdc.MustMarshalBinaryBare(&rewards) + b := k.cdc.MustMarshal(&rewards) store.Set(types.GetValidatorHistoricalRewardsKey(val, period), b) } @@ -146,7 +146,7 @@ func (k Keeper) IterateValidatorHistoricalRewards(ctx sdk.Context, handler func( defer iter.Close() for ; iter.Valid(); iter.Next() { var rewards types.ValidatorHistoricalRewards - k.cdc.MustUnmarshalBinaryBare(iter.Value(), &rewards) + k.cdc.MustUnmarshal(iter.Value(), &rewards) addr, period := types.GetValidatorHistoricalRewardsAddressPeriod(iter.Key()) if handler(addr, period, rewards) { break @@ -187,7 +187,7 @@ func (k Keeper) GetValidatorHistoricalReferenceCount(ctx sdk.Context) (count uin defer iter.Close() for ; iter.Valid(); iter.Next() { var rewards types.ValidatorHistoricalRewards - k.cdc.MustUnmarshalBinaryBare(iter.Value(), &rewards) + k.cdc.MustUnmarshal(iter.Value(), &rewards) count += uint64(rewards.ReferenceCount) } return @@ -197,14 +197,14 @@ func (k Keeper) GetValidatorHistoricalReferenceCount(ctx sdk.Context) (count uin func (k Keeper) GetValidatorCurrentRewards(ctx sdk.Context, val sdk.ValAddress) (rewards types.ValidatorCurrentRewards) { store := ctx.KVStore(k.storeKey) b := store.Get(types.GetValidatorCurrentRewardsKey(val)) - k.cdc.MustUnmarshalBinaryBare(b, &rewards) + k.cdc.MustUnmarshal(b, &rewards) return } // set current rewards for a validator func (k Keeper) SetValidatorCurrentRewards(ctx sdk.Context, val sdk.ValAddress, rewards types.ValidatorCurrentRewards) { store := ctx.KVStore(k.storeKey) - b := k.cdc.MustMarshalBinaryBare(&rewards) + b := k.cdc.MustMarshal(&rewards) store.Set(types.GetValidatorCurrentRewardsKey(val), b) } @@ -221,7 +221,7 @@ func (k Keeper) IterateValidatorCurrentRewards(ctx sdk.Context, handler func(val defer iter.Close() for ; iter.Valid(); iter.Next() { var rewards types.ValidatorCurrentRewards - k.cdc.MustUnmarshalBinaryBare(iter.Value(), &rewards) + k.cdc.MustUnmarshal(iter.Value(), &rewards) addr := types.GetValidatorCurrentRewardsAddress(iter.Key()) if handler(addr, rewards) { break @@ -236,7 +236,7 @@ func (k Keeper) GetValidatorAccumulatedCommission(ctx sdk.Context, val sdk.ValAd if b == nil { return types.ValidatorAccumulatedCommission{} } - k.cdc.MustUnmarshalBinaryBare(b, &commission) + k.cdc.MustUnmarshal(b, &commission) return } @@ -246,9 +246,9 @@ func (k Keeper) SetValidatorAccumulatedCommission(ctx sdk.Context, val sdk.ValAd store := ctx.KVStore(k.storeKey) if commission.Commission.IsZero() { - bz = k.cdc.MustMarshalBinaryBare(&types.ValidatorAccumulatedCommission{}) + bz = k.cdc.MustMarshal(&types.ValidatorAccumulatedCommission{}) } else { - bz = k.cdc.MustMarshalBinaryBare(&commission) + bz = k.cdc.MustMarshal(&commission) } store.Set(types.GetValidatorAccumulatedCommissionKey(val), bz) @@ -267,7 +267,7 @@ func (k Keeper) IterateValidatorAccumulatedCommissions(ctx sdk.Context, handler defer iter.Close() for ; iter.Valid(); iter.Next() { var commission types.ValidatorAccumulatedCommission - k.cdc.MustUnmarshalBinaryBare(iter.Value(), &commission) + k.cdc.MustUnmarshal(iter.Value(), &commission) addr := types.GetValidatorAccumulatedCommissionAddress(iter.Key()) if handler(addr, commission) { break @@ -279,14 +279,14 @@ func (k Keeper) IterateValidatorAccumulatedCommissions(ctx sdk.Context, handler func (k Keeper) GetValidatorOutstandingRewards(ctx sdk.Context, val sdk.ValAddress) (rewards types.ValidatorOutstandingRewards) { store := ctx.KVStore(k.storeKey) bz := store.Get(types.GetValidatorOutstandingRewardsKey(val)) - k.cdc.MustUnmarshalBinaryBare(bz, &rewards) + k.cdc.MustUnmarshal(bz, &rewards) return } // set validator outstanding rewards func (k Keeper) SetValidatorOutstandingRewards(ctx sdk.Context, val sdk.ValAddress, rewards types.ValidatorOutstandingRewards) { store := ctx.KVStore(k.storeKey) - b := k.cdc.MustMarshalBinaryBare(&rewards) + b := k.cdc.MustMarshal(&rewards) store.Set(types.GetValidatorOutstandingRewardsKey(val), b) } @@ -303,7 +303,7 @@ func (k Keeper) IterateValidatorOutstandingRewards(ctx sdk.Context, handler func defer iter.Close() for ; iter.Valid(); iter.Next() { rewards := types.ValidatorOutstandingRewards{} - k.cdc.MustUnmarshalBinaryBare(iter.Value(), &rewards) + k.cdc.MustUnmarshal(iter.Value(), &rewards) addr := types.GetValidatorOutstandingRewardsAddress(iter.Key()) if handler(addr, rewards) { break @@ -318,14 +318,14 @@ func (k Keeper) GetValidatorSlashEvent(ctx sdk.Context, val sdk.ValAddress, heig if b == nil { return types.ValidatorSlashEvent{}, false } - k.cdc.MustUnmarshalBinaryBare(b, &event) + k.cdc.MustUnmarshal(b, &event) return event, true } // set slash event for height func (k Keeper) SetValidatorSlashEvent(ctx sdk.Context, val sdk.ValAddress, height, period uint64, event types.ValidatorSlashEvent) { store := ctx.KVStore(k.storeKey) - b := k.cdc.MustMarshalBinaryBare(&event) + b := k.cdc.MustMarshal(&event) store.Set(types.GetValidatorSlashEventKey(val, height, period), b) } @@ -340,7 +340,7 @@ func (k Keeper) IterateValidatorSlashEventsBetween(ctx sdk.Context, val sdk.ValA defer iter.Close() for ; iter.Valid(); iter.Next() { var event types.ValidatorSlashEvent - k.cdc.MustUnmarshalBinaryBare(iter.Value(), &event) + k.cdc.MustUnmarshal(iter.Value(), &event) _, height := types.GetValidatorSlashEventAddressHeight(iter.Key()) if handler(height, event) { break @@ -355,7 +355,7 @@ func (k Keeper) IterateValidatorSlashEvents(ctx sdk.Context, handler func(val sd defer iter.Close() for ; iter.Valid(); iter.Next() { var event types.ValidatorSlashEvent - k.cdc.MustUnmarshalBinaryBare(iter.Value(), &event) + k.cdc.MustUnmarshal(iter.Value(), &event) val, height := types.GetValidatorSlashEventAddressHeight(iter.Key()) if handler(val, height, event) { break diff --git a/x/distribution/legacy/v040/keys.go b/x/distribution/legacy/v040/keys.go new file mode 100644 index 0000000000..d95f7a9cec --- /dev/null +++ b/x/distribution/legacy/v040/keys.go @@ -0,0 +1,196 @@ +// Package v040 is copy-pasted from: +// https://github.com/cosmos/cosmos-sdk/blob/v0.41.0/x/distribution/types/keys.go +package v040 + +import ( + "encoding/binary" + + sdk "github.com/line/lbm-sdk/types" + v040auth "github.com/line/lbm-sdk/x/auth/legacy/v040" +) + +const ( + // ModuleName is the module name constant used in many places + ModuleName = "distribution" + + // StoreKey is the store key string for distribution + StoreKey = ModuleName + + // RouterKey is the message route for distribution + RouterKey = ModuleName + + // QuerierRoute is the querier route for distribution + QuerierRoute = ModuleName +) + +// Keys for distribution store +// Items are stored with the following key: values +// +// - 0x00: FeePol +// +// - 0x01: sdk.ConsAddress +// +// - 0x02: ValidatorOutstandingRewards +// +// - 0x03: sdk.AccAddress +// +// - 0x04: DelegatorStartingInfo +// +// - 0x05: ValidatorHistoricalRewards +// +// - 0x06: ValidatorCurrentRewards +// +// - 0x07: ValidatorCurrentRewards +// +// - 0x08: ValidatorSlashEvent +var ( + FeePoolKey = []byte{0x00} // key for global distribution state + ProposerKey = []byte{0x01} // key for the proposer operator address + ValidatorOutstandingRewardsPrefix = []byte{0x02} // key for outstanding rewards + + DelegatorWithdrawAddrPrefix = []byte{0x03} // key for delegator withdraw address + DelegatorStartingInfoPrefix = []byte{0x04} // key for delegator starting info + ValidatorHistoricalRewardsPrefix = []byte{0x05} // key for historical validators rewards / stake + ValidatorCurrentRewardsPrefix = []byte{0x06} // key for current validator rewards + ValidatorAccumulatedCommissionPrefix = []byte{0x07} // key for accumulated validator commission + ValidatorSlashEventPrefix = []byte{0x08} // key for validator slash fraction +) + +// gets an address from a validator's outstanding rewards key +func GetValidatorOutstandingRewardsAddress(key []byte) (valAddr sdk.ValAddress) { + addr := key[1:] + if len(addr) != v040auth.AddrLen { + panic("unexpected key length") + } + return sdk.ValAddress(addr) +} + +// gets an address from a delegator's withdraw info key +func GetDelegatorWithdrawInfoAddress(key []byte) (delAddr sdk.AccAddress) { + addr := key[1:] + if len(addr) != v040auth.AddrLen { + panic("unexpected key length") + } + return sdk.AccAddress(addr) +} + +// gets the addresses from a delegator starting info key +func GetDelegatorStartingInfoAddresses(key []byte) (valAddr sdk.ValAddress, delAddr sdk.AccAddress) { + addr := key[1 : 1+v040auth.AddrLen] + if len(addr) != v040auth.AddrLen { + panic("unexpected key length") + } + valAddr = sdk.ValAddress(addr) + addr = key[1+v040auth.AddrLen:] + if len(addr) != v040auth.AddrLen { + panic("unexpected key length") + } + delAddr = sdk.AccAddress(addr) + return +} + +// gets the address & period from a validator's historical rewards key +func GetValidatorHistoricalRewardsAddressPeriod(key []byte) (valAddr sdk.ValAddress, period uint64) { + addr := key[1 : 1+v040auth.AddrLen] + if len(addr) != v040auth.AddrLen { + panic("unexpected key length") + } + valAddr = sdk.ValAddress(addr) + b := key[1+v040auth.AddrLen:] + if len(b) != 8 { + panic("unexpected key length") + } + period = binary.LittleEndian.Uint64(b) + return +} + +// gets the address from a validator's current rewards key +func GetValidatorCurrentRewardsAddress(key []byte) (valAddr sdk.ValAddress) { + addr := key[1:] + if len(addr) != v040auth.AddrLen { + panic("unexpected key length") + } + return sdk.ValAddress(addr) +} + +// gets the address from a validator's accumulated commission key +func GetValidatorAccumulatedCommissionAddress(key []byte) (valAddr sdk.ValAddress) { + addr := key[1:] + if len(addr) != v040auth.AddrLen { + panic("unexpected key length") + } + return sdk.ValAddress(addr) +} + +// gets the height from a validator's slash event key +func GetValidatorSlashEventAddressHeight(key []byte) (valAddr sdk.ValAddress, height uint64) { + addr := key[1 : 1+v040auth.AddrLen] + if len(addr) != v040auth.AddrLen { + panic("unexpected key length") + } + valAddr = sdk.ValAddress(addr) + startB := 1 + v040auth.AddrLen + b := key[startB : startB+8] // the next 8 bytes represent the height + height = binary.BigEndian.Uint64(b) + return +} + +// gets the outstanding rewards key for a validator +func GetValidatorOutstandingRewardsKey(valAddr sdk.ValAddress) []byte { + return append(ValidatorOutstandingRewardsPrefix, valAddr.Bytes()...) +} + +// gets the key for a delegator's withdraw addr +func GetDelegatorWithdrawAddrKey(delAddr sdk.AccAddress) []byte { + return append(DelegatorWithdrawAddrPrefix, delAddr.Bytes()...) +} + +// gets the key for a delegator's starting info +func GetDelegatorStartingInfoKey(v sdk.ValAddress, d sdk.AccAddress) []byte { + return append(append(DelegatorStartingInfoPrefix, v.Bytes()...), d.Bytes()...) +} + +// gets the prefix key for a validator's historical rewards +func GetValidatorHistoricalRewardsPrefix(v sdk.ValAddress) []byte { + return append(ValidatorHistoricalRewardsPrefix, v.Bytes()...) +} + +// gets the key for a validator's historical rewards +func GetValidatorHistoricalRewardsKey(v sdk.ValAddress, k uint64) []byte { + b := make([]byte, 8) + binary.LittleEndian.PutUint64(b, k) + return append(append(ValidatorHistoricalRewardsPrefix, v.Bytes()...), b...) +} + +// gets the key for a validator's current rewards +func GetValidatorCurrentRewardsKey(v sdk.ValAddress) []byte { + return append(ValidatorCurrentRewardsPrefix, v.Bytes()...) +} + +// gets the key for a validator's current commission +func GetValidatorAccumulatedCommissionKey(v sdk.ValAddress) []byte { + return append(ValidatorAccumulatedCommissionPrefix, v.Bytes()...) +} + +// gets the prefix key for a validator's slash fractions +func GetValidatorSlashEventPrefix(v sdk.ValAddress) []byte { + return append(ValidatorSlashEventPrefix, v.Bytes()...) +} + +// gets the prefix key for a validator's slash fraction (ValidatorSlashEventPrefix + height) +func GetValidatorSlashEventKeyPrefix(v sdk.ValAddress, height uint64) []byte { + heightBz := make([]byte, 8) + binary.BigEndian.PutUint64(heightBz, height) + return append( + ValidatorSlashEventPrefix, + append(v.Bytes(), heightBz...)..., + ) +} + +// gets the key for a validator's slash fraction +func GetValidatorSlashEventKey(v sdk.ValAddress, height, period uint64) []byte { + periodBz := make([]byte, 8) + binary.BigEndian.PutUint64(periodBz, period) + prefix := GetValidatorSlashEventKeyPrefix(v, height) + return append(prefix, periodBz...) +} diff --git a/x/distribution/legacy/v043/helpers.go b/x/distribution/legacy/v043/helpers.go new file mode 100644 index 0000000000..cd1b098b0b --- /dev/null +++ b/x/distribution/legacy/v043/helpers.go @@ -0,0 +1,92 @@ +package v043 + +import ( + "github.com/line/lbm-sdk/store/prefix" + sdk "github.com/line/lbm-sdk/types" + "github.com/line/lbm-sdk/types/address" + v040auth "github.com/line/lbm-sdk/x/auth/legacy/v040" +) + +// MigratePrefixAddress is a helper function that migrates all keys of format: +// prefix_bytes | address_bytes +// into format: +// prefix_bytes | address_len (1 byte) | address_bytes +func MigratePrefixAddress(store sdk.KVStore, prefixBz []byte) { + oldStore := prefix.NewStore(store, prefixBz) + + oldStoreIter := oldStore.Iterator(nil, nil) + defer oldStoreIter.Close() + + for ; oldStoreIter.Valid(); oldStoreIter.Next() { + addr := oldStoreIter.Key() + var newStoreKey = prefixBz + newStoreKey = append(newStoreKey, address.MustLengthPrefix(addr)...) + + // Set new key on store. Values don't change. + store.Set(newStoreKey, oldStoreIter.Value()) + oldStore.Delete(oldStoreIter.Key()) + } +} + +// MigratePrefixAddressBytes is a helper function that migrates all keys of format: +// prefix_bytes | address_bytes | arbitrary_bytes +// into format: +// prefix_bytes | address_len (1 byte) | address_bytes | arbitrary_bytes +func MigratePrefixAddressBytes(store sdk.KVStore, prefixBz []byte) { + oldStore := prefix.NewStore(store, prefixBz) + + oldStoreIter := oldStore.Iterator(nil, nil) + defer oldStoreIter.Close() + + for ; oldStoreIter.Valid(); oldStoreIter.Next() { + addr := oldStoreIter.Key()[:v040auth.AddrLen] + endBz := oldStoreIter.Key()[v040auth.AddrLen:] + newStoreKey := append(append(prefixBz, address.MustLengthPrefix(addr)...), endBz...) + + // Set new key on store. Values don't change. + store.Set(newStoreKey, oldStoreIter.Value()) + oldStore.Delete(oldStoreIter.Key()) + } +} + +// MigratePrefixAddressAddress is a helper function that migrates all keys of format: +// prefix_bytes | address_1_bytes | address_2_bytes +// into format: +// prefix_bytes | address_1_len (1 byte) | address_1_bytes | address_2_len (1 byte) | address_2_bytes +func MigratePrefixAddressAddress(store sdk.KVStore, prefixBz []byte) { + oldStore := prefix.NewStore(store, prefixBz) + + oldStoreIter := oldStore.Iterator(nil, nil) + defer oldStoreIter.Close() + + for ; oldStoreIter.Valid(); oldStoreIter.Next() { + addr1 := oldStoreIter.Key()[:v040auth.AddrLen] + addr2 := oldStoreIter.Key()[v040auth.AddrLen:] + newStoreKey := append(append(prefixBz, address.MustLengthPrefix(addr1)...), address.MustLengthPrefix(addr2)...) + + // Set new key on store. Values don't change. + store.Set(newStoreKey, oldStoreIter.Value()) + oldStore.Delete(oldStoreIter.Key()) + } +} + +// MigratePrefixValAddressAddress is a helper function that migrates all keys of format: +// prefix_bytes | val_address_bytes | address_bytes +// into format: +// prefix_bytes | val_address_len (1 byte) | val_address_bytes | address_len (1 byte) | address_bytes +func MigratePrefixValAddressAddress(store sdk.KVStore, prefixBz []byte) { + oldStore := prefix.NewStore(store, prefixBz) + + oldStoreIter := oldStore.Iterator(nil, nil) + defer oldStoreIter.Close() + + for ; oldStoreIter.Valid(); oldStoreIter.Next() { + addr1 := oldStoreIter.Key()[:v040auth.ValAddrLen] + addr2 := oldStoreIter.Key()[v040auth.ValAddrLen:] + newStoreKey := append(append(prefixBz, address.MustLengthPrefix(addr1)...), address.MustLengthPrefix(addr2)...) + + // Set new key on store. Values don't change. + store.Set(newStoreKey, oldStoreIter.Value()) + oldStore.Delete(oldStoreIter.Key()) + } +} diff --git a/x/distribution/legacy/v043/store.go b/x/distribution/legacy/v043/store.go new file mode 100644 index 0000000000..f5067500d4 --- /dev/null +++ b/x/distribution/legacy/v043/store.go @@ -0,0 +1,23 @@ +package v043 + +import ( + sdk "github.com/line/lbm-sdk/types" + v040distribution "github.com/line/lbm-sdk/x/distribution/legacy/v040" +) + +// MigrateStore performs in-place store migrations from v0.40 to v0.43. The +// migration includes: +// +// - Change addresses to be length-prefixed. +func MigrateStore(ctx sdk.Context, storeKey sdk.StoreKey) error { + store := ctx.KVStore(storeKey) + MigratePrefixAddress(store, v040distribution.ValidatorOutstandingRewardsPrefix) + MigratePrefixAddress(store, v040distribution.DelegatorWithdrawAddrPrefix) + MigratePrefixAddressAddress(store, v040distribution.DelegatorStartingInfoPrefix) + MigratePrefixAddressBytes(store, v040distribution.ValidatorHistoricalRewardsPrefix) + MigratePrefixAddress(store, v040distribution.ValidatorCurrentRewardsPrefix) + MigratePrefixAddress(store, v040distribution.ValidatorAccumulatedCommissionPrefix) + MigratePrefixAddressBytes(store, v040distribution.ValidatorSlashEventPrefix) + + return nil +} diff --git a/x/distribution/legacy/v043/store_test.go b/x/distribution/legacy/v043/store_test.go new file mode 100644 index 0000000000..71a9bef78f --- /dev/null +++ b/x/distribution/legacy/v043/store_test.go @@ -0,0 +1,99 @@ +package v043_test + +import ( + "bytes" + "testing" + + "github.com/stretchr/testify/require" + + "github.com/line/lbm-sdk/testutil" + "github.com/line/lbm-sdk/testutil/testdata" + sdk "github.com/line/lbm-sdk/types" + v040distribution "github.com/line/lbm-sdk/x/distribution/legacy/v040" + v043distribution "github.com/line/lbm-sdk/x/distribution/legacy/v043" + "github.com/line/lbm-sdk/x/distribution/types" +) + +func TestStoreMigration(t *testing.T) { + distributionKey := sdk.NewKVStoreKey("distribution") + ctx := testutil.DefaultContext(distributionKey, sdk.NewTransientStoreKey("transient_test")) + store := ctx.KVStore(distributionKey) + + _, _, addr1 := testdata.KeyTestPubAddr() + valAddr := sdk.ValAddress(addr1) + _, _, addr2 := testdata.KeyTestPubAddr() + // Use dummy value for all keys. + value := []byte("foo") + + testCases := []struct { + name string + oldKey []byte + newKey []byte + }{ + { + "FeePoolKey", + v040distribution.FeePoolKey, + types.FeePoolKey, + }, + { + "ProposerKey", + v040distribution.ProposerKey, + types.ProposerKey, + }, + { + "ValidatorOutstandingRewards", + v040distribution.GetValidatorOutstandingRewardsKey(valAddr), + types.GetValidatorOutstandingRewardsKey(valAddr), + }, + { + "DelegatorWithdrawAddr", + v040distribution.GetDelegatorWithdrawAddrKey(addr2), + types.GetDelegatorWithdrawAddrKey(addr2), + }, + { + "DelegatorStartingInfo", + v040distribution.GetDelegatorStartingInfoKey(valAddr, addr2), + types.GetDelegatorStartingInfoKey(valAddr, addr2), + }, + { + "ValidatorHistoricalRewards", + v040distribution.GetValidatorHistoricalRewardsKey(valAddr, 6), + types.GetValidatorHistoricalRewardsKey(valAddr, 6), + }, + { + "ValidatorCurrentRewards", + v040distribution.GetValidatorCurrentRewardsKey(valAddr), + types.GetValidatorCurrentRewardsKey(valAddr), + }, + { + "ValidatorAccumulatedCommission", + v040distribution.GetValidatorAccumulatedCommissionKey(valAddr), + types.GetValidatorAccumulatedCommissionKey(valAddr), + }, + { + "ValidatorSlashEvent", + v040distribution.GetValidatorSlashEventKey(valAddr, 6, 8), + types.GetValidatorSlashEventKey(valAddr, 6, 8), + }, + } + + // Set all the old keys to the store + for _, tc := range testCases { + store.Set(tc.oldKey, value) + } + + // Run migrations. + err := v043distribution.MigrateStore(ctx, distributionKey) + require.NoError(t, err) + + // Make sure the new keys are set and old keys are deleted. + for _, tc := range testCases { + tc := tc + t.Run(tc.name, func(t *testing.T) { + if !bytes.Equal(tc.oldKey, tc.newKey) { + require.Nil(t, store.Get(tc.oldKey)) + } + require.Equal(t, value, store.Get(tc.newKey)) + }) + } +} diff --git a/x/distribution/module.go b/x/distribution/module.go index 489dabf2a0..10d659bd19 100644 --- a/x/distribution/module.go +++ b/x/distribution/module.go @@ -34,7 +34,7 @@ var ( // AppModuleBasic defines the basic application module used by the distribution module. type AppModuleBasic struct { - cdc codec.Marshaler + cdc codec.Codec } // Name returns the distribution module's name. @@ -49,12 +49,12 @@ func (AppModuleBasic) RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) { // DefaultGenesis returns default genesis state as raw bytes for the distribution // module. -func (AppModuleBasic) DefaultGenesis(cdc codec.JSONMarshaler) json.RawMessage { +func (AppModuleBasic) DefaultGenesis(cdc codec.JSONCodec) json.RawMessage { return cdc.MustMarshalJSON(types.DefaultGenesisState()) } // ValidateGenesis performs genesis state validation for the distribution module. -func (AppModuleBasic) ValidateGenesis(cdc codec.JSONMarshaler, config sdkclient.TxEncodingConfig, bz json.RawMessage) error { +func (AppModuleBasic) ValidateGenesis(cdc codec.JSONCodec, config sdkclient.TxEncodingConfig, bz json.RawMessage) error { var data types.GenesisState if err := cdc.UnmarshalJSON(bz, &data); err != nil { return fmt.Errorf("failed to unmarshal %s genesis state: %w", types.ModuleName, err) @@ -88,8 +88,6 @@ func (b AppModuleBasic) RegisterInterfaces(registry cdctypes.InterfaceRegistry) types.RegisterInterfaces(registry) } -// ____________________________________________________________________________ - // AppModule implements an application module for the distribution module. type AppModule struct { AppModuleBasic @@ -102,7 +100,7 @@ type AppModule struct { // NewAppModule creates a new AppModule object func NewAppModule( - cdc codec.Marshaler, keeper keeper.Keeper, accountKeeper types.AccountKeeper, + cdc codec.Codec, keeper keeper.Keeper, accountKeeper types.AccountKeeper, bankKeeper types.BankKeeper, stakingKeeper stakingkeeper.Keeper, ) AppModule { return AppModule{ @@ -152,7 +150,7 @@ func (am AppModule) RegisterServices(cfg module.Configurator) { // InitGenesis performs genesis initialization for the distribution module. It returns // no validator updates. -func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONMarshaler, data json.RawMessage) []abci.ValidatorUpdate { +func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONCodec, data json.RawMessage) []abci.ValidatorUpdate { var genesisState types.GenesisState cdc.MustUnmarshalJSON(data, &genesisState) am.keeper.InitGenesis(ctx, genesisState) @@ -161,7 +159,7 @@ func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONMarshaler, data j // ExportGenesis returns the exported genesis state as raw bytes for the distribution // module. -func (am AppModule) ExportGenesis(ctx sdk.Context, cdc codec.JSONMarshaler) json.RawMessage { +func (am AppModule) ExportGenesis(ctx sdk.Context, cdc codec.JSONCodec) json.RawMessage { gs := am.keeper.ExportGenesis(ctx) return cdc.MustMarshalJSON(gs) } @@ -180,8 +178,6 @@ func (AppModule) EndBlock(_ sdk.Context, _ abci.RequestEndBlock) []abci.Validato return []abci.ValidatorUpdate{} } -// ____________________________________________________________________________ - // AppModuleSimulation functions // GenerateGenesisState creates a randomized GenState of the distribution module. diff --git a/x/distribution/proposal_handler_test.go b/x/distribution/proposal_handler_test.go index e0e7790ce5..e33578da37 100644 --- a/x/distribution/proposal_handler_test.go +++ b/x/distribution/proposal_handler_test.go @@ -33,8 +33,7 @@ func TestProposalHandlerPassed(t *testing.T) { // add coins to the module account macc := app.DistrKeeper.GetDistributionAccount(ctx) balances := app.BankKeeper.GetAllBalances(ctx, macc.GetAddress()) - err := app.BankKeeper.SetBalances(ctx, macc.GetAddress(), balances.Add(amount...)) - require.NoError(t, err) + require.NoError(t, simapp.FundModuleAccount(app, ctx, macc.GetName(), amount)) app.AccountKeeper.SetModuleAccount(ctx, macc) diff --git a/x/distribution/simulation/decoder.go b/x/distribution/simulation/decoder.go index 2e2761c04a..a125db75eb 100644 --- a/x/distribution/simulation/decoder.go +++ b/x/distribution/simulation/decoder.go @@ -12,13 +12,13 @@ import ( // NewDecodeStore returns a decoder function closure that unmarshals the KVPair's // Value to the corresponding distribution type. -func NewDecodeStore(cdc codec.Marshaler) func(kvA, kvB kv.Pair) string { +func NewDecodeStore(cdc codec.Codec) func(kvA, kvB kv.Pair) string { return func(kvA, kvB kv.Pair) string { switch { case bytes.Equal(kvA.Key[:1], types.FeePoolKey): var feePoolA, feePoolB types.FeePool - cdc.MustUnmarshalBinaryBare(kvA.Value, &feePoolA) - cdc.MustUnmarshalBinaryBare(kvB.Value, &feePoolB) + cdc.MustUnmarshal(kvA.Value, &feePoolA) + cdc.MustUnmarshal(kvB.Value, &feePoolB) return fmt.Sprintf("%v\n%v", feePoolA, feePoolB) case bytes.Equal(kvA.Key[:1], types.ProposerKey): @@ -26,8 +26,8 @@ func NewDecodeStore(cdc codec.Marshaler) func(kvA, kvB kv.Pair) string { case bytes.Equal(kvA.Key[:1], types.ValidatorOutstandingRewardsPrefix): var rewardsA, rewardsB types.ValidatorOutstandingRewards - cdc.MustUnmarshalBinaryBare(kvA.Value, &rewardsA) - cdc.MustUnmarshalBinaryBare(kvB.Value, &rewardsB) + cdc.MustUnmarshal(kvA.Value, &rewardsA) + cdc.MustUnmarshal(kvB.Value, &rewardsB) return fmt.Sprintf("%v\n%v", rewardsA, rewardsB) case bytes.Equal(kvA.Key[:1], types.DelegatorWithdrawAddrPrefix): @@ -35,32 +35,32 @@ func NewDecodeStore(cdc codec.Marshaler) func(kvA, kvB kv.Pair) string { case bytes.Equal(kvA.Key[:1], types.DelegatorStartingInfoPrefix): var infoA, infoB types.DelegatorStartingInfo - cdc.MustUnmarshalBinaryBare(kvA.Value, &infoA) - cdc.MustUnmarshalBinaryBare(kvB.Value, &infoB) + cdc.MustUnmarshal(kvA.Value, &infoA) + cdc.MustUnmarshal(kvB.Value, &infoB) return fmt.Sprintf("%v\n%v", infoA, infoB) case bytes.Equal(kvA.Key[:1], types.ValidatorHistoricalRewardsPrefix): var rewardsA, rewardsB types.ValidatorHistoricalRewards - cdc.MustUnmarshalBinaryBare(kvA.Value, &rewardsA) - cdc.MustUnmarshalBinaryBare(kvB.Value, &rewardsB) + cdc.MustUnmarshal(kvA.Value, &rewardsA) + cdc.MustUnmarshal(kvB.Value, &rewardsB) return fmt.Sprintf("%v\n%v", rewardsA, rewardsB) case bytes.Equal(kvA.Key[:1], types.ValidatorCurrentRewardsPrefix): var rewardsA, rewardsB types.ValidatorCurrentRewards - cdc.MustUnmarshalBinaryBare(kvA.Value, &rewardsA) - cdc.MustUnmarshalBinaryBare(kvB.Value, &rewardsB) + cdc.MustUnmarshal(kvA.Value, &rewardsA) + cdc.MustUnmarshal(kvB.Value, &rewardsB) return fmt.Sprintf("%v\n%v", rewardsA, rewardsB) case bytes.Equal(kvA.Key[:1], types.ValidatorAccumulatedCommissionPrefix): var commissionA, commissionB types.ValidatorAccumulatedCommission - cdc.MustUnmarshalBinaryBare(kvA.Value, &commissionA) - cdc.MustUnmarshalBinaryBare(kvB.Value, &commissionB) + cdc.MustUnmarshal(kvA.Value, &commissionA) + cdc.MustUnmarshal(kvB.Value, &commissionB) return fmt.Sprintf("%v\n%v", commissionA, commissionB) case bytes.Equal(kvA.Key[:1], types.ValidatorSlashEventPrefix): var eventA, eventB types.ValidatorSlashEvent - cdc.MustUnmarshalBinaryBare(kvA.Value, &eventA) - cdc.MustUnmarshalBinaryBare(kvB.Value, &eventB) + cdc.MustUnmarshal(kvA.Value, &eventA) + cdc.MustUnmarshal(kvB.Value, &eventB) return fmt.Sprintf("%v\n%v", eventA, eventB) default: diff --git a/x/distribution/simulation/decoder_test.go b/x/distribution/simulation/decoder_test.go index 546a22c12b..6ba7ec0861 100644 --- a/x/distribution/simulation/decoder_test.go +++ b/x/distribution/simulation/decoder_test.go @@ -22,7 +22,7 @@ var ( ) func TestDecodeDistributionStore(t *testing.T) { - cdc, _ := simapp.MakeCodecs() + cdc := simapp.MakeTestEncodingConfig().Marshaler dec := simulation.NewDecodeStore(cdc) decCoins := sdk.DecCoins{sdk.NewDecCoinFromDec(sdk.DefaultBondDenom, sdk.OneDec())} @@ -37,15 +37,15 @@ func TestDecodeDistributionStore(t *testing.T) { kvPairs := kv.Pairs{ Pairs: []kv.Pair{ - {Key: types.FeePoolKey, Value: cdc.MustMarshalBinaryBare(&feePool)}, + {Key: types.FeePoolKey, Value: cdc.MustMarshal(&feePool)}, {Key: types.ProposerKey, Value: consAddr1.Bytes()}, - {Key: types.GetValidatorOutstandingRewardsKey(valAddr1), Value: cdc.MustMarshalBinaryBare(&outstanding)}, + {Key: types.GetValidatorOutstandingRewardsKey(valAddr1), Value: cdc.MustMarshal(&outstanding)}, {Key: types.GetDelegatorWithdrawAddrKey(delAddr1), Value: delAddr1.Bytes()}, - {Key: types.GetDelegatorStartingInfoKey(valAddr1, delAddr1), Value: cdc.MustMarshalBinaryBare(&info)}, - {Key: types.GetValidatorHistoricalRewardsKey(valAddr1, 100), Value: cdc.MustMarshalBinaryBare(&historicalRewards)}, - {Key: types.GetValidatorCurrentRewardsKey(valAddr1), Value: cdc.MustMarshalBinaryBare(¤tRewards)}, - {Key: types.GetValidatorAccumulatedCommissionKey(valAddr1), Value: cdc.MustMarshalBinaryBare(&commission)}, - {Key: types.GetValidatorSlashEventKeyPrefix(valAddr1, 13), Value: cdc.MustMarshalBinaryBare(&slashEvent)}, + {Key: types.GetDelegatorStartingInfoKey(valAddr1, delAddr1), Value: cdc.MustMarshal(&info)}, + {Key: types.GetValidatorHistoricalRewardsKey(valAddr1, 100), Value: cdc.MustMarshal(&historicalRewards)}, + {Key: types.GetValidatorCurrentRewardsKey(valAddr1), Value: cdc.MustMarshal(¤tRewards)}, + {Key: types.GetValidatorAccumulatedCommissionKey(valAddr1), Value: cdc.MustMarshal(&commission)}, + {Key: types.GetValidatorSlashEventKeyPrefix(valAddr1, 13), Value: cdc.MustMarshal(&slashEvent)}, {Key: []byte{0x99}, Value: []byte{0x99}}, }, } diff --git a/x/distribution/simulation/operations.go b/x/distribution/simulation/operations.go index 5149ea899d..f8f84f7c61 100644 --- a/x/distribution/simulation/operations.go +++ b/x/distribution/simulation/operations.go @@ -6,7 +6,6 @@ import ( "github.com/line/lbm-sdk/baseapp" "github.com/line/lbm-sdk/codec" - "github.com/line/lbm-sdk/simapp/helpers" simappparams "github.com/line/lbm-sdk/simapp/params" sdk "github.com/line/lbm-sdk/types" simtypes "github.com/line/lbm-sdk/types/simulation" @@ -16,6 +15,7 @@ import ( stakingkeeper "github.com/line/lbm-sdk/x/staking/keeper" ) +// nolint:gosec // Simulation operation weights constants const ( OpWeightMsgSetWithdrawAddress = "op_weight_msg_set_withdraw_address" @@ -26,7 +26,7 @@ const ( // WeightedOperations returns all the operations from the module with their respective weights func WeightedOperations( - appParams simtypes.AppParams, cdc codec.JSONMarshaler, ak types.AccountKeeper, + appParams simtypes.AppParams, cdc codec.JSONCodec, ak types.AccountKeeper, bk types.BankKeeper, k keeper.Keeper, sk stakingkeeper.Keeper, ) simulation.WeightedOperations { @@ -93,34 +93,24 @@ func SimulateMsgSetWithdrawAddress(ak types.AccountKeeper, bk types.BankKeeper, account := ak.GetAccount(ctx, simAccount.Address) spendable := bk.SpendableCoins(ctx, account.GetAddress()) - fees, err := simtypes.RandomFees(r, ctx, spendable) - if err != nil { - return simtypes.NoOpMsg(types.ModuleName, types.TypeMsgSetWithdrawAddress, "unable to generate fees"), nil, err - } - msg := types.NewMsgSetWithdrawAddress(simAccount.Address, simToAccount.Address) - txGen := simappparams.MakeTestEncodingConfig().TxConfig - tx, err := helpers.GenTx( - txGen, - []sdk.Msg{msg}, - fees, - helpers.DefaultGenTxGas, - chainID, - []uint64{account.GetAccountNumber()}, - []uint64{account.GetSequence()}, - simAccount.PrivKey, - ) - if err != nil { - return simtypes.NoOpMsg(types.ModuleName, msg.Type(), "unable to generate mock tx"), nil, err - } - - _, _, err = app.Deliver(txGen.TxEncoder(), tx) - if err != nil { - return simtypes.NoOpMsg(types.ModuleName, msg.Type(), "unable to deliver tx"), nil, err - } - - return simtypes.NewOperationMsg(msg, true, ""), nil, nil + txCtx := simulation.OperationInput{ + R: r, + App: app, + TxGen: simappparams.MakeTestEncodingConfig().TxConfig, + Cdc: nil, + Msg: msg, + MsgType: msg.Type(), + Context: ctx, + SimAccount: simAccount, + AccountKeeper: ak, + Bankkeeper: bk, + ModuleName: types.ModuleName, + CoinsSpentInMsg: spendable, + } + + return simulation.GenAndDeliverTxWithRandFees(txCtx) } } @@ -145,34 +135,24 @@ func SimulateMsgWithdrawDelegatorReward(ak types.AccountKeeper, bk types.BankKee account := ak.GetAccount(ctx, simAccount.Address) spendable := bk.SpendableCoins(ctx, account.GetAddress()) - fees, err := simtypes.RandomFees(r, ctx, spendable) - if err != nil { - return simtypes.NoOpMsg(types.ModuleName, types.TypeMsgWithdrawDelegatorReward, "unable to generate fees"), nil, err - } - msg := types.NewMsgWithdrawDelegatorReward(simAccount.Address, validator.GetOperator()) - txGen := simappparams.MakeTestEncodingConfig().TxConfig - tx, err := helpers.GenTx( - txGen, - []sdk.Msg{msg}, - fees, - helpers.DefaultGenTxGas, - chainID, - []uint64{account.GetAccountNumber()}, - []uint64{account.GetSequence()}, - simAccount.PrivKey, - ) - if err != nil { - return simtypes.NoOpMsg(types.ModuleName, msg.Type(), "unable to generate mock tx"), nil, err - } - - _, _, err = app.Deliver(txGen.TxEncoder(), tx) - if err != nil { - return simtypes.NoOpMsg(types.ModuleName, msg.Type(), "unable to deliver tx"), nil, err - } - - return simtypes.NewOperationMsg(msg, true, ""), nil, nil + txCtx := simulation.OperationInput{ + R: r, + App: app, + TxGen: simappparams.MakeTestEncodingConfig().TxConfig, + Cdc: nil, + Msg: msg, + MsgType: msg.Type(), + Context: ctx, + SimAccount: simAccount, + AccountKeeper: ak, + Bankkeeper: bk, + ModuleName: types.ModuleName, + CoinsSpentInMsg: spendable, + } + + return simulation.GenAndDeliverTxWithRandFees(txCtx) } } @@ -200,34 +180,24 @@ func SimulateMsgWithdrawValidatorCommission(ak types.AccountKeeper, bk types.Ban account := ak.GetAccount(ctx, simAccount.Address) spendable := bk.SpendableCoins(ctx, account.GetAddress()) - fees, err := simtypes.RandomFees(r, ctx, spendable) - if err != nil { - return simtypes.NoOpMsg(types.ModuleName, types.TypeMsgWithdrawValidatorCommission, "unable to generate fees"), nil, err - } - msg := types.NewMsgWithdrawValidatorCommission(validator.GetOperator()) - txGen := simappparams.MakeTestEncodingConfig().TxConfig - tx, err := helpers.GenTx( - txGen, - []sdk.Msg{msg}, - fees, - helpers.DefaultGenTxGas, - chainID, - []uint64{account.GetAccountNumber()}, - []uint64{account.GetSequence()}, - simAccount.PrivKey, - ) - if err != nil { - return simtypes.NoOpMsg(types.ModuleName, msg.Type(), "unable to generate mock tx"), nil, err - } - - _, _, err = app.Deliver(txGen.TxEncoder(), tx) - if err != nil { - return simtypes.NoOpMsg(types.ModuleName, msg.Type(), "unable to deliver tx"), nil, err - } - - return simtypes.NewOperationMsg(msg, true, ""), nil, nil + txCtx := simulation.OperationInput{ + R: r, + App: app, + TxGen: simappparams.MakeTestEncodingConfig().TxConfig, + Cdc: nil, + Msg: msg, + MsgType: msg.Type(), + Context: ctx, + SimAccount: simAccount, + AccountKeeper: ak, + Bankkeeper: bk, + ModuleName: types.ModuleName, + CoinsSpentInMsg: spendable, + } + + return simulation.GenAndDeliverTxWithRandFees(txCtx) } } @@ -262,26 +232,19 @@ func SimulateMsgFundCommunityPool(ak types.AccountKeeper, bk types.BankKeeper, k } msg := types.NewMsgFundCommunityPool(fundAmount, funder.Address) - txGen := simappparams.MakeTestEncodingConfig().TxConfig - tx, err := helpers.GenTx( - txGen, - []sdk.Msg{msg}, - fees, - helpers.DefaultGenTxGas, - chainID, - []uint64{account.GetAccountNumber()}, - []uint64{account.GetSequence()}, - funder.PrivKey, - ) - if err != nil { - return simtypes.NoOpMsg(types.ModuleName, msg.Type(), "unable to generate mock tx"), nil, err - } - _, _, err = app.Deliver(txGen.TxEncoder(), tx) - if err != nil { - return simtypes.NoOpMsg(types.ModuleName, msg.Type(), "unable to deliver tx"), nil, err + txCtx := simulation.OperationInput{ + App: app, + TxGen: simappparams.MakeTestEncodingConfig().TxConfig, + Cdc: nil, + Msg: msg, + MsgType: msg.Type(), + Context: ctx, + SimAccount: funder, + AccountKeeper: ak, + ModuleName: types.ModuleName, } - return simtypes.NewOperationMsg(msg, true, ""), nil, nil + return simulation.GenAndDeliverTx(txCtx, fees) } } diff --git a/x/distribution/simulation/operations_test.go b/x/distribution/simulation/operations_test.go index ebf1d48a18..e6f1dcae06 100644 --- a/x/distribution/simulation/operations_test.go +++ b/x/distribution/simulation/operations_test.go @@ -95,7 +95,7 @@ func (suite *SimTestSuite) TestSimulateMsgWithdrawDelegatorReward() { validator0 := suite.getTestingValidator0(accounts) // setup delegation - delTokens := sdk.TokensFromConsensusPower(2) + delTokens := suite.app.StakingKeeper.TokensFromConsensusPower(suite.ctx, 2) validator0, issuedShares := validator0.AddTokensFromDel(delTokens) delegator := accounts[1] delegation := stakingtypes.NewDelegation(delegator.Address, validator0.GetOperator(), issuedShares) @@ -143,11 +143,10 @@ func (suite *SimTestSuite) testSimulateMsgWithdrawValidatorCommission(tokenName // set module account coins distrAcc := suite.app.DistrKeeper.GetDistributionAccount(suite.ctx) - err := suite.app.BankKeeper.SetBalances(suite.ctx, distrAcc.GetAddress(), sdk.NewCoins( + suite.Require().NoError(simapp.FundModuleAccount(suite.app, suite.ctx, distrAcc.GetName(), sdk.NewCoins( sdk.NewCoin(tokenName, sdk.NewInt(10)), sdk.NewCoin("stake", sdk.NewInt(5)), - )) - suite.Require().NoError(err) + ))) suite.app.AccountKeeper.SetModuleAccount(suite.ctx, distrAcc) // set outstanding rewards @@ -223,15 +222,14 @@ func (suite *SimTestSuite) SetupTest() { func (suite *SimTestSuite) getTestingAccounts(r *rand.Rand, n int) []simtypes.Account { accounts := simtypes.RandomAccounts(r, n) - initAmt := sdk.TokensFromConsensusPower(200) + initAmt := suite.app.StakingKeeper.TokensFromConsensusPower(suite.ctx, 200) initCoins := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, initAmt)) // add coins to the accounts for _, account := range accounts { acc := suite.app.AccountKeeper.NewAccountWithAddress(suite.ctx, account.Address) suite.app.AccountKeeper.SetAccount(suite.ctx, acc) - err := suite.app.BankKeeper.SetBalances(suite.ctx, account.Address, initCoins) - suite.Require().NoError(err) + suite.Require().NoError(simapp.FundAccount(suite.app, suite.ctx, account.Address, initCoins)) } return accounts diff --git a/x/distribution/spec/01_concepts.md b/x/distribution/spec/01_concepts.md index 70c684690c..6bef259f16 100644 --- a/x/distribution/spec/01_concepts.md +++ b/x/distribution/spec/01_concepts.md @@ -4,11 +4,21 @@ order: 1 # Concepts +In Proof of Stake (PoS) blockchains, rewards gained from transaction fees are paid to validators. The fee distribution module fairly distributes the rewards to the validators' constituent delegators. + +Rewards are calculated per period. The period is updated each time a validator's delegation changes, for example, when the validator receives a new delegation. +The rewards for a single validator can then be calculated by taking the total rewards for the period before the delegation started, minus the current total rewards. +To learn more, see the [F1 Fee Distribution paper](/docs/spec/fee_distribution/f1_fee_distr.pdf). + +The commission to the validator is paid when the validator is removed or when the validator requests a withdrawal. +The commission is calculated and incremented at every `BeginBlock` operation to update accumulated fee amounts. + +The rewards to a delegator are distributed when the delegation is changed or removed, or a withdrawal is requested. +Before rewards are distributed, all slashes to the validator that occurred during the current delegation are applied. + ## Reference Counting in F1 Fee Distribution -In F1 fee distribution, in order to calculate the rewards a delegator ought to receive when they -withdraw their delegation, we must read the terms of the summation of rewards divided by tokens from -the period which they ended when they delegated, and the final period (created when they withdraw). +In F1 fee distribution, the rewards a delegator receives are calculated when their delegation is withdrawn. This calculation must read the terms of the summation of rewards divided by the share of tokens from the period which they ended when they delegated, and the final period that was created for the withdrawal. Additionally, as slashes change the amount of tokens a delegation will have (but we calculate this lazily, only when a delegator un-delegates), we must calculate rewards in separate periods before / after any slashes diff --git a/x/distribution/spec/02_state.md b/x/distribution/spec/02_state.md index 7dd01fd6cc..df85f3f7ed 100644 --- a/x/distribution/spec/02_state.md +++ b/x/distribution/spec/02_state.md @@ -27,16 +27,16 @@ type DecCoin struct { } ``` -+++ https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/distribution/v1/distribution.proto#L94-L101 ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/distribution/v1beta1/distribution.proto#L94-L101 ## Validator Distribution Validator distribution information for the relevant validator is updated each time: - 1. delegation amount to a validator is updated, - 2. a validator successfully proposes a block and receives a reward, - 3. any delegator withdraws from a validator, or - 4. the validator withdraws it's commission. +1. delegation amount to a validator is updated, +2. a validator successfully proposes a block and receives a reward, +3. any delegator withdraws from a validator, or +4. the validator withdraws its commission. - ValidatorDistInfo: `0x02 | ValOperatorAddrLen (1 byte) | ValOperatorAddr -> ProtocolBuffer(validatorDistribution)` diff --git a/x/distribution/spec/03_begin_block.md b/x/distribution/spec/03_begin_block.md new file mode 100644 index 0000000000..bf279759da --- /dev/null +++ b/x/distribution/spec/03_begin_block.md @@ -0,0 +1,87 @@ + + +# Begin Block + +At each `BeginBlock`, all fees received in the previous block are transferred to +the distribution `ModuleAccount` account. When a delegator or validator +withdraws their rewards, they are taken out of the `ModuleAccount`. During begin +block, the different claims on the fees collected are updated as follows: + +- The block proposer of the previous height and its delegators receive between 1% and 5% of fee rewards. +- The reserve community tax is charged. +- The remainder is distributed proportionally by voting power to all bonded validators + +To incentivize validators to wait and include additional pre-commits in the block, the block proposer reward is calculated from Tendermint pre-commit messages. + +## The Distribution Scheme + +See [params](07_params.md) for description of parameters. + +Let `fees` be the total fees collected in the previous block, including +inflationary rewards to the stake. All fees are collected in a specific module +account during the block. During `BeginBlock`, they are sent to the +`"distribution"` `ModuleAccount`. No other sending of tokens occurs. Instead, the +rewards each account is entitled to are stored, and withdrawals can be triggered +through the messages `FundCommunityPool`, `WithdrawValidatorCommission` and +`WithdrawDelegatorReward`. + +### Reward to the Community Pool + +The community pool gets `community_tax * fees`, plus any remaining dust after +validators get their rewards that are always rounded down to the nearest +integer value. + +### Reward To the Validators + +The proposer receives a base reward of `fees * baseproposerreward` and a bonus +of `fees * bonusproposerreward * P`, where `P = (total power of validators with +included precommits / total bonded validator power)`. The more precommits the +proposer includes, the larger `P` is. `P` can never be larger than `1.00` (since +only bonded validators can supply valid precommits) and is always larger than +`2/3`. + +Any remaining fees are distributed among all the bonded validators, including +the proposer, in proportion to their consensus power. + +``` +powFrac = validator power / total bonded validator power +proposerMul = baseproposerreward + bonusproposerreward * P +voteMul = 1 - communitytax - proposerMul +``` + +In total, the proposer receives `fees * (voteMul * powFrac + proposerMul)`. +All other validators receive `fees * voteMul * powFrac`. + +### Rewards to Delegators + +Each validator's rewards are distributed to its delegators. The validator also +has a self-delegation that is treated like a regular delegation in +distribution calculations. + +The validator sets a commission rate. The commission rate is flexible, but each +validator sets a maximum rate and a maximum daily increase. These maximums cannot be exceeded and protect delegators from sudden increases of validator commission rates to prevent validators from taking all of the rewards. + +The outstanding rewards that the operator is entitled to are stored in +`ValidatorAccumulatedCommission`, while the rewards the delegators are entitled +to are stored in `ValidatorCurrentRewards`. The [F1 fee distribution +scheme](01_concepts.md) is used to calculate the rewards per delegator as they +withdraw or update their delegation, and is thus not handled in `BeginBlock`. + +### Example Distribution + +For this example distribution, the underlying consensus engine selects block proposers in +proportion to their power relative to the entire bonded power. + +All validators are equally performant at including pre-commits in their proposed +blocks. Then hold `(precommits included) / (total bonded validator power)` +constant so that the amortized block reward for the validator is `( validator power / total bonded power) * (1 - community tax rate)` of +the total rewards. Consequently, the reward for a single delegator is: + +``` +(delegator proportion of the validator power / validator power) * (validator power / total bonded power) + * (1 - community tax rate) * (1 - validator commision rate) += (delegator proportion of the validator power / total bonded power) * (1 - +community tax rate) * (1 - validator commision rate) +``` diff --git a/x/distribution/spec/03_end_block.md b/x/distribution/spec/03_end_block.md deleted file mode 100644 index c5f8d655a5..0000000000 --- a/x/distribution/spec/03_end_block.md +++ /dev/null @@ -1,33 +0,0 @@ - - -# End Block - -At each `EndBlock`, the fees received are transferred to the distribution `ModuleAccount`, as it's the account the one who keeps track of the flow of coins in (as in this case) and out the module. The fees are also allocated to the proposer, community fund and global pool. When the validator is the proposer of the round, that validator (and their delegators) receives between 1% and 5% of fee rewards, the reserve community tax is then charged, then the remainder is distributed proportionally by voting power to all bonded validators independent of whether they voted (social distribution). Note the social distribution is applied to proposer validator in addition to the proposer reward. - -The amount of proposer reward is calculated from pre-commits Tendermint messages in order to incentivize validators to wait and include additional pre-commits in the block. All provision rewards are added to a provision reward pool which validator holds individually (`ValidatorDistribution.ProvisionsRewardPool`). - -```go -func AllocateTokens(feesCollected sdk.Coins, feePool FeePool, proposer ValidatorDistribution, - sumPowerPrecommitValidators, totalBondedTokens, communityTax, - proposerCommissionRate sdk.Dec) - - SendCoins(FeeCollectorAddr, DistributionModuleAccAddr, feesCollected) - feesCollectedDec = MakeDecCoins(feesCollected) - proposerReward = feesCollectedDec * (0.01 + 0.04 - * sumPowerPrecommitValidators / totalBondedTokens) - - commission = proposerReward * proposerCommissionRate - proposer.PoolCommission += commission - proposer.Pool += proposerReward - commission - - communityFunding = feesCollectedDec * communityTax - feePool.CommunityFund += communityFunding - - poolReceived = feesCollectedDec - proposerReward - communityFunding - feePool.Pool += poolReceived - - SetValidatorDistribution(proposer) - SetFeePool(feePool) -``` diff --git a/x/distribution/spec/04_messages.md b/x/distribution/spec/04_messages.md index 26a345ba75..65fde1af03 100644 --- a/x/distribution/spec/04_messages.md +++ b/x/distribution/spec/04_messages.md @@ -6,14 +6,17 @@ order: 4 ## MsgSetWithdrawAddress -By default a withdrawal address is delegator address. If a delegator wants to change it's -withdrawal address it must send `MsgSetWithdrawAddress`. +By default, the withdraw address is the delegator address. To change its withdraw address, a delegator must send a `MsgSetWithdrawAddress` message. +Changing the withdraw address is possible only if the parameter `WithdrawAddrEnabled` is set to `true`. -+++ https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/distribution/v1/tx.proto#L29-L37 +The withdraw address cannot be any of the module accounts. These accounts are blocked from being withdraw addresses by being added to the distribution keeper's `blockedAddrs` array at initialization. -```go +Response: + ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.42.4/proto/cosmos/distribution/v1beta1/tx.proto#L29-L37 -func (k Keeper) SetWithdrawAddr(ctx sdk.Context, delegatorAddr sdk.AccAddress, withdrawAddr sdk.AccAddress) error +```go +func (k Keeper) SetWithdrawAddr(ctx sdk.Context, delegatorAddr sdk.AccAddress, withdrawAddr sdk.AccAddress) error if k.blockedAddrs[withdrawAddr.String()] { fail with "`{withdrawAddr}` is not allowed to receive external funds" } @@ -27,162 +30,93 @@ func (k Keeper) SetWithdrawAddr(ctx sdk.Context, delegatorAddr sdk.AccAddress, w ## MsgWithdrawDelegatorReward -Under special circumstances a delegator may wish to withdraw rewards from only -a single validator. +A delegator can withdraw its rewards. +Internally in the distribution module, this transaction simultaneously removes the previous delegation with associated rewards, the same as if the delegator simply started a new delegation of the same value. +The rewards are sent immediately from the distribution `ModuleAccount` to the withdraw address. +Any remainder (truncated decimals) are sent to the community pool. +The starting height of the delegation is set to the current validator period, and the reference count for the previous period is decremented. +The amount withdrawn is deducted from the `ValidatorOutstandingRewards` variable for the validator. -+++ https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/distribution/v1/tx.proto#L42-L50 +In the F1 distribution, the total rewards are calculated per validator period, and a delegator receives a piece of those rewards in proportion to their stake in the validator. +In basic F1, the total rewards that all the delegators are entitled to between to periods is calculated the following way. +Let `R(X)` be the total accumulated rewards up to period `X` divided by the tokens staked at that time. The delegator allocation is `R(X) * delegator_stake`. +Then the rewards for all the delegators for staking between periods `A` and `B` are `(R(B) - R(A)) * total stake`. +However, these calculated rewards don't account for slashing. -```go -// withdraw rewards from a delegation -func (k Keeper) WithdrawDelegationRewards(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress) (sdk.Coins, error) { - val := k.stakingKeeper.Validator(ctx, valAddr) - if val == nil { - return nil, types.ErrNoValidatorDistInfo - } - - del := k.stakingKeeper.Delegation(ctx, delAddr, valAddr) - if del == nil { - return nil, types.ErrEmptyDelegationDistInfo - } - - // withdraw rewards - rewards, err := k.withdrawDelegationRewards(ctx, val, del) - if err != nil { - return nil, err - } +Taking the slashes into account requires iteration. +Let `F(X)` be the fraction a validator is to be slashed for a slashing event that happened at period `X`. +If the validator was slashed at periods `P1, ..., PN`, where `A < P1`, `PN < B`, the distribution module calculates the individual delegator's rewards, `T(A, B)`, as follows: - // reinitialize the delegation - k.initializeDelegation(ctx, valAddr, delAddr) - return rewards, nil -} ``` - -## Withdraw Validator Rewards All - -When a validator wishes to withdraw their rewards it must send an -array of `MsgWithdrawDelegatorReward`. Note that parts of this transaction logic are also -triggered each with any change in individual delegations, such as an unbond, -redelegation, or delegation of additional tokens to a specific validator. This -transaction withdraws the validators commission fee, as well as any rewards -earning on their self-delegation. - -```go - -for _, valAddr := range validators { - val, err := sdk.ValAddressFromBech32(valAddr) - if err != nil { - return err - } - - msg := types.NewMsgWithdrawDelegatorReward(delAddr, val) - if err := msg.ValidateBasic(); err != nil { - return err - } - msgs = append(msgs, msg) -} +stake := initial stake +rewards := 0 +previous := A +for P in P1, ..., PN`: + rewards = (R(P) - previous) * stake + stake = stake * F(P) + previous = P +rewards = rewards + (R(B) - R(PN)) * stake ``` -## Common calculations +The historical rewards are calculated retroactively by playing back all the slashes and then attenuating the delegator's stake at each step. +The final calculated stake is equivalent to the actual staked coins in the delegation with a margin of error due to rounding errors. -### Update total validator accum +Response: -The total amount of validator accum must be calculated in order to determine -the amount of pool tokens which a validator is entitled to at a particular -block. The accum is always additive to the existing accum. This term is to be -updated each time rewards are withdrawn from the system. ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.42.4/proto/cosmos/distribution/v1beta1/tx.proto#L42-L50 -```go -func (g FeePool) UpdateTotalValAccum(height int64, totalBondedTokens Dec) FeePool - blocks = height - g.TotalValAccumUpdateHeight - g.TotalValAccum += totalDelShares * blocks - g.TotalValAccumUpdateHeight = height - return g -``` +## WithdrawValidatorCommission -### Update validator's accums +The validator can send the WithdrawValidatorCommission message to withdraw their accumulated commission. +The commission is calculated in every block during `BeginBlock`, so no iteration is required to withdraw. +The amount withdrawn is deducted from the `ValidatorOutstandingRewards` variable for the validator. +Only integer amounts can be sent. If the accumulated awards have decimals, the amount is truncated before the withdrawal is sent, and the remainder is left to be withdrawn later. -The total amount of delegator accum must be updated in order to determine the -amount of pool tokens which each delegator is entitled to, relative to the -other delegators for that validator. The accum is always additive to -the existing accum. This term is to be updated each time a -withdrawal is made from a validator. +## FundCommunityPool -``` go -func (vi ValidatorDistInfo) UpdateTotalDelAccum(height int64, totalDelShares Dec) ValidatorDistInfo - blocks = height - vi.TotalDelAccumUpdateHeight - vi.TotalDelAccum += totalDelShares * blocks - vi.TotalDelAccumUpdateHeight = height - return vi -``` - -### FeePool pool to validator pool +This message sends coins directly from the sender to the community pool. -Every time a validator or delegator executes a withdrawal or the validator is -the proposer and receives new tokens, the relevant validator must move tokens -from the passive global pool to their own pool. It is at this point that the -commission is withdrawn +The transaction fails if the amount cannot be transferred from the sender to the distribution module account. ```go -func (vi ValidatorDistInfo) TakeFeePoolRewards(g FeePool, height int64, totalBonded, vdTokens, commissionRate Dec) ( - vi ValidatorDistInfo, g FeePool) - - g.UpdateTotalValAccum(height, totalBondedShares) - - // update the validators pool - blocks = height - vi.FeePoolWithdrawalHeight - vi.FeePoolWithdrawalHeight = height - accum = blocks * vdTokens - withdrawalTokens := g.Pool * accum / g.TotalValAccum - commission := withdrawalTokens * commissionRate - - g.TotalValAccum -= accumm - vi.PoolCommission += commission - vi.PoolCommissionFree += withdrawalTokens - commission - g.Pool -= withdrawalTokens - - return vi, g -``` - - -### Delegation reward withdrawal - -For delegations (including validator's self-delegation) all rewards from reward -pool have already had the validator's commission taken away. +func (k Keeper) FundCommunityPool(ctx sdk.Context, amount sdk.Coins, sender sdk.AccAddress) error { + if err := k.bankKeeper.SendCoinsFromAccountToModule(ctx, sender, types.ModuleName, amount); err != nil { + return err + } -```go -func (di DelegationDistInfo) WithdrawRewards(g FeePool, vi ValidatorDistInfo, - height int64, totalBonded, vdTokens, totalDelShares, commissionRate Dec) ( - di DelegationDistInfo, g FeePool, withdrawn DecCoins) - - vi.UpdateTotalDelAccum(height, totalDelShares) - g = vi.TakeFeePoolRewards(g, height, totalBonded, vdTokens, commissionRate) - - blocks = height - di.WithdrawalHeight - di.WithdrawalHeight = height - accum = delegatorShares * blocks - - withdrawalTokens := vi.Pool * accum / vi.TotalDelAccum - vi.TotalDelAccum -= accum - - vi.Pool -= withdrawalTokens - vi.TotalDelAccum -= accum - return di, g, withdrawalTokens + feePool := k.GetFeePool(ctx) + feePool.CommunityPool = feePool.CommunityPool.Add(sdk.NewDecCoinsFromCoins(amount...)...) + k.SetFeePool(ctx, feePool) + return nil +} ``` -### Validator commission withdrawal +## Common distribution operations -Commission is calculated each time rewards enter into the validator. +These operations take place during many different messages. -```go -func (vi ValidatorDistInfo) WithdrawCommission(g FeePool, height int64, - totalBonded, vdTokens, commissionRate Dec) ( - vi ValidatorDistInfo, g FeePool, withdrawn DecCoins) +### Initialize delegation - g = vi.TakeFeePoolRewards(g, height, totalBonded, vdTokens, commissionRate) - - withdrawalTokens := vi.PoolCommission - vi.PoolCommission = 0 +Each time a delegation is changed, the rewards are withdrawn and the delegation is reinitialized. +Initializing a delegation increments the validator period and keeps track of the starting period of the delegation. - return vi, g, withdrawalTokens +```go +// initialize starting info for a new delegation +func (k Keeper) initializeDelegation(ctx sdk.Context, val sdk.ValAddress, del sdk.AccAddress) { + // period has already been incremented - we want to store the period ended by this delegation action + previousPeriod := k.GetValidatorCurrentRewards(ctx, val).Period - 1 + + // increment reference count for the period we're going to track + k.incrementReferenceCount(ctx, val, previousPeriod) + + validator := k.stakingKeeper.Validator(ctx, val) + delegation := k.stakingKeeper.Delegation(ctx, del, val) + + // calculate delegation stake in tokens + // we don't store directly, so multiply delegation shares * (tokens per share) + // note: necessary to truncate so we don't allow withdrawing more rewards than owed + stake := validator.TokensFromSharesTruncated(delegation.GetShares()) + k.SetDelegatorStartingInfo(ctx, val, del, types.NewDelegatorStartingInfo(previousPeriod, stake, uint64(ctx.BlockHeight()))) +} ``` diff --git a/x/distribution/spec/05_hooks.md b/x/distribution/spec/05_hooks.md index dfedf31831..417a0cc08f 100644 --- a/x/distribution/spec/05_hooks.md +++ b/x/distribution/spec/05_hooks.md @@ -4,27 +4,56 @@ order: 5 # Hooks +Available hooks that can be called by and from this module. + ## Create or modify delegation distribution - - - triggered-by: `staking.MsgDelegate`, `staking.MsgBeginRedelegate`, `staking.MsgUndelegate` -The pool of a new delegator bond will be 0 for the height at which the bond was -added, or the withdrawal has taken place. This is achieved by setting -`DelegationDistInfo.WithdrawalHeight` to the height of the triggering transaction. +- triggered-by: `staking.MsgDelegate`, `staking.MsgBeginRedelegate`, `staking.MsgUndelegate` + +### Before + +- The delegation rewards are withdrawn to the withdraw address of the delegator. + The rewards include the current period and exclude the starting period. +- The validator period is incremented. + The validator period is incremented because the validator's power and share distribution might have changed. +- The reference count for the delegator's starting period is decremented. + +### After + +The starting height of the delegation is set to the previous period. +Because of the `Before`-hook, this period is the last period for which the delegator was rewarded. + +## Validator created + +- triggered-by: `staking.MsgCreateValidator` + +When a validator is created, the following validator variables are initialized: + +- Historical rewards +- Current accumulated rewards +- Accumulated commission +- Total outstanding rewards +- Period + +By default, all values are set to a `0`, except period, which is set to `1`. + +## Validator removed + +- triggered-by: `staking.RemoveValidator` -## Commission rate change - - - triggered-by: `staking.MsgEditValidator` +Outstanding commission is sent to the validator's self-delegation withdrawal address. +Remaining delegator rewards get sent to the community fee pool. -If a validator changes its commission rate, all commission on fees must be -simultaneously withdrawn using the transaction `TxWithdrawValidator`. -Additionally the change and associated height must be recorded in a -`ValidatorUpdate` state record. +Note: The validator gets removed only when it has no remaining delegations. +At that time, all outstanding delegator rewards will have been withdrawn. +Any remaining rewards are dust amounts. -## Change in Validator State - - - triggered-by: `staking.Slash`, `staking.UpdateValidator` +## Validator is slashed -Whenever a validator is slashed or enters/leaves the validator group all of the -validator entitled reward tokens must be simultaneously withdrawn from -`Global.Pool` and added to `ValidatorDistInfo.Pool`. +- triggered-by: `staking.Slash` + +- The current validator period reference count is incremented. + The reference count is incremented because the slash event has created a reference to it. +- The validator period is incremented. +- The slash event is stored for later use. + The slash event will be referenced when calculating delegator rewards. diff --git a/x/distribution/spec/07_params.md b/x/distribution/spec/07_params.md index 432a4e5a96..4cee94c9d1 100644 --- a/x/distribution/spec/07_params.md +++ b/x/distribution/spec/07_params.md @@ -9,9 +9,9 @@ The distribution module contains the following parameters: | Key | Type | Example | | ------------------- | ------------ | -------------------------- | | communitytax | string (dec) | "0.020000000000000000" [0] | -| baseproposerreward | string (dec) | "0.010000000000000000" [1] | -| bonusproposerreward | string (dec) | "0.040000000000000000" [1] | +| baseproposerreward | string (dec) | "0.010000000000000000" [0] | +| bonusproposerreward | string (dec) | "0.040000000000000000" [0] | | withdrawaddrenabled | bool | true | -* [0] The value of `communitytax` must be positive and cannot exceed 1.00. -* [1] `baseproposerreward` and `bonusproposerreward` must be positive and their sum cannot exceed 1.00. +* [0] `communitytax`, `baseproposerreward` and `bonusproposerreward` must be + positive and their sum cannot exceed 1.00. diff --git a/x/distribution/spec/README.md b/x/distribution/spec/README.md index fe5f5069d6..ea56f59e6f 100644 --- a/x/distribution/spec/README.md +++ b/x/distribution/spec/README.md @@ -42,7 +42,7 @@ following rewards between validators and associated delegators: Fees are pooled within a global pool, as well as validator specific proposer-reward pools. The mechanisms used allow for validators and delegators -to independently and lazily withdraw their rewards. +to independently and lazily withdraw their rewards. ## Shortcomings @@ -87,12 +87,12 @@ to set up a script to periodically withdraw and rebond rewards. 1. **[Concepts](01_concepts.md)** - [Reference Counting in F1 Fee Distribution](01_concepts.md#reference-counting-in-f1-fee-distribution) 2. **[State](02_state.md)** -3. **[End Block](03_end_block.md)** +3. **[Begin Block](03_begin_block.md)** 4. **[Messages](04_messages.md)** - [MsgSetWithdrawAddress](04_messages.md#msgsetwithdrawaddress) - [MsgWithdrawDelegatorReward](04_messages.md#msgwithdrawdelegatorreward) - [Withdraw Validator Rewards All](04_messages.md#withdraw-validator-rewards-all) - - [Common calculations ](04_messages.md#common-calculations-) + - [Common calculations](04_messages.md#common-calculations-) 5. **[Hooks](05_hooks.md)** - [Create or modify delegation distribution](05_hooks.md#create-or-modify-delegation-distribution) - [Commission rate change](05_hooks.md#commission-rate-change) diff --git a/x/distribution/types/expected_keepers.go b/x/distribution/types/expected_keepers.go index fd99fb4e36..f1e69abab0 100644 --- a/x/distribution/types/expected_keepers.go +++ b/x/distribution/types/expected_keepers.go @@ -21,7 +21,6 @@ type AccountKeeper interface { type BankKeeper interface { GetAllBalances(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins GetBalance(ctx sdk.Context, addr sdk.AccAddress, denom string) sdk.Coin - SetBalances(ctx sdk.Context, addr sdk.AccAddress, balances sdk.Coins) error LockedCoins(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins SpendableCoins(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins diff --git a/x/distribution/types/fee_pool_test.go b/x/distribution/types/fee_pool_test.go index c8d361f841..0162734f93 100644 --- a/x/distribution/types/fee_pool_test.go +++ b/x/distribution/types/fee_pool_test.go @@ -1,4 +1,4 @@ -package types +package types_test import ( "testing" @@ -6,14 +6,14 @@ import ( "github.com/stretchr/testify/require" sdk "github.com/line/lbm-sdk/types" + "github.com/line/lbm-sdk/x/distribution/types" ) func TestValidateGenesis(t *testing.T) { - fp := InitialFeePool() + fp := types.InitialFeePool() require.Nil(t, fp.ValidateGenesis()) - fp2 := FeePool{CommunityPool: sdk.DecCoins{{Denom: "stake", Amount: sdk.NewDec(-1)}}} + fp2 := types.FeePool{CommunityPool: sdk.DecCoins{{Denom: "stake", Amount: sdk.NewDec(-1)}}} require.NotNil(t, fp2.ValidateGenesis()) - } diff --git a/x/distribution/types/keys.go b/x/distribution/types/keys.go index 714521e694..9da16763bf 100644 --- a/x/distribution/types/keys.go +++ b/x/distribution/types/keys.go @@ -2,9 +2,9 @@ package types import ( "encoding/binary" - "strings" sdk "github.com/line/lbm-sdk/types" + "github.com/line/lbm-sdk/types/address" ) const ( @@ -28,19 +28,19 @@ const ( // // - 0x01: sdk.ConsAddress // -// - 0x02: ValidatorOutstandingRewards +// - 0x02: ValidatorOutstandingRewards // -// - 0x03: sdk.AccAddress +// - 0x03: sdk.AccAddress // -// - 0x04: DelegatorStartingInfo +// - 0x04: DelegatorStartingInfo // -// - 0x05: ValidatorHistoricalRewards +// - 0x05: ValidatorHistoricalRewards // -// - 0x06: ValidatorCurrentRewards +// - 0x06: ValidatorCurrentRewards // -// - 0x07: ValidatorCurrentRewards +// - 0x07: ValidatorCurrentCommission // -// - 0x08: ValidatorSlashEvent +// - 0x08: ValidatorSlashEvent var ( FeePoolKey = []byte{0x00} // key for global distribution state ProposerKey = []byte{0x01} // key for the proposer operator address @@ -56,113 +56,161 @@ var ( AddressDelimiter = "," ) -// gets an address from a validator's outstanding rewards key +// GetValidatorOutstandingRewardsAddress creates an address from a validator's outstanding rewards key. func GetValidatorOutstandingRewardsAddress(key []byte) (valAddr sdk.ValAddress) { - addr := key[1:] + // key is in the format: + // 0x02 + + // Remove prefix and address length. + addr := key[2:] + if len(addr) != int(key[1]) { + panic("unexpected key length") + } + return sdk.ValAddress(addr) } -// gets an address from a delegator's withdraw info key +// GetDelegatorWithdrawInfoAddress creates an address from a delegator's withdraw info key. func GetDelegatorWithdrawInfoAddress(key []byte) (delAddr sdk.AccAddress) { - addr := key[1:] + // key is in the format: + // 0x03 + + // Remove prefix and address length. + addr := key[2:] + if len(addr) != int(key[1]) { + panic("unexpected key length") + } + return sdk.AccAddress(addr) } -// gets the addresses from a delegator starting info key +// GetDelegatorStartingInfoAddresses creates the addresses from a delegator starting info key. func GetDelegatorStartingInfoAddresses(key []byte) (valAddr sdk.ValAddress, delAddr sdk.AccAddress) { - addrsStr := string(key[1:]) - addrs := strings.Split(addrsStr, AddressDelimiter) - valAddr = sdk.ValAddress(addrs[0]) - delAddr = sdk.AccAddress(addrs[1]) + // key is in the format: + // 0x04 + valAddrLen := int(key[1]) + valAddr = sdk.ValAddress(key[2 : 2+valAddrLen]) + delAddrLen := int(key[2+valAddrLen]) + delAddr = sdk.AccAddress(key[3+valAddrLen:]) + if len(delAddr.Bytes()) != delAddrLen { + panic("unexpected key length") + } + return } -// gets the address & period from a validator's historical rewards key +// GetValidatorHistoricalRewardsAddressPeriod creates the address & period from a validator's historical rewards key. func GetValidatorHistoricalRewardsAddressPeriod(key []byte) (valAddr sdk.ValAddress, period uint64) { - addr := key[1 : len(key)-8] - valAddr = sdk.ValAddress(addr) - b := key[len(key)-8:] + // key is in the format: + // 0x05 + valAddrLen := int(key[1]) + valAddr = sdk.ValAddress(key[2 : 2+valAddrLen]) + b := key[2+valAddrLen:] + if len(b) != 8 { + panic("unexpected key length") + } period = binary.LittleEndian.Uint64(b) return } -// gets the address from a validator's current rewards key +// GetValidatorCurrentRewardsAddress creates the address from a validator's current rewards key. func GetValidatorCurrentRewardsAddress(key []byte) (valAddr sdk.ValAddress) { - addr := key[1:] + // key is in the format: + // 0x06: ValidatorCurrentRewards + + // Remove prefix and address length. + addr := key[2:] + if len(addr) != int(key[1]) { + panic("unexpected key length") + } + return sdk.ValAddress(addr) } -// gets the address from a validator's accumulated commission key +// GetValidatorAccumulatedCommissionAddress creates the address from a validator's accumulated commission key. func GetValidatorAccumulatedCommissionAddress(key []byte) (valAddr sdk.ValAddress) { - addr := key[1:] + // key is in the format: + // 0x07: ValidatorCurrentRewards + + // Remove prefix and address length. + addr := key[2:] + if len(addr) != int(key[1]) { + panic("unexpected key length") + } + return sdk.ValAddress(addr) } -// gets the height from a validator's slash event key +// GetValidatorSlashEventAddressHeight creates the height from a validator's slash event key. func GetValidatorSlashEventAddressHeight(key []byte) (valAddr sdk.ValAddress, height uint64) { - addr := key[1 : len(key)-16] // 8 bytes height + 8 bytes period - valAddr = sdk.ValAddress(addr) - b := key[len(key)-16 : len(key)-8] // the next 8 bytes represent the height + // key is in the format: + // 0x08: ValidatorSlashEvent + valAddrLen := int(key[1]) + valAddr = sdk.ValAddress(key[2 : 2+valAddrLen]) + startB := 2 + valAddrLen + b := key[startB : startB+8] // the next 8 bytes represent the height height = binary.BigEndian.Uint64(b) return } -// gets the outstanding rewards key for a validator +// GetValidatorOutstandingRewardsKey creates the outstanding rewards key for a validator. func GetValidatorOutstandingRewardsKey(valAddr sdk.ValAddress) []byte { - return append(ValidatorOutstandingRewardsPrefix, valAddr.Bytes()...) + return append(ValidatorOutstandingRewardsPrefix, address.MustLengthPrefix(valAddr.Bytes())...) } -// gets the key for a delegator's withdraw addr +// GetDelegatorWithdrawAddrKey creates the key for a delegator's withdraw addr. func GetDelegatorWithdrawAddrKey(delAddr sdk.AccAddress) []byte { - return append(DelegatorWithdrawAddrPrefix, delAddr.Bytes()...) + return append(DelegatorWithdrawAddrPrefix, address.MustLengthPrefix(delAddr.Bytes())...) } -// gets the key for a delegator's starting info +// GetDelegatorStartingInfoKey creates the key for a delegator's starting info. func GetDelegatorStartingInfoKey(v sdk.ValAddress, d sdk.AccAddress) []byte { - return append(append(append(DelegatorStartingInfoPrefix, v.Bytes()...), AddressDelimiter...), d.Bytes()...) + return append(append(DelegatorStartingInfoPrefix, address.MustLengthPrefix(v.Bytes())...), address.MustLengthPrefix(d.Bytes())...) } -// gets the prefix key for a validator's historical rewards +// GetValidatorHistoricalRewardsPrefix creates the prefix key for a validator's historical rewards. func GetValidatorHistoricalRewardsPrefix(v sdk.ValAddress) []byte { - return append(ValidatorHistoricalRewardsPrefix, v.Bytes()...) + return append(ValidatorHistoricalRewardsPrefix, address.MustLengthPrefix(v.Bytes())...) } -// gets the key for a validator's historical rewards +// GetValidatorHistoricalRewardsKey creates the key for a validator's historical rewards. func GetValidatorHistoricalRewardsKey(v sdk.ValAddress, k uint64) []byte { b := make([]byte, 8) binary.LittleEndian.PutUint64(b, k) - return append(append(ValidatorHistoricalRewardsPrefix, v.Bytes()...), b...) + return append(append(ValidatorHistoricalRewardsPrefix, address.MustLengthPrefix(v.Bytes())...), b...) } -// gets the key for a validator's current rewards +// GetValidatorCurrentRewardsKey creates the key for a validator's current rewards. func GetValidatorCurrentRewardsKey(v sdk.ValAddress) []byte { - return append(ValidatorCurrentRewardsPrefix, v.Bytes()...) + return append(ValidatorCurrentRewardsPrefix, address.MustLengthPrefix(v.Bytes())...) } -// gets the key for a validator's current commission +// GetValidatorAccumulatedCommissionKey creates the key for a validator's current commission. func GetValidatorAccumulatedCommissionKey(v sdk.ValAddress) []byte { - return append(ValidatorAccumulatedCommissionPrefix, v.Bytes()...) + return append(ValidatorAccumulatedCommissionPrefix, address.MustLengthPrefix(v.Bytes())...) } -// gets the prefix key for a validator's slash fractions +// GetValidatorSlashEventPrefix creates the prefix key for a validator's slash fractions. func GetValidatorSlashEventPrefix(v sdk.ValAddress) []byte { - return append(ValidatorSlashEventPrefix, v.Bytes()...) + return append(ValidatorSlashEventPrefix, address.MustLengthPrefix(v.Bytes())...) } -// gets the prefix key for a validator's slash fraction (ValidatorSlashEventPrefix + height) +// GetValidatorSlashEventKeyPrefix creates the prefix key for a validator's slash fraction (ValidatorSlashEventPrefix + height). func GetValidatorSlashEventKeyPrefix(v sdk.ValAddress, height uint64) []byte { heightBz := make([]byte, 8) binary.BigEndian.PutUint64(heightBz, height) + return append( ValidatorSlashEventPrefix, - append(v.Bytes(), heightBz...)..., + append(address.MustLengthPrefix(v.Bytes()), heightBz...)..., ) } -// gets the key for a validator's slash fraction +// GetValidatorSlashEventKey creates the key for a validator's slash fraction. func GetValidatorSlashEventKey(v sdk.ValAddress, height, period uint64) []byte { periodBz := make([]byte, 8) binary.BigEndian.PutUint64(periodBz, period) prefix := GetValidatorSlashEventKeyPrefix(v, height) + return append(prefix, periodBz...) } diff --git a/x/distribution/types/msg.go b/x/distribution/types/msg.go index 329951e43d..f63617c3ab 100644 --- a/x/distribution/types/msg.go +++ b/x/distribution/types/msg.go @@ -1,4 +1,3 @@ -//nolint package types import ( diff --git a/x/distribution/types/params.go b/x/distribution/types/params.go index 261c3b6827..5b22dddf04 100644 --- a/x/distribution/types/params.go +++ b/x/distribution/types/params.go @@ -51,7 +51,7 @@ func (p *Params) ParamSetPairs() paramtypes.ParamSetPairs { func (p Params) ValidateBasic() error { if p.CommunityTax.IsNegative() || p.CommunityTax.GT(sdk.OneDec()) { return fmt.Errorf( - "community tax should non-negative and less than one: %s", p.CommunityTax, + "community tax should be non-negative and less than one: %s", p.CommunityTax, ) } if p.BaseProposerReward.IsNegative() { @@ -64,9 +64,9 @@ func (p Params) ValidateBasic() error { "bonus proposer reward should be positive: %s", p.BonusProposerReward, ) } - if v := p.BaseProposerReward.Add(p.BonusProposerReward); v.GT(sdk.OneDec()) { + if v := p.BaseProposerReward.Add(p.BonusProposerReward).Add(p.CommunityTax); v.GT(sdk.OneDec()) { return fmt.Errorf( - "sum of base and bonus proposer reward cannot greater than one: %s", v, + "sum of base, bonus proposer rewards, and community tax cannot be greater than one: %s", v, ) } diff --git a/x/distribution/types/params_internal_test.go b/x/distribution/types/params_internal_test.go new file mode 100644 index 0000000000..651fe6ccb0 --- /dev/null +++ b/x/distribution/types/params_internal_test.go @@ -0,0 +1,34 @@ +package types + +import ( + "testing" + + "github.com/stretchr/testify/require" + + sdk "github.com/line/lbm-sdk/types" +) + +func Test_validateAuxFuncs(t *testing.T) { + type args struct { + i interface{} + } + tests := []struct { + name string + args args + wantErr bool + }{ + {"wrong type", args{10.5}, true}, + {"empty sdk.Dec", args{sdk.Dec{}}, true}, + {"negative", args{sdk.NewDec(-1)}, true}, + {"one dec", args{sdk.NewDec(1)}, false}, + {"two dec", args{sdk.NewDec(2)}, true}, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + require.Equal(t, tt.wantErr, validateCommunityTax(tt.args.i) != nil) + require.Equal(t, tt.wantErr, validateBaseProposerReward(tt.args.i) != nil) + require.Equal(t, tt.wantErr, validateBonusProposerReward(tt.args.i) != nil) + }) + } +} diff --git a/x/distribution/types/params_test.go b/x/distribution/types/params_test.go index a9ab8e162a..70d9c580b1 100644 --- a/x/distribution/types/params_test.go +++ b/x/distribution/types/params_test.go @@ -1,4 +1,4 @@ -package types +package types_test import ( "testing" @@ -6,29 +6,44 @@ import ( "github.com/stretchr/testify/require" sdk "github.com/line/lbm-sdk/types" + "github.com/line/lbm-sdk/x/distribution/types" ) -func Test_validateAuxFuncs(t *testing.T) { - type args struct { - i interface{} +func TestParams_ValidateBasic(t *testing.T) { + toDec := sdk.MustNewDecFromStr + + type fields struct { + CommunityTax sdk.Dec + BaseProposerReward sdk.Dec + BonusProposerReward sdk.Dec + WithdrawAddrEnabled bool } tests := []struct { name string - args args + fields fields wantErr bool }{ - {"wrong type", args{10.5}, true}, - {"nil Int pointer", args{sdk.Dec{}}, true}, - {"negative", args{sdk.NewDec(-1)}, true}, - {"one dec", args{sdk.NewDec(1)}, false}, - {"two dec", args{sdk.NewDec(2)}, true}, + {"success", fields{toDec("0.1"), toDec("0.5"), toDec("0.4"), false}, false}, + {"negative community tax", fields{toDec("-0.1"), toDec("0.5"), toDec("0.4"), false}, true}, + {"negative base proposer reward", fields{toDec("0.1"), toDec("-0.5"), toDec("0.4"), false}, true}, + {"negative bonus proposer reward", fields{toDec("0.1"), toDec("0.5"), toDec("-0.4"), false}, true}, + {"total sum greater than 1", fields{toDec("0.2"), toDec("0.5"), toDec("0.4"), false}, true}, } for _, tt := range tests { - tt := tt t.Run(tt.name, func(t *testing.T) { - require.Equal(t, tt.wantErr, validateCommunityTax(tt.args.i) != nil) - require.Equal(t, tt.wantErr, validateBaseProposerReward(tt.args.i) != nil) - require.Equal(t, tt.wantErr, validateBonusProposerReward(tt.args.i) != nil) + p := types.Params{ + CommunityTax: tt.fields.CommunityTax, + BaseProposerReward: tt.fields.BaseProposerReward, + BonusProposerReward: tt.fields.BonusProposerReward, + WithdrawAddrEnabled: tt.fields.WithdrawAddrEnabled, + } + if err := p.ValidateBasic(); (err != nil) != tt.wantErr { + t.Errorf("ValidateBasic() error = %v, wantErr %v", err, tt.wantErr) + } }) } } + +func TestDefaultParams(t *testing.T) { + require.NoError(t, types.DefaultParams().ValidateBasic()) +} diff --git a/x/distribution/types/query.pb.gw.go b/x/distribution/types/query.pb.gw.go index 8181412763..f96d5f659f 100644 --- a/x/distribution/types/query.pb.gw.go +++ b/x/distribution/types/query.pb.gw.go @@ -896,23 +896,23 @@ func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, clie } var ( - pattern_Query_Params_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"lbm", "distribution", "v1", "params"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_Query_Params_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"lbm", "distribution", "v1", "params"}, "", runtime.AssumeColonVerbOpt(false))) - pattern_Query_ValidatorOutstandingRewards_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4, 2, 5}, []string{"lbm", "distribution", "v1", "validators", "validator_address", "outstanding_rewards"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_Query_ValidatorOutstandingRewards_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4, 2, 5}, []string{"lbm", "distribution", "v1", "validators", "validator_address", "outstanding_rewards"}, "", runtime.AssumeColonVerbOpt(false))) - pattern_Query_ValidatorCommission_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4, 2, 5}, []string{"lbm", "distribution", "v1", "validators", "validator_address", "commission"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_Query_ValidatorCommission_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4, 2, 5}, []string{"lbm", "distribution", "v1", "validators", "validator_address", "commission"}, "", runtime.AssumeColonVerbOpt(false))) - pattern_Query_ValidatorSlashes_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4, 2, 5}, []string{"lbm", "distribution", "v1", "validators", "validator_address", "slashes"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_Query_ValidatorSlashes_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4, 2, 5}, []string{"lbm", "distribution", "v1", "validators", "validator_address", "slashes"}, "", runtime.AssumeColonVerbOpt(false))) - pattern_Query_DelegationRewards_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4, 2, 5, 1, 0, 4, 1, 5, 6}, []string{"lbm", "distribution", "v1", "delegators", "delegator_address", "rewards", "validator_address"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_Query_DelegationRewards_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4, 2, 5, 1, 0, 4, 1, 5, 6}, []string{"lbm", "distribution", "v1", "delegators", "delegator_address", "rewards", "validator_address"}, "", runtime.AssumeColonVerbOpt(false))) - pattern_Query_DelegationTotalRewards_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4, 2, 5}, []string{"lbm", "distribution", "v1", "delegators", "delegator_address", "rewards"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_Query_DelegationTotalRewards_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4, 2, 5}, []string{"lbm", "distribution", "v1", "delegators", "delegator_address", "rewards"}, "", runtime.AssumeColonVerbOpt(false))) - pattern_Query_DelegatorValidators_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4, 2, 5}, []string{"lbm", "distribution", "v1", "delegators", "delegator_address", "validators"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_Query_DelegatorValidators_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4, 2, 5}, []string{"lbm", "distribution", "v1", "delegators", "delegator_address", "validators"}, "", runtime.AssumeColonVerbOpt(false))) - pattern_Query_DelegatorWithdrawAddress_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4, 2, 5}, []string{"lbm", "distribution", "v1", "delegators", "delegator_address", "withdraw_address"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_Query_DelegatorWithdrawAddress_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4, 2, 5}, []string{"lbm", "distribution", "v1", "delegators", "delegator_address", "withdraw_address"}, "", runtime.AssumeColonVerbOpt(false))) - pattern_Query_CommunityPool_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"lbm", "distribution", "v1", "community_pool"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_Query_CommunityPool_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"lbm", "distribution", "v1", "community_pool"}, "", runtime.AssumeColonVerbOpt(false))) ) var ( diff --git a/x/evidence/atlas/atlas-v0.41.x.md b/x/evidence/atlas/atlas-v0.41.x.md new file mode 100644 index 0000000000..e37835d57c --- /dev/null +++ b/x/evidence/atlas/atlas-v0.41.x.md @@ -0,0 +1,167 @@ +# x/evidence + +The `x/evidence` module is responsible for handling multi-asset coin transfers between +accounts and tracking special-case pseudo-transfers which must work differently +with particular kinds of accounts. + +## Usage + +1. Import the module. + + ```go + import ( + "github.com/line/lbm-sdk/x/evidence" + evidencekeeper "github.com/line/lbm-sdk/x/evidence/keeper" + evidencetypes "github.com/line/lbm-sdk/x/evidence/types" + ) + ``` + +2. Add `AppModuleBasic` to your `ModuleBasics`. + + ```go + var ( + ModuleBasics = module.NewBasicManager( + // ... + evidence.AppModuleBasic{}, + } + ) + ``` + +3. Add the evidence keeper to your apps struct. + + ```go + type app struct { + // ... + EvidenceKeeper evidencekeeper.Keeper + // ... + } + ``` + +4. Add the evidence store key to the group of store keys. + + ```go + func NewApp(...) *App { + // ... + keys := sdk.NewKVStoreKeys( + evidencetypes.StoreKey, + ) + // ... + } + ``` + +5. Create the keeper. Note, the `x/evidence` module depends on the `x/staking` and `x/slashing` modules. Evidence has expected interfaces, these interfaces are linked to slashing and staking. You can find these interfaces [here](https://github.com/cosmos/cosmos-sdk/blob/v0.41.0/x/evidence/types/expected_keepers.go) + + ```go + func NewApp(...) *App { + // ... + // create evidence keeper with router + evidenceKeeper := evidencekeeper.NewKeeper( + appCodec, keys[evidencetypes.StoreKey], &app.StakingKeeper, app.SlashingKeeper, + ) + } + ``` + +6. Add the `x/evidence` module to the app's `ModuleManager`. + + ```go + func NewApp(...) *App { + // ... + app.mm = module.NewManager( + // ... + evidence.NewAppModule(app.EvidenceKeeper), + // ... + ) + } + ``` + +7. Set the `x/evidence` module begin blocker order. + + ```go + func NewApp(...) *App { + // ... + app.mm.SetOrderBeginBlockers( + // ... + evidencetypes.ModuleName, + // ... + ) + } + ``` + +8. Set the `x/evidence` module genesis order. + + ```go + func NewApp(...) *App { + // ... + app.mm.SetOrderInitGenesis(..., evidencetypes.ModuleName, ...) + } + ``` + +9. Add the `x/evidence` module to the simulation manager (if you have one set). + + ```go + func NewApp(...) *App { + // ... + app.sm = module.NewSimulationManager( + // ... + evidence.NewAppModule(app.EvidenceKeeper), + // ... + ) + } + +## Genesis + +The `x/evidence` module defines its genesis state as follows: + +```proto +type GenesisState struct { + // evidence defines all the evidence at genesis. + Evidence []*types.Any `protobuf:"bytes,1,rep,name=evidence,proto3" json:"evidence,omitempty"` +} +``` + +## Messages + + +View supported messages at [docs.cosmos.network/v0.40/modules/evidence](https://docs.cosmos.network/v0.40/modules/evidence/03_messages.html) + +## Client + +Evidence supports querying of old evidence and submission of new evidence. There are two queries. One for all the evidence, and one for a specific piece of evidence. + +### CLI + +The evidence module supports the blow command to query evidence. + +```sh +Usage: + app query evidence [flags] + +Flags: + --count-total count total number of records in evidence to query for + --height int Use a specific height to query state at (this can error if the node is pruning state) + -h, --help help for evidence + --limit uint pagination limit of evidence to query for (default 100) + --node string : to Tendermint RPC interface for this chain (default "tcp://localhost:26657") + --offset uint pagination offset of evidence to query for + -o, --output string Output format (text|json) (default "text") + --page uint pagination page of evidence to query for. This sets offset to a multiple of limit (default 1) + --page-key string pagination page-key of evidence to query for +``` + +### REST + +Evidence REST API supports only queries of evidence. To submit evidence please use gRPC or the cli. + +### gRPC + +Evidence supports both querying and submitting transactions via gRPC + +#### Query + +[gRPC query](https://docs.cosmos.network/master/core/proto-docs.html#cosmos/evidence/v1beta1/query.proto) + +#### Tx + +[gRPC Tx](https://docs.cosmos.network/master/core/proto-docs.html#cosmos-evidence-v1beta1-tx-proto) + +View supported messages at [docs.cosmos.network/v0.40/modules/evidence](https://docs.cosmos.network/v0.40/modules/evidence/03_messages.html) diff --git a/x/evidence/atlas/manifest.toml b/x/evidence/atlas/manifest.toml new file mode 100644 index 0000000000..e277c68024 --- /dev/null +++ b/x/evidence/atlas/manifest.toml @@ -0,0 +1,48 @@ +[module] +# Name of the module. (Required) +name = "x/evidence" + +# Description of the module. (Optional) +description = "The evidence module is responsible for storing and handling evidence of misbeaviour." + +# Link to where the module is located, it can also be a link to your project. (Optional) +homepage = "https://github.com/cosmos/cosmos-sdk" + +#List of key words describing your module (Optional) +keywords = [ + "evidence", + "misbeaviour", + "accountability" +] + + +[bug_tracker] +# A URL to a site that provides information or guidance on how to submit or deal +# with security vulnerabilities and bug reports. +url = "https://github.com/cosmos/cosmos-sdk/issues" + +# To list multiple authors, multiple [[authors]] need to be created +[[authors]] +# Name of one of the authors. Typically their Github name. (Required) +name = "alexanderbez" + +[[authors]] +name = "fedekunze" + +[[authors]] +name = "aaronc" + +[version] +# The repository field should be a URL to the source repository for your module. +# Typically, this will point to the specific GitHub repository release/tag for the +# module, although this is not enforced or required. (Required) +repo = "https://github.com/cosmos/cosmos-sdk" + +# The documentation field specifies a URL to a website hosting the module's documentation. (Optional) +documentation = "https://raw.githubusercontent.com/cosmos/cosmos-sdk/master/x/evidence/atlas/atlas-v0.41.x.md" + +# The module version to be published. (Required) +version = "v0.41" + +# An optional Cosmos SDK version compatibility may be provided. (Optional) +sdk_compat = "v0.41" diff --git a/x/evidence/client/rest/query.go b/x/evidence/client/rest/query.go index f339de5141..8ce64be87e 100644 --- a/x/evidence/client/rest/query.go +++ b/x/evidence/client/rest/query.go @@ -47,7 +47,7 @@ func queryEvidenceHandler(clientCtx client.Context) http.HandlerFunc { } params := types.NewQueryEvidenceRequest(decodedHash) - bz, err := clientCtx.JSONMarshaler.MarshalJSON(params) + bz, err := clientCtx.Codec.MarshalJSON(params) if err != nil { rest.WriteErrorResponse(w, http.StatusBadRequest, fmt.Sprintf("failed to marshal query params: %s", err)) return diff --git a/x/evidence/client/testutil/cli_test.go b/x/evidence/client/testutil/cli_test.go new file mode 100644 index 0000000000..8ded31fefa --- /dev/null +++ b/x/evidence/client/testutil/cli_test.go @@ -0,0 +1,18 @@ +//go:build norace +// +build norace + +package testutil + +import ( + "testing" + + "github.com/line/lbm-sdk/testutil/network" + + "github.com/stretchr/testify/suite" +) + +func TestIntegrationTestSuite(t *testing.T) { + cfg := network.DefaultConfig() + cfg.NumValidators = 1 + suite.Run(t, NewIntegrationTestSuite(cfg)) +} diff --git a/x/evidence/client/cli/cli_test.go b/x/evidence/client/testutil/suite.go similarity index 81% rename from x/evidence/client/cli/cli_test.go rename to x/evidence/client/testutil/suite.go index 7009f48f99..cc52b33c0f 100644 --- a/x/evidence/client/cli/cli_test.go +++ b/x/evidence/client/testutil/suite.go @@ -1,31 +1,30 @@ -package cli_test +package testutil import ( "strings" - "testing" "github.com/stretchr/testify/suite" clitestutil "github.com/line/lbm-sdk/testutil/cli" - testnet "github.com/line/lbm-sdk/testutil/network" + "github.com/line/lbm-sdk/testutil/network" "github.com/line/lbm-sdk/x/evidence/client/cli" ) type IntegrationTestSuite struct { suite.Suite - cfg testnet.Config - network *testnet.Network + cfg network.Config + network *network.Network +} + +func NewIntegrationTestSuite(cfg network.Config) *IntegrationTestSuite { + return &IntegrationTestSuite{cfg: cfg} } func (s *IntegrationTestSuite) SetupSuite() { s.T().Log("setting up integration test suite") - cfg := testnet.DefaultConfig() - cfg.NumValidators = 1 - - s.cfg = cfg - s.network = testnet.New(s.T(), cfg) + s.network = network.New(s.T(), s.cfg) _, err := s.network.WaitForHeight(1) s.Require().NoError(err) @@ -36,10 +35,6 @@ func (s *IntegrationTestSuite) TearDownSuite() { s.network.Cleanup() } -func TestIntegrationTestSuite(t *testing.T) { - suite.Run(t, new(IntegrationTestSuite)) -} - func (s *IntegrationTestSuite) TestGetQueryCmd() { val := s.network.Validators[0] diff --git a/x/evidence/handler_test.go b/x/evidence/handler_test.go index ee19652e93..fb1a764cda 100644 --- a/x/evidence/handler_test.go +++ b/x/evidence/handler_test.go @@ -116,7 +116,7 @@ func (suite *HandlerTestSuite) TestMsgSubmitEvidence() { msg := tc.msg.(exported.MsgSubmitEvidenceI) var resultData types.MsgSubmitEvidenceResponse - suite.app.AppCodec().UnmarshalBinaryBare(res.Data, &resultData) + suite.app.AppCodec().Unmarshal(res.Data, &resultData) suite.Require().Equal(msg.GetEvidence().Hash().Bytes(), resultData.Hash, "invalid hash; tc #%d", i) } } diff --git a/x/evidence/keeper/infraction.go b/x/evidence/keeper/infraction.go index 0fa3d2c5b6..6c674307d6 100644 --- a/x/evidence/keeper/infraction.go +++ b/x/evidence/keeper/infraction.go @@ -119,4 +119,5 @@ func (k Keeper) HandleEquivocationEvidence(ctx sdk.Context, evidence *types.Equi k.slashingKeeper.JailUntil(ctx, consAddr, types.DoubleSignJailEndTime) k.slashingKeeper.Tombstone(ctx, consAddr) + k.SetEvidence(ctx, evidence) } diff --git a/x/evidence/keeper/infraction_test.go b/x/evidence/keeper/infraction_test.go index 2efa312d3d..4ae2c78c4f 100644 --- a/x/evidence/keeper/infraction_test.go +++ b/x/evidence/keeper/infraction_test.go @@ -69,6 +69,10 @@ func (suite *KeeperTestSuite) TestHandleDoubleSign() { tstaking.Ctx = ctx tstaking.Denom = stakingParams.BondDenom tstaking.Undelegate(operatorAddr.ToAccAddress(), operatorAddr, totalBond, true) + + // query evidence from store + evidences := suite.app.EvidenceKeeper.GetAllEvidence(ctx) + suite.Len(evidences, 1) } func (suite *KeeperTestSuite) TestHandleDoubleSign_TooOld() { diff --git a/x/evidence/keeper/keeper.go b/x/evidence/keeper/keeper.go index fb0e33cee8..1d93f8c3a1 100644 --- a/x/evidence/keeper/keeper.go +++ b/x/evidence/keeper/keeper.go @@ -18,7 +18,7 @@ import ( // managing persistence, state transitions and query handling for the evidence // module. type Keeper struct { - cdc codec.BinaryMarshaler + cdc codec.BinaryCodec storeKey sdk.StoreKey router types.Router stakingKeeper types.StakingKeeper @@ -26,7 +26,7 @@ type Keeper struct { } func NewKeeper( - cdc codec.BinaryMarshaler, storeKey sdk.StoreKey, stakingKeeper types.StakingKeeper, + cdc codec.BinaryCodec, storeKey sdk.StoreKey, stakingKeeper types.StakingKeeper, slashingKeeper types.SlashingKeeper, ) *Keeper { diff --git a/x/evidence/keeper/keeper_test.go b/x/evidence/keeper/keeper_test.go index 89969b4e07..b789cb1d4b 100644 --- a/x/evidence/keeper/keeper_test.go +++ b/x/evidence/keeper/keeper_test.go @@ -14,10 +14,10 @@ import ( "github.com/line/lbm-sdk/simapp" sdk "github.com/line/lbm-sdk/types" authtypes "github.com/line/lbm-sdk/x/auth/types" - banktypes "github.com/line/lbm-sdk/x/bank/types" "github.com/line/lbm-sdk/x/evidence/exported" "github.com/line/lbm-sdk/x/evidence/keeper" "github.com/line/lbm-sdk/x/evidence/types" + minttypes "github.com/line/lbm-sdk/x/mint/types" "github.com/line/lbm-sdk/x/staking" ) @@ -34,7 +34,8 @@ var ( sdk.BytesToValAddress(pubkeys[2].Address()), } - initAmt = sdk.TokensFromConsensusPower(200) + // The default power validators are initialized to have within tests + initAmt = sdk.TokensFromConsensusPower(200, sdk.DefaultPowerReduction) initCoins = sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, initAmt)) ) @@ -130,11 +131,10 @@ func (suite *KeeperTestSuite) populateValidators(ctx sdk.Context) { // add accounts and set total supply totalSupplyAmt := initAmt.MulRaw(int64(len(valAddresses))) totalSupply := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, totalSupplyAmt)) - suite.app.BankKeeper.SetSupply(ctx, banktypes.NewSupply(totalSupply)) + suite.NoError(suite.app.BankKeeper.MintCoins(ctx, minttypes.ModuleName, totalSupply)) for _, addr := range valAddresses { - err := suite.app.BankKeeper.AddCoins(ctx, addr.ToAccAddress(), initCoins) - suite.NoError(err) + suite.NoError(suite.app.BankKeeper.SendCoinsFromModuleToAccount(ctx, minttypes.ModuleName, addr.ToAccAddress(), initCoins)) } } diff --git a/x/evidence/keeper/querier_test.go b/x/evidence/keeper/querier_test.go index 2a52b2d46e..f5e148c78e 100644 --- a/x/evidence/keeper/querier_test.go +++ b/x/evidence/keeper/querier_test.go @@ -18,12 +18,12 @@ const ( func (suite *KeeperTestSuite) TestQuerier_QueryEvidence_Existing() { ctx := suite.ctx.WithIsCheckTx(false) numEvidence := 100 - _, cdc := simapp.MakeCodecs() + legacyCdc := simapp.MakeTestEncodingConfig().Amino evidence := suite.populateEvidence(ctx, numEvidence) query := abci.RequestQuery{ Path: strings.Join([]string{custom, types.QuerierRoute, types.QueryEvidence}, "/"), - Data: cdc.MustMarshalJSON(types.NewQueryEvidenceRequest(evidence[0].Hash())), + Data: legacyCdc.MustMarshalJSON(types.NewQueryEvidenceRequest(evidence[0].Hash())), } bz, err := suite.querier(ctx, []string{types.QueryEvidence}, query) @@ -31,13 +31,13 @@ func (suite *KeeperTestSuite) TestQuerier_QueryEvidence_Existing() { suite.NotNil(bz) var e exported.Evidence - suite.Nil(cdc.UnmarshalJSON(bz, &e)) + suite.Nil(legacyCdc.UnmarshalJSON(bz, &e)) suite.Equal(evidence[0], e) } func (suite *KeeperTestSuite) TestQuerier_QueryEvidence_NonExisting() { ctx := suite.ctx.WithIsCheckTx(false) - cdc, _ := simapp.MakeCodecs() + cdc := simapp.MakeTestEncodingConfig().Marshaler numEvidence := 100 suite.populateEvidence(ctx, numEvidence) @@ -53,7 +53,7 @@ func (suite *KeeperTestSuite) TestQuerier_QueryEvidence_NonExisting() { func (suite *KeeperTestSuite) TestQuerier_QueryAllEvidence() { ctx := suite.ctx.WithIsCheckTx(false) - _, cdc := simapp.MakeCodecs() + cdc := simapp.MakeTestEncodingConfig().Amino numEvidence := 100 suite.populateEvidence(ctx, numEvidence) @@ -73,7 +73,7 @@ func (suite *KeeperTestSuite) TestQuerier_QueryAllEvidence() { func (suite *KeeperTestSuite) TestQuerier_QueryAllEvidence_InvalidPagination() { ctx := suite.ctx.WithIsCheckTx(false) - _, cdc := simapp.MakeCodecs() + cdc := simapp.MakeTestEncodingConfig().Amino numEvidence := 100 suite.populateEvidence(ctx, numEvidence) diff --git a/x/evidence/module.go b/x/evidence/module.go index 07dbda08e3..6e3779e1fb 100644 --- a/x/evidence/module.go +++ b/x/evidence/module.go @@ -60,12 +60,12 @@ func (AppModuleBasic) RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) { } // DefaultGenesis returns the evidence module's default genesis state. -func (AppModuleBasic) DefaultGenesis(cdc codec.JSONMarshaler) json.RawMessage { +func (AppModuleBasic) DefaultGenesis(cdc codec.JSONCodec) json.RawMessage { return cdc.MustMarshalJSON(types.DefaultGenesisState()) } // ValidateGenesis performs genesis state validation for the evidence module. -func (AppModuleBasic) ValidateGenesis(cdc codec.JSONMarshaler, config client.TxEncodingConfig, bz json.RawMessage) error { +func (AppModuleBasic) ValidateGenesis(cdc codec.JSONCodec, config client.TxEncodingConfig, bz json.RawMessage) error { var gs types.GenesisState if err := cdc.UnmarshalJSON(bz, &gs); err != nil { return fmt.Errorf("failed to unmarshal %s genesis state: %w", types.ModuleName, err) @@ -164,7 +164,7 @@ func (am AppModule) RegisterInvariants(ir sdk.InvariantRegistry) {} // InitGenesis performs the evidence module's genesis initialization It returns // no validator updates. -func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONMarshaler, bz json.RawMessage) []abci.ValidatorUpdate { +func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONCodec, bz json.RawMessage) []abci.ValidatorUpdate { var gs types.GenesisState err := cdc.UnmarshalJSON(bz, &gs) if err != nil { @@ -176,7 +176,7 @@ func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONMarshaler, bz jso } // ExportGenesis returns the evidence module's exported genesis state as raw JSON bytes. -func (am AppModule) ExportGenesis(ctx sdk.Context, cdc codec.JSONMarshaler) json.RawMessage { +func (am AppModule) ExportGenesis(ctx sdk.Context, cdc codec.JSONCodec) json.RawMessage { return cdc.MustMarshalJSON(ExportGenesis(ctx, am.keeper)) } @@ -194,8 +194,6 @@ func (am AppModule) EndBlock(ctx sdk.Context, _ abci.RequestEndBlock) []abci.Val return []abci.ValidatorUpdate{} } -// ____________________________________________________________________________ - // AppModuleSimulation functions // GenerateGenesisState creates a randomized GenState of the evidence module. diff --git a/x/evidence/spec/01_concepts.md b/x/evidence/spec/01_concepts.md index 1e3866e3c7..69b379d876 100644 --- a/x/evidence/spec/01_concepts.md +++ b/x/evidence/spec/01_concepts.md @@ -66,7 +66,8 @@ The `Handler` (defined below) is responsible for executing the entirety of the business logic for handling `Evidence`. This typically includes validating the evidence, both stateless checks via `ValidateBasic` and stateful checks via any keepers provided to the `Handler`. In addition, the `Handler` may also perform -capabilities such as slashing and jailing a validator. +capabilities such as slashing and jailing a validator. All `Evidence` handled +by the `Handler` should be persisted. ```go // Handler defines an agnostic Evidence handler. The handler is responsible diff --git a/x/evidence/spec/06_begin_block.md b/x/evidence/spec/06_begin_block.md index 317b5523ee..8a6c83327f 100644 --- a/x/evidence/spec/06_begin_block.md +++ b/x/evidence/spec/06_begin_block.md @@ -7,19 +7,16 @@ order: 6 ## Evidence Handling Tendermint blocks can include -[Evidence](https://github.com/tendermint/tendermint/blob/master/docs/spec/blockchain/blockchain.md#evidence), -which indicates that a validator committed malicious behavior. The relevant information is -forwarded to the application as ABCI Evidence in `abci.RequestBeginBlock` so that -the validator an be accordingly punished. +[Evidence](https://github.com/tendermint/tendermint/blob/master/docs/spec/blockchain/blockchain.md#evidence) that indicates if a validator committed malicious behavior. The relevant information is forwarded to the application as ABCI Evidence in `abci.RequestBeginBlock` so that the validator can be punished accordingly. ### Equivocation -Currently, the SDK handles two types of evidence inside ABCI's `BeginBlock`: +Currently, the SDK handles two types of evidence inside the ABCI `BeginBlock`: - `DuplicateVoteEvidence`, - `LightClientAttackEvidence`. -These two evidence types are handled the same way by the evidence module. First, the SDK converts the Tendermint concrete evidence type to a SDK `Evidence` interface using `Equivocation` as the concrete type. +The evidence module handles these two evidence types the same way. First, the SDK converts the Tendermint concrete evidence type to a SDK `Evidence` interface using `Equivocation` as the concrete type. ```proto // Equivocation implements the Evidence interface. @@ -35,16 +32,18 @@ For some `Equivocation` submitted in `block` to be valid, it must satisfy: `Evidence.Timestamp >= block.Timestamp - MaxEvidenceAge` -Where `Evidence.Timestamp` is the timestamp in the block at height `Evidence.Height` and -`block.Timestamp` is the current block timestamp. +Where: + +- `Evidence.Timestamp` is the timestamp in the block at height `Evidence.Height` +- `block.Timestamp` is the current block timestamp. If valid `Equivocation` evidence is included in a block, the validator's stake is -reduced (slashed) by `SlashFractionDoubleSign`, which is defined by the `x/slashing` module, -of what their stake was when the infraction occurred (rather than when the evidence was discovered). -We want to "follow the stake", i.e. the stake which contributed to the infraction +reduced (slashed) by `SlashFractionDoubleSign` as defined by the `x/slashing` module +of what their stake was when the infraction occurred, rather than when the evidence was discovered. +We want to "follow the stake", i.e., the stake that contributed to the infraction should be slashed, even if it has since been redelegated or started unbonding. -In addition, the validator is permanently jailed and tombstoned making it impossible for that +In addition, the validator is permanently jailed and tombstoned to make it impossible for that validator to ever re-enter the validator set. The `Equivocation` evidence is handled as follows: @@ -151,5 +150,5 @@ func (k Keeper) HandleEquivocationEvidence(ctx sdk.Context, evidence *types.Equi ``` Note, the slashing, jailing, and tombstoning calls are delegated through the `x/slashing` module -which emit informative events and finally delegate calls to the `x/staking` module. Documentation -on slashing and jailing can be found in the [x/staking spec](/.././cosmos-sdk/x/staking/spec/02_state_transitions.md) +that emits informative events and finally delegates calls to the `x/staking` module. See documentation +on slashing and jailing in [x/staking spec](/.././cosmos-sdk/x/staking/spec/02_state_transitions.md). diff --git a/x/evidence/spec/07_client.md b/x/evidence/spec/07_client.md new file mode 100644 index 0000000000..52a4b34f70 --- /dev/null +++ b/x/evidence/spec/07_client.md @@ -0,0 +1,188 @@ +# Client + +## CLI + +A user can query and interact with the `evidence` module using the CLI. + +### Query + +The `query` commands allows users to query `evidence` state. + +```bash +simd query evidence --help +``` + +### evidence + +The `evidence` command allows users to list all evidence or evidence by hash. + +Usage: + +```bash +simd query evidence [flags] +``` + +To query evidence by hash + +Example: + +```bash +simd query evidence "DF0C23E8634E480F84B9D5674A7CDC9816466DEC28A3358F73260F68D28D7660" +``` + +Example Output: + +```bash +evidence: + consensus_address: cosmosvalcons1ntk8eualewuprz0gamh8hnvcem2nrcdsgz563h + height: 11 + power: 100 + time: "2021-10-20T16:08:38.194017624Z" +``` + +To get all evidence + +Example: + +```bash +simd query evidence +``` + +Example Output: + +```bash +evidence: + consensus_address: cosmosvalcons1ntk8eualewuprz0gamh8hnvcem2nrcdsgz563h + height: 11 + power: 100 + time: "2021-10-20T16:08:38.194017624Z" +pagination: + next_key: null + total: "1" +``` + +## REST + +A user can query the `evidence` module using REST endpoints. + +### Evidence + +Get evidence by hash + +```bash +/cosmos/evidence/v1beta1/evidence/{evidence_hash} +``` + +Example: + +```bash +curl -X GET "http://localhost:1317/cosmos/evidence/v1beta1/evidence/DF0C23E8634E480F84B9D5674A7CDC9816466DEC28A3358F73260F68D28D7660" +``` + +Example Output: + +```bash +{ + "evidence": { + "consensus_address": "cosmosvalcons1ntk8eualewuprz0gamh8hnvcem2nrcdsgz563h", + "height": "11", + "power": "100", + "time": "2021-10-20T16:08:38.194017624Z" + } +} +``` + +### All evidence + +Get all evidence + +```bash +/cosmos/evidence/v1beta1/evidence +``` + +Example: + +```bash +curl -X GET "http://localhost:1317/cosmos/evidence/v1beta1/evidence" +``` + +Example Output: + +```bash +{ + "evidence": [ + { + "consensus_address": "cosmosvalcons1ntk8eualewuprz0gamh8hnvcem2nrcdsgz563h", + "height": "11", + "power": "100", + "time": "2021-10-20T16:08:38.194017624Z" + } + ], + "pagination": { + "total": "1" + } +} +``` + +## gRPC + +A user can query the `evidence` module using gRPC endpoints. + +### Evidence + +Get evidence by hash + +```bash +cosmos.evidence.v1beta1.Query/Evidence +``` + +Example: + +```bash +grpcurl -plaintext -d '{"evidence_hash":"DF0C23E8634E480F84B9D5674A7CDC9816466DEC28A3358F73260F68D28D7660"}' localhost:9090 cosmos.evidence.v1beta1.Query/Evidence +``` + +Example Output: + +```bash +{ + "evidence": { + "consensus_address": "cosmosvalcons1ntk8eualewuprz0gamh8hnvcem2nrcdsgz563h", + "height": "11", + "power": "100", + "time": "2021-10-20T16:08:38.194017624Z" + } +} +``` + +### All evidence + +Get all evidence + +```bash +cosmos.evidence.v1beta1.Query/AllEvidence +``` + +Example: + +```bash +grpcurl -plaintext localhost:9090 cosmos.evidence.v1beta1.Query/AllEvidence +``` + +Example Output: + +```bash +{ + "evidence": [ + { + "consensus_address": "cosmosvalcons1ntk8eualewuprz0gamh8hnvcem2nrcdsgz563h", + "height": "11", + "power": "100", + "time": "2021-10-20T16:08:38.194017624Z" + } + ], + "pagination": { + "total": "1" + } +} +``` diff --git a/x/evidence/types/msgs_test.go b/x/evidence/types/msgs_test.go index 65efd370d5..60b2da4c76 100644 --- a/x/evidence/types/msgs_test.go +++ b/x/evidence/types/msgs_test.go @@ -50,8 +50,7 @@ func TestMsgSubmitEvidence(t *testing.T) { } for i, tc := range testCases { - require.Equal(t, tc.msg.Route(), types.RouterKey, "unexpected result for tc #%d", i) - require.Equal(t, tc.msg.Type(), types.TypeMsgSubmitEvidence, "unexpected result for tc #%d", i) + require.Equal(t, sdk.MsgTypeURL(&types.MsgSubmitEvidence{}), sdk.MsgTypeURL(tc.msg), "unexpected result for tc #%d", i) require.Equal(t, tc.expectErr, tc.msg.ValidateBasic() != nil, "unexpected result for tc #%d", i) if !tc.expectErr { diff --git a/x/evidence/types/query.pb.gw.go b/x/evidence/types/query.pb.gw.go index d57ad3a7ad..5a0cc8f340 100644 --- a/x/evidence/types/query.pb.gw.go +++ b/x/evidence/types/query.pb.gw.go @@ -252,9 +252,9 @@ func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, clie } var ( - pattern_Query_Evidence_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 1, 1, 0, 4, 1, 5, 3}, []string{"lbm", "evidence", "v1", "evidence_hash"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_Query_Evidence_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 1, 1, 0, 4, 1, 5, 3}, []string{"lbm", "evidence", "v1", "evidence_hash"}, "", runtime.AssumeColonVerbOpt(false))) - pattern_Query_AllEvidence_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 1}, []string{"lbm", "evidence", "v1"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_Query_AllEvidence_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 1}, []string{"lbm", "evidence", "v1"}, "", runtime.AssumeColonVerbOpt(false))) ) var ( diff --git a/x/feegrant/types/basic_fee.go b/x/feegrant/basic_fee.go similarity index 99% rename from x/feegrant/types/basic_fee.go rename to x/feegrant/basic_fee.go index e15565e09c..a7861c056b 100644 --- a/x/feegrant/types/basic_fee.go +++ b/x/feegrant/basic_fee.go @@ -1,4 +1,4 @@ -package types +package feegrant import ( sdk "github.com/line/lbm-sdk/types" diff --git a/x/feegrant/types/filtered_fee_test.go b/x/feegrant/basic_fee_test.go similarity index 51% rename from x/feegrant/types/filtered_fee_test.go rename to x/feegrant/basic_fee_test.go index fe80b972a1..364343bf97 100644 --- a/x/feegrant/types/filtered_fee_test.go +++ b/x/feegrant/basic_fee_test.go @@ -1,26 +1,25 @@ -package types_test +package feegrant_test import ( "testing" "time" - ocproto "github.com/line/ostracon/proto/ostracon/types" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - authtypes "github.com/line/lbm-sdk/x/auth/types" - "github.com/line/lbm-sdk/x/feegrant/types" + ocproto "github.com/line/ostracon/proto/ostracon/types" "github.com/line/lbm-sdk/simapp" sdk "github.com/line/lbm-sdk/types" + "github.com/line/lbm-sdk/x/feegrant" ) -func TestFilteredFeeValidAllow(t *testing.T) { +func TestBasicFeeValidAllow(t *testing.T) { app := simapp.Setup(false) ctx := app.BaseApp.NewContext(false, ocproto.Header{}) badTime := ctx.BlockTime().AddDate(0, 0, -1) - allowace := &types.BasicAllowance{ + allowace := &feegrant.BasicAllowance{ Expiration: &badTime, } require.Error(t, allowace.ValidateBasic()) @@ -37,8 +36,7 @@ func TestFilteredFeeValidAllow(t *testing.T) { oneHour := now.Add(1 * time.Hour) cases := map[string]struct { - allowance *types.BasicAllowance - msgs []string + allowance *feegrant.BasicAllowance // all other checks are ignored if valid=false fee sdk.Coins blockTime time.Time @@ -47,49 +45,39 @@ func TestFilteredFeeValidAllow(t *testing.T) { remove bool remains sdk.Coins }{ - "msg contained": { - allowance: &types.BasicAllowance{}, - msgs: []string{"/lbm.auth.v1.MsgEmpty"}, + "empty": { + allowance: &feegrant.BasicAllowance{}, accept: true, }, - "msg not contained": { - allowance: &types.BasicAllowance{}, - msgs: []string{"/lbm.feegrant.v1.MsgGrant"}, - accept: false, - }, "small fee without expire": { - allowance: &types.BasicAllowance{ + allowance: &feegrant.BasicAllowance{ SpendLimit: atom, }, - msgs: []string{"/lbm.auth.v1.MsgEmpty"}, fee: smallAtom, accept: true, remove: false, remains: leftAtom, }, "all fee without expire": { - allowance: &types.BasicAllowance{ + allowance: &feegrant.BasicAllowance{ SpendLimit: smallAtom, }, - msgs: []string{"/lbm.auth.v1.MsgEmpty"}, fee: smallAtom, accept: true, remove: true, }, "wrong fee": { - allowance: &types.BasicAllowance{ + allowance: &feegrant.BasicAllowance{ SpendLimit: smallAtom, }, - msgs: []string{"/lbm.auth.v1.MsgEmpty"}, fee: eth, accept: false, }, "non-expired": { - allowance: &types.BasicAllowance{ + allowance: &feegrant.BasicAllowance{ SpendLimit: atom, Expiration: &oneHour, }, - msgs: []string{"/lbm.auth.v1.MsgEmpty"}, valid: true, fee: smallAtom, blockTime: now, @@ -98,11 +86,10 @@ func TestFilteredFeeValidAllow(t *testing.T) { remains: leftAtom, }, "expired": { - allowance: &types.BasicAllowance{ + allowance: &feegrant.BasicAllowance{ SpendLimit: atom, Expiration: &now, }, - msgs: []string{"/lbm.auth.v1.MsgEmpty"}, valid: true, fee: smallAtom, blockTime: oneHour, @@ -110,37 +97,35 @@ func TestFilteredFeeValidAllow(t *testing.T) { remove: true, }, "fee more than allowed": { - allowance: &types.BasicAllowance{ + allowance: &feegrant.BasicAllowance{ SpendLimit: atom, Expiration: &oneHour, }, - msgs: []string{"/lbm.auth.v1.MsgEmpty"}, valid: true, fee: bigAtom, blockTime: now, accept: false, }, "with out spend limit": { - allowance: &types.BasicAllowance{ + allowance: &feegrant.BasicAllowance{ Expiration: &oneHour, }, - msgs: []string{"/lbm.auth.v1.MsgEmpty"}, valid: true, fee: bigAtom, blockTime: now, accept: true, }, "expired no spend limit": { - allowance: &types.BasicAllowance{ + allowance: &feegrant.BasicAllowance{ Expiration: &now, }, - msgs: []string{"/lbm.auth.v1.MsgEmpty"}, valid: true, fee: bigAtom, blockTime: oneHour, accept: false, }, } + require.Error(t, allowace.ValidateBasic()) for name, stc := range cases { tc := stc // to make scopelint happy @@ -150,26 +135,8 @@ func TestFilteredFeeValidAllow(t *testing.T) { ctx := app.BaseApp.NewContext(false, ocproto.Header{}).WithBlockTime(tc.blockTime) - // create grant - createGrant := func() types.Grant { - var granter, grantee sdk.AccAddress - allowance, err := types.NewAllowedMsgAllowance(tc.allowance, tc.msgs) - require.NoError(t, err) - grant, err := types.NewGrant(granter, grantee, allowance) - require.NoError(t, err) - return grant - } - grant := createGrant() - - // create empty msg - call := authtypes.MsgEmpty{ - FromAddress: "", - } - // now try to deduct - allowance, err := grant.GetGrant() - require.NoError(t, err) - removed, err := allowance.Accept(ctx, tc.fee, []sdk.Msg{&call}) + removed, err := tc.allowance.Accept(ctx, tc.fee, []sdk.Msg{}) if !tc.accept { require.Error(t, err) return @@ -178,31 +145,7 @@ func TestFilteredFeeValidAllow(t *testing.T) { require.Equal(t, tc.remove, removed) if !removed { - updatedGrant := func(granter, grantee sdk.AccAddress, - allowance types.FeeAllowanceI) types.Grant { - newGrant, err := types.NewGrant( - granter, - grantee, - allowance) - require.NoError(t, err) - - cdc := simapp.MakeTestEncodingConfig().Marshaler - bz, err := cdc.MarshalBinaryBare(&newGrant) - require.NoError(t, err) - - var loaded types.Grant - err = cdc.UnmarshalBinaryBare(bz, &loaded) - require.NoError(t, err) - return loaded - } - newGrant := updatedGrant(sdk.AccAddress(grant.Granter), - sdk.AccAddress(grant.Grantee), allowance) - - newAllowance, err := newGrant.GetGrant() - require.NoError(t, err) - feeAllowance, err := newAllowance.(*types.AllowedMsgAllowance).GetAllowance() - require.NoError(t, err) - assert.Equal(t, tc.remains, feeAllowance.(*types.BasicAllowance).SpendLimit) + assert.Equal(t, tc.allowance.SpendLimit, tc.remains) } }) } diff --git a/x/feegrant/client/cli/query.go b/x/feegrant/client/cli/query.go index e26d6b10ba..44eb1ab99b 100644 --- a/x/feegrant/client/cli/query.go +++ b/x/feegrant/client/cli/query.go @@ -6,18 +6,17 @@ import ( "github.com/spf13/cobra" - "github.com/line/lbm-sdk/x/feegrant/types" - "github.com/line/lbm-sdk/client" "github.com/line/lbm-sdk/client/flags" sdk "github.com/line/lbm-sdk/types" "github.com/line/lbm-sdk/version" + "github.com/line/lbm-sdk/x/feegrant" ) // GetQueryCmd returns the cli query commands for this module func GetQueryCmd() *cobra.Command { feegrantQueryCmd := &cobra.Command{ - Use: types.ModuleName, + Use: feegrant.ModuleName, Short: "Querying commands for the feegrant module", DisableFlagParsing: true, SuggestionsMinimumDistance: 2, @@ -48,7 +47,7 @@ $ %s query feegrant grant [granter] [grantee] ), RunE: func(cmd *cobra.Command, args []string) error { clientCtx := client.GetClientContextFromCmd(cmd) - queryClient := types.NewQueryClient(clientCtx) + queryClient := feegrant.NewQueryClient(clientCtx) err := sdk.ValidateAccAddress(args[0]) if err != nil { @@ -64,7 +63,7 @@ $ %s query feegrant grant [granter] [grantee] res, err := queryClient.Allowance( cmd.Context(), - &types.QueryAllowanceRequest{ + &feegrant.QueryAllowanceRequest{ Granter: granterAddr.String(), Grantee: granteeAddr.String(), }, @@ -98,7 +97,7 @@ $ %s query feegrant grants [grantee] ), RunE: func(cmd *cobra.Command, args []string) error { clientCtx := client.GetClientContextFromCmd(cmd) - queryClient := types.NewQueryClient(clientCtx) + queryClient := feegrant.NewQueryClient(clientCtx) err := sdk.ValidateAccAddress(args[0]) if err != nil { @@ -113,7 +112,7 @@ $ %s query feegrant grants [grantee] res, err := queryClient.Allowances( cmd.Context(), - &types.QueryAllowancesRequest{ + &feegrant.QueryAllowancesRequest{ Grantee: granteeAddr.String(), Pagination: pageReq, }, diff --git a/x/feegrant/client/cli/tx.go b/x/feegrant/client/cli/tx.go index 175c732af6..e4e2cb23a1 100644 --- a/x/feegrant/client/cli/tx.go +++ b/x/feegrant/client/cli/tx.go @@ -7,13 +7,12 @@ import ( "github.com/spf13/cobra" - "github.com/line/lbm-sdk/x/feegrant/types" - "github.com/line/lbm-sdk/client" "github.com/line/lbm-sdk/client/flags" "github.com/line/lbm-sdk/client/tx" sdk "github.com/line/lbm-sdk/types" "github.com/line/lbm-sdk/version" + "github.com/line/lbm-sdk/x/feegrant" ) // flag for feegrant module @@ -28,7 +27,7 @@ const ( // GetTxCmd returns the transaction commands for this module func GetTxCmd() *cobra.Command { feegrantTxCmd := &cobra.Command{ - Use: types.ModuleName, + Use: feegrant.ModuleName, Short: "Feegrant transactions subcommands", Long: "Grant and revoke fee allowance for a grantee by a granter", DisableFlagParsing: true, @@ -55,11 +54,11 @@ func NewCmdFeeGrant() *cobra.Command { ignored as it is implied from [granter]. Examples: -%s tx %s grant cosmos1skjw... cosmos1skjw... --spend-limit 100stake --expiration 2022-01-30T15:04:05Z or -%s tx %s grant cosmos1skjw... cosmos1skjw... --spend-limit 100stake --period 3600 --period-limit 10stake --expiration 36000 or -%s tx %s grant cosmos1skjw... cosmos1skjw... --spend-limit 100stake --expiration 2022-01-30T15:04:05Z - --allowed-messages "/cosmos.gov.v1beta1.MsgSubmitProposal,/cosmos.gov.v1beta1.MsgVote" - `, version.AppName, types.ModuleName, version.AppName, types.ModuleName, version.AppName, types.ModuleName, +%s tx %s grant link1skjw... link1skjw... --spend-limit 100stake --expiration 2022-01-30T15:04:05Z or +%s tx %s grant link1skjw... link1skjw... --spend-limit 100stake --period 3600 --period-limit 10stake --expiration 2022-01-30T15:04:05Z or +%s tx %s grant link1skjw... link1skjw... --spend-limit 100stake --expiration 2022-01-30T15:04:05Z + --allowed-messages "/lbm.gov.v1.MsgSubmitProposal,/lbm.gov.v1.MsgVote" + `, version.AppName, feegrant.ModuleName, version.AppName, feegrant.ModuleName, version.AppName, feegrant.ModuleName, ), ), Args: cobra.ExactArgs(2), @@ -94,7 +93,7 @@ Examples: return err } - basic := types.BasicAllowance{ + basic := feegrant.BasicAllowance{ SpendLimit: limit, } @@ -107,7 +106,7 @@ Examples: basic.Expiration = &expiresAtTime } - var grant types.FeeAllowanceI + var grant feegrant.FeeAllowanceI grant = &basic periodClock, err := cmd.Flags().GetInt64(FlagPeriod) @@ -140,7 +139,7 @@ Examples: return fmt.Errorf("period (%d) cannot reset after expiration (%v)", periodClock, exp) } - periodic := types.PeriodicAllowance{ + periodic := feegrant.PeriodicAllowance{ Basic: basic, Period: getPeriod(periodClock), PeriodReset: getPeriodReset(periodClock), @@ -157,13 +156,13 @@ Examples: } if len(allowedMsgs) > 0 { - grant, err = types.NewAllowedMsgAllowance(grant, allowedMsgs) + grant, err = feegrant.NewAllowedMsgAllowance(grant, allowedMsgs) if err != nil { return err } } - msg, err := types.NewMsgGrantAllowance(grant, granter, grantee) + msg, err := feegrant.NewMsgGrantAllowance(grant, granter, grantee) if err != nil { return err } @@ -176,7 +175,7 @@ Examples: cmd.Flags().StringSlice(FlagAllowedMsgs, []string{}, "Set of allowed messages for fee allowance") cmd.Flags().String(FlagExpiration, "", "The RFC 3339 timestamp after which the grant expires for the user") cmd.Flags().String(FlagSpendLimit, "", "Spend limit specifies the max limit can be used, if not mentioned there is no limit") - cmd.Flags().Int64(FlagPeriod, 0, "period specifies the time duration in which period_spend_limit coins can be spent before that allowance is reset") + cmd.Flags().Int64(FlagPeriod, 0, "period specifies the time duration(in seconds) in which period_limit coins can be spent before that allowance is reset (ex: 3600)") cmd.Flags().String(FlagPeriodLimit, "", "period limit specifies the maximum number of coins that can be spent in the period") return cmd @@ -192,8 +191,8 @@ func NewCmdRevokeFeegrant() *cobra.Command { ignored as it is implied from [granter]. Example: - $ %s tx %s revoke cosmos1skj.. cosmos1skj.. - `, version.AppName, types.ModuleName), + $ %s tx %s revoke link1skj.. link1skj.. + `, version.AppName, feegrant.ModuleName), ), Args: cobra.ExactArgs(2), RunE: func(cmd *cobra.Command, args []string) error { @@ -209,7 +208,7 @@ Example: } grantee := sdk.AccAddress(args[1]) - msg := types.NewMsgRevokeAllowance(clientCtx.GetFromAddress(), grantee) + msg := feegrant.NewMsgRevokeAllowance(clientCtx.GetFromAddress(), grantee) return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), &msg) }, diff --git a/x/feegrant/client/testutil/cli_test.go b/x/feegrant/client/testutil/cli_test.go index a4cc047579..fd0f9ed0d5 100644 --- a/x/feegrant/client/testutil/cli_test.go +++ b/x/feegrant/client/testutil/cli_test.go @@ -1,3 +1,4 @@ +//go:build norace // +build norace package testutil @@ -5,9 +6,9 @@ package testutil import ( "testing" - "github.com/line/lbm-sdk/testutil/network" - "github.com/stretchr/testify/suite" + + "github.com/line/lbm-sdk/testutil/network" ) func TestIntegrationTestSuite(t *testing.T) { diff --git a/x/feegrant/client/testutil/suite.go b/x/feegrant/client/testutil/suite.go index f4baee8439..0ad6ea733f 100644 --- a/x/feegrant/client/testutil/suite.go +++ b/x/feegrant/client/testutil/suite.go @@ -7,10 +7,9 @@ import ( "time" "github.com/gogo/protobuf/proto" - tmcli "github.com/line/ostracon/libs/cli" "github.com/stretchr/testify/suite" - "github.com/line/lbm-sdk/x/feegrant/types" + ostcli "github.com/line/ostracon/libs/cli" "github.com/line/lbm-sdk/client" "github.com/line/lbm-sdk/client/flags" @@ -20,6 +19,7 @@ import ( clitestutil "github.com/line/lbm-sdk/testutil/cli" "github.com/line/lbm-sdk/testutil/network" sdk "github.com/line/lbm-sdk/types" + "github.com/line/lbm-sdk/x/feegrant" "github.com/line/lbm-sdk/x/feegrant/client/cli" govtestutil "github.com/line/lbm-sdk/x/gov/client/testutil" govtypes "github.com/line/lbm-sdk/x/gov/types" @@ -38,7 +38,7 @@ type IntegrationTestSuite struct { network *network.Network addedGranter sdk.AccAddress addedGrantee sdk.AccAddress - addedGrant types.Grant + addedGrant feegrant.Grant } func NewIntegrationTestSuite(cfg network.Config) *IntegrationTestSuite { @@ -64,7 +64,7 @@ func (s *IntegrationTestSuite) SetupSuite() { s.createGrant(granter, grantee) - grant, err := types.NewGrant(granter, grantee, &types.BasicAllowance{ + grant, err := feegrant.NewGrant(granter, grantee, &feegrant.BasicAllowance{ SpendLimit: sdk.NewCoins(sdk.NewCoin("stake", sdk.NewInt(100))), }) s.Require().NoError(err) @@ -122,15 +122,15 @@ func (s *IntegrationTestSuite) TestCmdGetFeeGrant() { args []string expectErrMsg string expectErr bool - respType *types.Grant - resp *types.Grant + respType *feegrant.Grant + resp *feegrant.Grant }{ { "wrong granter", []string{ "wrong_granter", grantee.String(), - fmt.Sprintf("--%s=json", tmcli.OutputFlag), + fmt.Sprintf("--%s=json", ostcli.OutputFlag), }, "decoding bech32 failed", true, nil, nil, @@ -140,7 +140,7 @@ func (s *IntegrationTestSuite) TestCmdGetFeeGrant() { []string{ granter.String(), "wrong_grantee", - fmt.Sprintf("--%s=json", tmcli.OutputFlag), + fmt.Sprintf("--%s=json", ostcli.OutputFlag), }, "decoding bech32 failed", true, nil, nil, @@ -150,7 +150,7 @@ func (s *IntegrationTestSuite) TestCmdGetFeeGrant() { []string{ "link19lrl5da53xtd2yssw2799y53uyaskadqkzv0ky", grantee.String(), - fmt.Sprintf("--%s=json", tmcli.OutputFlag), + fmt.Sprintf("--%s=json", ostcli.OutputFlag), }, "fee-grant not found", true, nil, nil, @@ -160,11 +160,11 @@ func (s *IntegrationTestSuite) TestCmdGetFeeGrant() { []string{ granter.String(), grantee.String(), - fmt.Sprintf("--%s=json", tmcli.OutputFlag), + fmt.Sprintf("--%s=json", ostcli.OutputFlag), }, "", false, - &types.Grant{}, + &feegrant.Grant{}, &s.addedGrant, }, } @@ -181,7 +181,7 @@ func (s *IntegrationTestSuite) TestCmdGetFeeGrant() { s.Require().Contains(err.Error(), tc.expectErrMsg) } else { s.Require().NoError(err) - s.Require().NoError(clientCtx.JSONMarshaler.UnmarshalJSON(out.Bytes(), tc.respType), out.String()) + s.Require().NoError(clientCtx.Codec.UnmarshalJSON(out.Bytes(), tc.respType), out.String()) s.Require().Equal(tc.respType.Grantee, tc.respType.Grantee) s.Require().Equal(tc.respType.Granter, tc.respType.Granter) grant, err := tc.respType.GetGrant() @@ -189,8 +189,8 @@ func (s *IntegrationTestSuite) TestCmdGetFeeGrant() { grant1, err1 := tc.resp.GetGrant() s.Require().NoError(err1) s.Require().Equal( - grant.(*types.BasicAllowance).SpendLimit, - grant1.(*types.BasicAllowance).SpendLimit, + grant.(*feegrant.BasicAllowance).SpendLimit, + grant1.(*feegrant.BasicAllowance).SpendLimit, ) } }) @@ -206,14 +206,14 @@ func (s *IntegrationTestSuite) TestCmdGetFeeGrants() { name string args []string expectErr bool - resp *types.QueryAllowancesResponse + resp *feegrant.QueryAllowancesResponse expectLength int }{ { "wrong grantee", []string{ "wrong_grantee", - fmt.Sprintf("--%s=json", tmcli.OutputFlag), + fmt.Sprintf("--%s=json", ostcli.OutputFlag), }, true, nil, 0, }, @@ -221,17 +221,17 @@ func (s *IntegrationTestSuite) TestCmdGetFeeGrants() { "non existed grantee", []string{ "link19lrl5da53xtd2yssw2799y53uyaskadqkzv0ky", - fmt.Sprintf("--%s=json", tmcli.OutputFlag), + fmt.Sprintf("--%s=json", ostcli.OutputFlag), }, - false, &types.QueryAllowancesResponse{}, 0, + false, &feegrant.QueryAllowancesResponse{}, 0, }, { "valid req", []string{ grantee.String(), - fmt.Sprintf("--%s=json", tmcli.OutputFlag), + fmt.Sprintf("--%s=json", ostcli.OutputFlag), }, - false, &types.QueryAllowancesResponse{}, 1, + false, &feegrant.QueryAllowancesResponse{}, 1, }, } @@ -246,7 +246,7 @@ func (s *IntegrationTestSuite) TestCmdGetFeeGrants() { s.Require().Error(err) } else { s.Require().NoError(err) - s.Require().NoError(clientCtx.JSONMarshaler.UnmarshalJSON(out.Bytes(), tc.resp), out.String()) + s.Require().NoError(clientCtx.Codec.UnmarshalJSON(out.Bytes(), tc.resp), out.String()) s.Require().Len(tc.resp.Allowances, tc.expectLength) } }) @@ -539,7 +539,7 @@ func (s *IntegrationTestSuite) TestNewCmdFeeGrant() { s.Require().Error(err) } else { s.Require().NoError(err) - s.Require().NoError(clientCtx.JSONMarshaler.UnmarshalJSON(out.Bytes(), tc.respType), out.String()) + s.Require().NoError(clientCtx.Codec.UnmarshalJSON(out.Bytes(), tc.respType), out.String()) txResp := tc.respType.(*sdk.TxResponse) s.Require().Equal(tc.expectedCode, txResp.Code, out.String()) @@ -645,7 +645,7 @@ func (s *IntegrationTestSuite) TestNewCmdRevokeFeegrant() { s.Require().Error(err) } else { s.Require().NoError(err) - s.Require().NoError(clientCtx.JSONMarshaler.UnmarshalJSON(out.Bytes(), tc.respType), out.String()) + s.Require().NoError(clientCtx.Codec.UnmarshalJSON(out.Bytes(), tc.respType), out.String()) txResp := tc.respType.(*sdk.TxResponse) s.Require().Equal(tc.expectedCode, txResp.Code, out.String()) @@ -660,7 +660,7 @@ func (s *IntegrationTestSuite) TestTxWithFeeGrant() { granter := val.Address // creating an account manually (This account won't be exist in state) - k, _, err := val.ClientCtx.Keyring.NewMnemonic("grantee", keyring.English, sdk.FullFundraiserPath, hd.Secp256k1) + k, _, err := val.ClientCtx.Keyring.NewMnemonic("grantee", keyring.English, sdk.FullFundraiserPath, keyring.DefaultBIP39Passphrase, hd.Secp256k1) s.Require().NoError(err) pub := k.GetPubKey() grantee := sdk.BytesToAccAddress(pub.Address()) @@ -700,7 +700,7 @@ func (s *IntegrationTestSuite) TestTxWithFeeGrant() { s.Require().NoError(err) var resp sdk.TxResponse - s.Require().NoError(clientCtx.JSONMarshaler.UnmarshalJSON(out.Bytes(), &resp), out.String()) + s.Require().NoError(clientCtx.Codec.UnmarshalJSON(out.Bytes(), &resp), out.String()) s.Require().Equal(uint32(0), resp.Code) } @@ -708,7 +708,7 @@ func (s *IntegrationTestSuite) TestFilteredFeeAllowance() { val := s.network.Validators[0] granter := val.Address - k, _, err := val.ClientCtx.Keyring.NewMnemonic("grantee1", keyring.English, sdk.FullFundraiserPath, hd.Secp256k1) + k, _, err := val.ClientCtx.Keyring.NewMnemonic("grantee1", keyring.English, sdk.FullFundraiserPath, keyring.DefaultBIP39Passphrase, hd.Secp256k1) s.Require().NoError(err) pub := k.GetPubKey() grantee := sdk.BytesToAccAddress(pub.Address()) @@ -786,7 +786,7 @@ func (s *IntegrationTestSuite) TestFilteredFeeAllowance() { s.Require().Error(err) } else { s.Require().NoError(err) - s.Require().NoError(clientCtx.JSONMarshaler.UnmarshalJSON(out.Bytes(), tc.respType), out.String()) + s.Require().NoError(clientCtx.Codec.UnmarshalJSON(out.Bytes(), tc.respType), out.String()) txResp := tc.respType.(*sdk.TxResponse) s.Require().Equal(tc.expectedCode, txResp.Code, out.String()) @@ -797,7 +797,7 @@ func (s *IntegrationTestSuite) TestFilteredFeeAllowance() { args := []string{ granter.String(), grantee.String(), - fmt.Sprintf("--%s=json", tmcli.OutputFlag), + fmt.Sprintf("--%s=json", ostcli.OutputFlag), } // get filtered fee allowance and check info @@ -805,20 +805,20 @@ func (s *IntegrationTestSuite) TestFilteredFeeAllowance() { out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, args) s.Require().NoError(err) - resp := &types.Grant{} + resp := &feegrant.Grant{} - s.Require().NoError(clientCtx.JSONMarshaler.UnmarshalJSON(out.Bytes(), resp), out.String()) + s.Require().NoError(clientCtx.Codec.UnmarshalJSON(out.Bytes(), resp), out.String()) s.Require().Equal(resp.Grantee, resp.Grantee) s.Require().Equal(resp.Granter, resp.Granter) grant, err := resp.GetGrant() s.Require().NoError(err) - filteredFeeGrant, err := grant.(*types.AllowedMsgAllowance).GetAllowance() + filteredFeeGrant, err := grant.(*feegrant.AllowedMsgAllowance).GetAllowance() s.Require().NoError(err) s.Require().Equal( - filteredFeeGrant.(*types.BasicAllowance).SpendLimit.String(), + filteredFeeGrant.(*feegrant.BasicAllowance).SpendLimit.String(), spendLimit.String(), ) @@ -876,7 +876,7 @@ func (s *IntegrationTestSuite) TestFilteredFeeAllowance() { s.Run(tc.name, func() { out, err := tc.malleate() s.Require().NoError(err) - s.Require().NoError(clientCtx.JSONMarshaler.UnmarshalJSON(out.Bytes(), tc.respType), out.String()) + s.Require().NoError(clientCtx.Codec.UnmarshalJSON(out.Bytes(), tc.respType), out.String()) txResp := tc.respType.(*sdk.TxResponse) s.Require().Equal(tc.expectedCode, txResp.Code, out.String()) }) diff --git a/x/feegrant/types/codec.go b/x/feegrant/codec.go similarity index 97% rename from x/feegrant/types/codec.go rename to x/feegrant/codec.go index a57bbe2db9..790dddaf70 100644 --- a/x/feegrant/types/codec.go +++ b/x/feegrant/codec.go @@ -1,4 +1,4 @@ -package types +package feegrant import ( "github.com/line/lbm-sdk/codec/types" diff --git a/x/feegrant/types/errors.go b/x/feegrant/errors.go similarity index 98% rename from x/feegrant/types/errors.go rename to x/feegrant/errors.go index a12402d10d..b715aa53a0 100644 --- a/x/feegrant/types/errors.go +++ b/x/feegrant/errors.go @@ -1,4 +1,4 @@ -package types +package feegrant import ( sdkerrors "github.com/line/lbm-sdk/types/errors" diff --git a/x/feegrant/types/events.go b/x/feegrant/events.go similarity index 94% rename from x/feegrant/types/events.go rename to x/feegrant/events.go index b82ccb7b1c..a4470b8270 100644 --- a/x/feegrant/types/events.go +++ b/x/feegrant/events.go @@ -1,4 +1,4 @@ -package types +package feegrant // evidence module events const ( diff --git a/x/feegrant/types/expected_keepers.go b/x/feegrant/expected_keepers.go similarity index 97% rename from x/feegrant/types/expected_keepers.go rename to x/feegrant/expected_keepers.go index 3348eb4f38..80ae17dfe2 100644 --- a/x/feegrant/types/expected_keepers.go +++ b/x/feegrant/expected_keepers.go @@ -1,4 +1,4 @@ -package types +package feegrant import ( sdk "github.com/line/lbm-sdk/types" diff --git a/x/feegrant/types/feegrant.pb.go b/x/feegrant/feegrant.pb.go similarity index 90% rename from x/feegrant/types/feegrant.pb.go rename to x/feegrant/feegrant.pb.go index 3ab8355e03..27b417ad24 100644 --- a/x/feegrant/types/feegrant.pb.go +++ b/x/feegrant/feegrant.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-gogo. DO NOT EDIT. // source: lbm/feegrant/v1/feegrant.proto -package types +package feegrant import ( fmt "fmt" @@ -292,44 +292,44 @@ func init() { func init() { proto.RegisterFile("lbm/feegrant/v1/feegrant.proto", fileDescriptor_3cc1909be6bd11e2) } var fileDescriptor_3cc1909be6bd11e2 = []byte{ - // 590 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x54, 0x3b, 0x6f, 0xd3, 0x50, - 0x14, 0x8e, 0x9b, 0xb6, 0x90, 0x1b, 0x68, 0x1b, 0x53, 0x2a, 0x37, 0x83, 0x1d, 0x85, 0x25, 0x08, - 0xd5, 0x56, 0x0a, 0x53, 0xba, 0x50, 0x17, 0xa8, 0x90, 0xa8, 0x84, 0x0c, 0x13, 0x8b, 0x75, 0x6d, - 0x9f, 0xba, 0x16, 0xb6, 0xaf, 0xe5, 0xeb, 0x84, 0xe6, 0x1f, 0x30, 0x76, 0x64, 0x42, 0xcc, 0xcc, - 0x4c, 0x6c, 0x2c, 0xa8, 0x62, 0xaa, 0x98, 0x98, 0x5a, 0x94, 0xfc, 0x03, 0x7e, 0x01, 0xba, 0x8f, - 0x3c, 0x48, 0x8a, 0x90, 0x50, 0x37, 0xdf, 0x73, 0xce, 0xf7, 0x38, 0x0f, 0x19, 0xe9, 0xb1, 0x97, - 0x58, 0x87, 0x00, 0x61, 0x8e, 0xd3, 0xc2, 0xea, 0xb5, 0xc7, 0xdf, 0x66, 0x96, 0x93, 0x82, 0xa8, - 0xab, 0xb1, 0x97, 0x98, 0xe3, 0x58, 0xaf, 0x5d, 0x5f, 0x0f, 0x49, 0x48, 0x78, 0xce, 0x62, 0x5f, - 0xa2, 0xac, 0xbe, 0x19, 0x12, 0x12, 0xc6, 0x60, 0xf1, 0x97, 0xd7, 0x3d, 0xb4, 0x70, 0xda, 0x1f, - 0xa5, 0x7c, 0x42, 0x13, 0x42, 0x5d, 0x81, 0x11, 0x0f, 0x99, 0xda, 0x60, 0xe2, 0x1e, 0xa6, 0xc0, - 0x84, 0x7d, 0x12, 0xa5, 0x32, 0x6e, 0xcc, 0xb2, 0x15, 0x51, 0x02, 0xb4, 0xc0, 0x49, 0x26, 0x0b, - 0xf4, 0xd9, 0x82, 0xa0, 0x9b, 0xe3, 0x22, 0x22, 0x92, 0xa0, 0xf9, 0x55, 0x41, 0x2b, 0x36, 0xa6, - 0x91, 0xbf, 0x1b, 0xc7, 0xe4, 0x0d, 0x4e, 0x7d, 0x50, 0x5d, 0x54, 0xa5, 0x19, 0xa4, 0x81, 0x1b, - 0x47, 0x49, 0x54, 0x68, 0x4a, 0xa3, 0xdc, 0xaa, 0x6e, 0xd7, 0x4c, 0xd6, 0x1e, 0x73, 0x60, 0xf6, - 0xda, 0xe6, 0x1e, 0x89, 0x52, 0xfb, 0xde, 0xe9, 0xb9, 0x51, 0xfa, 0x78, 0x61, 0xdc, 0x09, 0xa3, - 0xe2, 0xa8, 0xeb, 0x99, 0x3e, 0x49, 0xac, 0x38, 0x4a, 0xc1, 0x8a, 0xbd, 0x64, 0x8b, 0x06, 0xaf, - 0xad, 0xa2, 0x9f, 0x01, 0xe5, 0xb5, 0xd4, 0x41, 0x9c, 0xf2, 0x19, 0x63, 0x54, 0x1f, 0x22, 0x04, - 0xc7, 0x59, 0x24, 0x7c, 0x68, 0x0b, 0x0d, 0xa5, 0x55, 0xdd, 0xae, 0x9b, 0xc2, 0xa8, 0x39, 0x32, - 0x6a, 0xbe, 0x1c, 0x75, 0x62, 0x2f, 0x9e, 0x5c, 0x18, 0x8a, 0x33, 0x85, 0xe9, 0xd4, 0xbe, 0x7f, - 0xda, 0xba, 0xf9, 0x04, 0x60, 0x6c, 0xfa, 0x69, 0xf3, 0x4b, 0x19, 0xd5, 0x9e, 0x43, 0x1e, 0x91, - 0x60, 0xba, 0x97, 0x1d, 0xb4, 0xe4, 0xb1, 0xee, 0x34, 0x85, 0xab, 0x18, 0xe6, 0xcc, 0x92, 0xcc, - 0x3f, 0x7b, 0xb7, 0x17, 0x59, 0x4f, 0x8e, 0xc0, 0xa8, 0x3b, 0x68, 0x39, 0xe3, 0x8c, 0xd2, 0xe3, - 0xe6, 0x9c, 0xc7, 0x47, 0x72, 0x98, 0xf6, 0x75, 0x86, 0x7b, 0xc7, 0x6c, 0x4a, 0x88, 0x1a, 0x23, - 0x55, 0x7c, 0xb9, 0xd3, 0xc3, 0x2c, 0x5f, 0xc9, 0x30, 0xd7, 0x04, 0xf3, 0x8b, 0xc9, 0x48, 0x8f, - 0x90, 0x8c, 0xb9, 0x3e, 0x4e, 0x85, 0xa2, 0xb6, 0x78, 0x25, 0x5a, 0x2b, 0x82, 0x77, 0x0f, 0xa7, - 0x5c, 0x4e, 0xdd, 0x47, 0x37, 0xa4, 0x52, 0x0e, 0x14, 0x0a, 0x6d, 0xe9, 0x9f, 0xeb, 0xe3, 0xb3, - 0xe1, 0x2b, 0xac, 0x0a, 0xa4, 0xc3, 0x80, 0x97, 0xed, 0xf0, 0xbd, 0x82, 0x6e, 0xf1, 0x27, 0x04, - 0x07, 0x34, 0x9c, 0x6c, 0xf1, 0x31, 0xaa, 0xe0, 0xd1, 0x43, 0x6e, 0x72, 0x7d, 0x4e, 0x70, 0x37, - 0xed, 0xdb, 0xb5, 0x6f, 0xb3, 0x9c, 0xce, 0x04, 0xa9, 0xde, 0x45, 0x6b, 0x58, 0xb0, 0xbb, 0x09, - 0x50, 0x8a, 0x43, 0xa0, 0xda, 0x42, 0xa3, 0xdc, 0xaa, 0x38, 0xab, 0x32, 0x7e, 0x20, 0xc3, 0x9d, - 0xdb, 0x6f, 0x3f, 0x18, 0xa5, 0x79, 0x83, 0x9f, 0x15, 0xb4, 0xb4, 0xcf, 0x4e, 0x47, 0x7d, 0x80, - 0xae, 0xf1, 0x1b, 0x82, 0x9c, 0x1b, 0xaa, 0xd8, 0xf5, 0x5f, 0xe7, 0xc6, 0x46, 0x1f, 0x27, 0x71, - 0xa7, 0x29, 0x13, 0x2e, 0x0e, 0x82, 0x1c, 0x28, 0x6d, 0x3a, 0xa3, 0xd2, 0x09, 0x0a, 0xf8, 0x49, - 0x5d, 0x82, 0x82, 0x39, 0xd4, 0x4c, 0xfb, 0xe5, 0xff, 0x6d, 0xdf, 0xb6, 0x4f, 0x07, 0xba, 0x72, - 0x36, 0xd0, 0x95, 0x9f, 0x03, 0x5d, 0x39, 0x19, 0xea, 0xa5, 0xb3, 0xa1, 0x5e, 0xfa, 0x31, 0xd4, - 0x4b, 0xaf, 0x5a, 0x7f, 0x3b, 0x84, 0xe3, 0xc9, 0x0f, 0x8f, 0xdf, 0x84, 0xb7, 0xcc, 0xf5, 0xee, - 0xff, 0x0e, 0x00, 0x00, 0xff, 0xff, 0x2c, 0x40, 0x60, 0x50, 0x0d, 0x05, 0x00, 0x00, + // 591 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x54, 0x3d, 0x6f, 0xd3, 0x4e, + 0x18, 0x8f, 0x9b, 0xb6, 0xff, 0x7f, 0x2e, 0xd0, 0x36, 0xa6, 0x54, 0x6e, 0x06, 0x3b, 0x0a, 0x4b, + 0x10, 0xaa, 0xad, 0x14, 0xa6, 0x94, 0x81, 0xba, 0x40, 0x85, 0x44, 0x25, 0x64, 0x98, 0x58, 0xac, + 0xb3, 0xfd, 0xd4, 0xb5, 0xb0, 0x7d, 0x96, 0xcf, 0x09, 0xcd, 0x37, 0x60, 0xec, 0xc8, 0x84, 0x98, + 0x99, 0x99, 0xd8, 0x58, 0x50, 0xc5, 0x54, 0x31, 0x31, 0xb5, 0x28, 0xf9, 0x06, 0x7c, 0x02, 0x74, + 0x2f, 0x79, 0x21, 0x29, 0x42, 0x42, 0xdd, 0x7c, 0xcf, 0x3d, 0xbf, 0xb7, 0xe7, 0x39, 0x19, 0xe9, + 0xb1, 0x97, 0x58, 0x87, 0x00, 0x61, 0x8e, 0xd3, 0xc2, 0xea, 0xb5, 0xc7, 0xdf, 0x66, 0x96, 0x93, + 0x82, 0xa8, 0xab, 0xb1, 0x97, 0x98, 0xe3, 0x5a, 0xaf, 0x5d, 0x5f, 0x0f, 0x49, 0x48, 0xf8, 0x9d, + 0xc5, 0xbe, 0x44, 0x5b, 0x7d, 0x33, 0x24, 0x24, 0x8c, 0xc1, 0xe2, 0x27, 0xaf, 0x7b, 0x68, 0xe1, + 0xb4, 0x3f, 0xba, 0xf2, 0x09, 0x4d, 0x08, 0x75, 0x05, 0x46, 0x1c, 0xe4, 0xd5, 0x06, 0x13, 0xf7, + 0x30, 0x05, 0x26, 0xec, 0x93, 0x28, 0x95, 0x75, 0x63, 0x96, 0xad, 0x88, 0x12, 0xa0, 0x05, 0x4e, + 0x32, 0xd9, 0xa0, 0xcf, 0x36, 0x04, 0xdd, 0x1c, 0x17, 0x11, 0x91, 0x04, 0xcd, 0x2f, 0x0a, 0x5a, + 0xb1, 0x31, 0x8d, 0xfc, 0xdd, 0x38, 0x26, 0xaf, 0x71, 0xea, 0x83, 0xea, 0xa2, 0x2a, 0xcd, 0x20, + 0x0d, 0xdc, 0x38, 0x4a, 0xa2, 0x42, 0x53, 0x1a, 0xe5, 0x56, 0x75, 0xbb, 0x66, 0xb2, 0x78, 0xcc, + 0x81, 0xd9, 0x6b, 0x9b, 0x7b, 0x24, 0x4a, 0xed, 0x3b, 0xa7, 0xe7, 0x46, 0xe9, 0xc3, 0x85, 0x71, + 0x2b, 0x8c, 0x8a, 0xa3, 0xae, 0x67, 0xfa, 0x24, 0xb1, 0xe2, 0x28, 0x05, 0x2b, 0xf6, 0x92, 0x2d, + 0x1a, 0xbc, 0xb2, 0x8a, 0x7e, 0x06, 0x94, 0xf7, 0x52, 0x07, 0x71, 0xca, 0xa7, 0x8c, 0x51, 0x7d, + 0x80, 0x10, 0x1c, 0x67, 0x91, 0xf0, 0xa1, 0x2d, 0x34, 0x94, 0x56, 0x75, 0xbb, 0x6e, 0x0a, 0xa3, + 0xe6, 0xc8, 0xa8, 0xf9, 0x62, 0x94, 0xc4, 0x5e, 0x3c, 0xb9, 0x30, 0x14, 0x67, 0x0a, 0xd3, 0xa9, + 0x7d, 0xfb, 0xb8, 0x75, 0xfd, 0x31, 0xc0, 0xd8, 0xf4, 0x93, 0xe6, 0xe7, 0x32, 0xaa, 0x3d, 0x83, + 0x3c, 0x22, 0xc1, 0x74, 0x96, 0x1d, 0xb4, 0xe4, 0xb1, 0x74, 0x9a, 0xc2, 0x55, 0x0c, 0x73, 0x66, + 0x49, 0xe6, 0xef, 0xd9, 0xed, 0x45, 0x96, 0xc9, 0x11, 0x18, 0x75, 0x07, 0x2d, 0x67, 0x9c, 0x51, + 0x7a, 0xdc, 0x9c, 0xf3, 0xf8, 0x50, 0x0e, 0xd3, 0xfe, 0x9f, 0xe1, 0xde, 0x32, 0x9b, 0x12, 0xa2, + 0xc6, 0x48, 0x15, 0x5f, 0xee, 0xf4, 0x30, 0xcb, 0x57, 0x32, 0xcc, 0x35, 0xc1, 0xfc, 0x7c, 0x32, + 0xd2, 0x23, 0x24, 0x6b, 0xae, 0x8f, 0x53, 0xa1, 0xa8, 0x2d, 0x5e, 0x89, 0xd6, 0x8a, 0xe0, 0xdd, + 0xc3, 0x29, 0x97, 0x53, 0xf7, 0xd1, 0x35, 0xa9, 0x94, 0x03, 0x85, 0x42, 0x5b, 0xfa, 0xeb, 0xfa, + 0xf8, 0x6c, 0xf8, 0x0a, 0xab, 0x02, 0xe9, 0x30, 0xe0, 0x65, 0x3b, 0x7c, 0xa7, 0xa0, 0x1b, 0xfc, + 0x08, 0xc1, 0x01, 0x0d, 0x27, 0x5b, 0x7c, 0x84, 0x2a, 0x78, 0x74, 0x90, 0x9b, 0x5c, 0x9f, 0x13, + 0xdc, 0x4d, 0xfb, 0x76, 0xed, 0xeb, 0x2c, 0xa7, 0x33, 0x41, 0xaa, 0xb7, 0xd1, 0x1a, 0x16, 0xec, + 0x6e, 0x02, 0x94, 0xe2, 0x10, 0xa8, 0xb6, 0xd0, 0x28, 0xb7, 0x2a, 0xce, 0xaa, 0xac, 0x1f, 0xc8, + 0x72, 0xe7, 0xe6, 0x9b, 0xf7, 0x46, 0x69, 0xde, 0xe0, 0x27, 0x05, 0x2d, 0xed, 0xb3, 0xa7, 0xa3, + 0xde, 0x43, 0xff, 0xf1, 0x37, 0x04, 0x39, 0x37, 0x54, 0xb1, 0xeb, 0x3f, 0xcf, 0x8d, 0x8d, 0x3e, + 0x4e, 0xe2, 0x4e, 0x53, 0x5e, 0xb8, 0x38, 0x08, 0x72, 0xa0, 0xb4, 0xe9, 0x8c, 0x5a, 0x27, 0x28, + 0xe0, 0x4f, 0xea, 0x12, 0x14, 0xcc, 0xa1, 0x66, 0xe2, 0x97, 0xff, 0x35, 0xbe, 0x7d, 0xff, 0x74, + 0xa0, 0x2b, 0x67, 0x03, 0x5d, 0xf9, 0x31, 0xd0, 0x95, 0x93, 0xa1, 0x5e, 0x3a, 0x1b, 0xea, 0xa5, + 0xef, 0x43, 0xbd, 0xf4, 0xb2, 0xf9, 0xa7, 0x87, 0x70, 0x3c, 0xfe, 0xc9, 0x79, 0xcb, 0x5c, 0xe9, + 0xee, 0xaf, 0x00, 0x00, 0x00, 0xff, 0xff, 0x1d, 0xca, 0xf4, 0x74, 0x07, 0x05, 0x00, 0x00, } func (m *BasicAllowance) Marshal() (dAtA []byte, err error) { diff --git a/x/feegrant/types/fees.go b/x/feegrant/fees.go similarity index 98% rename from x/feegrant/types/fees.go rename to x/feegrant/fees.go index fbd4739fe9..aa84e4c85a 100644 --- a/x/feegrant/types/fees.go +++ b/x/feegrant/fees.go @@ -1,4 +1,4 @@ -package types +package feegrant import ( sdk "github.com/line/lbm-sdk/types" diff --git a/x/feegrant/types/filtered_fee.go b/x/feegrant/filtered_fee.go similarity index 81% rename from x/feegrant/types/filtered_fee.go rename to x/feegrant/filtered_fee.go index a0f2d98090..290e111914 100644 --- a/x/feegrant/types/filtered_fee.go +++ b/x/feegrant/filtered_fee.go @@ -1,4 +1,4 @@ -package types +package feegrant import ( "github.com/gogo/protobuf/proto" @@ -9,7 +9,7 @@ import ( ) // TODO: Revisit this once we have propoer gas fee framework. -// Tracking issues https://github.com/line/lbm-sdk/issues/9054, https://github.com/line/lbm-sdk/discussions/9072 +// Tracking issues https://github.com/cosmos/cosmos-sdk/issues/9054, https://github.com/line/lbm-sdk/discussions/9072 const ( gasCostPerIteration = uint64(10) ) @@ -50,6 +50,17 @@ func (a *AllowedMsgAllowance) GetAllowance() (FeeAllowanceI, error) { return allowance, nil } +// SetAllowance sets allowed fee allowance. +func (a *AllowedMsgAllowance) SetAllowance(allowance FeeAllowanceI) error { + var err error + a.Allowance, err = types.NewAnyWithValue(allowance.(proto.Message)) + if err != nil { + return sdkerrors.Wrapf(sdkerrors.ErrPackAny, "cannot proto marshal %T", allowance) + } + + return nil +} + // Accept method checks for the filtered messages has valid expiry func (a *AllowedMsgAllowance) Accept(ctx sdk.Context, fee sdk.Coins, msgs []sdk.Msg) (bool, error) { if !a.allMsgTypesAllowed(ctx, msgs) { @@ -61,14 +72,13 @@ func (a *AllowedMsgAllowance) Accept(ctx sdk.Context, fee sdk.Coins, msgs []sdk. return false, err } - remove, reserr := allowance.Accept(ctx, fee, msgs) - if !remove { - a.Allowance, err = types.NewAnyWithValue(allowance.(proto.Message)) - if err != nil { - return false, sdkerrors.Wrapf(sdkerrors.ErrPackAny, "cannot proto marshal %T", allowance) + remove, err := allowance.Accept(ctx, fee, msgs) + if err == nil && !remove { + if err = a.SetAllowance(allowance); err != nil { + return false, err } } - return remove, reserr + return remove, err } func (a *AllowedMsgAllowance) allowedMsgsToMap(ctx sdk.Context) map[string]bool { diff --git a/x/feegrant/filtered_fee_test.go b/x/feegrant/filtered_fee_test.go new file mode 100644 index 0000000000..b9c15318fd --- /dev/null +++ b/x/feegrant/filtered_fee_test.go @@ -0,0 +1,188 @@ +package feegrant_test + +import ( + "testing" + "time" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + ocproto "github.com/line/ostracon/proto/ostracon/types" + + "github.com/line/lbm-sdk/simapp" + sdk "github.com/line/lbm-sdk/types" + banktypes "github.com/line/lbm-sdk/x/bank/types" + "github.com/line/lbm-sdk/x/feegrant" +) + +func TestFilteredFeeValidAllow(t *testing.T) { + app := simapp.Setup(false) + + ctx := app.BaseApp.NewContext(false, ocproto.Header{ + Time: time.Now(), + }) + eth := sdk.NewCoins(sdk.NewInt64Coin("eth", 10)) + atom := sdk.NewCoins(sdk.NewInt64Coin("atom", 555)) + smallAtom := sdk.NewCoins(sdk.NewInt64Coin("atom", 43)) + bigAtom := sdk.NewCoins(sdk.NewInt64Coin("atom", 1000)) + leftAtom := sdk.NewCoins(sdk.NewInt64Coin("atom", 512)) + now := ctx.BlockTime() + oneHour := now.Add(1 * time.Hour) + + // msg we will call in the all cases + call := banktypes.MsgSend{} + cases := map[string]struct { + allowance *feegrant.BasicAllowance + msgs []string + fee sdk.Coins + blockTime time.Time + accept bool + remove bool + remains sdk.Coins + }{ + "msg contained": { + allowance: &feegrant.BasicAllowance{}, + msgs: []string{sdk.MsgTypeURL(&call)}, + accept: true, + }, + "msg not contained": { + allowance: &feegrant.BasicAllowance{}, + msgs: []string{"/lbm.gov.v1.MsgVote"}, + accept: false, + }, + "small fee without expire": { + allowance: &feegrant.BasicAllowance{ + SpendLimit: atom, + }, + msgs: []string{sdk.MsgTypeURL(&call)}, + fee: smallAtom, + accept: true, + remove: false, + remains: leftAtom, + }, + "all fee without expire": { + allowance: &feegrant.BasicAllowance{ + SpendLimit: smallAtom, + }, + msgs: []string{sdk.MsgTypeURL(&call)}, + fee: smallAtom, + accept: true, + remove: true, + }, + "wrong fee": { + allowance: &feegrant.BasicAllowance{ + SpendLimit: smallAtom, + }, + msgs: []string{sdk.MsgTypeURL(&call)}, + fee: eth, + accept: false, + }, + "non-expired": { + allowance: &feegrant.BasicAllowance{ + SpendLimit: atom, + Expiration: &oneHour, + }, + msgs: []string{sdk.MsgTypeURL(&call)}, + fee: smallAtom, + blockTime: now, + accept: true, + remove: false, + remains: leftAtom, + }, + "expired": { + allowance: &feegrant.BasicAllowance{ + SpendLimit: atom, + Expiration: &now, + }, + msgs: []string{sdk.MsgTypeURL(&call)}, + fee: smallAtom, + blockTime: oneHour, + accept: false, + remove: true, + }, + "fee more than allowed": { + allowance: &feegrant.BasicAllowance{ + SpendLimit: atom, + Expiration: &oneHour, + }, + msgs: []string{sdk.MsgTypeURL(&call)}, + fee: bigAtom, + blockTime: now, + accept: false, + }, + "with out spend limit": { + allowance: &feegrant.BasicAllowance{ + Expiration: &oneHour, + }, + msgs: []string{sdk.MsgTypeURL(&call)}, + fee: bigAtom, + blockTime: now, + accept: true, + }, + "expired no spend limit": { + allowance: &feegrant.BasicAllowance{ + Expiration: &now, + }, + msgs: []string{sdk.MsgTypeURL(&call)}, + fee: bigAtom, + blockTime: oneHour, + accept: false, + }, + } + + for name, stc := range cases { + tc := stc // to make scopelint happy + t.Run(name, func(t *testing.T) { + err := tc.allowance.ValidateBasic() + require.NoError(t, err) + + ctx := app.BaseApp.NewContext(false, ocproto.Header{}).WithBlockTime(tc.blockTime) + + // create grant + var granter, grantee sdk.AccAddress + allowance, err := feegrant.NewAllowedMsgAllowance(tc.allowance, tc.msgs) + require.NoError(t, err) + grant, err := feegrant.NewGrant(granter, grantee, allowance) + require.NoError(t, err) + + // now try to deduct + removed, err := allowance.Accept(ctx, tc.fee, []sdk.Msg{&call}) + if !tc.accept { + require.Error(t, err) + return + } + require.NoError(t, err) + + require.Equal(t, tc.remove, removed) + if !removed { + // mimic save & load process (#10564) + // the cached allowance was correct even before the fix, + // however, the saved value was not. + // so we need this to catch the bug. + + // create a new updated grant + newGrant, err := feegrant.NewGrant( + sdk.AccAddress(grant.Granter), + sdk.AccAddress(grant.Grantee), + allowance) + require.NoError(t, err) + + // save the grant + cdc := simapp.MakeTestEncodingConfig().Marshaler + bz, err := cdc.Marshal(&newGrant) + require.NoError(t, err) + + // load the grant + var loadedGrant feegrant.Grant + err = cdc.Unmarshal(bz, &loadedGrant) + require.NoError(t, err) + + newAllowance, err := loadedGrant.GetGrant() + require.NoError(t, err) + feeAllowance, err := newAllowance.(*feegrant.AllowedMsgAllowance).GetAllowance() + require.NoError(t, err) + assert.Equal(t, tc.remains, feeAllowance.(*feegrant.BasicAllowance).SpendLimit) + } + }) + } +} diff --git a/x/feegrant/types/genesis.go b/x/feegrant/genesis.go similarity index 91% rename from x/feegrant/types/genesis.go rename to x/feegrant/genesis.go index 559effeb68..247ae2f888 100644 --- a/x/feegrant/types/genesis.go +++ b/x/feegrant/genesis.go @@ -1,4 +1,4 @@ -package types +package feegrant import ( "github.com/line/lbm-sdk/codec/types" @@ -16,11 +16,11 @@ func NewGenesisState(entries []Grant) *GenesisState { // ValidateGenesis ensures all grants in the genesis state are valid func ValidateGenesis(data GenesisState) error { for _, f := range data.Allowances { - allowance, err := f.GetGrant() + grant, err := f.GetGrant() if err != nil { return err } - err = allowance.ValidateBasic() + err = grant.ValidateBasic() if err != nil { return err } diff --git a/x/feegrant/types/genesis.pb.go b/x/feegrant/genesis.pb.go similarity index 96% rename from x/feegrant/types/genesis.pb.go rename to x/feegrant/genesis.pb.go index e990b78693..c3d93ce22c 100644 --- a/x/feegrant/types/genesis.pb.go +++ b/x/feegrant/genesis.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-gogo. DO NOT EDIT. // source: lbm/feegrant/v1/genesis.proto -package types +package feegrant import ( fmt "fmt" @@ -75,7 +75,7 @@ func init() { func init() { proto.RegisterFile("lbm/feegrant/v1/genesis.proto", fileDescriptor_5d0f05d61b086d9c) } var fileDescriptor_5d0f05d61b086d9c = []byte{ - // 204 bytes of a gzipped FileDescriptorProto + // 199 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0xcd, 0x49, 0xca, 0xd5, 0x4f, 0x4b, 0x4d, 0x4d, 0x2f, 0x4a, 0xcc, 0x2b, 0xd1, 0x2f, 0x33, 0xd4, 0x4f, 0x4f, 0xcd, 0x4b, 0x2d, 0xce, 0x2c, 0xd6, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0xe2, 0xcf, 0x49, 0xca, 0xd5, 0x83, @@ -83,12 +83,12 @@ var fileDescriptor_5d0f05d61b086d9c = []byte{ 0x32, 0x29, 0x39, 0x74, 0x53, 0xe0, 0x5a, 0xc0, 0xf2, 0x4a, 0x3e, 0x5c, 0x3c, 0xee, 0x10, 0x73, 0x83, 0x4b, 0x12, 0x4b, 0x52, 0x85, 0x6c, 0xb8, 0xb8, 0x12, 0x73, 0x72, 0xf2, 0xcb, 0x13, 0xf3, 0x92, 0x53, 0x8b, 0x25, 0x18, 0x15, 0x98, 0x35, 0xb8, 0x8d, 0xc4, 0xf4, 0xd0, 0xec, 0xd2, 0x73, - 0x07, 0x31, 0x9c, 0x58, 0x4e, 0xdc, 0x93, 0x67, 0x08, 0x42, 0x52, 0xef, 0xe4, 0x74, 0xe2, 0x91, + 0x07, 0x31, 0x9c, 0x58, 0x4e, 0xdc, 0x93, 0x67, 0x08, 0x42, 0x52, 0xef, 0x64, 0x73, 0xe2, 0x91, 0x1c, 0xe3, 0x85, 0x47, 0x72, 0x8c, 0x0f, 0x1e, 0xc9, 0x31, 0x4e, 0x78, 0x2c, 0xc7, 0x70, 0xe1, - 0xb1, 0x1c, 0xc3, 0x8d, 0xc7, 0x72, 0x0c, 0x51, 0x1a, 0xe9, 0x99, 0x25, 0x19, 0xa5, 0x49, 0x7a, + 0xb1, 0x1c, 0xc3, 0x8d, 0xc7, 0x72, 0x0c, 0x51, 0x4a, 0xe9, 0x99, 0x25, 0x19, 0xa5, 0x49, 0x7a, 0xc9, 0xf9, 0xb9, 0xfa, 0x39, 0x99, 0x79, 0xa9, 0xfa, 0x39, 0x49, 0xb9, 0xba, 0xc5, 0x29, 0xd9, - 0xfa, 0x15, 0x08, 0xd7, 0x95, 0x54, 0x16, 0xa4, 0x16, 0x27, 0xb1, 0x81, 0x1d, 0x66, 0x0c, 0x08, - 0x00, 0x00, 0xff, 0xff, 0x52, 0x20, 0x03, 0x5b, 0x00, 0x01, 0x00, 0x00, + 0xfa, 0x15, 0x70, 0x17, 0x25, 0xb1, 0x81, 0x9d, 0x64, 0x0c, 0x08, 0x00, 0x00, 0xff, 0xff, 0xe3, + 0x05, 0xed, 0x2c, 0xfa, 0x00, 0x00, 0x00, } func (m *GenesisState) Marshal() (dAtA []byte, err error) { diff --git a/x/feegrant/types/grant.go b/x/feegrant/grant.go similarity index 99% rename from x/feegrant/types/grant.go rename to x/feegrant/grant.go index 12e733358b..8c84df01c6 100644 --- a/x/feegrant/types/grant.go +++ b/x/feegrant/grant.go @@ -1,4 +1,4 @@ -package types +package feegrant import ( "github.com/gogo/protobuf/proto" diff --git a/x/feegrant/grant_test.go b/x/feegrant/grant_test.go new file mode 100644 index 0000000000..d28130a4d4 --- /dev/null +++ b/x/feegrant/grant_test.go @@ -0,0 +1,103 @@ +package feegrant_test + +import ( + "testing" + "time" + + "github.com/stretchr/testify/require" + + ocproto "github.com/line/ostracon/proto/ostracon/types" + + "github.com/line/lbm-sdk/simapp" + sdk "github.com/line/lbm-sdk/types" + "github.com/line/lbm-sdk/x/feegrant" +) + +func TestGrant(t *testing.T) { + app := simapp.Setup(false) + addr := sdk.AccAddress("link1qyqszqgpqyqszqgpqyqszqgpqyqszqgp8apuk5") + addr2 := sdk.AccAddress("link1ghekyjucln7y67ntx7cf27m9dpuxxemnqk82wt") + atom := sdk.NewCoins(sdk.NewInt64Coin("atom", 555)) + ctx := app.BaseApp.NewContext(false, ocproto.Header{ + Time: time.Now(), + }) + now := ctx.BlockTime() + oneYear := now.AddDate(1, 0, 0) + + zeroAtoms := sdk.NewCoins(sdk.NewInt64Coin("atom", 0)) + cdc := app.AppCodec() + + cases := map[string]struct { + granter sdk.AccAddress + grantee sdk.AccAddress + limit sdk.Coins + expires time.Time + valid bool + }{ + "good": { + granter: addr2, + grantee: addr, + limit: atom, + expires: oneYear, + valid: true, + }, + "no grantee": { + granter: addr2, + grantee: "", + limit: atom, + expires: oneYear, + valid: false, + }, + "no granter": { + granter: "", + grantee: addr, + limit: atom, + expires: oneYear, + valid: false, + }, + "self-grant": { + granter: addr2, + grantee: addr2, + limit: atom, + expires: oneYear, + valid: false, + }, + "zero allowance": { + granter: addr2, + grantee: addr, + limit: zeroAtoms, + expires: oneYear, + valid: false, + }, + } + + for name, tc := range cases { + tc := tc + t.Run(name, func(t *testing.T) { + grant, err := feegrant.NewGrant(tc.granter, tc.grantee, &feegrant.BasicAllowance{ + SpendLimit: tc.limit, + Expiration: &tc.expires, + }) + require.NoError(t, err) + err = grant.ValidateBasic() + + if !tc.valid { + require.Error(t, err) + return + } + require.NoError(t, err) + + // if it is valid, let's try to serialize, deserialize, and make sure it matches + bz, err := cdc.Marshal(&grant) + require.NoError(t, err) + var loaded feegrant.Grant + err = cdc.Unmarshal(bz, &loaded) + require.NoError(t, err) + + err = loaded.ValidateBasic() + require.NoError(t, err) + + require.Equal(t, grant, loaded) + }) + } +} diff --git a/x/feegrant/handler.go b/x/feegrant/handler.go deleted file mode 100644 index efa9de035e..0000000000 --- a/x/feegrant/handler.go +++ /dev/null @@ -1,30 +0,0 @@ -package feegrant - -import ( - sdk "github.com/line/lbm-sdk/types" - "github.com/line/lbm-sdk/types/errors" - "github.com/line/lbm-sdk/x/feegrant/keeper" - "github.com/line/lbm-sdk/x/feegrant/types" -) - -// NewHandler creates an sdk.Handler for all the gov type messages -func NewHandler(k keeper.Keeper) sdk.Handler { - msgServer := keeper.NewMsgServerImpl(k) - - return func(ctx sdk.Context, msg sdk.Msg) (*sdk.Result, error) { - ctx = ctx.WithEventManager(sdk.NewEventManager()) - - switch msg := msg.(type) { - case *types.MsgGrantAllowance: - res, err := msgServer.GrantAllowance(sdk.WrapSDKContext(ctx), msg) - return sdk.WrapServiceResult(ctx, res, err) - - case *types.MsgRevokeAllowance: - res, err := msgServer.RevokeAllowance(sdk.WrapSDKContext(ctx), msg) - return sdk.WrapServiceResult(ctx, res, err) - - default: - return nil, errors.Wrapf(errors.ErrUnknownRequest, "unrecognized %s message type: %T", types.ModuleName, msg) - } - } -} diff --git a/x/feegrant/keeper/genesis_test.go b/x/feegrant/keeper/genesis_test.go index 84e135e42f..df17ca1c65 100644 --- a/x/feegrant/keeper/genesis_test.go +++ b/x/feegrant/keeper/genesis_test.go @@ -3,16 +3,16 @@ package keeper_test import ( "testing" - tmproto "github.com/line/ostracon/proto/ostracon/types" "github.com/stretchr/testify/suite" - "github.com/line/lbm-sdk/x/feegrant/types" + ocproto "github.com/line/ostracon/proto/ostracon/types" codectypes "github.com/line/lbm-sdk/codec/types" "github.com/line/lbm-sdk/crypto/keys/secp256k1" "github.com/line/lbm-sdk/simapp" "github.com/line/lbm-sdk/testutil/testdata" sdk "github.com/line/lbm-sdk/types" + "github.com/line/lbm-sdk/x/feegrant" "github.com/line/lbm-sdk/x/feegrant/keeper" ) @@ -25,7 +25,7 @@ type GenesisTestSuite struct { func (suite *GenesisTestSuite) SetupTest() { checkTx := false app := simapp.Setup(checkTx) - suite.ctx = app.BaseApp.NewContext(checkTx, tmproto.Header{Height: 1}) + suite.ctx = app.BaseApp.NewContext(checkTx, ocproto.Header{Height: 1}) suite.keeper = app.FeeGrantKeeper } @@ -42,14 +42,14 @@ func (suite *GenesisTestSuite) TestImportExportGenesis() { oneYear := now.AddDate(1, 0, 0) msgSrvr := keeper.NewMsgServerImpl(suite.keeper) - allowance := &types.BasicAllowance{SpendLimit: coins, Expiration: &oneYear} + allowance := &feegrant.BasicAllowance{SpendLimit: coins, Expiration: &oneYear} err := suite.keeper.GrantAllowance(suite.ctx, granterAddr, granteeAddr, allowance) suite.Require().NoError(err) genesis, err := suite.keeper.ExportGenesis(suite.ctx) suite.Require().NoError(err) // revoke fee allowance - _, err = msgSrvr.RevokeAllowance(sdk.WrapSDKContext(suite.ctx), &types.MsgRevokeAllowance{ + _, err = msgSrvr.RevokeAllowance(sdk.WrapSDKContext(suite.ctx), &feegrant.MsgRevokeAllowance{ Granter: granterAddr.String(), Grantee: granteeAddr.String(), }) @@ -68,11 +68,11 @@ func (suite *GenesisTestSuite) TestInitGenesis() { testCases := []struct { name string - feeAllowances []types.Grant + feeAllowances []feegrant.Grant }{ { "invalid granter", - []types.Grant{ + []feegrant.Grant{ { Granter: "invalid granter", Grantee: granteeAddr.String(), @@ -81,7 +81,7 @@ func (suite *GenesisTestSuite) TestInitGenesis() { }, { "invalid grantee", - []types.Grant{ + []feegrant.Grant{ { Granter: granterAddr.String(), Grantee: "invalid grantee", @@ -90,7 +90,7 @@ func (suite *GenesisTestSuite) TestInitGenesis() { }, { "invalid allowance", - []types.Grant{ + []feegrant.Grant{ { Granter: granterAddr.String(), Grantee: granteeAddr.String(), @@ -103,7 +103,7 @@ func (suite *GenesisTestSuite) TestInitGenesis() { for _, tc := range testCases { tc := tc suite.Run(tc.name, func() { - err := suite.keeper.InitGenesis(suite.ctx, &types.GenesisState{Allowances: tc.feeAllowances}) + err := suite.keeper.InitGenesis(suite.ctx, &feegrant.GenesisState{Allowances: tc.feeAllowances}) suite.Require().Error(err) }) } diff --git a/x/feegrant/keeper/grpc_query.go b/x/feegrant/keeper/grpc_query.go index cdae1b7d54..e484e40598 100644 --- a/x/feegrant/keeper/grpc_query.go +++ b/x/feegrant/keeper/grpc_query.go @@ -7,18 +7,17 @@ import ( "google.golang.org/grpc/codes" "google.golang.org/grpc/status" - "github.com/line/lbm-sdk/x/feegrant/types" - codectypes "github.com/line/lbm-sdk/codec/types" "github.com/line/lbm-sdk/store/prefix" sdk "github.com/line/lbm-sdk/types" "github.com/line/lbm-sdk/types/query" + "github.com/line/lbm-sdk/x/feegrant" ) -var _ types.QueryServer = Keeper{} +var _ feegrant.QueryServer = Keeper{} // Allowance returns fee granted to the grantee by the granter. -func (q Keeper) Allowance(c context.Context, req *types.QueryAllowanceRequest) (*types.QueryAllowanceResponse, error) { +func (q Keeper) Allowance(c context.Context, req *feegrant.QueryAllowanceRequest) (*feegrant.QueryAllowanceResponse, error) { if req == nil { return nil, status.Error(codes.InvalidArgument, "invalid request") } @@ -43,8 +42,8 @@ func (q Keeper) Allowance(c context.Context, req *types.QueryAllowanceRequest) ( return nil, status.Errorf(codes.Internal, err.Error()) } - return &types.QueryAllowanceResponse{ - Allowance: &types.Grant{ + return &feegrant.QueryAllowanceResponse{ + Allowance: &feegrant.Grant{ Granter: granterAddr.String(), Grantee: granteeAddr.String(), Allowance: feeAllowanceAny, @@ -53,7 +52,7 @@ func (q Keeper) Allowance(c context.Context, req *types.QueryAllowanceRequest) ( } // Allowances queries all the allowances granted to the given grantee. -func (q Keeper) Allowances(c context.Context, req *types.QueryAllowancesRequest) (*types.QueryAllowancesResponse, error) { +func (q Keeper) Allowances(c context.Context, req *feegrant.QueryAllowancesRequest) (*feegrant.QueryAllowancesResponse, error) { if req == nil { return nil, status.Error(codes.InvalidArgument, "invalid request") } @@ -66,15 +65,15 @@ func (q Keeper) Allowances(c context.Context, req *types.QueryAllowancesRequest) ctx := sdk.UnwrapSDKContext(c) - var grants []*types.Grant + var grants []*feegrant.Grant store := ctx.KVStore(q.storeKey) - grantsStore := prefix.NewStore(store, types.FeeAllowancePrefixByGrantee(granteeAddr)) + grantsStore := prefix.NewStore(store, feegrant.FeeAllowancePrefixByGrantee(granteeAddr)) pageRes, err := query.Paginate(grantsStore, req.Pagination, func(key []byte, value []byte) error { - var grant types.Grant + var grant feegrant.Grant - if err := q.cdc.UnmarshalBinaryBare(value, &grant); err != nil { + if err := q.cdc.Unmarshal(value, &grant); err != nil { return err } @@ -86,5 +85,5 @@ func (q Keeper) Allowances(c context.Context, req *types.QueryAllowancesRequest) return nil, status.Error(codes.Internal, err.Error()) } - return &types.QueryAllowancesResponse{Allowances: grants, Pagination: pageRes}, nil + return &feegrant.QueryAllowancesResponse{Allowances: grants, Pagination: pageRes}, nil } diff --git a/x/feegrant/keeper/grpc_query_test.go b/x/feegrant/keeper/grpc_query_test.go index c54b15064a..86bb144672 100644 --- a/x/feegrant/keeper/grpc_query_test.go +++ b/x/feegrant/keeper/grpc_query_test.go @@ -2,58 +2,58 @@ package keeper_test import ( sdk "github.com/line/lbm-sdk/types" - "github.com/line/lbm-sdk/x/feegrant/types" + "github.com/line/lbm-sdk/x/feegrant" ) func (suite *KeeperTestSuite) TestFeeAllowance() { testCases := []struct { name string - req *types.QueryAllowanceRequest + req *feegrant.QueryAllowanceRequest expectErr bool preRun func() - postRun func(_ *types.QueryAllowanceResponse) + postRun func(_ *feegrant.QueryAllowanceResponse) }{ { "nil request", nil, true, func() {}, - func(*types.QueryAllowanceResponse) {}, + func(*feegrant.QueryAllowanceResponse) {}, }, { "fail: invalid granter", - &types.QueryAllowanceRequest{ + &feegrant.QueryAllowanceRequest{ Granter: "invalid_granter", Grantee: suite.addrs[0].String(), }, true, func() {}, - func(*types.QueryAllowanceResponse) {}, + func(*feegrant.QueryAllowanceResponse) {}, }, { "fail: invalid grantee", - &types.QueryAllowanceRequest{ + &feegrant.QueryAllowanceRequest{ Granter: suite.addrs[0].String(), Grantee: "invalid_grantee", }, true, func() {}, - func(*types.QueryAllowanceResponse) {}, + func(*feegrant.QueryAllowanceResponse) {}, }, { "fail: no grants", - &types.QueryAllowanceRequest{ + &feegrant.QueryAllowanceRequest{ Granter: suite.addrs[0].String(), Grantee: suite.addrs[1].String(), }, true, func() {}, - func(*types.QueryAllowanceResponse) {}, + func(*feegrant.QueryAllowanceResponse) {}, }, { "valid query: expect single grant", - &types.QueryAllowanceRequest{ + &feegrant.QueryAllowanceRequest{ Granter: suite.addrs[0].String(), Grantee: suite.addrs[1].String(), }, @@ -61,7 +61,7 @@ func (suite *KeeperTestSuite) TestFeeAllowance() { func() { grantFeeAllowance(suite) }, - func(response *types.QueryAllowanceResponse) { + func(response *feegrant.QueryAllowanceResponse) { suite.Require().Equal(response.Allowance.Granter, suite.addrs[0].String()) suite.Require().Equal(response.Allowance.Grantee, suite.addrs[1].String()) }, @@ -85,48 +85,48 @@ func (suite *KeeperTestSuite) TestFeeAllowance() { func (suite *KeeperTestSuite) TestFeeAllowances() { testCases := []struct { name string - req *types.QueryAllowancesRequest + req *feegrant.QueryAllowancesRequest expectErr bool preRun func() - postRun func(_ *types.QueryAllowancesResponse) + postRun func(_ *feegrant.QueryAllowancesResponse) }{ { "nil request", nil, true, func() {}, - func(*types.QueryAllowancesResponse) {}, + func(*feegrant.QueryAllowancesResponse) {}, }, { "fail: invalid grantee", - &types.QueryAllowancesRequest{ + &feegrant.QueryAllowancesRequest{ Grantee: "invalid_grantee", }, true, func() {}, - func(*types.QueryAllowancesResponse) {}, + func(*feegrant.QueryAllowancesResponse) {}, }, { "no grants", - &types.QueryAllowancesRequest{ + &feegrant.QueryAllowancesRequest{ Grantee: suite.addrs[1].String(), }, false, func() {}, - func(resp *types.QueryAllowancesResponse) { + func(resp *feegrant.QueryAllowancesResponse) { suite.Require().Equal(len(resp.Allowances), 0) }, }, { "valid query: expect single grant", - &types.QueryAllowancesRequest{ + &feegrant.QueryAllowancesRequest{ Grantee: suite.addrs[1].String(), }, false, func() { grantFeeAllowance(suite) }, - func(resp *types.QueryAllowancesResponse) { + func(resp *feegrant.QueryAllowancesResponse) { suite.Require().Equal(len(resp.Allowances), 1) suite.Require().Equal(resp.Allowances[0].Granter, suite.addrs[0].String()) suite.Require().Equal(resp.Allowances[0].Grantee, suite.addrs[1].String()) @@ -150,7 +150,7 @@ func (suite *KeeperTestSuite) TestFeeAllowances() { func grantFeeAllowance(suite *KeeperTestSuite) { exp := suite.sdkCtx.BlockTime().AddDate(1, 0, 0) - err := suite.app.FeeGrantKeeper.GrantAllowance(suite.sdkCtx, suite.addrs[0], suite.addrs[1], &types.BasicAllowance{ + err := suite.app.FeeGrantKeeper.GrantAllowance(suite.sdkCtx, suite.addrs[0], suite.addrs[1], &feegrant.BasicAllowance{ SpendLimit: sdk.NewCoins(sdk.NewInt64Coin("atom", 555)), Expiration: &exp, }) diff --git a/x/feegrant/keeper/keeper.go b/x/feegrant/keeper/keeper.go index 8a3510095c..c553371604 100644 --- a/x/feegrant/keeper/keeper.go +++ b/x/feegrant/keeper/keeper.go @@ -5,24 +5,25 @@ import ( "github.com/line/ostracon/libs/log" - storetypes "github.com/line/lbm-sdk/store/types" - "github.com/line/lbm-sdk/x/feegrant/types" - "github.com/line/lbm-sdk/codec" sdk "github.com/line/lbm-sdk/types" sdkerrors "github.com/line/lbm-sdk/types/errors" + "github.com/line/lbm-sdk/x/auth/ante" + "github.com/line/lbm-sdk/x/feegrant" ) // Keeper manages state of all fee grants, as well as calculating approval. // It must have a codec with all available allowances registered. type Keeper struct { - cdc codec.Marshaler - storeKey storetypes.StoreKey - authKeeper types.AccountKeeper + cdc codec.BinaryCodec + storeKey sdk.StoreKey + authKeeper feegrant.AccountKeeper } +var _ ante.FeegrantKeeper = &Keeper{} + // NewKeeper creates a fee grant Keeper -func NewKeeper(cdc codec.Marshaler, storeKey storetypes.StoreKey, ak types.AccountKeeper) Keeper { +func NewKeeper(cdc codec.BinaryCodec, storeKey sdk.StoreKey, ak feegrant.AccountKeeper) Keeper { return Keeper{ cdc: cdc, storeKey: storeKey, @@ -32,11 +33,11 @@ func NewKeeper(cdc codec.Marshaler, storeKey storetypes.StoreKey, ak types.Accou // Logger returns a module-specific logger. func (k Keeper) Logger(ctx sdk.Context) log.Logger { - return ctx.Logger().With("module", fmt.Sprintf("x/%s", types.ModuleName)) + return ctx.Logger().With("module", fmt.Sprintf("x/%s", feegrant.ModuleName)) } // GrantAllowance creates a new grant -func (k Keeper) GrantAllowance(ctx sdk.Context, granter, grantee sdk.AccAddress, feeAllowance types.FeeAllowanceI) error { +func (k Keeper) GrantAllowance(ctx sdk.Context, granter, grantee sdk.AccAddress, feeAllowance feegrant.FeeAllowanceI) error { // create the account if it is not in account state granteeAcc := k.authKeeper.GetAccount(ctx, grantee) @@ -46,13 +47,13 @@ func (k Keeper) GrantAllowance(ctx sdk.Context, granter, grantee sdk.AccAddress, } store := ctx.KVStore(k.storeKey) - key := types.FeeAllowanceKey(granter, grantee) - grant, err := types.NewGrant(granter, grantee, feeAllowance) + key := feegrant.FeeAllowanceKey(granter, grantee) + grant, err := feegrant.NewGrant(granter, grantee, feeAllowance) if err != nil { return err } - bz, err := k.cdc.MarshalBinaryBare(&grant) + bz, err := k.cdc.Marshal(&grant) if err != nil { return err } @@ -61,9 +62,9 @@ func (k Keeper) GrantAllowance(ctx sdk.Context, granter, grantee sdk.AccAddress, ctx.EventManager().EmitEvent( sdk.NewEvent( - types.EventTypeSetFeeGrant, - sdk.NewAttribute(types.AttributeKeyGranter, grant.Granter), - sdk.NewAttribute(types.AttributeKeyGrantee, grant.Grantee), + feegrant.EventTypeSetFeeGrant, + sdk.NewAttribute(feegrant.AttributeKeyGranter, grant.Granter), + sdk.NewAttribute(feegrant.AttributeKeyGrantee, grant.Grantee), ), ) @@ -78,14 +79,14 @@ func (k Keeper) revokeAllowance(ctx sdk.Context, granter, grantee sdk.AccAddress } store := ctx.KVStore(k.storeKey) - key := types.FeeAllowanceKey(granter, grantee) + key := feegrant.FeeAllowanceKey(granter, grantee) store.Delete(key) ctx.EventManager().EmitEvent( sdk.NewEvent( - types.EventTypeRevokeFeeGrant, - sdk.NewAttribute(types.AttributeKeyGranter, granter.String()), - sdk.NewAttribute(types.AttributeKeyGrantee, grantee.String()), + feegrant.EventTypeRevokeFeeGrant, + sdk.NewAttribute(feegrant.AttributeKeyGranter, granter.String()), + sdk.NewAttribute(feegrant.AttributeKeyGrantee, grantee.String()), ), ) return nil @@ -94,7 +95,7 @@ func (k Keeper) revokeAllowance(ctx sdk.Context, granter, grantee sdk.AccAddress // GetAllowance returns the allowance between the granter and grantee. // If there is none, it returns nil, nil. // Returns an error on parsing issues -func (k Keeper) GetAllowance(ctx sdk.Context, granter, grantee sdk.AccAddress) (types.FeeAllowanceI, error) { +func (k Keeper) GetAllowance(ctx sdk.Context, granter, grantee sdk.AccAddress) (feegrant.FeeAllowanceI, error) { grant, err := k.getGrant(ctx, granter, grantee) if err != nil { return nil, err @@ -104,16 +105,16 @@ func (k Keeper) GetAllowance(ctx sdk.Context, granter, grantee sdk.AccAddress) ( } // getGrant returns entire grant between both accounts -func (k Keeper) getGrant(ctx sdk.Context, granter sdk.AccAddress, grantee sdk.AccAddress) (*types.Grant, error) { +func (k Keeper) getGrant(ctx sdk.Context, granter sdk.AccAddress, grantee sdk.AccAddress) (*feegrant.Grant, error) { store := ctx.KVStore(k.storeKey) - key := types.FeeAllowanceKey(granter, grantee) + key := feegrant.FeeAllowanceKey(granter, grantee) bz := store.Get(key) if len(bz) == 0 { return nil, sdkerrors.Wrap(sdkerrors.ErrUnauthorized, "fee-grant not found") } - var feegrant types.Grant - if err := k.cdc.UnmarshalBinaryBare(bz, &feegrant); err != nil { + var feegrant feegrant.Grant + if err := k.cdc.Unmarshal(bz, &feegrant); err != nil { return nil, err } @@ -123,16 +124,16 @@ func (k Keeper) getGrant(ctx sdk.Context, granter sdk.AccAddress, grantee sdk.Ac // IterateAllFeeAllowances iterates over all the grants in the store. // Callback to get all data, returns true to stop, false to keep reading // Calling this without pagination is very expensive and only designed for export genesis -func (k Keeper) IterateAllFeeAllowances(ctx sdk.Context, cb func(grant types.Grant) bool) error { +func (k Keeper) IterateAllFeeAllowances(ctx sdk.Context, cb func(grant feegrant.Grant) bool) error { store := ctx.KVStore(k.storeKey) - iter := sdk.KVStorePrefixIterator(store, types.FeeAllowanceKeyPrefix) + iter := sdk.KVStorePrefixIterator(store, feegrant.FeeAllowanceKeyPrefix) defer iter.Close() stop := false for ; iter.Valid() && !stop; iter.Next() { bz := iter.Value() - var feeGrant types.Grant - if err := k.cdc.UnmarshalBinaryBare(bz, &feeGrant); err != nil { + var feeGrant feegrant.Grant + if err := k.cdc.Unmarshal(bz, &feeGrant); err != nil { return err } @@ -181,15 +182,15 @@ func (k Keeper) UseGrantedFees(ctx sdk.Context, granter, grantee sdk.AccAddress, func emitUseGrantEvent(ctx sdk.Context, granter, grantee string) { ctx.EventManager().EmitEvent( sdk.NewEvent( - types.EventTypeUseFeeGrant, - sdk.NewAttribute(types.AttributeKeyGranter, granter), - sdk.NewAttribute(types.AttributeKeyGrantee, grantee), + feegrant.EventTypeUseFeeGrant, + sdk.NewAttribute(feegrant.AttributeKeyGranter, granter), + sdk.NewAttribute(feegrant.AttributeKeyGrantee, grantee), ), ) } // InitGenesis will initialize the keeper from a *previously validated* GenesisState -func (k Keeper) InitGenesis(ctx sdk.Context, data *types.GenesisState) error { +func (k Keeper) InitGenesis(ctx sdk.Context, data *feegrant.GenesisState) error { for _, f := range data.Allowances { err := sdk.ValidateAccAddress(f.Granter) if err != nil { @@ -216,15 +217,15 @@ func (k Keeper) InitGenesis(ctx sdk.Context, data *types.GenesisState) error { } // ExportGenesis will dump the contents of the keeper into a serializable GenesisState. -func (k Keeper) ExportGenesis(ctx sdk.Context) (*types.GenesisState, error) { - var grants []types.Grant +func (k Keeper) ExportGenesis(ctx sdk.Context) (*feegrant.GenesisState, error) { + var grants []feegrant.Grant - err := k.IterateAllFeeAllowances(ctx, func(grant types.Grant) bool { + err := k.IterateAllFeeAllowances(ctx, func(grant feegrant.Grant) bool { grants = append(grants, grant) return false }) - return &types.GenesisState{ + return &feegrant.GenesisState{ Allowances: grants, }, err } diff --git a/x/feegrant/keeper/keeper_test.go b/x/feegrant/keeper/keeper_test.go index 72a0f38be0..39da4f20ea 100644 --- a/x/feegrant/keeper/keeper_test.go +++ b/x/feegrant/keeper/keeper_test.go @@ -4,13 +4,13 @@ import ( "context" "testing" - tmproto "github.com/line/ostracon/proto/ostracon/types" "github.com/stretchr/testify/suite" - "github.com/line/lbm-sdk/x/feegrant/types" + ocproto "github.com/line/ostracon/proto/ostracon/types" "github.com/line/lbm-sdk/simapp" sdk "github.com/line/lbm-sdk/types" + "github.com/line/lbm-sdk/x/feegrant" "github.com/line/lbm-sdk/x/feegrant/keeper" ) @@ -20,7 +20,7 @@ type KeeperTestSuite struct { app *simapp.SimApp sdkCtx sdk.Context addrs []sdk.AccAddress - msgSrvr types.MsgServer + msgSrvr feegrant.MsgServer ctx context.Context atom sdk.Coins keeper keeper.Keeper @@ -32,7 +32,7 @@ func TestKeeperTestSuite(t *testing.T) { func (suite *KeeperTestSuite) SetupTest() { app := simapp.Setup(false) - ctx := app.BaseApp.NewContext(false, tmproto.Header{}) + ctx := app.BaseApp.NewContext(false, ocproto.Header{}) suite.app = app suite.sdkCtx = ctx @@ -47,12 +47,12 @@ func (suite *KeeperTestSuite) TestKeeperCrud() { // some helpers eth := sdk.NewCoins(sdk.NewInt64Coin("eth", 123)) exp := suite.sdkCtx.BlockTime().AddDate(1, 0, 0) - basic := &types.BasicAllowance{ + basic := &feegrant.BasicAllowance{ SpendLimit: suite.atom, Expiration: &exp, } - basic2 := &types.BasicAllowance{ + basic2 := &feegrant.BasicAllowance{ SpendLimit: eth, Expiration: &exp, } @@ -74,13 +74,13 @@ func (suite *KeeperTestSuite) TestKeeperCrud() { suite.Require().NoError(err) // remove some, overwrite other - _, err = suite.msgSrvr.RevokeAllowance(suite.ctx, &types.MsgRevokeAllowance{Granter: suite.addrs[0].String(), Grantee: suite.addrs[1].String()}) + _, err = suite.msgSrvr.RevokeAllowance(suite.ctx, &feegrant.MsgRevokeAllowance{Granter: suite.addrs[0].String(), Grantee: suite.addrs[1].String()}) suite.Require().NoError(err) - _, err = suite.msgSrvr.RevokeAllowance(suite.ctx, &types.MsgRevokeAllowance{Granter: suite.addrs[0].String(), Grantee: suite.addrs[2].String()}) + _, err = suite.msgSrvr.RevokeAllowance(suite.ctx, &feegrant.MsgRevokeAllowance{Granter: suite.addrs[0].String(), Grantee: suite.addrs[2].String()}) suite.Require().NoError(err) // revoke non-exist fee allowance - _, err = suite.msgSrvr.RevokeAllowance(suite.ctx, &types.MsgRevokeAllowance{Granter: suite.addrs[0].String(), Grantee: suite.addrs[2].String()}) + _, err = suite.msgSrvr.RevokeAllowance(suite.ctx, &feegrant.MsgRevokeAllowance{Granter: suite.addrs[0].String(), Grantee: suite.addrs[2].String()}) suite.Require().Error(err) err = suite.keeper.GrantAllowance(suite.sdkCtx, suite.addrs[0], suite.addrs[2], basic) @@ -98,7 +98,7 @@ func (suite *KeeperTestSuite) TestKeeperCrud() { cases := map[string]struct { grantee sdk.AccAddress granter sdk.AccAddress - allowance types.FeeAllowanceI + allowance feegrant.FeeAllowanceI }{ "addr revoked": { granter: suite.addrs[0], @@ -143,7 +143,7 @@ func (suite *KeeperTestSuite) TestKeeperCrud() { _, err = suite.keeper.GetAllowance(suite.sdkCtx, suite.addrs[3], accAddr) suite.Require().NoError(err) - _, err = suite.msgSrvr.RevokeAllowance(suite.ctx, &types.MsgRevokeAllowance{Granter: suite.addrs[3].String(), Grantee: accAddr.String()}) + _, err = suite.msgSrvr.RevokeAllowance(suite.ctx, &feegrant.MsgRevokeAllowance{Granter: suite.addrs[3].String(), Grantee: accAddr.String()}) suite.Require().NoError(err) } @@ -153,7 +153,7 @@ func (suite *KeeperTestSuite) TestUseGrantedFee() { blockTime := suite.sdkCtx.BlockTime() oneYear := blockTime.AddDate(1, 0, 0) - future := &types.BasicAllowance{ + future := &feegrant.BasicAllowance{ SpendLimit: suite.atom, Expiration: &oneYear, } @@ -161,7 +161,7 @@ func (suite *KeeperTestSuite) TestUseGrantedFee() { // for testing limits of the contract hugeAtom := sdk.NewCoins(sdk.NewInt64Coin("atom", 9999)) smallAtom := sdk.NewCoins(sdk.NewInt64Coin("atom", 1)) - futureAfterSmall := &types.BasicAllowance{ + futureAfterSmall := &feegrant.BasicAllowance{ SpendLimit: sdk.NewCoins(sdk.NewInt64Coin("atom", 554)), Expiration: &oneYear, } @@ -172,7 +172,7 @@ func (suite *KeeperTestSuite) TestUseGrantedFee() { granter sdk.AccAddress fee sdk.Coins allowed bool - final types.FeeAllowanceI + final feegrant.FeeAllowanceI }{ "use entire pot": { granter: suite.addrs[0], @@ -215,7 +215,7 @@ func (suite *KeeperTestSuite) TestUseGrantedFee() { }) } - expired := &types.BasicAllowance{ + expired := &feegrant.BasicAllowance{ SpendLimit: eth, Expiration: &blockTime, } @@ -240,12 +240,12 @@ func (suite *KeeperTestSuite) TestIterateGrants() { eth := sdk.NewCoins(sdk.NewInt64Coin("eth", 123)) exp := suite.sdkCtx.BlockTime().AddDate(1, 0, 0) - allowance := &types.BasicAllowance{ + allowance := &feegrant.BasicAllowance{ SpendLimit: suite.atom, Expiration: &exp, } - allowance1 := &types.BasicAllowance{ + allowance1 := &feegrant.BasicAllowance{ SpendLimit: eth, Expiration: &exp, } @@ -253,10 +253,9 @@ func (suite *KeeperTestSuite) TestIterateGrants() { suite.keeper.GrantAllowance(suite.sdkCtx, suite.addrs[0], suite.addrs[1], allowance) suite.keeper.GrantAllowance(suite.sdkCtx, suite.addrs[2], suite.addrs[1], allowance1) - suite.keeper.IterateAllFeeAllowances(suite.sdkCtx, func(grant types.Grant) bool { + suite.keeper.IterateAllFeeAllowances(suite.sdkCtx, func(grant feegrant.Grant) bool { suite.Require().Equal(suite.addrs[1].String(), grant.Grantee) suite.Require().Contains([]string{suite.addrs[0].String(), suite.addrs[2].String()}, grant.Granter) return true }) - } diff --git a/x/feegrant/keeper/msg_server.go b/x/feegrant/keeper/msg_server.go index f50efb6817..c280cf7786 100644 --- a/x/feegrant/keeper/msg_server.go +++ b/x/feegrant/keeper/msg_server.go @@ -4,9 +4,8 @@ import ( "context" sdk "github.com/line/lbm-sdk/types" - "github.com/line/lbm-sdk/x/feegrant/types" - sdkerrors "github.com/line/lbm-sdk/types/errors" + "github.com/line/lbm-sdk/x/feegrant" ) type msgServer struct { @@ -15,16 +14,16 @@ type msgServer struct { // NewMsgServerImpl returns an implementation of the feegrant MsgServer interface // for the provided Keeper. -func NewMsgServerImpl(k Keeper) types.MsgServer { +func NewMsgServerImpl(k Keeper) feegrant.MsgServer { return &msgServer{ Keeper: k, } } -var _ types.MsgServer = msgServer{} +var _ feegrant.MsgServer = msgServer{} // GrantAllowance grants an allowance from the granter's funds to be used by the grantee. -func (k msgServer) GrantAllowance(goCtx context.Context, msg *types.MsgGrantAllowance) (*types.MsgGrantAllowanceResponse, error) { +func (k msgServer) GrantAllowance(goCtx context.Context, msg *feegrant.MsgGrantAllowance) (*feegrant.MsgGrantAllowanceResponse, error) { ctx := sdk.UnwrapSDKContext(goCtx) err := sdk.ValidateAccAddress(msg.Grantee) @@ -54,11 +53,11 @@ func (k msgServer) GrantAllowance(goCtx context.Context, msg *types.MsgGrantAllo return nil, err } - return &types.MsgGrantAllowanceResponse{}, nil + return &feegrant.MsgGrantAllowanceResponse{}, nil } // RevokeAllowance revokes a fee allowance between a granter and grantee. -func (k msgServer) RevokeAllowance(goCtx context.Context, msg *types.MsgRevokeAllowance) (*types.MsgRevokeAllowanceResponse, error) { +func (k msgServer) RevokeAllowance(goCtx context.Context, msg *feegrant.MsgRevokeAllowance) (*feegrant.MsgRevokeAllowanceResponse, error) { ctx := sdk.UnwrapSDKContext(goCtx) err := sdk.ValidateAccAddress(msg.Grantee) @@ -78,5 +77,5 @@ func (k msgServer) RevokeAllowance(goCtx context.Context, msg *types.MsgRevokeAl return nil, err } - return &types.MsgRevokeAllowanceResponse{}, nil + return &feegrant.MsgRevokeAllowanceResponse{}, nil } diff --git a/x/feegrant/keeper/msg_server_test.go b/x/feegrant/keeper/msg_server_test.go index 2b4da9fa14..9f4a57b04d 100644 --- a/x/feegrant/keeper/msg_server_test.go +++ b/x/feegrant/keeper/msg_server_test.go @@ -2,7 +2,7 @@ package keeper_test import ( codectypes "github.com/line/lbm-sdk/codec/types" - "github.com/line/lbm-sdk/x/feegrant/types" + "github.com/line/lbm-sdk/x/feegrant" ) func (suite *KeeperTestSuite) TestGrantAllowance() { @@ -10,16 +10,16 @@ func (suite *KeeperTestSuite) TestGrantAllowance() { testCases := []struct { name string - req func() *types.MsgGrantAllowance + req func() *feegrant.MsgGrantAllowance expectErr bool errMsg string }{ { "invalid granter address", - func() *types.MsgGrantAllowance { - any, err := codectypes.NewAnyWithValue(&types.BasicAllowance{}) + func() *feegrant.MsgGrantAllowance { + any, err := codectypes.NewAnyWithValue(&feegrant.BasicAllowance{}) suite.Require().NoError(err) - return &types.MsgGrantAllowance{ + return &feegrant.MsgGrantAllowance{ Granter: "invalid-granter", Grantee: suite.addrs[1].String(), Allowance: any, @@ -30,10 +30,10 @@ func (suite *KeeperTestSuite) TestGrantAllowance() { }, { "invalid grantee address", - func() *types.MsgGrantAllowance { - any, err := codectypes.NewAnyWithValue(&types.BasicAllowance{}) + func() *feegrant.MsgGrantAllowance { + any, err := codectypes.NewAnyWithValue(&feegrant.BasicAllowance{}) suite.Require().NoError(err) - return &types.MsgGrantAllowance{ + return &feegrant.MsgGrantAllowance{ Granter: suite.addrs[0].String(), Grantee: "invalid-grantee", Allowance: any, @@ -44,13 +44,13 @@ func (suite *KeeperTestSuite) TestGrantAllowance() { }, { "valid: basic fee allowance", - func() *types.MsgGrantAllowance { - any, err := codectypes.NewAnyWithValue(&types.BasicAllowance{ + func() *feegrant.MsgGrantAllowance { + any, err := codectypes.NewAnyWithValue(&feegrant.BasicAllowance{ SpendLimit: suite.atom, Expiration: &oneYear, }) suite.Require().NoError(err) - return &types.MsgGrantAllowance{ + return &feegrant.MsgGrantAllowance{ Granter: suite.addrs[0].String(), Grantee: suite.addrs[1].String(), Allowance: any, @@ -61,13 +61,13 @@ func (suite *KeeperTestSuite) TestGrantAllowance() { }, { "fail: fee allowance exists", - func() *types.MsgGrantAllowance { - any, err := codectypes.NewAnyWithValue(&types.BasicAllowance{ + func() *feegrant.MsgGrantAllowance { + any, err := codectypes.NewAnyWithValue(&feegrant.BasicAllowance{ SpendLimit: suite.atom, Expiration: &oneYear, }) suite.Require().NoError(err) - return &types.MsgGrantAllowance{ + return &feegrant.MsgGrantAllowance{ Granter: suite.addrs[0].String(), Grantee: suite.addrs[1].String(), Allowance: any, @@ -78,15 +78,15 @@ func (suite *KeeperTestSuite) TestGrantAllowance() { }, { "valid: periodic fee allowance", - func() *types.MsgGrantAllowance { - any, err := codectypes.NewAnyWithValue(&types.PeriodicAllowance{ - Basic: types.BasicAllowance{ + func() *feegrant.MsgGrantAllowance { + any, err := codectypes.NewAnyWithValue(&feegrant.PeriodicAllowance{ + Basic: feegrant.BasicAllowance{ SpendLimit: suite.atom, Expiration: &oneYear, }, }) suite.Require().NoError(err) - return &types.MsgGrantAllowance{ + return &feegrant.MsgGrantAllowance{ Granter: suite.addrs[1].String(), Grantee: suite.addrs[2].String(), Allowance: any, @@ -97,15 +97,15 @@ func (suite *KeeperTestSuite) TestGrantAllowance() { }, { "error: fee allowance exists", - func() *types.MsgGrantAllowance { - any, err := codectypes.NewAnyWithValue(&types.PeriodicAllowance{ - Basic: types.BasicAllowance{ + func() *feegrant.MsgGrantAllowance { + any, err := codectypes.NewAnyWithValue(&feegrant.PeriodicAllowance{ + Basic: feegrant.BasicAllowance{ SpendLimit: suite.atom, Expiration: &oneYear, }, }) suite.Require().NoError(err) - return &types.MsgGrantAllowance{ + return &feegrant.MsgGrantAllowance{ Granter: suite.addrs[1].String(), Grantee: suite.addrs[2].String(), Allowance: any, @@ -131,14 +131,14 @@ func (suite *KeeperTestSuite) TestRevokeAllowance() { testCases := []struct { name string - request *types.MsgRevokeAllowance + request *feegrant.MsgRevokeAllowance preRun func() expectErr bool errMsg string }{ { "error: invalid granter", - &types.MsgRevokeAllowance{ + &feegrant.MsgRevokeAllowance{ Granter: "invalid-granter", Grantee: suite.addrs[1].String(), }, @@ -148,7 +148,7 @@ func (suite *KeeperTestSuite) TestRevokeAllowance() { }, { "error: invalid grantee", - &types.MsgRevokeAllowance{ + &feegrant.MsgRevokeAllowance{ Granter: suite.addrs[0].String(), Grantee: "invalid-grantee", }, @@ -158,7 +158,7 @@ func (suite *KeeperTestSuite) TestRevokeAllowance() { }, { "error: fee allowance not found", - &types.MsgRevokeAllowance{ + &feegrant.MsgRevokeAllowance{ Granter: suite.addrs[0].String(), Grantee: suite.addrs[1].String(), }, @@ -168,24 +168,24 @@ func (suite *KeeperTestSuite) TestRevokeAllowance() { }, { "success: revoke fee allowance", - &types.MsgRevokeAllowance{ + &feegrant.MsgRevokeAllowance{ Granter: suite.addrs[0].String(), Grantee: suite.addrs[1].String(), }, func() { // removing fee allowance from previous tests if exists - suite.msgSrvr.RevokeAllowance(suite.ctx, &types.MsgRevokeAllowance{ + suite.msgSrvr.RevokeAllowance(suite.ctx, &feegrant.MsgRevokeAllowance{ Granter: suite.addrs[0].String(), Grantee: suite.addrs[1].String(), }) - any, err := codectypes.NewAnyWithValue(&types.PeriodicAllowance{ - Basic: types.BasicAllowance{ + any, err := codectypes.NewAnyWithValue(&feegrant.PeriodicAllowance{ + Basic: feegrant.BasicAllowance{ SpendLimit: suite.atom, Expiration: &oneYear, }, }) suite.Require().NoError(err) - req := &types.MsgGrantAllowance{ + req := &feegrant.MsgGrantAllowance{ Granter: suite.addrs[0].String(), Grantee: suite.addrs[1].String(), Allowance: any, @@ -198,7 +198,7 @@ func (suite *KeeperTestSuite) TestRevokeAllowance() { }, { "error: check fee allowance revoked", - &types.MsgRevokeAllowance{ + &feegrant.MsgRevokeAllowance{ Granter: suite.addrs[0].String(), Grantee: suite.addrs[1].String(), }, diff --git a/x/feegrant/types/key.go b/x/feegrant/key.go similarity index 78% rename from x/feegrant/types/key.go rename to x/feegrant/key.go index 9996a57155..49faa422ea 100644 --- a/x/feegrant/types/key.go +++ b/x/feegrant/key.go @@ -1,7 +1,8 @@ -package types +package feegrant import ( sdk "github.com/line/lbm-sdk/types" + "github.com/line/lbm-sdk/types/address" ) const ( @@ -26,10 +27,10 @@ var ( // FeeAllowanceKey is the canonical key to store a grant from granter to grantee // We store by grantee first to allow searching by everyone who granted to you func FeeAllowanceKey(granter sdk.AccAddress, grantee sdk.AccAddress) []byte { - return append(FeeAllowancePrefixByGrantee(grantee), granter.Bytes()...) + return append(FeeAllowancePrefixByGrantee(grantee), address.MustLengthPrefix(granter.Bytes())...) } // FeeAllowancePrefixByGrantee returns a prefix to scan for all grants to this given address. func FeeAllowancePrefixByGrantee(grantee sdk.AccAddress) []byte { - return append(FeeAllowanceKeyPrefix, grantee.Bytes()...) + return append(FeeAllowanceKeyPrefix, address.MustLengthPrefix(grantee.Bytes())...) } diff --git a/x/feegrant/module.go b/x/feegrant/module/module.go similarity index 81% rename from x/feegrant/module.go rename to x/feegrant/module/module.go index b89f4d3ec8..67560e6589 100644 --- a/x/feegrant/module.go +++ b/x/feegrant/module/module.go @@ -1,4 +1,4 @@ -package feegrant +package module import ( "context" @@ -10,8 +10,6 @@ import ( abci "github.com/line/ostracon/abci/types" "github.com/spf13/cobra" - "github.com/line/lbm-sdk/x/feegrant/types" - sdkclient "github.com/line/lbm-sdk/client" "github.com/line/lbm-sdk/codec" cdctypes "github.com/line/lbm-sdk/codec/types" @@ -19,6 +17,7 @@ import ( sdkerrors "github.com/line/lbm-sdk/types/errors" "github.com/line/lbm-sdk/types/module" simtypes "github.com/line/lbm-sdk/types/simulation" + "github.com/line/lbm-sdk/x/feegrant" "github.com/line/lbm-sdk/x/feegrant/client/cli" "github.com/line/lbm-sdk/x/feegrant/keeper" "github.com/line/lbm-sdk/x/feegrant/simulation" @@ -36,19 +35,19 @@ var ( // AppModuleBasic defines the basic application module used by the feegrant module. type AppModuleBasic struct { - cdc codec.Marshaler + cdc codec.Codec } // Name returns the feegrant module's name. func (AppModuleBasic) Name() string { - return types.ModuleName + return feegrant.ModuleName } // RegisterServices registers a gRPC query service to respond to the // module-specific gRPC queries. func (am AppModule) RegisterServices(cfg module.Configurator) { - types.RegisterMsgServer(cfg.MsgServer(), keeper.NewMsgServerImpl(am.keeper)) - types.RegisterQueryServer(cfg.QueryServer(), am.keeper) + feegrant.RegisterMsgServer(cfg.MsgServer(), keeper.NewMsgServerImpl(am.keeper)) + feegrant.RegisterQueryServer(cfg.QueryServer(), am.keeper) } // RegisterLegacyAminoCodec registers the feegrant module's types for the given codec. @@ -57,7 +56,7 @@ func (AppModuleBasic) RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) { // RegisterInterfaces registers the feegrant module's interface types func (AppModuleBasic) RegisterInterfaces(registry cdctypes.InterfaceRegistry) { - types.RegisterInterfaces(registry) + feegrant.RegisterInterfaces(registry) } // LegacyQuerierHandler returns the feegrant module sdk.Querier. @@ -67,18 +66,18 @@ func (am AppModule) LegacyQuerierHandler(legacyQuerierCdc *codec.LegacyAmino) sd // DefaultGenesis returns default genesis state as raw bytes for the feegrant // module. -func (AppModuleBasic) DefaultGenesis(cdc codec.JSONMarshaler) json.RawMessage { - return cdc.MustMarshalJSON(types.DefaultGenesisState()) +func (AppModuleBasic) DefaultGenesis(cdc codec.JSONCodec) json.RawMessage { + return cdc.MustMarshalJSON(feegrant.DefaultGenesisState()) } // ValidateGenesis performs genesis state validation for the feegrant module. -func (a AppModuleBasic) ValidateGenesis(cdc codec.JSONMarshaler, config sdkclient.TxEncodingConfig, bz json.RawMessage) error { - var data types.GenesisState +func (a AppModuleBasic) ValidateGenesis(cdc codec.JSONCodec, config sdkclient.TxEncodingConfig, bz json.RawMessage) error { + var data feegrant.GenesisState if err := cdc.UnmarshalJSON(bz, &data); err != nil { - sdkerrors.Wrapf(err, "failed to unmarshal %s genesis state", types.ModuleName) + sdkerrors.Wrapf(err, "failed to unmarshal %s genesis state", feegrant.ModuleName) } - return types.ValidateGenesis(data) + return feegrant.ValidateGenesis(data) } // RegisterRESTRoutes registers the REST routes for the feegrant module. @@ -87,7 +86,7 @@ func (AppModuleBasic) RegisterRESTRoutes(clientCtx sdkclient.Context, rtr *mux.R // RegisterGRPCGatewayRoutes registers the gRPC Gateway routes for the feegrant module. func (AppModuleBasic) RegisterGRPCGatewayRoutes(clientCtx sdkclient.Context, mux *runtime.ServeMux) { - if err := types.RegisterQueryHandlerClient(context.Background(), mux, types.NewQueryClient(clientCtx)); err != nil { + if err := feegrant.RegisterQueryHandlerClient(context.Background(), mux, feegrant.NewQueryClient(clientCtx)); err != nil { panic(err) } } @@ -110,13 +109,13 @@ func (AppModuleBasic) GetQueryCmd() *cobra.Command { type AppModule struct { AppModuleBasic keeper keeper.Keeper - accountKeeper types.AccountKeeper - bankKeeper types.BankKeeper + accountKeeper feegrant.AccountKeeper + bankKeeper feegrant.BankKeeper registry cdctypes.InterfaceRegistry } // NewAppModule creates a new AppModule object -func NewAppModule(cdc codec.Marshaler, ak types.AccountKeeper, bk types.BankKeeper, keeper keeper.Keeper, registry cdctypes.InterfaceRegistry) AppModule { +func NewAppModule(cdc codec.Codec, ak feegrant.AccountKeeper, bk feegrant.BankKeeper, keeper keeper.Keeper, registry cdctypes.InterfaceRegistry) AppModule { return AppModule{ AppModuleBasic: AppModuleBasic{cdc: cdc}, keeper: keeper, @@ -128,7 +127,7 @@ func NewAppModule(cdc codec.Marshaler, ak types.AccountKeeper, bk types.BankKeep // Name returns the feegrant module's name. func (AppModule) Name() string { - return types.ModuleName + return feegrant.ModuleName } // RegisterInvariants registers the feegrant module invariants. @@ -136,7 +135,7 @@ func (am AppModule) RegisterInvariants(ir sdk.InvariantRegistry) {} // Deprecated: Route returns the message routing key for the feegrant module. func (am AppModule) Route() sdk.Route { - return sdk.NewRoute(types.RouterKey, NewHandler(am.keeper)) + return sdk.Route{} } // NewHandler returns an sdk.Handler for the feegrant module. @@ -151,8 +150,8 @@ func (AppModule) QuerierRoute() string { // InitGenesis performs genesis initialization for the feegrant module. It returns // no validator updates. -func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONMarshaler, bz json.RawMessage) []abci.ValidatorUpdate { - var gs types.GenesisState +func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONCodec, bz json.RawMessage) []abci.ValidatorUpdate { + var gs feegrant.GenesisState cdc.MustUnmarshalJSON(bz, &gs) err := am.keeper.InitGenesis(ctx, &gs) @@ -164,7 +163,7 @@ func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONMarshaler, bz jso // ExportGenesis returns the exported genesis state as raw bytes for the feegrant // module. -func (am AppModule) ExportGenesis(ctx sdk.Context, cdc codec.JSONMarshaler) json.RawMessage { +func (am AppModule) ExportGenesis(ctx sdk.Context, cdc codec.JSONCodec) json.RawMessage { gs, err := am.keeper.ExportGenesis(ctx) if err != nil { panic(err) @@ -205,7 +204,7 @@ func (AppModule) RandomizedParams(r *rand.Rand) []simtypes.ParamChange { // RegisterStoreDecoder registers a decoder for feegrant module's types func (am AppModule) RegisterStoreDecoder(sdr sdk.StoreDecoderRegistry) { - sdr[types.StoreKey] = simulation.NewDecodeStore(am.cdc) + sdr[feegrant.StoreKey] = simulation.NewDecodeStore(am.cdc) } // WeightedOperations returns all the feegrant module operations with their respective weights. diff --git a/x/feegrant/types/msgs.go b/x/feegrant/msgs.go similarity index 90% rename from x/feegrant/types/msgs.go rename to x/feegrant/msgs.go index 87ffd781d8..0ba7a09202 100644 --- a/x/feegrant/types/msgs.go +++ b/x/feegrant/msgs.go @@ -1,4 +1,4 @@ -package types +package feegrant import ( "github.com/gogo/protobuf/proto" @@ -7,10 +7,12 @@ import ( "github.com/line/lbm-sdk/codec/types" sdk "github.com/line/lbm-sdk/types" sdkerrors "github.com/line/lbm-sdk/types/errors" + "github.com/line/lbm-sdk/x/auth/legacy/legacytx" ) var ( - _, _ sdk.Msg = &MsgGrantAllowance{}, &MsgRevokeAllowance{} + _, _ sdk.Msg = &MsgGrantAllowance{}, &MsgRevokeAllowance{} + _, _ legacytx.LegacyMsg = &MsgGrantAllowance{}, &MsgRevokeAllowance{} // For amino support. _ types.UnpackInterfacesMessage = &MsgGrantAllowance{} ) @@ -66,7 +68,7 @@ func (msg MsgGrantAllowance) Type() string { // Route implements the LegacyMsg.Route method. func (msg MsgGrantAllowance) Route() string { - return RouterKey + return sdk.MsgTypeURL(&msg) } // GetSignBytes implements the LegacyMsg.GetSignBytes method. @@ -108,6 +110,9 @@ func (msg MsgRevokeAllowance) ValidateBasic() error { if msg.Grantee == msg.Granter { return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, "addresses must be different") } + if msg.Grantee == msg.Granter { + return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, "addresses must be different") + } return nil } @@ -126,7 +131,7 @@ func (msg MsgRevokeAllowance) Type() string { // Route implements the LegacyMsg.Route method. func (msg MsgRevokeAllowance) Route() string { - return RouterKey + return sdk.MsgTypeURL(&msg) } // GetSignBytes implements the LegacyMsg.GetSignBytes method. diff --git a/x/feegrant/types/msgs_test.go b/x/feegrant/msgs_test.go similarity index 88% rename from x/feegrant/types/msgs_test.go rename to x/feegrant/msgs_test.go index bd416e7728..122956a3a0 100644 --- a/x/feegrant/types/msgs_test.go +++ b/x/feegrant/msgs_test.go @@ -1,4 +1,4 @@ -package types_test +package feegrant_test import ( "testing" @@ -6,11 +6,10 @@ import ( "github.com/stretchr/testify/require" - "github.com/line/lbm-sdk/x/feegrant/types" - "github.com/line/lbm-sdk/codec" codectypes "github.com/line/lbm-sdk/codec/types" sdk "github.com/line/lbm-sdk/types" + "github.com/line/lbm-sdk/x/feegrant" ) func TestMsgGrantAllowance(t *testing.T) { @@ -19,7 +18,7 @@ func TestMsgGrantAllowance(t *testing.T) { addr2 := sdk.AccAddress("link18vd8fpwxzck93qlwghaj6arh4p7c5n89fvcmzu") atom := sdk.NewCoins(sdk.NewInt64Coin("atom", 555)) threeHours := time.Now().Add(3 * time.Hour) - basic := &types.BasicAllowance{ + basic := &feegrant.BasicAllowance{ SpendLimit: atom, Expiration: &threeHours, } @@ -27,7 +26,7 @@ func TestMsgGrantAllowance(t *testing.T) { cases := map[string]struct { grantee sdk.AccAddress granter sdk.AccAddress - grant *types.BasicAllowance + grant *feegrant.BasicAllowance valid bool }{ "valid": { @@ -57,7 +56,7 @@ func TestMsgGrantAllowance(t *testing.T) { } for _, tc := range cases { - msg, err := types.NewMsgGrantAllowance(tc.grant, tc.granter, tc.grantee) + msg, err := feegrant.NewMsgGrantAllowance(tc.grant, tc.granter, tc.grantee) require.NoError(t, err) err = msg.ValidateBasic() @@ -85,14 +84,14 @@ func TestMsgRevokeAllowance(t *testing.T) { atom := sdk.NewCoins(sdk.NewInt64Coin("atom", 555)) threeHours := time.Now().Add(3 * time.Hour) - basic := &types.BasicAllowance{ + basic := &feegrant.BasicAllowance{ SpendLimit: atom, Expiration: &threeHours, } cases := map[string]struct { grantee sdk.AccAddress granter sdk.AccAddress - grant *types.BasicAllowance + grant *feegrant.BasicAllowance valid bool }{ "valid": { @@ -122,7 +121,7 @@ func TestMsgRevokeAllowance(t *testing.T) { } for _, tc := range cases { - msg := types.NewMsgRevokeAllowance(tc.granter, tc.grantee) + msg := feegrant.NewMsgRevokeAllowance(tc.granter, tc.grantee) err := msg.ValidateBasic() if tc.valid { require.NoError(t, err) diff --git a/x/feegrant/types/periodic_fee.go b/x/feegrant/periodic_fee.go similarity index 99% rename from x/feegrant/types/periodic_fee.go rename to x/feegrant/periodic_fee.go index 396f233635..20151f45f5 100644 --- a/x/feegrant/types/periodic_fee.go +++ b/x/feegrant/periodic_fee.go @@ -1,4 +1,4 @@ -package types +package feegrant import ( "time" diff --git a/x/feegrant/periodic_fee_test.go b/x/feegrant/periodic_fee_test.go new file mode 100644 index 0000000000..1aea4326be --- /dev/null +++ b/x/feegrant/periodic_fee_test.go @@ -0,0 +1,213 @@ +package feegrant_test + +import ( + "testing" + "time" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + ocproto "github.com/line/ostracon/proto/ostracon/types" + + "github.com/line/lbm-sdk/simapp" + sdk "github.com/line/lbm-sdk/types" + "github.com/line/lbm-sdk/x/feegrant" +) + +func TestPeriodicFeeValidAllow(t *testing.T) { + app := simapp.Setup(false) + ctx := app.BaseApp.NewContext(false, ocproto.Header{ + Time: time.Now(), + }) + + atom := sdk.NewCoins(sdk.NewInt64Coin("atom", 555)) + smallAtom := sdk.NewCoins(sdk.NewInt64Coin("atom", 43)) + leftAtom := sdk.NewCoins(sdk.NewInt64Coin("atom", 512)) + oneAtom := sdk.NewCoins(sdk.NewInt64Coin("atom", 1)) + eth := sdk.NewCoins(sdk.NewInt64Coin("eth", 1)) + + now := ctx.BlockTime() + oneHour := now.Add(1 * time.Hour) + twoHours := now.Add(2 * time.Hour) + tenMinutes := time.Duration(10) * time.Minute + + cases := map[string]struct { + allow feegrant.PeriodicAllowance + fee sdk.Coins + blockTime time.Time + valid bool // all other checks are ignored if valid=false + accept bool + remove bool + remains sdk.Coins + remainsPeriod sdk.Coins + periodReset time.Time + }{ + "empty": { + allow: feegrant.PeriodicAllowance{}, + valid: false, + }, + "only basic": { + allow: feegrant.PeriodicAllowance{ + Basic: feegrant.BasicAllowance{ + SpendLimit: atom, + Expiration: &oneHour, + }, + }, + valid: false, + }, + "empty basic": { + allow: feegrant.PeriodicAllowance{ + Period: tenMinutes, + PeriodSpendLimit: smallAtom, + PeriodReset: now.Add(30 * time.Minute), + }, + blockTime: now, + valid: true, + accept: true, + remove: false, + periodReset: now.Add(30 * time.Minute), + }, + "mismatched currencies": { + allow: feegrant.PeriodicAllowance{ + Basic: feegrant.BasicAllowance{ + SpendLimit: atom, + Expiration: &oneHour, + }, + Period: tenMinutes, + PeriodSpendLimit: eth, + }, + valid: false, + }, + "same period": { + allow: feegrant.PeriodicAllowance{ + Basic: feegrant.BasicAllowance{ + SpendLimit: atom, + Expiration: &twoHours, + }, + Period: tenMinutes, + PeriodReset: now.Add(1 * time.Hour), + PeriodSpendLimit: leftAtom, + PeriodCanSpend: smallAtom, + }, + valid: true, + fee: smallAtom, + blockTime: now, + accept: true, + remove: false, + remainsPeriod: nil, + remains: leftAtom, + periodReset: now.Add(1 * time.Hour), + }, + "step one period": { + allow: feegrant.PeriodicAllowance{ + Basic: feegrant.BasicAllowance{ + SpendLimit: atom, + Expiration: &twoHours, + }, + Period: tenMinutes, + PeriodReset: now, + PeriodSpendLimit: leftAtom, + }, + valid: true, + fee: leftAtom, + blockTime: now.Add(1 * time.Hour), + accept: true, + remove: false, + remainsPeriod: nil, + remains: smallAtom, + periodReset: oneHour.Add(tenMinutes), // one step from last reset, not now + }, + "step limited by global allowance": { + allow: feegrant.PeriodicAllowance{ + Basic: feegrant.BasicAllowance{ + SpendLimit: smallAtom, + Expiration: &twoHours, + }, + Period: tenMinutes, + PeriodReset: now, + PeriodSpendLimit: atom, + }, + valid: true, + fee: oneAtom, + blockTime: oneHour, + accept: true, + remove: false, + remainsPeriod: smallAtom.Sub(oneAtom), + remains: smallAtom.Sub(oneAtom), + periodReset: oneHour.Add(tenMinutes), // one step from last reset, not now + }, + "period reset no spend limit": { + allow: feegrant.PeriodicAllowance{ + Period: tenMinutes, + PeriodReset: now, + PeriodSpendLimit: atom, + }, + valid: true, + fee: atom, + blockTime: oneHour, + accept: true, + remove: false, + periodReset: oneHour.Add(tenMinutes), // one step from last reset, not now + }, + "expired": { + allow: feegrant.PeriodicAllowance{ + Basic: feegrant.BasicAllowance{ + SpendLimit: atom, + Expiration: &now, + }, + Period: time.Hour, + PeriodSpendLimit: smallAtom, + }, + valid: true, + fee: smallAtom, + blockTime: oneHour, + accept: false, + remove: true, + }, + "over period limit": { + allow: feegrant.PeriodicAllowance{ + Basic: feegrant.BasicAllowance{ + SpendLimit: atom, + Expiration: &now, + }, + Period: time.Hour, + PeriodReset: now.Add(1 * time.Hour), + PeriodSpendLimit: leftAtom, + PeriodCanSpend: smallAtom, + }, + valid: true, + fee: leftAtom, + blockTime: now, + accept: false, + remove: true, + }, + } + + for name, stc := range cases { + tc := stc // to make scopelint happy + t.Run(name, func(t *testing.T) { + err := tc.allow.ValidateBasic() + if !tc.valid { + require.Error(t, err) + return + } + require.NoError(t, err) + + ctx := app.BaseApp.NewContext(false, ocproto.Header{}).WithBlockTime(tc.blockTime) + // now try to deduct + remove, err := tc.allow.Accept(ctx, tc.fee, []sdk.Msg{}) + if !tc.accept { + require.Error(t, err) + return + } + require.NoError(t, err) + + require.Equal(t, tc.remove, remove) + if !remove { + assert.Equal(t, tc.remains, tc.allow.Basic.SpendLimit) + assert.Equal(t, tc.remainsPeriod, tc.allow.PeriodCanSpend) + assert.Equal(t, tc.periodReset.String(), tc.allow.PeriodReset.String()) + } + }) + } +} diff --git a/x/feegrant/types/query.pb.go b/x/feegrant/query.pb.go similarity index 91% rename from x/feegrant/types/query.pb.go rename to x/feegrant/query.pb.go index 3a9b57f8b4..1102ac48f9 100644 --- a/x/feegrant/types/query.pb.go +++ b/x/feegrant/query.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-gogo. DO NOT EDIT. // source: lbm/feegrant/v1/query.proto -package types +package feegrant import ( context "context" @@ -250,36 +250,36 @@ func init() { func init() { proto.RegisterFile("lbm/feegrant/v1/query.proto", fileDescriptor_e2fd9dc33a9e9ee8) } var fileDescriptor_e2fd9dc33a9e9ee8 = []byte{ - // 464 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x84, 0x93, 0x31, 0x8f, 0xd3, 0x30, - 0x14, 0xc7, 0xeb, 0x22, 0x40, 0xf5, 0x0d, 0x48, 0x16, 0x94, 0x2a, 0x20, 0xdf, 0xc9, 0x12, 0x5c, - 0x97, 0xb3, 0x69, 0x39, 0xdd, 0xc0, 0x00, 0xa2, 0x0b, 0x1b, 0x82, 0x8e, 0x2c, 0xc8, 0xb9, 0x3e, - 0x4c, 0x44, 0x6a, 0xe7, 0xe2, 0xb4, 0x50, 0xa1, 0x5b, 0x60, 0x3f, 0x21, 0xe0, 0x7b, 0xf0, 0x35, - 0x18, 0x2b, 0xb1, 0x30, 0x21, 0xd4, 0xf2, 0x09, 0xf8, 0x04, 0x28, 0x4e, 0xd2, 0x54, 0x69, 0x4a, - 0x37, 0x2b, 0xff, 0xff, 0x7b, 0xef, 0xf7, 0x7f, 0x76, 0xf0, 0xad, 0xd0, 0x1f, 0x8b, 0x57, 0x00, - 0x2a, 0x96, 0x3a, 0x11, 0xd3, 0x9e, 0x38, 0x9b, 0x40, 0x3c, 0xe3, 0x51, 0x6c, 0x12, 0x43, 0xae, - 0x85, 0xfe, 0x98, 0x17, 0x22, 0x9f, 0xf6, 0xbc, 0xeb, 0xca, 0x28, 0xe3, 0x34, 0x91, 0x9e, 0x32, - 0x9b, 0x47, 0xab, 0x3d, 0x56, 0x25, 0x99, 0xce, 0x52, 0xdd, 0x97, 0x16, 0xb2, 0xe6, 0xa9, 0x23, - 0x92, 0x2a, 0xd0, 0x32, 0x09, 0x8c, 0xce, 0x3d, 0xb7, 0x95, 0x31, 0x2a, 0x04, 0x21, 0xa3, 0x40, - 0x48, 0xad, 0x4d, 0xe2, 0x44, 0x9b, 0xa9, 0xec, 0x23, 0xc2, 0x37, 0x9e, 0xa7, 0xb5, 0x8f, 0xc3, - 0xd0, 0xbc, 0x95, 0xfa, 0x14, 0x86, 0x70, 0x36, 0x01, 0x9b, 0x90, 0x63, 0x7c, 0xd5, 0x8d, 0x82, - 0xb8, 0x83, 0x0e, 0x50, 0xb7, 0x35, 0xf0, 0xfe, 0xfe, 0xda, 0x6f, 0xcf, 0xe4, 0x38, 0x7c, 0xc0, - 0x72, 0xe1, 0xa5, 0x1c, 0x8d, 0x62, 0xb0, 0x96, 0x0d, 0x0b, 0x6b, 0x59, 0x05, 0x9d, 0x66, 0x7d, - 0x15, 0x6c, 0x54, 0x01, 0x7b, 0x8a, 0xdb, 0x55, 0x08, 0x1b, 0x19, 0x6d, 0x81, 0x1c, 0xe3, 0x96, - 0x2c, 0x3e, 0x3a, 0x8e, 0xbd, 0x7e, 0x9b, 0x57, 0x96, 0xc7, 0x9f, 0xa4, 0x87, 0x61, 0x69, 0x64, - 0x17, 0xa8, 0xda, 0xd0, 0x6e, 0xc4, 0x82, 0x6d, 0xb1, 0x6a, 0x00, 0xc9, 0x43, 0x8c, 0xcb, 0xc5, - 0xba, 0x64, 0x7b, 0x7d, 0xea, 0x38, 0xd2, 0xed, 0xf3, 0xec, 0x6a, 0xa7, 0x3d, 0xfe, 0x4c, 0xaa, - 0x62, 0x81, 0xc3, 0xb5, 0x0a, 0xf6, 0x19, 0xe1, 0x9b, 0x1b, 0x40, 0x79, 0xc4, 0x13, 0x8c, 0x57, - 0xe4, 0xb6, 0x83, 0x0e, 0x2e, 0xfd, 0x27, 0xe3, 0x9a, 0x93, 0x3c, 0xaa, 0x61, 0xda, 0xdf, 0xca, - 0x94, 0x0d, 0x5b, 0x87, 0xea, 0x7f, 0x6b, 0xe2, 0xcb, 0x0e, 0x8a, 0x7c, 0x45, 0xb8, 0xb5, 0x22, - 0x23, 0x77, 0x37, 0x86, 0xd7, 0xbe, 0x10, 0xef, 0x70, 0xa7, 0x2f, 0x1b, 0xca, 0x4e, 0x3e, 0xfc, - 0xf8, 0xf3, 0xa5, 0x79, 0x8f, 0x70, 0x51, 0x7d, 0xcf, 0xab, 0x38, 0xe2, 0x7d, 0xfe, 0x82, 0xce, - 0x8b, 0x13, 0x9c, 0x93, 0x0b, 0x84, 0x71, 0xb9, 0x30, 0xb2, 0x6b, 0x5e, 0x71, 0xc7, 0x5e, 0x77, - 0xb7, 0x31, 0x27, 0x3b, 0x72, 0x64, 0x87, 0xe4, 0xce, 0x76, 0x32, 0x5b, 0x02, 0x0d, 0x06, 0xdf, - 0x17, 0x14, 0xcd, 0x17, 0x14, 0xfd, 0x5e, 0x50, 0xf4, 0x69, 0x49, 0x1b, 0xf3, 0x25, 0x6d, 0xfc, - 0x5c, 0xd2, 0xc6, 0x8b, 0xae, 0x0a, 0x92, 0xd7, 0x13, 0x9f, 0x9f, 0x9a, 0xb1, 0x08, 0x03, 0x0d, - 0x69, 0xbf, 0x23, 0x3b, 0x7a, 0x23, 0xde, 0x95, 0x5d, 0x93, 0x59, 0x04, 0xd6, 0xbf, 0xe2, 0x7e, - 0xbc, 0xfb, 0xff, 0x02, 0x00, 0x00, 0xff, 0xff, 0x83, 0xe4, 0xf8, 0x5c, 0x20, 0x04, 0x00, 0x00, + // 461 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x84, 0x93, 0xcf, 0x6e, 0x13, 0x31, + 0x10, 0xc6, 0xe3, 0x20, 0x40, 0x71, 0x0f, 0x48, 0x16, 0x84, 0x68, 0x41, 0x6e, 0x65, 0x09, 0xda, + 0x4b, 0x6d, 0x12, 0xaa, 0x1e, 0x10, 0x02, 0xd1, 0x0b, 0x37, 0x04, 0x39, 0x72, 0x41, 0xde, 0x66, + 0x30, 0x2b, 0x36, 0x76, 0xba, 0xde, 0x04, 0x2a, 0xd4, 0x0b, 0xdc, 0x2b, 0x04, 0xbc, 0x07, 0xaf, + 0xc1, 0x31, 0x12, 0x17, 0x4e, 0x08, 0x25, 0x3c, 0x01, 0x4f, 0x80, 0xd6, 0xfb, 0x2f, 0xda, 0xdd, + 0x34, 0x37, 0x6b, 0xbf, 0x6f, 0x66, 0x7e, 0xdf, 0xd8, 0x8b, 0x6f, 0x85, 0xfe, 0x58, 0xbc, 0x06, + 0x50, 0x91, 0xd4, 0xb1, 0x98, 0xf5, 0xc5, 0xc9, 0x14, 0xa2, 0x53, 0x3e, 0x89, 0x4c, 0x6c, 0xc8, + 0xb5, 0xd0, 0x1f, 0xf3, 0x5c, 0xe4, 0xb3, 0xbe, 0x77, 0x5d, 0x19, 0x65, 0x9c, 0x26, 0x92, 0x53, + 0x6a, 0xf3, 0x68, 0xb5, 0x47, 0x51, 0x92, 0xea, 0x2c, 0xd1, 0x7d, 0x69, 0x21, 0x6d, 0x9e, 0x38, + 0x26, 0x52, 0x05, 0x5a, 0xc6, 0x81, 0xd1, 0x99, 0xe7, 0xb6, 0x32, 0x46, 0x85, 0x20, 0xe4, 0x24, + 0x10, 0x52, 0x6b, 0x13, 0x3b, 0xd1, 0xa6, 0x2a, 0xfb, 0x84, 0xf0, 0x8d, 0x17, 0x49, 0xed, 0x93, + 0x30, 0x34, 0xef, 0xa4, 0x3e, 0x86, 0x21, 0x9c, 0x4c, 0xc1, 0xc6, 0xe4, 0x00, 0x5f, 0x75, 0xa3, + 0x20, 0xea, 0xa1, 0x1d, 0xb4, 0xd7, 0x39, 0xf2, 0xfe, 0xfd, 0xde, 0xee, 0x9e, 0xca, 0x71, 0xf8, + 0x80, 0x65, 0xc2, 0x2b, 0x39, 0x1a, 0x45, 0x60, 0x2d, 0x1b, 0xe6, 0xd6, 0xb2, 0x0a, 0x7a, 0xed, + 0xe6, 0x2a, 0xa8, 0x55, 0x01, 0x7b, 0x86, 0xbb, 0x55, 0x08, 0x3b, 0x31, 0xda, 0x02, 0x39, 0xc0, + 0x1d, 0x99, 0x7f, 0x74, 0x1c, 0x5b, 0x83, 0x2e, 0xaf, 0x2c, 0x8f, 0x3f, 0x4d, 0x0e, 0xc3, 0xd2, + 0xc8, 0xce, 0x51, 0xb5, 0xa1, 0xad, 0xc5, 0x82, 0x75, 0xb1, 0x1a, 0x00, 0xc9, 0x23, 0x8c, 0xcb, + 0xc5, 0xba, 0x64, 0x5b, 0x03, 0xea, 0x38, 0x92, 0xed, 0xf3, 0xf4, 0x6a, 0x67, 0x7d, 0xfe, 0x5c, + 0xaa, 0x7c, 0x81, 0xc3, 0x95, 0x0a, 0xf6, 0x05, 0xe1, 0x9b, 0x35, 0xa0, 0x2c, 0xe2, 0x21, 0xc6, + 0x05, 0xb9, 0xed, 0xa1, 0x9d, 0x4b, 0x17, 0x64, 0x5c, 0x71, 0x92, 0xc7, 0x0d, 0x4c, 0xdb, 0x6b, + 0x99, 0xd2, 0x61, 0xab, 0x50, 0x83, 0xef, 0x6d, 0x7c, 0xd9, 0x41, 0x91, 0x6f, 0x08, 0x77, 0x0a, + 0x32, 0x72, 0xb7, 0x36, 0xbc, 0xf1, 0x85, 0x78, 0xbb, 0x1b, 0x7d, 0xe9, 0x50, 0x76, 0xf8, 0xf1, + 0xe7, 0xdf, 0xaf, 0xed, 0x7b, 0x84, 0x8b, 0xea, 0x7b, 0x2e, 0xe2, 0x88, 0x0f, 0xd9, 0x0b, 0x3a, + 0xcb, 0x4f, 0x70, 0x46, 0xce, 0x11, 0xc6, 0xe5, 0xc2, 0xc8, 0xa6, 0x79, 0xf9, 0x1d, 0x7b, 0x7b, + 0x9b, 0x8d, 0x19, 0xd9, 0xbe, 0x23, 0xdb, 0x25, 0x77, 0xd6, 0x93, 0xd9, 0x12, 0xe8, 0xe8, 0xe1, + 0x8f, 0x05, 0x45, 0xf3, 0x05, 0x45, 0x7f, 0x16, 0x14, 0x7d, 0x5e, 0xd2, 0xd6, 0x7c, 0x49, 0x5b, + 0xbf, 0x96, 0xb4, 0xf5, 0x92, 0xa9, 0x20, 0x7e, 0x33, 0xf5, 0xf9, 0xb1, 0x19, 0x8b, 0x30, 0xd0, + 0x90, 0xf4, 0xdb, 0xb7, 0xa3, 0xb7, 0xe2, 0x7d, 0xd1, 0xd5, 0xbf, 0xe2, 0x7e, 0xb9, 0xfb, 0xff, + 0x03, 0x00, 0x00, 0xff, 0xff, 0x34, 0xe8, 0x50, 0x05, 0x1a, 0x04, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. diff --git a/x/feegrant/types/query.pb.gw.go b/x/feegrant/query.pb.gw.go similarity index 98% rename from x/feegrant/types/query.pb.gw.go rename to x/feegrant/query.pb.gw.go index 3df57aa1b8..a94505f7cb 100644 --- a/x/feegrant/types/query.pb.gw.go +++ b/x/feegrant/query.pb.gw.go @@ -2,11 +2,11 @@ // source: lbm/feegrant/v1/query.proto /* -Package types is a reverse proxy. +Package feegrant is a reverse proxy. It translates gRPC into RESTful JSON APIs. */ -package types +package feegrant import ( "context" @@ -310,9 +310,9 @@ func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, clie } var ( - pattern_Query_Allowance_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4, 1, 0, 4, 1, 5, 5}, []string{"lbm", "feegrant", "v1", "allowance", "granter", "grantee"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_Query_Allowance_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4, 1, 0, 4, 1, 5, 5}, []string{"lbm", "feegrant", "v1", "allowance", "granter", "grantee"}, "", runtime.AssumeColonVerbOpt(false))) - pattern_Query_Allowances_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4}, []string{"lbm", "feegrant", "v1", "allowances", "grantee"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_Query_Allowances_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4}, []string{"lbm", "feegrant", "v1", "allowances", "grantee"}, "", runtime.AssumeColonVerbOpt(false))) ) var ( diff --git a/x/feegrant/simulation/decoder.go b/x/feegrant/simulation/decoder.go index 5de093f15e..9255841706 100644 --- a/x/feegrant/simulation/decoder.go +++ b/x/feegrant/simulation/decoder.go @@ -6,18 +6,18 @@ import ( "github.com/line/lbm-sdk/codec" "github.com/line/lbm-sdk/types/kv" - "github.com/line/lbm-sdk/x/feegrant/types" + "github.com/line/lbm-sdk/x/feegrant" ) // NewDecodeStore returns a decoder function closure that unmarshals the KVPair's // Value to the corresponding feegrant type. -func NewDecodeStore(cdc codec.Marshaler) func(kvA, kvB kv.Pair) string { +func NewDecodeStore(cdc codec.Codec) func(kvA, kvB kv.Pair) string { return func(kvA, kvB kv.Pair) string { switch { - case bytes.Equal(kvA.Key[:1], types.FeeAllowanceKeyPrefix): - var grantA, grantB types.Grant - cdc.MustUnmarshalBinaryBare(kvA.Value, &grantA) - cdc.MustUnmarshalBinaryBare(kvB.Value, &grantB) + case bytes.Equal(kvA.Key[:1], feegrant.FeeAllowanceKeyPrefix): + var grantA, grantB feegrant.Grant + cdc.MustUnmarshal(kvA.Value, &grantA) + cdc.MustUnmarshal(kvB.Value, &grantB) return fmt.Sprintf("%v\n%v", grantA, grantB) default: panic(fmt.Sprintf("invalid feegrant key %X", kvA.Key)) diff --git a/x/feegrant/simulation/decoder_test.go b/x/feegrant/simulation/decoder_test.go index be5a0b5bcf..0d4cb8c649 100644 --- a/x/feegrant/simulation/decoder_test.go +++ b/x/feegrant/simulation/decoder_test.go @@ -6,38 +6,36 @@ import ( "github.com/stretchr/testify/require" - "github.com/line/lbm-sdk/x/feegrant/types" - "github.com/line/lbm-sdk/crypto/keys/ed25519" "github.com/line/lbm-sdk/simapp" sdk "github.com/line/lbm-sdk/types" "github.com/line/lbm-sdk/types/kv" + "github.com/line/lbm-sdk/x/feegrant" "github.com/line/lbm-sdk/x/feegrant/simulation" ) var ( granterPk = ed25519.GenPrivKey().PubKey() granterAddr = sdk.AccAddress(granterPk.Address()) - granteePk = ed25519.GenPrivKey().PubKey() granteeAddr = sdk.AccAddress(granterPk.Address()) ) func TestDecodeStore(t *testing.T) { - cdc, _ := simapp.MakeCodecs() + cdc := simapp.MakeTestEncodingConfig().Marshaler dec := simulation.NewDecodeStore(cdc) - grant, err := types.NewGrant(granterAddr, granteeAddr, &types.BasicAllowance{ + grant, err := feegrant.NewGrant(granterAddr, granteeAddr, &feegrant.BasicAllowance{ SpendLimit: sdk.NewCoins(sdk.NewCoin("foo", sdk.NewInt(100))), }) require.NoError(t, err) - grantBz, err := cdc.MarshalBinaryBare(&grant) + grantBz, err := cdc.Marshal(&grant) require.NoError(t, err) kvPairs := kv.Pairs{ Pairs: []kv.Pair{ - {Key: []byte(types.FeeAllowanceKeyPrefix), Value: grantBz}, + {Key: []byte(feegrant.FeeAllowanceKeyPrefix), Value: grantBz}, {Key: []byte{0x99}, Value: []byte{0x99}}, }, } diff --git a/x/feegrant/simulation/genesis.go b/x/feegrant/simulation/genesis.go index d78d3eb7b4..92debdeddc 100644 --- a/x/feegrant/simulation/genesis.go +++ b/x/feegrant/simulation/genesis.go @@ -7,12 +7,12 @@ import ( sdk "github.com/line/lbm-sdk/types" "github.com/line/lbm-sdk/types/module" simtypes "github.com/line/lbm-sdk/types/simulation" - "github.com/line/lbm-sdk/x/feegrant/types" + "github.com/line/lbm-sdk/x/feegrant" ) // genFeeGrants returns a slice of randomly generated allowances. -func genFeeGrants(r *rand.Rand, accounts []simtypes.Account) []types.Grant { - allowances := make([]types.Grant, len(accounts)-1) +func genFeeGrants(r *rand.Rand, accounts []simtypes.Account) []feegrant.Grant { + allowances := make([]feegrant.Grant, len(accounts)-1) for i := 0; i < len(accounts)-1; i++ { granter := accounts[i].Address grantee := accounts[i+1].Address @@ -21,22 +21,22 @@ func genFeeGrants(r *rand.Rand, accounts []simtypes.Account) []types.Grant { return allowances } -func generateRandomAllowances(granter, grantee sdk.AccAddress, r *rand.Rand) types.Grant { - allowances := make([]types.Grant, 3) +func generateRandomAllowances(granter, grantee sdk.AccAddress, r *rand.Rand) feegrant.Grant { + allowances := make([]feegrant.Grant, 3) spendLimit := sdk.NewCoins(sdk.NewCoin("stake", sdk.NewInt(100))) periodSpendLimit := sdk.NewCoins(sdk.NewCoin("stake", sdk.NewInt(10))) - basic := types.BasicAllowance{ + basic := feegrant.BasicAllowance{ SpendLimit: spendLimit, } - basicAllowance, err := types.NewGrant(granter, grantee, &basic) + basicAllowance, err := feegrant.NewGrant(granter, grantee, &basic) if err != nil { panic(err) } allowances[0] = basicAllowance - periodicAllowance, err := types.NewGrant(granter, grantee, &types.PeriodicAllowance{ + periodicAllowance, err := feegrant.NewGrant(granter, grantee, &feegrant.PeriodicAllowance{ Basic: basic, PeriodSpendLimit: periodSpendLimit, Period: time.Hour, @@ -46,7 +46,7 @@ func generateRandomAllowances(granter, grantee sdk.AccAddress, r *rand.Rand) typ } allowances[1] = periodicAllowance - filteredAllowance, err := types.NewGrant(granter, grantee, &types.AllowedMsgAllowance{ + filteredAllowance, err := feegrant.NewGrant(granter, grantee, &feegrant.AllowedMsgAllowance{ Allowance: basicAllowance.GetAllowance(), AllowedMessages: []string{"/lbm.gov.v1.MsgSubmitProposal"}, }) @@ -60,18 +60,18 @@ func generateRandomAllowances(granter, grantee sdk.AccAddress, r *rand.Rand) typ // RandomizedGenState generates a random GenesisState for feegrant func RandomizedGenState(simState *module.SimulationState) { - var feegrants []types.Grant + var feegrants []feegrant.Grant simState.AppParams.GetOrGenerate( simState.Cdc, "feegrant", &feegrants, simState.Rand, func(r *rand.Rand) { feegrants = genFeeGrants(r, simState.Accounts) }, ) - feegrantGenesis := types.NewGenesisState(feegrants) + feegrantGenesis := feegrant.NewGenesisState(feegrants) bz, err := simState.Cdc.MarshalJSON(feegrantGenesis) if err != nil { panic(err) } - simState.GenState[types.ModuleName] = bz + simState.GenState[feegrant.ModuleName] = bz } diff --git a/x/feegrant/simulation/genesis_test.go b/x/feegrant/simulation/genesis_test.go index 2e4c403c03..1c56c64b32 100644 --- a/x/feegrant/simulation/genesis_test.go +++ b/x/feegrant/simulation/genesis_test.go @@ -7,11 +7,10 @@ import ( "github.com/stretchr/testify/require" - "github.com/line/lbm-sdk/x/feegrant/types" - "github.com/line/lbm-sdk/simapp" "github.com/line/lbm-sdk/types/module" simtypes "github.com/line/lbm-sdk/types/simulation" + "github.com/line/lbm-sdk/x/feegrant" "github.com/line/lbm-sdk/x/feegrant/simulation" ) @@ -34,8 +33,8 @@ func TestRandomizedGenState(t *testing.T) { } simulation.RandomizedGenState(&simState) - var feegrantGenesis types.GenesisState - simState.Cdc.MustUnmarshalJSON(simState.GenState[types.ModuleName], &feegrantGenesis) + var feegrantGenesis feegrant.GenesisState + simState.Cdc.MustUnmarshalJSON(simState.GenState[feegrant.ModuleName], &feegrantGenesis) require.Len(t, feegrantGenesis.Allowances, len(accounts)-1) } diff --git a/x/feegrant/simulation/operations.go b/x/feegrant/simulation/operations.go index 504af677bb..ab58e5bcba 100644 --- a/x/feegrant/simulation/operations.go +++ b/x/feegrant/simulation/operations.go @@ -8,11 +8,12 @@ import ( simappparams "github.com/line/lbm-sdk/simapp/params" sdk "github.com/line/lbm-sdk/types" simtypes "github.com/line/lbm-sdk/types/simulation" + "github.com/line/lbm-sdk/x/feegrant" "github.com/line/lbm-sdk/x/feegrant/keeper" - "github.com/line/lbm-sdk/x/feegrant/types" "github.com/line/lbm-sdk/x/simulation" ) +// nolint:gosec // Simulation operation weights constants const ( OpWeightMsgGrantAllowance = "op_weight_msg_grant_fee_allowance" @@ -20,13 +21,13 @@ const ( ) var ( - TypeMsgGrantAllowance = sdk.MsgTypeURL(&types.MsgGrantAllowance{}) - TypeMsgRevokeAllowance = sdk.MsgTypeURL(&types.MsgRevokeAllowance{}) + TypeMsgGrantAllowance = sdk.MsgTypeURL(&feegrant.MsgGrantAllowance{}) + TypeMsgRevokeAllowance = sdk.MsgTypeURL(&feegrant.MsgRevokeAllowance{}) ) func WeightedOperations( - appParams simtypes.AppParams, cdc codec.JSONMarshaler, - ak types.AccountKeeper, bk types.BankKeeper, k keeper.Keeper, + appParams simtypes.AppParams, cdc codec.JSONCodec, + ak feegrant.AccountKeeper, bk feegrant.BankKeeper, k keeper.Keeper, ) simulation.WeightedOperations { var ( @@ -59,35 +60,35 @@ func WeightedOperations( } // SimulateMsgGrantAllowance generates MsgGrantAllowance with random values. -func SimulateMsgGrantAllowance(ak types.AccountKeeper, bk types.BankKeeper, k keeper.Keeper) simtypes.Operation { +func SimulateMsgGrantAllowance(ak feegrant.AccountKeeper, bk feegrant.BankKeeper, k keeper.Keeper) simtypes.Operation { return func( r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simtypes.Account, chainID string, ) (simtypes.OperationMsg, []simtypes.FutureOperation, error) { granter, _ := simtypes.RandomAcc(r, accs) grantee, _ := simtypes.RandomAcc(r, accs) if grantee.Address.String() == granter.Address.String() { - return simtypes.NoOpMsg(types.ModuleName, TypeMsgGrantAllowance, "grantee and granter cannot be same"), nil, nil + return simtypes.NoOpMsg(feegrant.ModuleName, TypeMsgGrantAllowance, "grantee and granter cannot be same"), nil, nil } if f, _ := k.GetAllowance(ctx, granter.Address, grantee.Address); f != nil { - return simtypes.NoOpMsg(types.ModuleName, TypeMsgGrantAllowance, "fee allowance exists"), nil, nil + return simtypes.NoOpMsg(feegrant.ModuleName, TypeMsgGrantAllowance, "fee allowance exists"), nil, nil } account := ak.GetAccount(ctx, granter.Address) spendableCoins := bk.SpendableCoins(ctx, account.GetAddress()) if spendableCoins.Empty() { - return simtypes.NoOpMsg(types.ModuleName, TypeMsgGrantAllowance, "unable to grant empty coins as SpendLimit"), nil, nil + return simtypes.NoOpMsg(feegrant.ModuleName, TypeMsgGrantAllowance, "unable to grant empty coins as SpendLimit"), nil, nil } oneYear := ctx.BlockTime().AddDate(1, 0, 0) - msg, err := types.NewMsgGrantAllowance(&types.BasicAllowance{ + msg, err := feegrant.NewMsgGrantAllowance(&feegrant.BasicAllowance{ SpendLimit: spendableCoins, Expiration: &oneYear, }, granter.Address, grantee.Address) if err != nil { - return simtypes.NoOpMsg(types.ModuleName, TypeMsgGrantAllowance, err.Error()), nil, err + return simtypes.NoOpMsg(feegrant.ModuleName, TypeMsgGrantAllowance, err.Error()), nil, err } txCtx := simulation.OperationInput{ @@ -101,7 +102,7 @@ func SimulateMsgGrantAllowance(ak types.AccountKeeper, bk types.BankKeeper, k ke SimAccount: granter, AccountKeeper: ak, Bankkeeper: bk, - ModuleName: types.ModuleName, + ModuleName: feegrant.ModuleName, CoinsSpentInMsg: spendableCoins, } @@ -110,7 +111,7 @@ func SimulateMsgGrantAllowance(ak types.AccountKeeper, bk types.BankKeeper, k ke } // SimulateMsgRevokeAllowance generates a MsgRevokeAllowance with random values. -func SimulateMsgRevokeAllowance(ak types.AccountKeeper, bk types.BankKeeper, k keeper.Keeper) simtypes.Operation { +func SimulateMsgRevokeAllowance(ak feegrant.AccountKeeper, bk feegrant.BankKeeper, k keeper.Keeper) simtypes.Operation { return func( r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simtypes.Account, chainID string, ) (simtypes.OperationMsg, []simtypes.FutureOperation, error) { @@ -118,7 +119,7 @@ func SimulateMsgRevokeAllowance(ak types.AccountKeeper, bk types.BankKeeper, k k hasGrant := false var granterAddr sdk.AccAddress var granteeAddr sdk.AccAddress - k.IterateAllFeeAllowances(ctx, func(grant types.Grant) bool { + k.IterateAllFeeAllowances(ctx, func(grant feegrant.Grant) bool { granter := sdk.AccAddress(grant.Granter) grantee := sdk.AccAddress(grant.Grantee) @@ -129,18 +130,18 @@ func SimulateMsgRevokeAllowance(ak types.AccountKeeper, bk types.BankKeeper, k k }) if !hasGrant { - return simtypes.NoOpMsg(types.ModuleName, TypeMsgRevokeAllowance, "no grants"), nil, nil + return simtypes.NoOpMsg(feegrant.ModuleName, TypeMsgRevokeAllowance, "no grants"), nil, nil } granter, ok := simtypes.FindAccount(accs, granterAddr) if !ok { - return simtypes.NoOpMsg(types.ModuleName, TypeMsgRevokeAllowance, "Account not found"), nil, nil + return simtypes.NoOpMsg(feegrant.ModuleName, TypeMsgRevokeAllowance, "Account not found"), nil, nil } account := ak.GetAccount(ctx, granter.Address) spendableCoins := bk.SpendableCoins(ctx, account.GetAddress()) - msg := types.NewMsgRevokeAllowance(granterAddr, granteeAddr) + msg := feegrant.NewMsgRevokeAllowance(granterAddr, granteeAddr) txCtx := simulation.OperationInput{ R: r, @@ -153,7 +154,7 @@ func SimulateMsgRevokeAllowance(ak types.AccountKeeper, bk types.BankKeeper, k k SimAccount: granter, AccountKeeper: ak, Bankkeeper: bk, - ModuleName: types.ModuleName, + ModuleName: feegrant.ModuleName, CoinsSpentInMsg: spendableCoins, } diff --git a/x/feegrant/simulation/operations_test.go b/x/feegrant/simulation/operations_test.go index d9c4e35c17..79014dcda0 100644 --- a/x/feegrant/simulation/operations_test.go +++ b/x/feegrant/simulation/operations_test.go @@ -5,17 +5,16 @@ import ( "testing" "time" - abci "github.com/line/ostracon/abci/types" - tmproto "github.com/line/ostracon/proto/ostracon/types" "github.com/stretchr/testify/suite" - "github.com/line/lbm-sdk/x/feegrant/types" + abci "github.com/line/ostracon/abci/types" + ocproto "github.com/line/ostracon/proto/ostracon/types" "github.com/line/lbm-sdk/simapp" simappparams "github.com/line/lbm-sdk/simapp/params" sdk "github.com/line/lbm-sdk/types" simtypes "github.com/line/lbm-sdk/types/simulation" - "github.com/line/lbm-sdk/x/bank/testutil" + "github.com/line/lbm-sdk/x/feegrant" "github.com/line/lbm-sdk/x/feegrant/simulation" ) @@ -30,7 +29,7 @@ func (suite *SimTestSuite) SetupTest() { checkTx := false app := simapp.Setup(checkTx) suite.app = app - suite.ctx = app.BaseApp.NewContext(checkTx, tmproto.Header{ + suite.ctx = app.BaseApp.NewContext(checkTx, ocproto.Header{ Time: time.Now(), }) @@ -39,12 +38,12 @@ func (suite *SimTestSuite) SetupTest() { func (suite *SimTestSuite) getTestingAccounts(r *rand.Rand, n int) []simtypes.Account { accounts := simtypes.RandomAccounts(r, n) - initAmt := sdk.TokensFromConsensusPower(200) + initAmt := sdk.TokensFromConsensusPower(200, sdk.DefaultPowerReduction) initCoins := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, initAmt)) // add coins to the accounts for _, account := range accounts { - err := testutil.FundAccount(suite.app.BankKeeper, suite.ctx, account.Address, initCoins) + err := simapp.FundAccount(suite.app, suite.ctx, account.Address, initCoins) suite.Require().NoError(err) } @@ -76,12 +75,12 @@ func (suite *SimTestSuite) TestWeightedOperations() { }{ { simappparams.DefaultWeightGrantAllowance, - types.MsgGrantAllowance{}.Route(), + feegrant.ModuleName, simulation.TypeMsgGrantAllowance, }, { simappparams.DefaultWeightRevokeAllowance, - types.MsgRevokeAllowance{}.Route(), + feegrant.ModuleName, simulation.TypeMsgRevokeAllowance, }, } @@ -106,14 +105,14 @@ func (suite *SimTestSuite) TestSimulateMsgGrantAllowance() { accounts := suite.getTestingAccounts(r, 3) // begin a new block - app.BeginBlock(abci.RequestBeginBlock{Header: tmproto.Header{Height: app.LastBlockHeight() + 1, AppHash: app.LastCommitID().Hash}}) + app.BeginBlock(abci.RequestBeginBlock{Header: ocproto.Header{Height: app.LastBlockHeight() + 1, AppHash: app.LastCommitID().Hash}}) // execute operation op := simulation.SimulateMsgGrantAllowance(app.AccountKeeper, app.BankKeeper, app.FeeGrantKeeper) operationMsg, futureOperations, err := op(r, app.BaseApp, ctx, accounts, "") require.NoError(err) - var msg types.MsgGrantAllowance + var msg feegrant.MsgGrantAllowance suite.app.AppCodec().UnmarshalJSON(operationMsg.Msg, &msg) require.True(operationMsg.OK) @@ -131,9 +130,9 @@ func (suite *SimTestSuite) TestSimulateMsgRevokeAllowance() { accounts := suite.getTestingAccounts(r, 3) // begin a new block - app.BeginBlock(abci.RequestBeginBlock{Header: tmproto.Header{Height: suite.app.LastBlockHeight() + 1, AppHash: suite.app.LastCommitID().Hash}}) + app.BeginBlock(abci.RequestBeginBlock{Header: ocproto.Header{Height: suite.app.LastBlockHeight() + 1, AppHash: suite.app.LastCommitID().Hash}}) - feeAmt := sdk.TokensFromConsensusPower(200000) + feeAmt := app.StakingKeeper.TokensFromConsensusPower(ctx, 200000) feeCoins := sdk.NewCoins(sdk.NewCoin("foo", feeAmt)) granter, grantee := accounts[0], accounts[1] @@ -143,7 +142,7 @@ func (suite *SimTestSuite) TestSimulateMsgRevokeAllowance() { ctx, granter.Address, grantee.Address, - &types.BasicAllowance{ + &feegrant.BasicAllowance{ SpendLimit: feeCoins, Expiration: &oneYear, }, @@ -155,7 +154,7 @@ func (suite *SimTestSuite) TestSimulateMsgRevokeAllowance() { operationMsg, futureOperations, err := op(r, app.BaseApp, ctx, accounts, "") require.NoError(err) - var msg types.MsgRevokeAllowance + var msg feegrant.MsgRevokeAllowance suite.app.AppCodec().UnmarshalJSON(operationMsg.Msg, &msg) require.True(operationMsg.OK) diff --git a/x/feegrant/spec/01_concepts.md b/x/feegrant/spec/01_concepts.md index b99250eb7b..feba289ea5 100644 --- a/x/feegrant/spec/01_concepts.md +++ b/x/feegrant/spec/01_concepts.md @@ -8,11 +8,11 @@ order: 1 `Grant` is stored in the KVStore to record a grant with full context. Every grant will contain `granter`, `grantee` and what kind of `allowance` is granted. `granter` is an account address who is giving permission to `grantee` (the beneficiary account address) to pay for some or all of `grantee`'s transaction fees. `allowance` defines what kind of fee allowance (`BasicAllowance` or `PeriodicAllowance`, see below) is granted to `grantee`. `allowance` accepts an interface which implements `FeeAllowanceI`, encoded as `Any` type. There can be only one existing fee grant allowed for a `grantee` and `granter`, self grants are not allowed. -+++ https://github.com/line/lbm-sdk/blob/691032b8be0f7539ec99f8882caecefc51f33d1f/proto/cosmos/feegrant/v1beta1/feegrant.proto#L75-L81 ++++ https://github.com/cosmos/cosmos-sdk/blob/691032b8be0f7539ec99f8882caecefc51f33d1f/proto/cosmos/feegrant/v1beta1/feegrant.proto#L75-L81 `FeeAllowanceI` looks like: -+++ https://github.com/line/lbm-sdk/blob/691032b8be0f7539ec99f8882caecefc51f33d1f/x/feegrant/fees.go#L9-L32 ++++ https://github.com/cosmos/cosmos-sdk/blob/691032b8be0f7539ec99f8882caecefc51f33d1f/x/feegrant/fees.go#L9-L32 ## Fee Allowance types @@ -25,7 +25,7 @@ There are two types of fee allowances present at the moment: `BasicAllowance` is permission for `grantee` to use fee from a `granter`'s account. If any of the `spend_limit` or `expiration` reaches its limit, the grant will be removed from the state. -+++ https://github.com/line/lbm-sdk/blob/691032b8be0f7539ec99f8882caecefc51f33d1f/proto/cosmos/feegrant/v1beta1/feegrant.proto#L13-L26 ++++ https://github.com/cosmos/cosmos-sdk/blob/691032b8be0f7539ec99f8882caecefc51f33d1f/proto/cosmos/feegrant/v1beta1/feegrant.proto#L13-L26 - `spend_limit` is the limit of coins that are allowed to be used from the `granter` account. If it is empty, it assumes there's no spend limit, `grantee` can use any number of available tokens from `granter` account address before the expiration. @@ -37,7 +37,7 @@ There are two types of fee allowances present at the moment: `PeriodicAllowance` is a repeating fee allowance for the mentioned period, we can mention when the grant can expire as well as when a period can reset. We can also define the maximum number of coins that can be used in a mentioned period of time. -+++ https://github.com/line/lbm-sdk/blob/691032b8be0f7539ec99f8882caecefc51f33d1f/proto/cosmos/feegrant/v1beta1/feegrant.proto#L28-L73 ++++ https://github.com/cosmos/cosmos-sdk/blob/691032b8be0f7539ec99f8882caecefc51f33d1f/proto/cosmos/feegrant/v1beta1/feegrant.proto#L28-L73 - `basic` is the instance of `BasicAllowance` which is optional for periodic fee allowance. If empty, the grant will have no `expiration` and no `spend_limit`. @@ -53,13 +53,13 @@ There are two types of fee allowances present at the moment: `feegrant` module introduces a `FeeAccount` flag for CLI for the sake of executing transactions with fee granter. When this flag is set, `clientCtx` will append the granter account address for transactions generated through CLI. -+++ https://github.com/line/lbm-sdk/blob/d97e7907f176777ed8a464006d360bb3e1a223e4/client/cmd.go#L224-L235 ++++ https://github.com/cosmos/cosmos-sdk/blob/d97e7907f176777ed8a464006d360bb3e1a223e4/client/cmd.go#L224-L235 -+++ https://github.com/line/lbm-sdk/blob/d97e7907f176777ed8a464006d360bb3e1a223e4/client/tx/tx.go#L120 ++++ https://github.com/cosmos/cosmos-sdk/blob/d97e7907f176777ed8a464006d360bb3e1a223e4/client/tx/tx.go#L120 -+++ https://github.com/line/lbm-sdk/blob/d97e7907f176777ed8a464006d360bb3e1a223e4/x/auth/tx/builder.go#L268-L277 ++++ https://github.com/cosmos/cosmos-sdk/blob/d97e7907f176777ed8a464006d360bb3e1a223e4/x/auth/tx/builder.go#L268-L277 -+++ https://github.com/line/lbm-sdk/blob/d97e7907f176777ed8a464006d360bb3e1a223e4/proto/cosmos/tx/v1beta1/tx.proto#L160-L181 ++++ https://github.com/cosmos/cosmos-sdk/blob/d97e7907f176777ed8a464006d360bb3e1a223e4/proto/cosmos/tx/v1beta1/tx.proto#L160-L181 Example cmd: @@ -75,4 +75,4 @@ Fees are deducted from grants in the `x/auth` ante handler. To learn more about In order to prevent DoS attacks, using a filtered `x/feegrant` incurs gas. The SDK must assure that the `grantee`'s transactions all conform to the filter set by the `granter`. The SDK does this by iterating over the allowed messages in the filter and charging 10 gas per filtered message. The SDK will then iterate over the messages being sent by the `grantee` to ensure the messages adhere to the filter, also charging 10 gas per message. The SDK will stop iterating and fail the transaction if it finds a message that does not conform to the filter. -**WARNING**: The gas is charged against the granted allowance. Ensure your messages conform to the filter, if any, before sending transactions using your allowance. +**WARNING**: The gas is charged against the granted allowance. Ensure your messages conform to the filter, if any, before sending transactions using your allowance. diff --git a/x/feegrant/spec/02_state.md b/x/feegrant/spec/02_state.md index fbf90d8b34..0c5b9177d1 100644 --- a/x/feegrant/spec/02_state.md +++ b/x/feegrant/spec/02_state.md @@ -10,6 +10,14 @@ Fee Allowances are identified by combining `Grantee` (the account address of fee Fee allowance grants are stored in the state as follows: -- Grant: `0x00 | grantee_addr_len (1 byte) | grantee_addr_bytes | granter_addr_len (1 byte) | granter_addr_bytes -> ProtocolBuffer(Grant)` +* Grant: `0x00 | grantee_addr_len (1 byte) | grantee_addr_bytes | granter_addr_len (1 byte) | granter_addr_bytes -> ProtocolBuffer(Grant)` -+++ https://github.com/line/lbm-sdk/blob/691032b8be0f7539ec99f8882caecefc51f33d1f/x/feegrant/feegrant.pb.go#L221-L229 ++++ https://github.com/cosmos/cosmos-sdk/blob/691032b8be0f7539ec99f8882caecefc51f33d1f/x/feegrant/feegrant.pb.go#L221-L229 + +## FeeAllowanceQueue + +Fee Allowances queue items are identified by combining the `FeeAllowancePrefixQueue` (i.e., 0x01), `expiration`, `grantee` (the account address of fee allowance grantee), `granter` (the account address of fee allowance granter). Endblocker checks `FeeAllowanceQueue` state for the expired grants and prunes them from `FeeAllowance` if there are any found. + +Fee allowance queue keys are stored in the state as follows: + +* Grant: `0x01 | expiration_bytes | grantee_addr_len (1 byte) | grantee_addr_bytes | granter_addr_len (1 byte) | granter_addr_bytes -> EmptyBytes` diff --git a/x/feegrant/spec/03_messages.md b/x/feegrant/spec/03_messages.md index 9aaccf9686..602dd2b712 100644 --- a/x/feegrant/spec/03_messages.md +++ b/x/feegrant/spec/03_messages.md @@ -8,10 +8,10 @@ order: 3 A fee allowance grant will be created with the `MsgGrantAllowance` message. -+++ https://github.com/line/lbm-sdk/blob/691032b8be0f7539ec99f8882caecefc51f33d1f/proto/cosmos/feegrant/v1beta1/tx.proto#L22-L33 ++++ https://github.com/cosmos/cosmos-sdk/blob/691032b8be0f7539ec99f8882caecefc51f33d1f/proto/cosmos/feegrant/v1beta1/tx.proto#L22-L33 ## Msg/RevokeAllowance An allowed grant fee allowance can be removed with the `MsgRevokeAllowance` message. -+++ https://github.com/line/lbm-sdk/blob/691032b8be0f7539ec99f8882caecefc51f33d1f/proto/cosmos/feegrant/v1beta1/tx.proto#L38-L45 ++++ https://github.com/cosmos/cosmos-sdk/blob/691032b8be0f7539ec99f8882caecefc51f33d1f/proto/cosmos/feegrant/v1beta1/tx.proto#L38-L45 diff --git a/x/feegrant/spec/04_events.md b/x/feegrant/spec/04_events.md index 55012f8c68..7790b37fdf 100644 --- a/x/feegrant/spec/04_events.md +++ b/x/feegrant/spec/04_events.md @@ -10,24 +10,21 @@ The feegrant module emits the following events: ### MsgGrantAllowance -| Type | Attribute Key | Attribute Value | -| -------- | ------------- | ------------------ | -| message | action | set_feegrant | -| message | granter | {granterAddress} | -| message | grantee | {granteeAddress} | +| Type | Attribute Key | Attribute Value | +| ------- | ------------- | ---------------- | +| message | action | set_feegrant | +| message | granter | {granterAddress} | +| message | grantee | {granteeAddress} | ### MsgRevokeAllowance +| ------- | ------------- | ---------------- | +| message | granter | {granterAddress} | +| message | grantee | {granteeAddress} | -| Type | Attribute Key | Attribute Value | -| -------- | ------------- | ------------------ | -| message | action | revoke_feegrant | -| message | granter | {granterAddress} | -| message | grantee | {granteeAddress} | +## Exec fee allowance -### Exec fee allowance - -| Type | Attribute Key | Attribute Value | -| -------- | ------------- | ------------------ | -| message | action | use_feegrant | -| message | granter | {granterAddress} | -| message | grantee | {granteeAddress} | +| Type | Attribute Key | Attribute Value | +| ------- | ------------- | ---------------- | +| message | action | use_feegrant | +| message | granter | {granterAddress} | +| message | grantee | {granteeAddress} | diff --git a/x/feegrant/spec/README.md b/x/feegrant/spec/README.md index 00cd685c62..109baf23ed 100644 --- a/x/feegrant/spec/README.md +++ b/x/feegrant/spec/README.md @@ -5,9 +5,11 @@ parent: title: "feegrant" --> +# Fee grant + ## Abstract -This document specifies the feegrant module. For the full ADR, please see [Fee Grant ADR-029](https://github.com/line/lbm-sdk/blob/v0.40.0/docs/architecture/adr-029-fee-grant-module.md). +This document specifies the fee grant module. For the full ADR, please see [Fee Grant ADR-029](https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/docs/architecture/adr-029-fee-grant-module.md). This module allows accounts to grant fee allowances and to use fees from their accounts. Grantees can execute any transaction without the need to maintain sufficient fees. @@ -22,14 +24,11 @@ This module allows accounts to grant fee allowances and to use fees from their a - [Granted Fee Deductions](01_concepts.md#granted-fee-deductions) - [Gas](01_concepts.md#gas) 2. **[State](02_state.md)** - - [FeeAllowance](02_state.md#feeallowance) + * [FeeAllowance](02_state.md#feeallowance) 3. **[Messages](03_messages.md)** - - [Msg/GrantAllowance](03_messages.md#msggrantallowance) - - [Msg/RevokeAllowance](03_messages.md#msgrevokeallowance) + * [Msg/GrantAllowance](03_messages.md#msggrantallowance) + * [Msg/RevokeAllowance](03_messages.md#msgrevokeallowance) 4. **[Events](04_events.md)** - [MsgGrantAllowance](04_events.md#msggrantallowance) - [MsgRevokeAllowance](04_events.md#msgrevokeallowance) - [Exec fee allowance](04_events.md#exec-fee-allowance) -5. **[Client](05_client.md)** - - [CLI](05_client.md#cli) - - [gRPC](05_client.md#grpc) diff --git a/x/feegrant/types/tx.pb.go b/x/feegrant/tx.pb.go similarity index 98% rename from x/feegrant/types/tx.pb.go rename to x/feegrant/tx.pb.go index 42fae6bb42..d3e63b6a81 100644 --- a/x/feegrant/types/tx.pb.go +++ b/x/feegrant/tx.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-gogo. DO NOT EDIT. // source: lbm/feegrant/v1/tx.proto -package types +package feegrant import ( context "context" @@ -234,7 +234,7 @@ func init() { func init() { proto.RegisterFile("lbm/feegrant/v1/tx.proto", fileDescriptor_b4bf88d0a96288f9) } var fileDescriptor_b4bf88d0a96288f9 = []byte{ - // 373 bytes of a gzipped FileDescriptorProto + // 368 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0xc8, 0x49, 0xca, 0xd5, 0x4f, 0x4b, 0x4d, 0x4d, 0x2f, 0x4a, 0xcc, 0x2b, 0xd1, 0x2f, 0x33, 0xd4, 0x2f, 0xa9, 0xd0, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0xe2, 0xcf, 0x49, 0xca, 0xd5, 0x83, 0xc9, 0xe8, 0x95, 0x19, 0x4a, @@ -253,12 +253,11 @@ var fileDescriptor_b4bf88d0a96288f9 = []byte{ 0xc2, 0x74, 0x01, 0xcc, 0x81, 0x46, 0x67, 0x18, 0xb9, 0x98, 0x7d, 0x8b, 0xd3, 0x85, 0x12, 0xb8, 0xf8, 0xd0, 0xa2, 0x42, 0x49, 0x0f, 0x2d, 0xfa, 0xf5, 0x30, 0xbc, 0x29, 0xa5, 0x45, 0x58, 0x0d, 0xcc, 0x26, 0xa1, 0x64, 0x2e, 0x7e, 0xf4, 0x60, 0x50, 0xc6, 0xa6, 0x1d, 0x4d, 0x91, 0x94, 0x36, - 0x11, 0x8a, 0x60, 0x96, 0x38, 0x39, 0x9d, 0x78, 0x24, 0xc7, 0x78, 0xe1, 0x91, 0x1c, 0xe3, 0x83, + 0x11, 0x8a, 0x60, 0x96, 0x38, 0xd9, 0x9c, 0x78, 0x24, 0xc7, 0x78, 0xe1, 0x91, 0x1c, 0xe3, 0x83, 0x47, 0x72, 0x8c, 0x13, 0x1e, 0xcb, 0x31, 0x5c, 0x78, 0x2c, 0xc7, 0x70, 0xe3, 0xb1, 0x1c, 0x43, - 0x94, 0x46, 0x7a, 0x66, 0x49, 0x46, 0x69, 0x92, 0x5e, 0x72, 0x7e, 0xae, 0x7e, 0x4e, 0x66, 0x5e, - 0xaa, 0x7e, 0x4e, 0x52, 0xae, 0x6e, 0x71, 0x4a, 0xb6, 0x7e, 0x05, 0x22, 0xf1, 0x97, 0x54, 0x16, - 0xa4, 0x16, 0x27, 0xb1, 0x81, 0x23, 0xdf, 0x18, 0x10, 0x00, 0x00, 0xff, 0xff, 0x65, 0x04, 0x27, - 0xf4, 0x19, 0x03, 0x00, 0x00, + 0x94, 0x52, 0x7a, 0x66, 0x49, 0x46, 0x69, 0x92, 0x5e, 0x72, 0x7e, 0xae, 0x7e, 0x4e, 0x66, 0x5e, + 0xaa, 0x7e, 0x4e, 0x52, 0xae, 0x6e, 0x71, 0x4a, 0xb6, 0x7e, 0x05, 0x3c, 0xf1, 0x27, 0xb1, 0x81, + 0xa3, 0xdd, 0x18, 0x10, 0x00, 0x00, 0xff, 0xff, 0x60, 0x71, 0x72, 0x88, 0x13, 0x03, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. diff --git a/x/feegrant/types/basic_fee_test.go b/x/feegrant/types/basic_fee_test.go index 62c9947bbb..0f54169aa8 100644 --- a/x/feegrant/types/basic_fee_test.go +++ b/x/feegrant/types/basic_fee_test.go @@ -4,14 +4,14 @@ import ( "testing" "time" - ocproto "github.com/line/ostracon/proto/ostracon/types" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/line/lbm-sdk/x/feegrant/types" + ocproto "github.com/line/ostracon/proto/ostracon/types" "github.com/line/lbm-sdk/simapp" sdk "github.com/line/lbm-sdk/types" + "github.com/line/lbm-sdk/x/feegrant" ) func TestBasicFeeValidAllow(t *testing.T) { @@ -19,7 +19,7 @@ func TestBasicFeeValidAllow(t *testing.T) { ctx := app.BaseApp.NewContext(false, ocproto.Header{}) badTime := ctx.BlockTime().AddDate(0, 0, -1) - allowace := &types.BasicAllowance{ + allowace := &feegrant.BasicAllowance{ Expiration: &badTime, } require.Error(t, allowace.ValidateBasic()) @@ -36,7 +36,7 @@ func TestBasicFeeValidAllow(t *testing.T) { oneHour := now.Add(1 * time.Hour) cases := map[string]struct { - allowance *types.BasicAllowance + allowance *feegrant.BasicAllowance // all other checks are ignored if valid=false fee sdk.Coins blockTime time.Time @@ -46,11 +46,11 @@ func TestBasicFeeValidAllow(t *testing.T) { remains sdk.Coins }{ "empty": { - allowance: &types.BasicAllowance{}, + allowance: &feegrant.BasicAllowance{}, accept: true, }, "small fee without expire": { - allowance: &types.BasicAllowance{ + allowance: &feegrant.BasicAllowance{ SpendLimit: atom, }, fee: smallAtom, @@ -59,7 +59,7 @@ func TestBasicFeeValidAllow(t *testing.T) { remains: leftAtom, }, "all fee without expire": { - allowance: &types.BasicAllowance{ + allowance: &feegrant.BasicAllowance{ SpendLimit: smallAtom, }, fee: smallAtom, @@ -67,14 +67,14 @@ func TestBasicFeeValidAllow(t *testing.T) { remove: true, }, "wrong fee": { - allowance: &types.BasicAllowance{ + allowance: &feegrant.BasicAllowance{ SpendLimit: smallAtom, }, fee: eth, accept: false, }, "non-expired": { - allowance: &types.BasicAllowance{ + allowance: &feegrant.BasicAllowance{ SpendLimit: atom, Expiration: &oneHour, }, @@ -86,7 +86,7 @@ func TestBasicFeeValidAllow(t *testing.T) { remains: leftAtom, }, "expired": { - allowance: &types.BasicAllowance{ + allowance: &feegrant.BasicAllowance{ SpendLimit: atom, Expiration: &now, }, @@ -97,7 +97,7 @@ func TestBasicFeeValidAllow(t *testing.T) { remove: true, }, "fee more than allowed": { - allowance: &types.BasicAllowance{ + allowance: &feegrant.BasicAllowance{ SpendLimit: atom, Expiration: &oneHour, }, @@ -107,7 +107,7 @@ func TestBasicFeeValidAllow(t *testing.T) { accept: false, }, "with out spend limit": { - allowance: &types.BasicAllowance{ + allowance: &feegrant.BasicAllowance{ Expiration: &oneHour, }, valid: true, @@ -116,7 +116,7 @@ func TestBasicFeeValidAllow(t *testing.T) { accept: true, }, "expired no spend limit": { - allowance: &types.BasicAllowance{ + allowance: &feegrant.BasicAllowance{ Expiration: &now, }, valid: true, @@ -125,6 +125,7 @@ func TestBasicFeeValidAllow(t *testing.T) { accept: false, }, } + require.Error(t, allowace.ValidateBasic()) for name, stc := range cases { tc := stc // to make scopelint happy diff --git a/x/feegrant/types/grant_test.go b/x/feegrant/types/grant_test.go index ff150a7ab9..0681dbb464 100644 --- a/x/feegrant/types/grant_test.go +++ b/x/feegrant/types/grant_test.go @@ -4,13 +4,13 @@ import ( "testing" "time" - ocproto "github.com/line/ostracon/proto/ostracon/types" "github.com/stretchr/testify/require" - "github.com/line/lbm-sdk/x/feegrant/types" + ocproto "github.com/line/ostracon/proto/ostracon/types" "github.com/line/lbm-sdk/simapp" sdk "github.com/line/lbm-sdk/types" + "github.com/line/lbm-sdk/x/feegrant" ) func TestGrant(t *testing.T) { @@ -74,7 +74,7 @@ func TestGrant(t *testing.T) { for name, tc := range cases { tc := tc t.Run(name, func(t *testing.T) { - grant, err := types.NewGrant(tc.granter, tc.grantee, &types.BasicAllowance{ + grant, err := feegrant.NewGrant(tc.granter, tc.grantee, &feegrant.BasicAllowance{ SpendLimit: tc.limit, Expiration: &tc.expires, }) @@ -88,10 +88,10 @@ func TestGrant(t *testing.T) { require.NoError(t, err) // if it is valid, let's try to serialize, deserialize, and make sure it matches - bz, err := cdc.MarshalBinaryBare(&grant) + bz, err := cdc.Marshal(&grant) require.NoError(t, err) - var loaded types.Grant - err = cdc.UnmarshalBinaryBare(bz, &loaded) + var loaded feegrant.Grant + err = cdc.Unmarshal(bz, &loaded) require.NoError(t, err) err = loaded.ValidateBasic() diff --git a/x/feegrant/types/periodic_fee_test.go b/x/feegrant/types/periodic_fee_test.go index 0d551e17c0..adcd3ef85d 100644 --- a/x/feegrant/types/periodic_fee_test.go +++ b/x/feegrant/types/periodic_fee_test.go @@ -4,19 +4,19 @@ import ( "testing" "time" - tmproto "github.com/line/ostracon/proto/ostracon/types" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/line/lbm-sdk/x/feegrant/types" + ocproto "github.com/line/ostracon/proto/ostracon/types" "github.com/line/lbm-sdk/simapp" sdk "github.com/line/lbm-sdk/types" + "github.com/line/lbm-sdk/x/feegrant" ) func TestPeriodicFeeValidAllow(t *testing.T) { app := simapp.Setup(false) - ctx := app.BaseApp.NewContext(false, tmproto.Header{ + ctx := app.BaseApp.NewContext(false, ocproto.Header{ Time: time.Now(), }) @@ -32,7 +32,7 @@ func TestPeriodicFeeValidAllow(t *testing.T) { tenMinutes := time.Duration(10) * time.Minute cases := map[string]struct { - allow types.PeriodicAllowance + allow feegrant.PeriodicAllowance fee sdk.Coins blockTime time.Time valid bool // all other checks are ignored if valid=false @@ -43,12 +43,12 @@ func TestPeriodicFeeValidAllow(t *testing.T) { periodReset time.Time }{ "empty": { - allow: types.PeriodicAllowance{}, + allow: feegrant.PeriodicAllowance{}, valid: false, }, "only basic": { - allow: types.PeriodicAllowance{ - Basic: types.BasicAllowance{ + allow: feegrant.PeriodicAllowance{ + Basic: feegrant.BasicAllowance{ SpendLimit: atom, Expiration: &oneHour, }, @@ -56,7 +56,7 @@ func TestPeriodicFeeValidAllow(t *testing.T) { valid: false, }, "empty basic": { - allow: types.PeriodicAllowance{ + allow: feegrant.PeriodicAllowance{ Period: tenMinutes, PeriodSpendLimit: smallAtom, PeriodReset: now.Add(30 * time.Minute), @@ -68,8 +68,8 @@ func TestPeriodicFeeValidAllow(t *testing.T) { periodReset: now.Add(30 * time.Minute), }, "mismatched currencies": { - allow: types.PeriodicAllowance{ - Basic: types.BasicAllowance{ + allow: feegrant.PeriodicAllowance{ + Basic: feegrant.BasicAllowance{ SpendLimit: atom, Expiration: &oneHour, }, @@ -79,8 +79,8 @@ func TestPeriodicFeeValidAllow(t *testing.T) { valid: false, }, "same period": { - allow: types.PeriodicAllowance{ - Basic: types.BasicAllowance{ + allow: feegrant.PeriodicAllowance{ + Basic: feegrant.BasicAllowance{ SpendLimit: atom, Expiration: &twoHours, }, @@ -99,8 +99,8 @@ func TestPeriodicFeeValidAllow(t *testing.T) { periodReset: now.Add(1 * time.Hour), }, "step one period": { - allow: types.PeriodicAllowance{ - Basic: types.BasicAllowance{ + allow: feegrant.PeriodicAllowance{ + Basic: feegrant.BasicAllowance{ SpendLimit: atom, Expiration: &twoHours, }, @@ -118,8 +118,8 @@ func TestPeriodicFeeValidAllow(t *testing.T) { periodReset: oneHour.Add(tenMinutes), // one step from last reset, not now }, "step limited by global allowance": { - allow: types.PeriodicAllowance{ - Basic: types.BasicAllowance{ + allow: feegrant.PeriodicAllowance{ + Basic: feegrant.BasicAllowance{ SpendLimit: smallAtom, Expiration: &twoHours, }, @@ -137,7 +137,7 @@ func TestPeriodicFeeValidAllow(t *testing.T) { periodReset: oneHour.Add(tenMinutes), // one step from last reset, not now }, "period reset no spend limit": { - allow: types.PeriodicAllowance{ + allow: feegrant.PeriodicAllowance{ Period: tenMinutes, PeriodReset: now, PeriodSpendLimit: atom, @@ -150,8 +150,8 @@ func TestPeriodicFeeValidAllow(t *testing.T) { periodReset: oneHour.Add(tenMinutes), // one step from last reset, not now }, "expired": { - allow: types.PeriodicAllowance{ - Basic: types.BasicAllowance{ + allow: feegrant.PeriodicAllowance{ + Basic: feegrant.BasicAllowance{ SpendLimit: atom, Expiration: &now, }, @@ -165,8 +165,8 @@ func TestPeriodicFeeValidAllow(t *testing.T) { remove: true, }, "over period limit": { - allow: types.PeriodicAllowance{ - Basic: types.BasicAllowance{ + allow: feegrant.PeriodicAllowance{ + Basic: feegrant.BasicAllowance{ SpendLimit: atom, Expiration: &now, }, @@ -193,7 +193,7 @@ func TestPeriodicFeeValidAllow(t *testing.T) { } require.NoError(t, err) - ctx := app.BaseApp.NewContext(false, tmproto.Header{}).WithBlockTime(tc.blockTime) + ctx := app.BaseApp.NewContext(false, ocproto.Header{}).WithBlockTime(tc.blockTime) // now try to deduct remove, err := tc.allow.Accept(ctx, tc.fee, []sdk.Msg{}) if !tc.accept { diff --git a/x/genaccounts/doc.go b/x/genaccounts/doc.go deleted file mode 100644 index 2d255ad465..0000000000 --- a/x/genaccounts/doc.go +++ /dev/null @@ -1,15 +0,0 @@ -/* -Package genaccounts is now deprecated. - -IMPORTANT: This module has been replaced by ADR 011: Generalize Module Accounts. -The ADR can be found here: https://github.com/cosmos/cosmos-sdk/blob/master/docs/architecture/adr-011-generalize-genesis-accounts.md. - -Genesis accounts that existed in the genesis application state under `app_state.accounts` -now exists under the x/auth module's genesis state under the `app_state.auth.accounts` key. -Migration can be performed via x/auth/legacy/v038/migrate.go. In addition, because genesis -accounts are now generalized via an interface, it is now up to the application to -define the concrete types and the respective client logic to add them to a genesis -state/file. For an example implementation of the `add-genesis-account` command please -refer to https://github.com/cosmos/gaia/pull/122. -*/ -package genaccounts diff --git a/x/genutil/client/cli/collect.go b/x/genutil/client/cli/collect.go index 5489d811a7..26dad48a29 100644 --- a/x/genutil/client/cli/collect.go +++ b/x/genutil/client/cli/collect.go @@ -27,7 +27,7 @@ func CollectGenTxsCmd(genBalIterator types.GenesisBalancesIterator, defaultNodeH config := serverCtx.Config clientCtx := client.GetClientContextFromCmd(cmd) - cdc := clientCtx.JSONMarshaler + cdc := clientCtx.Codec config.SetRoot(clientCtx.HomeDir) diff --git a/x/genutil/client/cli/gentx.go b/x/genutil/client/cli/gentx.go index 86e056c132..a5d35efa9e 100644 --- a/x/genutil/client/cli/gentx.go +++ b/x/genutil/client/cli/gentx.go @@ -61,7 +61,7 @@ $ %s gentx my-key-name 1000000stake --home=/path/to/home/dir --keyring-backend=o if err != nil { return err } - cdc := clientCtx.JSONMarshaler + cdc := clientCtx.Codec config := serverCtx.Config config.SetRoot(clientCtx.HomeDir) @@ -77,10 +77,9 @@ $ %s gentx my-key-name 1000000stake --home=/path/to/home/dir --keyring-backend=o } // read --pubkey, if empty take it from priv_validator.json - if valPubKeyString, _ := cmd.Flags().GetString(cli.FlagPubKey); valPubKeyString != "" { - valPubKey, err = sdk.GetPubKeyFromBech32(sdk.Bech32PubKeyTypeConsPub, valPubKeyString) - if err != nil { - return errors.Wrap(err, "failed to get consensus node public key") + if pkStr, _ := cmd.Flags().GetString(cli.FlagPubKey); pkStr != "" { + if err := clientCtx.Codec.UnmarshalInterfaceJSON([]byte(pkStr), &valPubKey); err != nil { + return errors.Wrap(err, "failed to unmarshal validator public key") } } diff --git a/x/genutil/client/cli/gentx_test.go b/x/genutil/client/cli/gentx_test.go deleted file mode 100644 index 413d9497ea..0000000000 --- a/x/genutil/client/cli/gentx_test.go +++ /dev/null @@ -1,97 +0,0 @@ -package cli_test - -import ( - "context" - "fmt" - "io/ioutil" - "os" - "path/filepath" - "testing" - - "github.com/stretchr/testify/suite" - - "github.com/line/lbm-sdk/client" - "github.com/line/lbm-sdk/client/flags" - "github.com/line/lbm-sdk/simapp" - "github.com/line/lbm-sdk/testutil" - "github.com/line/lbm-sdk/testutil/network" - sdk "github.com/line/lbm-sdk/types" - banktypes "github.com/line/lbm-sdk/x/bank/types" - "github.com/line/lbm-sdk/x/genutil/client/cli" - "github.com/line/lbm-sdk/x/staking/types" -) - -type IntegrationTestSuite struct { - suite.Suite - - cfg network.Config - network *network.Network -} - -func (s *IntegrationTestSuite) SetupSuite() { - s.T().Log("setting up integration test suite") - - cfg := network.DefaultConfig() - cfg.NumValidators = 1 - - s.cfg = cfg - s.network = network.New(s.T(), cfg) - - _, err := s.network.WaitForHeight(1) - s.Require().NoError(err) -} - -func (s *IntegrationTestSuite) TearDownSuite() { - s.T().Log("tearing down integration test suite") - s.network.Cleanup() -} - -func (s *IntegrationTestSuite) TestGenTxCmd() { - val := s.network.Validators[0] - dir := s.T().TempDir() - - cmd := cli.GenTxCmd( - simapp.ModuleBasics, - val.ClientCtx.TxConfig, banktypes.GenesisBalancesIterator{}, val.ClientCtx.HomeDir) - - _, out := testutil.ApplyMockIO(cmd) - clientCtx := val.ClientCtx.WithOutput(out) - - ctx := context.Background() - ctx = context.WithValue(ctx, client.ClientContextKey, &clientCtx) - - amount := sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(12)) - genTxFile := filepath.Join(dir, "myTx") - cmd.SetArgs([]string{ - fmt.Sprintf("--%s=%s", flags.FlagChainID, s.network.Config.ChainID), - fmt.Sprintf("--%s=%s", flags.FlagOutputDocument, genTxFile), - val.Moniker, - amount.String(), - }) - - err := cmd.ExecuteContext(ctx) - s.Require().NoError(err) - - // Validate generated transaction. - open, err := os.Open(genTxFile) - s.Require().NoError(err) - - all, err := ioutil.ReadAll(open) - s.Require().NoError(err) - - tx, err := val.ClientCtx.TxConfig.TxJSONDecoder()(all) - s.Require().NoError(err) - - msgs := tx.GetMsgs() - s.Require().Len(msgs, 1) - - s.Require().Equal(types.TypeMsgCreateValidator, msgs[0].Type()) - s.Require().Equal([]sdk.AccAddress{val.Address}, msgs[0].GetSigners()) - s.Require().Equal(amount, msgs[0].(*types.MsgCreateValidator).Value) - err = tx.ValidateBasic() - s.Require().NoError(err) -} - -func TestIntegrationTestSuite(t *testing.T) { - suite.Run(t, new(IntegrationTestSuite)) -} diff --git a/x/genutil/client/cli/init.go b/x/genutil/client/cli/init.go index 71d910dfc3..4682c7b94e 100644 --- a/x/genutil/client/cli/init.go +++ b/x/genutil/client/cli/init.go @@ -72,7 +72,7 @@ func InitCmd(mbm module.BasicManager, defaultNodeHome string) *cobra.Command { Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { clientCtx := client.GetClientContextFromCmd(cmd) - cdc := clientCtx.JSONMarshaler + cdc := clientCtx.Codec serverCtx := server.GetServerContextFromCmd(cmd) config := serverCtx.Config @@ -112,6 +112,7 @@ func InitCmd(mbm module.BasicManager, defaultNodeHome string) *cobra.Command { if !overwrite && ostos.FileExists(genFile) { return fmt.Errorf("genesis.json file already exists: %v", genFile) } + appState, err := json.MarshalIndent(mbm.DefaultGenesis(cdc), "", " ") if err != nil { return errors.Wrap(err, "Failed to marshall default genesis state") @@ -132,6 +133,7 @@ func InitCmd(mbm module.BasicManager, defaultNodeHome string) *cobra.Command { genDoc.ChainID = chainID genDoc.Validators = nil genDoc.AppState = appState + if err = genutil.ExportGenesisFile(genDoc, genFile); err != nil { return errors.Wrap(err, "Failed to export gensis file") } diff --git a/x/genutil/client/cli/init_test.go b/x/genutil/client/cli/init_test.go index ade835702a..80324cb868 100644 --- a/x/genutil/client/cli/init_test.go +++ b/x/genutil/client/cli/init_test.go @@ -49,8 +49,7 @@ func TestInitCmd(t *testing.T) { } }, shouldErr: false, - - err: nil, + err: nil, }, } @@ -66,7 +65,7 @@ func TestInitCmd(t *testing.T) { interfaceRegistry := types.NewInterfaceRegistry() marshaler := codec.NewProtoCodec(interfaceRegistry) clientCtx := client.Context{}. - WithJSONMarshaler(marshaler). + WithCodec(marshaler). WithLegacyAmino(makeCodec()). WithHomeDir(home) @@ -100,7 +99,7 @@ func TestInitRecover(t *testing.T) { interfaceRegistry := types.NewInterfaceRegistry() marshaler := codec.NewProtoCodec(interfaceRegistry) clientCtx := client.Context{}. - WithJSONMarshaler(marshaler). + WithCodec(marshaler). WithLegacyAmino(makeCodec()). WithHomeDir(home) @@ -131,7 +130,7 @@ func TestEmptyState(t *testing.T) { interfaceRegistry := types.NewInterfaceRegistry() marshaler := codec.NewProtoCodec(interfaceRegistry) clientCtx := client.Context{}. - WithJSONMarshaler(marshaler). + WithCodec(marshaler). WithLegacyAmino(makeCodec()). WithHomeDir(home) diff --git a/x/genutil/client/cli/validate_genesis.go b/x/genutil/client/cli/validate_genesis.go index 926acb1f2e..9d7aca4a17 100644 --- a/x/genutil/client/cli/validate_genesis.go +++ b/x/genutil/client/cli/validate_genesis.go @@ -24,7 +24,7 @@ func ValidateGenesisCmd(mbm module.BasicManager) *cobra.Command { serverCtx := server.GetServerContextFromCmd(cmd) clientCtx := client.GetClientContextFromCmd(cmd) - cdc := clientCtx.JSONMarshaler + cdc := clientCtx.Codec // Load default if passed no args, otherwise load passed file var genesis string diff --git a/x/genutil/client/rest/query.go b/x/genutil/client/rest/query.go index 66a0a796cb..a8ab1a44ab 100644 --- a/x/genutil/client/rest/query.go +++ b/x/genutil/client/rest/query.go @@ -32,7 +32,7 @@ func QueryGenesisTxs(clientCtx client.Context, w http.ResponseWriter) { return } - genState := types.GetGenesisStateFromAppState(clientCtx.JSONMarshaler, appState) + genState := types.GetGenesisStateFromAppState(clientCtx.Codec, appState) genTxs := make([]sdk.Tx, len(genState.GenTxs)) for i, tx := range genState.GenTxs { err := clientCtx.LegacyAmino.UnmarshalJSON(tx, &genTxs[i]) diff --git a/x/genutil/client/testutil/cli_test.go b/x/genutil/client/testutil/cli_test.go new file mode 100644 index 0000000000..8ded31fefa --- /dev/null +++ b/x/genutil/client/testutil/cli_test.go @@ -0,0 +1,18 @@ +//go:build norace +// +build norace + +package testutil + +import ( + "testing" + + "github.com/line/lbm-sdk/testutil/network" + + "github.com/stretchr/testify/suite" +) + +func TestIntegrationTestSuite(t *testing.T) { + cfg := network.DefaultConfig() + cfg.NumValidators = 1 + suite.Run(t, NewIntegrationTestSuite(cfg)) +} diff --git a/x/genutil/client/testutil/helpers.go b/x/genutil/client/testutil/helpers.go index 57bd16b27c..662d2d8891 100644 --- a/x/genutil/client/testutil/helpers.go +++ b/x/genutil/client/testutil/helpers.go @@ -17,7 +17,7 @@ import ( genutilcli "github.com/line/lbm-sdk/x/genutil/client/cli" ) -func ExecInitCmd(testMbm module.BasicManager, home string, cdc codec.JSONMarshaler) error { +func ExecInitCmd(testMbm module.BasicManager, home string, cdc codec.Codec) error { logger := log.NewNopLogger() cfg, err := CreateDefaultTendermintConfig(home) if err != nil { @@ -26,7 +26,7 @@ func ExecInitCmd(testMbm module.BasicManager, home string, cdc codec.JSONMarshal cmd := genutilcli.InitCmd(testMbm, home) serverCtx := server.NewContext(viper.New(), cfg, logger) - clientCtx := client.Context{}.WithJSONMarshaler(cdc).WithHomeDir(home) + clientCtx := client.Context{}.WithCodec(cdc).WithHomeDir(home) _, out := testutil.ApplyMockIO(cmd) clientCtx = clientCtx.WithOutput(out) diff --git a/x/genutil/client/testutil/migrate.go b/x/genutil/client/testutil/migrate.go index b7fec4f04c..a7d830f7eb 100644 --- a/x/genutil/client/testutil/migrate.go +++ b/x/genutil/client/testutil/migrate.go @@ -10,66 +10,6 @@ import ( "github.com/line/lbm-sdk/x/genutil/client/cli" ) -// An example exported genesis file from a 0.37 chain. Note that evidence -// parameters only contains `max_age`. -var v037Exported = `{ - "app_hash": "", - "app_state": {}, - "chain_id": "test", - "consensus_params": { - "block": { - "max_bytes": "22020096", - "max_gas": "-1", - "time_iota_ms": "1000" - }, - "evidence": { "max_age": "100000" }, - "validator": { "pub_key_types": ["ed25519"] } - }, - "genesis_time": "2020-09-29T20:16:29.172362037Z", - "validators": [] -}` - -// An example exported genesis file that's 0.40 compatible. -// We added the following app_state: -// -// - x/gov: added votes to test ADR-037 split votes migration. -var v040Valid = `{ - "app_hash": "", - "app_state": { - "gov": { - "starting_proposal_id": "0", - "deposits": [], - "votes": [ - { - "proposal_id": "5", - "voter": "cosmos1fl48vsnmsdzcv85q5d2q4z5ajdha8yu34mf0eh", - "option": "VOTE_OPTION_YES" - } - ], - "proposals": [], - "deposit_params": { "min_deposit": [], "max_deposit_period": "0s" }, - "voting_params": { "voting_period": "0s" }, - "tally_params": { "quorum": "0", "threshold": "0", "veto_threshold": "0" } - } - }, - "chain_id": "test", - "consensus_params": { - "block": { - "max_bytes": "22020096", - "max_gas": "-1", - "time_iota_ms": "1000" - }, - "evidence": { - "max_age_num_blocks": "100000", - "max_age_duration": "172800000000000", - "max_bytes": "0" - }, - "validator": { "pub_key_types": ["ed25519"] } - }, - "genesis_time": "2020-09-29T20:16:29.172362037Z", - "validators": [] -}` - func TestGetMigrationCallback(t *testing.T) { for _, version := range cli.GetMigrationVersions() { require.NotNil(t, cli.GetMigrationCallback(version)) @@ -86,24 +26,7 @@ func (s *IntegrationTestSuite) TestMigrateGenesis() { expErr bool expErrMsg string check func(jsonOut string) - }{ - { - "migrate 0.37 to 0.42", - v037Exported, - "v0.42", - true, "Make sure that you have correctly migrated all Tendermint consensus params", func(_ string) {}, - }, - { - "migrate 0.42 to 0.43", - v040Valid, - "v0.43", - false, "", - func(jsonOut string) { - // Make sure the json output contains the ADR-037 gov weighted votes. - s.Require().Contains(jsonOut, "\"weight\":\"1.000000000000000000\"") - }, - }, - } + }{} for _, tc := range testCases { tc := tc diff --git a/x/genutil/client/testutil/suite.go b/x/genutil/client/testutil/suite.go index ff74c65d84..d87006ce4f 100644 --- a/x/genutil/client/testutil/suite.go +++ b/x/genutil/client/testutil/suite.go @@ -125,7 +125,7 @@ func (s *IntegrationTestSuite) TestGenTxCmdPubkey() { cmd.SetArgs([]string{ fmt.Sprintf("--%s=%s", flags.FlagChainID, s.network.Config.ChainID), fmt.Sprintf("--%s=%s", flags.FlagOutputDocument, genTxFile), - fmt.Sprintf("--%s={\"@type\":\"/cosmos.crypto.ed25519.PubKey\",\"key\":\"BOIkjkFruMpfOFC9oNPhiJGfmY2pHF/gwHdLDLnrnS0=\"}", stakingcli.FlagPubKey), + fmt.Sprintf("--%s={\"@type\":\"/lbm.crypto.ed25519.PubKey\",\"key\":\"BOIkjkFruMpfOFC9oNPhiJGfmY2pHF/gwHdLDLnrnS0=\"}", stakingcli.FlagPubKey), val.Moniker, amount.String(), }) diff --git a/x/genutil/client/cli/validate_genesis_test.go b/x/genutil/client/testutil/validate_genesis.go similarity index 75% rename from x/genutil/client/cli/validate_genesis_test.go rename to x/genutil/client/testutil/validate_genesis.go index ab8b41b596..fa22f1dcd5 100644 --- a/x/genutil/client/cli/validate_genesis_test.go +++ b/x/genutil/client/testutil/validate_genesis.go @@ -1,4 +1,4 @@ -package cli_test +package testutil import ( "github.com/line/lbm-sdk/testutil" @@ -26,9 +26,28 @@ var v037Exported = `{ }` // An example exported genesis file that's 0.40 compatible. +// We added the following app_state: +// +// - x/gov: added votes to test ADR-037 split votes migration. var v040Valid = `{ "app_hash": "", - "app_state": {}, + "app_state": { + "gov": { + "starting_proposal_id": "0", + "deposits": [], + "votes": [ + { + "proposal_id": "5", + "voter": "link1fl48vsnmsdzcv85q5d2q4z5ajdha8yu34mf0eh", + "option": "VOTE_OPTION_YES" + } + ], + "proposals": [], + "deposit_params": { "min_deposit": [], "max_deposit_period": "0s" }, + "voting_params": { "voting_period": "0s" }, + "tally_params": { "quorum": "0", "threshold": "0", "veto_threshold": "0" } + } + }, "chain_id": "test", "consensus_params": { "block": { @@ -68,6 +87,7 @@ func (s *IntegrationTestSuite) TestValidateGenesis() { } for _, tc := range testCases { + tc := tc s.Run(tc.name, func() { genesisFile := testutil.WriteToNewTempFile(s.T(), tc.genesis) _, err := clitestutil.ExecTestCLICmd(val0.ClientCtx, cli.ValidateGenesisCmd(nil), []string{genesisFile.Name()}) diff --git a/x/genutil/collect.go b/x/genutil/collect.go index fabe70efba..4f1c513833 100644 --- a/x/genutil/collect.go +++ b/x/genutil/collect.go @@ -25,7 +25,7 @@ import ( ) // GenAppStateFromConfig gets the genesis app state from the config -func GenAppStateFromConfig(cdc codec.JSONMarshaler, txEncodingConfig client.TxEncodingConfig, +func GenAppStateFromConfig(cdc codec.JSONCodec, txEncodingConfig client.TxEncodingConfig, config *cfg.Config, initCfg types.InitConfig, genDoc octypes.GenesisDoc, genBalIterator types.GenesisBalancesIterator, ) (appState json.RawMessage, err error) { @@ -69,7 +69,7 @@ func GenAppStateFromConfig(cdc codec.JSONMarshaler, txEncodingConfig client.TxEn // CollectTxs processes and validates application's genesis Txs and returns // the list of appGenTxs, and persistent peers required to generate genesis.json. -func CollectTxs(cdc codec.JSONMarshaler, txJSONDecoder sdk.TxDecoder, moniker, genTxsDir string, +func CollectTxs(cdc codec.JSONCodec, txJSONDecoder sdk.TxDecoder, moniker, genTxsDir string, genDoc octypes.GenesisDoc, genBalIterator types.GenesisBalancesIterator, ) (appGenTxs []sdk.Tx, persistentPeers string, err error) { // prepare a map of all balances in genesis state to then validate @@ -134,9 +134,6 @@ func CollectTxs(cdc codec.JSONMarshaler, txJSONDecoder sdk.TxDecoder, moniker, g // genesis transactions must be single-message msgs := genTx.GetMsgs() - if len(msgs) != 1 { - return appGenTxs, persistentPeers, errors.New("each genesis transaction must provide a single genesis message") - } // TODO abstract out staking message validation back to staking msg := msgs[0].(*stakingtypes.MsgCreateValidator) diff --git a/x/genutil/collect_test.go b/x/genutil/collect_test.go index 69c739d92d..18d1ed7705 100644 --- a/x/genutil/collect_test.go +++ b/x/genutil/collect_test.go @@ -21,7 +21,7 @@ import ( ) type doNothingUnmarshalJSON struct { - codec.JSONMarshaler + codec.JSONCodec } func (dnj *doNothingUnmarshalJSON) UnmarshalJSON(_ []byte, _ proto.Message) error { @@ -32,7 +32,7 @@ type doNothingIterator struct { gtypes.GenesisBalancesIterator } -func (dni *doNothingIterator) IterateGenesisBalances(_ codec.JSONMarshaler, _ map[string]json.RawMessage, _ func(bankexported.GenesisBalance) bool) { +func (dni *doNothingIterator) IterateGenesisBalances(_ codec.JSONCodec, _ map[string]json.RawMessage, _ func(bankexported.GenesisBalance) bool) { } // Ensures that CollectTx correctly traverses directories and won't error out on encountering diff --git a/x/genutil/gentx.go b/x/genutil/gentx.go index 7593983fb2..fd4083a351 100644 --- a/x/genutil/gentx.go +++ b/x/genutil/gentx.go @@ -16,7 +16,7 @@ import ( // SetGenTxsInAppGenesisState - sets the genesis transactions in the app genesis state func SetGenTxsInAppGenesisState( - cdc codec.JSONMarshaler, txJSONEncoder sdk.TxEncoder, appGenesisState map[string]json.RawMessage, genTxs []sdk.Tx, + cdc codec.JSONCodec, txJSONEncoder sdk.TxEncoder, appGenesisState map[string]json.RawMessage, genTxs []sdk.Tx, ) (map[string]json.RawMessage, error) { genesisState := types.GetGenesisStateFromAppState(cdc, appGenesisState) @@ -39,7 +39,7 @@ func SetGenTxsInAppGenesisState( // balance in the set of genesis accounts. func ValidateAccountInGenesis( appGenesisState map[string]json.RawMessage, genBalIterator types.GenesisBalancesIterator, - addr sdk.Address, coins sdk.Coins, cdc codec.JSONMarshaler, + addr sdk.Address, coins sdk.Coins, cdc codec.JSONCodec, ) error { var stakingData stakingtypes.GenesisState diff --git a/x/genutil/gentx_test.go b/x/genutil/gentx_test.go index dd6c19d5b4..5824dbed19 100644 --- a/x/genutil/gentx_test.go +++ b/x/genutil/gentx_test.go @@ -64,9 +64,7 @@ func (suite *GenTxTestSuite) setAccountBalance(addr sdk.AccAddress, amount int64 acc := suite.app.AccountKeeper.NewAccountWithAddress(suite.ctx, addr) suite.app.AccountKeeper.SetAccount(suite.ctx, acc) - err := suite.app.BankKeeper.SetBalances( - suite.ctx, addr, sdk.Coins{sdk.NewInt64Coin(sdk.DefaultBondDenom, 25)}, - ) + err := simapp.FundAccount(suite.app, suite.ctx, addr, sdk.Coins{sdk.NewInt64Coin(sdk.DefaultBondDenom, 25)}) suite.Require().NoError(err) bankGenesisState := suite.app.BankKeeper.ExportGenesis(suite.ctx) diff --git a/x/genutil/legacy/v043/migrate.go b/x/genutil/legacy/v043/migrate.go new file mode 100644 index 0000000000..7f7fabdc73 --- /dev/null +++ b/x/genutil/legacy/v043/migrate.go @@ -0,0 +1,44 @@ +package v043 + +import ( + "github.com/line/lbm-sdk/client" + v040bank "github.com/line/lbm-sdk/x/bank/legacy/v040" + v043bank "github.com/line/lbm-sdk/x/bank/legacy/v043" + bank "github.com/line/lbm-sdk/x/bank/types" + "github.com/line/lbm-sdk/x/genutil/types" + v040gov "github.com/line/lbm-sdk/x/gov/legacy/v040" + v043gov "github.com/line/lbm-sdk/x/gov/legacy/v043" + gov "github.com/line/lbm-sdk/x/gov/types" +) + +// Migrate migrates exported state from v0.40 to a v0.43 genesis state. +func Migrate(appState types.AppMap, clientCtx client.Context) types.AppMap { + // Migrate x/gov. + if appState[v040gov.ModuleName] != nil { + // unmarshal relative source genesis application state + var oldGovState gov.GenesisState + clientCtx.Codec.MustUnmarshalJSON(appState[v040gov.ModuleName], &oldGovState) + + // delete deprecated x/gov genesis state + delete(appState, v040gov.ModuleName) + + // Migrate relative source genesis application state and marshal it into + // the respective key. + appState[v043gov.ModuleName] = clientCtx.Codec.MustMarshalJSON(v043gov.MigrateJSON(&oldGovState)) + } + + if appState[v040bank.ModuleName] != nil { + // unmarshal relative source genesis application state + var oldBankState bank.GenesisState + clientCtx.Codec.MustUnmarshalJSON(appState[v040bank.ModuleName], &oldBankState) + + // delete deprecated x/bank genesis state + delete(appState, v040bank.ModuleName) + + // Migrate relative source genesis application state and marshal it into + // the respective key. + appState[v043bank.ModuleName] = clientCtx.Codec.MustMarshalJSON(v043bank.MigrateJSON(&oldBankState)) + } + + return appState +} diff --git a/x/genutil/module.go b/x/genutil/module.go index 8cb1c909d8..17e6bc9ccc 100644 --- a/x/genutil/module.go +++ b/x/genutil/module.go @@ -39,12 +39,12 @@ func (b AppModuleBasic) RegisterInterfaces(_ cdctypes.InterfaceRegistry) {} // DefaultGenesis returns default genesis state as raw bytes for the genutil // module. -func (AppModuleBasic) DefaultGenesis(cdc codec.JSONMarshaler) json.RawMessage { +func (AppModuleBasic) DefaultGenesis(cdc codec.JSONCodec) json.RawMessage { return cdc.MustMarshalJSON(types.DefaultGenesisState()) } // ValidateGenesis performs genesis state validation for the genutil module. -func (b AppModuleBasic) ValidateGenesis(cdc codec.JSONMarshaler, txEncodingConfig client.TxEncodingConfig, bz json.RawMessage) error { +func (b AppModuleBasic) ValidateGenesis(cdc codec.JSONCodec, txEncodingConfig client.TxEncodingConfig, bz json.RawMessage) error { var data types.GenesisState if err := cdc.UnmarshalJSON(bz, &data); err != nil { return fmt.Errorf("failed to unmarshal %s genesis state: %w", types.ModuleName, err) @@ -66,8 +66,6 @@ func (AppModuleBasic) GetTxCmd() *cobra.Command { return nil } // GetQueryCmd returns no root query command for the genutil module. func (AppModuleBasic) GetQueryCmd() *cobra.Command { return nil } -// ____________________________________________________________________________ - // AppModule implements an application module for the genutil module. type AppModule struct { AppModuleBasic @@ -95,7 +93,7 @@ func NewAppModule(accountKeeper types.AccountKeeper, // InitGenesis performs genesis initialization for the genutil module. It returns // no validator updates. -func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONMarshaler, data json.RawMessage) []abci.ValidatorUpdate { +func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONCodec, data json.RawMessage) []abci.ValidatorUpdate { var genesisState types.GenesisState cdc.MustUnmarshalJSON(data, &genesisState) validators, err := InitGenesis(ctx, am.stakingKeeper, am.deliverTx, genesisState, am.txEncodingConfig) @@ -107,7 +105,7 @@ func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONMarshaler, data j // ExportGenesis returns the exported genesis state as raw bytes for the genutil // module. -func (am AppModule) ExportGenesis(_ sdk.Context, cdc codec.JSONMarshaler) json.RawMessage { +func (am AppModule) ExportGenesis(_ sdk.Context, cdc codec.JSONCodec) json.RawMessage { return am.DefaultGenesis(cdc) } diff --git a/x/genutil/types/expected_keepers.go b/x/genutil/types/expected_keepers.go index 94f1745fb3..a99c7b5519 100644 --- a/x/genutil/types/expected_keepers.go +++ b/x/genutil/types/expected_keepers.go @@ -35,7 +35,7 @@ type GenesisAccountsIterator interface { // GenesisAccountsIterator defines the expected iterating genesis accounts object (noalias) type GenesisBalancesIterator interface { IterateGenesisBalances( - cdc codec.JSONMarshaler, + cdc codec.JSONCodec, appGenesis map[string]json.RawMessage, cb func(bankexported.GenesisBalance) (stop bool), ) diff --git a/x/genutil/types/genesis_state.go b/x/genutil/types/genesis_state.go index 8d3181ebdf..c1a982ed7f 100644 --- a/x/genutil/types/genesis_state.go +++ b/x/genutil/types/genesis_state.go @@ -46,7 +46,7 @@ func NewGenesisStateFromTx(txJSONEncoder sdk.TxEncoder, genTxs []sdk.Tx) *Genesi } // GetGenesisStateFromAppState gets the genutil genesis state from the expected app state -func GetGenesisStateFromAppState(cdc codec.JSONMarshaler, appState map[string]json.RawMessage) *GenesisState { +func GetGenesisStateFromAppState(cdc codec.JSONCodec, appState map[string]json.RawMessage) *GenesisState { var genesisState GenesisState if appState[ModuleName] != nil { cdc.MustUnmarshalJSON(appState[ModuleName], &genesisState) @@ -56,7 +56,7 @@ func GetGenesisStateFromAppState(cdc codec.JSONMarshaler, appState map[string]js // SetGenesisStateInAppState sets the genutil genesis state within the expected app state func SetGenesisStateInAppState( - cdc codec.JSONMarshaler, appState map[string]json.RawMessage, genesisState *GenesisState, + cdc codec.JSONCodec, appState map[string]json.RawMessage, genesisState *GenesisState, ) map[string]json.RawMessage { genesisStateBz := cdc.MustMarshalJSON(genesisState) diff --git a/x/gov/abci.go b/x/gov/abci.go index 7a4386eb02..fed62802a7 100644 --- a/x/gov/abci.go +++ b/x/gov/abci.go @@ -21,6 +21,9 @@ func EndBlocker(ctx sdk.Context, keeper keeper.Keeper) { keeper.DeleteProposal(ctx, proposal.ProposalId) keeper.DeleteDeposits(ctx, proposal.ProposalId) + // called when proposal become inactive + keeper.AfterProposalFailedMinDeposit(ctx, proposal.ProposalId) + ctx.EventManager().EmitEvent( sdk.NewEvent( types.EventTypeInactiveProposal, @@ -89,6 +92,9 @@ func EndBlocker(ctx sdk.Context, keeper keeper.Keeper) { keeper.SetProposal(ctx, proposal) keeper.RemoveFromActiveProposalQueue(ctx, proposal.ProposalId, proposal.VotingEndTime) + // when proposal become active + keeper.AfterProposalVotingPeriodEnded(ctx, proposal.ProposalId) + logger.Info( "proposal tallied", "proposal", proposal.ProposalId, diff --git a/x/gov/abci_test.go b/x/gov/abci_test.go index 8d352798d3..da203bbdc5 100644 --- a/x/gov/abci_test.go +++ b/x/gov/abci_test.go @@ -221,7 +221,7 @@ func TestTickPassedVotingPeriod(t *testing.T) { require.False(t, activeQueue.Valid()) activeQueue.Close() - proposalCoins := sdk.Coins{sdk.NewCoin(sdk.DefaultBondDenom, sdk.TokensFromConsensusPower(5))} + proposalCoins := sdk.Coins{sdk.NewCoin(sdk.DefaultBondDenom, app.StakingKeeper.TokensFromConsensusPower(ctx, 5))} newProposalMsg, err := types.NewMsgSubmitProposal(TestProposal, proposalCoins, addrs[0]) require.NoError(t, err) @@ -295,7 +295,7 @@ func TestProposalPassedEndblocker(t *testing.T) { proposal, err := app.GovKeeper.SubmitProposal(ctx, TestProposal) require.NoError(t, err) - proposalCoins := sdk.Coins{sdk.NewCoin(sdk.DefaultBondDenom, sdk.TokensFromConsensusPower(10))} + proposalCoins := sdk.Coins{sdk.NewCoin(sdk.DefaultBondDenom, app.StakingKeeper.TokensFromConsensusPower(ctx, 10))} newDepositMsg := types.NewMsgDeposit(addrs[0], proposal.ProposalId, proposalCoins) handleAndCheck(t, handler, ctx, newDepositMsg) @@ -343,7 +343,7 @@ func TestEndBlockerProposalHandlerFailed(t *testing.T) { proposal, err := app.GovKeeper.SubmitProposal(ctx, TestProposal) require.NoError(t, err) - proposalCoins := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.TokensFromConsensusPower(10))) + proposalCoins := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, app.StakingKeeper.TokensFromConsensusPower(ctx, 10))) newDepositMsg := types.NewMsgDeposit(addrs[0], proposal.ProposalId, proposalCoins) handleAndCheck(t, gov.NewHandler(app.GovKeeper), ctx, newDepositMsg) diff --git a/x/gov/client/cli/parse.go b/x/gov/client/cli/parse.go index e861517804..a1ee463699 100644 --- a/x/gov/client/cli/parse.go +++ b/x/gov/client/cli/parse.go @@ -10,17 +10,41 @@ import ( govutils "github.com/line/lbm-sdk/x/gov/client/utils" ) +func (p proposal) validate() error { + if p.Type == "" { + return fmt.Errorf("proposal type is required") + } + + if p.Title == "" { + return fmt.Errorf("proposal title is required") + } + + if p.Description == "" { + return fmt.Errorf("proposal description is required") + } + return nil +} + func parseSubmitProposalFlags(fs *pflag.FlagSet) (*proposal, error) { proposal := &proposal{} proposalFile, _ := fs.GetString(FlagProposal) if proposalFile == "" { proposalType, _ := fs.GetString(FlagProposalType) + title, _ := fs.GetString(FlagTitle) + description, _ := fs.GetString(FlagDescription) + if proposalType == "" && title == "" && description == "" { + return nil, fmt.Errorf("one of the --proposal or (--title, --description and --type) flags are required") + } proposal.Title, _ = fs.GetString(FlagTitle) proposal.Description, _ = fs.GetString(FlagDescription) proposal.Type = govutils.NormalizeProposalType(proposalType) proposal.Deposit, _ = fs.GetString(FlagDeposit) + if err := proposal.validate(); err != nil { + return nil, err + } + return proposal, nil } diff --git a/x/gov/client/cli/query.go b/x/gov/client/cli/query.go index ae4c95bdcc..e36621a482 100644 --- a/x/gov/client/cli/query.go +++ b/x/gov/client/cli/query.go @@ -1,7 +1,6 @@ package cli import ( - "context" "fmt" "strconv" "strings" @@ -74,7 +73,7 @@ $ %s query gov proposal 1 // Query the proposal res, err := queryClient.Proposal( - context.Background(), + cmd.Context(), &types.QueryProposalRequest{ProposalId: proposalID}, ) if err != nil { @@ -100,8 +99,8 @@ func GetCmdQueryProposals() *cobra.Command { fmt.Sprintf(`Query for a all paginated proposals that match optional filters: Example: -$ %s query gov proposals --depositor cosmos1skjwj5whet0lpe65qaq4rpq03hjxlwd9nf39lk -$ %s query gov proposals --voter cosmos1skjwj5whet0lpe65qaq4rpq03hjxlwd9nf39lk +$ %s query gov proposals --depositor link1skjwj5whet0lpe65qaq4rpq03hjxlwd9nf39lk +$ %s query gov proposals --voter link1skjwj5whet0lpe65qaq4rpq03hjxlwd9nf39lk $ %s query gov proposals --status (DepositPeriod|VotingPeriod|Passed|Rejected) $ %s query gov proposals --page=2 --limit=100 `, @@ -135,7 +134,7 @@ $ %s query gov proposals --page=2 --limit=100 } res, err := queryClient.Proposals( - context.Background(), + cmd.Context(), &types.QueryProposalsRequest{ ProposalStatus: proposalStatus, Voter: bechVoterAddr, @@ -175,7 +174,7 @@ func GetCmdQueryVote() *cobra.Command { fmt.Sprintf(`Query details for a single vote on a proposal given its identifier. Example: -$ %s query gov vote 1 cosmos1skjwj5whet0lpe65qaq4rpq03hjxlwd9nf39lk +$ %s query gov vote 1 link1skjwj5whet0lpe65qaq4rpq03hjxlwd9nf39lk `, version.AppName, ), @@ -194,8 +193,9 @@ $ %s query gov vote 1 cosmos1skjwj5whet0lpe65qaq4rpq03hjxlwd9nf39lk } // check to see if the proposal is in the store + ctx := cmd.Context() _, err = queryClient.Proposal( - context.Background(), + ctx, &types.QueryProposalRequest{ProposalId: proposalID}, ) if err != nil { @@ -205,7 +205,7 @@ $ %s query gov vote 1 cosmos1skjwj5whet0lpe65qaq4rpq03hjxlwd9nf39lk voterAddr := sdk.AccAddress(args[1]) res, err := queryClient.Vote( - context.Background(), + ctx, &types.QueryVoteRequest{ProposalId: proposalID, Voter: args[1]}, ) if err != nil { @@ -221,7 +221,7 @@ $ %s query gov vote 1 cosmos1skjwj5whet0lpe65qaq4rpq03hjxlwd9nf39lk return err } - if err := clientCtx.JSONMarshaler.UnmarshalJSON(resByTxQuery, &vote); err != nil { + if err := clientCtx.Codec.UnmarshalJSON(resByTxQuery, &vote); err != nil { return err } } @@ -265,8 +265,9 @@ $ %[1]s query gov votes 1 --page=2 --limit=100 } // check to see if the proposal is in the store + ctx := cmd.Context() proposalRes, err := queryClient.Proposal( - context.Background(), + ctx, &types.QueryProposalRequest{ProposalId: proposalID}, ) if err != nil { @@ -285,7 +286,7 @@ $ %[1]s query gov votes 1 --page=2 --limit=100 } var votes types.Votes - // TODO migrate to use JSONMarshaler (implement MarshalJSONArray + // TODO migrate to use JSONCodec (implement MarshalJSONArray // or wrap lists of proto.Message in some other message) clientCtx.LegacyAmino.MustUnmarshalJSON(resByTxQuery, &votes) return clientCtx.PrintObjectLegacy(votes) @@ -298,7 +299,7 @@ $ %[1]s query gov votes 1 --page=2 --limit=100 } res, err := queryClient.Votes( - context.Background(), + ctx, &types.QueryVotesRequest{ProposalId: proposalID, Pagination: pageReq}, ) @@ -328,7 +329,7 @@ func GetCmdQueryDeposit() *cobra.Command { fmt.Sprintf(`Query details for a single proposal deposit on a proposal by its identifier. Example: -$ %s query gov deposit 1 cosmos1skjwj5whet0lpe65qaq4rpq03hjxlwd9nf39lk +$ %s query gov deposit 1 link1skjwj5whet0lpe65qaq4rpq03hjxlwd9nf39lk `, version.AppName, ), @@ -366,7 +367,7 @@ $ %s query gov deposit 1 cosmos1skjwj5whet0lpe65qaq4rpq03hjxlwd9nf39lk if err != nil { return err } - clientCtx.JSONMarshaler.MustUnmarshalJSON(resByTxQuery, &deposit) + clientCtx.Codec.MustUnmarshalJSON(resByTxQuery, &deposit) return clientCtx.PrintProto(&deposit) } @@ -417,8 +418,9 @@ $ %s query gov deposits 1 } // check to see if the proposal is in the store + ctx := cmd.Context() proposalRes, err := queryClient.Proposal( - context.Background(), + ctx, &types.QueryProposalRequest{ProposalId: proposalID}, ) if err != nil { @@ -434,7 +436,7 @@ $ %s query gov deposits 1 } var dep types.Deposits - // TODO migrate to use JSONMarshaler (implement MarshalJSONArray + // TODO migrate to use JSONCodec (implement MarshalJSONArray // or wrap lists of proto.Message in some other message) clientCtx.LegacyAmino.MustUnmarshalJSON(resByTxQuery, &dep) @@ -447,7 +449,7 @@ $ %s query gov deposits 1 } res, err := queryClient.Deposits( - context.Background(), + ctx, &types.QueryDepositsRequest{ProposalId: proposalID, Pagination: pageReq}, ) @@ -495,8 +497,9 @@ $ %s query gov tally 1 } // check to see if the proposal is in the store + ctx := cmd.Context() _, err = queryClient.Proposal( - context.Background(), + ctx, &types.QueryProposalRequest{ProposalId: proposalID}, ) if err != nil { @@ -505,7 +508,7 @@ $ %s query gov tally 1 // Query store res, err := queryClient.TallyResult( - context.Background(), + ctx, &types.QueryTallyResultRequest{ProposalId: proposalID}, ) if err != nil { @@ -544,8 +547,9 @@ $ %s query gov params queryClient := types.NewQueryClient(clientCtx) // Query store for all 3 params + ctx := cmd.Context() votingRes, err := queryClient.Params( - context.Background(), + ctx, &types.QueryParamsRequest{ParamsType: "voting"}, ) if err != nil { @@ -553,7 +557,7 @@ $ %s query gov params } tallyRes, err := queryClient.Params( - context.Background(), + ctx, &types.QueryParamsRequest{ParamsType: "tallying"}, ) if err != nil { @@ -561,7 +565,7 @@ $ %s query gov params } depositRes, err := queryClient.Params( - context.Background(), + ctx, &types.QueryParamsRequest{ParamsType: "deposit"}, ) if err != nil { @@ -609,7 +613,7 @@ $ %s query gov param deposit // Query store res, err := queryClient.Params( - context.Background(), + cmd.Context(), &types.QueryParamsRequest{ParamsType: args[0]}, ) if err != nil { diff --git a/x/gov/client/cli/tx.go b/x/gov/client/cli/tx.go index 030615f0e8..5c2b3a8d1e 100644 --- a/x/gov/client/cli/tx.go +++ b/x/gov/client/cli/tx.go @@ -126,10 +126,6 @@ $ %s tx gov submit-proposal --title="Test Proposal" --description="My awesome pr return fmt.Errorf("invalid message: %w", err) } - if err = msg.ValidateBasic(); err != nil { - return fmt.Errorf("message validation failed: %w", err) - } - return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) }, } @@ -182,10 +178,6 @@ $ %s tx gov deposit 1 10stake --from mykey } msg := types.NewMsgDeposit(from, proposalID, amount) - err = msg.ValidateBasic() - if err != nil { - return err - } return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) }, @@ -206,7 +198,6 @@ func NewCmdVote() *cobra.Command { fmt.Sprintf(`Submit a vote for an active proposal. You can find the proposal-id by running "%s query gov proposals". - Example: $ %s tx gov vote 1 yes --from mykey `, @@ -235,10 +226,6 @@ $ %s tx gov vote 1 yes --from mykey // Build vote message and run basic validation msg := types.NewMsgVote(from, proposalID, byteVoteOption) - err = msg.ValidateBasic() - if err != nil { - return err - } return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) }, diff --git a/x/gov/client/rest/grpc_query_test.go b/x/gov/client/rest/grpc_query_test.go index ace6c285f0..b424d932ae 100644 --- a/x/gov/client/rest/grpc_query_test.go +++ b/x/gov/client/rest/grpc_query_test.go @@ -101,7 +101,7 @@ func (s *IntegrationTestSuite) TestGetProposalGRPC() { s.Require().NoError(err) var proposal types.QueryProposalResponse - err = val.ClientCtx.JSONMarshaler.UnmarshalJSON(resp, &proposal) + err = val.ClientCtx.Codec.UnmarshalJSON(resp, &proposal) if tc.expErr { s.Require().Error(err) @@ -155,7 +155,7 @@ func (s *IntegrationTestSuite) TestGetProposalsGRPC() { s.Require().NoError(err) var proposals types.QueryProposalsResponse - err = val.ClientCtx.JSONMarshaler.UnmarshalJSON(resp, &proposals) + err = val.ClientCtx.Codec.UnmarshalJSON(resp, &proposals) if tc.expErr { s.Require().Empty(proposals.Proposals) @@ -222,7 +222,7 @@ func (s *IntegrationTestSuite) TestGetProposalVoteGRPC() { s.Require().NoError(err) var vote types.QueryVoteResponse - err = val.ClientCtx.JSONMarshaler.UnmarshalJSON(resp, &vote) + err = val.ClientCtx.Codec.UnmarshalJSON(resp, &vote) if tc.expErr { s.Require().Error(err) @@ -266,7 +266,7 @@ func (s *IntegrationTestSuite) TestGetProposalVotesGRPC() { s.Require().NoError(err) var votes types.QueryVotesResponse - err = val.ClientCtx.JSONMarshaler.UnmarshalJSON(resp, &votes) + err = val.ClientCtx.Codec.UnmarshalJSON(resp, &votes) if tc.expErr { s.Require().Error(err) @@ -315,7 +315,7 @@ func (s *IntegrationTestSuite) TestGetProposalDepositGRPC() { s.Require().NoError(err) var deposit types.QueryDepositResponse - err = val.ClientCtx.JSONMarshaler.UnmarshalJSON(resp, &deposit) + err = val.ClientCtx.Codec.UnmarshalJSON(resp, &deposit) if tc.expErr { s.Require().Error(err) @@ -354,7 +354,7 @@ func (s *IntegrationTestSuite) TestGetProposalDepositsGRPC() { s.Require().NoError(err) var deposits types.QueryDepositsResponse - err = val.ClientCtx.JSONMarshaler.UnmarshalJSON(resp, &deposits) + err = val.ClientCtx.Codec.UnmarshalJSON(resp, &deposits) if tc.expErr { s.Require().Error(err) @@ -399,7 +399,7 @@ func (s *IntegrationTestSuite) TestGetTallyGRPC() { s.Require().NoError(err) var tally types.QueryTallyResultResponse - err = val.ClientCtx.JSONMarshaler.UnmarshalJSON(resp, &tally) + err = val.ClientCtx.Codec.UnmarshalJSON(resp, &tally) if tc.expErr { s.Require().Error(err) @@ -461,7 +461,7 @@ func (s *IntegrationTestSuite) TestGetParamsGRPC() { resp, err := rest.GetRequest(tc.url) s.Require().NoError(err) - err = val.ClientCtx.JSONMarshaler.UnmarshalJSON(resp, tc.respType) + err = val.ClientCtx.Codec.UnmarshalJSON(resp, tc.respType) if tc.expErr { s.Require().Error(err) diff --git a/x/gov/client/rest/rest_test.go b/x/gov/client/rest/rest_test.go index 5fb15a2f34..d893701634 100644 --- a/x/gov/client/rest/rest_test.go +++ b/x/gov/client/rest/rest_test.go @@ -1,3 +1,6 @@ +//go:build norace +// +build norace + package rest_test import ( diff --git a/x/gov/client/testutil/cli_test.go b/x/gov/client/testutil/cli_test.go index 87c4f14d57..0749c99f98 100644 --- a/x/gov/client/testutil/cli_test.go +++ b/x/gov/client/testutil/cli_test.go @@ -1,3 +1,4 @@ +//go:build norace // +build norace package testutil @@ -6,17 +7,19 @@ import ( "testing" "time" + "github.com/stretchr/testify/require" + "github.com/stretchr/testify/suite" + "github.com/line/lbm-sdk/testutil/network" sdk "github.com/line/lbm-sdk/types" "github.com/line/lbm-sdk/x/gov/types" - - "github.com/stretchr/testify/require" - "github.com/stretchr/testify/suite" ) func TestIntegrationTestSuite(t *testing.T) { cfg := network.DefaultConfig() cfg.NumValidators = 1 + suite.Run(t, NewIntegrationTestSuite(cfg)) + genesisState := types.DefaultGenesisState() genesisState.DepositParams = types.NewDepositParams(sdk.NewCoins(sdk.NewCoin(cfg.BondDenom, types.DefaultMinDepositTokens)), time.Duration(15)*time.Second) genesisState.VotingParams = types.NewVotingParams(time.Duration(5) * time.Second) diff --git a/x/gov/client/testutil/deposits.go b/x/gov/client/testutil/deposits.go index 4c92af2ea4..3c2fdf4e32 100644 --- a/x/gov/client/testutil/deposits.go +++ b/x/gov/client/testutil/deposits.go @@ -4,9 +4,10 @@ import ( "fmt" "time" - ostcli "github.com/line/ostracon/libs/cli" "github.com/stretchr/testify/suite" + ostcli "github.com/line/ostracon/libs/cli" + clitestutil "github.com/line/lbm-sdk/testutil/cli" "github.com/line/lbm-sdk/testutil/network" sdk "github.com/line/lbm-sdk/types" diff --git a/x/gov/client/cli/cli_test.go b/x/gov/client/testutil/suite.go similarity index 80% rename from x/gov/client/cli/cli_test.go rename to x/gov/client/testutil/suite.go index ba6fd6a3f2..a1162a2e56 100644 --- a/x/gov/client/cli/cli_test.go +++ b/x/gov/client/testutil/suite.go @@ -1,26 +1,20 @@ -//go:build norace -// +build norace - -package cli_test +package testutil import ( "fmt" "strings" - "testing" "github.com/gogo/protobuf/proto" "github.com/stretchr/testify/suite" - "github.com/line/lbm-sdk/testutil" - ostcli "github.com/line/ostracon/libs/cli" "github.com/line/lbm-sdk/client/flags" + "github.com/line/lbm-sdk/testutil" clitestutil "github.com/line/lbm-sdk/testutil/cli" "github.com/line/lbm-sdk/testutil/network" sdk "github.com/line/lbm-sdk/types" "github.com/line/lbm-sdk/x/gov/client/cli" - govtestutil "github.com/line/lbm-sdk/x/gov/client/testutil" "github.com/line/lbm-sdk/x/gov/types" ) @@ -31,12 +25,13 @@ type IntegrationTestSuite struct { network *network.Network } +func NewIntegrationTestSuite(cfg network.Config) *IntegrationTestSuite { + return &IntegrationTestSuite{cfg: cfg} +} + func (s *IntegrationTestSuite) SetupSuite() { s.T().Log("setting up integration test suite") - s.cfg = network.DefaultConfig() - s.cfg.NumValidators = 1 - s.network = network.New(s.T(), s.cfg) _, err := s.network.WaitForHeight(1) @@ -45,7 +40,7 @@ func (s *IntegrationTestSuite) SetupSuite() { val := s.network.Validators[0] // create a proposal with deposit - _, err = govtestutil.MsgSubmitProposal(val.ClientCtx, val.Address.String(), + _, err = MsgSubmitProposal(val.ClientCtx, val.Address.String(), "Text Proposal 1", "Where is the title!?", types.ProposalTypeText, fmt.Sprintf("--%s=%s", cli.FlagDeposit, sdk.NewCoin(s.cfg.BondDenom, types.DefaultMinDepositTokens).String())) s.Require().NoError(err) @@ -53,18 +48,18 @@ func (s *IntegrationTestSuite) SetupSuite() { s.Require().NoError(err) // vote for proposal - _, err = govtestutil.MsgVote(val.ClientCtx, val.Address.String(), "1", "yes") + _, err = MsgVote(val.ClientCtx, val.Address.String(), "1", "yes") s.Require().NoError(err) // create a proposal without deposit - _, err = govtestutil.MsgSubmitProposal(val.ClientCtx, val.Address.String(), + _, err = MsgSubmitProposal(val.ClientCtx, val.Address.String(), "Text Proposal 2", "Where is the title!?", types.ProposalTypeText) s.Require().NoError(err) _, err = s.network.WaitForHeight(1) s.Require().NoError(err) // create a proposal3 with deposit - _, err = govtestutil.MsgSubmitProposal(val.ClientCtx, val.Address.String(), + _, err = MsgSubmitProposal(val.ClientCtx, val.Address.String(), "Text Proposal 3", "Where is the title!?", types.ProposalTypeText, fmt.Sprintf("--%s=%s", cli.FlagDeposit, sdk.NewCoin(s.cfg.BondDenom, types.DefaultMinDepositTokens).String())) s.Require().NoError(err) @@ -72,7 +67,7 @@ func (s *IntegrationTestSuite) SetupSuite() { s.Require().NoError(err) // vote for proposal3 as val - _, err = govtestutil.MsgVote(val.ClientCtx, val.Address.String(), "3", "yes=0.6,no=0.3,abstain=0.05,no_with_veto=0.05") + _, err = MsgVote(val.ClientCtx, val.Address.String(), "3", "yes=0.6,no=0.3,abstain=0.05,no_with_veto=0.05") s.Require().NoError(err) } @@ -270,7 +265,7 @@ func (s *IntegrationTestSuite) TestCmdTally() { s.Require().Error(err) } else { var tally types.TallyResult - s.Require().NoError(clientCtx.JSONMarshaler.UnmarshalJSON(out.Bytes(), &tally), out.String()) + s.Require().NoError(clientCtx.Codec.UnmarshalJSON(out.Bytes(), &tally), out.String()) s.Require().Equal(tally, tc.expectedOutput) } }) @@ -280,25 +275,25 @@ func (s *IntegrationTestSuite) TestCmdTally() { func (s *IntegrationTestSuite) TestNewCmdSubmitProposal() { val := s.network.Validators[0] invalidProp := `{ - "title": "", - "description": "Where is the title!?", - "type": "Text", - "deposit": "-324foocoin" -}` + "title": "", + "description": "Where is the title!?", + "type": "Text", + "deposit": "-324foocoin" + }` invalidPropFile := testutil.WriteToNewTempFile(s.T(), invalidProp) validProp := fmt.Sprintf(`{ - "title": "Text Proposal", - "description": "Hello, World!", - "type": "Text", - "deposit": "%s" -}`, sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(5431))) + "title": "Text Proposal", + "description": "Hello, World!", + "type": "Text", + "deposit": "%s" + }`, sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(5431))) validPropFile := testutil.WriteToNewTempFile(s.T(), validProp) testCases := []struct { name string args []string expectErr bool - respType proto.Message expectedCode uint32 + respType proto.Message }{ { "invalid proposal (file)", @@ -308,7 +303,7 @@ func (s *IntegrationTestSuite) TestNewCmdSubmitProposal() { fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), }, - true, nil, 0, + true, 0, nil, }, { "invalid proposal", @@ -320,7 +315,7 @@ func (s *IntegrationTestSuite) TestNewCmdSubmitProposal() { fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), }, - true, nil, 0, + true, 0, nil, }, { "valid transaction (file)", @@ -331,7 +326,7 @@ func (s *IntegrationTestSuite) TestNewCmdSubmitProposal() { fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), }, - false, &sdk.TxResponse{}, 0, + false, 0, &sdk.TxResponse{}, }, { "valid transaction", @@ -345,7 +340,7 @@ func (s *IntegrationTestSuite) TestNewCmdSubmitProposal() { fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), }, - false, &sdk.TxResponse{}, 0, + false, 0, &sdk.TxResponse{}, }, } @@ -361,7 +356,7 @@ func (s *IntegrationTestSuite) TestNewCmdSubmitProposal() { s.Require().Error(err) } else { s.Require().NoError(err) - s.Require().NoError(clientCtx.JSONMarshaler.UnmarshalJSON(out.Bytes(), tc.respType), out.String()) + s.Require().NoError(clientCtx.Codec.UnmarshalJSON(out.Bytes(), tc.respType), out.String()) txResp := tc.respType.(*sdk.TxResponse) s.Require().Equal(tc.expectedCode, txResp.Code, out.String()) } @@ -410,7 +405,7 @@ func (s *IntegrationTestSuite) TestCmdGetProposal() { } else { s.Require().NoError(err) var proposal types.Proposal - s.Require().NoError(clientCtx.JSONMarshaler.UnmarshalJSON(out.Bytes(), &proposal), out.String()) + s.Require().NoError(clientCtx.Codec.UnmarshalJSON(out.Bytes(), &proposal), out.String()) s.Require().Equal(title, proposal.GetTitle()) } }) @@ -456,7 +451,7 @@ func (s *IntegrationTestSuite) TestCmdGetProposals() { s.Require().NoError(err) var proposals types.QueryProposalsResponse - s.Require().NoError(clientCtx.JSONMarshaler.UnmarshalJSON(out.Bytes(), &proposals), out.String()) + s.Require().NoError(clientCtx.Codec.UnmarshalJSON(out.Bytes(), &proposals), out.String()) s.Require().Len(proposals.Proposals, 3) } }) @@ -502,7 +497,7 @@ func (s *IntegrationTestSuite) TestCmdQueryDeposits() { s.Require().NoError(err) var deposits types.QueryDepositsResponse - s.Require().NoError(clientCtx.JSONMarshaler.UnmarshalJSON(out.Bytes(), &deposits), out.String()) + s.Require().NoError(clientCtx.Codec.UnmarshalJSON(out.Bytes(), &deposits), out.String()) s.Require().Len(deposits.Deposits, 1) } }) @@ -558,7 +553,7 @@ func (s *IntegrationTestSuite) TestCmdQueryDeposit() { s.Require().NoError(err) var deposit types.Deposit - s.Require().NoError(clientCtx.JSONMarshaler.UnmarshalJSON(out.Bytes(), &deposit), out.String()) + s.Require().NoError(clientCtx.Codec.UnmarshalJSON(out.Bytes(), &deposit), out.String()) s.Require().Equal(depositAmount.String(), deposit.Amount.String()) } }) @@ -577,7 +572,7 @@ func (s *IntegrationTestSuite) TestNewCmdDeposit() { { "without proposal id", []string{ - sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10)).String(), //10stake + sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10)).String(), // 10stake fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()), fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), @@ -600,7 +595,7 @@ func (s *IntegrationTestSuite) TestNewCmdDeposit() { "deposit on non existing proposal", []string{ "10", - sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10)).String(), //10stake + sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10)).String(), // 10stake fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()), fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), @@ -612,7 +607,7 @@ func (s *IntegrationTestSuite) TestNewCmdDeposit() { "deposit on non existing proposal", []string{ "1", - sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10)).String(), //10stake + sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10)).String(), // 10stake fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()), fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), @@ -636,7 +631,7 @@ func (s *IntegrationTestSuite) TestNewCmdDeposit() { } else { s.Require().NoError(err) - s.Require().NoError(clientCtx.JSONMarshaler.UnmarshalJSON(out.Bytes(), &resp), out.String()) + s.Require().NoError(clientCtx.Codec.UnmarshalJSON(out.Bytes(), &resp), out.String()) s.Require().Equal(tc.expectedCode, resp.Code, out.String()) } }) @@ -687,7 +682,7 @@ func (s *IntegrationTestSuite) TestCmdQueryVotes() { s.Require().NoError(err) var votes types.QueryVotesResponse - s.Require().NoError(clientCtx.JSONMarshaler.UnmarshalJSON(out.Bytes(), &votes), out.String()) + s.Require().NoError(clientCtx.Codec.UnmarshalJSON(out.Bytes(), &votes), out.String()) s.Require().Len(votes.Votes, 1) } }) @@ -762,7 +757,7 @@ func (s *IntegrationTestSuite) TestCmdQueryVote() { s.Require().NoError(err) var vote types.Vote - s.Require().NoError(clientCtx.JSONMarshaler.UnmarshalJSON(out.Bytes(), &vote), out.String()) + s.Require().NoError(clientCtx.Codec.UnmarshalJSON(out.Bytes(), &vote), out.String()) s.Require().Equal(len(vote.Options), len(tc.expVoteOptions)) for i, option := range tc.expVoteOptions { s.Require().Equal(option.Option, vote.Options[i].Option) @@ -791,7 +786,7 @@ func (s *IntegrationTestSuite) TestNewCmdVote() { "vote for invalid proposal", []string{ "10", - fmt.Sprintf("%s", "yes"), + "yes", fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()), fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), @@ -803,7 +798,7 @@ func (s *IntegrationTestSuite) TestNewCmdVote() { "valid vote", []string{ "1", - fmt.Sprintf("%s", "yes"), + "yes", fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()), fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), @@ -826,13 +821,93 @@ func (s *IntegrationTestSuite) TestNewCmdVote() { s.Require().Error(err) } else { s.Require().NoError(err) - s.Require().NoError(clientCtx.JSONMarshaler.UnmarshalJSON(out.Bytes(), &txResp), out.String()) + s.Require().NoError(clientCtx.Codec.UnmarshalJSON(out.Bytes(), &txResp), out.String()) s.Require().Equal(tc.expectedCode, txResp.Code, out.String()) } }) } } -func TestIntegrationTestSuite(t *testing.T) { - suite.Run(t, new(IntegrationTestSuite)) +func (s *IntegrationTestSuite) TestNewCmdWeightedVote() { + val := s.network.Validators[0] + + testCases := []struct { + name string + args []string + expectErr bool + expectedCode uint32 + }{ + { + "invalid vote", + []string{}, + true, 0, + }, + { + "vote for invalid proposal", + []string{ + "10", + "yes", + fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()), + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), + fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), + }, + false, 2, + }, + { + "valid vote", + []string{ + "1", + "yes", + fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()), + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), + fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), + }, + false, 0, + }, + { + "invalid valid split vote string", + []string{ + "1", + "yes/0.6,no/0.3,abstain/0.05,no_with_veto/0.05", + fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()), + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), + fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), + }, + true, 0, + }, + { + "valid split vote", + []string{ + "1", + "yes=0.6,no=0.3,abstain=0.05,no_with_veto=0.05", + fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()), + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), + fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), + }, + false, 0, + }, + } + + for _, tc := range testCases { + tc := tc + s.Run(tc.name, func() { + cmd := cli.NewCmdWeightedVote() + clientCtx := val.ClientCtx + var txResp sdk.TxResponse + + out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, tc.args) + + if tc.expectErr { + s.Require().Error(err) + } else { + s.Require().NoError(err) + s.Require().NoError(clientCtx.Codec.UnmarshalJSON(out.Bytes(), &txResp), out.String()) + s.Require().Equal(tc.expectedCode, txResp.Code, out.String()) + } + }) + } } diff --git a/x/gov/client/utils/query.go b/x/gov/client/utils/query.go index d26eeb5b07..ce29a5242d 100644 --- a/x/gov/client/utils/query.go +++ b/x/gov/client/utils/query.go @@ -6,7 +6,7 @@ import ( "github.com/line/lbm-sdk/client" sdk "github.com/line/lbm-sdk/types" sdkerrors "github.com/line/lbm-sdk/types/errors" - authclient "github.com/line/lbm-sdk/x/auth/client" + authtx "github.com/line/lbm-sdk/x/auth/tx" "github.com/line/lbm-sdk/x/gov/types" ) @@ -50,23 +50,26 @@ func QueryDepositsByTxQuery(clientCtx client.Context, params types.QueryProposal deposits = append(deposits, initialDeposit) } - events := []string{ - fmt.Sprintf("%s.%s='%s'", sdk.EventTypeMessage, sdk.AttributeKeyAction, types.TypeMsgDeposit), - fmt.Sprintf("%s.%s='%s'", types.EventTypeProposalDeposit, types.AttributeKeyProposalID, []byte(fmt.Sprintf("%d", params.ProposalID))), - } - - // NOTE: SearchTxs is used to facilitate the txs query which does not currently - // support configurable pagination. - searchResult, err := authclient.QueryTxsByEvents(clientCtx, events, defaultPage, defaultLimit, "") + searchResult, err := combineEvents( + clientCtx, defaultPage, + // Query legacy Msgs event action + []string{ + fmt.Sprintf("%s.%s='%s'", sdk.EventTypeMessage, sdk.AttributeKeyAction, types.TypeMsgDeposit), + fmt.Sprintf("%s.%s='%s'", types.EventTypeProposalDeposit, types.AttributeKeyProposalID, []byte(fmt.Sprintf("%d", params.ProposalID))), + }, + // Query proto Msgs event action + []string{ + fmt.Sprintf("%s.%s='%s'", sdk.EventTypeMessage, sdk.AttributeKeyAction, sdk.MsgTypeURL(&types.MsgDeposit{})), + fmt.Sprintf("%s.%s='%s'", types.EventTypeProposalDeposit, types.AttributeKeyProposalID, []byte(fmt.Sprintf("%d", params.ProposalID))), + }, + ) if err != nil { return nil, err } for _, info := range searchResult.Txs { for _, msg := range info.GetTx().GetMsgs() { - if msg.Type() == types.TypeMsgDeposit { - depMsg := msg.(*types.MsgDeposit) - + if depMsg, ok := msg.(*types.MsgDeposit); ok { deposits = append(deposits, types.Deposit{ Depositor: depMsg.Depositor, ProposalId: params.ProposalID, @@ -84,28 +87,6 @@ func QueryDepositsByTxQuery(clientCtx client.Context, params types.QueryProposal return bz, nil } -// combineEvents queries txs by events with all events from each event group, -// and combines all those events together. -// -// Tx are indexed in tendermint via their Msgs `Type()`, which can be: -// - via legacy Msgs (amino or proto), their `Type()` is a custom string, -// - via ADR-031 proto msgs, their `Type()` is the protobuf FQ method name. -// In searching for events, we search for both `Type()`s, and we use the -// `combineEvents` function here to merge events. -func combineEvents(clientCtx client.Context, page int, eventGroups ...[]string) (*sdk.SearchTxsResult, error) { - // Only the Txs field will be populated in the final SearchTxsResult. - allTxs := []*sdk.TxResponse{} - for _, events := range eventGroups { - res, err := authclient.QueryTxsByEvents(clientCtx, events, page, defaultLimit, "") - if err != nil { - return nil, err - } - allTxs = append(allTxs, res.Txs...) - } - - return &sdk.SearchTxsResult{Txs: allTxs}, nil -} - // QueryVotesByTxQuery will query for votes via a direct txs tags query. It // will fetch and build votes directly from the returned txs and return a JSON // marshalled result or any error that occurred. @@ -188,31 +169,59 @@ func QueryVotesByTxQuery(clientCtx client.Context, params types.QueryProposalVot // QueryVoteByTxQuery will query for a single vote via a direct txs tags query. func QueryVoteByTxQuery(clientCtx client.Context, params types.QueryVoteParams) ([]byte, error) { - events := []string{ - fmt.Sprintf("%s.%s='%s'", sdk.EventTypeMessage, sdk.AttributeKeyAction, types.TypeMsgVote), - fmt.Sprintf("%s.%s='%s'", types.EventTypeProposalVote, types.AttributeKeyProposalID, []byte(fmt.Sprintf("%d", params.ProposalID))), - fmt.Sprintf("%s.%s='%s'", sdk.EventTypeMessage, sdk.AttributeKeySender, params.Voter.String()), - } - - // NOTE: SearchTxs is used to facilitate the txs query which does not currently - // support configurable pagination. - searchResult, err := authclient.QueryTxsByEvents(clientCtx, events, defaultPage, defaultLimit, "") + searchResult, err := combineEvents( + clientCtx, defaultPage, + // Query legacy Vote Msgs + []string{ + fmt.Sprintf("%s.%s='%s'", sdk.EventTypeMessage, sdk.AttributeKeyAction, types.TypeMsgVote), + fmt.Sprintf("%s.%s='%s'", types.EventTypeProposalVote, types.AttributeKeyProposalID, []byte(fmt.Sprintf("%d", params.ProposalID))), + fmt.Sprintf("%s.%s='%s'", sdk.EventTypeMessage, sdk.AttributeKeySender, []byte(params.Voter.String())), + }, + // Query Vote proto Msgs + []string{ + fmt.Sprintf("%s.%s='%s'", sdk.EventTypeMessage, sdk.AttributeKeyAction, sdk.MsgTypeURL(&types.MsgVote{})), + fmt.Sprintf("%s.%s='%s'", types.EventTypeProposalVote, types.AttributeKeyProposalID, []byte(fmt.Sprintf("%d", params.ProposalID))), + fmt.Sprintf("%s.%s='%s'", sdk.EventTypeMessage, sdk.AttributeKeySender, []byte(params.Voter.String())), + }, + // Query legacy VoteWeighted Msgs + []string{ + fmt.Sprintf("%s.%s='%s'", sdk.EventTypeMessage, sdk.AttributeKeyAction, types.TypeMsgVoteWeighted), + fmt.Sprintf("%s.%s='%s'", types.EventTypeProposalVote, types.AttributeKeyProposalID, []byte(fmt.Sprintf("%d", params.ProposalID))), + fmt.Sprintf("%s.%s='%s'", sdk.EventTypeMessage, sdk.AttributeKeySender, []byte(params.Voter.String())), + }, + // Query VoteWeighted proto Msgs + []string{ + fmt.Sprintf("%s.%s='%s'", sdk.EventTypeMessage, sdk.AttributeKeyAction, sdk.MsgTypeURL(&types.MsgVoteWeighted{})), + fmt.Sprintf("%s.%s='%s'", types.EventTypeProposalVote, types.AttributeKeyProposalID, []byte(fmt.Sprintf("%d", params.ProposalID))), + fmt.Sprintf("%s.%s='%s'", sdk.EventTypeMessage, sdk.AttributeKeySender, []byte(params.Voter.String())), + }, + ) if err != nil { return nil, err } + for _, info := range searchResult.Txs { for _, msg := range info.GetTx().GetMsgs() { // there should only be a single vote under the given conditions - if msg.Type() == types.TypeMsgVote { - voteMsg := msg.(*types.MsgVote) - - vote := types.Vote{ + var vote *types.Vote + if voteMsg, ok := msg.(*types.MsgVote); ok { + vote = &types.Vote{ Voter: voteMsg.Voter, ProposalId: params.ProposalID, - Option: voteMsg.Option, + Options: types.NewNonSplitVoteOption(voteMsg.Option), + } + } + + if voteWeightedMsg, ok := msg.(*types.MsgVoteWeighted); ok { + vote = &types.Vote{ + Voter: voteWeightedMsg.Voter, + ProposalId: params.ProposalID, + Options: voteWeightedMsg.Options, } + } - bz, err := clientCtx.JSONMarshaler.MarshalJSON(&vote) + if vote != nil { + bz, err := clientCtx.Codec.MarshalJSON(vote) if err != nil { return nil, err } @@ -235,7 +244,7 @@ func QueryDepositByTxQuery(clientCtx client.Context, params types.QueryDepositPa } if !initialDeposit.Amount.IsZero() { - bz, err := clientCtx.JSONMarshaler.MarshalJSON(&initialDeposit) + bz, err := clientCtx.Codec.MarshalJSON(&initialDeposit) if err != nil { return nil, err } @@ -243,15 +252,21 @@ func QueryDepositByTxQuery(clientCtx client.Context, params types.QueryDepositPa return bz, nil } - events := []string{ - fmt.Sprintf("%s.%s='%s'", sdk.EventTypeMessage, sdk.AttributeKeyAction, types.TypeMsgDeposit), - fmt.Sprintf("%s.%s='%s'", types.EventTypeProposalDeposit, types.AttributeKeyProposalID, []byte(fmt.Sprintf("%d", params.ProposalID))), - fmt.Sprintf("%s.%s='%s'", sdk.EventTypeMessage, sdk.AttributeKeySender, []byte(params.Depositor.String())), - } - - // NOTE: SearchTxs is used to facilitate the txs query which does not currently - // support configurable pagination. - searchResult, err := authclient.QueryTxsByEvents(clientCtx, events, defaultPage, defaultLimit, "") + searchResult, err := combineEvents( + clientCtx, defaultPage, + // Query legacy Msgs event action + []string{ + fmt.Sprintf("%s.%s='%s'", sdk.EventTypeMessage, sdk.AttributeKeyAction, types.TypeMsgDeposit), + fmt.Sprintf("%s.%s='%d'", types.EventTypeProposalDeposit, types.AttributeKeyProposalID, params.ProposalID), + fmt.Sprintf("%s.%s='%s'", sdk.EventTypeMessage, sdk.AttributeKeySender, params.Depositor.String()), + }, + // Query proto Msgs event action v1 + []string{ + fmt.Sprintf("%s.%s='%s'", sdk.EventTypeMessage, sdk.AttributeKeyAction, sdk.MsgTypeURL(&types.MsgDeposit{})), + fmt.Sprintf("%s.%s='%d'", types.EventTypeProposalDeposit, types.AttributeKeyProposalID, params.ProposalID), + fmt.Sprintf("%s.%s='%s'", sdk.EventTypeMessage, sdk.AttributeKeySender, params.Depositor.String()), + }, + ) if err != nil { return nil, err } @@ -259,16 +274,14 @@ func QueryDepositByTxQuery(clientCtx client.Context, params types.QueryDepositPa for _, info := range searchResult.Txs { for _, msg := range info.GetTx().GetMsgs() { // there should only be a single deposit under the given conditions - if msg.Type() == types.TypeMsgDeposit { - depMsg := msg.(*types.MsgDeposit) - + if depMsg, ok := msg.(*types.MsgDeposit); ok { deposit := types.Deposit{ Depositor: depMsg.Depositor, ProposalId: params.ProposalID, Amount: depMsg.Amount, } - bz, err := clientCtx.JSONMarshaler.MarshalJSON(&deposit) + bz, err := clientCtx.Codec.MarshalJSON(&deposit) if err != nil { return nil, err } @@ -284,14 +297,20 @@ func QueryDepositByTxQuery(clientCtx client.Context, params types.QueryDepositPa // QueryProposerByTxQuery will query for a proposer of a governance proposal by // ID. func QueryProposerByTxQuery(clientCtx client.Context, proposalID uint64) (Proposer, error) { - events := []string{ - fmt.Sprintf("%s.%s='%s'", sdk.EventTypeMessage, sdk.AttributeKeyAction, types.TypeMsgSubmitProposal), - fmt.Sprintf("%s.%s='%s'", types.EventTypeSubmitProposal, types.AttributeKeyProposalID, []byte(fmt.Sprintf("%d", proposalID))), - } - - // NOTE: SearchTxs is used to facilitate the txs query which does not currently - // support configurable pagination. - searchResult, err := authclient.QueryTxsByEvents(clientCtx, events, defaultPage, defaultLimit, "") + searchResult, err := combineEvents( + clientCtx, + defaultPage, + // Query legacy Msgs event action + []string{ + fmt.Sprintf("%s.%s='%s'", sdk.EventTypeMessage, sdk.AttributeKeyAction, types.TypeMsgSubmitProposal), + fmt.Sprintf("%s.%s='%s'", types.EventTypeSubmitProposal, types.AttributeKeyProposalID, []byte(fmt.Sprintf("%d", proposalID))), + }, + // Query proto Msgs event action + []string{ + fmt.Sprintf("%s.%s='%s'", sdk.EventTypeMessage, sdk.AttributeKeyAction, sdk.MsgTypeURL(&types.MsgSubmitProposal{})), + fmt.Sprintf("%s.%s='%s'", types.EventTypeSubmitProposal, types.AttributeKeyProposalID, []byte(fmt.Sprintf("%d", proposalID))), + }, + ) if err != nil { return Proposer{}, err } @@ -299,8 +318,7 @@ func QueryProposerByTxQuery(clientCtx client.Context, proposalID uint64) (Propos for _, info := range searchResult.Txs { for _, msg := range info.GetTx().GetMsgs() { // there should only be a single proposal under the given conditions - if msg.Type() == types.TypeMsgSubmitProposal { - subMsg := msg.(*types.MsgSubmitProposal) + if subMsg, ok := msg.(*types.MsgSubmitProposal); ok { return NewProposer(proposalID, subMsg.Proposer), nil } } @@ -328,12 +346,19 @@ func QueryProposalByID(proposalID uint64, clientCtx client.Context, queryRoute s // queryInitialDepositByTxQuery will query for a initial deposit of a governance proposal by // ID. func queryInitialDepositByTxQuery(clientCtx client.Context, proposalID uint64) (types.Deposit, error) { - // Query legacy Msgs event action - events := []string{ - fmt.Sprintf("%s.%s='%s'", sdk.EventTypeMessage, sdk.AttributeKeyAction, types.TypeMsgSubmitProposal), - fmt.Sprintf("%s.%s='%s'", types.EventTypeSubmitProposal, types.AttributeKeyProposalID, []byte(fmt.Sprintf("%d", proposalID))), - } - searchResult, err := authclient.QueryTxsByEvents(clientCtx, events, defaultPage, defaultLimit, "") + searchResult, err := combineEvents( + clientCtx, defaultPage, + // Query legacy Msgs event action + []string{ + fmt.Sprintf("%s.%s='%s'", sdk.EventTypeMessage, sdk.AttributeKeyAction, types.TypeMsgSubmitProposal), + fmt.Sprintf("%s.%s='%s'", types.EventTypeSubmitProposal, types.AttributeKeyProposalID, []byte(fmt.Sprintf("%d", proposalID))), + }, + // Query proto Msgs event action + []string{ + fmt.Sprintf("%s.%s='%s'", sdk.EventTypeMessage, sdk.AttributeKeyAction, sdk.MsgTypeURL(&types.MsgSubmitProposal{})), + fmt.Sprintf("%s.%s='%s'", types.EventTypeSubmitProposal, types.AttributeKeyProposalID, []byte(fmt.Sprintf("%d", proposalID))), + }, + ) if err != nil { return types.Deposit{}, err @@ -352,5 +377,27 @@ func queryInitialDepositByTxQuery(clientCtx client.Context, proposalID uint64) ( } } - return types.Deposit{}, sdkerrors.Wrapf(sdkerrors.ErrKeyNotFound, "failed to find the initial deposit for proposalID %d", proposalID) + return types.Deposit{}, sdkerrors.ErrNotFound.Wrapf("failed to find the initial deposit for proposalID %d", proposalID) +} + +// combineEvents queries txs by events with all events from each event group, +// and combines all those events together. +// +// Tx are indexed in tendermint via their Msgs `Type()`, which can be: +// - via legacy Msgs (amino or proto), their `Type()` is a custom string, +// - via ADR-031 proto msgs, their `Type()` is the protobuf FQ method name. +// In searching for events, we search for both `Type()`s, and we use the +// `combineEvents` function here to merge events. +func combineEvents(clientCtx client.Context, page int, eventGroups ...[]string) (*sdk.SearchTxsResult, error) { + // Only the Txs field will be populated in the final SearchTxsResult. + allTxs := []*sdk.TxResponse{} + for _, events := range eventGroups { + res, err := authtx.QueryTxsByEvents(clientCtx, events, page, defaultLimit, "") + if err != nil { + return nil, err + } + allTxs = append(allTxs, res.Txs...) + } + + return &sdk.SearchTxsResult{Txs: allTxs}, nil } diff --git a/x/gov/client/utils/query_test.go b/x/gov/client/utils/query_test.go index 12d12a0210..7513b57224 100644 --- a/x/gov/client/utils/query_test.go +++ b/x/gov/client/utils/query_test.go @@ -5,17 +5,16 @@ import ( "regexp" "testing" + "github.com/stretchr/testify/require" + "github.com/line/ostracon/rpc/client/mock" ctypes "github.com/line/ostracon/rpc/core/types" octypes "github.com/line/ostracon/types" - "github.com/stretchr/testify/require" "github.com/line/lbm-sdk/client" - "github.com/line/lbm-sdk/codec" "github.com/line/lbm-sdk/simapp" sdk "github.com/line/lbm-sdk/types" "github.com/line/lbm-sdk/x/auth/legacy/legacytx" - authtypes "github.com/line/lbm-sdk/x/auth/types" "github.com/line/lbm-sdk/x/gov/client/utils" "github.com/line/lbm-sdk/x/gov/types" ) @@ -63,7 +62,7 @@ func (mock TxSearchMock) TxSearch(ctx context.Context, query string, prove bool, return &ctypes.ResultTxSearch{}, nil } - txs := mock.txs[start:end] + txs := matchingTxs[start:end] rst := &ctypes.ResultTxSearch{Txs: make([]*ctypes.ResultTx, len(txs)), TotalCount: len(txs)} for i := range txs { rst.Txs[i] = &ctypes.ResultTx{Tx: txs[i]} @@ -76,15 +75,9 @@ func (mock TxSearchMock) Block(ctx context.Context, height *int64) (*ctypes.Resu return &ctypes.ResultBlock{Block: &octypes.Block{}}, nil } -func newTestCodec() *codec.LegacyAmino { - cdc := codec.NewLegacyAmino() - sdk.RegisterLegacyAminoCodec(cdc) - types.RegisterLegacyAminoCodec(cdc) - authtypes.RegisterLegacyAminoCodec(cdc) - return cdc -} - func TestGetPaginatedVotes(t *testing.T) { + encCfg := simapp.MakeTestEncodingConfig() + type testCase struct { description string page, limit int @@ -116,7 +109,8 @@ func TestGetPaginatedVotes(t *testing.T) { }, votes: []types.Vote{ types.NewVote(0, acc1, types.NewNonSplitVoteOption(types.OptionYes)), - types.NewVote(0, acc2, types.NewNonSplitVoteOption(types.OptionYes))}, + types.NewVote(0, acc2, types.NewNonSplitVoteOption(types.OptionYes)), + }, }, { description: "2MsgPerTx1Chunk", @@ -128,7 +122,8 @@ func TestGetPaginatedVotes(t *testing.T) { }, votes: []types.Vote{ types.NewVote(0, acc1, types.NewNonSplitVoteOption(types.OptionYes)), - types.NewVote(0, acc1, types.NewNonSplitVoteOption(types.OptionYes))}, + types.NewVote(0, acc1, types.NewNonSplitVoteOption(types.OptionYes)), + }, }, { description: "2MsgPerTx2Chunk", @@ -140,7 +135,8 @@ func TestGetPaginatedVotes(t *testing.T) { }, votes: []types.Vote{ types.NewVote(0, acc2, types.NewNonSplitVoteOption(types.OptionYes)), - types.NewVote(0, acc2, types.NewNonSplitVoteOption(types.OptionYes))}, + types.NewVote(0, acc2, types.NewNonSplitVoteOption(types.OptionYes)), + }, }, { description: "IncompleteSearchTx", @@ -170,17 +166,12 @@ func TestGetPaginatedVotes(t *testing.T) { tc := tc t.Run(tc.description, func(t *testing.T) { - var ( - marshalled = make([]octypes.Tx, len(tc.msgs)) - cdc = newTestCodec() - ) - - encodingConfig := simapp.MakeTestEncodingConfig() - cli := TxSearchMock{txs: marshalled, txConfig: encodingConfig.TxConfig} + var marshalled = make([]octypes.Tx, len(tc.msgs)) + cli := TxSearchMock{txs: marshalled, txConfig: encCfg.TxConfig} clientCtx := client.Context{}. - WithLegacyAmino(cdc). + WithLegacyAmino(encCfg.Amino). WithClient(cli). - WithTxConfig(encodingConfig.TxConfig) + WithTxConfig(encCfg.TxConfig) for i := range tc.msgs { txBuilder := clientCtx.TxConfig.NewTxBuilder() diff --git a/x/gov/client/utils/utils.go b/x/gov/client/utils/utils.go index d875b9430c..4f8d7afe58 100644 --- a/x/gov/client/utils/utils.go +++ b/x/gov/client/utils/utils.go @@ -40,7 +40,7 @@ func NormalizeWeightedVoteOptions(options string) string { return strings.Join(newOptions, ",") } -// NormalizeProposalType - normalize user specified proposal type +// NormalizeProposalType - normalize user specified proposal type. func NormalizeProposalType(proposalType string) string { switch proposalType { case "Text", "text": @@ -51,7 +51,7 @@ func NormalizeProposalType(proposalType string) string { } } -// NormalizeProposalStatus - normalize user specified proposal status +// NormalizeProposalStatus - normalize user specified proposal status. func NormalizeProposalStatus(status string) string { switch status { case "DepositPeriod", "deposit_period": diff --git a/x/gov/common_test.go b/x/gov/common_test.go index a703bcd3ec..d80a063199 100644 --- a/x/gov/common_test.go +++ b/x/gov/common_test.go @@ -16,7 +16,7 @@ import ( ) var ( - valTokens = sdk.TokensFromConsensusPower(42) + valTokens = sdk.TokensFromConsensusPower(42, sdk.DefaultPowerReduction) TestProposal = types.NewTextProposal("Test", "description") TestDescription = stakingtypes.NewDescription("T", "E", "S", "T", "Z") TestCommissionRates = stakingtypes.NewCommissionRates(sdk.ZeroDec(), sdk.ZeroDec(), sdk.ZeroDec()) @@ -82,7 +82,7 @@ func createValidators(t *testing.T, stakingHandler sdk.Handler, ctx sdk.Context, require.True(t, len(addrs) <= len(pubkeys), "Not enough pubkeys specified at top of file.") for i := 0; i < len(addrs); i++ { - valTokens := sdk.TokensFromConsensusPower(powerAmt[i]) + valTokens := sdk.TokensFromConsensusPower(powerAmt[i], sdk.DefaultPowerReduction) valCreateMsg, err := stakingtypes.NewMsgCreateValidator( addrs[i], pubkeys[i], sdk.NewCoin(sdk.DefaultBondDenom, valTokens), TestDescription, TestCommissionRates, sdk.OneInt(), diff --git a/x/gov/genesis.go b/x/gov/genesis.go index f10b432b9c..665770f0e6 100644 --- a/x/gov/genesis.go +++ b/x/gov/genesis.go @@ -41,14 +41,16 @@ func InitGenesis(ctx sdk.Context, ak types.AccountKeeper, bk types.BankKeeper, k k.SetProposal(ctx, proposal) } - // add coins if not provided on genesis - if bk.GetAllBalances(ctx, moduleAcc.GetAddress()).IsZero() { - if err := bk.SetBalances(ctx, moduleAcc.GetAddress(), totalDeposits); err != nil { - panic(err) - } - + // if account has zero balance it probably means it's not set, so we set it + balance := bk.GetAllBalances(ctx, moduleAcc.GetAddress()) + if balance.IsZero() { ak.SetModuleAccount(ctx, moduleAcc) } + + // check if total deposits equals balance, if it doesn't panic because there were export/import errors + if !balance.IsEqual(totalDeposits) { + panic(fmt.Sprintf("expected module account was %s but we got %s", balance.String(), totalDeposits.String())) + } } // ExportGenesis - output genesis parameters diff --git a/x/gov/genesis_test.go b/x/gov/genesis_test.go index 33fd90dfd7..c32e149dc3 100644 --- a/x/gov/genesis_test.go +++ b/x/gov/genesis_test.go @@ -11,6 +11,7 @@ import ( "github.com/stretchr/testify/require" "github.com/line/lbm-sdk/simapp" + sdk "github.com/line/lbm-sdk/types" "github.com/line/lbm-sdk/x/auth" authtypes "github.com/line/lbm-sdk/x/auth/types" banktypes "github.com/line/lbm-sdk/x/bank/types" @@ -111,6 +112,27 @@ func TestImportExportQueues(t *testing.T) { require.True(t, proposal2.Status == types.StatusRejected) } +func TestImportExportQueues_ErrorUnconsistentState(t *testing.T) { + app := simapp.Setup(false) + ctx := app.BaseApp.NewContext(false, ocproto.Header{}) + require.Panics(t, func() { + gov.InitGenesis(ctx, app.AccountKeeper, app.BankKeeper, app.GovKeeper, &types.GenesisState{ + Deposits: types.Deposits{ + { + ProposalId: 1234, + Depositor: "me", + Amount: sdk.Coins{ + sdk.NewCoin( + "stake", + sdk.NewInt(1234), + ), + }, + }, + }, + }) + }) +} + func TestEqualProposals(t *testing.T) { app := simapp.Setup(false) ctx := app.BaseApp.NewContext(false, ocproto.Header{}) diff --git a/x/gov/keeper/common_test.go b/x/gov/keeper/common_test.go index 4665720a87..6312786e18 100644 --- a/x/gov/keeper/common_test.go +++ b/x/gov/keeper/common_test.go @@ -21,10 +21,10 @@ func createValidators(t *testing.T, ctx sdk.Context, app *simapp.SimApp, powers addrs := simapp.AddTestAddrsIncremental(app, ctx, 5, sdk.NewInt(30000000)) valAddrs := simapp.ConvertAddrsToValAddrs(addrs) pks := simapp.CreateTestPubKeys(5) + cdc := simapp.MakeTestEncodingConfig().Marshaler - appCodec, _ := simapp.MakeCodecs() app.StakingKeeper = stakingkeeper.NewKeeper( - appCodec, + cdc, app.GetKey(stakingtypes.StoreKey), app.AccountKeeper, app.BankKeeper, @@ -48,9 +48,9 @@ func createValidators(t *testing.T, ctx sdk.Context, app *simapp.SimApp, powers app.StakingKeeper.SetNewValidatorByPowerIndex(ctx, val2) app.StakingKeeper.SetNewValidatorByPowerIndex(ctx, val3) - _, _ = app.StakingKeeper.Delegate(ctx, addrs[0], sdk.TokensFromConsensusPower(powers[0]), stakingtypes.Unbonded, val1, true) - _, _ = app.StakingKeeper.Delegate(ctx, addrs[1], sdk.TokensFromConsensusPower(powers[1]), stakingtypes.Unbonded, val2, true) - _, _ = app.StakingKeeper.Delegate(ctx, addrs[2], sdk.TokensFromConsensusPower(powers[2]), stakingtypes.Unbonded, val3, true) + _, _ = app.StakingKeeper.Delegate(ctx, addrs[0], app.StakingKeeper.TokensFromConsensusPower(ctx, powers[0]), stakingtypes.Unbonded, val1, true) + _, _ = app.StakingKeeper.Delegate(ctx, addrs[1], app.StakingKeeper.TokensFromConsensusPower(ctx, powers[1]), stakingtypes.Unbonded, val2, true) + _, _ = app.StakingKeeper.Delegate(ctx, addrs[2], app.StakingKeeper.TokensFromConsensusPower(ctx, powers[2]), stakingtypes.Unbonded, val3, true) _ = staking.EndBlocker(ctx, app.StakingKeeper) diff --git a/x/gov/keeper/deposit.go b/x/gov/keeper/deposit.go index c0f2d3fcaa..a970b30ed0 100644 --- a/x/gov/keeper/deposit.go +++ b/x/gov/keeper/deposit.go @@ -16,7 +16,7 @@ func (keeper Keeper) GetDeposit(ctx sdk.Context, proposalID uint64, depositorAdd return deposit, false } - keeper.cdc.MustUnmarshalBinaryBare(bz, &deposit) + keeper.cdc.MustUnmarshal(bz, &deposit) return deposit, true } @@ -24,7 +24,7 @@ func (keeper Keeper) GetDeposit(ctx sdk.Context, proposalID uint64, depositorAdd // SetDeposit sets a Deposit to the gov store func (keeper Keeper) SetDeposit(ctx sdk.Context, deposit types.Deposit) { store := ctx.KVStore(keeper.storeKey) - bz := keeper.cdc.MustMarshalBinaryBare(&deposit) + bz := keeper.cdc.MustMarshal(&deposit) depositor := sdk.AccAddress(deposit.Depositor) store.Set(types.DepositKey(deposit.ProposalId, depositor), bz) @@ -76,7 +76,7 @@ func (keeper Keeper) IterateAllDeposits(ctx sdk.Context, cb func(deposit types.D for ; iterator.Valid(); iterator.Next() { var deposit types.Deposit - keeper.cdc.MustUnmarshalBinaryBare(iterator.Value(), &deposit) + keeper.cdc.MustUnmarshal(iterator.Value(), &deposit) if cb(deposit) { break @@ -94,7 +94,7 @@ func (keeper Keeper) IterateDeposits(ctx sdk.Context, proposalID uint64, cb func for ; iterator.Valid(); iterator.Next() { var deposit types.Deposit - keeper.cdc.MustUnmarshalBinaryBare(iterator.Value(), &deposit) + keeper.cdc.MustUnmarshal(iterator.Value(), &deposit) if cb(deposit) { break @@ -144,6 +144,9 @@ func (keeper Keeper) AddDeposit(ctx sdk.Context, proposalID uint64, depositorAdd deposit = types.NewDeposit(proposalID, depositorAddr, depositAmount) } + // called when deposit has been added to a proposal, however the proposal may not be active + keeper.AfterProposalDeposit(ctx, proposalID, depositorAddr) + ctx.EventManager().EmitEvent( sdk.NewEvent( types.EventTypeProposalDeposit, diff --git a/x/gov/keeper/deposit_test.go b/x/gov/keeper/deposit_test.go index 4a980ae73d..dc66029551 100644 --- a/x/gov/keeper/deposit_test.go +++ b/x/gov/keeper/deposit_test.go @@ -22,8 +22,8 @@ func TestDeposits(t *testing.T) { require.NoError(t, err) proposalID := proposal.ProposalId - fourStake := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.TokensFromConsensusPower(4))) - fiveStake := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.TokensFromConsensusPower(5))) + fourStake := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, app.StakingKeeper.TokensFromConsensusPower(ctx, 4))) + fiveStake := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, app.StakingKeeper.TokensFromConsensusPower(ctx, 5))) addr0Initial := app.BankKeeper.GetAllBalances(ctx, TestAddrs[0]) addr1Initial := app.BankKeeper.GetAllBalances(ctx, TestAddrs[1]) @@ -100,4 +100,11 @@ func TestDeposits(t *testing.T) { require.False(t, found) require.Equal(t, addr0Initial, app.BankKeeper.GetAllBalances(ctx, TestAddrs[0])) require.Equal(t, addr1Initial, app.BankKeeper.GetAllBalances(ctx, TestAddrs[1])) + + // Test delete deposits + _, err = app.GovKeeper.AddDeposit(ctx, proposalID, TestAddrs[0], fourStake) + require.NoError(t, err) + app.GovKeeper.DeleteDeposits(ctx, proposalID) + deposits = app.GovKeeper.GetDeposits(ctx, proposalID) + require.Len(t, deposits, 0) } diff --git a/x/gov/keeper/grpc_query.go b/x/gov/keeper/grpc_query.go index d3a7dbfc7f..a96f63b351 100644 --- a/x/gov/keeper/grpc_query.go +++ b/x/gov/keeper/grpc_query.go @@ -44,7 +44,7 @@ func (q Keeper) Proposals(c context.Context, req *types.QueryProposalsRequest) ( pageRes, err := query.FilteredPaginate(proposalStore, req.Pagination, func(key []byte, value []byte, accumulate bool) (bool, error) { var p types.Proposal - if err := q.cdc.UnmarshalBinaryBare(value, &p); err != nil { + if err := q.cdc.Unmarshal(value, &p); err != nil { return false, status.Error(codes.Internal, err.Error()) } @@ -130,7 +130,7 @@ func (q Keeper) Votes(c context.Context, req *types.QueryVotesRequest) (*types.Q pageRes, err := query.Paginate(votesStore, req.Pagination, func(key []byte, value []byte) error { var vote types.Vote - if err := q.cdc.UnmarshalBinaryBare(value, &vote); err != nil { + if err := q.cdc.Unmarshal(value, &vote); err != nil { return err } populateLegacyOption(&vote) @@ -217,7 +217,7 @@ func (q Keeper) Deposits(c context.Context, req *types.QueryDepositsRequest) (*t pageRes, err := query.Paginate(depositStore, req.Pagination, func(key []byte, value []byte) error { var deposit types.Deposit - if err := q.cdc.UnmarshalBinaryBare(value, &deposit); err != nil { + if err := q.cdc.Unmarshal(value, &deposit); err != nil { return err } diff --git a/x/gov/keeper/grpc_query_test.go b/x/gov/keeper/grpc_query_test.go index 3eed8bb07e..2d99d7fc5f 100644 --- a/x/gov/keeper/grpc_query_test.go +++ b/x/gov/keeper/grpc_query_test.go @@ -164,7 +164,7 @@ func (suite *KeeperTestSuite) TestGRPCQueryProposals() { { "request with filter of deposit address", func() { - depositCoins := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.TokensFromConsensusPower(20))) + depositCoins := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, app.StakingKeeper.TokensFromConsensusPower(ctx, 20))) deposit := types.NewDeposit(testProposals[0].ProposalId, addrs[0], depositCoins) app.GovKeeper.SetDeposit(ctx, deposit) @@ -582,7 +582,7 @@ func (suite *KeeperTestSuite) TestGRPCQueryDeposit() { { "valid request", func() { - depositCoins := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.TokensFromConsensusPower(20))) + depositCoins := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, app.StakingKeeper.TokensFromConsensusPower(ctx, 20))) deposit := types.NewDeposit(proposal.ProposalId, addrs[0], depositCoins) app.GovKeeper.SetDeposit(ctx, deposit) @@ -669,11 +669,11 @@ func (suite *KeeperTestSuite) TestGRPCQueryDeposits() { { "get deposits with default limit", func() { - depositAmount1 := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.TokensFromConsensusPower(20))) + depositAmount1 := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, app.StakingKeeper.TokensFromConsensusPower(ctx, 20))) deposit1 := types.NewDeposit(proposal.ProposalId, addrs[0], depositAmount1) app.GovKeeper.SetDeposit(ctx, deposit1) - depositAmount2 := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.TokensFromConsensusPower(30))) + depositAmount2 := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, app.StakingKeeper.TokensFromConsensusPower(ctx, 30))) deposit2 := types.NewDeposit(proposal.ProposalId, addrs[1], depositAmount2) app.GovKeeper.SetDeposit(ctx, deposit2) diff --git a/x/gov/keeper/hooks.go b/x/gov/keeper/hooks.go new file mode 100644 index 0000000000..78440e5f6e --- /dev/null +++ b/x/gov/keeper/hooks.go @@ -0,0 +1,44 @@ +package keeper + +import ( + sdk "github.com/line/lbm-sdk/types" + "github.com/line/lbm-sdk/x/gov/types" +) + +// Implements GovHooks interface +var _ types.GovHooks = Keeper{} + +// AfterProposalSubmission - call hook if registered +func (keeper Keeper) AfterProposalSubmission(ctx sdk.Context, proposalID uint64) { + if keeper.hooks != nil { + keeper.hooks.AfterProposalSubmission(ctx, proposalID) + } +} + +// AfterProposalDeposit - call hook if registered +func (keeper Keeper) AfterProposalDeposit(ctx sdk.Context, proposalID uint64, depositorAddr sdk.AccAddress) { + if keeper.hooks != nil { + keeper.hooks.AfterProposalDeposit(ctx, proposalID, depositorAddr) + } +} + +// AfterProposalVote - call hook if registered +func (keeper Keeper) AfterProposalVote(ctx sdk.Context, proposalID uint64, voterAddr sdk.AccAddress) { + if keeper.hooks != nil { + keeper.hooks.AfterProposalVote(ctx, proposalID, voterAddr) + } +} + +// AfterProposalFailedMinDeposit - call hook if registered +func (keeper Keeper) AfterProposalFailedMinDeposit(ctx sdk.Context, proposalID uint64) { + if keeper.hooks != nil { + keeper.hooks.AfterProposalFailedMinDeposit(ctx, proposalID) + } +} + +// AfterProposalVotingPeriodEnded - call hook if registered +func (keeper Keeper) AfterProposalVotingPeriodEnded(ctx sdk.Context, proposalID uint64) { + if keeper.hooks != nil { + keeper.hooks.AfterProposalVotingPeriodEnded(ctx, proposalID) + } +} diff --git a/x/gov/keeper/hooks_test.go b/x/gov/keeper/hooks_test.go new file mode 100644 index 0000000000..df9060faf6 --- /dev/null +++ b/x/gov/keeper/hooks_test.go @@ -0,0 +1,95 @@ +package keeper_test + +import ( + "testing" + "time" + + "github.com/stretchr/testify/require" + + ocproto "github.com/line/ostracon/proto/ostracon/types" + + "github.com/line/lbm-sdk/simapp" + sdk "github.com/line/lbm-sdk/types" + "github.com/line/lbm-sdk/x/gov" + "github.com/line/lbm-sdk/x/gov/keeper" + "github.com/line/lbm-sdk/x/gov/types" +) + +var _ types.GovHooks = &MockGovHooksReceiver{} + +// GovHooks event hooks for governance proposal object (noalias) +type MockGovHooksReceiver struct { + AfterProposalSubmissionValid bool + AfterProposalDepositValid bool + AfterProposalVoteValid bool + AfterProposalFailedMinDepositValid bool + AfterProposalVotingPeriodEndedValid bool +} + +func (h *MockGovHooksReceiver) AfterProposalSubmission(ctx sdk.Context, proposalID uint64) { + h.AfterProposalSubmissionValid = true +} + +func (h *MockGovHooksReceiver) AfterProposalDeposit(ctx sdk.Context, proposalID uint64, depositorAddr sdk.AccAddress) { + h.AfterProposalDepositValid = true +} + +func (h *MockGovHooksReceiver) AfterProposalVote(ctx sdk.Context, proposalID uint64, voterAddr sdk.AccAddress) { + h.AfterProposalVoteValid = true +} +func (h *MockGovHooksReceiver) AfterProposalFailedMinDeposit(ctx sdk.Context, proposalID uint64) { + h.AfterProposalFailedMinDepositValid = true +} +func (h *MockGovHooksReceiver) AfterProposalVotingPeriodEnded(ctx sdk.Context, proposalID uint64) { + h.AfterProposalVotingPeriodEndedValid = true +} + +func TestHooks(t *testing.T) { + app := simapp.Setup(false) + ctx := app.BaseApp.NewContext(false, ocproto.Header{}) + + minDeposit := app.GovKeeper.GetDepositParams(ctx).MinDeposit + addrs := simapp.AddTestAddrs(app, ctx, 1, minDeposit[0].Amount) + + govHooksReceiver := MockGovHooksReceiver{} + + keeper.UnsafeSetHooks( + &app.GovKeeper, types.NewMultiGovHooks(&govHooksReceiver), + ) + + require.False(t, govHooksReceiver.AfterProposalSubmissionValid) + require.False(t, govHooksReceiver.AfterProposalDepositValid) + require.False(t, govHooksReceiver.AfterProposalVoteValid) + require.False(t, govHooksReceiver.AfterProposalFailedMinDepositValid) + require.False(t, govHooksReceiver.AfterProposalVotingPeriodEndedValid) + + tp := TestProposal + _, err := app.GovKeeper.SubmitProposal(ctx, tp) + require.NoError(t, err) + require.True(t, govHooksReceiver.AfterProposalSubmissionValid) + + newHeader := ctx.BlockHeader() + newHeader.Time = ctx.BlockHeader().Time.Add(app.GovKeeper.GetDepositParams(ctx).MaxDepositPeriod).Add(time.Duration(1) * time.Second) + ctx = ctx.WithBlockHeader(newHeader) + gov.EndBlocker(ctx, app.GovKeeper) + + require.True(t, govHooksReceiver.AfterProposalFailedMinDepositValid) + + p2, err := app.GovKeeper.SubmitProposal(ctx, tp) + require.NoError(t, err) + + activated, err := app.GovKeeper.AddDeposit(ctx, p2.ProposalId, addrs[0], minDeposit) + require.True(t, activated) + require.NoError(t, err) + require.True(t, govHooksReceiver.AfterProposalDepositValid) + + err = app.GovKeeper.AddVote(ctx, p2.ProposalId, addrs[0], types.NewNonSplitVoteOption(types.OptionYes)) + require.NoError(t, err) + require.True(t, govHooksReceiver.AfterProposalVoteValid) + + newHeader = ctx.BlockHeader() + newHeader.Time = ctx.BlockHeader().Time.Add(app.GovKeeper.GetVotingParams(ctx).VotingPeriod).Add(time.Duration(1) * time.Second) + ctx = ctx.WithBlockHeader(newHeader) + gov.EndBlocker(ctx, app.GovKeeper) + require.True(t, govHooksReceiver.AfterProposalVotingPeriodEndedValid) +} diff --git a/x/gov/keeper/internal_test.go b/x/gov/keeper/internal_test.go new file mode 100644 index 0000000000..d99dd5fd44 --- /dev/null +++ b/x/gov/keeper/internal_test.go @@ -0,0 +1,10 @@ +package keeper + +import "github.com/line/lbm-sdk/x/gov/types" + +// UnsafeSetHooks updates the gov keeper's hooks, overriding any potential +// pre-existing hooks. +// WARNING: this function should only be used in tests. +func UnsafeSetHooks(k *Keeper, h types.GovHooks) { + k.hooks = h +} diff --git a/x/gov/keeper/keeper.go b/x/gov/keeper/keeper.go index 66e9592576..de1a2bf31a 100644 --- a/x/gov/keeper/keeper.go +++ b/x/gov/keeper/keeper.go @@ -23,11 +23,14 @@ type Keeper struct { // The reference to the DelegationSet and ValidatorSet to get information about validators and delegators sk types.StakingKeeper + // GovHooks + hooks types.GovHooks + // The (unexposed) keys used to access the stores from the Context. storeKey sdk.StoreKey // The codec codec for binary encoding/decoding. - cdc codec.BinaryMarshaler + cdc codec.BinaryCodec // Proposal router router types.Router @@ -41,7 +44,7 @@ type Keeper struct { // // CONTRACT: the parameter Subspace must have the param key table already initialized func NewKeeper( - cdc codec.BinaryMarshaler, key sdk.StoreKey, paramSpace types.ParamSubspace, + cdc codec.BinaryCodec, key sdk.StoreKey, paramSpace types.ParamSubspace, authKeeper types.AccountKeeper, bankKeeper types.BankKeeper, sk types.StakingKeeper, rtr types.Router, ) Keeper { @@ -66,6 +69,17 @@ func NewKeeper( } } +// SetHooks sets the hooks for governance +func (keeper *Keeper) SetHooks(gh types.GovHooks) *Keeper { + if keeper.hooks != nil { + panic("cannot set governance hooks twice") + } + + keeper.hooks = gh + + return keeper +} + // Logger returns a module-specific logger. func (keeper Keeper) Logger(ctx sdk.Context) log.Logger { return ctx.Logger().With("module", "x/"+types.ModuleName) diff --git a/x/gov/keeper/proposal.go b/x/gov/keeper/proposal.go index 15113361a6..1d434b3f4a 100644 --- a/x/gov/keeper/proposal.go +++ b/x/gov/keeper/proposal.go @@ -41,6 +41,9 @@ func (keeper Keeper) SubmitProposal(ctx sdk.Context, content types.Content) (typ keeper.InsertInactiveProposalQueue(ctx, proposalID, proposal.DepositEndTime) keeper.SetProposalID(ctx, proposalID+1) + // called right after a proposal is submitted + keeper.AfterProposalSubmission(ctx, proposalID) + ctx.EventManager().EmitEvent( sdk.NewEvent( types.EventTypeSubmitProposal, @@ -192,7 +195,7 @@ func (keeper Keeper) ActivateVotingPeriod(ctx sdk.Context, proposal types.Propos } func (keeper Keeper) MarshalProposal(proposal types.Proposal) ([]byte, error) { - bz, err := keeper.cdc.MarshalBinaryBare(&proposal) + bz, err := keeper.cdc.Marshal(&proposal) if err != nil { return nil, err } @@ -200,7 +203,7 @@ func (keeper Keeper) MarshalProposal(proposal types.Proposal) ([]byte, error) { } func (keeper Keeper) UnmarshalProposal(bz []byte, proposal *types.Proposal) error { - err := keeper.cdc.UnmarshalBinaryBare(bz, proposal) + err := keeper.cdc.Unmarshal(bz, proposal) if err != nil { return err } diff --git a/x/gov/keeper/proposal_test.go b/x/gov/keeper/proposal_test.go index ed4907fac9..0301016fb5 100644 --- a/x/gov/keeper/proposal_test.go +++ b/x/gov/keeper/proposal_test.go @@ -4,54 +4,43 @@ import ( "errors" "fmt" "strings" - "testing" "time" - ocproto "github.com/line/ostracon/proto/ostracon/types" - "github.com/stretchr/testify/require" - - "github.com/line/lbm-sdk/simapp" sdk "github.com/line/lbm-sdk/types" "github.com/line/lbm-sdk/x/gov/types" ) -func TestGetSetProposal(t *testing.T) { - app := simapp.Setup(false) - ctx := app.BaseApp.NewContext(false, ocproto.Header{}) - +func (suite *KeeperTestSuite) TestGetSetProposal() { tp := TestProposal - proposal, err := app.GovKeeper.SubmitProposal(ctx, tp) - require.NoError(t, err) + proposal, err := suite.app.GovKeeper.SubmitProposal(suite.ctx, tp) + suite.Require().NoError(err) proposalID := proposal.ProposalId - app.GovKeeper.SetProposal(ctx, proposal) + suite.app.GovKeeper.SetProposal(suite.ctx, proposal) - gotProposal, ok := app.GovKeeper.GetProposal(ctx, proposalID) - require.True(t, ok) - require.True(t, proposal.Equal(gotProposal)) + gotProposal, ok := suite.app.GovKeeper.GetProposal(suite.ctx, proposalID) + suite.Require().True(ok) + suite.Require().True(proposal.Equal(gotProposal)) } -func TestActivateVotingPeriod(t *testing.T) { - app := simapp.Setup(false) - ctx := app.BaseApp.NewContext(false, ocproto.Header{}) - +func (suite *KeeperTestSuite) TestActivateVotingPeriod() { tp := TestProposal - proposal, err := app.GovKeeper.SubmitProposal(ctx, tp) - require.NoError(t, err) + proposal, err := suite.app.GovKeeper.SubmitProposal(suite.ctx, tp) + suite.Require().NoError(err) - require.True(t, proposal.VotingStartTime.Equal(time.Time{})) + suite.Require().True(proposal.VotingStartTime.Equal(time.Time{})) - app.GovKeeper.ActivateVotingPeriod(ctx, proposal) + suite.app.GovKeeper.ActivateVotingPeriod(suite.ctx, proposal) - require.True(t, proposal.VotingStartTime.Equal(ctx.BlockHeader().Time)) + suite.Require().True(proposal.VotingStartTime.Equal(suite.ctx.BlockHeader().Time)) - proposal, ok := app.GovKeeper.GetProposal(ctx, proposal.ProposalId) - require.True(t, ok) + proposal, ok := suite.app.GovKeeper.GetProposal(suite.ctx, proposal.ProposalId) + suite.Require().True(ok) - activeIterator := app.GovKeeper.ActiveProposalQueueIterator(ctx, proposal.VotingEndTime) - require.True(t, activeIterator.Valid()) + activeIterator := suite.app.GovKeeper.ActiveProposalQueueIterator(suite.ctx, proposal.VotingEndTime) + suite.Require().True(activeIterator.Valid()) proposalID := types.GetProposalIDFromBytes(activeIterator.Value()) - require.Equal(t, proposalID, proposal.ProposalId) + suite.Require().Equal(proposalID, proposal.ProposalId) activeIterator.Close() } @@ -59,10 +48,7 @@ type invalidProposalRoute struct{ types.TextProposal } func (invalidProposalRoute) ProposalRoute() string { return "nonexistingroute" } -func TestSubmitProposal(t *testing.T) { - app := simapp.Setup(false) - ctx := app.BaseApp.NewContext(false, ocproto.Header{}) - +func (suite *KeeperTestSuite) TestSubmitProposal() { testCases := []struct { content types.Content expectedErr error @@ -78,35 +64,32 @@ func TestSubmitProposal(t *testing.T) { } for i, tc := range testCases { - _, err := app.GovKeeper.SubmitProposal(ctx, tc.content) - require.True(t, errors.Is(tc.expectedErr, err), "tc #%d; got: %v, expected: %v", i, err, tc.expectedErr) + _, err := suite.app.GovKeeper.SubmitProposal(suite.ctx, tc.content) + suite.Require().True(errors.Is(tc.expectedErr, err), "tc #%d; got: %v, expected: %v", i, err, tc.expectedErr) } } -func TestGetProposalsFiltered(t *testing.T) { +func (suite *KeeperTestSuite) TestGetProposalsFiltered() { proposalID := uint64(1) - app := simapp.Setup(false) - ctx := app.BaseApp.NewContext(false, ocproto.Header{}) - status := []types.ProposalStatus{types.StatusDepositPeriod, types.StatusVotingPeriod} - addr1 := sdk.AccAddress("foo_________________") + addr1 := sdk.BytesToAccAddress([]byte("foo_________________")) for _, s := range status { for i := 0; i < 50; i++ { p, err := types.NewProposal(TestProposal, proposalID, time.Now(), time.Now()) - require.NoError(t, err) + suite.Require().NoError(err) p.Status = s if i%2 == 0 { d := types.NewDeposit(proposalID, addr1, nil) v := types.NewVote(proposalID, addr1, types.NewNonSplitVoteOption(types.OptionYes)) - app.GovKeeper.SetDeposit(ctx, d) - app.GovKeeper.SetVote(ctx, v) + suite.app.GovKeeper.SetDeposit(suite.ctx, d) + suite.app.GovKeeper.SetVote(suite.ctx, v) } - app.GovKeeper.SetProposal(ctx, p) + suite.app.GovKeeper.SetProposal(suite.ctx, p) proposalID++ } } @@ -130,13 +113,13 @@ func TestGetProposalsFiltered(t *testing.T) { } for i, tc := range testCases { - t.Run(fmt.Sprintf("Test Case %d", i), func(t *testing.T) { - proposals := app.GovKeeper.GetProposalsFiltered(ctx, tc.params) - require.Len(t, proposals, tc.expectedNumResults) + suite.Run(fmt.Sprintf("Test Case %d", i), func() { + proposals := suite.app.GovKeeper.GetProposalsFiltered(suite.ctx, tc.params) + suite.Require().Len(proposals, tc.expectedNumResults) for _, p := range proposals { if types.ValidProposalStatus(tc.params.ProposalStatus) { - require.Equal(t, tc.params.ProposalStatus, p.Status) + suite.Require().Equal(tc.params.ProposalStatus, p.Status) } } }) diff --git a/x/gov/keeper/querier_test.go b/x/gov/keeper/querier_test.go index 2070cca6e3..7e8caf0a82 100644 --- a/x/gov/keeper/querier_test.go +++ b/x/gov/keeper/querier_test.go @@ -153,7 +153,7 @@ func TestQueries(t *testing.T) { TestAddrs := simapp.AddTestAddrsIncremental(app, ctx, 2, sdk.NewInt(20000001)) oneCoins := sdk.NewCoins(sdk.NewInt64Coin(sdk.DefaultBondDenom, 1)) - consCoins := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.TokensFromConsensusPower(10))) + consCoins := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, app.StakingKeeper.TokensFromConsensusPower(ctx, 10))) tp := TestProposal @@ -334,7 +334,7 @@ func TestPaginatedVotesQuery(t *testing.T) { vote := types.Vote{ ProposalId: proposal.ProposalId, Voter: genAddr(), - Option: types.OptionYes, + Options: types.NewNonSplitVoteOption(types.OptionYes), } votes[i] = vote app.GovKeeper.SetVote(ctx, vote) diff --git a/x/gov/keeper/tally_test.go b/x/gov/keeper/tally_test.go index c9b9954e67..e230858801 100644 --- a/x/gov/keeper/tally_test.go +++ b/x/gov/keeper/tally_test.go @@ -245,7 +245,7 @@ func TestTallyDelgatorOverride(t *testing.T) { addrs, valAddrs := createValidators(t, ctx, app, []int64{5, 6, 7}) - delTokens := sdk.TokensFromConsensusPower(30) + delTokens := app.StakingKeeper.TokensFromConsensusPower(ctx, 30) val1, found := app.StakingKeeper.GetValidator(ctx, valAddrs[0]) require.True(t, found) @@ -281,7 +281,7 @@ func TestTallyDelgatorInherit(t *testing.T) { addrs, vals := createValidators(t, ctx, app, []int64{5, 6, 7}) - delTokens := sdk.TokensFromConsensusPower(30) + delTokens := app.StakingKeeper.TokensFromConsensusPower(ctx, 30) val3, found := app.StakingKeeper.GetValidator(ctx, vals[2]) require.True(t, found) @@ -316,7 +316,7 @@ func TestTallyDelgatorMultipleOverride(t *testing.T) { addrs, vals := createValidators(t, ctx, app, []int64{5, 6, 7}) - delTokens := sdk.TokensFromConsensusPower(10) + delTokens := app.StakingKeeper.TokensFromConsensusPower(ctx, 10) val1, found := app.StakingKeeper.GetValidator(ctx, vals[0]) require.True(t, found) val2, found := app.StakingKeeper.GetValidator(ctx, vals[1]) @@ -358,7 +358,7 @@ func TestTallyDelgatorMultipleInherit(t *testing.T) { addrs, vals := createValidators(t, ctx, app, []int64{5, 6, 7}) - delTokens := sdk.TokensFromConsensusPower(10) + delTokens := app.StakingKeeper.TokensFromConsensusPower(ctx, 10) val2, found := app.StakingKeeper.GetValidator(ctx, vals[1]) require.True(t, found) val3, found := app.StakingKeeper.GetValidator(ctx, vals[2]) @@ -397,7 +397,7 @@ func TestTallyJailedValidator(t *testing.T) { addrs, valAddrs := createValidators(t, ctx, app, []int64{25, 6, 7}) - delTokens := sdk.TokensFromConsensusPower(10) + delTokens := app.StakingKeeper.TokensFromConsensusPower(ctx, 10) val2, found := app.StakingKeeper.GetValidator(ctx, valAddrs[1]) require.True(t, found) val3, found := app.StakingKeeper.GetValidator(ctx, valAddrs[2]) @@ -440,7 +440,7 @@ func TestTallyValidatorMultipleDelegations(t *testing.T) { addrs, valAddrs := createValidators(t, ctx, app, []int64{10, 10, 10}) - delTokens := sdk.TokensFromConsensusPower(10) + delTokens := app.StakingKeeper.TokensFromConsensusPower(ctx, 10) val2, found := app.StakingKeeper.GetValidator(ctx, valAddrs[1]) require.True(t, found) @@ -465,10 +465,10 @@ func TestTallyValidatorMultipleDelegations(t *testing.T) { require.True(t, passes) require.False(t, burnDeposits) - expectedYes := sdk.TokensFromConsensusPower(30) - expectedAbstain := sdk.TokensFromConsensusPower(0) - expectedNo := sdk.TokensFromConsensusPower(10) - expectedNoWithVeto := sdk.TokensFromConsensusPower(0) + expectedYes := app.StakingKeeper.TokensFromConsensusPower(ctx, 30) + expectedAbstain := app.StakingKeeper.TokensFromConsensusPower(ctx, 0) + expectedNo := app.StakingKeeper.TokensFromConsensusPower(ctx, 10) + expectedNoWithVeto := app.StakingKeeper.TokensFromConsensusPower(ctx, 0) expectedTallyResult := types.NewTallyResult(expectedYes, expectedAbstain, expectedNo, expectedNoWithVeto) require.True(t, tallyResults.Equals(expectedTallyResult)) diff --git a/x/gov/keeper/vote.go b/x/gov/keeper/vote.go index dbfdcf9c5c..ea6127b526 100644 --- a/x/gov/keeper/vote.go +++ b/x/gov/keeper/vote.go @@ -20,13 +20,16 @@ func (keeper Keeper) AddVote(ctx sdk.Context, proposalID uint64, voterAddr sdk.A for _, option := range options { if !types.ValidWeightedVoteOption(option) { - return sdkerrors.Wrap(types.ErrInvalidVote, options.String()) + return sdkerrors.Wrap(types.ErrInvalidVote, option.String()) } } vote := types.NewVote(proposalID, voterAddr, options) keeper.SetVote(ctx, vote) + // called after a vote on a proposal is cast + keeper.AfterProposalVote(ctx, proposalID, voterAddr) + ctx.EventManager().EmitEvent( sdk.NewEvent( types.EventTypeProposalVote, @@ -66,7 +69,7 @@ func (keeper Keeper) GetVote(ctx sdk.Context, proposalID uint64, voterAddr sdk.A return vote, false } - keeper.cdc.MustUnmarshalBinaryBare(bz, &vote) + keeper.cdc.MustUnmarshal(bz, &vote) populateLegacyOption(&vote) return vote, true @@ -80,7 +83,7 @@ func (keeper Keeper) SetVote(ctx sdk.Context, vote types.Vote) { } store := ctx.KVStore(keeper.storeKey) - bz := keeper.cdc.MustMarshalBinaryBare(&vote) + bz := keeper.cdc.MustMarshal(&vote) addr := sdk.AccAddress(vote.Voter) store.Set(types.VoteKey(vote.ProposalId, addr), bz) } @@ -93,7 +96,7 @@ func (keeper Keeper) IterateAllVotes(ctx sdk.Context, cb func(vote types.Vote) ( defer iterator.Close() for ; iterator.Valid(); iterator.Next() { var vote types.Vote - keeper.cdc.MustUnmarshalBinaryBare(iterator.Value(), &vote) + keeper.cdc.MustUnmarshal(iterator.Value(), &vote) populateLegacyOption(&vote) if cb(vote) { @@ -110,7 +113,7 @@ func (keeper Keeper) IterateVotes(ctx sdk.Context, proposalID uint64, cb func(vo defer iterator.Close() for ; iterator.Valid(); iterator.Next() { var vote types.Vote - keeper.cdc.MustUnmarshalBinaryBare(iterator.Value(), &vote) + keeper.cdc.MustUnmarshal(iterator.Value(), &vote) populateLegacyOption(&vote) if cb(vote) { diff --git a/x/gov/legacy/v040/keys.go b/x/gov/legacy/v040/keys.go new file mode 100644 index 0000000000..a22925c7fd --- /dev/null +++ b/x/gov/legacy/v040/keys.go @@ -0,0 +1,167 @@ +// Package v040 is copy-pasted from: +// https://github.com/cosmos/cosmos-sdk/blob/v0.41.0/x/gov/types/keys.go +package v040 + +import ( + "encoding/binary" + "fmt" + "time" + + sdk "github.com/line/lbm-sdk/types" + v040auth "github.com/line/lbm-sdk/x/auth/legacy/v040" +) + +const ( + // ModuleName is the name of the module + ModuleName = "gov" + + // StoreKey is the store key string for gov + StoreKey = ModuleName + + // RouterKey is the message route for gov + RouterKey = ModuleName + + // QuerierRoute is the querier route for gov + QuerierRoute = ModuleName +) + +// Keys for governance store +// Items are stored with the following key: values +// +// - 0x00: Proposal +// +// - 0x01: activeProposalID +// +// - 0x02: inactiveProposalID +// +// - 0x03: nextProposalID +// +// - 0x10: Deposit +// +// - 0x20: Voter +var ( + ProposalsKeyPrefix = []byte{0x00} + ActiveProposalQueuePrefix = []byte{0x01} + InactiveProposalQueuePrefix = []byte{0x02} + ProposalIDKey = []byte{0x03} + + DepositsKeyPrefix = []byte{0x10} + + VotesKeyPrefix = []byte{0x20} +) + +var lenTime = len(sdk.FormatTimeBytes(time.Now())) + +// GetProposalIDBytes returns the byte representation of the proposalID +func GetProposalIDBytes(proposalID uint64) (proposalIDBz []byte) { + proposalIDBz = make([]byte, 8) + binary.BigEndian.PutUint64(proposalIDBz, proposalID) + return +} + +// GetProposalIDFromBytes returns proposalID in uint64 format from a byte array +func GetProposalIDFromBytes(bz []byte) (proposalID uint64) { + return binary.BigEndian.Uint64(bz) +} + +// ProposalKey gets a specific proposal from the store +func ProposalKey(proposalID uint64) []byte { + return append(ProposalsKeyPrefix, GetProposalIDBytes(proposalID)...) +} + +// ActiveProposalByTimeKey gets the active proposal queue key by endTime +func ActiveProposalByTimeKey(endTime time.Time) []byte { + return append(ActiveProposalQueuePrefix, sdk.FormatTimeBytes(endTime)...) +} + +// ActiveProposalQueueKey returns the key for a proposalID in the activeProposalQueue +func ActiveProposalQueueKey(proposalID uint64, endTime time.Time) []byte { + return append(ActiveProposalByTimeKey(endTime), GetProposalIDBytes(proposalID)...) +} + +// InactiveProposalByTimeKey gets the inactive proposal queue key by endTime +func InactiveProposalByTimeKey(endTime time.Time) []byte { + return append(InactiveProposalQueuePrefix, sdk.FormatTimeBytes(endTime)...) +} + +// InactiveProposalQueueKey returns the key for a proposalID in the inactiveProposalQueue +func InactiveProposalQueueKey(proposalID uint64, endTime time.Time) []byte { + return append(InactiveProposalByTimeKey(endTime), GetProposalIDBytes(proposalID)...) +} + +// DepositsKey gets the first part of the deposits key based on the proposalID +func DepositsKey(proposalID uint64) []byte { + return append(DepositsKeyPrefix, GetProposalIDBytes(proposalID)...) +} + +// DepositKey key of a specific deposit from the store +func DepositKey(proposalID uint64, depositorAddr sdk.AccAddress) []byte { + return append(DepositsKey(proposalID), depositorAddr.Bytes()...) +} + +// VotesKey gets the first part of the votes key based on the proposalID +func VotesKey(proposalID uint64) []byte { + return append(VotesKeyPrefix, GetProposalIDBytes(proposalID)...) +} + +// VoteKey key of a specific vote from the store +func VoteKey(proposalID uint64, voterAddr sdk.AccAddress) []byte { + return append(VotesKey(proposalID), voterAddr.Bytes()...) +} + +// Split keys function; used for iterators + +// SplitProposalKey split the proposal key and returns the proposal id +func SplitProposalKey(key []byte) (proposalID uint64) { + if len(key[1:]) != 8 { + panic(fmt.Sprintf("unexpected key length (%d ≠ 8)", len(key[1:]))) + } + + return GetProposalIDFromBytes(key[1:]) +} + +// SplitActiveProposalQueueKey split the active proposal key and returns the proposal id and endTime +func SplitActiveProposalQueueKey(key []byte) (proposalID uint64, endTime time.Time) { + return splitKeyWithTime(key) +} + +// SplitInactiveProposalQueueKey split the inactive proposal key and returns the proposal id and endTime +func SplitInactiveProposalQueueKey(key []byte) (proposalID uint64, endTime time.Time) { + return splitKeyWithTime(key) +} + +// SplitKeyDeposit split the deposits key and returns the proposal id and depositor address +func SplitKeyDeposit(key []byte) (proposalID uint64, depositorAddr sdk.AccAddress) { + return splitKeyWithAddress(key) +} + +// SplitKeyVote split the votes key and returns the proposal id and voter address +func SplitKeyVote(key []byte) (proposalID uint64, voterAddr sdk.AccAddress) { + return splitKeyWithAddress(key) +} + +// private functions + +func splitKeyWithTime(key []byte) (proposalID uint64, endTime time.Time) { + if len(key[1:]) != 8+lenTime { + panic(fmt.Sprintf("unexpected key length (%d ≠ %d)", len(key[1:]), lenTime+8)) + } + + endTime, err := sdk.ParseTimeBytes(key[1 : 1+lenTime]) + if err != nil { + panic(err) + } + + proposalID = GetProposalIDFromBytes(key[1+lenTime:]) + return +} + +func splitKeyWithAddress(key []byte) (proposalID uint64, addr sdk.AccAddress) { + if len(key[1:]) != 8+v040auth.AddrLen { + panic(fmt.Sprintf("unexpected key length (%d ≠ %d)", len(key), 8+v040auth.AddrLen)) + } + + proposalID = GetProposalIDFromBytes(key[1:9]) + addr = sdk.AccAddress(key[9:]) + return +} diff --git a/x/gov/legacy/v043/json.go b/x/gov/legacy/v043/json.go new file mode 100644 index 0000000000..1c3d19bac6 --- /dev/null +++ b/x/gov/legacy/v043/json.go @@ -0,0 +1,31 @@ +package v043 + +import ( + "github.com/line/lbm-sdk/x/gov/types" +) + +// migrateWeightedVotes migrates the ADR-037 weighted votes. +func migrateJSONWeightedVotes(oldVotes types.Votes) types.Votes { + newVotes := make(types.Votes, len(oldVotes)) + for i, oldVote := range oldVotes { + newVotes[i] = migrateVote(oldVote) + } + + return newVotes +} + +// MigrateJSON accepts exported v0.40 x/gov genesis state and migrates it to +// v0.43 x/gov genesis state. The migration includes: +// +// - Gov weighted votes. +func MigrateJSON(oldState *types.GenesisState) *types.GenesisState { + return &types.GenesisState{ + StartingProposalId: oldState.StartingProposalId, + Deposits: oldState.Deposits, + Votes: migrateJSONWeightedVotes(oldState.Votes), + Proposals: oldState.Proposals, + DepositParams: oldState.DepositParams, + VotingParams: oldState.VotingParams, + TallyParams: oldState.TallyParams, + } +} diff --git a/x/gov/legacy/v043/json_test.go b/x/gov/legacy/v043/json_test.go new file mode 100644 index 0000000000..84e50818b4 --- /dev/null +++ b/x/gov/legacy/v043/json_test.go @@ -0,0 +1,129 @@ +package v043_test + +import ( + "encoding/json" + "fmt" + "testing" + + "github.com/stretchr/testify/require" + + "github.com/line/lbm-sdk/client" + "github.com/line/lbm-sdk/simapp" + sdk "github.com/line/lbm-sdk/types" + v043gov "github.com/line/lbm-sdk/x/gov/legacy/v043" + "github.com/line/lbm-sdk/x/gov/types" +) + +func TestMigrateJSON(t *testing.T) { + encodingConfig := simapp.MakeTestEncodingConfig() + clientCtx := client.Context{}. + WithInterfaceRegistry(encodingConfig.InterfaceRegistry). + WithTxConfig(encodingConfig.TxConfig). + WithCodec(encodingConfig.Marshaler) + + voter := sdk.AccAddress("link1fl48vsnmsdzcv85q5d2q4z5ajdha8yu3q4fdzl") + err := sdk.ValidateAccAddress(voter.String()) + require.NoError(t, err) + govGenState := &types.GenesisState{ + Votes: types.Votes{ + types.Vote{ProposalId: 1, Voter: voter.String(), Option: types.OptionAbstain}, + types.Vote{ProposalId: 2, Voter: voter.String(), Option: types.OptionEmpty}, + types.Vote{ProposalId: 3, Voter: voter.String(), Option: types.OptionNo}, + types.Vote{ProposalId: 4, Voter: voter.String(), Option: types.OptionNoWithVeto}, + types.Vote{ProposalId: 5, Voter: voter.String(), Option: types.OptionYes}, + }, + } + + migrated := v043gov.MigrateJSON(govGenState) + + bz, err := clientCtx.Codec.MarshalJSON(migrated) + require.NoError(t, err) + + // Indent the JSON bz correctly. + var jsonObj map[string]interface{} + err = json.Unmarshal(bz, &jsonObj) + require.NoError(t, err) + indentedBz, err := json.MarshalIndent(jsonObj, "", "\t") + require.NoError(t, err) + + // Make sure about: + // - Votes are all ADR-037 weighted votes with weight 1. + expected := `{ + "deposit_params": { + "max_deposit_period": "0s", + "min_deposit": [] + }, + "deposits": [], + "proposals": [], + "starting_proposal_id": "0", + "tally_params": { + "quorum": "0", + "threshold": "0", + "veto_threshold": "0" + }, + "votes": [ + { + "option": "VOTE_OPTION_UNSPECIFIED", + "options": [ + { + "option": "VOTE_OPTION_ABSTAIN", + "weight": "1.000000000000000000" + } + ], + "proposal_id": "1", + "voter": "link1fl48vsnmsdzcv85q5d2q4z5ajdha8yu3q4fdzl" + }, + { + "option": "VOTE_OPTION_UNSPECIFIED", + "options": [ + { + "option": "VOTE_OPTION_UNSPECIFIED", + "weight": "1.000000000000000000" + } + ], + "proposal_id": "2", + "voter": "link1fl48vsnmsdzcv85q5d2q4z5ajdha8yu3q4fdzl" + }, + { + "option": "VOTE_OPTION_UNSPECIFIED", + "options": [ + { + "option": "VOTE_OPTION_NO", + "weight": "1.000000000000000000" + } + ], + "proposal_id": "3", + "voter": "link1fl48vsnmsdzcv85q5d2q4z5ajdha8yu3q4fdzl" + }, + { + "option": "VOTE_OPTION_UNSPECIFIED", + "options": [ + { + "option": "VOTE_OPTION_NO_WITH_VETO", + "weight": "1.000000000000000000" + } + ], + "proposal_id": "4", + "voter": "link1fl48vsnmsdzcv85q5d2q4z5ajdha8yu3q4fdzl" + }, + { + "option": "VOTE_OPTION_UNSPECIFIED", + "options": [ + { + "option": "VOTE_OPTION_YES", + "weight": "1.000000000000000000" + } + ], + "proposal_id": "5", + "voter": "link1fl48vsnmsdzcv85q5d2q4z5ajdha8yu3q4fdzl" + } + ], + "voting_params": { + "voting_period": "0s" + } +}` + + fmt.Println(string(indentedBz)) + + require.Equal(t, expected, string(indentedBz)) +} diff --git a/x/gov/legacy/v043/keys.go b/x/gov/legacy/v043/keys.go new file mode 100644 index 0000000000..8a2528ce5c --- /dev/null +++ b/x/gov/legacy/v043/keys.go @@ -0,0 +1,6 @@ +package v043 + +const ( + // ModuleName is the name of the module + ModuleName = "gov" +) diff --git a/x/gov/legacy/v043/store.go b/x/gov/legacy/v043/store.go new file mode 100644 index 0000000000..8e2ce8df2b --- /dev/null +++ b/x/gov/legacy/v043/store.go @@ -0,0 +1,81 @@ +package v043 + +import ( + "fmt" + + "github.com/line/lbm-sdk/codec" + "github.com/line/lbm-sdk/store/prefix" + sdk "github.com/line/lbm-sdk/types" + "github.com/line/lbm-sdk/types/address" + "github.com/line/lbm-sdk/x/gov/types" +) + +const proposalIDLen = 8 + +// migratePrefixProposalAddress is a helper function that migrates all keys of format: +// +// into format: +// +func migratePrefixProposalAddress(store sdk.KVStore, prefixBz []byte) { + oldStore := prefix.NewStore(store, prefixBz) + + oldStoreIter := oldStore.Iterator(nil, nil) + defer oldStoreIter.Close() + + for ; oldStoreIter.Valid(); oldStoreIter.Next() { + proposalID := oldStoreIter.Key()[:proposalIDLen] + addr := oldStoreIter.Key()[proposalIDLen:] + newStoreKey := append(append(prefixBz, proposalID...), address.MustLengthPrefix(addr)...) + + // Set new key on store. Values don't change. + store.Set(newStoreKey, oldStoreIter.Value()) + oldStore.Delete(oldStoreIter.Key()) + } +} + +// migrateStoreWeightedVotes migrates a legacy vote to an ADR-037 weighted vote. +// Important: the `oldVote` has its `Option` field set, whereas the new weighted +// vote has its `Options` field set. +func migrateVote(oldVote types.Vote) types.Vote { + return types.Vote{ + ProposalId: oldVote.ProposalId, + Voter: oldVote.Voter, + Options: types.NewNonSplitVoteOption(oldVote.Option), // nolint: staticcheck + } +} + +// migrateStoreWeightedVotes migrates in-place all legacy votes to ADR-037 weighted votes. +func migrateStoreWeightedVotes(store sdk.KVStore, cdc codec.BinaryCodec) error { + iterator := sdk.KVStorePrefixIterator(store, types.VotesKeyPrefix) + + defer iterator.Close() + for ; iterator.Valid(); iterator.Next() { + var oldVote types.Vote + err := cdc.Unmarshal(iterator.Value(), &oldVote) + if err != nil { + return err + } + + newVote := migrateVote(oldVote) + fmt.Println("migrateStoreWeightedVotes newVote=", newVote) + bz, err := cdc.Marshal(&newVote) + if err != nil { + return err + } + + store.Set(iterator.Key(), bz) + } + + return nil +} + +// MigrateStore performs in-place store migrations from v0.40 to v0.43. The +// migration includes: +// +// - Change addresses to be length-prefixed. +func MigrateStore(ctx sdk.Context, storeKey sdk.StoreKey, cdc codec.BinaryCodec) error { + store := ctx.KVStore(storeKey) + migratePrefixProposalAddress(store, types.DepositsKeyPrefix) + migratePrefixProposalAddress(store, types.VotesKeyPrefix) + return migrateStoreWeightedVotes(store, cdc) +} diff --git a/x/gov/legacy/v043/store_test.go b/x/gov/legacy/v043/store_test.go new file mode 100644 index 0000000000..c01931bd5d --- /dev/null +++ b/x/gov/legacy/v043/store_test.go @@ -0,0 +1,91 @@ +package v043_test + +import ( + "bytes" + "testing" + "time" + + "github.com/stretchr/testify/require" + + "github.com/line/lbm-sdk/simapp" + "github.com/line/lbm-sdk/testutil" + "github.com/line/lbm-sdk/testutil/testdata" + sdk "github.com/line/lbm-sdk/types" + v040gov "github.com/line/lbm-sdk/x/gov/legacy/v040" + v043gov "github.com/line/lbm-sdk/x/gov/legacy/v043" + "github.com/line/lbm-sdk/x/gov/types" +) + +func TestMigrateStore(t *testing.T) { + cdc := simapp.MakeTestEncodingConfig().Marshaler + govKey := sdk.NewKVStoreKey("gov") + ctx := testutil.DefaultContext(govKey, sdk.NewTransientStoreKey("transient_test")) + store := ctx.KVStore(govKey) + + _, _, addr1 := testdata.KeyTestPubAddr() + proposalID := uint64(6) + now := time.Now() + // Use dummy value for keys where we don't test values. + dummyValue := []byte("foo") + // Use real values for votes, as we're testing weighted votes. + oldVote := types.Vote{ProposalId: 1, Voter: "foobar", Option: types.OptionNoWithVeto} + oldVoteValue := cdc.MustMarshal(&oldVote) + newVote := types.Vote{ProposalId: 1, Voter: "foobar", Options: types.WeightedVoteOptions{{Option: types.OptionNoWithVeto, Weight: sdk.NewDec(1)}}} + newVoteValue := cdc.MustMarshal(&newVote) + + testCases := []struct { + name string + oldKey, oldValue, newKey, newValue []byte + }{ + { + "ProposalKey", + v040gov.ProposalKey(proposalID), dummyValue, + types.ProposalKey(proposalID), dummyValue, + }, + { + "ActiveProposalQueue", + v040gov.ActiveProposalQueueKey(proposalID, now), dummyValue, + types.ActiveProposalQueueKey(proposalID, now), dummyValue, + }, + { + "InactiveProposalQueue", + v040gov.InactiveProposalQueueKey(proposalID, now), dummyValue, + types.InactiveProposalQueueKey(proposalID, now), dummyValue, + }, + { + "ProposalIDKey", + v040gov.ProposalIDKey, dummyValue, + types.ProposalIDKey, dummyValue, + }, + { + "DepositKey", + v040gov.DepositKey(proposalID, addr1), dummyValue, + types.DepositKey(proposalID, addr1), dummyValue, + }, + { + "VotesKeyPrefix", + v040gov.VoteKey(proposalID, addr1), oldVoteValue, + types.VoteKey(proposalID, addr1), newVoteValue, + }, + } + + // Set all the old keys to the store + for _, tc := range testCases { + store.Set(tc.oldKey, tc.oldValue) + } + + // Run migrations. + err := v043gov.MigrateStore(ctx, govKey, cdc) + require.NoError(t, err) + + // Make sure the new keys are set and old keys are deleted. + for _, tc := range testCases { + tc := tc + t.Run(tc.name, func(t *testing.T) { + if !bytes.Equal(tc.oldKey, tc.newKey) { + require.Nil(t, store.Get(tc.oldKey)) + } + require.Equal(t, tc.newValue, store.Get(tc.newKey)) + }) + } +} diff --git a/x/gov/module.go b/x/gov/module.go index 21ef62330f..6655468c37 100644 --- a/x/gov/module.go +++ b/x/gov/module.go @@ -8,9 +8,8 @@ import ( "fmt" "math/rand" - "github.com/grpc-ecosystem/grpc-gateway/runtime" - "github.com/gorilla/mux" + "github.com/grpc-ecosystem/grpc-gateway/runtime" "github.com/spf13/cobra" abci "github.com/line/ostracon/abci/types" @@ -37,7 +36,7 @@ var ( // AppModuleBasic defines the basic application module used by the gov module. type AppModuleBasic struct { - cdc codec.Marshaler + cdc codec.Codec proposalHandlers []govclient.ProposalHandler // proposal handlers which live in governance cli and rest } @@ -60,12 +59,12 @@ func (AppModuleBasic) RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) { // DefaultGenesis returns default genesis state as raw bytes for the gov // module. -func (AppModuleBasic) DefaultGenesis(cdc codec.JSONMarshaler) json.RawMessage { +func (AppModuleBasic) DefaultGenesis(cdc codec.JSONCodec) json.RawMessage { return cdc.MustMarshalJSON(types.DefaultGenesisState()) } // ValidateGenesis performs genesis state validation for the gov module. -func (AppModuleBasic) ValidateGenesis(cdc codec.JSONMarshaler, config client.TxEncodingConfig, bz json.RawMessage) error { +func (AppModuleBasic) ValidateGenesis(cdc codec.JSONCodec, config client.TxEncodingConfig, bz json.RawMessage) error { var data types.GenesisState if err := cdc.UnmarshalJSON(bz, &data); err != nil { return fmt.Errorf("failed to unmarshal %s genesis state: %w", types.ModuleName, err) @@ -109,8 +108,6 @@ func (a AppModuleBasic) RegisterInterfaces(registry codectypes.InterfaceRegistry types.RegisterInterfaces(registry) } -// ____________________________________________________________________________ - // AppModule implements an application module for the gov module. type AppModule struct { AppModuleBasic @@ -121,7 +118,7 @@ type AppModule struct { } // NewAppModule creates a new AppModule object -func NewAppModule(cdc codec.Marshaler, keeper keeper.Keeper, ak types.AccountKeeper, bk types.BankKeeper) AppModule { +func NewAppModule(cdc codec.Codec, keeper keeper.Keeper, ak types.AccountKeeper, bk types.BankKeeper) AppModule { return AppModule{ AppModuleBasic: AppModuleBasic{cdc: cdc}, keeper: keeper, @@ -168,7 +165,7 @@ func (am AppModule) RegisterServices(cfg module.Configurator) { // InitGenesis performs genesis initialization for the gov module. It returns // no validator updates. -func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONMarshaler, data json.RawMessage) []abci.ValidatorUpdate { +func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONCodec, data json.RawMessage) []abci.ValidatorUpdate { var genesisState types.GenesisState cdc.MustUnmarshalJSON(data, &genesisState) InitGenesis(ctx, am.accountKeeper, am.bankKeeper, am.keeper, &genesisState) @@ -177,7 +174,7 @@ func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONMarshaler, data j // ExportGenesis returns the exported genesis state as raw bytes for the gov // module. -func (am AppModule) ExportGenesis(ctx sdk.Context, cdc codec.JSONMarshaler) json.RawMessage { +func (am AppModule) ExportGenesis(ctx sdk.Context, cdc codec.JSONCodec) json.RawMessage { gs := ExportGenesis(ctx, am.keeper) return cdc.MustMarshalJSON(gs) } @@ -195,8 +192,6 @@ func (am AppModule) EndBlock(ctx sdk.Context, _ abci.RequestEndBlock) []abci.Val return []abci.ValidatorUpdate{} } -// ____________________________________________________________________________ - // AppModuleSimulation functions // GenerateGenesisState creates a randomized GenState of the gov module. diff --git a/x/gov/simulation/decoder.go b/x/gov/simulation/decoder.go index 9561d435dc..579b6f305f 100644 --- a/x/gov/simulation/decoder.go +++ b/x/gov/simulation/decoder.go @@ -12,17 +12,17 @@ import ( // NewDecodeStore returns a decoder function closure that unmarshals the KVPair's // Value to the corresponding gov type. -func NewDecodeStore(cdc codec.Marshaler) func(kvA, kvB kv.Pair) string { +func NewDecodeStore(cdc codec.Codec) func(kvA, kvB kv.Pair) string { return func(kvA, kvB kv.Pair) string { switch { case bytes.Equal(kvA.Key[:1], types.ProposalsKeyPrefix): var proposalA types.Proposal - err := cdc.UnmarshalBinaryBare(kvA.Value, &proposalA) + err := cdc.Unmarshal(kvA.Value, &proposalA) if err != nil { panic(err) } var proposalB types.Proposal - err = cdc.UnmarshalBinaryBare(kvA.Value, &proposalB) + err = cdc.Unmarshal(kvB.Value, &proposalB) if err != nil { panic(err) } @@ -37,14 +37,14 @@ func NewDecodeStore(cdc codec.Marshaler) func(kvA, kvB kv.Pair) string { case bytes.Equal(kvA.Key[:1], types.DepositsKeyPrefix): var depositA, depositB types.Deposit - cdc.MustUnmarshalBinaryBare(kvA.Value, &depositA) - cdc.MustUnmarshalBinaryBare(kvB.Value, &depositB) + cdc.MustUnmarshal(kvA.Value, &depositA) + cdc.MustUnmarshal(kvB.Value, &depositB) return fmt.Sprintf("%v\n%v", depositA, depositB) case bytes.Equal(kvA.Key[:1], types.VotesKeyPrefix): var voteA, voteB types.Vote - cdc.MustUnmarshalBinaryBare(kvA.Value, &voteA) - cdc.MustUnmarshalBinaryBare(kvB.Value, &voteB) + cdc.MustUnmarshal(kvA.Value, &voteA) + cdc.MustUnmarshal(kvB.Value, &voteB) return fmt.Sprintf("%v\n%v", voteA, voteB) default: diff --git a/x/gov/simulation/decoder_test.go b/x/gov/simulation/decoder_test.go index 9e1370db08..7cb28ebf57 100644 --- a/x/gov/simulation/decoder_test.go +++ b/x/gov/simulation/decoder_test.go @@ -22,13 +22,14 @@ var ( ) func TestDecodeStore(t *testing.T) { - cdc, _ := simapp.MakeCodecs() + cdc := simapp.MakeTestEncodingConfig().Marshaler dec := simulation.NewDecodeStore(cdc) endTime := time.Now().UTC() - content := types.ContentFromProposalType("test", "test", types.ProposalTypeText) - proposal, err := types.NewProposal(content, 1, endTime, endTime.Add(24*time.Hour)) + proposalA, err := types.NewProposal(content, 1, endTime, endTime.Add(24*time.Hour)) + require.NoError(t, err) + proposalB, err := types.NewProposal(content, 2, endTime, endTime.Add(24*time.Hour)) require.NoError(t, err) proposalIDBz := make([]byte, 8) @@ -36,38 +37,56 @@ func TestDecodeStore(t *testing.T) { deposit := types.NewDeposit(1, delAddr1, sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.OneInt()))) vote := types.NewVote(1, delAddr1, types.NewNonSplitVoteOption(types.OptionYes)) - proposalBz, err := cdc.MarshalBinaryBare(&proposal) + proposalBzA, err := cdc.Marshal(&proposalA) + require.NoError(t, err) + proposalBzB, err := cdc.Marshal(&proposalB) require.NoError(t, err) - - kvPairs := kv.Pairs{ - Pairs: []kv.Pair{ - {Key: types.ProposalKey(1), Value: proposalBz}, - {Key: types.InactiveProposalQueueKey(1, endTime), Value: proposalIDBz}, - {Key: types.DepositKey(1, delAddr1), Value: cdc.MustMarshalBinaryBare(&deposit)}, - {Key: types.VoteKey(1, delAddr1), Value: cdc.MustMarshalBinaryBare(&vote)}, - {Key: []byte{0x99}, Value: []byte{0x99}}, - }, - } tests := []struct { name string + kvA, kvB kv.Pair expectedLog string + wantPanic bool }{ - {"proposals", fmt.Sprintf("%v\n%v", proposal, proposal)}, - {"proposal IDs", "proposalIDA: 1\nProposalIDB: 1"}, - {"deposits", fmt.Sprintf("%v\n%v", deposit, deposit)}, - {"votes", fmt.Sprintf("%v\n%v", vote, vote)}, - {"other", ""}, + { + "proposals", + kv.Pair{Key: types.ProposalKey(1), Value: proposalBzA}, + kv.Pair{Key: types.ProposalKey(2), Value: proposalBzB}, + fmt.Sprintf("%v\n%v", proposalA, proposalB), false, + }, + { + "proposal IDs", + kv.Pair{Key: types.InactiveProposalQueueKey(1, endTime), Value: proposalIDBz}, + kv.Pair{Key: types.InactiveProposalQueueKey(1, endTime), Value: proposalIDBz}, + "proposalIDA: 1\nProposalIDB: 1", false, + }, + { + "deposits", + kv.Pair{Key: types.DepositKey(1, delAddr1), Value: cdc.MustMarshal(&deposit)}, + kv.Pair{Key: types.DepositKey(1, delAddr1), Value: cdc.MustMarshal(&deposit)}, + fmt.Sprintf("%v\n%v", deposit, deposit), false, + }, + { + "votes", + kv.Pair{Key: types.VoteKey(1, delAddr1), Value: cdc.MustMarshal(&vote)}, + kv.Pair{Key: types.VoteKey(1, delAddr1), Value: cdc.MustMarshal(&vote)}, + fmt.Sprintf("%v\n%v", vote, vote), false, + }, + { + "other", + kv.Pair{Key: []byte{0x99}, Value: []byte{0x99}}, + kv.Pair{Key: []byte{0x99}, Value: []byte{0x99}}, + "", true, + }, } - for i, tt := range tests { - i, tt := i, tt + for _, tt := range tests { + tt := tt t.Run(tt.name, func(t *testing.T) { - switch i { - case len(tests) - 1: - require.Panics(t, func() { dec(kvPairs.Pairs[i], kvPairs.Pairs[i]) }, tt.name) - default: - require.Equal(t, tt.expectedLog, dec(kvPairs.Pairs[i], kvPairs.Pairs[i]), tt.name) + if tt.wantPanic { + require.Panics(t, func() { dec(tt.kvA, tt.kvB) }, tt.name) + } else { + require.Equal(t, tt.expectedLog, dec(tt.kvA, tt.kvB), tt.name) } }) } diff --git a/x/gov/simulation/operations.go b/x/gov/simulation/operations.go index 5f73239e91..84b5755310 100644 --- a/x/gov/simulation/operations.go +++ b/x/gov/simulation/operations.go @@ -18,6 +18,7 @@ import ( var initialProposalID = uint64(100000000000000) +// nolint:gosec // Simulation operation weights constants const ( OpWeightMsgDeposit = "op_weight_msg_deposit" @@ -27,7 +28,7 @@ const ( // WeightedOperations returns all the operations from the module with their respective weights func WeightedOperations( - appParams simtypes.AppParams, cdc codec.JSONMarshaler, ak types.AccountKeeper, + appParams simtypes.AppParams, cdc codec.JSONCodec, ak types.AccountKeeper, bk types.BankKeeper, k keeper.Keeper, wContents []simtypes.WeightedProposalContent, ) simulation.WeightedOperations { @@ -91,7 +92,7 @@ func WeightedOperations( return append(wProposalOps, wGovOps...) } -// SimulateSubmitProposal simulates creating a msg Submit Proposal +// SimulateMsgSubmitProposal simulates creating a msg Submit Proposal // voting on the proposal, and subsequently slashing the proposal. It is implemented using // future operations. func SimulateMsgSubmitProposal( @@ -174,7 +175,7 @@ func SimulateMsgSubmitProposal( return simtypes.NoOpMsg(types.ModuleName, msg.Type(), "unable to deliver tx"), nil, err } - opMsg := simtypes.NewOperationMsg(msg, true, "") + opMsg := simtypes.NewOperationMsg(msg, true, "", nil) // get the submitted proposal ID proposalID, err := k.GetProposalID(ctx) @@ -241,26 +242,19 @@ func SimulateMsgDeposit(ak types.AccountKeeper, bk types.BankKeeper, k keeper.Ke } } - txGen := simappparams.MakeTestEncodingConfig().TxConfig - tx, err := helpers.GenTx( - txGen, - []sdk.Msg{msg}, - fees, - helpers.DefaultGenTxGas, - chainID, - []uint64{account.GetAccountNumber()}, - []uint64{account.GetSequence()}, - simAccount.PrivKey, - ) - if err != nil { - return simtypes.NoOpMsg(types.ModuleName, msg.Type(), "unable to generate mock tx"), nil, err - } - _, _, err = app.Deliver(txGen.TxEncoder(), tx) - if err != nil { - return simtypes.NoOpMsg(types.ModuleName, msg.Type(), "unable to deliver tx"), nil, err + txCtx := simulation.OperationInput{ + App: app, + TxGen: simappparams.MakeTestEncodingConfig().TxConfig, + Cdc: nil, + Msg: msg, + MsgType: msg.Type(), + Context: ctx, + SimAccount: simAccount, + AccountKeeper: ak, + ModuleName: types.ModuleName, } - return simtypes.NewOperationMsg(msg, true, ""), nil, nil + return simulation.GenAndDeliverTx(txCtx, fees) } } @@ -298,32 +292,22 @@ func operationSimulateMsgVote(ak types.AccountKeeper, bk types.BankKeeper, k kee account := ak.GetAccount(ctx, simAccount.Address) spendable := bk.SpendableCoins(ctx, account.GetAddress()) - fees, err := simtypes.RandomFees(r, ctx, spendable) - if err != nil { - return simtypes.NoOpMsg(types.ModuleName, msg.Type(), "unable to generate fees"), nil, err - } - - txGen := simappparams.MakeTestEncodingConfig().TxConfig - tx, err := helpers.GenTx( - txGen, - []sdk.Msg{msg}, - fees, - helpers.DefaultGenTxGas, - chainID, - []uint64{account.GetAccountNumber()}, - []uint64{account.GetSequence()}, - simAccount.PrivKey, - ) - if err != nil { - return simtypes.NoOpMsg(types.ModuleName, msg.Type(), "unable to generate mock tx"), nil, err - } - - _, _, err = app.Deliver(txGen.TxEncoder(), tx) - if err != nil { - return simtypes.NoOpMsg(types.ModuleName, msg.Type(), "unable to deliver tx"), nil, err + txCtx := simulation.OperationInput{ + R: r, + App: app, + TxGen: simappparams.MakeTestEncodingConfig().TxConfig, + Cdc: nil, + Msg: msg, + MsgType: msg.Type(), + Context: ctx, + SimAccount: simAccount, + AccountKeeper: ak, + Bankkeeper: bk, + ModuleName: types.ModuleName, + CoinsSpentInMsg: spendable, } - return simtypes.NewOperationMsg(msg, true, ""), nil, nil + return simulation.GenAndDeliverTxWithRandFees(txCtx) } } @@ -361,32 +345,22 @@ func operationSimulateMsgVoteWeighted(ak types.AccountKeeper, bk types.BankKeepe account := ak.GetAccount(ctx, simAccount.Address) spendable := bk.SpendableCoins(ctx, account.GetAddress()) - fees, err := simtypes.RandomFees(r, ctx, spendable) - if err != nil { - return simtypes.NoOpMsg(types.ModuleName, msg.Type(), "unable to generate fees"), nil, err - } - - txGen := simappparams.MakeTestEncodingConfig().TxConfig - tx, err := helpers.GenTx( - txGen, - []sdk.Msg{msg}, - fees, - helpers.DefaultGenTxGas, - ctx.ChainID(), - []uint64{account.GetAccountNumber()}, - []uint64{account.GetSequence()}, - simAccount.PrivKey, - ) - if err != nil { - return simtypes.NoOpMsg(types.ModuleName, msg.Type(), "unable to generate mock tx"), nil, err - } - - _, _, err = app.Deliver(txGen.TxEncoder(), tx) - if err != nil { - return simtypes.NoOpMsg(types.ModuleName, msg.Type(), "unable to deliver tx"), nil, err + txCtx := simulation.OperationInput{ + R: r, + App: app, + TxGen: simappparams.MakeTestEncodingConfig().TxConfig, + Cdc: nil, + Msg: msg, + MsgType: msg.Type(), + Context: ctx, + SimAccount: simAccount, + AccountKeeper: ak, + Bankkeeper: bk, + ModuleName: types.ModuleName, + CoinsSpentInMsg: spendable, } - return simtypes.NewOperationMsg(msg, true, ""), nil, nil + return simulation.GenAndDeliverTxWithRandFees(txCtx) } } diff --git a/x/gov/simulation/operations_test.go b/x/gov/simulation/operations_test.go index baf8869937..455a7b19b3 100644 --- a/x/gov/simulation/operations_test.go +++ b/x/gov/simulation/operations_test.go @@ -206,7 +206,6 @@ func TestSimulateMsgVote(t *testing.T) { require.Equal(t, types.OptionYes, msg.Option) require.Equal(t, "gov", msg.Route()) require.Equal(t, types.TypeMsgVote, msg.Type()) - } // TestSimulateMsgVoteWeighted tests the normal scenario of a valid message of type TypeMsgVoteWeighted. @@ -265,15 +264,14 @@ func createTestApp(isCheckTx bool) (*simapp.SimApp, sdk.Context) { func getTestingAccounts(t *testing.T, r *rand.Rand, app *simapp.SimApp, ctx sdk.Context, n int) []simtypes.Account { accounts := simtypes.RandomAccounts(r, n) - initAmt := sdk.TokensFromConsensusPower(200) + initAmt := app.StakingKeeper.TokensFromConsensusPower(ctx, 200) initCoins := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, initAmt)) // add coins to the accounts for _, account := range accounts { acc := app.AccountKeeper.NewAccountWithAddress(ctx, account.Address) app.AccountKeeper.SetAccount(ctx, acc) - err := app.BankKeeper.SetBalances(ctx, account.Address, initCoins) - require.NoError(t, err) + require.NoError(t, simapp.FundAccount(app, ctx, account.Address, initCoins)) } return accounts diff --git a/x/gov/spec/01_concepts.md b/x/gov/spec/01_concepts.md index 0acbfa3b70..29e582990b 100644 --- a/x/gov/spec/01_concepts.md +++ b/x/gov/spec/01_concepts.md @@ -14,9 +14,9 @@ The governance process is divided in a few steps that are outlined below: confirmed and vote opens. Bonded Atom holders can then send `TxGovVote` transactions to vote on the proposal. - If the proposal involves a software upgrade: - - **Signal:** Validators start signaling that they are ready to switch to the + - **Signal:** Validators start signaling that they are ready to switch to the new version. - - **Switch:** Once more than 75% of validators have signaled that they are + - **Switch:** Once more than 75% of validators have signaled that they are ready to switch, their software automatically flips to the new version. ## Proposal submission @@ -29,18 +29,24 @@ its unique `proposalID`. ### Proposal types -In the initial version of the governance module, there are two types of -proposal: +In the initial version of the governance module, there are five types of +proposals: -- `PlainTextProposal` All the proposals that do not involve a modification of +- `TextProposal` All the proposals that do not involve a modification of the source code go under this type. For example, an opinion poll would use a - proposal of type `PlainTextProposal`. + proposal of type `TextProposal`. - `SoftwareUpgradeProposal`. If accepted, validators are expected to update their software in accordance with the proposal. They must do so by following a 2-steps process described in the [Software Upgrade](#software-upgrade) section below. Software upgrade roadmap may be discussed and agreed on via - `PlainTextProposals`, but actual software upgrades must be performed via + `TextProposals`, but actual software upgrades must be performed via `SoftwareUpgradeProposals`. +- `CommunityPoolSpendProposal` details a proposal for use of community funds, + together with how many coins are proposed to be spent, and to which recipient account. +- `ParameterChangeProposal` defines a proposal to change one or + more parameters. If accepted, the requested parameter change is updated + automatically by the proposal handler upon conclusion of the voting period. +- `CancelSoftwareUpgradeProposal` is a gov Content type for cancelling a software upgrade. Other modules may expand upon the governance module by implementing their own proposal types and handlers. These types are registered and processed through the @@ -112,6 +118,20 @@ proposal but accept the result of the vote. _Note: from the UI, for urgent proposals we should maybe add a ‘Not Urgent’ option that casts a `NoWithVeto` vote._ +### Weighted Votes + +[ADR-037](../../../docs/architecture/adr-037-gov-split-vote.md) introduces the weighted vote feature which allows a staker to split their votes into several voting options. For example, it could use 70% of its voting power to vote Yes and 30% of its voting power to vote No. + +Often times the entity owning that address might not be a single individual. For example, a company might have different stakeholders who want to vote differently, and so it makes sense to allow them to split their voting power. Currently, it is not possible for them to do "passthrough voting" and giving their users voting rights over their tokens. However, with this system, exchanges can poll their users for voting preferences, and then vote on-chain proportionally to the results of the poll. + +To represent weighted vote on chain, we use the following Protobuf message. + ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.43.0-alpha1/proto/cosmos/gov/v1beta1/gov.proto#L32-L40 + ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.43.0-alpha1/proto/cosmos/gov/v1beta1/gov.proto#L126-L137 + +For a weighted vote to be valid, the `options` field must not contain duplicate vote options, and the sum of weights of all options must be equal to 1. + ### Quorum Quorum is defined as the minimum percentage of voting power that needs to be diff --git a/x/gov/spec/02_state.md b/x/gov/spec/02_state.md index ba3b12b3f3..269ff69272 100644 --- a/x/gov/spec/02_state.md +++ b/x/gov/spec/02_state.md @@ -11,26 +11,17 @@ be one active parameter set at any given time. If governance wants to change a parameter set, either to modify a value or add/remove a parameter field, a new parameter set has to be created and the previous one rendered inactive. -```go -type DepositParams struct { - MinDeposit sdk.Coins // Minimum deposit for a proposal to enter voting period. - MaxDepositPeriod time.Time // Maximum period for Atom holders to deposit on a proposal. Initial value: 2 months -} -``` +### DepositParams -```go -type VotingParams struct { - VotingPeriod time.Time // Length of the voting period. Initial value: 2 weeks -} -``` ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/gov/v1beta1/gov.proto#L127-L145 -```go -type TallyParams struct { - Quorum sdk.Dec // Minimum percentage of stake that needs to vote for a proposal to be considered valid - Threshold sdk.Dec // Minimum proportion of Yes votes for proposal to pass. Initial value: 0.5 - Veto sdk.Dec // Minimum proportion of Veto votes to Total votes ratio for proposal to be vetoed. Initial value: 1/3 -} -``` +### VotingParams + ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/gov/v1beta1/gov.proto#L147-L156 + +### TallyParams + ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/gov/v1beta1/gov.proto#L158-L183 Parameters are stored in a global `GlobalParams` KVStore. @@ -68,12 +59,7 @@ const ( ## Deposit -```go - type Deposit struct { - Amount sdk.Coins // Amount of coins deposited by depositor - Depositor crypto.address // Address of depositor - } -``` ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/gov/v1beta1/gov.proto#L43-L53 ## ValidatorGovInfo @@ -92,22 +78,7 @@ This type is used in a temp map when tallying what this proposal is about, and other fields, which are the mutable state of the governance process. -```go -type Proposal struct { - Content // Proposal content interface - - ProposalID uint64 - Status ProposalStatus // Status of the Proposal {Pending, Active, Passed, Rejected} - FinalTallyResult TallyResult // Result of Tallies - - SubmitTime time.Time // Time of the block where TxGovSubmitProposal was included - DepositEndTime time.Time // Time that the Proposal would expire if deposit amount isn't met - TotalDeposit sdk.Coins // Current deposit on this proposal. Initial value is set at InitialDeposit - - VotingStartTime time.Time // Time of the block where MinDeposit was reached. -1 if MinDeposit is not reached - VotingEndTime time.Time // Time that the VotingPeriod for this proposal will end and votes will be tallied -} -``` ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/gov/v1beta1/gov.proto#L55-L77 ```go type Content interface { diff --git a/x/gov/spec/03_messages.md b/x/gov/spec/03_messages.md index cac55b5ed9..53d550bda6 100644 --- a/x/gov/spec/03_messages.md +++ b/x/gov/spec/03_messages.md @@ -6,18 +6,12 @@ order: 3 ## Proposal Submission -Proposals can be submitted by any Atom holder via a `TxGovSubmitProposal` +Proposals can be submitted by any account via a `MsgSubmitProposal` transaction. -```go -type TxGovSubmitProposal struct { - Content Content - InitialDeposit sdk.Coins - Proposer sdk.AccAddress -} -``` ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/gov/v1beta1/tx.proto#L24-L39 -The `Content` of a `TxGovSubmitProposal` message must have an appropriate router +The `Content` of a `MsgSubmitProposal` message must have an appropriate router set in the governance module. **State modifications:** @@ -27,15 +21,15 @@ set in the governance module. - Initialise `Proposals` attributes - Decrease balance of sender by `InitialDeposit` - If `MinDeposit` is reached: - - Push `proposalID` in `ProposalProcessingQueue` + - Push `proposalID` in `ProposalProcessingQueue` - Transfer `InitialDeposit` from the `Proposer` to the governance `ModuleAccount` -A `TxGovSubmitProposal` transaction can be handled according to the following +A `MsgSubmitProposal` transaction can be handled according to the following pseudocode. ```go // PSEUDOCODE // -// Check if TxGovSubmitProposal is valid. If it is, create proposal // +// Check if MsgSubmitProposal is valid. If it is, create proposal // upon receiving txGovSubmitProposal from sender do @@ -79,14 +73,9 @@ upon receiving txGovSubmitProposal from sender do Once a proposal is submitted, if `Proposal.TotalDeposit < ActiveParam.MinDeposit`, Atom holders can send -`TxGovDeposit` transactions to increase the proposal's deposit. +`MsgDeposit` transactions to increase the proposal's deposit. -```go -type TxGovDeposit struct { - ProposalID int64 // ID of the proposal - Deposit sdk.Coins // Number of Atoms to add to the proposal's deposit -} -``` ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/gov/v1beta1/tx.proto#L61-L72 **State modifications:** @@ -94,15 +83,15 @@ type TxGovDeposit struct { - Add `deposit` of sender in `proposal.Deposits` - Increase `proposal.TotalDeposit` by sender's `deposit` - If `MinDeposit` is reached: - - Push `proposalID` in `ProposalProcessingQueueEnd` + - Push `proposalID` in `ProposalProcessingQueueEnd` - Transfer `Deposit` from the `proposer` to the governance `ModuleAccount` -A `TxGovDeposit` transaction has to go through a number of checks to be valid. +A `MsgDeposit` transaction has to go through a number of checks to be valid. These checks are outlined in the following pseudocode. ```go // PSEUDOCODE // -// Check if TxGovDeposit is valid. If it is, increase deposit and check if MinDeposit is reached +// Check if MsgDeposit is valid. If it is, increase deposit and check if MinDeposit is reached upon receiving txGovDeposit from sender do // check if proposal is correctly formatted. Includes fee payment. @@ -149,15 +138,10 @@ upon receiving txGovDeposit from sender do ## Vote Once `ActiveParam.MinDeposit` is reached, voting period starts. From there, -bonded Atom holders are able to send `TxGovVote` transactions to cast their +bonded Atom holders are able to send `MsgVote` transactions to cast their vote on the proposal. -```go - type TxGovVote struct { - ProposalID int64 // proposalID of the proposal - Vote byte // option from OptionSet chosen by the voter - } -``` ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/gov/v1beta1/tx.proto#L46-L56 **State modifications:** @@ -165,12 +149,12 @@ vote on the proposal. _Note: Gas cost for this message has to take into account the future tallying of the vote in EndBlocker_ -Next is a pseudocode proposal of the way `TxGovVote` transactions are +Next is a pseudocode outline of the way `MsgVote` transactions are handled: ```go // PSEUDOCODE // - // Check if TxGovVote is valid. If it is, count vote// + // Check if MsgVote is valid. If it is, count vote// upon receiving txGovVote from sender do // check if proposal is correctly formatted. Includes fee payment. diff --git a/x/gov/spec/05_future_improvements.md b/x/gov/spec/05_future_improvements.md index 6a8350f569..12f2e9e5c6 100644 --- a/x/gov/spec/05_future_improvements.md +++ b/x/gov/spec/05_future_improvements.md @@ -4,27 +4,27 @@ order: 5 # Future Improvements -The current documentation only describes the minimum viable product for the +The current documentation only describes the minimum viable product for the governance module. Future improvements may include: -* **`BountyProposals`:** If accepted, a `BountyProposal` creates an open +* **`BountyProposals`:** If accepted, a `BountyProposal` creates an open bounty. The `BountyProposal` specifies how many Atoms will be given upon - completion. These Atoms will be taken from the `reserve pool`. After a - `BountyProposal` is accepted by governance, anybody can submit a - `SoftwareUpgradeProposal` with the code to claim the bounty. Note that once a - `BountyProposal` is accepted, the corresponding funds in the `reserve pool` - are locked so that payment can always be honored. In order to link a - `SoftwareUpgradeProposal` to an open bounty, the submitter of the - `SoftwareUpgradeProposal` will use the `Proposal.LinkedProposal` attribute. - If a `SoftwareUpgradeProposal` linked to an open bounty is accepted by + completion. These Atoms will be taken from the `reserve pool`. After a + `BountyProposal` is accepted by governance, anybody can submit a + `SoftwareUpgradeProposal` with the code to claim the bounty. Note that once a + `BountyProposal` is accepted, the corresponding funds in the `reserve pool` + are locked so that payment can always be honored. In order to link a + `SoftwareUpgradeProposal` to an open bounty, the submitter of the + `SoftwareUpgradeProposal` will use the `Proposal.LinkedProposal` attribute. + If a `SoftwareUpgradeProposal` linked to an open bounty is accepted by governance, the funds that were reserved are automatically transferred to the submitter. -* **Complex delegation:** Delegators could choose other representatives than - their validators. Ultimately, the chain of representatives would always end - up to a validator, but delegators could inherit the vote of their chosen - representative before they inherit the vote of their validator. In other - words, they would only inherit the vote of their validator if their other +* **Complex delegation:** Delegators could choose other representatives than + their validators. Ultimately, the chain of representatives would always end + up to a validator, but delegators could inherit the vote of their chosen + representative before they inherit the vote of their validator. In other + words, they would only inherit the vote of their validator if their other appointed representative did not vote. -* **Better process for proposal review:** There would be two parts to - `proposal.Deposit`, one for anti-spam (same as in MVP) and an other one to +* **Better process for proposal review:** There would be two parts to + `proposal.Deposit`, one for anti-spam (same as in MVP) and an other one to reward third party auditors. diff --git a/x/gov/spec/06_params.md b/x/gov/spec/06_params.md index f8dbe5edc9..2cc0176693 100644 --- a/x/gov/spec/06_params.md +++ b/x/gov/spec/06_params.md @@ -25,4 +25,4 @@ The governance module contains the following parameters: __NOTE__: The governance module contains parameters that are objects unlike other modules. If only a subset of parameters are desired to be changed, only they need -to be included and not the entire parameter object structure. +to be included and not the entire parameter object structure. diff --git a/x/gov/spec/07_client.md b/x/gov/spec/07_client.md new file mode 100644 index 0000000000..66cab628f2 --- /dev/null +++ b/x/gov/spec/07_client.md @@ -0,0 +1,1060 @@ + + +# Client + +## CLI + +A user can query and interact with the `gov` module using the CLI. + +### Query + +The `query` commands allow users to query `gov` state. + +```bash +simd query gov --help +``` + +#### deposit + +The `deposit` command allows users to query a deposit for a given proposal from a given depositor. + +```bash +simd query gov deposit [proposal-id] [depositer-addr] [flags] +``` + +Example: + +```bash +simd query gov deposit 1 cosmos1.. +``` + +Example Output: + +```bash +amount: +- amount: "100" + denom: stake +depositor: cosmos1.. +proposal_id: "1" +``` + +#### deposits + +The `deposits` command allows users to query all deposits for a given proposal. + +```bash +simd query gov deposits [proposal-id] [flags] +``` + +Example: + +```bash +simd query gov deposits 1 +``` + +Example Output: + +```bash +deposits: +- amount: + - amount: "100" + denom: stake + depositor: cosmos1.. + proposal_id: "1" +pagination: + next_key: null + total: "0" +``` + +#### param + +The `param` command allows users to query a given parameter for the `gov` module. + +```bash +simd query gov param [param-type] [flags] +``` + +Example: + +```bash +simd query gov param voting +``` + +Example Output: + +```bash +voting_period: "172800000000000" +``` + +#### params + +The `params` command allows users to query all parameters for the `gov` module. + +```bash +simd query gov params [flags] +``` + +Example: + +```bash +simd query gov params +``` + +Example Output: + +```bash +deposit_params: + max_deposit_period: "172800000000000" + min_deposit: + - amount: "10000000" + denom: stake +tally_params: + quorum: "0.334000000000000000" + threshold: "0.500000000000000000" + veto_threshold: "0.334000000000000000" +voting_params: + voting_period: "172800000000000" +``` + +#### proposal + +The `proposal` command allows users to query a given proposal. + +```bash +simd query gov proposal [proposal-id] [flags] +``` + +Example: + +```bash +simd query gov proposal 1 +``` + +Example Output: + +```bash +content: + '@type': /cosmos.gov.v1beta1.TextProposal + description: testing, testing, 1, 2, 3 + title: Test Proposal +deposit_end_time: "2021-09-17T23:36:18.254995423Z" +final_tally_result: + abstain: "0" + "no": "0" + no_with_veto: "0" + "yes": "0" +proposal_id: "1" +status: PROPOSAL_STATUS_DEPOSIT_PERIOD +submit_time: "2021-09-15T23:36:18.254995423Z" +total_deposit: +- amount: "100" + denom: stake +voting_end_time: "0001-01-01T00:00:00Z" +voting_start_time: "0001-01-01T00:00:00Z" +``` + +#### proposals + +The `proposals` command allows users to query all proposals with optional filters. + +```bash +simd query gov proposals [flags] +``` + +Example: + +```bash +simd query gov proposals +``` + +Example Output: + +```bash +pagination: + next_key: null + total: "1" +proposals: +- content: + '@type': /cosmos.gov.v1beta1.TextProposal + description: testing, testing, 1, 2, 3 + title: Test Proposal + deposit_end_time: "2021-09-17T23:36:18.254995423Z" + final_tally_result: + abstain: "0" + "no": "0" + no_with_veto: "0" + "yes": "0" + proposal_id: "1" + status: PROPOSAL_STATUS_DEPOSIT_PERIOD + submit_time: "2021-09-15T23:36:18.254995423Z" + total_deposit: + - amount: "100" + denom: stake + voting_end_time: "0001-01-01T00:00:00Z" + voting_start_time: "0001-01-01T00:00:00Z" +``` + +#### proposer + +The `proposer` command allows users to query the proposer for a given proposal. + +```bash +simd query gov proposer [proposal-id] [flags] +``` + +Example: + +```bash +simd query gov proposer 1 +``` + +Example Output: + +```bash +proposal_id: "1" +proposer: cosmos1r0tllwu5c9dtgwg3wr28lpvf76hg85f5zmh9l2 +``` + +#### tally + +The `tally` command allows users to query the tally of a given proposal vote. + +```bash +simd query gov tally [proposal-id] [flags] +``` + +Example: + +```bash +simd query gov tally 1 +``` + +Example Output: + +```bash +abstain: "0" +"no": "0" +no_with_veto: "0" +"yes": "1" +``` + +#### vote + +The `vote` command allows users to query a vote for a given proposal. + +```bash +simd query gov vote [proposal-id] [voter-addr] [flags] +``` + +Example: + +```bash +simd query gov vote 1 cosmos1.. +``` + +Example Output: + +```bash +option: VOTE_OPTION_YES +options: +- option: VOTE_OPTION_YES + weight: "1.000000000000000000" +proposal_id: "1" +voter: cosmos1.. +``` + +#### votes + +The `votes` command allows users to query all votes for a given proposal. + +```bash +simd query gov votes [proposal-id] [flags] +``` + +Example: + +```bash +simd query gov votes 1 +``` + +Example Output: + +```bash +pagination: + next_key: null + total: "0" +votes: +- option: VOTE_OPTION_YES + options: + - option: VOTE_OPTION_YES + weight: "1.000000000000000000" + proposal_id: "1" + voter: cosmos1r0tllwu5c9dtgwg3wr28lpvf76hg85f5zmh9l2 +``` + +### Transactions + +The `tx` commands allow users to interact with the `gov` module. + +```bash +simd tx gov --help +``` + +#### deposit + +The `deposit` command allows users to deposit tokens for a given proposal. + +```bash +simd tx gov deposit [proposal-id] [deposit] [flags] +``` + +Example: + +```bash +simd tx gov deposit 1 10000000stake --from cosmos1.. +``` + +#### submit-proposal + +The `submit-proposal` command allows users to submit a governance proposal and to optionally include an initial deposit. + +```bash +simd tx gov submit-proposal [command] [flags] +``` + +Example: + +```bash +simd tx gov submit-proposal --title="Test Proposal" --description="testing, testing, 1, 2, 3" --type="Text" --deposit="10000000stake" --from cosmos1.. +``` + +Example (`cancel-software-upgrade`): + +```bash +simd tx gov submit-proposal cancel-software-upgrade --title="Test Proposal" --description="testing, testing, 1, 2, 3" --deposit="10000000stake" --from cosmos1.. +``` + +Example (`community-pool-spend`): + +```bash +simd tx gov submit-proposal community-pool-spend proposal.json --from cosmos1.. +``` + +```json +{ + "title": "Test Proposal", + "description": "testing, testing, 1, 2, 3", + "recipient": "cosmos1..", + "amount": "10000000stake", + "deposit": "10000000stake" +} +``` + +Example (`param-change`): + +```bash +simd tx gov submit-proposal param-change proposal.json --from cosmos1.. +``` + +```json +{ + "title": "Test Proposal", + "description": "testing, testing, 1, 2, 3", + "changes": [ + { + "subspace": "staking", + "key": "MaxValidators", + "value": 100 + } + ], + "deposit": "10000000stake" +} +``` + +Example (`software-upgrade`): + +```bash +simd tx gov submit-proposal software-upgrade v2 --title="Test Proposal" --description="testing, testing, 1, 2, 3" --upgrade-height 1000000 --from cosmos1.. +``` + +#### vote + +The `vote` command allows users to submit a vote for a given governance proposal. + +```bash +simd tx gov vote [command] [flags] +``` + +Example: + +```bash +simd tx gov vote 1 yes --from cosmos1.. +``` + +#### weighted-vote + +The `weighted-vote` command allows users to submit a weighted vote for a given governance proposal. + +```bash +simd tx gov weighted-vote [proposal-id] [weighted-options] +``` + +Example: + +```bash +simd tx gov weighted-vote 1 yes=0.5,no=0.5 --from cosmos1 +``` + +## gRPC + +A user can query the `gov` module using gRPC endpoints. + +### Proposal + +The `Proposal` endpoint allows users to query a given proposal. + +```bash +cosmos.gov.v1beta1.Query/Proposal +``` + +Example: + +```bash +grpcurl -plaintext \ + -d '{"proposal_id":"1"}' \ + localhost:9090 \ + cosmos.gov.v1beta1.Query/Proposal +``` + +Example Output: + +```bash +{ + "proposal": { + "proposalId": "1", + "content": {"@type":"/cosmos.gov.v1beta1.TextProposal","description":"testing, testing, 1, 2, 3","title":"Test Proposal"}, + "status": "PROPOSAL_STATUS_VOTING_PERIOD", + "finalTallyResult": { + "yes": "0", + "abstain": "0", + "no": "0", + "noWithVeto": "0" + }, + "submitTime": "2021-09-16T19:40:08.712440474Z", + "depositEndTime": "2021-09-18T19:40:08.712440474Z", + "totalDeposit": [ + { + "denom": "stake", + "amount": "10000000" + } + ], + "votingStartTime": "2021-09-16T19:40:08.712440474Z", + "votingEndTime": "2021-09-18T19:40:08.712440474Z" + } +} +``` + +### Proposals + +The `Proposals` endpoint allows users to query all proposals with optional filters. + +```bash +cosmos.gov.v1beta1.Query/Proposals +``` + +Example: + +```bash +grpcurl -plaintext \ + localhost:9090 \ + cosmos.gov.v1beta1.Query/Proposals +``` + +Example Output: + +```bash +{ + "proposals": [ + { + "proposalId": "1", + "content": {"@type":"/cosmos.gov.v1beta1.TextProposal","description":"testing, testing, 1, 2, 3","title":"Test Proposal"}, + "status": "PROPOSAL_STATUS_VOTING_PERIOD", + "finalTallyResult": { + "yes": "0", + "abstain": "0", + "no": "0", + "noWithVeto": "0" + }, + "submitTime": "2021-09-16T19:40:08.712440474Z", + "depositEndTime": "2021-09-18T19:40:08.712440474Z", + "totalDeposit": [ + { + "denom": "stake", + "amount": "10000000" + } + ], + "votingStartTime": "2021-09-16T19:40:08.712440474Z", + "votingEndTime": "2021-09-18T19:40:08.712440474Z" + }, + { + "proposalId": "2", + "content": {"@type":"/cosmos.upgrade.v1beta1.CancelSoftwareUpgradeProposal","description":"Test Proposal","title":"testing, testing, 1, 2, 3"}, + "status": "PROPOSAL_STATUS_DEPOSIT_PERIOD", + "finalTallyResult": { + "yes": "0", + "abstain": "0", + "no": "0", + "noWithVeto": "0" + }, + "submitTime": "2021-09-17T18:26:57.866854713Z", + "depositEndTime": "2021-09-19T18:26:57.866854713Z", + "votingStartTime": "0001-01-01T00:00:00Z", + "votingEndTime": "0001-01-01T00:00:00Z" + } + ], + "pagination": { + "total": "2" + } +} +``` + +### Vote + +The `Vote` endpoint allows users to query a vote for a given proposal. + +```bash +cosmos.gov.v1beta1.Query/Vote +``` + +Example: + +```bash +grpcurl -plaintext \ + -d '{"proposal_id":"1","voter":"cosmos1.."}' \ + localhost:9090 \ + cosmos.gov.v1beta1.Query/Vote +``` + +Example Output: + +```bash +{ + "vote": { + "proposalId": "1", + "voter": "cosmos1..", + "option": "VOTE_OPTION_YES", + "options": [ + { + "option": "VOTE_OPTION_YES", + "weight": "1000000000000000000" + } + ] + } +} +``` + +### Votes + +The `Votes` endpoint allows users to query all votes for a given proposal. + +```bash +cosmos.gov.v1beta1.Query/Votes +``` + +Example: + +```bash +grpcurl -plaintext \ + -d '{"proposal_id":"1"}' \ + localhost:9090 \ + cosmos.gov.v1beta1.Query/Votes +``` + +Example Output: + +```bash +{ + "votes": [ + { + "proposalId": "1", + "voter": "cosmos1..", + "option": "VOTE_OPTION_YES", + "options": [ + { + "option": "VOTE_OPTION_YES", + "weight": "1000000000000000000" + } + ] + } + ], + "pagination": { + "total": "1" + } +} +``` + +### Params + +The `Params` endpoint allows users to query all parameters for the `gov` module. + + + +```bash +cosmos.gov.v1beta1.Query/Params +``` + +Example: + +```bash +grpcurl -plaintext \ + -d '{"params_type":"voting"}' \ + localhost:9090 \ + cosmos.gov.v1beta1.Query/Params +``` + +Example Output: + +```bash +{ + "votingParams": { + "votingPeriod": "172800s" + }, + "depositParams": { + "maxDepositPeriod": "0s" + }, + "tallyParams": { + "quorum": "MA==", + "threshold": "MA==", + "vetoThreshold": "MA==" + } +} +``` + +### Deposit + +The `Deposit` endpoint allows users to query a deposit for a given proposal from a given depositor. + +```bash +cosmos.gov.v1beta1.Query/Deposit +``` + +Example: + +```bash +grpcurl -plaintext \ + '{"proposal_id":"1","depositor":"cosmos1.."}' \ + localhost:9090 \ + cosmos.gov.v1beta1.Query/Deposit +``` + +Example Output: + +```bash +{ + "deposit": { + "proposalId": "1", + "depositor": "cosmos1..", + "amount": [ + { + "denom": "stake", + "amount": "10000000" + } + ] + } +} +``` + +### deposits + +The `Deposits` endpoint allows users to query all deposits for a given proposal. + +```bash +cosmos.gov.v1beta1.Query/Deposits +``` + +Example: + +```bash +grpcurl -plaintext \ + -d '{"proposal_id":"1"}' \ + localhost:9090 \ + cosmos.gov.v1beta1.Query/Deposits +``` + +Example Output: + +```bash +{ + "deposits": [ + { + "proposalId": "1", + "depositor": "cosmos1..", + "amount": [ + { + "denom": "stake", + "amount": "10000000" + } + ] + } + ], + "pagination": { + "total": "1" + } +} +``` + +### TallyResult + +The `TallyResult` endpoint allows users to query the tally of a given proposal. + +```bash +cosmos.gov.v1beta1.Query/TallyResult +``` + +Example: + +```bash +grpcurl -plaintext \ + -d '{"proposal_id":"1"}' \ + localhost:9090 \ + cosmos.gov.v1beta1.Query/TallyResult +``` + +Example Output: + +```bash +{ + "tally": { + "yes": "1000000", + "abstain": "0", + "no": "0", + "noWithVeto": "0" + } +} +``` + +## REST + +A user can query the `gov` module using REST endpoints. + +### proposal + +The `proposals` endpoint allows users to query a given proposal. + +```bash +/cosmos/gov/v1beta1/proposals/{proposal_id} +``` + +Example: + +```bash +curl localhost:1317/cosmos/gov/v1beta1/proposals/1 +``` + +Example Output: + +```bash +{ + "proposal": { + "proposal_id": "1", + "content": { + "@type": "/cosmos.gov.v1beta1.TextProposal", + "title": "Test Proposal", + "description": "testing, testing, 1, 2, 3" + }, + "status": "PROPOSAL_STATUS_VOTING_PERIOD", + "final_tally_result": { + "yes": "0", + "abstain": "0", + "no": "0", + "no_with_veto": "0" + }, + "submit_time": "2021-09-16T19:40:08.712440474Z", + "deposit_end_time": "2021-09-18T19:40:08.712440474Z", + "total_deposit": [ + { + "denom": "stake", + "amount": "10000000" + } + ], + "voting_start_time": "2021-09-16T19:40:08.712440474Z", + "voting_end_time": "2021-09-18T19:40:08.712440474Z" + } +} +``` + +### proposals + +The `proposals` endpoint also allows users to query all proposals with optional filters. + +```bash +/cosmos/gov/v1beta1/proposals +``` + +Example: + +```bash +curl localhost:1317/cosmos/gov/v1beta1/proposals +``` + +Example Output: + +```bash +{ + "proposals": [ + { + "proposal_id": "1", + "content": { + "@type": "/cosmos.gov.v1beta1.TextProposal", + "title": "Test Proposal", + "description": "testing, testing, 1, 2, 3" + }, + "status": "PROPOSAL_STATUS_VOTING_PERIOD", + "final_tally_result": { + "yes": "0", + "abstain": "0", + "no": "0", + "no_with_veto": "0" + }, + "submit_time": "2021-09-16T19:40:08.712440474Z", + "deposit_end_time": "2021-09-18T19:40:08.712440474Z", + "total_deposit": [ + { + "denom": "stake", + "amount": "10000000" + } + ], + "voting_start_time": "2021-09-16T19:40:08.712440474Z", + "voting_end_time": "2021-09-18T19:40:08.712440474Z" + }, + { + "proposal_id": "2", + "content": { + "@type": "/cosmos.upgrade.v1beta1.CancelSoftwareUpgradeProposal", + "title": "Test Proposal", + "description": "testing, testing, 1, 2, 3" + }, + "status": "PROPOSAL_STATUS_DEPOSIT_PERIOD", + "final_tally_result": { + "yes": "0", + "abstain": "0", + "no": "0", + "no_with_veto": "0" + }, + "submit_time": "2021-09-17T18:26:57.866854713Z", + "deposit_end_time": "2021-09-19T18:26:57.866854713Z", + "total_deposit": [ + ], + "voting_start_time": "0001-01-01T00:00:00Z", + "voting_end_time": "0001-01-01T00:00:00Z" + } + ], + "pagination": { + "next_key": null, + "total": "2" + } +} +``` + +### voter vote + +The `votes` endpoint allows users to query a vote for a given proposal. + +```bash +/cosmos/gov/v1beta1/proposals/{proposal_id}/votes/{voter} +``` + +Example: + +```bash +curl localhost:1317/cosmos/gov/v1beta1/proposals/1/votes/cosmos1.. +``` + +Example Output: + +```bash +{ + "vote": { + "proposal_id": "1", + "voter": "cosmos1..", + "option": "VOTE_OPTION_YES", + "options": [ + { + "option": "VOTE_OPTION_YES", + "weight": "1.000000000000000000" + } + ] + } +} +``` + +### votes + +The `votes` endpoint allows users to query all votes for a given proposal. + +```bash +/cosmos/gov/v1beta1/proposals/{proposal_id}/votes +``` + +Example: + +```bash +curl localhost:1317/cosmos/gov/v1beta1/proposals/1/votes +``` + +Example Output: + +```bash +{ + "votes": [ + { + "proposal_id": "1", + "voter": "cosmos1..", + "option": "VOTE_OPTION_YES", + "options": [ + { + "option": "VOTE_OPTION_YES", + "weight": "1.000000000000000000" + } + ] + } + ], + "pagination": { + "next_key": null, + "total": "1" + } +} +``` + +### params + +The `params` endpoint allows users to query all parameters for the `gov` module. + + + +```bash +/cosmos/gov/v1beta1/params/{params_type} +``` + +Example: + +```bash +curl localhost:1317/cosmos/gov/v1beta1/params/voting +``` + +Example Output: + +```bash +{ + "voting_params": { + "voting_period": "172800s" + }, + "deposit_params": { + "min_deposit": [ + ], + "max_deposit_period": "0s" + }, + "tally_params": { + "quorum": "0.000000000000000000", + "threshold": "0.000000000000000000", + "veto_threshold": "0.000000000000000000" + } +} +``` + +### deposits + +The `deposits` endpoint allows users to query a deposit for a given proposal from a given depositor. + +```bash +/cosmos/gov/v1beta1/proposals/{proposal_id}/deposits/{depositor} +``` + +Example: + +```bash +curl localhost:1317/cosmos/gov/v1beta1/proposals/1/deposits/cosmos1.. +``` + +Example Output: + +```bash +{ + "deposit": { + "proposal_id": "1", + "depositor": "cosmos1..", + "amount": [ + { + "denom": "stake", + "amount": "10000000" + } + ] + } +} +``` + +### proposal deposits + +The `deposits` endpoint allows users to query all deposits for a given proposal. + +```bash +/cosmos/gov/v1beta1/proposals/{proposal_id}/deposits +``` + +Example: + +```bash +curl localhost:1317/cosmos/gov/v1beta1/proposals/1/deposits +``` + +Example Output: + +```bash +{ + "deposits": [ + { + "proposal_id": "1", + "depositor": "cosmos1..", + "amount": [ + { + "denom": "stake", + "amount": "10000000" + } + ] + } + ], + "pagination": { + "next_key": null, + "total": "1" + } +} +``` + +### tally + +The `tally` endpoint allows users to query the tally of a given proposal. + +```bash +/cosmos/gov/v1beta1/proposals/{proposal_id}/tally +``` + +Example: + +```bash +curl localhost:1317/cosmos/gov/v1beta1/proposals/1/tally +``` + +Example Output: + +```bash +{ + "tally": { + "yes": "1000000", + "abstain": "0", + "no": "0", + "no_with_veto": "0" + } +} +``` diff --git a/x/gov/types/codec.go b/x/gov/types/codec.go index 2252c067ca..1b43dc147a 100644 --- a/x/gov/types/codec.go +++ b/x/gov/types/codec.go @@ -14,6 +14,7 @@ func RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) { cdc.RegisterInterface((*Content)(nil), nil) cdc.RegisterConcrete(&MsgSubmitProposal{}, "lbm-sdk/MsgSubmitProposal", nil) cdc.RegisterConcrete(&MsgDeposit{}, "lbm-sdk/MsgDeposit", nil) + cdc.RegisterConcrete(&MsgVote{}, "lbm-sdk/MsgVote", nil) cdc.RegisterConcrete(&MsgVoteWeighted{}, "lbm-sdk/MsgVoteWeighted", nil) cdc.RegisterConcrete(&TextProposal{}, "lbm-sdk/TextProposal", nil) } diff --git a/x/gov/types/content.go b/x/gov/types/content.go index 633930d811..57361b142c 100644 --- a/x/gov/types/content.go +++ b/x/gov/types/content.go @@ -9,7 +9,7 @@ import ( // Constants pertaining to a Content object const ( - MaxDescriptionLength int = 5000 + MaxDescriptionLength int = 10000 MaxTitleLength int = 140 ) diff --git a/x/gov/types/expected_keepers.go b/x/gov/types/expected_keepers.go index f1c2797740..7be6c07d00 100644 --- a/x/gov/types/expected_keepers.go +++ b/x/gov/types/expected_keepers.go @@ -41,7 +41,6 @@ type AccountKeeper interface { type BankKeeper interface { GetAllBalances(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins GetBalance(ctx sdk.Context, addr sdk.AccAddress, denom string) sdk.Coin - SetBalances(ctx sdk.Context, addr sdk.AccAddress, balances sdk.Coins) error LockedCoins(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins SpendableCoins(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins @@ -50,3 +49,16 @@ type BankKeeper interface { BurnCoins(ctx sdk.Context, name string, amt sdk.Coins) error Prefetch(ctx sdk.Context, tx sdk.Tx) } + +// Event Hooks +// These can be utilized to communicate between a governance keeper and another +// keepers. + +// GovHooks event hooks for governance proposal object (noalias) +type GovHooks interface { + AfterProposalSubmission(ctx sdk.Context, proposalID uint64) // Must be called after proposal is submitted + AfterProposalDeposit(ctx sdk.Context, proposalID uint64, depositorAddr sdk.AccAddress) // Must be called after a deposit is made + AfterProposalVote(ctx sdk.Context, proposalID uint64, voterAddr sdk.AccAddress) // Must be called after a vote on a proposal is cast + AfterProposalFailedMinDeposit(ctx sdk.Context, proposalID uint64) // Must be called when proposal fails to reach min deposit + AfterProposalVotingPeriodEnded(ctx sdk.Context, proposalID uint64) // Must be called when proposal's finishes it's voting period +} diff --git a/x/gov/types/gov.pb.go b/x/gov/types/gov.pb.go index e27d31de0a..0d406bd257 100644 --- a/x/gov/types/gov.pb.go +++ b/x/gov/types/gov.pb.go @@ -122,6 +122,8 @@ func (ProposalStatus) EnumDescriptor() ([]byte, []int) { } // WeightedVoteOption defines a unit of vote for vote split. +// +// Since: cosmos-sdk 0.43 type WeightedVoteOption struct { Option VoteOption `protobuf:"varint,1,opt,name=option,proto3,enum=lbm.gov.v1.VoteOption" json:"option,omitempty"` Weight github_com_line_lbm_sdk_types.Dec `protobuf:"bytes,2,opt,name=weight,proto3,customtype=github.com/line/lbm-sdk/types.Dec" json:"weight" yaml:"weight"` @@ -331,7 +333,8 @@ type Vote struct { // Deprecated: Prefer to use `options` instead. This field is set in queries // if and only if `len(options) == 1` and that option has weight 1. In all // other cases, this field will default to VOTE_OPTION_UNSPECIFIED. - Option VoteOption `protobuf:"varint,3,opt,name=option,proto3,enum=lbm.gov.v1.VoteOption" json:"option,omitempty"` // Deprecated: Do not use. + Option VoteOption `protobuf:"varint,3,opt,name=option,proto3,enum=lbm.gov.v1.VoteOption" json:"option,omitempty"` // Deprecated: Do not use. + // Since: cosmos-sdk 0.43 Options []WeightedVoteOption `protobuf:"bytes,4,rep,name=options,proto3" json:"options"` } diff --git a/x/gov/types/hooks.go b/x/gov/types/hooks.go new file mode 100644 index 0000000000..6139b11c93 --- /dev/null +++ b/x/gov/types/hooks.go @@ -0,0 +1,42 @@ +package types + +import ( + sdk "github.com/line/lbm-sdk/types" +) + +var _ GovHooks = MultiGovHooks{} + +// combine multiple governance hooks, all hook functions are run in array sequence +type MultiGovHooks []GovHooks + +func NewMultiGovHooks(hooks ...GovHooks) MultiGovHooks { + return hooks +} + +func (h MultiGovHooks) AfterProposalSubmission(ctx sdk.Context, proposalID uint64) { + for i := range h { + h[i].AfterProposalSubmission(ctx, proposalID) + } +} + +func (h MultiGovHooks) AfterProposalDeposit(ctx sdk.Context, proposalID uint64, depositorAddr sdk.AccAddress) { + for i := range h { + h[i].AfterProposalDeposit(ctx, proposalID, depositorAddr) + } +} + +func (h MultiGovHooks) AfterProposalVote(ctx sdk.Context, proposalID uint64, voterAddr sdk.AccAddress) { + for i := range h { + h[i].AfterProposalVote(ctx, proposalID, voterAddr) + } +} +func (h MultiGovHooks) AfterProposalFailedMinDeposit(ctx sdk.Context, proposalID uint64) { + for i := range h { + h[i].AfterProposalFailedMinDeposit(ctx, proposalID) + } +} +func (h MultiGovHooks) AfterProposalVotingPeriodEnded(ctx sdk.Context, proposalID uint64) { + for i := range h { + h[i].AfterProposalVotingPeriodEnded(ctx, proposalID) + } +} diff --git a/x/gov/types/keys.go b/x/gov/types/keys.go index cb60e77b8f..1a57121ce6 100644 --- a/x/gov/types/keys.go +++ b/x/gov/types/keys.go @@ -6,6 +6,7 @@ import ( "time" sdk "github.com/line/lbm-sdk/types" + "github.com/line/lbm-sdk/types/address" ) const ( @@ -33,9 +34,9 @@ const ( // // - 0x03: nextProposalID // -// - 0x10: Deposit +// - 0x10: Deposit // -// - 0x20: Voter +// - 0x20: Voter var ( ProposalsKeyPrefix = []byte{0x00} ActiveProposalQueuePrefix = []byte{0x01} @@ -93,7 +94,7 @@ func DepositsKey(proposalID uint64) []byte { // DepositKey key of a specific deposit from the store func DepositKey(proposalID uint64, depositorAddr sdk.AccAddress) []byte { - return append(DepositsKey(proposalID), depositorAddr.Bytes()...) + return append(DepositsKey(proposalID), address.MustLengthPrefix(depositorAddr.Bytes())...) } // VotesKey gets the first part of the votes key based on the proposalID @@ -103,7 +104,7 @@ func VotesKey(proposalID uint64) []byte { // VoteKey key of a specific vote from the store func VoteKey(proposalID uint64, voterAddr sdk.AccAddress) []byte { - return append(VotesKey(proposalID), voterAddr.Bytes()...) + return append(VotesKey(proposalID), address.MustLengthPrefix(voterAddr.Bytes())...) } // Split keys function; used for iterators @@ -154,7 +155,9 @@ func splitKeyWithTime(key []byte) (proposalID uint64, endTime time.Time) { } func splitKeyWithAddress(key []byte) (proposalID uint64, addr sdk.AccAddress) { + // Both Vote and Deposit store keys are of format: + // proposalID = GetProposalIDFromBytes(key[1:9]) - addr = sdk.AccAddress(key[9:]) + addr = sdk.AccAddress(key[10:]) return } diff --git a/x/gov/types/keys_test.go b/x/gov/types/keys_test.go index 985593a6a0..3fe829e492 100644 --- a/x/gov/types/keys_test.go +++ b/x/gov/types/keys_test.go @@ -46,12 +46,6 @@ func TestDepositKeys(t *testing.T) { proposalID, depositorAddr := SplitKeyDeposit(key) require.Equal(t, int(proposalID), 2) require.Equal(t, addr, depositorAddr) - - // invalid key - addr2 := sdk.AccAddress("test1") - key = DepositKey(5, addr2) - // SplitKeyDeposit does not check key length - require.NotPanics(t, func() { SplitKeyDeposit(key) }) } func TestVoteKeys(t *testing.T) { @@ -64,10 +58,4 @@ func TestVoteKeys(t *testing.T) { proposalID, voterAddr := SplitKeyDeposit(key) require.Equal(t, int(proposalID), 2) require.Equal(t, addr, voterAddr) - - // invalid key - addr2 := sdk.AccAddress("test1") - key = VoteKey(5, addr2) - // SplitKeyVote does not check key length - require.NotPanics(t, func() { SplitKeyVote(key) }) } diff --git a/x/gov/types/msgs.go b/x/gov/types/msgs.go index ea8a3ca7c4..c7f0c1396c 100644 --- a/x/gov/types/msgs.go +++ b/x/gov/types/msgs.go @@ -21,8 +21,8 @@ const ( ) var ( - _, _, _ sdk.Msg = &MsgSubmitProposal{}, &MsgDeposit{}, &MsgVoteWeighted{} - _ types.UnpackInterfacesMessage = &MsgSubmitProposal{} + _, _, _, _ sdk.Msg = &MsgSubmitProposal{}, &MsgDeposit{}, &MsgVote{}, &MsgVoteWeighted{} + _ types.UnpackInterfacesMessage = &MsgSubmitProposal{} ) // NewMsgSubmitProposal creates a new MsgSubmitProposal. @@ -196,9 +196,6 @@ func (msg MsgVote) ValidateBasic() error { if msg.Voter == "" { return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, msg.Voter) } - if err := sdk.ValidateAccAddress(msg.Voter); err != nil { - return sdkerrors.Wrapf(sdkerrors.ErrInvalidAddress, "Invalid voter address (%s)", err) - } if !ValidVoteOption(msg.Option) { return sdkerrors.Wrap(ErrInvalidVote, msg.Option.String()) } diff --git a/x/gov/types/msgs_test.go b/x/gov/types/msgs_test.go index f18283dd5d..4cb6cb1125 100644 --- a/x/gov/types/msgs_test.go +++ b/x/gov/types/msgs_test.go @@ -92,7 +92,7 @@ func TestMsgDeposit(t *testing.T) { } } -// test ValidateBasic for MsgDeposit +// test ValidateBasic for MsgVote func TestMsgVote(t *testing.T) { tests := []struct { proposalID uint64 diff --git a/x/gov/types/params.go b/x/gov/types/params.go index 809efdde21..fc312c771d 100644 --- a/x/gov/types/params.go +++ b/x/gov/types/params.go @@ -17,7 +17,7 @@ const ( // Default governance params var ( - DefaultMinDepositTokens = sdk.TokensFromConsensusPower(10) + DefaultMinDepositTokens = sdk.NewInt(10000000) DefaultQuorum = sdk.NewDecWithPrec(334, 3) DefaultThreshold = sdk.NewDecWithPrec(5, 1) DefaultVetoThreshold = sdk.NewDecWithPrec(334, 3) diff --git a/x/gov/types/proposal.go b/x/gov/types/proposal.go index cae38a62f1..9c1efad3f6 100644 --- a/x/gov/types/proposal.go +++ b/x/gov/types/proposal.go @@ -18,15 +18,6 @@ const DefaultStartingProposalID uint64 = 1 // NewProposal creates a new Proposal instance func NewProposal(content Content, id uint64, submitTime, depositEndTime time.Time) (Proposal, error) { - p := Proposal{ - ProposalId: id, - Status: StatusDepositPeriod, - FinalTallyResult: EmptyTallyResult(), - TotalDeposit: sdk.NewCoins(), - SubmitTime: submitTime, - DepositEndTime: depositEndTime, - } - msg, ok := content.(proto.Message) if !ok { return Proposal{}, fmt.Errorf("%T does not implement proto.Message", content) @@ -37,7 +28,15 @@ func NewProposal(content Content, id uint64, submitTime, depositEndTime time.Tim return Proposal{}, err } - p.Content = any + p := Proposal{ + Content: any, + ProposalId: id, + Status: StatusDepositPeriod, + FinalTallyResult: EmptyTallyResult(), + TotalDeposit: sdk.NewCoins(), + SubmitTime: submitTime, + DepositEndTime: depositEndTime, + } return p, nil } diff --git a/x/gov/types/query.pb.gw.go b/x/gov/types/query.pb.gw.go index 58e66a24f1..210722332a 100644 --- a/x/gov/types/query.pb.gw.go +++ b/x/gov/types/query.pb.gw.go @@ -896,21 +896,21 @@ func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, clie } var ( - pattern_Query_Proposal_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4}, []string{"lbm", "gov", "v1", "proposals", "proposal_id"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_Query_Proposal_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4}, []string{"lbm", "gov", "v1", "proposals", "proposal_id"}, "", runtime.AssumeColonVerbOpt(false))) - pattern_Query_Proposals_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"lbm", "gov", "v1", "proposals"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_Query_Proposals_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"lbm", "gov", "v1", "proposals"}, "", runtime.AssumeColonVerbOpt(false))) - pattern_Query_Vote_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4, 2, 5, 1, 0, 4, 1, 5, 6}, []string{"lbm", "gov", "v1", "proposals", "proposal_id", "votes", "voter"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_Query_Vote_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4, 2, 5, 1, 0, 4, 1, 5, 6}, []string{"lbm", "gov", "v1", "proposals", "proposal_id", "votes", "voter"}, "", runtime.AssumeColonVerbOpt(false))) - pattern_Query_Votes_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4, 2, 5}, []string{"lbm", "gov", "v1", "proposals", "proposal_id", "votes"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_Query_Votes_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4, 2, 5}, []string{"lbm", "gov", "v1", "proposals", "proposal_id", "votes"}, "", runtime.AssumeColonVerbOpt(false))) - pattern_Query_Params_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4}, []string{"lbm", "gov", "v1", "params", "params_type"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_Query_Params_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4}, []string{"lbm", "gov", "v1", "params", "params_type"}, "", runtime.AssumeColonVerbOpt(false))) - pattern_Query_Deposit_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4, 2, 5, 1, 0, 4, 1, 5, 6}, []string{"lbm", "gov", "v1", "proposals", "proposal_id", "deposits", "depositor"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_Query_Deposit_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4, 2, 5, 1, 0, 4, 1, 5, 6}, []string{"lbm", "gov", "v1", "proposals", "proposal_id", "deposits", "depositor"}, "", runtime.AssumeColonVerbOpt(false))) - pattern_Query_Deposits_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4, 2, 5}, []string{"lbm", "gov", "v1", "proposals", "proposal_id", "deposits"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_Query_Deposits_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4, 2, 5}, []string{"lbm", "gov", "v1", "proposals", "proposal_id", "deposits"}, "", runtime.AssumeColonVerbOpt(false))) - pattern_Query_TallyResult_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4, 2, 5}, []string{"lbm", "gov", "v1", "proposals", "proposal_id", "tally"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_Query_TallyResult_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4, 2, 5}, []string{"lbm", "gov", "v1", "proposals", "proposal_id", "tally"}, "", runtime.AssumeColonVerbOpt(false))) ) var ( diff --git a/x/gov/types/tally.go b/x/gov/types/tally.go index d2dbb43de1..bad1a78eef 100644 --- a/x/gov/types/tally.go +++ b/x/gov/types/tally.go @@ -17,14 +17,14 @@ type ValidatorGovInfo struct { // NewValidatorGovInfo creates a ValidatorGovInfo instance func NewValidatorGovInfo(address sdk.ValAddress, bondedTokens sdk.Int, delegatorShares, - delegatorDeductions sdk.Dec, vote WeightedVoteOptions) ValidatorGovInfo { + delegatorDeductions sdk.Dec, options WeightedVoteOptions) ValidatorGovInfo { return ValidatorGovInfo{ Address: address, BondedTokens: bondedTokens, DelegatorShares: delegatorShares, DelegatorDeductions: delegatorDeductions, - Vote: vote, + Vote: options, } } diff --git a/x/gov/types/tx.pb.go b/x/gov/types/tx.pb.go index 5a69af390a..c71bc2cf92 100644 --- a/x/gov/types/tx.pb.go +++ b/x/gov/types/tx.pb.go @@ -194,6 +194,8 @@ func (m *MsgVoteResponse) XXX_DiscardUnknown() { var xxx_messageInfo_MsgVoteResponse proto.InternalMessageInfo // MsgVoteWeighted defines a message to cast a vote. +// +// Since: cosmos-sdk 0.43 type MsgVoteWeighted struct { ProposalId uint64 `protobuf:"varint,1,opt,name=proposal_id,json=proposalId,proto3" json:"proposal_id,omitempty" yaml:"proposal_id"` Voter string `protobuf:"bytes,2,opt,name=voter,proto3" json:"voter,omitempty"` @@ -233,6 +235,8 @@ func (m *MsgVoteWeighted) XXX_DiscardUnknown() { var xxx_messageInfo_MsgVoteWeighted proto.InternalMessageInfo // MsgVoteWeightedResponse defines the Msg/VoteWeighted response type. +// +// Since: cosmos-sdk 0.43 type MsgVoteWeightedResponse struct { } @@ -420,6 +424,8 @@ type MsgClient interface { // Vote defines a method to add a vote on a specific proposal. Vote(ctx context.Context, in *MsgVote, opts ...grpc.CallOption) (*MsgVoteResponse, error) // VoteWeighted defines a method to add a weighted vote on a specific proposal. + // + // Since: cosmos-sdk 0.43 VoteWeighted(ctx context.Context, in *MsgVoteWeighted, opts ...grpc.CallOption) (*MsgVoteWeightedResponse, error) // Deposit defines a method to add deposit on a specific proposal. Deposit(ctx context.Context, in *MsgDeposit, opts ...grpc.CallOption) (*MsgDepositResponse, error) @@ -476,6 +482,8 @@ type MsgServer interface { // Vote defines a method to add a vote on a specific proposal. Vote(context.Context, *MsgVote) (*MsgVoteResponse, error) // VoteWeighted defines a method to add a weighted vote on a specific proposal. + // + // Since: cosmos-sdk 0.43 VoteWeighted(context.Context, *MsgVoteWeighted) (*MsgVoteWeightedResponse, error) // Deposit defines a method to add deposit on a specific proposal. Deposit(context.Context, *MsgDeposit) (*MsgDepositResponse, error) diff --git a/x/gov/types/vote.go b/x/gov/types/vote.go index 90f55636d3..a6ef5681cb 100644 --- a/x/gov/types/vote.go +++ b/x/gov/types/vote.go @@ -45,7 +45,7 @@ func (v Votes) String() string { } out := fmt.Sprintf("Votes for Proposal %d:", v[0].ProposalId) for _, vot := range v { - out += fmt.Sprintf("\n %s: %s", vot.Voter, vot.Option) + out += fmt.Sprintf("\n %s: %s", vot.Voter, vot.Options) } return out } diff --git a/x/ibc/applications/transfer/client/cli/query.go b/x/ibc/applications/transfer/client/cli/query.go index 0438f78fee..97a7a33fad 100644 --- a/x/ibc/applications/transfer/client/cli/query.go +++ b/x/ibc/applications/transfer/client/cli/query.go @@ -1,7 +1,6 @@ package cli import ( - "context" "fmt" "github.com/spf13/cobra" @@ -31,7 +30,7 @@ func GetCmdQueryDenomTrace() *cobra.Command { Hash: args[0], } - res, err := queryClient.DenomTrace(context.Background(), req) + res, err := queryClient.DenomTrace(cmd.Context(), req) if err != nil { return err } @@ -69,7 +68,7 @@ func GetCmdQueryDenomTraces() *cobra.Command { Pagination: pageReq, } - res, err := queryClient.DenomTraces(context.Background(), req) + res, err := queryClient.DenomTraces(cmd.Context(), req) if err != nil { return err } @@ -98,7 +97,7 @@ func GetCmdParams() *cobra.Command { } queryClient := types.NewQueryClient(clientCtx) - res, _ := queryClient.Params(context.Background(), &types.QueryParamsRequest{}) + res, _ := queryClient.Params(cmd.Context(), &types.QueryParamsRequest{}) return clientCtx.PrintProto(res.Params) }, } diff --git a/x/ibc/applications/transfer/client/cli/tx.go b/x/ibc/applications/transfer/client/cli/tx.go index 93d13413ae..bc0568a21d 100644 --- a/x/ibc/applications/transfer/client/cli/tx.go +++ b/x/ibc/applications/transfer/client/cli/tx.go @@ -96,9 +96,6 @@ to the counterparty channel. Any timeout set to 0 is disabled.`), msg := types.NewMsgTransfer( srcPort, srcChannel, coin, sender, receiver, timeoutHeight, timeoutTimestamp, ) - if err := msg.ValidateBasic(); err != nil { - return err - } return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) }, diff --git a/x/ibc/applications/transfer/keeper/encoding.go b/x/ibc/applications/transfer/keeper/encoding.go index 9340095f3d..6cab8007a0 100644 --- a/x/ibc/applications/transfer/keeper/encoding.go +++ b/x/ibc/applications/transfer/keeper/encoding.go @@ -8,7 +8,7 @@ import ( // raw encoded bytes. func (k Keeper) UnmarshalDenomTrace(bz []byte) (types.DenomTrace, error) { var denomTrace types.DenomTrace - if err := k.cdc.UnmarshalBinaryBare(bz, &denomTrace); err != nil { + if err := k.cdc.Unmarshal(bz, &denomTrace); err != nil { return types.DenomTrace{}, err } return denomTrace, nil @@ -18,18 +18,18 @@ func (k Keeper) UnmarshalDenomTrace(bz []byte) (types.DenomTrace, error) { // raw encoded bytes. It panics on error. func (k Keeper) MustUnmarshalDenomTrace(bz []byte) types.DenomTrace { var denomTrace types.DenomTrace - k.cdc.MustUnmarshalBinaryBare(bz, &denomTrace) + k.cdc.MustUnmarshal(bz, &denomTrace) return denomTrace } // MarshalDenomTrace attempts to encode an DenomTrace object and returns the // raw encoded bytes. func (k Keeper) MarshalDenomTrace(denomTrace types.DenomTrace) ([]byte, error) { - return k.cdc.MarshalBinaryBare(&denomTrace) + return k.cdc.Marshal(&denomTrace) } // MustMarshalDenomTrace attempts to encode an DenomTrace object and returns the // raw encoded bytes. It panics on error. func (k Keeper) MustMarshalDenomTrace(denomTrace types.DenomTrace) []byte { - return k.cdc.MustMarshalBinaryBare(&denomTrace) + return k.cdc.MustMarshal(&denomTrace) } diff --git a/x/ibc/applications/transfer/keeper/keeper.go b/x/ibc/applications/transfer/keeper/keeper.go index d12e2e4183..5889161e03 100644 --- a/x/ibc/applications/transfer/keeper/keeper.go +++ b/x/ibc/applications/transfer/keeper/keeper.go @@ -20,8 +20,8 @@ import ( // Keeper defines the IBC fungible transfer keeper type Keeper struct { storeKey sdk.StoreKey - cdc codec.BinaryMarshaler - paramSpace *paramtypes.Subspace + cdc codec.Codec + paramSpace paramtypes.Subspace channelKeeper types.ChannelKeeper portKeeper types.PortKeeper @@ -32,7 +32,7 @@ type Keeper struct { // NewKeeper creates a new IBC transfer Keeper instance func NewKeeper( - cdc codec.BinaryMarshaler, key sdk.StoreKey, paramSpace *paramtypes.Subspace, + cdc codec.Codec, key sdk.StoreKey, paramSpace paramtypes.Subspace, channelKeeper types.ChannelKeeper, portKeeper types.PortKeeper, authKeeper types.AccountKeeper, bankKeeper types.BankKeeper, scopedKeeper capabilitykeeper.ScopedKeeper, ) Keeper { diff --git a/x/ibc/applications/transfer/keeper/mbt_relay_test.go b/x/ibc/applications/transfer/keeper/mbt_relay_test.go index 6e5008e2a9..330d827592 100644 --- a/x/ibc/applications/transfer/keeper/mbt_relay_test.go +++ b/x/ibc/applications/transfer/keeper/mbt_relay_test.go @@ -262,23 +262,6 @@ func BankOfChain(chain *ibctesting.TestChain) Bank { return bank } -// Set balances of the chain bank for balances present in the bank -func (suite *KeeperTestSuite) SetChainBankBalances(chain *ibctesting.TestChain, bank *Bank) error { - for coin, amount := range bank.balances { - err := sdk.ValidateAccAddress(coin.Address) - if err != nil { - return err - } - trace := types.ParseDenomTrace(coin.Denom) - err = chain.App.BankKeeper.SetBalance(chain.GetContext(), sdk.AccAddress(coin.Address), - sdk.NewCoin(trace.IBCDenom(), amount)) - if err != nil { - return err - } - } - return nil -} - // Check that the state of the bank is the bankBefore + expectedBankChange func (suite *KeeperTestSuite) CheckBankBalances(chain *ibctesting.TestChain, bankBefore *Bank, expectedBankChange *Bank) error { bankAfter := BankOfChain(chain) diff --git a/x/ibc/applications/transfer/keeper/relay_test.go b/x/ibc/applications/transfer/keeper/relay_test.go index 3077e9a857..5783ac6aa5 100644 --- a/x/ibc/applications/transfer/keeper/relay_test.go +++ b/x/ibc/applications/transfer/keeper/relay_test.go @@ -3,6 +3,7 @@ package keeper_test import ( "fmt" + "github.com/line/lbm-sdk/simapp" sdk "github.com/line/lbm-sdk/types" "github.com/line/lbm-sdk/x/ibc/applications/transfer/types" clienttypes "github.com/line/lbm-sdk/x/ibc/core/02-client/types" @@ -257,8 +258,7 @@ func (suite *KeeperTestSuite) TestOnAcknowledgementPacket() { trace = types.ParseDenomTrace(sdk.DefaultBondDenom) coin := sdk.NewCoin(sdk.DefaultBondDenom, amount) - err := suite.chainA.App.BankKeeper.AddCoins(suite.chainA.GetContext(), escrow, sdk.NewCoins(coin)) - suite.Require().NoError(err) + suite.Require().NoError(simapp.FundAccount(suite.chainA.App, suite.chainA.GetContext(), escrow, sdk.NewCoins(coin))) }, false, true}, {"unsuccessful refund from source", failedAck, func() { @@ -270,8 +270,7 @@ func (suite *KeeperTestSuite) TestOnAcknowledgementPacket() { trace = types.ParseDenomTrace(types.GetPrefixedDenom(channelA.PortID, channelA.ID, sdk.DefaultBondDenom)) coin := sdk.NewCoin(trace.IBCDenom(), amount) - err := suite.chainA.App.BankKeeper.AddCoins(suite.chainA.GetContext(), escrow, sdk.NewCoins(coin)) - suite.Require().NoError(err) + suite.Require().NoError(simapp.FundAccount(suite.chainA.App, suite.chainA.GetContext(), escrow, sdk.NewCoins(coin))) }, false, true}, } @@ -332,8 +331,7 @@ func (suite *KeeperTestSuite) TestOnTimeoutPacket() { trace = types.ParseDenomTrace(sdk.DefaultBondDenom) coin := sdk.NewCoin(trace.IBCDenom(), amount) - err := suite.chainA.App.BankKeeper.AddCoins(suite.chainA.GetContext(), escrow, sdk.NewCoins(coin)) - suite.Require().NoError(err) + suite.Require().NoError(simapp.FundAccount(suite.chainA.App, suite.chainA.GetContext(), escrow, sdk.NewCoins(coin))) }, true}, {"successful timeout from external chain", func() { @@ -341,8 +339,7 @@ func (suite *KeeperTestSuite) TestOnTimeoutPacket() { trace = types.ParseDenomTrace(types.GetPrefixedDenom(channelA.PortID, channelA.ID, sdk.DefaultBondDenom)) coin := sdk.NewCoin(trace.IBCDenom(), amount) - err := suite.chainA.App.BankKeeper.AddCoins(suite.chainA.GetContext(), escrow, sdk.NewCoins(coin)) - suite.Require().NoError(err) + suite.Require().NoError(simapp.FundAccount(suite.chainA.App, suite.chainA.GetContext(), escrow, sdk.NewCoins(coin))) }, true}, {"no balance for coin denom", func() { diff --git a/x/ibc/applications/transfer/module.go b/x/ibc/applications/transfer/module.go index ae44955240..d019814ed6 100644 --- a/x/ibc/applications/transfer/module.go +++ b/x/ibc/applications/transfer/module.go @@ -57,12 +57,12 @@ func (AppModuleBasic) RegisterInterfaces(registry codectypes.InterfaceRegistry) // DefaultGenesis returns default genesis state as raw bytes for the ibc // transfer module. -func (AppModuleBasic) DefaultGenesis(cdc codec.JSONMarshaler) json.RawMessage { +func (AppModuleBasic) DefaultGenesis(cdc codec.JSONCodec) json.RawMessage { return cdc.MustMarshalJSON(types.DefaultGenesisState()) } // ValidateGenesis performs genesis state validation for the ibc transfer module. -func (AppModuleBasic) ValidateGenesis(cdc codec.JSONMarshaler, config client.TxEncodingConfig, bz json.RawMessage) error { +func (AppModuleBasic) ValidateGenesis(cdc codec.JSONCodec, config client.TxEncodingConfig, bz json.RawMessage) error { var gs types.GenesisState if err := cdc.UnmarshalJSON(bz, &gs); err != nil { return fmt.Errorf("failed to unmarshal %s genesis state: %w", types.ModuleName, err) @@ -131,7 +131,7 @@ func (am AppModule) RegisterServices(cfg module.Configurator) { // InitGenesis performs genesis initialization for the ibc-transfer module. It returns // no validator updates. -func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONMarshaler, data json.RawMessage) []abci.ValidatorUpdate { +func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONCodec, data json.RawMessage) []abci.ValidatorUpdate { var genesisState types.GenesisState cdc.MustUnmarshalJSON(data, &genesisState) am.keeper.InitGenesis(ctx, genesisState) @@ -140,7 +140,7 @@ func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONMarshaler, data j // ExportGenesis returns the exported genesis state as raw bytes for the ibc-transfer // module. -func (am AppModule) ExportGenesis(ctx sdk.Context, cdc codec.JSONMarshaler) json.RawMessage { +func (am AppModule) ExportGenesis(ctx sdk.Context, cdc codec.JSONCodec) json.RawMessage { gs := am.keeper.ExportGenesis(ctx) return cdc.MustMarshalJSON(gs) } @@ -157,8 +157,6 @@ func (am AppModule) EndBlock(ctx sdk.Context, req abci.RequestEndBlock) []abci.V return []abci.ValidatorUpdate{} } -// ____________________________________________________________________________ - // AppModuleSimulation functions // GenerateGenesisState creates a randomized GenState of the transfer module. @@ -186,8 +184,6 @@ func (am AppModule) WeightedOperations(_ module.SimulationState) []simtypes.Weig return nil } -// ____________________________________________________________________________ - // ValidateTransferChannelParams does validation of a newly created transfer channel. A transfer // channel must be UNORDERED, use the correct port (by default 'transfer'), and use the current // supported version. Only 2^32 channels are allowed to be created. @@ -200,7 +196,7 @@ func ValidateTransferChannelParams( version string, ) error { // NOTE: for escrow address security only 2^32 channels are allowed to be created - // Issue: https://github.com/line/lbm-sdk/issues/7737 + // Issue: https://github.com/cosmos/cosmos-sdk/issues/7737 channelSequence, err := channeltypes.ParseChannelSequence(channelID) if err != nil { return err @@ -382,7 +378,7 @@ func (am AppModule) OnAcknowledgementPacket( sdk.NewAttribute(types.AttributeKeyReceiver, data.Receiver), sdk.NewAttribute(types.AttributeKeyDenom, data.Denom), sdk.NewAttribute(types.AttributeKeyAmount, fmt.Sprintf("%d", data.Amount)), - sdk.NewAttribute(types.AttributeKeyAck, fmt.Sprintf("%v", ack)), + sdk.NewAttribute(types.AttributeKeyAck, ack.String()), ), ) diff --git a/x/ibc/applications/transfer/types/query.pb.gw.go b/x/ibc/applications/transfer/types/query.pb.gw.go index bc2c16afa7..ab89f16604 100644 --- a/x/ibc/applications/transfer/types/query.pb.gw.go +++ b/x/ibc/applications/transfer/types/query.pb.gw.go @@ -310,11 +310,11 @@ func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, clie } var ( - pattern_Query_DenomTrace_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 1, 0, 4, 1, 5, 5}, []string{"ibc", "applications", "transfer", "v1", "denom_traces", "hash"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_Query_DenomTrace_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 1, 0, 4, 1, 5, 5}, []string{"ibc", "applications", "transfer", "v1", "denom_traces", "hash"}, "", runtime.AssumeColonVerbOpt(false))) - pattern_Query_DenomTraces_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4}, []string{"ibc", "applications", "transfer", "v1", "denom_traces"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_Query_DenomTraces_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4}, []string{"ibc", "applications", "transfer", "v1", "denom_traces"}, "", runtime.AssumeColonVerbOpt(false))) - pattern_Query_Params_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4}, []string{"ibc", "applications", "transfer", "v1", "params"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_Query_Params_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4}, []string{"ibc", "applications", "transfer", "v1", "params"}, "", runtime.AssumeColonVerbOpt(false))) ) var ( diff --git a/x/ibc/core/02-client/abci.go b/x/ibc/core/02-client/abci.go index 25da3f7067..f672f54f30 100644 --- a/x/ibc/core/02-client/abci.go +++ b/x/ibc/core/02-client/abci.go @@ -4,11 +4,32 @@ import ( sdk "github.com/line/lbm-sdk/types" "github.com/line/lbm-sdk/x/ibc/core/02-client/keeper" "github.com/line/lbm-sdk/x/ibc/core/exported" + ibcoctypes "github.com/line/lbm-sdk/x/ibc/light-clients/99-ostracon/types" ) // BeginBlocker updates an existing localhost client with the latest block height. func BeginBlocker(ctx sdk.Context, k keeper.Keeper) { - _, found := k.GetClientState(ctx, exported.Localhost) + plan, found := k.GetUpgradePlan(ctx) + if found { + // Once we are at the last block this chain will commit, set the upgraded consensus state + // so that IBC clients can use the last NextValidatorsHash as a trusted kernel for verifying + // headers on the next version of the chain. + // Set the time to the last block time of the current chain. + // In order for a client to upgrade successfully, the first block of the new chain must be committed + // within the trusting period of the last block time on this chain. + _, exists := k.GetUpgradedClient(ctx, plan.Height) + if exists && ctx.BlockHeight() == plan.Height-1 { + upgradedConsState := &ibcoctypes.ConsensusState{ + Timestamp: ctx.BlockTime(), + NextValidatorsHash: ctx.BlockHeader().NextValidatorsHash, + } + bz := k.MustMarshalConsensusState(upgradedConsState) + + k.SetUpgradedConsensusState(ctx, plan.Height, bz) + } + } + + _, found = k.GetClientState(ctx, exported.Localhost) if !found { return } diff --git a/x/ibc/core/02-client/abci_test.go b/x/ibc/core/02-client/abci_test.go index 8dbcfb6d61..7b38349baf 100644 --- a/x/ibc/core/02-client/abci_test.go +++ b/x/ibc/core/02-client/abci_test.go @@ -3,13 +3,17 @@ package client_test import ( "testing" + abci "github.com/line/ostracon/abci/types" + ocproto "github.com/line/ostracon/proto/ostracon/types" "github.com/stretchr/testify/suite" client "github.com/line/lbm-sdk/x/ibc/core/02-client" "github.com/line/lbm-sdk/x/ibc/core/02-client/types" "github.com/line/lbm-sdk/x/ibc/core/exported" localhoctypes "github.com/line/lbm-sdk/x/ibc/light-clients/09-localhost/types" + ibcoctypes "github.com/line/lbm-sdk/x/ibc/light-clients/99-ostracon/types" ibctesting "github.com/line/lbm-sdk/x/ibc/testing" + upgradetypes "github.com/line/lbm-sdk/x/upgrade/types" ) type ClientTestSuite struct { @@ -58,3 +62,33 @@ func (suite *ClientTestSuite) TestBeginBlocker() { prevHeight = localHostClient.GetLatestHeight().(types.Height) } } + +func (suite *ClientTestSuite) TestBeginBlockerConsensusState() { + plan := &upgradetypes.Plan{ + Name: "test", + Height: suite.chainA.GetContext().BlockHeight() + 1, + } + // set upgrade plan in the upgrade store + store := suite.chainA.GetContext().KVStore(suite.chainA.App.GetKey(upgradetypes.StoreKey)) + bz := suite.chainA.App.AppCodec().MustMarshal(plan) + store.Set(upgradetypes.PlanKey(), bz) + + nextValsHash := []byte("nextValsHash") + newCtx := suite.chainA.GetContext().WithBlockHeader(ocproto.Header{ + Height: suite.chainA.GetContext().BlockHeight(), + NextValidatorsHash: nextValsHash, + }) + + err := suite.chainA.App.UpgradeKeeper.SetUpgradedClient(newCtx, plan.Height, []byte("client state")) + suite.Require().NoError(err) + + req := abci.RequestBeginBlock{Header: newCtx.BlockHeader()} + suite.chainA.App.BeginBlock(req) + + // plan Height is at ctx.BlockHeight+1 + consState, found := suite.chainA.App.UpgradeKeeper.GetUpgradedConsensusState(newCtx, plan.Height) + suite.Require().True(found) + bz, err = types.MarshalConsensusState(suite.chainA.App.AppCodec(), &ibcoctypes.ConsensusState{Timestamp: newCtx.BlockTime(), NextValidatorsHash: nextValsHash}) + suite.Require().NoError(err) + suite.Require().Equal(bz, consState) +} diff --git a/x/ibc/core/02-client/client/cli/cli.go b/x/ibc/core/02-client/client/cli/cli.go index d7d8b3d5f4..172d99aed2 100644 --- a/x/ibc/core/02-client/client/cli/cli.go +++ b/x/ibc/core/02-client/client/cli/cli.go @@ -29,3 +29,23 @@ func GetQueryCmd() *cobra.Command { return queryCmd } + +// NewTxCmd returns the command to create and handle IBC clients +func NewTxCmd() *cobra.Command { + txCmd := &cobra.Command{ + Use: types.SubModuleName, + Short: "IBC client transaction subcommands", + DisableFlagParsing: true, + SuggestionsMinimumDistance: 2, + RunE: client.ValidateCmd, + } + + txCmd.AddCommand( + NewCreateClientCmd(), + NewUpdateClientCmd(), + NewSubmitMisbehaviourCmd(), + NewUpgradeClientCmd(), + ) + + return txCmd +} diff --git a/x/ibc/core/02-client/client/cli/query.go b/x/ibc/core/02-client/client/cli/query.go index 9a94fb98e4..3506b539d3 100644 --- a/x/ibc/core/02-client/client/cli/query.go +++ b/x/ibc/core/02-client/client/cli/query.go @@ -1,7 +1,6 @@ package cli import ( - "context" "errors" "fmt" @@ -44,7 +43,7 @@ func GetCmdQueryClientStates() *cobra.Command { Pagination: pageReq, } - res, err := queryClient.ClientStates(context.Background(), req) + res, err := queryClient.ClientStates(cmd.Context(), req) if err != nil { return err } @@ -118,7 +117,7 @@ func GetCmdQueryConsensusStates() *cobra.Command { Pagination: pageReq, } - res, err := queryClient.ConsensusStates(context.Background(), req) + res, err := queryClient.ConsensusStates(cmd.Context(), req) if err != nil { return err } @@ -193,12 +192,11 @@ func GetCmdQueryHeader() *cobra.Command { if err != nil { return err } - header, height, err := utils.QueryOstraconHeader(clientCtx) + header, _, err := utils.QueryOstraconHeader(clientCtx) if err != nil { return err } - clientCtx = clientCtx.WithHeight(height) return clientCtx.PrintProto(&header) }, } @@ -222,12 +220,11 @@ func GetCmdNodeConsensusState() *cobra.Command { if err != nil { return err } - state, height, err := utils.QueryNodeConsensusState(clientCtx) + state, _, err := utils.QueryNodeConsensusState(clientCtx) if err != nil { return err } - clientCtx = clientCtx.WithHeight(height) return clientCtx.PrintProto(state) }, } @@ -252,7 +249,7 @@ func GetCmdParams() *cobra.Command { } queryClient := types.NewQueryClient(clientCtx) - res, _ := queryClient.ClientParams(context.Background(), &types.QueryClientParamsRequest{}) + res, _ := queryClient.ClientParams(cmd.Context(), &types.QueryClientParamsRequest{}) return clientCtx.PrintProto(res.Params) }, } diff --git a/x/ibc/core/02-client/client/cli/tx.go b/x/ibc/core/02-client/client/cli/tx.go new file mode 100644 index 0000000000..17ebe38fcb --- /dev/null +++ b/x/ibc/core/02-client/client/cli/tx.go @@ -0,0 +1,389 @@ +package cli + +import ( + "fmt" + "io/ioutil" + + "github.com/pkg/errors" + "github.com/spf13/cobra" + + "github.com/line/lbm-sdk/client" + "github.com/line/lbm-sdk/client/flags" + "github.com/line/lbm-sdk/client/tx" + "github.com/line/lbm-sdk/codec" + sdk "github.com/line/lbm-sdk/types" + "github.com/line/lbm-sdk/version" + govcli "github.com/line/lbm-sdk/x/gov/client/cli" + govtypes "github.com/line/lbm-sdk/x/gov/types" + "github.com/line/lbm-sdk/x/ibc/core/02-client/types" + "github.com/line/lbm-sdk/x/ibc/core/exported" + upgradetypes "github.com/line/lbm-sdk/x/upgrade/types" +) + +// NewCreateClientCmd defines the command to create a new IBC light client. +func NewCreateClientCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "create [path/to/client_state.json] [path/to/consensus_state.json]", + Short: "create new IBC client", + Long: `create a new IBC client with the specified client state and consensus state + - ClientState JSON example: {"@type":"/ibc.lightclients.solomachine.v1.ClientState","sequence":"1","frozen_sequence":"0","consensus_state":{"public_key":{"@type":"/lbm.crypto.secp256k1.PubKey","key":"AtK50+5pJOoaa04qqAqrnyAqsYrwrR/INnA6UPIaYZlp"},"diversifier":"testing","timestamp":"10"},"allow_update_after_proposal":false} + - ConsensusState JSON example: {"@type":"/ibc.lightclients.solomachine.v1.ConsensusState","public_key":{"@type":"/lbm.crypto.secp256k1.PubKey","key":"AtK50+5pJOoaa04qqAqrnyAqsYrwrR/INnA6UPIaYZlp"},"diversifier":"testing","timestamp":"10"}`, + Example: fmt.Sprintf("%s tx ibc %s create [path/to/client_state.json] [path/to/consensus_state.json] --from node0 --home ../node0/cli --chain-id $CID", version.AppName, types.SubModuleName), + Args: cobra.ExactArgs(2), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + cdc := codec.NewProtoCodec(clientCtx.InterfaceRegistry) + + // attempt to unmarshal client state argument + var clientState exported.ClientState + clientContentOrFileName := args[0] + if err := cdc.UnmarshalInterfaceJSON([]byte(clientContentOrFileName), &clientState); err != nil { + + // check for file path if JSON input is not provided + contents, err := ioutil.ReadFile(clientContentOrFileName) + if err != nil { + return errors.Wrap(err, "neither JSON input nor path to .json file for client state were provided") + } + + if err := cdc.UnmarshalInterfaceJSON(contents, &clientState); err != nil { + return errors.Wrap(err, "error unmarshalling client state file") + } + } + + // attempt to unmarshal consensus state argument + var consensusState exported.ConsensusState + consensusContentOrFileName := args[1] + if err := cdc.UnmarshalInterfaceJSON([]byte(consensusContentOrFileName), &consensusState); err != nil { + + // check for file path if JSON input is not provided + contents, err := ioutil.ReadFile(consensusContentOrFileName) + if err != nil { + return errors.Wrap(err, "neither JSON input nor path to .json file for consensus state were provided") + } + + if err := cdc.UnmarshalInterfaceJSON(contents, &consensusState); err != nil { + return errors.Wrap(err, "error unmarshalling consensus state file") + } + } + + msg, err := types.NewMsgCreateClient(clientState, consensusState, clientCtx.GetFromAddress()) + if err != nil { + return err + } + + return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) + }, + } + + flags.AddTxFlagsToCmd(cmd) + + return cmd +} + +// NewUpdateClientCmd defines the command to update an IBC client. +func NewUpdateClientCmd() *cobra.Command { + return &cobra.Command{ + Use: "update [client-id] [path/to/header.json]", + Short: "update existing client with a header", + Long: "update existing client with a header", + Example: fmt.Sprintf("%s tx ibc %s update [client-id] [path/to/header.json] --from node0 --home ../node0/cli --chain-id $CID", version.AppName, types.SubModuleName), + Args: cobra.ExactArgs(2), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + clientID := args[0] + + cdc := codec.NewProtoCodec(clientCtx.InterfaceRegistry) + + var header exported.Header + headerContentOrFileName := args[1] + if err := cdc.UnmarshalInterfaceJSON([]byte(headerContentOrFileName), &header); err != nil { + + // check for file path if JSON input is not provided + contents, err := ioutil.ReadFile(headerContentOrFileName) + if err != nil { + return errors.Wrap(err, "neither JSON input nor path to .json file for header were provided") + } + + if err := cdc.UnmarshalInterfaceJSON(contents, &header); err != nil { + return errors.Wrap(err, "error unmarshalling header file") + } + } + + msg, err := types.NewMsgUpdateClient(clientID, header, clientCtx.GetFromAddress()) + if err != nil { + return err + } + + return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) + }, + } +} + +// NewSubmitMisbehaviourCmd defines the command to submit a misbehaviour to prevent +// future updates. +func NewSubmitMisbehaviourCmd() *cobra.Command { + return &cobra.Command{ + Use: "misbehaviour [path/to/misbehaviour.json]", + Short: "submit a client misbehaviour", + Long: "submit a client misbehaviour to prevent future updates", + Example: fmt.Sprintf("%s tx ibc %s misbehaviour [path/to/misbehaviour.json] --from node0 --home ../node0/cli --chain-id $CID", version.AppName, types.SubModuleName), + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + cdc := codec.NewProtoCodec(clientCtx.InterfaceRegistry) + + var misbehaviour exported.Misbehaviour + misbehaviourContentOrFileName := args[0] + if err := cdc.UnmarshalInterfaceJSON([]byte(misbehaviourContentOrFileName), &misbehaviour); err != nil { + + // check for file path if JSON input is not provided + contents, err := ioutil.ReadFile(misbehaviourContentOrFileName) + if err != nil { + return errors.Wrap(err, "neither JSON input nor path to .json file for misbehaviour were provided") + } + + if err := cdc.UnmarshalInterfaceJSON(contents, misbehaviour); err != nil { + return errors.Wrap(err, "error unmarshalling misbehaviour file") + } + } + + msg, err := types.NewMsgSubmitMisbehaviour(misbehaviour.GetClientID(), misbehaviour, clientCtx.GetFromAddress()) + if err != nil { + return err + } + + return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) + }, + } +} + +// NewUpgradeClientCmd defines the command to upgrade an IBC light client. +func NewUpgradeClientCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "upgrade [client-identifier] [path/to/client_state.json] [path/to/consensus_state.json] [upgrade-client-proof] [upgrade-consensus-state-proof]", + Short: "upgrade an IBC client", + Long: `upgrade the IBC client associated with the provided client identifier while providing proof committed by the counterparty chain to the new client and consensus states + - ClientState JSON example: {"@type":"/ibc.lightclients.solomachine.v1.ClientState","sequence":"1","frozen_sequence":"0","consensus_state":{"public_key":{"@type":"/lbm.crypto.secp256k1.PubKey","key":"AtK50+5pJOoaa04qqAqrnyAqsYrwrR/INnA6UPIaYZlp"},"diversifier":"testing","timestamp":"10"},"allow_update_after_proposal":false} + - ConsensusState JSON example: {"@type":"/ibc.lightclients.solomachine.v1.ConsensusState","public_key":{"@type":"/lbm.crypto.secp256k1.PubKey","key":"AtK50+5pJOoaa04qqAqrnyAqsYrwrR/INnA6UPIaYZlp"},"diversifier":"testing","timestamp":"10"}`, + Example: fmt.Sprintf("%s tx ibc %s upgrade [client-identifier] [path/to/client_state.json] [path/to/consensus_state.json] [client-state-proof] [consensus-state-proof] --from node0 --home ../node0/cli --chain-id $CID", version.AppName, types.SubModuleName), + Args: cobra.ExactArgs(5), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + cdc := codec.NewProtoCodec(clientCtx.InterfaceRegistry) + clientID := args[0] + + // attempt to unmarshal client state argument + var clientState exported.ClientState + clientContentOrFileName := args[1] + if err := cdc.UnmarshalInterfaceJSON([]byte(clientContentOrFileName), &clientState); err != nil { + + // check for file path if JSON input is not provided + contents, err := ioutil.ReadFile(clientContentOrFileName) + if err != nil { + return errors.Wrap(err, "neither JSON input nor path to .json file for client state were provided") + } + + if err := cdc.UnmarshalInterfaceJSON(contents, &clientState); err != nil { + return errors.Wrap(err, "error unmarshalling client state file") + } + } + + // attempt to unmarshal consensus state argument + var consensusState exported.ConsensusState + consensusContentOrFileName := args[2] + if err := cdc.UnmarshalInterfaceJSON([]byte(consensusContentOrFileName), &consensusState); err != nil { + + // check for file path if JSON input is not provided + contents, err := ioutil.ReadFile(consensusContentOrFileName) + if err != nil { + return errors.Wrap(err, "neither JSON input nor path to .json file for consensus state were provided") + } + + if err := cdc.UnmarshalInterfaceJSON(contents, &consensusState); err != nil { + return errors.Wrap(err, "error unmarshalling consensus state file") + } + } + + proofUpgradeClient := []byte(args[3]) + proofUpgradeConsensus := []byte(args[4]) + + msg, err := types.NewMsgUpgradeClient(clientID, clientState, consensusState, proofUpgradeClient, proofUpgradeConsensus, clientCtx.GetFromAddress()) + if err != nil { + return err + } + + return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) + }, + } + + flags.AddTxFlagsToCmd(cmd) + + return cmd +} + +// NewCmdSubmitUpdateClientProposal implements a command handler for submitting an update IBC client proposal transaction. +func NewCmdSubmitUpdateClientProposal() *cobra.Command { + cmd := &cobra.Command{ + Use: "update-client [subject-client-id] [substitute-client-id] [initial-height] [flags]", + Args: cobra.ExactArgs(3), + Short: "Submit an update IBC client proposal", + Long: "Submit an update IBC client proposal along with an initial deposit.\n" + + "Please specify a subject client identifier you want to update..\n" + + "Please specify the substitute client the subject client will use and the initial height to reference the substitute client's state.", + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + + title, err := cmd.Flags().GetString(govcli.FlagTitle) + if err != nil { + return err + } + + description, err := cmd.Flags().GetString(govcli.FlagDescription) + if err != nil { + return err + } + + subjectClientID := args[0] + substituteClientID := args[1] + + initialHeight, err := types.ParseHeight(args[2]) + if err != nil { + return err + } + + content := types.NewClientUpdateProposal(title, description, subjectClientID, substituteClientID, initialHeight) + + from := clientCtx.GetFromAddress() + + depositStr, err := cmd.Flags().GetString(govcli.FlagDeposit) + if err != nil { + return err + } + deposit, err := sdk.ParseCoinsNormalized(depositStr) + if err != nil { + return err + } + + msg, err := govtypes.NewMsgSubmitProposal(content, deposit, from) + if err != nil { + return err + } + + if err = msg.ValidateBasic(); err != nil { + return err + } + + return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) + }, + } + + cmd.Flags().String(govcli.FlagTitle, "", "title of proposal") + cmd.Flags().String(govcli.FlagDescription, "", "description of proposal") + cmd.Flags().String(govcli.FlagDeposit, "", "deposit of proposal") + + return cmd +} + +// NewCmdSubmitUpgradeProposal implements a command handler for submitting an upgrade IBC client proposal transaction. +func NewCmdSubmitUpgradeProposal() *cobra.Command { + cmd := &cobra.Command{ + Use: "ibc-upgrade [name] [height] [path/to/upgraded_client_state.json] [flags]", + Args: cobra.ExactArgs(3), + Short: "Submit an IBC upgrade proposal", + Long: "Submit an IBC client breaking upgrade proposal along with an initial deposit.\n" + + "The client state specified is the upgraded client state representing the upgraded chain", + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + cdc := codec.NewProtoCodec(clientCtx.InterfaceRegistry) + + title, err := cmd.Flags().GetString(govcli.FlagTitle) + if err != nil { + return err + } + + description, err := cmd.Flags().GetString(govcli.FlagDescription) + if err != nil { + return err + } + + name := args[0] + + height, err := cmd.Flags().GetInt64(args[1]) + if err != nil { + return err + } + + plan := upgradetypes.Plan{ + Name: name, + Height: height, + } + + // attempt to unmarshal client state argument + var clientState exported.ClientState + clientContentOrFileName := args[2] + if err := cdc.UnmarshalInterfaceJSON([]byte(clientContentOrFileName), &clientState); err != nil { + + // check for file path if JSON input is not provided + contents, err := ioutil.ReadFile(clientContentOrFileName) + if err != nil { + return errors.Wrap(err, "neither JSON input nor path to .json file for client state were provided") + } + + if err := cdc.UnmarshalInterfaceJSON(contents, &clientState); err != nil { + return errors.Wrap(err, "error unmarshalling client state file") + } + } + + content, err := types.NewUpgradeProposal(title, description, plan, clientState) + if err != nil { + return err + } + + from := clientCtx.GetFromAddress() + + depositStr, err := cmd.Flags().GetString(govcli.FlagDeposit) + if err != nil { + return err + } + deposit, err := sdk.ParseCoinsNormalized(depositStr) + if err != nil { + return err + } + + msg, err := govtypes.NewMsgSubmitProposal(content, deposit, from) + if err != nil { + return err + } + + if err = msg.ValidateBasic(); err != nil { + return err + } + + return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) + }, + } + + cmd.Flags().String(govcli.FlagTitle, "", "title of proposal") + cmd.Flags().String(govcli.FlagDescription, "", "description of proposal") + cmd.Flags().String(govcli.FlagDeposit, "", "deposit of proposal") + + return cmd +} diff --git a/x/ibc/core/02-client/client/proposal_handler.go b/x/ibc/core/02-client/client/proposal_handler.go new file mode 100644 index 0000000000..f75e9c64c5 --- /dev/null +++ b/x/ibc/core/02-client/client/proposal_handler.go @@ -0,0 +1,25 @@ +package client + +import ( + "net/http" + + "github.com/line/lbm-sdk/client" + "github.com/line/lbm-sdk/types/rest" + govclient "github.com/line/lbm-sdk/x/gov/client" + govrest "github.com/line/lbm-sdk/x/gov/client/rest" + "github.com/line/lbm-sdk/x/ibc/core/02-client/client/cli" +) + +var ( + UpdateClientProposalHandler = govclient.NewProposalHandler(cli.NewCmdSubmitUpdateClientProposal, emptyRestHandler) + UpgradeProposalHandler = govclient.NewProposalHandler(cli.NewCmdSubmitUpgradeProposal, emptyRestHandler) +) + +func emptyRestHandler(client.Context) govrest.ProposalRESTHandler { + return govrest.ProposalRESTHandler{ + SubRoute: "unsupported-ibc-client", + Handler: func(w http.ResponseWriter, r *http.Request) { + rest.WriteErrorResponse(w, http.StatusBadRequest, "Legacy REST Routes are not supported for IBC proposals") + }, + } +} diff --git a/x/ibc/core/02-client/keeper/client_test.go b/x/ibc/core/02-client/keeper/client_test.go index d5f2701d13..7e45e56244 100644 --- a/x/ibc/core/02-client/keeper/client_test.go +++ b/x/ibc/core/02-client/keeper/client_test.go @@ -235,6 +235,8 @@ func (suite *KeeperTestSuite) TestUpgradeClient() { lastHeight exported.Height clientA string proofUpgradedClient, proofUpgradedConsState []byte + upgradedClientBz, upgradedConsStateBz []byte + err error ) testCases := []struct { @@ -245,18 +247,12 @@ func (suite *KeeperTestSuite) TestUpgradeClient() { { name: "successful upgrade", setup: func() { - - upgradedClient = ibctmtypes.NewClientState("newChainId", ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod+trustingPeriod, maxClockDrift, newClientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false) - upgradedConsState = &ibctmtypes.ConsensusState{ - NextValidatorsHash: []byte("nextValsHash"), - } - // last Height is at next block lastHeight = clienttypes.NewHeight(0, uint64(suite.chainB.GetContext().BlockHeight()+1)) // zero custom fields and store in upgrade store - suite.chainB.App.UpgradeKeeper.SetUpgradedClient(suite.chainB.GetContext(), int64(lastHeight.GetRevisionHeight()), upgradedClient) - suite.chainB.App.UpgradeKeeper.SetUpgradedConsensusState(suite.chainB.GetContext(), int64(lastHeight.GetRevisionHeight()), upgradedConsState) + suite.chainB.App.UpgradeKeeper.SetUpgradedClient(suite.chainB.GetContext(), int64(lastHeight.GetRevisionHeight()), upgradedClientBz) + suite.chainB.App.UpgradeKeeper.SetUpgradedConsensusState(suite.chainB.GetContext(), int64(lastHeight.GetRevisionHeight()), upgradedConsStateBz) // commit upgrade store changes and update clients @@ -275,18 +271,12 @@ func (suite *KeeperTestSuite) TestUpgradeClient() { { name: "client state not found", setup: func() { - - upgradedClient = ibctmtypes.NewClientState("newChainId", ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod+trustingPeriod, maxClockDrift, newClientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false) - upgradedConsState = &ibctmtypes.ConsensusState{ - NextValidatorsHash: []byte("nextValsHash"), - } - // last Height is at next block lastHeight = clienttypes.NewHeight(0, uint64(suite.chainB.GetContext().BlockHeight()+1)) // zero custom fields and store in upgrade store - suite.chainB.App.UpgradeKeeper.SetUpgradedClient(suite.chainB.GetContext(), int64(lastHeight.GetRevisionHeight()), upgradedClient) - suite.chainB.App.UpgradeKeeper.SetUpgradedConsensusState(suite.chainB.GetContext(), int64(lastHeight.GetRevisionHeight()), upgradedConsState) + suite.chainB.App.UpgradeKeeper.SetUpgradedClient(suite.chainB.GetContext(), int64(lastHeight.GetRevisionHeight()), upgradedClientBz) + suite.chainB.App.UpgradeKeeper.SetUpgradedConsensusState(suite.chainB.GetContext(), int64(lastHeight.GetRevisionHeight()), upgradedConsStateBz) // commit upgrade store changes and update clients @@ -307,18 +297,12 @@ func (suite *KeeperTestSuite) TestUpgradeClient() { { name: "client state frozen", setup: func() { - - upgradedClient = ibctmtypes.NewClientState("newChainId", ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod+trustingPeriod, maxClockDrift, newClientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false) - upgradedConsState = &ibctmtypes.ConsensusState{ - NextValidatorsHash: []byte("nextValsHash"), - } - // last Height is at next block lastHeight = clienttypes.NewHeight(0, uint64(suite.chainB.GetContext().BlockHeight()+1)) // zero custom fields and store in upgrade store - suite.chainB.App.UpgradeKeeper.SetUpgradedClient(suite.chainB.GetContext(), int64(lastHeight.GetRevisionHeight()), upgradedClient) - suite.chainB.App.UpgradeKeeper.SetUpgradedConsensusState(suite.chainB.GetContext(), int64(lastHeight.GetRevisionHeight()), upgradedConsState) + suite.chainB.App.UpgradeKeeper.SetUpgradedClient(suite.chainB.GetContext(), int64(lastHeight.GetRevisionHeight()), upgradedClientBz) + suite.chainB.App.UpgradeKeeper.SetUpgradedConsensusState(suite.chainB.GetContext(), int64(lastHeight.GetRevisionHeight()), upgradedConsStateBz) // commit upgrade store changes and update clients @@ -343,18 +327,12 @@ func (suite *KeeperTestSuite) TestUpgradeClient() { { name: "tendermint client VerifyUpgrade fails", setup: func() { - - upgradedClient = ibctmtypes.NewClientState("newChainId", ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod+trustingPeriod, maxClockDrift, newClientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false) - upgradedConsState = &ibctmtypes.ConsensusState{ - NextValidatorsHash: []byte("nextValsHash"), - } - // last Height is at next block lastHeight = clienttypes.NewHeight(0, uint64(suite.chainB.GetContext().BlockHeight()+1)) // zero custom fields and store in upgrade store - suite.chainB.App.UpgradeKeeper.SetUpgradedClient(suite.chainB.GetContext(), int64(lastHeight.GetRevisionHeight()), upgradedClient) - suite.chainB.App.UpgradeKeeper.SetUpgradedConsensusState(suite.chainB.GetContext(), int64(lastHeight.GetRevisionHeight()), upgradedConsState) + suite.chainB.App.UpgradeKeeper.SetUpgradedClient(suite.chainB.GetContext(), int64(lastHeight.GetRevisionHeight()), upgradedClientBz) + suite.chainB.App.UpgradeKeeper.SetUpgradedConsensusState(suite.chainB.GetContext(), int64(lastHeight.GetRevisionHeight()), upgradedConsStateBz) // change upgradedClient client-specified parameters upgradedClient = ibctmtypes.NewClientState("wrongchainID", ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, newClientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, true, true) @@ -376,13 +354,23 @@ func (suite *KeeperTestSuite) TestUpgradeClient() { for _, tc := range testCases { tc := tc clientA, _ = suite.coordinator.SetupClients(suite.chainA, suite.chainB, exported.Ostracon) + upgradedClient = ibctmtypes.NewClientState("newChainId", ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod+trustingPeriod, maxClockDrift, newClientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false) + upgradedClient = upgradedClient.ZeroCustomFields() + upgradedClientBz, err = types.MarshalClientState(suite.chainA.App.AppCodec(), upgradedClient) + suite.Require().NoError(err) + + upgradedConsState = &ibctmtypes.ConsensusState{ + NextValidatorsHash: []byte("nextValsHash"), + } + upgradedConsStateBz, err = types.MarshalConsensusState(suite.chainA.App.AppCodec(), upgradedConsState) + suite.Require().NoError(err) tc.setup() // Call ZeroCustomFields on upgraded clients to clear any client-chosen parameters in test-case upgradedClient upgradedClient = upgradedClient.ZeroCustomFields() - err := suite.chainA.App.IBCKeeper.ClientKeeper.UpgradeClient(suite.chainA.GetContext(), clientA, upgradedClient, upgradedConsState, proofUpgradedClient, proofUpgradedConsState) + err = suite.chainA.App.IBCKeeper.ClientKeeper.UpgradeClient(suite.chainA.GetContext(), clientA, upgradedClient, upgradedConsState, proofUpgradedClient, proofUpgradedConsState) if tc.expPass { suite.Require().NoError(err, "verify upgrade failed on valid case: %s", tc.name) @@ -623,7 +611,7 @@ func (suite *KeeperTestSuite) TestUpdateClientEventEmission() { result, err := suite.chainA.SendMsgs(msg) suite.Require().NoError(err) // first 3 event type are "tx.signature", "tx.acc_seq", and "message" - updateEvent := result.Events[3] + updateEvent := result.Events[4] suite.Require().Equal(clienttypes.EventTypeUpdateClient, updateEvent.Type) diff --git a/x/ibc/core/02-client/keeper/grpc_query.go b/x/ibc/core/02-client/keeper/grpc_query.go index 82318b1d88..c20ddc1206 100644 --- a/x/ibc/core/02-client/keeper/grpc_query.go +++ b/x/ibc/core/02-client/keeper/grpc_query.go @@ -1,6 +1,7 @@ package keeper import ( + "bytes" "context" "fmt" "sort" @@ -159,7 +160,7 @@ func (q Keeper) ConsensusStates(c context.Context, req *types.QueryConsensusStat pageRes, err := query.FilteredPaginate(store, req.Pagination, func(key, value []byte, accumulate bool) (bool, error) { // filter any metadata stored under consensus state key - if strings.Contains(string(key), "/") { + if bytes.Contains(key, []byte("/")) { return false, nil } @@ -196,3 +197,46 @@ func (q Keeper) ClientParams(c context.Context, _ *types.QueryClientParamsReques Params: ¶ms, }, nil } + +// UpgradedClientState implements the Query/UpgradedClientState gRPC method +func (q Keeper) UpgradedClientState(c context.Context, req *types.QueryUpgradedClientStateRequest) (*types.QueryUpgradedClientStateResponse, error) { + if req == nil { + return nil, status.Error(codes.InvalidArgument, "empty request") + } + + if err := host.ClientIdentifierValidator(req.ClientId); err != nil { + return nil, status.Error(codes.InvalidArgument, err.Error()) + } + + ctx := sdk.UnwrapSDKContext(c) + plan, found := q.GetUpgradePlan(ctx) + if !found { + return nil, status.Error( + codes.NotFound, "upgrade plan not found", + ) + } + + bz, found := q.GetUpgradedClient(ctx, plan.Height) + if !found { + return nil, status.Error( + codes.NotFound, + sdkerrors.Wrap(types.ErrClientNotFound, req.ClientId).Error(), + ) + } + + clientState, err := types.UnmarshalClientState(q.cdc, bz) + if err != nil { + return nil, status.Error( + codes.Internal, err.Error(), + ) + } + + any, err := types.PackClientState(clientState) + if err != nil { + return nil, status.Error(codes.Internal, err.Error()) + } + + return &types.QueryUpgradedClientStateResponse{ + UpgradedClientState: any, + }, nil +} diff --git a/x/ibc/core/02-client/keeper/keeper.go b/x/ibc/core/02-client/keeper/keeper.go index cb73a2023d..742d4e85a6 100644 --- a/x/ibc/core/02-client/keeper/keeper.go +++ b/x/ibc/core/02-client/keeper/keeper.go @@ -25,13 +25,14 @@ import ( // state information type Keeper struct { storeKey sdk.StoreKey - cdc codec.BinaryMarshaler - paramSpace *paramtypes.Subspace + cdc codec.Codec + paramSpace paramtypes.Subspace stakingKeeper types.StakingKeeper + upgradeKeeper types.UpgradeKeeper } // NewKeeper creates a new NewKeeper instance -func NewKeeper(cdc codec.BinaryMarshaler, key sdk.StoreKey, paramSpace *paramtypes.Subspace, sk types.StakingKeeper) Keeper { +func NewKeeper(cdc codec.Codec, key sdk.StoreKey, paramSpace paramtypes.Subspace, sk types.StakingKeeper, uk types.UpgradeKeeper) Keeper { // set KeyTable if it has not already been set if !paramSpace.HasKeyTable() { paramSpace = paramSpace.WithKeyTable(types.ParamKeyTable()) @@ -42,6 +43,7 @@ func NewKeeper(cdc codec.BinaryMarshaler, key sdk.StoreKey, paramSpace *paramtyp cdc: cdc, paramSpace: paramSpace, stakingKeeper: sk, + upgradeKeeper: uk, } } @@ -327,6 +329,21 @@ func (k Keeper) ValidateSelfClient(ctx sdk.Context, clientState exported.ClientS return nil } +// GetUpgradePlan executes the upgrade keeper GetUpgradePlan function. +func (k Keeper) GetUpgradePlan(ctx sdk.Context) (plan upgradetypes.Plan, havePlan bool) { + return k.upgradeKeeper.GetUpgradePlan(ctx) +} + +// GetUpgradedClient executes the upgrade keeper GetUpgradeClient function. +func (k Keeper) GetUpgradedClient(ctx sdk.Context, planHeight int64) ([]byte, bool) { + return k.upgradeKeeper.GetUpgradedClient(ctx, planHeight) +} + +// SetUpgradedConsensusState executes the upgrade keeper SetUpgradedConsensusState function. +func (k Keeper) SetUpgradedConsensusState(ctx sdk.Context, planHeight int64, bz []byte) error { + return k.upgradeKeeper.SetUpgradedConsensusState(ctx, planHeight, bz) +} + // IterateClients provides an iterator over all stored light client State // objects. For each State object, cb will be called. If the cb returns true, // the iterator will close and stop. diff --git a/x/ibc/core/02-client/keeper/keeper_test.go b/x/ibc/core/02-client/keeper/keeper_test.go index f5a2535ac2..55e8d2a9c5 100644 --- a/x/ibc/core/02-client/keeper/keeper_test.go +++ b/x/ibc/core/02-client/keeper/keeper_test.go @@ -55,7 +55,7 @@ type KeeperTestSuite struct { chainA *ibctesting.TestChain chainB *ibctesting.TestChain - cdc codec.Marshaler + cdc codec.Codec ctx sdk.Context keeper *keeper.Keeper consensusState *ibctmtypes.ConsensusState @@ -112,7 +112,7 @@ func (suite *KeeperTestSuite) SetupTest() { val.Tokens = sdk.NewInt(rand.Int63()) validators = append(validators, val) - hi := stakingtypes.NewHistoricalInfo(suite.ctx.BlockHeader(), validators) + hi := stakingtypes.NewHistoricalInfo(suite.ctx.BlockHeader(), validators, app.StakingKeeper.PowerReduction(suite.ctx)) app.StakingKeeper.SetHistoricalInfo(suite.ctx, int64(i), &hi) } diff --git a/x/ibc/core/02-client/keeper/proposal.go b/x/ibc/core/02-client/keeper/proposal.go index 2d94ff3f55..54349d843b 100644 --- a/x/ibc/core/02-client/keeper/proposal.go +++ b/x/ibc/core/02-client/keeper/proposal.go @@ -10,41 +10,50 @@ import ( "github.com/line/lbm-sdk/x/ibc/core/exported" ) -// ClientUpdateProposal will try to update the client with the new header if and only if -// the proposal passes. The localhost client is not allowed to be modified with a proposal. +// ClientUpdateProposal will retrieve the subject and substitute client. +// The initial height must be greater than the latest height of the subject +// client. A callback will occur to the subject client state with the client +// prefixed store being provided for both the subject and the substitute client. +// The localhost client is not allowed to be modified with a proposal. The IBC +// client implementations are responsible for validating the parameters of the +// subtitute (enusring they match the subject's parameters) as well as copying +// the necessary consensus states from the subtitute to the subject client +// store. func (k Keeper) ClientUpdateProposal(ctx sdk.Context, p *types.ClientUpdateProposal) error { - if p.ClientId == exported.Localhost { + if p.SubjectClientId == exported.Localhost || p.SubstituteClientId == exported.Localhost { return sdkerrors.Wrap(types.ErrInvalidUpdateClientProposal, "cannot update localhost client with proposal") } - clientState, found := k.GetClientState(ctx, p.ClientId) + subjectClientState, found := k.GetClientState(ctx, p.SubjectClientId) if !found { - return sdkerrors.Wrapf(types.ErrClientNotFound, "cannot update client with ID %s", p.ClientId) + return sdkerrors.Wrapf(types.ErrClientNotFound, "subject client with ID %s", p.SubjectClientId) } - header, err := types.UnpackHeader(p.Header) - if err != nil { - return err + if subjectClientState.GetLatestHeight().GTE(p.InitialHeight) { + return sdkerrors.Wrapf(types.ErrInvalidHeight, "subject client state latest height is greater or equal to initial height (%s >= %s)", subjectClientState.GetLatestHeight(), p.InitialHeight) + } + + substituteClientState, found := k.GetClientState(ctx, p.SubstituteClientId) + if !found { + return sdkerrors.Wrapf(types.ErrClientNotFound, "substitute client with ID %s", p.SubstituteClientId) } - clientState, consensusState, err := clientState.CheckProposedHeaderAndUpdateState(ctx, k.cdc, k.ClientStore(ctx, p.ClientId), header) + clientState, err := subjectClientState.CheckSubstituteAndUpdateState(ctx, k.cdc, k.ClientStore(ctx, p.SubjectClientId), k.ClientStore(ctx, p.SubstituteClientId), substituteClientState, p.InitialHeight) if err != nil { return err } + k.SetClientState(ctx, p.SubjectClientId, clientState) - k.SetClientState(ctx, p.ClientId, clientState) - k.SetClientConsensusState(ctx, p.ClientId, header.GetHeight(), consensusState) - - k.Logger(ctx).Info("client updated after governance proposal passed", "client-id", p.ClientId, "height", clientState.GetLatestHeight().String()) + k.Logger(ctx).Info("client updated after governance proposal passed", "client-id", p.SubjectClientId, "height", clientState.GetLatestHeight().String()) defer func() { telemetry.IncrCounterWithLabels( []string{"ibc", "client", "update"}, 1, []metrics.Label{ - telemetry.NewLabel(types.LabelClientType, clientState.ClientType()), - telemetry.NewLabel(types.LabelClientID, p.ClientId), - telemetry.NewLabel(types.LabelUpdateType, "proposal"), + telemetry.NewLabel("client-type", clientState.ClientType()), + telemetry.NewLabel("client-id", p.SubjectClientId), + telemetry.NewLabel("update-type", "proposal"), }, ) }() @@ -53,11 +62,37 @@ func (k Keeper) ClientUpdateProposal(ctx sdk.Context, p *types.ClientUpdatePropo ctx.EventManager().EmitEvent( sdk.NewEvent( types.EventTypeUpdateClientProposal, - sdk.NewAttribute(types.AttributeKeyClientID, p.ClientId), + sdk.NewAttribute(types.AttributeKeySubjectClientID, p.SubjectClientId), sdk.NewAttribute(types.AttributeKeyClientType, clientState.ClientType()), - sdk.NewAttribute(types.AttributeKeyConsensusHeight, header.GetHeight().String()), + sdk.NewAttribute(types.AttributeKeyConsensusHeight, clientState.GetLatestHeight().String()), ), ) return nil } + +// HandleUpgradeProposal sets the upgraded client state in the upgrade store. It clears +// an IBC client state and consensus state if a previous plan was set. Then it +// will schedule an upgrade and finally set the upgraded client state in upgrade +// store. +func (k Keeper) HandleUpgradeProposal(ctx sdk.Context, p *types.UpgradeProposal) error { + clientState, err := types.UnpackClientState(p.UpgradedClientState) + if err != nil { + return sdkerrors.Wrap(err, "could not unpack UpgradedClientState") + } + + // zero out any custom fields before setting + cs := clientState.ZeroCustomFields() + bz, err := types.MarshalClientState(k.cdc, cs) + if err != nil { + return sdkerrors.Wrap(err, "could not marshal UpgradedClientState") + } + + if err := k.upgradeKeeper.ScheduleUpgrade(ctx, p.Plan); err != nil { + return err + } + + // sets the new upgraded client in last height committed on this chain is at plan.Height, + // since the chain will panic at plan.Height and new chain will resume at plan.Height + return k.upgradeKeeper.SetUpgradedClient(ctx, p.Plan.Height, bz) +} diff --git a/x/ibc/core/02-client/keeper/proposal_test.go b/x/ibc/core/02-client/keeper/proposal_test.go index c72b91cea4..6a70eae8b9 100644 --- a/x/ibc/core/02-client/keeper/proposal_test.go +++ b/x/ibc/core/02-client/keeper/proposal_test.go @@ -1,17 +1,22 @@ package keeper_test import ( + govtypes "github.com/line/lbm-sdk/x/gov/types" "github.com/line/lbm-sdk/x/ibc/core/02-client/types" clienttypes "github.com/line/lbm-sdk/x/ibc/core/02-client/types" "github.com/line/lbm-sdk/x/ibc/core/exported" - ibctmtypes "github.com/line/lbm-sdk/x/ibc/light-clients/99-ostracon/types" + ibcoctypes "github.com/line/lbm-sdk/x/ibc/light-clients/99-ostracon/types" ibctesting "github.com/line/lbm-sdk/x/ibc/testing" + upgradetypes "github.com/line/lbm-sdk/x/upgrade/types" ) func (suite *KeeperTestSuite) TestClientUpdateProposal() { var ( - content *types.ClientUpdateProposal - err error + subject, substitute string + subjectClientState, substituteClientState exported.ClientState + initialHeight types.Height + content govtypes.Content + err error ) testCases := []struct { @@ -21,53 +26,63 @@ func (suite *KeeperTestSuite) TestClientUpdateProposal() { }{ { "valid update client proposal", func() { - clientA, _ := suite.coordinator.SetupClients(suite.chainA, suite.chainB, exported.Ostracon) - clientState := suite.chainA.GetClientState(clientA) - - tmClientState, ok := clientState.(*ibctmtypes.ClientState) + content = types.NewClientUpdateProposal(ibctesting.Title, ibctesting.Description, subject, substitute, initialHeight) + }, true, + }, + { + "subject and substitute use different revision numbers", func() { + tmClientState, ok := substituteClientState.(*ibcoctypes.ClientState) suite.Require().True(ok) - tmClientState.AllowUpdateAfterMisbehaviour = true - tmClientState.FrozenHeight = tmClientState.LatestHeight - suite.chainA.App.IBCKeeper.ClientKeeper.SetClientState(suite.chainA.GetContext(), clientA, tmClientState) + consState, found := suite.chainA.App.IBCKeeper.ClientKeeper.GetClientConsensusState(suite.chainA.GetContext(), substitute, tmClientState.LatestHeight) + suite.Require().True(found) + newRevisionNumber := tmClientState.GetLatestHeight().GetRevisionNumber() + 1 - // use next header for chainB to update the client on chainA - header, err := suite.chainA.ConstructUpdateOCClientHeader(suite.chainB, clientA) - suite.Require().NoError(err) + tmClientState.LatestHeight = types.NewHeight(newRevisionNumber, tmClientState.GetLatestHeight().GetRevisionHeight()) + initialHeight = types.NewHeight(newRevisionNumber, initialHeight.GetRevisionHeight()) + suite.chainA.App.IBCKeeper.ClientKeeper.SetClientConsensusState(suite.chainA.GetContext(), substitute, tmClientState.LatestHeight, consState) + suite.chainA.App.IBCKeeper.ClientKeeper.SetClientState(suite.chainA.GetContext(), substitute, tmClientState) - content, err = clienttypes.NewClientUpdateProposal(ibctesting.Title, ibctesting.Description, clientA, header) - suite.Require().NoError(err) + content = types.NewClientUpdateProposal(ibctesting.Title, ibctesting.Description, subject, substitute, initialHeight) }, true, }, { - "client type does not exist", func() { - content, err = clienttypes.NewClientUpdateProposal(ibctesting.Title, ibctesting.Description, ibctesting.InvalidID, &ibctmtypes.Header{}) - suite.Require().NoError(err) + "cannot use localhost as subject", func() { + content = types.NewClientUpdateProposal(ibctesting.Title, ibctesting.Description, exported.Localhost, substitute, initialHeight) }, false, }, { - "cannot update localhost", func() { - content, err = clienttypes.NewClientUpdateProposal(ibctesting.Title, ibctesting.Description, exported.Localhost, &ibctmtypes.Header{}) - suite.Require().NoError(err) + "cannot use localhost as substitute", func() { + content = types.NewClientUpdateProposal(ibctesting.Title, ibctesting.Description, subject, exported.Localhost, initialHeight) }, false, }, { - "client does not exist", func() { - content, err = clienttypes.NewClientUpdateProposal(ibctesting.Title, ibctesting.Description, ibctesting.InvalidID, &ibctmtypes.Header{}) - suite.Require().NoError(err) + "subject client does not exist", func() { + content = types.NewClientUpdateProposal(ibctesting.Title, ibctesting.Description, ibctesting.InvalidID, substitute, initialHeight) }, false, }, { - "cannot unpack header, header is nil", func() { - clientA, _ := suite.coordinator.SetupClients(suite.chainA, suite.chainB, exported.Ostracon) - content = &clienttypes.ClientUpdateProposal{ibctesting.Title, ibctesting.Description, clientA, nil} + "substitute client does not exist", func() { + content = types.NewClientUpdateProposal(ibctesting.Title, ibctesting.Description, subject, ibctesting.InvalidID, initialHeight) }, false, }, { - "update fails", func() { - header := &ibctmtypes.Header{} - clientA, _ := suite.coordinator.SetupClients(suite.chainA, suite.chainB, exported.Ostracon) - content, err = clienttypes.NewClientUpdateProposal(ibctesting.Title, ibctesting.Description, clientA, header) - suite.Require().NoError(err) + "subject and substitute have equal latest height", func() { + tmClientState, ok := subjectClientState.(*ibcoctypes.ClientState) + suite.Require().True(ok) + tmClientState.LatestHeight = substituteClientState.GetLatestHeight().(types.Height) + suite.chainA.App.IBCKeeper.ClientKeeper.SetClientState(suite.chainA.GetContext(), subject, tmClientState) + + content = types.NewClientUpdateProposal(ibctesting.Title, ibctesting.Description, subject, substitute, initialHeight) + }, false, + }, + { + "update fails, client is not frozen or expired", func() { + tmClientState, ok := subjectClientState.(*ibcoctypes.ClientState) + suite.Require().True(ok) + tmClientState.FrozenHeight = types.ZeroHeight() + suite.chainA.App.IBCKeeper.ClientKeeper.SetClientState(suite.chainA.GetContext(), subject, tmClientState) + + content = types.NewClientUpdateProposal(ibctesting.Title, ibctesting.Description, subject, substitute, initialHeight) }, false, }, } @@ -78,14 +93,172 @@ func (suite *KeeperTestSuite) TestClientUpdateProposal() { suite.Run(tc.name, func() { suite.SetupTest() // reset + subject, _ = suite.coordinator.SetupClients(suite.chainA, suite.chainB, exported.Ostracon) + subjectClientState = suite.chainA.GetClientState(subject) + substitute, _ = suite.coordinator.SetupClients(suite.chainA, suite.chainB, exported.Ostracon) + initialHeight = clienttypes.NewHeight(subjectClientState.GetLatestHeight().GetRevisionNumber(), subjectClientState.GetLatestHeight().GetRevisionHeight()+1) + + // update substitute twice + suite.coordinator.UpdateClient(suite.chainA, suite.chainB, substitute, exported.Ostracon) + suite.coordinator.UpdateClient(suite.chainA, suite.chainB, substitute, exported.Ostracon) + substituteClientState = suite.chainA.GetClientState(substitute) + + tmClientState, ok := subjectClientState.(*ibcoctypes.ClientState) + suite.Require().True(ok) + tmClientState.AllowUpdateAfterMisbehaviour = true + tmClientState.AllowUpdateAfterExpiry = true + tmClientState.FrozenHeight = tmClientState.LatestHeight + suite.chainA.App.IBCKeeper.ClientKeeper.SetClientState(suite.chainA.GetContext(), subject, tmClientState) + + tmClientState, ok = substituteClientState.(*ibcoctypes.ClientState) + suite.Require().True(ok) + tmClientState.AllowUpdateAfterMisbehaviour = true + tmClientState.AllowUpdateAfterExpiry = true + tmClientState.FrozenHeight = tmClientState.LatestHeight + suite.chainA.App.IBCKeeper.ClientKeeper.SetClientState(suite.chainA.GetContext(), substitute, tmClientState) + + tc.malleate() + + updateProp, ok := content.(*types.ClientUpdateProposal) + suite.Require().True(ok) + err = suite.chainA.App.IBCKeeper.ClientKeeper.ClientUpdateProposal(suite.chainA.GetContext(), updateProp) + + if tc.expPass { + suite.Require().NoError(err) + } else { + suite.Require().Error(err) + } + }) + } + +} + +func (suite *KeeperTestSuite) TestHandleUpgradeProposal() { + var ( + upgradedClientState *ibcoctypes.ClientState + oldPlan, plan upgradetypes.Plan + content govtypes.Content + err error + ) + + testCases := []struct { + name string + malleate func() + expPass bool + }{ + { + "valid upgrade proposal", func() { + content, err = types.NewUpgradeProposal(ibctesting.Title, ibctesting.Description, plan, upgradedClientState) + suite.Require().NoError(err) + }, true, + }, + { + "valid upgrade proposal with previous IBC state", func() { + oldPlan = upgradetypes.Plan{ + Name: "upgrade IBC clients", + Height: 100, + } + + content, err = types.NewUpgradeProposal(ibctesting.Title, ibctesting.Description, plan, upgradedClientState) + suite.Require().NoError(err) + }, true, + }, + { + "cannot unpack client state", func() { + any, err := types.PackConsensusState(&ibcoctypes.ConsensusState{}) + suite.Require().NoError(err) + content = &types.UpgradeProposal{ + Title: ibctesting.Title, + Description: ibctesting.Description, + Plan: plan, + UpgradedClientState: any, + } + }, false, + }, + { + "schedule upgrade fails - plan sets time and height", func() { + plan = upgradetypes.Plan{ + Name: "invalid plan", + Height: 1000, + Time: suite.chainA.GetContext().BlockTime(), + } + content, err = types.NewUpgradeProposal(ibctesting.Title, ibctesting.Description, plan, upgradedClientState) + suite.Require().NoError(err) + }, false, + }, + } + + for _, tc := range testCases { + tc := tc + + suite.Run(tc.name, func() { + suite.SetupTest() // reset + oldPlan.Height = 0 //reset + + clientID, _ := suite.coordinator.SetupClients(suite.chainA, suite.chainB, exported.Ostracon) + upgradedClientState = suite.chainA.GetClientState(clientID).ZeroCustomFields().(*ibcoctypes.ClientState) + + // use height 1000 to distinguish from old plan + plan = upgradetypes.Plan{ + Name: "upgrade IBC clients", + Height: 1000, + } + tc.malleate() - err = suite.chainA.App.IBCKeeper.ClientKeeper.ClientUpdateProposal(suite.chainA.GetContext(), content) + // set the old plan if it is not empty + if oldPlan.Height != 0 { + // set upgrade plan in the upgrade store + store := suite.chainA.GetContext().KVStore(suite.chainA.App.GetKey(upgradetypes.StoreKey)) + bz := suite.chainA.App.AppCodec().MustMarshal(&oldPlan) + store.Set(upgradetypes.PlanKey(), bz) + + bz, err := types.MarshalClientState(suite.chainA.App.AppCodec(), upgradedClientState) + suite.Require().NoError(err) + suite.chainA.App.UpgradeKeeper.SetUpgradedClient(suite.chainA.GetContext(), oldPlan.Height, bz) + } + + upgradeProp, ok := content.(*types.UpgradeProposal) + suite.Require().True(ok) + err = suite.chainA.App.IBCKeeper.ClientKeeper.HandleUpgradeProposal(suite.chainA.GetContext(), upgradeProp) if tc.expPass { suite.Require().NoError(err) + + // check that the correct plan is returned + storedPlan, found := suite.chainA.App.UpgradeKeeper.GetUpgradePlan(suite.chainA.GetContext()) + suite.Require().True(found) + suite.Require().Equal(plan, storedPlan) + + // check that old upgraded client state is cleared + _, found = suite.chainA.App.UpgradeKeeper.GetUpgradedClient(suite.chainA.GetContext(), oldPlan.Height) + suite.Require().False(found) + + // check that client state was set + storedClientState, found := suite.chainA.App.UpgradeKeeper.GetUpgradedClient(suite.chainA.GetContext(), plan.Height) + suite.Require().True(found) + clientState, err := types.UnmarshalClientState(suite.chainA.App.AppCodec(), storedClientState) + suite.Require().NoError(err) + suite.Require().Equal(upgradedClientState, clientState) } else { suite.Require().Error(err) + + // check that the new plan wasn't stored + storedPlan, found := suite.chainA.App.UpgradeKeeper.GetUpgradePlan(suite.chainA.GetContext()) + if oldPlan.Height != 0 { + // NOTE: this is only true if the ScheduleUpgrade function + // returns an error before clearing the old plan + suite.Require().True(found) + suite.Require().Equal(oldPlan, storedPlan) + } else { + suite.Require().False(found) + suite.Require().Empty(storedPlan) + } + + // check that client state was not set + _, found = suite.chainA.App.UpgradeKeeper.GetUpgradedClient(suite.chainA.GetContext(), plan.Height) + suite.Require().False(found) + } }) } diff --git a/x/ibc/core/02-client/module.go b/x/ibc/core/02-client/module.go index add6ae5528..9523a59a39 100644 --- a/x/ibc/core/02-client/module.go +++ b/x/ibc/core/02-client/module.go @@ -18,6 +18,11 @@ func GetQueryCmd() *cobra.Command { return cli.GetQueryCmd() } +// GetTxCmd returns the root tx command for 02-client. +func GetTxCmd() *cobra.Command { + return cli.NewTxCmd() +} + // RegisterQueryService registers the gRPC query service for IBC client. func RegisterQueryService(server grpc.Server, queryServer types.QueryServer) { types.RegisterQueryServer(server, queryServer) diff --git a/x/ibc/core/02-client/proposal_handler.go b/x/ibc/core/02-client/proposal_handler.go index ffac93fb4b..f1cbb1e504 100644 --- a/x/ibc/core/02-client/proposal_handler.go +++ b/x/ibc/core/02-client/proposal_handler.go @@ -8,12 +8,14 @@ import ( "github.com/line/lbm-sdk/x/ibc/core/02-client/types" ) -// NewClientUpdateProposalHandler defines the client update proposal handler -func NewClientUpdateProposalHandler(k keeper.Keeper) govtypes.Handler { +// NewClientProposalHandler defines the 02-client proposal handler +func NewClientProposalHandler(k keeper.Keeper) govtypes.Handler { return func(ctx sdk.Context, content govtypes.Content) error { switch c := content.(type) { case *types.ClientUpdateProposal: return k.ClientUpdateProposal(ctx, c) + case *types.UpgradeProposal: + return k.HandleUpgradeProposal(ctx, c) default: return sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unrecognized ibc proposal content type: %T", c) diff --git a/x/ibc/core/02-client/proposal_handler_test.go b/x/ibc/core/02-client/proposal_handler_test.go index 2cccefac4c..8cb12b7f9f 100644 --- a/x/ibc/core/02-client/proposal_handler_test.go +++ b/x/ibc/core/02-client/proposal_handler_test.go @@ -24,21 +24,29 @@ func (suite *ClientTestSuite) TestNewClientUpdateProposalHandler() { }{ { "valid update client proposal", func() { - clientA, _ := suite.coordinator.SetupClients(suite.chainA, suite.chainB, exported.Ostracon) - clientState := suite.chainA.GetClientState(clientA) + subject, _ := suite.coordinator.SetupClients(suite.chainA, suite.chainB, exported.Ostracon) + subjectClientState := suite.chainA.GetClientState(subject) + substitute, _ := suite.coordinator.SetupClients(suite.chainA, suite.chainB, exported.Ostracon) + initialHeight := clienttypes.NewHeight(subjectClientState.GetLatestHeight().GetRevisionNumber(), subjectClientState.GetLatestHeight().GetRevisionHeight()+1) - tmClientState, ok := clientState.(*ibctmtypes.ClientState) + // update substitute twice + suite.coordinator.UpdateClient(suite.chainA, suite.chainB, substitute, exported.Ostracon) + suite.coordinator.UpdateClient(suite.chainA, suite.chainB, substitute, exported.Ostracon) + substituteClientState := suite.chainA.GetClientState(substitute) + + tmClientState, ok := subjectClientState.(*ibctmtypes.ClientState) suite.Require().True(ok) tmClientState.AllowUpdateAfterMisbehaviour = true tmClientState.FrozenHeight = tmClientState.LatestHeight - suite.chainA.App.IBCKeeper.ClientKeeper.SetClientState(suite.chainA.GetContext(), clientA, tmClientState) + suite.chainA.App.IBCKeeper.ClientKeeper.SetClientState(suite.chainA.GetContext(), subject, tmClientState) - // use next header for chainB to update the client on chainA - header, err := suite.chainA.ConstructUpdateOCClientHeader(suite.chainB, clientA) - suite.Require().NoError(err) + // replicate changes to substitute (they must match) + tmClientState, ok = substituteClientState.(*ibctmtypes.ClientState) + suite.Require().True(ok) + tmClientState.AllowUpdateAfterMisbehaviour = true + suite.chainA.App.IBCKeeper.ClientKeeper.SetClientState(suite.chainA.GetContext(), substitute, tmClientState) - content, err = clienttypes.NewClientUpdateProposal(ibctesting.Title, ibctesting.Description, clientA, header) - suite.Require().NoError(err) + content = clienttypes.NewClientUpdateProposal(ibctesting.Title, ibctesting.Description, subject, substitute, initialHeight) }, true, }, { @@ -61,7 +69,7 @@ func (suite *ClientTestSuite) TestNewClientUpdateProposalHandler() { tc.malleate() - proposalHandler := client.NewClientUpdateProposalHandler(suite.chainA.App.IBCKeeper.ClientKeeper) + proposalHandler := client.NewClientProposalHandler(suite.chainA.App.IBCKeeper.ClientKeeper) err = proposalHandler(suite.chainA.GetContext(), content) diff --git a/x/ibc/core/02-client/types/client.pb.go b/x/ibc/core/02-client/types/client.pb.go index 4ef960f701..f4dddd00e6 100644 --- a/x/ibc/core/02-client/types/client.pb.go +++ b/x/ibc/core/02-client/types/client.pb.go @@ -8,6 +8,7 @@ import ( _ "github.com/gogo/protobuf/gogoproto" proto "github.com/gogo/protobuf/proto" types "github.com/line/lbm-sdk/codec/types" + types1 "github.com/line/lbm-sdk/x/upgrade/types" io "io" math "math" math_bits "math/bits" @@ -191,18 +192,22 @@ func (m *ClientConsensusStates) GetConsensusStates() []ConsensusStateWithHeight return nil } -// ClientUpdateProposal is a governance proposal. If it passes, the client is -// updated with the provided header. The update may fail if the header is not -// valid given certain conditions specified by the client implementation. +// ClientUpdateProposal is a governance proposal. If it passes, the substitute client's +// consensus states starting from the 'initial height' are copied over to the subjects +// client state. The proposal handler may fail if the subject and the substitute do not +// match in client and chain parameters (with exception to latest height, frozen height, and chain-id). +// The updated client must also be valid (cannot be expired). type ClientUpdateProposal struct { // the title of the update proposal Title string `protobuf:"bytes,1,opt,name=title,proto3" json:"title,omitempty"` // the description of the proposal Description string `protobuf:"bytes,2,opt,name=description,proto3" json:"description,omitempty"` // the client identifier for the client to be updated if the proposal passes - ClientId string `protobuf:"bytes,3,opt,name=client_id,json=clientId,proto3" json:"client_id,omitempty" yaml:"client_id"` - // the header used to update the client if the proposal passes - Header *types.Any `protobuf:"bytes,4,opt,name=header,proto3" json:"header,omitempty"` + SubjectClientId string `protobuf:"bytes,3,opt,name=subject_client_id,json=subjectClientId,proto3" json:"subject_client_id,omitempty" yaml:"subject_client_id"` + // the substitute client identifier for the client standing in for the subject client + SubstituteClientId string `protobuf:"bytes,4,opt,name=substitute_client_id,json=substituteClientId,proto3" json:"substitute_client_id,omitempty" yaml:"susbtitute_client_id"` + // the intital height to copy consensus states from the substitute to the subject + InitialHeight Height `protobuf:"bytes,5,opt,name=initial_height,json=initialHeight,proto3" json:"initial_height" yaml:"initial_height"` } func (m *ClientUpdateProposal) Reset() { *m = ClientUpdateProposal{} } @@ -238,6 +243,52 @@ func (m *ClientUpdateProposal) XXX_DiscardUnknown() { var xxx_messageInfo_ClientUpdateProposal proto.InternalMessageInfo +// UpgradeProposal is a gov Content type for initiating an IBC breaking +// upgrade. +type UpgradeProposal struct { + Title string `protobuf:"bytes,1,opt,name=title,proto3" json:"title,omitempty"` + Description string `protobuf:"bytes,2,opt,name=description,proto3" json:"description,omitempty"` + Plan types1.Plan `protobuf:"bytes,3,opt,name=plan,proto3" json:"plan"` + // An UpgradedClientState must be provided to perform an IBC breaking upgrade. + // This will make the chain commit to the correct upgraded (self) client state before the upgrade occurs, + // so that connecting chains can verify that the new upgraded client is valid by verifying a proof on the + // previous version of the chain. + // This will allow IBC connections to persist smoothly across planned chain upgrades + UpgradedClientState *types.Any `protobuf:"bytes,4,opt,name=upgraded_client_state,json=upgradedClientState,proto3" json:"upgraded_client_state,omitempty" yaml:"upgraded_client_state"` +} + +func (m *UpgradeProposal) Reset() { *m = UpgradeProposal{} } +func (*UpgradeProposal) ProtoMessage() {} +func (*UpgradeProposal) Descriptor() ([]byte, []int) { + return fileDescriptor_b6bc4c8185546947, []int{4} +} +func (m *UpgradeProposal) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *UpgradeProposal) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_UpgradeProposal.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *UpgradeProposal) XXX_Merge(src proto.Message) { + xxx_messageInfo_UpgradeProposal.Merge(m, src) +} +func (m *UpgradeProposal) XXX_Size() int { + return m.Size() +} +func (m *UpgradeProposal) XXX_DiscardUnknown() { + xxx_messageInfo_UpgradeProposal.DiscardUnknown(m) +} + +var xxx_messageInfo_UpgradeProposal proto.InternalMessageInfo + // Height is a monotonically increasing data type // that can be compared against another Height for the purposes of updating and // freezing clients @@ -257,7 +308,7 @@ type Height struct { func (m *Height) Reset() { *m = Height{} } func (*Height) ProtoMessage() {} func (*Height) Descriptor() ([]byte, []int) { - return fileDescriptor_b6bc4c8185546947, []int{4} + return fileDescriptor_b6bc4c8185546947, []int{5} } func (m *Height) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -296,7 +347,7 @@ func (m *Params) Reset() { *m = Params{} } func (m *Params) String() string { return proto.CompactTextString(m) } func (*Params) ProtoMessage() {} func (*Params) Descriptor() ([]byte, []int) { - return fileDescriptor_b6bc4c8185546947, []int{5} + return fileDescriptor_b6bc4c8185546947, []int{6} } func (m *Params) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -337,6 +388,7 @@ func init() { proto.RegisterType((*ConsensusStateWithHeight)(nil), "ibc.core.client.v1.ConsensusStateWithHeight") proto.RegisterType((*ClientConsensusStates)(nil), "ibc.core.client.v1.ClientConsensusStates") proto.RegisterType((*ClientUpdateProposal)(nil), "ibc.core.client.v1.ClientUpdateProposal") + proto.RegisterType((*UpgradeProposal)(nil), "ibc.core.client.v1.UpgradeProposal") proto.RegisterType((*Height)(nil), "ibc.core.client.v1.Height") proto.RegisterType((*Params)(nil), "ibc.core.client.v1.Params") } @@ -344,45 +396,88 @@ func init() { func init() { proto.RegisterFile("ibc/core/client/v1/client.proto", fileDescriptor_b6bc4c8185546947) } var fileDescriptor_b6bc4c8185546947 = []byte{ - // 572 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x54, 0xbf, 0x8e, 0x12, 0x41, - 0x1c, 0x66, 0x00, 0xc9, 0x31, 0x18, 0xb8, 0xac, 0xe0, 0xed, 0x51, 0xec, 0x92, 0xa9, 0x28, 0xee, - 0x76, 0x05, 0x1b, 0x43, 0xe7, 0xd2, 0x78, 0x89, 0x1a, 0xb2, 0xc6, 0x68, 0x6c, 0xc8, 0xfe, 0x99, - 0x5b, 0x26, 0x2e, 0x3b, 0x64, 0x67, 0xc0, 0xe3, 0x0d, 0x2c, 0x2d, 0x2d, 0x2c, 0x7c, 0x02, 0x3b, - 0xdf, 0xc0, 0xe2, 0xca, 0x2b, 0xad, 0x36, 0x06, 0xde, 0x80, 0x27, 0x30, 0x3b, 0xb3, 0x9c, 0x2c, - 0x4a, 0x72, 0xb1, 0xfb, 0xcd, 0x37, 0xdf, 0x7c, 0xbf, 0xef, 0xfb, 0xcd, 0x64, 0xa0, 0x4e, 0x5c, - 0xcf, 0xf4, 0x68, 0x8c, 0x4d, 0x2f, 0x24, 0x38, 0xe2, 0xe6, 0xa2, 0x97, 0x55, 0xc6, 0x2c, 0xa6, - 0x9c, 0x2a, 0x0a, 0x71, 0x3d, 0x23, 0x25, 0x18, 0x19, 0xbc, 0xe8, 0xb5, 0x9b, 0x01, 0x0d, 0xa8, - 0xd8, 0x36, 0xd3, 0x4a, 0x32, 0xdb, 0xa7, 0x01, 0xa5, 0x41, 0x88, 0x4d, 0xb1, 0x72, 0xe7, 0x97, - 0xa6, 0x13, 0x2d, 0xe5, 0x16, 0xfa, 0x02, 0x60, 0xeb, 0xc2, 0xc7, 0x11, 0x27, 0x97, 0x04, 0xfb, - 0x43, 0x21, 0xf4, 0x8a, 0x3b, 0x1c, 0x2b, 0x3d, 0x58, 0x95, 0xba, 0x63, 0xe2, 0xab, 0xa0, 0x03, - 0xba, 0x55, 0xab, 0xb9, 0x49, 0xf4, 0xe3, 0xa5, 0x33, 0x0d, 0x07, 0xe8, 0x76, 0x0b, 0xd9, 0x47, - 0xb2, 0xbe, 0xf0, 0x95, 0x11, 0xbc, 0x9f, 0xe1, 0x2c, 0x95, 0x50, 0x8b, 0x1d, 0xd0, 0xad, 0xf5, - 0x9b, 0x86, 0x6c, 0x6f, 0x6c, 0xdb, 0x1b, 0x4f, 0xa3, 0xa5, 0x75, 0xb2, 0x49, 0xf4, 0x07, 0x39, - 0x2d, 0x71, 0x06, 0xd9, 0x35, 0xef, 0x8f, 0x09, 0xf4, 0x0d, 0x40, 0x75, 0x48, 0x23, 0x86, 0x23, - 0x36, 0x67, 0x02, 0x7a, 0x43, 0xf8, 0xe4, 0x19, 0x26, 0xc1, 0x84, 0x2b, 0x4f, 0x60, 0x65, 0x22, - 0x2a, 0x61, 0xaf, 0xd6, 0x6f, 0x1b, 0x7f, 0x4f, 0xc4, 0x90, 0x5c, 0xab, 0x7c, 0x9d, 0xe8, 0x05, - 0x3b, 0xe3, 0x2b, 0x6f, 0x61, 0xc3, 0xdb, 0xaa, 0xde, 0xc1, 0xeb, 0xe9, 0x26, 0xd1, 0x5b, 0xa9, - 0x57, 0xb4, 0x77, 0x0a, 0xd9, 0x75, 0x2f, 0xe7, 0x0e, 0xfd, 0x00, 0xb0, 0x25, 0xa7, 0x98, 0xb7, - 0xcd, 0xfe, 0x67, 0x9e, 0x57, 0xf0, 0x78, 0xaf, 0x21, 0x53, 0x8b, 0x9d, 0x52, 0xb7, 0xd6, 0x3f, - 0xfb, 0x57, 0xd4, 0x43, 0x83, 0xb2, 0xf4, 0x34, 0xfc, 0x26, 0xd1, 0x4f, 0xb2, 0x5e, 0x7b, 0x9a, - 0xc8, 0x6e, 0xe4, 0x53, 0x30, 0xf4, 0x1d, 0xc0, 0xa6, 0x8c, 0xf1, 0x7a, 0xe6, 0x3b, 0x1c, 0x8f, - 0x62, 0x3a, 0xa3, 0xcc, 0x09, 0x95, 0x26, 0xbc, 0xc7, 0x09, 0x0f, 0xb1, 0x4c, 0x60, 0xcb, 0x85, - 0xd2, 0x81, 0x35, 0x1f, 0x33, 0x2f, 0x26, 0x33, 0x4e, 0x68, 0x24, 0x66, 0x59, 0xb5, 0x77, 0xa1, - 0x7c, 0xfa, 0xd2, 0x9d, 0xd2, 0x9f, 0xa5, 0xd7, 0xeb, 0xf8, 0x38, 0x56, 0xcb, 0x87, 0xef, 0xc6, - 0xce, 0x38, 0x83, 0xf2, 0xc7, 0xaf, 0x7a, 0x21, 0x7d, 0xce, 0x95, 0xec, 0x75, 0x0c, 0x61, 0x23, - 0xc6, 0x0b, 0xc2, 0x08, 0x8d, 0xc6, 0xd1, 0x7c, 0xea, 0xe2, 0x58, 0x78, 0x2e, 0x5b, 0xed, 0x4d, - 0xa2, 0x3f, 0x94, 0x7d, 0xf7, 0x08, 0xc8, 0xae, 0x6f, 0x91, 0x97, 0x02, 0xc8, 0x89, 0x64, 0x6f, - 0xad, 0x78, 0x50, 0x44, 0x12, 0x76, 0x44, 0xa4, 0x93, 0xc1, 0x51, 0x6a, 0xed, 0x73, 0x6a, 0xef, - 0x05, 0xac, 0x8c, 0x9c, 0xd8, 0x99, 0xb2, 0x54, 0xd8, 0x09, 0x43, 0xfa, 0x01, 0xfb, 0x63, 0x19, - 0x98, 0xa9, 0xa0, 0x53, 0xea, 0x56, 0x77, 0x85, 0xf7, 0x08, 0xc8, 0xae, 0x67, 0x88, 0xbc, 0x19, - 0x66, 0x3d, 0xbf, 0x5e, 0x69, 0xe0, 0x66, 0xa5, 0x81, 0x5f, 0x2b, 0x0d, 0x7c, 0x5a, 0x6b, 0x85, - 0x9b, 0xb5, 0x56, 0xf8, 0xb9, 0xd6, 0x0a, 0xef, 0xfa, 0x01, 0xe1, 0x93, 0xb9, 0x6b, 0x78, 0x74, - 0x6a, 0x86, 0x24, 0xc2, 0x66, 0xe8, 0x4e, 0xcf, 0x99, 0xff, 0xde, 0xbc, 0x32, 0x6f, 0xbf, 0x95, - 0x47, 0xfd, 0xf3, 0xec, 0x67, 0xe1, 0xcb, 0x19, 0x66, 0x6e, 0x45, 0xcc, 0xf5, 0xf1, 0xef, 0x00, - 0x00, 0x00, 0xff, 0xff, 0xbb, 0x7a, 0x79, 0x0e, 0x79, 0x04, 0x00, 0x00, + // 734 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x55, 0x3f, 0x6f, 0xdb, 0x38, + 0x1c, 0xb5, 0x1c, 0xc7, 0x88, 0xe9, 0x9c, 0x9d, 0x53, 0xec, 0x8b, 0xe3, 0xcb, 0x99, 0x06, 0x27, + 0x0f, 0x17, 0xe9, 0xec, 0x5b, 0x0e, 0xd9, 0xce, 0x5e, 0x12, 0xe0, 0xae, 0x70, 0x55, 0x04, 0x2d, + 0xba, 0xb8, 0xfa, 0xc3, 0xd8, 0x4c, 0x65, 0xc9, 0x10, 0x29, 0x37, 0xfe, 0x06, 0x1d, 0x3b, 0x76, + 0xe8, 0x90, 0x4f, 0xd0, 0x4f, 0xd1, 0x21, 0x63, 0x80, 0x2e, 0x9d, 0x84, 0x22, 0x59, 0x3a, 0xab, + 0x5f, 0xa0, 0x10, 0x49, 0x39, 0xb6, 0x93, 0xb4, 0x45, 0xbb, 0x51, 0x3f, 0x3e, 0xbe, 0xdf, 0x7b, + 0x8f, 0xa4, 0x08, 0x20, 0xb1, 0x6c, 0xdd, 0xf6, 0x03, 0xac, 0xdb, 0x2e, 0xc1, 0x1e, 0xd3, 0xa7, + 0x6d, 0x39, 0xd2, 0x26, 0x81, 0xcf, 0x7c, 0x55, 0x25, 0x96, 0xad, 0x25, 0x00, 0x4d, 0x96, 0xa7, + 0xed, 0x7a, 0x65, 0xe8, 0x0f, 0x7d, 0x3e, 0xad, 0x27, 0x23, 0x81, 0xac, 0xef, 0x0e, 0x7d, 0x7f, + 0xe8, 0x62, 0x9d, 0x7f, 0x59, 0xe1, 0x89, 0x6e, 0x7a, 0x33, 0x39, 0xb5, 0xe7, 0x5a, 0x63, 0x3d, + 0x9c, 0x0c, 0x03, 0xd3, 0xc1, 0x49, 0x07, 0x39, 0x14, 0xb3, 0xe8, 0x8d, 0x02, 0xaa, 0x47, 0x0e, + 0xf6, 0x18, 0x39, 0x21, 0xd8, 0xe9, 0xf1, 0x36, 0x8f, 0x98, 0xc9, 0xb0, 0xda, 0x06, 0x05, 0xd1, + 0x75, 0x40, 0x9c, 0x9a, 0xd2, 0x54, 0x5a, 0x85, 0x6e, 0x25, 0x8e, 0xe0, 0xd6, 0xcc, 0x1c, 0xbb, + 0x07, 0x68, 0x3e, 0x85, 0x8c, 0x0d, 0x31, 0x3e, 0x72, 0xd4, 0x3e, 0xd8, 0x94, 0x75, 0x9a, 0x50, + 0xd4, 0xb2, 0x4d, 0xa5, 0x55, 0xec, 0x54, 0x34, 0x21, 0x4e, 0x4b, 0xc5, 0x69, 0xff, 0x7a, 0xb3, + 0xee, 0x4e, 0x1c, 0xc1, 0xed, 0x25, 0x2e, 0xbe, 0x06, 0x19, 0x45, 0xfb, 0x46, 0x04, 0x7a, 0xab, + 0x80, 0x5a, 0xcf, 0xf7, 0x28, 0xf6, 0x68, 0x48, 0x79, 0xe9, 0x31, 0x61, 0xa3, 0x43, 0x4c, 0x86, + 0x23, 0xa6, 0xfe, 0x03, 0xf2, 0x23, 0x3e, 0xe2, 0xf2, 0x8a, 0x9d, 0xba, 0x76, 0x3b, 0x2f, 0x4d, + 0x60, 0xbb, 0xb9, 0x8b, 0x08, 0x66, 0x0c, 0x89, 0x57, 0x9f, 0x80, 0xb2, 0x9d, 0xb2, 0x7e, 0x87, + 0xd6, 0xdd, 0x38, 0x82, 0xd5, 0x44, 0x2b, 0x5a, 0x59, 0x85, 0x8c, 0x92, 0xbd, 0xa4, 0x0e, 0xbd, + 0x53, 0x40, 0x55, 0xa4, 0xb8, 0x2c, 0x9b, 0xfe, 0x48, 0x9e, 0x67, 0x60, 0x6b, 0xa5, 0x21, 0xad, + 0x65, 0x9b, 0x6b, 0xad, 0x62, 0xe7, 0xcf, 0xbb, 0xac, 0xde, 0x17, 0x54, 0x17, 0x26, 0xe6, 0xe3, + 0x08, 0xee, 0xc8, 0x5e, 0x2b, 0x9c, 0xc8, 0x28, 0x2f, 0xbb, 0xa0, 0xe8, 0x7d, 0x16, 0x54, 0x84, + 0x8d, 0xe3, 0x89, 0x63, 0x32, 0xdc, 0x0f, 0xfc, 0x89, 0x4f, 0x4d, 0x57, 0xad, 0x80, 0x75, 0x46, + 0x98, 0x8b, 0x85, 0x03, 0x43, 0x7c, 0xa8, 0x4d, 0x50, 0x74, 0x30, 0xb5, 0x03, 0x32, 0x61, 0xc4, + 0xf7, 0x78, 0x96, 0x05, 0x63, 0xb1, 0xa4, 0x1e, 0x82, 0x5f, 0x69, 0x68, 0x9d, 0x62, 0x9b, 0x0d, + 0x6e, 0x52, 0x58, 0xe3, 0x29, 0xec, 0xc5, 0x11, 0xac, 0x09, 0x65, 0xb7, 0x20, 0xc8, 0x28, 0xcb, + 0x5a, 0x2f, 0x0d, 0xe5, 0x21, 0xa8, 0xd0, 0xd0, 0xa2, 0x8c, 0xb0, 0x90, 0xe1, 0x05, 0xb2, 0x1c, + 0x27, 0x83, 0x71, 0x04, 0x7f, 0x4f, 0xc9, 0xa8, 0xb5, 0x8a, 0x42, 0x86, 0x7a, 0xb3, 0x78, 0x4e, + 0xf9, 0x0c, 0x94, 0x88, 0x47, 0x18, 0x31, 0xdd, 0x81, 0x3c, 0x50, 0xeb, 0xdf, 0x3c, 0x50, 0x7f, + 0xc8, 0x4c, 0xab, 0xa2, 0xd9, 0xf2, 0x7a, 0x64, 0xfc, 0x22, 0x0b, 0x02, 0x7d, 0x90, 0x7b, 0x79, + 0x0e, 0x33, 0xe8, 0xb3, 0x02, 0xca, 0xc7, 0xe2, 0xfa, 0xfd, 0x74, 0xa0, 0x1a, 0xc8, 0x4d, 0x5c, + 0xd3, 0xe3, 0x19, 0x26, 0xe7, 0xd6, 0xb5, 0xc6, 0x5a, 0x7a, 0xb5, 0xa7, 0x6d, 0xad, 0xef, 0x9a, + 0x9e, 0x3c, 0xf4, 0x1c, 0xa7, 0x9e, 0x82, 0xaa, 0x9c, 0x76, 0x06, 0x4b, 0x97, 0x34, 0xf7, 0x95, + 0x83, 0xdf, 0x8c, 0x23, 0xb8, 0x27, 0x0c, 0xde, 0xb9, 0x18, 0x19, 0xdb, 0x69, 0x7d, 0xe1, 0xd7, + 0x71, 0xb0, 0x99, 0xb8, 0x7d, 0x7d, 0x0e, 0x33, 0x9f, 0xce, 0xa1, 0x92, 0xfc, 0x62, 0xf2, 0xf2, + 0xc6, 0xf6, 0x40, 0x39, 0xc0, 0x53, 0x42, 0x89, 0xef, 0x0d, 0xbc, 0x70, 0x6c, 0xe1, 0x80, 0xdb, + 0xce, 0x75, 0xeb, 0x71, 0x04, 0x7f, 0x13, 0x8d, 0x56, 0x00, 0xc8, 0x28, 0xa5, 0x95, 0x07, 0xbc, + 0xb0, 0x44, 0x22, 0xb7, 0x2b, 0x7b, 0x2f, 0x49, 0xba, 0x1f, 0x73, 0x12, 0xb9, 0x21, 0x1b, 0xa9, + 0x44, 0xf4, 0x3f, 0xc8, 0xf7, 0xcd, 0xc0, 0x1c, 0xd3, 0x84, 0xd8, 0x74, 0x5d, 0xff, 0xc5, 0xdc, + 0x24, 0xad, 0x29, 0xcd, 0xb5, 0x56, 0x61, 0x91, 0x78, 0x05, 0x80, 0x8c, 0x92, 0xac, 0x08, 0xff, + 0xb4, 0xfb, 0xdf, 0xc5, 0x55, 0x43, 0xb9, 0xbc, 0x6a, 0x28, 0x1f, 0xaf, 0x1a, 0xca, 0xab, 0xeb, + 0x46, 0xe6, 0xf2, 0xba, 0x91, 0xf9, 0x70, 0xdd, 0xc8, 0x3c, 0xed, 0x0c, 0x09, 0x1b, 0x85, 0x96, + 0x66, 0xfb, 0x63, 0xdd, 0x25, 0x1e, 0xd6, 0x5d, 0x6b, 0xbc, 0x4f, 0x9d, 0xe7, 0xfa, 0x99, 0x3e, + 0x7f, 0x08, 0xfe, 0xea, 0xec, 0xcb, 0xb7, 0x80, 0xcd, 0x26, 0x98, 0x5a, 0x79, 0xbe, 0x1d, 0x7f, + 0x7f, 0x09, 0x00, 0x00, 0xff, 0xff, 0x79, 0x2e, 0xdd, 0x8e, 0x2b, 0x06, 0x00, 0x00, +} + +func (this *UpgradeProposal) Equal(that interface{}) bool { + if that == nil { + return this == nil + } + + that1, ok := that.(*UpgradeProposal) + if !ok { + that2, ok := that.(UpgradeProposal) + if ok { + that1 = &that2 + } else { + return false + } + } + if that1 == nil { + return this == nil + } else if this == nil { + return false + } + if this.Title != that1.Title { + return false + } + if this.Description != that1.Description { + return false + } + if !this.Plan.Equal(&that1.Plan) { + return false + } + if !this.UpgradedClientState.Equal(that1.UpgradedClientState) { + return false + } + return true } - func (m *IdentifiedClientState) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -534,9 +629,70 @@ func (m *ClientUpdateProposal) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l - if m.Header != nil { + { + size, err := m.InitialHeight.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintClient(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x2a + if len(m.SubstituteClientId) > 0 { + i -= len(m.SubstituteClientId) + copy(dAtA[i:], m.SubstituteClientId) + i = encodeVarintClient(dAtA, i, uint64(len(m.SubstituteClientId))) + i-- + dAtA[i] = 0x22 + } + if len(m.SubjectClientId) > 0 { + i -= len(m.SubjectClientId) + copy(dAtA[i:], m.SubjectClientId) + i = encodeVarintClient(dAtA, i, uint64(len(m.SubjectClientId))) + i-- + dAtA[i] = 0x1a + } + if len(m.Description) > 0 { + i -= len(m.Description) + copy(dAtA[i:], m.Description) + i = encodeVarintClient(dAtA, i, uint64(len(m.Description))) + i-- + dAtA[i] = 0x12 + } + if len(m.Title) > 0 { + i -= len(m.Title) + copy(dAtA[i:], m.Title) + i = encodeVarintClient(dAtA, i, uint64(len(m.Title))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *UpgradeProposal) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *UpgradeProposal) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *UpgradeProposal) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.UpgradedClientState != nil { { - size, err := m.Header.MarshalToSizedBuffer(dAtA[:i]) + size, err := m.UpgradedClientState.MarshalToSizedBuffer(dAtA[:i]) if err != nil { return 0, err } @@ -546,13 +702,16 @@ func (m *ClientUpdateProposal) MarshalToSizedBuffer(dAtA []byte) (int, error) { i-- dAtA[i] = 0x22 } - if len(m.ClientId) > 0 { - i -= len(m.ClientId) - copy(dAtA[i:], m.ClientId) - i = encodeVarintClient(dAtA, i, uint64(len(m.ClientId))) - i-- - dAtA[i] = 0x1a + { + size, err := m.Plan.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintClient(dAtA, i, uint64(size)) } + i-- + dAtA[i] = 0x1a if len(m.Description) > 0 { i -= len(m.Description) copy(dAtA[i:], m.Description) @@ -711,12 +870,37 @@ func (m *ClientUpdateProposal) Size() (n int) { if l > 0 { n += 1 + l + sovClient(uint64(l)) } - l = len(m.ClientId) + l = len(m.SubjectClientId) + if l > 0 { + n += 1 + l + sovClient(uint64(l)) + } + l = len(m.SubstituteClientId) + if l > 0 { + n += 1 + l + sovClient(uint64(l)) + } + l = m.InitialHeight.Size() + n += 1 + l + sovClient(uint64(l)) + return n +} + +func (m *UpgradeProposal) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Title) + if l > 0 { + n += 1 + l + sovClient(uint64(l)) + } + l = len(m.Description) if l > 0 { n += 1 + l + sovClient(uint64(l)) } - if m.Header != nil { - l = m.Header.Size() + l = m.Plan.Size() + n += 1 + l + sovClient(uint64(l)) + if m.UpgradedClientState != nil { + l = m.UpgradedClientState.Size() n += 1 + l + sovClient(uint64(l)) } return n @@ -1206,7 +1390,7 @@ func (m *ClientUpdateProposal) Unmarshal(dAtA []byte) error { iNdEx = postIndex case 3: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field ClientId", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field SubjectClientId", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -1234,11 +1418,223 @@ func (m *ClientUpdateProposal) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.ClientId = string(dAtA[iNdEx:postIndex]) + m.SubjectClientId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field SubstituteClientId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowClient + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthClient + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthClient + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.SubstituteClientId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field InitialHeight", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowClient + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthClient + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthClient + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.InitialHeight.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipClient(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthClient + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *UpgradeProposal) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowClient + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: UpgradeProposal: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: UpgradeProposal: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Title", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowClient + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthClient + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthClient + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Title = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Description", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowClient + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthClient + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthClient + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Description = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Plan", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowClient + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthClient + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthClient + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Plan.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } iNdEx = postIndex case 4: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Header", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field UpgradedClientState", wireType) } var msglen int for shift := uint(0); ; shift += 7 { @@ -1265,10 +1661,10 @@ func (m *ClientUpdateProposal) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - if m.Header == nil { - m.Header = &types.Any{} + if m.UpgradedClientState == nil { + m.UpgradedClientState = &types.Any{} } - if err := m.Header.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + if err := m.UpgradedClientState.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex diff --git a/x/ibc/core/02-client/types/codec.go b/x/ibc/core/02-client/types/codec.go index 1ae2814dfa..c72bc04467 100644 --- a/x/ibc/core/02-client/types/codec.go +++ b/x/ibc/core/02-client/types/codec.go @@ -7,6 +7,7 @@ import ( sdk "github.com/line/lbm-sdk/types" sdkerrors "github.com/line/lbm-sdk/types/errors" "github.com/line/lbm-sdk/types/msgservice" + govtypes "github.com/line/lbm-sdk/x/gov/types" "github.com/line/lbm-sdk/x/ibc/core/exported" ) @@ -33,6 +34,11 @@ func RegisterInterfaces(registry codectypes.InterfaceRegistry) { "ibc.core.client.v1.Misbehaviour", (*exported.Misbehaviour)(nil), ) + registry.RegisterImplementations( + (*govtypes.Content)(nil), + &ClientUpdateProposal{}, + &UpgradeProposal{}, + ) registry.RegisterImplementations( (*sdk.Msg)(nil), &MsgCreateClient{}, diff --git a/x/ibc/core/02-client/types/encoding.go b/x/ibc/core/02-client/types/encoding.go index d1716a001d..9f9c0f749f 100644 --- a/x/ibc/core/02-client/types/encoding.go +++ b/x/ibc/core/02-client/types/encoding.go @@ -9,7 +9,7 @@ import ( // MustUnmarshalClientState attempts to decode and return an ClientState object from // raw encoded bytes. It panics on error. -func MustUnmarshalClientState(cdc codec.BinaryMarshaler, bz []byte) exported.ClientState { +func MustUnmarshalClientState(cdc codec.Codec, bz []byte) exported.ClientState { clientState, err := UnmarshalClientState(cdc, bz) if err != nil { panic(fmt.Errorf("failed to decode client state: %w", err)) @@ -20,7 +20,7 @@ func MustUnmarshalClientState(cdc codec.BinaryMarshaler, bz []byte) exported.Cli // MustMarshalClientState attempts to encode an ClientState object and returns the // raw encoded bytes. It panics on error. -func MustMarshalClientState(cdc codec.BinaryMarshaler, clientState exported.ClientState) []byte { +func MustMarshalClientState(cdc codec.Codec, clientState exported.ClientState) []byte { bz, err := MarshalClientState(cdc, clientState) if err != nil { panic(fmt.Errorf("failed to encode client state: %w", err)) @@ -30,14 +30,14 @@ func MustMarshalClientState(cdc codec.BinaryMarshaler, clientState exported.Clie } // MarshalClientState protobuf serializes an ClientState interface -func MarshalClientState(cdc codec.BinaryMarshaler, clientStateI exported.ClientState) ([]byte, error) { +func MarshalClientState(cdc codec.Codec, clientStateI exported.ClientState) ([]byte, error) { return cdc.MarshalInterface(clientStateI) } // UnmarshalClientState returns an ClientState interface from raw encoded clientState // bytes of a Proto-based ClientState type. An error is returned upon decoding // failure. -func UnmarshalClientState(cdc codec.BinaryMarshaler, bz []byte) (exported.ClientState, error) { +func UnmarshalClientState(cdc codec.Codec, bz []byte) (exported.ClientState, error) { var clientState exported.ClientState if err := cdc.UnmarshalInterface(bz, &clientState); err != nil { return nil, err @@ -48,7 +48,7 @@ func UnmarshalClientState(cdc codec.BinaryMarshaler, bz []byte) (exported.Client // MustUnmarshalConsensusState attempts to decode and return an ConsensusState object from // raw encoded bytes. It panics on error. -func MustUnmarshalConsensusState(cdc codec.BinaryMarshaler, bz []byte) exported.ConsensusState { +func MustUnmarshalConsensusState(cdc codec.Codec, bz []byte) exported.ConsensusState { consensusState, err := UnmarshalConsensusState(cdc, bz) if err != nil { panic(fmt.Errorf("failed to decode consensus state: %w", err)) @@ -59,7 +59,7 @@ func MustUnmarshalConsensusState(cdc codec.BinaryMarshaler, bz []byte) exported. // MustMarshalConsensusState attempts to encode a ConsensusState object and returns the // raw encoded bytes. It panics on error. -func MustMarshalConsensusState(cdc codec.BinaryMarshaler, consensusState exported.ConsensusState) []byte { +func MustMarshalConsensusState(cdc codec.Codec, consensusState exported.ConsensusState) []byte { bz, err := MarshalConsensusState(cdc, consensusState) if err != nil { panic(fmt.Errorf("failed to encode consensus state: %w", err)) @@ -69,14 +69,14 @@ func MustMarshalConsensusState(cdc codec.BinaryMarshaler, consensusState exporte } // MarshalConsensusState protobuf serializes a ConsensusState interface -func MarshalConsensusState(cdc codec.BinaryMarshaler, cs exported.ConsensusState) ([]byte, error) { +func MarshalConsensusState(cdc codec.Codec, cs exported.ConsensusState) ([]byte, error) { return cdc.MarshalInterface(cs) } // UnmarshalConsensusState returns a ConsensusState interface from raw encoded consensus state // bytes of a Proto-based ConsensusState type. An error is returned upon decoding // failure. -func UnmarshalConsensusState(cdc codec.BinaryMarshaler, bz []byte) (exported.ConsensusState, error) { +func UnmarshalConsensusState(cdc codec.Codec, bz []byte) (exported.ConsensusState, error) { var consensusState exported.ConsensusState if err := cdc.UnmarshalInterface(bz, &consensusState); err != nil { return nil, err @@ -86,13 +86,13 @@ func UnmarshalConsensusState(cdc codec.BinaryMarshaler, bz []byte) (exported.Con } // MarshalHeader protobuf serializes a Header interface -func MarshalHeader(cdc codec.BinaryMarshaler, h exported.Header) ([]byte, error) { +func MarshalHeader(cdc codec.Codec, h exported.Header) ([]byte, error) { return cdc.MarshalInterface(h) } // MustMarshalHeader attempts to encode a Header object and returns the // raw encoded bytes. It panics on error. -func MustMarshalHeader(cdc codec.BinaryMarshaler, header exported.Header) []byte { +func MustMarshalHeader(cdc codec.Codec, header exported.Header) []byte { bz, err := MarshalHeader(cdc, header) if err != nil { panic(fmt.Errorf("failed to encode header: %w", err)) @@ -103,7 +103,7 @@ func MustMarshalHeader(cdc codec.BinaryMarshaler, header exported.Header) []byte // UnmarshalHeader returns a Header interface from raw proto encoded header bytes. // An error is returned upon decoding failure. -func UnmarshalHeader(cdc codec.BinaryMarshaler, bz []byte) (exported.Header, error) { +func UnmarshalHeader(cdc codec.Codec, bz []byte) (exported.Header, error) { var header exported.Header if err := cdc.UnmarshalInterface(bz, &header); err != nil { return nil, err diff --git a/x/ibc/core/02-client/types/encoding_test.go b/x/ibc/core/02-client/types/encoding_test.go index 7e8ff77e67..6505a54f7e 100644 --- a/x/ibc/core/02-client/types/encoding_test.go +++ b/x/ibc/core/02-client/types/encoding_test.go @@ -2,13 +2,13 @@ package types_test import ( "github.com/line/lbm-sdk/x/ibc/core/02-client/types" - ibctmtypes "github.com/line/lbm-sdk/x/ibc/light-clients/99-ostracon/types" + ibcoctypes "github.com/line/lbm-sdk/x/ibc/light-clients/99-ostracon/types" ) func (suite *TypesTestSuite) TestMarshalHeader() { cdc := suite.chainA.App.AppCodec() - h := &ibctmtypes.Header{ + h := &ibcoctypes.Header{ TrustedHeight: types.NewHeight(4, 100), } diff --git a/x/ibc/core/02-client/types/errors.go b/x/ibc/core/02-client/types/errors.go index 5945e28f6a..56dec47841 100644 --- a/x/ibc/core/02-client/types/errors.go +++ b/x/ibc/core/02-client/types/errors.go @@ -30,4 +30,7 @@ var ( ErrUpdateClientFailed = sdkerrors.Register(SubModuleName, 23, "unable to update light client") ErrInvalidUpdateClientProposal = sdkerrors.Register(SubModuleName, 24, "invalid update client proposal") ErrInvalidUpgradeClient = sdkerrors.Register(SubModuleName, 25, "invalid client upgrade") + ErrInvalidHeight = sdkerrors.Register(SubModuleName, 26, "invalid height") + ErrInvalidSubstitute = sdkerrors.Register(SubModuleName, 27, "invalid client state substitute") + ErrInvalidUpgradeProposal = sdkerrors.Register(SubModuleName, 28, "invalid upgrade proposal") ) diff --git a/x/ibc/core/02-client/types/events.go b/x/ibc/core/02-client/types/events.go index 6563e9b870..e74f5fab57 100644 --- a/x/ibc/core/02-client/types/events.go +++ b/x/ibc/core/02-client/types/events.go @@ -9,6 +9,7 @@ import ( // IBC client events const ( AttributeKeyClientID = "client_id" + AttributeKeySubjectClientID = "subject_client_id" AttributeKeyClientType = "client_type" AttributeKeyConsensusHeight = "consensus_height" AttributeKeyHeader = "header" diff --git a/x/ibc/core/02-client/types/expected_keepers.go b/x/ibc/core/02-client/types/expected_keepers.go index 7ffae30789..fb6679d053 100644 --- a/x/ibc/core/02-client/types/expected_keepers.go +++ b/x/ibc/core/02-client/types/expected_keepers.go @@ -5,6 +5,7 @@ import ( sdk "github.com/line/lbm-sdk/types" stakingtypes "github.com/line/lbm-sdk/x/staking/types" + upgradetypes "github.com/line/lbm-sdk/x/upgrade/types" ) // StakingKeeper expected staking keeper @@ -12,3 +13,13 @@ type StakingKeeper interface { GetHistoricalInfo(ctx sdk.Context, height int64) (stakingtypes.HistoricalInfo, bool) UnbondingTime(ctx sdk.Context) time.Duration } + +// UpgradeKeeper expected upgrade keeper +type UpgradeKeeper interface { + ClearIBCState(ctx sdk.Context, lastHeight int64) + GetUpgradePlan(ctx sdk.Context) (plan upgradetypes.Plan, havePlan bool) + GetUpgradedClient(ctx sdk.Context, height int64) ([]byte, bool) + SetUpgradedConsensusState(ctx sdk.Context, planHeight int64, bz []byte) error + SetUpgradedClient(ctx sdk.Context, planHeight int64, bz []byte) error + ScheduleUpgrade(ctx sdk.Context, plan upgradetypes.Plan) error +} diff --git a/x/ibc/core/02-client/types/proposal.go b/x/ibc/core/02-client/types/proposal.go index b7e6672ef4..dfb4b22354 100644 --- a/x/ibc/core/02-client/types/proposal.go +++ b/x/ibc/core/02-client/types/proposal.go @@ -1,35 +1,41 @@ package types import ( + "fmt" + codectypes "github.com/line/lbm-sdk/codec/types" + sdkerrors "github.com/line/lbm-sdk/types/errors" govtypes "github.com/line/lbm-sdk/x/gov/types" - host "github.com/line/lbm-sdk/x/ibc/core/24-host" "github.com/line/lbm-sdk/x/ibc/core/exported" + upgradetypes "github.com/line/lbm-sdk/x/upgrade/types" ) const ( // ProposalTypeClientUpdate defines the type for a ClientUpdateProposal ProposalTypeClientUpdate = "ClientUpdate" + ProposalTypeUpgrade = "IBCUpgrade" ) var ( _ govtypes.Content = &ClientUpdateProposal{} - _ codectypes.UnpackInterfacesMessage = ClientUpdateProposal{} + _ govtypes.Content = &UpgradeProposal{} + _ codectypes.UnpackInterfacesMessage = &UpgradeProposal{} ) -// NewClientUpdateProposal creates a new client update proposal. -func NewClientUpdateProposal(title, description, clientID string, header exported.Header) (*ClientUpdateProposal, error) { - any, err := PackHeader(header) - if err != nil { - return nil, err - } +func init() { + govtypes.RegisterProposalType(ProposalTypeClientUpdate) + govtypes.RegisterProposalType(ProposalTypeUpgrade) +} +// NewClientUpdateProposal creates a new client update proposal. +func NewClientUpdateProposal(title, description, subjectClientID, substituteClientID string, initialHeight Height) govtypes.Content { return &ClientUpdateProposal{ - Title: title, - Description: description, - ClientId: clientID, - Header: any, - }, nil + Title: title, + Description: description, + SubjectClientId: subjectClientID, + SubstituteClientId: substituteClientID, + InitialHeight: initialHeight, + } } // GetTitle returns the title of a client update proposal. @@ -51,20 +57,94 @@ func (cup *ClientUpdateProposal) ValidateBasic() error { return err } - if err := host.ClientIdentifierValidator(cup.ClientId); err != nil { + if cup.SubjectClientId == cup.SubstituteClientId { + return sdkerrors.Wrap(ErrInvalidSubstitute, "subject and substitute client identifiers are equal") + } + if _, _, err := ParseClientIdentifier(cup.SubjectClientId); err != nil { return err } + if _, _, err := ParseClientIdentifier(cup.SubstituteClientId); err != nil { + return err + } + + if cup.InitialHeight.IsZero() { + return sdkerrors.Wrap(ErrInvalidHeight, "initial height cannot be zero height") + } + + return nil +} - header, err := UnpackHeader(cup.Header) +// NewUpgradeProposal creates a new IBC breaking upgrade proposal. +func NewUpgradeProposal(title, description string, plan upgradetypes.Plan, upgradedClientState exported.ClientState) (govtypes.Content, error) { + any, err := PackClientState(upgradedClientState) if err != nil { + return nil, err + } + + return &UpgradeProposal{ + Title: title, + Description: description, + Plan: plan, + UpgradedClientState: any, + }, nil +} + +// GetTitle returns the title of a upgrade proposal. +func (up *UpgradeProposal) GetTitle() string { return up.Title } + +// GetDescription returns the description of a upgrade proposal. +func (up *UpgradeProposal) GetDescription() string { return up.Description } + +// ProposalRoute returns the routing key of a upgrade proposal. +func (up *UpgradeProposal) ProposalRoute() string { return RouterKey } + +// ProposalType returns the upgrade proposal type. +func (up *UpgradeProposal) ProposalType() string { return ProposalTypeUpgrade } + +// ValidateBasic runs basic stateless validity checks +func (up *UpgradeProposal) ValidateBasic() error { + if err := govtypes.ValidateAbstract(up); err != nil { return err } - return header.ValidateBasic() + if err := up.Plan.ValidateBasic(); err != nil { + return err + } + + if up.Plan.Height <= 0 { + return sdkerrors.Wrap(ErrInvalidUpgradeProposal, "IBC chain upgrades must set a positive height") + } + + if up.UpgradedClientState == nil { + return sdkerrors.Wrap(ErrInvalidUpgradeProposal, "upgraded client state cannot be nil") + } + + _, err := UnpackClientState(up.UpgradedClientState) + if err != nil { + return sdkerrors.Wrap(err, "failed to unpack upgraded client state") + } + + return nil +} + +// String returns the string representation of the UpgradeProposal. +func (up UpgradeProposal) String() string { + var upgradedClientStr string + upgradedClient, err := UnpackClientState(up.UpgradedClientState) + if err != nil { + upgradedClientStr = "invalid IBC Client State" + } else { + upgradedClientStr = upgradedClient.String() + } + + return fmt.Sprintf(`IBC Upgrade Proposal + Title: %s + Description: %s + %s + Upgraded IBC Client: %s`, up.Title, up.Description, up.Plan, upgradedClientStr) } -// UnpackInterfaces implements the UnpackInterfacesMessage interface. -func (cup ClientUpdateProposal) UnpackInterfaces(unpacker codectypes.AnyUnpacker) error { - var header exported.Header - return unpacker.UnpackAny(cup.Header, &header) +// UnpackInterfaces implements UnpackInterfacesMessage.UnpackInterfaces +func (up UpgradeProposal) UnpackInterfaces(unpacker codectypes.AnyUnpacker) error { + return unpacker.UnpackAny(up.UpgradedClientState, new(exported.ClientState)) } diff --git a/x/ibc/core/02-client/types/proposal_test.go b/x/ibc/core/02-client/types/proposal_test.go index e21f9c0035..a9c32b8891 100644 --- a/x/ibc/core/02-client/types/proposal_test.go +++ b/x/ibc/core/02-client/types/proposal_test.go @@ -1,39 +1,24 @@ package types_test import ( + "fmt" + "time" + "github.com/line/lbm-sdk/codec" codectypes "github.com/line/lbm-sdk/codec/types" govtypes "github.com/line/lbm-sdk/x/gov/types" "github.com/line/lbm-sdk/x/ibc/core/02-client/types" - ibctmtypes "github.com/line/lbm-sdk/x/ibc/light-clients/99-ostracon/types" + "github.com/line/lbm-sdk/x/ibc/core/exported" + ibcoctypes "github.com/line/lbm-sdk/x/ibc/light-clients/99-ostracon/types" ibctesting "github.com/line/lbm-sdk/x/ibc/testing" + upgradetypes "github.com/line/lbm-sdk/x/upgrade/types" ) -func (suite *TypesTestSuite) TestNewUpdateClientProposal() { - p, err := types.NewClientUpdateProposal(ibctesting.Title, ibctesting.Description, clientID, &ibctmtypes.Header{}) - suite.Require().NoError(err) - suite.Require().NotNil(p) - - p, err = types.NewClientUpdateProposal(ibctesting.Title, ibctesting.Description, clientID, nil) - suite.Require().Error(err) - suite.Require().Nil(p) -} - func (suite *TypesTestSuite) TestValidateBasic() { - // use solo machine header for testing - solomachine := ibctesting.NewSolomachine(suite.T(), suite.chainA.Codec, clientID, "", 2) - smHeader := solomachine.CreateHeader() - header, err := types.PackHeader(smHeader) - suite.Require().NoError(err) - - // use a different pointer so we don't modify 'header' - smInvalidHeader := solomachine.CreateHeader() - - // a sequence of 0 will fail basic validation - smInvalidHeader.Sequence = 0 - - invalidHeader, err := types.PackHeader(smInvalidHeader) - suite.Require().NoError(err) + subject, _ := suite.coordinator.SetupClients(suite.chainA, suite.chainB, exported.Ostracon) + subjectClientState := suite.chainA.GetClientState(subject) + substitute, _ := suite.coordinator.SetupClients(suite.chainA, suite.chainB, exported.Ostracon) + initialHeight := types.NewHeight(subjectClientState.GetLatestHeight().GetRevisionNumber(), subjectClientState.GetLatestHeight().GetRevisionHeight()+1) testCases := []struct { name string @@ -42,22 +27,32 @@ func (suite *TypesTestSuite) TestValidateBasic() { }{ { "success", - &types.ClientUpdateProposal{ibctesting.Title, ibctesting.Description, clientID, header}, + types.NewClientUpdateProposal(ibctesting.Title, ibctesting.Description, subject, substitute, initialHeight), true, }, { "fails validate abstract - empty title", - &types.ClientUpdateProposal{"", ibctesting.Description, clientID, header}, + types.NewClientUpdateProposal("", ibctesting.Description, subject, substitute, initialHeight), false, }, { - "fails to unpack header", - &types.ClientUpdateProposal{ibctesting.Title, ibctesting.Description, clientID, nil}, + "subject and substitute use the same identifier", + types.NewClientUpdateProposal(ibctesting.Title, ibctesting.Description, subject, subject, initialHeight), false, }, { - "fails header validate basic", - &types.ClientUpdateProposal{ibctesting.Title, ibctesting.Description, clientID, invalidHeader}, + "invalid subject clientID", + types.NewClientUpdateProposal(ibctesting.Title, ibctesting.Description, ibctesting.InvalidID, substitute, initialHeight), + false, + }, + { + "invalid substitute clientID", + types.NewClientUpdateProposal(ibctesting.Title, ibctesting.Description, subject, ibctesting.InvalidID, initialHeight), + false, + }, + { + "initial height is zero", + types.NewClientUpdateProposal(ibctesting.Title, ibctesting.Description, subject, substitute, types.ZeroHeight()), false, }, } @@ -74,34 +69,166 @@ func (suite *TypesTestSuite) TestValidateBasic() { } } -// tests a client update proposal can be marshaled and unmarshaled, and the -// client state can be unpacked +// tests a client update proposal can be marshaled and unmarshaled func (suite *TypesTestSuite) TestMarshalClientUpdateProposalProposal() { - _, err := types.PackHeader(&ibctmtypes.Header{}) + // create proposal + proposal := types.NewClientUpdateProposal("update IBC client", "description", "subject", "substitute", types.NewHeight(1, 0)) + + // create codec + ir := codectypes.NewInterfaceRegistry() + types.RegisterInterfaces(ir) + govtypes.RegisterInterfaces(ir) + cdc := codec.NewProtoCodec(ir) + + // marshal message + content := proposal.(*types.ClientUpdateProposal) + bz, err := cdc.MarshalJSON(content) + suite.Require().NoError(err) + + // unmarshal proposal + newProposal := &types.ClientUpdateProposal{} + err = cdc.UnmarshalJSON(bz, newProposal) suite.Require().NoError(err) +} +func (suite *TypesTestSuite) TestUpgradeProposalValidateBasic() { + var ( + proposal govtypes.Content + err error + ) + + client, _ := suite.coordinator.SetupClients(suite.chainA, suite.chainB, exported.Ostracon) + cs := suite.chainA.GetClientState(client) + plan := upgradetypes.Plan{ + Name: "ibc upgrade", + Height: 1000, + } + + testCases := []struct { + name string + malleate func() + expPass bool + }{ + { + "success", func() { + proposal, err = types.NewUpgradeProposal(ibctesting.Title, ibctesting.Description, plan, cs) + suite.Require().NoError(err) + }, true, + }, + { + "fails validate abstract - empty title", func() { + proposal, err = types.NewUpgradeProposal("", ibctesting.Description, plan, cs) + suite.Require().NoError(err) + + }, false, + }, + { + "fails plan validate basic, height and time is 0", func() { + invalidPlan := upgradetypes.Plan{Name: "ibc upgrade"} + proposal, err = types.NewUpgradeProposal(ibctesting.Title, ibctesting.Description, invalidPlan, cs) + suite.Require().NoError(err) + }, false, + }, + { + "plan height is zero", func() { + invalidPlan := upgradetypes.Plan{Name: "ibc upgrade", Height: 0} + proposal, err = types.NewUpgradeProposal(ibctesting.Title, ibctesting.Description, invalidPlan, cs) + suite.Require().NoError(err) + }, false, + }, + { + "plan time is not set to 0", func() { + invalidPlan := upgradetypes.Plan{Name: "ibc upgrade", Time: time.Now()} + proposal, err = types.NewUpgradeProposal(ibctesting.Title, ibctesting.Description, invalidPlan, cs) + suite.Require().NoError(err) + }, false, + }, + { + "client state is nil", func() { + proposal = &types.UpgradeProposal{ + Title: ibctesting.Title, + Description: ibctesting.Description, + Plan: plan, + UpgradedClientState: nil, + } + }, false, + }, + { + "failed to unpack client state", func() { + any, err := types.PackConsensusState(&ibcoctypes.ConsensusState{}) + suite.Require().NoError(err) + + proposal = &types.UpgradeProposal{ + Title: ibctesting.Title, + Description: ibctesting.Description, + Plan: plan, + UpgradedClientState: any, + } + }, false, + }, + } + + for _, tc := range testCases { + + tc.malleate() + + err := proposal.ValidateBasic() + + if tc.expPass { + suite.Require().NoError(err, tc.name) + } else { + suite.Require().Error(err, tc.name) + } + } +} + +// tests an upgrade proposal can be marshaled and unmarshaled, and the +// client state can be unpacked +func (suite *TypesTestSuite) TestMarshalUpgradeProposal() { // create proposal - header := suite.chainA.CurrentOCClientHeader() - proposal, err := types.NewClientUpdateProposal("update IBC client", "description", "client-id", header) + plan := upgradetypes.Plan{ + Name: "upgrade ibc", + Height: 1000, + } + content, err := types.NewUpgradeProposal("title", "description", plan, &ibcoctypes.ClientState{}) suite.Require().NoError(err) + up, ok := content.(*types.UpgradeProposal) + suite.Require().True(ok) + // create codec ir := codectypes.NewInterfaceRegistry() types.RegisterInterfaces(ir) govtypes.RegisterInterfaces(ir) - ibctmtypes.RegisterInterfaces(ir) + ibcoctypes.RegisterInterfaces(ir) cdc := codec.NewProtoCodec(ir) // marshal message - bz, err := cdc.MarshalJSON(proposal) + bz, err := cdc.MarshalJSON(up) suite.Require().NoError(err) // unmarshal proposal - newProposal := &types.ClientUpdateProposal{} - err = cdc.UnmarshalJSON(bz, newProposal) + newUp := &types.UpgradeProposal{} + err = cdc.UnmarshalJSON(bz, newUp) suite.Require().NoError(err) // unpack client state - _, err = types.UnpackHeader(newProposal.Header) + _, err = types.UnpackClientState(newUp.UpgradedClientState) + suite.Require().NoError(err) + +} + +func (suite *TypesTestSuite) TestUpgradeString() { + plan := upgradetypes.Plan{ + Name: "ibc upgrade", + Info: "https://foo.bar/baz", + Height: 1000, + } + + proposal, err := types.NewUpgradeProposal(ibctesting.Title, ibctesting.Description, plan, &ibcoctypes.ClientState{}) suite.Require().NoError(err) + + expect := fmt.Sprintf("IBC Upgrade Proposal\n Title: title\n Description: description\n Upgrade Plan\n Name: ibc upgrade\n Height: 1000\n Info: https://foo.bar/baz.\n Upgraded IBC Client: %s", &ibcoctypes.ClientState{}) + + suite.Require().Equal(expect, proposal.String()) } diff --git a/x/ibc/core/02-client/types/query.pb.go b/x/ibc/core/02-client/types/query.pb.go index 85fb439677..415a23e7dc 100644 --- a/x/ibc/core/02-client/types/query.pb.go +++ b/x/ibc/core/02-client/types/query.pb.go @@ -583,6 +583,110 @@ func (m *QueryClientParamsResponse) GetParams() *Params { return nil } +// QueryUpgradedClientStateRequest is the request type for the Query/UpgradedClientState RPC +// method +type QueryUpgradedClientStateRequest struct { + // client state unique identifier + ClientId string `protobuf:"bytes,1,opt,name=client_id,json=clientId,proto3" json:"client_id,omitempty"` + // plan height of the current chain must be sent in request + // as this is the height under which upgraded client state is stored + PlanHeight int64 `protobuf:"varint,2,opt,name=plan_height,json=planHeight,proto3" json:"plan_height,omitempty"` +} + +func (m *QueryUpgradedClientStateRequest) Reset() { *m = QueryUpgradedClientStateRequest{} } +func (m *QueryUpgradedClientStateRequest) String() string { return proto.CompactTextString(m) } +func (*QueryUpgradedClientStateRequest) ProtoMessage() {} +func (*QueryUpgradedClientStateRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_dc42cdfd1d52d76e, []int{10} +} +func (m *QueryUpgradedClientStateRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryUpgradedClientStateRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryUpgradedClientStateRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryUpgradedClientStateRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryUpgradedClientStateRequest.Merge(m, src) +} +func (m *QueryUpgradedClientStateRequest) XXX_Size() int { + return m.Size() +} +func (m *QueryUpgradedClientStateRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QueryUpgradedClientStateRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryUpgradedClientStateRequest proto.InternalMessageInfo + +func (m *QueryUpgradedClientStateRequest) GetClientId() string { + if m != nil { + return m.ClientId + } + return "" +} + +func (m *QueryUpgradedClientStateRequest) GetPlanHeight() int64 { + if m != nil { + return m.PlanHeight + } + return 0 +} + +// QueryUpgradedClientStateResponse is the response type for the Query/UpgradedClientState RPC +// method. +type QueryUpgradedClientStateResponse struct { + // client state associated with the request identifier + UpgradedClientState *types.Any `protobuf:"bytes,1,opt,name=upgraded_client_state,json=upgradedClientState,proto3" json:"upgraded_client_state,omitempty"` +} + +func (m *QueryUpgradedClientStateResponse) Reset() { *m = QueryUpgradedClientStateResponse{} } +func (m *QueryUpgradedClientStateResponse) String() string { return proto.CompactTextString(m) } +func (*QueryUpgradedClientStateResponse) ProtoMessage() {} +func (*QueryUpgradedClientStateResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_dc42cdfd1d52d76e, []int{11} +} +func (m *QueryUpgradedClientStateResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryUpgradedClientStateResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryUpgradedClientStateResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryUpgradedClientStateResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryUpgradedClientStateResponse.Merge(m, src) +} +func (m *QueryUpgradedClientStateResponse) XXX_Size() int { + return m.Size() +} +func (m *QueryUpgradedClientStateResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryUpgradedClientStateResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryUpgradedClientStateResponse proto.InternalMessageInfo + +func (m *QueryUpgradedClientStateResponse) GetUpgradedClientState() *types.Any { + if m != nil { + return m.UpgradedClientState + } + return nil +} + func init() { proto.RegisterType((*QueryClientStateRequest)(nil), "ibc.core.client.v1.QueryClientStateRequest") proto.RegisterType((*QueryClientStateResponse)(nil), "ibc.core.client.v1.QueryClientStateResponse") @@ -594,63 +698,71 @@ func init() { proto.RegisterType((*QueryConsensusStatesResponse)(nil), "ibc.core.client.v1.QueryConsensusStatesResponse") proto.RegisterType((*QueryClientParamsRequest)(nil), "ibc.core.client.v1.QueryClientParamsRequest") proto.RegisterType((*QueryClientParamsResponse)(nil), "ibc.core.client.v1.QueryClientParamsResponse") + proto.RegisterType((*QueryUpgradedClientStateRequest)(nil), "ibc.core.client.v1.QueryUpgradedClientStateRequest") + proto.RegisterType((*QueryUpgradedClientStateResponse)(nil), "ibc.core.client.v1.QueryUpgradedClientStateResponse") } func init() { proto.RegisterFile("ibc/core/client/v1/query.proto", fileDescriptor_dc42cdfd1d52d76e) } var fileDescriptor_dc42cdfd1d52d76e = []byte{ - // 811 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x55, 0xbd, 0x6f, 0xd3, 0x5a, - 0x14, 0xcf, 0xed, 0x97, 0xda, 0x9b, 0xb4, 0x79, 0xba, 0xea, 0x7b, 0x4d, 0xdd, 0x3e, 0x27, 0xcf, - 0x1d, 0x5e, 0x2a, 0x1a, 0xdf, 0x36, 0x88, 0x8f, 0x85, 0x22, 0xda, 0x85, 0x4a, 0x08, 0x8a, 0x19, - 0x90, 0x2a, 0xa1, 0xca, 0x76, 0x6e, 0x1c, 0x0b, 0xc7, 0x4e, 0x73, 0x9d, 0x88, 0x52, 0x75, 0x61, - 0x64, 0x42, 0x42, 0x62, 0x65, 0x67, 0xa8, 0xd8, 0xd8, 0x98, 0x3b, 0x30, 0x54, 0x62, 0x61, 0xa2, - 0x28, 0xe5, 0x0f, 0x41, 0xbe, 0xf7, 0x3a, 0xb5, 0x53, 0x47, 0x75, 0x25, 0xd8, 0x9c, 0xf3, 0x75, - 0x7f, 0xbf, 0x73, 0x7e, 0xe7, 0x04, 0xca, 0xb6, 0x61, 0x62, 0xd3, 0x6b, 0x13, 0x6c, 0x3a, 0x36, - 0x71, 0x7d, 0xdc, 0x5d, 0xc3, 0x7b, 0x1d, 0xd2, 0xde, 0x57, 0x5b, 0x6d, 0xcf, 0xf7, 0x10, 0xb2, - 0x0d, 0x53, 0x0d, 0xfc, 0x2a, 0xf7, 0xab, 0xdd, 0x35, 0x49, 0x71, 0x8c, 0x26, 0x36, 0x74, 0x4a, - 0x78, 0x64, 0x90, 0xd2, 0xd2, 0x2d, 0xdb, 0xd5, 0x7d, 0xdb, 0x73, 0x79, 0x9e, 0x54, 0x4c, 0xa8, - 0x2b, 0x2a, 0xf0, 0x80, 0x79, 0xcb, 0xf3, 0x2c, 0x87, 0x60, 0xf6, 0xcb, 0xe8, 0xd4, 0xb1, 0xee, - 0x8a, 0x37, 0xa5, 0x45, 0xe1, 0xd2, 0x5b, 0x36, 0xd6, 0x5d, 0xd7, 0xf3, 0x59, 0x61, 0x2a, 0xbc, - 0xb3, 0x96, 0x67, 0x79, 0xec, 0x13, 0x07, 0x5f, 0xdc, 0xaa, 0xdc, 0x84, 0x73, 0x8f, 0x03, 0x30, - 0x9b, 0xec, 0x8d, 0x27, 0xbe, 0xee, 0x13, 0x8d, 0xec, 0x75, 0x08, 0xf5, 0xd1, 0x02, 0x9c, 0xe2, - 0x2f, 0xef, 0xda, 0xb5, 0x02, 0x28, 0x81, 0xf2, 0x94, 0x36, 0xc9, 0x0d, 0x5b, 0x35, 0xe5, 0x08, - 0xc0, 0xc2, 0xc5, 0x44, 0xda, 0xf2, 0x5c, 0x4a, 0xd0, 0x2d, 0x98, 0x13, 0x99, 0x34, 0xb0, 0xb3, - 0xe4, 0x6c, 0x75, 0x56, 0xe5, 0xf8, 0xd4, 0x10, 0xba, 0x7a, 0xcf, 0xdd, 0xd7, 0xb2, 0xe6, 0x79, - 0x01, 0x34, 0x0b, 0xc7, 0x5b, 0x6d, 0xcf, 0xab, 0x17, 0x46, 0x4a, 0xa0, 0x9c, 0xd3, 0xf8, 0x0f, - 0xb4, 0x09, 0x73, 0xec, 0x63, 0xb7, 0x41, 0x6c, 0xab, 0xe1, 0x17, 0x46, 0x59, 0x39, 0x49, 0xbd, - 0xd8, 0x62, 0xf5, 0x3e, 0x8b, 0xd8, 0x18, 0x3b, 0xfe, 0x5e, 0xcc, 0x68, 0x59, 0x96, 0xc5, 0x4d, - 0xca, 0xce, 0x45, 0xbc, 0x34, 0x64, 0xba, 0x0e, 0xe1, 0xf9, 0x20, 0x04, 0x5a, 0x59, 0x75, 0x8c, - 0xa6, 0x1a, 0x4c, 0x4b, 0xe5, 0x73, 0xed, 0xae, 0xa9, 0xdb, 0xba, 0x15, 0x76, 0x47, 0x8b, 0x64, - 0x28, 0x5f, 0x00, 0x9c, 0x4f, 0x28, 0x2e, 0xba, 0xe1, 0xc2, 0xe9, 0x68, 0x37, 0x68, 0x01, 0x94, - 0x46, 0xcb, 0xd9, 0xea, 0x72, 0x12, 0xfe, 0xad, 0x1a, 0x71, 0x7d, 0xbb, 0x6e, 0x93, 0x5a, 0xa4, - 0xd4, 0x86, 0x1c, 0xd0, 0xf9, 0x70, 0x5a, 0xfc, 0x27, 0xd1, 0x4d, 0xb5, 0x5c, 0xa4, 0x87, 0x14, - 0xdd, 0x8d, 0xb1, 0x19, 0x61, 0x6c, 0x8a, 0x43, 0xd9, 0x70, 0x90, 0x31, 0x3a, 0x1f, 0x01, 0x94, - 0x38, 0x9d, 0xc0, 0xe5, 0xd2, 0x0e, 0x4d, 0xad, 0x0b, 0xf4, 0x3f, 0xcc, 0xb7, 0x49, 0xd7, 0xa6, - 0xb6, 0xe7, 0xee, 0xba, 0x9d, 0xa6, 0x41, 0xda, 0x0c, 0xc1, 0x98, 0x36, 0x13, 0x9a, 0x1f, 0x32, - 0x6b, 0x2c, 0x30, 0x32, 0xd7, 0x48, 0x20, 0x1f, 0x1c, 0x5a, 0x82, 0xd3, 0x4e, 0xc0, 0xcb, 0x0f, - 0xc3, 0xc6, 0x4a, 0xa0, 0x3c, 0xa9, 0xe5, 0xb8, 0x51, 0x4c, 0xf7, 0x13, 0x80, 0x0b, 0x89, 0x90, - 0xc5, 0x0c, 0xee, 0xc0, 0xbc, 0x19, 0x7a, 0x52, 0x88, 0x72, 0xc6, 0x8c, 0x95, 0xf9, 0x93, 0xba, - 0x7c, 0x99, 0x08, 0x9c, 0xa6, 0x6a, 0xf6, 0x7a, 0xc2, 0xa4, 0xaf, 0xa2, 0xdb, 0xcf, 0x00, 0x2e, - 0x26, 0x3f, 0x2e, 0xda, 0xf6, 0x0c, 0xfe, 0x35, 0xd0, 0xb6, 0x50, 0xbd, 0x2b, 0x49, 0x2c, 0xe3, - 0x65, 0x9e, 0xda, 0x7e, 0x23, 0xc6, 0x3b, 0x1f, 0xef, 0xea, 0x6f, 0x50, 0xaa, 0x14, 0x5b, 0xea, - 0x6d, 0xbd, 0xad, 0x37, 0xc3, 0xce, 0x29, 0x8f, 0x62, 0x3b, 0x19, 0xfa, 0x04, 0xb1, 0x2a, 0x9c, - 0x68, 0x31, 0x8b, 0x90, 0x41, 0xe2, 0xd0, 0x44, 0x8e, 0x88, 0xac, 0xf6, 0x26, 0xe0, 0x38, 0xab, - 0x88, 0xde, 0x03, 0x98, 0x8d, 0x2c, 0x20, 0xba, 0x96, 0x94, 0x3d, 0xe4, 0xac, 0x4a, 0x2b, 0xe9, - 0x82, 0x39, 0x50, 0xe5, 0xc6, 0xab, 0xaf, 0x3f, 0xdf, 0x8e, 0x60, 0x54, 0xc1, 0x43, 0xff, 0x18, - 0xc4, 0x60, 0xf0, 0x41, 0x5f, 0x28, 0x87, 0xe8, 0x1d, 0x80, 0xb9, 0xe8, 0x89, 0x40, 0xa9, 0x5e, - 0x0d, 0x7b, 0x27, 0x55, 0x52, 0x46, 0x0b, 0x90, 0xcb, 0x0c, 0xe4, 0x12, 0xfa, 0xef, 0x52, 0x90, - 0xe8, 0x14, 0xc0, 0x99, 0xb8, 0x4c, 0x90, 0x3a, 0xfc, 0xb1, 0xa4, 0xfb, 0x23, 0xe1, 0xd4, 0xf1, - 0x02, 0x9e, 0xc3, 0xe0, 0xd5, 0x51, 0x2d, 0x11, 0xde, 0x80, 0xbe, 0xa3, 0x6d, 0xc4, 0xe1, 0x29, - 0xc2, 0x07, 0x03, 0x47, 0xed, 0x10, 0xf3, 0x9d, 0x8f, 0x38, 0xb8, 0xe1, 0x10, 0x1d, 0x01, 0x98, - 0x1f, 0xd8, 0x27, 0x94, 0x16, 0x72, 0x7f, 0x00, 0xab, 0xe9, 0x13, 0x04, 0xc9, 0xdb, 0x8c, 0x64, - 0x15, 0xad, 0x5e, 0x95, 0x24, 0x7a, 0xdd, 0xd7, 0x0a, 0x17, 0xfc, 0xa5, 0x5a, 0x89, 0xed, 0xd9, - 0xa5, 0x5a, 0x89, 0x6f, 0x9e, 0xf2, 0x2f, 0xc3, 0x39, 0x87, 0xfe, 0xe6, 0x38, 0xfb, 0x10, 0xf9, - 0x92, 0x6d, 0x3c, 0x38, 0xee, 0xc9, 0xe0, 0xa4, 0x27, 0x83, 0x1f, 0x3d, 0x19, 0xbc, 0x39, 0x93, - 0x33, 0x27, 0x67, 0x72, 0xe6, 0xdb, 0x99, 0x9c, 0xd9, 0xa9, 0x5a, 0xb6, 0xdf, 0xe8, 0x18, 0xaa, - 0xe9, 0x35, 0xb1, 0x63, 0xbb, 0x04, 0x3b, 0x46, 0xb3, 0x42, 0x6b, 0xcf, 0xf1, 0x8b, 0x73, 0xc6, - 0xab, 0xd5, 0x8a, 0xa8, 0xe8, 0xef, 0xb7, 0x08, 0x35, 0x26, 0xd8, 0x55, 0xbf, 0xfe, 0x2b, 0x00, - 0x00, 0xff, 0xff, 0x21, 0xd9, 0x0b, 0x22, 0xae, 0x09, 0x00, 0x00, + // 897 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x55, 0xcf, 0x6f, 0xe3, 0x44, + 0x14, 0xce, 0xb4, 0xdd, 0x55, 0x77, 0x92, 0x6d, 0xd0, 0x6c, 0x97, 0xcd, 0x7a, 0x17, 0x27, 0x78, + 0x0f, 0x64, 0xc5, 0xc6, 0xd3, 0x66, 0xa1, 0xf4, 0x42, 0x11, 0xed, 0xa5, 0x95, 0x10, 0x14, 0x23, + 0x84, 0x54, 0x09, 0x45, 0xb6, 0x33, 0x71, 0x2c, 0x1c, 0xdb, 0xf5, 0xd8, 0x11, 0xa5, 0xea, 0x85, + 0x23, 0x27, 0x24, 0x24, 0xae, 0x9c, 0xb8, 0x70, 0xa8, 0xb8, 0x71, 0x43, 0x1c, 0x7b, 0xe0, 0x50, + 0x89, 0x0b, 0x27, 0x8a, 0x5a, 0xfe, 0x10, 0xe4, 0x99, 0x71, 0x6a, 0x27, 0x13, 0xd5, 0x95, 0xe0, + 0xe6, 0xbc, 0x9f, 0xdf, 0xfb, 0xde, 0x37, 0x2f, 0x50, 0x75, 0x2d, 0x1b, 0xdb, 0x41, 0x44, 0xb0, + 0xed, 0xb9, 0xc4, 0x8f, 0xf1, 0x78, 0x1d, 0x1f, 0x26, 0x24, 0x3a, 0xd2, 0xc3, 0x28, 0x88, 0x03, + 0x84, 0x5c, 0xcb, 0xd6, 0x53, 0xbf, 0xce, 0xfd, 0xfa, 0x78, 0x5d, 0xd1, 0x3c, 0x6b, 0x84, 0x2d, + 0x93, 0x12, 0x1e, 0x99, 0xa6, 0x84, 0xa6, 0xe3, 0xfa, 0x66, 0xec, 0x06, 0x3e, 0xcf, 0x53, 0x9a, + 0x92, 0xba, 0xa2, 0x02, 0x0f, 0x78, 0xec, 0x04, 0x81, 0xe3, 0x11, 0xcc, 0x7e, 0x59, 0xc9, 0x00, + 0x9b, 0xbe, 0xe8, 0xa9, 0x3c, 0x15, 0x2e, 0x33, 0x74, 0xb1, 0xe9, 0xfb, 0x41, 0xcc, 0x0a, 0x53, + 0xe1, 0x5d, 0x75, 0x02, 0x27, 0x60, 0x9f, 0x38, 0xfd, 0xe2, 0x56, 0x6d, 0x03, 0x3e, 0xfa, 0x38, + 0x05, 0xb3, 0xc3, 0x7a, 0x7c, 0x12, 0x9b, 0x31, 0x31, 0xc8, 0x61, 0x42, 0x68, 0x8c, 0x9e, 0xc0, + 0x7b, 0xbc, 0x73, 0xcf, 0xed, 0x37, 0x40, 0x0b, 0xb4, 0xef, 0x19, 0xcb, 0xdc, 0xb0, 0xd7, 0xd7, + 0x4e, 0x01, 0x6c, 0xcc, 0x26, 0xd2, 0x30, 0xf0, 0x29, 0x41, 0xef, 0xc0, 0x9a, 0xc8, 0xa4, 0xa9, + 0x9d, 0x25, 0x57, 0xbb, 0xab, 0x3a, 0xc7, 0xa7, 0x67, 0xd0, 0xf5, 0xf7, 0xfd, 0x23, 0xa3, 0x6a, + 0x5f, 0x17, 0x40, 0xab, 0xf0, 0x4e, 0x18, 0x05, 0xc1, 0xa0, 0xb1, 0xd0, 0x02, 0xed, 0x9a, 0xc1, + 0x7f, 0xa0, 0x1d, 0x58, 0x63, 0x1f, 0xbd, 0x21, 0x71, 0x9d, 0x61, 0xdc, 0x58, 0x64, 0xe5, 0x14, + 0x7d, 0x96, 0x62, 0x7d, 0x97, 0x45, 0x6c, 0x2f, 0x9d, 0xfd, 0xd5, 0xac, 0x18, 0x55, 0x96, 0xc5, + 0x4d, 0xda, 0xc1, 0x2c, 0x5e, 0x9a, 0x4d, 0xba, 0x05, 0xe1, 0xf5, 0x22, 0x04, 0x5a, 0x55, 0xf7, + 0xac, 0x91, 0x9e, 0x6e, 0x4b, 0xe7, 0x7b, 0x1d, 0xaf, 0xeb, 0xfb, 0xa6, 0x93, 0xb1, 0x63, 0xe4, + 0x32, 0xb4, 0xdf, 0x01, 0x7c, 0x2c, 0x29, 0x2e, 0xd8, 0xf0, 0xe1, 0xfd, 0x3c, 0x1b, 0xb4, 0x01, + 0x5a, 0x8b, 0xed, 0x6a, 0xf7, 0xb9, 0x0c, 0xff, 0x5e, 0x9f, 0xf8, 0xb1, 0x3b, 0x70, 0x49, 0x3f, + 0x57, 0x6a, 0x5b, 0x4d, 0xc7, 0xf9, 0xe9, 0xa2, 0xf9, 0xaa, 0xd4, 0x4d, 0x8d, 0x5a, 0x8e, 0x43, + 0x8a, 0xde, 0x2b, 0x4c, 0xb3, 0xc0, 0xa6, 0x69, 0xce, 0x9d, 0x86, 0x83, 0x2c, 0x8c, 0xf3, 0x33, + 0x80, 0x0a, 0x1f, 0x27, 0x75, 0xf9, 0x34, 0xa1, 0xa5, 0x75, 0x81, 0xde, 0x80, 0xf5, 0x88, 0x8c, + 0x5d, 0xea, 0x06, 0x7e, 0xcf, 0x4f, 0x46, 0x16, 0x89, 0x18, 0x82, 0x25, 0x63, 0x25, 0x33, 0x7f, + 0xc8, 0xac, 0x85, 0xc0, 0xdc, 0x5e, 0x73, 0x81, 0x7c, 0x71, 0xe8, 0x19, 0xbc, 0xef, 0xa5, 0x73, + 0xc5, 0x59, 0xd8, 0x52, 0x0b, 0xb4, 0x97, 0x8d, 0x1a, 0x37, 0x8a, 0xed, 0xfe, 0x02, 0xe0, 0x13, + 0x29, 0x64, 0xb1, 0x83, 0x77, 0x61, 0xdd, 0xce, 0x3c, 0x25, 0x44, 0xb9, 0x62, 0x17, 0xca, 0xfc, + 0x9f, 0xba, 0xfc, 0x4a, 0x0a, 0x9c, 0x96, 0x22, 0x7b, 0x4b, 0xb2, 0xe9, 0xdb, 0xe8, 0xf6, 0x57, + 0x00, 0x9f, 0xca, 0x9b, 0x0b, 0xda, 0x3e, 0x87, 0xaf, 0x4c, 0xd1, 0x96, 0xa9, 0xf7, 0x85, 0x6c, + 0xca, 0x62, 0x99, 0xcf, 0xdc, 0x78, 0x58, 0x98, 0xbb, 0x5e, 0x64, 0xf5, 0x3f, 0x50, 0xaa, 0x52, + 0x78, 0xd4, 0xfb, 0x66, 0x64, 0x8e, 0x32, 0xe6, 0xb4, 0x8f, 0x0a, 0x6f, 0x32, 0xf3, 0x89, 0xc1, + 0xba, 0xf0, 0x6e, 0xc8, 0x2c, 0x42, 0x06, 0xd2, 0xa5, 0x89, 0x1c, 0x11, 0xa9, 0xf5, 0x60, 0x93, + 0x15, 0xfc, 0x34, 0x74, 0x22, 0xb3, 0x5f, 0x78, 0x82, 0xa5, 0xb6, 0xd5, 0x84, 0xd5, 0xd0, 0x33, + 0x27, 0x6a, 0x4f, 0xc7, 0x5d, 0x34, 0x60, 0x6a, 0x12, 0x52, 0xf0, 0x60, 0x6b, 0x7e, 0x03, 0x01, + 0x7c, 0x17, 0x3e, 0x4c, 0x84, 0xbb, 0x57, 0xfa, 0xc6, 0x3e, 0x48, 0x66, 0x2b, 0x76, 0x7f, 0x5c, + 0x86, 0x77, 0x58, 0x3b, 0xf4, 0x03, 0x80, 0xd5, 0x9c, 0x07, 0xbd, 0x29, 0x23, 0x63, 0xce, 0xbf, + 0x84, 0xf2, 0xa2, 0x5c, 0x30, 0x87, 0xaf, 0xbd, 0xfd, 0xf5, 0x1f, 0xff, 0x7c, 0xb7, 0x80, 0x51, + 0x07, 0xcf, 0xfd, 0x9f, 0x13, 0x3a, 0xc3, 0xc7, 0x13, 0x26, 0x4f, 0xd0, 0xf7, 0x00, 0xd6, 0xf2, + 0x17, 0x0f, 0x95, 0xea, 0x9a, 0x49, 0x41, 0xe9, 0x94, 0x8c, 0x16, 0x20, 0x9f, 0x33, 0x90, 0xcf, + 0xd0, 0xeb, 0x37, 0x82, 0x44, 0x17, 0x00, 0xae, 0x14, 0x55, 0x8f, 0xf4, 0xf9, 0xcd, 0x64, 0xe7, + 0x54, 0xc1, 0xa5, 0xe3, 0x05, 0x3c, 0x8f, 0xc1, 0x1b, 0xa0, 0xbe, 0x14, 0xde, 0xd4, 0x73, 0xcd, + 0xd3, 0x88, 0xb3, 0xcb, 0x8a, 0x8f, 0xa7, 0x6e, 0xf4, 0x09, 0xe6, 0xa2, 0xcc, 0x39, 0xb8, 0xe1, + 0x04, 0x9d, 0x02, 0x58, 0x9f, 0x3a, 0x0f, 0xa8, 0x2c, 0xe4, 0xc9, 0x02, 0xd6, 0xca, 0x27, 0x88, + 0x21, 0x37, 0xd9, 0x90, 0x5d, 0xb4, 0x76, 0xdb, 0x21, 0xd1, 0x37, 0x13, 0xad, 0xf0, 0xf7, 0x7b, + 0xa3, 0x56, 0x0a, 0x67, 0xe3, 0x46, 0xad, 0x14, 0x0f, 0x89, 0xf6, 0x1a, 0xc3, 0xf9, 0x08, 0x3d, + 0xe4, 0x38, 0x27, 0x10, 0xf9, 0xcd, 0x40, 0xbf, 0x01, 0xf8, 0x40, 0xf2, 0x9c, 0xd1, 0xcb, 0xb9, + 0x5d, 0xe6, 0x5f, 0x17, 0xe5, 0xad, 0xdb, 0x25, 0x09, 0x84, 0x5b, 0x0c, 0xe1, 0x26, 0xda, 0x90, + 0x31, 0x29, 0xbd, 0x25, 0x05, 0x3e, 0xb7, 0x3f, 0x38, 0xbb, 0x54, 0xc1, 0xf9, 0xa5, 0x0a, 0xfe, + 0xbe, 0x54, 0xc1, 0xb7, 0x57, 0x6a, 0xe5, 0xfc, 0x4a, 0xad, 0xfc, 0x79, 0xa5, 0x56, 0x0e, 0xba, + 0x8e, 0x1b, 0x0f, 0x13, 0x4b, 0xb7, 0x83, 0x11, 0xf6, 0x5c, 0x9f, 0x60, 0xcf, 0x1a, 0x75, 0x68, + 0xff, 0x0b, 0xfc, 0xe5, 0x75, 0xab, 0xb5, 0x6e, 0x47, 0x74, 0x8b, 0x8f, 0x42, 0x42, 0xad, 0xbb, + 0xec, 0x30, 0xbd, 0xfc, 0x37, 0x00, 0x00, 0xff, 0xff, 0xe1, 0xf2, 0x3a, 0xdf, 0x40, 0x0b, 0x00, + 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -677,6 +789,8 @@ type QueryClient interface { ConsensusStates(ctx context.Context, in *QueryConsensusStatesRequest, opts ...grpc.CallOption) (*QueryConsensusStatesResponse, error) // ClientParams queries all parameters of the ibc client. ClientParams(ctx context.Context, in *QueryClientParamsRequest, opts ...grpc.CallOption) (*QueryClientParamsResponse, error) + // UpgradedClientState queries an Upgraded IBC light client. + UpgradedClientState(ctx context.Context, in *QueryUpgradedClientStateRequest, opts ...grpc.CallOption) (*QueryUpgradedClientStateResponse, error) } type queryClient struct { @@ -732,6 +846,15 @@ func (c *queryClient) ClientParams(ctx context.Context, in *QueryClientParamsReq return out, nil } +func (c *queryClient) UpgradedClientState(ctx context.Context, in *QueryUpgradedClientStateRequest, opts ...grpc.CallOption) (*QueryUpgradedClientStateResponse, error) { + out := new(QueryUpgradedClientStateResponse) + err := c.cc.Invoke(ctx, "/ibc.core.client.v1.Query/UpgradedClientState", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + // QueryServer is the server API for Query service. type QueryServer interface { // ClientState queries an IBC light client. @@ -746,6 +869,8 @@ type QueryServer interface { ConsensusStates(context.Context, *QueryConsensusStatesRequest) (*QueryConsensusStatesResponse, error) // ClientParams queries all parameters of the ibc client. ClientParams(context.Context, *QueryClientParamsRequest) (*QueryClientParamsResponse, error) + // UpgradedClientState queries an Upgraded IBC light client. + UpgradedClientState(context.Context, *QueryUpgradedClientStateRequest) (*QueryUpgradedClientStateResponse, error) } // UnimplementedQueryServer can be embedded to have forward compatible implementations. @@ -767,6 +892,9 @@ func (*UnimplementedQueryServer) ConsensusStates(ctx context.Context, req *Query func (*UnimplementedQueryServer) ClientParams(ctx context.Context, req *QueryClientParamsRequest) (*QueryClientParamsResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method ClientParams not implemented") } +func (*UnimplementedQueryServer) UpgradedClientState(ctx context.Context, req *QueryUpgradedClientStateRequest) (*QueryUpgradedClientStateResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method UpgradedClientState not implemented") +} func RegisterQueryServer(s grpc1.Server, srv QueryServer) { s.RegisterService(&_Query_serviceDesc, srv) @@ -862,6 +990,24 @@ func _Query_ClientParams_Handler(srv interface{}, ctx context.Context, dec func( return interceptor(ctx, in, info, handler) } +func _Query_UpgradedClientState_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryUpgradedClientStateRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).UpgradedClientState(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/ibc.core.client.v1.Query/UpgradedClientState", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).UpgradedClientState(ctx, req.(*QueryUpgradedClientStateRequest)) + } + return interceptor(ctx, in, info, handler) +} + var _Query_serviceDesc = grpc.ServiceDesc{ ServiceName: "ibc.core.client.v1.Query", HandlerType: (*QueryServer)(nil), @@ -886,6 +1032,10 @@ var _Query_serviceDesc = grpc.ServiceDesc{ MethodName: "ClientParams", Handler: _Query_ClientParams_Handler, }, + { + MethodName: "UpgradedClientState", + Handler: _Query_UpgradedClientState_Handler, + }, }, Streams: []grpc.StreamDesc{}, Metadata: "ibc/core/client/v1/query.proto", @@ -1308,6 +1458,76 @@ func (m *QueryClientParamsResponse) MarshalToSizedBuffer(dAtA []byte) (int, erro return len(dAtA) - i, nil } +func (m *QueryUpgradedClientStateRequest) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryUpgradedClientStateRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryUpgradedClientStateRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.PlanHeight != 0 { + i = encodeVarintQuery(dAtA, i, uint64(m.PlanHeight)) + i-- + dAtA[i] = 0x10 + } + if len(m.ClientId) > 0 { + i -= len(m.ClientId) + copy(dAtA[i:], m.ClientId) + i = encodeVarintQuery(dAtA, i, uint64(len(m.ClientId))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *QueryUpgradedClientStateResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryUpgradedClientStateResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryUpgradedClientStateResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.UpgradedClientState != nil { + { + size, err := m.UpgradedClientState.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + func encodeVarintQuery(dAtA []byte, offset int, v uint64) int { offset -= sovQuery(v) base := offset @@ -1482,6 +1702,35 @@ func (m *QueryClientParamsResponse) Size() (n int) { return n } +func (m *QueryUpgradedClientStateRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.ClientId) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + if m.PlanHeight != 0 { + n += 1 + sovQuery(uint64(m.PlanHeight)) + } + return n +} + +func (m *QueryUpgradedClientStateResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.UpgradedClientState != nil { + l = m.UpgradedClientState.Size() + n += 1 + l + sovQuery(uint64(l)) + } + return n +} + func sovQuery(x uint64) (n int) { return (math_bits.Len64(x|1) + 6) / 7 } @@ -2596,6 +2845,193 @@ func (m *QueryClientParamsResponse) Unmarshal(dAtA []byte) error { } return nil } +func (m *QueryUpgradedClientStateRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryUpgradedClientStateRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryUpgradedClientStateRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ClientId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ClientId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field PlanHeight", wireType) + } + m.PlanHeight = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.PlanHeight |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryUpgradedClientStateResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryUpgradedClientStateResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryUpgradedClientStateResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field UpgradedClientState", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.UpgradedClientState == nil { + m.UpgradedClientState = &types.Any{} + } + if err := m.UpgradedClientState.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func skipQuery(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 diff --git a/x/ibc/core/02-client/types/query.pb.gw.go b/x/ibc/core/02-client/types/query.pb.gw.go index 5c5d5a31fc..5f7f89384d 100644 --- a/x/ibc/core/02-client/types/query.pb.gw.go +++ b/x/ibc/core/02-client/types/query.pb.gw.go @@ -327,6 +327,78 @@ func local_request_Query_ClientParams_0(ctx context.Context, marshaler runtime.M } +var ( + filter_Query_UpgradedClientState_0 = &utilities.DoubleArray{Encoding: map[string]int{"client_id": 0}, Base: []int{1, 1, 0}, Check: []int{0, 1, 2}} +) + +func request_Query_UpgradedClientState_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryUpgradedClientStateRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["client_id"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "client_id") + } + + protoReq.ClientId, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "client_id", err) + } + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_UpgradedClientState_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := client.UpgradedClientState(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_UpgradedClientState_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryUpgradedClientStateRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["client_id"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "client_id") + } + + protoReq.ClientId, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "client_id", err) + } + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_UpgradedClientState_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := server.UpgradedClientState(ctx, &protoReq) + return msg, metadata, err + +} + // RegisterQueryHandlerServer registers the http handlers for service Query to "mux". // UnaryRPC :call QueryServer directly. // StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906. @@ -433,6 +505,26 @@ func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, serv }) + mux.Handle("GET", pattern_Query_UpgradedClientState_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_Query_UpgradedClientState_0(rctx, inboundMarshaler, server, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_UpgradedClientState_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + return nil } @@ -574,19 +666,41 @@ func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, clie }) + mux.Handle("GET", pattern_Query_UpgradedClientState_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_Query_UpgradedClientState_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_UpgradedClientState_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + return nil } var ( - pattern_Query_ClientState_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 1, 0, 4, 1, 5, 5}, []string{"ibc", "core", "client", "v1", "client_states", "client_id"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_Query_ClientState_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 1, 0, 4, 1, 5, 5}, []string{"ibc", "core", "client", "v1", "client_states", "client_id"}, "", runtime.AssumeColonVerbOpt(false))) + + pattern_Query_ClientStates_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4}, []string{"ibc", "core", "client", "v1", "client_states"}, "", runtime.AssumeColonVerbOpt(false))) - pattern_Query_ClientStates_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4}, []string{"ibc", "core", "client", "v1", "client_states"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_Query_ConsensusState_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 1, 0, 4, 1, 5, 5, 2, 6, 1, 0, 4, 1, 5, 7, 2, 8, 1, 0, 4, 1, 5, 9}, []string{"ibc", "core", "client", "v1", "consensus_states", "client_id", "revision", "revision_number", "height", "revision_height"}, "", runtime.AssumeColonVerbOpt(false))) - pattern_Query_ConsensusState_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 1, 0, 4, 1, 5, 5, 2, 6, 1, 0, 4, 1, 5, 7, 2, 8, 1, 0, 4, 1, 5, 9}, []string{"ibc", "core", "client", "v1", "consensus_states", "client_id", "revision", "revision_number", "height", "revision_height"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_Query_ConsensusStates_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 1, 0, 4, 1, 5, 5}, []string{"ibc", "core", "client", "v1", "consensus_states", "client_id"}, "", runtime.AssumeColonVerbOpt(false))) - pattern_Query_ConsensusStates_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 1, 0, 4, 1, 5, 5}, []string{"ibc", "core", "client", "v1", "consensus_states", "client_id"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_Query_ClientParams_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"ibc", "client", "v1", "params"}, "", runtime.AssumeColonVerbOpt(false))) - pattern_Query_ClientParams_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"ibc", "client", "v1", "params"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_Query_UpgradedClientState_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 1, 0, 4, 1, 5, 5}, []string{"ibc", "core", "client", "v1", "upgraded_client_states", "client_id"}, "", runtime.AssumeColonVerbOpt(false))) ) var ( @@ -599,4 +713,6 @@ var ( forward_Query_ConsensusStates_0 = runtime.ForwardResponseMessage forward_Query_ClientParams_0 = runtime.ForwardResponseMessage + + forward_Query_UpgradedClientState_0 = runtime.ForwardResponseMessage ) diff --git a/x/ibc/core/03-connection/client/cli/query.go b/x/ibc/core/03-connection/client/cli/query.go index 3195386920..1bae81d017 100644 --- a/x/ibc/core/03-connection/client/cli/query.go +++ b/x/ibc/core/03-connection/client/cli/query.go @@ -1,7 +1,6 @@ package cli import ( - "context" "fmt" "github.com/spf13/cobra" @@ -39,7 +38,7 @@ func GetCmdQueryConnections() *cobra.Command { Pagination: pageReq, } - res, err := queryClient.Connections(context.Background(), req) + res, err := queryClient.Connections(cmd.Context(), req) if err != nil { return err } diff --git a/x/ibc/core/03-connection/client/cli/tx.go b/x/ibc/core/03-connection/client/cli/tx.go index 63003bdcb0..f58acff973 100644 --- a/x/ibc/core/03-connection/client/cli/tx.go +++ b/x/ibc/core/03-connection/client/cli/tx.go @@ -76,10 +76,6 @@ func NewConnectionOpenInitCmd() *cobra.Command { counterpartyPrefix, version, delayPeriod, clientCtx.GetFromAddress(), ) - if err := msg.ValidateBasic(); err != nil { - return err - } - return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) }, } @@ -189,10 +185,6 @@ func NewConnectionOpenTryCmd() *cobra.Command { consensusHeight, clientCtx.GetFromAddress(), ) - if err := msg.ValidateBasic(); err != nil { - return err - } - return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) }, } @@ -276,10 +268,6 @@ func NewConnectionOpenAckCmd() *cobra.Command { consensusHeight, version, clientCtx.GetFromAddress(), ) - if err := msg.ValidateBasic(); err != nil { - return err - } - return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) }, } @@ -321,10 +309,6 @@ func NewConnectionOpenConfirmCmd() *cobra.Command { connectionID, proofAck, proofHeight, clientCtx.GetFromAddress(), ) - if err := msg.ValidateBasic(); err != nil { - return err - } - return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) }, } diff --git a/x/ibc/core/03-connection/client/utils/utils.go b/x/ibc/core/03-connection/client/utils/utils.go index cb5ac94162..4a64f5fb66 100644 --- a/x/ibc/core/03-connection/client/utils/utils.go +++ b/x/ibc/core/03-connection/client/utils/utils.go @@ -53,7 +53,7 @@ func queryConnectionABCI(clientCtx client.Context, connectionID string) (*types. cdc := codec.NewProtoCodec(clientCtx.InterfaceRegistry) var connection types.ConnectionEnd - if err := cdc.UnmarshalBinaryBare(value, &connection); err != nil { + if err := cdc.Unmarshal(value, &connection); err != nil { return nil, err } @@ -92,7 +92,7 @@ func queryClientConnectionsABCI(clientCtx client.Context, clientID string) (*typ } var paths []string - if err := clientCtx.LegacyAmino.UnmarshalBinaryBare(value, &paths); err != nil { + if err := clientCtx.LegacyAmino.Unmarshal(value, &paths); err != nil { return nil, err } @@ -215,5 +215,5 @@ func ParseProof(cdc *codec.LegacyAmino, arg string) ([]byte, error) { } } - return cdc.MarshalBinaryBare(&merkleProof) + return cdc.Marshal(&merkleProof) } diff --git a/x/ibc/core/03-connection/keeper/grpc_query.go b/x/ibc/core/03-connection/keeper/grpc_query.go index f7720a1334..66873c5f7e 100644 --- a/x/ibc/core/03-connection/keeper/grpc_query.go +++ b/x/ibc/core/03-connection/keeper/grpc_query.go @@ -55,7 +55,7 @@ func (q Keeper) Connections(c context.Context, req *types.QueryConnectionsReques pageRes, err := query.Paginate(store, req.Pagination, func(key, value []byte) error { var result types.ConnectionEnd - if err := q.cdc.UnmarshalBinaryBare(value, &result); err != nil { + if err := q.cdc.Unmarshal(value, &result); err != nil { return err } diff --git a/x/ibc/core/03-connection/keeper/keeper.go b/x/ibc/core/03-connection/keeper/keeper.go index 4db7fbc410..520d7a0bb7 100644 --- a/x/ibc/core/03-connection/keeper/keeper.go +++ b/x/ibc/core/03-connection/keeper/keeper.go @@ -19,12 +19,12 @@ type Keeper struct { types.QueryServer storeKey sdk.StoreKey - cdc codec.BinaryMarshaler + cdc codec.Codec clientKeeper types.ClientKeeper } // NewKeeper creates a new IBC connection Keeper instance -func NewKeeper(cdc codec.BinaryMarshaler, key sdk.StoreKey, ck types.ClientKeeper) Keeper { +func NewKeeper(cdc codec.Codec, key sdk.StoreKey, ck types.ClientKeeper) Keeper { return Keeper{ storeKey: key, cdc: cdc, @@ -62,7 +62,7 @@ func (k Keeper) GetConnection(ctx sdk.Context, connectionID string) (types.Conne } var connection types.ConnectionEnd - k.cdc.MustUnmarshalBinaryBare(bz, &connection) + k.cdc.MustUnmarshal(bz, &connection) return connection, true } @@ -70,7 +70,7 @@ func (k Keeper) GetConnection(ctx sdk.Context, connectionID string) (types.Conne // SetConnection sets a connection to the store func (k Keeper) SetConnection(ctx sdk.Context, connectionID string, connection types.ConnectionEnd) { store := ctx.KVStore(k.storeKey) - bz := k.cdc.MustMarshalBinaryBare(&connection) + bz := k.cdc.MustMarshal(&connection) store.Set(host.ConnectionKey(connectionID), bz) } @@ -101,7 +101,7 @@ func (k Keeper) GetClientConnectionPaths(ctx sdk.Context, clientID string) ([]st } var clientPaths types.ClientPaths - k.cdc.MustUnmarshalBinaryBare(bz, &clientPaths) + k.cdc.MustUnmarshal(bz, &clientPaths) return clientPaths.Paths, true } @@ -109,7 +109,7 @@ func (k Keeper) GetClientConnectionPaths(ctx sdk.Context, clientID string) ([]st func (k Keeper) SetClientConnectionPaths(ctx sdk.Context, clientID string, paths []string) { store := ctx.KVStore(k.storeKey) clientPaths := types.ClientPaths{Paths: paths} - bz := k.cdc.MustMarshalBinaryBare(&clientPaths) + bz := k.cdc.MustMarshal(&clientPaths) store.Set(host.ClientConnectionsKey(clientID), bz) } @@ -160,7 +160,7 @@ func (k Keeper) IterateConnections(ctx sdk.Context, cb func(types.IdentifiedConn defer iterator.Close() for ; iterator.Valid(); iterator.Next() { var connection types.ConnectionEnd - k.cdc.MustUnmarshalBinaryBare(iterator.Value(), &connection) + k.cdc.MustUnmarshal(iterator.Value(), &connection) connectionID := host.MustParseConnectionPath(string(iterator.Key())) identifiedConnection := types.NewIdentifiedConnection(connectionID, connection) diff --git a/x/ibc/core/03-connection/simulation/decoder.go b/x/ibc/core/03-connection/simulation/decoder.go index 44016d0ffa..215e4d4f69 100644 --- a/x/ibc/core/03-connection/simulation/decoder.go +++ b/x/ibc/core/03-connection/simulation/decoder.go @@ -12,18 +12,18 @@ import ( // NewDecodeStore returns a decoder function closure that unmarshals the KVPair's // Value to the corresponding connection type. -func NewDecodeStore(cdc codec.BinaryMarshaler, kvA, kvB kv.Pair) (string, bool) { +func NewDecodeStore(cdc codec.Codec, kvA, kvB kv.Pair) (string, bool) { switch { case bytes.HasPrefix(kvA.Key, host.KeyClientStorePrefix) && bytes.HasSuffix(kvA.Key, []byte(host.KeyConnectionPrefix)): var clientConnectionsA, clientConnectionsB types.ClientPaths - cdc.MustUnmarshalBinaryBare(kvA.Value, &clientConnectionsA) - cdc.MustUnmarshalBinaryBare(kvB.Value, &clientConnectionsB) + cdc.MustUnmarshal(kvA.Value, &clientConnectionsA) + cdc.MustUnmarshal(kvB.Value, &clientConnectionsB) return fmt.Sprintf("ClientPaths A: %v\nClientPaths B: %v", clientConnectionsA, clientConnectionsB), true case bytes.HasPrefix(kvA.Key, []byte(host.KeyConnectionPrefix)): var connectionA, connectionB types.ConnectionEnd - cdc.MustUnmarshalBinaryBare(kvA.Value, &connectionA) - cdc.MustUnmarshalBinaryBare(kvB.Value, &connectionB) + cdc.MustUnmarshal(kvA.Value, &connectionA) + cdc.MustUnmarshal(kvB.Value, &connectionB) return fmt.Sprintf("ConnectionEnd A: %v\nConnectionEnd B: %v", connectionA, connectionB), true default: diff --git a/x/ibc/core/03-connection/simulation/decoder_test.go b/x/ibc/core/03-connection/simulation/decoder_test.go index e4f566656b..be639523bf 100644 --- a/x/ibc/core/03-connection/simulation/decoder_test.go +++ b/x/ibc/core/03-connection/simulation/decoder_test.go @@ -32,11 +32,11 @@ func TestDecodeStore(t *testing.T) { Pairs: []kv.Pair{ { Key: host.ClientConnectionsKey(connection.ClientId), - Value: cdc.MustMarshalBinaryBare(&paths), + Value: cdc.MustMarshal(&paths), }, { Key: host.ConnectionKey(connectionID), - Value: cdc.MustMarshalBinaryBare(&connection), + Value: cdc.MustMarshal(&connection), }, { Key: []byte{0x99}, diff --git a/x/ibc/core/03-connection/types/msgs_test.go b/x/ibc/core/03-connection/types/msgs_test.go index 1a82a721fd..82dd77c349 100644 --- a/x/ibc/core/03-connection/types/msgs_test.go +++ b/x/ibc/core/03-connection/types/msgs_test.go @@ -65,7 +65,7 @@ func (suite *MsgTestSuite) SetupTest() { merkleProof, err := commitmenttypes.ConvertProofs(res.ProofOps) suite.Require().NoError(err) - proof, err := app.AppCodec().MarshalBinaryBare(&merkleProof) + proof, err := app.AppCodec().Marshal(&merkleProof) suite.Require().NoError(err) suite.proof = proof @@ -139,7 +139,7 @@ func (suite *MsgTestSuite) TestNewMsgConnectionOpenTry() { {"invalid counterparty client ID", types.NewMsgConnectionOpenTry(connectionID, "clienttotesta", "connectiontotest", "test/conn1", clientState, prefix, []*types.Version{ibctesting.ConnectionVersion}, 500, suite.proof, suite.proof, suite.proof, clientHeight, clientHeight, signer), false}, {"invalid nil counterparty client", types.NewMsgConnectionOpenTry(connectionID, "clienttotesta", "connectiontotest", "clienttotest", nil, prefix, []*types.Version{ibctesting.ConnectionVersion}, 500, suite.proof, suite.proof, suite.proof, clientHeight, clientHeight, signer), false}, {"invalid client unpacking", &types.MsgConnectionOpenTry{connectionID, "clienttotesta", invalidAny, counterparty, 500, []*types.Version{ibctesting.ConnectionVersion}, clientHeight, suite.proof, suite.proof, suite.proof, clientHeight, signer.String()}, false}, - {"counterparty failed Validate", types.NewMsgConnectionOpenTry(connectionID, "clienttotesta", "connectiontotest", "clienttotest", invalidClient, prefix, []*types.Version{ibctesting.ConnectionVersion}, 500, suite.proof, suite.proof, suite.proof, clientHeight, clientHeight, signer), false}, + {"counterparty failed validate", types.NewMsgConnectionOpenTry(connectionID, "clienttotesta", "connectiontotest", "clienttotest", invalidClient, prefix, []*types.Version{ibctesting.ConnectionVersion}, 500, suite.proof, suite.proof, suite.proof, clientHeight, clientHeight, signer), false}, {"empty counterparty prefix", types.NewMsgConnectionOpenTry(connectionID, "clienttotesta", "connectiontotest", "clienttotest", clientState, emptyPrefix, []*types.Version{ibctesting.ConnectionVersion}, 500, suite.proof, suite.proof, suite.proof, clientHeight, clientHeight, signer), false}, {"empty counterpartyVersions", types.NewMsgConnectionOpenTry(connectionID, "clienttotesta", "connectiontotest", "clienttotest", clientState, prefix, []*types.Version{}, 500, suite.proof, suite.proof, suite.proof, clientHeight, clientHeight, signer), false}, {"empty proofInit", types.NewMsgConnectionOpenTry(connectionID, "clienttotesta", "connectiontotest", "clienttotest", clientState, prefix, []*types.Version{ibctesting.ConnectionVersion}, 500, emptyProof, suite.proof, suite.proof, clientHeight, clientHeight, signer), false}, @@ -189,7 +189,7 @@ func (suite *MsgTestSuite) TestNewMsgConnectionOpenAck() { {"invalid counterparty connection ID", types.NewMsgConnectionOpenAck(connectionID, "test/conn1", clientState, suite.proof, suite.proof, suite.proof, clientHeight, clientHeight, ibctesting.ConnectionVersion, signer), false}, {"invalid nil counterparty client", types.NewMsgConnectionOpenAck(connectionID, connectionID, nil, suite.proof, suite.proof, suite.proof, clientHeight, clientHeight, ibctesting.ConnectionVersion, signer), false}, {"invalid unpacking counterparty client", &types.MsgConnectionOpenAck{connectionID, connectionID, ibctesting.ConnectionVersion, invalidAny, clientHeight, suite.proof, suite.proof, suite.proof, clientHeight, signer.String()}, false}, - {"counterparty client failed Validate", types.NewMsgConnectionOpenAck(connectionID, connectionID, invalidClient, suite.proof, suite.proof, suite.proof, clientHeight, clientHeight, ibctesting.ConnectionVersion, signer), false}, + {"counterparty client failed validate", types.NewMsgConnectionOpenAck(connectionID, connectionID, invalidClient, suite.proof, suite.proof, suite.proof, clientHeight, clientHeight, ibctesting.ConnectionVersion, signer), false}, {"empty proofTry", types.NewMsgConnectionOpenAck(connectionID, connectionID, clientState, emptyProof, suite.proof, suite.proof, clientHeight, clientHeight, ibctesting.ConnectionVersion, signer), false}, {"empty proofClient", types.NewMsgConnectionOpenAck(connectionID, connectionID, clientState, suite.proof, emptyProof, suite.proof, clientHeight, clientHeight, ibctesting.ConnectionVersion, signer), false}, {"empty proofConsensus", types.NewMsgConnectionOpenAck(connectionID, connectionID, clientState, suite.proof, suite.proof, emptyProof, clientHeight, clientHeight, ibctesting.ConnectionVersion, signer), false}, diff --git a/x/ibc/core/03-connection/types/query.go b/x/ibc/core/03-connection/types/query.go index b99eeb55f5..fe93659ed9 100644 --- a/x/ibc/core/03-connection/types/query.go +++ b/x/ibc/core/03-connection/types/query.go @@ -11,6 +11,11 @@ var ( _ codectypes.UnpackInterfacesMessage = QueryConnectionConsensusStateResponse{} ) +var ( + _ codectypes.UnpackInterfacesMessage = QueryConnectionClientStateResponse{} + _ codectypes.UnpackInterfacesMessage = QueryConnectionConsensusStateResponse{} +) + // NewQueryConnectionResponse creates a new QueryConnectionResponse instance func NewQueryConnectionResponse( connection ConnectionEnd, proof []byte, height clienttypes.Height, diff --git a/x/ibc/core/03-connection/types/query.pb.gw.go b/x/ibc/core/03-connection/types/query.pb.gw.go index 2de52353c7..8204d080e4 100644 --- a/x/ibc/core/03-connection/types/query.pb.gw.go +++ b/x/ibc/core/03-connection/types/query.pb.gw.go @@ -578,15 +578,15 @@ func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, clie } var ( - pattern_Query_Connection_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 1, 0, 4, 1, 5, 5}, []string{"ibc", "core", "connection", "v1", "connections", "connection_id"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_Query_Connection_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 1, 0, 4, 1, 5, 5}, []string{"ibc", "core", "connection", "v1", "connections", "connection_id"}, "", runtime.AssumeColonVerbOpt(false))) - pattern_Query_Connections_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4}, []string{"ibc", "core", "connection", "v1", "connections"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_Query_Connections_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4}, []string{"ibc", "core", "connection", "v1", "connections"}, "", runtime.AssumeColonVerbOpt(false))) - pattern_Query_ClientConnections_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 1, 0, 4, 1, 5, 5}, []string{"ibc", "core", "connection", "v1", "client_connections", "client_id"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_Query_ClientConnections_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 1, 0, 4, 1, 5, 5}, []string{"ibc", "core", "connection", "v1", "client_connections", "client_id"}, "", runtime.AssumeColonVerbOpt(false))) - pattern_Query_ConnectionClientState_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 1, 0, 4, 1, 5, 5, 2, 6}, []string{"ibc", "core", "connection", "v1", "connections", "connection_id", "client_state"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_Query_ConnectionClientState_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 1, 0, 4, 1, 5, 5, 2, 6}, []string{"ibc", "core", "connection", "v1", "connections", "connection_id", "client_state"}, "", runtime.AssumeColonVerbOpt(false))) - pattern_Query_ConnectionConsensusState_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 1, 0, 4, 1, 5, 5, 2, 6, 2, 7, 1, 0, 4, 1, 5, 8, 2, 9, 1, 0, 4, 1, 5, 10}, []string{"ibc", "core", "connection", "v1", "connections", "connection_id", "consensus_state", "revision", "revision_number", "height", "revision_height"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_Query_ConnectionConsensusState_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 1, 0, 4, 1, 5, 5, 2, 6, 2, 7, 1, 0, 4, 1, 5, 8, 2, 9, 1, 0, 4, 1, 5, 10}, []string{"ibc", "core", "connection", "v1", "connections", "connection_id", "consensus_state", "revision", "revision_number", "height", "revision_height"}, "", runtime.AssumeColonVerbOpt(false))) ) var ( diff --git a/x/ibc/core/04-channel/client/cli/query.go b/x/ibc/core/04-channel/client/cli/query.go index 8ee21448d4..afca388d14 100644 --- a/x/ibc/core/04-channel/client/cli/query.go +++ b/x/ibc/core/04-channel/client/cli/query.go @@ -1,7 +1,6 @@ package cli import ( - "context" "fmt" "strconv" @@ -44,7 +43,7 @@ func GetCmdQueryChannels() *cobra.Command { Pagination: pageReq, } - res, err := queryClient.Channels(context.Background(), req) + res, err := queryClient.Channels(cmd.Context(), req) if err != nil { return err } @@ -118,7 +117,7 @@ func GetCmdQueryConnectionChannels() *cobra.Command { Pagination: pageReq, } - res, err := queryClient.ConnectionChannels(context.Background(), req) + res, err := queryClient.ConnectionChannels(cmd.Context(), req) if err != nil { return err } @@ -189,7 +188,7 @@ func GetCmdQueryPacketCommitments() *cobra.Command { Pagination: pageReq, } - res, err := queryClient.PacketCommitments(context.Background(), req) + res, err := queryClient.PacketCommitments(cmd.Context(), req) if err != nil { return err } @@ -357,7 +356,7 @@ The return value represents: PacketCommitmentSequences: seqs, } - res, err := queryClient.UnreceivedPackets(context.Background(), req) + res, err := queryClient.UnreceivedPackets(cmd.Context(), req) if err != nil { return err } @@ -407,7 +406,7 @@ The return value represents: PacketAckSequences: seqs, } - res, err := queryClient.UnreceivedAcks(context.Background(), req) + res, err := queryClient.UnreceivedAcks(cmd.Context(), req) if err != nil { return err } diff --git a/x/ibc/core/04-channel/client/cli/tx.go b/x/ibc/core/04-channel/client/cli/tx.go index 4118dd7d87..f29bff0b78 100644 --- a/x/ibc/core/04-channel/client/cli/tx.go +++ b/x/ibc/core/04-channel/client/cli/tx.go @@ -42,9 +42,6 @@ func NewChannelOpenInitCmd() *cobra.Command { portID, version, order, hops, counterpartyPortID, clientCtx.GetFromAddress(), ) - if err := msg.ValidateBasic(); err != nil { - return err - } return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) }, @@ -93,9 +90,6 @@ func NewChannelOpenTryCmd() *cobra.Command { counterpartyPortID, counterpartyChannelID, version, proofInit, proofHeight, clientCtx.GetFromAddress(), ) - if err := msg.ValidateBasic(); err != nil { - return err - } return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) }, @@ -139,9 +133,6 @@ func NewChannelOpenAckCmd() *cobra.Command { msg := types.NewMsgChannelOpenAck( portID, channelID, counterpartyChannelID, version, proofTry, proofHeight, clientCtx.GetFromAddress(), ) - if err := msg.ValidateBasic(); err != nil { - return err - } return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) }, @@ -179,9 +170,6 @@ func NewChannelOpenConfirmCmd() *cobra.Command { msg := types.NewMsgChannelOpenConfirm( portID, channelID, proofAck, proofHeight, clientCtx.GetFromAddress(), ) - if err := msg.ValidateBasic(); err != nil { - return err - } return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) }, @@ -207,9 +195,6 @@ func NewChannelCloseInitCmd() *cobra.Command { channelID := args[1] msg := types.NewMsgChannelCloseInit(portID, channelID, clientCtx.GetFromAddress()) - if err := msg.ValidateBasic(); err != nil { - return err - } return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) }, @@ -247,9 +232,6 @@ func NewChannelCloseConfirmCmd() *cobra.Command { msg := types.NewMsgChannelCloseConfirm( portID, channelID, proofInit, proofHeight, clientCtx.GetFromAddress(), ) - if err := msg.ValidateBasic(); err != nil { - return err - } return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) }, diff --git a/x/ibc/core/04-channel/client/utils/utils.go b/x/ibc/core/04-channel/client/utils/utils.go index cd58c8b3de..2f29a860a5 100644 --- a/x/ibc/core/04-channel/client/utils/utils.go +++ b/x/ibc/core/04-channel/client/utils/utils.go @@ -50,7 +50,7 @@ func queryChannelABCI(clientCtx client.Context, portID, channelID string) (*type cdc := codec.NewProtoCodec(clientCtx.InterfaceRegistry) var channel types.Channel - if err := cdc.UnmarshalBinaryBare(value, &channel); err != nil { + if err := cdc.Unmarshal(value, &channel); err != nil { return nil, err } diff --git a/x/ibc/core/04-channel/keeper/grpc_query.go b/x/ibc/core/04-channel/keeper/grpc_query.go index a3683e6d0e..ea2fa037a8 100644 --- a/x/ibc/core/04-channel/keeper/grpc_query.go +++ b/x/ibc/core/04-channel/keeper/grpc_query.go @@ -56,7 +56,7 @@ func (q Keeper) Channels(c context.Context, req *types.QueryChannelsRequest) (*t pageRes, err := query.Paginate(store, req.Pagination, func(key, value []byte) error { var result types.Channel - if err := q.cdc.UnmarshalBinaryBare(value, &result); err != nil { + if err := q.cdc.Unmarshal(value, &result); err != nil { return err } @@ -99,7 +99,7 @@ func (q Keeper) ConnectionChannels(c context.Context, req *types.QueryConnection pageRes, err := query.Paginate(store, req.Pagination, func(key, value []byte) error { var result types.Channel - if err := q.cdc.UnmarshalBinaryBare(value, &result); err != nil { + if err := q.cdc.Unmarshal(value, &result); err != nil { return err } diff --git a/x/ibc/core/04-channel/keeper/keeper.go b/x/ibc/core/04-channel/keeper/keeper.go index 4367636079..a884f8aa4b 100644 --- a/x/ibc/core/04-channel/keeper/keeper.go +++ b/x/ibc/core/04-channel/keeper/keeper.go @@ -26,7 +26,7 @@ type Keeper struct { types.QueryServer storeKey sdk.StoreKey - cdc codec.BinaryMarshaler + cdc codec.Codec clientKeeper types.ClientKeeper connectionKeeper types.ConnectionKeeper portKeeper types.PortKeeper @@ -35,7 +35,7 @@ type Keeper struct { // NewKeeper creates a new IBC channel Keeper instance func NewKeeper( - cdc codec.BinaryMarshaler, key sdk.StoreKey, + cdc codec.Codec, key sdk.StoreKey, clientKeeper types.ClientKeeper, connectionKeeper types.ConnectionKeeper, portKeeper types.PortKeeper, scopedKeeper capabilitykeeper.ScopedKeeper, ) Keeper { @@ -73,14 +73,14 @@ func (k Keeper) GetChannel(ctx sdk.Context, portID, channelID string) (types.Cha } var channel types.Channel - k.cdc.MustUnmarshalBinaryBare(bz, &channel) + k.cdc.MustUnmarshal(bz, &channel) return channel, true } // SetChannel sets a channel to the store func (k Keeper) SetChannel(ctx sdk.Context, portID, channelID string, channel types.Channel) { store := ctx.KVStore(k.storeKey) - bz := k.cdc.MustMarshalBinaryBare(&channel) + bz := k.cdc.MustMarshal(&channel) store.Set(host.ChannelKey(portID, channelID), bz) } @@ -362,7 +362,7 @@ func (k Keeper) IterateChannels(ctx sdk.Context, cb func(types.IdentifiedChannel defer iterator.Close() for ; iterator.Valid(); iterator.Next() { var channel types.Channel - k.cdc.MustUnmarshalBinaryBare(iterator.Value(), &channel) + k.cdc.MustUnmarshal(iterator.Value(), &channel) portID, channelID := host.MustParseChannelPath(string(iterator.Key())) identifiedChannel := types.NewIdentifiedChannel(portID, channelID, channel) diff --git a/x/ibc/core/04-channel/simulation/decoder.go b/x/ibc/core/04-channel/simulation/decoder.go index 005668dbda..49196429bb 100644 --- a/x/ibc/core/04-channel/simulation/decoder.go +++ b/x/ibc/core/04-channel/simulation/decoder.go @@ -13,12 +13,12 @@ import ( // NewDecodeStore returns a decoder function closure that unmarshals the KVPair's // Value to the corresponding channel type. -func NewDecodeStore(cdc codec.BinaryMarshaler, kvA, kvB kv.Pair) (string, bool) { +func NewDecodeStore(cdc codec.Codec, kvA, kvB kv.Pair) (string, bool) { switch { case bytes.HasPrefix(kvA.Key, []byte(host.KeyChannelEndPrefix)): var channelA, channelB types.Channel - cdc.MustUnmarshalBinaryBare(kvA.Value, &channelA) - cdc.MustUnmarshalBinaryBare(kvB.Value, &channelB) + cdc.MustUnmarshal(kvA.Value, &channelA) + cdc.MustUnmarshal(kvB.Value, &channelB) return fmt.Sprintf("Channel A: %v\nChannel B: %v", channelA, channelB), true case bytes.HasPrefix(kvA.Key, []byte(host.KeyNextSeqSendPrefix)): diff --git a/x/ibc/core/04-channel/simulation/decoder_test.go b/x/ibc/core/04-channel/simulation/decoder_test.go index 002c3a48bb..1dd0f39d61 100644 --- a/x/ibc/core/04-channel/simulation/decoder_test.go +++ b/x/ibc/core/04-channel/simulation/decoder_test.go @@ -32,7 +32,7 @@ func TestDecodeStore(t *testing.T) { Pairs: []kv.Pair{ { Key: host.ChannelKey(portID, channelID), - Value: cdc.MustMarshalBinaryBare(&channel), + Value: cdc.MustMarshal(&channel), }, { Key: host.NextSequenceSendKey(portID, channelID), diff --git a/x/ibc/core/04-channel/types/acknowledgement.go b/x/ibc/core/04-channel/types/acknowledgement.go new file mode 100644 index 0000000000..a48f0ee9f5 --- /dev/null +++ b/x/ibc/core/04-channel/types/acknowledgement.go @@ -0,0 +1,50 @@ +package types + +import ( + "strings" + + sdk "github.com/line/lbm-sdk/types" + sdkerrors "github.com/line/lbm-sdk/types/errors" +) + +// NewResultAcknowledgement returns a new instance of Acknowledgement using an Acknowledgement_Result +// type in the Response field. +func NewResultAcknowledgement(result []byte) Acknowledgement { + return Acknowledgement{ + Response: &Acknowledgement_Result{ + Result: result, + }, + } +} + +// NewErrorAcknowledgement returns a new instance of Acknowledgement using an Acknowledgement_Error +// type in the Response field. +func NewErrorAcknowledgement(err string) Acknowledgement { + return Acknowledgement{ + Response: &Acknowledgement_Error{ + Error: err, + }, + } +} + +// GetBytes is a helper for serialising acknowledgements +func (ack Acknowledgement) GetBytes() []byte { + return sdk.MustSortJSON(SubModuleCdc.MustMarshalJSON(&ack)) +} + +// ValidateBasic performs a basic validation of the acknowledgement +func (ack Acknowledgement) ValidateBasic() error { + switch resp := ack.Response.(type) { + case *Acknowledgement_Result: + if len(resp.Result) == 0 { + return sdkerrors.Wrap(ErrInvalidAcknowledgement, "acknowledgement result cannot be empty") + } + case *Acknowledgement_Error: + if strings.TrimSpace(resp.Error) == "" { + return sdkerrors.Wrap(ErrInvalidAcknowledgement, "acknowledgement error cannot be empty") + } + default: + return sdkerrors.Wrapf(ErrInvalidAcknowledgement, "unsupported acknowledgement response field type %T", resp) + } + return nil +} diff --git a/x/ibc/core/04-channel/types/acknowledgement_test.go b/x/ibc/core/04-channel/types/acknowledgement_test.go new file mode 100644 index 0000000000..63a944194c --- /dev/null +++ b/x/ibc/core/04-channel/types/acknowledgement_test.go @@ -0,0 +1,63 @@ +package types_test + +import "github.com/line/lbm-sdk/x/ibc/core/04-channel/types" + +// tests acknowledgement.ValidateBasic and acknowledgement.GetBytes +func (suite TypesTestSuite) TestAcknowledgement() { + testCases := []struct { + name string + ack types.Acknowledgement + expPass bool + }{ + { + "valid successful ack", + types.NewResultAcknowledgement([]byte("success")), + true, + }, + { + "valid failed ack", + types.NewErrorAcknowledgement("error"), + true, + }, + { + "empty successful ack", + types.NewResultAcknowledgement([]byte{}), + false, + }, + { + "empty faied ack", + types.NewErrorAcknowledgement(" "), + false, + }, + { + "nil response", + types.Acknowledgement{ + Response: nil, + }, + false, + }, + } + + for _, tc := range testCases { + tc := tc + + suite.Run(tc.name, func() { + suite.SetupTest() + + err := tc.ack.ValidateBasic() + + if tc.expPass { + suite.Require().NoError(err) + } else { + suite.Require().Error(err) + } + + // expect all acks to be able to be marshaled + suite.NotPanics(func() { + bz := tc.ack.GetBytes() + suite.Require().NotNil(bz) + }) + }) + } + +} diff --git a/x/ibc/core/04-channel/types/channel.go b/x/ibc/core/04-channel/types/channel.go index e7bdcb46db..cc2fe3d45c 100644 --- a/x/ibc/core/04-channel/types/channel.go +++ b/x/ibc/core/04-channel/types/channel.go @@ -1,9 +1,6 @@ package types import ( - "strings" - - sdk "github.com/line/lbm-sdk/types" sdkerrors "github.com/line/lbm-sdk/types/errors" host "github.com/line/lbm-sdk/x/ibc/core/24-host" "github.com/line/lbm-sdk/x/ibc/core/exported" @@ -128,45 +125,3 @@ func (ic IdentifiedChannel) ValidateBasic() error { channel := NewChannel(ic.State, ic.Ordering, ic.Counterparty, ic.ConnectionHops, ic.Version) return channel.ValidateBasic() } - -// NewResultAcknowledgement returns a new instance of Acknowledgement using an Acknowledgement_Result -// type in the Response field. -func NewResultAcknowledgement(result []byte) Acknowledgement { - return Acknowledgement{ - Response: &Acknowledgement_Result{ - Result: result, - }, - } -} - -// NewErrorAcknowledgement returns a new instance of Acknowledgement using an Acknowledgement_Error -// type in the Response field. -func NewErrorAcknowledgement(err string) Acknowledgement { - return Acknowledgement{ - Response: &Acknowledgement_Error{ - Error: err, - }, - } -} - -// GetBytes is a helper for serialising acknowledgements -func (ack Acknowledgement) GetBytes() []byte { - return sdk.MustSortJSON(SubModuleCdc.MustMarshalJSON(&ack)) -} - -// ValidateBasic performs a basic validation of the acknowledgement -func (ack Acknowledgement) ValidateBasic() error { - switch resp := ack.Response.(type) { - case *Acknowledgement_Result: - if len(resp.Result) == 0 { - return sdkerrors.Wrap(ErrInvalidAcknowledgement, "acknowledgement result cannot be empty") - } - case *Acknowledgement_Error: - if strings.TrimSpace(resp.Error) == "" { - return sdkerrors.Wrap(ErrInvalidAcknowledgement, "acknowledgement error cannot be empty") - } - default: - return sdkerrors.Wrapf(ErrInvalidAcknowledgement, "unsupported acknowledgement response field type %T", resp) - } - return nil -} diff --git a/x/ibc/core/04-channel/types/channel_test.go b/x/ibc/core/04-channel/types/channel_test.go index b942dd7a24..66e838ab36 100644 --- a/x/ibc/core/04-channel/types/channel_test.go +++ b/x/ibc/core/04-channel/types/channel_test.go @@ -57,63 +57,3 @@ func TestCounterpartyValidateBasic(t *testing.T) { } } } - -// tests acknowledgement.ValidateBasic and acknowledgement.GetBytes -func (suite TypesTestSuite) TestAcknowledgement() { - testCases := []struct { - name string - ack types.Acknowledgement - expPass bool - }{ - { - "valid successful ack", - types.NewResultAcknowledgement([]byte("success")), - true, - }, - { - "valid failed ack", - types.NewErrorAcknowledgement("error"), - true, - }, - { - "empty successful ack", - types.NewResultAcknowledgement([]byte{}), - false, - }, - { - "empty faied ack", - types.NewErrorAcknowledgement(" "), - false, - }, - { - "nil response", - types.Acknowledgement{ - Response: nil, - }, - false, - }, - } - - for _, tc := range testCases { - tc := tc - - suite.Run(tc.name, func() { - suite.SetupTest() - - err := tc.ack.ValidateBasic() - - if tc.expPass { - suite.Require().NoError(err) - } else { - suite.Require().Error(err) - } - - // expect all acks to be able to be marshaled - suite.NotPanics(func() { - bz := tc.ack.GetBytes() - suite.Require().NotNil(bz) - }) - }) - } - -} diff --git a/x/ibc/core/04-channel/types/codec.go b/x/ibc/core/04-channel/types/codec.go index 26c549cbf4..003e4d3684 100644 --- a/x/ibc/core/04-channel/types/codec.go +++ b/x/ibc/core/04-channel/types/codec.go @@ -14,25 +14,16 @@ func RegisterInterfaces(registry codectypes.InterfaceRegistry) { registry.RegisterInterface( "ibc.core.channel.v1.ChannelI", (*exported.ChannelI)(nil), + &Channel{}, ) registry.RegisterInterface( "ibc.core.channel.v1.CounterpartyChannelI", (*exported.CounterpartyChannelI)(nil), + &Counterparty{}, ) registry.RegisterInterface( "ibc.core.channel.v1.PacketI", (*exported.PacketI)(nil), - ) - registry.RegisterImplementations( - (*exported.ChannelI)(nil), - &Channel{}, - ) - registry.RegisterImplementations( - (*exported.CounterpartyChannelI)(nil), - &Counterparty{}, - ) - registry.RegisterImplementations( - (*exported.PacketI)(nil), &Packet{}, ) registry.RegisterImplementations( diff --git a/x/ibc/core/04-channel/types/msgs_test.go b/x/ibc/core/04-channel/types/msgs_test.go index a0f379191a..7637c10da0 100644 --- a/x/ibc/core/04-channel/types/msgs_test.go +++ b/x/ibc/core/04-channel/types/msgs_test.go @@ -96,7 +96,7 @@ func (suite *TypesTestSuite) SetupTest() { merkleProof, err := commitmenttypes.ConvertProofs(res.ProofOps) suite.Require().NoError(err) - proof, err := app.AppCodec().MarshalBinaryBare(&merkleProof) + proof, err := app.AppCodec().Marshal(&merkleProof) suite.Require().NoError(err) suite.proof = proof diff --git a/x/ibc/core/04-channel/types/packet.go b/x/ibc/core/04-channel/types/packet.go index bca19f351c..835205030b 100644 --- a/x/ibc/core/04-channel/types/packet.go +++ b/x/ibc/core/04-channel/types/packet.go @@ -15,7 +15,7 @@ import ( // sha256_hash(timeout_timestamp + timeout_height.RevisionNumber + timeout_height.RevisionHeight + sha256_hash(data)) // from a given packet. This results in a fixed length preimage. // NOTE: sdk.Uint64ToBigEndian sets the uint64 to a slice of length 8. -func CommitPacket(cdc codec.BinaryMarshaler, packet exported.PacketI) []byte { +func CommitPacket(cdc codec.Codec, packet exported.PacketI) []byte { timeoutHeight := packet.GetTimeoutHeight() buf := sdk.Uint64ToBigEndian(packet.GetTimeoutTimestamp()) diff --git a/x/ibc/core/04-channel/types/query.go b/x/ibc/core/04-channel/types/query.go index 6a02c01f9d..a77a0867e0 100644 --- a/x/ibc/core/04-channel/types/query.go +++ b/x/ibc/core/04-channel/types/query.go @@ -11,6 +11,11 @@ var ( _ codectypes.UnpackInterfacesMessage = QueryChannelConsensusStateResponse{} ) +var ( + _ codectypes.UnpackInterfacesMessage = QueryChannelClientStateResponse{} + _ codectypes.UnpackInterfacesMessage = QueryChannelConsensusStateResponse{} +) + // NewQueryChannelResponse creates a new QueryChannelResponse instance func NewQueryChannelResponse(channel Channel, proof []byte, height clienttypes.Height) *QueryChannelResponse { return &QueryChannelResponse{ diff --git a/x/ibc/core/04-channel/types/query.pb.gw.go b/x/ibc/core/04-channel/types/query.pb.gw.go index 9e59c03b53..b022011e1b 100644 --- a/x/ibc/core/04-channel/types/query.pb.gw.go +++ b/x/ibc/core/04-channel/types/query.pb.gw.go @@ -1736,31 +1736,31 @@ func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, clie } var ( - pattern_Query_Channel_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 1, 0, 4, 1, 5, 5, 2, 6, 1, 0, 4, 1, 5, 7}, []string{"ibc", "core", "channel", "v1", "channels", "channel_id", "ports", "port_id"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_Query_Channel_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 1, 0, 4, 1, 5, 5, 2, 6, 1, 0, 4, 1, 5, 7}, []string{"ibc", "core", "channel", "v1", "channels", "channel_id", "ports", "port_id"}, "", runtime.AssumeColonVerbOpt(false))) - pattern_Query_Channels_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4}, []string{"ibc", "core", "channel", "v1", "channels"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_Query_Channels_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4}, []string{"ibc", "core", "channel", "v1", "channels"}, "", runtime.AssumeColonVerbOpt(false))) - pattern_Query_ConnectionChannels_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 1, 0, 4, 1, 5, 5, 2, 6}, []string{"ibc", "core", "channel", "v1", "connections", "connection", "channels"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_Query_ConnectionChannels_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 1, 0, 4, 1, 5, 5, 2, 6}, []string{"ibc", "core", "channel", "v1", "connections", "connection", "channels"}, "", runtime.AssumeColonVerbOpt(false))) - pattern_Query_ChannelClientState_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 1, 0, 4, 1, 5, 5, 2, 6, 1, 0, 4, 1, 5, 7, 2, 8}, []string{"ibc", "core", "channel", "v1", "channels", "channel_id", "ports", "port_id", "client_state"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_Query_ChannelClientState_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 1, 0, 4, 1, 5, 5, 2, 6, 1, 0, 4, 1, 5, 7, 2, 8}, []string{"ibc", "core", "channel", "v1", "channels", "channel_id", "ports", "port_id", "client_state"}, "", runtime.AssumeColonVerbOpt(false))) - pattern_Query_ChannelConsensusState_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 1, 0, 4, 1, 5, 5, 2, 6, 1, 0, 4, 1, 5, 7, 2, 8, 2, 9, 1, 0, 4, 1, 5, 10, 2, 11, 1, 0, 4, 1, 5, 12}, []string{"ibc", "core", "channel", "v1", "channels", "channel_id", "ports", "port_id", "consensus_state", "revision", "revision_number", "height", "revision_height"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_Query_ChannelConsensusState_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 1, 0, 4, 1, 5, 5, 2, 6, 1, 0, 4, 1, 5, 7, 2, 8, 2, 9, 1, 0, 4, 1, 5, 10, 2, 11, 1, 0, 4, 1, 5, 12}, []string{"ibc", "core", "channel", "v1", "channels", "channel_id", "ports", "port_id", "consensus_state", "revision", "revision_number", "height", "revision_height"}, "", runtime.AssumeColonVerbOpt(false))) - pattern_Query_PacketCommitment_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 1, 0, 4, 1, 5, 5, 2, 6, 1, 0, 4, 1, 5, 7, 2, 8, 1, 0, 4, 1, 5, 9}, []string{"ibc", "core", "channel", "v1", "channels", "channel_id", "ports", "port_id", "packet_commitments", "sequence"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_Query_PacketCommitment_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 1, 0, 4, 1, 5, 5, 2, 6, 1, 0, 4, 1, 5, 7, 2, 8, 1, 0, 4, 1, 5, 9}, []string{"ibc", "core", "channel", "v1", "channels", "channel_id", "ports", "port_id", "packet_commitments", "sequence"}, "", runtime.AssumeColonVerbOpt(false))) - pattern_Query_PacketCommitments_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 1, 0, 4, 1, 5, 5, 2, 6, 1, 0, 4, 1, 5, 7, 2, 8}, []string{"ibc", "core", "channel", "v1", "channels", "channel_id", "ports", "port_id", "packet_commitments"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_Query_PacketCommitments_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 1, 0, 4, 1, 5, 5, 2, 6, 1, 0, 4, 1, 5, 7, 2, 8}, []string{"ibc", "core", "channel", "v1", "channels", "channel_id", "ports", "port_id", "packet_commitments"}, "", runtime.AssumeColonVerbOpt(false))) - pattern_Query_PacketReceipt_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 1, 0, 4, 1, 5, 5, 2, 6, 1, 0, 4, 1, 5, 7, 2, 8, 1, 0, 4, 1, 5, 9}, []string{"ibc", "core", "channel", "v1", "channels", "channel_id", "ports", "port_id", "packet_receipts", "sequence"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_Query_PacketReceipt_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 1, 0, 4, 1, 5, 5, 2, 6, 1, 0, 4, 1, 5, 7, 2, 8, 1, 0, 4, 1, 5, 9}, []string{"ibc", "core", "channel", "v1", "channels", "channel_id", "ports", "port_id", "packet_receipts", "sequence"}, "", runtime.AssumeColonVerbOpt(false))) - pattern_Query_PacketAcknowledgement_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 1, 0, 4, 1, 5, 5, 2, 6, 1, 0, 4, 1, 5, 7, 2, 8, 1, 0, 4, 1, 5, 9}, []string{"ibc", "core", "channel", "v1", "channels", "channel_id", "ports", "port_id", "packet_acks", "sequence"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_Query_PacketAcknowledgement_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 1, 0, 4, 1, 5, 5, 2, 6, 1, 0, 4, 1, 5, 7, 2, 8, 1, 0, 4, 1, 5, 9}, []string{"ibc", "core", "channel", "v1", "channels", "channel_id", "ports", "port_id", "packet_acks", "sequence"}, "", runtime.AssumeColonVerbOpt(false))) - pattern_Query_PacketAcknowledgements_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 1, 0, 4, 1, 5, 5, 2, 6, 1, 0, 4, 1, 5, 7, 2, 8}, []string{"ibc", "core", "channel", "v1", "channels", "channel_id", "ports", "port_id", "packet_acknowledgements"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_Query_PacketAcknowledgements_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 1, 0, 4, 1, 5, 5, 2, 6, 1, 0, 4, 1, 5, 7, 2, 8}, []string{"ibc", "core", "channel", "v1", "channels", "channel_id", "ports", "port_id", "packet_acknowledgements"}, "", runtime.AssumeColonVerbOpt(false))) - pattern_Query_UnreceivedPackets_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 1, 0, 4, 1, 5, 5, 2, 6, 1, 0, 4, 1, 5, 7, 2, 8, 1, 0, 4, 1, 5, 9, 2, 10}, []string{"ibc", "core", "channel", "v1", "channels", "channel_id", "ports", "port_id", "packet_commitments", "packet_commitment_sequences", "unreceived_packets"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_Query_UnreceivedPackets_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 1, 0, 4, 1, 5, 5, 2, 6, 1, 0, 4, 1, 5, 7, 2, 8, 1, 0, 4, 1, 5, 9, 2, 10}, []string{"ibc", "core", "channel", "v1", "channels", "channel_id", "ports", "port_id", "packet_commitments", "packet_commitment_sequences", "unreceived_packets"}, "", runtime.AssumeColonVerbOpt(false))) - pattern_Query_UnreceivedAcks_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 1, 0, 4, 1, 5, 5, 2, 6, 1, 0, 4, 1, 5, 7, 2, 8, 1, 0, 4, 1, 5, 9, 2, 10}, []string{"ibc", "core", "channel", "v1", "channels", "channel_id", "ports", "port_id", "packet_commitments", "packet_ack_sequences", "unreceived_acks"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_Query_UnreceivedAcks_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 1, 0, 4, 1, 5, 5, 2, 6, 1, 0, 4, 1, 5, 7, 2, 8, 1, 0, 4, 1, 5, 9, 2, 10}, []string{"ibc", "core", "channel", "v1", "channels", "channel_id", "ports", "port_id", "packet_commitments", "packet_ack_sequences", "unreceived_acks"}, "", runtime.AssumeColonVerbOpt(false))) - pattern_Query_NextSequenceReceive_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 1, 0, 4, 1, 5, 5, 2, 6, 1, 0, 4, 1, 5, 7, 2, 8}, []string{"ibc", "core", "channel", "v1", "channels", "channel_id", "ports", "port_id", "next_sequence"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_Query_NextSequenceReceive_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 1, 0, 4, 1, 5, 5, 2, 6, 1, 0, 4, 1, 5, 7, 2, 8}, []string{"ibc", "core", "channel", "v1", "channels", "channel_id", "ports", "port_id", "next_sequence"}, "", runtime.AssumeColonVerbOpt(false))) ) var ( diff --git a/x/ibc/core/client/cli/cli.go b/x/ibc/core/client/cli/cli.go index 5d94051eb8..e4a0af1503 100644 --- a/x/ibc/core/client/cli/cli.go +++ b/x/ibc/core/client/cli/cli.go @@ -8,8 +8,6 @@ import ( connection "github.com/line/lbm-sdk/x/ibc/core/03-connection" channel "github.com/line/lbm-sdk/x/ibc/core/04-channel" host "github.com/line/lbm-sdk/x/ibc/core/24-host" - solomachine "github.com/line/lbm-sdk/x/ibc/light-clients/06-solomachine" - tendermint "github.com/line/lbm-sdk/x/ibc/light-clients/99-ostracon" ) // GetTxCmd returns the transaction commands for this module @@ -23,8 +21,7 @@ func GetTxCmd() *cobra.Command { } ibcTxCmd.AddCommand( - solomachine.GetTxCmd(), - tendermint.GetTxCmd(), + ibcclient.GetTxCmd(), connection.GetTxCmd(), channel.GetTxCmd(), ) diff --git a/x/ibc/core/client/query.go b/x/ibc/core/client/query.go index 65c7acdac3..6fca7fb8d5 100644 --- a/x/ibc/core/client/query.go +++ b/x/ibc/core/client/query.go @@ -20,7 +20,7 @@ import ( // the correct merkle proof. Proof queries at height less than or equal to 2 are // not supported. Queries with a client context height of 0 will perform a query // at the lastest state available. -// Issue: https://github.com/line/lbm-sdk/issues/6567 +// Issue: https://github.com/cosmos/cosmos-sdk/issues/6567 func QueryTendermintProof(clientCtx client.Context, key []byte) ([]byte, []byte, clienttypes.Height, error) { height := clientCtx.Height @@ -57,7 +57,7 @@ func QueryTendermintProof(clientCtx client.Context, key []byte) ([]byte, []byte, cdc := codec.NewProtoCodec(clientCtx.InterfaceRegistry) - proofBz, err := cdc.MarshalBinaryBare(&merkleProof) + proofBz, err := cdc.Marshal(&merkleProof) if err != nil { return nil, nil, clienttypes.Height{}, err } diff --git a/x/ibc/core/exported/client.go b/x/ibc/core/exported/client.go index ad4f2b6687..04bc6b7815 100644 --- a/x/ibc/core/exported/client.go +++ b/x/ibc/core/exported/client.go @@ -37,16 +37,16 @@ type ClientState interface { // Initialization function // Clients must validate the initial consensus state, and may store any client-specific metadata // necessary for correct light client operation - Initialize(sdk.Context, codec.BinaryMarshaler, sdk.KVStore, ConsensusState) error + Initialize(sdk.Context, codec.Codec, sdk.KVStore, ConsensusState) error // Genesis function ExportMetadata(sdk.KVStore) []GenesisMetadata // Update and Misbehaviour functions - CheckHeaderAndUpdateState(sdk.Context, codec.BinaryMarshaler, sdk.KVStore, Header) (ClientState, ConsensusState, error) - CheckMisbehaviourAndUpdateState(sdk.Context, codec.BinaryMarshaler, sdk.KVStore, Misbehaviour) (ClientState, error) - CheckProposedHeaderAndUpdateState(sdk.Context, codec.BinaryMarshaler, sdk.KVStore, Header) (ClientState, ConsensusState, error) + CheckHeaderAndUpdateState(sdk.Context, codec.Codec, sdk.KVStore, Header) (ClientState, ConsensusState, error) + CheckMisbehaviourAndUpdateState(sdk.Context, codec.Codec, sdk.KVStore, Misbehaviour) (ClientState, error) + CheckSubstituteAndUpdateState(ctx sdk.Context, cdc codec.Codec, subjectClientStore, substituteClientStore sdk.KVStore, substituteClient ClientState, height Height) (ClientState, error) // Upgrade functions // NOTE: proof heights are not included as upgrade to a new revision is expected to pass only on the last @@ -56,7 +56,7 @@ type ClientState interface { // may be cancelled or modified before the last planned height. VerifyUpgradeAndUpdateState( ctx sdk.Context, - cdc codec.BinaryMarshaler, + cdc codec.Codec, store sdk.KVStore, newClient ClientState, newConsState ConsensusState, @@ -72,7 +72,7 @@ type ClientState interface { VerifyClientState( store sdk.KVStore, - cdc codec.BinaryMarshaler, + cdc codec.Codec, height Height, prefix Prefix, counterpartyClientIdentifier string, @@ -81,7 +81,7 @@ type ClientState interface { ) error VerifyClientConsensusState( store sdk.KVStore, - cdc codec.BinaryMarshaler, + cdc codec.Codec, height Height, counterpartyClientIdentifier string, consensusHeight Height, @@ -91,7 +91,7 @@ type ClientState interface { ) error VerifyConnectionState( store sdk.KVStore, - cdc codec.BinaryMarshaler, + cdc codec.Codec, height Height, prefix Prefix, proof []byte, @@ -100,7 +100,7 @@ type ClientState interface { ) error VerifyChannelState( store sdk.KVStore, - cdc codec.BinaryMarshaler, + cdc codec.Codec, height Height, prefix Prefix, proof []byte, @@ -110,7 +110,7 @@ type ClientState interface { ) error VerifyPacketCommitment( store sdk.KVStore, - cdc codec.BinaryMarshaler, + cdc codec.Codec, height Height, currentTimestamp uint64, delayPeriod uint64, @@ -123,7 +123,7 @@ type ClientState interface { ) error VerifyPacketAcknowledgement( store sdk.KVStore, - cdc codec.BinaryMarshaler, + cdc codec.Codec, height Height, currentTimestamp uint64, delayPeriod uint64, @@ -136,7 +136,7 @@ type ClientState interface { ) error VerifyPacketReceiptAbsence( store sdk.KVStore, - cdc codec.BinaryMarshaler, + cdc codec.Codec, height Height, currentTimestamp uint64, delayPeriod uint64, @@ -148,7 +148,7 @@ type ClientState interface { ) error VerifyNextSequenceRecv( store sdk.KVStore, - cdc codec.BinaryMarshaler, + cdc codec.Codec, height Height, currentTimestamp uint64, delayPeriod uint64, diff --git a/x/ibc/core/keeper/grpc_query.go b/x/ibc/core/keeper/grpc_query.go index b9061ce08a..a009af80c8 100644 --- a/x/ibc/core/keeper/grpc_query.go +++ b/x/ibc/core/keeper/grpc_query.go @@ -33,6 +33,11 @@ func (q Keeper) ClientParams(c context.Context, req *clienttypes.QueryClientPara return q.ClientKeeper.ClientParams(c, req) } +// UpgradedClientState implements the IBC QueryServer interface +func (q Keeper) UpgradedClientState(c context.Context, req *clienttypes.QueryUpgradedClientStateRequest) (*clienttypes.QueryUpgradedClientStateResponse, error) { + return q.ClientKeeper.UpgradedClientState(c, req) +} + // Connection implements the IBC QueryServer interface func (q Keeper) Connection(c context.Context, req *connectiontypes.QueryConnectionRequest) (*connectiontypes.QueryConnectionResponse, error) { return q.ConnectionKeeper.Connection(c, req) diff --git a/x/ibc/core/keeper/keeper.go b/x/ibc/core/keeper/keeper.go index 2621b45115..5ad1d6c658 100644 --- a/x/ibc/core/keeper/keeper.go +++ b/x/ibc/core/keeper/keeper.go @@ -21,7 +21,7 @@ type Keeper struct { // implements gRPC QueryServer interface types.QueryServer - cdc codec.BinaryMarshaler + cdc codec.Codec ClientKeeper clientkeeper.Keeper ConnectionKeeper connectionkeeper.Keeper @@ -32,10 +32,11 @@ type Keeper struct { // NewKeeper creates a new ibc Keeper func NewKeeper( - cdc codec.BinaryMarshaler, key sdk.StoreKey, paramSpace *paramtypes.Subspace, - stakingKeeper clienttypes.StakingKeeper, scopedKeeper capabilitykeeper.ScopedKeeper, + cdc codec.Codec, key sdk.StoreKey, paramSpace paramtypes.Subspace, + stakingKeeper clienttypes.StakingKeeper, upgradeKeeper clienttypes.UpgradeKeeper, + scopedKeeper capabilitykeeper.ScopedKeeper, ) *Keeper { - clientKeeper := clientkeeper.NewKeeper(cdc, key, paramSpace, stakingKeeper) + clientKeeper := clientkeeper.NewKeeper(cdc, key, paramSpace, stakingKeeper, upgradeKeeper) connectionKeeper := connectionkeeper.NewKeeper(cdc, key, clientKeeper) portKeeper := portkeeper.NewKeeper(scopedKeeper) channelKeeper := channelkeeper.NewKeeper(cdc, key, clientKeeper, connectionKeeper, portKeeper, scopedKeeper) @@ -50,7 +51,7 @@ func NewKeeper( } // Codec returns the IBC module codec. -func (k Keeper) Codec() codec.BinaryMarshaler { +func (k Keeper) Codec() codec.Codec { return k.cdc } diff --git a/x/ibc/core/keeper/msg_server_test.go b/x/ibc/core/keeper/msg_server_test.go index 9e2bcfe159..969aba969b 100644 --- a/x/ibc/core/keeper/msg_server_test.go +++ b/x/ibc/core/keeper/msg_server_test.go @@ -639,14 +639,18 @@ func (suite *KeeperTestSuite) TestUpgradeClient() { // last Height is at next block lastHeight = clienttypes.NewHeight(0, uint64(suite.chainB.GetContext().BlockHeight()+1)) + upgradedClientBz, err := clienttypes.MarshalClientState(suite.chainA.App.AppCodec(), upgradedClient) + suite.Require().NoError(err) + upgradedConsStateBz, err := clienttypes.MarshalConsensusState(suite.chainA.App.AppCodec(), upgradedConsState) + suite.Require().NoError(err) + // zero custom fields and store in upgrade store - suite.chainB.App.UpgradeKeeper.SetUpgradedClient(suite.chainB.GetContext(), int64(lastHeight.GetRevisionHeight()), upgradedClient) - suite.chainB.App.UpgradeKeeper.SetUpgradedConsensusState(suite.chainB.GetContext(), int64(lastHeight.GetRevisionHeight()), upgradedConsState) + suite.chainB.App.UpgradeKeeper.SetUpgradedClient(suite.chainB.GetContext(), int64(lastHeight.GetRevisionHeight()), upgradedClientBz) + suite.chainB.App.UpgradeKeeper.SetUpgradedConsensusState(suite.chainB.GetContext(), int64(lastHeight.GetRevisionHeight()), upgradedConsStateBz) // commit upgrade store changes and update clients - suite.coordinator.CommitBlock(suite.chainB) - err := suite.coordinator.UpdateClient(suite.chainA, suite.chainB, clientA, exported.Ostracon) + err = suite.coordinator.UpdateClient(suite.chainA, suite.chainB, clientA, exported.Ostracon) suite.Require().NoError(err) cs, found := suite.chainA.App.IBCKeeper.ClientKeeper.GetClientState(suite.chainA.GetContext(), clientA) @@ -676,14 +680,18 @@ func (suite *KeeperTestSuite) TestUpgradeClient() { // last Height is at next block lastHeight = clienttypes.NewHeight(0, uint64(suite.chainB.GetContext().BlockHeight()+1)) + upgradedClientBz, err := clienttypes.MarshalClientState(suite.chainA.App.AppCodec(), upgradedClient) + suite.Require().NoError(err) + upgradedConsStateBz, err := clienttypes.MarshalConsensusState(suite.chainA.App.AppCodec(), upgradedConsState) + suite.Require().NoError(err) + // zero custom fields and store in upgrade store - suite.chainB.App.UpgradeKeeper.SetUpgradedClient(suite.chainB.GetContext(), int64(lastHeight.GetRevisionHeight()), upgradedClient) - suite.chainB.App.UpgradeKeeper.SetUpgradedConsensusState(suite.chainB.GetContext(), int64(lastHeight.GetRevisionHeight()), upgradedConsState) + suite.chainB.App.UpgradeKeeper.SetUpgradedClient(suite.chainB.GetContext(), int64(lastHeight.GetRevisionHeight()), upgradedClientBz) + suite.chainB.App.UpgradeKeeper.SetUpgradedConsensusState(suite.chainB.GetContext(), int64(lastHeight.GetRevisionHeight()), upgradedConsStateBz) // commit upgrade store changes and update clients - suite.coordinator.CommitBlock(suite.chainB) - err := suite.coordinator.UpdateClient(suite.chainA, suite.chainB, clientA, exported.Ostracon) + err = suite.coordinator.UpdateClient(suite.chainA, suite.chainB, clientA, exported.Ostracon) suite.Require().NoError(err) msg, err = clienttypes.NewMsgUpgradeClient(clientA, upgradedClient, upgradedConsState, nil, nil, suite.chainA.SenderAccount.GetAddress()) diff --git a/x/ibc/core/module.go b/x/ibc/core/module.go index 44d6a38dda..8cb26b855c 100644 --- a/x/ibc/core/module.go +++ b/x/ibc/core/module.go @@ -50,12 +50,12 @@ func (AppModuleBasic) RegisterLegacyAminoCodec(*codec.LegacyAmino) {} // DefaultGenesis returns default genesis state as raw bytes for the ibc // module. -func (AppModuleBasic) DefaultGenesis(cdc codec.JSONMarshaler) json.RawMessage { +func (AppModuleBasic) DefaultGenesis(cdc codec.JSONCodec) json.RawMessage { return cdc.MustMarshalJSON(types.DefaultGenesisState()) } // ValidateGenesis performs genesis state validation for the ibc module. -func (AppModuleBasic) ValidateGenesis(cdc codec.JSONMarshaler, config client.TxEncodingConfig, bz json.RawMessage) error { +func (AppModuleBasic) ValidateGenesis(cdc codec.JSONCodec, config client.TxEncodingConfig, bz json.RawMessage) error { var gs types.GenesisState if err := cdc.UnmarshalJSON(bz, &gs); err != nil { return fmt.Errorf("failed to unmarshal %s genesis state: %w", host.ModuleName, err) @@ -140,7 +140,7 @@ func (am AppModule) RegisterServices(cfg module.Configurator) { // InitGenesis performs genesis initialization for the ibc module. It returns // no validator updates. -func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONMarshaler, bz json.RawMessage) []abci.ValidatorUpdate { +func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONCodec, bz json.RawMessage) []abci.ValidatorUpdate { var gs types.GenesisState err := cdc.UnmarshalJSON(bz, &gs) if err != nil { @@ -152,7 +152,7 @@ func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONMarshaler, bz jso // ExportGenesis returns the exported genesis state as raw bytes for the ibc // module. -func (am AppModule) ExportGenesis(ctx sdk.Context, cdc codec.JSONMarshaler) json.RawMessage { +func (am AppModule) ExportGenesis(ctx sdk.Context, cdc codec.JSONCodec) json.RawMessage { return cdc.MustMarshalJSON(ExportGenesis(ctx, *am.keeper)) } @@ -170,8 +170,6 @@ func (am AppModule) EndBlock(ctx sdk.Context, req abci.RequestEndBlock) []abci.V return []abci.ValidatorUpdate{} } -// ____________________________________________________________________________ - // AppModuleSimulation functions // GenerateGenesisState creates a randomized GenState of the ibc module. diff --git a/x/ibc/core/simulation/decoder_test.go b/x/ibc/core/simulation/decoder_test.go index 601b855aac..b420c84c01 100644 --- a/x/ibc/core/simulation/decoder_test.go +++ b/x/ibc/core/simulation/decoder_test.go @@ -45,11 +45,11 @@ func TestDecodeStore(t *testing.T) { }, { Key: host.ConnectionKey(connectionID), - Value: app.IBCKeeper.Codec().MustMarshalBinaryBare(&connection), + Value: app.IBCKeeper.Codec().MustMarshal(&connection), }, { Key: host.ChannelKey(portID, channelID), - Value: app.IBCKeeper.Codec().MustMarshalBinaryBare(&channel), + Value: app.IBCKeeper.Codec().MustMarshal(&channel), }, { Key: []byte{0x99}, diff --git a/x/ibc/core/spec/01_concepts.md b/x/ibc/core/spec/01_concepts.md index 7e73ceaa1c..91fcf14eab 100644 --- a/x/ibc/core/spec/01_concepts.md +++ b/x/ibc/core/spec/01_concepts.md @@ -50,11 +50,11 @@ submission. ## ClientUpdateProposal -A governance proposal may be passed to update a specified client with a provided -header. This is useful in unfreezing clients or updating expired clients. Each -client is expected to implement this functionality. A client may choose to disallow -an update by a governance proposal by returning an error in the client state function -'CheckProposedHeaderAndUpdateState'. +A governance proposal may be passed to update a specified client using another client +known as the "substitute client". This is useful in unfreezing clients or updating +expired clients, thereby making the effected channels active again. Each client is +expected to implement this functionality. A client may choose to disallow an update +by a governance proposal by returning an error in the client state function 'CheckSubstituteAndUpdateState'. The localhost client cannot be updated by a governance proposal. @@ -65,9 +65,21 @@ be updated later. The tendermint client has two flags update flags, 'AllowUpdateAfterExpiry' and 'AllowUpdateAfterMisbehaviour'. The former flag can only be used to unexpire clients. The latter flag can be used to unfreeze a client and if necessary it will also unexpire the client. -It is advised to let a client expire if it has become frozen before proposing a new header. -This is to avoid the client from becoming refrozen if the misbehaviour evidence has not -expired. These boolean flags are set upon client creation and cannot be updated later. +It is best practice to initialize a new substitute client instead of using an existing one +This avoids potential issues of the substitute becoming frozen due to misbehaviour or the +subject client becoming refrozen due to misbehaviour not being expired at the time the +proposal passes. These boolean flags are set upon client creation and cannot be updated later. + +The `CheckSubstituteAndUpdateState` function provides the light client with its own client +store, the client store of the substitute, the substitute client state, and the intitial +height that should be used when referring to the substitute client. Most light client +implementations should copy consensus states from the substitute to the subject, but +are not required to do so. Light clients may copy informationa as they deem necessary. + +It is not recommended to use a substitute client in normal operations since the subject +light client will be given unrestricted access to the substitute client store. Governance +should not pass votes which enable byzantine light client modules from modifying the state +of the substitute. ## IBC Client Heights diff --git a/x/ibc/core/spec/03_state_transitions.md b/x/ibc/core/spec/03_state_transitions.md index be3b508b79..518ff9247b 100644 --- a/x/ibc/core/spec/03_state_transitions.md +++ b/x/ibc/core/spec/03_state_transitions.md @@ -27,8 +27,9 @@ parameters and if applicable will update to the new light client implementation. ## Client Update Proposal -An Update Client Proposal will unfreeze a client and set an updated `ClientState` and a new -`ConsensusState`. +An Update Client Proposal will unfreeze a client (if necessary) and set an updated `ClientState`. +The light client may make optional modifications to the client prefixed store of the subject client +including copying `ConsensusStates` from the substitute to the subject. ## Connection Open Init diff --git a/x/ibc/light-clients/06-solomachine/client/cli/cli.go b/x/ibc/light-clients/06-solomachine/client/cli/cli.go deleted file mode 100644 index 23c492d5a1..0000000000 --- a/x/ibc/light-clients/06-solomachine/client/cli/cli.go +++ /dev/null @@ -1,27 +0,0 @@ -package cli - -import ( - "github.com/spf13/cobra" - - "github.com/line/lbm-sdk/client" - "github.com/line/lbm-sdk/x/ibc/light-clients/06-solomachine/types" -) - -// NewTxCmd returns a root CLI command handler for all solo machine transaction commands. -func NewTxCmd() *cobra.Command { - txCmd := &cobra.Command{ - Use: types.SubModuleName, - Short: "Solo Machine transaction subcommands", - DisableFlagParsing: true, - SuggestionsMinimumDistance: 2, - RunE: client.ValidateCmd, - } - - txCmd.AddCommand( - NewCreateClientCmd(), - NewUpdateClientCmd(), - NewSubmitMisbehaviourCmd(), - ) - - return txCmd -} diff --git a/x/ibc/light-clients/06-solomachine/client/cli/tx.go b/x/ibc/light-clients/06-solomachine/client/cli/tx.go deleted file mode 100644 index 0fa8eda43c..0000000000 --- a/x/ibc/light-clients/06-solomachine/client/cli/tx.go +++ /dev/null @@ -1,169 +0,0 @@ -package cli - -import ( - "fmt" - "io/ioutil" - "strconv" - - "github.com/pkg/errors" - "github.com/spf13/cobra" - - "github.com/line/lbm-sdk/client" - "github.com/line/lbm-sdk/client/flags" - "github.com/line/lbm-sdk/client/tx" - "github.com/line/lbm-sdk/codec" - "github.com/line/lbm-sdk/version" - clienttypes "github.com/line/lbm-sdk/x/ibc/core/02-client/types" - "github.com/line/lbm-sdk/x/ibc/light-clients/06-solomachine/types" -) - -const ( - flagAllowUpdateAfterProposal = "allow_update_after_proposal" -) - -// NewCreateClientCmd defines the command to create a new solo machine client. -func NewCreateClientCmd() *cobra.Command { - cmd := &cobra.Command{ - Use: "create [sequence] [path/to/consensus_state.json]", - Short: "create new solo machine client", - Long: `create a new solo machine client with the specified identifier and public key - - ConsensusState json example: {"public_key":{"@type":"/lbm.crypto.secp256k1.PubKey","key":"A/3SXL2ONYaOkxpdR5P8tHTlSlPv1AwQwSFxKRee5JQW"},"diversifier":"diversifier","timestamp":"10"}`, - Example: fmt.Sprintf("%s tx ibc %s create [sequence] [path/to/consensus_state] --from node0 --home ../node0/cli --chain-id $CID", version.AppName, types.SubModuleName), - Args: cobra.ExactArgs(2), - RunE: func(cmd *cobra.Command, args []string) error { - clientCtx, err := client.GetClientTxContext(cmd) - if err != nil { - return err - } - sequence, err := strconv.ParseUint(args[0], 10, 64) - if err != nil { - return err - } - - cdc := codec.NewProtoCodec(clientCtx.InterfaceRegistry) - - // attempt to unmarshal consensus state argument - consensusState := &types.ConsensusState{} - if err := cdc.UnmarshalJSON([]byte(args[1]), consensusState); err != nil { - - // check for file path if JSON input is not provided - contents, err := ioutil.ReadFile(args[1]) - if err != nil { - return errors.Wrap(err, "neither JSON input nor path to .json file for consensus state were provided") - } - - if err := cdc.UnmarshalJSON(contents, consensusState); err != nil { - return errors.Wrap(err, "error unmarshalling consensus state file") - } - } - - allowUpdateAfterProposal, _ := cmd.Flags().GetBool(flagAllowUpdateAfterProposal) - - clientState := types.NewClientState(sequence, consensusState, allowUpdateAfterProposal) - msg, err := clienttypes.NewMsgCreateClient(clientState, consensusState, clientCtx.GetFromAddress()) - if err != nil { - return err - } - - if err := msg.ValidateBasic(); err != nil { - return err - } - - return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) - }, - } - - cmd.Flags().Bool(flagAllowUpdateAfterProposal, false, "allow governance proposal to update client") - flags.AddTxFlagsToCmd(cmd) - - return cmd -} - -// NewUpdateClientCmd defines the command to update a solo machine client. -func NewUpdateClientCmd() *cobra.Command { - return &cobra.Command{ - Use: "update [client-id] [path/to/header.json]", - Short: "update existing client with a header", - Long: "update existing client with a solo machine header", - Example: fmt.Sprintf("%s tx ibc %s update [client-id] [path/to/header.json] --from node0 --home ../node0/cli --chain-id $CID", version.AppName, types.SubModuleName), - Args: cobra.ExactArgs(2), - RunE: func(cmd *cobra.Command, args []string) error { - clientCtx, err := client.GetClientTxContext(cmd) - if err != nil { - return err - } - clientID := args[0] - - cdc := codec.NewProtoCodec(clientCtx.InterfaceRegistry) - - header := &types.Header{} - if err := cdc.UnmarshalJSON([]byte(args[1]), header); err != nil { - - // check for file path if JSON input is not provided - contents, err := ioutil.ReadFile(args[1]) - if err != nil { - return errors.Wrap(err, "neither JSON input nor path to .json file for header were provided") - } - - if err := cdc.UnmarshalJSON(contents, header); err != nil { - return errors.Wrap(err, "error unmarshalling header file") - } - } - - msg, err := clienttypes.NewMsgUpdateClient(clientID, header, clientCtx.GetFromAddress()) - if err != nil { - return err - } - - if err := msg.ValidateBasic(); err != nil { - return err - } - - return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) - }, - } -} - -// NewSubmitMisbehaviourCmd defines the command to submit a misbehaviour to prevent -// future updates. -func NewSubmitMisbehaviourCmd() *cobra.Command { - return &cobra.Command{ - Use: "misbehaviour [path/to/misbehaviour.json]", - Short: "submit a client misbehaviour", - Long: "submit a client misbehaviour to prevent future updates", - Example: fmt.Sprintf("%s tx ibc %s misbehaviour [path/to/misbehaviour.json] --from node0 --home ../node0/cli --chain-id $CID", version.AppName, types.SubModuleName), - Args: cobra.ExactArgs(1), - RunE: func(cmd *cobra.Command, args []string) error { - clientCtx, err := client.GetClientTxContext(cmd) - if err != nil { - return err - } - cdc := codec.NewProtoCodec(clientCtx.InterfaceRegistry) - - m := &types.Misbehaviour{} - if err := cdc.UnmarshalJSON([]byte(args[0]), m); err != nil { - - // check for file path if JSON input is not provided - contents, err := ioutil.ReadFile(args[0]) - if err != nil { - return errors.Wrap(err, "neither JSON input nor path to .json file for misbehaviour were provided") - } - - if err := cdc.UnmarshalJSON(contents, m); err != nil { - return errors.Wrap(err, "error unmarshalling misbehaviour file") - } - } - - msg, err := clienttypes.NewMsgSubmitMisbehaviour(m.ClientId, m, clientCtx.GetFromAddress()) - if err != nil { - return err - } - - if err := msg.ValidateBasic(); err != nil { - return err - } - - return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) - }, - } -} diff --git a/x/ibc/light-clients/06-solomachine/module.go b/x/ibc/light-clients/06-solomachine/module.go index dc7604c42d..b41becb189 100644 --- a/x/ibc/light-clients/06-solomachine/module.go +++ b/x/ibc/light-clients/06-solomachine/module.go @@ -1,9 +1,6 @@ package solomachine import ( - "github.com/spf13/cobra" - - "github.com/line/lbm-sdk/x/ibc/light-clients/06-solomachine/client/cli" "github.com/line/lbm-sdk/x/ibc/light-clients/06-solomachine/types" ) @@ -11,8 +8,3 @@ import ( func Name() string { return types.SubModuleName } - -// GetTxCmd returns the root tx command for the solo machine client. -func GetTxCmd() *cobra.Command { - return cli.NewTxCmd() -} diff --git a/x/ibc/light-clients/06-solomachine/spec/01_concepts.md b/x/ibc/light-clients/06-solomachine/spec/01_concepts.md index fd8a4f71b2..de486b71b1 100644 --- a/x/ibc/light-clients/06-solomachine/spec/01_concepts.md +++ b/x/ibc/light-clients/06-solomachine/spec/01_concepts.md @@ -129,17 +129,14 @@ If the update is successful: An update by a governance proposal will only succeed if: -- the header provided is parseable to solo machine header +- the substitute provided is parseable to solo machine client state - the `AllowUpdateAfterProposal` client parameter is set to `true` -- the new header public key does not equal the consensus state public key +- the new consensus state public key does not equal the current consensus state public key If the update is successful: -- the public key is updated -- the diversifier is updated -- the timestamp is updated -- the sequence is updated -- the new consensus state is set in the client state +- the subject client state is updated to the substitute client state +- the subject consensus state is updated to the substitute consensus state - the client is unfrozen (if it was previously frozen) ## Misbehaviour diff --git a/x/ibc/light-clients/06-solomachine/spec/03_state_transitions.md b/x/ibc/light-clients/06-solomachine/spec/03_state_transitions.md index 3ca4b7017a..48a1e18f1c 100644 --- a/x/ibc/light-clients/06-solomachine/spec/03_state_transitions.md +++ b/x/ibc/light-clients/06-solomachine/spec/03_state_transitions.md @@ -24,11 +24,8 @@ A successful update of a solo machine light client by a header will result in: A successful update of a solo machine light client by a governance proposal will result in: -- the public key being updated to the new public key provided by the header. -- the diversifier being updated to the new diviersifier provided by the header. -- the timestamp being updated to the new timestamp provided by the header. -- the sequence being set to the new sequence provided by the header. -- the consensus state being updated (consensus state stores the public key, diversifier, and timestamp) +- the client state being updated to the substitute client state +- the consensus state being updated to the substitute consensus state (consensus state stores the public key, diversifier, and timestamp) - the frozen sequence being set to zero (client is unfrozen if it was previously frozen). ## Upgrade diff --git a/x/ibc/light-clients/06-solomachine/types/client_state.go b/x/ibc/light-clients/06-solomachine/types/client_state.go index 1a3bbeb6ee..01ef61aeac 100644 --- a/x/ibc/light-clients/06-solomachine/types/client_state.go +++ b/x/ibc/light-clients/06-solomachine/types/client_state.go @@ -77,7 +77,7 @@ func (cs ClientState) ZeroCustomFields() exported.ClientState { } // Initialize will check that initial consensus state is equal to the latest consensus state of the initial client. -func (cs ClientState) Initialize(_ sdk.Context, _ codec.BinaryMarshaler, _ sdk.KVStore, consState exported.ConsensusState) error { +func (cs ClientState) Initialize(_ sdk.Context, _ codec.Codec, _ sdk.KVStore, consState exported.ConsensusState) error { if !reflect.DeepEqual(cs.ConsensusState, consState) { return sdkerrors.Wrapf(clienttypes.ErrInvalidConsensus, "consensus state in initial client does not equal initial consensus state. expected: %s, got: %s", cs.ConsensusState, consState) @@ -92,7 +92,7 @@ func (cs ClientState) ExportMetadata(_ sdk.KVStore) []exported.GenesisMetadata { // VerifyUpgradeAndUpdateState returns an error since solomachine client does not support upgrades func (cs ClientState) VerifyUpgradeAndUpdateState( - _ sdk.Context, _ codec.BinaryMarshaler, _ sdk.KVStore, + _ sdk.Context, _ codec.Codec, _ sdk.KVStore, _ exported.ClientState, _ exported.ConsensusState, _, _ []byte, ) (exported.ClientState, exported.ConsensusState, error) { return nil, nil, sdkerrors.Wrap(clienttypes.ErrInvalidUpgradeClient, "cannot upgrade solomachine client") @@ -102,7 +102,7 @@ func (cs ClientState) VerifyUpgradeAndUpdateState( // stored on the solo machine. func (cs ClientState) VerifyClientState( store sdk.KVStore, - cdc codec.BinaryMarshaler, + cdc codec.Codec, height exported.Height, prefix exported.Prefix, counterpartyClientIdentifier string, @@ -139,7 +139,7 @@ func (cs ClientState) VerifyClientState( // running chain stored on the solo machine. func (cs ClientState) VerifyClientConsensusState( store sdk.KVStore, - cdc codec.BinaryMarshaler, + cdc codec.Codec, height exported.Height, counterpartyClientIdentifier string, consensusHeight exported.Height, @@ -177,7 +177,7 @@ func (cs ClientState) VerifyClientConsensusState( // specified connection end stored on the target machine. func (cs ClientState) VerifyConnectionState( store sdk.KVStore, - cdc codec.BinaryMarshaler, + cdc codec.Codec, height exported.Height, prefix exported.Prefix, proof []byte, @@ -214,7 +214,7 @@ func (cs ClientState) VerifyConnectionState( // channel end, under the specified port, stored on the target machine. func (cs ClientState) VerifyChannelState( store sdk.KVStore, - cdc codec.BinaryMarshaler, + cdc codec.Codec, height exported.Height, prefix exported.Prefix, proof []byte, @@ -252,7 +252,7 @@ func (cs ClientState) VerifyChannelState( // the specified port, specified channel, and specified sequence. func (cs ClientState) VerifyPacketCommitment( store sdk.KVStore, - cdc codec.BinaryMarshaler, + cdc codec.Codec, height exported.Height, _ uint64, _ uint64, @@ -293,7 +293,7 @@ func (cs ClientState) VerifyPacketCommitment( // acknowledgement at the specified port, specified channel, and specified sequence. func (cs ClientState) VerifyPacketAcknowledgement( store sdk.KVStore, - cdc codec.BinaryMarshaler, + cdc codec.Codec, height exported.Height, _ uint64, _ uint64, @@ -335,7 +335,7 @@ func (cs ClientState) VerifyPacketAcknowledgement( // specified sequence. func (cs ClientState) VerifyPacketReceiptAbsence( store sdk.KVStore, - cdc codec.BinaryMarshaler, + cdc codec.Codec, height exported.Height, _ uint64, _ uint64, @@ -375,7 +375,7 @@ func (cs ClientState) VerifyPacketReceiptAbsence( // received of the specified channel at the specified port. func (cs ClientState) VerifyNextSequenceRecv( store sdk.KVStore, - cdc codec.BinaryMarshaler, + cdc codec.Codec, height exported.Height, _ uint64, _ uint64, @@ -416,7 +416,7 @@ func (cs ClientState) VerifyNextSequenceRecv( // consensus state, the unmarshalled proof representing the signature and timestamp // along with the solo-machine sequence encoded in the proofHeight. func produceVerificationArgs( - cdc codec.BinaryMarshaler, + cdc codec.Codec, cs ClientState, height exported.Height, prefix exported.Prefix, @@ -445,7 +445,7 @@ func produceVerificationArgs( } timestampedSigData := &TimestampedSignatureData{} - if err := cdc.UnmarshalBinaryBare(proof, timestampedSigData); err != nil { + if err := cdc.Unmarshal(proof, timestampedSigData); err != nil { return nil, nil, 0, 0, sdkerrors.Wrapf(err, "failed to unmarshal proof into type %T", timestampedSigData) } @@ -485,7 +485,7 @@ func produceVerificationArgs( } // sets the client state to the store -func setClientState(store sdk.KVStore, cdc codec.BinaryMarshaler, clientState exported.ClientState) { +func setClientState(store sdk.KVStore, cdc codec.Codec, clientState exported.ClientState) { bz := clienttypes.MustMarshalClientState(cdc, clientState) store.Set([]byte(host.KeyClientState), bz) } diff --git a/x/ibc/light-clients/06-solomachine/types/client_state_test.go b/x/ibc/light-clients/06-solomachine/types/client_state_test.go index 1a7bde8d56..677056fdf5 100644 --- a/x/ibc/light-clients/06-solomachine/types/client_state_test.go +++ b/x/ibc/light-clients/06-solomachine/types/client_state_test.go @@ -149,7 +149,7 @@ func (suite *SoloMachineTestSuite) TestVerifyClientState() { Timestamp: solomachine.Time, } - proof, err := suite.chainA.Codec.MarshalBinaryBare(signatureDoc) + proof, err := suite.chainA.Codec.Marshal(signatureDoc) suite.Require().NoError(err) testCases := []struct { @@ -277,7 +277,7 @@ func (suite *SoloMachineTestSuite) TestVerifyClientConsensusState() { Timestamp: solomachine.Time, } - proof, err := suite.chainA.Codec.MarshalBinaryBare(signatureDoc) + proof, err := suite.chainA.Codec.Marshal(signatureDoc) suite.Require().NoError(err) testCases := []struct { @@ -402,7 +402,7 @@ func (suite *SoloMachineTestSuite) TestVerifyConnectionState() { Timestamp: solomachine.Time, } - proof, err := suite.chainA.Codec.MarshalBinaryBare(signatureDoc) + proof, err := suite.chainA.Codec.Marshal(signatureDoc) suite.Require().NoError(err) testCases := []struct { @@ -491,7 +491,7 @@ func (suite *SoloMachineTestSuite) TestVerifyChannelState() { Timestamp: solomachine.Time, } - proof, err := suite.chainA.Codec.MarshalBinaryBare(signatureDoc) + proof, err := suite.chainA.Codec.Marshal(signatureDoc) suite.Require().NoError(err) testCases := []struct { @@ -579,7 +579,7 @@ func (suite *SoloMachineTestSuite) TestVerifyPacketCommitment() { Timestamp: solomachine.Time, } - proof, err := suite.chainA.Codec.MarshalBinaryBare(signatureDoc) + proof, err := suite.chainA.Codec.Marshal(signatureDoc) suite.Require().NoError(err) testCases := []struct { @@ -666,7 +666,7 @@ func (suite *SoloMachineTestSuite) TestVerifyPacketAcknowledgement() { Timestamp: solomachine.Time, } - proof, err := suite.chainA.Codec.MarshalBinaryBare(signatureDoc) + proof, err := suite.chainA.Codec.Marshal(signatureDoc) suite.Require().NoError(err) testCases := []struct { @@ -753,7 +753,7 @@ func (suite *SoloMachineTestSuite) TestVerifyPacketReceiptAbsence() { Timestamp: solomachine.Time, } - proof, err := suite.chainA.Codec.MarshalBinaryBare(signatureDoc) + proof, err := suite.chainA.Codec.Marshal(signatureDoc) suite.Require().NoError(err) testCases := []struct { @@ -840,7 +840,7 @@ func (suite *SoloMachineTestSuite) TestVerifyNextSeqRecv() { Timestamp: solomachine.Time, } - proof, err := suite.chainA.Codec.MarshalBinaryBare(signatureDoc) + proof, err := suite.chainA.Codec.Marshal(signatureDoc) suite.Require().NoError(err) testCases := []struct { diff --git a/x/ibc/light-clients/06-solomachine/types/codec.go b/x/ibc/light-clients/06-solomachine/types/codec.go index 2d367e64e1..5ae6ec50cf 100644 --- a/x/ibc/light-clients/06-solomachine/types/codec.go +++ b/x/ibc/light-clients/06-solomachine/types/codec.go @@ -30,9 +30,9 @@ func RegisterInterfaces(registry codectypes.InterfaceRegistry) { ) } -func UnmarshalSignatureData(cdc codec.BinaryMarshaler, data []byte) (signing.SignatureData, error) { +func UnmarshalSignatureData(cdc codec.Codec, data []byte) (signing.SignatureData, error) { protoSigData := &signing.SignatureDescriptor_Data{} - if err := cdc.UnmarshalBinaryBare(data, protoSigData); err != nil { + if err := cdc.Unmarshal(data, protoSigData); err != nil { return nil, sdkerrors.Wrapf(err, "failed to unmarshal proof into type %T", protoSigData) } @@ -43,7 +43,7 @@ func UnmarshalSignatureData(cdc codec.BinaryMarshaler, data []byte) (signing.Sig // UnmarshalDataByType attempts to unmarshal the data to the specified type. An error is // return if it fails. -func UnmarshalDataByType(cdc codec.BinaryMarshaler, dataType DataType, data []byte) (Data, error) { +func UnmarshalDataByType(cdc codec.Codec, dataType DataType, data []byte) (Data, error) { if len(data) == 0 { return nil, sdkerrors.Wrap(ErrInvalidSignatureAndData, "data cannot be empty") } @@ -54,7 +54,7 @@ func UnmarshalDataByType(cdc codec.BinaryMarshaler, dataType DataType, data []by case CLIENT: clientData := &ClientStateData{} - if err := cdc.UnmarshalBinaryBare(data, clientData); err != nil { + if err := cdc.Unmarshal(data, clientData); err != nil { return nil, err } @@ -66,7 +66,7 @@ func UnmarshalDataByType(cdc codec.BinaryMarshaler, dataType DataType, data []by case CONSENSUS: consensusData := &ConsensusStateData{} - if err := cdc.UnmarshalBinaryBare(data, consensusData); err != nil { + if err := cdc.Unmarshal(data, consensusData); err != nil { return nil, err } @@ -78,7 +78,7 @@ func UnmarshalDataByType(cdc codec.BinaryMarshaler, dataType DataType, data []by case CONNECTION: connectionData := &ConnectionStateData{} - if err := cdc.UnmarshalBinaryBare(data, connectionData); err != nil { + if err := cdc.Unmarshal(data, connectionData); err != nil { return nil, err } @@ -86,7 +86,7 @@ func UnmarshalDataByType(cdc codec.BinaryMarshaler, dataType DataType, data []by case CHANNEL: channelData := &ChannelStateData{} - if err := cdc.UnmarshalBinaryBare(data, channelData); err != nil { + if err := cdc.Unmarshal(data, channelData); err != nil { return nil, err } @@ -94,7 +94,7 @@ func UnmarshalDataByType(cdc codec.BinaryMarshaler, dataType DataType, data []by case PACKETCOMMITMENT: commitmentData := &PacketCommitmentData{} - if err := cdc.UnmarshalBinaryBare(data, commitmentData); err != nil { + if err := cdc.Unmarshal(data, commitmentData); err != nil { return nil, err } @@ -102,7 +102,7 @@ func UnmarshalDataByType(cdc codec.BinaryMarshaler, dataType DataType, data []by case PACKETACKNOWLEDGEMENT: ackData := &PacketAcknowledgementData{} - if err := cdc.UnmarshalBinaryBare(data, ackData); err != nil { + if err := cdc.Unmarshal(data, ackData); err != nil { return nil, err } @@ -110,7 +110,7 @@ func UnmarshalDataByType(cdc codec.BinaryMarshaler, dataType DataType, data []by case PACKETRECEIPTABSENCE: receiptAbsenceData := &PacketReceiptAbsenceData{} - if err := cdc.UnmarshalBinaryBare(data, receiptAbsenceData); err != nil { + if err := cdc.Unmarshal(data, receiptAbsenceData); err != nil { return nil, err } @@ -118,7 +118,7 @@ func UnmarshalDataByType(cdc codec.BinaryMarshaler, dataType DataType, data []by case NEXTSEQUENCERECV: nextSeqRecvData := &NextSequenceRecvData{} - if err := cdc.UnmarshalBinaryBare(data, nextSeqRecvData); err != nil { + if err := cdc.Unmarshal(data, nextSeqRecvData); err != nil { return nil, err } diff --git a/x/ibc/light-clients/06-solomachine/types/misbehaviour.go b/x/ibc/light-clients/06-solomachine/types/misbehaviour.go index 12bc796647..42210e16fc 100644 --- a/x/ibc/light-clients/06-solomachine/types/misbehaviour.go +++ b/x/ibc/light-clients/06-solomachine/types/misbehaviour.go @@ -9,9 +9,7 @@ import ( "github.com/line/lbm-sdk/x/ibc/core/exported" ) -var ( - _ exported.Misbehaviour = (*Misbehaviour)(nil) -) +var _ exported.Misbehaviour = &Misbehaviour{} // ClientType is a Solo Machine light client. func (misbehaviour Misbehaviour) ClientType() string { diff --git a/x/ibc/light-clients/06-solomachine/types/misbehaviour_handle.go b/x/ibc/light-clients/06-solomachine/types/misbehaviour_handle.go index 55e351eec5..0f9c08c93e 100644 --- a/x/ibc/light-clients/06-solomachine/types/misbehaviour_handle.go +++ b/x/ibc/light-clients/06-solomachine/types/misbehaviour_handle.go @@ -16,7 +16,7 @@ import ( // order processing dependent. func (cs ClientState) CheckMisbehaviourAndUpdateState( ctx sdk.Context, - cdc codec.BinaryMarshaler, + cdc codec.Codec, clientStore sdk.KVStore, misbehaviour exported.Misbehaviour, ) (exported.ClientState, error) { @@ -53,7 +53,7 @@ func (cs ClientState) CheckMisbehaviourAndUpdateState( // verifySignatureAndData verifies that the currently registered public key has signed // over the provided data and that the data is valid. The data is valid if it can be // unmarshaled into the specified data type. -func verifySignatureAndData(cdc codec.BinaryMarshaler, clientState ClientState, misbehaviour *Misbehaviour, sigAndData *SignatureAndData) error { +func verifySignatureAndData(cdc codec.Codec, clientState ClientState, misbehaviour *Misbehaviour, sigAndData *SignatureAndData) error { // do not check misbehaviour timestamp since we want to allow processing of past misbehaviour diff --git a/x/ibc/light-clients/06-solomachine/types/misbehaviour_handle_test.go b/x/ibc/light-clients/06-solomachine/types/misbehaviour_handle_test.go index 33f0b97424..8aa0d628de 100644 --- a/x/ibc/light-clients/06-solomachine/types/misbehaviour_handle_test.go +++ b/x/ibc/light-clients/06-solomachine/types/misbehaviour_handle_test.go @@ -120,7 +120,7 @@ func (suite *SoloMachineTestSuite) TestCheckMisbehaviourAndUpdateState() { Data: msg, } - data, err := suite.chainA.Codec.MarshalBinaryBare(signBytes) + data, err := suite.chainA.Codec.Marshal(signBytes) suite.Require().NoError(err) sig := solomachine.GenerateSignature(data) @@ -148,7 +148,7 @@ func (suite *SoloMachineTestSuite) TestCheckMisbehaviourAndUpdateState() { Data: msg, } - data, err := suite.chainA.Codec.MarshalBinaryBare(signBytes) + data, err := suite.chainA.Codec.Marshal(signBytes) suite.Require().NoError(err) sig := solomachine.GenerateSignature(data) @@ -209,7 +209,7 @@ func (suite *SoloMachineTestSuite) TestCheckMisbehaviourAndUpdateState() { Data: msg, } - data, err := suite.chainA.Codec.MarshalBinaryBare(signBytes) + data, err := suite.chainA.Codec.Marshal(signBytes) suite.Require().NoError(err) sig := solomachine.GenerateSignature(data) @@ -228,7 +228,7 @@ func (suite *SoloMachineTestSuite) TestCheckMisbehaviourAndUpdateState() { DataType: types.CLIENT, Data: msg, } - data, err = suite.chainA.Codec.MarshalBinaryBare(signBytes) + data, err = suite.chainA.Codec.Marshal(signBytes) suite.Require().NoError(err) sig = solomachine.GenerateSignature(data) diff --git a/x/ibc/light-clients/06-solomachine/types/proof.go b/x/ibc/light-clients/06-solomachine/types/proof.go index a5bdb8380c..1b4afea708 100644 --- a/x/ibc/light-clients/06-solomachine/types/proof.go +++ b/x/ibc/light-clients/06-solomachine/types/proof.go @@ -50,7 +50,7 @@ func VerifySignature(pubKey cryptotypes.PubKey, signBytes []byte, sigData signin // MisbehaviourSignBytes returns the sign bytes for verification of misbehaviour. func MisbehaviourSignBytes( - cdc codec.BinaryMarshaler, + cdc codec.Codec, sequence, timestamp uint64, diversifier string, dataType DataType, @@ -63,12 +63,12 @@ func MisbehaviourSignBytes( Data: data, } - return cdc.MarshalBinaryBare(signBytes) + return cdc.Marshal(signBytes) } // HeaderSignBytes returns the sign bytes for verification of misbehaviour. func HeaderSignBytes( - cdc codec.BinaryMarshaler, + cdc codec.Codec, header *Header, ) ([]byte, error) { data := &HeaderData{ @@ -76,7 +76,7 @@ func HeaderSignBytes( NewDiversifier: header.NewDiversifier, } - dataBz, err := cdc.MarshalBinaryBare(data) + dataBz, err := cdc.Marshal(data) if err != nil { return nil, err } @@ -89,13 +89,13 @@ func HeaderSignBytes( Data: dataBz, } - return cdc.MarshalBinaryBare(signBytes) + return cdc.Marshal(signBytes) } // ClientStateSignBytes returns the sign bytes for verification of the // client state. func ClientStateSignBytes( - cdc codec.BinaryMarshaler, + cdc codec.Codec, sequence, timestamp uint64, diversifier string, path commitmenttypes.MerklePath, @@ -114,13 +114,13 @@ func ClientStateSignBytes( Data: dataBz, } - return cdc.MarshalBinaryBare(signBytes) + return cdc.Marshal(signBytes) } // ClientStateDataBytes returns the client state data bytes used in constructing // SignBytes. func ClientStateDataBytes( - cdc codec.BinaryMarshaler, + cdc codec.Codec, path commitmenttypes.MerklePath, // nolint: interfacer clientState exported.ClientState, ) ([]byte, error) { @@ -134,7 +134,7 @@ func ClientStateDataBytes( ClientState: any, } - dataBz, err := cdc.MarshalBinaryBare(data) + dataBz, err := cdc.Marshal(data) if err != nil { return nil, err } @@ -145,7 +145,7 @@ func ClientStateDataBytes( // ConsensusStateSignBytes returns the sign bytes for verification of the // consensus state. func ConsensusStateSignBytes( - cdc codec.BinaryMarshaler, + cdc codec.Codec, sequence, timestamp uint64, diversifier string, path commitmenttypes.MerklePath, @@ -164,13 +164,13 @@ func ConsensusStateSignBytes( Data: dataBz, } - return cdc.MarshalBinaryBare(signBytes) + return cdc.Marshal(signBytes) } // ConsensusStateDataBytes returns the consensus state data bytes used in constructing // SignBytes. func ConsensusStateDataBytes( - cdc codec.BinaryMarshaler, + cdc codec.Codec, path commitmenttypes.MerklePath, // nolint: interfacer consensusState exported.ConsensusState, ) ([]byte, error) { @@ -184,7 +184,7 @@ func ConsensusStateDataBytes( ConsensusState: any, } - dataBz, err := cdc.MarshalBinaryBare(data) + dataBz, err := cdc.Marshal(data) if err != nil { return nil, err } @@ -195,7 +195,7 @@ func ConsensusStateDataBytes( // ConnectionStateSignBytes returns the sign bytes for verification of the // connection state. func ConnectionStateSignBytes( - cdc codec.BinaryMarshaler, + cdc codec.Codec, sequence, timestamp uint64, diversifier string, path commitmenttypes.MerklePath, @@ -214,13 +214,13 @@ func ConnectionStateSignBytes( Data: dataBz, } - return cdc.MarshalBinaryBare(signBytes) + return cdc.Marshal(signBytes) } // ConnectionStateDataBytes returns the connection state data bytes used in constructing // SignBytes. func ConnectionStateDataBytes( - cdc codec.BinaryMarshaler, + cdc codec.Codec, path commitmenttypes.MerklePath, // nolint: interfacer connectionEnd exported.ConnectionI, ) ([]byte, error) { @@ -237,7 +237,7 @@ func ConnectionStateDataBytes( Connection: &connection, } - dataBz, err := cdc.MarshalBinaryBare(data) + dataBz, err := cdc.Marshal(data) if err != nil { return nil, err } @@ -248,7 +248,7 @@ func ConnectionStateDataBytes( // ChannelStateSignBytes returns the sign bytes for verification of the // channel state. func ChannelStateSignBytes( - cdc codec.BinaryMarshaler, + cdc codec.Codec, sequence, timestamp uint64, diversifier string, path commitmenttypes.MerklePath, @@ -267,13 +267,13 @@ func ChannelStateSignBytes( Data: dataBz, } - return cdc.MarshalBinaryBare(signBytes) + return cdc.Marshal(signBytes) } // ChannelStateDataBytes returns the channel state data bytes used in constructing // SignBytes. func ChannelStateDataBytes( - cdc codec.BinaryMarshaler, + cdc codec.Codec, path commitmenttypes.MerklePath, // nolint: interfacer channelEnd exported.ChannelI, ) ([]byte, error) { @@ -289,7 +289,7 @@ func ChannelStateDataBytes( Channel: &channel, } - dataBz, err := cdc.MarshalBinaryBare(data) + dataBz, err := cdc.Marshal(data) if err != nil { return nil, err } @@ -300,7 +300,7 @@ func ChannelStateDataBytes( // PacketCommitmentSignBytes returns the sign bytes for verification of the // packet commitment. func PacketCommitmentSignBytes( - cdc codec.BinaryMarshaler, + cdc codec.Codec, sequence, timestamp uint64, diversifier string, path commitmenttypes.MerklePath, @@ -319,13 +319,13 @@ func PacketCommitmentSignBytes( Data: dataBz, } - return cdc.MarshalBinaryBare(signBytes) + return cdc.Marshal(signBytes) } // PacketCommitmentDataBytes returns the packet commitment data bytes used in constructing // SignBytes. func PacketCommitmentDataBytes( - cdc codec.BinaryMarshaler, + cdc codec.Codec, path commitmenttypes.MerklePath, // nolint: interfacer commitmentBytes []byte, ) ([]byte, error) { @@ -334,7 +334,7 @@ func PacketCommitmentDataBytes( Commitment: commitmentBytes, } - dataBz, err := cdc.MarshalBinaryBare(data) + dataBz, err := cdc.Marshal(data) if err != nil { return nil, err } @@ -345,7 +345,7 @@ func PacketCommitmentDataBytes( // PacketAcknowledgementSignBytes returns the sign bytes for verification of // the acknowledgement. func PacketAcknowledgementSignBytes( - cdc codec.BinaryMarshaler, + cdc codec.Codec, sequence, timestamp uint64, diversifier string, path commitmenttypes.MerklePath, @@ -364,13 +364,13 @@ func PacketAcknowledgementSignBytes( Data: dataBz, } - return cdc.MarshalBinaryBare(signBytes) + return cdc.Marshal(signBytes) } // PacketAcknowledgementDataBytes returns the packet acknowledgement data bytes used in constructing // SignBytes. func PacketAcknowledgementDataBytes( - cdc codec.BinaryMarshaler, + cdc codec.Codec, path commitmenttypes.MerklePath, // nolint: interfacer acknowledgement []byte, ) ([]byte, error) { @@ -379,7 +379,7 @@ func PacketAcknowledgementDataBytes( Acknowledgement: acknowledgement, } - dataBz, err := cdc.MarshalBinaryBare(data) + dataBz, err := cdc.Marshal(data) if err != nil { return nil, err } @@ -390,7 +390,7 @@ func PacketAcknowledgementDataBytes( // PacketReceiptAbsenceSignBytes returns the sign bytes for verification // of the absence of an receipt. func PacketReceiptAbsenceSignBytes( - cdc codec.BinaryMarshaler, + cdc codec.Codec, sequence, timestamp uint64, diversifier string, path commitmenttypes.MerklePath, @@ -408,20 +408,20 @@ func PacketReceiptAbsenceSignBytes( Data: dataBz, } - return cdc.MarshalBinaryBare(signBytes) + return cdc.Marshal(signBytes) } // PacketReceiptAbsenceDataBytes returns the packet receipt absence data bytes // used in constructing SignBytes. func PacketReceiptAbsenceDataBytes( - cdc codec.BinaryMarshaler, + cdc codec.Codec, path commitmenttypes.MerklePath, // nolint: interfacer ) ([]byte, error) { data := &PacketReceiptAbsenceData{ Path: []byte(path.String()), } - dataBz, err := cdc.MarshalBinaryBare(data) + dataBz, err := cdc.Marshal(data) if err != nil { return nil, err } @@ -432,7 +432,7 @@ func PacketReceiptAbsenceDataBytes( // NextSequenceRecvSignBytes returns the sign bytes for verification of the next // sequence to be received. func NextSequenceRecvSignBytes( - cdc codec.BinaryMarshaler, + cdc codec.Codec, sequence, timestamp uint64, diversifier string, path commitmenttypes.MerklePath, @@ -451,13 +451,13 @@ func NextSequenceRecvSignBytes( Data: dataBz, } - return cdc.MarshalBinaryBare(signBytes) + return cdc.Marshal(signBytes) } // NextSequenceRecvDataBytes returns the next sequence recv data bytes used in constructing // SignBytes. func NextSequenceRecvDataBytes( - cdc codec.BinaryMarshaler, + cdc codec.Codec, path commitmenttypes.MerklePath, // nolint: interfacer nextSequenceRecv uint64, ) ([]byte, error) { @@ -466,7 +466,7 @@ func NextSequenceRecvDataBytes( NextSeqRecv: nextSequenceRecv, } - dataBz, err := cdc.MarshalBinaryBare(data) + dataBz, err := cdc.Marshal(data) if err != nil { return nil, err } diff --git a/x/ibc/light-clients/06-solomachine/types/proposal_handle.go b/x/ibc/light-clients/06-solomachine/types/proposal_handle.go index 1908bb66c5..e485591dd4 100644 --- a/x/ibc/light-clients/06-solomachine/types/proposal_handle.go +++ b/x/ibc/light-clients/06-solomachine/types/proposal_handle.go @@ -10,56 +10,55 @@ import ( "github.com/line/lbm-sdk/x/ibc/core/exported" ) -// CheckProposedHeaderAndUpdateState updates the consensus state to the header's sequence and -// public key. An error is returned if the client has been disallowed to be updated by a -// governance proposal, the header cannot be casted to a solo machine header, or the current -// public key equals the new public key. -func (cs ClientState) CheckProposedHeaderAndUpdateState( - ctx sdk.Context, cdc codec.BinaryMarshaler, clientStore sdk.KVStore, - header exported.Header, -) (exported.ClientState, exported.ConsensusState, error) { +// CheckSubstituteAndUpdateState verifies that the subject is allowed to be updated by +// a governance proposal and that the substitute client is a solo machine. +// It will update the consensus state to the substitute's consensus state and +// the sequence to the substitute's current sequence. An error is returned if +// the client has been disallowed to be updated by a governance proposal, +// the substitute is not a solo machine, or the current public key equals +// the new public key. +func (cs ClientState) CheckSubstituteAndUpdateState( + ctx sdk.Context, cdc codec.Codec, subjectClientStore, + _ sdk.KVStore, substituteClient exported.ClientState, + _ exported.Height, +) (exported.ClientState, error) { if !cs.AllowUpdateAfterProposal { - return nil, nil, sdkerrors.Wrapf( + return nil, sdkerrors.Wrapf( clienttypes.ErrUpdateClientFailed, "solo machine client is not allowed to updated with a proposal", ) } - smHeader, ok := header.(*Header) + substituteClientState, ok := substituteClient.(*ClientState) if !ok { - return nil, nil, sdkerrors.Wrapf( - clienttypes.ErrInvalidHeader, "header type %T, expected %T", header, &Header{}, + return nil, sdkerrors.Wrapf( + clienttypes.ErrInvalidClientType, "substitute client state type %T, expected %T", substituteClient, &ClientState{}, ) } - consensusPublicKey, err := cs.ConsensusState.GetPubKey() + subjectPublicKey, err := cs.ConsensusState.GetPubKey() if err != nil { - return nil, nil, sdkerrors.Wrap(err, "failed to get consensus public key") + return nil, sdkerrors.Wrap(err, "failed to get consensus public key") } - headerPublicKey, err := smHeader.GetPubKey() + substitutePublicKey, err := substituteClientState.ConsensusState.GetPubKey() if err != nil { - return nil, nil, sdkerrors.Wrap(err, "failed to get header public key") + return nil, sdkerrors.Wrap(err, "failed to get substitute client public key") } - if reflect.DeepEqual(consensusPublicKey, headerPublicKey) { - return nil, nil, sdkerrors.Wrapf( - clienttypes.ErrInvalidHeader, "new public key in header equals current public key", + if reflect.DeepEqual(subjectPublicKey, substitutePublicKey) { + return nil, sdkerrors.Wrapf( + clienttypes.ErrInvalidHeader, "subject and substitute have the same public key", ) } clientState := &cs - consensusState := &ConsensusState{ - PublicKey: smHeader.NewPublicKey, - Diversifier: smHeader.NewDiversifier, - Timestamp: smHeader.Timestamp, - } - - clientState.Sequence = smHeader.Sequence - clientState.ConsensusState = consensusState + // update to substitute parameters + clientState.Sequence = substituteClientState.Sequence + clientState.ConsensusState = substituteClientState.ConsensusState clientState.FrozenSequence = 0 - return clientState, consensusState, nil + return clientState, nil } diff --git a/x/ibc/light-clients/06-solomachine/types/proposal_handle_test.go b/x/ibc/light-clients/06-solomachine/types/proposal_handle_test.go index 5089d547ca..b35be45553 100644 --- a/x/ibc/light-clients/06-solomachine/types/proposal_handle_test.go +++ b/x/ibc/light-clients/06-solomachine/types/proposal_handle_test.go @@ -7,8 +7,11 @@ import ( ibctesting "github.com/line/lbm-sdk/x/ibc/testing" ) -func (suite *SoloMachineTestSuite) TestCheckProposedHeaderAndUpdateState() { - var header exported.Header +func (suite *SoloMachineTestSuite) TestCheckSubstituteAndUpdateState() { + var ( + subjectClientState *types.ClientState + substituteClientState exported.ClientState + ) // test singlesig and multisig public keys for _, solomachine := range []*ibctesting.Solomachine{suite.solomachine, suite.solomachineMulti} { @@ -19,21 +22,34 @@ func (suite *SoloMachineTestSuite) TestCheckProposedHeaderAndUpdateState() { expPass bool }{ { - "valid header", func() { - header = solomachine.CreateHeader() + "valid substitute", func() { + subjectClientState.AllowUpdateAfterProposal = true }, true, }, { - "nil header", func() { - header = &ibctmtypes.Header{} + "subject not allowed to be updated", func() { + subjectClientState.AllowUpdateAfterProposal = false }, false, }, { - "header does not update public key", func() { - header = &types.Header{ - Sequence: 1, - NewPublicKey: solomachine.ConsensusState().PublicKey, - } + "substitute is not the solo machine", func() { + substituteClientState = &ibctmtypes.ClientState{} + }, false, + }, + { + "subject public key is nil", func() { + subjectClientState.ConsensusState.PublicKey = nil + }, false, + }, + + { + "substitute public key is nil", func() { + substituteClientState.(*types.ClientState).ConsensusState.PublicKey = nil + }, false, + }, + { + "subject and substitute use the same public key", func() { + substituteClientState.(*types.ClientState).ConsensusState.PublicKey = subjectClientState.ConsensusState.PublicKey }, false, }, } @@ -44,46 +60,27 @@ func (suite *SoloMachineTestSuite) TestCheckProposedHeaderAndUpdateState() { suite.Run(tc.name, func() { suite.SetupTest() - clientState := solomachine.ClientState() + subjectClientState = solomachine.ClientState() + subjectClientState.AllowUpdateAfterProposal = true + substitute := ibctesting.NewSolomachine(suite.T(), suite.chainA.Codec, "substitute", "testing", 5) + substituteClientState = substitute.ClientState() tc.malleate() - clientStore := suite.chainA.App.IBCKeeper.ClientKeeper.ClientStore(suite.chainA.GetContext(), solomachine.ClientID) - - // all cases should always fail if the client has 'AllowUpdateAfterProposal' set to false - clientState.AllowUpdateAfterProposal = false - cs, consState, err := clientState.CheckProposedHeaderAndUpdateState(suite.chainA.GetContext(), suite.chainA.App.AppCodec(), clientStore, header) - suite.Require().Error(err) - suite.Require().Nil(cs) - suite.Require().Nil(consState) + subjectClientStore := suite.chainA.App.IBCKeeper.ClientKeeper.ClientStore(suite.chainA.GetContext(), solomachine.ClientID) + substituteClientStore := suite.chainA.App.IBCKeeper.ClientKeeper.ClientStore(suite.chainA.GetContext(), substitute.ClientID) - clientState.AllowUpdateAfterProposal = true - cs, consState, err = clientState.CheckProposedHeaderAndUpdateState(suite.chainA.GetContext(), suite.chainA.App.AppCodec(), clientStore, header) + updatedClient, err := subjectClientState.CheckSubstituteAndUpdateState(suite.chainA.GetContext(), suite.chainA.App.AppCodec(), subjectClientStore, substituteClientStore, substituteClientState, nil) if tc.expPass { suite.Require().NoError(err) - smConsState, ok := consState.(*types.ConsensusState) - suite.Require().True(ok) - smHeader, ok := header.(*types.Header) - suite.Require().True(ok) - - suite.Require().Equal(cs.(*types.ClientState).ConsensusState, consState) - - headerPubKey, err := smHeader.GetPubKey() - suite.Require().NoError(err) - - consStatePubKey, err := smConsState.GetPubKey() - suite.Require().NoError(err) - - suite.Require().Equal(headerPubKey, consStatePubKey) - suite.Require().Equal(smHeader.NewDiversifier, smConsState.Diversifier) - suite.Require().Equal(smHeader.Timestamp, smConsState.Timestamp) - suite.Require().Equal(smHeader.GetHeight().GetRevisionHeight(), cs.(*types.ClientState).Sequence) + suite.Require().Equal(substituteClientState.(*types.ClientState).ConsensusState, updatedClient.(*types.ClientState).ConsensusState) + suite.Require().Equal(substituteClientState.(*types.ClientState).Sequence, updatedClient.(*types.ClientState).Sequence) + suite.Require().Equal(uint64(0), updatedClient.(*types.ClientState).FrozenSequence) } else { suite.Require().Error(err) - suite.Require().Nil(cs) - suite.Require().Nil(consState) + suite.Require().Nil(updatedClient) } }) } diff --git a/x/ibc/light-clients/06-solomachine/types/solomachine_test.go b/x/ibc/light-clients/06-solomachine/types/solomachine_test.go index db54c80fe9..c83f7cd17b 100644 --- a/x/ibc/light-clients/06-solomachine/types/solomachine_test.go +++ b/x/ibc/light-clients/06-solomachine/types/solomachine_test.go @@ -58,7 +58,7 @@ func (suite *SoloMachineTestSuite) GetSequenceFromStore() uint64 { } func (suite *SoloMachineTestSuite) GetInvalidProof() []byte { - invalidProof, err := suite.chainA.Codec.MarshalBinaryBare(&types.TimestampedSignatureData{Timestamp: suite.solomachine.Time}) + invalidProof, err := suite.chainA.Codec.Marshal(&types.TimestampedSignatureData{Timestamp: suite.solomachine.Time}) suite.Require().NoError(err) return invalidProof diff --git a/x/ibc/light-clients/06-solomachine/types/update.go b/x/ibc/light-clients/06-solomachine/types/update.go index 5dbe16c2f5..b0fa23bc1e 100644 --- a/x/ibc/light-clients/06-solomachine/types/update.go +++ b/x/ibc/light-clients/06-solomachine/types/update.go @@ -15,7 +15,7 @@ import ( // - the header timestamp is less than the consensus state timestamp // - the currently registered public key did not provide the update signature func (cs ClientState) CheckHeaderAndUpdateState( - ctx sdk.Context, cdc codec.BinaryMarshaler, clientStore sdk.KVStore, + ctx sdk.Context, cdc codec.Codec, clientStore sdk.KVStore, header exported.Header, ) (exported.ClientState, exported.ConsensusState, error) { smHeader, ok := header.(*Header) @@ -34,7 +34,7 @@ func (cs ClientState) CheckHeaderAndUpdateState( } // checkHeader checks if the Solo Machine update signature is valid. -func checkHeader(cdc codec.BinaryMarshaler, clientState *ClientState, header *Header) error { +func checkHeader(cdc codec.Codec, clientState *ClientState, header *Header) error { // assert update sequence is current sequence if header.Sequence != clientState.Sequence { return sdkerrors.Wrapf( diff --git a/x/ibc/light-clients/06-solomachine/types/update_test.go b/x/ibc/light-clients/06-solomachine/types/update_test.go index 867c24bcb2..55f3641e7c 100644 --- a/x/ibc/light-clients/06-solomachine/types/update_test.go +++ b/x/ibc/light-clients/06-solomachine/types/update_test.go @@ -100,7 +100,7 @@ func (suite *SoloMachineTestSuite) TestCheckHeaderAndUpdateState() { NewDiversifier: h.NewDiversifier, } - dataBz, err := suite.chainA.Codec.MarshalBinaryBare(data) + dataBz, err := suite.chainA.Codec.Marshal(data) suite.Require().NoError(err) // generate invalid signature @@ -112,7 +112,7 @@ func (suite *SoloMachineTestSuite) TestCheckHeaderAndUpdateState() { Data: dataBz, } - signBz, err := suite.chainA.Codec.MarshalBinaryBare(signBytes) + signBz, err := suite.chainA.Codec.Marshal(signBytes) suite.Require().NoError(err) sig := solomachine.GenerateSignature(signBz) diff --git a/x/ibc/light-clients/09-localhost/types/client_state.go b/x/ibc/light-clients/09-localhost/types/client_state.go index e3beded953..931fe6a757 100644 --- a/x/ibc/light-clients/09-localhost/types/client_state.go +++ b/x/ibc/light-clients/09-localhost/types/client_state.go @@ -75,7 +75,7 @@ func (cs ClientState) ZeroCustomFields() exported.ClientState { } // Initialize ensures that initial consensus state for localhost is nil -func (cs ClientState) Initialize(_ sdk.Context, _ codec.BinaryMarshaler, _ sdk.KVStore, consState exported.ConsensusState) error { +func (cs ClientState) Initialize(_ sdk.Context, _ codec.Codec, _ sdk.KVStore, consState exported.ConsensusState) error { if consState != nil { return sdkerrors.Wrap(clienttypes.ErrInvalidConsensus, "initial consensus state for localhost must be nil.") } @@ -89,7 +89,7 @@ func (cs ClientState) ExportMetadata(_ sdk.KVStore) []exported.GenesisMetadata { // CheckHeaderAndUpdateState updates the localhost client. It only needs access to the context func (cs *ClientState) CheckHeaderAndUpdateState( - ctx sdk.Context, _ codec.BinaryMarshaler, _ sdk.KVStore, _ exported.Header, + ctx sdk.Context, _ codec.Codec, _ sdk.KVStore, _ exported.Header, ) (exported.ClientState, exported.ConsensusState, error) { // use the chain ID from context since the localhost client is from the running chain (i.e self). cs.ChainId = ctx.ChainID() @@ -102,22 +102,23 @@ func (cs *ClientState) CheckHeaderAndUpdateState( // Since localhost is the client of the running chain, misbehaviour cannot be submitted to it // Thus, CheckMisbehaviourAndUpdateState returns an error for localhost func (cs ClientState) CheckMisbehaviourAndUpdateState( - _ sdk.Context, _ codec.BinaryMarshaler, _ sdk.KVStore, _ exported.Misbehaviour, + _ sdk.Context, _ codec.Codec, _ sdk.KVStore, _ exported.Misbehaviour, ) (exported.ClientState, error) { return nil, sdkerrors.Wrap(clienttypes.ErrInvalidMisbehaviour, "cannot submit misbehaviour to localhost client") } -// CheckProposedHeaderAndUpdateState returns an error. The localhost cannot be modified by +// CheckSubstituteAndUpdateState returns an error. The localhost cannot be modified by // proposals. -func (cs ClientState) CheckProposedHeaderAndUpdateState( - ctx sdk.Context, _ codec.BinaryMarshaler, _ sdk.KVStore, _ exported.Header, -) (exported.ClientState, exported.ConsensusState, error) { - return nil, nil, sdkerrors.Wrap(clienttypes.ErrUpdateClientFailed, "cannot update localhost client with a proposal") +func (cs ClientState) CheckSubstituteAndUpdateState( + ctx sdk.Context, _ codec.Codec, _, _ sdk.KVStore, + _ exported.ClientState, _ exported.Height, +) (exported.ClientState, error) { + return nil, sdkerrors.Wrap(clienttypes.ErrUpdateClientFailed, "cannot update localhost client with a proposal") } // VerifyUpgradeAndUpdateState returns an error since localhost cannot be upgraded func (cs ClientState) VerifyUpgradeAndUpdateState( - _ sdk.Context, _ codec.BinaryMarshaler, _ sdk.KVStore, + _ sdk.Context, _ codec.Codec, _ sdk.KVStore, _ exported.ClientState, _ exported.ConsensusState, _, _ []byte, ) (exported.ClientState, exported.ConsensusState, error) { return nil, nil, sdkerrors.Wrap(clienttypes.ErrInvalidUpgradeClient, "cannot upgrade localhost client") @@ -125,7 +126,7 @@ func (cs ClientState) VerifyUpgradeAndUpdateState( // VerifyClientState verifies that the localhost client state is stored locally func (cs ClientState) VerifyClientState( - store sdk.KVStore, cdc codec.BinaryMarshaler, + store sdk.KVStore, cdc codec.Codec, _ exported.Height, _ exported.Prefix, _ string, _ []byte, clientState exported.ClientState, ) error { path := host.KeyClientState @@ -149,7 +150,7 @@ func (cs ClientState) VerifyClientState( // VerifyClientConsensusState returns nil since a local host client does not store consensus // states. func (cs ClientState) VerifyClientConsensusState( - sdk.KVStore, codec.BinaryMarshaler, + sdk.KVStore, codec.Codec, exported.Height, string, exported.Height, exported.Prefix, []byte, exported.ConsensusState, ) error { @@ -160,7 +161,7 @@ func (cs ClientState) VerifyClientConsensusState( // specified connection end stored locally. func (cs ClientState) VerifyConnectionState( store sdk.KVStore, - cdc codec.BinaryMarshaler, + cdc codec.Codec, _ exported.Height, _ exported.Prefix, _ []byte, @@ -174,7 +175,7 @@ func (cs ClientState) VerifyConnectionState( } var prevConnection connectiontypes.ConnectionEnd - err := cdc.UnmarshalBinaryBare(bz, &prevConnection) + err := cdc.Unmarshal(bz, &prevConnection) if err != nil { return err } @@ -193,7 +194,7 @@ func (cs ClientState) VerifyConnectionState( // channel end, under the specified port, stored on the local machine. func (cs ClientState) VerifyChannelState( store sdk.KVStore, - cdc codec.BinaryMarshaler, + cdc codec.Codec, _ exported.Height, prefix exported.Prefix, _ []byte, @@ -208,7 +209,7 @@ func (cs ClientState) VerifyChannelState( } var prevChannel channeltypes.Channel - err := cdc.UnmarshalBinaryBare(bz, &prevChannel) + err := cdc.Unmarshal(bz, &prevChannel) if err != nil { return err } @@ -227,7 +228,7 @@ func (cs ClientState) VerifyChannelState( // the specified port, specified channel, and specified sequence. func (cs ClientState) VerifyPacketCommitment( store sdk.KVStore, - _ codec.BinaryMarshaler, + _ codec.Codec, _ exported.Height, _ uint64, _ uint64, @@ -259,7 +260,7 @@ func (cs ClientState) VerifyPacketCommitment( // acknowledgement at the specified port, specified channel, and specified sequence. func (cs ClientState) VerifyPacketAcknowledgement( store sdk.KVStore, - _ codec.BinaryMarshaler, + _ codec.Codec, _ exported.Height, _ uint64, _ uint64, @@ -292,7 +293,7 @@ func (cs ClientState) VerifyPacketAcknowledgement( // specified sequence. func (cs ClientState) VerifyPacketReceiptAbsence( store sdk.KVStore, - _ codec.BinaryMarshaler, + _ codec.Codec, _ exported.Height, _ uint64, _ uint64, @@ -316,7 +317,7 @@ func (cs ClientState) VerifyPacketReceiptAbsence( // received of the specified channel at the specified port. func (cs ClientState) VerifyNextSequenceRecv( store sdk.KVStore, - _ codec.BinaryMarshaler, + _ codec.Codec, _ exported.Height, _ uint64, _ uint64, diff --git a/x/ibc/light-clients/09-localhost/types/client_state_test.go b/x/ibc/light-clients/09-localhost/types/client_state_test.go index e795e1e3fb..307b1bff58 100644 --- a/x/ibc/light-clients/09-localhost/types/client_state_test.go +++ b/x/ibc/light-clients/09-localhost/types/client_state_test.go @@ -170,10 +170,9 @@ func (suite *LocalhostTestSuite) TestMisbehaviourAndUpdateState() { func (suite *LocalhostTestSuite) TestProposedHeaderAndUpdateState() { clientState := types.NewClientState("chainID", clientHeight) - cs, consState, err := clientState.CheckProposedHeaderAndUpdateState(suite.ctx, nil, nil, nil) + cs, err := clientState.CheckSubstituteAndUpdateState(suite.ctx, nil, nil, nil, nil, nil) suite.Require().Error(err) suite.Require().Nil(cs) - suite.Require().Nil(consState) } func (suite *LocalhostTestSuite) TestVerifyConnectionState() { @@ -192,7 +191,7 @@ func (suite *LocalhostTestSuite) TestVerifyConnectionState() { name: "proof verification success", clientState: types.NewClientState("chainID", clientHeight), malleate: func() { - bz, err := suite.cdc.MarshalBinaryBare(&conn1) + bz, err := suite.cdc.Marshal(&conn1) suite.Require().NoError(err) suite.store.Set(host.ConnectionKey(testConnectionID), bz) }, @@ -219,7 +218,7 @@ func (suite *LocalhostTestSuite) TestVerifyConnectionState() { name: "proof verification failed: different connection stored", clientState: types.NewClientState("chainID", clientHeight), malleate: func() { - bz, err := suite.cdc.MarshalBinaryBare(&conn2) + bz, err := suite.cdc.Marshal(&conn2) suite.Require().NoError(err) suite.store.Set(host.ConnectionKey(testConnectionID), bz) }, @@ -264,7 +263,7 @@ func (suite *LocalhostTestSuite) TestVerifyChannelState() { name: "proof verification success", clientState: types.NewClientState("chainID", clientHeight), malleate: func() { - bz, err := suite.cdc.MarshalBinaryBare(&ch1) + bz, err := suite.cdc.Marshal(&ch1) suite.Require().NoError(err) suite.store.Set(host.ChannelKey(testPortID, testChannelID), bz) }, @@ -292,7 +291,7 @@ func (suite *LocalhostTestSuite) TestVerifyChannelState() { name: "proof verification failed: different channel stored", clientState: types.NewClientState("chainID", clientHeight), malleate: func() { - bz, err := suite.cdc.MarshalBinaryBare(&ch2) + bz, err := suite.cdc.Marshal(&ch2) suite.Require().NoError(err) suite.store.Set(host.ChannelKey(testPortID, testChannelID), bz) diff --git a/x/ibc/light-clients/09-localhost/types/localhost_test.go b/x/ibc/light-clients/09-localhost/types/localhost_test.go index 6b2e0ff2a6..f4f308da93 100644 --- a/x/ibc/light-clients/09-localhost/types/localhost_test.go +++ b/x/ibc/light-clients/09-localhost/types/localhost_test.go @@ -24,7 +24,7 @@ var ( type LocalhostTestSuite struct { suite.Suite - cdc codec.Marshaler + cdc codec.Codec ctx sdk.Context store sdk.KVStore } diff --git a/x/ibc/light-clients/99-ostracon/module.go b/x/ibc/light-clients/99-ostracon/module.go index 49435565d4..8b36700225 100644 --- a/x/ibc/light-clients/99-ostracon/module.go +++ b/x/ibc/light-clients/99-ostracon/module.go @@ -1,9 +1,6 @@ package tendermint import ( - "github.com/spf13/cobra" - - "github.com/line/lbm-sdk/x/ibc/light-clients/99-ostracon/client/cli" "github.com/line/lbm-sdk/x/ibc/light-clients/99-ostracon/types" ) @@ -11,8 +8,3 @@ import ( func Name() string { return types.SubModuleName } - -// GetTxCmd returns the root tx command for the IBC client -func GetTxCmd() *cobra.Command { - return cli.NewTxCmd() -} diff --git a/x/ibc/light-clients/99-ostracon/types/client_state.go b/x/ibc/light-clients/99-ostracon/types/client_state.go index a99329627d..cb0bded6c5 100644 --- a/x/ibc/light-clients/99-ostracon/types/client_state.go +++ b/x/ibc/light-clients/99-ostracon/types/client_state.go @@ -142,7 +142,7 @@ func (cs ClientState) ZeroCustomFields() exported.ClientState { // Initialize will check that initial consensus state is a Ostracon consensus state // and will store ProcessedTime for initial consensus state as ctx.BlockTime() -func (cs ClientState) Initialize(ctx sdk.Context, _ codec.BinaryMarshaler, clientStore sdk.KVStore, consState exported.ConsensusState) error { +func (cs ClientState) Initialize(ctx sdk.Context, _ codec.Codec, clientStore sdk.KVStore, consState exported.ConsensusState) error { if _, ok := consState.(*ConsensusState); !ok { return sdkerrors.Wrapf(clienttypes.ErrInvalidConsensus, "invalid initial consensus state. expected type: %T, got: %T", &ConsensusState{}, consState) @@ -156,7 +156,7 @@ func (cs ClientState) Initialize(ctx sdk.Context, _ codec.BinaryMarshaler, clien // stored on the target machine func (cs ClientState) VerifyClientState( store sdk.KVStore, - cdc codec.BinaryMarshaler, + cdc codec.Codec, height exported.Height, prefix exported.Prefix, counterpartyClientIdentifier string, @@ -195,7 +195,7 @@ func (cs ClientState) VerifyClientState( // Ostracon client stored on the target machine. func (cs ClientState) VerifyClientConsensusState( store sdk.KVStore, - cdc codec.BinaryMarshaler, + cdc codec.Codec, height exported.Height, counterpartyClientIdentifier string, consensusHeight exported.Height, @@ -239,7 +239,7 @@ func (cs ClientState) VerifyClientConsensusState( // specified connection end stored on the target machine. func (cs ClientState) VerifyConnectionState( store sdk.KVStore, - cdc codec.BinaryMarshaler, + cdc codec.Codec, height exported.Height, prefix exported.Prefix, proof []byte, @@ -262,7 +262,7 @@ func (cs ClientState) VerifyConnectionState( return sdkerrors.Wrapf(sdkerrors.ErrInvalidType, "invalid connection type %T", connectionEnd) } - bz, err := cdc.MarshalBinaryBare(&connection) + bz, err := cdc.Marshal(&connection) if err != nil { return err } @@ -278,7 +278,7 @@ func (cs ClientState) VerifyConnectionState( // channel end, under the specified port, stored on the target machine. func (cs ClientState) VerifyChannelState( store sdk.KVStore, - cdc codec.BinaryMarshaler, + cdc codec.Codec, height exported.Height, prefix exported.Prefix, proof []byte, @@ -302,7 +302,7 @@ func (cs ClientState) VerifyChannelState( return sdkerrors.Wrapf(sdkerrors.ErrInvalidType, "invalid channel type %T", channel) } - bz, err := cdc.MarshalBinaryBare(&channelEnd) + bz, err := cdc.Marshal(&channelEnd) if err != nil { return err } @@ -318,7 +318,7 @@ func (cs ClientState) VerifyChannelState( // the specified port, specified channel, and specified sequence. func (cs ClientState) VerifyPacketCommitment( store sdk.KVStore, - cdc codec.BinaryMarshaler, + cdc codec.Codec, height exported.Height, currentTimestamp uint64, delayPeriod uint64, @@ -356,7 +356,7 @@ func (cs ClientState) VerifyPacketCommitment( // acknowledgement at the specified port, specified channel, and specified sequence. func (cs ClientState) VerifyPacketAcknowledgement( store sdk.KVStore, - cdc codec.BinaryMarshaler, + cdc codec.Codec, height exported.Height, currentTimestamp uint64, delayPeriod uint64, @@ -395,7 +395,7 @@ func (cs ClientState) VerifyPacketAcknowledgement( // specified sequence. func (cs ClientState) VerifyPacketReceiptAbsence( store sdk.KVStore, - cdc codec.BinaryMarshaler, + cdc codec.Codec, height exported.Height, currentTimestamp uint64, delayPeriod uint64, @@ -432,7 +432,7 @@ func (cs ClientState) VerifyPacketReceiptAbsence( // received of the specified channel at the specified port. func (cs ClientState) VerifyNextSequenceRecv( store sdk.KVStore, - cdc codec.BinaryMarshaler, + cdc codec.Codec, height exported.Height, currentTimestamp uint64, delayPeriod uint64, @@ -489,7 +489,7 @@ func verifyDelayPeriodPassed(store sdk.KVStore, proofHeight exported.Height, cur // merkle proof, the consensus state and an error if one occurred. func produceVerificationArgs( store sdk.KVStore, - cdc codec.BinaryMarshaler, + cdc codec.Codec, cs ClientState, height exported.Height, prefix exported.Prefix, @@ -519,7 +519,7 @@ func produceVerificationArgs( return commitmenttypes.MerkleProof{}, nil, sdkerrors.Wrap(commitmenttypes.ErrInvalidProof, "proof cannot be empty") } - if err = cdc.UnmarshalBinaryBare(proof, &merkleProof); err != nil { + if err = cdc.Unmarshal(proof, &merkleProof); err != nil { return commitmenttypes.MerkleProof{}, nil, sdkerrors.Wrap(commitmenttypes.ErrInvalidProof, "failed to unmarshal proof into commitment merkle proof") } diff --git a/x/ibc/light-clients/99-ostracon/types/header.go b/x/ibc/light-clients/99-ostracon/types/header.go index 38d6d74eaf..53a61a5711 100644 --- a/x/ibc/light-clients/99-ostracon/types/header.go +++ b/x/ibc/light-clients/99-ostracon/types/header.go @@ -81,3 +81,5 @@ func (h Header) ValidateBasic() error { } return nil } + +// TODO(dudong2): need to remove ibc from lbm-sdk(move to other repo) diff --git a/x/ibc/light-clients/99-ostracon/types/misbehaviour_handle.go b/x/ibc/light-clients/99-ostracon/types/misbehaviour_handle.go index 028aad9806..07a4a68818 100644 --- a/x/ibc/light-clients/99-ostracon/types/misbehaviour_handle.go +++ b/x/ibc/light-clients/99-ostracon/types/misbehaviour_handle.go @@ -21,7 +21,7 @@ import ( // to misbehaviour.Header2 func (cs ClientState) CheckMisbehaviourAndUpdateState( ctx sdk.Context, - cdc codec.BinaryMarshaler, + cdc codec.Codec, clientStore sdk.KVStore, misbehaviour exported.Misbehaviour, ) (exported.ClientState, error) { diff --git a/x/ibc/light-clients/99-ostracon/types/ostracon_test.go b/x/ibc/light-clients/99-ostracon/types/ostracon_test.go index f281cede5b..741f950cbe 100644 --- a/x/ibc/light-clients/99-ostracon/types/ostracon_test.go +++ b/x/ibc/light-clients/99-ostracon/types/ostracon_test.go @@ -45,7 +45,7 @@ type TendermintTestSuite struct { // TODO: deprecate usage in favor of testing package ctx sdk.Context - cdc codec.Marshaler + cdc codec.Codec privVal octypes.PrivValidator valSet *octypes.ValidatorSet valsHash ostbytes.HexBytes diff --git a/x/ibc/light-clients/99-ostracon/types/proposal_handle.go b/x/ibc/light-clients/99-ostracon/types/proposal_handle.go index 2727683265..b96051c7d2 100644 --- a/x/ibc/light-clients/99-ostracon/types/proposal_handle.go +++ b/x/ibc/light-clients/99-ostracon/types/proposal_handle.go @@ -1,9 +1,7 @@ package types import ( - "time" - - octypes "github.com/line/ostracon/types" + "reflect" "github.com/line/lbm-sdk/codec" sdk "github.com/line/lbm-sdk/types" @@ -12,31 +10,52 @@ import ( "github.com/line/lbm-sdk/x/ibc/core/exported" ) -// CheckProposedHeaderAndUpdateState will try to update the client with the new header if and -// only if the proposal passes and one of the following two conditions is satisfied: -// 1) AllowUpdateAfterExpiry=true and Expire(ctx.BlockTime) = true -// 2) AllowUpdateAfterMisbehaviour and IsFrozen() = true -// In case 2) before trying to update the client, the client will be unfrozen by resetting -// the FrozenHeight to the zero Height. If AllowUpdateAfterMisbehaviour is set to true, -// expired clients will also be updated even if AllowUpdateAfterExpiry is set to false. -// Note, that even if the update happens, it may not be successful. The header may fail -// validation checks and an error will be returned in that case. -func (cs ClientState) CheckProposedHeaderAndUpdateState( - ctx sdk.Context, cdc codec.BinaryMarshaler, clientStore sdk.KVStore, - header exported.Header, -) (exported.ClientState, exported.ConsensusState, error) { - tmHeader, ok := header.(*Header) +// CheckSubstituteAndUpdateState will try to update the client with the state of the +// substitute if and only if the proposal passes and one of the following conditions are +// satisfied: +// 1) AllowUpdateAfterMisbehaviour and IsFrozen() = true +// 2) AllowUpdateAfterExpiry=true and Expire(ctx.BlockTime) = true +// +// The following must always be true: +// - The substitute client is the same type as the subject client +// - The subject and substitute client states match in all parameters (expect frozen height, latest height, and chain-id) +// +// In case 1) before updating the client, the client will be unfrozen by resetting +// the FrozenHeight to the zero Height. If a client is frozen and AllowUpdateAfterMisbehaviour +// is set to true, the client will be unexpired even if AllowUpdateAfterExpiry is set to false. +// Note, that even if the subject is updated to the state of the substitute, an error may be +// returned if the updated client state is invalid or the client is expired. +func (cs ClientState) CheckSubstituteAndUpdateState( + ctx sdk.Context, cdc codec.Codec, subjectClientStore, + substituteClientStore sdk.KVStore, substituteClient exported.ClientState, + initialHeight exported.Height, +) (exported.ClientState, error) { + substituteClientState, ok := substituteClient.(*ClientState) if !ok { - return nil, nil, sdkerrors.Wrapf( - clienttypes.ErrInvalidHeader, "expected type %T, got %T", &Header{}, header, + return nil, sdkerrors.Wrapf( + clienttypes.ErrInvalidClient, "expected type %T, got %T", &ClientState{}, substituteClient, ) } + // substitute clients are not allowed to be upgraded during the voting period + // If an upgrade passes before the subject client has been updated, a new proposal must be created + // with an initial height that contains the new revision number. + if substituteClientState.GetLatestHeight().GetRevisionNumber() != initialHeight.GetRevisionNumber() { + return nil, sdkerrors.Wrapf( + clienttypes.ErrInvalidHeight, "substitute client revision number must equal initial height revision number (%d != %d)", + substituteClientState.GetLatestHeight().GetRevisionNumber(), initialHeight.GetRevisionNumber(), + ) + } + + if !IsMatchingClientState(cs, *substituteClientState) { + return nil, sdkerrors.Wrap(clienttypes.ErrInvalidSubstitute, "subject client state does not match substitute client state") + } + // get consensus state corresponding to client state to check if the client is expired - consensusState, err := GetConsensusState(clientStore, cdc, cs.GetLatestHeight()) + consensusState, err := GetConsensusState(subjectClientStore, cdc, cs.GetLatestHeight()) if err != nil { - return nil, nil, sdkerrors.Wrapf( - err, "could not get consensus state from clientstore at height: %d", cs.GetLatestHeight(), + return nil, sdkerrors.Wrapf( + err, "unexpected error: could not get consensus state from clientstore at height: %d", cs.GetLatestHeight(), ) } @@ -44,84 +63,72 @@ func (cs ClientState) CheckProposedHeaderAndUpdateState( case cs.IsFrozen(): if !cs.AllowUpdateAfterMisbehaviour { - return nil, nil, sdkerrors.Wrap(clienttypes.ErrUpdateClientFailed, "client is not allowed to be unfrozen") + return nil, sdkerrors.Wrap(clienttypes.ErrUpdateClientFailed, "client is not allowed to be unfrozen") } // unfreeze the client cs.FrozenHeight = clienttypes.ZeroHeight() - // if the client is expired we unexpire the client using softer validation, otherwise - // full validation on the header is performed. - if cs.IsExpired(consensusState.Timestamp, ctx.BlockTime()) { - return cs.unexpireClient(ctx, clientStore, consensusState, tmHeader, ctx.BlockTime()) + case cs.IsExpired(consensusState.Timestamp, ctx.BlockTime()): + if !cs.AllowUpdateAfterExpiry { + return nil, sdkerrors.Wrap(clienttypes.ErrUpdateClientFailed, "client is not allowed to be unexpired") } - // NOTE: the client may be frozen again since the misbehaviour evidence may - // not be expired yet - return cs.CheckHeaderAndUpdateState(ctx, cdc, clientStore, header) - - case cs.AllowUpdateAfterExpiry && cs.IsExpired(consensusState.Timestamp, ctx.BlockTime()): - return cs.unexpireClient(ctx, clientStore, consensusState, tmHeader, ctx.BlockTime()) - default: - return nil, nil, sdkerrors.Wrap(clienttypes.ErrUpdateClientFailed, "client cannot be updated with proposal") + return nil, sdkerrors.Wrap(clienttypes.ErrUpdateClientFailed, "client cannot be updated with proposal") } -} - -// unexpireClient checks if the proposed header is sufficient to update an expired client. -// The client is updated if no error occurs. -func (cs ClientState) unexpireClient( - ctx sdk.Context, clientStore sdk.KVStore, consensusState *ConsensusState, header *Header, currentTimestamp time.Time, -) (exported.ClientState, exported.ConsensusState, error) { + // copy consensus states and processed time from substitute to subject + // starting from initial height and ending on the latest height (inclusive) + for i := initialHeight.GetRevisionHeight(); i <= substituteClientState.GetLatestHeight().GetRevisionHeight(); i++ { + height := clienttypes.NewHeight(substituteClientState.GetLatestHeight().GetRevisionNumber(), i) - // the client is expired and either AllowUpdateAfterMisbehaviour or AllowUpdateAfterExpiry - // is set to true so light validation of the header is executed - if err := cs.checkProposedHeader(consensusState, header, currentTimestamp); err != nil { - return nil, nil, err - } + consensusState, err := GetConsensusState(substituteClientStore, cdc, height) + if err != nil { + // not all consensus states will be filled in + continue + } + SetConsensusState(subjectClientStore, cdc, consensusState, height) - newClientState, consensusState := update(ctx, clientStore, &cs, header) - return newClientState, consensusState, nil -} + processedTime, found := GetProcessedTime(substituteClientStore, height) + if !found { + continue + } + SetProcessedTime(subjectClientStore, height, processedTime) -// checkProposedHeader checks if the Ostracon header is valid for updating a client after -// a passed proposal. -// It returns an error if: -// - the header provided is not parseable to tendermint types -// - header height is less than or equal to the latest client state height -// - signed tendermint header is invalid -// - header timestamp is less than or equal to the latest consensus state timestamp -// - header timestamp is expired -// NOTE: header.ValidateBasic is called in the 02-client proposal handler. Additional checks -// on the validator set and the validator set hash are done in header.ValidateBasic. -func (cs ClientState) checkProposedHeader(consensusState *ConsensusState, header *Header, currentTimestamp time.Time) error { - tmSignedHeader, err := octypes.SignedHeaderFromProto(header.SignedHeader) - if err != nil { - return sdkerrors.Wrap(err, "signed header in not tendermint signed header type") } - if !header.GetTime().After(consensusState.Timestamp) { - return sdkerrors.Wrapf( - clienttypes.ErrInvalidHeader, - "header timestamp is less than or equal to latest consensus state timestamp (%s ≤ %s)", header.GetTime(), consensusState.Timestamp) + cs.LatestHeight = substituteClientState.LatestHeight + + // validate the updated client and ensure it isn't expired + if err := cs.Validate(); err != nil { + return nil, sdkerrors.Wrap(err, "unexpected error: updated subject client state is invalid") } - // assert header height is newer than latest client state - if header.GetHeight().LTE(cs.GetLatestHeight()) { - return sdkerrors.Wrapf( - clienttypes.ErrInvalidHeader, - "header height ≤ consensus state height (%s ≤ %s)", header.GetHeight(), cs.GetLatestHeight(), + latestConsensusState, err := GetConsensusState(subjectClientStore, cdc, cs.GetLatestHeight()) + if err != nil { + return nil, sdkerrors.Wrapf( + err, "unexpected error: could not get consensus state for updated subject client from clientstore at height: %d", cs.GetLatestHeight(), ) } - if err := tmSignedHeader.ValidateBasic(cs.GetChainID()); err != nil { - return sdkerrors.Wrap(err, "signed header failed basic validation") + if cs.IsExpired(latestConsensusState.Timestamp, ctx.BlockTime()) { + return nil, sdkerrors.Wrap(clienttypes.ErrInvalidClient, "updated subject client is expired") } - if cs.IsExpired(header.GetTime(), currentTimestamp) { - return sdkerrors.Wrap(clienttypes.ErrInvalidHeader, "header timestamp is already expired") - } + return &cs, nil +} - return nil +// IsMatchingClientState returns true if all the client state parameters match +// except for frozen height, latest height, and chain-id. +func IsMatchingClientState(subject, substitute ClientState) bool { + // zero out parameters which do not need to match + subject.LatestHeight = clienttypes.ZeroHeight() + subject.FrozenHeight = clienttypes.ZeroHeight() + substitute.LatestHeight = clienttypes.ZeroHeight() + substitute.FrozenHeight = clienttypes.ZeroHeight() + subject.ChainId = "" + substitute.ChainId = "" + + return reflect.DeepEqual(subject, substitute) } diff --git a/x/ibc/light-clients/99-ostracon/types/proposal_handle_test.go b/x/ibc/light-clients/99-ostracon/types/proposal_handle_test.go index 6eecda6651..32dbabdcb9 100644 --- a/x/ibc/light-clients/99-ostracon/types/proposal_handle_test.go +++ b/x/ibc/light-clients/99-ostracon/types/proposal_handle_test.go @@ -1,6 +1,8 @@ package types_test import ( + "time" + clienttypes "github.com/line/lbm-sdk/x/ibc/core/02-client/types" "github.com/line/lbm-sdk/x/ibc/core/exported" "github.com/line/lbm-sdk/x/ibc/light-clients/99-ostracon/types" @@ -11,38 +13,120 @@ var ( frozenHeight = clienttypes.NewHeight(0, 1) ) -// sanity checks -func (suite *TendermintTestSuite) TestCheckProposedHeaderAndUpdateStateBasic() { - clientA, _ := suite.coordinator.SetupClients(suite.chainA, suite.chainB, exported.Ostracon) - clientState := suite.chainA.GetClientState(clientA).(*types.ClientState) - clientStore := suite.chainA.App.IBCKeeper.ClientKeeper.ClientStore(suite.chainA.GetContext(), clientA) - - // use nil header - cs, consState, err := clientState.CheckProposedHeaderAndUpdateState(suite.chainA.GetContext(), suite.chainA.App.AppCodec(), clientStore, nil) - suite.Require().Error(err) - suite.Require().Nil(cs) - suite.Require().Nil(consState) - - clientState.LatestHeight = clientState.LatestHeight.Increment().(clienttypes.Height) - - // consensus state for latest height does not exist - cs, consState, err = clientState.CheckProposedHeaderAndUpdateState(suite.chainA.GetContext(), suite.chainA.App.AppCodec(), clientStore, suite.chainA.LastHeader) - suite.Require().Error(err) - suite.Require().Nil(cs) - suite.Require().Nil(consState) +func (suite *TendermintTestSuite) TestCheckSubstituteUpdateStateBasic() { + var ( + substitute string + substituteClientState exported.ClientState + initialHeight clienttypes.Height + ) + testCases := []struct { + name string + malleate func() + }{ + { + "solo machine used for substitute", func() { + substituteClientState = ibctesting.NewSolomachine(suite.T(), suite.cdc, "solo machine", "", 1).ClientState() + }, + }, + { + "initial height and substitute revision numbers do not match", func() { + initialHeight = clienttypes.NewHeight(substituteClientState.GetLatestHeight().GetRevisionNumber()+1, 1) + }, + }, + { + "non-matching substitute", func() { + substitute, _ := suite.coordinator.SetupClients(suite.chainA, suite.chainB, exported.Ostracon) + substituteClientState = suite.chainA.GetClientState(substitute).(*types.ClientState) + tmClientState, ok := substituteClientState.(*types.ClientState) + suite.Require().True(ok) + + tmClientState.ChainId = tmClientState.ChainId + "different chain" + }, + }, + { + "updated client is invalid - revision height is zero", func() { + substitute, _ := suite.coordinator.SetupClients(suite.chainA, suite.chainB, exported.Ostracon) + substituteClientState = suite.chainA.GetClientState(substitute).(*types.ClientState) + tmClientState, ok := substituteClientState.(*types.ClientState) + suite.Require().True(ok) + // match subject + tmClientState.AllowUpdateAfterMisbehaviour = true + tmClientState.AllowUpdateAfterExpiry = true + + // will occur. This case should never occur (caught by upstream checks) + initialHeight = clienttypes.NewHeight(5, 0) + tmClientState.LatestHeight = clienttypes.NewHeight(5, 0) + }, + }, + { + "updated client is expired", func() { + substitute, _ = suite.coordinator.SetupClients(suite.chainA, suite.chainB, exported.Ostracon) + substituteClientState = suite.chainA.GetClientState(substitute).(*types.ClientState) + tmClientState, ok := substituteClientState.(*types.ClientState) + suite.Require().True(ok) + initialHeight = tmClientState.LatestHeight + + // match subject + tmClientState.AllowUpdateAfterMisbehaviour = true + tmClientState.AllowUpdateAfterExpiry = true + suite.chainA.App.IBCKeeper.ClientKeeper.SetClientState(suite.chainA.GetContext(), substitute, tmClientState) + + // update substitute a few times + err := suite.coordinator.UpdateClient(suite.chainA, suite.chainB, substitute, exported.Ostracon) + suite.Require().NoError(err) + substituteClientState = suite.chainA.GetClientState(substitute) + + err = suite.coordinator.UpdateClient(suite.chainA, suite.chainB, substitute, exported.Ostracon) + suite.Require().NoError(err) + + suite.chainA.ExpireClient(tmClientState.TrustingPeriod) + suite.chainB.ExpireClient(tmClientState.TrustingPeriod) + suite.coordinator.CommitBlock(suite.chainA, suite.chainB) + + substituteClientState = suite.chainA.GetClientState(substitute) + }, + }, + } + + for _, tc := range testCases { + tc := tc + + suite.Run(tc.name, func() { + + suite.SetupTest() // reset + + subject, _ := suite.coordinator.SetupClients(suite.chainA, suite.chainB, exported.Ostracon) + subjectClientState := suite.chainA.GetClientState(subject).(*types.ClientState) + subjectClientState.AllowUpdateAfterMisbehaviour = true + subjectClientState.AllowUpdateAfterExpiry = true + + // expire subject + suite.chainA.ExpireClient(subjectClientState.TrustingPeriod) + suite.chainB.ExpireClient(subjectClientState.TrustingPeriod) + suite.coordinator.CommitBlock(suite.chainA, suite.chainB) + + tc.malleate() + + subjectClientStore := suite.chainA.App.IBCKeeper.ClientKeeper.ClientStore(suite.chainA.GetContext(), subject) + substituteClientStore := suite.chainA.App.IBCKeeper.ClientKeeper.ClientStore(suite.chainA.GetContext(), substitute) + + updatedClient, err := subjectClientState.CheckSubstituteAndUpdateState(suite.chainA.GetContext(), suite.chainA.App.AppCodec(), subjectClientStore, substituteClientStore, substituteClientState, initialHeight) + suite.Require().Error(err) + suite.Require().Nil(updatedClient) + }) + } } // to expire clients, time needs to be fast forwarded on both chainA and chainB. // this is to prevent headers from failing when attempting to update later. -func (suite *TendermintTestSuite) TestCheckProposedHeaderAndUpdateState() { +func (suite *TendermintTestSuite) TestCheckSubstituteAndUpdateState() { testCases := []struct { name string AllowUpdateAfterExpiry bool AllowUpdateAfterMisbehaviour bool FreezeClient bool ExpireClient bool - expPassUnfreeze bool // expected result using a header that passes stronger validation - expPassUnexpire bool // expected result using a header that passes weaker validation + expPass bool }{ { name: "not allowed to be updated, not frozen or expired", @@ -50,8 +134,7 @@ func (suite *TendermintTestSuite) TestCheckProposedHeaderAndUpdateState() { AllowUpdateAfterMisbehaviour: false, FreezeClient: false, ExpireClient: false, - expPassUnfreeze: false, - expPassUnexpire: false, + expPass: false, }, { name: "not allowed to be updated, client is frozen", @@ -59,8 +142,7 @@ func (suite *TendermintTestSuite) TestCheckProposedHeaderAndUpdateState() { AllowUpdateAfterMisbehaviour: false, FreezeClient: true, ExpireClient: false, - expPassUnfreeze: false, - expPassUnexpire: false, + expPass: false, }, { name: "not allowed to be updated, client is expired", @@ -68,8 +150,7 @@ func (suite *TendermintTestSuite) TestCheckProposedHeaderAndUpdateState() { AllowUpdateAfterMisbehaviour: false, FreezeClient: false, ExpireClient: true, - expPassUnfreeze: false, - expPassUnexpire: false, + expPass: false, }, { name: "not allowed to be updated, client is frozen and expired", @@ -77,8 +158,7 @@ func (suite *TendermintTestSuite) TestCheckProposedHeaderAndUpdateState() { AllowUpdateAfterMisbehaviour: false, FreezeClient: true, ExpireClient: true, - expPassUnfreeze: false, - expPassUnexpire: false, + expPass: false, }, { name: "allowed to be updated only after misbehaviour, not frozen or expired", @@ -86,17 +166,7 @@ func (suite *TendermintTestSuite) TestCheckProposedHeaderAndUpdateState() { AllowUpdateAfterMisbehaviour: true, FreezeClient: false, ExpireClient: false, - expPassUnfreeze: false, - expPassUnexpire: false, - }, - { - name: "PASS: allowed to be updated only after misbehaviour, client is frozen", - AllowUpdateAfterExpiry: false, - AllowUpdateAfterMisbehaviour: true, - FreezeClient: true, - ExpireClient: false, - expPassUnfreeze: true, - expPassUnexpire: false, + expPass: false, }, { name: "allowed to be updated only after misbehaviour, client is expired", @@ -104,17 +174,7 @@ func (suite *TendermintTestSuite) TestCheckProposedHeaderAndUpdateState() { AllowUpdateAfterMisbehaviour: true, FreezeClient: false, ExpireClient: true, - expPassUnfreeze: false, - expPassUnexpire: false, - }, - { - name: "allowed to be updated only after misbehaviour, client is frozen and expired", - AllowUpdateAfterExpiry: false, - AllowUpdateAfterMisbehaviour: true, - FreezeClient: true, - ExpireClient: true, - expPassUnfreeze: true, - expPassUnexpire: true, + expPass: false, }, { name: "allowed to be updated only after expiry, not frozen or expired", @@ -122,8 +182,7 @@ func (suite *TendermintTestSuite) TestCheckProposedHeaderAndUpdateState() { AllowUpdateAfterMisbehaviour: false, FreezeClient: false, ExpireClient: false, - expPassUnfreeze: false, - expPassUnexpire: false, + expPass: false, }, { name: "allowed to be updated only after expiry, client is frozen", @@ -131,8 +190,23 @@ func (suite *TendermintTestSuite) TestCheckProposedHeaderAndUpdateState() { AllowUpdateAfterMisbehaviour: false, FreezeClient: true, ExpireClient: false, - expPassUnfreeze: false, - expPassUnexpire: false, + expPass: false, + }, + { + name: "PASS: allowed to be updated only after misbehaviour, client is frozen", + AllowUpdateAfterExpiry: false, + AllowUpdateAfterMisbehaviour: true, + FreezeClient: true, + ExpireClient: false, + expPass: true, + }, + { + name: "PASS: allowed to be updated only after misbehaviour, client is frozen and expired", + AllowUpdateAfterExpiry: false, + AllowUpdateAfterMisbehaviour: true, + FreezeClient: true, + ExpireClient: true, + expPass: true, }, { name: "PASS: allowed to be updated only after expiry, client is expired", @@ -140,8 +214,7 @@ func (suite *TendermintTestSuite) TestCheckProposedHeaderAndUpdateState() { AllowUpdateAfterMisbehaviour: false, FreezeClient: false, ExpireClient: true, - expPassUnfreeze: true, - expPassUnexpire: true, + expPass: true, }, { name: "allowed to be updated only after expiry, client is frozen and expired", @@ -149,8 +222,7 @@ func (suite *TendermintTestSuite) TestCheckProposedHeaderAndUpdateState() { AllowUpdateAfterMisbehaviour: false, FreezeClient: true, ExpireClient: true, - expPassUnfreeze: false, - expPassUnexpire: false, + expPass: false, }, { name: "allowed to be updated after expiry and misbehaviour, not frozen or expired", @@ -158,8 +230,7 @@ func (suite *TendermintTestSuite) TestCheckProposedHeaderAndUpdateState() { AllowUpdateAfterMisbehaviour: true, FreezeClient: false, ExpireClient: false, - expPassUnfreeze: false, - expPassUnexpire: false, + expPass: false, }, { name: "PASS: allowed to be updated after expiry and misbehaviour, client is frozen", @@ -167,8 +238,7 @@ func (suite *TendermintTestSuite) TestCheckProposedHeaderAndUpdateState() { AllowUpdateAfterMisbehaviour: true, FreezeClient: true, ExpireClient: false, - expPassUnfreeze: true, - expPassUnexpire: false, + expPass: true, }, { name: "PASS: allowed to be updated after expiry and misbehaviour, client is expired", @@ -176,8 +246,7 @@ func (suite *TendermintTestSuite) TestCheckProposedHeaderAndUpdateState() { AllowUpdateAfterMisbehaviour: true, FreezeClient: false, ExpireClient: true, - expPassUnfreeze: true, - expPassUnexpire: true, + expPass: true, }, { name: "PASS: allowed to be updated after expiry and misbehaviour, client is frozen and expired", @@ -185,8 +254,7 @@ func (suite *TendermintTestSuite) TestCheckProposedHeaderAndUpdateState() { AllowUpdateAfterMisbehaviour: true, FreezeClient: true, ExpireClient: true, - expPassUnfreeze: true, - expPassUnexpire: true, + expPass: true, }, } @@ -201,67 +269,67 @@ func (suite *TendermintTestSuite) TestCheckProposedHeaderAndUpdateState() { // start by testing unexpiring the client suite.SetupTest() // reset - // construct client state based on test case parameters - clientA, _ := suite.coordinator.SetupClients(suite.chainA, suite.chainB, exported.Ostracon) - clientState := suite.chainA.GetClientState(clientA).(*types.ClientState) - clientState.AllowUpdateAfterExpiry = tc.AllowUpdateAfterExpiry - clientState.AllowUpdateAfterMisbehaviour = tc.AllowUpdateAfterMisbehaviour + // construct subject using test case parameters + subject, _ := suite.coordinator.SetupClients(suite.chainA, suite.chainB, exported.Ostracon) + subjectClientState := suite.chainA.GetClientState(subject).(*types.ClientState) + subjectClientState.AllowUpdateAfterExpiry = tc.AllowUpdateAfterExpiry + subjectClientState.AllowUpdateAfterMisbehaviour = tc.AllowUpdateAfterMisbehaviour + + // apply freezing or expiry as determined by the test case if tc.FreezeClient { - clientState.FrozenHeight = frozenHeight + subjectClientState.FrozenHeight = frozenHeight } if tc.ExpireClient { - suite.chainA.ExpireClient(clientState.TrustingPeriod) - suite.chainB.ExpireClient(clientState.TrustingPeriod) + suite.chainA.ExpireClient(subjectClientState.TrustingPeriod) + suite.chainB.ExpireClient(subjectClientState.TrustingPeriod) suite.coordinator.CommitBlock(suite.chainA, suite.chainB) } - // use next header for chainB to unfreeze client on chainA - unfreezeClientHeader, err := suite.chainA.ConstructUpdateOCClientHeader(suite.chainB, clientA) - suite.Require().NoError(err) + // construct the substitute to match the subject client + // NOTE: the substitute is explicitly created after the freezing or expiry occurs, + // primarily to prevent the substitute from becoming frozen. It also should be + // the natural flow of events in practice. The subject will become frozen/expired + // and a substitute will be created along with a governance proposal as a response - clientStore := suite.chainA.App.IBCKeeper.ClientKeeper.ClientStore(suite.chainA.GetContext(), clientA) - cs, consState, err := clientState.CheckProposedHeaderAndUpdateState(suite.chainA.GetContext(), suite.chainA.App.AppCodec(), clientStore, unfreezeClientHeader) + substitute, _ := suite.coordinator.SetupClients(suite.chainA, suite.chainB, exported.Ostracon) + substituteClientState := suite.chainA.GetClientState(substitute).(*types.ClientState) + substituteClientState.AllowUpdateAfterExpiry = tc.AllowUpdateAfterExpiry + substituteClientState.AllowUpdateAfterMisbehaviour = tc.AllowUpdateAfterMisbehaviour + suite.chainA.App.IBCKeeper.ClientKeeper.SetClientState(suite.chainA.GetContext(), substitute, substituteClientState) - if tc.expPassUnfreeze { + initialHeight := substituteClientState.GetLatestHeight() + + // update substitute a few times + for i := 0; i < 3; i++ { + err := suite.coordinator.UpdateClient(suite.chainA, suite.chainB, substitute, exported.Ostracon) suite.Require().NoError(err) - suite.Require().Equal(clienttypes.ZeroHeight(), cs.GetFrozenHeight()) - suite.Require().NotNil(consState) - } else { - suite.Require().Error(err) - suite.Require().Nil(cs) - suite.Require().Nil(consState) + // skip a block + suite.coordinator.CommitBlock(suite.chainA, suite.chainB) } - // use next header for chainB to unexpire clients but with empty trusted heights - // and validators. Update chainB time so header won't be expired. - unexpireClientHeader, err := suite.chainA.ConstructUpdateOCClientHeader(suite.chainB, clientA) - suite.Require().NoError(err) - unexpireClientHeader.TrustedHeight = clienttypes.ZeroHeight() - unexpireClientHeader.TrustedValidators = nil + // get updated substitute + substituteClientState = suite.chainA.GetClientState(substitute).(*types.ClientState) - clientStore = suite.chainA.App.IBCKeeper.ClientKeeper.ClientStore(suite.chainA.GetContext(), clientA) - cs, consState, err = clientState.CheckProposedHeaderAndUpdateState(suite.chainA.GetContext(), suite.chainA.App.AppCodec(), clientStore, unexpireClientHeader) + subjectClientStore := suite.chainA.App.IBCKeeper.ClientKeeper.ClientStore(suite.chainA.GetContext(), subject) + substituteClientStore := suite.chainA.App.IBCKeeper.ClientKeeper.ClientStore(suite.chainA.GetContext(), substitute) + updatedClient, err := subjectClientState.CheckSubstituteAndUpdateState(suite.chainA.GetContext(), suite.chainA.App.AppCodec(), subjectClientStore, substituteClientStore, substituteClientState, initialHeight) - if tc.expPassUnexpire { + if tc.expPass { suite.Require().NoError(err) - suite.Require().NotNil(cs) - suite.Require().NotNil(consState) + suite.Require().Equal(clienttypes.ZeroHeight(), updatedClient.GetFrozenHeight()) } else { suite.Require().Error(err) - suite.Require().Nil(cs) - suite.Require().Nil(consState) + suite.Require().Nil(updatedClient) } + }) } } -// test softer validation on headers used for unexpiring clients -func (suite *TendermintTestSuite) TestCheckProposedHeader() { +func (suite *TendermintTestSuite) TestIsMatchingClientState() { var ( - header *types.Header - clientState *types.ClientState - clientA string - err error + subject, substitute string + subjectClientState, substituteClientState *types.ClientState ) testCases := []struct { @@ -270,46 +338,33 @@ func (suite *TendermintTestSuite) TestCheckProposedHeader() { expPass bool }{ { - "success", func() {}, true, + "matching clients", func() { + subjectClientState = suite.chainA.GetClientState(subject).(*types.ClientState) + substituteClientState = suite.chainA.GetClientState(substitute).(*types.ClientState) + }, true, }, { - "invalid signed header", func() { - header.SignedHeader = nil - }, false, + "matching, frozen height is not used in check for equality", func() { + subjectClientState.FrozenHeight = frozenHeight + substituteClientState.FrozenHeight = clienttypes.ZeroHeight() + }, true, }, { - "header time is less than or equal to consensus state timestamp", func() { - consensusState, found := suite.chainA.GetConsensusState(clientA, clientState.GetLatestHeight()) - suite.Require().True(found) - consensusState.(*types.ConsensusState).Timestamp = header.GetTime() - suite.chainA.App.IBCKeeper.ClientKeeper.SetClientConsensusState(suite.chainA.GetContext(), clientA, clientState.GetLatestHeight(), consensusState) - - // update block time so client is expired - suite.chainA.ExpireClient(clientState.TrustingPeriod) - suite.chainB.ExpireClient(clientState.TrustingPeriod) - suite.coordinator.CommitBlock(suite.chainA, suite.chainB) - }, false, + "matching, latest height is not used in check for equality", func() { + subjectClientState.LatestHeight = clienttypes.NewHeight(0, 10) + substituteClientState.FrozenHeight = clienttypes.ZeroHeight() + }, true, }, { - "header height is not newer than client state", func() { - consensusState, found := suite.chainA.GetConsensusState(clientA, clientState.GetLatestHeight()) - suite.Require().True(found) - clientState.LatestHeight = header.GetHeight().(clienttypes.Height) - suite.chainA.App.IBCKeeper.ClientKeeper.SetClientConsensusState(suite.chainA.GetContext(), clientA, clientState.GetLatestHeight(), consensusState) - - }, false, + "matching, chain id is different", func() { + subjectClientState.ChainId = "bitcoin" + substituteClientState.ChainId = "ethereum" + }, true, }, { - "signed header failed validate basic - wrong chain ID", func() { - clientState.ChainId = ibctesting.InvalidID - }, false, - }, - { - "header is already expired", func() { - // expire client - suite.chainA.ExpireClient(clientState.TrustingPeriod) - suite.chainB.ExpireClient(clientState.TrustingPeriod) - suite.coordinator.CommitBlock(suite.chainA, suite.chainB) + "not matching, trusting period is different", func() { + subjectClientState.TrustingPeriod = time.Duration(time.Hour * 10) + substituteClientState.TrustingPeriod = time.Duration(time.Hour * 1) }, false, }, } @@ -320,37 +375,13 @@ func (suite *TendermintTestSuite) TestCheckProposedHeader() { suite.Run(tc.name, func() { suite.SetupTest() // reset - clientA, _ = suite.coordinator.SetupClients(suite.chainA, suite.chainB, exported.Ostracon) - clientState = suite.chainA.GetClientState(clientA).(*types.ClientState) - clientState.AllowUpdateAfterExpiry = true - clientState.AllowUpdateAfterMisbehaviour = false - - // expire client - suite.chainA.ExpireClient(clientState.TrustingPeriod) - suite.chainB.ExpireClient(clientState.TrustingPeriod) - suite.coordinator.CommitBlock(suite.chainA, suite.chainB) - - // use next header for chainB to unexpire clients but with empty trusted heights - // and validators. - header, err = suite.chainA.ConstructUpdateOCClientHeader(suite.chainB, clientA) - suite.Require().NoError(err) - header.TrustedHeight = clienttypes.ZeroHeight() - header.TrustedValidators = nil + subject, _ = suite.coordinator.SetupClients(suite.chainA, suite.chainB, exported.Ostracon) + substitute, _ = suite.coordinator.SetupClients(suite.chainA, suite.chainB, exported.Ostracon) tc.malleate() - clientStore := suite.chainA.App.IBCKeeper.ClientKeeper.ClientStore(suite.chainA.GetContext(), clientA) - cs, consState, err := clientState.CheckProposedHeaderAndUpdateState(suite.chainA.GetContext(), suite.chainA.App.AppCodec(), clientStore, header) + suite.Require().Equal(tc.expPass, types.IsMatchingClientState(*subjectClientState, *substituteClientState)) - if tc.expPass { - suite.Require().NoError(err) - suite.Require().NotNil(cs) - suite.Require().NotNil(consState) - } else { - suite.Require().Error(err) - suite.Require().Nil(cs) - suite.Require().Nil(consState) - } }) } } diff --git a/x/ibc/light-clients/99-ostracon/types/store.go b/x/ibc/light-clients/99-ostracon/types/store.go index e66aa51dbb..4b204854c1 100644 --- a/x/ibc/light-clients/99-ostracon/types/store.go +++ b/x/ibc/light-clients/99-ostracon/types/store.go @@ -14,9 +14,16 @@ import ( // KeyProcessedTime is appended to consensus state key to store the processed time var KeyProcessedTime = []byte("/processedTime") +// SetConsensusState stores the consensus state at the given height. +func SetConsensusState(clientStore sdk.KVStore, cdc codec.Codec, consensusState *ConsensusState, height exported.Height) { + key := host.ConsensusStateKey(height) + val := clienttypes.MustMarshalConsensusState(cdc, consensusState) + clientStore.Set(key, val) +} + // GetConsensusState retrieves the consensus state from the client prefixed // store. An error is returned if the consensus state does not exist. -func GetConsensusState(store sdk.KVStore, cdc codec.BinaryMarshaler, height exported.Height) (*ConsensusState, error) { +func GetConsensusState(store sdk.KVStore, cdc codec.Codec, height exported.Height) (*ConsensusState, error) { bz := store.Get(host.ConsensusStateKey(height)) if bz == nil { return nil, sdkerrors.Wrapf( diff --git a/x/ibc/light-clients/99-ostracon/types/update.go b/x/ibc/light-clients/99-ostracon/types/update.go index d6e233585c..399ea68651 100644 --- a/x/ibc/light-clients/99-ostracon/types/update.go +++ b/x/ibc/light-clients/99-ostracon/types/update.go @@ -38,7 +38,7 @@ import ( // Ostracon client validity checking uses the bisection algorithm described // in the [Ostracon spec](https://github.com/tendermint/spec/blob/master/spec/consensus/light-client.md). func (cs ClientState) CheckHeaderAndUpdateState( - ctx sdk.Context, cdc codec.BinaryMarshaler, clientStore sdk.KVStore, + ctx sdk.Context, cdc codec.Codec, clientStore sdk.KVStore, header exported.Header, ) (exported.ClientState, exported.ConsensusState, error) { tmHeader, ok := header.(*Header) diff --git a/x/ibc/light-clients/99-ostracon/types/upgrade.go b/x/ibc/light-clients/99-ostracon/types/upgrade.go index c66a0d2cc3..cf79672842 100644 --- a/x/ibc/light-clients/99-ostracon/types/upgrade.go +++ b/x/ibc/light-clients/99-ostracon/types/upgrade.go @@ -24,7 +24,7 @@ import ( // - any Ostracon chain specified parameter in upgraded client such as ChainID, UnbondingPeriod, // and ProofSpecs do not match parameters set by committed client func (cs ClientState) VerifyUpgradeAndUpdateState( - ctx sdk.Context, cdc codec.BinaryMarshaler, clientStore sdk.KVStore, + ctx sdk.Context, cdc codec.Codec, clientStore sdk.KVStore, upgradedClient exported.ClientState, upgradedConsState exported.ConsensusState, proofUpgradeClient, proofUpgradeConsState []byte, ) (exported.ClientState, exported.ConsensusState, error) { @@ -40,8 +40,8 @@ func (cs ClientState) VerifyUpgradeAndUpdateState( upgradedClient.GetLatestHeight(), lastHeight) } - // counterparty chain must commit the upgraded client with all client-customizable fields zeroed out - // at the upgrade path specified by current client + // upgraded client state and consensus state must be IBC tendermint client state and consensus state + // this may be modified in the future to upgrade to a new IBC tendermint type // counterparty must also commit to the upgraded consensus state at a sub-path under the upgrade path specified tmUpgradeClient, ok := upgradedClient.(*ClientState) if !ok { @@ -56,10 +56,10 @@ func (cs ClientState) VerifyUpgradeAndUpdateState( // unmarshal proofs var merkleProofClient, merkleProofConsState commitmenttypes.MerkleProof - if err := cdc.UnmarshalBinaryBare(proofUpgradeClient, &merkleProofClient); err != nil { + if err := cdc.Unmarshal(proofUpgradeClient, &merkleProofClient); err != nil { return nil, nil, sdkerrors.Wrapf(commitmenttypes.ErrInvalidProof, "could not unmarshal client merkle proof: %v", err) } - if err := cdc.UnmarshalBinaryBare(proofUpgradeConsState, &merkleProofConsState); err != nil { + if err := cdc.Unmarshal(proofUpgradeConsState, &merkleProofConsState); err != nil { return nil, nil, sdkerrors.Wrapf(commitmenttypes.ErrInvalidProof, "could not unmarshal consensus state merkle proof: %v", err) } diff --git a/x/ibc/light-clients/99-ostracon/types/upgrade_test.go b/x/ibc/light-clients/99-ostracon/types/upgrade_test.go index 7903db2be4..e3b41bd198 100644 --- a/x/ibc/light-clients/99-ostracon/types/upgrade_test.go +++ b/x/ibc/light-clients/99-ostracon/types/upgrade_test.go @@ -15,6 +15,8 @@ func (suite *TendermintTestSuite) TestVerifyUpgrade() { lastHeight clienttypes.Height clientA string proofUpgradedClient, proofUpgradedConsState []byte + upgradedClientBz, upgradedConsStateBz []byte + err error ) testCases := []struct { @@ -25,18 +27,12 @@ func (suite *TendermintTestSuite) TestVerifyUpgrade() { { name: "successful upgrade", setup: func() { - - upgradedClient = types.NewClientState("newChainId", types.DefaultTrustLevel, trustingPeriod, ubdPeriod+trustingPeriod, maxClockDrift, newClientHeight, commitmenttypes.GetSDKSpecs(), upgradePath, false, false) - upgradedConsState = &types.ConsensusState{ - NextValidatorsHash: []byte("nextValsHash"), - } - // upgrade Height is at next block lastHeight = clienttypes.NewHeight(0, uint64(suite.chainB.GetContext().BlockHeight()+1)) // zero custom fields and store in upgrade store - suite.chainB.App.UpgradeKeeper.SetUpgradedClient(suite.chainB.GetContext(), int64(lastHeight.GetRevisionHeight()), upgradedClient) - suite.chainB.App.UpgradeKeeper.SetUpgradedConsensusState(suite.chainB.GetContext(), int64(lastHeight.GetRevisionHeight()), upgradedConsState) + suite.chainB.App.UpgradeKeeper.SetUpgradedClient(suite.chainB.GetContext(), int64(lastHeight.GetRevisionHeight()), upgradedClientBz) + suite.chainB.App.UpgradeKeeper.SetUpgradedConsensusState(suite.chainB.GetContext(), int64(lastHeight.GetRevisionHeight()), upgradedConsStateBz) // commit upgrade store changes and update clients @@ -57,16 +53,16 @@ func (suite *TendermintTestSuite) TestVerifyUpgrade() { setup: func() { upgradedHeight := clienttypes.NewHeight(0, uint64(suite.chainB.GetContext().BlockHeight()+2)) upgradedClient = types.NewClientState("newChainId", types.DefaultTrustLevel, trustingPeriod, ubdPeriod+trustingPeriod, maxClockDrift, upgradedHeight, commitmenttypes.GetSDKSpecs(), upgradePath, false, false) - upgradedConsState = &types.ConsensusState{ - NextValidatorsHash: []byte("nextValsHash"), - } + upgradedClient = upgradedClient.ZeroCustomFields() + upgradedClientBz, err = clienttypes.MarshalClientState(suite.chainA.App.AppCodec(), upgradedClient) + suite.Require().NoError(err) // upgrade Height is at next block lastHeight = clienttypes.NewHeight(0, uint64(suite.chainB.GetContext().BlockHeight()+1)) // zero custom fields and store in upgrade store - suite.chainB.App.UpgradeKeeper.SetUpgradedClient(suite.chainB.GetContext(), int64(lastHeight.GetRevisionHeight()), upgradedClient) - suite.chainB.App.UpgradeKeeper.SetUpgradedConsensusState(suite.chainB.GetContext(), int64(lastHeight.GetRevisionHeight()), upgradedConsState) + suite.chainB.App.UpgradeKeeper.SetUpgradedClient(suite.chainB.GetContext(), int64(lastHeight.GetRevisionHeight()), upgradedClientBz) + suite.chainB.App.UpgradeKeeper.SetUpgradedConsensusState(suite.chainB.GetContext(), int64(lastHeight.GetRevisionHeight()), upgradedConsStateBz) // commit upgrade store changes and update clients @@ -86,18 +82,12 @@ func (suite *TendermintTestSuite) TestVerifyUpgrade() { { name: "unsuccessful upgrade: upgrade height revision height is more than the current client revision height", setup: func() { - - upgradedClient = types.NewClientState("newChainId", types.DefaultTrustLevel, trustingPeriod, ubdPeriod+trustingPeriod, maxClockDrift, newClientHeight, commitmenttypes.GetSDKSpecs(), upgradePath, false, false) - upgradedConsState = &types.ConsensusState{ - NextValidatorsHash: []byte("nextValsHash"), - } - // upgrade Height is 10 blocks from now lastHeight = clienttypes.NewHeight(0, uint64(suite.chainB.GetContext().BlockHeight()+10)) // zero custom fields and store in upgrade store - suite.chainB.App.UpgradeKeeper.SetUpgradedClient(suite.chainB.GetContext(), int64(lastHeight.GetRevisionHeight()), upgradedClient) - suite.chainB.App.UpgradeKeeper.SetUpgradedConsensusState(suite.chainB.GetContext(), int64(lastHeight.GetRevisionHeight()), upgradedConsState) + suite.chainB.App.UpgradeKeeper.SetUpgradedClient(suite.chainB.GetContext(), int64(lastHeight.GetRevisionHeight()), upgradedClientBz) + suite.chainB.App.UpgradeKeeper.SetUpgradedConsensusState(suite.chainB.GetContext(), int64(lastHeight.GetRevisionHeight()), upgradedConsStateBz) // commit upgrade store changes and update clients @@ -114,20 +104,43 @@ func (suite *TendermintTestSuite) TestVerifyUpgrade() { expPass: false, }, { - name: "unsuccessful upgrade: chain-specified parameters do not match committed client", + name: "unsuccessful upgrade: committed client does not have zeroed custom fields", setup: func() { - + // non-zeroed upgrade client upgradedClient = types.NewClientState("newChainId", types.DefaultTrustLevel, trustingPeriod, ubdPeriod+trustingPeriod, maxClockDrift, newClientHeight, commitmenttypes.GetSDKSpecs(), upgradePath, false, false) - upgradedConsState = &types.ConsensusState{ - NextValidatorsHash: []byte("nextValsHash"), - } + upgradedClientBz, err = clienttypes.MarshalClientState(suite.chainA.App.AppCodec(), upgradedClient) + suite.Require().NoError(err) + + // upgrade Height is at next block + lastHeight = clienttypes.NewHeight(0, uint64(suite.chainB.GetContext().BlockHeight()+1)) + + // zero custom fields and store in upgrade store + suite.chainB.App.UpgradeKeeper.SetUpgradedClient(suite.chainB.GetContext(), int64(lastHeight.GetRevisionHeight()), upgradedClientBz) + suite.chainB.App.UpgradeKeeper.SetUpgradedConsensusState(suite.chainB.GetContext(), int64(lastHeight.GetRevisionHeight()), upgradedConsStateBz) + // commit upgrade store changes and update clients + + suite.coordinator.CommitBlock(suite.chainB) + err := suite.coordinator.UpdateClient(suite.chainA, suite.chainB, clientA, exported.Ostracon) + suite.Require().NoError(err) + + cs, found := suite.chainA.App.IBCKeeper.ClientKeeper.GetClientState(suite.chainA.GetContext(), clientA) + suite.Require().True(found) + + proofUpgradedClient, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedClientKey(int64(lastHeight.GetRevisionHeight())), cs.GetLatestHeight().GetRevisionHeight()) + proofUpgradedConsState, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedConsStateKey(int64(lastHeight.GetRevisionHeight())), cs.GetLatestHeight().GetRevisionHeight()) + }, + expPass: false, + }, + { + name: "unsuccessful upgrade: chain-specified parameters do not match committed client", + setup: func() { // upgrade Height is at next block lastHeight = clienttypes.NewHeight(0, uint64(suite.chainB.GetContext().BlockHeight()+1)) // zero custom fields and store in upgrade store - suite.chainB.App.UpgradeKeeper.SetUpgradedClient(suite.chainB.GetContext(), int64(lastHeight.GetRevisionHeight()), upgradedClient) - suite.chainB.App.UpgradeKeeper.SetUpgradedConsensusState(suite.chainB.GetContext(), int64(lastHeight.GetRevisionHeight()), upgradedConsState) + suite.chainB.App.UpgradeKeeper.SetUpgradedClient(suite.chainB.GetContext(), int64(lastHeight.GetRevisionHeight()), upgradedClientBz) + suite.chainB.App.UpgradeKeeper.SetUpgradedConsensusState(suite.chainB.GetContext(), int64(lastHeight.GetRevisionHeight()), upgradedConsStateBz) // change upgradedClient client-specified parameters upgradedClient = types.NewClientState("wrongchainID", types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, newClientHeight, commitmenttypes.GetSDKSpecs(), upgradePath, true, true) @@ -147,15 +160,9 @@ func (suite *TendermintTestSuite) TestVerifyUpgrade() { { name: "unsuccessful upgrade: client-specified parameters do not match previous client", setup: func() { - - upgradedClient = types.NewClientState("newChainId", types.DefaultTrustLevel, trustingPeriod, ubdPeriod+trustingPeriod, maxClockDrift, lastHeight, commitmenttypes.GetSDKSpecs(), upgradePath, false, false) - upgradedConsState = &types.ConsensusState{ - NextValidatorsHash: []byte("nextValsHash"), - } - // zero custom fields and store in upgrade store - suite.chainB.App.UpgradeKeeper.SetUpgradedClient(suite.chainB.GetContext(), int64(lastHeight.GetRevisionHeight()), upgradedClient) - suite.chainB.App.UpgradeKeeper.SetUpgradedConsensusState(suite.chainB.GetContext(), int64(lastHeight.GetRevisionHeight()), upgradedConsState) + suite.chainB.App.UpgradeKeeper.SetUpgradedClient(suite.chainB.GetContext(), int64(lastHeight.GetRevisionHeight()), upgradedClientBz) + suite.chainB.App.UpgradeKeeper.SetUpgradedConsensusState(suite.chainB.GetContext(), int64(lastHeight.GetRevisionHeight()), upgradedConsStateBz) // change upgradedClient client-specified parameters upgradedClient = types.NewClientState("newChainId", types.DefaultTrustLevel, ubdPeriod, ubdPeriod+trustingPeriod, maxClockDrift+5, lastHeight, commitmenttypes.GetSDKSpecs(), upgradePath, true, false) @@ -175,18 +182,12 @@ func (suite *TendermintTestSuite) TestVerifyUpgrade() { { name: "unsuccessful upgrade: relayer-submitted consensus state does not match counterparty-committed consensus state", setup: func() { - - upgradedClient = types.NewClientState("newChainId", types.DefaultTrustLevel, trustingPeriod, ubdPeriod+trustingPeriod, maxClockDrift, newClientHeight, commitmenttypes.GetSDKSpecs(), upgradePath, false, false) - upgradedConsState = &types.ConsensusState{ - NextValidatorsHash: []byte("nextValsHash"), - } - // upgrade Height is at next block lastHeight = clienttypes.NewHeight(0, uint64(suite.chainB.GetContext().BlockHeight()+1)) // zero custom fields and store in upgrade store - suite.chainB.App.UpgradeKeeper.SetUpgradedClient(suite.chainB.GetContext(), int64(lastHeight.GetRevisionHeight()), upgradedClient) - suite.chainB.App.UpgradeKeeper.SetUpgradedConsensusState(suite.chainB.GetContext(), int64(lastHeight.GetRevisionHeight()), upgradedConsState) + suite.chainB.App.UpgradeKeeper.SetUpgradedClient(suite.chainB.GetContext(), int64(lastHeight.GetRevisionHeight()), upgradedClientBz) + suite.chainB.App.UpgradeKeeper.SetUpgradedConsensusState(suite.chainB.GetContext(), int64(lastHeight.GetRevisionHeight()), upgradedConsStateBz) // change submitted upgradedConsensusState upgradedConsState = &types.ConsensusState{ @@ -210,11 +211,7 @@ func (suite *TendermintTestSuite) TestVerifyUpgrade() { { name: "unsuccessful upgrade: client proof unmarshal failed", setup: func() { - upgradedClient = types.NewClientState("newChainId", types.DefaultTrustLevel, trustingPeriod, ubdPeriod+trustingPeriod, maxClockDrift, newClientHeight, commitmenttypes.GetSDKSpecs(), upgradePath, false, false) - upgradedConsState = &types.ConsensusState{ - NextValidatorsHash: []byte("nextValsHash"), - } - suite.chainB.App.UpgradeKeeper.SetUpgradedConsensusState(suite.chainB.GetContext(), int64(lastHeight.GetRevisionHeight()), upgradedConsState) + suite.chainB.App.UpgradeKeeper.SetUpgradedConsensusState(suite.chainB.GetContext(), int64(lastHeight.GetRevisionHeight()), upgradedConsStateBz) cs, found := suite.chainA.App.IBCKeeper.ClientKeeper.GetClientState(suite.chainA.GetContext(), clientA) suite.Require().True(found) @@ -228,12 +225,7 @@ func (suite *TendermintTestSuite) TestVerifyUpgrade() { { name: "unsuccessful upgrade: consensus state proof unmarshal failed", setup: func() { - upgradedClient = types.NewClientState("newChainId", types.DefaultTrustLevel, trustingPeriod, ubdPeriod+trustingPeriod, maxClockDrift, newClientHeight, commitmenttypes.GetSDKSpecs(), upgradePath, false, false) - upgradedConsState = &types.ConsensusState{ - NextValidatorsHash: []byte("nextValsHash"), - } - - suite.chainB.App.UpgradeKeeper.SetUpgradedClient(suite.chainB.GetContext(), int64(lastHeight.GetRevisionHeight()), upgradedClient) + suite.chainB.App.UpgradeKeeper.SetUpgradedClient(suite.chainB.GetContext(), int64(lastHeight.GetRevisionHeight()), upgradedClientBz) cs, found := suite.chainA.App.IBCKeeper.ClientKeeper.GetClientState(suite.chainA.GetContext(), clientA) suite.Require().True(found) @@ -247,16 +239,12 @@ func (suite *TendermintTestSuite) TestVerifyUpgrade() { { name: "unsuccessful upgrade: client proof verification failed", setup: func() { - // create but do not store upgraded client - upgradedClient = types.NewClientState("newChainId", types.DefaultTrustLevel, trustingPeriod, ubdPeriod+trustingPeriod, maxClockDrift, newClientHeight, commitmenttypes.GetSDKSpecs(), upgradePath, false, false) - upgradedConsState = &types.ConsensusState{ - NextValidatorsHash: []byte("nextValsHash"), - } + // do not store upgraded client // upgrade Height is at next block lastHeight = clienttypes.NewHeight(0, uint64(suite.chainB.GetContext().BlockHeight()+1)) - suite.chainB.App.UpgradeKeeper.SetUpgradedConsensusState(suite.chainB.GetContext(), int64(lastHeight.GetRevisionHeight()), upgradedConsState) + suite.chainB.App.UpgradeKeeper.SetUpgradedConsensusState(suite.chainB.GetContext(), int64(lastHeight.GetRevisionHeight()), upgradedConsStateBz) cs, found := suite.chainA.App.IBCKeeper.ClientKeeper.GetClientState(suite.chainA.GetContext(), clientA) suite.Require().True(found) @@ -269,16 +257,12 @@ func (suite *TendermintTestSuite) TestVerifyUpgrade() { { name: "unsuccessful upgrade: consensus state proof verification failed", setup: func() { - // create but do not store upgraded client - upgradedClient = types.NewClientState("newChainId", types.DefaultTrustLevel, trustingPeriod, ubdPeriod+trustingPeriod, maxClockDrift, newClientHeight, commitmenttypes.GetSDKSpecs(), upgradePath, false, false) - upgradedConsState = &types.ConsensusState{ - NextValidatorsHash: []byte("nextValsHash"), - } + // do not store upgraded client // upgrade Height is at next block lastHeight = clienttypes.NewHeight(0, uint64(suite.chainB.GetContext().BlockHeight()+1)) - suite.chainB.App.UpgradeKeeper.SetUpgradedClient(suite.chainB.GetContext(), int64(lastHeight.GetRevisionHeight()), upgradedClient) + suite.chainB.App.UpgradeKeeper.SetUpgradedClient(suite.chainB.GetContext(), int64(lastHeight.GetRevisionHeight()), upgradedClientBz) cs, found := suite.chainA.App.IBCKeeper.ClientKeeper.GetClientState(suite.chainA.GetContext(), clientA) suite.Require().True(found) @@ -291,17 +275,11 @@ func (suite *TendermintTestSuite) TestVerifyUpgrade() { { name: "unsuccessful upgrade: upgrade path is empty", setup: func() { - - upgradedClient = types.NewClientState("newChainId", types.DefaultTrustLevel, trustingPeriod, ubdPeriod+trustingPeriod, maxClockDrift, newClientHeight, commitmenttypes.GetSDKSpecs(), upgradePath, false, false) - upgradedConsState = &types.ConsensusState{ - NextValidatorsHash: []byte("nextValsHash"), - } - // upgrade Height is at next block lastHeight = clienttypes.NewHeight(0, uint64(suite.chainB.GetContext().BlockHeight()+1)) // zero custom fields and store in upgrade store - suite.chainB.App.UpgradeKeeper.SetUpgradedClient(suite.chainB.GetContext(), int64(lastHeight.GetRevisionHeight()), upgradedClient) + suite.chainB.App.UpgradeKeeper.SetUpgradedClient(suite.chainB.GetContext(), int64(lastHeight.GetRevisionHeight()), upgradedClientBz) // commit upgrade store changes and update clients @@ -325,17 +303,11 @@ func (suite *TendermintTestSuite) TestVerifyUpgrade() { { name: "unsuccessful upgrade: upgraded height is not greater than current height", setup: func() { - - upgradedClient = types.NewClientState("newChainId", types.DefaultTrustLevel, trustingPeriod, ubdPeriod+trustingPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), upgradePath, false, false) - upgradedConsState = &types.ConsensusState{ - NextValidatorsHash: []byte("nextValsHash"), - } - // upgrade Height is at next block lastHeight = clienttypes.NewHeight(0, uint64(suite.chainB.GetContext().BlockHeight()+1)) // zero custom fields and store in upgrade store - suite.chainB.App.UpgradeKeeper.SetUpgradedClient(suite.chainB.GetContext(), int64(lastHeight.GetRevisionHeight()), upgradedClient) + suite.chainB.App.UpgradeKeeper.SetUpgradedClient(suite.chainB.GetContext(), int64(lastHeight.GetRevisionHeight()), upgradedClientBz) // commit upgrade store changes and update clients @@ -354,17 +326,11 @@ func (suite *TendermintTestSuite) TestVerifyUpgrade() { { name: "unsuccessful upgrade: consensus state for upgrade height cannot be found", setup: func() { - - upgradedClient = types.NewClientState("newChainId", types.DefaultTrustLevel, trustingPeriod, ubdPeriod+trustingPeriod, maxClockDrift, newClientHeight, commitmenttypes.GetSDKSpecs(), upgradePath, false, false) - upgradedConsState = &types.ConsensusState{ - NextValidatorsHash: []byte("nextValsHash"), - } - // upgrade Height is at next block lastHeight = clienttypes.NewHeight(0, uint64(suite.chainB.GetContext().BlockHeight()+100)) // zero custom fields and store in upgrade store - suite.chainB.App.UpgradeKeeper.SetUpgradedClient(suite.chainB.GetContext(), int64(lastHeight.GetRevisionHeight()), upgradedClient) + suite.chainB.App.UpgradeKeeper.SetUpgradedClient(suite.chainB.GetContext(), int64(lastHeight.GetRevisionHeight()), upgradedClientBz) // commit upgrade store changes and update clients @@ -383,14 +349,8 @@ func (suite *TendermintTestSuite) TestVerifyUpgrade() { { name: "unsuccessful upgrade: client is expired", setup: func() { - - upgradedClient = types.NewClientState("newChainId", types.DefaultTrustLevel, trustingPeriod, ubdPeriod+trustingPeriod, maxClockDrift, lastHeight, commitmenttypes.GetSDKSpecs(), upgradePath, false, false) - upgradedConsState = &types.ConsensusState{ - NextValidatorsHash: []byte("nextValsHash"), - } - // zero custom fields and store in upgrade store - suite.chainB.App.UpgradeKeeper.SetUpgradedClient(suite.chainB.GetContext(), int64(lastHeight.GetRevisionHeight()), upgradedClient) + suite.chainB.App.UpgradeKeeper.SetUpgradedClient(suite.chainB.GetContext(), int64(lastHeight.GetRevisionHeight()), upgradedClientBz) // commit upgrade store changes and update clients @@ -412,17 +372,11 @@ func (suite *TendermintTestSuite) TestVerifyUpgrade() { { name: "unsuccessful upgrade: updated unbonding period is equal to trusting period", setup: func() { - - upgradedClient = types.NewClientState("newChainId", types.DefaultTrustLevel, trustingPeriod, trustingPeriod, maxClockDrift, newClientHeight, commitmenttypes.GetSDKSpecs(), upgradePath, false, false) - upgradedConsState = &types.ConsensusState{ - NextValidatorsHash: []byte("nextValsHash"), - } - // upgrade Height is at next block lastHeight = clienttypes.NewHeight(0, uint64(suite.chainB.GetContext().BlockHeight()+1)) // zero custom fields and store in upgrade store - suite.chainB.App.UpgradeKeeper.SetUpgradedClient(suite.chainB.GetContext(), int64(lastHeight.GetRevisionHeight()), upgradedClient) + suite.chainB.App.UpgradeKeeper.SetUpgradedClient(suite.chainB.GetContext(), int64(lastHeight.GetRevisionHeight()), upgradedClientBz) // commit upgrade store changes and update clients @@ -441,19 +395,17 @@ func (suite *TendermintTestSuite) TestVerifyUpgrade() { { name: "unsuccessful upgrade: final client is not valid", setup: func() { - // new client has smaller unbonding period such that old trusting period is no longer valid upgradedClient = types.NewClientState("newChainId", types.DefaultTrustLevel, trustingPeriod, trustingPeriod, maxClockDrift, newClientHeight, commitmenttypes.GetSDKSpecs(), upgradePath, false, false) - upgradedConsState = &types.ConsensusState{ - NextValidatorsHash: []byte("nextValsHash"), - } + upgradedClientBz, err = clienttypes.MarshalClientState(suite.chainA.App.AppCodec(), upgradedClient) + suite.Require().NoError(err) // upgrade Height is at next block lastHeight = clienttypes.NewHeight(0, uint64(suite.chainB.GetContext().BlockHeight()+1)) // zero custom fields and store in upgrade store - suite.chainB.App.UpgradeKeeper.SetUpgradedClient(suite.chainB.GetContext(), int64(lastHeight.GetRevisionHeight()), upgradedClient) - suite.chainB.App.UpgradeKeeper.SetUpgradedConsensusState(suite.chainB.GetContext(), int64(lastHeight.GetRevisionHeight()), upgradedConsState) + suite.chainB.App.UpgradeKeeper.SetUpgradedClient(suite.chainB.GetContext(), int64(lastHeight.GetRevisionHeight()), upgradedClientBz) + suite.chainB.App.UpgradeKeeper.SetUpgradedConsensusState(suite.chainB.GetContext(), int64(lastHeight.GetRevisionHeight()), upgradedConsStateBz) // commit upgrade store changes and update clients @@ -478,6 +430,16 @@ func (suite *TendermintTestSuite) TestVerifyUpgrade() { suite.SetupTest() clientA, _ = suite.coordinator.SetupClients(suite.chainA, suite.chainB, exported.Ostracon) + upgradedClient = types.NewClientState("newChainId", types.DefaultTrustLevel, trustingPeriod, ubdPeriod+trustingPeriod, maxClockDrift, newClientHeight, commitmenttypes.GetSDKSpecs(), upgradePath, false, false) + upgradedClient = upgradedClient.ZeroCustomFields() + upgradedClientBz, err = clienttypes.MarshalClientState(suite.chainA.App.AppCodec(), upgradedClient) + suite.Require().NoError(err) + + upgradedConsState = &types.ConsensusState{ + NextValidatorsHash: []byte("nextValsHash"), + } + upgradedConsStateBz, err = clienttypes.MarshalConsensusState(suite.chainA.App.AppCodec(), upgradedConsState) + suite.Require().NoError(err) tc.setup() diff --git a/x/ibc/testing/chain.go b/x/ibc/testing/chain.go index 7e165a6223..f74ea600fb 100644 --- a/x/ibc/testing/chain.go +++ b/x/ibc/testing/chain.go @@ -91,7 +91,7 @@ type TestChain struct { CurrentHeader ocproto.Header // header for current block height QueryServer types.QueryServer TxConfig client.TxConfig - Codec codec.BinaryMarshaler + Codec codec.Codec Vals *octypes.ValidatorSet Voters *octypes.VoterSet @@ -195,7 +195,7 @@ func (chain *TestChain) QueryProof(key []byte) ([]byte, clienttypes.Height) { merkleProof, err := commitmenttypes.ConvertProofs(res.ProofOps) require.NoError(chain.t, err) - proof, err := chain.App.AppCodec().MarshalBinaryBare(&merkleProof) + proof, err := chain.App.AppCodec().Marshal(&merkleProof) require.NoError(chain.t, err) revision := clienttypes.ParseChainID(chain.ChainID) @@ -219,7 +219,7 @@ func (chain *TestChain) QueryUpgradeProof(key []byte, height uint64) ([]byte, cl merkleProof, err := commitmenttypes.ConvertProofs(res.ProofOps) require.NoError(chain.t, err) - proof, err := chain.App.AppCodec().MarshalBinaryBare(&merkleProof) + proof, err := chain.App.AppCodec().Marshal(&merkleProof) require.NoError(chain.t, err) revision := clienttypes.ParseChainID(chain.ChainID) @@ -346,7 +346,7 @@ func (chain *TestChain) GetValsAtHeight(height int64) (*octypes.ValidatorSet, bo valSet := stakingtypes.Validators(histInfo.Valset) - ocValidators, err := teststaking.ToOcValidators(valSet) + ocValidators, err := teststaking.ToOcValidators(valSet, sdk.DefaultPowerReduction) if err != nil { panic(err) } @@ -362,7 +362,7 @@ func (chain *TestChain) GetVotersAtHeight(height int64) (*octypes.VoterSet, bool // Voters of test chain is always same to validator set voters := stakingtypes.Validators(histInfo.Valset) - ocVoters, err := teststaking.ToOcValidators(voters) + ocVoters, err := teststaking.ToOcValidators(voters, sdk.DefaultPowerReduction) if err != nil { panic(err) } diff --git a/x/ibc/testing/mock/mock.go b/x/ibc/testing/mock/mock.go index 69e06ea54f..b6b0ea0c08 100644 --- a/x/ibc/testing/mock/mock.go +++ b/x/ibc/testing/mock/mock.go @@ -46,12 +46,12 @@ func (AppModuleBasic) RegisterLegacyAminoCodec(*codec.LegacyAmino) {} func (AppModuleBasic) RegisterInterfaces(registry codectypes.InterfaceRegistry) {} // DefaultGenesis implements AppModuleBasic interface. -func (AppModuleBasic) DefaultGenesis(cdc codec.JSONMarshaler) json.RawMessage { +func (AppModuleBasic) DefaultGenesis(cdc codec.JSONCodec) json.RawMessage { return nil } // ValidateGenesis implements the AppModuleBasic interface. -func (AppModuleBasic) ValidateGenesis(codec.JSONMarshaler, client.TxEncodingConfig, json.RawMessage) error { +func (AppModuleBasic) ValidateGenesis(codec.JSONCodec, client.TxEncodingConfig, json.RawMessage) error { return nil } @@ -106,12 +106,12 @@ func (am AppModule) LegacyQuerierHandler(*codec.LegacyAmino) sdk.Querier { func (am AppModule) RegisterServices(module.Configurator) {} // InitGenesis implements the AppModule interface. -func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONMarshaler, data json.RawMessage) []abci.ValidatorUpdate { +func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONCodec, data json.RawMessage) []abci.ValidatorUpdate { return []abci.ValidatorUpdate{} } // ExportGenesis implements the AppModule interface. -func (am AppModule) ExportGenesis(ctx sdk.Context, cdc codec.JSONMarshaler) json.RawMessage { +func (am AppModule) ExportGenesis(ctx sdk.Context, cdc codec.JSONCodec) json.RawMessage { return nil } @@ -124,8 +124,6 @@ func (am AppModule) EndBlock(ctx sdk.Context, req abci.RequestEndBlock) []abci.V return []abci.ValidatorUpdate{} } -// ____________________________________________________________________________ - // OnChanOpenInit implements the IBCModule interface. func (am AppModule) OnChanOpenInit( ctx sdk.Context, _ channeltypes.Order, _ []string, portID string, diff --git a/x/ibc/testing/solomachine.go b/x/ibc/testing/solomachine.go index 733d8e3b53..1545ecbe0b 100644 --- a/x/ibc/testing/solomachine.go +++ b/x/ibc/testing/solomachine.go @@ -26,7 +26,7 @@ var prefix = commitmenttypes.NewMerklePrefix([]byte("ibc")) type Solomachine struct { t *testing.T - cdc codec.BinaryMarshaler + cdc codec.Codec ClientID string PrivateKeys []cryptotypes.PrivKey // keys used for signing PublicKeys []cryptotypes.PubKey // keys used for generating solo machine pub key @@ -39,7 +39,7 @@ type Solomachine struct { // NewSolomachine returns a new solomachine instance with an `nKeys` amount of // generated private/public key pairs and a sequence starting at 1. If nKeys // is greater than 1 then a multisig public key is used. -func NewSolomachine(t *testing.T, cdc codec.BinaryMarshaler, clientID, diversifier string, nKeys uint64) *Solomachine { +func NewSolomachine(t *testing.T, cdc codec.Codec, clientID, diversifier string, nKeys uint64) *Solomachine { privKeys, pubKeys, pk := GenerateKeys(t, nKeys) return &Solomachine{ @@ -121,7 +121,7 @@ func (solo *Solomachine) CreateHeader() *solomachinetypes.Header { NewDiversifier: solo.Diversifier, } - dataBz, err := solo.cdc.MarshalBinaryBare(data) + dataBz, err := solo.cdc.Marshal(data) require.NoError(solo.t, err) signBytes := &solomachinetypes.SignBytes{ @@ -132,7 +132,7 @@ func (solo *Solomachine) CreateHeader() *solomachinetypes.Header { Data: dataBz, } - bz, err := solo.cdc.MarshalBinaryBare(signBytes) + bz, err := solo.cdc.Marshal(signBytes) require.NoError(solo.t, err) sig := solo.GenerateSignature(bz) @@ -173,7 +173,7 @@ func (solo *Solomachine) CreateMisbehaviour() *solomachinetypes.Misbehaviour { Data: dataOne, } - bz, err := solo.cdc.MarshalBinaryBare(signBytes) + bz, err := solo.cdc.Marshal(signBytes) require.NoError(solo.t, err) sig := solo.GenerateSignature(bz) @@ -195,7 +195,7 @@ func (solo *Solomachine) CreateMisbehaviour() *solomachinetypes.Misbehaviour { Data: dataTwo, } - bz, err = solo.cdc.MarshalBinaryBare(signBytes) + bz, err = solo.cdc.Marshal(signBytes) require.NoError(solo.t, err) sig = solo.GenerateSignature(bz) @@ -243,7 +243,7 @@ func (solo *Solomachine) GenerateSignature(signBytes []byte) []byte { } protoSigData := signing.SignatureDataToProto(sigData) - bz, err := solo.cdc.MarshalBinaryBare(protoSigData) + bz, err := solo.cdc.Marshal(protoSigData) require.NoError(solo.t, err) return bz diff --git a/x/mint/client/cli/query.go b/x/mint/client/cli/query.go index 28c9a59703..5221c0af7c 100644 --- a/x/mint/client/cli/query.go +++ b/x/mint/client/cli/query.go @@ -1,7 +1,6 @@ package cli import ( - "context" "fmt" "github.com/spf13/cobra" @@ -45,7 +44,7 @@ func GetCmdQueryParams() *cobra.Command { queryClient := types.NewQueryClient(clientCtx) params := &types.QueryParamsRequest{} - res, err := queryClient.Params(context.Background(), params) + res, err := queryClient.Params(cmd.Context(), params) if err != nil { return err @@ -75,7 +74,7 @@ func GetCmdQueryInflation() *cobra.Command { queryClient := types.NewQueryClient(clientCtx) params := &types.QueryInflationRequest{} - res, err := queryClient.Inflation(context.Background(), params) + res, err := queryClient.Inflation(cmd.Context(), params) if err != nil { return err @@ -105,7 +104,7 @@ func GetCmdQueryAnnualProvisions() *cobra.Command { queryClient := types.NewQueryClient(clientCtx) params := &types.QueryAnnualProvisionsRequest{} - res, err := queryClient.AnnualProvisions(context.Background(), params) + res, err := queryClient.AnnualProvisions(cmd.Context(), params) if err != nil { return err diff --git a/x/mint/client/rest/grpc_query_test.go b/x/mint/client/rest/grpc_query_test.go index de5d479304..7543b85f2f 100644 --- a/x/mint/client/rest/grpc_query_test.go +++ b/x/mint/client/rest/grpc_query_test.go @@ -101,7 +101,7 @@ func (s *IntegrationTestSuite) TestQueryGRPC() { resp, err := testutil.GetRequestWithHeaders(tc.url, tc.headers) s.Run(tc.name, func() { s.Require().NoError(err) - s.Require().NoError(val.ClientCtx.JSONMarshaler.UnmarshalJSON(resp, tc.respType)) + s.Require().NoError(val.ClientCtx.Codec.UnmarshalJSON(resp, tc.respType)) s.Require().Equal(tc.expected.String(), tc.respType.String()) }) } diff --git a/x/mint/client/testutil/cli_test.go b/x/mint/client/testutil/cli_test.go new file mode 100644 index 0000000000..8ded31fefa --- /dev/null +++ b/x/mint/client/testutil/cli_test.go @@ -0,0 +1,18 @@ +//go:build norace +// +build norace + +package testutil + +import ( + "testing" + + "github.com/line/lbm-sdk/testutil/network" + + "github.com/stretchr/testify/suite" +) + +func TestIntegrationTestSuite(t *testing.T) { + cfg := network.DefaultConfig() + cfg.NumValidators = 1 + suite.Run(t, NewIntegrationTestSuite(cfg)) +} diff --git a/x/mint/client/cli/cli_test.go b/x/mint/client/testutil/suite.go similarity index 87% rename from x/mint/client/cli/cli_test.go rename to x/mint/client/testutil/suite.go index 69aaf8c7cb..02b4cddf10 100644 --- a/x/mint/client/cli/cli_test.go +++ b/x/mint/client/testutil/suite.go @@ -1,18 +1,16 @@ -// +build norace - -package cli_test +package testutil import ( "fmt" "strings" - "testing" - ostcli "github.com/line/ostracon/libs/cli" "github.com/stretchr/testify/suite" + ostcli "github.com/line/ostracon/libs/cli" + "github.com/line/lbm-sdk/client/flags" clitestutil "github.com/line/lbm-sdk/testutil/cli" - testnet "github.com/line/lbm-sdk/testutil/network" + "github.com/line/lbm-sdk/testutil/network" sdk "github.com/line/lbm-sdk/types" "github.com/line/lbm-sdk/x/mint/client/cli" minttypes "github.com/line/lbm-sdk/x/mint/types" @@ -21,32 +19,33 @@ import ( type IntegrationTestSuite struct { suite.Suite - cfg testnet.Config - network *testnet.Network + cfg network.Config + network *network.Network +} + +func NewIntegrationTestSuite(cfg network.Config) *IntegrationTestSuite { + return &IntegrationTestSuite{cfg: cfg} } func (s *IntegrationTestSuite) SetupSuite() { s.T().Log("setting up integration test suite") - cfg := testnet.DefaultConfig() - genesisState := cfg.GenesisState - cfg.NumValidators = 1 + genesisState := s.cfg.GenesisState var mintData minttypes.GenesisState - s.Require().NoError(cfg.Codec.UnmarshalJSON(genesisState[minttypes.ModuleName], &mintData)) + s.Require().NoError(s.cfg.Codec.UnmarshalJSON(genesisState[minttypes.ModuleName], &mintData)) inflation := sdk.MustNewDecFromStr("1.0") mintData.Minter.Inflation = inflation mintData.Params.InflationMin = inflation mintData.Params.InflationMax = inflation - mintDataBz, err := cfg.Codec.MarshalJSON(&mintData) + mintDataBz, err := s.cfg.Codec.MarshalJSON(&mintData) s.Require().NoError(err) genesisState[minttypes.ModuleName] = mintDataBz - cfg.GenesisState = genesisState + s.cfg.GenesisState = genesisState - s.cfg = cfg - s.network = testnet.New(s.T(), cfg) + s.network = network.New(s.T(), s.cfg) _, err = s.network.WaitForHeight(1) s.Require().NoError(err) @@ -163,7 +162,3 @@ func (s *IntegrationTestSuite) TestGetCmdQueryAnnualProvisions() { }) } } - -func TestIntegrationTestSuite(t *testing.T) { - suite.Run(t, new(IntegrationTestSuite)) -} diff --git a/x/mint/keeper/keeper.go b/x/mint/keeper/keeper.go index eb824c7b45..979fcbda7b 100644 --- a/x/mint/keeper/keeper.go +++ b/x/mint/keeper/keeper.go @@ -11,9 +11,9 @@ import ( // Keeper of the mint store type Keeper struct { - cdc codec.BinaryMarshaler + cdc codec.BinaryCodec storeKey sdk.StoreKey - paramSpace *paramtypes.Subspace + paramSpace paramtypes.Subspace stakingKeeper types.StakingKeeper bankKeeper types.BankKeeper feeCollectorName string @@ -21,7 +21,7 @@ type Keeper struct { // NewKeeper creates a new mint Keeper instance func NewKeeper( - cdc codec.BinaryMarshaler, key sdk.StoreKey, paramSpace *paramtypes.Subspace, + cdc codec.BinaryCodec, key sdk.StoreKey, paramSpace paramtypes.Subspace, sk types.StakingKeeper, ak types.AccountKeeper, bk types.BankKeeper, feeCollectorName string, ) Keeper { @@ -45,8 +45,6 @@ func NewKeeper( } } -// ______________________________________________________________________ - // Logger returns a module-specific logger. func (k Keeper) Logger(ctx sdk.Context) log.Logger { return ctx.Logger().With("module", "x/"+types.ModuleName) @@ -60,19 +58,17 @@ func (k Keeper) GetMinter(ctx sdk.Context) (minter types.Minter) { panic("stored minter should not have been nil") } - k.cdc.MustUnmarshalBinaryBare(b, &minter) + k.cdc.MustUnmarshal(b, &minter) return } // set the minter func (k Keeper) SetMinter(ctx sdk.Context, minter types.Minter) { store := ctx.KVStore(k.storeKey) - b := k.cdc.MustMarshalBinaryBare(&minter) + b := k.cdc.MustMarshal(&minter) store.Set(types.MinterKey, b) } -// ______________________________________________________________________ - // GetParams returns the total set of minting parameters. func (k Keeper) GetParams(ctx sdk.Context) (params types.Params) { k.paramSpace.GetParamSet(ctx, ¶ms) @@ -84,8 +80,6 @@ func (k Keeper) SetParams(ctx sdk.Context, params types.Params) { k.paramSpace.SetParamSet(ctx, ¶ms) } -// ______________________________________________________________________ - // StakingTokenSupply implements an alias call to the underlying staking keeper's // StakingTokenSupply to be used in BeginBlocker. func (k Keeper) StakingTokenSupply(ctx sdk.Context) sdk.Int { diff --git a/x/mint/module.go b/x/mint/module.go index 4c5ec1e1e2..b8241e0c2a 100644 --- a/x/mint/module.go +++ b/x/mint/module.go @@ -32,7 +32,7 @@ var ( // AppModuleBasic defines the basic application module used by the mint module. type AppModuleBasic struct { - cdc codec.Marshaler + cdc codec.Codec } var _ module.AppModuleBasic = AppModuleBasic{} @@ -50,12 +50,12 @@ func (b AppModuleBasic) RegisterInterfaces(_ cdctypes.InterfaceRegistry) {} // DefaultGenesis returns default genesis state as raw bytes for the mint // module. -func (AppModuleBasic) DefaultGenesis(cdc codec.JSONMarshaler) json.RawMessage { +func (AppModuleBasic) DefaultGenesis(cdc codec.JSONCodec) json.RawMessage { return cdc.MustMarshalJSON(types.DefaultGenesisState()) } // ValidateGenesis performs genesis state validation for the mint module. -func (AppModuleBasic) ValidateGenesis(cdc codec.JSONMarshaler, config client.TxEncodingConfig, bz json.RawMessage) error { +func (AppModuleBasic) ValidateGenesis(cdc codec.JSONCodec, config client.TxEncodingConfig, bz json.RawMessage) error { var data types.GenesisState if err := cdc.UnmarshalJSON(bz, &data); err != nil { return fmt.Errorf("failed to unmarshal %s genesis state: %w", types.ModuleName, err) @@ -83,8 +83,6 @@ func (AppModuleBasic) GetQueryCmd() *cobra.Command { return cli.GetQueryCmd() } -// ____________________________________________________________________________ - // AppModule implements an application module for the mint module. type AppModule struct { AppModuleBasic @@ -94,7 +92,7 @@ type AppModule struct { } // NewAppModule creates a new AppModule object -func NewAppModule(cdc codec.Marshaler, keeper keeper.Keeper, ak types.AccountKeeper) AppModule { +func NewAppModule(cdc codec.Codec, keeper keeper.Keeper, ak types.AccountKeeper) AppModule { return AppModule{ AppModuleBasic: AppModuleBasic{cdc: cdc}, keeper: keeper, @@ -136,7 +134,7 @@ func (am AppModule) RegisterServices(cfg module.Configurator) { // InitGenesis performs genesis initialization for the mint module. It returns // no validator updates. -func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONMarshaler, data json.RawMessage) []abci.ValidatorUpdate { +func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONCodec, data json.RawMessage) []abci.ValidatorUpdate { var genesisState types.GenesisState cdc.MustUnmarshalJSON(data, &genesisState) @@ -146,7 +144,7 @@ func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONMarshaler, data j // ExportGenesis returns the exported genesis state as raw bytes for the mint // module. -func (am AppModule) ExportGenesis(ctx sdk.Context, cdc codec.JSONMarshaler) json.RawMessage { +func (am AppModule) ExportGenesis(ctx sdk.Context, cdc codec.JSONCodec) json.RawMessage { gs := ExportGenesis(ctx, am.keeper) return cdc.MustMarshalJSON(gs) } @@ -165,8 +163,6 @@ func (AppModule) EndBlock(_ sdk.Context, _ abci.RequestEndBlock) []abci.Validato return []abci.ValidatorUpdate{} } -// ____________________________________________________________________________ - // AppModuleSimulation functions // GenerateGenesisState creates a randomized GenState of the mint module. diff --git a/x/mint/simulation/decoder.go b/x/mint/simulation/decoder.go index 4b0c06270d..f10f622958 100644 --- a/x/mint/simulation/decoder.go +++ b/x/mint/simulation/decoder.go @@ -11,13 +11,13 @@ import ( // NewDecodeStore returns a decoder function closure that umarshals the KVPair's // Value to the corresponding mint type. -func NewDecodeStore(cdc codec.Marshaler) func(kvA, kvB kv.Pair) string { +func NewDecodeStore(cdc codec.Codec) func(kvA, kvB kv.Pair) string { return func(kvA, kvB kv.Pair) string { switch { case bytes.Equal(kvA.Key, types.MinterKey): var minterA, minterB types.Minter - cdc.MustUnmarshalBinaryBare(kvA.Value, &minterA) - cdc.MustUnmarshalBinaryBare(kvB.Value, &minterB) + cdc.MustUnmarshal(kvA.Value, &minterA) + cdc.MustUnmarshal(kvB.Value, &minterB) return fmt.Sprintf("%v\n%v", minterA, minterB) default: panic(fmt.Sprintf("invalid mint key %X", kvA.Key)) diff --git a/x/mint/simulation/decoder_test.go b/x/mint/simulation/decoder_test.go index af8cbe76a8..7afc813760 100644 --- a/x/mint/simulation/decoder_test.go +++ b/x/mint/simulation/decoder_test.go @@ -14,14 +14,14 @@ import ( ) func TestDecodeStore(t *testing.T) { - cdc, _ := simapp.MakeCodecs() + cdc := simapp.MakeTestEncodingConfig().Marshaler dec := simulation.NewDecodeStore(cdc) minter := types.NewMinter(sdk.OneDec(), sdk.NewDec(15)) kvPairs := kv.Pairs{ Pairs: []kv.Pair{ - {Key: types.MinterKey, Value: cdc.MustMarshalBinaryBare(&minter)}, + {Key: types.MinterKey, Value: cdc.MustMarshal(&minter)}, {Key: []byte{0x99}, Value: []byte{0x99}}, }, } diff --git a/x/mint/spec/01_concepts.md b/x/mint/spec/01_concepts.md index 1dd137b97b..e17e7845e8 100644 --- a/x/mint/spec/01_concepts.md +++ b/x/mint/spec/01_concepts.md @@ -7,8 +7,9 @@ order: 0 ## The Minting Mechanism The minting mechanism was designed to: - - allow for a flexible inflation rate determined by market demand targeting a particular bonded-stake ratio - - effect a balance between market liquidity and staked supply + +- allow for a flexible inflation rate determined by market demand targeting a particular bonded-stake ratio +- effect a balance between market liquidity and staked supply In order to best determine the appropriate market rate for inflation rewards, a moving change rate is used. The moving change rate mechanism ensures that if @@ -17,10 +18,11 @@ adjust to further incentivize or disincentivize being bonded, respectively. Sett %-bonded at less than 100% encourages the network to maintain some non-staked tokens which should help provide some liquidity. -It can be broken down in the following way: - - If the inflation rate is below the goal %-bonded the inflation rate will +It can be broken down in the following way: + +- If the inflation rate is below the goal %-bonded the inflation rate will increase until a maximum value is reached - - If the goal % bonded (67% in Cosmos-Hub) is maintained, then the inflation - rate will stay constant - - If the inflation rate is above the goal %-bonded the inflation rate will +- If the goal % bonded (67% in Cosmos-Hub) is maintained, then the inflation + rate will stay constant +- If the inflation rate is above the goal %-bonded the inflation rate will decrease until a minimum value is reached diff --git a/x/mint/spec/02_state.md b/x/mint/spec/02_state.md index c4d7a3eff1..9e25ac1b34 100644 --- a/x/mint/spec/02_state.md +++ b/x/mint/spec/02_state.md @@ -8,28 +8,14 @@ order: 2 The minter is a space for holding current inflation information. - - Minter: `0x00 -> amino(minter)` +- Minter: `0x00 -> ProtocolBuffer(minter)` -```go -type Minter struct { - Inflation sdk.Dec // current annual inflation rate - AnnualProvisions sdk.Dec // current annual exptected provisions -} -``` ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.40.0-rc7/proto/cosmos/mint/v1beta1/mint.proto#L8-L19 ## Params -Minting params are held in the global params store. +Minting params are held in the global params store. - - Params: `mint/params -> amino(params)` +- Params: `mint/params -> legacy_amino(params)` -```go -type Params struct { - MintDenom string // type of coin to mint - InflationRateChange sdk.Dec // maximum annual change in inflation rate - InflationMax sdk.Dec // maximum inflation rate - InflationMin sdk.Dec // minimum inflation rate - GoalBonded sdk.Dec // goal of percent bonded atoms - BlocksPerYear uint64 // expected blocks per year -} -``` ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.40.0-rc7/proto/cosmos/mint/v1beta1/mint.proto#L21-L53 diff --git a/x/mint/spec/03_begin_block.md b/x/mint/spec/03_begin_block.md index 33eeffa529..2f23f0aeb1 100644 --- a/x/mint/spec/03_begin_block.md +++ b/x/mint/spec/03_begin_block.md @@ -36,7 +36,7 @@ NextInflationRate(params Params, bondedRatio sdk.Dec) (inflation sdk.Dec) { ## NextAnnualProvisions Calculate the annual provisions based on current total supply and inflation -rate. This parameter is calculated once per block. +rate. This parameter is calculated once per block. ``` NextAnnualProvisions(params Params, totalSupply sdk.Dec) (provisions sdk.Dec) { diff --git a/x/mint/spec/06_client.md b/x/mint/spec/06_client.md new file mode 100644 index 0000000000..e2c366d932 --- /dev/null +++ b/x/mint/spec/06_client.md @@ -0,0 +1,224 @@ + + +# Client + +## CLI + +A user can query and interact with the `mint` module using the CLI. + +### Query + +The `query` commands allow users to query `mint` state. + +``` +simd query mint --help +``` + +#### annual-provisions + +The `annual-provisions` command allow users to query the current minting annual provisions value + +``` +simd query mint annual-provisions [flags] +``` + +Example: + +``` +simd query mint annual-provisions +``` + +Example Output: + +``` +22268504368893.612100895088410693 +``` + +#### inflation + +The `inflation` command allow users to query the current minting inflation value + +``` +simd query mint inflation [flags] +``` + +Example: + +``` +simd query mint inflation +``` + +Example Output: + +``` +0.199200302563256955 +``` + +#### params + +The `params` command allow users to query the current minting parameters + +``` +simd query mint params [flags] +``` + +Example: + +``` +blocks_per_year: "4360000" +goal_bonded: "0.670000000000000000" +inflation_max: "0.200000000000000000" +inflation_min: "0.070000000000000000" +inflation_rate_change: "0.130000000000000000" +mint_denom: stake +``` + +## gRPC + +A user can query the `mint` module using gRPC endpoints. + +### AnnualProvisions + +The `AnnualProvisions` endpoint allow users to query the current minting annual provisions value + +``` +/cosmos.mint.v1beta1.Query/AnnualProvisions +``` + +Example: + +``` +grpcurl -plaintext localhost:9090 cosmos.mint.v1beta1.Query/AnnualProvisions +``` + +Example Output: + +``` +{ + "annualProvisions": "1432452520532626265712995618" +} +``` + +### Inflation + +The `Inflation` endpoint allow users to query the current minting inflation value + +``` +/cosmos.mint.v1beta1.Query/Inflation +``` + +Example: + +``` +grpcurl -plaintext localhost:9090 cosmos.mint.v1beta1.Query/Inflation +``` + +Example Output: + +``` +{ + "inflation": "130197115720711261" +} +``` + +### Params + +The `Params` endpoint allow users to query the current minting parameters + +``` +/cosmos.mint.v1beta1.Query/Params +``` + +Example: + +``` +grpcurl -plaintext localhost:9090 cosmos.mint.v1beta1.Query/Params +``` + +Example Output: + +``` +{ + "params": { + "mintDenom": "stake", + "inflationRateChange": "130000000000000000", + "inflationMax": "200000000000000000", + "inflationMin": "70000000000000000", + "goalBonded": "670000000000000000", + "blocksPerYear": "6311520" + } +} +``` + +## REST + +A user can query the `mint` module using REST endpoints. + +### annual-provisions + +``` +/cosmos/mint/v1beta1/annual_provisions +``` + +Example: + +``` +curl "localhost:1317/cosmos/mint/v1beta1/annual_provisions" +``` + +Example Output: + +``` +{ + "annualProvisions": "1432452520532626265712995618" +} +``` + +### inflation + +``` +/cosmos/mint/v1beta1/inflation +``` + +Example: + +``` +curl "localhost:1317/cosmos/mint/v1beta1/inflation" +``` + +Example Output: + +``` +{ + "inflation": "130197115720711261" +} +``` + +### params + +``` +/cosmos/mint/v1beta1/params +``` + +Example: + +``` +curl "localhost:1317/cosmos/mint/v1beta1/params" +``` + +Example Output: + +``` +{ + "params": { + "mintDenom": "stake", + "inflationRateChange": "130000000000000000", + "inflationMax": "200000000000000000", + "inflationMin": "70000000000000000", + "goalBonded": "670000000000000000", + "blocksPerYear": "6311520" + } +} +``` diff --git a/x/mint/spec/README.md b/x/mint/spec/README.md index 950cadbb1c..dc60da9995 100644 --- a/x/mint/spec/README.md +++ b/x/mint/spec/README.md @@ -20,4 +20,3 @@ parent: 4. **[Parameters](04_params.md)** 5. **[Events](05_events.md)** - [BeginBlocker](05_events.md#beginblocker) - diff --git a/x/mint/types/minter_test.go b/x/mint/types/minter_test.go index c988244adc..778a3c4f71 100644 --- a/x/mint/types/minter_test.go +++ b/x/mint/types/minter_test.go @@ -89,6 +89,7 @@ func TestBlockProvision(t *testing.T) { // using sdk.Dec operations: (current implementation) // BenchmarkBlockProvision-4 3000000 429 ns/op func BenchmarkBlockProvision(b *testing.B) { + b.ReportAllocs() minter := InitialMinter(sdk.NewDecWithPrec(1, 1)) params := DefaultParams() @@ -105,6 +106,7 @@ func BenchmarkBlockProvision(b *testing.B) { // Next inflation benchmarking // BenchmarkNextInflation-4 1000000 1828 ns/op func BenchmarkNextInflation(b *testing.B) { + b.ReportAllocs() minter := InitialMinter(sdk.NewDecWithPrec(1, 1)) params := DefaultParams() bondedRatio := sdk.NewDecWithPrec(1, 1) @@ -119,6 +121,7 @@ func BenchmarkNextInflation(b *testing.B) { // Next annual provisions benchmarking // BenchmarkNextAnnualProvisions-4 5000000 251 ns/op func BenchmarkNextAnnualProvisions(b *testing.B) { + b.ReportAllocs() minter := InitialMinter(sdk.NewDecWithPrec(1, 1)) params := DefaultParams() totalSupply := sdk.NewInt(100000000000000) diff --git a/x/mint/types/query.pb.gw.go b/x/mint/types/query.pb.gw.go index a2574065e8..b437c09994 100644 --- a/x/mint/types/query.pb.gw.go +++ b/x/mint/types/query.pb.gw.go @@ -256,11 +256,11 @@ func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, clie } var ( - pattern_Query_Params_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"lbm", "mint", "v1", "params"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_Query_Params_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"lbm", "mint", "v1", "params"}, "", runtime.AssumeColonVerbOpt(false))) - pattern_Query_Inflation_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"lbm", "mint", "v1", "inflation"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_Query_Inflation_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"lbm", "mint", "v1", "inflation"}, "", runtime.AssumeColonVerbOpt(false))) - pattern_Query_AnnualProvisions_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"lbm", "mint", "v1", "annual_provisions"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_Query_AnnualProvisions_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"lbm", "mint", "v1", "annual_provisions"}, "", runtime.AssumeColonVerbOpt(false))) ) var ( diff --git a/x/params/client/cli/query.go b/x/params/client/cli/query.go index b83fc00502..bf84c7b638 100644 --- a/x/params/client/cli/query.go +++ b/x/params/client/cli/query.go @@ -1,8 +1,6 @@ package cli import ( - "context" - "github.com/spf13/cobra" "github.com/line/lbm-sdk/client" @@ -41,7 +39,7 @@ func NewQuerySubspaceParamsCmd() *cobra.Command { queryClient := proposal.NewQueryClient(clientCtx) params := proposal.QueryParamsRequest{Subspace: args[0], Key: args[1]} - res, err := queryClient.Params(context.Background(), ¶ms) + res, err := queryClient.Params(cmd.Context(), ¶ms) if err != nil { return err } diff --git a/x/params/client/cli/tx.go b/x/params/client/cli/tx.go index ca34eafaac..d48c0a0110 100644 --- a/x/params/client/cli/tx.go +++ b/x/params/client/cli/tx.go @@ -80,9 +80,6 @@ Where proposal.json contains: if err != nil { return err } - if err := msg.ValidateBasic(); err != nil { - return err - } return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) }, diff --git a/x/params/client/rest/grpc_query_test.go b/x/params/client/rest/grpc_query_test.go index 3eca45a1ae..7f93d6d26e 100644 --- a/x/params/client/rest/grpc_query_test.go +++ b/x/params/client/rest/grpc_query_test.go @@ -113,7 +113,7 @@ func (s *IntegrationTestSuite) TestQueryParamsGRPC() { resp, err := testutil.GetRequestWithHeaders(tc.url, tc.headers) s.Require().NoError(err) - err = val.ClientCtx.JSONMarshaler.UnmarshalJSON(resp, tc.respType) + err = val.ClientCtx.Codec.UnmarshalJSON(resp, tc.respType) if tc.expErr { s.Require().Error(err) diff --git a/x/params/client/testutil/cli_test.go b/x/params/client/testutil/cli_test.go new file mode 100644 index 0000000000..8ded31fefa --- /dev/null +++ b/x/params/client/testutil/cli_test.go @@ -0,0 +1,18 @@ +//go:build norace +// +build norace + +package testutil + +import ( + "testing" + + "github.com/line/lbm-sdk/testutil/network" + + "github.com/stretchr/testify/suite" +) + +func TestIntegrationTestSuite(t *testing.T) { + cfg := network.DefaultConfig() + cfg.NumValidators = 1 + suite.Run(t, NewIntegrationTestSuite(cfg)) +} diff --git a/x/params/client/cli/cli_test.go b/x/params/client/testutil/suite.go similarity index 86% rename from x/params/client/cli/cli_test.go rename to x/params/client/testutil/suite.go index 653df4421c..711f2c5761 100644 --- a/x/params/client/cli/cli_test.go +++ b/x/params/client/testutil/suite.go @@ -1,11 +1,8 @@ -// +build norace - -package cli_test +package testutil import ( "fmt" "strings" - "testing" ostcli "github.com/line/ostracon/libs/cli" "github.com/stretchr/testify/suite" @@ -22,14 +19,14 @@ type IntegrationTestSuite struct { network *network.Network } +func NewIntegrationTestSuite(cfg network.Config) *IntegrationTestSuite { + return &IntegrationTestSuite{cfg: cfg} +} + func (s *IntegrationTestSuite) SetupSuite() { s.T().Log("setting up integration test suite") - cfg := network.DefaultConfig() - cfg.NumValidators = 1 - - s.cfg = cfg - s.network = network.New(s.T(), cfg) + s.network = network.New(s.T(), s.cfg) _, err := s.network.WaitForHeight(1) s.Require().NoError(err) @@ -81,7 +78,3 @@ value: "100"`, }) } } - -func TestIntegrationTestSuite(t *testing.T) { - suite.Run(t, new(IntegrationTestSuite)) -} diff --git a/x/params/doc.go b/x/params/doc.go index 68ab4dee0e..2a79b0fd51 100644 --- a/x/params/doc.go +++ b/x/params/doc.go @@ -6,9 +6,8 @@ namespace for a parameter store, where keys are prefixed by pre-configured subspace names which modules provide. The Keeper has a permission to access all existing subspaces. -Subspace can be used by the individual keepers, who needs a private parameter store -that the other keeper cannot modify. Keeper can be used by the Governance keeper, -who need to modify any parameter in case of the proposal passes. +Subspace can be used by the individual keepers, which need a private parameter store +that the other keepers cannot modify. Basic Usage: @@ -23,11 +22,11 @@ Basic Usage: KeyParameter2 = "myparameter2" ) -2. Create a concrete parameter struct and define the validation functions: +2. Define parameters as proto message and define the validation functions: - type MyParams struct { - MyParam1 int64 `json:"my_param1" yaml:"my_param1"` - MyParam2 bool `json:"my_param2" yaml:"my_param2"` + message MyParams { + int64 my_param1 = 1; + bool my_param2 = 2; } func validateMyParam1(i interface{}) error { @@ -56,12 +55,12 @@ Basic Usage: func (p *MyParams) ParamSetPairs() params.ParamSetPairs { return params.ParamSetPairs{ - {KeyParameter1, &p.MyParam1, validateMyParam1}, - {KeyParameter2, &p.MyParam2, validateMyParam2}, + params.NewParamSetPair(KeyParameter1, &p.MyParam1, validateMyParam1), + params.NewParamSetPair(KeyParameter2, &p.MyParam2, validateMyParam2), } } - func paramKeyTable() params.KeyTable { + func ParamKeyTable() params.KeyTable { return params.NewKeyTable().RegisterParamSet(&MyParams{}) } @@ -70,7 +69,7 @@ Basic Usage: func NewKeeper(..., paramSpace params.Subspace, ...) Keeper { // set KeyTable if it has not already been set if !paramSpace.HasKeyTable() { - paramSpace = paramSpace.WithKeyTable(paramKeyTable()) + paramSpace = paramSpace.WithKeyTable(ParamKeyTable()) } return Keeper { diff --git a/x/params/keeper/common_test.go b/x/params/keeper/common_test.go index 412ea049a6..57b234bd83 100644 --- a/x/params/keeper/common_test.go +++ b/x/params/keeper/common_test.go @@ -1,10 +1,9 @@ package keeper_test import ( + "github.com/line/lbm-sdk/codec" "github.com/line/lbm-sdk/simapp" "github.com/line/lbm-sdk/testutil" - - "github.com/line/lbm-sdk/codec" sdk "github.com/line/lbm-sdk/types" paramskeeper "github.com/line/lbm-sdk/x/params/keeper" ) @@ -13,8 +12,9 @@ func testComponents() (*codec.LegacyAmino, sdk.Context, sdk.StoreKey, paramskeep marshaler := simapp.MakeTestEncodingConfig().Marshaler legacyAmino := createTestCodec() mkey := sdk.NewKVStoreKey("test") - ctx := testutil.DefaultContext(mkey) - keeper := paramskeeper.NewKeeper(marshaler, legacyAmino, mkey) + tkey := sdk.NewTransientStoreKey("transient_test") + ctx := testutil.DefaultContext(mkey, tkey) + keeper := paramskeeper.NewKeeper(marshaler, legacyAmino, mkey, tkey) return legacyAmino, ctx, mkey, keeper } diff --git a/x/params/keeper/grpc_query_test.go b/x/params/keeper/grpc_query_test.go index 5ed6a0246d..c8a437e3d2 100644 --- a/x/params/keeper/grpc_query_test.go +++ b/x/params/keeper/grpc_query_test.go @@ -12,7 +12,7 @@ func (suite *KeeperTestSuite) TestGRPCQueryParams() { var ( req *proposal.QueryParamsRequest expValue string - space *types.Subspace + space types.Subspace ) key := []byte("key") diff --git a/x/params/keeper/keeper.go b/x/params/keeper/keeper.go index 7ab35ca616..9056216ceb 100644 --- a/x/params/keeper/keeper.go +++ b/x/params/keeper/keeper.go @@ -11,19 +11,21 @@ import ( // Keeper of the global paramstore type Keeper struct { - cdc codec.BinaryMarshaler + cdc codec.BinaryCodec legacyAmino *codec.LegacyAmino key sdk.StoreKey - spaces map[string]*types.Subspace + tkey sdk.StoreKey + spaces map[string]types.Subspace } // NewKeeper constructs a params keeper -func NewKeeper(cdc codec.BinaryMarshaler, legacyAmino *codec.LegacyAmino, key sdk.StoreKey) Keeper { +func NewKeeper(cdc codec.BinaryCodec, legacyAmino *codec.LegacyAmino, key, tkey sdk.StoreKey) Keeper { return Keeper{ cdc: cdc, legacyAmino: legacyAmino, key: key, - spaces: make(map[string]*types.Subspace), + tkey: tkey, + spaces: make(map[string]types.Subspace), } } @@ -33,7 +35,7 @@ func (k Keeper) Logger(ctx sdk.Context) log.Logger { } // Allocate subspace used for keepers -func (k Keeper) Subspace(s string) *types.Subspace { +func (k Keeper) Subspace(s string) types.Subspace { _, ok := k.spaces[s] if ok { panic("subspace already occupied") @@ -43,17 +45,17 @@ func (k Keeper) Subspace(s string) *types.Subspace { panic("cannot use empty string for subspace") } - space := types.NewSubspace(k.cdc, k.legacyAmino, k.key, s) + space := types.NewSubspace(k.cdc, k.legacyAmino, k.key, k.tkey, s) k.spaces[s] = space return space } // Get existing substore from keeper -func (k Keeper) GetSubspace(s string) (*types.Subspace, bool) { +func (k Keeper) GetSubspace(s string) (types.Subspace, bool) { space, ok := k.spaces[s] if !ok { - return &types.Subspace{}, false + return types.Subspace{}, false } return space, ok } diff --git a/x/params/module.go b/x/params/module.go index 829e586176..e19d06a7d3 100644 --- a/x/params/module.go +++ b/x/params/module.go @@ -45,10 +45,10 @@ func (AppModuleBasic) RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) { // DefaultGenesis returns default genesis state as raw bytes for the params // module. -func (AppModuleBasic) DefaultGenesis(_ codec.JSONMarshaler) json.RawMessage { return nil } +func (AppModuleBasic) DefaultGenesis(_ codec.JSONCodec) json.RawMessage { return nil } // ValidateGenesis performs genesis state validation for the params module. -func (AppModuleBasic) ValidateGenesis(_ codec.JSONMarshaler, config client.TxEncodingConfig, _ json.RawMessage) error { +func (AppModuleBasic) ValidateGenesis(_ codec.JSONCodec, config client.TxEncodingConfig, _ json.RawMessage) error { return nil } @@ -72,8 +72,6 @@ func (am AppModuleBasic) RegisterInterfaces(registry codectypes.InterfaceRegistr proposal.RegisterInterfaces(registry) } -// ____________________________________________________________________________ - // AppModule implements an application module for the distribution module. type AppModule struct { AppModuleBasic @@ -92,7 +90,7 @@ func NewAppModule(k keeper.Keeper) AppModule { func (am AppModule) RegisterInvariants(_ sdk.InvariantRegistry) {} // InitGenesis performs a no-op. -func (am AppModule) InitGenesis(_ sdk.Context, _ codec.JSONMarshaler, _ json.RawMessage) []abci.ValidatorUpdate { +func (am AppModule) InitGenesis(_ sdk.Context, _ codec.JSONCodec, _ json.RawMessage) []abci.ValidatorUpdate { return []abci.ValidatorUpdate{} } @@ -140,7 +138,7 @@ func (am AppModule) WeightedOperations(_ module.SimulationState) []simtypes.Weig } // ExportGenesis performs a no-op. -func (am AppModule) ExportGenesis(_ sdk.Context, _ codec.JSONMarshaler) json.RawMessage { +func (am AppModule) ExportGenesis(_ sdk.Context, _ codec.JSONCodec) json.RawMessage { return nil } diff --git a/x/params/proposal_handler_test.go b/x/params/proposal_handler_test.go index 48aaa4b695..d1e7956cc9 100644 --- a/x/params/proposal_handler_test.go +++ b/x/params/proposal_handler_test.go @@ -3,130 +3,90 @@ package params_test import ( "testing" - "github.com/line/lbm-sdk/simapp" + "github.com/stretchr/testify/suite" - "github.com/line/ostracon/libs/log" ocproto "github.com/line/ostracon/proto/ostracon/types" - "github.com/line/tm-db/v2/memdb" - "github.com/stretchr/testify/require" - "github.com/line/lbm-sdk/codec" - "github.com/line/lbm-sdk/store" + "github.com/line/lbm-sdk/simapp" sdk "github.com/line/lbm-sdk/types" + govtypes "github.com/line/lbm-sdk/x/gov/types" "github.com/line/lbm-sdk/x/params" - "github.com/line/lbm-sdk/x/params/keeper" - "github.com/line/lbm-sdk/x/params/types" "github.com/line/lbm-sdk/x/params/types/proposal" + stakingtypes "github.com/line/lbm-sdk/x/staking/types" ) -func validateNoOp(_ interface{}) error { return nil } - -type testInput struct { - ctx sdk.Context - cdc *codec.LegacyAmino - keeper keeper.Keeper -} - -var ( - _ types.ParamSet = (*testParams)(nil) - - keyMaxValidators = "MaxValidators" - keySlashingRate = "SlashingRate" - testSubspace = "TestSubspace" -) +type HandlerTestSuite struct { + suite.Suite -type testParamsSlashingRate struct { - DoubleSign uint16 `json:"double_sign,omitempty" yaml:"double_sign,omitempty"` - Downtime uint16 `json:"downtime,omitempty" yaml:"downtime,omitempty"` + app *simapp.SimApp + ctx sdk.Context + govHandler govtypes.Handler } -type testParams struct { - MaxValidators uint16 `json:"max_validators" yaml:"max_validators"` // maximum number of validators (max uint16 = 65535) - SlashingRate testParamsSlashingRate `json:"slashing_rate" yaml:"slashing_rate"` +func (suite *HandlerTestSuite) SetupTest() { + suite.app = simapp.Setup(false) + suite.ctx = suite.app.BaseApp.NewContext(false, ocproto.Header{}) + suite.govHandler = params.NewParamChangeProposalHandler(suite.app.ParamsKeeper) } -func (tp *testParams) ParamSetPairs() types.ParamSetPairs { - return types.ParamSetPairs{ - types.NewParamSetPair([]byte(keyMaxValidators), &tp.MaxValidators, validateNoOp), - types.NewParamSetPair([]byte(keySlashingRate), &tp.SlashingRate, validateNoOp), - } +func TestHandlerTestSuite(t *testing.T) { + suite.Run(t, new(HandlerTestSuite)) } func testProposal(changes ...proposal.ParamChange) *proposal.ParameterChangeProposal { - return proposal.NewParameterChangeProposal( - "Test", - "description", - changes, - ) -} - -func newTestInput(t *testing.T) testInput { - cdc := codec.NewLegacyAmino() - proposal.RegisterLegacyAminoCodec(cdc) - - db := memdb.NewDB() - cms := store.NewCommitMultiStore(db) - - keyParams := sdk.NewKVStoreKey("params") - - cms.MountStoreWithDB(keyParams, sdk.StoreTypeIAVL, db) - - err := cms.LoadLatestVersion() - require.Nil(t, err) - - encCfg := simapp.MakeTestEncodingConfig() - keeper := keeper.NewKeeper(encCfg.Marshaler, encCfg.Amino, keyParams) - ctx := sdk.NewContext(cms, ocproto.Header{}, false, log.NewNopLogger()) - - return testInput{ctx, cdc, keeper} -} - -func TestProposalHandlerPassed(t *testing.T) { - input := newTestInput(t) - ss := input.keeper.Subspace(testSubspace).WithKeyTable( - types.NewKeyTable().RegisterParamSet(&testParams{}), - ) - - tp := testProposal(proposal.NewParamChange(testSubspace, keyMaxValidators, "1")) - hdlr := params.NewParamChangeProposalHandler(input.keeper) - require.NoError(t, hdlr(input.ctx, tp)) - - var param uint16 - ss.Get(input.ctx, []byte(keyMaxValidators), ¶m) - require.Equal(t, param, uint16(1)) + return proposal.NewParameterChangeProposal("title", "description", changes) } -func TestProposalHandlerFailed(t *testing.T) { - input := newTestInput(t) - ss := input.keeper.Subspace(testSubspace).WithKeyTable( - types.NewKeyTable().RegisterParamSet(&testParams{}), - ) - - tp := testProposal(proposal.NewParamChange(testSubspace, keyMaxValidators, "invalidType")) - hdlr := params.NewParamChangeProposalHandler(input.keeper) - require.Error(t, hdlr(input.ctx, tp)) - - require.False(t, ss.Has(input.ctx, []byte(keyMaxValidators))) -} - -func TestProposalHandlerUpdateOmitempty(t *testing.T) { - input := newTestInput(t) - ss := input.keeper.Subspace(testSubspace).WithKeyTable( - types.NewKeyTable().RegisterParamSet(&testParams{}), - ) - - hdlr := params.NewParamChangeProposalHandler(input.keeper) - var param testParamsSlashingRate - - tp := testProposal(proposal.NewParamChange(testSubspace, keySlashingRate, `{"downtime": 7}`)) - require.NoError(t, hdlr(input.ctx, tp)) - - ss.Get(input.ctx, []byte(keySlashingRate), ¶m) - require.Equal(t, testParamsSlashingRate{0, 7}, param) - - tp = testProposal(proposal.NewParamChange(testSubspace, keySlashingRate, `{"double_sign": 10}`)) - require.NoError(t, hdlr(input.ctx, tp)) +func (suite *HandlerTestSuite) TestProposalHandler() { + testCases := []struct { + name string + proposal *proposal.ParameterChangeProposal + onHandle func() + expErr bool + }{ + { + "all fields", + testProposal(proposal.NewParamChange(stakingtypes.ModuleName, string(stakingtypes.KeyMaxValidators), "1")), + func() { + maxVals := suite.app.StakingKeeper.MaxValidators(suite.ctx) + suite.Require().Equal(uint32(1), maxVals) + }, + false, + }, + { + "invalid type", + testProposal(proposal.NewParamChange(stakingtypes.ModuleName, string(stakingtypes.KeyMaxValidators), "-")), + func() {}, + true, + }, + { + "omit empty fields", + testProposal(proposal.ParamChange{ + Subspace: govtypes.ModuleName, + Key: string(govtypes.ParamStoreKeyDepositParams), + Value: `{"min_deposit": [{"denom": "uatom","amount": "64000000"}]}`, + }), + func() { + depositParams := suite.app.GovKeeper.GetDepositParams(suite.ctx) + suite.Require().Equal(govtypes.DepositParams{ + MinDeposit: sdk.NewCoins(sdk.NewCoin("uatom", sdk.NewInt(64000000))), + MaxDepositPeriod: govtypes.DefaultPeriod, + }, depositParams) + }, + false, + }, + } - ss.Get(input.ctx, []byte(keySlashingRate), ¶m) - require.Equal(t, testParamsSlashingRate{10, 7}, param) + for _, tc := range testCases { + tc := tc + suite.Run(tc.name, func() { + err := suite.govHandler(suite.ctx, tc.proposal) + if tc.expErr { + suite.Require().Error(err) + } else { + suite.Require().NoError(err) + tc.onHandle() + } + }) + } } diff --git a/x/params/simulation/operations.go b/x/params/simulation/operations.go index 563bfbb0e1..99c7abb254 100644 --- a/x/params/simulation/operations.go +++ b/x/params/simulation/operations.go @@ -1,6 +1,7 @@ package simulation import ( + "fmt" "math/rand" sdk "github.com/line/lbm-sdk/types" @@ -8,44 +9,45 @@ import ( "github.com/line/lbm-sdk/x/params/types/proposal" ) +func min(a int, b int) int { + if a <= b { + return a + } + return b +} + // SimulateParamChangeProposalContent returns random parameter change content. // It will generate a ParameterChangeProposal object with anywhere between 1 and // the total amount of defined parameters changes, all of which have random valid values. func SimulateParamChangeProposalContent(paramChangePool []simulation.ParamChange) simulation.ContentSimulatorFn { - return func(r *rand.Rand, _ sdk.Context, _ []simulation.Account) simulation.Content { - - lenParamChange := len(paramChangePool) - if lenParamChange == 0 { - panic("param changes array is empty") - } + numProposals := 0 + // Bound the maximum number of simultaneous parameter changes + maxSimultaneousParamChanges := min(len(paramChangePool), 1000) + if maxSimultaneousParamChanges == 0 { + panic("param changes array is empty") + } - numChanges := simulation.RandIntBetween(r, 1, lenParamChange) + return func(r *rand.Rand, _ sdk.Context, _ []simulation.Account) simulation.Content { + numChanges := simulation.RandIntBetween(r, 1, maxSimultaneousParamChanges) paramChanges := make([]proposal.ParamChange, numChanges) - // map from key to empty struct; used only for look-up of the keys of the - // parameters that are already in the random set of changes. - paramChangesKeys := make(map[string]struct{}) + // perm here takes at most len(paramChangePool) calls to random + paramChoices := r.Perm(len(paramChangePool)) for i := 0; i < numChanges; i++ { - spc := paramChangePool[r.Intn(len(paramChangePool))] - - // do not include duplicate parameter changes for a given subspace/key - _, ok := paramChangesKeys[spc.ComposedKey()] - for ok { - spc = paramChangePool[r.Intn(len(paramChangePool))] - _, ok = paramChangesKeys[spc.ComposedKey()] - } - - // add a new distinct parameter to the set of changes and register the key - // to avoid further duplicates - paramChangesKeys[spc.ComposedKey()] = struct{}{} + spc := paramChangePool[paramChoices[i]] + // add a new distinct parameter to the set of changes paramChanges[i] = proposal.NewParamChange(spc.Subspace(), spc.Key(), spc.SimValue()(r)) } + title := fmt.Sprintf("title from SimulateParamChangeProposalContent-%d", numProposals) + desc := fmt.Sprintf("desc from SimulateParamChangeProposalContent-%d. Random short desc: %s", + numProposals, simulation.RandStringOfLength(r, 20)) + numProposals++ return proposal.NewParameterChangeProposal( - simulation.RandStringOfLength(r, 140), // title - simulation.RandStringOfLength(r, 5000), // description - paramChanges, // set of changes + title, // title + desc, // description + paramChanges, // set of changes ) } } diff --git a/x/params/simulation/operations_test.go b/x/params/simulation/operations_test.go index 9d787e837f..8dc76846b2 100644 --- a/x/params/simulation/operations_test.go +++ b/x/params/simulation/operations_test.go @@ -51,8 +51,8 @@ func TestSimulateParamChangeProposalContent(t *testing.T) { op := simulation.SimulateParamChangeProposalContent(paramChangePool) content := op(r, ctx, accounts) - require.Equal(t, "BrTEdFUqHtDtDBPzlahrrStzkUNxImpptHBIFDQfnxaTiOBJUgNzvqHbVcVJYlIFWFlzFqqRTTyFzDUMntPzyRamUFqeJAEaSHIuUHZoTWDjWXsYxYvwXwXZEsjRQKgKMselyUqWXMbHzRNDHnMzhWSirUgVggjiBxtWDfhzPDgrorEoNmDEiDdBldYegphCBTYWrmFFXNjxhtygsGBFHTejaKjMsqNdikEzDalEyWRHfJhKqifCKsedVuuJbQMbmRVuIPDluAWGpngjgBjOxuRFwSadayHNIhVVmNWBbfaTOldclxTTLUMvaBnLfwjHTtsKetEIvgrxLijhKJNablmvqpWIWsmhWQAYNLycREypoASHnyKWrxpoNLBJuyCGysZJgXbQAAmSIbGxMFXuwMVGZgBiZWfPWorAfjBeekCFvljHAtVZaTOsRxbPIioNxLTnWUTzGTvaNhplQQPmMADRRDuUIsiBpnGqPheKmLnopieVseFdTSAvOCacxaqFWFuXzsrVZzlGfeRpClwKuGEBujaPrzSLjVIOMvLlWxuznEOXlxbZroBRVEvEfBBAHOECribZNrYiFnzQqQmBnLksmFNAadusWAGltuqYNntgOlgOGwSdDjWdLboWyAWIcCfmpGJTfbljKPriLehwObuszICkaXNUkmeddeeRulbZBXJVLgteiKIfofGdNBregwUPlINQECatDSNXSIuefyMxxoKfcmjHEwbVtFiXtEnLJkLHUghmzFiymrgBChucZgOQUpGGVQEpRtIQjIBxYhtZPgUORdxXNWUMErWrUeriqYJPcgIDgLMWAyuuQnsHncCtjvHmvFbzYErxeunQllYDUVlXaRBveRUKeXwEGJFTSAqZtaBSDGDtzlADCnGjuTmYMJlapRsWfugmjwKEuoXJVpZvlcHeFvVvRRktRVGwzLfKezPEMABZtbLExQIjynSoahmkmoTHefdzFoBHMcQHFkKVHhpNtudPqJrYuQswzFuFHbSmpNltFnYJpvMrAYHFrNouZaanEUGHvbHIUUFTCtZrcpRHwgjblxlDNJWzHdBNpAXKJPHWQdrGYcAHSctgVlqwqHoLfHsXUdStwfefwzqLuKEhmMyYLdbZrcPgYqjNHxPexsruwEGStAneKbWkQDDIlCWBLSiAASNhZqNFlPtfqPJoxKsgMdzjWqLWdqKQuJqWPMvwPQWZUtVMOTMYKJbfdlZsjdsomuScvDmbDkgRualsxDvRJuCAmPOXitIbcyWsKGSdrEunFAOdmXnsuyFVgJqEjbklvmwrUlsxjRSfKZxGcpayDdgoFcnVSutxjRgOSFzPwidAjubMncNweqpbxhXGchpZUxuFDOtpnhNUycJICRYqsPhPSCjPTWZFLkstHWJxvdPEAyEIxXgLwbNOjrgzmaujiBABBIXvcXpLrbcEWNNQsbjvgJFgJkflpRohHUutvnaUqoopuKjTDaemDeSdqbnOzcfJpcTuAQtZoiLZOoAIlboFDAeGmSNwkvObPRvRWQgWkGkxwtPauYgdkmypLjbqhlHJIQTntgWjXwZdOyYEdQRRLfMSdnxqppqUofqLbLQDUjwKVKfZJUJQPsWIPwIVaSTrmKskoAhvmZyJgeRpkaTfGgrJzAigcxtfshmiDCFkuiluqtMOkidknnTBtumyJYlIsWLnCQclqdVmikUoMOPdPWwYbJxXyqUVicNxFxyqJTenNblyyKSdlCbiXxUiYUiMwXZASYfvMDPFgxniSjWaZTjHkqlJvtBsXqwPpyVxnJVGFWhfSxgOcduoxkiopJvFjMmFabrGYeVtTXLhxVUEiGwYUvndjFGzDVntUvibiyZhfMQdMhgsiuysLMiePBNXifRLMsSmXPkwlPloUbJveCvUlaalhZHuvdkCnkSHbMbmOnrfEGPwQiACiPlnihiaOdbjPqPiTXaHDoJXjSlZmltGqNHHNrcKdlFSCdmVOuvDcBLdSklyGJmcLTbSFtALdGlPkqqecJrpLCXNPWefoTJNgEJlyMEPneVaxxduAAEqQpHWZodWyRkDAxzyMnFMcjSVqeRXLqsNyNtQBbuRvunZflWSbbvXXdkyLikYqutQhLPONXbvhcQZJPSWnOulqQaXmbfFxAkqfYeseSHOQidHwbcsOaMnSrrmGjjRmEMQNuknupMxJiIeVjmgZvbmjPIQTEhQFULQLBMPrxcFPvBinaOPYWGvYGRKxLZdwamfRQQFngcdSlvwjfaPbURasIsGJVHtcEAxnIIrhSriiXLOlbEBLXFElXJFGxHJczRBIxAuPKtBisjKBwfzZFagdNmjdwIRvwzLkFKWRTDPxJCmpzHUcrPiiXXHnOIlqNVoGSXZewdnCRhuxeYGPVTfrNTQNOxZmxInOazUYNTNDgzsxlgiVEHPKMfbesvPHUqpNkUqbzeuzfdrsuLDpKHMUbBMKczKKWOdYoIXoPYtEjfOnlQLoGnbQUCuERdEFaptwnsHzTJDsuZkKtzMpFaZobynZdzNydEeJJHDYaQcwUxcqvwfWwNUsCiLvkZQiSfzAHftYgAmVsXgtmcYgTqJIawstRYJrZdSxlfRiqTufgEQVambeZZmaAyRQbcmdjVUZZCgqDrSeltJGXPMgZnGDZqISrGDOClxXCxMjmKqEPwKHoOfOeyGmqWqihqjINXLqnyTesZePQRqaWDQNqpLgNrAUKulklmckTijUltQKuWQDwpLmDyxLppPVMwsmBIpOwQttYFMjgJQZLYFPmxWFLIeZihkRNnkzoypBICIxgEuYsVWGIGRbbxqVasYnstWomJnHwmtOhAFSpttRYYzBmyEtZXiCthvKvWszTXDbiJbGXMcrYpKAgvUVFtdKUfvdMfhAryctklUCEdjetjuGNfJjajZtvzdYaqInKtFPPLYmRaXPdQzxdSQfmZDEVHlHGEGNSPRFJuIfKLLfUmnHxHnRjmzQPNlqrXgifUdzAGKVabYqvcDeYoTYgPsBUqehrBhmQUgTvDnsdpuhUoxskDdppTsYMcnDIPSwKIqhXDCIxOuXrywahvVavvHkPuaenjLmEbMgrkrQLHEAwrhHkPRNvonNQKqprqOFVZKAtpRSpvQUxMoXCMZLSSbnLEFsjVfANdQNQVwTmGxqVjVqRuxREAhuaDrFgEZpYKhwWPEKBevBfsOIcaZKyykQafzmGPLRAKDtTcJxJVgiiuUkmyMYuDUNEUhBEdoBLJnamtLmMJQgmLiUELIhLpiEvpOXOvXCPUeldLFqkKOwfacqIaRcnnZvERKRMCKUkMABbDHytQqQblrvoxOZkwzosQfDKGtIdfcXRJNqlBNwOCWoQBcEWyqrMlYZIAXYJmLfnjoJepgSFvrgajaBAIksoyeHqgqbGvpAstMIGmIhRYGGNPRIfOQKsGoKgxtsidhTaAePRCBFqZgPDWCIkqOJezGVkjfYUCZTlInbxBXwUAVRsxHTQtJFnnpmMvXDYCVlEmnZBKhmmxQOIQzxFWpJQkQoSAYzTEiDWEOsVLNrbfzeHFRyeYATakQQWmFDLPbVMCJcWjFGJjfqCoVzlbNNEsqxdSmNPjTjHYOkuEMFLkXYGaoJlraLqayMeCsTjWNRDPBywBJLAPVkGQqTwApVVwYAetlwSbzsdHWsTwSIcctkyKDuRWYDQikRqsKTMJchrliONJeaZIzwPQrNbTwxsGdwuduvibtYndRwpdsvyCktRHFalvUuEKMqXbItfGcNGWsGzubdPMYayOUOINjpcFBeESdwpdlTYmrPsLsVDhpTzoMegKrytNVZkfJRPuDCUXxSlSthOohmsuxmIZUedzxKmowKOdXTMcEtdpHaPWgIsIjrViKrQOCONlSuazmLuCUjLltOGXeNgJKedTVrrVCpWYWHyVrdXpKgNaMJVjbXxnVMSChdWKuZdqpisvrkBJPoURDYxWOtpjzZoOpWzyUuYNhCzRoHsMjmmWDcXzQiHIyjwdhPNwiPqFxeUfMVFQGImhykFgMIlQEoZCaRoqSBXTSWAeDumdbsOGtATwEdZlLfoBKiTvodQBGOEcuATWXfiinSjPmJKcWgQrTVYVrwlyMWhxqNbCMpIQNoSMGTiWfPTCezUjYcdWppnsYJihLQCqbNLRGgqrwHuIvsazapTpoPZIyZyeeSueJuTIhpHMEJfJpScshJubJGfkusuVBgfTWQoywSSliQQSfbvaHKiLnyjdSbpMkdBgXepoSsHnCQaYuHQqZsoEOmJCiuQUpJkmfyfbIShzlZpHFmLCsbknEAkKXKfRTRnuwdBeuOGgFbJLbDksHVapaRayWzwoYBEpmrlAxrUxYMUekKbpjPNfjUCjhbdMAnJmYQVZBQZkFVweHDAlaqJjRqoQPoOMLhyvYCzqEuQsAFoxWrzRnTVjStPadhsESlERnKhpEPsfDxNvxqcOyIulaCkmPdambLHvGhTZzysvqFauEgkFRItPfvisehFmoBhQqmkfbHVsgfHXDPJVyhwPllQpuYLRYvGodxKjkarnSNgsXoKEMlaSKxKdcVgvOkuLcfLFfdtXGTclqfPOfeoVLbqcjcXCUEBgAGplrkgsmIEhWRZLlGPGCwKWRaCKMkBHTAcypUrYjWwCLtOPVygMwMANGoQwFnCqFrUGMCRZUGJKTZIGPyldsifauoMnJPLTcDHmilcmahlqOELaAUYDBuzsVywnDQfwRLGIWozYaOAilMBcObErwgTDNGWnwQMUgFFSKtPDMEoEQCTKVREqrXZSGLqwTMcxHfWotDllNkIJPMbXzjDVjPOOjCFuIvTyhXKLyhUScOXvYthRXpPfKwMhptXaxIxgqBoUqzrWbaoLTVpQoottZyPFfNOoMioXHRuFwMRYUiKvcWPkrayyTLOCFJlAyslDameIuqVAuxErqFPEWIScKpBORIuZqoXlZuTvAjEdlEWDODFRregDTqGNoFBIHxvimmIZwLfFyKUfEWAnNBdtdzDmT", content.GetDescription()) - require.Equal(t, "tpHRGdIbuucfTjOygZsTxPjfweXhSUkMhPjMaxKlMIJMOXcnQfyzeOcbWwNbeHVIkPZBSpYuLyYggwexjxusrBqDOTtGTOWeLrQKjLxzIivHSlcxgdXhhuTSkuxKGLwQvuyNhYFmBZHe", content.GetTitle()) + require.Equal(t, "desc from SimulateParamChangeProposalContent-0. Random short desc: IivHSlcxgdXhhuTSkuxK", content.GetDescription()) + require.Equal(t, "title from SimulateParamChangeProposalContent-0", content.GetTitle()) require.Equal(t, "params", content.ProposalRoute()) require.Equal(t, "ParameterChange", content.ProposalType()) @@ -60,6 +60,6 @@ func TestSimulateParamChangeProposalContent(t *testing.T) { require.True(t, ok) require.Equal(t, "test-Key2", pcp.Changes[0].GetKey()) - require.Equal(t, "test-value 2610 ", pcp.Changes[0].GetValue()) + require.Equal(t, "test-value 2791 ", pcp.Changes[0].GetValue()) require.Equal(t, "test-Subspace2", pcp.Changes[0].GetSubspace()) } diff --git a/x/params/simulation/proposals_test.go b/x/params/simulation/proposals_test.go index 479229e177..0f70de3ad3 100644 --- a/x/params/simulation/proposals_test.go +++ b/x/params/simulation/proposals_test.go @@ -36,8 +36,8 @@ func TestProposalContents(t *testing.T) { content := w0.ContentSimulatorFn()(r, ctx, accounts) - require.Equal(t, "BrTEdFUqHtDtDBPzlahrrStzkUNxImpptHBIFDQfnxaTiOBJUgNzvqHbVcVJYlIFWFlzFqqRTTyFzDUMntPzyRamUFqeJAEaSHIuUHZoTWDjWXsYxYvwXwXZEsjRQKgKMselyUqWXMbHzRNDHnMzhWSirUgVggjiBxtWDfhzPDgrorEoNmDEiDdBldYegphCBTYWrmFFXNjxhtygsGBFHTejaKjMsqNdikEzDalEyWRHfJhKqifCKsedVuuJbQMbmRVuIPDluAWGpngjgBjOxuRFwSadayHNIhVVmNWBbfaTOldclxTTLUMvaBnLfwjHTtsKetEIvgrxLijhKJNablmvqpWIWsmhWQAYNLycREypoASHnyKWrxpoNLBJuyCGysZJgXbQAAmSIbGxMFXuwMVGZgBiZWfPWorAfjBeekCFvljHAtVZaTOsRxbPIioNxLTnWUTzGTvaNhplQQPmMADRRDuUIsiBpnGqPheKmLnopieVseFdTSAvOCacxaqFWFuXzsrVZzlGfeRpClwKuGEBujaPrzSLjVIOMvLlWxuznEOXlxbZroBRVEvEfBBAHOECribZNrYiFnzQqQmBnLksmFNAadusWAGltuqYNntgOlgOGwSdDjWdLboWyAWIcCfmpGJTfbljKPriLehwObuszICkaXNUkmeddeeRulbZBXJVLgteiKIfofGdNBregwUPlINQECatDSNXSIuefyMxxoKfcmjHEwbVtFiXtEnLJkLHUghmzFiymrgBChucZgOQUpGGVQEpRtIQjIBxYhtZPgUORdxXNWUMErWrUeriqYJPcgIDgLMWAyuuQnsHncCtjvHmvFbzYErxeunQllYDUVlXaRBveRUKeXwEGJFTSAqZtaBSDGDtzlADCnGjuTmYMJlapRsWfugmjwKEuoXJVpZvlcHeFvVvRRktRVGwzLfKezPEMABZtbLExQIjynSoahmkmoTHefdzFoBHMcQHFkKVHhpNtudPqJrYuQswzFuFHbSmpNltFnYJpvMrAYHFrNouZaanEUGHvbHIUUFTCtZrcpRHwgjblxlDNJWzHdBNpAXKJPHWQdrGYcAHSctgVlqwqHoLfHsXUdStwfefwzqLuKEhmMyYLdbZrcPgYqjNHxPexsruwEGStAneKbWkQDDIlCWBLSiAASNhZqNFlPtfqPJoxKsgMdzjWqLWdqKQuJqWPMvwPQWZUtVMOTMYKJbfdlZsjdsomuScvDmbDkgRualsxDvRJuCAmPOXitIbcyWsKGSdrEunFAOdmXnsuyFVgJqEjbklvmwrUlsxjRSfKZxGcpayDdgoFcnVSutxjRgOSFzPwidAjubMncNweqpbxhXGchpZUxuFDOtpnhNUycJICRYqsPhPSCjPTWZFLkstHWJxvdPEAyEIxXgLwbNOjrgzmaujiBABBIXvcXpLrbcEWNNQsbjvgJFgJkflpRohHUutvnaUqoopuKjTDaemDeSdqbnOzcfJpcTuAQtZoiLZOoAIlboFDAeGmSNwkvObPRvRWQgWkGkxwtPauYgdkmypLjbqhlHJIQTntgWjXwZdOyYEdQRRLfMSdnxqppqUofqLbLQDUjwKVKfZJUJQPsWIPwIVaSTrmKskoAhvmZyJgeRpkaTfGgrJzAigcxtfshmiDCFkuiluqtMOkidknnTBtumyJYlIsWLnCQclqdVmikUoMOPdPWwYbJxXyqUVicNxFxyqJTenNblyyKSdlCbiXxUiYUiMwXZASYfvMDPFgxniSjWaZTjHkqlJvtBsXqwPpyVxnJVGFWhfSxgOcduoxkiopJvFjMmFabrGYeVtTXLhxVUEiGwYUvndjFGzDVntUvibiyZhfMQdMhgsiuysLMiePBNXifRLMsSmXPkwlPloUbJveCvUlaalhZHuvdkCnkSHbMbmOnrfEGPwQiACiPlnihiaOdbjPqPiTXaHDoJXjSlZmltGqNHHNrcKdlFSCdmVOuvDcBLdSklyGJmcLTbSFtALdGlPkqqecJrpLCXNPWefoTJNgEJlyMEPneVaxxduAAEqQpHWZodWyRkDAxzyMnFMcjSVqeRXLqsNyNtQBbuRvunZflWSbbvXXdkyLikYqutQhLPONXbvhcQZJPSWnOulqQaXmbfFxAkqfYeseSHOQidHwbcsOaMnSrrmGjjRmEMQNuknupMxJiIeVjmgZvbmjPIQTEhQFULQLBMPrxcFPvBinaOPYWGvYGRKxLZdwamfRQQFngcdSlvwjfaPbURasIsGJVHtcEAxnIIrhSriiXLOlbEBLXFElXJFGxHJczRBIxAuPKtBisjKBwfzZFagdNmjdwIRvwzLkFKWRTDPxJCmpzHUcrPiiXXHnOIlqNVoGSXZewdnCRhuxeYGPVTfrNTQNOxZmxInOazUYNTNDgzsxlgiVEHPKMfbesvPHUqpNkUqbzeuzfdrsuLDpKHMUbBMKczKKWOdYoIXoPYtEjfOnlQLoGnbQUCuERdEFaptwnsHzTJDsuZkKtzMpFaZobynZdzNydEeJJHDYaQcwUxcqvwfWwNUsCiLvkZQiSfzAHftYgAmVsXgtmcYgTqJIawstRYJrZdSxlfRiqTufgEQVambeZZmaAyRQbcmdjVUZZCgqDrSeltJGXPMgZnGDZqISrGDOClxXCxMjmKqEPwKHoOfOeyGmqWqihqjINXLqnyTesZePQRqaWDQNqpLgNrAUKulklmckTijUltQKuWQDwpLmDyxLppPVMwsmBIpOwQttYFMjgJQZLYFPmxWFLIeZihkRNnkzoypBICIxgEuYsVWGIGRbbxqVasYnstWomJnHwmtOhAFSpttRYYzBmyEtZXiCthvKvWszTXDbiJbGXMcrYpKAgvUVFtdKUfvdMfhAryctklUCEdjetjuGNfJjajZtvzdYaqInKtFPPLYmRaXPdQzxdSQfmZDEVHlHGEGNSPRFJuIfKLLfUmnHxHnRjmzQPNlqrXgifUdzAGKVabYqvcDeYoTYgPsBUqehrBhmQUgTvDnsdpuhUoxskDdppTsYMcnDIPSwKIqhXDCIxOuXrywahvVavvHkPuaenjLmEbMgrkrQLHEAwrhHkPRNvonNQKqprqOFVZKAtpRSpvQUxMoXCMZLSSbnLEFsjVfANdQNQVwTmGxqVjVqRuxREAhuaDrFgEZpYKhwWPEKBevBfsOIcaZKyykQafzmGPLRAKDtTcJxJVgiiuUkmyMYuDUNEUhBEdoBLJnamtLmMJQgmLiUELIhLpiEvpOXOvXCPUeldLFqkKOwfacqIaRcnnZvERKRMCKUkMABbDHytQqQblrvoxOZkwzosQfDKGtIdfcXRJNqlBNwOCWoQBcEWyqrMlYZIAXYJmLfnjoJepgSFvrgajaBAIksoyeHqgqbGvpAstMIGmIhRYGGNPRIfOQKsGoKgxtsidhTaAePRCBFqZgPDWCIkqOJezGVkjfYUCZTlInbxBXwUAVRsxHTQtJFnnpmMvXDYCVlEmnZBKhmmxQOIQzxFWpJQkQoSAYzTEiDWEOsVLNrbfzeHFRyeYATakQQWmFDLPbVMCJcWjFGJjfqCoVzlbNNEsqxdSmNPjTjHYOkuEMFLkXYGaoJlraLqayMeCsTjWNRDPBywBJLAPVkGQqTwApVVwYAetlwSbzsdHWsTwSIcctkyKDuRWYDQikRqsKTMJchrliONJeaZIzwPQrNbTwxsGdwuduvibtYndRwpdsvyCktRHFalvUuEKMqXbItfGcNGWsGzubdPMYayOUOINjpcFBeESdwpdlTYmrPsLsVDhpTzoMegKrytNVZkfJRPuDCUXxSlSthOohmsuxmIZUedzxKmowKOdXTMcEtdpHaPWgIsIjrViKrQOCONlSuazmLuCUjLltOGXeNgJKedTVrrVCpWYWHyVrdXpKgNaMJVjbXxnVMSChdWKuZdqpisvrkBJPoURDYxWOtpjzZoOpWzyUuYNhCzRoHsMjmmWDcXzQiHIyjwdhPNwiPqFxeUfMVFQGImhykFgMIlQEoZCaRoqSBXTSWAeDumdbsOGtATwEdZlLfoBKiTvodQBGOEcuATWXfiinSjPmJKcWgQrTVYVrwlyMWhxqNbCMpIQNoSMGTiWfPTCezUjYcdWppnsYJihLQCqbNLRGgqrwHuIvsazapTpoPZIyZyeeSueJuTIhpHMEJfJpScshJubJGfkusuVBgfTWQoywSSliQQSfbvaHKiLnyjdSbpMkdBgXepoSsHnCQaYuHQqZsoEOmJCiuQUpJkmfyfbIShzlZpHFmLCsbknEAkKXKfRTRnuwdBeuOGgFbJLbDksHVapaRayWzwoYBEpmrlAxrUxYMUekKbpjPNfjUCjhbdMAnJmYQVZBQZkFVweHDAlaqJjRqoQPoOMLhyvYCzqEuQsAFoxWrzRnTVjStPadhsESlERnKhpEPsfDxNvxqcOyIulaCkmPdambLHvGhTZzysvqFauEgkFRItPfvisehFmoBhQqmkfbHVsgfHXDPJVyhwPllQpuYLRYvGodxKjkarnSNgsXoKEMlaSKxKdcVgvOkuLcfLFfdtXGTclqfPOfeoVLbqcjcXCUEBgAGplrkgsmIEhWRZLlGPGCwKWRaCKMkBHTAcypUrYjWwCLtOPVygMwMANGoQwFnCqFrUGMCRZUGJKTZIGPyldsifauoMnJPLTcDHmilcmahlqOELaAUYDBuzsVywnDQfwRLGIWozYaOAilMBcObErwgTDNGWnwQMUgFFSKtPDMEoEQCTKVREqrXZSGLqwTMcxHfWotDllNkIJPMbXzjDVjPOOjCFuIvTyhXKLyhUScOXvYthRXpPfKwMhptXaxIxgqBoUqzrWbaoLTVpQoottZyPFfNOoMioXHRuFwMRYUiKvcWPkrayyTLOCFJlAyslDameIuqVAuxErqFPEWIScKpBORIuZqoXlZuTvAjEdlEWDODFRregDTqGNoFBIHxvimmIZwLfFyKUfEWAnNBdtdzDmT", content.GetDescription()) - require.Equal(t, "tpHRGdIbuucfTjOygZsTxPjfweXhSUkMhPjMaxKlMIJMOXcnQfyzeOcbWwNbeHVIkPZBSpYuLyYggwexjxusrBqDOTtGTOWeLrQKjLxzIivHSlcxgdXhhuTSkuxKGLwQvuyNhYFmBZHe", content.GetTitle()) + require.Equal(t, "desc from SimulateParamChangeProposalContent-0. Random short desc: IivHSlcxgdXhhuTSkuxK", content.GetDescription()) + require.Equal(t, "title from SimulateParamChangeProposalContent-0", content.GetTitle()) require.Equal(t, "params", content.ProposalRoute()) require.Equal(t, "ParameterChange", content.ProposalType()) @@ -46,6 +46,6 @@ func TestProposalContents(t *testing.T) { require.Len(t, pcp.Changes, 1) require.Equal(t, "test-Key2", pcp.Changes[0].GetKey()) - require.Equal(t, "test-value 2610 ", pcp.Changes[0].GetValue()) + require.Equal(t, "test-value 2791 ", pcp.Changes[0].GetValue()) require.Equal(t, "test-Subspace2", pcp.Changes[0].GetSubspace()) } diff --git a/x/params/spec/01_keeper.md b/x/params/spec/01_keeper.md index 8cf7e2a53f..fa97ec5b37 100644 --- a/x/params/spec/01_keeper.md +++ b/x/params/spec/01_keeper.md @@ -4,24 +4,16 @@ order: 1 # Keeper -In the app initialization stage, `Keeper.Subspace(Paramspace)` is passed to the -user modules, and the subspaces are stored in `Keeper.spaces`. Later it can be -retrieved with `Keeper.GetSubspace`, so the keepers holding `Keeper` can access -to any subspace. For example, Gov module can take `Keeper` as its argument and -modify parameter of any subspace when a `ParameterChangeProposal` is accepted. +In the app initialization stage, [subspaces](02_subspace.md) can be allocated for other modules' keeper using `Keeper.Subspace` and are stored in `Keeper.spaces`. Then, those modules can have a reference to their specific parameter store through `Keeper.GetSubspace`. Example: ```go -type MasterKeeper struct { - pk params.Keeper +type ExampleKeeper struct { + paramSpace paramtypes.Subspace } -func (k MasterKeeper) SetParam(ctx sdk.Context, space string, key string, param interface{}) { - space, ok := k.ps.GetSubspace(space) - if !ok { - return - } - space.Set(ctx, key, param) +func (k ExampleKeeper) SetParams(ctx sdk.Context, params types.Params) { + k.paramSpace.SetParamSet(ctx, ¶ms) } ``` diff --git a/x/params/spec/02_subspace.md b/x/params/spec/02_subspace.md index 5e36eaf498..2eaa391a25 100644 --- a/x/params/spec/02_subspace.md +++ b/x/params/spec/02_subspace.md @@ -4,13 +4,13 @@ order: 2 # Subspace -`Subspace` is a prefixed subspace of the parameter store. Each module who use the -parameter store will take a `Subspace`, not the `Keeper`, to isolate permission to access. +`Subspace` is a prefixed subspace of the parameter store. Each module which uses the +parameter store will take a `Subspace` to isolate permission to access. ## Key -Parameter keys are human readable alphanumeric strings. A parameter for the key -`"ExampleParameter"` is stored under `[]byte("SubspaceName" + "/" + "ExampleParameter")`, +Parameter keys are human readable alphanumeric strings. A parameter for the key +`"ExampleParameter"` is stored under `[]byte("SubspaceName" + "/" + "ExampleParameter")`, where `"SubspaceName"` is the name of the subspace. Subkeys are secondary parameter keys those are used along with a primary parameter key. @@ -18,23 +18,21 @@ Subkeys can be used for grouping or dynamic parameter key generation during runt ## KeyTable -All of the parameter keys that will be used should be registered at the compile +All of the parameter keys that will be used should be registered at the compile time. `KeyTable` is essentially a `map[string]attribute`, where the `string` is a parameter key. -Currently, `attribute` only consists of `reflect.Type`, which indicates the parameter -type. It is needed even if the state machine has no error, because the paraeter -can be modified externally, for example via the governance. +Currently, `attribute` consists of a `reflect.Type`, which indicates the parameter +type to check that provided key and value are compatible and registered, as well as a function `ValueValidatorFn` to validate values. -Only primary keys have to be registered on the `KeyTable`. Subkeys inherit the +Only primary keys have to be registered on the `KeyTable`. Subkeys inherit the attribute of the primary key. ## ParamSet -Modules often define a struct of parameters. Instead of calling methods with -each of those parameters, when the struct implements `ParamSet`, it can be used -with the following methods: +Modules often define parameters as a proto message. The generated struct can implement +`ParamSet` interface to be used with the following methods: * `KeyTable.RegisterParamSet()`: registers all parameters in the struct * `Subspace.{Get, Set}ParamSet()`: Get to & Set from the struct -The implementor should be a pointer in order to use `GetParamSet()` +The implementor should be a pointer in order to use `GetParamSet()`. diff --git a/x/params/spec/README.md b/x/params/spec/README.md index c84ad6e5bc..4a136cce57 100644 --- a/x/params/spec/README.md +++ b/x/params/spec/README.md @@ -15,9 +15,8 @@ There are two main types, Keeper and Subspace. Subspace is an isolated namespace paramstore, where keys are prefixed by preconfigured spacename. Keeper has a permission to access all existing spaces. -Subspace can be used by the individual keepers, who needs a private parameter store -that the other keeper cannot modify. Keeper can be used by the Governance keeper, -who need to modify any parameter in case of the proposal passes. +Subspace can be used by the individual keepers, which need a private parameter store +that the other keepers cannot modify. The params Keeper can be used to add a route to `x/gov` router in order to modify any parameter in case a proposal passes. The following contents explains how to use params module for master and user modules. diff --git a/x/params/types/common_test.go b/x/params/types/common_test.go index 229754c14b..a8638766d5 100644 --- a/x/params/types/common_test.go +++ b/x/params/types/common_test.go @@ -14,7 +14,8 @@ var ( keyMaxValidators = []byte("MaxValidators") keyBondDenom = []byte("BondDenom") - key = sdk.NewKVStoreKey("storekey") + key = sdk.NewKVStoreKey("storekey") + tkey = sdk.NewTransientStoreKey("transientstorekey") ) type params struct { diff --git a/x/params/types/proposal/query.pb.gw.go b/x/params/types/proposal/query.pb.gw.go index e6526e5c1b..aab88f9965 100644 --- a/x/params/types/proposal/query.pb.gw.go +++ b/x/params/types/proposal/query.pb.gw.go @@ -158,7 +158,7 @@ func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, clie } var ( - pattern_Query_Params_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 1}, []string{"lbm", "params", "v1"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_Query_Params_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 1}, []string{"lbm", "params", "v1"}, "", runtime.AssumeColonVerbOpt(false))) ) var ( diff --git a/x/params/types/subspace.go b/x/params/types/subspace.go index 0cea9f8823..f021040694 100644 --- a/x/params/types/subspace.go +++ b/x/params/types/subspace.go @@ -6,17 +6,21 @@ import ( "github.com/line/lbm-sdk/codec" "github.com/line/lbm-sdk/store/prefix" + storetypes "github.com/line/lbm-sdk/store/types" sdk "github.com/line/lbm-sdk/types" ) const ( // StoreKey is the string store key for the param store StoreKey = "params" + + // TStoreKey is the string store key for the param transient store + TStoreKey = "transient_params" ) // Individual parameter store for each keeper type Subspace struct { - cdc codec.BinaryMarshaler + cdc codec.BinaryCodec legacyAmino *codec.LegacyAmino key sdk.StoreKey // []byte -> []byte, stores parameter name []byte @@ -24,8 +28,8 @@ type Subspace struct { } // NewSubspace constructs a store with namestore -func NewSubspace(cdc codec.BinaryMarshaler, legacyAmino *codec.LegacyAmino, key sdk.StoreKey, name string) *Subspace { - return &Subspace{ +func NewSubspace(cdc codec.BinaryCodec, legacyAmino *codec.LegacyAmino, key storetypes.StoreKey, tkey storetypes.StoreKey, name string) Subspace { + return Subspace{ cdc: cdc, legacyAmino: legacyAmino, key: key, @@ -35,12 +39,12 @@ func NewSubspace(cdc codec.BinaryMarshaler, legacyAmino *codec.LegacyAmino, key } // HasKeyTable returns if the Subspace has a KeyTable registered. -func (s *Subspace) HasKeyTable() bool { +func (s Subspace) HasKeyTable() bool { return len(s.table.m) > 0 } // WithKeyTable initializes KeyTable and returns modified Subspace -func (s *Subspace) WithKeyTable(table KeyTable) *Subspace { +func (s Subspace) WithKeyTable(table KeyTable) Subspace { if table.m == nil { panic("SetKeyTable() called with nil KeyTable") } @@ -62,7 +66,7 @@ func (s *Subspace) WithKeyTable(table KeyTable) *Subspace { } // Returns a KVStore identical with ctx.KVStore(s.key).Prefix() -func (s *Subspace) kvStore(ctx sdk.Context) sdk.KVStore { +func (s Subspace) kvStore(ctx sdk.Context) sdk.KVStore { // this function can be called concurrently so we should not call append on s.name directly name := make([]byte, len(s.name)) copy(name, s.name) @@ -71,7 +75,7 @@ func (s *Subspace) kvStore(ctx sdk.Context) sdk.KVStore { // Validate attempts to validate a parameter value by its key. If the key is not // registered or if the validation of the value fails, an error is returned. -func (s *Subspace) Validate(ctx sdk.Context, key []byte, value interface{}) error { +func (s Subspace) Validate(ctx sdk.Context, key []byte, value interface{}) error { attr, ok := s.table.m[string(key)] if !ok { return fmt.Errorf("parameter %s not registered", string(key)) @@ -86,7 +90,7 @@ func (s *Subspace) Validate(ctx sdk.Context, key []byte, value interface{}) erro // Get queries for a parameter by key from the Subspace's KVStore and sets the // value to the provided pointer. If the value does not exist, it will panic. -func (s *Subspace) Get(ctx sdk.Context, key []byte, ptr interface{}) { +func (s Subspace) Get(ctx sdk.Context, key []byte, ptr interface{}) { s.checkType(key, ptr) store := s.kvStore(ctx) @@ -100,7 +104,7 @@ func (s *Subspace) Get(ctx sdk.Context, key []byte, ptr interface{}) { // GetIfExists queries for a parameter by key from the Subspace's KVStore and // sets the value to the provided pointer. If the value does not exist, it will // perform a no-op. -func (s *Subspace) GetIfExists(ctx sdk.Context, key []byte, ptr interface{}) { +func (s Subspace) GetIfExists(ctx sdk.Context, key []byte, ptr interface{}) { store := s.kvStore(ctx) bz := store.Get(key) if bz == nil { @@ -115,19 +119,19 @@ func (s *Subspace) GetIfExists(ctx sdk.Context, key []byte, ptr interface{}) { } // GetRaw queries for the raw values bytes for a parameter by key. -func (s *Subspace) GetRaw(ctx sdk.Context, key []byte) []byte { +func (s Subspace) GetRaw(ctx sdk.Context, key []byte) []byte { store := s.kvStore(ctx) return store.Get(key) } // Has returns if a parameter key exists or not in the Subspace's KVStore. -func (s *Subspace) Has(ctx sdk.Context, key []byte) bool { +func (s Subspace) Has(ctx sdk.Context, key []byte) bool { store := s.kvStore(ctx) return store.Has(key) } // checkType verifies that the provided key and value are comptable and registered. -func (s *Subspace) checkType(key []byte, value interface{}) { +func (s Subspace) checkType(key []byte, value interface{}) { attr, ok := s.table.m[string(key)] if !ok { panic(fmt.Sprintf("parameter %s not registered", string(key))) @@ -148,7 +152,7 @@ func (s *Subspace) checkType(key []byte, value interface{}) { // been registered. It will panic if the parameter type has not been registered // or if the value cannot be encoded. A change record is also set in the Subspace's // transient KVStore to mark the parameter as modified. -func (s *Subspace) Set(ctx sdk.Context, key []byte, value interface{}) { +func (s Subspace) Set(ctx sdk.Context, key []byte, value interface{}) { s.checkType(key, value) store := s.kvStore(ctx) @@ -166,7 +170,7 @@ func (s *Subspace) Set(ctx sdk.Context, key []byte, value interface{}) { // if the raw value is not compatible with the registered type for the parameter // key or if the new value is invalid as determined by the registered type's // validation function. -func (s *Subspace) Update(ctx sdk.Context, key, value []byte) error { +func (s Subspace) Update(ctx sdk.Context, key, value []byte) error { attr, ok := s.table.m[string(key)] if !ok { panic(fmt.Sprintf("parameter %s not registered", string(key))) @@ -194,7 +198,7 @@ func (s *Subspace) Update(ctx sdk.Context, key, value []byte) error { // GetParamSet iterates through each ParamSetPair where for each pair, it will // retrieve the value and set it to the corresponding value pointer provided // in the ParamSetPair by calling Subspace#Get. -func (s *Subspace) GetParamSet(ctx sdk.Context, ps ParamSet) { +func (s Subspace) GetParamSet(ctx sdk.Context, ps ParamSet) { for _, pair := range ps.ParamSetPairs() { s.Get(ctx, pair.Key, pair.Value) } @@ -202,7 +206,7 @@ func (s *Subspace) GetParamSet(ctx sdk.Context, ps ParamSet) { // SetParamSet iterates through each ParamSetPair and sets the value with the // corresponding parameter key in the Subspace's KVStore. -func (s *Subspace) SetParamSet(ctx sdk.Context, ps ParamSet) { +func (s Subspace) SetParamSet(ctx sdk.Context, ps ParamSet) { for _, pair := range ps.ParamSetPairs() { // pair.Field is a pointer to the field, so indirecting the ptr. // go-amino automatically handles it but just for sure, @@ -219,13 +223,13 @@ func (s *Subspace) SetParamSet(ctx sdk.Context, ps ParamSet) { } // Name returns the name of the Subspace. -func (s *Subspace) Name() string { +func (s Subspace) Name() string { return string(s.name) } // Wrapper of Subspace, provides immutable functions only type ReadOnlySubspace struct { - s *Subspace + s Subspace } // Get delegates a read-only Get call to the Subspace. diff --git a/x/params/types/subspace_test.go b/x/params/types/subspace_test.go index 15fc26f1dc..1491128e01 100644 --- a/x/params/types/subspace_test.go +++ b/x/params/types/subspace_test.go @@ -20,10 +20,10 @@ import ( type SubspaceTestSuite struct { suite.Suite - cdc codec.BinaryMarshaler + cdc codec.BinaryCodec amino *codec.LegacyAmino ctx sdk.Context - ss *types.Subspace + ss types.Subspace } func (suite *SubspaceTestSuite) SetupTest() { @@ -34,7 +34,7 @@ func (suite *SubspaceTestSuite) SetupTest() { suite.NoError(ms.LoadLatestVersion()) encCfg := simapp.MakeTestEncodingConfig() - ss := types.NewSubspace(encCfg.Marshaler, encCfg.Amino, key, "testsubspace") + ss := types.NewSubspace(encCfg.Marshaler, encCfg.Amino, key, tkey, "testsubspace") suite.cdc = encCfg.Marshaler suite.amino = encCfg.Amino @@ -48,7 +48,7 @@ func (suite *SubspaceTestSuite) TestKeyTable() { suite.ss.WithKeyTable(paramKeyTable()) }) suite.Require().NotPanics(func() { - ss := types.NewSubspace(suite.cdc, suite.amino, key, "testsubspace2") + ss := types.NewSubspace(suite.cdc, suite.amino, key, tkey, "testsubspace2") ss = ss.WithKeyTable(paramKeyTable()) }) } diff --git a/x/simulation/log.go b/x/simulation/log.go index b50163b33c..ba22b2af4a 100644 --- a/x/simulation/log.go +++ b/x/simulation/log.go @@ -68,7 +68,6 @@ func createLogFile() *os.File { return f } -// _____________________ // dummy log writter type DummyLogWriter struct{} diff --git a/x/simulation/mock_ostracon.go b/x/simulation/mock_ostracon.go index 64ea4b79bd..53a6fbfb2f 100644 --- a/x/simulation/mock_ostracon.go +++ b/x/simulation/mock_ostracon.go @@ -59,8 +59,6 @@ func (vals mockValidators) getKeys() []string { return keys } -// _________________________________________________________________________________ - // randomProposer picks a random proposer from the current validator set func (vals mockValidators) randomProposer(r *rand.Rand) ostbytes.HexBytes { keys := vals.getKeys() diff --git a/x/simulation/operation.go b/x/simulation/operation.go index 28079f0705..86ba7dd376 100644 --- a/x/simulation/operation.go +++ b/x/simulation/operation.go @@ -64,8 +64,6 @@ func (oe OperationEntry) MustMarshal() json.RawMessage { return out } -// _____________________________________________________________________ - // OperationQueue defines an object for a queue of operations type OperationQueue map[int][]simulation.Operation @@ -107,8 +105,6 @@ func queueOperations(queuedOps OperationQueue, queuedTimeOps []simulation.Future } } -// ________________________________________________________________________ - // WeightedOperation is an operation with associated weight. // This is used to bias the selection operation within the simulator. type WeightedOperation struct { diff --git a/x/simulation/params.go b/x/simulation/params.go index 3543355ff6..fc149a3eb9 100644 --- a/x/simulation/params.go +++ b/x/simulation/params.go @@ -87,7 +87,6 @@ func RandomParams(r *rand.Rand) Params { } } -//----------------------------------------------------------------------------- // Param change proposals // ParamChange defines the object used for simulating parameter change proposals @@ -120,10 +119,9 @@ func NewSimParamChange(subspace, key string, simVal simulation.SimValFn) simulat // ComposedKey creates a new composed key for the param change proposal func (spc ParamChange) ComposedKey() string { - return fmt.Sprintf("%s/%s", spc.Subspace(), spc.Key()) + return spc.Subspace() + "/" + spc.Key() } -//----------------------------------------------------------------------------- // Proposal Contents // WeightedProposalContent defines a common struct for proposal contents defined by @@ -150,11 +148,10 @@ func (w WeightedProposalContent) ContentSimulatorFn() simulation.ContentSimulato return w.contentSimulatorFn } -//----------------------------------------------------------------------------- // Param change proposals // randomConsensusParams returns random simulation consensus parameters, it extracts the Evidence from the Staking genesis state. -func randomConsensusParams(r *rand.Rand, appState json.RawMessage, cdc codec.JSONMarshaler) *abci.ConsensusParams { +func randomConsensusParams(r *rand.Rand, appState json.RawMessage, cdc codec.JSONCodec) *abci.ConsensusParams { var genesisState map[string]json.RawMessage err := json.Unmarshal(appState, &genesisState) if err != nil { diff --git a/x/simulation/simulate.go b/x/simulation/simulate.go index 5065c7d94b..a213a2fdb7 100644 --- a/x/simulation/simulate.go +++ b/x/simulation/simulate.go @@ -23,17 +23,22 @@ const AverageBlockTime = 6 * time.Second // initialize the chain for the simulation func initChain( - r *rand.Rand, params Params, accounts []simulation.Account, app *baseapp.BaseApp, - appStateFn simulation.AppStateFn, config simulation.Config, cdc codec.JSONMarshaler, + r *rand.Rand, + params Params, + accounts []simulation.Account, + app *baseapp.BaseApp, + appStateFn simulation.AppStateFn, + config simulation.Config, + cdc codec.JSONCodec, ) (mockValidators, time.Time, []simulation.Account, string) { - appState, accounts, chainID, genesisTimestamp := appStateFn(r, accounts, config) + appState, accounts, chainID, genesisTimestamp := appStateFn(r, accounts, config) consensusParams := randomConsensusParams(r, appState, cdc) - req := abci.RequestInitChain{ AppStateBytes: appState, ChainId: chainID, ConsensusParams: consensusParams, + Time: genesisTimestamp, } res := app.InitChain(req) validators := newMockValidators(r, res.Validators, params) @@ -53,7 +58,7 @@ func SimulateFromSeed( ops WeightedOperations, blockedAddrs map[string]bool, config simulation.Config, - cdc codec.JSONMarshaler, + cdc codec.JSONCodec, ) (stopEarly bool, exportedParams Params, err error) { // in case we have to end early, don't os.Exit so that we can run cleanup code. testingMode, _, b := getTestingMode(tb) @@ -240,8 +245,6 @@ func SimulateFromSeed( return false, exportedParams, nil } -// ______________________________________________________________________________ - type blockSimFn func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accounts []simulation.Account, header ocproto.Header) (opCount int) diff --git a/x/simulation/util.go b/x/simulation/util.go index d276147ee2..5d15a21f1f 100644 --- a/x/simulation/util.go +++ b/x/simulation/util.go @@ -10,8 +10,8 @@ import ( "github.com/line/lbm-sdk/client" "github.com/line/lbm-sdk/codec" "github.com/line/lbm-sdk/simapp/helpers" - "github.com/line/lbm-sdk/types" - simtype "github.com/line/lbm-sdk/types/simulation" + sdk "github.com/line/lbm-sdk/types" + simtypes "github.com/line/lbm-sdk/types/simulation" ) func getTestingMode(tb testing.TB) (testingMode bool, t *testing.T, b *testing.B) { @@ -67,42 +67,42 @@ type OperationInput struct { App *baseapp.BaseApp TxGen client.TxConfig Cdc *codec.ProtoCodec - Msg types.Msg + Msg sdk.Msg MsgType string - CoinsSpentInMsg types.Coins - Context types.Context - SimAccount simtype.Account + CoinsSpentInMsg sdk.Coins + Context sdk.Context + SimAccount simtypes.Account AccountKeeper AccountKeeper Bankkeeper BankKeeper ModuleName string } // GenAndDeliverTxWithRandFees generates a transaction with a random fee and delivers it. -func GenAndDeliverTxWithRandFees(txCtx OperationInput) (simtype.OperationMsg, []simtype.FutureOperation, error) { +func GenAndDeliverTxWithRandFees(txCtx OperationInput) (simtypes.OperationMsg, []simtypes.FutureOperation, error) { account := txCtx.AccountKeeper.GetAccount(txCtx.Context, txCtx.SimAccount.Address) spendable := txCtx.Bankkeeper.SpendableCoins(txCtx.Context, account.GetAddress()) - var fees types.Coins + var fees sdk.Coins var err error coins, hasNeg := spendable.SafeSub(txCtx.CoinsSpentInMsg) if hasNeg { - return simtype.NoOpMsg(txCtx.ModuleName, txCtx.MsgType, "message doesn't leave room for fees"), nil, err + return simtypes.NoOpMsg(txCtx.ModuleName, txCtx.MsgType, "message doesn't leave room for fees"), nil, err } - fees, err = simtype.RandomFees(txCtx.R, txCtx.Context, coins) + fees, err = simtypes.RandomFees(txCtx.R, txCtx.Context, coins) if err != nil { - return simtype.NoOpMsg(txCtx.ModuleName, txCtx.MsgType, "unable to generate fees"), nil, err + return simtypes.NoOpMsg(txCtx.ModuleName, txCtx.MsgType, "unable to generate fees"), nil, err } return GenAndDeliverTx(txCtx, fees) } // GenAndDeliverTx generates a transactions and delivers it. -func GenAndDeliverTx(txCtx OperationInput, fees types.Coins) (simtype.OperationMsg, []simtype.FutureOperation, error) { +func GenAndDeliverTx(txCtx OperationInput, fees sdk.Coins) (simtypes.OperationMsg, []simtypes.FutureOperation, error) { account := txCtx.AccountKeeper.GetAccount(txCtx.Context, txCtx.SimAccount.Address) tx, err := helpers.GenTx( txCtx.TxGen, - []types.Msg{txCtx.Msg}, + []sdk.Msg{txCtx.Msg}, fees, helpers.DefaultGenTxGas, txCtx.Context.ChainID(), @@ -112,14 +112,13 @@ func GenAndDeliverTx(txCtx OperationInput, fees types.Coins) (simtype.OperationM ) if err != nil { - return simtype.NoOpMsg(txCtx.ModuleName, txCtx.MsgType, "unable to generate mock tx"), nil, err + return simtypes.NoOpMsg(txCtx.ModuleName, txCtx.MsgType, "unable to generate mock tx"), nil, err } _, _, err = txCtx.App.Deliver(txCtx.TxGen.TxEncoder(), tx) if err != nil { - return simtype.NoOpMsg(txCtx.ModuleName, txCtx.MsgType, "unable to deliver tx"), nil, err + return simtypes.NoOpMsg(txCtx.ModuleName, txCtx.MsgType, "unable to deliver tx"), nil, err } - return simtype.NewOperationMsg(txCtx.Msg, true, ""), nil, nil - + return simtypes.NewOperationMsg(txCtx.Msg, true, "", txCtx.Cdc), nil, nil } diff --git a/x/slashing/abci_test.go b/x/slashing/abci_test.go index 82cb42767c..a43f778a67 100644 --- a/x/slashing/abci_test.go +++ b/x/slashing/abci_test.go @@ -21,7 +21,7 @@ func TestBeginBlocker(t *testing.T) { ctx := app.BaseApp.NewContext(false, ocproto.Header{}) pks := simapp.CreateTestPubKeys(1) - simapp.AddTestAddrsFromPubKeys(app, ctx, pks, sdk.TokensFromConsensusPower(200)) + simapp.AddTestAddrsFromPubKeys(app, ctx, pks, app.StakingKeeper.TokensFromConsensusPower(ctx, 200)) addr, pk := sdk.BytesToValAddress(pks[0].Address()), pks[0] tstaking := teststaking.NewHelper(t, ctx, app.StakingKeeper) diff --git a/x/slashing/app_test.go b/x/slashing/app_test.go index 5b095bda4c..51234f3097 100644 --- a/x/slashing/app_test.go +++ b/x/slashing/app_test.go @@ -41,8 +41,8 @@ func checkValidatorSigningInfo(t *testing.T, app *simapp.SimApp, addr sdk.ConsAd } func TestSlashingMsgs(t *testing.T) { - genTokens := sdk.TokensFromConsensusPower(42) - bondTokens := sdk.TokensFromConsensusPower(10) + genTokens := sdk.TokensFromConsensusPower(42, sdk.DefaultPowerReduction) + bondTokens := sdk.TokensFromConsensusPower(10, sdk.DefaultPowerReduction) genCoin := sdk.NewCoin(sdk.DefaultBondDenom, genTokens) bondCoin := sdk.NewCoin(sdk.DefaultBondDenom, bondTokens) diff --git a/x/slashing/client/cli/query.go b/x/slashing/client/cli/query.go index f194f83d40..300cd0825a 100644 --- a/x/slashing/client/cli/query.go +++ b/x/slashing/client/cli/query.go @@ -1,15 +1,14 @@ package cli import ( - "context" "strings" "github.com/spf13/cobra" "github.com/line/lbm-sdk/client" "github.com/line/lbm-sdk/client/flags" + cryptotypes "github.com/line/lbm-sdk/crypto/types" sdk "github.com/line/lbm-sdk/types" - "github.com/line/lbm-sdk/x/slashing/types" ) @@ -41,7 +40,7 @@ func GetCmdQuerySigningInfo() *cobra.Command { Short: "Query a validator's signing information", Long: strings.TrimSpace(`Use a validators' consensus public key to find the signing-info for that validator: -$ query slashing signing-info cosmosvalconspub1zcjduepqfhvwcmt7p06fvdgexxhmz0l8c7sgswl7ulv7aulk364x4g5xsw7sr0k2g5 +$ query slashing signing-info '{"@type":"/lbm.crypto.ed25519.PubKey","key":"OauFcTKbN5Lx3fJL689cikXBqe+hcp6Y+x0rYUdR9Jk="}' `), Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { @@ -49,16 +48,16 @@ $ query slashing signing-info cosmosvalconspub1zcjduepqfhvwcmt7p06fvdgexx if err != nil { return err } - queryClient := types.NewQueryClient(clientCtx) - pk, err := sdk.GetPubKeyFromBech32(sdk.Bech32PubKeyTypeConsPub, args[0]) - if err != nil { + var pk cryptotypes.PubKey + if err := clientCtx.Codec.UnmarshalInterfaceJSON([]byte(args[0]), &pk); err != nil { return err } + queryClient := types.NewQueryClient(clientCtx) consAddr := sdk.BytesToConsAddress(pk.Address()) params := &types.QuerySigningInfoRequest{ConsAddress: consAddr.String()} - res, err := queryClient.SigningInfo(context.Background(), params) + res, err := queryClient.SigningInfo(cmd.Context(), params) if err != nil { return err } @@ -95,7 +94,7 @@ $ query slashing signing-infos } params := &types.QuerySigningInfosRequest{Pagination: pageReq} - res, err := queryClient.SigningInfos(context.Background(), params) + res, err := queryClient.SigningInfos(cmd.Context(), params) if err != nil { return err } @@ -128,7 +127,7 @@ $ query slashing params queryClient := types.NewQueryClient(clientCtx) params := &types.QueryParamsRequest{} - res, err := queryClient.Params(context.Background(), params) + res, err := queryClient.Params(cmd.Context(), params) if err != nil { return err } diff --git a/x/slashing/client/cli/tx.go b/x/slashing/client/cli/tx.go index aecd1796ba..c692bc019c 100644 --- a/x/slashing/client/cli/tx.go +++ b/x/slashing/client/cli/tx.go @@ -40,9 +40,6 @@ $ tx slashing unjail --from mykey valAddr := clientCtx.GetFromAddress() msg := types.NewMsgUnjail(valAddr.ToValAddress()) - if err := msg.ValidateBasic(); err != nil { - return err - } return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) }, diff --git a/x/slashing/client/rest/grpc_query_test.go b/x/slashing/client/rest/grpc_query_test.go index aaf79d3dc2..099fb730ab 100644 --- a/x/slashing/client/rest/grpc_query_test.go +++ b/x/slashing/client/rest/grpc_query_test.go @@ -117,7 +117,7 @@ func (s *IntegrationTestSuite) TestGRPCQueries() { resp, err := testutil.GetRequestWithHeaders(tc.url, tc.headers) s.Require().NoError(err) - err = val.ClientCtx.JSONMarshaler.UnmarshalJSON(resp, tc.respType) + err = val.ClientCtx.Codec.UnmarshalJSON(resp, tc.respType) if tc.expErr { s.Require().Error(err) diff --git a/x/slashing/client/rest/query.go b/x/slashing/client/rest/query.go index bd135504f7..a91150a6b4 100644 --- a/x/slashing/client/rest/query.go +++ b/x/slashing/client/rest/query.go @@ -7,7 +7,7 @@ import ( "github.com/gorilla/mux" "github.com/line/lbm-sdk/client" - sdk "github.com/line/lbm-sdk/types" + "github.com/line/lbm-sdk/types/bech32/legacybech32" //nolint:staticcheck "github.com/line/lbm-sdk/types/rest" "github.com/line/lbm-sdk/x/slashing/types" ) @@ -29,11 +29,11 @@ func registerQueryRoutes(clientCtx client.Context, r *mux.Router) { ).Methods("GET") } -// http request handler to query signing info +// Deprecated: http request handler to query signing info func signingInfoHandlerFn(clientCtx client.Context) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) - pk, err := sdk.GetPubKeyFromBech32(sdk.Bech32PubKeyTypeConsPub, vars["validatorPubKey"]) + pk, err := legacybech32.UnmarshalPubKey(legacybech32.ConsPK, vars["validatorPubKey"]) if rest.CheckBadRequestError(w, err) { return } diff --git a/x/slashing/client/rest/rest.go b/x/slashing/client/rest/rest.go index f529c0ceea..ac8b6e3c28 100644 --- a/x/slashing/client/rest/rest.go +++ b/x/slashing/client/rest/rest.go @@ -3,9 +3,8 @@ package rest import ( "github.com/gorilla/mux" - "github.com/line/lbm-sdk/client/rest" - "github.com/line/lbm-sdk/client" + "github.com/line/lbm-sdk/client/rest" ) func RegisterHandlers(clientCtx client.Context, rtr *mux.Router) { diff --git a/x/slashing/client/testutil/cli_test.go b/x/slashing/client/testutil/cli_test.go new file mode 100644 index 0000000000..8ded31fefa --- /dev/null +++ b/x/slashing/client/testutil/cli_test.go @@ -0,0 +1,18 @@ +//go:build norace +// +build norace + +package testutil + +import ( + "testing" + + "github.com/line/lbm-sdk/testutil/network" + + "github.com/stretchr/testify/suite" +) + +func TestIntegrationTestSuite(t *testing.T) { + cfg := network.DefaultConfig() + cfg.NumValidators = 1 + suite.Run(t, NewIntegrationTestSuite(cfg)) +} diff --git a/x/slashing/client/cli/cli_test.go b/x/slashing/client/testutil/suite.go similarity index 90% rename from x/slashing/client/cli/cli_test.go rename to x/slashing/client/testutil/suite.go index 64ed523522..a17be423f8 100644 --- a/x/slashing/client/cli/cli_test.go +++ b/x/slashing/client/testutil/suite.go @@ -1,11 +1,8 @@ -// +build norace - -package cli_test +package testutil import ( "fmt" "strings" - "testing" "github.com/gogo/protobuf/proto" ostcli "github.com/line/ostracon/libs/cli" @@ -25,16 +22,16 @@ type IntegrationTestSuite struct { network *network.Network } +func NewIntegrationTestSuite(cfg network.Config) *IntegrationTestSuite { + return &IntegrationTestSuite{cfg: cfg} +} + // SetupSuite executes bootstrapping logic before all the tests, i.e. once before // the entire suite, start executing. func (s *IntegrationTestSuite) SetupSuite() { s.T().Log("setting up integration test suite") - cfg := network.DefaultConfig() - cfg.NumValidators = 1 - - s.cfg = cfg - s.network = network.New(s.T(), cfg) + s.network = network.New(s.T(), s.cfg) _, err := s.network.WaitForHeight(1) s.Require().NoError(err) @@ -49,9 +46,9 @@ func (s *IntegrationTestSuite) TearDownSuite() { func (s *IntegrationTestSuite) TestGetCmdQuerySigningInfo() { val := s.network.Validators[0] - - valConsPubKey, err := sdk.Bech32ifyPubKey(sdk.Bech32PubKeyTypeConsPub, val.PubKey) + pubKeyBz, err := s.cfg.Codec.MarshalInterfaceJSON(val.PubKey) s.Require().NoError(err) + pubKeyStr := string(pubKeyBz) testCases := []struct { name string @@ -63,7 +60,7 @@ func (s *IntegrationTestSuite) TestGetCmdQuerySigningInfo() { { "valid address (json output)", []string{ - valConsPubKey, + pubKeyStr, fmt.Sprintf("--%s=json", ostcli.OutputFlag), fmt.Sprintf("--%s=1", flags.FlagHeight), }, @@ -73,7 +70,7 @@ func (s *IntegrationTestSuite) TestGetCmdQuerySigningInfo() { { "valid address (text output)", []string{ - valConsPubKey, + pubKeyStr, fmt.Sprintf("--%s=text", ostcli.OutputFlag), fmt.Sprintf("--%s=1", flags.FlagHeight), }, @@ -144,13 +141,12 @@ slash_fraction_downtime: "0.010000000000000000"`, func (s *IntegrationTestSuite) TestNewUnjailTxCmd() { val := s.network.Validators[0] - testCases := []struct { name string args []string expectErr bool - respType proto.Message expectedCode uint32 + respType proto.Message }{ { "valid transaction", @@ -160,7 +156,7 @@ func (s *IntegrationTestSuite) TestNewUnjailTxCmd() { fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync), // sync mode as there are no funds yet fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), }, - false, &sdk.TxResponse{}, 0, + false, 0, &sdk.TxResponse{}, }, } @@ -176,7 +172,7 @@ func (s *IntegrationTestSuite) TestNewUnjailTxCmd() { s.Require().Error(err) } else { s.Require().NoError(err) - s.Require().NoError(clientCtx.JSONMarshaler.UnmarshalJSON(out.Bytes(), tc.respType), out.String()) + s.Require().NoError(clientCtx.Codec.UnmarshalJSON(out.Bytes(), tc.respType), out.String()) txResp := tc.respType.(*sdk.TxResponse) s.Require().Equal(tc.expectedCode, txResp.Code, out.String()) @@ -184,7 +180,3 @@ func (s *IntegrationTestSuite) TestNewUnjailTxCmd() { }) } } - -func TestIntegrationTestSuite(t *testing.T) { - suite.Run(t, new(IntegrationTestSuite)) -} diff --git a/x/slashing/genesis_test.go b/x/slashing/genesis_test.go index e0a5efc757..f8ee6ae373 100644 --- a/x/slashing/genesis_test.go +++ b/x/slashing/genesis_test.go @@ -8,7 +8,6 @@ import ( "github.com/stretchr/testify/require" "github.com/line/lbm-sdk/simapp" - sdk "github.com/line/lbm-sdk/types" "github.com/line/lbm-sdk/x/slashing" "github.com/line/lbm-sdk/x/slashing/testslashing" "github.com/line/lbm-sdk/x/slashing/types" @@ -20,7 +19,7 @@ func TestExportAndInitGenesis(t *testing.T) { app.SlashingKeeper.SetParams(ctx, testslashing.TestParams()) - addrDels := simapp.AddTestAddrsIncremental(app, ctx, 2, sdk.TokensFromConsensusPower(200)) + addrDels := simapp.AddTestAddrsIncremental(app, ctx, 2, app.StakingKeeper.TokensFromConsensusPower(ctx, 200)) info1 := types.NewValidatorSigningInfo(addrDels[0].ToConsAddress(), time.Now().UTC().Add(100000000000), false, int64(10), int64(3)) info2 := types.NewValidatorSigningInfo(addrDels[1].ToConsAddress(), diff --git a/x/slashing/handler_test.go b/x/slashing/handler_test.go index 4229e2d185..3dd4d348d8 100644 --- a/x/slashing/handler_test.go +++ b/x/slashing/handler_test.go @@ -26,7 +26,7 @@ func TestCannotUnjailUnlessJailed(t *testing.T) { app := simapp.Setup(false) ctx := app.BaseApp.NewContext(false, ocproto.Header{}) pks := simapp.CreateTestPubKeys(1) - simapp.AddTestAddrsFromPubKeys(app, ctx, pks, sdk.TokensFromConsensusPower(200)) + simapp.AddTestAddrsFromPubKeys(app, ctx, pks, app.StakingKeeper.TokensFromConsensusPower(ctx, 200)) tstaking := teststaking.NewHelper(t, ctx, app.StakingKeeper) slh := slashing.NewHandler(app.SlashingKeeper) @@ -52,12 +52,12 @@ func TestCannotUnjailUnlessMeetMinSelfDelegation(t *testing.T) { app := simapp.Setup(false) ctx := app.BaseApp.NewContext(false, ocproto.Header{}) pks := simapp.CreateTestPubKeys(1) - simapp.AddTestAddrsFromPubKeys(app, ctx, pks, sdk.TokensFromConsensusPower(200)) + simapp.AddTestAddrsFromPubKeys(app, ctx, pks, app.StakingKeeper.TokensFromConsensusPower(ctx, 200)) tstaking := teststaking.NewHelper(t, ctx, app.StakingKeeper) slh := slashing.NewHandler(app.SlashingKeeper) addr, val := sdk.BytesToValAddress(pks[0].Address()), pks[0] - amt := sdk.TokensFromConsensusPower(100) + amt := app.StakingKeeper.TokensFromConsensusPower(ctx, 100) msg := tstaking.CreateValidatorMsg(addr, val, amt) msg.MinSelfDelegation = amt tstaking.Handle(msg, true) @@ -84,7 +84,7 @@ func TestJailedValidatorDelegations(t *testing.T) { ctx := app.BaseApp.NewContext(false, ocproto.Header{Time: time.Unix(0, 0)}) pks := simapp.CreateTestPubKeys(3) - simapp.AddTestAddrsFromPubKeys(app, ctx, pks, sdk.TokensFromConsensusPower(20)) + simapp.AddTestAddrsFromPubKeys(app, ctx, pks, app.StakingKeeper.TokensFromConsensusPower(ctx, 20)) app.SlashingKeeper.SetParams(ctx, testslashing.TestParams()) tstaking := teststaking.NewHelper(t, ctx, app.StakingKeeper) @@ -145,7 +145,7 @@ func TestHandleAbsentValidator(t *testing.T) { app := simapp.Setup(false) ctx := app.BaseApp.NewContext(false, ocproto.Header{Time: time.Unix(0, 0)}) pks := simapp.CreateTestPubKeys(1) - simapp.AddTestAddrsFromPubKeys(app, ctx, pks, sdk.TokensFromConsensusPower(200)) + simapp.AddTestAddrsFromPubKeys(app, ctx, pks, app.StakingKeeper.TokensFromConsensusPower(ctx, 200)) app.SlashingKeeper.SetParams(ctx, testslashing.TestParams()) power := int64(100) diff --git a/x/slashing/init_test.go b/x/slashing/init_test.go index 6c551970fd..6f7e17f997 100644 --- a/x/slashing/init_test.go +++ b/x/slashing/init_test.go @@ -5,5 +5,6 @@ import ( ) var ( - InitTokens = sdk.TokensFromConsensusPower(200) + // The default power validators are initialized to have within tests + InitTokens = sdk.TokensFromConsensusPower(200, sdk.DefaultPowerReduction) ) diff --git a/x/slashing/keeper/common_test.go b/x/slashing/keeper/common_test.go index 89aa6ab56f..fff2d20126 100644 --- a/x/slashing/keeper/common_test.go +++ b/x/slashing/keeper/common_test.go @@ -3,5 +3,6 @@ package keeper_test import sdk "github.com/line/lbm-sdk/types" var ( - InitTokens = sdk.TokensFromConsensusPower(200) + // The default power validators are initialized to have within tests + InitTokens = sdk.TokensFromConsensusPower(200, sdk.DefaultPowerReduction) ) diff --git a/x/slashing/keeper/grpc_query.go b/x/slashing/keeper/grpc_query.go index cf5f4821c0..acae75d114 100644 --- a/x/slashing/keeper/grpc_query.go +++ b/x/slashing/keeper/grpc_query.go @@ -57,7 +57,7 @@ func (k Keeper) SigningInfos(c context.Context, req *types.QuerySigningInfosRequ sigInfoStore := prefix.NewStore(store, types.ValidatorSigningInfoKeyPrefix) pageRes, err := query.Paginate(sigInfoStore, req.Pagination, func(key []byte, value []byte) error { var info types.ValidatorSigningInfo - err := k.cdc.UnmarshalBinaryBare(value, &info) + err := k.cdc.Unmarshal(value, &info) if err != nil { return err } diff --git a/x/slashing/keeper/grpc_query_test.go b/x/slashing/keeper/grpc_query_test.go index b1f70c5cbd..7067b18300 100644 --- a/x/slashing/keeper/grpc_query_test.go +++ b/x/slashing/keeper/grpc_query_test.go @@ -35,7 +35,7 @@ func (suite *SlashingTestSuite) SetupTest() { app.BankKeeper.SetParams(ctx, banktypes.DefaultParams()) app.SlashingKeeper.SetParams(ctx, testslashing.TestParams()) - addrDels := simapp.AddTestAddrsIncremental(app, ctx, 2, sdk.TokensFromConsensusPower(200)) + addrDels := simapp.AddTestAddrsIncremental(app, ctx, 2, app.StakingKeeper.TokensFromConsensusPower(ctx, 200)) info1 := types.NewValidatorSigningInfo(addrDels[0].ToConsAddress(), time.Unix(2, 0), false, int64(10), int64(3)) diff --git a/x/slashing/keeper/hooks.go b/x/slashing/keeper/hooks.go index 4bb4ae9969..368ae24702 100644 --- a/x/slashing/keeper/hooks.go +++ b/x/slashing/keeper/hooks.go @@ -40,8 +40,6 @@ func (k Keeper) AfterValidatorRemoved(ctx sdk.Context, address sdk.ConsAddress) k.deleteAddrPubkeyRelation(ctx, addrBytes) } -// _________________________________________________________________________________________ - // Hooks wrapper struct for slashing keeper type Hooks struct { k Keeper diff --git a/x/slashing/keeper/keeper.go b/x/slashing/keeper/keeper.go index f98b661b1f..f44f4390e8 100644 --- a/x/slashing/keeper/keeper.go +++ b/x/slashing/keeper/keeper.go @@ -14,13 +14,13 @@ import ( // Keeper of the slashing store type Keeper struct { storeKey sdk.StoreKey - cdc codec.BinaryMarshaler + cdc codec.BinaryCodec sk types.StakingKeeper paramspace types.ParamSubspace } // NewKeeper creates a slashing keeper -func NewKeeper(cdc codec.BinaryMarshaler, key sdk.StoreKey, sk types.StakingKeeper, paramspace types.ParamSubspace) Keeper { +func NewKeeper(cdc codec.BinaryCodec, key sdk.StoreKey, sk types.StakingKeeper, paramspace types.ParamSubspace) Keeper { // set KeyTable if it has not already been set if !paramspace.HasKeyTable() { paramspace = paramspace.WithKeyTable(types.ParamKeyTable()) diff --git a/x/slashing/keeper/keeper_test.go b/x/slashing/keeper/keeper_test.go index 660d765f0c..a1c4209622 100644 --- a/x/slashing/keeper/keeper_test.go +++ b/x/slashing/keeper/keeper_test.go @@ -23,7 +23,7 @@ func TestUnJailNotBonded(t *testing.T) { p.MaxValidators = 5 app.StakingKeeper.SetParams(ctx, p) - addrDels := simapp.AddTestAddrsIncremental(app, ctx, 6, sdk.TokensFromConsensusPower(200)) + addrDels := simapp.AddTestAddrsIncremental(app, ctx, 6, app.StakingKeeper.TokensFromConsensusPower(ctx, 200)) valAddrs := simapp.ConvertAddrsToValAddrs(addrDels) pks := simapp.CreateTestPubKeys(6) tstaking := teststaking.NewHelper(t, ctx, app.StakingKeeper) @@ -39,7 +39,7 @@ func TestUnJailNotBonded(t *testing.T) { // create a 6th validator with less power than the cliff validator (won't be bonded) addr, val := valAddrs[5], pks[5] - amt := sdk.TokensFromConsensusPower(50) + amt := app.StakingKeeper.TokensFromConsensusPower(ctx, 50) msg := tstaking.CreateValidatorMsg(addr, val, amt) msg.MinSelfDelegation = amt tstaking.Handle(msg, true) @@ -51,7 +51,7 @@ func TestUnJailNotBonded(t *testing.T) { // unbond below minimum self-delegation require.Equal(t, p.BondDenom, tstaking.Denom) - tstaking.Undelegate(addr.ToAccAddress(), addr, sdk.TokensFromConsensusPower(1), true) + tstaking.Undelegate(addr.ToAccAddress(), addr, app.StakingKeeper.TokensFromConsensusPower(ctx, 1), true) staking.EndBlocker(ctx, app.StakingKeeper) ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1) @@ -83,7 +83,7 @@ func TestHandleNewValidator(t *testing.T) { app := simapp.Setup(false) ctx := app.BaseApp.NewContext(false, ocproto.Header{}) - addrDels := simapp.AddTestAddrsIncremental(app, ctx, 1, sdk.TokensFromConsensusPower(200)) + addrDels := simapp.AddTestAddrsIncremental(app, ctx, 1, app.StakingKeeper.TokensFromConsensusPower(ctx, 200)) valAddrs := simapp.ConvertAddrsToValAddrs(addrDels) pks := simapp.CreateTestPubKeys(1) addr, val := valAddrs[0], pks[0] @@ -115,7 +115,7 @@ func TestHandleNewValidator(t *testing.T) { validator, _ := app.StakingKeeper.GetValidatorByConsAddr(ctx, sdk.GetConsAddress(val)) require.Equal(t, stakingtypes.Bonded, validator.GetStatus()) bondPool := app.StakingKeeper.GetBondedPool(ctx) - expTokens := sdk.TokensFromConsensusPower(100) + expTokens := app.StakingKeeper.TokensFromConsensusPower(ctx, 100) require.True(t, expTokens.Equal(app.BankKeeper.GetBalance(ctx, bondPool.GetAddress(), app.StakingKeeper.BondDenom(ctx)).Amount)) } @@ -126,7 +126,7 @@ func TestHandleAlreadyJailed(t *testing.T) { app := simapp.Setup(false) ctx := app.BaseApp.NewContext(false, ocproto.Header{}) - addrDels := simapp.AddTestAddrsIncremental(app, ctx, 1, sdk.TokensFromConsensusPower(200)) + addrDels := simapp.AddTestAddrsIncremental(app, ctx, 1, app.StakingKeeper.TokensFromConsensusPower(ctx, 200)) valAddrs := simapp.ConvertAddrsToValAddrs(addrDels) pks := simapp.CreateTestPubKeys(1) addr, val := valAddrs[0], pks[0] @@ -158,7 +158,7 @@ func TestHandleAlreadyJailed(t *testing.T) { require.Equal(t, stakingtypes.Unbonding, validator.GetStatus()) // validator should have been slashed - resultingTokens := amt.Sub(sdk.TokensFromConsensusPower(1)) + resultingTokens := amt.Sub(app.StakingKeeper.TokensFromConsensusPower(ctx, 1)) require.Equal(t, resultingTokens, validator.GetTokens()) // another block missed @@ -187,7 +187,7 @@ func TestValidatorDippingInAndOut(t *testing.T) { power := int64(100) pks := simapp.CreateTestPubKeys(3) - simapp.AddTestAddrsFromPubKeys(app, ctx, pks, sdk.TokensFromConsensusPower(200)) + simapp.AddTestAddrsFromPubKeys(app, ctx, pks, app.StakingKeeper.TokensFromConsensusPower(ctx, 200)) addr, val := pks[0].Address(), pks[0] consAddr := sdk.BytesToConsAddress(addr) diff --git a/x/slashing/keeper/signing_info.go b/x/slashing/keeper/signing_info.go index 9690558279..90ac783460 100644 --- a/x/slashing/keeper/signing_info.go +++ b/x/slashing/keeper/signing_info.go @@ -18,7 +18,7 @@ func (k Keeper) GetValidatorSigningInfo(ctx sdk.Context, address sdk.ConsAddress found = false return } - k.cdc.MustUnmarshalBinaryBare(bz, &info) + k.cdc.MustUnmarshal(bz, &info) found = true return } @@ -33,7 +33,7 @@ func (k Keeper) HasValidatorSigningInfo(ctx sdk.Context, consAddr sdk.ConsAddres // SetValidatorSigningInfo sets the validator signing info to a consensus address key func (k Keeper) SetValidatorSigningInfo(ctx sdk.Context, address sdk.ConsAddress, info types.ValidatorSigningInfo) { store := ctx.KVStore(k.storeKey) - bz := k.cdc.MustMarshalBinaryBare(&info) + bz := k.cdc.MustMarshal(&info) store.Set(types.ValidatorSigningInfoKey(address), bz) } @@ -47,7 +47,7 @@ func (k Keeper) IterateValidatorSigningInfos(ctx sdk.Context, for ; iter.Valid(); iter.Next() { address := types.ValidatorSigningInfoAddress(iter.Key()) var info types.ValidatorSigningInfo - k.cdc.MustUnmarshalBinaryBare(iter.Value(), &info) + k.cdc.MustUnmarshal(iter.Value(), &info) if handler(address, info) { break } @@ -63,7 +63,7 @@ func (k Keeper) GetValidatorMissedBlockBitArray(ctx sdk.Context, address sdk.Con // lazy: treat empty key as not missed return false } - k.cdc.MustUnmarshalBinaryBare(bz, &missed) + k.cdc.MustUnmarshal(bz, &missed) return missed.Value } @@ -83,7 +83,7 @@ func (k Keeper) IterateValidatorMissedBlockBitArray(ctx sdk.Context, continue } - k.cdc.MustUnmarshalBinaryBare(bz, &missed) + k.cdc.MustUnmarshal(bz, &missed) if handler(index, missed.Value) { break } @@ -143,7 +143,7 @@ func (k Keeper) IsTombstoned(ctx sdk.Context, consAddr sdk.ConsAddress) bool { // missed a block in the current window func (k Keeper) SetValidatorMissedBlockBitArray(ctx sdk.Context, address sdk.ConsAddress, index int64, missed bool) { store := ctx.KVStore(k.storeKey) - bz := k.cdc.MustMarshalBinaryBare(&gogotypes.BoolValue{Value: missed}) + bz := k.cdc.MustMarshal(&gogotypes.BoolValue{Value: missed}) store.Set(types.ValidatorMissedBlockBitArrayKey(address, index), bz) } diff --git a/x/slashing/keeper/signing_info_test.go b/x/slashing/keeper/signing_info_test.go index ac8d5ea204..28f70a300a 100644 --- a/x/slashing/keeper/signing_info_test.go +++ b/x/slashing/keeper/signing_info_test.go @@ -4,18 +4,18 @@ import ( "testing" "time" - ocproto "github.com/line/ostracon/proto/ostracon/types" "github.com/stretchr/testify/require" + ocproto "github.com/line/ostracon/proto/ostracon/types" + "github.com/line/lbm-sdk/simapp" - sdk "github.com/line/lbm-sdk/types" "github.com/line/lbm-sdk/x/slashing/types" ) func TestGetSetValidatorSigningInfo(t *testing.T) { app := simapp.Setup(false) ctx := app.BaseApp.NewContext(false, ocproto.Header{}) - addrDels := simapp.AddTestAddrsIncremental(app, ctx, 1, sdk.TokensFromConsensusPower(200)) + addrDels := simapp.AddTestAddrsIncremental(app, ctx, 1, app.StakingKeeper.TokensFromConsensusPower(ctx, 200)) info, found := app.SlashingKeeper.GetValidatorSigningInfo(ctx, addrDels[0].ToConsAddress()) require.False(t, found) @@ -37,7 +37,7 @@ func TestGetSetValidatorSigningInfo(t *testing.T) { func TestGetSetValidatorMissedBlockBitArray(t *testing.T) { app := simapp.Setup(false) ctx := app.BaseApp.NewContext(false, ocproto.Header{}) - addrDels := simapp.AddTestAddrsIncremental(app, ctx, 1, sdk.TokensFromConsensusPower(200)) + addrDels := simapp.AddTestAddrsIncremental(app, ctx, 1, app.StakingKeeper.TokensFromConsensusPower(ctx, 200)) missed := app.SlashingKeeper.GetValidatorMissedBlockBitArray(ctx, addrDels[0].ToConsAddress(), 0) require.False(t, missed) // treat empty key as not missed @@ -49,7 +49,7 @@ func TestGetSetValidatorMissedBlockBitArray(t *testing.T) { func TestTombstoned(t *testing.T) { app := simapp.Setup(false) ctx := app.BaseApp.NewContext(false, ocproto.Header{}) - addrDels := simapp.AddTestAddrsIncremental(app, ctx, 1, sdk.TokensFromConsensusPower(200)) + addrDels := simapp.AddTestAddrsIncremental(app, ctx, 1, app.StakingKeeper.TokensFromConsensusPower(ctx, 200)) require.Panics(t, func() { app.SlashingKeeper.Tombstone(ctx, addrDels[0].ToConsAddress()) }) require.False(t, app.SlashingKeeper.IsTombstoned(ctx, addrDels[0].ToConsAddress())) @@ -72,7 +72,7 @@ func TestTombstoned(t *testing.T) { func TestJailUntil(t *testing.T) { app := simapp.Setup(false) ctx := app.BaseApp.NewContext(false, ocproto.Header{}) - addrDels := simapp.AddTestAddrsIncremental(app, ctx, 1, sdk.TokensFromConsensusPower(200)) + addrDels := simapp.AddTestAddrsIncremental(app, ctx, 1, app.StakingKeeper.TokensFromConsensusPower(ctx, 200)) require.Panics(t, func() { app.SlashingKeeper.JailUntil(ctx, addrDels[0].ToConsAddress(), time.Now()) }) diff --git a/x/slashing/legacy/v040/keys.go b/x/slashing/legacy/v040/keys.go new file mode 100644 index 0000000000..580f894b35 --- /dev/null +++ b/x/slashing/legacy/v040/keys.go @@ -0,0 +1,69 @@ +// Package v040 is copy-pasted from: +// https://github.com/cosmos/cosmos-sdk/blob/v0.41.0/x/slashing/types/keys.go +package v040 + +import ( + "encoding/binary" + + sdk "github.com/line/lbm-sdk/types" + v040auth "github.com/line/lbm-sdk/x/auth/legacy/v040" +) + +const ( + // ModuleName is the name of the module + ModuleName = "slashing" + + // StoreKey is the store key string for slashing + StoreKey = ModuleName + + // RouterKey is the message route for slashing + RouterKey = ModuleName + + // QuerierRoute is the querier route for slashing + QuerierRoute = ModuleName +) + +// Keys for slashing store +// Items are stored with the following key: values +// +// - 0x01: ValidatorSigningInfo +// +// - 0x02: bool +// +// - 0x03: crypto.PubKey +var ( + ValidatorSigningInfoKeyPrefix = []byte{0x01} // Prefix for signing info + ValidatorMissedBlockBitArrayKeyPrefix = []byte{0x02} // Prefix for missed block bit array + AddrPubkeyRelationKeyPrefix = []byte{0x03} // Prefix for address-pubkey relation +) + +// ValidatorSigningInfoKey - stored by *Consensus* address (not operator address) +func ValidatorSigningInfoKey(v sdk.ConsAddress) []byte { + return append(ValidatorSigningInfoKeyPrefix, v.Bytes()...) +} + +// ValidatorSigningInfoAddress - extract the address from a validator signing info key +func ValidatorSigningInfoAddress(key []byte) (v sdk.ConsAddress) { + addr := key[1:] + if len(addr) != v040auth.AddrLen { + panic("unexpected key length") + } + return sdk.ConsAddress(addr) +} + +// ValidatorMissedBlockBitArrayPrefixKey - stored by *Consensus* address (not operator address) +func ValidatorMissedBlockBitArrayPrefixKey(v sdk.ConsAddress) []byte { + return append(ValidatorMissedBlockBitArrayKeyPrefix, v.Bytes()...) +} + +// ValidatorMissedBlockBitArrayKey - stored by *Consensus* address (not operator address) +func ValidatorMissedBlockBitArrayKey(v sdk.ConsAddress, i int64) []byte { + b := make([]byte, 8) + binary.LittleEndian.PutUint64(b, uint64(i)) + return append(ValidatorMissedBlockBitArrayPrefixKey(v), b...) +} + +// AddrPubkeyRelationKey gets pubkey relation key used to get the pubkey from the address +func AddrPubkeyRelationKey(address []byte) []byte { + return append(AddrPubkeyRelationKeyPrefix, address...) +} diff --git a/x/slashing/legacy/v043/store.go b/x/slashing/legacy/v043/store.go new file mode 100644 index 0000000000..61d85d3d62 --- /dev/null +++ b/x/slashing/legacy/v043/store.go @@ -0,0 +1,20 @@ +package v043 + +import ( + sdk "github.com/line/lbm-sdk/types" + v043distribution "github.com/line/lbm-sdk/x/distribution/legacy/v043" + v040slashing "github.com/line/lbm-sdk/x/slashing/legacy/v040" +) + +// MigrateStore performs in-place store migrations from v0.40 to v0.43. The +// migration includes: +// +// - Change addresses to be length-prefixed. +func MigrateStore(ctx sdk.Context, storeKey sdk.StoreKey) error { + store := ctx.KVStore(storeKey) + v043distribution.MigratePrefixAddress(store, v040slashing.ValidatorSigningInfoKeyPrefix) + v043distribution.MigratePrefixAddressBytes(store, v040slashing.ValidatorMissedBlockBitArrayKeyPrefix) + v043distribution.MigratePrefixAddress(store, v040slashing.AddrPubkeyRelationKeyPrefix) + + return nil +} diff --git a/x/slashing/legacy/v043/store_test.go b/x/slashing/legacy/v043/store_test.go new file mode 100644 index 0000000000..ce65d0cd7a --- /dev/null +++ b/x/slashing/legacy/v043/store_test.go @@ -0,0 +1,68 @@ +package v043_test + +import ( + "bytes" + "testing" + + "github.com/stretchr/testify/require" + + "github.com/line/lbm-sdk/testutil" + "github.com/line/lbm-sdk/testutil/testdata" + sdk "github.com/line/lbm-sdk/types" + v040slashing "github.com/line/lbm-sdk/x/slashing/legacy/v040" + v043slashing "github.com/line/lbm-sdk/x/slashing/legacy/v043" + "github.com/line/lbm-sdk/x/slashing/types" +) + +func TestStoreMigration(t *testing.T) { + slashingKey := sdk.NewKVStoreKey("slashing") + ctx := testutil.DefaultContext(slashingKey, sdk.NewTransientStoreKey("transient_test")) + store := ctx.KVStore(slashingKey) + + _, _, addr1 := testdata.KeyTestPubAddr() + consAddr := sdk.ConsAddress(addr1) + // Use dummy value for all keys. + value := []byte("foo") + + testCases := []struct { + name string + oldKey []byte + newKey []byte + }{ + { + "ValidatorSigningInfoKey", + v040slashing.ValidatorSigningInfoKey(consAddr), + types.ValidatorSigningInfoKey(consAddr), + }, + { + "ValidatorMissedBlockBitArrayKey", + v040slashing.ValidatorMissedBlockBitArrayKey(consAddr, 2), + types.ValidatorMissedBlockBitArrayKey(consAddr, 2), + }, + { + "AddrPubkeyRelationKey", + v040slashing.AddrPubkeyRelationKey(consAddr.Bytes()), + types.AddrPubkeyRelationKey(consAddr.Bytes()), + }, + } + + // Set all the old keys to the store + for _, tc := range testCases { + store.Set(tc.oldKey, value) + } + + // Run migrations. + err := v043slashing.MigrateStore(ctx, slashingKey) + require.NoError(t, err) + + // Make sure the new keys are set and old keys are deleted. + for _, tc := range testCases { + tc := tc + t.Run(tc.name, func(t *testing.T) { + if !bytes.Equal(tc.oldKey, tc.newKey) { + require.Nil(t, store.Get(tc.oldKey)) + } + require.Equal(t, value, store.Get(tc.newKey)) + }) + } +} diff --git a/x/slashing/module.go b/x/slashing/module.go index 5f57650e93..c0dfb2bd90 100644 --- a/x/slashing/module.go +++ b/x/slashing/module.go @@ -35,7 +35,7 @@ var ( // AppModuleBasic defines the basic application module used by the slashing module. type AppModuleBasic struct { - cdc codec.Marshaler + cdc codec.Codec } var _ module.AppModuleBasic = AppModuleBasic{} @@ -57,12 +57,12 @@ func (b AppModuleBasic) RegisterInterfaces(registry cdctypes.InterfaceRegistry) // DefaultGenesis returns default genesis state as raw bytes for the slashing // module. -func (AppModuleBasic) DefaultGenesis(cdc codec.JSONMarshaler) json.RawMessage { +func (AppModuleBasic) DefaultGenesis(cdc codec.JSONCodec) json.RawMessage { return cdc.MustMarshalJSON(types.DefaultGenesisState()) } // ValidateGenesis performs genesis state validation for the slashing module. -func (AppModuleBasic) ValidateGenesis(cdc codec.JSONMarshaler, config client.TxEncodingConfig, bz json.RawMessage) error { +func (AppModuleBasic) ValidateGenesis(cdc codec.JSONCodec, config client.TxEncodingConfig, bz json.RawMessage) error { var data types.GenesisState if err := cdc.UnmarshalJSON(bz, &data); err != nil { return fmt.Errorf("failed to unmarshal %s genesis state: %w", types.ModuleName, err) @@ -91,8 +91,6 @@ func (AppModuleBasic) GetQueryCmd() *cobra.Command { return cli.GetQueryCmd() } -// ____________________________________________________________________________ - // AppModule implements an application module for the slashing module. type AppModule struct { AppModuleBasic @@ -104,7 +102,7 @@ type AppModule struct { } // NewAppModule creates a new AppModule object -func NewAppModule(cdc codec.Marshaler, keeper keeper.Keeper, ak types.AccountKeeper, bk types.BankKeeper, sk stakingkeeper.Keeper) AppModule { +func NewAppModule(cdc codec.Codec, keeper keeper.Keeper, ak types.AccountKeeper, bk types.BankKeeper, sk stakingkeeper.Keeper) AppModule { return AppModule{ AppModuleBasic: AppModuleBasic{cdc: cdc}, keeper: keeper, @@ -142,15 +140,15 @@ func (am AppModule) RegisterServices(cfg module.Configurator) { types.RegisterMsgServer(cfg.MsgServer(), keeper.NewMsgServerImpl(am.keeper)) types.RegisterQueryServer(cfg.QueryServer(), am.keeper) - /* m := keeper.NewMigrator(am.keeper) - if err := cfg.RegisterMigration(types.ModuleName, 1, m.Migrate1to2); err != nil { - panic(fmt.Sprintf("failed to migrate x/slashing from version 1 to 2: %v", err)) - } */ + // m := keeper.NewMigrator(am.keeper) + // if err := cfg.RegisterMigration(types.ModuleName, 1, m.Migrate1to2); err != nil { + // panic(fmt.Sprintf("failed to migrate x/slashing from version 1 to 2: %v", err)) + // } } // InitGenesis performs genesis initialization for the slashing module. It returns // no validator updates. -func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONMarshaler, data json.RawMessage) []abci.ValidatorUpdate { +func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONCodec, data json.RawMessage) []abci.ValidatorUpdate { var genesisState types.GenesisState cdc.MustUnmarshalJSON(data, &genesisState) InitGenesis(ctx, am.keeper, am.stakingKeeper, &genesisState) @@ -159,7 +157,7 @@ func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONMarshaler, data j // ExportGenesis returns the exported genesis state as raw bytes for the slashing // module. -func (am AppModule) ExportGenesis(ctx sdk.Context, cdc codec.JSONMarshaler) json.RawMessage { +func (am AppModule) ExportGenesis(ctx sdk.Context, cdc codec.JSONCodec) json.RawMessage { gs := ExportGenesis(ctx, am.keeper) return cdc.MustMarshalJSON(gs) } @@ -178,8 +176,6 @@ func (AppModule) EndBlock(_ sdk.Context, _ abci.RequestEndBlock) []abci.Validato return []abci.ValidatorUpdate{} } -// ____________________________________________________________________________ - // AppModuleSimulation functions // GenerateGenesisState creates a randomized GenState of the slashing module. diff --git a/x/slashing/simulation/decoder.go b/x/slashing/simulation/decoder.go index 4819b6c089..c4c41020f7 100644 --- a/x/slashing/simulation/decoder.go +++ b/x/slashing/simulation/decoder.go @@ -7,32 +7,37 @@ import ( gogotypes "github.com/gogo/protobuf/types" "github.com/line/lbm-sdk/codec" + cryptotypes "github.com/line/lbm-sdk/crypto/types" "github.com/line/lbm-sdk/types/kv" "github.com/line/lbm-sdk/x/slashing/types" ) // NewDecodeStore returns a decoder function closure that unmarshals the KVPair's // Value to the corresponding slashing type. -func NewDecodeStore(cdc codec.Marshaler) func(kvA, kvB kv.Pair) string { +func NewDecodeStore(cdc codec.BinaryCodec) func(kvA, kvB kv.Pair) string { return func(kvA, kvB kv.Pair) string { switch { case bytes.Equal(kvA.Key[:1], types.ValidatorSigningInfoKeyPrefix): var infoA, infoB types.ValidatorSigningInfo - cdc.MustUnmarshalBinaryBare(kvA.Value, &infoA) - cdc.MustUnmarshalBinaryBare(kvB.Value, &infoB) + cdc.MustUnmarshal(kvA.Value, &infoA) + cdc.MustUnmarshal(kvB.Value, &infoB) return fmt.Sprintf("%v\n%v", infoA, infoB) case bytes.Equal(kvA.Key[:1], types.ValidatorMissedBlockBitArrayKeyPrefix): var missedA, missedB gogotypes.BoolValue - cdc.MustUnmarshalBinaryBare(kvA.Value, &missedA) - cdc.MustUnmarshalBinaryBare(kvB.Value, &missedB) + cdc.MustUnmarshal(kvA.Value, &missedA) + cdc.MustUnmarshal(kvB.Value, &missedB) return fmt.Sprintf("missedA: %v\nmissedB: %v", missedA.Value, missedB.Value) case bytes.Equal(kvA.Key[:1], types.AddrPubkeyRelationKeyPrefix): - var pubKeyA, pubKeyB gogotypes.StringValue - cdc.MustUnmarshalBinaryBare(kvA.Value, &pubKeyA) - cdc.MustUnmarshalBinaryBare(kvB.Value, &pubKeyB) - return fmt.Sprintf("PubKeyA: %s\nPubKeyB: %s", pubKeyA.Value, pubKeyB.Value) + var pubKeyA, pubKeyB cryptotypes.PubKey + if err := cdc.UnmarshalInterface(kvA.Value, &pubKeyA); err != nil { + panic(fmt.Sprint("Can't unmarshal kvA; ", err)) + } + if err := cdc.UnmarshalInterface(kvB.Value, &pubKeyB); err != nil { + panic(fmt.Sprint("Can't unmarshal kvB; ", err)) + } + return fmt.Sprintf("PubKeyA: %s\nPubKeyB: %s", pubKeyA, pubKeyB) default: panic(fmt.Sprintf("invalid slashing key prefix %X", kvA.Key[:1])) diff --git a/x/slashing/simulation/decoder_test.go b/x/slashing/simulation/decoder_test.go index b6297d3208..c4a3033840 100644 --- a/x/slashing/simulation/decoder_test.go +++ b/x/slashing/simulation/decoder_test.go @@ -25,38 +25,39 @@ var ( ) func TestDecodeStore(t *testing.T) { - cdc, _ := simapp.MakeCodecs() + cdc := simapp.MakeTestEncodingConfig().Marshaler dec := simulation.NewDecodeStore(cdc) info := types.NewValidatorSigningInfo(consAddr1, time.Now().UTC(), false, 0, 1) - bechPK := sdk.MustBech32ifyPubKey(sdk.Bech32PubKeyTypeConsPub, delPk1) missed := gogotypes.BoolValue{Value: true} + bz, err := cdc.MarshalInterface(delPk1) + require.NoError(t, err) kvPairs := kv.Pairs{ Pairs: []kv.Pair{ - {Key: types.ValidatorSigningInfoKey(consAddr1), Value: cdc.MustMarshalBinaryBare(&info)}, - {Key: types.ValidatorMissedBlockBitArrayKey(consAddr1, 6), Value: cdc.MustMarshalBinaryBare(&missed)}, - {Key: types.AddrPubkeyRelationKey(delAddr1.Bytes()), Value: cdc.MustMarshalBinaryBare(&gogotypes.StringValue{Value: bechPK})}, - {Key: []byte{0x99}, Value: []byte{0x99}}, + {Key: types.ValidatorSigningInfoKey(consAddr1), Value: cdc.MustMarshal(&info)}, + {Key: types.ValidatorMissedBlockBitArrayKey(consAddr1, 6), Value: cdc.MustMarshal(&missed)}, + {Key: types.AddrPubkeyRelationKey(delAddr1.Bytes()), Value: bz}, + {Key: []byte{0x99}, Value: []byte{0x99}}, // This test should panic }, } tests := []struct { name string expectedLog string + panics bool }{ - {"ValidatorSigningInfo", fmt.Sprintf("%v\n%v", info, info)}, - {"ValidatorMissedBlockBitArray", fmt.Sprintf("missedA: %v\nmissedB: %v", missed.Value, missed.Value)}, - {"AddrPubkeyRelation", fmt.Sprintf("PubKeyA: %s\nPubKeyB: %s", bechPK, bechPK)}, - {"other", ""}, + {"ValidatorSigningInfo", fmt.Sprintf("%v\n%v", info, info), false}, + {"ValidatorMissedBlockBitArray", fmt.Sprintf("missedA: %v\nmissedB: %v", missed.Value, missed.Value), false}, + {"AddrPubkeyRelation", fmt.Sprintf("PubKeyA: %s\nPubKeyB: %s", delPk1, delPk1), false}, + {"other", "", true}, } for i, tt := range tests { i, tt := i, tt t.Run(tt.name, func(t *testing.T) { - switch i { - case len(tests) - 1: + if tt.panics { require.Panics(t, func() { dec(kvPairs.Pairs[i], kvPairs.Pairs[i]) }, tt.name) - default: + } else { require.Equal(t, tt.expectedLog, dec(kvPairs.Pairs[i], kvPairs.Pairs[i]), tt.name) } }) diff --git a/x/slashing/simulation/operations.go b/x/slashing/simulation/operations.go index eae6add410..0419f821bf 100644 --- a/x/slashing/simulation/operations.go +++ b/x/slashing/simulation/operations.go @@ -16,6 +16,7 @@ import ( stakingkeeper "github.com/line/lbm-sdk/x/staking/keeper" ) +// nolint: gosec // Simulation operation weights constants const ( OpWeightMsgUnjail = "op_weight_msg_unjail" @@ -23,7 +24,7 @@ const ( // WeightedOperations returns all the operations from the module with their respective weights func WeightedOperations( - appParams simtypes.AppParams, cdc codec.JSONMarshaler, ak types.AccountKeeper, + appParams simtypes.AppParams, cdc codec.JSONCodec, ak types.AccountKeeper, bk types.BankKeeper, k keeper.Keeper, sk stakingkeeper.Keeper, ) simulation.WeightedOperations { @@ -114,23 +115,23 @@ func SimulateMsgUnjail(ak types.AccountKeeper, bk types.BankKeeper, k keeper.Kee validator.TokensFromShares(selfDel.GetShares()).TruncateInt().LT(validator.GetMinSelfDelegation()) { if res != nil && err == nil { if info.Tombstoned { - return simtypes.NewOperationMsg(msg, true, ""), nil, errors.New("validator should not have been unjailed if validator tombstoned") + return simtypes.NewOperationMsg(msg, true, "", nil), nil, errors.New("validator should not have been unjailed if validator tombstoned") } if ctx.BlockHeader().Time.Before(info.JailedUntil) { - return simtypes.NewOperationMsg(msg, true, ""), nil, errors.New("validator unjailed while validator still in jail period") + return simtypes.NewOperationMsg(msg, true, "", nil), nil, errors.New("validator unjailed while validator still in jail period") } if validator.TokensFromShares(selfDel.GetShares()).TruncateInt().LT(validator.GetMinSelfDelegation()) { - return simtypes.NewOperationMsg(msg, true, ""), nil, errors.New("validator unjailed even though self-delegation too low") + return simtypes.NewOperationMsg(msg, true, "", nil), nil, errors.New("validator unjailed even though self-delegation too low") } } // msg failed as expected - return simtypes.NewOperationMsg(msg, false, ""), nil, nil + return simtypes.NewOperationMsg(msg, false, "", nil), nil, nil } if err != nil { return simtypes.NoOpMsg(types.ModuleName, msg.Type(), "unable to deliver tx"), nil, err } - return simtypes.NewOperationMsg(msg, true, ""), nil, nil + return simtypes.NewOperationMsg(msg, true, "", nil), nil, nil } } diff --git a/x/slashing/simulation/operations_test.go b/x/slashing/simulation/operations_test.go index 699e0a76f6..47811b122a 100644 --- a/x/slashing/simulation/operations_test.go +++ b/x/slashing/simulation/operations_test.go @@ -77,7 +77,7 @@ func TestSimulateMsgUnjail(t *testing.T) { app.StakingKeeper.Jail(ctx, val0ConsAddress) // setup self delegation - delTokens := sdk.TokensFromConsensusPower(2) + delTokens := app.StakingKeeper.TokensFromConsensusPower(ctx, 2) validator0, issuedShares := validator0.AddTokensFromDel(delTokens) val0AccAddress := sdk.ValAddress(validator0.OperatorAddress).ToAccAddress() require.NoError(t, err) @@ -116,15 +116,14 @@ func createTestApp(isCheckTx bool) (*simapp.SimApp, sdk.Context) { func getTestingAccounts(t *testing.T, r *rand.Rand, app *simapp.SimApp, ctx sdk.Context, n int) []simtypes.Account { accounts := simtypes.RandomAccounts(r, n) - initAmt := sdk.TokensFromConsensusPower(200) + initAmt := app.StakingKeeper.TokensFromConsensusPower(ctx, 200) initCoins := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, initAmt)) // add coins to the accounts for _, account := range accounts { acc := app.AccountKeeper.NewAccountWithAddress(ctx, account.Address) app.AccountKeeper.SetAccount(ctx, acc) - err := app.BankKeeper.SetBalances(ctx, account.Address, initCoins) - require.NoError(t, err) + require.NoError(t, simapp.FundAccount(app, ctx, account.Address, initCoins)) } return accounts diff --git a/x/slashing/spec/02_state.md b/x/slashing/spec/02_state.md index ff83537b51..b296105fec 100644 --- a/x/slashing/spec/02_state.md +++ b/x/slashing/spec/02_state.md @@ -10,9 +10,16 @@ Every block includes a set of precommits by the validators for the previous bloc known as the `LastCommitInfo` provided by Tendermint. A `LastCommitInfo` is valid so long as it contains precommits from +2/3 of total voting power. -Proposers are incentivized to include precommits from all validators in the `LastCommitInfo` +Proposers are incentivized to include precommits from all validators in the Tendermint `LastCommitInfo` by receiving additional fees proportional to the difference between the voting -power included in the `LastCommitInfo` and +2/3 (see [TODO](https://github.com/cosmos/cosmos-sdk/issues/967)). +power included in the `LastCommitInfo` and +2/3 (see [fee distribution](x/distribution/spec/03_begin_block.md)). + +``` +type LastCommitInfo struct { + Round int32 + Votes []VoteInfo +} +``` Validators are penalized for failing to be included in the `LastCommitInfo` for some number of blocks by being automatically jailed, potentially slashed, and unbonded. @@ -20,15 +27,16 @@ number of blocks by being automatically jailed, potentially slashed, and unbonde Information about validator's liveness activity is tracked through `ValidatorSigningInfo`. It is indexed in the store as follows: -- ValidatorSigningInfo: ` 0x01 | ConsAddrLen (1 byte) | ConsAddress -> ProtocolBuffer(ValSigningInfo)` -- MissedBlocksBitArray: ` 0x02 | ConsAddrLen (1 byte) | ConsAddress | LittleEndianUint64(signArrayIndex) -> VarInt(didMiss)` (varint is a number encoding format) +- ValidatorSigningInfo: `0x01 | ConsAddrLen (1 byte) | ConsAddress -> ProtocolBuffer(ValSigningInfo)` +- MissedBlocksBitArray: `0x02 | ConsAddrLen (1 byte) | ConsAddress | LittleEndianUint64(signArrayIndex) -> VarInt(didMiss)` (varint is a number encoding format) The first mapping allows us to easily lookup the recent signing info for a -validator based on the validator's consensus address. The second mapping acts +validator based on the validator's consensus address. + +The second mapping (`MissedBlocksBitArray`) acts as a bit-array of size `SignedBlocksWindow` that tells us if the validator missed the block for a given index in the bit-array. The index in the bit-array is given as little endian uint64. - The result is a `varint` that takes on `0` or `1`, where `0` indicates the validator did not miss (did sign) the corresponding block, and `1` indicates they missed the block (did not sign). @@ -40,31 +48,4 @@ bonded validator. The `SignedBlocksWindow` parameter defines the size The information stored for tracking validator liveness is as follows: -```protobuf -// ValidatorSigningInfo defines a validator's signing info for monitoring their -// liveness activity. -message ValidatorSigningInfo { - string address = 1; - // timestamp validator cannot be unjailed until - google.protobuf.Timestamp jailed_until = 2; - // whether or not a validator has been tombstoned (killed out of validator - // set) - bool tombstoned = 3; - // missed blocks counter (to avoid scanning the array every time) - int64 missed_blocks_counter = 4; - // how many times the validator joined to voter set - int64 voter_set_counter = 5; -} -``` - -Where: - -- **Address**: The validator's consensus address. -- **JailedUntil**: Time for which the validator is jailed until due to liveness downtime. -- **Tombstoned**: Desribes if the validator is tombstoned or not. It is set once the - validator commits an equivocation or for any other configured misbehiavor. -- **MissedBlocksCounter**: A counter kept to avoid unnecessary array reads. Note - that `Sum(MissedBlocksBitArray)` equals `MissedBlocksCounter` always. -- **VoterSetCounter**: A counter keeps tracking the number of incidents the validator - joins to the voter set. This in conjunction with the `SignedBlocksWindow` param - determines the index in the `MissedBlocksBitArray`. ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/slashing/v1beta1/slashing.proto#L11-L33 diff --git a/x/slashing/spec/03_messages.md b/x/slashing/spec/03_messages.md index 6e7d168ffd..d680b83cdf 100644 --- a/x/slashing/spec/03_messages.md +++ b/x/slashing/spec/03_messages.md @@ -20,14 +20,17 @@ message MsgUnjail { } ``` -And below is its corresponding handler: +Below is a pseudocode of the `MsgSrv/Unjail` RPC: ``` -handleMsgUnjail(tx MsgUnjail) +unjail(tx MsgUnjail) validator = getValidator(tx.ValidatorAddr) if validator == nil fail with "No validator found" + if getSelfDelegation(validator) == 0 + fail with "validator must self delegate before unjailing" + if !validator.Jailed fail with "Validator not jailed, cannot unjail" @@ -43,6 +46,6 @@ handleMsgUnjail(tx MsgUnjail) return ``` -If the validator has enough stake to be in the top `n = MaximumBondedValidators`, they will be automatically rebonded, +If the validator has enough stake to be in the top `n = MaximumBondedValidators`, it will be automatically rebonded, and all delegators still delegated to the validator will be rebonded and begin to again collect provisions and rewards. diff --git a/x/slashing/spec/05_hooks.md b/x/slashing/spec/05_hooks.md index d87f6d289a..5a5ff6f2d1 100644 --- a/x/slashing/spec/05_hooks.md +++ b/x/slashing/spec/05_hooks.md @@ -4,7 +4,17 @@ order: 5 # Hooks -In this section we describe the "hooks" - slashing module code that runs when other events happen. +This section contains a description of the module's `hooks`. Hooks are operations that are executed automatically when events are raised. + +## Staking hooks + +The slashing module implements the `StakingHooks` defined in `x/staking` and are used as record-keeping of validators information. During the app initialization, these hooks should be registered in the staking module struct. + +The following hooks impact the slashing state: + ++ `AfterValidatorBonded` creates a `ValidatorSigningInfo` instance as described in the following section. ++ `AfterValidatorCreated` stores a validator's consensus key. ++ `AfterValidatorRemoved` removes a validator's consensus key. ## Validator Bonded diff --git a/x/slashing/spec/06_events.md b/x/slashing/spec/06_events.md index c5fceda519..8f259ae46c 100644 --- a/x/slashing/spec/06_events.md +++ b/x/slashing/spec/06_events.md @@ -6,7 +6,18 @@ order: 6 The slashing module emits the following events/tags: -## BeginBlocker +## MsgServer + +### MsgUnjail + +| Type | Attribute Key | Attribute Value | +| ------- | ------------- | --------------- | +| message | module | slashing | +| message | sender | {validatorAddress} | + +## Keeper + +## BeginBlocker: HandleValidatorSignature | Type | Attribute Key | Attribute Value | | ----- | ------------- | --------------------------- | @@ -23,12 +34,12 @@ The slashing module emits the following events/tags: | liveness | missed_blocks | {missedBlocksCounter} | | liveness | height | {blockHeight} | -## Handlers +### Slash -### MsgUnjail ++ same as `"slash"` event from `HandleValidatorSignature`, but without the `jailed` attribute. -| Type | Attribute Key | Attribute Value | -| ------- | ------------- | --------------- | -| message | module | slashing | -| message | action | unjail | -| message | sender | {senderAddress} | +### Jail + +| Type | Attribute Key | Attribute Value | +| ----- | ------------- | ------------------ | +| slash | jailed | {validatorAddress} | diff --git a/x/slashing/spec/07_tombstone.md b/x/slashing/spec/07_tombstone.md index 4759a89b71..216d1836f5 100644 --- a/x/slashing/spec/07_tombstone.md +++ b/x/slashing/spec/07_tombstone.md @@ -87,15 +87,17 @@ Currently, in the jail period implementation, once a validator unjails, all of their delegators who are delegated to them (haven't unbonded / redelegated away), stay with them. Given that consensus safety faults are so egregious (way more so than liveness faults), it is probably prudent to have delegators not -"auto-rebond" to the validator. Thus, we propose setting the "jail time" for a +"auto-rebond" to the validator. + +### Proposal: infinite jail + +We propose setting the "jail time" for a validator who commits a consensus safety fault, to `infinite` (i.e. a tombstone state). This essentially kicks the validator out of the validator set and does not allow them to re-enter the validator set. All of their delegators (including the operator themselves) have to either unbond or redelegate away. The validator operator can create a new validator if they would like, with a new operator key and consensus key, but they -have to "re-earn" their delegations back. To put the validator in the tombstone -state, we set `DoubleSignJailEndTime` to `time.Unix(253402300800)`, the maximum -time supported by Amino. +have to "re-earn" their delegations back. Implementing the tombstone system and getting rid of the slashing period tracking will make the `slashing` module way simpler, especially because we can remove all diff --git a/x/slashing/spec/08_params.md b/x/slashing/spec/08_params.md index 0ebfb9e27e..defed189ab 100644 --- a/x/slashing/spec/08_params.md +++ b/x/slashing/spec/08_params.md @@ -6,10 +6,10 @@ order: 8 The slashing module contains the following parameters: -| Key | Type | Example | -| ----------------------- | ---------------- | ---------------------- | -| SignedBlocksWindow | string (int64) | "100" | -| MinSignedPerWindow | string (dec) | "0.500000000000000000" | -| DowntimeJailDuration | string (time ns) | "600000000000" | -| SlashFractionDoubleSign | string (dec) | "0.050000000000000000" | -| SlashFractionDowntime | string (dec) | "0.010000000000000000" | +| Key | Type | Example | +| ----------------------- | -------------- | ---------------------- | +| SignedBlocksWindow | string (int64) | "100" | +| MinSignedPerWindow | string (dec) | "0.500000000000000000" | +| DowntimeJailDuration | string (ns) | "600000000000" | +| SlashFractionDoubleSign | string (dec) | "0.050000000000000000" | +| SlashFractionDowntime | string (dec) | "0.010000000000000000" | diff --git a/x/slashing/spec/09_client.md b/x/slashing/spec/09_client.md new file mode 100644 index 0000000000..fd5b2030fe --- /dev/null +++ b/x/slashing/spec/09_client.md @@ -0,0 +1,294 @@ + + +# CLI + +A user can query and interact with the `slashing` module using the CLI. + +### Query + +The `query` commands allow users to query `slashing` state. + +```bash +simd query slashing --help +``` + +#### params + +The `params` command allows users to query genesis parameters for the slashing module. + +```bash +simd query slashing params [flags] +``` + +Example: + +```bash +simd query slashing params +``` + +Example Output: + +```bash +downtime_jail_duration: 600s +min_signed_per_window: "0.500000000000000000" +signed_blocks_window: "100" +slash_fraction_double_sign: "0.050000000000000000" +slash_fraction_downtime: "0.010000000000000000" +``` + +#### signing-info + +The `signing-info` command allows users to query signing-info of the validator using consensus public key. + +```bash +simd query slashing signing-infos [flags] +``` + +Example: + +```bash +simd query slashing signing-info '{"@type":"/cosmos.crypto.ed25519.PubKey","key":"Auxs3865HpB/EfssYOzfqNhEJjzys6jD5B6tPgC8="}' + +``` + +Example Output: + +```bash +address: cosmosvalcons1nrqsld3aw6lh6t082frdqc84uwxn0t958c +index_offset: "2068" +jailed_until: "1970-01-01T00:00:00Z" +missed_blocks_counter: "0" +start_height: "0" +tombstoned: false +``` + +#### signing-infos + +The `signing-infos` command allows users to query signing infos of all validators. + +```bash +simd query slashing signing-infos [flags] +``` + +Example: + +```bash +simd query slashing signing-infos +``` + +Example Output: + +```bash +info: +- address: cosmosvalcons1nrqsld3aw6lh6t082frdqc84uwxn0t958c + index_offset: "2075" + jailed_until: "1970-01-01T00:00:00Z" + missed_blocks_counter: "0" + start_height: "0" + tombstoned: false +pagination: + next_key: null + total: "0" +``` + +### Transactions + +The `tx` commands allow users to interact with the `slashing` module. + +```bash +simd tx slashing --help +``` + +#### unjail + +The `unjail` command allows users to unjail a validator previously jailed for downtime. + +```bash + simd tx slashing unjail --from mykey [flags] +``` + +Example: + +```bash +simd tx slashing unjail --from mykey +``` + +## gRPC + +A user can query the `slashing` module using gRPC endpoints. + +### Params + +The `Params` endpoint allows users to query the parameters of slashing module. + +```bash +cosmos.slashing.v1beta1.Query/Params +``` + +Example: + +```bash +grpcurl -plaintext localhost:9090 cosmos.slashing.v1beta1.Query/Params +``` + +Example Output: + +```bash +{ + "params": { + "signedBlocksWindow": "100", + "minSignedPerWindow": "NTAwMDAwMDAwMDAwMDAwMDAw", + "downtimeJailDuration": "600s", + "slashFractionDoubleSign": "NTAwMDAwMDAwMDAwMDAwMDA=", + "slashFractionDowntime": "MTAwMDAwMDAwMDAwMDAwMDA=" + } +} +``` + +### SigningInfo + +The SigningInfo queries the signing info of given cons address. + +```bash +cosmos.slashing.v1beta1.Query/SigningInfo +``` + +Example: + +```bash +grpcurl -plaintext -d '{"cons_address":"cosmosvalcons1nrqsld3aw6lh6t082frdqc84uwxn0t958c"}' localhost:9090 cosmos.slashing.v1beta1.Query/SigningInfo +``` + +Example Output: + +```bash +{ + "valSigningInfo": { + "address": "cosmosvalcons1nrqsld3aw6lh6t082frdqc84uwxn0t958c", + "indexOffset": "3493", + "jailedUntil": "1970-01-01T00:00:00Z" + } +} +``` + +### SigningInfos + +The SigningInfos queries signing info of all validators. + +```bash +cosmos.slashing.v1beta1.Query/SigningInfos +``` + +Example: + +```bash +grpcurl -plaintext localhost:9090 cosmos.slashing.v1beta1.Query/SigningInfos +``` + +Example Output: + +```bash +{ + "info": [ + { + "address": "cosmosvalcons1nrqslkwd3pz096lh6t082frdqc84uwxn0t958c", + "indexOffset": "2467", + "jailedUntil": "1970-01-01T00:00:00Z" + } + ], + "pagination": { + "total": "1" + } +} +``` + +## REST + +A user can query the `slashing` module using REST endpoints. + +### Params + +```bash +/cosmos/slashing/v1beta1/params +``` + +Example: + +```bash +curl "localhost:1317/cosmos/slashing/v1beta1/params" +``` + +Example Output: + +```bash +{ + "params": { + "signed_blocks_window": "100", + "min_signed_per_window": "0.500000000000000000", + "downtime_jail_duration": "600s", + "slash_fraction_double_sign": "0.050000000000000000", + "slash_fraction_downtime": "0.010000000000000000" +} +``` + +### signing_info + +```bash +/cosmos/slashing/v1beta1/signing_infos/%s +``` + +Example: + +```bash +curl "localhost:1317/cosmos/slashing/v1beta1/signing_infos/cosmosvalcons1nrqslkwd3pz096lh6t082frdqc84uwxn0t958c" +``` + +Example Output: + +```bash +{ + "val_signing_info": { + "address": "cosmosvalcons1nrqslkwd3pz096lh6t082frdqc84uwxn0t958c", + "start_height": "0", + "index_offset": "4184", + "jailed_until": "1970-01-01T00:00:00Z", + "tombstoned": false, + "missed_blocks_counter": "0" + } +} +``` + +### signing_infos + +```bash +/cosmos/slashing/v1beta1/signing_infos +``` + +Example: + +```bash +curl "localhost:1317/cosmos/slashing/v1beta1/signing_infos +``` + +Example Output: + +```bash +{ + "info": [ + { + "address": "cosmosvalcons1nrqslkwd3pz096lh6t082frdqc84uwxn0t958c", + "start_height": "0", + "index_offset": "4169", + "jailed_until": "1970-01-01T00:00:00Z", + "tombstoned": false, + "missed_blocks_counter": "0" + } + ], + "pagination": { + "next_key": null, + "total": "1" + } +} +``` diff --git a/x/slashing/spec/README.md b/x/slashing/spec/README.md index 2263065623..b67c6f7c7d 100644 --- a/x/slashing/spec/README.md +++ b/x/slashing/spec/README.md @@ -43,3 +43,7 @@ This module will be used by the Cosmos Hub, the first hub in the Cosmos ecosyste 7. **[Staking Tombstone](07_tombstone.md)** - [Abstract](07_tombstone.md#abstract) 8. **[Parameters](08_params.md)** +9. **[Client](09_client.md)** + - [CLI](09_client.md#cli) + - [gRPC](09_client.md#grpc) + - [REST](09_client.md#rest) diff --git a/x/slashing/types/events.go b/x/slashing/types/events.go index 2e7eca79e9..e9fb254545 100644 --- a/x/slashing/types/events.go +++ b/x/slashing/types/events.go @@ -1,4 +1,3 @@ -// noalias package types // Slashing module event types diff --git a/x/slashing/types/expected_keepers.go b/x/slashing/types/expected_keepers.go index 06656b2910..d78c3252dd 100644 --- a/x/slashing/types/expected_keepers.go +++ b/x/slashing/types/expected_keepers.go @@ -19,7 +19,6 @@ type AccountKeeper interface { type BankKeeper interface { GetAllBalances(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins GetBalance(ctx sdk.Context, addr sdk.AccAddress, denom string) sdk.Coin - SetBalances(ctx sdk.Context, addr sdk.AccAddress, balances sdk.Coins) error LockedCoins(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins SpendableCoins(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins } @@ -27,7 +26,7 @@ type BankKeeper interface { // ParamSubspace defines the expected Subspace interfacace type ParamSubspace interface { HasKeyTable() bool - WithKeyTable(table paramtypes.KeyTable) *paramtypes.Subspace + WithKeyTable(table paramtypes.KeyTable) paramtypes.Subspace Get(ctx sdk.Context, key []byte, ptr interface{}) GetParamSet(ctx sdk.Context, ps paramtypes.ParamSet) SetParamSet(ctx sdk.Context, ps paramtypes.ParamSet) diff --git a/x/slashing/types/genesis.go b/x/slashing/types/genesis.go index f3b0b44c3a..eb40b3ab01 100644 --- a/x/slashing/types/genesis.go +++ b/x/slashing/types/genesis.go @@ -55,7 +55,7 @@ func ValidateGenesis(data GenesisState) error { downtimeJail := data.Params.DowntimeJailDuration if downtimeJail < 1*time.Minute { - return fmt.Errorf("downtime unblond duration must be at least 1 minute, is %s", downtimeJail.String()) + return fmt.Errorf("downtime unjail duration must be at least 1 minute, is %s", downtimeJail.String()) } signedWindow := data.Params.SignedBlocksWindow diff --git a/x/slashing/types/genesis.pb.go b/x/slashing/types/genesis.pb.go index 31a410addb..8a9611ef40 100644 --- a/x/slashing/types/genesis.pb.go +++ b/x/slashing/types/genesis.pb.go @@ -30,7 +30,7 @@ type GenesisState struct { // signing_infos represents a map between validator addresses and their // signing infos. SigningInfos []SigningInfo `protobuf:"bytes,2,rep,name=signing_infos,json=signingInfos,proto3" json:"signing_infos" yaml:"signing_infos"` - // signing_infos represents a map between validator addresses and their + // missed_blocks represents a map between validator addresses and their // missed blocks. MissedBlocks []ValidatorMissedBlocks `protobuf:"bytes,3,rep,name=missed_blocks,json=missedBlocks,proto3" json:"missed_blocks" yaml:"missed_blocks"` } diff --git a/x/slashing/types/keys.go b/x/slashing/types/keys.go index b85111c82d..4894b7851c 100644 --- a/x/slashing/types/keys.go +++ b/x/slashing/types/keys.go @@ -4,6 +4,7 @@ import ( "encoding/binary" sdk "github.com/line/lbm-sdk/types" + "github.com/line/lbm-sdk/types/address" ) const ( @@ -23,11 +24,11 @@ const ( // Keys for slashing store // Items are stored with the following key: values // -// - 0x01: ValidatorSigningInfo +// - 0x01: ValidatorSigningInfo // -// - 0x02: bool +// - 0x02: bool // -// - 0x03: crypto.PubKey +// - 0x03: cryptotypes.PubKey var ( ValidatorSigningInfoKeyPrefix = []byte{0x01} // Prefix for signing info ValidatorMissedBlockBitArrayKeyPrefix = []byte{0x02} // Prefix for missed block bit array @@ -36,28 +37,31 @@ var ( // ValidatorSigningInfoKey - stored by *Consensus* address (not operator address) func ValidatorSigningInfoKey(v sdk.ConsAddress) []byte { - return append(ValidatorSigningInfoKeyPrefix, v.Bytes()...) + return append(ValidatorSigningInfoKeyPrefix, address.MustLengthPrefix(v.Bytes())...) } // ValidatorSigningInfoAddress - extract the address from a validator signing info key func ValidatorSigningInfoAddress(key []byte) (v sdk.ConsAddress) { - addr := key[1:] + // Remove prefix and address length. + addr := key[2:] + return sdk.ConsAddress(addr) } // ValidatorMissedBlockBitArrayPrefixKey - stored by *Consensus* address (not operator address) func ValidatorMissedBlockBitArrayPrefixKey(v sdk.ConsAddress) []byte { - return append(ValidatorMissedBlockBitArrayKeyPrefix, v.Bytes()...) + return append(ValidatorMissedBlockBitArrayKeyPrefix, address.MustLengthPrefix(v.Bytes())...) } // ValidatorMissedBlockBitArrayKey - stored by *Consensus* address (not operator address) func ValidatorMissedBlockBitArrayKey(v sdk.ConsAddress, i int64) []byte { b := make([]byte, 8) binary.LittleEndian.PutUint64(b, uint64(i)) + return append(ValidatorMissedBlockBitArrayPrefixKey(v), b...) } // AddrPubkeyRelationKey gets pubkey relation key used to get the pubkey from the address -func AddrPubkeyRelationKey(address []byte) []byte { - return append(AddrPubkeyRelationKeyPrefix, address...) +func AddrPubkeyRelationKey(addr []byte) []byte { + return append(AddrPubkeyRelationKeyPrefix, address.MustLengthPrefix(addr)...) } diff --git a/x/slashing/types/query.pb.gw.go b/x/slashing/types/query.pb.gw.go index 434844cc2e..fba71ec48f 100644 --- a/x/slashing/types/query.pb.gw.go +++ b/x/slashing/types/query.pb.gw.go @@ -310,11 +310,11 @@ func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, clie } var ( - pattern_Query_Params_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"lbm", "slashing", "v1", "params"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_Query_Params_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"lbm", "slashing", "v1", "params"}, "", runtime.AssumeColonVerbOpt(false))) - pattern_Query_SigningInfo_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4}, []string{"lbm", "slashing", "v1", "signing_infos", "cons_address"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_Query_SigningInfo_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4}, []string{"lbm", "slashing", "v1", "signing_infos", "cons_address"}, "", runtime.AssumeColonVerbOpt(false))) - pattern_Query_SigningInfos_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"lbm", "slashing", "v1", "signing_infos"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_Query_SigningInfos_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"lbm", "slashing", "v1", "signing_infos"}, "", runtime.AssumeColonVerbOpt(false))) ) var ( diff --git a/x/slashing/types/signing_info.go b/x/slashing/types/signing_info.go index 53118d0682..2106109f9c 100644 --- a/x/slashing/types/signing_info.go +++ b/x/slashing/types/signing_info.go @@ -37,7 +37,7 @@ func (i ValidatorSigningInfo) String() string { } // unmarshal a validator signing info from a store value -func UnmarshalValSigningInfo(cdc codec.Marshaler, value []byte) (signingInfo ValidatorSigningInfo, err error) { - err = cdc.UnmarshalBinaryBare(value, &signingInfo) +func UnmarshalValSigningInfo(cdc codec.Codec, value []byte) (signingInfo ValidatorSigningInfo, err error) { + err = cdc.Unmarshal(value, &signingInfo) return signingInfo, err } diff --git a/x/staking/app_test.go b/x/staking/app_test.go index e320b0871d..fdbf2abbe7 100644 --- a/x/staking/app_test.go +++ b/x/staking/app_test.go @@ -40,8 +40,8 @@ func checkDelegation( } func TestStakingMsgs(t *testing.T) { - genTokens := sdk.TokensFromConsensusPower(42) - bondTokens := sdk.TokensFromConsensusPower(10) + genTokens := sdk.TokensFromConsensusPower(42, sdk.DefaultPowerReduction) + bondTokens := sdk.TokensFromConsensusPower(10, sdk.DefaultPowerReduction) genCoin := sdk.NewCoin(sdk.DefaultBondDenom, genTokens) bondCoin := sdk.NewCoin(sdk.DefaultBondDenom, bondTokens) diff --git a/x/staking/bench_test.go b/x/staking/bench_test.go new file mode 100644 index 0000000000..f648f0fe37 --- /dev/null +++ b/x/staking/bench_test.go @@ -0,0 +1,56 @@ +package staking_test + +import ( + "testing" + + "github.com/line/lbm-sdk/crypto/keys/ed25519" + sdk "github.com/line/lbm-sdk/types" + "github.com/line/lbm-sdk/x/staking" + "github.com/line/lbm-sdk/x/staking/teststaking" + "github.com/line/lbm-sdk/x/staking/types" +) + +func BenchmarkValidateGenesis10Validators(b *testing.B) { + benchmarkValidateGenesis(b, 10) +} + +func BenchmarkValidateGenesis100Validators(b *testing.B) { + benchmarkValidateGenesis(b, 100) +} + +func BenchmarkValidateGenesis400Validators(b *testing.B) { + benchmarkValidateGenesis(b, 400) +} + +func benchmarkValidateGenesis(b *testing.B, n int) { + b.ReportAllocs() + + validators := make([]types.Validator, 0, n) + addressL, pubKeyL := makeRandomAddressesAndPublicKeys(n) + for i := 0; i < n; i++ { + addr, pubKey := addressL[i], pubKeyL[i] + validator := teststaking.NewValidator(b, addr, pubKey) + ni := int64(i + 1) + validator.Tokens = sdk.NewInt(ni) + validator.DelegatorShares = sdk.NewDec(ni) + validators = append(validators, validator) + } + + b.ResetTimer() + for i := 0; i < b.N; i++ { + genesisState := types.DefaultGenesisState() + genesisState.Validators = validators + if err := staking.ValidateGenesis(genesisState); err != nil { + b.Fatal(err) + } + } +} + +func makeRandomAddressesAndPublicKeys(n int) (accL []sdk.ValAddress, pkL []*ed25519.PubKey) { + for i := 0; i < n; i++ { + pk := ed25519.GenPrivKey().PubKey().(*ed25519.PubKey) + pkL = append(pkL, pk) + accL = append(accL, sdk.ValAddress(pk.Address())) + } + return accL, pkL +} diff --git a/x/staking/client/cli/flags.go b/x/staking/client/cli/flags.go index e2521e9c82..b320c91a19 100644 --- a/x/staking/client/cli/flags.go +++ b/x/staking/client/cli/flags.go @@ -75,7 +75,7 @@ func FlagSetAmount() *flag.FlagSet { // FlagSetPublicKey Returns the flagset for Public Key related operations. func FlagSetPublicKey() *flag.FlagSet { fs := flag.NewFlagSet("", flag.ContinueOnError) - fs.String(FlagPubKey, "", "The Bech32 encoded PubKey of the validator") + fs.String(FlagPubKey, "", "The validator's Protobuf JSON encoded public key") return fs } diff --git a/x/staking/client/cli/query.go b/x/staking/client/cli/query.go index 31e779bed2..aa6e839de3 100644 --- a/x/staking/client/cli/query.go +++ b/x/staking/client/cli/query.go @@ -1,7 +1,6 @@ package cli import ( - "context" "fmt" "strconv" "strings" @@ -115,7 +114,7 @@ $ %s query staking validators return err } - result, err := queryClient.Validators(context.Background(), &types.QueryValidatorsRequest{ + result, err := queryClient.Validators(cmd.Context(), &types.QueryValidatorsRequest{ // Leaving status empty on purpose to query all validators. Pagination: pageReq, }) @@ -172,7 +171,7 @@ $ %s query staking unbonding-delegations-from %s1gghjut3ccd8ay0zduzj64hwre2fxs9l Pagination: pageReq, } - res, err := queryClient.ValidatorUnbondingDelegations(context.Background(), params) + res, err := queryClient.ValidatorUnbondingDelegations(cmd.Context(), params) if err != nil { return err } @@ -227,7 +226,7 @@ $ %s query staking redelegations-from %s1gghjut3ccd8ay0zduzj64hwre2fxs9ldmqhffj Pagination: pageReq, } - res, err := queryClient.Redelegations(context.Background(), params) + res, err := queryClient.Redelegations(cmd.Context(), params) if err != nil { return err } @@ -282,7 +281,7 @@ $ %s query staking delegation %s1gghjut3ccd8ay0zduzj64hwre2fxs9ld75ru9p %s1gghju ValidatorAddr: valAddr.String(), } - res, err := queryClient.Delegation(context.Background(), params) + res, err := queryClient.Delegation(cmd.Context(), params) if err != nil { return err } @@ -336,7 +335,7 @@ $ %s query staking delegations %s1gghjut3ccd8ay0zduzj64hwre2fxs9ld75ru9p Pagination: pageReq, } - res, err := queryClient.DelegatorDelegations(context.Background(), params) + res, err := queryClient.DelegatorDelegations(cmd.Context(), params) if err != nil { return err } @@ -391,7 +390,7 @@ $ %s query staking delegations-to %s1gghjut3ccd8ay0zduzj64hwre2fxs9ldmqhffj Pagination: pageReq, } - res, err := queryClient.ValidatorDelegations(context.Background(), params) + res, err := queryClient.ValidatorDelegations(cmd.Context(), params) if err != nil { return err } @@ -447,7 +446,7 @@ $ %s query staking unbonding-delegation %s1gghjut3ccd8ay0zduzj64hwre2fxs9ld75ru9 ValidatorAddr: valAddr.String(), } - res, err := queryClient.UnbondingDelegation(context.Background(), params) + res, err := queryClient.UnbondingDelegation(cmd.Context(), params) if err != nil { return err } @@ -501,7 +500,7 @@ $ %s query staking unbonding-delegations %s1gghjut3ccd8ay0zduzj64hwre2fxs9ld75ru Pagination: pageReq, } - res, err := queryClient.DelegatorUnbondingDelegations(context.Background(), params) + res, err := queryClient.DelegatorUnbondingDelegations(cmd.Context(), params) if err != nil { return err } @@ -563,7 +562,7 @@ $ %s query staking redelegation %s1gghjut3ccd8ay0zduzj64hwre2fxs9ld75ru9p %s1l2r SrcValidatorAddr: valSrcAddr.String(), } - res, err := queryClient.Redelegations(context.Background(), params) + res, err := queryClient.Redelegations(cmd.Context(), params) if err != nil { return err } @@ -617,7 +616,7 @@ $ %s query staking redelegation %s1gghjut3ccd8ay0zduzj64hwre2fxs9ld75ru9p Pagination: pageReq, } - res, err := queryClient.Redelegations(context.Background(), params) + res, err := queryClient.Redelegations(cmd.Context(), params) if err != nil { return err } @@ -660,8 +659,7 @@ $ %s query staking historical-info 5 } params := &types.QueryHistoricalInfoRequest{Height: height} - res, err := queryClient.HistoricalInfo(context.Background(), params) - + res, err := queryClient.HistoricalInfo(cmd.Context(), params) if err != nil { return err } @@ -697,7 +695,7 @@ $ %s query staking pool } queryClient := types.NewQueryClient(clientCtx) - res, err := queryClient.Pool(context.Background(), &types.QueryPoolRequest{}) + res, err := queryClient.Pool(cmd.Context(), &types.QueryPoolRequest{}) if err != nil { return err } @@ -733,7 +731,7 @@ $ %s query staking params } queryClient := types.NewQueryClient(clientCtx) - res, err := queryClient.Params(context.Background(), &types.QueryParamsRequest{}) + res, err := queryClient.Params(cmd.Context(), &types.QueryParamsRequest{}) if err != nil { return err } diff --git a/x/staking/client/cli/tx.go b/x/staking/client/cli/tx.go index 83f6b3a2f4..ddf1885439 100644 --- a/x/staking/client/cli/tx.go +++ b/x/staking/client/cli/tx.go @@ -13,13 +13,14 @@ import ( "github.com/line/lbm-sdk/client/tx" cryptotypes "github.com/line/lbm-sdk/crypto/types" sdk "github.com/line/lbm-sdk/types" + sdkerrors "github.com/line/lbm-sdk/types/errors" "github.com/line/lbm-sdk/version" "github.com/line/lbm-sdk/x/staking/types" ) // default values var ( - DefaultTokens = sdk.TokensFromConsensusPower(100) + DefaultTokens = sdk.TokensFromConsensusPower(100, sdk.DefaultPowerReduction) defaultAmount = DefaultTokens.String() + sdk.DefaultBondDenom defaultCommissionRate = "0.1" defaultCommissionMaxRate = "0.2" @@ -57,9 +58,10 @@ func NewCreateValidatorCmd() *cobra.Command { if err != nil { return err } - txf := tx.NewFactoryCLI(clientCtx, cmd.Flags()).WithTxConfig(clientCtx.TxConfig).WithAccountRetriever(clientCtx.AccountRetriever) - txf, msg, err := NewBuildCreateValidatorMsg(clientCtx, txf, cmd.Flags()) + txf := tx.NewFactoryCLI(clientCtx, cmd.Flags()). + WithTxConfig(clientCtx.TxConfig).WithAccountRetriever(clientCtx.AccountRetriever) + txf, msg, err := newBuildCreateValidatorMsg(clientCtx, txf, cmd.Flags()) if err != nil { return err } @@ -121,16 +123,13 @@ func NewEditValidatorCmd() *cobra.Command { if minSelfDelegationString != "" { msb, ok := sdk.NewIntFromString(minSelfDelegationString) if !ok { - return types.ErrMinSelfDelegationInvalid + return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "minimum self delegation must be a positive integer") } newMinSelfDelegation = &msb } msg := types.NewMsgEditValidator(valAddr.ToValAddress(), description, newRate, newMinSelfDelegation) - if err := msg.ValidateBasic(); err != nil { - return err - } return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) }, @@ -174,9 +173,6 @@ $ %s tx staking delegate %s1l2rsakp388kuv9k8qzq6lrm9taddae7fpx59wm 1000stake --f valAddr := sdk.ValAddress(args[0]) msg := types.NewMsgDelegate(delAddr, valAddr, amount) - if err := msg.ValidateBasic(); err != nil { - return err - } return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) }, @@ -219,9 +215,6 @@ $ %s tx staking redelegate %s1gghjut3ccd8ay0zduzj64hwre2fxs9ldmqhffj %s1l2rsakp3 } msg := types.NewMsgBeginRedelegate(delAddr, valSrcAddr, valDstAddr, amount) - if err := msg.ValidateBasic(); err != nil { - return err - } return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) }, @@ -262,9 +255,6 @@ $ %s tx staking unbond %s1gghjut3ccd8ay0zduzj64hwre2fxs9ldmqhffj 100stake --from } msg := types.NewMsgUndelegate(delAddr, valAddr, amount) - if err := msg.ValidateBasic(); err != nil { - return err - } return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) }, @@ -275,7 +265,7 @@ $ %s tx staking unbond %s1gghjut3ccd8ay0zduzj64hwre2fxs9ldmqhffj 100stake --from return cmd } -func NewBuildCreateValidatorMsg(clientCtx client.Context, txf tx.Factory, fs *flag.FlagSet) (tx.Factory, sdk.Msg, error) { +func newBuildCreateValidatorMsg(clientCtx client.Context, txf tx.Factory, fs *flag.FlagSet) (tx.Factory, *types.MsgCreateValidator, error) { fAmount, _ := fs.GetString(FlagAmount) amount, err := sdk.ParseCoinNormalized(fAmount) if err != nil { @@ -283,13 +273,16 @@ func NewBuildCreateValidatorMsg(clientCtx client.Context, txf tx.Factory, fs *fl } valAddr := clientCtx.GetFromAddress() - pkStr, _ := fs.GetString(FlagPubKey) - - pk, err := sdk.GetPubKeyFromBech32(sdk.Bech32PubKeyTypeConsPub, pkStr) + pkStr, err := fs.GetString(FlagPubKey) if err != nil { return txf, nil, err } + var pk cryptotypes.PubKey + if err := clientCtx.Codec.UnmarshalInterfaceJSON([]byte(pkStr), &pk); err != nil { + return txf, nil, err + } + moniker, _ := fs.GetString(FlagMoniker) identity, _ := fs.GetString(FlagIdentity) website, _ := fs.GetString(FlagWebsite) @@ -318,7 +311,7 @@ func NewBuildCreateValidatorMsg(clientCtx client.Context, txf tx.Factory, fs *fl minSelfDelegation, ok := sdk.NewIntFromString(msbStr) if !ok { - return txf, nil, types.ErrMinSelfDelegationInvalid + return txf, nil, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "minimum self delegation must be a positive integer") } msg, err := types.NewMsgCreateValidator( @@ -385,7 +378,7 @@ type TxCreateValidatorConfig struct { CommissionMaxChangeRate string MinSelfDelegation string - PubKey string + PubKey cryptotypes.PubKey IP string Website string @@ -457,7 +450,7 @@ func PrepareConfigForTxCreateValidator(flagSet *flag.FlagSet, moniker, nodeID, c } c.NodeID = nodeID - c.PubKey = sdk.MustBech32ifyPubKey(sdk.Bech32PubKeyTypeConsPub, valPubKey) + c.PubKey = valPubKey c.Website = website c.SecurityContact = securityContact c.Details = details @@ -498,13 +491,6 @@ func BuildCreateValidatorMsg(clientCtx client.Context, config TxCreateValidatorC } valAddr := clientCtx.GetFromAddress() - pkStr := config.PubKey - - pk, err := sdk.GetPubKeyFromBech32(sdk.Bech32PubKeyTypeConsPub, pkStr) - if err != nil { - return txBldr, nil, err - } - description := types.NewDescription( config.Moniker, config.Identity, @@ -528,11 +514,11 @@ func BuildCreateValidatorMsg(clientCtx client.Context, config TxCreateValidatorC minSelfDelegation, ok := sdk.NewIntFromString(msbStr) if !ok { - return txBldr, nil, types.ErrMinSelfDelegationInvalid + return txBldr, nil, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "minimum self delegation must be a positive integer") } msg, err := types.NewMsgCreateValidator( - valAddr.ToValAddress(), pk, amount, description, commissionRates, minSelfDelegation, + valAddr.ToValAddress(), config.PubKey, amount, description, commissionRates, minSelfDelegation, ) if err != nil { return txBldr, msg, err diff --git a/x/staking/client/cli/tx_test.go b/x/staking/client/cli/tx_test.go index 30a3b4554f..a983d00256 100644 --- a/x/staking/client/cli/tx_test.go +++ b/x/staking/client/cli/tx_test.go @@ -7,15 +7,30 @@ import ( "github.com/stretchr/testify/require" "github.com/line/lbm-sdk/client/flags" - sdk "github.com/line/lbm-sdk/types" + "github.com/line/lbm-sdk/crypto/keys/ed25519" ) func TestPrepareConfigForTxCreateValidator(t *testing.T) { chainID := "chainID" ip := "1.1.1.1" nodeID := "nodeID" - valPubKey, _ := sdk.GetPubKeyFromBech32(sdk.Bech32PubKeyTypeConsPub, "linkvalconspub1cqmsrdepqwygwv232a90sgk5k5wkdq990sg2r27wn5p7kc2cemm2yq50fvh526n3unm") + privKey := ed25519.GenPrivKey() + valPubKey := privKey.PubKey() moniker := "DefaultMoniker" + mkTxValCfg := func(amount, commission, commissionMax, commissionMaxChange, minSelfDelegation string) TxCreateValidatorConfig { + return TxCreateValidatorConfig{ + IP: ip, + ChainID: chainID, + NodeID: nodeID, + PubKey: valPubKey, + Moniker: moniker, + Amount: amount, + CommissionRate: commission, + CommissionMaxRate: commissionMax, + CommissionMaxChangeRate: commissionMaxChange, + MinSelfDelegation: minSelfDelegation, + } + } tests := []struct { name string @@ -27,108 +42,38 @@ func TestPrepareConfigForTxCreateValidator(t *testing.T) { fsModify: func(fs *pflag.FlagSet) { return }, - expectedCfg: TxCreateValidatorConfig{ - IP: ip, - ChainID: chainID, - NodeID: nodeID, - PubKey: sdk.MustBech32ifyPubKey(sdk.Bech32PubKeyTypeConsPub, valPubKey), - Moniker: moniker, - Amount: defaultAmount, - CommissionRate: "0.1", - CommissionMaxRate: "0.2", - CommissionMaxChangeRate: "0.01", - MinSelfDelegation: "1", - }, - }, - { + expectedCfg: mkTxValCfg(defaultAmount, "0.1", "0.2", "0.01", "1"), + }, { name: "Custom amount", fsModify: func(fs *pflag.FlagSet) { fs.Set(FlagAmount, "2000stake") }, - expectedCfg: TxCreateValidatorConfig{ - IP: ip, - Moniker: moniker, - ChainID: chainID, - NodeID: nodeID, - PubKey: sdk.MustBech32ifyPubKey(sdk.Bech32PubKeyTypeConsPub, valPubKey), - Amount: "2000stake", - CommissionRate: "0.1", - CommissionMaxRate: "0.2", - CommissionMaxChangeRate: "0.01", - MinSelfDelegation: "1", - }, - }, - { + expectedCfg: mkTxValCfg("2000stake", "0.1", "0.2", "0.01", "1"), + }, { name: "Custom commission rate", fsModify: func(fs *pflag.FlagSet) { fs.Set(FlagCommissionRate, "0.54") }, - expectedCfg: TxCreateValidatorConfig{ - IP: ip, - Moniker: moniker, - ChainID: chainID, - NodeID: nodeID, - PubKey: sdk.MustBech32ifyPubKey(sdk.Bech32PubKeyTypeConsPub, valPubKey), - Amount: defaultAmount, - CommissionRate: "0.54", - CommissionMaxRate: "0.2", - CommissionMaxChangeRate: "0.01", - MinSelfDelegation: "1", - }, - }, - { + expectedCfg: mkTxValCfg(defaultAmount, "0.54", "0.2", "0.01", "1"), + }, { name: "Custom commission max rate", fsModify: func(fs *pflag.FlagSet) { fs.Set(FlagCommissionMaxRate, "0.89") }, - expectedCfg: TxCreateValidatorConfig{ - IP: ip, - Moniker: moniker, - ChainID: chainID, - NodeID: nodeID, - PubKey: sdk.MustBech32ifyPubKey(sdk.Bech32PubKeyTypeConsPub, valPubKey), - Amount: defaultAmount, - CommissionRate: "0.1", - CommissionMaxRate: "0.89", - CommissionMaxChangeRate: "0.01", - MinSelfDelegation: "1", - }, - }, - { + expectedCfg: mkTxValCfg(defaultAmount, "0.1", "0.89", "0.01", "1"), + }, { name: "Custom commission max change rate", fsModify: func(fs *pflag.FlagSet) { fs.Set(FlagCommissionMaxChangeRate, "0.55") }, - expectedCfg: TxCreateValidatorConfig{ - IP: ip, - Moniker: moniker, - ChainID: chainID, - NodeID: nodeID, - PubKey: sdk.MustBech32ifyPubKey(sdk.Bech32PubKeyTypeConsPub, valPubKey), - Amount: defaultAmount, - CommissionRate: "0.1", - CommissionMaxRate: "0.2", - CommissionMaxChangeRate: "0.55", - MinSelfDelegation: "1", - }, + expectedCfg: mkTxValCfg(defaultAmount, "0.1", "0.2", "0.55", "1"), }, { name: "Custom min self delegations", fsModify: func(fs *pflag.FlagSet) { fs.Set(FlagMinSelfDelegation, "0.33") }, - expectedCfg: TxCreateValidatorConfig{ - IP: ip, - Moniker: moniker, - ChainID: chainID, - NodeID: nodeID, - PubKey: sdk.MustBech32ifyPubKey(sdk.Bech32PubKeyTypeConsPub, valPubKey), - Amount: defaultAmount, - CommissionRate: "0.1", - CommissionMaxRate: "0.2", - CommissionMaxChangeRate: "0.01", - MinSelfDelegation: "0.33", - }, + expectedCfg: mkTxValCfg(defaultAmount, "0.1", "0.2", "0.01", "0.33"), }, } diff --git a/x/staking/client/rest/grpc_query_test.go b/x/staking/client/rest/grpc_query_test.go index ad7c47fcff..36e36856dd 100644 --- a/x/staking/client/rest/grpc_query_test.go +++ b/x/staking/client/rest/grpc_query_test.go @@ -1,16 +1,16 @@ +//go:build norace // +build norace package rest_test import ( "fmt" - "io/ioutil" - "net/http" "testing" "github.com/gogo/protobuf/proto" "github.com/stretchr/testify/suite" + "github.com/line/lbm-sdk/client/flags" "github.com/line/lbm-sdk/crypto/hd" "github.com/line/lbm-sdk/crypto/keyring" "github.com/line/lbm-sdk/testutil" @@ -50,7 +50,15 @@ func (s *IntegrationTestSuite) SetupSuite() { val2 := s.network.Validators[1] // redelegate - _, err = stakingtestutil.MsgRedelegateExec(val.ClientCtx, val.Address, val.ValAddress, val2.ValAddress, unbond) + _, err = stakingtestutil.MsgRedelegateExec( + val.ClientCtx, + val.Address, + val.ValAddress, + val2.ValAddress, + unbond, + fmt.Sprintf("--%s=%d", flags.FlagGas, 254000), + ) // expected gas is 202987 + s.Require().NoError(err) _, err = s.network.WaitForHeight(1) s.Require().NoError(err) @@ -100,7 +108,7 @@ func (s *IntegrationTestSuite) TestQueryValidatorsGRPCHandler() { s.Require().NoError(err) var valRes types.QueryValidatorsResponse - err = val.ClientCtx.JSONMarshaler.UnmarshalJSON(resp, &valRes) + err = val.ClientCtx.Codec.UnmarshalJSON(resp, &valRes) if tc.error { s.Require().Error(err) @@ -148,7 +156,7 @@ func (s *IntegrationTestSuite) TestQueryValidatorGRPC() { s.Require().NoError(err) var validator types.QueryValidatorResponse - err = val.ClientCtx.JSONMarshaler.UnmarshalJSON(resp, &validator) + err = val.ClientCtx.Codec.UnmarshalJSON(resp, &validator) if tc.error { s.Require().Error(err) @@ -212,7 +220,7 @@ func (s *IntegrationTestSuite) TestQueryValidatorDelegationsGRPC() { resp, err := testutil.GetRequestWithHeaders(tc.url, tc.headers) s.Require().NoError(err) - err = val.ClientCtx.JSONMarshaler.UnmarshalJSON(resp, tc.respType) + err = val.ClientCtx.Codec.UnmarshalJSON(resp, tc.respType) if tc.error { s.Require().Error(err) @@ -258,7 +266,7 @@ func (s *IntegrationTestSuite) TestQueryValidatorUnbondingDelegationsGRPC() { var ubds types.QueryValidatorUnbondingDelegationsResponse - err = val.ClientCtx.JSONMarshaler.UnmarshalJSON(resp, &ubds) + err = val.ClientCtx.Codec.UnmarshalJSON(resp, &ubds) if tc.error { s.Require().Error(err) @@ -334,8 +342,8 @@ func (s *IntegrationTestSuite) TestQueryDelegationGRPC() { s.Run(tc.name, func() { resp, err := rest.GetRequest(tc.url) s.Require().NoError(err) - - err = val.ClientCtx.JSONMarshaler.UnmarshalJSON(resp, tc.respType) + s.T().Logf("%s", resp) + err = val.ClientCtx.Codec.UnmarshalJSON(resp, tc.respType) if tc.error { s.Require().Error(err) @@ -391,7 +399,7 @@ func (s *IntegrationTestSuite) TestQueryUnbondingDelegationGRPC() { var ubd types.QueryUnbondingDelegationResponse - err = val.ClientCtx.JSONMarshaler.UnmarshalJSON(resp, &ubd) + err = val.ClientCtx.Codec.UnmarshalJSON(resp, &ubd) if tc.error { s.Require().Error(err) @@ -405,39 +413,15 @@ func (s *IntegrationTestSuite) TestQueryUnbondingDelegationGRPC() { } } -func (s *IntegrationTestSuite) TestQueryDelegationsResponseCode() { +func (s *IntegrationTestSuite) TestQueryDelegatorDelegationsGRPC() { val := s.network.Validators[0] + baseURL := val.APIAddress - // Create new account in the keyring. - info, _, err := val.ClientCtx.Keyring.NewMnemonic("test", keyring.English, sdk.FullFundraiserPath, hd.Secp256k1) + // Create new account in the keyring for address without delegations. + info, _, err := val.ClientCtx.Keyring.NewMnemonic("test", keyring.English, sdk.FullFundraiserPath, keyring.DefaultBIP39Passphrase, hd.Secp256k1) s.Require().NoError(err) newAddr := sdk.BytesToAccAddress(info.GetPubKey().Address()) - s.T().Log("expect 404 error for address without delegations") - res, statusCode, err := getRequest(fmt.Sprintf("%s/lbm/staking/v1/delegations/%s", val.APIAddress, newAddr.String())) - s.Require().NoError(err) - s.Require().Contains(string(res), "\"code\": 5") - s.Require().Equal(404, statusCode) -} - -func getRequest(url string) ([]byte, int, error) { - res, err := http.Get(url) // nolint:gosec - body, err := ioutil.ReadAll(res.Body) - if err != nil { - return nil, res.StatusCode, err - } - - if err = res.Body.Close(); err != nil { - return nil, res.StatusCode, err - } - - return body, res.StatusCode, nil -} - -func (s *IntegrationTestSuite) TestQueryDelegatorDelegationsGRPC() { - val := s.network.Validators[0] - baseURL := val.APIAddress - testCases := []struct { name string url string @@ -477,6 +461,19 @@ func (s *IntegrationTestSuite) TestQueryDelegatorDelegationsGRPC() { Pagination: &query.PageResponse{Total: 1}, }, }, + { + "address without delegations", + fmt.Sprintf("%s/lbm/staking/v1/delegations/%s", baseURL, newAddr.String()), + map[string]string{ + grpctypes.GRPCBlockHeightHeader: "1", + }, + false, + &types.QueryDelegatorDelegationsResponse{}, + &types.QueryDelegatorDelegationsResponse{ + DelegationResponses: types.DelegationResponses{}, + Pagination: &query.PageResponse{Total: 0}, + }, + }, } for _, tc := range testCases { @@ -485,7 +482,7 @@ func (s *IntegrationTestSuite) TestQueryDelegatorDelegationsGRPC() { resp, err := testutil.GetRequestWithHeaders(tc.url, tc.headers) s.Require().NoError(err) - err = val.ClientCtx.JSONMarshaler.UnmarshalJSON(resp, tc.respType) + err = val.ClientCtx.Codec.UnmarshalJSON(resp, tc.respType) if tc.error { s.Require().Error(err) @@ -535,7 +532,7 @@ func (s *IntegrationTestSuite) TestQueryDelegatorUnbondingDelegationsGRPC() { var ubds types.QueryDelegatorUnbondingDelegationsResponse - err = val.ClientCtx.JSONMarshaler.UnmarshalJSON(resp, &ubds) + err = val.ClientCtx.Codec.UnmarshalJSON(resp, &ubds) if tc.error { s.Require().Error(err) @@ -596,7 +593,7 @@ func (s *IntegrationTestSuite) TestQueryRedelegationsGRPC() { s.Require().NoError(err) var redelegations types.QueryRedelegationsResponse - err = val.ClientCtx.JSONMarshaler.UnmarshalJSON(resp, &redelegations) + err = val.ClientCtx.Codec.UnmarshalJSON(resp, &redelegations) if tc.error { s.Require().Error(err) @@ -646,7 +643,7 @@ func (s *IntegrationTestSuite) TestQueryDelegatorValidatorsGRPC() { var validators types.QueryDelegatorValidatorsResponse - err = val.ClientCtx.JSONMarshaler.UnmarshalJSON(resp, &validators) + err = val.ClientCtx.Codec.UnmarshalJSON(resp, &validators) if tc.error { s.Require().Error(err) @@ -702,7 +699,7 @@ func (s *IntegrationTestSuite) TestQueryDelegatorValidatorGRPC() { s.Require().NoError(err) var validator types.QueryDelegatorValidatorResponse - err = val.ClientCtx.JSONMarshaler.UnmarshalJSON(resp, &validator) + err = val.ClientCtx.Codec.UnmarshalJSON(resp, &validator) if tc.error { s.Require().Error(err) @@ -747,15 +744,15 @@ func (s *IntegrationTestSuite) TestQueryHistoricalInfoGRPC() { resp, err := rest.GetRequest(tc.url) s.Require().NoError(err) - var historical_info types.QueryHistoricalInfoResponse + var historicalInfo types.QueryHistoricalInfoResponse - err = val.ClientCtx.JSONMarshaler.UnmarshalJSON(resp, &historical_info) + err = val.ClientCtx.Codec.UnmarshalJSON(resp, &historicalInfo) if tc.error { s.Require().Error(err) } else { s.Require().NoError(err) - s.Require().NotNil(historical_info) + s.Require().NotNil(historicalInfo) } }) } @@ -786,7 +783,7 @@ func (s *IntegrationTestSuite) TestQueryParamsGRPC() { resp, err := rest.GetRequest(tc.url) s.Run(tc.name, func() { s.Require().NoError(err) - s.Require().NoError(val.ClientCtx.JSONMarshaler.UnmarshalJSON(resp, tc.respType)) + s.Require().NoError(val.ClientCtx.Codec.UnmarshalJSON(resp, tc.respType)) s.Require().Equal(tc.expected, tc.respType) }) } @@ -820,7 +817,7 @@ func (s *IntegrationTestSuite) TestQueryPoolGRPC() { resp, err := rest.GetRequest(tc.url) s.Run(tc.name, func() { s.Require().NoError(err) - s.Require().NoError(val.ClientCtx.JSONMarshaler.UnmarshalJSON(resp, tc.respType)) + s.Require().NoError(val.ClientCtx.Codec.UnmarshalJSON(resp, tc.respType)) s.Require().Equal(tc.expected, tc.respType) }) } diff --git a/x/staking/client/rest/query.go b/x/staking/client/rest/query.go index 18fa185c20..2a23f9be73 100644 --- a/x/staking/client/rest/query.go +++ b/x/staking/client/rest/query.go @@ -151,20 +151,24 @@ func delegatorTxsHandlerFn(clientCtx client.Context) http.HandlerFunc { actions []string ) + // For each case, we search txs for both: + // - legacy messages: their Type() is a custom string, e.g. "delegate" + // - service Msgs: their Type() is their FQ method name, e.g. "/lbm.staking.v1.Msg/Deledate" + // and we combine the results. switch { case isBondTx: - actions = append(actions, types.MsgDelegate{}.Type()) + actions = append(actions, types.TypeMsgDelegate) case isUnbondTx: - actions = append(actions, types.MsgUndelegate{}.Type()) + actions = append(actions, types.TypeMsgUndelegate) case isRedTx: - actions = append(actions, types.MsgBeginRedelegate{}.Type()) + actions = append(actions, types.TypeMsgBeginRedelegate) case noQuery: - actions = append(actions, types.MsgDelegate{}.Type()) - actions = append(actions, types.MsgUndelegate{}.Type()) - actions = append(actions, types.MsgBeginRedelegate{}.Type()) + actions = append(actions, types.TypeMsgDelegate) + actions = append(actions, types.TypeMsgUndelegate) + actions = append(actions, types.TypeMsgBeginRedelegate) default: w.WriteHeader(http.StatusNoContent) diff --git a/x/staking/client/rest/rest.go b/x/staking/client/rest/rest.go index c7f1f513b4..edfa3d0cef 100644 --- a/x/staking/client/rest/rest.go +++ b/x/staking/client/rest/rest.go @@ -3,9 +3,8 @@ package rest import ( "github.com/gorilla/mux" - "github.com/line/lbm-sdk/client/rest" - "github.com/line/lbm-sdk/client" + "github.com/line/lbm-sdk/client/rest" ) func RegisterHandlers(clientCtx client.Context, rtr *mux.Router) { diff --git a/x/staking/client/rest/utils.go b/x/staking/client/rest/utils.go index 076f8f0c12..775aa4ed36 100644 --- a/x/staking/client/rest/utils.go +++ b/x/staking/client/rest/utils.go @@ -9,7 +9,7 @@ import ( "github.com/line/lbm-sdk/client" sdk "github.com/line/lbm-sdk/types" "github.com/line/lbm-sdk/types/rest" - authclient "github.com/line/lbm-sdk/x/auth/client" + authtx "github.com/line/lbm-sdk/x/auth/tx" "github.com/line/lbm-sdk/x/staking/types" ) @@ -33,7 +33,7 @@ func queryTxs(clientCtx client.Context, action string, delegatorAddr string) (*s fmt.Sprintf("%s.%s='%s'", sdk.EventTypeMessage, sdk.AttributeKeySender, delegatorAddr), } - return authclient.QueryTxsByEvents(clientCtx, events, page, limit, "") + return authtx.QueryTxsByEvents(clientCtx, events, page, limit, "") } func queryBonds(clientCtx client.Context, endpoint string) http.HandlerFunc { diff --git a/x/staking/client/testutil/cli_test.go b/x/staking/client/testutil/cli_test.go new file mode 100644 index 0000000000..df2d1b5152 --- /dev/null +++ b/x/staking/client/testutil/cli_test.go @@ -0,0 +1,18 @@ +//go:build norace +// +build norace + +package testutil + +import ( + "testing" + + "github.com/line/lbm-sdk/testutil/network" + + "github.com/stretchr/testify/suite" +) + +func TestIntegrationTestSuite(t *testing.T) { + cfg := network.DefaultConfig() + cfg.NumValidators = 2 + suite.Run(t, NewIntegrationTestSuite(cfg)) +} diff --git a/x/staking/client/cli/cli_test.go b/x/staking/client/testutil/suite.go similarity index 89% rename from x/staking/client/cli/cli_test.go rename to x/staking/client/testutil/suite.go index dce1bb84c2..354ae2cfc1 100644 --- a/x/staking/client/cli/cli_test.go +++ b/x/staking/client/testutil/suite.go @@ -1,6 +1,4 @@ -// +build norace - -package cli_test +package testutil import ( "context" @@ -9,10 +7,11 @@ import ( "testing" "github.com/gogo/protobuf/proto" + "github.com/stretchr/testify/suite" + ostcli "github.com/line/ostracon/libs/cli" "github.com/line/ostracon/proto/ostracon/crypto" "github.com/line/ostracon/rpc/client/http" - "github.com/stretchr/testify/suite" "github.com/line/lbm-sdk/client/flags" "github.com/line/lbm-sdk/crypto/hd" @@ -24,7 +23,6 @@ import ( "github.com/line/lbm-sdk/types/query" banktestutil "github.com/line/lbm-sdk/x/bank/client/testutil" "github.com/line/lbm-sdk/x/staking/client/cli" - stakingtestutil "github.com/line/lbm-sdk/x/staking/client/testutil" "github.com/line/lbm-sdk/x/staking/types" ) @@ -35,6 +33,10 @@ type IntegrationTestSuite struct { network *network.Network } +func NewIntegrationTestSuite(cfg network.Config) *IntegrationTestSuite { + return &IntegrationTestSuite{cfg: cfg} +} + func (s *IntegrationTestSuite) SetupSuite() { s.T().Log("setting up integration test suite") @@ -42,11 +44,7 @@ func (s *IntegrationTestSuite) SetupSuite() { s.T().Skip("skipping test in unit-tests mode.") } - cfg := network.DefaultConfig() - cfg.NumValidators = 2 - - s.cfg = cfg - s.network = network.New(s.T(), cfg) + s.network = network.New(s.T(), s.cfg) _, err := s.network.WaitForHeight(1) s.Require().NoError(err) @@ -58,13 +56,19 @@ func (s *IntegrationTestSuite) SetupSuite() { val2 := s.network.Validators[1] // redelegate - _, err = stakingtestutil.MsgRedelegateExec(val.ClientCtx, val.Address, val.ValAddress, val2.ValAddress, unbond) + _, err = MsgRedelegateExec( + val.ClientCtx, + val.Address, + val.ValAddress, + val2.ValAddress, + unbond, + fmt.Sprintf("--%s=%d", flags.FlagGas, 300000), + ) s.Require().NoError(err) _, err = s.network.WaitForHeight(1) s.Require().NoError(err) - // unbonding - _, err = stakingtestutil.MsgUnbondExec(val.ClientCtx, val.Address, val.ValAddress, unbond) + _, err = MsgUnbondExec(val.ClientCtx, val.Address, val.ValAddress, unbond) s.Require().NoError(err) _, err = s.network.WaitForHeight(1) s.Require().NoError(err) @@ -76,17 +80,18 @@ func (s *IntegrationTestSuite) TearDownSuite() { } func (s *IntegrationTestSuite) TestNewCreateValidatorCmd() { + require := s.Require() val := s.network.Validators[0] consPrivKey := ed25519.GenPrivKey() - consPubKey, err := sdk.Bech32ifyPubKey(sdk.Bech32PubKeyTypeConsPub, consPrivKey.PubKey()) - s.Require().NoError(err) + consPubKeyBz, err := s.cfg.Codec.MarshalInterfaceJSON(consPrivKey.PubKey()) + require.NoError(err) + require.NotNil(consPubKeyBz) - info, _, err := val.ClientCtx.Keyring.NewMnemonic("NewValidator", keyring.English, sdk.FullFundraiserPath, hd.Secp256k1) - s.Require().NoError(err) + info, _, err := val.ClientCtx.Keyring.NewMnemonic("NewValidator", keyring.English, sdk.FullFundraiserPath, keyring.DefaultBIP39Passphrase, hd.Secp256k1) + require.NoError(err) newAddr := sdk.BytesToAccAddress(info.GetPubKey().Address()) - _, err = banktestutil.MsgSendExec( val.ClientCtx, val.Address, @@ -95,14 +100,14 @@ func (s *IntegrationTestSuite) TestNewCreateValidatorCmd() { fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), ) - s.Require().NoError(err) + require.NoError(err) testCases := []struct { name string args []string expectErr bool - respType proto.Message expectedCode uint32 + respType proto.Message }{ { "invalid transaction (missing amount)", @@ -120,12 +125,12 @@ func (s *IntegrationTestSuite) TestNewCreateValidatorCmd() { fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), }, - true, nil, 0, + true, 0, nil, }, { "invalid transaction (missing pubkey)", []string{ - fmt.Sprintf("--%s=100stake", cli.FlagAmount), + fmt.Sprintf("--%s=%dstake", cli.FlagAmount, 100), fmt.Sprintf("--%s=AFAF00C4", cli.FlagIdentity), fmt.Sprintf("--%s=https://newvalidator.io", cli.FlagWebsite), fmt.Sprintf("--%s=contact@newvalidator.io", cli.FlagSecurityContact), @@ -139,13 +144,13 @@ func (s *IntegrationTestSuite) TestNewCreateValidatorCmd() { fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), }, - true, nil, 0, + true, 0, nil, }, { "invalid transaction (missing moniker)", []string{ - fmt.Sprintf("--%s=%s", cli.FlagPubKey, consPubKey), - fmt.Sprintf("--%s=100stake", cli.FlagAmount), + fmt.Sprintf("--%s=%s", cli.FlagPubKey, consPubKeyBz), + fmt.Sprintf("--%s=%dstake", cli.FlagAmount, 100), fmt.Sprintf("--%s=AFAF00C4", cli.FlagIdentity), fmt.Sprintf("--%s=https://newvalidator.io", cli.FlagWebsite), fmt.Sprintf("--%s=contact@newvalidator.io", cli.FlagSecurityContact), @@ -159,13 +164,13 @@ func (s *IntegrationTestSuite) TestNewCreateValidatorCmd() { fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), }, - true, nil, 0, + true, 0, nil, }, { "valid transaction", []string{ - fmt.Sprintf("--%s=%s", cli.FlagPubKey, consPubKey), - fmt.Sprintf("--%s=100stake", cli.FlagAmount), + fmt.Sprintf("--%s=%s", cli.FlagPubKey, consPubKeyBz), + fmt.Sprintf("--%s=%dstake", cli.FlagAmount, 100), fmt.Sprintf("--%s=NewValidator", cli.FlagMoniker), fmt.Sprintf("--%s=AFAF00C4", cli.FlagIdentity), fmt.Sprintf("--%s=https://newvalidator.io", cli.FlagWebsite), @@ -180,7 +185,7 @@ func (s *IntegrationTestSuite) TestNewCreateValidatorCmd() { fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), }, - false, &sdk.TxResponse{}, 0, + false, 0, &sdk.TxResponse{}, }, } @@ -193,13 +198,24 @@ func (s *IntegrationTestSuite) TestNewCreateValidatorCmd() { out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, tc.args) if tc.expectErr { - s.Require().Error(err) + require.Error(err) } else { - s.Require().NoError(err, out.String()) - s.Require().NoError(clientCtx.JSONMarshaler.UnmarshalJSON(out.Bytes(), tc.respType), out.String()) + require.NoError(err, "test: %s\noutput: %s", tc.name, out.String()) + err = clientCtx.Codec.UnmarshalJSON(out.Bytes(), tc.respType) + require.NoError(err, out.String(), "test: %s, output\n:", tc.name, out.String()) txResp := tc.respType.(*sdk.TxResponse) - s.Require().Equal(tc.expectedCode, txResp.Code, out.String()) + require.Equal(tc.expectedCode, txResp.Code, + "test: %s, output\n:", tc.name, out.String()) + + events := txResp.Logs[0].GetEvents() + for i := 0; i < len(events); i++ { + if events[i].GetType() == "create_validator" { + attributes := events[i].GetAttributes() + require.Equal(attributes[1].Value, "100stake") + break + } + } } }) } @@ -224,7 +240,7 @@ func (s *IntegrationTestSuite) TestGetCmdQueryValidator() { }, { "happy case", - []string{fmt.Sprintf("%s", val.ValAddress), fmt.Sprintf("--%s=json", ostcli.OutputFlag)}, + []string{val.ValAddress.String(), fmt.Sprintf("--%s=json", ostcli.OutputFlag)}, false, }, } @@ -239,7 +255,7 @@ func (s *IntegrationTestSuite) TestGetCmdQueryValidator() { s.Require().NotEqual("internal", err.Error()) } else { var result types.Validator - s.Require().NoError(clientCtx.JSONMarshaler.UnmarshalJSON(out.Bytes(), &result)) + s.Require().NoError(clientCtx.Codec.UnmarshalJSON(out.Bytes(), &result)) s.Require().Equal(val.ValAddress.String(), result.OperatorAddress) } }) @@ -280,7 +296,7 @@ func (s *IntegrationTestSuite) TestGetCmdQueryValidators() { s.Require().NoError(err) var result types.QueryValidatorsResponse - s.Require().NoError(clientCtx.JSONMarshaler.UnmarshalJSON(out.Bytes(), &result)) + s.Require().NoError(clientCtx.Codec.UnmarshalJSON(out.Bytes(), &result)) s.Require().Equal(tc.minValidatorCount, len(result.Validators)) }) } @@ -346,7 +362,7 @@ func (s *IntegrationTestSuite) TestGetCmdQueryDelegation() { s.Require().Error(err) } else { s.Require().NoError(err) - s.Require().NoError(clientCtx.JSONMarshaler.UnmarshalJSON(out.Bytes(), tc.respType), out.String()) + s.Require().NoError(clientCtx.Codec.UnmarshalJSON(out.Bytes(), tc.respType), out.String()) s.Require().Equal(tc.expected.String(), tc.respType.String()) } }) @@ -402,14 +418,14 @@ func (s *IntegrationTestSuite) TestGetCmdQueryDelegations() { s.Require().Error(err) } else { s.Require().NoError(err) - s.Require().NoError(clientCtx.JSONMarshaler.UnmarshalJSON(out.Bytes(), tc.respType), out.String()) + s.Require().NoError(clientCtx.Codec.UnmarshalJSON(out.Bytes(), tc.respType), out.String()) s.Require().Equal(tc.expected.String(), tc.respType.String()) } }) } } -func (s *IntegrationTestSuite) TestGetCmdQueryDelegationsTo() { +func (s *IntegrationTestSuite) TestGetCmdQueryValidatorDelegations() { val := s.network.Validators[0] testCases := []struct { @@ -458,7 +474,7 @@ func (s *IntegrationTestSuite) TestGetCmdQueryDelegationsTo() { s.Require().Error(err) } else { s.Require().NoError(err) - s.Require().NoError(clientCtx.JSONMarshaler.UnmarshalJSON(out.Bytes(), tc.respType), out.String()) + s.Require().NoError(clientCtx.Codec.UnmarshalJSON(out.Bytes(), tc.respType), out.String()) s.Require().Equal(tc.expected.String(), tc.respType.String()) } }) @@ -503,7 +519,7 @@ func (s *IntegrationTestSuite) TestGetCmdQueryUnbondingDelegations() { s.Require().Error(err) } else { var ubds types.QueryDelegatorUnbondingDelegationsResponse - err = val.ClientCtx.JSONMarshaler.UnmarshalJSON(out.Bytes(), &ubds) + err = val.ClientCtx.Codec.UnmarshalJSON(out.Bytes(), &ubds) s.Require().NoError(err) s.Require().Len(ubds.UnbondingResponses, 1) @@ -563,7 +579,7 @@ func (s *IntegrationTestSuite) TestGetCmdQueryUnbondingDelegation() { } else { var ubd types.UnbondingDelegation - err = val.ClientCtx.JSONMarshaler.UnmarshalJSON(out.Bytes(), &ubd) + err = val.ClientCtx.Codec.UnmarshalJSON(out.Bytes(), &ubd) s.Require().NoError(err) s.Require().Equal(ubd.DelegatorAddress, val.Address.String()) s.Require().Equal(ubd.ValidatorAddress, val.ValAddress.String()) @@ -611,7 +627,7 @@ func (s *IntegrationTestSuite) TestGetCmdQueryValidatorUnbondingDelegations() { s.Require().Error(err) } else { var ubds types.QueryValidatorUnbondingDelegationsResponse - err = val.ClientCtx.JSONMarshaler.UnmarshalJSON(out.Bytes(), &ubds) + err = val.ClientCtx.Codec.UnmarshalJSON(out.Bytes(), &ubds) s.Require().NoError(err) s.Require().Len(ubds.UnbondingResponses, 1) @@ -660,7 +676,7 @@ func (s *IntegrationTestSuite) TestGetCmdQueryRedelegations() { s.Require().Error(err) } else { var redelegations types.QueryRedelegationsResponse - err = val.ClientCtx.JSONMarshaler.UnmarshalJSON(out.Bytes(), &redelegations) + err = val.ClientCtx.Codec.UnmarshalJSON(out.Bytes(), &redelegations) s.Require().NoError(err) @@ -737,7 +753,7 @@ func (s *IntegrationTestSuite) TestGetCmdQueryRedelegation() { } else { var redelegations types.QueryRedelegationsResponse - err = val.ClientCtx.JSONMarshaler.UnmarshalJSON(out.Bytes(), &redelegations) + err = val.ClientCtx.Codec.UnmarshalJSON(out.Bytes(), &redelegations) s.Require().NoError(err) s.Require().Len(redelegations.RedelegationResponses, 1) @@ -749,7 +765,7 @@ func (s *IntegrationTestSuite) TestGetCmdQueryRedelegation() { } } -func (s *IntegrationTestSuite) TestGetCmdQueryRedelegationsFrom() { +func (s *IntegrationTestSuite) TestGetCmdQueryValidatorRedelegations() { val := s.network.Validators[0] val2 := s.network.Validators[1] @@ -788,7 +804,7 @@ func (s *IntegrationTestSuite) TestGetCmdQueryRedelegationsFrom() { s.Require().Error(err) } else { var redelegations types.QueryRedelegationsResponse - err = val.ClientCtx.JSONMarshaler.UnmarshalJSON(out.Bytes(), &redelegations) + err = val.ClientCtx.Codec.UnmarshalJSON(out.Bytes(), &redelegations) s.Require().NoError(err) @@ -837,11 +853,11 @@ func (s *IntegrationTestSuite) TestGetCmdQueryHistoricalInfo() { if tc.error { s.Require().Error(err) } else { - var historical_info types.HistoricalInfo + var historicalInfo types.HistoricalInfo - err = val.ClientCtx.JSONMarshaler.UnmarshalJSON(out.Bytes(), &historical_info) + err = val.ClientCtx.Codec.UnmarshalJSON(out.Bytes(), &historicalInfo) s.Require().NoError(err) - s.Require().NotNil(historical_info) + s.Require().NotNil(historicalInfo) } }) } @@ -918,7 +934,7 @@ not_bonded_tokens: "0"`, cli.DefaultTokens.Mul(sdk.NewInt(2)).String()), } } -func (s *IntegrationTestSuite) TestNewCmdEditValidator() { +func (s *IntegrationTestSuite) TestNewEditValidatorCmd() { val := s.network.Validators[0] details := "bio" @@ -930,8 +946,8 @@ func (s *IntegrationTestSuite) TestNewCmdEditValidator() { name string args []string expectErr bool - respType proto.Message expectedCode uint32 + respType proto.Message }{ { "with no edit flag (since all are optional)", @@ -941,7 +957,7 @@ func (s *IntegrationTestSuite) TestNewCmdEditValidator() { fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), }, - true, nil, 0, + true, 0, nil, }, { "with no edit flag (since all are optional)", @@ -951,7 +967,7 @@ func (s *IntegrationTestSuite) TestNewCmdEditValidator() { fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), }, - false, &sdk.TxResponse{}, 0, + false, 0, &sdk.TxResponse{}, }, { "edit validator details", @@ -962,7 +978,7 @@ func (s *IntegrationTestSuite) TestNewCmdEditValidator() { fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), }, - false, &sdk.TxResponse{}, 0, + false, 0, &sdk.TxResponse{}, }, { "edit validator identity", @@ -973,7 +989,7 @@ func (s *IntegrationTestSuite) TestNewCmdEditValidator() { fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), }, - false, &sdk.TxResponse{}, 0, + false, 0, &sdk.TxResponse{}, }, { "edit validator security-contact", @@ -984,7 +1000,7 @@ func (s *IntegrationTestSuite) TestNewCmdEditValidator() { fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), }, - false, &sdk.TxResponse{}, 0, + false, 0, &sdk.TxResponse{}, }, { "edit validator website", @@ -995,7 +1011,7 @@ func (s *IntegrationTestSuite) TestNewCmdEditValidator() { fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), }, - false, &sdk.TxResponse{}, 0, + false, 0, &sdk.TxResponse{}, }, { "with all edit flags", @@ -1009,7 +1025,7 @@ func (s *IntegrationTestSuite) TestNewCmdEditValidator() { fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), }, - false, &sdk.TxResponse{}, 0, + false, 0, &sdk.TxResponse{}, }, } @@ -1025,7 +1041,7 @@ func (s *IntegrationTestSuite) TestNewCmdEditValidator() { s.Require().Error(err) } else { s.Require().NoError(err, out.String()) - s.Require().NoError(clientCtx.JSONMarshaler.UnmarshalJSON(out.Bytes(), tc.respType), out.String()) + s.Require().NoError(clientCtx.Codec.UnmarshalJSON(out.Bytes(), tc.respType), out.String()) txResp := tc.respType.(*sdk.TxResponse) s.Require().Equal(tc.expectedCode, txResp.Code, out.String()) @@ -1034,10 +1050,10 @@ func (s *IntegrationTestSuite) TestNewCmdEditValidator() { } } -func (s *IntegrationTestSuite) TestNewCmdDelegate() { +func (s *IntegrationTestSuite) TestNewDelegateCmd() { val := s.network.Validators[0] - info, _, err := val.ClientCtx.Keyring.NewMnemonic("NewAccount", keyring.English, sdk.FullFundraiserPath, hd.Secp256k1) + info, _, err := val.ClientCtx.Keyring.NewMnemonic("NewAccount", keyring.English, sdk.FullFundraiserPath, keyring.DefaultBIP39Passphrase, hd.Secp256k1) s.Require().NoError(err) newAddr := sdk.BytesToAccAddress(info.GetPubKey().Address()) @@ -1056,8 +1072,8 @@ func (s *IntegrationTestSuite) TestNewCmdDelegate() { name string args []string expectErr bool - respType proto.Message expectedCode uint32 + respType proto.Message }{ { "without delegate amount", @@ -1068,7 +1084,7 @@ func (s *IntegrationTestSuite) TestNewCmdDelegate() { fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), }, - true, nil, 0, + true, 0, nil, }, { "without validator address", @@ -1079,7 +1095,7 @@ func (s *IntegrationTestSuite) TestNewCmdDelegate() { fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), }, - true, nil, 0, + true, 0, nil, }, { "valid transaction of delegate", @@ -1091,7 +1107,7 @@ func (s *IntegrationTestSuite) TestNewCmdDelegate() { fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), }, - false, &sdk.TxResponse{}, 0, + false, 0, &sdk.TxResponse{}, }, } @@ -1107,7 +1123,7 @@ func (s *IntegrationTestSuite) TestNewCmdDelegate() { s.Require().Error(err) } else { s.Require().NoError(err, out.String()) - s.Require().NoError(clientCtx.JSONMarshaler.UnmarshalJSON(out.Bytes(), tc.respType), out.String()) + s.Require().NoError(clientCtx.Codec.UnmarshalJSON(out.Bytes(), tc.respType), out.String()) txResp := tc.respType.(*sdk.TxResponse) s.Require().Equal(tc.expectedCode, txResp.Code, out.String()) @@ -1116,7 +1132,7 @@ func (s *IntegrationTestSuite) TestNewCmdDelegate() { } } -func (s *IntegrationTestSuite) TestNewCmdRedelegate() { +func (s *IntegrationTestSuite) TestNewRedelegateCmd() { val := s.network.Validators[0] val2 := s.network.Validators[1] @@ -1124,8 +1140,8 @@ func (s *IntegrationTestSuite) TestNewCmdRedelegate() { name string args []string expectErr bool - respType proto.Message expectedCode uint32 + respType proto.Message }{ { "without amount", @@ -1137,7 +1153,7 @@ func (s *IntegrationTestSuite) TestNewCmdRedelegate() { fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), }, - true, nil, 0, + true, 0, nil, }, { "with wrong source validator address", @@ -1150,7 +1166,7 @@ func (s *IntegrationTestSuite) TestNewCmdRedelegate() { fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), }, - false, &sdk.TxResponse{}, 4, + false, 3, &sdk.TxResponse{}, }, { "with wrong destination validator address", @@ -1163,7 +1179,7 @@ func (s *IntegrationTestSuite) TestNewCmdRedelegate() { fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), }, - false, &sdk.TxResponse{}, 39, + false, 31, &sdk.TxResponse{}, }, { "valid transaction of delegate", @@ -1177,7 +1193,7 @@ func (s *IntegrationTestSuite) TestNewCmdRedelegate() { fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), }, - false, &sdk.TxResponse{}, 0, + false, 0, &sdk.TxResponse{}, }, } @@ -1193,7 +1209,7 @@ func (s *IntegrationTestSuite) TestNewCmdRedelegate() { s.Require().Error(err) } else { s.Require().NoError(err, out.String()) - s.Require().NoError(clientCtx.JSONMarshaler.UnmarshalJSON(out.Bytes(), tc.respType), out.String()) + s.Require().NoError(clientCtx.Codec.UnmarshalJSON(out.Bytes(), tc.respType), out.String()) txResp := tc.respType.(*sdk.TxResponse) s.Require().Equal(tc.expectedCode, txResp.Code, out.String()) @@ -1202,15 +1218,15 @@ func (s *IntegrationTestSuite) TestNewCmdRedelegate() { } } -func (s *IntegrationTestSuite) TestNewCmdUnbond() { +func (s *IntegrationTestSuite) TestNewUnbondCmd() { val := s.network.Validators[0] testCases := []struct { name string args []string expectErr bool - respType proto.Message expectedCode uint32 + respType proto.Message }{ { "Without unbond amount", @@ -1221,7 +1237,7 @@ func (s *IntegrationTestSuite) TestNewCmdUnbond() { fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), }, - true, nil, 0, + true, 0, nil, }, { "Without validator address", @@ -1232,7 +1248,7 @@ func (s *IntegrationTestSuite) TestNewCmdUnbond() { fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), }, - true, nil, 0, + true, 0, nil, }, { "valid transaction of unbond", @@ -1244,7 +1260,7 @@ func (s *IntegrationTestSuite) TestNewCmdUnbond() { fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), }, - false, &sdk.TxResponse{}, 0, + false, 0, &sdk.TxResponse{}, }, } @@ -1260,7 +1276,7 @@ func (s *IntegrationTestSuite) TestNewCmdUnbond() { s.Require().Error(err) } else { s.Require().NoError(err, out.String()) - s.Require().NoError(clientCtx.JSONMarshaler.UnmarshalJSON(out.Bytes(), tc.respType), out.String()) + s.Require().NoError(clientCtx.Codec.UnmarshalJSON(out.Bytes(), tc.respType), out.String()) txResp := tc.respType.(*sdk.TxResponse) s.Require().Equal(tc.expectedCode, txResp.Code, out.String()) @@ -1277,7 +1293,7 @@ func (s *IntegrationTestSuite) TestBlockResults() { val := s.network.Validators[0] // Create new account in the keyring. - info, _, err := val.ClientCtx.Keyring.NewMnemonic("NewDelegator", keyring.English, sdk.FullFundraiserPath, hd.Secp256k1) + info, _, err := val.ClientCtx.Keyring.NewMnemonic("NewDelegator", keyring.English, sdk.FullFundraiserPath, keyring.DefaultBIP39Passphrase, hd.Secp256k1) require.NoError(err) newAddr := sdk.BytesToAccAddress(info.GetPubKey().Address()) @@ -1308,6 +1324,7 @@ func (s *IntegrationTestSuite) TestBlockResults() { // Create a HTTP rpc client. rpcClient, err := http.New(val.RPCAddress, "/websocket") + require.NoError(err) // Loop until we find a block result with the correct validator updates. // By experience, it happens around 2 blocks after `delHeight`. @@ -1337,7 +1354,3 @@ func (s *IntegrationTestSuite) TestBlockResults() { s.network.WaitForNextBlock() } } - -func TestIntegrationTestSuite(t *testing.T) { - suite.Run(t, new(IntegrationTestSuite)) -} diff --git a/x/staking/client/testutil/test_helpers.go b/x/staking/client/testutil/test_helpers.go index b48c631432..eee7ddbb84 100644 --- a/x/staking/client/testutil/test_helpers.go +++ b/x/staking/client/testutil/test_helpers.go @@ -26,7 +26,9 @@ func MsgRedelegateExec(clientCtx client.Context, from, src, dst, amount fmt.Stri dst.String(), amount.String(), fmt.Sprintf("--%s=%s", flags.FlagFrom, from.String()), + fmt.Sprintf("--%s=%d", flags.FlagGas, 300000), } + args = append(args, extraArgs...) args = append(args, commonArgs...) return clitestutil.ExecTestCLICmd(clientCtx, stakingcli.NewRedelegateCmd(), args) @@ -43,5 +45,6 @@ func MsgUnbondExec(clientCtx client.Context, from fmt.Stringer, valAddress, } args = append(args, commonArgs...) + args = append(args, extraArgs...) return clitestutil.ExecTestCLICmd(clientCtx, stakingcli.NewUnbondCmd(), args) } diff --git a/x/staking/common_test.go b/x/staking/common_test.go index fd690d36ac..0fc5aa6edd 100644 --- a/x/staking/common_test.go +++ b/x/staking/common_test.go @@ -15,7 +15,7 @@ import ( ) func init() { - sdk.PowerReduction = sdk.NewIntFromBigInt(new(big.Int).Exp(big.NewInt(10), big.NewInt(18), nil)) + sdk.DefaultPowerReduction = sdk.NewIntFromBigInt(new(big.Int).Exp(big.NewInt(10), big.NewInt(18), nil)) } // nolint:deadcode,unused,varcheck diff --git a/x/staking/exported/exported.go b/x/staking/exported/exported.go deleted file mode 100644 index eabd8aa3dd..0000000000 --- a/x/staking/exported/exported.go +++ /dev/null @@ -1 +0,0 @@ -package exported diff --git a/x/staking/genesis.go b/x/staking/genesis.go index 3038174baa..904d4e7642 100644 --- a/x/staking/genesis.go +++ b/x/staking/genesis.go @@ -102,30 +102,28 @@ func InitGenesis( if bondedPool == nil { panic(fmt.Sprintf("%s module account has not been set", types.BondedPoolName)) } - // TODO remove with genesis 2-phases refactor https://github.com/cosmos/cosmos-sdk/issues/2862 - // add coins if not provided on genesis - if bankKeeper.GetAllBalances(ctx, bondedPool.GetAddress()).IsZero() { - if err := bankKeeper.SetBalances(ctx, bondedPool.GetAddress(), bondedCoins); err != nil { - panic(err) - } - + bondedBalance := bankKeeper.GetAllBalances(ctx, bondedPool.GetAddress()) + if bondedBalance.IsZero() { accountKeeper.SetModuleAccount(ctx, bondedPool) } - + // if balance is different from bonded coins panic because genesis is most likely malformed + if !bondedBalance.IsEqual(bondedCoins) { + panic(fmt.Sprintf("bonded pool balance is different from bonded coins: %s <-> %s", bondedBalance, bondedCoins)) + } notBondedPool := keeper.GetNotBondedPool(ctx) if notBondedPool == nil { panic(fmt.Sprintf("%s module account has not been set", types.NotBondedPoolName)) } - if bankKeeper.GetAllBalances(ctx, notBondedPool.GetAddress()).IsZero() { - if err := bankKeeper.SetBalances(ctx, notBondedPool.GetAddress(), notBondedCoins); err != nil { - panic(err) - } - + notBondedBalance := bankKeeper.GetAllBalances(ctx, notBondedPool.GetAddress()) + if notBondedBalance.IsZero() { accountKeeper.SetModuleAccount(ctx, notBondedPool) } - + // if balance is different from non bonded coins panic because genesis is most likely malformed + if !notBondedBalance.IsEqual(notBondedCoins) { + panic(fmt.Sprintf("not bonded pool balance is different from not bonded coins: %s <-> %s", notBondedBalance, notBondedCoins)) + } // don't need to run Tendermint updates if we exported if data.Exported { for _, lv := range data.LastValidatorPowers { @@ -137,7 +135,7 @@ func InitGenesis( panic(fmt.Sprintf("validator %s not found", lv.Address)) } - update := validator.ABCIValidatorUpdate() + update := validator.ABCIValidatorUpdate(keeper.PowerReduction(ctx)) update.Power = lv.Power // keep the next-val-set offset, use the last power for the first block res = append(res, update) } @@ -204,7 +202,7 @@ func WriteValidators(ctx sdk.Context, keeper keeper.Keeper) (vals []octypes.Gene vals = append(vals, octypes.GenesisValidator{ Address: tmPk.Address(), PubKey: tmPk, - Power: validator.GetConsensusPower(), + Power: validator.GetConsensusPower(keeper.PowerReduction(ctx)), Name: validator.GetMoniker(), }) @@ -233,17 +231,22 @@ func validateGenesisStateValidators(validators []types.Validator) error { if err != nil { return err } - consAddr, err := val.GetConsAddr() - if err != nil { - return err - } + strKey := string(consPk.Bytes()) if _, ok := addrMap[strKey]; ok { + consAddr, err := val.GetConsAddr() + if err != nil { + return err + } return fmt.Errorf("duplicate validator in genesis state: moniker %v, address %v", val.Description.Moniker, consAddr) } if val.Jailed && val.IsBonded() { + consAddr, err := val.GetConsAddr() + if err != nil { + return err + } return fmt.Errorf("validator is bonded and jailed in genesis state: moniker %v, address %v", val.Description.Moniker, consAddr) } diff --git a/x/staking/genesis_test.go b/x/staking/genesis_test.go index aae03ed8c7..9555eb5201 100644 --- a/x/staking/genesis_test.go +++ b/x/staking/genesis_test.go @@ -2,9 +2,11 @@ package staking_test import ( "fmt" + "log" "testing" abci "github.com/line/ostracon/abci/types" + ocproto "github.com/line/ostracon/proto/ostracon/types" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -12,37 +14,25 @@ import ( "github.com/line/lbm-sdk/crypto/keys/ed25519" "github.com/line/lbm-sdk/simapp" sdk "github.com/line/lbm-sdk/types" - banktypes "github.com/line/lbm-sdk/x/bank/types" "github.com/line/lbm-sdk/x/staking" "github.com/line/lbm-sdk/x/staking/teststaking" "github.com/line/lbm-sdk/x/staking/types" ) -func bootstrapGenesisTest(t *testing.T, power int64, numAddrs int) (*simapp.SimApp, sdk.Context, []sdk.AccAddress) { +func bootstrapGenesisTest(numAddrs int) (*simapp.SimApp, sdk.Context, []sdk.AccAddress) { _, app, ctx := getBaseSimappWithCustomKeeper() addrDels, _ := generateAddresses(app, ctx, numAddrs, sdk.NewInt(10000)) - - amt := sdk.TokensFromConsensusPower(power) - totalSupply := sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), amt.MulRaw(int64(len(addrDels))))) - - notBondedPool := app.StakingKeeper.GetNotBondedPool(ctx) - err := app.BankKeeper.SetBalances(ctx, notBondedPool.GetAddress(), totalSupply) - require.NoError(t, err) - - app.AccountKeeper.SetModuleAccount(ctx, notBondedPool) - app.BankKeeper.SetSupply(ctx, banktypes.NewSupply(totalSupply)) - return app, ctx, addrDels } func TestInitGenesis(t *testing.T) { - app, ctx, addrs := bootstrapGenesisTest(t, 1000, 10) + app, ctx, addrs := bootstrapGenesisTest(10) - valTokens := sdk.TokensFromConsensusPower(1) + valTokens := app.StakingKeeper.TokensFromConsensusPower(ctx, 1) params := app.StakingKeeper.GetParams(ctx) - validators := make([]types.Validator, 2) + validators := app.StakingKeeper.GetAllValidators(ctx) var delegations []types.Delegation pk0, err := codectypes.NewAnyWithValue(PKs[0]) @@ -52,19 +42,37 @@ func TestInitGenesis(t *testing.T) { require.NoError(t, err) // initialize the validators - validators[0].OperatorAddress = addrs[0].ToValAddress().String() - validators[0].ConsensusPubkey = pk0 - validators[0].Description = types.NewDescription("hoop", "", "", "", "") - validators[0].Status = types.Bonded - validators[0].Tokens = valTokens - validators[0].DelegatorShares = valTokens.ToDec() - validators[1].OperatorAddress = addrs[1].ToValAddress().String() - validators[1].ConsensusPubkey = pk1 - validators[1].Description = types.NewDescription("bloop", "", "", "", "") - validators[1].Status = types.Bonded - validators[1].Tokens = valTokens - validators[1].DelegatorShares = valTokens.ToDec() + bondedVal1 := types.Validator{ + OperatorAddress: addrs[0].ToValAddress().String(), + ConsensusPubkey: pk0, + Status: types.Bonded, + Tokens: valTokens, + DelegatorShares: valTokens.ToDec(), + Description: types.NewDescription("hoop", "", "", "", ""), + } + bondedVal2 := types.Validator{ + OperatorAddress: addrs[1].ToValAddress().String(), + ConsensusPubkey: pk1, + Status: types.Bonded, + Tokens: valTokens, + DelegatorShares: valTokens.ToDec(), + Description: types.NewDescription("bloop", "", "", "", ""), + } + // append new bonded validators to the list + validators = append(validators, bondedVal1, bondedVal2) + log.Printf("%#v", len(validators)) + // mint coins in the bonded pool representing the validators coins + require.NoError(t, + simapp.FundModuleAccount( + app, + ctx, + types.BondedPoolName, + sdk.NewCoins( + sdk.NewCoin(params.BondDenom, valTokens.MulRaw((int64)(len(validators)))), + ), + ), + ) genesisState := types.NewGenesisState(params, validators, delegations) vals := staking.InitGenesis(ctx, app.StakingKeeper, app.AccountKeeper, app.BankKeeper, genesisState) @@ -91,42 +99,102 @@ func TestInitGenesis(t *testing.T) { abcivals := make([]abci.ValidatorUpdate, len(vals)) for i, val := range validators { - abcivals[i] = val.ABCIValidatorUpdate() + abcivals[i] = val.ABCIValidatorUpdate(app.StakingKeeper.PowerReduction(ctx)) } require.Equal(t, abcivals, vals) } +func TestInitGenesis_PoolsBalanceMismatch(t *testing.T) { + app := simapp.Setup(false) + ctx := app.NewContext(false, ocproto.Header{}) + + consPub, err := codectypes.NewAnyWithValue(PKs[0]) + require.NoError(t, err) + + // create mock validator + validator := types.Validator{ + OperatorAddress: sdk.ValAddress("12345678901234567890").String(), + ConsensusPubkey: consPub, + Jailed: false, + Tokens: sdk.NewInt(10), + DelegatorShares: sdk.NewInt(10).ToDec(), + Description: types.NewDescription("bloop", "", "", "", ""), + } + // valid params + params := types.Params{ + UnbondingTime: 10000, + MaxValidators: 1, + MaxEntries: 10, + BondDenom: "stake", + } + + // test + + require.Panics(t, func() { + // setting validator status to bonded so the balance counts towards bonded pool + validator.Status = types.Bonded + staking.InitGenesis(ctx, app.StakingKeeper, app.AccountKeeper, app.BankKeeper, &types.GenesisState{ + Params: params, + Validators: []types.Validator{validator}, + }) + }, "should panic because bonded pool balance is different from bonded pool coins") + + require.Panics(t, func() { + // setting validator status to unbonded so the balance counts towards not bonded pool + validator.Status = types.Unbonded + staking.InitGenesis(ctx, app.StakingKeeper, app.AccountKeeper, app.BankKeeper, &types.GenesisState{ + Params: params, + Validators: []types.Validator{validator}, + }) + }, "should panic because not bonded pool balance is different from not bonded pool coins") +} + func TestInitGenesisLargeValidatorSet(t *testing.T) { size := 200 require.True(t, size > 100) - app, ctx, addrs := bootstrapGenesisTest(t, 1000, 200) + app, ctx, addrs := bootstrapGenesisTest(200) params := app.StakingKeeper.GetParams(ctx) delegations := []types.Delegation{} validators := make([]types.Validator, size) var err error + + bondedPoolAmt := sdk.ZeroInt() for i := range validators { validators[i], err = types.NewValidator(addrs[i].ToValAddress(), PKs[i], types.NewDescription(fmt.Sprintf("#%d", i), "", "", "", "")) require.NoError(t, err) validators[i].Status = types.Bonded - tokens := sdk.TokensFromConsensusPower(1) + tokens := app.StakingKeeper.TokensFromConsensusPower(ctx, 1) if i < 100 { - tokens = sdk.TokensFromConsensusPower(2) + tokens = app.StakingKeeper.TokensFromConsensusPower(ctx, 2) } validators[i].Tokens = tokens validators[i].DelegatorShares = tokens.ToDec() + // add bonded coins + bondedPoolAmt = bondedPoolAmt.Add(tokens) } genesisState := types.NewGenesisState(params, validators, delegations) + + // mint coins in the bonded pool representing the validators coins + require.NoError(t, + simapp.FundModuleAccount( + app, + ctx, + types.BondedPoolName, + sdk.NewCoins(sdk.NewCoin(params.BondDenom, bondedPoolAmt)), + ), + ) + vals := staking.InitGenesis(ctx, app.StakingKeeper, app.AccountKeeper, app.BankKeeper, genesisState) abcivals := make([]abci.ValidatorUpdate, 100) for i, val := range validators[:100] { - abcivals[i] = val.ABCIValidatorUpdate() + abcivals[i] = val.ABCIValidatorUpdate(app.StakingKeeper.PowerReduction(ctx)) } require.Equal(t, abcivals, vals) diff --git a/x/staking/handler_test.go b/x/staking/handler_test.go index fc0e2541b1..52f5615de9 100644 --- a/x/staking/handler_test.go +++ b/x/staking/handler_test.go @@ -5,14 +5,13 @@ import ( "testing" "time" + "github.com/golang/protobuf/proto" abci "github.com/line/ostracon/abci/types" ocproto "github.com/line/ostracon/proto/ostracon/types" octypes "github.com/line/ostracon/types" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/golang/protobuf/proto" - cryptocodec "github.com/line/lbm-sdk/crypto/codec" "github.com/line/lbm-sdk/crypto/keys/ed25519" "github.com/line/lbm-sdk/crypto/keys/secp256k1" @@ -20,7 +19,6 @@ import ( "github.com/line/lbm-sdk/simapp" "github.com/line/lbm-sdk/testutil/testdata" sdk "github.com/line/lbm-sdk/types" - banktypes "github.com/line/lbm-sdk/x/bank/types" "github.com/line/lbm-sdk/x/staking" "github.com/line/lbm-sdk/x/staking/keeper" "github.com/line/lbm-sdk/x/staking/teststaking" @@ -32,22 +30,20 @@ func bootstrapHandlerGenesisTest(t *testing.T, power int64, numAddrs int, accAmo addrDels, addrVals := generateAddresses(app, ctx, numAddrs, accAmount) - amt := sdk.TokensFromConsensusPower(power) + amt := app.StakingKeeper.TokensFromConsensusPower(ctx, power) totalSupply := sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), amt.MulRaw(int64(len(addrDels))))) notBondedPool := app.StakingKeeper.GetNotBondedPool(ctx) - err := app.BankKeeper.SetBalances(ctx, notBondedPool.GetAddress(), totalSupply) - require.NoError(t, err) + // set non bonded pool balance app.AccountKeeper.SetModuleAccount(ctx, notBondedPool) - app.BankKeeper.SetSupply(ctx, banktypes.NewSupply(totalSupply)) - + require.NoError(t, simapp.FundModuleAccount(app, ctx, notBondedPool.GetName(), totalSupply)) return app, ctx, addrDels, addrVals } func TestValidatorByPowerIndex(t *testing.T) { initPower := int64(1000000) - app, ctx, _, valAddrs := bootstrapHandlerGenesisTest(t, initPower, 10, sdk.TokensFromConsensusPower(initPower)) + app, ctx, _, valAddrs := bootstrapHandlerGenesisTest(t, initPower, 10, sdk.TokensFromConsensusPower(initPower, sdk.DefaultPowerReduction)) validatorAddr, validatorAddr3 := valAddrs[0], valAddrs[1] tstaking := teststaking.NewHelper(t, ctx, app.StakingKeeper) @@ -68,7 +64,7 @@ func TestValidatorByPowerIndex(t *testing.T) { // verify that the by power index exists validator, found := app.StakingKeeper.GetValidator(ctx, validatorAddr) require.True(t, found) - power := types.GetValidatorsByPowerIndexKey(validator) + power := types.GetValidatorsByPowerIndexKey(validator, app.StakingKeeper.PowerReduction(ctx)) require.True(t, keeper.ValidatorByPowerIndexExists(ctx, app.StakingKeeper, power)) // create a second validator keep it bonded @@ -97,11 +93,11 @@ func TestValidatorByPowerIndex(t *testing.T) { // but the new power record should have been created validator, found = app.StakingKeeper.GetValidator(ctx, validatorAddr) require.True(t, found) - power2 := types.GetValidatorsByPowerIndexKey(validator) + power2 := types.GetValidatorsByPowerIndexKey(validator, app.StakingKeeper.PowerReduction(ctx)) require.True(t, keeper.ValidatorByPowerIndexExists(ctx, app.StakingKeeper, power2)) // now the new record power index should be the same as the original record - power3 := types.GetValidatorsByPowerIndexKey(validator) + power3 := types.GetValidatorsByPowerIndexKey(validator, app.StakingKeeper.PowerReduction(ctx)) require.Equal(t, power2, power3) // unbond self-delegation @@ -124,7 +120,7 @@ func TestValidatorByPowerIndex(t *testing.T) { func TestDuplicatesMsgCreateValidator(t *testing.T) { initPower := int64(1000000) - app, ctx, _, valAddrs := bootstrapHandlerGenesisTest(t, initPower, 10, sdk.TokensFromConsensusPower(initPower)) + app, ctx, _, valAddrs := bootstrapHandlerGenesisTest(t, initPower, 10, sdk.TokensFromConsensusPower(initPower, sdk.DefaultPowerReduction)) addr1, addr2 := valAddrs[0], valAddrs[1] pk1, pk2 := PKs[0], PKs[1] @@ -172,7 +168,7 @@ func TestDuplicatesMsgCreateValidator(t *testing.T) { func TestInvalidPubKeyTypeMsgCreateValidator(t *testing.T) { initPower := int64(1000) - app, ctx, _, valAddrs := bootstrapHandlerGenesisTest(t, initPower, 1, sdk.TokensFromConsensusPower(initPower)) + app, ctx, _, valAddrs := bootstrapHandlerGenesisTest(t, initPower, 1, sdk.TokensFromConsensusPower(initPower, sdk.DefaultPowerReduction)) ctx = ctx.WithConsensusParams(&abci.ConsensusParams{ Validator: &ocproto.ValidatorParams{PubKeyTypes: []string{octypes.ABCIPubKeyTypeEd25519}}, }) @@ -218,7 +214,7 @@ func TestBothPubKeyTypesMsgCreateValidator(t *testing.T) { func TestLegacyValidatorDelegations(t *testing.T) { initPower := int64(1000) - app, ctx, delAddrs, valAddrs := bootstrapHandlerGenesisTest(t, initPower, 2, sdk.TokensFromConsensusPower(initPower)) + app, ctx, delAddrs, valAddrs := bootstrapHandlerGenesisTest(t, initPower, 2, sdk.TokensFromConsensusPower(initPower, sdk.DefaultPowerReduction)) tstaking := teststaking.NewHelper(t, ctx, app.StakingKeeper) valAddr := valAddrs[0] @@ -297,8 +293,8 @@ func TestLegacyValidatorDelegations(t *testing.T) { func TestIncrementsMsgDelegate(t *testing.T) { initPower := int64(1000) - initBond := sdk.TokensFromConsensusPower(initPower) - app, ctx, delAddrs, valAddrs := bootstrapHandlerGenesisTest(t, initPower, 2, sdk.TokensFromConsensusPower(initPower)) + initBond := sdk.TokensFromConsensusPower(initPower, sdk.DefaultPowerReduction) + app, ctx, delAddrs, valAddrs := bootstrapHandlerGenesisTest(t, initPower, 2, sdk.TokensFromConsensusPower(initPower, sdk.DefaultPowerReduction)) params := app.StakingKeeper.GetParams(ctx) validatorAddr, delegatorAddr := valAddrs[0], delAddrs[1] @@ -356,8 +352,8 @@ func TestIncrementsMsgDelegate(t *testing.T) { func TestEditValidatorDecreaseMinSelfDelegation(t *testing.T) { initPower := int64(100) - initBond := sdk.TokensFromConsensusPower(100) - app, ctx, _, valAddrs := bootstrapHandlerGenesisTest(t, initPower, 1, sdk.TokensFromConsensusPower(initPower)) + initBond := sdk.TokensFromConsensusPower(100, sdk.DefaultPowerReduction) + app, ctx, _, valAddrs := bootstrapHandlerGenesisTest(t, initPower, 1, sdk.TokensFromConsensusPower(initPower, sdk.DefaultPowerReduction)) validatorAddr := valAddrs[0] tstaking := teststaking.NewHelper(t, ctx, app.StakingKeeper) @@ -387,9 +383,9 @@ func TestEditValidatorDecreaseMinSelfDelegation(t *testing.T) { func TestEditValidatorIncreaseMinSelfDelegationBeyondCurrentBond(t *testing.T) { initPower := int64(100) - initBond := sdk.TokensFromConsensusPower(100) + initBond := sdk.TokensFromConsensusPower(100, sdk.DefaultPowerReduction) - app, ctx, _, valAddrs := bootstrapHandlerGenesisTest(t, initPower, 2, sdk.TokensFromConsensusPower(initPower)) + app, ctx, _, valAddrs := bootstrapHandlerGenesisTest(t, initPower, 2, sdk.TokensFromConsensusPower(initPower, sdk.DefaultPowerReduction)) validatorAddr := valAddrs[0] tstaking := teststaking.NewHelper(t, ctx, app.StakingKeeper) @@ -419,7 +415,7 @@ func TestEditValidatorIncreaseMinSelfDelegationBeyondCurrentBond(t *testing.T) { func TestIncrementsMsgUnbond(t *testing.T) { initPower := int64(1000) - app, ctx, delAddrs, valAddrs := bootstrapHandlerGenesisTest(t, initPower, 2, sdk.TokensFromConsensusPower(initPower)) + app, ctx, delAddrs, valAddrs := bootstrapHandlerGenesisTest(t, initPower, 2, sdk.TokensFromConsensusPower(initPower, sdk.DefaultPowerReduction)) tstaking := teststaking.NewHelper(t, ctx, app.StakingKeeper) params := app.StakingKeeper.GetParams(ctx) denom := params.BondDenom @@ -491,8 +487,8 @@ func TestIncrementsMsgUnbond(t *testing.T) { errorCases := []sdk.Int{ //1<<64 - 1, // more than int64 power //1<<63 + 1, // more than int64 power - sdk.TokensFromConsensusPower(1<<63 - 1), - sdk.TokensFromConsensusPower(1 << 31), + app.StakingKeeper.TokensFromConsensusPower(ctx, 1<<63-1), + app.StakingKeeper.TokensFromConsensusPower(ctx, 1<<31), initBond, } @@ -507,8 +503,8 @@ func TestIncrementsMsgUnbond(t *testing.T) { func TestMultipleMsgCreateValidator(t *testing.T) { initPower := int64(1000) - initTokens := sdk.TokensFromConsensusPower(initPower) - app, ctx, delAddrs, valAddrs := bootstrapHandlerGenesisTest(t, initPower, 3, sdk.TokensFromConsensusPower(initPower)) + initTokens := sdk.TokensFromConsensusPower(initPower, sdk.DefaultPowerReduction) + app, ctx, delAddrs, valAddrs := bootstrapHandlerGenesisTest(t, initPower, 3, sdk.TokensFromConsensusPower(initPower, sdk.DefaultPowerReduction)) params := app.StakingKeeper.GetParams(ctx) blockTime := time.Now().UTC() @@ -527,7 +523,7 @@ func TestMultipleMsgCreateValidator(t *testing.T) { } // bond them all - amt := sdk.TokensFromConsensusPower(10) + amt := app.StakingKeeper.TokensFromConsensusPower(ctx, 10) for i, validatorAddr := range validatorAddrs { tstaking.CreateValidator(validatorAddr, PKs[i], amt, true) // verify that the account is bonded @@ -577,7 +573,7 @@ func TestMultipleMsgCreateValidator(t *testing.T) { func TestMultipleMsgDelegate(t *testing.T) { initPower := int64(1000) - app, ctx, delAddrs, valAddrs := bootstrapHandlerGenesisTest(t, initPower, 50, sdk.TokensFromConsensusPower(initPower)) + app, ctx, delAddrs, valAddrs := bootstrapHandlerGenesisTest(t, initPower, 50, sdk.TokensFromConsensusPower(initPower, sdk.DefaultPowerReduction)) validatorAddr, delegatorAddrs := valAddrs[0], delAddrs[1:] tstaking := teststaking.NewHelper(t, ctx, app.StakingKeeper) var amount int64 = 10 @@ -611,7 +607,7 @@ func TestMultipleMsgDelegate(t *testing.T) { func TestJailValidator(t *testing.T) { initPower := int64(1000) - app, ctx, delAddrs, valAddrs := bootstrapHandlerGenesisTest(t, initPower, 2, sdk.TokensFromConsensusPower(initPower)) + app, ctx, delAddrs, valAddrs := bootstrapHandlerGenesisTest(t, initPower, 2, sdk.TokensFromConsensusPower(initPower, sdk.DefaultPowerReduction)) validatorAddr, delegatorAddr := valAddrs[0], delAddrs[1] tstaking := teststaking.NewHelper(t, ctx, app.StakingKeeper) var amt int64 = 10 @@ -650,7 +646,7 @@ func TestJailValidator(t *testing.T) { func TestValidatorQueue(t *testing.T) { initPower := int64(1000) - app, ctx, delAddrs, valAddrs := bootstrapHandlerGenesisTest(t, initPower, 2, sdk.TokensFromConsensusPower(initPower)) + app, ctx, delAddrs, valAddrs := bootstrapHandlerGenesisTest(t, initPower, 2, sdk.TokensFromConsensusPower(initPower, sdk.DefaultPowerReduction)) validatorAddr, delegatorAddr := valAddrs[0], delAddrs[1] tstaking := teststaking.NewHelper(t, ctx, app.StakingKeeper) @@ -697,7 +693,7 @@ func TestValidatorQueue(t *testing.T) { func TestUnbondingPeriod(t *testing.T) { initPower := int64(1000) - app, ctx, _, valAddrs := bootstrapHandlerGenesisTest(t, initPower, 1, sdk.TokensFromConsensusPower(initPower)) + app, ctx, _, valAddrs := bootstrapHandlerGenesisTest(t, initPower, 1, sdk.TokensFromConsensusPower(initPower, sdk.DefaultPowerReduction)) validatorAddr := valAddrs[0] tstaking := teststaking.NewHelper(t, ctx, app.StakingKeeper) @@ -736,7 +732,7 @@ func TestUnbondingPeriod(t *testing.T) { func TestUnbondingFromUnbondingValidator(t *testing.T) { initPower := int64(1000) - app, ctx, delAddrs, valAddrs := bootstrapHandlerGenesisTest(t, initPower, 2, sdk.TokensFromConsensusPower(initPower)) + app, ctx, delAddrs, valAddrs := bootstrapHandlerGenesisTest(t, initPower, 2, sdk.TokensFromConsensusPower(initPower, sdk.DefaultPowerReduction)) validatorAddr, delegatorAddr := valAddrs[0], delAddrs[1] tstaking := teststaking.NewHelper(t, ctx, app.StakingKeeper) @@ -769,7 +765,7 @@ func TestUnbondingFromUnbondingValidator(t *testing.T) { func TestRedelegationPeriod(t *testing.T) { initPower := int64(1000) - app, ctx, _, valAddrs := bootstrapHandlerGenesisTest(t, initPower, 2, sdk.TokensFromConsensusPower(initPower)) + app, ctx, _, valAddrs := bootstrapHandlerGenesisTest(t, initPower, 2, sdk.TokensFromConsensusPower(initPower, sdk.DefaultPowerReduction)) validatorAddr, validatorAddr2 := valAddrs[0], valAddrs[1] denom := app.StakingKeeper.GetParams(ctx).BondDenom tstaking := teststaking.NewHelper(t, ctx, app.StakingKeeper) @@ -820,7 +816,7 @@ func TestRedelegationPeriod(t *testing.T) { func TestTransitiveRedelegation(t *testing.T) { initPower := int64(1000) - app, ctx, _, valAddrs := bootstrapHandlerGenesisTest(t, initPower, 3, sdk.TokensFromConsensusPower(initPower)) + app, ctx, _, valAddrs := bootstrapHandlerGenesisTest(t, initPower, 3, sdk.TokensFromConsensusPower(initPower, sdk.DefaultPowerReduction)) val1, val2, val3 := valAddrs[0], valAddrs[1], valAddrs[2] blockTime := time.Now().UTC() @@ -854,7 +850,7 @@ func TestTransitiveRedelegation(t *testing.T) { func TestMultipleRedelegationAtSameTime(t *testing.T) { initPower := int64(1000) - app, ctx, _, valAddrs := bootstrapHandlerGenesisTest(t, initPower, 2, sdk.TokensFromConsensusPower(initPower)) + app, ctx, _, valAddrs := bootstrapHandlerGenesisTest(t, initPower, 2, sdk.TokensFromConsensusPower(initPower, sdk.DefaultPowerReduction)) valAddr := valAddrs[0] valAddr2 := valAddrs[1] tstaking := teststaking.NewHelper(t, ctx, app.StakingKeeper) @@ -898,7 +894,7 @@ func TestMultipleRedelegationAtSameTime(t *testing.T) { func TestMultipleRedelegationAtUniqueTimes(t *testing.T) { initPower := int64(1000) - app, ctx, _, valAddrs := bootstrapHandlerGenesisTest(t, initPower, 2, sdk.TokensFromConsensusPower(initPower)) + app, ctx, _, valAddrs := bootstrapHandlerGenesisTest(t, initPower, 2, sdk.TokensFromConsensusPower(initPower, sdk.DefaultPowerReduction)) valAddr := valAddrs[0] valAddr2 := valAddrs[1] tstaking := teststaking.NewHelper(t, ctx, app.StakingKeeper) @@ -945,7 +941,7 @@ func TestMultipleRedelegationAtUniqueTimes(t *testing.T) { func TestMultipleUnbondingDelegationAtSameTime(t *testing.T) { initPower := int64(1000) - app, ctx, _, valAddrs := bootstrapHandlerGenesisTest(t, initPower, 1, sdk.TokensFromConsensusPower(initPower)) + app, ctx, _, valAddrs := bootstrapHandlerGenesisTest(t, initPower, 1, sdk.TokensFromConsensusPower(initPower, sdk.DefaultPowerReduction)) valAddr := valAddrs[0] tstaking := teststaking.NewHelper(t, ctx, app.StakingKeeper) @@ -985,7 +981,7 @@ func TestMultipleUnbondingDelegationAtSameTime(t *testing.T) { func TestMultipleUnbondingDelegationAtUniqueTimes(t *testing.T) { initPower := int64(1000) - app, ctx, _, valAddrs := bootstrapHandlerGenesisTest(t, initPower, 1, sdk.TokensFromConsensusPower(initPower)) + app, ctx, _, valAddrs := bootstrapHandlerGenesisTest(t, initPower, 1, sdk.TokensFromConsensusPower(initPower, sdk.DefaultPowerReduction)) valAddr := valAddrs[0] tstaking := teststaking.NewHelper(t, ctx, app.StakingKeeper) @@ -1033,7 +1029,7 @@ func TestMultipleUnbondingDelegationAtUniqueTimes(t *testing.T) { func TestUnbondingWhenExcessValidators(t *testing.T) { initPower := int64(1000) - app, ctx, _, valAddrs := bootstrapHandlerGenesisTest(t, initPower, 3, sdk.TokensFromConsensusPower(initPower)) + app, ctx, _, valAddrs := bootstrapHandlerGenesisTest(t, initPower, 3, sdk.TokensFromConsensusPower(initPower, sdk.DefaultPowerReduction)) val1 := valAddrs[0] val2 := valAddrs[1] val3 := valAddrs[2] @@ -1073,7 +1069,7 @@ func TestUnbondingWhenExcessValidators(t *testing.T) { func TestBondUnbondRedelegateSlashTwice(t *testing.T) { initPower := int64(1000) - app, ctx, delAddrs, valAddrs := bootstrapHandlerGenesisTest(t, initPower, 3, sdk.TokensFromConsensusPower(initPower)) + app, ctx, delAddrs, valAddrs := bootstrapHandlerGenesisTest(t, initPower, 3, sdk.TokensFromConsensusPower(initPower, sdk.DefaultPowerReduction)) valA, valB, del := valAddrs[0], valAddrs[1], delAddrs[2] consAddr0 := sdk.BytesToConsAddress(PKs[0].Address()) tstaking := teststaking.NewHelper(t, ctx, app.StakingKeeper) @@ -1094,11 +1090,11 @@ func TestBondUnbondRedelegateSlashTwice(t *testing.T) { tstaking.Ctx = ctx // begin unbonding 4 stake - unbondAmt := sdk.TokensFromConsensusPower(4) + unbondAmt := app.StakingKeeper.TokensFromConsensusPower(ctx, 4) tstaking.Undelegate(del, valA, unbondAmt, true) // begin redelegate 6 stake - redAmt := sdk.NewCoin(sdk.DefaultBondDenom, sdk.TokensFromConsensusPower(6)) + redAmt := sdk.NewCoin(sdk.DefaultBondDenom, app.StakingKeeper.TokensFromConsensusPower(ctx, 6)) msgBeginRedelegate := types.NewMsgBeginRedelegate(del, valA, valB, redAmt) tstaking.Handle(msgBeginRedelegate, true) @@ -1178,11 +1174,11 @@ func TestInvalidMsg(t *testing.T) { func TestInvalidCoinDenom(t *testing.T) { initPower := int64(1000) - app, ctx, delAddrs, valAddrs := bootstrapHandlerGenesisTest(t, initPower, 3, sdk.TokensFromConsensusPower(initPower)) + app, ctx, delAddrs, valAddrs := bootstrapHandlerGenesisTest(t, initPower, 3, sdk.TokensFromConsensusPower(initPower, sdk.DefaultPowerReduction)) valA, valB, delAddr := valAddrs[0], valAddrs[1], delAddrs[2] tstaking := teststaking.NewHelper(t, ctx, app.StakingKeeper) - valTokens := sdk.TokensFromConsensusPower(100) + valTokens := app.StakingKeeper.TokensFromConsensusPower(ctx, 100) invalidCoin := sdk.NewCoin("churros", valTokens) validCoin := sdk.NewCoin(sdk.DefaultBondDenom, valTokens) oneCoin := sdk.NewCoin(sdk.DefaultBondDenom, sdk.OneInt()) diff --git a/x/staking/keeper/alias_functions.go b/x/staking/keeper/alias_functions.go index 88b24b8cbf..c101890b1f 100644 --- a/x/staking/keeper/alias_functions.go +++ b/x/staking/keeper/alias_functions.go @@ -7,7 +7,6 @@ import ( "github.com/line/lbm-sdk/x/staking/types" ) -// _______________________________________________________________________ // Validator Set // iterate through the validator set and perform the provided function @@ -95,7 +94,6 @@ func (k Keeper) ValidatorByConsAddr(ctx sdk.Context, addr sdk.ConsAddress) types return val } -// _______________________________________________________________________ // Delegation Set // Returns self as it is both a validatorset and delegationset diff --git a/x/staking/keeper/common_test.go b/x/staking/keeper/common_test.go index 598876b11e..4487303a45 100644 --- a/x/staking/keeper/common_test.go +++ b/x/staking/keeper/common_test.go @@ -18,7 +18,7 @@ var ( ) func init() { - sdk.PowerReduction = sdk.NewIntFromBigInt(new(big.Int).Exp(big.NewInt(10), big.NewInt(18), nil)) + sdk.DefaultPowerReduction = sdk.NewIntFromBigInt(new(big.Int).Exp(big.NewInt(10), big.NewInt(18), nil)) } // createTestInput Returns a simapp with custom StakingKeeper diff --git a/x/staking/keeper/delegation.go b/x/staking/keeper/delegation.go index 89506b2d8a..5acaee0e53 100644 --- a/x/staking/keeper/delegation.go +++ b/x/staking/keeper/delegation.go @@ -240,7 +240,7 @@ func (k Keeper) GetUBDQueueTimeSlice(ctx sdk.Context, timestamp time.Time) (dvPa } pairs := types.DVPairs{} - k.cdc.MustUnmarshalBinaryBare(bz, &pairs) + k.cdc.MustUnmarshal(bz, &pairs) return pairs.Pairs } @@ -248,7 +248,7 @@ func (k Keeper) GetUBDQueueTimeSlice(ctx sdk.Context, timestamp time.Time) (dvPa // Sets a specific unbonding queue timeslice. func (k Keeper) SetUBDQueueTimeSlice(ctx sdk.Context, timestamp time.Time, keys []types.DVPair) { store := ctx.KVStore(k.storeKey) - bz := k.cdc.MustMarshalBinaryBare(&types.DVPairs{Pairs: keys}) + bz := k.cdc.MustMarshal(&types.DVPairs{Pairs: keys}) store.Set(types.GetUnbondingDelegationTimeKey(timestamp), bz) } @@ -285,7 +285,7 @@ func (k Keeper) DequeueAllMatureUBDQueue(ctx sdk.Context, currTime time.Time) (m for ; unbondingTimesliceIterator.Valid(); unbondingTimesliceIterator.Next() { timeslice := types.DVPairs{} value := unbondingTimesliceIterator.Value() - k.cdc.MustUnmarshalBinaryBare(value, ×lice) + k.cdc.MustUnmarshal(value, ×lice) matureUnbonds = append(matureUnbonds, timeslice.Pairs...) @@ -448,7 +448,7 @@ func (k Keeper) GetRedelegationQueueTimeSlice(ctx sdk.Context, timestamp time.Ti } triplets := types.DVVTriplets{} - k.cdc.MustUnmarshalBinaryBare(bz, &triplets) + k.cdc.MustUnmarshal(bz, &triplets) return triplets.Triplets } @@ -456,7 +456,7 @@ func (k Keeper) GetRedelegationQueueTimeSlice(ctx sdk.Context, timestamp time.Ti // Sets a specific redelegation queue timeslice. func (k Keeper) SetRedelegationQueueTimeSlice(ctx sdk.Context, timestamp time.Time, keys []types.DVVTriplet) { store := ctx.KVStore(k.storeKey) - bz := k.cdc.MustMarshalBinaryBare(&types.DVVTriplets{Triplets: keys}) + bz := k.cdc.MustMarshal(&types.DVVTriplets{Triplets: keys}) store.Set(types.GetRedelegationTimeKey(timestamp), bz) } @@ -495,7 +495,7 @@ func (k Keeper) DequeueAllMatureRedelegationQueue(ctx sdk.Context, currTime time for ; redelegationTimesliceIterator.Valid(); redelegationTimesliceIterator.Next() { timeslice := types.DVVTriplets{} value := redelegationTimesliceIterator.Value() - k.cdc.MustUnmarshalBinaryBare(value, ×lice) + k.cdc.MustUnmarshal(value, ×lice) matureRedelegations = append(matureRedelegations, timeslice.Triplets...) @@ -877,7 +877,7 @@ func (k Keeper) ValidateUnbondAmount( delShares := del.GetShares() if sharesTruncated.GT(delShares) { - return shares, types.ErrBadSharesAmount + return shares, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "invalid shares amount") } // Cap the shares at the delegation's shares. Shares being greater could occur diff --git a/x/staking/keeper/delegation_test.go b/x/staking/keeper/delegation_test.go index 622500eff1..ed6078fce0 100644 --- a/x/staking/keeper/delegation_test.go +++ b/x/staking/keeper/delegation_test.go @@ -183,16 +183,10 @@ func TestUnbondDelegation(t *testing.T) { delAddrs := simapp.AddTestAddrsIncremental(app, ctx, 1, sdk.NewInt(10000)) valAddrs := simapp.ConvertAddrsToValAddrs(delAddrs) - startTokens := sdk.TokensFromConsensusPower(10) + startTokens := app.StakingKeeper.TokensFromConsensusPower(ctx, 10) notBondedPool := app.StakingKeeper.GetNotBondedPool(ctx) - require.NoError(t, - app.BankKeeper.SetBalances( - ctx, - notBondedPool.GetAddress(), - sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), startTokens)), - ), - ) + require.NoError(t, simapp.FundModuleAccount(app, ctx, notBondedPool.GetName(), sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), startTokens)))) app.AccountKeeper.SetModuleAccount(ctx, notBondedPool) // create a validator and a delegator to that validator @@ -207,7 +201,7 @@ func TestUnbondDelegation(t *testing.T) { delegation := types.NewDelegation(delAddrs[0], valAddrs[0], issuedShares) app.StakingKeeper.SetDelegation(ctx, delegation) - bondTokens := sdk.TokensFromConsensusPower(6) + bondTokens := app.StakingKeeper.TokensFromConsensusPower(ctx, 6) amount, err := app.StakingKeeper.Unbond(ctx, delAddrs[0], valAddrs[0], bondTokens.ToDec()) require.NoError(t, err) require.Equal(t, bondTokens, amount) // shares to be added to an unbonding delegation @@ -228,13 +222,12 @@ func TestUnbondingDelegationsMaxEntries(t *testing.T) { addrDels := simapp.AddTestAddrsIncremental(app, ctx, 1, sdk.NewInt(10000)) addrVals := simapp.ConvertAddrsToValAddrs(addrDels) - startTokens := sdk.TokensFromConsensusPower(10) + startTokens := app.StakingKeeper.TokensFromConsensusPower(ctx, 10) bondDenom := app.StakingKeeper.BondDenom(ctx) notBondedPool := app.StakingKeeper.GetNotBondedPool(ctx) - err := app.BankKeeper.SetBalances(ctx, notBondedPool.GetAddress(), sdk.NewCoins(sdk.NewCoin(bondDenom, startTokens))) - require.NoError(t, err) + require.NoError(t, simapp.FundModuleAccount(app, ctx, notBondedPool.GetName(), sdk.NewCoins(sdk.NewCoin(bondDenom, startTokens)))) app.AccountKeeper.SetModuleAccount(ctx, notBondedPool) // create a validator and a delegator to that validator @@ -272,7 +265,7 @@ func TestUnbondingDelegationsMaxEntries(t *testing.T) { oldNotBonded = app.BankKeeper.GetBalance(ctx, app.StakingKeeper.GetNotBondedPool(ctx).GetAddress(), bondDenom).Amount // an additional unbond should fail due to max entries - _, err = app.StakingKeeper.Undelegate(ctx, addrDels[0], addrVals[0], sdk.NewDec(1)) + _, err := app.StakingKeeper.Undelegate(ctx, addrDels[0], addrVals[0], sdk.NewDec(1)) require.Error(t, err) newBonded = app.BankKeeper.GetBalance(ctx, app.StakingKeeper.GetBondedPool(ctx).GetAddress(), bondDenom).Amount @@ -310,7 +303,7 @@ func TestUndelegateSelfDelegationBelowMinSelfDelegation(t *testing.T) { addrDels := simapp.AddTestAddrsIncremental(app, ctx, 1, sdk.NewInt(10000)) addrVals := simapp.ConvertAddrsToValAddrs(addrDels) - delTokens := sdk.TokensFromConsensusPower(10) + delTokens := app.StakingKeeper.TokensFromConsensusPower(ctx, 10) delCoins := sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), delTokens)) //create a validator with a self-delegation @@ -322,9 +315,7 @@ func TestUndelegateSelfDelegationBelowMinSelfDelegation(t *testing.T) { // add bonded tokens to pool for delegations notBondedPool := app.StakingKeeper.GetNotBondedPool(ctx) - oldNotBonded := app.BankKeeper.GetAllBalances(ctx, notBondedPool.GetAddress()) - err := app.BankKeeper.SetBalances(ctx, notBondedPool.GetAddress(), oldNotBonded.Add(delCoins...)) - require.NoError(t, err) + require.NoError(t, simapp.FundModuleAccount(app, ctx, notBondedPool.GetName(), delCoins)) app.AccountKeeper.SetModuleAccount(ctx, notBondedPool) validator = keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validator, true) @@ -336,9 +327,7 @@ func TestUndelegateSelfDelegationBelowMinSelfDelegation(t *testing.T) { // add bonded tokens to pool for delegations bondedPool := app.StakingKeeper.GetBondedPool(ctx) - oldBonded := app.BankKeeper.GetAllBalances(ctx, bondedPool.GetAddress()) - err = app.BankKeeper.SetBalances(ctx, bondedPool.GetAddress(), oldBonded.Add(delCoins...)) - require.NoError(t, err) + require.NoError(t, simapp.FundModuleAccount(app, ctx, bondedPool.GetName(), delCoins)) app.AccountKeeper.SetModuleAccount(ctx, bondedPool) // create a second delegation to this validator @@ -348,9 +337,7 @@ func TestUndelegateSelfDelegationBelowMinSelfDelegation(t *testing.T) { require.Equal(t, delTokens, issuedShares.RoundInt()) // add bonded tokens to pool for delegations - oldBonded = app.BankKeeper.GetAllBalances(ctx, bondedPool.GetAddress()) - err = app.BankKeeper.SetBalances(ctx, bondedPool.GetAddress(), oldBonded.Add(delCoins...)) - require.NoError(t, err) + require.NoError(t, simapp.FundModuleAccount(app, ctx, bondedPool.GetName(), delCoins)) app.AccountKeeper.SetModuleAccount(ctx, bondedPool) validator = keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validator, true) @@ -358,7 +345,7 @@ func TestUndelegateSelfDelegationBelowMinSelfDelegation(t *testing.T) { app.StakingKeeper.SetDelegation(ctx, delegation) val0AccAddr := addrVals[0].ToAccAddress() - _, err = app.StakingKeeper.Undelegate(ctx, val0AccAddr, addrVals[0], sdk.TokensFromConsensusPower(6).ToDec()) + _, err := app.StakingKeeper.Undelegate(ctx, val0AccAddr, addrVals[0], app.StakingKeeper.TokensFromConsensusPower(ctx, 6).ToDec()) require.NoError(t, err) // end block @@ -366,14 +353,14 @@ func TestUndelegateSelfDelegationBelowMinSelfDelegation(t *testing.T) { validator, found := app.StakingKeeper.GetValidator(ctx, addrVals[0]) require.True(t, found) - require.Equal(t, sdk.TokensFromConsensusPower(14), validator.Tokens) + require.Equal(t, app.StakingKeeper.TokensFromConsensusPower(ctx, 14), validator.Tokens) require.Equal(t, types.Unbonding, validator.Status) require.True(t, validator.Jailed) } func TestUndelegateFromUnbondingValidator(t *testing.T) { _, app, ctx := createTestInput() - delTokens := sdk.TokensFromConsensusPower(10) + delTokens := app.StakingKeeper.TokensFromConsensusPower(ctx, 10) delCoins := sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), delTokens)) addrDels := simapp.AddTestAddrsIncremental(app, ctx, 2, sdk.NewInt(0)) @@ -388,9 +375,7 @@ func TestUndelegateFromUnbondingValidator(t *testing.T) { // add bonded tokens to pool for delegations notBondedPool := app.StakingKeeper.GetNotBondedPool(ctx) - oldNotBonded := app.BankKeeper.GetAllBalances(ctx, notBondedPool.GetAddress()) - err := app.BankKeeper.SetBalances(ctx, notBondedPool.GetAddress(), oldNotBonded.Add(delCoins...)) - require.NoError(t, err) + require.NoError(t, simapp.FundModuleAccount(app, ctx, notBondedPool.GetName(), delCoins)) app.AccountKeeper.SetModuleAccount(ctx, notBondedPool) validator = keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validator, true) @@ -399,10 +384,9 @@ func TestUndelegateFromUnbondingValidator(t *testing.T) { selfDelegation := types.NewDelegation(addrVals[0].ToAccAddress(), addrVals[0], issuedShares) app.StakingKeeper.SetDelegation(ctx, selfDelegation) + // add bonded tokens to pool for delegations bondedPool := app.StakingKeeper.GetBondedPool(ctx) - oldBonded := app.BankKeeper.GetAllBalances(ctx, bondedPool.GetAddress()) - err = app.BankKeeper.SetBalances(ctx, bondedPool.GetAddress(), oldBonded.Add(delCoins...)) - require.NoError(t, err) + require.NoError(t, simapp.FundModuleAccount(app, ctx, bondedPool.GetName(), delCoins)) app.AccountKeeper.SetModuleAccount(ctx, bondedPool) // create a second delegation to this validator @@ -411,18 +395,14 @@ func TestUndelegateFromUnbondingValidator(t *testing.T) { validator, issuedShares = validator.AddTokensFromDel(delTokens) require.Equal(t, delTokens, issuedShares.RoundInt()) - oldBonded = app.BankKeeper.GetAllBalances(ctx, bondedPool.GetAddress()) - err = app.BankKeeper.SetBalances(ctx, bondedPool.GetAddress(), oldBonded.Add(delCoins...)) - require.NoError(t, err) + require.NoError(t, simapp.FundModuleAccount(app, ctx, bondedPool.GetName(), delCoins)) app.AccountKeeper.SetModuleAccount(ctx, bondedPool) validator = keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validator, true) delegation := types.NewDelegation(addrDels[1], addrVals[0], issuedShares) app.StakingKeeper.SetDelegation(ctx, delegation) - oldBonded = app.BankKeeper.GetAllBalances(ctx, bondedPool.GetAddress()) - err = app.BankKeeper.SetBalances(ctx, bondedPool.GetAddress(), oldBonded.Add(delCoins...)) - require.NoError(t, err) + require.NoError(t, simapp.FundModuleAccount(app, ctx, bondedPool.GetName(), delCoins)) app.AccountKeeper.SetModuleAccount(ctx, bondedPool) header := ctx.BlockHeader() @@ -434,7 +414,7 @@ func TestUndelegateFromUnbondingValidator(t *testing.T) { // unbond the all self-delegation to put validator in unbonding state val0AccAddr := addrVals[0].ToAccAddress() - _, err = app.StakingKeeper.Undelegate(ctx, val0AccAddr, addrVals[0], delTokens.ToDec()) + _, err := app.StakingKeeper.Undelegate(ctx, val0AccAddr, addrVals[0], delTokens.ToDec()) require.NoError(t, err) // end block @@ -466,7 +446,7 @@ func TestUndelegateFromUnbondingValidator(t *testing.T) { func TestUndelegateFromUnbondedValidator(t *testing.T) { _, app, ctx := createTestInput() - delTokens := sdk.TokensFromConsensusPower(10) + delTokens := app.StakingKeeper.TokensFromConsensusPower(ctx, 10) delCoins := sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), delTokens)) addrDels := simapp.AddTestAddrsIncremental(app, ctx, 2, sdk.NewInt(0)) @@ -474,16 +454,14 @@ func TestUndelegateFromUnbondedValidator(t *testing.T) { // add bonded tokens to pool for delegations notBondedPool := app.StakingKeeper.GetNotBondedPool(ctx) - oldNotBonded := app.BankKeeper.GetAllBalances(ctx, notBondedPool.GetAddress()) - err := app.BankKeeper.SetBalances(ctx, notBondedPool.GetAddress(), oldNotBonded.Add(delCoins...)) - require.NoError(t, err) + require.NoError(t, simapp.FundModuleAccount(app, ctx, notBondedPool.GetName(), delCoins)) app.AccountKeeper.SetModuleAccount(ctx, notBondedPool) // create a validator with a self-delegation validator := teststaking.NewValidator(t, addrVals[0], PKs[0]) app.StakingKeeper.SetValidatorByConsAddr(ctx, validator) - valTokens := sdk.TokensFromConsensusPower(10) + valTokens := app.StakingKeeper.TokensFromConsensusPower(ctx, 10) validator, issuedShares := validator.AddTokensFromDel(valTokens) require.Equal(t, valTokens, issuedShares.RoundInt()) validator = keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validator, true) @@ -493,10 +471,9 @@ func TestUndelegateFromUnbondedValidator(t *testing.T) { selfDelegation := types.NewDelegation(val0AccAddr, addrVals[0], issuedShares) app.StakingKeeper.SetDelegation(ctx, selfDelegation) + // add bonded tokens to pool for delegations bondedPool := app.StakingKeeper.GetBondedPool(ctx) - oldBonded := app.BankKeeper.GetAllBalances(ctx, bondedPool.GetAddress()) - err = app.BankKeeper.SetBalances(ctx, bondedPool.GetAddress(), oldBonded.Add(delCoins...)) - require.NoError(t, err) + require.NoError(t, simapp.FundModuleAccount(app, ctx, bondedPool.GetName(), delCoins)) app.AccountKeeper.SetModuleAccount(ctx, bondedPool) // create a second delegation to this validator @@ -512,7 +489,7 @@ func TestUndelegateFromUnbondedValidator(t *testing.T) { ctx = ctx.WithBlockTime(time.Unix(333, 0)) // unbond the all self-delegation to put validator in unbonding state - _, err = app.StakingKeeper.Undelegate(ctx, val0AccAddr, addrVals[0], valTokens.ToDec()) + _, err := app.StakingKeeper.Undelegate(ctx, val0AccAddr, addrVals[0], valTokens.ToDec()) require.NoError(t, err) // end block @@ -534,7 +511,7 @@ func TestUndelegateFromUnbondedValidator(t *testing.T) { require.Equal(t, validator.Status, types.Unbonded) // unbond some of the other delegation's shares - unbondTokens := sdk.TokensFromConsensusPower(6) + unbondTokens := app.StakingKeeper.TokensFromConsensusPower(ctx, 6) _, err = app.StakingKeeper.Undelegate(ctx, addrDels[1], addrVals[0], unbondTokens.ToDec()) require.NoError(t, err) @@ -543,14 +520,14 @@ func TestUndelegateFromUnbondedValidator(t *testing.T) { _, err = app.StakingKeeper.Undelegate(ctx, addrDels[1], addrVals[0], remainingTokens.ToDec()) require.NoError(t, err) - // now validator should now be deleted from state + // now validator should be deleted from state validator, found = app.StakingKeeper.GetValidator(ctx, addrVals[0]) require.False(t, found, "%v", validator) } func TestUnbondingAllDelegationFromValidator(t *testing.T) { _, app, ctx := createTestInput() - delTokens := sdk.TokensFromConsensusPower(10) + delTokens := app.StakingKeeper.TokensFromConsensusPower(ctx, 10) delCoins := sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), delTokens)) addrDels := simapp.AddTestAddrsIncremental(app, ctx, 2, sdk.NewInt(0)) @@ -558,16 +535,14 @@ func TestUnbondingAllDelegationFromValidator(t *testing.T) { // add bonded tokens to pool for delegations notBondedPool := app.StakingKeeper.GetNotBondedPool(ctx) - oldNotBonded := app.BankKeeper.GetAllBalances(ctx, notBondedPool.GetAddress()) - err := app.BankKeeper.SetBalances(ctx, notBondedPool.GetAddress(), oldNotBonded.Add(delCoins...)) - require.NoError(t, err) + require.NoError(t, simapp.FundModuleAccount(app, ctx, notBondedPool.GetName(), delCoins)) app.AccountKeeper.SetModuleAccount(ctx, notBondedPool) //create a validator with a self-delegation validator := teststaking.NewValidator(t, addrVals[0], PKs[0]) app.StakingKeeper.SetValidatorByConsAddr(ctx, validator) - valTokens := sdk.TokensFromConsensusPower(10) + valTokens := app.StakingKeeper.TokensFromConsensusPower(ctx, 10) validator, issuedShares := validator.AddTokensFromDel(valTokens) require.Equal(t, valTokens, issuedShares.RoundInt()) @@ -583,10 +558,9 @@ func TestUnbondingAllDelegationFromValidator(t *testing.T) { validator, issuedShares = validator.AddTokensFromDel(delTokens) require.Equal(t, delTokens, issuedShares.RoundInt()) + // add bonded tokens to pool for delegations bondedPool := app.StakingKeeper.GetBondedPool(ctx) - oldBonded := app.BankKeeper.GetAllBalances(ctx, bondedPool.GetAddress()) - err = app.BankKeeper.SetBalances(ctx, bondedPool.GetAddress(), oldBonded.Add(delCoins...)) - require.NoError(t, err) + require.NoError(t, simapp.FundModuleAccount(app, ctx, bondedPool.GetName(), delCoins)) app.AccountKeeper.SetModuleAccount(ctx, bondedPool) validator = keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validator, true) @@ -599,7 +573,7 @@ func TestUnbondingAllDelegationFromValidator(t *testing.T) { ctx = ctx.WithBlockTime(time.Unix(333, 0)) // unbond the all self-delegation to put validator in unbonding state - _, err = app.StakingKeeper.Undelegate(ctx, val0AccAddr, addrVals[0], valTokens.ToDec()) + _, err := app.StakingKeeper.Undelegate(ctx, val0AccAddr, addrVals[0], valTokens.ToDec()) require.NoError(t, err) // end block @@ -720,14 +694,12 @@ func TestRedelegateToSameValidator(t *testing.T) { addrDels := simapp.AddTestAddrsIncremental(app, ctx, 1, sdk.NewInt(0)) addrVals := simapp.ConvertAddrsToValAddrs(addrDels) - valTokens := sdk.TokensFromConsensusPower(10) + valTokens := app.StakingKeeper.TokensFromConsensusPower(ctx, 10) startCoins := sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), valTokens)) // add bonded tokens to pool for delegations notBondedPool := app.StakingKeeper.GetNotBondedPool(ctx) - oldNotBonded := app.BankKeeper.GetAllBalances(ctx, notBondedPool.GetAddress()) - err := app.BankKeeper.SetBalances(ctx, notBondedPool.GetAddress(), oldNotBonded.Add(startCoins...)) - require.NoError(t, err) + require.NoError(t, simapp.FundModuleAccount(app, ctx, notBondedPool.GetName(), startCoins)) app.AccountKeeper.SetModuleAccount(ctx, notBondedPool) // create a validator with a self-delegation @@ -741,7 +713,7 @@ func TestRedelegateToSameValidator(t *testing.T) { selfDelegation := types.NewDelegation(val0AccAddr, addrVals[0], issuedShares) app.StakingKeeper.SetDelegation(ctx, selfDelegation) - _, err = app.StakingKeeper.BeginRedelegation(ctx, val0AccAddr, addrVals[0], addrVals[0], sdk.NewDec(5)) + _, err := app.StakingKeeper.BeginRedelegation(ctx, val0AccAddr, addrVals[0], addrVals[0], sdk.NewDec(5)) require.Error(t, err) } @@ -751,19 +723,17 @@ func TestRedelegationMaxEntries(t *testing.T) { addrDels := simapp.AddTestAddrsIncremental(app, ctx, 2, sdk.NewInt(0)) addrVals := simapp.ConvertAddrsToValAddrs(addrDels) - startTokens := sdk.TokensFromConsensusPower(20) + startTokens := app.StakingKeeper.TokensFromConsensusPower(ctx, 20) startCoins := sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), startTokens)) // add bonded tokens to pool for delegations notBondedPool := app.StakingKeeper.GetNotBondedPool(ctx) - oldNotBonded := app.BankKeeper.GetAllBalances(ctx, notBondedPool.GetAddress()) - err := app.BankKeeper.SetBalances(ctx, notBondedPool.GetAddress(), oldNotBonded.Add(startCoins...)) - require.NoError(t, err) + require.NoError(t, simapp.FundModuleAccount(app, ctx, notBondedPool.GetName(), startCoins)) app.AccountKeeper.SetModuleAccount(ctx, notBondedPool) // create a validator with a self-delegation validator := teststaking.NewValidator(t, addrVals[0], PKs[0]) - valTokens := sdk.TokensFromConsensusPower(10) + valTokens := app.StakingKeeper.TokensFromConsensusPower(ctx, 10) validator, issuedShares := validator.AddTokensFromDel(valTokens) require.Equal(t, valTokens, issuedShares.RoundInt()) validator = keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validator, true) @@ -790,7 +760,7 @@ func TestRedelegationMaxEntries(t *testing.T) { } // an additional redelegation should fail due to max entries - _, err = app.StakingKeeper.BeginRedelegation(ctx, val0AccAddr, addrVals[0], addrVals[1], sdk.NewDec(1)) + _, err := app.StakingKeeper.BeginRedelegation(ctx, val0AccAddr, addrVals[0], addrVals[1], sdk.NewDec(1)) require.Error(t, err) // mature redelegations @@ -809,21 +779,19 @@ func TestRedelegateSelfDelegation(t *testing.T) { addrDels := simapp.AddTestAddrsIncremental(app, ctx, 2, sdk.NewInt(0)) addrVals := simapp.ConvertAddrsToValAddrs(addrDels) - startTokens := sdk.TokensFromConsensusPower(30) + startTokens := app.StakingKeeper.TokensFromConsensusPower(ctx, 30) startCoins := sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), startTokens)) // add bonded tokens to pool for delegations notBondedPool := app.StakingKeeper.GetNotBondedPool(ctx) - oldNotBonded := app.BankKeeper.GetAllBalances(ctx, notBondedPool.GetAddress()) - err := app.BankKeeper.SetBalances(ctx, notBondedPool.GetAddress(), oldNotBonded.Add(startCoins...)) - require.NoError(t, err) + require.NoError(t, simapp.FundModuleAccount(app, ctx, notBondedPool.GetName(), startCoins)) app.AccountKeeper.SetModuleAccount(ctx, notBondedPool) //create a validator with a self-delegation validator := teststaking.NewValidator(t, addrVals[0], PKs[0]) app.StakingKeeper.SetValidatorByConsAddr(ctx, validator) - valTokens := sdk.TokensFromConsensusPower(10) + valTokens := app.StakingKeeper.TokensFromConsensusPower(ctx, 10) validator, issuedShares := validator.AddTokensFromDel(valTokens) require.Equal(t, valTokens, issuedShares.RoundInt()) @@ -841,7 +809,7 @@ func TestRedelegateSelfDelegation(t *testing.T) { require.Equal(t, types.Bonded, validator2.Status) // create a second delegation to validator 1 - delTokens := sdk.TokensFromConsensusPower(10) + delTokens := app.StakingKeeper.TokensFromConsensusPower(ctx, 10) validator, issuedShares = validator.AddTokensFromDel(delTokens) require.Equal(t, delTokens, issuedShares.RoundInt()) validator = keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validator, true) @@ -849,7 +817,7 @@ func TestRedelegateSelfDelegation(t *testing.T) { delegation := types.NewDelegation(addrDels[0], addrVals[0], issuedShares) app.StakingKeeper.SetDelegation(ctx, delegation) - _, err = app.StakingKeeper.BeginRedelegation(ctx, val0AccAddr, addrVals[0], addrVals[1], delTokens.ToDec()) + _, err := app.StakingKeeper.BeginRedelegation(ctx, val0AccAddr, addrVals[0], addrVals[1], delTokens.ToDec()) require.NoError(t, err) // end block @@ -867,21 +835,19 @@ func TestRedelegateFromUnbondingValidator(t *testing.T) { addrDels := simapp.AddTestAddrsIncremental(app, ctx, 2, sdk.NewInt(0)) addrVals := simapp.ConvertAddrsToValAddrs(addrDels) - startTokens := sdk.TokensFromConsensusPower(30) + startTokens := app.StakingKeeper.TokensFromConsensusPower(ctx, 30) startCoins := sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), startTokens)) // add bonded tokens to pool for delegations notBondedPool := app.StakingKeeper.GetNotBondedPool(ctx) - oldNotBonded := app.BankKeeper.GetAllBalances(ctx, notBondedPool.GetAddress()) - err := app.BankKeeper.SetBalances(ctx, notBondedPool.GetAddress(), oldNotBonded.Add(startCoins...)) - require.NoError(t, err) + require.NoError(t, simapp.FundModuleAccount(app, ctx, notBondedPool.GetName(), startCoins)) app.AccountKeeper.SetModuleAccount(ctx, notBondedPool) //create a validator with a self-delegation validator := teststaking.NewValidator(t, addrVals[0], PKs[0]) app.StakingKeeper.SetValidatorByConsAddr(ctx, validator) - valTokens := sdk.TokensFromConsensusPower(10) + valTokens := app.StakingKeeper.TokensFromConsensusPower(ctx, 10) validator, issuedShares := validator.AddTokensFromDel(valTokens) require.Equal(t, valTokens, issuedShares.RoundInt()) validator = keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validator, true) @@ -891,7 +857,7 @@ func TestRedelegateFromUnbondingValidator(t *testing.T) { // create a second delegation to this validator app.StakingKeeper.DeleteValidatorByPowerIndex(ctx, validator) - delTokens := sdk.TokensFromConsensusPower(10) + delTokens := app.StakingKeeper.TokensFromConsensusPower(ctx, 10) validator, issuedShares = validator.AddTokensFromDel(delTokens) require.Equal(t, delTokens, issuedShares.RoundInt()) validator = keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validator, true) @@ -912,7 +878,7 @@ func TestRedelegateFromUnbondingValidator(t *testing.T) { ctx = ctx.WithBlockHeader(header) // unbond the all self-delegation to put validator in unbonding state - _, err = app.StakingKeeper.Undelegate(ctx, val0AccAddr, addrVals[0], delTokens.ToDec()) + _, err := app.StakingKeeper.Undelegate(ctx, val0AccAddr, addrVals[0], delTokens.ToDec()) require.NoError(t, err) // end block @@ -933,7 +899,7 @@ func TestRedelegateFromUnbondingValidator(t *testing.T) { ctx = ctx.WithBlockHeader(header) // unbond some of the other delegation's shares - redelegateTokens := sdk.TokensFromConsensusPower(6) + redelegateTokens := app.StakingKeeper.TokensFromConsensusPower(ctx, 6) _, err = app.StakingKeeper.BeginRedelegation(ctx, addrDels[1], addrVals[0], addrVals[1], redelegateTokens.ToDec()) require.NoError(t, err) @@ -951,21 +917,19 @@ func TestRedelegateFromUnbondedValidator(t *testing.T) { addrDels := simapp.AddTestAddrsIncremental(app, ctx, 2, sdk.NewInt(0)) addrVals := simapp.ConvertAddrsToValAddrs(addrDels) - startTokens := sdk.TokensFromConsensusPower(30) + startTokens := app.StakingKeeper.TokensFromConsensusPower(ctx, 30) startCoins := sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), startTokens)) // add bonded tokens to pool for delegations notBondedPool := app.StakingKeeper.GetNotBondedPool(ctx) - oldNotBonded := app.BankKeeper.GetAllBalances(ctx, notBondedPool.GetAddress()) - err := app.BankKeeper.SetBalances(ctx, notBondedPool.GetAddress(), oldNotBonded.Add(startCoins...)) - require.NoError(t, err) + require.NoError(t, simapp.FundModuleAccount(app, ctx, notBondedPool.GetName(), startCoins)) app.AccountKeeper.SetModuleAccount(ctx, notBondedPool) //create a validator with a self-delegation validator := teststaking.NewValidator(t, addrVals[0], PKs[0]) app.StakingKeeper.SetValidatorByConsAddr(ctx, validator) - valTokens := sdk.TokensFromConsensusPower(10) + valTokens := app.StakingKeeper.TokensFromConsensusPower(ctx, 10) validator, issuedShares := validator.AddTokensFromDel(valTokens) require.Equal(t, valTokens, issuedShares.RoundInt()) validator = keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validator, true) @@ -975,7 +939,7 @@ func TestRedelegateFromUnbondedValidator(t *testing.T) { // create a second delegation to this validator app.StakingKeeper.DeleteValidatorByPowerIndex(ctx, validator) - delTokens := sdk.TokensFromConsensusPower(10) + delTokens := app.StakingKeeper.TokensFromConsensusPower(ctx, 10) validator, issuedShares = validator.AddTokensFromDel(delTokens) require.Equal(t, delTokens, issuedShares.RoundInt()) validator = keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validator, true) @@ -993,7 +957,7 @@ func TestRedelegateFromUnbondedValidator(t *testing.T) { ctx = ctx.WithBlockTime(time.Unix(333, 0)) // unbond the all self-delegation to put validator in unbonding state - _, err = app.StakingKeeper.Undelegate(ctx, val0AccAddr, addrVals[0], delTokens.ToDec()) + _, err := app.StakingKeeper.Undelegate(ctx, val0AccAddr, addrVals[0], delTokens.ToDec()) require.NoError(t, err) // end block @@ -1009,7 +973,7 @@ func TestRedelegateFromUnbondedValidator(t *testing.T) { app.StakingKeeper.UnbondingToUnbonded(ctx, validator) // redelegate some of the delegation's shares - redelegationTokens := sdk.TokensFromConsensusPower(6) + redelegationTokens := app.StakingKeeper.TokensFromConsensusPower(ctx, 6) _, err = app.StakingKeeper.BeginRedelegation(ctx, addrDels[1], addrVals[0], addrVals[1], redelegationTokens.ToDec()) require.NoError(t, err) diff --git a/x/staking/keeper/grpc_query.go b/x/staking/keeper/grpc_query.go index 43fd1cc7db..c05c909515 100644 --- a/x/staking/keeper/grpc_query.go +++ b/x/staking/keeper/grpc_query.go @@ -61,7 +61,7 @@ func (k Querier) Validators(c context.Context, req *types.QueryValidatorsRequest return &types.QueryValidatorsResponse{Validators: validators, Pagination: pageRes}, nil } -// Validator queries validator info for given validator addr +// Validator queries validator info for given validator address func (k Querier) Validator(c context.Context, req *types.QueryValidatorRequest) (*types.QueryValidatorResponse, error) { if req == nil { return nil, status.Error(codes.InvalidArgument, "empty request") @@ -285,11 +285,6 @@ func (k Querier) DelegatorDelegations(c context.Context, req *types.QueryDelegat return nil, status.Error(codes.Internal, err.Error()) } - if delegations == nil { - return nil, status.Errorf( - codes.NotFound, - "unable to find delegations for address %s", req.DelegatorAddr) - } delegationResps, err := DelegationsToDelegationResponses(ctx, k.Keeper, delegations) if err != nil { return nil, status.Error(codes.Internal, err.Error()) @@ -386,6 +381,7 @@ func (k Querier) HistoricalInfo(c context.Context, req *types.QueryHistoricalInf return &types.QueryHistoricalInfoResponse{Hist: &hi}, nil } +// Redelegations queries redelegations of given address func (k Querier) Redelegations(c context.Context, req *types.QueryRedelegationsRequest) (*types.QueryRedelegationsResponse, error) { if req == nil { return nil, status.Error(codes.InvalidArgument, "empty request") @@ -431,6 +427,7 @@ func (k Querier) Redelegations(c context.Context, req *types.QueryRedelegationsR return &types.QueryRedelegationsResponse{RedelegationResponses: redelResponses, Pagination: pageRes}, nil } +// DelegatorValidators queries all validators info for given delegator address func (k Querier) DelegatorValidators(c context.Context, req *types.QueryDelegatorValidatorsRequest) (*types.QueryDelegatorValidatorsResponse, error) { if req == nil { return nil, status.Error(codes.InvalidArgument, "empty request") diff --git a/x/staking/keeper/grpc_query_test.go b/x/staking/keeper/grpc_query_test.go index 3593194bba..41cd1191a6 100644 --- a/x/staking/keeper/grpc_query_test.go +++ b/x/staking/keeper/grpc_query_test.go @@ -35,7 +35,8 @@ func (suite *KeeperTestSuite) TestGRPCQueryValidators() { len(vals), false, }, - {"empty status returns all the validators", + { + "empty status returns all the validators", func() { req = &types.QueryValidatorsRequest{Status: ""} }, @@ -52,7 +53,8 @@ func (suite *KeeperTestSuite) TestGRPCQueryValidators() { 0, false, }, - {"valid request", + { + "valid request", func() { req = &types.QueryValidatorsRequest{Status: types.Bonded.String(), Pagination: &query.PageRequest{Limit: 1, CountTotal: true}} @@ -84,7 +86,7 @@ func (suite *KeeperTestSuite) TestGRPCQueryValidators() { } } -func (suite *KeeperTestSuite) TestGRPCValidator() { +func (suite *KeeperTestSuite) TestGRPCQueryValidator() { app, ctx, queryClient, vals := suite.app, suite.ctx, suite.queryClient, suite.vals validator, found := app.StakingKeeper.GetValidator(ctx, vals[0].GetOperator()) suite.True(found) @@ -101,7 +103,8 @@ func (suite *KeeperTestSuite) TestGRPCValidator() { }, false, }, - {"valid request", + { + "valid request", func() { req = &types.QueryValidatorRequest{ValidatorAddr: vals[0].OperatorAddress} }, @@ -141,7 +144,8 @@ func (suite *KeeperTestSuite) TestGRPCQueryDelegatorValidators() { }, false, }, - {"valid request", + { + "valid request", func() { req = &types.QueryDelegatorValidatorsRequest{ DelegatorAddr: addrs[0].String(), @@ -185,7 +189,8 @@ func (suite *KeeperTestSuite) TestGRPCQueryDelegatorValidator() { }, false, }, - {"invalid delegator, validator pair", + { + "invalid delegator, validator pair", func() { req = &types.QueryDelegatorValidatorRequest{ DelegatorAddr: addr.String(), @@ -194,7 +199,8 @@ func (suite *KeeperTestSuite) TestGRPCQueryDelegatorValidator() { }, false, }, - {"valid request", + { + "valid request", func() { req = &types.QueryDelegatorValidatorRequest{ DelegatorAddr: addr.String(), @@ -233,13 +239,15 @@ func (suite *KeeperTestSuite) TestGRPCQueryDelegation() { malleate func() expPass bool }{ - {"empty request", + { + "empty request", func() { req = &types.QueryDelegationRequest{} }, false, }, - {"invalid validator, delegator pair", + { + "invalid validator, delegator pair", func() { req = &types.QueryDelegationRequest{ DelegatorAddr: addrAcc1.String(), @@ -248,7 +256,8 @@ func (suite *KeeperTestSuite) TestGRPCQueryDelegation() { }, false, }, - {"valid request", + { + "valid request", func() { req = &types.QueryDelegationRequest{DelegatorAddr: addrAcc.String(), ValidatorAddr: addrVal.String()} }, @@ -282,27 +291,42 @@ func (suite *KeeperTestSuite) TestGRPCQueryDelegatorDelegations() { var req *types.QueryDelegatorDelegationsRequest testCases := []struct { - msg string - malleate func() - expPass bool + msg string + malleate func() + onSuccess func(suite *KeeperTestSuite, response *types.QueryDelegatorDelegationsResponse) + expErr bool }{ - {"empty request", + { + "empty request", func() { req = &types.QueryDelegatorDelegationsRequest{} }, - false, - }, {"invalid request", + func(suite *KeeperTestSuite, response *types.QueryDelegatorDelegationsResponse) {}, + true, + }, + { + "valid request with no delegations", func() { req = &types.QueryDelegatorDelegationsRequest{DelegatorAddr: addrs[4].String()} }, + func(suite *KeeperTestSuite, response *types.QueryDelegatorDelegationsResponse) { + suite.Equal(uint64(0), response.Pagination.Total) + suite.Len(response.DelegationResponses, 0) + }, false, }, - {"valid request", + { + "valid request", func() { req = &types.QueryDelegatorDelegationsRequest{DelegatorAddr: addrAcc.String(), Pagination: &query.PageRequest{Limit: 1, CountTotal: true}} }, - true, + func(suite *KeeperTestSuite, response *types.QueryDelegatorDelegationsResponse) { + suite.Equal(uint64(2), response.Pagination.Total) + suite.Len(response.DelegationResponses, 1) + suite.Equal(sdk.NewCoin(sdk.DefaultBondDenom, delegation.Shares.TruncateInt()), response.DelegationResponses[0].Balance) + }, + false, }, } @@ -310,14 +334,11 @@ func (suite *KeeperTestSuite) TestGRPCQueryDelegatorDelegations() { suite.Run(fmt.Sprintf("Case %s", tc.msg), func() { tc.malleate() res, err := queryClient.DelegatorDelegations(gocontext.Background(), req) - if tc.expPass { - suite.Equal(uint64(2), res.Pagination.Total) - suite.Len(res.DelegationResponses, 1) - suite.Equal(1, len(res.DelegationResponses)) - suite.Equal(sdk.NewCoin(sdk.DefaultBondDenom, delegation.Shares.TruncateInt()), res.DelegationResponses[0].Balance) - } else { + if tc.expErr { suite.Error(err) - suite.Nil(res) + } else { + suite.NoError(err) + tc.onSuccess(suite, res) } }) } @@ -340,21 +361,24 @@ func (suite *KeeperTestSuite) TestGRPCQueryValidatorDelegations() { expPass bool expErr bool }{ - {"empty request", + { + "empty request", func() { req = &types.QueryValidatorDelegationsRequest{} }, false, true, }, - {"invalid validator delegator pair", + { + "invalid validator delegator pair", func() { req = &types.QueryValidatorDelegationsRequest{ValidatorAddr: addrVal2.String()} }, false, false, }, - {"valid request", + { + "valid request", func() { req = &types.QueryValidatorDelegationsRequest{ValidatorAddr: addrVal1, Pagination: &query.PageRequest{Limit: 1, CountTotal: true}} @@ -391,7 +415,7 @@ func (suite *KeeperTestSuite) TestGRPCQueryUnbondingDelegation() { addrAcc2 := addrs[1] addrVal2 := vals[1].OperatorAddress - unbondingTokens := sdk.TokensFromConsensusPower(2) + unbondingTokens := app.StakingKeeper.TokensFromConsensusPower(ctx, 2) valAddr := sdk.ValAddress(addrVal2) _, err := app.StakingKeeper.Undelegate(ctx, addrAcc2, valAddr, unbondingTokens.ToDec()) suite.NoError(err) @@ -404,19 +428,22 @@ func (suite *KeeperTestSuite) TestGRPCQueryUnbondingDelegation() { malleate func() expPass bool }{ - {"empty request", + { + "empty request", func() { req = &types.QueryUnbondingDelegationRequest{} }, false, }, - {"invalid request", + { + "invalid request", func() { req = &types.QueryUnbondingDelegationRequest{} }, false, }, - {"valid request", + { + "valid request", func() { req = &types.QueryUnbondingDelegationRequest{ DelegatorAddr: addrAcc2.String(), ValidatorAddr: addrVal2} @@ -445,7 +472,7 @@ func (suite *KeeperTestSuite) TestGRPCQueryDelegatorUnbondingDelegations() { addrAcc, addrAcc1 := addrs[0], addrs[1] addrVal, addrVal2 := vals[0].OperatorAddress, vals[1].OperatorAddress - unbondingTokens := sdk.TokensFromConsensusPower(2) + unbondingTokens := app.StakingKeeper.TokensFromConsensusPower(ctx, 2) valAddr1 := sdk.ValAddress(addrVal) _, err := app.StakingKeeper.Undelegate(ctx, addrAcc, valAddr1, unbondingTokens.ToDec()) suite.NoError(err) @@ -462,21 +489,24 @@ func (suite *KeeperTestSuite) TestGRPCQueryDelegatorUnbondingDelegations() { expPass bool expErr bool }{ - {"empty request", + { + "empty request", func() { req = &types.QueryDelegatorUnbondingDelegationsRequest{} }, false, true, }, - {"invalid request", + { + "invalid request", func() { req = &types.QueryDelegatorUnbondingDelegationsRequest{DelegatorAddr: addrAcc1.String()} }, false, false, }, - {"valid request", + { + "valid request", func() { req = &types.QueryDelegatorUnbondingDelegationsRequest{DelegatorAddr: addrAcc.String(), Pagination: &query.PageRequest{Limit: 1, CountTotal: true}} @@ -537,25 +567,29 @@ func (suite *KeeperTestSuite) TestGRPCQueryHistoricalInfo() { malleate func() expPass bool }{ - {"empty request", + { + "empty request", func() { req = &types.QueryHistoricalInfoRequest{} }, false, }, - {"invalid request with negative height", + { + "invalid request with negative height", func() { req = &types.QueryHistoricalInfoRequest{Height: -1} }, false, }, - {"valid request with old height", + { + "valid request with old height", func() { req = &types.QueryHistoricalInfoRequest{Height: 4} }, false, }, - {"valid request with current height", + { + "valid request with current height", func() { req = &types.QueryHistoricalInfoRequest{Height: 5} }, @@ -579,18 +613,18 @@ func (suite *KeeperTestSuite) TestGRPCQueryHistoricalInfo() { } } -func (suite *KeeperTestSuite) TestGRPCQueryRedelegation() { +func (suite *KeeperTestSuite) TestGRPCQueryRedelegations() { app, ctx, queryClient, addrs, vals := suite.app, suite.ctx, suite.queryClient, suite.addrs, suite.vals addrAcc, addrAcc1 := addrs[0], addrs[1] valAddrs := simapp.ConvertAddrsToValAddrs(addrs) val1, val2, val3, val4 := vals[0], vals[1], valAddrs[3], valAddrs[4] - delAmount := sdk.TokensFromConsensusPower(1) + delAmount := app.StakingKeeper.TokensFromConsensusPower(ctx, 1) _, err := app.StakingKeeper.Delegate(ctx, addrAcc1, delAmount, types.Unbonded, val1, true) suite.NoError(err) applyValidatorSetUpdates(suite.T(), ctx, app.StakingKeeper, -1) - rdAmount := sdk.TokensFromConsensusPower(1) + rdAmount := app.StakingKeeper.TokensFromConsensusPower(ctx, 1) _, err = app.StakingKeeper.BeginRedelegation(ctx, addrAcc1, val1.GetOperator(), val2.GetOperator(), rdAmount.ToDec()) suite.NoError(err) applyValidatorSetUpdates(suite.T(), ctx, app.StakingKeeper, -1) @@ -605,14 +639,16 @@ func (suite *KeeperTestSuite) TestGRPCQueryRedelegation() { expPass bool expErr bool }{ - {"request redelegations for non existent addr", + { + "request redelegations for non existent addr", func() { req = &types.QueryRedelegationsRequest{DelegatorAddr: addrAcc.String()} }, false, false, }, - {"request redelegations with non existent pairs", + { + "request redelegations with non existent pairs", func() { req = &types.QueryRedelegationsRequest{DelegatorAddr: addrAcc.String(), SrcValidatorAddr: val3.String(), DstValidatorAddr: val4.String()} @@ -620,7 +656,8 @@ func (suite *KeeperTestSuite) TestGRPCQueryRedelegation() { false, true, }, - {"request redelegations with delegatoraddr, sourceValAddr, destValAddr", + { + "request redelegations with delegatoraddr, sourceValAddr, destValAddr", func() { req = &types.QueryRedelegationsRequest{ DelegatorAddr: addrAcc1.String(), SrcValidatorAddr: val1.OperatorAddress, @@ -629,7 +666,8 @@ func (suite *KeeperTestSuite) TestGRPCQueryRedelegation() { true, false, }, - {"request redelegations with delegatoraddr and sourceValAddr", + { + "request redelegations with delegatoraddr and sourceValAddr", func() { req = &types.QueryRedelegationsRequest{ DelegatorAddr: addrAcc1.String(), SrcValidatorAddr: val1.OperatorAddress, @@ -638,7 +676,8 @@ func (suite *KeeperTestSuite) TestGRPCQueryRedelegation() { true, false, }, - {"query redelegations with sourceValAddr only", + { + "query redelegations with sourceValAddr only", func() { req = &types.QueryRedelegationsRequest{ SrcValidatorAddr: val1.GetOperator().String(), @@ -677,7 +716,7 @@ func (suite *KeeperTestSuite) TestGRPCQueryValidatorUnbondingDelegations() { val1 := vals[0] // undelegate - undelAmount := sdk.TokensFromConsensusPower(2) + undelAmount := app.StakingKeeper.TokensFromConsensusPower(ctx, 2) _, err := app.StakingKeeper.Undelegate(ctx, addrAcc1, val1.GetOperator(), undelAmount.ToDec()) suite.NoError(err) applyValidatorSetUpdates(suite.T(), ctx, app.StakingKeeper, -1) @@ -688,13 +727,15 @@ func (suite *KeeperTestSuite) TestGRPCQueryValidatorUnbondingDelegations() { malleate func() expPass bool }{ - {"empty request", + { + "empty request", func() { req = &types.QueryValidatorUnbondingDelegationsRequest{} }, false, }, - {"valid request", + { + "valid request", func() { req = &types.QueryValidatorUnbondingDelegationsRequest{ ValidatorAddr: val1.GetOperator().String(), @@ -722,13 +763,12 @@ func (suite *KeeperTestSuite) TestGRPCQueryValidatorUnbondingDelegations() { } func createValidators(t *testing.T, ctx sdk.Context, app *simapp.SimApp, powers []int64) ([]sdk.AccAddress, []sdk.ValAddress, []types.Validator) { - addrs := simapp.AddTestAddrsIncremental(app, ctx, 5, sdk.TokensFromConsensusPower(300)) + addrs := simapp.AddTestAddrsIncremental(app, ctx, 5, app.StakingKeeper.TokensFromConsensusPower(ctx, 300)) valAddrs := simapp.ConvertAddrsToValAddrs(addrs) pks := simapp.CreateTestPubKeys(5) - - appCodec, _ := simapp.MakeCodecs() + cdc := simapp.MakeTestEncodingConfig().Marshaler app.StakingKeeper = keeper.NewKeeper( - appCodec, + cdc, app.GetKey(types.StoreKey), app.AccountKeeper, app.BankKeeper, @@ -746,11 +786,11 @@ func createValidators(t *testing.T, ctx sdk.Context, app *simapp.SimApp, powers app.StakingKeeper.SetNewValidatorByPowerIndex(ctx, val1) app.StakingKeeper.SetNewValidatorByPowerIndex(ctx, val2) - _, err := app.StakingKeeper.Delegate(ctx, addrs[0], sdk.TokensFromConsensusPower(powers[0]), types.Unbonded, val1, true) + _, err := app.StakingKeeper.Delegate(ctx, addrs[0], app.StakingKeeper.TokensFromConsensusPower(ctx, powers[0]), types.Unbonded, val1, true) require.NoError(t, err) - _, err = app.StakingKeeper.Delegate(ctx, addrs[1], sdk.TokensFromConsensusPower(powers[1]), types.Unbonded, val2, true) + _, err = app.StakingKeeper.Delegate(ctx, addrs[1], app.StakingKeeper.TokensFromConsensusPower(ctx, powers[1]), types.Unbonded, val2, true) require.NoError(t, err) - _, err = app.StakingKeeper.Delegate(ctx, addrs[0], sdk.TokensFromConsensusPower(powers[2]), types.Unbonded, val2, true) + _, err = app.StakingKeeper.Delegate(ctx, addrs[0], app.StakingKeeper.TokensFromConsensusPower(ctx, powers[2]), types.Unbonded, val2, true) require.NoError(t, err) applyValidatorSetUpdates(t, ctx, app.StakingKeeper, -1) diff --git a/x/staking/keeper/historical_info.go b/x/staking/keeper/historical_info.go index 836f1b97dd..c50e41ce29 100644 --- a/x/staking/keeper/historical_info.go +++ b/x/staking/keeper/historical_info.go @@ -22,7 +22,7 @@ func (k Keeper) GetHistoricalInfo(ctx sdk.Context, height int64) (types.Historic func (k Keeper) SetHistoricalInfo(ctx sdk.Context, height int64, hi *types.HistoricalInfo) { store := ctx.KVStore(k.storeKey) key := types.GetHistoricalInfoKey(height) - value := k.cdc.MustMarshalBinaryBare(hi) + value := k.cdc.MustMarshal(hi) store.Set(key, value) } @@ -91,7 +91,7 @@ func (k Keeper) TrackHistoricalInfo(ctx sdk.Context) { // Create HistoricalInfo struct lastVals := k.GetLastValidators(ctx) - historicalEntry := types.NewHistoricalInfo(ctx.BlockHeader(), lastVals) + historicalEntry := types.NewHistoricalInfo(ctx.BlockHeader(), lastVals, k.PowerReduction(ctx)) // Set latest HistoricalInfo at current height k.SetHistoricalInfo(ctx, ctx.BlockHeight(), &historicalEntry) diff --git a/x/staking/keeper/historical_info_test.go b/x/staking/keeper/historical_info_test.go index 6cde364c2a..87a8079510 100644 --- a/x/staking/keeper/historical_info_test.go +++ b/x/staking/keeper/historical_info_test.go @@ -1,7 +1,6 @@ package keeper_test import ( - "sort" "testing" ocproto "github.com/line/ostracon/proto/ostracon/types" @@ -13,6 +12,17 @@ import ( "github.com/line/lbm-sdk/x/staking/types" ) +// IsValSetSorted reports whether valset is sorted. +func IsValSetSorted(data []types.Validator, powerReduction sdk.Int) bool { + n := len(data) + for i := n - 1; i > 0; i-- { + if types.ValidatorsByVotingPower(data).Less(i, i-1, powerReduction) { + return false + } + } + return true +} + func TestHistoricalInfo(t *testing.T) { _, app, ctx := createTestInput() @@ -25,13 +35,13 @@ func TestHistoricalInfo(t *testing.T) { validators[i] = teststaking.NewValidator(t, valAddr, PKs[i]) } - hi := types.NewHistoricalInfo(ctx.BlockHeader(), validators) + hi := types.NewHistoricalInfo(ctx.BlockHeader(), validators, app.StakingKeeper.PowerReduction(ctx)) app.StakingKeeper.SetHistoricalInfo(ctx, 2, &hi) recv, found := app.StakingKeeper.GetHistoricalInfo(ctx, 2) require.True(t, found, "HistoricalInfo not found after set") require.Equal(t, hi, recv, "HistoricalInfo not equal") - require.True(t, sort.IsSorted(types.ValidatorsByVotingPower(recv.Valset)), "HistoricalInfo validators is not sorted") + require.True(t, IsValSetSorted(recv.Valset, app.StakingKeeper.PowerReduction(ctx)), "HistoricalInfo validators is not sorted") app.StakingKeeper.DeleteHistoricalInfo(ctx, 2) @@ -65,8 +75,8 @@ func TestTrackHistoricalInfo(t *testing.T) { teststaking.NewValidator(t, addrVals[0], PKs[0]), teststaking.NewValidator(t, addrVals[1], PKs[1]), } - hi4 := types.NewHistoricalInfo(h4, valSet) - hi5 := types.NewHistoricalInfo(h5, valSet) + hi4 := types.NewHistoricalInfo(h4, valSet, app.StakingKeeper.PowerReduction(ctx)) + hi5 := types.NewHistoricalInfo(h5, valSet, app.StakingKeeper.PowerReduction(ctx)) app.StakingKeeper.SetHistoricalInfo(ctx, 4, &hi4) app.StakingKeeper.SetHistoricalInfo(ctx, 5, &hi5) recv, found := app.StakingKeeper.GetHistoricalInfo(ctx, 4) @@ -78,14 +88,18 @@ func TestTrackHistoricalInfo(t *testing.T) { // Set bonded validators in keeper val1 := teststaking.NewValidator(t, addrVals[2], PKs[2]) + val1.Status = types.Bonded // when not bonded, consensus power is Zero + val1.Tokens = app.StakingKeeper.TokensFromConsensusPower(ctx, 10) app.StakingKeeper.SetValidator(ctx, val1) app.StakingKeeper.SetLastValidatorPower(ctx, val1.GetOperator(), 10) val2 := teststaking.NewValidator(t, addrVals[3], PKs[3]) + val1.Status = types.Bonded + val2.Tokens = app.StakingKeeper.TokensFromConsensusPower(ctx, 80) app.StakingKeeper.SetValidator(ctx, val2) app.StakingKeeper.SetLastValidatorPower(ctx, val2.GetOperator(), 80) vals := []types.Validator{val1, val2} - sort.Sort(types.ValidatorsByVotingPower(vals)) + IsValSetSorted(vals, app.StakingKeeper.PowerReduction(ctx)) // Set Header for BeginBlock context header := ocproto.Header{ @@ -103,7 +117,7 @@ func TestTrackHistoricalInfo(t *testing.T) { } recv, found = app.StakingKeeper.GetHistoricalInfo(ctx, 10) require.True(t, found, "GetHistoricalInfo failed after BeginBlock") - require.Equal(t, expected, recv, "GetHistoricalInfo returned eunexpected result") + require.Equal(t, expected, recv, "GetHistoricalInfo returned unexpected result") // Check HistoricalInfo at height 5, 4 is pruned recv, found = app.StakingKeeper.GetHistoricalInfo(ctx, 4) diff --git a/x/staking/keeper/invariants.go b/x/staking/keeper/invariants.go index 2afeb06a87..12123979a5 100644 --- a/x/staking/keeper/invariants.go +++ b/x/staking/keeper/invariants.go @@ -105,13 +105,13 @@ func NonNegativePowerInvariant(k Keeper) sdk.Invariant { panic(fmt.Sprintf("validator record not found for address: %X\n", iterator.Value())) } - powerKey := types.GetValidatorsByPowerIndexKey(validator) + powerKey := types.GetValidatorsByPowerIndexKey(validator, k.PowerReduction(ctx)) if !bytes.Equal(iterator.Key(), powerKey) { broken = true msg += fmt.Sprintf("power store invariance:\n\tvalidator.Power: %v"+ "\n\tkey should be: %v\n\tkey in store: %v\n", - validator.GetConsensusPower(), powerKey, iterator.Key()) + validator.GetConsensusPower(k.PowerReduction(ctx)), powerKey, iterator.Key()) } if validator.Tokens.IsNegative() { diff --git a/x/staking/keeper/keeper.go b/x/staking/keeper/keeper.go index e1e9827b92..e7a135f6b6 100644 --- a/x/staking/keeper/keeper.go +++ b/x/staking/keeper/keeper.go @@ -1,7 +1,6 @@ package keeper import ( - "container/list" "fmt" "github.com/line/ostracon/libs/log" @@ -20,19 +19,18 @@ var _ types.DelegationSet = Keeper{} // keeper of the staking store type Keeper struct { - storeKey sdk.StoreKey - cdc codec.BinaryMarshaler - authKeeper types.AccountKeeper - bankKeeper types.BankKeeper - hooks types.StakingHooks - paramstore *paramtypes.Subspace - validatorCacheList *list.List + storeKey sdk.StoreKey + cdc codec.BinaryCodec + authKeeper types.AccountKeeper + bankKeeper types.BankKeeper + hooks types.StakingHooks + paramstore paramtypes.Subspace } // NewKeeper creates a new staking Keeper instance func NewKeeper( - cdc codec.BinaryMarshaler, key sdk.StoreKey, ak types.AccountKeeper, bk types.BankKeeper, - ps *paramtypes.Subspace, + cdc codec.BinaryCodec, key sdk.StoreKey, ak types.AccountKeeper, bk types.BankKeeper, + ps paramtypes.Subspace, ) Keeper { // set KeyTable if it has not already been set if !ps.HasKeyTable() { @@ -49,13 +47,12 @@ func NewKeeper( } return Keeper{ - storeKey: key, - cdc: cdc, - authKeeper: ak, - bankKeeper: bk, - paramstore: ps, - hooks: nil, - validatorCacheList: list.New(), + storeKey: key, + cdc: cdc, + authKeeper: ak, + bankKeeper: bk, + paramstore: ps, + hooks: nil, } } @@ -85,7 +82,7 @@ func (k Keeper) GetLastTotalPower(ctx sdk.Context) sdk.Int { } ip := sdk.IntProto{} - k.cdc.MustUnmarshalBinaryBare(bz, &ip) + k.cdc.MustUnmarshal(bz, &ip) return ip.Int } @@ -93,6 +90,6 @@ func (k Keeper) GetLastTotalPower(ctx sdk.Context) sdk.Int { // Set the last total validator power. func (k Keeper) SetLastTotalPower(ctx sdk.Context, power sdk.Int) { store := ctx.KVStore(k.storeKey) - bz := k.cdc.MustMarshalBinaryBare(&sdk.IntProto{Int: power}) + bz := k.cdc.MustMarshal(&sdk.IntProto{Int: power}) store.Set(types.LastTotalPowerKey, bz) } diff --git a/x/staking/keeper/keeper_test.go b/x/staking/keeper/keeper_test.go index 7b640e7d7c..4db8ee4a20 100644 --- a/x/staking/keeper/keeper_test.go +++ b/x/staking/keeper/keeper_test.go @@ -45,7 +45,7 @@ func (suite *KeeperTestSuite) SetupTest() { // have its order changed sortedVals := make([]types.Validator, len(validators)) copy(sortedVals, validators) - hi := types.NewHistoricalInfo(header, sortedVals) + hi := types.NewHistoricalInfo(header, sortedVals, app.StakingKeeper.PowerReduction(ctx)) app.StakingKeeper.SetHistoricalInfo(ctx, 5, &hi) suite.app, suite.ctx, suite.queryClient, suite.addrs, suite.vals = app, ctx, queryClient, addrs, validators diff --git a/x/staking/keeper/msg_server.go b/x/staking/keeper/msg_server.go index 19c0d4be09..283562f095 100644 --- a/x/staking/keeper/msg_server.go +++ b/x/staking/keeper/msg_server.go @@ -26,6 +26,7 @@ func NewMsgServerImpl(keeper Keeper) types.MsgServer { var _ types.MsgServer = msgServer{} +// CreateValidator defines a method for creating a new validator func (k msgServer) CreateValidator(goCtx context.Context, msg *types.MsgCreateValidator) (*types.MsgCreateValidatorResponse, error) { ctx := sdk.UnwrapSDKContext(goCtx) @@ -47,7 +48,9 @@ func (k msgServer) CreateValidator(goCtx context.Context, msg *types.MsgCreateVa bondDenom := k.BondDenom(ctx) if msg.Value.Denom != bondDenom { - return nil, sdkerrors.Wrapf(types.ErrBadDenom, "got %s, expected %s", msg.Value.Denom, bondDenom) + return nil, sdkerrors.Wrapf( + sdkerrors.ErrInvalidRequest, "invalid coin denomination: got %s, expected %s", msg.Value.Denom, bondDenom, + ) } if _, err := msg.Description.EnsureLength(); err != nil { @@ -101,7 +104,7 @@ func (k msgServer) CreateValidator(goCtx context.Context, msg *types.MsgCreateVa sdk.NewEvent( types.EventTypeCreateValidator, sdk.NewAttribute(types.AttributeKeyValidator, msg.ValidatorAddress), - sdk.NewAttribute(sdk.AttributeKeyAmount, msg.Value.Amount.String()), + sdk.NewAttribute(sdk.AttributeKeyAmount, msg.Value.String()), ), sdk.NewEvent( sdk.EventTypeMessage, @@ -113,6 +116,7 @@ func (k msgServer) CreateValidator(goCtx context.Context, msg *types.MsgCreateVa return &types.MsgCreateValidatorResponse{}, nil } +// EditValidator defines a method for editing an existing validator func (k msgServer) EditValidator(goCtx context.Context, msg *types.MsgEditValidator) (*types.MsgEditValidatorResponse, error) { ctx := sdk.UnwrapSDKContext(goCtx) valAddr := sdk.ValAddress(msg.ValidatorAddress) @@ -172,6 +176,7 @@ func (k msgServer) EditValidator(goCtx context.Context, msg *types.MsgEditValida return &types.MsgEditValidatorResponse{}, nil } +// Delegate defines a method for performing a delegation of coins from a delegator to a validator func (k msgServer) Delegate(goCtx context.Context, msg *types.MsgDelegate) (*types.MsgDelegateResponse, error) { ctx := sdk.UnwrapSDKContext(goCtx) valAddr := sdk.ValAddress(msg.ValidatorAddress) @@ -185,11 +190,13 @@ func (k msgServer) Delegate(goCtx context.Context, msg *types.MsgDelegate) (*typ bondDenom := k.BondDenom(ctx) if msg.Amount.Denom != bondDenom { - return nil, sdkerrors.Wrapf(types.ErrBadDenom, "got %s, expected %s", msg.Amount.Denom, bondDenom) + return nil, sdkerrors.Wrapf( + sdkerrors.ErrInvalidRequest, "invalid coin denomination: got %s, expected %s", msg.Amount.Denom, bondDenom, + ) } // NOTE: source funds are always unbonded - _, err := k.Keeper.Delegate(ctx, delegatorAddress, msg.Amount.Amount, types.Unbonded, validator, true) + newShares, err := k.Keeper.Delegate(ctx, delegatorAddress, msg.Amount.Amount, types.Unbonded, validator, true) if err != nil { return nil, err } @@ -209,7 +216,8 @@ func (k msgServer) Delegate(goCtx context.Context, msg *types.MsgDelegate) (*typ sdk.NewEvent( types.EventTypeDelegate, sdk.NewAttribute(types.AttributeKeyValidator, msg.ValidatorAddress), - sdk.NewAttribute(sdk.AttributeKeyAmount, msg.Amount.Amount.String()), + sdk.NewAttribute(sdk.AttributeKeyAmount, msg.Amount.String()), + sdk.NewAttribute(types.AttributeKeyNewShares, newShares.String()), ), sdk.NewEvent( sdk.EventTypeMessage, @@ -221,6 +229,7 @@ func (k msgServer) Delegate(goCtx context.Context, msg *types.MsgDelegate) (*typ return &types.MsgDelegateResponse{}, nil } +// BeginRedelegate defines a method for performing a redelegation of coins from a delegator and source validator to a destination validator func (k msgServer) BeginRedelegate(goCtx context.Context, msg *types.MsgBeginRedelegate) (*types.MsgBeginRedelegateResponse, error) { ctx := sdk.UnwrapSDKContext(goCtx) valSrcAddr := sdk.ValAddress(msg.ValidatorSrcAddress) @@ -234,7 +243,9 @@ func (k msgServer) BeginRedelegate(goCtx context.Context, msg *types.MsgBeginRed bondDenom := k.BondDenom(ctx) if msg.Amount.Denom != bondDenom { - return nil, sdkerrors.Wrapf(types.ErrBadDenom, "got %s, expected %s", msg.Amount.Denom, bondDenom) + return nil, sdkerrors.Wrapf( + sdkerrors.ErrInvalidRequest, "invalid coin denomination: got %s, expected %s", msg.Amount.Denom, bondDenom, + ) } valDstAddr := sdk.ValAddress(msg.ValidatorDstAddress) @@ -262,7 +273,7 @@ func (k msgServer) BeginRedelegate(goCtx context.Context, msg *types.MsgBeginRed types.EventTypeRedelegate, sdk.NewAttribute(types.AttributeKeySrcValidator, msg.ValidatorSrcAddress), sdk.NewAttribute(types.AttributeKeyDstValidator, msg.ValidatorDstAddress), - sdk.NewAttribute(sdk.AttributeKeyAmount, msg.Amount.Amount.String()), + sdk.NewAttribute(sdk.AttributeKeyAmount, msg.Amount.String()), sdk.NewAttribute(types.AttributeKeyCompletionTime, completionTime.Format(time.RFC3339)), ), sdk.NewEvent( @@ -277,6 +288,7 @@ func (k msgServer) BeginRedelegate(goCtx context.Context, msg *types.MsgBeginRed }, nil } +// Undelegate defines a method for performing an undelegation from a delegate and a validator func (k msgServer) Undelegate(goCtx context.Context, msg *types.MsgUndelegate) (*types.MsgUndelegateResponse, error) { ctx := sdk.UnwrapSDKContext(goCtx) @@ -291,7 +303,9 @@ func (k msgServer) Undelegate(goCtx context.Context, msg *types.MsgUndelegate) ( bondDenom := k.BondDenom(ctx) if msg.Amount.Denom != bondDenom { - return nil, sdkerrors.Wrapf(types.ErrBadDenom, "got %s, expected %s", msg.Amount.Denom, bondDenom) + return nil, sdkerrors.Wrapf( + sdkerrors.ErrInvalidRequest, "invalid coin denomination: got %s, expected %s", msg.Amount.Denom, bondDenom, + ) } completionTime, err := k.Keeper.Undelegate(ctx, delegatorAddress, addr, shares) @@ -314,7 +328,7 @@ func (k msgServer) Undelegate(goCtx context.Context, msg *types.MsgUndelegate) ( sdk.NewEvent( types.EventTypeUnbond, sdk.NewAttribute(types.AttributeKeyValidator, msg.ValidatorAddress), - sdk.NewAttribute(sdk.AttributeKeyAmount, msg.Amount.Amount.String()), + sdk.NewAttribute(sdk.AttributeKeyAmount, msg.Amount.String()), sdk.NewAttribute(types.AttributeKeyCompletionTime, completionTime.Format(time.RFC3339)), ), sdk.NewEvent( diff --git a/x/staking/keeper/params.go b/x/staking/keeper/params.go index 38ca0358d1..c71e00a6d8 100644 --- a/x/staking/keeper/params.go +++ b/x/staking/keeper/params.go @@ -39,6 +39,14 @@ func (k Keeper) BondDenom(ctx sdk.Context) (res string) { return } +// PowerReduction - is the amount of staking tokens required for 1 unit of consensus-engine power. +// Currently, this returns a global variable that the app developer can tweak. +// TODO: we might turn this into an on-chain param: +// https://github.com/cosmos/cosmos-sdk/issues/8365 +func (k Keeper) PowerReduction(ctx sdk.Context) sdk.Int { + return sdk.DefaultPowerReduction +} + // Get all parameteras as types.Params func (k Keeper) GetParams(ctx sdk.Context) types.Params { return types.NewParams( diff --git a/x/staking/keeper/pool.go b/x/staking/keeper/pool.go index 183f351f76..2552c01f62 100644 --- a/x/staking/keeper/pool.go +++ b/x/staking/keeper/pool.go @@ -64,7 +64,7 @@ func (k Keeper) TotalBondedTokens(ctx sdk.Context) sdk.Int { // StakingTokenSupply staking tokens from the total supply func (k Keeper) StakingTokenSupply(ctx sdk.Context) sdk.Int { - return k.bankKeeper.GetSupply(ctx).GetTotal().AmountOf(k.BondDenom(ctx)) + return k.bankKeeper.GetSupply(ctx, k.BondDenom(ctx)).Amount } // BondedRatio the fraction of the staking tokens which are currently bonded diff --git a/x/staking/keeper/power_reduction.go b/x/staking/keeper/power_reduction.go new file mode 100644 index 0000000000..03dd0cf049 --- /dev/null +++ b/x/staking/keeper/power_reduction.go @@ -0,0 +1,15 @@ +package keeper + +import ( + sdk "github.com/line/lbm-sdk/types" +) + +// TokensToConsensusPower - convert input tokens to potential consensus-engine power +func (k Keeper) TokensToConsensusPower(ctx sdk.Context, tokens sdk.Int) int64 { + return sdk.TokensToConsensusPower(tokens, k.PowerReduction(ctx)) +} + +// TokensFromConsensusPower - convert input power to tokens +func (k Keeper) TokensFromConsensusPower(ctx sdk.Context, power int64) sdk.Int { + return sdk.TokensFromConsensusPower(power, k.PowerReduction(ctx)) +} diff --git a/x/staking/keeper/querier.go b/x/staking/keeper/querier.go index 7c238000bb..aaa5597c45 100644 --- a/x/staking/keeper/querier.go +++ b/x/staking/keeper/querier.go @@ -450,7 +450,6 @@ func queryParameters(ctx sdk.Context, k Keeper, legacyQuerierCdc *codec.LegacyAm return res, nil } -// ______________________________________________________ // util func DelegationToDelegationResponse(ctx sdk.Context, k Keeper, del types.Delegation) (types.DelegationResponse, error) { diff --git a/x/staking/keeper/querier_test.go b/x/staking/keeper/querier_test.go index 52e4a9369f..a742933364 100644 --- a/x/staking/keeper/querier_test.go +++ b/x/staking/keeper/querier_test.go @@ -20,14 +20,14 @@ func TestNewQuerier(t *testing.T) { cdc, app, ctx := createTestInput() addrs := simapp.AddTestAddrs(app, ctx, 500, sdk.NewInt(10000)) - _, addrAcc2 := addrs[0], addrs[1] - addrVal1, _ := sdk.ValAddress(addrs[0]), sdk.ValAddress(addrs[1]) + addrAcc1, addrAcc2 := addrs[0], addrs[1] + addrVal1 := addrAcc1.ToValAddress() // Create Validators amts := []sdk.Int{sdk.NewInt(9), sdk.NewInt(8)} var validators [2]types.Validator for i, amt := range amts { - validators[i] = teststaking.NewValidator(t, sdk.ValAddress(addrs[i]), PKs[i]) + validators[i] = teststaking.NewValidator(t, sdk.AccAddress(addrs[i]).ToValAddress(), PKs[i]) validators[i], _ = validators[i].AddTokensFromDel(amt) app.StakingKeeper.SetValidator(ctx, validators[i]) app.StakingKeeper.SetValidatorByPowerIndex(ctx, validators[i]) @@ -37,7 +37,7 @@ func TestNewQuerier(t *testing.T) { ChainID: "HelloChain", Height: 5, } - hi := types.NewHistoricalInfo(header, validators[:]) + hi := types.NewHistoricalInfo(header, validators[:], app.StakingKeeper.PowerReduction(ctx)) app.StakingKeeper.SetHistoricalInfo(ctx, 5, &hi) query := abci.RequestQuery{ @@ -140,7 +140,7 @@ func TestQueryValidators(t *testing.T) { legacyQuerierCdc := codec.NewAminoCodec(app.LegacyAmino()) querier := keeper.NewQuerier(app.StakingKeeper, legacyQuerierCdc.LegacyAmino) - addrs := simapp.AddTestAddrs(app, ctx, 500, sdk.TokensFromConsensusPower(10000)) + addrs := simapp.AddTestAddrs(app, ctx, 500, app.StakingKeeper.TokensFromConsensusPower(ctx, 10000)) // Create Validators amts := []sdk.Int{sdk.NewInt(9), sdk.NewInt(8), sdk.NewInt(7)} @@ -208,7 +208,7 @@ func TestQueryDelegation(t *testing.T) { legacyQuerierCdc := codec.NewAminoCodec(app.LegacyAmino()) querier := keeper.NewQuerier(app.StakingKeeper, legacyQuerierCdc.LegacyAmino) - addrs := simapp.AddTestAddrs(app, ctx, 2, sdk.TokensFromConsensusPower(10000)) + addrs := simapp.AddTestAddrs(app, ctx, 2, app.StakingKeeper.TokensFromConsensusPower(ctx, 10000)) addrAcc1, addrAcc2 := addrs[0], addrs[1] addrVal1, addrVal2 := addrAcc1.ToValAddress(), addrAcc2.ToValAddress() @@ -224,7 +224,7 @@ func TestQueryDelegation(t *testing.T) { app.StakingKeeper.SetValidator(ctx, val2) app.StakingKeeper.SetValidatorByPowerIndex(ctx, val2) - delTokens := sdk.TokensFromConsensusPower(20) + delTokens := app.StakingKeeper.TokensFromConsensusPower(ctx, 20) _, err := app.StakingKeeper.Delegate(ctx, addrAcc2, delTokens, types.Unbonded, val1, true) require.NoError(t, err) @@ -348,7 +348,7 @@ func TestQueryDelegation(t *testing.T) { require.Equal(t, sdk.NewCoin(sdk.DefaultBondDenom, delegation.Shares.TruncateInt()), delegationsRes[0].Balance) // Query unbonding delegation - unbondingTokens := sdk.TokensFromConsensusPower(10) + unbondingTokens := app.StakingKeeper.TokensFromConsensusPower(ctx, 10) _, err = app.StakingKeeper.Undelegate(ctx, addrAcc2, val1.GetOperator(), unbondingTokens.ToDec()) require.NoError(t, err) @@ -401,7 +401,7 @@ func TestQueryDelegation(t *testing.T) { require.Error(t, err) // Query redelegation - redelegationTokens := sdk.TokensFromConsensusPower(10) + redelegationTokens := app.StakingKeeper.TokensFromConsensusPower(ctx, 10) _, err = app.StakingKeeper.BeginRedelegation(ctx, addrAcc2, val1.GetOperator(), val2.GetOperator(), redelegationTokens.ToDec()) require.NoError(t, err) @@ -456,7 +456,7 @@ func TestQueryValidatorDelegations_Pagination(t *testing.T) { legacyQuerierCdc := codec.NewAminoCodec(app.LegacyAmino()) querier := keeper.NewQuerier(app.StakingKeeper, legacyQuerierCdc.LegacyAmino) - addrs := simapp.AddTestAddrs(app, ctx, 100, sdk.TokensFromConsensusPower(10000)) + addrs := simapp.AddTestAddrs(app, ctx, 100, app.StakingKeeper.TokensFromConsensusPower(ctx, 10000)) pubKeys := simapp.CreateTestPubKeys(1) valAddress := addrs[0].ToValAddress() @@ -472,7 +472,7 @@ func TestQueryValidatorDelegations_Pagination(t *testing.T) { t.Error("expected validator not found") } - delTokens := sdk.TokensFromConsensusPower(20) + delTokens := app.StakingKeeper.TokensFromConsensusPower(ctx, 20) _, err := app.StakingKeeper.Delegate(ctx, addr, delTokens, types.Unbonded, validator, true) require.NoError(t, err) } @@ -506,7 +506,7 @@ func TestQueryValidatorDelegations_Pagination(t *testing.T) { // Undelegate for _, addr := range addrs { - delTokens := sdk.TokensFromConsensusPower(20) + delTokens := app.StakingKeeper.TokensFromConsensusPower(ctx, 20) _, err := app.StakingKeeper.Undelegate(ctx, addr, val1.GetOperator(), delTokens.ToDec()) require.NoError(t, err) } @@ -541,7 +541,7 @@ func TestQueryRedelegations(t *testing.T) { legacyQuerierCdc := codec.NewAminoCodec(app.LegacyAmino()) querier := keeper.NewQuerier(app.StakingKeeper, legacyQuerierCdc.LegacyAmino) - addrs := simapp.AddTestAddrs(app, ctx, 2, sdk.TokensFromConsensusPower(10000)) + addrs := simapp.AddTestAddrs(app, ctx, 2, app.StakingKeeper.TokensFromConsensusPower(ctx, 10000)) addrAcc1, addrAcc2 := addrs[0], addrs[1] addrVal1, addrVal2 := addrAcc1.ToValAddress(), addrAcc2.ToValAddress() @@ -551,12 +551,12 @@ func TestQueryRedelegations(t *testing.T) { app.StakingKeeper.SetValidator(ctx, val1) app.StakingKeeper.SetValidator(ctx, val2) - delAmount := sdk.TokensFromConsensusPower(100) + delAmount := app.StakingKeeper.TokensFromConsensusPower(ctx, 100) _, err := app.StakingKeeper.Delegate(ctx, addrAcc2, delAmount, types.Unbonded, val1, true) require.NoError(t, err) applyValidatorSetUpdates(t, ctx, app.StakingKeeper, -1) - rdAmount := sdk.TokensFromConsensusPower(20) + rdAmount := app.StakingKeeper.TokensFromConsensusPower(ctx, 20) _, err = app.StakingKeeper.BeginRedelegation(ctx, addrAcc2, val1.GetOperator(), val2.GetOperator(), rdAmount.ToDec()) require.NoError(t, err) applyValidatorSetUpdates(t, ctx, app.StakingKeeper, -1) @@ -613,7 +613,7 @@ func TestQueryUnbondingDelegation(t *testing.T) { legacyQuerierCdc := codec.NewAminoCodec(app.LegacyAmino()) querier := keeper.NewQuerier(app.StakingKeeper, legacyQuerierCdc.LegacyAmino) - addrs := simapp.AddTestAddrs(app, ctx, 2, sdk.TokensFromConsensusPower(10000)) + addrs := simapp.AddTestAddrs(app, ctx, 2, app.StakingKeeper.TokensFromConsensusPower(ctx, 10000)) addrAcc1, addrAcc2 := addrs[0], addrs[1] addrVal1 := addrAcc1.ToValAddress() @@ -622,13 +622,13 @@ func TestQueryUnbondingDelegation(t *testing.T) { app.StakingKeeper.SetValidator(ctx, val1) // delegate - delAmount := sdk.TokensFromConsensusPower(100) + delAmount := app.StakingKeeper.TokensFromConsensusPower(ctx, 100) _, err := app.StakingKeeper.Delegate(ctx, addrAcc1, delAmount, types.Unbonded, val1, true) require.NoError(t, err) applyValidatorSetUpdates(t, ctx, app.StakingKeeper, -1) // undelegate - undelAmount := sdk.TokensFromConsensusPower(20) + undelAmount := app.StakingKeeper.TokensFromConsensusPower(ctx, 20) _, err = app.StakingKeeper.Undelegate(ctx, addrAcc1, val1.GetOperator(), undelAmount.ToDec()) require.NoError(t, err) applyValidatorSetUpdates(t, ctx, app.StakingKeeper, -1) @@ -709,7 +709,7 @@ func TestQueryHistoricalInfo(t *testing.T) { legacyQuerierCdc := codec.NewAminoCodec(cdc) querier := keeper.NewQuerier(app.StakingKeeper, legacyQuerierCdc.LegacyAmino) - addrs := simapp.AddTestAddrs(app, ctx, 2, sdk.TokensFromConsensusPower(10000)) + addrs := simapp.AddTestAddrs(app, ctx, 2, app.StakingKeeper.TokensFromConsensusPower(ctx, 10000)) addrAcc1, addrAcc2 := addrs[0], addrs[1] addrVal1, addrVal2 := addrAcc1.ToValAddress(), addrAcc2.ToValAddress() @@ -724,7 +724,7 @@ func TestQueryHistoricalInfo(t *testing.T) { ChainID: "HelloChain", Height: 5, } - hi := types.NewHistoricalInfo(header, vals) + hi := types.NewHistoricalInfo(header, vals, app.StakingKeeper.PowerReduction(ctx)) app.StakingKeeper.SetHistoricalInfo(ctx, 5, &hi) queryHistoricalParams := types.QueryHistoricalInfoRequest{Height: 4} diff --git a/x/staking/keeper/query_utils.go b/x/staking/keeper/query_utils.go index 731c149e5f..9d04cfaf1a 100644 --- a/x/staking/keeper/query_utils.go +++ b/x/staking/keeper/query_utils.go @@ -50,8 +50,6 @@ func (k Keeper) GetDelegatorValidator( return validator, nil } -// _____________________________________________________________________________________ - // return all delegations for a delegator func (k Keeper) GetAllDelegatorDelegations(ctx sdk.Context, delegator sdk.AccAddress) []types.Delegation { delegations := make([]types.Delegation, 0) diff --git a/x/staking/keeper/slash.go b/x/staking/keeper/slash.go index fd2550118d..fe4f9bf238 100644 --- a/x/staking/keeper/slash.go +++ b/x/staking/keeper/slash.go @@ -29,7 +29,7 @@ func (k Keeper) Slash(ctx sdk.Context, consAddr sdk.ConsAddress, infractionHeigh } // Amount of slashing = slash slashFactor * power at time of infraction - amount := sdk.TokensFromConsensusPower(power) + amount := k.TokensFromConsensusPower(ctx, power) slashAmountDec := amount.ToDec().Mul(slashFactor) slashAmount := slashAmountDec.TruncateInt() diff --git a/x/staking/keeper/slash_test.go b/x/staking/keeper/slash_test.go index 0bac8fa9e8..ba098d91cf 100644 --- a/x/staking/keeper/slash_test.go +++ b/x/staking/keeper/slash_test.go @@ -10,7 +10,6 @@ import ( "github.com/line/lbm-sdk/simapp" sdk "github.com/line/lbm-sdk/types" - banktypes "github.com/line/lbm-sdk/x/bank/types" "github.com/line/lbm-sdk/x/staking/keeper" "github.com/line/lbm-sdk/x/staking/teststaking" "github.com/line/lbm-sdk/x/staking/types" @@ -22,12 +21,11 @@ func bootstrapSlashTest(t *testing.T, power int64) (*simapp.SimApp, sdk.Context, addrDels, addrVals := generateAddresses(app, ctx, 100) - amt := sdk.TokensFromConsensusPower(power) + amt := app.StakingKeeper.TokensFromConsensusPower(ctx, power) totalSupply := sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), amt.MulRaw(int64(len(addrDels))))) notBondedPool := app.StakingKeeper.GetNotBondedPool(ctx) - err := app.BankKeeper.SetBalances(ctx, notBondedPool.GetAddress(), totalSupply) - require.NoError(t, err) + require.NoError(t, simapp.FundModuleAccount(app, ctx, notBondedPool.GetName(), totalSupply)) app.AccountKeeper.SetModuleAccount(ctx, notBondedPool) @@ -35,11 +33,9 @@ func bootstrapSlashTest(t *testing.T, power int64) (*simapp.SimApp, sdk.Context, bondedCoins := sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), amt.MulRaw(numVals))) bondedPool := app.StakingKeeper.GetBondedPool(ctx) - err = app.BankKeeper.SetBalances(ctx, bondedPool.GetAddress(), bondedCoins) - require.NoError(t, err) - + // set bonded pool balance app.AccountKeeper.SetModuleAccount(ctx, bondedPool) - app.BankKeeper.SetSupply(ctx, banktypes.NewSupply(totalSupply)) + require.NoError(t, simapp.FundModuleAccount(app, ctx, bondedPool.GetName(), bondedCoins)) for i := int64(0); i < numVals; i++ { validator := teststaking.NewValidator(t, addrVals[i], PKs[i]) @@ -129,7 +125,7 @@ func TestSlashRedelegation(t *testing.T) { bondedPool := app.StakingKeeper.GetBondedPool(ctx) balances := app.BankKeeper.GetAllBalances(ctx, bondedPool.GetAddress()) - require.NoError(t, app.BankKeeper.SetBalances(ctx, bondedPool.GetAddress(), balances.Add(startCoins...))) + require.NoError(t, simapp.FundModuleAccount(app, ctx, bondedPool.GetName(), startCoins)) app.AccountKeeper.SetModuleAccount(ctx, bondedPool) // set a redelegation with an expiration timestamp beyond which the @@ -219,12 +215,12 @@ func TestSlashAtNegativeHeight(t *testing.T) { validator, found = app.StakingKeeper.GetValidator(ctx, validator.GetOperator()) require.True(t, found) // power decreased - require.Equal(t, int64(5), validator.GetConsensusPower()) + require.Equal(t, int64(5), validator.GetConsensusPower(app.StakingKeeper.PowerReduction(ctx))) // pool bonded shares decreased newBondedPoolBalances := app.BankKeeper.GetAllBalances(ctx, bondedPool.GetAddress()) diffTokens := oldBondedPoolBalances.Sub(newBondedPoolBalances).AmountOf(app.StakingKeeper.BondDenom(ctx)) - require.Equal(t, sdk.TokensFromConsensusPower(5).String(), diffTokens.String()) + require.Equal(t, app.StakingKeeper.TokensFromConsensusPower(ctx, 5).String(), diffTokens.String()) } // tests Slash at the current height @@ -250,12 +246,12 @@ func TestSlashValidatorAtCurrentHeight(t *testing.T) { validator, found = app.StakingKeeper.GetValidator(ctx, validator.GetOperator()) assert.True(t, found) // power decreased - require.Equal(t, int64(5), validator.GetConsensusPower()) + require.Equal(t, int64(5), validator.GetConsensusPower(app.StakingKeeper.PowerReduction(ctx))) // pool bonded shares decreased newBondedPoolBalances := app.BankKeeper.GetAllBalances(ctx, bondedPool.GetAddress()) diffTokens := oldBondedPoolBalances.Sub(newBondedPoolBalances).AmountOf(app.StakingKeeper.BondDenom(ctx)) - require.Equal(t, sdk.TokensFromConsensusPower(5).String(), diffTokens.String()) + require.Equal(t, app.StakingKeeper.TokensFromConsensusPower(ctx, 5).String(), diffTokens.String()) } // tests Slash at a previous height with an unbonding delegation @@ -267,7 +263,7 @@ func TestSlashWithUnbondingDelegation(t *testing.T) { // set an unbonding delegation with expiration timestamp beyond which the // unbonding delegation shouldn't be slashed - ubdTokens := sdk.TokensFromConsensusPower(4) + ubdTokens := app.StakingKeeper.TokensFromConsensusPower(ctx, 4) ubd := types.NewUnbondingDelegation(addrDels[0], addrVals[0], 11, time.Unix(0, 0), ubdTokens) app.StakingKeeper.SetUnbondingDelegation(ctx, ubd) @@ -289,12 +285,12 @@ func TestSlashWithUnbondingDelegation(t *testing.T) { require.Len(t, ubd.Entries, 1) // balance decreased - require.Equal(t, sdk.TokensFromConsensusPower(2), ubd.Entries[0].Balance) + require.Equal(t, app.StakingKeeper.TokensFromConsensusPower(ctx, 2), ubd.Entries[0].Balance) // bonded tokens burned newBondedPoolBalances := app.BankKeeper.GetAllBalances(ctx, bondedPool.GetAddress()) diffTokens := oldBondedPoolBalances.Sub(newBondedPoolBalances).AmountOf(app.StakingKeeper.BondDenom(ctx)) - require.Equal(t, sdk.TokensFromConsensusPower(3), diffTokens) + require.Equal(t, app.StakingKeeper.TokensFromConsensusPower(ctx, 3), diffTokens) // read updated validator validator, found = app.StakingKeeper.GetValidatorByConsAddr(ctx, consAddr) @@ -304,7 +300,7 @@ func TestSlashWithUnbondingDelegation(t *testing.T) { // was still bonded at the time of discovery and was slashed by half, 4 stake // bonded at the time of discovery hadn't been bonded at the time of infraction // and wasn't slashed - require.Equal(t, int64(7), validator.GetConsensusPower()) + require.Equal(t, int64(7), validator.GetConsensusPower(app.StakingKeeper.PowerReduction(ctx))) // slash validator again ctx = ctx.WithBlockHeight(13) @@ -320,19 +316,19 @@ func TestSlashWithUnbondingDelegation(t *testing.T) { // bonded tokens burned again newBondedPoolBalances = app.BankKeeper.GetAllBalances(ctx, bondedPool.GetAddress()) diffTokens = oldBondedPoolBalances.Sub(newBondedPoolBalances).AmountOf(app.StakingKeeper.BondDenom(ctx)) - require.Equal(t, sdk.TokensFromConsensusPower(6), diffTokens) + require.Equal(t, app.StakingKeeper.TokensFromConsensusPower(ctx, 6), diffTokens) // read updated validator validator, found = app.StakingKeeper.GetValidatorByConsAddr(ctx, consAddr) require.True(t, found) // power decreased by 3 again - require.Equal(t, int64(4), validator.GetConsensusPower()) + require.Equal(t, int64(4), validator.GetConsensusPower(app.StakingKeeper.PowerReduction(ctx))) // slash validator again // all originally bonded stake has been slashed, so this will have no effect // on the unbonding delegation, but it will slash stake bonded since the infraction - // this may not be the desirable behaviour, ref https://github.com/line/lbm-sdk/issues/1440 + // this may not be the desirable behaviour, ref https://github.com/cosmos/cosmos-sdk/issues/1440 ctx = ctx.WithBlockHeight(13) app.StakingKeeper.Slash(ctx, consAddr, 9, 10, fraction) @@ -346,19 +342,19 @@ func TestSlashWithUnbondingDelegation(t *testing.T) { // bonded tokens burned again newBondedPoolBalances = app.BankKeeper.GetAllBalances(ctx, bondedPool.GetAddress()) diffTokens = oldBondedPoolBalances.Sub(newBondedPoolBalances).AmountOf(app.StakingKeeper.BondDenom(ctx)) - require.Equal(t, sdk.TokensFromConsensusPower(9), diffTokens) + require.Equal(t, app.StakingKeeper.TokensFromConsensusPower(ctx, 9), diffTokens) // read updated validator validator, found = app.StakingKeeper.GetValidatorByConsAddr(ctx, consAddr) require.True(t, found) // power decreased by 3 again - require.Equal(t, int64(1), validator.GetConsensusPower()) + require.Equal(t, int64(1), validator.GetConsensusPower(app.StakingKeeper.PowerReduction(ctx))) // slash validator again // all originally bonded stake has been slashed, so this will have no effect // on the unbonding delegation, but it will slash stake bonded since the infraction - // this may not be the desirable behaviour, ref https://github.com/line/lbm-sdk/issues/1440 + // this may not be the desirable behaviour, ref https://github.com/cosmos/cosmos-sdk/issues/1440 ctx = ctx.WithBlockHeight(13) app.StakingKeeper.Slash(ctx, consAddr, 9, 10, fraction) @@ -372,7 +368,7 @@ func TestSlashWithUnbondingDelegation(t *testing.T) { // just 1 bonded token burned again since that's all the validator now has newBondedPoolBalances = app.BankKeeper.GetAllBalances(ctx, bondedPool.GetAddress()) diffTokens = oldBondedPoolBalances.Sub(newBondedPoolBalances).AmountOf(app.StakingKeeper.BondDenom(ctx)) - require.Equal(t, sdk.TokensFromConsensusPower(10), diffTokens) + require.Equal(t, app.StakingKeeper.TokensFromConsensusPower(ctx, 10), diffTokens) // apply TM updates applyValidatorSetUpdates(t, ctx, app.StakingKeeper, -1) @@ -384,7 +380,6 @@ func TestSlashWithUnbondingDelegation(t *testing.T) { require.Equal(t, validator.GetStatus(), types.Unbonding) } -// _________________________________________________________________________________ // tests Slash at a previous height with a redelegation func TestSlashWithRedelegation(t *testing.T) { app, ctx, addrDels, addrVals := bootstrapSlashTest(t, 10) @@ -393,7 +388,7 @@ func TestSlashWithRedelegation(t *testing.T) { bondDenom := app.StakingKeeper.BondDenom(ctx) // set a redelegation - rdTokens := sdk.TokensFromConsensusPower(6) + rdTokens := app.StakingKeeper.TokensFromConsensusPower(ctx, 6) rd := types.NewRedelegation(addrDels[0], addrVals[0], addrVals[1], 11, time.Unix(0, 0), rdTokens, rdTokens.ToDec()) app.StakingKeeper.SetRedelegation(ctx, rd) @@ -407,10 +402,7 @@ func TestSlashWithRedelegation(t *testing.T) { notBondedPool := app.StakingKeeper.GetNotBondedPool(ctx) rdCoins := sdk.NewCoins(sdk.NewCoin(bondDenom, rdTokens.MulRaw(2))) - balances := app.BankKeeper.GetAllBalances(ctx, bondedPool.GetAddress()) - - err := app.BankKeeper.SetBalances(ctx, bondedPool.GetAddress(), balances.Add(rdCoins...)) - require.NoError(t, err) + require.NoError(t, simapp.FundModuleAccount(app, ctx, bondedPool.GetName(), rdCoins)) app.AccountKeeper.SetModuleAccount(ctx, bondedPool) @@ -423,7 +415,7 @@ func TestSlashWithRedelegation(t *testing.T) { require.True(t, found) require.NotPanics(t, func() { app.StakingKeeper.Slash(ctx, consAddr, 10, 10, fraction) }) - burnAmount := sdk.TokensFromConsensusPower(10).ToDec().Mul(fraction).TruncateInt() + burnAmount := app.StakingKeeper.TokensFromConsensusPower(ctx, 10).ToDec().Mul(fraction).TruncateInt() bondedPool = app.StakingKeeper.GetBondedPool(ctx) notBondedPool = app.StakingKeeper.GetNotBondedPool(ctx) @@ -447,14 +439,14 @@ func TestSlashWithRedelegation(t *testing.T) { // was still bonded at the time of discovery and was slashed by half, 4 stake // bonded at the time of discovery hadn't been bonded at the time of infraction // and wasn't slashed - require.Equal(t, int64(8), validator.GetConsensusPower()) + require.Equal(t, int64(8), validator.GetConsensusPower(app.StakingKeeper.PowerReduction(ctx))) // slash the validator again validator, found = app.StakingKeeper.GetValidatorByConsAddr(ctx, consAddr) require.True(t, found) require.NotPanics(t, func() { app.StakingKeeper.Slash(ctx, consAddr, 10, 10, sdk.OneDec()) }) - burnAmount = sdk.TokensFromConsensusPower(7) + burnAmount = app.StakingKeeper.TokensFromConsensusPower(ctx, 7) // read updated pool bondedPool = app.StakingKeeper.GetBondedPool(ctx) @@ -480,7 +472,7 @@ func TestSlashWithRedelegation(t *testing.T) { validator, found = app.StakingKeeper.GetValidatorByConsAddr(ctx, consAddr) require.True(t, found) // power decreased by 4 - require.Equal(t, int64(4), validator.GetConsensusPower()) + require.Equal(t, int64(4), validator.GetConsensusPower(app.StakingKeeper.PowerReduction(ctx))) // slash the validator again, by 100% ctx = ctx.WithBlockHeight(12) @@ -489,7 +481,7 @@ func TestSlashWithRedelegation(t *testing.T) { require.NotPanics(t, func() { app.StakingKeeper.Slash(ctx, consAddr, 10, 10, sdk.OneDec()) }) - burnAmount = sdk.TokensFromConsensusPower(10).ToDec().Mul(sdk.OneDec()).TruncateInt() + burnAmount = app.StakingKeeper.TokensFromConsensusPower(ctx, 10).ToDec().Mul(sdk.OneDec()).TruncateInt() burnAmount = burnAmount.Sub(sdk.OneDec().MulInt(rdTokens).TruncateInt()) // read updated pool @@ -549,7 +541,7 @@ func TestSlashBoth(t *testing.T) { // set a redelegation with expiration timestamp beyond which the // redelegation shouldn't be slashed - rdATokens := sdk.TokensFromConsensusPower(6) + rdATokens := app.StakingKeeper.TokensFromConsensusPower(ctx, 6) rdA := types.NewRedelegation(addrDels[0], addrVals[0], addrVals[1], 11, time.Unix(0, 0), rdATokens, rdATokens.ToDec()) @@ -561,7 +553,7 @@ func TestSlashBoth(t *testing.T) { // set an unbonding delegation with expiration timestamp (beyond which the // unbonding delegation shouldn't be slashed) - ubdATokens := sdk.TokensFromConsensusPower(4) + ubdATokens := app.StakingKeeper.TokensFromConsensusPower(ctx, 4) ubdA := types.NewUnbondingDelegation(addrDels[0], addrVals[0], 11, time.Unix(0, 0), ubdATokens) app.StakingKeeper.SetUnbondingDelegation(ctx, ubdA) @@ -573,11 +565,8 @@ func TestSlashBoth(t *testing.T) { bondedPool := app.StakingKeeper.GetBondedPool(ctx) notBondedPool := app.StakingKeeper.GetNotBondedPool(ctx) - bondedPoolBalances := app.BankKeeper.GetAllBalances(ctx, bondedPool.GetAddress()) - require.NoError(t, app.BankKeeper.SetBalances(ctx, bondedPool.GetAddress(), bondedPoolBalances.Add(bondedCoins...))) - - notBondedPoolBalances := app.BankKeeper.GetAllBalances(ctx, notBondedPool.GetAddress()) - require.NoError(t, app.BankKeeper.SetBalances(ctx, notBondedPool.GetAddress(), notBondedPoolBalances.Add(notBondedCoins...))) + require.NoError(t, simapp.FundModuleAccount(app, ctx, bondedPool.GetName(), bondedCoins)) + require.NoError(t, simapp.FundModuleAccount(app, ctx, notBondedPool.GetName(), notBondedCoins)) app.AccountKeeper.SetModuleAccount(ctx, bondedPool) app.AccountKeeper.SetModuleAccount(ctx, notBondedPool) @@ -592,7 +581,7 @@ func TestSlashBoth(t *testing.T) { app.StakingKeeper.Slash(ctx, consAddr0, 10, 10, fraction) burnedNotBondedAmount := fraction.MulInt(ubdATokens).TruncateInt() - burnedBondAmount := sdk.TokensFromConsensusPower(10).ToDec().Mul(fraction).TruncateInt() + burnedBondAmount := app.StakingKeeper.TokensFromConsensusPower(ctx, 10).ToDec().Mul(fraction).TruncateInt() burnedBondAmount = burnedBondAmount.Sub(burnedNotBondedAmount) // read updated pool @@ -613,5 +602,5 @@ func TestSlashBoth(t *testing.T) { validator, found = app.StakingKeeper.GetValidatorByConsAddr(ctx, sdk.GetConsAddress(PKs[0])) require.True(t, found) // power not decreased, all stake was bonded since - require.Equal(t, int64(10), validator.GetConsensusPower()) + require.Equal(t, int64(10), validator.GetConsensusPower(app.StakingKeeper.PowerReduction(ctx))) } diff --git a/x/staking/keeper/val_state_change.go b/x/staking/keeper/val_state_change.go index 97d1b92b7f..f577ac1160 100644 --- a/x/staking/keeper/val_state_change.go +++ b/x/staking/keeper/val_state_change.go @@ -13,7 +13,7 @@ import ( "github.com/line/lbm-sdk/x/staking/types" ) -// Calculate the ValidatorUpdates for the current block +// BlockValidatorUpdates calculates the ValidatorUpdates for the current block // Called in each EndBlock func (k Keeper) BlockValidatorUpdates(ctx sdk.Context) []abci.ValidatorUpdate { // Calculate validator set changes. @@ -79,7 +79,7 @@ func (k Keeper) BlockValidatorUpdates(ctx sdk.Context) []abci.ValidatorUpdate { return validatorUpdates } -// Apply and return accumulated updates to the bonded validator set. Also, +// ApplyAndReturnValidatorSetUpdates applies and return accumulated updates to the bonded validator set. Also, // * Updates the active valset as keyed by LastValidatorPowerKey. // * Updates the total power as keyed by LastTotalPowerKey. // * Updates validator status' according to updated powers. @@ -92,7 +92,9 @@ func (k Keeper) BlockValidatorUpdates(ctx sdk.Context) []abci.ValidatorUpdate { // at the previous block height or were removed from the validator set entirely // are returned to Tendermint. func (k Keeper) ApplyAndReturnValidatorSetUpdates(ctx sdk.Context) (updates []abci.ValidatorUpdate, err error) { - maxValidators := k.GetParams(ctx).MaxValidators + params := k.GetParams(ctx) + maxValidators := params.MaxValidators + powerReduction := k.PowerReduction(ctx) totalPower := sdk.ZeroInt() amtFromBondedToNotBonded, amtFromNotBondedToBonded := sdk.ZeroInt(), sdk.ZeroInt() @@ -117,7 +119,7 @@ func (k Keeper) ApplyAndReturnValidatorSetUpdates(ctx sdk.Context) (updates []ab // if we get to a zero-power validator (which we don't bond), // there are no more possible bonded validators - if validator.PotentialConsensusPower() == 0 { + if validator.PotentialConsensusPower(k.PowerReduction(ctx)) == 0 { break } @@ -143,12 +145,12 @@ func (k Keeper) ApplyAndReturnValidatorSetUpdates(ctx sdk.Context) (updates []ab // fetch the old power bytes oldPowerBytes, found := last[valAddr.String()] - newPower := validator.ConsensusPower() - newPowerBytes := k.cdc.MustMarshalBinaryBare(&gogotypes.Int64Value{Value: newPower}) + newPower := validator.ConsensusPower(powerReduction) + newPowerBytes := k.cdc.MustMarshal(&gogotypes.Int64Value{Value: newPower}) // update the validator set if power has changed if !found || !bytes.Equal(oldPowerBytes, newPowerBytes) { - updates = append(updates, validator.ABCIValidatorUpdate()) + updates = append(updates, validator.ABCIValidatorUpdate(powerReduction)) k.SetLastValidatorPower(ctx, valAddr, newPower) } @@ -318,7 +320,8 @@ func (k Keeper) completeUnbondingValidator(ctx sdk.Context, validator types.Vali return validator } -// map of operator addresses to serialized power +// map of operator bech32-addresses to serialized power +// We use bech32 strings here, because we can't have slices as keys: map[[]byte][]byte type validatorsByAddr map[string][]byte // get the last validator set @@ -329,8 +332,8 @@ func (k Keeper) getLastValidatorsByAddr(ctx sdk.Context) validatorsByAddr { defer iterator.Close() for ; iterator.Valid(); iterator.Next() { - // extract the validator address from the key (prefix is 1-byte) - valAddr := string(iterator.Key()[1:]) + // extract the validator address from the key (prefix is 1-byte, addrLen is 1-byte) + valAddr := string(iterator.Key()[2:]) powerBytes := iterator.Value() last[valAddr] = make([]byte, len(powerBytes)) copy(last[valAddr], powerBytes) @@ -346,8 +349,8 @@ func sortNoLongerBonded(last validatorsByAddr) []string { noLongerBonded := make([]string, len(last)) index := 0 - for valAddrBytes := range last { - noLongerBonded[index] = valAddrBytes + for valAddrStr := range last { + noLongerBonded[index] = valAddrStr index++ } // sorted by address - order doesn't matter diff --git a/x/staking/keeper/validator.go b/x/staking/keeper/validator.go index ab4d7bc4a3..d40eef4397 100644 --- a/x/staking/keeper/validator.go +++ b/x/staking/keeper/validator.go @@ -79,19 +79,19 @@ func (k Keeper) SetValidatorByPowerIndex(ctx sdk.Context, validator types.Valida } store := ctx.KVStore(k.storeKey) - store.Set(types.GetValidatorsByPowerIndexKey(validator), validator.GetOperator().Bytes()) + store.Set(types.GetValidatorsByPowerIndexKey(validator, k.PowerReduction(ctx)), validator.GetOperator().Bytes()) } // validator index func (k Keeper) DeleteValidatorByPowerIndex(ctx sdk.Context, validator types.Validator) { store := ctx.KVStore(k.storeKey) - store.Delete(types.GetValidatorsByPowerIndexKey(validator)) + store.Delete(types.GetValidatorsByPowerIndexKey(validator, k.PowerReduction(ctx))) } // validator index func (k Keeper) SetNewValidatorByPowerIndex(ctx sdk.Context, validator types.Validator) { store := ctx.KVStore(k.storeKey) - store.Set(types.GetValidatorsByPowerIndexKey(validator), validator.GetOperator().Bytes()) + store.Set(types.GetValidatorsByPowerIndexKey(validator, k.PowerReduction(ctx)), validator.GetOperator().Bytes()) } // Update the tokens of an existing validator, update the validators power index key @@ -171,7 +171,7 @@ func (k Keeper) RemoveValidator(ctx sdk.Context, address sdk.ValAddress) { store := ctx.KVStore(k.storeKey) store.Delete(types.GetValidatorKey(address)) store.Delete(types.GetValidatorByConsAddrKey(valConsAddr)) - store.Delete(types.GetValidatorsByPowerIndexKey(validator)) + store.Delete(types.GetValidatorsByPowerIndexKey(validator, k.PowerReduction(ctx))) // call hooks k.AfterValidatorRemoved(ctx, valConsAddr, validator.GetOperator()) @@ -240,7 +240,6 @@ func (k Keeper) ValidatorsPowerStoreIterator(ctx sdk.Context) sdk.Iterator { return sdk.KVStoreReversePrefixIterator(store, types.ValidatorsByPowerIndexKey) } -// _______________________________________________________________________ // Last Validator Index // Load the last validator power. @@ -254,7 +253,7 @@ func (k Keeper) GetLastValidatorPower(ctx sdk.Context, operator sdk.ValAddress) } intV := gogotypes.Int64Value{} - k.cdc.MustUnmarshalBinaryBare(bz, &intV) + k.cdc.MustUnmarshal(bz, &intV) return intV.GetValue() } @@ -262,7 +261,7 @@ func (k Keeper) GetLastValidatorPower(ctx sdk.Context, operator sdk.ValAddress) // Set the last validator power. func (k Keeper) SetLastValidatorPower(ctx sdk.Context, operator sdk.ValAddress, power int64) { store := ctx.KVStore(k.storeKey) - bz := k.cdc.MustMarshalBinaryBare(&gogotypes.Int64Value{Value: power}) + bz := k.cdc.MustMarshal(&gogotypes.Int64Value{Value: power}) store.Set(types.GetLastValidatorPowerKey(operator), bz) } @@ -288,10 +287,10 @@ func (k Keeper) IterateLastValidatorPowers(ctx sdk.Context, handler func(operato defer iter.Close() for ; iter.Valid(); iter.Next() { - addr := sdk.ValAddress(iter.Key()[len(types.LastValidatorPowerKey):]) + addr := sdk.ValAddress(types.AddressFromLastValidatorPowerKey(iter.Key())) intV := &gogotypes.Int64Value{} - k.cdc.MustUnmarshalBinaryBare(iter.Value(), intV) + k.cdc.MustUnmarshal(iter.Value(), intV) if handler(addr, intV.GetValue()) { break @@ -338,7 +337,7 @@ func (k Keeper) GetUnbondingValidators(ctx sdk.Context, endTime time.Time, endHe } addrs := types.ValAddresses{} - k.cdc.MustUnmarshalBinaryBare(bz, &addrs) + k.cdc.MustUnmarshal(bz, &addrs) return addrs.Addresses } @@ -347,7 +346,7 @@ func (k Keeper) GetUnbondingValidators(ctx sdk.Context, endTime time.Time, endHe // the unbonding validator queue by a given height and time. func (k Keeper) SetUnbondingValidatorsQueue(ctx sdk.Context, endTime time.Time, endHeight int64, addrs []string) { store := ctx.KVStore(k.storeKey) - bz := k.cdc.MustMarshalBinaryBare(&types.ValAddresses{Addresses: addrs}) + bz := k.cdc.MustMarshal(&types.ValAddresses{Addresses: addrs}) store.Set(types.GetValidatorQueueKey(endTime, endHeight), bz) } @@ -420,7 +419,7 @@ func (k Keeper) UnbondAllMatureValidators(ctx sdk.Context) { // and time. if keyHeight <= blockHeight && (keyTime.Before(blockTime) || keyTime.Equal(blockTime)) { addrs := types.ValAddresses{} - k.cdc.MustUnmarshalBinaryBare(unbondingValIterator.Value(), &addrs) + k.cdc.MustUnmarshal(unbondingValIterator.Value(), &addrs) for _, valAddr := range addrs.Addresses { addr := sdk.ValAddress(valAddr) diff --git a/x/staking/keeper/validator_test.go b/x/staking/keeper/validator_test.go index 0c640cb5ed..c36e7e1bdd 100644 --- a/x/staking/keeper/validator_test.go +++ b/x/staking/keeper/validator_test.go @@ -13,7 +13,6 @@ import ( cryptotypes "github.com/line/lbm-sdk/crypto/types" "github.com/line/lbm-sdk/simapp" sdk "github.com/line/lbm-sdk/types" - banktypes "github.com/line/lbm-sdk/x/bank/types" "github.com/line/lbm-sdk/x/staking/keeper" "github.com/line/lbm-sdk/x/staking/teststaking" "github.com/line/lbm-sdk/x/staking/types" @@ -30,15 +29,14 @@ func bootstrapValidatorTest(t testing.TB, power int64, numAddrs int) (*simapp.Si addrDels, addrVals := generateAddresses(app, ctx, numAddrs) - amt := sdk.TokensFromConsensusPower(power) + amt := app.StakingKeeper.TokensFromConsensusPower(ctx, power) totalSupply := sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), amt.MulRaw(int64(len(addrDels))))) notBondedPool := app.StakingKeeper.GetNotBondedPool(ctx) - err := app.BankKeeper.SetBalances(ctx, notBondedPool.GetAddress(), totalSupply) - require.NoError(t, err) - + // set bonded pool supply app.AccountKeeper.SetModuleAccount(ctx, notBondedPool) - app.BankKeeper.SetSupply(ctx, banktypes.NewSupply(totalSupply)) + + require.NoError(t, simapp.FundModuleAccount(app, ctx, notBondedPool.GetName(), totalSupply)) return app, ctx, addrDels, addrVals } @@ -50,7 +48,7 @@ func initValidators(t testing.TB, power int64, numAddrs int, powers []int64) (*s vs := make([]types.Validator, len(powers)) for i, power := range powers { vs[i] = teststaking.NewValidator(t, addrs[i].ToValAddress(), pks[i]) - tokens := sdk.TokensFromConsensusPower(power) + tokens := app.StakingKeeper.TokensFromConsensusPower(ctx, power) vs[i], _ = vs[i].AddTokensFromDel(tokens) } return app, ctx, addrs, valAddrs, vs @@ -61,7 +59,7 @@ func TestSetValidator(t *testing.T) { valPubKey := PKs[0] valAddr := sdk.BytesToValAddress(valPubKey.Address()) - valTokens := sdk.TokensFromConsensusPower(10) + valTokens := app.StakingKeeper.TokensFromConsensusPower(ctx, 10) // test how the validator is set from a purely unbonbed pool validator := teststaking.NewValidator(t, valAddr, valPubKey) @@ -76,7 +74,7 @@ func TestSetValidator(t *testing.T) { updates := applyValidatorSetUpdates(t, ctx, app.StakingKeeper, 1) validator, found := app.StakingKeeper.GetValidator(ctx, valAddr) require.True(t, found) - require.Equal(t, validator.ABCIValidatorUpdate(), updates[0]) + require.Equal(t, validator.ABCIValidatorUpdate(app.StakingKeeper.PowerReduction(ctx)), updates[0]) // after the save the validator should be bonded require.Equal(t, types.Bonded, validator.Status) @@ -115,39 +113,36 @@ func TestUpdateValidatorByPowerIndex(t *testing.T) { bondedPool := app.StakingKeeper.GetBondedPool(ctx) notBondedPool := app.StakingKeeper.GetNotBondedPool(ctx) - err := app.BankKeeper.SetBalances(ctx, bondedPool.GetAddress(), sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), sdk.TokensFromConsensusPower(1234)))) - require.NoError(t, err) - - err = app.BankKeeper.SetBalances(ctx, notBondedPool.GetAddress(), sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), sdk.TokensFromConsensusPower(10000)))) - require.NoError(t, err) + require.NoError(t, simapp.FundModuleAccount(app, ctx, bondedPool.GetName(), sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), app.StakingKeeper.TokensFromConsensusPower(ctx, 1234))))) + require.NoError(t, simapp.FundModuleAccount(app, ctx, notBondedPool.GetName(), sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), app.StakingKeeper.TokensFromConsensusPower(ctx, 10000))))) app.AccountKeeper.SetModuleAccount(ctx, bondedPool) app.AccountKeeper.SetModuleAccount(ctx, notBondedPool) // add a validator validator := teststaking.NewValidator(t, addrVals[0], PKs[0]) - validator, delSharesCreated := validator.AddTokensFromDel(sdk.TokensFromConsensusPower(100)) + validator, delSharesCreated := validator.AddTokensFromDel(app.StakingKeeper.TokensFromConsensusPower(ctx, 100)) require.Equal(t, types.Unbonded, validator.Status) - require.Equal(t, sdk.TokensFromConsensusPower(100), validator.Tokens) + require.Equal(t, app.StakingKeeper.TokensFromConsensusPower(ctx, 100), validator.Tokens) keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validator, true) validator, found := app.StakingKeeper.GetValidator(ctx, addrVals[0]) require.True(t, found) - require.Equal(t, sdk.TokensFromConsensusPower(100), validator.Tokens) + require.Equal(t, app.StakingKeeper.TokensFromConsensusPower(ctx, 100), validator.Tokens) - power := types.GetValidatorsByPowerIndexKey(validator) + power := types.GetValidatorsByPowerIndexKey(validator, app.StakingKeeper.PowerReduction(ctx)) require.True(t, keeper.ValidatorByPowerIndexExists(ctx, app.StakingKeeper, power)) // burn half the delegator shares app.StakingKeeper.DeleteValidatorByPowerIndex(ctx, validator) validator, burned := validator.RemoveDelShares(delSharesCreated.Quo(sdk.NewDec(2))) - require.Equal(t, sdk.TokensFromConsensusPower(50), burned) + require.Equal(t, app.StakingKeeper.TokensFromConsensusPower(ctx, 50), burned) keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validator, true) // update the validator, possibly kicking it out require.False(t, keeper.ValidatorByPowerIndexExists(ctx, app.StakingKeeper, power)) validator, found = app.StakingKeeper.GetValidator(ctx, addrVals[0]) require.True(t, found) - power = types.GetValidatorsByPowerIndexKey(validator) + power = types.GetValidatorsByPowerIndexKey(validator, app.StakingKeeper.PowerReduction(ctx)) require.True(t, keeper.ValidatorByPowerIndexExists(ctx, app.StakingKeeper, power)) } @@ -167,11 +162,8 @@ func TestUpdateBondedValidatorsDecreaseCliff(t *testing.T) { app.StakingKeeper.SetParams(ctx, params) // create a random pool - err := app.BankKeeper.SetBalances(ctx, bondedPool.GetAddress(), sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), sdk.TokensFromConsensusPower(1234)))) - require.NoError(t, err) - - err = app.BankKeeper.SetBalances(ctx, notBondedPool.GetAddress(), sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), sdk.TokensFromConsensusPower(10000)))) - require.NoError(t, err) + require.NoError(t, simapp.FundModuleAccount(app, ctx, bondedPool.GetName(), sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), app.StakingKeeper.TokensFromConsensusPower(ctx, 1234))))) + require.NoError(t, simapp.FundModuleAccount(app, ctx, notBondedPool.GetName(), sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), app.StakingKeeper.TokensFromConsensusPower(ctx, 10000))))) app.AccountKeeper.SetModuleAccount(ctx, bondedPool) app.AccountKeeper.SetModuleAccount(ctx, notBondedPool) @@ -180,7 +172,7 @@ func TestUpdateBondedValidatorsDecreaseCliff(t *testing.T) { for i := 0; i < len(validators); i++ { moniker := fmt.Sprintf("val#%d", int64(i)) val := newMonikerValidator(t, valAddrs[i], PKs[i], moniker) - delTokens := sdk.TokensFromConsensusPower(int64((i + 1) * 10)) + delTokens := app.StakingKeeper.TokensFromConsensusPower(ctx, int64((i+1)*10)) val, _ = val.AddTokensFromDel(delTokens) val = keeper.TestingUpdateValidator(app.StakingKeeper, ctx, val, true) @@ -192,7 +184,7 @@ func TestUpdateBondedValidatorsDecreaseCliff(t *testing.T) { // remove enough tokens to kick out the validator below the current cliff // validator and next in line cliff validator app.StakingKeeper.DeleteValidatorByPowerIndex(ctx, nextCliffVal) - shares := sdk.TokensFromConsensusPower(21) + shares := app.StakingKeeper.TokensFromConsensusPower(ctx, 21) nextCliffVal, _ = nextCliffVal.RemoveDelShares(shares.ToDec()) nextCliffVal = keeper.TestingUpdateValidator(app.StakingKeeper, ctx, nextCliffVal, true) @@ -221,12 +213,11 @@ func TestSlashToZeroPowerRemoved(t *testing.T) { // add a validator validator := teststaking.NewValidator(t, addrVals[0], PKs[0]) - valTokens := sdk.TokensFromConsensusPower(100) + valTokens := app.StakingKeeper.TokensFromConsensusPower(ctx, 100) bondedPool := app.StakingKeeper.GetBondedPool(ctx) - err := app.BankKeeper.SetBalances(ctx, bondedPool.GetAddress(), sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), valTokens))) - require.NoError(t, err) + require.NoError(t, simapp.FundModuleAccount(app, ctx, bondedPool.GetName(), sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), valTokens)))) app.AccountKeeper.SetModuleAccount(ctx, bondedPool) @@ -257,13 +248,13 @@ func TestValidatorBasics(t *testing.T) { validators[i] = teststaking.NewValidator(t, addrVals[i], PKs[i]) validators[i].Status = types.Unbonded validators[i].Tokens = sdk.ZeroInt() - tokens := sdk.TokensFromConsensusPower(power) + tokens := app.StakingKeeper.TokensFromConsensusPower(ctx, power) validators[i], _ = validators[i].AddTokensFromDel(tokens) } - assert.Equal(t, sdk.TokensFromConsensusPower(9), validators[0].Tokens) - assert.Equal(t, sdk.TokensFromConsensusPower(8), validators[1].Tokens) - assert.Equal(t, sdk.TokensFromConsensusPower(7), validators[2].Tokens) + assert.Equal(t, app.StakingKeeper.TokensFromConsensusPower(ctx, 9), validators[0].Tokens) + assert.Equal(t, app.StakingKeeper.TokensFromConsensusPower(ctx, 8), validators[1].Tokens) + assert.Equal(t, app.StakingKeeper.TokensFromConsensusPower(ctx, 7), validators[2].Tokens) // check the empty keeper first _, found := app.StakingKeeper.GetValidator(ctx, addrVals[0]) @@ -293,11 +284,11 @@ func TestValidatorBasics(t *testing.T) { require.Equal(t, 1, len(resVals)) assert.True(ValEq(t, validators[0], resVals[0])) assert.Equal(t, types.Bonded, validators[0].Status) - assert.True(sdk.IntEq(t, sdk.TokensFromConsensusPower(9), validators[0].BondedTokens())) + assert.True(sdk.IntEq(t, app.StakingKeeper.TokensFromConsensusPower(ctx, 9), validators[0].BondedTokens())) // modify a records, save, and retrieve validators[0].Status = types.Bonded - validators[0].Tokens = sdk.TokensFromConsensusPower(10) + validators[0].Tokens = app.StakingKeeper.TokensFromConsensusPower(ctx, 10) validators[0].DelegatorShares = validators[0].Tokens.ToDec() validators[0] = keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validators[0], true) resVal, found = app.StakingKeeper.GetValidator(ctx, addrVals[0]) @@ -352,10 +343,10 @@ func TestGetValidatorSortingUnmixed(t *testing.T) { // initialize some validators into the state amts := []sdk.Int{ sdk.NewIntFromUint64(0), - sdk.PowerReduction.MulRaw(100), - sdk.PowerReduction, - sdk.PowerReduction.MulRaw(400), - sdk.PowerReduction.MulRaw(200)} + app.StakingKeeper.PowerReduction(ctx).MulRaw(100), + app.StakingKeeper.PowerReduction(ctx), + app.StakingKeeper.PowerReduction(ctx).MulRaw(400), + app.StakingKeeper.PowerReduction(ctx).MulRaw(200)} n := len(amts) var validators [5]types.Validator for i, amt := range amts { @@ -369,10 +360,10 @@ func TestGetValidatorSortingUnmixed(t *testing.T) { // first make sure everything made it in to the gotValidator group resValidators := app.StakingKeeper.GetBondedValidatorsByPower(ctx) assert.Equal(t, n, len(resValidators)) - assert.Equal(t, sdk.NewInt(400).Mul(sdk.PowerReduction), resValidators[0].BondedTokens(), "%v", resValidators) - assert.Equal(t, sdk.NewInt(200).Mul(sdk.PowerReduction), resValidators[1].BondedTokens(), "%v", resValidators) - assert.Equal(t, sdk.NewInt(100).Mul(sdk.PowerReduction), resValidators[2].BondedTokens(), "%v", resValidators) - assert.Equal(t, sdk.NewInt(1).Mul(sdk.PowerReduction), resValidators[3].BondedTokens(), "%v", resValidators) + assert.Equal(t, sdk.NewInt(400).Mul(app.StakingKeeper.PowerReduction(ctx)), resValidators[0].BondedTokens(), "%v", resValidators) + assert.Equal(t, sdk.NewInt(200).Mul(app.StakingKeeper.PowerReduction(ctx)), resValidators[1].BondedTokens(), "%v", resValidators) + assert.Equal(t, sdk.NewInt(100).Mul(app.StakingKeeper.PowerReduction(ctx)), resValidators[2].BondedTokens(), "%v", resValidators) + assert.Equal(t, sdk.NewInt(1).Mul(app.StakingKeeper.PowerReduction(ctx)), resValidators[3].BondedTokens(), "%v", resValidators) assert.Equal(t, sdk.NewInt(0), resValidators[4].BondedTokens(), "%v", resValidators) assert.Equal(t, validators[3].OperatorAddress, resValidators[0].OperatorAddress, "%v", resValidators) assert.Equal(t, validators[4].OperatorAddress, resValidators[1].OperatorAddress, "%v", resValidators) @@ -381,14 +372,14 @@ func TestGetValidatorSortingUnmixed(t *testing.T) { assert.Equal(t, validators[0].OperatorAddress, resValidators[4].OperatorAddress, "%v", resValidators) // test a basic increase in voting power - validators[3].Tokens = sdk.NewInt(500).Mul(sdk.PowerReduction) + validators[3].Tokens = sdk.NewInt(500).Mul(app.StakingKeeper.PowerReduction(ctx)) keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validators[3], true) resValidators = app.StakingKeeper.GetBondedValidatorsByPower(ctx) require.Equal(t, len(resValidators), n) assert.True(ValEq(t, validators[3], resValidators[0])) // test a decrease in voting power - validators[3].Tokens = sdk.NewInt(300).Mul(sdk.PowerReduction) + validators[3].Tokens = sdk.NewInt(300).Mul(app.StakingKeeper.PowerReduction(ctx)) keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validators[3], true) resValidators = app.StakingKeeper.GetBondedValidatorsByPower(ctx) require.Equal(t, len(resValidators), n) @@ -396,7 +387,7 @@ func TestGetValidatorSortingUnmixed(t *testing.T) { assert.True(ValEq(t, validators[4], resValidators[1])) // test equal voting power, different age - validators[3].Tokens = sdk.NewInt(200).Mul(sdk.PowerReduction) + validators[3].Tokens = sdk.NewInt(200).Mul(app.StakingKeeper.PowerReduction(ctx)) ctx = ctx.WithBlockHeight(10) keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validators[3], true) resValidators = app.StakingKeeper.GetBondedValidatorsByPower(ctx) @@ -413,8 +404,8 @@ func TestGetValidatorSortingUnmixed(t *testing.T) { assert.True(ValEq(t, validators[4], resValidators[1])) // change in voting power of both validators, both still in v-set, no age change - validators[3].Tokens = sdk.NewInt(300).Mul(sdk.PowerReduction) - validators[4].Tokens = sdk.NewInt(300).Mul(sdk.PowerReduction) + validators[3].Tokens = sdk.NewInt(300).Mul(app.StakingKeeper.PowerReduction(ctx)) + validators[4].Tokens = sdk.NewInt(300).Mul(app.StakingKeeper.PowerReduction(ctx)) keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validators[3], true) resValidators = app.StakingKeeper.GetBondedValidatorsByPower(ctx) require.Equal(t, len(resValidators), n) @@ -431,11 +422,8 @@ func TestGetValidatorSortingMixed(t *testing.T) { bondedPool := app.StakingKeeper.GetBondedPool(ctx) notBondedPool := app.StakingKeeper.GetNotBondedPool(ctx) - err := app.BankKeeper.SetBalances(ctx, bondedPool.GetAddress(), sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), sdk.TokensFromConsensusPower(501)))) - require.NoError(t, err) - - err = app.BankKeeper.SetBalances(ctx, notBondedPool.GetAddress(), sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), sdk.TokensFromConsensusPower(0)))) - require.NoError(t, err) + require.NoError(t, simapp.FundModuleAccount(app, ctx, bondedPool.GetName(), sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), app.StakingKeeper.TokensFromConsensusPower(ctx, 501))))) + require.NoError(t, simapp.FundModuleAccount(app, ctx, notBondedPool.GetName(), sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), app.StakingKeeper.TokensFromConsensusPower(ctx, 0))))) app.AccountKeeper.SetModuleAccount(ctx, notBondedPool) app.AccountKeeper.SetModuleAccount(ctx, bondedPool) @@ -448,10 +436,10 @@ func TestGetValidatorSortingMixed(t *testing.T) { // initialize some validators into the state amts := []sdk.Int{ sdk.NewIntFromUint64(0), - sdk.PowerReduction.MulRaw(100), - sdk.PowerReduction, - sdk.PowerReduction.MulRaw(400), - sdk.PowerReduction.MulRaw(200)} + app.StakingKeeper.PowerReduction(ctx).MulRaw(100), + app.StakingKeeper.PowerReduction(ctx), + app.StakingKeeper.PowerReduction(ctx).MulRaw(400), + app.StakingKeeper.PowerReduction(ctx).MulRaw(200)} var validators [5]types.Validator for i, amt := range amts { @@ -482,8 +470,8 @@ func TestGetValidatorSortingMixed(t *testing.T) { resValidators := app.StakingKeeper.GetBondedValidatorsByPower(ctx) // The validators returned should match the max validators assert.Equal(t, 2, len(resValidators)) - assert.Equal(t, sdk.NewInt(400).Mul(sdk.PowerReduction), resValidators[0].BondedTokens(), "%v", resValidators) - assert.Equal(t, sdk.NewInt(200).Mul(sdk.PowerReduction), resValidators[1].BondedTokens(), "%v", resValidators) + assert.Equal(t, sdk.NewInt(400).Mul(app.StakingKeeper.PowerReduction(ctx)), resValidators[0].BondedTokens(), "%v", resValidators) + assert.Equal(t, sdk.NewInt(200).Mul(app.StakingKeeper.PowerReduction(ctx)), resValidators[1].BondedTokens(), "%v", resValidators) assert.Equal(t, validators[3].OperatorAddress, resValidators[0].OperatorAddress, "%v", resValidators) assert.Equal(t, validators[4].OperatorAddress, resValidators[1].OperatorAddress, "%v", resValidators) } @@ -505,13 +493,11 @@ func TestGetValidatorsEdgeCases(t *testing.T) { moniker := fmt.Sprintf("val#%d", int64(i)) validators[i] = newMonikerValidator(t, addrs[i].ToValAddress(), PKs[i], moniker) - tokens := sdk.TokensFromConsensusPower(power) + tokens := app.StakingKeeper.TokensFromConsensusPower(ctx, power) validators[i], _ = validators[i].AddTokensFromDel(tokens) notBondedPool := app.StakingKeeper.GetNotBondedPool(ctx) - balances := app.BankKeeper.GetAllBalances(ctx, notBondedPool.GetAddress()) - require.NoError(t, app.BankKeeper.SetBalances(ctx, notBondedPool.GetAddress(), balances.Add(sdk.NewCoin(params.BondDenom, tokens)))) - + require.NoError(t, simapp.FundModuleAccount(app, ctx, notBondedPool.GetName(), sdk.NewCoins(sdk.NewCoin(params.BondDenom, tokens)))) app.AccountKeeper.SetModuleAccount(ctx, notBondedPool) validators[i] = keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validators[i], true) } @@ -524,14 +510,13 @@ func TestGetValidatorsEdgeCases(t *testing.T) { // delegate 500 tokens to validator 0 app.StakingKeeper.DeleteValidatorByPowerIndex(ctx, validators[0]) - delTokens := sdk.TokensFromConsensusPower(500) + delTokens := app.StakingKeeper.TokensFromConsensusPower(ctx, 500) validators[0], _ = validators[0].AddTokensFromDel(delTokens) notBondedPool := app.StakingKeeper.GetNotBondedPool(ctx) newTokens := sdk.NewCoins() - balances := app.BankKeeper.GetAllBalances(ctx, notBondedPool.GetAddress()) - require.NoError(t, app.BankKeeper.SetBalances(ctx, notBondedPool.GetAddress(), balances.Add(newTokens...))) + require.NoError(t, simapp.FundModuleAccount(app, ctx, notBondedPool.GetName(), newTokens)) app.AccountKeeper.SetModuleAccount(ctx, notBondedPool) // test that the two largest validators are @@ -559,12 +544,11 @@ func TestGetValidatorsEdgeCases(t *testing.T) { validators[3], found = app.StakingKeeper.GetValidator(ctx, validators[3].GetOperator()) assert.True(t, found) app.StakingKeeper.DeleteValidatorByPowerIndex(ctx, validators[3]) - validators[3], _ = validators[3].AddTokensFromDel(sdk.TokensFromConsensusPower(1)) + validators[3], _ = validators[3].AddTokensFromDel(app.StakingKeeper.TokensFromConsensusPower(ctx, 1)) notBondedPool = app.StakingKeeper.GetNotBondedPool(ctx) - newTokens = sdk.NewCoins(sdk.NewCoin(params.BondDenom, sdk.TokensFromConsensusPower(1))) - balances = app.BankKeeper.GetAllBalances(ctx, notBondedPool.GetAddress()) - require.NoError(t, app.BankKeeper.SetBalances(ctx, notBondedPool.GetAddress(), balances.Add(newTokens...))) + newTokens = sdk.NewCoins(sdk.NewCoin(params.BondDenom, app.StakingKeeper.TokensFromConsensusPower(ctx, 1))) + require.NoError(t, simapp.FundModuleAccount(app, ctx, notBondedPool.GetName(), newTokens)) app.AccountKeeper.SetModuleAccount(ctx, notBondedPool) validators[3] = keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validators[3], true) @@ -579,8 +563,7 @@ func TestGetValidatorsEdgeCases(t *testing.T) { validators[3], _ = validators[3].RemoveDelShares(sdk.NewDec(201)) bondedPool := app.StakingKeeper.GetBondedPool(ctx) - balances = app.BankKeeper.GetAllBalances(ctx, bondedPool.GetAddress()) - require.NoError(t, app.BankKeeper.SetBalances(ctx, bondedPool.GetAddress(), balances.Add(sdk.NewCoin(params.BondDenom, rmTokens)))) + require.NoError(t, simapp.FundModuleAccount(app, ctx, bondedPool.GetName(), sdk.NewCoins(sdk.NewCoin(params.BondDenom, rmTokens)))) app.AccountKeeper.SetModuleAccount(ctx, bondedPool) validators[3] = keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validators[3], true) @@ -594,8 +577,7 @@ func TestGetValidatorsEdgeCases(t *testing.T) { validators[3], _ = validators[3].AddTokensFromDel(sdk.NewInt(200)) notBondedPool = app.StakingKeeper.GetNotBondedPool(ctx) - balances = app.BankKeeper.GetAllBalances(ctx, notBondedPool.GetAddress()) - require.NoError(t, app.BankKeeper.SetBalances(ctx, notBondedPool.GetAddress(), balances.Add(sdk.NewCoin(params.BondDenom, sdk.NewInt(200))))) + require.NoError(t, simapp.FundModuleAccount(app, ctx, notBondedPool.GetName(), sdk.NewCoins(sdk.NewCoin(params.BondDenom, sdk.NewInt(200))))) app.AccountKeeper.SetModuleAccount(ctx, notBondedPool) validators[3] = keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validators[3], true) @@ -621,9 +603,9 @@ func TestValidatorBondHeight(t *testing.T) { validators[1] = teststaking.NewValidator(t, addrs[1].ToValAddress(), PKs[1]) validators[2] = teststaking.NewValidator(t, addrs[2].ToValAddress(), PKs[2]) - tokens0 := sdk.TokensFromConsensusPower(200) - tokens1 := sdk.TokensFromConsensusPower(100) - tokens2 := sdk.TokensFromConsensusPower(100) + tokens0 := app.StakingKeeper.TokensFromConsensusPower(ctx, 200) + tokens1 := app.StakingKeeper.TokensFromConsensusPower(ctx, 100) + tokens2 := app.StakingKeeper.TokensFromConsensusPower(ctx, 100) validators[0], _ = validators[0].AddTokensFromDel(tokens0) validators[1], _ = validators[1].AddTokensFromDel(tokens1) validators[2], _ = validators[2].AddTokensFromDel(tokens2) @@ -643,7 +625,7 @@ func TestValidatorBondHeight(t *testing.T) { assert.True(ValEq(t, validators[1], resValidators[1])) app.StakingKeeper.DeleteValidatorByPowerIndex(ctx, validators[1]) app.StakingKeeper.DeleteValidatorByPowerIndex(ctx, validators[2]) - delTokens := sdk.TokensFromConsensusPower(50) + delTokens := app.StakingKeeper.TokensFromConsensusPower(ctx, 50) validators[1], _ = validators[1].AddTokensFromDel(delTokens) validators[2], _ = validators[2].AddTokensFromDel(delTokens) validators[2] = keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validators[2], true) @@ -666,7 +648,7 @@ func TestFullValidatorSetPowerChange(t *testing.T) { var validators [5]types.Validator for i, power := range powers { validators[i] = teststaking.NewValidator(t, addrs[i].ToValAddress(), PKs[i]) - tokens := sdk.TokensFromConsensusPower(power) + tokens := app.StakingKeeper.TokensFromConsensusPower(ctx, power) validators[i], _ = validators[i].AddTokensFromDel(tokens) keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validators[i], true) } @@ -687,7 +669,7 @@ func TestFullValidatorSetPowerChange(t *testing.T) { // test a swap in voting power - tokens := sdk.TokensFromConsensusPower(600) + tokens := app.StakingKeeper.TokensFromConsensusPower(ctx, 600) validators[0], _ = validators[0].AddTokensFromDel(tokens) validators[0] = keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validators[0], true) resValidators = app.StakingKeeper.GetBondedValidatorsByPower(ctx) @@ -706,7 +688,7 @@ func TestApplyAndReturnValidatorSetUpdatesAllNone(t *testing.T) { valAddr := sdk.BytesToValAddress(valPubKey.Address()) validators[i] = teststaking.NewValidator(t, valAddr, valPubKey) - tokens := sdk.TokensFromConsensusPower(power) + tokens := app.StakingKeeper.TokensFromConsensusPower(ctx, power) validators[i], _ = validators[i].AddTokensFromDel(tokens) } @@ -721,8 +703,8 @@ func TestApplyAndReturnValidatorSetUpdatesAllNone(t *testing.T) { updates := applyValidatorSetUpdates(t, ctx, app.StakingKeeper, 2) validators[0], _ = app.StakingKeeper.GetValidator(ctx, validators[0].GetOperator()) validators[1], _ = app.StakingKeeper.GetValidator(ctx, validators[1].GetOperator()) - assert.Equal(t, validators[0].ABCIValidatorUpdate(), updates[1]) - assert.Equal(t, validators[1].ABCIValidatorUpdate(), updates[0]) + assert.Equal(t, validators[0].ABCIValidatorUpdate(app.StakingKeeper.PowerReduction(ctx)), updates[1]) + assert.Equal(t, validators[1].ABCIValidatorUpdate(app.StakingKeeper.PowerReduction(ctx)), updates[0]) } func TestApplyAndReturnValidatorSetUpdatesIdentical(t *testing.T) { @@ -733,7 +715,7 @@ func TestApplyAndReturnValidatorSetUpdatesIdentical(t *testing.T) { for i, power := range powers { validators[i] = teststaking.NewValidator(t, addrs[i].ToValAddress(), PKs[i]) - tokens := sdk.TokensFromConsensusPower(power) + tokens := app.StakingKeeper.TokensFromConsensusPower(ctx, power) validators[i], _ = validators[i].AddTokensFromDel(tokens) } @@ -756,7 +738,7 @@ func TestApplyAndReturnValidatorSetUpdatesSingleValueChange(t *testing.T) { for i, power := range powers { validators[i] = teststaking.NewValidator(t, addrs[i].ToValAddress(), PKs[i]) - tokens := sdk.TokensFromConsensusPower(power) + tokens := app.StakingKeeper.TokensFromConsensusPower(ctx, power) validators[i], _ = validators[i].AddTokensFromDel(tokens) } @@ -767,11 +749,11 @@ func TestApplyAndReturnValidatorSetUpdatesSingleValueChange(t *testing.T) { // test single value change // tendermintUpdate set: {} -> {c1'} validators[0].Status = types.Bonded - validators[0].Tokens = sdk.TokensFromConsensusPower(600) + validators[0].Tokens = app.StakingKeeper.TokensFromConsensusPower(ctx, 600) validators[0] = keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validators[0], false) updates := applyValidatorSetUpdates(t, ctx, app.StakingKeeper, 1) - require.Equal(t, validators[0].ABCIValidatorUpdate(), updates[0]) + require.Equal(t, validators[0].ABCIValidatorUpdate(app.StakingKeeper.PowerReduction(ctx)), updates[0]) } func TestApplyAndReturnValidatorSetUpdatesMultipleValueChange(t *testing.T) { @@ -785,16 +767,16 @@ func TestApplyAndReturnValidatorSetUpdatesMultipleValueChange(t *testing.T) { // test multiple value change // tendermintUpdate set: {c1, c3} -> {c1', c3'} - delTokens1 := sdk.TokensFromConsensusPower(190) - delTokens2 := sdk.TokensFromConsensusPower(80) + delTokens1 := app.StakingKeeper.TokensFromConsensusPower(ctx, 190) + delTokens2 := app.StakingKeeper.TokensFromConsensusPower(ctx, 80) validators[0], _ = validators[0].AddTokensFromDel(delTokens1) validators[1], _ = validators[1].AddTokensFromDel(delTokens2) validators[0] = keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validators[0], false) validators[1] = keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validators[1], false) updates := applyValidatorSetUpdates(t, ctx, app.StakingKeeper, 2) - require.Equal(t, validators[0].ABCIValidatorUpdate(), updates[0]) - require.Equal(t, validators[1].ABCIValidatorUpdate(), updates[1]) + require.Equal(t, validators[0].ABCIValidatorUpdate(app.StakingKeeper.PowerReduction(ctx)), updates[0]) + require.Equal(t, validators[1].ABCIValidatorUpdate(app.StakingKeeper.PowerReduction(ctx)), updates[1]) } func TestApplyAndReturnValidatorSetUpdatesInserted(t *testing.T) { @@ -811,7 +793,7 @@ func TestApplyAndReturnValidatorSetUpdatesInserted(t *testing.T) { app.StakingKeeper.SetValidatorByPowerIndex(ctx, validators[2]) updates := applyValidatorSetUpdates(t, ctx, app.StakingKeeper, 1) validators[2], _ = app.StakingKeeper.GetValidator(ctx, validators[2].GetOperator()) - require.Equal(t, validators[2].ABCIValidatorUpdate(), updates[0]) + require.Equal(t, validators[2].ABCIValidatorUpdate(app.StakingKeeper.PowerReduction(ctx)), updates[0]) // test validtor added at the beginning // tendermintUpdate set: {} -> {c0} @@ -819,7 +801,7 @@ func TestApplyAndReturnValidatorSetUpdatesInserted(t *testing.T) { app.StakingKeeper.SetValidatorByPowerIndex(ctx, validators[3]) updates = applyValidatorSetUpdates(t, ctx, app.StakingKeeper, 1) validators[3], _ = app.StakingKeeper.GetValidator(ctx, validators[3].GetOperator()) - require.Equal(t, validators[3].ABCIValidatorUpdate(), updates[0]) + require.Equal(t, validators[3].ABCIValidatorUpdate(app.StakingKeeper.PowerReduction(ctx)), updates[0]) // test validtor added at the end // tendermintUpdate set: {} -> {c0} @@ -827,7 +809,7 @@ func TestApplyAndReturnValidatorSetUpdatesInserted(t *testing.T) { app.StakingKeeper.SetValidatorByPowerIndex(ctx, validators[4]) updates = applyValidatorSetUpdates(t, ctx, app.StakingKeeper, 1) validators[4], _ = app.StakingKeeper.GetValidator(ctx, validators[4].GetOperator()) - require.Equal(t, validators[4].ABCIValidatorUpdate(), updates[0]) + require.Equal(t, validators[4].ABCIValidatorUpdate(app.StakingKeeper.PowerReduction(ctx)), updates[0]) } func TestApplyAndReturnValidatorSetUpdatesWithCliffValidator(t *testing.T) { @@ -840,7 +822,7 @@ func TestApplyAndReturnValidatorSetUpdatesWithCliffValidator(t *testing.T) { var validators [5]types.Validator for i, power := range powers { validators[i] = teststaking.NewValidator(t, addrs[i].ToValAddress(), PKs[i]) - tokens := sdk.TokensFromConsensusPower(power) + tokens := app.StakingKeeper.TokensFromConsensusPower(ctx, power) validators[i], _ = validators[i].AddTokensFromDel(tokens) } validators[0] = keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validators[0], false) @@ -856,14 +838,14 @@ func TestApplyAndReturnValidatorSetUpdatesWithCliffValidator(t *testing.T) { // tendermintUpdate set: {} -> {c0, c4} applyValidatorSetUpdates(t, ctx, app.StakingKeeper, 0) - tokens := sdk.TokensFromConsensusPower(10) + tokens := app.StakingKeeper.TokensFromConsensusPower(ctx, 10) validators[2], _ = validators[2].AddTokensFromDel(tokens) app.StakingKeeper.SetValidator(ctx, validators[2]) app.StakingKeeper.SetValidatorByPowerIndex(ctx, validators[2]) updates := applyValidatorSetUpdates(t, ctx, app.StakingKeeper, 2) validators[2], _ = app.StakingKeeper.GetValidator(ctx, validators[2].GetOperator()) require.Equal(t, validators[0].ABCIValidatorUpdateZero(), updates[1]) - require.Equal(t, validators[2].ABCIValidatorUpdate(), updates[0]) + require.Equal(t, validators[2].ABCIValidatorUpdate(app.StakingKeeper.PowerReduction(ctx)), updates[0]) } func TestApplyAndReturnValidatorSetUpdatesPowerDecrease(t *testing.T) { @@ -873,7 +855,7 @@ func TestApplyAndReturnValidatorSetUpdatesPowerDecrease(t *testing.T) { var validators [2]types.Validator for i, power := range powers { validators[i] = teststaking.NewValidator(t, addrs[i].ToValAddress(), PKs[i]) - tokens := sdk.TokensFromConsensusPower(power) + tokens := app.StakingKeeper.TokensFromConsensusPower(ctx, power) validators[i], _ = validators[i].AddTokensFromDel(tokens) } validators[0] = keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validators[0], false) @@ -881,26 +863,26 @@ func TestApplyAndReturnValidatorSetUpdatesPowerDecrease(t *testing.T) { applyValidatorSetUpdates(t, ctx, app.StakingKeeper, 2) // check initial power - require.Equal(t, int64(100), validators[0].GetConsensusPower()) - require.Equal(t, int64(100), validators[1].GetConsensusPower()) + require.Equal(t, int64(100), validators[0].GetConsensusPower(app.StakingKeeper.PowerReduction(ctx))) + require.Equal(t, int64(100), validators[1].GetConsensusPower(app.StakingKeeper.PowerReduction(ctx))) // test multiple value change // tendermintUpdate set: {c1, c3} -> {c1', c3'} - delTokens1 := sdk.TokensFromConsensusPower(20) - delTokens2 := sdk.TokensFromConsensusPower(30) + delTokens1 := app.StakingKeeper.TokensFromConsensusPower(ctx, 20) + delTokens2 := app.StakingKeeper.TokensFromConsensusPower(ctx, 30) validators[0], _ = validators[0].RemoveDelShares(delTokens1.ToDec()) validators[1], _ = validators[1].RemoveDelShares(delTokens2.ToDec()) validators[0] = keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validators[0], false) validators[1] = keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validators[1], false) // power has changed - require.Equal(t, int64(80), validators[0].GetConsensusPower()) - require.Equal(t, int64(70), validators[1].GetConsensusPower()) + require.Equal(t, int64(80), validators[0].GetConsensusPower(app.StakingKeeper.PowerReduction(ctx))) + require.Equal(t, int64(70), validators[1].GetConsensusPower(app.StakingKeeper.PowerReduction(ctx))) // Tendermint updates should reflect power change updates := applyValidatorSetUpdates(t, ctx, app.StakingKeeper, 2) - require.Equal(t, validators[0].ABCIValidatorUpdate(), updates[0]) - require.Equal(t, validators[1].ABCIValidatorUpdate(), updates[1]) + require.Equal(t, validators[0].ABCIValidatorUpdate(app.StakingKeeper.PowerReduction(ctx)), updates[0]) + require.Equal(t, validators[1].ABCIValidatorUpdate(app.StakingKeeper.PowerReduction(ctx)), updates[1]) } func TestApplyAndReturnValidatorSetUpdatesNewValidator(t *testing.T) { @@ -919,7 +901,7 @@ func TestApplyAndReturnValidatorSetUpdatesNewValidator(t *testing.T) { valAddr := sdk.BytesToValAddress(valPubKey.Address()) validators[i] = teststaking.NewValidator(t, valAddr, valPubKey) - tokens := sdk.TokensFromConsensusPower(power) + tokens := app.StakingKeeper.TokensFromConsensusPower(ctx, power) validators[i], _ = validators[i].AddTokensFromDel(tokens) app.StakingKeeper.SetValidator(ctx, validators[i]) @@ -930,8 +912,8 @@ func TestApplyAndReturnValidatorSetUpdatesNewValidator(t *testing.T) { updates := applyValidatorSetUpdates(t, ctx, app.StakingKeeper, len(validators)) validators[0], _ = app.StakingKeeper.GetValidator(ctx, validators[0].GetOperator()) validators[1], _ = app.StakingKeeper.GetValidator(ctx, validators[1].GetOperator()) - require.Equal(t, validators[0].ABCIValidatorUpdate(), updates[0]) - require.Equal(t, validators[1].ABCIValidatorUpdate(), updates[1]) + require.Equal(t, validators[0].ABCIValidatorUpdate(app.StakingKeeper.PowerReduction(ctx)), updates[0]) + require.Equal(t, validators[1].ABCIValidatorUpdate(app.StakingKeeper.PowerReduction(ctx)), updates[1]) applyValidatorSetUpdates(t, ctx, app.StakingKeeper, 0) @@ -939,7 +921,7 @@ func TestApplyAndReturnValidatorSetUpdatesNewValidator(t *testing.T) { for i, power := range powers { app.StakingKeeper.DeleteValidatorByPowerIndex(ctx, validators[i]) - tokens := sdk.TokensFromConsensusPower(power) + tokens := app.StakingKeeper.TokensFromConsensusPower(ctx, power) validators[i], _ = validators[i].AddTokensFromDel(tokens) app.StakingKeeper.SetValidator(ctx, validators[i]) @@ -966,7 +948,7 @@ func TestApplyAndReturnValidatorSetUpdatesNewValidator(t *testing.T) { valAddr = sdk.BytesToValAddress(valPubKey.Address()) validator = teststaking.NewValidator(t, valAddr, valPubKey) - tokens := sdk.TokensFromConsensusPower(500) + tokens := app.StakingKeeper.TokensFromConsensusPower(ctx, 500) validator, _ = validator.AddTokensFromDel(tokens) app.StakingKeeper.SetValidator(ctx, validator) app.StakingKeeper.SetValidatorByPowerIndex(ctx, validator) @@ -976,9 +958,9 @@ func TestApplyAndReturnValidatorSetUpdatesNewValidator(t *testing.T) { validator, _ = app.StakingKeeper.GetValidator(ctx, validator.GetOperator()) validators[0], _ = app.StakingKeeper.GetValidator(ctx, validators[0].GetOperator()) validators[1], _ = app.StakingKeeper.GetValidator(ctx, validators[1].GetOperator()) - require.Equal(t, validator.ABCIValidatorUpdate(), updates[0]) - require.Equal(t, validators[0].ABCIValidatorUpdate(), updates[1]) - require.Equal(t, validators[1].ABCIValidatorUpdate(), updates[2]) + require.Equal(t, validator.ABCIValidatorUpdate(app.StakingKeeper.PowerReduction(ctx)), updates[0]) + require.Equal(t, validators[0].ABCIValidatorUpdate(app.StakingKeeper.PowerReduction(ctx)), updates[1]) + require.Equal(t, validators[1].ABCIValidatorUpdate(app.StakingKeeper.PowerReduction(ctx)), updates[2]) } func TestApplyAndReturnValidatorSetUpdatesBondTransition(t *testing.T) { @@ -998,7 +980,7 @@ func TestApplyAndReturnValidatorSetUpdatesBondTransition(t *testing.T) { valAddr := sdk.BytesToValAddress(valPubKey.Address()) validators[i] = newMonikerValidator(t, valAddr, valPubKey, moniker) - tokens := sdk.TokensFromConsensusPower(power) + tokens := app.StakingKeeper.TokensFromConsensusPower(ctx, power) validators[i], _ = validators[i].AddTokensFromDel(tokens) app.StakingKeeper.SetValidator(ctx, validators[i]) app.StakingKeeper.SetValidatorByPowerIndex(ctx, validators[i]) @@ -1008,8 +990,8 @@ func TestApplyAndReturnValidatorSetUpdatesBondTransition(t *testing.T) { updates := applyValidatorSetUpdates(t, ctx, app.StakingKeeper, 2) validators[2], _ = app.StakingKeeper.GetValidator(ctx, validators[2].GetOperator()) validators[1], _ = app.StakingKeeper.GetValidator(ctx, validators[1].GetOperator()) - require.Equal(t, validators[2].ABCIValidatorUpdate(), updates[0]) - require.Equal(t, validators[1].ABCIValidatorUpdate(), updates[1]) + require.Equal(t, validators[2].ABCIValidatorUpdate(app.StakingKeeper.PowerReduction(ctx)), updates[0]) + require.Equal(t, validators[1].ABCIValidatorUpdate(app.StakingKeeper.PowerReduction(ctx)), updates[1]) applyValidatorSetUpdates(t, ctx, app.StakingKeeper, 0) @@ -1021,7 +1003,7 @@ func TestApplyAndReturnValidatorSetUpdatesBondTransition(t *testing.T) { require.True(t, found) app.StakingKeeper.DeleteValidatorByPowerIndex(ctx, validators[0]) - tokens := sdk.TokensFromConsensusPower(1) + tokens := app.StakingKeeper.TokensFromConsensusPower(ctx, 1) validators[0], _ = validators[0].AddTokensFromDel(tokens) app.StakingKeeper.SetValidator(ctx, validators[0]) app.StakingKeeper.SetValidatorByPowerIndex(ctx, validators[0]) @@ -1043,14 +1025,14 @@ func TestApplyAndReturnValidatorSetUpdatesBondTransition(t *testing.T) { applyValidatorSetUpdates(t, ctx, app.StakingKeeper, 0) app.StakingKeeper.DeleteValidatorByPowerIndex(ctx, validators[1]) - tokens = sdk.TokensFromConsensusPower(250) + tokens = app.StakingKeeper.TokensFromConsensusPower(ctx, 250) validators[1], _ = validators[1].AddTokensFromDel(tokens) app.StakingKeeper.SetValidator(ctx, validators[1]) app.StakingKeeper.SetValidatorByPowerIndex(ctx, validators[1]) // verify initial Tendermint updates are correct updates = applyValidatorSetUpdates(t, ctx, app.StakingKeeper, 1) - require.Equal(t, validators[1].ABCIValidatorUpdate(), updates[0]) + require.Equal(t, validators[1].ABCIValidatorUpdate(app.StakingKeeper.PowerReduction(ctx)), updates[0]) applyValidatorSetUpdates(t, ctx, app.StakingKeeper, 0) } diff --git a/x/staking/legacy/v040/keys.go b/x/staking/legacy/v040/keys.go new file mode 100644 index 0000000000..ce2a96f512 --- /dev/null +++ b/x/staking/legacy/v040/keys.go @@ -0,0 +1,331 @@ +// Package v040 is copy-pasted from: +// https://github.com/cosmos/cosmos-sdk/blob/v0.41.0/x/staking/types/keys.go +package v040 + +import ( + "bytes" + "encoding/binary" + "fmt" + "strconv" + "time" + + sdk "github.com/line/lbm-sdk/types" + v040auth "github.com/line/lbm-sdk/x/auth/legacy/v040" + "github.com/line/lbm-sdk/x/staking/types" +) + +const ( + // ModuleName is the name of the staking module + ModuleName = "staking" + + // StoreKey is the string store representation + StoreKey = ModuleName + + // QuerierRoute is the querier route for the staking module + QuerierRoute = ModuleName + + // RouterKey is the msg router key for the staking module + RouterKey = ModuleName +) + +var ( + // Keys for store prefixes + // Last* values are constant during a block. + LastValidatorPowerKey = []byte{0x11} // prefix for each key to a validator index, for bonded validators + LastTotalPowerKey = []byte{0x12} // prefix for the total power + + ValidatorsKey = []byte{0x21} // prefix for each key to a validator + ValidatorsByConsAddrKey = []byte{0x22} // prefix for each key to a validator index, by pubkey + ValidatorsByPowerIndexKey = []byte{0x23} // prefix for each key to a validator index, sorted by power + + DelegationKey = []byte{0x31} // key for a delegation + UnbondingDelegationKey = []byte{0x32} // key for an unbonding-delegation + UnbondingDelegationByValIndexKey = []byte{0x33} // prefix for each key for an unbonding-delegation, by validator operator + RedelegationKey = []byte{0x34} // key for a redelegation + RedelegationByValSrcIndexKey = []byte{0x35} // prefix for each key for an redelegation, by source validator operator + RedelegationByValDstIndexKey = []byte{0x36} // prefix for each key for an redelegation, by destination validator operator + + UnbondingQueueKey = []byte{0x41} // prefix for the timestamps in unbonding queue + RedelegationQueueKey = []byte{0x42} // prefix for the timestamps in redelegations queue + ValidatorQueueKey = []byte{0x43} // prefix for the timestamps in validator queue + + HistoricalInfoKey = []byte{0x50} // prefix for the historical info +) + +// gets the key for the validator with address +// VALUE: staking/Validator +func GetValidatorKey(operatorAddr sdk.ValAddress) []byte { + return append(ValidatorsKey, operatorAddr.Bytes()...) +} + +// gets the key for the validator with pubkey +// VALUE: validator operator address ([]byte) +func GetValidatorByConsAddrKey(addr sdk.ConsAddress) []byte { + return append(ValidatorsByConsAddrKey, addr.Bytes()...) +} + +// Get the validator operator address from LastValidatorPowerKey +func AddressFromLastValidatorPowerKey(key []byte) []byte { + return key[1:] // remove prefix bytes +} + +// get the validator by power index. +// Power index is the key used in the power-store, and represents the relative +// power ranking of the validator. +// VALUE: validator operator address ([]byte) +func GetValidatorsByPowerIndexKey(validator types.Validator) []byte { + // NOTE the address doesn't need to be stored because counter bytes must always be different + // NOTE the larger values are of higher value + + consensusPower := sdk.TokensToConsensusPower(validator.Tokens, sdk.DefaultPowerReduction) + consensusPowerBytes := make([]byte, 8) + binary.BigEndian.PutUint64(consensusPowerBytes, uint64(consensusPower)) + + powerBytes := consensusPowerBytes + powerBytesLen := len(powerBytes) // 8 + + // key is of format prefix || powerbytes || addrBytes + key := make([]byte, 1+powerBytesLen+v040auth.ValAddrLen) + + key[0] = ValidatorsByPowerIndexKey[0] + copy(key[1:powerBytesLen+1], powerBytes) + err := sdk.ValidateValAddress(validator.OperatorAddress) + if err != nil { + panic(err) + } + addr := sdk.ValAddress(validator.OperatorAddress) + operAddrInvr := sdk.CopyBytes(addr.Bytes()) + + for i, b := range operAddrInvr { + operAddrInvr[i] = ^b + } + + copy(key[powerBytesLen+1:], operAddrInvr) + + return key +} + +// get the bonded validator index key for an operator address +func GetLastValidatorPowerKey(operator sdk.ValAddress) []byte { + return append(LastValidatorPowerKey, operator...) +} + +// parse the validators operator address from power rank key +func ParseValidatorPowerRankKey(key []byte) (operAddr []byte) { + powerBytesLen := 8 + if len(key) != 1+powerBytesLen+v040auth.AddrLen { + panic("Invalid validator power rank key length") + } + + operAddr = sdk.CopyBytes(key[powerBytesLen+1:]) + + for i, b := range operAddr { + operAddr[i] = ^b + } + + return operAddr +} + +// GetValidatorQueueKey returns the prefix key used for getting a set of unbonding +// validators whose unbonding completion occurs at the given time and height. +func GetValidatorQueueKey(timestamp time.Time, height int64) []byte { + heightBz := sdk.Uint64ToBigEndian(uint64(height)) + timeBz := sdk.FormatTimeBytes(timestamp) + timeBzL := len(timeBz) + prefixL := len(ValidatorQueueKey) + + bz := make([]byte, prefixL+8+timeBzL+8) + + // copy the prefix + copy(bz[:prefixL], ValidatorQueueKey) + + // copy the encoded time bytes length + copy(bz[prefixL:prefixL+8], sdk.Uint64ToBigEndian(uint64(timeBzL))) + + // copy the encoded time bytes + copy(bz[prefixL+8:prefixL+8+timeBzL], timeBz) + + // copy the encoded height + copy(bz[prefixL+8+timeBzL:], heightBz) + + return bz +} + +// ParseValidatorQueueKey returns the encoded time and height from a key created +// from GetValidatorQueueKey. +func ParseValidatorQueueKey(bz []byte) (time.Time, int64, error) { + prefixL := len(ValidatorQueueKey) + if prefix := bz[:prefixL]; !bytes.Equal(prefix, ValidatorQueueKey) { + return time.Time{}, 0, fmt.Errorf("invalid prefix; expected: %X, got: %X", ValidatorQueueKey, prefix) + } + + timeBzL := sdk.BigEndianToUint64(bz[prefixL : prefixL+8]) + ts, err := sdk.ParseTimeBytes(bz[prefixL+8 : prefixL+8+int(timeBzL)]) + if err != nil { + return time.Time{}, 0, err + } + + height := sdk.BigEndianToUint64(bz[prefixL+8+int(timeBzL):]) + + return ts, int64(height), nil +} + +// gets the key for delegator bond with validator +// VALUE: staking/Delegation +func GetDelegationKey(delAddr sdk.AccAddress, valAddr sdk.ValAddress) []byte { + return append(GetDelegationsKey(delAddr), valAddr.Bytes()...) +} + +// gets the prefix for a delegator for all validators +func GetDelegationsKey(delAddr sdk.AccAddress) []byte { + return append(DelegationKey, delAddr.Bytes()...) +} + +// gets the key for an unbonding delegation by delegator and validator addr +// VALUE: staking/UnbondingDelegation +func GetUBDKey(delAddr sdk.AccAddress, valAddr sdk.ValAddress) []byte { + return append( + GetUBDsKey(delAddr), + valAddr.Bytes()...) +} + +// gets the index-key for an unbonding delegation, stored by validator-index +// VALUE: none (key rearrangement used) +func GetUBDByValIndexKey(delAddr sdk.AccAddress, valAddr sdk.ValAddress) []byte { + return append(GetUBDsByValIndexKey(valAddr), delAddr.Bytes()...) +} + +// rearranges the ValIndexKey to get the UBDKey +func GetUBDKeyFromValIndexKey(indexKey []byte) []byte { + addrs := indexKey[1:] // remove prefix bytes + if len(addrs) != 2*v040auth.AddrLen { + panic("unexpected key length") + } + + valAddr := addrs[:v040auth.AddrLen] + delAddr := addrs[v040auth.AddrLen:] + + return GetUBDKey(sdk.AccAddress(delAddr), sdk.ValAddress(valAddr)) +} + +// gets the prefix for all unbonding delegations from a delegator +func GetUBDsKey(delAddr sdk.AccAddress) []byte { + return append(UnbondingDelegationKey, delAddr.Bytes()...) +} + +// gets the prefix keyspace for the indexes of unbonding delegations for a validator +func GetUBDsByValIndexKey(valAddr sdk.ValAddress) []byte { + return append(UnbondingDelegationByValIndexKey, valAddr.Bytes()...) +} + +// gets the prefix for all unbonding delegations from a delegator +func GetUnbondingDelegationTimeKey(timestamp time.Time) []byte { + bz := sdk.FormatTimeBytes(timestamp) + return append(UnbondingQueueKey, bz...) +} + +// GetREDKey returns a key prefix for indexing a redelegation from a delegator +// and source validator to a destination validator. +func GetREDKey(delAddr sdk.AccAddress, valSrcAddr, valDstAddr sdk.ValAddress) []byte { + key := make([]byte, 1+v040auth.AddrLen+v040auth.ValAddrLen*2) + + copy(key[0:v040auth.AddrLen+1], GetREDsKey(delAddr)) + copy(key[v040auth.AddrLen+1:v040auth.AddrLen+v040auth.ValAddrLen+1], valSrcAddr.Bytes()) + copy(key[v040auth.AddrLen+v040auth.ValAddrLen+1:v040auth.AddrLen+v040auth.ValAddrLen*2+1], valDstAddr.Bytes()) + + return key +} + +// gets the index-key for a redelegation, stored by source-validator-index +// VALUE: none (key rearrangement used) +func GetREDByValSrcIndexKey(delAddr sdk.AccAddress, valSrcAddr, valDstAddr sdk.ValAddress) []byte { + REDSFromValsSrcKey := GetREDsFromValSrcIndexKey(valSrcAddr) + offset := len(REDSFromValsSrcKey) + + // key is of the form REDSFromValsSrcKey || delAddr || valDstAddr + key := make([]byte, len(REDSFromValsSrcKey)+v040auth.AddrLen+v040auth.ValAddrLen) + copy(key[0:offset], REDSFromValsSrcKey) + copy(key[offset:offset+v040auth.AddrLen], delAddr.Bytes()) + copy(key[offset+v040auth.AddrLen:offset+v040auth.AddrLen+v040auth.ValAddrLen], valDstAddr.Bytes()) + + return key +} + +// gets the index-key for a redelegation, stored by destination-validator-index +// VALUE: none (key rearrangement used) +func GetREDByValDstIndexKey(delAddr sdk.AccAddress, valSrcAddr, valDstAddr sdk.ValAddress) []byte { + REDSToValsDstKey := GetREDsToValDstIndexKey(valDstAddr) + offset := len(REDSToValsDstKey) + + // key is of the form REDSToValsDstKey || delAddr || valSrcAddr + key := make([]byte, len(REDSToValsDstKey)+v040auth.AddrLen+v040auth.ValAddrLen) + copy(key[0:offset], REDSToValsDstKey) + copy(key[offset:offset+v040auth.AddrLen], delAddr.Bytes()) + copy(key[offset+v040auth.AddrLen:offset+v040auth.AddrLen+v040auth.ValAddrLen], valSrcAddr.Bytes()) + + return key +} + +// GetREDKeyFromValSrcIndexKey rearranges the ValSrcIndexKey to get the REDKey +func GetREDKeyFromValSrcIndexKey(indexKey []byte) []byte { + // note that first byte is prefix byte + if len(indexKey) != 3*v040auth.AddrLen+1 { + panic("unexpected key length") + } + + valSrcAddr := sdk.ValAddress(indexKey[1 : v040auth.AddrLen+1]) + delAddr := sdk.AccAddress(indexKey[v040auth.AddrLen+1 : 2*v040auth.AddrLen+1]) + valDstAddr := sdk.ValAddress(indexKey[2*v040auth.AddrLen+1 : 3*v040auth.AddrLen+1]) + + return GetREDKey(delAddr, valSrcAddr, valDstAddr) +} + +// GetREDKeyFromValDstIndexKey rearranges the ValDstIndexKey to get the REDKey +func GetREDKeyFromValDstIndexKey(indexKey []byte) []byte { + // note that first byte is prefix byte + if len(indexKey) != 3*v040auth.AddrLen+1 { + panic("unexpected key length") + } + + valDstAddr := sdk.ValAddress(indexKey[1 : v040auth.AddrLen+1]) + delAddr := sdk.AccAddress(indexKey[v040auth.AddrLen+1 : 2*v040auth.AddrLen+1]) + valSrcAddr := sdk.ValAddress(indexKey[2*v040auth.AddrLen+1 : 3*v040auth.AddrLen+1]) + + return GetREDKey(delAddr, valSrcAddr, valDstAddr) +} + +// GetRedelegationTimeKey returns a key prefix for indexing an unbonding +// redelegation based on a completion time. +func GetRedelegationTimeKey(timestamp time.Time) []byte { + bz := sdk.FormatTimeBytes(timestamp) + return append(RedelegationQueueKey, bz...) +} + +// GetREDsKey returns a key prefix for indexing a redelegation from a delegator +// address. +func GetREDsKey(delAddr sdk.AccAddress) []byte { + return append(RedelegationKey, delAddr.Bytes()...) +} + +// GetREDsFromValSrcIndexKey returns a key prefix for indexing a redelegation to +// a source validator. +func GetREDsFromValSrcIndexKey(valSrcAddr sdk.ValAddress) []byte { + return append(RedelegationByValSrcIndexKey, valSrcAddr.Bytes()...) +} + +// GetREDsToValDstIndexKey returns a key prefix for indexing a redelegation to a +// destination (target) validator. +func GetREDsToValDstIndexKey(valDstAddr sdk.ValAddress) []byte { + return append(RedelegationByValDstIndexKey, valDstAddr.Bytes()...) +} + +// GetREDsByDelToValDstIndexKey returns a key prefix for indexing a redelegation +// from an address to a source validator. +func GetREDsByDelToValDstIndexKey(delAddr sdk.AccAddress, valDstAddr sdk.ValAddress) []byte { + return append(GetREDsToValDstIndexKey(valDstAddr), delAddr.Bytes()...) +} + +// GetHistoricalInfoKey returns a key prefix for indexing HistoricalInfo objects. +func GetHistoricalInfoKey(height int64) []byte { + return append(HistoricalInfoKey, []byte(strconv.FormatInt(height, 10))...) +} diff --git a/x/staking/legacy/v043/store.go b/x/staking/legacy/v043/store.go new file mode 100644 index 0000000000..ec897cc318 --- /dev/null +++ b/x/staking/legacy/v043/store.go @@ -0,0 +1,103 @@ +package v043 + +import ( + "github.com/line/lbm-sdk/store/prefix" + sdk "github.com/line/lbm-sdk/types" + "github.com/line/lbm-sdk/types/address" + v040auth "github.com/line/lbm-sdk/x/auth/legacy/v040" + v043distribution "github.com/line/lbm-sdk/x/distribution/legacy/v043" + v040staking "github.com/line/lbm-sdk/x/staking/legacy/v040" + "github.com/line/lbm-sdk/x/staking/types" +) + +// migratePrefixAddressAddressAddress is a helper function that migrates all keys of format: +// prefix_bytes | address_1_bytes | address_2_bytes | address_3_bytes +// into format: +// prefix_bytes | address_1_len (1 byte) | address_1_bytes | address_2_len (1 byte) | address_2_bytes | address_3_len (1 byte) | address_3_bytes +func migratePrefixAddressValAddressValAddress(store sdk.KVStore, prefixBz []byte) { + oldStore := prefix.NewStore(store, prefixBz) + + oldStoreIter := oldStore.Iterator(nil, nil) + defer oldStoreIter.Close() + + for ; oldStoreIter.Valid(); oldStoreIter.Next() { + addr1 := oldStoreIter.Key()[:v040auth.AddrLen] + addr2 := oldStoreIter.Key()[v040auth.AddrLen : v040auth.AddrLen+v040auth.ValAddrLen] + addr3 := oldStoreIter.Key()[v040auth.AddrLen+v040auth.ValAddrLen:] + newStoreKey := append(append(append( + prefixBz, + address.MustLengthPrefix(addr1)...), address.MustLengthPrefix(addr2)...), address.MustLengthPrefix(addr3)..., + ) + + // Set new key on store. Values don't change. + store.Set(newStoreKey, oldStoreIter.Value()) + oldStore.Delete(oldStoreIter.Key()) + } +} + +// migratePrefixAddressAddressAddress is a helper function that migrates all keys of format: +// prefix_bytes | address_1_bytes | address_2_bytes | address_3_bytes +// into format: +// prefix_bytes | address_1_len (1 byte) | address_1_bytes | address_2_len (1 byte) | address_2_bytes | address_3_len (1 byte) | address_3_bytes +func migratePrefixValAddressAddressValAddress(store sdk.KVStore, prefixBz []byte) { + oldStore := prefix.NewStore(store, prefixBz) + + oldStoreIter := oldStore.Iterator(nil, nil) + defer oldStoreIter.Close() + + for ; oldStoreIter.Valid(); oldStoreIter.Next() { + addr1 := oldStoreIter.Key()[:v040auth.ValAddrLen] + addr2 := oldStoreIter.Key()[v040auth.ValAddrLen : v040auth.ValAddrLen+v040auth.AddrLen] + addr3 := oldStoreIter.Key()[v040auth.ValAddrLen+v040auth.AddrLen:] + newStoreKey := append(append(append( + prefixBz, + address.MustLengthPrefix(addr1)...), address.MustLengthPrefix(addr2)...), address.MustLengthPrefix(addr3)..., + ) + + // Set new key on store. Values don't change. + store.Set(newStoreKey, oldStoreIter.Value()) + oldStore.Delete(oldStoreIter.Key()) + } +} + +const powerBytesLen = 8 + +func migrateValidatorsByPowerIndexKey(store sdk.KVStore) { + oldStore := prefix.NewStore(store, v040staking.ValidatorsByPowerIndexKey) + + oldStoreIter := oldStore.Iterator(nil, nil) + defer oldStoreIter.Close() + + for ; oldStoreIter.Valid(); oldStoreIter.Next() { + powerBytes := oldStoreIter.Key()[:powerBytesLen] + valAddr := oldStoreIter.Key()[powerBytesLen:] + newStoreKey := append(append(types.ValidatorsByPowerIndexKey, powerBytes...), address.MustLengthPrefix(valAddr)...) + + // Set new key on store. Values don't change. + store.Set(newStoreKey, oldStoreIter.Value()) + oldStore.Delete(oldStoreIter.Key()) + } +} + +// MigrateStore performs in-place store migrations from v0.40 to v0.43. The +// migration includes: +// +// - Setting the Power Reduction param in the paramstore +func MigrateStore(ctx sdk.Context, storeKey sdk.StoreKey) error { + store := ctx.KVStore(storeKey) + + v043distribution.MigratePrefixAddress(store, v040staking.LastValidatorPowerKey) + + v043distribution.MigratePrefixAddress(store, v040staking.ValidatorsKey) + v043distribution.MigratePrefixAddress(store, v040staking.ValidatorsByConsAddrKey) + migrateValidatorsByPowerIndexKey(store) + + v043distribution.MigratePrefixAddressAddress(store, v040staking.DelegationKey) + v043distribution.MigratePrefixAddressAddress(store, v040staking.UnbondingDelegationKey) + v043distribution.MigratePrefixValAddressAddress(store, v040staking.UnbondingDelegationByValIndexKey) + migratePrefixAddressValAddressValAddress(store, v040staking.RedelegationKey) + migratePrefixValAddressAddressValAddress(store, v040staking.RedelegationByValSrcIndexKey) + migratePrefixValAddressAddressValAddress(store, v040staking.RedelegationByValDstIndexKey) + + return nil +} diff --git a/x/staking/legacy/v043/store_test.go b/x/staking/legacy/v043/store_test.go new file mode 100644 index 0000000000..ff9ebb9bde --- /dev/null +++ b/x/staking/legacy/v043/store_test.go @@ -0,0 +1,138 @@ +package v043_test + +import ( + "bytes" + "testing" + "time" + + "github.com/stretchr/testify/require" + + "github.com/line/lbm-sdk/testutil" + "github.com/line/lbm-sdk/testutil/testdata" + sdk "github.com/line/lbm-sdk/types" + v040staking "github.com/line/lbm-sdk/x/staking/legacy/v040" + v043staking "github.com/line/lbm-sdk/x/staking/legacy/v043" + "github.com/line/lbm-sdk/x/staking/teststaking" + "github.com/line/lbm-sdk/x/staking/types" +) + +func TestStoreMigration(t *testing.T) { + stakingKey := sdk.NewKVStoreKey("staking") + tStakingKey := sdk.NewTransientStoreKey("transient_test") + ctx := testutil.DefaultContext(stakingKey, tStakingKey) + store := ctx.KVStore(stakingKey) + + _, pk1, addr1 := testdata.KeyTestPubAddr() + valAddr1 := sdk.AccAddress(addr1).ToValAddress() + val := teststaking.NewValidator(t, valAddr1, pk1) + _, _, addr2 := testdata.KeyTestPubAddr() + valAddr2 := sdk.AccAddress(addr2).ToValAddress() + _, _, addr3 := testdata.KeyTestPubAddr() + consAddr := sdk.AccAddress(addr3).ToConsAddress() + _, _, addr4 := testdata.KeyTestPubAddr() + now := time.Now() + // Use dummy value for all keys. + value := []byte("foo") + + testCases := []struct { + name string + oldKey []byte + newKey []byte + }{ + { + "LastValidatorPowerKey", + v040staking.GetLastValidatorPowerKey(valAddr1), + types.GetLastValidatorPowerKey(valAddr1), + }, + { + "LastTotalPowerKey", + v040staking.LastTotalPowerKey, + types.LastTotalPowerKey, + }, + { + "ValidatorsKey", + v040staking.GetValidatorKey(valAddr1), + types.GetValidatorKey(valAddr1), + }, + { + "ValidatorsByConsAddrKey", + v040staking.GetValidatorByConsAddrKey(consAddr), + types.GetValidatorByConsAddrKey(consAddr), + }, + { + "ValidatorsByPowerIndexKey", + v040staking.GetValidatorsByPowerIndexKey(val), + types.GetValidatorsByPowerIndexKey(val, sdk.DefaultPowerReduction), + }, + { + "DelegationKey", + v040staking.GetDelegationKey(addr4, valAddr1), + types.GetDelegationKey(addr4, valAddr1), + }, + { + "UnbondingDelegationKey", + v040staking.GetUBDKey(addr4, valAddr1), + types.GetUBDKey(addr4, valAddr1), + }, + { + "UnbondingDelegationByValIndexKey", + v040staking.GetUBDByValIndexKey(addr4, valAddr1), + types.GetUBDByValIndexKey(addr4, valAddr1), + }, + { + "RedelegationKey", + v040staking.GetREDKey(addr4, valAddr1, valAddr2), + types.GetREDKey(addr4, valAddr1, valAddr2), + }, + { + "RedelegationByValSrcIndexKey", + v040staking.GetREDByValSrcIndexKey(addr4, valAddr1, valAddr2), + types.GetREDByValSrcIndexKey(addr4, valAddr1, valAddr2), + }, + { + "RedelegationByValDstIndexKey", + v040staking.GetREDByValDstIndexKey(addr4, valAddr1, valAddr2), + types.GetREDByValDstIndexKey(addr4, valAddr1, valAddr2), + }, + { + "UnbondingQueueKey", + v040staking.GetUnbondingDelegationTimeKey(now), + types.GetUnbondingDelegationTimeKey(now), + }, + { + "RedelegationQueueKey", + v040staking.GetRedelegationTimeKey(now), + types.GetRedelegationTimeKey(now), + }, + { + "ValidatorQueueKey", + v040staking.GetValidatorQueueKey(now, 4), + types.GetValidatorQueueKey(now, 4), + }, + { + "HistoricalInfoKey", + v040staking.GetHistoricalInfoKey(4), + types.GetHistoricalInfoKey(4), + }, + } + + // Set all the old keys to the store + for _, tc := range testCases { + store.Set(tc.oldKey, value) + } + + // Run migrations. + err := v043staking.MigrateStore(ctx, stakingKey) + require.NoError(t, err) + + // Make sure the new keys are set and old keys are deleted. + for _, tc := range testCases { + tc := tc + t.Run(tc.name, func(t *testing.T) { + if !bytes.Equal(tc.oldKey, tc.newKey) { + require.Nil(t, store.Get(tc.oldKey)) + } + require.Equal(t, value, store.Get(tc.newKey)) + }) + } +} diff --git a/x/staking/module.go b/x/staking/module.go index f0a7bbbe23..1409dbecc4 100644 --- a/x/staking/module.go +++ b/x/staking/module.go @@ -33,7 +33,7 @@ var ( // AppModuleBasic defines the basic application module used by the staking module. type AppModuleBasic struct { - cdc codec.Marshaler + cdc codec.Codec } var _ module.AppModuleBasic = AppModuleBasic{} @@ -55,12 +55,12 @@ func (b AppModuleBasic) RegisterInterfaces(registry cdctypes.InterfaceRegistry) // DefaultGenesis returns default genesis state as raw bytes for the staking // module. -func (AppModuleBasic) DefaultGenesis(cdc codec.JSONMarshaler) json.RawMessage { +func (AppModuleBasic) DefaultGenesis(cdc codec.JSONCodec) json.RawMessage { return cdc.MustMarshalJSON(types.DefaultGenesisState()) } // ValidateGenesis performs genesis state validation for the staking module. -func (AppModuleBasic) ValidateGenesis(cdc codec.JSONMarshaler, config client.TxEncodingConfig, bz json.RawMessage) error { +func (AppModuleBasic) ValidateGenesis(cdc codec.JSONCodec, config client.TxEncodingConfig, bz json.RawMessage) error { var data types.GenesisState if err := cdc.UnmarshalJSON(bz, &data); err != nil { return fmt.Errorf("failed to unmarshal %s genesis state: %w", types.ModuleName, err) @@ -99,7 +99,7 @@ type AppModule struct { } // NewAppModule creates a new AppModule object -func NewAppModule(cdc codec.Marshaler, keeper keeper.Keeper, ak types.AccountKeeper, bk types.BankKeeper) AppModule { +func NewAppModule(cdc codec.Codec, keeper keeper.Keeper, ak types.AccountKeeper, bk types.BankKeeper) AppModule { return AppModule{ AppModuleBasic: AppModuleBasic{cdc: cdc}, keeper: keeper, @@ -147,7 +147,7 @@ func (am AppModule) RegisterServices(cfg module.Configurator) { // InitGenesis performs genesis initialization for the staking module. It returns // no validator updates. -func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONMarshaler, data json.RawMessage) []abci.ValidatorUpdate { +func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONCodec, data json.RawMessage) []abci.ValidatorUpdate { var genesisState types.GenesisState cdc.MustUnmarshalJSON(data, &genesisState) @@ -157,7 +157,7 @@ func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONMarshaler, data j // ExportGenesis returns the exported genesis state as raw bytes for the staking // module. -func (am AppModule) ExportGenesis(ctx sdk.Context, cdc codec.JSONMarshaler) json.RawMessage { +func (am AppModule) ExportGenesis(ctx sdk.Context, cdc codec.JSONCodec) json.RawMessage { gs := ExportGenesis(ctx, am.keeper) return cdc.MustMarshalJSON(gs) } @@ -176,8 +176,6 @@ func (am AppModule) EndBlock(ctx sdk.Context, _ abci.RequestEndBlock) []abci.Val return EndBlocker(ctx, am.keeper) } -// ____________________________________________________________________________ - // AppModuleSimulation functions // GenerateGenesisState creates a randomized GenState of the staking module. diff --git a/x/staking/simulation/common_test.go b/x/staking/simulation/common_test.go index 09ef67504e..dac0879f2a 100644 --- a/x/staking/simulation/common_test.go +++ b/x/staking/simulation/common_test.go @@ -7,5 +7,5 @@ import ( ) func init() { - sdk.PowerReduction = sdk.NewIntFromBigInt(new(big.Int).Exp(big.NewInt(10), big.NewInt(18), nil)) + sdk.DefaultPowerReduction = sdk.NewIntFromBigInt(new(big.Int).Exp(big.NewInt(10), big.NewInt(18), nil)) } diff --git a/x/staking/simulation/decoder.go b/x/staking/simulation/decoder.go index b53f996df2..007782baf9 100644 --- a/x/staking/simulation/decoder.go +++ b/x/staking/simulation/decoder.go @@ -12,21 +12,21 @@ import ( // NewDecodeStore returns a decoder function closure that unmarshals the KVPair's // Value to the corresponding staking type. -func NewDecodeStore(cdc codec.Marshaler) func(kvA, kvB kv.Pair) string { +func NewDecodeStore(cdc codec.Codec) func(kvA, kvB kv.Pair) string { return func(kvA, kvB kv.Pair) string { switch { case bytes.Equal(kvA.Key[:1], types.LastTotalPowerKey): var powerA, powerB sdk.IntProto - cdc.MustUnmarshalBinaryBare(kvA.Value, &powerA) - cdc.MustUnmarshalBinaryBare(kvB.Value, &powerB) + cdc.MustUnmarshal(kvA.Value, &powerA) + cdc.MustUnmarshal(kvB.Value, &powerB) return fmt.Sprintf("%v\n%v", powerA, powerB) case bytes.Equal(kvA.Key[:1], types.ValidatorsKey): var validatorA, validatorB types.Validator - cdc.MustUnmarshalBinaryBare(kvA.Value, &validatorA) - cdc.MustUnmarshalBinaryBare(kvB.Value, &validatorB) + cdc.MustUnmarshal(kvA.Value, &validatorA) + cdc.MustUnmarshal(kvB.Value, &validatorB) return fmt.Sprintf("%v\n%v", validatorA, validatorB) case bytes.Equal(kvA.Key[:1], types.LastValidatorPowerKey), @@ -37,24 +37,24 @@ func NewDecodeStore(cdc codec.Marshaler) func(kvA, kvB kv.Pair) string { case bytes.Equal(kvA.Key[:1], types.DelegationKey): var delegationA, delegationB types.Delegation - cdc.MustUnmarshalBinaryBare(kvA.Value, &delegationA) - cdc.MustUnmarshalBinaryBare(kvB.Value, &delegationB) + cdc.MustUnmarshal(kvA.Value, &delegationA) + cdc.MustUnmarshal(kvB.Value, &delegationB) return fmt.Sprintf("%v\n%v", delegationA, delegationB) case bytes.Equal(kvA.Key[:1], types.UnbondingDelegationKey), bytes.Equal(kvA.Key[:1], types.UnbondingDelegationByValIndexKey): var ubdA, ubdB types.UnbondingDelegation - cdc.MustUnmarshalBinaryBare(kvA.Value, &ubdA) - cdc.MustUnmarshalBinaryBare(kvB.Value, &ubdB) + cdc.MustUnmarshal(kvA.Value, &ubdA) + cdc.MustUnmarshal(kvB.Value, &ubdB) return fmt.Sprintf("%v\n%v", ubdA, ubdB) case bytes.Equal(kvA.Key[:1], types.RedelegationKey), bytes.Equal(kvA.Key[:1], types.RedelegationByValSrcIndexKey): var redA, redB types.Redelegation - cdc.MustUnmarshalBinaryBare(kvA.Value, &redA) - cdc.MustUnmarshalBinaryBare(kvB.Value, &redB) + cdc.MustUnmarshal(kvA.Value, &redA) + cdc.MustUnmarshal(kvB.Value, &redB) return fmt.Sprintf("%v\n%v", redA, redB) default: diff --git a/x/staking/simulation/decoder_test.go b/x/staking/simulation/decoder_test.go index da8ebe021f..3ceb69a70c 100644 --- a/x/staking/simulation/decoder_test.go +++ b/x/staking/simulation/decoder_test.go @@ -32,9 +32,8 @@ func makeTestCodec() (cdc *codec.LegacyAmino) { } func TestDecodeStore(t *testing.T) { - cdc, _ := simapp.MakeCodecs() + cdc := simapp.MakeTestEncodingConfig().Marshaler dec := simulation.NewDecodeStore(cdc) - bondTime := time.Now().UTC() val, err := types.NewValidator(valAddr1, delPk1, types.NewDescription("test", "test", "test", "test", "test")) @@ -45,12 +44,12 @@ func TestDecodeStore(t *testing.T) { kvPairs := kv.Pairs{ Pairs: []kv.Pair{ - {Key: types.LastTotalPowerKey, Value: cdc.MustMarshalBinaryBare(&sdk.IntProto{Int: sdk.OneInt()})}, - {Key: types.GetValidatorKey(valAddr1), Value: cdc.MustMarshalBinaryBare(&val)}, + {Key: types.LastTotalPowerKey, Value: cdc.MustMarshal(&sdk.IntProto{Int: sdk.OneInt()})}, + {Key: types.GetValidatorKey(valAddr1), Value: cdc.MustMarshal(&val)}, {Key: types.LastValidatorPowerKey, Value: valAddr1.Bytes()}, - {Key: types.GetDelegationKey(delAddr1, valAddr1), Value: cdc.MustMarshalBinaryBare(&del)}, - {Key: types.GetUBDKey(delAddr1, valAddr1), Value: cdc.MustMarshalBinaryBare(&ubd)}, - {Key: types.GetREDKey(delAddr1, valAddr1, valAddr1), Value: cdc.MustMarshalBinaryBare(&red)}, + {Key: types.GetDelegationKey(delAddr1, valAddr1), Value: cdc.MustMarshal(&del)}, + {Key: types.GetUBDKey(delAddr1, valAddr1), Value: cdc.MustMarshal(&ubd)}, + {Key: types.GetREDKey(delAddr1, valAddr1, valAddr1), Value: cdc.MustMarshal(&red)}, {Key: []byte{0x99}, Value: []byte{0x99}}, }, } diff --git a/x/staking/simulation/genesis.go b/x/staking/simulation/genesis.go index ac8102481f..cbf564dcd1 100644 --- a/x/staking/simulation/genesis.go +++ b/x/staking/simulation/genesis.go @@ -21,18 +21,18 @@ const ( historicalEntries = "historical_entries" ) -// GenUnbondingTime randomized UnbondingTime -func GenUnbondingTime(r *rand.Rand) (ubdTime time.Duration) { +// genUnbondingTime returns randomized UnbondingTime +func genUnbondingTime(r *rand.Rand) (ubdTime time.Duration) { return time.Duration(simulation.RandIntBetween(r, 60, 60*60*24*3*2)) * time.Second } -// GenMaxValidators randomized MaxValidators -func GenMaxValidators(r *rand.Rand) (maxValidators uint32) { +// genMaxValidators returns randomized MaxValidators +func genMaxValidators(r *rand.Rand) (maxValidators uint32) { return uint32(r.Intn(250) + 1) } -// GetHistEntries randomized HistoricalEntries between 0-100. -func GetHistEntries(r *rand.Rand) uint32 { +// getHistEntries returns randomized HistoricalEntries between 0-100. +func getHistEntries(r *rand.Rand) uint32 { return uint32(r.Intn(int(types.DefaultHistoricalEntries + 1))) } @@ -47,17 +47,17 @@ func RandomizedGenState(simState *module.SimulationState) { simState.AppParams.GetOrGenerate( simState.Cdc, unbondingTime, &unbondTime, simState.Rand, - func(r *rand.Rand) { unbondTime = GenUnbondingTime(r) }, + func(r *rand.Rand) { unbondTime = genUnbondingTime(r) }, ) simState.AppParams.GetOrGenerate( simState.Cdc, maxValidators, &maxVals, simState.Rand, - func(r *rand.Rand) { maxVals = GenMaxValidators(r) }, + func(r *rand.Rand) { maxVals = genMaxValidators(r) }, ) simState.AppParams.GetOrGenerate( simState.Cdc, historicalEntries, &histEntries, simState.Rand, - func(r *rand.Rand) { histEntries = GetHistEntries(r) }, + func(r *rand.Rand) { histEntries = getHistEntries(r) }, ) // NOTE: the slashing module need to be defined after the staking module on the diff --git a/x/staking/simulation/genesis_test.go b/x/staking/simulation/genesis_test.go index d114742b06..ff2ce14df7 100644 --- a/x/staking/simulation/genesis_test.go +++ b/x/staking/simulation/genesis_test.go @@ -66,7 +66,7 @@ func TestRandomizedGenState(t *testing.T) { require.Equal(t, "1", stakingGenesis.Validators[2].MinSelfDelegation.String()) } -// TestRandomizedGenState tests abnormal scenarios of applying RandomizedGenState. +// TestRandomizedGenState1 tests abnormal scenarios of applying RandomizedGenState. func TestRandomizedGenState1(t *testing.T) { interfaceRegistry := codectypes.NewInterfaceRegistry() cdc := codec.NewProtoCodec(interfaceRegistry) diff --git a/x/staking/simulation/operations.go b/x/staking/simulation/operations.go index 90b88c864f..2b5816dfa7 100644 --- a/x/staking/simulation/operations.go +++ b/x/staking/simulation/operations.go @@ -6,7 +6,6 @@ import ( "github.com/line/lbm-sdk/baseapp" "github.com/line/lbm-sdk/codec" - "github.com/line/lbm-sdk/simapp/helpers" simappparams "github.com/line/lbm-sdk/simapp/params" sdk "github.com/line/lbm-sdk/types" simtypes "github.com/line/lbm-sdk/types/simulation" @@ -16,6 +15,7 @@ import ( ) // Simulation operation weights constants +// nolint:gosec const ( OpWeightMsgCreateValidator = "op_weight_msg_create_validator" OpWeightMsgEditValidator = "op_weight_msg_edit_validator" @@ -26,7 +26,7 @@ const ( // WeightedOperations returns all the operations from the module with their respective weights func WeightedOperations( - appParams simtypes.AppParams, cdc codec.JSONMarshaler, ak types.AccountKeeper, + appParams simtypes.AppParams, cdc codec.JSONCodec, ak types.AccountKeeper, bk types.BankKeeper, k keeper.Keeper, ) simulation.WeightedOperations { var ( @@ -152,27 +152,19 @@ func SimulateMsgCreateValidator(ak types.AccountKeeper, bk types.BankKeeper, k k return simtypes.NoOpMsg(types.ModuleName, msg.Type(), "unable to create CreateValidator message"), nil, err } - txGen := simappparams.MakeTestEncodingConfig().TxConfig - tx, err := helpers.GenTx( - txGen, - []sdk.Msg{msg}, - fees, - helpers.DefaultGenTxGas, - chainID, - []uint64{account.GetAccountNumber()}, - []uint64{account.GetSequence()}, - simAccount.PrivKey, - ) - if err != nil { - return simtypes.NoOpMsg(types.ModuleName, msg.Type(), "unable to generate mock tx"), nil, err - } - - _, _, err = app.Deliver(txGen.TxEncoder(), tx) - if err != nil { - return simtypes.NoOpMsg(types.ModuleName, msg.Type(), "unable to deliver tx"), nil, err + txCtx := simulation.OperationInput{ + App: app, + TxGen: simappparams.MakeTestEncodingConfig().TxConfig, + Cdc: nil, + Msg: msg, + MsgType: msg.Type(), + Context: ctx, + SimAccount: simAccount, + AccountKeeper: ak, + ModuleName: types.ModuleName, } - return simtypes.NewOperationMsg(msg, true, ""), nil, nil + return simulation.GenAndDeliverTx(txCtx, fees) } } @@ -207,11 +199,6 @@ func SimulateMsgEditValidator(ak types.AccountKeeper, bk types.BankKeeper, k kee account := ak.GetAccount(ctx, simAccount.Address) spendable := bk.SpendableCoins(ctx, account.GetAddress()) - fees, err := simtypes.RandomFees(r, ctx, spendable) - if err != nil { - return simtypes.NoOpMsg(types.ModuleName, types.TypeMsgEditValidator, "unable to generate fees"), nil, err - } - description := types.NewDescription( simtypes.RandStringOfLength(r, 10), simtypes.RandStringOfLength(r, 10), @@ -222,27 +209,22 @@ func SimulateMsgEditValidator(ak types.AccountKeeper, bk types.BankKeeper, k kee msg := types.NewMsgEditValidator(address, description, &newCommissionRate, nil) - txGen := simappparams.MakeTestEncodingConfig().TxConfig - tx, err := helpers.GenTx( - txGen, - []sdk.Msg{msg}, - fees, - helpers.DefaultGenTxGas, - chainID, - []uint64{account.GetAccountNumber()}, - []uint64{account.GetSequence()}, - simAccount.PrivKey, - ) - if err != nil { - return simtypes.NoOpMsg(types.ModuleName, msg.Type(), "unable to generate mock tx"), nil, err - } - - _, _, err = app.Deliver(txGen.TxEncoder(), tx) - if err != nil { - return simtypes.NoOpMsg(types.ModuleName, msg.Type(), "unable to deliver tx"), nil, err - } - - return simtypes.NewOperationMsg(msg, true, ""), nil, nil + txCtx := simulation.OperationInput{ + R: r, + App: app, + TxGen: simappparams.MakeTestEncodingConfig().TxConfig, + Cdc: nil, + Msg: msg, + MsgType: msg.Type(), + Context: ctx, + SimAccount: simAccount, + AccountKeeper: ak, + Bankkeeper: bk, + ModuleName: types.ModuleName, + CoinsSpentInMsg: spendable, + } + + return simulation.GenAndDeliverTxWithRandFees(txCtx) } } @@ -294,27 +276,19 @@ func SimulateMsgDelegate(ak types.AccountKeeper, bk types.BankKeeper, k keeper.K msg := types.NewMsgDelegate(simAccount.Address, val.GetOperator(), bondAmt) - txGen := simappparams.MakeTestEncodingConfig().TxConfig - tx, err := helpers.GenTx( - txGen, - []sdk.Msg{msg}, - fees, - helpers.DefaultGenTxGas, - chainID, - []uint64{account.GetAccountNumber()}, - []uint64{account.GetSequence()}, - simAccount.PrivKey, - ) - if err != nil { - return simtypes.NoOpMsg(types.ModuleName, msg.Type(), "unable to generate mock tx"), nil, err - } - - _, _, err = app.Deliver(txGen.TxEncoder(), tx) - if err != nil { - return simtypes.NoOpMsg(types.ModuleName, msg.Type(), "unable to deliver tx"), nil, err + txCtx := simulation.OperationInput{ + App: app, + TxGen: simappparams.MakeTestEncodingConfig().TxConfig, + Cdc: nil, + Msg: msg, + MsgType: msg.Type(), + Context: ctx, + SimAccount: simAccount, + AccountKeeper: ak, + ModuleName: types.ModuleName, } - return simtypes.NewOperationMsg(msg, true, ""), nil, nil + return simulation.GenAndDeliverTx(txCtx, fees) } } @@ -378,32 +352,22 @@ func SimulateMsgUndelegate(ak types.AccountKeeper, bk types.BankKeeper, k keeper account := ak.GetAccount(ctx, delAddr) spendable := bk.SpendableCoins(ctx, account.GetAddress()) - fees, err := simtypes.RandomFees(r, ctx, spendable) - if err != nil { - return simtypes.NoOpMsg(types.ModuleName, msg.Type(), "unable to generate fees"), nil, err - } - - txGen := simappparams.MakeTestEncodingConfig().TxConfig - tx, err := helpers.GenTx( - txGen, - []sdk.Msg{msg}, - fees, - helpers.DefaultGenTxGas, - chainID, - []uint64{account.GetAccountNumber()}, - []uint64{account.GetSequence()}, - simAccount.PrivKey, - ) - if err != nil { - return simtypes.NoOpMsg(types.ModuleName, msg.Type(), "unable to generate mock tx"), nil, err - } - - _, _, err = app.Deliver(txGen.TxEncoder(), tx) - if err != nil { - return simtypes.NoOpMsg(types.ModuleName, msg.Type(), "unable to deliver tx"), nil, err - } - - return simtypes.NewOperationMsg(msg, true, ""), nil, nil + txCtx := simulation.OperationInput{ + R: r, + App: app, + TxGen: simappparams.MakeTestEncodingConfig().TxConfig, + Cdc: nil, + Msg: msg, + MsgType: msg.Type(), + Context: ctx, + SimAccount: simAccount, + AccountKeeper: ak, + Bankkeeper: bk, + ModuleName: types.ModuleName, + CoinsSpentInMsg: spendable, + } + + return simulation.GenAndDeliverTxWithRandFees(txCtx) } } @@ -485,36 +449,26 @@ func SimulateMsgBeginRedelegate(ak types.AccountKeeper, bk types.BankKeeper, k k account := ak.GetAccount(ctx, delAddr) spendable := bk.SpendableCoins(ctx, account.GetAddress()) - fees, err := simtypes.RandomFees(r, ctx, spendable) - if err != nil { - return simtypes.NoOpMsg(types.ModuleName, types.TypeMsgBeginRedelegate, "unable to generate fees"), nil, err - } - msg := types.NewMsgBeginRedelegate( delAddr, srcAddr, destAddr, sdk.NewCoin(k.BondDenom(ctx), redAmt), ) - txGen := simappparams.MakeTestEncodingConfig().TxConfig - tx, err := helpers.GenTx( - txGen, - []sdk.Msg{msg}, - fees, - helpers.DefaultGenTxGas, - chainID, - []uint64{account.GetAccountNumber()}, - []uint64{account.GetSequence()}, - simAccount.PrivKey, - ) - if err != nil { - return simtypes.NoOpMsg(types.ModuleName, msg.Type(), "unable to generate mock tx"), nil, err - } - - _, _, err = app.Deliver(txGen.TxEncoder(), tx) - if err != nil { - return simtypes.NoOpMsg(types.ModuleName, msg.Type(), "unable to deliver tx"), nil, err - } - - return simtypes.NewOperationMsg(msg, true, ""), nil, nil + txCtx := simulation.OperationInput{ + R: r, + App: app, + TxGen: simappparams.MakeTestEncodingConfig().TxConfig, + Cdc: nil, + Msg: msg, + MsgType: msg.Type(), + Context: ctx, + SimAccount: simAccount, + AccountKeeper: ak, + Bankkeeper: bk, + ModuleName: types.ModuleName, + CoinsSpentInMsg: spendable, + } + + return simulation.GenAndDeliverTxWithRandFees(txCtx) } } diff --git a/x/staking/simulation/operations_test.go b/x/staking/simulation/operations_test.go index cd5b9f1b87..cdb48c08cf 100644 --- a/x/staking/simulation/operations_test.go +++ b/x/staking/simulation/operations_test.go @@ -120,10 +120,10 @@ func TestSimulateMsgEditValidator(t *testing.T) { require.True(t, operationMsg.OK) require.Equal(t, "0.280623462081924936", msg.CommissionRate.String()) - require.Equal(t, "rBqDOTtGTO", msg.Description.Moniker) - require.Equal(t, "BSpYuLyYgg", msg.Description.Identity) - require.Equal(t, "wNbeHVIkPZ", msg.Description.Website) - require.Equal(t, "MOXcnQfyze", msg.Description.SecurityContact) + require.Equal(t, "xKGLwQvuyN", msg.Description.Moniker) + require.Equal(t, "SlcxgdXhhu", msg.Description.Identity) + require.Equal(t, "WeLrQKjLxz", msg.Description.Website) + require.Equal(t, "rBqDOTtGTO", msg.Description.SecurityContact) require.Equal(t, types.TypeMsgEditValidator, msg.Type()) require.Equal(t, "linkvaloper1tnh2q55v8wyygtt9srz5safamzdengsn8rx882", msg.ValidatorAddress) require.Len(t, futureOperations, 0) @@ -181,7 +181,7 @@ func TestSimulateMsgUndelegate(t *testing.T) { validator0 := getTestingValidator0(t, app, ctx, accounts) // setup delegation - delTokens := sdk.TokensFromConsensusPower(2) + delTokens := app.StakingKeeper.TokensFromConsensusPower(ctx, 2) validator0, issuedShares := validator0.AddTokensFromDel(delTokens) delegator := accounts[1] delegation := types.NewDelegation(delegator.Address, validator0.GetOperator(), issuedShares) @@ -227,7 +227,7 @@ func TestSimulateMsgBeginRedelegate(t *testing.T) { validator0 := getTestingValidator0(t, app, ctx, accounts) validator1 := getTestingValidator1(t, app, ctx, accounts) - delTokens := sdk.TokensFromConsensusPower(2) + delTokens := app.StakingKeeper.TokensFromConsensusPower(ctx, 2) validator0, issuedShares := validator0.AddTokensFromDel(delTokens) // setup accounts[2] as delegator @@ -277,15 +277,14 @@ func createTestApp(isCheckTx bool) (*simapp.SimApp, sdk.Context) { func getTestingAccounts(t *testing.T, r *rand.Rand, app *simapp.SimApp, ctx sdk.Context, n int) []simtypes.Account { accounts := simtypes.RandomAccounts(r, n) - initAmt := sdk.TokensFromConsensusPower(200) + initAmt := app.StakingKeeper.TokensFromConsensusPower(ctx, 200) initCoins := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, initAmt)) // add coins to the accounts for _, account := range accounts { acc := app.AccountKeeper.NewAccountWithAddress(ctx, account.Address) app.AccountKeeper.SetAccount(ctx, acc) - err := app.BankKeeper.SetBalances(ctx, account.Address, initCoins) - require.NoError(t, err) + require.NoError(t, simapp.FundAccount(app, ctx, account.Address, initCoins)) } return accounts @@ -310,7 +309,7 @@ func getTestingValidator(t *testing.T, app *simapp.SimApp, ctx sdk.Context, acco require.NoError(t, err) validator.DelegatorShares = sdk.NewDec(100) - validator.Tokens = sdk.TokensFromConsensusPower(100) + validator.Tokens = app.StakingKeeper.TokensFromConsensusPower(ctx, 100) app.StakingKeeper.SetValidator(ctx, validator) diff --git a/x/staking/simulation/params.go b/x/staking/simulation/params.go index 2fe79239b2..76012a4227 100644 --- a/x/staking/simulation/params.go +++ b/x/staking/simulation/params.go @@ -6,9 +6,8 @@ import ( "fmt" "math/rand" - "github.com/line/lbm-sdk/x/simulation" - simtypes "github.com/line/lbm-sdk/types/simulation" + "github.com/line/lbm-sdk/x/simulation" "github.com/line/lbm-sdk/x/staking/types" ) @@ -18,17 +17,17 @@ func ParamChanges(r *rand.Rand) []simtypes.ParamChange { return []simtypes.ParamChange{ simulation.NewSimParamChange(types.ModuleName, string(types.KeyMaxValidators), func(r *rand.Rand) string { - return fmt.Sprintf("%d", GenMaxValidators(r)) + return fmt.Sprintf("%d", genMaxValidators(r)) }, ), simulation.NewSimParamChange(types.ModuleName, string(types.KeyUnbondingTime), func(r *rand.Rand) string { - return fmt.Sprintf("\"%d\"", GenUnbondingTime(r)) + return fmt.Sprintf("\"%d\"", genUnbondingTime(r)) }, ), simulation.NewSimParamChange(types.ModuleName, string(types.KeyHistoricalEntries), func(r *rand.Rand) string { - return fmt.Sprintf("%d", GetHistEntries(r)) + return fmt.Sprintf("%d", getHistEntries(r)) }, ), } diff --git a/x/staking/spec/01_state.md b/x/staking/spec/01_state.md index 47fabdd8ab..8bfbb3387f 100644 --- a/x/staking/spec/01_state.md +++ b/x/staking/spec/01_state.md @@ -4,6 +4,10 @@ order: 1 # State +## Pool + +Pool is used for tracking bonded and not-bonded token supply of the bond denomination. + ## LastTotalPower LastTotalPower tracks the total amounts of bonded tokens recorded during the previous end block. @@ -18,7 +22,7 @@ and defines overall functioning of the staking module. - Params: `Paramsspace("staking") -> legacy_amino(params)` -+++ https://github.com/line/lbm-sdk/blob/main/proto/lbm/staking/v1/staking.proto#L269-L284 ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.40.1/proto/cosmos/staking/v1beta1/staking.proto#L230-L241 ## Validator @@ -37,7 +41,6 @@ Validators can have one of three statuses tombstoning, an unbonding of all their delegations begins. All delegations must then wait the UnbondingTime before their tokens are moved to their accounts from the `BondedPool`. -Validators objects should be primarily stored and accessed by the `OperatorAddr`, an SDK validator address for the operator of the validator. Two additional indices are maintained per validator object in order to fulfill required lookups for slashing and validator-set updates. A third special index @@ -68,10 +71,11 @@ where `Jailed` is true are not stored within this index. `LastValidatorsPower` is a special index that provides a historical list of the last-block's bonded validators. This index remains constant during a block but is updated during the validator set update process which takes place in [`EndBlock`](./05_end_block.md). - Each validator's state is stored in a `Validator` struct: -+++ https://github.com/line/lbm-sdk/blob/main/proto/lbm/staking/v1/staking.proto#L83-L120 ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/staking/v1beta1/staking.proto#L65-L99 + ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/staking/v1beta1/staking.proto#L24-L63 ## Delegation @@ -85,7 +89,7 @@ funds are held in a `Delegation` data structure. It is owned by one delegator, and is associated with the shares for one validator. The sender of the transaction is the owner of the bond. -+++ https://github.com/line/lbm-sdk/blob/main/proto/lbm/staking/v1/staking.proto#L183-L194 ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/staking/v1beta1/staking.proto#L159-L170 ### Delegator Shares @@ -124,7 +128,7 @@ slashed. A UnbondingDelegation object is created every time an unbonding is initiated. -+++ https://github.com/line/lbm-sdk/blob/main/proto/lbm/staking/v1/staking.proto#L198-L209 ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/staking/v1beta1/staking.proto#L172-L198 ## Redelegation @@ -152,7 +156,7 @@ A redelegation object is created every time a redelegation occurs. To prevent - and, the (re)delegator is attempting to create a _new_ redelegation where the source validator for this new redelegation is `Validator X`. -+++ https://github.com/line/lbm-sdk/blob/main/proto/lbm/staking/v1/staking.proto#L253-L266 ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/staking/v1beta1/staking.proto#L200-L228 ## Queues @@ -174,7 +178,7 @@ delegations queue is kept. - UnbondingDelegation: `0x41 | format(time) -> []DVPair` -+++ https://github.com/line/lbm-sdk/blob/main/proto/lbm/staking/v1/staking.proto#L212-L229 ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/staking/v1beta1/staking.proto#L123-L133 ### RedelegationQueue @@ -183,7 +187,7 @@ kept. - RedelegationQueue: `0x42 | format(time) -> []DVVTriplet` -+++ https://github.com/line/lbm-sdk/blob/main/proto/lbm/staking/v1/staking.proto#L232-L249 ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/staking/v1beta1/staking.proto#L140-L152 ### ValidatorQueue @@ -202,7 +206,7 @@ that multiple validators exist in the queue at the same location. HistoricalInfo objects are stored and pruned at each block such that the staking keeper persists the `n` most recent historical info defined by staking module parameter: `HistoricalEntries`. -+++ https://github.com/line/lbm-sdk/blob/main/proto/lbm/staking/v1/staking.proto#L19-L22 ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/staking/v1beta1/staking.proto#L15-L22 At each BeginBlock, the staking keeper will persist the current Header and the Validators that committed the current block in a `HistoricalInfo` object. The Validators are sorted on their address to ensure that diff --git a/x/staking/spec/02_state_transitions.md b/x/staking/spec/02_state_transitions.md index 5777ed2517..d62761d16a 100644 --- a/x/staking/spec/02_state_transitions.md +++ b/x/staking/spec/02_state_transitions.md @@ -60,6 +60,7 @@ this process may be also be reversed. the following operations occur: - if unjailed add record to `ValidatorByPowerIndex` Jailed validators are not present in any of the following stores: + - the power store (from consensus power to address) ## Delegations @@ -112,6 +113,9 @@ Redelegations affect the delegation, source and destination validators. is `Bonded`, transfer the newly delegated tokens from the `NotBondedPool` to the `BondedPool` `ModuleAccount` - record the token amount in an new entry in the relevant `Redelegation` +From when a redelegation begins until it completes, the delegator is in a state of "pseudo-unbonding", and can still be +slashed for infractions that occured before the redelegation began. + ### Complete Redelegation When a redelegations complete the following occurs: @@ -126,13 +130,17 @@ When a Validator is slashed, the following occurs: - The total `slashAmount` is calculated as the `slashFactor` (a chain parameter) \* `TokensFromConsensusPower`, the total number of tokens bonded to the validator at the time of the infraction. -- Every unbonding delegation and redelegation from the validator are slashed by the `slashFactor` - percentage of the initialBalance. +- Every unbonding delegation and pseudo-unbonding redelegation such that the infraction occured before the unbonding or + redelegation began from the validator are slashed by the `slashFactor` percentage of the initialBalance. - Each amount slashed from redelegations and unbonding delegations is subtracted from the total slash amount. - The `remaingSlashAmount` is then slashed from the validator's tokens in the `BondedPool` or `NonBondedPool` depending on the validator's status. This reduces the total supply of tokens. +In the case of a slash due to any infraction that requires evidence to submitted (for example double-sign), the slash +occurs at the block where the evidence is included, not at the block where the infraction occured. +Put otherwise, validators are not slashed retroactively, only when they are caught. + ### Slash Unbonding Delegation When a validator is slashed, so are those unbonding delegations from the validator that began unbonding @@ -144,5 +152,25 @@ delegation and is capped to prevent a resulting negative balance. Completed (or When a validator is slashed, so are all redelegations from the validator that began after the infraction. Redelegations are slashed by `slashFactor`. +Redelegations that began before the infraction are not slashed. The amount slashed is calculated from the `InitialBalance` of the delegation and is capped to -prevent a resulting negative balance. Mature redelegations are not slashed. +prevent a resulting negative balance. +Mature redelegations (that have completed pseudo-unbonding) are not slashed. + +## How Shares are calculated + +At any given point in time, each validator has a number of tokens, `T`, and has a number of shares issued, `S`. +Each delegator, `i`, holds a number of shares, `S_i`. +The number of tokens is the sum of all tokens delegated to the validator, plus the rewards, minus the slashes. + +The delegator is entitled to a portion of the underlying tokens proportional to their proportion of shares. +So delegator `i` is entitled to `T * S_i / S` of the validator's tokens. + +When a delegator delegates new tokens to the validator, they receive a number of shares proportional to their contribution. +So when delegator `j` delegates `T_j` tokens, they receive `S_j = S * T_j / T` shares. +The total number of tokens is now `T + T_j`, and the total number of shares is `S + S_j`. +`j`s proportion of the shares is the same as their proportion of the total tokens contributed: `(S + S_j) / S = (T + T_j) / T`. + +A special case is the initial delegation, when `T = 0` and `S = 0`, so `T_j / T` is undefined. +For the initial delegation, delegator `j` who delegates `T_j` tokens receive `S_j = T_j` shares. +So a validator that hasn't received any rewards and has not been slashed will have `T = S`. diff --git a/x/staking/spec/03_messages.md b/x/staking/spec/03_messages.md index 45c20cf4b4..9dce41e9a4 100644 --- a/x/staking/spec/03_messages.md +++ b/x/staking/spec/03_messages.md @@ -6,65 +6,68 @@ order: 3 In this section we describe the processing of the staking messages and the corresponding updates to the state. All created/modified state objects specified by each message are defined within the [state](./02_state_transitions.md) section. -## Msg/CreateValidator +## MsgCreateValidator -A validator is created using the `Msg/CreateValidator` service message. +A validator is created using the `MsgCreateValidator` message. +The validator must be created with an initial delegation from the operator. -+++ https://github.com/line/lbm-sdk/blob/main/proto/lbm/staking/v1/tx.proto#L16-L17 ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/staking/v1beta1/tx.proto#L16-L17 -+++ https://github.com/line/lbm-sdk/blob/main/proto/lbm/staking/v1/tx.proto#L36-L51 ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/staking/v1beta1/tx.proto#L35-L51 -This service message is expected to fail if: +This message is expected to fail if: - another validator with this operator address is already registered - another validator with this pubkey is already registered - the initial self-delegation tokens are of a denom not specified as the bonding denom - the commission parameters are faulty, namely: - - `MaxRate` is either > 1 or < 0 - - the initial `Rate` is either negative or > `MaxRate` - - the initial `MaxChangeRate` is either negative or > `MaxRate` + - `MaxRate` is either > 1 or < 0 + - the initial `Rate` is either negative or > `MaxRate` + - the initial `MaxChangeRate` is either negative or > `MaxRate` - the description fields are too large -This service message creates and stores the `Validator` object at appropriate indexes. +This message creates and stores the `Validator` object at appropriate indexes. Additionally a self-delegation is made with the initial tokens delegation tokens `Delegation`. The validator always starts as unbonded but may be bonded in the first end-block. -## Msg/EditValidator +## MsgEditValidator The `Description`, `CommissionRate` of a validator can be updated using the -`Msg/EditCandidacy` service message. +`MsgEditValidator` message. -+++ https://github.com/line/lbm-sdk/blob/main/proto/lbm/staking/v1/tx.proto#L19-L20 ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/staking/v1beta1/tx.proto#L19-L20 -+++ https://github.com/line/lbm-sdk/blob/main/proto/lbm/staking/v1/tx.proto#L56-L76 ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/staking/v1beta1/tx.proto#L56-L76 -This service message is expected to fail if: +This message is expected to fail if: - the initial `CommissionRate` is either negative or > `MaxRate` - the `CommissionRate` has already been updated within the previous 24 hours - the `CommissionRate` is > `MaxChangeRate` - the description fields are too large -This service message stores the updated `Validator` object. +This message stores the updated `Validator` object. -## Msg/Delegate +## MsgDelegate -Within this service message the delegator provides coins, and in return receives +Within this message the delegator provides coins, and in return receives some amount of their validator's (newly created) delegator-shares that are assigned to `Delegation.Shares`. -+++ https://github.com/line/lbm-sdk/blob/main/proto/lbm/staking/v1/tx.proto#L22-L24 ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/staking/v1beta1/tx.proto#L22-L24 -+++ https://github.com/line/lbm-sdk/blob/main/proto/lbm/staking/v1/tx.proto#L81-L90 ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/staking/v1beta1/tx.proto#L81-L90 -This service message is expected to fail if: +This message is expected to fail if: -- the validator is does not exist +- the validator does not exist - the `Amount` `Coin` has a denomination different than one defined by `params.BondDenom` +- the exchange rate is invalid, meaning the validator has no tokens (due to slashing) but there are outstanding shares +- the amount delegated is less than the minimum allowed delegation If an existing `Delegation` object for provided addresses does not already -exist than it is created as part of this service message otherwise the existing +exist then it is created as part of this message otherwise the existing `Delegation` is updated to include the newly received shares. The delegator receives newly minted shares at the current exchange rate. @@ -77,20 +80,22 @@ tracked in validator object in the `Validators` index. It is possible to delegate to a jailed validator, the only difference being it will not be added to the power index until it is unjailed. -## Msg/Undelegate +![Delegation sequence](../../../docs/uml/svg/delegation_sequence.svg) -The `Msg/Undelegate` service message allows delegators to undelegate their tokens from +## MsgUndelegate + +The `MsgUndelegate` message allows delegators to undelegate their tokens from validator. -+++ https://github.com/line/lbm-sdk/blob/main/proto/lbm/staking/v1/tx.proto#L30-L32 ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/staking/v1beta1/tx.proto#L30-L32 -+++ https://github.com/line/lbm-sdk/blob/main/proto/lbm/staking/v1/tx.proto#L112-L121 ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/staking/v1beta1/tx.proto#L112-L121 -This service message returns a response containing the completion time of the undelegation: +This message returns a response containing the completion time of the undelegation: -+++ https://github.com/line/lbm-sdk/blob/main/proto/lbm/staking/v1/tx.proto#L123-L126 ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/staking/v1beta1/tx.proto#L123-L126 -This service message is expected to fail if: +This message is expected to fail if: - the delegation doesn't exist - the validator doesn't exist @@ -98,32 +103,34 @@ This service message is expected to fail if: - existing `UnbondingDelegation` has maximum entries as defined by `params.MaxEntries` - the `Amount` has a denomination different than one defined by `params.BondDenom` -When this service message is processed the following actions occur: +When this message is processed the following actions occur: - validator's `DelegatorShares` and the delegation's `Shares` are both reduced by the message `SharesAmount` - calculate the token worth of the shares remove that amount tokens held within the validator - with those removed tokens, if the validator is: - - `Bonded` - add them to an entry in `UnbondingDelegation` (create `UnbondingDelegation` if it doesn't exist) with a completion time a full unbonding period from the current time. Update pool shares to reduce BondedTokens and increase NotBondedTokens by token worth of the shares. - - `Unbonding` - add them to an entry in `UnbondingDelegation` (create `UnbondingDelegation` if it doesn't exist) with the same completion time as the validator (`UnbondingMinTime`). - - `Unbonded` - then send the coins the message `DelegatorAddr` + - `Bonded` - add them to an entry in `UnbondingDelegation` (create `UnbondingDelegation` if it doesn't exist) with a completion time a full unbonding period from the current time. Update pool shares to reduce BondedTokens and increase NotBondedTokens by token worth of the shares. + - `Unbonding` - add them to an entry in `UnbondingDelegation` (create `UnbondingDelegation` if it doesn't exist) with the same completion time as the validator (`UnbondingMinTime`). + - `Unbonded` - then send the coins the message `DelegatorAddr` - if there are no more `Shares` in the delegation, then the delegation object is removed from the store - - under this situation if the delegation is the validator's self-delegation then also jail the validator. + - under this situation if the delegation is the validator's self-delegation then also jail the validator. + +![Unbond sequence](../../../docs/uml/svg/unbond_sequence.svg) -## Msg/BeginRedelegate +## MsgBeginRedelegate The redelegation command allows delegators to instantly switch validators. Once the unbonding period has passed, the redelegation is automatically completed in the EndBlocker. -+++ https://github.com/line/lbm-sdk/blob/main/proto/lbm/staking/v1/tx.proto#L26-L28 ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/staking/v1beta1/tx.proto#L26-L28 -+++ https://github.com/line/lbm-sdk/blob/main/proto/lbm/staking/v1/tx.proto#L95-L105 ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/staking/v1beta1/tx.proto#L95-L105 -This service message returns a response containing the completion time of the redelegation: +This message returns a response containing the completion time of the redelegation: -+++ https://github.com/line/lbm-sdk/blob/main/proto/lbm/staking/v1/tx.proto#L107-L110 ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/staking/v1beta1/tx.proto#L107-L110 -This service message is expected to fail if: +This message is expected to fail if: - the delegation doesn't exist - the source or destination validators don't exist @@ -132,14 +139,16 @@ This service message is expected to fail if: - existing `Redelegation` has maximum entries as defined by `params.MaxEntries` - the `Amount` `Coin` has a denomination different than one defined by `params.BondDenom` -When this service message is processed the following actions occur: +When this message is processed the following actions occur: - the source validator's `DelegatorShares` and the delegations `Shares` are both reduced by the message `SharesAmount` - calculate the token worth of the shares remove that amount tokens held within the source validator. - if the source validator is: - - `Bonded` - add an entry to the `Redelegation` (create `Redelegation` if it doesn't exist) with a completion time a full unbonding period from the current time. Update pool shares to reduce BondedTokens and increase NotBondedTokens by token worth of the shares (this may be effectively reversed in the next step however). - - `Unbonding` - add an entry to the `Redelegation` (create `Redelegation` if it doesn't exist) with the same completion time as the validator (`UnbondingMinTime`). - - `Unbonded` - no action required in this step + - `Bonded` - add an entry to the `Redelegation` (create `Redelegation` if it doesn't exist) with a completion time a full unbonding period from the current time. Update pool shares to reduce BondedTokens and increase NotBondedTokens by token worth of the shares (this may be effectively reversed in the next step however). + - `Unbonding` - add an entry to the `Redelegation` (create `Redelegation` if it doesn't exist) with the same completion time as the validator (`UnbondingMinTime`). + - `Unbonded` - no action required in this step - Delegate the token worth to the destination validator, possibly moving tokens back to the bonded state. - if there are no more `Shares` in the source delegation, then the source delegation object is removed from the store - - under this situation if the delegation is the validator's self-delegation then also jail the validator. + - under this situation if the delegation is the validator's self-delegation then also jail the validator. + +![Begin redelegation sequence](../../../docs/uml/svg/begin_redelegation_sequence.svg) diff --git a/x/staking/spec/05_end_block.md b/x/staking/spec/05_end_block.md index 769b986b7c..c097579e09 100644 --- a/x/staking/spec/05_end_block.md +++ b/x/staking/spec/05_end_block.md @@ -18,9 +18,9 @@ consensus layer. Operations are as following: - the new validator set is taken as the top `params.MaxValidators` number of validators retrieved from the `ValidatorsByPower` index - the previous validator set is compared with the new validator set: - - missing validators begin unbonding and their `Tokens` are transferred from the + - missing validators begin unbonding and their `Tokens` are transferred from the `BondedPool` to the `NotBondedPool` `ModuleAccount` - - new validators are instantly bonded and their `Tokens` are transferred from the + - new validators are instantly bonded and their `Tokens` are transferred from the `NotBondedPool` to the `BondedPool` `ModuleAccount` In all cases, any validators leaving or entering the bonded validator set or diff --git a/x/staking/spec/06_hooks.md b/x/staking/spec/06_hooks.md index 2eac2d4a17..d4c3228eca 100644 --- a/x/staking/spec/06_hooks.md +++ b/x/staking/spec/06_hooks.md @@ -7,21 +7,21 @@ order: 5 Other modules may register operations to execute when a certain event has occurred within staking. These events can be registered to execute either right `Before` or `After` the staking event (as per the hook name). The -following hooks can registered with staking: +following hooks can registered with staking: - - `AfterValidatorCreated(Context, ValAddress)` - - called when a validator is created - - `BeforeValidatorModified(Context, ValAddress)` - - called when a validator's state is changed - - `AfterValidatorRemoved(Context, ConsAddress, ValAddress)` - - called when a validator is deleted - - `AfterValidatorBonded(Context, ConsAddress, ValAddress)` - - called when a validator is bonded - - `AfterValidatorBeginUnbonding(Context, ConsAddress, ValAddress)` - - called when a validator begins unbonding - - `BeforeDelegationCreated(Context, AccAddress, ValAddress)` - - called when a delegation is created - - `BeforeDelegationSharesModified(Context, AccAddress, ValAddress)` - - called when a delegation's shares are modified - - `BeforeDelegationRemoved(Context, AccAddress, ValAddress)` - - called when a delegation is removed +- `AfterValidatorCreated(Context, ValAddress)` + - called when a validator is created +- `BeforeValidatorModified(Context, ValAddress)` + - called when a validator's state is changed +- `AfterValidatorRemoved(Context, ConsAddress, ValAddress)` + - called when a validator is deleted +- `AfterValidatorBonded(Context, ConsAddress, ValAddress)` + - called when a validator is bonded +- `AfterValidatorBeginUnbonding(Context, ConsAddress, ValAddress)` + - called when a validator begins unbonding +- `BeforeDelegationCreated(Context, AccAddress, ValAddress)` + - called when a delegation is created +- `BeforeDelegationSharesModified(Context, AccAddress, ValAddress)` + - called when a delegation's shares are modified +- `BeforeDelegationRemoved(Context, AccAddress, ValAddress)` + - called when a delegation is removed diff --git a/x/staking/spec/07_events.md b/x/staking/spec/07_events.md index 660319b3c1..f219fa2ca4 100644 --- a/x/staking/spec/07_events.md +++ b/x/staking/spec/07_events.md @@ -18,9 +18,9 @@ The staking module emits the following events: | complete_redelegation | destination_validator | {dstValidatorAddress} | | complete_redelegation | delegator | {delegatorAddress} | -## Service Messages +## Msg's -### Msg/CreateValidator +### MsgCreateValidator | Type | Attribute Key | Attribute Value | | ---------------- | ------------- | ------------------ | @@ -30,7 +30,7 @@ The staking module emits the following events: | message | action | create_validator | | message | sender | {senderAddress} | -### Msg/EditValidator +### MsgEditValidator | Type | Attribute Key | Attribute Value | | -------------- | ------------------- | ------------------- | @@ -40,7 +40,7 @@ The staking module emits the following events: | message | action | edit_validator | | message | sender | {senderAddress} | -### Msg/Delegate +### MsgDelegate | Type | Attribute Key | Attribute Value | | -------- | ------------- | ------------------ | @@ -50,7 +50,7 @@ The staking module emits the following events: | message | action | delegate | | message | sender | {senderAddress} | -### Msg/Undelegate +### MsgUndelegate | Type | Attribute Key | Attribute Value | | ------- | ------------------- | ------------------ | @@ -63,7 +63,7 @@ The staking module emits the following events: - [0] Time is formatted in the RFC3339 standard -### Msg/BeginRedelegate +### MsgBeginRedelegate | Type | Attribute Key | Attribute Value | | ---------- | --------------------- | --------------------- | diff --git a/x/staking/spec/08_params.md b/x/staking/spec/08_params.md index 3d87879e18..a7f2c59263 100644 --- a/x/staking/spec/08_params.md +++ b/x/staking/spec/08_params.md @@ -12,4 +12,5 @@ The staking module contains the following parameters: | MaxValidators | uint16 | 100 | | KeyMaxEntries | uint16 | 7 | | HistoricalEntries | uint16 | 3 | -| BondDenom | string | "uatom" | +| BondDenom | string | "stake" | +| PowerReduction | string | "1000000" | diff --git a/x/staking/spec/09_client.md b/x/staking/spec/09_client.md new file mode 100644 index 0000000000..608705352c --- /dev/null +++ b/x/staking/spec/09_client.md @@ -0,0 +1,2088 @@ + + +# Client + +## CLI + +A user can query and interact with the `staking` module using the CLI. + +### Query + +The `query` commands allows users to query `staking` state. + +```bash +simd query staking --help +``` + +#### delegation + +The `delegation` command allows users to query delegations for an individual delegator on an individual validator. + +Usage: + +```bash +simd query staking delegation [delegator-addr] [validator-addr] [flags] +``` + +Example: + +```bash +simd query staking delegation cosmos1gghjut3ccd8ay0zduzj64hwre2fxs9ld75ru9p cosmosvaloper1gghjut3ccd8ay0zduzj64hwre2fxs9ldmqhffj +``` + +Example Output: + +```bash +balance: + amount: "10000000000" + denom: stake +delegation: + delegator_address: cosmos1gghjut3ccd8ay0zduzj64hwre2fxs9ld75ru9p + shares: "10000000000.000000000000000000" + validator_address: cosmosvaloper1gghjut3ccd8ay0zduzj64hwre2fxs9ldmqhffj +``` + +#### delegations + +The `delegations` command allows users to query delegations for an individual delegator on all validators. + +Usage: + +```bash +simd query staking delegations [delegator-addr] [flags] +``` + +Example: + +```bash +simd query staking delegations cosmos1gghjut3ccd8ay0zduzj64hwre2fxs9ld75ru9p +``` + +Example Output: + +```bash +delegation_responses: +- balance: + amount: "10000000000" + denom: stake + delegation: + delegator_address: cosmos1gghjut3ccd8ay0zduzj64hwre2fxs9ld75ru9p + shares: "10000000000.000000000000000000" + validator_address: cosmosvaloper1gghjut3ccd8ay0zduzj64hwre2fxs9ldmqhffj +- balance: + amount: "10000000000" + denom: stake + delegation: + delegator_address: cosmos1gghjut3ccd8ay0zduzj64hwre2fxs9ld75ru9p + shares: "10000000000.000000000000000000" + validator_address: cosmosvaloper1x20lytyf6zkcrv5edpkfkn8sz578qg5sqfyqnp +pagination: + next_key: null + total: "0" +``` + +#### delegations-to + +The `delegations-to` command allows users to query delegations on an individual validator. + +Usage: + +```bash +simd query staking delegations-to [validator-addr] [flags] +``` + +Example: + +```bash +simd query staking delegations-to cosmosvaloper1gghjut3ccd8ay0zduzj64hwre2fxs9ldmqhffj +``` + +Example Output: + +```bash +- balance: + amount: "504000000" + denom: stake + delegation: + delegator_address: cosmos1q2qwwynhv8kh3lu5fkeex4awau9x8fwt45f5cp + shares: "504000000.000000000000000000" + validator_address: cosmosvaloper1gghjut3ccd8ay0zduzj64hwre2fxs9ldmqhffj +- balance: + amount: "78125000000" + denom: uixo + delegation: + delegator_address: cosmos1qvppl3479hw4clahe0kwdlfvf8uvjtcd99m2ca + shares: "78125000000.000000000000000000" + validator_address: cosmosvaloper1gghjut3ccd8ay0zduzj64hwre2fxs9ldmqhffj +pagination: + next_key: null + total: "0" +``` + +#### historical-info + +The `historical-info` command allows users to query historical information at given height. + +Usage: + +```bash +simd query staking historical-info [height] [flags] +``` + +Example: + +```bash +simd query staking historical-info 10 +``` + +Example Output: + +```bash +header: + app_hash: Lbx8cXpI868wz8sgp4qPYVrlaKjevR5WP/IjUxwp3oo= + chain_id: testnet + consensus_hash: BICRvH3cKD93v7+R1zxE2ljD34qcvIZ0Bdi389qtoi8= + data_hash: 47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU= + evidence_hash: 47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU= + height: "10" + last_block_id: + hash: RFbkpu6pWfSThXxKKl6EZVDnBSm16+U0l0xVjTX08Fk= + part_set_header: + hash: vpIvXD4rxD5GM4MXGz0Sad9I7//iVYLzZsEU4BVgWIU= + total: 1 + last_commit_hash: Ne4uXyx4QtNp4Zx89kf9UK7oG9QVbdB6e7ZwZkhy8K0= + last_results_hash: 47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU= + next_validators_hash: nGBgKeWBjoxeKFti00CxHsnULORgKY4LiuQwBuUrhCs= + proposer_address: mMEP2c2IRPLr99LedSRtBg9eONM= + time: "2021-10-01T06:00:49.785790894Z" + validators_hash: nGBgKeWBjoxeKFti00CxHsnULORgKY4LiuQwBuUrhCs= + version: + app: "0" + block: "11" +valset: +- commission: + commission_rates: + max_change_rate: "0.010000000000000000" + max_rate: "0.200000000000000000" + rate: "0.100000000000000000" + update_time: "2021-10-01T05:52:50.380144238Z" + consensus_pubkey: + '@type': /cosmos.crypto.ed25519.PubKey + key: Auxs3865HpB/EfssYOzfqNhEJjzys2Fo6jD5B8tPgC8= + delegator_shares: "10000000.000000000000000000" + description: + details: "" + identity: "" + moniker: myvalidator + security_contact: "" + website: "" + jailed: false + min_self_delegation: "1" + operator_address: cosmosvaloper1rne8lgs98p0jqe82sgt0qr4rdn4hgvmgp9ggcc + status: BOND_STATUS_BONDED + tokens: "10000000" + unbonding_height: "0" + unbonding_time: "1970-01-01T00:00:00Z" +``` + +#### params + +The `params` command allows users to query values set as staking parameters. + +Usage: + +```bash +simd query staking params [flags] +``` + +Example: + +```bash +simd query staking params +``` + +Example Output: + +```bash +bond_denom: stake +historical_entries: 10000 +max_entries: 7 +max_validators: 50 +unbonding_time: 1814400s +``` + +#### pool + +The `pool` command allows users to query values for amounts stored in the staking pool. + +Usage: + +```bash +simd q staking pool [flags] +``` + +Example: + +```bash +simd q staking pool +``` + +Example Output: + +```bash +bonded_tokens: "10000000" +not_bonded_tokens: "0" +``` + +#### redelegation + +The `redelegation` command allows users to query a redelegation record based on delegator and a source and destination validator address. + +Usage: + +```bash +simd query staking redelegation [delegator-addr] [src-validator-addr] [dst-validator-addr] [flags] +``` + +Example: + +```bash +simd query staking redelegation cosmos1gghjut3ccd8ay0zduzj64hwre2fxs9ld75ru9p cosmosvaloper1l2rsakp388kuv9k8qzq6lrm9taddae7fpx59wm cosmosvaloper1gghjut3ccd8ay0zduzj64hwre2fxs9ldmqhffj +``` + +Example Output: + +```bash +pagination: null +redelegation_responses: +- entries: + - balance: "50000000" + redelegation_entry: + completion_time: "2021-10-24T20:33:21.960084845Z" + creation_height: 2.382847e+06 + initial_balance: "50000000" + shares_dst: "50000000.000000000000000000" + - balance: "5000000000" + redelegation_entry: + completion_time: "2021-10-25T21:33:54.446846862Z" + creation_height: 2.397271e+06 + initial_balance: "5000000000" + shares_dst: "5000000000.000000000000000000" + redelegation: + delegator_address: cosmos1gghjut3ccd8ay0zduzj64hwre2fxs9ld75ru9p + entries: null + validator_dst_address: cosmosvaloper1l2rsakp388kuv9k8qzq6lrm9taddae7fpx59wm + validator_src_address: cosmosvaloper1l2rsakp388kuv9k8qzq6lrm9taddae7fpx59wm +``` + +#### redelegations + +The `redelegations` command allows users to query all redelegation records for an individual delegator. + +Usage: + +```bash +simd query staking redelegations [delegator-addr] [flags] +``` + +Example: + +```bash +simd query staking redelegation cosmos1gghjut3ccd8ay0zduzj64hwre2fxs9ld75ru9p +``` + +Example Output: + +```bash +pagination: + next_key: null + total: "0" +redelegation_responses: +- entries: + - balance: "50000000" + redelegation_entry: + completion_time: "2021-10-24T20:33:21.960084845Z" + creation_height: 2.382847e+06 + initial_balance: "50000000" + shares_dst: "50000000.000000000000000000" + - balance: "5000000000" + redelegation_entry: + completion_time: "2021-10-25T21:33:54.446846862Z" + creation_height: 2.397271e+06 + initial_balance: "5000000000" + shares_dst: "5000000000.000000000000000000" + redelegation: + delegator_address: cosmos1gghjut3ccd8ay0zduzj64hwre2fxs9ld75ru9p + entries: null + validator_dst_address: cosmosvaloper1uccl5ugxrm7vqlzwqr04pjd320d2fz0z3hc6vm + validator_src_address: cosmosvaloper1zppjyal5emta5cquje8ndkpz0rs046m7zqxrpp +- entries: + - balance: "562770000000" + redelegation_entry: + completion_time: "2021-10-25T21:42:07.336911677Z" + creation_height: 2.39735e+06 + initial_balance: "562770000000" + shares_dst: "562770000000.000000000000000000" + redelegation: + delegator_address: cosmos1gghjut3ccd8ay0zduzj64hwre2fxs9ld75ru9p + entries: null + validator_dst_address: cosmosvaloper1uccl5ugxrm7vqlzwqr04pjd320d2fz0z3hc6vm + validator_src_address: cosmosvaloper1zppjyal5emta5cquje8ndkpz0rs046m7zqxrpp +``` + +#### redelegations-from + +The `redelegations-from` command allows users to query delegations that are redelegating _from_ a validator. + +Usage: + +```bash +simd query staking redelegations-from [validator-addr] [flags] +``` + +Example: + +```bash +simd query staking redelegations-from cosmosvaloper1y4rzzrgl66eyhzt6gse2k7ej3zgwmngeleucjy +``` + +Example Output: + +```bash +pagination: + next_key: null + total: "0" +redelegation_responses: +- entries: + - balance: "50000000" + redelegation_entry: + completion_time: "2021-10-24T20:33:21.960084845Z" + creation_height: 2.382847e+06 + initial_balance: "50000000" + shares_dst: "50000000.000000000000000000" + - balance: "5000000000" + redelegation_entry: + completion_time: "2021-10-25T21:33:54.446846862Z" + creation_height: 2.397271e+06 + initial_balance: "5000000000" + shares_dst: "5000000000.000000000000000000" + redelegation: + delegator_address: cosmos1pm6e78p4pgn0da365plzl4t56pxy8hwtqp2mph + entries: null + validator_dst_address: cosmosvaloper1uccl5ugxrm7vqlzwqr04pjd320d2fz0z3hc6vm + validator_src_address: cosmosvaloper1y4rzzrgl66eyhzt6gse2k7ej3zgwmngeleucjy +- entries: + - balance: "221000000" + redelegation_entry: + completion_time: "2021-10-05T21:05:45.669420544Z" + creation_height: 2.120693e+06 + initial_balance: "221000000" + shares_dst: "221000000.000000000000000000" + redelegation: + delegator_address: cosmos1zqv8qxy2zgn4c58fz8jt8jmhs3d0attcussrf6 + entries: null + validator_dst_address: cosmosvaloper10mseqwnwtjaqfrwwp2nyrruwmjp6u5jhah4c3y + validator_src_address: cosmosvaloper1y4rzzrgl66eyhzt6gse2k7ej3zgwmngeleucjy +``` + +#### unbonding-delegation + +The `unbonding-delegation` command allows users to query unbonding delegations for an individual delegator on an individual validator. + +Usage: + +```bash +simd query staking unbonding-delegation [delegator-addr] [validator-addr] [flags] +``` + +Example: + +```bash +simd query staking unbonding-delegation cosmos1gghjut3ccd8ay0zduzj64hwre2fxs9ld75ru9p cosmosvaloper1gghjut3ccd8ay0zduzj64hwre2fxs9ldmqhffj +``` + +Example Output: + +```bash +delegator_address: cosmos1gghjut3ccd8ay0zduzj64hwre2fxs9ld75ru9p +entries: +- balance: "52000000" + completion_time: "2021-11-02T11:35:55.391594709Z" + creation_height: "55078" + initial_balance: "52000000" +validator_address: cosmosvaloper1gghjut3ccd8ay0zduzj64hwre2fxs9ldmqhffj +``` + +#### unbonding-delegations + +The `unbonding-delegations` command allows users to query all unbonding-delegations records for one delegator. + +Usage: + +```bash +simd query staking unbonding-delegations [delegator-addr] [flags] +``` + +Example: + +```bash +simd query staking unbonding-delegations cosmos1gghjut3ccd8ay0zduzj64hwre2fxs9ld75ru9p +``` + +Example Output: + +```bash +pagination: + next_key: null + total: "0" +unbonding_responses: +- delegator_address: cosmos1gghjut3ccd8ay0zduzj64hwre2fxs9ld75ru9p + entries: + - balance: "52000000" + completion_time: "2021-11-02T11:35:55.391594709Z" + creation_height: "55078" + initial_balance: "52000000" + validator_address: cosmosvaloper1t8ehvswxjfn3ejzkjtntcyrqwvmvuknzmvtaaa + +``` + +#### unbonding-delegations-from + +The `unbonding-delegations-from` command allows users to query delegations that are unbonding _from_ a validator. + +Usage: + +```bash +simd query staking unbonding-delegations-from [validator-addr] [flags] +``` + +Example: + +```bash +simd query staking unbonding-delegations-from cosmosvaloper1gghjut3ccd8ay0zduzj64hwre2fxs9ldmqhffj +``` + +Example Output: + +```bash +pagination: + next_key: null + total: "0" +unbonding_responses: +- delegator_address: cosmos1qqq9txnw4c77sdvzx0tkedsafl5s3vk7hn53fn + entries: + - balance: "150000000" + completion_time: "2021-11-01T21:41:13.098141574Z" + creation_height: "46823" + initial_balance: "150000000" + validator_address: cosmosvaloper1gghjut3ccd8ay0zduzj64hwre2fxs9ldmqhffj +- delegator_address: cosmos1peteje73eklqau66mr7h7rmewmt2vt99y24f5z + entries: + - balance: "24000000" + completion_time: "2021-10-31T02:57:18.192280361Z" + creation_height: "21516" + initial_balance: "24000000" + validator_address: cosmosvaloper1gghjut3ccd8ay0zduzj64hwre2fxs9ldmqhffj +``` + +#### validator + +The `validator` command allows users to query details about an individual validator. + +Usage: + +```bash +simd query staking validator [validator-addr] [flags] +``` + +Example: + +```bash +simd query staking validator cosmosvaloper1gghjut3ccd8ay0zduzj64hwre2fxs9ldmqhffj +``` + +Example Output: + +```bash +commission: + commission_rates: + max_change_rate: "0.020000000000000000" + max_rate: "0.200000000000000000" + rate: "0.050000000000000000" + update_time: "2021-10-01T19:24:52.663191049Z" +consensus_pubkey: + '@type': /cosmos.crypto.ed25519.PubKey + key: sIiexdJdYWn27+7iUHQJDnkp63gq/rzUq1Y+fxoGjXc= +delegator_shares: "32948270000.000000000000000000" +description: + details: Witval is the validator arm from Vitwit. Vitwit is into software consulting + and services business since 2015. We are working closely with Cosmos ecosystem + since 2018. We are also building tools for the ecosystem, Aneka is our explorer + for the cosmos ecosystem. + identity: 51468B615127273A + moniker: Witval + security_contact: "" + website: "" +jailed: false +min_self_delegation: "1" +operator_address: cosmosvaloper1gghjut3ccd8ay0zduzj64hwre2fxs9ldmqhffj +status: BOND_STATUS_BONDED +tokens: "32948270000" +unbonding_height: "0" +unbonding_time: "1970-01-01T00:00:00Z" +``` + +#### validators + +The `validators` command allows users to query details about all validators on a network. + +Usage: + +```bash +simd query staking validators [flags] +``` + +Example: + +```bash +simd query staking validators +``` + +Example Output: + +```bash +pagination: + next_key: FPTi7TKAjN63QqZh+BaXn6gBmD5/ + total: "0" +validators: +commission: + commission_rates: + max_change_rate: "0.020000000000000000" + max_rate: "0.200000000000000000" + rate: "0.050000000000000000" + update_time: "2021-10-01T19:24:52.663191049Z" +consensus_pubkey: + '@type': /cosmos.crypto.ed25519.PubKey + key: sIiexdJdYWn27+7iUHQJDnkp63gq/rzUq1Y+fxoGjXc= +delegator_shares: "32948270000.000000000000000000" +description: + details: Witval is the validator arm from Vitwit. Vitwit is into software consulting + and services business since 2015. We are working closely with Cosmos ecosystem + since 2018. We are also building tools for the ecosystem, Aneka is our explorer + for the cosmos ecosystem. + identity: 51468B615127273A + moniker: Witval + security_contact: "" + website: "" + jailed: false + min_self_delegation: "1" + operator_address: cosmosvaloper1gghjut3ccd8ay0zduzj64hwre2fxs9ldmqhffj + status: BOND_STATUS_BONDED + tokens: "32948270000" + unbonding_height: "0" + unbonding_time: "1970-01-01T00:00:00Z" +- commission: + commission_rates: + max_change_rate: "0.100000000000000000" + max_rate: "0.200000000000000000" + rate: "0.050000000000000000" + update_time: "2021-10-04T18:02:21.446645619Z" + consensus_pubkey: + '@type': /cosmos.crypto.ed25519.PubKey + key: GDNpuKDmCg9GnhnsiU4fCWktuGUemjNfvpCZiqoRIYA= + delegator_shares: "559343421.000000000000000000" + description: + details: Noderunners is a professional validator in POS networks. We have a huge + node running experience, reliable soft and hardware. Our commissions are always + low, our support to delegators is always full. Stake with us and start receiving + your Cosmos rewards now! + identity: 812E82D12FEA3493 + moniker: Noderunners + security_contact: info@noderunners.biz + website: http://noderunners.biz + jailed: false + min_self_delegation: "1" + operator_address: cosmosvaloper1q5ku90atkhktze83j9xjaks2p7uruag5zp6wt7 + status: BOND_STATUS_BONDED + tokens: "559343421" + unbonding_height: "0" + unbonding_time: "1970-01-01T00:00:00Z" +``` + +### Transactions + +The `tx` commands allows users to interact with the `staking` module. + +```bash +simd tx staking --help +``` + +#### create-validator + +The command `create-validator` allows users to create new validator initialized with a self-delegation to it. + +Usage: + +```bash +simd tx staking create-validator [flags] +``` + +Example: + +```bash +simd tx staking create-validator \ + --amount=1000000stake \ + --pubkey=$(simd tendermint show-validator) \ + --moniker="my-moniker" \ + --website="https://myweb.site" \ + --details="description of your validator" \ + --chain-id="name_of_chain_id" \ + --commission-rate="0.10" \ + --commission-max-rate="0.20" \ + --commission-max-change-rate="0.01" \ + --min-self-delegation="1" \ + --gas="auto" \ + --gas-adjustment="1.2" \ + --gas-prices="0.025stake" \ + --from=mykey +``` + +#### delegate + +The command `delegate` allows users to delegate liquid tokens to a validator. + +Usage: + +```bash +simd tx staking delegate [validator-addr] [amount] [flags] +``` + +Example: + +```bash +simd tx staking delegate cosmosvaloper1l2rsakp388kuv9k8qzq6lrm9taddae7fpx59wm 1000stake --from mykey +``` + +#### edit-validator + +The command `edit-validator` allows users to edit an existing validator account. + +Usage: + +```bash +simd tx staking edit-validator [flags] +``` + +Example: + +```bash +simd tx staking edit-validator --moniker "new_moniker_name" --website "new_webiste_url" --from mykey +``` + +#### redelegate + +The command `redelegate` allows users to redelegate illiquid tokens from one validator to another. + +Usage: + +```bash +simd tx staking redelegate [src-validator-addr] [dst-validator-addr] [amount] [flags] +``` + +Example: + +```bash +simd tx staking redelegate cosmosvaloper1gghjut3ccd8ay0zduzj64hwre2fxs9ldmqhffj cosmosvaloper1l2rsakp388kuv9k8qzq6lrm9taddae7fpx59wm 100stake --from mykey +``` + +#### unbond + +The command `unbond` allows users to unbond shares from a validator. + +Usage: + +```bash +simd tx staking unbond [validator-addr] [amount] [flags] +``` + +Example: + +```bash +simd tx staking unbond cosmosvaloper1gghjut3ccd8ay0zduzj64hwre2fxs9ldmqhffj 100stake --from mykey +``` + +## gRPC + +A user can query the `staking` module using gRPC endpoints. + +### Validators + +The `Validators` endpoint queries all validators that match the given status. + +```bash +cosmos.staking.v1beta1.Query/Validators +``` + +Example: + +```bash +grpcurl -plaintext localhost:9090 cosmos.staking.v1beta1.Query/Validators +``` + +Example Output: + +```bash +{ + "validators": [ + { + "operatorAddress": "cosmosvaloper1rne8lgs98p0jqe82sgt0qr4rdn4hgvmgp9ggcc", + "consensusPubkey": {"@type":"/cosmos.crypto.ed25519.PubKey","key":"Auxs3865HpB/EfssYOzfqNhEJjzys2Fo6jD5B8tPgC8="}, + "status": "BOND_STATUS_BONDED", + "tokens": "10000000", + "delegatorShares": "10000000000000000000000000", + "description": { + "moniker": "myvalidator" + }, + "unbondingTime": "1970-01-01T00:00:00Z", + "commission": { + "commissionRates": { + "rate": "100000000000000000", + "maxRate": "200000000000000000", + "maxChangeRate": "10000000000000000" + }, + "updateTime": "2021-10-01T05:52:50.380144238Z" + }, + "minSelfDelegation": "1" + } + ], + "pagination": { + "total": "1" + } +} +``` + +### Validator + +The `Validator` endpoint queries validator information for given validator address. + +```bash +cosmos.staking.v1beta1.Query/Validator +``` + +Example: + +```bash +grpcurl -plaintext -d '{"validator_addr":"cosmosvaloper1rne8lgs98p0jqe82sgt0qr4rdn4hgvmgp9ggcc"}' \ +localhost:9090 cosmos.staking.v1beta1.Query/Validator +``` + +Example Output: + +```bash +{ + "validator": { + "operatorAddress": "cosmosvaloper1rne8lgs98p0jqe82sgt0qr4rdn4hgvmgp9ggcc", + "consensusPubkey": {"@type":"/cosmos.crypto.ed25519.PubKey","key":"Auxs3865HpB/EfssYOzfqNhEJjzys2Fo6jD5B8tPgC8="}, + "status": "BOND_STATUS_BONDED", + "tokens": "10000000", + "delegatorShares": "10000000000000000000000000", + "description": { + "moniker": "myvalidator" + }, + "unbondingTime": "1970-01-01T00:00:00Z", + "commission": { + "commissionRates": { + "rate": "100000000000000000", + "maxRate": "200000000000000000", + "maxChangeRate": "10000000000000000" + }, + "updateTime": "2021-10-01T05:52:50.380144238Z" + }, + "minSelfDelegation": "1" + } +} +``` + +### ValidatorDelegations + +The `ValidatorDelegations` endpoint queries delegate information for given validator. + +```bash +cosmos.staking.v1beta1.Query/ValidatorDelegations +``` + +Example: + +```bash +grpcurl -plaintext -d '{"validator_addr":"cosmosvaloper1rne8lgs98p0jqe82sgt0qr4rdn4hgvmgp9ggcc"}' \ +localhost:9090 cosmos.staking.v1beta1.Query/ValidatorDelegations +``` + +Example Output: + +```bash +{ + "delegationResponses": [ + { + "delegation": { + "delegatorAddress": "cosmos1rne8lgs98p0jqe82sgt0qr4rdn4hgvmgy3ua5t", + "validatorAddress": "cosmosvaloper1rne8lgs98p0jqe82sgt0qr4rdn4hgvmgp9ggcc", + "shares": "10000000000000000000000000" + }, + "balance": { + "denom": "stake", + "amount": "10000000" + } + } + ], + "pagination": { + "total": "1" + } +} +``` + +### ValidatorUnbondingDelegations + +The `ValidatorUnbondingDelegations` endpoint queries delegate information for given validator. + +```bash +cosmos.staking.v1beta1.Query/ValidatorUnbondingDelegations +``` + +Example: + +```bash +grpcurl -plaintext -d '{"validator_addr":"cosmosvaloper1rne8lgs98p0jqe82sgt0qr4rdn4hgvmgp9ggcc"}' \ +localhost:9090 cosmos.staking.v1beta1.Query/ValidatorUnbondingDelegations +``` + +Example Output: + +```bash +{ + "unbonding_responses": [ + { + "delegator_address": "cosmos1z3pzzw84d6xn00pw9dy3yapqypfde7vg6965fy", + "validator_address": "cosmosvaloper1rne8lgs98p0jqe82sgt0qr4rdn4hgvmgp9ggcc", + "entries": [ + { + "creation_height": "25325", + "completion_time": "2021-10-31T09:24:36.797320636Z", + "initial_balance": "20000000", + "balance": "20000000" + } + ] + }, + { + "delegator_address": "cosmos1y8nyfvmqh50p6ldpzljk3yrglppdv3t8phju77", + "validator_address": "cosmosvaloper1rne8lgs98p0jqe82sgt0qr4rdn4hgvmgp9ggcc", + "entries": [ + { + "creation_height": "13100", + "completion_time": "2021-10-30T12:53:02.272266791Z", + "initial_balance": "1000000", + "balance": "1000000" + } + ] + }, + ], + "pagination": { + "next_key": null, + "total": "8" + } +} +``` + +### Delegation + +The `Delegation` endpoint queries delegate information for given validator delegator pair. + +```bash +cosmos.staking.v1beta1.Query/Delegation +``` + +Example: + +```bash +grpcurl -plaintext \ +-d '{"delegator_addr": "cosmos1y8nyfvmqh50p6ldpzljk3yrglppdv3t8phju77", validator_addr":"cosmosvaloper1rne8lgs98p0jqe82sgt0qr4rdn4hgvmgp9ggcc"}' \ +localhost:9090 cosmos.staking.v1beta1.Query/Delegation +``` + +Example Output: + +```bash +{ + "delegation_response": + { + "delegation": + { + "delegator_address":"cosmos1y8nyfvmqh50p6ldpzljk3yrglppdv3t8phju77", + "validator_address":"cosmosvaloper1rne8lgs98p0jqe82sgt0qr4rdn4hgvmgp9ggcc", + "shares":"25083119936.000000000000000000" + }, + "balance": + { + "denom":"stake", + "amount":"25083119936" + } + } +} +``` + +### UnbondingDelegation + +The `UnbondingDelegation` endpoint queries unbonding information for given validator delegator. + +```bash +cosmos.staking.v1beta1.Query/UnbondingDelegation +``` + +Example: + +```bash +grpcurl -plaintext \ +-d '{"delegator_addr": "cosmos1y8nyfvmqh50p6ldpzljk3yrglppdv3t8phju77", validator_addr":"cosmosvaloper1rne8lgs98p0jqe82sgt0qr4rdn4hgvmgp9ggcc"}' \ +localhost:9090 cosmos.staking.v1beta1.Query/UnbondingDelegation +``` + +Example Output: + +```bash +{ + "unbond": { + "delegator_address": "cosmos1y8nyfvmqh50p6ldpzljk3yrglppdv3t8phju77", + "validator_address": "cosmosvaloper1rne8lgs98p0jqe82sgt0qr4rdn4hgvmgp9ggcc", + "entries": [ + { + "creation_height": "136984", + "completion_time": "2021-11-08T05:38:47.505593891Z", + "initial_balance": "400000000", + "balance": "400000000" + }, + { + "creation_height": "137005", + "completion_time": "2021-11-08T05:40:53.526196312Z", + "initial_balance": "385000000", + "balance": "385000000" + } + ] + } +} +``` + +### DelegatorDelegations + +The `DelegatorDelegations` endpoint queries all delegations of a given delegator address. + +```bash +cosmos.staking.v1beta1.Query/DelegatorDelegations +``` + +Example: + +```bash +grpcurl -plaintext \ +-d '{"delegator_addr": "cosmos1y8nyfvmqh50p6ldpzljk3yrglppdv3t8phju77"}' \ +localhost:9090 cosmos.staking.v1beta1.Query/DelegatorDelegations +``` + +Example Output: + +```bash +{ + "delegation_responses": [ + {"delegation":{"delegator_address":"cosmos1y8nyfvmqh50p6ldpzljk3yrglppdv3t8phju77","validator_address":"cosmosvaloper1eh5mwu044gd5ntkkc2xgfg8247mgc56fww3vc8","shares":"25083339023.000000000000000000"},"balance":{"denom":"stake","amount":"25083339023"}} + ], + "pagination": { + "next_key": null, + "total": "1" + } +} +``` + +### DelegatorUnbondingDelegations + +The `DelegatorUnbondingDelegations` endpoint queries all unbonding delegations of a given delegator address. + +```bash +cosmos.staking.v1beta1.Query/DelegatorUnbondingDelegations +``` + +Example: + +```bash +grpcurl -plaintext \ +-d '{"delegator_addr": "cosmos1y8nyfvmqh50p6ldpzljk3yrglppdv3t8phju77"}' \ +localhost:9090 cosmos.staking.v1beta1.Query/DelegatorUnbondingDelegations +``` + +Example Output: + +```bash +{ + "unbonding_responses": [ + { + "delegator_address": "cosmos1y8nyfvmqh50p6ldpzljk3yrglppdv3t8phju77", + "validator_address": "cosmosvaloper1sjllsnramtg3ewxqwwrwjxfgc4n4ef9uxyejze", + "entries": [ + { + "creation_height": "136984", + "completion_time": "2021-11-08T05:38:47.505593891Z", + "initial_balance": "400000000", + "balance": "400000000" + }, + { + "creation_height": "137005", + "completion_time": "2021-11-08T05:40:53.526196312Z", + "initial_balance": "385000000", + "balance": "385000000" + } + ] + } + ], + "pagination": { + "next_key": null, + "total": "1" + } +} +``` + +### Redelegations + +The `Redelegations` endpoint queries redelegations of given address. + +```bash +cosmos.staking.v1beta1.Query/Redelegations +``` + +Example: + +```bash +grpcurl -plaintext \ +-d '{"delegator_addr": "cosmos1ld5p7hn43yuh8ht28gm9pfjgj2fctujp2tgwvf", "src_validator_addr" : "cosmosvaloper1j7euyj85fv2jugejrktj540emh9353ltgppc3g", "dst_validator_addr" : "cosmosvaloper1yy3tnegzmkdcm7czzcy3flw5z0zyr9vkkxrfse"}' \ +localhost:9090 cosmos.staking.v1beta1.Query/Redelegations +``` + +Example Output: + +```bash +{ + "redelegation_responses": [ + { + "redelegation": { + "delegator_address": "cosmos1ld5p7hn43yuh8ht28gm9pfjgj2fctujp2tgwvf", + "validator_src_address": "cosmosvaloper1j7euyj85fv2jugejrktj540emh9353ltgppc3g", + "validator_dst_address": "cosmosvaloper1yy3tnegzmkdcm7czzcy3flw5z0zyr9vkkxrfse", + "entries": null + }, + "entries": [ + { + "redelegation_entry": { + "creation_height": 135932, + "completion_time": "2021-11-08T03:52:55.299147901Z", + "initial_balance": "2900000", + "shares_dst": "2900000.000000000000000000" + }, + "balance": "2900000" + } + ] + } + ], + "pagination": null +} +``` + +### DelegatorValidators + +The `DelegatorValidators` endpoint queries all validators information for given delegator. + +```bash +cosmos.staking.v1beta1.Query/DelegatorValidators +``` + +Example: + +```bash +grpcurl -plaintext \ +-d '{"delegator_addr": "cosmos1ld5p7hn43yuh8ht28gm9pfjgj2fctujp2tgwvf"}' \ +localhost:9090 cosmos.staking.v1beta1.Query/DelegatorValidators +``` + +Example Output: + +```bash +{ + "validators": [ + { + "operator_address": "cosmosvaloper1eh5mwu044gd5ntkkc2xgfg8247mgc56fww3vc8", + "consensus_pubkey": { + "@type": "/cosmos.crypto.ed25519.PubKey", + "key": "UPwHWxH1zHJWGOa/m6JB3f5YjHMvPQPkVbDqqi+U7Uw=" + }, + "jailed": false, + "status": "BOND_STATUS_BONDED", + "tokens": "347260647559", + "delegator_shares": "347260647559.000000000000000000", + "description": { + "moniker": "BouBouNode", + "identity": "", + "website": "https://boubounode.com", + "security_contact": "", + "details": "AI-based Validator. #1 AI Validator on Game of Stakes. Fairly priced. Don't trust (humans), verify. Made with BouBou love." + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.061000000000000000", + "max_rate": "0.300000000000000000", + "max_change_rate": "0.150000000000000000" + }, + "update_time": "2021-10-01T15:00:00Z" + }, + "min_self_delegation": "1" + } + ], + "pagination": { + "next_key": null, + "total": "1" + } +} +``` + +### DelegatorValidator + +The `DelegatorValidator` endpoint queries validator information for given delegator validator + +```bash +cosmos.staking.v1beta1.Query/DelegatorValidator +``` + +Example: + +```bash +grpcurl -plaintext \ +-d '{"delegator_addr": "cosmos1eh5mwu044gd5ntkkc2xgfg8247mgc56f3n8rr7", "validator_addr": "cosmosvaloper1eh5mwu044gd5ntkkc2xgfg8247mgc56fww3vc8"}' \ +localhost:9090 cosmos.staking.v1beta1.Query/DelegatorValidator +``` + +Example Output: + +```bash +{ + "validator": { + "operator_address": "cosmosvaloper1eh5mwu044gd5ntkkc2xgfg8247mgc56fww3vc8", + "consensus_pubkey": { + "@type": "/cosmos.crypto.ed25519.PubKey", + "key": "UPwHWxH1zHJWGOa/m6JB3f5YjHMvPQPkVbDqqi+U7Uw=" + }, + "jailed": false, + "status": "BOND_STATUS_BONDED", + "tokens": "347262754841", + "delegator_shares": "347262754841.000000000000000000", + "description": { + "moniker": "BouBouNode", + "identity": "", + "website": "https://boubounode.com", + "security_contact": "", + "details": "AI-based Validator. #1 AI Validator on Game of Stakes. Fairly priced. Don't trust (humans), verify. Made with BouBou love." + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.061000000000000000", + "max_rate": "0.300000000000000000", + "max_change_rate": "0.150000000000000000" + }, + "update_time": "2021-10-01T15:00:00Z" + }, + "min_self_delegation": "1" + } +} +``` + +### HistoricalInfo + +```bash +cosmos.staking.v1beta1.Query/HistoricalInfo +``` + +Example: + +```bash +grpcurl -plaintext -d '{"height" : 1}' localhost:9090 cosmos.staking.v1beta1.Query/HistoricalInfo +``` + +Example Output: + +```bash +{ + "hist": { + "header": { + "version": { + "block": "11", + "app": "0" + }, + "chain_id": "simd-1", + "height": "140142", + "time": "2021-10-11T10:56:29.720079569Z", + "last_block_id": { + "hash": "9gri/4LLJUBFqioQ3NzZIP9/7YHR9QqaM6B2aJNQA7o=", + "part_set_header": { + "total": 1, + "hash": "Hk1+C864uQkl9+I6Zn7IurBZBKUevqlVtU7VqaZl1tc=" + } + }, + "last_commit_hash": "VxrcS27GtvGruS3I9+AlpT7udxIT1F0OrRklrVFSSKc=", + "data_hash": "80BjOrqNYUOkTnmgWyz9AQ8n7SoEmPVi4QmAe8RbQBY=", + "validators_hash": "95W49n2hw8RWpr1GPTAO5MSPi6w6Wjr3JjjS7AjpBho=", + "next_validators_hash": "95W49n2hw8RWpr1GPTAO5MSPi6w6Wjr3JjjS7AjpBho=", + "consensus_hash": "BICRvH3cKD93v7+R1zxE2ljD34qcvIZ0Bdi389qtoi8=", + "app_hash": "ZZaxnSY3E6Ex5Bvkm+RigYCK82g8SSUL53NymPITeOE=", + "last_results_hash": "47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=", + "evidence_hash": "47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=", + "proposer_address": "aH6dO428B+ItuoqPq70efFHrSMY=" + }, + "valset": [ + { + "operator_address": "cosmosvaloper196ax4vc0lwpxndu9dyhvca7jhxp70rmcqcnylw", + "consensus_pubkey": { + "@type": "/cosmos.crypto.ed25519.PubKey", + "key": "/O7BtNW0pafwfvomgR4ZnfldwPXiFfJs9mHg3gwfv5Q=" + }, + "jailed": false, + "status": "BOND_STATUS_BONDED", + "tokens": "1426045203613", + "delegator_shares": "1426045203613.000000000000000000", + "description": { + "moniker": "SG-1", + "identity": "48608633F99D1B60", + "website": "https://sg-1.online", + "security_contact": "", + "details": "SG-1 - your favorite validator on Witval. We offer 100% Soft Slash protection." + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.037500000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.030000000000000000" + }, + "update_time": "2021-10-01T15:00:00Z" + }, + "min_self_delegation": "1" + } + ] + } +} + +``` + +### Pool + +The `Pool` endpoint queries the pool information. + +```bash +cosmos.staking.v1beta1.Query/Pool +``` + +Example: + +```bash +grpcurl -plaintext -d localhost:9090 cosmos.staking.v1beta1.Query/Pool +``` + +Example Output: + +```bash +{ + "pool": { + "not_bonded_tokens": "369054400189", + "bonded_tokens": "15657192425623" + } +} +``` + +### Params + +The `Params` endpoint queries the pool information. + +```bash +cosmos.staking.v1beta1.Query/Params +``` + +Example: + +```bash +grpcurl -plaintext localhost:9090 cosmos.staking.v1beta1.Query/Params +``` + +Example Output: + +```bash +{ + "params": { + "unbondingTime": "1814400s", + "maxValidators": 100, + "maxEntries": 7, + "historicalEntries": 10000, + "bondDenom": "stake" + } +} +``` + +## REST + +A user can query the `staking` module using REST endpoints. + +### DelegatorDelegations + +The `DelegtaorDelegations` REST endpoint queries all delegations of a given delegator address. + +```bash +/cosmos/staking/v1beta1/delegations/{delegatorAddr} +``` + +Example: + +```bash +curl -X GET "http://localhost:1317/cosmos/staking/v1beta1/delegations/cosmos1vcs68xf2tnqes5tg0khr0vyevm40ff6zdxatp5" -H "accept: application/json" +``` + +Example Output: + +```bash +{ + "delegation_responses": [ + { + "delegation": { + "delegator_address": "cosmos1vcs68xf2tnqes5tg0khr0vyevm40ff6zdxatp5", + "validator_address": "cosmosvaloper1quqxfrxkycr0uzt4yk0d57tcq3zk7srm7sm6r8", + "shares": "256250000.000000000000000000" + }, + "balance": { + "denom": "stake", + "amount": "256250000" + } + }, + { + "delegation": { + "delegator_address": "cosmos1vcs68xf2tnqes5tg0khr0vyevm40ff6zdxatp5", + "validator_address": "cosmosvaloper194v8uwee2fvs2s8fa5k7j03ktwc87h5ym39jfv", + "shares": "255150000.000000000000000000" + }, + "balance": { + "denom": "stake", + "amount": "255150000" + } + } + ], + "pagination": { + "next_key": null, + "total": "2" + } +} +``` + +### Redelegations + +The `Redelegations` REST endpoint queries redelegations of given address. + +```bash +/cosmos/staking/v1beta1/delegators/{delegatorAddr}/redelegations +``` + +Example: + +```bash +curl -X GET \ +"http://localhost:1317/cosmos/staking/v1beta1/delegators/cosmos1thfntksw0d35n2tkr0k8v54fr8wxtxwxl2c56e/redelegations?srcValidatorAddr=cosmosvaloper1lzhlnpahvznwfv4jmay2tgaha5kmz5qx4cuznf&dstValidatorAddr=cosmosvaloper1vq8tw77kp8lvxq9u3c8eeln9zymn68rng8pgt4" \ +-H "accept: application/json" +``` + +Example Output: + +```bash +{ + "redelegation_responses": [ + { + "redelegation": { + "delegator_address": "cosmos1thfntksw0d35n2tkr0k8v54fr8wxtxwxl2c56e", + "validator_src_address": "cosmosvaloper1lzhlnpahvznwfv4jmay2tgaha5kmz5qx4cuznf", + "validator_dst_address": "cosmosvaloper1vq8tw77kp8lvxq9u3c8eeln9zymn68rng8pgt4", + "entries": null + }, + "entries": [ + { + "redelegation_entry": { + "creation_height": 151523, + "completion_time": "2021-11-09T06:03:25.640682116Z", + "initial_balance": "200000000", + "shares_dst": "200000000.000000000000000000" + }, + "balance": "200000000" + } + ] + } + ], + "pagination": null +} +``` + +### DelegatorUnbondingDelegations + +The `DelegatorUnbondingDelegations` REST endpoint queries all unbonding delegations of a given delegator address. + +```bash +/cosmos/staking/v1beta1/delegators/{delegatorAddr}/unbonding_delegations +``` + +Example: + +```bash +curl -X GET \ +"http://localhost:1317/cosmos/staking/v1beta1/delegators/cosmos1nxv42u3lv642q0fuzu2qmrku27zgut3n3z7lll/unbonding_delegations" \ +-H "accept: application/json" +``` + +Example Output: + +```bash +{ + "unbonding_responses": [ + { + "delegator_address": "cosmos1nxv42u3lv642q0fuzu2qmrku27zgut3n3z7lll", + "validator_address": "cosmosvaloper1e7mvqlz50ch6gw4yjfemsc069wfre4qwmw53kq", + "entries": [ + { + "creation_height": "2442278", + "completion_time": "2021-10-12T10:59:03.797335857Z", + "initial_balance": "50000000000", + "balance": "50000000000" + } + ] + } + ], + "pagination": { + "next_key": null, + "total": "1" + } +} +``` + +### DelegatorValidators + +The `DelegatorValidators` REST endpoint queries all validators information for given delegator address. + +```bash +/cosmos/staking/v1beta1/delegators/{delegatorAddr}/validators +``` + +Example: + +```bash +curl -X GET \ +"http://localhost:1317/cosmos/staking/v1beta1/delegators/cosmos1xwazl8ftks4gn00y5x3c47auquc62ssune9ppv/validators" \ +-H "accept: application/json" +``` + +Example Output: + +```bash +{ + "validators": [ + { + "operator_address": "cosmosvaloper1xwazl8ftks4gn00y5x3c47auquc62ssuvynw64", + "consensus_pubkey": { + "@type": "/cosmos.crypto.ed25519.PubKey", + "key": "5v4n3px3PkfNnKflSgepDnsMQR1hiNXnqOC11Y72/PQ=" + }, + "jailed": false, + "status": "BOND_STATUS_BONDED", + "tokens": "21592843799", + "delegator_shares": "21592843799.000000000000000000", + "description": { + "moniker": "jabbey", + "identity": "", + "website": "https://twitter.com/JoeAbbey", + "security_contact": "", + "details": "just another dad in the cosmos" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.100000000000000000" + }, + "update_time": "2021-10-09T19:03:54.984821705Z" + }, + "min_self_delegation": "1" + } + ], + "pagination": { + "next_key": null, + "total": "1" + } +} +``` + +### DelegatorValidator + +The `DelegatorValidator` REST endpoint queries validator information for given delegator validator pair. + +```bash +/cosmos/staking/v1beta1/delegators/{delegatorAddr}/validators/{validatorAddr} +``` + +Example: + +```bash +curl -X GET \ +"http://localhost:1317/cosmos/staking/v1beta1/delegators/cosmos1xwazl8ftks4gn00y5x3c47auquc62ssune9ppv/validators/cosmosvaloper1xwazl8ftks4gn00y5x3c47auquc62ssuvynw64" \ +-H "accept: application/json" +``` + +Example Output: + +```bash +{ + "validator": { + "operator_address": "cosmosvaloper1xwazl8ftks4gn00y5x3c47auquc62ssuvynw64", + "consensus_pubkey": { + "@type": "/cosmos.crypto.ed25519.PubKey", + "key": "5v4n3px3PkfNnKflSgepDnsMQR1hiNXnqOC11Y72/PQ=" + }, + "jailed": false, + "status": "BOND_STATUS_BONDED", + "tokens": "21592843799", + "delegator_shares": "21592843799.000000000000000000", + "description": { + "moniker": "jabbey", + "identity": "", + "website": "https://twitter.com/JoeAbbey", + "security_contact": "", + "details": "just another dad in the cosmos" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.100000000000000000" + }, + "update_time": "2021-10-09T19:03:54.984821705Z" + }, + "min_self_delegation": "1" + } +} +``` + +### HistoricalInfo + +The `HistoricalInfo` REST endpoint queries the historical information for given height. + +```bash +/cosmos/staking/v1beta1/historical_info/{height} +``` + +Example: + +```bash +curl -X GET "http://localhost:1317/cosmos/staking/v1beta1/historical_info/153332" -H "accept: application/json" +``` + +Example Output: + +```bash +{ + "hist": { + "header": { + "version": { + "block": "11", + "app": "0" + }, + "chain_id": "cosmos-1", + "height": "153332", + "time": "2021-10-12T09:05:35.062230221Z", + "last_block_id": { + "hash": "NX8HevR5khb7H6NGKva+jVz7cyf0skF1CrcY9A0s+d8=", + "part_set_header": { + "total": 1, + "hash": "zLQ2FiKM5tooL3BInt+VVfgzjlBXfq0Hc8Iux/xrhdg=" + } + }, + "last_commit_hash": "P6IJrK8vSqU3dGEyRHnAFocoDGja0bn9euLuy09s350=", + "data_hash": "eUd+6acHWrNXYju8Js449RJ99lOYOs16KpqQl4SMrEM=", + "validators_hash": "mB4pravvMsJKgi+g8aYdSeNlt0kPjnRFyvtAQtaxcfw=", + "next_validators_hash": "mB4pravvMsJKgi+g8aYdSeNlt0kPjnRFyvtAQtaxcfw=", + "consensus_hash": "BICRvH3cKD93v7+R1zxE2ljD34qcvIZ0Bdi389qtoi8=", + "app_hash": "fuELArKRK+CptnZ8tu54h6xEleSWenHNmqC84W866fU=", + "last_results_hash": "p/BPexV4LxAzlVcPRvW+lomgXb6Yze8YLIQUo/4Kdgc=", + "evidence_hash": "47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=", + "proposer_address": "G0MeY8xQx7ooOsni8KE/3R/Ib3Q=" + }, + "valset": [ + { + "operator_address": "cosmosvaloper196ax4vc0lwpxndu9dyhvca7jhxp70rmcqcnylw", + "consensus_pubkey": { + "@type": "/cosmos.crypto.ed25519.PubKey", + "key": "/O7BtNW0pafwfvomgR4ZnfldwPXiFfJs9mHg3gwfv5Q=" + }, + "jailed": false, + "status": "BOND_STATUS_BONDED", + "tokens": "1416521659632", + "delegator_shares": "1416521659632.000000000000000000", + "description": { + "moniker": "SG-1", + "identity": "48608633F99D1B60", + "website": "https://sg-1.online", + "security_contact": "", + "details": "SG-1 - your favorite validator on cosmos. We offer 100% Soft Slash protection." + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.037500000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.030000000000000000" + }, + "update_time": "2021-10-01T15:00:00Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1t8ehvswxjfn3ejzkjtntcyrqwvmvuknzmvtaaa", + "consensus_pubkey": { + "@type": "/cosmos.crypto.ed25519.PubKey", + "key": "uExZyjNLtr2+FFIhNDAMcQ8+yTrqE7ygYTsI7khkA5Y=" + }, + "jailed": false, + "status": "BOND_STATUS_BONDED", + "tokens": "1348298958808", + "delegator_shares": "1348298958808.000000000000000000", + "description": { + "moniker": "Cosmostation", + "identity": "AE4C403A6E7AA1AC", + "website": "https://www.cosmostation.io", + "security_contact": "admin@stamper.network", + "details": "Cosmostation validator node. Delegate your tokens and Start Earning Staking Rewards" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.050000000000000000", + "max_rate": "1.000000000000000000", + "max_change_rate": "0.200000000000000000" + }, + "update_time": "2021-10-01T15:06:38.821314287Z" + }, + "min_self_delegation": "1" + } + ] + } +} +``` + +### Parameters + +The `Parameters` REST endpoint queries the staking parameters. + +```bash +/cosmos/staking/v1beta1/params +``` + +Example: + +```bash +curl -X GET "http://localhost:1317/cosmos/staking/v1beta1/params" -H "accept: application/json" +``` + +Example Output: + +```bash +{ + "params": { + "unbonding_time": "2419200s", + "max_validators": 100, + "max_entries": 7, + "historical_entries": 10000, + "bond_denom": "stake" + } +} +``` + +### Pool + +The `Pool` REST endpoint queries the pool information. + +```bash +/cosmos/staking/v1beta1/pool +``` + +Example: + +```bash +curl -X GET "http://localhost:1317/cosmos/staking/v1beta1/pool" -H "accept: application/json" +``` + +Example Output: + +```bash +{ + "pool": { + "not_bonded_tokens": "432805737458", + "bonded_tokens": "15783637712645" + } +} +``` + +### Validators + +The `Validators` REST endpoint queries all validators that match the given status. + +```bash +/cosmos/staking/v1beta1/validators +``` + +Example: + +```bash +curl -X GET "http://localhost:1317/cosmos/staking/v1beta1/validators" -H "accept: application/json" +``` + +Example Output: + +```bash +{ + "validators": [ + { + "operator_address": "cosmosvaloper1q3jsx9dpfhtyqqgetwpe5tmk8f0ms5qywje8tw", + "consensus_pubkey": { + "@type": "/cosmos.crypto.ed25519.PubKey", + "key": "N7BPyek2aKuNZ0N/8YsrqSDhGZmgVaYUBuddY8pwKaE=" + }, + "jailed": false, + "status": "BOND_STATUS_BONDED", + "tokens": "383301887799", + "delegator_shares": "383301887799.000000000000000000", + "description": { + "moniker": "SmartNodes", + "identity": "D372724899D1EDC8", + "website": "https://smartnodes.co", + "security_contact": "", + "details": "Earn Rewards with Crypto Staking & Node Deployment" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.050000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.100000000000000000" + }, + "update_time": "2021-10-01T15:51:31.596618510Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1q5ku90atkhktze83j9xjaks2p7uruag5zp6wt7", + "consensus_pubkey": { + "@type": "/cosmos.crypto.ed25519.PubKey", + "key": "GDNpuKDmCg9GnhnsiU4fCWktuGUemjNfvpCZiqoRIYA=" + }, + "jailed": false, + "status": "BOND_STATUS_UNBONDING", + "tokens": "1017819654", + "delegator_shares": "1017819654.000000000000000000", + "description": { + "moniker": "Noderunners", + "identity": "812E82D12FEA3493", + "website": "http://noderunners.biz", + "security_contact": "info@noderunners.biz", + "details": "Noderunners is a professional validator in POS networks. We have a huge node running experience, reliable soft and hardware. Our commissions are always low, our support to delegators is always full. Stake with us and start receiving your cosmos rewards now!" + }, + "unbonding_height": "147302", + "unbonding_time": "2021-11-08T22:58:53.718662452Z", + "commission": { + "commission_rates": { + "rate": "0.050000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.100000000000000000" + }, + "update_time": "2021-10-04T18:02:21.446645619Z" + }, + "min_self_delegation": "1" + } + ], + "pagination": { + "next_key": "FONDBFkE4tEEf7yxWWKOD49jC2NK", + "total": "2" + } +} +``` + +### Validator + +The `Validator` REST endpoint queries validator information for given validator address. + +```bash +/cosmos/staking/v1beta1/validators/{validatorAddr} +``` + +Example: + +```bash +curl -X GET \ +"http://localhost:1317/cosmos/staking/v1beta1/validators/cosmosvaloper16msryt3fqlxtvsy8u5ay7wv2p8mglfg9g70e3q" \ +-H "accept: application/json" +``` + +Example Output: + +```bash +{ + "validator": { + "operator_address": "cosmosvaloper16msryt3fqlxtvsy8u5ay7wv2p8mglfg9g70e3q", + "consensus_pubkey": { + "@type": "/cosmos.crypto.ed25519.PubKey", + "key": "sIiexdJdYWn27+7iUHQJDnkp63gq/rzUq1Y+fxoGjXc=" + }, + "jailed": false, + "status": "BOND_STATUS_BONDED", + "tokens": "33027900000", + "delegator_shares": "33027900000.000000000000000000", + "description": { + "moniker": "Witval", + "identity": "51468B615127273A", + "website": "", + "security_contact": "", + "details": "Witval is the validator arm from Vitwit. Vitwit is into software consulting and services business since 2015. We are working closely with Cosmos ecosystem since 2018. We are also building tools for the ecosystem, Aneka is our explorer for the cosmos ecosystem." + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.050000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.020000000000000000" + }, + "update_time": "2021-10-01T19:24:52.663191049Z" + }, + "min_self_delegation": "1" + } +} +``` + +### ValidatorDelegations + +The `ValidatorDelegations` REST endpoint queries delegate information for given validator. + +```bash +/cosmos/staking/v1beta1/validators/{validatorAddr}/delegations +``` + +Example: + +```bash +curl -X GET "http://localhost:1317/cosmos/staking/v1beta1/validators/cosmosvaloper16msryt3fqlxtvsy8u5ay7wv2p8mglfg9g70e3q/delegations" -H "accept: application/json" +``` + +Example Output: + +```bash +{ + "delegation_responses": [ + { + "delegation": { + "delegator_address": "cosmos190g5j8aszqhvtg7cprmev8xcxs6csra7xnk3n3", + "validator_address": "cosmosvaloper16msryt3fqlxtvsy8u5ay7wv2p8mglfg9g70e3q", + "shares": "31000000000.000000000000000000" + }, + "balance": { + "denom": "stake", + "amount": "31000000000" + } + }, + { + "delegation": { + "delegator_address": "cosmos1ddle9tczl87gsvmeva3c48nenyng4n56qwq4ee", + "validator_address": "cosmosvaloper16msryt3fqlxtvsy8u5ay7wv2p8mglfg9g70e3q", + "shares": "628470000.000000000000000000" + }, + "balance": { + "denom": "stake", + "amount": "628470000" + } + }, + { + "delegation": { + "delegator_address": "cosmos10fdvkczl76m040smd33lh9xn9j0cf26kk4s2nw", + "validator_address": "cosmosvaloper16msryt3fqlxtvsy8u5ay7wv2p8mglfg9g70e3q", + "shares": "838120000.000000000000000000" + }, + "balance": { + "denom": "stake", + "amount": "838120000" + } + }, + { + "delegation": { + "delegator_address": "cosmos1n8f5fknsv2yt7a8u6nrx30zqy7lu9jfm0t5lq8", + "validator_address": "cosmosvaloper16msryt3fqlxtvsy8u5ay7wv2p8mglfg9g70e3q", + "shares": "500000000.000000000000000000" + }, + "balance": { + "denom": "stake", + "amount": "500000000" + } + }, + { + "delegation": { + "delegator_address": "cosmos16msryt3fqlxtvsy8u5ay7wv2p8mglfg9hrek2e", + "validator_address": "cosmosvaloper16msryt3fqlxtvsy8u5ay7wv2p8mglfg9g70e3q", + "shares": "61310000.000000000000000000" + }, + "balance": { + "denom": "stake", + "amount": "61310000" + } + } + ], + "pagination": { + "next_key": null, + "total": "5" + } +} +``` + +### Delegation + +The `Delegation` REST endpoint queries delegate information for given validator delegator pair. + +```bash +/cosmos/staking/v1beta1/validators/{validatorAddr}/delegations/{delegatorAddr} +``` + +Example: + +```bash +curl -X GET \ +"http://localhost:1317/cosmos/staking/v1beta1/validators/cosmosvaloper16msryt3fqlxtvsy8u5ay7wv2p8mglfg9g70e3q/delegations/cosmos1n8f5fknsv2yt7a8u6nrx30zqy7lu9jfm0t5lq8" \ +-H "accept: application/json" +``` + +Example Output: + +```bash +{ + "delegation_response": { + "delegation": { + "delegator_address": "cosmos1n8f5fknsv2yt7a8u6nrx30zqy7lu9jfm0t5lq8", + "validator_address": "cosmosvaloper16msryt3fqlxtvsy8u5ay7wv2p8mglfg9g70e3q", + "shares": "500000000.000000000000000000" + }, + "balance": { + "denom": "stake", + "amount": "500000000" + } + } +} +``` + +### UnbondingDelegation + +The `UnbondingDelegation` REST endpoint queries unbonding information for given validator delegator pair. + +```bash +/cosmos/staking/v1beta1/validators/{validatorAddr}/delegations/{delegatorAddr}/unbonding_delegation +``` + +Example: + +```bash +curl -X GET \ +"http://localhost:1317/cosmos/staking/v1beta1/validators/cosmosvaloper13v4spsah85ps4vtrw07vzea37gq5la5gktlkeu/delegations/cosmos1ze2ye5u5k3qdlexvt2e0nn0508p04094ya0qpm/unbonding_delegation" \ +-H "accept: application/json" +``` + +Example Output: + +```bash +{ + "unbond": { + "delegator_address": "cosmos1ze2ye5u5k3qdlexvt2e0nn0508p04094ya0qpm", + "validator_address": "cosmosvaloper13v4spsah85ps4vtrw07vzea37gq5la5gktlkeu", + "entries": [ + { + "creation_height": "153687", + "completion_time": "2021-11-09T09:41:18.352401903Z", + "initial_balance": "525111", + "balance": "525111" + } + ] + } +} +``` + +### ValidatorUnbondingDelegations + +The `ValidatorUnbondingDelegations` REST endpoint queries unbonding delegations of a validator. + +```bash +/cosmos/staking/v1beta1/validators/{validatorAddr}/unbonding_delegations +``` + +Example: + +```bash +curl -X GET \ +"http://localhost:1317/cosmos/staking/v1beta1/validators/cosmosvaloper13v4spsah85ps4vtrw07vzea37gq5la5gktlkeu/unbonding_delegations" \ +-H "accept: application/json" +``` + +Example Output: + +```bash +{ + "unbonding_responses": [ + { + "delegator_address": "cosmos1q9snn84jfrd9ge8t46kdcggpe58dua82vnj7uy", + "validator_address": "cosmosvaloper13v4spsah85ps4vtrw07vzea37gq5la5gktlkeu", + "entries": [ + { + "creation_height": "90998", + "completion_time": "2021-11-05T00:14:37.005841058Z", + "initial_balance": "24000000", + "balance": "24000000" + } + ] + }, + { + "delegator_address": "cosmos1qf36e6wmq9h4twhdvs6pyq9qcaeu7ye0s3dqq2", + "validator_address": "cosmosvaloper13v4spsah85ps4vtrw07vzea37gq5la5gktlkeu", + "entries": [ + { + "creation_height": "47478", + "completion_time": "2021-11-01T22:47:26.714116854Z", + "initial_balance": "8000000", + "balance": "8000000" + } + ] + } + ], + "pagination": { + "next_key": null, + "total": "2" + } +} +``` diff --git a/x/staking/spec/README.md b/x/staking/spec/README.md index a2cb7cf3a8..b56ae71cdb 100644 --- a/x/staking/spec/README.md +++ b/x/staking/spec/README.md @@ -11,7 +11,7 @@ parent: This paper specifies the Staking module of the Cosmos-SDK, which was first described in the [Cosmos Whitepaper](https://cosmos.network/about/whitepaper) -in June 2016. +in June 2016. The module enables Cosmos-SDK based blockchain to support an advanced Proof-of-Stake system. In this system, holders of the native staking token of @@ -38,18 +38,18 @@ network. - [Delegations](02_state_transitions.md#delegations) - [Slashing](02_state_transitions.md#slashing) 3. **[Messages](03_messages.md)** - - [Msg/CreateValidator](03_messages.md#msgcreatevalidator) - - [Msg/EditValidator](03_messages.md#msgeditvalidator) - - [Msg/Delegate](03_messages.md#msgdelegate) - - [Msg/BeginUnbonding](03_messages.md#msgbeginunbonding) - - [Msg/BeginRedelegate](03_messages.md#msgbeginredelegate) + - [MsgCreateValidator](03_messages.md#msgcreatevalidator) + - [MsgEditValidator](03_messages.md#msgeditvalidator) + - [MsgDelegate](03_messages.md#msgdelegate) + - [MsgUndelegate](03_messages.md#msgundelegate) + - [MsgBeginRedelegate](03_messages.md#msgbeginredelegate) 4. **[Begin-Block](04_begin_block.md)** - [Historical Info Tracking](04_begin_block.md#historical-info-tracking) -5. **[End-Block ](05_end_block.md)** +5. **[End-Block](05_end_block.md)** - [Validator Set Changes](05_end_block.md#validator-set-changes) - - [Queues ](05_end_block.md#queues-) + - [Queues](05_end_block.md#queues-) 6. **[Hooks](06_hooks.md)** 7. **[Events](07_events.md)** - [EndBlocker](07_events.md#endblocker) - - [Handlers](07_events.md#handlers) + - [Msg's](07_events.md#msg's) 8. **[Parameters](08_params.md)** diff --git a/x/staking/teststaking/helper.go b/x/staking/teststaking/helper.go index 8746e625f7..7421e0bd16 100644 --- a/x/staking/teststaking/helper.go +++ b/x/staking/teststaking/helper.go @@ -40,7 +40,7 @@ func (sh *Helper) CreateValidator(addr sdk.ValAddress, pk cryptotypes.PubKey, st // CreateValidatorWithValPower calls handler to create a new staking validator with zero // commission func (sh *Helper) CreateValidatorWithValPower(addr sdk.ValAddress, pk cryptotypes.PubKey, valPower int64, ok bool) sdk.Int { - amount := sdk.TokensFromConsensusPower(valPower) + amount := sh.k.TokensFromConsensusPower(sh.Ctx, valPower) coin := sdk.NewCoin(sh.Denom, amount) sh.createValidator(addr, pk, coin, ok) return amount @@ -69,7 +69,7 @@ func (sh *Helper) Delegate(delegator sdk.AccAddress, val sdk.ValAddress, amount // DelegateWithPower calls handler to delegate stake for a validator func (sh *Helper) DelegateWithPower(delegator sdk.AccAddress, val sdk.ValAddress, power int64) { - coin := sdk.NewCoin(sh.Denom, sdk.TokensFromConsensusPower(power)) + coin := sdk.NewCoin(sh.Denom, sh.k.TokensFromConsensusPower(sh.Ctx, power)) msg := stakingtypes.NewMsgDelegate(delegator, val, coin) sh.Handle(msg, true) } diff --git a/x/staking/teststaking/tm.go b/x/staking/teststaking/tm.go index 42a7dbbb6e..40cdb3b09f 100644 --- a/x/staking/teststaking/tm.go +++ b/x/staking/teststaking/tm.go @@ -5,6 +5,7 @@ import ( octypes "github.com/line/ostracon/types" cryptocodec "github.com/line/lbm-sdk/crypto/codec" + sdk "github.com/line/lbm-sdk/types" "github.com/line/lbm-sdk/x/staking/types" ) @@ -18,22 +19,22 @@ func GetOcConsPubKey(v types.Validator) (occrypto.PubKey, error) { return cryptocodec.ToOcPubKeyInterface(pk) } -// ToOcValidator casts an SDK validator to an ostracon type Validator. -func ToOcValidator(v types.Validator) (*octypes.Validator, error) { - tmPk, err := GetOcConsPubKey(v) +// ToOcValidator casts an SDK validator to a tendermint type Validator. +func ToOcValidator(v types.Validator, r sdk.Int) (*octypes.Validator, error) { + ocPk, err := GetOcConsPubKey(v) if err != nil { return nil, err } - return octypes.NewValidator(tmPk, v.ConsensusPower()), nil + return octypes.NewValidator(ocPk, v.ConsensusPower(r)), nil } // ToOcValidators casts all validators to the corresponding tendermint type. -func ToOcValidators(v types.Validators) ([]*octypes.Validator, error) { +func ToOcValidators(v types.Validators, r sdk.Int) ([]*octypes.Validator, error) { validators := make([]*octypes.Validator, len(v)) var err error for i, val := range v { - validators[i], err = ToOcValidator(val) + validators[i], err = ToOcValidator(val, r) if err != nil { return nil, err } diff --git a/x/staking/types/authz.go b/x/staking/types/authz.go new file mode 100644 index 0000000000..0771786db5 --- /dev/null +++ b/x/staking/types/authz.go @@ -0,0 +1,150 @@ +package types + +import ( + sdk "github.com/line/lbm-sdk/types" + sdkerrors "github.com/line/lbm-sdk/types/errors" + "github.com/line/lbm-sdk/x/authz" +) + +// TODO: Revisit this once we have propoer gas fee framework. +// Tracking issues https://github.com/cosmos/cosmos-sdk/issues/9054, https://github.com/cosmos/cosmos-sdk/discussions/9072 +const gasCostPerIteration = uint64(10) + +// Normalized Msg type URLs +var ( + _ authz.Authorization = &StakeAuthorization{} +) + +// NewStakeAuthorization creates a new StakeAuthorization object. +func NewStakeAuthorization(allowed []sdk.ValAddress, denied []sdk.ValAddress, authzType AuthorizationType, amount *sdk.Coin) (*StakeAuthorization, error) { + allowedValidators, deniedValidators, err := validateAndBech32fy(allowed, denied) + if err != nil { + return nil, err + } + + a := StakeAuthorization{} + if allowedValidators != nil { + a.Validators = &StakeAuthorization_AllowList{AllowList: &StakeAuthorization_Validators{Address: allowedValidators}} + } else { + a.Validators = &StakeAuthorization_DenyList{DenyList: &StakeAuthorization_Validators{Address: deniedValidators}} + } + + if amount != nil { + a.MaxTokens = amount + } + a.AuthorizationType = authzType + + return &a, nil +} + +// MsgTypeURL implements Authorization.MsgTypeURL. +func (a StakeAuthorization) MsgTypeURL() string { + authzType, err := normalizeAuthzType(a.AuthorizationType) + if err != nil { + panic(err) + } + return authzType +} + +func (a StakeAuthorization) ValidateBasic() error { + if a.MaxTokens != nil && a.MaxTokens.IsNegative() { + return sdkerrors.Wrapf(sdkerrors.ErrInvalidCoins, "negative coin amount: %v", a.MaxTokens) + } + if a.AuthorizationType == AuthorizationType_AUTHORIZATION_TYPE_UNSPECIFIED { + return sdkerrors.Wrapf(sdkerrors.ErrInvalidType, "unknown authorization type") + } + + return nil +} + +// Accept implements Authorization.Accept. +func (a StakeAuthorization) Accept(ctx sdk.Context, msg sdk.Msg) (authz.AcceptResponse, error) { + var validatorAddress string + var amount sdk.Coin + + switch msg := msg.(type) { + case *MsgDelegate: + validatorAddress = msg.ValidatorAddress + amount = msg.Amount + case *MsgUndelegate: + validatorAddress = msg.ValidatorAddress + amount = msg.Amount + case *MsgBeginRedelegate: + validatorAddress = msg.ValidatorDstAddress + amount = msg.Amount + default: + return authz.AcceptResponse{}, sdkerrors.ErrInvalidRequest.Wrap("unknown msg type") + } + + isValidatorExists := false + allowedList := a.GetAllowList().GetAddress() + for _, validator := range allowedList { + ctx.GasMeter().ConsumeGas(gasCostPerIteration, "stake authorization") + if validator == validatorAddress { + isValidatorExists = true + break + } + } + + denyList := a.GetDenyList().GetAddress() + for _, validator := range denyList { + ctx.GasMeter().ConsumeGas(gasCostPerIteration, "stake authorization") + if validator == validatorAddress { + return authz.AcceptResponse{}, sdkerrors.ErrUnauthorized.Wrapf(" cannot delegate/undelegate to %s validator", validator) + } + } + + if !isValidatorExists { + return authz.AcceptResponse{}, sdkerrors.ErrUnauthorized.Wrapf("cannot delegate/undelegate to %s validator", validatorAddress) + } + + if a.MaxTokens == nil { + return authz.AcceptResponse{Accept: true, Delete: false, + Updated: &StakeAuthorization{Validators: a.GetValidators(), AuthorizationType: a.GetAuthorizationType()}}, nil + } + + limitLeft := a.MaxTokens.Sub(amount) + if limitLeft.IsZero() { + return authz.AcceptResponse{Accept: true, Delete: true}, nil + } + return authz.AcceptResponse{Accept: true, Delete: false, + Updated: &StakeAuthorization{Validators: a.GetValidators(), AuthorizationType: a.GetAuthorizationType(), MaxTokens: &limitLeft}}, nil +} + +func validateAndBech32fy(allowed []sdk.ValAddress, denied []sdk.ValAddress) ([]string, []string, error) { + if len(allowed) == 0 && len(denied) == 0 { + return nil, nil, sdkerrors.ErrInvalidRequest.Wrap("both allowed & deny list cannot be empty") + } + + if len(allowed) > 0 && len(denied) > 0 { + return nil, nil, sdkerrors.ErrInvalidRequest.Wrap("cannot set both allowed & deny list") + } + + allowedValidators := make([]string, len(allowed)) + if len(allowed) > 0 { + for i, validator := range allowed { + allowedValidators[i] = validator.String() + } + return allowedValidators, nil, nil + } + + deniedValidators := make([]string, len(denied)) + for i, validator := range denied { + deniedValidators[i] = validator.String() + } + + return nil, deniedValidators, nil +} + +func normalizeAuthzType(authzType AuthorizationType) (string, error) { + switch authzType { + case AuthorizationType_AUTHORIZATION_TYPE_DELEGATE: + return sdk.MsgTypeURL(&MsgDelegate{}), nil + case AuthorizationType_AUTHORIZATION_TYPE_UNDELEGATE: + return sdk.MsgTypeURL(&MsgUndelegate{}), nil + case AuthorizationType_AUTHORIZATION_TYPE_REDELEGATE: + return sdk.MsgTypeURL(&MsgBeginRedelegate{}), nil + default: + return "", sdkerrors.ErrInvalidType.Wrapf("unknown authorization type %T", authzType) + } +} diff --git a/x/staking/types/authz.pb.go b/x/staking/types/authz.pb.go new file mode 100644 index 0000000000..a4cdb9ad8c --- /dev/null +++ b/x/staking/types/authz.pb.go @@ -0,0 +1,799 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: lbm/staking/v1/authz.proto + +package types + +import ( + fmt "fmt" + _ "github.com/gogo/protobuf/gogoproto" + proto "github.com/gogo/protobuf/proto" + types "github.com/line/lbm-sdk/types" + _ "github.com/regen-network/cosmos-proto" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +// AuthorizationType defines the type of staking module authorization type +// +// Since: cosmos-sdk 0.43 +type AuthorizationType int32 + +const ( + // AUTHORIZATION_TYPE_UNSPECIFIED specifies an unknown authorization type + AuthorizationType_AUTHORIZATION_TYPE_UNSPECIFIED AuthorizationType = 0 + // AUTHORIZATION_TYPE_DELEGATE defines an authorization type for Msg/Delegate + AuthorizationType_AUTHORIZATION_TYPE_DELEGATE AuthorizationType = 1 + // AUTHORIZATION_TYPE_UNDELEGATE defines an authorization type for Msg/Undelegate + AuthorizationType_AUTHORIZATION_TYPE_UNDELEGATE AuthorizationType = 2 + // AUTHORIZATION_TYPE_REDELEGATE defines an authorization type for Msg/BeginRedelegate + AuthorizationType_AUTHORIZATION_TYPE_REDELEGATE AuthorizationType = 3 +) + +var AuthorizationType_name = map[int32]string{ + 0: "AUTHORIZATION_TYPE_UNSPECIFIED", + 1: "AUTHORIZATION_TYPE_DELEGATE", + 2: "AUTHORIZATION_TYPE_UNDELEGATE", + 3: "AUTHORIZATION_TYPE_REDELEGATE", +} + +var AuthorizationType_value = map[string]int32{ + "AUTHORIZATION_TYPE_UNSPECIFIED": 0, + "AUTHORIZATION_TYPE_DELEGATE": 1, + "AUTHORIZATION_TYPE_UNDELEGATE": 2, + "AUTHORIZATION_TYPE_REDELEGATE": 3, +} + +func (x AuthorizationType) String() string { + return proto.EnumName(AuthorizationType_name, int32(x)) +} + +func (AuthorizationType) EnumDescriptor() ([]byte, []int) { + return fileDescriptor_37a194c8cc250db7, []int{0} +} + +// StakeAuthorization defines authorization for delegate/undelegate/redelegate. +// +// Since: cosmos-sdk 0.43 +type StakeAuthorization struct { + // max_tokens specifies the maximum amount of tokens can be delegate to a validator. If it is + // empty, there is no spend limit and any amount of coins can be delegated. + MaxTokens *types.Coin `protobuf:"bytes,1,opt,name=max_tokens,json=maxTokens,proto3,castrepeated=github.com/line/lbm-sdk/types.Coin" json:"max_tokens,omitempty"` + // validators is the oneof that represents either allow_list or deny_list + // + // Types that are valid to be assigned to Validators: + // *StakeAuthorization_AllowList + // *StakeAuthorization_DenyList + Validators isStakeAuthorization_Validators `protobuf_oneof:"validators"` + // authorization_type defines one of AuthorizationType. + AuthorizationType AuthorizationType `protobuf:"varint,4,opt,name=authorization_type,json=authorizationType,proto3,enum=lbm.staking.v1.AuthorizationType" json:"authorization_type,omitempty"` +} + +func (m *StakeAuthorization) Reset() { *m = StakeAuthorization{} } +func (m *StakeAuthorization) String() string { return proto.CompactTextString(m) } +func (*StakeAuthorization) ProtoMessage() {} +func (*StakeAuthorization) Descriptor() ([]byte, []int) { + return fileDescriptor_37a194c8cc250db7, []int{0} +} +func (m *StakeAuthorization) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *StakeAuthorization) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_StakeAuthorization.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *StakeAuthorization) XXX_Merge(src proto.Message) { + xxx_messageInfo_StakeAuthorization.Merge(m, src) +} +func (m *StakeAuthorization) XXX_Size() int { + return m.Size() +} +func (m *StakeAuthorization) XXX_DiscardUnknown() { + xxx_messageInfo_StakeAuthorization.DiscardUnknown(m) +} + +var xxx_messageInfo_StakeAuthorization proto.InternalMessageInfo + +type isStakeAuthorization_Validators interface { + isStakeAuthorization_Validators() + MarshalTo([]byte) (int, error) + Size() int +} + +type StakeAuthorization_AllowList struct { + AllowList *StakeAuthorization_Validators `protobuf:"bytes,2,opt,name=allow_list,json=allowList,proto3,oneof" json:"allow_list,omitempty"` +} +type StakeAuthorization_DenyList struct { + DenyList *StakeAuthorization_Validators `protobuf:"bytes,3,opt,name=deny_list,json=denyList,proto3,oneof" json:"deny_list,omitempty"` +} + +func (*StakeAuthorization_AllowList) isStakeAuthorization_Validators() {} +func (*StakeAuthorization_DenyList) isStakeAuthorization_Validators() {} + +func (m *StakeAuthorization) GetValidators() isStakeAuthorization_Validators { + if m != nil { + return m.Validators + } + return nil +} + +func (m *StakeAuthorization) GetMaxTokens() *types.Coin { + if m != nil { + return m.MaxTokens + } + return nil +} + +func (m *StakeAuthorization) GetAllowList() *StakeAuthorization_Validators { + if x, ok := m.GetValidators().(*StakeAuthorization_AllowList); ok { + return x.AllowList + } + return nil +} + +func (m *StakeAuthorization) GetDenyList() *StakeAuthorization_Validators { + if x, ok := m.GetValidators().(*StakeAuthorization_DenyList); ok { + return x.DenyList + } + return nil +} + +func (m *StakeAuthorization) GetAuthorizationType() AuthorizationType { + if m != nil { + return m.AuthorizationType + } + return AuthorizationType_AUTHORIZATION_TYPE_UNSPECIFIED +} + +// XXX_OneofWrappers is for the internal use of the proto package. +func (*StakeAuthorization) XXX_OneofWrappers() []interface{} { + return []interface{}{ + (*StakeAuthorization_AllowList)(nil), + (*StakeAuthorization_DenyList)(nil), + } +} + +// Validators defines list of validator addresses. +type StakeAuthorization_Validators struct { + Address []string `protobuf:"bytes,1,rep,name=address,proto3" json:"address,omitempty"` +} + +func (m *StakeAuthorization_Validators) Reset() { *m = StakeAuthorization_Validators{} } +func (m *StakeAuthorization_Validators) String() string { return proto.CompactTextString(m) } +func (*StakeAuthorization_Validators) ProtoMessage() {} +func (*StakeAuthorization_Validators) Descriptor() ([]byte, []int) { + return fileDescriptor_37a194c8cc250db7, []int{0, 0} +} +func (m *StakeAuthorization_Validators) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *StakeAuthorization_Validators) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_StakeAuthorization_Validators.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *StakeAuthorization_Validators) XXX_Merge(src proto.Message) { + xxx_messageInfo_StakeAuthorization_Validators.Merge(m, src) +} +func (m *StakeAuthorization_Validators) XXX_Size() int { + return m.Size() +} +func (m *StakeAuthorization_Validators) XXX_DiscardUnknown() { + xxx_messageInfo_StakeAuthorization_Validators.DiscardUnknown(m) +} + +var xxx_messageInfo_StakeAuthorization_Validators proto.InternalMessageInfo + +func (m *StakeAuthorization_Validators) GetAddress() []string { + if m != nil { + return m.Address + } + return nil +} + +func init() { + proto.RegisterEnum("lbm.staking.v1.AuthorizationType", AuthorizationType_name, AuthorizationType_value) + proto.RegisterType((*StakeAuthorization)(nil), "lbm.staking.v1.StakeAuthorization") + proto.RegisterType((*StakeAuthorization_Validators)(nil), "lbm.staking.v1.StakeAuthorization.Validators") +} + +func init() { proto.RegisterFile("lbm/staking/v1/authz.proto", fileDescriptor_37a194c8cc250db7) } + +var fileDescriptor_37a194c8cc250db7 = []byte{ + // 458 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x92, 0xc1, 0x6e, 0xd3, 0x40, + 0x10, 0x86, 0xed, 0x06, 0x01, 0x19, 0xa0, 0x6a, 0x56, 0x08, 0x85, 0x20, 0xdc, 0x36, 0x87, 0x12, + 0x21, 0x65, 0xad, 0x94, 0x1b, 0x37, 0xa7, 0x35, 0x34, 0x52, 0x94, 0x46, 0xae, 0x8b, 0xa0, 0x17, + 0x6b, 0x1d, 0x5b, 0xc9, 0x2a, 0x6b, 0x6f, 0x94, 0xdd, 0x84, 0xa4, 0x4f, 0xc1, 0x13, 0x70, 0x45, + 0xe2, 0xcc, 0x43, 0x70, 0xac, 0x38, 0x71, 0x03, 0x25, 0x2f, 0x82, 0x76, 0x5d, 0x0c, 0x69, 0x9b, + 0x4b, 0x6f, 0x9e, 0xf9, 0x7f, 0x7f, 0x33, 0xb3, 0xfa, 0xa1, 0xc2, 0xc2, 0xc4, 0x16, 0x92, 0x0c, + 0x69, 0xda, 0xb7, 0xa7, 0x0d, 0x9b, 0x4c, 0xe4, 0xe0, 0x1c, 0x8f, 0xc6, 0x5c, 0x72, 0xb4, 0xc9, + 0xc2, 0x04, 0x5f, 0x6a, 0x78, 0xda, 0xa8, 0x3c, 0xee, 0xf3, 0x3e, 0xd7, 0x92, 0xad, 0xbe, 0x32, + 0x57, 0xe5, 0x69, 0x8f, 0x8b, 0x84, 0x8b, 0x20, 0x13, 0xb2, 0xe2, 0x52, 0x7a, 0xa2, 0xe0, 0x21, + 0x11, 0xb1, 0x22, 0xf7, 0x38, 0x4d, 0xb3, 0x7e, 0xf5, 0x4b, 0x01, 0xd0, 0x89, 0x24, 0xc3, 0xd8, + 0x99, 0xc8, 0x01, 0x1f, 0xd3, 0x73, 0x22, 0x29, 0x4f, 0xd1, 0x7b, 0x80, 0x84, 0xcc, 0x02, 0xc9, + 0x87, 0x71, 0x2a, 0xca, 0xe6, 0x8e, 0x59, 0x7b, 0xb0, 0x5f, 0xc2, 0x6a, 0x09, 0xc5, 0xc0, 0xd3, + 0x06, 0x3e, 0xe0, 0x34, 0x6d, 0xee, 0x7d, 0xfd, 0xb5, 0x5d, 0xed, 0x53, 0x39, 0x98, 0x84, 0xb8, + 0xc7, 0x13, 0x9b, 0xd1, 0x34, 0xb6, 0x59, 0x98, 0xd4, 0x45, 0x34, 0xb4, 0xe5, 0x7c, 0x14, 0x0b, + 0xed, 0xf3, 0x8a, 0x09, 0x99, 0xf9, 0x9a, 0x85, 0x3a, 0x00, 0x84, 0x31, 0xfe, 0x31, 0x60, 0x54, + 0xc8, 0xf2, 0x86, 0x26, 0xd7, 0xf1, 0xea, 0x79, 0xf8, 0xfa, 0x46, 0xf8, 0x1d, 0x61, 0x34, 0x22, + 0x92, 0x8f, 0xc5, 0x91, 0xe1, 0x15, 0x35, 0xa2, 0x4d, 0x85, 0x44, 0x6d, 0x28, 0x46, 0x71, 0x3a, + 0xcf, 0x70, 0x85, 0xdb, 0xe1, 0xee, 0x2b, 0x82, 0xa6, 0x75, 0x01, 0x91, 0xff, 0x7d, 0x81, 0x3a, + 0xa2, 0x7c, 0x67, 0xc7, 0xac, 0x6d, 0xee, 0xef, 0x5e, 0xc5, 0xae, 0x10, 0xfd, 0xf9, 0x28, 0xf6, + 0x4a, 0xe4, 0x6a, 0xab, 0xb2, 0x07, 0xf0, 0x6f, 0x16, 0x2a, 0xc3, 0x3d, 0x12, 0x45, 0xe3, 0x58, + 0xa8, 0x47, 0x2d, 0xd4, 0x8a, 0xde, 0xdf, 0xf2, 0x75, 0xe9, 0xc7, 0xb7, 0xfa, 0xa3, 0x15, 0x62, + 0xf3, 0x21, 0xc0, 0x34, 0xff, 0xf5, 0xe5, 0x67, 0x13, 0x4a, 0xd7, 0x26, 0xa2, 0x2a, 0x58, 0xce, + 0xa9, 0x7f, 0x74, 0xec, 0xb5, 0xce, 0x1c, 0xbf, 0x75, 0xdc, 0x09, 0xfc, 0x0f, 0x5d, 0x37, 0x38, + 0xed, 0x9c, 0x74, 0xdd, 0x83, 0xd6, 0x9b, 0x96, 0x7b, 0xb8, 0x65, 0xa0, 0x6d, 0x78, 0x76, 0x83, + 0xe7, 0xd0, 0x6d, 0xbb, 0x6f, 0x1d, 0xdf, 0xdd, 0x32, 0xd1, 0x2e, 0x3c, 0xbf, 0x11, 0x92, 0x5b, + 0x36, 0xd6, 0x58, 0x3c, 0x37, 0xb7, 0x14, 0x9a, 0xce, 0xf7, 0x85, 0x65, 0x5e, 0x2c, 0x2c, 0xf3, + 0xf7, 0xc2, 0x32, 0x3f, 0x2d, 0x2d, 0xe3, 0x62, 0x69, 0x19, 0x3f, 0x97, 0x96, 0x71, 0xf6, 0x62, + 0x5d, 0x44, 0x66, 0x79, 0xde, 0x75, 0x58, 0xc2, 0xbb, 0x3a, 0x94, 0xaf, 0xfe, 0x04, 0x00, 0x00, + 0xff, 0xff, 0x99, 0x34, 0x31, 0xbf, 0x0b, 0x03, 0x00, 0x00, +} + +func (m *StakeAuthorization) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *StakeAuthorization) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *StakeAuthorization) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.AuthorizationType != 0 { + i = encodeVarintAuthz(dAtA, i, uint64(m.AuthorizationType)) + i-- + dAtA[i] = 0x20 + } + if m.Validators != nil { + { + size := m.Validators.Size() + i -= size + if _, err := m.Validators.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + } + } + if m.MaxTokens != nil { + { + size, err := m.MaxTokens.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintAuthz(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *StakeAuthorization_AllowList) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *StakeAuthorization_AllowList) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + if m.AllowList != nil { + { + size, err := m.AllowList.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintAuthz(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + return len(dAtA) - i, nil +} +func (m *StakeAuthorization_DenyList) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *StakeAuthorization_DenyList) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + if m.DenyList != nil { + { + size, err := m.DenyList.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintAuthz(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + } + return len(dAtA) - i, nil +} +func (m *StakeAuthorization_Validators) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *StakeAuthorization_Validators) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *StakeAuthorization_Validators) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Address) > 0 { + for iNdEx := len(m.Address) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.Address[iNdEx]) + copy(dAtA[i:], m.Address[iNdEx]) + i = encodeVarintAuthz(dAtA, i, uint64(len(m.Address[iNdEx]))) + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func encodeVarintAuthz(dAtA []byte, offset int, v uint64) int { + offset -= sovAuthz(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *StakeAuthorization) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.MaxTokens != nil { + l = m.MaxTokens.Size() + n += 1 + l + sovAuthz(uint64(l)) + } + if m.Validators != nil { + n += m.Validators.Size() + } + if m.AuthorizationType != 0 { + n += 1 + sovAuthz(uint64(m.AuthorizationType)) + } + return n +} + +func (m *StakeAuthorization_AllowList) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.AllowList != nil { + l = m.AllowList.Size() + n += 1 + l + sovAuthz(uint64(l)) + } + return n +} +func (m *StakeAuthorization_DenyList) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.DenyList != nil { + l = m.DenyList.Size() + n += 1 + l + sovAuthz(uint64(l)) + } + return n +} +func (m *StakeAuthorization_Validators) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.Address) > 0 { + for _, s := range m.Address { + l = len(s) + n += 1 + l + sovAuthz(uint64(l)) + } + } + return n +} + +func sovAuthz(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozAuthz(x uint64) (n int) { + return sovAuthz(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *StakeAuthorization) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAuthz + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: StakeAuthorization: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: StakeAuthorization: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field MaxTokens", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAuthz + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthAuthz + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthAuthz + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.MaxTokens == nil { + m.MaxTokens = &types.Coin{} + } + if err := m.MaxTokens.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field AllowList", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAuthz + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthAuthz + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthAuthz + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + v := &StakeAuthorization_Validators{} + if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + m.Validators = &StakeAuthorization_AllowList{v} + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field DenyList", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAuthz + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthAuthz + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthAuthz + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + v := &StakeAuthorization_Validators{} + if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + m.Validators = &StakeAuthorization_DenyList{v} + iNdEx = postIndex + case 4: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field AuthorizationType", wireType) + } + m.AuthorizationType = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAuthz + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.AuthorizationType |= AuthorizationType(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipAuthz(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthAuthz + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *StakeAuthorization_Validators) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAuthz + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: Validators: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Validators: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Address", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAuthz + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthAuthz + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthAuthz + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Address = append(m.Address, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipAuthz(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthAuthz + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipAuthz(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowAuthz + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowAuthz + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowAuthz + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthAuthz + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupAuthz + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthAuthz + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthAuthz = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowAuthz = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupAuthz = fmt.Errorf("proto: unexpected end of group") +) diff --git a/x/staking/types/authz_test.go b/x/staking/types/authz_test.go new file mode 100644 index 0000000000..d425dc358d --- /dev/null +++ b/x/staking/types/authz_test.go @@ -0,0 +1,267 @@ +package types_test + +import ( + "testing" + + "github.com/stretchr/testify/require" + + ocproto "github.com/line/ostracon/proto/ostracon/types" + + "github.com/line/lbm-sdk/simapp" + sdk "github.com/line/lbm-sdk/types" + stakingtypes "github.com/line/lbm-sdk/x/staking/types" +) + +var ( + coin100 = sdk.NewInt64Coin("steak", 100) + coin50 = sdk.NewInt64Coin("steak", 50) + delAddr = sdk.AccAddress("_____delegator _____") + val1 = sdk.ValAddress("_____validator1_____") + val2 = sdk.ValAddress("_____validator2_____") + val3 = sdk.ValAddress("_____validator3_____") +) + +func TestAuthzAuthorizations(t *testing.T) { + app := simapp.Setup(false) + ctx := app.BaseApp.NewContext(false, ocproto.Header{}) + + // verify ValidateBasic returns error for the AUTHORIZATION_TYPE_UNSPECIFIED authorization type + delAuth, err := stakingtypes.NewStakeAuthorization([]sdk.ValAddress{val1, val2}, []sdk.ValAddress{}, stakingtypes.AuthorizationType_AUTHORIZATION_TYPE_UNSPECIFIED, &coin100) + require.NoError(t, err) + require.Error(t, delAuth.ValidateBasic()) + + // verify MethodName + delAuth, err = stakingtypes.NewStakeAuthorization([]sdk.ValAddress{val1, val2}, []sdk.ValAddress{}, stakingtypes.AuthorizationType_AUTHORIZATION_TYPE_DELEGATE, &coin100) + require.NoError(t, err) + require.Equal(t, delAuth.MsgTypeURL(), sdk.MsgTypeURL(&stakingtypes.MsgDelegate{})) + + // error both allow & deny list + _, err = stakingtypes.NewStakeAuthorization([]sdk.ValAddress{val1, val2}, []sdk.ValAddress{val1}, stakingtypes.AuthorizationType_AUTHORIZATION_TYPE_DELEGATE, &coin100) + require.Error(t, err) + + // verify MethodName + undelAuth, _ := stakingtypes.NewStakeAuthorization([]sdk.ValAddress{val1, val2}, []sdk.ValAddress{}, stakingtypes.AuthorizationType_AUTHORIZATION_TYPE_UNDELEGATE, &coin100) + require.Equal(t, undelAuth.MsgTypeURL(), sdk.MsgTypeURL(&stakingtypes.MsgUndelegate{})) + + // verify MethodName + beginRedelAuth, _ := stakingtypes.NewStakeAuthorization([]sdk.ValAddress{val1, val2}, []sdk.ValAddress{}, stakingtypes.AuthorizationType_AUTHORIZATION_TYPE_REDELEGATE, &coin100) + require.Equal(t, beginRedelAuth.MsgTypeURL(), sdk.MsgTypeURL(&stakingtypes.MsgBeginRedelegate{})) + + validators1_2 := []string{val1.String(), val2.String()} + + testCases := []struct { + msg string + allowed []sdk.ValAddress + denied []sdk.ValAddress + msgType stakingtypes.AuthorizationType + limit *sdk.Coin + srvMsg sdk.Msg + expectErr bool + isDelete bool + updatedAuthorization *stakingtypes.StakeAuthorization + }{ + { + "delegate: expect 0 remaining coins", + []sdk.ValAddress{val1, val2}, + []sdk.ValAddress{}, + stakingtypes.AuthorizationType_AUTHORIZATION_TYPE_DELEGATE, + &coin100, + stakingtypes.NewMsgDelegate(delAddr, val1, coin100), + false, + true, + nil, + }, + { + "delegate: verify remaining coins", + []sdk.ValAddress{val1, val2}, + []sdk.ValAddress{}, + stakingtypes.AuthorizationType_AUTHORIZATION_TYPE_DELEGATE, + &coin100, + stakingtypes.NewMsgDelegate(delAddr, val1, coin50), + false, + false, + &stakingtypes.StakeAuthorization{ + Validators: &stakingtypes.StakeAuthorization_AllowList{ + AllowList: &stakingtypes.StakeAuthorization_Validators{Address: validators1_2}, + }, MaxTokens: &coin50, AuthorizationType: stakingtypes.AuthorizationType_AUTHORIZATION_TYPE_DELEGATE}, + }, + { + "delegate: testing with invalid validator", + []sdk.ValAddress{val1, val2}, + []sdk.ValAddress{}, + stakingtypes.AuthorizationType_AUTHORIZATION_TYPE_DELEGATE, + &coin100, + stakingtypes.NewMsgDelegate(delAddr, val3, coin100), + true, + false, + nil, + }, + { + "delegate: testing delegate without spent limit", + []sdk.ValAddress{val1, val2}, + []sdk.ValAddress{}, + stakingtypes.AuthorizationType_AUTHORIZATION_TYPE_DELEGATE, + nil, + stakingtypes.NewMsgDelegate(delAddr, val2, coin100), + false, + false, + &stakingtypes.StakeAuthorization{ + Validators: &stakingtypes.StakeAuthorization_AllowList{ + AllowList: &stakingtypes.StakeAuthorization_Validators{Address: validators1_2}, + }, MaxTokens: nil, AuthorizationType: stakingtypes.AuthorizationType_AUTHORIZATION_TYPE_DELEGATE}, + }, + { + "delegate: fail validator denied", + []sdk.ValAddress{}, + []sdk.ValAddress{val1}, + stakingtypes.AuthorizationType_AUTHORIZATION_TYPE_DELEGATE, + nil, + stakingtypes.NewMsgDelegate(delAddr, val1, coin100), + true, + false, + nil, + }, + + { + "undelegate: expect 0 remaining coins", + []sdk.ValAddress{val1, val2}, + []sdk.ValAddress{}, + stakingtypes.AuthorizationType_AUTHORIZATION_TYPE_UNDELEGATE, + &coin100, + stakingtypes.NewMsgUndelegate(delAddr, val1, coin100), + false, + true, + nil, + }, + { + "undelegate: verify remaining coins", + []sdk.ValAddress{val1, val2}, + []sdk.ValAddress{}, + stakingtypes.AuthorizationType_AUTHORIZATION_TYPE_UNDELEGATE, + &coin100, + stakingtypes.NewMsgUndelegate(delAddr, val1, coin50), + false, + false, + &stakingtypes.StakeAuthorization{ + Validators: &stakingtypes.StakeAuthorization_AllowList{ + AllowList: &stakingtypes.StakeAuthorization_Validators{Address: validators1_2}, + }, MaxTokens: &coin50, AuthorizationType: stakingtypes.AuthorizationType_AUTHORIZATION_TYPE_UNDELEGATE}, + }, + { + "undelegate: testing with invalid validator", + []sdk.ValAddress{val1, val2}, + []sdk.ValAddress{}, + stakingtypes.AuthorizationType_AUTHORIZATION_TYPE_UNDELEGATE, + &coin100, + stakingtypes.NewMsgUndelegate(delAddr, val3, coin100), + true, + false, + nil, + }, + { + "undelegate: testing delegate without spent limit", + []sdk.ValAddress{val1, val2}, + []sdk.ValAddress{}, + stakingtypes.AuthorizationType_AUTHORIZATION_TYPE_UNDELEGATE, + nil, + stakingtypes.NewMsgUndelegate(delAddr, val2, coin100), + false, + false, + &stakingtypes.StakeAuthorization{ + Validators: &stakingtypes.StakeAuthorization_AllowList{ + AllowList: &stakingtypes.StakeAuthorization_Validators{Address: validators1_2}, + }, MaxTokens: nil, AuthorizationType: stakingtypes.AuthorizationType_AUTHORIZATION_TYPE_UNDELEGATE}, + }, + { + "undelegate: fail cannot undelegate, permission denied", + []sdk.ValAddress{}, + []sdk.ValAddress{val1}, + stakingtypes.AuthorizationType_AUTHORIZATION_TYPE_UNDELEGATE, + &coin100, + stakingtypes.NewMsgUndelegate(delAddr, val1, coin100), + true, + false, + nil, + }, + + { + "redelegate: expect 0 remaining coins", + []sdk.ValAddress{val1, val2}, + []sdk.ValAddress{}, + stakingtypes.AuthorizationType_AUTHORIZATION_TYPE_REDELEGATE, + &coin100, + stakingtypes.NewMsgUndelegate(delAddr, val1, coin100), + false, + true, + nil, + }, + { + "redelegate: verify remaining coins", + []sdk.ValAddress{val1, val2}, + []sdk.ValAddress{}, + stakingtypes.AuthorizationType_AUTHORIZATION_TYPE_REDELEGATE, + &coin100, + stakingtypes.NewMsgBeginRedelegate(delAddr, val1, val1, coin50), + false, + false, + &stakingtypes.StakeAuthorization{ + Validators: &stakingtypes.StakeAuthorization_AllowList{ + AllowList: &stakingtypes.StakeAuthorization_Validators{Address: validators1_2}, + }, MaxTokens: &coin50, AuthorizationType: stakingtypes.AuthorizationType_AUTHORIZATION_TYPE_REDELEGATE}, + }, + { + "redelegate: testing with invalid validator", + []sdk.ValAddress{val1, val2}, + []sdk.ValAddress{}, + stakingtypes.AuthorizationType_AUTHORIZATION_TYPE_REDELEGATE, + &coin100, + stakingtypes.NewMsgBeginRedelegate(delAddr, val3, val3, coin100), + true, + false, + nil, + }, + { + "redelegate: testing delegate without spent limit", + []sdk.ValAddress{val1, val2}, + []sdk.ValAddress{}, + stakingtypes.AuthorizationType_AUTHORIZATION_TYPE_REDELEGATE, + nil, + stakingtypes.NewMsgBeginRedelegate(delAddr, val2, val2, coin100), + false, + false, + &stakingtypes.StakeAuthorization{ + Validators: &stakingtypes.StakeAuthorization_AllowList{ + AllowList: &stakingtypes.StakeAuthorization_Validators{Address: validators1_2}, + }, MaxTokens: nil, AuthorizationType: stakingtypes.AuthorizationType_AUTHORIZATION_TYPE_REDELEGATE}, + }, + { + "redelegate: fail cannot undelegate, permission denied", + []sdk.ValAddress{}, + []sdk.ValAddress{val1}, + stakingtypes.AuthorizationType_AUTHORIZATION_TYPE_REDELEGATE, + &coin100, + stakingtypes.NewMsgBeginRedelegate(delAddr, val1, val1, coin100), + true, + false, + nil, + }, + } + + for _, tc := range testCases { + tc := tc + t.Run(tc.msg, func(t *testing.T) { + delAuth, err := stakingtypes.NewStakeAuthorization(tc.allowed, tc.denied, tc.msgType, tc.limit) + require.NoError(t, err) + resp, err := delAuth.Accept(ctx, tc.srvMsg) + require.Equal(t, tc.isDelete, resp.Delete) + if tc.expectErr { + require.Error(t, err) + } else { + require.NoError(t, err) + if tc.updatedAuthorization != nil { + require.Equal(t, tc.updatedAuthorization.String(), resp.Updated.String()) + } + } + }) + } +} diff --git a/x/staking/types/codec.go b/x/staking/types/codec.go index 5a5c44c334..69db39dde1 100644 --- a/x/staking/types/codec.go +++ b/x/staking/types/codec.go @@ -6,6 +6,7 @@ import ( cryptocodec "github.com/line/lbm-sdk/crypto/codec" sdk "github.com/line/lbm-sdk/types" "github.com/line/lbm-sdk/types/msgservice" + "github.com/line/lbm-sdk/x/authz" ) // RegisterLegacyAminoCodec registers the necessary x/staking interfaces and concrete types @@ -27,6 +28,10 @@ func RegisterInterfaces(registry types.InterfaceRegistry) { &MsgUndelegate{}, &MsgBeginRedelegate{}, ) + registry.RegisterImplementations( + (*authz.Authorization)(nil), + &StakeAuthorization{}, + ) msgservice.RegisterMsgServiceDesc(registry, &_Msg_serviceDesc) } diff --git a/x/staking/types/delegation.go b/x/staking/types/delegation.go index 59f16281a1..2ffc720362 100644 --- a/x/staking/types/delegation.go +++ b/x/staking/types/delegation.go @@ -38,13 +38,13 @@ func NewDelegation(delegatorAddr sdk.AccAddress, validatorAddr sdk.ValAddress, s } // MustMarshalDelegation returns the delegation bytes. Panics if fails -func MustMarshalDelegation(cdc codec.BinaryMarshaler, delegation Delegation) []byte { - return cdc.MustMarshalBinaryBare(&delegation) +func MustMarshalDelegation(cdc codec.BinaryCodec, delegation Delegation) []byte { + return cdc.MustMarshal(&delegation) } // MustUnmarshalDelegation return the unmarshaled delegation from bytes. // Panics if fails. -func MustUnmarshalDelegation(cdc codec.BinaryMarshaler, value []byte) Delegation { +func MustUnmarshalDelegation(cdc codec.BinaryCodec, value []byte) Delegation { delegation, err := UnmarshalDelegation(cdc, value) if err != nil { panic(err) @@ -54,8 +54,8 @@ func MustUnmarshalDelegation(cdc codec.BinaryMarshaler, value []byte) Delegation } // return the delegation -func UnmarshalDelegation(cdc codec.BinaryMarshaler, value []byte) (delegation Delegation, err error) { - err = cdc.UnmarshalBinaryBare(value, &delegation) +func UnmarshalDelegation(cdc codec.BinaryCodec, value []byte) (delegation Delegation, err error) { + err = cdc.Unmarshal(value, &delegation) return delegation, err } @@ -137,12 +137,12 @@ func (ubd *UnbondingDelegation) RemoveEntry(i int64) { } // return the unbonding delegation -func MustMarshalUBD(cdc codec.BinaryMarshaler, ubd UnbondingDelegation) []byte { - return cdc.MustMarshalBinaryBare(&ubd) +func MustMarshalUBD(cdc codec.BinaryCodec, ubd UnbondingDelegation) []byte { + return cdc.MustMarshal(&ubd) } // unmarshal a unbonding delegation from a store value -func MustUnmarshalUBD(cdc codec.BinaryMarshaler, value []byte) UnbondingDelegation { +func MustUnmarshalUBD(cdc codec.BinaryCodec, value []byte) UnbondingDelegation { ubd, err := UnmarshalUBD(cdc, value) if err != nil { panic(err) @@ -152,8 +152,8 @@ func MustUnmarshalUBD(cdc codec.BinaryMarshaler, value []byte) UnbondingDelegati } // unmarshal a unbonding delegation from a store value -func UnmarshalUBD(cdc codec.BinaryMarshaler, value []byte) (ubd UnbondingDelegation, err error) { - err = cdc.UnmarshalBinaryBare(value, &ubd) +func UnmarshalUBD(cdc codec.BinaryCodec, value []byte) (ubd UnbondingDelegation, err error) { + err = cdc.Unmarshal(value, &ubd) return ubd, err } @@ -232,12 +232,12 @@ func (red *Redelegation) RemoveEntry(i int64) { } // MustMarshalRED returns the Redelegation bytes. Panics if fails. -func MustMarshalRED(cdc codec.BinaryMarshaler, red Redelegation) []byte { - return cdc.MustMarshalBinaryBare(&red) +func MustMarshalRED(cdc codec.BinaryCodec, red Redelegation) []byte { + return cdc.MustMarshal(&red) } // MustUnmarshalRED unmarshals a redelegation from a store value. Panics if fails. -func MustUnmarshalRED(cdc codec.BinaryMarshaler, value []byte) Redelegation { +func MustUnmarshalRED(cdc codec.BinaryCodec, value []byte) Redelegation { red, err := UnmarshalRED(cdc, value) if err != nil { panic(err) @@ -247,8 +247,8 @@ func MustUnmarshalRED(cdc codec.BinaryMarshaler, value []byte) Redelegation { } // UnmarshalRED unmarshals a redelegation from a store value -func UnmarshalRED(cdc codec.BinaryMarshaler, value []byte) (red Redelegation, err error) { - err = cdc.UnmarshalBinaryBare(value, &red) +func UnmarshalRED(cdc codec.BinaryCodec, value []byte) (red Redelegation, err error) { + err = cdc.Unmarshal(value, &red) return red, err } diff --git a/x/staking/types/errors.go b/x/staking/types/errors.go index b2b189a8cc..f5db32098d 100644 --- a/x/staking/types/errors.go +++ b/x/staking/types/errors.go @@ -12,49 +12,41 @@ import ( // REF: https://github.com/cosmos/cosmos-sdk/issues/5450 var ( ErrEmptyValidatorAddr = sdkerrors.Register(ModuleName, 2, "empty validator address") - ErrBadValidatorAddr = sdkerrors.Register(ModuleName, 3, "validator address is invalid") - ErrNoValidatorFound = sdkerrors.Register(ModuleName, 4, "validator does not exist") - ErrValidatorOwnerExists = sdkerrors.Register(ModuleName, 5, "validator already exist for this operator address; must use new validator operator address") - ErrValidatorPubKeyExists = sdkerrors.Register(ModuleName, 6, "validator already exist for this pubkey; must use new validator pubkey") - ErrValidatorPubKeyTypeNotSupported = sdkerrors.Register(ModuleName, 7, "validator pubkey type is not supported") - ErrValidatorJailed = sdkerrors.Register(ModuleName, 8, "validator for this address is currently jailed") - ErrBadRemoveValidator = sdkerrors.Register(ModuleName, 9, "failed to remove validator") - ErrCommissionNegative = sdkerrors.Register(ModuleName, 10, "commission must be positive") - ErrCommissionHuge = sdkerrors.Register(ModuleName, 11, "commission cannot be more than 100%") - ErrCommissionGTMaxRate = sdkerrors.Register(ModuleName, 12, "commission cannot be more than the max rate") - ErrCommissionUpdateTime = sdkerrors.Register(ModuleName, 13, "commission cannot be changed more than once in 24h") - ErrCommissionChangeRateNegative = sdkerrors.Register(ModuleName, 14, "commission change rate must be positive") - ErrCommissionChangeRateGTMaxRate = sdkerrors.Register(ModuleName, 15, "commission change rate cannot be more than the max rate") - ErrCommissionGTMaxChangeRate = sdkerrors.Register(ModuleName, 16, "commission cannot be changed more than max change rate") - ErrSelfDelegationBelowMinimum = sdkerrors.Register(ModuleName, 17, "validator's self delegation must be greater than their minimum self delegation") - ErrMinSelfDelegationInvalid = sdkerrors.Register(ModuleName, 18, "minimum self delegation must be a positive integer") - ErrMinSelfDelegationDecreased = sdkerrors.Register(ModuleName, 19, "minimum self delegation cannot be decrease") - ErrEmptyDelegatorAddr = sdkerrors.Register(ModuleName, 20, "empty delegator address") - ErrBadDenom = sdkerrors.Register(ModuleName, 21, "invalid coin denomination") - ErrBadDelegationAddr = sdkerrors.Register(ModuleName, 22, "invalid address for (address, validator) tuple") - ErrBadDelegationAmount = sdkerrors.Register(ModuleName, 23, "invalid delegation amount") - ErrNoDelegation = sdkerrors.Register(ModuleName, 24, "no delegation for (address, validator) tuple") - ErrBadDelegatorAddr = sdkerrors.Register(ModuleName, 25, "delegator does not exist with address") - ErrNoDelegatorForAddress = sdkerrors.Register(ModuleName, 26, "delegator does not contain delegation") - ErrInsufficientShares = sdkerrors.Register(ModuleName, 27, "insufficient delegation shares") - ErrDelegationValidatorEmpty = sdkerrors.Register(ModuleName, 28, "cannot delegate to an empty validator") - ErrNotEnoughDelegationShares = sdkerrors.Register(ModuleName, 29, "not enough delegation shares") - ErrBadSharesAmount = sdkerrors.Register(ModuleName, 30, "invalid shares amount") - ErrBadSharesPercent = sdkerrors.Register(ModuleName, 31, "Invalid shares percent") - ErrNotMature = sdkerrors.Register(ModuleName, 32, "entry not mature") - ErrNoUnbondingDelegation = sdkerrors.Register(ModuleName, 33, "no unbonding delegation found") - ErrMaxUnbondingDelegationEntries = sdkerrors.Register(ModuleName, 34, "too many unbonding delegation entries for (delegator, validator) tuple") - ErrBadRedelegationAddr = sdkerrors.Register(ModuleName, 35, "invalid address for (address, src-validator, dst-validator) tuple") - ErrNoRedelegation = sdkerrors.Register(ModuleName, 36, "no redelegation found") - ErrSelfRedelegation = sdkerrors.Register(ModuleName, 37, "cannot redelegate to the same validator") - ErrTinyRedelegationAmount = sdkerrors.Register(ModuleName, 38, "too few tokens to redelegate (truncates to zero tokens)") - ErrBadRedelegationDst = sdkerrors.Register(ModuleName, 39, "redelegation destination validator not found") - ErrTransitiveRedelegation = sdkerrors.Register(ModuleName, 40, "redelegation to this validator already in progress; first redelegation to this validator must complete before next redelegation") - ErrMaxRedelegationEntries = sdkerrors.Register(ModuleName, 41, "too many redelegation entries for (delegator, src-validator, dst-validator) tuple") - ErrDelegatorShareExRateInvalid = sdkerrors.Register(ModuleName, 42, "cannot delegate to validators with invalid (zero) ex-rate") - ErrBothShareMsgsGiven = sdkerrors.Register(ModuleName, 43, "both shares amount and shares percent provided") - ErrNeitherShareMsgsGiven = sdkerrors.Register(ModuleName, 44, "neither shares amount nor shares percent provided") - ErrInvalidHistoricalInfo = sdkerrors.Register(ModuleName, 45, "invalid historical info") - ErrNoHistoricalInfo = sdkerrors.Register(ModuleName, 46, "no historical info found") - ErrEmptyValidatorPubKey = sdkerrors.Register(ModuleName, 47, "empty validator public key") + ErrNoValidatorFound = sdkerrors.Register(ModuleName, 3, "validator does not exist") + ErrValidatorOwnerExists = sdkerrors.Register(ModuleName, 4, "validator already exist for this operator address; must use new validator operator address") + ErrValidatorPubKeyExists = sdkerrors.Register(ModuleName, 5, "validator already exist for this pubkey; must use new validator pubkey") + ErrValidatorPubKeyTypeNotSupported = sdkerrors.Register(ModuleName, 6, "validator pubkey type is not supported") + ErrValidatorJailed = sdkerrors.Register(ModuleName, 7, "validator for this address is currently jailed") + ErrBadRemoveValidator = sdkerrors.Register(ModuleName, 8, "failed to remove validator") + ErrCommissionNegative = sdkerrors.Register(ModuleName, 9, "commission must be positive") + ErrCommissionHuge = sdkerrors.Register(ModuleName, 10, "commission cannot be more than 100%") + ErrCommissionGTMaxRate = sdkerrors.Register(ModuleName, 11, "commission cannot be more than the max rate") + ErrCommissionUpdateTime = sdkerrors.Register(ModuleName, 12, "commission cannot be changed more than once in 24h") + ErrCommissionChangeRateNegative = sdkerrors.Register(ModuleName, 13, "commission change rate must be positive") + ErrCommissionChangeRateGTMaxRate = sdkerrors.Register(ModuleName, 14, "commission change rate cannot be more than the max rate") + ErrCommissionGTMaxChangeRate = sdkerrors.Register(ModuleName, 15, "commission cannot be changed more than max change rate") + ErrSelfDelegationBelowMinimum = sdkerrors.Register(ModuleName, 16, "validator's self delegation must be greater than their minimum self delegation") + ErrMinSelfDelegationDecreased = sdkerrors.Register(ModuleName, 17, "minimum self delegation cannot be decrease") + ErrEmptyDelegatorAddr = sdkerrors.Register(ModuleName, 18, "empty delegator address") + ErrNoDelegation = sdkerrors.Register(ModuleName, 19, "no delegation for (address, validator) tuple") + ErrBadDelegatorAddr = sdkerrors.Register(ModuleName, 20, "delegator does not exist with address") + ErrNoDelegatorForAddress = sdkerrors.Register(ModuleName, 21, "delegator does not contain delegation") + ErrInsufficientShares = sdkerrors.Register(ModuleName, 22, "insufficient delegation shares") + ErrDelegationValidatorEmpty = sdkerrors.Register(ModuleName, 23, "cannot delegate to an empty validator") + ErrNotEnoughDelegationShares = sdkerrors.Register(ModuleName, 24, "not enough delegation shares") + ErrNotMature = sdkerrors.Register(ModuleName, 25, "entry not mature") + ErrNoUnbondingDelegation = sdkerrors.Register(ModuleName, 26, "no unbonding delegation found") + ErrMaxUnbondingDelegationEntries = sdkerrors.Register(ModuleName, 27, "too many unbonding delegation entries for (delegator, validator) tuple") + ErrNoRedelegation = sdkerrors.Register(ModuleName, 28, "no redelegation found") + ErrSelfRedelegation = sdkerrors.Register(ModuleName, 29, "cannot redelegate to the same validator") + ErrTinyRedelegationAmount = sdkerrors.Register(ModuleName, 30, "too few tokens to redelegate (truncates to zero tokens)") + ErrBadRedelegationDst = sdkerrors.Register(ModuleName, 31, "redelegation destination validator not found") + ErrTransitiveRedelegation = sdkerrors.Register(ModuleName, 32, "redelegation to this validator already in progress; first redelegation to this validator must complete before next redelegation") + ErrMaxRedelegationEntries = sdkerrors.Register(ModuleName, 33, "too many redelegation entries for (delegator, src-validator, dst-validator) tuple") + ErrDelegatorShareExRateInvalid = sdkerrors.Register(ModuleName, 34, "cannot delegate to validators with invalid (zero) ex-rate") + ErrBothShareMsgsGiven = sdkerrors.Register(ModuleName, 35, "both shares amount and shares percent provided") + ErrNeitherShareMsgsGiven = sdkerrors.Register(ModuleName, 36, "neither shares amount nor shares percent provided") + ErrInvalidHistoricalInfo = sdkerrors.Register(ModuleName, 37, "invalid historical info") + ErrNoHistoricalInfo = sdkerrors.Register(ModuleName, 38, "no historical info found") + ErrEmptyValidatorPubKey = sdkerrors.Register(ModuleName, 39, "empty validator public key") ) diff --git a/x/staking/types/events.go b/x/staking/types/events.go index ef0f01aa5c..99a0be1ad6 100644 --- a/x/staking/types/events.go +++ b/x/staking/types/events.go @@ -17,5 +17,6 @@ const ( AttributeKeyDstValidator = "destination_validator" AttributeKeyDelegator = "delegator" AttributeKeyCompletionTime = "completion_time" + AttributeKeyNewShares = "new_shares" AttributeValueCategory = ModuleName ) diff --git a/x/staking/types/expected_keepers.go b/x/staking/types/expected_keepers.go index 27eb012b6f..33b6db580e 100644 --- a/x/staking/types/expected_keepers.go +++ b/x/staking/types/expected_keepers.go @@ -3,7 +3,6 @@ package types import ( sdk "github.com/line/lbm-sdk/types" authtypes "github.com/line/lbm-sdk/x/auth/types" - bankexported "github.com/line/lbm-sdk/x/bank/exported" ) // DistributionKeeper expected distribution keeper (noalias) @@ -28,11 +27,10 @@ type AccountKeeper interface { type BankKeeper interface { GetAllBalances(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins GetBalance(ctx sdk.Context, addr sdk.AccAddress, denom string) sdk.Coin - SetBalances(ctx sdk.Context, addr sdk.AccAddress, balances sdk.Coins) error LockedCoins(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins SpendableCoins(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins - GetSupply(ctx sdk.Context) bankexported.SupplyI + GetSupply(ctx sdk.Context, denom string) sdk.Coin SendCoinsFromModuleToModule(ctx sdk.Context, senderPool, recipientPool string, amt sdk.Coins) error UndelegateCoinsFromModuleToAccount(ctx sdk.Context, senderModule string, recipientAddr sdk.AccAddress, amt sdk.Coins) error @@ -83,7 +81,6 @@ type DelegationSet interface { fn func(index int64, delegation DelegationI) (stop bool)) } -// _______________________________________________________________________________ // Event Hooks // These can be utilized to communicate between a staking keeper and another // keeper which must take particular actions when validators/delegators change diff --git a/x/staking/types/exported.go b/x/staking/types/exported.go index 0ae7e1fb03..98e80a8c5e 100644 --- a/x/staking/types/exported.go +++ b/x/staking/types/exported.go @@ -28,7 +28,7 @@ type ValidatorI interface { GetConsAddr() (sdk.ConsAddress, error) // validation consensus address GetTokens() sdk.Int // validation tokens GetBondedTokens() sdk.Int // validator bonded tokens - GetConsensusPower() int64 // validation power in tendermint + GetConsensusPower(sdk.Int) int64 // validation power in tendermint GetCommission() sdk.Dec // validator commission rate GetMinSelfDelegation() sdk.Int // validator minimum self delegation GetDelegatorShares() sdk.Dec // total outstanding delegator shares diff --git a/x/staking/types/genesis.go b/x/staking/types/genesis.go index e3e3a6fd22..5586d7b21e 100644 --- a/x/staking/types/genesis.go +++ b/x/staking/types/genesis.go @@ -25,7 +25,7 @@ func DefaultGenesisState() *GenesisState { // GetGenesisStateFromAppState returns x/staking GenesisState given raw application // genesis state. -func GetGenesisStateFromAppState(cdc codec.JSONMarshaler, appState map[string]json.RawMessage) *GenesisState { +func GetGenesisStateFromAppState(cdc codec.JSONCodec, appState map[string]json.RawMessage) *GenesisState { var genesisState GenesisState if appState[ModuleName] != nil { diff --git a/x/staking/types/historical_info.go b/x/staking/types/historical_info.go index 857053881a..b3b20b086c 100644 --- a/x/staking/types/historical_info.go +++ b/x/staking/types/historical_info.go @@ -8,14 +8,17 @@ import ( "github.com/line/lbm-sdk/codec" codectypes "github.com/line/lbm-sdk/codec/types" + sdk "github.com/line/lbm-sdk/types" sdkerrors "github.com/line/lbm-sdk/types/errors" ) // NewHistoricalInfo will create a historical information struct from header and valset // it will first sort valset before inclusion into historical info -func NewHistoricalInfo(header ocproto.Header, valSet Validators) HistoricalInfo { - // Must sort in the same way that ostracon does - sort.Sort(ValidatorsByVotingPower(valSet)) +func NewHistoricalInfo(header ocproto.Header, valSet Validators, powerReduction sdk.Int) HistoricalInfo { + // Must sort in the same way that tendermint does + sort.SliceStable(valSet, func(i, j int) bool { + return ValidatorsByVotingPower(valSet).Less(i, j, powerReduction) + }) return HistoricalInfo{ Header: header, @@ -24,7 +27,7 @@ func NewHistoricalInfo(header ocproto.Header, valSet Validators) HistoricalInfo } // MustUnmarshalHistoricalInfo wll unmarshal historical info and panic on error -func MustUnmarshalHistoricalInfo(cdc codec.BinaryMarshaler, value []byte) HistoricalInfo { +func MustUnmarshalHistoricalInfo(cdc codec.BinaryCodec, value []byte) HistoricalInfo { hi, err := UnmarshalHistoricalInfo(cdc, value) if err != nil { panic(err) @@ -34,8 +37,8 @@ func MustUnmarshalHistoricalInfo(cdc codec.BinaryMarshaler, value []byte) Histor } // UnmarshalHistoricalInfo will unmarshal historical info and return any error -func UnmarshalHistoricalInfo(cdc codec.BinaryMarshaler, value []byte) (hi HistoricalInfo, err error) { - err = cdc.UnmarshalBinaryBare(value, &hi) +func UnmarshalHistoricalInfo(cdc codec.BinaryCodec, value []byte) (hi HistoricalInfo, err error) { + err = cdc.Unmarshal(value, &hi) return hi, err } diff --git a/x/staking/types/historical_info_test.go b/x/staking/types/historical_info_test.go index c4ab195968..f559594115 100644 --- a/x/staking/types/historical_info_test.go +++ b/x/staking/types/historical_info_test.go @@ -5,9 +5,11 @@ import ( "sort" "testing" - ocproto "github.com/line/ostracon/proto/ostracon/types" "github.com/stretchr/testify/require" + ocproto "github.com/line/ostracon/proto/ostracon/types" + + sdk "github.com/line/lbm-sdk/types" "github.com/line/lbm-sdk/x/staking/types" ) @@ -26,12 +28,12 @@ func createValidators(t *testing.T) []types.Validator { func TestHistoricalInfo(t *testing.T) { validators := createValidators(t) - hi := types.NewHistoricalInfo(header, validators) + hi := types.NewHistoricalInfo(header, validators, sdk.DefaultPowerReduction) require.True(t, sort.IsSorted(types.Validators(hi.Valset)), "Validators are not sorted") var value []byte require.NotPanics(t, func() { - value = types.ModuleCdc.MustMarshalBinaryBare(&hi) + value = types.ModuleCdc.MustMarshal(&hi) }) require.NotNil(t, value, "Marshalled HistoricalInfo is nil") @@ -67,7 +69,7 @@ func TestValidateBasic(t *testing.T) { err = types.ValidateBasic(hi) require.Error(t, err, "ValidateBasic passed on unsorted ValSet") - hi = types.NewHistoricalInfo(header, validators) + hi = types.NewHistoricalInfo(header, validators, sdk.DefaultPowerReduction) err = types.ValidateBasic(hi) require.NoError(t, err, "ValidateBasic failed on valid HistoricalInfo") } diff --git a/x/staking/types/keys.go b/x/staking/types/keys.go index 78b854eec1..8564497c75 100644 --- a/x/staking/types/keys.go +++ b/x/staking/types/keys.go @@ -5,10 +5,10 @@ import ( "encoding/binary" "fmt" "strconv" - "strings" "time" sdk "github.com/line/lbm-sdk/types" + "github.com/line/lbm-sdk/types/address" ) const ( @@ -51,64 +51,76 @@ var ( AddressDelimiter = "," ) -// gets the key for the validator with address +// GetValidatorKey creates the key for the validator with address // VALUE: staking/Validator func GetValidatorKey(operatorAddr sdk.ValAddress) []byte { - return append(ValidatorsKey, operatorAddr.Bytes()...) + return append(ValidatorsKey, address.MustLengthPrefix(operatorAddr.Bytes())...) } -// gets the key for the validator with pubkey +// GetValidatorByConsAddrKey creates the key for the validator with pubkey // VALUE: validator operator address ([]byte) func GetValidatorByConsAddrKey(addr sdk.ConsAddress) []byte { - return append(ValidatorsByConsAddrKey, addr.Bytes()...) + return append(ValidatorsByConsAddrKey, address.MustLengthPrefix(addr.Bytes())...) } -// Get the validator operator address from LastValidatorPowerKey +// AddressFromValidatorsKey creates the validator operator address from ValidatorsKey +func AddressFromValidatorsKey(key []byte) []byte { + return key[2:] // remove prefix bytes and address length +} + +// AddressFromLastValidatorPowerKey creates the validator operator address from LastValidatorPowerKey func AddressFromLastValidatorPowerKey(key []byte) []byte { - return key[1:] // remove prefix bytes + return key[2:] // remove prefix bytes and address length } -// get the validator by power index. +// GetValidatorsByPowerIndexKey creates the validator by power index. // Power index is the key used in the power-store, and represents the relative // power ranking of the validator. // VALUE: validator operator address ([]byte) -func GetValidatorsByPowerIndexKey(validator Validator) []byte { +func GetValidatorsByPowerIndexKey(validator Validator, powerReduction sdk.Int) []byte { // NOTE the address doesn't need to be stored because counter bytes must always be different // NOTE the larger values are of higher value - consensusPower := sdk.TokensToConsensusPower(validator.Tokens) + consensusPower := sdk.TokensToConsensusPower(validator.Tokens, powerReduction) consensusPowerBytes := make([]byte, 8) binary.BigEndian.PutUint64(consensusPowerBytes, uint64(consensusPower)) powerBytes := consensusPowerBytes powerBytesLen := len(powerBytes) // 8 - // key is of format prefix || powerbytes || addrBytes - key := make([]byte, 1+powerBytesLen) - - key[0] = ValidatorsByPowerIndexKey[0] - copy(key[1:powerBytesLen+1], powerBytes) + err := sdk.ValidateValAddress(validator.OperatorAddress) + if err != nil { + panic(err) + } operAddrInvr := sdk.CopyBytes([]byte(validator.OperatorAddress)) + addrLen := len(operAddrInvr) for i, b := range operAddrInvr { operAddrInvr[i] = ^b } - key = append(key, operAddrInvr...) + // key is of format prefix || powerbytes || addrLen (1byte) || addrBytes + key := make([]byte, 1+powerBytesLen+1+addrLen) + + key[0] = ValidatorsByPowerIndexKey[0] + copy(key[1:powerBytesLen+1], powerBytes) + key[powerBytesLen+1] = byte(addrLen) + copy(key[powerBytesLen+2:], operAddrInvr) return key } -// get the bonded validator index key for an operator address +// GetLastValidatorPowerKey creates the bonded validator index key for an operator address func GetLastValidatorPowerKey(operator sdk.ValAddress) []byte { - return append(LastValidatorPowerKey, operator...) + return append(LastValidatorPowerKey, address.MustLengthPrefix(operator.Bytes())...) } -// parse the validators operator address from power rank key +// ParseValidatorPowerRankKey parses the validators operator address from power rank key func ParseValidatorPowerRankKey(key []byte) (operAddr []byte) { powerBytesLen := 8 - operAddr = sdk.CopyBytes(key[powerBytesLen+1:]) + // key is of format prefix (1 byte) || powerbytes || addrLen (1byte) || addrBytes + operAddr = sdk.CopyBytes(key[powerBytesLen+2:]) for i, b := range operAddr { operAddr[i] = ^b @@ -161,47 +173,51 @@ func ParseValidatorQueueKey(bz []byte) (time.Time, int64, error) { return ts, int64(height), nil } -// gets the key for delegator bond with validator +// GetDelegationKey creates the key for delegator bond with validator // VALUE: staking/Delegation func GetDelegationKey(delAddr sdk.AccAddress, valAddr sdk.ValAddress) []byte { - return append(append(GetDelegationsKey(delAddr), AddressDelimiter...), valAddr.Bytes()...) + return append(GetDelegationsKey(delAddr), address.MustLengthPrefix(valAddr.Bytes())...) } -// gets the prefix for a delegator for all validators +// GetDelegationsKey creates the prefix for a delegator for all validators func GetDelegationsKey(delAddr sdk.AccAddress) []byte { - return append(DelegationKey, delAddr.Bytes()...) + return append(DelegationKey, address.MustLengthPrefix(delAddr.Bytes())...) } -// gets the key for an unbonding delegation by delegator and validator addr +// GetUBDKey creates the key for an unbonding delegation by delegator and validator addr // VALUE: staking/UnbondingDelegation func GetUBDKey(delAddr sdk.AccAddress, valAddr sdk.ValAddress) []byte { - return append(append(GetUBDsKey(delAddr), AddressDelimiter...), valAddr...) + return append(GetUBDsKey(delAddr), address.MustLengthPrefix(valAddr.Bytes())...) } -// gets the index-key for an unbonding delegation, stored by validator-index +// GetUBDByValIndexKey creates the index-key for an unbonding delegation, stored by validator-index // VALUE: none (key rearrangement used) func GetUBDByValIndexKey(delAddr sdk.AccAddress, valAddr sdk.ValAddress) []byte { - return append(append(GetUBDsByValIndexKey(valAddr), AddressDelimiter...), delAddr...) + return append(GetUBDsByValIndexKey(valAddr), address.MustLengthPrefix(delAddr.Bytes())...) } -// rearranges the ValIndexKey to get the UBDKey +// GetUBDKeyFromValIndexKey rearranges the ValIndexKey to get the UBDKey func GetUBDKeyFromValIndexKey(indexKey []byte) []byte { addrs := indexKey[1:] // remove prefix bytes - addresses := strings.Split(string(addrs), AddressDelimiter) - return GetUBDKey(sdk.AccAddress(addresses[1]), sdk.ValAddress(addresses[0])) + + valAddrLen := addrs[0] + valAddr := sdk.ValAddress(addrs[1 : 1+valAddrLen]) + delAddr := sdk.AccAddress(addrs[valAddrLen+2:]) + + return GetUBDKey(delAddr, valAddr) } -// gets the prefix for all unbonding delegations from a delegator +// GetUBDsKey creates the prefix for all unbonding delegations from a delegator func GetUBDsKey(delAddr sdk.AccAddress) []byte { - return append(UnbondingDelegationKey, delAddr.Bytes()...) + return append(UnbondingDelegationKey, address.MustLengthPrefix(delAddr.Bytes())...) } -// gets the prefix keyspace for the indexes of unbonding delegations for a validator +// GetUBDsByValIndexKey creates the prefix keyspace for the indexes of unbonding delegations for a validator func GetUBDsByValIndexKey(valAddr sdk.ValAddress) []byte { - return append(UnbondingDelegationByValIndexKey, valAddr.Bytes()...) + return append(UnbondingDelegationByValIndexKey, address.MustLengthPrefix(valAddr.Bytes())...) } -// gets the prefix for all unbonding delegations from a delegator +// GetUnbondingDelegationTimeKey creates the prefix for all unbonding delegations from a delegator func GetUnbondingDelegationTimeKey(timestamp time.Time) []byte { bz := sdk.FormatTimeBytes(timestamp) return append(UnbondingQueueKey, bz...) @@ -210,60 +226,78 @@ func GetUnbondingDelegationTimeKey(timestamp time.Time) []byte { // GetREDKey returns a key prefix for indexing a redelegation from a delegator // and source validator to a destination validator. func GetREDKey(delAddr sdk.AccAddress, valSrcAddr, valDstAddr sdk.ValAddress) []byte { - key := GetREDsKey(delAddr) + // key is of the form GetREDsKey || valSrcAddrLen (1 byte) || valSrcAddr || valDstAddrLen (1 byte) || valDstAddr + key := make([]byte, 1+3+len(delAddr)+len(valSrcAddr)+len(valDstAddr)) - key = append(append(key, AddressDelimiter...), valSrcAddr...) - key = append(append(key, AddressDelimiter...), valDstAddr...) + copy(key[0:2+len(delAddr)], GetREDsKey(delAddr)) + key[2+len(delAddr)] = byte(len(valSrcAddr)) + copy(key[3+len(delAddr):3+len(delAddr)+len(valSrcAddr)], valSrcAddr.Bytes()) + key[3+len(delAddr)+len(valSrcAddr)] = byte(len(valDstAddr)) + copy(key[4+len(delAddr)+len(valSrcAddr):], valDstAddr.Bytes()) return key } -// gets the index-key for a redelegation, stored by source-validator-index +// GetREDByValSrcIndexKey creates the index-key for a redelegation, stored by source-validator-index // VALUE: none (key rearrangement used) func GetREDByValSrcIndexKey(delAddr sdk.AccAddress, valSrcAddr, valDstAddr sdk.ValAddress) []byte { REDSFromValsSrcKey := GetREDsFromValSrcIndexKey(valSrcAddr) + offset := len(REDSFromValsSrcKey) - // key is of the form REDSFromValsSrcKey || delAddr || valDstAddr - key := append(append(REDSFromValsSrcKey, AddressDelimiter...), delAddr...) - key = append(append(key, AddressDelimiter...), valDstAddr...) + // key is of the form REDSFromValsSrcKey || delAddrLen (1 byte) || delAddr || valDstAddrLen (1 byte) || valDstAddr + key := make([]byte, offset+2+len(delAddr)+len(valDstAddr)) + copy(key[0:offset], REDSFromValsSrcKey) + key[offset] = byte(len(delAddr)) + copy(key[offset+1:offset+1+len(delAddr)], delAddr.Bytes()) + key[offset+1+len(delAddr)] = byte(len(valDstAddr)) + copy(key[offset+2+len(delAddr):], valDstAddr.Bytes()) return key } -// gets the index-key for a redelegation, stored by destination-validator-index +// GetREDByValDstIndexKey creates the index-key for a redelegation, stored by destination-validator-index // VALUE: none (key rearrangement used) func GetREDByValDstIndexKey(delAddr sdk.AccAddress, valSrcAddr, valDstAddr sdk.ValAddress) []byte { REDSToValsDstKey := GetREDsToValDstIndexKey(valDstAddr) + offset := len(REDSToValsDstKey) - // key is of the form REDSToValsDstKey || delAddr || valSrcAddr - key := append(append(REDSToValsDstKey, AddressDelimiter...), delAddr...) - key = append(append(key, AddressDelimiter...), valSrcAddr...) + // key is of the form REDSToValsDstKey || delAddrLen (1 byte) || delAddr || valSrcAddrLen (1 byte) || valSrcAddr + key := make([]byte, offset+2+len(delAddr)+len(valSrcAddr)) + copy(key[0:offset], REDSToValsDstKey) + key[offset] = byte(len(delAddr)) + copy(key[offset+1:offset+1+len(delAddr)], delAddr.Bytes()) + key[offset+1+len(delAddr)] = byte(len(valSrcAddr)) + copy(key[offset+2+len(delAddr):], valSrcAddr.Bytes()) return key } // GetREDKeyFromValSrcIndexKey rearranges the ValSrcIndexKey to get the REDKey func GetREDKeyFromValSrcIndexKey(indexKey []byte) []byte { - // note that first byte is prefix byte - addrs := indexKey[1:] // remove prefix bytes + // note that first byte is prefix byte, which we remove + addrs := indexKey[1:] - addresses := strings.Split(string(addrs), AddressDelimiter) - if len(addresses) != 3 { - panic(fmt.Sprintf("%s does not contain three addresses", addrs)) - } - return GetREDKey(sdk.AccAddress(addresses[1]), sdk.ValAddress(addresses[0]), sdk.ValAddress(addresses[2])) + valSrcAddrLen := addrs[0] + valSrcAddr := sdk.ValAddress(addrs[1 : valSrcAddrLen+1]) + delAddrLen := addrs[valSrcAddrLen+1] + delAddr := sdk.AccAddress(addrs[valSrcAddrLen+2 : valSrcAddrLen+2+delAddrLen]) + valDstAddr := sdk.ValAddress(addrs[valSrcAddrLen+delAddrLen+3:]) + + return GetREDKey(delAddr, valSrcAddr, valDstAddr) } // GetREDKeyFromValDstIndexKey rearranges the ValDstIndexKey to get the REDKey func GetREDKeyFromValDstIndexKey(indexKey []byte) []byte { - // note that first byte is prefix byte - addrs := indexKey[1:] // remove prefix bytes + // note that first byte is prefix byte, which we remove + addrs := indexKey[1:] - addresses := strings.Split(string(addrs), AddressDelimiter) - if len(addresses) != 3 { - panic(fmt.Sprintf("%s does not contain three addresses", addrs)) - } - return GetREDKey(sdk.AccAddress(addresses[1]), sdk.ValAddress(addresses[2]), sdk.ValAddress(addresses[0])) + valDstAddrLen := addrs[0] + valDstAddr := sdk.ValAddress(addrs[1 : valDstAddrLen+1]) + delAddrLen := addrs[valDstAddrLen+1] + delAddr := sdk.AccAddress(addrs[valDstAddrLen+2 : valDstAddrLen+2+delAddrLen]) + valSrcAddr := sdk.ValAddress(addrs[valDstAddrLen+delAddrLen+3:]) + + return GetREDKey(delAddr, valSrcAddr, valDstAddr) } // GetRedelegationTimeKey returns a key prefix for indexing an unbonding @@ -276,25 +310,25 @@ func GetRedelegationTimeKey(timestamp time.Time) []byte { // GetREDsKey returns a key prefix for indexing a redelegation from a delegator // address. func GetREDsKey(delAddr sdk.AccAddress) []byte { - return append(RedelegationKey, delAddr.Bytes()...) + return append(RedelegationKey, address.MustLengthPrefix(delAddr.Bytes())...) } // GetREDsFromValSrcIndexKey returns a key prefix for indexing a redelegation to // a source validator. func GetREDsFromValSrcIndexKey(valSrcAddr sdk.ValAddress) []byte { - return append(RedelegationByValSrcIndexKey, valSrcAddr.Bytes()...) + return append(RedelegationByValSrcIndexKey, address.MustLengthPrefix(valSrcAddr.Bytes())...) } // GetREDsToValDstIndexKey returns a key prefix for indexing a redelegation to a // destination (target) validator. func GetREDsToValDstIndexKey(valDstAddr sdk.ValAddress) []byte { - return append(RedelegationByValDstIndexKey, valDstAddr.Bytes()...) + return append(RedelegationByValDstIndexKey, address.MustLengthPrefix(valDstAddr.Bytes())...) } // GetREDsByDelToValDstIndexKey returns a key prefix for indexing a redelegation // from an address to a source validator. func GetREDsByDelToValDstIndexKey(delAddr sdk.AccAddress, valDstAddr sdk.ValAddress) []byte { - return append(append(GetREDsToValDstIndexKey(valDstAddr), AddressDelimiter...), delAddr.Bytes()...) + return append(GetREDsToValDstIndexKey(valDstAddr), address.MustLengthPrefix(delAddr.Bytes())...) } // GetHistoricalInfoKey returns a key prefix for indexing HistoricalInfo objects. diff --git a/x/staking/types/keys_test.go b/x/staking/types/keys_test.go index 0a9baea7bd..26b1e6889e 100644 --- a/x/staking/types/keys_test.go +++ b/x/staking/types/keys_test.go @@ -28,22 +28,22 @@ func TestGetValidatorPowerRank(t *testing.T) { val1 := newValidator(t, valAddr1, keysPK1) val1.Tokens = sdk.ZeroInt() val2, val3, val4 := val1, val1, val1 - val2.Tokens = sdk.TokensFromConsensusPower(1) - val3.Tokens = sdk.TokensFromConsensusPower(10) + val2.Tokens = sdk.TokensFromConsensusPower(1, sdk.DefaultPowerReduction) + val3.Tokens = sdk.TokensFromConsensusPower(10, sdk.DefaultPowerReduction) x := new(big.Int).Exp(big.NewInt(2), big.NewInt(40), big.NewInt(0)) - val4.Tokens = sdk.TokensFromConsensusPower(x.Int64()) + val4.Tokens = sdk.TokensFromConsensusPower(x.Int64(), sdk.DefaultPowerReduction) tests := []struct { validator types.Validator wantHex string }{ - {val1, "23000000000000000093969194899e93908f9a8dce89cf8b97859889858fc7898bc98ec8868c8b929992c89ec6888998cf8f8f8c9992c6cd9998c6"}, - {val2, "23000000000000000193969194899e93908f9a8dce89cf8b97859889858fc7898bc98ec8868c8b929992c89ec6888998cf8f8f8c9992c6cd9998c6"}, - {val3, "23000000000000000a93969194899e93908f9a8dce89cf8b97859889858fc7898bc98ec8868c8b929992c89ec6888998cf8f8f8c9992c6cd9998c6"}, - {val4, "23000001000000000093969194899e93908f9a8dce89cf8b97859889858fc7898bc98ec8868c8b929992c89ec6888998cf8f8f8c9992c6cd9998c6"}, + {val1, "2300000000000000003293969194899e93908f9a8dce89cf8b97859889858fc7898bc98ec8868c8b929992c89ec6888998cf8f8f8c9992c6cd9998c6"}, + {val2, "2300000000000000013293969194899e93908f9a8dce89cf8b97859889858fc7898bc98ec8868c8b929992c89ec6888998cf8f8f8c9992c6cd9998c6"}, + {val3, "23000000000000000a3293969194899e93908f9a8dce89cf8b97859889858fc7898bc98ec8868c8b929992c89ec6888998cf8f8f8c9992c6cd9998c6"}, + {val4, "2300000100000000003293969194899e93908f9a8dce89cf8b97859889858fc7898bc98ec8868c8b929992c89ec6888998cf8f8f8c9992c6cd9998c6"}, } for i, tt := range tests { - got := hex.EncodeToString(types.GetValidatorsByPowerIndexKey(tt.validator)) + got := hex.EncodeToString(types.GetValidatorsByPowerIndexKey(tt.validator, sdk.DefaultPowerReduction)) require.Equal(t, tt.wantHex, got, "Keys did not match on test case %d", i) } @@ -57,11 +57,11 @@ func TestGetREDByValDstIndexKey(t *testing.T) { wantHex string }{ {sdk.BytesToAccAddress(keysAddr1), sdk.BytesToValAddress(keysAddr1), sdk.BytesToValAddress(keysAddr1), - "366c696e6b76616c6f70657231763074687a67767a703876743671377973746d666d37613977766730707073666d39326667392c6c696e6b31763074687a67767a703876743671377973746d666d376139777667307070736666336735786b2c6c696e6b76616c6f70657231763074687a67767a703876743671377973746d666d37613977766730707073666d3932666739"}, + "36326c696e6b76616c6f70657231763074687a67767a703876743671377973746d666d37613977766730707073666d39326667392b6c696e6b31763074687a67767a703876743671377973746d666d376139777667307070736666336735786b326c696e6b76616c6f70657231763074687a67767a703876743671377973746d666d37613977766730707073666d3932666739"}, {sdk.BytesToAccAddress(keysAddr1), sdk.BytesToValAddress(keysAddr2), sdk.BytesToValAddress(keysAddr3), - "366c696e6b76616c6f7065723138326d7a3772766e736a64376639307a72636c66717961397a757063373364613074633273342c6c696e6b31763074687a67767a703876743671377973746d666d376139777667307070736666336735786b2c6c696e6b76616c6f70657231746d656d74756a75326a3278366a35666c7378736e356833796573353273386a7a37736e7777"}, + "36326c696e6b76616c6f7065723138326d7a3772766e736a64376639307a72636c66717961397a757063373364613074633273342b6c696e6b31763074687a67767a703876743671377973746d666d376139777667307070736666336735786b326c696e6b76616c6f70657231746d656d74756a75326a3278366a35666c7378736e356833796573353273386a7a37736e7777"}, {sdk.BytesToAccAddress(keysAddr2), sdk.BytesToValAddress(keysAddr1), sdk.BytesToValAddress(keysAddr3), - "366c696e6b76616c6f7065723138326d7a3772766e736a64376639307a72636c66717961397a757063373364613074633273342c6c696e6b31746d656d74756a75326a3278366a35666c7378736e356833796573353273386a73326a7771612c6c696e6b76616c6f70657231763074687a67767a703876743671377973746d666d37613977766730707073666d3932666739"}, + "36326c696e6b76616c6f7065723138326d7a3772766e736a64376639307a72636c66717961397a757063373364613074633273342b6c696e6b31746d656d74756a75326a3278366a35666c7378736e356833796573353273386a73326a777161326c696e6b76616c6f70657231763074687a67767a703876743671377973746d666d37613977766730707073666d3932666739"}, } for i, tt := range tests { got := hex.EncodeToString(types.GetREDByValDstIndexKey(tt.delAddr, tt.valSrcAddr, tt.valDstAddr)) @@ -78,11 +78,11 @@ func TestGetREDByValSrcIndexKey(t *testing.T) { wantHex string }{ {sdk.BytesToAccAddress(keysAddr1), sdk.BytesToValAddress(keysAddr1), sdk.BytesToValAddress(keysAddr1), - "356c696e6b76616c6f70657231763074687a67767a703876743671377973746d666d37613977766730707073666d39326667392c6c696e6b31763074687a67767a703876743671377973746d666d376139777667307070736666336735786b2c6c696e6b76616c6f70657231763074687a67767a703876743671377973746d666d37613977766730707073666d3932666739"}, + "35326c696e6b76616c6f70657231763074687a67767a703876743671377973746d666d37613977766730707073666d39326667392b6c696e6b31763074687a67767a703876743671377973746d666d376139777667307070736666336735786b326c696e6b76616c6f70657231763074687a67767a703876743671377973746d666d37613977766730707073666d3932666739"}, {sdk.BytesToAccAddress(keysAddr1), sdk.BytesToValAddress(keysAddr2), sdk.BytesToValAddress(keysAddr3), - "356c696e6b76616c6f70657231746d656d74756a75326a3278366a35666c7378736e356833796573353273386a7a37736e77772c6c696e6b31763074687a67767a703876743671377973746d666d376139777667307070736666336735786b2c6c696e6b76616c6f7065723138326d7a3772766e736a64376639307a72636c66717961397a75706337336461307463327334"}, + "35326c696e6b76616c6f70657231746d656d74756a75326a3278366a35666c7378736e356833796573353273386a7a37736e77772b6c696e6b31763074687a67767a703876743671377973746d666d376139777667307070736666336735786b326c696e6b76616c6f7065723138326d7a3772766e736a64376639307a72636c66717961397a75706337336461307463327334"}, {sdk.BytesToAccAddress(keysAddr2), sdk.BytesToValAddress(keysAddr1), sdk.BytesToValAddress(keysAddr3), - "356c696e6b76616c6f70657231763074687a67767a703876743671377973746d666d37613977766730707073666d39326667392c6c696e6b31746d656d74756a75326a3278366a35666c7378736e356833796573353273386a73326a7771612c6c696e6b76616c6f7065723138326d7a3772766e736a64376639307a72636c66717961397a75706337336461307463327334"}, + "35326c696e6b76616c6f70657231763074687a67767a703876743671377973746d666d37613977766730707073666d39326667392b6c696e6b31746d656d74756a75326a3278366a35666c7378736e356833796573353273386a73326a777161326c696e6b76616c6f7065723138326d7a3772766e736a64376639307a72636c66717961397a75706337336461307463327334"}, } for i, tt := range tests { got := hex.EncodeToString(types.GetREDByValSrcIndexKey(tt.delAddr, tt.valSrcAddr, tt.valDstAddr)) diff --git a/x/staking/types/msg.go b/x/staking/types/msg.go index 0abc0cd98e..0f04e1bb40 100644 --- a/x/staking/types/msg.go +++ b/x/staking/types/msg.go @@ -90,16 +90,16 @@ func (msg MsgCreateValidator) ValidateBasic() error { return ErrEmptyDelegatorAddr } - if msg.ValidatorAddress == "" { - return ErrEmptyValidatorAddr - } - valAddrBytes, err := sdk.ValAddressToBytes(msg.ValidatorAddress) if err != nil { return err } + if len(valAddrBytes) == 0 { + return ErrEmptyValidatorAddr + } + if !bytes.Equal(delAddrBytes, valAddrBytes) { - return ErrBadValidatorAddr + return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "validator address is invalid") } if msg.Pubkey == nil { @@ -107,7 +107,7 @@ func (msg MsgCreateValidator) ValidateBasic() error { } if !msg.Value.IsValid() || !msg.Value.Amount.IsPositive() { - return ErrBadDelegationAmount + return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "invalid delegation amount") } if msg.Description == (Description{}) { @@ -123,7 +123,10 @@ func (msg MsgCreateValidator) ValidateBasic() error { } if !msg.MinSelfDelegation.IsPositive() { - return ErrMinSelfDelegationInvalid + return sdkerrors.Wrap( + sdkerrors.ErrInvalidRequest, + "minimum self delegation must be a positive integer", + ) } if msg.Value.Amount.LT(msg.MinSelfDelegation) { @@ -181,7 +184,10 @@ func (msg MsgEditValidator) ValidateBasic() error { } if msg.MinSelfDelegation != nil && !msg.MinSelfDelegation.IsPositive() { - return ErrMinSelfDelegationInvalid + return sdkerrors.Wrap( + sdkerrors.ErrInvalidRequest, + "minimum self delegation must be a positive integer", + ) } if msg.CommissionRate != nil { @@ -241,7 +247,10 @@ func (msg MsgDelegate) ValidateBasic() error { } if !msg.Amount.IsValid() || !msg.Amount.Amount.IsPositive() { - return ErrBadDelegationAmount + return sdkerrors.Wrap( + sdkerrors.ErrInvalidRequest, + "invalid delegation amount", + ) } return nil @@ -305,7 +314,10 @@ func (msg MsgBeginRedelegate) ValidateBasic() error { } if !msg.Amount.IsValid() || !msg.Amount.Amount.IsPositive() { - return ErrBadSharesAmount + return sdkerrors.Wrap( + sdkerrors.ErrInvalidRequest, + "invalid shares amount", + ) } return nil @@ -359,7 +371,10 @@ func (msg MsgUndelegate) ValidateBasic() error { } if !msg.Amount.IsValid() || !msg.Amount.Amount.IsPositive() { - return ErrBadSharesAmount + return sdkerrors.Wrap( + sdkerrors.ErrInvalidRequest, + "invalid shares amount", + ) } return nil diff --git a/x/staking/types/params.go b/x/staking/types/params.go index 8272571334..0f56fc0bbf 100644 --- a/x/staking/types/params.go +++ b/x/staking/types/params.go @@ -38,6 +38,7 @@ var ( KeyMaxEntries = []byte("MaxEntries") KeyBondDenom = []byte("BondDenom") KeyHistoricalEntries = []byte("HistoricalEntries") + KeyPowerReduction = []byte("PowerReduction") ) var _ paramtypes.ParamSet = (*Params)(nil) @@ -98,7 +99,7 @@ func MustUnmarshalParams(cdc *codec.LegacyAmino, value []byte) Params { // unmarshal the current staking params value from store key func UnmarshalParams(cdc *codec.LegacyAmino, value []byte) (params Params, err error) { - err = cdc.UnmarshalBinaryBare(value, ¶ms) + err = cdc.Unmarshal(value, ¶ms) if err != nil { return } @@ -191,3 +192,16 @@ func validateBondDenom(i interface{}) error { return nil } + +func ValidatePowerReduction(i interface{}) error { + v, ok := i.(sdk.Int) + if !ok { + return fmt.Errorf("invalid parameter type: %T", i) + } + + if v.LT(sdk.NewInt(1)) { + return fmt.Errorf("power reduction cannot be lower than 1") + } + + return nil +} diff --git a/x/staking/types/query.pb.gw.go b/x/staking/types/query.pb.gw.go index 60a17a9d5a..b8ac6ae527 100644 --- a/x/staking/types/query.pb.gw.go +++ b/x/staking/types/query.pb.gw.go @@ -1482,33 +1482,33 @@ func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, clie } var ( - pattern_Query_Validators_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"lbm", "staking", "v1", "validators"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_Query_Validators_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"lbm", "staking", "v1", "validators"}, "", runtime.AssumeColonVerbOpt(false))) - pattern_Query_Validator_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4}, []string{"lbm", "staking", "v1", "validators", "validator_addr"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_Query_Validator_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4}, []string{"lbm", "staking", "v1", "validators", "validator_addr"}, "", runtime.AssumeColonVerbOpt(false))) - pattern_Query_ValidatorDelegations_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4, 2, 5}, []string{"lbm", "staking", "v1", "validators", "validator_addr", "delegations"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_Query_ValidatorDelegations_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4, 2, 5}, []string{"lbm", "staking", "v1", "validators", "validator_addr", "delegations"}, "", runtime.AssumeColonVerbOpt(false))) - pattern_Query_ValidatorUnbondingDelegations_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4, 2, 5}, []string{"lbm", "staking", "v1", "validators", "validator_addr", "unbonding_delegations"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_Query_ValidatorUnbondingDelegations_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4, 2, 5}, []string{"lbm", "staking", "v1", "validators", "validator_addr", "unbonding_delegations"}, "", runtime.AssumeColonVerbOpt(false))) - pattern_Query_Delegation_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4, 2, 5, 1, 0, 4, 1, 5, 6}, []string{"lbm", "staking", "v1", "validators", "validator_addr", "delegations", "delegator_addr"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_Query_Delegation_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4, 2, 5, 1, 0, 4, 1, 5, 6}, []string{"lbm", "staking", "v1", "validators", "validator_addr", "delegations", "delegator_addr"}, "", runtime.AssumeColonVerbOpt(false))) - pattern_Query_UnbondingDelegation_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4, 2, 5, 1, 0, 4, 1, 5, 6, 2, 7}, []string{"lbm", "staking", "v1", "validators", "validator_addr", "delegations", "delegator_addr", "unbonding_delegation"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_Query_UnbondingDelegation_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4, 2, 5, 1, 0, 4, 1, 5, 6, 2, 7}, []string{"lbm", "staking", "v1", "validators", "validator_addr", "delegations", "delegator_addr", "unbonding_delegation"}, "", runtime.AssumeColonVerbOpt(false))) - pattern_Query_DelegatorDelegations_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4}, []string{"lbm", "staking", "v1", "delegations", "delegator_addr"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_Query_DelegatorDelegations_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4}, []string{"lbm", "staking", "v1", "delegations", "delegator_addr"}, "", runtime.AssumeColonVerbOpt(false))) - pattern_Query_DelegatorUnbondingDelegations_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4, 2, 5}, []string{"lbm", "staking", "v1", "delegators", "delegator_addr", "unbonding_delegations"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_Query_DelegatorUnbondingDelegations_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4, 2, 5}, []string{"lbm", "staking", "v1", "delegators", "delegator_addr", "unbonding_delegations"}, "", runtime.AssumeColonVerbOpt(false))) - pattern_Query_Redelegations_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4, 2, 5}, []string{"lbm", "staking", "v1", "delegators", "delegator_addr", "redelegations"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_Query_Redelegations_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4, 2, 5}, []string{"lbm", "staking", "v1", "delegators", "delegator_addr", "redelegations"}, "", runtime.AssumeColonVerbOpt(false))) - pattern_Query_DelegatorValidators_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4, 2, 5}, []string{"lbm", "staking", "v1", "delegators", "delegator_addr", "validators"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_Query_DelegatorValidators_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4, 2, 5}, []string{"lbm", "staking", "v1", "delegators", "delegator_addr", "validators"}, "", runtime.AssumeColonVerbOpt(false))) - pattern_Query_DelegatorValidator_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4, 2, 5, 1, 0, 4, 1, 5, 6}, []string{"lbm", "staking", "v1", "delegators", "delegator_addr", "validators", "validator_addr"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_Query_DelegatorValidator_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4, 2, 5, 1, 0, 4, 1, 5, 6}, []string{"lbm", "staking", "v1", "delegators", "delegator_addr", "validators", "validator_addr"}, "", runtime.AssumeColonVerbOpt(false))) - pattern_Query_HistoricalInfo_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4}, []string{"lbm", "staking", "v1", "historical_info", "height"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_Query_HistoricalInfo_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4}, []string{"lbm", "staking", "v1", "historical_info", "height"}, "", runtime.AssumeColonVerbOpt(false))) - pattern_Query_Pool_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"lbm", "staking", "v1", "pool"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_Query_Pool_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"lbm", "staking", "v1", "pool"}, "", runtime.AssumeColonVerbOpt(false))) - pattern_Query_Params_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"lbm", "staking", "v1", "params"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_Query_Params_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"lbm", "staking", "v1", "params"}, "", runtime.AssumeColonVerbOpt(false))) ) var ( diff --git a/x/staking/types/staking.pb.go b/x/staking/types/staking.pb.go index 98ee3fcc1c..28b25b13bc 100644 --- a/x/staking/types/staking.pb.go +++ b/x/staking/types/staking.pb.go @@ -1257,604 +1257,620 @@ func (this *Pool) Description() (desc *github_com_gogo_protobuf_protoc_gen_gogo_ func StakingDescription() (desc *github_com_gogo_protobuf_protoc_gen_gogo_descriptor.FileDescriptorSet) { d := &github_com_gogo_protobuf_protoc_gen_gogo_descriptor.FileDescriptorSet{} var gzipped = []byte{ - // 9551 bytes of a gzipped FileDescriptorSet - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0xbd, 0x6b, 0x70, 0x1c, 0xd9, - 0x75, 0x18, 0x8c, 0x9e, 0x19, 0x00, 0x33, 0x07, 0x03, 0x60, 0x70, 0x01, 0x82, 0xc3, 0x21, 0x17, - 0x00, 0x7b, 0xb5, 0xbb, 0x5c, 0xee, 0x2e, 0xb0, 0xe4, 0x3e, 0x39, 0xd4, 0x2e, 0x8d, 0x01, 0x86, - 0x20, 0x96, 0x78, 0xa9, 0x01, 0x70, 0xa5, 0x55, 0xa9, 0xe6, 0x6b, 0xcc, 0x5c, 0x0c, 0x7a, 0xd1, - 0xd3, 0xdd, 0xdb, 0xdd, 0x43, 0x12, 0x2b, 0xcb, 0xdf, 0x4a, 0x8a, 0x1d, 0x69, 0x53, 0x8e, 0xf5, - 0x48, 0x95, 0xd7, 0x92, 0xa8, 0xac, 0x2c, 0x27, 0xb2, 0x15, 0xdb, 0x92, 0x12, 0x47, 0xb6, 0x13, - 0x95, 0x4b, 0xfa, 0x61, 0x45, 0x52, 0xaa, 0x52, 0x52, 0xa5, 0xca, 0x51, 0x39, 0x29, 0x4a, 0x5e, - 0xa9, 0x2a, 0x8a, 0xa2, 0xc4, 0x0a, 0x2d, 0xa5, 0x52, 0xa5, 0x3f, 0xa9, 0xfb, 0xea, 0xd7, 0xf4, - 0x3c, 0x40, 0x91, 0x6b, 0x25, 0xce, 0x2f, 0xcc, 0x3d, 0xf7, 0x9c, 0x73, 0xcf, 0x3d, 0xf7, 0xdc, - 0x73, 0xce, 0x7d, 0x35, 0xe0, 0x0b, 0xe7, 0x61, 0xa6, 0x6e, 0x9a, 0x75, 0x1d, 0xcf, 0x59, 0xb6, - 0xe9, 0x9a, 0x3b, 0xcd, 0xdd, 0xb9, 0x1a, 0x76, 0xaa, 0xb6, 0x66, 0xb9, 0xa6, 0x3d, 0x4b, 0x61, - 0x68, 0x94, 0x61, 0xcc, 0x0a, 0x0c, 0x79, 0x15, 0xc6, 0x2e, 0x6a, 0x3a, 0x5e, 0xf4, 0x10, 0x37, - 0xb1, 0x8b, 0x9e, 0x86, 0xd4, 0xae, 0xa6, 0xe3, 0xbc, 0x34, 0x93, 0x3c, 0x35, 0x74, 0xf6, 0x2d, - 0xb3, 0x11, 0xa2, 0xd9, 0x30, 0xc5, 0x06, 0x01, 0x2b, 0x94, 0x42, 0xfe, 0x7e, 0x0a, 0xc6, 0x63, - 0x6a, 0x11, 0x82, 0x94, 0xa1, 0x36, 0x08, 0x47, 0xe9, 0x54, 0x46, 0xa1, 0xbf, 0x51, 0x1e, 0x06, - 0x2d, 0xb5, 0xba, 0xaf, 0xd6, 0x71, 0x3e, 0x41, 0xc1, 0xa2, 0x88, 0xa6, 0x00, 0x6a, 0xd8, 0xc2, - 0x46, 0x0d, 0x1b, 0xd5, 0x83, 0x7c, 0x72, 0x26, 0x79, 0x2a, 0xa3, 0x04, 0x20, 0xe8, 0x21, 0x18, - 0xb3, 0x9a, 0x3b, 0xba, 0x56, 0xad, 0x04, 0xd0, 0x60, 0x26, 0x79, 0xaa, 0x5f, 0xc9, 0xb1, 0x8a, - 0x45, 0x1f, 0xf9, 0x01, 0x18, 0xbd, 0x86, 0xd5, 0xfd, 0x20, 0xea, 0x10, 0x45, 0x1d, 0x21, 0xe0, - 0x00, 0xe2, 0x02, 0x64, 0x1b, 0xd8, 0x71, 0xd4, 0x3a, 0xae, 0xb8, 0x07, 0x16, 0xce, 0xa7, 0x68, - 0xef, 0x67, 0x5a, 0x7a, 0x1f, 0xed, 0xf9, 0x10, 0xa7, 0xda, 0x3a, 0xb0, 0x30, 0x9a, 0x87, 0x0c, - 0x36, 0x9a, 0x0d, 0xc6, 0xa1, 0xbf, 0x8d, 0xfe, 0xca, 0x46, 0xb3, 0x11, 0xe5, 0x92, 0x26, 0x64, - 0x9c, 0xc5, 0xa0, 0x83, 0xed, 0xab, 0x5a, 0x15, 0xe7, 0x07, 0x28, 0x83, 0x07, 0x5a, 0x18, 0x6c, - 0xb2, 0xfa, 0x28, 0x0f, 0x41, 0x87, 0x16, 0x20, 0x83, 0xaf, 0xbb, 0xd8, 0x70, 0x34, 0xd3, 0xc8, - 0x0f, 0x52, 0x26, 0xf7, 0xc5, 0x8c, 0x22, 0xd6, 0x6b, 0x51, 0x16, 0x3e, 0x1d, 0x7a, 0x12, 0x06, - 0x4d, 0xcb, 0xd5, 0x4c, 0xc3, 0xc9, 0xa7, 0x67, 0xa4, 0x53, 0x43, 0x67, 0x4f, 0xc4, 0x1a, 0xc2, - 0x3a, 0xc3, 0x51, 0x04, 0x32, 0x5a, 0x86, 0x9c, 0x63, 0x36, 0xed, 0x2a, 0xae, 0x54, 0xcd, 0x1a, - 0xae, 0x68, 0xc6, 0xae, 0x99, 0xcf, 0x50, 0x06, 0xd3, 0xad, 0x1d, 0xa1, 0x88, 0x0b, 0x66, 0x0d, - 0x2f, 0x1b, 0xbb, 0xa6, 0x32, 0xe2, 0x84, 0xca, 0x68, 0x12, 0x06, 0x9c, 0x03, 0xc3, 0x55, 0xaf, - 0xe7, 0xb3, 0xd4, 0x42, 0x78, 0x49, 0xfe, 0xd3, 0x01, 0x18, 0xed, 0xc5, 0xc4, 0xce, 0x43, 0xff, - 0x2e, 0xe9, 0x65, 0x3e, 0x71, 0x18, 0x1d, 0x30, 0x9a, 0xb0, 0x12, 0x07, 0x6e, 0x53, 0x89, 0xf3, - 0x30, 0x64, 0x60, 0xc7, 0xc5, 0x35, 0x66, 0x11, 0xc9, 0x1e, 0x6d, 0x0a, 0x18, 0x51, 0xab, 0x49, - 0xa5, 0x6e, 0xcb, 0xa4, 0xde, 0x0e, 0xa3, 0x9e, 0x48, 0x15, 0x5b, 0x35, 0xea, 0xc2, 0x36, 0xe7, - 0xba, 0x49, 0x32, 0x5b, 0x16, 0x74, 0x0a, 0x21, 0x53, 0x46, 0x70, 0xa8, 0x8c, 0x16, 0x01, 0x4c, - 0x03, 0x9b, 0xbb, 0x95, 0x1a, 0xae, 0xea, 0xf9, 0x74, 0x1b, 0x2d, 0xad, 0x13, 0x94, 0x16, 0x2d, - 0x99, 0x0c, 0x5a, 0xd5, 0xd1, 0x39, 0xdf, 0xd4, 0x06, 0xdb, 0x58, 0xca, 0x2a, 0x9b, 0x64, 0x2d, - 0xd6, 0xb6, 0x0d, 0x23, 0x36, 0x26, 0x76, 0x8f, 0x6b, 0xbc, 0x67, 0x19, 0x2a, 0xc4, 0x6c, 0xd7, - 0x9e, 0x29, 0x9c, 0x8c, 0x75, 0x6c, 0xd8, 0x0e, 0x16, 0xd1, 0xbd, 0xe0, 0x01, 0x2a, 0xd4, 0xac, - 0x80, 0x7a, 0xa1, 0xac, 0x00, 0xae, 0xa9, 0x0d, 0x5c, 0x78, 0x19, 0x46, 0xc2, 0xea, 0x41, 0x13, - 0xd0, 0xef, 0xb8, 0xaa, 0xed, 0x52, 0x2b, 0xec, 0x57, 0x58, 0x01, 0xe5, 0x20, 0x89, 0x8d, 0x1a, - 0xf5, 0x72, 0xfd, 0x0a, 0xf9, 0x89, 0x7e, 0xc9, 0xef, 0x70, 0x92, 0x76, 0xf8, 0xfe, 0xd6, 0x11, - 0x0d, 0x71, 0x8e, 0xf6, 0xbb, 0xf0, 0x14, 0x0c, 0x87, 0x3a, 0xd0, 0x6b, 0xd3, 0xf2, 0x2f, 0xc3, - 0x91, 0x58, 0xd6, 0xe8, 0xed, 0x30, 0xd1, 0x34, 0x34, 0xc3, 0xc5, 0xb6, 0x65, 0x63, 0x62, 0xb1, - 0xac, 0xa9, 0xfc, 0x7f, 0x1e, 0x6c, 0x63, 0x73, 0xdb, 0x41, 0x6c, 0xc6, 0x45, 0x19, 0x6f, 0xb6, - 0x02, 0x4f, 0x67, 0xd2, 0x3f, 0x18, 0xcc, 0xbd, 0xf2, 0xca, 0x2b, 0xaf, 0x24, 0xe4, 0xaf, 0x0c, - 0xc0, 0x44, 0xdc, 0x9c, 0x89, 0x9d, 0xbe, 0x93, 0x30, 0x60, 0x34, 0x1b, 0x3b, 0xd8, 0xa6, 0x4a, - 0xea, 0x57, 0x78, 0x09, 0xcd, 0x43, 0xbf, 0xae, 0xee, 0x60, 0x3d, 0x9f, 0x9a, 0x91, 0x4e, 0x8d, - 0x9c, 0x7d, 0xa8, 0xa7, 0x59, 0x39, 0xbb, 0x42, 0x48, 0x14, 0x46, 0x89, 0x9e, 0x85, 0x14, 0x77, - 0xd1, 0x84, 0xc3, 0xe9, 0xde, 0x38, 0x90, 0xb9, 0xa4, 0x50, 0x3a, 0x74, 0x1c, 0x32, 0xe4, 0x2f, - 0xb3, 0x8d, 0x01, 0x2a, 0x73, 0x9a, 0x00, 0x88, 0x5d, 0xa0, 0x02, 0xa4, 0xe9, 0x34, 0xa9, 0x61, - 0x11, 0xda, 0xbc, 0x32, 0x31, 0xac, 0x1a, 0xde, 0x55, 0x9b, 0xba, 0x5b, 0xb9, 0xaa, 0xea, 0x4d, - 0x4c, 0x0d, 0x3e, 0xa3, 0x64, 0x39, 0xf0, 0x0a, 0x81, 0xa1, 0x69, 0x18, 0x62, 0xb3, 0x4a, 0x33, - 0x6a, 0xf8, 0x3a, 0xf5, 0x9e, 0xfd, 0x0a, 0x9b, 0x68, 0xcb, 0x04, 0x42, 0x9a, 0x7f, 0xd1, 0x31, - 0x0d, 0x61, 0x9a, 0xb4, 0x09, 0x02, 0xa0, 0xcd, 0x3f, 0x15, 0x75, 0xdc, 0xf7, 0xc4, 0x77, 0xaf, - 0x65, 0x2e, 0x3d, 0x00, 0xa3, 0x14, 0xe3, 0x31, 0x3e, 0xf4, 0xaa, 0x9e, 0x1f, 0x9b, 0x91, 0x4e, - 0xa5, 0x95, 0x11, 0x06, 0x5e, 0xe7, 0x50, 0xf9, 0x8b, 0x09, 0x48, 0x51, 0xc7, 0x32, 0x0a, 0x43, - 0x5b, 0xef, 0xd8, 0x28, 0x57, 0x16, 0xd7, 0xb7, 0x4b, 0x2b, 0xe5, 0x9c, 0x84, 0x46, 0x00, 0x28, - 0xe0, 0xe2, 0xca, 0xfa, 0xfc, 0x56, 0x2e, 0xe1, 0x95, 0x97, 0xd7, 0xb6, 0x9e, 0x7c, 0x3c, 0x97, - 0xf4, 0x08, 0xb6, 0x19, 0x20, 0x15, 0x44, 0x78, 0xec, 0x6c, 0xae, 0x1f, 0xe5, 0x20, 0xcb, 0x18, - 0x2c, 0xbf, 0xbd, 0xbc, 0xf8, 0xe4, 0xe3, 0xb9, 0x81, 0x30, 0xe4, 0xb1, 0xb3, 0xb9, 0x41, 0x34, - 0x0c, 0x19, 0x0a, 0x29, 0xad, 0xaf, 0xaf, 0xe4, 0xd2, 0x1e, 0xcf, 0xcd, 0x2d, 0x65, 0x79, 0x6d, - 0x29, 0x97, 0xf1, 0x78, 0x2e, 0x29, 0xeb, 0xdb, 0x1b, 0x39, 0xf0, 0x38, 0xac, 0x96, 0x37, 0x37, - 0xe7, 0x97, 0xca, 0xb9, 0x21, 0x0f, 0xa3, 0xf4, 0x8e, 0xad, 0xf2, 0x66, 0x2e, 0x1b, 0x12, 0xeb, - 0xb1, 0xb3, 0xb9, 0x61, 0xaf, 0x89, 0xf2, 0xda, 0xf6, 0x6a, 0x6e, 0x04, 0x8d, 0xc1, 0x30, 0x6b, - 0x42, 0x08, 0x31, 0x1a, 0x01, 0x3d, 0xf9, 0x78, 0x2e, 0xe7, 0x0b, 0xc2, 0xb8, 0x8c, 0x85, 0x00, - 0x4f, 0x3e, 0x9e, 0x43, 0xf2, 0x02, 0xf4, 0x53, 0x33, 0x44, 0x08, 0x46, 0x56, 0xe6, 0x4b, 0xe5, - 0x95, 0xca, 0xfa, 0xc6, 0xd6, 0xf2, 0xfa, 0xda, 0xfc, 0x4a, 0x4e, 0xf2, 0x61, 0x4a, 0xf9, 0x6d, - 0xdb, 0xcb, 0x4a, 0x79, 0x31, 0x97, 0x08, 0xc2, 0x36, 0xca, 0xf3, 0x5b, 0xe5, 0xc5, 0x5c, 0x52, - 0xae, 0xc2, 0x44, 0x9c, 0x43, 0x8d, 0x9d, 0x42, 0x01, 0x5b, 0x48, 0xb4, 0xb1, 0x05, 0xca, 0x2b, - 0x6a, 0x0b, 0xf2, 0xf7, 0x12, 0x30, 0x1e, 0x13, 0x54, 0x62, 0x1b, 0xb9, 0x00, 0xfd, 0xcc, 0x96, - 0x59, 0x98, 0x7d, 0x30, 0x36, 0x3a, 0x51, 0xcb, 0x6e, 0x09, 0xb5, 0x94, 0x2e, 0x98, 0x6a, 0x24, - 0xdb, 0xa4, 0x1a, 0x84, 0x45, 0x8b, 0xc1, 0xbe, 0xab, 0xc5, 0xf9, 0xb3, 0xf8, 0xf8, 0x64, 0x2f, - 0xf1, 0x91, 0xc2, 0x0e, 0x17, 0x04, 0xfa, 0x63, 0x82, 0xc0, 0x79, 0x18, 0x6b, 0x61, 0xd4, 0xb3, - 0x33, 0x7e, 0xbf, 0x04, 0xf9, 0x76, 0xca, 0xe9, 0xe2, 0x12, 0x13, 0x21, 0x97, 0x78, 0x3e, 0xaa, - 0xc1, 0x93, 0xed, 0x07, 0xa1, 0x65, 0xac, 0x3f, 0x23, 0xc1, 0x64, 0x7c, 0x4a, 0x19, 0x2b, 0xc3, - 0xb3, 0x30, 0xd0, 0xc0, 0xee, 0x9e, 0x29, 0xd2, 0xaa, 0xfb, 0x63, 0x82, 0x35, 0xa9, 0x8e, 0x0e, - 0x36, 0xa7, 0x0a, 0x46, 0xfb, 0x64, 0xbb, 0xbc, 0x90, 0x49, 0xd3, 0x22, 0xe9, 0x07, 0x13, 0x70, - 0x24, 0x96, 0x79, 0xac, 0xa0, 0xf7, 0x00, 0x68, 0x86, 0xd5, 0x74, 0x59, 0xea, 0xc4, 0x3c, 0x71, - 0x86, 0x42, 0xa8, 0xf3, 0x22, 0x5e, 0xb6, 0xe9, 0x7a, 0xf5, 0x49, 0x5a, 0x0f, 0x0c, 0x44, 0x11, - 0x9e, 0xf6, 0x05, 0x4d, 0x51, 0x41, 0xa7, 0xda, 0xf4, 0xb4, 0xc5, 0x30, 0x1f, 0x85, 0x5c, 0x55, - 0xd7, 0xb0, 0xe1, 0x56, 0x1c, 0xd7, 0xc6, 0x6a, 0x43, 0x33, 0xea, 0x34, 0xd4, 0xa4, 0x8b, 0xfd, - 0xbb, 0xaa, 0xee, 0x60, 0x65, 0x94, 0x55, 0x6f, 0x8a, 0x5a, 0x42, 0x41, 0x0d, 0xc8, 0x0e, 0x50, - 0x0c, 0x84, 0x28, 0x58, 0xb5, 0x47, 0x21, 0x7f, 0x38, 0x03, 0x43, 0x81, 0x04, 0x1c, 0x9d, 0x84, - 0xec, 0x8b, 0xea, 0x55, 0xb5, 0x22, 0x16, 0x55, 0x4c, 0x13, 0x43, 0x04, 0xb6, 0xc1, 0x17, 0x56, - 0x8f, 0xc2, 0x04, 0x45, 0x31, 0x9b, 0x2e, 0xb6, 0x2b, 0x55, 0x5d, 0x75, 0x1c, 0xaa, 0xb4, 0x34, - 0x45, 0x45, 0xa4, 0x6e, 0x9d, 0x54, 0x2d, 0x88, 0x1a, 0xf4, 0x04, 0x8c, 0x53, 0x8a, 0x46, 0x53, - 0x77, 0x35, 0x4b, 0xc7, 0x15, 0xb2, 0xcc, 0x73, 0x68, 0xc8, 0xf1, 0x24, 0x1b, 0x23, 0x18, 0xab, - 0x1c, 0x81, 0x48, 0xe4, 0xa0, 0x45, 0xb8, 0x87, 0x92, 0xd5, 0xb1, 0x81, 0x6d, 0xd5, 0xc5, 0x15, - 0xfc, 0x52, 0x53, 0xd5, 0x9d, 0x8a, 0x6a, 0xd4, 0x2a, 0x7b, 0xaa, 0xb3, 0x97, 0x9f, 0x20, 0x0c, - 0x4a, 0x89, 0xbc, 0xa4, 0x1c, 0x23, 0x88, 0x4b, 0x1c, 0xaf, 0x4c, 0xd1, 0xe6, 0x8d, 0xda, 0x25, - 0xd5, 0xd9, 0x43, 0x45, 0x98, 0xa4, 0x5c, 0x1c, 0xd7, 0xd6, 0x8c, 0x7a, 0xa5, 0xba, 0x87, 0xab, - 0xfb, 0x95, 0xa6, 0xbb, 0xfb, 0x74, 0xfe, 0x78, 0xb0, 0x7d, 0x2a, 0xe1, 0x26, 0xc5, 0x59, 0x20, - 0x28, 0xdb, 0xee, 0xee, 0xd3, 0x68, 0x13, 0xb2, 0x64, 0x30, 0x1a, 0xda, 0xcb, 0xb8, 0xb2, 0x6b, - 0xda, 0x34, 0x86, 0x8e, 0xc4, 0xb8, 0xa6, 0x80, 0x06, 0x67, 0xd7, 0x39, 0xc1, 0xaa, 0x59, 0xc3, - 0xc5, 0xfe, 0xcd, 0x8d, 0x72, 0x79, 0x51, 0x19, 0x12, 0x5c, 0x2e, 0x9a, 0x36, 0x31, 0xa8, 0xba, - 0xe9, 0x29, 0x78, 0x88, 0x19, 0x54, 0xdd, 0x14, 0xea, 0x7d, 0x02, 0xc6, 0xab, 0x55, 0xd6, 0x67, - 0xad, 0x5a, 0xe1, 0x8b, 0x31, 0x27, 0x9f, 0x0b, 0x29, 0xab, 0x5a, 0x5d, 0x62, 0x08, 0xdc, 0xc6, - 0x1d, 0x74, 0x0e, 0x8e, 0xf8, 0xca, 0x0a, 0x12, 0x8e, 0xb5, 0xf4, 0x32, 0x4a, 0xfa, 0x04, 0x8c, - 0x5b, 0x07, 0xad, 0x84, 0x28, 0xd4, 0xa2, 0x75, 0x10, 0x25, 0x7b, 0x0a, 0x26, 0xac, 0x3d, 0xab, - 0x95, 0xee, 0x74, 0x90, 0x0e, 0x59, 0x7b, 0x56, 0x94, 0xf0, 0x3e, 0xba, 0x32, 0xb7, 0x71, 0x55, - 0x75, 0x71, 0x2d, 0x7f, 0x34, 0x88, 0x1e, 0xa8, 0x40, 0xb3, 0x90, 0xab, 0x56, 0x2b, 0xd8, 0x50, - 0x77, 0x74, 0x5c, 0x51, 0x6d, 0x6c, 0xa8, 0x4e, 0x7e, 0x9a, 0x22, 0xa7, 0x5c, 0xbb, 0x89, 0x95, - 0x91, 0x6a, 0xb5, 0x4c, 0x2b, 0xe7, 0x69, 0x1d, 0x3a, 0x0d, 0x63, 0xe6, 0xce, 0x8b, 0x55, 0x66, - 0x91, 0x15, 0xcb, 0xc6, 0xbb, 0xda, 0xf5, 0xfc, 0x5b, 0xa8, 0x7a, 0x47, 0x49, 0x05, 0xb5, 0xc7, - 0x0d, 0x0a, 0x46, 0x0f, 0x42, 0xae, 0xea, 0xec, 0xa9, 0xb6, 0x45, 0x5d, 0xb2, 0x63, 0xa9, 0x55, - 0x9c, 0xbf, 0x8f, 0xa1, 0x32, 0xf8, 0x9a, 0x00, 0x93, 0x19, 0xe1, 0x5c, 0xd3, 0x76, 0x5d, 0xc1, - 0xf1, 0x01, 0x36, 0x23, 0x28, 0x8c, 0x73, 0x3b, 0x05, 0x39, 0xa2, 0x89, 0x50, 0xc3, 0xa7, 0x28, - 0xda, 0x88, 0xb5, 0x67, 0x05, 0xdb, 0xbd, 0x17, 0x86, 0x09, 0xa6, 0xdf, 0xe8, 0x83, 0x2c, 0x71, - 0xb3, 0xf6, 0x02, 0x2d, 0x3e, 0x0e, 0x93, 0x04, 0xa9, 0x81, 0x5d, 0xb5, 0xa6, 0xba, 0x6a, 0x00, - 0xfb, 0x61, 0x8a, 0x4d, 0xd4, 0xbe, 0xca, 0x2b, 0x43, 0x72, 0xda, 0xcd, 0x9d, 0x03, 0xcf, 0xb0, - 0x1e, 0x61, 0x72, 0x12, 0x98, 0x30, 0xad, 0xbb, 0x96, 0x9c, 0xcb, 0x45, 0xc8, 0x06, 0xed, 0x1e, - 0x65, 0x80, 0x59, 0x7e, 0x4e, 0x22, 0x49, 0xd0, 0xc2, 0xfa, 0x22, 0x49, 0x5f, 0x5e, 0x28, 0xe7, - 0x12, 0x24, 0x8d, 0x5a, 0x59, 0xde, 0x2a, 0x57, 0x94, 0xed, 0xb5, 0xad, 0xe5, 0xd5, 0x72, 0x2e, - 0x19, 0x48, 0xec, 0x9f, 0x4b, 0xa5, 0xef, 0xcf, 0x3d, 0x20, 0x7f, 0x2b, 0x01, 0x23, 0xe1, 0x95, - 0x1a, 0x7a, 0x2b, 0x1c, 0x15, 0xdb, 0x2a, 0x0e, 0x76, 0x2b, 0xd7, 0x34, 0x9b, 0x4e, 0xc8, 0x86, - 0xca, 0x82, 0xa3, 0x67, 0x3f, 0x13, 0x1c, 0x6b, 0x13, 0xbb, 0xcf, 0x6b, 0x36, 0x99, 0x6e, 0x0d, - 0xd5, 0x45, 0x2b, 0x30, 0x6d, 0x98, 0x15, 0xc7, 0x55, 0x8d, 0x9a, 0x6a, 0xd7, 0x2a, 0xfe, 0x86, - 0x56, 0x45, 0xad, 0x56, 0xb1, 0xe3, 0x98, 0x2c, 0x10, 0x7a, 0x5c, 0x4e, 0x18, 0xe6, 0x26, 0x47, - 0xf6, 0x23, 0xc4, 0x3c, 0x47, 0x8d, 0x98, 0x6f, 0xb2, 0x9d, 0xf9, 0x1e, 0x87, 0x4c, 0x43, 0xb5, - 0x2a, 0xd8, 0x70, 0xed, 0x03, 0x9a, 0x9f, 0xa7, 0x95, 0x74, 0x43, 0xb5, 0xca, 0xa4, 0xfc, 0xa6, - 0x2c, 0x93, 0x9e, 0x4b, 0xa5, 0xd3, 0xb9, 0xcc, 0x73, 0xa9, 0x74, 0x26, 0x07, 0xf2, 0x1b, 0x49, - 0xc8, 0x06, 0xf3, 0x75, 0xb2, 0xfc, 0xa9, 0xd2, 0x88, 0x25, 0x51, 0x9f, 0x76, 0x6f, 0xc7, 0xec, - 0x7e, 0x76, 0x81, 0x84, 0xb2, 0xe2, 0x00, 0x4b, 0x8e, 0x15, 0x46, 0x49, 0xd2, 0x08, 0x62, 0x6c, - 0x98, 0x25, 0x23, 0x69, 0x85, 0x97, 0xd0, 0x12, 0x0c, 0xbc, 0xe8, 0x50, 0xde, 0x03, 0x94, 0xf7, - 0x5b, 0x3a, 0xf3, 0x7e, 0x6e, 0x93, 0x32, 0xcf, 0x3c, 0xb7, 0x59, 0x59, 0x5b, 0x57, 0x56, 0xe7, - 0x57, 0x14, 0x4e, 0x8e, 0x8e, 0x41, 0x4a, 0x57, 0x5f, 0x3e, 0x08, 0x07, 0x3d, 0x0a, 0xea, 0x75, - 0x10, 0x8e, 0x41, 0xea, 0x1a, 0x56, 0xf7, 0xc3, 0xa1, 0x86, 0x82, 0xee, 0xe2, 0x64, 0x98, 0x83, - 0x7e, 0xaa, 0x2f, 0x04, 0xc0, 0x35, 0x96, 0xeb, 0x43, 0x69, 0x48, 0x2d, 0xac, 0x2b, 0x64, 0x42, - 0xe4, 0x20, 0xcb, 0xa0, 0x95, 0x8d, 0xe5, 0xf2, 0x42, 0x39, 0x97, 0x90, 0x9f, 0x80, 0x01, 0xa6, - 0x04, 0x32, 0x59, 0x3c, 0x35, 0xe4, 0xfa, 0x78, 0x91, 0xf3, 0x90, 0x44, 0xed, 0xf6, 0x6a, 0xa9, - 0xac, 0xe4, 0x12, 0xe1, 0xa1, 0x4e, 0xe5, 0xfa, 0x65, 0x07, 0xb2, 0xc1, 0x3c, 0xfc, 0xcd, 0x59, - 0x8c, 0x7f, 0x59, 0x82, 0xa1, 0x40, 0x5e, 0x4d, 0x12, 0x22, 0x55, 0xd7, 0xcd, 0x6b, 0x15, 0x55, - 0xd7, 0x54, 0x87, 0x9b, 0x06, 0x50, 0xd0, 0x3c, 0x81, 0xf4, 0x3a, 0x74, 0x6f, 0xd2, 0x14, 0xe9, - 0xcf, 0x0d, 0xc8, 0x9f, 0x94, 0x20, 0x17, 0x4d, 0x6c, 0x23, 0x62, 0x4a, 0x7f, 0x9b, 0x62, 0xca, - 0x9f, 0x90, 0x60, 0x24, 0x9c, 0xcd, 0x46, 0xc4, 0x3b, 0xf9, 0xb7, 0x2a, 0xde, 0x77, 0x13, 0x30, - 0x1c, 0xca, 0x61, 0x7b, 0x95, 0xee, 0x25, 0x18, 0xd3, 0x6a, 0xb8, 0x61, 0x99, 0x2e, 0x36, 0xaa, - 0x07, 0x15, 0x1d, 0x5f, 0xc5, 0x7a, 0x5e, 0xa6, 0x4e, 0x63, 0xae, 0x73, 0x96, 0x3c, 0xbb, 0xec, - 0xd3, 0xad, 0x10, 0xb2, 0xe2, 0xf8, 0xf2, 0x62, 0x79, 0x75, 0x63, 0x7d, 0xab, 0xbc, 0xb6, 0xf0, - 0x8e, 0xca, 0xf6, 0xda, 0xe5, 0xb5, 0xf5, 0xe7, 0xd7, 0x94, 0x9c, 0x16, 0x41, 0xbb, 0x8b, 0xd3, - 0x7e, 0x03, 0x72, 0x51, 0xa1, 0xd0, 0x51, 0x88, 0x13, 0x2b, 0xd7, 0x87, 0xc6, 0x61, 0x74, 0x6d, - 0xbd, 0xb2, 0xb9, 0xbc, 0x58, 0xae, 0x94, 0x2f, 0x5e, 0x2c, 0x2f, 0x6c, 0x6d, 0xb2, 0x7d, 0x0f, - 0x0f, 0x7b, 0x2b, 0x34, 0xc1, 0xe5, 0x8f, 0x25, 0x61, 0x3c, 0x46, 0x12, 0x34, 0xcf, 0x57, 0x2c, - 0x6c, 0x11, 0xf5, 0x48, 0x2f, 0xd2, 0xcf, 0x92, 0x9c, 0x61, 0x43, 0xb5, 0x5d, 0xbe, 0xc0, 0x79, - 0x10, 0x88, 0x96, 0x0c, 0x57, 0xdb, 0xd5, 0xb0, 0xcd, 0xf7, 0x93, 0xd8, 0x32, 0x66, 0xd4, 0x87, - 0xb3, 0x2d, 0xa5, 0x87, 0x01, 0x59, 0xa6, 0xa3, 0xb9, 0xda, 0x55, 0x5c, 0xd1, 0x0c, 0xb1, 0xf9, - 0x44, 0x96, 0x35, 0x29, 0x25, 0x27, 0x6a, 0x96, 0x0d, 0xd7, 0xc3, 0x36, 0x70, 0x5d, 0x8d, 0x60, - 0x13, 0x67, 0x9e, 0x54, 0x72, 0xa2, 0xc6, 0xc3, 0x3e, 0x09, 0xd9, 0x9a, 0xd9, 0x24, 0xb9, 0x1e, - 0xc3, 0x23, 0xb1, 0x43, 0x52, 0x86, 0x18, 0xcc, 0x43, 0xe1, 0x59, 0xbc, 0xbf, 0xeb, 0x95, 0x55, - 0x86, 0x18, 0x8c, 0xa1, 0x3c, 0x00, 0xa3, 0x6a, 0xbd, 0x6e, 0x13, 0xe6, 0x82, 0x11, 0x5b, 0x97, - 0x8c, 0x78, 0x60, 0x8a, 0x58, 0x78, 0x0e, 0xd2, 0x42, 0x0f, 0x24, 0x54, 0x13, 0x4d, 0x54, 0x2c, - 0xb6, 0xd8, 0x4e, 0x9c, 0xca, 0x28, 0x69, 0x43, 0x54, 0x9e, 0x84, 0xac, 0xe6, 0x54, 0xfc, 0x4d, - 0xfc, 0xc4, 0x4c, 0xe2, 0x54, 0x5a, 0x19, 0xd2, 0x1c, 0x6f, 0x03, 0x54, 0xfe, 0x4c, 0x02, 0x46, - 0xc2, 0x87, 0x10, 0x68, 0x11, 0xd2, 0xba, 0x59, 0x55, 0xa9, 0x69, 0xb1, 0x13, 0xb0, 0x53, 0x5d, - 0xce, 0x2d, 0x66, 0x57, 0x38, 0xbe, 0xe2, 0x51, 0x16, 0xfe, 0x9d, 0x04, 0x69, 0x01, 0x46, 0x93, - 0x90, 0xb2, 0x54, 0x77, 0x8f, 0xb2, 0xeb, 0x2f, 0x25, 0x72, 0x92, 0x42, 0xcb, 0x04, 0xee, 0x58, - 0xaa, 0x41, 0x4d, 0x80, 0xc3, 0x49, 0x99, 0x8c, 0xab, 0x8e, 0xd5, 0x1a, 0x5d, 0xf4, 0x98, 0x8d, - 0x06, 0x36, 0x5c, 0x47, 0x8c, 0x2b, 0x87, 0x2f, 0x70, 0x30, 0x7a, 0x08, 0xc6, 0x5c, 0x5b, 0xd5, - 0xf4, 0x10, 0x6e, 0x8a, 0xe2, 0xe6, 0x44, 0x85, 0x87, 0x5c, 0x84, 0x63, 0x82, 0x6f, 0x0d, 0xbb, - 0x6a, 0x75, 0x0f, 0xd7, 0x7c, 0xa2, 0x01, 0xba, 0xb9, 0x71, 0x94, 0x23, 0x2c, 0xf2, 0x7a, 0x41, - 0x2b, 0x7f, 0x4b, 0x82, 0x31, 0xb1, 0x4c, 0xab, 0x79, 0xca, 0x5a, 0x05, 0x50, 0x0d, 0xc3, 0x74, - 0x83, 0xea, 0x6a, 0x35, 0xe5, 0x16, 0xba, 0xd9, 0x79, 0x8f, 0x48, 0x09, 0x30, 0x28, 0x34, 0x00, - 0xfc, 0x9a, 0xb6, 0x6a, 0x9b, 0x86, 0x21, 0x7e, 0xc2, 0x44, 0x8f, 0x29, 0xd9, 0xc2, 0x1e, 0x18, - 0x88, 0xac, 0xe7, 0xd0, 0x04, 0xf4, 0xef, 0xe0, 0xba, 0x66, 0xf0, 0x7d, 0x63, 0x56, 0x10, 0xdb, - 0x2f, 0x29, 0x6f, 0xfb, 0xa5, 0xf4, 0x2b, 0x30, 0x5e, 0x35, 0x1b, 0x51, 0x71, 0x4b, 0xb9, 0xc8, - 0xe6, 0x82, 0x73, 0x49, 0x7a, 0xe1, 0x11, 0x8e, 0x54, 0x37, 0x75, 0xd5, 0xa8, 0xcf, 0x9a, 0x76, - 0xdd, 0x3f, 0x66, 0x25, 0x19, 0x8f, 0x13, 0x38, 0x6c, 0xb5, 0x76, 0xfe, 0x97, 0x24, 0xfd, 0x76, - 0x22, 0xb9, 0xb4, 0x51, 0xfa, 0x6c, 0xa2, 0xb0, 0xc4, 0x08, 0x37, 0x84, 0x32, 0x14, 0xbc, 0xab, - 0xe3, 0x2a, 0xe9, 0x20, 0xfc, 0xf0, 0x21, 0x98, 0xa8, 0x9b, 0x75, 0x93, 0x72, 0x9a, 0x23, 0xbf, - 0xf8, 0x39, 0x6d, 0xc6, 0x83, 0x16, 0xba, 0x1e, 0xea, 0x16, 0xd7, 0x60, 0x9c, 0x23, 0x57, 0xe8, - 0x41, 0x11, 0x5b, 0xc6, 0xa0, 0x8e, 0x7b, 0x68, 0xf9, 0x2f, 0x7c, 0x9f, 0x86, 0x6f, 0x65, 0x8c, - 0x93, 0x92, 0x3a, 0xb6, 0xd2, 0x29, 0x2a, 0x70, 0x24, 0xc4, 0x8f, 0x4d, 0x52, 0x6c, 0x77, 0xe1, - 0xf8, 0xe7, 0x9c, 0xe3, 0x78, 0x80, 0xe3, 0x26, 0x27, 0x2d, 0x2e, 0xc0, 0xf0, 0x61, 0x78, 0x7d, - 0x95, 0xf3, 0xca, 0xe2, 0x20, 0x93, 0x25, 0x18, 0xa5, 0x4c, 0xaa, 0x4d, 0xc7, 0x35, 0x1b, 0xd4, - 0x03, 0x76, 0x66, 0xf3, 0x6f, 0xbe, 0xcf, 0x66, 0xcd, 0x08, 0x21, 0x5b, 0xf0, 0xa8, 0x8a, 0x45, - 0xa0, 0x67, 0x63, 0x35, 0x5c, 0xd5, 0xbb, 0x70, 0xf8, 0x1a, 0x17, 0xc4, 0xc3, 0x2f, 0x5e, 0x81, - 0x09, 0xf2, 0x9b, 0x3a, 0xa8, 0xa0, 0x24, 0xdd, 0x37, 0xdc, 0xf2, 0xdf, 0x7a, 0x3f, 0x9b, 0x98, - 0xe3, 0x1e, 0x83, 0x80, 0x4c, 0x81, 0x51, 0xac, 0x63, 0xd7, 0xc5, 0xb6, 0x53, 0x51, 0xf5, 0x38, - 0xf1, 0x02, 0x3b, 0x16, 0xf9, 0xdf, 0xfa, 0x51, 0x78, 0x14, 0x97, 0x18, 0xe5, 0xbc, 0xae, 0x17, - 0xb7, 0xe1, 0x68, 0x8c, 0x55, 0xf4, 0xc0, 0xf3, 0x63, 0x9c, 0xe7, 0x44, 0x8b, 0x65, 0x10, 0xb6, - 0x1b, 0x20, 0xe0, 0xde, 0x58, 0xf6, 0xc0, 0xf3, 0xe3, 0x9c, 0x27, 0xe2, 0xb4, 0x62, 0x48, 0x09, - 0xc7, 0xe7, 0x60, 0xec, 0x2a, 0xb6, 0x77, 0x4c, 0x87, 0xef, 0x12, 0xf5, 0xc0, 0xee, 0x13, 0x9c, - 0xdd, 0x28, 0x27, 0xa4, 0xdb, 0x46, 0x84, 0xd7, 0x39, 0x48, 0xef, 0xaa, 0x55, 0xdc, 0x03, 0x8b, - 0x1b, 0x9c, 0xc5, 0x20, 0xc1, 0x27, 0xa4, 0xf3, 0x90, 0xad, 0x9b, 0x3c, 0x46, 0x75, 0x27, 0xff, - 0x24, 0x27, 0x1f, 0x12, 0x34, 0x9c, 0x85, 0x65, 0x5a, 0x4d, 0x9d, 0x04, 0xb0, 0xee, 0x2c, 0xfe, - 0xb1, 0x60, 0x21, 0x68, 0x38, 0x8b, 0x43, 0xa8, 0xf5, 0x75, 0xc1, 0xc2, 0x09, 0xe8, 0xf3, 0x02, - 0x0c, 0x99, 0x86, 0x7e, 0x60, 0x1a, 0xbd, 0x08, 0xf1, 0x29, 0xce, 0x01, 0x38, 0x09, 0x61, 0x70, - 0x1e, 0x32, 0xbd, 0x0e, 0xc4, 0x3f, 0xf9, 0x91, 0x98, 0x1e, 0x62, 0x04, 0x96, 0x60, 0x54, 0x38, - 0x28, 0xcd, 0x34, 0x7a, 0x60, 0xf1, 0x4f, 0x39, 0x8b, 0x91, 0x00, 0x19, 0xef, 0x86, 0x8b, 0x1d, - 0xb7, 0x8e, 0x7b, 0x61, 0xf2, 0x19, 0xd1, 0x0d, 0x4e, 0xc2, 0x55, 0xb9, 0x83, 0x8d, 0xea, 0x5e, - 0x6f, 0x1c, 0x7e, 0x57, 0xa8, 0x52, 0xd0, 0x10, 0x16, 0x0b, 0x30, 0xdc, 0x50, 0x6d, 0x67, 0x4f, - 0xd5, 0x7b, 0x1a, 0x8e, 0xdf, 0xe3, 0x3c, 0xb2, 0x1e, 0x11, 0xd7, 0x48, 0xd3, 0x38, 0x0c, 0x9b, - 0xcf, 0x0a, 0x8d, 0x04, 0xc8, 0xf8, 0xd4, 0x73, 0x5c, 0xba, 0xa5, 0x76, 0x18, 0x6e, 0xff, 0x4c, - 0x4c, 0x3d, 0x46, 0xbb, 0x1a, 0xe4, 0x78, 0x1e, 0x32, 0x8e, 0xf6, 0x72, 0x4f, 0x6c, 0x7e, 0x5f, - 0x8c, 0x34, 0x25, 0x20, 0xc4, 0xef, 0x80, 0x63, 0xb1, 0x61, 0xa2, 0x07, 0x66, 0x7f, 0xc0, 0x99, - 0x4d, 0xc6, 0x84, 0x0a, 0xee, 0x12, 0x0e, 0xcb, 0xf2, 0x0f, 0x85, 0x4b, 0xc0, 0x11, 0x5e, 0x1b, - 0x64, 0xd5, 0xe0, 0xa8, 0xbb, 0x87, 0xd3, 0xda, 0xe7, 0x84, 0xd6, 0x18, 0x6d, 0x48, 0x6b, 0x5b, - 0x30, 0xc9, 0x39, 0x1e, 0x6e, 0x5c, 0x3f, 0x2f, 0x1c, 0x2b, 0xa3, 0xde, 0x0e, 0x8f, 0xee, 0x3b, - 0xa1, 0xe0, 0xa9, 0x53, 0xa4, 0xa7, 0x4e, 0xa5, 0xa1, 0x5a, 0x3d, 0x70, 0xfe, 0x02, 0xe7, 0x2c, - 0x3c, 0xbe, 0x97, 0xdf, 0x3a, 0xab, 0xaa, 0x45, 0x98, 0xbf, 0x1d, 0xf2, 0x82, 0x79, 0xd3, 0xb0, - 0x71, 0xd5, 0xac, 0x1b, 0xda, 0xcb, 0xb8, 0xd6, 0x03, 0xeb, 0x7f, 0x1e, 0x19, 0xaa, 0xed, 0x00, - 0x39, 0xe1, 0xbc, 0x0c, 0x39, 0x2f, 0x57, 0xa9, 0x68, 0x0d, 0xcb, 0xb4, 0xdd, 0x2e, 0x1c, 0xff, - 0x85, 0x18, 0x29, 0x8f, 0x6e, 0x99, 0x92, 0x15, 0xcb, 0xc0, 0xce, 0x99, 0x7b, 0x35, 0xc9, 0x3f, - 0xe2, 0x8c, 0x86, 0x7d, 0x2a, 0xee, 0x38, 0xaa, 0x66, 0xc3, 0x52, 0xed, 0x5e, 0xfc, 0xdf, 0xbf, - 0x14, 0x8e, 0x83, 0x93, 0x70, 0xc7, 0x41, 0x32, 0x3a, 0x12, 0xed, 0x7b, 0xe0, 0xf0, 0x45, 0xe1, - 0x38, 0x04, 0x0d, 0x67, 0x21, 0x12, 0x86, 0x1e, 0x58, 0xfc, 0xb1, 0x60, 0x21, 0x68, 0x08, 0x8b, - 0xb7, 0xf9, 0x81, 0xd6, 0xc6, 0x75, 0xcd, 0x71, 0x6d, 0x96, 0x14, 0x77, 0x66, 0xf5, 0x27, 0x3f, - 0x0a, 0x27, 0x61, 0x4a, 0x80, 0x94, 0x78, 0x22, 0xbe, 0xc9, 0x4a, 0xd7, 0x4c, 0xdd, 0x05, 0xfb, - 0x53, 0xe1, 0x89, 0x02, 0x64, 0x44, 0xb6, 0x40, 0x86, 0x48, 0xd4, 0x5e, 0x25, 0x2b, 0x85, 0x1e, - 0xd8, 0xfd, 0xab, 0x88, 0x70, 0x9b, 0x82, 0x96, 0xf0, 0x0c, 0xe4, 0x3f, 0x4d, 0x63, 0x1f, 0x1f, - 0xf4, 0x64, 0x9d, 0xff, 0x3a, 0x92, 0xff, 0x6c, 0x33, 0x4a, 0xe6, 0x43, 0x46, 0x23, 0xf9, 0x14, - 0xea, 0x76, 0xab, 0x28, 0xff, 0xde, 0x9f, 0xf0, 0xfe, 0x86, 0xd3, 0xa9, 0xe2, 0x0a, 0x31, 0xf2, - 0x70, 0xd2, 0xd3, 0x9d, 0xd9, 0xfb, 0x7f, 0xe2, 0xd9, 0x79, 0x28, 0xe7, 0x29, 0x5e, 0x84, 0xe1, - 0x50, 0xc2, 0xd3, 0x9d, 0xd5, 0xdf, 0xe3, 0xac, 0xb2, 0xc1, 0x7c, 0xa7, 0xf8, 0x04, 0xa4, 0x48, - 0xf2, 0xd2, 0x9d, 0xfc, 0x57, 0x39, 0x39, 0x45, 0x2f, 0x3e, 0x03, 0x69, 0x91, 0xb4, 0x74, 0x27, - 0xfd, 0x35, 0x4e, 0xea, 0x91, 0x10, 0x72, 0x91, 0xb0, 0x74, 0x27, 0xff, 0xfb, 0x82, 0x5c, 0x90, - 0x10, 0xf2, 0xde, 0x55, 0xf8, 0xe5, 0x7f, 0x90, 0xe2, 0x41, 0x47, 0xe8, 0xee, 0x3c, 0x0c, 0xf2, - 0x4c, 0xa5, 0x3b, 0xf5, 0x07, 0x79, 0xe3, 0x82, 0xa2, 0xf8, 0x14, 0xf4, 0xf7, 0xa8, 0xf0, 0x5f, - 0xe7, 0xa4, 0x0c, 0xbf, 0xb8, 0x00, 0x43, 0x81, 0xec, 0xa4, 0x3b, 0xf9, 0x3f, 0xe4, 0xe4, 0x41, - 0x2a, 0x22, 0x3a, 0xcf, 0x4e, 0xba, 0x33, 0xf8, 0x0d, 0x21, 0x3a, 0xa7, 0x20, 0x6a, 0x13, 0x89, - 0x49, 0x77, 0xea, 0x0f, 0x09, 0xad, 0x0b, 0x92, 0xe2, 0x05, 0xc8, 0x78, 0xc1, 0xa6, 0x3b, 0xfd, - 0x87, 0x39, 0xbd, 0x4f, 0x43, 0x34, 0x10, 0x08, 0x76, 0xdd, 0x59, 0x7c, 0x44, 0x68, 0x20, 0x40, - 0x45, 0xa6, 0x51, 0x34, 0x81, 0xe9, 0xce, 0xe9, 0xa3, 0x62, 0x1a, 0x45, 0xf2, 0x17, 0x32, 0x9a, - 0xd4, 0xe7, 0x77, 0x67, 0xf1, 0x8f, 0xc4, 0x68, 0x52, 0x7c, 0x22, 0x46, 0x34, 0x23, 0xe8, 0xce, - 0xe3, 0x37, 0x85, 0x18, 0x91, 0x84, 0xa0, 0xb8, 0x01, 0xa8, 0x35, 0x1b, 0xe8, 0xce, 0xef, 0x35, - 0xce, 0x6f, 0xac, 0x25, 0x19, 0x28, 0x3e, 0x0f, 0x93, 0xf1, 0x99, 0x40, 0x77, 0xae, 0xbf, 0xf5, - 0x93, 0xc8, 0xda, 0x2d, 0x98, 0x08, 0x14, 0xb7, 0xfc, 0x90, 0x12, 0xcc, 0x02, 0xba, 0xb3, 0xfd, - 0xd8, 0x4f, 0xc2, 0x8e, 0x3b, 0x98, 0x04, 0x14, 0xe7, 0x01, 0xfc, 0x00, 0xdc, 0x9d, 0xd7, 0x27, - 0x38, 0xaf, 0x00, 0x11, 0x99, 0x1a, 0x3c, 0xfe, 0x76, 0xa7, 0xbf, 0x21, 0xa6, 0x06, 0xa7, 0x20, - 0x53, 0x43, 0x84, 0xde, 0xee, 0xd4, 0x9f, 0x14, 0x53, 0x43, 0x90, 0x10, 0xcb, 0x0e, 0x44, 0xb7, - 0xee, 0x1c, 0x3e, 0x25, 0x2c, 0x3b, 0x40, 0x55, 0x5c, 0x83, 0xb1, 0x96, 0x80, 0xd8, 0x9d, 0xd5, - 0x6f, 0x73, 0x56, 0xb9, 0x68, 0x3c, 0x0c, 0x06, 0x2f, 0x1e, 0x0c, 0xbb, 0x73, 0xfb, 0x74, 0x24, - 0x78, 0xf1, 0x58, 0x58, 0x3c, 0x0f, 0x69, 0xa3, 0xa9, 0xeb, 0x64, 0xf2, 0xa0, 0xce, 0x37, 0x01, - 0xf3, 0xff, 0xe5, 0x67, 0x5c, 0x3b, 0x82, 0xa0, 0xf8, 0x04, 0xf4, 0xe3, 0xc6, 0x0e, 0xae, 0x75, - 0xa3, 0xfc, 0xe1, 0xcf, 0x84, 0xc3, 0x24, 0xd8, 0xc5, 0x0b, 0x00, 0x6c, 0x6b, 0x84, 0x1e, 0x06, - 0x76, 0xa1, 0xfd, 0xaf, 0x3f, 0xe3, 0x57, 0x6f, 0x7c, 0x12, 0x9f, 0x01, 0xbb, 0xc8, 0xd3, 0x99, - 0xc1, 0x8f, 0xc2, 0x0c, 0xe8, 0x88, 0x9c, 0x83, 0xc1, 0x17, 0x1d, 0xd3, 0x70, 0xd5, 0x7a, 0x37, - 0xea, 0xff, 0xc6, 0xa9, 0x05, 0x3e, 0x51, 0x58, 0xc3, 0xb4, 0xb1, 0xab, 0xd6, 0x9d, 0x6e, 0xb4, - 0xff, 0x9d, 0xd3, 0x7a, 0x04, 0x84, 0xb8, 0xaa, 0x3a, 0x6e, 0x2f, 0xfd, 0xfe, 0x6b, 0x41, 0x2c, - 0x08, 0x88, 0xd0, 0xe4, 0xf7, 0x3e, 0x3e, 0xe8, 0x46, 0xfb, 0x63, 0x21, 0x34, 0xc7, 0x2f, 0x3e, - 0x03, 0x19, 0xf2, 0x93, 0xdd, 0xa7, 0xeb, 0x42, 0xfc, 0x3f, 0x38, 0xb1, 0x4f, 0x41, 0x5a, 0x76, - 0xdc, 0x9a, 0xab, 0x75, 0x57, 0xf6, 0x2d, 0x3e, 0xd2, 0x02, 0xbf, 0x38, 0x0f, 0x43, 0x8e, 0x5b, - 0xab, 0x35, 0x79, 0x7e, 0xda, 0x85, 0xfc, 0x6f, 0x7e, 0xe6, 0x6d, 0x59, 0x78, 0x34, 0x64, 0xb4, - 0xaf, 0xed, 0xbb, 0x96, 0x49, 0x0f, 0x3c, 0xba, 0x71, 0xf8, 0x09, 0xe7, 0x10, 0x20, 0x29, 0x2e, - 0x40, 0x96, 0xf4, 0xc5, 0xc6, 0x16, 0xa6, 0xa7, 0x53, 0x5d, 0x58, 0xfc, 0x94, 0x2b, 0x20, 0x44, - 0x54, 0x7a, 0xd7, 0xd7, 0xde, 0x98, 0x92, 0xbe, 0xf9, 0xc6, 0x94, 0xf4, 0xdd, 0x37, 0xa6, 0xa4, - 0x0f, 0x7d, 0x6f, 0xaa, 0xef, 0x9b, 0xdf, 0x9b, 0xea, 0xfb, 0xf6, 0xf7, 0xa6, 0xfa, 0xe2, 0x77, - 0x89, 0x61, 0xc9, 0x5c, 0x32, 0xd9, 0xfe, 0xf0, 0x0b, 0x72, 0x5d, 0x73, 0xf7, 0x9a, 0x3b, 0xb3, - 0x55, 0xb3, 0x41, 0xb7, 0x71, 0xfd, 0xdd, 0x5a, 0x6f, 0x91, 0x03, 0x3f, 0x95, 0xc8, 0x82, 0x39, - 0xbc, 0x97, 0xab, 0x1a, 0x07, 0x6d, 0x5e, 0xe6, 0x14, 0x62, 0x37, 0x86, 0xe5, 0xb7, 0x42, 0x72, - 0xde, 0x38, 0x40, 0xc7, 0x98, 0xcf, 0xab, 0x34, 0x6d, 0x9d, 0xdf, 0xf3, 0x1a, 0x24, 0xe5, 0x6d, - 0x5b, 0x47, 0x13, 0xfe, 0x65, 0x4c, 0xe9, 0x54, 0x96, 0xdf, 0xb0, 0x2c, 0xa6, 0x7e, 0xfc, 0xa9, - 0xe9, 0xbe, 0xd2, 0x7e, 0xb4, 0x87, 0x5f, 0xee, 0xda, 0xcb, 0xf4, 0xbc, 0x71, 0x40, 0x3b, 0xb9, - 0x21, 0xbd, 0xd0, 0x4f, 0x37, 0xba, 0xc5, 0xc6, 0xf6, 0x54, 0x74, 0x63, 0xfb, 0x79, 0xac, 0xeb, - 0x97, 0x0d, 0xf3, 0x9a, 0xb1, 0x45, 0xd0, 0x76, 0x06, 0xd8, 0xa5, 0x61, 0xf8, 0x68, 0x02, 0xa6, - 0x5a, 0xf6, 0xb0, 0xf9, 0xc8, 0xb7, 0x7b, 0x96, 0x54, 0x84, 0xf4, 0xa2, 0x30, 0xa8, 0x3c, 0x0c, - 0x3a, 0xb8, 0x6a, 0x1a, 0x35, 0x87, 0x76, 0x35, 0xa9, 0x88, 0x22, 0xe9, 0xaa, 0xa1, 0x1a, 0xa6, - 0xc3, 0xef, 0x42, 0xb2, 0x42, 0xe9, 0xe3, 0xd2, 0xe1, 0xc6, 0x71, 0x58, 0xb4, 0x24, 0xba, 0x79, - 0xa6, 0xeb, 0x56, 0xff, 0x3e, 0xe9, 0xa5, 0xd7, 0x89, 0xd0, 0x76, 0x7f, 0xaf, 0x5a, 0xf9, 0xcd, - 0x04, 0x4c, 0x47, 0xb5, 0x42, 0xa6, 0x93, 0xe3, 0xaa, 0x0d, 0xab, 0x9d, 0x5a, 0xce, 0x43, 0x66, - 0x4b, 0xe0, 0x1c, 0x5a, 0x2f, 0x37, 0x0e, 0xa9, 0x97, 0x11, 0xaf, 0x29, 0xa1, 0x98, 0xb3, 0x3d, - 0x2a, 0xc6, 0xeb, 0xc7, 0x6d, 0x69, 0xe6, 0x7d, 0x49, 0x38, 0x56, 0x35, 0x9d, 0x86, 0xe9, 0x54, - 0x98, 0xf9, 0xb3, 0x02, 0xd7, 0x49, 0x36, 0x58, 0xd5, 0xc3, 0xe1, 0xc8, 0x25, 0x18, 0xa1, 0x2e, - 0x82, 0x6e, 0x0b, 0x53, 0xaf, 0xdc, 0x35, 0x90, 0x7e, 0xfd, 0x2f, 0xfa, 0xe9, 0x94, 0x1a, 0xf6, - 0x08, 0xe9, 0x2d, 0x97, 0x2d, 0x98, 0xd0, 0x1a, 0x96, 0x8e, 0xe9, 0x71, 0x58, 0xc5, 0xab, 0xeb, - 0xce, 0xef, 0x1b, 0x9c, 0xdf, 0xb8, 0x4f, 0xbe, 0x2c, 0xa8, 0x8b, 0x2b, 0x30, 0xa6, 0x56, 0xab, - 0xd8, 0x0a, 0xb1, 0xec, 0xe2, 0xbe, 0x84, 0x80, 0x39, 0x4e, 0xe9, 0x71, 0x2b, 0x5d, 0x68, 0x37, - 0xc4, 0x2f, 0xdc, 0x17, 0xf0, 0x50, 0x36, 0xae, 0x63, 0xe3, 0x11, 0x03, 0xbb, 0xd7, 0x4c, 0x7b, - 0x9f, 0xab, 0xf7, 0x11, 0xd6, 0x94, 0x18, 0x84, 0xbf, 0x4e, 0xc0, 0xa4, 0xbe, 0xd3, 0x98, 0xdb, - 0x51, 0x1d, 0x3c, 0x77, 0xf5, 0xcc, 0x5c, 0xd5, 0xd4, 0xc4, 0x64, 0x1d, 0xd2, 0x77, 0x1a, 0xb3, - 0x04, 0x3e, 0x7b, 0xf5, 0x4c, 0x1b, 0x2f, 0xb5, 0x04, 0xa9, 0x05, 0x53, 0x33, 0x88, 0x21, 0xd6, - 0xb0, 0x61, 0x36, 0xb8, 0x8f, 0x62, 0x05, 0x74, 0x2f, 0x0c, 0xa8, 0x0d, 0xb3, 0x69, 0xb8, 0xec, - 0xe4, 0xae, 0x34, 0xf4, 0xb5, 0x9b, 0xd3, 0x7d, 0x7f, 0x79, 0x73, 0x3a, 0xb9, 0x6c, 0xb8, 0x0a, - 0xaf, 0x2a, 0xa6, 0x7e, 0xf0, 0xfa, 0xb4, 0x24, 0x3f, 0x07, 0x83, 0x8b, 0xb8, 0x7a, 0x3b, 0xbc, - 0x16, 0x71, 0x35, 0xc2, 0xeb, 0x41, 0x48, 0x2f, 0x1b, 0x2e, 0xbb, 0x2d, 0x7c, 0x0f, 0x24, 0x35, - 0x83, 0x5d, 0x40, 0x8b, 0xb4, 0x4f, 0xe0, 0x04, 0x75, 0x11, 0x57, 0x3d, 0xd4, 0x1a, 0xae, 0x46, - 0x51, 0x09, 0x7b, 0x02, 0x2f, 0x5d, 0xf8, 0xf6, 0x5f, 0x4d, 0xf5, 0xbd, 0xf2, 0xc6, 0x54, 0x5f, - 0x5b, 0xcd, 0xdf, 0x13, 0xd0, 0xbc, 0xae, 0x19, 0x78, 0x4e, 0xdf, 0x69, 0x3c, 0xe2, 0xd4, 0xf6, - 0xd9, 0x94, 0xf1, 0x34, 0xfe, 0x5a, 0x0a, 0x8e, 0x93, 0x35, 0xb6, 0x5a, 0x35, 0x8d, 0xb9, 0xaa, - 0x7d, 0x60, 0xb9, 0x34, 0x8a, 0x98, 0xbb, 0xc2, 0x19, 0x88, 0xca, 0x59, 0x56, 0xd9, 0x46, 0xf5, - 0xbb, 0xd0, 0xbf, 0x41, 0xa8, 0x88, 0xbe, 0x5c, 0xd3, 0x55, 0x75, 0xee, 0x1c, 0x58, 0x81, 0x40, - 0xd9, 0x9b, 0x92, 0x04, 0x83, 0x6a, 0xe2, 0x39, 0x89, 0x8e, 0xd5, 0x5d, 0x76, 0x35, 0x37, 0x49, - 0xe3, 0x46, 0x9a, 0x00, 0xe8, 0x2d, 0xdc, 0x09, 0xe8, 0x57, 0x9b, 0xec, 0x54, 0x39, 0x49, 0x02, - 0x0a, 0x2d, 0xc8, 0xcb, 0x30, 0xc8, 0xcf, 0xb6, 0x50, 0x0e, 0x92, 0xfb, 0xf8, 0x80, 0xb6, 0x93, - 0x55, 0xc8, 0x4f, 0xf4, 0x30, 0xf4, 0x53, 0xd1, 0xf9, 0x9b, 0x83, 0xc9, 0xd9, 0x88, 0xec, 0xb3, - 0x54, 0x44, 0x85, 0x21, 0xc9, 0xcf, 0x41, 0x7a, 0xd1, 0x6c, 0x68, 0x86, 0x19, 0xe6, 0x95, 0x61, - 0xbc, 0xa8, 0xc4, 0x56, 0x93, 0x0f, 0xb0, 0xc2, 0x0a, 0x68, 0x12, 0x06, 0xd8, 0x45, 0x6d, 0x7e, - 0x2e, 0xce, 0x4b, 0xf2, 0x02, 0x0c, 0x52, 0xde, 0xeb, 0x16, 0x42, 0xfc, 0x89, 0x0f, 0xbf, 0x11, - 0x4e, 0xe7, 0x3e, 0x67, 0x9f, 0xf0, 0x45, 0x45, 0x90, 0xaa, 0xa9, 0xae, 0xca, 0x7b, 0x4d, 0x7f, - 0xcb, 0x6f, 0x85, 0x34, 0x67, 0xe2, 0xa0, 0x47, 0x21, 0x69, 0x5a, 0x0e, 0x3f, 0xd9, 0xce, 0xc7, - 0x77, 0x64, 0xdd, 0x2a, 0xa5, 0x88, 0x61, 0x28, 0x04, 0xb5, 0x74, 0xa9, 0xad, 0x25, 0xcc, 0x46, - 0x2d, 0xc1, 0x1b, 0x6f, 0x36, 0x8c, 0x91, 0xe1, 0x0f, 0x46, 0xd0, 0x13, 0x5e, 0xdd, 0x55, 0x6c, - 0x93, 0x05, 0x1d, 0xb3, 0x1e, 0x6e, 0x1b, 0x39, 0x4f, 0x2c, 0x5e, 0xdb, 0xc6, 0x38, 0x9e, 0x81, - 0xe4, 0xbc, 0x65, 0xa1, 0x02, 0xa4, 0x69, 0xb9, 0x6a, 0x32, 0xeb, 0x48, 0x29, 0x5e, 0x99, 0xd4, - 0x39, 0xe6, 0xae, 0x7b, 0x4d, 0xb5, 0xbd, 0xb7, 0x4b, 0xa2, 0x2c, 0x9f, 0x83, 0xcc, 0x82, 0x69, - 0x38, 0xd8, 0x70, 0x9a, 0x34, 0xc8, 0xec, 0xe8, 0x66, 0x75, 0x9f, 0x73, 0x60, 0x05, 0xa2, 0x60, - 0xd5, 0xb2, 0x28, 0x65, 0x4a, 0x21, 0x3f, 0xd9, 0xe4, 0x2b, 0x2d, 0xb7, 0x55, 0xca, 0x5c, 0xaf, - 0x4a, 0xe1, 0x5d, 0xf3, 0x5d, 0x94, 0x04, 0x85, 0xe8, 0x84, 0xd9, 0xc7, 0x07, 0xce, 0xe1, 0xe6, - 0xcb, 0xdb, 0x21, 0xb3, 0x41, 0x9f, 0x0c, 0x5f, 0xc6, 0x07, 0xa8, 0x00, 0x83, 0xb8, 0x76, 0xf6, - 0x89, 0x27, 0xce, 0x9c, 0x63, 0xd6, 0x7c, 0xa9, 0x4f, 0x11, 0x00, 0x34, 0x05, 0x19, 0x07, 0x57, - 0xad, 0xb3, 0x4f, 0x3c, 0xb9, 0x7f, 0x86, 0x19, 0xd0, 0xa5, 0x3e, 0xc5, 0x07, 0x15, 0xd3, 0xa4, - 0x9f, 0x3f, 0xf8, 0xd4, 0xb4, 0x54, 0xea, 0x87, 0xa4, 0xd3, 0x6c, 0xdc, 0x05, 0x3b, 0x78, 0x5f, - 0x3f, 0x4c, 0x79, 0x75, 0x2c, 0xe0, 0x5e, 0x55, 0x75, 0xad, 0xa6, 0xfa, 0x0f, 0xbc, 0x47, 0xbc, - 0x5e, 0xd3, 0xfa, 0xf8, 0x4e, 0x17, 0x3a, 0xe8, 0x4d, 0xfe, 0x43, 0x09, 0xb2, 0x57, 0x04, 0xd7, - 0x4d, 0xec, 0xa2, 0x73, 0x00, 0x5e, 0x2b, 0x62, 0x22, 0x1c, 0x9b, 0x0d, 0xb7, 0x33, 0xeb, 0x51, - 0x28, 0x01, 0x64, 0xf4, 0x04, 0x35, 0x34, 0xcb, 0x74, 0xf8, 0x7b, 0x95, 0x8e, 0x84, 0x1e, 0x2a, - 0x7a, 0x18, 0x10, 0xf5, 0x56, 0x95, 0xab, 0xa6, 0xab, 0x19, 0xf5, 0x8a, 0x65, 0x5e, 0xe3, 0x6f, - 0x00, 0x93, 0x4a, 0x8e, 0xd6, 0x5c, 0xa1, 0x15, 0x1b, 0x04, 0x2e, 0x7f, 0x5e, 0x82, 0x8c, 0xc7, - 0x85, 0x64, 0x45, 0x6a, 0xad, 0x66, 0x63, 0xc7, 0xe1, 0x0e, 0x49, 0x14, 0xd1, 0x39, 0x18, 0xb4, - 0x9a, 0x3b, 0x15, 0x31, 0xff, 0x87, 0xce, 0x16, 0x5a, 0x67, 0xb3, 0xb0, 0x04, 0x3e, 0x9f, 0x07, - 0xac, 0xe6, 0x0e, 0xb1, 0x8b, 0x93, 0x90, 0x8d, 0x11, 0x65, 0xe8, 0xaa, 0x2f, 0x05, 0x7d, 0x93, - 0xce, 0xe5, 0xaf, 0x58, 0xb6, 0x66, 0xda, 0x9a, 0x7b, 0x40, 0xaf, 0x9a, 0x24, 0x95, 0x9c, 0xa8, - 0xd8, 0xe0, 0x70, 0x59, 0x83, 0xd1, 0x4d, 0x9a, 0x0c, 0xf8, 0x72, 0x3f, 0xe6, 0x4b, 0x27, 0x75, - 0x93, 0xae, 0xad, 0x5c, 0x89, 0x16, 0xb9, 0x4a, 0x4b, 0x6d, 0xad, 0xf0, 0x91, 0x5e, 0xad, 0x30, - 0x1c, 0xa7, 0xfe, 0xf8, 0x58, 0x60, 0xda, 0x31, 0x23, 0x0c, 0xba, 0xa2, 0xde, 0x0c, 0xb0, 0x5b, - 0xea, 0x5b, 0xe8, 0x14, 0x0a, 0x0b, 0x1d, 0x9d, 0x61, 0xa1, 0xcb, 0x14, 0x91, 0xcf, 0xc1, 0xf0, - 0x86, 0x6a, 0xbb, 0x9b, 0xd8, 0xbd, 0x84, 0xd5, 0x1a, 0xb6, 0xc3, 0x91, 0x72, 0x58, 0x44, 0x4a, - 0x04, 0x29, 0x1a, 0x0e, 0x59, 0xac, 0xa0, 0xbf, 0xe5, 0x5d, 0x48, 0xd1, 0x8b, 0x65, 0x5e, 0x14, - 0xe5, 0x14, 0x2c, 0x8a, 0x12, 0x8f, 0x78, 0xe0, 0x62, 0x47, 0xac, 0xbc, 0x68, 0x01, 0x9d, 0x15, - 0xb1, 0x30, 0xd9, 0x29, 0x16, 0x72, 0x83, 0xe3, 0x11, 0xf1, 0x45, 0x18, 0x2c, 0x11, 0x77, 0xba, - 0xbc, 0xe8, 0x89, 0x21, 0xf9, 0x62, 0xa0, 0xcb, 0x30, 0x6a, 0xa9, 0xb6, 0x4b, 0xef, 0xd3, 0xef, - 0xd1, 0x3e, 0x78, 0x8f, 0xfb, 0x22, 0xb3, 0x2b, 0xd4, 0x51, 0xde, 0xc6, 0xb0, 0x15, 0x04, 0xca, - 0x6f, 0xa4, 0x60, 0x80, 0x2b, 0xe2, 0x3c, 0x0c, 0x72, 0x85, 0x72, 0x1b, 0x3c, 0x3e, 0x1b, 0x0d, - 0x2c, 0xb3, 0x5e, 0x00, 0xe0, 0xdc, 0x04, 0x05, 0xba, 0x1f, 0xd2, 0xd5, 0x3d, 0x55, 0x33, 0x2a, - 0x5a, 0x4d, 0xe4, 0x62, 0x6f, 0xdc, 0x9c, 0x1e, 0x5c, 0x20, 0xb0, 0xe5, 0x45, 0x65, 0x90, 0x56, - 0x2e, 0xd7, 0x48, 0xe4, 0xde, 0xc3, 0x5a, 0x7d, 0xcf, 0xe5, 0xb3, 0x88, 0x97, 0xd0, 0xd3, 0x90, - 0x22, 0x46, 0xc0, 0x5f, 0x5a, 0x15, 0x5a, 0x32, 0x60, 0x6f, 0x35, 0x52, 0x4a, 0x93, 0x86, 0x3f, - 0xf4, 0x9d, 0x69, 0x49, 0xa1, 0x14, 0x68, 0x1e, 0x86, 0x75, 0xd5, 0x71, 0x2b, 0x34, 0x02, 0x91, - 0xe6, 0xfb, 0x29, 0x8b, 0xa3, 0x51, 0x65, 0x70, 0x95, 0x72, 0xc1, 0x87, 0x08, 0x0d, 0x03, 0xd5, - 0xd0, 0x29, 0xc8, 0x51, 0x16, 0x55, 0xb3, 0xd1, 0xd0, 0x5c, 0x96, 0x07, 0x0d, 0x50, 0x8d, 0x8f, - 0x10, 0xf8, 0x02, 0x05, 0xd3, 0x6c, 0xe8, 0x38, 0x64, 0xe8, 0xcb, 0x0e, 0x8a, 0xc2, 0x6e, 0x31, - 0xa6, 0x09, 0x80, 0x56, 0x3e, 0x00, 0xa3, 0xbe, 0xf7, 0x63, 0x28, 0x69, 0xc6, 0xc5, 0x07, 0x53, - 0xc4, 0x47, 0x61, 0xc2, 0xc0, 0xd7, 0xe9, 0xbd, 0xca, 0x10, 0x76, 0x86, 0x62, 0x23, 0x52, 0x77, - 0x25, 0x4c, 0x71, 0x1f, 0x8c, 0x54, 0x85, 0xea, 0x19, 0x2e, 0x50, 0xdc, 0x61, 0x0f, 0x4a, 0xd1, - 0x8e, 0x41, 0x5a, 0xb5, 0x2c, 0x86, 0x30, 0xc4, 0xfd, 0x9f, 0x65, 0xd1, 0xaa, 0xd3, 0x30, 0x46, - 0xfb, 0x68, 0x63, 0xa7, 0xa9, 0xbb, 0x9c, 0x49, 0x96, 0xe2, 0x8c, 0x92, 0x0a, 0x85, 0xc1, 0x29, - 0xee, 0xbd, 0x30, 0x8c, 0xaf, 0x6a, 0x35, 0x6c, 0x54, 0x31, 0xc3, 0x1b, 0xa6, 0x78, 0x59, 0x01, - 0xa4, 0x48, 0x0f, 0x82, 0xe7, 0xd9, 0x2a, 0xc2, 0xe7, 0x8e, 0x30, 0x7e, 0x02, 0x3e, 0xcf, 0xc0, - 0x72, 0x1e, 0x52, 0x8b, 0xaa, 0xab, 0x92, 0xf4, 0xc0, 0xbd, 0xce, 0x82, 0x48, 0x56, 0x21, 0x3f, - 0xe5, 0xef, 0x27, 0x20, 0x75, 0xc5, 0x74, 0x31, 0x3a, 0x13, 0x48, 0xd7, 0x46, 0x5a, 0x2d, 0x79, - 0x53, 0xab, 0x1b, 0xb8, 0xb6, 0xea, 0xd4, 0x03, 0x8f, 0xb0, 0x7d, 0x53, 0x4a, 0x84, 0x4c, 0x69, - 0x02, 0xfa, 0x6d, 0xb3, 0x69, 0xd4, 0xc4, 0xf5, 0x3f, 0x5a, 0x40, 0x0b, 0x90, 0xf6, 0x2c, 0x24, - 0xd5, 0xd9, 0x42, 0x46, 0x89, 0x85, 0x10, 0xeb, 0xe5, 0x00, 0x65, 0x70, 0x87, 0x1b, 0x4a, 0x09, - 0x32, 0x9e, 0xab, 0xe2, 0x76, 0xd6, 0x9b, 0xa9, 0xfa, 0x64, 0x24, 0x54, 0x78, 0xe3, 0xee, 0x29, - 0x8e, 0x59, 0x5b, 0xce, 0xab, 0xe0, 0x9a, 0x0b, 0x99, 0x14, 0x7f, 0x0e, 0x3e, 0x48, 0x7b, 0xe5, - 0x9b, 0x14, 0x7b, 0x12, 0x7e, 0x02, 0x32, 0x8e, 0x56, 0x37, 0x54, 0xb7, 0x69, 0x63, 0x6e, 0x75, - 0x3e, 0x40, 0xfe, 0x92, 0x04, 0x03, 0xcc, 0x8a, 0x03, 0x5a, 0x93, 0xe2, 0xb5, 0x96, 0x68, 0xa7, - 0xb5, 0xe4, 0xed, 0x6a, 0xed, 0x02, 0x80, 0x27, 0x8a, 0xc3, 0xdf, 0xe8, 0xb6, 0x64, 0x02, 0x4c, - 0xbc, 0x4d, 0xad, 0xce, 0x27, 0x68, 0x80, 0x44, 0xfe, 0x8f, 0x12, 0x49, 0x3d, 0x79, 0x3d, 0xba, - 0x00, 0xc3, 0x42, 0xa6, 0xca, 0xae, 0xae, 0xd6, 0xb9, 0xcd, 0x1c, 0x6f, 0x23, 0xd8, 0x45, 0x5d, - 0xad, 0x2b, 0x43, 0x5c, 0x16, 0x52, 0x88, 0x1f, 0x81, 0x44, 0x9b, 0x11, 0x08, 0x0d, 0x79, 0xf2, - 0xf6, 0x86, 0x3c, 0x34, 0x38, 0xa9, 0xe8, 0xe0, 0x7c, 0x2e, 0x41, 0x17, 0x1c, 0x96, 0xe9, 0xa8, - 0xfa, 0xdd, 0x9f, 0x07, 0xc7, 0x21, 0x63, 0x99, 0x7a, 0x85, 0xd5, 0xb0, 0xcb, 0xb0, 0x69, 0xcb, - 0xd4, 0x95, 0x96, 0xe1, 0xee, 0xbf, 0x23, 0x93, 0x64, 0xe0, 0x0e, 0x68, 0x6c, 0x30, 0xaa, 0x31, - 0x03, 0xb2, 0x4c, 0x11, 0x3c, 0x72, 0xcd, 0x12, 0x0d, 0xd0, 0x40, 0x28, 0x45, 0xa3, 0x2c, 0x13, - 0x9a, 0xe1, 0x29, 0x1c, 0x8b, 0xe0, 0x33, 0x57, 0xdf, 0xba, 0x42, 0x0d, 0x1a, 0xa3, 0xc2, 0xb1, - 0xe4, 0x8f, 0x48, 0x00, 0x2b, 0x44, 0xa7, 0xb4, 0xaf, 0x24, 0xe2, 0x38, 0xb4, 0xf9, 0x4a, 0xa8, - 0xd5, 0x13, 0xf1, 0x83, 0xc5, 0xdb, 0xce, 0x3a, 0x41, 0x89, 0xe7, 0x61, 0xd8, 0x37, 0x41, 0x07, - 0x0b, 0x41, 0x4e, 0xb4, 0xcd, 0x8f, 0x37, 0xb1, 0xab, 0x64, 0xaf, 0x06, 0x4a, 0xf2, 0x9f, 0x49, - 0x90, 0xa1, 0xf2, 0xac, 0x62, 0x57, 0x0d, 0x8d, 0x9c, 0x74, 0xbb, 0x23, 0x77, 0x0f, 0x00, 0x63, - 0xe2, 0x68, 0x2f, 0x63, 0x6e, 0x4d, 0x19, 0x0a, 0xd9, 0xd4, 0x5e, 0xc6, 0xe8, 0x71, 0x4f, 0xcd, - 0xc9, 0x4e, 0x6a, 0x16, 0xd9, 0x33, 0x57, 0xf6, 0x51, 0x18, 0xa4, 0xdf, 0xaf, 0xb9, 0xee, 0xf0, - 0x84, 0x78, 0xc0, 0x68, 0x36, 0xb6, 0xae, 0x3b, 0xf2, 0x1e, 0x0c, 0x6e, 0x5d, 0x67, 0xbb, 0x15, - 0xc7, 0x21, 0x63, 0x9b, 0x26, 0x8f, 0xbc, 0x2c, 0xd7, 0x49, 0x13, 0x00, 0x0d, 0x34, 0x62, 0x8d, - 0x9e, 0xf0, 0xd7, 0xe8, 0xfe, 0x16, 0x43, 0xb2, 0x87, 0x2d, 0x86, 0xd3, 0xff, 0x41, 0x82, 0xa1, - 0x80, 0x37, 0x40, 0x67, 0xe0, 0x48, 0x69, 0x65, 0x7d, 0xe1, 0x72, 0x65, 0x79, 0xb1, 0x72, 0x71, - 0x65, 0x7e, 0xc9, 0x7f, 0xde, 0x51, 0x98, 0x7c, 0xf5, 0xc6, 0x0c, 0x0a, 0xe0, 0x6e, 0x1b, 0x74, - 0x53, 0x13, 0xcd, 0xc1, 0x44, 0x98, 0x64, 0xbe, 0xb4, 0x59, 0x5e, 0xdb, 0xca, 0x49, 0x85, 0x23, - 0xaf, 0xde, 0x98, 0x19, 0x0b, 0x50, 0xcc, 0xef, 0x38, 0xd8, 0x70, 0x5b, 0x09, 0x16, 0xd6, 0x57, - 0x57, 0x97, 0xb7, 0x72, 0x89, 0x16, 0x02, 0xee, 0x98, 0x1f, 0x84, 0xb1, 0x30, 0xc1, 0xda, 0xf2, - 0x4a, 0x2e, 0x59, 0x40, 0xaf, 0xde, 0x98, 0x19, 0x09, 0x60, 0xaf, 0x69, 0x7a, 0x21, 0xfd, 0x81, - 0x4f, 0x4f, 0xf5, 0xfd, 0xee, 0xef, 0x4c, 0x49, 0xa4, 0x67, 0xc3, 0x21, 0x9f, 0x80, 0x1e, 0x86, - 0xa3, 0x9b, 0xcb, 0x4b, 0x6b, 0xe5, 0xc5, 0xca, 0xea, 0xe6, 0x52, 0x85, 0x7d, 0xd6, 0xc2, 0xeb, - 0xdd, 0xe8, 0xab, 0x37, 0x66, 0x86, 0x78, 0x97, 0xda, 0x61, 0x6f, 0x28, 0xe5, 0x2b, 0xeb, 0x5b, - 0xe5, 0x9c, 0xc4, 0xb0, 0x37, 0x6c, 0x7c, 0xd5, 0x74, 0xd9, 0xe7, 0xad, 0x1e, 0x85, 0x63, 0x31, - 0xd8, 0x5e, 0xc7, 0xc6, 0x5e, 0xbd, 0x31, 0x33, 0xbc, 0x61, 0x63, 0x36, 0x6b, 0x28, 0xc5, 0x2c, - 0xe4, 0x5b, 0x29, 0xd6, 0x37, 0xd6, 0x37, 0xe7, 0x57, 0x72, 0x33, 0x85, 0xdc, 0xab, 0x37, 0x66, - 0xb2, 0xc2, 0xf5, 0x11, 0x7c, 0xbf, 0x67, 0x77, 0x7e, 0xe5, 0xf2, 0xda, 0xc3, 0x70, 0x42, 0xdf, - 0x69, 0xcc, 0x39, 0xae, 0xba, 0xaf, 0x19, 0xf5, 0xb9, 0xab, 0x67, 0xc4, 0x4f, 0xb1, 0x76, 0xd1, - 0x77, 0x1a, 0xb3, 0x02, 0xd4, 0x6e, 0x73, 0xb3, 0xd0, 0xfe, 0x10, 0xa7, 0xd0, 0xe5, 0x9c, 0xa3, - 0xfb, 0xb2, 0xa7, 0xfd, 0xc6, 0x77, 0xa1, 0xcd, 0x76, 0x6c, 0xa1, 0xc3, 0x62, 0x4c, 0xfe, 0xff, - 0x61, 0xe4, 0x92, 0xe6, 0xb8, 0xa6, 0xad, 0x55, 0x55, 0x9d, 0xbe, 0xd7, 0x78, 0xbc, 0x37, 0x47, - 0x19, 0x99, 0xc1, 0x4f, 0xc1, 0xc0, 0x55, 0x55, 0x67, 0x5e, 0x8a, 0xc5, 0xee, 0xb0, 0xa6, 0x7c, - 0x2f, 0x25, 0x08, 0x19, 0xba, 0xfc, 0x7a, 0x02, 0x46, 0xa9, 0x75, 0x3b, 0xec, 0x73, 0x43, 0x64, - 0x41, 0xf4, 0x0c, 0xa4, 0x6c, 0xd5, 0xe5, 0xfb, 0x72, 0xa5, 0x07, 0xf9, 0x8e, 0xea, 0xc9, 0x8e, - 0xbb, 0xa4, 0xb3, 0x8b, 0xb8, 0xaa, 0x50, 0x32, 0xf4, 0x3c, 0xa4, 0x1b, 0xea, 0xf5, 0x0a, 0x65, - 0xc1, 0xd6, 0x19, 0x6f, 0xed, 0x99, 0xc5, 0xad, 0x9b, 0xd3, 0xa3, 0x07, 0x6a, 0x43, 0x2f, 0xca, - 0x82, 0x85, 0xac, 0x0c, 0x36, 0xd4, 0xeb, 0x44, 0x30, 0xb4, 0x0f, 0xa3, 0x04, 0x5a, 0xdd, 0x53, - 0x8d, 0x3a, 0x66, 0xfc, 0xe9, 0xde, 0x62, 0x69, 0xe1, 0x30, 0xfc, 0x27, 0x7d, 0xfe, 0x01, 0x4e, - 0xb2, 0x32, 0xdc, 0x50, 0xaf, 0x2f, 0x50, 0x00, 0x69, 0xac, 0x98, 0x7e, 0xed, 0xf5, 0xe9, 0x3e, - 0xba, 0x2d, 0xfd, 0x75, 0x09, 0xc0, 0x57, 0x11, 0xda, 0x82, 0x5c, 0xd5, 0x2b, 0x51, 0x5a, 0x87, - 0x0f, 0xd5, 0x74, 0x54, 0xe9, 0x11, 0xc5, 0xb2, 0x38, 0xfa, 0xcd, 0x9b, 0xd3, 0x92, 0x32, 0x5a, - 0x8d, 0xe8, 0xfc, 0x9d, 0x30, 0xd4, 0xb4, 0x6a, 0xaa, 0x8b, 0x2b, 0x74, 0x8d, 0x95, 0xe8, 0x1a, - 0x93, 0xa7, 0x08, 0xaf, 0x5b, 0x37, 0xa7, 0x11, 0xeb, 0x4e, 0x80, 0x58, 0xa6, 0x91, 0x1a, 0x18, - 0x84, 0x10, 0x84, 0xfb, 0x32, 0xb4, 0x18, 0xb8, 0x28, 0x95, 0x87, 0xc1, 0x86, 0x69, 0x68, 0xfb, - 0xdc, 0xdc, 0x32, 0x8a, 0x28, 0xa2, 0x02, 0xa4, 0xd9, 0x0b, 0x35, 0xf7, 0x40, 0x6c, 0x33, 0x8a, - 0x32, 0xa1, 0xba, 0x86, 0x77, 0x1c, 0x4d, 0x0c, 0x80, 0x22, 0x8a, 0xe8, 0x22, 0xe4, 0x1c, 0x5c, - 0x6d, 0xda, 0x9a, 0x7b, 0x50, 0xa9, 0x9a, 0x86, 0xab, 0x56, 0x5d, 0xf6, 0xd6, 0xa9, 0x74, 0xfc, - 0xd6, 0xcd, 0xe9, 0xa3, 0x4c, 0xd6, 0x28, 0x86, 0xac, 0x8c, 0x0a, 0xd0, 0x02, 0x83, 0x90, 0x16, - 0x6a, 0xd8, 0x55, 0x35, 0xdd, 0xc9, 0xb3, 0x93, 0x14, 0x51, 0x0c, 0xf4, 0xe5, 0x7d, 0x83, 0xc1, - 0x6d, 0xa5, 0x8b, 0x90, 0x33, 0x2d, 0x6c, 0x87, 0x12, 0x46, 0x29, 0xda, 0x72, 0x14, 0x43, 0x56, - 0x46, 0x05, 0x48, 0x24, 0x93, 0x2f, 0x91, 0xe1, 0x15, 0xcb, 0x38, 0xab, 0xb9, 0xe3, 0xef, 0x46, - 0x4d, 0xb4, 0x8c, 0xc6, 0xbc, 0x71, 0x50, 0x7a, 0xd4, 0xe7, 0x1e, 0xa5, 0x93, 0xbf, 0xf1, 0x47, - 0x8f, 0x8c, 0x11, 0x93, 0xf0, 0xb7, 0x87, 0x2e, 0xe3, 0x03, 0x32, 0xf6, 0x1c, 0x6f, 0x83, 0xa2, - 0x91, 0xec, 0xf0, 0x45, 0x55, 0xd3, 0xc5, 0x83, 0x5d, 0x85, 0x97, 0xd0, 0x59, 0x18, 0x70, 0x5c, - 0xd5, 0x6d, 0x3a, 0xfc, 0x33, 0x5a, 0x85, 0xa8, 0x7d, 0x95, 0x4c, 0xa3, 0xb6, 0x49, 0x31, 0x14, - 0x8e, 0x89, 0xe6, 0x61, 0xc0, 0x35, 0xf7, 0xb1, 0xc1, 0xf5, 0xd6, 0xeb, 0xec, 0xa5, 0x07, 0x3b, - 0x8c, 0x10, 0x99, 0x90, 0xab, 0x61, 0x1d, 0xd7, 0x59, 0xe2, 0xb3, 0xa7, 0x92, 0x15, 0x01, 0xfd, - 0x80, 0x56, 0x69, 0xf1, 0x30, 0xf3, 0x8c, 0x2b, 0x25, 0xca, 0x4a, 0x56, 0x46, 0x3d, 0xd0, 0x26, - 0x85, 0xa0, 0xf0, 0xe5, 0x3d, 0xfe, 0x81, 0xb9, 0xe3, 0xd1, 0xce, 0x06, 0xcc, 0x56, 0x6c, 0x10, - 0x04, 0xaf, 0xfc, 0x5d, 0x84, 0x5c, 0xd3, 0xd8, 0x31, 0x0d, 0xfa, 0x76, 0x8e, 0x27, 0xdb, 0x64, - 0x91, 0x95, 0x0c, 0x8e, 0x7f, 0x14, 0x43, 0x56, 0x46, 0x3d, 0xd0, 0x25, 0x96, 0x92, 0xd7, 0x60, - 0xc4, 0xc7, 0xa2, 0x73, 0x31, 0xd3, 0x75, 0x2e, 0x9e, 0xe4, 0x73, 0xf1, 0x48, 0xb4, 0x15, 0x7f, - 0x3a, 0x0e, 0x7b, 0x40, 0x42, 0x86, 0x7e, 0x09, 0xc0, 0xf7, 0x00, 0x74, 0xa3, 0x60, 0xa8, 0x75, - 0x78, 0x7d, 0xf7, 0x21, 0x16, 0x5c, 0x3e, 0x0d, 0xba, 0x06, 0xe3, 0x0d, 0xcd, 0xa8, 0x38, 0x58, - 0xdf, 0xad, 0x70, 0x85, 0x12, 0x56, 0xf4, 0x93, 0x27, 0xa5, 0xa5, 0x9e, 0x47, 0xfd, 0xd6, 0xcd, - 0xe9, 0x02, 0x77, 0x88, 0xad, 0xdc, 0x64, 0x65, 0xac, 0xa1, 0x19, 0x9b, 0x58, 0xdf, 0x5d, 0xf4, - 0x60, 0xc5, 0xec, 0x07, 0x5e, 0x9f, 0xee, 0xe3, 0x93, 0xb0, 0x4f, 0x7e, 0x92, 0xee, 0x45, 0xf3, - 0xc9, 0x83, 0x1d, 0xb2, 0x2a, 0x50, 0x45, 0x81, 0xee, 0x22, 0x64, 0x14, 0x1f, 0xc0, 0x26, 0xef, - 0x2b, 0xff, 0x69, 0x46, 0x92, 0x7f, 0x5f, 0x82, 0x81, 0xc5, 0x2b, 0x1b, 0xaa, 0x66, 0xa3, 0x65, - 0x18, 0xf3, 0x8d, 0x24, 0x3c, 0x75, 0x4f, 0xdc, 0xba, 0x39, 0x9d, 0x8f, 0xda, 0x91, 0x37, 0x77, - 0x7d, 0x33, 0x15, 0x93, 0x77, 0xb9, 0xdd, 0xb2, 0x31, 0xc4, 0xaa, 0x05, 0x45, 0x6e, 0x5d, 0x54, - 0x46, 0xba, 0xf9, 0x0c, 0x0c, 0x32, 0x69, 0xd9, 0x76, 0x21, 0xf9, 0xc1, 0x37, 0xda, 0x27, 0x5b, - 0xec, 0x94, 0xe2, 0x79, 0xdb, 0x85, 0x04, 0x55, 0xfe, 0x70, 0x02, 0x60, 0xf1, 0xca, 0x95, 0x2d, - 0x5b, 0xb3, 0x74, 0xec, 0xde, 0xc9, 0x1e, 0x6f, 0xc1, 0x91, 0xc0, 0x2a, 0xc5, 0xae, 0x46, 0x7a, - 0x3d, 0x73, 0xeb, 0xe6, 0xf4, 0x89, 0x68, 0xaf, 0x03, 0x68, 0xb2, 0x32, 0xee, 0xaf, 0x58, 0xec, - 0x6a, 0x2c, 0xd7, 0x9a, 0xe3, 0x7a, 0x5c, 0x93, 0xed, 0xb9, 0x06, 0xd0, 0x82, 0x5c, 0x17, 0x1d, - 0x37, 0x5e, 0xa5, 0x97, 0x61, 0xc8, 0x57, 0x89, 0x83, 0xde, 0x0a, 0x69, 0x97, 0xff, 0xe6, 0x9a, - 0x2d, 0xb4, 0x6a, 0x56, 0xa0, 0x73, 0xed, 0x7a, 0x14, 0xf2, 0xdf, 0x48, 0x00, 0xbe, 0x8d, 0xfe, - 0x62, 0x9a, 0x14, 0xf1, 0xcd, 0xdc, 0x9d, 0x26, 0x0f, 0x9b, 0x59, 0x71, 0xc2, 0x88, 0x0a, 0xdf, - 0x9f, 0x80, 0xf1, 0x6d, 0xe1, 0x57, 0x7e, 0xe1, 0xbb, 0x7f, 0x09, 0x06, 0xb1, 0xe1, 0xda, 0x1a, - 0xed, 0x3f, 0x7b, 0xb5, 0x1d, 0x19, 0xe0, 0x98, 0xbe, 0xd0, 0x4f, 0xba, 0x88, 0x9d, 0x6c, 0x4e, - 0x1e, 0xd1, 0xc2, 0xaf, 0x26, 0x21, 0xdf, 0x8e, 0x12, 0x2d, 0xc0, 0x68, 0xd5, 0xc6, 0x14, 0x50, - 0x09, 0x6e, 0xaa, 0x95, 0x0a, 0x7e, 0x2a, 0x18, 0x41, 0x90, 0x95, 0x11, 0x01, 0xe1, 0x31, 0xa1, - 0x0e, 0x24, 0x5f, 0x23, 0x96, 0x46, 0xb0, 0x7a, 0x4c, 0xd0, 0x64, 0x1e, 0x14, 0x44, 0x23, 0x61, - 0x06, 0x2c, 0x2a, 0x8c, 0xf8, 0x50, 0x1a, 0x16, 0x74, 0x18, 0xd5, 0x0c, 0xcd, 0xd5, 0x54, 0xbd, - 0xb2, 0xa3, 0xea, 0xaa, 0x51, 0x3d, 0x64, 0x86, 0xcb, 0x1c, 0x3a, 0x6f, 0x31, 0xc2, 0x49, 0x56, - 0x46, 0x38, 0xa4, 0xc4, 0x00, 0x68, 0x01, 0x06, 0x45, 0x2b, 0xa9, 0xc3, 0x26, 0x0b, 0x82, 0x32, - 0x90, 0x8f, 0xbd, 0x3f, 0x09, 0x63, 0x0a, 0xae, 0xfd, 0xbf, 0x01, 0xe8, 0x79, 0x00, 0x2e, 0x01, - 0xb0, 0x79, 0x4d, 0x9c, 0xe7, 0xe1, 0xc6, 0x80, 0x38, 0x85, 0x0c, 0x23, 0x5e, 0x74, 0xdc, 0xc0, - 0x28, 0xfc, 0x45, 0x02, 0xb2, 0xc1, 0x51, 0xf8, 0x3b, 0x1a, 0x6c, 0xd0, 0xbc, 0xef, 0x6d, 0xd8, - 0x76, 0xf6, 0xc9, 0xa8, 0xb7, 0x69, 0xb1, 0xd5, 0xce, 0x6e, 0xe6, 0x7f, 0x26, 0x60, 0x60, 0x43, - 0xb5, 0xd5, 0x86, 0x83, 0xaa, 0x2d, 0x39, 0xa2, 0xc4, 0xcf, 0xce, 0x5b, 0x3e, 0x69, 0xcc, 0xb7, - 0x17, 0xba, 0xa4, 0x88, 0xaf, 0xc5, 0xa6, 0x88, 0x23, 0x64, 0x8d, 0x1a, 0x38, 0xd9, 0x27, 0x5a, - 0x1e, 0x2e, 0x1d, 0xf3, 0xb9, 0x84, 0xeb, 0xd9, 0x12, 0xd6, 0x3f, 0x95, 0x42, 0x4f, 0xc1, 0x10, - 0xc1, 0xf0, 0x9d, 0x2e, 0x21, 0x9f, 0xf4, 0xd7, 0x8c, 0x81, 0x4a, 0x59, 0x81, 0x86, 0x7a, 0xbd, - 0xcc, 0x0a, 0x68, 0x05, 0xd0, 0x9e, 0xb7, 0x2b, 0x51, 0xf1, 0xd5, 0x48, 0xe8, 0xef, 0xb9, 0x75, - 0x73, 0xfa, 0x18, 0xa3, 0x6f, 0xc5, 0x91, 0x95, 0x31, 0x1f, 0x28, 0xb8, 0x3d, 0x0e, 0x40, 0xfa, - 0x55, 0x61, 0x97, 0xc3, 0xd8, 0xb2, 0xe4, 0xc8, 0xad, 0x9b, 0xd3, 0x63, 0x8c, 0x8b, 0x5f, 0x27, - 0x2b, 0x19, 0x52, 0x58, 0x24, 0xbf, 0x03, 0x16, 0xfd, 0x51, 0x09, 0x90, 0xef, 0xd6, 0x15, 0xec, - 0x58, 0x64, 0xfd, 0x44, 0x52, 0xe8, 0x40, 0xde, 0x2b, 0xc5, 0xa7, 0xd0, 0x3e, 0x9d, 0x48, 0xa1, - 0x03, 0x33, 0xe3, 0x8c, 0xef, 0xff, 0x98, 0x37, 0x19, 0x9b, 0x0d, 0xdc, 0x9c, 0x9b, 0x5d, 0x30, - 0x35, 0x41, 0xd5, 0xe2, 0xed, 0xfa, 0xe4, 0x3f, 0x93, 0xe0, 0x58, 0x8b, 0x05, 0x79, 0xc2, 0x5d, - 0x01, 0x64, 0x07, 0x2a, 0xf9, 0x97, 0xca, 0x24, 0xfe, 0xe1, 0xcf, 0x1e, 0x0d, 0x71, 0xcc, 0x8e, - 0xf1, 0xa6, 0x77, 0xc0, 0x65, 0xb3, 0xdb, 0x76, 0x9f, 0x93, 0x60, 0x22, 0xd8, 0xb2, 0x27, 0xfb, - 0x45, 0xc8, 0x06, 0x1b, 0xf6, 0xb6, 0xce, 0x3b, 0x48, 0xcd, 0x05, 0x0e, 0xd1, 0xa1, 0x65, 0x7f, - 0x06, 0x8a, 0xcf, 0xce, 0x76, 0xeb, 0xb8, 0x90, 0x21, 0x3a, 0x13, 0x53, 0x54, 0xe5, 0x3f, 0x95, - 0x20, 0xb5, 0x61, 0x9a, 0x3a, 0x7a, 0x11, 0xc6, 0x0c, 0xd3, 0xad, 0x10, 0x63, 0xc1, 0xb5, 0x0a, - 0x5f, 0xef, 0x32, 0x97, 0xf6, 0x6c, 0xcf, 0xfa, 0xf8, 0xe1, 0xcd, 0xe9, 0x56, 0x2e, 0xca, 0xa8, - 0x61, 0xba, 0x25, 0x0a, 0xd9, 0x62, 0xab, 0xe1, 0x6b, 0x30, 0x1c, 0x6e, 0x87, 0xf9, 0x3a, 0xe5, - 0x30, 0xed, 0x84, 0x39, 0xdc, 0xba, 0x39, 0x3d, 0xe1, 0x9b, 0xbe, 0x07, 0x96, 0x95, 0xec, 0x4e, - 0xa0, 0x61, 0x76, 0x5d, 0xe9, 0xc7, 0xaf, 0x4f, 0x4b, 0xa7, 0xbf, 0x28, 0x01, 0xf8, 0x4b, 0x7d, - 0xf4, 0x30, 0x1c, 0x2d, 0xad, 0xaf, 0x2d, 0x56, 0x36, 0xb7, 0xe6, 0xb7, 0xb6, 0x37, 0x2b, 0xdb, - 0x6b, 0x9b, 0x1b, 0xe5, 0x85, 0xe5, 0x8b, 0xcb, 0xe5, 0x45, 0x7f, 0xfb, 0xd8, 0xb1, 0x70, 0x55, - 0xdb, 0xd5, 0x70, 0x0d, 0xdd, 0x0f, 0x13, 0x61, 0x6c, 0x52, 0x2a, 0x2f, 0xe6, 0xa4, 0x42, 0xf6, - 0xd5, 0x1b, 0x33, 0x69, 0x96, 0x38, 0xe1, 0x1a, 0x3a, 0x05, 0x47, 0x5a, 0xf1, 0x96, 0xd7, 0x96, - 0x72, 0x89, 0xc2, 0xf0, 0xab, 0x37, 0x66, 0x32, 0x5e, 0x86, 0x85, 0x64, 0x40, 0x41, 0x4c, 0xce, - 0x2f, 0x59, 0x80, 0x57, 0x6f, 0xcc, 0x0c, 0x30, 0xdd, 0x15, 0x52, 0x1f, 0xf8, 0xf4, 0x54, 0x5f, - 0x69, 0xbe, 0xed, 0x06, 0xf1, 0x03, 0xed, 0xd4, 0x76, 0xdd, 0xdb, 0xfc, 0x0d, 0x6f, 0x0d, 0xdf, - 0x18, 0x6c, 0xd9, 0x1a, 0xae, 0x63, 0x03, 0x3b, 0x9a, 0x73, 0xa8, 0xad, 0xe1, 0x8e, 0xdb, 0xcb, - 0xf2, 0x8d, 0x7e, 0xc8, 0x2e, 0x31, 0xae, 0x44, 0xd7, 0xf4, 0x38, 0xc5, 0xa2, 0x2e, 0xdf, 0xdb, - 0x8c, 0x8d, 0x58, 0x30, 0x0b, 0x08, 0xde, 0x65, 0x24, 0x16, 0x1e, 0x0c, 0x7e, 0x57, 0x81, 0x5d, - 0x91, 0xf2, 0x2f, 0xfe, 0x64, 0x7b, 0xdd, 0x40, 0x61, 0x59, 0x04, 0xdf, 0xb3, 0x88, 0xb2, 0x92, - 0xd9, 0x8d, 0x87, 0x2d, 0x02, 0x61, 0x37, 0x9b, 0x7e, 0x19, 0x8e, 0x50, 0x24, 0x3f, 0x3c, 0x52, - 0x44, 0x91, 0x66, 0xcb, 0x51, 0xa1, 0x57, 0x54, 0xc7, 0xbf, 0xbc, 0xc0, 0x2e, 0x21, 0xbd, 0x85, - 0x87, 0xa7, 0x13, 0x81, 0x36, 0xa3, 0xec, 0x64, 0x65, 0x5c, 0x6f, 0xa1, 0x74, 0xd0, 0x85, 0xd0, - 0xed, 0xb3, 0x54, 0x6f, 0xdb, 0xcf, 0xc1, 0x3b, 0x68, 0x25, 0x18, 0xf2, 0xdd, 0x80, 0xc3, 0xff, - 0xef, 0x41, 0x77, 0x4f, 0x1e, 0x24, 0x42, 0xbf, 0x02, 0x47, 0xfc, 0x90, 0x1a, 0xe4, 0xc6, 0xfe, - 0x2d, 0xc4, 0xbd, 0x3d, 0xac, 0x34, 0xa2, 0x3a, 0x88, 0xe5, 0x27, 0x2b, 0x13, 0xcd, 0x56, 0x52, - 0xb2, 0xb6, 0x19, 0x0e, 0xfa, 0x3e, 0x87, 0xff, 0x4f, 0x8f, 0x5e, 0x9c, 0x66, 0x98, 0x90, 0x7d, - 0x9a, 0xde, 0x32, 0x6d, 0x17, 0xd7, 0xe8, 0xfe, 0x55, 0x5a, 0xf1, 0xca, 0xf2, 0x1a, 0xa0, 0xd6, - 0xb1, 0x8b, 0x5e, 0xa8, 0xcb, 0xf8, 0x17, 0xea, 0x26, 0xa0, 0x3f, 0x78, 0xed, 0x8c, 0x15, 0x8a, - 0xe9, 0x0f, 0xf0, 0x18, 0x76, 0x27, 0xe7, 0xe7, 0xe7, 0x12, 0x20, 0x7b, 0xe7, 0x1f, 0x2f, 0x35, - 0xb1, 0x7d, 0x40, 0xa6, 0x97, 0xa5, 0xd6, 0x35, 0x23, 0xf8, 0x8e, 0x64, 0xcc, 0x0b, 0xb0, 0x14, - 0x67, 0xf6, 0xea, 0x19, 0xd9, 0x80, 0xa1, 0x0d, 0xb5, 0x8e, 0x15, 0xfc, 0x52, 0x13, 0x3b, 0x6e, - 0xcc, 0x5d, 0xe5, 0x49, 0x18, 0x30, 0x77, 0x77, 0xc5, 0x09, 0x6c, 0x4a, 0xe1, 0x25, 0xd2, 0x3b, - 0x5d, 0x6b, 0x68, 0xec, 0x9a, 0x52, 0x4a, 0x61, 0x05, 0x34, 0x0d, 0x43, 0x55, 0xb3, 0x69, 0xf0, - 0x29, 0x93, 0x4f, 0x89, 0x8f, 0x07, 0x34, 0x0d, 0x36, 0x65, 0xe4, 0x0b, 0x90, 0x65, 0xed, 0xf1, - 0x70, 0x77, 0x0c, 0xd2, 0xf4, 0xa6, 0x8f, 0xdf, 0xea, 0x20, 0x29, 0x5f, 0x66, 0x37, 0x9b, 0x19, - 0x17, 0xd6, 0x30, 0x2b, 0x94, 0x9e, 0x69, 0xab, 0xb5, 0x7b, 0x3b, 0x4e, 0x6b, 0xa6, 0x16, 0x4f, - 0x63, 0x7f, 0xde, 0x0f, 0x47, 0xf8, 0x69, 0x93, 0x6a, 0x69, 0x73, 0x7b, 0xae, 0x2b, 0x5e, 0x95, - 0x00, 0xcf, 0x22, 0x55, 0x4b, 0x93, 0x0f, 0x20, 0x75, 0xc9, 0x75, 0x2d, 0x74, 0x1a, 0xfa, 0xed, - 0xa6, 0x8e, 0xc5, 0xde, 0x88, 0xb7, 0x17, 0xad, 0x5a, 0xda, 0x2c, 0x41, 0x50, 0x9a, 0x3a, 0x56, - 0x18, 0x0a, 0x2a, 0xc3, 0xf4, 0x6e, 0x53, 0xd7, 0x0f, 0x2a, 0x35, 0x4c, 0xff, 0xc1, 0x8b, 0xf7, - 0x89, 0x74, 0x7c, 0xdd, 0x52, 0xc5, 0x87, 0xd6, 0x88, 0x5a, 0x4e, 0x50, 0xb4, 0x45, 0x8a, 0x25, - 0x3e, 0x8f, 0x5e, 0x16, 0x38, 0xf2, 0x5f, 0x26, 0x20, 0x2d, 0x58, 0xd3, 0x5b, 0xc7, 0x58, 0xc7, - 0x55, 0xd7, 0x14, 0x27, 0x05, 0x5e, 0x19, 0x21, 0x48, 0xd6, 0xf9, 0xe8, 0x64, 0x2e, 0xf5, 0x29, - 0xa4, 0x40, 0x60, 0xde, 0xdd, 0x6f, 0x02, 0xb3, 0x9a, 0x64, 0xc0, 0x52, 0x96, 0x29, 0x16, 0x3a, - 0x97, 0xfa, 0x14, 0x5a, 0x42, 0x79, 0x18, 0x20, 0xf6, 0xef, 0xb2, 0xaf, 0xd7, 0x11, 0x38, 0x2f, - 0xa3, 0x49, 0xe8, 0xb7, 0x54, 0xb7, 0xca, 0x2e, 0x7a, 0x91, 0x0a, 0x56, 0x44, 0x4f, 0xc1, 0x00, - 0x7b, 0x47, 0x18, 0xfd, 0xef, 0x09, 0x44, 0x19, 0xec, 0x83, 0x4d, 0x44, 0xee, 0x0d, 0xd5, 0x75, - 0xb1, 0x6d, 0x10, 0x86, 0x0c, 0x1d, 0x21, 0x48, 0xed, 0x98, 0xb5, 0x03, 0xfe, 0x1f, 0x1d, 0xe8, - 0x6f, 0xfe, 0x09, 0x79, 0x6a, 0x0a, 0x15, 0x5a, 0xc9, 0xfe, 0x91, 0x4d, 0x56, 0x00, 0x4b, 0x04, - 0xa9, 0x0c, 0xe3, 0x6a, 0xad, 0xa6, 0xb1, 0x7f, 0xae, 0x50, 0xd9, 0xd1, 0xe8, 0xfc, 0x77, 0xe8, - 0xbf, 0x29, 0x6a, 0x37, 0x16, 0xc8, 0x27, 0x28, 0x71, 0xfc, 0x52, 0x06, 0x06, 0x2d, 0x26, 0x94, - 0x7c, 0x1e, 0xc6, 0x5a, 0x24, 0x25, 0xf2, 0xed, 0x6b, 0x46, 0x4d, 0x5c, 0x88, 0x27, 0xbf, 0x09, - 0x8c, 0x7e, 0x62, 0x8d, 0x9d, 0xc1, 0xd0, 0xdf, 0xa5, 0xf7, 0xb5, 0x7f, 0x28, 0x34, 0x12, 0x78, - 0x28, 0xa4, 0x5a, 0x5a, 0x29, 0x43, 0xf9, 0xf3, 0xe7, 0x41, 0xf3, 0xad, 0xcf, 0x83, 0xea, 0xd8, - 0x10, 0x41, 0x92, 0x54, 0xa9, 0x96, 0xe6, 0x50, 0x73, 0xf4, 0x3f, 0xf9, 0xe6, 0x9c, 0x0f, 0xfc, - 0xa6, 0xaf, 0x85, 0x52, 0x4b, 0xf3, 0x1b, 0xcb, 0x9e, 0x1d, 0x7f, 0x25, 0x01, 0x27, 0x02, 0x76, - 0x1c, 0x40, 0x6e, 0x35, 0xe7, 0x42, 0xbc, 0xc5, 0xf7, 0xf0, 0x4a, 0xe8, 0x32, 0xa4, 0x08, 0x3e, - 0xea, 0xf2, 0x81, 0xf7, 0xfc, 0xe7, 0xbf, 0xf1, 0x25, 0x39, 0x7c, 0x5a, 0x13, 0x1a, 0x15, 0xca, - 0xa4, 0xf4, 0x6b, 0xbd, 0xeb, 0x2f, 0xe7, 0x7f, 0xed, 0xce, 0xb9, 0x73, 0x6a, 0x8c, 0xea, 0xf0, - 0xd7, 0xcf, 0x40, 0x21, 0x92, 0x99, 0x30, 0xff, 0x18, 0x9f, 0xdb, 0xf4, 0xe0, 0x69, 0xdb, 0xe5, - 0x3f, 0x9d, 0x46, 0xaa, 0x4b, 0x76, 0x64, 0xc1, 0xe4, 0xdb, 0x48, 0x73, 0xfe, 0x0a, 0x53, 0xf8, - 0xec, 0x49, 0xef, 0xa0, 0x4a, 0xe2, 0xff, 0x05, 0x8a, 0x65, 0xaa, 0xcf, 0x02, 0xf8, 0x72, 0xf1, - 0x35, 0xd6, 0xd4, 0x6c, 0x4b, 0x08, 0x98, 0x0d, 0xf8, 0x7f, 0x25, 0x40, 0x21, 0x7f, 0x5c, 0x82, - 0xa3, 0x2d, 0x4d, 0x72, 0xb7, 0x7d, 0x21, 0xf6, 0xd2, 0xfb, 0x21, 0xd2, 0x8e, 0x0b, 0x31, 0xc2, - 0x4d, 0xb7, 0x15, 0x8e, 0xb5, 0x1a, 0x92, 0xee, 0x59, 0x38, 0x12, 0x16, 0x4e, 0xa8, 0xe3, 0x3e, - 0x18, 0x09, 0x6f, 0x88, 0x72, 0xb5, 0x0c, 0x87, 0xb6, 0x44, 0xe5, 0xe7, 0xa3, 0xfa, 0xf4, 0xfa, - 0xf6, 0x0c, 0x64, 0x3c, 0x54, 0x6f, 0x6b, 0xa1, 0x4b, 0xd7, 0x7c, 0x0a, 0xf9, 0x83, 0x12, 0xcc, - 0x84, 0x39, 0x07, 0x52, 0x95, 0xc3, 0x09, 0xf9, 0x73, 0x0f, 0xe1, 0xb7, 0x25, 0x38, 0xd9, 0x41, - 0x16, 0xde, 0x61, 0x1b, 0x26, 0x02, 0x8b, 0x65, 0xe1, 0x7a, 0xc5, 0xb0, 0xca, 0xed, 0x73, 0x41, - 0x6f, 0xc1, 0x78, 0x9c, 0x28, 0xe1, 0xb3, 0xdf, 0x99, 0x1e, 0x6f, 0xad, 0x73, 0x94, 0xf1, 0xd6, - 0x55, 0xee, 0x1d, 0x18, 0xff, 0x8f, 0x48, 0xf0, 0x60, 0xb8, 0x6b, 0x31, 0x59, 0xe5, 0x9b, 0xad, - 0xef, 0xaf, 0x4b, 0x70, 0xba, 0x17, 0xa1, 0xb8, 0xe2, 0x5f, 0x80, 0x71, 0x3f, 0xcf, 0x8d, 0xea, - 0xbd, 0xa7, 0xac, 0x99, 0x59, 0x1f, 0xf2, 0xb8, 0xdc, 0x41, 0x05, 0x0b, 0x87, 0x13, 0x1c, 0x52, - 0x4f, 0x99, 0xe1, 0x0d, 0x4b, 0xa1, 0xcc, 0xd0, 0x96, 0x65, 0x8c, 0xce, 0x13, 0x31, 0x3a, 0xf7, - 0x13, 0x62, 0xd9, 0xe0, 0xfe, 0x26, 0x66, 0xbb, 0x69, 0x13, 0xc6, 0x63, 0x4c, 0x94, 0xcf, 0xce, - 0x1e, 0x2c, 0x54, 0x41, 0xad, 0x46, 0x28, 0x1f, 0xc0, 0x34, 0x6d, 0x2f, 0x46, 0xb1, 0x77, 0xbb, - 0xab, 0x98, 0xfb, 0x88, 0xd8, 0xa6, 0x79, 0x9f, 0xe7, 0x61, 0x80, 0x8d, 0x2b, 0xef, 0xe6, 0x21, - 0x0c, 0x82, 0x13, 0xca, 0x1f, 0x15, 0xbe, 0x68, 0x51, 0x88, 0x1b, 0x3f, 0x37, 0x7a, 0xe9, 0xe3, - 0xcf, 0x39, 0x37, 0x02, 0x9d, 0xff, 0x8a, 0xf0, 0x4a, 0xf1, 0x52, 0xf1, 0xee, 0xbf, 0xf3, 0xe7, - 0xf6, 0x4a, 0x4c, 0x17, 0x77, 0xc7, 0xfd, 0x7c, 0x42, 0xb8, 0x1f, 0xaf, 0x0f, 0x5d, 0xdc, 0xcf, - 0x9b, 0xab, 0x62, 0xcf, 0x11, 0x75, 0x11, 0xef, 0xff, 0x04, 0x47, 0xf4, 0x03, 0x09, 0x8e, 0xd1, - 0xbe, 0x04, 0x97, 0xef, 0x87, 0x55, 0xed, 0xc3, 0x80, 0x1c, 0xbb, 0x5a, 0x89, 0x9d, 0xa5, 0x39, - 0xc7, 0xae, 0x5e, 0x09, 0xc5, 0x81, 0x87, 0x01, 0xd5, 0x42, 0x7b, 0x30, 0x14, 0x9b, 0xdd, 0xb6, - 0xca, 0xd5, 0x02, 0x7b, 0x00, 0x31, 0xc3, 0x96, 0xfa, 0x39, 0x86, 0xed, 0xcb, 0x12, 0x14, 0xe2, - 0xba, 0xca, 0x87, 0x49, 0x85, 0xc9, 0xd0, 0xbe, 0x76, 0x74, 0xa4, 0xde, 0xd2, 0x69, 0xc3, 0x23, - 0x32, 0x2d, 0x8e, 0xd8, 0xf8, 0x6e, 0xc5, 0xe5, 0xe9, 0xb0, 0xe5, 0xb5, 0x66, 0xac, 0x6f, 0xfa, - 0x74, 0xf8, 0x9d, 0x16, 0x3f, 0xf8, 0x0b, 0x99, 0xd3, 0x5e, 0x87, 0xa9, 0x36, 0x52, 0xde, 0xed, - 0x78, 0xf4, 0xff, 0xb5, 0x1d, 0xb4, 0x3b, 0x95, 0x16, 0x3f, 0xce, 0x2d, 0x3b, 0x7c, 0xe1, 0x36, - 0xb0, 0x86, 0x89, 0x7b, 0x74, 0x23, 0xbf, 0x0d, 0x8e, 0xc7, 0x52, 0x71, 0x99, 0xce, 0x42, 0x6a, - 0x4f, 0x73, 0x5c, 0x2e, 0xce, 0x54, 0x54, 0x9c, 0x08, 0x15, 0xc5, 0x95, 0x11, 0xe4, 0x28, 0xcb, - 0x0d, 0xd3, 0xd4, 0x79, 0xf3, 0xf2, 0x02, 0x8c, 0x05, 0x60, 0x9c, 0xf9, 0x2c, 0xa4, 0x2c, 0x93, - 0x3f, 0x01, 0x27, 0x2b, 0xda, 0xe8, 0xe6, 0xb3, 0x69, 0xea, 0xbc, 0x9b, 0x14, 0x4f, 0x9e, 0x00, - 0xc4, 0x98, 0xd0, 0x7d, 0x68, 0xc1, 0xfa, 0x32, 0x8c, 0x87, 0xa0, 0x9c, 0xf9, 0x6d, 0xed, 0x6d, - 0x9f, 0x7d, 0x6d, 0x1c, 0xfa, 0x29, 0x37, 0xf4, 0x5e, 0x09, 0x20, 0x70, 0xd8, 0x78, 0x7f, 0x94, - 0x3c, 0x7e, 0xad, 0x58, 0x78, 0xa0, 0x2b, 0x1e, 0xcf, 0x8d, 0xe4, 0xf7, 0xfd, 0xfb, 0xef, 0x7f, - 0x34, 0x71, 0x02, 0x15, 0xe6, 0x22, 0xab, 0xd2, 0x80, 0xbd, 0xff, 0x46, 0xe8, 0x65, 0xf1, 0x7d, - 0x9d, 0x59, 0x0b, 0x09, 0xee, 0xef, 0x86, 0xc6, 0x05, 0x78, 0x8c, 0x0a, 0xf0, 0x08, 0x7a, 0xa8, - 0xbd, 0x00, 0x73, 0xef, 0x0e, 0x1b, 0xf9, 0x7b, 0xd0, 0x97, 0x24, 0x98, 0x88, 0x5b, 0xea, 0xa0, - 0x47, 0x3b, 0xb7, 0xda, 0x1a, 0xb2, 0x0b, 0x67, 0x0e, 0x41, 0xc1, 0x45, 0xbe, 0x40, 0x45, 0x3e, - 0x87, 0x9e, 0x3a, 0x84, 0xc8, 0x73, 0xc1, 0xdd, 0xe7, 0xbf, 0x92, 0xe0, 0x9e, 0x8e, 0x2b, 0x07, - 0x74, 0xae, 0xb3, 0x54, 0x1d, 0x72, 0x90, 0x42, 0xf1, 0x76, 0x48, 0x79, 0xcf, 0x96, 0x69, 0xcf, - 0x16, 0xd0, 0xfc, 0x61, 0x7a, 0x16, 0xbb, 0x85, 0x8f, 0x3e, 0x17, 0xbe, 0x2b, 0x16, 0x6f, 0x0e, - 0x2d, 0x89, 0x78, 0x1b, 0xc3, 0x6d, 0x4d, 0xfa, 0xe4, 0x0d, 0x2a, 0xea, 0x73, 0xe8, 0xd2, 0x6d, - 0x0e, 0xc2, 0xdc, 0xbb, 0xc3, 0x0e, 0xf6, 0x3d, 0xe8, 0x3b, 0x52, 0xfc, 0x3d, 0xaf, 0xb9, 0x58, - 0x91, 0xda, 0x2f, 0x26, 0x0a, 0x8f, 0xf6, 0x4e, 0xc0, 0x3b, 0x83, 0x69, 0x67, 0x2a, 0xe8, 0x5d, - 0x77, 0xaa, 0x33, 0xb1, 0x83, 0x82, 0xbe, 0x20, 0xc1, 0x44, 0x5c, 0x2e, 0xde, 0x66, 0xda, 0x74, - 0x58, 0x4c, 0xb4, 0x99, 0x36, 0x9d, 0x12, 0x7d, 0xf9, 0x71, 0xda, 0xc9, 0x59, 0xf4, 0x70, 0xb4, - 0x93, 0x1d, 0x47, 0x85, 0xcc, 0x95, 0x8e, 0xc9, 0x6d, 0x9b, 0xb9, 0xd2, 0x4b, 0xbe, 0xde, 0x66, - 0xae, 0xf4, 0x94, 0x4b, 0xb7, 0x9f, 0x2b, 0x5e, 0x0f, 0x7a, 0x1c, 0x16, 0x07, 0xfd, 0x9e, 0x04, - 0xc3, 0xa1, 0x4c, 0x10, 0x3d, 0x18, 0x2b, 0x58, 0x5c, 0x62, 0x5c, 0x38, 0xdd, 0x0b, 0x2a, 0x97, - 0x79, 0x9e, 0xca, 0x7c, 0x1e, 0x9d, 0x3b, 0x8c, 0xcc, 0xe1, 0x93, 0xb3, 0x3f, 0x91, 0x60, 0x3c, - 0x26, 0xbb, 0x6a, 0x33, 0x4b, 0xda, 0x27, 0x87, 0x85, 0x47, 0x7b, 0x27, 0xe0, 0xd2, 0x3f, 0x4b, - 0xa5, 0x7f, 0x1a, 0x3d, 0x79, 0x18, 0xe9, 0x03, 0x71, 0xec, 0xab, 0xfe, 0x15, 0x97, 0x00, 0x7f, - 0x34, 0xdb, 0xa3, 0x20, 0x42, 0xf0, 0xb9, 0x9e, 0xf1, 0xb9, 0xdc, 0xeb, 0x54, 0xee, 0x65, 0xb4, - 0x74, 0x7b, 0x72, 0xb7, 0x86, 0xbf, 0x8f, 0x4b, 0x2d, 0x0f, 0x9a, 0xe2, 0xad, 0x20, 0x36, 0x09, - 0x2b, 0x3c, 0xd4, 0x13, 0x2e, 0x17, 0xfe, 0x51, 0x2a, 0xfc, 0x69, 0x74, 0x2a, 0x2a, 0x7c, 0xe0, - 0x5e, 0x92, 0x66, 0xec, 0x9a, 0x73, 0xef, 0x66, 0xa9, 0xdc, 0x7b, 0x90, 0xc6, 0xef, 0x8f, 0xcc, - 0xc4, 0x36, 0x13, 0x48, 0xc7, 0x0a, 0x27, 0x3b, 0x60, 0xf0, 0xe6, 0x4f, 0xd0, 0xe6, 0x27, 0xd1, - 0x44, 0xb4, 0x79, 0x92, 0x8a, 0xa1, 0x97, 0xbc, 0xcb, 0x62, 0x72, 0x3c, 0xab, 0x60, 0x8a, 0x56, - 0xb8, 0xb7, 0x23, 0x0e, 0x6f, 0x70, 0x8a, 0x36, 0x98, 0x47, 0x93, 0x2d, 0x0d, 0xb2, 0x44, 0xed, - 0x0e, 0x9e, 0xe6, 0xfe, 0xdb, 0x23, 0x70, 0x34, 0xd2, 0x88, 0x7b, 0xbd, 0xcd, 0x61, 0x44, 0x87, - 0xd7, 0x76, 0x5d, 0x5f, 0xd3, 0xb5, 0x79, 0xbf, 0x77, 0xf8, 0x37, 0x76, 0x9d, 0x4f, 0x2e, 0xfe, - 0x20, 0x05, 0x68, 0xd5, 0xa9, 0x2f, 0xd8, 0x98, 0xfd, 0x8b, 0x2a, 0x3e, 0xbd, 0x22, 0xef, 0x4e, - 0xa4, 0xdb, 0x7a, 0x77, 0x52, 0x0e, 0xbd, 0xe4, 0x48, 0xf4, 0xf6, 0x10, 0xac, 0xe7, 0xe7, 0x1c, - 0xc9, 0xbb, 0xfd, 0x9c, 0x23, 0xfe, 0x7a, 0x68, 0xea, 0xce, 0xdd, 0x15, 0xef, 0xbf, 0xad, 0xbb, - 0xe2, 0x0b, 0x30, 0xc0, 0xdf, 0x5e, 0x0d, 0x74, 0x78, 0x7b, 0x75, 0x24, 0xfe, 0x81, 0x15, 0x27, - 0x45, 0x8f, 0x88, 0x0f, 0x6d, 0x0e, 0x76, 0xbe, 0xdd, 0xc7, 0xbf, 0xc0, 0xe9, 0xaf, 0x45, 0x4f, - 0x40, 0xa1, 0xd5, 0x5c, 0xbc, 0x79, 0xf8, 0xde, 0x24, 0xe4, 0x56, 0x9d, 0x7a, 0xb9, 0xa6, 0xb9, - 0x77, 0xd8, 0x96, 0x2e, 0xb4, 0xbf, 0x6c, 0x8f, 0x6e, 0xdd, 0x9c, 0x1e, 0x61, 0x0a, 0xec, 0xa0, - 0xb6, 0x3d, 0x18, 0x8d, 0xbc, 0x4d, 0xe4, 0x16, 0x74, 0xe1, 0x90, 0xaf, 0x23, 0x23, 0x5c, 0x64, - 0x7a, 0x51, 0x3a, 0x60, 0xc2, 0xc8, 0x89, 0xb7, 0x57, 0x66, 0x38, 0x0b, 0x77, 0xe9, 0xe9, 0x91, - 0x3f, 0x42, 0x05, 0xc8, 0x47, 0x87, 0xc0, 0x1b, 0x9f, 0x9b, 0x12, 0x0c, 0xad, 0x3a, 0x22, 0x33, - 0xc2, 0xbf, 0xa0, 0xaf, 0x21, 0xe6, 0xbc, 0xef, 0x22, 0x26, 0x3b, 0x5b, 0xa7, 0xf8, 0x46, 0xa2, - 0xdf, 0xf9, 0x23, 0x30, 0x1e, 0xe8, 0x9f, 0xd7, 0xef, 0xaf, 0x26, 0xa8, 0x97, 0x2b, 0xe1, 0xba, - 0x66, 0x78, 0x49, 0x16, 0xfe, 0xbb, 0x7a, 0xff, 0xdb, 0xd7, 0x6f, 0xea, 0xb0, 0xfa, 0xdd, 0xa7, - 0xd3, 0x3f, 0xa2, 0x47, 0x6f, 0xdf, 0x64, 0xb5, 0xf5, 0x2d, 0x82, 0x74, 0x88, 0x2f, 0x68, 0x44, - 0x5e, 0x1c, 0xc8, 0xdf, 0x95, 0x60, 0x78, 0xd5, 0xa9, 0x6f, 0x1b, 0xb5, 0xff, 0x6b, 0xed, 0x75, - 0x17, 0x8e, 0x84, 0x7a, 0x78, 0x97, 0x54, 0x79, 0xf6, 0x1b, 0x49, 0x48, 0xae, 0x3a, 0x75, 0xa4, - 0xc2, 0x68, 0x34, 0xd4, 0xb7, 0x24, 0x61, 0xad, 0xfe, 0xbd, 0x75, 0xb9, 0xd2, 0x3e, 0x06, 0xa0, - 0x77, 0xc2, 0x70, 0xd8, 0xff, 0xcf, 0xc4, 0x10, 0x87, 0x30, 0x0a, 0xa7, 0xba, 0x61, 0x78, 0xcc, - 0x57, 0x20, 0xed, 0x39, 0xaf, 0xe3, 0x31, 0x54, 0xa2, 0xb2, 0x35, 0x6d, 0x8c, 0x71, 0x0b, 0x44, - 0x1b, 0x51, 0x97, 0x10, 0xa7, 0x8d, 0x08, 0x4e, 0xac, 0x36, 0xda, 0x4d, 0x09, 0x05, 0x20, 0x60, - 0xbf, 0xf7, 0xc4, 0x50, 0xfa, 0xd5, 0x85, 0xfb, 0x3a, 0x56, 0x7b, 0x67, 0x04, 0x77, 0x2e, 0x9b, - 0xfd, 0xdf, 0x01, 0x00, 0x00, 0xff, 0xff, 0xe7, 0x8d, 0x7c, 0x56, 0x79, 0x8f, 0x00, 0x00, + // 9793 bytes of a gzipped FileDescriptorSet + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x7d, 0x7b, 0x70, 0x24, 0xc7, + 0x79, 0x1f, 0x66, 0x77, 0x01, 0xec, 0x7e, 0x78, 0x2d, 0x1a, 0x38, 0xdc, 0xde, 0xde, 0x11, 0xc0, + 0x0d, 0x45, 0xf2, 0x78, 0xe4, 0x01, 0xe4, 0xf1, 0x79, 0x7b, 0x22, 0xcf, 0xbb, 0xc0, 0x1e, 0x0e, + 0x24, 0x5e, 0x1a, 0x00, 0x47, 0x8a, 0x2a, 0xd5, 0x66, 0xb0, 0xdb, 0x58, 0x0c, 0x31, 0x3b, 0x33, + 0x9c, 0x99, 0xbd, 0x3b, 0x50, 0x96, 0x43, 0x49, 0xb1, 0x23, 0xd1, 0xe5, 0x58, 0x8f, 0x54, 0x99, + 0x96, 0x74, 0x0a, 0x65, 0x39, 0x91, 0xad, 0xd8, 0x96, 0x94, 0x28, 0xb2, 0x9d, 0xa8, 0x5c, 0xd2, + 0x1f, 0x56, 0x24, 0xa5, 0x2a, 0x25, 0x25, 0x55, 0x8e, 0xca, 0x71, 0x9d, 0x64, 0x4a, 0x55, 0x51, + 0x14, 0x25, 0x56, 0xce, 0x72, 0x2a, 0x55, 0xfa, 0x27, 0xd5, 0xaf, 0x79, 0xed, 0xec, 0x03, 0xa7, + 0x3b, 0x5a, 0x89, 0xf3, 0x17, 0xb6, 0xbb, 0xbf, 0xef, 0xd7, 0x5f, 0x7f, 0xfd, 0xf5, 0xd7, 0x5f, + 0xbf, 0x06, 0xf0, 0xf9, 0xf3, 0x30, 0x5b, 0x37, 0xcd, 0xba, 0x8e, 0xe7, 0x2d, 0xdb, 0x74, 0xcd, + 0x9d, 0xe6, 0xee, 0x7c, 0x0d, 0x3b, 0x55, 0x5b, 0xb3, 0x5c, 0xd3, 0x9e, 0xa3, 0x79, 0x68, 0x8c, + 0x51, 0xcc, 0x09, 0x0a, 0x79, 0x15, 0xc6, 0x2f, 0x6a, 0x3a, 0x5e, 0xf4, 0x08, 0x37, 0xb1, 0x8b, + 0x9e, 0x84, 0xd4, 0xae, 0xa6, 0xe3, 0x9c, 0x34, 0x9b, 0x3c, 0x35, 0x74, 0xf6, 0x2d, 0x73, 0x11, + 0xa6, 0xb9, 0x30, 0xc7, 0x06, 0xc9, 0x56, 0x28, 0x87, 0xfc, 0xfd, 0x14, 0x4c, 0xc4, 0x94, 0x22, + 0x04, 0x29, 0x43, 0x6d, 0x10, 0x44, 0xe9, 0x54, 0x46, 0xa1, 0xbf, 0x51, 0x0e, 0x06, 0x2d, 0xb5, + 0xba, 0xaf, 0xd6, 0x71, 0x2e, 0x41, 0xb3, 0x45, 0x12, 0x4d, 0x03, 0xd4, 0xb0, 0x85, 0x8d, 0x1a, + 0x36, 0xaa, 0x07, 0xb9, 0xe4, 0x6c, 0xf2, 0x54, 0x46, 0x09, 0xe4, 0xa0, 0x07, 0x60, 0xdc, 0x6a, + 0xee, 0xe8, 0x5a, 0xb5, 0x12, 0x20, 0x83, 0xd9, 0xe4, 0xa9, 0x7e, 0x25, 0xcb, 0x0a, 0x16, 0x7d, + 0xe2, 0xfb, 0x60, 0xec, 0x2a, 0x56, 0xf7, 0x83, 0xa4, 0x43, 0x94, 0x74, 0x94, 0x64, 0x07, 0x08, + 0x17, 0x60, 0xb8, 0x81, 0x1d, 0x47, 0xad, 0xe3, 0x8a, 0x7b, 0x60, 0xe1, 0x5c, 0x8a, 0xb6, 0x7e, + 0xb6, 0xa5, 0xf5, 0xd1, 0x96, 0x0f, 0x71, 0xae, 0xad, 0x03, 0x0b, 0xa3, 0x22, 0x64, 0xb0, 0xd1, + 0x6c, 0x30, 0x84, 0xfe, 0x36, 0xfa, 0x2b, 0x1b, 0xcd, 0x46, 0x14, 0x25, 0x4d, 0xd8, 0x38, 0xc4, + 0xa0, 0x83, 0xed, 0x2b, 0x5a, 0x15, 0xe7, 0x06, 0x28, 0xc0, 0x7d, 0x2d, 0x00, 0x9b, 0xac, 0x3c, + 0x8a, 0x21, 0xf8, 0xd0, 0x02, 0x64, 0xf0, 0x35, 0x17, 0x1b, 0x8e, 0x66, 0x1a, 0xb9, 0x41, 0x0a, + 0x72, 0x4f, 0x4c, 0x2f, 0x62, 0xbd, 0x16, 0x85, 0xf0, 0xf9, 0xd0, 0xe3, 0x30, 0x68, 0x5a, 0xae, + 0x66, 0x1a, 0x4e, 0x2e, 0x3d, 0x2b, 0x9d, 0x1a, 0x3a, 0x7b, 0x22, 0xd6, 0x10, 0xd6, 0x19, 0x8d, + 0x22, 0x88, 0xd1, 0x32, 0x64, 0x1d, 0xb3, 0x69, 0x57, 0x71, 0xa5, 0x6a, 0xd6, 0x70, 0x45, 0x33, + 0x76, 0xcd, 0x5c, 0x86, 0x02, 0xcc, 0xb4, 0x36, 0x84, 0x12, 0x2e, 0x98, 0x35, 0xbc, 0x6c, 0xec, + 0x9a, 0xca, 0xa8, 0x13, 0x4a, 0xa3, 0x29, 0x18, 0x70, 0x0e, 0x0c, 0x57, 0xbd, 0x96, 0x1b, 0xa6, + 0x16, 0xc2, 0x53, 0xf2, 0x1f, 0x0f, 0xc0, 0x58, 0x2f, 0x26, 0x76, 0x1e, 0xfa, 0x77, 0x49, 0x2b, + 0x73, 0x89, 0xc3, 0xe8, 0x80, 0xf1, 0x84, 0x95, 0x38, 0x70, 0x8b, 0x4a, 0x2c, 0xc2, 0x90, 0x81, + 0x1d, 0x17, 0xd7, 0x98, 0x45, 0x24, 0x7b, 0xb4, 0x29, 0x60, 0x4c, 0xad, 0x26, 0x95, 0xba, 0x25, + 0x93, 0x7a, 0x1e, 0xc6, 0x3c, 0x91, 0x2a, 0xb6, 0x6a, 0xd4, 0x85, 0x6d, 0xce, 0x77, 0x93, 0x64, + 0xae, 0x2c, 0xf8, 0x14, 0xc2, 0xa6, 0x8c, 0xe2, 0x50, 0x1a, 0x2d, 0x02, 0x98, 0x06, 0x36, 0x77, + 0x2b, 0x35, 0x5c, 0xd5, 0x73, 0xe9, 0x36, 0x5a, 0x5a, 0x27, 0x24, 0x2d, 0x5a, 0x32, 0x59, 0x6e, + 0x55, 0x47, 0xe7, 0x7c, 0x53, 0x1b, 0x6c, 0x63, 0x29, 0xab, 0x6c, 0x90, 0xb5, 0x58, 0xdb, 0x36, + 0x8c, 0xda, 0x98, 0xd8, 0x3d, 0xae, 0xf1, 0x96, 0x65, 0xa8, 0x10, 0x73, 0x5d, 0x5b, 0xa6, 0x70, + 0x36, 0xd6, 0xb0, 0x11, 0x3b, 0x98, 0x44, 0x77, 0x83, 0x97, 0x51, 0xa1, 0x66, 0x05, 0xd4, 0x0b, + 0x0d, 0x8b, 0xcc, 0x35, 0xb5, 0x81, 0xf3, 0x2f, 0xc3, 0x68, 0x58, 0x3d, 0x68, 0x12, 0xfa, 0x1d, + 0x57, 0xb5, 0x5d, 0x6a, 0x85, 0xfd, 0x0a, 0x4b, 0xa0, 0x2c, 0x24, 0xb1, 0x51, 0xa3, 0x5e, 0xae, + 0x5f, 0x21, 0x3f, 0xd1, 0x2f, 0xf8, 0x0d, 0x4e, 0xd2, 0x06, 0xdf, 0xdb, 0xda, 0xa3, 0x21, 0xe4, + 0x68, 0xbb, 0xf3, 0x4f, 0xc0, 0x48, 0xa8, 0x01, 0xbd, 0x56, 0x2d, 0xff, 0x22, 0x1c, 0x89, 0x85, + 0x46, 0xcf, 0xc3, 0x64, 0xd3, 0xd0, 0x0c, 0x17, 0xdb, 0x96, 0x8d, 0x89, 0xc5, 0xb2, 0xaa, 0x72, + 0xff, 0x65, 0xb0, 0x8d, 0xcd, 0x6d, 0x07, 0xa9, 0x19, 0x8a, 0x32, 0xd1, 0x6c, 0xcd, 0x3c, 0x9d, + 0x49, 0xff, 0x60, 0x30, 0xfb, 0xca, 0x2b, 0xaf, 0xbc, 0x92, 0x90, 0xbf, 0x32, 0x00, 0x93, 0x71, + 0x63, 0x26, 0x76, 0xf8, 0x4e, 0xc1, 0x80, 0xd1, 0x6c, 0xec, 0x60, 0x9b, 0x2a, 0xa9, 0x5f, 0xe1, + 0x29, 0x54, 0x84, 0x7e, 0x5d, 0xdd, 0xc1, 0x7a, 0x2e, 0x35, 0x2b, 0x9d, 0x1a, 0x3d, 0xfb, 0x40, + 0x4f, 0xa3, 0x72, 0x6e, 0x85, 0xb0, 0x28, 0x8c, 0x13, 0x3d, 0x0d, 0x29, 0xee, 0xa2, 0x09, 0xc2, + 0xe9, 0xde, 0x10, 0xc8, 0x58, 0x52, 0x28, 0x1f, 0x3a, 0x0e, 0x19, 0xf2, 0x97, 0xd9, 0xc6, 0x00, + 0x95, 0x39, 0x4d, 0x32, 0x88, 0x5d, 0xa0, 0x3c, 0xa4, 0xe9, 0x30, 0xa9, 0x61, 0x31, 0xb5, 0x79, + 0x69, 0x62, 0x58, 0x35, 0xbc, 0xab, 0x36, 0x75, 0xb7, 0x72, 0x45, 0xd5, 0x9b, 0x98, 0x1a, 0x7c, + 0x46, 0x19, 0xe6, 0x99, 0x97, 0x49, 0x1e, 0x9a, 0x81, 0x21, 0x36, 0xaa, 0x34, 0xa3, 0x86, 0xaf, + 0x51, 0xef, 0xd9, 0xaf, 0xb0, 0x81, 0xb6, 0x4c, 0x72, 0x48, 0xf5, 0x2f, 0x3a, 0xa6, 0x21, 0x4c, + 0x93, 0x56, 0x41, 0x32, 0x68, 0xf5, 0x4f, 0x44, 0x1d, 0xf7, 0x5d, 0xf1, 0xcd, 0x6b, 0x19, 0x4b, + 0xf7, 0xc1, 0x18, 0xa5, 0x78, 0x84, 0x77, 0xbd, 0xaa, 0xe7, 0xc6, 0x67, 0xa5, 0x53, 0x69, 0x65, + 0x94, 0x65, 0xaf, 0xf3, 0x5c, 0xf9, 0x8b, 0x09, 0x48, 0x51, 0xc7, 0x32, 0x06, 0x43, 0x5b, 0x6f, + 0xdf, 0x28, 0x57, 0x16, 0xd7, 0xb7, 0x4b, 0x2b, 0xe5, 0xac, 0x84, 0x46, 0x01, 0x68, 0xc6, 0xc5, + 0x95, 0xf5, 0xe2, 0x56, 0x36, 0xe1, 0xa5, 0x97, 0xd7, 0xb6, 0x1e, 0x7f, 0x34, 0x9b, 0xf4, 0x18, + 0xb6, 0x59, 0x46, 0x2a, 0x48, 0xf0, 0xc8, 0xd9, 0x6c, 0x3f, 0xca, 0xc2, 0x30, 0x03, 0x58, 0x7e, + 0xbe, 0xbc, 0xf8, 0xf8, 0xa3, 0xd9, 0x81, 0x70, 0xce, 0x23, 0x67, 0xb3, 0x83, 0x68, 0x04, 0x32, + 0x34, 0xa7, 0xb4, 0xbe, 0xbe, 0x92, 0x4d, 0x7b, 0x98, 0x9b, 0x5b, 0xca, 0xf2, 0xda, 0x52, 0x36, + 0xe3, 0x61, 0x2e, 0x29, 0xeb, 0xdb, 0x1b, 0x59, 0xf0, 0x10, 0x56, 0xcb, 0x9b, 0x9b, 0xc5, 0xa5, + 0x72, 0x76, 0xc8, 0xa3, 0x28, 0xbd, 0x7d, 0xab, 0xbc, 0x99, 0x1d, 0x0e, 0x89, 0xf5, 0xc8, 0xd9, + 0xec, 0x88, 0x57, 0x45, 0x79, 0x6d, 0x7b, 0x35, 0x3b, 0x8a, 0xc6, 0x61, 0x84, 0x55, 0x21, 0x84, + 0x18, 0x8b, 0x64, 0x3d, 0xfe, 0x68, 0x36, 0xeb, 0x0b, 0xc2, 0x50, 0xc6, 0x43, 0x19, 0x8f, 0x3f, + 0x9a, 0x45, 0xf2, 0x02, 0xf4, 0x53, 0x33, 0x44, 0x08, 0x46, 0x57, 0x8a, 0xa5, 0xf2, 0x4a, 0x65, + 0x7d, 0x63, 0x6b, 0x79, 0x7d, 0xad, 0xb8, 0x92, 0x95, 0xfc, 0x3c, 0xa5, 0xfc, 0xb6, 0xed, 0x65, + 0xa5, 0xbc, 0x98, 0x4d, 0x04, 0xf3, 0x36, 0xca, 0xc5, 0xad, 0xf2, 0x62, 0x36, 0x29, 0x57, 0x61, + 0x32, 0xce, 0xa1, 0xc6, 0x0e, 0xa1, 0x80, 0x2d, 0x24, 0xda, 0xd8, 0x02, 0xc5, 0x8a, 0xda, 0x82, + 0xfc, 0xbd, 0x04, 0x4c, 0xc4, 0x4c, 0x2a, 0xb1, 0x95, 0x5c, 0x80, 0x7e, 0x66, 0xcb, 0x6c, 0x9a, + 0xbd, 0x3f, 0x76, 0x76, 0xa2, 0x96, 0xdd, 0x32, 0xd5, 0x52, 0xbe, 0x60, 0xa8, 0x91, 0x6c, 0x13, + 0x6a, 0x10, 0x88, 0x16, 0x83, 0x7d, 0x67, 0x8b, 0xf3, 0x67, 0xf3, 0xe3, 0xe3, 0xbd, 0xcc, 0x8f, + 0x34, 0xef, 0x70, 0x93, 0x40, 0x7f, 0xcc, 0x24, 0x70, 0x1e, 0xc6, 0x5b, 0x80, 0x7a, 0x76, 0xc6, + 0xef, 0x93, 0x20, 0xd7, 0x4e, 0x39, 0x5d, 0x5c, 0x62, 0x22, 0xe4, 0x12, 0xcf, 0x47, 0x35, 0x78, + 0xb2, 0x7d, 0x27, 0xb4, 0xf4, 0xf5, 0xa7, 0x25, 0x98, 0x8a, 0x0f, 0x29, 0x63, 0x65, 0x78, 0x1a, + 0x06, 0x1a, 0xd8, 0xdd, 0x33, 0x45, 0x58, 0x75, 0x6f, 0xcc, 0x64, 0x4d, 0x8a, 0xa3, 0x9d, 0xcd, + 0xb9, 0x82, 0xb3, 0x7d, 0xb2, 0x5d, 0x5c, 0xc8, 0xa4, 0x69, 0x91, 0xf4, 0x03, 0x09, 0x38, 0x12, + 0x0b, 0x1e, 0x2b, 0xe8, 0x5d, 0x00, 0x9a, 0x61, 0x35, 0x5d, 0x16, 0x3a, 0x31, 0x4f, 0x9c, 0xa1, + 0x39, 0xd4, 0x79, 0x11, 0x2f, 0xdb, 0x74, 0xbd, 0xf2, 0x24, 0x2d, 0x07, 0x96, 0x45, 0x09, 0x9e, + 0xf4, 0x05, 0x4d, 0x51, 0x41, 0xa7, 0xdb, 0xb4, 0xb4, 0xc5, 0x30, 0x1f, 0x82, 0x6c, 0x55, 0xd7, + 0xb0, 0xe1, 0x56, 0x1c, 0xd7, 0xc6, 0x6a, 0x43, 0x33, 0xea, 0x74, 0xaa, 0x49, 0x17, 0xfa, 0x77, + 0x55, 0xdd, 0xc1, 0xca, 0x18, 0x2b, 0xde, 0x14, 0xa5, 0x84, 0x83, 0x1a, 0x90, 0x1d, 0xe0, 0x18, + 0x08, 0x71, 0xb0, 0x62, 0x8f, 0x43, 0xfe, 0x50, 0x06, 0x86, 0x02, 0x01, 0x38, 0x3a, 0x09, 0xc3, + 0x2f, 0xaa, 0x57, 0xd4, 0x8a, 0x58, 0x54, 0x31, 0x4d, 0x0c, 0x91, 0xbc, 0x0d, 0xbe, 0xb0, 0x7a, + 0x08, 0x26, 0x29, 0x89, 0xd9, 0x74, 0xb1, 0x5d, 0xa9, 0xea, 0xaa, 0xe3, 0x50, 0xa5, 0xa5, 0x29, + 0x29, 0x22, 0x65, 0xeb, 0xa4, 0x68, 0x41, 0x94, 0xa0, 0xc7, 0x60, 0x82, 0x72, 0x34, 0x9a, 0xba, + 0xab, 0x59, 0x3a, 0xae, 0x90, 0x65, 0x9e, 0x43, 0xa7, 0x1c, 0x4f, 0xb2, 0x71, 0x42, 0xb1, 0xca, + 0x09, 0x88, 0x44, 0x0e, 0x5a, 0x84, 0xbb, 0x28, 0x5b, 0x1d, 0x1b, 0xd8, 0x56, 0x5d, 0x5c, 0xc1, + 0x2f, 0x35, 0x55, 0xdd, 0xa9, 0xa8, 0x46, 0xad, 0xb2, 0xa7, 0x3a, 0x7b, 0xb9, 0x49, 0x02, 0x50, + 0x4a, 0xe4, 0x24, 0xe5, 0x18, 0x21, 0x5c, 0xe2, 0x74, 0x65, 0x4a, 0x56, 0x34, 0x6a, 0x97, 0x54, + 0x67, 0x0f, 0x15, 0x60, 0x8a, 0xa2, 0x38, 0xae, 0xad, 0x19, 0xf5, 0x4a, 0x75, 0x0f, 0x57, 0xf7, + 0x2b, 0x4d, 0x77, 0xf7, 0xc9, 0xdc, 0xf1, 0x60, 0xfd, 0x54, 0xc2, 0x4d, 0x4a, 0xb3, 0x40, 0x48, + 0xb6, 0xdd, 0xdd, 0x27, 0xd1, 0x26, 0x0c, 0x93, 0xce, 0x68, 0x68, 0x2f, 0xe3, 0xca, 0xae, 0x69, + 0xd3, 0x39, 0x74, 0x34, 0xc6, 0x35, 0x05, 0x34, 0x38, 0xb7, 0xce, 0x19, 0x56, 0xcd, 0x1a, 0x2e, + 0xf4, 0x6f, 0x6e, 0x94, 0xcb, 0x8b, 0xca, 0x90, 0x40, 0xb9, 0x68, 0xda, 0xc4, 0xa0, 0xea, 0xa6, + 0xa7, 0xe0, 0x21, 0x66, 0x50, 0x75, 0x53, 0xa8, 0xf7, 0x31, 0x98, 0xa8, 0x56, 0x59, 0x9b, 0xb5, + 0x6a, 0x85, 0x2f, 0xc6, 0x9c, 0x5c, 0x36, 0xa4, 0xac, 0x6a, 0x75, 0x89, 0x11, 0x70, 0x1b, 0x77, + 0xd0, 0x39, 0x38, 0xe2, 0x2b, 0x2b, 0xc8, 0x38, 0xde, 0xd2, 0xca, 0x28, 0xeb, 0x63, 0x30, 0x61, + 0x1d, 0xb4, 0x32, 0xa2, 0x50, 0x8d, 0xd6, 0x41, 0x94, 0xed, 0x09, 0x98, 0xb4, 0xf6, 0xac, 0x56, + 0xbe, 0xd3, 0x41, 0x3e, 0x64, 0xed, 0x59, 0x51, 0xc6, 0x7b, 0xe8, 0xca, 0xdc, 0xc6, 0x55, 0xd5, + 0xc5, 0xb5, 0xdc, 0xd1, 0x20, 0x79, 0xa0, 0x00, 0xcd, 0x41, 0xb6, 0x5a, 0xad, 0x60, 0x43, 0xdd, + 0xd1, 0x71, 0x45, 0xb5, 0xb1, 0xa1, 0x3a, 0xb9, 0x19, 0x4a, 0x9c, 0x72, 0xed, 0x26, 0x56, 0x46, + 0xab, 0xd5, 0x32, 0x2d, 0x2c, 0xd2, 0x32, 0x74, 0x1a, 0xc6, 0xcd, 0x9d, 0x17, 0xab, 0xcc, 0x22, + 0x2b, 0x96, 0x8d, 0x77, 0xb5, 0x6b, 0xb9, 0xb7, 0x50, 0xf5, 0x8e, 0x91, 0x02, 0x6a, 0x8f, 0x1b, + 0x34, 0x1b, 0xdd, 0x0f, 0xd9, 0xaa, 0xb3, 0xa7, 0xda, 0x16, 0x75, 0xc9, 0x8e, 0xa5, 0x56, 0x71, + 0xee, 0x1e, 0x46, 0xca, 0xf2, 0xd7, 0x44, 0x36, 0x19, 0x11, 0xce, 0x55, 0x6d, 0xd7, 0x15, 0x88, + 0xf7, 0xb1, 0x11, 0x41, 0xf3, 0x38, 0xda, 0x29, 0xc8, 0x12, 0x4d, 0x84, 0x2a, 0x3e, 0x45, 0xc9, + 0x46, 0xad, 0x3d, 0x2b, 0x58, 0xef, 0xdd, 0x30, 0x42, 0x28, 0xfd, 0x4a, 0xef, 0x67, 0x81, 0x9b, + 0xb5, 0x17, 0xa8, 0xf1, 0x51, 0x98, 0x22, 0x44, 0x0d, 0xec, 0xaa, 0x35, 0xd5, 0x55, 0x03, 0xd4, + 0x0f, 0x52, 0x6a, 0xa2, 0xf6, 0x55, 0x5e, 0x18, 0x92, 0xd3, 0x6e, 0xee, 0x1c, 0x78, 0x86, 0x75, + 0x86, 0xc9, 0x49, 0xf2, 0x84, 0x69, 0xdd, 0xb1, 0xe0, 0x5c, 0x2e, 0xc0, 0x70, 0xd0, 0xee, 0x51, + 0x06, 0x98, 0xe5, 0x67, 0x25, 0x12, 0x04, 0x2d, 0xac, 0x2f, 0x92, 0xf0, 0xe5, 0x85, 0x72, 0x36, + 0x41, 0xc2, 0xa8, 0x95, 0xe5, 0xad, 0x72, 0x45, 0xd9, 0x5e, 0xdb, 0x5a, 0x5e, 0x2d, 0x67, 0x93, + 0x81, 0xc0, 0xfe, 0x99, 0x54, 0xfa, 0xde, 0xec, 0x7d, 0xf2, 0xb7, 0x12, 0x30, 0x1a, 0x5e, 0xa9, + 0xa1, 0xb7, 0xc2, 0x51, 0xb1, 0xad, 0xe2, 0x60, 0xb7, 0x72, 0x55, 0xb3, 0xe9, 0x80, 0x6c, 0xa8, + 0x6c, 0x72, 0xf4, 0xec, 0x67, 0x92, 0x53, 0x6d, 0x62, 0xf7, 0x39, 0xcd, 0x26, 0xc3, 0xad, 0xa1, + 0xba, 0x68, 0x05, 0x66, 0x0c, 0xb3, 0xe2, 0xb8, 0xaa, 0x51, 0x53, 0xed, 0x5a, 0xc5, 0xdf, 0xd0, + 0xaa, 0xa8, 0xd5, 0x2a, 0x76, 0x1c, 0x93, 0x4d, 0x84, 0x1e, 0xca, 0x09, 0xc3, 0xdc, 0xe4, 0xc4, + 0xfe, 0x0c, 0x51, 0xe4, 0xa4, 0x11, 0xf3, 0x4d, 0xb6, 0x33, 0xdf, 0xe3, 0x90, 0x69, 0xa8, 0x56, + 0x05, 0x1b, 0xae, 0x7d, 0x40, 0xe3, 0xf3, 0xb4, 0x92, 0x6e, 0xa8, 0x56, 0x99, 0xa4, 0xdf, 0x94, + 0x65, 0xd2, 0x33, 0xa9, 0x74, 0x3a, 0x9b, 0x79, 0x26, 0x95, 0xce, 0x64, 0x41, 0x7e, 0x23, 0x09, + 0xc3, 0xc1, 0x78, 0x9d, 0x2c, 0x7f, 0xaa, 0x74, 0xc6, 0x92, 0xa8, 0x4f, 0xbb, 0xbb, 0x63, 0x74, + 0x3f, 0xb7, 0x40, 0xa6, 0xb2, 0xc2, 0x00, 0x0b, 0x8e, 0x15, 0xc6, 0x49, 0xc2, 0x08, 0x62, 0x6c, + 0x98, 0x05, 0x23, 0x69, 0x85, 0xa7, 0xd0, 0x12, 0x0c, 0xbc, 0xe8, 0x50, 0xec, 0x01, 0x8a, 0xfd, + 0x96, 0xce, 0xd8, 0xcf, 0x6c, 0x52, 0xf0, 0xcc, 0x33, 0x9b, 0x95, 0xb5, 0x75, 0x65, 0xb5, 0xb8, + 0xa2, 0x70, 0x76, 0x74, 0x0c, 0x52, 0xba, 0xfa, 0xf2, 0x41, 0x78, 0xd2, 0xa3, 0x59, 0xbd, 0x76, + 0xc2, 0x31, 0x48, 0x5d, 0xc5, 0xea, 0x7e, 0x78, 0xaa, 0xa1, 0x59, 0x77, 0x70, 0x30, 0xcc, 0x43, + 0x3f, 0xd5, 0x17, 0x02, 0xe0, 0x1a, 0xcb, 0xf6, 0xa1, 0x34, 0xa4, 0x16, 0xd6, 0x15, 0x32, 0x20, + 0xb2, 0x30, 0xcc, 0x72, 0x2b, 0x1b, 0xcb, 0xe5, 0x85, 0x72, 0x36, 0x21, 0x3f, 0x06, 0x03, 0x4c, + 0x09, 0x64, 0xb0, 0x78, 0x6a, 0xc8, 0xf6, 0xf1, 0x24, 0xc7, 0x90, 0x44, 0xe9, 0xf6, 0x6a, 0xa9, + 0xac, 0x64, 0x13, 0xe1, 0xae, 0x4e, 0x65, 0xfb, 0x65, 0x07, 0x86, 0x83, 0x71, 0xf8, 0x9b, 0xb3, + 0x18, 0xff, 0xb2, 0x04, 0x43, 0x81, 0xb8, 0x9a, 0x04, 0x44, 0xaa, 0xae, 0x9b, 0x57, 0x2b, 0xaa, + 0xae, 0xa9, 0x0e, 0x37, 0x0d, 0xa0, 0x59, 0x45, 0x92, 0xd3, 0x6b, 0xd7, 0xbd, 0x49, 0x43, 0xa4, + 0x3f, 0x3b, 0x20, 0x7f, 0x42, 0x82, 0x6c, 0x34, 0xb0, 0x8d, 0x88, 0x29, 0xfd, 0x6d, 0x8a, 0x29, + 0x7f, 0x5c, 0x82, 0xd1, 0x70, 0x34, 0x1b, 0x11, 0xef, 0xe4, 0xdf, 0xaa, 0x78, 0xdf, 0x4d, 0xc0, + 0x48, 0x28, 0x86, 0xed, 0x55, 0xba, 0x97, 0x60, 0x5c, 0xab, 0xe1, 0x86, 0x65, 0xba, 0xd8, 0xa8, + 0x1e, 0x54, 0x74, 0x7c, 0x05, 0xeb, 0x39, 0x99, 0x3a, 0x8d, 0xf9, 0xce, 0x51, 0xf2, 0xdc, 0xb2, + 0xcf, 0xb7, 0x42, 0xd8, 0x0a, 0x13, 0xcb, 0x8b, 0xe5, 0xd5, 0x8d, 0xf5, 0xad, 0xf2, 0xda, 0xc2, + 0xdb, 0x2b, 0xdb, 0x6b, 0xcf, 0xae, 0xad, 0x3f, 0xb7, 0xa6, 0x64, 0xb5, 0x08, 0xd9, 0x1d, 0x1c, + 0xf6, 0x1b, 0x90, 0x8d, 0x0a, 0x85, 0x8e, 0x42, 0x9c, 0x58, 0xd9, 0x3e, 0x34, 0x01, 0x63, 0x6b, + 0xeb, 0x95, 0xcd, 0xe5, 0xc5, 0x72, 0xa5, 0x7c, 0xf1, 0x62, 0x79, 0x61, 0x6b, 0x93, 0xed, 0x7b, + 0x78, 0xd4, 0x5b, 0xa1, 0x01, 0x2e, 0x7f, 0x34, 0x09, 0x13, 0x31, 0x92, 0xa0, 0x22, 0x5f, 0xb1, + 0xb0, 0x45, 0xd4, 0x99, 0x5e, 0xa4, 0x9f, 0x23, 0x31, 0xc3, 0x86, 0x6a, 0xbb, 0x7c, 0x81, 0x73, + 0x3f, 0x10, 0x2d, 0x19, 0xae, 0xb6, 0xab, 0x61, 0x9b, 0xef, 0x27, 0xb1, 0x65, 0xcc, 0x98, 0x9f, + 0xcf, 0xb6, 0x94, 0x1e, 0x04, 0x64, 0x99, 0x8e, 0xe6, 0x6a, 0x57, 0x70, 0x45, 0x33, 0xc4, 0xe6, + 0x13, 0x59, 0xd6, 0xa4, 0x94, 0xac, 0x28, 0x59, 0x36, 0x5c, 0x8f, 0xda, 0xc0, 0x75, 0x35, 0x42, + 0x4d, 0x9c, 0x79, 0x52, 0xc9, 0x8a, 0x12, 0x8f, 0xfa, 0x24, 0x0c, 0xd7, 0xcc, 0x26, 0x89, 0xf5, + 0x18, 0x1d, 0x99, 0x3b, 0x24, 0x65, 0x88, 0xe5, 0x79, 0x24, 0x3c, 0x8a, 0xf7, 0x77, 0xbd, 0x86, + 0x95, 0x21, 0x96, 0xc7, 0x48, 0xee, 0x83, 0x31, 0xb5, 0x5e, 0xb7, 0x09, 0xb8, 0x00, 0x62, 0xeb, + 0x92, 0x51, 0x2f, 0x9b, 0x12, 0xe6, 0x9f, 0x81, 0xb4, 0xd0, 0x03, 0x99, 0xaa, 0x89, 0x26, 0x2a, + 0x16, 0x5b, 0x6c, 0x27, 0x4e, 0x65, 0x94, 0xb4, 0x21, 0x0a, 0x4f, 0xc2, 0xb0, 0xe6, 0x54, 0xfc, + 0x4d, 0xfc, 0xc4, 0x6c, 0xe2, 0x54, 0x5a, 0x19, 0xd2, 0x1c, 0x6f, 0x03, 0x54, 0xfe, 0x74, 0x02, + 0x46, 0xc3, 0x87, 0x10, 0x68, 0x11, 0xd2, 0xba, 0x59, 0x55, 0xa9, 0x69, 0xb1, 0x13, 0xb0, 0x53, + 0x5d, 0xce, 0x2d, 0xe6, 0x56, 0x38, 0xbd, 0xe2, 0x71, 0xe6, 0xff, 0xbd, 0x04, 0x69, 0x91, 0x8d, + 0xa6, 0x20, 0x65, 0xa9, 0xee, 0x1e, 0x85, 0xeb, 0x2f, 0x25, 0xb2, 0x92, 0x42, 0xd3, 0x24, 0xdf, + 0xb1, 0x54, 0x83, 0x9a, 0x00, 0xcf, 0x27, 0x69, 0xd2, 0xaf, 0x3a, 0x56, 0x6b, 0x74, 0xd1, 0x63, + 0x36, 0x1a, 0xd8, 0x70, 0x1d, 0xd1, 0xaf, 0x3c, 0x7f, 0x81, 0x67, 0xa3, 0x07, 0x60, 0xdc, 0xb5, + 0x55, 0x4d, 0x0f, 0xd1, 0xa6, 0x28, 0x6d, 0x56, 0x14, 0x78, 0xc4, 0x05, 0x38, 0x26, 0x70, 0x6b, + 0xd8, 0x55, 0xab, 0x7b, 0xb8, 0xe6, 0x33, 0x0d, 0xd0, 0xcd, 0x8d, 0xa3, 0x9c, 0x60, 0x91, 0x97, + 0x0b, 0x5e, 0xf9, 0x5b, 0x12, 0x8c, 0x8b, 0x65, 0x5a, 0xcd, 0x53, 0xd6, 0x2a, 0x80, 0x6a, 0x18, + 0xa6, 0x1b, 0x54, 0x57, 0xab, 0x29, 0xb7, 0xf0, 0xcd, 0x15, 0x3d, 0x26, 0x25, 0x00, 0x90, 0x6f, + 0x00, 0xf8, 0x25, 0x6d, 0xd5, 0x36, 0x03, 0x43, 0xfc, 0x84, 0x89, 0x1e, 0x53, 0xb2, 0x85, 0x3d, + 0xb0, 0x2c, 0xb2, 0x9e, 0x43, 0x93, 0xd0, 0xbf, 0x83, 0xeb, 0x9a, 0xc1, 0xf7, 0x8d, 0x59, 0x42, + 0x6c, 0xbf, 0xa4, 0xbc, 0xed, 0x97, 0xd2, 0x2f, 0xc1, 0x44, 0xd5, 0x6c, 0x44, 0xc5, 0x2d, 0x65, + 0x23, 0x9b, 0x0b, 0xce, 0x25, 0xe9, 0x85, 0x33, 0x9c, 0xa8, 0x6e, 0xea, 0xaa, 0x51, 0x9f, 0x33, + 0xed, 0xba, 0x7f, 0xcc, 0x4a, 0x22, 0x1e, 0x27, 0x70, 0xd8, 0x6a, 0xed, 0xfc, 0x6f, 0x49, 0xfa, + 0xad, 0x44, 0x72, 0x69, 0xa3, 0xf4, 0x99, 0x44, 0x7e, 0x89, 0x31, 0x6e, 0x08, 0x65, 0x28, 0x78, + 0x57, 0xc7, 0x55, 0xd2, 0x40, 0xf8, 0xe1, 0x03, 0x30, 0x59, 0x37, 0xeb, 0x26, 0x45, 0x9a, 0x27, + 0xbf, 0xf8, 0x39, 0x6d, 0xc6, 0xcb, 0xcd, 0x77, 0x3d, 0xd4, 0x2d, 0xac, 0xc1, 0x04, 0x27, 0xae, + 0xd0, 0x83, 0x22, 0xb6, 0x8c, 0x41, 0x1d, 0xf7, 0xd0, 0x72, 0x9f, 0xff, 0x3e, 0x9d, 0xbe, 0x95, + 0x71, 0xce, 0x4a, 0xca, 0xd8, 0x4a, 0xa7, 0xa0, 0xc0, 0x91, 0x10, 0x1e, 0x1b, 0xa4, 0xd8, 0xee, + 0x82, 0xf8, 0xa7, 0x1c, 0x71, 0x22, 0x80, 0xb8, 0xc9, 0x59, 0x0b, 0x0b, 0x30, 0x72, 0x18, 0xac, + 0xaf, 0x72, 0xac, 0x61, 0x1c, 0x04, 0x59, 0x82, 0x31, 0x0a, 0x52, 0x6d, 0x3a, 0xae, 0xd9, 0xa0, + 0x1e, 0xb0, 0x33, 0xcc, 0xbf, 0xfd, 0x3e, 0x1b, 0x35, 0xa3, 0x84, 0x6d, 0xc1, 0xe3, 0x2a, 0x14, + 0x80, 0x9e, 0x8d, 0xd5, 0x70, 0x55, 0xef, 0x82, 0xf0, 0x35, 0x2e, 0x88, 0x47, 0x5f, 0xb8, 0x0c, + 0x93, 0xe4, 0x37, 0x75, 0x50, 0x41, 0x49, 0xba, 0x6f, 0xb8, 0xe5, 0xbe, 0xf5, 0x3e, 0x36, 0x30, + 0x27, 0x3c, 0x80, 0x80, 0x4c, 0x81, 0x5e, 0xac, 0x63, 0xd7, 0xc5, 0xb6, 0x53, 0x51, 0xf5, 0x38, + 0xf1, 0x02, 0x3b, 0x16, 0xb9, 0xdf, 0xfc, 0x51, 0xb8, 0x17, 0x97, 0x18, 0x67, 0x51, 0xd7, 0x0b, + 0xdb, 0x70, 0x34, 0xc6, 0x2a, 0x7a, 0xc0, 0xfc, 0x28, 0xc7, 0x9c, 0x6c, 0xb1, 0x0c, 0x02, 0xbb, + 0x01, 0x22, 0xdf, 0xeb, 0xcb, 0x1e, 0x30, 0x3f, 0xc6, 0x31, 0x11, 0xe7, 0x15, 0x5d, 0x4a, 0x10, + 0x9f, 0x81, 0xf1, 0x2b, 0xd8, 0xde, 0x31, 0x1d, 0xbe, 0x4b, 0xd4, 0x03, 0xdc, 0xc7, 0x39, 0xdc, + 0x18, 0x67, 0xa4, 0xdb, 0x46, 0x04, 0xeb, 0x1c, 0xa4, 0x77, 0xd5, 0x2a, 0xee, 0x01, 0xe2, 0x3a, + 0x87, 0x18, 0x24, 0xf4, 0x84, 0xb5, 0x08, 0xc3, 0x75, 0x93, 0xcf, 0x51, 0xdd, 0xd9, 0x3f, 0xc1, + 0xd9, 0x87, 0x04, 0x0f, 0x87, 0xb0, 0x4c, 0xab, 0xa9, 0x93, 0x09, 0xac, 0x3b, 0xc4, 0x3f, 0x11, + 0x10, 0x82, 0x87, 0x43, 0x1c, 0x42, 0xad, 0xaf, 0x0b, 0x08, 0x27, 0xa0, 0xcf, 0x0b, 0x30, 0x64, + 0x1a, 0xfa, 0x81, 0x69, 0xf4, 0x22, 0xc4, 0x27, 0x39, 0x02, 0x70, 0x16, 0x02, 0x70, 0x1e, 0x32, + 0xbd, 0x76, 0xc4, 0x3f, 0xfd, 0x91, 0x18, 0x1e, 0xa2, 0x07, 0x96, 0x60, 0x4c, 0x38, 0x28, 0xcd, + 0x34, 0x7a, 0x80, 0xf8, 0x67, 0x1c, 0x62, 0x34, 0xc0, 0xc6, 0x9b, 0xe1, 0x62, 0xc7, 0xad, 0xe3, + 0x5e, 0x40, 0x3e, 0x2d, 0x9a, 0xc1, 0x59, 0xb8, 0x2a, 0x77, 0xb0, 0x51, 0xdd, 0xeb, 0x0d, 0xe1, + 0x77, 0x84, 0x2a, 0x05, 0x0f, 0x81, 0x58, 0x80, 0x91, 0x86, 0x6a, 0x3b, 0x7b, 0xaa, 0xde, 0x53, + 0x77, 0xfc, 0x2e, 0xc7, 0x18, 0xf6, 0x98, 0xb8, 0x46, 0x9a, 0xc6, 0x61, 0x60, 0x3e, 0x23, 0x34, + 0x12, 0x60, 0xe3, 0x43, 0xcf, 0x71, 0xe9, 0x96, 0xda, 0x61, 0xd0, 0xfe, 0xb9, 0x18, 0x7a, 0x8c, + 0x77, 0x35, 0x88, 0x78, 0x1e, 0x32, 0x8e, 0xf6, 0x72, 0x4f, 0x30, 0xbf, 0x27, 0x7a, 0x9a, 0x32, + 0x10, 0xe6, 0xb7, 0xc3, 0xb1, 0xd8, 0x69, 0xa2, 0x07, 0xb0, 0xdf, 0xe7, 0x60, 0x53, 0x31, 0x53, + 0x05, 0x77, 0x09, 0x87, 0x85, 0xfc, 0x03, 0xe1, 0x12, 0x70, 0x04, 0x6b, 0x83, 0xac, 0x1a, 0x1c, + 0x75, 0xf7, 0x70, 0x5a, 0xfb, 0xac, 0xd0, 0x1a, 0xe3, 0x0d, 0x69, 0x6d, 0x0b, 0xa6, 0x38, 0xe2, + 0xe1, 0xfa, 0xf5, 0x73, 0xc2, 0xb1, 0x32, 0xee, 0xed, 0x70, 0xef, 0xbe, 0x03, 0xf2, 0x9e, 0x3a, + 0x45, 0x78, 0xea, 0x54, 0x1a, 0xaa, 0xd5, 0x03, 0xf2, 0xe7, 0x39, 0xb2, 0xf0, 0xf8, 0x5e, 0x7c, + 0xeb, 0xac, 0xaa, 0x16, 0x01, 0x7f, 0x1e, 0x72, 0x02, 0xbc, 0x69, 0xd8, 0xb8, 0x6a, 0xd6, 0x0d, + 0xed, 0x65, 0x5c, 0xeb, 0x01, 0xfa, 0x5f, 0x44, 0xba, 0x6a, 0x3b, 0xc0, 0x4e, 0x90, 0x97, 0x21, + 0xeb, 0xc5, 0x2a, 0x15, 0xad, 0x61, 0x99, 0xb6, 0xdb, 0x05, 0xf1, 0x5f, 0x8a, 0x9e, 0xf2, 0xf8, + 0x96, 0x29, 0x5b, 0xa1, 0x0c, 0xec, 0x9c, 0xb9, 0x57, 0x93, 0xfc, 0x02, 0x07, 0x1a, 0xf1, 0xb9, + 0xb8, 0xe3, 0xa8, 0x9a, 0x0d, 0x4b, 0xb5, 0x7b, 0xf1, 0x7f, 0xff, 0x4a, 0x38, 0x0e, 0xce, 0xc2, + 0x1d, 0x07, 0x89, 0xe8, 0xc8, 0x6c, 0xdf, 0x03, 0xc2, 0x17, 0x85, 0xe3, 0x10, 0x3c, 0x1c, 0x42, + 0x04, 0x0c, 0x3d, 0x40, 0xfc, 0xa1, 0x80, 0x10, 0x3c, 0x04, 0xe2, 0x6d, 0xfe, 0x44, 0x6b, 0xe3, + 0xba, 0xe6, 0xb8, 0x36, 0x0b, 0x8a, 0x3b, 0x43, 0xfd, 0xd1, 0x8f, 0xc2, 0x41, 0x98, 0x12, 0x60, + 0x25, 0x9e, 0x88, 0x6f, 0xb2, 0xd2, 0x35, 0x53, 0x77, 0xc1, 0xfe, 0x58, 0x78, 0xa2, 0x00, 0x1b, + 0x91, 0x2d, 0x10, 0x21, 0x12, 0xb5, 0x57, 0xc9, 0x4a, 0xa1, 0x07, 0xb8, 0x7f, 0x1d, 0x11, 0x6e, + 0x53, 0xf0, 0x12, 0xcc, 0x40, 0xfc, 0xd3, 0x34, 0xf6, 0xf1, 0x41, 0x4f, 0xd6, 0xf9, 0x6f, 0x22, + 0xf1, 0xcf, 0x36, 0xe3, 0x64, 0x3e, 0x64, 0x2c, 0x12, 0x4f, 0xa1, 0x6e, 0xb7, 0x8a, 0x72, 0xef, + 0xf9, 0x09, 0x6f, 0x6f, 0x38, 0x9c, 0x2a, 0xac, 0x10, 0x23, 0x0f, 0x07, 0x3d, 0xdd, 0xc1, 0xde, + 0xf7, 0x13, 0xcf, 0xce, 0x43, 0x31, 0x4f, 0xe1, 0x22, 0x8c, 0x84, 0x02, 0x9e, 0xee, 0x50, 0xff, + 0x80, 0x43, 0x0d, 0x07, 0xe3, 0x9d, 0xc2, 0x63, 0x90, 0x22, 0xc1, 0x4b, 0x77, 0xf6, 0x5f, 0xe6, + 0xec, 0x94, 0xbc, 0xf0, 0x14, 0xa4, 0x45, 0xd0, 0xd2, 0x9d, 0xf5, 0x57, 0x38, 0xab, 0xc7, 0x42, + 0xd8, 0x45, 0xc0, 0xd2, 0x9d, 0xfd, 0x1f, 0x0a, 0x76, 0xc1, 0x42, 0xd8, 0x7b, 0x57, 0xe1, 0x97, + 0x7f, 0x35, 0xc5, 0x27, 0x1d, 0xa1, 0xbb, 0xf3, 0x30, 0xc8, 0x23, 0x95, 0xee, 0xdc, 0x1f, 0xe0, + 0x95, 0x0b, 0x8e, 0xc2, 0x13, 0xd0, 0xdf, 0xa3, 0xc2, 0x7f, 0x8d, 0xb3, 0x32, 0xfa, 0xc2, 0x02, + 0x0c, 0x05, 0xa2, 0x93, 0xee, 0xec, 0xff, 0x88, 0xb3, 0x07, 0xb9, 0x88, 0xe8, 0x3c, 0x3a, 0xe9, + 0x0e, 0xf0, 0xeb, 0x42, 0x74, 0xce, 0x41, 0xd4, 0x26, 0x02, 0x93, 0xee, 0xdc, 0x1f, 0x14, 0x5a, + 0x17, 0x2c, 0x85, 0x0b, 0x90, 0xf1, 0x26, 0x9b, 0xee, 0xfc, 0x1f, 0xe2, 0xfc, 0x3e, 0x0f, 0xd1, + 0x40, 0x60, 0xb2, 0xeb, 0x0e, 0xf1, 0x61, 0xa1, 0x81, 0x00, 0x17, 0x19, 0x46, 0xd1, 0x00, 0xa6, + 0x3b, 0xd2, 0x47, 0xc4, 0x30, 0x8a, 0xc4, 0x2f, 0xa4, 0x37, 0xa9, 0xcf, 0xef, 0x0e, 0xf1, 0x8f, + 0x45, 0x6f, 0x52, 0x7a, 0x22, 0x46, 0x34, 0x22, 0xe8, 0x8e, 0xf1, 0x1b, 0x42, 0x8c, 0x48, 0x40, + 0x50, 0xd8, 0x00, 0xd4, 0x1a, 0x0d, 0x74, 0xc7, 0x7b, 0x8d, 0xe3, 0x8d, 0xb7, 0x04, 0x03, 0x85, + 0xe7, 0x60, 0x2a, 0x3e, 0x12, 0xe8, 0x8e, 0xfa, 0x9b, 0x3f, 0x89, 0xac, 0xdd, 0x82, 0x81, 0x40, + 0x61, 0xcb, 0x9f, 0x52, 0x82, 0x51, 0x40, 0x77, 0xd8, 0x8f, 0xfe, 0x24, 0xec, 0xb8, 0x83, 0x41, + 0x40, 0xa1, 0x08, 0xe0, 0x4f, 0xc0, 0xdd, 0xb1, 0x3e, 0xce, 0xb1, 0x02, 0x4c, 0x64, 0x68, 0xf0, + 0xf9, 0xb7, 0x3b, 0xff, 0x75, 0x31, 0x34, 0x38, 0x07, 0x19, 0x1a, 0x62, 0xea, 0xed, 0xce, 0xfd, + 0x09, 0x31, 0x34, 0x04, 0x0b, 0xb1, 0xec, 0xc0, 0xec, 0xd6, 0x1d, 0xe1, 0x93, 0xc2, 0xb2, 0x03, + 0x5c, 0x85, 0x35, 0x18, 0x6f, 0x99, 0x10, 0xbb, 0x43, 0xfd, 0x16, 0x87, 0xca, 0x46, 0xe7, 0xc3, + 0xe0, 0xe4, 0xc5, 0x27, 0xc3, 0xee, 0x68, 0x9f, 0x8a, 0x4c, 0x5e, 0x7c, 0x2e, 0x2c, 0x9c, 0x87, + 0xb4, 0xd1, 0xd4, 0x75, 0x32, 0x78, 0x50, 0xe7, 0x9b, 0x80, 0xb9, 0xff, 0xfa, 0x53, 0xae, 0x1d, + 0xc1, 0x50, 0x78, 0x0c, 0xfa, 0x71, 0x63, 0x07, 0xd7, 0xba, 0x71, 0xfe, 0xf0, 0xa7, 0xc2, 0x61, + 0x12, 0xea, 0xc2, 0x05, 0x00, 0xb6, 0x35, 0x42, 0x0f, 0x03, 0xbb, 0xf0, 0xfe, 0xb7, 0x9f, 0xf2, + 0xab, 0x37, 0x3e, 0x8b, 0x0f, 0xc0, 0x2e, 0xf2, 0x74, 0x06, 0xf8, 0x51, 0x18, 0x80, 0xf6, 0xc8, + 0x39, 0x18, 0x7c, 0xd1, 0x31, 0x0d, 0x57, 0xad, 0x77, 0xe3, 0xfe, 0xef, 0x9c, 0x5b, 0xd0, 0x13, + 0x85, 0x35, 0x4c, 0x1b, 0xbb, 0x6a, 0xdd, 0xe9, 0xc6, 0xfb, 0x3f, 0x38, 0xaf, 0xc7, 0x40, 0x98, + 0xab, 0xaa, 0xe3, 0xf6, 0xd2, 0xee, 0xbf, 0x12, 0xcc, 0x82, 0x81, 0x08, 0x4d, 0x7e, 0xef, 0xe3, + 0x83, 0x6e, 0xbc, 0x3f, 0x16, 0x42, 0x73, 0xfa, 0xc2, 0x53, 0x90, 0x21, 0x3f, 0xd9, 0x7d, 0xba, + 0x2e, 0xcc, 0xff, 0x93, 0x33, 0xfb, 0x1c, 0xa4, 0x66, 0xc7, 0xad, 0xb9, 0x5a, 0x77, 0x65, 0xdf, + 0xe4, 0x3d, 0x2d, 0xe8, 0x0b, 0x45, 0x18, 0x72, 0xdc, 0x5a, 0xad, 0xc9, 0xe3, 0xd3, 0x2e, 0xec, + 0x7f, 0xfd, 0x53, 0x6f, 0xcb, 0xc2, 0xe3, 0x21, 0xbd, 0x7d, 0x75, 0xdf, 0xb5, 0x4c, 0x7a, 0xe0, + 0xd1, 0x0d, 0xe1, 0x27, 0x1c, 0x21, 0xc0, 0x52, 0x58, 0x80, 0x61, 0xd2, 0x16, 0x1b, 0x5b, 0x98, + 0x9e, 0x4e, 0x75, 0x81, 0xf8, 0x1b, 0xae, 0x80, 0x10, 0x53, 0xe9, 0x9d, 0x5f, 0x7b, 0x63, 0x5a, + 0xfa, 0xe6, 0x1b, 0xd3, 0xd2, 0x77, 0xdf, 0x98, 0x96, 0x3e, 0xf8, 0xbd, 0xe9, 0xbe, 0x6f, 0x7e, + 0x6f, 0xba, 0xef, 0xdb, 0xdf, 0x9b, 0xee, 0x8b, 0xdf, 0x25, 0x86, 0x25, 0x73, 0xc9, 0x64, 0xfb, + 0xc3, 0x2f, 0xc8, 0x75, 0xcd, 0xdd, 0x6b, 0xee, 0xcc, 0x55, 0xcd, 0x06, 0xdd, 0xc6, 0xf5, 0x77, + 0x6b, 0xbd, 0x45, 0x0e, 0xbc, 0x37, 0x09, 0xc7, 0xaa, 0xa6, 0xd3, 0x30, 0x9d, 0x0a, 0xdb, 0xef, + 0x65, 0x09, 0xbe, 0xe3, 0x3b, 0x1c, 0x2c, 0xea, 0x61, 0xd3, 0xf7, 0x12, 0x8c, 0xd2, 0xa6, 0xd3, + 0xed, 0x2e, 0x6a, 0x6d, 0x5d, 0x1d, 0xc4, 0xd7, 0xff, 0xac, 0x9f, 0xb6, 0x7a, 0xc4, 0x63, 0xa4, + 0xa7, 0xf7, 0x5b, 0x30, 0xa9, 0x35, 0x2c, 0x1d, 0xd3, 0x6d, 0xfe, 0x8a, 0x57, 0xd6, 0x1d, 0xef, + 0x1b, 0x1c, 0x6f, 0xc2, 0x67, 0x5f, 0x16, 0xdc, 0x85, 0x15, 0x18, 0x57, 0xab, 0x55, 0x6c, 0x85, + 0x20, 0xbb, 0x74, 0x8b, 0x10, 0x30, 0xcb, 0x39, 0x3d, 0xb4, 0xd2, 0x85, 0x76, 0x5d, 0xf3, 0xc2, + 0x3d, 0x01, 0xcd, 0xdb, 0xb8, 0x8e, 0x8d, 0x33, 0x06, 0x76, 0xaf, 0x9a, 0xf6, 0x3e, 0x57, 0xef, + 0x19, 0x56, 0xd5, 0x00, 0xbb, 0xc1, 0x0c, 0x7f, 0x95, 0x80, 0x29, 0x7d, 0xa7, 0x31, 0xbf, 0xa3, + 0x3a, 0x78, 0xfe, 0xca, 0xc3, 0xf3, 0x55, 0x53, 0x33, 0x78, 0x0f, 0x0c, 0xe9, 0x3b, 0x8d, 0x39, + 0x92, 0x3f, 0x77, 0xe5, 0xe1, 0x7c, 0xec, 0xb6, 0xbc, 0xbc, 0x04, 0xa9, 0x05, 0x53, 0x33, 0xd0, + 0x24, 0xf4, 0xd7, 0xb0, 0x61, 0x36, 0xf8, 0x1d, 0x3b, 0x96, 0x40, 0x77, 0xc3, 0x80, 0xda, 0x30, + 0x9b, 0x86, 0xcb, 0x4e, 0x24, 0x4a, 0x43, 0x5f, 0xbb, 0x31, 0xd3, 0xf7, 0xe7, 0x37, 0x66, 0x92, + 0xcb, 0x86, 0xab, 0xf0, 0xa2, 0x42, 0xea, 0x07, 0xaf, 0xcf, 0x48, 0xf2, 0x33, 0x30, 0xb8, 0x88, + 0xab, 0xb7, 0x82, 0xb5, 0x88, 0xab, 0x11, 0xac, 0xfb, 0x21, 0xbd, 0x6c, 0xb8, 0xec, 0x16, 0xe4, + 0x5d, 0x90, 0xd4, 0x0c, 0x76, 0xb1, 0x26, 0x52, 0x3f, 0xc9, 0x27, 0xa4, 0x8b, 0xb8, 0xea, 0x91, + 0xd6, 0x70, 0x35, 0x4a, 0x4a, 0xe0, 0x49, 0x7e, 0xe9, 0xc2, 0xb7, 0xff, 0x72, 0xba, 0xef, 0x95, + 0x37, 0xa6, 0xfb, 0xda, 0x6a, 0xfe, 0xae, 0x80, 0xe6, 0x75, 0xcd, 0xc0, 0xf3, 0xfa, 0x4e, 0xe3, + 0x8c, 0x53, 0xdb, 0x67, 0xc7, 0x21, 0x9e, 0xc6, 0x7f, 0x75, 0x00, 0xf2, 0x44, 0xe3, 0x8e, 0xab, + 0xee, 0x6b, 0x46, 0x9d, 0x28, 0x5d, 0x6d, 0xba, 0x7b, 0x2f, 0x73, 0xad, 0x8f, 0x12, 0xad, 0xf3, + 0xb2, 0xb6, 0x8a, 0xcf, 0xb7, 0x1f, 0x38, 0xf9, 0x36, 0xdd, 0x29, 0x7f, 0x3a, 0x09, 0x68, 0xd3, + 0x55, 0xf7, 0x71, 0xb1, 0xe9, 0xee, 0x99, 0xb6, 0xf6, 0x32, 0x73, 0x4f, 0xcf, 0x03, 0x34, 0xd4, + 0x6b, 0x15, 0xd7, 0xdc, 0xc7, 0x86, 0x43, 0x5b, 0x3f, 0x74, 0x76, 0x7c, 0x2e, 0xd0, 0xf5, 0x73, + 0xa4, 0x57, 0x4a, 0xf7, 0x7e, 0xe6, 0x3b, 0x33, 0x72, 0xc7, 0x06, 0x52, 0x3a, 0x12, 0x22, 0x5f, + 0xdb, 0xa2, 0x58, 0x68, 0x0d, 0xd8, 0x55, 0x89, 0x8a, 0xae, 0x39, 0x2e, 0xbf, 0x6d, 0x7d, 0x66, + 0x2e, 0xdc, 0xbc, 0xb9, 0x56, 0x89, 0xe6, 0x2e, 0xab, 0xba, 0x56, 0x53, 0x5d, 0xd3, 0x76, 0x2e, + 0xf5, 0x29, 0x19, 0x0a, 0xb1, 0xa2, 0x39, 0x2e, 0x5a, 0x81, 0x4c, 0x0d, 0x1b, 0x07, 0x0c, 0x2e, + 0x79, 0x6b, 0x70, 0x69, 0x82, 0x40, 0xd1, 0x36, 0x00, 0xa9, 0x41, 0x3a, 0xf1, 0x9c, 0x48, 0x3a, + 0x35, 0x7a, 0xf6, 0x64, 0x14, 0x36, 0x84, 0x48, 0x5f, 0x3d, 0x8c, 0xab, 0xd1, 0xac, 0xfc, 0xbd, + 0x00, 0x7e, 0x5d, 0x28, 0x07, 0x83, 0x6a, 0xad, 0x66, 0x63, 0xc7, 0xa1, 0xc7, 0x75, 0x19, 0x45, + 0x24, 0x0b, 0xe3, 0xff, 0xe1, 0x0b, 0x67, 0x46, 0x42, 0x88, 0xa5, 0x61, 0x80, 0x2b, 0x1e, 0xeb, + 0xe9, 0x4f, 0x48, 0x30, 0xde, 0x52, 0x23, 0x92, 0x61, 0xba, 0xb8, 0xbd, 0x75, 0x69, 0x5d, 0x59, + 0x7e, 0xa1, 0xb8, 0xb5, 0xbc, 0xbe, 0x56, 0x61, 0x17, 0xf4, 0xd7, 0x36, 0x37, 0xca, 0x0b, 0xcb, + 0x17, 0x97, 0xcb, 0x8b, 0xd9, 0x3e, 0x34, 0x03, 0xc7, 0x63, 0x68, 0x16, 0xcb, 0x2b, 0xe5, 0xa5, + 0xe2, 0x56, 0x39, 0x2b, 0xa1, 0x93, 0x70, 0x57, 0x2c, 0x88, 0x47, 0x92, 0x68, 0x43, 0xa2, 0x94, + 0x3d, 0x92, 0x64, 0xa9, 0xd8, 0x76, 0x0c, 0xdc, 0xd7, 0xce, 0x44, 0xae, 0x79, 0xf6, 0x1e, 0x1e, + 0x0d, 0xef, 0x49, 0xc0, 0xb1, 0xa8, 0x6f, 0x57, 0x8d, 0x83, 0x36, 0xcf, 0x33, 0xdb, 0xb8, 0xa1, + 0x4b, 0x90, 0x2c, 0x1a, 0x07, 0xe8, 0x18, 0x0b, 0x7c, 0x2b, 0x4d, 0x5b, 0xe7, 0xce, 0x63, 0x90, + 0xa4, 0xb7, 0x6d, 0x9d, 0x38, 0x15, 0x71, 0x23, 0x5f, 0x3a, 0x35, 0xcc, 0xaf, 0xd9, 0x17, 0xb2, + 0xaf, 0xbd, 0x3e, 0xd3, 0xf7, 0xb9, 0xd7, 0x67, 0xfa, 0x7e, 0xfc, 0xc9, 0x99, 0xbe, 0x57, 0xfe, + 0x62, 0xb6, 0xaf, 0xb4, 0x1f, 0x6d, 0xd9, 0x97, 0xbb, 0x4e, 0x7b, 0xe9, 0xa2, 0x71, 0x40, 0x3d, + 0xc8, 0x86, 0xf4, 0x42, 0x3f, 0x6d, 0x9c, 0x38, 0xe9, 0x9c, 0x8e, 0x9e, 0x74, 0x3e, 0x87, 0x75, + 0xfd, 0x59, 0xc3, 0xbc, 0x4a, 0x3b, 0xd4, 0xd7, 0xc1, 0x47, 0x12, 0x30, 0xdd, 0x32, 0xbf, 0xf1, + 0x50, 0xa0, 0xdd, 0x3b, 0xd5, 0x02, 0xa4, 0x17, 0x45, 0x84, 0x91, 0x83, 0x41, 0x07, 0x57, 0x4d, + 0xa3, 0xc6, 0xc6, 0x6f, 0x52, 0x11, 0x49, 0xd2, 0x6c, 0x43, 0x35, 0x4c, 0x87, 0x5f, 0x8e, 0x67, + 0x89, 0xd2, 0xc7, 0xa4, 0xc3, 0x4d, 0xec, 0x23, 0xa2, 0x26, 0xd1, 0xcc, 0x87, 0xbb, 0x9e, 0xfd, + 0xee, 0x93, 0x56, 0x7a, 0x8d, 0x08, 0x9d, 0xff, 0xf6, 0xaa, 0x95, 0xdf, 0x48, 0xc0, 0x4c, 0x54, + 0x2b, 0x24, 0xbe, 0x72, 0x5c, 0xb5, 0x61, 0xb5, 0x53, 0xcb, 0x79, 0xc8, 0x6c, 0x09, 0x9a, 0x43, + 0xeb, 0xe5, 0xfa, 0x21, 0xf5, 0x32, 0xea, 0x55, 0x25, 0x14, 0x73, 0xb6, 0x47, 0xc5, 0x78, 0xed, + 0xb8, 0x25, 0xcd, 0xbc, 0x96, 0x82, 0xe3, 0xa6, 0xe3, 0xda, 0x6a, 0xd5, 0x34, 0xe6, 0xab, 0xf6, + 0x81, 0xe5, 0xd2, 0xf8, 0xca, 0xdc, 0x15, 0x5a, 0x11, 0x85, 0x73, 0xac, 0xb0, 0xcd, 0xa8, 0xd9, + 0x85, 0xfe, 0x0d, 0xc2, 0x45, 0xb4, 0xe1, 0x9a, 0xae, 0xaa, 0x73, 0x2d, 0xb1, 0x04, 0xc9, 0x65, + 0xaf, 0xad, 0x12, 0x2c, 0x57, 0x13, 0x0f, 0xad, 0x74, 0xac, 0xee, 0xb2, 0x4b, 0xeb, 0x49, 0x3a, + 0x98, 0xd2, 0x24, 0x83, 0xde, 0x4f, 0x9f, 0x84, 0x7e, 0xb5, 0xc9, 0xee, 0x5b, 0x24, 0xc9, 0x28, + 0xa3, 0x09, 0x79, 0x19, 0x06, 0xf9, 0xa9, 0x2f, 0xca, 0x42, 0x72, 0x1f, 0x1f, 0xd0, 0x7a, 0x86, + 0x15, 0xf2, 0x13, 0x3d, 0x08, 0xfd, 0x54, 0x74, 0x3e, 0x3f, 0x4c, 0xcd, 0x45, 0x64, 0x9f, 0xa3, + 0x22, 0x2a, 0x8c, 0x48, 0x7e, 0x06, 0xd2, 0x8b, 0x66, 0x43, 0x33, 0xcc, 0x30, 0x56, 0x86, 0x61, + 0x51, 0x89, 0xad, 0x26, 0x0f, 0x11, 0x14, 0x96, 0x40, 0x53, 0x30, 0xc0, 0x9e, 0x30, 0xf0, 0x1b, + 0x23, 0x3c, 0x25, 0x2f, 0xc0, 0x20, 0xc5, 0x5e, 0xb7, 0x10, 0xe2, 0x8f, 0xdf, 0xf8, 0x5b, 0x09, + 0x1a, 0x3d, 0x72, 0xf8, 0x84, 0x2f, 0x2a, 0x82, 0x54, 0x4d, 0x75, 0x55, 0xde, 0x6a, 0xfa, 0x5b, + 0x7e, 0x2b, 0xa4, 0x39, 0x88, 0x83, 0x1e, 0x82, 0xa4, 0x69, 0x39, 0xfc, 0xce, 0x47, 0x2e, 0xbe, + 0x21, 0xeb, 0x56, 0x29, 0x45, 0x42, 0x0b, 0x85, 0x90, 0x96, 0x2e, 0xb5, 0xf5, 0xa3, 0x73, 0x51, + 0x3f, 0xea, 0xf5, 0x37, 0xeb, 0xc6, 0x48, 0xf7, 0x07, 0x5d, 0xc9, 0x09, 0xaf, 0xec, 0x0a, 0xb6, + 0x1d, 0xcd, 0x34, 0xf8, 0xf4, 0xcc, 0x6c, 0x23, 0xeb, 0x89, 0xc5, 0x4b, 0xdb, 0x18, 0xc7, 0x53, + 0x90, 0x2c, 0x5a, 0x16, 0xca, 0x43, 0x9a, 0xa6, 0xab, 0x26, 0xb3, 0x8e, 0x94, 0xe2, 0xa5, 0x49, + 0x99, 0x63, 0xee, 0xba, 0x57, 0x55, 0xdb, 0x7b, 0xd5, 0x27, 0xd2, 0xf2, 0x39, 0xc8, 0x2c, 0x98, + 0x86, 0x83, 0x0d, 0xa7, 0x49, 0x47, 0xdb, 0x8e, 0x6e, 0x56, 0xf7, 0x39, 0x02, 0x4b, 0x10, 0x05, + 0xab, 0x96, 0x45, 0x39, 0x53, 0x0a, 0xf9, 0xc9, 0xc2, 0xb7, 0xd2, 0x72, 0x5b, 0xa5, 0xcc, 0xf7, + 0xaa, 0x14, 0xde, 0x34, 0x3f, 0xc8, 0x95, 0x20, 0x1f, 0x1d, 0x30, 0xfb, 0xf8, 0xc0, 0x39, 0xdc, + 0x78, 0x79, 0x1e, 0x32, 0x1b, 0xf4, 0x31, 0xfd, 0xb3, 0xf8, 0x00, 0xe5, 0x61, 0x10, 0xd7, 0xce, + 0x3e, 0xf6, 0xd8, 0xc3, 0xe7, 0x98, 0x35, 0x5f, 0xea, 0x53, 0x44, 0x06, 0x9a, 0x86, 0x8c, 0x83, + 0xab, 0xd6, 0xd9, 0xc7, 0x1e, 0xdf, 0x7f, 0x98, 0x19, 0x10, 0x09, 0x64, 0xbc, 0xac, 0x42, 0x9a, + 0xb4, 0xf3, 0x07, 0x9f, 0x9c, 0x91, 0x4a, 0xfd, 0x90, 0x74, 0x9a, 0x8d, 0x3b, 0x60, 0x07, 0xef, + 0xed, 0x87, 0x69, 0xaf, 0x8c, 0x79, 0x1e, 0x2f, 0xc0, 0x10, 0x81, 0xa6, 0xd7, 0x6a, 0x5a, 0xde, + 0x26, 0xd0, 0xec, 0xa0, 0x37, 0xf9, 0x0f, 0x24, 0x18, 0xf6, 0x22, 0x9e, 0x4d, 0xec, 0xa2, 0x73, + 0xc1, 0x30, 0x86, 0x0f, 0x84, 0x63, 0x73, 0xe1, 0x7a, 0xfc, 0x78, 0x4c, 0x09, 0x10, 0xa3, 0xc7, + 0xa8, 0xa1, 0x59, 0xa6, 0xc3, 0x5f, 0x72, 0x75, 0x64, 0xf4, 0x48, 0xd1, 0x83, 0x80, 0xa8, 0xb7, + 0xaa, 0x5c, 0x31, 0x5d, 0xcd, 0xa8, 0x57, 0x2c, 0xf3, 0x2a, 0x7f, 0x1d, 0x9b, 0x54, 0xb2, 0xb4, + 0xe4, 0x32, 0x2d, 0xd8, 0x20, 0xf9, 0xf2, 0xe7, 0x24, 0xc8, 0x78, 0x28, 0xe1, 0x08, 0x8d, 0x0c, + 0x69, 0x91, 0x44, 0xe7, 0x60, 0xd0, 0x6a, 0xee, 0x54, 0xc4, 0xf8, 0x1f, 0x3a, 0x9b, 0x6f, 0x1d, + 0xcd, 0xc2, 0x12, 0xf8, 0x78, 0x1e, 0xb0, 0x9a, 0x3b, 0xc4, 0x2e, 0x4e, 0xc2, 0x70, 0x8c, 0x28, + 0x43, 0x57, 0x7c, 0x29, 0xe8, 0xd7, 0x1a, 0xb8, 0xfc, 0x15, 0xcb, 0xd6, 0x4c, 0x5b, 0x73, 0x0f, + 0x68, 0xe0, 0x99, 0x54, 0xb2, 0xa2, 0x60, 0x83, 0xe7, 0xcb, 0x1a, 0x8c, 0x6d, 0xd2, 0xe5, 0xa4, + 0x2f, 0xf7, 0x23, 0xbe, 0x74, 0x52, 0x37, 0xe9, 0xda, 0xca, 0x95, 0x68, 0x91, 0xab, 0xb4, 0xd4, + 0xd6, 0x0a, 0xcf, 0xf4, 0x6a, 0x85, 0xe1, 0xd8, 0xee, 0x0f, 0x8f, 0x05, 0x86, 0x1d, 0x33, 0xc2, + 0xa0, 0x2b, 0xea, 0xcd, 0x00, 0xbb, 0xc5, 0x00, 0xf9, 0x4e, 0x53, 0x61, 0xbe, 0xa3, 0x33, 0xcc, + 0x77, 0x19, 0x22, 0xf2, 0x39, 0x18, 0xd9, 0x50, 0x6d, 0x77, 0x13, 0xbb, 0x97, 0xb0, 0x5a, 0xc3, + 0x76, 0x78, 0xa6, 0x1c, 0x11, 0x33, 0x25, 0x82, 0x14, 0x9d, 0x0e, 0xd9, 0x5c, 0x41, 0x7f, 0xcb, + 0xbb, 0x90, 0xa2, 0x57, 0x2e, 0xbd, 0x59, 0x94, 0x73, 0xb0, 0x59, 0x94, 0x78, 0xc4, 0x03, 0x17, + 0x3b, 0x22, 0x1c, 0xa5, 0x09, 0x74, 0x56, 0xcc, 0x85, 0xc9, 0x4e, 0x73, 0x21, 0x37, 0x38, 0x3e, + 0x23, 0xbe, 0x08, 0x83, 0x25, 0xe2, 0x4e, 0x97, 0x17, 0x3d, 0x31, 0x24, 0x5f, 0x0c, 0xf4, 0x2c, + 0x8c, 0x59, 0xaa, 0xed, 0xd2, 0x97, 0x26, 0x7b, 0xb4, 0x0d, 0xde, 0xb3, 0xd7, 0xc8, 0xe8, 0x0a, + 0x35, 0x94, 0xd7, 0x31, 0x62, 0x05, 0x33, 0xe5, 0x37, 0x52, 0x30, 0xc0, 0x15, 0x71, 0x1e, 0x06, + 0xb9, 0x42, 0xb9, 0x0d, 0x1e, 0x9f, 0x8b, 0x4e, 0x2c, 0x73, 0xde, 0x04, 0xc0, 0xd1, 0x04, 0x07, + 0xba, 0x17, 0xd2, 0xd5, 0x3d, 0x55, 0x33, 0x2a, 0x5a, 0x4d, 0xac, 0xe6, 0xdf, 0xb8, 0x31, 0x33, + 0xb8, 0x40, 0xf2, 0x96, 0x17, 0x95, 0x41, 0x5a, 0xb8, 0x5c, 0x23, 0x33, 0xf7, 0x1e, 0xd6, 0xea, + 0x7b, 0x2e, 0x1f, 0x45, 0x3c, 0x85, 0x9e, 0x84, 0x14, 0x31, 0x02, 0xfe, 0x06, 0x31, 0xdf, 0xb2, + 0x87, 0xe2, 0x85, 0x65, 0xa5, 0x34, 0xa9, 0xf8, 0x83, 0xdf, 0x99, 0x91, 0x14, 0xca, 0x81, 0x8a, + 0x30, 0xa2, 0xab, 0x8e, 0x5b, 0xa1, 0x33, 0x10, 0xa9, 0xbe, 0x9f, 0x42, 0x1c, 0x8d, 0x2a, 0x83, + 0xab, 0x94, 0x0b, 0x3e, 0x44, 0x78, 0x58, 0x56, 0x0d, 0x9d, 0x82, 0x2c, 0x85, 0xa8, 0x9a, 0x8d, + 0x86, 0xe6, 0xb2, 0x38, 0x68, 0x80, 0x6a, 0x7c, 0x94, 0xe4, 0x2f, 0xd0, 0x6c, 0x1a, 0x0d, 0x1d, + 0x87, 0x0c, 0x7d, 0xf3, 0x44, 0x49, 0xd8, 0xfd, 0xde, 0x34, 0xc9, 0xa0, 0x85, 0xf7, 0xc1, 0x98, + 0xef, 0xfd, 0x18, 0x49, 0x9a, 0xa1, 0xf8, 0xd9, 0x94, 0xf0, 0x21, 0x98, 0x34, 0xf0, 0x35, 0x7a, + 0xe3, 0x38, 0x44, 0x9d, 0xa1, 0xd4, 0x88, 0x94, 0x5d, 0x0e, 0x73, 0xdc, 0x03, 0xa3, 0x55, 0xa1, + 0x7a, 0x46, 0x0b, 0x94, 0x76, 0xc4, 0xcb, 0xa5, 0x64, 0xc7, 0x20, 0xad, 0x5a, 0x16, 0x23, 0x18, + 0xe2, 0xfe, 0xcf, 0xb2, 0x68, 0xd1, 0x69, 0x18, 0xa7, 0x6d, 0xb4, 0xb1, 0xd3, 0xd4, 0x5d, 0x0e, + 0x32, 0x4c, 0x69, 0xc6, 0x48, 0x81, 0xc2, 0xf2, 0x29, 0xed, 0xdd, 0x30, 0x82, 0xaf, 0x68, 0x35, + 0x6c, 0x54, 0x31, 0xa3, 0x1b, 0xa1, 0x74, 0xc3, 0x22, 0x93, 0x12, 0xdd, 0x0f, 0x9e, 0x67, 0xab, + 0x08, 0x9f, 0x3b, 0xca, 0xf0, 0x44, 0x7e, 0x91, 0x65, 0xcb, 0x39, 0x48, 0x2d, 0xaa, 0xae, 0x4a, + 0xc2, 0x03, 0xf7, 0x1a, 0x9b, 0x44, 0x86, 0x15, 0xf2, 0x53, 0xfe, 0x7e, 0x02, 0x52, 0x97, 0x4d, + 0x17, 0xa3, 0x87, 0x03, 0xe1, 0xda, 0x68, 0xab, 0x25, 0x6f, 0x6a, 0x75, 0x03, 0xd7, 0x56, 0x9d, + 0x7a, 0xe0, 0xf3, 0x04, 0xbe, 0x29, 0x25, 0x42, 0xa6, 0x34, 0x09, 0xfd, 0xb6, 0xd9, 0x34, 0x6a, + 0xe2, 0x62, 0x2c, 0x4d, 0xa0, 0x05, 0x48, 0x7b, 0x16, 0x92, 0xea, 0x6c, 0x21, 0x63, 0xc4, 0x42, + 0x88, 0xf5, 0xf2, 0x0c, 0x65, 0x70, 0x87, 0x1b, 0x4a, 0x09, 0x32, 0x9e, 0xab, 0xe2, 0x76, 0xd6, + 0x9b, 0xa9, 0xfa, 0x6c, 0x64, 0xaa, 0xf0, 0xfa, 0xdd, 0x53, 0x1c, 0xb3, 0xb6, 0xac, 0x57, 0xc0, + 0x35, 0x17, 0x32, 0x29, 0xfe, 0xa1, 0x84, 0x41, 0xda, 0x2a, 0xdf, 0xa4, 0xd8, 0xc7, 0x12, 0x4e, + 0x40, 0xc6, 0xd1, 0xea, 0x86, 0xea, 0x36, 0x6d, 0xcc, 0xad, 0xce, 0xcf, 0x90, 0xbf, 0x24, 0xc1, + 0x00, 0xb3, 0xe2, 0x80, 0xd6, 0xa4, 0x78, 0xad, 0x25, 0xda, 0x69, 0x2d, 0x79, 0xab, 0x5a, 0xbb, + 0x00, 0xe0, 0x89, 0xe2, 0xf0, 0xd7, 0xeb, 0x2d, 0x91, 0x00, 0x13, 0x6f, 0x53, 0xab, 0xf3, 0x01, + 0x1a, 0x60, 0x91, 0xff, 0xb3, 0x44, 0x42, 0x4f, 0x5e, 0x8e, 0x2e, 0xc0, 0x88, 0x90, 0xa9, 0xb2, + 0xab, 0xab, 0x75, 0x6e, 0x33, 0xc7, 0xdb, 0x08, 0x76, 0x51, 0x57, 0xeb, 0xca, 0x10, 0x97, 0x85, + 0x24, 0xe2, 0x7b, 0x20, 0xd1, 0xa6, 0x07, 0x42, 0x5d, 0x9e, 0xbc, 0xb5, 0x2e, 0x0f, 0x75, 0x4e, + 0x2a, 0xda, 0x39, 0x9f, 0x4d, 0xd0, 0x05, 0x87, 0x65, 0x3a, 0xaa, 0x7e, 0xe7, 0xc7, 0xc1, 0x71, + 0xc8, 0x58, 0xa6, 0x5e, 0x61, 0x25, 0xec, 0x9a, 0x78, 0xda, 0x32, 0x75, 0xa5, 0xa5, 0xbb, 0xfb, + 0x6f, 0xcb, 0x20, 0x19, 0xb8, 0x0d, 0x1a, 0x1b, 0x8c, 0x6a, 0xcc, 0x80, 0x61, 0xa6, 0x08, 0x3e, + 0x73, 0xcd, 0x11, 0x0d, 0xd0, 0x89, 0x50, 0x8a, 0xce, 0xb2, 0x4c, 0x68, 0x46, 0xa7, 0x70, 0x2a, + 0x42, 0xcf, 0x5c, 0x7d, 0xeb, 0x0a, 0x35, 0x68, 0x8c, 0x0a, 0xa7, 0x92, 0x3f, 0x2c, 0x01, 0xac, + 0x10, 0x9d, 0xd2, 0xb6, 0x92, 0x19, 0xc7, 0xa1, 0xd5, 0x57, 0x42, 0xb5, 0x9e, 0x88, 0xef, 0x2c, + 0x5e, 0xf7, 0xb0, 0x13, 0x94, 0xb8, 0x08, 0x23, 0xbe, 0x09, 0x3a, 0x58, 0x08, 0x72, 0xa2, 0x6d, + 0x7c, 0xbc, 0x89, 0x5d, 0x65, 0xf8, 0x4a, 0x20, 0x25, 0xff, 0x89, 0x04, 0x19, 0x2a, 0xcf, 0x2a, + 0x76, 0xd5, 0x50, 0xcf, 0x49, 0xb7, 0xda, 0x73, 0x77, 0x01, 0x30, 0x10, 0x47, 0x7b, 0x19, 0x73, + 0x6b, 0xca, 0xd0, 0x9c, 0x4d, 0xed, 0x65, 0x8c, 0x1e, 0xf5, 0xd4, 0x9c, 0xec, 0xa4, 0x66, 0x11, + 0x3d, 0x73, 0x65, 0x1f, 0x85, 0x41, 0xfa, 0x65, 0xa7, 0x6b, 0x0e, 0x0f, 0x88, 0x07, 0x8c, 0x66, + 0x63, 0xeb, 0x9a, 0x23, 0xef, 0xc1, 0xe0, 0xd6, 0x35, 0xb6, 0x5b, 0x71, 0x1c, 0x32, 0xb6, 0x69, + 0xf2, 0x99, 0x97, 0xc5, 0x3a, 0x69, 0x92, 0x41, 0x27, 0x1a, 0xb1, 0x46, 0x4f, 0xf8, 0x6b, 0x74, + 0x7f, 0x8b, 0x21, 0xd9, 0xc3, 0x16, 0xc3, 0xe9, 0xff, 0x24, 0xc1, 0x50, 0xc0, 0x1b, 0xa0, 0x87, + 0xe1, 0x48, 0x69, 0x65, 0x7d, 0xe1, 0xd9, 0xca, 0xf2, 0x62, 0xe5, 0xe2, 0x4a, 0x71, 0xc9, 0x7f, + 0xf8, 0x94, 0x9f, 0x7a, 0xf5, 0xfa, 0x2c, 0x0a, 0xd0, 0x6e, 0x1b, 0x74, 0x77, 0x07, 0xcd, 0xc3, + 0x64, 0x98, 0xa5, 0x58, 0xda, 0x2c, 0xaf, 0x6d, 0x65, 0xa5, 0xfc, 0x91, 0x57, 0xaf, 0xcf, 0x8e, + 0x07, 0x38, 0x8a, 0x3b, 0x0e, 0x36, 0xdc, 0x56, 0x86, 0x85, 0xf5, 0xd5, 0xd5, 0xe5, 0xad, 0x6c, + 0xa2, 0x85, 0x81, 0x3b, 0xe6, 0xfb, 0x61, 0x3c, 0xcc, 0xb0, 0xb6, 0xbc, 0x92, 0x4d, 0xe6, 0xd1, + 0xab, 0xd7, 0x67, 0x47, 0x03, 0xd4, 0x6b, 0x9a, 0x9e, 0x4f, 0xbf, 0xff, 0x53, 0xd3, 0x7d, 0xbf, + 0xf3, 0xdb, 0xd3, 0x12, 0x69, 0xd9, 0x48, 0xc8, 0x27, 0xa0, 0x07, 0xe1, 0xe8, 0xe6, 0xf2, 0xd2, + 0x5a, 0x79, 0xb1, 0xb2, 0xba, 0xb9, 0x24, 0xb6, 0x82, 0x45, 0xeb, 0xc6, 0x5e, 0xbd, 0x3e, 0x3b, + 0xc4, 0x9b, 0xd4, 0x8e, 0x7a, 0x43, 0x29, 0x5f, 0x5e, 0xdf, 0x2a, 0x67, 0x25, 0x46, 0xbd, 0x61, + 0xe3, 0x2b, 0xa6, 0xcb, 0x3e, 0xfc, 0xf6, 0x10, 0x1c, 0x8b, 0xa1, 0xf6, 0x1a, 0x36, 0xfe, 0xea, + 0xf5, 0xd9, 0x91, 0x0d, 0x1b, 0xb3, 0x51, 0x43, 0x39, 0xe6, 0x20, 0xd7, 0xca, 0xb1, 0xbe, 0xb1, + 0xbe, 0x59, 0x5c, 0xc9, 0xce, 0xe6, 0xb3, 0xaf, 0x5e, 0x9f, 0x1d, 0x16, 0xae, 0x8f, 0xee, 0xb7, + 0x7b, 0x2d, 0xbb, 0xfd, 0x2b, 0x97, 0xd7, 0x1e, 0x84, 0x13, 0x91, 0x33, 0x1a, 0x71, 0x1a, 0x70, + 0xa8, 0x53, 0x9a, 0xb6, 0x3b, 0xdb, 0xf9, 0x2e, 0x1b, 0xbe, 0xdd, 0x97, 0x3d, 0x87, 0x3f, 0x01, + 0xca, 0x77, 0x58, 0x8c, 0xc9, 0x7f, 0x1f, 0x46, 0x2f, 0x69, 0x8e, 0x6b, 0xda, 0x5a, 0x55, 0xd5, + 0xe9, 0x4b, 0xa6, 0x47, 0x7b, 0x73, 0x94, 0x91, 0x11, 0xfc, 0x04, 0x0c, 0x5c, 0x51, 0x75, 0xe6, + 0xa5, 0xd8, 0xdc, 0x1d, 0x39, 0x4a, 0xf1, 0xbc, 0x94, 0x60, 0x64, 0xe4, 0xf2, 0xeb, 0x09, 0x18, + 0xa3, 0xd6, 0xed, 0xb0, 0x0f, 0x71, 0x91, 0x05, 0xd1, 0x53, 0x90, 0xb2, 0x55, 0x97, 0xef, 0xcb, + 0x95, 0xee, 0xe7, 0x67, 0x72, 0x27, 0x3b, 0x1f, 0x43, 0x2d, 0xe2, 0xaa, 0x42, 0xd9, 0xd0, 0x73, + 0x90, 0x6e, 0xa8, 0xd7, 0x2a, 0x14, 0x82, 0xad, 0x33, 0xde, 0xda, 0x33, 0xc4, 0xcd, 0x1b, 0x33, + 0x63, 0x07, 0x6a, 0x43, 0x2f, 0xc8, 0x02, 0x42, 0x56, 0x06, 0x1b, 0xea, 0x35, 0x22, 0x18, 0xda, + 0x87, 0x31, 0x92, 0x5b, 0xdd, 0x53, 0x8d, 0x3a, 0x66, 0xf8, 0x74, 0x6f, 0xb1, 0xb4, 0x70, 0x18, + 0xfc, 0x29, 0x1f, 0x3f, 0x80, 0x24, 0x2b, 0x23, 0x0d, 0xf5, 0xda, 0x02, 0xcd, 0x20, 0x95, 0x15, + 0xd2, 0xaf, 0xbd, 0x3e, 0xd3, 0x47, 0x0f, 0x36, 0xbf, 0x2e, 0x01, 0xf8, 0x2a, 0x42, 0x5b, 0x90, + 0xad, 0x7a, 0x29, 0xca, 0x2b, 0xce, 0xef, 0x66, 0xa2, 0x4a, 0x8f, 0x28, 0x96, 0xcd, 0xa3, 0xdf, + 0xbc, 0x31, 0x23, 0x29, 0x63, 0xd5, 0x88, 0xce, 0xdf, 0x01, 0x43, 0x4d, 0xab, 0xa6, 0xba, 0xb8, + 0x42, 0xd7, 0x58, 0x89, 0xae, 0x73, 0xf2, 0x34, 0xc1, 0xba, 0x79, 0x63, 0x06, 0xb1, 0xe6, 0x04, + 0x98, 0x65, 0x3a, 0x53, 0x03, 0xcb, 0x21, 0x0c, 0xe1, 0xb6, 0x0c, 0x2d, 0x06, 0xae, 0x10, 0xe6, + 0x60, 0xb0, 0x61, 0x1a, 0xda, 0x3e, 0x37, 0xb7, 0x8c, 0x22, 0x92, 0x28, 0x0f, 0x69, 0xf6, 0x76, + 0xd3, 0x3d, 0x10, 0xdb, 0x8c, 0x22, 0x4d, 0xb8, 0xae, 0xe2, 0x1d, 0x47, 0x13, 0x1d, 0xa0, 0x88, + 0x24, 0xba, 0x08, 0x59, 0x07, 0x57, 0x9b, 0xb6, 0xe6, 0x1e, 0x54, 0xaa, 0xa6, 0xe1, 0xaa, 0x55, + 0x97, 0xbd, 0x02, 0x2c, 0x1d, 0xbf, 0x79, 0x63, 0xe6, 0x28, 0x93, 0x35, 0x4a, 0x21, 0x2b, 0x63, + 0x22, 0x6b, 0x81, 0xe5, 0x90, 0x1a, 0x6a, 0xd8, 0x55, 0x35, 0xdd, 0xc9, 0xb1, 0xb3, 0x78, 0x91, + 0x0c, 0xb4, 0xe5, 0xbd, 0x83, 0xc1, 0x6d, 0xa5, 0x8b, 0x90, 0x35, 0x2d, 0x6c, 0x87, 0x02, 0x46, + 0x29, 0x5a, 0x73, 0x94, 0x42, 0x56, 0xc6, 0x44, 0x96, 0x08, 0x26, 0x5f, 0x22, 0xdd, 0x2b, 0x96, + 0x71, 0x56, 0x73, 0xc7, 0xdf, 0x8d, 0x9a, 0x6c, 0xe9, 0x8d, 0xa2, 0x71, 0x50, 0x7a, 0xc8, 0x47, + 0x8f, 0xf2, 0xc9, 0xdf, 0xf8, 0xc2, 0x99, 0x71, 0x62, 0x12, 0xfe, 0xf6, 0xd0, 0xb3, 0xf8, 0x80, + 0xf4, 0x3d, 0xa7, 0xdb, 0xa0, 0x64, 0x24, 0x3a, 0x7c, 0x51, 0xd5, 0x74, 0xf1, 0x94, 0x5d, 0xe1, + 0x29, 0x74, 0x16, 0x06, 0x1c, 0x57, 0x75, 0x9b, 0x0e, 0x3f, 0x1f, 0xcd, 0x47, 0xed, 0xab, 0x64, + 0x1a, 0xb5, 0x4d, 0x4a, 0xa1, 0x70, 0x4a, 0x54, 0x84, 0x01, 0x7e, 0xa6, 0xdc, 0x7f, 0x98, 0xd1, + 0x4b, 0xaf, 0x06, 0x30, 0x46, 0x64, 0x42, 0xb6, 0x86, 0x75, 0x5c, 0x67, 0x81, 0xcf, 0x9e, 0x4a, + 0x56, 0x04, 0xf4, 0xd3, 0x72, 0xa5, 0xc5, 0xc3, 0x8c, 0x33, 0xae, 0x94, 0x28, 0x94, 0xac, 0x8c, + 0x79, 0x59, 0x9b, 0x34, 0x07, 0x85, 0xaf, 0xb5, 0xf2, 0x4f, 0x2f, 0x1e, 0x8f, 0x36, 0x36, 0x60, + 0xb6, 0x62, 0x83, 0x20, 0x78, 0x19, 0xf6, 0x22, 0x64, 0x9b, 0xc6, 0x8e, 0x69, 0xd0, 0x57, 0xa5, + 0x3c, 0xd8, 0x26, 0x8b, 0xac, 0x64, 0xb0, 0xff, 0xa3, 0x14, 0xb2, 0x32, 0xe6, 0x65, 0x5d, 0x62, + 0x21, 0x79, 0x0d, 0x46, 0x7d, 0x2a, 0x3a, 0x16, 0x33, 0x5d, 0xc7, 0xe2, 0x49, 0x3e, 0x16, 0x8f, + 0x44, 0x6b, 0xf1, 0x87, 0xe3, 0x88, 0x97, 0x49, 0xd8, 0xd0, 0x2f, 0x00, 0xf8, 0x1e, 0x80, 0x6e, + 0x14, 0x0c, 0xb5, 0x76, 0xaf, 0xef, 0x3e, 0xc4, 0x82, 0xcb, 0xe7, 0x41, 0x57, 0x61, 0xa2, 0xa1, + 0x19, 0x15, 0x07, 0xeb, 0xbb, 0x15, 0xae, 0x50, 0x02, 0x45, 0x3f, 0x06, 0x54, 0x5a, 0xea, 0xb9, + 0xd7, 0x6f, 0xde, 0x98, 0xc9, 0x73, 0x87, 0xd8, 0x8a, 0x26, 0x2b, 0xe3, 0x0d, 0xcd, 0xd8, 0xc4, + 0xfa, 0xee, 0xa2, 0x97, 0x57, 0x18, 0x7e, 0xff, 0xeb, 0x33, 0x7d, 0x7c, 0x10, 0xf6, 0xc9, 0x8f, + 0xd3, 0xbd, 0x68, 0x3e, 0x78, 0xb0, 0x43, 0x56, 0x05, 0xaa, 0x48, 0xf0, 0x13, 0x78, 0x3f, 0x83, + 0x0d, 0xde, 0x57, 0xfe, 0x62, 0x56, 0x92, 0x7f, 0x4f, 0x82, 0x81, 0xc5, 0xcb, 0x1b, 0xaa, 0x66, + 0xa3, 0x65, 0x18, 0xf7, 0x8d, 0x24, 0x3c, 0x74, 0x4f, 0xdc, 0xbc, 0x31, 0x93, 0x8b, 0xda, 0x91, + 0x37, 0x76, 0x7d, 0x33, 0x15, 0x83, 0x77, 0xb9, 0xdd, 0xb2, 0x31, 0x04, 0xd5, 0x42, 0x22, 0xb7, + 0x2e, 0x2a, 0x23, 0xcd, 0x7c, 0x0a, 0x06, 0x99, 0xb4, 0x6c, 0xbb, 0x90, 0xfc, 0xe0, 0x1b, 0xed, + 0x53, 0x2d, 0x76, 0x4a, 0xe9, 0xbc, 0xed, 0x42, 0x42, 0x2a, 0x7f, 0x28, 0x01, 0xb0, 0x78, 0xf9, + 0xf2, 0x96, 0xad, 0x59, 0x3a, 0x76, 0x6f, 0x67, 0x8b, 0xb7, 0xe0, 0x48, 0x60, 0x95, 0x62, 0x57, + 0x23, 0xad, 0x9e, 0xbd, 0x79, 0x63, 0xe6, 0x44, 0xb4, 0xd5, 0x01, 0x32, 0x59, 0x99, 0xf0, 0x57, + 0x2c, 0x76, 0x35, 0x16, 0xb5, 0xe6, 0xb8, 0x1e, 0x6a, 0xb2, 0x3d, 0x6a, 0x80, 0x2c, 0x88, 0xba, + 0xe8, 0xb8, 0xf1, 0x2a, 0x7d, 0x16, 0x86, 0x7c, 0x95, 0x38, 0xe8, 0xad, 0x90, 0x76, 0xf9, 0x6f, + 0xae, 0xd9, 0x7c, 0xab, 0x66, 0x05, 0x39, 0xd7, 0xae, 0xc7, 0x21, 0xff, 0xb5, 0x04, 0xe0, 0xdb, + 0xe8, 0xcf, 0xa7, 0x49, 0x11, 0xdf, 0xcc, 0xdd, 0x69, 0xf2, 0xb0, 0x91, 0x15, 0x67, 0x8c, 0xa8, + 0xf0, 0x7d, 0x09, 0x98, 0xd8, 0x16, 0x7e, 0xe5, 0xe7, 0xbe, 0xf9, 0x97, 0x60, 0x10, 0x1b, 0xae, + 0xad, 0xd1, 0xf6, 0xb3, 0xef, 0x19, 0x44, 0x3a, 0x38, 0xa6, 0x2d, 0xf4, 0x63, 0x47, 0x62, 0x27, + 0x9b, 0xb3, 0x47, 0xb4, 0xf0, 0xcb, 0x49, 0xc8, 0xb5, 0xe3, 0x44, 0x0b, 0x30, 0x56, 0xb5, 0x31, + 0xbb, 0x6a, 0x14, 0xdc, 0x54, 0x2b, 0xe5, 0xfd, 0x50, 0x30, 0x42, 0x20, 0x2b, 0xa3, 0x22, 0x87, + 0xcf, 0x09, 0x75, 0x20, 0xf1, 0x1a, 0xb1, 0x34, 0x7a, 0x63, 0xa9, 0xb7, 0x00, 0x4d, 0xe6, 0x93, + 0x82, 0xa8, 0x24, 0x0c, 0xc0, 0x66, 0x85, 0x51, 0x3f, 0x97, 0x4e, 0x0b, 0x3a, 0x8c, 0x69, 0x86, + 0xe6, 0x6a, 0xaa, 0x5e, 0xd9, 0x51, 0x75, 0xd5, 0xa8, 0x1e, 0x32, 0xc2, 0x65, 0x0e, 0x9d, 0xd7, + 0x18, 0x41, 0x92, 0x95, 0x51, 0x9e, 0x53, 0x62, 0x19, 0x68, 0x01, 0x06, 0x45, 0x2d, 0xa9, 0xc3, + 0x06, 0x0b, 0x82, 0x33, 0x10, 0x8f, 0xbd, 0x2f, 0x09, 0xe3, 0x0a, 0xae, 0xfd, 0xff, 0x0e, 0xe8, + 0xb9, 0x03, 0x2e, 0x01, 0xb0, 0x71, 0x4d, 0x9c, 0xe7, 0xe1, 0xfa, 0x80, 0x38, 0x85, 0x0c, 0x63, + 0x5e, 0x74, 0xdc, 0x40, 0x2f, 0xfc, 0x59, 0x02, 0x86, 0x83, 0xbd, 0xf0, 0x77, 0x74, 0xb2, 0x41, + 0x45, 0xdf, 0xdb, 0xb0, 0xed, 0xec, 0x96, 0xdb, 0x85, 0x2d, 0xb6, 0xda, 0xd9, 0xcd, 0xfc, 0xaf, + 0x04, 0x0c, 0x6c, 0xa8, 0xb6, 0xda, 0x70, 0x50, 0xb5, 0x25, 0x46, 0x94, 0xf8, 0xd9, 0x79, 0xcb, + 0xc7, 0xbe, 0xf9, 0xf6, 0x42, 0x97, 0x10, 0xf1, 0xb5, 0xd8, 0x10, 0x71, 0x94, 0xac, 0x51, 0x03, + 0x27, 0xfb, 0x44, 0xcb, 0x23, 0xa5, 0x63, 0x3e, 0x4a, 0xb8, 0x9c, 0x2d, 0x61, 0x03, 0x77, 0x21, + 0x9f, 0x80, 0x21, 0x42, 0xe1, 0x3b, 0x5d, 0xc2, 0x3e, 0xe5, 0xaf, 0x19, 0x03, 0x85, 0xb2, 0x02, + 0x0d, 0xf5, 0x5a, 0x99, 0x25, 0xd0, 0x0a, 0xa0, 0x3d, 0x6f, 0x57, 0xa2, 0xe2, 0xab, 0x91, 0xf0, + 0xdf, 0x75, 0xf3, 0xc6, 0xcc, 0x31, 0xc6, 0xdf, 0x4a, 0x23, 0x2b, 0xe3, 0x7e, 0xa6, 0x40, 0x7b, + 0x14, 0x80, 0xb4, 0xab, 0xc2, 0xae, 0x17, 0xb3, 0x65, 0xc9, 0x91, 0x9b, 0x37, 0x66, 0xc6, 0x19, + 0x8a, 0x5f, 0x26, 0x2b, 0x19, 0x92, 0x58, 0x24, 0xbf, 0x03, 0x16, 0xfd, 0x11, 0x09, 0x90, 0xef, + 0xd6, 0x15, 0xec, 0x58, 0x64, 0xfd, 0x44, 0x42, 0xe8, 0x40, 0xdc, 0x2b, 0xc5, 0x87, 0xd0, 0x3e, + 0x9f, 0x08, 0xa1, 0x03, 0x23, 0xe3, 0x61, 0xdf, 0xff, 0x25, 0xda, 0x5d, 0xc0, 0xe5, 0x26, 0x11, + 0xf5, 0x76, 0x7d, 0xf2, 0x9f, 0x48, 0x70, 0xac, 0xc5, 0x82, 0x3c, 0xe1, 0x2e, 0x03, 0xb2, 0x03, + 0x85, 0xfc, 0x1b, 0x7e, 0x12, 0xff, 0x24, 0x6e, 0x8f, 0x86, 0x38, 0x6e, 0xc7, 0x78, 0xd3, 0xdb, + 0xe0, 0xb2, 0xd9, 0x7d, 0xed, 0xcf, 0x4a, 0x30, 0x19, 0xac, 0xd9, 0x93, 0xfd, 0x22, 0x0c, 0x07, + 0x2b, 0xf6, 0xb6, 0xce, 0x3b, 0x48, 0xcd, 0x05, 0x0e, 0xf1, 0xa1, 0x65, 0x7f, 0x04, 0x8a, 0x0f, + 0x32, 0x77, 0x6b, 0xb8, 0x90, 0x21, 0x3a, 0x12, 0x53, 0x54, 0xe5, 0x7f, 0x23, 0x41, 0x6a, 0xc3, + 0x34, 0x75, 0xf4, 0x22, 0x8c, 0x1b, 0xa6, 0x5b, 0x21, 0xc6, 0x82, 0x6b, 0xc1, 0x3b, 0xd4, 0x99, + 0xd2, 0xd3, 0x3d, 0xeb, 0xe3, 0x87, 0x37, 0x66, 0x5a, 0x51, 0x94, 0x31, 0xc3, 0x74, 0x4b, 0x34, + 0x87, 0x5f, 0xa7, 0xbe, 0x0a, 0x23, 0xe1, 0x7a, 0x98, 0xaf, 0x53, 0x0e, 0x53, 0x4f, 0x18, 0xe1, + 0xe6, 0x8d, 0x99, 0x49, 0xdf, 0xf4, 0xbd, 0x6c, 0x59, 0x19, 0xde, 0x09, 0x54, 0xcc, 0xae, 0x2b, + 0xfd, 0xf8, 0xf5, 0x19, 0xe9, 0xf4, 0x17, 0x25, 0x00, 0x7f, 0xa9, 0x8f, 0x1e, 0x84, 0xa3, 0xa5, + 0xf5, 0xb5, 0xc5, 0xca, 0xe6, 0x56, 0x71, 0x6b, 0x7b, 0x33, 0x7c, 0x15, 0x59, 0x6c, 0x1f, 0x3b, + 0x16, 0xae, 0x6a, 0xbb, 0x1a, 0xae, 0xa1, 0x7b, 0x61, 0x32, 0x4c, 0x4d, 0x52, 0xe5, 0xc5, 0xac, + 0x94, 0x1f, 0x7e, 0xf5, 0xfa, 0x6c, 0x9a, 0x05, 0x4e, 0xb8, 0x86, 0x4e, 0xc1, 0x91, 0x56, 0xba, + 0xe5, 0xb5, 0xa5, 0x6c, 0x22, 0x3f, 0xf2, 0xea, 0xf5, 0xd9, 0x8c, 0x17, 0x61, 0x21, 0x19, 0x50, + 0x90, 0x92, 0xe3, 0x25, 0xf3, 0xf0, 0xea, 0xf5, 0xd9, 0x01, 0xa6, 0xbb, 0x7c, 0xea, 0xfd, 0x9f, + 0x9a, 0xee, 0xbb, 0x9d, 0x17, 0x96, 0xaf, 0x0f, 0xb6, 0x6c, 0x0d, 0xd7, 0xb1, 0x81, 0x1d, 0xcd, + 0x39, 0xd4, 0xd6, 0x70, 0xc7, 0xed, 0x65, 0xf9, 0x7a, 0x3f, 0x0c, 0x2f, 0x31, 0x54, 0xa2, 0x6b, + 0x7a, 0x9c, 0x62, 0x51, 0x97, 0xef, 0x6d, 0xc6, 0x46, 0x2c, 0x98, 0x4d, 0x08, 0xde, 0x65, 0x24, + 0x36, 0x3d, 0x18, 0xfc, 0xae, 0x02, 0xbb, 0x22, 0xe5, 0x5f, 0xfc, 0x19, 0xee, 0x75, 0x03, 0x85, + 0x45, 0x11, 0x7c, 0xcf, 0x22, 0x0a, 0x25, 0xb3, 0x1b, 0x0f, 0x5b, 0x24, 0x87, 0xdd, 0x6c, 0xfa, + 0x45, 0x38, 0x42, 0x89, 0xfc, 0xe9, 0x91, 0x12, 0x8a, 0x30, 0x5b, 0x8e, 0x0a, 0xbd, 0xa2, 0x3a, + 0xfe, 0xe5, 0x05, 0x76, 0x09, 0xe9, 0x2d, 0x7c, 0x7a, 0x3a, 0x11, 0xa8, 0x33, 0x0a, 0x27, 0x2b, + 0x13, 0x7a, 0x0b, 0xa7, 0x83, 0x2e, 0x84, 0x6e, 0x9f, 0xa5, 0x7a, 0xdb, 0x7e, 0x0e, 0xde, 0x41, + 0x2b, 0xc1, 0x90, 0xef, 0x06, 0x1c, 0xfe, 0x1f, 0x41, 0xba, 0x7b, 0xf2, 0x20, 0x13, 0xfa, 0x25, + 0x38, 0xe2, 0x4f, 0xa9, 0x41, 0x34, 0xf6, 0x0f, 0x53, 0xee, 0xee, 0x61, 0xa5, 0x11, 0xd5, 0x41, + 0x2c, 0x9e, 0xac, 0x4c, 0x36, 0x5b, 0x59, 0xc9, 0xda, 0x66, 0x24, 0xe8, 0xfb, 0x1c, 0xfe, 0xdf, + 0x6e, 0x7a, 0x71, 0x9a, 0x61, 0x46, 0xf6, 0x4f, 0x1b, 0x2c, 0xd3, 0x76, 0x71, 0x8d, 0xee, 0x5f, + 0xa5, 0x15, 0x2f, 0x2d, 0xaf, 0x01, 0x6a, 0xed, 0xbb, 0xe8, 0x85, 0x3a, 0xff, 0xc9, 0x03, 0x9a, + 0x84, 0xfe, 0xe0, 0xb5, 0x33, 0x96, 0x28, 0xa4, 0xdf, 0xcf, 0xe7, 0xb0, 0xdb, 0x39, 0x3e, 0xbf, + 0x91, 0x00, 0xd9, 0x3b, 0xff, 0x78, 0xa9, 0x89, 0xed, 0x03, 0x32, 0xbc, 0x2c, 0xb5, 0xae, 0x19, + 0xc1, 0x0b, 0xf5, 0xe3, 0xde, 0x04, 0x4b, 0x69, 0xe6, 0xae, 0x3c, 0x2c, 0xbf, 0x5f, 0x82, 0xa1, + 0x0d, 0xb5, 0x8e, 0x15, 0xfc, 0x52, 0x13, 0x3b, 0x6e, 0xcc, 0x65, 0xe5, 0x29, 0x18, 0x30, 0x77, + 0x77, 0xc5, 0x11, 0x6c, 0x4a, 0xe1, 0x29, 0xd2, 0x3c, 0x5d, 0x6b, 0x68, 0xec, 0x9e, 0x52, 0x4a, + 0x61, 0x09, 0x34, 0x03, 0x43, 0x55, 0xb3, 0x69, 0xf0, 0x31, 0x93, 0x4b, 0x89, 0xef, 0x6a, 0x34, + 0x0d, 0x36, 0x66, 0x88, 0xbe, 0x6c, 0x7c, 0x05, 0xdb, 0x0e, 0xfb, 0x92, 0x60, 0x5a, 0x11, 0x49, + 0xf9, 0x02, 0x0c, 0x33, 0x49, 0xf8, 0x4c, 0x78, 0x0c, 0xd2, 0xf4, 0x12, 0x90, 0x2f, 0xcf, 0x20, + 0x49, 0x3f, 0xcb, 0x2e, 0x3d, 0x33, 0x7c, 0x26, 0x12, 0x4b, 0x94, 0x9e, 0x6a, 0xab, 0xd0, 0xbb, + 0x3b, 0x8e, 0x78, 0xa6, 0x31, 0x4f, 0x99, 0x7f, 0xda, 0x0f, 0x47, 0xf8, 0x41, 0x94, 0x6a, 0x69, + 0xf3, 0x7b, 0xae, 0x2b, 0x6e, 0xde, 0x03, 0x0f, 0x30, 0x55, 0x4b, 0x93, 0x0f, 0x20, 0x75, 0xc9, + 0x75, 0x2d, 0x74, 0x1a, 0xfa, 0xed, 0xa6, 0x8e, 0xc5, 0xb6, 0x89, 0xb7, 0x4d, 0xad, 0x5a, 0xda, + 0x1c, 0x21, 0x50, 0x9a, 0x3a, 0x56, 0x18, 0x09, 0x2a, 0xc3, 0xcc, 0x6e, 0x53, 0xd7, 0x0f, 0x2a, + 0x35, 0x4c, 0xff, 0x2b, 0x92, 0xf7, 0x7f, 0x05, 0xf0, 0x35, 0x4b, 0x15, 0x5f, 0x27, 0x24, 0x3a, + 0x39, 0x41, 0xc9, 0x16, 0x29, 0x95, 0xf8, 0x9f, 0x02, 0x65, 0x41, 0x23, 0xff, 0x79, 0x02, 0xd2, + 0x02, 0x9a, 0x5e, 0x48, 0xc6, 0x3a, 0xae, 0xba, 0xa6, 0x38, 0x44, 0xf0, 0xd2, 0x08, 0x41, 0xb2, + 0xce, 0xfb, 0x2d, 0x73, 0xa9, 0x4f, 0x21, 0x09, 0x92, 0xe7, 0x5d, 0x0b, 0x27, 0x79, 0x56, 0x93, + 0x74, 0x65, 0xca, 0x32, 0xc5, 0x1a, 0xe8, 0x52, 0x9f, 0x42, 0x53, 0x28, 0x07, 0x03, 0x64, 0x68, + 0xb8, 0xac, 0xa3, 0x48, 0x3e, 0x4f, 0xa3, 0x29, 0xe8, 0xb7, 0x54, 0xb7, 0xca, 0xee, 0x80, 0x91, + 0x02, 0x96, 0x44, 0x4f, 0xc0, 0x00, 0x7b, 0x7c, 0x1b, 0xfd, 0x97, 0x23, 0x44, 0x19, 0xec, 0x2b, + 0x67, 0x44, 0xee, 0x0d, 0xd5, 0x75, 0xb1, 0x6d, 0x10, 0x40, 0x46, 0x8e, 0x10, 0xa4, 0x76, 0xcc, + 0xda, 0x01, 0xff, 0x37, 0x28, 0xf4, 0x37, 0xff, 0xbf, 0x0b, 0xd4, 0x14, 0x2a, 0xb4, 0x90, 0xfd, + 0xf7, 0xa7, 0x61, 0x91, 0x59, 0x22, 0x44, 0x65, 0x98, 0x50, 0x6b, 0x35, 0x8d, 0xfd, 0x47, 0x92, + 0xca, 0x8e, 0x46, 0x5d, 0x83, 0x43, 0xff, 0xb7, 0x57, 0xbb, 0xbe, 0x40, 0x3e, 0x43, 0x89, 0xd3, + 0x97, 0x32, 0x30, 0x68, 0x31, 0xa1, 0xe4, 0xf3, 0x30, 0xde, 0x22, 0x29, 0x91, 0x6f, 0x5f, 0x33, + 0x6a, 0xe2, 0xae, 0x3c, 0xf9, 0x4d, 0xf2, 0xe8, 0x77, 0x09, 0xd9, 0xf1, 0x0c, 0xfd, 0x5d, 0x7a, + 0x6f, 0xfb, 0xc7, 0x14, 0xa3, 0x81, 0xc7, 0x14, 0xaa, 0xa5, 0x95, 0x32, 0x14, 0x9f, 0x3f, 0xa1, + 0x28, 0xb6, 0x3e, 0xa1, 0xa8, 0x63, 0x43, 0xcc, 0x9f, 0xa4, 0x48, 0xb5, 0x34, 0x87, 0x9a, 0xa3, + 0xff, 0x9d, 0x44, 0xe7, 0x7c, 0xe0, 0x37, 0x7d, 0x51, 0x91, 0x5a, 0x2a, 0x6e, 0x2c, 0x7b, 0x76, + 0xfc, 0x95, 0x04, 0x9c, 0x08, 0xd8, 0x71, 0x80, 0xb8, 0xd5, 0x9c, 0xf3, 0xf1, 0x16, 0xdf, 0xc3, + 0x13, 0xd4, 0x67, 0x21, 0x45, 0xe8, 0x51, 0x97, 0xff, 0x8a, 0x90, 0xfb, 0xdc, 0x37, 0xbe, 0x24, + 0x87, 0x0f, 0x72, 0x42, 0xbd, 0x42, 0x41, 0x4a, 0xbf, 0xd2, 0xbb, 0xfe, 0xb2, 0xfe, 0x27, 0x22, + 0x9d, 0xdb, 0xa7, 0xc6, 0xa8, 0x0e, 0x7f, 0xed, 0xe1, 0x96, 0x77, 0x8b, 0xcc, 0x75, 0xc6, 0x87, + 0x3d, 0x3d, 0x38, 0xe1, 0x76, 0xa1, 0x51, 0xa7, 0x9e, 0xea, 0x12, 0x38, 0x59, 0x30, 0xf5, 0x36, + 0x52, 0x9d, 0xbf, 0xf8, 0x14, 0xde, 0x7c, 0xca, 0x3b, 0xc3, 0x92, 0xf8, 0xbf, 0x4e, 0x63, 0x41, + 0xec, 0xd3, 0x00, 0xbe, 0x5c, 0x7c, 0xf9, 0x35, 0x3d, 0xd7, 0x32, 0x3b, 0xcc, 0x05, 0x66, 0x06, + 0x25, 0xc0, 0x21, 0x7f, 0x4c, 0x82, 0xa3, 0x2d, 0x55, 0x72, 0xb7, 0x7d, 0x21, 0xf6, 0x3e, 0xfc, + 0x21, 0x22, 0x92, 0x0b, 0x31, 0xc2, 0xcd, 0xb4, 0x15, 0x8e, 0xd5, 0x1a, 0x92, 0xee, 0x69, 0x38, + 0x12, 0x16, 0x4e, 0xa8, 0xe3, 0x1e, 0x18, 0x0d, 0xef, 0x95, 0x72, 0xb5, 0x8c, 0x84, 0x76, 0x4b, + 0xe5, 0xe7, 0xa2, 0xfa, 0xf4, 0xda, 0xf6, 0x14, 0x64, 0x3c, 0x52, 0x6f, 0xd7, 0xa1, 0x4b, 0xd3, + 0x7c, 0x0e, 0xf9, 0x03, 0x12, 0xcc, 0x86, 0x91, 0x03, 0x51, 0xcc, 0xe1, 0x84, 0xfc, 0x99, 0xbb, + 0xf0, 0xdb, 0x12, 0x9c, 0xec, 0x20, 0x0b, 0x6f, 0xb0, 0x0d, 0x93, 0x81, 0x75, 0xb4, 0x70, 0xbd, + 0xa2, 0x5b, 0xe5, 0xf6, 0x61, 0xa2, 0xb7, 0x96, 0x3c, 0x4e, 0x94, 0xf0, 0x99, 0xef, 0xcc, 0x4c, + 0xb4, 0x96, 0x39, 0xca, 0x44, 0xeb, 0x02, 0xf8, 0x36, 0xf4, 0xff, 0x87, 0x25, 0xb8, 0x3f, 0xdc, + 0xb4, 0x98, 0x80, 0xf3, 0xcd, 0xd6, 0xf7, 0xd7, 0x25, 0x38, 0xdd, 0x8b, 0x50, 0x5c, 0xf1, 0x2f, + 0xc0, 0x84, 0x1f, 0x02, 0x47, 0xf5, 0xde, 0x53, 0x40, 0xcd, 0xac, 0x0f, 0x79, 0x28, 0xb7, 0x51, + 0xc1, 0xc2, 0xe1, 0x04, 0xbb, 0xd4, 0x53, 0x66, 0x78, 0x2f, 0x53, 0x28, 0x33, 0xb4, 0x9b, 0x19, + 0xa3, 0xf3, 0x44, 0x8c, 0xce, 0xfd, 0x58, 0x59, 0x36, 0xb8, 0xbf, 0x89, 0xd9, 0x89, 0xda, 0x84, + 0x89, 0x18, 0x13, 0xe5, 0xa3, 0xb3, 0x07, 0x0b, 0x55, 0x50, 0xab, 0x11, 0xca, 0x07, 0x30, 0x43, + 0xeb, 0x8b, 0x51, 0xec, 0x9d, 0x6e, 0x2a, 0xe6, 0x3e, 0x22, 0xb6, 0x6a, 0xde, 0xe6, 0x22, 0x0c, + 0xb0, 0x7e, 0xe5, 0xcd, 0x3c, 0x84, 0x41, 0x70, 0x46, 0xf9, 0x23, 0xc2, 0x17, 0x2d, 0x0a, 0x71, + 0xe3, 0xc7, 0x46, 0x2f, 0x6d, 0xfc, 0x19, 0xc7, 0x46, 0xa0, 0xf1, 0x5f, 0x11, 0x5e, 0x29, 0x5e, + 0x2a, 0xde, 0xfc, 0x77, 0xfc, 0xcc, 0x5e, 0x89, 0xe9, 0xe2, 0xce, 0xb8, 0x9f, 0x8f, 0x0b, 0xf7, + 0xe3, 0xb5, 0xa1, 0x8b, 0xfb, 0x79, 0x73, 0x55, 0xec, 0x39, 0xa2, 0x2e, 0xe2, 0xfd, 0xdf, 0xe0, + 0x88, 0x7e, 0x20, 0xc1, 0x31, 0xda, 0x96, 0xe0, 0xca, 0xfe, 0xb0, 0xaa, 0x7d, 0x10, 0x90, 0x63, + 0x57, 0x2b, 0xb1, 0xa3, 0x34, 0xeb, 0xd8, 0xd5, 0xcb, 0xa1, 0x79, 0xe0, 0x41, 0x40, 0xb5, 0xd0, + 0xf6, 0x0c, 0xa5, 0x66, 0x17, 0xb1, 0xb2, 0xb5, 0xc0, 0xf6, 0x40, 0x4c, 0xb7, 0xa5, 0x7e, 0x86, + 0x6e, 0xfb, 0xb2, 0x04, 0xf9, 0xb8, 0xa6, 0xf2, 0x6e, 0x52, 0x61, 0x2a, 0xb4, 0xe5, 0x1d, 0xed, + 0xa9, 0xb7, 0x74, 0xda, 0x0b, 0x89, 0x0c, 0x8b, 0x23, 0x36, 0xbe, 0x53, 0xf3, 0xf2, 0x4c, 0xd8, + 0xf2, 0x5a, 0x23, 0xd6, 0x37, 0x7d, 0x38, 0xfc, 0x76, 0x8b, 0x1f, 0xfc, 0xb9, 0x8c, 0x69, 0xaf, + 0xc1, 0x74, 0x1b, 0x29, 0xef, 0xf4, 0x7c, 0xf4, 0xf7, 0xda, 0x76, 0xda, 0xed, 0x0a, 0x8b, 0x1f, + 0xe5, 0x96, 0x1d, 0xbe, 0x8b, 0x1b, 0x58, 0xc3, 0xc4, 0xbd, 0xc7, 0x91, 0xdf, 0x06, 0xc7, 0x63, + 0xb9, 0xb8, 0x4c, 0x67, 0x21, 0xb5, 0xa7, 0x39, 0x2e, 0x17, 0x67, 0x3a, 0x2a, 0x4e, 0x84, 0x8b, + 0xd2, 0xca, 0x08, 0xb2, 0x14, 0x72, 0xc3, 0x34, 0x75, 0x5e, 0xbd, 0xbc, 0x00, 0xe3, 0x81, 0x3c, + 0x0e, 0x3e, 0x07, 0x29, 0xcb, 0xe4, 0xaf, 0xc3, 0xc9, 0x8a, 0x36, 0xba, 0x2f, 0x6d, 0x9a, 0x3a, + 0x6f, 0x26, 0xa5, 0x93, 0x27, 0x01, 0x31, 0x10, 0xba, 0x45, 0x2d, 0xa0, 0x9f, 0x85, 0x89, 0x50, + 0x2e, 0x07, 0xbf, 0xa5, 0x6d, 0xef, 0xb3, 0xaf, 0x4d, 0x40, 0x3f, 0x45, 0x43, 0xef, 0x91, 0x42, + 0xdf, 0x64, 0xb9, 0x37, 0xca, 0x1e, 0xbf, 0x56, 0xcc, 0xdf, 0xd7, 0x95, 0x8e, 0xc7, 0x46, 0xf2, + 0x7b, 0xff, 0xe3, 0xf7, 0x3f, 0x92, 0x38, 0x81, 0xf2, 0xf3, 0x91, 0x55, 0x69, 0xc0, 0xde, 0x7f, + 0x3d, 0xf4, 0xe8, 0xf8, 0x9e, 0xce, 0xd0, 0x42, 0x82, 0x7b, 0xbb, 0x91, 0x71, 0x01, 0x1e, 0xa1, + 0x02, 0x9c, 0x41, 0x0f, 0xb4, 0x17, 0x60, 0xfe, 0x5d, 0x61, 0x23, 0x7f, 0x37, 0xfa, 0x92, 0x04, + 0x93, 0x71, 0x4b, 0x1d, 0xf4, 0x50, 0xe7, 0x5a, 0x5b, 0xa7, 0xec, 0xfc, 0xc3, 0x87, 0xe0, 0xe0, + 0x22, 0x5f, 0xa0, 0x22, 0x9f, 0x43, 0x4f, 0x1c, 0x42, 0xe4, 0xf9, 0xe0, 0xc6, 0xf4, 0x5f, 0x4a, + 0x70, 0x57, 0xc7, 0x95, 0x03, 0x3a, 0xd7, 0x59, 0xaa, 0x0e, 0x31, 0x48, 0xbe, 0x70, 0x2b, 0xac, + 0xbc, 0x65, 0xcb, 0xb4, 0x65, 0x0b, 0xa8, 0x78, 0x98, 0x96, 0xc5, 0xee, 0xee, 0xa3, 0xcf, 0x86, + 0xaf, 0x91, 0xc5, 0x9b, 0x43, 0x4b, 0x20, 0xde, 0xc6, 0x70, 0x5b, 0x83, 0x3e, 0x79, 0x83, 0x8a, + 0xfa, 0x0c, 0xba, 0x74, 0x8b, 0x9d, 0x30, 0xff, 0xae, 0xb0, 0x83, 0x7d, 0x37, 0xfa, 0x8e, 0x14, + 0x7f, 0x05, 0x6c, 0x3e, 0x56, 0xa4, 0xf6, 0x8b, 0x89, 0xfc, 0x43, 0xbd, 0x33, 0xf0, 0xc6, 0x60, + 0xda, 0x98, 0x0a, 0x7a, 0xe7, 0xed, 0x6a, 0x4c, 0x6c, 0xa7, 0xa0, 0xcf, 0x4b, 0x30, 0x19, 0x17, + 0x8b, 0xb7, 0x19, 0x36, 0x1d, 0x16, 0x13, 0x6d, 0x86, 0x4d, 0xa7, 0x40, 0x5f, 0x7e, 0x94, 0x36, + 0x72, 0x0e, 0x3d, 0x18, 0x6d, 0x64, 0xc7, 0x5e, 0x21, 0x63, 0xa5, 0x63, 0x70, 0xdb, 0x66, 0xac, + 0xf4, 0x12, 0xaf, 0xb7, 0x19, 0x2b, 0x3d, 0xc5, 0xd2, 0xed, 0xc7, 0x8a, 0xd7, 0x82, 0x1e, 0xbb, + 0xc5, 0x41, 0xbf, 0x2b, 0xc1, 0x48, 0x28, 0x12, 0x44, 0xf7, 0xc7, 0x0a, 0x16, 0x17, 0x18, 0xe7, + 0x4f, 0xf7, 0x42, 0xca, 0x65, 0x2e, 0x52, 0x99, 0xcf, 0xa3, 0x73, 0x87, 0x91, 0x39, 0x7c, 0xa8, + 0xf6, 0x47, 0x12, 0x4c, 0xc4, 0x44, 0x57, 0x6d, 0x46, 0x49, 0xfb, 0xe0, 0x30, 0xff, 0x50, 0xef, + 0x0c, 0x5c, 0xfa, 0xa7, 0xa9, 0xf4, 0x4f, 0xa2, 0xc7, 0x0f, 0x23, 0x7d, 0x60, 0x1e, 0xfb, 0xaa, + 0x7f, 0xfb, 0x25, 0x80, 0x8f, 0xe6, 0x7a, 0x14, 0x44, 0x08, 0x3e, 0xdf, 0x33, 0x3d, 0x97, 0x7b, + 0x9d, 0xca, 0xbd, 0x8c, 0x96, 0x6e, 0x4d, 0xee, 0xd6, 0xe9, 0xef, 0x63, 0x52, 0xcb, 0x5b, 0xa7, + 0x78, 0x2b, 0x88, 0x0d, 0xc2, 0xf2, 0x0f, 0xf4, 0x44, 0xcb, 0x85, 0x7f, 0x88, 0x0a, 0x7f, 0x1a, + 0x9d, 0x8a, 0x0a, 0x1f, 0xb8, 0xb2, 0xa4, 0x19, 0xbb, 0xe6, 0xfc, 0xbb, 0x58, 0x28, 0xf7, 0x6e, + 0xa4, 0xf1, 0xab, 0x25, 0xb3, 0xb1, 0xd5, 0x04, 0xc2, 0xb1, 0xfc, 0xc9, 0x0e, 0x14, 0xbc, 0xfa, + 0x13, 0xb4, 0xfa, 0x29, 0x34, 0x19, 0xad, 0x9e, 0x84, 0x62, 0xe8, 0x25, 0xef, 0x1e, 0x99, 0x1c, + 0x0f, 0x15, 0x0c, 0xd1, 0xf2, 0x77, 0x77, 0xa4, 0xe1, 0x15, 0x4e, 0xd3, 0x0a, 0x73, 0x68, 0xaa, + 0xa5, 0x42, 0x16, 0xa8, 0xdd, 0xc6, 0x83, 0xde, 0x7f, 0x77, 0x04, 0x8e, 0x46, 0x2a, 0x71, 0xaf, + 0xb5, 0x39, 0x8c, 0xe8, 0xf0, 0x10, 0xaf, 0xeb, 0x43, 0xbb, 0xdb, 0xf5, 0x01, 0xc6, 0x2e, 0x27, + 0x17, 0xbf, 0x9f, 0x02, 0xb4, 0xea, 0xd4, 0x17, 0x6c, 0xcc, 0xfe, 0xaf, 0x1b, 0x1f, 0x5e, 0x91, + 0x27, 0x29, 0xd2, 0x2d, 0x3d, 0x49, 0x29, 0x87, 0x1e, 0x79, 0x24, 0x7a, 0x7b, 0x23, 0xd6, 0xf3, + 0x4b, 0x8f, 0xe4, 0x9d, 0x7e, 0xe9, 0x11, 0x7f, 0x73, 0x34, 0x75, 0xfb, 0xae, 0x91, 0xf7, 0xdf, + 0xd2, 0x35, 0xf2, 0x05, 0x18, 0xe0, 0xcf, 0xb2, 0x06, 0x3a, 0x3c, 0xcb, 0x3a, 0x12, 0xff, 0xf6, + 0x8a, 0xb3, 0xa2, 0x33, 0xe2, 0xc3, 0x84, 0x83, 0x9d, 0x2f, 0xfe, 0xf1, 0x2f, 0x16, 0xfa, 0x6b, + 0xd1, 0x13, 0x90, 0x6f, 0x35, 0x17, 0x6f, 0x1c, 0xbe, 0x27, 0x09, 0xd9, 0x55, 0xa7, 0x5e, 0xae, + 0x69, 0xee, 0x6d, 0xb6, 0xa5, 0x0b, 0xed, 0xef, 0xe1, 0xa3, 0x9b, 0x37, 0x66, 0x46, 0x99, 0x02, + 0x3b, 0xa8, 0x6d, 0x0f, 0xc6, 0x22, 0xcf, 0x16, 0xb9, 0x05, 0x5d, 0x38, 0xe4, 0xc3, 0xc9, 0x08, + 0x8a, 0x4c, 0xef, 0x50, 0x07, 0x4c, 0x18, 0x39, 0xf1, 0xf6, 0xca, 0x0c, 0x67, 0xe1, 0x0e, 0xbd, + 0x4a, 0xf2, 0x7b, 0x28, 0x0f, 0xb9, 0x68, 0x17, 0x78, 0xfd, 0x73, 0x43, 0x82, 0xa1, 0x55, 0x47, + 0x44, 0x46, 0xf8, 0xe7, 0xf4, 0xa1, 0xc4, 0xbc, 0xf7, 0xd1, 0xdd, 0x64, 0x67, 0xeb, 0x14, 0x1f, + 0xe0, 0xf5, 0x1b, 0x7f, 0x04, 0x26, 0x02, 0xed, 0xf3, 0xda, 0xfd, 0xd5, 0x04, 0xf5, 0x72, 0x25, + 0x5c, 0xd7, 0x0c, 0x2f, 0xc8, 0xc2, 0x7f, 0x57, 0xaf, 0x86, 0xfb, 0xfa, 0x4d, 0x1d, 0x56, 0xbf, + 0xfb, 0x74, 0xf8, 0x47, 0xf4, 0xe8, 0xed, 0x9b, 0xac, 0xb6, 0x3e, 0x53, 0x90, 0x0e, 0xf1, 0x71, + 0x8d, 0xc8, 0x63, 0x04, 0xf9, 0xbb, 0x12, 0x8c, 0xac, 0x3a, 0xf5, 0x6d, 0xa3, 0xf6, 0xff, 0xac, + 0xbd, 0xee, 0xc2, 0x91, 0x50, 0x0b, 0xef, 0x90, 0x2a, 0xcf, 0x7e, 0x23, 0x09, 0xc9, 0x55, 0xa7, + 0x8e, 0x54, 0x18, 0x8b, 0x4e, 0xf5, 0x2d, 0x41, 0x58, 0xab, 0x7f, 0x6f, 0x5d, 0xae, 0xb4, 0x9f, + 0x03, 0xd0, 0x3b, 0x60, 0x24, 0xec, 0xff, 0x67, 0x63, 0x98, 0x43, 0x14, 0xf9, 0x53, 0xdd, 0x28, + 0x3c, 0xf0, 0x15, 0x48, 0x7b, 0xce, 0xeb, 0x78, 0x0c, 0x97, 0x28, 0x6c, 0x0d, 0x1b, 0x63, 0xdc, + 0x02, 0xd1, 0x46, 0xd4, 0x25, 0xc4, 0x69, 0x23, 0x42, 0x13, 0xab, 0x8d, 0x76, 0x43, 0x42, 0x01, + 0x08, 0xd8, 0xef, 0x5d, 0x31, 0x9c, 0x7e, 0x71, 0xfe, 0x9e, 0x8e, 0xc5, 0xde, 0x19, 0xc1, 0xed, + 0x8b, 0x66, 0xff, 0x4f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x6d, 0x2d, 0xbb, 0xd3, 0xae, 0x92, 0x00, + 0x00, } r := bytes.NewReader(gzipped) gzipr, err := compress_gzip.NewReader(r) diff --git a/x/staking/types/validator.go b/x/staking/types/validator.go index f875e4a5af..12426eb839 100644 --- a/x/staking/types/validator.go +++ b/x/staking/types/validator.go @@ -116,8 +116,8 @@ type ValidatorsByVotingPower []Validator func (valz ValidatorsByVotingPower) Len() int { return len(valz) } -func (valz ValidatorsByVotingPower) Less(i, j int) bool { - if valz[i].ConsensusPower() == valz[j].ConsensusPower() { +func (valz ValidatorsByVotingPower) Less(i, j int, r sdk.Int) bool { + if valz[i].ConsensusPower(r) == valz[j].ConsensusPower(r) { addrI, errI := valz[i].GetConsAddr() addrJ, errJ := valz[j].GetConsAddr() // If either returns error, then return false @@ -128,7 +128,7 @@ func (valz ValidatorsByVotingPower) Less(i, j int) bool { bytesJ, _ := sdk.ConsAddressToBytes(addrJ.String()) return bytes.Compare(bytesI, bytesJ) == -1 } - return valz[i].ConsensusPower() > valz[j].ConsensusPower() + return valz[i].ConsensusPower(r) > valz[j].ConsensusPower(r) } func (valz ValidatorsByVotingPower) Swap(i, j int) { @@ -146,12 +146,12 @@ func (v Validators) UnpackInterfaces(c codectypes.AnyUnpacker) error { } // return the redelegation -func MustMarshalValidator(cdc codec.BinaryMarshaler, validator *Validator) []byte { - return cdc.MustMarshalBinaryBare(validator) +func MustMarshalValidator(cdc codec.BinaryCodec, validator *Validator) []byte { + return cdc.MustMarshal(validator) } // unmarshal a redelegation from a store value -func MustUnmarshalValidator(cdc codec.BinaryMarshaler, value []byte) Validator { +func MustUnmarshalValidator(cdc codec.BinaryCodec, value []byte) Validator { validator, err := UnmarshalValidator(cdc, value) if err != nil { panic(err) @@ -161,8 +161,8 @@ func MustUnmarshalValidator(cdc codec.BinaryMarshaler, value []byte) Validator { } // unmarshal a redelegation from a store value -func UnmarshalValidator(cdc codec.BinaryMarshaler, value []byte) (v Validator, err error) { - err = cdc.UnmarshalBinaryBare(value, &v) +func UnmarshalValidator(cdc codec.BinaryCodec, value []byte) (v Validator, err error) { + err = cdc.Unmarshal(value, &v) return v, err } @@ -259,15 +259,15 @@ func (d Description) EnsureLength() (Description, error) { // ABCIValidatorUpdate returns an abci.ValidatorUpdate from a staking validator type // with the full validator power -func (v Validator) ABCIValidatorUpdate() abci.ValidatorUpdate { - ocprotoPk, err := v.OcConsPublicKey() +func (v Validator) ABCIValidatorUpdate(r sdk.Int) abci.ValidatorUpdate { + ocProtoPk, err := v.OcConsPublicKey() if err != nil { panic(err) } return abci.ValidatorUpdate{ - PubKey: ocprotoPk, - Power: v.ConsensusPower(), + PubKey: ocProtoPk, + Power: v.ConsensusPower(r), } } @@ -351,17 +351,17 @@ func (v Validator) BondedTokens() sdk.Int { // ConsensusPower gets the consensus-engine power. Aa reduction of 10^6 from // validator tokens is applied -func (v Validator) ConsensusPower() int64 { +func (v Validator) ConsensusPower(r sdk.Int) int64 { if v.IsBonded() { - return v.PotentialConsensusPower() + return v.PotentialConsensusPower(r) } return 0 } // PotentialConsensusPower returns the potential consensus-engine power. -func (v Validator) PotentialConsensusPower() int64 { - return sdk.TokensToConsensusPower(v.Tokens) +func (v Validator) PotentialConsensusPower(r sdk.Int) int64 { + return sdk.TokensToConsensusPower(v.Tokens, r) } // UpdateStatus updates the location of the shares within a validator @@ -503,9 +503,11 @@ func (v Validator) GetConsAddr() (sdk.ConsAddress, error) { return sdk.BytesToConsAddress(pk.Address()), nil } -func (v Validator) GetTokens() sdk.Int { return v.Tokens } -func (v Validator) GetBondedTokens() sdk.Int { return v.BondedTokens() } -func (v Validator) GetConsensusPower() int64 { return v.ConsensusPower() } +func (v Validator) GetTokens() sdk.Int { return v.Tokens } +func (v Validator) GetBondedTokens() sdk.Int { return v.BondedTokens() } +func (v Validator) GetConsensusPower(r sdk.Int) int64 { + return v.ConsensusPower(r) +} func (v Validator) GetCommission() sdk.Dec { return v.Commission.Rate } func (v Validator) GetMinSelfDelegation() sdk.Int { return v.MinSelfDelegation } func (v Validator) GetDelegatorShares() sdk.Dec { return v.DelegatorShares } diff --git a/x/staking/types/validator_test.go b/x/staking/types/validator_test.go index df2c1b5f2f..39e6e0b09c 100644 --- a/x/staking/types/validator_test.go +++ b/x/staking/types/validator_test.go @@ -58,7 +58,7 @@ func TestUpdateDescription(t *testing.T) { func TestABCIValidatorUpdate(t *testing.T) { validator := newValidator(t, valAddr1, pk1) - abciVal := validator.ABCIValidatorUpdate() + abciVal := validator.ABCIValidatorUpdate(sdk.DefaultPowerReduction) pk, err := validator.OcConsPublicKey() require.NoError(t, err) require.Equal(t, pk, abciVal.PubKey) @@ -290,13 +290,15 @@ func TestValidatorsSortTendermint(t *testing.T) { valz := types.Validators(vals) // create expected ostracon validators by converting to ostracon then sorting - expectedVals, err := teststaking.ToOcValidators(valz) + expectedVals, err := teststaking.ToOcValidators(valz, sdk.DefaultPowerReduction) require.NoError(t, err) sort.Sort(octypes.ValidatorsByVotingPower(expectedVals)) - // sort in SDK and then convert to ostracon - sort.Sort(types.ValidatorsByVotingPower(valz)) - actualVals, err := teststaking.ToOcValidators(valz) + // sort in SDK and then convert to tendermint + sort.SliceStable(valz, func(i, j int) bool { + return types.ValidatorsByVotingPower(valz).Less(i, j, sdk.DefaultPowerReduction) + }) + actualVals, err := teststaking.ToOcValidators(valz, sdk.DefaultPowerReduction) require.NoError(t, err) require.Equal(t, expectedVals, actualVals, "sorting in SDK is not the same as sorting in Tendermint") @@ -314,9 +316,9 @@ func TestValidatorToTm(t *testing.T) { vals[i] = val tmPk, err := cryptocodec.ToOcPubKeyInterface(pk) require.NoError(t, err) - expected[i] = octypes.NewValidator(tmPk, val.ConsensusPower()) + expected[i] = octypes.NewValidator(tmPk, val.ConsensusPower(sdk.DefaultPowerReduction)) } - vs, err := teststaking.ToOcValidators(vals) + vs, err := teststaking.ToOcValidators(vals, sdk.DefaultPowerReduction) require.NoError(t, err) require.Equal(t, expected, vs) } diff --git a/x/stakingplus/module.go b/x/stakingplus/module.go index ce1685f9c2..bafadf81c9 100644 --- a/x/stakingplus/module.go +++ b/x/stakingplus/module.go @@ -28,7 +28,7 @@ type AppModule struct { } // NewAppModule creates a new AppModule object -func NewAppModule(cdc codec.Marshaler, keeper stakingkeeper.Keeper, ak stakingtypes.AccountKeeper, bk stakingtypes.BankKeeper, ck types.ConsortiumKeeper) AppModule { +func NewAppModule(cdc codec.Codec, keeper stakingkeeper.Keeper, ak stakingtypes.AccountKeeper, bk stakingtypes.BankKeeper, ck types.ConsortiumKeeper) AppModule { return AppModule{ AppModule: staking.NewAppModule(cdc, keeper, ak, bk), keeper: keeper, diff --git a/x/stakingplus/spec/01_state.md b/x/stakingplus/spec/01_state.md new file mode 100644 index 0000000000..2964f3268f --- /dev/null +++ b/x/stakingplus/spec/01_state.md @@ -0,0 +1,7 @@ + + +# State + +There is no difference in state with that of Staking module of the Cosmos-SDK. Refer to the [original document](../../staking/spec/01_state.md) for more information. diff --git a/x/stakingplus/spec/02_state_transitions.md b/x/stakingplus/spec/02_state_transitions.md new file mode 100644 index 0000000000..67d4722346 --- /dev/null +++ b/x/stakingplus/spec/02_state_transitions.md @@ -0,0 +1,7 @@ + + +# State Transitions + +There is no difference in state trasitions with that of Staking module of the Cosmos-SDK. Refer to the [original document](../../staking/spec/02_state_transitions.md) for more information. diff --git a/x/stakingplus/spec/03_messages.md b/x/stakingplus/spec/03_messages.md new file mode 100644 index 0000000000..1f816feefd --- /dev/null +++ b/x/stakingplus/spec/03_messages.md @@ -0,0 +1,22 @@ + + +# Messages + +In this section we describe only the changes introduced by LBM-SDK. Refer to the [original document](../../staking/spec/03_messages.md) for more information. + +## Msg/CreateValidator + +A validator is created using the `Msg/CreateValidator` service message. + ++++ https://github.com/line/lbm-sdk/blob/main/proto/lbm/staking/v1/tx.proto#L16-L17 + ++++ https://github.com/line/lbm-sdk/blob/main/proto/lbm/staking/v1/tx.proto#L35-L51 + +This service message is expected to fail if: + +- one of the conditions described in the staking module of the Cosmos-SDK is met. +- the operator address is not registered on x/consortium through UpdateValidatorAuthsProposal. TODO: add a ref to x/consortium spec file. + +The other [statements](../../staking/spec/03_messages.md#msgcreatevalidator) on this message in the exising document are still valid. diff --git a/x/stakingplus/spec/04_begin_block.md b/x/stakingplus/spec/04_begin_block.md new file mode 100644 index 0000000000..e18353b6c7 --- /dev/null +++ b/x/stakingplus/spec/04_begin_block.md @@ -0,0 +1,7 @@ + + +# Begin-Block + +There is no difference in begin-block with that Staking module of the Cosmos-SDK. Refer to the [original document](../../staking/spec/04_begin_block.md) for more information. diff --git a/x/stakingplus/spec/05_end_block.md b/x/stakingplus/spec/05_end_block.md new file mode 100644 index 0000000000..8742811019 --- /dev/null +++ b/x/stakingplus/spec/05_end_block.md @@ -0,0 +1,7 @@ + + +# End-Block + +There is no difference in end-block with that Staking module of the Cosmos-SDK. Refer to the [original document](../../staking/spec/05_end_block.md) for more information. diff --git a/x/stakingplus/spec/06_hooks.md b/x/stakingplus/spec/06_hooks.md new file mode 100644 index 0000000000..f0ddd0630e --- /dev/null +++ b/x/stakingplus/spec/06_hooks.md @@ -0,0 +1,7 @@ + + +# Hooks + +There is no difference in hooks with that Staking module of the Cosmos-SDK. Refer to the [original document](../../staking/spec/06_hooks.md) for more information. diff --git a/x/stakingplus/spec/07_events.md b/x/stakingplus/spec/07_events.md new file mode 100644 index 0000000000..e533db8391 --- /dev/null +++ b/x/stakingplus/spec/07_events.md @@ -0,0 +1,7 @@ + + +# Events + +There is no difference in events with that Staking module of the Cosmos-SDK. Refer to the [original document](../../staking/spec/07_events.md) for more information. diff --git a/x/stakingplus/spec/08_params.md b/x/stakingplus/spec/08_params.md new file mode 100644 index 0000000000..0277fb605c --- /dev/null +++ b/x/stakingplus/spec/08_params.md @@ -0,0 +1,7 @@ + + +# Parameters + +There is no difference in parameters with that Staking module of the Cosmos-SDK. Refer to the [original document](../../staking/spec/08_params.md) for more information. diff --git a/x/stakingplus/spec/README.md b/x/stakingplus/spec/README.md new file mode 100644 index 0000000000..9ba410c263 --- /dev/null +++ b/x/stakingplus/spec/README.md @@ -0,0 +1,28 @@ + + +# `stakingplus` + +## Abstract + +This paper specifies the Staking Plus module of the LBM-SDK, which extends existing [Staking module](../../staking/spec/README.md) of the Cosmos-SDK. + +The module enables LBM-SDK based blockchain to support an advanced Proof-of-Stake system. In this system, holders of the native staking token of the chain can become validators and can delegate tokens to validators, ultimately determining the effective validator set for the system. + +This module is almost identical to the previous Staking module of the Cosmos-SDK, but introduces some breaking changes. For example, you must have x/consortium UpdateValidatorAuthsProposal passed before sending x/stakingplus MsgCreateValidator, or the message would fail. + +## Contents + +1. **[State](01_state.md)** +2. **[State Transitions](02_state_transitions.md)** +3. **[Messages](03_messages.md)** + - [Msg/CreateValidator](03_messages.md#msgcreatevalidator) +4. **[Begin-Block](04_begin_block.md)** +5. **[End-Block ](05_end_block.md)** +6. **[Hooks](06_hooks.md)** +7. **[Events](07_events.md)** +8. **[Parameters](08_params.md)** diff --git a/x/token/class/keeper/keeper.go b/x/token/class/keeper/keeper.go index edcbf88ae3..cfcf4f63d9 100644 --- a/x/token/class/keeper/keeper.go +++ b/x/token/class/keeper/keeper.go @@ -11,12 +11,12 @@ type Keeper struct { storeKey sdk.StoreKey // The codec for binary encoding/decoding. - cdc codec.BinaryMarshaler + cdc codec.Codec } // NewKeeper returns a class keeper func NewKeeper( - cdc codec.BinaryMarshaler, + cdc codec.Codec, key sdk.StoreKey, ) Keeper { return Keeper{ diff --git a/x/token/client/cli/query.go b/x/token/client/cli/query.go index d926c65614..2a8e97da62 100644 --- a/x/token/client/cli/query.go +++ b/x/token/client/cli/query.go @@ -23,7 +23,7 @@ func NewQueryCmd() *cobra.Command { } queryCmd.AddCommand( - NewQueryCmdTokenBalance(), + NewQueryCmdBalance(), NewQueryCmdSupply(), NewQueryCmdToken(), NewQueryCmdTokens(), @@ -35,7 +35,7 @@ func NewQueryCmd() *cobra.Command { return queryCmd } -func NewQueryCmdTokenBalance() *cobra.Command { +func NewQueryCmdBalance() *cobra.Command { cmd := &cobra.Command{ Use: "token-balance [class-id] [address]", Args: cobra.ExactArgs(2), @@ -47,7 +47,7 @@ func NewQueryCmdTokenBalance() *cobra.Command { return err } queryClient := token.NewQueryClient(clientCtx) - res, err := queryClient.TokenBalance(cmd.Context(), &token.QueryTokenBalanceRequest{ + res, err := queryClient.Balance(cmd.Context(), &token.QueryBalanceRequest{ ClassId: args[0], Address: args[1], }) diff --git a/x/token/client/testutil/query.go b/x/token/client/testutil/query.go index da39e5d685..85ebd31449 100644 --- a/x/token/client/testutil/query.go +++ b/x/token/client/testutil/query.go @@ -13,7 +13,7 @@ import ( "github.com/line/lbm-sdk/x/token/client/cli" ) -func (s *IntegrationTestSuite) TestNewQueryCmdTokenBalance() { +func (s *IntegrationTestSuite) TestNewQueryCmdBalance() { val := s.network.Validators[0] commonArgs := []string{ fmt.Sprintf("--%s=%d", flags.FlagHeight, s.setupHeight), @@ -31,7 +31,7 @@ func (s *IntegrationTestSuite) TestNewQueryCmdTokenBalance() { s.customer.String(), }, true, - &token.QueryTokenBalanceResponse{ + &token.QueryBalanceResponse{ Amount: s.balance, }, }, @@ -65,7 +65,7 @@ func (s *IntegrationTestSuite) TestNewQueryCmdTokenBalance() { tc := tc s.Run(name, func() { - cmd := cli.NewQueryCmdTokenBalance() + cmd := cli.NewQueryCmdBalance() out, err := clitestutil.ExecTestCLICmd(val.ClientCtx, cmd, append(tc.args, commonArgs...)) if !tc.valid { s.Require().Error(err) @@ -73,7 +73,7 @@ func (s *IntegrationTestSuite) TestNewQueryCmdTokenBalance() { } s.Require().NoError(err) - var actual token.QueryTokenBalanceResponse + var actual token.QueryBalanceResponse s.Require().NoError(val.ClientCtx.LegacyAmino.UnmarshalJSON(out.Bytes(), &actual), out.String()) s.Require().Equal(tc.expected, &actual) }) diff --git a/x/token/client/testutil/suite.go b/x/token/client/testutil/suite.go index 6b991f7aef..a5fc660d75 100644 --- a/x/token/client/testutil/suite.go +++ b/x/token/client/testutil/suite.go @@ -108,7 +108,7 @@ func (s *IntegrationTestSuite) createClass(owner, to sdk.AccAddress, name, symbo // creates an account and send some coins to it for the future transactions. func (s *IntegrationTestSuite) createAccount(uid string) sdk.AccAddress { val := s.network.Validators[0] - keyInfo, _, err := val.ClientCtx.Keyring.NewMnemonic(uid, keyring.English, sdk.FullFundraiserPath, hd.Secp256k1) + keyInfo, _, err := val.ClientCtx.Keyring.NewMnemonic(uid, keyring.English, sdk.FullFundraiserPath, keyring.DefaultBIP39Passphrase, hd.Secp256k1) s.Require().NoError(err) addr := keyInfo.GetAddress() diff --git a/x/token/keeper/alias.go b/x/token/keeper/alias.go index 4e851d5dc4..aa5b81fe23 100644 --- a/x/token/keeper/alias.go +++ b/x/token/keeper/alias.go @@ -40,7 +40,7 @@ func (k Keeper) iterateClasses(ctx sdk.Context, fn func(class token.Token) (stop for ; iterator.Valid(); iterator.Next() { var class token.Token - k.cdc.MustUnmarshalBinaryBare(iterator.Value(), &class) + k.cdc.MustUnmarshal(iterator.Value(), &class) stop := fn(class) if stop { diff --git a/x/token/keeper/keeper.go b/x/token/keeper/keeper.go index 6e39fcc006..446447f1a9 100644 --- a/x/token/keeper/keeper.go +++ b/x/token/keeper/keeper.go @@ -15,12 +15,12 @@ type Keeper struct { storeKey sdk.StoreKey // The codec for binary encoding/decoding. - cdc codec.BinaryMarshaler + cdc codec.Codec } // NewKeeper returns a token keeper func NewKeeper( - cdc codec.BinaryMarshaler, + cdc codec.Codec, key sdk.StoreKey, ak token.AccountKeeper, ck token.ClassKeeper, diff --git a/x/token/keeper/query_server.go b/x/token/keeper/query_server.go index cdb86c2024..f257fee1f1 100644 --- a/x/token/keeper/query_server.go +++ b/x/token/keeper/query_server.go @@ -27,8 +27,8 @@ func NewQueryServer(keeper Keeper) token.QueryServer { var _ token.QueryServer = queryServer{} -// TokenBalance queries the number of tokens of a given class owned by the owner. -func (s queryServer) TokenBalance(c context.Context, req *token.QueryTokenBalanceRequest) (*token.QueryTokenBalanceResponse, error) { +// Balance queries the number of tokens of a given class owned by the owner. +func (s queryServer) Balance(c context.Context, req *token.QueryBalanceRequest) (*token.QueryBalanceResponse, error) { if req == nil { return nil, status.Error(codes.InvalidArgument, "empty request") } @@ -43,7 +43,7 @@ func (s queryServer) TokenBalance(c context.Context, req *token.QueryTokenBalanc ctx := sdk.UnwrapSDKContext(c) balance := s.keeper.GetBalance(ctx, sdk.AccAddress(req.Address), req.ClassId) - return &token.QueryTokenBalanceResponse{Amount: balance.Amount}, nil + return &token.QueryBalanceResponse{Amount: balance.Amount}, nil } // Supply queries the number of tokens from the given class id. @@ -103,7 +103,7 @@ func (s queryServer) Tokens(c context.Context, req *token.QueryTokensRequest) (* var classes []token.Token pageRes, err := query.Paginate(classStore, req.Pagination, func(key []byte, value []byte) error { var class token.Token - s.keeper.cdc.MustUnmarshalBinaryBare(value, &class) + s.keeper.cdc.MustUnmarshal(value, &class) classes = append(classes, class) return nil }) diff --git a/x/token/keeper/query_server_test.go b/x/token/keeper/query_server_test.go index 773901beae..116475a1a1 100644 --- a/x/token/keeper/query_server_test.go +++ b/x/token/keeper/query_server_test.go @@ -6,22 +6,22 @@ import ( "github.com/line/lbm-sdk/x/token" ) -func (s *KeeperTestSuite) TestQueryTokenBalance() { +func (s *KeeperTestSuite) TestQueryBalance() { // empty request - _, err := s.queryServer.TokenBalance(s.goCtx, nil) + _, err := s.queryServer.Balance(s.goCtx, nil) s.Require().Error(err) testCases := map[string]struct { classId string address sdk.AccAddress valid bool - postTest func(res *token.QueryTokenBalanceResponse) + postTest func(res *token.QueryBalanceResponse) }{ "valid request": { classId: s.classID, address: s.vendor, valid: true, - postTest: func(res *token.QueryTokenBalanceResponse) { + postTest: func(res *token.QueryBalanceResponse) { s.Require().Equal(s.balance, res.Amount) }, }, @@ -39,11 +39,11 @@ func (s *KeeperTestSuite) TestQueryTokenBalance() { for name, tc := range testCases { s.Run(name, func() { - req := &token.QueryTokenBalanceRequest{ + req := &token.QueryBalanceRequest{ ClassId: tc.classId, Address: tc.address.String(), } - res, err := s.queryServer.TokenBalance(s.goCtx, req) + res, err := s.queryServer.Balance(s.goCtx, req) if !tc.valid { s.Require().Error(err) return diff --git a/x/token/keeper/supply.go b/x/token/keeper/supply.go index 92e33e8b67..22147b51cc 100644 --- a/x/token/keeper/supply.go +++ b/x/token/keeper/supply.go @@ -59,7 +59,7 @@ func (k Keeper) GetClass(ctx sdk.Context, classID string) (*token.Token, error) } var class token.Token - if err := k.cdc.UnmarshalBinaryBare(bz, &class); err != nil { + if err := k.cdc.Unmarshal(bz, &class); err != nil { return nil, err } @@ -68,7 +68,7 @@ func (k Keeper) GetClass(ctx sdk.Context, classID string) (*token.Token, error) func (k Keeper) setClass(ctx sdk.Context, class token.Token) error { store := ctx.KVStore(k.storeKey) - bz, err := k.cdc.MarshalBinaryBare(&class) + bz, err := k.cdc.Marshal(&class) if err != nil { return err } diff --git a/x/token/module/module.go b/x/token/module/module.go index 4da14b869f..7522c03563 100644 --- a/x/token/module/module.go +++ b/x/token/module/module.go @@ -27,7 +27,7 @@ var ( // AppModuleBasic defines the basic application module used by the token module. type AppModuleBasic struct { - cdc codec.Marshaler + cdc codec.Codec } // NewAppModuleBasic creates a new AppModuleBasic object @@ -45,12 +45,12 @@ func (AppModuleBasic) RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) {} // DefaultGenesis returns default genesis state as raw bytes for the token // module. -func (AppModuleBasic) DefaultGenesis(cdc codec.JSONMarshaler) json.RawMessage { +func (AppModuleBasic) DefaultGenesis(cdc codec.JSONCodec) json.RawMessage { return cdc.MustMarshalJSON(token.DefaultGenesisState()) } // ValidateGenesis performs genesis state validation for the token module. -func (AppModuleBasic) ValidateGenesis(cdc codec.JSONMarshaler, config client.TxEncodingConfig, bz json.RawMessage) error { +func (AppModuleBasic) ValidateGenesis(cdc codec.JSONCodec, config client.TxEncodingConfig, bz json.RawMessage) error { var data token.GenesisState if err := cdc.UnmarshalJSON(bz, &data); err != nil { return fmt.Errorf("failed to unmarshal %s genesis state: %w", token.ModuleName, err) @@ -93,7 +93,7 @@ type AppModule struct { } // NewAppModule creates a new AppModule object -func NewAppModule(cdc codec.Marshaler, keeper keeper.Keeper) AppModule { +func NewAppModule(cdc codec.Codec, keeper keeper.Keeper) AppModule { return AppModule{ AppModuleBasic: AppModuleBasic{cdc: cdc}, keeper: keeper, @@ -130,7 +130,7 @@ func (am AppModule) RegisterServices(cfg module.Configurator) { // InitGenesis performs genesis initialization for the token module. It returns // no validator updates. -func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONMarshaler, data json.RawMessage) []abci.ValidatorUpdate { +func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONCodec, data json.RawMessage) []abci.ValidatorUpdate { var genesisState token.GenesisState cdc.MustUnmarshalJSON(data, &genesisState) am.keeper.InitGenesis(ctx, &genesisState) @@ -139,7 +139,7 @@ func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONMarshaler, data j // ExportGenesis returns the exported genesis state as raw bytes for the token // module. -func (am AppModule) ExportGenesis(ctx sdk.Context, cdc codec.JSONMarshaler) json.RawMessage { +func (am AppModule) ExportGenesis(ctx sdk.Context, cdc codec.JSONCodec) json.RawMessage { gs := am.keeper.ExportGenesis(ctx) return cdc.MustMarshalJSON(gs) } diff --git a/x/token/query.pb.go b/x/token/query.pb.go index 34cfd938e7..b8e2972361 100644 --- a/x/token/query.pb.go +++ b/x/token/query.pb.go @@ -31,25 +31,25 @@ var _ = math.Inf // proto package needs to be updated. const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package -// QueryTokenBalanceRequest is the request type for the Query/TokenBalance RPC method -type QueryTokenBalanceRequest struct { +// QueryBalanceRequest is the request type for the Query/Balance RPC method +type QueryBalanceRequest struct { // class id associated with the token. ClassId string `protobuf:"bytes,1,opt,name=class_id,json=classId,proto3" json:"class_id,omitempty"` Address string `protobuf:"bytes,2,opt,name=address,proto3" json:"address,omitempty"` } -func (m *QueryTokenBalanceRequest) Reset() { *m = QueryTokenBalanceRequest{} } -func (m *QueryTokenBalanceRequest) String() string { return proto.CompactTextString(m) } -func (*QueryTokenBalanceRequest) ProtoMessage() {} -func (*QueryTokenBalanceRequest) Descriptor() ([]byte, []int) { +func (m *QueryBalanceRequest) Reset() { *m = QueryBalanceRequest{} } +func (m *QueryBalanceRequest) String() string { return proto.CompactTextString(m) } +func (*QueryBalanceRequest) ProtoMessage() {} +func (*QueryBalanceRequest) Descriptor() ([]byte, []int) { return fileDescriptor_7759ed3b35cde06a, []int{0} } -func (m *QueryTokenBalanceRequest) XXX_Unmarshal(b []byte) error { +func (m *QueryBalanceRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) } -func (m *QueryTokenBalanceRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { +func (m *QueryBalanceRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { if deterministic { - return xxx_messageInfo_QueryTokenBalanceRequest.Marshal(b, m, deterministic) + return xxx_messageInfo_QueryBalanceRequest.Marshal(b, m, deterministic) } else { b = b[:cap(b)] n, err := m.MarshalToSizedBuffer(b) @@ -59,49 +59,49 @@ func (m *QueryTokenBalanceRequest) XXX_Marshal(b []byte, deterministic bool) ([] return b[:n], nil } } -func (m *QueryTokenBalanceRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_QueryTokenBalanceRequest.Merge(m, src) +func (m *QueryBalanceRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryBalanceRequest.Merge(m, src) } -func (m *QueryTokenBalanceRequest) XXX_Size() int { +func (m *QueryBalanceRequest) XXX_Size() int { return m.Size() } -func (m *QueryTokenBalanceRequest) XXX_DiscardUnknown() { - xxx_messageInfo_QueryTokenBalanceRequest.DiscardUnknown(m) +func (m *QueryBalanceRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QueryBalanceRequest.DiscardUnknown(m) } -var xxx_messageInfo_QueryTokenBalanceRequest proto.InternalMessageInfo +var xxx_messageInfo_QueryBalanceRequest proto.InternalMessageInfo -func (m *QueryTokenBalanceRequest) GetClassId() string { +func (m *QueryBalanceRequest) GetClassId() string { if m != nil { return m.ClassId } return "" } -func (m *QueryTokenBalanceRequest) GetAddress() string { +func (m *QueryBalanceRequest) GetAddress() string { if m != nil { return m.Address } return "" } -// QueryTokenBalanceResponse is the response type for the Query/TokenBalance RPC method -type QueryTokenBalanceResponse struct { +// QueryBalanceResponse is the response type for the Query/Balance RPC method +type QueryBalanceResponse struct { Amount github_com_line_lbm_sdk_types.Int `protobuf:"bytes,1,opt,name=amount,proto3,customtype=github.com/line/lbm-sdk/types.Int" json:"amount"` } -func (m *QueryTokenBalanceResponse) Reset() { *m = QueryTokenBalanceResponse{} } -func (m *QueryTokenBalanceResponse) String() string { return proto.CompactTextString(m) } -func (*QueryTokenBalanceResponse) ProtoMessage() {} -func (*QueryTokenBalanceResponse) Descriptor() ([]byte, []int) { +func (m *QueryBalanceResponse) Reset() { *m = QueryBalanceResponse{} } +func (m *QueryBalanceResponse) String() string { return proto.CompactTextString(m) } +func (*QueryBalanceResponse) ProtoMessage() {} +func (*QueryBalanceResponse) Descriptor() ([]byte, []int) { return fileDescriptor_7759ed3b35cde06a, []int{1} } -func (m *QueryTokenBalanceResponse) XXX_Unmarshal(b []byte) error { +func (m *QueryBalanceResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) } -func (m *QueryTokenBalanceResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { +func (m *QueryBalanceResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { if deterministic { - return xxx_messageInfo_QueryTokenBalanceResponse.Marshal(b, m, deterministic) + return xxx_messageInfo_QueryBalanceResponse.Marshal(b, m, deterministic) } else { b = b[:cap(b)] n, err := m.MarshalToSizedBuffer(b) @@ -111,17 +111,17 @@ func (m *QueryTokenBalanceResponse) XXX_Marshal(b []byte, deterministic bool) ([ return b[:n], nil } } -func (m *QueryTokenBalanceResponse) XXX_Merge(src proto.Message) { - xxx_messageInfo_QueryTokenBalanceResponse.Merge(m, src) +func (m *QueryBalanceResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryBalanceResponse.Merge(m, src) } -func (m *QueryTokenBalanceResponse) XXX_Size() int { +func (m *QueryBalanceResponse) XXX_Size() int { return m.Size() } -func (m *QueryTokenBalanceResponse) XXX_DiscardUnknown() { - xxx_messageInfo_QueryTokenBalanceResponse.DiscardUnknown(m) +func (m *QueryBalanceResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryBalanceResponse.DiscardUnknown(m) } -var xxx_messageInfo_QueryTokenBalanceResponse proto.InternalMessageInfo +var xxx_messageInfo_QueryBalanceResponse proto.InternalMessageInfo // QuerySupplyRequest is the request type for the Query/Supply RPC method type QuerySupplyRequest struct { @@ -727,8 +727,8 @@ func (m *QueryApprovesResponse) GetPagination() *query.PageResponse { } func init() { - proto.RegisterType((*QueryTokenBalanceRequest)(nil), "lbm.token.v1.QueryTokenBalanceRequest") - proto.RegisterType((*QueryTokenBalanceResponse)(nil), "lbm.token.v1.QueryTokenBalanceResponse") + proto.RegisterType((*QueryBalanceRequest)(nil), "lbm.token.v1.QueryBalanceRequest") + proto.RegisterType((*QueryBalanceResponse)(nil), "lbm.token.v1.QueryBalanceResponse") proto.RegisterType((*QuerySupplyRequest)(nil), "lbm.token.v1.QuerySupplyRequest") proto.RegisterType((*QuerySupplyResponse)(nil), "lbm.token.v1.QuerySupplyResponse") proto.RegisterType((*QueryTokenRequest)(nil), "lbm.token.v1.QueryTokenRequest") @@ -746,56 +746,56 @@ func init() { func init() { proto.RegisterFile("lbm/token/v1/query.proto", fileDescriptor_7759ed3b35cde06a) } var fileDescriptor_7759ed3b35cde06a = []byte{ - // 778 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x56, 0xcd, 0x6b, 0x13, 0x41, - 0x1c, 0xcd, 0xb6, 0x4d, 0x52, 0xc7, 0x5e, 0x9c, 0xa6, 0x92, 0x86, 0xb2, 0x49, 0x47, 0xb0, 0xd6, - 0x8f, 0x1d, 0xd2, 0x22, 0x22, 0x82, 0xd2, 0x8a, 0xd4, 0x9e, 0xd4, 0xd8, 0x83, 0x78, 0x50, 0x66, - 0x9b, 0x65, 0x0d, 0xdd, 0xec, 0x6c, 0x77, 0x36, 0xa1, 0x21, 0x04, 0xc4, 0x83, 0xe2, 0x41, 0x50, - 0xfa, 0x4f, 0xf5, 0x58, 0xf0, 0x22, 0x1e, 0x8a, 0xb4, 0xfe, 0x21, 0xb2, 0xf3, 0x91, 0xee, 0xc8, - 0xee, 0xb6, 0x7e, 0xdc, 0x76, 0x3a, 0x6f, 0xde, 0x7b, 0xbf, 0xf9, 0xfd, 0xe6, 0x35, 0xa0, 0xea, - 0xd9, 0x5d, 0x1c, 0xd1, 0x1d, 0xc7, 0xc7, 0xfd, 0x26, 0xde, 0xed, 0x39, 0xe1, 0xc0, 0x0a, 0x42, - 0x1a, 0x51, 0x38, 0xe3, 0xd9, 0x5d, 0x8b, 0xef, 0x58, 0xfd, 0x66, 0x0d, 0xc5, 0x38, 0x9b, 0x30, - 0x47, 0x60, 0x62, 0x70, 0x40, 0xdc, 0x8e, 0x4f, 0xa2, 0x0e, 0xf5, 0xc5, 0x89, 0xda, 0x82, 0x4b, - 0xa9, 0xeb, 0x39, 0x98, 0x04, 0x1d, 0x4c, 0x7c, 0x9f, 0x46, 0x7c, 0x93, 0xc9, 0x5d, 0x5d, 0x49, - 0x10, 0x8b, 0x9d, 0x8a, 0x4b, 0x5d, 0xca, 0x3f, 0x71, 0xfc, 0x25, 0xfe, 0x8a, 0x9e, 0x80, 0xea, - 0xb3, 0x58, 0x6a, 0x2b, 0x46, 0xae, 0x13, 0x8f, 0xf8, 0xdb, 0x4e, 0xcb, 0xd9, 0xed, 0x39, 0x2c, - 0x82, 0xf3, 0x60, 0x7a, 0xdb, 0x23, 0x8c, 0xbd, 0xee, 0xb4, 0xab, 0x46, 0xc3, 0xb8, 0x76, 0xa1, - 0x55, 0xe6, 0xeb, 0xcd, 0x36, 0xac, 0x82, 0x32, 0x69, 0xb7, 0x43, 0x87, 0xb1, 0xea, 0x84, 0xd8, - 0x91, 0x4b, 0xf4, 0x0a, 0xcc, 0xa7, 0x10, 0xb2, 0x80, 0xfa, 0xcc, 0x81, 0x6b, 0xa0, 0x44, 0xba, - 0xb4, 0xe7, 0x47, 0x82, 0x6f, 0x7d, 0xf9, 0xe0, 0xa8, 0x5e, 0xf8, 0x7e, 0x54, 0x5f, 0x74, 0x3b, - 0xd1, 0x9b, 0x9e, 0x6d, 0x6d, 0xd3, 0x2e, 0xf6, 0x3a, 0xbe, 0x83, 0x3d, 0xbb, 0x7b, 0x8b, 0xb5, - 0x77, 0x70, 0x34, 0x08, 0x1c, 0x66, 0x6d, 0xfa, 0x51, 0x4b, 0x1e, 0x44, 0x0f, 0x01, 0xe4, 0xfc, - 0xcf, 0x7b, 0x41, 0xe0, 0x0d, 0xce, 0x61, 0x15, 0x82, 0xa9, 0x98, 0x45, 0xfa, 0xe4, 0xdf, 0xe8, - 0x05, 0x98, 0xd5, 0x48, 0xfe, 0x9f, 0x3d, 0x0b, 0x5c, 0x3a, 0x2d, 0xff, 0x6c, 0x77, 0xe8, 0x91, - 0x2c, 0x47, 0xe2, 0xa5, 0x11, 0x0c, 0x8a, 0xbc, 0x75, 0x1c, 0x7d, 0x71, 0x65, 0xd6, 0x4a, 0x4e, - 0x89, 0x25, 0xae, 0x76, 0x2a, 0x36, 0xd7, 0x12, 0x38, 0xb4, 0x95, 0xa4, 0x61, 0x4a, 0xf7, 0x3e, - 0x00, 0xa7, 0xe3, 0x23, 0xb9, 0x4c, 0xce, 0x15, 0xcf, 0x98, 0x25, 0xe6, 0xb0, 0xdf, 0xb4, 0x9e, - 0x12, 0x57, 0x35, 0xbd, 0x95, 0x38, 0x81, 0x3e, 0x1a, 0xf2, 0x9e, 0x14, 0xad, 0xb4, 0xd7, 0x04, - 0x25, 0x2e, 0xcb, 0xaa, 0x46, 0x63, 0x32, 0xdf, 0x9f, 0x04, 0xc2, 0x07, 0x9a, 0x95, 0x09, 0x6e, - 0xa5, 0x9e, 0x69, 0x45, 0xe8, 0x68, 0x5e, 0x36, 0x65, 0x85, 0x1b, 0x21, 0xf1, 0x23, 0x76, 0xbe, - 0x11, 0x75, 0x63, 0xac, 0xa3, 0x5a, 0xaf, 0x96, 0xe8, 0xb1, 0xac, 0x4a, 0x51, 0x9d, 0x56, 0xc5, - 0x11, 0x19, 0x55, 0x71, 0xb4, 0xaa, 0x4a, 0x00, 0x91, 0x2d, 0x99, 0xd6, 0x82, 0x20, 0xa4, 0xfd, - 0xf3, 0x3c, 0x9c, 0x0a, 0x28, 0x06, 0x21, 0xdd, 0x1b, 0x48, 0x4f, 0x62, 0x01, 0x6b, 0x60, 0x9a, - 0x08, 0x8a, 0xb0, 0x3a, 0xc9, 0x37, 0xc6, 0x6b, 0xb4, 0x01, 0x2a, 0xba, 0xc6, 0x78, 0x46, 0xca, - 0x12, 0x23, 0x3b, 0x3b, 0xa7, 0xfb, 0x55, 0x78, 0x85, 0x42, 0x1f, 0x0c, 0x9d, 0x89, 0xfd, 0xb5, - 0x5d, 0x7d, 0xae, 0x26, 0xff, 0x78, 0xae, 0xbe, 0x18, 0x60, 0xee, 0x37, 0x27, 0xb2, 0xa8, 0x3b, - 0xe3, 0x8b, 0x50, 0x5d, 0x48, 0xaf, 0x4a, 0xf6, 0x61, 0x0c, 0xfe, 0xe7, 0xf9, 0x5a, 0xd9, 0x2f, - 0x83, 0x22, 0xf7, 0x04, 0xf7, 0x0d, 0x30, 0x93, 0x4c, 0x2f, 0x78, 0x55, 0xb7, 0x90, 0x95, 0x97, - 0xb5, 0xa5, 0x33, 0x71, 0x42, 0x17, 0xad, 0xbc, 0xfb, 0xfa, 0x73, 0x7f, 0xe2, 0x26, 0xbc, 0x8e, - 0xb5, 0xb4, 0xb6, 0x05, 0x0c, 0x0f, 0x65, 0x96, 0x8e, 0xf0, 0x50, 0xf5, 0x65, 0x04, 0xfb, 0xa0, - 0x24, 0xd2, 0x0a, 0x36, 0x52, 0x64, 0xb4, 0x34, 0xac, 0x2d, 0xe6, 0x20, 0xa4, 0x85, 0x25, 0x6e, - 0x61, 0x11, 0xd6, 0x75, 0x0b, 0x8c, 0xa3, 0x92, 0xba, 0x0c, 0x14, 0x79, 0x0d, 0xb0, 0x9e, 0x55, - 0x9d, 0x52, 0x6d, 0x64, 0x03, 0xf2, 0x45, 0x45, 0x44, 0x24, 0x45, 0x77, 0x40, 0x49, 0x44, 0x0e, - 0xcc, 0x24, 0x65, 0x79, 0xc5, 0xea, 0x79, 0x85, 0x16, 0xb8, 0xee, 0x65, 0x58, 0x49, 0xd3, 0x85, - 0x6f, 0x0d, 0x50, 0x12, 0x51, 0x90, 0xaa, 0xa6, 0x05, 0x4e, 0xaa, 0x9a, 0x9e, 0x23, 0xa8, 0xc9, - 0xd5, 0x6e, 0xc0, 0x65, 0x5d, 0x4d, 0x44, 0x06, 0x1e, 0xca, 0x14, 0xd2, 0x9a, 0xfb, 0xc9, 0x00, - 0x65, 0x39, 0xd9, 0x30, 0x4d, 0x41, 0xcf, 0x97, 0x1a, 0xca, 0x83, 0x48, 0x17, 0xf7, 0xb8, 0x8b, - 0xdb, 0x70, 0x55, 0x77, 0x21, 0x1f, 0x4c, 0x42, 0x1c, 0x0f, 0xf9, 0xa3, 0x1e, 0xe1, 0xa1, 0x8a, - 0x9c, 0x11, 0x7c, 0x6f, 0x80, 0x69, 0xf5, 0x36, 0x61, 0x8e, 0xda, 0xf8, 0x5a, 0xae, 0xe4, 0x62, - 0xf2, 0x2f, 0x46, 0xbd, 0xe1, 0x14, 0x4f, 0xeb, 0x77, 0x0f, 0x8e, 0x4d, 0xe3, 0xf0, 0xd8, 0x34, - 0x7e, 0x1c, 0x9b, 0xc6, 0xe7, 0x13, 0xb3, 0x70, 0x78, 0x62, 0x16, 0xbe, 0x9d, 0x98, 0x85, 0x97, - 0xf5, 0xac, 0xff, 0xc9, 0x7b, 0x82, 0xd9, 0x2e, 0xf1, 0x1f, 0x38, 0xab, 0xbf, 0x02, 0x00, 0x00, - 0xff, 0xff, 0x63, 0x06, 0xf3, 0xca, 0x7c, 0x09, 0x00, 0x00, + // 781 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x56, 0xcd, 0x6b, 0x13, 0x4f, + 0x18, 0xce, 0xb6, 0x4d, 0xd2, 0xdf, 0xfc, 0xbc, 0x38, 0x4d, 0x25, 0x86, 0x92, 0x8f, 0xf1, 0xa0, + 0xf5, 0x63, 0x87, 0xb4, 0x88, 0x88, 0xa0, 0x34, 0x22, 0xb5, 0x9e, 0x34, 0xf6, 0xa0, 0x5e, 0x64, + 0xb7, 0x59, 0xd6, 0xd0, 0xcd, 0xce, 0x76, 0x67, 0x13, 0x1a, 0x42, 0x40, 0xa4, 0x28, 0x1e, 0x04, + 0xc5, 0x7f, 0xaa, 0xc7, 0x82, 0x17, 0xf1, 0x50, 0xa4, 0xf5, 0x0f, 0x91, 0x9d, 0x79, 0x27, 0xdd, + 0x29, 0x9b, 0xb5, 0x7e, 0xdc, 0x76, 0x3b, 0xcf, 0x3e, 0xcf, 0xf3, 0xce, 0xfb, 0xbe, 0x4f, 0x83, + 0xca, 0x9e, 0xdd, 0xa3, 0x11, 0xdb, 0x76, 0x7c, 0x3a, 0x68, 0xd2, 0x9d, 0xbe, 0x13, 0x0e, 0xcd, + 0x20, 0x64, 0x11, 0xc3, 0xe7, 0x3c, 0xbb, 0x67, 0x8a, 0x13, 0x73, 0xd0, 0xac, 0x90, 0x18, 0x67, + 0x5b, 0xdc, 0x91, 0x98, 0x18, 0x1c, 0x58, 0x6e, 0xd7, 0xb7, 0xa2, 0x2e, 0xf3, 0xe5, 0x17, 0x95, + 0x25, 0x97, 0x31, 0xd7, 0x73, 0xa8, 0x15, 0x74, 0xa9, 0xe5, 0xfb, 0x2c, 0x12, 0x87, 0x1c, 0x4e, + 0x75, 0x25, 0x49, 0x2c, 0x4f, 0x4a, 0x2e, 0x73, 0x99, 0x78, 0xa4, 0xf1, 0x93, 0xfc, 0x2b, 0x79, + 0x84, 0x16, 0x9e, 0xc4, 0x52, 0x2d, 0xcb, 0xb3, 0xfc, 0x2d, 0xa7, 0xed, 0xec, 0xf4, 0x1d, 0x1e, + 0xe1, 0x8b, 0x68, 0x7e, 0xcb, 0xb3, 0x38, 0x7f, 0xd9, 0xed, 0x94, 0x8d, 0xba, 0x71, 0xe5, 0xbf, + 0x76, 0x51, 0xbc, 0x6f, 0x74, 0x70, 0x19, 0x15, 0xad, 0x4e, 0x27, 0x74, 0x38, 0x2f, 0xcf, 0xc8, + 0x13, 0x78, 0x25, 0xcf, 0x51, 0x49, 0xe7, 0xe2, 0x01, 0xf3, 0xb9, 0x83, 0xd7, 0x50, 0xc1, 0xea, + 0xb1, 0xbe, 0x1f, 0x49, 0xaa, 0xd6, 0xf2, 0xfe, 0x61, 0x2d, 0xf7, 0xed, 0xb0, 0xd6, 0x70, 0xbb, + 0xd1, 0xab, 0xbe, 0x6d, 0x6e, 0xb1, 0x1e, 0xf5, 0xba, 0xbe, 0x43, 0x3d, 0xbb, 0x77, 0x83, 0x77, + 0xb6, 0x69, 0x34, 0x0c, 0x1c, 0x6e, 0x6e, 0xf8, 0x51, 0x1b, 0x3e, 0x24, 0xf7, 0x11, 0x16, 0xd4, + 0x4f, 0xfb, 0x41, 0xe0, 0x0d, 0xcf, 0xe0, 0x12, 0xa3, 0xb9, 0x98, 0x05, 0x2c, 0x8a, 0x67, 0xf2, + 0x0c, 0x6a, 0x55, 0x24, 0xff, 0xce, 0x9e, 0x89, 0xce, 0x0b, 0xe6, 0xcd, 0xf8, 0xbe, 0x7f, 0xed, + 0x8e, 0x3c, 0x80, 0x72, 0x00, 0x0f, 0x46, 0x28, 0xca, 0x8b, 0x86, 0x09, 0xf4, 0xff, 0x2b, 0x0b, + 0x66, 0x72, 0x36, 0x4c, 0x81, 0x6d, 0xcd, 0xc5, 0xe6, 0xda, 0x12, 0x47, 0x36, 0x93, 0x34, 0x5c, + 0xe9, 0xde, 0x45, 0xe8, 0x64, 0x68, 0x80, 0xab, 0x2a, 0xb8, 0xe2, 0xc9, 0x32, 0xe5, 0xf4, 0x0d, + 0x9a, 0xe6, 0x63, 0xcb, 0x55, 0xfd, 0x6e, 0x27, 0xbe, 0x20, 0xef, 0x0d, 0xb8, 0x27, 0x45, 0x0b, + 0xf6, 0x9a, 0xa8, 0x20, 0x64, 0x79, 0xd9, 0xa8, 0xcf, 0x66, 0xfb, 0x03, 0x20, 0xbe, 0xa7, 0x59, + 0x99, 0x11, 0x56, 0x6a, 0x53, 0xad, 0x48, 0x1d, 0xcd, 0xcb, 0x06, 0x54, 0xb8, 0x1e, 0x5a, 0x7e, + 0xc4, 0xcf, 0x36, 0x9d, 0x6e, 0x8c, 0x75, 0x54, 0xeb, 0xd5, 0x2b, 0x79, 0x08, 0x55, 0x29, 0xaa, + 0x93, 0xaa, 0x04, 0x62, 0x4a, 0x55, 0x02, 0xad, 0xaa, 0x92, 0x40, 0x62, 0x03, 0xd3, 0x5a, 0x10, + 0x84, 0x6c, 0x70, 0x96, 0x9d, 0x29, 0xa1, 0x7c, 0x10, 0xb2, 0xdd, 0x21, 0x78, 0x92, 0x2f, 0xb8, + 0x82, 0xe6, 0x2d, 0x49, 0x11, 0x96, 0x67, 0xc5, 0xc1, 0xe4, 0x9d, 0xac, 0xc3, 0x2e, 0x4d, 0x34, + 0x26, 0x33, 0x52, 0x04, 0x0c, 0x74, 0x76, 0x51, 0xf7, 0xab, 0xf0, 0x0a, 0x45, 0xde, 0x19, 0x3a, + 0x13, 0xff, 0x63, 0xbb, 0xfa, 0x5c, 0xcd, 0xfe, 0xf6, 0x5c, 0x7d, 0x32, 0xd0, 0xe2, 0x29, 0x27, + 0x50, 0xd4, 0xad, 0xc9, 0x45, 0xa8, 0x2e, 0xa4, 0x57, 0x05, 0x7d, 0x98, 0x80, 0xff, 0x7a, 0xbe, + 0x56, 0xf6, 0x8a, 0x28, 0x2f, 0x3c, 0xe1, 0x3d, 0x03, 0x15, 0x21, 0xb8, 0x70, 0x43, 0x57, 0x4f, + 0x09, 0xc8, 0x0a, 0xc9, 0x82, 0x48, 0x21, 0xb2, 0xf2, 0xe6, 0xcb, 0x8f, 0xcf, 0x33, 0xd7, 0xf1, + 0x55, 0xaa, 0x85, 0xb2, 0x2d, 0x61, 0x74, 0x04, 0xb9, 0x39, 0xa6, 0x23, 0xd5, 0x88, 0x31, 0x1e, + 0xa0, 0x82, 0x8c, 0x27, 0x5c, 0x4f, 0x51, 0xd0, 0xe2, 0xaf, 0xd2, 0xc8, 0x40, 0x80, 0x85, 0xcb, + 0xc2, 0x42, 0x03, 0xd7, 0x74, 0x0b, 0x5c, 0xa0, 0x92, 0xba, 0x1c, 0xe5, 0xc5, 0x02, 0xe3, 0x5a, + 0x0a, 0x69, 0x32, 0xd6, 0x2a, 0xf5, 0xe9, 0x80, 0x6c, 0x51, 0x99, 0x09, 0x49, 0xd1, 0x6d, 0x54, + 0x90, 0x19, 0x83, 0xa7, 0x92, 0xf2, 0xac, 0x62, 0xf5, 0x80, 0x22, 0x4b, 0x42, 0xf7, 0x02, 0x2e, + 0xa5, 0xe9, 0xe2, 0xd7, 0x06, 0x2a, 0xc8, 0xdd, 0x4f, 0x55, 0xd3, 0x12, 0x26, 0x55, 0x4d, 0x0f, + 0x0e, 0xd2, 0x14, 0x6a, 0xd7, 0xf0, 0xb2, 0xae, 0x26, 0x33, 0x82, 0x8e, 0x20, 0x76, 0xb4, 0xe6, + 0x7e, 0x30, 0x50, 0x11, 0x46, 0x39, 0x75, 0xc6, 0xf4, 0x40, 0x49, 0x9d, 0xb1, 0x53, 0x79, 0x40, + 0xee, 0x08, 0x17, 0x37, 0xf1, 0xaa, 0xee, 0x02, 0x36, 0x24, 0x21, 0x4e, 0x47, 0x62, 0x8b, 0xc7, + 0x74, 0xa4, 0x32, 0x66, 0x8c, 0xdf, 0x1a, 0x68, 0x5e, 0x2d, 0x23, 0xce, 0x50, 0x9b, 0x5c, 0xcb, + 0xa5, 0x4c, 0x4c, 0xf6, 0xc5, 0xa8, 0xa5, 0x4d, 0xf1, 0xd4, 0xba, 0xbd, 0x7f, 0x54, 0x35, 0x0e, + 0x8e, 0xaa, 0xc6, 0xf7, 0xa3, 0xaa, 0xf1, 0xf1, 0xb8, 0x9a, 0x3b, 0x38, 0xae, 0xe6, 0xbe, 0x1e, + 0x57, 0x73, 0x2f, 0x6a, 0xd3, 0xfe, 0x09, 0xef, 0x4a, 0x66, 0xbb, 0x20, 0x7e, 0xc7, 0xac, 0xfe, + 0x0c, 0x00, 0x00, 0xff, 0xff, 0x6a, 0xa7, 0x6f, 0x75, 0x63, 0x09, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -810,8 +810,8 @@ const _ = grpc.SupportPackageIsVersion4 // // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. type QueryClient interface { - // TokenBalance queries the number of tokens of a given class owned by the address. - TokenBalance(ctx context.Context, in *QueryTokenBalanceRequest, opts ...grpc.CallOption) (*QueryTokenBalanceResponse, error) + // Balance queries the number of tokens of a given class owned by the address. + Balance(ctx context.Context, in *QueryBalanceRequest, opts ...grpc.CallOption) (*QueryBalanceResponse, error) // Supply queries the number of tokens from the given class id. Supply(ctx context.Context, in *QuerySupplyRequest, opts ...grpc.CallOption) (*QuerySupplyResponse, error) // Token queries an token metadata based on its class id. @@ -834,9 +834,9 @@ func NewQueryClient(cc grpc1.ClientConn) QueryClient { return &queryClient{cc} } -func (c *queryClient) TokenBalance(ctx context.Context, in *QueryTokenBalanceRequest, opts ...grpc.CallOption) (*QueryTokenBalanceResponse, error) { - out := new(QueryTokenBalanceResponse) - err := c.cc.Invoke(ctx, "/lbm.token.v1.Query/TokenBalance", in, out, opts...) +func (c *queryClient) Balance(ctx context.Context, in *QueryBalanceRequest, opts ...grpc.CallOption) (*QueryBalanceResponse, error) { + out := new(QueryBalanceResponse) + err := c.cc.Invoke(ctx, "/lbm.token.v1.Query/Balance", in, out, opts...) if err != nil { return nil, err } @@ -899,8 +899,8 @@ func (c *queryClient) Approves(ctx context.Context, in *QueryApprovesRequest, op // QueryServer is the server API for Query service. type QueryServer interface { - // TokenBalance queries the number of tokens of a given class owned by the address. - TokenBalance(context.Context, *QueryTokenBalanceRequest) (*QueryTokenBalanceResponse, error) + // Balance queries the number of tokens of a given class owned by the address. + Balance(context.Context, *QueryBalanceRequest) (*QueryBalanceResponse, error) // Supply queries the number of tokens from the given class id. Supply(context.Context, *QuerySupplyRequest) (*QuerySupplyResponse, error) // Token queries an token metadata based on its class id. @@ -919,8 +919,8 @@ type QueryServer interface { type UnimplementedQueryServer struct { } -func (*UnimplementedQueryServer) TokenBalance(ctx context.Context, req *QueryTokenBalanceRequest) (*QueryTokenBalanceResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method TokenBalance not implemented") +func (*UnimplementedQueryServer) Balance(ctx context.Context, req *QueryBalanceRequest) (*QueryBalanceResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Balance not implemented") } func (*UnimplementedQueryServer) Supply(ctx context.Context, req *QuerySupplyRequest) (*QuerySupplyResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method Supply not implemented") @@ -945,20 +945,20 @@ func RegisterQueryServer(s grpc1.Server, srv QueryServer) { s.RegisterService(&_Query_serviceDesc, srv) } -func _Query_TokenBalance_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(QueryTokenBalanceRequest) +func _Query_Balance_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryBalanceRequest) if err := dec(in); err != nil { return nil, err } if interceptor == nil { - return srv.(QueryServer).TokenBalance(ctx, in) + return srv.(QueryServer).Balance(ctx, in) } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/lbm.token.v1.Query/TokenBalance", + FullMethod: "/lbm.token.v1.Query/Balance", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(QueryServer).TokenBalance(ctx, req.(*QueryTokenBalanceRequest)) + return srv.(QueryServer).Balance(ctx, req.(*QueryBalanceRequest)) } return interceptor(ctx, in, info, handler) } @@ -1076,8 +1076,8 @@ var _Query_serviceDesc = grpc.ServiceDesc{ HandlerType: (*QueryServer)(nil), Methods: []grpc.MethodDesc{ { - MethodName: "TokenBalance", - Handler: _Query_TokenBalance_Handler, + MethodName: "Balance", + Handler: _Query_Balance_Handler, }, { MethodName: "Supply", @@ -1108,7 +1108,7 @@ var _Query_serviceDesc = grpc.ServiceDesc{ Metadata: "lbm/token/v1/query.proto", } -func (m *QueryTokenBalanceRequest) Marshal() (dAtA []byte, err error) { +func (m *QueryBalanceRequest) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) n, err := m.MarshalToSizedBuffer(dAtA[:size]) @@ -1118,12 +1118,12 @@ func (m *QueryTokenBalanceRequest) Marshal() (dAtA []byte, err error) { return dAtA[:n], nil } -func (m *QueryTokenBalanceRequest) MarshalTo(dAtA []byte) (int, error) { +func (m *QueryBalanceRequest) MarshalTo(dAtA []byte) (int, error) { size := m.Size() return m.MarshalToSizedBuffer(dAtA[:size]) } -func (m *QueryTokenBalanceRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { +func (m *QueryBalanceRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { i := len(dAtA) _ = i var l int @@ -1145,7 +1145,7 @@ func (m *QueryTokenBalanceRequest) MarshalToSizedBuffer(dAtA []byte) (int, error return len(dAtA) - i, nil } -func (m *QueryTokenBalanceResponse) Marshal() (dAtA []byte, err error) { +func (m *QueryBalanceResponse) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) n, err := m.MarshalToSizedBuffer(dAtA[:size]) @@ -1155,12 +1155,12 @@ func (m *QueryTokenBalanceResponse) Marshal() (dAtA []byte, err error) { return dAtA[:n], nil } -func (m *QueryTokenBalanceResponse) MarshalTo(dAtA []byte) (int, error) { +func (m *QueryBalanceResponse) MarshalTo(dAtA []byte) (int, error) { size := m.Size() return m.MarshalToSizedBuffer(dAtA[:size]) } -func (m *QueryTokenBalanceResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { +func (m *QueryBalanceResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { i := len(dAtA) _ = i var l int @@ -1657,7 +1657,7 @@ func encodeVarintQuery(dAtA []byte, offset int, v uint64) int { dAtA[offset] = uint8(v) return base } -func (m *QueryTokenBalanceRequest) Size() (n int) { +func (m *QueryBalanceRequest) Size() (n int) { if m == nil { return 0 } @@ -1674,7 +1674,7 @@ func (m *QueryTokenBalanceRequest) Size() (n int) { return n } -func (m *QueryTokenBalanceResponse) Size() (n int) { +func (m *QueryBalanceResponse) Size() (n int) { if m == nil { return 0 } @@ -1881,7 +1881,7 @@ func sovQuery(x uint64) (n int) { func sozQuery(x uint64) (n int) { return sovQuery(uint64((x << 1) ^ uint64((int64(x) >> 63)))) } -func (m *QueryTokenBalanceRequest) Unmarshal(dAtA []byte) error { +func (m *QueryBalanceRequest) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -1904,10 +1904,10 @@ func (m *QueryTokenBalanceRequest) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: QueryTokenBalanceRequest: wiretype end group for non-group") + return fmt.Errorf("proto: QueryBalanceRequest: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: QueryTokenBalanceRequest: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: QueryBalanceRequest: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: @@ -1995,7 +1995,7 @@ func (m *QueryTokenBalanceRequest) Unmarshal(dAtA []byte) error { } return nil } -func (m *QueryTokenBalanceResponse) Unmarshal(dAtA []byte) error { +func (m *QueryBalanceResponse) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -2018,10 +2018,10 @@ func (m *QueryTokenBalanceResponse) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: QueryTokenBalanceResponse: wiretype end group for non-group") + return fmt.Errorf("proto: QueryBalanceResponse: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: QueryTokenBalanceResponse: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: QueryBalanceResponse: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: diff --git a/x/token/query.pb.gw.go b/x/token/query.pb.gw.go index e9b3ec2485..aa91396b7c 100644 --- a/x/token/query.pb.gw.go +++ b/x/token/query.pb.gw.go @@ -31,8 +31,8 @@ var _ = runtime.String var _ = utilities.NewDoubleArray var _ = descriptor.ForMessage -func request_Query_TokenBalance_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq QueryTokenBalanceRequest +func request_Query_Balance_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryBalanceRequest var metadata runtime.ServerMetadata var ( @@ -64,13 +64,13 @@ func request_Query_TokenBalance_0(ctx context.Context, marshaler runtime.Marshal return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "class_id", err) } - msg, err := client.TokenBalance(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + msg, err := client.Balance(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } -func local_request_Query_TokenBalance_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq QueryTokenBalanceRequest +func local_request_Query_Balance_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryBalanceRequest var metadata runtime.ServerMetadata var ( @@ -102,7 +102,7 @@ func local_request_Query_TokenBalance_0(ctx context.Context, marshaler runtime.M return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "class_id", err) } - msg, err := server.TokenBalance(ctx, &protoReq) + msg, err := server.Balance(ctx, &protoReq) return msg, metadata, err } @@ -543,7 +543,7 @@ func local_request_Query_Approves_0(ctx context.Context, marshaler runtime.Marsh // Note that using this registration option will cause many gRPC library features (such as grpc.SendHeader, etc) to stop working. Consider using RegisterQueryHandlerFromEndpoint instead. func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, server QueryServer) error { - mux.Handle("GET", pattern_Query_TokenBalance_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + mux.Handle("GET", pattern_Query_Balance_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) @@ -552,14 +552,14 @@ func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, serv runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } - resp, md, err := local_request_Query_TokenBalance_0(rctx, inboundMarshaler, server, req, pathParams) + resp, md, err := local_request_Query_Balance_0(rctx, inboundMarshaler, server, req, pathParams) ctx = runtime.NewServerMetadataContext(ctx, md) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } - forward_Query_TokenBalance_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + forward_Query_Balance_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) }) @@ -724,7 +724,7 @@ func RegisterQueryHandler(ctx context.Context, mux *runtime.ServeMux, conn *grpc // "QueryClient" to call the correct interceptors. func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, client QueryClient) error { - mux.Handle("GET", pattern_Query_TokenBalance_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + mux.Handle("GET", pattern_Query_Balance_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) @@ -733,14 +733,14 @@ func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, clie runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } - resp, md, err := request_Query_TokenBalance_0(rctx, inboundMarshaler, client, req, pathParams) + resp, md, err := request_Query_Balance_0(rctx, inboundMarshaler, client, req, pathParams) ctx = runtime.NewServerMetadataContext(ctx, md) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } - forward_Query_TokenBalance_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + forward_Query_Balance_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) }) @@ -868,23 +868,23 @@ func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, clie } var ( - pattern_Query_TokenBalance_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4, 1, 0, 4, 1, 5, 5}, []string{"lbm", "token", "v1", "balance", "address", "class_id"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_Query_Balance_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4, 1, 0, 4, 1, 5, 5}, []string{"lbm", "token", "v1", "balance", "address", "class_id"}, "", runtime.AssumeColonVerbOpt(false))) - pattern_Query_Supply_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4}, []string{"lbm", "token", "v1", "supply", "class_id"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_Query_Supply_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4}, []string{"lbm", "token", "v1", "supply", "class_id"}, "", runtime.AssumeColonVerbOpt(false))) - pattern_Query_Token_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4}, []string{"lbm", "token", "v1", "tokens", "class_id"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_Query_Token_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4}, []string{"lbm", "token", "v1", "tokens", "class_id"}, "", runtime.AssumeColonVerbOpt(false))) - pattern_Query_Tokens_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"lbm", "token", "v1", "tokens"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_Query_Tokens_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"lbm", "token", "v1", "tokens"}, "", runtime.AssumeColonVerbOpt(false))) - pattern_Query_Grants_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4, 1, 0, 4, 1, 5, 5}, []string{"lbm", "token", "v1", "grants", "grantee", "class_id"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_Query_Grants_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4, 1, 0, 4, 1, 5, 5}, []string{"lbm", "token", "v1", "grants", "grantee", "class_id"}, "", runtime.AssumeColonVerbOpt(false))) - pattern_Query_Approve_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4, 1, 0, 4, 1, 5, 5, 1, 0, 4, 1, 5, 6}, []string{"lbm", "token", "v1", "approve", "class_id", "proxy", "approver"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_Query_Approve_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4, 1, 0, 4, 1, 5, 5, 1, 0, 4, 1, 5, 6}, []string{"lbm", "token", "v1", "approve", "class_id", "proxy", "approver"}, "", runtime.AssumeColonVerbOpt(false))) - pattern_Query_Approves_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4, 1, 0, 4, 1, 5, 5}, []string{"lbm", "token", "v1", "approves", "class_id", "proxy"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_Query_Approves_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4, 1, 0, 4, 1, 5, 5}, []string{"lbm", "token", "v1", "approves", "class_id", "proxy"}, "", runtime.AssumeColonVerbOpt(false))) ) var ( - forward_Query_TokenBalance_0 = runtime.ForwardResponseMessage + forward_Query_Balance_0 = runtime.ForwardResponseMessage forward_Query_Supply_0 = runtime.ForwardResponseMessage diff --git a/x/upgrade/abci.go b/x/upgrade/abci.go index 45cb8231a4..128cf21bc2 100644 --- a/x/upgrade/abci.go +++ b/x/upgrade/abci.go @@ -10,8 +10,6 @@ import ( sdk "github.com/line/lbm-sdk/types" "github.com/line/lbm-sdk/x/upgrade/keeper" "github.com/line/lbm-sdk/x/upgrade/types" - - ibctmtypes "github.com/line/lbm-sdk/x/ibc/light-clients/99-ostracon/types" ) // BeginBlock will check if there is a scheduled plan and if it is ready to be executed. @@ -26,23 +24,26 @@ func BeginBlocker(k keeper.Keeper, ctx sdk.Context, _ abci.RequestBeginBlock) { defer telemetry.ModuleMeasureSince(types.ModuleName, time.Now(), telemetry.MetricKeyBeginBlocker) plan, found := k.GetUpgradePlan(ctx) + + if !k.DowngradeVerified() { + k.SetDowngradeVerified(true) + lastAppliedPlan, _ := k.GetLastCompletedUpgrade(ctx) + // This check will make sure that we are using a valid binary. + // It'll panic in these cases if there is no upgrade handler registered for the last applied upgrade. + // 1. If there is no scheduled upgrade. + // 2. If the plan is not ready. + // 3. If the plan is ready and skip upgrade height is set for current height. + if !found || !plan.ShouldExecute(ctx) || (plan.ShouldExecute(ctx) && k.IsSkipHeight(ctx.BlockHeight())) { + if lastAppliedPlan != "" && !k.HasHandler(lastAppliedPlan) { + panic(fmt.Sprintf("Wrong app version %d, upgrade handler is missing for %s upgrade plan", ctx.ConsensusParams().Version.AppVersion, lastAppliedPlan)) + } + } + } + if !found { return } - // Once we are at the last block this chain will commit, set the upgraded consensus state - // so that IBC clients can use the last NextValidatorsHash as a trusted kernel for verifying - // headers on the next version of the chain. - // Set the time to the last block time of the current chain. - // In order for a client to upgrade successfully, the first block of the new chain must be committed - // within the trusting period of the last block time on this chain. - if plan.IsIBCPlan() && ctx.BlockHeight() == plan.Height-1 { - upgradedConsState := &ibctmtypes.ConsensusState{ - Timestamp: ctx.BlockTime(), - NextValidatorsHash: ctx.BlockHeader().NextValidatorsHash, - } - k.SetUpgradedConsensusState(ctx, plan.Height, upgradedConsState) - } // To make sure clear upgrade is executed at the same block if plan.ShouldExecute(ctx) { // If skip upgrade has been set for current height, we clear the upgrade plan @@ -58,7 +59,7 @@ func BeginBlocker(k keeper.Keeper, ctx sdk.Context, _ abci.RequestBeginBlock) { if !k.HasHandler(plan.Name) { // Write the upgrade info to disk. The UpgradeStoreLoader uses this info to perform or skip // store migrations. - err := k.DumpUpgradeInfoToDisk(ctx.BlockHeight(), plan.Name) + err := k.DumpUpgradeInfoWithInfoToDisk(ctx.BlockHeight(), plan.Name, plan.Info) //nolint:staticcheck if err != nil { panic(fmt.Errorf("unable to write upgrade info to filesystem: %s", err.Error())) } diff --git a/x/upgrade/abci_test.go b/x/upgrade/abci_test.go index 6eb6845c05..3a4f14005c 100644 --- a/x/upgrade/abci_test.go +++ b/x/upgrade/abci_test.go @@ -3,17 +3,17 @@ package upgrade_test import ( "encoding/json" "errors" - "fmt" "io/ioutil" "os" "testing" "time" + "github.com/stretchr/testify/require" + abci "github.com/line/ostracon/abci/types" "github.com/line/ostracon/libs/log" ocproto "github.com/line/ostracon/proto/ostracon/types" "github.com/line/tm-db/v2/memdb" - "github.com/stretchr/testify/require" "github.com/line/lbm-sdk/simapp" storetypes "github.com/line/lbm-sdk/store/types" @@ -21,8 +21,6 @@ import ( sdkerrors "github.com/line/lbm-sdk/types/errors" "github.com/line/lbm-sdk/types/module" govtypes "github.com/line/lbm-sdk/x/gov/types" - clienttypes "github.com/line/lbm-sdk/x/ibc/core/02-client/types" - ibctmtypes "github.com/line/lbm-sdk/x/ibc/light-clients/99-ostracon/types" "github.com/line/lbm-sdk/x/upgrade" "github.com/line/lbm-sdk/x/upgrade/keeper" "github.com/line/lbm-sdk/x/upgrade/types" @@ -70,13 +68,6 @@ func TestRequireName(t *testing.T) { require.True(t, errors.Is(sdkerrors.ErrInvalidRequest, err), err) } -func TestRequireFutureTime(t *testing.T) { - s := setupTest(10, map[int64]bool{}) - err := s.handler(s.ctx, &types.SoftwareUpgradeProposal{Title: "prop", Plan: types.Plan{Name: "test", Time: s.ctx.BlockHeader().Time}}) - require.NotNil(t, err) - require.True(t, errors.Is(sdkerrors.ErrInvalidRequest, err), err) -} - func TestRequireFutureBlock(t *testing.T) { s := setupTest(10, map[int64]bool{}) err := s.handler(s.ctx, &types.SoftwareUpgradeProposal{Title: "prop", Plan: types.Plan{Name: "test", Height: s.ctx.BlockHeight()}}) @@ -84,22 +75,6 @@ func TestRequireFutureBlock(t *testing.T) { require.True(t, errors.Is(sdkerrors.ErrInvalidRequest, err), err) } -func TestCantSetBothTimeAndHeight(t *testing.T) { - s := setupTest(10, map[int64]bool{}) - err := s.handler(s.ctx, &types.SoftwareUpgradeProposal{Title: "prop", Plan: types.Plan{Name: "test", Time: time.Now(), Height: s.ctx.BlockHeight() + 1}}) - require.NotNil(t, err) - require.True(t, errors.Is(sdkerrors.ErrInvalidRequest, err), err) -} - -func TestDoTimeUpgrade(t *testing.T) { - s := setupTest(10, map[int64]bool{}) - t.Log("Verify can schedule an upgrade") - err := s.handler(s.ctx, &types.SoftwareUpgradeProposal{Title: "prop", Plan: types.Plan{Name: "test", Time: time.Now()}}) - require.Nil(t, err) - - VerifyDoUpgrade(t) -} - func TestDoHeightUpgrade(t *testing.T) { s := setupTest(10, map[int64]bool{}) t.Log("Verify can schedule an upgrade") @@ -120,61 +95,6 @@ func TestCanOverwriteScheduleUpgrade(t *testing.T) { VerifyDoUpgrade(t) } -func VerifyDoIBCLastBlock(t *testing.T) { - t.Log("Verify that chain committed to consensus state on the last height it will commit") - nextValsHash := []byte("nextValsHash") - newCtx := s.ctx.WithBlockHeader(ocproto.Header{ - Height: s.ctx.BlockHeight(), - NextValidatorsHash: nextValsHash, - }) - - req := abci.RequestBeginBlock{Header: newCtx.BlockHeader()} - s.module.BeginBlock(newCtx, req) - - // plan Height is at ctx.BlockHeight+1 - consState, err := s.keeper.GetUpgradedConsensusState(newCtx, s.ctx.BlockHeight()+1) - require.NoError(t, err) - require.Equal(t, &ibctmtypes.ConsensusState{Timestamp: newCtx.BlockTime(), NextValidatorsHash: nextValsHash}, consState) -} - -func VerifyDoIBCUpgrade(t *testing.T) { - t.Log("Verify that a panic happens at the upgrade time/height") - newCtx := s.ctx.WithBlockHeight(s.ctx.BlockHeight() + 1).WithBlockTime(time.Now()) - - // Check IBC state is set before upgrade using last height: s.ctx.BlockHeight() - cs, err := s.keeper.GetUpgradedClient(newCtx, s.ctx.BlockHeight()) - require.NoError(t, err, "could not retrieve upgraded client before upgrade plan is applied") - require.NotNil(t, cs, "IBC client is nil before upgrade") - - consState, err := s.keeper.GetUpgradedConsensusState(newCtx, s.ctx.BlockHeight()) - require.NoError(t, err, "could not retrieve upgraded consensus state before upgrade plan is applied") - require.NotNil(t, consState, "IBC consensus state is nil before upgrade") - - req := abci.RequestBeginBlock{Header: newCtx.BlockHeader()} - require.Panics(t, func() { - s.module.BeginBlock(newCtx, req) - }) - - t.Log("Verify that the upgrade can be successfully applied with a handler") - s.keeper.SetUpgradeHandler("test", func(ctx sdk.Context, plan types.Plan, vm module.VersionMap) (module.VersionMap, error) { - return vm, nil - }) - require.NotPanics(t, func() { - s.module.BeginBlock(newCtx, req) - }) - - VerifyCleared(t, newCtx) - - // Check IBC state is cleared after upgrade using last height: s.ctx.BlockHeight() - cs, err = s.keeper.GetUpgradedClient(newCtx, s.ctx.BlockHeight()) - require.Error(t, err, "retrieved upgraded client after upgrade plan is applied") - require.Nil(t, cs, "IBC client is not-nil after upgrade") - - consState, err = s.keeper.GetUpgradedConsensusState(newCtx, s.ctx.BlockHeight()) - require.Error(t, err, "retrieved upgraded consensus state after upgrade plan is applied") - require.Nil(t, consState, "IBC consensus state is not-nil after upgrade") -} - func VerifyDoUpgrade(t *testing.T) { t.Log("Verify that a panic happens at the upgrade time/height") newCtx := s.ctx.WithBlockHeight(s.ctx.BlockHeight() + 1).WithBlockTime(time.Now()) @@ -259,7 +179,7 @@ func VerifyCleared(t *testing.T, newCtx sdk.Context) { func TestCanClear(t *testing.T) { s := setupTest(10, map[int64]bool{}) t.Log("Verify upgrade is scheduled") - err := s.handler(s.ctx, &types.SoftwareUpgradeProposal{Title: "prop", Plan: types.Plan{Name: "test", Time: time.Now()}}) + err := s.handler(s.ctx, &types.SoftwareUpgradeProposal{Title: "prop", Plan: types.Plan{Name: "test", Height: s.ctx.BlockHeight() + 100}}) require.Nil(t, err) err = s.handler(s.ctx, &types.CancelSoftwareUpgradeProposal{Title: "cancel"}) @@ -270,11 +190,12 @@ func TestCanClear(t *testing.T) { func TestCantApplySameUpgradeTwice(t *testing.T) { s := setupTest(10, map[int64]bool{}) - err := s.handler(s.ctx, &types.SoftwareUpgradeProposal{Title: "prop", Plan: types.Plan{Name: "test", Time: time.Now()}}) + height := s.ctx.BlockHeader().Height + 1 + err := s.handler(s.ctx, &types.SoftwareUpgradeProposal{Title: "prop", Plan: types.Plan{Name: "test", Height: height}}) require.Nil(t, err) VerifyDoUpgrade(t) t.Log("Verify an executed upgrade \"test\" can't be rescheduled") - err = s.handler(s.ctx, &types.SoftwareUpgradeProposal{Title: "prop", Plan: types.Plan{Name: "test", Time: time.Now()}}) + err = s.handler(s.ctx, &types.SoftwareUpgradeProposal{Title: "prop", Plan: types.Plan{Name: "test", Height: height}}) require.NotNil(t, err) require.True(t, errors.Is(sdkerrors.ErrInvalidRequest, err), err) } @@ -289,27 +210,15 @@ func TestNoSpuriousUpgrades(t *testing.T) { } func TestPlanStringer(t *testing.T) { - clientState := &ibctmtypes.ClientState{ChainId: "gaiachain"} - cs, err := clienttypes.PackClientState(clientState) - require.NoError(t, err) - - ti, err := time.Parse(time.RFC3339, "2020-01-01T00:00:00Z") - require.Nil(t, err) - require.Equal(t, `Upgrade Plan - Name: test - Time: 2020-01-01T00:00:00Z - Info: . - Upgraded IBC Client: no upgraded client provided`, types.Plan{Name: "test", Time: ti}.String()) require.Equal(t, `Upgrade Plan Name: test Height: 100 - Info: . - Upgraded IBC Client: no upgraded client provided`, types.Plan{Name: "test", Height: 100}.String()) - require.Equal(t, fmt.Sprintf(`Upgrade Plan + Info: .`, types.Plan{Name: "test", Height: 100, Info: ""}.String()) + + require.Equal(t, `Upgrade Plan Name: test Height: 100 - Info: . - Upgraded IBC Client: %s`, clientState), types.Plan{Name: "test", Height: 100, UpgradedClientState: cs}.String()) + Info: .`, types.Plan{Name: "test", Height: 100, Info: ""}.String()) } func VerifyNotDone(t *testing.T, newCtx sdk.Context, name string) { @@ -476,27 +385,6 @@ func TestUpgradeWithoutSkip(t *testing.T) { VerifyDone(t, s.ctx, "test") } -func TestIBCUpgradeWithoutSkip(t *testing.T) { - s := setupTest(10, map[int64]bool{}) - cs, err := clienttypes.PackClientState(&ibctmtypes.ClientState{}) - require.NoError(t, err) - err = s.handler(s.ctx, &types.SoftwareUpgradeProposal{ - Title: "prop", - Plan: types.Plan{ - Name: "test", - Height: s.ctx.BlockHeight() + 1, - UpgradedClientState: cs, - }, - }) - require.Nil(t, err) - - t.Log("Verify if last height stores consensus state") - VerifyDoIBCLastBlock(t) - - VerifyDoUpgrade(t) - VerifyDone(t, s.ctx, "test") -} - func TestDumpUpgradeInfoToFile(t *testing.T) { s := setupTest(10, map[int64]bool{}) @@ -523,3 +411,70 @@ func TestDumpUpgradeInfoToFile(t *testing.T) { err = os.Remove(upgradeInfoFilePath) require.Nil(t, err) } + +// TODO: add testcase to for `no upgrade handler is present for last applied upgrade`. +func TestBinaryVersion(t *testing.T) { + var skipHeight int64 = 15 + s := setupTest(10, map[int64]bool{skipHeight: true}) + + testCases := []struct { + name string + preRun func() (sdk.Context, abci.RequestBeginBlock) + expectPanic bool + }{ + { + "test not panic: no scheduled upgrade or applied upgrade is present", + func() (sdk.Context, abci.RequestBeginBlock) { + req := abci.RequestBeginBlock{Header: s.ctx.BlockHeader()} + return s.ctx, req + }, + false, + }, + { + "test not panic: upgrade handler is present for last applied upgrade", + func() (sdk.Context, abci.RequestBeginBlock) { + s.keeper.SetUpgradeHandler("test0", func(_ sdk.Context, _ types.Plan, vm module.VersionMap) (module.VersionMap, error) { + return vm, nil + }) + + err := s.handler(s.ctx, &types.SoftwareUpgradeProposal{Title: "Upgrade test", Plan: types.Plan{Name: "test0", Height: s.ctx.BlockHeight() + 2}}) + require.Nil(t, err) + + newCtx := s.ctx.WithBlockHeight(12) + s.keeper.ApplyUpgrade(newCtx, types.Plan{ + Name: "test0", + Height: 12, + }) + + req := abci.RequestBeginBlock{Header: newCtx.BlockHeader()} + return newCtx, req + }, + false, + }, + { + "test panic: upgrade needed", + func() (sdk.Context, abci.RequestBeginBlock) { + err := s.handler(s.ctx, &types.SoftwareUpgradeProposal{Title: "Upgrade test", Plan: types.Plan{Name: "test2", Height: 13}}) + require.Nil(t, err) + + newCtx := s.ctx.WithBlockHeight(13) + req := abci.RequestBeginBlock{Header: newCtx.BlockHeader()} + return newCtx, req + }, + true, + }, + } + + for _, tc := range testCases { + ctx, req := tc.preRun() + if tc.expectPanic { + require.Panics(t, func() { + s.module.BeginBlock(ctx, req) + }) + } else { + require.NotPanics(t, func() { + s.module.BeginBlock(ctx, req) + }) + } + } +} diff --git a/x/upgrade/client/cli/query.go b/x/upgrade/client/cli/query.go index 18edd82a6b..35ae8f4cac 100644 --- a/x/upgrade/client/cli/query.go +++ b/x/upgrade/client/cli/query.go @@ -1,13 +1,13 @@ package cli import ( - "context" "fmt" "github.com/spf13/cobra" "github.com/line/lbm-sdk/client" "github.com/line/lbm-sdk/client/flags" + "github.com/line/lbm-sdk/types/errors" "github.com/line/lbm-sdk/x/upgrade/types" ) @@ -21,6 +21,7 @@ func GetQueryCmd() *cobra.Command { cmd.AddCommand( GetCurrentPlanCmd(), GetAppliedPlanCmd(), + GetModuleVersionsCmd(), ) return cmd @@ -41,7 +42,7 @@ func GetCurrentPlanCmd() *cobra.Command { queryClient := types.NewQueryClient(clientCtx) params := types.QueryCurrentPlanRequest{} - res, err := queryClient.CurrentPlan(context.Background(), ¶ms) + res, err := queryClient.CurrentPlan(cmd.Context(), ¶ms) if err != nil { return err } @@ -74,9 +75,9 @@ func GetAppliedPlanCmd() *cobra.Command { return err } queryClient := types.NewQueryClient(clientCtx) - + ctx := cmd.Context() params := types.QueryAppliedPlanRequest{Name: args[0]} - res, err := queryClient.AppliedPlan(context.Background(), ¶ms) + res, err := queryClient.AppliedPlan(ctx, ¶ms) if err != nil { return err } @@ -90,7 +91,7 @@ func GetAppliedPlanCmd() *cobra.Command { if err != nil { return err } - headers, err := node.BlockchainInfo(context.Background(), res.Height, res.Height) + headers, err := node.BlockchainInfo(ctx, res.Height, res.Height) if err != nil { return err } @@ -111,3 +112,45 @@ func GetAppliedPlanCmd() *cobra.Command { return cmd } + +// GetModuleVersionsCmd returns the module version list from state +func GetModuleVersionsCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "module_versions [optional module_name]", + Short: "get the list of module versions", + Long: "Gets a list of module names and their respective consensus versions.\n" + + "Following the command with a specific module name will return only\n" + + "that module's information.", + Args: cobra.MaximumNArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } + + queryClient := types.NewQueryClient(clientCtx) + var params types.QueryModuleVersionsRequest + + if len(args) == 1 { + params = types.QueryModuleVersionsRequest{ModuleName: args[0]} + } else { + params = types.QueryModuleVersionsRequest{} + } + + res, err := queryClient.ModuleVersions(cmd.Context(), ¶ms) + if err != nil { + return err + } + + if res.ModuleVersions == nil { + return errors.ErrNotFound + } + + return clientCtx.PrintProto(res) + }, + } + + flags.AddQueryFlagsToCmd(cmd) + + return cmd +} diff --git a/x/upgrade/client/cli/tx.go b/x/upgrade/client/cli/tx.go index 4e10ab4661..20fa17626b 100644 --- a/x/upgrade/client/cli/tx.go +++ b/x/upgrade/client/cli/tx.go @@ -69,10 +69,6 @@ func NewCmdSubmitUpgradeProposal() *cobra.Command { return err } - if err = msg.ValidateBasic(); err != nil { - return err - } - return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) }, } @@ -128,10 +124,6 @@ func NewCmdSubmitCancelUpgradeProposal() *cobra.Command { return err } - if err = msg.ValidateBasic(); err != nil { - return err - } - return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) }, } diff --git a/x/upgrade/client/rest/rest.go b/x/upgrade/client/rest/rest.go index 4e15eb1a07..3f16e33d43 100644 --- a/x/upgrade/client/rest/rest.go +++ b/x/upgrade/client/rest/rest.go @@ -3,9 +3,8 @@ package rest import ( "github.com/gorilla/mux" - "github.com/line/lbm-sdk/client/rest" - "github.com/line/lbm-sdk/client" + "github.com/line/lbm-sdk/client/rest" ) // RegisterRoutes registers REST routes for the upgrade module under the path specified by routeName. diff --git a/x/upgrade/client/testutil/cli_test.go b/x/upgrade/client/testutil/cli_test.go new file mode 100644 index 0000000000..5cc6f45f5f --- /dev/null +++ b/x/upgrade/client/testutil/cli_test.go @@ -0,0 +1,15 @@ +package testutil + +import ( + "testing" + + "github.com/stretchr/testify/suite" + + "github.com/line/lbm-sdk/testutil/network" +) + +func TestIntegrationTestSuite(t *testing.T) { + cfg := network.DefaultConfig() + cfg.NumValidators = 1 + suite.Run(t, NewIntegrationTestSuite(cfg)) +} diff --git a/x/upgrade/client/testutil/suite.go b/x/upgrade/client/testutil/suite.go new file mode 100644 index 0000000000..fe2a95f5dc --- /dev/null +++ b/x/upgrade/client/testutil/suite.go @@ -0,0 +1,115 @@ +package testutil + +import ( + "fmt" + + "github.com/stretchr/testify/suite" + + ocproto "github.com/line/ostracon/proto/ostracon/types" + + "github.com/line/lbm-sdk/simapp" + clitestutil "github.com/line/lbm-sdk/testutil/cli" + "github.com/line/lbm-sdk/testutil/network" + sdk "github.com/line/lbm-sdk/types" + "github.com/line/lbm-sdk/x/upgrade/client/cli" + "github.com/line/lbm-sdk/x/upgrade/types" +) + +func NewIntegrationTestSuite(cfg network.Config) *IntegrationTestSuite { + return &IntegrationTestSuite{cfg: cfg} +} + +type IntegrationTestSuite struct { + suite.Suite + + app *simapp.SimApp + cfg network.Config + network *network.Network + ctx sdk.Context +} + +func (s *IntegrationTestSuite) SetupSuite() { + s.T().Log("setting up integration test suite") + app := simapp.Setup(false) + s.app = app + s.ctx = app.BaseApp.NewContext(false, ocproto.Header{}) + + cfg := network.DefaultConfig() + cfg.NumValidators = 1 + + s.cfg = cfg + s.network = network.New(s.T(), cfg) +} + +func (s *IntegrationTestSuite) TearDownSuite() { + s.T().Log("tearing down integration test suite") + s.network.Cleanup() +} + +func (s *IntegrationTestSuite) TestModuleVersionsCLI() { + testCases := []struct { + msg string + req types.QueryModuleVersionsRequest + single bool + expPass bool + }{ + { + msg: "test full query", + req: types.QueryModuleVersionsRequest{ModuleName: ""}, + single: false, + expPass: true, + }, + { + msg: "test single module", + req: types.QueryModuleVersionsRequest{ModuleName: "bank"}, + single: true, + expPass: true, + }, + { + msg: "test non-existent module", + req: types.QueryModuleVersionsRequest{ModuleName: "abcdefg"}, + single: true, + expPass: false, + }, + } + + val := s.network.Validators[0] + clientCtx := val.ClientCtx + // avoid printing as yaml from CLI command + clientCtx.OutputFormat = "JSON" + + vm := s.app.UpgradeKeeper.GetModuleVersionMap(s.ctx) + mv := s.app.UpgradeKeeper.GetModuleVersions(s.ctx) + s.Require().NotEmpty(vm) + + for _, stc := range testCases { + tc := stc + s.Run(fmt.Sprintf("Case %s", tc.msg), func() { + expect := mv + if tc.expPass { + if tc.single { + expect = []*types.ModuleVersion{{Name: tc.req.ModuleName, Version: vm[tc.req.ModuleName]}} + } + // setup expected response + pm := types.QueryModuleVersionsResponse{ + ModuleVersions: expect, + } + jsonVM, _ := clientCtx.Codec.MarshalJSON(&pm) + expectedRes := string(jsonVM) + // append new line to match behaviour of PrintProto + expectedRes += "\n" + + // get actual module versions list response from cli + cmd := cli.GetModuleVersionsCmd() + outVM, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, []string{tc.req.ModuleName}) + s.Require().NoError(err) + + s.Require().Equal(expectedRes, outVM.String()) + } else { + cmd := cli.GetModuleVersionsCmd() + _, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, []string{tc.req.ModuleName}) + s.Require().Error(err) + } + }) + } +} diff --git a/x/upgrade/exported/exported.go b/x/upgrade/exported/exported.go new file mode 100644 index 0000000000..859f7fe1f0 --- /dev/null +++ b/x/upgrade/exported/exported.go @@ -0,0 +1,7 @@ +package exported + +// ProtocolVersionSetter defines the interface fulfilled by BaseApp +// which allows setting it's appVersion field. +type ProtocolVersionSetter interface { + SetProtocolVersion(uint64) +} diff --git a/x/upgrade/keeper/grpc_query.go b/x/upgrade/keeper/grpc_query.go index c2e75ddb13..5671ca563e 100644 --- a/x/upgrade/keeper/grpc_query.go +++ b/x/upgrade/keeper/grpc_query.go @@ -5,7 +5,6 @@ import ( sdk "github.com/line/lbm-sdk/types" "github.com/line/lbm-sdk/types/errors" - clienttypes "github.com/line/lbm-sdk/x/ibc/core/02-client/types" "github.com/line/lbm-sdk/x/upgrade/types" ) @@ -36,21 +35,17 @@ func (k Keeper) AppliedPlan(c context.Context, req *types.QueryAppliedPlanReques } // UpgradedConsensusState implements the Query/UpgradedConsensusState gRPC method +// nolint: staticcheck func (k Keeper) UpgradedConsensusState(c context.Context, req *types.QueryUpgradedConsensusStateRequest) (*types.QueryUpgradedConsensusStateResponse, error) { ctx := sdk.UnwrapSDKContext(c) - consState, err := k.GetUpgradedConsensusState(ctx, req.LastHeight) - if err != nil { - return nil, err - } - - cs, err := clienttypes.PackConsensusState(consState) - if err != nil { - return nil, err + consState, found := k.GetUpgradedConsensusState(ctx, req.LastHeight) + if !found { + return &types.QueryUpgradedConsensusStateResponse{}, nil } return &types.QueryUpgradedConsensusStateResponse{ - UpgradedConsensusState: cs, + UpgradedConsensusState: consState, }, nil } diff --git a/x/upgrade/keeper/keeper.go b/x/upgrade/keeper/keeper.go index a40d9a07b7..a76edf8701 100644 --- a/x/upgrade/keeper/keeper.go +++ b/x/upgrade/keeper/keeper.go @@ -3,6 +3,7 @@ package keeper import ( "encoding/binary" "encoding/json" + "fmt" "io/ioutil" "os" "path" @@ -18,8 +19,7 @@ import ( sdk "github.com/line/lbm-sdk/types" sdkerrors "github.com/line/lbm-sdk/types/errors" "github.com/line/lbm-sdk/types/module" - clienttypes "github.com/line/lbm-sdk/x/ibc/core/02-client/types" - ibcexported "github.com/line/lbm-sdk/x/ibc/core/exported" + xp "github.com/line/lbm-sdk/x/upgrade/exported" "github.com/line/lbm-sdk/x/upgrade/types" ) @@ -27,21 +27,29 @@ import ( const UpgradeInfoFileName string = "upgrade-info.json" type Keeper struct { - homePath string - skipUpgradeHeights map[int64]bool - storeKey sdk.StoreKey - cdc codec.BinaryMarshaler - upgradeHandlers map[string]types.UpgradeHandler + homePath string // root directory of app config + skipUpgradeHeights map[int64]bool // map of heights to skip for an upgrade + storeKey sdk.StoreKey // key to access x/upgrade store + cdc codec.BinaryCodec // App-wide binary codec + upgradeHandlers map[string]types.UpgradeHandler // map of plan name to upgrade handler + versionSetter xp.ProtocolVersionSetter // implements setting the protocol version field on BaseApp + downgradeVerified bool // tells if we've already sanity checked that this binary version isn't being used against an old state. } -// NewKeeper constructs an upgrade Keeper -func NewKeeper(skipUpgradeHeights map[int64]bool, storeKey sdk.StoreKey, cdc codec.BinaryMarshaler, homePath string) Keeper { +// NewKeeper constructs an upgrade Keeper which requires the following arguments: +// skipUpgradeHeights - map of heights to skip an upgrade +// storeKey - a store key with which to access upgrade's store +// cdc - the app-wide binary codec +// homePath - root directory of the application's config +// vs - the interface implemented by baseapp which allows setting baseapp's protocol version field +func NewKeeper(skipUpgradeHeights map[int64]bool, storeKey sdk.StoreKey, cdc codec.BinaryCodec, homePath string, vs xp.ProtocolVersionSetter) Keeper { return Keeper{ homePath: homePath, skipUpgradeHeights: skipUpgradeHeights, storeKey: storeKey, cdc: cdc, upgradeHandlers: map[string]types.UpgradeHandler{}, + versionSetter: vs, } } @@ -52,6 +60,28 @@ func (k Keeper) SetUpgradeHandler(name string, upgradeHandler types.UpgradeHandl k.upgradeHandlers[name] = upgradeHandler } +// setProtocolVersion sets the protocol version to state +func (k Keeper) setProtocolVersion(ctx sdk.Context, v uint64) { + store := ctx.KVStore(k.storeKey) + versionBytes := make([]byte, 8) + binary.BigEndian.PutUint64(versionBytes, v) + store.Set([]byte{types.ProtocolVersionByte}, versionBytes) +} + +// getProtocolVersion gets the protocol version from state +func (k Keeper) getProtocolVersion(ctx sdk.Context) uint64 { + store := ctx.KVStore(k.storeKey) + ok := store.Has([]byte{types.ProtocolVersionByte}) + if ok { + pvBytes := store.Get([]byte{types.ProtocolVersionByte}) + protocolVersion := binary.BigEndian.Uint64(pvBytes) + + return protocolVersion + } + // default value + return 0 +} + // SetModuleVersionMap saves a given version map to state func (k Keeper) SetModuleVersionMap(ctx sdk.Context, vm module.VersionMap) { if len(vm) > 0 { @@ -141,11 +171,7 @@ func (k Keeper) ScheduleUpgrade(ctx sdk.Context, plan types.Plan) error { return err } - if plan.Time.Unix() > 0 { - if !plan.Time.After(ctx.BlockHeader().Time) { - return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "upgrade cannot be scheduled in the past") - } - } else if plan.Height <= ctx.BlockHeight() { + if plan.Height <= ctx.BlockHeight() { return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "upgrade cannot be scheduled in the past") } @@ -156,84 +182,72 @@ func (k Keeper) ScheduleUpgrade(ctx sdk.Context, plan types.Plan) error { store := ctx.KVStore(k.storeKey) // clear any old IBC state stored by previous plan - oldPlan, exists := k.GetUpgradePlan(ctx) - if exists && oldPlan.IsIBCPlan() { - k.ClearIBCState(ctx, oldPlan.Height-1) + oldPlan, found := k.GetUpgradePlan(ctx) + if found { + k.ClearIBCState(ctx, oldPlan.Height) } - bz := k.cdc.MustMarshalBinaryBare(&plan) + bz := k.cdc.MustMarshal(&plan) store.Set(types.PlanKey(), bz) - if plan.IsIBCPlan() { - // Set UpgradedClientState in store - clientState, err := clienttypes.UnpackClientState(plan.UpgradedClientState) - if err != nil { - return sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "could not unpack clientstate: %v", err) - } - // sets the new upgraded client in last height committed on this chain is at plan.Height, - // since the chain will panic at plan.Height and new chain will resume at plan.Height - return k.SetUpgradedClient(ctx, plan.Height, clientState) - } return nil } // SetUpgradedClient sets the expected upgraded client for the next version of this chain at the last height the current chain will commit. -func (k Keeper) SetUpgradedClient(ctx sdk.Context, planHeight int64, cs ibcexported.ClientState) error { +func (k Keeper) SetUpgradedClient(ctx sdk.Context, planHeight int64, bz []byte) error { store := ctx.KVStore(k.storeKey) - - // zero out any custom fields before setting - cs = cs.ZeroCustomFields() - bz, err := clienttypes.MarshalClientState(k.cdc, cs) - if err != nil { - return sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "could not marshal clientstate: %v", err) - } - store.Set(types.UpgradedClientKey(planHeight), bz) return nil } // GetUpgradedClient gets the expected upgraded client for the next version of this chain -func (k Keeper) GetUpgradedClient(ctx sdk.Context, height int64) (ibcexported.ClientState, error) { +func (k Keeper) GetUpgradedClient(ctx sdk.Context, height int64) ([]byte, bool) { store := ctx.KVStore(k.storeKey) - bz := store.Get(types.UpgradedClientKey(height)) if len(bz) == 0 { - return nil, sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "upgraded client not found in store for height %d", height) + return nil, false } - clientState, err := clienttypes.UnmarshalClientState(k.cdc, bz) - if err != nil { - return nil, err - } - return clientState, nil + return bz, true } // SetUpgradedConsensusState set the expected upgraded consensus state for the next version of this chain // using the last height committed on this chain. -func (k Keeper) SetUpgradedConsensusState(ctx sdk.Context, planHeight int64, cs ibcexported.ConsensusState) error { +func (k Keeper) SetUpgradedConsensusState(ctx sdk.Context, planHeight int64, bz []byte) error { store := ctx.KVStore(k.storeKey) - bz, err := clienttypes.MarshalConsensusState(k.cdc, cs) - if err != nil { - return sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "could not marshal consensus state: %v", err) - } - store.Set(types.UpgradedConsStateKey(planHeight), bz) return nil } // GetUpgradedConsensusState set the expected upgraded consensus state for the next version of this chain -func (k Keeper) GetUpgradedConsensusState(ctx sdk.Context, lastHeight int64) (ibcexported.ConsensusState, error) { +func (k Keeper) GetUpgradedConsensusState(ctx sdk.Context, lastHeight int64) ([]byte, bool) { store := ctx.KVStore(k.storeKey) - bz := store.Get(types.UpgradedConsStateKey(lastHeight)) if len(bz) == 0 { - return nil, sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "upgraded consensus state not found in store for height: %d", lastHeight) + return nil, false } - consState, err := clienttypes.UnmarshalConsensusState(k.cdc, bz) - if err != nil { - return nil, err + + return bz, true +} + +// GetLastCompletedUpgrade returns the last applied upgrade name and height. +func (k Keeper) GetLastCompletedUpgrade(ctx sdk.Context) (string, int64) { + iter := sdk.KVStoreReversePrefixIterator(ctx.KVStore(k.storeKey), []byte{types.DoneByte}) + defer iter.Close() + if iter.Valid() { + return parseDoneKey(iter.Key()), int64(binary.BigEndian.Uint64(iter.Value())) } - return consState, nil + + return "", 0 +} + +// parseDoneKey - split upgrade name from the done key +func parseDoneKey(key []byte) string { + if len(key) < 2 { + panic(fmt.Sprintf("expected key of length at least %d, got %d", 2, len(key))) + } + + return string(key[1:]) } // GetDoneHeight returns the height at which the given upgrade was executed @@ -255,8 +269,14 @@ func (k Keeper) ClearIBCState(ctx sdk.Context, lastHeight int64) { store.Delete(types.UpgradedConsStateKey(lastHeight)) } -// ClearUpgradePlan clears any schedule upgrade +// ClearUpgradePlan clears any schedule upgrade and associated IBC states. func (k Keeper) ClearUpgradePlan(ctx sdk.Context) { + // clear IBC states everytime upgrade plan is removed + oldPlan, found := k.GetUpgradePlan(ctx) + if found { + k.ClearIBCState(ctx, oldPlan.Height) + } + store := ctx.KVStore(k.storeKey) store.Delete(types.PlanKey()) } @@ -275,7 +295,7 @@ func (k Keeper) GetUpgradePlan(ctx sdk.Context) (plan types.Plan, havePlan bool) return plan, false } - k.cdc.MustUnmarshalBinaryBare(bz, &plan) + k.cdc.MustUnmarshal(bz, &plan) return plan, true } @@ -307,11 +327,17 @@ func (k Keeper) ApplyUpgrade(ctx sdk.Context, plan types.Plan) { k.SetModuleVersionMap(ctx, updatedVM) + // incremement the protocol version and set it in state and baseapp + nextProtocolVersion := k.getProtocolVersion(ctx) + 1 + k.setProtocolVersion(ctx, nextProtocolVersion) + if k.versionSetter != nil { + // set protocol version on BaseApp + k.versionSetter.SetProtocolVersion(nextProtocolVersion) + } + // Must clear IBC state after upgrade is applied as it is stored separately from the upgrade plan. // This will prevent resubmission of upgrade msg after upgrade is already completed. - if plan.IsIBCPlan() { - k.ClearIBCState(ctx, plan.Height-1) - } + k.ClearIBCState(ctx, plan.Height) k.ClearUpgradePlan(ctx) k.setDone(ctx, plan.Name) } @@ -321,23 +347,35 @@ func (k Keeper) IsSkipHeight(height int64) bool { return k.skipUpgradeHeights[height] } -// DumpUpgradeInfoToDisk writes upgrade information to UpgradeInfoFileName. +// DumpUpgradeInfoToDisk writes upgrade information to UpgradeInfoFileName. The function +// doesn't save the `Plan.Info` data, hence it won't support auto download functionality +// by cosmvisor. +// NOTE: this function will be update in the next release. func (k Keeper) DumpUpgradeInfoToDisk(height int64, name string) error { + return k.DumpUpgradeInfoWithInfoToDisk(height, name, "") +} + +// Deprecated: DumpUpgradeInfoWithInfoToDisk writes upgrade information to UpgradeInfoFileName. +// `info` should be provided and contain Plan.Info data in order to support +// auto download functionality by cosmovisor and other tools using upgarde-info.json +// (GetUpgradeInfoPath()) file. +func (k Keeper) DumpUpgradeInfoWithInfoToDisk(height int64, name string, info string) error { upgradeInfoFilePath, err := k.GetUpgradeInfoPath() if err != nil { return err } - upgradeInfo := store.UpgradeInfo{ + upgradeInfo := upgradeInfo{ Name: name, Height: height, + Info: info, } - info, err := json.Marshal(upgradeInfo) + bz, err := json.Marshal(upgradeInfo) if err != nil { return err } - return ioutil.WriteFile(upgradeInfoFilePath, info, 0600) + return ioutil.WriteFile(upgradeInfoFilePath, bz, 0600) } // GetUpgradeInfoPath returns the upgrade info file path @@ -384,3 +422,23 @@ func (k Keeper) ReadUpgradeInfoFromDisk() (store.UpgradeInfo, error) { return upgradeInfo, nil } + +// upgradeInfo is stripped types.Plan structure used to dump upgrade plan data. +type upgradeInfo struct { + // Name has types.Plan.Name value + Name string `json:"name,omitempty"` + // Height has types.Plan.Height value + Height int64 `json:"height,omitempty"` + // Height has types.Plan.Height value + Info string `json:"info,omitempty"` +} + +// SetDowngradeVerified updates downgradeVerified. +func (k *Keeper) SetDowngradeVerified(v bool) { + k.downgradeVerified = v +} + +// DowngradeVerified returns downgradeVerified. +func (k Keeper) DowngradeVerified() bool { + return k.downgradeVerified +} diff --git a/x/upgrade/keeper/keeper_test.go b/x/upgrade/keeper/keeper_test.go index ae5bbf6f64..04a30a9317 100644 --- a/x/upgrade/keeper/keeper_test.go +++ b/x/upgrade/keeper/keeper_test.go @@ -12,10 +12,6 @@ import ( store "github.com/line/lbm-sdk/store/types" sdk "github.com/line/lbm-sdk/types" "github.com/line/lbm-sdk/types/module" - clienttypes "github.com/line/lbm-sdk/x/ibc/core/02-client/types" - commitmenttypes "github.com/line/lbm-sdk/x/ibc/core/23-commitment/types" - ibcexported "github.com/line/lbm-sdk/x/ibc/core/exported" - ibctmtypes "github.com/line/lbm-sdk/x/ibc/light-clients/99-ostracon/types" "github.com/line/lbm-sdk/x/upgrade/keeper" "github.com/line/lbm-sdk/x/upgrade/types" ) @@ -32,7 +28,7 @@ func (s *KeeperTestSuite) SetupTest() { app := simapp.Setup(false) homeDir := filepath.Join(s.T().TempDir(), "x_upgrade_keeper_test") app.UpgradeKeeper = keeper.NewKeeper( // recreate keeper in order to use a custom home path - make(map[int64]bool), app.GetKey(types.StoreKey), app.AppCodec(), homeDir, + make(map[int64]bool), app.GetKey(types.StoreKey), app.AppCodec(), homeDir, app.BaseApp, ) s.T().Log("home dir:", homeDir) s.homeDir = homeDir @@ -62,34 +58,12 @@ func (s *KeeperTestSuite) TestReadUpgradeInfoFromDisk() { } func (s *KeeperTestSuite) TestScheduleUpgrade() { - clientState := &ibctmtypes.ClientState{ChainId: "gaiachain"} - cs, err := clienttypes.PackClientState(clientState) - s.Require().NoError(err) - - altClientState := &ibctmtypes.ClientState{ChainId: "ethermint"} - altCs, err := clienttypes.PackClientState(altClientState) - s.Require().NoError(err) - - consState := ibctmtypes.NewConsensusState(time.Now(), commitmenttypes.NewMerkleRoot([]byte("app_hash")), []byte("next_vals_hash")) - consAny, err := clienttypes.PackConsensusState(consState) - s.Require().NoError(err) - cases := []struct { name string plan types.Plan setup func() expPass bool }{ - { - name: "successful time schedule", - plan: types.Plan{ - Name: "all-good", - Info: "some text here", - Time: s.ctx.BlockTime().Add(time.Hour), - }, - setup: func() {}, - expPass: true, - }, { name: "successful height schedule", plan: types.Plan{ @@ -100,17 +74,6 @@ func (s *KeeperTestSuite) TestScheduleUpgrade() { setup: func() {}, expPass: true, }, - { - name: "successful ibc schedule", - plan: types.Plan{ - Name: "all-good", - Info: "some text here", - Height: 123450000, - UpgradedClientState: cs, - }, - setup: func() {}, - expPass: true, - }, { name: "successful overwrite", plan: types.Plan{ @@ -127,41 +90,6 @@ func (s *KeeperTestSuite) TestScheduleUpgrade() { }, expPass: true, }, - { - name: "successful IBC overwrite", - plan: types.Plan{ - Name: "all-good", - Info: "some text here", - Height: 123450000, - UpgradedClientState: cs, - }, - setup: func() { - s.app.UpgradeKeeper.ScheduleUpgrade(s.ctx, types.Plan{ - Name: "alt-good", - Info: "new text here", - Height: 543210000, - UpgradedClientState: altCs, - }) - }, - expPass: true, - }, - { - name: "successful IBC overwrite with non IBC plan", - plan: types.Plan{ - Name: "all-good", - Info: "some text here", - Height: 123450000, - }, - setup: func() { - s.app.UpgradeKeeper.ScheduleUpgrade(s.ctx, types.Plan{ - Name: "alt-good", - Info: "new text here", - Height: 543210000, - UpgradedClientState: altCs, - }) - }, - expPass: true, - }, { name: "unsuccessful schedule: invalid plan", plan: types.Plan{ @@ -209,17 +137,6 @@ func (s *KeeperTestSuite) TestScheduleUpgrade() { }, expPass: false, }, - { - name: "unsuccessful IBC schedule: UpgradedClientState is not valid client state", - plan: types.Plan{ - Name: "all-good", - Info: "some text here", - Height: 123450000, - UpgradedClientState: consAny, - }, - setup: func() {}, - expPass: false, - }, } for _, tc := range cases { @@ -236,16 +153,6 @@ func (s *KeeperTestSuite) TestScheduleUpgrade() { if tc.expPass { s.Require().NoError(err, "valid test case failed") - if tc.plan.UpgradedClientState != nil { - got, err := s.app.UpgradeKeeper.GetUpgradedClient(s.ctx, tc.plan.Height) - s.Require().NoError(err) - s.Require().Equal(clientState, got, "upgradedClient not equal to expected value") - } else { - // check that upgraded client is empty if latest plan does not specify an upgraded client - got, err := s.app.UpgradeKeeper.GetUpgradedClient(s.ctx, tc.plan.Height) - s.Require().Error(err) - s.Require().Nil(got) - } } else { s.Require().Error(err, "invalid test case passed") } @@ -254,9 +161,8 @@ func (s *KeeperTestSuite) TestScheduleUpgrade() { } func (s *KeeperTestSuite) TestSetUpgradedClient() { - var ( - clientState ibcexported.ClientState - ) + cs := []byte("IBC client state") + cases := []struct { name string height int64 @@ -273,8 +179,7 @@ func (s *KeeperTestSuite) TestSetUpgradedClient() { name: "success", height: 10, setup: func() { - clientState = &ibctmtypes.ClientState{ChainId: "gaiachain"} - s.app.UpgradeKeeper.SetUpgradedClient(s.ctx, 10, clientState) + s.app.UpgradeKeeper.SetUpgradedClient(s.ctx, 10, cs) }, exists: true, }, @@ -287,18 +192,34 @@ func (s *KeeperTestSuite) TestSetUpgradedClient() { // setup test case tc.setup() - gotCs, err := s.app.UpgradeKeeper.GetUpgradedClient(s.ctx, tc.height) + gotCs, exists := s.app.UpgradeKeeper.GetUpgradedClient(s.ctx, tc.height) if tc.exists { - s.Require().Equal(clientState, gotCs, "valid case: %s did not retrieve correct client state", tc.name) - s.Require().NoError(err, "valid case: %s returned error") + s.Require().Equal(cs, gotCs, "valid case: %s did not retrieve correct client state", tc.name) + s.Require().True(exists, "valid case: %s did not retrieve client state", tc.name) } else { s.Require().Nil(gotCs, "invalid case: %s retrieved valid client state", tc.name) - s.Require().Error(err, "invalid case: %s did not return error", tc.name) + s.Require().False(exists, "invalid case: %s retrieved valid client state", tc.name) } } } +// Test that the protocol version successfully increments after an +// upgrade and is successfully set on BaseApp's appVersion. +func (s *KeeperTestSuite) TestIncrementProtocolVersion() { + oldProtocolVersion := s.app.BaseApp.AppVersion() + s.app.UpgradeKeeper.SetUpgradeHandler("dummy", func(_ sdk.Context, _ types.Plan, vm module.VersionMap) (module.VersionMap, error) { return vm, nil }) + dummyPlan := types.Plan{ + Name: "dummy", + Info: "some text here", + Height: 100, + } + s.app.UpgradeKeeper.ApplyUpgrade(s.ctx, dummyPlan) + upgradedProtocolVersion := s.app.BaseApp.AppVersion() + + s.Require().Equal(oldProtocolVersion+1, upgradedProtocolVersion) +} + // Tests that the underlying state of x/upgrade is set correctly after // an upgrade. func (s *KeeperTestSuite) TestMigrations() { @@ -321,6 +242,45 @@ func (s *KeeperTestSuite) TestMigrations() { s.Require().Equal(vmBefore["bank"]+1, vm["bank"]) } +func (s *KeeperTestSuite) TestLastCompletedUpgrade() { + keeper := s.app.UpgradeKeeper + require := s.Require() + + s.T().Log("verify empty name if applied upgrades are empty") + name, height := keeper.GetLastCompletedUpgrade(s.ctx) + require.Equal("", name) + require.Equal(int64(0), height) + + keeper.SetUpgradeHandler("test0", func(_ sdk.Context, _ types.Plan, vm module.VersionMap) (module.VersionMap, error) { + return vm, nil + }) + + keeper.ApplyUpgrade(s.ctx, types.Plan{ + Name: "test0", + Height: 10, + }) + + s.T().Log("verify valid upgrade name and height") + name, height = keeper.GetLastCompletedUpgrade(s.ctx) + require.Equal("test0", name) + require.Equal(int64(10), height) + + keeper.SetUpgradeHandler("test1", func(_ sdk.Context, _ types.Plan, vm module.VersionMap) (module.VersionMap, error) { + return vm, nil + }) + + newCtx := s.ctx.WithBlockHeight(15) + keeper.ApplyUpgrade(newCtx, types.Plan{ + Name: "test1", + Height: 15, + }) + + s.T().Log("verify valid upgrade name and height with multiple upgrades") + name, height = keeper.GetLastCompletedUpgrade(newCtx) + require.Equal("test1", name) + require.Equal(int64(15), height) +} + func TestKeeperTestSuite(t *testing.T) { suite.Run(t, new(KeeperTestSuite)) } diff --git a/x/upgrade/module.go b/x/upgrade/module.go index a8a988df37..77ef989e30 100644 --- a/x/upgrade/module.go +++ b/x/upgrade/module.go @@ -106,22 +106,22 @@ func (am AppModule) RegisterServices(cfg module.Configurator) { } // InitGenesis is ignored, no sense in serializing future upgrades -func (am AppModule) InitGenesis(_ sdk.Context, _ codec.JSONMarshaler, _ json.RawMessage) []abci.ValidatorUpdate { +func (am AppModule) InitGenesis(_ sdk.Context, _ codec.JSONCodec, _ json.RawMessage) []abci.ValidatorUpdate { return []abci.ValidatorUpdate{} } // DefaultGenesis is an empty object -func (AppModuleBasic) DefaultGenesis(_ codec.JSONMarshaler) json.RawMessage { +func (AppModuleBasic) DefaultGenesis(_ codec.JSONCodec) json.RawMessage { return []byte("{}") } // ValidateGenesis is always successful, as we ignore the value -func (AppModuleBasic) ValidateGenesis(_ codec.JSONMarshaler, config client.TxEncodingConfig, _ json.RawMessage) error { +func (AppModuleBasic) ValidateGenesis(_ codec.JSONCodec, config client.TxEncodingConfig, _ json.RawMessage) error { return nil } // ExportGenesis is always empty, as InitGenesis does nothing either -func (am AppModule) ExportGenesis(_ sdk.Context, cdc codec.JSONMarshaler) json.RawMessage { +func (am AppModule) ExportGenesis(_ sdk.Context, cdc codec.JSONCodec) json.RawMessage { return am.DefaultGenesis(cdc) } diff --git a/x/upgrade/spec/01_concepts.md b/x/upgrade/spec/01_concepts.md index a565b95ad5..796fe39f99 100644 --- a/x/upgrade/spec/01_concepts.md +++ b/x/upgrade/spec/01_concepts.md @@ -58,10 +58,9 @@ or if the binary was upgraded too early, the node will gracefully panic and exit ## StoreLoader - The `x/upgrade` module also facilitates store migrations as part of the upgrade. The -`StoreLoader` sets the migrations that need to occur before the new binary can -successfully run the chain. This `StoreLoader` is also application specific and +`StoreLoader` sets the migrations that need to occur before the new binary can +successfully run the chain. This `StoreLoader` is also application specific and not defined on a per-module basis. Registering this `StoreLoader` is done via `app#SetStoreLoader` in the application. diff --git a/x/upgrade/spec/02_state.md b/x/upgrade/spec/02_state.md index f069b4f967..73c64ad2dd 100644 --- a/x/upgrade/spec/02_state.md +++ b/x/upgrade/spec/02_state.md @@ -5,7 +5,16 @@ order: 2 # State The internal state of the `x/upgrade` module is relatively minimal and simple. The -state only contains the currently active upgrade `Plan` (if one exists) by key -`0x0` and if a `Plan` is marked as "done" by key `0x1`. +state contains the currently active upgrade `Plan` (if one exists) by key +`0x0` and if a `Plan` is marked as "done" by key `0x1`. The state +contains the consensus versions of all app modules in the application. The versions +are stored as big endian `uint64`, and can be accessed with prefix `0x2` appended +by the corresponding module name of type `string`. The state maintains a +`Protocol Version` which can be accessed by key `0x3`. + +- Plan: `0x0 -> Plan` +- Done: `0x1 | byte(plan name) -> BigEndian(Block Height)` +- ConsensusVersion: `0x2 | byte(module name) -> BigEndian(Module Consensus Version)` +- ProtocolVersion: `0x3 -> BigEndian(Protocol Version)` The `x/upgrade` module contains no genesis state. diff --git a/x/upgrade/spec/04_client.md b/x/upgrade/spec/04_client.md new file mode 100644 index 0000000000..da55709ee7 --- /dev/null +++ b/x/upgrade/spec/04_client.md @@ -0,0 +1,459 @@ + + +# Client + +## CLI + +A user can query and interact with the `upgrade` module using the CLI. + +### Query + +The `query` commands allow users to query `upgrade` state. + +```bash +simd query upgrade --help +``` + +#### applied + +The `applied` command allows users to query the block header for height at which a completed upgrade was applied. + +```bash +simd query upgrade applied [upgrade-name] [flags] +``` + +If upgrade-name was previously executed on the chain, this returns the header for the block at which it was applied. +This helps a client determine which binary was valid over a given range of blocks, as well as more context to understand past migrations. + +Example: + +```bash +simd query upgrade applied "test-upgrade" +``` + +Example Output: + +```bash +"block_id": { + "hash": "A769136351786B9034A5F196DC53F7E50FCEB53B48FA0786E1BFC45A0BB646B5", + "parts": { + "total": 1, + "hash": "B13CBD23011C7480E6F11BE4594EE316548648E6A666B3575409F8F16EC6939E" + } + }, + "block_size": "7213", + "header": { + "version": { + "block": "11" + }, + "chain_id": "testnet-2", + "height": "455200", + "time": "2021-04-10T04:37:57.085493838Z", + "last_block_id": { + "hash": "0E8AD9309C2DC411DF98217AF59E044A0E1CCEAE7C0338417A70338DF50F4783", + "parts": { + "total": 1, + "hash": "8FE572A48CD10BC2CBB02653CA04CA247A0F6830FF19DC972F64D339A355E77D" + } + }, + "last_commit_hash": "DE890239416A19E6164C2076B837CC1D7F7822FC214F305616725F11D2533140", + "data_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "validators_hash": "A31047ADE54AE9072EE2A12FF260A8990BA4C39F903EAF5636B50D58DBA72582", + "next_validators_hash": "A31047ADE54AE9072EE2A12FF260A8990BA4C39F903EAF5636B50D58DBA72582", + "consensus_hash": "048091BC7DDC283F77BFBF91D73C44DA58C3DF8A9CBC867405D8B7F3DAADA22F", + "app_hash": "28ECC486AFC332BA6CC976706DBDE87E7D32441375E3F10FD084CD4BAF0DA021", + "last_results_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "evidence_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "proposer_address": "2ABC4854B1A1C5AA8403C4EA853A81ACA901CC76" + }, + "num_txs": "0" +} +``` + +#### module versions + +The `module_versions` command gets a list of module names and their respective consensus versions. + +Following the command with a specific module name will return only +that module's information. + +```bash +simd query upgrade module_versions [optional module_name] [flags] +``` + +Example: + +```bash +simd query upgrade module_versions +``` + +Example Output: + +```bash +module_versions: +- name: auth + version: "2" +- name: authz + version: "1" +- name: bank + version: "2" +- name: capability + version: "1" +- name: crisis + version: "1" +- name: distribution + version: "2" +- name: evidence + version: "1" +- name: feegrant + version: "1" +- name: genutil + version: "1" +- name: gov + version: "2" +- name: ibc + version: "2" +- name: mint + version: "1" +- name: params + version: "1" +- name: slashing + version: "2" +- name: staking + version: "2" +- name: transfer + version: "1" +- name: upgrade + version: "1" +- name: vesting + version: "1" +``` + +Example: + +```bash +regen query upgrade module_versions ibc +``` + +Example Output: + +```bash +module_versions: +- name: ibc + version: "2" +``` + +#### plan + +The `plan` command gets the currently scheduled upgrade plan, if one exists. + +```bash +regen query upgrade plan [flags] +``` + +Example: + +```bash +simd query upgrade plan +``` + +Example Output: + +```bash +height: "130" +info: "" +name: test-upgrade +time: "0001-01-01T00:00:00Z" +upgraded_client_state: null +``` + +## REST + +A user can query the `upgrade` module using REST endpoints. + +### Applied Plan + +`AppliedPlan` queries a previously applied upgrade plan by its name. + +```bash +/cosmos/upgrade/v1beta1/applied_plan/{name} +``` + +Example: + +```bash +curl -X GET "http://localhost:1317/cosmos/upgrade/v1beta1/applied_plan/v2.0-upgrade" -H "accept: application/json" +``` + +Example Output: + +```bash +{ + "height": "30" +} +``` + +### Current Plan + +`CurrentPlan` queries the current upgrade plan. + +```bash +/cosmos/upgrade/v1beta1/current_plan +``` + +Example: + +```bash +curl -X GET "http://localhost:1317/cosmos/upgrade/v1beta1/current_plan" -H "accept: application/json" +``` + +Example Output: + +```bash +{ + "plan": "v2.1-upgrade" +} +``` + +### Module versions + +`ModuleVersions` queries the list of module versions from state. + +```bash +/cosmos/upgrade/v1beta1/module_versions +``` + +Example: + +```bash +curl -X GET "http://localhost:1317/cosmos/upgrade/v1beta1/module_versions" -H "accept: application/json" +``` + +Example Output: + +```bash +{ + "module_versions": [ + { + "name": "auth", + "version": "2" + }, + { + "name": "authz", + "version": "1" + }, + { + "name": "bank", + "version": "2" + }, + { + "name": "capability", + "version": "1" + }, + { + "name": "crisis", + "version": "1" + }, + { + "name": "distribution", + "version": "2" + }, + { + "name": "evidence", + "version": "1" + }, + { + "name": "feegrant", + "version": "1" + }, + { + "name": "genutil", + "version": "1" + }, + { + "name": "gov", + "version": "2" + }, + { + "name": "ibc", + "version": "2" + }, + { + "name": "mint", + "version": "1" + }, + { + "name": "params", + "version": "1" + }, + { + "name": "slashing", + "version": "2" + }, + { + "name": "staking", + "version": "2" + }, + { + "name": "transfer", + "version": "1" + }, + { + "name": "upgrade", + "version": "1" + }, + { + "name": "vesting", + "version": "1" + } + ] +} +``` + +## gRPC + +A user can query the `upgrade` module using gRPC endpoints. + +### Applied Plan + +`AppliedPlan` queries a previously applied upgrade plan by its name. + +```bash +cosmos.upgrade.v1beta1.Query/AppliedPlan +``` + +Example: + +```bash +grpcurl -plaintext \ + -d '{"name":"v2.0-upgrade"}' \ + localhost:9090 \ + cosmos.upgrade.v1beta1.Query/AppliedPlan +``` + +Example Output: + +```bash +{ + "height": "30" +} +``` + +### Current Plan + +`CurrentPlan` queries the current upgrade plan. + +```bash +cosmos.upgrade.v1beta1.Query/CurrentPlan +``` + +Example: + +```bash +grpcurl -plaintext localhost:9090 cosmos.slashing.v1beta1.Query/CurrentPlan +``` + +Example Output: + +```bash +{ + "plan": "v2.1-upgrade" +} +``` + +### Module versions + +`ModuleVersions` queries the list of module versions from state. + +```bash +cosmos.upgrade.v1beta1.Query/ModuleVersions +``` + +Example: + +```bash +grpcurl -plaintext localhost:9090 cosmos.slashing.v1beta1.Query/ModuleVersions +``` + +Example Output: + +```bash +{ + "module_versions": [ + { + "name": "auth", + "version": "2" + }, + { + "name": "authz", + "version": "1" + }, + { + "name": "bank", + "version": "2" + }, + { + "name": "capability", + "version": "1" + }, + { + "name": "crisis", + "version": "1" + }, + { + "name": "distribution", + "version": "2" + }, + { + "name": "evidence", + "version": "1" + }, + { + "name": "feegrant", + "version": "1" + }, + { + "name": "genutil", + "version": "1" + }, + { + "name": "gov", + "version": "2" + }, + { + "name": "ibc", + "version": "2" + }, + { + "name": "mint", + "version": "1" + }, + { + "name": "params", + "version": "1" + }, + { + "name": "slashing", + "version": "2" + }, + { + "name": "staking", + "version": "2" + }, + { + "name": "transfer", + "version": "1" + }, + { + "name": "upgrade", + "version": "1" + }, + { + "name": "vesting", + "version": "1" + } + ] +} +``` diff --git a/x/upgrade/types/keys.go b/x/upgrade/types/keys.go index 2505bd5ce4..45128fc704 100644 --- a/x/upgrade/types/keys.go +++ b/x/upgrade/types/keys.go @@ -25,6 +25,9 @@ const ( // VersionMapByte is a prefix to look up module names (key) and versions (value) VersionMapByte = 0x2 + // ProtocolVersionByte is a prefix to look up Protocol Version + ProtocolVersionByte = 0x3 + // KeyUpgradedIBCState is the key under which upgraded ibc state is stored in the upgrade store KeyUpgradedIBCState = "upgradedIBCState" diff --git a/x/upgrade/types/plan.go b/x/upgrade/types/plan.go index 6e7dba2517..9892efb7d1 100644 --- a/x/upgrade/types/plan.go +++ b/x/upgrade/types/plan.go @@ -3,36 +3,28 @@ package types import ( "fmt" "strings" - "time" - codectypes "github.com/line/lbm-sdk/codec/types" sdk "github.com/line/lbm-sdk/types" sdkerrors "github.com/line/lbm-sdk/types/errors" - clienttypes "github.com/line/lbm-sdk/x/ibc/core/02-client/types" - ibcexported "github.com/line/lbm-sdk/x/ibc/core/exported" ) -var _ codectypes.UnpackInterfacesMessage = Plan{} - func (p Plan) String() string { due := p.DueAt() dueUp := strings.ToUpper(due[0:1]) + due[1:] - var upgradedClientStr string - upgradedClient, err := clienttypes.UnpackClientState(p.UpgradedClientState) - if err != nil { - upgradedClientStr = "no upgraded client provided" - } else { - upgradedClientStr = upgradedClient.String() - } return fmt.Sprintf(`Upgrade Plan Name: %s %s - Info: %s. - Upgraded IBC Client: %s`, p.Name, dueUp, p.Info, upgradedClientStr) + Info: %s.`, p.Name, dueUp, p.Info) } // ValidateBasic does basic validation of a Plan func (p Plan) ValidateBasic() error { + if !p.Time.IsZero() { + return sdkerrors.ErrInvalidRequest.Wrap("time-based upgrades have been deprecated in the SDK") + } + if p.UpgradedClientState != nil { + return sdkerrors.ErrInvalidRequest.Wrap("upgrade logic for IBC has been moved to the IBC module") + } if len(p.Name) == 0 { return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "name cannot be empty") } @@ -45,9 +37,6 @@ func (p Plan) ValidateBasic() error { if p.Time.Unix() > 0 && p.Height != 0 { return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "cannot set both time and height") } - if p.Time.Unix() > 0 && p.UpgradedClientState != nil { - return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "IBC chain upgrades must only set height") - } return nil } @@ -65,24 +54,5 @@ func (p Plan) ShouldExecute(ctx sdk.Context) bool { // DueAt is a string representation of when this plan is due to be executed func (p Plan) DueAt() string { - if p.Time.Unix() > 0 { - return fmt.Sprintf("time: %s", p.Time.UTC().Format(time.RFC3339)) - } return fmt.Sprintf("height: %d", p.Height) } - -// IsIBCPlan will return true if plan includes IBC client information -func (p Plan) IsIBCPlan() bool { - return p.UpgradedClientState != nil -} - -// UnpackInterfaces implements UnpackInterfacesMessage.UnpackInterfaces -func (p Plan) UnpackInterfaces(unpacker codectypes.AnyUnpacker) error { - // UpgradedClientState may be nil - if p.UpgradedClientState == nil { - return nil - } - - var clientState ibcexported.ClientState - return unpacker.UnpackAny(p.UpgradedClientState, &clientState) -} diff --git a/x/upgrade/types/plan_test.go b/x/upgrade/types/plan_test.go index 3cf85ec695..963b6ff518 100644 --- a/x/upgrade/types/plan_test.go +++ b/x/upgrade/types/plan_test.go @@ -1,20 +1,18 @@ package types_test import ( - "fmt" "testing" "time" - "github.com/line/ostracon/libs/log" - ocproto "github.com/line/ostracon/proto/ostracon/types" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - clienttypes "github.com/line/lbm-sdk/x/ibc/core/02-client/types" - ibctmtypes "github.com/line/lbm-sdk/x/ibc/light-clients/99-ostracon/types" - "github.com/line/lbm-sdk/x/upgrade/types" + "github.com/line/ostracon/libs/log" + ocproto "github.com/line/ostracon/proto/ostracon/types" + codectypes "github.com/line/lbm-sdk/codec/types" sdk "github.com/line/lbm-sdk/types" + "github.com/line/lbm-sdk/x/upgrade/types" ) func mustParseTime(s string) time.Time { @@ -26,44 +24,23 @@ func mustParseTime(s string) time.Time { } func TestPlanString(t *testing.T) { - cs, err := clienttypes.PackClientState(&ibctmtypes.ClientState{}) - require.NoError(t, err) - cases := map[string]struct { p types.Plan expect string }{ - "with time": { - p: types.Plan{ - Name: "due_time", - Info: "https://foo.bar", - Time: mustParseTime("2019-07-08T11:33:55Z"), - }, - expect: "Upgrade Plan\n Name: due_time\n Time: 2019-07-08T11:33:55Z\n Info: https://foo.bar.\n Upgraded IBC Client: no upgraded client provided", - }, "with height": { p: types.Plan{ Name: "by height", Info: "https://foo.bar/baz", Height: 7890, }, - expect: "Upgrade Plan\n Name: by height\n Height: 7890\n Info: https://foo.bar/baz.\n Upgraded IBC Client: no upgraded client provided", - }, - "with IBC client": { - p: types.Plan{ - Name: "by height", - Info: "https://foo.bar/baz", - Height: 7890, - UpgradedClientState: cs, - }, - expect: fmt.Sprintf("Upgrade Plan\n Name: by height\n Height: 7890\n Info: https://foo.bar/baz.\n Upgraded IBC Client: %s", &ibctmtypes.ClientState{}), + expect: "Upgrade Plan\n Name: by height\n Height: 7890\n Info: https://foo.bar/baz.", }, - "neither": { p: types.Plan{ Name: "almost-empty", }, - expect: "Upgrade Plan\n Name: almost-empty\n Height: 0\n Info: .\n Upgraded IBC Client: no upgraded client provided", + expect: "Upgrade Plan\n Name: almost-empty\n Height: 0\n Info: .", }, } @@ -77,40 +54,31 @@ func TestPlanString(t *testing.T) { } func TestPlanValid(t *testing.T) { - cs, err := clienttypes.PackClientState(&ibctmtypes.ClientState{}) - require.NoError(t, err) - cases := map[string]struct { p types.Plan valid bool }{ - "proper": { + "proper by height": { p: types.Plan{ - Name: "all-good", - Info: "some text here", - Time: mustParseTime("2019-07-08T11:33:55Z"), + Name: "all-good", + Height: 123450000, }, valid: true, }, - "proper ibc upgrade": { + "no name": { p: types.Plan{ - Name: "ibc-all-good", - Info: "some text here", - Height: 123450000, - UpgradedClientState: cs, + Height: 123450000, }, - valid: true, }, - "proper by height": { + "time-base upgrade": { p: types.Plan{ - Name: "all-good", - Height: 123450000, + Time: time.Now(), }, - valid: true, }, - "no name": { + "IBC upgrade": { p: types.Plan{ - Height: 123450000, + Height: 123450000, + UpgradedClientState: &codectypes.Any{}, }, }, "no due at": { @@ -125,15 +93,6 @@ func TestPlanValid(t *testing.T) { Height: -12345, }, }, - "time due date defined for IBC plan": { - p: types.Plan{ - Name: "ibc-all-good", - Info: "some text here", - Time: mustParseTime("2019-07-08T11:33:55Z"), - UpgradedClientState: cs, - }, - valid: false, - }, } for name, tc := range cases { diff --git a/x/upgrade/types/proposal.go b/x/upgrade/types/proposal.go index 3218bdc022..bdce193362 100644 --- a/x/upgrade/types/proposal.go +++ b/x/upgrade/types/proposal.go @@ -3,7 +3,6 @@ package types import ( "fmt" - codectypes "github.com/line/lbm-sdk/codec/types" gov "github.com/line/lbm-sdk/x/gov/types" ) @@ -18,7 +17,6 @@ func NewSoftwareUpgradeProposal(title, description string, plan Plan) gov.Conten // Implements Proposal Interface var _ gov.Content = &SoftwareUpgradeProposal{} -var _ codectypes.UnpackInterfacesMessage = SoftwareUpgradeProposal{} func init() { gov.RegisterProposalType(ProposalTypeSoftwareUpgrade) @@ -45,11 +43,6 @@ func (sup SoftwareUpgradeProposal) String() string { `, sup.Title, sup.Description) } -// UnpackInterfaces implements UnpackInterfacesMessage.UnpackInterfaces -func (sup SoftwareUpgradeProposal) UnpackInterfaces(unpacker codectypes.AnyUnpacker) error { - return sup.Plan.UnpackInterfaces(unpacker) -} - func NewCancelSoftwareUpgradeProposal(title, description string) gov.Content { return &CancelSoftwareUpgradeProposal{title, description} } diff --git a/x/upgrade/types/proposal_test.go b/x/upgrade/types/proposal_test.go index 545b73fdcd..f3be8fb718 100644 --- a/x/upgrade/types/proposal_test.go +++ b/x/upgrade/types/proposal_test.go @@ -9,8 +9,6 @@ import ( "github.com/line/lbm-sdk/codec" codectypes "github.com/line/lbm-sdk/codec/types" gov "github.com/line/lbm-sdk/x/gov/types" - clienttypes "github.com/line/lbm-sdk/x/ibc/core/02-client/types" - ibctmtypes "github.com/line/lbm-sdk/x/ibc/light-clients/99-ostracon/types" "github.com/line/lbm-sdk/x/upgrade/types" ) @@ -61,10 +59,10 @@ func TestContentAccessors(t *testing.T) { // try to encode and decode type to ensure codec works wrap := ProposalWrapper{tc.p} - bz, err := cdc.MarshalBinaryBare(&wrap) + bz, err := cdc.Marshal(&wrap) require.NoError(t, err) unwrap := ProposalWrapper{} - err = cdc.UnmarshalBinaryBare(bz, &unwrap) + err = cdc.Unmarshal(bz, &unwrap) require.NoError(t, err) // all methods should look the same @@ -79,17 +77,12 @@ func TestContentAccessors(t *testing.T) { } } -// tests a software update proposal can be marshaled and unmarshaled, and the -// client state can be unpacked +// tests a software update proposal can be marshaled and unmarshaled func TestMarshalSoftwareUpdateProposal(t *testing.T) { - cs, err := clienttypes.PackClientState(&ibctmtypes.ClientState{}) - require.NoError(t, err) - // create proposal plan := types.Plan{ - Name: "upgrade ibc", - Height: 1000, - UpgradedClientState: cs, + Name: "upgrade", + Height: 1000, } content := types.NewSoftwareUpgradeProposal("title", "description", plan) sup, ok := content.(*types.SoftwareUpgradeProposal) @@ -98,9 +91,7 @@ func TestMarshalSoftwareUpdateProposal(t *testing.T) { // create codec ir := codectypes.NewInterfaceRegistry() types.RegisterInterfaces(ir) - clienttypes.RegisterInterfaces(ir) gov.RegisterInterfaces(ir) - ibctmtypes.RegisterInterfaces(ir) cdc := codec.NewProtoCodec(ir) // marshal message @@ -111,8 +102,4 @@ func TestMarshalSoftwareUpdateProposal(t *testing.T) { newSup := &types.SoftwareUpgradeProposal{} err = cdc.UnmarshalJSON(bz, newSup) require.NoError(t, err) - - // unpack client state - _, err = clienttypes.UnpackClientState(newSup.Plan.UpgradedClientState) - require.NoError(t, err) } diff --git a/x/upgrade/types/query.pb.go b/x/upgrade/types/query.pb.go index a62d39a943..7f7c312ade 100644 --- a/x/upgrade/types/query.pb.go +++ b/x/upgrade/types/query.pb.go @@ -8,7 +8,7 @@ import ( fmt "fmt" grpc1 "github.com/gogo/protobuf/grpc" proto "github.com/gogo/protobuf/proto" - types "github.com/line/lbm-sdk/codec/types" + _ "github.com/line/lbm-sdk/codec/types" _ "google.golang.org/genproto/googleapis/api/annotations" grpc "google.golang.org/grpc" codes "google.golang.org/grpc/codes" @@ -210,6 +210,8 @@ func (m *QueryAppliedPlanResponse) GetHeight() int64 { // QueryUpgradedConsensusStateRequest is the request type for the Query/UpgradedConsensusState // RPC method. +// +// Deprecated: Do not use. type QueryUpgradedConsensusStateRequest struct { // last height of the current chain must be sent in request // as this is the height under which next consensus state is stored @@ -258,8 +260,11 @@ func (m *QueryUpgradedConsensusStateRequest) GetLastHeight() int64 { // QueryUpgradedConsensusStateResponse is the response type for the Query/UpgradedConsensusState // RPC method. +// +// Deprecated: Do not use. type QueryUpgradedConsensusStateResponse struct { - UpgradedConsensusState *types.Any `protobuf:"bytes,1,opt,name=upgraded_consensus_state,json=upgradedConsensusState,proto3" json:"upgraded_consensus_state,omitempty"` + // Since: cosmos-sdk 0.43 + UpgradedConsensusState []byte `protobuf:"bytes,2,opt,name=upgraded_consensus_state,json=upgradedConsensusState,proto3" json:"upgraded_consensus_state,omitempty"` } func (m *QueryUpgradedConsensusStateResponse) Reset() { *m = QueryUpgradedConsensusStateResponse{} } @@ -295,7 +300,7 @@ func (m *QueryUpgradedConsensusStateResponse) XXX_DiscardUnknown() { var xxx_messageInfo_QueryUpgradedConsensusStateResponse proto.InternalMessageInfo -func (m *QueryUpgradedConsensusStateResponse) GetUpgradedConsensusState() *types.Any { +func (m *QueryUpgradedConsensusStateResponse) GetUpgradedConsensusState() []byte { if m != nil { return m.UpgradedConsensusState } @@ -304,6 +309,8 @@ func (m *QueryUpgradedConsensusStateResponse) GetUpgradedConsensusState() *types // QueryModuleVersionsRequest is the request type for the Query/ModuleVersions // RPC method. +// +// Since: cosmos-sdk 0.43 type QueryModuleVersionsRequest struct { // module_name is a field to query a specific module // consensus version from state. Leaving this empty will @@ -353,6 +360,8 @@ func (m *QueryModuleVersionsRequest) GetModuleName() string { // QueryModuleVersionsResponse is the response type for the Query/ModuleVersions // RPC method. +// +// Since: cosmos-sdk 0.43 type QueryModuleVersionsResponse struct { // module_versions is a list of module names with their consensus versions. ModuleVersions []*ModuleVersion `protobuf:"bytes,1,rep,name=module_versions,json=moduleVersions,proto3" json:"module_versions,omitempty"` @@ -412,43 +421,44 @@ func init() { func init() { proto.RegisterFile("lbm/upgrade/v1/query.proto", fileDescriptor_be137e92226ff1e7) } var fileDescriptor_be137e92226ff1e7 = []byte{ - // 568 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x53, 0x41, 0x6b, 0x13, 0x41, - 0x18, 0xed, 0xda, 0x58, 0xf0, 0x0b, 0x44, 0x18, 0x24, 0xa6, 0x6b, 0xdd, 0xd6, 0xad, 0x92, 0x60, - 0xe9, 0x0e, 0x4d, 0x41, 0xbc, 0x28, 0xc4, 0xaa, 0x78, 0xb1, 0x68, 0x44, 0x0f, 0x5e, 0xc2, 0x24, - 0x3b, 0x26, 0x8b, 0xbb, 0xb3, 0xdb, 0x9d, 0x99, 0x60, 0x28, 0xbd, 0x78, 0xf0, 0x26, 0x88, 0xfe, - 0x22, 0x6f, 0x1e, 0x0b, 0x5e, 0x3c, 0x4a, 0xe2, 0x9f, 0xf0, 0x26, 0x3b, 0x3b, 0x29, 0xbb, 0x9b, - 0x4d, 0xd5, 0x5b, 0x32, 0xef, 0x7d, 0xef, 0xbd, 0x9d, 0xef, 0x0d, 0x98, 0x7e, 0x3f, 0xc0, 0x32, - 0x1a, 0xc6, 0xc4, 0xa5, 0x78, 0xbc, 0x87, 0x8f, 0x24, 0x8d, 0x27, 0x4e, 0x14, 0x87, 0x22, 0x44, - 0x35, 0xbf, 0x1f, 0x38, 0x1a, 0x73, 0xc6, 0x7b, 0xe6, 0xfa, 0x30, 0x0c, 0x87, 0x3e, 0xc5, 0x0a, - 0xed, 0xcb, 0x37, 0x98, 0x30, 0x4d, 0x35, 0x37, 0x34, 0x44, 0x22, 0x0f, 0x13, 0xc6, 0x42, 0x41, - 0x84, 0x17, 0x32, 0x3e, 0x47, 0x0b, 0x26, 0x73, 0x4d, 0x85, 0xda, 0xeb, 0x70, 0xf5, 0x79, 0xe2, - 0x7a, 0x20, 0xe3, 0x98, 0x32, 0xf1, 0xcc, 0x27, 0xac, 0x4b, 0x8f, 0x24, 0xe5, 0xc2, 0x7e, 0x08, - 0x8d, 0x45, 0x88, 0x47, 0x21, 0xe3, 0x14, 0xb5, 0xa0, 0x12, 0xf9, 0x84, 0x35, 0x8c, 0x2d, 0xa3, - 0x55, 0x6d, 0x5f, 0x71, 0xf2, 0x61, 0x1d, 0xc5, 0x55, 0x0c, 0x7b, 0x57, 0x1b, 0x74, 0xa2, 0xc8, - 0xf7, 0xa8, 0x9b, 0x31, 0x40, 0x08, 0x2a, 0x8c, 0x04, 0x54, 0x89, 0x5c, 0xea, 0xaa, 0xdf, 0x76, - 0x5b, 0x9b, 0xe6, 0xe8, 0xda, 0xb4, 0x0e, 0x6b, 0x23, 0xea, 0x0d, 0x47, 0x42, 0x4d, 0xac, 0x76, - 0xf5, 0x3f, 0xfb, 0x11, 0xd8, 0x6a, 0xe6, 0x65, 0x1a, 0xc0, 0x3d, 0x48, 0xd8, 0x8c, 0x4b, 0xfe, - 0x42, 0x10, 0x41, 0xe7, 0x6e, 0x9b, 0x50, 0xf5, 0x09, 0x17, 0xbd, 0x9c, 0x04, 0x24, 0x47, 0x4f, - 0x52, 0x19, 0x09, 0xdb, 0xe7, 0xca, 0xe8, 0x14, 0x87, 0xd0, 0xd0, 0x5f, 0xea, 0xf6, 0x06, 0x73, - 0x4a, 0x8f, 0x27, 0x9c, 0xb3, 0xeb, 0x48, 0x17, 0xe2, 0xcc, 0x77, 0xe5, 0x74, 0xd8, 0xa4, 0x5b, - 0x97, 0xa5, 0xba, 0xf6, 0x3d, 0x30, 0x95, 0xed, 0xd3, 0xd0, 0x95, 0x3e, 0x7d, 0x45, 0x63, 0x9e, - 0x2c, 0x2f, 0x93, 0x3a, 0x50, 0x40, 0x2f, 0x73, 0x55, 0x90, 0x1e, 0x1d, 0x26, 0x17, 0x46, 0xe1, - 0x5a, 0xe9, 0xb8, 0x4e, 0xfb, 0x18, 0x2e, 0xeb, 0xf9, 0xb1, 0x86, 0x1a, 0xc6, 0xd6, 0x6a, 0xab, - 0xda, 0xbe, 0x5e, 0xdc, 0x59, 0x4e, 0xa0, 0x5b, 0x0b, 0x72, 0x7a, 0xed, 0xdf, 0x15, 0xb8, 0xa8, - 0x7c, 0xd0, 0x07, 0x03, 0xaa, 0x99, 0x4a, 0xa0, 0x66, 0x51, 0x68, 0x49, 0x9f, 0xcc, 0xd6, 0xdf, - 0x89, 0x69, 0x68, 0xfb, 0xe6, 0xfb, 0xef, 0xbf, 0xbe, 0x5c, 0xb0, 0xd0, 0x06, 0x2e, 0x74, 0x77, - 0x90, 0x92, 0x7b, 0x49, 0xb3, 0xd0, 0x47, 0x03, 0xaa, 0x99, 0x9a, 0x2c, 0x09, 0xb2, 0xd8, 0xbb, - 0x25, 0x41, 0x4a, 0x1a, 0x67, 0xef, 0xa8, 0x20, 0xb7, 0xd0, 0x76, 0x31, 0x08, 0x49, 0xc9, 0x2a, - 0x08, 0x3e, 0x4e, 0x56, 0x73, 0x82, 0xbe, 0x1a, 0x50, 0x2f, 0xef, 0x0e, 0x6a, 0x97, 0x3a, 0x9e, - 0xdb, 0x57, 0x73, 0xff, 0xbf, 0x66, 0x74, 0xe0, 0xfb, 0x2a, 0xf0, 0x5d, 0x74, 0x07, 0x97, 0xbf, - 0xfa, 0x85, 0xca, 0xe2, 0xe3, 0xcc, 0xa3, 0x38, 0x41, 0x9f, 0x0d, 0xa8, 0xe5, 0x9b, 0x84, 0x6e, - 0x97, 0xe6, 0x28, 0x6d, 0xab, 0xb9, 0xf3, 0x4f, 0x5c, 0x9d, 0xb5, 0xa9, 0xb2, 0xde, 0x40, 0x9b, - 0xc5, 0xac, 0x85, 0xc2, 0x3e, 0xe8, 0x7c, 0x9b, 0x5a, 0xc6, 0xe9, 0xd4, 0x32, 0x7e, 0x4e, 0x2d, - 0xe3, 0xd3, 0xcc, 0x5a, 0x39, 0x9d, 0x59, 0x2b, 0x3f, 0x66, 0xd6, 0xca, 0xeb, 0xe6, 0xd0, 0x13, - 0x23, 0xd9, 0x77, 0x06, 0x61, 0x80, 0x7d, 0x8f, 0xd1, 0x44, 0x69, 0x97, 0xbb, 0x6f, 0xf1, 0xbb, - 0x33, 0x3d, 0x31, 0x89, 0x28, 0xef, 0xaf, 0xa9, 0xa7, 0xb8, 0xff, 0x27, 0x00, 0x00, 0xff, 0xff, - 0xfd, 0xe2, 0xab, 0x5d, 0x72, 0x05, 0x00, 0x00, + // 581 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x94, 0xc1, 0x8b, 0xd3, 0x4e, + 0x1c, 0xc5, 0x3b, 0xdd, 0xfe, 0x96, 0x9f, 0x53, 0xa9, 0x32, 0x48, 0xcd, 0xc6, 0x35, 0x5b, 0xb3, + 0x4a, 0x8b, 0xcb, 0x66, 0xd8, 0x2e, 0xc8, 0x22, 0x78, 0xa8, 0x2b, 0xa2, 0x82, 0xa2, 0x15, 0x3d, + 0x78, 0x29, 0xd3, 0x66, 0x6c, 0x83, 0xc9, 0x24, 0x9b, 0x99, 0x14, 0x97, 0x65, 0x2f, 0x1e, 0xc4, + 0x8b, 0x20, 0xfa, 0x2f, 0x79, 0xf0, 0xb8, 0xe0, 0xc5, 0xa3, 0xb4, 0xfe, 0x19, 0x1e, 0x64, 0xa6, + 0x53, 0x49, 0xd2, 0x74, 0xd5, 0x5b, 0x3b, 0xdf, 0xf7, 0x7d, 0xef, 0xd3, 0xcc, 0x4b, 0xa1, 0xe9, + 0xf7, 0x03, 0x9c, 0x44, 0xc3, 0x98, 0xb8, 0x14, 0x8f, 0x77, 0xf0, 0x41, 0x42, 0xe3, 0x43, 0x27, + 0x8a, 0x43, 0x11, 0xa2, 0x9a, 0xdf, 0x0f, 0x1c, 0x3d, 0x73, 0xc6, 0x3b, 0xe6, 0xda, 0x30, 0x0c, + 0x87, 0x3e, 0xc5, 0x6a, 0xda, 0x4f, 0x5e, 0x62, 0xc2, 0xb4, 0xd4, 0x5c, 0xd7, 0x23, 0x12, 0x79, + 0x98, 0x30, 0x16, 0x0a, 0x22, 0xbc, 0x90, 0xf1, 0xf9, 0x34, 0x17, 0x32, 0xf7, 0x54, 0x53, 0x7b, + 0x0d, 0x5e, 0x7c, 0x22, 0x53, 0xf7, 0x93, 0x38, 0xa6, 0x4c, 0x3c, 0xf6, 0x09, 0xeb, 0xd2, 0x83, + 0x84, 0x72, 0x61, 0xdf, 0x81, 0xc6, 0xe2, 0x88, 0x47, 0x21, 0xe3, 0x14, 0xb5, 0x60, 0x25, 0xf2, + 0x09, 0x33, 0x40, 0x03, 0xb4, 0xaa, 0xed, 0x0b, 0x4e, 0x16, 0xd6, 0x51, 0x5a, 0xa5, 0xb0, 0xb7, + 0x75, 0x40, 0x27, 0x8a, 0x7c, 0x8f, 0xba, 0xa9, 0x00, 0x84, 0x60, 0x85, 0x91, 0x80, 0x2a, 0x93, + 0x33, 0x5d, 0xf5, 0xd9, 0x6e, 0xeb, 0xd0, 0x8c, 0x5c, 0x87, 0xd6, 0xe1, 0xea, 0x88, 0x7a, 0xc3, + 0x91, 0x50, 0x1b, 0x2b, 0x5d, 0xfd, 0xcd, 0xbe, 0x0f, 0x6d, 0xb5, 0xf3, 0x6c, 0x06, 0xe0, 0xee, + 0x4b, 0x35, 0xe3, 0x09, 0x7f, 0x2a, 0x88, 0xa0, 0xf3, 0xb4, 0x0d, 0x58, 0xf5, 0x09, 0x17, 0xbd, + 0x8c, 0x05, 0x94, 0x47, 0xf7, 0xd4, 0xc9, 0xcd, 0xb2, 0x01, 0x6c, 0x0f, 0x6e, 0x9e, 0x6a, 0xa5, + 0x49, 0xf6, 0xa0, 0xa1, 0x7f, 0xad, 0xdb, 0x1b, 0xcc, 0x25, 0x3d, 0x2e, 0x35, 0x46, 0xb9, 0x01, + 0x5a, 0x67, 0xbb, 0xf5, 0xa4, 0xd0, 0x41, 0x86, 0x3c, 0xa8, 0xfc, 0x0f, 0xce, 0x97, 0xed, 0x5b, + 0xd0, 0x54, 0x51, 0x0f, 0x43, 0x37, 0xf1, 0xe9, 0x73, 0x1a, 0x73, 0x79, 0x69, 0x29, 0xda, 0x40, + 0x0d, 0x7a, 0xa9, 0x47, 0x04, 0x67, 0x47, 0x8f, 0xe4, 0x83, 0xa2, 0xf0, 0x52, 0xe1, 0xba, 0x26, + 0xbc, 0x0b, 0xcf, 0xe9, 0xfd, 0xb1, 0x1e, 0x19, 0xa0, 0xb1, 0xd2, 0xaa, 0xb6, 0x2f, 0xe7, 0xef, + 0x2a, 0x63, 0xd0, 0xad, 0x05, 0x19, 0xbf, 0xf6, 0xcf, 0x0a, 0xfc, 0x4f, 0xe5, 0xa0, 0xb7, 0x00, + 0x56, 0x53, 0x55, 0x40, 0xcd, 0xbc, 0xd1, 0x92, 0x1e, 0x99, 0xad, 0x3f, 0x0b, 0x67, 0xd0, 0xf6, + 0xd5, 0x37, 0x5f, 0x7f, 0x7c, 0x2a, 0x5b, 0x68, 0x1d, 0xe7, 0x3a, 0x3b, 0x98, 0x89, 0x7b, 0xb2, + 0x51, 0xe8, 0x3d, 0x80, 0xd5, 0x54, 0x3d, 0x96, 0x80, 0x2c, 0xf6, 0x6d, 0x09, 0x48, 0x41, 0xd3, + 0xec, 0x2d, 0x05, 0x72, 0x0d, 0x6d, 0xe6, 0x41, 0xc8, 0x4c, 0xac, 0x40, 0xf0, 0x91, 0xbc, 0x9a, + 0x63, 0xf4, 0x19, 0xc0, 0x7a, 0x71, 0x5f, 0x50, 0xbb, 0x30, 0xf1, 0xd4, 0x9e, 0x9a, 0xbb, 0xff, + 0xb4, 0xa3, 0x81, 0x3b, 0x0a, 0x78, 0x0f, 0xdd, 0xc0, 0xc5, 0x6f, 0xfb, 0x42, 0x4d, 0xf1, 0x51, + 0xea, 0x65, 0x38, 0x7e, 0x57, 0x06, 0xe8, 0x23, 0x80, 0xb5, 0x6c, 0x99, 0xd0, 0xf5, 0x42, 0x94, + 0xc2, 0xc2, 0x9a, 0x5b, 0x7f, 0xa5, 0xd5, 0xb8, 0x4d, 0x85, 0x7b, 0x05, 0x6d, 0xe4, 0x71, 0x73, + 0x9d, 0xbd, 0xdd, 0xf9, 0x32, 0xb1, 0xc0, 0xc9, 0xc4, 0x02, 0xdf, 0x27, 0x16, 0xf8, 0x30, 0xb5, + 0x4a, 0x27, 0x53, 0xab, 0xf4, 0x6d, 0x6a, 0x95, 0x5e, 0x34, 0x87, 0x9e, 0x18, 0x25, 0x7d, 0x67, + 0x10, 0x06, 0xd8, 0xf7, 0x18, 0x95, 0x4e, 0xdb, 0xdc, 0x7d, 0x85, 0x5f, 0xff, 0xf6, 0x13, 0x87, + 0x11, 0xe5, 0xfd, 0x55, 0xf5, 0x47, 0xb7, 0xfb, 0x2b, 0x00, 0x00, 0xff, 0xff, 0xab, 0x82, 0x27, + 0x21, 0x6d, 0x05, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -471,8 +481,12 @@ type QueryClient interface { // as a trusted kernel for the next version of this chain. It will only be // stored at the last height of this chain. // UpgradedConsensusState RPC not supported with legacy querier + // This rpc is deprecated now that IBC has its own replacement + // (https://github.com/cosmos/ibc-go/blob/2c880a22e9f9cc75f62b527ca94aa75ce1106001/proto/ibc/core/client/v1/query.proto#L54) UpgradedConsensusState(ctx context.Context, in *QueryUpgradedConsensusStateRequest, opts ...grpc.CallOption) (*QueryUpgradedConsensusStateResponse, error) // ModuleVersions queries the list of module versions from state. + // + // Since: cosmos-sdk 0.43 ModuleVersions(ctx context.Context, in *QueryModuleVersionsRequest, opts ...grpc.CallOption) (*QueryModuleVersionsResponse, error) } @@ -502,6 +516,7 @@ func (c *queryClient) AppliedPlan(ctx context.Context, in *QueryAppliedPlanReque return out, nil } +// Deprecated: Do not use. func (c *queryClient) UpgradedConsensusState(ctx context.Context, in *QueryUpgradedConsensusStateRequest, opts ...grpc.CallOption) (*QueryUpgradedConsensusStateResponse, error) { out := new(QueryUpgradedConsensusStateResponse) err := c.cc.Invoke(ctx, "/lbm.upgrade.v1.Query/UpgradedConsensusState", in, out, opts...) @@ -530,8 +545,12 @@ type QueryServer interface { // as a trusted kernel for the next version of this chain. It will only be // stored at the last height of this chain. // UpgradedConsensusState RPC not supported with legacy querier + // This rpc is deprecated now that IBC has its own replacement + // (https://github.com/cosmos/ibc-go/blob/2c880a22e9f9cc75f62b527ca94aa75ce1106001/proto/ibc/core/client/v1/query.proto#L54) UpgradedConsensusState(context.Context, *QueryUpgradedConsensusStateRequest) (*QueryUpgradedConsensusStateResponse, error) // ModuleVersions queries the list of module versions from state. + // + // Since: cosmos-sdk 0.43 ModuleVersions(context.Context, *QueryModuleVersionsRequest) (*QueryModuleVersionsResponse, error) } @@ -817,17 +836,12 @@ func (m *QueryUpgradedConsensusStateResponse) MarshalToSizedBuffer(dAtA []byte) _ = i var l int _ = l - if m.UpgradedConsensusState != nil { - { - size, err := m.UpgradedConsensusState.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintQuery(dAtA, i, uint64(size)) - } + if len(m.UpgradedConsensusState) > 0 { + i -= len(m.UpgradedConsensusState) + copy(dAtA[i:], m.UpgradedConsensusState) + i = encodeVarintQuery(dAtA, i, uint64(len(m.UpgradedConsensusState))) i-- - dAtA[i] = 0xa + dAtA[i] = 0x12 } return len(dAtA) - i, nil } @@ -975,8 +989,8 @@ func (m *QueryUpgradedConsensusStateResponse) Size() (n int) { } var l int _ = l - if m.UpgradedConsensusState != nil { - l = m.UpgradedConsensusState.Size() + l = len(m.UpgradedConsensusState) + if l > 0 { n += 1 + l + sovQuery(uint64(l)) } return n @@ -1401,11 +1415,11 @@ func (m *QueryUpgradedConsensusStateResponse) Unmarshal(dAtA []byte) error { return fmt.Errorf("proto: QueryUpgradedConsensusStateResponse: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { - case 1: + case 2: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field UpgradedConsensusState", wireType) } - var msglen int + var byteLen int for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowQuery @@ -1415,26 +1429,24 @@ func (m *QueryUpgradedConsensusStateResponse) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - msglen |= int(b&0x7F) << shift + byteLen |= int(b&0x7F) << shift if b < 0x80 { break } } - if msglen < 0 { + if byteLen < 0 { return ErrInvalidLengthQuery } - postIndex := iNdEx + msglen + postIndex := iNdEx + byteLen if postIndex < 0 { return ErrInvalidLengthQuery } if postIndex > l { return io.ErrUnexpectedEOF } + m.UpgradedConsensusState = append(m.UpgradedConsensusState[:0], dAtA[iNdEx:postIndex]...) if m.UpgradedConsensusState == nil { - m.UpgradedConsensusState = &types.Any{} - } - if err := m.UpgradedConsensusState.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err + m.UpgradedConsensusState = []byte{} } iNdEx = postIndex default: diff --git a/x/upgrade/types/query.pb.gw.go b/x/upgrade/types/query.pb.gw.go index 64e2bdc13b..68dcee8ada 100644 --- a/x/upgrade/types/query.pb.gw.go +++ b/x/upgrade/types/query.pb.gw.go @@ -404,13 +404,13 @@ func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, clie } var ( - pattern_Query_CurrentPlan_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"lbm", "upgrade", "v1", "current_plan"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_Query_CurrentPlan_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"lbm", "upgrade", "v1", "current_plan"}, "", runtime.AssumeColonVerbOpt(false))) - pattern_Query_AppliedPlan_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4}, []string{"lbm", "upgrade", "v1", "applied_plan", "name"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_Query_AppliedPlan_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4}, []string{"lbm", "upgrade", "v1", "applied_plan", "name"}, "", runtime.AssumeColonVerbOpt(false))) - pattern_Query_UpgradedConsensusState_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4}, []string{"lbm", "upgrade", "v1", "upgraded_consensus_state", "last_height"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_Query_UpgradedConsensusState_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4}, []string{"lbm", "upgrade", "v1", "upgraded_consensus_state", "last_height"}, "", runtime.AssumeColonVerbOpt(false))) - pattern_Query_ModuleVersions_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"lbm", "upgrade", "v1", "module_versions"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_Query_ModuleVersions_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"lbm", "upgrade", "v1", "module_versions"}, "", runtime.AssumeColonVerbOpt(false))) ) var ( diff --git a/x/upgrade/types/upgrade.pb.go b/x/upgrade/types/upgrade.pb.go index 3507570a2c..350392550e 100644 --- a/x/upgrade/types/upgrade.pb.go +++ b/x/upgrade/types/upgrade.pb.go @@ -38,21 +38,20 @@ type Plan struct { // assumed that the software is out-of-date when the upgrade Time or Height is // reached and the software will exit. Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` - // The time after which the upgrade must be performed. - // Leave set to its zero value to use a pre-defined Height instead. - Time time.Time `protobuf:"bytes,2,opt,name=time,proto3,stdtime" json:"time"` + // Deprecated: Time based upgrades have been deprecated. Time based upgrade logic + // has been removed from the SDK. + // If this field is not empty, an error will be thrown. + Time time.Time `protobuf:"bytes,2,opt,name=time,proto3,stdtime" json:"time"` // Deprecated: Do not use. // The height at which the upgrade must be performed. // Only used if Time is not set. Height int64 `protobuf:"varint,3,opt,name=height,proto3" json:"height,omitempty"` // Any application specific upgrade info to be included on-chain // such as a git commit that validators could automatically upgrade to Info string `protobuf:"bytes,4,opt,name=info,proto3" json:"info,omitempty"` - // IBC-enabled chains can opt-in to including the upgraded client state in its upgrade plan - // This will make the chain commit to the correct upgraded (self) client state before the upgrade occurs, - // so that connecting chains can verify that the new upgraded client is valid by verifying a proof on the - // previous version of the chain. - // This will allow IBC connections to persist smoothly across planned chain upgrades - UpgradedClientState *types.Any `protobuf:"bytes,5,opt,name=upgraded_client_state,json=upgradedClientState,proto3" json:"upgraded_client_state,omitempty" yaml:"upgraded_client_state"` + // Deprecated: UpgradedClientState field has been deprecated. IBC upgrade logic has been + // moved to the IBC module in the sub module 02-client. + // If this field is not empty, an error will be thrown. + UpgradedClientState *types.Any `protobuf:"bytes,5,opt,name=upgraded_client_state,json=upgradedClientState,proto3" json:"upgraded_client_state,omitempty" yaml:"upgraded_client_state"` // Deprecated: Do not use. } func (m *Plan) Reset() { *m = Plan{} } @@ -167,6 +166,8 @@ func (m *CancelSoftwareUpgradeProposal) XXX_DiscardUnknown() { var xxx_messageInfo_CancelSoftwareUpgradeProposal proto.InternalMessageInfo // ModuleVersion specifies a module and its consensus version. +// +// Since: cosmos-sdk 0.43 type ModuleVersion struct { // name of the app module Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` @@ -217,36 +218,36 @@ func init() { func init() { proto.RegisterFile("lbm/upgrade/v1/upgrade.proto", fileDescriptor_3f5591fe51496e2b) } var fileDescriptor_3f5591fe51496e2b = []byte{ - // 455 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x52, 0x3d, 0x6f, 0xd3, 0x40, - 0x18, 0xf6, 0x51, 0xb7, 0xb4, 0x57, 0xc1, 0x70, 0x04, 0x30, 0x51, 0xb1, 0xad, 0x2c, 0x64, 0xe1, - 0x4e, 0x85, 0x05, 0x65, 0x23, 0x1d, 0x10, 0x03, 0x52, 0xe5, 0x02, 0x03, 0x12, 0xaa, 0xce, 0xf1, - 0xc5, 0x39, 0xb8, 0x0f, 0xcb, 0xbe, 0x04, 0xfc, 0x0b, 0x58, 0x3b, 0x32, 0xf6, 0xe7, 0x64, 0xec, - 0xd8, 0xa9, 0xd0, 0x64, 0x61, 0xee, 0x2f, 0x40, 0x77, 0xb6, 0x11, 0x1f, 0x1d, 0xd9, 0x9e, 0xf7, - 0xb9, 0xe7, 0x7d, 0xde, 0xaf, 0x83, 0x7b, 0x22, 0x95, 0x64, 0x5e, 0xe4, 0x25, 0xcd, 0x18, 0x59, - 0xec, 0x77, 0x10, 0x17, 0xa5, 0x36, 0x1a, 0xdd, 0x16, 0xa9, 0xc4, 0x1d, 0xb5, 0xd8, 0xef, 0x3f, - 0xc8, 0xb5, 0xce, 0x05, 0x23, 0xee, 0x35, 0x9d, 0x4f, 0x09, 0x55, 0x75, 0x23, 0xed, 0xf7, 0x72, - 0x9d, 0x6b, 0x07, 0x89, 0x45, 0x2d, 0x1b, 0xfd, 0x9d, 0x60, 0xb8, 0x64, 0x95, 0xa1, 0xb2, 0x68, - 0x04, 0x83, 0x2b, 0x00, 0xfd, 0x43, 0x41, 0x15, 0x42, 0xd0, 0x57, 0x54, 0xb2, 0x00, 0xc4, 0x60, - 0xb8, 0x93, 0x38, 0x8c, 0x9e, 0x41, 0xdf, 0xea, 0x83, 0x1b, 0x31, 0x18, 0xee, 0x3e, 0xe9, 0xe3, - 0xc6, 0x0c, 0x77, 0x66, 0xf8, 0x75, 0x67, 0x36, 0xde, 0x5e, 0x5e, 0x44, 0xde, 0xc9, 0xb7, 0x08, - 0x24, 0x2e, 0x03, 0xdd, 0x83, 0x5b, 0x33, 0xc6, 0xf3, 0x99, 0x09, 0x36, 0x62, 0x30, 0xdc, 0x48, - 0xda, 0xc8, 0x56, 0xe1, 0x6a, 0xaa, 0x03, 0xbf, 0xa9, 0x62, 0x31, 0xfa, 0x00, 0xef, 0xb6, 0x23, - 0x66, 0xc7, 0x13, 0xc1, 0x99, 0x32, 0xc7, 0x95, 0xa1, 0x86, 0x05, 0x9b, 0xae, 0x6c, 0xef, 0x9f, - 0xb2, 0xcf, 0x55, 0x3d, 0x8e, 0xaf, 0x2e, 0xa2, 0xbd, 0x9a, 0x4a, 0x31, 0x1a, 0x5c, 0x9b, 0x3c, - 0x48, 0xee, 0x74, 0xfc, 0x81, 0xa3, 0x8f, 0x2c, 0x3b, 0xf2, 0x7f, 0x9c, 0x46, 0x60, 0xf0, 0x05, - 0xc0, 0xfb, 0x47, 0x7a, 0x6a, 0x3e, 0xd1, 0x92, 0xbd, 0x69, 0x54, 0x87, 0xa5, 0x2e, 0x74, 0x45, - 0x05, 0xea, 0xc1, 0x4d, 0xc3, 0x8d, 0xe8, 0x16, 0xd1, 0x04, 0x28, 0x86, 0xbb, 0x19, 0xab, 0x26, - 0x25, 0x2f, 0x0c, 0xd7, 0xca, 0x2d, 0x64, 0x27, 0xf9, 0x9d, 0x42, 0x18, 0xfa, 0x85, 0xa0, 0xca, - 0xcd, 0x6b, 0x9b, 0xfe, 0xf3, 0x72, 0xd8, 0xee, 0x78, 0xec, 0xdb, 0x2d, 0x25, 0x4e, 0xd7, 0x76, - 0xf2, 0x1e, 0x3e, 0x3c, 0xa0, 0x6a, 0xc2, 0xc4, 0x7f, 0x6e, 0xa7, 0xb5, 0x7f, 0x01, 0x6f, 0xbd, - 0xd2, 0xd9, 0x5c, 0xb0, 0xb7, 0xac, 0xac, 0x6c, 0x97, 0xd7, 0x5d, 0x39, 0x80, 0x37, 0x17, 0xcd, - 0xb3, 0x33, 0xf2, 0x93, 0x2e, 0x1c, 0x6d, 0x7f, 0x3d, 0x8d, 0x80, 0x35, 0x1a, 0xbf, 0x5c, 0x5e, - 0x86, 0xde, 0xf9, 0x65, 0xe8, 0x2d, 0x57, 0x21, 0x38, 0x5b, 0x85, 0xe0, 0xfb, 0x2a, 0x04, 0x27, - 0xeb, 0xd0, 0x3b, 0x5b, 0x87, 0xde, 0xf9, 0x3a, 0xf4, 0xde, 0x3d, 0xca, 0xb9, 0x99, 0xcd, 0x53, - 0x3c, 0xd1, 0x92, 0x08, 0xae, 0x18, 0x11, 0xa9, 0x7c, 0x5c, 0x65, 0x1f, 0xc9, 0xe7, 0x5f, 0xdf, - 0xdb, 0xd4, 0x05, 0xab, 0xd2, 0x2d, 0x77, 0xc7, 0xa7, 0x3f, 0x03, 0x00, 0x00, 0xff, 0xff, 0x63, - 0x94, 0x3c, 0xad, 0xfa, 0x02, 0x00, 0x00, + // 454 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x52, 0xbf, 0x73, 0xd3, 0x30, + 0x14, 0xb6, 0xa8, 0x5b, 0xa8, 0x7a, 0x30, 0x88, 0x00, 0x22, 0x57, 0xec, 0x9c, 0x17, 0xb2, 0x20, + 0x5d, 0x61, 0xcb, 0x46, 0x7a, 0x1c, 0x13, 0x77, 0x3d, 0x17, 0x18, 0x58, 0x7a, 0x72, 0xac, 0x38, + 0x3a, 0xf4, 0xc3, 0x67, 0x2b, 0x81, 0xfc, 0x0d, 0x2c, 0x1d, 0x19, 0xfb, 0xe7, 0x64, 0xec, 0xc8, + 0x54, 0x20, 0x59, 0x98, 0x19, 0x99, 0x38, 0xc9, 0x31, 0x17, 0x20, 0x63, 0xb7, 0xef, 0xbd, 0xf7, + 0xbd, 0xef, 0x7b, 0x7a, 0x4f, 0xf0, 0x50, 0x66, 0x8a, 0x4e, 0xcb, 0xa2, 0x62, 0x39, 0xa7, 0xb3, + 0xa3, 0x16, 0x92, 0xb2, 0x32, 0xd6, 0xa0, 0x3b, 0x32, 0x53, 0xa4, 0x4d, 0xcd, 0x8e, 0xba, 0x0f, + 0x0b, 0x63, 0x0a, 0xc9, 0xa9, 0xaf, 0x66, 0xd3, 0x31, 0x65, 0x7a, 0xde, 0x50, 0xbb, 0x9d, 0xc2, + 0x14, 0xc6, 0x43, 0xea, 0xd0, 0x3a, 0x1b, 0xff, 0xdb, 0x60, 0x85, 0xe2, 0xb5, 0x65, 0xaa, 0x6c, + 0x08, 0xc9, 0x2f, 0x00, 0xc3, 0x13, 0xc9, 0x34, 0x42, 0x30, 0xd4, 0x4c, 0x71, 0x0c, 0x7a, 0xa0, + 0xbf, 0x9f, 0x7a, 0x8c, 0x06, 0x30, 0x74, 0x7c, 0x7c, 0xa3, 0x07, 0xfa, 0x07, 0x4f, 0xbb, 0xa4, + 0x11, 0x23, 0xad, 0x18, 0x79, 0xdd, 0x8a, 0x0d, 0xe1, 0xe2, 0x2a, 0x0e, 0xce, 0xbf, 0xc6, 0x00, + 0x83, 0xd4, 0xf7, 0xa0, 0xfb, 0x70, 0x6f, 0xc2, 0x45, 0x31, 0xb1, 0x78, 0xa7, 0x07, 0xfa, 0x3b, + 0xe9, 0x3a, 0x72, 0x3e, 0x42, 0x8f, 0x0d, 0x0e, 0x1b, 0x1f, 0x87, 0x91, 0x84, 0xf7, 0xd6, 0x8f, + 0xcc, 0xcf, 0x46, 0x52, 0x70, 0x6d, 0xcf, 0x6a, 0xcb, 0x2c, 0xc7, 0xbb, 0xde, 0xb8, 0xf3, 0x9f, + 0xf1, 0x73, 0x3d, 0x1f, 0x26, 0x3f, 0xaf, 0xe2, 0xc3, 0x39, 0x53, 0x72, 0x90, 0x6c, 0x6d, 0x4e, + 0x30, 0x48, 0xef, 0xb6, 0x95, 0x63, 0x5f, 0x38, 0x75, 0xf9, 0xc1, 0xad, 0xcf, 0x17, 0x71, 0xf0, + 0xe3, 0x22, 0x06, 0xc9, 0x27, 0x00, 0x1f, 0x9c, 0x9a, 0xb1, 0xfd, 0xc0, 0x2a, 0xfe, 0xa6, 0x61, + 0x9e, 0x54, 0xa6, 0x34, 0x35, 0x93, 0xa8, 0x03, 0x77, 0xad, 0xb0, 0xb2, 0x5d, 0x48, 0x13, 0xa0, + 0x1e, 0x3c, 0xc8, 0x79, 0x3d, 0xaa, 0x44, 0x69, 0x85, 0xd1, 0x7e, 0x31, 0xfb, 0xe9, 0x66, 0x0a, + 0x11, 0x18, 0x96, 0x92, 0x69, 0xff, 0x6a, 0x37, 0xfa, 0xdf, 0x17, 0x24, 0x6e, 0xd7, 0xc3, 0xd0, + 0x6d, 0x2b, 0xf5, 0xbc, 0x8d, 0x69, 0x18, 0x7c, 0x74, 0xcc, 0xf4, 0x88, 0xcb, 0x6b, 0x1e, 0x69, + 0xc3, 0xe2, 0x25, 0xbc, 0xfd, 0xca, 0xe4, 0x53, 0xc9, 0xdf, 0xf2, 0xaa, 0x76, 0xd3, 0x6e, 0xbb, + 0x3a, 0x86, 0x37, 0x67, 0x4d, 0xd9, 0x8b, 0x85, 0x69, 0x1b, 0x7a, 0x21, 0xe0, 0x84, 0x86, 0x2f, + 0x16, 0xdf, 0xa3, 0x60, 0xb1, 0x8c, 0xc0, 0xe5, 0x32, 0x02, 0xdf, 0x96, 0x11, 0x38, 0x5f, 0x45, + 0xc1, 0xe5, 0x2a, 0x0a, 0xbe, 0xac, 0xa2, 0xe0, 0xdd, 0xe3, 0x42, 0xd8, 0xc9, 0x34, 0x23, 0x23, + 0xa3, 0xa8, 0x14, 0x9a, 0x53, 0x99, 0xa9, 0x27, 0x75, 0xfe, 0x9e, 0x7e, 0xfc, 0xf3, 0xd5, 0xed, + 0xbc, 0xe4, 0x75, 0xb6, 0xe7, 0x2f, 0xfa, 0xec, 0x77, 0x00, 0x00, 0x00, 0xff, 0xff, 0x23, 0x17, + 0xed, 0x08, 0x06, 0x03, 0x00, 0x00, } func (this *Plan) Equal(that interface{}) bool { diff --git a/x/wasm/client/cli/genesis_msg.go b/x/wasm/client/cli/genesis_msg.go index c20dfe287f..96de7ad8a5 100644 --- a/x/wasm/client/cli/genesis_msg.go +++ b/x/wasm/client/cli/genesis_msg.go @@ -337,7 +337,7 @@ func hasAccountBalance(cmd *cobra.Command, appState map[string]json.RawMessage, if err != nil { return false, err } - cdc := clientCtx.JSONMarshaler + cdc := clientCtx.Codec var genBalIterator banktypes.GenesisBalancesIterator err = genutil.ValidateAccountInGenesis(appState, genBalIterator, sender, coins, cdc) if err != nil { @@ -392,7 +392,7 @@ func (d DefaultGenesisReader) ReadWasmGenesis(cmd *cobra.Command) (*GenesisData, var wasmGenesisState types.GenesisState if appState[types.ModuleName] != nil { clientCtx := client.GetClientContextFromCmd(cmd) - clientCtx.JSONMarshaler.MustUnmarshalJSON(appState[types.ModuleName], &wasmGenesisState) + clientCtx.Codec.MustUnmarshalJSON(appState[types.ModuleName], &wasmGenesisState) } return NewGenesisData( @@ -434,7 +434,7 @@ func (x DefaultGenesisIO) AlterWasmModuleState(cmd *cobra.Command, callback func return err } clientCtx := client.GetClientContextFromCmd(cmd) - wasmGenStateBz, err := clientCtx.JSONMarshaler.MarshalJSON(g.WasmModuleState) + wasmGenStateBz, err := clientCtx.Codec.MarshalJSON(g.WasmModuleState) if err != nil { return sdkerrors.Wrap(err, "marshal wasm genesis state") } diff --git a/x/wasm/client/cli/genesis_msg_test.go b/x/wasm/client/cli/genesis_msg_test.go index 24e4d80a13..a3dc6d6d1b 100644 --- a/x/wasm/client/cli/genesis_msg_test.go +++ b/x/wasm/client/cli/genesis_msg_test.go @@ -21,6 +21,7 @@ import ( "github.com/line/lbm-sdk/crypto/keyring" "github.com/line/lbm-sdk/server" "github.com/line/lbm-sdk/testutil" + "github.com/line/lbm-sdk/testutil/testdata" sdk "github.com/line/lbm-sdk/types" banktypes "github.com/line/lbm-sdk/x/bank/types" "github.com/line/lbm-sdk/x/genutil" @@ -638,7 +639,7 @@ func executeCmdWithContext(t *testing.T, homeDir string, cmd *cobra.Command) err require.NoError(t, err) appCodec := keeper.MakeEncodingConfig(t).Marshaler serverCtx := server.NewContext(viper.New(), cfg, logger) - clientCtx := client.Context{}.WithJSONMarshaler(appCodec).WithHomeDir(homeDir) + clientCtx := client.Context{}.WithJSONCodec(appCodec).WithHomeDir(homeDir) ctx := context.Background() ctx = context.WithValue(ctx, client.ClientContextKey, &clientCtx) @@ -650,7 +651,7 @@ func executeCmdWithContext(t *testing.T, homeDir string, cmd *cobra.Command) err mockIn := testutil.ApplyMockIODiscardOutErr(cmd) kb, err := keyring.New(sdk.KeyringServiceName(), keyring.BackendTest, homeDir, mockIn) require.NoError(t, err) - _, err = kb.NewAccount(defaultTestKeyName, testutil.TestMnemonic, "", sdk.FullFundraiserPath, hd.Secp256k1) + _, err = kb.NewAccount(defaultTestKeyName, testdata.TestMnemonic, "", sdk.FullFundraiserPath, hd.Secp256k1) require.NoError(t, err) return cmd.ExecuteContext(ctx) } diff --git a/x/wasm/client/codec/marshaller.go b/x/wasm/client/codec/marshaller.go index 696bc7e6ef..514bce13ee 100644 --- a/x/wasm/client/codec/marshaller.go +++ b/x/wasm/client/codec/marshaller.go @@ -11,18 +11,18 @@ import ( "github.com/line/lbm-sdk/codec/types" ) -var _ codec.Marshaler = (*ProtoCodec)(nil) +var _ codec.Codec = (*ProtoCodec)(nil) // ProtoCodec that omits empty values. // This Marshaler can be used globally when setting up the client context or individually // for each command via `clientCtx.WithJSONMarshaler(myMarshaler)`. type ProtoCodec struct { - codec.Marshaler + codec.Codec interfaceRegistry types.InterfaceRegistry } -func NewProtoCodec(marshaler codec.Marshaler, registry types.InterfaceRegistry) *ProtoCodec { - return &ProtoCodec{Marshaler: marshaler, interfaceRegistry: registry} +func NewProtoCodec(codec codec.Codec, registry types.InterfaceRegistry) *ProtoCodec { + return &ProtoCodec{Codec: codec, interfaceRegistry: registry} } // MarshalJSON implements JSONMarshaler.MarshalJSON method, diff --git a/x/wasm/client/proposal_handler_test.go b/x/wasm/client/proposal_handler_test.go index 2b6843b009..df059182ff 100644 --- a/x/wasm/client/proposal_handler_test.go +++ b/x/wasm/client/proposal_handler_test.go @@ -33,7 +33,7 @@ func TestGovRestHandlers(t *testing.T) { ) encodingConfig := keeper.MakeEncodingConfig(t) clientCtx := client.Context{}. - WithJSONMarshaler(encodingConfig.Marshaler). + WithJSONCodec(encodingConfig.Marshaler). WithTxConfig(encodingConfig.TxConfig). WithLegacyAmino(encodingConfig.Amino). WithInput(os.Stdin). @@ -159,7 +159,7 @@ func TestGovRestHandlers(t *testing.T) { "admin": "link18vd8fpwxzck93qlwghaj6arh4p7c5n89fvcmzu", "code_id": "1", "label": "https://example.com/", - "msg": dict{"recipient": "cosmos100dejzacpanrldpjjwksjm62shqhyss44jf5xz"}, + "msg": dict{"recipient": "link100dejzacpanrldpjjwksjm62shqhyss44jf5xz"}, "funds": []dict{{"denom": "ustake", "amount": "100"}}, "deposit": []dict{{"denom": "ustake", "amount": "10"}}, "proposer": "link1qyqszqgpqyqszqgpqyqszqgpqyqszqgp8apuk5", diff --git a/x/wasm/client/rest/query.go b/x/wasm/client/rest/query.go index cbfb3b316b..f2107adad3 100644 --- a/x/wasm/client/rest/query.go +++ b/x/wasm/client/rest/query.go @@ -43,7 +43,7 @@ func listCodesHandlerFn(cliCtx client.Context) http.HandlerFunc { return } - pageReq, err := client.NewPageRequest(pageKey, offset, limit, page, countTotal) + pageReq, err := client.NewPageRequest(pageKey, offset, limit, page, countTotal, false) if err != nil { rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) return @@ -116,7 +116,7 @@ func listContractsByCodeHandlerFn(cliCtx client.Context) http.HandlerFunc { return } - pageReq, err := client.NewPageRequest(pageKey, offset, limit, page, countTotal) + pageReq, err := client.NewPageRequest(pageKey, offset, limit, page, countTotal, false) if err != nil { rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) return @@ -296,7 +296,7 @@ func queryContractHistoryFn(cliCtx client.Context) http.HandlerFunc { return } - pageReq, err := client.NewPageRequest(pageKey, offset, limit, page, countTotal) + pageReq, err := client.NewPageRequest(pageKey, offset, limit, page, countTotal, false) if err != nil { rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) return diff --git a/x/wasm/keeper/genesis_test.go b/x/wasm/keeper/genesis_test.go index d52882bc24..7fb35b5252 100644 --- a/x/wasm/keeper/genesis_test.go +++ b/x/wasm/keeper/genesis_test.go @@ -12,13 +12,11 @@ import ( "testing" "time" - bankpluskeeper "github.com/line/lbm-sdk/x/bankplus/keeper" - fuzz "github.com/google/gofuzz" abci "github.com/line/ostracon/abci/types" "github.com/line/ostracon/libs/log" "github.com/line/ostracon/proto/ostracon/crypto" - tmproto "github.com/line/ostracon/proto/ostracon/types" + ocproto "github.com/line/ostracon/proto/ostracon/types" "github.com/line/tm-db/v2/memdb" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -27,6 +25,7 @@ import ( "github.com/line/lbm-sdk/store/prefix" sdk "github.com/line/lbm-sdk/types" authkeeper "github.com/line/lbm-sdk/x/auth/keeper" + bankpluskeeper "github.com/line/lbm-sdk/x/bankplus/keeper" distributionkeeper "github.com/line/lbm-sdk/x/distribution/keeper" govtypes "github.com/line/lbm-sdk/x/gov/types" paramskeeper "github.com/line/lbm-sdk/x/params/keeper" @@ -638,8 +637,9 @@ func setupKeeper(t *testing.T) (*Keeper, sdk.Context, []sdk.StoreKey) { require.NoError(t, err) t.Cleanup(func() { os.RemoveAll(tempDir) }) var ( - keyParams = sdk.NewKVStoreKey(paramtypes.StoreKey) - keyWasm = sdk.NewKVStoreKey(wasmTypes.StoreKey) + keyParams = sdk.NewKVStoreKey(paramtypes.StoreKey) + tkeyParams = sdk.NewKVStoreKey(paramtypes.TStoreKey) + keyWasm = sdk.NewKVStoreKey(wasmTypes.StoreKey) ) db := memdb.NewDB() @@ -648,7 +648,7 @@ func setupKeeper(t *testing.T) (*Keeper, sdk.Context, []sdk.StoreKey) { ms.MountStoreWithDB(keyParams, sdk.StoreTypeIAVL, db) require.NoError(t, ms.LoadLatestVersion()) - ctx := sdk.NewContext(ms, tmproto.Header{ + ctx := sdk.NewContext(ms, ocproto.Header{ Height: 1234567, Time: time.Date(2020, time.April, 22, 12, 0, 0, 0, time.UTC), }, false, log.NewNopLogger()) @@ -663,7 +663,7 @@ func setupKeeper(t *testing.T) (*Keeper, sdk.Context, []sdk.StoreKey) { govtypes.RegisterInterfaces(encodingConfig.InterfaceRegistry) wasmConfig := wasmTypes.DefaultWasmConfig() - pk := paramskeeper.NewKeeper(encodingConfig.Marshaler, encodingConfig.Amino, keyParams) + pk := paramskeeper.NewKeeper(encodingConfig.Marshaler, encodingConfig.Amino, keyParams, tkeyParams) srcKeeper := NewKeeper(encodingConfig.Marshaler, keyWasm, pk.Subspace(wasmTypes.DefaultParamspace), authkeeper.AccountKeeper{}, bankpluskeeper.BaseKeeper{}, stakingkeeper.Keeper{}, distributionkeeper.Keeper{}, nil, nil, nil, nil, nil, nil, tempDir, wasmConfig, SupportedFeatures, nil, nil) return &srcKeeper, ctx, []sdk.StoreKey{keyWasm, keyParams} diff --git a/x/wasm/keeper/handler_plugin.go b/x/wasm/keeper/handler_plugin.go index eba074ca86..8709efffcf 100644 --- a/x/wasm/keeper/handler_plugin.go +++ b/x/wasm/keeper/handler_plugin.go @@ -4,14 +4,14 @@ import ( "errors" "fmt" - wasmvmtypes "github.com/line/wasmvm/types" - codectypes "github.com/line/lbm-sdk/codec/types" sdk "github.com/line/lbm-sdk/types" sdkerrors "github.com/line/lbm-sdk/types/errors" + "github.com/line/lbm-sdk/x/auth/legacy/legacytx" channeltypes "github.com/line/lbm-sdk/x/ibc/core/04-channel/types" host "github.com/line/lbm-sdk/x/ibc/core/24-host" "github.com/line/lbm-sdk/x/wasm/types" + wasmvmtypes "github.com/line/wasmvm/types" ) // msgEncoder is an extension point to customize encodings @@ -86,16 +86,21 @@ func (h SDKMessageHandler) handleSdkMessage(ctx sdk.Context, contractAddr sdk.Ad } } - // find the handler and execute it - handler := h.router.Route(ctx, msg.Route()) - if handler == nil { - return nil, sdkerrors.Wrap(sdkerrors.ErrUnknownRequest, msg.Route()) - } - res, err := handler(ctx, msg) - if err != nil { - return nil, err + if legacyMsg, ok := msg.(legacytx.LegacyMsg); ok { + msgRoute := legacyMsg.Route() + // find the handler and execute it + handler := h.router.Route(ctx, msgRoute) + if handler == nil { + return nil, sdkerrors.Wrap(sdkerrors.ErrUnknownRequest, msgRoute) + } + res, err := handler(ctx, msg) + if err != nil { + return nil, err + } + return res, nil } - return res, nil + + return nil, sdkerrors.Wrap(sdkerrors.ErrUnknownRequest, "no route") } // MessageHandlerChain defines a chain of handlers that are called one by one until it can be handled. diff --git a/x/wasm/keeper/keeper.go b/x/wasm/keeper/keeper.go index 21f5baac63..e5520c5200 100644 --- a/x/wasm/keeper/keeper.go +++ b/x/wasm/keeper/keeper.go @@ -20,6 +20,7 @@ import ( storetypes "github.com/line/lbm-sdk/store/types" sdk "github.com/line/lbm-sdk/types" sdkerrors "github.com/line/lbm-sdk/types/errors" + authkeeper "github.com/line/lbm-sdk/x/auth/keeper" bankpluskeeper "github.com/line/lbm-sdk/x/bankplus/keeper" paramtypes "github.com/line/lbm-sdk/x/params/types" "github.com/line/lbm-sdk/x/wasm/types" @@ -62,7 +63,7 @@ type WasmVMResponseHandler interface { // Keeper will have a reference to Wasmer with it's own data directory. type Keeper struct { storeKey sdk.StoreKey - cdc codec.Marshaler + cdc codec.Codec accountKeeper types.AccountKeeper bank CoinTransferrer portKeeper types.PortKeeper @@ -74,17 +75,17 @@ type Keeper struct { metrics *Metrics // queryGasLimit is the max wasmvm gas that can be spent on executing a query with a contract queryGasLimit uint64 - paramSpace *paramtypes.Subspace + paramSpace paramtypes.Subspace gasRegister WasmGasRegister } // NewKeeper creates a new contract Keeper instance // If customEncoders is non-nil, we can use this to override some of the message handler, especially custom func NewKeeper( - cdc codec.Marshaler, + cdc codec.Codec, storeKey sdk.StoreKey, - paramSpace *paramtypes.Subspace, - accountKeeper types.AccountKeeper, + paramSpace paramtypes.Subspace, + accountKeeper authkeeper.AccountKeeper, bankKeeper types.BankKeeper, stakingKeeper types.StakingKeeper, distKeeper types.DistributionKeeper, @@ -268,7 +269,7 @@ func (k Keeper) create(ctx sdk.Context, creator sdk.AccAddress, wasmCode []byte, func (k Keeper) storeCodeInfo(ctx sdk.Context, codeID uint64, codeInfo types.CodeInfo) { store := ctx.KVStore(k.storeKey) // 0x01 | codeID (uint64) -> ContractInfo - store.Set(types.GetCodeKey(codeID), k.cdc.MustMarshalBinaryBare(&codeInfo)) + store.Set(types.GetCodeKey(codeID), k.cdc.MustMarshal(&codeInfo)) } func (k Keeper) importCode(ctx sdk.Context, codeID uint64, codeInfo types.CodeInfo, wasmCode []byte) error { @@ -290,7 +291,7 @@ func (k Keeper) importCode(ctx sdk.Context, codeID uint64, codeInfo types.CodeIn return sdkerrors.Wrapf(types.ErrDuplicate, "duplicate code: %d", codeID) } // 0x01 | codeID (uint64) -> ContractInfo - store.Set(key, k.cdc.MustMarshalBinaryBare(&codeInfo)) + store.Set(key, k.cdc.MustMarshal(&codeInfo)) return nil } @@ -327,7 +328,7 @@ func (k Keeper) instantiate(ctx sdk.Context, codeID uint64, creator, admin sdk.A return "", nil, sdkerrors.Wrap(types.ErrNotFound, "code") } var codeInfo types.CodeInfo - k.cdc.MustUnmarshalBinaryBare(bz, &codeInfo) + k.cdc.MustUnmarshal(bz, &codeInfo) if !authZ.CanInstantiateContract(codeInfo.InstantiateConfig, creator) { return "", nil, sdkerrors.Wrap(sdkerrors.ErrUnauthorized, "can not instantiate") @@ -664,7 +665,7 @@ func (k Keeper) appendToContractHistory(ctx sdk.Context, contractAddr sdk.AccAdd for i := range newEntries { pos++ key := types.GetContractCodeHistoryElementKey(contractAddr, pos) - store.Set(key, k.cdc.MustMarshalBinaryBare(&newEntries[i])) + store.Set(key, k.cdc.MustMarshal(&newEntries[i])) } } @@ -674,7 +675,7 @@ func (k Keeper) GetContractHistory(ctx sdk.Context, contractAddr sdk.AccAddress) iter := prefixStore.Iterator(nil, nil) for ; iter.Valid(); iter.Next() { var e types.ContractCodeHistoryEntry - k.cdc.MustUnmarshalBinaryBare(iter.Value(), &e) + k.cdc.MustUnmarshal(iter.Value(), &e) r = append(r, e) } return r @@ -689,7 +690,7 @@ func (k Keeper) getLastContractHistoryEntry(ctx sdk.Context, contractAddr sdk.Ac // all contracts have a history panic(fmt.Sprintf("no history for %s", contractAddr.String())) } - k.cdc.MustUnmarshalBinaryBare(iter.Value(), &r) + k.cdc.MustUnmarshal(iter.Value(), &r) return r } @@ -737,14 +738,14 @@ func (k Keeper) contractInstance(ctx sdk.Context, contractAddress sdk.AccAddress return types.ContractInfo{}, types.CodeInfo{}, prefix.Store{}, sdkerrors.Wrap(types.ErrNotFound, "contract") } var contractInfo types.ContractInfo - k.cdc.MustUnmarshalBinaryBare(contractBz, &contractInfo) + k.cdc.MustUnmarshal(contractBz, &contractInfo) codeInfoBz := store.Get(types.GetCodeKey(contractInfo.CodeID)) if codeInfoBz == nil { return contractInfo, types.CodeInfo{}, prefix.Store{}, sdkerrors.Wrap(types.ErrNotFound, "code info") } var codeInfo types.CodeInfo - k.cdc.MustUnmarshalBinaryBare(codeInfoBz, &codeInfo) + k.cdc.MustUnmarshal(codeInfoBz, &codeInfo) prefixStoreKey := types.GetContractStorePrefix(contractAddress) prefixStore := prefix.NewStore(ctx.KVStore(k.storeKey), prefixStoreKey) return contractInfo, codeInfo, prefixStore, nil @@ -757,7 +758,7 @@ func (k Keeper) GetContractInfo(ctx sdk.Context, contractAddress sdk.AccAddress) if contractBz == nil { return nil } - k.cdc.MustUnmarshalBinaryBare(contractBz, &contract) + k.cdc.MustUnmarshal(contractBz, &contract) return &contract } @@ -769,7 +770,7 @@ func (k Keeper) HasContractInfo(ctx sdk.Context, contractAddress sdk.AccAddress) // storeContractInfo persists the ContractInfo. No secondary index updated here. func (k Keeper) storeContractInfo(ctx sdk.Context, contractAddress sdk.AccAddress, contract *types.ContractInfo) { store := ctx.KVStore(k.storeKey) - store.Set(types.GetContractAddressKey(contractAddress), k.cdc.MustMarshalBinaryBare(contract)) + store.Set(types.GetContractAddressKey(contractAddress), k.cdc.MustMarshal(contract)) } func (k Keeper) IterateContractInfo(ctx sdk.Context, cb func(sdk.AccAddress, types.ContractInfo) bool) { @@ -777,7 +778,7 @@ func (k Keeper) IterateContractInfo(ctx sdk.Context, cb func(sdk.AccAddress, typ iter := prefixStore.Iterator(nil, nil) for ; iter.Valid(); iter.Next() { var contract types.ContractInfo - k.cdc.MustUnmarshalBinaryBare(iter.Value(), &contract) + k.cdc.MustUnmarshal(iter.Value(), &contract) // cb returns true to stop early if cb(sdk.AccAddress(string(iter.Key())), contract) { break @@ -813,7 +814,7 @@ func (k Keeper) GetCodeInfo(ctx sdk.Context, codeID uint64) *types.CodeInfo { if codeInfoBz == nil { return nil } - k.cdc.MustUnmarshalBinaryBare(codeInfoBz, &codeInfo) + k.cdc.MustUnmarshal(codeInfoBz, &codeInfo) return &codeInfo } @@ -827,7 +828,7 @@ func (k Keeper) IterateCodeInfos(ctx sdk.Context, cb func(uint64, types.CodeInfo iter := prefixStore.Iterator(nil, nil) for ; iter.Valid(); iter.Next() { var c types.CodeInfo - k.cdc.MustUnmarshalBinaryBare(iter.Value(), &c) + k.cdc.MustUnmarshal(iter.Value(), &c) // cb returns true to stop early if cb(binary.BigEndian.Uint64(iter.Key()), c) { return @@ -842,7 +843,7 @@ func (k Keeper) GetByteCode(ctx sdk.Context, codeID uint64) ([]byte, error) { if codeInfoBz == nil { return nil, nil } - k.cdc.MustUnmarshalBinaryBare(codeInfoBz, &codeInfo) + k.cdc.MustUnmarshal(codeInfoBz, &codeInfo) return k.wasmVM.GetCode(codeInfo.CodeHash) } @@ -1171,7 +1172,7 @@ func NewBankCoinTransferrer(keeper types.BankKeeper) BankCoinTransferrer { func (c BankCoinTransferrer) TransferCoins(parentCtx sdk.Context, fromAddr sdk.AccAddress, toAddr sdk.AccAddress, amt sdk.Coins) error { em := sdk.NewEventManager() ctx := parentCtx.WithEventManager(em) - if err := c.keeper.SendEnabledCoins(ctx, amt...); err != nil { + if err := c.keeper.IsSendEnabledCoins(ctx, amt...); err != nil { return err } diff --git a/x/wasm/keeper/keeper_test.go b/x/wasm/keeper/keeper_test.go index 4911f89c02..01c5bb0888 100644 --- a/x/wasm/keeper/keeper_test.go +++ b/x/wasm/keeper/keeper_test.go @@ -11,7 +11,7 @@ import ( "time" "github.com/line/ostracon/crypto" - tmproto "github.com/line/ostracon/proto/ostracon/types" + ocproto "github.com/line/ostracon/proto/ostracon/types" wasmvm "github.com/line/wasmvm" wasmvmtypes "github.com/line/wasmvm/types" "github.com/stretchr/testify/assert" @@ -221,7 +221,7 @@ func TestCreateWithSimulation(t *testing.T) { ctx, keepers := CreateTestInput(t, false, SupportedFeatures, nil, nil) accKeeper, keeper, bankKeeper := keepers.AccountKeeper, keepers.ContractKeeper, keepers.BankKeeper - ctx = ctx.WithBlockHeader(tmproto.Header{Height: 1}). + ctx = ctx.WithBlockHeader(ocproto.Header{Height: 1}). WithGasMeter(stypes.NewInfiniteGasMeter()) deposit := sdk.NewCoins(sdk.NewInt64Coin("denom", 100000)) @@ -251,15 +251,15 @@ func TestIsSimulationMode(t *testing.T) { exp bool }{ "genesis block": { - ctx: sdk.Context{}.WithBlockHeader(tmproto.Header{}).WithGasMeter(stypes.NewInfiniteGasMeter()), + ctx: sdk.Context{}.WithBlockHeader(ocproto.Header{}).WithGasMeter(stypes.NewInfiniteGasMeter()), exp: false, }, "any regular block": { - ctx: sdk.Context{}.WithBlockHeader(tmproto.Header{Height: 1}).WithGasMeter(stypes.NewGasMeter(10000000)), + ctx: sdk.Context{}.WithBlockHeader(ocproto.Header{Height: 1}).WithGasMeter(stypes.NewGasMeter(10000000)), exp: false, }, "simulation": { - ctx: sdk.Context{}.WithBlockHeader(tmproto.Header{Height: 1}).WithGasMeter(stypes.NewInfiniteGasMeter()), + ctx: sdk.Context{}.WithBlockHeader(ocproto.Header{Height: 1}).WithGasMeter(stypes.NewInfiniteGasMeter()), exp: true, }, } @@ -319,7 +319,7 @@ func TestInstantiate(t *testing.T) { gasAfter := ctx.GasMeter().GasConsumed() if types.EnableGasVerification { - require.Equal(t, uint64(0x11ccf), gasAfter-gasBefore) + require.Equal(t, uint64(0x142fa), gasAfter-gasBefore) } // ensure it is stored properly @@ -554,7 +554,7 @@ func TestExecute(t *testing.T) { // make sure gas is properly deducted from ctx gasAfter := ctx.GasMeter().GasConsumed() if types.EnableGasVerification { - require.Equal(t, uint64(0x115d7), gasAfter-gasBefore) + require.Equal(t, uint64(0x1278a), gasAfter-gasBefore) } // ensure bob now exists and got both payments released bobAcct = accKeeper.GetAccount(ctx, bob) @@ -565,13 +565,13 @@ func TestExecute(t *testing.T) { // ensure contract has updated balance contractAcct = accKeeper.GetAccount(ctx, addr) require.NotNil(t, contractAcct) - assert.Equal(t, sdk.Coins(nil), bankKeeper.GetAllBalances(ctx, contractAcct.GetAddress())) + assert.Equal(t, sdk.NewCoins().String(), bankKeeper.GetAllBalances(ctx, contractAcct.GetAddress()).String()) // and events emitted - require.Len(t, em.Events(), 5) + require.Len(t, em.Events(), 9) expEvt := sdk.NewEvent("execute", sdk.NewAttribute("_contract_address", addr.String())) - assert.Equal(t, expEvt, em.Events()[1]) + assert.Equal(t, expEvt, em.Events()[3]) t.Logf("Duration: %v (%d gas)\n", diff, gasAfter-gasBefore) } @@ -1058,11 +1058,25 @@ func TestMigrateWithDispatchedMessage(t *testing.T) { {"payout": myPayoutAddr}, }, }, + { + "Type": "coin_spent", + "Attr": []dict{ + {"spender": "link14hj2tavq8fpesdwxxcu44rty3hh90vhud63e6j"}, + {"amount": "100000denom"}, + }, + }, + { + "Type": "coin_received", + "Attr": []dict{ + {"receiver": "link1pfvr4mx003jylaxrp9ckjze20ndsvxgfkwt864"}, + {"amount": "100000denom"}, + }, + }, { "Type": "transfer", "Attr": []dict{ - {"recipient": myPayoutAddr}, - {"sender": contractAddr}, + {"recipient": "link1pfvr4mx003jylaxrp9ckjze20ndsvxgfkwt864"}, + {"sender": "link14hj2tavq8fpesdwxxcu44rty3hh90vhud63e6j"}, {"amount": "100000denom"}, }, }, @@ -1217,7 +1231,7 @@ func TestSudo(t *testing.T) { balance := bankKeeper.GetBalance(ctx, comAcct.GetAddress(), "denom") assert.Equal(t, sdk.NewInt64Coin("denom", 76543), balance) // and events emitted - require.Len(t, em.Events(), 2) + require.Len(t, em.Events(), 4) expEvt := sdk.NewEvent("sudo", sdk.NewAttribute("_contract_address", addr.String())) assert.Equal(t, expEvt, em.Events()[0]) diff --git a/x/wasm/keeper/options_test.go b/x/wasm/keeper/options_test.go index faff8f505f..4ebc9a388c 100644 --- a/x/wasm/keeper/options_test.go +++ b/x/wasm/keeper/options_test.go @@ -65,7 +65,7 @@ func TestConstructorOptions(t *testing.T) { } for name, spec := range specs { t.Run(name, func(t *testing.T) { - k := NewKeeper(nil, nil, paramtypes.NewSubspace(nil, nil, nil, ""), authkeeper.AccountKeeper{}, bankpluskeeper.BaseKeeper{}, stakingkeeper.Keeper{}, distributionkeeper.Keeper{}, nil, nil, nil, nil, nil, nil, "tempDir", types.DefaultWasmConfig(), SupportedFeatures, nil, nil, spec.srcOpt) + k := NewKeeper(nil, nil, paramtypes.NewSubspace(nil, nil, nil, nil, ""), authkeeper.AccountKeeper{}, bankpluskeeper.BaseKeeper{}, stakingkeeper.Keeper{}, distributionkeeper.Keeper{}, nil, nil, nil, nil, nil, nil, "tempDir", types.DefaultWasmConfig(), SupportedFeatures, nil, nil, spec.srcOpt) spec.verify(t, k) }) } diff --git a/x/wasm/keeper/querier.go b/x/wasm/keeper/querier.go index 5c7f24c6a4..fb93f08296 100644 --- a/x/wasm/keeper/querier.go +++ b/x/wasm/keeper/querier.go @@ -20,13 +20,13 @@ import ( var _ types.QueryServer = &GrpcQuerier{} type GrpcQuerier struct { - cdc codec.Marshaler + cdc codec.Codec storeKey sdk.StoreKey keeper types.ViewKeeper queryGasLimit sdk.Gas } -func NewGrpcQuerier(cdc codec.Marshaler, storeKey sdk.StoreKey, keeper types.ViewKeeper, queryGasLimit sdk.Gas) *GrpcQuerier { +func NewGrpcQuerier(cdc codec.Codec, storeKey sdk.StoreKey, keeper types.ViewKeeper, queryGasLimit sdk.Gas) *GrpcQuerier { return &GrpcQuerier{cdc: cdc, storeKey: storeKey, keeper: keeper, queryGasLimit: queryGasLimit} } @@ -64,7 +64,7 @@ func (q GrpcQuerier) ContractHistory(c context.Context, req *types.QueryContract pageRes, err := query.FilteredPaginate(prefixStore, req.Pagination, func(key []byte, value []byte, accumulate bool) (bool, error) { if accumulate { var e types.ContractCodeHistoryEntry - if err := q.cdc.UnmarshalBinaryBare(value, &e); err != nil { + if err := q.cdc.Unmarshal(value, &e); err != nil { return false, err } e.Updated = nil // redact @@ -231,7 +231,7 @@ func (q GrpcQuerier) Codes(c context.Context, req *types.QueryCodesRequest) (*ty pageRes, err := query.FilteredPaginate(prefixStore, req.Pagination, func(key []byte, value []byte, accumulate bool) (bool, error) { if accumulate { var c types.CodeInfo - if err := q.cdc.UnmarshalBinaryBare(value, &c); err != nil { + if err := q.cdc.Unmarshal(value, &c); err != nil { return false, err } r = append(r, types.CodeInfoResponse{ diff --git a/x/wasm/keeper/recurse_test.go b/x/wasm/keeper/recurse_test.go index 0741b38508..97d8811377 100644 --- a/x/wasm/keeper/recurse_test.go +++ b/x/wasm/keeper/recurse_test.go @@ -54,9 +54,9 @@ func initRecurseContract(t *testing.T) (contract sdk.AccAddress, creator sdk.Acc func TestGasCostOnQuery(t *testing.T) { const ( - GasNoWork uint64 = 44_134 + GasNoWork uint64 = 44_293 // Note: about 100 SDK gas (10k wasmer gas) for each round of sha256 - GasWork50 uint64 = 49_794 // this is a little shy of 50k gas - to keep an eye on the limit + GasWork50 uint64 = 49_953 // this is a little shy of 50k gas - to keep an eye on the limit GasReturnUnhashed uint64 = 255 GasReturnHashed uint64 = 230 @@ -218,7 +218,7 @@ func TestLimitRecursiveQueryGas(t *testing.T) { const ( // Note: about 100 SDK gas (10k wasmer gas) for each round of sha256 - GasWork2k uint64 = 273_061 // = InstanceCost + x // we have 6x gas used in cpu than in the instance + GasWork2k uint64 = 273_220 // = InstanceCost + x // we have 6x gas used in cpu than in the instance // This is overhead for calling into a sub-contract GasReturnHashed uint64 = 234 diff --git a/x/wasm/keeper/reflect_test.go b/x/wasm/keeper/reflect_test.go index 41c4a4b66f..310e58d5ad 100644 --- a/x/wasm/keeper/reflect_test.go +++ b/x/wasm/keeper/reflect_test.go @@ -528,7 +528,7 @@ type reflectCustomMsg struct { // toReflectRawMsg encodes an sdk msg using any type with json encoding. // Then wraps it as an opaque message -func toReflectRawMsg(cdc codec.Marshaler, msg sdk.Msg) (wasmvmtypes.CosmosMsg, error) { +func toReflectRawMsg(cdc codec.Codec, msg sdk.Msg) (wasmvmtypes.CosmosMsg, error) { any, err := codectypes.NewAnyWithValue(msg) if err != nil { return wasmvmtypes.CosmosMsg{}, err @@ -547,7 +547,7 @@ func toReflectRawMsg(cdc codec.Marshaler, msg sdk.Msg) (wasmvmtypes.CosmosMsg, e } // reflectEncoders needs to be registered in test setup to handle custom message callbacks -func reflectEncoders(cdc codec.Marshaler) *MessageEncoders { +func reflectEncoders(cdc codec.Codec) *MessageEncoders { return &MessageEncoders{ Custom: fromReflectRawMsg(cdc), } @@ -555,7 +555,7 @@ func reflectEncoders(cdc codec.Marshaler) *MessageEncoders { // fromReflectRawMsg decodes msg.Data to an sdk.Msg using proto Any and json encoding. // this needs to be registered on the Encoders -func fromReflectRawMsg(cdc codec.Marshaler) CustomEncoder { +func fromReflectRawMsg(cdc codec.Codec) CustomEncoder { return func(_sender sdk.AccAddress, msg json.RawMessage) ([]sdk.Msg, error) { var custom reflectCustomMsg err := json.Unmarshal(msg, &custom) diff --git a/x/wasm/keeper/relay_test.go b/x/wasm/keeper/relay_test.go index 12dcd232b5..5ada546030 100644 --- a/x/wasm/keeper/relay_test.go +++ b/x/wasm/keeper/relay_test.go @@ -80,7 +80,7 @@ func TestOnOpenChannel(t *testing.T) { } require.NoError(t, err) // verify gas consumed - const storageCosts = sdk.Gas(0xa8b) + const storageCosts = sdk.Gas(0xb2a) assert.Equal(t, spec.expGas, ctx.GasMeter().GasConsumed()-before-storageCosts) }) } @@ -186,7 +186,7 @@ func TestOnConnectChannel(t *testing.T) { require.NoError(t, err) // verify gas consumed - const storageCosts = sdk.Gas(0xa8b) + const storageCosts = sdk.Gas(0xb2a) assert.Equal(t, spec.expContractGas, ctx.GasMeter().GasConsumed()-before-storageCosts) // verify msgs dispatched @@ -297,7 +297,7 @@ func TestOnCloseChannel(t *testing.T) { } require.NoError(t, err) // verify gas consumed - const storageCosts = sdk.Gas(0xa8b) + const storageCosts = sdk.Gas(0xb2a) assert.Equal(t, spec.expContractGas, ctx.GasMeter().GasConsumed()-before-storageCosts) // verify msgs dispatched @@ -403,7 +403,7 @@ func TestOnRecvPacket(t *testing.T) { }, "submessage reply can overwrite ack data": { contractAddr: example.Contract, - expContractGas: myContractGas + 10 + types.DefaultInstanceCost + 3689, + expContractGas: myContractGas + 10 + types.DefaultInstanceCost + 3848, contractResp: &wasmvmtypes.IBCReceiveResponse{ Acknowledgement: []byte("myAck"), Messages: []wasmvmtypes.SubMsg{{ReplyOn: wasmvmtypes.ReplyAlways, Msg: wasmvmtypes.CosmosMsg{Bank: &wasmvmtypes.BankMsg{}}}}, @@ -459,7 +459,7 @@ func TestOnRecvPacket(t *testing.T) { require.Equal(t, spec.expAck, gotAck) // verify gas consumed - const storageCosts = sdk.Gas(0xa8b) + const storageCosts = sdk.Gas(0xb2a) assert.Equal(t, spec.expContractGas, ctx.GasMeter().GasConsumed()-before-storageCosts) // verify msgs dispatched @@ -567,7 +567,7 @@ func TestOnAckPacket(t *testing.T) { require.NoError(t, err) // verify gas consumed - const storageCosts = sdk.Gas(0xa8b) + const storageCosts = sdk.Gas(0xb2a) assert.Equal(t, spec.expContractGas, ctx.GasMeter().GasConsumed()-before-storageCosts) // verify msgs dispatched @@ -689,7 +689,7 @@ func TestOnTimeoutPacket(t *testing.T) { } require.NoError(t, err) // verify gas consumed - const storageCosts = sdk.Gas(0xa8b) + const storageCosts = sdk.Gas(0xb2a) assert.Equal(t, spec.expContractGas, ctx.GasMeter().GasConsumed()-before-storageCosts) // verify msgs dispatched diff --git a/x/wasm/keeper/submsg_test.go b/x/wasm/keeper/submsg_test.go index f35b5e5cc4..9416b14235 100644 --- a/x/wasm/keeper/submsg_test.go +++ b/x/wasm/keeper/submsg_test.go @@ -95,9 +95,9 @@ func TestDispatchSubMsgSuccessCase(t *testing.T) { require.NotNil(t, res.Result.Ok) sub := res.Result.Ok assert.Empty(t, sub.Data) - require.Len(t, sub.Events, 1) + require.Len(t, sub.Events, 3) - transfer := sub.Events[0] + transfer := sub.Events[2] assert.Equal(t, "transfer", transfer.Type) assert.Equal(t, wasmvmtypes.EventAttribute{ Key: "recipient", @@ -248,7 +248,7 @@ func TestDispatchSubMsgErrorHandling(t *testing.T) { submsgID: 5, msg: validBankSend, // note we charge another 40k for the reply call - resultAssertions: []assertion{assertReturnedEvents(1), assertGasUsed(115534, 121000)}, + resultAssertions: []assertion{assertReturnedEvents(3), assertGasUsed(115534, 134000)}, }, "not enough tokens": { submsgID: 6, @@ -268,7 +268,7 @@ func TestDispatchSubMsgErrorHandling(t *testing.T) { msg: validBankSend, gasLimit: &subGasLimit, // uses same gas as call without limit - resultAssertions: []assertion{assertReturnedEvents(1), assertGasUsed(115534, 121000)}, + resultAssertions: []assertion{assertReturnedEvents(3), assertGasUsed(115534, 134000)}, }, "not enough tokens with limit": { submsgID: 16, diff --git a/x/wasm/keeper/test_common.go b/x/wasm/keeper/test_common.go index fb5d64737b..005616b7f3 100644 --- a/x/wasm/keeper/test_common.go +++ b/x/wasm/keeper/test_common.go @@ -11,7 +11,7 @@ import ( "github.com/line/ostracon/crypto/ed25519" "github.com/line/ostracon/libs/log" "github.com/line/ostracon/libs/rand" - tmproto "github.com/line/ostracon/proto/ostracon/types" + ocproto "github.com/line/ostracon/proto/ostracon/types" dbm "github.com/line/tm-db/v2" "github.com/line/tm-db/v2/memdb" "github.com/stretchr/testify/require" @@ -96,7 +96,7 @@ var ModuleBasics = module.NewBasicManager( transfer.AppModuleBasic{}, ) -func MakeTestCodec(t TestingT) codec.Marshaler { +func MakeTestCodec(t TestingT) codec.Codec { return MakeEncodingConfig(t).Marshaler } @@ -173,6 +173,7 @@ func createTestInput( keyStaking := sdk.NewKVStoreKey(stakingtypes.StoreKey) keyDistro := sdk.NewKVStoreKey(distributiontypes.StoreKey) keyParams := sdk.NewKVStoreKey(paramstypes.StoreKey) + tkeyParams := sdk.NewKVStoreKey(paramstypes.TStoreKey) keyGov := sdk.NewKVStoreKey(govtypes.StoreKey) keyIBC := sdk.NewKVStoreKey(ibchost.StoreKey) keyCapability := sdk.NewKVStoreKey(capabilitytypes.StoreKey) @@ -191,14 +192,14 @@ func createTestInput( ms.MountStoreWithDB(keyCapabilityTransient, sdk.StoreTypeMemory, db) require.NoError(t, ms.LoadLatestVersion()) - ctx := sdk.NewContext(ms, tmproto.Header{ + ctx := sdk.NewContext(ms, ocproto.Header{ Height: 1234567, Time: time.Date(2020, time.April, 22, 12, 0, 0, 0, time.UTC), }, isCheckTx, log.NewNopLogger()) encodingConfig := MakeEncodingConfig(t) appCodec, legacyAmino := encodingConfig.Marshaler, encodingConfig.Amino - paramsKeeper := paramskeeper.NewKeeper(appCodec, legacyAmino, keyParams) + paramsKeeper := paramskeeper.NewKeeper(appCodec, legacyAmino, keyParams, tkeyParams) paramsKeeper.Subspace(authtypes.ModuleName) paramsKeeper.Subspace(banktypes.ModuleName) paramsKeeper.Subspace(stakingtypes.ModuleName) @@ -244,9 +245,7 @@ func createTestInput( ) bankParams := banktypes.DefaultParams() bankKeeper.SetParams(ctx, bankParams) - bankKeeper.SetSupply(ctx, banktypes.NewSupply(sdk.NewCoins( - sdk.NewCoin("denom", sdk.NewInt(10000)), - ))) + bankKeeper.SetSupply(ctx, sdk.NewCoin("denom", sdk.NewInt(10000))) stakingSubsp, _ := paramsKeeper.GetSubspace(stakingtypes.ModuleName) stakingKeeper := stakingkeeper.NewKeeper(appCodec, keyStaking, authKeeper, bankKeeper, stakingSubsp) stakingKeeper.SetParams(ctx, TestingStakeParams) @@ -262,9 +261,7 @@ func createTestInput( // set some funds ot pay out validatores, based on code from: // https://github.com/line/lbm-sdk/blob/95b22d3a685f7eb531198e0023ef06873835e632/x/distribution/keeper/keeper_test.go#L49-L56 distrAcc := distKeeper.GetDistributionAccount(ctx) - err := bankKeeper.SetBalances(ctx, distrAcc.GetAddress(), sdk.NewCoins( - sdk.NewCoin("stake", sdk.NewInt(2000000)), - )) + err := bankKeeper.SetBalance(ctx, distrAcc.GetAddress(), sdk.NewCoin("stake", sdk.NewInt(2000000))) require.NoError(t, err) authKeeper.SetModuleAccount(ctx, distrAcc) capabilityKeeper := capabilitykeeper.NewKeeper(appCodec, keyCapability, keyCapabilityTransient) @@ -274,7 +271,7 @@ func createTestInput( ibcSubsp, _ := paramsKeeper.GetSubspace(ibchost.ModuleName) ibcKeeper := ibckeeper.NewKeeper( - appCodec, keyIBC, ibcSubsp, stakingKeeper, scopedIBCKeeper, + appCodec, keyIBC, ibcSubsp, stakingKeeper, nil, scopedIBCKeeper, ) router := baseapp.NewRouter() @@ -611,7 +608,9 @@ func createFakeFundedAccount(t TestingT, ctx sdk.Context, am authkeeper.AccountK func fundAccounts(t TestingT, ctx sdk.Context, am authkeeper.AccountKeeper, bank bankkeeper.Keeper, addr sdk.AccAddress, coins sdk.Coins) { acc := am.NewAccountWithAddress(ctx, addr) am.SetAccount(ctx, acc) - require.NoError(t, bank.SetBalances(ctx, addr, coins)) + for _, coin := range coins { + require.NoError(t, bank.SetBalance(ctx, addr, coin)) + } } var keyCounter uint64 = 0 diff --git a/x/wasm/module.go b/x/wasm/module.go index e82f91a756..5211e23078 100644 --- a/x/wasm/module.go +++ b/x/wasm/module.go @@ -55,14 +55,14 @@ func (AppModuleBasic) Name() string { // DefaultGenesis returns default genesis state as raw bytes for the wasm // module. -func (AppModuleBasic) DefaultGenesis(cdc codec.JSONMarshaler) json.RawMessage { +func (AppModuleBasic) DefaultGenesis(cdc codec.JSONCodec) json.RawMessage { return cdc.MustMarshalJSON(&GenesisState{ Params: DefaultParams(), }) } // ValidateGenesis performs genesis state validation for the wasm module. -func (b AppModuleBasic) ValidateGenesis(marshaler codec.JSONMarshaler, config client.TxEncodingConfig, message json.RawMessage) error { +func (b AppModuleBasic) ValidateGenesis(marshaler codec.JSONCodec, config client.TxEncodingConfig, message json.RawMessage) error { var data GenesisState err := marshaler.UnmarshalJSON(message, &data) if err != nil { @@ -96,13 +96,13 @@ func (b AppModuleBasic) RegisterInterfaces(registry cdctypes.InterfaceRegistry) // AppModule implements an application module for the wasm module. type AppModule struct { AppModuleBasic - cdc codec.Marshaler + cdc codec.Codec keeper *Keeper validatorSetSource keeper.ValidatorSetSource } // NewAppModule creates a new AppModule object -func NewAppModule(cdc codec.Marshaler, keeper *Keeper, validatorSetSource keeper.ValidatorSetSource) AppModule { +func NewAppModule(cdc codec.Codec, keeper *Keeper, validatorSetSource keeper.ValidatorSetSource) AppModule { return AppModule{ AppModuleBasic: AppModuleBasic{}, cdc: cdc, @@ -140,7 +140,7 @@ func (AppModule) QuerierRoute() string { // InitGenesis performs genesis initialization for the wasm module. It returns // no validator updates. -func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONMarshaler, data json.RawMessage) []abci.ValidatorUpdate { +func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONCodec, data json.RawMessage) []abci.ValidatorUpdate { var genesisState GenesisState cdc.MustUnmarshalJSON(data, &genesisState) validators, err := InitGenesis(ctx, am.keeper, genesisState, am.validatorSetSource, am.Route().Handler()) @@ -152,7 +152,7 @@ func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONMarshaler, data j // ExportGenesis returns the exported genesis state as raw bytes for the wasm // module. -func (am AppModule) ExportGenesis(ctx sdk.Context, cdc codec.JSONMarshaler) json.RawMessage { +func (am AppModule) ExportGenesis(ctx sdk.Context, cdc codec.JSONCodec) json.RawMessage { gs := ExportGenesis(ctx, am.keeper) return cdc.MustMarshalJSON(gs) } diff --git a/x/wasm/module_test.go b/x/wasm/module_test.go index 199959fa12..617fec9660 100644 --- a/x/wasm/module_test.go +++ b/x/wasm/module_test.go @@ -414,13 +414,15 @@ func TestHandleExecute(t *testing.T) { assert.Equal(t, "link14hj2tavq8fpesdwxxcu44rty3hh90vhud63e6j", contractBech32Addr) // this should be standard x/wasm init event, plus a bank send event (2), with no custom contract events - assert.Equal(t, 4, len(res.Events), prettyEvents(res.Events)) + assert.Equal(t, 6, len(res.Events), prettyEvents(res.Events)) assert.Equal(t, "message", res.Events[0].Type) assertAttribute(t, "module", "wasm", res.Events[0].Attributes[0]) - assert.Equal(t, "transfer", res.Events[1].Type) - assert.Equal(t, "instantiate", res.Events[2].Type) - assert.Equal(t, "wasm", res.Events[3].Type) - assertAttribute(t, "_contract_address", contractBech32Addr, res.Events[3].Attributes[0]) + assert.Equal(t, "coin_spent", res.Events[1].Type) + assert.Equal(t, "coin_received", res.Events[2].Type) + assert.Equal(t, "transfer", res.Events[3].Type) + assert.Equal(t, "instantiate", res.Events[4].Type) + assert.Equal(t, "wasm", res.Events[5].Type) + assertAttribute(t, "_contract_address", contractBech32Addr, res.Events[5].Attributes[0]) // ensure bob doesn't exist bobAcct := data.acctKeeper.GetAccount(data.ctx, bob) @@ -450,32 +452,42 @@ func TestHandleExecute(t *testing.T) { assertExecuteResponse(t, res.Data, []byte{0xf0, 0x0b, 0xaa}) // this should be standard message event, plus x/wasm init event, plus 2 bank send event, plus a special event from the contract - require.Equal(t, 6, len(res.Events), prettyEvents(res.Events)) + require.Equal(t, 10, len(res.Events), prettyEvents(res.Events)) assert.Equal(t, "message", res.Events[0].Type) assertAttribute(t, "module", "wasm", res.Events[0].Attributes[0]) - require.Equal(t, "transfer", res.Events[1].Type) - require.Len(t, res.Events[1].Attributes, 3) - assertAttribute(t, "recipient", contractBech32Addr, res.Events[1].Attributes[0]) - assertAttribute(t, "sender", fred.String(), res.Events[1].Attributes[1]) - assertAttribute(t, "amount", "5000denom", res.Events[1].Attributes[2]) + assert.Equal(t, "coin_spent", res.Events[1].Type) + assertAttribute(t, "spender", fred.String(), res.Events[1].Attributes[0]) + assert.Equal(t, "coin_received", res.Events[2].Type) + assertAttribute(t, "receiver", contractBech32Addr, res.Events[2].Attributes[0]) + require.Equal(t, "transfer", res.Events[3].Type) + require.Len(t, res.Events[3].Attributes, 3) + assertAttribute(t, "recipient", contractBech32Addr, res.Events[3].Attributes[0]) + assertAttribute(t, "sender", fred.String(), res.Events[3].Attributes[1]) + assertAttribute(t, "amount", "5000denom", res.Events[3].Attributes[2]) - assert.Equal(t, "execute", res.Events[2].Type) + assert.Equal(t, "execute", res.Events[4].Type) // custom contract event attribute - assert.Equal(t, "wasm", res.Events[3].Type) - assertAttribute(t, "_contract_address", contractBech32Addr, res.Events[3].Attributes[0]) - assertAttribute(t, "action", "release", res.Events[3].Attributes[1]) + assert.Equal(t, "wasm", res.Events[5].Type) + assertAttribute(t, "_contract_address", contractBech32Addr, res.Events[5].Attributes[0]) + assertAttribute(t, "action", "release", res.Events[5].Attributes[1]) // custom contract event - assert.Equal(t, "wasm-hackatom", res.Events[4].Type) - assertAttribute(t, "_contract_address", contractBech32Addr, res.Events[4].Attributes[0]) - assertAttribute(t, "action", "release", res.Events[4].Attributes[1]) + assert.Equal(t, "wasm-hackatom", res.Events[6].Type) + assertAttribute(t, "_contract_address", contractBech32Addr, res.Events[6].Attributes[0]) + assertAttribute(t, "action", "release", res.Events[6].Attributes[1]) + // second transfer (this without conflicting message) - assert.Equal(t, "transfer", res.Events[5].Type) - assertAttribute(t, "recipient", bob.String(), res.Events[5].Attributes[0]) - assertAttribute(t, "sender", contractBech32Addr, res.Events[5].Attributes[1]) - assertAttribute(t, "amount", "105000denom", res.Events[5].Attributes[2]) + assert.Equal(t, "coin_spent", res.Events[7].Type) + assertAttribute(t, "spender", contractBech32Addr, res.Events[7].Attributes[0]) + assert.Equal(t, "coin_received", res.Events[8].Type) + assertAttribute(t, "receiver", bob.String(), res.Events[8].Attributes[0]) + assert.Equal(t, "transfer", res.Events[9].Type) + assertAttribute(t, "recipient", bob.String(), res.Events[9].Attributes[0]) + assertAttribute(t, "sender", contractBech32Addr, res.Events[9].Attributes[1]) + assertAttribute(t, "amount", "105000denom", res.Events[9].Attributes[2]) + // ensure bob now exists and got both payments released bobAcct = data.acctKeeper.GetAccount(data.ctx, bob) require.NotNil(t, bobAcct) @@ -486,7 +498,7 @@ func TestHandleExecute(t *testing.T) { contractAcct = data.acctKeeper.GetAccount(data.ctx, contractAddr) require.NotNil(t, contractAcct) - assert.Equal(t, sdk.Coins(nil), data.bankKeeper.GetAllBalances(data.ctx, contractAcct.GetAddress())) + assert.Equal(t, sdk.NewCoins().String(), data.bankKeeper.GetAllBalances(data.ctx, contractAcct.GetAddress()).String()) // ensure all contract state is as after init assertCodeList(t, q, data.ctx, 1) @@ -564,7 +576,7 @@ func TestHandleExecuteEscrow(t *testing.T) { contractAddr := sdk.AccAddress(contractBech32Addr) contractAcct := data.acctKeeper.GetAccount(data.ctx, contractAddr) require.NotNil(t, contractAcct) - assert.Equal(t, sdk.Coins(nil), data.bankKeeper.GetAllBalances(data.ctx, contractAcct.GetAddress())) + assert.Equal(t, sdk.NewCoins().String(), data.bankKeeper.GetAllBalances(data.ctx, contractAcct.GetAddress()).String()) } func TestReadWasmConfig(t *testing.T) { @@ -751,6 +763,8 @@ func createFakeFundedAccount(t *testing.T, ctx sdk.Context, am authkeeper.Accoun _, _, addr := keyPubAddr() acc := am.NewAccountWithAddress(ctx, addr) am.SetAccount(ctx, acc) - require.NoError(t, bankKeeper.SetBalances(ctx, addr, coins)) + for _, coin := range coins { + require.NoError(t, bankKeeper.SetBalance(ctx, addr, coin)) + } return addr } diff --git a/x/wasm/simulation/params.go b/x/wasm/simulation/params.go index b04a8d5e01..69246ad1c8 100644 --- a/x/wasm/simulation/params.go +++ b/x/wasm/simulation/params.go @@ -10,7 +10,7 @@ import ( "github.com/line/lbm-sdk/x/wasm/types" ) -func ParamChanges(r *rand.Rand, cdc codec.Marshaler) []simtypes.ParamChange { +func ParamChanges(r *rand.Rand, cdc codec.Codec) []simtypes.ParamChange { params := RandomParams(r) return []simtypes.ParamChange{ simulation.NewSimParamChange(types.ModuleName, string(types.ParamStoreKeyUploadAccess), diff --git a/x/wasm/types/expected_keepers.go b/x/wasm/types/expected_keepers.go index 1bf2568443..ede15c08cd 100644 --- a/x/wasm/types/expected_keepers.go +++ b/x/wasm/types/expected_keepers.go @@ -29,7 +29,7 @@ type Burner interface { type BankKeeper interface { BankViewKeeper Burner - SendEnabledCoins(ctx sdk.Context, coins ...sdk.Coin) error + IsSendEnabledCoins(ctx sdk.Context, coins ...sdk.Coin) error BlockedAddr(addr sdk.AccAddress) bool SendCoins(ctx sdk.Context, fromAddr sdk.AccAddress, toAddr sdk.AccAddress, amt sdk.Coins) error } diff --git a/x/wasm/types/query.pb.gw.go b/x/wasm/types/query.pb.gw.go index 1297e43469..5ccae1aef4 100644 --- a/x/wasm/types/query.pb.gw.go +++ b/x/wasm/types/query.pb.gw.go @@ -914,21 +914,21 @@ func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, clie } var ( - pattern_Query_ContractInfo_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4}, []string{"lbm", "wasm", "v1", "contract", "address"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_Query_ContractInfo_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4}, []string{"lbm", "wasm", "v1", "contract", "address"}, "", runtime.AssumeColonVerbOpt(false))) - pattern_Query_ContractHistory_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4, 2, 5}, []string{"lbm", "wasm", "v1", "contract", "address", "history"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_Query_ContractHistory_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4, 2, 5}, []string{"lbm", "wasm", "v1", "contract", "address", "history"}, "", runtime.AssumeColonVerbOpt(false))) - pattern_Query_ContractsByCode_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4, 2, 5}, []string{"lbm", "wasm", "v1", "code", "code_id", "contracts"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_Query_ContractsByCode_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4, 2, 5}, []string{"lbm", "wasm", "v1", "code", "code_id", "contracts"}, "", runtime.AssumeColonVerbOpt(false))) - pattern_Query_AllContractState_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4, 2, 5}, []string{"lbm", "wasm", "v1", "contract", "address", "state"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_Query_AllContractState_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4, 2, 5}, []string{"lbm", "wasm", "v1", "contract", "address", "state"}, "", runtime.AssumeColonVerbOpt(false))) - pattern_Query_RawContractState_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4, 2, 5, 1, 0, 4, 1, 5, 6}, []string{"lbm", "wasm", "v1", "contract", "address", "raw", "query_data"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_Query_RawContractState_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4, 2, 5, 1, 0, 4, 1, 5, 6}, []string{"lbm", "wasm", "v1", "contract", "address", "raw", "query_data"}, "", runtime.AssumeColonVerbOpt(false))) - pattern_Query_SmartContractState_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4, 2, 5, 1, 0, 4, 1, 5, 6}, []string{"lbm", "wasm", "v1", "contract", "address", "smart", "query_data"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_Query_SmartContractState_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4, 2, 5, 1, 0, 4, 1, 5, 6}, []string{"lbm", "wasm", "v1", "contract", "address", "smart", "query_data"}, "", runtime.AssumeColonVerbOpt(false))) - pattern_Query_Code_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4}, []string{"lbm", "wasm", "v1", "code", "code_id"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_Query_Code_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4}, []string{"lbm", "wasm", "v1", "code", "code_id"}, "", runtime.AssumeColonVerbOpt(false))) - pattern_Query_Codes_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"lbm", "wasm", "v1", "code"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_Query_Codes_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"lbm", "wasm", "v1", "code"}, "", runtime.AssumeColonVerbOpt(false))) ) var ( diff --git a/x/wasm/types/tx_test.go b/x/wasm/types/tx_test.go index a0bfec24fb..a492ffee56 100644 --- a/x/wasm/types/tx_test.go +++ b/x/wasm/types/tx_test.go @@ -46,7 +46,7 @@ func TestStoreCodeValidation(t *testing.T) { Sender: badAddress, WASMByteCode: []byte("foo"), }, - valid: false, + valid: true, }, "correct maximal": { msg: MsgStoreCode{ @@ -61,7 +61,7 @@ func TestStoreCodeValidation(t *testing.T) { WASMByteCode: []byte("foo"), InstantiatePermission: &AccessConfig{Permission: AccessTypeOnlyAddress, Address: badAddress}, }, - valid: false, + valid: true, }, } @@ -130,7 +130,7 @@ func TestInstantiateContractValidation(t *testing.T) { Label: "foo", Msg: []byte("{}"), }, - valid: false, + valid: true, }, "correct maximal": { msg: MsgInstantiateContract{ @@ -252,7 +252,7 @@ func TestStoreCodeAndInstantiateContractValidation(t *testing.T) { InitMsg: []byte(`{"some": "data"}`), Funds: sdk.Coins{sdk.Coin{Denom: "foobar", Amount: sdk.NewInt(200)}}, }, - valid: false, + valid: true, }, "negative funds": { msg: MsgStoreCodeAndInstantiateContract{ @@ -280,7 +280,7 @@ func TestStoreCodeAndInstantiateContractValidation(t *testing.T) { Label: "foo", InitMsg: []byte("{}"), }, - valid: false, + valid: true, }, } @@ -334,7 +334,7 @@ func TestExecuteContractValidation(t *testing.T) { Contract: goodAddress, Msg: []byte(`{"some": "data"}`), }, - valid: false, + valid: true, }, "empty sender": { msg: MsgExecuteContract{ @@ -349,7 +349,7 @@ func TestExecuteContractValidation(t *testing.T) { Contract: badAddress, Msg: []byte(`{"some": "data"}`), }, - valid: false, + valid: true, }, "empty contract": { msg: MsgExecuteContract{ @@ -438,7 +438,6 @@ func TestMsgUpdateAdministrator(t *testing.T) { NewAdmin: otherGoodAddress, Contract: anotherGoodAddress, }, - expErr: true, }, "bad new admin": { src: MsgUpdateAdmin{ @@ -446,7 +445,6 @@ func TestMsgUpdateAdministrator(t *testing.T) { NewAdmin: badAddress, Contract: anotherGoodAddress, }, - expErr: true, }, "bad contract addr": { src: MsgUpdateAdmin{ @@ -454,7 +452,6 @@ func TestMsgUpdateAdministrator(t *testing.T) { NewAdmin: otherGoodAddress, Contract: badAddress, }, - expErr: true, }, "new admin same as old admin": { src: MsgUpdateAdmin{ @@ -500,14 +497,12 @@ func TestMsgClearAdministrator(t *testing.T) { Sender: badAddress, Contract: anotherGoodAddress, }, - expErr: true, }, "bad contract addr": { src: MsgClearAdmin{ Sender: goodAddress, Contract: badAddress, }, - expErr: true, }, "contract missing": { src: MsgClearAdmin{ diff --git a/x/wasm/types/types_test.go b/x/wasm/types/types_test.go index 738134efeb..e91a12f576 100644 --- a/x/wasm/types/types_test.go +++ b/x/wasm/types/types_test.go @@ -197,11 +197,11 @@ func TestContractInfoMarshalUnmarshal(t *testing.T) { govtypes.RegisterInterfaces(interfaceRegistry) // when encode - bz, err := marshaler.MarshalBinaryBare(&src) + bz, err := marshaler.Marshal(&src) require.NoError(t, err) // and decode var dest ContractInfo - err = marshaler.UnmarshalBinaryBare(bz, &dest) + err = marshaler.Unmarshal(bz, &dest) // then require.NoError(t, err) assert.Equal(t, src, dest)